aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acorn/block/Kconfig2
-rw-r--r--drivers/acorn/block/mfmhd.c3
-rw-r--r--drivers/acorn/char/i2c.c1
-rw-r--r--drivers/acpi/Kconfig21
-rw-r--r--drivers/acpi/Makefile3
-rw-r--r--drivers/acpi/ac.c97
-rw-r--r--drivers/acpi/acpi_memhotplug.c278
-rw-r--r--drivers/acpi/asus_acpi.c337
-rw-r--r--drivers/acpi/battery.c171
-rw-r--r--drivers/acpi/bus.c133
-rw-r--r--drivers/acpi/button.c86
-rw-r--r--drivers/acpi/cm_sbs.c113
-rw-r--r--drivers/acpi/container.c38
-rw-r--r--drivers/acpi/debug.c19
-rw-r--r--drivers/acpi/dispatcher/dsinit.c40
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c349
-rw-r--r--drivers/acpi/dispatcher/dswexec.c8
-rw-r--r--drivers/acpi/dispatcher/dswload.c49
-rw-r--r--drivers/acpi/dock.c739
-rw-r--r--drivers/acpi/ec.c170
-rw-r--r--drivers/acpi/event.c21
-rw-r--r--drivers/acpi/events/evgpe.c14
-rw-r--r--drivers/acpi/events/evregion.c44
-rw-r--r--drivers/acpi/events/evxface.c39
-rw-r--r--drivers/acpi/events/evxfregn.c13
-rw-r--r--drivers/acpi/executer/exconfig.c9
-rw-r--r--drivers/acpi/executer/exconvrt.c3
-rw-r--r--drivers/acpi/executer/excreate.c27
-rw-r--r--drivers/acpi/executer/exdump.c8
-rw-r--r--drivers/acpi/executer/exfldio.c71
-rw-r--r--drivers/acpi/executer/exmutex.c16
-rw-r--r--drivers/acpi/executer/exsystem.c84
-rw-r--r--drivers/acpi/fan.c63
-rw-r--r--drivers/acpi/glue.c8
-rw-r--r--drivers/acpi/hardware/hwregs.c77
-rw-r--r--drivers/acpi/hotkey.c417
-rw-r--r--drivers/acpi/i2c_ec.c406
-rw-r--r--drivers/acpi/i2c_ec.h23
-rw-r--r--drivers/acpi/motherboard.c5
-rw-r--r--drivers/acpi/namespace/nsaccess.c27
-rw-r--r--drivers/acpi/namespace/nsalloc.c13
-rw-r--r--drivers/acpi/namespace/nsxfeval.c2
-rw-r--r--drivers/acpi/numa.c14
-rw-r--r--drivers/acpi/osl.c184
-rw-r--r--drivers/acpi/parser/psparse.c18
-rw-r--r--drivers/acpi/parser/psutils.c2
-rw-r--r--drivers/acpi/pci_bind.c87
-rw-r--r--drivers/acpi/pci_irq.c92
-rw-r--r--drivers/acpi/pci_link.c211
-rw-r--r--drivers/acpi/pci_root.c59
-rw-r--r--drivers/acpi/power.c165
-rw-r--r--drivers/acpi/processor_core.c163
-rw-r--r--drivers/acpi/processor_idle.c154
-rw-r--r--drivers/acpi/processor_perflib.c138
-rw-r--r--drivers/acpi/processor_thermal.c48
-rw-r--r--drivers/acpi/processor_throttling.c45
-rw-r--r--drivers/acpi/sbs.c1769
-rw-r--r--drivers/acpi/scan.c125
-rw-r--r--drivers/acpi/sleep/proc.c6
-rw-r--r--drivers/acpi/system.c31
-rw-r--r--drivers/acpi/tables.c1
-rw-r--r--drivers/acpi/tables/tbget.c12
-rw-r--r--drivers/acpi/tables/tbinstal.c21
-rw-r--r--drivers/acpi/tables/tbrsdt.c27
-rw-r--r--drivers/acpi/tables/tbxface.c32
-rw-r--r--drivers/acpi/thermal.c296
-rw-r--r--drivers/acpi/utilities/utalloc.c6
-rw-r--r--drivers/acpi/utilities/utcache.c2
-rw-r--r--drivers/acpi/utilities/utdebug.c4
-rw-r--r--drivers/acpi/utilities/utdelete.c49
-rw-r--r--drivers/acpi/utilities/utglobal.c1
-rw-r--r--drivers/acpi/utilities/utmisc.c28
-rw-r--r--drivers/acpi/utilities/utmutex.c47
-rw-r--r--drivers/acpi/utilities/utstate.c7
-rw-r--r--drivers/acpi/utils.c110
-rw-r--r--drivers/acpi/video.c342
-rw-r--r--drivers/amba/bus.c5
-rw-r--r--drivers/ata/Kconfig487
-rw-r--r--drivers/ata/Makefile62
-rw-r--r--drivers/ata/ahci.c (renamed from drivers/scsi/ahci.c)750
-rw-r--r--drivers/ata/ata_generic.c252
-rw-r--r--drivers/ata/ata_piix.c (renamed from drivers/scsi/ata_piix.c)730
-rw-r--r--drivers/ata/libata-core.c (renamed from drivers/scsi/libata-core.c)994
-rw-r--r--drivers/ata/libata-eh.c (renamed from drivers/scsi/libata-eh.c)552
-rw-r--r--drivers/ata/libata-scsi.c (renamed from drivers/scsi/libata-scsi.c)356
-rw-r--r--drivers/ata/libata-sff.c (renamed from drivers/scsi/libata-bmdma.c)203
-rw-r--r--drivers/ata/libata.h (renamed from drivers/scsi/libata.h)9
-rw-r--r--drivers/ata/pata_ali.c679
-rw-r--r--drivers/ata/pata_amd.c709
-rw-r--r--drivers/ata/pata_artop.c512
-rw-r--r--drivers/ata/pata_atiixp.c304
-rw-r--r--drivers/ata/pata_cmd64x.c505
-rw-r--r--drivers/ata/pata_cs5520.c334
-rw-r--r--drivers/ata/pata_cs5530.c387
-rw-r--r--drivers/ata/pata_cs5535.c291
-rw-r--r--drivers/ata/pata_cypress.c227
-rw-r--r--drivers/ata/pata_efar.c338
-rw-r--r--drivers/ata/pata_hpt366.c478
-rw-r--r--drivers/ata/pata_hpt37x.c1257
-rw-r--r--drivers/ata/pata_hpt3x2n.c597
-rw-r--r--drivers/ata/pata_hpt3x3.c226
-rw-r--r--drivers/ata/pata_isapnp.c156
-rw-r--r--drivers/ata/pata_it821x.c847
-rw-r--r--drivers/ata/pata_jmicron.c265
-rw-r--r--drivers/ata/pata_legacy.c949
-rw-r--r--drivers/ata/pata_mpiix.c310
-rw-r--r--drivers/ata/pata_netcell.c174
-rw-r--r--drivers/ata/pata_ns87410.c233
-rw-r--r--drivers/ata/pata_oldpiix.c336
-rw-r--r--drivers/ata/pata_opti.c290
-rw-r--r--drivers/ata/pata_optidma.c545
-rw-r--r--drivers/ata/pata_pcmcia.c393
-rw-r--r--drivers/ata/pata_pdc2027x.c867
-rw-r--r--drivers/ata/pata_pdc202xx_old.c423
-rw-r--r--drivers/ata/pata_qdi.c403
-rw-r--r--drivers/ata/pata_radisys.c333
-rw-r--r--drivers/ata/pata_rz1000.c205
-rw-r--r--drivers/ata/pata_sc1200.c287
-rw-r--r--drivers/ata/pata_serverworks.c591
-rw-r--r--drivers/ata/pata_sil680.c381
-rw-r--r--drivers/ata/pata_sis.c1022
-rw-r--r--drivers/ata/pata_sl82c105.c385
-rw-r--r--drivers/ata/pata_triflex.c282
-rw-r--r--drivers/ata/pata_via.c565
-rw-r--r--drivers/ata/pdc_adma.c (renamed from drivers/scsi/pdc_adma.c)55
-rw-r--r--drivers/ata/sata_mv.c (renamed from drivers/scsi/sata_mv.c)106
-rw-r--r--drivers/ata/sata_nv.c (renamed from drivers/scsi/sata_nv.c)69
-rw-r--r--drivers/ata/sata_promise.c (renamed from drivers/scsi/sata_promise.c)65
-rw-r--r--drivers/ata/sata_promise.h (renamed from drivers/scsi/sata_promise.h)0
-rw-r--r--drivers/ata/sata_qstor.c (renamed from drivers/scsi/sata_qstor.c)48
-rw-r--r--drivers/ata/sata_sil.c (renamed from drivers/scsi/sata_sil.c)181
-rw-r--r--drivers/ata/sata_sil24.c (renamed from drivers/scsi/sata_sil24.c)190
-rw-r--r--drivers/ata/sata_sis.c (renamed from drivers/scsi/sata_sis.c)27
-rw-r--r--drivers/ata/sata_svw.c (renamed from drivers/scsi/sata_svw.c)19
-rw-r--r--drivers/ata/sata_sx4.c (renamed from drivers/scsi/sata_sx4.c)68
-rw-r--r--drivers/ata/sata_uli.c (renamed from drivers/scsi/sata_uli.c)19
-rw-r--r--drivers/ata/sata_via.c (renamed from drivers/scsi/sata_via.c)141
-rw-r--r--drivers/ata/sata_vsc.c (renamed from drivers/scsi/sata_vsc.c)34
-rw-r--r--drivers/atm/Kconfig2
-rw-r--r--drivers/atm/adummy.c1
-rw-r--r--drivers/atm/ambassador.c8
-rw-r--r--drivers/atm/ambassador.h1
-rw-r--r--drivers/atm/eni.c3
-rw-r--r--drivers/atm/firestream.c12
-rw-r--r--drivers/atm/fore200e.c3
-rw-r--r--drivers/atm/fore200e.h1
-rw-r--r--drivers/atm/he.c34
-rw-r--r--drivers/atm/horizon.c2
-rw-r--r--drivers/atm/horizon.h1
-rw-r--r--drivers/atm/idt77105.c2
-rw-r--r--drivers/atm/idt77105.h2
-rw-r--r--drivers/atm/idt77252.c6
-rw-r--r--drivers/atm/iphase.c6
-rw-r--r--drivers/atm/iphase.h1
-rw-r--r--drivers/atm/lanai.c2
-rw-r--r--drivers/atm/nicstar.c3
-rw-r--r--drivers/atm/suni.c2
-rw-r--r--drivers/atm/zatm.c3
-rw-r--r--drivers/atm/zatm.h1
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/base.h2
-rw-r--r--drivers/base/bus.c139
-rw-r--r--drivers/base/class.c43
-rw-r--r--drivers/base/core.c261
-rw-r--r--drivers/base/cpu.c28
-rw-r--r--drivers/base/dd.c147
-rw-r--r--drivers/base/dmapool.c3
-rw-r--r--drivers/base/driver.c17
-rw-r--r--drivers/base/firmware_class.c14
-rw-r--r--drivers/base/hypervisor.c3
-rw-r--r--drivers/base/memory.c4
-rw-r--r--drivers/base/node.c135
-rw-r--r--drivers/base/platform.c30
-rw-r--r--drivers/base/power/Makefile1
-rw-r--r--drivers/base/power/main.c1
-rw-r--r--drivers/base/power/resume.c45
-rw-r--r--drivers/base/power/shutdown.c1
-rw-r--r--drivers/base/power/suspend.c99
-rw-r--r--drivers/base/power/sysfs.c35
-rw-r--r--drivers/base/power/trace.c228
-rw-r--r--drivers/base/sys.c1
-rw-r--r--drivers/base/topology.c6
-rw-r--r--drivers/block/DAC960.c5
-rw-r--r--drivers/block/Kconfig10
-rw-r--r--drivers/block/acsi.c6
-rw-r--r--drivers/block/acsi_slm.c10
-rw-r--r--drivers/block/amiflop.c1
-rw-r--r--drivers/block/aoe/aoechr.c2
-rw-r--r--drivers/block/cciss.c3241
-rw-r--r--drivers/block/cciss.h2
-rw-r--r--drivers/block/cciss_scsi.c14
-rw-r--r--drivers/block/cpqarray.c16
-rw-r--r--drivers/block/cryptoloop.c160
-rw-r--r--drivers/block/floppy.c109
-rw-r--r--drivers/block/loop.c98
-rw-r--r--drivers/block/nbd.c60
-rw-r--r--drivers/block/paride/paride.c1
-rw-r--r--drivers/block/paride/pf.c2
-rw-r--r--drivers/block/paride/pg.c18
-rw-r--r--drivers/block/paride/pt.c21
-rw-r--r--drivers/block/pktcdvd.c8
-rw-r--r--drivers/block/ps2esdi.c6
-rw-r--r--drivers/block/rd.c10
-rw-r--r--drivers/block/swim3.c235
-rw-r--r--drivers/block/sx8.c12
-rw-r--r--drivers/block/ub.c44
-rw-r--r--drivers/block/umem.c4
-rw-r--r--drivers/block/viodasd.c3
-rw-r--r--drivers/block/xd.c1
-rw-r--r--drivers/block/z2ram.c1
-rw-r--r--drivers/bluetooth/bcm203x.c2
-rw-r--r--drivers/bluetooth/bfusb.c317
-rw-r--r--drivers/bluetooth/bluecard_cs.c2
-rw-r--r--drivers/bluetooth/bpa10x.c1
-rw-r--r--drivers/bluetooth/bt3c_cs.c2
-rw-r--r--drivers/bluetooth/btuart_cs.c2
-rw-r--r--drivers/bluetooth/dtl1_cs.c5
-rw-r--r--drivers/bluetooth/hci_bcsp.c1
-rw-r--r--drivers/bluetooth/hci_h4.c1
-rw-r--r--drivers/bluetooth/hci_ldisc.c18
-rw-r--r--drivers/bluetooth/hci_usb.c103
-rw-r--r--drivers/bluetooth/hci_usb.h1
-rw-r--r--drivers/bluetooth/hci_vhci.c101
-rw-r--r--drivers/cdrom/aztcd.c1
-rw-r--r--drivers/cdrom/cdrom.c3
-rw-r--r--drivers/cdrom/cdu31a.c3
-rw-r--r--drivers/cdrom/cm206.c10
-rw-r--r--drivers/cdrom/gscd.c3
-rw-r--r--drivers/cdrom/mcdx.c5
-rw-r--r--drivers/cdrom/optcd.c1
-rw-r--r--drivers/cdrom/sbpcd.c7
-rw-r--r--drivers/cdrom/sjcd.c1
-rw-r--r--drivers/cdrom/sonycd535.c3
-rw-r--r--drivers/cdrom/viocd.c3
-rw-r--r--drivers/char/Kconfig97
-rw-r--r--drivers/char/Makefile8
-rw-r--r--drivers/char/agp/Kconfig5
-rw-r--r--drivers/char/agp/agp.h2
-rw-r--r--drivers/char/agp/amd-k7-agp.c2
-rw-r--r--drivers/char/agp/amd64-agp.c84
-rw-r--r--drivers/char/agp/ati-agp.c35
-rw-r--r--drivers/char/agp/backend.c2
-rw-r--r--drivers/char/agp/efficeon-agp.c18
-rw-r--r--drivers/char/agp/frontend.c29
-rw-r--r--drivers/char/agp/generic.c40
-rw-r--r--drivers/char/agp/intel-agp.c173
-rw-r--r--drivers/char/agp/nvidia-agp.c27
-rw-r--r--drivers/char/agp/sgi-agp.c5
-rw-r--r--drivers/char/agp/uninorth-agp.c4
-rw-r--r--drivers/char/agp/via-agp.c4
-rw-r--r--drivers/char/amiserial.c3
-rw-r--r--drivers/char/applicom.c55
-rw-r--r--drivers/char/briq_panel.c271
-rw-r--r--drivers/char/consolemap.c1
-rw-r--r--drivers/char/cs5535_gpio.c2
-rw-r--r--drivers/char/cyclades.c17
-rw-r--r--drivers/char/decserial.c1
-rw-r--r--drivers/char/drm/drm.h1
-rw-r--r--drivers/char/drm/drmP.h1
-rw-r--r--drivers/char/drm/drm_irq.c2
-rw-r--r--drivers/char/drm/drm_memory.c1
-rw-r--r--drivers/char/drm/drm_memory.h1
-rw-r--r--drivers/char/drm/drm_memory_debug.h3
-rw-r--r--drivers/char/drm/drm_scatter.c1
-rw-r--r--drivers/char/drm/drm_sysfs.c1
-rw-r--r--drivers/char/drm/ffb_drv.c1
-rw-r--r--drivers/char/drm/i810_drv.c1
-rw-r--r--drivers/char/drm/i830_drv.c1
-rw-r--r--drivers/char/drm/i915_dma.c4
-rw-r--r--drivers/char/drm/i915_drm.h13
-rw-r--r--drivers/char/drm/i915_drv.h6
-rw-r--r--drivers/char/drm/i915_irq.c69
-rw-r--r--drivers/char/drm/mga_drv.c1
-rw-r--r--drivers/char/drm/r128_drv.c1
-rw-r--r--drivers/char/drm/radeon_cp.c6
-rw-r--r--drivers/char/drm/radeon_drm.h7
-rw-r--r--drivers/char/drm/radeon_drv.c1
-rw-r--r--drivers/char/drm/radeon_drv.h10
-rw-r--r--drivers/char/drm/radeon_state.c48
-rw-r--r--drivers/char/drm/savage_drv.c1
-rw-r--r--drivers/char/drm/sis_drv.c1
-rw-r--r--drivers/char/drm/tdfx_drv.c1
-rw-r--r--drivers/char/drm/via_dmablit.c2
-rw-r--r--drivers/char/drm/via_drv.c1
-rw-r--r--drivers/char/ds1286.c2
-rw-r--r--drivers/char/ds1302.c3
-rw-r--r--drivers/char/ds1620.c3
-rw-r--r--drivers/char/dsp56k.c12
-rw-r--r--drivers/char/dtlk.c7
-rw-r--r--drivers/char/ec3104_keyb.c1
-rw-r--r--drivers/char/efirtc.c2
-rw-r--r--drivers/char/epca.c4
-rw-r--r--drivers/char/esp.c7
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c2
-rw-r--r--drivers/char/ftape/lowlevel/ftape-calibr.c1
-rw-r--r--drivers/char/ftape/lowlevel/ftape-ctl.c1
-rw-r--r--drivers/char/ftape/lowlevel/ftape-init.c1
-rw-r--r--drivers/char/ftape/lowlevel/ftape-proc.c1
-rw-r--r--drivers/char/ftape/lowlevel/ftape-setup.c1
-rw-r--r--drivers/char/ftape/lowlevel/ftape-tracing.h1
-rw-r--r--drivers/char/ftape/lowlevel/ftape_syms.c1
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.c1
-rw-r--r--drivers/char/ftape/zftape/zftape-ctl.h1
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c28
-rw-r--r--drivers/char/generic_serial.c11
-rw-r--r--drivers/char/genrtc.c3
-rw-r--r--drivers/char/hangcheck-timer.c4
-rw-r--r--drivers/char/hpet.c9
-rw-r--r--drivers/char/hvc_console.c23
-rw-r--r--drivers/char/hvc_console.h2
-rw-r--r--drivers/char/hvc_iseries.c594
-rw-r--r--drivers/char/hvc_rtas.c2
-rw-r--r--drivers/char/hvc_vio.c7
-rw-r--r--drivers/char/hvcs.c14
-rw-r--r--drivers/char/hvsi.c25
-rw-r--r--drivers/char/hw_random.c698
-rw-r--r--drivers/char/hw_random/Kconfig90
-rw-r--r--drivers/char/hw_random/Makefile11
-rw-r--r--drivers/char/hw_random/amd-rng.c152
-rw-r--r--drivers/char/hw_random/core.c354
-rw-r--r--drivers/char/hw_random/geode-rng.c132
-rw-r--r--drivers/char/hw_random/intel-rng.c357
-rw-r--r--drivers/char/hw_random/ixp4xx-rng.c73
-rw-r--r--drivers/char/hw_random/omap-rng.c205
-rw-r--r--drivers/char/hw_random/via-rng.c183
-rw-r--r--drivers/char/i8k.c2
-rw-r--r--drivers/char/ip2/i2ellis.h1
-rw-r--r--drivers/char/ip2/ip2main.c52
-rw-r--r--drivers/char/ip27-rtc.c2
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c11
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c25
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c1
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c83
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c21
-rw-r--r--drivers/char/isicom.c13
-rw-r--r--drivers/char/istallion.c1874
-rw-r--r--drivers/char/ite_gpio.c4
-rw-r--r--drivers/char/keyboard.c167
-rw-r--r--drivers/char/lcd.c3
-rw-r--r--drivers/char/lp.c14
-rw-r--r--drivers/char/mbcs.c7
-rw-r--r--drivers/char/mem.c76
-rw-r--r--drivers/char/misc.c20
-rw-r--r--drivers/char/mmtimer.c7
-rw-r--r--drivers/char/moxa.c12
-rw-r--r--drivers/char/mspec.c421
-rw-r--r--drivers/char/mwave/3780i.c1
-rw-r--r--drivers/char/mwave/mwavedd.c2
-rw-r--r--drivers/char/mxser.c840
-rw-r--r--drivers/char/n_hdlc.c1
-rw-r--r--drivers/char/n_r3964.c3
-rw-r--r--drivers/char/n_tty.c6
-rw-r--r--drivers/char/nsc_gpio.c140
-rw-r--r--drivers/char/nvram.c3
-rw-r--r--drivers/char/nwbutton.c5
-rw-r--r--drivers/char/nwflash.c2
-rw-r--r--drivers/char/pc8736x_gpio.c347
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c9
-rw-r--r--drivers/char/pcmcia/cm4040_cs.c2
-rw-r--r--drivers/char/pcmcia/synclink_cs.c18
-rw-r--r--drivers/char/ppdev.c17
-rw-r--r--drivers/char/pty.c11
-rw-r--r--drivers/char/qtronix.c3
-rw-r--r--drivers/char/random.c7
-rw-r--r--drivers/char/raw.c40
-rw-r--r--drivers/char/rio/rio_linux.c5
-rw-r--r--drivers/char/rio/rio_linux.h1
-rw-r--r--drivers/char/rio/rioinit.c1
-rw-r--r--drivers/char/rio/riointr.c2
-rw-r--r--drivers/char/riscom8.c3
-rw-r--r--drivers/char/rocket.c67
-rw-r--r--drivers/char/rtc.c71
-rw-r--r--drivers/char/s3c2410-rtc.c591
-rw-r--r--drivers/char/scx200_gpio.c158
-rw-r--r--drivers/char/selection.c2
-rw-r--r--drivers/char/serial167.c2
-rw-r--r--drivers/char/snsc.c11
-rw-r--r--drivers/char/snsc_event.c17
-rw-r--r--drivers/char/sonypi.c5
-rw-r--r--drivers/char/specialix.c33
-rw-r--r--drivers/char/stallion.c232
-rw-r--r--drivers/char/sx.c8
-rw-r--r--drivers/char/synclink.c16
-rw-r--r--drivers/char/synclink_gt.c150
-rw-r--r--drivers/char/synclinkmp.c21
-rw-r--r--drivers/char/sysrq.c8
-rw-r--r--drivers/char/tb0219.c2
-rw-r--r--drivers/char/tipar.c20
-rw-r--r--drivers/char/tlclk.c7
-rw-r--r--drivers/char/toshiba.c2
-rw-r--r--drivers/char/tpm/tpm.c1
-rw-r--r--drivers/char/tpm/tpm_atmel.c2
-rw-r--r--drivers/char/tpm/tpm_atmel.h4
-rw-r--r--drivers/char/tpm/tpm_infineon.c2
-rw-r--r--drivers/char/tpm/tpm_nsc.c2
-rw-r--r--drivers/char/tpm/tpm_tis.c83
-rw-r--r--drivers/char/tty_io.c973
-rw-r--r--drivers/char/tty_ioctl.c88
-rw-r--r--drivers/char/vc_screen.c19
-rw-r--r--drivers/char/viocons.c33
-rw-r--r--drivers/char/viotape.c19
-rw-r--r--drivers/char/vme_scc.c50
-rw-r--r--drivers/char/vr41xx_giu.c7
-rw-r--r--drivers/char/vt.c688
-rw-r--r--drivers/char/vt_ioctl.c20
-rw-r--r--drivers/char/watchdog/Kconfig23
-rw-r--r--drivers/char/watchdog/Makefile1
-rw-r--r--drivers/char/watchdog/acquirewdt.c2
-rw-r--r--drivers/char/watchdog/advantechwdt.c2
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c2
-rw-r--r--drivers/char/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/char/watchdog/at91_wdt.c85
-rw-r--r--drivers/char/watchdog/booke_wdt.c3
-rw-r--r--drivers/char/watchdog/cpu5wdt.c2
-rw-r--r--drivers/char/watchdog/ep93xx_wdt.c2
-rw-r--r--drivers/char/watchdog/eurotechwdt.c5
-rw-r--r--drivers/char/watchdog/i6300esb.c2
-rw-r--r--drivers/char/watchdog/i8xx_tco.c30
-rw-r--r--drivers/char/watchdog/ib700wdt.c3
-rw-r--r--drivers/char/watchdog/ibmasr.c3
-rw-r--r--drivers/char/watchdog/indydog.c3
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c3
-rw-r--r--drivers/char/watchdog/ixp4xx_wdt.c3
-rw-r--r--drivers/char/watchdog/machzwd.c3
-rw-r--r--drivers/char/watchdog/mixcomwd.c3
-rw-r--r--drivers/char/watchdog/mpc83xx_wdt.c3
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c3
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c5
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c3
-rw-r--r--drivers/char/watchdog/omap_wdt.c391
-rw-r--r--drivers/char/watchdog/omap_wdt.h64
-rw-r--r--drivers/char/watchdog/pcwd.c4
-rw-r--r--drivers/char/watchdog/pcwd_pci.c34
-rw-r--r--drivers/char/watchdog/pcwd_usb.c28
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c3
-rw-r--r--drivers/char/watchdog/sa1100_wdt.c3
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c2
-rw-r--r--drivers/char/watchdog/sbc8360.c7
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c3
-rw-r--r--drivers/char/watchdog/sc1200wdt.c3
-rw-r--r--drivers/char/watchdog/sc520_wdt.c2
-rw-r--r--drivers/char/watchdog/scx200_wdt.c3
-rw-r--r--drivers/char/watchdog/shwdt.c113
-rw-r--r--drivers/char/watchdog/softdog.c3
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c2
-rw-r--r--drivers/char/watchdog/w83877f_wdt.c2
-rw-r--r--drivers/char/watchdog/w83977f_wdt.c3
-rw-r--r--drivers/char/watchdog/wafer5823wdt.c2
-rw-r--r--drivers/char/watchdog/wd501p.h1
-rw-r--r--drivers/char/watchdog/wdrtas.c5
-rw-r--r--drivers/char/watchdog/wdt.c7
-rw-r--r--drivers/char/watchdog/wdt285.c2
-rw-r--r--drivers/char/watchdog/wdt977.c3
-rw-r--r--drivers/char/watchdog/wdt_pci.c7
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/acpi_pm.c177
-rw-r--r--drivers/clocksource/cyclone.c119
-rw-r--r--drivers/clocksource/scx200_hrt.c101
-rw-r--r--drivers/connector/cn_proc.c20
-rw-r--r--drivers/cpufreq/cpufreq.c130
-rw-r--r--drivers/cpufreq/cpufreq_conservative.c2
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c421
-rw-r--r--drivers/cpufreq/cpufreq_stats.c7
-rw-r--r--drivers/cpufreq/cpufreq_userspace.c4
-rw-r--r--drivers/crypto/Kconfig45
-rw-r--r--drivers/crypto/Makefile8
-rw-r--r--drivers/crypto/padlock-aes.c288
-rw-r--r--drivers/crypto/padlock-generic.c63
-rw-r--r--drivers/crypto/padlock-sha.c318
-rw-r--r--drivers/crypto/padlock.c58
-rw-r--r--drivers/crypto/padlock.h17
-rw-r--r--drivers/dma/dmaengine.c20
-rw-r--r--drivers/dma/ioatdma.c15
-rw-r--r--drivers/dma/ioatdma_registers.h2
-rw-r--r--drivers/dma/iovlock.c2
-rw-r--r--drivers/edac/amd76x_edac.c99
-rw-r--r--drivers/edac/e752x_edac.c346
-rw-r--r--drivers/edac/e7xxx_edac.c177
-rw-r--r--drivers/edac/edac_mc.c1097
-rw-r--r--drivers/edac/edac_mc.h24
-rw-r--r--drivers/edac/i82860_edac.c133
-rw-r--r--drivers/edac/i82875p_edac.c221
-rw-r--r--drivers/edac/r82600_edac.c144
-rw-r--r--drivers/eisa/eisa-bus.c23
-rw-r--r--drivers/eisa/virtual_root.c1
-rw-r--r--drivers/fc4/fc.c4
-rw-r--r--drivers/fc4/fc_syms.c1
-rw-r--r--drivers/fc4/soc.c2
-rw-r--r--drivers/fc4/socal.c2
-rw-r--r--drivers/firmware/Kconfig3
-rw-r--r--drivers/firmware/dell_rbu.c1
-rw-r--r--drivers/firmware/dmi_scan.c36
-rw-r--r--drivers/firmware/efivars.c1
-rw-r--r--drivers/firmware/pcdp.c1
-rw-r--r--drivers/hwmon/Kconfig51
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/abituguru.c150
-rw-r--r--drivers/hwmon/adm1021.c31
-rw-r--r--drivers/hwmon/adm1025.c94
-rw-r--r--drivers/hwmon/adm1026.c286
-rw-r--r--drivers/hwmon/adm1031.c114
-rw-r--r--drivers/hwmon/adm9240.c105
-rw-r--r--drivers/hwmon/asb100.c124
-rw-r--r--drivers/hwmon/atxp1.c28
-rw-r--r--drivers/hwmon/ds1621.c28
-rw-r--r--drivers/hwmon/f71805f.c336
-rw-r--r--drivers/hwmon/fscher.c106
-rw-r--r--drivers/hwmon/fscpos.c75
-rw-r--r--drivers/hwmon/gl518sm.c74
-rw-r--r--drivers/hwmon/gl520sm.c128
-rw-r--r--drivers/hwmon/hdaps.c6
-rw-r--r--drivers/hwmon/hwmon-vid.c1
-rw-r--r--drivers/hwmon/it87.c470
-rw-r--r--drivers/hwmon/k8temp.c294
-rw-r--r--drivers/hwmon/lm63.c96
-rw-r--r--drivers/hwmon/lm75.c24
-rw-r--r--drivers/hwmon/lm77.c33
-rw-r--r--drivers/hwmon/lm78.c91
-rw-r--r--drivers/hwmon/lm80.c87
-rw-r--r--drivers/hwmon/lm83.c128
-rw-r--r--drivers/hwmon/lm85.c173
-rw-r--r--drivers/hwmon/lm87.c193
-rw-r--r--drivers/hwmon/lm90.c90
-rw-r--r--drivers/hwmon/lm92.c34
-rw-r--r--drivers/hwmon/max1619.c33
-rw-r--r--drivers/hwmon/pc87360.c231
-rw-r--r--drivers/hwmon/sis5595.c104
-rw-r--r--drivers/hwmon/smsc47b397.c40
-rw-r--r--drivers/hwmon/smsc47m1.c84
-rw-r--r--drivers/hwmon/smsc47m192.c150
-rw-r--r--drivers/hwmon/via686a.c84
-rw-r--r--drivers/hwmon/vt1211.c1355
-rw-r--r--drivers/hwmon/vt8231.c187
-rw-r--r--drivers/hwmon/w83627ehf.c486
-rw-r--r--drivers/hwmon/w83627hf.c235
-rw-r--r--drivers/hwmon/w83781d.c280
-rw-r--r--drivers/hwmon/w83791d.c7
-rw-r--r--drivers/hwmon/w83792d.c557
-rw-r--r--drivers/hwmon/w83l785ts.c28
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/algos/Kconfig6
-rw-r--r--drivers/i2c/algos/Makefile1
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c27
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.c4
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c8
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c10
-rw-r--r--drivers/i2c/algos/i2c-algo-sgi.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-sibyte.c217
-rw-r--r--drivers/i2c/busses/Kconfig36
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-au1550.c21
-rw-r--r--drivers/i2c/busses/i2c-elektor.c1
-rw-r--r--drivers/i2c/busses/i2c-hydra.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c22
-rw-r--r--drivers/i2c/busses/i2c-i810.c2
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c3
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c36
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.h2
-rw-r--r--drivers/i2c/busses/i2c-isa.c42
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c1
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c1
-rw-r--r--drivers/i2c/busses/i2c-mpc.c5
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c2
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c2
-rw-r--r--drivers/i2c/busses/i2c-ocores.c2
-rw-r--r--drivers/i2c/busses/i2c-omap.c676
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c1
-rw-r--r--drivers/i2c/busses/i2c-parport.c1
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-powermac.c10
-rw-r--r--drivers/i2c/busses/i2c-prosavage.c1
-rw-r--r--drivers/i2c/busses/i2c-pxa.c4
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c5
-rw-r--r--drivers/i2c/busses/i2c-savage4.c1
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c160
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-stub.c21
-rw-r--r--drivers/i2c/busses/i2c-via.c1
-rw-r--r--drivers/i2c/busses/i2c-viapro.c10
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c29
-rw-r--r--drivers/i2c/busses/scx200_i2c.c13
-rw-r--r--drivers/i2c/chips/eeprom.c8
-rw-r--r--drivers/i2c/chips/isp1301_omap.c7
-rw-r--r--drivers/i2c/chips/max6875.c25
-rw-r--r--drivers/i2c/chips/pca9539.c23
-rw-r--r--drivers/i2c/chips/pcf8574.c22
-rw-r--r--drivers/i2c/chips/pcf8591.c58
-rw-r--r--drivers/i2c/chips/tps65010.c19
-rw-r--r--drivers/i2c/i2c-core.c76
-rw-r--r--drivers/i2c/i2c-dev.c109
-rw-r--r--drivers/ide/Kconfig8
-rw-r--r--drivers/ide/arm/icside.c1
-rw-r--r--drivers/ide/cris/ide-cris.c1
-rw-r--r--drivers/ide/h8300/ide-h8300.c1
-rw-r--r--drivers/ide/ide-cd.c123
-rw-r--r--drivers/ide/ide-disk.c7
-rw-r--r--drivers/ide/ide-dma.c3
-rw-r--r--drivers/ide/ide-floppy.c6
-rw-r--r--drivers/ide/ide-io.c72
-rw-r--r--drivers/ide/ide-iops.c7
-rw-r--r--drivers/ide/ide-lib.c5
-rw-r--r--drivers/ide/ide-probe.c22
-rw-r--r--drivers/ide/ide-proc.c3
-rw-r--r--drivers/ide/ide-tape.c62
-rw-r--r--drivers/ide/ide-taskfile.c3
-rw-r--r--drivers/ide/ide-timing.h8
-rw-r--r--drivers/ide/ide.c22
-rw-r--r--drivers/ide/legacy/ali14xx.c1
-rw-r--r--drivers/ide/legacy/dtc2278.c1
-rw-r--r--drivers/ide/legacy/gayle.c1
-rw-r--r--drivers/ide/legacy/hd.c4
-rw-r--r--drivers/ide/legacy/ht6560b.c1
-rw-r--r--drivers/ide/legacy/macide.c1
-rw-r--r--drivers/ide/legacy/qd65xx.c1
-rw-r--r--drivers/ide/legacy/umc8672.c1
-rw-r--r--drivers/ide/mips/au1xxx-ide.c4
-rw-r--r--drivers/ide/pci/aec62xx.c8
-rw-r--r--drivers/ide/pci/alim15x3.c3
-rw-r--r--drivers/ide/pci/amd74xx.c8
-rw-r--r--drivers/ide/pci/atiixp.c22
-rw-r--r--drivers/ide/pci/cmd640.c1
-rw-r--r--drivers/ide/pci/cmd64x.c16
-rw-r--r--drivers/ide/pci/cs5520.c1
-rw-r--r--drivers/ide/pci/cs5530.c1
-rw-r--r--drivers/ide/pci/cs5535.c1
-rw-r--r--drivers/ide/pci/cy82c693.c1
-rw-r--r--drivers/ide/pci/generic.c38
-rw-r--r--drivers/ide/pci/hpt34x.c3
-rw-r--r--drivers/ide/pci/hpt366.c1
-rw-r--r--drivers/ide/pci/it8172.c1
-rw-r--r--drivers/ide/pci/it821x.c14
-rw-r--r--drivers/ide/pci/ns87415.c1
-rw-r--r--drivers/ide/pci/pdc202xx_new.c7
-rw-r--r--drivers/ide/pci/pdc202xx_old.c160
-rw-r--r--drivers/ide/pci/piix.c13
-rw-r--r--drivers/ide/pci/sc1200.c5
-rw-r--r--drivers/ide/pci/serverworks.c44
-rw-r--r--drivers/ide/pci/sgiioc4.c60
-rw-r--r--drivers/ide/pci/siimage.c57
-rw-r--r--drivers/ide/pci/sis5513.c3
-rw-r--r--drivers/ide/pci/sl82c105.c5
-rw-r--r--drivers/ide/pci/slc90e66.c12
-rw-r--r--drivers/ide/pci/triflex.c1
-rw-r--r--drivers/ide/pci/trm290.c1
-rw-r--r--drivers/ide/pci/via82cxxx.c4
-rw-r--r--drivers/ide/ppc/mpc8xx.c1
-rw-r--r--drivers/ide/ppc/pmac.c148
-rw-r--r--drivers/ide/setup-pci.c1
-rw-r--r--drivers/ieee1394/Kconfig2
-rw-r--r--drivers/ieee1394/config_roms.c1
-rw-r--r--drivers/ieee1394/dv1394.c1
-rw-r--r--drivers/ieee1394/eth1394.c3
-rw-r--r--drivers/ieee1394/highlevel.c1
-rw-r--r--drivers/ieee1394/hosts.c13
-rw-r--r--drivers/ieee1394/ieee1394_core.c1
-rw-r--r--drivers/ieee1394/ieee1394_core.h2
-rw-r--r--drivers/ieee1394/nodemgr.c6
-rw-r--r--drivers/ieee1394/ohci1394.c26
-rw-r--r--drivers/ieee1394/oui2c.sh1
-rw-r--r--drivers/ieee1394/pcilynx.c4
-rw-r--r--drivers/ieee1394/pcilynx.h1
-rw-r--r--drivers/ieee1394/raw1394.c3
-rw-r--r--drivers/ieee1394/sbp2.c4
-rw-r--r--drivers/ieee1394/video1394.c1
-rw-r--r--drivers/infiniband/Kconfig6
-rw-r--r--drivers/infiniband/Makefile5
-rw-r--r--drivers/infiniband/core/Makefile4
-rw-r--r--drivers/infiniband/core/addr.c52
-rw-r--r--drivers/infiniband/core/cache.c8
-rw-r--r--drivers/infiniband/core/cm.c92
-rw-r--r--drivers/infiniband/core/cma.c427
-rw-r--r--drivers/infiniband/core/device.c6
-rw-r--r--drivers/infiniband/core/fmr_pool.c8
-rw-r--r--drivers/infiniband/core/iwcm.c1019
-rw-r--r--drivers/infiniband/core/iwcm.h62
-rw-r--r--drivers/infiniband/core/mad.c55
-rw-r--r--drivers/infiniband/core/mad_priv.h2
-rw-r--r--drivers/infiniband/core/mad_rmpp.c97
-rw-r--r--drivers/infiniband/core/sa_query.c80
-rw-r--r--drivers/infiniband/core/smi.c16
-rw-r--r--drivers/infiniband/core/sysfs.c13
-rw-r--r--drivers/infiniband/core/ucm.c9
-rw-r--r--drivers/infiniband/core/user_mad.c94
-rw-r--r--drivers/infiniband/core/uverbs.h2
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c106
-rw-r--r--drivers/infiniband/core/uverbs_main.c14
-rw-r--r--drivers/infiniband/core/verbs.c21
-rw-r--r--drivers/infiniband/hw/amso1100/Kbuild8
-rw-r--r--drivers/infiniband/hw/amso1100/Kconfig15
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c1255
-rw-r--r--drivers/infiniband/hw/amso1100/c2.h551
-rw-r--r--drivers/infiniband/hw/amso1100/c2_ae.c321
-rw-r--r--drivers/infiniband/hw/amso1100/c2_ae.h108
-rw-r--r--drivers/infiniband/hw/amso1100/c2_alloc.c144
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cm.c451
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cq.c433
-rw-r--r--drivers/infiniband/hw/amso1100/c2_intr.c209
-rw-r--r--drivers/infiniband/hw/amso1100/c2_mm.c375
-rw-r--r--drivers/infiniband/hw/amso1100/c2_mq.c174
-rw-r--r--drivers/infiniband/hw/amso1100/c2_mq.h106
-rw-r--r--drivers/infiniband/hw/amso1100/c2_pd.c89
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c874
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.h181
-rw-r--r--drivers/infiniband/hw/amso1100/c2_qp.c975
-rw-r--r--drivers/infiniband/hw/amso1100/c2_rnic.c664
-rw-r--r--drivers/infiniband/hw/amso1100/c2_status.h158
-rw-r--r--drivers/infiniband/hw/amso1100/c2_user.h82
-rw-r--r--drivers/infiniband/hw/amso1100/c2_vq.c260
-rw-r--r--drivers/infiniband/hw/amso1100/c2_vq.h63
-rw-r--r--drivers/infiniband/hw/amso1100/c2_wr.h1520
-rw-r--r--drivers/infiniband/hw/ehca/Kconfig16
-rw-r--r--drivers/infiniband/hw/ehca/Makefile16
-rw-r--r--drivers/infiniband/hw/ehca/ehca_av.c271
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h346
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes_pSeries.h236
-rw-r--r--drivers/infiniband/hw/ehca/ehca_cq.c427
-rw-r--r--drivers/infiniband/hw/ehca/ehca_eq.c185
-rw-r--r--drivers/infiniband/hw/ehca/ehca_hca.c241
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c762
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.h77
-rw-r--r--drivers/infiniband/hw/ehca/ehca_iverbs.h182
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c818
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mcast.c131
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.c2261
-rw-r--r--drivers/infiniband/hw/ehca/ehca_mrmw.h140
-rw-r--r--drivers/infiniband/hw/ehca/ehca_pd.c114
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qes.h259
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c1507
-rw-r--r--drivers/infiniband/hw/ehca/ehca_reqs.c653
-rw-r--r--drivers/infiniband/hw/ehca/ehca_sqp.c111
-rw-r--r--drivers/infiniband/hw/ehca/ehca_tools.h172
-rw-r--r--drivers/infiniband/hw/ehca/ehca_uverbs.c392
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.c874
-rw-r--r--drivers/infiniband/hw/ehca/hcp_if.h261
-rw-r--r--drivers/infiniband/hw/ehca/hcp_phyp.c80
-rw-r--r--drivers/infiniband/hw/ehca/hcp_phyp.h90
-rw-r--r--drivers/infiniband/hw/ehca/hipz_fns.h68
-rw-r--r--drivers/infiniband/hw/ehca/hipz_fns_core.h100
-rw-r--r--drivers/infiniband/hw/ehca/hipz_hw.h388
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.c149
-rw-r--r--drivers/infiniband/hw/ehca/ipz_pt_fn.h247
-rw-r--r--drivers/infiniband/hw/ipath/Kconfig21
-rw-r--r--drivers/infiniband/hw/ipath/Makefile31
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h219
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c213
-rw-r--r--drivers/infiniband/hw/ipath/ipath_debug.h3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c253
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c1086
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c45
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c1215
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c28
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c (renamed from drivers/infiniband/hw/ipath/ipath_ht400.c)192
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c (renamed from drivers/infiniband/hw/ipath/ipath_pe800.c)344
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c143
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c536
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h229
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c81
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.c1175
-rw-r--r--drivers/infiniband/hw/ipath/ipath_layer.h112
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c472
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mmap.c122
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c21
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c346
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c959
-rw-r--r--drivers/infiniband/hw/ipath/ipath_registers.h48
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c417
-rw-r--r--drivers/infiniband/hw/ipath/ipath_srq.c261
-rw-r--r--drivers/infiniband/hw/ipath/ipath_stats.c29
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c177
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c172
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c219
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c68
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c860
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h350
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs_mcast.c46
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_ppc64.c62
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_x86_64.c14
-rw-r--r--drivers/infiniband/hw/ipath/ips_common.h263
-rw-r--r--drivers/infiniband/hw/ipath/verbs_debug.h107
-rw-r--r--drivers/infiniband/hw/mthca/mthca_allocator.c30
-rw-r--r--drivers/infiniband/hw/mthca/mthca_av.c7
-rw-r--r--drivers/infiniband/hw/mthca/mthca_catas.c62
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c7
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h12
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mad.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c100
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h4
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c88
-rw-r--r--drivers/infiniband/hw/mthca/mthca_reset.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c5
-rw-r--r--drivers/infiniband/hw/mthca/mthca_uar.c2
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig3
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_fs.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c194
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c60
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c49
-rw-r--r--drivers/infiniband/ulp/iser/Kconfig12
-rw-r--r--drivers/infiniband/ulp/iser/Makefile4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c660
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h365
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c710
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c483
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c831
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c79
-rw-r--r--drivers/input/evdev.c20
-rw-r--r--drivers/input/gameport/emu10k1-gp.c1
-rw-r--r--drivers/input/gameport/fm801-gp.c4
-rw-r--r--drivers/input/gameport/gameport.c66
-rw-r--r--drivers/input/gameport/ns558.c1
-rw-r--r--drivers/input/input.c141
-rw-r--r--drivers/input/joydev.c69
-rw-r--r--drivers/input/joystick/a3d.c2
-rw-r--r--drivers/input/joystick/analog.c24
-rw-r--r--drivers/input/joystick/cobra.c3
-rw-r--r--drivers/input/joystick/db9.c5
-rw-r--r--drivers/input/joystick/gamecon.c3
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip.c3
-rw-r--r--drivers/input/joystick/guillemot.c2
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c8
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c25
-rw-r--r--drivers/input/joystick/iforce/iforce.h1
-rw-r--r--drivers/input/joystick/interact.c2
-rw-r--r--drivers/input/joystick/magellan.c2
-rw-r--r--drivers/input/joystick/sidewinder.c15
-rw-r--r--drivers/input/joystick/spaceball.c4
-rw-r--r--drivers/input/joystick/spaceorb.c2
-rw-r--r--drivers/input/joystick/stinger.c2
-rw-r--r--drivers/input/joystick/twidjoy.c2
-rw-r--r--drivers/input/joystick/warrior.c2
-rw-r--r--drivers/input/keyboard/Kconfig9
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/atkbd.c322
-rw-r--r--drivers/input/keyboard/corgikbd.c2
-rw-r--r--drivers/input/keyboard/hilkbd.c1
-rw-r--r--drivers/input/keyboard/lkkbd.c9
-rw-r--r--drivers/input/keyboard/locomokbd.c1
-rw-r--r--drivers/input/keyboard/newtonkbd.c2
-rw-r--r--drivers/input/keyboard/omap-keypad.c492
-rw-r--r--drivers/input/keyboard/spitzkbd.c12
-rw-r--r--drivers/input/keyboard/sunkbd.c2
-rw-r--r--drivers/input/keyboard/xtkbd.c2
-rw-r--r--drivers/input/misc/Kconfig2
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c2
-rw-r--r--drivers/input/misc/sparcspkr.c219
-rw-r--r--drivers/input/misc/wistron_btns.c23
-rw-r--r--drivers/input/mouse/alps.c2
-rw-r--r--drivers/input/mouse/inport.c1
-rw-r--r--drivers/input/mouse/logips2pp.c3
-rw-r--r--drivers/input/mouse/psmouse-base.c32
-rw-r--r--drivers/input/mouse/rpcmouse.c2
-rw-r--r--drivers/input/mouse/sermouse.c3
-rw-r--r--drivers/input/mouse/trackpoint.c52
-rw-r--r--drivers/input/mouse/vsxxxaa.c23
-rw-r--r--drivers/input/mousedev.c43
-rw-r--r--drivers/input/power.c1
-rw-r--r--drivers/input/serio/ct82c710.c7
-rw-r--r--drivers/input/serio/gscps2.c3
-rw-r--r--drivers/input/serio/i8042-sparcio.h109
-rw-r--r--drivers/input/serio/i8042.c5
-rw-r--r--drivers/input/serio/i8042.h1
-rw-r--r--drivers/input/serio/libps2.c7
-rw-r--r--drivers/input/serio/pcips2.c2
-rw-r--r--drivers/input/serio/serio.c65
-rw-r--r--drivers/input/serio/serio_raw.c1
-rw-r--r--drivers/input/touchscreen/ads7846.c3
-rw-r--r--drivers/input/touchscreen/corgi_ts.c4
-rw-r--r--drivers/input/touchscreen/gunze.c2
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c8
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c16
-rw-r--r--drivers/input/touchscreen/mtouch.c2
-rw-r--r--drivers/input/tsdev.c23
-rw-r--r--drivers/isdn/capi/capi.c60
-rw-r--r--drivers/isdn/capi/capifs.c2
-rw-r--r--drivers/isdn/capi/capiutil.c1
-rw-r--r--drivers/isdn/divert/divert_procfs.c1
-rw-r--r--drivers/isdn/divert/isdn_divert.c2
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c304
-rw-r--r--drivers/isdn/gigaset/common.c6
-rw-r--r--drivers/isdn/gigaset/ev-layer.c13
-rw-r--r--drivers/isdn/gigaset/gigaset.h4
-rw-r--r--drivers/isdn/gigaset/interface.c6
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c4
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c1
-rw-r--r--drivers/isdn/hardware/avm/b1pci.c5
-rw-r--r--drivers/isdn/hardware/avm/b1pcmcia.c2
-rw-r--r--drivers/isdn/hardware/avm/c4.c3
-rw-r--r--drivers/isdn/hardware/avm/t1pci.c3
-rw-r--r--drivers/isdn/hardware/eicon/capimain.c1
-rw-r--r--drivers/isdn/hardware/eicon/diva_didd.c1
-rw-r--r--drivers/isdn/hardware/eicon/divamnt.c4
-rw-r--r--drivers/isdn/hardware/eicon/divasi.c4
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c6
-rw-r--r--drivers/isdn/hardware/eicon/divasproc.c1
-rw-r--r--drivers/isdn/hardware/eicon/divasync.h1
-rw-r--r--drivers/isdn/hardware/eicon/platform.h1
-rw-r--r--drivers/isdn/hisax/asuscom.c6
-rw-r--r--drivers/isdn/hisax/avm_a1.c2
-rw-r--r--drivers/isdn/hisax/avm_a1p.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c11
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c7
-rw-r--r--drivers/isdn/hisax/bkm_a8.c19
-rw-r--r--drivers/isdn/hisax/config.c3
-rw-r--r--drivers/isdn/hisax/diva.c17
-rw-r--r--drivers/isdn/hisax/elsa.c23
-rw-r--r--drivers/isdn/hisax/elsa_ser.c1
-rw-r--r--drivers/isdn/hisax/enternow_pci.c7
-rw-r--r--drivers/isdn/hisax/gazel.c11
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c5
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c4
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c4
-rw-r--r--drivers/isdn/hisax/hfc_pci.c11
-rw-r--r--drivers/isdn/hisax/hfc_usb.c1
-rw-r--r--drivers/isdn/hisax/hfc_usb.h6
-rw-r--r--drivers/isdn/hisax/hfcscard.c6
-rw-r--r--drivers/isdn/hisax/hisax.h1
-rw-r--r--drivers/isdn/hisax/hisax_debug.h1
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c4
-rw-r--r--drivers/isdn/hisax/icc.c8
-rw-r--r--drivers/isdn/hisax/icc.h2
-rw-r--r--drivers/isdn/hisax/ipacx.c19
-rw-r--r--drivers/isdn/hisax/isdnl3.c1
-rw-r--r--drivers/isdn/hisax/isurf.c4
-rw-r--r--drivers/isdn/hisax/ix1_micro.c6
-rw-r--r--drivers/isdn/hisax/jade.c6
-rw-r--r--drivers/isdn/hisax/l3dss1.c1
-rw-r--r--drivers/isdn/hisax/mic.c2
-rw-r--r--drivers/isdn/hisax/netjet.c2
-rw-r--r--drivers/isdn/hisax/niccy.c7
-rw-r--r--drivers/isdn/hisax/nj_s.c7
-rw-r--r--drivers/isdn/hisax/nj_u.c7
-rw-r--r--drivers/isdn/hisax/q931.c4
-rw-r--r--drivers/isdn/hisax/s0box.c2
-rw-r--r--drivers/isdn/hisax/saphir.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c5
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c2
-rw-r--r--drivers/isdn/hisax/sportster.c4
-rw-r--r--drivers/isdn/hisax/st5481.h1
-rw-r--r--drivers/isdn/hisax/st5481_init.c1
-rw-r--r--drivers/isdn/hisax/teleint.c2
-rw-r--r--drivers/isdn/hisax/teles0.c2
-rw-r--r--drivers/isdn/hisax/teles3.c1
-rw-r--r--drivers/isdn/hisax/telespci.c12
-rw-r--r--drivers/isdn/hisax/w6692.c13
-rw-r--r--drivers/isdn/hysdn/boardergo.c3
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h1
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c1
-rw-r--r--drivers/isdn/i4l/Kconfig1
-rw-r--r--drivers/isdn/i4l/isdn_common.c33
-rw-r--r--drivers/isdn/i4l/isdn_net.c5
-rw-r--r--drivers/isdn/i4l/isdn_ppp.c3
-rw-r--r--drivers/isdn/i4l/isdn_tty.c6
-rw-r--r--drivers/isdn/i4l/isdn_tty.h1
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c4
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c1
-rw-r--r--drivers/isdn/sc/init.c2
-rw-r--r--drivers/leds/Kconfig16
-rw-r--r--drivers/leds/Makefile2
-rw-r--r--drivers/leds/led-class.c1
-rw-r--r--drivers/leds/led-core.c2
-rw-r--r--drivers/leds/led-triggers.c3
-rw-r--r--drivers/leds/leds-corgi.c1
-rw-r--r--drivers/leds/leds-ixp4xx-gpio.c1
-rw-r--r--drivers/leds/leds-locomo.c1
-rw-r--r--drivers/leds/leds-net48xx.c115
-rw-r--r--drivers/leds/leds-s3c24xx.c1
-rw-r--r--drivers/leds/leds-spitz.c1
-rw-r--r--drivers/leds/leds-tosa.c1
-rw-r--r--drivers/leds/ledtrig-heartbeat.c118
-rw-r--r--drivers/leds/ledtrig-timer.c1
-rw-r--r--drivers/macintosh/Kconfig45
-rw-r--r--drivers/macintosh/Makefile4
-rw-r--r--drivers/macintosh/adb.c4
-rw-r--r--drivers/macintosh/adbhid.c41
-rw-r--r--drivers/macintosh/apm_emu.c1
-rw-r--r--drivers/macintosh/mac_hid.c1
-rw-r--r--drivers/macintosh/macio-adb.c19
-rw-r--r--drivers/macintosh/macio_asic.c167
-rw-r--r--drivers/macintosh/macio_sysfs.c9
-rw-r--r--drivers/macintosh/mediabay.c1
-rw-r--r--drivers/macintosh/smu.c75
-rw-r--r--drivers/macintosh/therm_adt746x.c9
-rw-r--r--drivers/macintosh/therm_pm72.c233
-rw-r--r--drivers/macintosh/therm_pm72.h35
-rw-r--r--drivers/macintosh/therm_windtunnel.c5
-rw-r--r--drivers/macintosh/via-cuda.c29
-rw-r--r--drivers/macintosh/via-pmu-backlight.c187
-rw-r--r--drivers/macintosh/via-pmu-event.c80
-rw-r--r--drivers/macintosh/via-pmu-event.h8
-rw-r--r--drivers/macintosh/via-pmu-led.c144
-rw-r--r--drivers/macintosh/via-pmu.c217
-rw-r--r--drivers/macintosh/windfarm_cpufreq_clamp.c1
-rw-r--r--drivers/macintosh/windfarm_pm81.c4
-rw-r--r--drivers/macintosh/windfarm_pm91.c2
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c13
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c15
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c12
-rw-r--r--drivers/md/Kconfig46
-rw-r--r--drivers/md/Makefile5
-rw-r--r--drivers/md/bitmap.c484
-rw-r--r--drivers/md/dm-crypt.c194
-rw-r--r--drivers/md/dm-emc.c40
-rw-r--r--drivers/md/dm-exception-store.c67
-rw-r--r--drivers/md/dm-ioctl.c139
-rw-r--r--drivers/md/dm-linear.c8
-rw-r--r--drivers/md/dm-log.c157
-rw-r--r--drivers/md/dm-mpath.c46
-rw-r--r--drivers/md/dm-raid1.c101
-rw-r--r--drivers/md/dm-round-robin.c6
-rw-r--r--drivers/md/dm-snap.c17
-rw-r--r--drivers/md/dm-stripe.c25
-rw-r--r--drivers/md/dm-table.c57
-rw-r--r--drivers/md/dm-target.c2
-rw-r--r--drivers/md/dm-zero.c8
-rw-r--r--drivers/md/dm.c186
-rw-r--r--drivers/md/dm.h81
-rw-r--r--drivers/md/kcopyd.c5
-rw-r--r--drivers/md/linear.c80
-rw-r--r--drivers/md/md.c754
-rw-r--r--drivers/md/raid1.c104
-rw-r--r--drivers/md/raid10.c81
-rw-r--r--drivers/md/raid5.c1390
-rw-r--r--drivers/md/raid6main.c2427
-rw-r--r--drivers/media/Kconfig6
-rw-r--r--drivers/media/common/Makefile2
-rw-r--r--drivers/media/common/ir-functions.c1
-rw-r--r--drivers/media/common/ir-keymaps.c82
-rw-r--r--drivers/media/common/saa7146_core.c2
-rw-r--r--drivers/media/common/saa7146_fops.c4
-rw-r--r--drivers/media/common/saa7146_hlp.c3
-rw-r--r--drivers/media/common/saa7146_video.c4
-rw-r--r--drivers/media/common/saa7146_vv_ksyms.c12
-rw-r--r--drivers/media/dvb/b2c2/Kconfig1
-rw-r--r--drivers/media/dvb/b2c2/flexcop-common.h1
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c122
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c21
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c10
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c12
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig1
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c13
-rw-r--r--drivers/media/dvb/bt8xx/dst.c658
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c116
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h33
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c118
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h2
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c11
-rw-r--r--drivers/media/dvb/dvb-core/Makefile6
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c3
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c25
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c4
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c193
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h45
-rw-r--r--drivers/media/dvb/dvb-core/dvb_math.c145
-rw-r--r--drivers/media/dvb/dvb-core/dvb_math.h58
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c230
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c18
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h5
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig11
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c48
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c9
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c7
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c15
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u-fe.c8
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c17
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c24
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c1
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h7
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c272
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c256
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h79
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c2
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x-fe.c7
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045-fe.c9
-rw-r--r--drivers/media/dvb/frontends/Kconfig74
-rw-r--r--drivers/media/dvb/frontends/Makefile4
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c4
-rw-r--r--drivers/media/dvb/frontends/bsbe1.h6
-rw-r--r--drivers/media/dvb/frontends/bsru6.h6
-rw-r--r--drivers/media/dvb/frontends/cx22700.c32
-rw-r--r--drivers/media/dvb/frontends/cx22700.h4
-rw-r--r--drivers/media/dvb/frontends/cx22702.c29
-rw-r--r--drivers/media/dvb/frontends/cx22702.h7
-rw-r--r--drivers/media/dvb/frontends/cx24110.c26
-rw-r--r--drivers/media/dvb/frontends/cx24110.h5
-rw-r--r--drivers/media/dvb/frontends/cx24123.c195
-rw-r--r--drivers/media/dvb/frontends/cx24123.h13
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000.h4
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c12
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c15
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c205
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h18
-rw-r--r--drivers/media/dvb/frontends/dvb_dummy_fe.c21
-rw-r--r--drivers/media/dvb/frontends/isl6421.c149
-rw-r--r--drivers/media/dvb/frontends/isl6421.h46
-rw-r--r--drivers/media/dvb/frontends/l64781.c11
-rw-r--r--drivers/media/dvb/frontends/l64781.h4
-rw-r--r--drivers/media/dvb/frontends/lg_h06xf.h64
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c21
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.h1
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c145
-rw-r--r--drivers/media/dvb/frontends/lnbp21.h102
-rw-r--r--drivers/media/dvb/frontends/mt312.c46
-rw-r--r--drivers/media/dvb/frontends/mt312.h4
-rw-r--r--drivers/media/dvb/frontends/mt352.c23
-rw-r--r--drivers/media/dvb/frontends/mt352.h6
-rw-r--r--drivers/media/dvb/frontends/nxt200x.c24
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h4
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c29
-rw-r--r--drivers/media/dvb/frontends/nxt6000.h4
-rw-r--r--drivers/media/dvb/frontends/or51132.c157
-rw-r--r--drivers/media/dvb/frontends/or51132.h2
-rw-r--r--drivers/media/dvb/frontends/or51211.c6
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c43
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h4
-rw-r--r--drivers/media/dvb/frontends/sp8870.c33
-rw-r--r--drivers/media/dvb/frontends/sp8870.h4
-rw-r--r--drivers/media/dvb/frontends/sp887x.c40
-rw-r--r--drivers/media/dvb/frontends/sp887x.h6
-rw-r--r--drivers/media/dvb/frontends/stv0297.c73
-rw-r--r--drivers/media/dvb/frontends/stv0297.h6
-rw-r--r--drivers/media/dvb/frontends/stv0299.c41
-rw-r--r--drivers/media/dvb/frontends/stv0299.h5
-rw-r--r--drivers/media/dvb/frontends/tda10021.c40
-rw-r--r--drivers/media/dvb/frontends/tda10021.h6
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c55
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h5
-rw-r--r--drivers/media/dvb/frontends/tda8083.c12
-rw-r--r--drivers/media/dvb/frontends/tda8083.h4
-rw-r--r--drivers/media/dvb/frontends/ves1820.c20
-rw-r--r--drivers/media/dvb/frontends/ves1820.h4
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c29
-rw-r--r--drivers/media/dvb/frontends/ves1x93.h4
-rw-r--r--drivers/media/dvb/frontends/zl10353.c30
-rw-r--r--drivers/media/dvb/frontends/zl10353.h6
-rw-r--r--drivers/media/dvb/pluto2/Kconfig1
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c17
-rw-r--r--drivers/media/dvb/ttpci/Kconfig8
-rw-r--r--drivers/media/dvb/ttpci/Makefile6
-rw-r--r--drivers/media/dvb/ttpci/av7110.c148
-rw-r--r--drivers/media/dvb/ttpci/av7110.h4
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c25
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c62
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c291
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c61
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c61
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c45
-rw-r--r--drivers/media/dvb/ttpci/budget.c68
-rw-r--r--drivers/media/dvb/ttpci/budget.h7
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig5
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c277
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c8
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c8
-rw-r--r--drivers/media/radio/Kconfig14
-rw-r--r--drivers/media/radio/Makefile3
-rw-r--r--drivers/media/radio/dsbr100.c (renamed from drivers/media/video/dsbr100.c)1
-rw-r--r--drivers/media/radio/miropcm20-radio.c17
-rw-r--r--drivers/media/radio/miropcm20-rds-core.c34
-rw-r--r--drivers/media/radio/miropcm20-rds.c3
-rw-r--r--drivers/media/radio/radio-aimslab.c51
-rw-r--r--drivers/media/radio/radio-aztech.c45
-rw-r--r--drivers/media/radio/radio-cadet.c317
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c48
-rw-r--r--drivers/media/radio/radio-gemtek.c33
-rw-r--r--drivers/media/radio/radio-maestro.c10
-rw-r--r--drivers/media/radio/radio-maxiradio.c81
-rw-r--r--drivers/media/radio/radio-rtrack2.c35
-rw-r--r--drivers/media/radio/radio-sf16fmi.c41
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c5
-rw-r--r--drivers/media/radio/radio-terratec.c63
-rw-r--r--drivers/media/radio/radio-trust.c27
-rw-r--r--drivers/media/radio/radio-typhoon.c5
-rw-r--r--drivers/media/radio/radio-zoltrix.c31
-rw-r--r--drivers/media/video/Kconfig113
-rw-r--r--drivers/media/video/Makefile10
-rw-r--r--drivers/media/video/arv.c5
-rw-r--r--drivers/media/video/bt866.c377
-rw-r--r--drivers/media/video/bt8xx/Kconfig2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c18
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c27
-rw-r--r--drivers/media/video/bt8xx/bttv-gpio.c14
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c1
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c3
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c15
-rw-r--r--drivers/media/video/bt8xx/bttv.h1
-rw-r--r--drivers/media/video/bt8xx/bttvp.h4
-rw-r--r--drivers/media/video/bw-qcam.c3
-rw-r--r--drivers/media/video/c-qcam.c1
-rw-r--r--drivers/media/video/compat_ioctl32.c55
-rw-r--r--drivers/media/video/cpia.c23
-rw-r--r--drivers/media/video/cpia.h3
-rw-r--r--drivers/media/video/cpia2/Kconfig2
-rw-r--r--drivers/media/video/cpia2/cpia2.h1
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c7
-rw-r--r--drivers/media/video/cpia_pp.c9
-rw-r--r--drivers/media/video/cpia_usb.c6
-rw-r--r--drivers/media/video/cx2341x.c932
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c54
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c310
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h8
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c177
-rw-r--r--drivers/media/video/cx88/Kconfig17
-rw-r--r--drivers/media/video/cx88/Makefile5
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c15
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c949
-rw-r--r--drivers/media/video/cx88/cx88-cards.c174
-rw-r--r--drivers/media/video/cx88/cx88-core.c14
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c280
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c10
-rw-r--r--drivers/media/video/cx88/cx88-input.c34
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c56
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c18
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c4
-rw-r--r--drivers/media/video/cx88/cx88-video.c78
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c1
-rw-r--r--drivers/media/video/cx88/cx88.h35
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c64
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c12
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c31
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c8
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c24
-rw-r--r--drivers/media/video/em28xx/em28xx.h8
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c3
-rw-r--r--drivers/media/video/ir-kbd-i2c.c60
-rw-r--r--drivers/media/video/ks0127.c846
-rw-r--r--drivers/media/video/ks0127.h53
-rw-r--r--drivers/media/video/meye.c8
-rw-r--r--drivers/media/video/meye.h1
-rw-r--r--drivers/media/video/msp3400-driver.c122
-rw-r--r--drivers/media/video/msp3400-driver.h4
-rw-r--r--drivers/media/video/msp3400-kthreads.c44
-rw-r--r--drivers/media/video/ov511.c12
-rw-r--r--drivers/media/video/ov511.h1
-rw-r--r--drivers/media/video/planb.c1
-rw-r--r--drivers/media/video/pms.c3
-rw-r--r--drivers/media/video/pvrusb2/Kconfig62
-rw-r--r--drivers/media/video/pvrusb2/Makefile18
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.c204
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-audio.h40
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c230
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.h92
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c593
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.h123
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c279
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h67
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c478
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.h53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.c164
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-eeprom.h40
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c418
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.h42
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h367
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c3098
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h303
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c109
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c232
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h47
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c941
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.h93
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c667
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.h91
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c510
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.h49
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c172
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c408
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.h60
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c926
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.h47
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-tuner.c122
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-tuner.h38
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-util.h63
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c1124
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.h40
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.c253
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-video-v4l.h52
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-wm8775.c170
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-wm8775.h53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2.h43
-rw-r--r--drivers/media/video/pwc/Kconfig13
-rw-r--r--drivers/media/video/pwc/Makefile11
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c699
-rw-r--r--drivers/media/video/pwc/pwc-dec1.c50
-rw-r--r--drivers/media/video/pwc/pwc-dec1.h43
-rw-r--r--drivers/media/video/pwc/pwc-dec23.c941
-rw-r--r--drivers/media/video/pwc/pwc-dec23.h67
-rw-r--r--drivers/media/video/pwc/pwc-if.c1342
-rw-r--r--drivers/media/video/pwc/pwc-kiara.c575
-rw-r--r--drivers/media/video/pwc/pwc-kiara.h8
-rw-r--r--drivers/media/video/pwc/pwc-misc.c67
-rw-r--r--drivers/media/video/pwc/pwc-timon.c1132
-rw-r--r--drivers/media/video/pwc/pwc-timon.h8
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.c154
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.h5
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c1202
-rw-r--r--drivers/media/video/pwc/pwc.h175
-rw-r--r--drivers/media/video/saa5246a.c1
-rw-r--r--drivers/media/video/saa5249.c1
-rw-r--r--drivers/media/video/saa7110.c1
-rw-r--r--drivers/media/video/saa7115.c137
-rw-r--r--drivers/media/video/saa7127.c2
-rw-r--r--drivers/media/video/saa7134/Kconfig1
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c315
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c14
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c58
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c29
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c259
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c24
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c13
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c6
-rw-r--r--drivers/media/video/saa7134/saa7134.h7
-rw-r--r--drivers/media/video/se401.c1
-rw-r--r--drivers/media/video/se401.h1
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c3
-rw-r--r--drivers/media/video/stradis.c8
-rw-r--r--drivers/media/video/stv680.c2
-rw-r--r--drivers/media/video/tda9875.c3
-rw-r--r--drivers/media/video/tda9887.c488
-rw-r--r--drivers/media/video/tea5767.c2
-rw-r--r--drivers/media/video/tlv320aic23b.c217
-rw-r--r--drivers/media/video/tuner-3036.c1
-rw-r--r--drivers/media/video/tuner-core.c67
-rw-r--r--drivers/media/video/tuner-simple.c95
-rw-r--r--drivers/media/video/tuner-types.c94
-rw-r--r--drivers/media/video/tvaudio.c1
-rw-r--r--drivers/media/video/tveeprom.c20
-rw-r--r--drivers/media/video/tvmixer.c8
-rw-r--r--drivers/media/video/tvp5150.c45
-rw-r--r--drivers/media/video/usbvideo/Kconfig18
-rw-r--r--drivers/media/video/usbvideo/Makefile1
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c1120
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.h126
-rw-r--r--drivers/media/video/usbvideo/usbvideo.h2
-rw-r--r--drivers/media/video/v4l1-compat.c6
-rw-r--r--drivers/media/video/v4l2-common.c572
-rw-r--r--drivers/media/video/video-buf-dvb.c5
-rw-r--r--drivers/media/video/videocodec.c1
-rw-r--r--drivers/media/video/videocodec.h16
-rw-r--r--drivers/media/video/videodev.c1307
-rw-r--r--drivers/media/video/vino.c2
-rw-r--r--drivers/media/video/vivi.c664
-rw-r--r--drivers/media/video/vpx3220.c1
-rw-r--r--drivers/media/video/w9966.c1
-rw-r--r--drivers/media/video/w9968cf.c7
-rw-r--r--drivers/media/video/w9968cf.h1
-rw-r--r--drivers/media/video/zc0301/Kconfig6
-rw-r--r--drivers/media/video/zc0301/Makefile2
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c22
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c187
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h26
-rw-r--r--drivers/media/video/zoran.h10
-rw-r--r--drivers/media/video/zoran_card.c92
-rw-r--r--drivers/media/video/zoran_device.c3
-rw-r--r--drivers/media/video/zoran_driver.c50
-rw-r--r--drivers/media/video/zoran_procfs.c2
-rw-r--r--drivers/media/video/zr36120.c2
-rw-r--r--drivers/media/video/zr36120_mem.c1
-rw-r--r--drivers/message/fusion/Kconfig2
-rw-r--r--drivers/message/fusion/Makefile6
-rw-r--r--drivers/message/fusion/lsi/fc_log.h89
-rw-r--r--drivers/message/fusion/lsi/mpi.h5
-rw-r--r--drivers/message/fusion/lsi/mpi_cnfg.h158
-rw-r--r--drivers/message/fusion/lsi/mpi_history.txt76
-rw-r--r--drivers/message/fusion/lsi/mpi_init.h4
-rw-r--r--drivers/message/fusion/lsi/mpi_ioc.h154
-rw-r--r--drivers/message/fusion/lsi/mpi_log_sas.h82
-rw-r--r--drivers/message/fusion/lsi/mpi_sas.h13
-rw-r--r--drivers/message/fusion/lsi/mpi_targ.h5
-rw-r--r--drivers/message/fusion/mptbase.c179
-rw-r--r--drivers/message/fusion/mptbase.h24
-rw-r--r--drivers/message/fusion/mptctl.c4
-rw-r--r--drivers/message/fusion/mptctl.h5
-rw-r--r--drivers/message/fusion/mptfc.c228
-rw-r--r--drivers/message/fusion/mptsas.c1063
-rw-r--r--drivers/message/fusion/mptscsih.c118
-rw-r--r--drivers/message/fusion/mptspi.c14
-rw-r--r--drivers/message/i2o/core.h3
-rw-r--r--drivers/message/i2o/debug.c1
-rw-r--r--drivers/message/i2o/i2o_block.c1
-rw-r--r--drivers/message/i2o/i2o_config.c4
-rw-r--r--drivers/message/i2o/iop.c15
-rw-r--r--drivers/message/i2o/pci.c2
-rw-r--r--drivers/mfd/ucb1x00-core.c9
-rw-r--r--drivers/mfd/ucb1x00-ts.c46
-rw-r--r--drivers/mfd/ucb1x00.h1
-rw-r--r--drivers/misc/ibmasm/ibmasm.h1
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c17
-rw-r--r--drivers/misc/ibmasm/module.c4
-rw-r--r--drivers/mmc/at91_mci.c6
-rw-r--r--drivers/mmc/au1xmmc.c5
-rw-r--r--drivers/mmc/imxmmc.c72
-rw-r--r--drivers/mmc/mmc.c59
-rw-r--r--drivers/mmc/mmc_block.c130
-rw-r--r--drivers/mmc/mmc_queue.c3
-rw-r--r--drivers/mmc/mmci.c22
-rw-r--r--drivers/mmc/omap.c51
-rw-r--r--drivers/mmc/pxamci.c1
-rw-r--r--drivers/mmc/sdhci.c598
-rw-r--r--drivers/mmc/sdhci.h34
-rw-r--r--drivers/mmc/wbsd.c14
-rw-r--r--drivers/mtd/Kconfig14
-rw-r--r--drivers/mtd/Makefile1
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c88
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c113
-rw-r--r--drivers/mtd/chips/cfi_probe.c1
-rw-r--r--drivers/mtd/chips/chipreg.c1
-rw-r--r--drivers/mtd/chips/jedec.c1
-rw-r--r--drivers/mtd/chips/jedec_probe.c15
-rw-r--r--drivers/mtd/chips/map_absent.c3
-rw-r--r--drivers/mtd/chips/map_ram.c1
-rw-r--r--drivers/mtd/chips/map_rom.c1
-rw-r--r--drivers/mtd/devices/block2mtd.c95
-rw-r--r--drivers/mtd/devices/doc2000.c179
-rw-r--r--drivers/mtd/devices/doc2001.c179
-rw-r--r--drivers/mtd/devices/doc2001plus.c164
-rw-r--r--drivers/mtd/devices/docprobe.c1
-rw-r--r--drivers/mtd/devices/m25p80.c12
-rw-r--r--drivers/mtd/devices/ms02-nv.c1
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c2
-rw-r--r--drivers/mtd/devices/mtdram.c1
-rw-r--r--drivers/mtd/devices/phram.c1
-rw-r--r--drivers/mtd/devices/pmc551.c1154
-rw-r--r--drivers/mtd/devices/slram.c1
-rw-r--r--drivers/mtd/inftlcore.c1
-rw-r--r--drivers/mtd/maps/Kconfig22
-rw-r--r--drivers/mtd/maps/Makefile1
-rw-r--r--drivers/mtd/maps/alchemy-flash.c1
-rw-r--r--drivers/mtd/maps/amd76xrom.c11
-rw-r--r--drivers/mtd/maps/arctic-mtd.c14
-rw-r--r--drivers/mtd/maps/beech-mtd.c14
-rw-r--r--drivers/mtd/maps/ceiva.c1
-rw-r--r--drivers/mtd/maps/cstm_mips_ixx.c19
-rw-r--r--drivers/mtd/maps/dbox2-flash.c1
-rw-r--r--drivers/mtd/maps/dc21285.c1
-rw-r--r--drivers/mtd/maps/dilnetpc.c1
-rw-r--r--drivers/mtd/maps/dmv182.c1
-rw-r--r--drivers/mtd/maps/ebony.c5
-rw-r--r--drivers/mtd/maps/edb7312.c1
-rw-r--r--drivers/mtd/maps/fortunet.c3
-rw-r--r--drivers/mtd/maps/h720x-flash.c1
-rw-r--r--drivers/mtd/maps/ichxrom.c9
-rw-r--r--drivers/mtd/maps/impa7.c1
-rw-r--r--drivers/mtd/maps/integrator-flash.c1
-rw-r--r--drivers/mtd/maps/ipaq-flash.c1
-rw-r--r--drivers/mtd/maps/iq80310.c118
-rw-r--r--drivers/mtd/maps/ixp2000.c2
-rw-r--r--drivers/mtd/maps/ixp4xx.c2
-rw-r--r--drivers/mtd/maps/l440gx.c13
-rw-r--r--drivers/mtd/maps/lasat.c3
-rw-r--r--drivers/mtd/maps/mpc1211.c1
-rw-r--r--drivers/mtd/maps/mtx-1_flash.c1
-rw-r--r--drivers/mtd/maps/nettel.c34
-rw-r--r--drivers/mtd/maps/ocotea.c5
-rw-r--r--drivers/mtd/maps/omap-toto-flash.c1
-rw-r--r--drivers/mtd/maps/pcmciamtd.c4
-rw-r--r--drivers/mtd/maps/physmap.c36
-rw-r--r--drivers/mtd/maps/redwood.c12
-rw-r--r--drivers/mtd/maps/sa1100-flash.c1
-rw-r--r--drivers/mtd/maps/sbc8240.c12
-rw-r--r--drivers/mtd/maps/sc520cdp.c1
-rw-r--r--drivers/mtd/maps/scb2_flash.c1
-rw-r--r--drivers/mtd/maps/scx200_docflash.c15
-rw-r--r--drivers/mtd/maps/solutionengine.c1
-rw-r--r--drivers/mtd/maps/sun_uflash.c198
-rw-r--r--drivers/mtd/maps/tqm834x.c1
-rw-r--r--drivers/mtd/maps/tqm8xxl.c1
-rw-r--r--drivers/mtd/maps/ts5500_flash.c1
-rw-r--r--drivers/mtd/maps/uclinux.c1
-rw-r--r--drivers/mtd/maps/walnut.c5
-rw-r--r--drivers/mtd/maps/wr_sbc82xx_flash.c1
-rw-r--r--drivers/mtd/mtdblock.c1
-rw-r--r--drivers/mtd/mtdchar.c12
-rw-r--r--drivers/mtd/mtdcore.c11
-rw-r--r--drivers/mtd/mtdpart.c1
-rw-r--r--drivers/mtd/nand/Kconfig2
-rw-r--r--drivers/mtd/nand/ams-delta.c10
-rw-r--r--drivers/mtd/nand/au1550nd.c11
-rw-r--r--drivers/mtd/nand/edb7312.c3
-rw-r--r--drivers/mtd/nand/nand_base.c44
-rw-r--r--drivers/mtd/nand/nand_ecc.c3
-rw-r--r--drivers/mtd/nand/nandsim.c1
-rw-r--r--drivers/mtd/nand/ndfc.c8
-rw-r--r--drivers/mtd/nand/ppchameleonevb.c7
-rw-r--r--drivers/mtd/nand/s3c2410.c164
-rw-r--r--drivers/mtd/nand/sharpsl.c14
-rw-r--r--drivers/mtd/nand/ts7250.c2
-rw-r--r--drivers/mtd/nftlcore.c1
-rw-r--r--drivers/mtd/ssfdc.c474
-rw-r--r--drivers/net/3c501.c65
-rw-r--r--drivers/net/3c501.h4
-rw-r--r--drivers/net/3c503.c16
-rw-r--r--drivers/net/3c503.h4
-rw-r--r--drivers/net/3c505.c24
-rw-r--r--drivers/net/3c505.h2
-rw-r--r--drivers/net/3c507.c14
-rw-r--r--drivers/net/3c509.c55
-rw-r--r--drivers/net/3c515.c70
-rw-r--r--drivers/net/3c523.c30
-rw-r--r--drivers/net/3c523.h14
-rw-r--r--drivers/net/3c527.c532
-rw-r--r--drivers/net/3c527.h4
-rw-r--r--drivers/net/3c59x.c299
-rw-r--r--drivers/net/7990.c60
-rw-r--r--drivers/net/7990.h24
-rw-r--r--drivers/net/8139cp.c167
-rw-r--r--drivers/net/8139too.c59
-rw-r--r--drivers/net/82596.c22
-rw-r--r--drivers/net/8390.c250
-rw-r--r--drivers/net/8390.h3
-rw-r--r--drivers/net/Kconfig115
-rw-r--r--drivers/net/Makefile16
-rw-r--r--drivers/net/Space.c25
-rw-r--r--drivers/net/a2065.c43
-rw-r--r--drivers/net/a2065.h4
-rw-r--r--drivers/net/ac3200.c9
-rw-r--r--drivers/net/acenic.c61
-rw-r--r--drivers/net/acenic.h7
-rw-r--r--drivers/net/acenic_firmware.h18809
-rw-r--r--drivers/net/amd8111e.c492
-rw-r--r--drivers/net/amd8111e.h102
-rw-r--r--drivers/net/apne.c12
-rw-r--r--drivers/net/appletalk/Kconfig2
-rw-r--r--drivers/net/appletalk/cops.c3
-rw-r--r--drivers/net/appletalk/cops_ffdrv.h1
-rw-r--r--drivers/net/appletalk/cops_ltdrv.h1
-rw-r--r--drivers/net/appletalk/ipddp.c6
-rw-r--r--drivers/net/arcnet/arcnet.c1
-rw-r--r--drivers/net/arcnet/com20020-pci.c5
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/arm/Kconfig7
-rw-r--r--drivers/net/arm/Makefile1
-rw-r--r--drivers/net/arm/at91_ether.c5
-rw-r--r--drivers/net/arm/ep93xx_eth.c944
-rw-r--r--drivers/net/arm/etherh.c2
-rw-r--r--drivers/net/at1700.c33
-rw-r--r--drivers/net/atari_bionet.c14
-rw-r--r--drivers/net/atari_pamsnet.c2
-rw-r--r--drivers/net/atarilance.c22
-rw-r--r--drivers/net/atp.c2
-rw-r--r--drivers/net/au1000_eth.c72
-rw-r--r--drivers/net/au1000_eth.h12
-rw-r--r--drivers/net/b44.c35
-rw-r--r--drivers/net/bmac.c68
-rw-r--r--drivers/net/bmac.h2
-rw-r--r--drivers/net/bnx2.c312
-rw-r--r--drivers/net/bnx2.h95
-rw-r--r--drivers/net/bonding/bond_3ad.c70
-rw-r--r--drivers/net/bonding/bond_main.c233
-rw-r--r--drivers/net/bonding/bond_sysfs.c57
-rw-r--r--drivers/net/bonding/bonding.h34
-rw-r--r--drivers/net/bsd_comp.c68
-rw-r--r--drivers/net/cassini.c572
-rw-r--r--drivers/net/cassini.h766
-rw-r--r--drivers/net/chelsio/common.h1
-rw-r--r--drivers/net/chelsio/cxgb2.c7
-rw-r--r--drivers/net/chelsio/sge.c13
-rw-r--r--drivers/net/cris/eth_v10.c7
-rw-r--r--drivers/net/cs89x0.c86
-rw-r--r--drivers/net/cs89x0.h5
-rw-r--r--drivers/net/de600.c4
-rw-r--r--drivers/net/de620.c38
-rw-r--r--drivers/net/declance.c16
-rw-r--r--drivers/net/defxx.c272
-rw-r--r--drivers/net/defxx.h192
-rw-r--r--drivers/net/depca.c111
-rw-r--r--drivers/net/depca.h28
-rw-r--r--drivers/net/dgrs.c28
-rw-r--r--drivers/net/dgrs.h4
-rw-r--r--drivers/net/dgrs_asstruct.h2
-rw-r--r--drivers/net/dgrs_bcomm.h2
-rw-r--r--drivers/net/dgrs_ether.h4
-rw-r--r--drivers/net/dgrs_i82596.h2
-rw-r--r--drivers/net/dl2k.c213
-rw-r--r--drivers/net/dl2k.h18
-rw-r--r--drivers/net/dm9000.c54
-rw-r--r--drivers/net/dummy.c30
-rw-r--r--drivers/net/e100.c45
-rw-r--r--drivers/net/e1000/e1000.h20
-rw-r--r--drivers/net/e1000/e1000_ethtool.c392
-rw-r--r--drivers/net/e1000/e1000_hw.c2946
-rw-r--r--drivers/net/e1000/e1000_hw.h412
-rw-r--r--drivers/net/e1000/e1000_main.c600
-rw-r--r--drivers/net/e1000/e1000_osdep.h32
-rw-r--r--drivers/net/e1000/e1000_param.c74
-rw-r--r--drivers/net/e2100.c8
-rw-r--r--drivers/net/eepro.c12
-rw-r--r--drivers/net/eepro100.c54
-rw-r--r--drivers/net/eexpress.c101
-rw-r--r--drivers/net/eexpress.h14
-rw-r--r--drivers/net/ehea/Makefile6
-rw-r--r--drivers/net/ehea/ehea.h447
-rw-r--r--drivers/net/ehea/ehea_ethtool.c294
-rw-r--r--drivers/net/ehea/ehea_hcall.h51
-rw-r--r--drivers/net/ehea/ehea_hw.h292
-rw-r--r--drivers/net/ehea/ehea_main.c2654
-rw-r--r--drivers/net/ehea/ehea_phyp.c705
-rw-r--r--drivers/net/ehea/ehea_phyp.h455
-rw-r--r--drivers/net/ehea/ehea_qmr.c582
-rw-r--r--drivers/net/ehea/ehea_qmr.h358
-rw-r--r--drivers/net/epic100.c117
-rw-r--r--drivers/net/eql.c32
-rw-r--r--drivers/net/es3210.c3
-rw-r--r--drivers/net/eth16i.c310
-rw-r--r--drivers/net/ewrk3.c68
-rw-r--r--drivers/net/ewrk3.h30
-rw-r--r--drivers/net/fealnx.c92
-rw-r--r--drivers/net/fec.c389
-rw-r--r--drivers/net/fec.h2
-rw-r--r--drivers/net/fec_8xx/fec_8xx-netta.c1
-rw-r--r--drivers/net/fec_8xx/fec_main.c31
-rw-r--r--drivers/net/fec_8xx/fec_mii.c1
-rw-r--r--drivers/net/forcedeth.c670
-rw-r--r--drivers/net/fs_enet/Makefile6
-rw-r--r--drivers/net/fs_enet/fec.h42
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c212
-rw-r--r--drivers/net/fs_enet/fs_enet-mii.c507
-rw-r--r--drivers/net/fs_enet/fs_enet.h43
-rw-r--r--drivers/net/fs_enet/mac-fcc.c33
-rw-r--r--drivers/net/fs_enet/mac-fec.c143
-rw-r--r--drivers/net/fs_enet/mac-scc.c5
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c449
-rw-r--r--drivers/net/fs_enet/mii-fec.c243
-rw-r--r--drivers/net/fs_enet/mii-fixed.c92
-rw-r--r--drivers/net/gianfar.c14
-rw-r--r--drivers/net/gianfar.h3
-rw-r--r--drivers/net/gianfar_ethtool.c19
-rw-r--r--drivers/net/gianfar_mii.c5
-rw-r--r--drivers/net/gianfar_mii.h2
-rw-r--r--drivers/net/gianfar_sysfs.c3
-rw-r--r--drivers/net/gt64240eth.h402
-rw-r--r--drivers/net/gt96100eth.c1567
-rw-r--r--drivers/net/gt96100eth.h349
-rw-r--r--drivers/net/hamachi.c256
-rw-r--r--drivers/net/hamradio/6pack.c1
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c2
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c2
-rw-r--r--drivers/net/hamradio/bpqether.c8
-rw-r--r--drivers/net/hamradio/dmascc.c2
-rw-r--r--drivers/net/hamradio/mkiss.c1
-rw-r--r--drivers/net/hamradio/scc.c3
-rw-r--r--drivers/net/hamradio/yam.c3
-rw-r--r--drivers/net/hp-plus.c4
-rw-r--r--drivers/net/hp.c2
-rw-r--r--drivers/net/hp100.c157
-rw-r--r--drivers/net/hp100.h44
-rw-r--r--drivers/net/hplance.c12
-rw-r--r--drivers/net/hydra.c2
-rw-r--r--drivers/net/ibm_emac/ibm_emac.h1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c5
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.h1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.c1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.h1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.c1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.h1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_phy.c1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_rgmii.c1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_rgmii.h1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_tah.c1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_tah.h1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_zmii.c1
-rw-r--r--drivers/net/ibm_emac/ibm_emac_zmii.h1
-rw-r--r--drivers/net/ibmlana.c2
-rw-r--r--drivers/net/ibmveth.c6
-rw-r--r--drivers/net/ibmveth.h27
-rw-r--r--drivers/net/ifb.c44
-rw-r--r--drivers/net/ioc3-eth.c13
-rw-r--r--drivers/net/irda/Kconfig3
-rw-r--r--drivers/net/irda/ali-ircc.c11
-rw-r--r--drivers/net/irda/au1k_ir.c1
-rw-r--r--drivers/net/irda/donauboe.c4
-rw-r--r--drivers/net/irda/irda-usb.c20
-rw-r--r--drivers/net/irda/irport.c6
-rw-r--r--drivers/net/irda/mcs7780.c3
-rw-r--r--drivers/net/irda/nsc-ircc.c10
-rw-r--r--drivers/net/irda/pxaficp_ir.c1
-rw-r--r--drivers/net/irda/sa1100_ir.c1
-rw-r--r--drivers/net/irda/smsc-ircc2.c40
-rw-r--r--drivers/net/irda/stir4200.c15
-rw-r--r--drivers/net/irda/via-ircc.c12
-rw-r--r--drivers/net/irda/vlsi_ir.c3
-rw-r--r--drivers/net/irda/vlsi_ir.h2
-rw-r--r--drivers/net/irda/w83977af_ir.c5
-rw-r--r--drivers/net/isa-skeleton.c16
-rw-r--r--drivers/net/iseries_veth.c3
-rw-r--r--drivers/net/ixgb/ixgb.h6
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c8
-rw-r--r--drivers/net/ixgb/ixgb_hw.c17
-rw-r--r--drivers/net/ixgb/ixgb_ids.h1
-rw-r--r--drivers/net/ixgb/ixgb_main.c162
-rw-r--r--drivers/net/ixgb/ixgb_osdep.h12
-rw-r--r--drivers/net/ixp2000/caleb.c1
-rw-r--r--drivers/net/ixp2000/enp2611.c1
-rw-r--r--drivers/net/ixp2000/ixp2400-msf.c1
-rw-r--r--drivers/net/ixp2000/ixpdev.c3
-rw-r--r--drivers/net/ixp2000/pm3386.c1
-rw-r--r--drivers/net/jazzsonic.c14
-rw-r--r--drivers/net/lance.c40
-rw-r--r--drivers/net/lasi_82596.c48
-rw-r--r--drivers/net/lne390.c6
-rw-r--r--drivers/net/loopback.c37
-rw-r--r--drivers/net/lp486e.c30
-rw-r--r--drivers/net/mac8390.c48
-rw-r--r--drivers/net/mac89x0.c18
-rw-r--r--drivers/net/mace.c17
-rw-r--r--drivers/net/macmace.c88
-rw-r--r--drivers/net/macsonic.c38
-rw-r--r--drivers/net/meth.c14
-rw-r--r--drivers/net/mii.c18
-rw-r--r--drivers/net/mipsnet.c2
-rw-r--r--drivers/net/mv643xx_eth.c12
-rw-r--r--drivers/net/mv643xx_eth.h2
-rw-r--r--drivers/net/myri10ge/myri10ge.c302
-rw-r--r--drivers/net/myri10ge/myri10ge_mcp.h47
-rw-r--r--drivers/net/myri_code.h9538
-rw-r--r--drivers/net/myri_sbus.c147
-rw-r--r--drivers/net/myri_sbus.h1
-rw-r--r--drivers/net/natsemi.c257
-rw-r--r--drivers/net/ne-h8300.c2
-rw-r--r--drivers/net/ne.c4
-rw-r--r--drivers/net/ne2.c70
-rw-r--r--drivers/net/ne2k-pci.c23
-rw-r--r--drivers/net/ne3210.c17
-rw-r--r--drivers/net/netx-eth.c3
-rw-r--r--drivers/net/ni5010.c170
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni52.h16
-rw-r--r--drivers/net/ni65.c22
-rw-r--r--drivers/net/ni65.h6
-rw-r--r--drivers/net/ns83820.c88
-rw-r--r--drivers/net/oaknet.c14
-rw-r--r--drivers/net/pci-skeleton.c31
-rw-r--r--drivers/net/pcmcia/3c574_cs.c4
-rw-r--r--drivers/net/pcmcia/3c589_cs.c4
-rw-r--r--drivers/net/pcmcia/axnet_cs.c9
-rw-r--r--drivers/net/pcmcia/com20020_cs.c5
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c8
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c2
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c4
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c21
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c11
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c22
-rw-r--r--drivers/net/pcnet32.c1233
-rw-r--r--drivers/net/phy/Kconfig17
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/cicada.c43
-rw-r--r--drivers/net/phy/davicom.c1
-rw-r--r--drivers/net/phy/fixed.c362
-rw-r--r--drivers/net/phy/lxt.c9
-rw-r--r--drivers/net/phy/marvell.c1
-rw-r--r--drivers/net/phy/mdio_bus.c2
-rw-r--r--drivers/net/phy/phy.c11
-rw-r--r--drivers/net/phy/phy_device.c54
-rw-r--r--drivers/net/phy/qsemi.c1
-rw-r--r--drivers/net/phy/smsc.c1
-rw-r--r--drivers/net/phy/vitesse.c1
-rw-r--r--drivers/net/plip.c42
-rw-r--r--drivers/net/ppp_async.c6
-rw-r--r--drivers/net/ppp_deflate.c4
-rw-r--r--drivers/net/ppp_generic.c59
-rw-r--r--drivers/net/ppp_mppe.c69
-rw-r--r--drivers/net/ppp_synctty.c2
-rw-r--r--drivers/net/pppoe.c17
-rw-r--r--drivers/net/qla3xxx.c3536
-rw-r--r--drivers/net/qla3xxx.h1194
-rw-r--r--drivers/net/r8169.c678
-rw-r--r--drivers/net/rionet.c2
-rw-r--r--drivers/net/rrunner.c55
-rw-r--r--drivers/net/rrunner.h9
-rw-r--r--drivers/net/s2io-regs.h4
-rw-r--r--drivers/net/s2io.c741
-rw-r--r--drivers/net/s2io.h27
-rw-r--r--drivers/net/saa9730.c2
-rw-r--r--drivers/net/saa9730.h16
-rw-r--r--drivers/net/sb1000.c24
-rw-r--r--drivers/net/sb1250-mac.c12
-rw-r--r--drivers/net/seeq8005.c100
-rw-r--r--drivers/net/seeq8005.h4
-rw-r--r--drivers/net/sgiseeq.h4
-rw-r--r--drivers/net/shaper.c105
-rw-r--r--drivers/net/sis190.c9
-rw-r--r--drivers/net/sis900.c229
-rw-r--r--drivers/net/sis900.h18
-rw-r--r--drivers/net/sk98lin/h/xmac_ii.h2
-rw-r--r--drivers/net/sk98lin/skethtool.c2
-rw-r--r--drivers/net/sk98lin/skge.c18
-rw-r--r--drivers/net/sk98lin/skvpd.c2
-rw-r--r--drivers/net/sk_mca.c20
-rw-r--r--drivers/net/sk_mca.h4
-rw-r--r--drivers/net/skfp/h/sba.h2
-rw-r--r--drivers/net/skfp/skfddi.c4
-rw-r--r--drivers/net/skge.c577
-rw-r--r--drivers/net/skge.h42
-rw-r--r--drivers/net/sky2.c485
-rw-r--r--drivers/net/sky2.h37
-rw-r--r--drivers/net/slhc.c35
-rw-r--r--drivers/net/slip.c33
-rw-r--r--drivers/net/slip.h5
-rw-r--r--drivers/net/smc-mca.c10
-rw-r--r--drivers/net/smc-ultra.c7
-rw-r--r--drivers/net/smc-ultra32.c8
-rw-r--r--drivers/net/smc911x.c7
-rw-r--r--drivers/net/smc9194.c4
-rw-r--r--drivers/net/smc9194.h72
-rw-r--r--drivers/net/smc91x.c17
-rw-r--r--drivers/net/smc91x.h70
-rw-r--r--drivers/net/sonic.c22
-rw-r--r--drivers/net/sonic.h5
-rw-r--r--drivers/net/spider_net.c609
-rw-r--r--drivers/net/spider_net.h87
-rw-r--r--drivers/net/spider_net_ethtool.c70
-rw-r--r--drivers/net/starfire.c140
-rw-r--r--drivers/net/stnic.c11
-rw-r--r--drivers/net/sun3_82586.c18
-rw-r--r--drivers/net/sun3_82586.h18
-rw-r--r--drivers/net/sun3lance.c78
-rw-r--r--drivers/net/sunbmac.c131
-rw-r--r--drivers/net/sunbmac.h1
-rw-r--r--drivers/net/sundance.c175
-rw-r--r--drivers/net/sungem.c115
-rw-r--r--drivers/net/sungem.h12
-rw-r--r--drivers/net/sungem_phy.c51
-rw-r--r--drivers/net/sungem_phy.h2
-rw-r--r--drivers/net/sunhme.c443
-rw-r--r--drivers/net/sunhme.h2
-rw-r--r--drivers/net/sunlance.c233
-rw-r--r--drivers/net/sunqe.c472
-rw-r--r--drivers/net/tc35815.c12
-rw-r--r--drivers/net/tg3.c1117
-rw-r--r--drivers/net/tg3.h61
-rw-r--r--drivers/net/tlan.c346
-rw-r--r--drivers/net/tlan.h24
-rw-r--r--drivers/net/tokenring/3c359.c5
-rw-r--r--drivers/net/tokenring/abyss.c2
-rw-r--r--drivers/net/tokenring/ibmtr.c4
-rw-r--r--drivers/net/tokenring/lanstreamer.c64
-rw-r--r--drivers/net/tokenring/lanstreamer.h12
-rw-r--r--drivers/net/tokenring/madgemc.c2
-rw-r--r--drivers/net/tokenring/olympic.c3
-rw-r--r--drivers/net/tokenring/smctr.c10
-rw-r--r--drivers/net/tokenring/smctr_firmware.h1
-rw-r--r--drivers/net/tokenring/tmspci.c2
-rw-r--r--drivers/net/tulip/21142.c6
-rw-r--r--drivers/net/tulip/de2104x.c32
-rw-r--r--drivers/net/tulip/de4x5.c12
-rw-r--r--drivers/net/tulip/dmfe.c8
-rw-r--r--drivers/net/tulip/eeprom.c2
-rw-r--r--drivers/net/tulip/interrupt.c3
-rw-r--r--drivers/net/tulip/media.c2
-rw-r--r--drivers/net/tulip/pnic.c2
-rw-r--r--drivers/net/tulip/pnic2.c2
-rw-r--r--drivers/net/tulip/timer.c16
-rw-r--r--drivers/net/tulip/tulip.h37
-rw-r--r--drivers/net/tulip/tulip_core.c125
-rw-r--r--drivers/net/tulip/uli526x.c18
-rw-r--r--drivers/net/tulip/winbond-840.c145
-rw-r--r--drivers/net/tulip/xircom_cb.c7
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c36
-rw-r--r--drivers/net/tun.c60
-rw-r--r--drivers/net/typhoon-firmware.h7488
-rw-r--r--drivers/net/typhoon.c37
-rw-r--r--drivers/net/typhoon.h4
-rw-r--r--drivers/net/ucc_geth.c4263
-rw-r--r--drivers/net/ucc_geth.h1339
-rw-r--r--drivers/net/ucc_geth_phy.c801
-rw-r--r--drivers/net/ucc_geth_phy.h217
-rw-r--r--drivers/net/via-rhine.c222
-rw-r--r--drivers/net/via-velocity.c351
-rw-r--r--drivers/net/via-velocity.h27
-rw-r--r--drivers/net/wan/Kconfig24
-rw-r--r--drivers/net/wan/Makefile20
-rw-r--r--drivers/net/wan/c101.c35
-rw-r--r--drivers/net/wan/cosa.c15
-rw-r--r--drivers/net/wan/cycx_main.c1
-rw-r--r--drivers/net/wan/dlci.c1
-rw-r--r--drivers/net/wan/dscc4.c16
-rw-r--r--drivers/net/wan/farsync.c4
-rw-r--r--drivers/net/wan/hd6457x.c26
-rw-r--r--drivers/net/wan/hdlc.c (renamed from drivers/net/wan/hdlc_generic.c)233
-rw-r--r--drivers/net/wan/hdlc_cisco.c214
-rw-r--r--drivers/net/wan/hdlc_fr.c401
-rw-r--r--drivers/net/wan/hdlc_ppp.c78
-rw-r--r--drivers/net/wan/hdlc_raw.c51
-rw-r--r--drivers/net/wan/hdlc_raw_eth.c50
-rw-r--r--drivers/net/wan/hdlc_x25.c55
-rw-r--r--drivers/net/wan/hostess_sv11.c2
-rw-r--r--drivers/net/wan/lmc/lmc_main.c4
-rw-r--r--drivers/net/wan/lmc/lmc_media.c1
-rw-r--r--drivers/net/wan/n2.c5
-rw-r--r--drivers/net/wan/pc300.h1
-rw-r--r--drivers/net/wan/pc300_drv.c38
-rw-r--r--drivers/net/wan/pci200syn.c6
-rw-r--r--drivers/net/wan/sbni.c3
-rw-r--r--drivers/net/wan/sdla.c5
-rw-r--r--drivers/net/wan/sealevel.c2
-rw-r--r--drivers/net/wan/syncppp.c5
-rw-r--r--drivers/net/wan/wanxl.c9
-rw-r--r--drivers/net/wd.c16
-rw-r--r--drivers/net/wireless/Kconfig25
-rw-r--r--drivers/net/wireless/Makefile1
-rw-r--r--drivers/net/wireless/airo.c96
-rw-r--r--drivers/net/wireless/airo_cs.c1
-rw-r--r--drivers/net/wireless/airport.c1
-rw-r--r--drivers/net/wireless/arlan-main.c1
-rw-r--r--drivers/net/wireless/arlan-proc.c1
-rw-r--r--drivers/net/wireless/arlan.h1
-rw-r--r--drivers/net/wireless/atmel.c21
-rw-r--r--drivers/net/wireless/atmel_cs.c1
-rw-r--r--drivers/net/wireless/atmel_pci.c3
-rw-r--r--drivers/net/wireless/bcm43xx/Kconfig1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h186
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c82
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.c583
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_dma.h296
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_leds.c10
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c948
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.h30
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c48
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_pio.c4
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_radio.c7
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c178
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c170
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c15
-rw-r--r--drivers/net/wireless/hermes.c1
-rw-r--r--drivers/net/wireless/hostap/hostap.h2
-rw-r--r--drivers/net/wireless/hostap/hostap_cs.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c14
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c12
-rw-r--r--drivers/net/wireless/hostap/hostap_main.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_pci.c3
-rw-r--r--drivers/net/wireless/hostap/hostap_plx.c5
-rw-r--r--drivers/net/wireless/ipw2100.c30
-rw-r--r--drivers/net/wireless/ipw2200.c284
-rw-r--r--drivers/net/wireless/ipw2200.h52
-rw-r--r--drivers/net/wireless/netwave_cs.c1
-rw-r--r--drivers/net/wireless/orinoco.c20
-rw-r--r--drivers/net/wireless/orinoco.h8
-rw-r--r--drivers/net/wireless/orinoco_cs.c1
-rw-r--r--drivers/net/wireless/orinoco_nortel.c5
-rw-r--r--drivers/net/wireless/orinoco_pci.c5
-rw-r--r--drivers/net/wireless/orinoco_pci.h2
-rw-r--r--drivers/net/wireless/orinoco_plx.c5
-rw-r--r--drivers/net/wireless/orinoco_tmd.c5
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c613
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.h6
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h2
-rw-r--r--drivers/net/wireless/prism54/islpci_hotplug.c4
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c1
-rw-r--r--drivers/net/wireless/prism54/prismcompat.h1
-rw-r--r--drivers/net/wireless/ray_cs.c9
-rw-r--r--drivers/net/wireless/spectrum_cs.c40
-rw-r--r--drivers/net/wireless/strip.c11
-rw-r--r--drivers/net/wireless/wavelan_cs.c2
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h1
-rw-r--r--drivers/net/wireless/wl3501_cs.c9
-rw-r--r--drivers/net/wireless/zd1201.c8
-rw-r--r--drivers/net/wireless/zd1211rw/Kconfig19
-rw-r--r--drivers/net/wireless/zd1211rw/Makefile12
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c1655
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h845
-rw-r--r--drivers/net/wireless/zd1211rw/zd_def.h54
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.c191
-rw-r--r--drivers/net/wireless/zd1211rw/zd_ieee80211.h85
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c1132
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h198
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c276
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.h45
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.c156
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf.h83
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al2230.c373
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_al7230b.c274
-rw-r--r--drivers/net/wireless/zd1211rw/zd_rf_rf2959.c279
-rw-r--r--drivers/net/wireless/zd1211rw/zd_types.h71
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c1421
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h243
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.c82
-rw-r--r--drivers/net/wireless/zd1211rw/zd_util.h (renamed from drivers/w1/w1_io.h)27
-rw-r--r--drivers/net/yellowfin.c113
-rw-r--r--drivers/net/znet.c73
-rw-r--r--drivers/net/zorro8390.c2
-rw-r--r--drivers/nubus/nubus.c1
-rw-r--r--drivers/nubus/nubus_syms.c1
-rw-r--r--drivers/oprofile/buffer_sync.c8
-rw-r--r--drivers/oprofile/event_buffer.c12
-rw-r--r--drivers/oprofile/event_buffer.h4
-rw-r--r--drivers/oprofile/oprof.c26
-rw-r--r--drivers/oprofile/oprofilefs.c11
-rw-r--r--drivers/parisc/Kconfig33
-rw-r--r--drivers/parisc/ccio-dma.c1
-rw-r--r--drivers/parisc/dino.c5
-rw-r--r--drivers/parisc/eisa.c4
-rw-r--r--drivers/parisc/gsc.c9
-rw-r--r--drivers/parisc/iosapic.c2
-rw-r--r--drivers/parisc/led.c12
-rw-r--r--drivers/parisc/pdc_stable.c223
-rw-r--r--drivers/parisc/power.c1
-rw-r--r--drivers/parisc/sba_iommu.c18
-rw-r--r--drivers/parisc/superio.c4
-rw-r--r--drivers/parport/Kconfig12
-rw-r--r--drivers/parport/Makefile3
-rw-r--r--drivers/parport/daisy.c2
-rw-r--r--drivers/parport/ieee1284.c1
-rw-r--r--drivers/parport/ieee1284_ops.c1
-rw-r--r--drivers/parport/parport_ax88796.c443
-rw-r--r--drivers/parport/parport_gsc.c2
-rw-r--r--drivers/parport/parport_gsc.h2
-rw-r--r--drivers/parport/parport_mfc3.c2
-rw-r--r--drivers/parport/parport_pc.c3
-rw-r--r--drivers/parport/parport_serial.c4
-rw-r--r--drivers/parport/parport_sunbpp.c136
-rw-r--r--drivers/parport/procfs.c3
-rw-r--r--drivers/parport/share.c3
-rw-r--r--drivers/pci/Kconfig25
-rw-r--r--drivers/pci/bus.c32
-rw-r--r--drivers/pci/hotplug/Kconfig12
-rw-r--r--drivers/pci/hotplug/Makefile3
-rw-r--r--drivers/pci/hotplug/acpiphp.h39
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c22
-rw-r--r--drivers/pci/hotplug/acpiphp_dock.c438
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c252
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c4
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c3
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c55
-rw-r--r--drivers/pci/hotplug/cpcihp_generic.c1
-rw-r--r--drivers/pci/hotplug/cpcihp_zt5550.c15
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c13
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c1
-rw-r--r--drivers/pci/hotplug/cpqphp_nvram.c1
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c1
-rw-r--r--drivers/pci/hotplug/cpqphp_sysfs.c3
-rw-r--r--drivers/pci/hotplug/fakephp.c19
-rw-r--r--drivers/pci/hotplug/pci_hotplug.h4
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c158
-rw-r--r--drivers/pci/hotplug/pciehp.h5
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c12
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c11
-rw-r--r--drivers/pci/hotplug/pcihp_skeleton.c10
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c33
-rw-r--r--drivers/pci/hotplug/shpchp.h2
-rw-r--r--drivers/pci/hotplug/shpchp_core.c6
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c2
-rw-r--r--drivers/pci/hotplug/shpchp_sysfs.c22
-rw-r--r--drivers/pci/msi-apic.c1
-rw-r--r--drivers/pci/msi.c71
-rw-r--r--drivers/pci/pci-driver.c50
-rw-r--r--drivers/pci/pci-sysfs.c158
-rw-r--r--drivers/pci/pci.c78
-rw-r--r--drivers/pci/pci.h18
-rw-r--r--drivers/pci/pcie/Kconfig1
-rw-r--r--drivers/pci/pcie/Makefile3
-rw-r--r--drivers/pci/pcie/aer/Kconfig12
-rw-r--r--drivers/pci/pcie/aer/Makefile8
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c346
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h125
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c68
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c758
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c248
-rw-r--r--drivers/pci/pcie/portdrv.h2
-rw-r--r--drivers/pci/pcie/portdrv_bus.c1
-rw-r--r--drivers/pci/pcie/portdrv_core.c11
-rw-r--r--drivers/pci/pcie/portdrv_pci.c199
-rw-r--r--drivers/pci/probe.c17
-rw-r--r--drivers/pci/proc.c20
-rw-r--r--drivers/pci/quirks.c284
-rw-r--r--drivers/pci/remove.c37
-rw-r--r--drivers/pci/rom.c11
-rw-r--r--drivers/pci/search.c48
-rw-r--r--drivers/pci/setup-bus.c19
-rw-r--r--drivers/pci/setup-res.c34
-rw-r--r--drivers/pcmcia/Kconfig2
-rw-r--r--drivers/pcmcia/at91_cf.c79
-rw-r--r--drivers/pcmcia/au1000_db1x00.c3
-rw-r--r--drivers/pcmcia/au1000_generic.c1
-rw-r--r--drivers/pcmcia/au1000_generic.h1
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c1
-rw-r--r--drivers/pcmcia/cs.c29
-rw-r--r--drivers/pcmcia/hd64465_ss.c8
-rw-r--r--drivers/pcmcia/i82092.c2
-rw-r--r--drivers/pcmcia/i82365.c11
-rw-r--r--drivers/pcmcia/m32r_cfc.c1
-rw-r--r--drivers/pcmcia/m32r_pcc.c1
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c4
-rw-r--r--drivers/pcmcia/omap_cf.c2
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c16
-rw-r--r--drivers/pcmcia/pcmcia_resource.c42
-rw-r--r--drivers/pcmcia/pd6729.c5
-rw-r--r--drivers/pcmcia/pxa2xx_base.c1
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c26
-rw-r--r--drivers/pcmcia/sa1100_generic.c1
-rw-r--r--drivers/pcmcia/sa1111_generic.c1
-rw-r--r--drivers/pcmcia/sa11xx_base.c1
-rw-r--r--drivers/pcmcia/soc_common.c5
-rw-r--r--drivers/pcmcia/tcic.c5
-rw-r--r--drivers/pcmcia/ti113x.h1
-rw-r--r--drivers/pcmcia/vrc4171_card.c2
-rw-r--r--drivers/pcmcia/vrc4173_cardu.c2
-rw-r--r--drivers/pcmcia/yenta_socket.c87
-rw-r--r--drivers/pnp/card.c49
-rw-r--r--drivers/pnp/driver.c1
-rw-r--r--drivers/pnp/interface.c20
-rw-r--r--drivers/pnp/isapnp/compat.c1
-rw-r--r--drivers/pnp/isapnp/core.c1
-rw-r--r--drivers/pnp/isapnp/proc.c1
-rw-r--r--drivers/pnp/manager.c16
-rw-r--r--drivers/pnp/pnpacpi/core.c1
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c19
-rw-r--r--drivers/pnp/pnpbios/core.c2
-rw-r--r--drivers/pnp/pnpbios/rsparser.c1
-rw-r--r--drivers/pnp/quirks.c1
-rw-r--r--drivers/pnp/resource.c12
-rw-r--r--drivers/pnp/support.c1
-rw-r--r--drivers/rapidio/rio-access.c4
-rw-r--r--drivers/rapidio/rio-scan.c1
-rw-r--r--drivers/rapidio/rio-sysfs.c1
-rw-r--r--drivers/rapidio/rio.c1
-rw-r--r--drivers/rtc/Kconfig141
-rw-r--r--drivers/rtc/Makefile12
-rw-r--r--drivers/rtc/class.c3
-rw-r--r--drivers/rtc/interface.c22
-rw-r--r--drivers/rtc/rtc-at91.c407
-rw-r--r--drivers/rtc/rtc-dev.c131
-rw-r--r--drivers/rtc/rtc-ds1307.c388
-rw-r--r--drivers/rtc/rtc-ds1553.c414
-rw-r--r--drivers/rtc/rtc-ds1742.c259
-rw-r--r--drivers/rtc/rtc-isl1208.c591
-rw-r--r--drivers/rtc/rtc-lib.c19
-rw-r--r--drivers/rtc/rtc-max6902.c286
-rw-r--r--drivers/rtc/rtc-pcf8583.c394
-rw-r--r--drivers/rtc/rtc-pl031.c233
-rw-r--r--drivers/rtc/rtc-rs5c348.c253
-rw-r--r--drivers/rtc/rtc-s3c.c621
-rw-r--r--drivers/rtc/rtc-sa1100.c12
-rw-r--r--drivers/rtc/rtc-sh.c467
-rw-r--r--drivers/rtc/rtc-v3020.c264
-rw-r--r--drivers/rtc/rtc-vr41xx.c16
-rw-r--r--drivers/s390/Kconfig30
-rw-r--r--drivers/s390/block/dasd.c310
-rw-r--r--drivers/s390/block/dasd_3370_erp.c27
-rw-r--r--drivers/s390/block/dasd_3990_erp.c189
-rw-r--r--drivers/s390/block/dasd_9336_erp.c27
-rw-r--r--drivers/s390/block/dasd_9343_erp.c2
-rw-r--r--drivers/s390/block/dasd_devmap.c193
-rw-r--r--drivers/s390/block/dasd_diag.c41
-rw-r--r--drivers/s390/block/dasd_diag.h2
-rw-r--r--drivers/s390/block/dasd_eckd.c366
-rw-r--r--drivers/s390/block/dasd_eckd.h24
-rw-r--r--drivers/s390/block/dasd_eer.c8
-rw-r--r--drivers/s390/block/dasd_erp.c9
-rw-r--r--drivers/s390/block/dasd_fba.c54
-rw-r--r--drivers/s390/block/dasd_fba.h2
-rw-r--r--drivers/s390/block/dasd_genhd.c17
-rw-r--r--drivers/s390/block/dasd_int.h41
-rw-r--r--drivers/s390/block/dasd_ioctl.c15
-rw-r--r--drivers/s390/block/dasd_proc.c1
-rw-r--r--drivers/s390/block/xpram.c161
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/con3215.c3
-rw-r--r--drivers/s390/char/con3270.c1
-rw-r--r--drivers/s390/char/ctrlchar.c3
-rw-r--r--drivers/s390/char/defkeymap.c6
-rw-r--r--drivers/s390/char/fs3270.c14
-rw-r--r--drivers/s390/char/keyboard.c7
-rw-r--r--drivers/s390/char/monreader.c1
-rw-r--r--drivers/s390/char/monwriter.c292
-rw-r--r--drivers/s390/char/raw3270.c154
-rw-r--r--drivers/s390/char/raw3270.h2
-rw-r--r--drivers/s390/char/sclp.c41
-rw-r--r--drivers/s390/char/sclp_con.c1
-rw-r--r--drivers/s390/char/sclp_cpi.c1
-rw-r--r--drivers/s390/char/sclp_quiesce.c4
-rw-r--r--drivers/s390/char/sclp_rw.c1
-rw-r--r--drivers/s390/char/sclp_tty.c1
-rw-r--r--drivers/s390/char/sclp_vt220.c1
-rw-r--r--drivers/s390/char/tape.h1
-rw-r--r--drivers/s390/char/tape_34xx.c7
-rw-r--r--drivers/s390/char/tape_3590.c1
-rw-r--r--drivers/s390/char/tape_block.c1
-rw-r--r--drivers/s390/char/tape_char.c1
-rw-r--r--drivers/s390/char/tape_class.c10
-rw-r--r--drivers/s390/char/tape_core.c19
-rw-r--r--drivers/s390/char/tape_proc.c1
-rw-r--r--drivers/s390/char/tape_std.c1
-rw-r--r--drivers/s390/char/tty3270.c29
-rw-r--r--drivers/s390/char/vmcp.c2
-rw-r--r--drivers/s390/char/vmcp.h2
-rw-r--r--drivers/s390/char/vmlogrdr.c6
-rw-r--r--drivers/s390/char/vmwatchdog.c54
-rw-r--r--drivers/s390/cio/blacklist.c36
-rw-r--r--drivers/s390/cio/ccwgroup.c43
-rw-r--r--drivers/s390/cio/chsc.c54
-rw-r--r--drivers/s390/cio/cio.c102
-rw-r--r--drivers/s390/cio/cio.h3
-rw-r--r--drivers/s390/cio/cmf.c628
-rw-r--r--drivers/s390/cio/css.c298
-rw-r--r--drivers/s390/cio/css.h4
-rw-r--r--drivers/s390/cio/device.c147
-rw-r--r--drivers/s390/cio/device.h10
-rw-r--r--drivers/s390/cio/device_fsm.c166
-rw-r--r--drivers/s390/cio/device_id.c39
-rw-r--r--drivers/s390/cio/device_ops.c31
-rw-r--r--drivers/s390/cio/device_pgid.c215
-rw-r--r--drivers/s390/cio/device_status.c8
-rw-r--r--drivers/s390/cio/ioasm.h220
-rw-r--r--drivers/s390/cio/qdio.c7
-rw-r--r--drivers/s390/cio/qdio.h208
-rw-r--r--drivers/s390/crypto/Makefile15
-rw-r--r--drivers/s390/crypto/ap_bus.c1221
-rw-r--r--drivers/s390/crypto/ap_bus.h158
-rw-r--r--drivers/s390/crypto/z90common.h166
-rw-r--r--drivers/s390/crypto/z90crypt.h71
-rw-r--r--drivers/s390/crypto/z90hardware.c2531
-rw-r--r--drivers/s390/crypto/z90main.c3380
-rw-r--r--drivers/s390/crypto/zcrypt_api.c1091
-rw-r--r--drivers/s390/crypto/zcrypt_api.h141
-rw-r--r--drivers/s390/crypto/zcrypt_cca_key.h350
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.c435
-rw-r--r--drivers/s390/crypto/zcrypt_cex2a.h126
-rw-r--r--drivers/s390/crypto/zcrypt_error.h133
-rw-r--r--drivers/s390/crypto/zcrypt_mono.c100
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.c418
-rw-r--r--drivers/s390/crypto/zcrypt_pcica.h117
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.c630
-rw-r--r--drivers/s390/crypto/zcrypt_pcicc.h176
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c951
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.h79
-rw-r--r--drivers/s390/net/Kconfig9
-rw-r--r--drivers/s390/net/Makefile1
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcmain.c24
-rw-r--r--drivers/s390/net/fsm.c1
-rw-r--r--drivers/s390/net/iucv.c46
-rw-r--r--drivers/s390/net/lcs.c20
-rw-r--r--drivers/s390/net/netiucv.c82
-rw-r--r--drivers/s390/net/qeth.h73
-rw-r--r--drivers/s390/net/qeth_eddp.c6
-rw-r--r--drivers/s390/net/qeth_main.c557
-rw-r--r--drivers/s390/net/qeth_proc.c23
-rw-r--r--drivers/s390/net/qeth_sys.c68
-rw-r--r--drivers/s390/net/qeth_tso.h2
-rw-r--r--drivers/s390/net/smsgiucv.c14
-rw-r--r--drivers/s390/s390mach.c125
-rw-r--r--drivers/s390/scsi/zfcp_aux.c204
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c18
-rw-r--r--drivers/s390/scsi/zfcp_dbf.c13
-rw-r--r--drivers/s390/scsi/zfcp_def.h45
-rw-r--r--drivers/s390/scsi/zfcp_erp.c397
-rw-r--r--drivers/s390/scsi/zfcp_ext.h25
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c415
-rw-r--r--drivers/s390/scsi/zfcp_qdio.c78
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c174
-rw-r--r--drivers/s390/sysinfo.c456
-rw-r--r--drivers/sbus/char/aurora.c12
-rw-r--r--drivers/sbus/char/bbc_envctrl.c4
-rw-r--r--drivers/sbus/char/bbc_i2c.c6
-rw-r--r--drivers/sbus/char/bpp.c9
-rw-r--r--drivers/sbus/char/cpwatchdog.c4
-rw-r--r--drivers/sbus/char/display7seg.c2
-rw-r--r--drivers/sbus/char/envctrl.c72
-rw-r--r--drivers/sbus/char/flash.c18
-rw-r--r--drivers/sbus/char/openprom.c601
-rw-r--r--drivers/sbus/char/riowatchdog.c4
-rw-r--r--drivers/sbus/char/vfc.h2
-rw-r--r--drivers/sbus/char/vfc_dev.c9
-rw-r--r--drivers/sbus/dvma.c1
-rw-r--r--drivers/sbus/sbus.c583
-rw-r--r--drivers/scsi/3w-9xxx.c2
-rw-r--r--drivers/scsi/3w-xxxx.c2
-rw-r--r--drivers/scsi/53c700.c57
-rw-r--r--drivers/scsi/53c700.h34
-rw-r--r--drivers/scsi/53c7xx.c13
-rw-r--r--drivers/scsi/BusLogic.c64
-rw-r--r--drivers/scsi/BusLogic.h1
-rw-r--r--drivers/scsi/FlashPoint.c1
-rw-r--r--drivers/scsi/Kconfig174
-rw-r--r--drivers/scsi/Makefile22
-rw-r--r--drivers/scsi/NCR5380.c4
-rw-r--r--drivers/scsi/NCR53C9x.c19
-rw-r--r--drivers/scsi/NCR53C9x.h1
-rw-r--r--drivers/scsi/NCR_D700.c16
-rw-r--r--drivers/scsi/NCR_Q720.c2
-rw-r--r--drivers/scsi/a100u2w.c2
-rw-r--r--drivers/scsi/a2091.c8
-rw-r--r--drivers/scsi/a2091.h4
-rw-r--r--drivers/scsi/a3000.c10
-rw-r--r--drivers/scsi/a3000.h4
-rw-r--r--drivers/scsi/aacraid/aachba.c60
-rw-r--r--drivers/scsi/aacraid/aacraid.h20
-rw-r--r--drivers/scsi/aacraid/commctrl.c25
-rw-r--r--drivers/scsi/aacraid/comminit.c36
-rw-r--r--drivers/scsi/aacraid/commsup.c280
-rw-r--r--drivers/scsi/aacraid/dpcsup.c10
-rw-r--r--drivers/scsi/aacraid/linit.c35
-rw-r--r--drivers/scsi/aacraid/rkt.c446
-rw-r--r--drivers/scsi/aacraid/rx.c119
-rw-r--r--drivers/scsi/aacraid/sa.c23
-rw-r--r--drivers/scsi/advansys.c117
-rw-r--r--drivers/scsi/aha152x.c100
-rw-r--r--drivers/scsi/aha1542.c1
-rw-r--r--drivers/scsi/aha1740.c3
-rw-r--r--drivers/scsi/aic7xxx/aic7770_osm.c5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h1
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c26
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c87
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h13
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c19
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c24
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h1
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aicasm/Makefile2
-rw-r--r--drivers/scsi/aic7xxx_old.c15
-rw-r--r--drivers/scsi/aic7xxx_old/aic7xxx_proc.c1
-rw-r--r--drivers/scsi/aic94xx/Kconfig41
-rw-r--r--drivers/scsi/aic94xx/Makefile39
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h114
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dev.c353
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.c959
-rw-r--r--drivers/scsi/aic94xx/aic94xx_dump.h52
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c1376
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h397
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c866
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg.c332
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg.h302
-rw-r--r--drivers/scsi/aic94xx/aic94xx_reg_def.h2398
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sas.h785
-rw-r--r--drivers/scsi/aic94xx/aic94xx_scb.c758
-rw-r--r--drivers/scsi/aic94xx/aic94xx_sds.c1089
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.c1404
-rw-r--r--drivers/scsi/aic94xx/aic94xx_seq.h70
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c642
-rw-r--r--drivers/scsi/aic94xx/aic94xx_tmf.c636
-rw-r--r--drivers/scsi/amiga7xx.c1
-rw-r--r--drivers/scsi/arcmsr/Makefile6
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h472
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c381
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c1496
-rw-r--r--drivers/scsi/arm/Kconfig3
-rw-r--r--drivers/scsi/arm/acornscsi.c3
-rw-r--r--drivers/scsi/arm/cumana_1.c2
-rw-r--r--drivers/scsi/arm/cumana_2.c2
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/arm/powertec.c2
-rw-r--r--drivers/scsi/arm/scsi.h2
-rw-r--r--drivers/scsi/atari_NCR5380.c3
-rw-r--r--drivers/scsi/atari_scsi.c1
-rw-r--r--drivers/scsi/atp870u.c163
-rw-r--r--drivers/scsi/blz1230.c2
-rw-r--r--drivers/scsi/blz2060.c2
-rw-r--r--drivers/scsi/ch.c1
-rw-r--r--drivers/scsi/constants.c127
-rw-r--r--drivers/scsi/cyberstorm.c2
-rw-r--r--drivers/scsi/cyberstormII.c2
-rw-r--r--drivers/scsi/dc395x.c4
-rw-r--r--drivers/scsi/dec_esp.c10
-rw-r--r--drivers/scsi/dmx3191d.c2
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h1
-rw-r--r--drivers/scsi/dpt_i2o.c9
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/eata.c3
-rw-r--r--drivers/scsi/eata_generic.h1
-rw-r--r--drivers/scsi/eata_pio.c132
-rw-r--r--drivers/scsi/esp.c335
-rw-r--r--drivers/scsi/esp.h4
-rw-r--r--drivers/scsi/fastlane.c2
-rw-r--r--drivers/scsi/fcal.c4
-rw-r--r--drivers/scsi/fd_mcs.c2
-rw-r--r--drivers/scsi/fdomain.c3
-rw-r--r--drivers/scsi/g_NCR5380.c6
-rw-r--r--drivers/scsi/g_NCR5380.h1
-rw-r--r--drivers/scsi/gdth.c6
-rw-r--r--drivers/scsi/gvp11.c10
-rw-r--r--drivers/scsi/gvp11.h4
-rw-r--r--drivers/scsi/hosts.c7
-rw-r--r--drivers/scsi/hptiop.c571
-rw-r--r--drivers/scsi/ibmmca.c15
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c64
-rw-r--r--drivers/scsi/ibmvscsi/iseries_vscsi.c2
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c17
-rw-r--r--drivers/scsi/ide-scsi.c3
-rw-r--r--drivers/scsi/imm.c4
-rw-r--r--drivers/scsi/imm.h2
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/initio.c3
-rw-r--r--drivers/scsi/initio.h13
-rw-r--r--drivers/scsi/ipr.c37
-rw-r--r--drivers/scsi/ipr.h82
-rw-r--r--drivers/scsi/ips.c9
-rw-r--r--drivers/scsi/iscsi_tcp.c1134
-rw-r--r--drivers/scsi/iscsi_tcp.h46
-rw-r--r--drivers/scsi/jazz_esp.c4
-rw-r--r--drivers/scsi/lasi700.c2
-rw-r--r--drivers/scsi/libiscsi.c533
-rw-r--r--drivers/scsi/libsas/Kconfig39
-rw-r--r--drivers/scsi/libsas/Makefile36
-rw-r--r--drivers/scsi/libsas/sas_discover.c749
-rw-r--r--drivers/scsi/libsas/sas_dump.c76
-rw-r--r--drivers/scsi/libsas/sas_dump.h42
-rw-r--r--drivers/scsi/libsas/sas_event.c75
-rw-r--r--drivers/scsi/libsas/sas_expander.c1855
-rw-r--r--drivers/scsi/libsas/sas_init.c267
-rw-r--r--drivers/scsi/libsas/sas_internal.h146
-rw-r--r--drivers/scsi/libsas/sas_phy.c158
-rw-r--r--drivers/scsi/libsas/sas_port.c279
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c786
-rw-r--r--drivers/scsi/lpfc/lpfc.h18
-rw-r--r--drivers/scsi/lpfc/lpfc_attr.c475
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h5
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c38
-rw-r--r--drivers/scsi/lpfc/lpfc_disc.h6
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c97
-rw-r--r--drivers/scsi/lpfc/lpfc_hbadisc.c205
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c87
-rw-r--r--drivers/scsi/lpfc/lpfc_mbox.c16
-rw-r--r--drivers/scsi/lpfc/lpfc_mem.c5
-rw-r--r--drivers/scsi/lpfc/lpfc_nportdisc.c37
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c115
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c112
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.h22
-rw-r--r--drivers/scsi/lpfc/lpfc_version.h2
-rw-r--r--drivers/scsi/mac53c94.c4
-rw-r--r--drivers/scsi/mac_esp.c7
-rw-r--r--drivers/scsi/mac_scsi.c7
-rw-r--r--drivers/scsi/megaraid.c11
-rw-r--r--drivers/scsi/megaraid/mega_common.h6
-rw-r--r--drivers/scsi/megaraid/megaraid_ioctl.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c62
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_mm.h4
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c52
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h21
-rw-r--r--drivers/scsi/mesh.c23
-rw-r--r--drivers/scsi/mvme147.c6
-rw-r--r--drivers/scsi/mvme147.h4
-rw-r--r--drivers/scsi/ncr53c8xx.c3
-rw-r--r--drivers/scsi/ncr53c8xx.h2
-rw-r--r--drivers/scsi/nsp32.c12
-rw-r--r--drivers/scsi/oktagon_esp.c3
-rw-r--r--drivers/scsi/oktagon_io.S1
-rw-r--r--drivers/scsi/osst.h1
-rw-r--r--drivers/scsi/pas16.c2
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c2
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c2
-rw-r--r--drivers/scsi/pluto.c3
-rw-r--r--drivers/scsi/ppa.c3
-rw-r--r--drivers/scsi/ppa.h2
-rw-r--r--drivers/scsi/qla1280.c7
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c120
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.c925
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h151
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h22
-rw-r--r--drivers/scsi/qla2xxx/qla_devtbl.h17
-rw-r--r--drivers/scsi/qla2xxx/qla_fw.h4
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h26
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c157
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c4
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c29
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c280
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c142
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h4
-rw-r--r--drivers/scsi/qlogicpti.c367
-rw-r--r--drivers/scsi/scsi.c61
-rw-r--r--drivers/scsi/scsi.h2
-rw-r--r--drivers/scsi/scsi_debug.c1456
-rw-r--r--drivers/scsi/scsi_devinfo.c2
-rw-r--r--drivers/scsi/scsi_error.c242
-rw-r--r--drivers/scsi/scsi_ioctl.c5
-rw-r--r--drivers/scsi/scsi_lib.c220
-rw-r--r--drivers/scsi/scsi_logging.h1
-rw-r--r--drivers/scsi/scsi_netlink.c199
-rw-r--r--drivers/scsi/scsi_priv.h15
-rw-r--r--drivers/scsi/scsi_proc.c4
-rw-r--r--drivers/scsi/scsi_sas_internal.h10
-rw-r--r--drivers/scsi/scsi_scan.c148
-rw-r--r--drivers/scsi/scsi_sysfs.c1
-rw-r--r--drivers/scsi/scsi_transport_fc.c408
-rw-r--r--drivers/scsi/scsi_transport_iscsi.c663
-rw-r--r--drivers/scsi/scsi_transport_sas.c510
-rw-r--r--drivers/scsi/scsi_transport_spi.c31
-rw-r--r--drivers/scsi/scsicam.c3
-rw-r--r--drivers/scsi/sd.c175
-rw-r--r--drivers/scsi/seagate.c4
-rw-r--r--drivers/scsi/sg.c19
-rw-r--r--drivers/scsi/sgiwd93.c8
-rw-r--r--drivers/scsi/sim710.c4
-rw-r--r--drivers/scsi/sr.c7
-rw-r--r--drivers/scsi/sr_vendor.c1
-rw-r--r--drivers/scsi/st.c10
-rw-r--r--drivers/scsi/st.h1
-rw-r--r--drivers/scsi/stex.c1252
-rw-r--r--drivers/scsi/sun3_NCR5380.c3
-rw-r--r--drivers/scsi/sun3x_esp.c12
-rw-r--r--drivers/scsi/sym53c8xx_2/sym53c8xx.h1
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c4
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.h1
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/tmscsim.c3
-rw-r--r--drivers/scsi/tmscsim.h1
-rw-r--r--drivers/scsi/u14-34f.c3
-rw-r--r--drivers/scsi/ultrastor.c23
-rw-r--r--drivers/scsi/ultrastor.h12
-rw-r--r--drivers/scsi/wd33c93.c3
-rw-r--r--drivers/scsi/wd33c93.h1
-rw-r--r--drivers/scsi/wd7000.c4
-rw-r--r--drivers/scsi/zalon.c2
-rw-r--r--drivers/serial/21285.c2
-rw-r--r--drivers/serial/68328serial.c103
-rw-r--r--drivers/serial/68328serial.h1
-rw-r--r--drivers/serial/68360serial.c1
-rw-r--r--drivers/serial/8250.c31
-rw-r--r--drivers/serial/8250.h1
-rw-r--r--drivers/serial/8250_mca.c1
-rw-r--r--drivers/serial/8250_pci.c55
-rw-r--r--drivers/serial/8250_pnp.c6
-rw-r--r--drivers/serial/Kconfig20
-rw-r--r--drivers/serial/amba-pl010.c1
-rw-r--r--drivers/serial/amba-pl011.c1
-rw-r--r--drivers/serial/at91_serial.c11
-rw-r--r--drivers/serial/clps711x.c1
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c1
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c1
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c1
-rw-r--r--drivers/serial/crisv10.c31
-rw-r--r--drivers/serial/crisv10.h1
-rw-r--r--drivers/serial/dz.c9
-rw-r--r--drivers/serial/icom.c3
-rw-r--r--drivers/serial/imx.c4
-rw-r--r--drivers/serial/ioc4_serial.c2
-rw-r--r--drivers/serial/ip22zilog.c5
-rw-r--r--drivers/serial/jsm/jsm_driver.c2
-rw-r--r--drivers/serial/jsm/jsm_tty.c7
-rw-r--r--drivers/serial/m32r_sio.c4
-rw-r--r--drivers/serial/m32r_sio.h1
-rw-r--r--drivers/serial/m32r_sio_reg.h1
-rw-r--r--drivers/serial/mcfserial.c31
-rw-r--r--drivers/serial/mcfserial.h1
-rw-r--r--drivers/serial/mpc52xx_uart.c7
-rw-r--r--drivers/serial/mpsc.c5
-rw-r--r--drivers/serial/mux.c1
-rw-r--r--drivers/serial/pmac_zilog.c19
-rw-r--r--drivers/serial/pxa.c4
-rw-r--r--drivers/serial/s3c2410.c146
-rw-r--r--drivers/serial/sa1100.c2
-rw-r--r--drivers/serial/serial_core.c41
-rw-r--r--drivers/serial/serial_cs.c1
-rw-r--r--drivers/serial/serial_lh7a40x.c1
-rw-r--r--drivers/serial/serial_txx9.c6
-rw-r--r--drivers/serial/sh-sci.c1148
-rw-r--r--drivers/serial/sh-sci.h89
-rw-r--r--drivers/serial/sn_console.c3
-rw-r--r--drivers/serial/suncore.c1
-rw-r--r--drivers/serial/sunhv.c166
-rw-r--r--drivers/serial/sunsab.c311
-rw-r--r--drivers/serial/sunsu.c525
-rw-r--r--drivers/serial/sunzilog.c837
-rw-r--r--drivers/serial/v850e_uart.c5
-rw-r--r--drivers/serial/vr41xx_siu.c3
-rw-r--r--drivers/sn/ioc3.c9
-rw-r--r--drivers/sn/ioc4.c2
-rw-r--r--drivers/spi/spi.c3
-rw-r--r--drivers/spi/spi_bitbang.c1
-rw-r--r--drivers/spi/spi_butterfly.c1
-rw-r--r--drivers/tc/lk201.c1
-rw-r--r--drivers/tc/zs.c6
-rw-r--r--drivers/telephony/ixj.c2
-rw-r--r--drivers/telephony/phonedev.c4
-rw-r--r--drivers/usb/Kconfig4
-rw-r--r--drivers/usb/Makefile14
-rw-r--r--drivers/usb/atm/ueagle-atm.c74
-rw-r--r--drivers/usb/class/cdc-acm.c52
-rw-r--r--drivers/usb/class/usblp.c15
-rw-r--r--drivers/usb/core/Kconfig3
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/buffer.c5
-rw-r--r--drivers/usb/core/config.c5
-rw-r--r--drivers/usb/core/devices.c6
-rw-r--r--drivers/usb/core/devio.c102
-rw-r--r--drivers/usb/core/driver.c1013
-rw-r--r--drivers/usb/core/endpoint.c30
-rw-r--r--drivers/usb/core/file.c16
-rw-r--r--drivers/usb/core/generic.c208
-rw-r--r--drivers/usb/core/hcd-pci.c21
-rw-r--r--drivers/usb/core/hcd.c251
-rw-r--r--drivers/usb/core/hcd.h60
-rw-r--r--drivers/usb/core/hub.c566
-rw-r--r--drivers/usb/core/hub.h3
-rw-r--r--drivers/usb/core/inode.c24
-rw-r--r--drivers/usb/core/message.c149
-rw-r--r--drivers/usb/core/notify.c4
-rw-r--r--drivers/usb/core/sysfs.c61
-rw-r--r--drivers/usb/core/urb.c16
-rw-r--r--drivers/usb/core/usb.c570
-rw-r--r--drivers/usb/core/usb.h94
-rw-r--r--drivers/usb/gadget/Kconfig18
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/at91_udc.c183
-rw-r--r--drivers/usb/gadget/at91_udc.h1
-rw-r--r--drivers/usb/gadget/dummy_hcd.c48
-rw-r--r--drivers/usb/gadget/epautoconf.c16
-rw-r--r--drivers/usb/gadget/ether.c63
-rw-r--r--drivers/usb/gadget/file_storage.c38
-rw-r--r--drivers/usb/gadget/gmidi.c1337
-rw-r--r--drivers/usb/gadget/goku_udc.c3
-rw-r--r--drivers/usb/gadget/inode.c67
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c4
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.h1
-rw-r--r--drivers/usb/gadget/net2280.c159
-rw-r--r--drivers/usb/gadget/omap_udc.c13
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c79
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h24
-rw-r--r--drivers/usb/gadget/rndis.c3
-rw-r--r--drivers/usb/gadget/rndis.h2
-rw-r--r--drivers/usb/gadget/serial.c9
-rw-r--r--drivers/usb/gadget/zero.c3
-rw-r--r--drivers/usb/host/Kconfig29
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-au1xxx.c27
-rw-r--r--drivers/usb/host/ehci-dbg.c31
-rw-r--r--drivers/usb/host/ehci-fsl.c4
-rw-r--r--drivers/usb/host/ehci-hcd.c105
-rw-r--r--drivers/usb/host/ehci-hub.c14
-rw-r--r--drivers/usb/host/ehci-mem.c14
-rw-r--r--drivers/usb/host/ehci-pci.c10
-rw-r--r--drivers/usb/host/ehci-q.c26
-rw-r--r--drivers/usb/host/ehci-sched.c26
-rw-r--r--drivers/usb/host/ehci.h59
-rw-r--r--drivers/usb/host/hc_crisv10.c4
-rw-r--r--drivers/usb/host/isp116x-hcd.c6
-rw-r--r--drivers/usb/host/isp116x.h2
-rw-r--r--drivers/usb/host/ohci-at91.c95
-rw-r--r--drivers/usb/host/ohci-au1xxx.c15
-rw-r--r--drivers/usb/host/ohci-dbg.c18
-rw-r--r--drivers/usb/host/ohci-ep93xx.c228
-rw-r--r--drivers/usb/host/ohci-hcd.c73
-rw-r--r--drivers/usb/host/ohci-hub.c277
-rw-r--r--drivers/usb/host/ohci-lh7a404.c9
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-omap.c124
-rw-r--r--drivers/usb/host/ohci-pci.c16
-rw-r--r--drivers/usb/host/ohci-pnx4008.c476
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c5
-rw-r--r--drivers/usb/host/ohci-pxa27x.c5
-rw-r--r--drivers/usb/host/ohci-s3c2410.c7
-rw-r--r--drivers/usb/host/ohci-sa1111.c7
-rw-r--r--drivers/usb/host/ohci.h5
-rw-r--r--drivers/usb/host/pci-quirks.c9
-rw-r--r--drivers/usb/host/sl811-hcd.c26
-rw-r--r--drivers/usb/host/u132-hcd.c3295
-rw-r--r--drivers/usb/host/uhci-debug.c7
-rw-r--r--drivers/usb/host/uhci-hcd.c13
-rw-r--r--drivers/usb/host/uhci-hub.c12
-rw-r--r--drivers/usb/host/uhci-q.c8
-rw-r--r--drivers/usb/image/mdc800.c4
-rw-r--r--drivers/usb/image/microtek.c18
-rw-r--r--drivers/usb/image/microtek.h4
-rw-r--r--drivers/usb/input/Kconfig30
-rw-r--r--drivers/usb/input/Makefile2
-rw-r--r--drivers/usb/input/acecad.c5
-rw-r--r--drivers/usb/input/appletouch.c8
-rw-r--r--drivers/usb/input/ati_remote.c183
-rw-r--r--drivers/usb/input/fixp-arith.h15
-rw-r--r--drivers/usb/input/hid-core.c181
-rw-r--r--drivers/usb/input/hid-debug.h2
-rw-r--r--drivers/usb/input/hid-input.c3
-rw-r--r--drivers/usb/input/hiddev.c75
-rw-r--r--drivers/usb/input/itmtouch.c3
-rw-r--r--drivers/usb/input/keyspan_remote.c4
-rw-r--r--drivers/usb/input/mtouchusb.c3
-rw-r--r--drivers/usb/input/powermate.c4
-rw-r--r--drivers/usb/input/touchkitusb.c3
-rw-r--r--drivers/usb/input/trancevibrator.c159
-rw-r--r--drivers/usb/input/usbmouse.c2
-rw-r--r--drivers/usb/input/usbtouchscreen.c287
-rw-r--r--drivers/usb/input/wacom.c1003
-rw-r--r--drivers/usb/input/wacom.h132
-rw-r--r--drivers/usb/input/wacom_sys.c315
-rw-r--r--drivers/usb/input/wacom_wac.c646
-rw-r--r--drivers/usb/input/wacom_wac.h48
-rw-r--r--drivers/usb/input/xpad.c1
-rw-r--r--drivers/usb/input/yealink.c15
-rw-r--r--drivers/usb/misc/Kconfig71
-rw-r--r--drivers/usb/misc/Makefile7
-rw-r--r--drivers/usb/misc/adutux.c900
-rw-r--r--drivers/usb/misc/auerswald.c6
-rw-r--r--drivers/usb/misc/cy7c63.c244
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c295
-rw-r--r--drivers/usb/misc/cytherm.c36
-rw-r--r--drivers/usb/misc/ftdi-elan.c2809
-rw-r--r--drivers/usb/misc/idmouse.c3
-rw-r--r--drivers/usb/misc/ldusb.c11
-rw-r--r--drivers/usb/misc/legousbtower.c3
-rw-r--r--drivers/usb/misc/phidget.c43
-rw-r--r--drivers/usb/misc/phidget.h12
-rw-r--r--drivers/usb/misc/phidgetkit.c373
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c466
-rw-r--r--drivers/usb/misc/phidgetservo.c118
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c4
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_init.c1
-rw-r--r--drivers/usb/misc/usb_u132.h97
-rw-r--r--drivers/usb/misc/usblcd.c16
-rw-r--r--drivers/usb/misc/usbled.c21
-rw-r--r--drivers/usb/misc/usbtest.c6
-rw-r--r--drivers/usb/mon/mon_main.c7
-rw-r--r--drivers/usb/mon/mon_stat.c4
-rw-r--r--drivers/usb/mon/mon_text.c26
-rw-r--r--drivers/usb/mon/usb_mon.h5
-rw-r--r--drivers/usb/net/asix.c1006
-rw-r--r--drivers/usb/net/cdc_ether.c1
-rw-r--r--drivers/usb/net/cdc_subset.c1
-rw-r--r--drivers/usb/net/gl620a.c1
-rw-r--r--drivers/usb/net/kaweth.c1
-rw-r--r--drivers/usb/net/net1080.c16
-rw-r--r--drivers/usb/net/pegasus.c20
-rw-r--r--drivers/usb/net/pegasus.h3
-rw-r--r--drivers/usb/net/plusb.c1
-rw-r--r--drivers/usb/net/rndis_host.c1
-rw-r--r--drivers/usb/net/rtl8150.c90
-rw-r--r--drivers/usb/net/usbnet.c45
-rw-r--r--drivers/usb/net/usbnet.h1
-rw-r--r--drivers/usb/net/zaurus.c1
-rw-r--r--drivers/usb/serial/Kconfig60
-rw-r--r--drivers/usb/serial/Makefile4
-rw-r--r--drivers/usb/serial/aircable.c625
-rw-r--r--drivers/usb/serial/airprime.c263
-rw-r--r--drivers/usb/serial/anydata.c123
-rw-r--r--drivers/usb/serial/ark3116.c235
-rw-r--r--drivers/usb/serial/belkin_sa.c3
-rw-r--r--drivers/usb/serial/bus.c3
-rw-r--r--drivers/usb/serial/console.c4
-rw-r--r--drivers/usb/serial/cp2101.c3
-rw-r--r--drivers/usb/serial/cyberjack.c9
-rw-r--r--drivers/usb/serial/cypress_m8.c132
-rw-r--r--drivers/usb/serial/digi_acceleport.c3
-rw-r--r--drivers/usb/serial/empeg.c3
-rw-r--r--drivers/usb/serial/ezusb.c3
-rw-r--r--drivers/usb/serial/ftdi_sio.c147
-rw-r--r--drivers/usb/serial/ftdi_sio.h40
-rw-r--r--drivers/usb/serial/funsoft.c2
-rw-r--r--drivers/usb/serial/garmin_gps.c223
-rw-r--r--drivers/usb/serial/generic.c10
-rw-r--r--drivers/usb/serial/hp4x.c3
-rw-r--r--drivers/usb/serial/io_edgeport.c3
-rw-r--r--drivers/usb/serial/io_ti.c3
-rw-r--r--drivers/usb/serial/ipaq.c58
-rw-r--r--drivers/usb/serial/ipw.c10
-rw-r--r--drivers/usb/serial/ir-usb.c12
-rw-r--r--drivers/usb/serial/keyspan.c3
-rw-r--r--drivers/usb/serial/keyspan_pda.c10
-rw-r--r--drivers/usb/serial/kl5kusb105.c3
-rw-r--r--drivers/usb/serial/kobil_sct.c3
-rw-r--r--drivers/usb/serial/mct_u232.c3
-rw-r--r--drivers/usb/serial/mos7840.c2962
-rw-r--r--drivers/usb/serial/navman.c2
-rw-r--r--drivers/usb/serial/omninet.c9
-rw-r--r--drivers/usb/serial/option.c83
-rw-r--r--drivers/usb/serial/pl2303.c835
-rw-r--r--drivers/usb/serial/pl2303.h19
-rw-r--r--drivers/usb/serial/safe_serial.c9
-rw-r--r--drivers/usb/serial/sierra.c75
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c3
-rw-r--r--drivers/usb/serial/usb-serial.c61
-rw-r--r--drivers/usb/serial/usb-serial.h301
-rw-r--r--drivers/usb/serial/visor.c40
-rw-r--r--drivers/usb/serial/whiteheat.c22
-rw-r--r--drivers/usb/storage/Kconfig12
-rw-r--r--drivers/usb/storage/Makefile1
-rw-r--r--drivers/usb/storage/debug.h1
-rw-r--r--drivers/usb/storage/dpcm.c1
-rw-r--r--drivers/usb/storage/freecom.c1
-rw-r--r--drivers/usb/storage/initializers.c73
-rw-r--r--drivers/usb/storage/initializers.h2
-rw-r--r--drivers/usb/storage/karma.c155
-rw-r--r--drivers/usb/storage/karma.h7
-rw-r--r--drivers/usb/storage/libusual.c10
-rw-r--r--drivers/usb/storage/onetouch.c9
-rw-r--r--drivers/usb/storage/scsiglue.c27
-rw-r--r--drivers/usb/storage/transport.c8
-rw-r--r--drivers/usb/storage/unusual_devs.h154
-rw-r--r--drivers/usb/storage/usb.c54
-rw-r--r--drivers/usb/storage/usb.h8
-rw-r--r--drivers/usb/usb-skeleton.c102
-rw-r--r--drivers/video/68328fb.c1
-rw-r--r--drivers/video/Kconfig140
-rw-r--r--drivers/video/Makefile13
-rw-r--r--drivers/video/S3triofb.c14
-rw-r--r--drivers/video/acornfb.c1
-rw-r--r--drivers/video/amifb.c2
-rw-r--r--drivers/video/arcfb.c3
-rw-r--r--drivers/video/asiliantfb.c2
-rw-r--r--drivers/video/atafb.c1
-rw-r--r--drivers/video/aty/Makefile1
-rw-r--r--drivers/video/aty/aty128fb.c377
-rw-r--r--drivers/video/aty/atyfb.h2
-rw-r--r--drivers/video/aty/atyfb_base.c237
-rw-r--r--drivers/video/aty/mach64_accel.c10
-rw-r--r--drivers/video/aty/mach64_cursor.c33
-rw-r--r--drivers/video/aty/radeon_backlight.c247
-rw-r--r--drivers/video/aty/radeon_base.c170
-rw-r--r--drivers/video/aty/radeon_i2c.c1
-rw-r--r--drivers/video/aty/radeon_monitor.c12
-rw-r--r--drivers/video/aty/radeon_pm.c165
-rw-r--r--drivers/video/aty/radeonfb.h18
-rw-r--r--drivers/video/au1100fb.c63
-rw-r--r--drivers/video/au1200fb.c2
-rw-r--r--drivers/video/backlight/Kconfig8
-rw-r--r--drivers/video/backlight/Makefile2
-rw-r--r--drivers/video/backlight/hp680_bl.c6
-rw-r--r--drivers/video/backlight/locomolcd.c150
-rw-r--r--drivers/video/bw2.c213
-rw-r--r--drivers/video/cfbcopyarea.c1
-rw-r--r--drivers/video/cfbfillrect.c1
-rw-r--r--drivers/video/cfbimgblt.c2
-rw-r--r--drivers/video/cg14.c326
-rw-r--r--drivers/video/cg3.c217
-rw-r--r--drivers/video/cg6.c337
-rw-r--r--drivers/video/chipsfb.c31
-rw-r--r--drivers/video/cirrusfb.c4
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/console/bitblit.c1
-rw-r--r--drivers/video/console/dummycon.c3
-rw-r--r--drivers/video/console/fbcon.c363
-rw-r--r--drivers/video/console/fbcon.h2
-rw-r--r--drivers/video/console/fbcon_ccw.c1
-rw-r--r--drivers/video/console/fbcon_cw.c1
-rw-r--r--drivers/video/console/fbcon_rotate.c1
-rw-r--r--drivers/video/console/fbcon_ud.c1
-rw-r--r--drivers/video/console/font_acorn_8x8.c1
-rw-r--r--drivers/video/console/fonts.c1
-rw-r--r--drivers/video/console/mdacon.c7
-rw-r--r--drivers/video/console/newport_con.c39
-rw-r--r--drivers/video/console/promcon.c6
-rw-r--r--drivers/video/console/softcursor.c1
-rw-r--r--drivers/video/console/sticon.c3
-rw-r--r--drivers/video/console/sticore.c1
-rw-r--r--drivers/video/console/tileblit.c1
-rw-r--r--drivers/video/console/vgacon.c43
-rw-r--r--drivers/video/controlfb.c2
-rw-r--r--drivers/video/cyber2000fb.c2
-rw-r--r--drivers/video/cyber2000fb.h1
-rw-r--r--drivers/video/cyberfb.c1
-rw-r--r--drivers/video/cyblafb.c1
-rw-r--r--drivers/video/dnfb.c1
-rw-r--r--drivers/video/epson1355fb.c30
-rw-r--r--drivers/video/fb_notify.c46
-rw-r--r--drivers/video/fbcmap.c1
-rw-r--r--drivers/video/fbcvt.c1
-rw-r--r--drivers/video/fbmem.c116
-rw-r--r--drivers/video/fbmon.c34
-rw-r--r--drivers/video/fbsysfs.c152
-rw-r--r--drivers/video/ffb.c466
-rw-r--r--drivers/video/g364fb.c1
-rw-r--r--drivers/video/gbefb.c1
-rw-r--r--drivers/video/geode/gx1fb_core.c4
-rw-r--r--drivers/video/geode/gxfb_core.c4
-rw-r--r--drivers/video/hgafb.c1
-rw-r--r--drivers/video/hitfb.c231
-rw-r--r--drivers/video/hpfb.c1
-rw-r--r--drivers/video/i810/i810-i2c.c2
-rw-r--r--drivers/video/i810/i810_main.c17
-rw-r--r--drivers/video/igafb.c4
-rw-r--r--drivers/video/imacfb.c380
-rw-r--r--drivers/video/imsttfb.c2
-rw-r--r--drivers/video/imxfb.c1
-rw-r--r--drivers/video/intelfb/intelfbdrv.c3
-rw-r--r--drivers/video/intelfb/intelfbhw.c2
-rw-r--r--drivers/video/kyro/fbdev.c2
-rw-r--r--drivers/video/leo.c294
-rw-r--r--drivers/video/logo/logo.c1
-rw-r--r--drivers/video/macfb.c1
-rw-r--r--drivers/video/macmodes.c7
-rw-r--r--drivers/video/macmodes.h7
-rw-r--r--drivers/video/matrox/g450_pll.c8
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c12
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.c1
-rw-r--r--drivers/video/matrox/matroxfb_DAC1064.h1
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.c1
-rw-r--r--drivers/video/matrox/matroxfb_Ti3026.h1
-rw-r--r--drivers/video/matrox/matroxfb_base.c55
-rw-r--r--drivers/video/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/matrox/matroxfb_misc.c1
-rw-r--r--drivers/video/maxinefb.c1
-rw-r--r--drivers/video/mbx/Makefile4
-rw-r--r--drivers/video/mbx/mbxdebugfs.c188
-rw-r--r--drivers/video/mbx/mbxfb.c683
-rw-r--r--drivers/video/mbx/reg_bits.h418
-rw-r--r--drivers/video/mbx/regs.h195
-rw-r--r--drivers/video/modedb.c12
-rw-r--r--drivers/video/neofb.c34
-rw-r--r--drivers/video/nvidia/Makefile3
-rw-r--r--drivers/video/nvidia/nv_backlight.c203
-rw-r--r--drivers/video/nvidia/nv_hw.c10
-rw-r--r--drivers/video/nvidia/nv_i2c.c1
-rw-r--r--drivers/video/nvidia/nv_of.c13
-rw-r--r--drivers/video/nvidia/nv_proto.h12
-rw-r--r--drivers/video/nvidia/nvidia.c480
-rw-r--r--drivers/video/offb.c445
-rw-r--r--drivers/video/p9100.c251
-rw-r--r--drivers/video/platinumfb.c2
-rw-r--r--drivers/video/pm2fb.c2
-rw-r--r--drivers/video/pm3fb.c2
-rw-r--r--drivers/video/pmag-aa-fb.c1
-rw-r--r--drivers/video/pnx4008/Makefile7
-rw-r--r--drivers/video/pnx4008/dum.h211
-rw-r--r--drivers/video/pnx4008/fbcommon.h43
-rw-r--r--drivers/video/pnx4008/pnxrgbfb.c213
-rw-r--r--drivers/video/pnx4008/sdum.c872
-rw-r--r--drivers/video/pnx4008/sdum.h139
-rw-r--r--drivers/video/pvr2fb.c24
-rw-r--r--drivers/video/pxafb.c3
-rw-r--r--drivers/video/q40fb.c1
-rw-r--r--drivers/video/retz3fb.c1
-rw-r--r--drivers/video/riva/fbdev.c262
-rw-r--r--drivers/video/riva/rivafb-i2c.c1
-rw-r--r--drivers/video/riva/rivafb.h1
-rw-r--r--drivers/video/s1d13xxxfb.c1
-rw-r--r--drivers/video/s3c2410fb.c20
-rw-r--r--drivers/video/sa1100fb.c3
-rw-r--r--drivers/video/savage/savagefb-i2c.c2
-rw-r--r--drivers/video/savage/savagefb.h45
-rw-r--r--drivers/video/savage/savagefb_driver.c1489
-rw-r--r--drivers/video/sgivwfb.c7
-rw-r--r--drivers/video/sis/init.h1
-rw-r--r--drivers/video/sis/init301.c4
-rw-r--r--drivers/video/sis/init301.h1
-rw-r--r--drivers/video/sis/initextlfb.c1
-rw-r--r--drivers/video/sis/osdef.h1
-rw-r--r--drivers/video/sis/sis.h1
-rw-r--r--drivers/video/sis/sis_accel.c1
-rw-r--r--drivers/video/sis/sis_main.c9
-rw-r--r--drivers/video/skeletonfb.c6
-rw-r--r--drivers/video/sstfb.c1
-rw-r--r--drivers/video/stifb.c1
-rw-r--r--drivers/video/sun3fb.c2
-rw-r--r--drivers/video/tcx.c224
-rw-r--r--drivers/video/tdfxfb.c2
-rw-r--r--drivers/video/tgafb.c2
-rw-r--r--drivers/video/tridentfb.c7
-rw-r--r--drivers/video/tx3912fb.c1
-rw-r--r--drivers/video/valkyriefb.c2
-rw-r--r--drivers/video/vesafb.c61
-rw-r--r--drivers/video/vfb.c30
-rw-r--r--drivers/video/vga16fb.c42
-rw-r--r--drivers/video/vgastate.c1
-rw-r--r--drivers/video/virgefb.c1
-rw-r--r--drivers/w1/masters/ds2482.c2
-rw-r--r--drivers/zorro/names.c1
2969 files changed, 263604 insertions, 98681 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 8b11cebe65d..263e86ddc1a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -18,6 +18,8 @@ source "drivers/ide/Kconfig"
source "drivers/scsi/Kconfig"
+source "drivers/ata/Kconfig"
+
source "drivers/cdrom/Kconfig"
source "drivers/md/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 3c5170310bd..4ac14dab307 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_PPC_PMAC) += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_FC4) += fc4/
obj-$(CONFIG_SCSI) += scsi/
+obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_FUSION) += message/
obj-$(CONFIG_IEEE1394) += ieee1394/
obj-y += cdrom/
@@ -74,4 +75,5 @@ obj-$(CONFIG_SGI_SN) += sn/
obj-y += firmware/
obj-$(CONFIG_CRYPTO) += crypto/
obj-$(CONFIG_SUPERH) += sh/
+obj-$(CONFIG_GENERIC_TIME) += clocksource/
obj-$(CONFIG_DMA_ENGINE) += dma/
diff --git a/drivers/acorn/block/Kconfig b/drivers/acorn/block/Kconfig
index 073add35e66..a0ff25ea439 100644
--- a/drivers/acorn/block/Kconfig
+++ b/drivers/acorn/block/Kconfig
@@ -3,7 +3,7 @@
#
menu "Acorn-specific block devices"
- depends on ARCH_ACORN
+ depends on ARCH_ARC || ARCH_A5K
config BLK_DEV_FD1772
tristate "Old Archimedes floppy (1772) support"
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index ce074f6f336..3dd6b7bb5d3 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -99,7 +99,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
@@ -1279,7 +1278,7 @@ static int mfm_do_init(unsigned char irqmask)
printk("mfm: detected %d hard drive%s\n", mfm_drives,
mfm_drives == 1 ? "" : "s");
- ret = request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL);
+ ret = request_irq(mfm_irq, mfm_interrupt_handler, IRQF_DISABLED, "MFM harddisk", NULL);
if (ret) {
printk("mfm: unable to get IRQ%d\n", mfm_irq);
goto out4;
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
index c26c08b3682..bdb9c8b78ed 100644
--- a/drivers/acorn/char/i2c.c
+++ b/drivers/acorn/char/i2c.c
@@ -308,7 +308,6 @@ static struct i2c_algo_bit_data ioc_data = {
.getsda = ioc_getsda,
.getscl = ioc_getscl,
.udelay = 80,
- .mdelay = 80,
.timeout = 100
};
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 94b8d820c51..56c5ba87462 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -107,7 +107,6 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
depends on X86
- default y
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -133,6 +132,12 @@ config ACPI_FAN
This driver adds support for ACPI fan devices, allowing user-mode
applications to perform basic fan control (on, off, status).
+config ACPI_DOCK
+ tristate "Dock"
+ depends on EXPERIMENTAL
+ help
+ This driver adds support for ACPI controlled docking stations
+
config ACPI_PROCESSOR
tristate "Processor"
default y
@@ -207,6 +212,7 @@ config ACPI_IBM
config ACPI_IBM_DOCK
bool "Legacy Docking Station Support"
depends on ACPI_IBM
+ depends on ACPI_DOCK=n
default n
---help---
Allows the ibm_acpi driver to handle docking station events.
@@ -328,7 +334,7 @@ config ACPI_CONTAINER
config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug"
depends on ACPI
- depends on MEMORY_HOTPLUG || X86_64
+ depends on MEMORY_HOTPLUG
default n
help
This driver adds supports for ACPI Memory Hotplug. This driver
@@ -345,6 +351,17 @@ config ACPI_HOTPLUG_MEMORY
If one selects "m," this driver can be loaded using the following
command:
$>modprobe acpi_memhotplug
+
+config ACPI_SBS
+ tristate "Smart Battery System (EXPERIMENTAL)"
+ depends on X86 && I2C
+ depends on EXPERIMENTAL
+ help
+ This driver adds support for the Smart Battery System.
+ Depends on I2C (Device Drivers ---> I2C support)
+ A "Smart Battery" is quite old and quite rare compared
+ to today's ACPI "Control Method" battery.
+
endif # ACPI
endmenu
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 5984b4f6715..bce7ca27b42 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
+obj-$(CONFIG_ACPI_DOCK) += dock.o
obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o
obj-y += pci_root.o pci_link.o pci_irq.o pci_bind.o
@@ -57,3 +58,5 @@ obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-y += scan.o motherboard.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
+obj-y += cm_sbs.o
+obj-$(CONFIG_ACPI_SBS) += i2c_ec.o sbs.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 7839b831df9..11abc7bf777 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -50,6 +50,9 @@ ACPI_MODULE_NAME("acpi_ac")
MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
MODULE_LICENSE("GPL");
+extern struct proc_dir_entry *acpi_lock_ac_dir(void);
+extern void *acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+
static int acpi_ac_add(struct acpi_device *device);
static int acpi_ac_remove(struct acpi_device *device, int type);
static int acpi_ac_open_fs(struct inode *inode, struct file *file);
@@ -65,11 +68,11 @@ static struct acpi_driver acpi_ac_driver = {
};
struct acpi_ac {
- acpi_handle handle;
+ struct acpi_device * device;
unsigned long state;
};
-static struct file_operations acpi_ac_fops = {
+static const struct file_operations acpi_ac_fops = {
.open = acpi_ac_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -84,20 +87,18 @@ static int acpi_ac_get_state(struct acpi_ac *ac)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_ac_get_state");
if (!ac)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- status = acpi_evaluate_integer(ac->handle, "_PSR", NULL, &ac->state);
+ status = acpi_evaluate_integer(ac->device->handle, "_PSR", NULL, &ac->state);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error reading AC Adapter state\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Error reading AC Adapter state"));
ac->state = ACPI_AC_STATUS_UNKNOWN;
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -110,14 +111,13 @@ static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_ac *ac = (struct acpi_ac *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_ac_seq_show");
if (!ac)
- return_VALUE(0);
+ return 0;
if (acpi_ac_get_state(ac)) {
seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
- return_VALUE(0);
+ return 0;
}
seq_puts(seq, "state: ");
@@ -133,7 +133,7 @@ static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
break;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_ac_open_fs(struct inode *inode, struct file *file)
@@ -145,13 +145,12 @@ static int acpi_ac_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_ac_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ac_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_device_dir(device)->owner = THIS_MODULE;
}
@@ -159,21 +158,18 @@ static int acpi_ac_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_AC_FILE_STATE,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_AC_FILE_STATE));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_ac_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_ac_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_ac_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_AC_FILE_STATE, acpi_device_dir(device));
@@ -182,7 +178,7 @@ static int acpi_ac_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -194,16 +190,15 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
struct acpi_ac *ac = (struct acpi_ac *)data;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_ac_notify");
if (!ac)
- return_VOID;
-
- if (acpi_bus_get_device(ac->handle, &device))
- return_VOID;
+ return;
+ device = ac->device;
switch (event) {
case ACPI_AC_NOTIFY_STATUS:
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
acpi_ac_get_state(ac);
acpi_bus_generate_event(device, event, (u32) ac->state);
break;
@@ -213,7 +208,7 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static int acpi_ac_add(struct acpi_device *device)
@@ -222,17 +217,16 @@ static int acpi_ac_add(struct acpi_device *device)
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL;
- ACPI_FUNCTION_TRACE("acpi_ac_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
if (!ac)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(ac, 0, sizeof(struct acpi_ac));
- ac->handle = device->handle;
+ ac->device = device;
strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_AC_CLASS);
acpi_driver_data(device) = ac;
@@ -245,12 +239,10 @@ static int acpi_ac_add(struct acpi_device *device)
if (result)
goto end;
- status = acpi_install_notify_handler(ac->handle,
- ACPI_DEVICE_NOTIFY, acpi_ac_notify,
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_ALL_NOTIFY, acpi_ac_notify,
ac);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
result = -ENODEV;
goto end;
}
@@ -265,7 +257,7 @@ static int acpi_ac_add(struct acpi_device *device)
kfree(ac);
}
- return_VALUE(result);
+ return result;
}
static int acpi_ac_remove(struct acpi_device *device, int type)
@@ -273,55 +265,50 @@ static int acpi_ac_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_ac *ac = NULL;
- ACPI_FUNCTION_TRACE("acpi_ac_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
ac = (struct acpi_ac *)acpi_driver_data(device);
- status = acpi_remove_notify_handler(ac->handle,
- ACPI_DEVICE_NOTIFY, acpi_ac_notify);
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
+ status = acpi_remove_notify_handler(device->handle,
+ ACPI_ALL_NOTIFY, acpi_ac_notify);
acpi_ac_remove_fs(device);
kfree(ac);
- return_VALUE(0);
+ return 0;
}
static int __init acpi_ac_init(void)
{
- int result = 0;
+ int result;
- ACPI_FUNCTION_TRACE("acpi_ac_init");
+ if (acpi_disabled)
+ return -ENODEV;
- acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
+ acpi_ac_dir = acpi_lock_ac_dir();
if (!acpi_ac_dir)
- return_VALUE(-ENODEV);
- acpi_ac_dir->owner = THIS_MODULE;
+ return -ENODEV;
result = acpi_bus_register_driver(&acpi_ac_driver);
if (result < 0) {
- remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ acpi_unlock_ac_dir(acpi_ac_dir);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_ac_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_ac_exit");
acpi_bus_unregister_driver(&acpi_ac_driver);
- remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
+ acpi_unlock_ac_dir(acpi_ac_dir);
- return_VOID;
+ return;
}
module_init(acpi_ac_init);
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index e0a95ba7237..1dda370f402 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -57,6 +57,7 @@ MODULE_LICENSE("GPL");
static int acpi_memory_device_add(struct acpi_device *device);
static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_start(struct acpi_device *device);
static struct acpi_driver acpi_memory_device_driver = {
.name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
@@ -65,48 +66,82 @@ static struct acpi_driver acpi_memory_device_driver = {
.ops = {
.add = acpi_memory_device_add,
.remove = acpi_memory_device_remove,
+ .start = acpi_memory_device_start,
},
};
-struct acpi_memory_device {
- acpi_handle handle;
- unsigned int state; /* State of the memory device */
- unsigned short caching; /* memory cache attribute */
- unsigned short write_protect; /* memory read/write attribute */
+struct acpi_memory_info {
+ struct list_head list;
u64 start_addr; /* Memory Range start physical addr */
u64 length; /* Memory Range length */
+ unsigned short caching; /* memory cache attribute */
+ unsigned short write_protect; /* memory read/write attribute */
+ unsigned int enabled:1;
};
+struct acpi_memory_device {
+ struct acpi_device * device;
+ unsigned int state; /* State of the memory device */
+ struct list_head res_list;
+};
+
+static acpi_status
+acpi_memory_get_resource(struct acpi_resource *resource, void *context)
+{
+ struct acpi_memory_device *mem_device = context;
+ struct acpi_resource_address64 address64;
+ struct acpi_memory_info *info, *new;
+ acpi_status status;
+
+ status = acpi_resource_to_address64(resource, &address64);
+ if (ACPI_FAILURE(status) ||
+ (address64.resource_type != ACPI_MEMORY_RANGE))
+ return AE_OK;
+
+ list_for_each_entry(info, &mem_device->res_list, list) {
+ /* Can we combine the resource range information? */
+ if ((info->caching == address64.info.mem.caching) &&
+ (info->write_protect == address64.info.mem.write_protect) &&
+ (info->start_addr + info->length == address64.minimum)) {
+ info->length += address64.address_length;
+ return AE_OK;
+ }
+ }
+
+ new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
+ if (!new)
+ return AE_ERROR;
+
+ INIT_LIST_HEAD(&new->list);
+ new->caching = address64.info.mem.caching;
+ new->write_protect = address64.info.mem.write_protect;
+ new->start_addr = address64.minimum;
+ new->length = address64.address_length;
+ list_add_tail(&new->list, &mem_device->res_list);
+
+ return AE_OK;
+}
+
static int
acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
{
acpi_status status;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- struct acpi_resource *resource = NULL;
- struct acpi_resource_address64 address64;
+ struct acpi_memory_info *info, *n;
- ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources");
- /* Get the range from the _CRS */
- status = acpi_get_current_resources(mem_device->handle, &buffer);
- if (ACPI_FAILURE(status))
- return_VALUE(-EINVAL);
+ if (!list_empty(&mem_device->res_list))
+ return 0;
- resource = (struct acpi_resource *)buffer.pointer;
- status = acpi_resource_to_address64(resource, &address64);
- if (ACPI_SUCCESS(status)) {
- if (address64.resource_type == ACPI_MEMORY_RANGE) {
- /* Populate the structure */
- mem_device->caching = address64.info.mem.caching;
- mem_device->write_protect =
- address64.info.mem.write_protect;
- mem_device->start_addr = address64.minimum;
- mem_device->length = address64.address_length;
- }
+ status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
+ acpi_memory_get_resource, mem_device);
+ if (ACPI_FAILURE(status)) {
+ list_for_each_entry_safe(info, n, &mem_device->res_list, list)
+ kfree(info);
+ INIT_LIST_HEAD(&mem_device->res_list);
+ return -EINVAL;
}
- acpi_os_free(buffer.pointer);
- return_VALUE(0);
+ return 0;
}
static int
@@ -118,23 +153,21 @@ acpi_memory_get_device(acpi_handle handle,
struct acpi_device *device = NULL;
struct acpi_device *pdevice = NULL;
- ACPI_FUNCTION_TRACE("acpi_memory_get_device");
if (!acpi_bus_get_device(handle, &device) && device)
goto end;
status = acpi_get_parent(handle, &phandle);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error in acpi_get_parent\n"));
- return_VALUE(-EINVAL);
+ ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
+ return -EINVAL;
}
/* Get the parent device */
status = acpi_bus_get_device(phandle, &pdevice);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error in acpi_bus_get_device\n"));
- return_VALUE(-EINVAL);
+ ACPI_EXCEPTION((AE_INFO, status, "Cannot get acpi bus device"));
+ return -EINVAL;
}
/*
@@ -143,30 +176,29 @@ acpi_memory_get_device(acpi_handle handle,
*/
status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error in acpi_bus_add\n"));
- return_VALUE(-EINVAL);
+ ACPI_EXCEPTION((AE_INFO, status, "Cannot add acpi bus"));
+ return -EINVAL;
}
end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
printk(KERN_ERR "\n driver data not found");
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
{
unsigned long current_status;
- ACPI_FUNCTION_TRACE("acpi_memory_check_device");
/* Get device present/absent information from the _STA */
- if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->handle, "_STA",
+ if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
NULL, &current_status)))
- return_VALUE(-ENODEV);
+ return -ENODEV;
/*
* Check for device status. Device should be
* present/enabled/functioning.
@@ -174,35 +206,48 @@ static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
if (!((current_status & ACPI_MEMORY_STA_PRESENT)
&& (current_status & ACPI_MEMORY_STA_ENABLED)
&& (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
- return_VALUE(-ENODEV);
+ return -ENODEV;
- return_VALUE(0);
+ return 0;
}
static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
{
- int result;
+ int result, num_enabled = 0;
+ struct acpi_memory_info *info;
+ int node;
- ACPI_FUNCTION_TRACE("acpi_memory_enable_device");
/* Get the range from the _CRS */
result = acpi_memory_get_device_resources(mem_device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "\nget_device_resources failed\n"));
+ printk(KERN_ERR PREFIX "get_device_resources failed\n");
mem_device->state = MEMORY_INVALID_STATE;
return result;
}
+ node = acpi_get_node(mem_device->device->handle);
/*
* Tell the VM there is more memory here...
* Note: Assume that this function returns zero on success
+ * We don't have memory-hot-add rollback function,now.
+ * (i.e. memory-hot-remove function)
*/
- result = add_memory(mem_device->start_addr, mem_device->length);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "\nadd_memory failed\n"));
+ list_for_each_entry(info, &mem_device->res_list, list) {
+ if (info->enabled) { /* just sanity check...*/
+ num_enabled++;
+ continue;
+ }
+ result = add_memory(node, info->start_addr, info->length);
+ if (result)
+ continue;
+ info->enabled = 1;
+ num_enabled++;
+ }
+ if (!num_enabled) {
+ printk(KERN_ERR PREFIX "add_memory failed\n");
mem_device->state = MEMORY_INVALID_STATE;
- return result;
+ return -EINVAL;
}
return result;
@@ -215,57 +260,55 @@ static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
union acpi_object arg;
unsigned long current_status;
- ACPI_FUNCTION_TRACE("acpi_memory_powerdown_device");
/* Issue the _EJ0 command */
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = 1;
- status = acpi_evaluate_object(mem_device->handle,
+ status = acpi_evaluate_object(mem_device->device->handle,
"_EJ0", &arg_list, NULL);
/* Return on _EJ0 failure */
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_EJ0 failed.\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
+ return -ENODEV;
}
/* Evalute _STA to check if the device is disabled */
- status = acpi_evaluate_integer(mem_device->handle, "_STA",
+ status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
NULL, &current_status);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
/* Check for device status. Device should be disabled */
if (current_status & ACPI_MEMORY_STA_ENABLED)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- return_VALUE(0);
+ return 0;
}
static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
{
int result;
- u64 start = mem_device->start_addr;
- u64 len = mem_device->length;
+ struct acpi_memory_info *info, *n;
- ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
/*
* Ask the VM to offline this memory range.
* Note: Assume that this function returns zero on success
*/
- result = remove_memory(start, len);
- if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
- return_VALUE(result);
+ list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
+ if (info->enabled) {
+ result = remove_memory(info->start_addr, info->length);
+ if (result)
+ return result;
+ }
+ kfree(info);
}
/* Power-off and eject the device */
result = acpi_memory_powerdown_device(mem_device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device Power Down failed.\n"));
/* Set the status of the device to invalid */
mem_device->state = MEMORY_INVALID_STATE;
return result;
@@ -280,7 +323,6 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
struct acpi_memory_device *mem_device;
struct acpi_device *device;
- ACPI_FUNCTION_TRACE("acpi_memory_device_notify");
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -292,15 +334,14 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived DEVICE CHECK notification for device\n"));
if (acpi_memory_get_device(handle, &mem_device)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error in finding driver data\n"));
- return_VOID;
+ printk(KERN_ERR PREFIX "Cannot find driver data\n");
+ return;
}
if (!acpi_memory_check_device(mem_device)) {
if (acpi_memory_enable_device(mem_device))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error in acpi_memory_enable_device\n"));
+ printk(KERN_ERR PREFIX
+ "Cannot enable memory device\n");
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
@@ -308,14 +349,12 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
"\nReceived EJECT REQUEST notification for device\n"));
if (acpi_bus_get_device(handle, &device)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device doesn't exist\n"));
+ printk(KERN_ERR PREFIX "Device doesn't exist\n");
break;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Driver Data is NULL\n"));
+ printk(KERN_ERR PREFIX "Driver Data is NULL\n");
break;
}
@@ -326,8 +365,8 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
* with generic sysfs driver
*/
if (acpi_memory_disable_device(mem_device))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error in acpi_memory_disable_device\n"));
+ printk(KERN_ERR PREFIX
+ "Disable memory device\n");
/*
* TBD: Invoke acpi_bus_remove to cleanup data structures
*/
@@ -338,7 +377,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static int acpi_memory_device_add(struct acpi_device *device)
@@ -346,17 +385,17 @@ static int acpi_memory_device_add(struct acpi_device *device)
int result;
struct acpi_memory_device *mem_device = NULL;
- ACPI_FUNCTION_TRACE("acpi_memory_device_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
if (!mem_device)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(mem_device, 0, sizeof(struct acpi_memory_device));
- mem_device->handle = device->handle;
+ INIT_LIST_HEAD(&mem_device->res_list);
+ mem_device->device = device;
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
acpi_driver_data(device) = mem_device;
@@ -365,7 +404,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
result = acpi_memory_get_device_resources(mem_device);
if (result) {
kfree(mem_device);
- return_VALUE(result);
+ return result;
}
/* Set the device state */
@@ -373,22 +412,38 @@ static int acpi_memory_device_add(struct acpi_device *device)
printk(KERN_INFO "%s \n", acpi_device_name(device));
- return_VALUE(result);
+ return result;
}
static int acpi_memory_device_remove(struct acpi_device *device, int type)
{
struct acpi_memory_device *mem_device = NULL;
- ACPI_FUNCTION_TRACE("acpi_memory_device_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
mem_device = (struct acpi_memory_device *)acpi_driver_data(device);
kfree(mem_device);
- return_VALUE(0);
+ return 0;
+}
+
+static int acpi_memory_device_start (struct acpi_device *device)
+{
+ struct acpi_memory_device *mem_device;
+ int result = 0;
+
+ mem_device = acpi_driver_data(device);
+
+ if (!acpi_memory_check_device(mem_device)) {
+ /* call add_memory func */
+ result = acpi_memory_enable_device(mem_device);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in acpi_memory_enable_device\n"));
+ }
+ return result;
}
/*
@@ -401,16 +456,15 @@ static acpi_status is_memory_device(acpi_handle handle)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_device_info *info;
- ACPI_FUNCTION_TRACE("is_memory_device");
status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status))
- return_ACPI_STATUS(AE_ERROR);
+ return status;
info = buffer.pointer;
if (!(info->valid & ACPI_VALID_HID)) {
- acpi_os_free(buffer.pointer);
- return_ACPI_STATUS(AE_ERROR);
+ kfree(buffer.pointer);
+ return AE_ERROR;
}
hardware_id = info->hardware_id.value;
@@ -418,8 +472,8 @@ static acpi_status is_memory_device(acpi_handle handle)
(strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
status = AE_ERROR;
- acpi_os_free(buffer.pointer);
- return_ACPI_STATUS(status);
+ kfree(buffer.pointer);
+ return status;
}
static acpi_status
@@ -428,21 +482,15 @@ acpi_memory_register_notify_handler(acpi_handle handle,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_memory_register_notify_handler");
status = is_memory_device(handle);
if (ACPI_FAILURE(status))
- return_ACPI_STATUS(AE_OK); /* continue */
+ return AE_OK; /* continue */
status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
acpi_memory_device_notify, NULL);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
- return_ACPI_STATUS(AE_OK); /* continue */
- }
-
- return_ACPI_STATUS(status);
+ /* continue */
+ return AE_OK;
}
static acpi_status
@@ -451,22 +499,16 @@ acpi_memory_deregister_notify_handler(acpi_handle handle,
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_memory_deregister_notify_handler");
status = is_memory_device(handle);
if (ACPI_FAILURE(status))
- return_ACPI_STATUS(AE_OK); /* continue */
+ return AE_OK; /* continue */
status = acpi_remove_notify_handler(handle,
ACPI_SYSTEM_NOTIFY,
acpi_memory_device_notify);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
- return_ACPI_STATUS(AE_OK); /* continue */
- }
- return_ACPI_STATUS(status);
+ return AE_OK; /* continue */
}
static int __init acpi_memory_device_init(void)
@@ -474,12 +516,11 @@ static int __init acpi_memory_device_init(void)
int result;
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_memory_device_init");
result = acpi_bus_register_driver(&acpi_memory_device_driver);
if (result < 0)
- return_VALUE(-ENODEV);
+ return -ENODEV;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
@@ -487,19 +528,18 @@ static int __init acpi_memory_device_init(void)
NULL, NULL);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "walk_namespace failed\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
acpi_bus_unregister_driver(&acpi_memory_device_driver);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_memory_device_exit(void)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_memory_device_exit");
/*
* Adding this to un-install notification handlers for all the device
@@ -511,11 +551,11 @@ static void __exit acpi_memory_device_exit(void)
NULL, NULL);
if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "walk_namespace failed\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "walk_namespace failed"));
acpi_bus_unregister_driver(&acpi_memory_device_driver);
- return_VOID;
+ return;
}
module_init(acpi_memory_device_init);
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 839f423d738..e9ee4c52a5f 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -2,7 +2,7 @@
* asus_acpi.c - Asus Laptop ACPI Extras
*
*
- * Copyright (C) 2002, 2003, 2004 Julien Lerouge, Karol Kozimor
+ * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
*
* 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
@@ -26,11 +26,8 @@
* Pontus Fuchs - Helper functions, cleanup
* Johann Wiesner - Small compile fixes
* John Belmonte - ACPI code for Toshiba laptop was a good starting point.
+ * Éric Burghard - LED display support for W1N
*
- * TODO:
- * add Fn key status
- * Add mode selection on module loading (parameter) -> still necessary?
- * Complete display switching -- may require dirty hacks or calling _DOS?
*/
#include <linux/kernel.h>
@@ -42,12 +39,14 @@
#include <acpi/acpi_bus.h>
#include <asm/uaccess.h>
-#define ASUS_ACPI_VERSION "0.29"
+#define ASUS_ACPI_VERSION "0.30"
#define PROC_ASUS "asus" //the directory
#define PROC_MLED "mled"
#define PROC_WLED "wled"
#define PROC_TLED "tled"
+#define PROC_BT "bluetooth"
+#define PROC_LEDD "ledd"
#define PROC_INFO "info"
#define PROC_LCD "lcd"
#define PROC_BRN "brn"
@@ -67,9 +66,10 @@
/*
* Flags for hotk status
*/
-#define MLED_ON 0x01 //is MLED ON ?
-#define WLED_ON 0x02
-#define TLED_ON 0x04
+#define MLED_ON 0x01 //mail LED
+#define WLED_ON 0x02 //wireless LED
+#define TLED_ON 0x04 //touchpad LED
+#define BT_ON 0x08 //internal Bluetooth
MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
MODULE_DESCRIPTION(ACPI_HOTK_NAME);
@@ -92,7 +92,10 @@ struct model_data {
char *wled_status; //node to handle wled reading_______A
char *mt_tled; //method to handle tled_____________R
char *tled_status; //node to handle tled reading_______A
- char *mt_lcd_switch; //method to turn LCD ON/OFF_________A
+ char *mt_ledd; //method to handle LED display______R
+ char *mt_bt_switch; //method to switch Bluetooth on/off_R
+ char *bt_status; //no model currently supports this__?
+ char *mt_lcd_switch; //method to turn LCD on/off_________A
char *lcd_status; //node to read LCD panel state______A
char *brightness_up; //method to set brightness up_______A
char *brightness_down; //guess what ?______________________A
@@ -111,27 +114,31 @@ struct asus_hotk {
struct acpi_device *device; //the device we are in
acpi_handle handle; //the handle of the hotk device
char status; //status of the hotk, for LEDs, ...
+ u32 ledd_status; //status of the LED display
struct model_data *methods; //methods available on the laptop
u8 brightness; //brightness level
enum {
A1x = 0, //A1340D, A1300F
A2x, //A2500H
+ A4G, //A4700G
D1x, //D1
L2D, //L2000D
L3C, //L3800C
L3D, //L3400D
- L3H, //L3H, but also L2000E
+ L3H, //L3H, L2000E, L5D
L4R, //L4500R
L5x, //L5800C
L8L, //L8400L
M1A, //M1300A
M2E, //M2400E, L4400L
- M6N, //M6800N
- M6R, //M6700R
+ M6N, //M6800N, W3400N
+ M6R, //M6700R, A3000G
P30, //Samsung P30
S1x, //S1300A, but also L1400B and M2400A (L84F)
S2x, //S200 (J1 reported), Victor MP-XP7210
- xxN, //M2400N, M3700N, M5200N, S1300N, S5200N, W1OOON
+ W1N, //W1000N
+ W5A, //W5A
+ xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
//(Centrino)
END_MODEL
} model; //Models currently supported
@@ -149,17 +156,8 @@ struct asus_hotk {
static struct model_data model_conf[END_MODEL] = {
/*
- * Those pathnames are relative to the HOTK / ATKD device :
- * - mt_mled
- * - mt_wled
- * - brightness_set
- * - brightness_get
- * - display_set
- * - display_get
- *
* TODO I have seen a SWBX and AIBX method on some models, like L1400B,
* it seems to be a kind of switch, but what for ?
- *
*/
{
@@ -184,6 +182,16 @@ static struct model_data model_conf[END_MODEL] = {
.display_get = "\\INFB"},
{
+ .name = "A4G",
+ .mt_mled = "MLED",
+/* WLED present, but not controlled by ACPI */
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\ADVG"},
+
+ {
.name = "D1x",
.mt_mled = "MLED",
.mt_lcd_switch = "\\Q0D",
@@ -302,7 +310,8 @@ static struct model_data model_conf[END_MODEL] = {
.brightness_set = "SPLV",
.brightness_get = "GPLV",
.display_set = "SDSP",
- .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
+ .display_get = "\\SSTE"},
+
{
.name = "M6R",
.mt_mled = "MLED",
@@ -312,7 +321,7 @@ static struct model_data model_conf[END_MODEL] = {
.brightness_set = "SPLV",
.brightness_get = "GPLV",
.display_set = "SDSP",
- .display_get = "\\SSTE"},
+ .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
{
.name = "P30",
@@ -345,6 +354,28 @@ static struct model_data model_conf[END_MODEL] = {
.brightness_down = S2x_PREFIX "_Q0A"},
{
+ .name = "W1N",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_ledd = "SLCM",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\BKLT",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\ADVG"},
+
+ {
+ .name = "W5A",
+ .mt_bt_switch = "BLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\ADVG"},
+
+ {
.name = "xxN",
.mt_mled = "MLED",
/* WLED present, but not controlled by ACPI */
@@ -563,6 +594,36 @@ proc_write_mled(struct file *file, const char __user * buffer,
}
/*
+ * Proc handlers for LED display
+ */
+static int
+proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "0x%08x\n", hotk->ledd_status);
+}
+
+static int
+proc_write_ledd(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+{
+ int value;
+
+ count = parse_arg(buffer, count, &value);
+ if (count > 0) {
+ if (!write_acpi_int
+ (hotk->handle, hotk->methods->mt_ledd, value, NULL))
+ printk(KERN_WARNING
+ "Asus ACPI: LED display write failed\n");
+ else
+ hotk->ledd_status = (u32) value;
+ } else if (count < 0)
+ printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+
+ return count;
+}
+
+/*
* Proc handlers for WLED
*/
static int
@@ -581,6 +642,25 @@ proc_write_wled(struct file *file, const char __user * buffer,
}
/*
+ * Proc handlers for Bluetooth
+ */
+static int
+proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
+}
+
+static int
+proc_write_bluetooth(struct file *file, const char __user * buffer,
+ unsigned long count, void *data)
+{
+ /* Note: mt_bt_switch controls both internal Bluetooth adapter's
+ presence and its LED */
+ return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
+}
+
+/*
* Proc handlers for TLED
*/
static int
@@ -876,6 +956,11 @@ static int asus_hotk_add_fs(struct acpi_device *device)
mode, device);
}
+ if (hotk->methods->mt_ledd) {
+ asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd,
+ mode, device);
+ }
+
if (hotk->methods->mt_mled) {
asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled,
mode, device);
@@ -886,6 +971,11 @@ static int asus_hotk_add_fs(struct acpi_device *device)
mode, device);
}
+ if (hotk->methods->mt_bt_switch) {
+ asus_proc_add(PROC_BT, &proc_write_bluetooth,
+ &proc_read_bluetooth, mode, device);
+ }
+
/*
* We need both read node and write method as LCD switch is also accessible
* from keyboard
@@ -919,6 +1009,10 @@ static int asus_hotk_remove_fs(struct acpi_device *device)
remove_proc_entry(PROC_MLED, acpi_device_dir(device));
if (hotk->methods->mt_tled)
remove_proc_entry(PROC_TLED, acpi_device_dir(device));
+ if (hotk->methods->mt_ledd)
+ remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
+ if (hotk->methods->mt_bt_switch)
+ remove_proc_entry(PROC_BT, acpi_device_dir(device));
if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
remove_proc_entry(PROC_LCD, acpi_device_dir(device));
if ((hotk->methods->brightness_up
@@ -951,6 +1045,65 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
}
/*
+ * Match the model string to the list of supported models. Return END_MODEL if
+ * no match or model is NULL.
+ */
+static int asus_model_match(char *model)
+{
+ if (model == NULL)
+ return END_MODEL;
+
+ if (strncmp(model, "L3D", 3) == 0)
+ return L3D;
+ else if (strncmp(model, "L2E", 3) == 0 ||
+ strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
+ return L3H;
+ else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
+ return L3C;
+ else if (strncmp(model, "L8L", 3) == 0)
+ return L8L;
+ else if (strncmp(model, "L4R", 3) == 0)
+ return L4R;
+ else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
+ return M6N;
+ else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
+ return M6R;
+ else if (strncmp(model, "M2N", 3) == 0 ||
+ strncmp(model, "M3N", 3) == 0 ||
+ strncmp(model, "M5N", 3) == 0 ||
+ strncmp(model, "M6N", 3) == 0 ||
+ strncmp(model, "S1N", 3) == 0 ||
+ strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0)
+ return xxN;
+ else if (strncmp(model, "M1", 2) == 0)
+ return M1A;
+ else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
+ return M2E;
+ else if (strncmp(model, "L2", 2) == 0)
+ return L2D;
+ else if (strncmp(model, "L8", 2) == 0)
+ return S1x;
+ else if (strncmp(model, "D1", 2) == 0)
+ return D1x;
+ else if (strncmp(model, "A1", 2) == 0)
+ return A1x;
+ else if (strncmp(model, "A2", 2) == 0)
+ return A2x;
+ else if (strncmp(model, "J1", 2) == 0)
+ return S2x;
+ else if (strncmp(model, "L5", 2) == 0)
+ return L5x;
+ else if (strncmp(model, "A4G", 3) == 0)
+ return A4G;
+ else if (strncmp(model, "W1N", 3) == 0)
+ return W1N;
+ else if (strncmp(model, "W5A", 3) == 0)
+ return W5A;
+ else
+ return END_MODEL;
+}
+
+/*
* This function is used to initialize the hotk with right values. In this
* method, we can make all the detection we want, and modify the hotk struct
*/
@@ -960,6 +1113,7 @@ static int asus_hotk_get_info(void)
struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *model = NULL;
int bsts_result;
+ char *string = NULL;
acpi_status status;
/*
@@ -989,114 +1143,73 @@ static int asus_hotk_get_info(void)
printk(KERN_NOTICE " BSTS called, 0x%02x returned\n",
bsts_result);
- /* This is unlikely with implicit return */
- if (buffer.pointer == NULL)
- return -EINVAL;
-
- model = (union acpi_object *) buffer.pointer;
/*
- * Samsung P30 has a device with a valid _HID whose INIT does not
- * return anything. It used to be possible to catch this exception,
- * but the implicit return code will now happily confuse the
- * driver. We assume that every ACPI_TYPE_STRING is a valid model
- * identifier but it's still possible to get completely bogus data.
+ * Try to match the object returned by INIT to the specific model.
+ * Handle every possible object (or the lack of thereof) the DSDT
+ * writers might throw at us. When in trouble, we pass NULL to
+ * asus_model_match() and try something completely different.
*/
- if (model->type == ACPI_TYPE_STRING) {
- printk(KERN_NOTICE " %s model detected, ", model->string.pointer);
- } else {
- if (asus_info && /* Samsung P30 */
+ if (buffer.pointer) {
+ model = (union acpi_object *)buffer.pointer;
+ switch (model->type) {
+ case ACPI_TYPE_STRING:
+ string = model->string.pointer;
+ break;
+ case ACPI_TYPE_BUFFER:
+ string = model->buffer.pointer;
+ break;
+ default:
+ kfree(model);
+ break;
+ }
+ }
+ hotk->model = asus_model_match(string);
+ if (hotk->model == END_MODEL) { /* match failed */
+ if (asus_info &&
strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
hotk->model = P30;
printk(KERN_NOTICE
" Samsung P30 detected, supported\n");
} else {
hotk->model = M2E;
- printk(KERN_WARNING " no string returned by INIT\n");
- printk(KERN_WARNING " trying default values, supply "
- "the developers with your DSDT\n");
+ printk(KERN_NOTICE " unsupported model %s, trying "
+ "default values\n", string);
+ printk(KERN_NOTICE
+ " send /proc/acpi/dsdt to the developers\n");
}
hotk->methods = &model_conf[hotk->model];
-
- acpi_os_free(model);
-
return AE_OK;
}
-
- hotk->model = END_MODEL;
- if (strncmp(model->string.pointer, "L3D", 3) == 0)
- hotk->model = L3D;
- else if (strncmp(model->string.pointer, "L3H", 3) == 0 ||
- strncmp(model->string.pointer, "L2E", 3) == 0)
- hotk->model = L3H;
- else if (strncmp(model->string.pointer, "L3", 2) == 0 ||
- strncmp(model->string.pointer, "L2B", 3) == 0)
- hotk->model = L3C;
- else if (strncmp(model->string.pointer, "L8L", 3) == 0)
- hotk->model = L8L;
- else if (strncmp(model->string.pointer, "L4R", 3) == 0)
- hotk->model = L4R;
- else if (strncmp(model->string.pointer, "M6N", 3) == 0)
- hotk->model = M6N;
- else if (strncmp(model->string.pointer, "M6R", 3) == 0)
- hotk->model = M6R;
- else if (strncmp(model->string.pointer, "M2N", 3) == 0 ||
- strncmp(model->string.pointer, "M3N", 3) == 0 ||
- strncmp(model->string.pointer, "M5N", 3) == 0 ||
- strncmp(model->string.pointer, "M6N", 3) == 0 ||
- strncmp(model->string.pointer, "S1N", 3) == 0 ||
- strncmp(model->string.pointer, "S5N", 3) == 0 ||
- strncmp(model->string.pointer, "W1N", 3) == 0)
- hotk->model = xxN;
- else if (strncmp(model->string.pointer, "M1", 2) == 0)
- hotk->model = M1A;
- else if (strncmp(model->string.pointer, "M2", 2) == 0 ||
- strncmp(model->string.pointer, "L4E", 3) == 0)
- hotk->model = M2E;
- else if (strncmp(model->string.pointer, "L2", 2) == 0)
- hotk->model = L2D;
- else if (strncmp(model->string.pointer, "L8", 2) == 0)
- hotk->model = S1x;
- else if (strncmp(model->string.pointer, "D1", 2) == 0)
- hotk->model = D1x;
- else if (strncmp(model->string.pointer, "A1", 2) == 0)
- hotk->model = A1x;
- else if (strncmp(model->string.pointer, "A2", 2) == 0)
- hotk->model = A2x;
- else if (strncmp(model->string.pointer, "J1", 2) == 0)
- hotk->model = S2x;
- else if (strncmp(model->string.pointer, "L5", 2) == 0)
- hotk->model = L5x;
-
- if (hotk->model == END_MODEL) {
- printk("unsupported, trying default values, supply the "
- "developers with your DSDT\n");
- hotk->model = M2E;
- } else {
- printk("supported\n");
- }
-
hotk->methods = &model_conf[hotk->model];
+ printk(KERN_NOTICE " %s model detected, supported\n", string);
/* Sort of per-model blacklist */
- if (strncmp(model->string.pointer, "L2B", 3) == 0)
+ if (strncmp(string, "L2B", 3) == 0)
hotk->methods->lcd_status = NULL;
/* L2B is similar enough to L3C to use its settings, with this only
exception */
- else if (strncmp(model->string.pointer, "S5N", 3) == 0 ||
- strncmp(model->string.pointer, "M5N", 3) == 0)
+ else if (strncmp(string, "A3G", 3) == 0)
+ hotk->methods->lcd_status = "\\BLFG";
+ /* A3G is like M6R */
+ else if (strncmp(string, "S5N", 3) == 0 ||
+ strncmp(string, "M5N", 3) == 0 ||
+ strncmp(string, "W3N", 3) == 0)
hotk->methods->mt_mled = NULL;
- /* S5N and M5N have no MLED */
- else if (strncmp(model->string.pointer, "M2N", 3) == 0 ||
- strncmp(model->string.pointer, "W1N", 3) == 0)
+ /* S5N, M5N and W3N have no MLED */
+ else if (strncmp(string, "L5D", 3) == 0)
+ hotk->methods->mt_wled = NULL;
+ /* L5D's WLED is not controlled by ACPI */
+ else if (strncmp(string, "M2N", 3) == 0 ||
+ strncmp(string, "S1N", 3) == 0)
hotk->methods->mt_wled = "WLED";
- /* M2N and W1N have a usable WLED */
+ /* M2N and S1N have a usable WLED */
else if (asus_info) {
if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
hotk->methods->mled_status = NULL;
/* S1300A reports L84F, but L1400B too, account for that */
}
- acpi_os_free(model);
+ kfree(model);
return AE_OK;
}
@@ -1164,8 +1277,7 @@ static int asus_hotk_add(struct acpi_device *device)
/* For laptops without GPLV: init the hotk->brightness value */
if ((!hotk->methods->brightness_get)
&& (!hotk->methods->brightness_status)
- && (hotk->methods->brightness_up
- && hotk->methods->brightness_down)) {
+ && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
status =
acpi_evaluate_object(NULL, hotk->methods->brightness_down,
NULL, NULL);
@@ -1184,6 +1296,9 @@ static int asus_hotk_add(struct acpi_device *device)
asus_hotk_found = 1;
+ /* LED display is off by default */
+ hotk->ledd_status = 0xFFF;
+
end:
if (result) {
kfree(hotk);
@@ -1232,7 +1347,7 @@ static int __init asus_acpi_init(void)
result = acpi_bus_register_driver(&asus_hotk_driver);
if (result < 0) {
remove_proc_entry(PROC_ASUS, acpi_root_dir);
- return -ENODEV;
+ return result;
}
/*
@@ -1256,7 +1371,7 @@ static void __exit asus_acpi_exit(void)
acpi_bus_unregister_driver(&asus_hotk_driver);
remove_proc_entry(PROC_ASUS, acpi_root_dir);
- acpi_os_free(asus_info);
+ kfree(asus_info);
return;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 702e857e98c..9810e2a55d0 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -59,6 +59,9 @@ ACPI_MODULE_NAME("acpi_battery")
MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
MODULE_LICENSE("GPL");
+extern struct proc_dir_entry *acpi_lock_battery_dir(void);
+extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
+
static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
@@ -108,7 +111,7 @@ struct acpi_battery_trips {
};
struct acpi_battery {
- acpi_handle handle;
+ struct acpi_device * device;
struct acpi_battery_flags flags;
struct acpi_battery_trips trips;
unsigned long alarm;
@@ -132,17 +135,16 @@ acpi_battery_get_info(struct acpi_battery *battery,
struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_get_info");
if (!battery || !bif)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Evalute _BIF */
- status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer);
+ status = acpi_evaluate_object(battery->device->handle, "_BIF", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BIF"));
+ return -ENODEV;
}
package = (union acpi_object *)buffer.pointer;
@@ -151,7 +153,7 @@ acpi_battery_get_info(struct acpi_battery *battery,
status = acpi_extract_package(package, &format, &data);
if (status != AE_BUFFER_OVERFLOW) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
result = -ENODEV;
goto end;
}
@@ -165,19 +167,19 @@ acpi_battery_get_info(struct acpi_battery *battery,
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting _BIF"));
kfree(data.pointer);
result = -ENODEV;
goto end;
}
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
if (!result)
(*bif) = (struct acpi_battery_info *)data.pointer;
- return_VALUE(result);
+ return result;
}
static int
@@ -193,17 +195,16 @@ acpi_battery_get_status(struct acpi_battery *battery,
struct acpi_buffer data = { 0, NULL };
union acpi_object *package = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_get_status");
if (!battery || !bst)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Evalute _BST */
- status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer);
+ status = acpi_evaluate_object(battery->device->handle, "_BST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BST"));
+ return -ENODEV;
}
package = (union acpi_object *)buffer.pointer;
@@ -212,7 +213,7 @@ acpi_battery_get_status(struct acpi_battery *battery,
status = acpi_extract_package(package, &format, &data);
if (status != AE_BUFFER_OVERFLOW) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
result = -ENODEV;
goto end;
}
@@ -226,19 +227,19 @@ acpi_battery_get_status(struct acpi_battery *battery,
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting _BST"));
kfree(data.pointer);
result = -ENODEV;
goto end;
}
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
if (!result)
(*bst) = (struct acpi_battery_status *)data.pointer;
- return_VALUE(result);
+ return result;
}
static int
@@ -248,25 +249,24 @@ acpi_battery_set_alarm(struct acpi_battery *battery, unsigned long alarm)
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list arg_list = { 1, &arg0 };
- ACPI_FUNCTION_TRACE("acpi_battery_set_alarm");
if (!battery)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!battery->flags.alarm)
- return_VALUE(-ENODEV);
+ return -ENODEV;
arg0.integer.value = alarm;
- status = acpi_evaluate_object(battery->handle, "_BTP", &arg_list, NULL);
+ status = acpi_evaluate_object(battery->device->handle, "_BTP", &arg_list, NULL);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
battery->alarm = alarm;
- return_VALUE(0);
+ return 0;
}
static int acpi_battery_check(struct acpi_battery *battery)
@@ -277,18 +277,15 @@ static int acpi_battery_check(struct acpi_battery *battery)
struct acpi_device *device = NULL;
struct acpi_battery_info *bif = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_check");
if (!battery)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- result = acpi_bus_get_device(battery->handle, &device);
- if (result)
- return_VALUE(result);
+ device = battery->device;
result = acpi_bus_get_status(device);
if (result)
- return_VALUE(result);
+ return result;
/* Insertion? */
@@ -300,7 +297,7 @@ static int acpi_battery_check(struct acpi_battery *battery)
result = acpi_battery_get_info(battery, &bif);
if (result)
- return_VALUE(result);
+ return result;
battery->flags.power_unit = bif->power_unit;
battery->trips.warning = bif->design_capacity_warning;
@@ -309,7 +306,7 @@ static int acpi_battery_check(struct acpi_battery *battery)
/* See if alarms are supported, and if so, set default */
- status = acpi_get_handle(battery->handle, "_BTP", &handle);
+ status = acpi_get_handle(battery->device->handle, "_BTP", &handle);
if (ACPI_SUCCESS(status)) {
battery->flags.alarm = 1;
acpi_battery_set_alarm(battery, battery->trips.warning);
@@ -324,7 +321,7 @@ static int acpi_battery_check(struct acpi_battery *battery)
battery->flags.present = device->status.battery_present;
- return_VALUE(result);
+ return result;
}
/* --------------------------------------------------------------------------
@@ -339,7 +336,6 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
struct acpi_battery_info *bif = NULL;
char *units = "?";
- ACPI_FUNCTION_TRACE("acpi_battery_read_info");
if (!battery)
goto end;
@@ -409,7 +405,7 @@ static int acpi_battery_read_info(struct seq_file *seq, void *offset)
end:
kfree(bif);
- return_VALUE(0);
+ return 0;
}
static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
@@ -424,7 +420,6 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
struct acpi_battery_status *bst = NULL;
char *units = "?";
- ACPI_FUNCTION_TRACE("acpi_battery_read_state");
if (!battery)
goto end;
@@ -458,8 +453,6 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
if ((bst->state & 0x01) && (bst->state & 0x02)) {
seq_printf(seq,
"charging state: charging/discharging\n");
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Battery Charging and Discharging?\n"));
} else if (bst->state & 0x01)
seq_printf(seq, "charging state: discharging\n");
else if (bst->state & 0x02)
@@ -489,7 +482,7 @@ static int acpi_battery_read_state(struct seq_file *seq, void *offset)
end:
kfree(bst);
- return_VALUE(0);
+ return 0;
}
static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
@@ -502,7 +495,6 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
struct acpi_battery *battery = (struct acpi_battery *)seq->private;
char *units = "?";
- ACPI_FUNCTION_TRACE("acpi_battery_read_alarm");
if (!battery)
goto end;
@@ -527,7 +519,7 @@ static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
end:
- return_VALUE(0);
+ return 0;
}
static ssize_t
@@ -540,25 +532,24 @@ acpi_battery_write_alarm(struct file *file,
struct seq_file *m = (struct seq_file *)file->private_data;
struct acpi_battery *battery = (struct acpi_battery *)m->private;
- ACPI_FUNCTION_TRACE("acpi_battery_write_alarm");
if (!battery || (count > sizeof(alarm_string) - 1))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!battery->flags.present)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (copy_from_user(alarm_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
alarm_string[count] = '\0';
result = acpi_battery_set_alarm(battery,
simple_strtoul(alarm_string, NULL, 0));
if (result)
- return_VALUE(result);
+ return result;
- return_VALUE(count);
+ return count;
}
static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
@@ -566,7 +557,7 @@ static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
}
-static struct file_operations acpi_battery_info_ops = {
+static const struct file_operations acpi_battery_info_ops = {
.open = acpi_battery_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -574,7 +565,7 @@ static struct file_operations acpi_battery_info_ops = {
.owner = THIS_MODULE,
};
-static struct file_operations acpi_battery_state_ops = {
+static const struct file_operations acpi_battery_state_ops = {
.open = acpi_battery_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -582,7 +573,7 @@ static struct file_operations acpi_battery_state_ops = {
.owner = THIS_MODULE,
};
-static struct file_operations acpi_battery_alarm_ops = {
+static const struct file_operations acpi_battery_alarm_ops = {
.open = acpi_battery_alarm_open_fs,
.read = seq_read,
.write = acpi_battery_write_alarm,
@@ -595,13 +586,12 @@ static int acpi_battery_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_battery_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_device_dir(device)->owner = THIS_MODULE;
}
@@ -609,9 +599,7 @@ static int acpi_battery_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BATTERY_FILE_INFO));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_battery_info_ops;
entry->data = acpi_driver_data(device);
@@ -622,9 +610,7 @@ static int acpi_battery_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BATTERY_FILE_STATUS));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_battery_state_ops;
entry->data = acpi_driver_data(device);
@@ -636,21 +622,18 @@ static int acpi_battery_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BATTERY_FILE_ALARM));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_battery_alarm_ops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_battery_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_battery_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
@@ -664,7 +647,7 @@ static int acpi_battery_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -676,17 +659,17 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
struct acpi_battery *battery = (struct acpi_battery *)data;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_notify");
if (!battery)
- return_VOID;
+ return;
- if (acpi_bus_get_device(handle, &device))
- return_VOID;
+ device = battery->device;
switch (event) {
case ACPI_BATTERY_NOTIFY_STATUS:
case ACPI_BATTERY_NOTIFY_INFO:
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
acpi_battery_check(battery);
acpi_bus_generate_event(device, event, battery->flags.present);
break;
@@ -696,7 +679,7 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static int acpi_battery_add(struct acpi_device *device)
@@ -705,17 +688,16 @@ static int acpi_battery_add(struct acpi_device *device)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(battery, 0, sizeof(struct acpi_battery));
- battery->handle = device->handle;
+ battery->device = device;
strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
acpi_driver_data(device) = battery;
@@ -728,12 +710,10 @@ static int acpi_battery_add(struct acpi_device *device)
if (result)
goto end;
- status = acpi_install_notify_handler(battery->handle,
- ACPI_DEVICE_NOTIFY,
+ status = acpi_install_notify_handler(device->handle,
+ ACPI_ALL_NOTIFY,
acpi_battery_notify, battery);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
result = -ENODEV;
goto end;
}
@@ -748,7 +728,7 @@ static int acpi_battery_add(struct acpi_device *device)
kfree(battery);
}
- return_VALUE(result);
+ return result;
}
static int acpi_battery_remove(struct acpi_device *device, int type)
@@ -756,56 +736,51 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
acpi_status status = 0;
struct acpi_battery *battery = NULL;
- ACPI_FUNCTION_TRACE("acpi_battery_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
battery = (struct acpi_battery *)acpi_driver_data(device);
- status = acpi_remove_notify_handler(battery->handle,
- ACPI_DEVICE_NOTIFY,
+ status = acpi_remove_notify_handler(device->handle,
+ ACPI_ALL_NOTIFY,
acpi_battery_notify);
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
acpi_battery_remove_fs(device);
kfree(battery);
- return_VALUE(0);
+ return 0;
}
static int __init acpi_battery_init(void)
{
- int result = 0;
+ int result;
- ACPI_FUNCTION_TRACE("acpi_battery_init");
+ if (acpi_disabled)
+ return -ENODEV;
- acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
+ acpi_battery_dir = acpi_lock_battery_dir();
if (!acpi_battery_dir)
- return_VALUE(-ENODEV);
- acpi_battery_dir->owner = THIS_MODULE;
+ return -ENODEV;
result = acpi_bus_register_driver(&acpi_battery_driver);
if (result < 0) {
- remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ acpi_unlock_battery_dir(acpi_battery_dir);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_battery_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_battery_exit");
acpi_bus_unregister_driver(&acpi_battery_driver);
- remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
+ acpi_unlock_battery_dir(acpi_battery_dir);
- return_VOID;
+ return;
}
module_init(acpi_battery_init);
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index dd3983cece9..279c4bac92e 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/sched.h>
#include <linux/pm.h>
@@ -60,21 +61,20 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_bus_get_device");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* TBD: Support fixed-feature devices */
status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device);
if (ACPI_FAILURE(status) || !*device) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "No context for object [%p]\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
handle));
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_get_device);
@@ -84,10 +84,9 @@ int acpi_bus_get_status(struct acpi_device *device)
acpi_status status = AE_OK;
unsigned long sta = 0;
- ACPI_FUNCTION_TRACE("acpi_bus_get_status");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* Evaluate _STA if present.
@@ -96,7 +95,7 @@ int acpi_bus_get_status(struct acpi_device *device)
status =
acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
STRUCT_TO_INT(device->status) = (int)sta;
}
@@ -120,7 +119,7 @@ int acpi_bus_get_status(struct acpi_device *device)
device->pnp.bus_id,
(u32) STRUCT_TO_INT(device->status)));
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_get_status);
@@ -136,11 +135,10 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
struct acpi_device *device = NULL;
unsigned long psc = 0;
- ACPI_FUNCTION_TRACE("acpi_bus_get_power");
result = acpi_bus_get_device(handle, &device);
if (result)
- return_VALUE(result);
+ return result;
*state = ACPI_STATE_UNKNOWN;
@@ -159,12 +157,12 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
status = acpi_evaluate_integer(device->handle, "_PSC",
NULL, &psc);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
device->power.state = (int)psc;
} else if (device->power.flags.power_resources) {
result = acpi_power_get_inferred_state(device);
if (result)
- return_VALUE(result);
+ return result;
}
*state = device->power.state;
@@ -173,7 +171,7 @@ int acpi_bus_get_power(acpi_handle handle, int *state)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
device->pnp.bus_id, device->power.state));
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_get_power);
@@ -185,21 +183,20 @@ int acpi_bus_set_power(acpi_handle handle, int state)
struct acpi_device *device = NULL;
char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' };
- ACPI_FUNCTION_TRACE("acpi_bus_set_power");
result = acpi_bus_get_device(handle, &device);
if (result)
- return_VALUE(result);
+ return result;
if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Make sure this is a valid target state */
if (!device->flags.power_manageable) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Device is not power manageable\n"));
- return_VALUE(-ENODEV);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
+ device->kobj.name));
+ return -ENODEV;
}
/*
* Get device's current power state if it's unknown
@@ -211,18 +208,18 @@ int acpi_bus_set_power(acpi_handle handle, int state)
if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n",
state));
- return_VALUE(0);
+ return 0;
}
}
if (!device->power.states[state].flags.valid) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n",
- state));
- return_VALUE(-ENODEV);
+ printk(KERN_WARNING PREFIX "Device does not support D%d\n", state);
+ return -ENODEV;
}
if (device->parent && (state < device->parent->power.state)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Cannot set device to a higher-powered state than parent\n"));
- return_VALUE(-ENODEV);
+ printk(KERN_WARNING PREFIX
+ "Cannot set device to a higher-powered"
+ " state than parent\n");
+ return -ENODEV;
}
/*
@@ -264,15 +261,15 @@ int acpi_bus_set_power(acpi_handle handle, int state)
end:
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Error transitioning device [%s] to D%d\n",
- device->pnp.bus_id, state));
+ printk(KERN_WARNING PREFIX
+ "Transitioning device [%s] to D%d\n",
+ device->pnp.bus_id, state);
else
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device [%s] transitioned to D%d\n",
device->pnp.bus_id, state));
- return_VALUE(result);
+ return result;
}
EXPORT_SYMBOL(acpi_bus_set_power);
@@ -293,18 +290,17 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
struct acpi_bus_event *event = NULL;
unsigned long flags = 0;
- ACPI_FUNCTION_TRACE("acpi_bus_generate_event");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* drop event on the floor if no one's listening */
if (!event_is_open)
- return_VALUE(0);
+ return 0;
event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
if (!event)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
strcpy(event->device_class, device->pnp.device_class);
strcpy(event->bus_id, device->pnp.bus_id);
@@ -317,7 +313,7 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
wake_up_interruptible(&acpi_bus_event_queue);
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_generate_event);
@@ -329,10 +325,9 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
DECLARE_WAITQUEUE(wait, current);
- ACPI_FUNCTION_TRACE("acpi_bus_receive_event");
if (!event)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (list_empty(&acpi_bus_event_list)) {
@@ -346,7 +341,7 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
set_current_state(TASK_RUNNING);
if (signal_pending(current))
- return_VALUE(-ERESTARTSYS);
+ return -ERESTARTSYS;
}
spin_lock_irqsave(&acpi_bus_event_lock, flags);
@@ -357,13 +352,13 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
if (!entry)
- return_VALUE(-ENODEV);
+ return -ENODEV;
memcpy(event, entry, sizeof(struct acpi_bus_event));
kfree(entry);
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_receive_event);
@@ -378,10 +373,9 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
acpi_status status = 0;
struct acpi_device_status old_status;
- ACPI_FUNCTION_TRACE("acpi_bus_check_device");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (status_changed)
*status_changed = 0;
@@ -398,15 +392,15 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
if (status_changed)
*status_changed = 1;
}
- return_VALUE(0);
+ return 0;
}
status = acpi_bus_get_status(device);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
- return_VALUE(0);
+ return 0;
if (status_changed)
*status_changed = 1;
@@ -422,7 +416,7 @@ acpi_bus_check_device(struct acpi_device *device, int *status_changed)
/* TBD: Handle device removal */
}
- return_VALUE(0);
+ return 0;
}
static int acpi_bus_check_scope(struct acpi_device *device)
@@ -430,25 +424,24 @@ static int acpi_bus_check_scope(struct acpi_device *device)
int result = 0;
int status_changed = 0;
- ACPI_FUNCTION_TRACE("acpi_bus_check_scope");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Status Change? */
result = acpi_bus_check_device(device, &status_changed);
if (result)
- return_VALUE(result);
+ return result;
if (!status_changed)
- return_VALUE(0);
+ return 0;
/*
* TBD: Enumerate child devices within this device's scope and
* run acpi_bus_check_device()'s on them.
*/
- return_VALUE(0);
+ return 0;
}
/**
@@ -461,10 +454,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
int result = 0;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_notify");
if (acpi_bus_get_device(handle, &device))
- return_VOID;
+ return;
switch (type) {
@@ -539,7 +531,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
break;
}
- return_VOID;
+ return;
}
/* --------------------------------------------------------------------------
@@ -553,7 +545,6 @@ static int __init acpi_bus_init_irq(void)
struct acpi_object_list arg_list = { 1, &arg };
char *message = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_init_irq");
/*
* Let the system know what interrupt model we are using by
@@ -572,7 +563,7 @@ static int __init acpi_bus_init_irq(void)
break;
default:
printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
@@ -581,11 +572,11 @@ static int __init acpi_bus_init_irq(void)
status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PIC"));
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
void __init acpi_early_init(void)
@@ -593,10 +584,9 @@ void __init acpi_early_init(void)
acpi_status status = AE_OK;
struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
- ACPI_FUNCTION_TRACE("acpi_early_init");
if (acpi_disabled)
- return_VOID;
+ return;
printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
@@ -656,11 +646,11 @@ void __init acpi_early_init(void)
goto error0;
}
- return_VOID;
+ return;
error0:
disable_acpi();
- return_VOID;
+ return;
}
static int __init acpi_bus_init(void)
@@ -669,7 +659,6 @@ static int __init acpi_bus_init(void)
acpi_status status = AE_OK;
extern acpi_status acpi_os_initialize1(void);
- ACPI_FUNCTION_TRACE("acpi_bus_init");
status = acpi_os_initialize1();
@@ -731,12 +720,12 @@ static int __init acpi_bus_init(void)
*/
acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
- return_VALUE(0);
+ return 0;
/* Mimic structured exception handling */
error1:
acpi_terminate();
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
decl_subsys(acpi, NULL, NULL);
@@ -745,14 +734,16 @@ static int __init acpi_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_init");
if (acpi_disabled) {
printk(KERN_INFO PREFIX "Interpreter disabled.\n");
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- firmware_register(&acpi_subsys);
+ result = firmware_register(&acpi_subsys);
+ if (result < 0)
+ printk(KERN_WARNING "%s: firmware_register error: %d\n",
+ __FUNCTION__, result);
result = acpi_bus_init();
@@ -770,7 +761,7 @@ static int __init acpi_init(void)
} else
disable_acpi();
- return_VALUE(result);
+ return result;
}
subsys_initcall(acpi_init);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 4b6d9f0096a..5ef885e82c7 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -82,20 +82,19 @@ static struct acpi_driver acpi_button_driver = {
};
struct acpi_button {
- acpi_handle handle;
struct acpi_device *device; /* Fixed button kludge */
u8 type;
unsigned long pushed;
};
-static struct file_operations acpi_button_info_fops = {
+static const struct file_operations acpi_button_info_fops = {
.open = acpi_button_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_button_state_fops = {
+static const struct file_operations acpi_button_state_fops = {
.open = acpi_button_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -112,15 +111,14 @@ static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_button *button = (struct acpi_button *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_button_info_seq_show");
if (!button || !button->device)
- return_VALUE(0);
+ return 0;
seq_printf(seq, "type: %s\n",
acpi_device_name(button->device));
- return_VALUE(0);
+ return 0;
}
static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
@@ -134,12 +132,11 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
acpi_status status;
unsigned long state;
- ACPI_FUNCTION_TRACE("acpi_button_state_seq_show");
if (!button || !button->device)
- return_VALUE(0);
+ return 0;
- status = acpi_evaluate_integer(button->handle, "_LID", NULL, &state);
+ status = acpi_evaluate_integer(button->device->handle, "_LID", NULL, &state);
if (ACPI_FAILURE(status)) {
seq_printf(seq, "state: unsupported\n");
} else {
@@ -147,7 +144,7 @@ static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
(state ? "open" : "closed"));
}
- return_VALUE(0);
+ return 0;
}
static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
@@ -164,10 +161,9 @@ static int acpi_button_add_fs(struct acpi_device *device)
struct proc_dir_entry *entry = NULL;
struct acpi_button *button = NULL;
- ACPI_FUNCTION_TRACE("acpi_button_add_fs");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
button = acpi_driver_data(device);
@@ -195,21 +191,19 @@ static int acpi_button_add_fs(struct acpi_device *device)
}
if (!entry)
- return_VALUE(-ENODEV);
+ return -ENODEV;
entry->owner = THIS_MODULE;
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_device_dir(device)->owner = THIS_MODULE;
/* 'info' [R] */
entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BUTTON_FILE_INFO));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_button_info_fops;
entry->data = acpi_driver_data(device);
@@ -221,9 +215,7 @@ static int acpi_button_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BUTTON_FILE_INFO));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_button_state_fops;
entry->data = acpi_driver_data(device);
@@ -231,14 +223,13 @@ static int acpi_button_add_fs(struct acpi_device *device)
}
}
- return_VALUE(0);
+ return 0;
}
static int acpi_button_remove_fs(struct acpi_device *device)
{
struct acpi_button *button = NULL;
- ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
button = acpi_driver_data(device);
if (acpi_device_dir(device)) {
@@ -253,7 +244,7 @@ static int acpi_button_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -264,10 +255,9 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_button *button = (struct acpi_button *)data;
- ACPI_FUNCTION_TRACE("acpi_button_notify");
if (!button || !button->device)
- return_VOID;
+ return;
switch (event) {
case ACPI_BUTTON_NOTIFY_STATUS:
@@ -280,21 +270,20 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static acpi_status acpi_button_notify_fixed(void *data)
{
struct acpi_button *button = (struct acpi_button *)data;
- ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
if (!button)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
- acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
+ acpi_button_notify(button->device->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
static int acpi_button_add(struct acpi_device *device)
@@ -303,18 +292,16 @@ static int acpi_button_add(struct acpi_device *device)
acpi_status status = AE_OK;
struct acpi_button *button = NULL;
- ACPI_FUNCTION_TRACE("acpi_button_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
if (!button)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(button, 0, sizeof(struct acpi_button));
button->device = device;
- button->handle = device->handle;
acpi_driver_data(device) = button;
/*
@@ -349,8 +336,8 @@ static int acpi_button_add(struct acpi_device *device)
sprintf(acpi_device_class(device), "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
- acpi_device_hid(device)));
+ printk(KERN_ERR PREFIX "Unsupported hid [%s]\n",
+ acpi_device_hid(device));
result = -ENODEV;
goto end;
}
@@ -373,7 +360,7 @@ static int acpi_button_add(struct acpi_device *device)
button);
break;
default:
- status = acpi_install_notify_handler(button->handle,
+ status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_button_notify,
button);
@@ -381,8 +368,6 @@ static int acpi_button_add(struct acpi_device *device)
}
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
result = -ENODEV;
goto end;
}
@@ -406,7 +391,7 @@ static int acpi_button_add(struct acpi_device *device)
kfree(button);
}
- return_VALUE(result);
+ return result;
}
static int acpi_button_remove(struct acpi_device *device, int type)
@@ -414,10 +399,9 @@ static int acpi_button_remove(struct acpi_device *device, int type)
acpi_status status = 0;
struct acpi_button *button = NULL;
- ACPI_FUNCTION_TRACE("acpi_button_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
button = acpi_driver_data(device);
@@ -434,45 +418,39 @@ static int acpi_button_remove(struct acpi_device *device, int type)
acpi_button_notify_fixed);
break;
default:
- status = acpi_remove_notify_handler(button->handle,
+ status = acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_button_notify);
break;
}
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
-
acpi_button_remove_fs(device);
kfree(button);
- return_VALUE(0);
+ return 0;
}
static int __init acpi_button_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_button_init");
acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
if (!acpi_button_dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_button_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_button_driver);
if (result < 0) {
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_button_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_button_exit");
acpi_bus_unregister_driver(&acpi_button_driver);
@@ -484,7 +462,7 @@ static void __exit acpi_button_exit(void)
remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID, acpi_button_dir);
remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
module_init(acpi_button_init);
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
new file mode 100644
index 00000000000..a01ce6700bf
--- /dev/null
+++ b/drivers/acpi/cm_sbs.c
@@ -0,0 +1,113 @@
+/*
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+#include <acpi/acutils.h>
+
+ACPI_MODULE_NAME("cm_sbs")
+#define ACPI_AC_CLASS "ac_adapter"
+#define ACPI_BATTERY_CLASS "battery"
+#define ACPI_SBS_COMPONENT 0x00080000
+#define _COMPONENT ACPI_SBS_COMPONENT
+static struct proc_dir_entry *acpi_ac_dir;
+static struct proc_dir_entry *acpi_battery_dir;
+
+static DEFINE_MUTEX(cm_sbs_mutex);
+
+static int lock_ac_dir_cnt;
+static int lock_battery_dir_cnt;
+
+struct proc_dir_entry *acpi_lock_ac_dir(void)
+{
+ mutex_lock(&cm_sbs_mutex);
+ if (!acpi_ac_dir)
+ acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
+ if (acpi_ac_dir) {
+ lock_ac_dir_cnt++;
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Cannot create %s\n", ACPI_AC_CLASS));
+ }
+ mutex_unlock(&cm_sbs_mutex);
+ return acpi_ac_dir;
+}
+EXPORT_SYMBOL(acpi_lock_ac_dir);
+
+void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)
+{
+ mutex_lock(&cm_sbs_mutex);
+ if (acpi_ac_dir_param)
+ lock_ac_dir_cnt--;
+ if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
+ remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
+ acpi_ac_dir = 0;
+ }
+ mutex_unlock(&cm_sbs_mutex);
+}
+EXPORT_SYMBOL(acpi_unlock_ac_dir);
+
+struct proc_dir_entry *acpi_lock_battery_dir(void)
+{
+ mutex_lock(&cm_sbs_mutex);
+ if (!acpi_battery_dir) {
+ acpi_battery_dir =
+ proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
+ }
+ if (acpi_battery_dir) {
+ lock_battery_dir_cnt++;
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Cannot create %s\n", ACPI_BATTERY_CLASS));
+ }
+ mutex_unlock(&cm_sbs_mutex);
+ return acpi_battery_dir;
+}
+EXPORT_SYMBOL(acpi_lock_battery_dir);
+
+void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)
+{
+ mutex_lock(&cm_sbs_mutex);
+ if (acpi_battery_dir_param)
+ lock_battery_dir_cnt--;
+ if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
+ && acpi_battery_dir) {
+ remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
+ acpi_battery_dir = 0;
+ }
+ mutex_unlock(&cm_sbs_mutex);
+ return;
+}
+EXPORT_SYMBOL(acpi_unlock_battery_dir);
+
+static int __init acpi_cm_sbs_init(void)
+{
+ return 0;
+}
+subsys_initcall(acpi_cm_sbs_init);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index b69a8cad82b..871aa520ece 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -73,17 +73,16 @@ static int is_device_present(acpi_handle handle)
acpi_status status;
unsigned long sta;
- ACPI_FUNCTION_TRACE("is_device_present");
status = acpi_get_handle(handle, "_STA", &temp);
if (ACPI_FAILURE(status))
- return_VALUE(1); /* _STA not found, assmue device present */
+ return 1; /* _STA not found, assmue device present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
- return_VALUE(0); /* Firmware error */
+ return 0; /* Firmware error */
- return_VALUE((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+ return ((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
}
/*******************************************************************/
@@ -91,16 +90,15 @@ static int acpi_container_add(struct acpi_device *device)
{
struct acpi_container *container;
- ACPI_FUNCTION_TRACE("acpi_container_add");
if (!device) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "device is NULL\n"));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "device is NULL\n");
+ return -EINVAL;
}
container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
if (!container)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(container, 0, sizeof(struct acpi_container));
container->handle = device->handle;
@@ -111,7 +109,7 @@ static int acpi_container_add(struct acpi_device *device)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
acpi_device_name(device), acpi_device_bid(device)));
- return_VALUE(0);
+ return 0;
}
static int acpi_container_remove(struct acpi_device *device, int type)
@@ -130,23 +128,22 @@ static int container_device_add(struct acpi_device **device, acpi_handle handle)
struct acpi_device *pdev;
int result;
- ACPI_FUNCTION_TRACE("container_device_add");
if (acpi_get_parent(handle, &phandle)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (acpi_bus_get_device(phandle, &pdev)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
result = acpi_bus_start(*device);
- return_VALUE(result);
+ return result;
}
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
@@ -156,7 +153,6 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
int present;
acpi_status status;
- ACPI_FUNCTION_TRACE("container_notify_cb");
present = is_device_present(handle);
@@ -192,7 +188,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
default:
break;
}
- return_VOID;
+ return;
}
static acpi_status
@@ -205,11 +201,10 @@ container_walk_namespace_cb(acpi_handle handle,
acpi_status status;
int *action = context;
- ACPI_FUNCTION_TRACE("container_walk_namespace_cb");
status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status) || !buffer.pointer) {
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
info = buffer.pointer;
@@ -241,9 +236,9 @@ container_walk_namespace_cb(acpi_handle handle,
}
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
static int __init acpi_container_init(void)
@@ -269,7 +264,6 @@ static void __exit acpi_container_exit(void)
{
int action = UNINSTALL_NOTIFY_HANDLER;
- ACPI_FUNCTION_TRACE("acpi_container_exit");
acpi_walk_namespace(ACPI_TYPE_DEVICE,
ACPI_ROOT_OBJECT,
@@ -278,7 +272,7 @@ static void __exit acpi_container_exit(void)
acpi_bus_unregister_driver(&acpi_container_driver);
- return_VOID;
+ return;
}
module_init(acpi_container_init);
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
index 263322b7d11..35c6af8a83c 100644
--- a/drivers/acpi/debug.c
+++ b/drivers/acpi/debug.c
@@ -155,13 +155,12 @@ acpi_system_write_debug(struct file *file,
{
char debug_string[12] = { '\0' };
- ACPI_FUNCTION_TRACE("acpi_system_write_debug");
if (count > sizeof(debug_string) - 1)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(debug_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
debug_string[count] = '\0';
@@ -173,10 +172,10 @@ acpi_system_write_debug(struct file *file,
acpi_dbg_level = simple_strtoul(debug_string, NULL, 0);
break;
default:
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
- return_VALUE(count);
+ return count;
}
static int __init acpi_debug_init(void)
@@ -185,10 +184,9 @@ static int __init acpi_debug_init(void)
int error = 0;
char *name;
- ACPI_FUNCTION_TRACE("acpi_debug_init");
if (acpi_disabled)
- return_VALUE(0);
+ return 0;
/* 'debug_layer' [R/W] */
name = ACPI_SYSTEM_FILE_DEBUG_LAYER;
@@ -213,15 +211,12 @@ static int __init acpi_debug_init(void)
goto Error;
Done:
- return_VALUE(error);
+ return error;
Error:
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' proc fs entry\n", name));
-
remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir);
- error = -EFAULT;
+ error = -ENODEV;
goto Done;
}
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index bbdf990e9f6..1888c055d10 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -116,46 +116,6 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
case ACPI_TYPE_METHOD:
- /*
- * Set the execution data width (32 or 64) based upon the
- * revision number of the parent ACPI table.
- * TBD: This is really for possible future support of integer width
- * on a per-table basis. Currently, we just use a global for the width.
- */
- if (info->table_desc->pointer->revision == 1) {
- node->flags |= ANOBJ_DATA_WIDTH_32;
- }
-#ifdef ACPI_INIT_PARSE_METHODS
- /*
- * Note 11/2005: Removed this code to parse all methods during table
- * load because it causes problems if there are any errors during the
- * parse. Also, it seems like overkill and we probably don't want to
- * abort a table load because of an issue with a single method.
- */
-
- /*
- * Print a dot for each method unless we are going to print
- * the entire pathname
- */
- if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "."));
- }
-
- /*
- * Always parse methods to detect errors, we will delete
- * the parse tree below
- */
- status = acpi_ds_parse_method(obj_handle);
- if (ACPI_FAILURE(status)) {
- ACPI_ERROR((AE_INFO,
- "Method %p [%4.4s] - parse failure, %s",
- obj_handle,
- acpi_ut_get_node_name(obj_handle),
- acpi_format_exception(status)));
-
- /* This parse failed, but we will continue parsing more methods */
- }
-#endif
info->method_count++;
break;
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index bc9aca4e740..cf888add319 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -52,6 +52,10 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsmethod")
+/* Local prototypes */
+static acpi_status
+acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
+
/*******************************************************************************
*
* FUNCTION: acpi_ds_method_error
@@ -67,6 +71,7 @@ ACPI_MODULE_NAME("dsmethod")
* Note: Allows the exception handler to change the status code
*
******************************************************************************/
+
acpi_status
acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
{
@@ -113,11 +118,51 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_create_method_mutex
+ *
+ * PARAMETERS: obj_desc - The method object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a mutex object for a serialized control method
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
+{
+ union acpi_operand_object *mutex_desc;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(ds_create_method_mutex);
+
+ /* Create the new mutex object */
+
+ mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
+ if (!mutex_desc) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Create the actual OS Mutex */
+
+ status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ mutex_desc->mutex.sync_level = method_desc->method.sync_level;
+ method_desc->method.mutex = mutex_desc;
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_begin_method_execution
*
* PARAMETERS: method_node - Node of the method
* obj_desc - The method object
- * calling_method_node - Caller of this method (if non-null)
+ * walk_state - current state, NULL if not yet executing
+ * a method.
*
* RETURN: Status
*
@@ -128,9 +173,9 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
******************************************************************************/
acpi_status
-acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
- union acpi_operand_object * obj_desc,
- struct acpi_namespace_node * calling_method_node)
+acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state)
{
acpi_status status = AE_OK;
@@ -149,35 +194,80 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
}
/*
- * If there is a concurrency limit on this method, we need to
- * obtain a unit from the method semaphore.
+ * If this method is serialized, we need to acquire the method mutex.
*/
- if (obj_desc->method.semaphore) {
+ if (obj_desc->method.method_flags & AML_METHOD_SERIALIZED) {
/*
- * Allow recursive method calls, up to the reentrancy/concurrency
- * limit imposed by the SERIALIZED rule and the sync_level method
- * parameter.
- *
- * The point of this code is to avoid permanently blocking a
- * thread that is making recursive method calls.
+ * Create a mutex for the method if it is defined to be Serialized
+ * and a mutex has not already been created. We defer the mutex creation
+ * until a method is actually executed, to minimize the object count
*/
- if (method_node == calling_method_node) {
- if (obj_desc->method.thread_count >=
- obj_desc->method.concurrency) {
- return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
+ if (!obj_desc->method.mutex) {
+ status = acpi_ds_create_method_mutex(obj_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
}
}
/*
- * Get a unit from the method semaphore. This releases the
- * interpreter if we block (then reacquires it)
+ * The current_sync_level (per-thread) must be less than or equal to
+ * the sync level of the method. This mechanism provides some
+ * deadlock prevention
+ *
+ * Top-level method invocation has no walk state at this point
*/
- status =
- acpi_ex_system_wait_semaphore(obj_desc->method.semaphore,
- ACPI_WAIT_FOREVER);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if (walk_state &&
+ (walk_state->thread->current_sync_level >
+ obj_desc->method.mutex->mutex.sync_level)) {
+ ACPI_ERROR((AE_INFO,
+ "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%d)",
+ acpi_ut_get_node_name(method_node),
+ walk_state->thread->current_sync_level));
+
+ return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
+
+ /*
+ * Obtain the method mutex if necessary. Do not acquire mutex for a
+ * recursive call.
+ */
+ if (!walk_state ||
+ !obj_desc->method.mutex->mutex.owner_thread ||
+ (walk_state->thread !=
+ obj_desc->method.mutex->mutex.owner_thread)) {
+ /*
+ * Acquire the method mutex. This releases the interpreter if we
+ * block (and reacquires it before it returns)
+ */
+ status =
+ acpi_ex_system_wait_mutex(obj_desc->method.mutex->
+ mutex.os_mutex,
+ ACPI_WAIT_FOREVER);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Update the mutex and walk info and save the original sync_level */
+
+ if (walk_state) {
+ obj_desc->method.mutex->mutex.
+ original_sync_level =
+ walk_state->thread->current_sync_level;
+
+ obj_desc->method.mutex->mutex.owner_thread =
+ walk_state->thread;
+ walk_state->thread->current_sync_level =
+ obj_desc->method.sync_level;
+ } else {
+ obj_desc->method.mutex->mutex.
+ original_sync_level =
+ obj_desc->method.mutex->mutex.sync_level;
+ }
+ }
+
+ /* Always increase acquisition depth */
+
+ obj_desc->method.mutex->mutex.acquisition_depth++;
}
/*
@@ -200,10 +290,10 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node * method_node,
return_ACPI_STATUS(status);
cleanup:
- /* On error, must signal the method semaphore if present */
+ /* On error, must release the method mutex (if present) */
- if (obj_desc->method.semaphore) {
- (void)acpi_os_signal_semaphore(obj_desc->method.semaphore, 1);
+ if (obj_desc->method.mutex) {
+ acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
}
return_ACPI_STATUS(status);
}
@@ -253,10 +343,10 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
return_ACPI_STATUS(AE_NULL_OBJECT);
}
- /* Init for new method, possibly wait on concurrency semaphore */
+ /* Init for new method, possibly wait on method mutex */
status = acpi_ds_begin_method_execution(method_node, obj_desc,
- this_walk_state->method_node);
+ this_walk_state);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -403,7 +493,7 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
- (char *)&walk_state->method_node->name,
+ acpi_ut_get_node_name(walk_state->method_node),
walk_state->method_call_op, return_desc));
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
@@ -478,6 +568,8 @@ acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
* created, delete all locals and arguments, and delete the parse
* tree if requested.
*
+ * MUTEX: Interpreter is locked
+ *
******************************************************************************/
void
@@ -503,26 +595,22 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
}
/*
- * Lock the parser while we terminate this method.
- * If this is the last thread executing the method,
- * we have additional cleanup to perform
+ * If method is serialized, release the mutex and restore the
+ * current sync level for this thread
*/
- status = acpi_ut_acquire_mutex(ACPI_MTX_CONTROL_METHOD);
- if (ACPI_FAILURE(status)) {
- return_VOID;
- }
-
- /* Signal completion of the execution of this method if necessary */
+ if (method_desc->method.mutex) {
- if (method_desc->method.semaphore) {
- status =
- acpi_os_signal_semaphore(method_desc->method.semaphore, 1);
- if (ACPI_FAILURE(status)) {
+ /* Acquisition Depth handles recursive calls */
- /* Ignore error and continue */
+ method_desc->method.mutex->mutex.acquisition_depth--;
+ if (!method_desc->method.mutex->mutex.acquisition_depth) {
+ walk_state->thread->current_sync_level =
+ method_desc->method.mutex->mutex.
+ original_sync_level;
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not signal method semaphore"));
+ acpi_os_release_mutex(method_desc->method.mutex->mutex.
+ os_mutex);
+ method_desc->method.mutex->mutex.owner_thread = NULL;
}
}
@@ -533,27 +621,11 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
*/
method_node = walk_state->method_node;
- /* Lock namespace for possible update */
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- goto exit;
- }
-
- /*
- * Delete any namespace entries created immediately underneath
- * the method
- */
- if (method_node && method_node->child) {
- acpi_ns_delete_namespace_subtree(method_node);
- }
-
/*
- * Delete any namespace entries created anywhere else within
+ * Delete any namespace objects created anywhere within
* the namespace by the execution of this method
*/
acpi_ns_delete_namespace_by_owner(method_desc->method.owner_id);
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
}
/* Decrement the thread count on the method */
@@ -580,18 +652,16 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
/*
* Support to dynamically change a method from not_serialized to
* Serialized if it appears that the method is incorrectly written and
- * does not support multiple thread execution. The best example of this
- * is if such a method creates namespace objects and blocks. A second
+ * does not support multiple thread execution. The best example of this
+ * is if such a method creates namespace objects and blocks. A second
* thread will fail with an AE_ALREADY_EXISTS exception
*
* This code is here because we must wait until the last thread exits
* before creating the synchronization semaphore.
*/
- if ((method_desc->method.concurrency == 1) &&
- (!method_desc->method.semaphore)) {
- status = acpi_os_create_semaphore(1, 1,
- &method_desc->method.
- semaphore);
+ if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
+ && (!method_desc->method.mutex)) {
+ status = acpi_ds_create_method_mutex(method_desc);
}
/* No more threads, we can free the owner_id */
@@ -599,144 +669,5 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
acpi_ut_release_owner_id(&method_desc->method.owner_id);
}
- exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_CONTROL_METHOD);
return_VOID;
}
-
-#ifdef ACPI_INIT_PARSE_METHODS
- /*
- * Note 11/2005: Removed this code to parse all methods during table
- * load because it causes problems if there are any errors during the
- * parse. Also, it seems like overkill and we probably don't want to
- * abort a table load because of an issue with a single method.
- */
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_parse_method
- *
- * PARAMETERS: Node - Method node
- *
- * RETURN: Status
- *
- * DESCRIPTION: Parse the AML that is associated with the method.
- *
- * MUTEX: Assumes parser is locked
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node)
-{
- acpi_status status;
- union acpi_operand_object *obj_desc;
- union acpi_parse_object *op;
- struct acpi_walk_state *walk_state;
-
- ACPI_FUNCTION_TRACE_PTR(ds_parse_method, node);
-
- /* Parameter Validation */
-
- if (!node) {
- return_ACPI_STATUS(AE_NULL_ENTRY);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** Parsing [%4.4s] **** NamedObj=%p\n",
- acpi_ut_get_node_name(node), node));
-
- /* Extract the method object from the method Node */
-
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc) {
- return_ACPI_STATUS(AE_NULL_OBJECT);
- }
-
- /* Create a mutex for the method if there is a concurrency limit */
-
- if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
- (!obj_desc->method.semaphore)) {
- status = acpi_os_create_semaphore(obj_desc->method.concurrency,
- obj_desc->method.concurrency,
- &obj_desc->method.semaphore);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
- }
-
- /*
- * Allocate a new parser op to be the root of the parsed
- * method tree
- */
- op = acpi_ps_alloc_op(AML_METHOD_OP);
- if (!op) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /* Init new op with the method name and pointer back to the Node */
-
- acpi_ps_set_name(op, node->name.integer);
- op->common.node = node;
-
- /*
- * Get a new owner_id for objects created by this method. Namespace
- * objects (such as Operation Regions) can be created during the
- * first pass parse.
- */
- status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- /* Create and initialize a new walk state */
-
- walk_state =
- acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, NULL,
- NULL);
- if (!walk_state) {
- status = AE_NO_MEMORY;
- goto cleanup2;
- }
-
- status = acpi_ds_init_aml_walk(walk_state, op, node,
- obj_desc->method.aml_start,
- obj_desc->method.aml_length, NULL, 1);
- if (ACPI_FAILURE(status)) {
- acpi_ds_delete_walk_state(walk_state);
- goto cleanup2;
- }
-
- /*
- * Parse the method, first pass
- *
- * The first pass load is where newly declared named objects are added into
- * the namespace. Actual evaluation of the named objects (what would be
- * called a "second pass") happens during the actual execution of the
- * method so that operands to the named objects can take on dynamic
- * run-time values.
- */
- status = acpi_ps_parse_aml(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup2;
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
- "**** [%4.4s] Parsed **** NamedObj=%p Op=%p\n",
- acpi_ut_get_node_name(node), node, op));
-
- /*
- * Delete the parse tree. We simply re-parse the method for every
- * execution since there isn't much overhead (compared to keeping lots
- * of parse trees around)
- */
- acpi_ns_delete_namespace_subtree(node);
- acpi_ns_delete_namespace_by_owner(obj_desc->method.owner_id);
-
- cleanup2:
- acpi_ut_release_owner_id(&obj_desc->method.owner_id);
-
- cleanup:
- acpi_ps_delete_parse_tree(op);
- return_ACPI_STATUS(status);
-}
-#endif
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index 3acbd9145d7..d7a616c3104 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -313,10 +313,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
case AML_CLASS_EXECUTE:
case AML_CLASS_CREATE:
/*
- * Most operators with arguments.
+ * Most operators with arguments (except create_xxx_field operators)
* Start a new result/operand state
*/
- if (walk_state->opcode != AML_CREATE_FIELD_OP) {
+ if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) {
status = acpi_ds_result_stack_push(walk_state);
}
break;
@@ -472,7 +472,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
acpi_ds_result_push(walk_state->result_obj,
walk_state);
}
-
break;
default:
@@ -510,6 +509,7 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Method Reference in a Package, Op=%p\n",
op));
+
op->common.node =
(struct acpi_namespace_node *)op->asl.value.
arg->asl.node->object;
@@ -670,7 +670,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
status = acpi_ds_result_stack_pop(walk_state);
}
-
break;
case AML_TYPE_UNDEFINED:
@@ -708,7 +707,6 @@ acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *walk_state)
* Check if we just completed the evaluation of a
* conditional predicate
*/
-
if ((ACPI_SUCCESS(status)) &&
(walk_state->control_state) &&
(walk_state->control_state->common.state ==
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 35074399c61..e3ca7f6539c 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -175,7 +175,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
if (status == AE_NOT_FOUND) {
/*
* Table disassembly:
- * Target of Scope() not found. Generate an External for it, and
+ * Target of Scope() not found. Generate an External for it, and
* insert the name into the namespace.
*/
acpi_dm_add_to_external_list(path, ACPI_TYPE_DEVICE, 0);
@@ -210,16 +210,15 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
case ACPI_TYPE_BUFFER:
/*
- * These types we will allow, but we will change the type. This
+ * These types we will allow, but we will change the type. This
* enables some existing code of the form:
*
* Name (DEB, 0)
* Scope (DEB) { ... }
*
- * Note: silently change the type here. On the second pass, we will report
+ * Note: silently change the type here. On the second pass, we will report
* a warning
*/
-
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
path,
@@ -242,7 +241,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
break;
default:
-
/*
* For all other named opcodes, we will enter the name into
* the namespace.
@@ -259,7 +257,6 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
* buffer_field, or Package), the name of the object is already
* in the namespace.
*/
-
if (walk_state->deferred_node) {
/* This name is already in the namespace, get the node */
@@ -293,8 +290,8 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
}
/*
- * Enter the named type into the internal namespace. We enter the name
- * as we go downward in the parse tree. Any necessary subobjects that
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that
* involve arguments to the opcode must be created as we go back up the
* parse tree later.
*/
@@ -327,12 +324,12 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
(status);
}
}
+
status = AE_OK;
}
}
if (ACPI_FAILURE(status)) {
-
ACPI_ERROR_NAMESPACE(path, status);
return_ACPI_STATUS(status);
}
@@ -434,9 +431,13 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
status =
acpi_ex_create_region(op->named.data,
op->named.length,
- (acpi_adr_space_type)
- ((op->common.value.arg)->
- common.value.integer),
+ (acpi_adr_space_type) ((op->
+ common.
+ value.
+ arg)->
+ common.
+ value.
+ integer),
walk_state);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -474,7 +475,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
* method_op pkg_length name_string method_flags term_list
*
* Note: We must create the method node/object pair as soon as we
- * see the method declaration. This allows later pass1 parsing
+ * see the method declaration. This allows later pass1 parsing
* of invocations of the method (need to know the number of
* arguments.)
*/
@@ -499,6 +500,7 @@ acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state)
length,
walk_state);
}
+
walk_state->operands[0] = NULL;
walk_state->num_operands = 0;
@@ -570,7 +572,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
(walk_state->op_info->class == AML_CLASS_CONTROL)) {
-
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Begin/EXEC: %s (fl %8.8X)\n",
walk_state->op_info->name,
@@ -602,7 +603,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
} else {
/* Get name from the op */
- buffer_ptr = (char *)&op->named.name;
+ buffer_ptr = ACPI_CAST_PTR(char, &op->named.name);
}
} else {
/* Get the namestring from the raw AML */
@@ -629,7 +630,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
break;
case AML_INT_NAMEPATH_OP:
-
/*
* The name_path is an object reference to an existing object.
* Don't enter the name into the namespace, but look it up
@@ -642,7 +642,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
break;
case AML_SCOPE_OP:
-
/*
* The Path is an object reference to an existing object.
* Don't enter the name into the namespace, but look it up
@@ -664,6 +663,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
#endif
return_ACPI_STATUS(status);
}
+
/*
* We must check to make sure that the target is
* one of the opcodes that actually opens a scope
@@ -683,13 +683,12 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
case ACPI_TYPE_BUFFER:
/*
- * These types we will allow, but we will change the type. This
+ * These types we will allow, but we will change the type. This
* enables some existing code of the form:
*
* Name (DEB, 0)
* Scope (DEB) { ... }
*/
-
ACPI_WARNING((AE_INFO,
"Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)",
buffer_ptr,
@@ -729,14 +728,14 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
}
+
return_ACPI_STATUS(AE_OK);
}
/*
- * Enter the named type into the internal namespace. We enter the name
- * as we go downward in the parse tree. Any necessary subobjects that
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that
* involve arguments to the opcode must be created as we go back up the
* parse tree later.
*
@@ -787,7 +786,6 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
* can get it again quickly when this scope is closed
*/
op->common.node = node;
-
return_ACPI_STATUS(status);
}
@@ -922,7 +920,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_TYPE_CREATE_FIELD:
-
/*
* Create the field object, but the field buffer and index must
* be evaluated later during the execution phase
@@ -931,7 +928,6 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
break;
case AML_TYPE_NAMED_FIELD:
-
/*
* If we are executing a method, initialize the field
*/
@@ -1051,6 +1047,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
* argument is the space_id. (We must save the address of the
* AML of the address and length operands)
*/
+
/*
* If we have a valid region, initialize it
* Namespace is NOT locked at this point.
@@ -1080,7 +1077,7 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
* method_op pkg_length name_string method_flags term_list
*
* Note: We must create the method node/object pair as soon as we
- * see the method declaration. This allows later pass1 parsing
+ * see the method declaration. This allows later pass1 parsing
* of invocations of the method (need to know the number of
* arguments.)
*/
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
new file mode 100644
index 00000000000..578b99b71d9
--- /dev/null
+++ b/drivers/acpi/dock.c
@@ -0,0 +1,739 @@
+/*
+ * dock.c - ACPI dock station driver
+ *
+ * Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_DOCK_DRIVER_NAME "ACPI Dock Station Driver"
+
+ACPI_MODULE_NAME("dock")
+MODULE_AUTHOR("Kristen Carlson Accardi");
+MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static struct atomic_notifier_head dock_notifier_list;
+
+struct dock_station {
+ acpi_handle handle;
+ unsigned long last_dock_time;
+ u32 flags;
+ spinlock_t dd_lock;
+ spinlock_t hp_lock;
+ struct list_head dependent_devices;
+ struct list_head hotplug_devices;
+};
+
+struct dock_dependent_device {
+ struct list_head list;
+ struct list_head hotplug_list;
+ acpi_handle handle;
+ acpi_notify_handler handler;
+ void *context;
+};
+
+#define DOCK_DOCKING 0x00000001
+#define DOCK_EVENT 3
+#define UNDOCK_EVENT 2
+
+static struct dock_station *dock_station;
+
+/*****************************************************************************
+ * Dock Dependent device functions *
+ *****************************************************************************/
+/**
+ * alloc_dock_dependent_device - allocate and init a dependent device
+ * @handle: the acpi_handle of the dependent device
+ *
+ * Allocate memory for a dependent device structure for a device referenced
+ * by the acpi handle
+ */
+static struct dock_dependent_device *
+alloc_dock_dependent_device(acpi_handle handle)
+{
+ struct dock_dependent_device *dd;
+
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ if (dd) {
+ dd->handle = handle;
+ INIT_LIST_HEAD(&dd->list);
+ INIT_LIST_HEAD(&dd->hotplug_list);
+ }
+ return dd;
+}
+
+/**
+ * add_dock_dependent_device - associate a device with the dock station
+ * @ds: The dock station
+ * @dd: The dependent device
+ *
+ * Add the dependent device to the dock's dependent device list.
+ */
+static void
+add_dock_dependent_device(struct dock_station *ds,
+ struct dock_dependent_device *dd)
+{
+ spin_lock(&ds->dd_lock);
+ list_add_tail(&dd->list, &ds->dependent_devices);
+ spin_unlock(&ds->dd_lock);
+}
+
+/**
+ * dock_add_hotplug_device - associate a hotplug handler with the dock station
+ * @ds: The dock station
+ * @dd: The dependent device struct
+ *
+ * Add the dependent device to the dock's hotplug device list
+ */
+static void
+dock_add_hotplug_device(struct dock_station *ds,
+ struct dock_dependent_device *dd)
+{
+ spin_lock(&ds->hp_lock);
+ list_add_tail(&dd->hotplug_list, &ds->hotplug_devices);
+ spin_unlock(&ds->hp_lock);
+}
+
+/**
+ * dock_del_hotplug_device - remove a hotplug handler from the dock station
+ * @ds: The dock station
+ * @dd: the dependent device struct
+ *
+ * Delete the dependent device from the dock's hotplug device list
+ */
+static void
+dock_del_hotplug_device(struct dock_station *ds,
+ struct dock_dependent_device *dd)
+{
+ spin_lock(&ds->hp_lock);
+ list_del(&dd->hotplug_list);
+ spin_unlock(&ds->hp_lock);
+}
+
+/**
+ * find_dock_dependent_device - get a device dependent on this dock
+ * @ds: the dock station
+ * @handle: the acpi_handle of the device we want
+ *
+ * iterate over the dependent device list for this dock. If the
+ * dependent device matches the handle, return.
+ */
+static struct dock_dependent_device *
+find_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
+{
+ struct dock_dependent_device *dd;
+
+ spin_lock(&ds->dd_lock);
+ list_for_each_entry(dd, &ds->dependent_devices, list) {
+ if (handle == dd->handle) {
+ spin_unlock(&ds->dd_lock);
+ return dd;
+ }
+ }
+ spin_unlock(&ds->dd_lock);
+ return NULL;
+}
+
+/*****************************************************************************
+ * Dock functions *
+ *****************************************************************************/
+/**
+ * is_dock - see if a device is a dock station
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has a _DCK method, then it is by definition a dock
+ * station, so return true.
+ */
+static int is_dock(acpi_handle handle)
+{
+ acpi_status status;
+ acpi_handle tmp;
+
+ status = acpi_get_handle(handle, "_DCK", &tmp);
+ if (ACPI_FAILURE(status))
+ return 0;
+ return 1;
+}
+
+/**
+ * is_dock_device - see if a device is on a dock station
+ * @handle: acpi handle of the device
+ *
+ * If this device is either the dock station itself,
+ * or is a device dependent on the dock station, then it
+ * is a dock device
+ */
+int is_dock_device(acpi_handle handle)
+{
+ if (!dock_station)
+ return 0;
+
+ if (is_dock(handle) || find_dock_dependent_device(dock_station, handle))
+ return 1;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(is_dock_device);
+
+/**
+ * dock_present - see if the dock station is present.
+ * @ds: the dock station
+ *
+ * execute the _STA method. note that present does not
+ * imply that we are docked.
+ */
+static int dock_present(struct dock_station *ds)
+{
+ unsigned long sta;
+ acpi_status status;
+
+ if (ds) {
+ status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta)
+ return 1;
+ }
+ return 0;
+}
+
+
+
+/**
+ * dock_create_acpi_device - add new devices to acpi
+ * @handle - handle of the device to add
+ *
+ * This function will create a new acpi_device for the given
+ * handle if one does not exist already. This should cause
+ * acpi to scan for drivers for the given devices, and call
+ * matching driver's add routine.
+ *
+ * Returns a pointer to the acpi_device corresponding to the handle.
+ */
+static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
+{
+ struct acpi_device *device = NULL;
+ struct acpi_device *parent_device;
+ acpi_handle parent;
+ int ret;
+
+ if (acpi_bus_get_device(handle, &device)) {
+ /*
+ * no device created for this object,
+ * so we should create one.
+ */
+ acpi_get_parent(handle, &parent);
+ if (acpi_bus_get_device(parent, &parent_device))
+ parent_device = NULL;
+
+ ret = acpi_bus_add(&device, parent_device, handle,
+ ACPI_BUS_TYPE_DEVICE);
+ if (ret) {
+ pr_debug("error adding bus, %x\n",
+ -ret);
+ return NULL;
+ }
+ }
+ return device;
+}
+
+/**
+ * dock_remove_acpi_device - remove the acpi_device struct from acpi
+ * @handle - the handle of the device to remove
+ *
+ * Tell acpi to remove the acpi_device. This should cause any loaded
+ * driver to have it's remove routine called.
+ */
+static void dock_remove_acpi_device(acpi_handle handle)
+{
+ struct acpi_device *device;
+ int ret;
+
+ if (!acpi_bus_get_device(handle, &device)) {
+ ret = acpi_bus_trim(device, 1);
+ if (ret)
+ pr_debug("error removing bus, %x\n", -ret);
+ }
+}
+
+
+/**
+ * hotplug_dock_devices - insert or remove devices on the dock station
+ * @ds: the dock station
+ * @event: either bus check or eject request
+ *
+ * Some devices on the dock station need to have drivers called
+ * to perform hotplug operations after a dock event has occurred.
+ * Traverse the list of dock devices that have registered a
+ * hotplug handler, and call the handler.
+ */
+static void hotplug_dock_devices(struct dock_station *ds, u32 event)
+{
+ struct dock_dependent_device *dd;
+
+ spin_lock(&ds->hp_lock);
+
+ /*
+ * First call driver specific hotplug functions
+ */
+ list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
+ if (dd->handler)
+ dd->handler(dd->handle, event, dd->context);
+ }
+
+ /*
+ * Now make sure that an acpi_device is created for each
+ * dependent device, or removed if this is an eject request.
+ * This will cause acpi_drivers to be stopped/started if they
+ * exist
+ */
+ list_for_each_entry(dd, &ds->dependent_devices, list) {
+ if (event == ACPI_NOTIFY_EJECT_REQUEST)
+ dock_remove_acpi_device(dd->handle);
+ else
+ dock_create_acpi_device(dd->handle);
+ }
+ spin_unlock(&ds->hp_lock);
+}
+
+static void dock_event(struct dock_station *ds, u32 event, int num)
+{
+ /*
+ * we don't do events until someone tells me that
+ * they would like to have them.
+ */
+}
+
+/**
+ * eject_dock - respond to a dock eject request
+ * @ds: the dock station
+ *
+ * This is called after _DCK is called, to execute the dock station's
+ * _EJ0 method.
+ */
+static void eject_dock(struct dock_station *ds)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status;
+ acpi_handle tmp;
+
+ /* all dock devices should have _EJ0, but check anyway */
+ status = acpi_get_handle(ds->handle, "_EJ0", &tmp);
+ if (ACPI_FAILURE(status)) {
+ pr_debug("No _EJ0 support for dock device\n");
+ return;
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
+ &arg_list, NULL)))
+ pr_debug("Failed to evaluate _EJ0!\n");
+}
+
+/**
+ * handle_dock - handle a dock event
+ * @ds: the dock station
+ * @dock: to dock, or undock - that is the question
+ *
+ * Execute the _DCK method in response to an acpi event
+ */
+static void handle_dock(struct dock_station *ds, int dock)
+{
+ acpi_status status;
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+
+ acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
+ obj = name_buffer.pointer;
+
+ printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
+
+ /* _DCK method has one argument */
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = dock;
+ status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
+ if (ACPI_FAILURE(status))
+ pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
+ kfree(buffer.pointer);
+ kfree(name_buffer.pointer);
+}
+
+static inline void dock(struct dock_station *ds)
+{
+ handle_dock(ds, 1);
+}
+
+static inline void undock(struct dock_station *ds)
+{
+ handle_dock(ds, 0);
+}
+
+static inline void begin_dock(struct dock_station *ds)
+{
+ ds->flags |= DOCK_DOCKING;
+}
+
+static inline void complete_dock(struct dock_station *ds)
+{
+ ds->flags &= ~(DOCK_DOCKING);
+ ds->last_dock_time = jiffies;
+}
+
+/**
+ * dock_in_progress - see if we are in the middle of handling a dock event
+ * @ds: the dock station
+ *
+ * Sometimes while docking, false dock events can be sent to the driver
+ * because good connections aren't made or some other reason. Ignore these
+ * if we are in the middle of doing something.
+ */
+static int dock_in_progress(struct dock_station *ds)
+{
+ if ((ds->flags & DOCK_DOCKING) ||
+ time_before(jiffies, (ds->last_dock_time + HZ)))
+ return 1;
+ return 0;
+}
+
+/**
+ * register_dock_notifier - add yourself to the dock notifier list
+ * @nb: the callers notifier block
+ *
+ * If a driver wishes to be notified about dock events, they can
+ * use this function to put a notifier block on the dock notifier list.
+ * this notifier call chain will be called after a dock event, but
+ * before hotplugging any new devices.
+ */
+int register_dock_notifier(struct notifier_block *nb)
+{
+ return atomic_notifier_chain_register(&dock_notifier_list, nb);
+}
+
+EXPORT_SYMBOL_GPL(register_dock_notifier);
+
+/**
+ * unregister_dock_notifier - remove yourself from the dock notifier list
+ * @nb: the callers notifier block
+ */
+void unregister_dock_notifier(struct notifier_block *nb)
+{
+ atomic_notifier_chain_unregister(&dock_notifier_list, nb);
+}
+
+EXPORT_SYMBOL_GPL(unregister_dock_notifier);
+
+/**
+ * register_hotplug_dock_device - register a hotplug function
+ * @handle: the handle of the device
+ * @handler: the acpi_notifier_handler to call after docking
+ * @context: device specific data
+ *
+ * If a driver would like to perform a hotplug operation after a dock
+ * event, they can register an acpi_notifiy_handler to be called by
+ * the dock driver after _DCK is executed.
+ */
+int
+register_hotplug_dock_device(acpi_handle handle, acpi_notify_handler handler,
+ void *context)
+{
+ struct dock_dependent_device *dd;
+
+ if (!dock_station)
+ return -ENODEV;
+
+ /*
+ * make sure this handle is for a device dependent on the dock,
+ * this would include the dock station itself
+ */
+ dd = find_dock_dependent_device(dock_station, handle);
+ if (dd) {
+ dd->handler = handler;
+ dd->context = context;
+ dock_add_hotplug_device(dock_station, dd);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
+
+/**
+ * unregister_hotplug_dock_device - remove yourself from the hotplug list
+ * @handle: the acpi handle of the device
+ */
+void unregister_hotplug_dock_device(acpi_handle handle)
+{
+ struct dock_dependent_device *dd;
+
+ if (!dock_station)
+ return;
+
+ dd = find_dock_dependent_device(dock_station, handle);
+ if (dd)
+ dock_del_hotplug_device(dock_station, dd);
+}
+
+EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
+
+/**
+ * dock_notify - act upon an acpi dock notification
+ * @handle: the dock station handle
+ * @event: the acpi event
+ * @data: our driver data struct
+ *
+ * If we are notified to dock, then check to see if the dock is
+ * present and then dock. Notify all drivers of the dock event,
+ * and then hotplug and devices that may need hotplugging. For undock
+ * check to make sure the dock device is still present, then undock
+ * and hotremove all the devices that may need removing.
+ */
+static void dock_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct dock_station *ds = (struct dock_station *)data;
+
+ switch (event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ if (!dock_in_progress(ds) && dock_present(ds)) {
+ begin_dock(ds);
+ dock(ds);
+ if (!dock_present(ds)) {
+ printk(KERN_ERR PREFIX "Unable to dock!\n");
+ break;
+ }
+ atomic_notifier_call_chain(&dock_notifier_list,
+ event, NULL);
+ hotplug_dock_devices(ds, event);
+ complete_dock(ds);
+ dock_event(ds, event, DOCK_EVENT);
+ }
+ break;
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ /*
+ * According to acpi spec 3.0a, if a DEVICE_CHECK notification
+ * is sent and _DCK is present, it is assumed to mean an
+ * undock request. This notify routine will only be called
+ * for objects defining _DCK, so we will fall through to eject
+ * request here. However, we will pass an eject request through
+ * to the driver who wish to hotplug.
+ */
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ if (!dock_in_progress(ds) && dock_present(ds)) {
+ /*
+ * here we need to generate the undock
+ * event prior to actually doing the undock
+ * so that the device struct still exists.
+ */
+ dock_event(ds, event, UNDOCK_EVENT);
+ hotplug_dock_devices(ds, ACPI_NOTIFY_EJECT_REQUEST);
+ undock(ds);
+ eject_dock(ds);
+ if (dock_present(ds))
+ printk(KERN_ERR PREFIX "Unable to undock!\n");
+ }
+ break;
+ default:
+ printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
+ }
+}
+
+/**
+ * find_dock_devices - find devices on the dock station
+ * @handle: the handle of the device we are examining
+ * @lvl: unused
+ * @context: the dock station private data
+ * @rv: unused
+ *
+ * This function is called by acpi_walk_namespace. It will
+ * check to see if an object has an _EJD method. If it does, then it
+ * will see if it is dependent on the dock station.
+ */
+static acpi_status
+find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ acpi_status status;
+ acpi_handle tmp;
+ struct dock_station *ds = (struct dock_station *)context;
+ struct dock_dependent_device *dd;
+
+ status = acpi_bus_get_ejd(handle, &tmp);
+ if (ACPI_FAILURE(status))
+ return AE_OK;
+
+ if (tmp == ds->handle) {
+ dd = alloc_dock_dependent_device(handle);
+ if (dd)
+ add_dock_dependent_device(ds, dd);
+ }
+
+ return AE_OK;
+}
+
+/**
+ * dock_add - add a new dock station
+ * @handle: the dock station handle
+ *
+ * allocated and initialize a new dock station device. Find all devices
+ * that are on the dock station, and register for dock event notifications.
+ */
+static int dock_add(acpi_handle handle)
+{
+ int ret;
+ acpi_status status;
+ struct dock_dependent_device *dd;
+
+ /* allocate & initialize the dock_station private data */
+ dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
+ if (!dock_station)
+ return -ENOMEM;
+ dock_station->handle = handle;
+ dock_station->last_dock_time = jiffies - HZ;
+ INIT_LIST_HEAD(&dock_station->dependent_devices);
+ INIT_LIST_HEAD(&dock_station->hotplug_devices);
+ spin_lock_init(&dock_station->dd_lock);
+ spin_lock_init(&dock_station->hp_lock);
+ ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
+
+ /* Find dependent devices */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_dock_devices, dock_station,
+ NULL);
+
+ /* add the dock station as a device dependent on itself */
+ dd = alloc_dock_dependent_device(handle);
+ if (!dd) {
+ kfree(dock_station);
+ return -ENOMEM;
+ }
+ add_dock_dependent_device(dock_station, dd);
+
+ /* register for dock events */
+ status = acpi_install_notify_handler(dock_station->handle,
+ ACPI_SYSTEM_NOTIFY,
+ dock_notify, dock_station);
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Error installing notify handler\n");
+ ret = -ENODEV;
+ goto dock_add_err;
+ }
+
+ printk(KERN_INFO PREFIX "%s \n", ACPI_DOCK_DRIVER_NAME);
+
+ return 0;
+
+dock_add_err:
+ kfree(dock_station);
+ kfree(dd);
+ return ret;
+}
+
+/**
+ * dock_remove - free up resources related to the dock station
+ */
+static int dock_remove(void)
+{
+ struct dock_dependent_device *dd, *tmp;
+ acpi_status status;
+
+ if (!dock_station)
+ return 0;
+
+ /* remove dependent devices */
+ list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,
+ list)
+ kfree(dd);
+
+ /* remove dock notify handler */
+ status = acpi_remove_notify_handler(dock_station->handle,
+ ACPI_SYSTEM_NOTIFY,
+ dock_notify);
+ if (ACPI_FAILURE(status))
+ printk(KERN_ERR "Error removing notify handler\n");
+
+ /* free dock station memory */
+ kfree(dock_station);
+ return 0;
+}
+
+/**
+ * find_dock - look for a dock station
+ * @handle: acpi handle of a device
+ * @lvl: unused
+ * @context: counter of dock stations found
+ * @rv: unused
+ *
+ * This is called by acpi_walk_namespace to look for dock stations.
+ */
+static acpi_status
+find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+ acpi_status status = AE_OK;
+
+ if (is_dock(handle)) {
+ if (dock_add(handle) >= 0) {
+ (*count)++;
+ status = AE_CTRL_TERMINATE;
+ }
+ }
+ return status;
+}
+
+static int __init dock_init(void)
+{
+ int num = 0;
+
+ dock_station = NULL;
+
+ /* look for a dock station */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_dock, &num, NULL);
+
+ if (!num)
+ return -ENODEV;
+
+ return 0;
+}
+
+static void __exit dock_exit(void)
+{
+ dock_remove();
+}
+
+postcore_initcall(dock_init);
+module_exit(dock_exit);
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 18b3ea9dace..e5d79636285 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -207,16 +207,15 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_wait");
ec->intr.expect_event = event;
smp_mb();
switch (event) {
case ACPI_EC_EVENT_IBE:
- if (~acpi_ec_read_status(ec) & event) {
+ if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) {
ec->intr.expect_event = 0;
- return_VALUE(0);
+ return 0;
}
break;
default:
@@ -238,16 +237,16 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
switch (event) {
case ACPI_EC_EVENT_OBF:
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
- return_VALUE(0);
+ return 0;
break;
case ACPI_EC_EVENT_IBE:
if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
- return_VALUE(0);
+ return 0;
break;
}
- return_VALUE(-ETIME);
+ return -ETIME;
}
#ifdef ACPI_FUTURE_USAGE
@@ -260,7 +259,6 @@ int acpi_ec_enter_burst_mode(union acpi_ec *ec)
u32 tmp = 0;
int status = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_enter_burst_mode");
status = acpi_ec_read_status(ec);
if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
@@ -272,22 +270,21 @@ int acpi_ec_enter_burst_mode(union acpi_ec *ec)
status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
if (tmp != 0x90) { /* Burst ACK byte */
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
}
atomic_set(&ec->intr.leaving_burst, 0);
- return_VALUE(0);
+ return 0;
end:
- printk(KERN_WARNING PREFIX "Error in acpi_ec_wait\n");
- return_VALUE(-1);
+ ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
+ return -1;
}
int acpi_ec_leave_burst_mode(union acpi_ec *ec)
{
int status = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode");
status = acpi_ec_read_status(ec);
if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
@@ -298,10 +295,10 @@ int acpi_ec_leave_burst_mode(union acpi_ec *ec)
acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
}
atomic_set(&ec->intr.leaving_burst, 1);
- return_VALUE(0);
+ return 0;
end:
- printk(KERN_WARNING PREFIX "leave burst_mode:error\n");
- return_VALUE(-1);
+ ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
+ return -1;
}
#endif /* ACPI_FUTURE_USAGE */
@@ -325,17 +322,16 @@ static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
int result = 0;
u32 glk = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_read");
if (!ec || !data)
- return_VALUE(-EINVAL);
+ return -EINVAL;
*data = 0;
if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (down_interruptible(&ec->poll.sem)) {
@@ -365,7 +361,7 @@ end_nosem:
if (ec->common.global_lock)
acpi_release_global_lock(glk);
- return_VALUE(result);
+ return result;
}
static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
@@ -374,15 +370,14 @@ static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
acpi_status status = AE_OK;
u32 glk = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_write");
if (!ec)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (down_interruptible(&ec->poll.sem)) {
@@ -415,7 +410,7 @@ end_nosem:
if (ec->common.global_lock)
acpi_release_global_lock(glk);
- return_VALUE(result);
+ return result;
}
static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
@@ -423,17 +418,16 @@ static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
int status = 0;
u32 glk;
- ACPI_FUNCTION_TRACE("acpi_ec_read");
if (!ec || !data)
- return_VALUE(-EINVAL);
+ return -EINVAL;
*data = 0;
if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
WARN_ON(in_interrupt());
@@ -467,7 +461,7 @@ static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
if (ec->common.global_lock)
acpi_release_global_lock(glk);
- return_VALUE(status);
+ return status;
}
static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
@@ -475,15 +469,14 @@ static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
int status = 0;
u32 glk;
- ACPI_FUNCTION_TRACE("acpi_ec_write");
if (!ec)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
WARN_ON(in_interrupt());
@@ -516,7 +509,7 @@ static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
if (ec->common.global_lock)
acpi_release_global_lock(glk);
- return_VALUE(status);
+ return status;
}
/*
@@ -574,17 +567,16 @@ static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
acpi_status status = AE_OK;
u32 glk = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_query");
if (!ec || !data)
- return_VALUE(-EINVAL);
+ return -EINVAL;
*data = 0;
if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
/*
@@ -613,23 +605,22 @@ end_nosem:
if (ec->common.global_lock)
acpi_release_global_lock(glk);
- return_VALUE(result);
+ return result;
}
static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
{
int status = 0;
u32 glk;
- ACPI_FUNCTION_TRACE("acpi_ec_query");
if (!ec || !data)
- return_VALUE(-EINVAL);
+ return -EINVAL;
*data = 0;
if (ec->common.global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
down(&ec->intr.sem);
@@ -662,7 +653,7 @@ static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
if (ec->common.global_lock)
acpi_release_global_lock(glk);
- return_VALUE(status);
+ return status;
}
/* --------------------------------------------------------------------------
@@ -691,13 +682,12 @@ static void acpi_ec_gpe_poll_query(void *ec_cxt)
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
- ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
if (!ec_cxt)
goto end;
if (down_interruptible (&ec->poll.sem)) {
- return_VOID;
+ return;
}
acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
up(&ec->poll.sem);
@@ -734,7 +724,6 @@ static void acpi_ec_gpe_intr_query(void *ec_cxt)
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
- ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
result = acpi_ec_query(ec, &value);
@@ -793,12 +782,15 @@ static u32 acpi_ec_gpe_intr_handler(void *data)
case ACPI_EC_EVENT_OBF:
if (!(value & ACPI_EC_FLAG_OBF))
break;
+ ec->intr.expect_event = 0;
+ wake_up(&ec->intr.wait);
+ break;
case ACPI_EC_EVENT_IBE:
if ((value & ACPI_EC_FLAG_IBF))
break;
ec->intr.expect_event = 0;
wake_up(&ec->intr.wait);
- return ACPI_INTERRUPT_HANDLED;
+ break;
default:
break;
}
@@ -846,15 +838,14 @@ acpi_ec_space_handler(u32 function,
acpi_integer f_v = 0;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_space_handler");
if ((address > 0xFF) || !value || !handler_context)
- return_VALUE(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
if (bit_width != 8 && acpi_strict) {
printk(KERN_WARNING PREFIX
"acpi_ec_space_handler: bit_width should be 8\n");
- return_VALUE(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
}
ec = (union acpi_ec *)handler_context;
@@ -893,16 +884,16 @@ acpi_ec_space_handler(u32 function,
out:
switch (result) {
case -EINVAL:
- return_VALUE(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
break;
case -ENODEV:
- return_VALUE(AE_NOT_FOUND);
+ return AE_NOT_FOUND;
break;
case -ETIME:
- return_VALUE(AE_TIME);
+ return AE_TIME;
break;
default:
- return_VALUE(AE_OK);
+ return AE_OK;
}
}
@@ -916,7 +907,6 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
union acpi_ec *ec = (union acpi_ec *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_ec_read_info");
if (!ec)
goto end;
@@ -931,7 +921,7 @@ static int acpi_ec_read_info(struct seq_file *seq, void *offset)
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
@@ -939,7 +929,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_ec_read_info, PDE(inode)->data);
}
-static struct file_operations acpi_ec_info_ops = {
+static const struct file_operations acpi_ec_info_ops = {
.open = acpi_ec_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -951,33 +941,29 @@ static int acpi_ec_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_ec_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Unable to create '%s' fs entry\n",
- ACPI_EC_FILE_INFO));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_ec_info_ops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_ec_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_ec_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
@@ -985,7 +971,7 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -998,14 +984,13 @@ static int acpi_ec_poll_add(struct acpi_device *device)
acpi_status status = AE_OK;
union acpi_ec *ec = NULL;
- ACPI_FUNCTION_TRACE("acpi_ec_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
if (!ec)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(ec, 0, sizeof(union acpi_ec));
ec->common.handle = device->handle;
@@ -1038,8 +1023,7 @@ static int acpi_ec_poll_add(struct acpi_device *device)
acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
&ec->common.gpe_bit);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error obtaining GPE bit assignment\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
result = -ENODEV;
goto end;
}
@@ -1059,7 +1043,7 @@ static int acpi_ec_poll_add(struct acpi_device *device)
if (result)
kfree(ec);
- return_VALUE(result);
+ return result;
}
static int acpi_ec_intr_add(struct acpi_device *device)
{
@@ -1067,14 +1051,13 @@ static int acpi_ec_intr_add(struct acpi_device *device)
acpi_status status = AE_OK;
union acpi_ec *ec = NULL;
- ACPI_FUNCTION_TRACE("acpi_ec_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
if (!ec)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(ec, 0, sizeof(union acpi_ec));
ec->common.handle = device->handle;
@@ -1110,8 +1093,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
&ec->common.gpe_bit);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error obtaining GPE bit assignment\n"));
+ printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n");
result = -ENODEV;
goto end;
}
@@ -1131,17 +1113,16 @@ static int acpi_ec_intr_add(struct acpi_device *device)
if (result)
kfree(ec);
- return_VALUE(result);
+ return result;
}
static int acpi_ec_remove(struct acpi_device *device, int type)
{
union acpi_ec *ec = NULL;
- ACPI_FUNCTION_TRACE("acpi_ec_remove");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
ec = acpi_driver_data(device);
@@ -1149,7 +1130,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
kfree(ec);
- return_VALUE(0);
+ return 0;
}
static acpi_status
@@ -1188,15 +1169,14 @@ static int acpi_ec_start(struct acpi_device *device)
acpi_status status = AE_OK;
union acpi_ec *ec = NULL;
- ACPI_FUNCTION_TRACE("acpi_ec_start");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
ec = acpi_driver_data(device);
if (!ec)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* Get I/O port addresses. Convert to GAS format.
@@ -1205,9 +1185,8 @@ static int acpi_ec_start(struct acpi_device *device)
acpi_ec_io_ports, ec);
if (ACPI_FAILURE(status)
|| ec->common.command_addr.register_bit_width == 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error getting I/O port addresses"));
- return_VALUE(-ENODEV);
+ printk(KERN_ERR PREFIX "Error getting I/O port addresses\n");
+ return -ENODEV;
}
ec->common.status_addr = ec->common.command_addr;
@@ -1224,7 +1203,7 @@ static int acpi_ec_start(struct acpi_device *device)
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
@@ -1236,10 +1215,10 @@ static int acpi_ec_start(struct acpi_device *device)
if (ACPI_FAILURE(status)) {
acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
&acpi_ec_gpe_handler);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(AE_OK);
+ return AE_OK;
}
static int acpi_ec_stop(struct acpi_device *device, int type)
@@ -1247,10 +1226,9 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
acpi_status status = AE_OK;
union acpi_ec *ec = NULL;
- ACPI_FUNCTION_TRACE("acpi_ec_stop");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
ec = acpi_driver_data(device);
@@ -1258,15 +1236,15 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
status =
acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
&acpi_ec_gpe_handler);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
- return_VALUE(0);
+ return 0;
}
static acpi_status __init
@@ -1536,23 +1514,22 @@ static int __init acpi_ec_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_ec_init");
if (acpi_disabled)
- return_VALUE(0);
+ return 0;
acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
if (!acpi_ec_dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
/* Now register the driver for the EC */
result = acpi_bus_register_driver(&acpi_ec_driver);
if (result < 0) {
remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(result);
+ return result;
}
subsys_initcall(acpi_ec_init);
@@ -1561,13 +1538,12 @@ subsys_initcall(acpi_ec_init);
#if 0
static void __exit acpi_ec_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_ec_exit");
acpi_bus_unregister_driver(&acpi_ec_driver);
remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
#endif /* 0 */
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 2dbb1b0f11d..959a893c8d1 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -48,18 +48,17 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
static int chars_remaining = 0;
static char *ptr;
- ACPI_FUNCTION_TRACE("acpi_system_read_event");
if (!chars_remaining) {
memset(&event, 0, sizeof(struct acpi_bus_event));
if ((file->f_flags & O_NONBLOCK)
&& (list_empty(&acpi_bus_event_list)))
- return_VALUE(-EAGAIN);
+ return -EAGAIN;
result = acpi_bus_receive_event(&event);
if (result)
- return_VALUE(result);
+ return result;
chars_remaining = sprintf(str, "%s %s %08x %08x\n",
event.device_class ? event.
@@ -75,13 +74,13 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
}
if (copy_to_user(buffer, ptr, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
*ppos += count;
chars_remaining -= count;
ptr += count;
- return_VALUE(count);
+ return count;
}
static int acpi_system_close_event(struct inode *inode, struct file *file)
@@ -100,7 +99,7 @@ static unsigned int acpi_system_poll_event(struct file *file, poll_table * wait)
return 0;
}
-static struct file_operations acpi_system_event_ops = {
+static const struct file_operations acpi_system_event_ops = {
.open = acpi_system_open_event,
.read = acpi_system_read_event,
.release = acpi_system_close_event,
@@ -112,22 +111,18 @@ static int __init acpi_event_init(void)
struct proc_dir_entry *entry;
int error = 0;
- ACPI_FUNCTION_TRACE("acpi_event_init");
if (acpi_disabled)
- return_VALUE(0);
+ return 0;
/* 'event' [R] */
entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
if (entry)
entry->proc_fops = &acpi_system_event_ops;
else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' proc fs entry\n",
- "event"));
- error = -EFAULT;
+ error = -ENODEV;
}
- return_VALUE(error);
+ return error;
}
subsys_initcall(acpi_event_init);
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index f01d339407f..c76c0583ca6 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -382,7 +382,6 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
u32 status_reg;
u32 enable_reg;
acpi_cpu_flags flags;
- acpi_cpu_flags hw_flags;
acpi_native_uint i;
acpi_native_uint j;
@@ -394,8 +393,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
return (int_status);
}
- /* We need to hold the GPE lock now, hardware lock in the loop */
-
+ /*
+ * We need to obtain the GPE lock for both the data structs and registers
+ * Note: Not necessary to obtain the hardware lock, since the GPE registers
+ * are owned by the gpe_lock.
+ */
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
/* Examine all GPE blocks attached to this interrupt level */
@@ -413,8 +415,6 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
gpe_register_info = &gpe_block->register_info[i];
- hw_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
-
/* Read the Status Register */
status =
@@ -423,8 +423,6 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
&gpe_register_info->
status_address);
if (ACPI_FAILURE(status)) {
- acpi_os_release_lock(acpi_gbl_hardware_lock,
- hw_flags);
goto unlock_and_exit;
}
@@ -435,8 +433,6 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
&enable_reg,
&gpe_register_info->
enable_address);
- acpi_os_release_lock(acpi_gbl_hardware_lock, hw_flags);
-
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 094a17e4c86..21caae04fe8 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -528,34 +528,40 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj,
}
}
- /* Call the setup handler with the deactivate notification */
+ /*
+ * If the region has been activated, call the setup handler
+ * with the deactivate notification
+ */
+ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
+ region_setup = handler_obj->address_space.setup;
+ status =
+ region_setup(region_obj,
+ ACPI_REGION_DEACTIVATE,
+ handler_obj->address_space.
+ context, region_context);
- region_setup = handler_obj->address_space.setup;
- status =
- region_setup(region_obj, ACPI_REGION_DEACTIVATE,
- handler_obj->address_space.context,
- region_context);
+ /* Init routine may fail, Just ignore errors */
- /* Init routine may fail, Just ignore errors */
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "from region handler - deactivate, [%s]",
+ acpi_ut_get_region_name
+ (region_obj->region.
+ space_id)));
+ }
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "from region init, [%s]",
- acpi_ut_get_region_name
- (region_obj->region.space_id)));
+ region_obj->region.flags &=
+ ~(AOPOBJ_SETUP_COMPLETE);
}
- region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE);
-
/*
* Remove handler reference in the region
*
- * NOTE: this doesn't mean that the region goes away
- * The region is just inaccessible as indicated to
- * the _REG method
+ * NOTE: this doesn't mean that the region goes away, the region
+ * is just inaccessible as indicated to the _REG method
*
- * If the region is on the handler's list
- * this better be the region's handler
+ * If the region is on the handler's list, this must be the
+ * region's handler
*/
region_obj->region.handler = NULL;
acpi_ut_remove_reference(handler_obj);
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 76c34a66e0e..923fd2b4695 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -414,12 +414,13 @@ acpi_remove_notify_handler(acpi_handle device,
if ((!device) ||
(!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ status = AE_BAD_PARAMETER;
+ goto exit;
}
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
/* Convert and validate the device handle */
@@ -450,7 +451,7 @@ acpi_remove_notify_handler(acpi_handle device,
acpi_os_wait_events_complete(NULL);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
if (handler_type & ACPI_SYSTEM_NOTIFY) {
@@ -488,8 +489,12 @@ acpi_remove_notify_handler(acpi_handle device,
if (handler_type & ACPI_SYSTEM_NOTIFY) {
notify_obj = obj_desc->common_notify.system_notify;
- if ((!notify_obj) ||
- (notify_obj->notify.handler != handler)) {
+ if (!notify_obj) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ if (notify_obj->notify.handler != handler) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
@@ -499,7 +504,7 @@ acpi_remove_notify_handler(acpi_handle device,
acpi_os_wait_events_complete(NULL);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
/* Remove the handler */
@@ -509,8 +514,12 @@ acpi_remove_notify_handler(acpi_handle device,
if (handler_type & ACPI_DEVICE_NOTIFY) {
notify_obj = obj_desc->common_notify.device_notify;
- if ((!notify_obj) ||
- (notify_obj->notify.handler != handler)) {
+ if (!notify_obj) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ if (notify_obj->notify.handler != handler) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
@@ -520,7 +529,7 @@ acpi_remove_notify_handler(acpi_handle device,
acpi_os_wait_events_complete(NULL);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
/* Remove the handler */
@@ -531,6 +540,9 @@ acpi_remove_notify_handler(acpi_handle device,
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ exit:
+ if (ACPI_FAILURE(status))
+ ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
return_ACPI_STATUS(status);
}
@@ -568,12 +580,13 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
/* Parameter validation */
if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ status = AE_BAD_PARAMETER;
+ goto exit;
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
/* Ensure that we have a valid GPE number */
@@ -625,6 +638,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ exit:
+ if (ACPI_FAILURE(status))
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Installing notify handler failed"));
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index e8b86a0baad..83b12a9afa3 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -155,7 +155,11 @@ acpi_remove_address_space_handler(acpi_handle device,
/* Convert and validate the device handle */
node = acpi_ns_map_handle_to_node(device);
- if (!node) {
+ if (!node ||
+ ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_PROCESSOR) &&
+ (node->type != ACPI_TYPE_THERMAL) &&
+ (node != acpi_gbl_root_node))) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
@@ -178,6 +182,13 @@ acpi_remove_address_space_handler(acpi_handle device,
if (handler_obj->address_space.space_id == space_id) {
+ /* Handler must be the same as the installed handler */
+
+ if (handler_obj->address_space.handler != handler) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
/* Matched space_id, first dereference this in the Regions */
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 823352435e0..c8341fa5fe0 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -266,6 +266,10 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
}
}
+ ACPI_INFO((AE_INFO,
+ "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+ table->signature, table->oem_id, table->oem_table_id));
+
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
}
@@ -446,6 +450,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
+ ACPI_INFO((AE_INFO,
+ "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
+ table_ptr->oem_id, table_ptr->oem_table_id));
+
cleanup:
if (ACPI_FAILURE(status)) {
ACPI_FREE(table_ptr);
@@ -494,7 +502,6 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
* (Offset contains the table_id)
*/
acpi_ns_delete_namespace_by_owner(table_info->owner_id);
- acpi_ut_release_owner_id(&table_info->owner_id);
/* Delete the table itself */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index b732e399b1e..544e81a6a43 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -170,6 +170,9 @@ acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_NO_MEMORY);
}
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64(result)));
+
/* Save the Result */
return_desc->integer.value = result;
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 106dc7219df..34eec82c1b1 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -177,7 +177,7 @@ acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state)
* that the event is created in an unsignalled state
*/
status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0,
- &obj_desc->event.semaphore);
+ &obj_desc->event.os_semaphore);
if (ACPI_FAILURE(status)) {
goto cleanup;
}
@@ -226,12 +226,9 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state)
goto cleanup;
}
- /*
- * Create the actual OS semaphore.
- * One unit max to make it a mutex, with one initial unit to allow
- * the mutex to be acquired.
- */
- status = acpi_os_create_semaphore(1, 1, &obj_desc->mutex.semaphore);
+ /* Create the actual OS Mutex */
+
+ status = acpi_os_create_mutex(&obj_desc->mutex.os_mutex);
if (ACPI_FAILURE(status)) {
goto cleanup;
}
@@ -565,7 +562,7 @@ acpi_ex_create_method(u8 * aml_start,
obj_desc->method.aml_length = aml_length;
/*
- * Disassemble the method flags. Split off the Arg Count
+ * Disassemble the method flags. Split off the Arg Count
* for efficiency
*/
method_flags = (u8) operand[1]->integer.value;
@@ -576,21 +573,19 @@ acpi_ex_create_method(u8 * aml_start,
(u8) (method_flags & AML_METHOD_ARG_COUNT);
/*
- * Get the concurrency count. If required, a semaphore will be
+ * Get the sync_level. If method is serialized, a mutex will be
* created for this method when it is parsed.
*/
if (acpi_gbl_all_methods_serialized) {
- obj_desc->method.concurrency = 1;
+ obj_desc->method.sync_level = 0;
obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
} else if (method_flags & AML_METHOD_SERIALIZED) {
/*
- * ACPI 1.0: Concurrency = 1
- * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1)
+ * ACPI 1.0: sync_level = 0
+ * ACPI 2.0: sync_level = sync_level in method declaration
*/
- obj_desc->method.concurrency = (u8)
- (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1);
- } else {
- obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY;
+ obj_desc->method.sync_level = (u8)
+ ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4);
}
/* Attach the new object to the method Node */
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 7b9718e976b..2450943add3 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -118,14 +118,14 @@ static struct acpi_exdump_info acpi_ex_dump_device[4] = {
static struct acpi_exdump_info acpi_ex_dump_event[2] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_event), NULL},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.semaphore), "Semaphore"}
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"}
};
static struct acpi_exdump_info acpi_ex_dump_method[8] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"},
- {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.concurrency), "Concurrency"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.semaphore), "Semaphore"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"},
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.thread_count), "Thread Count"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(method.aml_length), "Aml Length"},
@@ -138,7 +138,7 @@ static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"},
- {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.semaphore), "Semaphore"}
+ {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.os_mutex), "OsMutex"}
};
static struct acpi_exdump_info acpi_ex_dump_region[7] = {
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 051053f7ccc..40f0bee6faa 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -727,11 +727,23 @@ acpi_ex_extract_from_field(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- /* Merge with previous datum if necessary */
-
- merged_datum |= raw_datum <<
- (obj_desc->common_field.access_bit_width -
- obj_desc->common_field.start_field_bit_offset);
+ /*
+ * Merge with previous datum if necessary.
+ *
+ * Note: Before the shift, check if the shift value will be larger than
+ * the integer size. If so, there is no need to perform the operation.
+ * This avoids the differences in behavior between different compilers
+ * concerning shift values larger than the target data width.
+ */
+ if ((obj_desc->common_field.access_bit_width -
+ obj_desc->common_field.start_field_bit_offset) <
+ ACPI_INTEGER_BIT_SIZE) {
+ merged_datum |=
+ raw_datum << (obj_desc->common_field.
+ access_bit_width -
+ obj_desc->common_field.
+ start_field_bit_offset);
+ }
if (i == datum_count) {
break;
@@ -808,13 +820,23 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
}
- /* Compute the number of datums (access width data items) */
+ /*
+ * Create the bitmasks used for bit insertion.
+ * Note: This if/else is used to bypass compiler differences with the
+ * shift operator
+ */
+ if (obj_desc->common_field.access_bit_width == ACPI_INTEGER_BIT_SIZE) {
+ width_mask = ACPI_INTEGER_MAX;
+ } else {
+ width_mask =
+ ACPI_MASK_BITS_ABOVE(obj_desc->common_field.
+ access_bit_width);
+ }
- width_mask =
- ACPI_MASK_BITS_ABOVE(obj_desc->common_field.access_bit_width);
- mask =
- width_mask & ACPI_MASK_BITS_BELOW(obj_desc->common_field.
- start_field_bit_offset);
+ mask = width_mask &
+ ACPI_MASK_BITS_BELOW(obj_desc->common_field.start_field_bit_offset);
+
+ /* Compute the number of datums (access width data items) */
datum_count = ACPI_ROUND_UP_TO(obj_desc->common_field.bit_length,
obj_desc->common_field.access_bit_width);
@@ -848,12 +870,29 @@ acpi_ex_insert_into_field(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- /* Start new output datum by merging with previous input datum */
-
field_offset += obj_desc->common_field.access_byte_width;
- merged_datum = raw_datum >>
- (obj_desc->common_field.access_bit_width -
- obj_desc->common_field.start_field_bit_offset);
+
+ /*
+ * Start new output datum by merging with previous input datum
+ * if necessary.
+ *
+ * Note: Before the shift, check if the shift value will be larger than
+ * the integer size. If so, there is no need to perform the operation.
+ * This avoids the differences in behavior between different compilers
+ * concerning shift values larger than the target data width.
+ */
+ if ((obj_desc->common_field.access_bit_width -
+ obj_desc->common_field.start_field_bit_offset) <
+ ACPI_INTEGER_BIT_SIZE) {
+ merged_datum =
+ raw_datum >> (obj_desc->common_field.
+ access_bit_width -
+ obj_desc->common_field.
+ start_field_bit_offset);
+ } else {
+ merged_datum = 0;
+ }
+
mask = width_mask;
if (i == datum_count) {
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 93098d68cad..3a39c2e8e10 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -161,12 +161,13 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
/*
* Current Sync must be less than or equal to the sync level of the
- * mutex. This mechanism provides some deadlock prevention
+ * mutex. This mechanism provides some deadlock prevention
*/
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
ACPI_ERROR((AE_INFO,
- "Cannot acquire Mutex [%4.4s], incorrect SyncLevel",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
+ "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%d)",
+ acpi_ut_get_node_name(obj_desc->mutex.node),
+ walk_state->thread->current_sync_level));
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
@@ -178,8 +179,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
if ((obj_desc->mutex.owner_thread->thread_id ==
walk_state->thread->thread_id) ||
- (obj_desc->mutex.semaphore ==
- acpi_gbl_global_lock_semaphore)) {
+ (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) {
/*
* The mutex is already owned by this thread,
* just increment the acquisition depth
@@ -264,12 +264,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
*/
if ((obj_desc->mutex.owner_thread->thread_id !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) {
+ && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
ACPI_ERROR((AE_INFO,
"Thread %X cannot release Mutex [%4.4s] acquired by thread %X",
- walk_state->thread->thread_id,
+ (u32) walk_state->thread->thread_id,
acpi_ut_get_node_name(obj_desc->mutex.node),
- obj_desc->mutex.owner_thread->thread_id));
+ (u32) obj_desc->mutex.owner_thread->thread_id));
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 52beee3674a..28aef3e69ec 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -60,17 +60,17 @@ ACPI_MODULE_NAME("exsystem")
*
* DESCRIPTION: Implements a semaphore wait with a check to see if the
* semaphore is available immediately. If it is not, the
- * interpreter is released.
+ * interpreter is released before waiting.
*
******************************************************************************/
-acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout)
+acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
{
acpi_status status;
acpi_status status2;
ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
- status = acpi_os_wait_semaphore(semaphore, 1, 0);
+ status = acpi_os_wait_semaphore(semaphore, 1, ACPI_DO_NOT_WAIT);
if (ACPI_SUCCESS(status)) {
return_ACPI_STATUS(status);
}
@@ -103,6 +103,59 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_handle semaphore, u16 timeout)
/*******************************************************************************
*
+ * FUNCTION: acpi_ex_system_wait_mutex
+ *
+ * PARAMETERS: Mutex - Mutex to wait on
+ * Timeout - Max time to wait
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implements a mutex wait with a check to see if the
+ * mutex is available immediately. If it is not, the
+ * interpreter is released before waiting.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
+{
+ acpi_status status;
+ acpi_status status2;
+
+ ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
+
+ status = acpi_os_acquire_mutex(mutex, ACPI_DO_NOT_WAIT);
+ if (ACPI_SUCCESS(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (status == AE_TIME) {
+
+ /* We must wait, so unlock the interpreter */
+
+ acpi_ex_exit_interpreter();
+
+ status = acpi_os_acquire_mutex(mutex, timeout);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "*** Thread awake after blocking, %s\n",
+ acpi_format_exception(status)));
+
+ /* Reacquire the interpreter */
+
+ status2 = acpi_ex_enter_interpreter();
+ if (ACPI_FAILURE(status2)) {
+
+ /* Report fatal error, could not acquire interpreter */
+
+ return_ACPI_STATUS(status2);
+ }
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ex_system_do_stall
*
* PARAMETERS: how_long - The amount of time to stall,
@@ -176,7 +229,7 @@ acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
*
* FUNCTION: acpi_ex_system_acquire_mutex
*
- * PARAMETERS: time_desc - The 'time to delay' object descriptor
+ * PARAMETERS: time_desc - Maximum time to wait for the mutex
* obj_desc - The object descriptor for this op
*
* RETURN: Status
@@ -201,14 +254,14 @@ acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
/* Support for the _GL_ Mutex object -- go get the global lock */
- if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
+ if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
status =
acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
return_ACPI_STATUS(status);
}
- status = acpi_ex_system_wait_semaphore(obj_desc->mutex.semaphore,
- (u16) time_desc->integer.value);
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ (u16) time_desc->integer.value);
return_ACPI_STATUS(status);
}
@@ -239,13 +292,13 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
/* Support for the _GL_ Mutex object -- release the global lock */
- if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
+ if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
status = acpi_ev_release_global_lock();
return_ACPI_STATUS(status);
}
- status = acpi_os_signal_semaphore(obj_desc->mutex.semaphore, 1);
- return_ACPI_STATUS(status);
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
@@ -268,7 +321,8 @@ acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
ACPI_FUNCTION_TRACE(ex_system_signal_event);
if (obj_desc) {
- status = acpi_os_signal_semaphore(obj_desc->event.semaphore, 1);
+ status =
+ acpi_os_signal_semaphore(obj_desc->event.os_semaphore, 1);
}
return_ACPI_STATUS(status);
@@ -299,7 +353,7 @@ acpi_ex_system_wait_event(union acpi_operand_object *time_desc,
if (obj_desc) {
status =
- acpi_ex_system_wait_semaphore(obj_desc->event.semaphore,
+ acpi_ex_system_wait_semaphore(obj_desc->event.os_semaphore,
(u16) time_desc->integer.
value);
}
@@ -322,7 +376,7 @@ acpi_ex_system_wait_event(union acpi_operand_object *time_desc,
acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc)
{
acpi_status status = AE_OK;
- void *temp_semaphore;
+ acpi_semaphore temp_semaphore;
ACPI_FUNCTION_ENTRY();
@@ -333,8 +387,8 @@ acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc)
status =
acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore);
if (ACPI_SUCCESS(status)) {
- (void)acpi_os_delete_semaphore(obj_desc->event.semaphore);
- obj_desc->event.semaphore = temp_semaphore;
+ (void)acpi_os_delete_semaphore(obj_desc->event.os_semaphore);
+ obj_desc->event.os_semaphore = temp_semaphore;
}
return (status);
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 1cd25784b7a..045c89477e5 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -64,7 +64,7 @@ static struct acpi_driver acpi_fan_driver = {
};
struct acpi_fan {
- acpi_handle handle;
+ struct acpi_device * device;
};
/* --------------------------------------------------------------------------
@@ -78,16 +78,15 @@ static int acpi_fan_read_state(struct seq_file *seq, void *offset)
struct acpi_fan *fan = seq->private;
int state = 0;
- ACPI_FUNCTION_TRACE("acpi_fan_read_state");
if (fan) {
- if (acpi_bus_get_power(fan->handle, &state))
+ if (acpi_bus_get_power(fan->device->handle, &state))
seq_printf(seq, "status: ERROR\n");
else
seq_printf(seq, "status: %s\n",
!state ? "on" : "off");
}
- return_VALUE(0);
+ return 0;
}
static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
@@ -104,25 +103,24 @@ acpi_fan_write_state(struct file *file, const char __user * buffer,
struct acpi_fan *fan = (struct acpi_fan *)m->private;
char state_string[12] = { '\0' };
- ACPI_FUNCTION_TRACE("acpi_fan_write_state");
if (!fan || (count > sizeof(state_string) - 1))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(state_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
state_string[count] = '\0';
- result = acpi_bus_set_power(fan->handle,
+ result = acpi_bus_set_power(fan->device->handle,
simple_strtoul(state_string, NULL, 0));
if (result)
- return_VALUE(result);
+ return result;
- return_VALUE(count);
+ return count;
}
-static struct file_operations acpi_fan_state_ops = {
+static const struct file_operations acpi_fan_state_ops = {
.open = acpi_fan_state_open_fs,
.read = seq_read,
.write = acpi_fan_write_state,
@@ -135,16 +133,15 @@ static int acpi_fan_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_fan_add_fs");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_fan_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_device_dir(device)->owner = THIS_MODULE;
}
@@ -153,21 +150,18 @@ static int acpi_fan_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_FAN_FILE_STATE));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_fan_state_ops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_fan_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_fan_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_FAN_FILE_STATE, acpi_device_dir(device));
@@ -175,7 +169,7 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -188,25 +182,23 @@ static int acpi_fan_add(struct acpi_device *device)
struct acpi_fan *fan = NULL;
int state = 0;
- ACPI_FUNCTION_TRACE("acpi_fan_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL);
if (!fan)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(fan, 0, sizeof(struct acpi_fan));
- fan->handle = device->handle;
+ fan->device = device;
strcpy(acpi_device_name(device), "Fan");
strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
acpi_driver_data(device) = fan;
- result = acpi_bus_get_power(fan->handle, &state);
+ result = acpi_bus_get_power(device->handle, &state);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error reading power state\n"));
+ printk(KERN_ERR PREFIX "Reading power state\n");
goto end;
}
@@ -226,17 +218,16 @@ static int acpi_fan_add(struct acpi_device *device)
if (result)
kfree(fan);
- return_VALUE(result);
+ return result;
}
static int acpi_fan_remove(struct acpi_device *device, int type)
{
struct acpi_fan *fan = NULL;
- ACPI_FUNCTION_TRACE("acpi_fan_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
fan = (struct acpi_fan *)acpi_driver_data(device);
@@ -244,7 +235,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
kfree(fan);
- return_VALUE(0);
+ return 0;
}
static int acpi_fan_suspend(struct acpi_device *device, int state)
@@ -283,31 +274,29 @@ static int __init acpi_fan_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_fan_init");
acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
if (!acpi_fan_dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_fan_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_fan_driver);
if (result < 0) {
remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_fan_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_fan_exit");
acpi_bus_unregister_driver(&acpi_fan_driver);
remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
module_init(acpi_fan_init);
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 8daef57b994..10f160dc75b 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -152,7 +152,7 @@ static int get_root_bridge_busnr(acpi_handle handle)
bbn = bus;
}
exit:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
return (int)bbn;
}
@@ -192,7 +192,7 @@ find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
find->handle = handle;
status = AE_OK;
exit:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
return status;
}
@@ -224,7 +224,7 @@ do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
info = buffer.pointer;
if (info->address == find->address)
find->handle = handle;
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
}
return AE_OK;
}
@@ -330,7 +330,7 @@ static int acpi_platform_notify(struct device *dev)
acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer);
DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer);
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
} else
DBG("Device %s -> No ACPI support\n", dev->bus_id);
#endif
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index ae142de1950..3143f36fcec 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -172,9 +172,9 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b)
}
/*
- * The package must have at least two elements. NOTE (March 2005): This
+ * The package must have at least two elements. NOTE (March 2005): This
* goes against the current ACPI spec which defines this object as a
- * package with one encoded DWORD element. However, existing practice
+ * package with one encoded DWORD element. However, existing practice
* by BIOS vendors seems to be to have 2 or more elements, at least
* one per sleep type (A/B).
*/
@@ -255,7 +255,7 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
* return_value - Value that was read from the register
* Flags - Lock the hardware or not
*
- * RETURN: Status and the value read from specified Register. Value
+ * RETURN: Status and the value read from specified Register. Value
* returned is normalized to bit0 (is shifted all the way right)
*
* DESCRIPTION: ACPI bit_register read function.
@@ -361,8 +361,8 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
case ACPI_REGISTER_PM1_STATUS:
/*
- * Status Registers are different from the rest. Clear by
- * writing 1, and writing 0 has no effect. So, the only relevant
+ * Status Registers are different from the rest. Clear by
+ * writing 1, and writing 0 has no effect. So, the only relevant
* information is the single bit we're interested in, all others should
* be written as 0 so they will be left unchanged.
*/
@@ -467,14 +467,13 @@ ACPI_EXPORT_SYMBOL(acpi_set_register)
*
* FUNCTION: acpi_hw_register_read
*
- * PARAMETERS: use_lock - Mutex hw access
- * register_id - register_iD + Offset
+ * PARAMETERS: use_lock - Lock hardware? True/False
+ * register_id - ACPI Register ID
* return_value - Where the register value is returned
*
* RETURN: Status and the value read.
*
- * DESCRIPTION: Acpi register read function. Registers are read at the
- * given offset.
+ * DESCRIPTION: Read from the specified ACPI register
*
******************************************************************************/
acpi_status
@@ -580,14 +579,26 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
*
* FUNCTION: acpi_hw_register_write
*
- * PARAMETERS: use_lock - Mutex hw access
- * register_id - register_iD + Offset
+ * PARAMETERS: use_lock - Lock hardware? True/False
+ * register_id - ACPI Register ID
* Value - The value to write
*
* RETURN: Status
*
- * DESCRIPTION: Acpi register Write function. Registers are written at the
- * given offset.
+ * DESCRIPTION: Write to the specified ACPI register
+ *
+ * NOTE: In accordance with the ACPI specification, this function automatically
+ * preserves the value of the following bits, meaning that these bits cannot be
+ * changed via this interface:
+ *
+ * PM1_CONTROL[0] = SCI_EN
+ * PM1_CONTROL[9]
+ * PM1_STATUS[11]
+ *
+ * ACPI References:
+ * 1) Hardware Ignored Bits: When software writes to a register with ignored
+ * bit fields, it preserves the ignored bit fields
+ * 2) SCI_EN: OSPM always preserves this bit position
*
******************************************************************************/
@@ -595,6 +606,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
{
acpi_status status;
acpi_cpu_flags lock_flags = 0;
+ u32 read_value;
ACPI_FUNCTION_TRACE(hw_register_write);
@@ -605,6 +617,22 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
switch (register_id) {
case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
+ /* Perform a read first to preserve certain bits (per ACPI spec) */
+
+ status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_STATUS,
+ &read_value);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Insert the bits to be preserved */
+
+ ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
+ read_value);
+
+ /* Now we can write the data */
+
status =
acpi_hw_low_level_write(16, value,
&acpi_gbl_FADT->xpm1a_evt_blk);
@@ -635,6 +663,25 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
+ /*
+ * Perform a read first to preserve certain bits (per ACPI spec)
+ *
+ * Note: This includes SCI_EN, we never want to change this bit
+ */
+ status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_CONTROL,
+ &read_value);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Insert the bits to be preserved */
+
+ ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
+ read_value);
+
+ /* Now we can write the data */
+
status =
acpi_hw_low_level_write(16, value,
&acpi_gbl_FADT->xpm1a_cnt_blk);
@@ -726,7 +773,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
return (AE_OK);
}
- /* Get a local copy of the address. Handles possible alignment issues */
+ /* Get a local copy of the address. Handles possible alignment issues */
ACPI_MOVE_64_TO_64(&address, &reg->address);
if (!address) {
@@ -798,7 +845,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
return (AE_OK);
}
- /* Get a local copy of the address. Handles possible alignment issues */
+ /* Get a local copy of the address. Handles possible alignment issues */
ACPI_MOVE_64_TO_64(&address, &reg->address);
if (!address) {
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
index c25b2b92edc..1ba2db67186 100644
--- a/drivers/acpi/hotkey.c
+++ b/drivers/acpi/hotkey.c
@@ -91,6 +91,14 @@ enum {
HK_EVENT_ENTERRING_S5,
};
+enum conf_entry_enum {
+ bus_handle = 0,
+ bus_method = 1,
+ action_handle = 2,
+ method = 3,
+ LAST_CONF_ENTRY
+};
+
/* procdir we use */
static struct proc_dir_entry *hotkey_proc_dir;
static struct proc_dir_entry *hotkey_config;
@@ -184,7 +192,7 @@ static union acpi_hotkey *get_hotkey_by_event(struct
*hotkey_list, int event);
/* event based config */
-static struct file_operations hotkey_config_fops = {
+static const struct file_operations hotkey_config_fops = {
.open = hotkey_open_config,
.read = seq_read,
.write = hotkey_write_config,
@@ -193,7 +201,7 @@ static struct file_operations hotkey_config_fops = {
};
/* polling based config */
-static struct file_operations hotkey_poll_config_fops = {
+static const struct file_operations hotkey_poll_config_fops = {
.open = hotkey_poll_open_config,
.read = seq_read,
.write = hotkey_write_config,
@@ -202,7 +210,7 @@ static struct file_operations hotkey_poll_config_fops = {
};
/* hotkey driver info */
-static struct file_operations hotkey_info_fops = {
+static const struct file_operations hotkey_info_fops = {
.open = hotkey_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -210,7 +218,7 @@ static struct file_operations hotkey_info_fops = {
};
/* action */
-static struct file_operations hotkey_action_fops = {
+static const struct file_operations hotkey_action_fops = {
.open = hotkey_action_open_fs,
.read = seq_read,
.write = hotkey_execute_aml_method,
@@ -219,7 +227,7 @@ static struct file_operations hotkey_action_fops = {
};
/* polling results */
-static struct file_operations hotkey_polling_fops = {
+static const struct file_operations hotkey_polling_fops = {
.open = hotkey_polling_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -231,11 +239,10 @@ struct list_head hotkey_entries; /* head of the list of hotkey_list */
static int hotkey_info_seq_show(struct seq_file *seq, void *offset)
{
- ACPI_FUNCTION_TRACE("hotkey_info_seq_show");
seq_printf(seq, "Hotkey generic driver ver: %s\n", HOTKEY_ACPI_VERSION);
- return_VALUE(0);
+ return 0;
}
static int hotkey_info_open_fs(struct inode *inode, struct file *file)
@@ -245,19 +252,15 @@ static int hotkey_info_open_fs(struct inode *inode, struct file *file)
static char *format_result(union acpi_object *object)
{
- char *buf = NULL;
-
- buf = (char *)kmalloc(RESULT_STR_LEN, GFP_KERNEL);
- if (buf)
- memset(buf, 0, RESULT_STR_LEN);
- else
- goto do_fail;
+ char *buf;
+ buf = kzalloc(RESULT_STR_LEN, GFP_KERNEL);
+ if (!buf)
+ return NULL;
/* Now, just support integer type */
if (object->type == ACPI_TYPE_INTEGER)
sprintf(buf, "%d\n", (u32) object->integer.value);
- do_fail:
- return (buf);
+ return buf;
}
static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
@@ -266,7 +269,6 @@ static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
(struct acpi_polling_hotkey *)seq->private;
char *buf;
- ACPI_FUNCTION_TRACE("hotkey_polling_seq_show");
if (poll_hotkey->poll_result) {
buf = format_result(poll_hotkey->poll_result);
@@ -274,7 +276,7 @@ static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "%s", buf);
kfree(buf);
}
- return_VALUE(0);
+ return 0;
}
static int hotkey_polling_open_fs(struct inode *inode, struct file *file)
@@ -293,7 +295,6 @@ static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
struct list_head *entries;
int val = -1;
- ACPI_FUNCTION_TRACE("hotkey_get_internal_event");
list_for_each(entries, list->entries) {
union acpi_hotkey *key =
@@ -305,7 +306,7 @@ static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
}
}
- return_VALUE(val);
+ return val;
}
static void
@@ -314,15 +315,14 @@ acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data)
struct acpi_device *device = NULL;
u32 internal_event;
- ACPI_FUNCTION_TRACE("acpi_hotkey_notify_handler");
if (acpi_bus_get_device(handle, &device))
- return_VOID;
+ return;
internal_event = hotkey_get_internal_event(event, &global_hotkey_list);
acpi_bus_generate_event(device, internal_event, 0);
- return_VOID;
+ return;
}
/* Need to invent automatically hotkey add method */
@@ -346,7 +346,6 @@ static int create_polling_proc(union acpi_hotkey *device)
char proc_name[80];
mode_t mode;
- ACPI_FUNCTION_TRACE("create_polling_proc");
mode = S_IFREG | S_IRUGO | S_IWUGO;
sprintf(proc_name, "%d", device->link.hotkey_standard_num);
@@ -356,10 +355,7 @@ static int create_polling_proc(union acpi_hotkey *device)
proc = create_proc_entry(proc_name, mode, hotkey_proc_dir);
if (!proc) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Hotkey: Unable to create %s entry\n",
- device->poll_hotkey.poll_method));
- return_VALUE(-ENODEV);
+ return -ENODEV;
} else {
proc->proc_fops = &hotkey_polling_fops;
proc->owner = THIS_MODULE;
@@ -368,7 +364,7 @@ static int create_polling_proc(union acpi_hotkey *device)
proc->gid = 0;
device->poll_hotkey.proc = proc;
}
- return_VALUE(0);
+ return 0;
}
static int hotkey_add(union acpi_hotkey *device)
@@ -376,7 +372,6 @@ static int hotkey_add(union acpi_hotkey *device)
int status = 0;
struct acpi_device *dev = NULL;
- ACPI_FUNCTION_TRACE("hotkey_add");
if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) {
acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
@@ -391,14 +386,13 @@ static int hotkey_add(union acpi_hotkey *device)
list_add_tail(&device->link.entries, global_hotkey_list.entries);
- return_VALUE(status);
+ return status;
}
static int hotkey_remove(union acpi_hotkey *device)
{
struct list_head *entries, *next;
- ACPI_FUNCTION_TRACE("hotkey_remove");
list_for_each_safe(entries, next, global_hotkey_list.entries) {
union acpi_hotkey *key =
@@ -412,14 +406,13 @@ static int hotkey_remove(union acpi_hotkey *device)
}
}
kfree(device);
- return_VALUE(0);
+ return 0;
}
static int hotkey_update(union acpi_hotkey *key)
{
struct list_head *entries;
- ACPI_FUNCTION_TRACE("hotkey_update");
list_for_each(entries, global_hotkey_list.entries) {
union acpi_hotkey *tmp =
@@ -461,19 +454,18 @@ static int hotkey_update(union acpi_hotkey *key)
*/
kfree(key);
}
- return_VALUE(0);
+ return 0;
break;
}
}
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
static void free_hotkey_device(union acpi_hotkey *key)
{
struct acpi_device *dev;
- ACPI_FUNCTION_TRACE("free_hotkey_device");
if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
@@ -493,119 +485,119 @@ static void free_hotkey_device(union acpi_hotkey *key)
free_poll_hotkey_buffer(key);
}
kfree(key);
- return_VOID;
+ return;
}
static void free_hotkey_buffer(union acpi_hotkey *key)
{
+ /* key would never be null, action method could be */
kfree(key->event_hotkey.action_method);
}
static void free_poll_hotkey_buffer(union acpi_hotkey *key)
{
+ /* key would never be null, others could be*/
kfree(key->poll_hotkey.action_method);
kfree(key->poll_hotkey.poll_method);
kfree(key->poll_hotkey.poll_result);
}
static int
-init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str,
- char *method, int std_num, int external_num)
+init_hotkey_device(union acpi_hotkey *key, char **config_entry,
+ int std_num, int external_num)
{
acpi_handle tmp_handle;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("init_hotkey_device");
-
if (std_num < 0 || IS_POLL(std_num) || !key)
goto do_fail;
- if (!bus_str || !action_str || !method)
+ if (!config_entry[bus_handle] || !config_entry[action_handle]
+ || !config_entry[method])
goto do_fail;
key->link.hotkey_type = ACPI_HOTKEY_EVENT;
key->link.hotkey_standard_num = std_num;
key->event_hotkey.flag = 0;
- key->event_hotkey.action_method = method;
+ key->event_hotkey.action_method = config_entry[method];
- status =
- acpi_get_handle(NULL, bus_str, &(key->event_hotkey.bus_handle));
+ status = acpi_get_handle(NULL, config_entry[bus_handle],
+ &(key->event_hotkey.bus_handle));
if (ACPI_FAILURE(status))
- goto do_fail;
+ goto do_fail_zero;
key->event_hotkey.external_hotkey_num = external_num;
- status =
- acpi_get_handle(NULL, action_str,
+ status = acpi_get_handle(NULL, config_entry[action_handle],
&(key->event_hotkey.action_handle));
if (ACPI_FAILURE(status))
- goto do_fail;
+ goto do_fail_zero;
status = acpi_get_handle(key->event_hotkey.action_handle,
- method, &tmp_handle);
+ config_entry[method], &tmp_handle);
if (ACPI_FAILURE(status))
- goto do_fail;
- return_VALUE(AE_OK);
- do_fail:
- return_VALUE(-ENODEV);
+ goto do_fail_zero;
+ return AE_OK;
+do_fail_zero:
+ key->event_hotkey.action_method = NULL;
+do_fail:
+ return -ENODEV;
}
static int
-init_poll_hotkey_device(union acpi_hotkey *key,
- char *poll_str,
- char *poll_method,
- char *action_str, char *action_method, int std_num)
+init_poll_hotkey_device(union acpi_hotkey *key, char **config_entry,
+ int std_num)
{
acpi_status status = AE_OK;
acpi_handle tmp_handle;
- ACPI_FUNCTION_TRACE("init_poll_hotkey_device");
-
if (std_num < 0 || IS_EVENT(std_num) || !key)
goto do_fail;
-
- if (!poll_str || !poll_method || !action_str || !action_method)
+ if (!config_entry[bus_handle] ||!config_entry[bus_method] ||
+ !config_entry[action_handle] || !config_entry[method])
goto do_fail;
key->link.hotkey_type = ACPI_HOTKEY_POLLING;
key->link.hotkey_standard_num = std_num;
key->poll_hotkey.flag = 0;
- key->poll_hotkey.poll_method = poll_method;
- key->poll_hotkey.action_method = action_method;
+ key->poll_hotkey.poll_method = config_entry[bus_method];
+ key->poll_hotkey.action_method = config_entry[method];
- status =
- acpi_get_handle(NULL, poll_str, &(key->poll_hotkey.poll_handle));
+ status = acpi_get_handle(NULL, config_entry[bus_handle],
+ &(key->poll_hotkey.poll_handle));
if (ACPI_FAILURE(status))
- goto do_fail;
+ goto do_fail_zero;
status = acpi_get_handle(key->poll_hotkey.poll_handle,
- poll_method, &tmp_handle);
+ config_entry[bus_method], &tmp_handle);
if (ACPI_FAILURE(status))
- goto do_fail;
+ goto do_fail_zero;
status =
- acpi_get_handle(NULL, action_str,
+ acpi_get_handle(NULL, config_entry[action_handle],
&(key->poll_hotkey.action_handle));
if (ACPI_FAILURE(status))
- goto do_fail;
+ goto do_fail_zero;
status = acpi_get_handle(key->poll_hotkey.action_handle,
- action_method, &tmp_handle);
+ config_entry[method], &tmp_handle);
if (ACPI_FAILURE(status))
- goto do_fail;
+ goto do_fail_zero;
key->poll_hotkey.poll_result =
(union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
if (!key->poll_hotkey.poll_result)
- goto do_fail;
- return_VALUE(AE_OK);
- do_fail:
- return_VALUE(-ENODEV);
+ goto do_fail_zero;
+ return AE_OK;
+
+do_fail_zero:
+ key->poll_hotkey.poll_method = NULL;
+ key->poll_hotkey.action_method = NULL;
+do_fail:
+ return -ENODEV;
}
static int hotkey_open_config(struct inode *inode, struct file *file)
{
- ACPI_FUNCTION_TRACE("hotkey_open_config");
- return_VALUE(single_open
+ return (single_open
(file, hotkey_config_seq_show, PDE(inode)->data));
}
static int hotkey_poll_open_config(struct inode *inode, struct file *file)
{
- ACPI_FUNCTION_TRACE("hotkey_poll_open_config");
- return_VALUE(single_open
+ return (single_open
(file, hotkey_poll_config_seq_show, PDE(inode)->data));
}
@@ -618,7 +610,6 @@ static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
- ACPI_FUNCTION_TRACE(("hotkey_config_seq_show"));
list_for_each(entries, hotkey_list->entries) {
union acpi_hotkey *key =
@@ -636,7 +627,7 @@ static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
}
}
seq_puts(seq, "\n");
- return_VALUE(0);
+ return 0;
}
static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset)
@@ -648,7 +639,6 @@ static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset)
struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
- ACPI_FUNCTION_TRACE(("hotkey_config_seq_show"));
list_for_each(entries, hotkey_list->entries) {
union acpi_hotkey *key =
@@ -666,22 +656,22 @@ static int hotkey_poll_config_seq_show(struct seq_file *seq, void *offset)
}
}
seq_puts(seq, "\n");
- return_VALUE(0);
+ return 0;
}
static int
-get_parms(char *config_record,
- int *cmd,
- char **bus_handle,
- char **bus_method,
- char **action_handle,
- char **method, int *internal_event_num, int *external_event_num)
+get_parms(char *config_record, int *cmd, char **config_entry,
+ int *internal_event_num, int *external_event_num)
{
+/* the format of *config_record =
+ * "1:\d+:*" : "cmd:internal_event_num"
+ * "\d+:\w+:\w+:\w+:\w+:\d+:\d+" :
+ * "cmd:bus_handle:bus_method:action_handle:method:internal_event_num:external_event_num"
+ */
char *tmp, *tmp1, count;
- ACPI_FUNCTION_TRACE(("get_parms"));
+ int i;
sscanf(config_record, "%d", cmd);
-
if (*cmd == 1) {
if (sscanf(config_record, "%d:%d", cmd, internal_event_num) !=
2)
@@ -693,60 +683,28 @@ get_parms(char *config_record,
if (!tmp)
goto do_fail;
tmp++;
- tmp1 = strchr(tmp, ':');
- if (!tmp1)
- goto do_fail;
-
- count = tmp1 - tmp;
- *bus_handle = (char *)kmalloc(count + 1, GFP_KERNEL);
- if (!*bus_handle)
- goto do_fail;
- strncpy(*bus_handle, tmp, count);
- *(*bus_handle + count) = 0;
-
- tmp = tmp1;
- tmp++;
- tmp1 = strchr(tmp, ':');
- if (!tmp1)
- goto do_fail;
- count = tmp1 - tmp;
- *bus_method = (char *)kmalloc(count + 1, GFP_KERNEL);
- if (!*bus_method)
- goto do_fail;
- strncpy(*bus_method, tmp, count);
- *(*bus_method + count) = 0;
-
- tmp = tmp1;
- tmp++;
- tmp1 = strchr(tmp, ':');
- if (!tmp1)
- goto do_fail;
- count = tmp1 - tmp;
- *action_handle = (char *)kmalloc(count + 1, GFP_KERNEL);
- if (!*action_handle)
- goto do_fail;
- strncpy(*action_handle, tmp, count);
- *(*action_handle + count) = 0;
-
- tmp = tmp1;
- tmp++;
- tmp1 = strchr(tmp, ':');
- if (!tmp1)
- goto do_fail;
- count = tmp1 - tmp;
- *method = (char *)kmalloc(count + 1, GFP_KERNEL);
- if (!*method)
- goto do_fail;
- strncpy(*method, tmp, count);
- *(*method + count) = 0;
-
- if (sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num) <=
- 0)
- goto do_fail;
-
- return_VALUE(6);
- do_fail:
- return_VALUE(-1);
+ for (i = 0; i < LAST_CONF_ENTRY; i++) {
+ tmp1 = strchr(tmp, ':');
+ if (!tmp1) {
+ goto do_fail;
+ }
+ count = tmp1 - tmp;
+ config_entry[i] = kzalloc(count + 1, GFP_KERNEL);
+ if (!config_entry[i])
+ goto handle_failure;
+ strncpy(config_entry[i], tmp, count);
+ tmp = tmp1 + 1;
+ }
+ if (sscanf(tmp, "%d:%d", internal_event_num, external_event_num) <= 0)
+ goto handle_failure;
+ if (!IS_OTHERS(*internal_event_num)) {
+ return 6;
+ }
+handle_failure:
+ while (i-- > 0)
+ kfree(config_entry[i]);
+do_fail:
+ return -1;
}
/* count is length for one input record */
@@ -755,91 +713,58 @@ static ssize_t hotkey_write_config(struct file *file,
size_t count, loff_t * data)
{
char *config_record = NULL;
- char *bus_handle = NULL;
- char *bus_method = NULL;
- char *action_handle = NULL;
- char *method = NULL;
+ char *config_entry[LAST_CONF_ENTRY];
int cmd, internal_event_num, external_event_num;
int ret = 0;
- union acpi_hotkey *key = NULL;
+ union acpi_hotkey *key = kzalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
- ACPI_FUNCTION_TRACE(("hotkey_write_config"));
+ if (!key)
+ return -ENOMEM;
- config_record = (char *)kmalloc(count + 1, GFP_KERNEL);
- if (!config_record)
- return_VALUE(-ENOMEM);
+ config_record = kzalloc(count + 1, GFP_KERNEL);
+ if (!config_record) {
+ kfree(key);
+ return -ENOMEM;
+ }
if (copy_from_user(config_record, buffer, count)) {
kfree(config_record);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
- return_VALUE(-EINVAL);
+ kfree(key);
+ printk(KERN_ERR PREFIX "Invalid data\n");
+ return -EINVAL;
}
- config_record[count] = 0;
-
- ret = get_parms(config_record,
- &cmd,
- &bus_handle,
- &bus_method,
- &action_handle,
- &method, &internal_event_num, &external_event_num);
-
+ ret = get_parms(config_record, &cmd, config_entry,
+ &internal_event_num, &external_event_num);
kfree(config_record);
- if (IS_OTHERS(internal_event_num))
- goto do_fail;
if (ret != 6) {
- do_fail:
- kfree(bus_handle);
- kfree(bus_method);
- kfree(action_handle);
- kfree(method);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid data format ret=%d\n", ret));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "Invalid data format ret=%d\n", ret);
+ return -EINVAL;
}
- key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
- if (!key)
- goto do_fail;
- memset(key, 0, sizeof(union acpi_hotkey));
if (cmd == 1) {
union acpi_hotkey *tmp = NULL;
tmp = get_hotkey_by_event(&global_hotkey_list,
internal_event_num);
if (!tmp)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid key"));
+ printk(KERN_ERR PREFIX "Invalid key\n");
else
memcpy(key, tmp, sizeof(union acpi_hotkey));
goto cont_cmd;
}
if (IS_EVENT(internal_event_num)) {
- kfree(bus_method);
- ret = init_hotkey_device(key, bus_handle, action_handle, method,
- internal_event_num,
- external_event_num);
- } else
- ret = init_poll_hotkey_device(key, bus_handle, bus_method,
- action_handle, method,
- internal_event_num);
- if (ret) {
- kfree(bus_handle);
- kfree(action_handle);
- if (IS_EVENT(internal_event_num))
- free_hotkey_buffer(key);
- else
- free_poll_hotkey_buffer(key);
- kfree(key);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
- return_VALUE(-EINVAL);
+ if (init_hotkey_device(key, config_entry,
+ internal_event_num, external_event_num))
+ goto init_hotkey_fail;
+ } else {
+ if (init_poll_hotkey_device(key, config_entry,
+ internal_event_num))
+ goto init_poll_hotkey_fail;
}
-
- cont_cmd:
- kfree(bus_handle);
- kfree(action_handle);
-
+cont_cmd:
switch (cmd) {
case 0:
- if (get_hotkey_by_event
- (&global_hotkey_list, key->link.hotkey_standard_num))
+ if (get_hotkey_by_event(&global_hotkey_list,
+ key->link.hotkey_standard_num))
goto fail_out;
else
hotkey_add(key);
@@ -848,6 +773,7 @@ static ssize_t hotkey_write_config(struct file *file,
hotkey_remove(key);
break;
case 2:
+ /* key is kfree()ed if matched*/
if (hotkey_update(key))
goto fail_out;
break;
@@ -855,15 +781,26 @@ static ssize_t hotkey_write_config(struct file *file,
goto fail_out;
break;
}
- return_VALUE(count);
- fail_out:
- if (IS_EVENT(internal_event_num))
- free_hotkey_buffer(key);
- else
- free_poll_hotkey_buffer(key);
+ return count;
+
+init_poll_hotkey_fail: /* failed init_poll_hotkey_device */
+ kfree(config_entry[bus_method]);
+ config_entry[bus_method] = NULL;
+init_hotkey_fail: /* failed init_hotkey_device */
+ kfree(config_entry[method]);
+fail_out:
+ kfree(config_entry[bus_handle]);
+ kfree(config_entry[action_handle]);
+ /* No double free since elements =NULL for error cases */
+ if (IS_EVENT(internal_event_num)) {
+ if (config_entry[bus_method])
+ kfree(config_entry[bus_method]);
+ free_hotkey_buffer(key); /* frees [method] */
+ } else
+ free_poll_hotkey_buffer(key); /* frees [bus_method]+[method] */
kfree(key);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid key\n"));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "invalid key\n");
+ return -EINVAL;
}
/*
@@ -880,7 +817,6 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
union acpi_object in_obj; /* the only param we use */
acpi_status status;
- ACPI_FUNCTION_TRACE("write_acpi_int");
params.count = 1;
params.pointer = &in_obj;
in_obj.type = ACPI_TYPE_INTEGER;
@@ -888,7 +824,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
status = acpi_evaluate_object(handle, (char *)method, &params, output);
- return_VALUE(status == AE_OK);
+ return (status == AE_OK);
}
static int read_acpi_int(acpi_handle handle, const char *method,
@@ -898,7 +834,6 @@ static int read_acpi_int(acpi_handle handle, const char *method,
union acpi_object out_obj;
acpi_status status;
- ACPI_FUNCTION_TRACE("read_acpi_int");
output.length = sizeof(out_obj);
output.pointer = &out_obj;
@@ -907,8 +842,8 @@ static int read_acpi_int(acpi_handle handle, const char *method,
val->integer.value = out_obj.integer.value;
val->type = out_obj.type;
} else
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "null val pointer"));
- return_VALUE((status == AE_OK)
+ printk(KERN_ERR PREFIX "null val pointer\n");
+ return ((status == AE_OK)
&& (out_obj.type == ACPI_TYPE_INTEGER));
}
@@ -945,24 +880,22 @@ static ssize_t hotkey_execute_aml_method(struct file *file,
int event, method_type, type, value;
union acpi_hotkey *key;
- ACPI_FUNCTION_TRACE("hotkey_execte_aml_method");
- arg = (char *)kmalloc(count + 1, GFP_KERNEL);
+ arg = kzalloc(count + 1, GFP_KERNEL);
if (!arg)
- return_VALUE(-ENOMEM);
- arg[count] = 0;
+ return -ENOMEM;
if (copy_from_user(arg, buffer, count)) {
kfree(arg);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2"));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "Invalid argument 2\n");
+ return -EINVAL;
}
if (sscanf(arg, "%d:%d:%d:%d", &event, &method_type, &type, &value) !=
4) {
kfree(arg);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3"));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "Invalid argument 3\n");
+ return -EINVAL;
}
kfree(arg);
if (type == ACPI_TYPE_INTEGER) {
@@ -987,12 +920,12 @@ static ssize_t hotkey_execute_aml_method(struct file *file,
}
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported"));
- return_VALUE(-EINVAL);
+ printk(KERN_WARNING "Not supported\n");
+ return -EINVAL;
}
- return_VALUE(count);
+ return count;
do_fail:
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
@@ -1001,7 +934,6 @@ static int __init hotkey_init(void)
int result;
mode_t mode = S_IFREG | S_IRUGO | S_IWUGO;
- ACPI_FUNCTION_TRACE("hotkey_init");
if (acpi_disabled)
return -ENODEV;
@@ -1013,9 +945,6 @@ static int __init hotkey_init(void)
hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir);
if (!hotkey_proc_dir) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Hotkey: Unable to create %s entry\n",
- HOTKEY_PROC));
return (-ENODEV);
}
hotkey_proc_dir->owner = THIS_MODULE;
@@ -1023,9 +952,6 @@ static int __init hotkey_init(void)
hotkey_config =
create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir);
if (!hotkey_config) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Hotkey: Unable to create %s entry\n",
- HOTKEY_EV_CONFIG));
goto do_fail1;
} else {
hotkey_config->proc_fops = &hotkey_config_fops;
@@ -1038,10 +964,6 @@ static int __init hotkey_init(void)
hotkey_poll_config =
create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir);
if (!hotkey_poll_config) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Hotkey: Unable to create %s entry\n",
- HOTKEY_EV_CONFIG));
-
goto do_fail2;
} else {
hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
@@ -1053,9 +975,6 @@ static int __init hotkey_init(void)
hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir);
if (!hotkey_action) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Hotkey: Unable to create %s entry\n",
- HOTKEY_ACTION));
goto do_fail3;
} else {
hotkey_action->proc_fops = &hotkey_action_fops;
@@ -1066,9 +985,6 @@ static int __init hotkey_init(void)
hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir);
if (!hotkey_info) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Hotkey: Unable to create %s entry\n",
- HOTKEY_INFO));
goto do_fail4;
} else {
hotkey_info->proc_fops = &hotkey_info_fops;
@@ -1104,7 +1020,6 @@ static void __exit hotkey_exit(void)
{
struct list_head *entries, *next;
- ACPI_FUNCTION_TRACE("hotkey_exit");
list_for_each_safe(entries, next, global_hotkey_list.entries) {
union acpi_hotkey *key =
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
new file mode 100644
index 00000000000..6342e612c20
--- /dev/null
+++ b/drivers/acpi/i2c_ec.c
@@ -0,0 +1,406 @@
+/*
+ * SMBus driver for ACPI Embedded Controller ($Revision: 1.3 $)
+ *
+ * Copyright (c) 2002, 2005 Ducrot Bruno
+ * Copyright (c) 2005 Rich Townsend (tiny hacks & tweaks)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+
+#include "i2c_ec.h"
+
+#define xudelay(t) udelay(t)
+#define xmsleep(t) msleep(t)
+
+#define ACPI_EC_HC_COMPONENT 0x00080000
+#define ACPI_EC_HC_CLASS "ec_hc_smbus"
+#define ACPI_EC_HC_HID "ACPI0001"
+#define ACPI_EC_HC_DRIVER_NAME "ACPI EC HC smbus driver"
+#define ACPI_EC_HC_DEVICE_NAME "EC HC smbus"
+
+#define _COMPONENT ACPI_EC_HC_COMPONENT
+
+ACPI_MODULE_NAME("acpi_smbus")
+
+static int acpi_ec_hc_add(struct acpi_device *device);
+static int acpi_ec_hc_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_ec_hc_driver = {
+ .name = ACPI_EC_HC_DRIVER_NAME,
+ .class = ACPI_EC_HC_CLASS,
+ .ids = ACPI_EC_HC_HID,
+ .ops = {
+ .add = acpi_ec_hc_add,
+ .remove = acpi_ec_hc_remove,
+ },
+};
+
+/* Various bit mask for EC_SC (R) */
+#define OBF 0x01
+#define IBF 0x02
+#define CMD 0x08
+#define BURST 0x10
+#define SCI_EVT 0x20
+#define SMI_EVT 0x40
+
+/* Commands for EC_SC (W) */
+#define RD_EC 0x80
+#define WR_EC 0x81
+#define BE_EC 0x82
+#define BD_EC 0x83
+#define QR_EC 0x84
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+
+#define ACPI_EC_SMB_PRTCL 0x00 /* protocol, PEC */
+#define ACPI_EC_SMB_STS 0x01 /* status */
+#define ACPI_EC_SMB_ADDR 0x02 /* address */
+#define ACPI_EC_SMB_CMD 0x03 /* command */
+#define ACPI_EC_SMB_DATA 0x04 /* 32 data registers */
+#define ACPI_EC_SMB_BCNT 0x24 /* number of data bytes */
+#define ACPI_EC_SMB_ALRM_A 0x25 /* alarm address */
+#define ACPI_EC_SMB_ALRM_D 0x26 /* 2 bytes alarm data */
+
+#define ACPI_EC_SMB_STS_DONE 0x80
+#define ACPI_EC_SMB_STS_ALRM 0x40
+#define ACPI_EC_SMB_STS_RES 0x20
+#define ACPI_EC_SMB_STS_STATUS 0x1f
+
+#define ACPI_EC_SMB_STATUS_OK 0x00
+#define ACPI_EC_SMB_STATUS_FAIL 0x07
+#define ACPI_EC_SMB_STATUS_DNAK 0x10
+#define ACPI_EC_SMB_STATUS_DERR 0x11
+#define ACPI_EC_SMB_STATUS_CMD_DENY 0x12
+#define ACPI_EC_SMB_STATUS_UNKNOWN 0x13
+#define ACPI_EC_SMB_STATUS_ACC_DENY 0x17
+#define ACPI_EC_SMB_STATUS_TIMEOUT 0x18
+#define ACPI_EC_SMB_STATUS_NOTSUP 0x19
+#define ACPI_EC_SMB_STATUS_BUSY 0x1A
+#define ACPI_EC_SMB_STATUS_PEC 0x1F
+
+#define ACPI_EC_SMB_PRTCL_WRITE 0x00
+#define ACPI_EC_SMB_PRTCL_READ 0x01
+#define ACPI_EC_SMB_PRTCL_QUICK 0x02
+#define ACPI_EC_SMB_PRTCL_BYTE 0x04
+#define ACPI_EC_SMB_PRTCL_BYTE_DATA 0x06
+#define ACPI_EC_SMB_PRTCL_WORD_DATA 0x08
+#define ACPI_EC_SMB_PRTCL_BLOCK_DATA 0x0a
+#define ACPI_EC_SMB_PRTCL_PROC_CALL 0x0c
+#define ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
+#define ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
+#define ACPI_EC_SMB_PRTCL_PEC 0x80
+
+/* Length of pre/post transaction sleep (msec) */
+#define ACPI_EC_SMB_TRANSACTION_SLEEP 1
+#define ACPI_EC_SMB_ACCESS_SLEEP1 1
+#define ACPI_EC_SMB_ACCESS_SLEEP2 10
+
+static int acpi_ec_smb_read(struct acpi_ec_smbus *smbus, u8 address, u8 * data)
+{
+ u8 val;
+ int err;
+
+ err = ec_read(smbus->base + address, &val);
+ if (!err) {
+ *data = val;
+ }
+ xmsleep(ACPI_EC_SMB_TRANSACTION_SLEEP);
+ return (err);
+}
+
+static int acpi_ec_smb_write(struct acpi_ec_smbus *smbus, u8 address, u8 data)
+{
+ int err;
+
+ err = ec_write(smbus->base + address, data);
+ return (err);
+}
+
+static int
+acpi_ec_smb_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+ char read_write, u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct acpi_ec_smbus *smbus = adap->algo_data;
+ unsigned char protocol, len = 0, pec, temp[2] = { 0, 0 };
+ int i;
+
+ if (read_write == I2C_SMBUS_READ) {
+ protocol = ACPI_EC_SMB_PRTCL_READ;
+ } else {
+ protocol = ACPI_EC_SMB_PRTCL_WRITE;
+ }
+ pec = (flags & I2C_CLIENT_PEC) ? ACPI_EC_SMB_PRTCL_PEC : 0;
+
+ switch (size) {
+
+ case I2C_SMBUS_QUICK:
+ protocol |= ACPI_EC_SMB_PRTCL_QUICK;
+ read_write = I2C_SMBUS_WRITE;
+ break;
+
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_WRITE) {
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_BYTE;
+ break;
+
+ case I2C_SMBUS_BYTE_DATA:
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->byte);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_BYTE_DATA;
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1,
+ data->word >> 8);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_WORD_DATA | pec;
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+ if (read_write == I2C_SMBUS_WRITE) {
+ len = min_t(u8, data->block[0], 32);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
+ for (i = 0; i < len; i++)
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
+ data->block[i + 1]);
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_BLOCK_DATA | pec;
+ break;
+
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ len = min_t(u8, data->block[0], 32);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
+ if (read_write == I2C_SMBUS_WRITE) {
+ for (i = 0; i < len; i++) {
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
+ data->block[i + 1]);
+ }
+ }
+ protocol |= ACPI_EC_SMB_PRTCL_I2C_BLOCK_DATA;
+ break;
+
+ case I2C_SMBUS_PROC_CALL:
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA, data->word);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + 1, data->word >> 8);
+ protocol = ACPI_EC_SMB_PRTCL_PROC_CALL | pec;
+ read_write = I2C_SMBUS_READ;
+ break;
+
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ protocol |= pec;
+ len = min_t(u8, data->block[0], 31);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_CMD, command);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_BCNT, len);
+ for (i = 0; i < len; i++)
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_DATA + i,
+ data->block[i + 1]);
+ protocol = ACPI_EC_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+ read_write = I2C_SMBUS_READ;
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "EC SMBus adapter: "
+ "Unsupported transaction %d\n", size));
+ return (-1);
+ }
+
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_ADDR, addr << 1);
+ acpi_ec_smb_write(smbus, ACPI_EC_SMB_PRTCL, protocol);
+
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
+
+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+ xudelay(500);
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
+ }
+ if (~temp[0] & ACPI_EC_SMB_STS_DONE) {
+ xmsleep(ACPI_EC_SMB_ACCESS_SLEEP2);
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_STS, temp + 0);
+ }
+ if ((~temp[0] & ACPI_EC_SMB_STS_DONE)
+ || (temp[0] & ACPI_EC_SMB_STS_STATUS)) {
+ return (-1);
+ }
+
+ if (read_write == I2C_SMBUS_WRITE) {
+ return (0);
+ }
+
+ switch (size) {
+
+ case I2C_SMBUS_BYTE:
+ case I2C_SMBUS_BYTE_DATA:
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, &data->byte);
+ break;
+
+ case I2C_SMBUS_WORD_DATA:
+ case I2C_SMBUS_PROC_CALL:
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA, temp + 0);
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + 1, temp + 1);
+ data->word = (temp[1] << 8) | temp[0];
+ break;
+
+ case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_BLOCK_PROC_CALL:
+ len = 0;
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_BCNT, &len);
+ len = min_t(u8, len, 32);
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ for (i = 0; i < len; i++)
+ acpi_ec_smb_read(smbus, ACPI_EC_SMB_DATA + i,
+ data->block + i + 1);
+ data->block[0] = len;
+ break;
+ }
+
+ return (0);
+}
+
+static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
+{
+
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_PROC_CALL |
+ I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
+}
+
+static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
+ .smbus_xfer = acpi_ec_smb_access,
+ .functionality = acpi_ec_smb_func,
+};
+
+static int acpi_ec_hc_add(struct acpi_device *device)
+{
+ int status;
+ unsigned long val;
+ struct acpi_ec_hc *ec_hc;
+ struct acpi_ec_smbus *smbus;
+
+ if (!device) {
+ return -EINVAL;
+ }
+
+ ec_hc = kmalloc(sizeof(struct acpi_ec_hc), GFP_KERNEL);
+ if (!ec_hc) {
+ return -ENOMEM;
+ }
+ memset(ec_hc, 0, sizeof(struct acpi_ec_hc));
+
+ smbus = kmalloc(sizeof(struct acpi_ec_smbus), GFP_KERNEL);
+ if (!smbus) {
+ kfree(ec_hc);
+ return -ENOMEM;
+ }
+ memset(smbus, 0, sizeof(struct acpi_ec_smbus));
+
+ ec_hc->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_EC_HC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_EC_HC_CLASS);
+ acpi_driver_data(device) = ec_hc;
+
+ status = acpi_evaluate_integer(ec_hc->handle, "_EC", NULL, &val);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error obtaining _EC\n"));
+ kfree(ec_hc);
+ kfree(smbus);
+ return -EIO;
+ }
+
+ smbus->ec = acpi_driver_data(device->parent);
+ smbus->base = (val & 0xff00ull) >> 8;
+ smbus->alert = val & 0xffull;
+
+ smbus->adapter.owner = THIS_MODULE;
+ smbus->adapter.algo = &acpi_ec_smbus_algorithm;
+ smbus->adapter.algo_data = smbus;
+
+ if (i2c_add_adapter(&smbus->adapter)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "EC SMBus adapter: Failed to register adapter\n"));
+ kfree(smbus);
+ kfree(ec_hc);
+ return -EIO;
+ }
+
+ ec_hc->smbus = smbus;
+
+ printk(KERN_INFO PREFIX "%s [%s]\n",
+ acpi_device_name(device), acpi_device_bid(device));
+
+ return AE_OK;
+}
+
+static int acpi_ec_hc_remove(struct acpi_device *device, int type)
+{
+ struct acpi_ec_hc *ec_hc;
+
+ if (!device) {
+ return -EINVAL;
+ }
+ ec_hc = acpi_driver_data(device);
+
+ i2c_del_adapter(&ec_hc->smbus->adapter);
+ kfree(ec_hc->smbus);
+ kfree(ec_hc);
+
+ return AE_OK;
+}
+
+static int __init acpi_ec_hc_init(void)
+{
+ int result;
+
+ result = acpi_bus_register_driver(&acpi_ec_hc_driver);
+ if (result < 0) {
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static void __exit acpi_ec_hc_exit(void)
+{
+ acpi_bus_unregister_driver(&acpi_ec_hc_driver);
+}
+
+struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device)
+{
+ return ((struct acpi_ec_hc *)acpi_driver_data(device->parent));
+}
+
+EXPORT_SYMBOL(acpi_get_ec_hc);
+
+module_init(acpi_ec_hc_init);
+module_exit(acpi_ec_hc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ducrot Bruno");
+MODULE_DESCRIPTION("ACPI EC SMBus driver");
diff --git a/drivers/acpi/i2c_ec.h b/drivers/acpi/i2c_ec.h
new file mode 100644
index 00000000000..7c53fb732d6
--- /dev/null
+++ b/drivers/acpi/i2c_ec.h
@@ -0,0 +1,23 @@
+/*
+ * SMBus driver for ACPI Embedded Controller ($Revision: 1.2 $)
+ *
+ * Copyright (c) 2002, 2005 Ducrot Bruno
+ *
+ * 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.
+ */
+
+struct acpi_ec_smbus {
+ struct i2c_adapter adapter;
+ union acpi_ec *ec;
+ int base;
+ int alert;
+};
+
+struct acpi_ec_hc {
+ acpi_handle handle;
+ struct acpi_ec_smbus *smbus;
+};
+
+struct acpi_ec_hc *acpi_get_ec_hc(struct acpi_device *device);
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
index d51d68f5dd8..ec6b7f9ede3 100644
--- a/drivers/acpi/motherboard.c
+++ b/drivers/acpi/motherboard.c
@@ -52,13 +52,12 @@ static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
{
struct resource *requested_res = NULL;
- ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges");
if (res->type == ACPI_RESOURCE_TYPE_IO) {
struct acpi_resource_io *io_res = &res->data.io;
if (io_res->minimum != io_res->maximum)
- return_VALUE(AE_OK);
+ return AE_OK;
if (IS_RESERVED_ADDR
(io_res->minimum, io_res->address_length)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -92,7 +91,7 @@ static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
if (requested_res)
requested_res->flags &= ~IORESOURCE_BUSY;
- return_VALUE(AE_OK);
+ return AE_OK;
}
static int acpi_motherboard_add(struct acpi_device *device)
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index 48fadade52e..c1c6c236df9 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -196,33 +196,30 @@ acpi_status acpi_ns_root_initialize(void)
(u8) (ACPI_TO_INTEGER(val) - 1);
if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
- /*
- * Create a counting semaphore for the
- * global lock
- */
+
+ /* Create a counting semaphore for the global lock */
+
status =
acpi_os_create_semaphore
(ACPI_NO_UNIT_LIMIT, 1,
- &obj_desc->mutex.semaphore);
+ &acpi_gbl_global_lock_semaphore);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference
(obj_desc);
goto unlock_and_exit;
}
- /*
- * We just created the mutex for the
- * global lock, save it
- */
- acpi_gbl_global_lock_semaphore =
- obj_desc->mutex.semaphore;
+ /* Mark this mutex as very special */
+
+ obj_desc->mutex.os_mutex =
+ ACPI_GLOBAL_LOCK;
} else {
/* Create a mutex */
- status = acpi_os_create_semaphore(1, 1,
- &obj_desc->
- mutex.
- semaphore);
+ status =
+ acpi_os_create_mutex(&obj_desc->
+ mutex.
+ os_mutex);
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference
(obj_desc);
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index dc3f0739a46..55b407aae26 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -386,14 +386,17 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node)
* specific ID. Used to delete entire ACPI tables. All
* reference counts are updated.
*
+ * MUTEX: Locks namespace during deletion walk.
+ *
******************************************************************************/
void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
{
struct acpi_namespace_node *child_node;
struct acpi_namespace_node *deletion_node;
- u32 level;
struct acpi_namespace_node *parent_node;
+ u32 level;
+ acpi_status status;
ACPI_FUNCTION_TRACE_U32(ns_delete_namespace_by_owner, owner_id);
@@ -401,6 +404,13 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
return_VOID;
}
+ /* Lock namespace for possible update */
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_VOID;
+ }
+
deletion_node = NULL;
parent_node = acpi_gbl_root_node;
child_node = NULL;
@@ -469,5 +479,6 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id)
}
}
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_VOID;
}
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index 6d9bd45af30..dca6799ac67 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -133,7 +133,7 @@ acpi_evaluate_object_typed(acpi_handle handle,
/* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */
- acpi_os_free(return_buffer->pointer);
+ ACPI_FREE(return_buffer->pointer);
return_buffer->pointer = NULL;
}
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index e2c1a16078c..e5e448edca4 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -23,7 +23,6 @@
*
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -254,5 +253,16 @@ int acpi_get_pxm(acpi_handle h)
} while (ACPI_SUCCESS(status));
return -1;
}
-
EXPORT_SYMBOL(acpi_get_pxm);
+
+int acpi_get_node(acpi_handle *handle)
+{
+ int pxm, node = -1;
+
+ pxm = acpi_get_pxm(handle);
+ if (pxm >= 0)
+ node = acpi_map_pxm_to_node(pxm);
+
+ return node;
+}
+EXPORT_SYMBOL(acpi_get_node);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 1bb558adee6..20beea778ea 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -25,7 +25,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -37,7 +36,6 @@
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
-#include <linux/kthread.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
@@ -137,22 +135,6 @@ void acpi_os_vprintf(const char *fmt, va_list args)
#endif
}
-extern int acpi_in_resume;
-void *acpi_os_allocate(acpi_size size)
-{
- if (acpi_in_resume)
- return kmalloc(size, GFP_ATOMIC);
- else
- return kmalloc(size, GFP_KERNEL);
-}
-
-void acpi_os_free(void *ptr)
-{
- kfree(ptr);
-}
-
-EXPORT_SYMBOL(acpi_os_free);
-
acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
{
if (efi_enabled) {
@@ -280,7 +262,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
acpi_irq_handler = handler;
acpi_irq_context = context;
- if (request_irq(irq, acpi_irq, SA_SHIRQ, "acpi", acpi_irq)) {
+ if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
return AE_NOT_ACQUIRED;
}
@@ -586,29 +568,18 @@ static void acpi_os_execute_deferred(void *context)
{
struct acpi_os_dpc *dpc = NULL;
- ACPI_FUNCTION_TRACE("os_execute_deferred");
dpc = (struct acpi_os_dpc *)context;
if (!dpc) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
- return_VOID;
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+ return;
}
dpc->function(dpc->context);
kfree(dpc);
- return_VOID;
-}
-
-static int acpi_os_execute_thread(void *context)
-{
- struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
- if (dpc) {
- dpc->function(dpc->context);
- kfree(dpc);
- }
- do_exit(0);
+ return;
}
/*******************************************************************************
@@ -632,10 +603,16 @@ acpi_status acpi_os_execute(acpi_execute_type type,
acpi_status status = AE_OK;
struct acpi_os_dpc *dpc;
struct work_struct *task;
- struct task_struct *p;
+
+ ACPI_FUNCTION_TRACE("os_queue_for_execution");
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Scheduling function [%p(%p)] for deferred execution.\n",
+ function, context));
if (!function)
- return AE_BAD_PARAMETER;
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
/*
* Allocate/initialize DPC structure. Note that this memory will be
* freed by the callee. The kernel handles the tq_struct list in a
@@ -646,34 +623,27 @@ acpi_status acpi_os_execute(acpi_execute_type type,
* We can save time and code by allocating the DPC and tq_structs
* from the same memory.
*/
- if (type == OSL_NOTIFY_HANDLER) {
- dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_KERNEL);
- } else {
- dpc = kmalloc(sizeof(struct acpi_os_dpc) +
- sizeof(struct work_struct), GFP_ATOMIC);
- }
+
+ dpc =
+ kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
+ GFP_ATOMIC);
if (!dpc)
- return AE_NO_MEMORY;
+ return_ACPI_STATUS(AE_NO_MEMORY);
+
dpc->function = function;
dpc->context = context;
- if (type == OSL_NOTIFY_HANDLER) {
- p = kthread_create(acpi_os_execute_thread, dpc, "kacpid_notify");
- if (!IS_ERR(p)) {
- wake_up_process(p);
- } else {
- status = AE_NO_MEMORY;
- kfree(dpc);
- }
- } else {
- task = (void *)(dpc + 1);
- INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
- if (!queue_work(kacpid_wq, task)) {
- status = AE_ERROR;
- kfree(dpc);
- }
+ task = (void *)(dpc + 1);
+ INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
+
+ if (!queue_work(kacpid_wq, task)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Call to queue_work() failed.\n"));
+ kfree(dpc);
+ status = AE_ERROR;
}
- return status;
+
+ return_ACPI_STATUS(status);
}
EXPORT_SYMBOL(acpi_os_execute);
@@ -688,35 +658,19 @@ EXPORT_SYMBOL(acpi_os_wait_events_complete);
/*
* Allocate the memory for a spinlock and initialize it.
*/
-acpi_status acpi_os_create_lock(acpi_handle * out_handle)
+acpi_status acpi_os_create_lock(acpi_spinlock * handle)
{
- spinlock_t *lock_ptr;
-
- ACPI_FUNCTION_TRACE("os_create_lock");
-
- lock_ptr = acpi_os_allocate(sizeof(spinlock_t));
-
- spin_lock_init(lock_ptr);
-
- ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating spinlock[%p].\n", lock_ptr));
+ spin_lock_init(*handle);
- *out_handle = lock_ptr;
-
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
/*
* Deallocate the memory for a spinlock.
*/
-void acpi_os_delete_lock(acpi_handle handle)
+void acpi_os_delete_lock(acpi_spinlock handle)
{
- ACPI_FUNCTION_TRACE("os_create_lock");
-
- ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting spinlock[%p].\n", handle));
-
- acpi_os_free(handle);
-
- return_VOID;
+ return;
}
acpi_status
@@ -724,11 +678,10 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
{
struct semaphore *sem = NULL;
- ACPI_FUNCTION_TRACE("os_create_semaphore");
sem = acpi_os_allocate(sizeof(struct semaphore));
if (!sem)
- return_ACPI_STATUS(AE_NO_MEMORY);
+ return AE_NO_MEMORY;
memset(sem, 0, sizeof(struct semaphore));
sema_init(sem, initial_units);
@@ -738,7 +691,7 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n",
*handle, initial_units));
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
EXPORT_SYMBOL(acpi_os_create_semaphore);
@@ -754,17 +707,16 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle)
{
struct semaphore *sem = (struct semaphore *)handle;
- ACPI_FUNCTION_TRACE("os_delete_semaphore");
if (!sem)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle));
- acpi_os_free(sem);
+ kfree(sem);
sem = NULL;
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
EXPORT_SYMBOL(acpi_os_delete_semaphore);
@@ -784,17 +736,26 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
struct semaphore *sem = (struct semaphore *)handle;
int ret = 0;
- ACPI_FUNCTION_TRACE("os_wait_semaphore");
if (!sem || (units < 1))
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
if (units > 1)
- return_ACPI_STATUS(AE_SUPPORT);
+ return AE_SUPPORT;
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
handle, units, timeout));
+ /*
+ * This can be called during resume with interrupts off.
+ * Like boot-time, we should be single threaded and will
+ * always get the lock if we try -- timeout or not.
+ * If this doesn't succeed, then we will oops courtesy of
+ * might_sleep() in down().
+ */
+ if (!down_trylock(sem))
+ return AE_OK;
+
switch (timeout) {
/*
* No Wait:
@@ -839,17 +800,17 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
}
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Failed to acquire semaphore[%p|%d|%d], %s\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
+ "Failed to acquire semaphore[%p|%d|%d], %s",
handle, units, timeout,
acpi_format_exception(status)));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Acquired semaphore[%p|%d|%d]\n", handle,
+ "Acquired semaphore[%p|%d|%d]", handle,
units, timeout));
}
- return_ACPI_STATUS(status);
+ return status;
}
EXPORT_SYMBOL(acpi_os_wait_semaphore);
@@ -861,20 +822,19 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
{
struct semaphore *sem = (struct semaphore *)handle;
- ACPI_FUNCTION_TRACE("os_signal_semaphore");
if (!sem || (units < 1))
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
if (units > 1)
- return_ACPI_STATUS(AE_SUPPORT);
+ return AE_SUPPORT;
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
units));
up(sem);
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
EXPORT_SYMBOL(acpi_os_signal_semaphore);
@@ -1043,10 +1003,10 @@ EXPORT_SYMBOL(max_cstate);
* handle is a pointer to the spinlock_t.
*/
-acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle)
+acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
{
acpi_cpu_flags flags;
- spin_lock_irqsave((spinlock_t *) handle, flags);
+ spin_lock_irqsave(lockp, flags);
return flags;
}
@@ -1054,9 +1014,9 @@ acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle)
* Release a spinlock. See above.
*/
-void acpi_os_release_lock(acpi_handle handle, acpi_cpu_flags flags)
+void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
{
- spin_unlock_irqrestore((spinlock_t *) handle, flags);
+ spin_unlock_irqrestore(lockp, flags);
}
#ifndef ACPI_USE_LOCAL_CACHE
@@ -1119,7 +1079,7 @@ acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
{
- (void)kmem_cache_destroy(cache);
+ kmem_cache_destroy(cache);
return (AE_OK);
}
@@ -1143,26 +1103,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
return (AE_OK);
}
-/*******************************************************************************
- *
- * FUNCTION: acpi_os_acquire_object
- *
- * PARAMETERS: Cache - Handle to cache object
- * ReturnObject - Where the object is returned
- *
- * RETURN: Status
- *
- * DESCRIPTION: Return a zero-filled object.
- *
- ******************************************************************************/
-
-void *acpi_os_acquire_object(acpi_cache_t * cache)
-{
- void *object = kmem_cache_zalloc(cache, GFP_KERNEL);
- WARN_ON(!object);
- return object;
-}
-
/******************************************************************************
*
* FUNCTION: acpi_os_validate_interface
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index 7ee2f2e7752..a02aa62fe1e 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -469,6 +469,16 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
}
walk_state->thread = thread;
+
+ /*
+ * If executing a method, the starting sync_level is this method's
+ * sync_level
+ */
+ if (walk_state->method_desc) {
+ walk_state->thread->current_sync_level =
+ walk_state->method_desc->method.sync_level;
+ }
+
acpi_ds_push_walk_state(walk_state, thread);
/*
@@ -505,6 +515,10 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
status =
acpi_ds_call_control_method(thread, walk_state,
NULL);
+ if (ACPI_FAILURE(status)) {
+ status =
+ acpi_ds_method_error(status, walk_state);
+ }
/*
* If the transfer to the new method method call worked, a new walk
@@ -525,7 +539,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
/* Check for possible multi-thread reentrancy problem */
if ((status == AE_ALREADY_EXISTS) &&
- (!walk_state->method_desc->method.semaphore)) {
+ (!walk_state->method_desc->method.mutex)) {
/*
* Method tried to create an object twice. The probable cause is
* that the method cannot handle reentrancy.
@@ -537,7 +551,7 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
*/
walk_state->method_desc->method.method_flags |=
AML_METHOD_SERIALIZED;
- walk_state->method_desc->method.concurrency = 1;
+ walk_state->method_desc->method.sync_level = 0;
}
}
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index 182474ae8ce..d405387b741 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -139,12 +139,10 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode)
/* The generic op (default) is by far the most common (16 to 1) */
op = acpi_os_acquire_object(acpi_gbl_ps_node_cache);
- memset(op, 0, sizeof(struct acpi_parse_obj_common));
} else {
/* Extended parseop */
op = acpi_os_acquire_object(acpi_gbl_ps_node_ext_cache);
- memset(op, 0, sizeof(struct acpi_parse_obj_named));
}
/* Initialize the Op */
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 2a718df769b..1e2ae6e7a7e 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -47,11 +47,10 @@ struct acpi_pci_data {
static void acpi_pci_data_handler(acpi_handle handle, u32 function,
void *context)
{
- ACPI_FUNCTION_TRACE("acpi_pci_data_handler");
/* TBD: Anything we need to do here? */
- return_VOID;
+ return;
}
/**
@@ -68,25 +67,24 @@ acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)
struct acpi_device *device = NULL;
struct acpi_pci_data *data = NULL;
- ACPI_FUNCTION_TRACE("acpi_get_pci_id");
if (!id)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
result = acpi_bus_get_device(handle, &device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid ACPI Bus context for device %s\n",
- acpi_device_bid(device)));
- return_ACPI_STATUS(AE_NOT_EXIST);
+ printk(KERN_ERR PREFIX
+ "Invalid ACPI Bus context for device %s\n",
+ acpi_device_bid(device));
+ return AE_NOT_EXIST;
}
status = acpi_get_data(handle, acpi_pci_data_handler, (void **)&data);
if (ACPI_FAILURE(status) || !data) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid ACPI-PCI context for device %s\n",
- acpi_device_bid(device)));
- return_ACPI_STATUS(status);
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Invalid ACPI-PCI context for device %s",
+ acpi_device_bid(device)));
+ return status;
}
*id = data->id;
@@ -103,7 +101,7 @@ acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id)
acpi_device_bid(device), id->segment, id->bus,
id->device, id->function));
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
EXPORT_SYMBOL(acpi_get_pci_id);
@@ -120,14 +118,13 @@ int acpi_pci_bind(struct acpi_device *device)
struct pci_dev *dev;
struct pci_bus *bus;
- ACPI_FUNCTION_TRACE("acpi_pci_bind");
if (!device || !device->parent)
- return_VALUE(-EINVAL);
+ return -EINVAL;
pathname = kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(pathname, 0, ACPI_PATHNAME_MAX);
buffer.length = ACPI_PATHNAME_MAX;
buffer.pointer = pathname;
@@ -135,7 +132,7 @@ int acpi_pci_bind(struct acpi_device *device)
data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data) {
kfree(pathname);
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
}
memset(data, 0, sizeof(struct acpi_pci_data));
@@ -151,9 +148,9 @@ int acpi_pci_bind(struct acpi_device *device)
status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
(void **)&pdata);
if (ACPI_FAILURE(status) || !pdata || !pdata->bus) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid ACPI-PCI context for parent device %s\n",
- acpi_device_bid(device->parent)));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Invalid ACPI-PCI context for parent device %s",
+ acpi_device_bid(device->parent)));
result = -ENODEV;
goto end;
}
@@ -206,10 +203,10 @@ int acpi_pci_bind(struct acpi_device *device)
goto end;
}
if (!data->dev->bus) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
- data->id.segment, data->id.bus,
- data->id.device, data->id.function));
+ printk(KERN_ERR PREFIX
+ "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
+ data->id.segment, data->id.bus,
+ data->id.device, data->id.function);
result = -ENODEV;
goto end;
}
@@ -237,9 +234,9 @@ int acpi_pci_bind(struct acpi_device *device)
*/
status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to attach ACPI-PCI context to device %s\n",
- acpi_device_bid(device)));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Unable to attach ACPI-PCI context to device %s",
+ acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
@@ -269,7 +266,7 @@ int acpi_pci_bind(struct acpi_device *device)
if (result)
kfree(data);
- return_VALUE(result);
+ return result;
}
int acpi_pci_unbind(struct acpi_device *device)
@@ -280,14 +277,13 @@ int acpi_pci_unbind(struct acpi_device *device)
char *pathname = NULL;
struct acpi_buffer buffer = { 0, NULL };
- ACPI_FUNCTION_TRACE("acpi_pci_unbind");
if (!device || !device->parent)
- return_VALUE(-EINVAL);
+ return -EINVAL;
pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(pathname, 0, ACPI_PATHNAME_MAX);
buffer.length = ACPI_PATHNAME_MAX;
@@ -301,18 +297,18 @@ int acpi_pci_unbind(struct acpi_device *device)
acpi_get_data(device->handle, acpi_pci_data_handler,
(void **)&data);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to get data from device %s\n",
- acpi_device_bid(device)));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Unable to get data from device %s",
+ acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
status = acpi_detach_data(device->handle, acpi_pci_data_handler);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to detach data from device %s\n",
- acpi_device_bid(device)));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Unable to detach data from device %s",
+ acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
@@ -322,7 +318,7 @@ int acpi_pci_unbind(struct acpi_device *device)
kfree(data);
end:
- return_VALUE(result);
+ return result;
}
int
@@ -335,11 +331,10 @@ acpi_pci_bind_root(struct acpi_device *device,
char *pathname = NULL;
struct acpi_buffer buffer = { 0, NULL };
- ACPI_FUNCTION_TRACE("acpi_pci_bind_root");
pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(pathname, 0, ACPI_PATHNAME_MAX);
buffer.length = ACPI_PATHNAME_MAX;
@@ -347,13 +342,13 @@ acpi_pci_bind_root(struct acpi_device *device,
if (!device || !id || !bus) {
kfree(pathname);
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data) {
kfree(pathname);
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
}
memset(data, 0, sizeof(struct acpi_pci_data));
@@ -369,9 +364,9 @@ acpi_pci_bind_root(struct acpi_device *device,
status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to attach ACPI-PCI context to device %s\n",
- pathname));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Unable to attach ACPI-PCI context to device %s",
+ pathname));
result = -ENODEV;
goto end;
}
@@ -381,5 +376,5 @@ acpi_pci_bind_root(struct acpi_device *device,
if (result != 0)
kfree(data);
- return_VALUE(result);
+ return result;
}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 65aee79b397..feda0341f5a 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -24,7 +24,6 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -55,10 +54,9 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
struct list_head *node = NULL;
struct acpi_prt_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry");
if (!acpi_prt.count)
- return_PTR(NULL);
+ return NULL;
/*
* Parse through all PRT entries looking for a match on the specified
@@ -73,12 +71,12 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
&& (device == entry->id.device)
&& (pin == entry->pin)) {
spin_unlock(&acpi_prt_lock);
- return_PTR(entry);
+ return entry;
}
}
spin_unlock(&acpi_prt_lock);
- return_PTR(NULL);
+ return NULL;
}
static int
@@ -87,14 +85,13 @@ acpi_pci_irq_add_entry(acpi_handle handle,
{
struct acpi_prt_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_add_entry");
if (!prt)
- return_VALUE(-EINVAL);
+ return -EINVAL;
entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
if (!entry)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(entry, 0, sizeof(struct acpi_prt_entry));
entry->id.segment = segment;
@@ -141,7 +138,7 @@ acpi_pci_irq_add_entry(acpi_handle handle,
acpi_prt.count++;
spin_unlock(&acpi_prt_lock);
- return_VALUE(0);
+ return 0;
}
static void
@@ -163,11 +160,10 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
struct acpi_pci_routing_table *entry = NULL;
static int first_time = 1;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_add_prt");
pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
if (!pathname)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(pathname, 0, ACPI_PATHNAME_MAX);
if (first_time) {
@@ -197,24 +193,24 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
kfree(pathname);
status = acpi_get_irq_routing_table(handle, &buffer);
if (status != AE_BUFFER_OVERFLOW) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
- acpi_format_exception(status)));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
+ acpi_format_exception(status)));
+ return -ENODEV;
}
prt = kmalloc(buffer.length, GFP_KERNEL);
if (!prt) {
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
}
memset(prt, 0, buffer.length);
buffer.pointer = prt;
status = acpi_get_irq_routing_table(handle, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
- acpi_format_exception(status)));
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]",
+ acpi_format_exception(status)));
kfree(buffer.pointer);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
entry = prt;
@@ -227,7 +223,7 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus)
kfree(prt);
- return_VALUE(0);
+ return 0;
}
void acpi_pci_irq_del_prt(int segment, int bus)
@@ -262,16 +258,15 @@ acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
{
int irq;
- ACPI_FUNCTION_TRACE("acpi_pci_allocate_irq");
if (entry->link.handle) {
irq = acpi_pci_link_allocate_irq(entry->link.handle,
entry->link.index, triggering,
polarity, link);
if (irq < 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid IRQ link routing entry\n"));
- return_VALUE(-1);
+ printk(KERN_WARNING PREFIX
+ "Invalid IRQ link routing entry\n");
+ return -1;
}
} else {
irq = entry->link.index;
@@ -280,7 +275,7 @@ acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
- return_VALUE(irq);
+ return irq;
}
static int
@@ -289,13 +284,12 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry,
{
int irq;
- ACPI_FUNCTION_TRACE("acpi_pci_free_irq");
if (entry->link.handle) {
irq = acpi_pci_link_free_irq(entry->link.handle);
} else {
irq = entry->link.index;
}
- return_VALUE(irq);
+ return irq;
}
/*
@@ -315,7 +309,6 @@ acpi_pci_irq_lookup(struct pci_bus *bus,
int bus_nr = bus->number;
int ret;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Searching for PRT entry for %02x:%02x:%02x[%c]\n",
@@ -324,11 +317,11 @@ acpi_pci_irq_lookup(struct pci_bus *bus,
entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin);
if (!entry) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
- return_VALUE(-1);
+ return -1;
}
ret = func(entry, triggering, polarity, link);
- return_VALUE(ret);
+ return ret;
}
/*
@@ -346,10 +339,9 @@ acpi_pci_irq_derive(struct pci_dev *dev,
int irq = -1;
u8 bridge_pin = 0;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_derive");
if (!dev)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* Attempt to derive an IRQ for this device from a parent bridge's
@@ -366,7 +358,7 @@ acpi_pci_irq_derive(struct pci_dev *dev,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No interrupt pin configured for device %s\n",
pci_name(bridge)));
- return_VALUE(-1);
+ return -1;
}
/* Pin is from 0 to 3 */
bridge_pin--;
@@ -379,16 +371,15 @@ acpi_pci_irq_derive(struct pci_dev *dev,
}
if (irq < 0) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Unable to derive IRQ for device %s\n",
- pci_name(dev)));
- return_VALUE(-1);
+ printk(KERN_WARNING PREFIX "Unable to derive IRQ for device %s\n",
+ pci_name(dev));
+ return -1;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n",
irq, pci_name(dev), pci_name(bridge)));
- return_VALUE(irq);
+ return irq;
}
/*
@@ -406,24 +397,22 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
char *link = NULL;
int rc;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
if (!dev)
- return_VALUE(-EINVAL);
+ return -EINVAL;
pin = dev->pin;
if (!pin) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No interrupt pin configured for device %s\n",
pci_name(dev)));
- return_VALUE(0);
+ return 0;
}
pin--;
if (!dev->bus) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid (NULL) 'bus' field\n"));
- return_VALUE(-ENODEV);
+ printk(KERN_ERR PREFIX "Invalid (NULL) 'bus' field\n");
+ return -ENODEV;
}
/*
@@ -455,10 +444,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
printk(" - using IRQ %d\n", dev->irq);
acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE,
ACPI_ACTIVE_LOW);
- return_VALUE(0);
+ return 0;
} else {
printk("\n");
- return_VALUE(0);
+ return 0;
}
}
@@ -466,7 +455,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
if (rc < 0) {
printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed "
"to register GSI\n", pci_name(dev), ('A' + pin));
- return_VALUE(rc);
+ return rc;
}
dev->irq = rc;
@@ -480,7 +469,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
(triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
(polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq);
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_pci_irq_enable);
@@ -497,14 +486,13 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
int triggering = ACPI_LEVEL_SENSITIVE;
int polarity = ACPI_ACTIVE_LOW;
- ACPI_FUNCTION_TRACE("acpi_pci_irq_disable");
if (!dev || !dev->bus)
- return_VOID;
+ return;
pin = dev->pin;
if (!pin)
- return_VOID;
+ return;
pin--;
/*
@@ -522,7 +510,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
&triggering, &polarity, NULL,
acpi_pci_free_irq);
if (gsi < 0)
- return_VOID;
+ return;
/*
* TBD: It might be worth clearing dev->irq by magic constant
@@ -534,5 +522,5 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
acpi_unregister_gsi(gsi);
- return_VOID;
+ return;
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 228bdb62650..7f3e7e77e79 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -83,7 +83,6 @@ struct acpi_pci_link_irq {
struct acpi_pci_link {
struct list_head node;
struct acpi_device *device;
- acpi_handle handle;
struct acpi_pci_link_irq irq;
int refcnt;
};
@@ -107,26 +106,23 @@ acpi_pci_link_check_possible(struct acpi_resource *resource, void *context)
struct acpi_pci_link *link = (struct acpi_pci_link *)context;
u32 i = 0;
- ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible");
switch (resource->type) {
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
case ACPI_RESOURCE_TYPE_IRQ:
{
struct acpi_resource_irq *p = &resource->data.irq;
if (!p || !p->interrupt_count) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Blank IRQ resource\n"));
- return_ACPI_STATUS(AE_OK);
+ printk(KERN_WARNING PREFIX "Blank IRQ resource\n");
+ return AE_OK;
}
for (i = 0;
(i < p->interrupt_count
&& i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
if (!p->interrupts[i]) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid IRQ %d\n",
- p->interrupts[i]));
+ printk(KERN_WARNING PREFIX "Invalid IRQ %d\n",
+ p->interrupts[i]);
continue;
}
link->irq.possible[i] = p->interrupts[i];
@@ -142,17 +138,16 @@ acpi_pci_link_check_possible(struct acpi_resource *resource, void *context)
struct acpi_resource_extended_irq *p =
&resource->data.extended_irq;
if (!p || !p->interrupt_count) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Blank EXT IRQ resource\n"));
- return_ACPI_STATUS(AE_OK);
+ printk(KERN_WARNING PREFIX
+ "Blank EXT IRQ resource\n");
+ return AE_OK;
}
for (i = 0;
(i < p->interrupt_count
&& i < ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
if (!p->interrupts[i]) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid IRQ %d\n",
- p->interrupts[i]));
+ printk(KERN_WARNING PREFIX "Invalid IRQ %d\n",
+ p->interrupts[i]);
continue;
}
link->irq.possible[i] = p->interrupts[i];
@@ -164,35 +159,33 @@ acpi_pci_link_check_possible(struct acpi_resource *resource, void *context)
break;
}
default:
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Resource is not an IRQ entry\n"));
- return_ACPI_STATUS(AE_OK);
+ printk(KERN_ERR PREFIX "Resource is not an IRQ entry\n");
+ return AE_OK;
}
- return_ACPI_STATUS(AE_CTRL_TERMINATE);
+ return AE_CTRL_TERMINATE;
}
static int acpi_pci_link_get_possible(struct acpi_pci_link *link)
{
acpi_status status;
- ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
if (!link)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- status = acpi_walk_resources(link->handle, METHOD_NAME__PRS,
+ status = acpi_walk_resources(link->device->handle, METHOD_NAME__PRS,
acpi_pci_link_check_possible, link);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRS"));
+ return -ENODEV;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found %d possible IRQs\n",
link->irq.possible_count));
- return_VALUE(0);
+ return 0;
}
static acpi_status
@@ -200,7 +193,6 @@ acpi_pci_link_check_current(struct acpi_resource *resource, void *context)
{
int *irq = (int *)context;
- ACPI_FUNCTION_TRACE("acpi_pci_link_check_current");
switch (resource->type) {
case ACPI_RESOURCE_TYPE_IRQ:
@@ -213,7 +205,7 @@ acpi_pci_link_check_current(struct acpi_resource *resource, void *context)
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Blank IRQ resource\n"));
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
*irq = p->interrupts[0];
break;
@@ -227,20 +219,20 @@ acpi_pci_link_check_current(struct acpi_resource *resource, void *context)
* extended IRQ descriptors must
* return at least 1 IRQ
*/
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Blank EXT IRQ resource\n"));
- return_ACPI_STATUS(AE_OK);
+ printk(KERN_WARNING PREFIX
+ "Blank EXT IRQ resource\n");
+ return AE_OK;
}
*irq = p->interrupts[0];
break;
}
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Resource %d isn't an IRQ\n", resource->type));
+ printk(KERN_ERR PREFIX "Resource %d isn't an IRQ\n", resource->type);
case ACPI_RESOURCE_TYPE_END_TAG:
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
- return_ACPI_STATUS(AE_CTRL_TERMINATE);
+ return AE_CTRL_TERMINATE;
}
/*
@@ -256,10 +248,8 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
acpi_status status = AE_OK;
int irq = 0;
- ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
-
- if (!link || !link->handle)
- return_VALUE(-EINVAL);
+ if (!link)
+ return -EINVAL;
link->irq.active = 0;
@@ -268,14 +258,13 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
/* Query _STA, set link->device->status */
result = acpi_bus_get_status(link->device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to read status\n"));
+ printk(KERN_ERR PREFIX "Unable to read status\n");
goto end;
}
if (!link->device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
- return_VALUE(0);
+ return 0;
}
}
@@ -283,16 +272,16 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
* Query and parse _CRS to get the current IRQ assignment.
*/
- status = acpi_walk_resources(link->handle, METHOD_NAME__CRS,
+ status = acpi_walk_resources(link->device->handle, METHOD_NAME__CRS,
acpi_pci_link_check_current, &irq);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _CRS"));
result = -ENODEV;
goto end;
}
if (acpi_strict && !irq) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n"));
+ printk(KERN_ERR PREFIX "_CRS returned 0\n");
result = -ENODEV;
}
@@ -301,7 +290,7 @@ static int acpi_pci_link_get_current(struct acpi_pci_link *link)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
end:
- return_VALUE(result);
+ return result;
}
static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
@@ -314,14 +303,13 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
} *resource;
struct acpi_buffer buffer = { 0, NULL };
- ACPI_FUNCTION_TRACE("acpi_pci_link_set");
if (!link || !irq)
- return_VALUE(-EINVAL);
+ return -EINVAL;
resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC);
if (!resource)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(resource, 0, sizeof(*resource) + 1);
buffer.length = sizeof(*resource) + 1;
@@ -362,7 +350,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
/* ignore resource_source, it's optional */
break;
default:
- printk("ACPI BUG: resource_type %d\n", link->irq.resource_type);
+ printk(KERN_ERR PREFIX "Invalid Resource_type %d\n", link->irq.resource_type);
result = -EINVAL;
goto end;
@@ -370,11 +358,11 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
resource->end.type = ACPI_RESOURCE_TYPE_END_TAG;
/* Attempt to set the resource */
- status = acpi_set_current_resources(link->handle, &buffer);
+ status = acpi_set_current_resources(link->device->handle, &buffer);
/* check for total failure */
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SRS"));
result = -ENODEV;
goto end;
}
@@ -382,14 +370,14 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
/* Query _STA, set device->status */
result = acpi_bus_get_status(link->device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+ printk(KERN_ERR PREFIX "Unable to read status\n");
goto end;
}
if (!link->device->status.enabled) {
printk(KERN_WARNING PREFIX
- "%s [%s] disabled and referenced, BIOS bug.\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device));
+ "%s [%s] disabled and referenced, BIOS bug\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device));
}
/* Query _CRS, set link->irq.active */
@@ -408,9 +396,9 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
* assume _SRS worked and override _CRS value.
*/
printk(KERN_WARNING PREFIX
- "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device), link->irq.active, irq);
+ "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device), link->irq.active, irq);
link->irq.active = irq;
}
@@ -418,7 +406,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
end:
kfree(resource);
- return_VALUE(result);
+ return result;
}
/* --------------------------------------------------------------------------
@@ -492,7 +480,6 @@ int __init acpi_irq_penalty_init(void)
struct acpi_pci_link *link = NULL;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
/*
* Update penalties to facilitate IRQ balancing.
@@ -501,8 +488,7 @@ int __init acpi_irq_penalty_init(void)
link = list_entry(node, struct acpi_pci_link, node);
if (!link) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid link context\n"));
+ printk(KERN_ERR PREFIX "Invalid link context\n");
continue;
}
@@ -530,7 +516,7 @@ int __init acpi_irq_penalty_init(void)
/* Add a penalty for the SCI */
acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
- return_VALUE(0);
+ return 0;
}
static int acpi_irq_balance; /* 0: static, 1: balance */
@@ -540,13 +526,12 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
int irq;
int i;
- ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
if (link->irq.initialized) {
if (link->refcnt == 0)
/* This means the link is disabled but initialized */
acpi_pci_link_set(link, link->irq.active);
- return_VALUE(0);
+ return 0;
}
/*
@@ -562,7 +547,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
if (i == link->irq.possible_count) {
if (acpi_strict)
printk(KERN_WARNING PREFIX "_CRS %d not found"
- " in _PRS\n", link->irq.active);
+ " in _PRS\n", link->irq.active);
link->irq.active = 0;
}
@@ -589,12 +574,11 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
/* Attempt to enable the link device at this IRQ. */
if (acpi_pci_link_set(link, irq)) {
- printk(PREFIX
- "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n"
- "Try pci=noacpi or acpi=off\n",
- acpi_device_name(link->device),
- acpi_device_bid(link->device));
- return_VALUE(-ENODEV);
+ printk(KERN_ERR PREFIX "Unable to set IRQ for %s [%s]. "
+ "Try pci=noacpi or acpi=off\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device));
+ return -ENODEV;
} else {
acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
printk(PREFIX "%s [%s] enabled at IRQ %d\n",
@@ -604,7 +588,7 @@ static int acpi_pci_link_allocate(struct acpi_pci_link *link)
link->irq.initialized = 1;
- return_VALUE(0);
+ return 0;
}
/*
@@ -622,36 +606,35 @@ acpi_pci_link_allocate_irq(acpi_handle handle,
struct acpi_device *device = NULL;
struct acpi_pci_link *link = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_link_allocate_irq");
result = acpi_bus_get_device(handle, &device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Invalid link device\n");
+ return -1;
}
link = (struct acpi_pci_link *)acpi_driver_data(device);
if (!link) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Invalid link context\n");
+ return -1;
}
/* TBD: Support multiple index (IRQ) entries per Link Device */
if (index) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Invalid index %d\n", index);
+ return -1;
}
mutex_lock(&acpi_link_lock);
if (acpi_pci_link_allocate(link)) {
mutex_unlock(&acpi_link_lock);
- return_VALUE(-1);
+ return -1;
}
if (!link->irq.active) {
mutex_unlock(&acpi_link_lock);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Link active IRQ is 0!\n");
+ return -1;
}
link->refcnt++;
mutex_unlock(&acpi_link_lock);
@@ -665,7 +648,7 @@ acpi_pci_link_allocate_irq(acpi_handle handle,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Link %s is referenced\n",
acpi_device_bid(link->device)));
- return_VALUE(link->irq.active);
+ return (link->irq.active);
}
/*
@@ -678,25 +661,24 @@ int acpi_pci_link_free_irq(acpi_handle handle)
struct acpi_pci_link *link = NULL;
acpi_status result;
- ACPI_FUNCTION_TRACE("acpi_pci_link_free_irq");
result = acpi_bus_get_device(handle, &device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Invalid link device\n");
+ return -1;
}
link = (struct acpi_pci_link *)acpi_driver_data(device);
if (!link) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Invalid link context\n");
+ return -1;
}
mutex_lock(&acpi_link_lock);
if (!link->irq.initialized) {
mutex_unlock(&acpi_link_lock);
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n"));
- return_VALUE(-1);
+ printk(KERN_ERR PREFIX "Link isn't initialized\n");
+ return -1;
}
#ifdef FUTURE_USE
/*
@@ -715,10 +697,10 @@ int acpi_pci_link_free_irq(acpi_handle handle)
acpi_device_bid(link->device)));
if (link->refcnt == 0) {
- acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+ acpi_ut_evaluate_object(link->device->handle, "_DIS", 0, NULL);
}
mutex_unlock(&acpi_link_lock);
- return_VALUE(link->irq.active);
+ return (link->irq.active);
}
/* --------------------------------------------------------------------------
@@ -732,18 +714,16 @@ static int acpi_pci_link_add(struct acpi_device *device)
int i = 0;
int found = 0;
- ACPI_FUNCTION_TRACE("acpi_pci_link_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
if (!link)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(link, 0, sizeof(struct acpi_pci_link));
link->device = device;
- link->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
acpi_driver_data(device) = link;
@@ -782,62 +762,51 @@ static int acpi_pci_link_add(struct acpi_device *device)
end:
/* disable all links -- to be activated on use */
- acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+ acpi_ut_evaluate_object(device->handle, "_DIS", 0, NULL);
mutex_unlock(&acpi_link_lock);
if (result)
kfree(link);
- return_VALUE(result);
+ return result;
}
static int acpi_pci_link_resume(struct acpi_pci_link *link)
{
- ACPI_FUNCTION_TRACE("acpi_pci_link_resume");
if (link->refcnt && link->irq.active && link->irq.initialized)
- return_VALUE(acpi_pci_link_set(link, link->irq.active));
+ return (acpi_pci_link_set(link, link->irq.active));
else
- return_VALUE(0);
+ return 0;
}
-/*
- * FIXME: this is a workaround to avoid nasty warning. It will be removed
- * after every device calls pci_disable_device in .resume.
- */
-int acpi_in_resume;
static int irqrouter_resume(struct sys_device *dev)
{
struct list_head *node = NULL;
struct acpi_pci_link *link = NULL;
- ACPI_FUNCTION_TRACE("irqrouter_resume");
/* Make sure SCI is enabled again (Apple firmware bug?) */
acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
- acpi_in_resume = 1;
list_for_each(node, &acpi_link.entries) {
link = list_entry(node, struct acpi_pci_link, node);
if (!link) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid link context\n"));
+ printk(KERN_ERR PREFIX "Invalid link context\n");
continue;
}
acpi_pci_link_resume(link);
}
- acpi_in_resume = 0;
- return_VALUE(0);
+ return 0;
}
static int acpi_pci_link_remove(struct acpi_device *device, int type)
{
struct acpi_pci_link *link = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_link_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
link = (struct acpi_pci_link *)acpi_driver_data(device);
@@ -847,7 +816,7 @@ static int acpi_pci_link_remove(struct acpi_device *device, int type)
kfree(link);
- return_VALUE(0);
+ return 0;
}
/*
@@ -953,34 +922,32 @@ static int __init irqrouter_init_sysfs(void)
{
int error;
- ACPI_FUNCTION_TRACE("irqrouter_init_sysfs");
if (acpi_disabled || acpi_noirq)
- return_VALUE(0);
+ return 0;
error = sysdev_class_register(&irqrouter_sysdev_class);
if (!error)
error = sysdev_register(&device_irqrouter);
- return_VALUE(error);
+ return error;
}
device_initcall(irqrouter_init_sysfs);
static int __init acpi_pci_link_init(void)
{
- ACPI_FUNCTION_TRACE("acpi_pci_link_init");
if (acpi_noirq)
- return_VALUE(0);
+ return 0;
acpi_link.count = 0;
INIT_LIST_HEAD(&acpi_link.entries);
if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
- return_VALUE(-ENODEV);
+ return -ENODEV;
- return_VALUE(0);
+ return 0;
}
subsys_initcall(acpi_pci_link_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4c313eab631..0984a1ee24e 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -58,7 +58,7 @@ static struct acpi_driver acpi_pci_root_driver = {
struct acpi_pci_root {
struct list_head node;
- acpi_handle handle;
+ struct acpi_device * device;
struct acpi_pci_id id;
struct pci_bus *bus;
};
@@ -83,7 +83,7 @@ int acpi_pci_register_driver(struct acpi_pci_driver *driver)
list_for_each(entry, &acpi_pci_roots) {
struct acpi_pci_root *root;
root = list_entry(entry, struct acpi_pci_root, node);
- driver->add(root->handle);
+ driver->add(root->device->handle);
n++;
}
@@ -110,7 +110,7 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
list_for_each(entry, &acpi_pci_roots) {
struct acpi_pci_root *root;
root = list_entry(entry, struct acpi_pci_root, node);
- driver->remove(root->handle);
+ driver->remove(root->device->handle);
}
}
@@ -160,18 +160,17 @@ static int acpi_pci_root_add(struct acpi_device *device)
unsigned long value = 0;
acpi_handle handle = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_root_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(root, 0, sizeof(struct acpi_pci_root));
INIT_LIST_HEAD(&root->node);
- root->handle = device->handle;
+ root->device = device;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = root;
@@ -186,7 +185,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
* -------
* Obtained via _SEG, if exists, otherwise assumed to be zero (0).
*/
- status = acpi_evaluate_integer(root->handle, METHOD_NAME__SEG, NULL,
+ status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
&value);
switch (status) {
case AE_OK:
@@ -198,7 +197,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
root->id.segment = 0;
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _SEG"));
result = -ENODEV;
goto end;
}
@@ -208,7 +207,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
* ---
* Obtained via _BBN, if exists, otherwise assumed to be zero (0).
*/
- status = acpi_evaluate_integer(root->handle, METHOD_NAME__BBN, NULL,
+ status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL,
&value);
switch (status) {
case AE_OK:
@@ -219,7 +218,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
root->id.bus = 0;
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _BBN"));
result = -ENODEV;
goto end;
}
@@ -231,10 +230,11 @@ static int acpi_pci_root_add(struct acpi_device *device)
int bus = 0;
acpi_status status;
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Wrong _BBN value, please reboot and using option 'pci=noacpi'\n"));
+ printk(KERN_ERR PREFIX
+ "Wrong _BBN value, reboot"
+ " and use option 'pci=noacpi'\n");
- status = try_get_root_bridge_busnr(root->handle, &bus);
+ status = try_get_root_bridge_busnr(device->handle, &bus);
if (ACPI_FAILURE(status))
break;
if (bus != root->id.bus) {
@@ -273,9 +273,9 @@ static int acpi_pci_root_add(struct acpi_device *device)
*/
root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
if (!root->bus) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Bus %04x:%02x not present in PCI namespace\n",
- root->id.segment, root->id.bus));
+ printk(KERN_ERR PREFIX
+ "Bus %04x:%02x not present in PCI namespace\n",
+ root->id.segment, root->id.bus);
result = -ENODEV;
goto end;
}
@@ -294,9 +294,9 @@ static int acpi_pci_root_add(struct acpi_device *device)
* -----------------
* Evaluate and parse _PRT, if exists.
*/
- status = acpi_get_handle(root->handle, METHOD_NAME__PRT, &handle);
+ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status))
- result = acpi_pci_irq_add_prt(root->handle, root->id.segment,
+ result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
root->id.bus);
end:
@@ -306,46 +306,43 @@ static int acpi_pci_root_add(struct acpi_device *device)
kfree(root);
}
- return_VALUE(result);
+ return result;
}
static int acpi_pci_root_start(struct acpi_device *device)
{
struct acpi_pci_root *root;
- ACPI_FUNCTION_TRACE("acpi_pci_root_start");
list_for_each_entry(root, &acpi_pci_roots, node) {
- if (root->handle == device->handle) {
+ if (root->device == device) {
pci_bus_add_devices(root->bus);
- return_VALUE(0);
+ return 0;
}
}
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
static int acpi_pci_root_remove(struct acpi_device *device, int type)
{
struct acpi_pci_root *root = NULL;
- ACPI_FUNCTION_TRACE("acpi_pci_root_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
root = (struct acpi_pci_root *)acpi_driver_data(device);
kfree(root);
- return_VALUE(0);
+ return 0;
}
static int __init acpi_pci_root_init(void)
{
- ACPI_FUNCTION_TRACE("acpi_pci_root_init");
if (acpi_pci_disabled)
- return_VALUE(0);
+ return 0;
/* DEBUG:
acpi_dbg_layer = ACPI_PCI_COMPONENT;
@@ -353,9 +350,9 @@ static int __init acpi_pci_root_init(void)
*/
if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
- return_VALUE(-ENODEV);
+ return -ENODEV;
- return_VALUE(0);
+ return 0;
}
subsys_initcall(acpi_pci_root_init);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 62a5595ed8b..fec225d1b6b 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -70,7 +70,7 @@ static struct acpi_driver acpi_power_driver = {
};
struct acpi_power_resource {
- acpi_handle handle;
+ struct acpi_device * device;
acpi_bus_id name;
u32 system_level;
u32 order;
@@ -80,7 +80,7 @@ struct acpi_power_resource {
static struct list_head acpi_power_resource_list;
-static struct file_operations acpi_power_fops = {
+static const struct file_operations acpi_power_fops = {
.open = acpi_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -98,23 +98,21 @@ acpi_power_get_context(acpi_handle handle,
int result = 0;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_power_get_context");
if (!resource)
- return_VALUE(-ENODEV);
+ return -ENODEV;
result = acpi_bus_get_device(handle, &device);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error getting context [%p]\n",
- handle));
- return_VALUE(result);
+ printk(KERN_WARNING PREFIX "Getting context [%p]\n", handle);
+ return result;
}
*resource = (struct acpi_power_resource *)acpi_driver_data(device);
if (!resource)
- return_VALUE(-ENODEV);
+ return -ENODEV;
- return_VALUE(0);
+ return 0;
}
static int acpi_power_get_state(struct acpi_power_resource *resource)
@@ -122,14 +120,13 @@ static int acpi_power_get_state(struct acpi_power_resource *resource)
acpi_status status = AE_OK;
unsigned long sta = 0;
- ACPI_FUNCTION_TRACE("acpi_power_get_state");
if (!resource)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- status = acpi_evaluate_integer(resource->handle, "_STA", NULL, &sta);
+ status = acpi_evaluate_integer(resource->device->handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (sta & 0x01)
resource->state = ACPI_POWER_RESOURCE_STATE_ON;
@@ -139,7 +136,7 @@ static int acpi_power_get_state(struct acpi_power_resource *resource)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
resource->name, resource->state ? "on" : "off"));
- return_VALUE(0);
+ return 0;
}
static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
@@ -148,20 +145,19 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
struct acpi_power_resource *resource = NULL;
u32 i = 0;
- ACPI_FUNCTION_TRACE("acpi_power_get_list_state");
if (!list || !state)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* The state of the list is 'on' IFF all resources are 'on'. */
for (i = 0; i < list->count; i++) {
result = acpi_power_get_context(list->handles[i], &resource);
if (result)
- return_VALUE(result);
+ return result;
result = acpi_power_get_state(resource);
if (result)
- return_VALUE(result);
+ return result;
*state = resource->state;
@@ -172,7 +168,7 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
*state ? "on" : "off"));
- return_VALUE(result);
+ return result;
}
static int acpi_power_on(acpi_handle handle)
@@ -182,11 +178,10 @@ static int acpi_power_on(acpi_handle handle)
struct acpi_device *device = NULL;
struct acpi_power_resource *resource = NULL;
- ACPI_FUNCTION_TRACE("acpi_power_on");
result = acpi_power_get_context(handle, &resource);
if (result)
- return_VALUE(result);
+ return result;
resource->references++;
@@ -194,29 +189,27 @@ static int acpi_power_on(acpi_handle handle)
|| (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n",
resource->name));
- return_VALUE(0);
+ return 0;
}
- status = acpi_evaluate_object(resource->handle, "_ON", NULL, NULL);
+ status = acpi_evaluate_object(resource->device->handle, "_ON", NULL, NULL);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
result = acpi_power_get_state(resource);
if (result)
- return_VALUE(result);
+ return result;
if (resource->state != ACPI_POWER_RESOURCE_STATE_ON)
- return_VALUE(-ENOEXEC);
+ return -ENOEXEC;
/* Update the power resource's _device_ power state */
- result = acpi_bus_get_device(resource->handle, &device);
- if (result)
- return_VALUE(result);
- device->power.state = ACPI_STATE_D0;
+ device = resource->device;
+ resource->device->power.state = ACPI_STATE_D0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n",
resource->name));
- return_VALUE(0);
+ return 0;
}
static int acpi_power_off_device(acpi_handle handle)
@@ -226,11 +219,10 @@ static int acpi_power_off_device(acpi_handle handle)
struct acpi_device *device = NULL;
struct acpi_power_resource *resource = NULL;
- ACPI_FUNCTION_TRACE("acpi_power_off_device");
result = acpi_power_get_context(handle, &resource);
if (result)
- return_VALUE(result);
+ return result;
if (resource->references)
resource->references--;
@@ -239,35 +231,33 @@ static int acpi_power_off_device(acpi_handle handle)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Resource [%s] is still in use, dereferencing\n",
device->pnp.bus_id));
- return_VALUE(0);
+ return 0;
}
if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
device->pnp.bus_id));
- return_VALUE(0);
+ return 0;
}
- status = acpi_evaluate_object(resource->handle, "_OFF", NULL, NULL);
+ status = acpi_evaluate_object(resource->device->handle, "_OFF", NULL, NULL);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
result = acpi_power_get_state(resource);
if (result)
- return_VALUE(result);
+ return result;
if (resource->state != ACPI_POWER_RESOURCE_STATE_OFF)
- return_VALUE(-ENOEXEC);
+ return -ENOEXEC;
/* Update the power resource's _device_ power state */
- result = acpi_bus_get_device(resource->handle, &device);
- if (result)
- return_VALUE(result);
+ device = resource->device;
device->power.state = ACPI_STATE_D3;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
resource->name));
- return_VALUE(0);
+ return 0;
}
/*
@@ -283,31 +273,29 @@ int acpi_enable_wakeup_device_power(struct acpi_device *dev)
int i;
int ret = 0;
- ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_power");
if (!dev || !dev->wakeup.flags.valid)
- return_VALUE(-1);
+ return -1;
arg.integer.value = 1;
/* Open power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
ret = acpi_power_on(dev->wakeup.resources.handles[i]);
if (ret) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error transition power state\n"));
+ printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
- return_VALUE(-1);
+ return -1;
}
}
/* Execute PSW */
status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+ printk(KERN_ERR PREFIX "Evaluate _PSW\n");
dev->wakeup.flags.valid = 0;
ret = -1;
}
- return_VALUE(ret);
+ return ret;
}
/*
@@ -323,32 +311,30 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev)
int i;
int ret = 0;
- ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device_power");
if (!dev || !dev->wakeup.flags.valid)
- return_VALUE(-1);
+ return -1;
arg.integer.value = 0;
/* Execute PSW */
status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+ printk(KERN_ERR PREFIX "Evaluate _PSW\n");
dev->wakeup.flags.valid = 0;
- return_VALUE(-1);
+ return -1;
}
/* Close power resource */
for (i = 0; i < dev->wakeup.resources.count; i++) {
ret = acpi_power_off_device(dev->wakeup.resources.handles[i]);
if (ret) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error transition power state\n"));
+ printk(KERN_ERR PREFIX "Transition power state\n");
dev->wakeup.flags.valid = 0;
- return_VALUE(-1);
+ return -1;
}
}
- return_VALUE(ret);
+ return ret;
}
/* --------------------------------------------------------------------------
@@ -362,10 +348,9 @@ int acpi_power_get_inferred_state(struct acpi_device *device)
int list_state = 0;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_power_get_inferred_state");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
device->power.state = ACPI_STATE_UNKNOWN;
@@ -380,17 +365,17 @@ int acpi_power_get_inferred_state(struct acpi_device *device)
result = acpi_power_get_list_state(list, &list_state);
if (result)
- return_VALUE(result);
+ return result;
if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
device->power.state = i;
- return_VALUE(0);
+ return 0;
}
}
device->power.state = ACPI_STATE_D3;
- return_VALUE(0);
+ return 0;
}
int acpi_power_transition(struct acpi_device *device, int state)
@@ -400,14 +385,13 @@ int acpi_power_transition(struct acpi_device *device, int state)
struct acpi_handle_list *tl = NULL; /* Target Resources */
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_power_transition");
if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if ((device->power.state < ACPI_STATE_D0)
|| (device->power.state > ACPI_STATE_D3))
- return_VALUE(-ENODEV);
+ return -ENODEV;
cl = &device->power.states[device->power.state].resources;
tl = &device->power.states[state].resources;
@@ -444,11 +428,10 @@ int acpi_power_transition(struct acpi_device *device, int state)
device->power.state = state;
end:
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Error transitioning device [%s] to D%d\n",
- device->pnp.bus_id, state));
+ printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n",
+ device->pnp.bus_id, state);
- return_VALUE(result);
+ return result;
}
/* --------------------------------------------------------------------------
@@ -461,7 +444,6 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_power_resource *resource = NULL;
- ACPI_FUNCTION_TRACE("acpi_power_seq_show");
resource = (struct acpi_power_resource *)seq->private;
@@ -488,7 +470,7 @@ static int acpi_power_seq_show(struct seq_file *seq, void *offset)
resource->order, resource->references);
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_power_open_fs(struct inode *inode, struct file *file)
@@ -500,36 +482,32 @@ static int acpi_power_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_power_add_fs");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_power_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
/* 'status' [R] */
entry = create_proc_entry(ACPI_POWER_FILE_STATUS,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_POWER_FILE_STATUS));
+ return -EIO;
else {
entry->proc_fops = &acpi_power_fops;
entry->data = acpi_driver_data(device);
}
- return_VALUE(0);
+ return 0;
}
static int acpi_power_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_power_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_POWER_FILE_STATUS,
@@ -538,7 +516,7 @@ static int acpi_power_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -553,24 +531,23 @@ static int acpi_power_add(struct acpi_device *device)
union acpi_object acpi_object;
struct acpi_buffer buffer = { sizeof(acpi_object), &acpi_object };
- ACPI_FUNCTION_TRACE("acpi_power_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
resource = kmalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
if (!resource)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(resource, 0, sizeof(struct acpi_power_resource));
- resource->handle = device->handle;
+ resource->device = device;
strcpy(resource->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
acpi_driver_data(device) = resource;
/* Evalute the object to get the system level and resource order. */
- status = acpi_evaluate_object(resource->handle, NULL, NULL, &buffer);
+ status = acpi_evaluate_object(device->handle, NULL, NULL, &buffer);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
@@ -605,17 +582,16 @@ static int acpi_power_add(struct acpi_device *device)
if (result)
kfree(resource);
- return_VALUE(result);
+ return result;
}
static int acpi_power_remove(struct acpi_device *device, int type)
{
struct acpi_power_resource *resource = NULL;
- ACPI_FUNCTION_TRACE("acpi_power_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
resource = (struct acpi_power_resource *)acpi_driver_data(device);
@@ -623,31 +599,30 @@ static int acpi_power_remove(struct acpi_device *device, int type)
kfree(resource);
- return_VALUE(0);
+ return 0;
}
static int __init acpi_power_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_power_init");
if (acpi_disabled)
- return_VALUE(0);
+ return 0;
INIT_LIST_HEAD(&acpi_power_resource_list);
acpi_power_dir = proc_mkdir(ACPI_POWER_CLASS, acpi_root_dir);
if (!acpi_power_dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
result = acpi_bus_register_driver(&acpi_power_driver);
if (result < 0) {
remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
subsys_initcall(acpi_power_init);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index decaebb4cbe..b13d64415b7 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -102,7 +102,7 @@ static struct acpi_driver acpi_processor_driver = {
#define INSTALL_NOTIFY_HANDLER 1
#define UNINSTALL_NOTIFY_HANDLER 2
-static struct file_operations acpi_processor_info_fops = {
+static const struct file_operations acpi_processor_info_fops = {
.open = acpi_processor_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -122,10 +122,9 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
u8 value1 = 0;
u8 value2 = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4");
if (!dev)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* Note that 'dev' references the PIIX4 ACPI Controller.
@@ -218,7 +217,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Type-F DMA livelock erratum (C3 disabled)\n"));
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_errata(struct acpi_processor *pr)
@@ -226,10 +225,9 @@ static int acpi_processor_errata(struct acpi_processor *pr)
int result = 0;
struct pci_dev *dev = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_errata");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* PIIX4
@@ -242,7 +240,7 @@ static int acpi_processor_errata(struct acpi_processor *pr)
pci_dev_put(dev);
}
- return_VALUE(result);
+ return result;
}
/* --------------------------------------------------------------------------
@@ -258,10 +256,9 @@ static int acpi_processor_set_pdc(struct acpi_processor *pr)
struct acpi_object_list *pdc_in = pr->pdc;
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
if (!pdc_in)
- return_VALUE(status);
+ return status;
status = acpi_evaluate_object(pr->handle, "_PDC", pdc_in, NULL);
@@ -269,7 +266,7 @@ static int acpi_processor_set_pdc(struct acpi_processor *pr)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Could not evaluate _PDC, using legacy perf. control...\n"));
- return_VALUE(status);
+ return status;
}
/* --------------------------------------------------------------------------
@@ -282,7 +279,6 @@ static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_processor_info_seq_show");
if (!pr)
goto end;
@@ -301,7 +297,7 @@ static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
pr->flags.limit ? "yes" : "no");
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_info_open_fs(struct inode *inode, struct file *file)
@@ -314,13 +310,12 @@ static int acpi_processor_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_processor_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
acpi_device_dir(device)->owner = THIS_MODULE;
@@ -328,9 +323,7 @@ static int acpi_processor_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_INFO));
+ return -EIO;
else {
entry->proc_fops = &acpi_processor_info_fops;
entry->data = acpi_driver_data(device);
@@ -342,9 +335,7 @@ static int acpi_processor_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_THROTTLING));
+ return -EIO;
else {
entry->proc_fops = &acpi_processor_throttling_fops;
entry->data = acpi_driver_data(device);
@@ -356,21 +347,18 @@ static int acpi_processor_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_LIMIT));
+ return -EIO;
else {
entry->proc_fops = &acpi_processor_limit_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_processor_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,
@@ -383,7 +371,7 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* Use the acpiid in MADT to map cpus in case of SMP */
@@ -430,10 +418,9 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
int cpu_index;
static int cpu0_initialized;
- ACPI_FUNCTION_TRACE("acpi_processor_get_info");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (num_online_cpus() > 1)
errata.smp = TRUE;
@@ -459,9 +446,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
*/
status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error evaluating processor object\n"));
- return_VALUE(-ENODEV);
+ printk(KERN_ERR PREFIX "Evaluating processor object\n");
+ return -ENODEV;
}
/*
@@ -490,10 +476,10 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
if (cpu_index == -1) {
if (ACPI_FAILURE
(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error getting cpuindex for acpiid 0x%x\n",
- pr->acpi_id));
- return_VALUE(-ENODEV);
+ printk(KERN_ERR PREFIX
+ "Getting cpuindex for acpiid 0x%x\n",
+ pr->acpi_id);
+ return -ENODEV;
}
}
@@ -503,8 +489,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
if (!object.processor.pblk_address)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
else if (object.processor.pblk_length != 6)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n",
- object.processor.pblk_length));
+ printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n",
+ object.processor.pblk_length);
else {
pr->throttling.address = object.processor.pblk_address;
pr->throttling.duty_offset = acpi_fadt.duty_offset;
@@ -528,7 +514,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
acpi_processor_get_throttling_info(pr);
acpi_processor_get_limit_info(pr);
- return_VALUE(0);
+ return 0;
}
static void *processor_device_array[NR_CPUS];
@@ -539,14 +525,13 @@ static int acpi_processor_start(struct acpi_device *device)
acpi_status status = AE_OK;
struct acpi_processor *pr;
- ACPI_FUNCTION_TRACE("acpi_processor_start");
pr = acpi_driver_data(device);
result = acpi_processor_get_info(pr);
if (result) {
/* Processor is physically not present */
- return_VALUE(0);
+ return 0;
}
BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0));
@@ -560,7 +545,7 @@ static int acpi_processor_start(struct acpi_device *device)
processor_device_array[pr->id] != (void *)device) {
printk(KERN_WARNING "BIOS reported wrong ACPI id"
"for the processor\n");
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
processor_device_array[pr->id] = (void *)device;
@@ -572,10 +557,6 @@ static int acpi_processor_start(struct acpi_device *device)
status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify, pr);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing device notify handler\n"));
- }
/* _PDC call should be done before doing anything else (if reqd.). */
arch_acpi_processor_init_pdc(pr);
@@ -592,7 +573,7 @@ static int acpi_processor_start(struct acpi_device *device)
end:
- return_VALUE(result);
+ return result;
}
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
@@ -600,13 +581,12 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
struct acpi_processor *pr = (struct acpi_processor *)data;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_notify");
if (!pr)
- return_VOID;
+ return;
if (acpi_bus_get_device(pr->handle, &device))
- return_VOID;
+ return;
switch (event) {
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
@@ -624,21 +604,20 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static int acpi_processor_add(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL);
if (!pr)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(pr, 0, sizeof(struct acpi_processor));
pr->handle = device->handle;
@@ -646,7 +625,7 @@ static int acpi_processor_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
acpi_driver_data(device) = pr;
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_remove(struct acpi_device *device, int type)
@@ -654,31 +633,26 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_processor *pr = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
pr = (struct acpi_processor *)acpi_driver_data(device);
if (pr->id >= NR_CPUS) {
kfree(pr);
- return_VALUE(0);
+ return 0;
}
if (type == ACPI_BUS_REMOVAL_EJECT) {
if (acpi_processor_handle_eject(pr))
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
acpi_processor_power_exit(pr, device);
status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify);
- if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
- }
acpi_processor_remove_fs(device);
@@ -686,7 +660,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
kfree(pr);
- return_VALUE(0);
+ return 0;
}
#ifdef CONFIG_ACPI_HOTPLUG_CPU
@@ -701,15 +675,13 @@ static int is_processor_present(acpi_handle handle)
acpi_status status;
unsigned long sta = 0;
- ACPI_FUNCTION_TRACE("is_processor_present");
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Processor Device is not present\n"));
- return_VALUE(0);
+ ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
+ return 0;
}
- return_VALUE(1);
+ return 1;
}
static
@@ -719,30 +691,29 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
struct acpi_device *pdev;
struct acpi_processor *pr;
- ACPI_FUNCTION_TRACE("acpi_processor_device_add");
if (acpi_get_parent(handle, &phandle)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (acpi_bus_get_device(phandle, &pdev)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
acpi_bus_start(*device);
pr = acpi_driver_data(*device);
if (!pr)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
}
- return_VALUE(0);
+ return 0;
}
static void
@@ -752,7 +723,6 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *device = NULL;
int result;
- ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify");
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -767,15 +737,14 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
if (acpi_bus_get_device(handle, &device)) {
result = acpi_processor_device_add(handle, &device);
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to add the device\n"));
+ printk(KERN_ERR PREFIX
+ "Unable to add the device\n");
break;
}
pr = acpi_driver_data(device);
if (!pr) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Driver data is NULL\n"));
+ printk(KERN_ERR PREFIX "Driver data is NULL\n");
break;
}
@@ -788,9 +757,8 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
kobject_uevent(&device->kobj, KOBJ_ONLINE);
} else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device [%s] failed to start\n",
- acpi_device_bid(device)));
+ printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
+ acpi_device_bid(device));
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
@@ -798,15 +766,15 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
"received ACPI_NOTIFY_EJECT_REQUEST\n"));
if (acpi_bus_get_device(handle, &device)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Device don't exist, dropping EJECT\n"));
+ printk(KERN_ERR PREFIX
+ "Device don't exist, dropping EJECT\n");
break;
}
pr = acpi_driver_data(device);
if (!pr) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Driver data is NULL, dropping EJECT\n"));
- return_VOID;
+ printk(KERN_ERR PREFIX
+ "Driver data is NULL, dropping EJECT\n");
+ return;
}
if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
@@ -818,7 +786,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static acpi_status
@@ -857,21 +825,20 @@ processor_walk_namespace_cb(acpi_handle handle,
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu)
{
- ACPI_FUNCTION_TRACE("acpi_processor_hotadd_init");
if (!is_processor_present(handle)) {
- return_VALUE(AE_ERROR);
+ return AE_ERROR;
}
if (acpi_map_lsapic(handle, p_cpu))
- return_VALUE(AE_ERROR);
+ return AE_ERROR;
if (arch_register_cpu(*p_cpu)) {
acpi_unmap_lsapic(*p_cpu);
- return_VALUE(AE_ERROR);
+ return AE_ERROR;
}
- return_VALUE(AE_OK);
+ return AE_OK;
}
static int acpi_processor_handle_eject(struct acpi_processor *pr)
@@ -928,20 +895,19 @@ static int __init acpi_processor_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_init");
memset(&processors, 0, sizeof(processors));
memset(&errata, 0, sizeof(errata));
acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
if (!acpi_processor_dir)
- return_VALUE(0);
+ return 0;
acpi_processor_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_processor_driver);
if (result < 0) {
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- return_VALUE(0);
+ return 0;
}
acpi_processor_install_hotplug_notify();
@@ -950,12 +916,11 @@ static int __init acpi_processor_init(void)
acpi_processor_ppc_init();
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_processor_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_processor_exit");
acpi_processor_ppc_exit();
@@ -967,7 +932,7 @@ static void __exit acpi_processor_exit(void)
remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
module_init(acpi_processor_init);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 3b97a5eae9e..71066066d62 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
- * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004, 2005 Dominik Brodowski <linux@brodo.de>
* Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
* - Added processor hotplug support
* Copyright (C) 2005 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
@@ -99,6 +99,9 @@ static int set_max_cstate(struct dmi_system_id *id)
static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
{ set_max_cstate, "IBM ThinkPad R40e", {
DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
+ DMI_MATCH(DMI_BIOS_VERSION,"1SET70WW")}, (void *)1},
+ { set_max_cstate, "IBM ThinkPad R40e", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1},
{ set_max_cstate, "IBM ThinkPad R40e", {
DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
@@ -206,11 +209,11 @@ acpi_processor_power_activate(struct acpi_processor *pr,
static void acpi_safe_halt(void)
{
- clear_thread_flag(TIF_POLLING_NRFLAG);
+ current_thread_info()->status &= ~TS_POLLING;
smp_mb__after_clear_bit();
if (!need_resched())
safe_halt();
- set_thread_flag(TIF_POLLING_NRFLAG);
+ current_thread_info()->status |= TS_POLLING;
}
static atomic_t c3_cpu_count;
@@ -261,21 +264,15 @@ static void acpi_processor_idle(void)
u32 bm_status = 0;
unsigned long diff = jiffies - pr->power.bm_check_timestamp;
- if (diff > 32)
- diff = 32;
+ if (diff > 31)
+ diff = 31;
- while (diff) {
- /* if we didn't get called, assume there was busmaster activity */
- diff--;
- if (diff)
- pr->power.bm_activity |= 0x1;
- pr->power.bm_activity <<= 1;
- }
+ pr->power.bm_activity <<= diff;
acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
&bm_status, ACPI_MTX_DO_NOT_LOCK);
if (bm_status) {
- pr->power.bm_activity++;
+ pr->power.bm_activity |= 0x1;
acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
1, ACPI_MTX_DO_NOT_LOCK);
}
@@ -287,16 +284,16 @@ static void acpi_processor_idle(void)
else if (errata.piix4.bmisx) {
if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
|| (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
- pr->power.bm_activity++;
+ pr->power.bm_activity |= 0x1;
}
pr->power.bm_check_timestamp = jiffies;
/*
- * Apply bus mastering demotion policy. Automatically demote
+ * If bus mastering is or was active this jiffy, demote
* to avoid a faulty transition. Note that the processor
* won't enter a low-power state during this call (to this
- * funciton) but should upon the next.
+ * function) but should upon the next.
*
* TBD: A better policy might be to fallback to the demotion
* state (use it for this quantum only) istead of
@@ -304,7 +301,8 @@ static void acpi_processor_idle(void)
* qualification. This may, however, introduce DMA
* issues (e.g. floppy DMA transfer overrun/underrun).
*/
- if (pr->power.bm_activity & cx->demotion.threshold.bm) {
+ if ((pr->power.bm_activity & 0x1) &&
+ cx->demotion.threshold.bm) {
local_irq_enable();
next_state = cx->demotion.state;
goto end;
@@ -322,18 +320,16 @@ static void acpi_processor_idle(void)
cx = &pr->power.states[ACPI_STATE_C1];
#endif
- cx->usage++;
-
/*
* Sleep:
* ------
* Invoke the current Cx state to put the processor to sleep.
*/
if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {
- clear_thread_flag(TIF_POLLING_NRFLAG);
+ current_thread_info()->status &= ~TS_POLLING;
smp_mb__after_clear_bit();
if (need_resched()) {
- set_thread_flag(TIF_POLLING_NRFLAG);
+ current_thread_info()->status |= TS_POLLING;
local_irq_enable();
return;
}
@@ -365,13 +361,20 @@ static void acpi_processor_idle(void)
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C2 */
inb(cx->address);
- /* Dummy op - must do something useless after P_LVL2 read */
+ /* Dummy wait op - must do something useless after P_LVL2 read
+ because chipsets cannot guarantee that STPCLK# signal
+ gets asserted in time to freeze execution properly. */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+
+#ifdef CONFIG_GENERIC_TIME
+ /* TSC halts in C2, so notify users */
+ mark_tsc_unstable();
+#endif
/* Re-enable interrupts */
local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
+ current_thread_info()->status |= TS_POLLING;
/* Compute time (ticks) that we were actually asleep */
sleep_ticks =
ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
@@ -398,7 +401,7 @@ static void acpi_processor_idle(void)
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C3 */
inb(cx->address);
- /* Dummy op - must do something useless after P_LVL3 read */
+ /* Dummy wait op (see above) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
@@ -409,9 +412,13 @@ static void acpi_processor_idle(void)
ACPI_MTX_DO_NOT_LOCK);
}
+#ifdef CONFIG_GENERIC_TIME
+ /* TSC halts in C3, so notify users */
+ mark_tsc_unstable();
+#endif
/* Re-enable interrupts */
local_irq_enable();
- set_thread_flag(TIF_POLLING_NRFLAG);
+ current_thread_info()->status |= TS_POLLING;
/* Compute time (ticks) that we were actually asleep */
sleep_ticks =
ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
@@ -421,6 +428,9 @@ static void acpi_processor_idle(void)
local_irq_enable();
return;
}
+ cx->usage++;
+ if ((cx->type != ACPI_STATE_C1) && (sleep_ticks > 0))
+ cx->time += sleep_ticks;
next_state = pr->power.state;
@@ -508,10 +518,9 @@ static int acpi_processor_set_power_policy(struct acpi_processor *pr)
struct acpi_processor_cx *higher = NULL;
struct acpi_processor_cx *cx;
- ACPI_FUNCTION_TRACE("acpi_processor_set_power_policy");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* This function sets the default Cx state policy (OS idle handler).
@@ -535,7 +544,7 @@ static int acpi_processor_set_power_policy(struct acpi_processor *pr)
}
if (!state_is_set)
- return_VALUE(-ENODEV);
+ return -ENODEV;
/* demotion */
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
@@ -574,18 +583,17 @@ static int acpi_processor_set_power_policy(struct acpi_processor *pr)
higher = cx;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
{
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_fadt");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!pr->pblk)
- return_VALUE(-ENODEV);
+ return -ENODEV;
/* if info is obtained from pblk/fadt, type equals state */
pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;
@@ -597,7 +605,7 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
* an SMP system.
*/
if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up)
- return_VALUE(-ENODEV);
+ return -ENODEV;
#endif
/* determine C2 and C3 address from pblk */
@@ -613,12 +621,11 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C2].address,
pr->power.states[ACPI_STATE_C3].address));
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
{
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_default_c1");
/* Zero initialize all the C-states info. */
memset(pr->power.states, 0, sizeof(pr->power.states));
@@ -631,7 +638,7 @@ static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
pr->power.states[ACPI_STATE_C0].valid = 1;
pr->power.states[ACPI_STATE_C1].valid = 1;
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
@@ -643,10 +650,9 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cst;
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_cst");
if (nocst)
- return_VALUE(-ENODEV);
+ return -ENODEV;
current_count = 1;
@@ -658,15 +664,14 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _CST, giving up\n"));
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
cst = (union acpi_object *)buffer.pointer;
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "not enough elements in _CST\n"));
+ printk(KERN_ERR PREFIX "not enough elements in _CST\n");
status = -EFAULT;
goto end;
}
@@ -675,8 +680,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* Validate number of power states. */
if (count < 1 || count != cst->package.count - 1) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "count given by _CST is not valid\n"));
+ printk(KERN_ERR PREFIX "count given by _CST is not valid\n");
status = -EFAULT;
goto end;
}
@@ -764,17 +768,16 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
status = -EFAULT;
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
- return_VALUE(status);
+ return status;
}
static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
{
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c2");
if (!cx->address)
- return_VOID;
+ return;
/*
* C2 latency must be less than or equal to 100
@@ -783,7 +786,7 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"latency too large [%d]\n", cx->latency));
- return_VOID;
+ return;
}
/*
@@ -793,7 +796,7 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
cx->valid = 1;
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
- return_VOID;
+ return;
}
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
@@ -801,10 +804,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
{
static int bm_check_flag;
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c3");
if (!cx->address)
- return_VOID;
+ return;
/*
* C3 latency must be less than or equal to 1000
@@ -813,7 +815,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"latency too large [%d]\n", cx->latency));
- return_VOID;
+ return;
}
/*
@@ -826,7 +828,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
else if (errata.piix4.fdma) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C3 not supported on PIIX4 with Type-F DMA\n"));
- return_VOID;
+ return;
}
/* All the logic here assumes flags.bm_check is same across all CPUs */
@@ -843,7 +845,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
if (!pr->flags.bm_control) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C3 support requires bus mastering control\n"));
- return_VOID;
+ return;
}
} else {
/*
@@ -854,7 +856,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Cache invalidation should work properly"
" for C3 to be enabled on SMP systems\n"));
- return_VOID;
+ return;
}
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
0, ACPI_MTX_DO_NOT_LOCK);
@@ -869,7 +871,7 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
cx->valid = 1;
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
- return_VOID;
+ return;
}
static int acpi_processor_power_verify(struct acpi_processor *pr)
@@ -928,7 +930,6 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
unsigned int i;
int result;
- ACPI_FUNCTION_TRACE("acpi_processor_get_power_info");
/* NOTE: the idle thread may not be running while calling
* this function */
@@ -951,7 +952,7 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
*/
result = acpi_processor_set_power_policy(pr);
if (result)
- return_VALUE(result);
+ return result;
/*
* if one state of type C2 or C3 is available, mark this
@@ -965,24 +966,23 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
}
}
- return_VALUE(0);
+ return 0;
}
int acpi_processor_cst_has_changed(struct acpi_processor *pr)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_cst_has_changed");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (nocst) {
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (!pr->flags.power_setup_done)
- return_VALUE(-ENODEV);
+ return -ENODEV;
/* Fall back to the default idle loop */
pm_idle = pm_idle_save;
@@ -993,7 +993,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr)
if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
pm_idle = acpi_processor_idle;
- return_VALUE(result);
+ return result;
}
/* proc interface */
@@ -1003,7 +1003,6 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
unsigned int i;
- ACPI_FUNCTION_TRACE("acpi_processor_power_seq_show");
if (!pr)
goto end;
@@ -1055,13 +1054,14 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
else
seq_puts(seq, "demotion[--] ");
- seq_printf(seq, "latency[%03d] usage[%08d]\n",
+ seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
pr->power.states[i].latency,
- pr->power.states[i].usage);
+ pr->power.states[i].usage,
+ pr->power.states[i].time);
}
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_power_open_fs(struct inode *inode, struct file *file)
@@ -1070,7 +1070,7 @@ static int acpi_processor_power_open_fs(struct inode *inode, struct file *file)
PDE(inode)->data);
}
-static struct file_operations acpi_processor_power_fops = {
+static const struct file_operations acpi_processor_power_fops = {
.open = acpi_processor_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -1085,7 +1085,6 @@ int acpi_processor_power_init(struct acpi_processor *pr,
struct proc_dir_entry *entry = NULL;
unsigned int i;
- ACPI_FUNCTION_TRACE("acpi_processor_power_init");
if (!first_run) {
dmi_check_system(processor_power_dmi_table);
@@ -1097,14 +1096,14 @@ int acpi_processor_power_init(struct acpi_processor *pr,
}
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (acpi_fadt.cst_cnt && !nocst) {
status =
acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Notifying BIOS of _CST ability failed\n"));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Notifying BIOS of _CST ability failed"));
}
}
@@ -1133,9 +1132,7 @@ int acpi_processor_power_init(struct acpi_processor *pr,
entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_POWER));
+ return -EIO;
else {
entry->proc_fops = &acpi_processor_power_fops;
entry->data = acpi_driver_data(device);
@@ -1144,13 +1141,12 @@ int acpi_processor_power_init(struct acpi_processor *pr,
pr->flags.power_setup_done = 1;
- return_VALUE(0);
+ return 0;
}
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_processor_power_exit");
pr->flags.power_setup_done = 0;
@@ -1170,5 +1166,5 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
cpu_idle_wait();
}
- return_VALUE(0);
+ return 0;
}
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 41aaaba74b1..7ba5e49ab30 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -108,10 +108,9 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
acpi_status status = 0;
unsigned long ppc = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_get_platform_limit");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/*
* _PPC indicates the maximum state currently supported by the platform
@@ -123,13 +122,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
acpi_processor_ppc_status |= PPC_IN_USE;
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PPC"));
+ return -ENODEV;
}
pr->performance_platform_limit = (int)ppc;
- return_VALUE(0);
+ return 0;
}
int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
@@ -168,18 +167,17 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
union acpi_object *pct = NULL;
union acpi_object obj = { 0 };
- ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control");
status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PCT"));
+ return -ENODEV;
}
pct = (union acpi_object *)buffer.pointer;
if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
|| (pct->package.count != 2)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n"));
+ printk(KERN_ERR PREFIX "Invalid _PCT data\n");
result = -EFAULT;
goto end;
}
@@ -193,8 +191,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_pct_register))
|| (obj.buffer.pointer == NULL)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid _PCT data (control_register)\n"));
+ printk(KERN_ERR PREFIX "Invalid _PCT data (control_register)\n");
result = -EFAULT;
goto end;
}
@@ -210,8 +207,7 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_pct_register))
|| (obj.buffer.pointer == NULL)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid _PCT data (status_register)\n"));
+ printk(KERN_ERR PREFIX "Invalid _PCT data (status_register)\n");
result = -EFAULT;
goto end;
}
@@ -220,9 +216,9 @@ static int acpi_processor_get_performance_control(struct acpi_processor *pr)
sizeof(struct acpi_pct_register));
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
- return_VALUE(result);
+ return result;
}
static int acpi_processor_get_performance_states(struct acpi_processor *pr)
@@ -235,17 +231,16 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
union acpi_object *pss = NULL;
int i;
- ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states");
status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PSS"));
+ return -ENODEV;
}
pss = (union acpi_object *)buffer.pointer;
if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
+ printk(KERN_ERR PREFIX "Invalid _PSS data\n");
result = -EFAULT;
goto end;
}
@@ -274,8 +269,7 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
status = acpi_extract_package(&(pss->package.elements[i]),
&format, &state);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid _PSS data\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid _PSS data"));
result = -EFAULT;
kfree(pr->performance->states);
goto end;
@@ -291,8 +285,8 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
(u32) px->control, (u32) px->status));
if (!px->core_frequency) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid _PSS data: freq is zero\n"));
+ printk(KERN_ERR PREFIX
+ "Invalid _PSS data: freq is zero\n");
result = -EFAULT;
kfree(pr->performance->states);
goto end;
@@ -300,9 +294,9 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
}
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
- return_VALUE(result);
+ return result;
}
static int acpi_processor_get_performance_info(struct acpi_processor *pr)
@@ -311,31 +305,30 @@ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
acpi_status status = AE_OK;
acpi_handle handle = NULL;
- ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info");
if (!pr || !pr->performance || !pr->handle)
- return_VALUE(-EINVAL);
+ return -EINVAL;
status = acpi_get_handle(pr->handle, "_PCT", &handle);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"ACPI-based processor performance control unavailable\n"));
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
result = acpi_processor_get_performance_control(pr);
if (result)
- return_VALUE(result);
+ return result;
result = acpi_processor_get_performance_states(pr);
if (result)
- return_VALUE(result);
+ return result;
result = acpi_processor_get_platform_limit(pr);
if (result)
- return_VALUE(result);
+ return result;
- return_VALUE(0);
+ return 0;
}
int acpi_processor_notify_smm(struct module *calling_module)
@@ -343,13 +336,12 @@ int acpi_processor_notify_smm(struct module *calling_module)
acpi_status status;
static int is_done = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_notify_smm");
if (!(acpi_processor_ppc_status & PPC_REGISTERED))
- return_VALUE(-EBUSY);
+ return -EBUSY;
if (!try_module_get(calling_module))
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* is_done is set to negative if an error occured,
* and to postitive if _no_ error occured, but SMM
@@ -358,10 +350,10 @@ int acpi_processor_notify_smm(struct module *calling_module)
*/
if (is_done > 0) {
module_put(calling_module);
- return_VALUE(0);
+ return 0;
} else if (is_done < 0) {
module_put(calling_module);
- return_VALUE(is_done);
+ return is_done;
}
is_done = -EIO;
@@ -370,7 +362,7 @@ int acpi_processor_notify_smm(struct module *calling_module)
if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n"));
module_put(calling_module);
- return_VALUE(0);
+ return 0;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -387,12 +379,12 @@ int acpi_processor_notify_smm(struct module *calling_module)
status = acpi_os_write_port(acpi_fadt.smi_cmd,
(u32) acpi_fadt.pstate_cnt, 8);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Failed to write pstate_cnt [0x%x] to "
- "smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt,
- acpi_fadt.smi_cmd));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Failed to write pstate_cnt [0x%x] to "
+ "smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
+ acpi_fadt.smi_cmd));
module_put(calling_module);
- return_VALUE(status);
+ return status;
}
/* Success. If there's no _PPC, we need to fear nothing, so
@@ -402,7 +394,7 @@ int acpi_processor_notify_smm(struct module *calling_module)
if (!(acpi_processor_ppc_status & PPC_IN_USE))
module_put(calling_module);
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_processor_notify_smm);
@@ -423,7 +415,6 @@ static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
int i;
- ACPI_FUNCTION_TRACE("acpi_processor_perf_seq_show");
if (!pr)
goto end;
@@ -447,7 +438,7 @@ static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
(u32) pr->performance->states[i].transition_latency);
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
@@ -469,23 +460,22 @@ acpi_processor_write_performance(struct file *file,
unsigned int new_state = 0;
struct cpufreq_policy policy;
- ACPI_FUNCTION_TRACE("acpi_processor_write_performance");
if (!pr || (count > sizeof(state_string) - 1))
- return_VALUE(-EINVAL);
+ return -EINVAL;
perf = pr->performance;
if (!perf)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(state_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
state_string[count] = '\0';
new_state = simple_strtoul(state_string, NULL, 0);
if (new_state >= perf->state_count)
- return_VALUE(-EINVAL);
+ return -EINVAL;
cpufreq_get_policy(&policy, pr->id);
@@ -495,9 +485,9 @@ acpi_processor_write_performance(struct file *file,
result = cpufreq_set_policy(&policy);
if (result)
- return_VALUE(result);
+ return result;
- return_VALUE(count);
+ return count;
}
static void acpi_cpufreq_add_file(struct acpi_processor *pr)
@@ -505,42 +495,36 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr)
struct proc_dir_entry *entry = NULL;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile");
if (acpi_bus_get_device(pr->handle, &device))
- return_VOID;
+ return;
/* add file 'performance' [R/W] */
entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
- if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_PROCESSOR_FILE_PERFORMANCE));
- else {
+ if (entry){
acpi_processor_perf_fops.write = acpi_processor_write_performance;
entry->proc_fops = &acpi_processor_perf_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VOID;
+ return;
}
static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
{
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile");
if (acpi_bus_get_device(pr->handle, &device))
- return_VOID;
+ return;
/* remove file 'performance' */
remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
acpi_device_dir(device));
- return_VOID;
+ return;
}
#else
@@ -608,7 +592,7 @@ static int acpi_processor_get_psd(struct acpi_processor *pr)
}
end:
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
return result;
}
@@ -698,12 +682,12 @@ int acpi_processor_preregister_performance(
/* Validate the Domain info */
count_target = pdomain->num_processors;
count = 1;
- if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL ||
- pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) {
+ if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
- } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) {
+ else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
+ pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW;
+ else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
- }
for_each_possible_cpu(j) {
if (i == j)
@@ -784,22 +768,21 @@ acpi_processor_register_performance(struct acpi_processor_performance
{
struct acpi_processor *pr;
- ACPI_FUNCTION_TRACE("acpi_processor_register_performance");
if (!(acpi_processor_ppc_status & PPC_REGISTERED))
- return_VALUE(-EINVAL);
+ return -EINVAL;
mutex_lock(&performance_mutex);
pr = processors[cpu];
if (!pr) {
mutex_unlock(&performance_mutex);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
if (pr->performance) {
mutex_unlock(&performance_mutex);
- return_VALUE(-EBUSY);
+ return -EBUSY;
}
WARN_ON(!performance);
@@ -809,13 +792,13 @@ acpi_processor_register_performance(struct acpi_processor_performance
if (acpi_processor_get_performance_info(pr)) {
pr->performance = NULL;
mutex_unlock(&performance_mutex);
- return_VALUE(-EIO);
+ return -EIO;
}
acpi_cpufreq_add_file(pr);
mutex_unlock(&performance_mutex);
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_processor_register_performance);
@@ -826,14 +809,13 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
{
struct acpi_processor *pr;
- ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance");
mutex_lock(&performance_mutex);
pr = processors[cpu];
if (!pr) {
mutex_unlock(&performance_mutex);
- return_VOID;
+ return;
}
if (pr->performance)
@@ -844,7 +826,7 @@ acpi_processor_unregister_performance(struct acpi_processor_performance
mutex_unlock(&performance_mutex);
- return_VOID;
+ return;
}
EXPORT_SYMBOL(acpi_processor_unregister_performance);
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index f99ad05cd6a..ef5e0f6efdb 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -54,13 +54,12 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
u16 px = 0;
u16 tx = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_apply_limit");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!pr->flags.limit)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (pr->flags.throttling) {
if (pr->limit.user.tx > tx)
@@ -82,9 +81,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
end:
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
+ printk(KERN_ERR PREFIX "Unable to set limit\n");
- return_VALUE(result);
+ return result;
}
#ifdef CONFIG_CPU_FREQ
@@ -200,19 +199,18 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type)
struct acpi_device *device = NULL;
int tx = 0, max_tx_px = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit");
if ((type < ACPI_PROCESSOR_LIMIT_NONE)
|| (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
- return_VALUE(-EINVAL);
+ return -EINVAL;
result = acpi_bus_get_device(handle, &device);
if (result)
- return_VALUE(result);
+ return result;
pr = (struct acpi_processor *)acpi_driver_data(device);
if (!pr)
- return_VALUE(-ENODEV);
+ return -ENODEV;
/* Thermal limits are always relative to the current Px/Tx state. */
if (pr->flags.throttling)
@@ -289,30 +287,28 @@ int acpi_processor_set_thermal_limit(acpi_handle handle, int type)
result = acpi_processor_apply_limit(pr);
if (result)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to set thermal limit\n"));
+ printk(KERN_ERR PREFIX "Unable to set thermal limit\n");
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
pr->limit.thermal.px, pr->limit.thermal.tx));
} else
result = 0;
if (max_tx_px)
- return_VALUE(1);
+ return 1;
else
- return_VALUE(result);
+ return result;
}
int acpi_processor_get_limit_info(struct acpi_processor *pr)
{
- ACPI_FUNCTION_TRACE("acpi_processor_get_limit_info");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (pr->flags.throttling)
pr->flags.limit = 1;
- return_VALUE(0);
+ return 0;
}
/* /proc interface */
@@ -321,7 +317,6 @@ static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_processor *pr = (struct acpi_processor *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_processor_limit_seq_show");
if (!pr)
goto end;
@@ -339,7 +334,7 @@ static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
pr->limit.thermal.px, pr->limit.thermal.tx);
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file)
@@ -359,36 +354,33 @@ static ssize_t acpi_processor_write_limit(struct file * file,
int px = 0;
int tx = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_write_limit");
if (!pr || (count > sizeof(limit_string) - 1)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
- return_VALUE(-EINVAL);
+ return -EINVAL;
}
if (copy_from_user(limit_string, buffer, count)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
- return_VALUE(-EFAULT);
+ return -EFAULT;
}
limit_string[count] = '\0';
if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "Invalid data format\n");
+ return -EINVAL;
}
if (pr->flags.throttling) {
if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n"));
- return_VALUE(-EINVAL);
+ printk(KERN_ERR PREFIX "Invalid tx\n");
+ return -EINVAL;
}
pr->limit.user.tx = tx;
}
result = acpi_processor_apply_limit(pr);
- return_VALUE(count);
+ return count;
}
struct file_operations acpi_processor_limit_fops = {
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index b966549ec00..d044ec519db 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -55,13 +55,12 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
u32 duty_mask = 0;
u32 duty_value = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_get_throttling");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!pr->flags.throttling)
- return_VALUE(-ENODEV);
+ return -ENODEV;
pr->throttling.state = 0;
@@ -93,7 +92,7 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
"Throttling state is T%d (%d%% throttling applied)\n",
state, pr->throttling.states[state].performance));
- return_VALUE(0);
+ return 0;
}
int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
@@ -102,19 +101,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
u32 duty_mask = 0;
u32 duty_value = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_set_throttling");
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!pr->flags.throttling)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (state == pr->throttling.state)
- return_VALUE(0);
+ return 0;
/*
* Calculate the duty_value and duty_mask.
@@ -165,7 +163,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
(pr->throttling.states[state].performance ? pr->
throttling.states[state].performance / 10 : 0)));
- return_VALUE(0);
+ return 0;
}
int acpi_processor_get_throttling_info(struct acpi_processor *pr)
@@ -174,7 +172,6 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
int step = 0;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_get_throttling_info");
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@@ -183,21 +180,21 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
pr->throttling.duty_width));
if (!pr)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* TBD: Support ACPI 2.0 objects */
if (!pr->throttling.address) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
- return_VALUE(0);
+ return 0;
} else if (!pr->throttling.duty_width) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
- return_VALUE(0);
+ return 0;
}
/* TBD: Support duty_cycle values that span bit 4. */
else if ((pr->throttling.duty_offset + pr->throttling.duty_width) > 4) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "duty_cycle spans bit 4\n"));
- return_VALUE(0);
+ printk(KERN_WARNING PREFIX "duty_cycle spans bit 4\n");
+ return 0;
}
/*
@@ -208,7 +205,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
if (errata.piix4.throttle) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling not supported on PIIX4 A- or B-step\n"));
- return_VALUE(0);
+ return 0;
}
pr->throttling.state_count = 1 << acpi_fadt.duty_width;
@@ -254,7 +251,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
if (result)
pr->flags.throttling = 0;
- return_VALUE(result);
+ return result;
}
/* proc interface */
@@ -266,7 +263,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
int i = 0;
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_processor_throttling_seq_show");
if (!pr)
goto end;
@@ -296,7 +292,7 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
throttling.states[i].performance / 10 : 0));
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_processor_throttling_open_fs(struct inode *inode,
@@ -315,13 +311,12 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
struct acpi_processor *pr = (struct acpi_processor *)m->private;
char state_string[12] = { '\0' };
- ACPI_FUNCTION_TRACE("acpi_processor_write_throttling");
if (!pr || (count > sizeof(state_string) - 1))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(state_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
state_string[count] = '\0';
@@ -329,9 +324,9 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
simple_strtoul(state_string,
NULL, 0));
if (result)
- return_VALUE(result);
+ return result;
- return_VALUE(count);
+ return count;
}
struct file_operations acpi_processor_throttling_fops = {
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
new file mode 100644
index 00000000000..62bef0b3b61
--- /dev/null
+++ b/drivers/acpi/sbs.c
@@ -0,0 +1,1769 @@
+/*
+ * acpi_sbs.c - ACPI Smart Battery System Driver ($Revision: 1.16 $)
+ *
+ * Copyright (c) 2005 Rich Townsend <rhdt@bartol.udel.edu>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+
+#include "i2c_ec.h"
+
+#define DEF_CAPACITY_UNIT 3
+#define MAH_CAPACITY_UNIT 1
+#define MWH_CAPACITY_UNIT 2
+#define CAPACITY_UNIT DEF_CAPACITY_UNIT
+
+#define REQUEST_UPDATE_MODE 1
+#define QUEUE_UPDATE_MODE 2
+
+#define DATA_TYPE_COMMON 0
+#define DATA_TYPE_INFO 1
+#define DATA_TYPE_STATE 2
+#define DATA_TYPE_ALARM 3
+#define DATA_TYPE_AC_STATE 4
+
+extern struct proc_dir_entry *acpi_lock_ac_dir(void);
+extern struct proc_dir_entry *acpi_lock_battery_dir(void);
+extern void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir);
+extern void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
+
+#define ACPI_SBS_COMPONENT 0x00080000
+#define ACPI_SBS_CLASS "sbs"
+#define ACPI_AC_CLASS "ac_adapter"
+#define ACPI_BATTERY_CLASS "battery"
+#define ACPI_SBS_HID "ACPI0002"
+#define ACPI_SBS_DRIVER_NAME "ACPI Smart Battery System Driver"
+#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
+#define ACPI_SBS_FILE_INFO "info"
+#define ACPI_SBS_FILE_STATE "state"
+#define ACPI_SBS_FILE_ALARM "alarm"
+#define ACPI_BATTERY_DIR_NAME "BAT%i"
+#define ACPI_AC_DIR_NAME "AC0"
+#define ACPI_SBC_SMBUS_ADDR 0x9
+#define ACPI_SBSM_SMBUS_ADDR 0xa
+#define ACPI_SB_SMBUS_ADDR 0xb
+#define ACPI_SBS_AC_NOTIFY_STATUS 0x80
+#define ACPI_SBS_BATTERY_NOTIFY_STATUS 0x80
+#define ACPI_SBS_BATTERY_NOTIFY_INFO 0x81
+
+#define _COMPONENT ACPI_SBS_COMPONENT
+
+#define MAX_SBS_BAT 4
+#define MAX_SMBUS_ERR 1
+
+ACPI_MODULE_NAME("acpi_sbs");
+
+MODULE_AUTHOR("Rich Townsend");
+MODULE_DESCRIPTION("Smart Battery System ACPI interface driver");
+MODULE_LICENSE("GPL");
+
+static struct semaphore sbs_sem;
+
+#define UPDATE_MODE QUEUE_UPDATE_MODE
+/* REQUEST_UPDATE_MODE QUEUE_UPDATE_MODE */
+#define UPDATE_INFO_MODE 0
+#define UPDATE_TIME 60
+#define UPDATE_TIME2 0
+
+static int capacity_mode = CAPACITY_UNIT;
+static int update_mode = UPDATE_MODE;
+static int update_info_mode = UPDATE_INFO_MODE;
+static int update_time = UPDATE_TIME;
+static int update_time2 = UPDATE_TIME2;
+
+module_param(capacity_mode, int, CAPACITY_UNIT);
+module_param(update_mode, int, UPDATE_MODE);
+module_param(update_info_mode, int, UPDATE_INFO_MODE);
+module_param(update_time, int, UPDATE_TIME);
+module_param(update_time2, int, UPDATE_TIME2);
+
+static int acpi_sbs_add(struct acpi_device *device);
+static int acpi_sbs_remove(struct acpi_device *device, int type);
+static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus);
+static void acpi_sbs_update_queue(void *data);
+
+static struct acpi_driver acpi_sbs_driver = {
+ .name = ACPI_SBS_DRIVER_NAME,
+ .class = ACPI_SBS_CLASS,
+ .ids = ACPI_SBS_HID,
+ .ops = {
+ .add = acpi_sbs_add,
+ .remove = acpi_sbs_remove,
+ },
+};
+
+struct acpi_battery_info {
+ int capacity_mode;
+ s16 full_charge_capacity;
+ s16 design_capacity;
+ s16 design_voltage;
+ int vscale;
+ int ipscale;
+ s16 serial_number;
+ char manufacturer_name[I2C_SMBUS_BLOCK_MAX + 3];
+ char device_name[I2C_SMBUS_BLOCK_MAX + 3];
+ char device_chemistry[I2C_SMBUS_BLOCK_MAX + 3];
+};
+
+struct acpi_battery_state {
+ s16 voltage;
+ s16 amperage;
+ s16 remaining_capacity;
+ s16 average_time_to_empty;
+ s16 average_time_to_full;
+ s16 battery_status;
+};
+
+struct acpi_battery_alarm {
+ s16 remaining_capacity;
+};
+
+struct acpi_battery {
+ int alive;
+ int battery_present;
+ int id;
+ int init_state;
+ struct acpi_sbs *sbs;
+ struct acpi_battery_info info;
+ struct acpi_battery_state state;
+ struct acpi_battery_alarm alarm;
+ struct proc_dir_entry *battery_entry;
+};
+
+struct acpi_sbs {
+ acpi_handle handle;
+ struct acpi_device *device;
+ struct acpi_ec_smbus *smbus;
+ int sbsm_present;
+ int sbsm_batteries_supported;
+ int ac_present;
+ struct proc_dir_entry *ac_entry;
+ struct acpi_battery battery[MAX_SBS_BAT];
+ int update_info_mode;
+ int zombie;
+ int update_time;
+ int update_time2;
+ struct timer_list update_timer;
+};
+
+static void acpi_update_delay(struct acpi_sbs *sbs);
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type);
+
+/* --------------------------------------------------------------------------
+ SMBus Communication
+ -------------------------------------------------------------------------- */
+
+static void acpi_battery_smbus_err_handler(struct acpi_ec_smbus *smbus)
+{
+ union i2c_smbus_data data;
+ int result = 0;
+ char *err_str;
+ int err_number;
+
+ data.word = 0;
+
+ result = smbus->adapter.algo->
+ smbus_xfer(&smbus->adapter,
+ ACPI_SB_SMBUS_ADDR,
+ 0, I2C_SMBUS_READ, 0x16, I2C_SMBUS_BLOCK_DATA, &data);
+
+ err_number = (data.word & 0x000f);
+
+ switch (data.word & 0x000f) {
+ case 0x0000:
+ err_str = "unexpected bus error";
+ break;
+ case 0x0001:
+ err_str = "busy";
+ break;
+ case 0x0002:
+ err_str = "reserved command";
+ break;
+ case 0x0003:
+ err_str = "unsupported command";
+ break;
+ case 0x0004:
+ err_str = "access denied";
+ break;
+ case 0x0005:
+ err_str = "overflow/underflow";
+ break;
+ case 0x0006:
+ err_str = "bad size";
+ break;
+ case 0x0007:
+ err_str = "unknown error";
+ break;
+ default:
+ err_str = "unrecognized error";
+ }
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "%s: ret %i, err %i\n", err_str, result, err_number));
+}
+
+static int
+acpi_sbs_smbus_read_word(struct acpi_ec_smbus *smbus, int addr, int func,
+ u16 * word,
+ void (*err_handler) (struct acpi_ec_smbus * smbus))
+{
+ union i2c_smbus_data data;
+ int result = 0;
+ int i;
+
+ if (err_handler == NULL) {
+ err_handler = acpi_battery_smbus_err_handler;
+ }
+
+ for (i = 0; i < MAX_SMBUS_ERR; i++) {
+ result =
+ smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
+ I2C_SMBUS_READ, func,
+ I2C_SMBUS_WORD_DATA, &data);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
+ i));
+ if (err_handler) {
+ err_handler(smbus);
+ }
+ } else {
+ *word = data.word;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static int
+acpi_sbs_smbus_read_str(struct acpi_ec_smbus *smbus, int addr, int func,
+ char *str,
+ void (*err_handler) (struct acpi_ec_smbus * smbus))
+{
+ union i2c_smbus_data data;
+ int result = 0;
+ int i;
+
+ if (err_handler == NULL) {
+ err_handler = acpi_battery_smbus_err_handler;
+ }
+
+ for (i = 0; i < MAX_SMBUS_ERR; i++) {
+ result =
+ smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
+ I2C_SMBUS_READ, func,
+ I2C_SMBUS_BLOCK_DATA,
+ &data);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "try %i: smbus->adapter.algo->smbus_xfer() failed\n",
+ i));
+ if (err_handler) {
+ err_handler(smbus);
+ }
+ } else {
+ strncpy(str, (const char *)data.block + 1,
+ data.block[0]);
+ str[data.block[0]] = 0;
+ break;
+ }
+ }
+
+ return result;
+}
+
+static int
+acpi_sbs_smbus_write_word(struct acpi_ec_smbus *smbus, int addr, int func,
+ int word,
+ void (*err_handler) (struct acpi_ec_smbus * smbus))
+{
+ union i2c_smbus_data data;
+ int result = 0;
+ int i;
+
+ if (err_handler == NULL) {
+ err_handler = acpi_battery_smbus_err_handler;
+ }
+
+ data.word = word;
+
+ for (i = 0; i < MAX_SMBUS_ERR; i++) {
+ result =
+ smbus->adapter.algo->smbus_xfer(&smbus->adapter, addr, 0,
+ I2C_SMBUS_WRITE, func,
+ I2C_SMBUS_WORD_DATA, &data);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "try %i: smbus->adapter.algo"
+ "->smbus_xfer() failed\n", i));
+ if (err_handler) {
+ err_handler(smbus);
+ }
+ } else {
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------
+ Smart Battery System Management
+ -------------------------------------------------------------------------- */
+
+/* Smart Battery */
+
+static int acpi_sbs_generate_event(struct acpi_device *device,
+ int event, int state, char *bid, char *class)
+{
+ char bid_saved[5];
+ char class_saved[20];
+ int result = 0;
+
+ strcpy(bid_saved, acpi_device_bid(device));
+ strcpy(class_saved, acpi_device_class(device));
+
+ strcpy(acpi_device_bid(device), bid);
+ strcpy(acpi_device_class(device), class);
+
+ result = acpi_bus_generate_event(device, event, state);
+
+ strcpy(acpi_device_bid(device), bid_saved);
+ strcpy(acpi_device_class(device), class_saved);
+
+ return result;
+}
+
+static int acpi_battery_get_present(struct acpi_battery *battery)
+{
+ s16 state;
+ int result = 0;
+ int is_present = 0;
+
+ result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
+ ACPI_SBSM_SMBUS_ADDR, 0x01,
+ &state, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed"));
+ }
+ if (!result) {
+ is_present = (state & 0x000f) & (1 << battery->id);
+ }
+ battery->battery_present = is_present;
+
+ return result;
+}
+
+static int acpi_battery_is_present(struct acpi_battery *battery)
+{
+ return (battery->battery_present);
+}
+
+static int acpi_ac_is_present(struct acpi_sbs *sbs)
+{
+ return (sbs->ac_present);
+}
+
+static int acpi_battery_select(struct acpi_battery *battery)
+{
+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ int result = 0;
+ s16 state;
+ int foo;
+
+ if (battery->sbs->sbsm_present) {
+
+ /* Take special care not to knobble other nibbles of
+ * state (aka selector_state), since
+ * it causes charging to halt on SBSELs */
+
+ result =
+ acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
+ &state, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ foo = (state & 0x0fff) | (1 << (battery->id + 12));
+ result =
+ acpi_sbs_smbus_write_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x01,
+ foo, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_write_word() failed\n"));
+ goto end;
+ }
+ }
+
+ end:
+ return result;
+}
+
+static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
+{
+ struct acpi_ec_smbus *smbus = sbs->smbus;
+ int result = 0;
+ s16 battery_system_info;
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SBSM_SMBUS_ADDR, 0x04,
+ &battery_system_info, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
+
+ end:
+
+ return result;
+}
+
+static int acpi_battery_get_info(struct acpi_battery *battery)
+{
+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ int result = 0;
+ s16 battery_mode;
+ s16 specification_info;
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+ battery->info.capacity_mode = (battery_mode & 0x8000) >> 15;
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x10,
+ &battery->info.full_charge_capacity,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x18,
+ &battery->info.design_capacity,
+ &acpi_battery_smbus_err_handler);
+
+ if (result) {
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x19,
+ &battery->info.design_voltage,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1a,
+ &specification_info,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ switch ((specification_info & 0x0f00) >> 8) {
+ case 1:
+ battery->info.vscale = 10;
+ break;
+ case 2:
+ battery->info.vscale = 100;
+ break;
+ case 3:
+ battery->info.vscale = 1000;
+ break;
+ default:
+ battery->info.vscale = 1;
+ }
+
+ switch ((specification_info & 0xf000) >> 12) {
+ case 1:
+ battery->info.ipscale = 10;
+ break;
+ case 2:
+ battery->info.ipscale = 100;
+ break;
+ case 3:
+ battery->info.ipscale = 1000;
+ break;
+ default:
+ battery->info.ipscale = 1;
+ }
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x1c,
+ &battery->info.serial_number,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x20,
+ battery->info.manufacturer_name,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_str() failed\n"));
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x21,
+ battery->info.device_name,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_str() failed\n"));
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_str(smbus, ACPI_SB_SMBUS_ADDR, 0x22,
+ battery->info.device_chemistry,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_str() failed\n"));
+ goto end;
+ }
+
+ end:
+ return result;
+}
+
+static void acpi_update_delay(struct acpi_sbs *sbs)
+{
+ if (sbs->zombie) {
+ return;
+ }
+ if (sbs->update_time2 > 0) {
+ msleep(sbs->update_time2 * 1000);
+ }
+}
+
+static int acpi_battery_get_state(struct acpi_battery *battery)
+{
+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ int result = 0;
+
+ acpi_update_delay(battery->sbs);
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x09,
+ &battery->state.voltage,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0a,
+ &battery->state.amperage,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x0f,
+ &battery->state.remaining_capacity,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x12,
+ &battery->state.average_time_to_empty,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x13,
+ &battery->state.average_time_to_full,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x16,
+ &battery->state.battery_status,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+
+ end:
+ return result;
+}
+
+static int acpi_battery_get_alarm(struct acpi_battery *battery)
+{
+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ int result = 0;
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
+ &battery->alarm.remaining_capacity,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ acpi_update_delay(battery->sbs);
+
+ end:
+
+ return result;
+}
+
+static int acpi_battery_set_alarm(struct acpi_battery *battery,
+ unsigned long alarm)
+{
+ struct acpi_ec_smbus *smbus = battery->sbs->smbus;
+ int result = 0;
+ s16 battery_mode;
+ int foo;
+
+ result = acpi_battery_select(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_select() failed\n"));
+ goto end;
+ }
+
+ /* If necessary, enable the alarm */
+
+ if (alarm > 0) {
+ result =
+ acpi_sbs_smbus_read_word(smbus, ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ result =
+ acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
+ battery_mode & 0xbfff,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_write_word() failed\n"));
+ goto end;
+ }
+ }
+
+ foo = alarm / (battery->info.capacity_mode ? 10 : 1);
+ result = acpi_sbs_smbus_write_word(smbus, ACPI_SB_SMBUS_ADDR, 0x01,
+ foo,
+ &acpi_battery_smbus_err_handler);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_write_word() failed\n"));
+ goto end;
+ }
+
+ end:
+
+ return result;
+}
+
+static int acpi_battery_set_mode(struct acpi_battery *battery)
+{
+ int result = 0;
+ s16 battery_mode;
+
+ if (capacity_mode == DEF_CAPACITY_UNIT) {
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
+ ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ if (capacity_mode == MAH_CAPACITY_UNIT) {
+ battery_mode &= 0x7fff;
+ } else {
+ battery_mode |= 0x8000;
+ }
+ result = acpi_sbs_smbus_write_word(battery->sbs->smbus,
+ ACPI_SB_SMBUS_ADDR, 0x03,
+ battery_mode, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_write_word() failed\n"));
+ goto end;
+ }
+
+ result = acpi_sbs_smbus_read_word(battery->sbs->smbus,
+ ACPI_SB_SMBUS_ADDR, 0x03,
+ &battery_mode, NULL);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ end:
+ return result;
+}
+
+static int acpi_battery_init(struct acpi_battery *battery)
+{
+ int result = 0;
+
+ result = acpi_battery_select(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_init() failed\n"));
+ goto end;
+ }
+
+ result = acpi_battery_set_mode(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_set_mode() failed\n"));
+ goto end;
+ }
+
+ result = acpi_battery_get_info(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_info() failed\n"));
+ goto end;
+ }
+
+ result = acpi_battery_get_state(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_state() failed\n"));
+ goto end;
+ }
+
+ result = acpi_battery_get_alarm(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_alarm() failed\n"));
+ goto end;
+ }
+
+ end:
+ return result;
+}
+
+static int acpi_ac_get_present(struct acpi_sbs *sbs)
+{
+ struct acpi_ec_smbus *smbus = sbs->smbus;
+ int result = 0;
+ s16 charger_status;
+
+ result = acpi_sbs_smbus_read_word(smbus, ACPI_SBC_SMBUS_ADDR, 0x13,
+ &charger_status, NULL);
+
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_smbus_read_word() failed\n"));
+ goto end;
+ }
+
+ sbs->ac_present = (charger_status & 0x8000) >> 15;
+
+ end:
+
+ return result;
+}
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc/acpi)
+ -------------------------------------------------------------------------- */
+
+/* Generic Routines */
+
+static int
+acpi_sbs_generic_add_fs(struct proc_dir_entry **dir,
+ struct proc_dir_entry *parent_dir,
+ char *dir_name,
+ struct file_operations *info_fops,
+ struct file_operations *state_fops,
+ struct file_operations *alarm_fops, void *data)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ if (!*dir) {
+ *dir = proc_mkdir(dir_name, parent_dir);
+ if (!*dir) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "proc_mkdir() failed\n"));
+ return -ENODEV;
+ }
+ (*dir)->owner = THIS_MODULE;
+ }
+
+ /* 'info' [R] */
+ if (info_fops) {
+ entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
+ if (!entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "create_proc_entry() failed\n"));
+ } else {
+ entry->proc_fops = info_fops;
+ entry->data = data;
+ entry->owner = THIS_MODULE;
+ }
+ }
+
+ /* 'state' [R] */
+ if (state_fops) {
+ entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
+ if (!entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "create_proc_entry() failed\n"));
+ } else {
+ entry->proc_fops = state_fops;
+ entry->data = data;
+ entry->owner = THIS_MODULE;
+ }
+ }
+
+ /* 'alarm' [R/W] */
+ if (alarm_fops) {
+ entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
+ if (!entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "create_proc_entry() failed\n"));
+ } else {
+ entry->proc_fops = alarm_fops;
+ entry->data = data;
+ entry->owner = THIS_MODULE;
+ }
+ }
+
+ return 0;
+}
+
+static void
+acpi_sbs_generic_remove_fs(struct proc_dir_entry **dir,
+ struct proc_dir_entry *parent_dir)
+{
+
+ if (*dir) {
+ remove_proc_entry(ACPI_SBS_FILE_INFO, *dir);
+ remove_proc_entry(ACPI_SBS_FILE_STATE, *dir);
+ remove_proc_entry(ACPI_SBS_FILE_ALARM, *dir);
+ remove_proc_entry((*dir)->name, parent_dir);
+ *dir = NULL;
+ }
+
+}
+
+/* Smart Battery Interface */
+
+static struct proc_dir_entry *acpi_battery_dir = NULL;
+
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ int cscale;
+ int result = 0;
+
+ if (battery->sbs->zombie) {
+ return -ENODEV;
+ }
+
+ down(&sbs_sem);
+
+ if (update_mode == REQUEST_UPDATE_MODE) {
+ result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_INFO);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_update_run() failed\n"));
+ }
+ }
+
+ if (acpi_battery_is_present(battery)) {
+ seq_printf(seq, "present: yes\n");
+ } else {
+ seq_printf(seq, "present: no\n");
+ goto end;
+ }
+
+ if (battery->info.capacity_mode) {
+ cscale = battery->info.vscale * battery->info.ipscale;
+ } else {
+ cscale = battery->info.ipscale;
+ }
+ seq_printf(seq, "design capacity: %i%s",
+ battery->info.design_capacity * cscale,
+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+ seq_printf(seq, "last full capacity: %i%s",
+ battery->info.full_charge_capacity * cscale,
+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+ seq_printf(seq, "battery technology: rechargeable\n");
+
+ seq_printf(seq, "design voltage: %i mV\n",
+ battery->info.design_voltage * battery->info.vscale);
+
+ seq_printf(seq, "design capacity warning: unknown\n");
+ seq_printf(seq, "design capacity low: unknown\n");
+ seq_printf(seq, "capacity granularity 1: unknown\n");
+ seq_printf(seq, "capacity granularity 2: unknown\n");
+
+ seq_printf(seq, "model number: %s\n",
+ battery->info.device_name);
+
+ seq_printf(seq, "serial number: %i\n",
+ battery->info.serial_number);
+
+ seq_printf(seq, "battery type: %s\n",
+ battery->info.device_chemistry);
+
+ seq_printf(seq, "OEM info: %s\n",
+ battery->info.manufacturer_name);
+
+ end:
+
+ up(&sbs_sem);
+
+ return result;
+}
+
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+static int acpi_battery_read_state(struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ int result = 0;
+ int cscale;
+ int foo;
+
+ if (battery->sbs->zombie) {
+ return -ENODEV;
+ }
+
+ down(&sbs_sem);
+
+ if (update_mode == REQUEST_UPDATE_MODE) {
+ result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_STATE);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_update_run() failed\n"));
+ }
+ }
+
+ if (acpi_battery_is_present(battery)) {
+ seq_printf(seq, "present: yes\n");
+ } else {
+ seq_printf(seq, "present: no\n");
+ goto end;
+ }
+
+ if (battery->info.capacity_mode) {
+ cscale = battery->info.vscale * battery->info.ipscale;
+ } else {
+ cscale = battery->info.ipscale;
+ }
+
+ if (battery->state.battery_status & 0x0010) {
+ seq_printf(seq, "capacity state: critical\n");
+ } else {
+ seq_printf(seq, "capacity state: ok\n");
+ }
+ if (battery->state.amperage < 0) {
+ seq_printf(seq, "charging state: discharging\n");
+ foo = battery->state.remaining_capacity * cscale * 60 /
+ (battery->state.average_time_to_empty == 0 ? 1 :
+ battery->state.average_time_to_empty);
+ seq_printf(seq, "present rate: %i%s\n",
+ foo, battery->info.capacity_mode ? "0 mW" : " mA");
+ } else if (battery->state.amperage > 0) {
+ seq_printf(seq, "charging state: charging\n");
+ foo = (battery->info.full_charge_capacity -
+ battery->state.remaining_capacity) * cscale * 60 /
+ (battery->state.average_time_to_full == 0 ? 1 :
+ battery->state.average_time_to_full);
+ seq_printf(seq, "present rate: %i%s\n",
+ foo, battery->info.capacity_mode ? "0 mW" : " mA");
+ } else {
+ seq_printf(seq, "charging state: charged\n");
+ seq_printf(seq, "present rate: 0 %s\n",
+ battery->info.capacity_mode ? "mW" : "mA");
+ }
+
+ seq_printf(seq, "remaining capacity: %i%s",
+ battery->state.remaining_capacity * cscale,
+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+
+ seq_printf(seq, "present voltage: %i mV\n",
+ battery->state.voltage * battery->info.vscale);
+
+ end:
+
+ up(&sbs_sem);
+
+ return result;
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_state, PDE(inode)->data);
+}
+
+static int acpi_battery_read_alarm(struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ int result = 0;
+ int cscale;
+
+ if (battery->sbs->zombie) {
+ return -ENODEV;
+ }
+
+ down(&sbs_sem);
+
+ if (update_mode == REQUEST_UPDATE_MODE) {
+ result = acpi_sbs_update_run(battery->sbs, DATA_TYPE_ALARM);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_update_run() failed\n"));
+ }
+ }
+
+ if (!acpi_battery_is_present(battery)) {
+ seq_printf(seq, "present: no\n");
+ goto end;
+ }
+
+ if (battery->info.capacity_mode) {
+ cscale = battery->info.vscale * battery->info.ipscale;
+ } else {
+ cscale = battery->info.ipscale;
+ }
+
+ seq_printf(seq, "alarm: ");
+ if (battery->alarm.remaining_capacity) {
+ seq_printf(seq, "%i%s",
+ battery->alarm.remaining_capacity * cscale,
+ battery->info.capacity_mode ? "0 mWh\n" : " mAh\n");
+ } else {
+ seq_printf(seq, "disabled\n");
+ }
+
+ end:
+
+ up(&sbs_sem);
+
+ return result;
+}
+
+static ssize_t
+acpi_battery_write_alarm(struct file *file, const char __user * buffer,
+ size_t count, loff_t * ppos)
+{
+ struct seq_file *seq = (struct seq_file *)file->private_data;
+ struct acpi_battery *battery = (struct acpi_battery *)seq->private;
+ char alarm_string[12] = { '\0' };
+ int result, old_alarm, new_alarm;
+
+ if (battery->sbs->zombie) {
+ return -ENODEV;
+ }
+
+ down(&sbs_sem);
+
+ if (!acpi_battery_is_present(battery)) {
+ result = -ENODEV;
+ goto end;
+ }
+
+ if (count > sizeof(alarm_string) - 1) {
+ result = -EINVAL;
+ goto end;
+ }
+
+ if (copy_from_user(alarm_string, buffer, count)) {
+ result = -EFAULT;
+ goto end;
+ }
+
+ alarm_string[count] = 0;
+
+ old_alarm = battery->alarm.remaining_capacity;
+ new_alarm = simple_strtoul(alarm_string, NULL, 0);
+
+ result = acpi_battery_set_alarm(battery, new_alarm);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_set_alarm() failed\n"));
+ (void)acpi_battery_set_alarm(battery, old_alarm);
+ goto end;
+ }
+ result = acpi_battery_get_alarm(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_alarm() failed\n"));
+ (void)acpi_battery_set_alarm(battery, old_alarm);
+ goto end;
+ }
+
+ end:
+ up(&sbs_sem);
+
+ if (result) {
+ return result;
+ } else {
+ return count;
+ }
+}
+
+static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
+}
+
+static struct file_operations acpi_battery_info_fops = {
+ .open = acpi_battery_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct file_operations acpi_battery_state_fops = {
+ .open = acpi_battery_state_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct file_operations acpi_battery_alarm_fops = {
+ .open = acpi_battery_alarm_open_fs,
+ .read = seq_read,
+ .write = acpi_battery_write_alarm,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+/* Legacy AC Adapter Interface */
+
+static struct proc_dir_entry *acpi_ac_dir = NULL;
+
+static int acpi_ac_read_state(struct seq_file *seq, void *offset)
+{
+ struct acpi_sbs *sbs = (struct acpi_sbs *)seq->private;
+ int result;
+
+ if (sbs->zombie) {
+ return -ENODEV;
+ }
+
+ down(&sbs_sem);
+
+ if (update_mode == REQUEST_UPDATE_MODE) {
+ result = acpi_sbs_update_run(sbs, DATA_TYPE_AC_STATE);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_update_run() failed\n"));
+ }
+ }
+
+ seq_printf(seq, "state: %s\n",
+ sbs->ac_present ? "on-line" : "off-line");
+
+ up(&sbs_sem);
+
+ return 0;
+}
+
+static int acpi_ac_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_ac_read_state, PDE(inode)->data);
+}
+
+static struct file_operations acpi_ac_state_fops = {
+ .open = acpi_ac_state_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+/* Smart Battery */
+
+static int acpi_battery_add(struct acpi_sbs *sbs, int id)
+{
+ int is_present;
+ int result;
+ char dir_name[32];
+ struct acpi_battery *battery;
+
+ battery = &sbs->battery[id];
+
+ battery->alive = 0;
+
+ battery->init_state = 0;
+ battery->id = id;
+ battery->sbs = sbs;
+
+ result = acpi_battery_select(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_select() failed\n"));
+ goto end;
+ }
+
+ result = acpi_battery_get_present(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_present() failed\n"));
+ goto end;
+ }
+
+ is_present = acpi_battery_is_present(battery);
+
+ if (is_present) {
+ result = acpi_battery_init(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_init() failed\n"));
+ goto end;
+ }
+ battery->init_state = 1;
+ }
+
+ (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+
+ result = acpi_sbs_generic_add_fs(&battery->battery_entry,
+ acpi_battery_dir,
+ dir_name,
+ &acpi_battery_info_fops,
+ &acpi_battery_state_fops,
+ &acpi_battery_alarm_fops, battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_generic_add_fs() failed\n"));
+ goto end;
+ }
+ battery->alive = 1;
+
+ end:
+ return result;
+}
+
+static void acpi_battery_remove(struct acpi_sbs *sbs, int id)
+{
+
+ if (sbs->battery[id].battery_entry) {
+ acpi_sbs_generic_remove_fs(&(sbs->battery[id].battery_entry),
+ acpi_battery_dir);
+ }
+}
+
+static int acpi_ac_add(struct acpi_sbs *sbs)
+{
+ int result;
+
+ result = acpi_ac_get_present(sbs);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_ac_get_present() failed\n"));
+ goto end;
+ }
+
+ result = acpi_sbs_generic_add_fs(&sbs->ac_entry,
+ acpi_ac_dir,
+ ACPI_AC_DIR_NAME,
+ NULL, &acpi_ac_state_fops, NULL, sbs);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_generic_add_fs() failed\n"));
+ goto end;
+ }
+
+ end:
+
+ return result;
+}
+
+static void acpi_ac_remove(struct acpi_sbs *sbs)
+{
+
+ if (sbs->ac_entry) {
+ acpi_sbs_generic_remove_fs(&sbs->ac_entry, acpi_ac_dir);
+ }
+}
+
+static void acpi_sbs_update_queue_run(unsigned long data)
+{
+ acpi_os_execute(OSL_GPE_HANDLER, acpi_sbs_update_queue, (void *)data);
+}
+
+static int acpi_sbs_update_run(struct acpi_sbs *sbs, int data_type)
+{
+ struct acpi_battery *battery;
+ int result = 0;
+ int old_ac_present;
+ int old_battery_present;
+ int new_ac_present;
+ int new_battery_present;
+ int id;
+ char dir_name[32];
+ int do_battery_init, do_ac_init;
+ s16 old_remaining_capacity;
+
+ if (sbs->zombie) {
+ goto end;
+ }
+
+ old_ac_present = acpi_ac_is_present(sbs);
+
+ result = acpi_ac_get_present(sbs);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_ac_get_present() failed\n"));
+ }
+
+ new_ac_present = acpi_ac_is_present(sbs);
+
+ do_ac_init = (old_ac_present != new_ac_present);
+
+ if (data_type == DATA_TYPE_AC_STATE) {
+ goto end;
+ }
+
+ for (id = 0; id < MAX_SBS_BAT; id++) {
+ battery = &sbs->battery[id];
+ if (battery->alive == 0) {
+ continue;
+ }
+
+ old_remaining_capacity = battery->state.remaining_capacity;
+
+ old_battery_present = acpi_battery_is_present(battery);
+
+ result = acpi_battery_select(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_select() failed\n"));
+ }
+ if (sbs->zombie) {
+ goto end;
+ }
+
+ result = acpi_battery_get_present(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_present() failed\n"));
+ }
+ if (sbs->zombie) {
+ goto end;
+ }
+
+ new_battery_present = acpi_battery_is_present(battery);
+
+ do_battery_init = ((old_battery_present != new_battery_present)
+ && new_battery_present);
+
+ if (sbs->zombie) {
+ goto end;
+ }
+ if (do_ac_init || do_battery_init ||
+ update_info_mode || sbs->update_info_mode) {
+ if (sbs->update_info_mode) {
+ sbs->update_info_mode = 0;
+ } else {
+ sbs->update_info_mode = 1;
+ }
+ result = acpi_battery_init(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_init() "
+ "failed\n"));
+ }
+ }
+ if (data_type == DATA_TYPE_INFO) {
+ continue;
+ }
+
+ if (sbs->zombie) {
+ goto end;
+ }
+ if (new_battery_present) {
+ result = acpi_battery_get_alarm(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_alarm() "
+ "failed\n"));
+ }
+ if (data_type == DATA_TYPE_ALARM) {
+ continue;
+ }
+
+ result = acpi_battery_get_state(battery);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_get_state() "
+ "failed\n"));
+ }
+ }
+ if (sbs->zombie) {
+ goto end;
+ }
+ if (data_type != DATA_TYPE_COMMON) {
+ continue;
+ }
+
+ if (old_battery_present != new_battery_present) {
+ (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+ result = acpi_sbs_generate_event(sbs->device,
+ ACPI_SBS_BATTERY_NOTIFY_STATUS,
+ new_battery_present,
+ dir_name,
+ ACPI_BATTERY_CLASS);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_generate_event() "
+ "failed\n"));
+ }
+ }
+ if (old_remaining_capacity != battery->state.remaining_capacity) {
+ (void)sprintf(dir_name, ACPI_BATTERY_DIR_NAME, id);
+ result = acpi_sbs_generate_event(sbs->device,
+ ACPI_SBS_BATTERY_NOTIFY_STATUS,
+ new_battery_present,
+ dir_name,
+ ACPI_BATTERY_CLASS);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_generate_event() failed\n"));
+ }
+ }
+
+ }
+ if (sbs->zombie) {
+ goto end;
+ }
+ if (data_type != DATA_TYPE_COMMON) {
+ goto end;
+ }
+
+ if (old_ac_present != new_ac_present) {
+ result = acpi_sbs_generate_event(sbs->device,
+ ACPI_SBS_AC_NOTIFY_STATUS,
+ new_ac_present,
+ ACPI_AC_DIR_NAME,
+ ACPI_AC_CLASS);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_generate_event() failed\n"));
+ }
+ }
+
+ end:
+ return result;
+}
+
+static void acpi_sbs_update_queue(void *data)
+{
+ struct acpi_sbs *sbs = data;
+ unsigned long delay = -1;
+ int result;
+
+ if (sbs->zombie) {
+ goto end;
+ }
+
+ result = acpi_sbs_update_run(sbs, DATA_TYPE_COMMON);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_update_run() failed\n"));
+ }
+
+ if (sbs->zombie) {
+ goto end;
+ }
+
+ if (update_mode == REQUEST_UPDATE_MODE) {
+ goto end;
+ }
+
+ delay = jiffies + HZ * update_time;
+ sbs->update_timer.data = (unsigned long)data;
+ sbs->update_timer.function = acpi_sbs_update_queue_run;
+ sbs->update_timer.expires = delay;
+ add_timer(&sbs->update_timer);
+ end:
+ ;
+}
+
+static int acpi_sbs_add(struct acpi_device *device)
+{
+ struct acpi_sbs *sbs = NULL;
+ struct acpi_ec_hc *ec_hc = NULL;
+ int result, remove_result = 0;
+ unsigned long sbs_obj;
+ int id, cnt;
+ acpi_status status = AE_OK;
+
+ sbs = kmalloc(sizeof(struct acpi_sbs), GFP_KERNEL);
+ if (!sbs) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "kmalloc() failed\n"));
+ return -ENOMEM;
+ }
+ memset(sbs, 0, sizeof(struct acpi_sbs));
+
+ cnt = 0;
+ while (cnt < 10) {
+ cnt++;
+ ec_hc = acpi_get_ec_hc(device);
+ if (ec_hc) {
+ break;
+ }
+ msleep(1000);
+ }
+
+ if (!ec_hc) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_get_ec_hc() failed: "
+ "NO driver found for EC HC SMBus\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ sbs->device = device;
+ sbs->smbus = ec_hc->smbus;
+
+ strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_SBS_CLASS);
+ acpi_driver_data(device) = sbs;
+
+ sbs->update_time = 0;
+ sbs->update_time2 = 0;
+
+ result = acpi_ac_add(sbs);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_ac_add() failed\n"));
+ goto end;
+ }
+ result = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
+ if (ACPI_FAILURE(result)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_evaluate_integer() failed\n"));
+ result = -EIO;
+ goto end;
+ }
+
+ if (sbs_obj > 0) {
+ result = acpi_sbsm_get_info(sbs);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbsm_get_info() failed\n"));
+ goto end;
+ }
+ sbs->sbsm_present = 1;
+ }
+ if (sbs->sbsm_present == 0) {
+ result = acpi_battery_add(sbs, 0);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_add() failed\n"));
+ goto end;
+ }
+ } else {
+ for (id = 0; id < MAX_SBS_BAT; id++) {
+ if ((sbs->sbsm_batteries_supported & (1 << id))) {
+ result = acpi_battery_add(sbs, id);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_battery_add() "
+ "failed\n"));
+ goto end;
+ }
+ }
+ }
+ }
+
+ sbs->handle = device->handle;
+
+ init_timer(&sbs->update_timer);
+ if (update_mode == QUEUE_UPDATE_MODE) {
+ status = acpi_os_execute(OSL_GPE_HANDLER,
+ acpi_sbs_update_queue, (void *)sbs);
+ if (status != AE_OK) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_os_execute() failed\n"));
+ }
+ }
+ sbs->update_time = update_time;
+ sbs->update_time2 = update_time2;
+
+ printk(KERN_INFO PREFIX "%s [%s]\n",
+ acpi_device_name(device), acpi_device_bid(device));
+
+ end:
+ if (result) {
+ remove_result = acpi_sbs_remove(device, 0);
+ if (remove_result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_sbs_remove() failed\n"));
+ }
+ }
+
+ return result;
+}
+
+int acpi_sbs_remove(struct acpi_device *device, int type)
+{
+ struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
+ int id;
+
+ if (!device || !sbs) {
+ return -EINVAL;
+ }
+
+ sbs->zombie = 1;
+ sbs->update_time = 0;
+ sbs->update_time2 = 0;
+ del_timer_sync(&sbs->update_timer);
+ acpi_os_wait_events_complete(NULL);
+ del_timer_sync(&sbs->update_timer);
+
+ for (id = 0; id < MAX_SBS_BAT; id++) {
+ acpi_battery_remove(sbs, id);
+ }
+
+ acpi_ac_remove(sbs);
+
+ kfree(sbs);
+
+ return 0;
+}
+
+static int __init acpi_sbs_init(void)
+{
+ int result = 0;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ init_MUTEX(&sbs_sem);
+
+ if (capacity_mode != DEF_CAPACITY_UNIT
+ && capacity_mode != MAH_CAPACITY_UNIT
+ && capacity_mode != MWH_CAPACITY_UNIT) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "acpi_sbs_init: "
+ "invalid capacity_mode = %d\n",
+ capacity_mode));
+ return -EINVAL;
+ }
+
+ acpi_ac_dir = acpi_lock_ac_dir();
+ if (!acpi_ac_dir) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_lock_ac_dir() failed\n"));
+ return -ENODEV;
+ }
+
+ acpi_battery_dir = acpi_lock_battery_dir();
+ if (!acpi_battery_dir) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_lock_battery_dir() failed\n"));
+ return -ENODEV;
+ }
+
+ result = acpi_bus_register_driver(&acpi_sbs_driver);
+ if (result < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "acpi_bus_register_driver() failed\n"));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit acpi_sbs_exit(void)
+{
+
+ acpi_bus_unregister_driver(&acpi_sbs_driver);
+
+ acpi_unlock_ac_dir(acpi_ac_dir);
+ acpi_ac_dir = NULL;
+ acpi_unlock_battery_dir(acpi_battery_dir);
+ acpi_battery_dir = NULL;
+
+ return;
+}
+
+module_init(acpi_sbs_init);
+module_exit(acpi_sbs_exit);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index f8316a05ede..698a1540e30 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -4,6 +4,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
@@ -113,6 +114,8 @@ static struct kset acpi_namespace_kset = {
static void acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
{
+ int err;
+
/*
* Linkage
* -------
@@ -138,7 +141,10 @@ static void acpi_device_register(struct acpi_device *device,
device->kobj.parent = &parent->kobj;
device->kobj.ktype = &ktype_acpi_ns;
device->kobj.kset = &acpi_namespace_kset;
- kobject_register(&device->kobj);
+ err = kobject_register(&device->kobj);
+ if (err < 0)
+ printk(KERN_WARNING "%s: kobject_register error: %d\n",
+ __FUNCTION__, err);
create_sysfs_device_files(device);
}
@@ -162,11 +168,10 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
{
- ACPI_FUNCTION_TRACE("acpi_bus_data_handler");
/* TBD */
- return_VOID;
+ return;
}
static int acpi_bus_get_power_flags(struct acpi_device *device)
@@ -175,7 +180,6 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
acpi_handle handle = NULL;
u32 i = 0;
- ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags");
/*
* Power Management Flags
@@ -228,7 +232,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device)
device->power.state = ACPI_STATE_UNKNOWN;
- return_VALUE(0);
+ return 0;
}
int acpi_match_ids(struct acpi_device *device, char *ids)
@@ -306,24 +310,22 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_get_wakeup_flags");
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW"));
goto end;
}
package = (union acpi_object *)buffer.pointer;
status = acpi_bus_extract_wakeup_device_power_package(device, package);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error extracting _PRW package\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package"));
goto end;
}
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
/* Power button, Lid switch always enable wakeup */
@@ -333,7 +335,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
end:
if (ACPI_FAILURE(status))
device->flags.wake_capable = 0;
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -489,19 +491,18 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_bus_driver_init");
if (!device || !driver)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!driver->ops.add)
- return_VALUE(-ENOSYS);
+ return -ENOSYS;
result = driver->ops.add(device);
if (result) {
device->driver = NULL;
acpi_driver_data(device) = NULL;
- return_VALUE(result);
+ return result;
}
device->driver = driver;
@@ -513,7 +514,7 @@ acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Driver successfully bound to device\n"));
- return_VALUE(0);
+ return 0;
}
static int acpi_start_single_object(struct acpi_device *device)
@@ -521,10 +522,9 @@ static int acpi_start_single_object(struct acpi_device *device)
int result = 0;
struct acpi_driver *driver;
- ACPI_FUNCTION_TRACE("acpi_start_single_object");
if (!(driver = device->driver))
- return_VALUE(0);
+ return 0;
if (driver->ops.start) {
result = driver->ops.start(device);
@@ -532,14 +532,13 @@ static int acpi_start_single_object(struct acpi_device *device)
driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
}
- return_VALUE(result);
+ return result;
}
static void acpi_driver_attach(struct acpi_driver *drv)
{
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_driver_attach");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_device_list) {
@@ -568,7 +567,6 @@ static void acpi_driver_detach(struct acpi_driver *drv)
{
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_driver_detach");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_device_list) {
@@ -598,17 +596,16 @@ static void acpi_driver_detach(struct acpi_driver *drv)
*/
int acpi_bus_register_driver(struct acpi_driver *driver)
{
- ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
if (acpi_disabled)
- return_VALUE(-ENODEV);
+ return -ENODEV;
spin_lock(&acpi_device_lock);
list_add_tail(&driver->node, &acpi_bus_drivers);
spin_unlock(&acpi_device_lock);
acpi_driver_attach(driver);
- return_VALUE(0);
+ return 0;
}
EXPORT_SYMBOL(acpi_bus_register_driver);
@@ -646,7 +643,6 @@ static int acpi_bus_find_driver(struct acpi_device *device)
int result = 0;
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_bus_find_driver");
spin_lock(&acpi_device_lock);
list_for_each_safe(node, next, &acpi_bus_drivers) {
@@ -666,19 +662,41 @@ static int acpi_bus_find_driver(struct acpi_device *device)
spin_unlock(&acpi_device_lock);
Done:
- return_VALUE(result);
+ return result;
}
/* --------------------------------------------------------------------------
Device Enumeration
-------------------------------------------------------------------------- */
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+ acpi_status status;
+ acpi_handle tmp;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+
+ status = acpi_get_handle(handle, "_EJD", &tmp);
+ if (ACPI_FAILURE(status))
+ return status;
+
+ status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ obj = buffer.pointer;
+ status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+ kfree(buffer.pointer);
+ }
+ return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+
+
static int acpi_bus_get_flags(struct acpi_device *device)
{
acpi_status status = AE_OK;
acpi_handle temp = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_get_flags");
/* Presence of _STA indicates 'dynamic_status' */
status = acpi_get_handle(device->handle, "_STA", &temp);
@@ -724,7 +742,7 @@ static int acpi_bus_get_flags(struct acpi_device *device)
/* TBD: Peformance management */
- return_VALUE(0);
+ return 0;
}
static void acpi_device_get_busid(struct acpi_device *device,
@@ -842,7 +860,7 @@ static void acpi_device_set_id(struct acpi_device *device,
printk(KERN_ERR "Memory allocation error\n");
}
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
}
static int acpi_device_set_context(struct acpi_device *device, int type)
@@ -918,10 +936,9 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
int result = 0;
struct acpi_driver *driver;
- ACPI_FUNCTION_TRACE("acpi_bus_remove");
if (!dev)
- return_VALUE(-EINVAL);
+ return -EINVAL;
driver = dev->driver;
@@ -930,12 +947,12 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
if (driver->ops.stop) {
result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
if (result)
- return_VALUE(result);
+ return result;
}
result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
if (result) {
- return_VALUE(result);
+ return result;
}
atomic_dec(&dev->driver->references);
@@ -944,7 +961,7 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
}
if (!rmdevice)
- return_VALUE(0);
+ return 0;
if (dev->flags.bus_address) {
if ((dev->parent) && (dev->parent->ops.unbind))
@@ -953,7 +970,7 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
- return_VALUE(0);
+ return 0;
}
static int
@@ -963,15 +980,14 @@ acpi_add_single_object(struct acpi_device **child,
int result = 0;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_add_single_object");
if (!child)
- return_VALUE(-EINVAL);
+ return -EINVAL;
device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
if (!device) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
- return_VALUE(-ENOMEM);
+ printk(KERN_ERR PREFIX "Memory allocation error\n");
+ return -ENOMEM;
}
memset(device, 0, sizeof(struct acpi_device));
@@ -1096,7 +1112,7 @@ acpi_add_single_object(struct acpi_device **child,
kfree(device);
}
- return_VALUE(result);
+ return result;
}
static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
@@ -1109,10 +1125,9 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
acpi_object_type type = 0;
u32 level = 1;
- ACPI_FUNCTION_TRACE("acpi_bus_scan");
if (!start)
- return_VALUE(-EINVAL);
+ return -EINVAL;
parent = start;
phandle = start->handle;
@@ -1209,7 +1224,7 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
}
}
- return_VALUE(0);
+ return 0;
}
int
@@ -1219,7 +1234,6 @@ acpi_bus_add(struct acpi_device **child,
int result;
struct acpi_bus_ops ops;
- ACPI_FUNCTION_TRACE("acpi_bus_add");
result = acpi_add_single_object(child, parent, handle, type);
if (!result) {
@@ -1227,7 +1241,7 @@ acpi_bus_add(struct acpi_device **child,
ops.acpi_op_add = 1;
result = acpi_bus_scan(*child, &ops);
}
- return_VALUE(result);
+ return result;
}
EXPORT_SYMBOL(acpi_bus_add);
@@ -1237,10 +1251,9 @@ int acpi_bus_start(struct acpi_device *device)
int result;
struct acpi_bus_ops ops;
- ACPI_FUNCTION_TRACE("acpi_bus_start");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
result = acpi_start_single_object(device);
if (!result) {
@@ -1248,7 +1261,7 @@ int acpi_bus_start(struct acpi_device *device)
ops.acpi_op_start = 1;
result = acpi_bus_scan(device, &ops);
}
- return_VALUE(result);
+ return result;
}
EXPORT_SYMBOL(acpi_bus_start);
@@ -1314,10 +1327,9 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
int result = 0;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
if (!root)
- return_VALUE(-ENODEV);
+ return -ENODEV;
/*
* Enumerate all fixed-feature devices.
@@ -1338,7 +1350,7 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
result = acpi_start_single_object(device);
}
- return_VALUE(result);
+ return result;
}
@@ -1427,7 +1439,7 @@ static int acpi_device_resume(struct device * dev)
}
-struct bus_type acpi_bus_type = {
+static struct bus_type acpi_bus_type = {
.name = "acpi",
.suspend = acpi_device_suspend,
.resume = acpi_device_resume,
@@ -1440,12 +1452,13 @@ static int __init acpi_scan_init(void)
int result;
struct acpi_bus_ops ops;
- ACPI_FUNCTION_TRACE("acpi_scan_init");
if (acpi_disabled)
- return_VALUE(0);
+ return 0;
- kset_register(&acpi_namespace_kset);
+ result = kset_register(&acpi_namespace_kset);
+ if (result < 0)
+ printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
result = bus_register(&acpi_bus_type);
if (result) {
@@ -1488,7 +1501,7 @@ static int __init acpi_scan_init(void)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
Done:
- return_VALUE(result);
+ return result;
}
subsys_initcall(acpi_scan_init);
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index 4696a85a98b..34962578039 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -434,7 +434,7 @@ acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
PDE(inode)->data);
}
-static struct file_operations acpi_system_wakeup_device_fops = {
+static const struct file_operations acpi_system_wakeup_device_fops = {
.open = acpi_system_wakeup_device_open_fs,
.read = seq_read,
.write = acpi_system_write_wakeup_device,
@@ -443,7 +443,7 @@ static struct file_operations acpi_system_wakeup_device_fops = {
};
#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
-static struct file_operations acpi_system_sleep_fops = {
+static const struct file_operations acpi_system_sleep_fops = {
.open = acpi_system_sleep_open_fs,
.read = seq_read,
.write = acpi_system_write_sleep,
@@ -452,7 +452,7 @@ static struct file_operations acpi_system_sleep_fops = {
};
#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
-static struct file_operations acpi_system_alarm_fops = {
+static const struct file_operations acpi_system_alarm_fops = {
.open = acpi_system_alarm_open_fs,
.read = seq_read,
.write = acpi_system_write_alarm,
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index a934ac42178..d86dcb3c236 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -47,10 +47,9 @@ extern struct fadt_descriptor acpi_fadt;
static int acpi_system_read_info(struct seq_file *seq, void *offset)
{
- ACPI_FUNCTION_TRACE("acpi_system_read_info");
seq_printf(seq, "version: %x\n", ACPI_CA_VERSION);
- return_VALUE(0);
+ return 0;
}
static int acpi_system_info_open_fs(struct inode *inode, struct file *file)
@@ -58,7 +57,7 @@ static int acpi_system_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_system_read_info, PDE(inode)->data);
}
-static struct file_operations acpi_system_info_ops = {
+static const struct file_operations acpi_system_info_ops = {
.open = acpi_system_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -68,7 +67,7 @@ static struct file_operations acpi_system_info_ops = {
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
loff_t *);
-static struct file_operations acpi_system_dsdt_ops = {
+static const struct file_operations acpi_system_dsdt_ops = {
.read = acpi_system_read_dsdt,
};
@@ -80,23 +79,22 @@ acpi_system_read_dsdt(struct file *file,
struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
ssize_t res;
- ACPI_FUNCTION_TRACE("acpi_system_read_dsdt");
status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
dsdt.pointer, dsdt.length);
- acpi_os_free(dsdt.pointer);
+ kfree(dsdt.pointer);
- return_VALUE(res);
+ return res;
}
static ssize_t acpi_system_read_fadt(struct file *, char __user *, size_t,
loff_t *);
-static struct file_operations acpi_system_fadt_ops = {
+static const struct file_operations acpi_system_fadt_ops = {
.read = acpi_system_read_fadt,
};
@@ -108,17 +106,16 @@ acpi_system_read_fadt(struct file *file,
struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL };
ssize_t res;
- ACPI_FUNCTION_TRACE("acpi_system_read_fadt");
status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
res = simple_read_from_buffer(buffer, count, ppos,
fadt.pointer, fadt.length);
- acpi_os_free(fadt.pointer);
+ kfree(fadt.pointer);
- return_VALUE(res);
+ return res;
}
static int __init acpi_system_init(void)
@@ -127,10 +124,9 @@ static int __init acpi_system_init(void)
int error = 0;
char *name;
- ACPI_FUNCTION_TRACE("acpi_system_init");
if (acpi_disabled)
- return_VALUE(0);
+ return 0;
/* 'info' [R] */
name = ACPI_SYSTEM_FILE_INFO;
@@ -158,12 +154,9 @@ static int __init acpi_system_init(void)
goto Error;
Done:
- return_VALUE(error);
+ return error;
Error:
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' proc fs entry\n", name));
-
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index ed5e8816d83..bfb3bfcf9e9 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -23,7 +23,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
index 99eacceff56..7856db759af 100644
--- a/drivers/acpi/tables/tbget.c
+++ b/drivers/acpi/tables/tbget.c
@@ -320,6 +320,16 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
ACPI_FUNCTION_TRACE(tb_get_this_table);
+ /* Validate minimum length */
+
+ if (header->length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO,
+ "Table length (%X) is smaller than minimum (%X)",
+ header->length, sizeof(struct acpi_table_header)));
+
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
+
/*
* Flags contains the current processor mode (Virtual or Physical
* addressing) The pointer_type is either Logical or Physical
@@ -356,7 +366,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
*/
status = acpi_os_map_memory(address->pointer.physical,
(acpi_size) header->length,
- (void *)&full_table);
+ ACPI_CAST_PTR(void, &full_table));
if (ACPI_FAILURE(status)) {
ACPI_ERROR((AE_INFO,
"Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X",
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 7ca2df75bb1..1668a232fb6 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -256,7 +256,7 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_exit1;
}
/* Install the table into the global data structure */
@@ -274,8 +274,8 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
* at this location, so return an error.
*/
if (list_head->next) {
- ACPI_FREE(table_desc);
- return_ACPI_STATUS(AE_ALREADY_EXISTS);
+ status = AE_ALREADY_EXISTS;
+ goto error_exit2;
}
table_desc->next = list_head->next;
@@ -335,6 +335,17 @@ acpi_tb_init_table_descriptor(acpi_table_type table_type,
table_info->owner_id = table_desc->owner_id;
table_info->installed_desc = table_desc;
return_ACPI_STATUS(AE_OK);
+
+ /* Error exit with cleanup */
+
+ error_exit2:
+
+ acpi_ut_release_owner_id(&table_desc->owner_id);
+
+ error_exit1:
+
+ ACPI_FREE(table_desc);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -525,6 +536,10 @@ struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
acpi_tb_delete_single_table(table_desc);
+ /* Free the owner ID associated with this table */
+
+ acpi_ut_release_owner_id(&table_desc->owner_id);
+
/* Free the table descriptor */
next_desc = table_desc->next;
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
index abcb08c2592..0ad3dbb9ebc 100644
--- a/drivers/acpi/tables/tbrsdt.c
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -183,6 +183,17 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
ACPI_FUNCTION_ENTRY();
+ /* Validate minimum length */
+
+ if (table_ptr->length < sizeof(struct acpi_table_header)) {
+ ACPI_ERROR((AE_INFO,
+ "RSDT/XSDT length (%X) is smaller than minimum (%X)",
+ table_ptr->length,
+ sizeof(struct acpi_table_header)));
+
+ return (AE_INVALID_TABLE_LENGTH);
+ }
+
/* Search for appropriate signature, RSDT or XSDT */
if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
@@ -210,7 +221,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
ACPI_ERROR((AE_INFO, "Looking for XSDT"));
}
- ACPI_DUMP_BUFFER((char *)table_ptr, 48);
+ ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
return (AE_BAD_SIGNATURE);
}
@@ -258,7 +269,7 @@ acpi_status acpi_tb_get_table_rsdt(void)
status = acpi_tb_validate_rsdt(table_info.pointer);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_cleanup;
}
/* Get the number of tables defined in the RSDT or XSDT */
@@ -270,14 +281,14 @@ acpi_status acpi_tb_get_table_rsdt(void)
status = acpi_tb_convert_to_xsdt(&table_info);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_cleanup;
}
/* Save the table pointers and allocation info */
status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto error_cleanup;
}
acpi_gbl_XSDT =
@@ -285,4 +296,12 @@ acpi_status acpi_tb_get_table_rsdt(void)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
return_ACPI_STATUS(status);
+
+ error_cleanup:
+
+ /* Free table allocated by acpi_tb_get_table */
+
+ acpi_tb_delete_single_table(&table_info);
+
+ return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 4e91f298481..7767987be15 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -134,8 +134,8 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables)
* RETURN: Status
*
* DESCRIPTION: This function is called to load a table from the caller's
- * buffer. The buffer must contain an entire ACPI Table including
- * a valid header. The header fields will be verified, and if it
+ * buffer. The buffer must contain an entire ACPI Table including
+ * a valid header. The header fields will be verified, and if it
* is determined that the table is invalid, the call will fail.
*
******************************************************************************/
@@ -245,15 +245,18 @@ acpi_status acpi_unload_table(acpi_table_type table_type)
/* Find all tables of the requested type */
table_desc = acpi_gbl_table_lists[table_type].next;
+ if (!table_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
while (table_desc) {
/*
- * Delete all namespace entries owned by this table. Note that these
- * entries can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
+ * Delete all namespace objects owned by this table. Note that these
+ * objects can appear anywhere in the namespace by virtue of the AML
+ * "Scope" operator. Thus, we need to track ownership by an ID, not
* simply a position within the hierarchy
*/
acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
- acpi_ut_release_owner_id(&table_desc->owner_id);
table_desc = table_desc->next;
}
@@ -275,12 +278,12 @@ ACPI_EXPORT_SYMBOL(acpi_unload_table)
* see acpi_gbl_acpi_table_flag
* out_table_header - pointer to the struct acpi_table_header if successful
*
- * DESCRIPTION: This function is called to get an ACPI table header. The caller
+ * DESCRIPTION: This function is called to get an ACPI table header. The caller
* supplies an pointer to a data area sufficient to contain an ACPI
* struct acpi_table_header structure.
*
* The header contains a length field that can be used to determine
- * the size of the buffer needed to contain the entire table. This
+ * the size of the buffer needed to contain the entire table. This
* function is not valid for the RSD PTR table since it does not
* have a standard header and is fixed length.
*
@@ -322,7 +325,8 @@ acpi_get_table_header(acpi_table_type table_type,
/* Copy the header to the caller's buffer */
- ACPI_MEMCPY((void *)out_table_header, (void *)tbl_ptr,
+ ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
+ ACPI_CAST_PTR(void, tbl_ptr),
sizeof(struct acpi_table_header));
return_ACPI_STATUS(status);
@@ -344,10 +348,10 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to get an ACPI table. The caller
+ * DESCRIPTION: This function is called to get an ACPI table. The caller
* supplies an out_buffer large enough to contain the entire ACPI
- * table. The caller should call the acpi_get_table_header function
- * first to determine the buffer size needed. Upon completion
+ * table. The caller should call the acpi_get_table_header function
+ * first to determine the buffer size needed. Upon completion
* the out_buffer->Length field will indicate the number of bytes
* copied into the out_buffer->buf_ptr buffer. This table will be
* a complete table including the header.
@@ -417,7 +421,9 @@ acpi_get_table(acpi_table_type table_type,
/* Copy the table to the buffer */
- ACPI_MEMCPY((void *)ret_buffer->pointer, (void *)tbl_ptr, table_length);
+ ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
+ ACPI_CAST_PTR(void, tbl_ptr), table_length);
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index e7fe3a14fda..5753d06b786 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -162,7 +162,7 @@ struct acpi_thermal_flags {
};
struct acpi_thermal {
- acpi_handle handle;
+ struct acpi_device * device;
acpi_bus_id name;
unsigned long temperature;
unsigned long last_temperature;
@@ -176,21 +176,21 @@ struct acpi_thermal {
struct timer_list timer;
};
-static struct file_operations acpi_thermal_state_fops = {
+static const struct file_operations acpi_thermal_state_fops = {
.open = acpi_thermal_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_thermal_temp_fops = {
+static const struct file_operations acpi_thermal_temp_fops = {
.open = acpi_thermal_temp_open_fs,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
-static struct file_operations acpi_thermal_trip_fops = {
+static const struct file_operations acpi_thermal_trip_fops = {
.open = acpi_thermal_trip_open_fs,
.read = seq_read,
.write = acpi_thermal_write_trip_points,
@@ -198,7 +198,7 @@ static struct file_operations acpi_thermal_trip_fops = {
.release = single_release,
};
-static struct file_operations acpi_thermal_cooling_fops = {
+static const struct file_operations acpi_thermal_cooling_fops = {
.open = acpi_thermal_cooling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_cooling_mode,
@@ -206,7 +206,7 @@ static struct file_operations acpi_thermal_cooling_fops = {
.release = single_release,
};
-static struct file_operations acpi_thermal_polling_fops = {
+static const struct file_operations acpi_thermal_polling_fops = {
.open = acpi_thermal_polling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_polling,
@@ -222,51 +222,48 @@ static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_thermal_get_temperature");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
tz->last_temperature = tz->temperature;
status =
- acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature);
+ acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tz->temperature);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
tz->temperature));
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_thermal_get_polling_frequency");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
status =
- acpi_evaluate_integer(tz->handle, "_TZP", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_TZP", NULL,
&tz->polling_frequency);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
tz->polling_frequency));
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
{
- ACPI_FUNCTION_TRACE("acpi_thermal_set_polling");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
@@ -274,7 +271,7 @@ static int acpi_thermal_set_polling(struct acpi_thermal *tz, int seconds)
"Polling frequency set to %lu seconds\n",
tz->polling_frequency));
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
@@ -284,29 +281,28 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
struct acpi_object_list arg_list = { 1, &arg0 };
acpi_handle handle = NULL;
- ACPI_FUNCTION_TRACE("acpi_thermal_set_cooling_mode");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
- status = acpi_get_handle(tz->handle, "_SCP", &handle);
+ status = acpi_get_handle(tz->device->handle, "_SCP", &handle);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
arg0.integer.value = mode;
status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
tz->cooling_mode = mode;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
mode ? "passive" : "active"));
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
@@ -314,19 +310,18 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
acpi_status status = AE_OK;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_get_trip_points");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Critical Shutdown (required) */
- status = acpi_evaluate_integer(tz->handle, "_CRT", NULL,
+ status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
&tz->trips.critical.temperature);
if (ACPI_FAILURE(status)) {
tz->trips.critical.flags.valid = 0;
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n"));
- return_VALUE(-ENODEV);
+ ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
+ return -ENODEV;
} else {
tz->trips.critical.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -337,7 +332,7 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
/* Critical Sleep (optional) */
status =
- acpi_evaluate_integer(tz->handle, "_HOT", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
&tz->trips.hot.temperature);
if (ACPI_FAILURE(status)) {
tz->trips.hot.flags.valid = 0;
@@ -351,7 +346,7 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
/* Passive: Processors (optional) */
status =
- acpi_evaluate_integer(tz->handle, "_PSV", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_PSV", NULL,
&tz->trips.passive.temperature);
if (ACPI_FAILURE(status)) {
tz->trips.passive.flags.valid = 0;
@@ -360,32 +355,31 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
tz->trips.passive.flags.valid = 1;
status =
- acpi_evaluate_integer(tz->handle, "_TC1", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,
&tz->trips.passive.tc1);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status =
- acpi_evaluate_integer(tz->handle, "_TC2", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
&tz->trips.passive.tc2);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status =
- acpi_evaluate_integer(tz->handle, "_TSP", NULL,
+ acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
&tz->trips.passive.tsp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status =
- acpi_evaluate_reference(tz->handle, "_PSL", NULL,
+ acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
&tz->trips.passive.devices);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
if (!tz->trips.passive.flags.valid)
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid passive threshold\n"));
+ printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
else
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found passive threshold [%lu]\n",
@@ -399,14 +393,14 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
status =
- acpi_evaluate_integer(tz->handle, name, NULL,
+ acpi_evaluate_integer(tz->device->handle, name, NULL,
&tz->trips.active[i].temperature);
if (ACPI_FAILURE(status))
break;
name[2] = 'L';
status =
- acpi_evaluate_reference(tz->handle, name, NULL,
+ acpi_evaluate_reference(tz->device->handle, name, NULL,
&tz->trips.active[i].devices);
if (ACPI_SUCCESS(status)) {
tz->trips.active[i].flags.valid = 1;
@@ -414,29 +408,27 @@ static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
"Found active threshold [%d]:[%lu]\n",
i, tz->trips.active[i].temperature));
} else
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid active threshold [%d]\n",
- i));
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Invalid active threshold [%d]", i));
}
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_get_devices(struct acpi_thermal *tz)
{
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE("acpi_thermal_get_devices");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
status =
- acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices);
+ acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_call_usermode(char *path)
@@ -444,10 +436,9 @@ static int acpi_thermal_call_usermode(char *path)
char *argv[2] = { NULL, NULL };
char *envp[3] = { NULL, NULL, NULL };
- ACPI_FUNCTION_TRACE("acpi_thermal_call_usermode");
if (!path)
- return_VALUE(-EINVAL);
+ return -EINVAL;
argv[0] = path;
@@ -457,66 +448,48 @@ static int acpi_thermal_call_usermode(char *path)
call_usermodehelper(argv[0], argv, envp, 0);
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_critical(struct acpi_thermal *tz)
{
- int result = 0;
- struct acpi_device *device = NULL;
-
- ACPI_FUNCTION_TRACE("acpi_thermal_critical");
-
if (!tz || !tz->trips.critical.flags.valid)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n"));
+ printk(KERN_WARNING PREFIX "Critical trip point\n");
tz->trips.critical.flags.enabled = 1;
} else if (tz->trips.critical.flags.enabled)
tz->trips.critical.flags.enabled = 0;
- result = acpi_bus_get_device(tz->handle, &device);
- if (result)
- return_VALUE(result);
-
printk(KERN_EMERG
"Critical temperature reached (%ld C), shutting down.\n",
KELVIN_TO_CELSIUS(tz->temperature));
- acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL,
+ acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled);
acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_hot(struct acpi_thermal *tz)
{
- int result = 0;
- struct acpi_device *device = NULL;
-
- ACPI_FUNCTION_TRACE("acpi_thermal_hot");
-
if (!tz || !tz->trips.hot.flags.valid)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n"));
+ printk(KERN_WARNING PREFIX "Hot trip point\n");
tz->trips.hot.flags.enabled = 1;
} else if (tz->trips.hot.flags.enabled)
tz->trips.hot.flags.enabled = 0;
- result = acpi_bus_get_device(tz->handle, &device);
- if (result)
- return_VALUE(result);
-
- acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT,
+ acpi_bus_generate_event(tz->device, ACPI_THERMAL_NOTIFY_HOT,
tz->trips.hot.flags.enabled);
/* TBD: Call user-mode "sleep(S4)" function */
- return_VALUE(0);
+ return 0;
}
static void acpi_thermal_passive(struct acpi_thermal *tz)
@@ -526,7 +499,6 @@ static void acpi_thermal_passive(struct acpi_thermal *tz)
int trend = 0;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_passive");
if (!tz || !tz->trips.passive.flags.valid)
return;
@@ -615,7 +587,6 @@ static void acpi_thermal_active(struct acpi_thermal *tz)
int j = 0;
unsigned long maxtemp = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_active");
if (!tz)
return;
@@ -642,10 +613,10 @@ static void acpi_thermal_active(struct acpi_thermal *tz)
handles[j],
ACPI_STATE_D0);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Unable to turn cooling device [%p] 'on'\n",
- active->devices.
- handles[j]));
+ printk(KERN_WARNING PREFIX
+ "Unable to turn cooling device [%p] 'on'\n",
+ active->devices.
+ handles[j]);
continue;
}
active->flags.enabled = 1;
@@ -667,9 +638,9 @@ static void acpi_thermal_active(struct acpi_thermal *tz)
result = acpi_bus_set_power(active->devices.handles[j],
ACPI_STATE_D3);
if (result) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Unable to turn cooling device [%p] 'off'\n",
- active->devices.handles[j]));
+ printk(KERN_WARNING PREFIX
+ "Unable to turn cooling device [%p] 'off'\n",
+ active->devices.handles[j]);
continue;
}
active->flags.enabled = 0;
@@ -697,18 +668,17 @@ static void acpi_thermal_check(void *data)
int i = 0;
struct acpi_thermal_state state;
- ACPI_FUNCTION_TRACE("acpi_thermal_check");
if (!tz) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
- return_VOID;
+ printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
+ return;
}
state = tz->state;
result = acpi_thermal_get_temperature(tz);
if (result)
- return_VOID;
+ return;
memset(&tz->state, 0, sizeof(tz->state));
@@ -797,7 +767,7 @@ static void acpi_thermal_check(void *data)
}
}
- return_VOID;
+ return;
}
/* --------------------------------------------------------------------------
@@ -810,7 +780,6 @@ static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_thermal_state_seq_show");
if (!tz)
goto end;
@@ -833,7 +802,7 @@ static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
}
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
@@ -846,7 +815,6 @@ static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
int result = 0;
struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_thermal_temp_seq_show");
if (!tz)
goto end;
@@ -859,7 +827,7 @@ static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
KELVIN_TO_CELSIUS(tz->temperature));
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
@@ -873,7 +841,6 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
int i = 0;
int j = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_trip_seq_show");
if (!tz)
goto end;
@@ -913,7 +880,7 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
}
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
@@ -934,28 +901,25 @@ acpi_thermal_write_trip_points(struct file *file,
int *active;
int i = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points");
limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
if (!limit_string)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
active = kmalloc(ACPI_THERMAL_MAX_ACTIVE * sizeof(int), GFP_KERNEL);
if (!active) {
kfree(limit_string);
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
}
if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
count = -EINVAL;
goto end;
}
if (copy_from_user(limit_string, buffer, count)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
count = -EFAULT;
goto end;
}
@@ -968,7 +932,6 @@ acpi_thermal_write_trip_points(struct file *file,
&active[5], &active[6], &active[7], &active[8],
&active[9]);
if (!(num >= 5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
count = -EINVAL;
goto end;
}
@@ -985,14 +948,13 @@ acpi_thermal_write_trip_points(struct file *file,
end:
kfree(active);
kfree(limit_string);
- return_VALUE(count);
+ return count;
}
static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_thermal_cooling_seq_show");
if (!tz)
goto end;
@@ -1008,7 +970,7 @@ static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
tz->cooling_mode ? "passive" : "active");
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
@@ -1027,16 +989,15 @@ acpi_thermal_write_cooling_mode(struct file *file,
int result = 0;
char mode_string[12] = { '\0' };
- ACPI_FUNCTION_TRACE("acpi_thermal_write_cooling_mode");
if (!tz || (count > sizeof(mode_string) - 1))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (!tz->flags.cooling_mode)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (copy_from_user(mode_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
mode_string[count] = '\0';
@@ -1044,18 +1005,17 @@ acpi_thermal_write_cooling_mode(struct file *file,
simple_strtoul(mode_string, NULL,
0));
if (result)
- return_VALUE(result);
+ return result;
acpi_thermal_check(tz);
- return_VALUE(count);
+ return count;
}
static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_thermal_polling_seq_show");
if (!tz)
goto end;
@@ -1069,7 +1029,7 @@ static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
(tz->polling_frequency / 10));
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
@@ -1089,13 +1049,12 @@ acpi_thermal_write_polling(struct file *file,
char polling_string[12] = { '\0' };
int seconds = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_write_polling");
if (!tz || (count > sizeof(polling_string) - 1))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(polling_string, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
polling_string[count] = '\0';
@@ -1103,24 +1062,23 @@ acpi_thermal_write_polling(struct file *file,
result = acpi_thermal_set_polling(tz, seconds);
if (result)
- return_VALUE(result);
+ return result;
acpi_thermal_check(tz);
- return_VALUE(count);
+ return count;
}
static int acpi_thermal_add_fs(struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
- ACPI_FUNCTION_TRACE("acpi_thermal_add_fs");
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_thermal_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_device_dir(device)->owner = THIS_MODULE;
}
@@ -1128,9 +1086,7 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_THERMAL_FILE_STATE));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_thermal_state_fops;
entry->data = acpi_driver_data(device);
@@ -1141,9 +1097,7 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_THERMAL_FILE_TEMPERATURE));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_thermal_temp_fops;
entry->data = acpi_driver_data(device);
@@ -1155,9 +1109,7 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_THERMAL_FILE_TRIP_POINTS));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_thermal_trip_fops;
entry->data = acpi_driver_data(device);
@@ -1169,9 +1121,7 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_THERMAL_FILE_COOLING_MODE));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_thermal_cooling_fops;
entry->data = acpi_driver_data(device);
@@ -1183,21 +1133,18 @@ static int acpi_thermal_add_fs(struct acpi_device *device)
S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_THERMAL_FILE_POLLING_FREQ));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_thermal_polling_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_remove_fs(struct acpi_device *device)
{
- ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs");
if (acpi_device_dir(device)) {
remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
@@ -1214,7 +1161,7 @@ static int acpi_thermal_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -1226,13 +1173,11 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
struct acpi_thermal *tz = (struct acpi_thermal *)data;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_thermal_notify");
if (!tz)
- return_VOID;
+ return;
- if (acpi_bus_get_device(tz->handle, &device))
- return_VOID;
+ device = tz->device;
switch (event) {
case ACPI_THERMAL_NOTIFY_TEMPERATURE:
@@ -1254,27 +1199,26 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static int acpi_thermal_get_info(struct acpi_thermal *tz)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_get_info");
if (!tz)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Get temperature [_TMP] (required) */
result = acpi_thermal_get_temperature(tz);
if (result)
- return_VALUE(result);
+ return result;
/* Get trip points [_CRT, _PSV, etc.] (required) */
result = acpi_thermal_get_trip_points(tz);
if (result)
- return_VALUE(result);
+ return result;
/* Set the cooling mode [_SCP] to active cooling (default) */
result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
@@ -1314,7 +1258,7 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
if (!result)
tz->flags.devices = 1;
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_add(struct acpi_device *device)
@@ -1323,17 +1267,16 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_status status = AE_OK;
struct acpi_thermal *tz = NULL;
- ACPI_FUNCTION_TRACE("acpi_thermal_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
if (!tz)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(tz, 0, sizeof(struct acpi_thermal));
- tz->handle = device->handle;
+ tz->device = device;
strcpy(tz->name, device->pnp.bus_id);
strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
@@ -1351,12 +1294,10 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_thermal_check(tz);
- status = acpi_install_notify_handler(tz->handle,
+ status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify, tz);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error installing notify handler\n"));
result = -ENODEV;
goto end;
}
@@ -1371,7 +1312,7 @@ static int acpi_thermal_add(struct acpi_device *device)
kfree(tz);
}
- return_VALUE(result);
+ return result;
}
static int acpi_thermal_remove(struct acpi_device *device, int type)
@@ -1379,10 +1320,9 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
acpi_status status = AE_OK;
struct acpi_thermal *tz = NULL;
- ACPI_FUNCTION_TRACE("acpi_thermal_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
tz = (struct acpi_thermal *)acpi_driver_data(device);
@@ -1395,12 +1335,9 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
/* deferred task may reinsert timer */
del_timer_sync(&(tz->timer));
- status = acpi_remove_notify_handler(tz->handle,
+ status = acpi_remove_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_thermal_notify);
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
/* Terminate policy */
if (tz->trips.passive.flags.valid && tz->trips.passive.flags.enabled) {
@@ -1416,19 +1353,34 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
acpi_thermal_remove_fs(device);
kfree(tz);
- return_VALUE(0);
+ return 0;
}
static int acpi_thermal_resume(struct acpi_device *device, int state)
{
struct acpi_thermal *tz = NULL;
+ int i;
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
tz = (struct acpi_thermal *)acpi_driver_data(device);
- acpi_thermal_check(tz);
+ acpi_thermal_get_temperature(tz);
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ if (tz->trips.active[i].flags.valid) {
+ tz->temperature = tz->trips.active[i].temperature;
+ tz->trips.active[i].flags.enabled = 0;
+
+ acpi_thermal_active(tz);
+
+ tz->state.active |= tz->trips.active[i].flags.enabled;
+ tz->state.active_index = i;
+ }
+ }
+
+ acpi_thermal_check(tz);
return AE_OK;
}
@@ -1437,31 +1389,29 @@ static int __init acpi_thermal_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_thermal_init");
acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
if (!acpi_thermal_dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_thermal_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_thermal_driver);
if (result < 0) {
remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_thermal_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_thermal_exit");
acpi_bus_unregister_driver(&acpi_thermal_driver);
remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
module_init(acpi_thermal_init);
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 7940fc1bd69..f6cbc0b1bfd 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -166,10 +166,10 @@ acpi_status acpi_ut_delete_caches(void)
/* Free memory lists */
- acpi_os_free(acpi_gbl_global_list);
+ ACPI_FREE(acpi_gbl_global_list);
acpi_gbl_global_list = NULL;
- acpi_os_free(acpi_gbl_ns_node_list);
+ ACPI_FREE(acpi_gbl_ns_node_list);
acpi_gbl_ns_node_list = NULL;
#endif
@@ -285,6 +285,7 @@ acpi_ut_initialize_buffer(struct acpi_buffer * buffer,
return (status);
}
+#ifdef NOT_USED_BY_LINUX
/*******************************************************************************
*
* FUNCTION: acpi_ut_allocate
@@ -360,3 +361,4 @@ void *acpi_ut_allocate_zeroed(acpi_size size,
return (allocation);
}
+#endif
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 56270a30718..1a1f8109159 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -162,7 +162,7 @@ acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache)
/* Now we can delete the cache object */
- acpi_os_free(cache);
+ ACPI_FREE(cache);
return (AE_OK);
}
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 5ec1cfcc611..bb1eaf9aa65 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -47,7 +47,7 @@
ACPI_MODULE_NAME("utdebug")
#ifdef ACPI_DEBUG_OUTPUT
-static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF;
+static acpi_thread_id acpi_gbl_prev_thread_id;
static char *acpi_gbl_fn_entry_str = "----Entry";
static char *acpi_gbl_fn_exit_str = "----Exit-";
@@ -181,7 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
if (ACPI_LV_THREADS & acpi_dbg_level) {
acpi_os_printf
("\n**** Context Switch from TID %X to TID %X ****\n\n",
- acpi_gbl_prev_thread_id, thread_id);
+ (u32) acpi_gbl_prev_thread_id, (u32) thread_id);
}
acpi_gbl_prev_thread_id = thread_id;
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 67b9f325c6f..9d3f1149ba2 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -155,21 +155,30 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
case ACPI_TYPE_MUTEX:
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "***** Mutex %p, Semaphore %p\n",
- object, object->mutex.semaphore));
+ "***** Mutex %p, OS Mutex %p\n",
+ object, object->mutex.os_mutex));
- acpi_ex_unlink_mutex(object);
- (void)acpi_os_delete_semaphore(object->mutex.semaphore);
+ if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) {
+ acpi_ex_unlink_mutex(object);
+ acpi_os_delete_mutex(object->mutex.os_mutex);
+ } else {
+ /* Global Lock "mutex" is actually a counting semaphore */
+
+ (void)
+ acpi_os_delete_semaphore
+ (acpi_gbl_global_lock_semaphore);
+ acpi_gbl_global_lock_semaphore = NULL;
+ }
break;
case ACPI_TYPE_EVENT:
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
- "***** Event %p, Semaphore %p\n",
- object, object->event.semaphore));
+ "***** Event %p, OS Semaphore %p\n",
+ object, object->event.os_semaphore));
- (void)acpi_os_delete_semaphore(object->event.semaphore);
- object->event.semaphore = NULL;
+ (void)acpi_os_delete_semaphore(object->event.os_semaphore);
+ object->event.os_semaphore = NULL;
break;
case ACPI_TYPE_METHOD:
@@ -177,12 +186,13 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
"***** Method %p\n", object));
- /* Delete the method semaphore if it exists */
+ /* Delete the method mutex if it exists */
- if (object->method.semaphore) {
- (void)acpi_os_delete_semaphore(object->method.
- semaphore);
- object->method.semaphore = NULL;
+ if (object->method.mutex) {
+ acpi_os_delete_mutex(object->method.mutex->mutex.
+ os_mutex);
+ acpi_ut_delete_object_desc(object->method.mutex);
+ object->method.mutex = NULL;
}
break;
@@ -437,11 +447,16 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
*/
switch (ACPI_GET_OBJECT_TYPE(object)) {
case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_THERMAL:
+
+ /* Update the notify objects for these types (if present) */
- acpi_ut_update_ref_count(object->device.system_notify,
- action);
- acpi_ut_update_ref_count(object->device.device_notify,
- action);
+ acpi_ut_update_ref_count(object->common_notify.
+ system_notify, action);
+ acpi_ut_update_ref_count(object->common_notify.
+ device_notify, action);
break;
case ACPI_TYPE_PACKAGE:
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index e5999c65c0b..014030af8b5 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -794,6 +794,7 @@ void acpi_ut_init_globals(void)
/* Global Lock support */
+ acpi_gbl_global_lock_semaphore = NULL;
acpi_gbl_global_lock_acquired = FALSE;
acpi_gbl_global_lock_thread_count = 0;
acpi_gbl_global_lock_handle = 0;
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 5c75d35ad1c..6d8a8211be9 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -41,6 +41,8 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
+#include <linux/module.h>
+
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
@@ -63,7 +65,7 @@ ACPI_MODULE_NAME("utmisc")
u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
{
- /* Ignore tables that contain AML */
+ /* These are the only tables that contain executable AML */
if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
@@ -417,10 +419,15 @@ void acpi_ut_set_integer_width(u8 revision)
{
if (revision <= 1) {
+
+ /* 32-bit case */
+
acpi_gbl_integer_bit_width = 32;
acpi_gbl_integer_nybble_width = 8;
acpi_gbl_integer_byte_width = 4;
} else {
+ /* 64-bit case (ACPI 2.0+) */
+
acpi_gbl_integer_bit_width = 64;
acpi_gbl_integer_nybble_width = 16;
acpi_gbl_integer_byte_width = 8;
@@ -500,6 +507,7 @@ acpi_ut_display_init_pathname(u8 type,
* FUNCTION: acpi_ut_valid_acpi_char
*
* PARAMETERS: Char - The character to be examined
+ * Position - Byte position (0-3)
*
* RETURN: TRUE if the character is valid, FALSE otherwise
*
@@ -607,7 +615,9 @@ acpi_name acpi_ut_repair_name(acpi_name name)
*
* RETURN: Status and Converted value
*
- * DESCRIPTION: Convert a string into an unsigned value.
+ * DESCRIPTION: Convert a string into an unsigned value. Performs either a
+ * 32-bit or 64-bit conversion, depending on the current mode
+ * of the interpreter.
* NOTE: Does not support Octal strings, not needed.
*
******************************************************************************/
@@ -625,7 +635,7 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
u8 sign_of0x = 0;
u8 term = 0;
- ACPI_FUNCTION_TRACE(ut_stroul64);
+ ACPI_FUNCTION_TRACE_STR(ut_stroul64, string);
switch (base) {
case ACPI_ANY_BASE:
@@ -673,11 +683,13 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
}
}
+ /*
+ * Perform a 32-bit or 64-bit conversion, depending upon the current
+ * execution mode of the interpreter
+ */
dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX;
- /* At least one character in the string here */
-
- /* Main loop: convert the string to a 64-bit integer */
+ /* Main loop: convert the string to a 32- or 64-bit integer */
while (*string) {
if (ACPI_IS_DIGIT(*string)) {
@@ -752,6 +764,9 @@ acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer)
all_done:
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64(return_value)));
+
*ret_integer = return_value;
return_ACPI_STATUS(AE_OK);
@@ -962,6 +977,7 @@ acpi_ut_exception(char *module_name,
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
}
+EXPORT_SYMBOL(acpi_ut_exception);
void ACPI_INTERNAL_VAR_XFACE
acpi_ut_warning(char *module_name, u32 line_number, char *format, ...)
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 25eb34369af..c39062a047c 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -82,12 +82,9 @@ acpi_status acpi_ut_mutex_initialize(void)
/* Create the spinlocks for use at interrupt level */
- status = acpi_os_create_lock(&acpi_gbl_gpe_lock);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ spin_lock_init(acpi_gbl_gpe_lock);
+ spin_lock_init(acpi_gbl_hardware_lock);
- status = acpi_os_create_lock(&acpi_gbl_hardware_lock);
return_ACPI_STATUS(status);
}
@@ -146,9 +143,8 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
}
if (!acpi_gbl_mutex_info[mutex_id].mutex) {
- status = acpi_os_create_semaphore(1, 1,
- &acpi_gbl_mutex_info
- [mutex_id].mutex);
+ status =
+ acpi_os_create_mutex(&acpi_gbl_mutex_info[mutex_id].mutex);
acpi_gbl_mutex_info[mutex_id].thread_id =
ACPI_MUTEX_NOT_ACQUIRED;
acpi_gbl_mutex_info[mutex_id].use_count = 0;
@@ -171,7 +167,6 @@ static acpi_status acpi_ut_create_mutex(acpi_mutex_handle mutex_id)
static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
{
- acpi_status status;
ACPI_FUNCTION_TRACE_U32(ut_delete_mutex, mutex_id);
@@ -179,12 +174,12 @@ static acpi_status acpi_ut_delete_mutex(acpi_mutex_handle mutex_id)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_os_delete_semaphore(acpi_gbl_mutex_info[mutex_id].mutex);
+ acpi_os_delete_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
acpi_gbl_mutex_info[mutex_id].mutex = NULL;
acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
/*******************************************************************************
@@ -249,14 +244,14 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %X attempting to acquire Mutex [%s]\n",
- this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
+ (u32) this_thread_id, acpi_ut_get_mutex_name(mutex_id)));
- status = acpi_os_wait_semaphore(acpi_gbl_mutex_info[mutex_id].mutex,
- 1, ACPI_WAIT_FOREVER);
+ status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex,
+ ACPI_WAIT_FOREVER);
if (ACPI_SUCCESS(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
"Thread %X acquired Mutex [%s]\n",
- this_thread_id,
+ (u32) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
@@ -264,7 +259,7 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
} else {
ACPI_EXCEPTION((AE_INFO, status,
"Thread %X could not acquire Mutex [%X]",
- this_thread_id, mutex_id));
+ (u32) this_thread_id, mutex_id));
}
return (status);
@@ -284,14 +279,13 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id)
acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
{
- acpi_status status;
acpi_thread_id this_thread_id;
ACPI_FUNCTION_NAME(ut_release_mutex);
this_thread_id = acpi_os_get_thread_id();
ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X releasing Mutex [%s]\n", this_thread_id,
+ "Thread %X releasing Mutex [%s]\n", (u32) this_thread_id,
acpi_ut_get_mutex_name(mutex_id)));
if (mutex_id > ACPI_MAX_MUTEX) {
@@ -340,19 +334,6 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id)
acpi_gbl_mutex_info[mutex_id].thread_id = ACPI_MUTEX_NOT_ACQUIRED;
- status =
- acpi_os_signal_semaphore(acpi_gbl_mutex_info[mutex_id].mutex, 1);
-
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Thread %X could not release Mutex [%X]",
- this_thread_id, mutex_id));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
- "Thread %X released Mutex [%s]\n",
- this_thread_id,
- acpi_ut_get_mutex_name(mutex_id)));
- }
-
- return (status);
+ acpi_os_release_mutex(acpi_gbl_mutex_info[mutex_id].mutex);
+ return (AE_OK);
}
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index 0f5c5bb5def..eaa13d05c85 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -199,6 +199,13 @@ struct acpi_thread_state *acpi_ut_create_thread_state(void)
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_THREAD;
state->thread.thread_id = acpi_os_get_thread_id();
+ /* Check for invalid thread ID - zero is very bad, it will break things */
+
+ if (!state->thread.thread_id) {
+ ACPI_ERROR((AE_INFO, "Invalid zero ID from AcpiOsGetThreadId"));
+ state->thread.thread_id = (acpi_thread_id) 1;
+ }
+
return_PTR((struct acpi_thread_state *)state);
}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 6b516852ac1..d0d84c43a9d 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -58,31 +58,29 @@ acpi_extract_package(union acpi_object *package,
u8 *head = NULL;
u8 *tail = NULL;
- ACPI_FUNCTION_TRACE("acpi_extract_package");
if (!package || (package->type != ACPI_TYPE_PACKAGE)
|| (package->package.count < 1)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid 'package' argument\n"));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ printk(KERN_WARNING PREFIX "Invalid package argument\n");
+ return AE_BAD_PARAMETER;
}
if (!format || !format->pointer || (format->length < 1)) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n"));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ printk(KERN_WARNING PREFIX "Invalid format argument\n");
+ return AE_BAD_PARAMETER;
}
if (!buffer) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n"));
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ printk(KERN_WARNING PREFIX "Invalid buffer argument\n");
+ return AE_BAD_PARAMETER;
}
format_count = (format->length / sizeof(char)) - 1;
if (format_count > package->package.count) {
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Format specifies more objects [%d] than exist in package [%d].",
- format_count, package->package.count));
- return_ACPI_STATUS(AE_BAD_DATA);
+ printk(KERN_WARNING PREFIX "Format specifies more objects [%d]"
+ " than exist in package [%d].\n",
+ format_count, package->package.count);
+ return AE_BAD_DATA;
}
format_string = (char *)format->pointer;
@@ -95,7 +93,7 @@ acpi_extract_package(union acpi_object *package,
union acpi_object *element = &(package->package.elements[i]);
if (!element) {
- return_ACPI_STATUS(AE_BAD_DATA);
+ return AE_BAD_DATA;
}
switch (element->type) {
@@ -113,10 +111,11 @@ acpi_extract_package(union acpi_object *package,
tail_offset += sizeof(char *);
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid package element [%d]: got number, expecing [%c].\n",
- i, format_string[i]));
- return_ACPI_STATUS(AE_BAD_DATA);
+ printk(KERN_WARNING PREFIX "Invalid package element"
+ " [%d]: got number, expecing"
+ " [%c]\n",
+ i, format_string[i]);
+ return AE_BAD_DATA;
break;
}
break;
@@ -138,10 +137,11 @@ acpi_extract_package(union acpi_object *package,
tail_offset += sizeof(u8 *);
break;
default:
- ACPI_DEBUG_PRINT((ACPI_DB_WARN,
- "Invalid package element [%d] got string/buffer, expecing [%c].\n",
- i, format_string[i]));
- return_ACPI_STATUS(AE_BAD_DATA);
+ printk(KERN_WARNING PREFIX "Invalid package element"
+ " [%d] got string/buffer,"
+ " expecing [%c]\n",
+ i, format_string[i]);
+ return AE_BAD_DATA;
break;
}
break;
@@ -152,7 +152,7 @@ acpi_extract_package(union acpi_object *package,
"Found unsupported element at index=%d\n",
i));
/* TBD: handle nested packages... */
- return_ACPI_STATUS(AE_SUPPORT);
+ return AE_SUPPORT;
break;
}
}
@@ -162,9 +162,9 @@ acpi_extract_package(union acpi_object *package,
*/
if (buffer->length < size_required) {
buffer->length = size_required;
- return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
+ return AE_BUFFER_OVERFLOW;
} else if (buffer->length != size_required || !buffer->pointer) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
}
head = buffer->pointer;
@@ -179,7 +179,7 @@ acpi_extract_package(union acpi_object *package,
union acpi_object *element = &(package->package.elements[i]);
if (!element) {
- return_ACPI_STATUS(AE_BAD_DATA);
+ return AE_BAD_DATA;
}
switch (element->type) {
@@ -244,7 +244,7 @@ acpi_extract_package(union acpi_object *package,
}
}
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
EXPORT_SYMBOL(acpi_extract_package);
@@ -258,14 +258,13 @@ acpi_evaluate_integer(acpi_handle handle,
union acpi_object *element;
struct acpi_buffer buffer = { 0, NULL };
- ACPI_FUNCTION_TRACE("acpi_evaluate_integer");
if (!data)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
- element = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+ element = kmalloc(sizeof(union acpi_object), irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
if (!element)
- return_ACPI_STATUS(AE_NO_MEMORY);
+ return AE_NO_MEMORY;
memset(element, 0, sizeof(union acpi_object));
buffer.length = sizeof(union acpi_object);
@@ -274,13 +273,13 @@ acpi_evaluate_integer(acpi_handle handle,
if (ACPI_FAILURE(status)) {
acpi_util_eval_error(handle, pathname, status);
kfree(element);
- return_ACPI_STATUS(status);
+ return status;
}
if (element->type != ACPI_TYPE_INTEGER) {
acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
kfree(element);
- return_ACPI_STATUS(AE_BAD_DATA);
+ return AE_BAD_DATA;
}
*data = element->integer.value;
@@ -288,7 +287,7 @@ acpi_evaluate_integer(acpi_handle handle,
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data));
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
EXPORT_SYMBOL(acpi_evaluate_integer);
@@ -303,15 +302,14 @@ acpi_evaluate_string(acpi_handle handle,
acpi_object *element = NULL;
acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- ACPI_FUNCTION_TRACE("acpi_evaluate_string");
if (!data)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
if (ACPI_FAILURE(status)) {
acpi_util_eval_error(handle, pathname, status);
- return_ACPI_STATUS(status);
+ return status;
}
element = (acpi_object *) buffer.pointer;
@@ -320,13 +318,13 @@ acpi_evaluate_string(acpi_handle handle,
|| (element->type != ACPI_TYPE_BUFFER)
|| !element->string.length) {
acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
- return_ACPI_STATUS(AE_BAD_DATA);
+ return AE_BAD_DATA;
}
*data = kmalloc(element->string.length + 1, GFP_KERNEL);
if (!data) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
- return_VALUE(-ENOMEM);
+ printk(KERN_ERR PREFIX "Memory allocation\n");
+ return -ENOMEM;
}
memset(*data, 0, element->string.length + 1);
@@ -334,9 +332,9 @@ acpi_evaluate_string(acpi_handle handle,
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data));
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
- return_ACPI_STATUS(AE_OK);
+ return AE_OK;
}
#endif
@@ -352,10 +350,9 @@ acpi_evaluate_reference(acpi_handle handle,
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
u32 i = 0;
- ACPI_FUNCTION_TRACE("acpi_evaluate_reference");
if (!list) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ return AE_BAD_PARAMETER;
}
/* Evaluate object. */
@@ -367,32 +364,29 @@ acpi_evaluate_reference(acpi_handle handle,
package = (union acpi_object *)buffer.pointer;
if ((buffer.length == 0) || !package) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "No return object (len %X ptr %p)\n",
- (unsigned)buffer.length, package));
+ printk(KERN_ERR PREFIX "No return object (len %X ptr %p)\n",
+ (unsigned)buffer.length, package);
status = AE_BAD_DATA;
acpi_util_eval_error(handle, pathname, status);
goto end;
}
if (package->type != ACPI_TYPE_PACKAGE) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Expecting a [Package], found type %X\n",
- package->type));
+ printk(KERN_ERR PREFIX "Expecting a [Package], found type %X\n",
+ package->type);
status = AE_BAD_DATA;
acpi_util_eval_error(handle, pathname, status);
goto end;
}
if (!package->package.count) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "[Package] has zero elements (%p)\n",
- package));
+ printk(KERN_ERR PREFIX "[Package] has zero elements (%p)\n",
+ package);
status = AE_BAD_DATA;
acpi_util_eval_error(handle, pathname, status);
goto end;
}
if (package->package.count > ACPI_MAX_HANDLES) {
- return_ACPI_STATUS(AE_NO_MEMORY);
+ return AE_NO_MEMORY;
}
list->count = package->package.count;
@@ -404,9 +398,9 @@ acpi_evaluate_reference(acpi_handle handle,
if (element->type != ACPI_TYPE_ANY) {
status = AE_BAD_DATA;
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Expecting a [Reference] package element, found type %X\n",
- element->type));
+ printk(KERN_ERR PREFIX
+ "Expecting a [Reference] package element, found type %X\n",
+ element->type);
acpi_util_eval_error(handle, pathname, status);
break;
}
@@ -424,9 +418,9 @@ acpi_evaluate_reference(acpi_handle handle,
//kfree(list->handles);
}
- acpi_os_free(buffer.pointer);
+ kfree(buffer.pointer);
- return_ACPI_STATUS(status);
+ return status;
}
EXPORT_SYMBOL(acpi_evaluate_reference);
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index e7e9a693953..56666a98247 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -117,7 +117,7 @@ struct acpi_video_enumerated_device {
};
struct acpi_video_bus {
- acpi_handle handle;
+ struct acpi_device *device;
u8 dos_setting;
struct acpi_video_enumerated_device *attached_array;
u8 attached_count;
@@ -155,7 +155,6 @@ struct acpi_video_device_brightness {
};
struct acpi_video_device {
- acpi_handle handle;
unsigned long device_id;
struct acpi_video_device_flags flags;
struct acpi_video_device_cap cap;
@@ -272,10 +271,10 @@ static int
acpi_video_device_query(struct acpi_video_device *device, unsigned long *state)
{
int status;
- ACPI_FUNCTION_TRACE("acpi_video_device_query");
- status = acpi_evaluate_integer(device->handle, "_DGS", NULL, state);
- return_VALUE(status);
+ status = acpi_evaluate_integer(device->dev->handle, "_DGS", NULL, state);
+
+ return status;
}
static int
@@ -284,11 +283,9 @@ acpi_video_device_get_state(struct acpi_video_device *device,
{
int status;
- ACPI_FUNCTION_TRACE("acpi_video_device_get_state");
-
- status = acpi_evaluate_integer(device->handle, "_DCS", NULL, state);
+ status = acpi_evaluate_integer(device->dev->handle, "_DCS", NULL, state);
- return_VALUE(status);
+ return status;
}
static int
@@ -299,12 +296,11 @@ acpi_video_device_set_state(struct acpi_video_device *device, int state)
struct acpi_object_list args = { 1, &arg0 };
unsigned long ret;
- ACPI_FUNCTION_TRACE("acpi_video_device_set_state");
arg0.integer.value = state;
- status = acpi_evaluate_integer(device->handle, "_DSS", &args, &ret);
+ status = acpi_evaluate_integer(device->dev->handle, "_DSS", &args, &ret);
- return_VALUE(status);
+ return status;
}
static int
@@ -315,28 +311,27 @@ acpi_video_device_lcd_query_levels(struct acpi_video_device *device,
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
- ACPI_FUNCTION_TRACE("acpi_video_device_lcd_query_levels");
*levels = NULL;
- status = acpi_evaluate_object(device->handle, "_BCL", NULL, &buffer);
+ status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer);
if (!ACPI_SUCCESS(status))
- return_VALUE(status);
+ return status;
obj = (union acpi_object *)buffer.pointer;
if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
+ printk(KERN_ERR PREFIX "Invalid _BCL data\n");
status = -EFAULT;
goto err;
}
*levels = obj;
- return_VALUE(0);
+ return 0;
err:
kfree(buffer.pointer);
- return_VALUE(status);
+ return status;
}
static int
@@ -346,13 +341,12 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
- ACPI_FUNCTION_TRACE("acpi_video_device_lcd_set_level");
arg0.integer.value = level;
- status = acpi_evaluate_object(device->handle, "_BCM", &args, NULL);
+ status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL);
printk(KERN_DEBUG "set_level status: %x\n", status);
- return_VALUE(status);
+ return status;
}
static int
@@ -360,11 +354,10 @@ acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
unsigned long *level)
{
int status;
- ACPI_FUNCTION_TRACE("acpi_video_device_lcd_get_level_current");
- status = acpi_evaluate_integer(device->handle, "_BQC", NULL, level);
+ status = acpi_evaluate_integer(device->dev->handle, "_BQC", NULL, level);
- return_VALUE(status);
+ return status;
}
static int
@@ -377,34 +370,33 @@ acpi_video_device_EDID(struct acpi_video_device *device,
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
- ACPI_FUNCTION_TRACE("acpi_video_device_get_EDID");
*edid = NULL;
if (!device)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (length == 128)
arg0.integer.value = 1;
else if (length == 256)
arg0.integer.value = 2;
else
- return_VALUE(-EINVAL);
+ return -EINVAL;
- status = acpi_evaluate_object(device->handle, "_DDC", &args, &buffer);
+ status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
if (ACPI_FAILURE(status))
- return_VALUE(-ENODEV);
+ return -ENODEV;
obj = (union acpi_object *)buffer.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER)
*edid = obj;
else {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DDC data\n"));
+ printk(KERN_ERR PREFIX "Invalid _DDC data\n");
status = -EFAULT;
kfree(obj);
}
- return_VALUE(status);
+ return status;
}
/* bus */
@@ -417,15 +409,14 @@ acpi_video_bus_set_POST(struct acpi_video_bus *video, unsigned long option)
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
- ACPI_FUNCTION_TRACE("acpi_video_bus_set_POST");
arg0.integer.value = option;
- status = acpi_evaluate_integer(video->handle, "_SPD", &args, &tmp);
+ status = acpi_evaluate_integer(video->device->handle, "_SPD", &args, &tmp);
if (ACPI_SUCCESS(status))
status = tmp ? (-EINVAL) : (AE_OK);
- return_VALUE(status);
+ return status;
}
static int
@@ -433,11 +424,9 @@ acpi_video_bus_get_POST(struct acpi_video_bus *video, unsigned long *id)
{
int status;
- ACPI_FUNCTION_TRACE("acpi_video_bus_get_POST");
-
- status = acpi_evaluate_integer(video->handle, "_GPD", NULL, id);
+ status = acpi_evaluate_integer(video->device->handle, "_GPD", NULL, id);
- return_VALUE(status);
+ return status;
}
static int
@@ -445,12 +434,11 @@ acpi_video_bus_POST_options(struct acpi_video_bus *video,
unsigned long *options)
{
int status;
- ACPI_FUNCTION_TRACE("acpi_video_bus_POST_options");
- status = acpi_evaluate_integer(video->handle, "_VPO", NULL, options);
+ status = acpi_evaluate_integer(video->device->handle, "_VPO", NULL, options);
*options &= 3;
- return_VALUE(status);
+ return status;
}
/*
@@ -481,7 +469,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
union acpi_object arg0 = { ACPI_TYPE_INTEGER };
struct acpi_object_list args = { 1, &arg0 };
- ACPI_FUNCTION_TRACE("acpi_video_bus_DOS");
if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1) {
status = -1;
@@ -489,10 +476,10 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
}
arg0.integer.value = (lcd_flag << 2) | bios_flag;
video->dos_setting = arg0.integer.value;
- acpi_evaluate_object(video->handle, "_DOS", &args, NULL);
+ acpi_evaluate_object(video->device->handle, "_DOS", &args, NULL);
Failed:
- return_VALUE(status);
+ return status;
}
/*
@@ -514,29 +501,28 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
union acpi_object *obj = NULL;
struct acpi_video_device_brightness *br = NULL;
- ACPI_FUNCTION_TRACE("acpi_video_device_find_cap");
memset(&device->cap, 0, 4);
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ADR", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_ADR", &h_dummy1))) {
device->cap._ADR = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCL", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCL", &h_dummy1))) {
device->cap._BCL = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCM", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
device->cap._BCM = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DDC", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
device->cap._DDC = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DCS", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DCS", &h_dummy1))) {
device->cap._DCS = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DGS", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DGS", &h_dummy1))) {
device->cap._DGS = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DSS", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DSS", &h_dummy1))) {
device->cap._DSS = 1;
}
@@ -560,8 +546,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
o = (union acpi_object *)&obj->package.
elements[i];
if (o->type != ACPI_TYPE_INTEGER) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid data\n"));
+ printk(KERN_ERR PREFIX "Invalid data\n");
continue;
}
br->levels[count] = (u32) o->integer.value;
@@ -583,7 +568,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj);
- return_VOID;
+ return;
}
/*
@@ -601,22 +586,22 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
acpi_handle h_dummy1;
memset(&video->cap, 0, 4);
- if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOS", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOS", &h_dummy1))) {
video->cap._DOS = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOD", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_DOD", &h_dummy1))) {
video->cap._DOD = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_ROM", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_ROM", &h_dummy1))) {
video->cap._ROM = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_GPD", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_GPD", &h_dummy1))) {
video->cap._GPD = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_SPD", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_SPD", &h_dummy1))) {
video->cap._SPD = 1;
}
- if (ACPI_SUCCESS(acpi_get_handle(video->handle, "_VPO", &h_dummy1))) {
+ if (ACPI_SUCCESS(acpi_get_handle(video->device->handle, "_VPO", &h_dummy1))) {
video->cap._VPO = 1;
}
}
@@ -630,10 +615,9 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
{
acpi_status status = -ENOENT;
- ACPI_FUNCTION_TRACE("acpi_video_bus_check");
if (!video)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Since there is no HID, CID and so on for VGA driver, we have
* to check well known required nodes.
@@ -657,7 +641,7 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
status = 0;
}
- return_VALUE(status);
+ return status;
}
/* --------------------------------------------------------------------------
@@ -673,7 +657,6 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
struct acpi_video_device *dev =
(struct acpi_video_device *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_video_device_info_seq_show");
if (!dev)
goto end;
@@ -692,7 +675,7 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "known by bios: %s\n", dev->flags.bios ? "yes" : "no");
end:
- return_VALUE(0);
+ return 0;
}
static int
@@ -709,7 +692,6 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
(struct acpi_video_device *)seq->private;
unsigned long state;
- ACPI_FUNCTION_TRACE("acpi_video_device_state_seq_show");
if (!dev)
goto end;
@@ -729,7 +711,7 @@ static int acpi_video_device_state_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "<not supported>\n");
end:
- return_VALUE(0);
+ return 0;
}
static int
@@ -750,13 +732,12 @@ acpi_video_device_write_state(struct file *file,
char str[12] = { 0 };
u32 state = 0;
- ACPI_FUNCTION_TRACE("acpi_video_device_write_state");
if (!dev || count + 1 > sizeof str)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(str, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
str[count] = 0;
state = simple_strtoul(str, NULL, 0);
@@ -765,9 +746,9 @@ acpi_video_device_write_state(struct file *file,
status = acpi_video_device_set_state(dev, state);
if (status)
- return_VALUE(-EFAULT);
+ return -EFAULT;
- return_VALUE(count);
+ return count;
}
static int
@@ -777,11 +758,10 @@ acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
(struct acpi_video_device *)seq->private;
int i;
- ACPI_FUNCTION_TRACE("acpi_video_device_brightness_seq_show");
if (!dev || !dev->brightness) {
seq_printf(seq, "<not supported>\n");
- return_VALUE(0);
+ return 0;
}
seq_printf(seq, "levels: ");
@@ -789,7 +769,7 @@ acpi_video_device_brightness_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, " %d", dev->brightness->levels[i]);
seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
- return_VALUE(0);
+ return 0;
}
static int
@@ -810,19 +790,18 @@ acpi_video_device_write_brightness(struct file *file,
unsigned int level = 0;
int i;
- ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness");
if (!dev || !dev->brightness || count + 1 > sizeof str)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(str, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
str[count] = 0;
level = simple_strtoul(str, NULL, 0);
if (level > 100)
- return_VALUE(-EFAULT);
+ return -EFAULT;
/* validate though the list of available levels */
for (i = 0; i < dev->brightness->count; i++)
@@ -833,7 +812,7 @@ acpi_video_device_write_brightness(struct file *file,
break;
}
- return_VALUE(count);
+ return count;
}
static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
@@ -844,7 +823,6 @@ static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
int i;
union acpi_object *edid = NULL;
- ACPI_FUNCTION_TRACE("acpi_video_device_EDID_seq_show");
if (!dev)
goto out;
@@ -869,7 +847,7 @@ static int acpi_video_device_EDID_seq_show(struct seq_file *seq, void *offset)
else
kfree(edid);
- return_VALUE(0);
+ return 0;
}
static int
@@ -884,28 +862,26 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
struct proc_dir_entry *entry = NULL;
struct acpi_video_device *vid_dev;
- ACPI_FUNCTION_TRACE("acpi_video_device_add_fs");
if (!device)
- return_VALUE(-ENODEV);
+ return -ENODEV;
vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
if (!vid_dev)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
vid_dev->video->dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_device_dir(device)->owner = THIS_MODULE;
}
/* 'info' [R] */
entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'info' fs entry\n"));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_video_device_info_fops;
entry->data = acpi_driver_data(device);
@@ -917,8 +893,7 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'state' fs entry\n"));
+ return -ENODEV;
else {
acpi_video_device_state_fops.write = acpi_video_device_write_state;
entry->proc_fops = &acpi_video_device_state_fops;
@@ -931,8 +906,7 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'brightness' fs entry\n"));
+ return -ENODEV;
else {
acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
entry->proc_fops = &acpi_video_device_brightness_fops;
@@ -943,25 +917,23 @@ static int acpi_video_device_add_fs(struct acpi_device *device)
/* 'EDID' [R] */
entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'brightness' fs entry\n"));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_video_device_EDID_fops;
entry->data = acpi_driver_data(device);
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_video_device_remove_fs(struct acpi_device *device)
{
struct acpi_video_device *vid_dev;
- ACPI_FUNCTION_TRACE("acpi_video_device_remove_fs");
vid_dev = (struct acpi_video_device *)acpi_driver_data(device);
if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
if (acpi_device_dir(device)) {
remove_proc_entry("info", acpi_device_dir(device));
@@ -972,7 +944,7 @@ static int acpi_video_device_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* video bus */
@@ -980,7 +952,6 @@ static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_video_bus_info_seq_show");
if (!video)
goto end;
@@ -993,7 +964,7 @@ static int acpi_video_bus_info_seq_show(struct seq_file *seq, void *offset)
video->flags.post ? "yes" : "no");
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file)
@@ -1006,7 +977,6 @@ static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_video_bus_ROM_seq_show");
if (!video)
goto end;
@@ -1015,7 +985,7 @@ static int acpi_video_bus_ROM_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "<TODO>\n");
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file)
@@ -1029,7 +999,6 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
unsigned long options;
int status;
- ACPI_FUNCTION_TRACE("acpi_video_bus_POST_info_seq_show");
if (!video)
goto end;
@@ -1052,7 +1021,7 @@ static int acpi_video_bus_POST_info_seq_show(struct seq_file *seq, void *offset)
} else
seq_printf(seq, "<not supported>\n");
end:
- return_VALUE(0);
+ return 0;
}
static int
@@ -1068,7 +1037,6 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
int status;
unsigned long id;
- ACPI_FUNCTION_TRACE("acpi_video_bus_POST_seq_show");
if (!video)
goto end;
@@ -1081,18 +1049,17 @@ static int acpi_video_bus_POST_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "device posted is <%s>\n", device_decode[id & 3]);
end:
- return_VALUE(0);
+ return 0;
}
static int acpi_video_bus_DOS_seq_show(struct seq_file *seq, void *offset)
{
struct acpi_video_bus *video = (struct acpi_video_bus *)seq->private;
- ACPI_FUNCTION_TRACE("acpi_video_bus_DOS_seq_show");
seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting);
- return_VALUE(0);
+ return 0;
}
static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file)
@@ -1117,22 +1084,21 @@ acpi_video_bus_write_POST(struct file *file,
char str[12] = { 0 };
unsigned long opt, options;
- ACPI_FUNCTION_TRACE("acpi_video_bus_write_POST");
if (!video || count + 1 > sizeof str)
- return_VALUE(-EINVAL);
+ return -EINVAL;
status = acpi_video_bus_POST_options(video, &options);
if (!ACPI_SUCCESS(status))
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(str, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
str[count] = 0;
opt = strtoul(str, NULL, 0);
if (opt > 3)
- return_VALUE(-EFAULT);
+ return -EFAULT;
/* just in case an OEM 'forget' the motherboard... */
options |= 1;
@@ -1140,11 +1106,11 @@ acpi_video_bus_write_POST(struct file *file,
if (options & (1ul << opt)) {
status = acpi_video_bus_set_POST(video, opt);
if (!ACPI_SUCCESS(status))
- return_VALUE(-EFAULT);
+ return -EFAULT;
}
- return_VALUE(count);
+ return count;
}
static ssize_t
@@ -1158,25 +1124,24 @@ acpi_video_bus_write_DOS(struct file *file,
char str[12] = { 0 };
unsigned long opt;
- ACPI_FUNCTION_TRACE("acpi_video_bus_write_DOS");
if (!video || count + 1 > sizeof str)
- return_VALUE(-EINVAL);
+ return -EINVAL;
if (copy_from_user(str, buffer, count))
- return_VALUE(-EFAULT);
+ return -EFAULT;
str[count] = 0;
opt = strtoul(str, NULL, 0);
if (opt > 7)
- return_VALUE(-EFAULT);
+ return -EFAULT;
status = acpi_video_bus_DOS(video, opt & 0x3, (opt & 0x4) >> 2);
if (!ACPI_SUCCESS(status))
- return_VALUE(-EFAULT);
+ return -EFAULT;
- return_VALUE(count);
+ return count;
}
static int acpi_video_bus_add_fs(struct acpi_device *device)
@@ -1184,7 +1149,6 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
struct proc_dir_entry *entry = NULL;
struct acpi_video_bus *video;
- ACPI_FUNCTION_TRACE("acpi_video_bus_add_fs");
video = (struct acpi_video_bus *)acpi_driver_data(device);
@@ -1192,7 +1156,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
acpi_video_dir);
if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
+ return -ENODEV;
video->dir = acpi_device_dir(device);
acpi_device_dir(device)->owner = THIS_MODULE;
}
@@ -1200,8 +1164,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
/* 'info' [R] */
entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'info' fs entry\n"));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_video_bus_info_fops;
entry->data = acpi_driver_data(device);
@@ -1211,8 +1174,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
/* 'ROM' [R] */
entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'ROM' fs entry\n"));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_video_bus_ROM_fops;
entry->data = acpi_driver_data(device);
@@ -1223,8 +1185,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
entry =
create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'POST_info' fs entry\n"));
+ return -ENODEV;
else {
entry->proc_fops = &acpi_video_bus_POST_info_fops;
entry->data = acpi_driver_data(device);
@@ -1236,8 +1197,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'POST' fs entry\n"));
+ return -ENODEV;
else {
acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
entry->proc_fops = &acpi_video_bus_POST_fops;
@@ -1250,8 +1210,7 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
acpi_device_dir(device));
if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create 'DOS' fs entry\n"));
+ return -ENODEV;
else {
acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
entry->proc_fops = &acpi_video_bus_DOS_fops;
@@ -1259,14 +1218,13 @@ static int acpi_video_bus_add_fs(struct acpi_device *device)
entry->owner = THIS_MODULE;
}
- return_VALUE(0);
+ return 0;
}
static int acpi_video_bus_remove_fs(struct acpi_device *device)
{
struct acpi_video_bus *video;
- ACPI_FUNCTION_TRACE("acpi_video_bus_remove_fs");
video = (struct acpi_video_bus *)acpi_driver_data(device);
@@ -1280,7 +1238,7 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
acpi_device_dir(device) = NULL;
}
- return_VALUE(0);
+ return 0;
}
/* --------------------------------------------------------------------------
@@ -1297,10 +1255,9 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
int status;
struct acpi_video_device *data;
- ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
if (!device || !video)
- return_VALUE(-EINVAL);
+ return -EINVAL;
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
@@ -1308,11 +1265,10 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
if (!data)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(data, 0, sizeof(struct acpi_video_device));
- data->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
acpi_driver_data(device) = data;
@@ -1339,7 +1295,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
acpi_video_device_bind(video, data);
acpi_video_device_find_cap(data);
- status = acpi_install_notify_handler(data->handle,
+ status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify,
data);
@@ -1359,10 +1315,10 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
acpi_video_device_add_fs(device);
- return_VALUE(0);
+ return 0;
}
- return_VALUE(-ENOENT);
+ return -ENOENT;
}
/*
@@ -1405,7 +1361,6 @@ acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device)
{
int i;
- ACPI_FUNCTION_TRACE("acpi_video_device_bind");
#define IDS_VAL(i) video->attached_array[i].value.int_val
#define IDS_BIND(i) video->attached_array[i].bind_info
@@ -1442,17 +1397,15 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
union acpi_object *dod = NULL;
union acpi_object *obj;
- ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
-
- status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
+ status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
if (!ACPI_SUCCESS(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
- return_VALUE(status);
+ ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
+ return status;
}
dod = (union acpi_object *)buffer.pointer;
if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
status = -EFAULT;
goto out;
}
@@ -1476,8 +1429,7 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
obj = (union acpi_object *)&dod->package.elements[i];
if (obj->type != ACPI_TYPE_INTEGER) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Invalid _DOD data\n"));
+ printk(KERN_ERR PREFIX "Invalid _DOD data\n");
active_device_list[i].value.int_val =
ACPI_VIDEO_HEAD_INVALID;
}
@@ -1494,8 +1446,8 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
video->attached_array = active_device_list;
video->attached_count = count;
out:
- acpi_os_free(buffer.pointer);
- return_VALUE(status);
+ kfree(buffer.pointer);
+ return status;
}
/*
@@ -1520,7 +1472,6 @@ static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
unsigned long state;
int status = 0;
- ACPI_FUNCTION_TRACE("acpi_video_switch_output");
list_for_each_safe(node, next, &video->video_device_list) {
dev = container_of(node, struct acpi_video_device, entry);
@@ -1551,7 +1502,7 @@ static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
break;
}
- return_VALUE(status);
+ return status;
}
static int
@@ -1578,7 +1529,6 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
int status = 0;
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_video_get_devices");
acpi_video_device_enumerate(video);
@@ -1591,13 +1541,12 @@ acpi_video_bus_get_devices(struct acpi_video_bus *video,
status = acpi_video_bus_get_one_device(dev, video);
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Cant attach device\n"));
+ ACPI_EXCEPTION((AE_INFO, status, "Cant attach device"));
continue;
}
}
- return_VALUE(status);
+ return status;
}
static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
@@ -1605,10 +1554,9 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
acpi_status status;
struct acpi_video_bus *video;
- ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
if (!device || !device->video)
- return_VALUE(-ENOENT);
+ return -ENOENT;
video = device->video;
@@ -1617,14 +1565,11 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
up(&video->sem);
acpi_video_device_remove_fs(device->dev);
- status = acpi_remove_notify_handler(device->handle,
+ status = acpi_remove_notify_handler(device->dev->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_device_notify);
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
- return_VALUE(0);
+ return 0;
}
static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
@@ -1632,7 +1577,6 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
int status;
struct list_head *node, *next;
- ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
list_for_each_safe(node, next, &video->video_device_list) {
struct acpi_video_device *data =
@@ -1651,7 +1595,7 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
kfree(data);
}
- return_VALUE(0);
+ return 0;
}
/* acpi_video interface */
@@ -1671,14 +1615,12 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
struct acpi_video_bus *video = (struct acpi_video_bus *)data;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
printk("video bus notify\n");
if (!video)
- return_VOID;
+ return;
- if (acpi_bus_get_device(handle, &device))
- return_VOID;
+ device = video->device;
switch (event) {
case ACPI_VIDEO_NOTIFY_SWITCH: /* User request that a switch occur,
@@ -1707,7 +1649,7 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
break;
}
- return_VOID;
+ return;
}
static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
@@ -1716,14 +1658,12 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
(struct acpi_video_device *)data;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_video_device_notify");
printk("video device notify\n");
if (!video_device)
- return_VOID;
+ return;
- if (acpi_bus_get_device(handle, &device))
- return_VOID;
+ device = video_device->dev;
switch (event) {
case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */
@@ -1743,7 +1683,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
"Unsupported event [0x%x]\n", event));
break;
}
- return_VOID;
+ return;
}
static int acpi_video_bus_add(struct acpi_device *device)
@@ -1752,17 +1692,16 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_status status = 0;
struct acpi_video_bus *video = NULL;
- ACPI_FUNCTION_TRACE("acpi_video_bus_add");
if (!device)
- return_VALUE(-EINVAL);
+ return -EINVAL;
video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
if (!video)
- return_VALUE(-ENOMEM);
+ return -ENOMEM;
memset(video, 0, sizeof(struct acpi_video_bus));
- video->handle = device->handle;
+ video->device = device;
strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
acpi_driver_data(device) = video;
@@ -1782,7 +1721,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_get_devices(video, device);
acpi_video_bus_start_devices(video);
- status = acpi_install_notify_handler(video->handle,
+ status = acpi_install_notify_handler(device->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_bus_notify, video);
if (ACPI_FAILURE(status)) {
@@ -1806,7 +1745,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
if (result)
kfree(video);
- return_VALUE(result);
+ return result;
}
static int acpi_video_bus_remove(struct acpi_device *device, int type)
@@ -1814,21 +1753,17 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
acpi_status status = 0;
struct acpi_video_bus *video = NULL;
- ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
+ return -EINVAL;
video = (struct acpi_video_bus *)acpi_driver_data(device);
acpi_video_bus_stop_devices(video);
- status = acpi_remove_notify_handler(video->handle,
+ status = acpi_remove_notify_handler(video->device->handle,
ACPI_DEVICE_NOTIFY,
acpi_video_bus_notify);
- if (ACPI_FAILURE(status))
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Error removing notify handler\n"));
acpi_video_bus_put_devices(video);
acpi_video_bus_remove_fs(device);
@@ -1836,7 +1771,7 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
kfree(video->attached_array);
kfree(video);
- return_VALUE(0);
+ return 0;
}
static int
@@ -1846,10 +1781,9 @@ acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
acpi_handle h_dummy2;
acpi_handle h_dummy3;
- ACPI_FUNCTION_TRACE("acpi_video_bus_match");
if (!device || !driver)
- return_VALUE(-EINVAL);
+ return -EINVAL;
/* Since there is no HID, CID for ACPI Video drivers, we have
* to check well known required nodes for each feature we support.
@@ -1858,26 +1792,25 @@ acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
/* Does this device able to support video switching ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
- return_VALUE(0);
+ return 0;
/* Does this device able to retrieve a video ROM ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
- return_VALUE(0);
+ return 0;
/* Does this device able to configure which video head to be POSTed ? */
if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
- return_VALUE(0);
+ return 0;
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
static int __init acpi_video_init(void)
{
int result = 0;
- ACPI_FUNCTION_TRACE("acpi_video_init");
/*
acpi_dbg_level = 0xFFFFFFFF;
@@ -1886,27 +1819,26 @@ static int __init acpi_video_init(void)
acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
if (!acpi_video_dir)
- return_VALUE(-ENODEV);
+ return -ENODEV;
acpi_video_dir->owner = THIS_MODULE;
result = acpi_bus_register_driver(&acpi_video_bus);
if (result < 0) {
remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
- return_VALUE(-ENODEV);
+ return -ENODEV;
}
- return_VALUE(0);
+ return 0;
}
static void __exit acpi_video_exit(void)
{
- ACPI_FUNCTION_TRACE("acpi_video_exit");
acpi_bus_unregister_driver(&acpi_video_bus);
remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
- return_VOID;
+ return;
}
module_init(acpi_video_init);
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 889855d8d9f..9e3e2a69c03 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -180,8 +180,9 @@ static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
amba_attr(id, "%08x\n", dev->periphid);
amba_attr(irq0, "%u\n", dev->irq[0]);
amba_attr(irq1, "%u\n", dev->irq[1]);
-amba_attr(resource, "\t%08lx\t%08lx\t%08lx\n",
- dev->res.start, dev->res.end, dev->res.flags);
+amba_attr(resource, "\t%016llx\t%016llx\t%016lx\n",
+ (unsigned long long)dev->res.start, (unsigned long long)dev->res.end,
+ dev->res.flags);
/**
* amba_device_register - register an AMBA device
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
new file mode 100644
index 00000000000..3f4aa0c99ee
--- /dev/null
+++ b/drivers/ata/Kconfig
@@ -0,0 +1,487 @@
+#
+# SATA/PATA driver configuration
+#
+
+menu "Serial ATA (prod) and Parallel ATA (experimental) drivers"
+
+config ATA
+ tristate "ATA device support"
+ depends on !(M32R || M68K) || BROKEN
+ depends on !SUN4 || BROKEN
+ select SCSI
+ ---help---
+ If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
+ any other ATA device under Linux, say Y and make sure that you know
+ the name of your ATA host adapter (the card inside your computer
+ that "speaks" the ATA protocol, also called ATA controller),
+ because you will be asked for it.
+
+if ATA
+
+config SATA_AHCI
+ tristate "AHCI SATA support"
+ depends on PCI
+ help
+ This option enables support for AHCI Serial ATA.
+
+ If unsure, say N.
+
+config SATA_SVW
+ tristate "ServerWorks Frodo / Apple K2 SATA support"
+ depends on PCI
+ help
+ This option enables support for Broadcom/Serverworks/Apple K2
+ SATA support.
+
+ If unsure, say N.
+
+config ATA_PIIX
+ tristate "Intel PIIX/ICH SATA support"
+ depends on PCI
+ help
+ This option enables support for ICH5/6/7/8 Serial ATA.
+ If PATA support was enabled previously, this enables
+ support for select Intel PIIX/ICH PATA host controllers.
+
+ If unsure, say N.
+
+config SATA_MV
+ tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Marvell Serial ATA family.
+ Currently supports 88SX[56]0[48][01] chips.
+
+ If unsure, say N.
+
+config SATA_NV
+ tristate "NVIDIA SATA support"
+ depends on PCI
+ help
+ This option enables support for NVIDIA Serial ATA.
+
+ If unsure, say N.
+
+config PDC_ADMA
+ tristate "Pacific Digital ADMA support"
+ depends on PCI
+ help
+ This option enables support for Pacific Digital ADMA controllers
+
+ If unsure, say N.
+
+config SATA_QSTOR
+ tristate "Pacific Digital SATA QStor support"
+ depends on PCI
+ help
+ This option enables support for Pacific Digital Serial ATA QStor.
+
+ If unsure, say N.
+
+config SATA_PROMISE
+ tristate "Promise SATA TX2/TX4 support"
+ depends on PCI
+ help
+ This option enables support for Promise Serial ATA TX2/TX4.
+
+ If unsure, say N.
+
+config SATA_SX4
+ tristate "Promise SATA SX4 support"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for Promise Serial ATA SX4.
+
+ If unsure, say N.
+
+config SATA_SIL
+ tristate "Silicon Image SATA support"
+ depends on PCI
+ help
+ This option enables support for Silicon Image Serial ATA.
+
+ If unsure, say N.
+
+config SATA_SIL24
+ tristate "Silicon Image 3124/3132 SATA support"
+ depends on PCI
+ help
+ This option enables support for Silicon Image 3124/3132 Serial ATA.
+
+ If unsure, say N.
+
+config SATA_SIS
+ tristate "SiS 964/180 SATA support"
+ depends on PCI
+ help
+ This option enables support for SiS Serial ATA 964/180.
+
+ If unsure, say N.
+
+config SATA_ULI
+ tristate "ULi Electronics SATA support"
+ depends on PCI
+ help
+ This option enables support for ULi Electronics SATA.
+
+ If unsure, say N.
+
+config SATA_VIA
+ tristate "VIA SATA support"
+ depends on PCI
+ help
+ This option enables support for VIA Serial ATA.
+
+ If unsure, say N.
+
+config SATA_VITESSE
+ tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
+ depends on PCI
+ help
+ This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
+
+ If unsure, say N.
+
+config SATA_INTEL_COMBINED
+ bool
+ depends on IDE=y && !BLK_DEV_IDE_SATA && (SATA_AHCI || ATA_PIIX)
+ default y
+
+config PATA_ALI
+ tristate "ALi PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ALi ATA interfaces
+ found on the many ALi chipsets.
+
+ If unsure, say N.
+
+config PATA_AMD
+ tristate "AMD/NVidia PATA support (Experimental)"
+ depends on PCI
+ help
+ This option enables support for the AMD and NVidia PATA
+ interfaces found on the chipsets for Athlon/Athlon64.
+
+ If unsure, say N.
+
+config PATA_ARTOP
+ tristate "ARTOP 6210/6260 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for ARTOP PATA controllers.
+
+ If unsure, say N.
+
+config PATA_ATIIXP
+ tristate "ATI PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ATI ATA interfaces
+ found on the many ATI chipsets.
+
+ If unsure, say N.
+
+config PATA_CMD64X
+ tristate "CMD64x PATA support (Very Experimental)"
+ depends on PCI&& EXPERIMENTAL
+ help
+ This option enables support for the CMD64x series chips
+ except for the CMD640.
+
+ If unsure, say N.
+
+config PATA_CS5520
+ tristate "CS5510/5520 PATA support"
+ depends on PCI
+ help
+ This option enables support for the Cyrix 5510/5520
+ companion chip used with the MediaGX/Geode processor family.
+
+ If unsure, say N.
+
+config PATA_CS5530
+ tristate "CS5530 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Cyrix/NatSemi/AMD CS5530
+ companion chip used with the MediaGX/Geode processor family.
+
+ If unsure, say N.
+
+config PATA_CS5535
+ tristate "CS5535 PATA support (Experimental)"
+ depends on PCI && X86 && !X86_64 && EXPERIMENTAL
+ help
+ This option enables support for the NatSemi/AMD CS5535
+ companion chip used with the Geode processor family.
+
+ If unsure, say N.
+
+config PATA_CYPRESS
+ tristate "Cypress CY82C693 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Cypress/Contaq CY82C693
+ chipset found in some Alpha systems
+
+ If unsure, say N.
+
+config PATA_EFAR
+ tristate "EFAR SLC90E66 support"
+ depends on PCI
+ help
+ This option enables support for the EFAR SLC90E66
+ IDE controller found on some older machines.
+
+ If unsure, say N.
+
+config ATA_GENERIC
+ tristate "Generic ATA support"
+ depends on PCI
+ help
+ This option enables support for generic BIOS configured
+ ATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_HPT366
+ tristate "HPT 366/368 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the HPT 366 and 368
+ PATA controllers via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_HPT37X
+ tristate "HPT 370/370A/371/372/374/302 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the majority of the later HPT
+ PATA controllers via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_HPT3X2N
+ tristate "HPT 372N/302N PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the N variant HPT PATA
+ controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_HPT3X3
+ tristate "HPT 343/363 PATA support (Experimental)"
+ depends on PCI
+ help
+ This option enables support for the HPT 343/363
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_ISAPNP
+ tristate "ISA Plug and Play PATA support (Very Experimental)"
+ depends on EXPERIMENTAL && ISAPNP
+ help
+ This option enables support for ISA plug & play ATA
+ controllers such as those found on old soundcards.
+
+ If unsure, say N.
+
+config PATA_IT821X
+ tristate "IT821x PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the ITE 8211 and 8212
+ PATA controllers via the new ATA layer, including RAID
+ mode.
+
+ If unsure, say N.
+
+config PATA_JMICRON
+ tristate "JMicron PATA support"
+ depends on PCI
+ help
+ Enable support for the JMicron IDE controller, via the new
+ ATA layer.
+
+ If unsure, say N.
+
+config PATA_LEGACY
+ tristate "Legacy ISA PATA support (Experimental)"
+ depends on ISA && EXPERIMENTAL
+ help
+ This option enables support for ISA/VLB bus legacy PATA
+ ports and allows them to be accessed via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_TRIFLEX
+ tristate "Compaq Triflex PATA support"
+ depends on PCI
+ help
+ Enable support for the Compaq 'Triflex' IDE controller as found
+ on many Compaq Pentium-Pro systems, via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_MPIIX
+ tristate "Intel PATA MPIIX support"
+ depends on PCI
+ help
+ This option enables support for MPIIX PATA support.
+
+ If unsure, say N.
+
+config PATA_OLDPIIX
+ tristate "Intel PATA old PIIX support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for old(?) PIIX PATA support.
+
+ If unsure, say N.
+
+config PATA_NETCELL
+ tristate "NETCELL Revolution RAID support"
+ depends on PCI
+ help
+ This option enables support for the Netcell Revolution RAID
+ PATA controller.
+
+ If unsure, say N.
+
+config PATA_NS87410
+ tristate "Nat Semi NS87410 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the National Semiconductor
+ NS87410 PCI-IDE controller.
+
+ If unsure, say N.
+
+config PATA_OPTI
+ tristate "OPTI621/6215 PATA support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables full PIO support for the early Opti ATA
+ controllers found on some old motherboards.
+
+ If unsure, say N.
+
+config PATA_OPTIDMA
+ tristate "OPTI FireStar PATA support (Veyr Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables DMA/PIO support for the later OPTi
+ controllers found on some old motherboards and in some
+ latops
+
+ If unsure, say N.
+
+config PATA_PCMCIA
+ tristate "PCMCIA PATA support"
+ depends on PCMCIA
+ help
+ This option enables support for PCMCIA ATA interfaces, including
+ compact flash card adapters via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_PDC_OLD
+ tristate "Older Promise PATA controller support (Very Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Promise 20246, 20262, 20263,
+ 20265 and 20267 adapters.
+
+ If unsure, say N.
+
+config PATA_QDI
+ tristate "QDI VLB PATA support"
+ depends on ISA
+ help
+ Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
+
+config PATA_RADISYS
+ tristate "RADISYS 82600 PATA support (Very experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the RADISYS 82600
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_RZ1000
+ tristate "PC Tech RZ1000 PATA support"
+ depends on PCI
+ help
+ This option enables basic support for the PC Tech RZ1000/1
+ PATA controllers via the new ATA layer
+
+ If unsure, say N.
+
+config PATA_SC1200
+ tristate "SC1200 PATA support (Raving Lunatic)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the NatSemi/AMD SC1200 SoC
+ companion chip used with the Geode processor family.
+
+ If unsure, say N.
+
+config PATA_SERVERWORKS
+ tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for the Serverworks OSB4/CSB5/CSB6 and
+ HT1000 PATA controllers, via the new ATA layer.
+
+ If unsure, say N.
+
+config PATA_PDC2027X
+ tristate "Promise PATA 2027x support"
+ depends on PCI
+ help
+ This option enables support for Promise PATA pdc20268 to pdc20277 host adapters.
+
+ If unsure, say N.
+
+config PATA_SIL680
+ tristate "CMD / Silicon Image 680 PATA support"
+ depends on PCI
+ help
+ This option enables support for CMD / Silicon Image 680 PATA.
+
+ If unsure, say N.
+
+config PATA_SIS
+ tristate "SiS PATA support (Experimental)"
+ depends on PCI && EXPERIMENTAL
+ help
+ This option enables support for SiS PATA controllers
+
+ If unsure, say N.
+
+config PATA_VIA
+ tristate "VIA PATA support"
+ depends on PCI
+ help
+ This option enables support for the VIA PATA interfaces
+ found on the many VIA chipsets.
+
+ If unsure, say N.
+
+config PATA_WINBOND
+ tristate "Winbond SL82C105 PATA support"
+ depends on PCI
+ help
+ This option enables support for SL82C105 PATA devices found in the
+ Netwinder and some other systems
+
+ If unsure, say N.
+
+endif
+endmenu
+
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
new file mode 100644
index 00000000000..72243a677f9
--- /dev/null
+++ b/drivers/ata/Makefile
@@ -0,0 +1,62 @@
+
+obj-$(CONFIG_ATA) += libata.o
+
+obj-$(CONFIG_SATA_AHCI) += ahci.o
+obj-$(CONFIG_SATA_SVW) += sata_svw.o
+obj-$(CONFIG_ATA_PIIX) += ata_piix.o
+obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
+obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
+obj-$(CONFIG_SATA_SIL) += sata_sil.o
+obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
+obj-$(CONFIG_SATA_VIA) += sata_via.o
+obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
+obj-$(CONFIG_SATA_SIS) += sata_sis.o
+obj-$(CONFIG_SATA_SX4) += sata_sx4.o
+obj-$(CONFIG_SATA_NV) += sata_nv.o
+obj-$(CONFIG_SATA_ULI) += sata_uli.o
+obj-$(CONFIG_SATA_MV) += sata_mv.o
+obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
+
+obj-$(CONFIG_PATA_ALI) += pata_ali.o
+obj-$(CONFIG_PATA_AMD) += pata_amd.o
+obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
+obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
+obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
+obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
+obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
+obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
+obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
+obj-$(CONFIG_PATA_EFAR) += pata_efar.o
+obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
+obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
+obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
+obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
+obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
+obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
+obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
+obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
+obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
+obj-$(CONFIG_PATA_OPTI) += pata_opti.o
+obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
+obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
+obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
+obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
+obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
+obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
+obj-$(CONFIG_PATA_QDI) += pata_qdi.o
+obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
+obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
+obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
+obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
+obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
+obj-$(CONFIG_PATA_VIA) += pata_via.o
+obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
+obj-$(CONFIG_PATA_SIS) += pata_sis.o
+obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
+# Should be last but one libata driver
+obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
+# Should be last libata driver
+obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
+
+libata-objs := libata-core.o libata-scsi.o libata-sff.o libata-eh.o
+
diff --git a/drivers/scsi/ahci.c b/drivers/ata/ahci.c
index 4bb77f62b3b..1aabc81d82f 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/ata/ahci.c
@@ -48,7 +48,7 @@
#include <asm/io.h>
#define DRV_NAME "ahci"
-#define DRV_VERSION "1.3"
+#define DRV_VERSION "2.0"
enum {
@@ -92,7 +92,9 @@ enum {
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */
+ HOST_CAP_SSC = (1 << 14), /* Slumber capable */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
@@ -155,6 +157,7 @@ enum {
PORT_CMD_SPIN_UP = (1 << 1), /* Spin up device */
PORT_CMD_START = (1 << 0), /* Enable port DMA engine */
+ PORT_CMD_ICC_MASK = (0xf << 28), /* i/f ICC state mask */
PORT_CMD_ICC_ACTIVE = (0x1 << 28), /* Put i/f in active state */
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
@@ -212,6 +215,10 @@ static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
static void ahci_error_handler(struct ata_port *ap);
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg);
+static int ahci_port_resume(struct ata_port *ap);
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
+static int ahci_pci_device_resume(struct pci_dev *pdev);
static void ahci_remove_one (struct pci_dev *pdev);
static struct scsi_host_template ahci_sht = {
@@ -231,6 +238,8 @@ static struct scsi_host_template ahci_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations ahci_ops = {
@@ -257,6 +266,9 @@ static const struct ata_port_operations ahci_ops = {
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
+ .port_suspend = ahci_port_suspend,
+ .port_resume = ahci_port_resume,
+
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
@@ -265,7 +277,7 @@ static const struct ata_port_info ahci_port_info[] = {
/* board_ahci */
{
.sht = &ahci_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
ATA_FLAG_SKIP_D2H_BSY,
.pio_mask = 0x1f, /* pio0-4 */
@@ -275,7 +287,7 @@ static const struct ata_port_info ahci_port_info[] = {
/* board_ahci_vt8251 */
{
.sht = &ahci_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
ATA_FLAG_SKIP_D2H_BSY |
AHCI_FLAG_RESET_NEEDS_CLO | AHCI_FLAG_NO_NCQ,
@@ -350,6 +362,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* MCP65 */
+ /* SiS */
+ { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* SiS 966 */
+ { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* SiS 966 */
+ { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci }, /* SiS 968 */
+
{ } /* terminate list */
};
@@ -358,6 +378,8 @@ static struct pci_driver ahci_pci_driver = {
.name = DRV_NAME,
.id_table = ahci_pci_tbl,
.probe = ahci_init_one,
+ .suspend = ahci_pci_device_suspend,
+ .resume = ahci_pci_device_resume,
.remove = ahci_remove_one,
};
@@ -372,177 +394,288 @@ static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int por
return (void __iomem *) ahci_port_base_ul((unsigned long)base, port);
}
-static int ahci_port_start(struct ata_port *ap)
+static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
{
- struct device *dev = ap->host_set->dev;
- struct ahci_host_priv *hpriv = ap->host_set->private_data;
- struct ahci_port_priv *pp;
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- void *mem;
- dma_addr_t mem_dma;
- int rc;
-
- pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp)
- return -ENOMEM;
- memset(pp, 0, sizeof(*pp));
+ unsigned int sc_reg;
- rc = ata_pad_alloc(ap, dev);
- if (rc) {
- kfree(pp);
- return rc;
+ switch (sc_reg_in) {
+ case SCR_STATUS: sc_reg = 0; break;
+ case SCR_CONTROL: sc_reg = 1; break;
+ case SCR_ERROR: sc_reg = 2; break;
+ case SCR_ACTIVE: sc_reg = 3; break;
+ default:
+ return 0xffffffffU;
}
- mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
- if (!mem) {
- ata_pad_free(ap, dev);
- kfree(pp);
- return -ENOMEM;
- }
- memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+ return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
- /*
- * First item in chunk of DMA memory: 32-slot command table,
- * 32 bytes each in size
- */
- pp->cmd_slot = mem;
- pp->cmd_slot_dma = mem_dma;
- mem += AHCI_CMD_SLOT_SZ;
- mem_dma += AHCI_CMD_SLOT_SZ;
+static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
+ u32 val)
+{
+ unsigned int sc_reg;
- /*
- * Second item: Received-FIS area
- */
- pp->rx_fis = mem;
- pp->rx_fis_dma = mem_dma;
+ switch (sc_reg_in) {
+ case SCR_STATUS: sc_reg = 0; break;
+ case SCR_CONTROL: sc_reg = 1; break;
+ case SCR_ERROR: sc_reg = 2; break;
+ case SCR_ACTIVE: sc_reg = 3; break;
+ default:
+ return;
+ }
- mem += AHCI_RX_FIS_SZ;
- mem_dma += AHCI_RX_FIS_SZ;
+ writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
- /*
- * Third item: data area for storing a single command
- * and its scatter-gather table
- */
- pp->cmd_tbl = mem;
- pp->cmd_tbl_dma = mem_dma;
+static void ahci_start_engine(void __iomem *port_mmio)
+{
+ u32 tmp;
- ap->private_data = pp;
+ /* start DMA */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+ readl(port_mmio + PORT_CMD); /* flush */
+}
+
+static int ahci_stop_engine(void __iomem *port_mmio)
+{
+ u32 tmp;
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
- writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
- readl(port_mmio + PORT_LST_ADDR); /* flush */
+ tmp = readl(port_mmio + PORT_CMD);
- if (hpriv->cap & HOST_CAP_64)
- writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
- writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
- readl(port_mmio + PORT_FIS_ADDR); /* flush */
+ /* check if the HBA is idle */
+ if ((tmp & (PORT_CMD_START | PORT_CMD_LIST_ON)) == 0)
+ return 0;
- writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
- PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
- PORT_CMD_START, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
+ /* setting HBA to idle */
+ tmp &= ~PORT_CMD_START;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* wait for engine to stop. This could be as long as 500 msec */
+ tmp = ata_wait_register(port_mmio + PORT_CMD,
+ PORT_CMD_LIST_ON, PORT_CMD_LIST_ON, 1, 500);
+ if (tmp & PORT_CMD_LIST_ON)
+ return -EIO;
return 0;
}
+static void ahci_start_fis_rx(void __iomem *port_mmio, u32 cap,
+ dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
+{
+ u32 tmp;
-static void ahci_port_stop(struct ata_port *ap)
+ /* set FIS registers */
+ if (cap & HOST_CAP_64)
+ writel((cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
+ writel(cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+
+ if (cap & HOST_CAP_64)
+ writel((rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
+ writel(rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+
+ /* enable FIS reception */
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_FIS_RX;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ /* flush */
+ readl(port_mmio + PORT_CMD);
+}
+
+static int ahci_stop_fis_rx(void __iomem *port_mmio)
{
- struct device *dev = ap->host_set->dev;
- struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
+ /* disable FIS reception */
tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
+ tmp &= ~PORT_CMD_FIS_RX;
writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
- /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
- * this is slightly incorrect.
- */
- msleep(500);
+ /* wait for completion, spec says 500ms, give it 1000 */
+ tmp = ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_FIS_ON,
+ PORT_CMD_FIS_ON, 10, 1000);
+ if (tmp & PORT_CMD_FIS_ON)
+ return -EBUSY;
- ap->private_data = NULL;
- dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
- pp->cmd_slot, pp->cmd_slot_dma);
- ata_pad_free(ap, dev);
- kfree(pp);
+ return 0;
}
-static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+static void ahci_power_up(void __iomem *port_mmio, u32 cap)
{
- unsigned int sc_reg;
+ u32 cmd;
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return 0xffffffffU;
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+ /* spin up device */
+ if (cap & HOST_CAP_SSS) {
+ cmd |= PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
}
- return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ /* wake up link */
+ writel(cmd | PORT_CMD_ICC_ACTIVE, port_mmio + PORT_CMD);
}
+static void ahci_power_down(void __iomem *port_mmio, u32 cap)
+{
+ u32 cmd, scontrol;
-static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
- u32 val)
+ cmd = readl(port_mmio + PORT_CMD) & ~PORT_CMD_ICC_MASK;
+
+ if (cap & HOST_CAP_SSC) {
+ /* enable transitions to slumber mode */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ if ((scontrol & 0x0f00) > 0x100) {
+ scontrol &= ~0xf00;
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+ }
+
+ /* put device into slumber mode */
+ writel(cmd | PORT_CMD_ICC_SLUMBER, port_mmio + PORT_CMD);
+
+ /* wait for the transition to complete */
+ ata_wait_register(port_mmio + PORT_CMD, PORT_CMD_ICC_SLUMBER,
+ PORT_CMD_ICC_SLUMBER, 1, 50);
+ }
+
+ /* put device into listen mode */
+ if (cap & HOST_CAP_SSS) {
+ /* first set PxSCTL.DET to 0 */
+ scontrol = readl(port_mmio + PORT_SCR_CTL);
+ scontrol &= ~0xf;
+ writel(scontrol, port_mmio + PORT_SCR_CTL);
+
+ /* then set PxCMD.SUD to 0 */
+ cmd &= ~PORT_CMD_SPIN_UP;
+ writel(cmd, port_mmio + PORT_CMD);
+ }
+}
+
+static void ahci_init_port(void __iomem *port_mmio, u32 cap,
+ dma_addr_t cmd_slot_dma, dma_addr_t rx_fis_dma)
{
- unsigned int sc_reg;
+ /* power up */
+ ahci_power_up(port_mmio, cap);
- switch (sc_reg_in) {
- case SCR_STATUS: sc_reg = 0; break;
- case SCR_CONTROL: sc_reg = 1; break;
- case SCR_ERROR: sc_reg = 2; break;
- case SCR_ACTIVE: sc_reg = 3; break;
- default:
- return;
+ /* enable FIS reception */
+ ahci_start_fis_rx(port_mmio, cap, cmd_slot_dma, rx_fis_dma);
+
+ /* enable DMA */
+ ahci_start_engine(port_mmio);
+}
+
+static int ahci_deinit_port(void __iomem *port_mmio, u32 cap, const char **emsg)
+{
+ int rc;
+
+ /* disable DMA */
+ rc = ahci_stop_engine(port_mmio);
+ if (rc) {
+ *emsg = "failed to stop engine";
+ return rc;
}
- writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4));
+ /* disable FIS reception */
+ rc = ahci_stop_fis_rx(port_mmio);
+ if (rc) {
+ *emsg = "failed stop FIS RX";
+ return rc;
+ }
+
+ /* put device into slumber mode */
+ ahci_power_down(port_mmio, cap);
+
+ return 0;
}
-static int ahci_stop_engine(struct ata_port *ap)
+static int ahci_reset_controller(void __iomem *mmio, struct pci_dev *pdev)
{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
- int work;
- u32 tmp;
+ u32 cap_save, tmp;
- tmp = readl(port_mmio + PORT_CMD);
- tmp &= ~PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
+ cap_save = readl(mmio + HOST_CAP);
+ cap_save &= ( (1<<28) | (1<<17) );
+ cap_save |= (1 << 27);
+
+ /* global controller reset */
+ tmp = readl(mmio + HOST_CTL);
+ if ((tmp & HOST_RESET) == 0) {
+ writel(tmp | HOST_RESET, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
- /* wait for engine to stop. TODO: this could be
- * as long as 500 msec
+ /* reset must complete within 1 second, or
+ * the hardware should be considered fried.
*/
- work = 1000;
- while (work-- > 0) {
- tmp = readl(port_mmio + PORT_CMD);
- if ((tmp & PORT_CMD_LIST_ON) == 0)
- return 0;
- udelay(10);
+ ssleep(1);
+
+ tmp = readl(mmio + HOST_CTL);
+ if (tmp & HOST_RESET) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "controller reset failed (0x%x)\n", tmp);
+ return -EIO;
+ }
+
+ writel(HOST_AHCI_EN, mmio + HOST_CTL);
+ (void) readl(mmio + HOST_CTL); /* flush */
+ writel(cap_save, mmio + HOST_CAP);
+ writel(0xf, mmio + HOST_PORTS_IMPL);
+ (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
+
+ if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+ u16 tmp16;
+
+ /* configure PCS */
+ pci_read_config_word(pdev, 0x92, &tmp16);
+ tmp16 |= 0xf;
+ pci_write_config_word(pdev, 0x92, tmp16);
}
- return -EIO;
+ return 0;
}
-static void ahci_start_engine(struct ata_port *ap)
+static void ahci_init_controller(void __iomem *mmio, struct pci_dev *pdev,
+ int n_ports, u32 cap)
{
- void __iomem *mmio = ap->host_set->mmio_base;
- void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ int i, rc;
u32 tmp;
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_START;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port_mmio = ahci_port_base(mmio, i);
+ const char *emsg = NULL;
+
+#if 0 /* BIOSen initialize this incorrectly */
+ if (!(hpriv->port_map & (1 << i)))
+ continue;
+#endif
+
+ /* make sure port is not active */
+ rc = ahci_deinit_port(port_mmio, cap, &emsg);
+ if (rc)
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "%s (%d)\n", emsg, rc);
+
+ /* clear SError */
+ tmp = readl(port_mmio + PORT_SCR_ERR);
+ VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+ writel(tmp, port_mmio + PORT_SCR_ERR);
+
+ /* clear port IRQ */
+ tmp = readl(port_mmio + PORT_IRQ_STAT);
+ VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+ if (tmp)
+ writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+ writel(1 << i, mmio + HOST_IRQ_STAT);
+ }
+
+ tmp = readl(mmio + HOST_CTL);
+ VPRINTK("HOST_CTL 0x%x\n", tmp);
+ writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+ tmp = readl(mmio + HOST_CTL);
+ VPRINTK("HOST_CTL 0x%x\n", tmp);
}
static unsigned int ahci_dev_classify(struct ata_port *ap)
@@ -576,7 +709,7 @@ static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
static int ahci_clo(struct ata_port *ap)
{
void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
- struct ahci_host_priv *hpriv = ap->host_set->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
u32 tmp;
if (!(hpriv->cap & HOST_CAP_CLO))
@@ -608,7 +741,7 @@ static int ahci_prereset(struct ata_port *ap)
static int ahci_softreset(struct ata_port *ap, unsigned int *class)
{
struct ahci_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
const u32 cmd_fis_len = 5; /* five dwords */
const char *reason = NULL;
@@ -626,7 +759,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
}
/* prepare for SRST (AHCI-1.1 10.4.1) */
- rc = ahci_stop_engine(ap);
+ rc = ahci_stop_engine(port_mmio);
if (rc) {
reason = "failed to stop engine";
goto fail_restart;
@@ -647,7 +780,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
}
/* restart engine */
- ahci_start_engine(ap);
+ ahci_start_engine(port_mmio);
ata_tf_init(ap->device, &tf);
fis = pp->cmd_tbl;
@@ -706,7 +839,7 @@ static int ahci_softreset(struct ata_port *ap, unsigned int *class)
return 0;
fail_restart:
- ahci_start_engine(ap);
+ ahci_start_engine(port_mmio);
fail:
ata_port_printk(ap, KERN_ERR, "softreset failed (%s)\n", reason);
return rc;
@@ -717,11 +850,13 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
struct ahci_port_priv *pp = ap->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
int rc;
DPRINTK("ENTER\n");
- ahci_stop_engine(ap);
+ ahci_stop_engine(port_mmio);
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(ap->device, &tf);
@@ -730,7 +865,7 @@ static int ahci_hardreset(struct ata_port *ap, unsigned int *class)
rc = sata_std_hardreset(ap, class);
- ahci_start_engine(ap);
+ ahci_start_engine(port_mmio);
if (rc == 0 && ata_port_online(ap))
*class = ahci_dev_classify(ap);
@@ -904,7 +1039,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat)
static void ahci_host_intr(struct ata_port *ap)
{
- void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
struct ata_eh_info *ehi = &ap->eh_info;
u32 status, qc_active;
@@ -940,14 +1075,8 @@ static void ahci_host_intr(struct ata_port *ap)
return;
/* ignore interim PIO setup fis interrupts */
- if (ata_tag_valid(ap->active_tag)) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->active_tag);
-
- if (qc && qc->tf.protocol == ATA_PROT_PIO &&
- (status & PORT_IRQ_PIOS_FIS))
- return;
- }
+ if (ata_tag_valid(ap->active_tag) && (status & PORT_IRQ_PIOS_FIS))
+ return;
if (ata_ratelimit())
ata_port_printk(ap, KERN_INFO, "spurious interrupt "
@@ -962,7 +1091,7 @@ static void ahci_irq_clear(struct ata_port *ap)
static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv;
unsigned int i, handled = 0;
void __iomem *mmio;
@@ -970,8 +1099,8 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *r
VPRINTK("ENTER\n");
- hpriv = host_set->private_data;
- mmio = host_set->mmio_base;
+ hpriv = host->private_data;
+ mmio = host->mmio_base;
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat = readl(mmio + HOST_IRQ_STAT);
@@ -979,22 +1108,22 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *r
if (!irq_stat)
return IRQ_NONE;
- spin_lock(&host_set->lock);
+ spin_lock(&host->lock);
- for (i = 0; i < host_set->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
if (!(irq_stat & (1 << i)))
continue;
- ap = host_set->ports[i];
+ ap = host->ports[i];
if (ap) {
ahci_host_intr(ap);
VPRINTK("port %u\n", i);
} else {
VPRINTK("port %u (no irq)\n", i);
if (ata_ratelimit())
- dev_printk(KERN_WARNING, host_set->dev,
+ dev_printk(KERN_WARNING, host->dev,
"interrupt on disabled port %u\n", i);
}
@@ -1006,7 +1135,7 @@ static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *r
handled = 1;
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
VPRINTK("EXIT\n");
@@ -1028,7 +1157,7 @@ static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc)
static void ahci_freeze(struct ata_port *ap)
{
- void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
/* turn IRQ off */
@@ -1037,7 +1166,7 @@ static void ahci_freeze(struct ata_port *ap)
static void ahci_thaw(struct ata_port *ap)
{
- void __iomem *mmio = ap->host_set->mmio_base;
+ void __iomem *mmio = ap->host->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
u32 tmp;
@@ -1052,10 +1181,13 @@ static void ahci_thaw(struct ata_port *ap)
static void ahci_error_handler(struct ata_port *ap)
{
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
/* restart engine */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
+ ahci_stop_engine(port_mmio);
+ ahci_start_engine(port_mmio);
}
/* perform recovery */
@@ -1066,15 +1198,176 @@ static void ahci_error_handler(struct ata_port *ap)
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
if (qc->flags & ATA_QCFLAG_FAILED)
qc->err_mask |= AC_ERR_OTHER;
if (qc->err_mask) {
/* make DMA engine forget about the failed command */
- ahci_stop_engine(ap);
- ahci_start_engine(ap);
+ ahci_stop_engine(port_mmio);
+ ahci_start_engine(port_mmio);
+ }
+}
+
+static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
+{
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ const char *emsg = NULL;
+ int rc;
+
+ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ if (rc) {
+ ata_port_printk(ap, KERN_ERR, "%s (%d)\n", emsg, rc);
+ ahci_init_port(port_mmio, hpriv->cap,
+ pp->cmd_slot_dma, pp->rx_fis_dma);
+ }
+
+ return rc;
+}
+
+static int ahci_port_resume(struct ata_port *ap)
+{
+ struct ahci_port_priv *pp = ap->private_data;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+
+ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+
+ return 0;
+}
+
+static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ void __iomem *mmio = host->mmio_base;
+ u32 ctl;
+
+ if (mesg.event == PM_EVENT_SUSPEND) {
+ /* AHCI spec rev1.1 section 8.3.3:
+ * Software must disable interrupts prior to requesting a
+ * transition of the HBA to D3 state.
+ */
+ ctl = readl(mmio + HOST_CTL);
+ ctl &= ~HOST_IRQ_EN;
+ writel(ctl, mmio + HOST_CTL);
+ readl(mmio + HOST_CTL); /* flush */
+ }
+
+ return ata_pci_device_suspend(pdev, mesg);
+}
+
+static int ahci_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct ahci_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = host->mmio_base;
+ int rc;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ rc = ahci_reset_controller(mmio, pdev);
+ if (rc)
+ return rc;
+
+ ahci_init_controller(mmio, pdev, host->n_ports, hpriv->cap);
+ }
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
+static int ahci_port_start(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ void *mem;
+ dma_addr_t mem_dma;
+ int rc;
+
+ pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+ if (!pp)
+ return -ENOMEM;
+ memset(pp, 0, sizeof(*pp));
+
+ rc = ata_pad_alloc(ap, dev);
+ if (rc) {
+ kfree(pp);
+ return rc;
}
+
+ mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
+ if (!mem) {
+ ata_pad_free(ap, dev);
+ kfree(pp);
+ return -ENOMEM;
+ }
+ memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+
+ /*
+ * First item in chunk of DMA memory: 32-slot command table,
+ * 32 bytes each in size
+ */
+ pp->cmd_slot = mem;
+ pp->cmd_slot_dma = mem_dma;
+
+ mem += AHCI_CMD_SLOT_SZ;
+ mem_dma += AHCI_CMD_SLOT_SZ;
+
+ /*
+ * Second item: Received-FIS area
+ */
+ pp->rx_fis = mem;
+ pp->rx_fis_dma = mem_dma;
+
+ mem += AHCI_RX_FIS_SZ;
+ mem_dma += AHCI_RX_FIS_SZ;
+
+ /*
+ * Third item: data area for storing a single command
+ * and its scatter-gather table
+ */
+ pp->cmd_tbl = mem;
+ pp->cmd_tbl_dma = mem_dma;
+
+ ap->private_data = pp;
+
+ /* initialize port */
+ ahci_init_port(port_mmio, hpriv->cap, pp->cmd_slot_dma, pp->rx_fis_dma);
+
+ return 0;
+}
+
+static void ahci_port_stop(struct ata_port *ap)
+{
+ struct device *dev = ap->host->dev;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
+ const char *emsg = NULL;
+ int rc;
+
+ /* de-initialize port */
+ rc = ahci_deinit_port(port_mmio, hpriv->cap, &emsg);
+ if (rc)
+ ata_port_printk(ap, KERN_WARNING, "%s (%d)\n", emsg, rc);
+
+ ap->private_data = NULL;
+ dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+ pp->cmd_slot, pp->cmd_slot_dma);
+ ata_pad_free(ap, dev);
+ kfree(pp);
}
static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
@@ -1095,47 +1388,12 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
struct ahci_host_priv *hpriv = probe_ent->private_data;
struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
void __iomem *mmio = probe_ent->mmio_base;
- u32 tmp, cap_save;
- unsigned int i, j, using_dac;
+ unsigned int i, using_dac;
int rc;
- void __iomem *port_mmio;
-
- cap_save = readl(mmio + HOST_CAP);
- cap_save &= ( (1<<28) | (1<<17) );
- cap_save |= (1 << 27);
-
- /* global controller reset */
- tmp = readl(mmio + HOST_CTL);
- if ((tmp & HOST_RESET) == 0) {
- writel(tmp | HOST_RESET, mmio + HOST_CTL);
- readl(mmio + HOST_CTL); /* flush */
- }
-
- /* reset must complete within 1 second, or
- * the hardware should be considered fried.
- */
- ssleep(1);
-
- tmp = readl(mmio + HOST_CTL);
- if (tmp & HOST_RESET) {
- dev_printk(KERN_ERR, &pdev->dev,
- "controller reset failed (0x%x)\n", tmp);
- return -EIO;
- }
-
- writel(HOST_AHCI_EN, mmio + HOST_CTL);
- (void) readl(mmio + HOST_CTL); /* flush */
- writel(cap_save, mmio + HOST_CAP);
- writel(0xf, mmio + HOST_PORTS_IMPL);
- (void) readl(mmio + HOST_PORTS_IMPL); /* flush */
- if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
- u16 tmp16;
-
- pci_read_config_word(pdev, 0x92, &tmp16);
- tmp16 |= 0xf;
- pci_write_config_word(pdev, 0x92, tmp16);
- }
+ rc = ahci_reset_controller(mmio, pdev);
+ if (rc)
+ return rc;
hpriv->cap = readl(mmio + HOST_CAP);
hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
@@ -1171,63 +1429,10 @@ static int ahci_host_init(struct ata_probe_ent *probe_ent)
}
}
- for (i = 0; i < probe_ent->n_ports; i++) {
-#if 0 /* BIOSen initialize this incorrectly */
- if (!(hpriv->port_map & (1 << i)))
- continue;
-#endif
-
- port_mmio = ahci_port_base(mmio, i);
- VPRINTK("mmio %p port_mmio %p\n", mmio, port_mmio);
-
- ahci_setup_port(&probe_ent->port[i],
- (unsigned long) mmio, i);
-
- /* make sure port is not active */
- tmp = readl(port_mmio + PORT_CMD);
- VPRINTK("PORT_CMD 0x%x\n", tmp);
- if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
- PORT_CMD_FIS_RX | PORT_CMD_START)) {
- tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
- PORT_CMD_FIS_RX | PORT_CMD_START);
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-
- /* spec says 500 msecs for each bit, so
- * this is slightly incorrect.
- */
- msleep(500);
- }
-
- writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
+ for (i = 0; i < probe_ent->n_ports; i++)
+ ahci_setup_port(&probe_ent->port[i], (unsigned long) mmio, i);
- j = 0;
- while (j < 100) {
- msleep(10);
- tmp = readl(port_mmio + PORT_SCR_STAT);
- if ((tmp & 0xf) == 0x3)
- break;
- j++;
- }
-
- tmp = readl(port_mmio + PORT_SCR_ERR);
- VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
- writel(tmp, port_mmio + PORT_SCR_ERR);
-
- /* ack any pending irq events for this port */
- tmp = readl(port_mmio + PORT_IRQ_STAT);
- VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
- if (tmp)
- writel(tmp, port_mmio + PORT_IRQ_STAT);
-
- writel(1 << i, mmio + HOST_IRQ_STAT);
- }
-
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
- writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
- tmp = readl(mmio + HOST_CTL);
- VPRINTK("HOST_CTL 0x%x\n", tmp);
+ ahci_init_controller(mmio, pdev, probe_ent->n_ports, hpriv->cap);
pci_set_master(pdev);
@@ -1323,6 +1528,17 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+ /* JMicron-specific fixup: make sure we're in AHCI mode */
+ /* This is protected from races with ata_jmicron by the pci probe
+ locking */
+ if (pdev->vendor == PCI_VENDOR_ID_JMICRON) {
+ /* AHCI enable, AHCI on function 0 */
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+ /* Function 1 is the PATA controller */
+ if (PCI_FUNC(pdev->devfn))
+ return -ENODEV;
+ }
+
rc = pci_enable_device(pdev);
if (rc)
return rc;
@@ -1365,31 +1581,27 @@ static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
memset(hpriv, 0, sizeof(*hpriv));
probe_ent->sht = ahci_port_info[board_idx].sht;
- probe_ent->host_flags = ahci_port_info[board_idx].host_flags;
+ probe_ent->port_flags = ahci_port_info[board_idx].flags;
probe_ent->pio_mask = ahci_port_info[board_idx].pio_mask;
probe_ent->udma_mask = ahci_port_info[board_idx].udma_mask;
probe_ent->port_ops = ahci_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
probe_ent->private_data = hpriv;
if (have_msi)
hpriv->flags |= AHCI_FLAG_MSI;
- /* JMicron-specific fixup: make sure we're in AHCI mode */
- if (pdev->vendor == 0x197b)
- pci_write_config_byte(pdev, 0x41, 0xa1);
-
/* initialize adapter */
rc = ahci_host_init(probe_ent);
if (rc)
goto err_out_hpriv;
- if (!(probe_ent->host_flags & AHCI_FLAG_NO_NCQ) &&
+ if (!(probe_ent->port_flags & AHCI_FLAG_NO_NCQ) &&
(hpriv->cap & HOST_CAP_NCQ))
- probe_ent->host_flags |= ATA_FLAG_NCQ;
+ probe_ent->port_flags |= ATA_FLAG_NCQ;
ahci_print_info(probe_ent);
@@ -1420,27 +1632,27 @@ err_out:
static void ahci_remove_one (struct pci_dev *pdev)
{
struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host_set *host_set = dev_get_drvdata(dev);
- struct ahci_host_priv *hpriv = host_set->private_data;
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct ahci_host_priv *hpriv = host->private_data;
unsigned int i;
int have_msi;
- for (i = 0; i < host_set->n_ports; i++)
- ata_port_detach(host_set->ports[i]);
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_detach(host->ports[i]);
have_msi = hpriv->flags & AHCI_FLAG_MSI;
- free_irq(host_set->irq, host_set);
+ free_irq(host->irq, host);
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
- ata_scsi_release(ap->host);
- scsi_host_put(ap->host);
+ ata_scsi_release(ap->scsi_host);
+ scsi_host_put(ap->scsi_host);
}
kfree(hpriv);
- pci_iounmap(pdev, host_set->mmio_base);
- kfree(host_set);
+ pci_iounmap(pdev, host->mmio_base);
+ kfree(host);
if (have_msi)
pci_disable_msi(pdev);
@@ -1453,7 +1665,7 @@ static void ahci_remove_one (struct pci_dev *pdev)
static int __init ahci_init(void)
{
- return pci_module_init(&ahci_pci_driver);
+ return pci_register_driver(&ahci_pci_driver);
}
static void __exit ahci_exit(void)
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
new file mode 100644
index 00000000000..377425e7139
--- /dev/null
+++ b/drivers/ata/ata_generic.c
@@ -0,0 +1,252 @@
+/*
+ * ata_generic.c - Generic PATA/SATA controller driver.
+ * Copyright 2005 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ *
+ * Elements from ide/pci/generic.c
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions (C) Copyright 2002 Red Hat Inc <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Driver for PCI IDE interfaces implementing the standard bus mastering
+ * interface functionality. This assumes the BIOS did the drive set up and
+ * tuning for us. By default we do not grab all IDE class devices as they
+ * may have other drivers or need fixups to avoid problems. Instead we keep
+ * a default list of stuff without documentation/driver that appears to
+ * work.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "ata_generic"
+#define DRV_VERSION "0.2.6"
+
+/*
+ * A generic parallel ATA driver using libata
+ */
+
+/**
+ * generic_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int generic_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * generic_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+
+static void generic_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, generic_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * generic_set_mode - mode setting
+ * @ap: interface to set up
+ *
+ * Use a non standard set_mode function. We don't want to be tuned.
+ * The BIOS configured everything. Our job is not to fiddle. We
+ * read the dma enabled bits from the PCI configuration of the device
+ * and respect them.
+ */
+
+static void generic_set_mode(struct ata_port *ap)
+{
+ int dma_enabled = 0;
+ int i;
+
+ /* Bits 5 and 6 indicate if DMA is active on master/slave */
+ if (ap->ioaddr.bmdma_addr)
+ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = XFER_MW_DMA_0;
+ /* We do need the right mode information for DMA or PIO
+ and this comes from the current configuration flags */
+ if (dma_enabled & (1 << (5 + i))) {
+ dev->xfer_mode = XFER_MW_DMA_0;
+ dev->xfer_shift = ATA_SHIFT_MWDMA;
+ dev->flags &= ~ATA_DFLAG_PIO;
+ } else {
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+ }
+}
+
+static struct scsi_host_template generic_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations generic_port_ops = {
+ .set_mode = generic_set_mode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = generic_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int all_generic_ide; /* Set to claim all devices */
+
+/**
+ * ata_generic_init - attach generic IDE
+ * @dev: PCI device found
+ * @id: match entry
+ *
+ * Called each time a matching IDE interface is found. We check if the
+ * interface is one we wish to claim and if so we perform any chip
+ * specific hacks then let the ATA layer do the heavy lifting.
+ */
+
+static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u16 command;
+ static struct ata_port_info info = {
+ .sht = &generic_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &generic_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ /* Don't use the generic entry unless instructed to do so */
+ if (id->driver_data == 1 && all_generic_ide == 0)
+ return -ENODEV;
+
+ /* Devices that need care */
+ if (dev->vendor == PCI_VENDOR_ID_UMC &&
+ dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ return -ENODEV;
+
+ if (dev->vendor == PCI_VENDOR_ID_OPTI &&
+ dev->device == PCI_DEVICE_ID_OPTI_82C558 &&
+ (!(PCI_FUNC(dev->devfn) & 1)))
+ return -ENODEV;
+
+ /* Don't re-enable devices in generic mode or we will break some
+ motherboards with disabled and unused IDE controllers */
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO))
+ return -ENODEV;
+
+ if (dev->vendor == PCI_VENDOR_ID_AL)
+ ata_pci_clear_simplex(dev);
+
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id ata_generic[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565), },
+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F), },
+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A), },
+ { PCI_DEVICE(PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF), },
+ { PCI_DEVICE(PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561), },
+ { PCI_DEVICE(PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2), },
+ /* Must come last. If you add entries adjust this table appropriately */
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 1},
+ { 0, },
+};
+
+static struct pci_driver ata_generic_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ata_generic,
+ .probe = ata_generic_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init ata_generic_init(void)
+{
+ return pci_module_init(&ata_generic_pci_driver);
+}
+
+
+static void __exit ata_generic_exit(void)
+{
+ pci_unregister_driver(&ata_generic_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for generic ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ata_generic);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ata_generic_init);
+module_exit(ata_generic_exit);
+
+module_param(all_generic_ide, int, 0);
diff --git a/drivers/scsi/ata_piix.c b/drivers/ata/ata_piix.c
index 521b718763f..5719704eb0e 100644
--- a/drivers/scsi/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -93,7 +93,7 @@
#include <linux/libata.h>
#define DRV_NAME "ata_piix"
-#define DRV_VERSION "1.10"
+#define DRV_VERSION "2.00ac6"
enum {
PIIX_IOCFG = 0x54, /* IDE I/O configuration register */
@@ -105,9 +105,6 @@ enum {
PIIX_FLAG_SCR = (1 << 26), /* SCR available */
PIIX_FLAG_AHCI = (1 << 27), /* AHCI possible */
PIIX_FLAG_CHECKINTR = (1 << 28), /* make sure PCI INTx enabled */
- PIIX_FLAG_COMBINED = (1 << 29), /* combined mode possible */
- /* ICH6/7 use different scheme for map value */
- PIIX_FLAG_COMBINED_ICH6 = PIIX_FLAG_COMBINED | (1 << 30),
/* combined mode. if set, PATA is channel 0.
* if clear, PATA is channel 1.
@@ -119,13 +116,18 @@ enum {
PIIX_80C_SEC = (1 << 7) | (1 << 6),
/* controller IDs */
- piix4_pata = 0,
- ich5_pata = 1,
- ich5_sata = 2,
- esb_sata = 3,
- ich6_sata = 4,
- ich6_sata_ahci = 5,
- ich6m_sata_ahci = 6,
+ piix_pata_33 = 0, /* PIIX3 or 4 at 33Mhz */
+ ich_pata_33 = 1, /* ICH up to UDMA 33 only */
+ ich_pata_66 = 2, /* ICH up to 66 Mhz */
+ ich_pata_100 = 3, /* ICH up to UDMA 100 */
+ ich_pata_133 = 4, /* ICH up to UDMA 133 */
+ ich5_sata = 5,
+ esb_sata = 6,
+ ich6_sata = 7,
+ ich6_sata_ahci = 8,
+ ich6m_sata_ahci = 9,
+ ich7m_sata_ahci = 10,
+ ich8_sata_ahci = 11,
/* constants for mapping table */
P0 = 0, /* port 0 */
@@ -141,24 +143,67 @@ enum {
struct piix_map_db {
const u32 mask;
+ const u16 port_enable;
+ const int present_shift;
const int map[][4];
};
+struct piix_host_priv {
+ const int *map;
+ const struct piix_map_db *map_db;
+};
+
static int piix_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static void piix_host_stop(struct ata_host *host);
static void piix_pata_error_handler(struct ata_port *ap);
+static void ich_pata_error_handler(struct ata_port *ap);
static void piix_sata_error_handler(struct ata_port *ap);
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev);
static unsigned int in_module_init = 1;
static const struct pci_device_id piix_pci_tbl[] = {
#ifdef ATA_ENABLE_PATA
- { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
- { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
- { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
- { 0x8086, 0x27df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+ /* Intel PIIX4 for the 430TX/440BX/MX chipset: UDMA 33 */
+ /* Also PIIX4E (fn3 rev 2) and PIIX4M (fn3 rev 3) */
+ { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ { 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel PIIX4 */
+ { 0x8086, 0x7199, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ /* Intel PIIX4 */
+ { 0x8086, 0x7601, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ /* Intel PIIX */
+ { 0x8086, 0x84CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix_pata_33 },
+ /* Intel ICH (i810, i815, i840) UDMA 66*/
+ { 0x8086, 0x2411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_66 },
+ /* Intel ICH0 : UDMA 33*/
+ { 0x8086, 0x2421, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_33 },
+ /* Intel ICH2M */
+ { 0x8086, 0x244A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH2 (i810E2, i845, 850, 860) UDMA 100 */
+ { 0x8086, 0x244B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH3M */
+ { 0x8086, 0x248A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH3 (E7500/1) UDMA 100 */
+ { 0x8086, 0x248B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH4 (i845GV, i845E, i852, i855) UDMA 100 */
+ { 0x8086, 0x24CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ { 0x8086, 0x24CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* Intel ICH5 */
+ { 0x8086, 0x24DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ /* C-ICH (i810E2) */
+ { 0x8086, 0x245B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* ESB (855GME/875P + 6300ESB) UDMA 100 */
+ { 0x8086, 0x25A2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* ICH6 (and 6) (i915) UDMA 100 */
+ { 0x8086, 0x266F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
+ /* ICH7/7-R (i945, i975) UDMA 100*/
+ { 0x8086, 0x27DF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_133 },
+ { 0x8086, 0x269E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
#endif
/* NOTE: The following PCI ids must be kept in sync with the
@@ -182,15 +227,15 @@ static const struct pci_device_id piix_pci_tbl[] = {
/* 82801GB/GR/GH (ICH7, identical to ICH6) */
{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
/* 2801GBM/GHM (ICH7M, identical to ICH6M) */
- { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+ { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7m_sata_ahci },
/* Enterprise Southbridge 2 (where's the datasheet?) */
{ 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
/* SATA Controller 1 IDE (ICH8, no datasheet yet) */
- { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* SATA Controller 2 IDE (ICH8, ditto) */
- { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+ { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
/* Mobile SATA Controller IDE (ICH8M, ditto) */
- { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6m_sata_ahci },
+ { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
{ } /* terminate list */
};
@@ -254,6 +299,39 @@ static const struct ata_port_operations piix_pata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
+ .host_stop = piix_host_stop,
+};
+
+static const struct ata_port_operations ich_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = piix_set_piomode,
+ .set_dmamode = ich_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ich_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
.host_stop = ata_host_stop,
};
@@ -284,11 +362,13 @@ static const struct ata_port_operations piix_sata_ops = {
.port_start = ata_port_start,
.port_stop = ata_port_stop,
- .host_stop = ata_host_stop,
+ .host_stop = piix_host_stop,
};
-static struct piix_map_db ich5_map_db = {
+static const struct piix_map_db ich5_map_db = {
.mask = 0x7,
+ .port_enable = 0x3,
+ .present_shift = 4,
.map = {
/* PM PS SM SS MAP */
{ P0, NA, P1, NA }, /* 000b */
@@ -302,8 +382,10 @@ static struct piix_map_db ich5_map_db = {
},
};
-static struct piix_map_db ich6_map_db = {
+static const struct piix_map_db ich6_map_db = {
.mask = 0x3,
+ .port_enable = 0xf,
+ .present_shift = 4,
.map = {
/* PM PS SM SS MAP */
{ P0, P2, P1, P3 }, /* 00b */
@@ -313,8 +395,10 @@ static struct piix_map_db ich6_map_db = {
},
};
-static struct piix_map_db ich6m_map_db = {
+static const struct piix_map_db ich6m_map_db = {
.mask = 0x3,
+ .port_enable = 0x5,
+ .present_shift = 4,
.map = {
/* PM PS SM SS MAP */
{ P0, P2, RV, RV }, /* 00b */
@@ -324,96 +408,178 @@ static struct piix_map_db ich6m_map_db = {
},
};
+static const struct piix_map_db ich7m_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x5,
+ .present_shift = 4,
+
+ /* Map 01b isn't specified in the doc but some notebooks use
+ * it anyway. ATM, the only case spotted carries subsystem ID
+ * 1025:0107. This is the only difference from ich6m.
+ */
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, P2, RV, RV }, /* 00b */
+ { IDE, IDE, P1, P3 }, /* 01b */
+ { P0, P2, IDE, IDE }, /* 10b */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db ich8_map_db = {
+ .mask = 0x3,
+ .port_enable = 0x3,
+ .present_shift = 8,
+ .map = {
+ /* PM PS SM SS MAP */
+ { P0, NA, P1, NA }, /* 00b (hardwired) */
+ { RV, RV, RV, RV },
+ { RV, RV, RV, RV }, /* 10b (never) */
+ { RV, RV, RV, RV },
+ },
+};
+
+static const struct piix_map_db *piix_map_db_table[] = {
+ [ich5_sata] = &ich5_map_db,
+ [esb_sata] = &ich5_map_db,
+ [ich6_sata] = &ich6_map_db,
+ [ich6_sata_ahci] = &ich6_map_db,
+ [ich6m_sata_ahci] = &ich6m_map_db,
+ [ich7m_sata_ahci] = &ich7m_map_db,
+ [ich8_sata_ahci] = &ich8_map_db,
+};
+
static struct ata_port_info piix_port_info[] = {
- /* piix4_pata */
+ /* piix_pata_33: 0: PIIX3 or 4 at 33MHz */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
.pio_mask = 0x1f, /* pio0-4 */
-#if 0
- .mwdma_mask = 0x06, /* mwdma1-2 */
-#else
- .mwdma_mask = 0x00, /* mwdma broken */
-#endif
+ .mwdma_mask = 0x06, /* mwdma1-2 ?? CHECK 0 should be ok but slow */
.udma_mask = ATA_UDMA_MASK_40C,
.port_ops = &piix_pata_ops,
},
- /* ich5_pata */
+ /* ich_pata_33: 1 ICH0 - ICH at 33Mhz*/
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */
+ .udma_mask = ATA_UDMA2, /* UDMA33 */
+ .port_ops = &ich_pata_ops,
+ },
+ /* ich_pata_66: 2 ICH controllers up to 66MHz */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .mwdma_mask = 0x06, /* MWDMA0 is broken on chip */
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &ich_pata_ops,
+ },
+
+ /* ich_pata_100: 3 */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
.pio_mask = 0x1f, /* pio0-4 */
-#if 0
.mwdma_mask = 0x06, /* mwdma1-2 */
-#else
- .mwdma_mask = 0x00, /* mwdma broken */
-#endif
- .udma_mask = 0x3f, /* udma0-5 */
- .port_ops = &piix_pata_ops,
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &ich_pata_ops,
},
- /* ich5_sata */
+ /* ich_pata_133: 4 ICH with full UDMA6 */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
- PIIX_FLAG_CHECKINTR,
+ .flags = ATA_FLAG_SRST | ATA_FLAG_SLAVE_POSS | PIIX_FLAG_CHECKINTR,
+ .pio_mask = 0x1f, /* pio 0-4 */
+ .mwdma_mask = 0x06, /* Check: maybe 0x07 */
+ .udma_mask = ATA_UDMA6, /* UDMA133 */
+ .port_ops = &ich_pata_ops,
+ },
+
+ /* ich5_sata: 5 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA | PIIX_FLAG_CHECKINTR |
+ PIIX_FLAG_IGNORE_PCS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich5_map_db,
},
- /* i6300esb_sata */
+ /* i6300esb_sata: 6 */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED |
+ .flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_IGNORE_PCS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich5_map_db,
},
- /* ich6_sata */
+ /* ich6_sata: 7 */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ .flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich6_map_db,
},
- /* ich6_sata_ahci */
+ /* ich6_sata_ahci: 8 */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ .flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich6_map_db,
},
- /* ich6m_sata_ahci */
+ /* ich6m_sata_ahci: 9 */
{
.sht = &piix_sht,
- .host_flags = ATA_FLAG_SATA | PIIX_FLAG_COMBINED_ICH6 |
+ .flags = ATA_FLAG_SATA |
PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
PIIX_FLAG_AHCI,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &piix_sata_ops,
- .private_data = &ich6m_map_db,
},
+
+ /* ich7m_sata_ahci: 10 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
+ /* ich8_sata_ahci: 11 */
+ {
+ .sht = &piix_sht,
+ .flags = ATA_FLAG_SATA |
+ PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
+ PIIX_FLAG_AHCI,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &piix_sata_ops,
+ },
+
};
static struct pci_bits piix_enable_bits[] = {
@@ -427,6 +593,11 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
MODULE_VERSION(DRV_VERSION);
+static int force_pcs = 0;
+module_param(force_pcs, int, 0444);
+MODULE_PARM_DESC(force_pcs, "force honoring or ignoring PCS to work around "
+ "device mis-detection (0=default, 1=ignore PCS, 2=honor PCS)");
+
/**
* piix_pata_cbl_detect - Probe host controller cable detect info
* @ap: Port for which cable detect info is desired
@@ -437,9 +608,10 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING:
* None (inherited from caller).
*/
-static void piix_pata_cbl_detect(struct ata_port *ap)
+
+static void ich_pata_cbl_detect(struct ata_port *ap)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 tmp, mask;
/* no 80c support in host controller? */
@@ -447,7 +619,7 @@ static void piix_pata_cbl_detect(struct ata_port *ap)
goto cbl40;
/* check BIOS cable detect results */
- mask = ap->hard_port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
+ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
if ((tmp & mask) == 0)
goto cbl40;
@@ -457,108 +629,141 @@ static void piix_pata_cbl_detect(struct ata_port *ap)
cbl40:
ap->cbl = ATA_CBL_PATA40;
- ap->udma_mask &= ATA_UDMA_MASK_40C;
}
/**
* piix_pata_prereset - prereset for PATA host controller
* @ap: Target port
*
- * Prereset including cable detection.
*
* LOCKING:
* None (inherited from caller).
*/
static int piix_pata_prereset(struct ata_port *ap)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void piix_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
+ ata_std_postreset);
+}
- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
+
+/**
+ * ich_pata_prereset - prereset for PATA host controller
+ * @ap: Target port
+ *
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static int ich_pata_prereset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) {
ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
return 0;
}
- piix_pata_cbl_detect(ap);
+ ich_pata_cbl_detect(ap);
return ata_std_prereset(ap);
}
-static void piix_pata_error_handler(struct ata_port *ap)
+static void ich_pata_error_handler(struct ata_port *ap)
{
- ata_bmdma_drive_eh(ap, piix_pata_prereset, ata_std_softreset, NULL,
+ ata_bmdma_drive_eh(ap, ich_pata_prereset, ata_std_softreset, NULL,
ata_std_postreset);
}
/**
- * piix_sata_prereset - prereset for SATA host controller
+ * piix_sata_present_mask - determine present mask for SATA host controller
* @ap: Target port
*
- * Reads and configures SATA PCI device's PCI config register
- * Port Configuration and Status (PCS) to determine port and
- * device availability. Return -ENODEV to skip reset if no
- * device is present.
+ * Reads SATA PCI device's PCI config register Port Configuration
+ * and Status (PCS) to determine port and device availability.
*
* LOCKING:
* None (inherited from caller).
*
* RETURNS:
- * 0 if device is present, -ENODEV otherwise.
+ * determined present_mask
*/
-static int piix_sata_prereset(struct ata_port *ap)
+static unsigned int piix_sata_present_mask(struct ata_port *ap)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
- const unsigned int *map = ap->host_set->private_data;
- int base = 2 * ap->hard_port_no;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct piix_host_priv *hpriv = ap->host->private_data;
+ const unsigned int *map = hpriv->map;
+ int base = 2 * ap->port_no;
unsigned int present_mask = 0;
int port, i;
- u8 pcs;
+ u16 pcs;
- pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+ pci_read_config_word(pdev, ICH5_PCS, &pcs);
DPRINTK("ata%u: ENTER, pcs=0x%x base=%d\n", ap->id, pcs, base);
- /* enable all ports on this ap and wait for them to settle */
- for (i = 0; i < 2; i++) {
- port = map[base + i];
- if (port >= 0)
- pcs |= 1 << port;
- }
-
- pci_write_config_byte(pdev, ICH5_PCS, pcs);
- msleep(100);
-
- /* let's see which devices are present */
- pci_read_config_byte(pdev, ICH5_PCS, &pcs);
-
for (i = 0; i < 2; i++) {
port = map[base + i];
if (port < 0)
continue;
- if (ap->flags & PIIX_FLAG_IGNORE_PCS || pcs & 1 << (4 + port))
+ if ((ap->flags & PIIX_FLAG_IGNORE_PCS) ||
+ (pcs & 1 << (hpriv->map_db->present_shift + port)))
present_mask |= 1 << i;
- else
- pcs &= ~(1 << port);
}
- /* disable offline ports on non-AHCI controllers */
- if (!(ap->flags & PIIX_FLAG_AHCI))
- pci_write_config_byte(pdev, ICH5_PCS, pcs);
-
DPRINTK("ata%u: LEAVE, pcs=0x%x present_mask=0x%x\n",
ap->id, pcs, present_mask);
- if (!present_mask) {
- ata_port_printk(ap, KERN_INFO, "SATA port has no device.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
- return 0;
+ return present_mask;
+}
+
+/**
+ * piix_sata_softreset - reset SATA host port via ATA SRST
+ * @ap: port to reset
+ * @classes: resulting classes of attached devices
+ *
+ * Reset SATA host port via ATA SRST. On controllers with
+ * reliable PCS present bits, the bits are used to determine
+ * device presence.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int piix_sata_softreset(struct ata_port *ap, unsigned int *classes)
+{
+ unsigned int present_mask;
+ int i, rc;
+
+ present_mask = piix_sata_present_mask(ap);
+
+ rc = ata_std_softreset(ap, classes);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ if (!(present_mask & (1 << i)))
+ classes[i] = ATA_DEV_NONE;
}
- return ata_std_prereset(ap);
+ return 0;
}
static void piix_sata_error_handler(struct ata_port *ap)
{
- ata_bmdma_drive_eh(ap, piix_sata_prereset, ata_std_softreset, NULL,
+ ata_bmdma_drive_eh(ap, ata_std_prereset, piix_sata_softreset, NULL,
ata_std_postreset);
}
@@ -576,12 +781,19 @@ static void piix_sata_error_handler(struct ata_port *ap)
static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
unsigned int pio = adev->pio_mode - XFER_PIO_0;
- struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
unsigned int is_slave = (adev->devno != 0);
- unsigned int master_port= ap->hard_port_no ? 0x42 : 0x40;
+ unsigned int master_port= ap->port_no ? 0x42 : 0x40;
unsigned int slave_port = 0x44;
u16 master_data;
u8 slave_data;
+ u8 udma_enable;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for ICH controllers.
+ */
static const /* ISP RTC */
u8 timings[][2] = { { 0, 0 },
@@ -590,20 +802,30 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
{ 2, 1 },
{ 2, 3 }, };
+ if (pio >= 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE enable */
+
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
pci_read_config_word(dev, master_port, &master_data);
if (is_slave) {
+ /* Enable SITRE (seperate slave timing register) */
master_data |= 0x4000;
- /* enable PPE, IE and TIME */
- master_data |= 0x0070;
+ /* enable PPE1, IE1 and TIME1 as needed */
+ master_data |= (control << 4);
pci_read_config_byte(dev, slave_port, &slave_data);
- slave_data &= (ap->hard_port_no ? 0x0f : 0xf0);
- slave_data |=
- (timings[pio][0] << 2) |
- (timings[pio][1] << (ap->hard_port_no ? 4 : 0));
+ slave_data &= (ap->port_no ? 0x0f : 0xf0);
+ /* Load the timing nibble for this slave */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
} else {
+ /* Master keeps the bits in a different format */
master_data &= 0xccf8;
- /* enable PPE, IE and TIME */
- master_data |= 0x0007;
+ /* Enable PPE, IE and TIME as appropriate */
+ master_data |= control;
master_data |=
(timings[pio][0] << 12) |
(timings[pio][1] << 8);
@@ -611,13 +833,23 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
pci_write_config_byte(dev, slave_port, slave_data);
+
+ /* Ensure the UDMA bit is off - it will be turned back on if
+ UDMA is selected */
+
+ if (ap->udma_mask) {
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+ udma_enable &= ~(1 << (2 * ap->port_no + adev->devno));
+ pci_write_config_byte(dev, 0x48, udma_enable);
+ }
}
/**
- * piix_set_dmamode - Initialize host controller PATA PIO timings
+ * do_pata_set_dmamode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
- * @adev: um
+ * @adev: Drive in question
* @udma: udma mode, 0 - 6
+ * @isich: set if the chip is an ICH device
*
* Set UDMA mode for device, in host controller PCI config space.
*
@@ -625,70 +857,140 @@ static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
* None (inherited from caller).
*/
-static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+static void do_pata_set_dmamode (struct ata_port *ap, struct ata_device *adev, int isich)
{
- unsigned int udma = adev->dma_mode; /* FIXME: MWDMA too */
- struct pci_dev *dev = to_pci_dev(ap->host_set->dev);
- u8 maslave = ap->hard_port_no ? 0x42 : 0x40;
- u8 speed = udma;
- unsigned int drive_dn = (ap->hard_port_no ? 2 : 0) + adev->devno;
- int a_speed = 3 << (drive_dn * 4);
- int u_flag = 1 << drive_dn;
- int v_flag = 0x01 << drive_dn;
- int w_flag = 0x10 << drive_dn;
- int u_speed = 0;
- int sitre;
- u16 reg4042, reg4a;
- u8 reg48, reg54, reg55;
-
- pci_read_config_word(dev, maslave, &reg4042);
- DPRINTK("reg4042 = 0x%04x\n", reg4042);
- sitre = (reg4042 & 0x4000) ? 1 : 0;
- pci_read_config_byte(dev, 0x48, &reg48);
- pci_read_config_word(dev, 0x4a, &reg4a);
- pci_read_config_byte(dev, 0x54, &reg54);
- pci_read_config_byte(dev, 0x55, &reg55);
-
- switch(speed) {
- case XFER_UDMA_4:
- case XFER_UDMA_2: u_speed = 2 << (drive_dn * 4); break;
- case XFER_UDMA_6:
- case XFER_UDMA_5:
- case XFER_UDMA_3:
- case XFER_UDMA_1: u_speed = 1 << (drive_dn * 4); break;
- case XFER_UDMA_0: u_speed = 0 << (drive_dn * 4); break;
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1: break;
- default:
- BUG();
- return;
- }
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno + 2 * ap->port_no;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, master_port, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
if (speed >= XFER_UDMA_0) {
- if (!(reg48 & u_flag))
- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- if (speed == XFER_UDMA_5) {
- pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
- } else {
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+ u16 ideconf;
+ int u_clock, u_speed;
+
+ /*
+ * UDMA is handled by a combination of clock switching and
+ * selection of dividers
+ *
+ * Handy rule: Odd modes are UDMATIMx 01, even are 02
+ * except UDMA0 which is 00
+ */
+ u_speed = min(2 - (udma & 1), udma);
+ if (udma == 5)
+ u_clock = 0x1000; /* 100Mhz */
+ else if (udma > 2)
+ u_clock = 1; /* 66Mhz */
+ else
+ u_clock = 0; /* 33Mhz */
+
+ udma_enable |= (1 << devid);
+
+ /* Load the CT/RP selection */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(3 << (4 * devid));
+ udma_timing |= u_speed << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+
+ if (isich) {
+ /* Select a 33/66/100Mhz clock */
+ pci_read_config_word(dev, 0x54, &ideconf);
+ ideconf &= ~(0x1001 << devid);
+ ideconf |= u_clock << devid;
+ /* For ICH or later we should set bit 10 for better
+ performance (WR_PingPong_En) */
+ pci_write_config_word(dev, 0x54, ideconf);
}
- if ((reg4a & a_speed) != u_speed)
- pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
- if (speed > XFER_UDMA_2) {
- if (!(reg54 & v_flag))
- pci_write_config_byte(dev, 0x54, reg54 | v_flag);
- } else
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
} else {
- if (reg48 & u_flag)
- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
- if (reg4a & a_speed)
- pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
- if (reg54 & v_flag)
- pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
- if (reg55 & w_flag)
- pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (adev->devno) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (0x0F + 0xE1 * ap->port_no);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, master_port, master_data);
}
+ /* Don't scribble on 0x48 if the controller does not support UDMA */
+ if (ap->udma_mask)
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+/**
+ * piix_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ do_pata_set_dmamode(ap, adev, 0);
+}
+
+/**
+ * ich_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void ich_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ do_pata_set_dmamode(ap, adev, 1);
}
#define AHCI_PCI_BAR 5
@@ -761,10 +1063,40 @@ static int __devinit piix_check_450nx_errata(struct pci_dev *ata_dev)
return no_piix_dma;
}
+static void __devinit piix_init_pcs(struct pci_dev *pdev,
+ struct ata_port_info *pinfo,
+ const struct piix_map_db *map_db)
+{
+ u16 pcs, new_pcs;
+
+ pci_read_config_word(pdev, ICH5_PCS, &pcs);
+
+ new_pcs = pcs | map_db->port_enable;
+
+ if (new_pcs != pcs) {
+ DPRINTK("updating PCS from 0x%x to 0x%x\n", pcs, new_pcs);
+ pci_write_config_word(pdev, ICH5_PCS, new_pcs);
+ msleep(150);
+ }
+
+ if (force_pcs == 1) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "force ignoring PCS (0x%x)\n", new_pcs);
+ pinfo[0].flags |= PIIX_FLAG_IGNORE_PCS;
+ pinfo[1].flags |= PIIX_FLAG_IGNORE_PCS;
+ } else if (force_pcs == 2) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "force honoring PCS (0x%x)\n", new_pcs);
+ pinfo[0].flags &= ~PIIX_FLAG_IGNORE_PCS;
+ pinfo[1].flags &= ~PIIX_FLAG_IGNORE_PCS;
+ }
+}
+
static void __devinit piix_init_sata_map(struct pci_dev *pdev,
- struct ata_port_info *pinfo)
+ struct ata_port_info *pinfo,
+ const struct piix_map_db *map_db)
{
- struct piix_map_db *map_db = pinfo[0].private_data;
+ struct piix_host_priv *hpriv = pinfo[0].private_data;
const unsigned int *map;
int i, invalid_map = 0;
u8 map_value;
@@ -787,7 +1119,8 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
case IDE:
WARN_ON((i & 1) || map[i + 1] != IDE);
- pinfo[i / 2] = piix_port_info[ich5_pata];
+ pinfo[i / 2] = piix_port_info[ich_pata_100];
+ pinfo[i / 2].private_data = hpriv;
i++;
printk(" IDE IDE");
break;
@@ -795,7 +1128,7 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
default:
printk(" P%d", map[i]);
if (i & 1)
- pinfo[i / 2].host_flags |= ATA_FLAG_SLAVE_POSS;
+ pinfo[i / 2].flags |= ATA_FLAG_SLAVE_POSS;
break;
}
}
@@ -805,8 +1138,8 @@ static void __devinit piix_init_sata_map(struct pci_dev *pdev,
dev_printk(KERN_ERR, &pdev->dev,
"invalid MAP value %u\n", map_value);
- pinfo[0].private_data = (void *)map;
- pinfo[1].private_data = (void *)map;
+ hpriv->map = map;
+ hpriv->map_db = map_db;
}
/**
@@ -829,7 +1162,8 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
static int printed_version;
struct ata_port_info port_info[2];
struct ata_port_info *ppinfo[2] = { &port_info[0], &port_info[1] };
- unsigned long host_flags;
+ struct piix_host_priv *hpriv;
+ unsigned long port_flags;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev,
@@ -839,12 +1173,18 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (!in_module_init)
return -ENODEV;
+ hpriv = kzalloc(sizeof(*hpriv), GFP_KERNEL);
+ if (!hpriv)
+ return -ENOMEM;
+
port_info[0] = piix_port_info[ent->driver_data];
port_info[1] = piix_port_info[ent->driver_data];
+ port_info[0].private_data = hpriv;
+ port_info[1].private_data = hpriv;
- host_flags = port_info[0].host_flags;
+ port_flags = port_info[0].flags;
- if (host_flags & PIIX_FLAG_AHCI) {
+ if (port_flags & PIIX_FLAG_AHCI) {
u8 tmp;
pci_read_config_byte(pdev, PIIX_SCC, &tmp);
if (tmp == PIIX_AHCI_DEVICE) {
@@ -855,8 +1195,12 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Initialize SATA map */
- if (host_flags & ATA_FLAG_SATA)
- piix_init_sata_map(pdev, port_info);
+ if (port_flags & ATA_FLAG_SATA) {
+ piix_init_sata_map(pdev, port_info,
+ piix_map_db_table[ent->driver_data]);
+ piix_init_pcs(pdev, port_info,
+ piix_map_db_table[ent->driver_data]);
+ }
/* On ICH5, some BIOSen disable the interrupt using the
* PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
@@ -864,7 +1208,7 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
* MSI is disabled (and it is disabled, as we don't use
* message-signalled interrupts currently).
*/
- if (host_flags & PIIX_FLAG_CHECKINTR)
+ if (port_flags & PIIX_FLAG_CHECKINTR)
pci_intx(pdev, 1);
if (piix_check_450nx_errata(pdev)) {
@@ -879,12 +1223,21 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return ata_pci_init_one(pdev, ppinfo, 2);
}
+static void piix_host_stop(struct ata_host *host)
+{
+ struct piix_host_priv *hpriv = host->private_data;
+
+ ata_host_stop(host);
+
+ kfree(hpriv);
+}
+
static int __init piix_init(void)
{
int rc;
- DPRINTK("pci_module_init\n");
- rc = pci_module_init(&piix_pci_driver);
+ DPRINTK("pci_register_driver\n");
+ rc = pci_register_driver(&piix_pci_driver);
if (rc)
return rc;
@@ -901,4 +1254,3 @@ static void __exit piix_exit(void)
module_init(piix_init);
module_exit(piix_exit);
-
diff --git a/drivers/scsi/libata-core.c b/drivers/ata/libata-core.c
index 6c66877be2b..b4abd685036 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -32,7 +32,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -51,7 +50,6 @@
#include <linux/jiffies.h>
#include <linux/scatterlist.h>
#include <scsi/scsi.h>
-#include "scsi_priv.h"
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
@@ -62,9 +60,9 @@
#include "libata.h"
/* debounce timing parameters in msecs { interval, duration, timeout } */
-const unsigned long sata_deb_timing_boot[] = { 5, 100, 2000 };
-const unsigned long sata_deb_timing_eh[] = { 25, 500, 2000 };
-const unsigned long sata_deb_timing_before_fsrst[] = { 100, 2000, 5000 };
+const unsigned long sata_deb_timing_normal[] = { 5, 100, 2000 };
+const unsigned long sata_deb_timing_hotplug[] = { 25, 500, 2000 };
+const unsigned long sata_deb_timing_long[] = { 100, 2000, 5000 };
static unsigned int ata_dev_init_params(struct ata_device *dev,
u16 heads, u16 sectors);
@@ -88,6 +86,10 @@ int libata_fua = 0;
module_param_named(fua, libata_fua, int, 0444);
MODULE_PARM_DESC(fua, "FUA support (0=off, 1=on)");
+static int ata_probe_timeout = ATA_TMOUT_INTERNAL / HZ;
+module_param(ata_probe_timeout, int, 0444);
+MODULE_PARM_DESC(ata_probe_timeout, "Set ATA probing timeout (seconds)");
+
MODULE_AUTHOR("Jeff Garzik");
MODULE_DESCRIPTION("Library module for ATA devices");
MODULE_LICENSE("GPL");
@@ -384,9 +386,13 @@ static const char *ata_mode_string(unsigned int xfer_mask)
"PIO2",
"PIO3",
"PIO4",
+ "PIO5",
+ "PIO6",
"MWDMA0",
"MWDMA1",
"MWDMA2",
+ "MWDMA3",
+ "MWDMA4",
"UDMA/16",
"UDMA/25",
"UDMA/33",
@@ -610,8 +616,11 @@ ata_dev_try_classify(struct ata_port *ap, unsigned int device, u8 *r_err)
if (r_err)
*r_err = err;
- /* see if device passed diags */
- if (err == 1)
+ /* see if device passed diags: if master then continue and warn later */
+ if (err == 0 && device == 0)
+ /* diagnostic fail : do nothing _YET_ */
+ ap->device[device].horkage |= ATA_HORKAGE_DIAGNOSTIC;
+ else if (err == 1)
/* do nothing */ ;
else if ((device == 0) && (err == 0x81))
/* do nothing */ ;
@@ -777,11 +786,9 @@ void ata_std_dev_select (struct ata_port *ap, unsigned int device)
void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep)
{
- if (ata_msg_probe(ap)) {
+ if (ata_msg_probe(ap))
ata_port_printk(ap, KERN_INFO, "ata_dev_select: ENTER, ata%u: "
- "device %u, wait %u\n",
- ap->id, device, wait);
- }
+ "device %u, wait %u\n", ap->id, device, wait);
if (wait)
ata_wait_idle(ap);
@@ -875,6 +882,23 @@ static unsigned int ata_id_xfermask(const u16 *id)
mwdma_mask = id[ATA_ID_MWDMA_MODES] & 0x07;
+ if (ata_id_is_cfa(id)) {
+ /*
+ * Process compact flash extended modes
+ */
+ int pio = id[163] & 0x7;
+ int dma = (id[163] >> 3) & 7;
+
+ if (pio)
+ pio_mask |= (1 << 5);
+ if (pio > 1)
+ pio_mask |= (1 << 6);
+ if (dma)
+ mwdma_mask |= (1 << 3);
+ if (dma > 1)
+ mwdma_mask |= (1 << 4);
+ }
+
udma_mask = 0;
if (id[ATA_ID_FIELD_VALID] & (1 << 2))
udma_mask = id[ATA_ID_UDMA_MODES] & 0xff;
@@ -906,7 +930,7 @@ void ata_port_queue_task(struct ata_port *ap, void (*fn)(void *), void *data,
{
int rc;
- if (ap->flags & ATA_FLAG_FLUSH_PORT_TASK)
+ if (ap->pflags & ATA_PFLAG_FLUSH_PORT_TASK)
return;
PREPARE_WORK(&ap->port_task, fn, data);
@@ -937,7 +961,7 @@ void ata_port_flush_task(struct ata_port *ap)
DPRINTK("ENTER\n");
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_FLUSH_PORT_TASK;
+ ap->pflags |= ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("flush #1\n");
@@ -950,12 +974,13 @@ void ata_port_flush_task(struct ata_port *ap)
*/
if (!cancel_delayed_work(&ap->port_task)) {
if (ata_msg_ctl(ap))
- ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n", __FUNCTION__);
+ ata_port_printk(ap, KERN_DEBUG, "%s: flush #2\n",
+ __FUNCTION__);
flush_workqueue(ata_wq);
}
spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FLUSH_PORT_TASK;
+ ap->pflags &= ~ATA_PFLAG_FLUSH_PORT_TASK;
spin_unlock_irqrestore(ap->lock, flags);
if (ata_msg_ctl(ap))
@@ -999,7 +1024,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
int rc;
@@ -1007,7 +1032,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_lock_irqsave(ap->lock, flags);
/* no internal command while frozen */
- if (ap->flags & ATA_FLAG_FROZEN) {
+ if (ap->pflags & ATA_PFLAG_FROZEN) {
spin_unlock_irqrestore(ap->lock, flags);
return AC_ERR_SYSTEM;
}
@@ -1059,7 +1084,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
spin_unlock_irqrestore(ap->lock, flags);
- rc = wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL);
+ rc = wait_for_completion_timeout(&wait, ata_probe_timeout);
ata_port_flush_task(ap);
@@ -1081,7 +1106,7 @@ unsigned ata_exec_internal(struct ata_device *dev,
if (ata_msg_warn(ap))
ata_dev_printk(dev, KERN_WARNING,
- "qc timeout (cmd 0x%x)\n", command);
+ "qc timeout (cmd 0x%x)\n", command);
}
spin_unlock_irqrestore(ap->lock, flags);
@@ -1093,9 +1118,9 @@ unsigned ata_exec_internal(struct ata_device *dev,
if (qc->flags & ATA_QCFLAG_FAILED && !qc->err_mask) {
if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
+ ata_dev_printk(dev, KERN_WARNING,
"zero err_mask for failed "
- "internal command, assuming AC_ERR_OTHER\n");
+ "internal command, assuming AC_ERR_OTHER\n");
qc->err_mask |= AC_ERR_OTHER;
}
@@ -1132,6 +1157,33 @@ unsigned ata_exec_internal(struct ata_device *dev,
}
/**
+ * ata_do_simple_cmd - execute simple internal command
+ * @dev: Device to which the command is sent
+ * @cmd: Opcode to execute
+ *
+ * Execute a 'simple' command, that only consists of the opcode
+ * 'cmd' itself, without filling any other registers
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, AC_ERR_* mask on failure
+ */
+unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
+{
+ struct ata_taskfile tf;
+
+ ata_tf_init(dev, &tf);
+
+ tf.command = cmd;
+ tf.flags |= ATA_TFLAG_DEVICE;
+ tf.protocol = ATA_PROT_NODATA;
+
+ return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
+}
+
+/**
* ata_pio_need_iordy - check if iordy needed
* @adev: ATA device
*
@@ -1193,8 +1245,8 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
int rc;
if (ata_msg_ctl(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
- __FUNCTION__, ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
ata_dev_select(ap, dev->devno, 1, 1); /* select device 0/1 */
@@ -1227,10 +1279,15 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
swap_buf_le16(id, ATA_ID_WORDS);
/* sanity check */
- if ((class == ATA_DEV_ATA) != (ata_id_is_ata(id) | ata_id_is_cfa(id))) {
- rc = -EINVAL;
- reason = "device reports illegal type";
- goto err_out;
+ rc = -EINVAL;
+ reason = "device reports illegal type";
+
+ if (class == ATA_DEV_ATA) {
+ if (!ata_id_is_ata(id) && !ata_id_is_cfa(id))
+ goto err_out;
+ } else {
+ if (ata_id_is_ata(id))
+ goto err_out;
}
if (post_reset && class == ATA_DEV_ATA) {
@@ -1263,9 +1320,9 @@ int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
return 0;
err_out:
- if (ata_msg_warn(ap))
+ if (ata_msg_warn(ap))
ata_dev_printk(dev, KERN_WARNING, "failed to IDENTIFY "
- "(%s, err_mask=0x%x)\n", reason, err_mask);
+ "(%s, err_mask=0x%x)\n", reason, err_mask);
return rc;
}
@@ -1286,7 +1343,7 @@ static void ata_dev_config_ncq(struct ata_device *dev,
}
if (ap->flags & ATA_FLAG_NCQ) {
- hdepth = min(ap->host->can_queue, ATA_MAX_QUEUE - 1);
+ hdepth = min(ap->scsi_host->can_queue, ATA_MAX_QUEUE - 1);
dev->flags |= ATA_DFLAG_NCQ;
}
@@ -1296,6 +1353,20 @@ static void ata_dev_config_ncq(struct ata_device *dev,
snprintf(desc, desc_sz, "NCQ (depth %d/%d)", hdepth, ddepth);
}
+static void ata_set_port_max_cmd_len(struct ata_port *ap)
+{
+ int i;
+
+ if (ap->scsi_host) {
+ unsigned int len = 0;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ len = max(len, ap->device[i].cdb_len);
+
+ ap->scsi_host->max_cmd_len = len;
+ }
+}
+
/**
* ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure
@@ -1315,22 +1386,25 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
struct ata_port *ap = dev->ap;
const u16 *id = dev->id;
unsigned int xfer_mask;
- int i, rc;
+ char revbuf[7]; /* XYZ-99\0 */
+ int rc;
if (!ata_dev_enabled(dev) && ata_msg_info(ap)) {
- ata_dev_printk(dev, KERN_INFO, "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
- __FUNCTION__, ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_INFO,
+ "%s: ENTER/EXIT (host %u, dev %u) -- nodev\n",
+ __FUNCTION__, ap->id, dev->devno);
return 0;
}
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
- __FUNCTION__, ap->id, dev->devno);
+ ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER, host %u, dev %u\n",
+ __FUNCTION__, ap->id, dev->devno);
/* print device capabilities */
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG, "%s: cfg 49:%04x 82:%04x 83:%04x "
- "84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+ ata_dev_printk(dev, KERN_DEBUG,
+ "%s: cfg 49:%04x 82:%04x 83:%04x 84:%04x "
+ "85:%04x 86:%04x 87:%04x 88:%04x\n",
__FUNCTION__,
id[49], id[82], id[83], id[84],
id[85], id[86], id[87], id[88]);
@@ -1356,6 +1430,15 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
/* ATA-specific feature tests */
if (dev->class == ATA_DEV_ATA) {
+ if (ata_id_is_cfa(id)) {
+ if (id[162] & 1) /* CPRM may make this media unusable */
+ ata_dev_printk(dev, KERN_WARNING, "ata%u: device %u supports DRM functions and may not be fully accessable.\n",
+ ap->id, dev->devno);
+ snprintf(revbuf, 7, "CFA");
+ }
+ else
+ snprintf(revbuf, 7, "ATA-%d", ata_id_major_version(id));
+
dev->n_sectors = ata_id_n_sectors(id);
if (ata_id_has_lba(id)) {
@@ -1373,10 +1456,10 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
ata_dev_config_ncq(dev, ncq_desc, sizeof(ncq_desc));
/* print device info to dmesg */
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO, "%s, "
"max %s, %Lu sectors: %s %s\n",
- ata_id_major_version(id),
+ revbuf,
ata_mode_string(xfer_mask),
(unsigned long long)dev->n_sectors,
lba_desc, ncq_desc);
@@ -1396,20 +1479,22 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ATA-%d, "
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO, "%s, "
"max %s, %Lu sectors: CHS %u/%u/%u\n",
- ata_id_major_version(id),
+ revbuf,
ata_mode_string(xfer_mask),
(unsigned long long)dev->n_sectors,
- dev->cylinders, dev->heads, dev->sectors);
+ dev->cylinders, dev->heads,
+ dev->sectors);
}
if (dev->id[59] & 0x100) {
dev->multi_count = dev->id[59] & 0xff;
- if (ata_msg_info(ap))
- ata_dev_printk(dev, KERN_INFO, "ata%u: dev %u multi count %u\n",
- ap->id, dev->devno, dev->multi_count);
+ if (ata_msg_drv(ap) && print_info)
+ ata_dev_printk(dev, KERN_INFO,
+ "ata%u: dev %u multi count %u\n",
+ ap->id, dev->devno, dev->multi_count);
}
dev->cdb_len = 16;
@@ -1422,8 +1507,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
rc = atapi_cdb_len(id);
if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
if (ata_msg_warn(ap))
- ata_dev_printk(dev, KERN_WARNING,
- "unsupported CDB len\n");
+ ata_dev_printk(dev, KERN_WARNING,
+ "unsupported CDB len\n");
rc = -EINVAL;
goto err_out_nosup;
}
@@ -1435,21 +1520,29 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
}
/* print device info to dmesg */
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO, "ATAPI, max %s%s\n",
ata_mode_string(xfer_mask),
cdb_intr_string);
}
- ap->host->max_cmd_len = 0;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ap->host->max_cmd_len = max_t(unsigned int,
- ap->host->max_cmd_len,
- ap->device[i].cdb_len);
+ if (dev->horkage & ATA_HORKAGE_DIAGNOSTIC) {
+ /* Let the user know. We don't want to disallow opens for
+ rescue purposes, or in case the vendor is just a blithering
+ idiot */
+ if (print_info) {
+ ata_dev_printk(dev, KERN_WARNING,
+"Drive reports diagnostics failure. This may indicate a drive\n");
+ ata_dev_printk(dev, KERN_WARNING,
+"fault or invalid emulation. Contact drive vendor for information.\n");
+ }
+ }
+
+ ata_set_port_max_cmd_len(ap);
/* limit bridge transfers to udma5, 200 sectors */
if (ata_dev_knobble(dev)) {
- if (ata_msg_info(ap))
+ if (ata_msg_drv(ap) && print_info)
ata_dev_printk(dev, KERN_INFO,
"applying bridge limits\n");
dev->udma_mask &= ATA_UDMA5;
@@ -1466,8 +1559,8 @@ int ata_dev_configure(struct ata_device *dev, int print_info)
err_out_nosup:
if (ata_msg_probe(ap))
- ata_dev_printk(dev, KERN_DEBUG,
- "%s: EXIT, err\n", __FUNCTION__);
+ ata_dev_printk(dev, KERN_DEBUG,
+ "%s: EXIT, err\n", __FUNCTION__);
return rc;
}
@@ -1486,7 +1579,7 @@ err_out_nosup:
* Zero on success, negative errno otherwise.
*/
-static int ata_bus_probe(struct ata_port *ap)
+int ata_bus_probe(struct ata_port *ap)
{
unsigned int classes[ATA_MAX_DEVICES];
int tries[ATA_MAX_DEVICES];
@@ -1590,7 +1683,7 @@ static int ata_bus_probe(struct ata_port *ap)
* Modify @ap data structure such that the system
* thinks that the entire port is enabled.
*
- * LOCKING: host_set lock, or some other form of
+ * LOCKING: host lock, or some other form of
* serialization.
*/
@@ -1728,7 +1821,7 @@ struct ata_device *ata_dev_pair(struct ata_device *adev)
* never attempt to probe or communicate with devices
* on this port.
*
- * LOCKING: host_set lock, or some other form of
+ * LOCKING: host lock, or some other form of
* serialization.
*/
@@ -1859,10 +1952,11 @@ int sata_set_spd(struct ata_port *ap)
* drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik
*/
/*
- * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
+ * PIO 0-4, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds).
* These were taken from ATA/ATAPI-6 standard, rev 0a, except
- * for PIO 5, which is a nonstandard extension and UDMA6, which
- * is currently supported only by Maxtor drives.
+ * for UDMA6, which is currently supported only by Maxtor drives.
+ *
+ * For PIO 5/6 MWDMA 3/4 see the CFA specification 3.0.
*/
static const struct ata_timing ata_timing[] = {
@@ -1872,6 +1966,8 @@ static const struct ata_timing ata_timing[] = {
{ XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 },
{ XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 },
+ { XFER_MW_DMA_4, 25, 0, 0, 0, 55, 20, 80, 0 },
+ { XFER_MW_DMA_3, 25, 0, 0, 0, 65, 25, 100, 0 },
{ XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 },
{ XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 },
{ XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 },
@@ -1886,7 +1982,8 @@ static const struct ata_timing ata_timing[] = {
{ XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 },
{ XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 },
-/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */
+ { XFER_PIO_6, 10, 55, 20, 80, 55, 20, 80, 0 },
+ { XFER_PIO_5, 15, 65, 25, 100, 65, 25, 100, 0 },
{ XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 },
{ XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 },
@@ -2104,7 +2201,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* return error code and failing device on failure.
*/
for (i = 0; i < ATA_MAX_DEVICES; i++) {
- if (ata_dev_enabled(&ap->device[i])) {
+ if (ata_dev_ready(&ap->device[i])) {
ap->ops->set_mode(ap);
break;
}
@@ -2170,7 +2267,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
for (i = 0; i < ATA_MAX_DEVICES; i++) {
dev = &ap->device[i];
- if (!ata_dev_enabled(dev))
+ /* don't udpate suspended devices' xfer mode */
+ if (!ata_dev_ready(dev))
continue;
rc = ata_dev_set_mode(dev);
@@ -2181,8 +2279,8 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
/* Record simplex status. If we selected DMA then the other
* host channels are not permitted to do so.
*/
- if (used_dma && (ap->host_set->flags & ATA_HOST_SIMPLEX))
- ap->host_set->simplex_claimed = 1;
+ if (used_dma && (ap->host->flags & ATA_HOST_SIMPLEX))
+ ap->host->simplex_claimed = 1;
/* step5: chip specific finalisation */
if (ap->ops->post_set_mode)
@@ -2204,7 +2302,7 @@ int ata_set_mode(struct ata_port *ap, struct ata_device **r_failed_dev)
* other threads.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static inline void ata_tf_to_host(struct ata_port *ap,
@@ -2368,7 +2466,7 @@ static unsigned int ata_bus_softreset(struct ata_port *ap,
*
* LOCKING:
* PCI/etc. bus probe sem.
- * Obtains host_set lock.
+ * Obtains host lock.
*
* SIDE EFFECTS:
* Sets ATA_FLAG_DISABLED if bus reset fails.
@@ -2546,7 +2644,7 @@ static void ata_wait_spinup(struct ata_port *ap)
/* first, debounce phy if SATA */
if (ap->cbl == ATA_CBL_SATA) {
- rc = sata_phy_debounce(ap, sata_deb_timing_eh);
+ rc = sata_phy_debounce(ap, sata_deb_timing_hotplug);
/* if debounced successfully and offline, no need to wait */
if ((rc == 0 || rc == -EOPNOTSUPP) && ata_port_offline(ap))
@@ -2582,16 +2680,17 @@ static void ata_wait_spinup(struct ata_port *ap)
int ata_std_prereset(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
- const unsigned long *timing;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
int rc;
- /* hotplug? */
- if (ehc->i.flags & ATA_EHI_HOTPLUGGED) {
- if (ap->flags & ATA_FLAG_HRST_TO_RESUME)
- ehc->i.action |= ATA_EH_HARDRESET;
- if (ap->flags & ATA_FLAG_SKIP_D2H_BSY)
- ata_wait_spinup(ap);
- }
+ /* handle link resume & hotplug spinup */
+ if ((ehc->i.flags & ATA_EHI_RESUME_LINK) &&
+ (ap->flags & ATA_FLAG_HRST_TO_RESUME))
+ ehc->i.action |= ATA_EH_HARDRESET;
+
+ if ((ehc->i.flags & ATA_EHI_HOTPLUGGED) &&
+ (ap->flags & ATA_FLAG_SKIP_D2H_BSY))
+ ata_wait_spinup(ap);
/* if we're about to do hardreset, nothing more to do */
if (ehc->i.action & ATA_EH_HARDRESET)
@@ -2599,11 +2698,6 @@ int ata_std_prereset(struct ata_port *ap)
/* if SATA, resume phy */
if (ap->cbl == ATA_CBL_SATA) {
- if (ap->flags & ATA_FLAG_LOADING)
- timing = sata_deb_timing_boot;
- else
- timing = sata_deb_timing_eh;
-
rc = sata_phy_resume(ap, timing);
if (rc && rc != -EOPNOTSUPP) {
/* phy resume failed */
@@ -2691,6 +2785,8 @@ int ata_std_softreset(struct ata_port *ap, unsigned int *classes)
*/
int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ const unsigned long *timing = sata_ehc_deb_timing(ehc);
u32 scontrol;
int rc;
@@ -2705,7 +2801,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
if ((rc = sata_scr_read(ap, SCR_CONTROL, &scontrol)))
return rc;
- scontrol = (scontrol & 0x0f0) | 0x302;
+ scontrol = (scontrol & 0x0f0) | 0x304;
if ((rc = sata_scr_write(ap, SCR_CONTROL, scontrol)))
return rc;
@@ -2728,7 +2824,7 @@ int sata_std_hardreset(struct ata_port *ap, unsigned int *class)
msleep(1);
/* bring phy back */
- sata_phy_resume(ap, sata_deb_timing_eh);
+ sata_phy_resume(ap, timing);
/* TODO: phy layer with polling, timeouts, etc. */
if (ata_port_offline(ap)) {
@@ -2999,20 +3095,16 @@ static int ata_dma_blacklisted(const struct ata_device *dev)
* known limits including host controller limits, device
* blacklist, etc...
*
- * FIXME: The current implementation limits all transfer modes to
- * the fastest of the lowested device on the port. This is not
- * required on most controllers.
- *
* LOCKING:
* None.
*/
static void ata_dev_xfermask(struct ata_device *dev)
{
struct ata_port *ap = dev->ap;
- struct ata_host_set *hs = ap->host_set;
+ struct ata_host *host = ap->host;
unsigned long xfer_mask;
- int i;
+ /* controller modes available */
xfer_mask = ata_pack_xfermask(ap->pio_mask,
ap->mwdma_mask, ap->udma_mask);
@@ -3022,34 +3114,31 @@ static void ata_dev_xfermask(struct ata_device *dev)
if (ap->cbl == ATA_CBL_PATA40)
xfer_mask &= ~(0xF8 << ATA_SHIFT_UDMA);
- /* FIXME: Use port-wide xfermask for now */
- for (i = 0; i < ATA_MAX_DEVICES; i++) {
- struct ata_device *d = &ap->device[i];
-
- if (ata_dev_absent(d))
- continue;
-
- if (ata_dev_disabled(d)) {
- /* to avoid violating device selection timing */
- xfer_mask &= ata_pack_xfermask(d->pio_mask,
- UINT_MAX, UINT_MAX);
- continue;
- }
+ xfer_mask &= ata_pack_xfermask(dev->pio_mask,
+ dev->mwdma_mask, dev->udma_mask);
+ xfer_mask &= ata_id_xfermask(dev->id);
- xfer_mask &= ata_pack_xfermask(d->pio_mask,
- d->mwdma_mask, d->udma_mask);
- xfer_mask &= ata_id_xfermask(d->id);
- if (ata_dma_blacklisted(d))
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ /*
+ * CFA Advanced TrueIDE timings are not allowed on a shared
+ * cable
+ */
+ if (ata_dev_pair(dev)) {
+ /* No PIO5 or PIO6 */
+ xfer_mask &= ~(0x03 << (ATA_SHIFT_PIO + 5));
+ /* No MWDMA3 or MWDMA 4 */
+ xfer_mask &= ~(0x03 << (ATA_SHIFT_MWDMA + 3));
}
- if (ata_dma_blacklisted(dev))
+ if (ata_dma_blacklisted(dev)) {
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
ata_dev_printk(dev, KERN_WARNING,
"device is on DMA blacklist, disabling DMA\n");
+ }
- if (hs->flags & ATA_HOST_SIMPLEX) {
- if (hs->simplex_claimed)
- xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ if ((host->flags & ATA_HOST_SIMPLEX) && host->simplex_claimed) {
+ xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ ata_dev_printk(dev, KERN_WARNING, "simplex DMA is claimed by "
+ "other device, disabling DMA\n");
}
if (ap->ops->mode_filter)
@@ -3139,7 +3228,7 @@ static unsigned int ata_dev_init_params(struct ata_device *dev,
* Unmap all mapped DMA memory associated with this command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_sg_clean(struct ata_queued_cmd *qc)
@@ -3199,7 +3288,7 @@ static void ata_sg_clean(struct ata_queued_cmd *qc)
* associated with the current disk command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
*/
static void ata_fill_sg(struct ata_queued_cmd *qc)
@@ -3251,7 +3340,7 @@ static void ata_fill_sg(struct ata_queued_cmd *qc)
* supplied PACKET command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS: 0 when ATAPI DMA can be used
* nonzero otherwise
@@ -3273,7 +3362,7 @@ int ata_check_atapi_dma(struct ata_queued_cmd *qc)
* Prepare ATA taskfile for submission.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_qc_prep(struct ata_queued_cmd *qc)
{
@@ -3295,7 +3384,7 @@ void ata_noop_qc_prep(struct ata_queued_cmd *qc) { }
* to point to a single memory buffer, @buf of byte length @buflen.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
@@ -3326,7 +3415,7 @@ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
* elements.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
@@ -3345,7 +3434,7 @@ void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
* DMA-map the memory buffer associated with queued_cmd @qc.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, negative on error.
@@ -3414,7 +3503,7 @@ skip_map:
* DMA-map the scatter-gather table associated with queued_cmd @qc.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, negative on error.
@@ -3527,7 +3616,7 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
* Inherited from caller.
*/
-void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
+void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
@@ -3573,7 +3662,7 @@ void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
* Inherited from caller.
*/
-void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
+void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->ap;
@@ -3607,7 +3696,7 @@ void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
* @buflen: buffer length
* @write_data: read/write
*
- * Transfer data from/to the device data register by PIO. Do the
+ * Transfer data from/to the device data register by PIO. Do the
* transfer with interrupts disabled.
*
* LOCKING:
@@ -3923,7 +4012,7 @@ static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *q
* Finish @qc which is running on standard HSM.
*
* LOCKING:
- * If @in_wq is zero, spin_lock_irqsave(host_set lock).
+ * If @in_wq is zero, spin_lock_irqsave(host lock).
* Otherwise, none on entry and grabs host lock.
*/
static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
@@ -3935,8 +4024,8 @@ static void ata_hsm_qc_complete(struct ata_queued_cmd *qc, int in_wq)
if (in_wq) {
spin_lock_irqsave(ap->lock, flags);
- /* EH might have kicked in while host_set lock
- * is released.
+ /* EH might have kicked in while host lock is
+ * released.
*/
qc = ata_qc_from_tag(ap, qc->tag);
if (qc) {
@@ -4252,7 +4341,7 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
unsigned int i;
/* no command while frozen */
- if (unlikely(ap->flags & ATA_FLAG_FROZEN))
+ if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
/* the last tag is reserved for internal command. */
@@ -4301,7 +4390,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
* in case something prevents using it.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_qc_free(struct ata_queued_cmd *qc)
{
@@ -4354,7 +4443,7 @@ void __ata_qc_complete(struct ata_queued_cmd *qc)
* command has completed, with either an ok or not-ok status.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_qc_complete(struct ata_queued_cmd *qc)
{
@@ -4374,7 +4463,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* taken care of.
*/
if (ap->ops->error_handler) {
- WARN_ON(ap->flags & ATA_FLAG_FROZEN);
+ WARN_ON(ap->pflags & ATA_PFLAG_FROZEN);
if (unlikely(qc->err_mask))
qc->flags |= ATA_QCFLAG_FAILED;
@@ -4417,7 +4506,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc)
* and commands are completed accordingly.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Number of completed commands on success, -errno otherwise.
@@ -4488,7 +4577,7 @@ static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
* writing the taskfile to hardware, starting the command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_qc_issue(struct ata_queued_cmd *qc)
{
@@ -4549,7 +4638,7 @@ err:
* May be used as the qc_issue() entry in ata_port_operations.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, AC_ERR_* mask on failure
@@ -4678,7 +4767,7 @@ unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc)
* handled via polling with interrupts disabled (nIEN bit).
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* One if interrupt was handled, zero if not (shared irq).
@@ -4765,14 +4854,14 @@ idle_irq:
/**
* ata_interrupt - Default ATA host interrupt handler
* @irq: irq line (unused)
- * @dev_instance: pointer to our ata_host_set information structure
+ * @dev_instance: pointer to our ata_host information structure
* @regs: unused
*
* Default interrupt handler for PCI IDE devices. Calls
* ata_host_intr() for each port that is not disabled.
*
* LOCKING:
- * Obtains host_set lock during operation.
+ * Obtains host lock during operation.
*
* RETURNS:
* IRQ_NONE or IRQ_HANDLED.
@@ -4780,18 +4869,18 @@ idle_irq:
irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
unsigned int i;
unsigned int handled = 0;
unsigned long flags;
/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
- spin_lock_irqsave(&host_set->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
- for (i = 0; i < host_set->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
- ap = host_set->ports[i];
+ ap = host->ports[i];
if (ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
@@ -4803,7 +4892,7 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
}
}
- spin_unlock_irqrestore(&host_set->lock, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
return IRQ_RETVAL(handled);
}
@@ -4946,31 +5035,9 @@ int ata_port_offline(struct ata_port *ap)
return 0;
}
-/*
- * Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
- * without filling any other registers
- */
-static int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
-{
- struct ata_taskfile tf;
- int err;
-
- ata_tf_init(dev, &tf);
-
- tf.command = cmd;
- tf.flags |= ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
-
- err = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0);
- if (err)
- ata_dev_printk(dev, KERN_ERR, "%s: ata command failed: %d\n",
- __FUNCTION__, err);
-
- return err;
-}
-
-static int ata_flush_cache(struct ata_device *dev)
+int ata_flush_cache(struct ata_device *dev)
{
+ unsigned int err_mask;
u8 cmd;
if (!ata_try_flush_cache(dev))
@@ -4981,71 +5048,129 @@ static int ata_flush_cache(struct ata_device *dev)
else
cmd = ATA_CMD_FLUSH;
- return ata_do_simple_cmd(dev, cmd);
-}
+ err_mask = ata_do_simple_cmd(dev, cmd);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to flush cache\n");
+ return -EIO;
+ }
-static int ata_standby_drive(struct ata_device *dev)
-{
- return ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ return 0;
}
-static int ata_start_drive(struct ata_device *dev)
+static int ata_host_request_pm(struct ata_host *host, pm_message_t mesg,
+ unsigned int action, unsigned int ehi_flags,
+ int wait)
{
- return ata_do_simple_cmd(dev, ATA_CMD_IDLEIMMEDIATE);
+ unsigned long flags;
+ int i, rc;
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ /* Previous resume operation might still be in
+ * progress. Wait for PM_PENDING to clear.
+ */
+ if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ }
+
+ /* request PM ops to EH */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pm_mesg = mesg;
+ if (wait) {
+ rc = 0;
+ ap->pm_result = &rc;
+ }
+
+ ap->pflags |= ATA_PFLAG_PM_PENDING;
+ ap->eh_info.action |= action;
+ ap->eh_info.flags |= ehi_flags;
+
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait and check result */
+ if (wait) {
+ ata_port_wait_eh(ap);
+ WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
+ if (rc)
+ return rc;
+ }
+ }
+
+ return 0;
}
/**
- * ata_device_resume - wakeup a previously suspended devices
- * @dev: the device to resume
+ * ata_host_suspend - suspend host
+ * @host: host to suspend
+ * @mesg: PM message
+ *
+ * Suspend @host. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and waits for EH
+ * to finish.
*
- * Kick the drive back into action, by sending it an idle immediate
- * command and making sure its transfer mode matches between drive
- * and host.
+ * LOCKING:
+ * Kernel thread context (may sleep).
*
+ * RETURNS:
+ * 0 on success, -errno on failure.
*/
-int ata_device_resume(struct ata_device *dev)
+int ata_host_suspend(struct ata_host *host, pm_message_t mesg)
{
- struct ata_port *ap = dev->ap;
-
- if (ap->flags & ATA_FLAG_SUSPENDED) {
- struct ata_device *failed_dev;
+ int i, j, rc;
- ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
- ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 200000);
+ rc = ata_host_request_pm(host, mesg, 0, ATA_EHI_QUIET, 1);
+ if (rc)
+ goto fail;
- ap->flags &= ~ATA_FLAG_SUSPENDED;
- while (ata_set_mode(ap, &failed_dev))
- ata_dev_disable(failed_dev);
+ /* EH is quiescent now. Fail if we have any ready device.
+ * This happens if hotplug occurs between completion of device
+ * suspension and here.
+ */
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+
+ for (j = 0; j < ATA_MAX_DEVICES; j++) {
+ struct ata_device *dev = &ap->device[j];
+
+ if (ata_dev_ready(dev)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "suspend failed, device %d "
+ "still active\n", dev->devno);
+ rc = -EBUSY;
+ goto fail;
+ }
+ }
}
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_start_drive(dev);
+ host->dev->power.power_state = mesg;
return 0;
+
+ fail:
+ ata_host_resume(host);
+ return rc;
}
/**
- * ata_device_suspend - prepare a device for suspend
- * @dev: the device to suspend
- * @state: target power management state
+ * ata_host_resume - resume host
+ * @host: host to resume
+ *
+ * Resume @host. Actual operation is performed by EH. This
+ * function requests EH to perform PM operations and returns.
+ * Note that all resume operations are performed parallely.
*
- * Flush the cache on the drive, if appropriate, then issue a
- * standbynow command.
+ * LOCKING:
+ * Kernel thread context (may sleep).
*/
-int ata_device_suspend(struct ata_device *dev, pm_message_t state)
+void ata_host_resume(struct ata_host *host)
{
- struct ata_port *ap = dev->ap;
-
- if (!ata_dev_enabled(dev))
- return 0;
- if (dev->class == ATA_DEV_ATA)
- ata_flush_cache(dev);
-
- if (state.event != PM_EVENT_FREEZE)
- ata_standby_drive(dev);
- ap->flags |= ATA_FLAG_SUSPENDED;
- return 0;
+ ata_host_request_pm(host, PMSG_ON, ATA_EH_SOFTRESET,
+ ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 0);
+ host->dev->power.power_state = PMSG_ON;
}
/**
@@ -5102,32 +5227,10 @@ void ata_port_stop (struct ata_port *ap)
ata_pad_free(ap, dev);
}
-void ata_host_stop (struct ata_host_set *host_set)
+void ata_host_stop (struct ata_host *host)
{
- if (host_set->mmio_base)
- iounmap(host_set->mmio_base);
-}
-
-
-/**
- * ata_host_remove - Unregister SCSI host structure with upper layers
- * @ap: Port to unregister
- * @do_unregister: 1 if we fully unregister, 0 to just stop the port
- *
- * LOCKING:
- * Inherited from caller.
- */
-
-static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
-{
- struct Scsi_Host *sh = ap->host;
-
- DPRINTK("ENTER\n");
-
- if (do_unregister)
- scsi_remove_host(sh);
-
- ap->ops->port_stop(ap);
+ if (host->mmio_base)
+ iounmap(host->mmio_base);
}
/**
@@ -5149,7 +5252,7 @@ void ata_dev_init(struct ata_device *dev)
/* High bits of dev->flags are used to record warm plug
* requests which occur asynchronously. Synchronize using
- * host_set lock.
+ * host lock.
*/
spin_lock_irqsave(ap->lock, flags);
dev->flags &= ~ATA_DFLAG_INIT_MASK;
@@ -5163,46 +5266,42 @@ void ata_dev_init(struct ata_device *dev)
}
/**
- * ata_host_init - Initialize an ata_port structure
+ * ata_port_init - Initialize an ata_port structure
* @ap: Structure to initialize
- * @host: associated SCSI mid-layer structure
- * @host_set: Collection of hosts to which @ap belongs
+ * @host: Collection of hosts to which @ap belongs
* @ent: Probe information provided by low-level driver
* @port_no: Port number associated with this ata_port
*
- * Initialize a new ata_port structure, and its associated
- * scsi_host.
+ * Initialize a new ata_port structure.
*
* LOCKING:
* Inherited from caller.
*/
-static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
- struct ata_host_set *host_set,
- const struct ata_probe_ent *ent, unsigned int port_no)
+void ata_port_init(struct ata_port *ap, struct ata_host *host,
+ const struct ata_probe_ent *ent, unsigned int port_no)
{
unsigned int i;
- host->max_id = 16;
- host->max_lun = 1;
- host->max_channel = 1;
- host->unique_id = ata_unique_id++;
- host->max_cmd_len = 12;
-
- ap->lock = &host_set->lock;
+ ap->lock = &host->lock;
ap->flags = ATA_FLAG_DISABLED;
- ap->id = host->unique_id;
- ap->host = host;
+ ap->id = ata_unique_id++;
ap->ctl = ATA_DEVCTL_OBS;
- ap->host_set = host_set;
+ ap->host = host;
ap->dev = ent->dev;
ap->port_no = port_no;
- ap->hard_port_no =
- ent->legacy_mode ? ent->hard_port_no : port_no;
- ap->pio_mask = ent->pio_mask;
- ap->mwdma_mask = ent->mwdma_mask;
- ap->udma_mask = ent->udma_mask;
- ap->flags |= ent->host_flags;
- ap->ops = ent->port_ops;
+ if (port_no == 1 && ent->pinfo2) {
+ ap->pio_mask = ent->pinfo2->pio_mask;
+ ap->mwdma_mask = ent->pinfo2->mwdma_mask;
+ ap->udma_mask = ent->pinfo2->udma_mask;
+ ap->flags |= ent->pinfo2->flags;
+ ap->ops = ent->pinfo2->port_ops;
+ } else {
+ ap->pio_mask = ent->pio_mask;
+ ap->mwdma_mask = ent->mwdma_mask;
+ ap->udma_mask = ent->udma_mask;
+ ap->flags |= ent->port_flags;
+ ap->ops = ent->port_ops;
+ }
ap->hw_sata_spd_limit = UINT_MAX;
ap->active_tag = ATA_TAG_POISON;
ap->last_ctl = 0xFF;
@@ -5212,7 +5311,7 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
ap->msg_enable = 0x00FF;
#elif defined(ATA_DEBUG)
ap->msg_enable = ATA_MSG_DRV | ATA_MSG_INFO | ATA_MSG_CTL | ATA_MSG_WARN | ATA_MSG_ERR;
-#else
+#else
ap->msg_enable = ATA_MSG_DRV | ATA_MSG_ERR | ATA_MSG_WARN;
#endif
@@ -5243,9 +5342,30 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
}
/**
- * ata_host_add - Attach low-level ATA driver to system
+ * ata_port_init_shost - Initialize SCSI host associated with ATA port
+ * @ap: ATA port to initialize SCSI host for
+ * @shost: SCSI host associated with @ap
+ *
+ * Initialize SCSI host @shost associated with ATA port @ap.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+static void ata_port_init_shost(struct ata_port *ap, struct Scsi_Host *shost)
+{
+ ap->scsi_host = shost;
+
+ shost->unique_id = ap->id;
+ shost->max_id = 16;
+ shost->max_lun = 1;
+ shost->max_channel = 1;
+ shost->max_cmd_len = 12;
+}
+
+/**
+ * ata_port_add - Attach low-level ATA driver to system
* @ent: Information provided by low-level driver
- * @host_set: Collections of ports to which we add
+ * @host: Collections of ports to which we add
* @port_no: Port number associated with this host
*
* Attach low-level ATA driver to system.
@@ -5256,43 +5376,55 @@ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
* RETURNS:
* New ata_port on success, for NULL on error.
*/
-
-static struct ata_port * ata_host_add(const struct ata_probe_ent *ent,
- struct ata_host_set *host_set,
+static struct ata_port * ata_port_add(const struct ata_probe_ent *ent,
+ struct ata_host *host,
unsigned int port_no)
{
- struct Scsi_Host *host;
+ struct Scsi_Host *shost;
struct ata_port *ap;
- int rc;
DPRINTK("ENTER\n");
if (!ent->port_ops->error_handler &&
- !(ent->host_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
+ !(ent->port_flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST))) {
printk(KERN_ERR "ata%u: no reset mechanism available\n",
port_no);
return NULL;
}
- host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
- if (!host)
+ shost = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+ if (!shost)
return NULL;
- host->transportt = &ata_scsi_transport_template;
+ shost->transportt = &ata_scsi_transport_template;
- ap = ata_shost_to_port(host);
+ ap = ata_shost_to_port(shost);
- ata_host_init(ap, host, host_set, ent, port_no);
-
- rc = ap->ops->port_start(ap);
- if (rc)
- goto err_out;
+ ata_port_init(ap, host, ent, port_no);
+ ata_port_init_shost(ap, shost);
return ap;
+}
-err_out:
- scsi_host_put(host);
- return NULL;
+/**
+ * ata_sas_host_init - Initialize a host struct
+ * @host: host to initialize
+ * @dev: device host is attached to
+ * @flags: host flags
+ * @ops: port_ops
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ */
+
+void ata_host_init(struct ata_host *host, struct device *dev,
+ unsigned long flags, const struct ata_port_operations *ops)
+{
+ spin_lock_init(&host->lock);
+ host->dev = dev;
+ host->flags = flags;
+ host->ops = ops;
}
/**
@@ -5315,78 +5447,111 @@ err_out:
*/
int ata_device_add(const struct ata_probe_ent *ent)
{
- unsigned int count = 0, i;
+ unsigned int i;
struct device *dev = ent->dev;
- struct ata_host_set *host_set;
+ struct ata_host *host;
int rc;
DPRINTK("ENTER\n");
+
+ if (ent->irq == 0) {
+ dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
+ return 0;
+ }
/* alloc a container for our list of ATA ports (buses) */
- host_set = kzalloc(sizeof(struct ata_host_set) +
- (ent->n_ports * sizeof(void *)), GFP_KERNEL);
- if (!host_set)
+ host = kzalloc(sizeof(struct ata_host) +
+ (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+ if (!host)
return 0;
- spin_lock_init(&host_set->lock);
- host_set->dev = dev;
- host_set->n_ports = ent->n_ports;
- host_set->irq = ent->irq;
- host_set->mmio_base = ent->mmio_base;
- host_set->private_data = ent->private_data;
- host_set->ops = ent->port_ops;
- host_set->flags = ent->host_set_flags;
+ ata_host_init(host, dev, ent->_host_flags, ent->port_ops);
+ host->n_ports = ent->n_ports;
+ host->irq = ent->irq;
+ host->irq2 = ent->irq2;
+ host->mmio_base = ent->mmio_base;
+ host->private_data = ent->private_data;
/* register each port bound to this device */
- for (i = 0; i < ent->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
unsigned long xfer_mode_mask;
+ int irq_line = ent->irq;
- ap = ata_host_add(ent, host_set, i);
+ ap = ata_port_add(ent, host, i);
if (!ap)
goto err_out;
- host_set->ports[i] = ap;
+ host->ports[i] = ap;
+
+ /* dummy? */
+ if (ent->dummy_port_mask & (1 << i)) {
+ ata_port_printk(ap, KERN_INFO, "DUMMY\n");
+ ap->ops = &ata_dummy_port_ops;
+ continue;
+ }
+
+ /* start port */
+ rc = ap->ops->port_start(ap);
+ if (rc) {
+ host->ports[i] = NULL;
+ scsi_host_put(ap->scsi_host);
+ goto err_out;
+ }
+
+ /* Report the secondary IRQ for second channel legacy */
+ if (i == 1 && ent->irq2)
+ irq_line = ent->irq2;
+
xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
(ap->mwdma_mask << ATA_SHIFT_MWDMA) |
(ap->pio_mask << ATA_SHIFT_PIO);
/* print per-port info to dmesg */
ata_port_printk(ap, KERN_INFO, "%cATA max %s cmd 0x%lX "
- "ctl 0x%lX bmdma 0x%lX irq %lu\n",
+ "ctl 0x%lX bmdma 0x%lX irq %d\n",
ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
ata_mode_string(xfer_mode_mask),
ap->ioaddr.cmd_addr,
ap->ioaddr.ctl_addr,
ap->ioaddr.bmdma_addr,
- ent->irq);
+ irq_line);
ata_chk_status(ap);
- host_set->ops->irq_clear(ap);
+ host->ops->irq_clear(ap);
ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
- count++;
}
- if (!count)
- goto err_free_ret;
-
- /* obtain irq, that is shared between channels */
+ /* obtain irq, that may be shared between channels */
rc = request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
- DRV_NAME, host_set);
+ DRV_NAME, host);
if (rc) {
dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
ent->irq, rc);
goto err_out;
}
+ /* do we have a second IRQ for the other channel, eg legacy mode */
+ if (ent->irq2) {
+ /* We will get weird core code crashes later if this is true
+ so trap it now */
+ BUG_ON(ent->irq == ent->irq2);
+
+ rc = request_irq(ent->irq2, ent->port_ops->irq_handler, ent->irq_flags,
+ DRV_NAME, host);
+ if (rc) {
+ dev_printk(KERN_ERR, dev, "irq %lu request failed: %d\n",
+ ent->irq2, rc);
+ goto err_out_free_irq;
+ }
+ }
+
/* perform each probe synchronously */
DPRINTK("probe begin\n");
- for (i = 0; i < count; i++) {
- struct ata_port *ap;
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
u32 scontrol;
int rc;
- ap = host_set->ports[i];
-
/* init sata_spd_limit to the current value */
if (sata_scr_read(ap, SCR_CONTROL, &scontrol) == 0) {
int spd = (scontrol >> 4) & 0xf;
@@ -5394,7 +5559,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
ap->sata_spd_limit = ap->hw_sata_spd_limit;
- rc = scsi_add_host(ap->host, dev);
+ rc = scsi_add_host(ap->scsi_host, dev);
if (rc) {
ata_port_printk(ap, KERN_ERR, "scsi_add_host failed\n");
/* FIXME: do something useful here */
@@ -5405,6 +5570,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
}
if (ap->ops->error_handler) {
+ struct ata_eh_info *ehi = &ap->eh_info;
unsigned long flags;
ata_port_probe(ap);
@@ -5412,10 +5578,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* kick EH for boot probing */
spin_lock_irqsave(ap->lock, flags);
- ap->eh_info.probe_mask = (1 << ATA_MAX_DEVICES) - 1;
- ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ehi->probe_mask = (1 << ATA_MAX_DEVICES) - 1;
+ ehi->action |= ATA_EH_SOFTRESET;
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
- ap->flags |= ATA_FLAG_LOADING;
+ ap->pflags |= ATA_PFLAG_LOADING;
ata_port_schedule_eh(ap);
spin_unlock_irqrestore(ap->lock, flags);
@@ -5440,24 +5607,29 @@ int ata_device_add(const struct ata_probe_ent *ent)
/* probes are done, now scan each port's disk(s) */
DPRINTK("host probe begin\n");
- for (i = 0; i < count; i++) {
- struct ata_port *ap = host_set->ports[i];
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
ata_scsi_scan_host(ap);
}
- dev_set_drvdata(dev, host_set);
+ dev_set_drvdata(dev, host);
VPRINTK("EXIT, returning %u\n", ent->n_ports);
return ent->n_ports; /* success */
+err_out_free_irq:
+ free_irq(ent->irq, host);
err_out:
- for (i = 0; i < count; i++) {
- ata_host_remove(host_set->ports[i], 1);
- scsi_host_put(host_set->ports[i]->host);
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ if (ap) {
+ ap->ops->port_stop(ap);
+ scsi_host_put(ap->scsi_host);
+ }
}
-err_free_ret:
- kfree(host_set);
+
+ kfree(host);
VPRINTK("EXIT, returning 0\n");
return 0;
}
@@ -5479,11 +5651,11 @@ void ata_port_detach(struct ata_port *ap)
int i;
if (!ap->ops->error_handler)
- return;
+ goto skip_eh;
/* tell EH we're leaving & flush EH */
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_UNLOADING;
+ ap->pflags |= ATA_PFLAG_UNLOADING;
spin_unlock_irqrestore(ap->lock, flags);
ata_port_wait_eh(ap);
@@ -5515,13 +5687,14 @@ void ata_port_detach(struct ata_port *ap)
cancel_delayed_work(&ap->hotplug_task);
flush_workqueue(ata_aux_wq);
+ skip_eh:
/* remove the associated SCSI host */
- scsi_remove_host(ap->host);
+ scsi_remove_host(ap->scsi_host);
}
/**
- * ata_host_set_remove - PCI layer callback for device removal
- * @host_set: ATA host set that was removed
+ * ata_host_remove - PCI layer callback for device removal
+ * @host: ATA host set that was removed
*
* Unregister all objects associated with this host set. Free those
* objects.
@@ -5530,36 +5703,39 @@ void ata_port_detach(struct ata_port *ap)
* Inherited from calling layer (may sleep).
*/
-void ata_host_set_remove(struct ata_host_set *host_set)
+void ata_host_remove(struct ata_host *host)
{
unsigned int i;
- for (i = 0; i < host_set->n_ports; i++)
- ata_port_detach(host_set->ports[i]);
+ for (i = 0; i < host->n_ports; i++)
+ ata_port_detach(host->ports[i]);
- free_irq(host_set->irq, host_set);
+ free_irq(host->irq, host);
+ if (host->irq2)
+ free_irq(host->irq2, host);
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
- ata_scsi_release(ap->host);
+ ata_scsi_release(ap->scsi_host);
if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
struct ata_ioports *ioaddr = &ap->ioaddr;
- if (ioaddr->cmd_addr == 0x1f0)
- release_region(0x1f0, 8);
- else if (ioaddr->cmd_addr == 0x170)
- release_region(0x170, 8);
+ /* FIXME: Add -ac IDE pci mods to remove these special cases */
+ if (ioaddr->cmd_addr == ATA_PRIMARY_CMD)
+ release_region(ATA_PRIMARY_CMD, 8);
+ else if (ioaddr->cmd_addr == ATA_SECONDARY_CMD)
+ release_region(ATA_SECONDARY_CMD, 8);
}
- scsi_host_put(ap->host);
+ scsi_host_put(ap->scsi_host);
}
- if (host_set->ops->host_stop)
- host_set->ops->host_stop(host_set);
+ if (host->ops->host_stop)
+ host->ops->host_stop(host);
- kfree(host_set);
+ kfree(host);
}
/**
@@ -5576,19 +5752,44 @@ void ata_host_set_remove(struct ata_host_set *host_set)
* One.
*/
-int ata_scsi_release(struct Scsi_Host *host)
+int ata_scsi_release(struct Scsi_Host *shost)
{
- struct ata_port *ap = ata_shost_to_port(host);
+ struct ata_port *ap = ata_shost_to_port(shost);
DPRINTK("ENTER\n");
ap->ops->port_disable(ap);
- ata_host_remove(ap, 0);
+ ap->ops->port_stop(ap);
DPRINTK("EXIT\n");
return 1;
}
+struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
+{
+ struct ata_probe_ent *probe_ent;
+
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (!probe_ent) {
+ printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+ kobject_name(&(dev->kobj)));
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&probe_ent->node);
+ probe_ent->dev = dev;
+
+ probe_ent->sht = port->sht;
+ probe_ent->port_flags = port->flags;
+ probe_ent->pio_mask = port->pio_mask;
+ probe_ent->mwdma_mask = port->mwdma_mask;
+ probe_ent->udma_mask = port->udma_mask;
+ probe_ent->port_ops = port->port_ops;
+
+ return probe_ent;
+}
+
/**
* ata_std_ports - initialize ioaddr with standard port offsets.
* @ioaddr: IO address structure to be initialized
@@ -5618,11 +5819,11 @@ void ata_std_ports(struct ata_ioports *ioaddr)
#ifdef CONFIG_PCI
-void ata_pci_host_stop (struct ata_host_set *host_set)
+void ata_pci_host_stop (struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
- pci_iounmap(pdev, host_set->mmio_base);
+ pci_iounmap(pdev, host->mmio_base);
}
/**
@@ -5642,12 +5843,9 @@ void ata_pci_host_stop (struct ata_host_set *host_set)
void ata_pci_remove_one (struct pci_dev *pdev)
{
struct device *dev = pci_dev_to_dev(pdev);
- struct ata_host_set *host_set = dev_get_drvdata(dev);
- struct ata_host_set *host_set2 = host_set->next;
+ struct ata_host *host = dev_get_drvdata(dev);
- ata_host_set_remove(host_set);
- if (host_set2)
- ata_host_set_remove(host_set2);
+ ata_host_remove(host);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -5688,20 +5886,44 @@ int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits)
return (tmp == bits->val) ? 1 : 0;
}
-int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t state)
+void ata_pci_device_do_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, PCI_D3hot);
- return 0;
+
+ if (mesg.event == PM_EVENT_SUSPEND) {
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+ }
}
-int ata_pci_device_resume(struct pci_dev *pdev)
+void ata_pci_device_do_resume(struct pci_dev *pdev)
{
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_device(pdev);
pci_set_master(pdev);
+}
+
+int ata_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc = 0;
+
+ rc = ata_host_suspend(host, mesg);
+ if (rc)
+ return rc;
+
+ ata_pci_device_do_suspend(pdev, mesg);
+
+ return 0;
+}
+
+int ata_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ ata_host_resume(host);
return 0;
}
#endif /* CONFIG_PCI */
@@ -5709,6 +5931,7 @@ int ata_pci_device_resume(struct pci_dev *pdev)
static int __init ata_init(void)
{
+ ata_probe_timeout *= HZ;
ata_wq = create_workqueue("ata");
if (!ata_wq)
return -ENOMEM;
@@ -5733,7 +5956,7 @@ module_init(ata_init);
module_exit(ata_exit);
static unsigned long ratelimit_time;
-static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ata_ratelimit_lock);
int ata_ratelimit(void)
{
@@ -5800,20 +6023,55 @@ u32 ata_wait_register(void __iomem *reg, u32 mask, u32 val,
}
/*
+ * Dummy port_ops
+ */
+static void ata_dummy_noret(struct ata_port *ap) { }
+static int ata_dummy_ret0(struct ata_port *ap) { return 0; }
+static void ata_dummy_qc_noret(struct ata_queued_cmd *qc) { }
+
+static u8 ata_dummy_check_status(struct ata_port *ap)
+{
+ return ATA_DRDY;
+}
+
+static unsigned int ata_dummy_qc_issue(struct ata_queued_cmd *qc)
+{
+ return AC_ERR_SYSTEM;
+}
+
+const struct ata_port_operations ata_dummy_port_ops = {
+ .port_disable = ata_port_disable,
+ .check_status = ata_dummy_check_status,
+ .check_altstatus = ata_dummy_check_status,
+ .dev_select = ata_noop_dev_select,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ata_dummy_qc_issue,
+ .freeze = ata_dummy_noret,
+ .thaw = ata_dummy_noret,
+ .error_handler = ata_dummy_noret,
+ .post_internal_cmd = ata_dummy_qc_noret,
+ .irq_clear = ata_dummy_noret,
+ .port_start = ata_dummy_ret0,
+ .port_stop = ata_dummy_noret,
+};
+
+/*
* libata is essentially a library of internal helper functions for
* low-level ATA host controller drivers. As such, the API/ABI is
* likely to change as new drivers are added and updated.
* Do not depend on ABI/API stability.
*/
-EXPORT_SYMBOL_GPL(sata_deb_timing_boot);
-EXPORT_SYMBOL_GPL(sata_deb_timing_eh);
-EXPORT_SYMBOL_GPL(sata_deb_timing_before_fsrst);
+EXPORT_SYMBOL_GPL(sata_deb_timing_normal);
+EXPORT_SYMBOL_GPL(sata_deb_timing_hotplug);
+EXPORT_SYMBOL_GPL(sata_deb_timing_long);
+EXPORT_SYMBOL_GPL(ata_dummy_port_ops);
EXPORT_SYMBOL_GPL(ata_std_bios_param);
EXPORT_SYMBOL_GPL(ata_std_ports);
+EXPORT_SYMBOL_GPL(ata_host_init);
EXPORT_SYMBOL_GPL(ata_device_add);
EXPORT_SYMBOL_GPL(ata_port_detach);
-EXPORT_SYMBOL_GPL(ata_host_set_remove);
+EXPORT_SYMBOL_GPL(ata_host_remove);
EXPORT_SYMBOL_GPL(ata_sg_init);
EXPORT_SYMBOL_GPL(ata_sg_init_one);
EXPORT_SYMBOL_GPL(ata_hsm_move);
@@ -5880,6 +6138,8 @@ EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
EXPORT_SYMBOL_GPL(ata_port_online);
EXPORT_SYMBOL_GPL(ata_port_offline);
+EXPORT_SYMBOL_GPL(ata_host_suspend);
+EXPORT_SYMBOL_GPL(ata_host_resume);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);
@@ -5894,14 +6154,14 @@ EXPORT_SYMBOL_GPL(ata_pci_host_stop);
EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
EXPORT_SYMBOL_GPL(ata_pci_init_one);
EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_suspend);
+EXPORT_SYMBOL_GPL(ata_pci_device_do_resume);
EXPORT_SYMBOL_GPL(ata_pci_device_suspend);
EXPORT_SYMBOL_GPL(ata_pci_device_resume);
EXPORT_SYMBOL_GPL(ata_pci_default_filter);
EXPORT_SYMBOL_GPL(ata_pci_clear_simplex);
#endif /* CONFIG_PCI */
-EXPORT_SYMBOL_GPL(ata_device_suspend);
-EXPORT_SYMBOL_GPL(ata_device_resume);
EXPORT_SYMBOL_GPL(ata_scsi_device_suspend);
EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
diff --git a/drivers/scsi/libata-eh.c b/drivers/ata/libata-eh.c
index 823385981a7..02b2b2787d9 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -32,14 +32,13 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
-#include "scsi_transport_api.h"
+#include "../scsi/scsi_transport_api.h"
#include <linux/libata.h>
@@ -47,6 +46,8 @@
static void __ata_port_freeze(struct ata_port *ap);
static void ata_eh_finish(struct ata_port *ap);
+static void ata_eh_handle_port_suspend(struct ata_port *ap);
+static void ata_eh_handle_port_resume(struct ata_port *ap);
static void ata_ering_record(struct ata_ering *ering, int is_io,
unsigned int err_mask)
@@ -93,6 +94,38 @@ static int ata_ering_map(struct ata_ering *ering,
return rc;
}
+static unsigned int ata_eh_dev_action(struct ata_device *dev)
+{
+ struct ata_eh_context *ehc = &dev->ap->eh_context;
+
+ return ehc->i.action | ehc->i.dev_action[dev->devno];
+}
+
+static void ata_eh_clear_action(struct ata_device *dev,
+ struct ata_eh_info *ehi, unsigned int action)
+{
+ int i;
+
+ if (!dev) {
+ ehi->action &= ~action;
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehi->dev_action[i] &= ~action;
+ } else {
+ /* doesn't make sense for port-wide EH actions */
+ WARN_ON(!(action & ATA_EH_PERDEV_MASK));
+
+ /* break ehi->action into ehi->dev_action */
+ if (ehi->action & action) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++)
+ ehi->dev_action[i] |= ehi->action & action;
+ ehi->action &= ~action;
+ }
+
+ /* turn off the specified per-dev action */
+ ehi->dev_action[dev->devno] &= ~action;
+ }
+}
+
/**
* ata_scsi_timed_out - SCSI layer time out callback
* @cmd: timed out SCSI command
@@ -158,7 +191,6 @@ enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd)
void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
- spinlock_t *ap_lock = ap->lock;
int i, repeat_cnt = ATA_EH_MAX_REPEAT;
unsigned long flags;
@@ -167,7 +199,7 @@ void ata_scsi_error(struct Scsi_Host *host)
/* synchronize with port task */
ata_port_flush_task(ap);
- /* synchronize with host_set lock and sort out timeouts */
+ /* synchronize with host lock and sort out timeouts */
/* For new EH, all qcs are finished in one of three ways -
* normal completion, error completion, and SCSI timeout.
@@ -185,7 +217,7 @@ void ata_scsi_error(struct Scsi_Host *host)
struct scsi_cmnd *scmd, *tmp;
int nr_timedout = 0;
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
list_for_each_entry_safe(scmd, tmp, &host->eh_cmd_q, eh_entry) {
struct ata_queued_cmd *qc;
@@ -224,43 +256,49 @@ void ata_scsi_error(struct Scsi_Host *host)
if (nr_timedout)
__ata_port_freeze(ap);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else
- spin_unlock_wait(ap_lock);
+ spin_unlock_wait(ap->lock);
repeat:
/* invoke error handler */
if (ap->ops->error_handler) {
+ /* process port resume request */
+ ata_eh_handle_port_resume(ap);
+
/* fetch & clear EH info */
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
memset(&ap->eh_context, 0, sizeof(ap->eh_context));
ap->eh_context.i = ap->eh_info;
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
- ap->flags |= ATA_FLAG_EH_IN_PROGRESS;
- ap->flags &= ~ATA_FLAG_EH_PENDING;
+ ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_PENDING;
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
- /* invoke EH. if unloading, just finish failed qcs */
- if (!(ap->flags & ATA_FLAG_UNLOADING))
+ /* invoke EH, skip if unloading or suspended */
+ if (!(ap->pflags & (ATA_PFLAG_UNLOADING | ATA_PFLAG_SUSPENDED)))
ap->ops->error_handler(ap);
else
ata_eh_finish(ap);
+ /* process port suspend request */
+ ata_eh_handle_port_suspend(ap);
+
/* Exception might have happend after ->error_handler
* recovered the port but before this point. Repeat
* EH in such case.
*/
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
- if (ap->flags & ATA_FLAG_EH_PENDING) {
+ if (ap->pflags & ATA_PFLAG_EH_PENDING) {
if (--repeat_cnt) {
ata_port_printk(ap, KERN_INFO,
"EH pending after completion, "
"repeating EH (cnt=%d)\n", repeat_cnt);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
goto repeat;
}
ata_port_printk(ap, KERN_ERR, "EH pending after %d "
@@ -270,14 +308,14 @@ void ata_scsi_error(struct Scsi_Host *host)
/* this run is complete, make sure EH info is clear */
memset(&ap->eh_info, 0, sizeof(ap->eh_info));
- /* Clear host_eh_scheduled while holding ap_lock such
+ /* Clear host_eh_scheduled while holding ap->lock such
* that if exception occurs after this point but
* before EH completion, SCSI midlayer will
* re-initiate EH.
*/
host->host_eh_scheduled = 0;
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
} else {
WARN_ON(ata_qc_from_tag(ap, ap->active_tag) == NULL);
ap->ops->eng_timeout(ap);
@@ -289,24 +327,23 @@ void ata_scsi_error(struct Scsi_Host *host)
scsi_eh_flush_done_q(&ap->eh_done_q);
/* clean up */
- spin_lock_irqsave(ap_lock, flags);
+ spin_lock_irqsave(ap->lock, flags);
- if (ap->flags & ATA_FLAG_LOADING) {
- ap->flags &= ~ATA_FLAG_LOADING;
- } else {
- if (ap->flags & ATA_FLAG_SCSI_HOTPLUG)
- queue_work(ata_aux_wq, &ap->hotplug_task);
- if (ap->flags & ATA_FLAG_RECOVERED)
- ata_port_printk(ap, KERN_INFO, "EH complete\n");
- }
+ if (ap->pflags & ATA_PFLAG_LOADING)
+ ap->pflags &= ~ATA_PFLAG_LOADING;
+ else if (ap->pflags & ATA_PFLAG_SCSI_HOTPLUG)
+ queue_work(ata_aux_wq, &ap->hotplug_task);
- ap->flags &= ~(ATA_FLAG_SCSI_HOTPLUG | ATA_FLAG_RECOVERED);
+ if (ap->pflags & ATA_PFLAG_RECOVERED)
+ ata_port_printk(ap, KERN_INFO, "EH complete\n");
+
+ ap->pflags &= ~(ATA_PFLAG_SCSI_HOTPLUG | ATA_PFLAG_RECOVERED);
/* tell wait_eh that we're done */
- ap->flags &= ~ATA_FLAG_EH_IN_PROGRESS;
+ ap->pflags &= ~ATA_PFLAG_EH_IN_PROGRESS;
wake_up_all(&ap->eh_wait_q);
- spin_unlock_irqrestore(ap_lock, flags);
+ spin_unlock_irqrestore(ap->lock, flags);
DPRINTK("EXIT\n");
}
@@ -328,7 +365,7 @@ void ata_port_wait_eh(struct ata_port *ap)
retry:
spin_lock_irqsave(ap->lock, flags);
- while (ap->flags & (ATA_FLAG_EH_PENDING | ATA_FLAG_EH_IN_PROGRESS)) {
+ while (ap->pflags & (ATA_PFLAG_EH_PENDING | ATA_PFLAG_EH_IN_PROGRESS)) {
prepare_to_wait(&ap->eh_wait_q, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock_irqrestore(ap->lock, flags);
schedule();
@@ -339,7 +376,7 @@ void ata_port_wait_eh(struct ata_port *ap)
spin_unlock_irqrestore(ap->lock, flags);
/* make sure SCSI EH is complete */
- if (scsi_host_in_recovery(ap->host)) {
+ if (scsi_host_in_recovery(ap->scsi_host)) {
msleep(10);
goto retry;
}
@@ -448,7 +485,7 @@ void ata_eng_timeout(struct ata_port *ap)
* other commands are drained.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
{
@@ -457,7 +494,7 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
WARN_ON(!ap->ops->error_handler);
qc->flags |= ATA_QCFLAG_FAILED;
- qc->ap->flags |= ATA_FLAG_EH_PENDING;
+ qc->ap->pflags |= ATA_PFLAG_EH_PENDING;
/* The following will fail if timeout has already expired.
* ata_scsi_error() takes care of such scmds on EH entry.
@@ -475,14 +512,14 @@ void ata_qc_schedule_eh(struct ata_queued_cmd *qc)
* all commands are drained.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_port_schedule_eh(struct ata_port *ap)
{
WARN_ON(!ap->ops->error_handler);
- ap->flags |= ATA_FLAG_EH_PENDING;
- scsi_schedule_eh(ap->host);
+ ap->pflags |= ATA_PFLAG_EH_PENDING;
+ scsi_schedule_eh(ap->scsi_host);
DPRINTK("port EH scheduled\n");
}
@@ -494,7 +531,7 @@ void ata_port_schedule_eh(struct ata_port *ap)
* Abort all active qc's of @ap and schedule EH.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Number of aborted qc's.
@@ -537,7 +574,7 @@ int ata_port_abort(struct ata_port *ap)
* is frozen.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void __ata_port_freeze(struct ata_port *ap)
{
@@ -546,7 +583,7 @@ static void __ata_port_freeze(struct ata_port *ap)
if (ap->ops->freeze)
ap->ops->freeze(ap);
- ap->flags |= ATA_FLAG_FROZEN;
+ ap->pflags |= ATA_PFLAG_FROZEN;
DPRINTK("ata%u port frozen\n", ap->id);
}
@@ -558,7 +595,7 @@ static void __ata_port_freeze(struct ata_port *ap)
* Abort and freeze @ap.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Number of aborted commands.
@@ -614,7 +651,7 @@ void ata_eh_thaw_port(struct ata_port *ap)
spin_lock_irqsave(ap->lock, flags);
- ap->flags &= ~ATA_FLAG_FROZEN;
+ ap->pflags &= ~ATA_PFLAG_FROZEN;
if (ap->ops->thaw)
ap->ops->thaw(ap);
@@ -699,35 +736,14 @@ static void ata_eh_detach_dev(struct ata_device *dev)
if (ata_scsi_offline_dev(dev)) {
dev->flags |= ATA_DFLAG_DETACHED;
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
}
- spin_unlock_irqrestore(ap->lock, flags);
-}
-
-static void ata_eh_clear_action(struct ata_device *dev,
- struct ata_eh_info *ehi, unsigned int action)
-{
- int i;
-
- if (!dev) {
- ehi->action &= ~action;
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] &= ~action;
- } else {
- /* doesn't make sense for port-wide EH actions */
- WARN_ON(!(action & ATA_EH_PERDEV_MASK));
-
- /* break ehi->action into ehi->dev_action */
- if (ehi->action & action) {
- for (i = 0; i < ATA_MAX_DEVICES; i++)
- ehi->dev_action[i] |= ehi->action & action;
- ehi->action &= ~action;
- }
+ /* clear per-dev EH actions */
+ ata_eh_clear_action(dev, &ap->eh_info, ATA_EH_PERDEV_MASK);
+ ata_eh_clear_action(dev, &ap->eh_context.i, ATA_EH_PERDEV_MASK);
- /* turn off the specified per-dev action */
- ehi->dev_action[dev->devno] &= ~action;
- }
+ spin_unlock_irqrestore(ap->lock, flags);
}
/**
@@ -747,10 +763,29 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
unsigned int action)
{
unsigned long flags;
+ struct ata_eh_info *ehi = &ap->eh_info;
+ struct ata_eh_context *ehc = &ap->eh_context;
spin_lock_irqsave(ap->lock, flags);
- ata_eh_clear_action(dev, &ap->eh_info, action);
- ap->flags |= ATA_FLAG_RECOVERED;
+
+ /* Reset is represented by combination of actions and EHI
+ * flags. Suck in all related bits before clearing eh_info to
+ * avoid losing requested action.
+ */
+ if (action & ATA_EH_RESET_MASK) {
+ ehc->i.action |= ehi->action & ATA_EH_RESET_MASK;
+ ehc->i.flags |= ehi->flags & ATA_EHI_RESET_MODIFIER_MASK;
+
+ /* make sure all reset actions are cleared & clear EHI flags */
+ action |= ATA_EH_RESET_MASK;
+ ehi->flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ }
+
+ ata_eh_clear_action(dev, ehi, action);
+
+ if (!(ehc->i.flags & ATA_EHI_QUIET))
+ ap->pflags |= ATA_PFLAG_RECOVERED;
+
spin_unlock_irqrestore(ap->lock, flags);
}
@@ -769,6 +804,12 @@ static void ata_eh_about_to_do(struct ata_port *ap, struct ata_device *dev,
static void ata_eh_done(struct ata_port *ap, struct ata_device *dev,
unsigned int action)
{
+ /* if reset is complete, clear all reset actions & reset modifier */
+ if (action & ATA_EH_RESET_MASK) {
+ action |= ATA_EH_RESET_MASK;
+ ap->eh_context.i.flags &= ~ATA_EHI_RESET_MODIFIER_MASK;
+ }
+
ata_eh_clear_action(dev, &ap->eh_context.i, action);
}
@@ -1016,7 +1057,7 @@ static void ata_eh_analyze_ncq_error(struct ata_port *ap)
int tag, rc;
/* if frozen, we can't do much */
- if (ap->flags & ATA_FLAG_FROZEN)
+ if (ap->pflags & ATA_PFLAG_FROZEN)
return;
/* is it NCQ device error? */
@@ -1255,8 +1296,6 @@ static int ata_eh_speed_down(struct ata_device *dev, int is_io,
static void ata_eh_autopsy(struct ata_port *ap)
{
struct ata_eh_context *ehc = &ap->eh_context;
- unsigned int action = ehc->i.action;
- struct ata_device *failed_dev = NULL;
unsigned int all_err_mask = 0;
int tag, is_io = 0;
u32 serror;
@@ -1264,13 +1303,16 @@ static void ata_eh_autopsy(struct ata_port *ap)
DPRINTK("ENTER\n");
+ if (ehc->i.flags & ATA_EHI_NO_AUTOPSY)
+ return;
+
/* obtain and analyze SError */
rc = sata_scr_read(ap, SCR_ERROR, &serror);
if (rc == 0) {
ehc->i.serror |= serror;
ata_eh_analyze_serror(ap);
} else if (rc != -EOPNOTSUPP)
- action |= ATA_EH_HARDRESET;
+ ehc->i.action |= ATA_EH_HARDRESET;
/* analyze NCQ failure */
ata_eh_analyze_ncq_error(ap);
@@ -1291,7 +1333,7 @@ static void ata_eh_autopsy(struct ata_port *ap)
qc->err_mask |= ehc->i.err_mask;
/* analyze TF */
- action |= ata_eh_analyze_tf(qc, &qc->result_tf);
+ ehc->i.action |= ata_eh_analyze_tf(qc, &qc->result_tf);
/* DEV errors are probably spurious in case of ATA_BUS error */
if (qc->err_mask & AC_ERR_ATA_BUS)
@@ -1305,38 +1347,35 @@ static void ata_eh_autopsy(struct ata_port *ap)
/* SENSE_VALID trumps dev/unknown error and revalidation */
if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
qc->err_mask &= ~(AC_ERR_DEV | AC_ERR_OTHER);
- action &= ~ATA_EH_REVALIDATE;
+ ehc->i.action &= ~ATA_EH_REVALIDATE;
}
/* accumulate error info */
- failed_dev = qc->dev;
+ ehc->i.dev = qc->dev;
all_err_mask |= qc->err_mask;
if (qc->flags & ATA_QCFLAG_IO)
is_io = 1;
}
/* enforce default EH actions */
- if (ap->flags & ATA_FLAG_FROZEN ||
+ if (ap->pflags & ATA_PFLAG_FROZEN ||
all_err_mask & (AC_ERR_HSM | AC_ERR_TIMEOUT))
- action |= ATA_EH_SOFTRESET;
+ ehc->i.action |= ATA_EH_SOFTRESET;
else if (all_err_mask)
- action |= ATA_EH_REVALIDATE;
+ ehc->i.action |= ATA_EH_REVALIDATE;
/* if we have offending qcs and the associated failed device */
- if (failed_dev) {
+ if (ehc->i.dev) {
/* speed down */
- action |= ata_eh_speed_down(failed_dev, is_io, all_err_mask);
+ ehc->i.action |= ata_eh_speed_down(ehc->i.dev, is_io,
+ all_err_mask);
/* perform per-dev EH action only on the offending device */
- ehc->i.dev_action[failed_dev->devno] |=
- action & ATA_EH_PERDEV_MASK;
- action &= ~ATA_EH_PERDEV_MASK;
+ ehc->i.dev_action[ehc->i.dev->devno] |=
+ ehc->i.action & ATA_EH_PERDEV_MASK;
+ ehc->i.action &= ~ATA_EH_PERDEV_MASK;
}
- /* record autopsy result */
- ehc->i.dev = failed_dev;
- ehc->i.action = action;
-
DPRINTK("EXIT\n");
}
@@ -1374,7 +1413,7 @@ static void ata_eh_report(struct ata_port *ap)
return;
frozen = "";
- if (ap->flags & ATA_FLAG_FROZEN)
+ if (ap->pflags & ATA_PFLAG_FROZEN)
frozen = " frozen";
if (ehc->i.dev) {
@@ -1454,11 +1493,14 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
struct ata_eh_context *ehc = &ap->eh_context;
unsigned int *classes = ehc->classes;
int tries = ATA_EH_RESET_TRIES;
- int verbose = !(ap->flags & ATA_FLAG_LOADING);
+ int verbose = !(ehc->i.flags & ATA_EHI_QUIET);
unsigned int action;
ata_reset_fn_t reset;
int i, did_followup_srst, rc;
+ /* about to reset */
+ ata_eh_about_to_do(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
+
/* Determine which reset to use and record in ehc->i.action.
* prereset() may examine and modify it.
*/
@@ -1473,7 +1515,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
if (prereset) {
rc = prereset(ap);
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ if (rc == -ENOENT) {
+ ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n");
+ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ } else
+ ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
return rc;
}
@@ -1507,8 +1553,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
ata_port_printk(ap, KERN_INFO, "%s resetting port\n",
reset == softreset ? "soft" : "hard");
- /* reset */
- ata_eh_about_to_do(ap, NULL, ATA_EH_RESET_MASK);
+ /* mark that this EH session started with reset */
ehc->i.flags |= ATA_EHI_DID_RESET;
rc = ata_do_reset(ap, reset, classes);
@@ -1571,7 +1616,7 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
postreset(ap, classes);
/* reset successful, schedule revalidation */
- ata_eh_done(ap, NULL, ATA_EH_RESET_MASK);
+ ata_eh_done(ap, NULL, ehc->i.action & ATA_EH_RESET_MASK);
ehc->i.action |= ATA_EH_REVALIDATE;
}
@@ -1592,9 +1637,9 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
unsigned int action;
dev = &ap->device[i];
- action = ehc->i.action | ehc->i.dev_action[dev->devno];
+ action = ata_eh_dev_action(dev);
- if (action & ATA_EH_REVALIDATE && ata_dev_enabled(dev)) {
+ if (action & ATA_EH_REVALIDATE && ata_dev_ready(dev)) {
if (ata_port_offline(ap)) {
rc = -EIO;
break;
@@ -1625,7 +1670,7 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
}
spin_lock_irqsave(ap->lock, flags);
- ap->flags |= ATA_FLAG_SCSI_HOTPLUG;
+ ap->pflags |= ATA_PFLAG_SCSI_HOTPLUG;
spin_unlock_irqrestore(ap->lock, flags);
}
}
@@ -1637,6 +1682,164 @@ static int ata_eh_revalidate_and_attach(struct ata_port *ap,
return rc;
}
+/**
+ * ata_eh_suspend - handle suspend EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle suspend EH action. Disk devices are spinned down and
+ * other types of devices are just marked suspended. Once
+ * suspended, no EH action to the device is allowed until it is
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_suspend(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned long flags;
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_SUSPEND))
+ continue;
+
+ WARN_ON(dev->flags & ATA_DFLAG_SUSPENDED);
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_SUSPEND);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ /* flush cache */
+ rc = ata_flush_cache(dev);
+ if (rc)
+ break;
+
+ /* spin down */
+ err_mask = ata_do_simple_cmd(dev, ATA_CMD_STANDBYNOW1);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin down (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags |= ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ ata_eh_done(ap, dev, ATA_EH_SUSPEND);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
+/**
+ * ata_eh_prep_resume - prep for resume EH action
+ * @ap: target host port
+ *
+ * Clear SUSPENDED in preparation for scheduled resume actions.
+ * This allows other parts of EH to access the devices being
+ * resumed.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_prep_resume(struct ata_port *ap)
+{
+ struct ata_device *dev;
+ unsigned long flags;
+ int i;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ spin_lock_irqsave(ap->lock, flags);
+ dev->flags &= ~ATA_DFLAG_SUSPENDED;
+ spin_unlock_irqrestore(ap->lock, flags);
+ }
+
+ DPRINTK("EXIT\n");
+}
+
+/**
+ * ata_eh_resume - handle resume EH action
+ * @ap: target host port
+ * @r_failed_dev: result parameter to indicate failing device
+ *
+ * Handle resume EH action. Target devices are already reset and
+ * revalidated. Spinning up is the only operation left.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise
+ */
+static int ata_eh_resume(struct ata_port *ap, struct ata_device **r_failed_dev)
+{
+ struct ata_device *dev;
+ int i, rc = 0;
+
+ DPRINTK("ENTER\n");
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ unsigned int action, err_mask;
+
+ dev = &ap->device[i];
+ action = ata_eh_dev_action(dev);
+
+ if (!ata_dev_enabled(dev) || !(action & ATA_EH_RESUME))
+ continue;
+
+ ata_eh_about_to_do(ap, dev, ATA_EH_RESUME);
+
+ if (dev->class == ATA_DEV_ATA && !(action & ATA_EH_PM_FREEZE)) {
+ err_mask = ata_do_simple_cmd(dev,
+ ATA_CMD_IDLEIMMEDIATE);
+ if (err_mask) {
+ ata_dev_printk(dev, KERN_ERR, "failed to "
+ "spin up (err_mask=0x%x)\n",
+ err_mask);
+ rc = -EIO;
+ break;
+ }
+ }
+
+ ata_eh_done(ap, dev, ATA_EH_RESUME);
+ }
+
+ if (rc)
+ *r_failed_dev = dev;
+
+ DPRINTK("EXIT\n");
+ return 0;
+}
+
static int ata_port_nr_enabled(struct ata_port *ap)
{
int i, cnt = 0;
@@ -1662,7 +1865,20 @@ static int ata_eh_skip_recovery(struct ata_port *ap)
struct ata_eh_context *ehc = &ap->eh_context;
int i;
- if (ap->flags & ATA_FLAG_FROZEN || ata_port_nr_enabled(ap))
+ /* skip if all possible devices are suspended */
+ for (i = 0; i < ata_port_max_devices(ap); i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (!(dev->flags & ATA_DFLAG_SUSPENDED))
+ break;
+ }
+
+ if (i == ata_port_max_devices(ap))
+ return 1;
+
+ /* thaw frozen port, resume link and recover failed devices */
+ if ((ap->pflags & ATA_PFLAG_FROZEN) ||
+ (ehc->i.flags & ATA_EHI_RESUME_LINK) || ata_port_nr_enabled(ap))
return 0;
/* skip if class codes for all vacant slots are ATA_DEV_NONE */
@@ -1733,9 +1949,12 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
rc = 0;
/* if UNLOADING, finish immediately */
- if (ap->flags & ATA_FLAG_UNLOADING)
+ if (ap->pflags & ATA_PFLAG_UNLOADING)
goto out;
+ /* prep for resume */
+ ata_eh_prep_resume(ap);
+
/* skip EH if possible. */
if (ata_eh_skip_recovery(ap))
ehc->i.action = 0;
@@ -1763,6 +1982,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
if (rc)
goto dev_fail;
+ /* resume devices */
+ rc = ata_eh_resume(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
/* configure transfer mode if the port has been reset */
if (ehc->i.flags & ATA_EHI_DID_RESET) {
rc = ata_set_mode(ap, &dev);
@@ -1772,6 +1996,11 @@ static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
}
}
+ /* suspend devices */
+ rc = ata_eh_suspend(ap, &dev);
+ if (rc)
+ goto dev_fail;
+
goto out;
dev_fail:
@@ -1897,11 +2126,124 @@ void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
ata_postreset_fn_t postreset)
{
- if (!(ap->flags & ATA_FLAG_LOADING)) {
- ata_eh_autopsy(ap);
- ata_eh_report(ap);
- }
-
+ ata_eh_autopsy(ap);
+ ata_eh_report(ap);
ata_eh_recover(ap, prereset, softreset, hardreset, postreset);
ata_eh_finish(ap);
}
+
+/**
+ * ata_eh_handle_port_suspend - perform port suspend operation
+ * @ap: port to suspend
+ *
+ * Suspend @ap.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_suspend(struct ata_port *ap)
+{
+ unsigned long flags;
+ int rc = 0;
+
+ /* are we suspending? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event == PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED);
+
+ /* suspend */
+ ata_eh_freeze_port(ap);
+
+ if (ap->ops->port_suspend)
+ rc = ap->ops->port_suspend(ap, ap->pm_mesg);
+
+ /* report result */
+ spin_lock_irqsave(ap->lock, flags);
+
+ ap->pflags &= ~ATA_PFLAG_PM_PENDING;
+ if (rc == 0)
+ ap->pflags |= ATA_PFLAG_SUSPENDED;
+ else
+ ata_port_schedule_eh(ap);
+
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ return;
+}
+
+/**
+ * ata_eh_handle_port_resume - perform port resume operation
+ * @ap: port to resume
+ *
+ * Resume @ap.
+ *
+ * This function also waits upto one second until all devices
+ * hanging off this port requests resume EH action. This is to
+ * prevent invoking EH and thus reset multiple times on resume.
+ *
+ * On DPM resume, where some of devices might not be resumed
+ * together, this may delay port resume upto one second, but such
+ * DPM resumes are rare and 1 sec delay isn't too bad.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ */
+static void ata_eh_handle_port_resume(struct ata_port *ap)
+{
+ unsigned long timeout;
+ unsigned long flags;
+ int i, rc = 0;
+
+ /* are we resuming? */
+ spin_lock_irqsave(ap->lock, flags);
+ if (!(ap->pflags & ATA_PFLAG_PM_PENDING) ||
+ ap->pm_mesg.event != PM_EVENT_ON) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* spurious? */
+ if (!(ap->pflags & ATA_PFLAG_SUSPENDED))
+ goto done;
+
+ if (ap->ops->port_resume)
+ rc = ap->ops->port_resume(ap);
+
+ /* give devices time to request EH */
+ timeout = jiffies + HZ; /* 1s max */
+ while (1) {
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ unsigned int action = ata_eh_dev_action(dev);
+
+ if ((dev->flags & ATA_DFLAG_SUSPENDED) &&
+ !(action & ATA_EH_RESUME))
+ break;
+ }
+
+ if (i == ATA_MAX_DEVICES || time_after(jiffies, timeout))
+ break;
+ msleep(10);
+ }
+
+ done:
+ spin_lock_irqsave(ap->lock, flags);
+ ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
+ if (ap->pm_result) {
+ *ap->pm_result = rc;
+ ap->pm_result = NULL;
+ }
+ spin_unlock_irqrestore(ap->lock, flags);
+}
diff --git a/drivers/scsi/libata-scsi.c b/drivers/ata/libata-scsi.c
index 93d18a74c40..3986ec8741b 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -222,9 +222,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
&& copy_to_user(arg + sizeof(args), argbuf, argsize))
rc = -EFAULT;
error:
- if (argbuf)
- kfree(argbuf);
-
+ kfree(argbuf);
return rc;
}
@@ -323,7 +321,7 @@ int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
* current command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Command allocated, or %NULL if none available.
@@ -399,20 +397,129 @@ void ata_dump_status(unsigned id, struct ata_taskfile *tf)
}
}
-int ata_scsi_device_resume(struct scsi_device *sdev)
+/**
+ * ata_scsi_device_suspend - suspend ATA device associated with sdev
+ * @sdev: the SCSI device to suspend
+ * @mesg: target power management message
+ *
+ * Request suspend EH action on the ATA device associated with
+ * @sdev and wait for the operation to complete.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t mesg)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ unsigned long flags;
+ unsigned int action;
+ int rc = 0;
+
+ if (!dev)
+ goto out;
+
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* wait for the previous resume to complete */
+ while (dev->flags & ATA_DFLAG_SUSPENDED) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ ata_port_wait_eh(ap);
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
+
+ /* request suspend */
+ action = ATA_EH_SUSPEND;
+ if (mesg.event != PM_EVENT_SUSPEND)
+ action |= ATA_EH_PM_FREEZE;
+ ap->eh_info.dev_action[dev->devno] |= action;
+ ap->eh_info.flags |= ATA_EHI_QUIET;
+ ata_port_schedule_eh(ap);
+
+ spin_unlock_irqrestore(ap->lock, flags);
+
+ /* wait for EH to do the job */
+ ata_port_wait_eh(ap);
+
+ spin_lock_irqsave(ap->lock, flags);
- return ata_device_resume(dev);
+ /* If @sdev is still attached but the associated ATA device
+ * isn't suspended, the operation failed.
+ */
+ if (sdev->sdev_state != SDEV_OFFLINE &&
+ sdev->sdev_state != SDEV_CANCEL && sdev->sdev_state != SDEV_DEL &&
+ !(dev->flags & ATA_DFLAG_SUSPENDED))
+ rc = -EIO;
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ if (rc == 0)
+ sdev->sdev_gendev.power.power_state = mesg;
+ return rc;
}
-int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
+/**
+ * ata_scsi_device_resume - resume ATA device associated with sdev
+ * @sdev: the SCSI device to resume
+ *
+ * Request resume EH action on the ATA device associated with
+ * @sdev and return immediately. This enables parallel
+ * wakeup/spinup of devices.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep).
+ *
+ * RETURNS:
+ * 0.
+ */
+int ata_scsi_device_resume(struct scsi_device *sdev)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- struct ata_device *dev = __ata_scsi_find_dev(ap, sdev);
+ struct ata_device *dev = ata_scsi_find_dev(ap, sdev);
+ struct ata_eh_info *ehi = &ap->eh_info;
+ unsigned long flags;
+ unsigned int action;
+
+ if (!dev)
+ goto out;
- return ata_device_suspend(dev, state);
+ spin_lock_irqsave(ap->lock, flags);
+
+ /* if @sdev is already detached, nothing to do */
+ if (sdev->sdev_state == SDEV_OFFLINE ||
+ sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL)
+ goto out_unlock;
+
+ /* request resume */
+ action = ATA_EH_RESUME;
+ if (sdev->sdev_gendev.power.power_state.event == PM_EVENT_SUSPEND)
+ __ata_ehi_hotplugged(ehi);
+ else
+ action |= ATA_EH_PM_FREEZE | ATA_EH_SOFTRESET;
+ ehi->dev_action[dev->devno] |= action;
+
+ /* We don't want autopsy and verbose EH messages. Disable
+ * those if we're the only device on this link.
+ */
+ if (ata_port_max_devices(ap) == 1)
+ ehi->flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET;
+
+ ata_port_schedule_eh(ap);
+
+ out_unlock:
+ spin_unlock_irqrestore(ap->lock, flags);
+ out:
+ sdev->sdev_gendev.power.power_state = PMSG_ON;
+ return 0;
}
/**
@@ -430,7 +537,7 @@ int ata_scsi_device_suspend(struct scsi_device *sdev, pm_message_t state)
* format sense blocks.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
u8 *ascq, int verbose)
@@ -542,7 +649,7 @@ void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc,
* block. Clear sense key, ASC & ASCQ if there is no error.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc)
{
@@ -811,7 +918,7 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
* [See SAT revision 5 at www.t10.org]
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, non-zero on error.
@@ -879,7 +986,7 @@ invalid_fld:
* FLUSH CACHE EXT.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, non-zero on error.
@@ -1002,7 +1109,7 @@ static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen)
* Converts SCSI VERIFY command to an ATA READ VERIFY command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, non-zero on error.
@@ -1126,7 +1233,7 @@ nothing_to_do:
* %WRITE_16 are currently supported.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, non-zero on error.
@@ -1360,7 +1467,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
* issued to @dev.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* 1 if deferring is needed, 0 otherwise.
@@ -1403,7 +1510,7 @@ static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
* termination.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* 0 on success, SCSI_ML_QUEUE_DEVICE_BUSY if the command
@@ -1482,7 +1589,7 @@ defer:
* Maps buffer contained within SCSI command @cmd.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Length of response buffer.
@@ -1516,7 +1623,7 @@ static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
* Unmaps response buffer contained within @cmd.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
@@ -1542,7 +1649,7 @@ static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
* and sense buffer are assumed to be set).
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
@@ -1573,7 +1680,7 @@ void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
* with non-VPD INQUIRY command output.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -1629,7 +1736,7 @@ unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
* Returns list of inquiry VPD pages available.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
@@ -1657,7 +1764,7 @@ unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
* Returns ATA device serial number.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
@@ -1690,7 +1797,7 @@ unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
* name ("ATA "), model and serial numbers.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
@@ -1742,7 +1849,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
* that the caller should successfully complete this SCSI command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
@@ -1883,7 +1990,7 @@ static int ata_dev_supports_fua(u16 *id)
* descriptor for other device types.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
@@ -2022,7 +2129,7 @@ saving_not_supp:
* Simulate READ CAPACITY commands.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
@@ -2097,7 +2204,7 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
* Simulate REPORT LUNS command.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
@@ -2149,7 +2256,7 @@ void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
* and the specified additional sense codes.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
@@ -2246,6 +2353,19 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
ata_gen_ata_desc_sense(qc);
}
+ /* SCSI EH automatically locks door if sdev->locked is
+ * set. Sometimes door lock request continues to
+ * fail, for example, when no media is present. This
+ * creates a loop - SCSI EH issues door lock which
+ * fails and gets invoked again to acquire sense data
+ * for the failed command.
+ *
+ * If door lock fails, always clear sdev->locked to
+ * avoid this infinite loop.
+ */
+ if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL)
+ qc->dev->sdev->locked = 0;
+
qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
qc->scsidone(cmd);
ata_qc_free(qc);
@@ -2301,7 +2421,7 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
* @scsicmd: SCSI CDB associated with this PACKET command
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Zero on success, non-zero on failure.
@@ -2380,7 +2500,7 @@ static struct ata_device * __ata_scsi_find_dev(struct ata_port *ap,
* Determine if commands should be sent to the specified device.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* 0 if commands are not allowed / 1 if commands are allowed
@@ -2414,7 +2534,7 @@ static int ata_scsi_dev_enabled(struct ata_device *dev)
* SCSI command to be sent.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* Associated ATA device, or %NULL if not found.
@@ -2688,7 +2808,7 @@ static inline int __ata_scsi_queuecmd(struct scsi_cmnd *cmd,
* ATA and ATAPI devices appearing as SCSI devices.
*
* LOCKING:
- * Releases scsi-layer-held lock, and obtains host_set lock.
+ * Releases scsi-layer-held lock, and obtains host lock.
*
* RETURNS:
* Return value from __ata_scsi_queuecmd() if @cmd can be queued,
@@ -2732,7 +2852,7 @@ int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* that can be handled internally.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd,
@@ -2824,7 +2944,7 @@ void ata_scsi_scan_host(struct ata_port *ap)
if (!ata_dev_enabled(dev) || dev->sdev)
continue;
- sdev = __scsi_add_device(ap->host, 0, i, 0, NULL);
+ sdev = __scsi_add_device(ap->scsi_host, 0, i, 0, NULL);
if (!IS_ERR(sdev)) {
dev->sdev = sdev;
scsi_device_put(sdev);
@@ -2838,11 +2958,11 @@ void ata_scsi_scan_host(struct ata_port *ap)
*
* This function is called from ata_eh_hotplug() and responsible
* for taking the SCSI device attached to @dev offline. This
- * function is called with host_set lock which protects dev->sdev
+ * function is called with host lock which protects dev->sdev
* against clearing.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*
* RETURNS:
* 1 if attached SCSI device exists, 0 otherwise.
@@ -2878,16 +2998,16 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
* be removed if there is __scsi_device_get() interface which
* increments reference counts regardless of device state.
*/
- mutex_lock(&ap->host->scan_mutex);
+ mutex_lock(&ap->scsi_host->scan_mutex);
spin_lock_irqsave(ap->lock, flags);
- /* clearing dev->sdev is protected by host_set lock */
+ /* clearing dev->sdev is protected by host lock */
sdev = dev->sdev;
dev->sdev = NULL;
if (sdev) {
/* If user initiated unplug races with us, sdev can go
- * away underneath us after the host_set lock and
+ * away underneath us after the host lock and
* scan_mutex are released. Hold onto it.
*/
if (scsi_device_get(sdev) == 0) {
@@ -2904,7 +3024,7 @@ static void ata_scsi_remove_dev(struct ata_device *dev)
}
spin_unlock_irqrestore(ap->lock, flags);
- mutex_unlock(&ap->host->scan_mutex);
+ mutex_unlock(&ap->scsi_host->scan_mutex);
if (sdev) {
ata_dev_printk(dev, KERN_INFO, "detaching (SCSI %s)\n",
@@ -2932,7 +3052,7 @@ void ata_scsi_hotplug(void *data)
struct ata_port *ap = data;
int i;
- if (ap->flags & ATA_FLAG_UNLOADING) {
+ if (ap->pflags & ATA_PFLAG_UNLOADING) {
DPRINTK("ENTER/EXIT - unloading\n");
return;
}
@@ -3013,6 +3133,7 @@ static int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
if (dev) {
ap->eh_info.probe_mask |= 1 << dev->devno;
ap->eh_info.action |= ATA_EH_SOFTRESET;
+ ap->eh_info.flags |= ATA_EHI_RESUME_LINK;
} else
rc = -EINVAL;
}
@@ -3050,3 +3171,152 @@ void ata_scsi_dev_rescan(void *data)
scsi_rescan_device(&(dev->sdev->sdev_gendev));
}
}
+
+/**
+ * ata_sas_port_alloc - Allocate port for a SAS attached SATA device
+ * @pdev: PCI device that the scsi device is attached to
+ * @port_info: Information from low-level host driver
+ * @shost: SCSI host that the scsi device is attached to
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * ata_port pointer on success / NULL on failure.
+ */
+
+struct ata_port *ata_sas_port_alloc(struct ata_host *host,
+ struct ata_port_info *port_info,
+ struct Scsi_Host *shost)
+{
+ struct ata_port *ap = kzalloc(sizeof(*ap), GFP_KERNEL);
+ struct ata_probe_ent *ent;
+
+ if (!ap)
+ return NULL;
+
+ ent = ata_probe_ent_alloc(host->dev, port_info);
+ if (!ent) {
+ kfree(ap);
+ return NULL;
+ }
+
+ ata_port_init(ap, host, ent, 0);
+ ap->lock = shost->host_lock;
+ kfree(ent);
+ return ap;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_alloc);
+
+/**
+ * ata_sas_port_start - Set port up for dma.
+ * @ap: Port to initialize
+ *
+ * Called just after data structures for each port are
+ * initialized. Allocates DMA pad.
+ *
+ * May be used as the port_start() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+int ata_sas_port_start(struct ata_port *ap)
+{
+ return ata_pad_alloc(ap, ap->dev);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_start);
+
+/**
+ * ata_port_stop - Undo ata_sas_port_start()
+ * @ap: Port to shut down
+ *
+ * Frees the DMA pad.
+ *
+ * May be used as the port_stop() entry in ata_port_operations.
+ *
+ * LOCKING:
+ * Inherited from caller.
+ */
+
+void ata_sas_port_stop(struct ata_port *ap)
+{
+ ata_pad_free(ap, ap->dev);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_stop);
+
+/**
+ * ata_sas_port_init - Initialize a SATA device
+ * @ap: SATA port to initialize
+ *
+ * LOCKING:
+ * PCI/etc. bus probe sem.
+ *
+ * RETURNS:
+ * Zero on success, non-zero on error.
+ */
+
+int ata_sas_port_init(struct ata_port *ap)
+{
+ int rc = ap->ops->port_start(ap);
+
+ if (!rc)
+ rc = ata_bus_probe(ap);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_init);
+
+/**
+ * ata_sas_port_destroy - Destroy a SATA port allocated by ata_sas_port_alloc
+ * @ap: SATA port to destroy
+ *
+ */
+
+void ata_sas_port_destroy(struct ata_port *ap)
+{
+ ap->ops->port_stop(ap);
+ kfree(ap);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_destroy);
+
+/**
+ * ata_sas_slave_configure - Default slave_config routine for libata devices
+ * @sdev: SCSI device to configure
+ * @ap: ATA port to which SCSI device is attached
+ *
+ * RETURNS:
+ * Zero.
+ */
+
+int ata_sas_slave_configure(struct scsi_device *sdev, struct ata_port *ap)
+{
+ ata_scsi_sdev_config(sdev);
+ ata_scsi_dev_config(sdev, ap->device);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_slave_configure);
+
+/**
+ * ata_sas_queuecmd - Issue SCSI cdb to libata-managed device
+ * @cmd: SCSI command to be sent
+ * @done: Completion function, called when command is complete
+ * @ap: ATA port to which the command is being sent
+ *
+ * RETURNS:
+ * Zero.
+ */
+
+int ata_sas_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *),
+ struct ata_port *ap)
+{
+ ata_scsi_dump_cdb(ap, cmd);
+
+ if (likely(ata_scsi_dev_enabled(ap->device)))
+ __ata_scsi_queuecmd(cmd, done, ap->device);
+ else {
+ cmd->result = (DID_BAD_TARGET << 16);
+ done(cmd);
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
diff --git a/drivers/scsi/libata-bmdma.c b/drivers/ata/libata-sff.c
index 004e1a0d8b7..08b3a407473 100644
--- a/drivers/scsi/libata-bmdma.c
+++ b/drivers/ata/libata-sff.c
@@ -32,7 +32,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/libata.h>
@@ -194,7 +193,7 @@ void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf)
* synchronization with interrupt handler / other threads.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf)
@@ -217,7 +216,7 @@ static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile
* FIXME: missing write posting for 400nS delay enforcement
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
@@ -238,7 +237,7 @@ static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile
* synchronization with interrupt handler / other threads.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
{
@@ -423,7 +422,7 @@ u8 ata_altstatus(struct ata_port *ap)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
@@ -453,7 +452,7 @@ static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
@@ -484,7 +483,7 @@ static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
@@ -512,7 +511,7 @@ static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
@@ -536,7 +535,7 @@ static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
* May be used as the bmdma_start() entry in ata_port_operations.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_bmdma_start(struct ata_queued_cmd *qc)
{
@@ -558,7 +557,7 @@ void ata_bmdma_start(struct ata_queued_cmd *qc)
* May be used as the bmdma_setup() entry in ata_port_operations.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_bmdma_setup(struct ata_queued_cmd *qc)
{
@@ -578,7 +577,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc)
* May be used as the irq_clear() entry in ata_port_operations.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_bmdma_irq_clear(struct ata_port *ap)
@@ -606,7 +605,7 @@ void ata_bmdma_irq_clear(struct ata_port *ap)
* May be used as the bmdma_status() entry in ata_port_operations.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
u8 ata_bmdma_status(struct ata_port *ap)
@@ -630,7 +629,7 @@ u8 ata_bmdma_status(struct ata_port *ap)
* May be used as the bmdma_stop() entry in ata_port_operations.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
void ata_bmdma_stop(struct ata_queued_cmd *qc)
@@ -798,32 +797,6 @@ void ata_bmdma_post_internal_cmd(struct ata_queued_cmd *qc)
}
#ifdef CONFIG_PCI
-static struct ata_probe_ent *
-ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
-{
- struct ata_probe_ent *probe_ent;
-
- probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
- if (!probe_ent) {
- printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
- kobject_name(&(dev->kobj)));
- return NULL;
- }
-
- INIT_LIST_HEAD(&probe_ent->node);
- probe_ent->dev = dev;
-
- probe_ent->sht = port->sht;
- probe_ent->host_flags = port->host_flags;
- probe_ent->pio_mask = port->pio_mask;
- probe_ent->mwdma_mask = port->mwdma_mask;
- probe_ent->udma_mask = port->udma_mask;
- probe_ent->port_ops = port->port_ops;
-
- return probe_ent;
-}
-
-
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
@@ -854,7 +827,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
return NULL;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->private_data = port[0]->private_data;
if (ports & ATA_PORT_PRIMARY) {
@@ -865,7 +838,7 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
bmdma = pci_resource_start(pdev, 4);
if (bmdma) {
if (inb(bmdma + 2) & 0x80)
- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
probe_ent->port[p].bmdma_addr = bmdma;
}
ata_std_ports(&probe_ent->port[p]);
@@ -881,10 +854,11 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
if (bmdma) {
bmdma += 8;
if(inb(bmdma + 2) & 0x80)
- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
probe_ent->port[p].bmdma_addr = bmdma;
}
ata_std_ports(&probe_ent->port[p]);
+ probe_ent->pinfo2 = port[1];
p++;
}
@@ -894,44 +868,49 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
- struct ata_port_info *port, int port_num)
+ struct ata_port_info **port, int port_mask)
{
struct ata_probe_ent *probe_ent;
- unsigned long bmdma;
+ unsigned long bmdma = pci_resource_start(pdev, 4);
- probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port);
+ probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
if (!probe_ent)
return NULL;
- probe_ent->legacy_mode = 1;
- probe_ent->n_ports = 1;
- probe_ent->hard_port_no = port_num;
- probe_ent->private_data = port->private_data;
-
- switch(port_num)
- {
- case 0:
- probe_ent->irq = 14;
- probe_ent->port[0].cmd_addr = 0x1f0;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = 0x3f6;
- break;
- case 1:
- probe_ent->irq = 15;
- probe_ent->port[0].cmd_addr = 0x170;
- probe_ent->port[0].altstatus_addr =
- probe_ent->port[0].ctl_addr = 0x376;
- break;
- }
+ probe_ent->n_ports = 2;
+ probe_ent->private_data = port[0]->private_data;
- bmdma = pci_resource_start(pdev, 4);
- if (bmdma != 0) {
- bmdma += 8 * port_num;
- probe_ent->port[0].bmdma_addr = bmdma;
- if (inb(bmdma + 2) & 0x80)
- probe_ent->host_set_flags |= ATA_HOST_SIMPLEX;
- }
- ata_std_ports(&probe_ent->port[0]);
+ if (port_mask & ATA_PORT_PRIMARY) {
+ probe_ent->irq = ATA_PRIMARY_IRQ;
+ probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
+ probe_ent->port[0].altstatus_addr =
+ probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
+ if (bmdma) {
+ probe_ent->port[0].bmdma_addr = bmdma;
+ if (inb(bmdma + 2) & 0x80)
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ }
+ ata_std_ports(&probe_ent->port[0]);
+ } else
+ probe_ent->dummy_port_mask |= ATA_PORT_PRIMARY;
+
+ if (port_mask & ATA_PORT_SECONDARY) {
+ if (probe_ent->irq)
+ probe_ent->irq2 = ATA_SECONDARY_IRQ;
+ else
+ probe_ent->irq = ATA_SECONDARY_IRQ;
+ probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
+ probe_ent->port[1].altstatus_addr =
+ probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
+ if (bmdma) {
+ probe_ent->port[1].bmdma_addr = bmdma + 8;
+ if (inb(bmdma + 10) & 0x80)
+ probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
+ }
+ ata_std_ports(&probe_ent->port[1]);
+ probe_ent->pinfo2 = port[1];
+ } else
+ probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
return probe_ent;
}
@@ -951,6 +930,10 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
* regions, sets the dma mask, enables bus master mode, and calls
* ata_device_add()
*
+ * ASSUMPTION:
+ * Nobody makes a single channel controller that appears solely as
+ * the secondary legacy port on PCI.
+ *
* LOCKING:
* Inherited from PCI layer (may sleep).
*
@@ -961,7 +944,7 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
unsigned int n_ports)
{
- struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
+ struct ata_probe_ent *probe_ent = NULL;
struct ata_port_info *port[2];
u8 tmp8, mask;
unsigned int legacy_mode = 0;
@@ -976,7 +959,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
else
port[1] = port[0];
- if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
+ if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0
&& (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
/* TODO: What if one channel is in native mode ... */
pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
@@ -1010,35 +993,44 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
goto err_out;
}
- /* FIXME: Should use platform specific mappers for legacy port ranges */
if (legacy_mode) {
- if (!request_region(0x1f0, 8, "libata")) {
+ if (!request_region(ATA_PRIMARY_CMD, 8, "libata")) {
struct resource *conflict, res;
- res.start = 0x1f0;
- res.end = 0x1f0 + 8 - 1;
+ res.start = ATA_PRIMARY_CMD;
+ res.end = ATA_PRIMARY_CMD + 8 - 1;
conflict = ____request_resource(&ioport_resource, &res);
+ while (conflict->child)
+ conflict = ____request_resource(conflict, &res);
if (!strcmp(conflict->name, "libata"))
- legacy_mode |= (1 << 0);
+ legacy_mode |= ATA_PORT_PRIMARY;
else {
disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+ printk(KERN_WARNING "ata: 0x%0X IDE port busy\n" \
+ "ata: conflict with %s\n",
+ ATA_PRIMARY_CMD,
+ conflict->name);
}
} else
- legacy_mode |= (1 << 0);
+ legacy_mode |= ATA_PORT_PRIMARY;
- if (!request_region(0x170, 8, "libata")) {
+ if (!request_region(ATA_SECONDARY_CMD, 8, "libata")) {
struct resource *conflict, res;
- res.start = 0x170;
- res.end = 0x170 + 8 - 1;
+ res.start = ATA_SECONDARY_CMD;
+ res.end = ATA_SECONDARY_CMD + 8 - 1;
conflict = ____request_resource(&ioport_resource, &res);
+ while (conflict->child)
+ conflict = ____request_resource(conflict, &res);
if (!strcmp(conflict->name, "libata"))
- legacy_mode |= (1 << 1);
+ legacy_mode |= ATA_PORT_SECONDARY;
else {
disable_dev_on_err = 0;
- printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+ printk(KERN_WARNING "ata: 0x%X IDE port busy\n" \
+ "ata: conflict with %s\n",
+ ATA_SECONDARY_CMD,
+ conflict->name);
}
} else
- legacy_mode |= (1 << 1);
+ legacy_mode |= ATA_PORT_SECONDARY;
}
/* we have legacy mode, but all ports are unavailable */
@@ -1056,17 +1048,14 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
goto err_out_regions;
if (legacy_mode) {
- if (legacy_mode & (1 << 0))
- probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0);
- if (legacy_mode & (1 << 1))
- probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1);
+ probe_ent = ata_pci_init_legacy_port(pdev, port, legacy_mode);
} else {
if (n_ports == 2)
probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
else
probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
}
- if (!probe_ent && !probe_ent2) {
+ if (!probe_ent) {
rc = -ENOMEM;
goto err_out_regions;
}
@@ -1074,35 +1063,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
pci_set_master(pdev);
/* FIXME: check ata_device_add return */
- if (legacy_mode) {
- struct device *dev = &pdev->dev;
- struct ata_host_set *host_set = NULL;
-
- if (legacy_mode & (1 << 0)) {
- ata_device_add(probe_ent);
- host_set = dev_get_drvdata(dev);
- }
-
- if (legacy_mode & (1 << 1)) {
- ata_device_add(probe_ent2);
- if (host_set) {
- host_set->next = dev_get_drvdata(dev);
- dev_set_drvdata(dev, host_set);
- }
- }
- } else
- ata_device_add(probe_ent);
+ ata_device_add(probe_ent);
kfree(probe_ent);
- kfree(probe_ent2);
return 0;
err_out_regions:
- if (legacy_mode & (1 << 0))
- release_region(0x1f0, 8);
- if (legacy_mode & (1 << 1))
- release_region(0x170, 8);
+ if (legacy_mode & ATA_PORT_PRIMARY)
+ release_region(ATA_PRIMARY_CMD, 8);
+ if (legacy_mode & ATA_PORT_SECONDARY)
+ release_region(ATA_SECONDARY_CMD, 8);
pci_release_regions(pdev);
err_out:
if (disable_dev_on_err)
diff --git a/drivers/scsi/libata.h b/drivers/ata/libata.h
index bdd48889709..a5ecb71390a 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/ata/libata.h
@@ -29,7 +29,7 @@
#define __LIBATA_H__
#define DRV_NAME "libata"
-#define DRV_VERSION "1.30" /* must be exactly four chars */
+#define DRV_VERSION "2.00" /* must be exactly four chars */
struct ata_scsi_args {
struct ata_device *dev;
@@ -50,6 +50,7 @@ extern void ata_port_flush_task(struct ata_port *ap);
extern unsigned ata_exec_internal(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, void *buf, unsigned int buflen);
+extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
int post_reset, u16 *id);
extern int ata_dev_configure(struct ata_device *dev, int print_info);
@@ -64,9 +65,14 @@ extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
extern void ata_dev_select(struct ata_port *ap, unsigned int device,
unsigned int wait, unsigned int can_sleep);
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
+extern void ata_port_init(struct ata_port *ap, struct ata_host *host,
+ const struct ata_probe_ent *ent, unsigned int port_no);
+extern struct ata_probe_ent *ata_probe_ent_alloc(struct device *dev,
+ const struct ata_port_info *port);
/* libata-scsi.c */
@@ -105,6 +111,7 @@ extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
u8 *rbuf, unsigned int buflen));
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(void *data);
+extern int ata_bus_probe(struct ata_port *ap);
/* libata-eh.c */
extern enum scsi_eh_timer_return ata_scsi_timed_out(struct scsi_cmnd *cmd);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
new file mode 100644
index 00000000000..87af3b5861a
--- /dev/null
+++ b/drivers/ata/pata_ali.c
@@ -0,0 +1,679 @@
+/*
+ * pata_ali.c - ALI 15x3 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based in part upon
+ * linux/drivers/ide/pci/alim15x3.c Version 0.17 2003/01/02
+ *
+ * Copyright (C) 1998-2000 Michel Aubry, Maintainer
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz, Maintainer
+ * Copyright (C) 1999-2000 CJ, cjtsai@ali.com.tw, Maintainer
+ *
+ * Copyright (C) 1998-2000 Andre Hedrick (andre@linux-ide.org)
+ * May be copied or modified under the terms of the GNU General Public License
+ * Copyright (C) 2002 Alan Cox <alan@redhat.com>
+ * ALi (now ULi M5228) support by Clear Zhang <Clear.Zhang@ali.com.tw>
+ *
+ * Documentation
+ * Chipset documentation available under NDA only
+ *
+ * TODO/CHECK
+ * Cannot have ATAPI on both master & slave for rev < c2 (???) but
+ * otherwise should do atapi DMA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_ali"
+#define DRV_VERSION "0.6.5"
+
+/*
+ * Cable special cases
+ */
+
+static struct dmi_system_id cable_dmi_table[] = {
+ {
+ .ident = "HP Pavilion N5430",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_BOARD_NAME, "OmniBook N32N-736"),
+ },
+ },
+ { }
+};
+
+static int ali_cable_override(struct pci_dev *pdev)
+{
+ /* Fujitsu P2000 */
+ if (pdev->subsystem_vendor == 0x10CF && pdev->subsystem_device == 0x10AF)
+ return 1;
+ /* Systems by DMI */
+ if (dmi_check_system(cable_dmi_table))
+ return 1;
+ return 0;
+}
+
+/**
+ * ali_c2_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection for C2 and later revisions
+ */
+
+static int ali_c2_cable_detect(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+
+ /* Certain laptops use short but suitable cables and don't
+ implement the detect logic */
+
+ if (ali_cable_override(pdev))
+ return ATA_CBL_PATA80;
+
+ /* Host view cable detect 0x4A bit 0 primary bit 1 secondary
+ Bit set for 40 pin */
+ pci_read_config_byte(pdev, 0x4A, &ata66);
+ if (ata66 & (1 << ap->port_no))
+ return ATA_CBL_PATA40;
+ else
+ return ATA_CBL_PATA80;
+}
+
+/**
+ * ali_early_error_handler - reset for eary chip
+ * @ap: ATA port
+ *
+ * Handle the reset callback for the later chips with cable detect
+ */
+
+static int ali_c2_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ali_c2_cable_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+static void ali_c2_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ali_c2_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * ali_early_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection for older chipsets. This turns out to be
+ * rather easy to implement
+ */
+
+static int ali_early_cable_detect(struct ata_port *ap)
+{
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * ali_early_probe_init - reset for early chip
+ * @ap: ATA port
+ *
+ * Handle the reset callback for the early (pre cable detect) chips.
+ */
+
+static int ali_early_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ali_early_cable_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+static void ali_early_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, ali_early_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * ali_20_filter - filter for earlier ALI DMA
+ * @ap: ALi ATA port
+ * @adev: attached device
+ *
+ * Ensure that we do not do DMA on CD devices. We may be able to
+ * fix that later on. Also ensure we do not do UDMA on WDC drives
+ */
+
+static unsigned long ali_20_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ char model_num[40];
+ /* No DMA on anything but a disk for now */
+ if (adev->class != ATA_DEV_ATA)
+ mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
+ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ if (strstr(model_num, "WDC"))
+ return mask &= ~ATA_MASK_UDMA;
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * ali_fifo_control - FIFO manager
+ * @ap: ALi channel to control
+ * @adev: device for FIFO control
+ * @on: 0 for off 1 for on
+ *
+ * Enable or disable the FIFO on a given device. Because of the way the
+ * ALi FIFO works it provides a boost on ATA disk but can be confused by
+ * ATAPI and we must therefore manage it.
+ */
+
+static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int on)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int pio_fifo = 0x54 + ap->port_no;
+ u8 fifo;
+ int shift = 4 * adev->devno;
+
+ /* ATA - FIFO on set nibble to 0x05, ATAPI - FIFO off, set nibble to
+ 0x00. Not all the docs agree but the behaviour we now use is the
+ one stated in the BIOS Programming Guide */
+
+ pci_read_config_byte(pdev, pio_fifo, &fifo);
+ fifo &= ~(0x0F << shift);
+ if (on)
+ fifo |= (on << shift);
+ pci_write_config_byte(pdev, pio_fifo, fifo);
+}
+
+/**
+ * ali_program_modes - load mode registers
+ * @ap: ALi channel to load
+ * @adev: Device the timing is for
+ * @cmd: Command timing
+ * @data: Data timing
+ * @ultra: UDMA timing or zero for off
+ *
+ * Loads the timing registers for cmd/data and disable UDMA if
+ * ultra is zero. If ultra is set then load and enable the UDMA
+ * timing but do not touch the command/data timing.
+ */
+
+static void ali_program_modes(struct ata_port *ap, struct ata_device *adev, struct ata_timing *t, u8 ultra)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int cas = 0x58 + 4 * ap->port_no; /* Command timing */
+ int cbt = 0x59 + 4 * ap->port_no; /* Command timing */
+ int drwt = 0x5A + 4 * ap->port_no + adev->devno; /* R/W timing */
+ int udmat = 0x56 + ap->port_no; /* UDMA timing */
+ int shift = 4 * adev->devno;
+ u8 udma;
+
+ if (t != NULL) {
+ t->setup = FIT(t->setup, 1, 8) & 7;
+ t->act8b = FIT(t->act8b, 1, 8) & 7;
+ t->rec8b = FIT(t->rec8b, 1, 16) & 15;
+ t->active = FIT(t->active, 1, 8) & 7;
+ t->recover = FIT(t->recover, 1, 16) & 15;
+
+ pci_write_config_byte(pdev, cas, t->setup);
+ pci_write_config_byte(pdev, cbt, (t->act8b << 4) | t->rec8b);
+ pci_write_config_byte(pdev, drwt, (t->active << 4) | t->recover);
+ }
+
+ /* Set up the UDMA enable */
+ pci_read_config_byte(pdev, udmat, &udma);
+ udma &= ~(0x0F << shift);
+ udma |= ultra << shift;
+ pci_write_config_byte(pdev, udmat, udma);
+}
+
+/**
+ * ali_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the ALi registers for PIO mode. FIXME: add timings for
+ * PIO5.
+ */
+
+static void ali_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_device *pair = ata_dev_pair(adev);
+ struct ata_timing t;
+ unsigned long T = 1000000000 / 33333; /* PCI clock based */
+
+ ata_timing_compute(adev, adev->pio_mode, &t, T, 1);
+ if (pair) {
+ struct ata_timing p;
+ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ if (pair->dma_mode) {
+ ata_timing_compute(pair, pair->dma_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ }
+ }
+
+ /* PIO FIFO is only permitted on ATA disk */
+ if (adev->class != ATA_DEV_ATA)
+ ali_fifo_control(ap, adev, 0x00);
+ ali_program_modes(ap, adev, &t, 0);
+ if (adev->class == ATA_DEV_ATA)
+ ali_fifo_control(ap, adev, 0x05);
+
+}
+
+/**
+ * ali_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * FIXME: MWDMA timings
+ */
+
+static void ali_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u8 udma_timing[7] = { 0xC, 0xB, 0xA, 0x9, 0x8, 0xF, 0xD };
+ struct ata_device *pair = ata_dev_pair(adev);
+ struct ata_timing t;
+ unsigned long T = 1000000000 / 33333; /* PCI clock based */
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+
+ if (adev->class == ATA_DEV_ATA)
+ ali_fifo_control(ap, adev, 0x08);
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ ali_program_modes(ap, adev, NULL, udma_timing[adev->dma_mode - XFER_UDMA_0]);
+ if (adev->dma_mode >= XFER_UDMA_3) {
+ u8 reg4b;
+ pci_read_config_byte(pdev, 0x4B, &reg4b);
+ reg4b |= 1;
+ pci_write_config_byte(pdev, 0x4B, reg4b);
+ }
+ } else {
+ ata_timing_compute(adev, adev->dma_mode, &t, T, 1);
+ if (pair) {
+ struct ata_timing p;
+ ata_timing_compute(pair, pair->pio_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ if (pair->dma_mode) {
+ ata_timing_compute(pair, pair->dma_mode, &p, T, 1);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_SETUP|ATA_TIMING_8BIT);
+ }
+ }
+ ali_program_modes(ap, adev, &t, 0);
+ }
+}
+
+/**
+ * ali_lock_sectors - Keep older devices to 255 sector mode
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * Called during the bus probe for each device that is found. We use
+ * this call to lock the sector count of the device to 255 or less on
+ * older ALi controllers. If we didn't do this then large I/O's would
+ * require LBA48 commands which the older ALi requires are issued by
+ * slower PIO methods
+ */
+
+static void ali_lock_sectors(struct ata_port *ap, struct ata_device *adev)
+{
+ adev->max_sectors = 255;
+}
+
+static struct scsi_host_template ali_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* Keep LBA28 counts so large I/O's don't turn LBA48 and PIO
+ with older controllers. Not locked so will grow on C5 or later */
+ .max_sectors = 255,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Port operations for PIO only ALi
+ */
+
+static struct ata_port_operations ali_early_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ali_set_piomode,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Port operations for DMA capable ALi without cable
+ * detect
+ */
+static struct ata_port_operations ali_20_port_ops = {
+ .port_disable = ata_port_disable,
+
+ .set_piomode = ali_set_piomode,
+ .set_dmamode = ali_set_dmamode,
+ .mode_filter = ali_20_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = ali_lock_sectors,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Port operations for DMA capable ALi with cable detect
+ */
+static struct ata_port_operations ali_c2_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ali_set_piomode,
+ .set_dmamode = ali_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = ali_lock_sectors,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_c2_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Port operations for DMA capable ALi with cable detect and LBA48
+ */
+static struct ata_port_operations ali_c5_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ali_set_piomode,
+ .set_dmamode = ali_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ali_c2_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * ali_init_one - discovery callback
+ * @pdev: PCI device ID
+ * @id: PCI table info
+ *
+ * An ALi IDE interface has been discovered. Figure out what revision
+ * and perform configuration work before handing it to the ATA layer
+ */
+
+static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_early = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &ali_early_port_ops
+ };
+ /* Revision 0x20 added DMA */
+ static struct ata_port_info info_20 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &ali_20_port_ops
+ };
+ /* Revision 0x20 with support logic added UDMA */
+ static struct ata_port_info info_20_udma = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07, /* UDMA33 */
+ .port_ops = &ali_20_port_ops
+ };
+ /* Revision 0xC2 adds UDMA66 */
+ static struct ata_port_info info_c2 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &ali_c2_port_ops
+ };
+ /* Revision 0xC3 is UDMA100 */
+ static struct ata_port_info info_c3 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &ali_c2_port_ops
+ };
+ /* Revision 0xC4 is UDMA133 */
+ static struct ata_port_info info_c4 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST | ATA_FLAG_PIO_LBA48,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &ali_c2_port_ops
+ };
+ /* Revision 0xC5 is UDMA133 with LBA48 DMA */
+ static struct ata_port_info info_c5 = {
+ .sht = &ali_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &ali_c5_port_ops
+ };
+
+ static struct ata_port_info *port_info[2];
+ u8 rev, tmp;
+ struct pci_dev *north, *isa_bridge;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+
+ /*
+ * The chipset revision selects the driver operations and
+ * mode data.
+ */
+
+ if (rev < 0x20) {
+ port_info[0] = port_info[1] = &info_early;
+ } else if (rev < 0xC2) {
+ /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */
+ pci_read_config_byte(pdev, 0x4B, &tmp);
+ /* Clear CD-ROM DMA write bit */
+ tmp &= 0x7F;
+ pci_write_config_byte(pdev, 0x4B, tmp);
+ port_info[0] = port_info[1] = &info_20;
+ } else if (rev == 0xC2) {
+ port_info[0] = port_info[1] = &info_c2;
+ } else if (rev == 0xC3) {
+ port_info[0] = port_info[1] = &info_c3;
+ } else if (rev == 0xC4) {
+ port_info[0] = port_info[1] = &info_c4;
+ } else
+ port_info[0] = port_info[1] = &info_c5;
+
+ if (rev >= 0xC2) {
+ /* Enable cable detection logic */
+ pci_read_config_byte(pdev, 0x4B, &tmp);
+ pci_write_config_byte(pdev, 0x4B, tmp | 0x08);
+ }
+
+ north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0));
+ isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+
+ if (north && north->vendor == PCI_VENDOR_ID_AL) {
+ /* Configure the ALi bridge logic. For non ALi rely on BIOS.
+ Set the south bridge enable bit */
+ pci_read_config_byte(isa_bridge, 0x79, &tmp);
+ if (rev == 0xC2)
+ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04);
+ else if (rev > 0xC2)
+ pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02);
+ }
+
+ if (rev >= 0x20) {
+ if (rev < 0xC2) {
+ /* Are we paired with a UDMA capable chip */
+ pci_read_config_byte(isa_bridge, 0x5E, &tmp);
+ if ((tmp & 0x1E) == 0x12)
+ port_info[0] = port_info[1] = &info_20_udma;
+ }
+ /*
+ * CD_ROM DMA on (0x53 bit 0). Enable this even if we want
+ * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control
+ * via 0x54/55.
+ */
+ pci_read_config_byte(pdev, 0x53, &tmp);
+ if (rev <= 0x20)
+ tmp &= ~0x02;
+ if (rev == 0xc7)
+ tmp |= 0x03;
+ else
+ tmp |= 0x01; /* CD_ROM enable for DMA */
+ pci_write_config_byte(pdev, 0x53, tmp);
+ }
+
+ pci_dev_put(isa_bridge);
+ pci_dev_put(north);
+
+ ata_pci_clear_simplex(pdev);
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static struct pci_device_id ali[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), },
+ { 0, },
+};
+
+static struct pci_driver ali_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ali,
+ .probe = ali_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init ali_init(void)
+{
+ return pci_register_driver(&ali_pci_driver);
+}
+
+
+static void __exit ali_exit(void)
+{
+ pci_unregister_driver(&ali_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for ALi PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ali);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ali_init);
+module_exit(ali_exit);
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
new file mode 100644
index 00000000000..599ee266722
--- /dev/null
+++ b/drivers/ata/pata_amd.c
@@ -0,0 +1,709 @@
+/*
+ * pata_amd.c - AMD PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based on pata-sil680. Errata information is taken from data sheets
+ * and the amd74xx.c driver by Vojtech Pavlik. Nvidia SATA devices are
+ * claimed by sata-nv.c.
+ *
+ * TODO:
+ * Variable system clock when/if it makes sense
+ * Power management on ports
+ *
+ *
+ * Documentation publically available.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_amd"
+#define DRV_VERSION "0.2.4"
+
+/**
+ * timing_setup - shared timing computation and load
+ * @ap: ATA port being set up
+ * @adev: drive being configured
+ * @offset: port offset
+ * @speed: target speed
+ * @clock: clock multiplier (number of times 33MHz for this part)
+ *
+ * Perform the actual timing set up for Nvidia or AMD PATA devices.
+ * The actual devices vary so they all call into this helper function
+ * providing the clock multipler and offset (because AMD and Nvidia put
+ * the ports at different locations).
+ */
+
+static void timing_setup(struct ata_port *ap, struct ata_device *adev, int offset, int speed, int clock)
+{
+ static const unsigned char amd_cyc2udma[] = {
+ 6, 6, 5, 4, 0, 1, 1, 2, 2, 3, 3, 3, 3, 3, 3, 7
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *peer = ata_dev_pair(adev);
+ int dn = ap->port_no * 2 + adev->devno;
+ struct ata_timing at, apeer;
+ int T, UT;
+ const int amd_clock = 33333; /* KHz. */
+ u8 t;
+
+ T = 1000000000 / amd_clock;
+ UT = T / min_t(int, max_t(int, clock, 1), 2);
+
+ if (ata_timing_compute(adev, speed, &at, T, UT) < 0) {
+ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", speed);
+ return;
+ }
+
+ if (peer) {
+ /* This may be over conservative */
+ if (peer->dma_mode) {
+ ata_timing_compute(peer, peer->dma_mode, &apeer, T, UT);
+ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT);
+ }
+ ata_timing_compute(peer, peer->pio_mode, &apeer, T, UT);
+ ata_timing_merge(&apeer, &at, &at, ATA_TIMING_8BIT);
+ }
+
+ if (speed == XFER_UDMA_5 && amd_clock <= 33333) at.udma = 1;
+ if (speed == XFER_UDMA_6 && amd_clock <= 33333) at.udma = 15;
+
+ /*
+ * Now do the setup work
+ */
+
+ /* Configure the address set up timing */
+ pci_read_config_byte(pdev, offset + 0x0C, &t);
+ t = (t & ~(3 << ((3 - dn) << 1))) | ((FIT(at.setup, 1, 4) - 1) << ((3 - dn) << 1));
+ pci_write_config_byte(pdev, offset + 0x0C , t);
+
+ /* Configure the 8bit I/O timing */
+ pci_write_config_byte(pdev, offset + 0x0E + (1 - (dn >> 1)),
+ ((FIT(at.act8b, 1, 16) - 1) << 4) | (FIT(at.rec8b, 1, 16) - 1));
+
+ /* Drive timing */
+ pci_write_config_byte(pdev, offset + 0x08 + (3 - dn),
+ ((FIT(at.active, 1, 16) - 1) << 4) | (FIT(at.recover, 1, 16) - 1));
+
+ switch (clock) {
+ case 1:
+ t = at.udma ? (0xc0 | (FIT(at.udma, 2, 5) - 2)) : 0x03;
+ break;
+
+ case 2:
+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 2, 10)]) : 0x03;
+ break;
+
+ case 3:
+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 10)]) : 0x03;
+ break;
+
+ case 4:
+ t = at.udma ? (0xc0 | amd_cyc2udma[FIT(at.udma, 1, 15)]) : 0x03;
+ break;
+
+ default:
+ return;
+ }
+
+ /* UDMA timing */
+ pci_write_config_byte(pdev, offset + 0x10 + (3 - dn), t);
+}
+
+/**
+ * amd_probe_init - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. The BIOS stores this in PCI config
+ * space for us.
+ */
+
+static int amd_pre_reset(struct ata_port *ap)
+{
+ static const u32 bitmask[2] = {0x03, 0xC0};
+ static const struct pci_bits amd_enable_bits[] = {
+ { 0x40, 1, 0x02, 0x02 },
+ { 0x40, 1, 0x01, 0x01 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+
+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x42, &ata66);
+ if (ata66 & bitmask[ap->port_no])
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+
+}
+
+static void amd_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, amd_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+static int amd_early_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static struct pci_bits amd_enable_bits[] = {
+ { 0x40, 1, 0x02, 0x02 },
+ { 0x40, 1, 0x01, 0x01 }
+ };
+
+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ /* No host side cable detection */
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+
+}
+
+static void amd_early_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, amd_early_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * amd33_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the AMD registers for PIO mode.
+ */
+
+static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 1);
+}
+
+static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 2);
+}
+
+static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 3);
+}
+
+static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->pio_mode, 4);
+}
+
+/**
+ * amd33_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the AMD and Nvidia
+ * chipset.
+ */
+
+static void amd33_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 1);
+}
+
+static void amd66_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 2);
+}
+
+static void amd100_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 3);
+}
+
+static void amd133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x40, adev->dma_mode, 4);
+}
+
+
+/**
+ * nv_probe_init - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. The BIOS stores this in PCI config
+ * space for us.
+ */
+
+static int nv_pre_reset(struct ata_port *ap) {
+ static const u8 bitmask[2] = {0x03, 0xC0};
+ static const struct pci_bits nv_enable_bits[] = {
+ { 0x50, 1, 0x02, 0x02 },
+ { 0x50, 1, 0x01, 0x01 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ata66;
+ u16 udma;
+
+ if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x52, &ata66);
+ if (ata66 & bitmask[ap->port_no])
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+
+ /* We now have to double check because the Nvidia boxes BIOS
+ doesn't always set the cable bits but does set mode bits */
+
+ pci_read_config_word(pdev, 0x62 - 2 * ap->port_no, &udma);
+ if ((udma & 0xC4) == 0xC4 || (udma & 0xC400) == 0xC400)
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+static void nv_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, nv_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+/**
+ * nv100_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the AMD registers for PIO mode.
+ */
+
+static void nv100_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->pio_mode, 3);
+}
+
+static void nv133_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->pio_mode, 4);
+}
+
+/**
+ * nv100_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the AMD and Nvidia
+ * chipset.
+ */
+
+static void nv100_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->dma_mode, 3);
+}
+
+static void nv133_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ timing_setup(ap, adev, 0x50, adev->dma_mode, 4);
+}
+
+static struct scsi_host_template amd_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations amd33_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd33_set_piomode,
+ .set_dmamode = amd33_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations amd66_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd66_set_piomode,
+ .set_dmamode = amd66_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_early_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations amd100_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd100_set_piomode,
+ .set_dmamode = amd100_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations amd133_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = amd133_set_piomode,
+ .set_dmamode = amd133_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = amd_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations nv100_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = nv100_set_piomode,
+ .set_dmamode = nv100_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations nv133_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = nv133_set_piomode,
+ .set_dmamode = nv133_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = nv_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info[10] = {
+ { /* 0: AMD 7401 */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07, /* No SWDMA */
+ .udma_mask = 0x07, /* UDMA 33 */
+ .port_ops = &amd33_port_ops
+ },
+ { /* 1: Early AMD7409 - no swdma */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f, /* UDMA 66 */
+ .port_ops = &amd66_port_ops
+ },
+ { /* 2: AMD 7409, no swdma errata */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f, /* UDMA 66 */
+ .port_ops = &amd66_port_ops
+ },
+ { /* 3: AMD 7411 */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &amd100_port_ops
+ },
+ { /* 4: AMD 7441 */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &amd100_port_ops
+ },
+ { /* 5: AMD 8111*/
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* UDMA 133, no swdma */
+ .port_ops = &amd133_port_ops
+ },
+ { /* 6: AMD 8111 UDMA 100 (Serenade) */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100, no swdma */
+ .port_ops = &amd133_port_ops
+ },
+ { /* 7: Nvidia Nforce */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &nv100_port_ops
+ },
+ { /* 8: Nvidia Nforce2 and later */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* UDMA 133, no swdma */
+ .port_ops = &nv133_port_ops
+ },
+ { /* 9: AMD CS5536 (Geode companion) */
+ .sht = &amd_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f, /* UDMA 100 */
+ .port_ops = &amd100_port_ops
+ }
+ };
+ static struct ata_port_info *port_info[2];
+ static int printed_version;
+ int type = id->driver_data;
+ u8 rev;
+ u8 fifo;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+ pci_read_config_byte(pdev, 0x41, &fifo);
+
+ /* Check for AMD7409 without swdma errata and if found adjust type */
+ if (type == 1 && rev > 0x7)
+ type = 2;
+
+ /* Check for AMD7411 */
+ if (type == 3)
+ /* FIFO is broken */
+ pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
+ else
+ pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
+
+ /* Serenade ? */
+ if (type == 5 && pdev->subsystem_vendor == PCI_VENDOR_ID_AMD &&
+ pdev->subsystem_device == PCI_DEVICE_ID_AMD_SERENADE)
+ type = 6; /* UDMA 100 only */
+
+ if (type < 3)
+ ata_pci_clear_simplex(pdev);
+
+ /* And fire it up */
+
+ port_info[0] = port_info[1] = &info[type];
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id amd[] = {
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
+ { 0, },
+};
+
+static struct pci_driver amd_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = amd,
+ .probe = amd_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init amd_init(void)
+{
+ return pci_register_driver(&amd_pci_driver);
+}
+
+static void __exit amd_exit(void)
+{
+ pci_unregister_driver(&amd_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for AMD PATA IDE");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, amd);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(amd_init);
+module_exit(amd_exit);
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
new file mode 100644
index 00000000000..c4ccb75a4f1
--- /dev/null
+++ b/drivers/ata/pata_artop.c
@@ -0,0 +1,512 @@
+/*
+ * pata_artop.c - ARTOP ATA controller driver
+ *
+ * (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * Based in part on drivers/ide/pci/aec62xx.c
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ * 865/865R fixes for Macintosh card version from a patch to the old
+ * driver by Thibaut VARENE <varenet@parisc-linux.org>
+ * When setting the PCI latency we must set 0x80 or higher for burst
+ * performance Alessandro Zummo <alessandro.zummo@towertech.it>
+ *
+ * TODO
+ * 850 serialization once the core supports it
+ * Investigate no_dsc on 850R
+ * Clock detect
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_artop"
+#define DRV_VERSION "0.4.2"
+
+/*
+ * The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
+ * get PCI bus speed functionality we leave this as 0. Its a variable
+ * for when we get the functionality and also for folks wanting to
+ * test stuff.
+ */
+
+static int clock = 0;
+
+static int artop6210_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ const struct pci_bits artop_enable_bits[] = {
+ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * artop6210_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, artop6210_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * artop6260_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * The ARTOP hardware reports the cable detect bits in register 0x49.
+ * Nothing complicated needed here.
+ */
+
+static int artop6260_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits artop_enable_bits[] = {
+ { 0x4AU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ /* Odd numbered device ids are the units with enable bits (the -R cards) */
+ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x49, &tmp);
+ if (tmp & (1 >> ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * artop6260_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, artop6260_pre_reset,
+ ata_std_softreset, NULL,
+ ata_std_postreset);
+}
+
+/**
+ * artop6210_load_piomode - Load a set of PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device
+ * @pio: PIO mode
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * is used both to set PIO timings in PIO mode and also to set the
+ * matching PIO clocking for UDMA, as well as the MWDMA timings.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_load_piomode(struct ata_port *ap, struct ata_device *adev, unsigned int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ const u16 timing[2][5] = {
+ { 0x0000, 0x000A, 0x0008, 0x0303, 0x0301 },
+ { 0x0700, 0x070A, 0x0708, 0x0403, 0x0401 }
+
+ };
+ /* Load the PIO timing active/recovery bits */
+ pci_write_config_word(pdev, 0x40 + 2 * dn, timing[clock][pio]);
+}
+
+/**
+ * artop6210_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ *
+ * Set PIO mode for device, in host controller PCI config space. For
+ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In
+ * the event UDMA is used the later call to set_dmamode will set the
+ * bits as required.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ u8 ultra;
+
+ artop6210_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+
+ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */
+ pci_read_config_byte(pdev, 0x54, &ultra);
+ ultra &= ~(3 << (2 * dn));
+ pci_write_config_byte(pdev, 0x54, ultra);
+}
+
+/**
+ * artop6260_load_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ * @pio: PIO mode
+ *
+ * Set PIO mode for device, in host controller PCI config space. The
+ * ARTOP6260 and relatives store the timing data differently.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_load_piomode (struct ata_port *ap, struct ata_device *adev, unsigned int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ const u8 timing[2][5] = {
+ { 0x00, 0x0A, 0x08, 0x33, 0x31 },
+ { 0x70, 0x7A, 0x78, 0x43, 0x41 }
+
+ };
+ /* Load the PIO timing active/recovery bits */
+ pci_write_config_byte(pdev, 0x40 + dn, timing[clock][pio]);
+}
+
+/**
+ * artop6260_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ *
+ * Set PIO mode for device, in host controller PCI config space. For
+ * ARTOP we must also clear the UDMA bits if we are not doing UDMA. In
+ * the event UDMA is used the later call to set_dmamode will set the
+ * bits as required.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ultra;
+
+ artop6260_load_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+
+ /* Clear the UDMA mode bits (set_dmamode will redo this if needed) */
+ pci_read_config_byte(pdev, 0x44 + ap->port_no, &ultra);
+ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */
+ pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
+}
+
+/**
+ * artop6210_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set DMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6210_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = adev->devno + 2 * ap->port_no;
+ u8 ultra;
+
+ if (adev->dma_mode == XFER_MW_DMA_0)
+ pio = 1;
+ else
+ pio = 4;
+
+ /* Load the PIO timing active/recovery bits */
+ artop6210_load_piomode(ap, adev, pio);
+
+ pci_read_config_byte(pdev, 0x54, &ultra);
+ ultra &= ~(3 << (2 * dn));
+
+ /* Add ultra DMA bits if in UDMA mode */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ u8 mode = (adev->dma_mode - XFER_UDMA_0) + 1 - clock;
+ if (mode == 0)
+ mode = 1;
+ ultra |= (mode << (2 * dn));
+ }
+ pci_write_config_byte(pdev, 0x54, ultra);
+}
+
+/**
+ * artop6260_set_dmamode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring
+ *
+ * Set DMA mode for device, in host controller PCI config space. The
+ * ARTOP6260 and relatives store the timing data differently.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void artop6260_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 ultra;
+
+ if (adev->dma_mode == XFER_MW_DMA_0)
+ pio = 1;
+ else
+ pio = 4;
+
+ /* Load the PIO timing active/recovery bits */
+ artop6260_load_piomode(ap, adev, pio);
+
+ /* Add ultra DMA bits if in UDMA mode */
+ pci_read_config_byte(pdev, 0x44 + ap->port_no, &ultra);
+ ultra &= ~(7 << (4 * adev->devno)); /* One nibble per drive */
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ u8 mode = adev->dma_mode - XFER_UDMA_0 + 1 - clock;
+ if (mode == 0)
+ mode = 1;
+ ultra |= (mode << (4 * adev->devno));
+ }
+ pci_write_config_byte(pdev, 0x44 + ap->port_no, ultra);
+}
+
+static struct scsi_host_template artop_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations artop6210_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = artop6210_set_piomode,
+ .set_dmamode = artop6210_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = artop6210_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations artop6260_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = artop6260_set_piomode,
+ .set_dmamode = artop6260_set_dmamode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = artop6260_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * artop_init_one - Register ARTOP ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in artop_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static int printed_version;
+ static struct ata_port_info info_6210 = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &artop6210_ops,
+ };
+ static struct ata_port_info info_626x = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &artop6260_ops,
+ };
+ static struct ata_port_info info_626x_fast = {
+ .sht = &artop_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &artop6260_ops,
+ };
+ struct ata_port_info *port_info[2];
+ struct ata_port_info *info;
+ int ports = 2;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ if (id->driver_data == 0) { /* 6210 variant */
+ info = &info_6210;
+ /* BIOS may have left us in UDMA, clear it before libata probe */
+ pci_write_config_byte(pdev, 0x54, 0);
+ /* For the moment (also lacks dsc) */
+ printk(KERN_WARNING "ARTOP 6210 requires serialize functionality not yet supported by libata.\n");
+ printk(KERN_WARNING "Secondary ATA ports will not be activated.\n");
+ ports = 1;
+ }
+ else if (id->driver_data == 1) /* 6260 */
+ info = &info_626x;
+ else if (id->driver_data == 2) { /* 6260 or 6260 + fast */
+ unsigned long io = pci_resource_start(pdev, 4);
+ u8 reg;
+
+ info = &info_626x;
+ if (inb(io) & 0x10)
+ info = &info_626x_fast;
+ /* Mac systems come up with some registers not set as we
+ will need them */
+
+ /* Clear reset & test bits */
+ pci_read_config_byte(pdev, 0x49, &reg);
+ pci_write_config_byte(pdev, 0x49, reg & ~ 0x30);
+
+ /* PCI latency must be > 0x80 for burst mode, tweak it
+ * if required.
+ */
+ pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &reg);
+ if (reg <= 0x80)
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x90);
+
+ /* Enable IRQ output and burst mode */
+ pci_read_config_byte(pdev, 0x4a, &reg);
+ pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
+
+ }
+ port_info[0] = port_info[1] = info;
+ return ata_pci_init_one(pdev, port_info, ports);
+}
+
+static const struct pci_device_id artop_pci_tbl[] = {
+ { 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { } /* terminate list */
+};
+
+static struct pci_driver artop_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = artop_pci_tbl,
+ .probe = artop_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init artop_init(void)
+{
+ return pci_register_driver(&artop_pci_driver);
+}
+
+static void __exit artop_exit(void)
+{
+ pci_unregister_driver(&artop_pci_driver);
+}
+
+
+module_init(artop_init);
+module_exit(artop_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for ARTOP PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, artop_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
new file mode 100644
index 00000000000..6c2269b6bd3
--- /dev/null
+++ b/drivers/ata/pata_atiixp.c
@@ -0,0 +1,304 @@
+/*
+ * pata_atiixp.c - ATI PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based on
+ *
+ * linux/drivers/ide/pci/atiixp.c Version 0.01-bart2 Feb. 26, 2004
+ *
+ * Copyright (C) 2003 ATI Inc. <hyu@ati.com>
+ * Copyright (C) 2004 Bartlomiej Zolnierkiewicz
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_atiixp"
+#define DRV_VERSION "0.4.3"
+
+enum {
+ ATIIXP_IDE_PIO_TIMING = 0x40,
+ ATIIXP_IDE_MWDMA_TIMING = 0x44,
+ ATIIXP_IDE_PIO_CONTROL = 0x48,
+ ATIIXP_IDE_PIO_MODE = 0x4a,
+ ATIIXP_IDE_UDMA_CONTROL = 0x54,
+ ATIIXP_IDE_UDMA_MODE = 0x56
+};
+
+static int atiixp_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static struct pci_bits atiixp_enable_bits[] = {
+ { 0x48, 1, 0x01, 0x00 },
+ { 0x48, 1, 0x08, 0x00 }
+ };
+
+ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+static void atiixp_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, atiixp_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * atiixp_set_pio_timing - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called by both the pio and dma setup functions to set the controller
+ * timings for PIO transfers. We must load both the mode number and
+ * timing values into the controller.
+ */
+
+static void atiixp_set_pio_timing(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ static u8 pio_timings[5] = { 0x5D, 0x47, 0x34, 0x22, 0x20 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = 2 * ap->port_no + adev->devno;
+
+ /* Check this is correct - the order is odd in both drivers */
+ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
+ u16 pio_mode_data, pio_timing_data;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_PIO_MODE, &pio_mode_data);
+ pio_mode_data &= ~(0x7 << (4 * dn));
+ pio_mode_data |= pio << (4 * dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
+
+ pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
+ pio_mode_data &= ~(0xFF << timing_shift);
+ pio_mode_data |= (pio_timings[pio] << timing_shift);
+ pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
+}
+
+/**
+ * atiixp_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. We use a shared helper for this
+ * as the DMA setup must also adjust the PIO timing information.
+ */
+
+static void atiixp_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ atiixp_set_pio_timing(ap, adev, adev->pio_mode - XFER_PIO_0);
+}
+
+/**
+ * atiixp_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup. We use timing tables for most
+ * modes but must tune an appropriate PIO mode to match.
+ */
+
+static void atiixp_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u8 mwdma_timings[5] = { 0x77, 0x21, 0x20 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dma = adev->dma_mode;
+ int dn = 2 * ap->port_no + adev->devno;
+ int wanted_pio;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ u16 udma_mode_data;
+
+ dma -= XFER_UDMA_0;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_MODE, &udma_mode_data);
+ udma_mode_data &= ~(0x7 << (4 * dn));
+ udma_mode_data |= dma << (4 * dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_MODE, udma_mode_data);
+ } else {
+ u16 mwdma_timing_data;
+ /* Check this is correct - the order is odd in both drivers */
+ int timing_shift = (16 * ap->port_no) + 8 * (adev->devno ^ 1);
+
+ dma -= XFER_MW_DMA_0;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, &mwdma_timing_data);
+ mwdma_timing_data &= ~(0xFF << timing_shift);
+ mwdma_timing_data |= (mwdma_timings[dma] << timing_shift);
+ pci_write_config_word(pdev, ATIIXP_IDE_MWDMA_TIMING, mwdma_timing_data);
+ }
+ /*
+ * We must now look at the PIO mode situation. We may need to
+ * adjust the PIO mode to keep the timings acceptable
+ */
+ if (adev->dma_mode >= XFER_MW_DMA_2)
+ wanted_pio = 4;
+ else if (adev->dma_mode == XFER_MW_DMA_1)
+ wanted_pio = 3;
+ else if (adev->dma_mode == XFER_MW_DMA_0)
+ wanted_pio = 0;
+ else BUG();
+
+ if (adev->pio_mode != wanted_pio)
+ atiixp_set_pio_timing(ap, adev, wanted_pio);
+}
+
+/**
+ * atiixp_bmdma_start - DMA start callback
+ * @qc: Command in progress
+ *
+ * When DMA begins we need to ensure that the UDMA control
+ * register for the channel is correctly set.
+ */
+
+static void atiixp_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = (2 * ap->port_no) + adev->devno;
+ u16 tmp16;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+ if (adev->dma_mode >= XFER_UDMA_0)
+ tmp16 |= (1 << dn);
+ else
+ tmp16 &= ~(1 << dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * atiixp_dma_stop - DMA stop callback
+ * @qc: Command in progress
+ *
+ * DMA has completed. Clear the UDMA flag as the next operations will
+ * be PIO ones not UDMA data transfer.
+ */
+
+static void atiixp_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int dn = (2 * ap->port_no) + qc->dev->devno;
+ u16 tmp16;
+
+ pci_read_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, &tmp16);
+ tmp16 &= ~(1 << dn);
+ pci_write_config_word(pdev, ATIIXP_IDE_UDMA_CONTROL, tmp16);
+ ata_bmdma_stop(qc);
+}
+
+static struct scsi_host_template atiixp_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations atiixp_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = atiixp_set_piomode,
+ .set_dmamode = atiixp_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = atiixp_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = atiixp_bmdma_start,
+ .bmdma_stop = atiixp_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &atiixp_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x06, /* No MWDMA0 support */
+ .udma_mask = 0x3F,
+ .port_ops = &atiixp_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id atiixp[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
+ { 0, },
+};
+
+static struct pci_driver atiixp_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = atiixp,
+ .probe = atiixp_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init atiixp_init(void)
+{
+ return pci_register_driver(&atiixp_pci_driver);
+}
+
+
+static void __exit atiixp_exit(void)
+{
+ pci_unregister_driver(&atiixp_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, atiixp);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(atiixp_init);
+module_exit(atiixp_exit);
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
new file mode 100644
index 00000000000..e92b0ef43ec
--- /dev/null
+++ b/drivers/ata/pata_cmd64x.c
@@ -0,0 +1,505 @@
+/*
+ * pata_cmd64x.c - ATI PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based upon
+ * linux/drivers/ide/pci/cmd64x.c Version 1.30 Sept 10, 2002
+ *
+ * cmd64x.c: Enable interrupts at initialization time on Ultra/PCI machines.
+ * Note, this driver is not used at all on other systems because
+ * there the "BIOS" has done all of the following already.
+ * Due to massive hardware bugs, UltraDMA is only supported
+ * on the 646U2 and not on the 646U.
+ *
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 David S. Miller (davem@redhat.com)
+ *
+ * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
+ *
+ * TODO
+ * Testing work
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cmd64x"
+#define DRV_VERSION "0.2.1"
+
+/*
+ * CMD64x specific registers definition.
+ */
+
+enum {
+ CFR = 0x50,
+ CFR_INTR_CH0 = 0x02,
+ CNTRL = 0x51,
+ CNTRL_DIS_RA0 = 0x40,
+ CNTRL_DIS_RA1 = 0x80,
+ CNTRL_ENA_2ND = 0x08,
+ CMDTIM = 0x52,
+ ARTTIM0 = 0x53,
+ DRWTIM0 = 0x54,
+ ARTTIM1 = 0x55,
+ DRWTIM1 = 0x56,
+ ARTTIM23 = 0x57,
+ ARTTIM23_DIS_RA2 = 0x04,
+ ARTTIM23_DIS_RA3 = 0x08,
+ ARTTIM23_INTR_CH1 = 0x10,
+ ARTTIM2 = 0x57,
+ ARTTIM3 = 0x57,
+ DRWTIM23 = 0x58,
+ DRWTIM2 = 0x58,
+ BRST = 0x59,
+ DRWTIM3 = 0x5b,
+ BMIDECR0 = 0x70,
+ MRDMODE = 0x71,
+ MRDMODE_INTR_CH0 = 0x04,
+ MRDMODE_INTR_CH1 = 0x08,
+ MRDMODE_BLK_CH0 = 0x10,
+ MRDMODE_BLK_CH1 = 0x20,
+ BMIDESR0 = 0x72,
+ UDIDETCR0 = 0x73,
+ DTPR0 = 0x74,
+ BMIDECR1 = 0x78,
+ BMIDECSR = 0x79,
+ BMIDESR1 = 0x7A,
+ UDIDETCR1 = 0x7B,
+ DTPR1 = 0x7C
+};
+
+static int cmd64x_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static int cmd648_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 r;
+
+ /* Check cable detect bits */
+ pci_read_config_byte(pdev, BMIDECSR, &r);
+ if (r & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+
+ return ata_std_prereset(ap);
+}
+
+static void cmd64x_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, cmd64x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+static void cmd648_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, cmd648_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * cmd64x_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup.
+ */
+
+static void cmd64x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_timing t;
+ const unsigned long T = 1000000 / 33;
+ const u8 setup_data[] = { 0x40, 0x40, 0x40, 0x80, 0x00 };
+
+ u8 reg;
+
+ /* Port layout is not logical so use a table */
+ const u8 arttim_port[2][2] = {
+ { ARTTIM0, ARTTIM1 },
+ { ARTTIM23, ARTTIM23 }
+ };
+ const u8 drwtim_port[2][2] = {
+ { DRWTIM0, DRWTIM1 },
+ { DRWTIM2, DRWTIM3 }
+ };
+
+ int arttim = arttim_port[ap->port_no][adev->devno];
+ int drwtim = drwtim_port[ap->port_no][adev->devno];
+
+
+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 0) < 0) {
+ printk(KERN_ERR DRV_NAME ": mode computation failed.\n");
+ return;
+ }
+ if (ap->port_no) {
+ /* Slave has shared address setup */
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (pair) {
+ struct ata_timing tp;
+ ata_timing_compute(pair, pair->pio_mode, &tp, T, 0);
+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ }
+ }
+
+ printk(KERN_DEBUG DRV_NAME ": active %d recovery %d setup %d.\n",
+ t.active, t.recover, t.setup);
+ if (t.recover > 16) {
+ t.active += t.recover - 16;
+ t.recover = 16;
+ }
+ if (t.active > 16)
+ t.active = 16;
+
+ /* Now convert the clocks into values we can actually stuff into
+ the chip */
+
+ if (t.recover > 1)
+ t.recover--;
+ else
+ t.recover = 15;
+
+ if (t.setup > 4)
+ t.setup = 0xC0;
+ else
+ t.setup = setup_data[t.setup];
+
+ t.active &= 0x0F; /* 0 = 16 */
+
+ /* Load setup timing */
+ pci_read_config_byte(pdev, arttim, &reg);
+ reg &= 0x3F;
+ reg |= t.setup;
+ pci_write_config_byte(pdev, arttim, reg);
+
+ /* Load active/recovery */
+ pci_write_config_byte(pdev, drwtim, (t.active << 4) | t.recover);
+}
+
+/**
+ * cmd64x_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup.
+ */
+
+static void cmd64x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 udma_data[] = {
+ 0x31, 0x21, 0x11, 0x25, 0x15, 0x05
+ };
+ static const u8 mwdma_data[] = {
+ 0x30, 0x20, 0x10
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 regU, regD;
+
+ int pciU = UDIDETCR0 + 8 * ap->port_no;
+ int pciD = BMIDESR0 + 8 * ap->port_no;
+ int shift = 2 * adev->devno;
+
+ pci_read_config_byte(pdev, pciD, &regD);
+ pci_read_config_byte(pdev, pciU, &regU);
+
+ regD &= ~(0x20 << shift);
+ regU &= ~(0x35 << shift);
+
+ if (adev->dma_mode >= XFER_UDMA_0)
+ regU |= udma_data[adev->dma_mode - XFER_UDMA_0] << shift;
+ else
+ regD |= mwdma_data[adev->dma_mode - XFER_MW_DMA_0] << shift;
+
+ regD |= 0x20 << adev->devno;
+
+ pci_write_config_byte(pdev, pciU, regU);
+ pci_write_config_byte(pdev, pciD, regD);
+}
+
+/**
+ * cmd648_dma_stop - DMA stop callback
+ * @qc: Command in progress
+ *
+ * DMA has completed.
+ */
+
+static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 dma_intr;
+ int dma_reg = ap->port_no ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0;
+ int dma_mask = ap->port_no ? ARTTIM2 : CFR;
+
+ ata_bmdma_stop(qc);
+
+ pci_read_config_byte(pdev, dma_reg, &dma_intr);
+ pci_write_config_byte(pdev, dma_reg, dma_intr | dma_mask);
+}
+
+/**
+ * cmd646r1_dma_stop - DMA stop callback
+ * @qc: Command in progress
+ *
+ * Stub for now while investigating the r1 quirk in the old driver.
+ */
+
+static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+}
+
+static struct scsi_host_template cmd64x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cmd64x_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd64x_set_piomode,
+ .set_dmamode = cmd64x_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cmd64x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations cmd646r1_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd64x_set_piomode,
+ .set_dmamode = cmd64x_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cmd64x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = cmd646r1_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations cmd648_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cmd64x_set_piomode,
+ .set_dmamode = cmd64x_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cmd648_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = cmd648_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ u32 class_rev;
+
+ static struct ata_port_info cmd_info[6] = {
+ { /* CMD 643 - no UDMA */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cmd64x_port_ops
+ },
+ { /* CMD 646 with broken UDMA */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cmd64x_port_ops
+ },
+ { /* CMD 646 with working UDMA */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA1,
+ .port_ops = &cmd64x_port_ops
+ },
+ { /* CMD 646 rev 1 */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cmd646r1_port_ops
+ },
+ { /* CMD 648 */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &cmd648_port_ops
+ },
+ { /* CMD 649 */
+ .sht = &cmd64x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA3,
+ .port_ops = &cmd648_port_ops
+ }
+ };
+ static struct ata_port_info *port_info[2], *info;
+ u8 mrdmode;
+
+ info = &cmd_info[id->driver_data];
+
+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ if (id->driver_data == 0) /* 643 */
+ ata_pci_clear_simplex(pdev);
+
+ if (pdev->device == PCI_DEVICE_ID_CMD_646) {
+ /* Does UDMA work ? */
+ if (class_rev > 4)
+ info = &cmd_info[2];
+ /* Early rev with other problems ? */
+ else if (class_rev == 1)
+ info = &cmd_info[3];
+ }
+
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(pdev, MRDMODE, &mrdmode);
+ mrdmode &= ~ 0x30; /* IRQ set up */
+ mrdmode |= 0x02; /* Memory read line enable */
+ pci_write_config_byte(pdev, MRDMODE, mrdmode);
+
+ /* Force PIO 0 here.. */
+
+ /* PPC specific fixup copied from old driver */
+#ifdef CONFIG_PPC
+ pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
+#endif
+
+ port_info[0] = port_info[1] = info;
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static struct pci_device_id cmd64x[] = {
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { 0, },
+};
+
+static struct pci_driver cmd64x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cmd64x,
+ .probe = cmd64x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cmd64x_init(void)
+{
+ return pci_register_driver(&cmd64x_pci_driver);
+}
+
+
+static void __exit cmd64x_exit(void)
+{
+ pci_unregister_driver(&cmd64x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cmd64x);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cmd64x_init);
+module_exit(cmd64x_exit);
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
new file mode 100644
index 00000000000..a6c6cebd0da
--- /dev/null
+++ b/drivers/ata/pata_cs5520.c
@@ -0,0 +1,334 @@
+/*
+ * IDE tuning and bus mastering support for the CS5510/CS5520
+ * chipsets
+ *
+ * The CS5510/CS5520 are slightly unusual devices. Unlike the
+ * typical IDE controllers they do bus mastering with the drive in
+ * PIO mode and smarter silicon.
+ *
+ * The practical upshot of this is that we must always tune the
+ * drive for the right PIO mode. We must also ignore all the blacklists
+ * and the drive bus mastering DMA information. Also to confuse matters
+ * further we can do DMA on PIO only drives.
+ *
+ * DMA on the 5510 also requires we disable_hlt() during DMA on early
+ * revisions.
+ *
+ * *** This driver is strictly experimental ***
+ *
+ * (c) Copyright Red Hat Inc 2002
+ *
+ * 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, 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.
+ *
+ * Documentation:
+ * Not publically available.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cs5520"
+#define DRV_VERSION "0.6.2"
+
+struct pio_clocks
+{
+ int address;
+ int assert;
+ int recovery;
+};
+
+static const struct pio_clocks cs5520_pio_clocks[]={
+ {3, 6, 11},
+ {2, 5, 6},
+ {1, 4, 3},
+ {1, 3, 2},
+ {1, 2, 1}
+};
+
+/**
+ * cs5520_set_timings - program PIO timings
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Program the PIO mode timings for the controller according to the pio
+ * clocking table.
+ */
+
+static void cs5520_set_timings(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int slave = adev->devno;
+
+ pio -= XFER_PIO_0;
+
+ /* Channel command timing */
+ pci_write_config_byte(pdev, 0x62 + ap->port_no,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+ /* FIXME: should these use address ? */
+ /* Read command timing */
+ pci_write_config_byte(pdev, 0x64 + 4*ap->port_no + slave,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+ /* Write command timing */
+ pci_write_config_byte(pdev, 0x66 + 4*ap->port_no + slave,
+ (cs5520_pio_clocks[pio].recovery << 4) |
+ (cs5520_pio_clocks[pio].assert));
+}
+
+/**
+ * cs5520_enable_dma - turn on DMA bits
+ *
+ * Turn on the DMA bits for this disk. Needed because the BIOS probably
+ * has not done the work for us. Belongs in the core SATA code.
+ */
+
+static void cs5520_enable_dma(struct ata_port *ap, struct ata_device *adev)
+{
+ /* Set the DMA enable/disable flag */
+ u8 reg = inb(ap->ioaddr.bmdma_addr + 0x02);
+ reg |= 1<<(adev->devno + 5);
+ outb(reg, ap->ioaddr.bmdma_addr + 0x02);
+}
+
+/**
+ * cs5520_set_dmamode - program DMA timings
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Program the DMA mode timings for the controller according to the pio
+ * clocking table. Note that this device sets the DMA timings to PIO
+ * mode values. This may seem bizarre but the 5520 architecture talks
+ * PIO mode to the disk and DMA mode to the controller so the underlying
+ * transfers are PIO timed.
+ */
+
+static void cs5520_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const int dma_xlate[3] = { XFER_PIO_0, XFER_PIO_3, XFER_PIO_4 };
+ cs5520_set_timings(ap, adev, dma_xlate[adev->dma_mode]);
+ cs5520_enable_dma(ap, adev);
+}
+
+/**
+ * cs5520_set_piomode - program PIO timings
+ * @ap: ATA port
+ * @adev: ATA device
+ *
+ * Program the PIO mode timings for the controller according to the pio
+ * clocking table. We know pio_mode will equal dma_mode because of the
+ * CS5520 architecture. At least once we turned DMA on and wrote a
+ * mode setter.
+ */
+
+static void cs5520_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ cs5520_set_timings(ap, adev, adev->pio_mode);
+}
+
+
+static int cs5520_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void cs5520_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, cs5520_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+static struct scsi_host_template cs5520_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5520_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cs5520_set_piomode,
+ .set_dmamode = cs5520_set_dmamode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cs5520_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ u8 pcicfg;
+ static struct ata_probe_ent probe[2];
+ int ports = 0;
+
+ /* IDE port enable bits */
+ pci_read_config_byte(dev, 0x60, &pcicfg);
+
+ /* Check if the ATA ports are enabled */
+ if ((pcicfg & 3) == 0)
+ return -ENODEV;
+
+ if ((pcicfg & 0x40) == 0) {
+ printk(KERN_WARNING DRV_NAME ": DMA mode disabled. Enabling.\n");
+ pci_write_config_byte(dev, 0x60, pcicfg | 0x40);
+ }
+
+ /* Perform set up for DMA */
+ if (pci_enable_device_bars(dev, 1<<2)) {
+ printk(KERN_ERR DRV_NAME ": unable to configure BAR2.\n");
+ return -ENODEV;
+ }
+ pci_set_master(dev);
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR DRV_NAME ": unable to configure DMA mask.\n");
+ return -ENODEV;
+ }
+ if (pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) {
+ printk(KERN_ERR DRV_NAME ": unable to configure consistent DMA mask.\n");
+ return -ENODEV;
+ }
+
+ /* We have to do our own plumbing as the PCI setup for this
+ chipset is non-standard so we can't punt to the libata code */
+
+ INIT_LIST_HEAD(&probe[0].node);
+ probe[0].dev = pci_dev_to_dev(dev);
+ probe[0].port_ops = &cs5520_port_ops;
+ probe[0].sht = &cs5520_sht;
+ probe[0].pio_mask = 0x1F;
+ probe[0].mwdma_mask = id->driver_data;
+ probe[0].irq = 14;
+ probe[0].irq_flags = 0;
+ probe[0].port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
+ probe[0].n_ports = 1;
+ probe[0].port[0].cmd_addr = 0x1F0;
+ probe[0].port[0].ctl_addr = 0x3F6;
+ probe[0].port[0].altstatus_addr = 0x3F6;
+ probe[0].port[0].bmdma_addr = pci_resource_start(dev, 2);
+
+ /* The secondary lurks at different addresses but is otherwise
+ the same beastie */
+
+ probe[1] = probe[0];
+ INIT_LIST_HEAD(&probe[1].node);
+ probe[1].irq = 15;
+ probe[1].port[0].cmd_addr = 0x170;
+ probe[1].port[0].ctl_addr = 0x376;
+ probe[1].port[0].altstatus_addr = 0x376;
+ probe[1].port[0].bmdma_addr = pci_resource_start(dev, 2) + 8;
+
+ /* Let libata fill in the port details */
+ ata_std_ports(&probe[0].port[0]);
+ ata_std_ports(&probe[1].port[0]);
+
+ /* Now add the ports that are active */
+ if (pcicfg & 1)
+ ports += ata_device_add(&probe[0]);
+ if (pcicfg & 2)
+ ports += ata_device_add(&probe[1]);
+ if (ports)
+ return 0;
+ return -ENODEV;
+}
+
+/**
+ * cs5520_remove_one - device unload
+ * @pdev: PCI device being removed
+ *
+ * Handle an unplug/unload event for a PCI device. Unload the
+ * PCI driver but do not use the default handler as we manage
+ * resources ourself and *MUST NOT* disable the device as it has
+ * other functions.
+ */
+
+static void __devexit cs5520_remove_one(struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+}
+
+/* For now keep DMA off. We can set it for all but A rev CS5510 once the
+ core ATA code can handle it */
+
+static struct pci_device_id pata_cs5520[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+ { 0, },
+};
+
+static struct pci_driver cs5520_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pata_cs5520,
+ .probe = cs5520_init_one,
+ .remove = cs5520_remove_one
+};
+
+
+static int __init cs5520_init(void)
+{
+ return pci_register_driver(&cs5520_pci_driver);
+}
+
+static void __exit cs5520_exit(void)
+{
+ pci_unregister_driver(&cs5520_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Cyrix CS5510/5520");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pata_cs5520);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cs5520_init);
+module_exit(cs5520_exit);
+
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
new file mode 100644
index 00000000000..7bba4d954e9
--- /dev/null
+++ b/drivers/ata/pata_cs5530.c
@@ -0,0 +1,387 @@
+/*
+ * pata-cs5530.c - CS5530 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon cs5530.c by Mark Lord.
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Available from AMD web site.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_cs5530"
+#define DRV_VERSION "0.6"
+
+/**
+ * cs5530_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. This is fairly simple on the CS5530
+ * chips.
+ */
+
+static void cs5530_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const unsigned int cs5530_pio_timings[2][5] = {
+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010},
+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}
+ };
+ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ u32 tuning;
+ int format;
+
+ /* Find out which table to use */
+ tuning = inl(base + 0x04);
+ format = (tuning & 0x80000000UL) ? 1 : 0;
+
+ /* Now load the right timing register */
+ if (adev->devno)
+ base += 0x08;
+
+ outl(cs5530_pio_timings[format][adev->pio_mode - XFER_PIO_0], base);
+}
+
+/**
+ * cs5530_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * We cannot mix MWDMA and UDMA without reloading timings each switch
+ * master to slave. We track the last DMA setup in order to minimise
+ * reloads.
+ */
+
+static void cs5530_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned long base = ( ap->ioaddr.bmdma_addr & ~0x0F) + 0x20 + 0x10 * ap->port_no;
+ u32 tuning, timing = 0;
+ u8 reg;
+
+ /* Find out which table to use */
+ tuning = inl(base + 0x04);
+
+ switch(adev->dma_mode) {
+ case XFER_UDMA_0:
+ timing = 0x00921250;break;
+ case XFER_UDMA_1:
+ timing = 0x00911140;break;
+ case XFER_UDMA_2:
+ timing = 0x00911030;break;
+ case XFER_MW_DMA_0:
+ timing = 0x00077771;break;
+ case XFER_MW_DMA_1:
+ timing = 0x00012121;break;
+ case XFER_MW_DMA_2:
+ timing = 0x00002020;break;
+ default:
+ BUG();
+ }
+ /* Merge in the PIO format bit */
+ timing |= (tuning & 0x80000000UL);
+ if (adev->devno == 0) /* Master */
+ outl(timing, base + 0x04);
+ else {
+ if (timing & 0x00100000)
+ tuning |= 0x00100000; /* UDMA for both */
+ else
+ tuning &= ~0x00100000; /* MWDMA for both */
+ outl(tuning, base + 0x04);
+ outl(timing, base + 0x0C);
+ }
+
+ /* Set the DMA capable bit in the BMDMA area */
+ reg = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+ reg |= (1 << (5 + adev->devno));
+ outb(reg, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+
+ /* Remember the last DMA setup we did */
+
+ ap->private_data = adev;
+}
+
+/**
+ * cs5530_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Specifically we have a problem that there is only
+ * one MWDMA/UDMA bit.
+ */
+
+static unsigned int cs5530_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_device *prev = ap->private_data;
+
+ /* See if the DMA settings could be wrong */
+ if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
+ /* Maybe, but do the channels match MWDMA/UDMA ? */
+ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
+ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
+ /* Switch the mode bits */
+ cs5530_set_dmamode(ap, adev);
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static int cs5530_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void cs5530_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, cs5530_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+static struct scsi_host_template cs5530_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5530_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cs5530_set_piomode,
+ .set_dmamode = cs5530_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cs5530_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = cs5530_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct dmi_system_id palmax_dmi_table[] = {
+ {
+ .ident = "Palmax PD1100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Cyrix"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Caddis"),
+ },
+ },
+ { }
+};
+
+static int cs5530_is_palmax(void)
+{
+ if (dmi_check_system(palmax_dmi_table)) {
+ printk(KERN_INFO "Palmax PD1100: Disabling DMA on docking port.\n");
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * cs5530_init_one - Initialise a CS5530
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Install a driver for the newly found CS5530 companion chip. Most of
+ * this is just housekeeping. We have to set the chip up correctly and
+ * turn off various bits of emulation magic.
+ */
+
+static int cs5530_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ int compiler_warning_pointless_fix;
+ struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
+ static struct ata_port_info info = {
+ .sht = &cs5530_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &cs5530_port_ops
+ };
+ /* The docking connector doesn't do UDMA, and it seems not MWDMA */
+ static struct ata_port_info info_palmax_secondary = {
+ .sht = &cs5530_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &cs5530_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ dev = NULL;
+ while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
+ switch (dev->device) {
+ case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
+ master_0 = pci_dev_get(dev);
+ break;
+ case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
+ cs5530_0 = pci_dev_get(dev);
+ break;
+ }
+ }
+ if (!master_0) {
+ printk(KERN_ERR DRV_NAME ": unable to locate PCI MASTER function\n");
+ goto fail_put;
+ }
+ if (!cs5530_0) {
+ printk(KERN_ERR DRV_NAME ": unable to locate CS5530 LEGACY function\n");
+ goto fail_put;
+ }
+
+ pci_set_master(cs5530_0);
+ compiler_warning_pointless_fix = pci_set_mwi(cs5530_0);
+
+ /*
+ * Set PCI CacheLineSize to 16-bytes:
+ * --> Write 0x04 into 8-bit PCI CACHELINESIZE reg of function 0 of the cs5530
+ *
+ * Note: This value is constant because the 5530 is only a Geode companion
+ */
+
+ pci_write_config_byte(cs5530_0, PCI_CACHE_LINE_SIZE, 0x04);
+
+ /*
+ * Disable trapping of UDMA register accesses (Win98 hack):
+ * --> Write 0x5006 into 16-bit reg at offset 0xd0 of function 0 of the cs5530
+ */
+
+ pci_write_config_word(cs5530_0, 0xd0, 0x5006);
+
+ /*
+ * Bit-1 at 0x40 enables MemoryWriteAndInvalidate on internal X-bus:
+ * The other settings are what is necessary to get the register
+ * into a sane state for IDE DMA operation.
+ */
+
+ pci_write_config_byte(master_0, 0x40, 0x1e);
+
+ /*
+ * Set max PCI burst size (16-bytes seems to work best):
+ * 16bytes: set bit-1 at 0x41 (reg value of 0x16)
+ * all others: clear bit-1 at 0x41, and do:
+ * 128bytes: OR 0x00 at 0x41
+ * 256bytes: OR 0x04 at 0x41
+ * 512bytes: OR 0x08 at 0x41
+ * 1024bytes: OR 0x0c at 0x41
+ */
+
+ pci_write_config_byte(master_0, 0x41, 0x14);
+
+ /*
+ * These settings are necessary to get the chip
+ * into a sane state for IDE DMA operation.
+ */
+
+ pci_write_config_byte(master_0, 0x42, 0x00);
+ pci_write_config_byte(master_0, 0x43, 0xc1);
+
+ pci_dev_put(master_0);
+ pci_dev_put(cs5530_0);
+
+ if (cs5530_is_palmax())
+ port_info[1] = &info_palmax_secondary;
+
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+
+fail_put:
+ if (master_0)
+ pci_dev_put(master_0);
+ if (cs5530_0)
+ pci_dev_put(cs5530_0);
+ return -ENODEV;
+}
+
+static struct pci_device_id cs5530[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
+ { 0, },
+};
+
+static struct pci_driver cs5530_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cs5530,
+ .probe = cs5530_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cs5530_init(void)
+{
+ return pci_register_driver(&cs5530_pci_driver);
+}
+
+
+static void __exit cs5530_exit(void)
+{
+ pci_unregister_driver(&cs5530_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cs5530);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cs5530_init);
+module_exit(cs5530_exit);
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
new file mode 100644
index 00000000000..d64fcdceaf0
--- /dev/null
+++ b/drivers/ata/pata_cs5535.c
@@ -0,0 +1,291 @@
+/*
+ * pata-cs5535.c - CS5535 PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon cs5535.c from AMD <Jens.Altmann@amd.com> as cleaned up and
+ * made readable and Linux style by Wolfgang Zuleger <wolfgang.zuleger@gmx.de
+ * and Alexander Kiausch <alex.kiausch@t-online.de>
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Available from AMD web site.
+ * TODO
+ * Review errata to see if serializing is neccessary
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/msr.h>
+
+#define DRV_NAME "cs5535"
+#define DRV_VERSION "0.2.10"
+
+/*
+ * The Geode (Aka Athlon GX now) uses an internal MSR based
+ * bus system for control. Demented but there you go.
+ */
+
+#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
+
+#define CS5535_BAD_PIO(timings) ( (timings&~0x80000000UL)==0x00009172 )
+
+/**
+ * cs5535_pre_reset - detect cable type
+ * @ap: Port to detect on
+ *
+ * Perform cable detection for ATA66 capable cable. Return a libata
+ * cable type.
+ */
+
+static int cs5535_pre_reset(struct ata_port *ap)
+{
+ u8 cable;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, CS5535_CABLE_DETECT, &cable);
+ if (cable & 1)
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * cs5535_error_handler - reset/probe
+ * @ap: Port to reset
+ *
+ * Reset and configure a port
+ */
+
+static void cs5535_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, cs5535_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * cs5535_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. The CS5535 is pretty clean about all this
+ */
+
+static void cs5535_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u16 pio_timings[5] = {
+ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+ };
+ static const u16 pio_cmd_timings[5] = {
+ 0xF7F4, 0x53F3, 0x13F1, 0x5131, 0x1131
+ };
+ u32 reg, dummy;
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ int mode = adev->pio_mode - XFER_PIO_0;
+ int cmdmode = mode;
+
+ /* Command timing has to be for the lowest of the pair of devices */
+ if (pair) {
+ int pairmode = pair->pio_mode - XFER_PIO_0;
+ cmdmode = min(mode, pairmode);
+ /* Write the other drive timing register if it changed */
+ if (cmdmode < pairmode)
+ wrmsr(ATAC_CH0D0_PIO + 2 * pair->devno,
+ pio_cmd_timings[cmdmode] << 16 | pio_timings[pairmode], 0);
+ }
+ /* Write the drive timing register */
+ wrmsr(ATAC_CH0D0_PIO + 2 * adev->devno,
+ pio_cmd_timings[cmdmode] << 16 | pio_timings[mode], 0);
+
+ /* Set the PIO "format 1" bit in the DMA timing register */
+ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
+ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg | 0x80000000UL, 0);
+}
+
+/**
+ * cs5535_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ */
+
+static void cs5535_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u32 udma_timings[5] = {
+ 0x7F7436A1, 0x7F733481, 0x7F723261, 0x7F713161, 0x7F703061
+ };
+ static const u32 mwdma_timings[3] = {
+ 0x7F0FFFF3, 0x7F035352, 0x7F024241
+ };
+ u32 reg, dummy;
+ int mode = adev->dma_mode;
+
+ rdmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, dummy);
+ reg &= 0x80000000UL;
+ if (mode >= XFER_UDMA_0)
+ reg |= udma_timings[mode - XFER_UDMA_0];
+ else
+ reg |= mwdma_timings[mode - XFER_MW_DMA_0];
+ wrmsr(ATAC_CH0D0_DMA + 2 * adev->devno, reg, 0);
+}
+
+static struct scsi_host_template cs5535_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cs5535_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cs5535_set_piomode,
+ .set_dmamode = cs5535_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cs5535_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * cs5535_init_one - Initialise a CS5530
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Install a driver for the newly found CS5530 companion chip. Most of
+ * this is just housekeeping. We have to set the chip up correctly and
+ * turn off various bits of emulation magic.
+ */
+
+static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &cs5535_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &cs5535_port_ops
+ };
+ struct ata_port_info *ports[1] = { &info };
+
+ u32 timings, dummy;
+
+ /* Check the BIOS set the initial timing clock. If not set the
+ timings for PIO0 */
+ rdmsr(ATAC_CH0D0_PIO, timings, dummy);
+ if (CS5535_BAD_PIO(timings))
+ wrmsr(ATAC_CH0D0_PIO, 0xF7F4F7F4UL, 0);
+ rdmsr(ATAC_CH0D1_PIO, timings, dummy);
+ if (CS5535_BAD_PIO(timings))
+ wrmsr(ATAC_CH0D1_PIO, 0xF7F4F7F4UL, 0);
+ return ata_pci_init_one(dev, ports, 1);
+}
+
+static struct pci_device_id cs5535[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), },
+ { 0, },
+};
+
+static struct pci_driver cs5535_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cs5535,
+ .probe = cs5535_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cs5535_init(void)
+{
+ return pci_register_driver(&cs5535_pci_driver);
+}
+
+
+static void __exit cs5535_exit(void)
+{
+ pci_unregister_driver(&cs5535_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
+MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cs5535);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cs5535_init);
+module_exit(cs5535_exit);
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
new file mode 100644
index 00000000000..dfa5ac53904
--- /dev/null
+++ b/drivers/ata/pata_cypress.c
@@ -0,0 +1,227 @@
+/*
+ * pata_cypress.c - Cypress PATA for new ATA layer
+ * (C) 2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based heavily on
+ * linux/drivers/ide/pci/cy82c693.c Version 0.40 Sep. 10, 2002
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_cypress"
+#define DRV_VERSION "0.1.2"
+
+/* here are the offset definitions for the registers */
+
+enum {
+ CY82_IDE_CMDREG = 0x04,
+ CY82_IDE_ADDRSETUP = 0x48,
+ CY82_IDE_MASTER_IOR = 0x4C,
+ CY82_IDE_MASTER_IOW = 0x4D,
+ CY82_IDE_SLAVE_IOR = 0x4E,
+ CY82_IDE_SLAVE_IOW = 0x4F,
+ CY82_IDE_MASTER_8BIT = 0x50,
+ CY82_IDE_SLAVE_8BIT = 0x51,
+
+ CY82_INDEX_PORT = 0x22,
+ CY82_DATA_PORT = 0x23,
+
+ CY82_INDEX_CTRLREG1 = 0x01,
+ CY82_INDEX_CHANNEL0 = 0x30,
+ CY82_INDEX_CHANNEL1 = 0x31,
+ CY82_INDEX_TIMEOUT = 0x32
+};
+
+static int cy82c693_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+static void cy82c693_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, cy82c693_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * cy82c693_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup.
+ */
+
+static void cy82c693_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_timing t;
+ const unsigned long T = 1000000 / 33;
+ short time_16, time_8;
+ u32 addr;
+
+ if (ata_timing_compute(adev, adev->pio_mode, &t, T, 1) < 0) {
+ printk(KERN_ERR DRV_NAME ": mome computation failed.\n");
+ return;
+ }
+
+ time_16 = FIT(t.recover, 0, 15) | (FIT(t.active, 0, 15) << 4);
+ time_8 = FIT(t.act8b, 0, 15) | (FIT(t.rec8b, 0, 15) << 4);
+
+ if (adev->devno == 0) {
+ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
+
+ addr &= ~0x0F; /* Mask bits */
+ addr |= FIT(t.setup, 0, 15);
+
+ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
+ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOR, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_MASTER_IOW, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_MASTER_8BIT, time_8);
+ } else {
+ pci_read_config_dword(pdev, CY82_IDE_ADDRSETUP, &addr);
+
+ addr &= ~0xF0; /* Mask bits */
+ addr |= (FIT(t.setup, 0, 15) << 4);
+
+ pci_write_config_dword(pdev, CY82_IDE_ADDRSETUP, addr);
+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOR, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_IOW, time_16);
+ pci_write_config_byte(pdev, CY82_IDE_SLAVE_8BIT, time_8);
+ }
+}
+
+/**
+ * cy82c693_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup.
+ */
+
+static void cy82c693_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ int reg = CY82_INDEX_CHANNEL0 + ap->port_no;
+
+ /* Be afraid, be very afraid. Magic registers in low I/O space */
+ outb(reg, 0x22);
+ outb(adev->dma_mode - XFER_MW_DMA_0, 0x23);
+
+ /* 0x50 gives the best behaviour on the Alpha's using this chip */
+ outb(CY82_INDEX_TIMEOUT, 0x22);
+ outb(0x50, 0x23);
+}
+
+static struct scsi_host_template cy82c693_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations cy82c693_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = cy82c693_set_piomode,
+ .set_dmamode = cy82c693_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = cy82c693_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &cy82c693_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &cy82c693_port_ops
+ };
+ static struct ata_port_info *port_info[1] = { &info };
+
+ /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the
+ moment we don't handle the secondary. FIXME */
+
+ if (PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
+
+ return ata_pci_init_one(pdev, port_info, 1);
+}
+
+static struct pci_device_id cy82c693[] = {
+ { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+
+static struct pci_driver cy82c693_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = cy82c693,
+ .probe = cy82c693_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init cy82c693_init(void)
+{
+ return pci_register_driver(&cy82c693_pci_driver);
+}
+
+
+static void __exit cy82c693_exit(void)
+{
+ pci_unregister_driver(&cy82c693_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the CY82C693 PATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, cy82c693);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(cy82c693_init);
+module_exit(cy82c693_exit);
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
new file mode 100644
index 00000000000..95cd1ca181f
--- /dev/null
+++ b/drivers/ata/pata_efar.c
@@ -0,0 +1,338 @@
+/*
+ * pata_efar.c - EFAR PIIX clone controller driver
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * Some parts based on ata_piix.c by Jeff Garzik and others.
+ *
+ * The EFAR is a PIIX4 clone with UDMA66 support. Unlike the later
+ * Intel ICH controllers the EFAR widened the UDMA mode register bits
+ * and doesn't require the funky clock selection.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_efar"
+#define DRV_VERSION "0.4.2"
+
+/**
+ * efar_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the EFAR ATA interface. This is
+ * different to the PIIX arrangement
+ */
+
+static int efar_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits efar_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ pci_read_config_byte(pdev, 0x47, &tmp);
+ if (tmp & (2 >> ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * efar_probe_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void efar_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, efar_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * efar_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. The EFAR is a clone so very similar
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio > 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
+ control |= 2; /* IE enable */
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ /* Enable PPE, IE and TIME as appropriate */
+
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCF0;
+ idetm_data |= control;
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ } else {
+ int shift = 4 * ap->port_no;
+ u8 slave_data;
+
+ idetm_data &= 0xCC0F;
+ idetm_data |= (control << 4);
+
+ /* Slave timing in seperate register */
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= 0x0F << shift;
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << shift;
+ pci_write_config_byte(dev, 0x44, slave_data);
+ }
+
+ idetm_data |= 0x4000; /* Ensure SITRE is enabled */
+ pci_write_config_word(dev, idetm_port, idetm_data);
+}
+
+/**
+ * efar_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void efar_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 master_port = ap->port_no ? 0x42 : 0x40;
+ u16 master_data;
+ u8 speed = adev->dma_mode;
+ int devid = adev->devno + 2 * ap->port_no;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(dev, master_port, &master_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (speed >= XFER_UDMA_0) {
+ unsigned int udma = adev->dma_mode - XFER_UDMA_0;
+ u16 udma_timing;
+
+ udma_enable |= (1 << devid);
+
+ /* Load the UDMA mode number */
+ pci_read_config_word(dev, 0x4A, &udma_timing);
+ udma_timing &= ~(7 << (4 * devid));
+ udma_timing |= udma << (4 * devid);
+ pci_write_config_word(dev, 0x4A, udma_timing);
+ } else {
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ u8 slave_data;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ control = 3; /* IORDY|TIME1 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ if (adev->devno) { /* Slave */
+ master_data &= 0xFF4F; /* Mask out IORDY|TIME1|DMAONLY */
+ master_data |= control << 4;
+ pci_read_config_byte(dev, 0x44, &slave_data);
+ slave_data &= (0x0F + 0xE1 * ap->port_no);
+ /* Load the matching timing */
+ slave_data |= ((timings[pio][0] << 2) | timings[pio][1]) << (ap->port_no ? 4 : 0);
+ pci_write_config_byte(dev, 0x44, slave_data);
+ } else { /* Master */
+ master_data &= 0xCCF4; /* Mask out IORDY|TIME1|DMAONLY
+ and master timing bits */
+ master_data |= control;
+ master_data |=
+ (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ }
+ udma_enable &= ~(1 << devid);
+ pci_write_config_word(dev, master_port, master_data);
+ }
+ pci_write_config_byte(dev, 0x48, udma_enable);
+}
+
+static struct scsi_host_template efar_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations efar_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = efar_set_piomode,
+ .set_dmamode = efar_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = efar_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * efar_init_one - Register EFAR ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in efar_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &efar_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma1-2 */
+ .udma_mask = 0x0f, /* UDMA 66 */
+ .port_ops = &efar_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id efar_pci_tbl[] = {
+ { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, },
+ { } /* terminate list */
+};
+
+static struct pci_driver efar_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = efar_pci_tbl,
+ .probe = efar_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init efar_init(void)
+{
+ return pci_register_driver(&efar_pci_driver);
+}
+
+static void __exit efar_exit(void)
+{
+ pci_unregister_driver(&efar_pci_driver);
+}
+
+
+module_init(efar_init);
+module_exit(efar_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for EFAR PIIX clones");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, efar_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
new file mode 100644
index 00000000000..cf656ecbe50
--- /dev/null
+++ b/drivers/ata/pata_hpt366.c
@@ -0,0 +1,478 @@
+/*
+ * Libata driver for the highpoint 366 and 368 UDMA66 ATA controllers.
+ *
+ * This driver is heavily based upon:
+ *
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ *
+ * TODO
+ * Maybe PLL mode
+ * Look into engine reset on timeout errors. Should not be
+ * required.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt366"
+#define DRV_VERSION "0.5"
+
+struct hpt_clock {
+ u8 xfer_speed;
+ u32 timing;
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+
+static const struct hpt_clock hpt366_40[] = {
+ { XFER_UDMA_4, 0x900fd943 },
+ { XFER_UDMA_3, 0x900ad943 },
+ { XFER_UDMA_2, 0x900bd943 },
+ { XFER_UDMA_1, 0x9008d943 },
+ { XFER_UDMA_0, 0x9008d943 },
+
+ { XFER_MW_DMA_2, 0xa008d943 },
+ { XFER_MW_DMA_1, 0xa010d955 },
+ { XFER_MW_DMA_0, 0xa010d9fc },
+
+ { XFER_PIO_4, 0xc008d963 },
+ { XFER_PIO_3, 0xc010d974 },
+ { XFER_PIO_2, 0xc010d997 },
+ { XFER_PIO_1, 0xc010d9c7 },
+ { XFER_PIO_0, 0xc018d9d9 },
+ { 0, 0x0120d9d9 }
+};
+
+static const struct hpt_clock hpt366_33[] = {
+ { XFER_UDMA_4, 0x90c9a731 },
+ { XFER_UDMA_3, 0x90cfa731 },
+ { XFER_UDMA_2, 0x90caa731 },
+ { XFER_UDMA_1, 0x90cba731 },
+ { XFER_UDMA_0, 0x90c8a731 },
+
+ { XFER_MW_DMA_2, 0xa0c8a731 },
+ { XFER_MW_DMA_1, 0xa0c8a732 }, /* 0xa0c8a733 */
+ { XFER_MW_DMA_0, 0xa0c8a797 },
+
+ { XFER_PIO_4, 0xc0c8a731 },
+ { XFER_PIO_3, 0xc0c8a742 },
+ { XFER_PIO_2, 0xc0d0a753 },
+ { XFER_PIO_1, 0xc0d0a7a3 }, /* 0xc0d0a793 */
+ { XFER_PIO_0, 0xc0d0a7aa }, /* 0xc0d0a7a7 */
+ { 0, 0x0120a7a7 }
+};
+
+static const struct hpt_clock hpt366_25[] = {
+ { XFER_UDMA_4, 0x90c98521 },
+ { XFER_UDMA_3, 0x90cf8521 },
+ { XFER_UDMA_2, 0x90cf8521 },
+ { XFER_UDMA_1, 0x90cb8521 },
+ { XFER_UDMA_0, 0x90cb8521 },
+
+ { XFER_MW_DMA_2, 0xa0ca8521 },
+ { XFER_MW_DMA_1, 0xa0ca8532 },
+ { XFER_MW_DMA_0, 0xa0ca8575 },
+
+ { XFER_PIO_4, 0xc0ca8521 },
+ { XFER_PIO_3, 0xc0ca8532 },
+ { XFER_PIO_2, 0xc0ca8542 },
+ { XFER_PIO_1, 0xc0d08572 },
+ { XFER_PIO_0, 0xc0d08585 },
+ { 0, 0x01208585 }
+};
+
+static const char *bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+ "Maxtor 90510D4",
+ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ NULL
+};
+
+static const char *bad_ata66_4[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
+ "IC35L010AVER07-0",
+ "IC35L020AVER07-0",
+ "IC35L030AVER07-0",
+ "IC35L040AVER07-0",
+ "IC35L060AVER07-0",
+ "WDC AC310200R",
+ NULL
+};
+
+static const char *bad_ata66_3[] = {
+ "WDC AC310200R",
+ NULL
+};
+
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+{
+ unsigned char model_num[40];
+ char *s;
+ unsigned int len;
+ int i = 0;
+
+ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ s = &model_num[0];
+ len = strnlen(s, sizeof(model_num));
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+
+ while(list[i] != NULL) {
+ if (!strncmp(list[i], s, len)) {
+ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
+ modestr, list[i]);
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+/**
+ * hpt366_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long hpt366_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class == ATA_DEV_ATA) {
+ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
+ mask &= ~ATA_MASK_UDMA;
+ if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3))
+ mask &= ~(0x07 << ATA_SHIFT_UDMA);
+ if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
+ mask &= ~(0x0F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * hpt36x_find_mode - reset the hpt36x bus
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided.
+ */
+
+static u32 hpt36x_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = ap->host->private_data;
+
+ while(clocks->xfer_speed) {
+ if (clocks->xfer_speed == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+static int hpt36x_pre_reset(struct ata_port *ap)
+{
+ u8 ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt36x_error_handler - reset the hpt36x bus
+ * @ap: ATA port to reset
+ *
+ * Perform the reset handling for the 366/368
+ */
+
+static void hpt36x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, hpt36x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt366_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ if (fast & 0x80) {
+ fast &= ~0x80;
+ pci_write_config_byte(pdev, addr2, fast);
+ }
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt36x_find_mode(ap, adev->pio_mode);
+ mode &= ~0x8000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt366_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ if (fast & 0x80) {
+ fast &= ~0x80;
+ pci_write_config_byte(pdev, addr2, fast);
+ }
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt36x_find_mode(ap, adev->dma_mode);
+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+static struct scsi_host_template hpt36x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Configuration for HPT366/68
+ */
+
+static struct ata_port_operations hpt366_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt366_set_piomode,
+ .set_dmamode = hpt366_set_dmamode,
+ .mode_filter = hpt366_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt36x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * hpt36x_init_one - Initialise an HPT366/368
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Initialise an HPT36x device. There are some interesting complications
+ * here. Firstly the chip may report 366 and be one of several variants.
+ * Secondly all the timings depend on the clock for the chip which we must
+ * detect and look up
+ *
+ * This is the known chip mappings. It may be missing a couple of later
+ * releases.
+ *
+ * Chip version PCI Rev Notes
+ * HPT366 4 (HPT366) 0 UDMA66
+ * HPT366 4 (HPT366) 1 UDMA66
+ * HPT368 4 (HPT366) 2 UDMA66
+ * HPT37x/30x 4 (HPT366) 3+ Other driver
+ *
+ */
+
+static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_hpt366 = {
+ .sht = &hpt36x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &hpt366_port_ops
+ };
+ struct ata_port_info *port_info[2] = {&info_hpt366, &info_hpt366};
+
+ u32 class_rev;
+ u32 reg1;
+ u8 drive_fast;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ /* May be a later chip in disguise. Check */
+ /* Newer chips are not in the HPT36x driver. Ignore them */
+ if (class_rev > 2)
+ return -ENODEV;
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ pci_read_config_byte(dev, 0x51, &drive_fast);
+ if (drive_fast & 0x80)
+ pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
+
+ pci_read_config_dword(dev, 0x40, &reg1);
+
+ /* PCI clocking determines the ATA timing values to use */
+ /* info_hpt366 is safe against re-entry so we can scribble on it */
+ switch(reg1 & 0x700) {
+ case 5:
+ info_hpt366.private_data = &hpt366_40;
+ break;
+ case 9:
+ info_hpt366.private_data = &hpt366_25;
+ break;
+ default:
+ info_hpt366.private_data = &hpt366_33;
+ break;
+ }
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt36x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { 0, },
+};
+
+static struct pci_driver hpt36x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt36x,
+ .probe = hpt36x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt36x_init(void)
+{
+ return pci_register_driver(&hpt36x_pci_driver);
+}
+
+
+static void __exit hpt36x_exit(void)
+{
+ pci_unregister_driver(&hpt36x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT366/368");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt36x);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt36x_init);
+module_exit(hpt36x_exit);
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
new file mode 100644
index 00000000000..10318c0012e
--- /dev/null
+++ b/drivers/ata/pata_hpt37x.c
@@ -0,0 +1,1257 @@
+/*
+ * Libata driver for the highpoint 37x and 30x UDMA66 ATA controllers.
+ *
+ * This driver is heavily based upon:
+ *
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ * TODO
+ * PLL mode
+ * Look into engine reset on timeout errors. Should not be
+ * required.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt37x"
+#define DRV_VERSION "0.5"
+
+struct hpt_clock {
+ u8 xfer_speed;
+ u32 timing;
+};
+
+struct hpt_chip {
+ const char *name;
+ unsigned int base;
+ struct hpt_clock const *clocks[4];
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+
+/* from highpoint documentation. these are old values */
+static const struct hpt_clock hpt370_timings_33[] = {
+/* { XFER_UDMA_5, 0x1A85F442, 0x16454e31 }, */
+ { XFER_UDMA_5, 0x16454e31 },
+ { XFER_UDMA_4, 0x16454e31 },
+ { XFER_UDMA_3, 0x166d4e31 },
+ { XFER_UDMA_2, 0x16494e31 },
+ { XFER_UDMA_1, 0x164d4e31 },
+ { XFER_UDMA_0, 0x16514e31 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+static const struct hpt_clock hpt370_timings_66[] = {
+ { XFER_UDMA_5, 0x14846231 },
+ { XFER_UDMA_4, 0x14886231 },
+ { XFER_UDMA_3, 0x148c6231 },
+ { XFER_UDMA_2, 0x148c6231 },
+ { XFER_UDMA_1, 0x14906231 },
+ { XFER_UDMA_0, 0x14986231 },
+
+ { XFER_MW_DMA_2, 0x26514e21 },
+ { XFER_MW_DMA_1, 0x26514e33 },
+ { XFER_MW_DMA_0, 0x26514e97 },
+
+ { XFER_PIO_4, 0x06514e21 },
+ { XFER_PIO_3, 0x06514e22 },
+ { XFER_PIO_2, 0x06514e33 },
+ { XFER_PIO_1, 0x06914e43 },
+ { XFER_PIO_0, 0x06914e57 },
+ { 0, 0x06514e57 }
+};
+
+/* these are the current (4 sep 2001) timings from highpoint */
+static const struct hpt_clock hpt370a_timings_33[] = {
+ { XFER_UDMA_5, 0x12446231 },
+ { XFER_UDMA_4, 0x12446231 },
+ { XFER_UDMA_3, 0x126c6231 },
+ { XFER_UDMA_2, 0x12486231 },
+ { XFER_UDMA_1, 0x124c6233 },
+ { XFER_UDMA_0, 0x12506297 },
+
+ { XFER_MW_DMA_2, 0x22406c31 },
+ { XFER_MW_DMA_1, 0x22406c33 },
+ { XFER_MW_DMA_0, 0x22406c97 },
+
+ { XFER_PIO_4, 0x06414e31 },
+ { XFER_PIO_3, 0x06414e42 },
+ { XFER_PIO_2, 0x06414e53 },
+ { XFER_PIO_1, 0x06814e93 },
+ { XFER_PIO_0, 0x06814ea7 },
+ { 0, 0x06814ea7 }
+};
+
+/* 2x 33MHz timings */
+static const struct hpt_clock hpt370a_timings_66[] = {
+ { XFER_UDMA_5, 0x1488e673 },
+ { XFER_UDMA_4, 0x1488e673 },
+ { XFER_UDMA_3, 0x1498e673 },
+ { XFER_UDMA_2, 0x1490e673 },
+ { XFER_UDMA_1, 0x1498e677 },
+ { XFER_UDMA_0, 0x14a0e73f },
+
+ { XFER_MW_DMA_2, 0x2480fa73 },
+ { XFER_MW_DMA_1, 0x2480fa77 },
+ { XFER_MW_DMA_0, 0x2480fb3f },
+
+ { XFER_PIO_4, 0x0c82be73 },
+ { XFER_PIO_3, 0x0c82be95 },
+ { XFER_PIO_2, 0x0c82beb7 },
+ { XFER_PIO_1, 0x0d02bf37 },
+ { XFER_PIO_0, 0x0d02bf5f },
+ { 0, 0x0d02bf5f }
+};
+
+static const struct hpt_clock hpt370a_timings_50[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0ac1f48a }
+};
+
+static const struct hpt_clock hpt372_timings_33[] = {
+ { XFER_UDMA_6, 0x1c81dc62 },
+ { XFER_UDMA_5, 0x1c6ddc62 },
+ { XFER_UDMA_4, 0x1c8ddc62 },
+ { XFER_UDMA_3, 0x1c8edc62 }, /* checkme */
+ { XFER_UDMA_2, 0x1c91dc62 },
+ { XFER_UDMA_1, 0x1c9adc62 }, /* checkme */
+ { XFER_UDMA_0, 0x1c82dc62 }, /* checkme */
+
+ { XFER_MW_DMA_2, 0x2c829262 },
+ { XFER_MW_DMA_1, 0x2c829266 }, /* checkme */
+ { XFER_MW_DMA_0, 0x2c82922e }, /* checkme */
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d5e }
+};
+
+static const struct hpt_clock hpt372_timings_50[] = {
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x0a81f443 }
+};
+
+static const struct hpt_clock hpt372_timings_66[] = {
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1cae9c62 },
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2e },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d26 }
+};
+
+static const struct hpt_clock hpt374_timings_33[] = {
+ { XFER_UDMA_6, 0x12808242 },
+ { XFER_UDMA_5, 0x12848242 },
+ { XFER_UDMA_4, 0x12ac8242 },
+ { XFER_UDMA_3, 0x128c8242 },
+ { XFER_UDMA_2, 0x120c8242 },
+ { XFER_UDMA_1, 0x12148254 },
+ { XFER_UDMA_0, 0x121882ea },
+
+ { XFER_MW_DMA_2, 0x22808242 },
+ { XFER_MW_DMA_1, 0x22808254 },
+ { XFER_MW_DMA_0, 0x228082ea },
+
+ { XFER_PIO_4, 0x0a81f442 },
+ { XFER_PIO_3, 0x0a81f443 },
+ { XFER_PIO_2, 0x0a81f454 },
+ { XFER_PIO_1, 0x0ac1f465 },
+ { XFER_PIO_0, 0x0ac1f48a },
+ { 0, 0x06814e93 }
+};
+
+static const struct hpt_chip hpt370 = {
+ "HPT370",
+ 48,
+ {
+ hpt370_timings_33,
+ NULL,
+ NULL,
+ hpt370_timings_66
+ }
+};
+
+static const struct hpt_chip hpt370a = {
+ "HPT370A",
+ 48,
+ {
+ hpt370a_timings_33,
+ NULL,
+ hpt370a_timings_50,
+ hpt370a_timings_66
+ }
+};
+
+static const struct hpt_chip hpt372 = {
+ "HPT372",
+ 55,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt302 = {
+ "HPT302",
+ 66,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt371 = {
+ "HPT371",
+ 66,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt372a = {
+ "HPT372A",
+ 66,
+ {
+ hpt372_timings_33,
+ NULL,
+ hpt372_timings_50,
+ hpt372_timings_66
+ }
+};
+
+static const struct hpt_chip hpt374 = {
+ "HPT374",
+ 48,
+ {
+ hpt374_timings_33,
+ NULL,
+ NULL,
+ NULL
+ }
+};
+
+/**
+ * hpt37x_find_mode - reset the hpt37x bus
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided.
+ */
+
+static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = ap->host->private_data;
+
+ while(clocks->xfer_speed) {
+ if (clocks->xfer_speed == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr, const char *list[])
+{
+ unsigned char model_num[40];
+ char *s;
+ unsigned int len;
+ int i = 0;
+
+ ata_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
+ sizeof(model_num));
+ s = &model_num[0];
+ len = strnlen(s, sizeof(model_num));
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+
+ while(list[i] != NULL) {
+ if (!strncmp(list[i], s, len)) {
+ printk(KERN_WARNING DRV_NAME ": %s is not supported for %s.\n",
+ modestr, list[i]);
+ return 1;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static const char *bad_ata33[] = {
+ "Maxtor 92720U8", "Maxtor 92040U6", "Maxtor 91360U4", "Maxtor 91020U3", "Maxtor 90845U3", "Maxtor 90650U2",
+ "Maxtor 91360D8", "Maxtor 91190D7", "Maxtor 91020D6", "Maxtor 90845D5", "Maxtor 90680D4", "Maxtor 90510D3", "Maxtor 90340D2",
+ "Maxtor 91152D8", "Maxtor 91008D7", "Maxtor 90845D6", "Maxtor 90840D6", "Maxtor 90720D5", "Maxtor 90648D5", "Maxtor 90576D4",
+ "Maxtor 90510D4",
+ "Maxtor 90432D3", "Maxtor 90288D2", "Maxtor 90256D2",
+ "Maxtor 91000D8", "Maxtor 90910D8", "Maxtor 90875D7", "Maxtor 90840D7", "Maxtor 90750D6", "Maxtor 90625D5", "Maxtor 90500D4",
+ "Maxtor 91728D8", "Maxtor 91512D7", "Maxtor 91303D6", "Maxtor 91080D5", "Maxtor 90845D4", "Maxtor 90680D4", "Maxtor 90648D3", "Maxtor 90432D2",
+ NULL
+};
+
+static const char *bad_ata100_5[] = {
+ "IBM-DTLA-307075",
+ "IBM-DTLA-307060",
+ "IBM-DTLA-307045",
+ "IBM-DTLA-307030",
+ "IBM-DTLA-307020",
+ "IBM-DTLA-307015",
+ "IBM-DTLA-305040",
+ "IBM-DTLA-305030",
+ "IBM-DTLA-305020",
+ "IC35L010AVER07-0",
+ "IC35L020AVER07-0",
+ "IC35L030AVER07-0",
+ "IC35L040AVER07-0",
+ "IC35L060AVER07-0",
+ "WDC AC310200R",
+ NULL
+};
+
+/**
+ * hpt370_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long hpt370_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class != ATA_DEV_ATA) {
+ if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
+ mask &= ~ATA_MASK_UDMA;
+ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
+ mask &= ~(0x1F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * hpt370a_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Block UDMA on devices that cause trouble with this controller.
+ */
+
+static unsigned long hpt370a_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class != ATA_DEV_ATA) {
+ if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
+ mask &= ~ (0x1F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+/**
+ * hpt37x_pre_reset - reset the hpt37x bus
+ * @ap: ATA port to reset
+ *
+ * Perform the initial reset handling for the 370/372 and 374 func 0
+ */
+
+static int hpt37x_pre_reset(struct ata_port *ap)
+{
+ u8 scr2, ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5B, &scr2);
+ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+ /* Cable register now active */
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ /* Restore state */
+ pci_write_config_byte(pdev, 0x5B, scr2);
+
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ /* Reset the state machine */
+ pci_write_config_byte(pdev, 0x50, 0x37);
+ pci_write_config_byte(pdev, 0x54, 0x37);
+ udelay(100);
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt37x_error_handler - reset the hpt374
+ * @ap: ATA port to reset
+ *
+ * Perform probe for HPT37x, except for HPT374 channel 2
+ */
+
+static void hpt37x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, hpt37x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+static int hpt374_pre_reset(struct ata_port *ap)
+{
+ u16 mcr3, mcr6;
+ u8 ata66;
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ /* Do the extra channel work */
+ pci_read_config_word(pdev, 0x52, &mcr3);
+ pci_read_config_word(pdev, 0x56, &mcr6);
+ /* Set bit 15 of 0x52 to enable TCBLID as input
+ Set bit 15 of 0x56 to enable FCBLID as input
+ */
+ pci_write_config_word(pdev, 0x52, mcr3 | 0x8000);
+ pci_write_config_word(pdev, 0x56, mcr6 | 0x8000);
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ /* Reset TCBLID/FCBLID to output */
+ pci_write_config_word(pdev, 0x52, mcr3);
+ pci_write_config_word(pdev, 0x56, mcr6);
+
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ /* Reset the state machine */
+ pci_write_config_byte(pdev, 0x50, 0x37);
+ pci_write_config_byte(pdev, 0x54, 0x37);
+ udelay(100);
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt374_error_handler - reset the hpt374
+ * @classes:
+ *
+ * The 374 cable detect is a little different due to the extra
+ * channels. The function 0 channels work like usual but function 1
+ * is special
+ */
+
+static void hpt374_error_handler(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!(PCI_FUNC(pdev->devfn) & 1))
+ hpt37x_error_handler(ap);
+ else
+ ata_bmdma_drive_eh(ap, hpt374_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt370_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt370_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x02;
+ fast |= 0x01;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->pio_mode);
+ mode &= ~0x8000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt370_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt370_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x02;
+ fast |= 0x01;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->dma_mode);
+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt370_bmdma_start - DMA engine begin
+ * @qc: ATA command
+ *
+ * The 370 and 370A want us to reset the DMA engine each time we
+ * use it. The 372 and later are fine.
+ */
+
+static void hpt370_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
+ udelay(10);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * hpt370_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Work around the HPT370 DMA engine.
+ */
+
+static void hpt370_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 dma_stat = inb(ap->ioaddr.bmdma_addr + 2);
+ u8 dma_cmd;
+ unsigned long bmdma = ap->ioaddr.bmdma_addr;
+
+ if (dma_stat & 0x01) {
+ udelay(20);
+ dma_stat = inb(bmdma + 2);
+ }
+ if (dma_stat & 0x01) {
+ /* Clear the engine */
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
+ udelay(10);
+ /* Stop DMA */
+ dma_cmd = inb(bmdma );
+ outb(dma_cmd & 0xFE, bmdma);
+ /* Clear Error */
+ dma_stat = inb(bmdma + 2);
+ outb(dma_stat | 0x06 , bmdma + 2);
+ /* Clear the engine */
+ pci_write_config_byte(pdev, 0x50 + 4 * ap->port_no, 0x37);
+ udelay(10);
+ }
+ ata_bmdma_stop(qc);
+}
+
+/**
+ * hpt372_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt372_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->pio_mode);
+
+ printk("Find mode for %d reports %X\n", adev->pio_mode, mode);
+ mode &= ~0x80000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt372_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt372_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt37x_find_mode(ap, adev->dma_mode);
+ printk("Find mode for DMA %d reports %X\n", adev->dma_mode, mode);
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ mode |= 0x80000000; /* FIFO in MWDMA or UDMA */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt37x_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Clean up after the HPT372 and later DMA engine
+ */
+
+static void hpt37x_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int mscreg = 0x50 + 2 * ap->port_no;
+ u8 bwsr_stat, msc_stat;
+
+ pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
+ pci_read_config_byte(pdev, mscreg, &msc_stat);
+ if (bwsr_stat & (1 << ap->port_no))
+ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30);
+ ata_bmdma_stop(qc);
+}
+
+
+static struct scsi_host_template hpt37x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Configuration for HPT370
+ */
+
+static struct ata_port_operations hpt370_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt370_set_piomode,
+ .set_dmamode = hpt370_set_dmamode,
+ .mode_filter = hpt370_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt37x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = hpt370_bmdma_start,
+ .bmdma_stop = hpt370_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Configuration for HPT370A. Close to 370 but less filters
+ */
+
+static struct ata_port_operations hpt370a_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt370_set_piomode,
+ .set_dmamode = hpt370_set_dmamode,
+ .mode_filter = hpt370a_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt37x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = hpt370_bmdma_start,
+ .bmdma_stop = hpt370_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Configuration for HPT372, HPT371, HPT302. Slightly different PIO
+ * and DMA mode setting functionality.
+ */
+
+static struct ata_port_operations hpt372_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt372_set_piomode,
+ .set_dmamode = hpt372_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt37x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = hpt37x_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Configuration for HPT374. Mode setting works like 372 and friends
+ * but we have a different cable detection procedure.
+ */
+
+static struct ata_port_operations hpt374_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt372_set_piomode,
+ .set_dmamode = hpt372_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt374_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = hpt37x_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * htp37x_clock_slot - Turn timing to PC clock entry
+ * @freq: Reported frequency timing
+ * @base: Base timing
+ *
+ * Turn the timing data intoa clock slot (0 for 33, 1 for 40, 2 for 50
+ * and 3 for 66Mhz)
+ */
+
+static int hpt37x_clock_slot(unsigned int freq, unsigned int base)
+{
+ unsigned int f = (base * freq) / 192; /* Mhz */
+ if (f < 40)
+ return 0; /* 33Mhz slot */
+ if (f < 45)
+ return 1; /* 40Mhz slot */
+ if (f < 55)
+ return 2; /* 50Mhz slot */
+ return 3; /* 60Mhz slot */
+}
+
+/**
+ * hpt37x_calibrate_dpll - Calibrate the DPLL loop
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the HPT37x DPLL. Returns 1 if this
+ * succeeds
+ */
+
+static int hpt37x_calibrate_dpll(struct pci_dev *dev)
+{
+ u8 reg5b;
+ u32 reg5c;
+ int tries;
+
+ for(tries = 0; tries < 0x5000; tries++) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ if (reg5b & 0x80) {
+ /* See if it stays set */
+ for(tries = 0; tries < 0x1000; tries ++) {
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ /* Failed ? */
+ if ((reg5b & 0x80) == 0)
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword(dev, 0x5c, &reg5c);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ return 1;
+ }
+ }
+ /* Never went stable */
+ return 0;
+}
+/**
+ * hpt37x_init_one - Initialise an HPT37X/302
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Initialise an HPT37x device. There are some interesting complications
+ * here. Firstly the chip may report 366 and be one of several variants.
+ * Secondly all the timings depend on the clock for the chip which we must
+ * detect and look up
+ *
+ * This is the known chip mappings. It may be missing a couple of later
+ * releases.
+ *
+ * Chip version PCI Rev Notes
+ * HPT366 4 (HPT366) 0 Other driver
+ * HPT366 4 (HPT366) 1 Other driver
+ * HPT368 4 (HPT366) 2 Other driver
+ * HPT370 4 (HPT366) 3 UDMA100
+ * HPT370A 4 (HPT366) 4 UDMA100
+ * HPT372 4 (HPT366) 5 UDMA133 (1)
+ * HPT372N 4 (HPT366) 6 Other driver
+ * HPT372A 5 (HPT372) 1 UDMA133 (1)
+ * HPT372N 5 (HPT372) 2 Other driver
+ * HPT302 6 (HPT302) 1 UDMA133
+ * HPT302N 6 (HPT302) 2 Other driver
+ * HPT371 7 (HPT371) * UDMA133
+ * HPT374 8 (HPT374) * UDMA133 4 channel
+ * HPT372N 9 (HPT372N) * Other driver
+ *
+ * (1) UDMA133 support depends on the bus clock
+ */
+
+static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ /* HPT370 - UDMA100 */
+ static struct ata_port_info info_hpt370 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &hpt370_port_ops
+ };
+ /* HPT370A - UDMA100 */
+ static struct ata_port_info info_hpt370a = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &hpt370a_port_ops
+ };
+ /* HPT371, 372 and friends - UDMA133 */
+ static struct ata_port_info info_hpt372 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &hpt372_port_ops
+ };
+ /* HPT371, 372 and friends - UDMA100 at 50MHz clock */
+ static struct ata_port_info info_hpt372_50 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &hpt372_port_ops
+ };
+ /* HPT374 - UDMA133 */
+ static struct ata_port_info info_hpt374 = {
+ .sht = &hpt37x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &hpt374_port_ops
+ };
+
+ static const int MHz[4] = { 33, 40, 50, 66 };
+
+ struct ata_port_info *port_info[2];
+ struct ata_port_info *port;
+
+ u8 irqmask;
+ u32 class_rev;
+ u32 freq;
+
+ const struct hpt_chip *chip_table;
+ int clock_slot;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ if (dev->device == PCI_DEVICE_ID_TTI_HPT366) {
+ /* May be a later chip in disguise. Check */
+ /* Older chips are in the HPT366 driver. Ignore them */
+ if (class_rev < 3)
+ return -ENODEV;
+ /* N series chips have their own driver. Ignore */
+ if (class_rev == 6)
+ return -ENODEV;
+
+ switch(class_rev) {
+ case 3:
+ port = &info_hpt370;
+ chip_table = &hpt370;
+ break;
+ case 4:
+ port = &info_hpt370a;
+ chip_table = &hpt370a;
+ break;
+ case 5:
+ port = &info_hpt372;
+ chip_table = &hpt372;
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt37x: Unknown HPT366 subtype please report (%d).\n", class_rev);
+ return -ENODEV;
+ }
+ } else {
+ switch(dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 2*/
+ if (class_rev >= 2)
+ return -ENODEV;
+ port = &info_hpt372;
+ chip_table = &hpt372a;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ /* 302N if rev > 1 */
+ if (class_rev > 1)
+ return -ENODEV;
+ port = &info_hpt372;
+ /* Check this */
+ chip_table = &hpt302;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT371:
+ port = &info_hpt372;
+ chip_table = &hpt371;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT374:
+ chip_table = &hpt374;
+ port = &info_hpt374;
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt37x: PCI table is bogus please report (%d).\n", dev->device);
+ return -ENODEV;
+ }
+ }
+ /* Ok so this is a chip we support */
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ pci_read_config_byte(dev, 0x5A, &irqmask);
+ irqmask &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, irqmask);
+
+ /*
+ * default to pci clock. make sure MA15/16 are set to output
+ * to prevent drives having problems with 40-pin cables. Needed
+ * for some drives such as IBM-DTLA which will not enter ready
+ * state on reset when PDIAG is a input.
+ */
+
+ pci_write_config_byte(dev, 0x5b, 0x23);
+
+ pci_read_config_dword(dev, 0x70, &freq);
+ if ((freq >> 12) != 0xABCDE) {
+ int i;
+ u8 sr;
+ u32 total = 0;
+
+ printk(KERN_WARNING "pata_hpt37x: BIOS has not set timing clocks.\n");
+
+ /* This is the process the HPT371 BIOS is reported to use */
+ for(i = 0; i < 128; i++) {
+ pci_read_config_byte(dev, 0x78, &sr);
+ total += sr;
+ udelay(15);
+ }
+ freq = total / 128;
+ }
+ freq &= 0x1FF;
+
+ /*
+ * Turn the frequency check into a band and then find a timing
+ * table to match it.
+ */
+
+ clock_slot = hpt37x_clock_slot(freq, chip_table->base);
+ if (chip_table->clocks[clock_slot] == NULL) {
+ /*
+ * We need to try PLL mode instead
+ */
+ unsigned int f_low = (MHz[clock_slot] * chip_table->base) / 192;
+ unsigned int f_high = f_low + 2;
+ int adjust;
+
+ for(adjust = 0; adjust < 8; adjust++) {
+ if (hpt37x_calibrate_dpll(dev))
+ break;
+ /* See if it'll settle at a fractionally different clock */
+ if ((adjust & 3) == 3) {
+ f_low --;
+ f_high ++;
+ }
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+ }
+ if (adjust == 8) {
+ printk(KERN_WARNING "hpt37x: DPLL did not stabilize.\n");
+ return -ENODEV;
+ }
+ /* Check if this works for all cases */
+ port->private_data = (void *)hpt370_timings_66;
+
+ printk(KERN_INFO "hpt37x: Bus clock %dMHz, using DPLL.\n", MHz[clock_slot]);
+ } else {
+ port->private_data = (void *)chip_table->clocks[clock_slot];
+ /*
+ * Perform a final fixup. The 371 and 372 clock determines
+ * if UDMA133 is available.
+ */
+
+ if (clock_slot == 2 && chip_table == &hpt372) { /* 50Mhz */
+ printk(KERN_WARNING "pata_hpt37x: No UDMA133 support available with 50MHz bus clock.\n");
+ if (port == &info_hpt372)
+ port = &info_hpt372_50;
+ else BUG();
+ }
+ printk(KERN_INFO "hpt37x: %s: Bus clock %dMHz.\n", chip_table->name, MHz[clock_slot]);
+ }
+ port_info[0] = port_info[1] = port;
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt37x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
+ { 0, },
+};
+
+static struct pci_driver hpt37x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt37x,
+ .probe = hpt37x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt37x_init(void)
+{
+ return pci_register_driver(&hpt37x_pci_driver);
+}
+
+
+static void __exit hpt37x_exit(void)
+{
+ pci_unregister_driver(&hpt37x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt37x);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt37x_init);
+module_exit(hpt37x_exit);
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
new file mode 100644
index 00000000000..5c5d4f6ab90
--- /dev/null
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -0,0 +1,597 @@
+/*
+ * Libata driver for the highpoint 372N and 302N UDMA66 ATA controllers.
+ *
+ * This driver is heavily based upon:
+ *
+ * linux/drivers/ide/pci/hpt366.c Version 0.36 April 25, 2003
+ *
+ * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 2001 Sun Microsystems, Inc.
+ * Portions Copyright (C) 2003 Red Hat Inc
+ *
+ *
+ * TODO
+ * 371N
+ * Work out best PLL policy
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt3x2n"
+#define DRV_VERSION "0.3"
+
+enum {
+ HPT_PCI_FAST = (1 << 31),
+ PCI66 = (1 << 1),
+ USE_DPLL = (1 << 0)
+};
+
+struct hpt_clock {
+ u8 xfer_speed;
+ u32 timing;
+};
+
+struct hpt_chip {
+ const char *name;
+ struct hpt_clock *clocks[3];
+};
+
+/* key for bus clock timings
+ * bit
+ * 0:3 data_high_time. inactive time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 4:8 data_low_time. active time of DIOW_/DIOR_ for PIO and MW
+ * DMA. cycles = value + 1
+ * 9:12 cmd_high_time. inactive time of DIOW_/DIOR_ during task file
+ * register access.
+ * 13:17 cmd_low_time. active time of DIOW_/DIOR_ during task file
+ * register access.
+ * 18:21 udma_cycle_time. clock freq and clock cycles for UDMA xfer.
+ * during task file register access.
+ * 22:24 pre_high_time. time to initialize 1st cycle for PIO and MW DMA
+ * xfer.
+ * 25:27 cmd_pre_high_time. time to initialize 1st PIO cycle for task
+ * register access.
+ * 28 UDMA enable
+ * 29 DMA enable
+ * 30 PIO_MST enable. if set, the chip is in bus master mode during
+ * PIO.
+ * 31 FIFO enable.
+ */
+
+/* 66MHz DPLL clocks */
+
+static struct hpt_clock hpt3x2n_clocks[] = {
+ { XFER_UDMA_7, 0x1c869c62 },
+ { XFER_UDMA_6, 0x1c869c62 },
+ { XFER_UDMA_5, 0x1c8a9c62 },
+ { XFER_UDMA_4, 0x1c8a9c62 },
+ { XFER_UDMA_3, 0x1c8e9c62 },
+ { XFER_UDMA_2, 0x1c929c62 },
+ { XFER_UDMA_1, 0x1c9a9c62 },
+ { XFER_UDMA_0, 0x1c829c62 },
+
+ { XFER_MW_DMA_2, 0x2c829c62 },
+ { XFER_MW_DMA_1, 0x2c829c66 },
+ { XFER_MW_DMA_0, 0x2c829d2c },
+
+ { XFER_PIO_4, 0x0c829c62 },
+ { XFER_PIO_3, 0x0c829c84 },
+ { XFER_PIO_2, 0x0c829ca6 },
+ { XFER_PIO_1, 0x0d029d26 },
+ { XFER_PIO_0, 0x0d029d5e },
+ { 0, 0x0d029d5e }
+};
+
+/**
+ * hpt3x2n_find_mode - reset the hpt3x2n bus
+ * @ap: ATA port
+ * @speed: transfer mode
+ *
+ * Return the 32bit register programming information for this channel
+ * that matches the speed provided. For the moment the clocks table
+ * is hard coded but easy to change. This will be needed if we use
+ * different DPLLs
+ */
+
+static u32 hpt3x2n_find_mode(struct ata_port *ap, int speed)
+{
+ struct hpt_clock *clocks = hpt3x2n_clocks;
+
+ while(clocks->xfer_speed) {
+ if (clocks->xfer_speed == speed)
+ return clocks->timing;
+ clocks++;
+ }
+ BUG();
+ return 0xffffffffU; /* silence compiler warning */
+}
+
+/**
+ * hpt3x2n_pre_reset - reset the hpt3x2n bus
+ * @ap: ATA port to reset
+ *
+ * Perform the initial reset handling for the 3x2n series controllers.
+ * Reset the hardware and state machine, obtain the cable type.
+ */
+
+static int hpt3xn_pre_reset(struct ata_port *ap)
+{
+ u8 scr2, ata66;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x5B, &scr2);
+ pci_write_config_byte(pdev, 0x5B, scr2 & ~0x01);
+ /* Cable register now active */
+ pci_read_config_byte(pdev, 0x5A, &ata66);
+ /* Restore state */
+ pci_write_config_byte(pdev, 0x5B, scr2);
+
+ if (ata66 & (1 << ap->port_no))
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ /* Reset the state machine */
+ pci_write_config_byte(pdev, 0x50, 0x37);
+ pci_write_config_byte(pdev, 0x54, 0x37);
+ udelay(100);
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt3x2n_error_handler - probe the hpt3x2n bus
+ * @ap: ATA port to reset
+ *
+ * Perform the probe reset handling for the 3x2N
+ */
+
+static void hpt3x2n_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, hpt3xn_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt3x2n_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Perform PIO mode setup.
+ */
+
+static void hpt3x2n_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt3x2n_find_mode(ap, adev->pio_mode);
+ mode &= ~0x8000000; /* No FIFO in PIO */
+ mode &= ~0x30070000; /* Leave config bits alone */
+ reg &= 0x30070000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt3x2n_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt3x2n_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 addr1, addr2;
+ u32 reg;
+ u32 mode;
+ u8 fast;
+
+ addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no);
+ addr2 = 0x51 + 4 * ap->port_no;
+
+ /* Fast interrupt prediction disable, hold off interrupt disable */
+ pci_read_config_byte(pdev, addr2, &fast);
+ fast &= ~0x07;
+ pci_write_config_byte(pdev, addr2, fast);
+
+ pci_read_config_dword(pdev, addr1, &reg);
+ mode = hpt3x2n_find_mode(ap, adev->dma_mode);
+ mode |= 0x8000000; /* FIFO in MWDMA or UDMA */
+ mode &= ~0xC0000000; /* Leave config bits alone */
+ reg &= 0xC0000000; /* Strip timing bits */
+ pci_write_config_dword(pdev, addr1, reg | mode);
+}
+
+/**
+ * hpt3x2n_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Clean up after the HPT3x2n and later DMA engine
+ */
+
+static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int mscreg = 0x50 + 2 * ap->port_no;
+ u8 bwsr_stat, msc_stat;
+
+ pci_read_config_byte(pdev, 0x6A, &bwsr_stat);
+ pci_read_config_byte(pdev, mscreg, &msc_stat);
+ if (bwsr_stat & (1 << ap->port_no))
+ pci_write_config_byte(pdev, mscreg, msc_stat | 0x30);
+ ata_bmdma_stop(qc);
+}
+
+/**
+ * hpt3x2n_set_clock - clock control
+ * @ap: ATA port
+ * @source: 0x21 or 0x23 for PLL or PCI sourced clock
+ *
+ * Switch the ATA bus clock between the PLL and PCI clock sources
+ * while correctly isolating the bus and resetting internal logic
+ *
+ * We must use the DPLL for
+ * - writing
+ * - second channel UDMA7 (SATA ports) or higher
+ * - 66MHz PCI
+ *
+ * or we will underclock the device and get reduced performance.
+ */
+
+static void hpt3x2n_set_clock(struct ata_port *ap, int source)
+{
+ unsigned long bmdma = ap->ioaddr.bmdma_addr;
+
+ /* Tristate the bus */
+ outb(0x80, bmdma+0x73);
+ outb(0x80, bmdma+0x77);
+
+ /* Switch clock and reset channels */
+ outb(source, bmdma+0x7B);
+ outb(0xC0, bmdma+0x79);
+
+ /* Reset state machines */
+ outb(0x37, bmdma+0x70);
+ outb(0x37, bmdma+0x74);
+
+ /* Complete reset */
+ outb(0x00, bmdma+0x79);
+
+ /* Reconnect channels to bus */
+ outb(0x00, bmdma+0x73);
+ outb(0x00, bmdma+0x77);
+}
+
+/* Check if our partner interface is busy */
+
+static int hpt3x2n_pair_idle(struct ata_port *ap)
+{
+ struct ata_host *host = ap->host;
+ struct ata_port *pair = host->ports[ap->port_no ^ 1];
+
+ if (pair->hsm_task_state == HSM_ST_IDLE)
+ return 1;
+ return 0;
+}
+
+static int hpt3x2n_use_dpll(struct ata_port *ap, int reading)
+{
+ long flags = (long)ap->host->private_data;
+ /* See if we should use the DPLL */
+ if (reading == 0)
+ return USE_DPLL; /* Needed for write */
+ if (flags & PCI66)
+ return USE_DPLL; /* Needed at 66Mhz */
+ return 0;
+}
+
+static unsigned int hpt3x2n_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *tf = &qc->tf;
+ struct ata_port *ap = qc->ap;
+ int flags = (long)ap->host->private_data;
+
+ if (hpt3x2n_pair_idle(ap)) {
+ int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE));
+ if ((flags & USE_DPLL) != dpll) {
+ if (dpll == 1)
+ hpt3x2n_set_clock(ap, 0x21);
+ else
+ hpt3x2n_set_clock(ap, 0x23);
+ }
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template hpt3x2n_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * Configuration for HPT3x2n.
+ */
+
+static struct ata_port_operations hpt3x2n_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt3x2n_set_piomode,
+ .set_dmamode = hpt3x2n_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt3x2n_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = hpt3x2n_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = hpt3x2n_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * hpt3xn_calibrate_dpll - Calibrate the DPLL loop
+ * @dev: PCI device
+ *
+ * Perform a calibration cycle on the HPT3xN DPLL. Returns 1 if this
+ * succeeds
+ */
+
+static int hpt3xn_calibrate_dpll(struct pci_dev *dev)
+{
+ u8 reg5b;
+ u32 reg5c;
+ int tries;
+
+ for(tries = 0; tries < 0x5000; tries++) {
+ udelay(50);
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ if (reg5b & 0x80) {
+ /* See if it stays set */
+ for(tries = 0; tries < 0x1000; tries ++) {
+ pci_read_config_byte(dev, 0x5b, &reg5b);
+ /* Failed ? */
+ if ((reg5b & 0x80) == 0)
+ return 0;
+ }
+ /* Turn off tuning, we have the DPLL set */
+ pci_read_config_dword(dev, 0x5c, &reg5c);
+ pci_write_config_dword(dev, 0x5c, reg5c & ~ 0x100);
+ return 1;
+ }
+ }
+ /* Never went stable */
+ return 0;
+}
+
+static int hpt3x2n_pci_clock(struct pci_dev *pdev)
+{
+ unsigned long freq;
+ u32 fcnt;
+
+ pci_read_config_dword(pdev, 0x70/*CHECKME*/, &fcnt);
+ if ((fcnt >> 12) != 0xABCDE) {
+ printk(KERN_WARNING "hpt3xn: BIOS clock data not set.\n");
+ return 33; /* Not BIOS set */
+ }
+ fcnt &= 0x1FF;
+
+ freq = (fcnt * 77) / 192;
+
+ /* Clamp to bands */
+ if (freq < 40)
+ return 33;
+ if (freq < 45)
+ return 40;
+ if (freq < 55)
+ return 50;
+ return 66;
+}
+
+/**
+ * hpt3x2n_init_one - Initialise an HPT37X/302
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Initialise an HPT3x2n device. There are some interesting complications
+ * here. Firstly the chip may report 366 and be one of several variants.
+ * Secondly all the timings depend on the clock for the chip which we must
+ * detect and look up
+ *
+ * This is the known chip mappings. It may be missing a couple of later
+ * releases.
+ *
+ * Chip version PCI Rev Notes
+ * HPT372 4 (HPT366) 5 Other driver
+ * HPT372N 4 (HPT366) 6 UDMA133
+ * HPT372 5 (HPT372) 1 Other driver
+ * HPT372N 5 (HPT372) 2 UDMA133
+ * HPT302 6 (HPT302) * Other driver
+ * HPT302N 6 (HPT302) > 1 UDMA133
+ * HPT371 7 (HPT371) * Other driver
+ * HPT371N 7 (HPT371) > 1 UDMA133
+ * HPT374 8 (HPT374) * Other driver
+ * HPT372N 9 (HPT372N) * UDMA133
+ *
+ * (1) UDMA133 support depends on the bus clock
+ *
+ * To pin down HPT371N
+ */
+
+static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ /* HPT372N and friends - UDMA133 */
+ static struct ata_port_info info = {
+ .sht = &hpt3x2n_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &hpt3x2n_port_ops
+ };
+ struct ata_port_info *port_info[2];
+ struct ata_port_info *port = &info;
+
+ u8 irqmask;
+ u32 class_rev;
+
+ unsigned int pci_mhz;
+ unsigned int f_low, f_high;
+ int adjust;
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xFF;
+
+ switch(dev->device) {
+ case PCI_DEVICE_ID_TTI_HPT366:
+ if (class_rev < 6)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372:
+ /* 372N if rev >= 1*/
+ if (class_rev == 0)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT302:
+ if (class_rev < 2)
+ return -ENODEV;
+ break;
+ case PCI_DEVICE_ID_TTI_HPT372N:
+ break;
+ default:
+ printk(KERN_ERR "pata_hpt3x2n: PCI table is bogus please report (%d).\n", dev->device);
+ return -ENODEV;
+ }
+
+ /* Ok so this is a chip we support */
+
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+
+ pci_read_config_byte(dev, 0x5A, &irqmask);
+ irqmask &= ~0x10;
+ pci_write_config_byte(dev, 0x5a, irqmask);
+
+ /* Tune the PLL. HPT recommend using 75 for SATA, 66 for UDMA133 or
+ 50 for UDMA100. Right now we always use 66 */
+
+ pci_mhz = hpt3x2n_pci_clock(dev);
+
+ f_low = (pci_mhz * 48) / 66; /* PCI Mhz for 66Mhz DPLL */
+ f_high = f_low + 2; /* Tolerance */
+
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low | 0x100);
+ /* PLL clock */
+ pci_write_config_byte(dev, 0x5B, 0x21);
+
+ /* Unlike the 37x we don't try jiggling the frequency */
+ for(adjust = 0; adjust < 8; adjust++) {
+ if (hpt3xn_calibrate_dpll(dev))
+ break;
+ pci_write_config_dword(dev, 0x5C, (f_high << 16) | f_low);
+ }
+ if (adjust == 8)
+ printk(KERN_WARNING "hpt3xn: DPLL did not stabilize.\n");
+
+ /* Set our private data up. We only need a few flags so we use
+ it directly */
+ port->private_data = NULL;
+ if (pci_mhz > 60)
+ port->private_data = (void *)PCI66;
+
+ /* Now kick off ATA set up */
+ port_info[0] = port_info[1] = port;
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt3x2n[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), },
+ { 0, },
+};
+
+static struct pci_driver hpt3x2n_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt3x2n,
+ .probe = hpt3x2n_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt3x2n_init(void)
+{
+ return pci_register_driver(&hpt3x2n_pci_driver);
+}
+
+
+static void __exit hpt3x2n_exit(void)
+{
+ pci_unregister_driver(&hpt3x2n_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt3x2n);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt3x2n_init);
+module_exit(hpt3x2n_exit);
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
new file mode 100644
index 00000000000..1f084ab1ccc
--- /dev/null
+++ b/drivers/ata/pata_hpt3x3.c
@@ -0,0 +1,226 @@
+/*
+ * pata_hpt3x3 - HPT3x3 driver
+ * (c) Copyright 2005-2006 Red Hat
+ *
+ * Was pata_hpt34x but the naming was confusing as it supported the
+ * 343 and 363 so it has been renamed.
+ *
+ * Based on:
+ * linux/drivers/ide/pci/hpt34x.c Version 0.40 Sept 10, 2002
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_hpt3x3"
+#define DRV_VERSION "0.4.1"
+
+static int hpt3x3_probe_init(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * hpt3x3_probe_reset - reset the hpt3x3 bus
+ * @ap: ATA port to reset
+ *
+ * Perform the housekeeping when doing an ATA bus reeset. We just
+ * need to force the cable type.
+ */
+
+static void hpt3x3_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, hpt3x3_probe_init, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * hpt3x3_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. This is fairly simple on the HPT3x3 as
+ * all we have to do is clear the MWDMA and UDMA bits then load the
+ * mode number.
+ */
+
+static void hpt3x3_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 r1, r2;
+ int dn = 2 * ap->port_no + adev->devno;
+
+ pci_read_config_dword(pdev, 0x44, &r1);
+ pci_read_config_dword(pdev, 0x48, &r2);
+ /* Load the PIO timing number */
+ r1 &= ~(7 << (3 * dn));
+ r1 |= (adev->pio_mode - XFER_PIO_0) << (3 * dn);
+ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
+
+ pci_write_config_dword(pdev, 0x44, r1);
+ pci_write_config_dword(pdev, 0x48, r2);
+}
+
+/**
+ * hpt3x3_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * Set up the channel for MWDMA or UDMA modes. Much the same as with
+ * PIO, load the mode number and then set MWDMA or UDMA flag.
+ */
+
+static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 r1, r2;
+ int dn = 2 * ap->port_no + adev->devno;
+ int mode_num = adev->dma_mode & 0x0F;
+
+ pci_read_config_dword(pdev, 0x44, &r1);
+ pci_read_config_dword(pdev, 0x48, &r2);
+ /* Load the timing number */
+ r1 &= ~(7 << (3 * dn));
+ r1 |= (mode_num << (3 * dn));
+ r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */
+
+ if (adev->dma_mode >= XFER_UDMA_0)
+ r2 |= 0x01 << dn; /* Ultra mode */
+ else
+ r2 |= 0x10 << dn; /* MWDMA */
+
+ pci_write_config_dword(pdev, 0x44, r1);
+ pci_write_config_dword(pdev, 0x48, r2);
+}
+
+static struct scsi_host_template hpt3x3_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations hpt3x3_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = hpt3x3_set_piomode,
+ .set_dmamode = hpt3x3_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = hpt3x3_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * hpt3x3_init_one - Initialise an HPT343/363
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Perform basic initialisation. The chip has a quirk that it won't
+ * function unless it is at XX00. The old ATA driver touched this up
+ * but we leave it for pci quirks to do properly.
+ */
+
+static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &hpt3x3_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &hpt3x3_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ u16 cmd;
+
+ /* Initialize the board */
+ pci_write_config_word(dev, 0x80, 0x00);
+ /* Check if it is a 343 or a 363. 363 has COMMAND_MEMORY set */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (cmd & PCI_COMMAND_MEMORY)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
+ else
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
+
+ /* Now kick off ATA set up */
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id hpt3x3[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), },
+ { 0, },
+};
+
+static struct pci_driver hpt3x3_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = hpt3x3,
+ .probe = hpt3x3_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init hpt3x3_init(void)
+{
+ return pci_register_driver(&hpt3x3_pci_driver);
+}
+
+
+static void __exit hpt3x3_exit(void)
+{
+ pci_unregister_driver(&hpt3x3_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the Highpoint HPT343/363");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, hpt3x3);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(hpt3x3_init);
+module_exit(hpt3x3_exit);
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
new file mode 100644
index 00000000000..640b8b0954f
--- /dev/null
+++ b/drivers/ata/pata_isapnp.c
@@ -0,0 +1,156 @@
+
+/*
+ * pata-isapnp.c - ISA PnP PATA controller driver.
+ * Copyright 2005/2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ *
+ * Based in part on ide-pnp.c by Andrey Panin <pazke@donpac.ru>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/isapnp.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_isapnp"
+#define DRV_VERSION "0.1.5"
+
+static struct scsi_host_template isapnp_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations isapnp_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * isapnp_init_one - attach an isapnp interface
+ * @idev: PnP device
+ * @dev_id: matching detect line
+ *
+ * Register an ISA bus IDE interface. Such interfaces are PIO 0 and
+ * non shared IRQ.
+ */
+
+static int isapnp_init_one(struct pnp_dev *idev, const struct pnp_device_id *dev_id)
+{
+ struct ata_probe_ent ae;
+
+ if (pnp_port_valid(idev, 0) == 0)
+ return -ENODEV;
+
+ /* FIXME: Should selected polled PIO here not fail */
+ if (pnp_irq_valid(idev, 0) == 0)
+ return -ENODEV;
+
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &idev->dev;
+ ae.port_ops = &isapnp_port_ops;
+ ae.sht = &isapnp_sht;
+ ae.n_ports = 1;
+ ae.pio_mask = 1; /* ISA so PIO 0 cycles */
+ ae.irq = pnp_irq(idev, 0);
+ ae.irq_flags = 0;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS;
+ ae.port[0].cmd_addr = pnp_port_start(idev, 0);
+
+ if (pnp_port_valid(idev, 1) == 0) {
+ ae.port[0].altstatus_addr = pnp_port_start(idev, 1);
+ ae.port[0].ctl_addr = pnp_port_start(idev, 1);
+ ae.port_flags |= ATA_FLAG_SRST;
+ }
+ ata_std_ports(&ae.port[0]);
+
+ if (ata_device_add(&ae) == 0)
+ return -ENODEV;
+ return 0;
+}
+
+/**
+ * isapnp_remove_one - unplug an isapnp interface
+ * @idev: PnP device
+ *
+ * Remove a previously configured PnP ATA port. Called only on module
+ * unload events as the core does not currently deal with ISAPnP docking.
+ */
+
+static void isapnp_remove_one(struct pnp_dev *idev)
+{
+ struct device *dev = &idev->dev;
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+}
+
+static struct pnp_device_id isapnp_devices[] = {
+ /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ {.id = "PNP0600", .driver_data = 0},
+ {.id = ""}
+};
+
+static struct pnp_driver isapnp_driver = {
+ .name = DRV_NAME,
+ .id_table = isapnp_devices,
+ .probe = isapnp_init_one,
+ .remove = isapnp_remove_one,
+};
+
+static int __init isapnp_init(void)
+{
+ return pnp_register_driver(&isapnp_driver);
+}
+
+static void __exit isapnp_exit(void)
+{
+ pnp_unregister_driver(&isapnp_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for ISA PnP ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(isapnp_init);
+module_exit(isapnp_exit);
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
new file mode 100644
index 00000000000..82a46ff4000
--- /dev/null
+++ b/drivers/ata/pata_it821x.c
@@ -0,0 +1,847 @@
+/*
+ * ata-it821x.c - IT821x PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * it821x.c
+ *
+ * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
+ *
+ * Copyright (C) 2004 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ * Based in part on the ITE vendor provided SCSI driver.
+ *
+ * Documentation available from
+ * http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ * Some other documents are NDA.
+ *
+ * The ITE8212 isn't exactly a standard IDE controller. It has two
+ * modes. In pass through mode then it is an IDE controller. In its smart
+ * mode its actually quite a capable hardware raid controller disguised
+ * as an IDE controller. Smart mode only understands DMA read/write and
+ * identify, none of the fancier commands apply. The IT8211 is identical
+ * in other respects but lacks the raid mode.
+ *
+ * Errata:
+ * o Rev 0x10 also requires master/slave hold the same DMA timings and
+ * cannot do ATAPI MWDMA.
+ * o The identify data for raid volumes lacks CHS info (technically ok)
+ * but also fails to set the LBA28 and other bits. We fix these in
+ * the IDE probe quirk code.
+ * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
+ * raid then the controller firmware dies
+ * o Smart mode without RAID doesn't clear all the necessary identify
+ * bits to reduce the command set to the one used
+ *
+ * This has a few impacts on the driver
+ * - In pass through mode we do all the work you would expect
+ * - In smart mode the clocking set up is done by the controller generally
+ * but we must watch the other limits and filter.
+ * - There are a few extra vendor commands that actually talk to the
+ * controller but only work PIO with no IRQ.
+ *
+ * Vendor areas of the identify block in smart mode are used for the
+ * timing and policy set up. Each HDD in raid mode also has a serial
+ * block on the disk. The hardware extra commands are get/set chip status,
+ * rebuild, get rebuild status.
+ *
+ * In Linux the driver supports pass through mode as if the device was
+ * just another IDE controller. If the smart mode is running then
+ * volumes are managed by the controller firmware and each IDE "disk"
+ * is a raid volume. Even more cute - the controller can do automated
+ * hotplug and rebuild.
+ *
+ * The pass through controller itself is a little demented. It has a
+ * flaw that it has a single set of PIO/MWDMA timings per channel so
+ * non UDMA devices restrict each others performance. It also has a
+ * single clock source per channel so mixed UDMA100/133 performance
+ * isn't perfect and we have to pick a clock. Thankfully none of this
+ * matters in smart mode. ATAPI DMA is not currently supported.
+ *
+ * It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
+ *
+ * TODO
+ * - ATAPI and other speed filtering
+ * - Command filter in smart mode
+ * - RAID configuration ioctls
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+
+#define DRV_NAME "pata_it821x"
+#define DRV_VERSION "0.3.2"
+
+struct it821x_dev
+{
+ unsigned int smart:1, /* Are we in smart raid mode */
+ timing10:1; /* Rev 0x10 */
+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */
+ u8 want[2][2]; /* Mode/Pri log for master slave */
+ /* We need these for switching the clock when DMA goes on/off
+ The high byte is the 66Mhz timing */
+ u16 pio[2]; /* Cached PIO values */
+ u16 mwdma[2]; /* Cached MWDMA values */
+ u16 udma[2]; /* Cached UDMA values (per drive) */
+ u16 last_device; /* Master or slave loaded ? */
+};
+
+#define ATA_66 0
+#define ATA_50 1
+#define ATA_ANY 2
+
+#define UDMA_OFF 0
+#define MWDMA_OFF 0
+
+/*
+ * We allow users to force the card into non raid mode without
+ * flashing the alternative BIOS. This is also neccessary right now
+ * for embedded platforms that cannot run a PC BIOS but are using this
+ * device.
+ */
+
+static int it8212_noraid;
+
+/**
+ * it821x_pre_reset - probe
+ * @ap: ATA port
+ *
+ * Set the cable type
+ */
+
+static int it821x_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * it821x_error_handler - probe/reset
+ * @ap: ATA port
+ *
+ * Set the cable type and trigger a probe
+ */
+
+static void it821x_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, it821x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * it821x_program - program the PIO/MWDMA registers
+ * @ap: ATA port
+ * @adev: Device to program
+ * @timing: Timing value (66Mhz in top 8bits, 50 in the low 8)
+ *
+ * Program the PIO/MWDMA timing for this channel according to the
+ * current clock. These share the same register so are managed by
+ * the DMA start/stop sequence as with the old driver.
+ */
+
+static void it821x_program(struct ata_port *ap, struct ata_device *adev, u16 timing)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev = ap->private_data;
+ int channel = ap->port_no;
+ u8 conf;
+
+ /* Program PIO/MWDMA timing bits */
+ if (itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ pci_write_config_byte(pdev, 0x54 + 4 * channel, conf);
+}
+
+
+/**
+ * it821x_program_udma - program the UDMA registers
+ * @ap: ATA port
+ * @adev: ATA device to update
+ * @timing: Timing bits. Top 8 are for 66Mhz bottom for 50Mhz
+ *
+ * Program the UDMA timing for this drive according to the
+ * current clock. Handles the dual clocks and also knows about
+ * the errata on the 0x10 revision. The UDMA errata is partly handled
+ * here and partly in start_dma.
+ */
+
+static void it821x_program_udma(struct ata_port *ap, struct ata_device *adev, u16 timing)
+{
+ struct it821x_dev *itdev = ap->private_data;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int channel = ap->port_no;
+ int unit = adev->devno;
+ u8 conf;
+
+ /* Program UDMA timing bits */
+ if (itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ if (itdev->timing10 == 0)
+ pci_write_config_byte(pdev, 0x56 + 4 * channel + unit, conf);
+ else {
+ /* Early revision must be programmed for both together */
+ pci_write_config_byte(pdev, 0x56 + 4 * channel, conf);
+ pci_write_config_byte(pdev, 0x56 + 4 * channel + 1, conf);
+ }
+}
+
+/**
+ * it821x_clock_strategy
+ * @ap: ATA interface
+ * @adev: ATA device being updated
+ *
+ * Select between the 50 and 66Mhz base clocks to get the best
+ * results for this interface.
+ */
+
+static void it821x_clock_strategy(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev = ap->private_data;
+ u8 unit = adev->devno;
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ int clock, altclock;
+ u8 v;
+ int sel = 0;
+
+ /* Look for the most wanted clocking */
+ if (itdev->want[0][0] > itdev->want[1][0]) {
+ clock = itdev->want[0][1];
+ altclock = itdev->want[1][1];
+ } else {
+ clock = itdev->want[1][1];
+ altclock = itdev->want[0][1];
+ }
+
+ /* Master doesn't care does the slave ? */
+ if (clock == ATA_ANY)
+ clock = altclock;
+
+ /* Nobody cares - keep the same clock */
+ if (clock == ATA_ANY)
+ return;
+ /* No change */
+ if (clock == itdev->clock_mode)
+ return;
+
+ /* Load this into the controller */
+ if (clock == ATA_66)
+ itdev->clock_mode = ATA_66;
+ else {
+ itdev->clock_mode = ATA_50;
+ sel = 1;
+ }
+ pci_read_config_byte(pdev, 0x50, &v);
+ v &= ~(1 << (1 + ap->port_no));
+ v |= sel << (1 + ap->port_no);
+ pci_write_config_byte(pdev, 0x50, v);
+
+ /*
+ * Reprogram the UDMA/PIO of the pair drive for the switch
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if (pair && itdev->udma[1-unit] != UDMA_OFF) {
+ it821x_program_udma(ap, pair, itdev->udma[1-unit]);
+ it821x_program(ap, pair, itdev->pio[1-unit]);
+ }
+ /*
+ * Reprogram the UDMA/PIO of our drive for the switch.
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if (itdev->udma[unit] != UDMA_OFF) {
+ it821x_program_udma(ap, adev, itdev->udma[unit]);
+ it821x_program(ap, adev, itdev->pio[unit]);
+ }
+}
+
+/**
+ * it821x_passthru_set_piomode - set PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Configure for PIO mode. This is complicated as the register is
+ * shared by PIO and MWDMA and for both channels.
+ */
+
+static void it821x_passthru_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ /* Spec says 89 ref driver uses 88 */
+ static const u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static const u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+ struct it821x_dev *itdev = ap->private_data;
+ int unit = adev->devno;
+ int mode_wanted = adev->pio_mode - XFER_PIO_0;
+
+ /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+ itdev->want[unit][1] = pio_want[mode_wanted];
+ itdev->want[unit][0] = 1; /* PIO is lowest priority */
+ itdev->pio[unit] = pio[mode_wanted];
+ it821x_clock_strategy(ap, adev);
+ it821x_program(ap, adev, itdev->pio[unit]);
+}
+
+/**
+ * it821x_passthru_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Set up the DMA modes. The actions taken depend heavily on the mode
+ * to use. If UDMA is used as is hopefully the usual case then the
+ * timing register is private and we need only consider the clock. If
+ * we are using MWDMA then we have to manage the setting ourself as
+ * we switch devices and mode.
+ */
+
+static void it821x_passthru_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static const u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+ static const u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+ static const u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev = ap->private_data;
+ int channel = ap->port_no;
+ int unit = adev->devno;
+ u8 conf;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int mode_wanted = adev->dma_mode - XFER_UDMA_0;
+
+ itdev->want[unit][1] = udma_want[mode_wanted];
+ itdev->want[unit][0] = 3; /* UDMA is high priority */
+ itdev->mwdma[unit] = MWDMA_OFF;
+ itdev->udma[unit] = udma[mode_wanted];
+ if (mode_wanted >= 5)
+ itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */
+
+ /* UDMA on. Again revision 0x10 must do the pair */
+ pci_read_config_byte(pdev, 0x50, &conf);
+ if (itdev->timing10)
+ conf &= channel ? 0x9F: 0xE7;
+ else
+ conf &= ~ (1 << (3 + 2 * channel + unit));
+ pci_write_config_byte(pdev, 0x50, conf);
+ it821x_clock_strategy(ap, adev);
+ it821x_program_udma(ap, adev, itdev->udma[unit]);
+ } else {
+ int mode_wanted = adev->dma_mode - XFER_MW_DMA_0;
+
+ itdev->want[unit][1] = mwdma_want[mode_wanted];
+ itdev->want[unit][0] = 2; /* MWDMA is low priority */
+ itdev->mwdma[unit] = dma[mode_wanted];
+ itdev->udma[unit] = UDMA_OFF;
+
+ /* UDMA bits off - Revision 0x10 do them in pairs */
+ pci_read_config_byte(pdev, 0x50, &conf);
+ if (itdev->timing10)
+ conf |= channel ? 0x60: 0x18;
+ else
+ conf |= 1 << (3 + 2 * channel + unit);
+ pci_write_config_byte(pdev, 0x50, conf);
+ it821x_clock_strategy(ap, adev);
+ }
+}
+
+/**
+ * it821x_passthru_dma_start - DMA start callback
+ * @qc: Command in progress
+ *
+ * Usually drivers set the DMA timing at the point the set_dmamode call
+ * is made. IT821x however requires we load new timings on the
+ * transitions in some cases.
+ */
+
+static void it821x_passthru_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct it821x_dev *itdev = ap->private_data;
+ int unit = adev->devno;
+
+ if (itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(ap, adev, itdev->mwdma[unit]);
+ else if (itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+ it821x_program_udma(ap, adev, itdev->udma[unit]);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * it821x_passthru_dma_stop - DMA stop callback
+ * @qc: ATA command
+ *
+ * We loaded new timings in dma_start, as a result we need to restore
+ * the PIO timings in dma_stop so that the next command issue gets the
+ * right clock values.
+ */
+
+static void it821x_passthru_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct it821x_dev *itdev = ap->private_data;
+ int unit = adev->devno;
+
+ ata_bmdma_stop(qc);
+ if (itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(ap, adev, itdev->pio[unit]);
+}
+
+
+/**
+ * it821x_passthru_dev_select - Select master/slave
+ * @ap: ATA port
+ * @device: Device number (not pointer)
+ *
+ * Device selection hook. If neccessary perform clock switching
+ */
+
+static void it821x_passthru_dev_select(struct ata_port *ap,
+ unsigned int device)
+{
+ struct it821x_dev *itdev = ap->private_data;
+ if (itdev && device != itdev->last_device) {
+ struct ata_device *adev = &ap->device[device];
+ it821x_program(ap, adev, itdev->pio[adev->devno]);
+ itdev->last_device = device;
+ }
+ ata_std_dev_select(ap, device);
+}
+
+/**
+ * it821x_smart_qc_issue_prot - wrap qc issue prot
+ * @qc: command
+ *
+ * Wrap the command issue sequence for the IT821x. We need to
+ * perform out own device selection timing loads before the
+ * usual happenings kick off
+ */
+
+static unsigned int it821x_smart_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ switch(qc->tf.command)
+ {
+ /* Commands the firmware supports */
+ case ATA_CMD_READ:
+ case ATA_CMD_READ_EXT:
+ case ATA_CMD_WRITE:
+ case ATA_CMD_WRITE_EXT:
+ case ATA_CMD_PIO_READ:
+ case ATA_CMD_PIO_READ_EXT:
+ case ATA_CMD_PIO_WRITE:
+ case ATA_CMD_PIO_WRITE_EXT:
+ case ATA_CMD_READ_MULTI:
+ case ATA_CMD_READ_MULTI_EXT:
+ case ATA_CMD_WRITE_MULTI:
+ case ATA_CMD_WRITE_MULTI_EXT:
+ case ATA_CMD_ID_ATA:
+ /* Arguably should just no-op this one */
+ case ATA_CMD_SET_FEATURES:
+ return ata_qc_issue_prot(qc);
+ }
+ printk(KERN_DEBUG "it821x: can't process command 0x%02X\n", qc->tf.command);
+ return AC_ERR_INVALID;
+}
+
+/**
+ * it821x_passthru_qc_issue_prot - wrap qc issue prot
+ * @qc: command
+ *
+ * Wrap the command issue sequence for the IT821x. We need to
+ * perform out own device selection timing loads before the
+ * usual happenings kick off
+ */
+
+static unsigned int it821x_passthru_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ it821x_passthru_dev_select(qc->ap, qc->dev->devno);
+ return ata_qc_issue_prot(qc);
+}
+
+/**
+ * it821x_smart_set_mode - mode setting
+ * @ap: interface to set up
+ *
+ * Use a non standard set_mode function. We don't want to be tuned.
+ * The BIOS configured everything. Our job is not to fiddle. We
+ * read the dma enabled bits from the PCI configuration of the device
+ * and respect them.
+ */
+
+static void it821x_smart_set_mode(struct ata_port *ap)
+{
+ int dma_enabled = 0;
+ int i;
+
+ /* Bits 5 and 6 indicate if DMA is active on master/slave */
+ /* It is possible that BMDMA isn't allocated */
+ if (ap->ioaddr.bmdma_addr)
+ dma_enabled = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->dma_mode = XFER_MW_DMA_0;
+ /* We do need the right mode information for DMA or PIO
+ and this comes from the current configuration flags */
+ if (dma_enabled & (1 << (5 + i))) {
+ dev->xfer_mode = XFER_MW_DMA_0;
+ dev->xfer_shift = ATA_SHIFT_MWDMA;
+ dev->flags &= ~ATA_DFLAG_PIO;
+ } else {
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+ }
+}
+
+/**
+ * it821x_dev_config - Called each device identify
+ * @ap: ATA port
+ * @adev: Device that has just been identified
+ *
+ * Perform the initial setup needed for each device that is chip
+ * special. In our case we need to lock the sector count to avoid
+ * blowing the brains out of the firmware with large LBA48 requests
+ *
+ * FIXME: When FUA appears we need to block FUA too. And SMART and
+ * basically we need to filter commands for this chip.
+ */
+
+static void it821x_dev_config(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned char model_num[40];
+ char *s;
+ unsigned int len;
+
+ /* This block ought to be a library routine as it is in several
+ drivers now */
+
+ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS,
+ sizeof(model_num));
+ s = &model_num[0];
+ len = strnlen(s, sizeof(model_num));
+
+ /* ATAPI specifies that empty space is blank-filled; remove blanks */
+ while ((len > 0) && (s[len - 1] == ' ')) {
+ len--;
+ s[len] = 0;
+ }
+
+ if (adev->max_sectors > 255)
+ adev->max_sectors = 255;
+
+ if (strstr(model_num, "Integrated Technology Express")) {
+ /* RAID mode */
+ printk(KERN_INFO "IT821x %sRAID%d volume",
+ adev->id[147]?"Bootable ":"",
+ adev->id[129]);
+ if (adev->id[129] != 1)
+ printk("(%dK stripe)", adev->id[146]);
+ printk(".\n");
+ }
+}
+
+
+/**
+ * it821x_check_atapi_dma - ATAPI DMA handler
+ * @qc: Command we are about to issue
+ *
+ * Decide if this ATAPI command can be issued by DMA on this
+ * controller. Return 0 if it can be.
+ */
+
+static int it821x_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct it821x_dev *itdev = ap->private_data;
+
+ /* No ATAPI DMA in smart mode */
+ if (itdev->smart)
+ return -EOPNOTSUPP;
+ /* No ATAPI DMA on rev 10 */
+ if (itdev->timing10)
+ return -EOPNOTSUPP;
+ /* Cool */
+ return 0;
+}
+
+
+/**
+ * it821x_port_start - port setup
+ * @ap: ATA port being set up
+ *
+ * The it821x needs to maintain private data structures and also to
+ * use the standard PCI interface which lacks support for this
+ * functionality. We instead set up the private data on the port
+ * start hook, and tear it down on port stop
+ */
+
+static int it821x_port_start(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct it821x_dev *itdev;
+ u8 conf;
+
+ int ret = ata_port_start(ap);
+ if (ret < 0)
+ return ret;
+
+ ap->private_data = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+ if (ap->private_data == NULL) {
+ ata_port_stop(ap);
+ return -ENOMEM;
+ }
+
+ itdev = ap->private_data;
+ memset(itdev, 0, sizeof(struct it821x_dev));
+
+ pci_read_config_byte(pdev, 0x50, &conf);
+
+ if (conf & 1) {
+ itdev->smart = 1;
+ /* Long I/O's although allowed in LBA48 space cause the
+ onboard firmware to enter the twighlight zone */
+ /* No ATAPI DMA in this mode either */
+ }
+ /* Pull the current clocks from 0x50 */
+ if (conf & (1 << (1 + ap->port_no)))
+ itdev->clock_mode = ATA_50;
+ else
+ itdev->clock_mode = ATA_66;
+
+ itdev->want[0][1] = ATA_ANY;
+ itdev->want[1][1] = ATA_ANY;
+ itdev->last_device = -1;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &conf);
+ if (conf == 0x10) {
+ itdev->timing10 = 1;
+ /* Need to disable ATAPI DMA for this case */
+ if (!itdev->smart)
+ printk(KERN_WARNING DRV_NAME": Revision 0x10, workarounds activated.\n");
+ }
+
+ return 0;
+}
+
+/**
+ * it821x_port_stop - port shutdown
+ * @ap: ATA port being removed
+ *
+ * Release the private objects we added in it821x_port_start
+ */
+
+static void it821x_port_stop(struct ata_port *ap) {
+ kfree(ap->private_data);
+ ap->private_data = NULL; /* We want an OOPS if we reuse this
+ too late! */
+ ata_port_stop(ap);
+}
+
+static struct scsi_host_template it821x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* 255 sectors to begin with. This is locked in smart mode but not
+ in pass through */
+ .max_sectors = 255,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations it821x_smart_port_ops = {
+ .set_mode = it821x_smart_set_mode,
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .mode_filter = ata_pci_default_filter,
+
+ .check_status = ata_check_status,
+ .check_atapi_dma= it821x_check_atapi_dma,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = it821x_dev_config,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = it821x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = it821x_smart_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = it821x_port_start,
+ .port_stop = it821x_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations it821x_passthru_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = it821x_passthru_set_piomode,
+ .set_dmamode = it821x_passthru_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .check_atapi_dma= it821x_check_atapi_dma,
+ .dev_select = it821x_passthru_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = it821x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = it821x_passthru_bmdma_start,
+ .bmdma_stop = it821x_passthru_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = it821x_passthru_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_clear = ata_bmdma_irq_clear,
+ .irq_handler = ata_interrupt,
+
+ .port_start = it821x_port_start,
+ .port_stop = it821x_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static void __devinit it821x_disable_raid(struct pci_dev *pdev)
+{
+ /* Reset local CPU, and set BIOS not ready */
+ pci_write_config_byte(pdev, 0x5E, 0x01);
+
+ /* Set to bypass mode, and reset PCI bus */
+ pci_write_config_byte(pdev, 0x50, 0x00);
+ pci_write_config_word(pdev, PCI_COMMAND,
+ PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_write_config_word(pdev, 0x40, 0xA0F3);
+
+ pci_write_config_dword(pdev,0x4C, 0x02040204);
+ pci_write_config_byte(pdev, 0x42, 0x36);
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20);
+}
+
+
+static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ u8 conf;
+
+ static struct ata_port_info info_smart = {
+ .sht = &it821x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &it821x_smart_port_ops
+ };
+ static struct ata_port_info info_passthru = {
+ .sht = &it821x_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &it821x_passthru_port_ops
+ };
+ static struct ata_port_info *port_info[2];
+
+ static char *mode[2] = { "pass through", "smart" };
+
+ /* Force the card into bypass mode if so requested */
+ if (it8212_noraid) {
+ printk(KERN_INFO DRV_NAME ": forcing bypass mode.\n");
+ it821x_disable_raid(pdev);
+ }
+ pci_read_config_byte(pdev, 0x50, &conf);
+ conf &= 1;
+
+ printk(KERN_INFO DRV_NAME ": controller in %s mode.\n", mode[conf]);
+ if (conf == 0)
+ port_info[0] = port_info[1] = &info_passthru;
+ else
+ port_info[0] = port_info[1] = &info_smart;
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static struct pci_device_id it821x[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), },
+ { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), },
+ { 0, },
+};
+
+static struct pci_driver it821x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = it821x,
+ .probe = it821x_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init it821x_init(void)
+{
+ return pci_register_driver(&it821x_pci_driver);
+}
+
+
+static void __exit it821x_exit(void)
+{
+ pci_unregister_driver(&it821x_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, it821x);
+MODULE_VERSION(DRV_VERSION);
+
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
+
+module_init(it821x_init);
+module_exit(it821x_exit);
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
new file mode 100644
index 00000000000..be3a866b111
--- /dev/null
+++ b/drivers/ata/pata_jmicron.c
@@ -0,0 +1,265 @@
+/*
+ * pata_jmicron.c - JMicron ATA driver for non AHCI mode. This drives the
+ * PATA port of the controller. The SATA ports are
+ * driven by AHCI in the usual configuration although
+ * this driver can handle other setups if we need it.
+ *
+ * (c) 2006 Red Hat <alan@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_jmicron"
+#define DRV_VERSION "0.1.2"
+
+typedef enum {
+ PORT_PATA0 = 0,
+ PORT_PATA1 = 1,
+ PORT_SATA = 2,
+} port_type;
+
+/**
+ * jmicron_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform the PATA port setup we need.
+
+ * On the Jmicron 361/363 there is a single PATA port that can be mapped
+ * either as primary or secondary (or neither). We don't do any policy
+ * and setup here. We assume that has been done by init_one and the
+ * BIOS.
+ */
+
+static int jmicron_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 control;
+ u32 control5;
+ int port_mask = 1<< (4 * ap->port_no);
+ int port = ap->port_no;
+ port_type port_map[2];
+
+ /* Check if our port is enabled */
+ pci_read_config_dword(pdev, 0x40, &control);
+ if ((control & port_mask) == 0)
+ return -ENOENT;
+
+ /* There are two basic mappings. One has the two SATA ports merged
+ as master/slave and the secondary as PATA, the other has only the
+ SATA port mapped */
+ if (control & (1 << 23)) {
+ port_map[0] = PORT_SATA;
+ port_map[1] = PORT_PATA0;
+ } else {
+ port_map[0] = PORT_SATA;
+ port_map[1] = PORT_SATA;
+ }
+
+ /* The 365/366 may have this bit set to map the second PATA port
+ as the internal primary channel */
+ pci_read_config_dword(pdev, 0x80, &control5);
+ if (control5 & (1<<24))
+ port_map[0] = PORT_PATA1;
+
+ /* The two ports may then be logically swapped by the firmware */
+ if (control & (1 << 22))
+ port = port ^ 1;
+
+ /*
+ * Now we know which physical port we are talking about we can
+ * actually do our cable checking etc. Thankfully we don't need
+ * to do the plumbing for other cases.
+ */
+ switch (port_map[port])
+ {
+ case PORT_PATA0:
+ if (control & (1 << 5))
+ return 0;
+ if (control & (1 << 3)) /* 40/80 pin primary */
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ break;
+ case PORT_PATA1:
+ /* Bit 21 is set if the port is enabled */
+ if ((control5 & (1 << 21)) == 0)
+ return 0;
+ if (control5 & (1 << 19)) /* 40/80 pin secondary */
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+ break;
+ case PORT_SATA:
+ ap->cbl = ATA_CBL_SATA;
+ break;
+ }
+ return ata_std_prereset(ap);
+}
+
+/**
+ * jmicron_error_handler - Setup and error handler
+ * @ap: Port to handle
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void jmicron_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/* No PIO or DMA methods needed for this device */
+
+static struct scsi_host_template jmicron_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* Special handling needed if you have sector or LBA48 limits */
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations jmicron_ops = {
+ .port_disable = ata_port_disable,
+
+ /* Task file is PCI ATA format, use helpers */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = jmicron_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ /* IRQ-related hooks */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * jmicron_init_one - Register Jmicron ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in jmicron_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &jmicron_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+
+ .port_ops = &jmicron_ops,
+ };
+ struct ata_port_info *port_info[2] = { &info, &info };
+
+ u32 reg;
+
+ if (id->driver_data != 368) {
+ /* Put the controller into AHCI mode in case the AHCI driver
+ has not yet been loaded. This can be done with either
+ function present */
+
+ /* FIXME: We may want a way to override this in future */
+ pci_write_config_byte(pdev, 0x41, 0xa1);
+ }
+
+ /* PATA controller is fn 1, AHCI is fn 0 */
+ if (PCI_FUNC(pdev->devfn) != 1)
+ return -ENODEV;
+
+ if ( id->driver_data == 365 || id->driver_data == 366) {
+ /* The 365/66 have two PATA channels, redirect the second */
+ pci_read_config_dword(pdev, 0x80, &reg);
+ reg |= (1 << 24); /* IDE1 to PATA IDE secondary */
+ pci_write_config_dword(pdev, 0x80, reg);
+ }
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id jmicron_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+ { } /* terminate list */
+};
+
+static struct pci_driver jmicron_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = jmicron_pci_tbl,
+ .probe = jmicron_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init jmicron_init(void)
+{
+ return pci_register_driver(&jmicron_pci_driver);
+}
+
+static void __exit jmicron_exit(void)
+{
+ pci_unregister_driver(&jmicron_pci_driver);
+}
+
+module_init(jmicron_init);
+module_exit(jmicron_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for Jmicron PATA ports");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
new file mode 100644
index 00000000000..10231ef731d
--- /dev/null
+++ b/drivers/ata/pata_legacy.c
@@ -0,0 +1,949 @@
+/*
+ * pata-legacy.c - Legacy port PATA/SATA controller driver.
+ * Copyright 2005/2006 Red Hat <alan@redhat.com>, all rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * An ATA driver for the legacy ATA ports.
+ *
+ * Data Sources:
+ * Opti 82C465/82C611 support: Data sheets at opti-inc.com
+ * HT6560 series:
+ * Promise 20230/20620:
+ * http://www.ryston.cz/petr/vlb/pdc20230b.html
+ * http://www.ryston.cz/petr/vlb/pdc20230c.html
+ * http://www.ryston.cz/petr/vlb/pdc20630.html
+ *
+ * Unsupported but docs exist:
+ * Appian/Adaptec AIC25VL01/Cirrus Logic PD7220
+ * Winbond W83759A
+ *
+ * This driver handles legacy (that is "ISA/VLB side") IDE ports found
+ * on PC class systems. There are three hybrid devices that are exceptions
+ * The Cyrix 5510/5520 where a pre SFF ATA device is on the bridge and
+ * the MPIIX where the tuning is PCI side but the IDE is "ISA side".
+ *
+ * Specific support is included for the ht6560a/ht6560b/opti82c611a/
+ * opti82c465mv/promise 20230c/20630
+ *
+ * Use the autospeed and pio_mask options with:
+ * Appian ADI/2 aka CLPD7220 or AIC25VL01.
+ * Use the jumpers, autospeed and set pio_mask to the mode on the jumpers with
+ * Goldstar GM82C711, PIC-1288A-125, UMC 82C871F, Winbond W83759,
+ * Winbond W83759A, Promise PDC20230-B
+ *
+ * For now use autospeed and pio_mask as above with the W83759A. This may
+ * change.
+ *
+ * TODO
+ * Merge existing pata_qdi driver
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME "pata_legacy"
+#define DRV_VERSION "0.5.3"
+
+#define NR_HOST 6
+
+static int legacy_port[NR_HOST] = { 0x1f0, 0x170, 0x1e8, 0x168, 0x1e0, 0x160 };
+static int legacy_irq[NR_HOST] = { 15, 14, 11, 10, 8, 12 };
+
+struct legacy_data {
+ unsigned long timing;
+ u8 clock[2];
+ u8 last;
+ int fast;
+ struct platform_device *platform_dev;
+
+};
+
+static struct legacy_data legacy_data[NR_HOST];
+static struct ata_host *legacy_host[NR_HOST];
+static int nr_legacy_host;
+
+
+static int probe_all; /* Set to check all ISA port ranges */
+static int ht6560a; /* HT 6560A on primary 1, secondary 2, both 3 */
+static int ht6560b; /* HT 6560A on primary 1, secondary 2, both 3 */
+static int opti82c611a; /* Opti82c611A on primary 1, secondary 2, both 3 */
+static int opti82c46x; /* Opti 82c465MV present (pri/sec autodetect) */
+static int autospeed; /* Chip present which snoops speed changes */
+static int pio_mask = 0x1F; /* PIO range for autospeed devices */
+
+/**
+ * legacy_set_mode - mode setting
+ * @ap: IDE interface
+ *
+ * Use a non standard set_mode function. We don't want to be tuned.
+ *
+ * The BIOS configured everything. Our job is not to fiddle. Just use
+ * whatever PIO the hardware is using and leave it at that. When we
+ * get some kind of nice user driven API for control then we can
+ * expand on this as per hdparm in the base kernel.
+ */
+
+static void legacy_set_mode(struct ata_port *ap)
+{
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+}
+
+static struct scsi_host_template legacy_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+/*
+ * These ops are used if the user indicates the hardware
+ * snoops the commands to decide on the mode and handles the
+ * mode selection "magically" itself. Several legacy controllers
+ * do this. The mode range can be set if it is not 0x1F by setting
+ * pio_mask as well.
+ */
+
+static struct ata_port_operations simple_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations legacy_port_ops = {
+ .set_mode = legacy_set_mode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Promise 20230C and 20620 support
+ *
+ * This controller supports PIO0 to PIO2. We set PIO timings conservatively to
+ * allow for 50MHz Vesa Local Bus. The 20620 DMA support is weird being DMA to
+ * controller and PIO'd to the host and not supported.
+ */
+
+static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int tries = 5;
+ int pio = adev->pio_mode - XFER_PIO_0;
+ u8 rt;
+ unsigned long flags;
+
+ /* Safe as UP only. Force I/Os to occur together */
+
+ local_irq_save(flags);
+
+ /* Unlock the control interface */
+ do
+ {
+ inb(0x1F5);
+ outb(inb(0x1F2) | 0x80, 0x1F2);
+ inb(0x1F2);
+ inb(0x3F6);
+ inb(0x3F6);
+ inb(0x1F2);
+ inb(0x1F2);
+ }
+ while((inb(0x1F2) & 0x80) && --tries);
+
+ local_irq_restore(flags);
+
+ outb(inb(0x1F4) & 0x07, 0x1F4);
+
+ rt = inb(0x1F3);
+ rt &= 0x07 << (3 * adev->devno);
+ if (pio)
+ rt |= (1 + 3 * pio) << (3 * adev->devno);
+
+ udelay(100);
+ outb(inb(0x1F2) | 0x01, 0x1F2);
+ udelay(100);
+ inb(0x1F5);
+
+}
+
+static void pdc_data_xfer_vlb(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ int slop = buflen & 3;
+ unsigned long flags;
+
+ if (ata_id_has_dword_io(adev->id)) {
+ local_irq_save(flags);
+
+ /* Perform the 32bit I/O synchronization sequence */
+ inb(ap->ioaddr.nsect_addr);
+ inb(ap->ioaddr.nsect_addr);
+ inb(ap->ioaddr.nsect_addr);
+
+ /* Now the data */
+
+ if (write_data)
+ outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+
+ if (unlikely(slop)) {
+ u32 pad;
+ if (write_data) {
+ memcpy(&pad, buf + buflen - slop, slop);
+ outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ } else {
+ pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ memcpy(buf + buflen - slop, &pad, slop);
+ }
+ }
+ local_irq_restore(flags);
+ }
+ else
+ ata_pio_data_xfer_noirq(adev, buf, buflen, write_data);
+}
+
+static struct ata_port_operations pdc20230_port_ops = {
+ .set_piomode = pdc20230_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = pdc_data_xfer_vlb,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Holtek 6560A support
+ *
+ * This controller supports PIO0 to PIO2 (no IORDY even though higher timings
+ * can be loaded).
+ */
+
+static void ht6560a_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover;
+ struct ata_timing t;
+
+ /* Get the timing data in cycles. For now play safe at 50Mhz */
+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+
+ active = FIT(t.active, 2, 15);
+ recover = FIT(t.recover, 4, 15);
+
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+
+ outb(recover << 4 | active, ap->ioaddr.device_addr);
+ inb(ap->ioaddr.status_addr);
+}
+
+static struct ata_port_operations ht6560a_port_ops = {
+ .set_piomode = ht6560a_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Holtek 6560B support
+ *
+ * This controller supports PIO0 to PIO4. We honour the BIOS/jumper FIFO setting
+ * unless we see an ATAPI device in which case we force it off.
+ *
+ * FIXME: need to implement 2nd channel support.
+ */
+
+static void ht6560b_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover;
+ struct ata_timing t;
+
+ /* Get the timing data in cycles. For now play safe at 50Mhz */
+ ata_timing_compute(adev, adev->pio_mode, &t, 20000, 1000);
+
+ active = FIT(t.active, 2, 15);
+ recover = FIT(t.recover, 2, 16);
+ recover &= 0x15;
+
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+ inb(0x3E6);
+
+ outb(recover << 4 | active, ap->ioaddr.device_addr);
+
+ if (adev->class != ATA_DEV_ATA) {
+ u8 rconf = inb(0x3E6);
+ if (rconf & 0x24) {
+ rconf &= ~ 0x24;
+ outb(rconf, 0x3E6);
+ }
+ }
+ inb(ap->ioaddr.status_addr);
+}
+
+static struct ata_port_operations ht6560b_port_ops = {
+ .set_piomode = ht6560b_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Opti core chipset helpers
+ */
+
+/**
+ * opti_syscfg - read OPTI chipset configuration
+ * @reg: Configuration register to read
+ *
+ * Returns the value of an OPTI system board configuration register.
+ */
+
+static u8 opti_syscfg(u8 reg)
+{
+ unsigned long flags;
+ u8 r;
+
+ /* Uniprocessor chipset and must force cycles adjancent */
+ local_irq_save(flags);
+ outb(reg, 0x22);
+ r = inb(0x24);
+ local_irq_restore(flags);
+ return r;
+}
+
+/*
+ * Opti 82C611A
+ *
+ * This controller supports PIO0 to PIO3.
+ */
+
+static void opti82c611a_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover, setup;
+ struct ata_timing t;
+ struct ata_device *pair = ata_dev_pair(adev);
+ int clock;
+ int khz[4] = { 50000, 40000, 33000, 25000 };
+ u8 rc;
+
+ /* Enter configuration mode */
+ inw(ap->ioaddr.error_addr);
+ inw(ap->ioaddr.error_addr);
+ outb(3, ap->ioaddr.nsect_addr);
+
+ /* Read VLB clock strapping */
+ clock = 1000000000 / khz[inb(ap->ioaddr.lbah_addr) & 0x03];
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
+
+ /* Setup timing is shared */
+ if (pair) {
+ struct ata_timing tp;
+ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);
+
+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ }
+
+ active = FIT(t.active, 2, 17) - 2;
+ recover = FIT(t.recover, 1, 16) - 1;
+ setup = FIT(t.setup, 1, 4) - 1;
+
+ /* Select the right timing bank for write timing */
+ rc = inb(ap->ioaddr.lbal_addr);
+ rc &= 0x7F;
+ rc |= (adev->devno << 7);
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Write the timings */
+ outb(active << 4 | recover, ap->ioaddr.error_addr);
+
+ /* Select the right bank for read timings, also
+ load the shared timings for address */
+ rc = inb(ap->ioaddr.device_addr);
+ rc &= 0xC0;
+ rc |= adev->devno; /* Index select */
+ rc |= (setup << 4) | 0x04;
+ outb(rc, ap->ioaddr.device_addr);
+
+ /* Load the read timings */
+ outb(active << 4 | recover, ap->ioaddr.data_addr);
+
+ /* Ensure the timing register mode is right */
+ rc = inb (ap->ioaddr.lbal_addr);
+ rc &= 0x73;
+ rc |= 0x84;
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Exit command mode */
+ outb(0x83, ap->ioaddr.nsect_addr);
+}
+
+
+static struct ata_port_operations opti82c611a_port_ops = {
+ .set_piomode = opti82c611a_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/*
+ * Opti 82C465MV
+ *
+ * This controller supports PIO0 to PIO3. Unlike the 611A the MVB
+ * version is dual channel but doesn't have a lot of unique registers.
+ */
+
+static void opti82c46x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ u8 active, recover, setup;
+ struct ata_timing t;
+ struct ata_device *pair = ata_dev_pair(adev);
+ int clock;
+ int khz[4] = { 50000, 40000, 33000, 25000 };
+ u8 rc;
+ u8 sysclk;
+
+ /* Get the clock */
+ sysclk = opti_syscfg(0xAC) & 0xC0; /* BIOS set */
+
+ /* Enter configuration mode */
+ inw(ap->ioaddr.error_addr);
+ inw(ap->ioaddr.error_addr);
+ outb(3, ap->ioaddr.nsect_addr);
+
+ /* Read VLB clock strapping */
+ clock = 1000000000 / khz[sysclk];
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, clock, 1000);
+
+ /* Setup timing is shared */
+ if (pair) {
+ struct ata_timing tp;
+ ata_timing_compute(pair, pair->pio_mode, &tp, clock, 1000);
+
+ ata_timing_merge(&t, &tp, &t, ATA_TIMING_SETUP);
+ }
+
+ active = FIT(t.active, 2, 17) - 2;
+ recover = FIT(t.recover, 1, 16) - 1;
+ setup = FIT(t.setup, 1, 4) - 1;
+
+ /* Select the right timing bank for write timing */
+ rc = inb(ap->ioaddr.lbal_addr);
+ rc &= 0x7F;
+ rc |= (adev->devno << 7);
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Write the timings */
+ outb(active << 4 | recover, ap->ioaddr.error_addr);
+
+ /* Select the right bank for read timings, also
+ load the shared timings for address */
+ rc = inb(ap->ioaddr.device_addr);
+ rc &= 0xC0;
+ rc |= adev->devno; /* Index select */
+ rc |= (setup << 4) | 0x04;
+ outb(rc, ap->ioaddr.device_addr);
+
+ /* Load the read timings */
+ outb(active << 4 | recover, ap->ioaddr.data_addr);
+
+ /* Ensure the timing register mode is right */
+ rc = inb (ap->ioaddr.lbal_addr);
+ rc &= 0x73;
+ rc |= 0x84;
+ outb(rc, ap->ioaddr.lbal_addr);
+
+ /* Exit command mode */
+ outb(0x83, ap->ioaddr.nsect_addr);
+
+ /* We need to know this for quad device on the MVB */
+ ap->host->private_data = ap;
+}
+
+/**
+ * opt82c465mv_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings. The
+ * MVB has a single set of timing registers and these are shared
+ * across channels. As there are two registers we really ought to
+ * track the last two used values as a sort of register window. For
+ * now we just reload on a channel switch. On the single channel
+ * setup this condition never fires so we do nothing extra.
+ *
+ * FIXME: dual channel needs ->serialize support
+ */
+
+static unsigned int opti82c46x_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /* If timings are set and for the wrong channel (2nd test is
+ due to a libata shortcoming and will eventually go I hope) */
+ if (ap->host->private_data != ap->host
+ && ap->host->private_data != NULL)
+ opti82c46x_set_piomode(ap, adev);
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct ata_port_operations opti82c46x_port_ops = {
+ .set_piomode = opti82c46x_set_piomode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = opti82c46x_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+
+/**
+ * legacy_init_one - attach a legacy interface
+ * @port: port number
+ * @io: I/O port start
+ * @ctrl: control port
+ * @irq: interrupt line
+ *
+ * Register an ISA bus IDE interface. Such interfaces are PIO and we
+ * assume do not support IRQ sharing.
+ */
+
+static __init int legacy_init_one(int port, unsigned long io, unsigned long ctrl, int irq)
+{
+ struct legacy_data *ld = &legacy_data[nr_legacy_host];
+ struct ata_probe_ent ae;
+ struct platform_device *pdev;
+ int ret = -EBUSY;
+ struct ata_port_operations *ops = &legacy_port_ops;
+ int pio_modes = pio_mask;
+ u32 mask = (1 << port);
+
+ if (request_region(io, 8, "pata_legacy") == NULL)
+ return -EBUSY;
+ if (request_region(ctrl, 1, "pata_legacy") == NULL)
+ goto fail_io;
+
+ pdev = platform_device_register_simple(DRV_NAME, nr_legacy_host, NULL, 0);
+ if (pdev == NULL)
+ goto fail_dev;
+
+ if (ht6560a & mask) {
+ ops = &ht6560a_port_ops;
+ pio_modes = 0x07;
+ }
+ if (ht6560b & mask) {
+ ops = &ht6560b_port_ops;
+ pio_modes = 0x1F;
+ }
+ if (opti82c611a & mask) {
+ ops = &opti82c611a_port_ops;
+ pio_modes = 0x0F;
+ }
+ if (opti82c46x & mask) {
+ ops = &opti82c46x_port_ops;
+ pio_modes = 0x0F;
+ }
+
+ /* Probe for automatically detectable controllers */
+
+ if (io == 0x1F0 && ops == &legacy_port_ops) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /* Probes */
+ inb(0x1F5);
+ outb(inb(0x1F2) | 0x80, 0x1F2);
+ inb(0x1F2);
+ inb(0x3F6);
+ inb(0x3F6);
+ inb(0x1F2);
+ inb(0x1F2);
+
+ if ((inb(0x1F2) & 0x80) == 0) {
+ /* PDC20230c or 20630 ? */
+ printk(KERN_INFO "PDC20230-C/20630 VLB ATA controller detected.\n");
+ pio_modes = 0x07;
+ ops = &pdc20230_port_ops;
+ udelay(100);
+ inb(0x1F5);
+ } else {
+ outb(0x55, 0x1F2);
+ inb(0x1F2);
+ inb(0x1F2);
+ if (inb(0x1F2) == 0x00) {
+ printk(KERN_INFO "PDC20230-B VLB ATA controller detected.\n");
+ }
+ }
+ local_irq_restore(flags);
+ }
+
+
+ /* Chip does mode setting by command snooping */
+ if (ops == &legacy_port_ops && (autospeed & mask))
+ ops = &simple_port_ops;
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &pdev->dev;
+ ae.port_ops = ops;
+ ae.sht = &legacy_sht;
+ ae.n_ports = 1;
+ ae.pio_mask = pio_modes;
+ ae.irq = irq;
+ ae.irq_flags = 0;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST;
+ ae.port[0].cmd_addr = io;
+ ae.port[0].altstatus_addr = ctrl;
+ ae.port[0].ctl_addr = ctrl;
+ ata_std_ports(&ae.port[0]);
+ ae.private_data = ld;
+
+ ret = ata_device_add(&ae);
+ if (ret == 0) {
+ ret = -ENODEV;
+ goto fail;
+ }
+ legacy_host[nr_legacy_host++] = dev_get_drvdata(&pdev->dev);
+ ld->platform_dev = pdev;
+ return 0;
+
+fail:
+ platform_device_unregister(pdev);
+fail_dev:
+ release_region(ctrl, 1);
+fail_io:
+ release_region(io, 8);
+ return ret;
+}
+
+/**
+ * legacy_check_special_cases - ATA special cases
+ * @p: PCI device to check
+ * @master: set this if we find an ATA master
+ * @master: set this if we find an ATA secondary
+ *
+ * A small number of vendors implemented early PCI ATA interfaces on bridge logic
+ * without the ATA interface being PCI visible. Where we have a matching PCI driver
+ * we must skip the relevant device here. If we don't know about it then the legacy
+ * driver is the right driver anyway.
+ */
+
+static void legacy_check_special_cases(struct pci_dev *p, int *primary, int *secondary)
+{
+ /* Cyrix CS5510 pre SFF MWDMA ATA on the bridge */
+ if (p->vendor == 0x1078 && p->device == 0x0000) {
+ *primary = *secondary = 1;
+ return;
+ }
+ /* Cyrix CS5520 pre SFF MWDMA ATA on the bridge */
+ if (p->vendor == 0x1078 && p->device == 0x0002) {
+ *primary = *secondary = 1;
+ return;
+ }
+ /* Intel MPIIX - PIO ATA on non PCI side of bridge */
+ if (p->vendor == 0x8086 && p->device == 0x1234) {
+ u16 r;
+ pci_read_config_word(p, 0x6C, &r);
+ if (r & 0x8000) { /* ATA port enabled */
+ if (r & 0x4000)
+ *secondary = 1;
+ else
+ *primary = 1;
+ }
+ return;
+ }
+}
+
+
+/**
+ * legacy_init - attach legacy interfaces
+ *
+ * Attach legacy IDE interfaces by scanning the usual IRQ/port suspects.
+ * Right now we do not scan the ide0 and ide1 address but should do so
+ * for non PCI systems or systems with no PCI IDE legacy mode devices.
+ * If you fix that note there are special cases to consider like VLB
+ * drivers and CS5510/20.
+ */
+
+static __init int legacy_init(void)
+{
+ int i;
+ int ct = 0;
+ int primary = 0;
+ int secondary = 0;
+ int last_port = NR_HOST;
+
+ struct pci_dev *p = NULL;
+
+ for_each_pci_dev(p) {
+ int r;
+ /* Check for any overlap of the system ATA mappings. Native mode controllers
+ stuck on these addresses or some devices in 'raid' mode won't be found by
+ the storage class test */
+ for (r = 0; r < 6; r++) {
+ if (pci_resource_start(p, r) == 0x1f0)
+ primary = 1;
+ if (pci_resource_start(p, r) == 0x170)
+ secondary = 1;
+ }
+ /* Check for special cases */
+ legacy_check_special_cases(p, &primary, &secondary);
+
+ /* If PCI bus is present then don't probe for tertiary legacy ports */
+ if (probe_all == 0)
+ last_port = 2;
+ }
+
+ /* If an OPTI 82C46X is present find out where the channels are */
+ if (opti82c46x) {
+ static const char *optis[4] = {
+ "3/463MV", "5MV",
+ "5MVA", "5MVB"
+ };
+ u8 chans = 1;
+ u8 ctrl = (opti_syscfg(0x30) & 0xC0) >> 6;
+
+ opti82c46x = 3; /* Assume master and slave first */
+ printk(KERN_INFO DRV_NAME ": Opti 82C46%s chipset support.\n", optis[ctrl]);
+ if (ctrl == 3)
+ chans = (opti_syscfg(0x3F) & 0x20) ? 2 : 1;
+ ctrl = opti_syscfg(0xAC);
+ /* Check enabled and this port is the 465MV port. On the
+ MVB we may have two channels */
+ if (ctrl & 8) {
+ if (ctrl & 4)
+ opti82c46x = 2; /* Slave */
+ else
+ opti82c46x = 1; /* Master */
+ if (chans == 2)
+ opti82c46x = 3; /* Master and Slave */
+ } /* Slave only */
+ else if (chans == 1)
+ opti82c46x = 1;
+ }
+
+ for (i = 0; i < last_port; i++) {
+ /* Skip primary if we have seen a PCI one */
+ if (i == 0 && primary == 1)
+ continue;
+ /* Skip secondary if we have seen a PCI one */
+ if (i == 1 && secondary == 1)
+ continue;
+ if (legacy_init_one(i, legacy_port[i],
+ legacy_port[i] + 0x0206,
+ legacy_irq[i]) == 0)
+ ct++;
+ }
+ if (ct != 0)
+ return 0;
+ return -ENODEV;
+}
+
+static __exit void legacy_exit(void)
+{
+ int i;
+
+ for (i = 0; i < nr_legacy_host; i++) {
+ struct legacy_data *ld = &legacy_data[i];
+ struct ata_port *ap =legacy_host[i]->ports[0];
+ unsigned long io = ap->ioaddr.cmd_addr;
+ unsigned long ctrl = ap->ioaddr.ctl_addr;
+ ata_host_remove(legacy_host[i]);
+ platform_device_unregister(ld->platform_dev);
+ if (ld->timing)
+ release_region(ld->timing, 2);
+ release_region(io, 8);
+ release_region(ctrl, 1);
+ }
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for legacy ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_param(probe_all, int, 0);
+module_param(autospeed, int, 0);
+module_param(ht6560a, int, 0);
+module_param(ht6560b, int, 0);
+module_param(opti82c611a, int, 0);
+module_param(opti82c46x, int, 0);
+module_param(pio_mask, int, 0);
+
+module_init(legacy_init);
+module_exit(legacy_exit);
+
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
new file mode 100644
index 00000000000..3c65393c1f0
--- /dev/null
+++ b/drivers/ata/pata_mpiix.c
@@ -0,0 +1,310 @@
+/*
+ * pata_mpiix.c - Intel MPIIX PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * The MPIIX is different enough to the PIIX4 and friends that we give it
+ * a separate driver. The old ide/pci code handles this by just not tuning
+ * MPIIX at all.
+ *
+ * The MPIIX also differs in another important way from the majority of PIIX
+ * devices. The chip is a bridge (pardon the pun) between the old world of
+ * ISA IDE and PCI IDE. Although the ATA timings are PCI configured the actual
+ * IDE controller is not decoded in PCI space and the chip does not claim to
+ * be IDE class PCI. This requires slightly non-standard probe logic compared
+ * with PCI IDE and also that we do not disable the device when our driver is
+ * unloaded (as it has many other functions).
+ *
+ * The driver conciously keeps this logic internally to avoid pushing quirky
+ * PATA history into the clean libata layer.
+ *
+ * Thinkpad specific note: If you boot an MPIIX using a thinkpad with a PCMCIA
+ * hard disk present this driver will not detect it. This is not a bug. In this
+ * configuration the secondary port of the MPIIX is disabled and the addresses
+ * are decoded by the PCMCIA bridge and therefore are for a generic IDE driver
+ * to operate.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_mpiix"
+#define DRV_VERSION "0.7.2"
+
+enum {
+ IDETIM = 0x6C, /* IDE control register */
+ IORDY = (1 << 1),
+ PPE = (1 << 2),
+ FTIM = (1 << 0),
+ ENABLED = (1 << 15),
+ SECONDARY = (1 << 14)
+};
+
+static int mpiix_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits mpiix_enable_bits[] = {
+ { 0x6D, 1, 0x80, 0x80 },
+ { 0x6F, 1, 0x80, 0x80 }
+ };
+
+ if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * mpiix_error_handler - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The MPIIX has the enable bits in a different place
+ * to PIIX4 and friends. As a pure PIO device it has no cable detect
+ */
+
+static void mpiix_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, mpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * mpiix_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. The MPIIX allows us to program the
+ * IORDY sample point (2-5 clocks), recovery 1-4 clocks and whether
+ * prefetching or iordy are used.
+ *
+ * This would get very ugly because we can only program timing for one
+ * device at a time, the other gets PIO0. Fortunately libata calls
+ * our qc_issue_prot command before a command is issued so we can
+ * flip the timings back and forth to reduce the pain.
+ */
+
+static void mpiix_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ int control = 0;
+ int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 idetim;
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ pci_read_config_word(pdev, IDETIM, &idetim);
+ /* Mask the IORDY/TIME/PPE0 bank for this device */
+ if (adev->class == ATA_DEV_ATA)
+ control |= PPE; /* PPE enable for disk */
+ if (ata_pio_need_iordy(adev))
+ control |= IORDY; /* IORDY */
+ if (pio > 0)
+ control |= FTIM; /* This drive is on the fast timing bank */
+
+ /* Mask out timing and clear both TIME bank selects */
+ idetim &= 0xCCEE;
+ idetim &= ~(0x07 << (2 * adev->devno));
+ idetim |= (control << (2 * adev->devno));
+
+ idetim |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ pci_write_config_word(pdev, IDETIM, idetim);
+
+ /* We use ap->private_data as a pointer to the device currently
+ loaded for timing */
+ ap->private_data = adev;
+}
+
+/**
+ * mpiix_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * that, even if we get this wrong, cycles to the other device will
+ * be made PIO0.
+ */
+
+static unsigned int mpiix_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /* If modes have been configured and the channel data is not loaded
+ then load it. We have to check if pio_mode is set as the core code
+ does not set adev->pio_mode to XFER_PIO_0 while probing as would be
+ logical */
+
+ if (adev->pio_mode && adev != ap->private_data)
+ mpiix_set_piomode(ap, adev);
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template mpiix_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations mpiix_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = mpiix_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = mpiix_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = mpiix_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ /* Single threaded by the PCI probe logic */
+ static struct ata_probe_ent probe[2];
+ static int printed_version;
+ u16 idetim;
+ int enabled;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ /* MPIIX has many functions which can be turned on or off according
+ to other devices present. Make sure IDE is enabled before we try
+ and use it */
+
+ pci_read_config_word(dev, IDETIM, &idetim);
+ if (!(idetim & ENABLED))
+ return -ENODEV;
+
+ /* We do our own plumbing to avoid leaking special cases for whacko
+ ancient hardware into the core code. There are two issues to
+ worry about. #1 The chip is a bridge so if in legacy mode and
+ without BARs set fools the setup. #2 If you pci_disable_device
+ the MPIIX your box goes castors up */
+
+ INIT_LIST_HEAD(&probe[0].node);
+ probe[0].dev = pci_dev_to_dev(dev);
+ probe[0].port_ops = &mpiix_port_ops;
+ probe[0].sht = &mpiix_sht;
+ probe[0].pio_mask = 0x1F;
+ probe[0].irq = 14;
+ probe[0].irq_flags = SA_SHIRQ;
+ probe[0].port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ probe[0].n_ports = 1;
+ probe[0].port[0].cmd_addr = 0x1F0;
+ probe[0].port[0].ctl_addr = 0x3F6;
+ probe[0].port[0].altstatus_addr = 0x3F6;
+
+ /* The secondary lurks at different addresses but is otherwise
+ the same beastie */
+
+ INIT_LIST_HEAD(&probe[1].node);
+ probe[1] = probe[0];
+ probe[1].irq = 15;
+ probe[1].port[0].cmd_addr = 0x170;
+ probe[1].port[0].ctl_addr = 0x376;
+ probe[1].port[0].altstatus_addr = 0x376;
+
+ /* Let libata fill in the port details */
+ ata_std_ports(&probe[0].port[0]);
+ ata_std_ports(&probe[1].port[0]);
+
+ /* Now add the port that is active */
+ enabled = (idetim & SECONDARY) ? 1 : 0;
+
+ if (ata_device_add(&probe[enabled]))
+ return 0;
+ return -ENODEV;
+}
+
+/**
+ * mpiix_remove_one - device unload
+ * @pdev: PCI device being removed
+ *
+ * Handle an unplug/unload event for a PCI device. Unload the
+ * PCI driver but do not use the default handler as we *MUST NOT*
+ * disable the device as it has other functions.
+ */
+
+static void __devexit mpiix_remove_one(struct pci_dev *pdev)
+{
+ struct device *dev = pci_dev_to_dev(pdev);
+ struct ata_host *host = dev_get_drvdata(dev);
+
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+}
+
+
+
+static const struct pci_device_id mpiix[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
+ { 0, },
+};
+
+static struct pci_driver mpiix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = mpiix,
+ .probe = mpiix_init_one,
+ .remove = mpiix_remove_one
+};
+
+static int __init mpiix_init(void)
+{
+ return pci_register_driver(&mpiix_pci_driver);
+}
+
+
+static void __exit mpiix_exit(void)
+{
+ pci_unregister_driver(&mpiix_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, mpiix);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(mpiix_init);
+module_exit(mpiix_exit);
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
new file mode 100644
index 00000000000..76eb9c90bee
--- /dev/null
+++ b/drivers/ata/pata_netcell.c
@@ -0,0 +1,174 @@
+/*
+ * pata_netcell.c - Netcell PATA driver
+ *
+ * (c) 2006 Red Hat <alan@redhat.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_netcell"
+#define DRV_VERSION "0.1.5"
+
+/**
+ * netcell_probe_init - check for 40/80 pin
+ * @ap: Port
+ *
+ * Cables are handled by the RAID controller. Report 80 pin.
+ */
+
+static int netcell_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * netcell_probe_reset - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void netcell_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, netcell_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/* No PIO or DMA methods needed for this device */
+
+static struct scsi_host_template netcell_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ /* Special handling needed if you have sector or LBA48 limits */
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ /* Use standard CHS mapping rules */
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations netcell_ops = {
+ .port_disable = ata_port_disable,
+
+ /* Task file is PCI ATA format, use helpers */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = netcell_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ /* BMDMA handling is PCI ATA format, use helpers */
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ /* IRQ-related hooks */
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ /* Generic PATA PCI ATA helpers */
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * netcell_init_one - Register Netcell ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in netcell_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &netcell_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ /* Actually we don't really care about these as the
+ firmware deals with it */
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* UDMA 133 */
+ .port_ops = &netcell_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* Any chip specific setup/optimisation/messages here */
+ ata_pci_clear_simplex(pdev);
+
+ /* And let the library code do the work */
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id netcell_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+ { } /* terminate list */
+};
+
+static struct pci_driver netcell_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = netcell_pci_tbl,
+ .probe = netcell_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init netcell_init(void)
+{
+ return pci_register_driver(&netcell_pci_driver);
+}
+
+static void __exit netcell_exit(void)
+{
+ pci_unregister_driver(&netcell_pci_driver);
+}
+
+module_init(netcell_init);
+module_exit(netcell_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for Netcell PATA RAID");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, netcell_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
new file mode 100644
index 00000000000..2005a95f48f
--- /dev/null
+++ b/drivers/ata/pata_ns87410.c
@@ -0,0 +1,233 @@
+/*
+ * pata_ns87410.c - National Semiconductor 87410 PATA for new ATA layer
+ * (C) 2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_ns87410"
+#define DRV_VERSION "0.4.2"
+
+/**
+ * ns87410_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int ns87410_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits ns87410_enable_bits[] = {
+ { 0x43, 1, 0x08, 0x08 },
+ { 0x47, 1, 0x08, 0x08 }
+ };
+
+ if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * ns87410_error_handler - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The MPIIX has the enable bits in a different place
+ * to PIIX4 and friends. As a pure PIO device it has no cable detect
+ */
+
+static void ns87410_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, ns87410_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * ns87410_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program timing data. This is kept per channel not per device,
+ * and only affects the data port.
+ */
+
+static void ns87410_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x40 + 4 * ap->port_no;
+ u8 idetcr, idefr;
+ struct ata_timing at;
+
+ static const u8 activebits[15] = {
+ 0, 1, 2, 3, 4,
+ 5, 5, 6, 6, 6,
+ 6, 7, 7, 7, 7
+ };
+
+ static const u8 recoverbits[12] = {
+ 0, 1, 2, 3, 4, 5, 6, 6, 7, 7, 7, 7
+ };
+
+ pci_read_config_byte(pdev, port + 3, &idefr);
+
+ if (ata_pio_need_iordy(adev))
+ idefr |= 0x04; /* IORDY enable */
+ else
+ idefr &= ~0x04;
+
+ if (ata_timing_compute(adev, adev->pio_mode, &at, 30303, 1) < 0) {
+ dev_printk(KERN_ERR, &pdev->dev, "unknown mode %d.\n", adev->pio_mode);
+ return;
+ }
+
+ at.active = FIT(at.active, 2, 16) - 2;
+ at.setup = FIT(at.setup, 1, 4) - 1;
+ at.recover = FIT(at.recover, 1, 12) - 1;
+
+ idetcr = (at.setup << 6) | (recoverbits[at.recover] << 3) | activebits[at.active];
+
+ pci_write_config_byte(pdev, port, idetcr);
+ pci_write_config_byte(pdev, port + 3, idefr);
+ /* We use ap->private_data as a pointer to the device currently
+ loaded for timing */
+ ap->private_data = adev;
+}
+
+/**
+ * ns87410_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary.
+ */
+
+static unsigned int ns87410_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ /* If modes have been configured and the channel data is not loaded
+ then load it. We have to check if pio_mode is set as the core code
+ does not set adev->pio_mode to XFER_PIO_0 while probing as would be
+ logical */
+
+ if (adev->pio_mode && adev != ap->private_data)
+ ns87410_set_piomode(ap, adev);
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template ns87410_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations ns87410_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = ns87410_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ns87410_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ns87410_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &ns87410_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x0F,
+ .port_ops = &ns87410_port_ops
+ };
+ static struct ata_port_info *port_info[2] = {&info, &info};
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id ns87410[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), },
+ { 0, },
+};
+
+static struct pci_driver ns87410_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = ns87410,
+ .probe = ns87410_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init ns87410_init(void)
+{
+ return pci_register_driver(&ns87410_pci_driver);
+}
+
+
+static void __exit ns87410_exit(void)
+{
+ pci_unregister_driver(&ns87410_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ns87410);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ns87410_init);
+module_exit(ns87410_exit);
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
new file mode 100644
index 00000000000..31a285ca88d
--- /dev/null
+++ b/drivers/ata/pata_oldpiix.c
@@ -0,0 +1,336 @@
+/*
+ * pata_oldpiix.c - Intel PATA/SATA controllers
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * Some parts based on ata_piix.c by Jeff Garzik and others.
+ *
+ * Early PIIX differs significantly from the later PIIX as it lacks
+ * SITRE and the slave timing registers. This means that you have to
+ * set timing per channel, or be clever. Libata tells us whenever it
+ * does drive selection and we use this to reload the timings.
+ *
+ * Because of these behaviour differences PIIX gets its own driver module.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_oldpiix"
+#define DRV_VERSION "0.5.2"
+
+/**
+ * oldpiix_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int oldpiix_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits oldpiix_enable_bits[] = {
+ { 0x41U, 1U, 0x80UL, 0x80UL }, /* port 0 */
+ { 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
+ };
+
+ if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * oldpiix_pata_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void oldpiix_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, oldpiix_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * oldpiix_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. Note that the early PIIX does not have the slave
+ * timing port at 0x44.
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ if (pio > 2)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE IORDY */
+
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ /* Enable PPE, IE and TIME as appropriate. Clear the other
+ drive timing bits */
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCE0;
+ idetm_data |= control;
+ } else {
+ idetm_data &= 0xCC0E;
+ idetm_data |= (control << 4);
+ }
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ pci_write_config_word(dev, idetm_port, idetm_data);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * oldpiix_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ * @isich: True if the device is an ICH and has IOCFG registers
+ *
+ * Set MWDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u8 idetm_port = ap->port_no ? 0x42 : 0x40;
+ u16 idetm_data;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
+
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally along with TIME1. PPE has already
+ * been set when the PIO timing was set.
+ */
+
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned int control;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+
+ pci_read_config_word(dev, idetm_port, &idetm_data);
+
+ control = 3; /* IORDY|TIME0 */
+ /* Intel specifies that the PPE functionality is for disk only */
+ if (adev->class == ATA_DEV_ATA)
+ control |= 4; /* PPE enable */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO into PIO0 */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ /* Enable DMA timing only */
+ control |= 8; /* PIO cycles in PIO0 */
+
+ /* Mask out the relevant control and timing bits we will load. Also
+ clear the other drive TIME register as a precaution */
+ if (adev->devno == 0) {
+ idetm_data &= 0xCCE0;
+ idetm_data |= control;
+ } else {
+ idetm_data &= 0xCC0E;
+ idetm_data |= (control << 4);
+ }
+ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+ pci_write_config_word(dev, idetm_port, idetm_data);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * oldpiix_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * that, even if we get this wrong, cycles to the other device will
+ * be made PIO0.
+ */
+
+static unsigned int oldpiix_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ if (adev != ap->private_data) {
+ if (adev->dma_mode)
+ oldpiix_set_dmamode(ap, adev);
+ else if (adev->pio_mode)
+ oldpiix_set_piomode(ap, adev);
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+
+static struct scsi_host_template oldpiix_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations oldpiix_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = oldpiix_set_piomode,
+ .set_dmamode = oldpiix_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = oldpiix_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = oldpiix_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * oldpiix_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in oldpiix_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &oldpiix_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma1-2 */
+ .port_ops = &oldpiix_pata_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id oldpiix_pci_tbl[] = {
+ { PCI_DEVICE(0x8086, 0x1230), },
+ { } /* terminate list */
+};
+
+static struct pci_driver oldpiix_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = oldpiix_pci_tbl,
+ .probe = oldpiix_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init oldpiix_init(void)
+{
+ return pci_register_driver(&oldpiix_pci_driver);
+}
+
+static void __exit oldpiix_exit(void)
+{
+ pci_unregister_driver(&oldpiix_pci_driver);
+}
+
+
+module_init(oldpiix_init);
+module_exit(oldpiix_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for early PIIX series controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, oldpiix_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
new file mode 100644
index 00000000000..57fe21f3a97
--- /dev/null
+++ b/drivers/ata/pata_opti.c
@@ -0,0 +1,290 @@
+/*
+ * pata_opti.c - ATI PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based on
+ * linux/drivers/ide/pci/opti621.c Version 0.7 Sept 10, 2002
+ *
+ * Copyright (C) 1996-1998 Linus Torvalds & authors (see below)
+ *
+ * Authors:
+ * Jaromir Koutek <miri@punknet.cz>,
+ * Jan Harkes <jaharkes@cwi.nl>,
+ * Mark Lord <mlord@pobox.com>
+ * Some parts of code are from ali14xx.c and from rz1000.c.
+ *
+ * Also consulted the FreeBSD prototype driver by Kevin Day to try
+ * and resolve some confusions. Further documentation can be found in
+ * Ralf Brown's interrupt list
+ *
+ * If you have other variants of the Opti range (Viper/Vendetta) please
+ * try this driver with those PCI idents and report back. For the later
+ * chips see the pata_optidma driver
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_opti"
+#define DRV_VERSION "0.2.5"
+
+enum {
+ READ_REG = 0, /* index of Read cycle timing register */
+ WRITE_REG = 1, /* index of Write cycle timing register */
+ CNTRL_REG = 3, /* index of Control register */
+ STRAP_REG = 5, /* index of Strap register */
+ MISC_REG = 6 /* index of Miscellaneous register */
+};
+
+/**
+ * opti_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int opti_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits opti_enable_bits[] = {
+ { 0x45, 1, 0x80, 0x00 },
+ { 0x40, 1, 0x08, 0x00 }
+ };
+
+ if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * opti_probe_reset - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The Opti needs little handling - we have no UDMA66
+ * capability that needs cable detection. All we must do is check the port
+ * is enabled.
+ */
+
+static void opti_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, opti_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * opti_write_reg - control register setup
+ * @ap: ATA port
+ * @value: value
+ * @reg: control register number
+ *
+ * The Opti uses magic 'trapdoor' register accesses to do configuration
+ * rather than using PCI space as other controllers do. The double inw
+ * on the error register activates configuration mode. We can then write
+ * the control register
+ */
+
+static void opti_write_reg(struct ata_port *ap, u8 val, int reg)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+
+ /* These 3 unlock the control register access */
+ inw(regio + 1);
+ inw(regio + 1);
+ outb(3, regio + 2);
+
+ /* Do the I/O */
+ outb(val, regio + reg);
+
+ /* Relock */
+ outb(0x83, regio + 2);
+}
+
+#if 0
+/**
+ * opti_read_reg - control register read
+ * @ap: ATA port
+ * @reg: control register number
+ *
+ * The Opti uses magic 'trapdoor' register accesses to do configuration
+ * rather than using PCI space as other controllers do. The double inw
+ * on the error register activates configuration mode. We can then read
+ * the control register
+ */
+
+static u8 opti_read_reg(struct ata_port *ap, int reg)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+ u8 ret;
+ inw(regio + 1);
+ inw(regio + 1);
+ outb(3, regio + 2);
+ ret = inb(regio + reg);
+ outb(0x83, regio + 2);
+}
+#endif
+
+/**
+ * opti_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. Timing numbers are taken from
+ * the FreeBSD driver then pre computed to keep the code clean. There
+ * are two tables depending on the hardware clock speed.
+ */
+
+static void opti_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_device *pair = ata_dev_pair(adev);
+ int clock;
+ int pio = adev->pio_mode - XFER_PIO_0;
+ unsigned long regio = ap->ioaddr.cmd_addr;
+ u8 addr;
+
+ /* Address table precomputed with prefetch off and a DCLK of 2 */
+ static const u8 addr_timing[2][5] = {
+ { 0x30, 0x20, 0x20, 0x10, 0x10 },
+ { 0x20, 0x20, 0x10, 0x10, 0x10 }
+ };
+ static const u8 data_rec_timing[2][5] = {
+ { 0x6B, 0x56, 0x42, 0x32, 0x31 },
+ { 0x58, 0x44, 0x32, 0x22, 0x21 }
+ };
+
+ outb(0xff, regio + 5);
+ clock = inw(regio + 5) & 1;
+
+ /*
+ * As with many controllers the address setup time is shared
+ * and must suit both devices if present.
+ */
+
+ addr = addr_timing[clock][pio];
+ if (pair) {
+ /* Hardware constraint */
+ u8 pair_addr = addr_timing[clock][pair->pio_mode - XFER_PIO_0];
+ if (pair_addr > addr)
+ addr = pair_addr;
+ }
+
+ /* Commence primary programming sequence */
+ opti_write_reg(ap, adev->devno, MISC_REG);
+ opti_write_reg(ap, data_rec_timing[clock][pio], READ_REG);
+ opti_write_reg(ap, data_rec_timing[clock][pio], WRITE_REG);
+ opti_write_reg(ap, addr, MISC_REG);
+
+ /* Programming sequence complete, override strapping */
+ opti_write_reg(ap, 0x85, CNTRL_REG);
+}
+
+static struct scsi_host_template opti_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations opti_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = opti_set_piomode,
+/* .set_dmamode = opti_set_dmamode, */
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = opti_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &opti_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &opti_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id opti[] = {
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { 0, },
+};
+
+static struct pci_driver opti_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = opti,
+ .probe = opti_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init opti_init(void)
+{
+ return pci_register_driver(&opti_pci_driver);
+}
+
+
+static void __exit opti_exit(void)
+{
+ pci_unregister_driver(&opti_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Opti 621/621X");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, opti);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(opti_init);
+module_exit(opti_exit);
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
new file mode 100644
index 00000000000..7296a20cd10
--- /dev/null
+++ b/drivers/ata/pata_optidma.c
@@ -0,0 +1,545 @@
+/*
+ * pata_optidma.c - Opti DMA PATA for new ATA layer
+ * (C) 2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * The Opti DMA controllers are related to the older PIO PCI controllers
+ * and indeed the VLB ones. The main differences are that the timing
+ * numbers are now based off PCI clocks not VLB and differ, and that
+ * MWDMA is supported.
+ *
+ * This driver should support Viper-N+, FireStar, FireStar Plus.
+ *
+ * These devices support virtual DMA for read (aka the CS5520). Later
+ * chips support UDMA33, but only if the rest of the board logic does,
+ * so you have to get this right. We don't support the virtual DMA
+ * but we do handle UDMA.
+ *
+ * Bits that are worth knowing
+ * Most control registers are shadowed into I/O registers
+ * 0x1F5 bit 0 tells you if the PCI/VLB clock is 33 or 25Mhz
+ * Virtual DMA registers *move* between rev 0x02 and rev 0x10
+ * UDMA requires a 66MHz FSB
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_optidma"
+#define DRV_VERSION "0.2.2"
+
+enum {
+ READ_REG = 0, /* index of Read cycle timing register */
+ WRITE_REG = 1, /* index of Write cycle timing register */
+ CNTRL_REG = 3, /* index of Control register */
+ STRAP_REG = 5, /* index of Strap register */
+ MISC_REG = 6 /* index of Miscellaneous register */
+};
+
+static int pci_clock; /* 0 = 33 1 = 25 */
+
+/**
+ * optidma_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int optidma_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static const struct pci_bits optidma_enable_bits = {
+ 0x40, 1, 0x08, 0x00
+ };
+
+ if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
+ return -ENOENT;
+
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * optidma_probe_reset - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA probe and bus reset sequence plus specific handling
+ * for this hardware. The Opti needs little handling - we have no UDMA66
+ * capability that needs cable detection. All we must do is check the port
+ * is enabled.
+ */
+
+static void optidma_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, optidma_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * optidma_unlock - unlock control registers
+ * @ap: ATA port
+ *
+ * Unlock the control register block for this adapter. Registers must not
+ * be unlocked in a situation where libata might look at them.
+ */
+
+static void optidma_unlock(struct ata_port *ap)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+
+ /* These 3 unlock the control register access */
+ inw(regio + 1);
+ inw(regio + 1);
+ outb(3, regio + 2);
+}
+
+/**
+ * optidma_lock - issue temporary relock
+ * @ap: ATA port
+ *
+ * Re-lock the configuration register settings.
+ */
+
+static void optidma_lock(struct ata_port *ap)
+{
+ unsigned long regio = ap->ioaddr.cmd_addr;
+
+ /* Relock */
+ outb(0x83, regio + 2);
+}
+
+/**
+ * optidma_set_mode - set mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @mode: Mode to set
+ *
+ * Called to do the DMA or PIO mode setup. Timing numbers are all
+ * pre computed to keep the code clean. There are two tables depending
+ * on the hardware clock speed.
+ *
+ * WARNING: While we do this the IDE registers vanish. If we take an
+ * IRQ here we depend on the host set locking to avoid catastrophe.
+ */
+
+static void optidma_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct ata_device *pair = ata_dev_pair(adev);
+ int pio = adev->pio_mode - XFER_PIO_0;
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
+ unsigned long regio = ap->ioaddr.cmd_addr;
+ u8 addr;
+
+ /* Address table precomputed with a DCLK of 2 */
+ static const u8 addr_timing[2][5] = {
+ { 0x30, 0x20, 0x20, 0x10, 0x10 },
+ { 0x20, 0x20, 0x10, 0x10, 0x10 }
+ };
+ static const u8 data_rec_timing[2][5] = {
+ { 0x59, 0x46, 0x30, 0x20, 0x20 },
+ { 0x46, 0x32, 0x20, 0x20, 0x10 }
+ };
+ static const u8 dma_data_rec_timing[2][3] = {
+ { 0x76, 0x20, 0x20 },
+ { 0x54, 0x20, 0x10 }
+ };
+
+ /* Switch from IDE to control mode */
+ optidma_unlock(ap);
+
+
+ /*
+ * As with many controllers the address setup time is shared
+ * and must suit both devices if present. FIXME: Check if we
+ * need to look at slowest of PIO/DMA mode of either device
+ */
+
+ if (mode >= XFER_MW_DMA_0)
+ addr = 0;
+ else
+ addr = addr_timing[pci_clock][pio];
+
+ if (pair) {
+ u8 pair_addr;
+ /* Hardware constraint */
+ if (pair->dma_mode)
+ pair_addr = 0;
+ else
+ pair_addr = addr_timing[pci_clock][pair->pio_mode - XFER_PIO_0];
+ if (pair_addr > addr)
+ addr = pair_addr;
+ }
+
+ /* Commence primary programming sequence */
+ /* First we load the device number into the timing select */
+ outb(adev->devno, regio + MISC_REG);
+ /* Now we load the data timings into read data/write data */
+ if (mode < XFER_MW_DMA_0) {
+ outb(data_rec_timing[pci_clock][pio], regio + READ_REG);
+ outb(data_rec_timing[pci_clock][pio], regio + WRITE_REG);
+ } else if (mode < XFER_UDMA_0) {
+ outb(dma_data_rec_timing[pci_clock][dma], regio + READ_REG);
+ outb(dma_data_rec_timing[pci_clock][dma], regio + WRITE_REG);
+ }
+ /* Finally we load the address setup into the misc register */
+ outb(addr | adev->devno, regio + MISC_REG);
+
+ /* Programming sequence complete, timing 0 dev 0, timing 1 dev 1 */
+ outb(0x85, regio + CNTRL_REG);
+
+ /* Switch back to IDE mode */
+ optidma_lock(ap);
+
+ /* Note: at this point our programming is incomplete. We are
+ not supposed to program PCI 0x43 "things we hacked onto the chip"
+ until we've done both sets of PIO/DMA timings */
+}
+
+/**
+ * optiplus_set_mode - DMA setup for Firestar Plus
+ * @ap: ATA port
+ * @adev: device
+ * @mode: desired mode
+ *
+ * The Firestar plus has additional UDMA functionality for UDMA0-2 and
+ * requires we do some additional work. Because the base work we must do
+ * is mostly shared we wrap the Firestar setup functionality in this
+ * one
+ */
+
+static void optiplus_set_mode(struct ata_port *ap, struct ata_device *adev, u8 mode)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 udcfg;
+ u8 udslave;
+ int dev2 = 2 * adev->devno;
+ int unit = 2 * ap->port_no + adev->devno;
+ int udma = mode - XFER_UDMA_0;
+
+ pci_read_config_byte(pdev, 0x44, &udcfg);
+ if (mode <= XFER_UDMA_0) {
+ udcfg &= ~(1 << unit);
+ optidma_set_mode(ap, adev, adev->dma_mode);
+ } else {
+ udcfg |= (1 << unit);
+ if (ap->port_no) {
+ pci_read_config_byte(pdev, 0x45, &udslave);
+ udslave &= ~(0x03 << dev2);
+ udslave |= (udma << dev2);
+ pci_write_config_byte(pdev, 0x45, udslave);
+ } else {
+ udcfg &= ~(0x30 << dev2);
+ udcfg |= (udma << dev2);
+ }
+ }
+ pci_write_config_byte(pdev, 0x44, udcfg);
+}
+
+/**
+ * optidma_set_pio_mode - PIO setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optidma_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optidma_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * optidma_set_dma_mode - DMA setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optidma_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optidma_set_mode(ap, adev, adev->dma_mode);
+}
+
+/**
+ * optiplus_set_pio_mode - PIO setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optiplus_set_pio_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optiplus_set_mode(ap, adev, adev->pio_mode);
+}
+
+/**
+ * optiplus_set_dma_mode - DMA setup callback
+ * @ap: ATA port
+ * @adev: Device
+ *
+ * The libata core provides separate functions for handling PIO and
+ * DMA programming. The architecture of the Firestar makes it easier
+ * for us to have a common function so we provide wrappers
+ */
+
+static void optiplus_set_dma_mode(struct ata_port *ap, struct ata_device *adev)
+{
+ optiplus_set_mode(ap, adev, adev->dma_mode);
+}
+
+/**
+ * optidma_make_bits - PCI setup helper
+ * @adev: ATA device
+ *
+ * Turn the ATA device setup into PCI configuration bits
+ * for register 0x43 and return the two bits needed.
+ */
+
+static u8 optidma_make_bits43(struct ata_device *adev)
+{
+ static const u8 bits43[5] = {
+ 0, 0, 0, 1, 2
+ };
+ if (!ata_dev_enabled(adev))
+ return 0;
+ if (adev->dma_mode)
+ return adev->dma_mode - XFER_MW_DMA_0;
+ return bits43[adev->pio_mode - XFER_PIO_0];
+}
+
+/**
+ * optidma_post_set_mode - finalize PCI setup
+ * @ap: port to set up
+ *
+ * Finalise the configuration by writing the nibble of extra bits
+ * of data into the chip.
+ */
+
+static void optidma_post_set_mode(struct ata_port *ap)
+{
+ u8 r;
+ int nybble = 4 * ap->port_no;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x43, &r);
+
+ r &= (0x0F << nybble);
+ r |= (optidma_make_bits43(&ap->device[0]) +
+ (optidma_make_bits43(&ap->device[0]) << 2)) << nybble;
+
+ pci_write_config_byte(pdev, 0x43, r);
+}
+
+static struct scsi_host_template optidma_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations optidma_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = optidma_set_pio_mode,
+ .set_dmamode = optidma_set_dma_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .error_handler = optidma_error_handler,
+ .post_set_mode = optidma_post_set_mode,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations optiplus_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = optiplus_set_pio_mode,
+ .set_dmamode = optiplus_set_dma_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+ .error_handler = optidma_error_handler,
+ .post_set_mode = optidma_post_set_mode,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * optiplus_with_udma - Look for UDMA capable setup
+ * @pdev; ATA controller
+ */
+
+static int optiplus_with_udma(struct pci_dev *pdev)
+{
+ u8 r;
+ int ret = 0;
+ int ioport = 0x22;
+ struct pci_dev *dev1;
+
+ /* Find function 1 */
+ dev1 = pci_get_device(0x1045, 0xC701, NULL);
+ if(dev1 == NULL)
+ return 0;
+
+ /* Rev must be >= 0x10 */
+ pci_read_config_byte(dev1, 0x08, &r);
+ if (r < 0x10)
+ goto done_nomsg;
+ /* Read the chipset system configuration to check our mode */
+ pci_read_config_byte(dev1, 0x5F, &r);
+ ioport |= (r << 8);
+ outb(0x10, ioport);
+ /* Must be 66Mhz sync */
+ if ((inb(ioport + 2) & 1) == 0)
+ goto done;
+
+ /* Check the ATA arbitration/timing is suitable */
+ pci_read_config_byte(pdev, 0x42, &r);
+ if ((r & 0x36) != 0x36)
+ goto done;
+ pci_read_config_byte(dev1, 0x52, &r);
+ if (r & 0x80) /* IDEDIR disabled */
+ ret = 1;
+done:
+ printk(KERN_WARNING "UDMA not supported in this configuration.\n");
+done_nomsg: /* Wrong chip revision */
+ pci_dev_put(dev1);
+ return ret;
+}
+
+static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_82c700 = {
+ .sht = &optidma_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &optidma_port_ops
+ };
+ static struct ata_port_info info_82c700_udma = {
+ .sht = &optidma_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &optiplus_port_ops
+ };
+ static struct ata_port_info *port_info[2];
+ struct ata_port_info *info = &info_82c700;
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ /* Fixed location chipset magic */
+ inw(0x1F1);
+ inw(0x1F1);
+ pci_clock = inb(0x1F5) & 1; /* 0 = 33Mhz, 1 = 25Mhz */
+
+ if (optiplus_with_udma(dev))
+ info = &info_82c700_udma;
+
+ port_info[0] = port_info[1] = info;
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id optidma[] = {
+ { PCI_DEVICE(0x1045, 0xD568), }, /* Opti 82C700 */
+ { 0, },
+};
+
+static struct pci_driver optidma_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = optidma,
+ .probe = optidma_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init optidma_init(void)
+{
+ return pci_register_driver(&optidma_pci_driver);
+}
+
+
+static void __exit optidma_exit(void)
+{
+ pci_unregister_driver(&optidma_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, optidma);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(optidma_init);
+module_exit(optidma_exit);
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
new file mode 100644
index 00000000000..cb501e145a4
--- /dev/null
+++ b/drivers/ata/pata_pcmcia.c
@@ -0,0 +1,393 @@
+/*
+ * pata_pcmcia.c - PCMCIA PATA controller driver.
+ * Copyright 2005-2006 Red Hat Inc <alan@redhat.com>, all rights reserved.
+ * PCMCIA ident update Copyright 2006 Marcin Juszkiewicz
+ * <openembedded@hrw.one.pl>
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Heavily based upon ide-cs.c
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/ata.h>
+#include <linux/libata.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+
+
+#define DRV_NAME "pata_pcmcia"
+#define DRV_VERSION "0.2.9"
+
+/*
+ * Private data structure to glue stuff together
+ */
+
+struct ata_pcmcia_info {
+ struct pcmcia_device *pdev;
+ int ndev;
+ dev_node_t node;
+};
+
+static struct scsi_host_template pcmcia_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pcmcia_port_ops = {
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+/**
+ * pcmcia_init_one - attach a PCMCIA interface
+ * @pdev: pcmcia device
+ *
+ * Register a PCMCIA IDE interface. Such interfaces are PIO 0 and
+ * shared IRQ.
+ */
+
+static int pcmcia_init_one(struct pcmcia_device *pdev)
+{
+ struct ata_probe_ent ae;
+ struct ata_pcmcia_info *info;
+ tuple_t tuple;
+ struct {
+ unsigned short buf[128];
+ cisparse_t parse;
+ config_info_t conf;
+ cistpl_cftable_entry_t dflt;
+ } *stk = NULL;
+ cistpl_cftable_entry_t *cfg;
+ int pass, last_ret = 0, last_fn = 0, is_kme = 0, ret = -ENOMEM;
+ unsigned long io_base, ctl_base;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL)
+ return -ENOMEM;
+
+ /* Glue stuff together. FIXME: We may be able to get rid of info with care */
+ info->pdev = pdev;
+ pdev->priv = info;
+
+ /* Set up attributes in order to probe card and get resources */
+ pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+ pdev->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+ pdev->io.IOAddrLines = 3;
+ pdev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
+ pdev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+ pdev->conf.Attributes = CONF_ENABLE_IRQ;
+ pdev->conf.IntType = INT_MEMORY_AND_IO;
+
+ /* Allocate resoure probing structures */
+
+ stk = kzalloc(sizeof(*stk), GFP_KERNEL);
+ if (!stk)
+ goto out1;
+
+ cfg = &stk->parse.cftable_entry;
+
+ /* Tuples we are walking */
+ tuple.TupleData = (cisdata_t *)&stk->buf;
+ tuple.TupleOffset = 0;
+ tuple.TupleDataMax = 255;
+ tuple.Attributes = 0;
+ tuple.DesiredTuple = CISTPL_CONFIG;
+
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+ CS_CHECK(GetTupleData, pcmcia_get_tuple_data(pdev, &tuple));
+ CS_CHECK(ParseTuple, pcmcia_parse_tuple(pdev, &tuple, &stk->parse));
+ pdev->conf.ConfigBase = stk->parse.config.base;
+ pdev->conf.Present = stk->parse.config.rmask[0];
+
+ /* See if we have a manufacturer identifier. Use it to set is_kme for
+ vendor quirks */
+ tuple.DesiredTuple = CISTPL_MANFID;
+ if (!pcmcia_get_first_tuple(pdev, &tuple) && !pcmcia_get_tuple_data(pdev, &tuple) && !pcmcia_parse_tuple(pdev, &tuple, &stk->parse))
+ is_kme = ((stk->parse.manfid.manf == MANFID_KME) && ((stk->parse.manfid.card == PRODID_KME_KXLC005_A) || (stk->parse.manfid.card == PRODID_KME_KXLC005_B)));
+
+ /* Not sure if this is right... look up the current Vcc */
+ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(pdev, &stk->conf));
+/* link->conf.Vcc = stk->conf.Vcc; */
+
+ pass = io_base = ctl_base = 0;
+ tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ tuple.Attributes = 0;
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+
+ /* Now munch the resources looking for a suitable set */
+ while (1) {
+ if (pcmcia_get_tuple_data(pdev, &tuple) != 0)
+ goto next_entry;
+ if (pcmcia_parse_tuple(pdev, &tuple, &stk->parse) != 0)
+ goto next_entry;
+ /* Check for matching Vcc, unless we're desperate */
+ if (!pass) {
+ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (stk->conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000)
+ goto next_entry;
+ } else if (stk->dflt.vcc.present & (1 << CISTPL_POWER_VNOM)) {
+ if (stk->conf.Vcc != stk->dflt.vcc.param[CISTPL_POWER_VNOM] / 10000)
+ goto next_entry;
+ }
+ }
+
+ if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM))
+ pdev->conf.Vpp = cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+ else if (stk->dflt.vpp1.present & (1 << CISTPL_POWER_VNOM))
+ pdev->conf.Vpp = stk->dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+
+ if ((cfg->io.nwin > 0) || (stk->dflt.io.nwin > 0)) {
+ cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &stk->dflt.io;
+ pdev->conf.ConfigIndex = cfg->index;
+ pdev->io.BasePort1 = io->win[0].base;
+ pdev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+ if (!(io->flags & CISTPL_IO_16BIT))
+ pdev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+ if (io->nwin == 2) {
+ pdev->io.NumPorts1 = 8;
+ pdev->io.BasePort2 = io->win[1].base;
+ pdev->io.NumPorts2 = (is_kme) ? 2 : 1;
+ if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ goto next_entry;
+ io_base = pdev->io.BasePort1;
+ ctl_base = pdev->io.BasePort2;
+ } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+ pdev->io.NumPorts1 = io->win[0].len;
+ pdev->io.NumPorts2 = 0;
+ if (pcmcia_request_io(pdev, &pdev->io) != 0)
+ goto next_entry;
+ io_base = pdev->io.BasePort1;
+ ctl_base = pdev->io.BasePort1 + 0x0e;
+ } else goto next_entry;
+ /* If we've got this far, we're done */
+ break;
+ }
+next_entry:
+ if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+ memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
+ if (pass) {
+ CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(pdev, &tuple));
+ } else if (pcmcia_get_next_tuple(pdev, &tuple) != 0) {
+ CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(pdev, &tuple));
+ memset(&stk->dflt, 0, sizeof(stk->dflt));
+ pass++;
+ }
+ }
+
+ CS_CHECK(RequestIRQ, pcmcia_request_irq(pdev, &pdev->irq));
+ CS_CHECK(RequestConfiguration, pcmcia_request_configuration(pdev, &pdev->conf));
+
+ /* Success. Disable the IRQ nIEN line, do quirks */
+ outb(0x02, ctl_base);
+ if (is_kme)
+ outb(0x81, ctl_base + 0x01);
+
+ /* FIXME: Could be more ports at base + 0x10 but we only deal with
+ one right now */
+ if (pdev->io.NumPorts1 >= 0x20)
+ printk(KERN_WARNING DRV_NAME ": second channel not yet supported.\n");
+
+ /*
+ * Having done the PCMCIA plumbing the ATA side is relatively
+ * sane.
+ */
+
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &pdev->dev;
+ ae.port_ops = &pcmcia_port_ops;
+ ae.sht = &pcmcia_sht;
+ ae.n_ports = 1;
+ ae.pio_mask = 1; /* ISA so PIO 0 cycles */
+ ae.irq = pdev->irq.AssignedIRQ;
+ ae.irq_flags = SA_SHIRQ;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ae.port[0].cmd_addr = io_base;
+ ae.port[0].altstatus_addr = ctl_base;
+ ae.port[0].ctl_addr = ctl_base;
+ ata_std_ports(&ae.port[0]);
+
+ if (ata_device_add(&ae) == 0)
+ goto failed;
+
+ info->ndev = 1;
+ kfree(stk);
+ return 0;
+
+cs_failed:
+ cs_error(pdev, last_fn, last_ret);
+failed:
+ kfree(stk);
+ info->ndev = 0;
+ pcmcia_disable_device(pdev);
+out1:
+ kfree(info);
+ return ret;
+}
+
+/**
+ * pcmcia_remove_one - unplug an pcmcia interface
+ * @pdev: pcmcia device
+ *
+ * A PCMCIA ATA device has been unplugged. Perform the needed
+ * cleanup. Also called on module unload for any active devices.
+ */
+
+static void pcmcia_remove_one(struct pcmcia_device *pdev)
+{
+ struct ata_pcmcia_info *info = pdev->priv;
+ struct device *dev = &pdev->dev;
+
+ if (info != NULL) {
+ /* If we have attached the device to the ATA layer, detach it */
+ if (info->ndev) {
+ struct ata_host *host = dev_get_drvdata(dev);
+ ata_host_remove(host);
+ dev_set_drvdata(dev, NULL);
+ }
+ info->ndev = 0;
+ pdev->priv = NULL;
+ }
+ pcmcia_disable_device(pdev);
+ kfree(info);
+}
+
+static struct pcmcia_device_id pcmcia_devices[] = {
+ PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+ PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */
+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+ PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */
+ PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */
+ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */
+ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
+ PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
+ PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
+ PCMCIA_DEVICE_PROD_ID12("EXP", "CD+GAME", 0x6f58c983, 0x63c13aaf),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae),
+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+ PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
+ PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+ PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
+ PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
+ PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+ PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "SanDisk", "ConnectPlus", 0x7a954bd9, 0x74be00c6),
+ PCMCIA_DEVICE_NULL,
+};
+
+MODULE_DEVICE_TABLE(pcmcia, pcmcia_devices);
+
+static struct pcmcia_driver pcmcia_driver = {
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = DRV_NAME,
+ },
+ .id_table = pcmcia_devices,
+ .probe = pcmcia_init_one,
+ .remove = pcmcia_remove_one,
+};
+
+static int __init pcmcia_init(void)
+{
+ return pcmcia_register_driver(&pcmcia_driver);
+}
+
+static void __exit pcmcia_exit(void)
+{
+ pcmcia_unregister_driver(&pcmcia_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for PCMCIA ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pcmcia_init);
+module_exit(pcmcia_exit);
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
new file mode 100644
index 00000000000..bd4ed6734ed
--- /dev/null
+++ b/drivers/ata/pata_pdc2027x.c
@@ -0,0 +1,867 @@
+/*
+ * Promise PATA TX2/TX4/TX2000/133 IDE driver for pdc20268 to pdc20277.
+ *
+ * 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.
+ *
+ * Ported to libata by:
+ * Albert Lee <albertcc@tw.ibm.com> IBM Corporation
+ *
+ * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>
+ * Portions Copyright (C) 1999 Promise Technology, Inc.
+ *
+ * Author: Frank Tiernan (frankt@promise.com)
+ * Released under terms of General Public License
+ *
+ *
+ * libata documentation is available via 'make {ps|pdf}docs',
+ * as Documentation/DocBook/libata.*
+ *
+ * Hardware information only available under NDA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_cmnd.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME "pata_pdc2027x"
+#define DRV_VERSION "0.74-ac5"
+#undef PDC_DEBUG
+
+#ifdef PDC_DEBUG
+#define PDPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define PDPRINTK(fmt, args...)
+#endif
+
+enum {
+ PDC_UDMA_100 = 0,
+ PDC_UDMA_133 = 1,
+
+ PDC_100_MHZ = 100000000,
+ PDC_133_MHZ = 133333333,
+
+ PDC_SYS_CTL = 0x1100,
+ PDC_ATA_CTL = 0x1104,
+ PDC_GLOBAL_CTL = 0x1108,
+ PDC_CTCR0 = 0x110C,
+ PDC_CTCR1 = 0x1110,
+ PDC_BYTE_COUNT = 0x1120,
+ PDC_PLL_CTL = 0x1202,
+};
+
+static int pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void pdc2027x_remove_one(struct pci_dev *pdev);
+static void pdc2027x_error_handler(struct ata_port *ap);
+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+static void pdc2027x_post_set_mode(struct ata_port *ap);
+static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc);
+
+/*
+ * ATA Timing Tables based on 133MHz controller clock.
+ * These tables are only used when the controller is in 133MHz clock.
+ * If the controller is in 100MHz clock, the ASIC hardware will
+ * set the timing registers automatically when "set feature" command
+ * is issued to the device. However, if the controller clock is 133MHz,
+ * the following tables must be used.
+ */
+static struct pdc2027x_pio_timing {
+ u8 value0, value1, value2;
+} pdc2027x_pio_timing_tbl [] = {
+ { 0xfb, 0x2b, 0xac }, /* PIO mode 0 */
+ { 0x46, 0x29, 0xa4 }, /* PIO mode 1 */
+ { 0x23, 0x26, 0x64 }, /* PIO mode 2 */
+ { 0x27, 0x0d, 0x35 }, /* PIO mode 3, IORDY on, Prefetch off */
+ { 0x23, 0x09, 0x25 }, /* PIO mode 4, IORDY on, Prefetch off */
+};
+
+static struct pdc2027x_mdma_timing {
+ u8 value0, value1;
+} pdc2027x_mdma_timing_tbl [] = {
+ { 0xdf, 0x5f }, /* MDMA mode 0 */
+ { 0x6b, 0x27 }, /* MDMA mode 1 */
+ { 0x69, 0x25 }, /* MDMA mode 2 */
+};
+
+static struct pdc2027x_udma_timing {
+ u8 value0, value1, value2;
+} pdc2027x_udma_timing_tbl [] = {
+ { 0x4a, 0x0f, 0xd5 }, /* UDMA mode 0 */
+ { 0x3a, 0x0a, 0xd0 }, /* UDMA mode 1 */
+ { 0x2a, 0x07, 0xcd }, /* UDMA mode 2 */
+ { 0x1a, 0x05, 0xcd }, /* UDMA mode 3 */
+ { 0x1a, 0x03, 0xcd }, /* UDMA mode 4 */
+ { 0x1a, 0x02, 0xcb }, /* UDMA mode 5 */
+ { 0x1a, 0x01, 0xcb }, /* UDMA mode 6 */
+};
+
+static const struct pci_device_id pdc2027x_pci_tbl[] = {
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { } /* terminate list */
+};
+
+static struct pci_driver pdc2027x_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc2027x_pci_tbl,
+ .probe = pdc2027x_init_one,
+ .remove = __devexit_p(pdc2027x_remove_one),
+};
+
+static struct scsi_host_template pdc2027x_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc2027x_pata100_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .check_atapi_dma = pdc2027x_check_atapi_dma,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2027x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static struct ata_port_operations pdc2027x_pata133_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc2027x_set_piomode,
+ .set_dmamode = pdc2027x_set_dmamode,
+ .post_set_mode = pdc2027x_post_set_mode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .check_atapi_dma = pdc2027x_check_atapi_dma,
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_mmio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2027x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_pci_host_stop,
+};
+
+static struct ata_port_info pdc2027x_port_info[] = {
+ /* PDC_UDMA_100 */
+ {
+ .sht = &pdc2027x_sht,
+ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &pdc2027x_pata100_ops,
+ },
+ /* PDC_UDMA_133 */
+ {
+ .sht = &pdc2027x_sht,
+ .flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_SLAVE_POSS |
+ ATA_FLAG_MMIO,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA6, /* udma0-6 */
+ .port_ops = &pdc2027x_pata133_ops,
+ },
+};
+
+MODULE_AUTHOR("Andre Hedrick, Frank Tiernan, Albert Lee");
+MODULE_DESCRIPTION("libata driver module for Promise PDC20268 to PDC20277");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, pdc2027x_pci_tbl);
+
+/**
+ * port_mmio - Get the MMIO address of PDC2027x extended registers
+ * @ap: Port
+ * @offset: offset from mmio base
+ */
+static inline void __iomem *port_mmio(struct ata_port *ap, unsigned int offset)
+{
+ return ap->host->mmio_base + ap->port_no * 0x100 + offset;
+}
+
+/**
+ * dev_mmio - Get the MMIO address of PDC2027x extended registers
+ * @ap: Port
+ * @adev: device
+ * @offset: offset from mmio base
+ */
+static inline void __iomem *dev_mmio(struct ata_port *ap, struct ata_device *adev, unsigned int offset)
+{
+ u8 adj = (adev->devno) ? 0x08 : 0x00;
+ return port_mmio(ap, offset) + adj;
+}
+
+/**
+ * pdc2027x_pata_cbl_detect - Probe host controller cable detect info
+ * @ap: Port for which cable detect info is desired
+ *
+ * Read 80c cable indicator from Promise extended register.
+ * This register is latched when the system is reset.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_cbl_detect(struct ata_port *ap)
+{
+ u32 cgcr;
+
+ /* check cable detect results */
+ cgcr = readl(port_mmio(ap, PDC_GLOBAL_CTL));
+ if (cgcr & (1 << 26))
+ goto cbl40;
+
+ PDPRINTK("No cable or 80-conductor cable on port %d\n", ap->port_no);
+
+ ap->cbl = ATA_CBL_PATA80;
+ return;
+
+cbl40:
+ printk(KERN_INFO DRV_NAME ": 40-conductor cable detected on port %d\n", ap->port_no);
+ ap->cbl = ATA_CBL_PATA40;
+ ap->udma_mask &= ATA_UDMA_MASK_40C;
+}
+
+/**
+ * pdc2027x_port_enabled - Check PDC ATA control register to see whether the port is enabled.
+ * @ap: Port to check
+ */
+static inline int pdc2027x_port_enabled(struct ata_port *ap)
+{
+ return readb(port_mmio(ap, PDC_ATA_CTL)) & 0x02;
+}
+
+/**
+ * pdc2027x_prereset - prereset for PATA host controller
+ * @ap: Target port
+ *
+ * Probeinit including cable detection.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static int pdc2027x_prereset(struct ata_port *ap)
+{
+ /* Check whether port enabled */
+ if (!pdc2027x_port_enabled(ap))
+ return -ENOENT;
+ pdc2027x_cbl_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+/**
+ * pdc2027x_error_handler - Perform reset on PATA port and classify
+ * @ap: Port to reset
+ *
+ * Reset PATA phy and classify attached devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pdc2027x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, pdc2027x_prereset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * pdc2027x_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port to configure
+ * @adev: um
+ * @pio: PIO mode, 0 - 4
+ *
+ * Set PIO mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void pdc2027x_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ u32 ctcr0, ctcr1;
+
+ PDPRINTK("adev->pio_mode[%X]\n", adev->pio_mode);
+
+ /* Sanity check */
+ if (pio > 4) {
+ printk(KERN_ERR DRV_NAME ": Unknown pio mode [%d] ignored\n", pio);
+ return;
+
+ }
+
+ /* Set the PIO timing registers using value table for 133MHz */
+ PDPRINTK("Set pio regs... \n");
+
+ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+ ctcr0 &= 0xffff0000;
+ ctcr0 |= pdc2027x_pio_timing_tbl[pio].value0 |
+ (pdc2027x_pio_timing_tbl[pio].value1 << 8);
+ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+
+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 &= 0x00ffffff;
+ ctcr1 |= (pdc2027x_pio_timing_tbl[pio].value2 << 24);
+ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+
+ PDPRINTK("Set pio regs done\n");
+
+ PDPRINTK("Set to pio mode[%u] \n", pio);
+}
+
+/**
+ * pdc2027x_set_dmamode - Initialize host controller PATA UDMA timings
+ * @ap: Port to configure
+ * @adev: um
+ * @udma: udma mode, XFER_UDMA_0 to XFER_UDMA_6
+ *
+ * Set UDMA mode for device.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+static void pdc2027x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ u32 ctcr0, ctcr1;
+
+ if ((dma_mode >= XFER_UDMA_0) &&
+ (dma_mode <= XFER_UDMA_6)) {
+ /* Set the UDMA timing registers with value table for 133MHz */
+ unsigned int udma_mode = dma_mode & 0x07;
+
+ if (dma_mode == XFER_UDMA_2) {
+ /*
+ * Turn off tHOLD.
+ * If tHOLD is '1', the hardware will add half clock for data hold time.
+ * This code segment seems to be no effect. tHOLD will be overwritten below.
+ */
+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ writel(ctcr1 & ~(1 << 7), dev_mmio(ap, adev, PDC_CTCR1));
+ }
+
+ PDPRINTK("Set udma regs... \n");
+
+ ctcr1 = readl(dev_mmio(ap, adev, PDC_CTCR1));
+ ctcr1 &= 0xff000000;
+ ctcr1 |= pdc2027x_udma_timing_tbl[udma_mode].value0 |
+ (pdc2027x_udma_timing_tbl[udma_mode].value1 << 8) |
+ (pdc2027x_udma_timing_tbl[udma_mode].value2 << 16);
+ writel(ctcr1, dev_mmio(ap, adev, PDC_CTCR1));
+
+ PDPRINTK("Set udma regs done\n");
+
+ PDPRINTK("Set to udma mode[%u] \n", udma_mode);
+
+ } else if ((dma_mode >= XFER_MW_DMA_0) &&
+ (dma_mode <= XFER_MW_DMA_2)) {
+ /* Set the MDMA timing registers with value table for 133MHz */
+ unsigned int mdma_mode = dma_mode & 0x07;
+
+ PDPRINTK("Set mdma regs... \n");
+ ctcr0 = readl(dev_mmio(ap, adev, PDC_CTCR0));
+
+ ctcr0 &= 0x0000ffff;
+ ctcr0 |= (pdc2027x_mdma_timing_tbl[mdma_mode].value0 << 16) |
+ (pdc2027x_mdma_timing_tbl[mdma_mode].value1 << 24);
+
+ writel(ctcr0, dev_mmio(ap, adev, PDC_CTCR0));
+ PDPRINTK("Set mdma regs done\n");
+
+ PDPRINTK("Set to mdma mode[%u] \n", mdma_mode);
+ } else {
+ printk(KERN_ERR DRV_NAME ": Unknown dma mode [%u] ignored\n", dma_mode);
+ }
+}
+
+/**
+ * pdc2027x_post_set_mode - Set the timing registers back to correct values.
+ * @ap: Port to configure
+ *
+ * The pdc2027x hardware will look at "SET FEATURES" and change the timing registers
+ * automatically. The values set by the hardware might be incorrect, under 133Mhz PLL.
+ * This function overwrites the possibly incorrect values set by the hardware to be correct.
+ */
+static void pdc2027x_post_set_mode(struct ata_port *ap)
+{
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+
+ if (ata_dev_enabled(dev)) {
+
+ pdc2027x_set_piomode(ap, dev);
+
+ /*
+ * Enable prefetch if the device support PIO only.
+ */
+ if (dev->xfer_shift == ATA_SHIFT_PIO) {
+ u32 ctcr1 = readl(dev_mmio(ap, dev, PDC_CTCR1));
+ ctcr1 |= (1 << 25);
+ writel(ctcr1, dev_mmio(ap, dev, PDC_CTCR1));
+
+ PDPRINTK("Turn on prefetch\n");
+ } else {
+ pdc2027x_set_dmamode(ap, dev);
+ }
+ }
+ }
+}
+
+/**
+ * pdc2027x_check_atapi_dma - Check whether ATAPI DMA can be supported for this command
+ * @qc: Metadata associated with taskfile to check
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ *
+ * RETURNS: 0 when ATAPI DMA can be used
+ * 1 otherwise
+ */
+static int pdc2027x_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ struct scsi_cmnd *cmd = qc->scsicmd;
+ u8 *scsicmd = cmd->cmnd;
+ int rc = 1; /* atapi dma off by default */
+
+ /*
+ * This workaround is from Promise's GPL driver.
+ * If ATAPI DMA is used for commands not in the
+ * following white list, say MODE_SENSE and REQUEST_SENSE,
+ * pdc2027x might hit the irq lost problem.
+ */
+ switch (scsicmd[0]) {
+ case READ_10:
+ case WRITE_10:
+ case READ_12:
+ case WRITE_12:
+ case READ_6:
+ case WRITE_6:
+ case 0xad: /* READ_DVD_STRUCTURE */
+ case 0xbe: /* READ_CD */
+ /* ATAPI DMA is ok */
+ rc = 0;
+ break;
+ default:
+ ;
+ }
+
+ return rc;
+}
+
+/**
+ * pdc_read_counter - Read the ctr counter
+ * @probe_ent: for the port address
+ */
+
+static long pdc_read_counter(struct ata_probe_ent *probe_ent)
+{
+ long counter;
+ int retry = 1;
+ u32 bccrl, bccrh, bccrlv, bccrhv;
+
+retry:
+ bccrl = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrh = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ rmb();
+
+ /* Read the counter values again for verification */
+ bccrlv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT) & 0xffff;
+ bccrhv = readl(probe_ent->mmio_base + PDC_BYTE_COUNT + 0x100) & 0xffff;
+ rmb();
+
+ counter = (bccrh << 15) | bccrl;
+
+ PDPRINTK("bccrh [%X] bccrl [%X]\n", bccrh, bccrl);
+ PDPRINTK("bccrhv[%X] bccrlv[%X]\n", bccrhv, bccrlv);
+
+ /*
+ * The 30-bit decreasing counter are read by 2 pieces.
+ * Incorrect value may be read when both bccrh and bccrl are changing.
+ * Ex. When 7900 decrease to 78FF, wrong value 7800 might be read.
+ */
+ if (retry && !(bccrh == bccrhv && bccrl >= bccrlv)) {
+ retry--;
+ PDPRINTK("rereading counter\n");
+ goto retry;
+ }
+
+ return counter;
+}
+
+/**
+ * adjust_pll - Adjust the PLL input clock in Hz.
+ *
+ * @pdc_controller: controller specific information
+ * @probe_ent: For the port address
+ * @pll_clock: The input of PLL in HZ
+ */
+static void pdc_adjust_pll(struct ata_probe_ent *probe_ent, long pll_clock, unsigned int board_idx)
+{
+
+ u16 pll_ctl;
+ long pll_clock_khz = pll_clock / 1000;
+ long pout_required = board_idx? PDC_133_MHZ:PDC_100_MHZ;
+ long ratio = pout_required / pll_clock_khz;
+ int F, R;
+
+ /* Sanity check */
+ if (unlikely(pll_clock_khz < 5000L || pll_clock_khz > 70000L)) {
+ printk(KERN_ERR DRV_NAME ": Invalid PLL input clock %ldkHz, give up!\n", pll_clock_khz);
+ return;
+ }
+
+#ifdef PDC_DEBUG
+ PDPRINTK("pout_required is %ld\n", pout_required);
+
+ /* Show the current clock value of PLL control register
+ * (maybe already configured by the firmware)
+ */
+ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+
+ PDPRINTK("pll_ctl[%X]\n", pll_ctl);
+#endif
+
+ /*
+ * Calculate the ratio of F, R and OD
+ * POUT = (F + 2) / (( R + 2) * NO)
+ */
+ if (ratio < 8600L) { /* 8.6x */
+ /* Using NO = 0x01, R = 0x0D */
+ R = 0x0d;
+ } else if (ratio < 12900L) { /* 12.9x */
+ /* Using NO = 0x01, R = 0x08 */
+ R = 0x08;
+ } else if (ratio < 16100L) { /* 16.1x */
+ /* Using NO = 0x01, R = 0x06 */
+ R = 0x06;
+ } else if (ratio < 64000L) { /* 64x */
+ R = 0x00;
+ } else {
+ /* Invalid ratio */
+ printk(KERN_ERR DRV_NAME ": Invalid ratio %ld, give up!\n", ratio);
+ return;
+ }
+
+ F = (ratio * (R+2)) / 1000 - 2;
+
+ if (unlikely(F < 0 || F > 127)) {
+ /* Invalid F */
+ printk(KERN_ERR DRV_NAME ": F[%d] invalid!\n", F);
+ return;
+ }
+
+ PDPRINTK("F[%d] R[%d] ratio*1000[%ld]\n", F, R, ratio);
+
+ pll_ctl = (R << 8) | F;
+
+ PDPRINTK("Writing pll_ctl[%X]\n", pll_ctl);
+
+ writew(pll_ctl, probe_ent->mmio_base + PDC_PLL_CTL);
+ readw(probe_ent->mmio_base + PDC_PLL_CTL); /* flush */
+
+ /* Wait the PLL circuit to be stable */
+ mdelay(30);
+
+#ifdef PDC_DEBUG
+ /*
+ * Show the current clock value of PLL control register
+ * (maybe configured by the firmware)
+ */
+ pll_ctl = readw(probe_ent->mmio_base + PDC_PLL_CTL);
+
+ PDPRINTK("pll_ctl[%X]\n", pll_ctl);
+#endif
+
+ return;
+}
+
+/**
+ * detect_pll_input_clock - Detect the PLL input clock in Hz.
+ * @probe_ent: for the port address
+ * Ex. 16949000 on 33MHz PCI bus for pdc20275.
+ * Half of the PCI clock.
+ */
+static long pdc_detect_pll_input_clock(struct ata_probe_ent *probe_ent)
+{
+ u32 scr;
+ long start_count, end_count;
+ long pll_clock;
+
+ /* Read current counter value */
+ start_count = pdc_read_counter(probe_ent);
+
+ /* Start the test mode */
+ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ PDPRINTK("scr[%X]\n", scr);
+ writel(scr | (0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
+ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+
+ /* Let the counter run for 100 ms. */
+ mdelay(100);
+
+ /* Read the counter values again */
+ end_count = pdc_read_counter(probe_ent);
+
+ /* Stop the test mode */
+ scr = readl(probe_ent->mmio_base + PDC_SYS_CTL);
+ PDPRINTK("scr[%X]\n", scr);
+ writel(scr & ~(0x01 << 14), probe_ent->mmio_base + PDC_SYS_CTL);
+ readl(probe_ent->mmio_base + PDC_SYS_CTL); /* flush */
+
+ /* calculate the input clock in Hz */
+ pll_clock = (start_count - end_count) * 10;
+
+ PDPRINTK("start[%ld] end[%ld] \n", start_count, end_count);
+ PDPRINTK("PLL input clock[%ld]Hz\n", pll_clock);
+
+ return pll_clock;
+}
+
+/**
+ * pdc_hardware_init - Initialize the hardware.
+ * @pdev: instance of pci_dev found
+ * @pdc_controller: controller specific information
+ * @pe: for the port address
+ */
+static int pdc_hardware_init(struct pci_dev *pdev, struct ata_probe_ent *pe, unsigned int board_idx)
+{
+ long pll_clock;
+
+ /*
+ * Detect PLL input clock rate.
+ * On some system, where PCI bus is running at non-standard clock rate.
+ * Ex. 25MHz or 40MHz, we have to adjust the cycle_time.
+ * The pdc20275 controller employs PLL circuit to help correct timing registers setting.
+ */
+ pll_clock = pdc_detect_pll_input_clock(pe);
+
+ if (pll_clock < 0) /* counter overflow? Try again. */
+ pll_clock = pdc_detect_pll_input_clock(pe);
+
+ dev_printk(KERN_INFO, &pdev->dev, "PLL input clock %ld kHz\n", pll_clock/1000);
+
+ /* Adjust PLL control register */
+ pdc_adjust_pll(pe, pll_clock, board_idx);
+
+ return 0;
+}
+
+/**
+ * pdc_ata_setup_port - setup the mmio address
+ * @port: ata ioports to setup
+ * @base: base address
+ */
+static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+ port->cmd_addr =
+ port->data_addr = base;
+ port->feature_addr =
+ port->error_addr = base + 0x05;
+ port->nsect_addr = base + 0x0a;
+ port->lbal_addr = base + 0x0f;
+ port->lbam_addr = base + 0x10;
+ port->lbah_addr = base + 0x15;
+ port->device_addr = base + 0x1a;
+ port->command_addr =
+ port->status_addr = base + 0x1f;
+ port->altstatus_addr =
+ port->ctl_addr = base + 0x81a;
+}
+
+/**
+ * pdc2027x_init_one - PCI probe function
+ * Called when an instance of PCI adapter is inserted.
+ * This function checks whether the hardware is supported,
+ * initialize hardware and register an instance of ata_host to
+ * libata by providing struct ata_probe_ent and ata_device_add().
+ * (implements struct pci_driver.probe() )
+ *
+ * @pdev: instance of pci_dev found
+ * @ent: matching entry in the id_tbl[]
+ */
+static int __devinit pdc2027x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ unsigned int board_idx = (unsigned int) ent->driver_data;
+
+ struct ata_probe_ent *probe_ent = NULL;
+ unsigned long base;
+ void __iomem *mmio_base;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ return rc;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out;
+
+ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+ if (rc)
+ goto err_out_regions;
+
+ /* Prepare the probe entry */
+ probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL);
+ if (probe_ent == NULL) {
+ rc = -ENOMEM;
+ goto err_out_regions;
+ }
+
+ probe_ent->dev = pci_dev_to_dev(pdev);
+ INIT_LIST_HEAD(&probe_ent->node);
+
+ mmio_base = pci_iomap(pdev, 5, 0);
+ if (!mmio_base) {
+ rc = -ENOMEM;
+ goto err_out_free_ent;
+ }
+
+ base = (unsigned long) mmio_base;
+
+ probe_ent->sht = pdc2027x_port_info[board_idx].sht;
+ probe_ent->port_flags = pdc2027x_port_info[board_idx].flags;
+ probe_ent->pio_mask = pdc2027x_port_info[board_idx].pio_mask;
+ probe_ent->mwdma_mask = pdc2027x_port_info[board_idx].mwdma_mask;
+ probe_ent->udma_mask = pdc2027x_port_info[board_idx].udma_mask;
+ probe_ent->port_ops = pdc2027x_port_info[board_idx].port_ops;
+
+ probe_ent->irq = pdev->irq;
+ probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->mmio_base = mmio_base;
+
+ pdc_ata_setup_port(&probe_ent->port[0], base + 0x17c0);
+ probe_ent->port[0].bmdma_addr = base + 0x1000;
+ pdc_ata_setup_port(&probe_ent->port[1], base + 0x15c0);
+ probe_ent->port[1].bmdma_addr = base + 0x1008;
+
+ probe_ent->n_ports = 2;
+
+ pci_set_master(pdev);
+ //pci_enable_intx(pdev);
+
+ /* initialize adapter */
+ if (pdc_hardware_init(pdev, probe_ent, board_idx) != 0)
+ goto err_out_free_ent;
+
+ ata_device_add(probe_ent);
+ kfree(probe_ent);
+
+ return 0;
+
+err_out_free_ent:
+ kfree(probe_ent);
+err_out_regions:
+ pci_release_regions(pdev);
+err_out:
+ pci_disable_device(pdev);
+ return rc;
+}
+
+/**
+ * pdc2027x_remove_one - Called to remove a single instance of the
+ * adapter.
+ *
+ * @dev: The PCI device to remove.
+ * FIXME: module load/unload not working yet
+ */
+static void __devexit pdc2027x_remove_one(struct pci_dev *pdev)
+{
+ ata_pci_remove_one(pdev);
+}
+
+/**
+ * pdc2027x_init - Called after this module is loaded into the kernel.
+ */
+static int __init pdc2027x_init(void)
+{
+ return pci_module_init(&pdc2027x_pci_driver);
+}
+
+/**
+ * pdc2027x_exit - Called before this module unloaded from the kernel
+ */
+static void __exit pdc2027x_exit(void)
+{
+ pci_unregister_driver(&pdc2027x_pci_driver);
+}
+
+module_init(pdc2027x_init);
+module_exit(pdc2027x_exit);
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
new file mode 100644
index 00000000000..48f43432764
--- /dev/null
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -0,0 +1,423 @@
+/*
+ * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based in part on linux/drivers/ide/pci/pdc202xx_old.c
+ *
+ * First cut with LBA48/ATAPI
+ *
+ * TODO:
+ * Channel interlock/reset on both required ?
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_pdc202xx_old"
+#define DRV_VERSION "0.2.1"
+
+/**
+ * pdc2024x_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int pdc2024x_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+static void pdc2024x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, pdc2024x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+static int pdc2026x_pre_reset(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 cis;
+
+ pci_read_config_word(pdev, 0x50, &cis);
+ if (cis & (1 << (10 + ap->port_no)))
+ ap->cbl = ATA_CBL_PATA80;
+ else
+ ap->cbl = ATA_CBL_PATA40;
+
+ return ata_std_prereset(ap);
+}
+
+static void pdc2026x_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, pdc2026x_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * pdc_configure_piomode - set chip PIO timing
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @pio: PIO mode
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * so a configure_dmamode call will undo any work we do here and vice
+ * versa
+ */
+
+static void pdc_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
+ static u16 pio_timing[5] = {
+ 0x0913, 0x050C , 0x0308, 0x0206, 0x0104
+ };
+ u8 r_ap, r_bp;
+
+ pci_read_config_byte(pdev, port, &r_ap);
+ pci_read_config_byte(pdev, port + 1, &r_bp);
+ r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */
+ r_bp &= ~0x07;
+ r_ap |= (pio_timing[pio] >> 8);
+ r_bp |= (pio_timing[pio] & 0xFF);
+
+ if (ata_pio_need_iordy(adev))
+ r_ap |= 0x20; /* IORDY enable */
+ if (adev->class == ATA_DEV_ATA)
+ r_ap |= 0x10; /* FIFO enable */
+ pci_write_config_byte(pdev, port, r_ap);
+ pci_write_config_byte(pdev, port + 1, r_bp);
+}
+
+/**
+ * pdc_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * but we want to set the PIO timing by default.
+ */
+
+static void pdc_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ pdc_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+}
+
+/**
+ * pdc_configure_dmamode - set DMA mode in chip
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Load DMA cycle times into the chip ready for a DMA transfer
+ * to occur.
+ */
+
+static void pdc_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x60 + 4 * ap->port_no + 2 * adev->devno;
+ static u8 udma_timing[6][2] = {
+ { 0x60, 0x03 }, /* 33 Mhz Clock */
+ { 0x40, 0x02 },
+ { 0x20, 0x01 },
+ { 0x40, 0x02 }, /* 66 Mhz Clock */
+ { 0x20, 0x01 },
+ { 0x20, 0x01 }
+ };
+ u8 r_bp, r_cp;
+
+ pci_read_config_byte(pdev, port + 1, &r_bp);
+ pci_read_config_byte(pdev, port + 2, &r_cp);
+
+ r_bp &= ~0xF0;
+ r_cp &= ~0x0F;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ int speed = adev->dma_mode - XFER_UDMA_0;
+ r_bp |= udma_timing[speed][0];
+ r_cp |= udma_timing[speed][1];
+
+ } else {
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ r_bp |= 0x60;
+ r_cp |= (5 - speed);
+ }
+ pci_write_config_byte(pdev, port + 1, r_bp);
+ pci_write_config_byte(pdev, port + 2, r_cp);
+
+}
+
+/**
+ * pdc2026x_bmdma_start - DMA engine begin
+ * @qc: ATA command
+ *
+ * In UDMA3 or higher we have to clock switch for the duration of the
+ * DMA transfer sequence.
+ */
+
+static void pdc2026x_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_taskfile *tf = &qc->tf;
+ int sel66 = ap->port_no ? 0x08: 0x02;
+
+ unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ unsigned long clock = master + 0x11;
+ unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+
+ u32 len;
+
+ /* Check we keep host level locking here */
+ if (adev->dma_mode >= XFER_UDMA_2)
+ outb(inb(clock) | sel66, clock);
+ else
+ outb(inb(clock) & ~sel66, clock);
+
+ /* The DMA clocks may have been trashed by a reset. FIXME: make conditional
+ and move to qc_issue ? */
+ pdc_set_dmamode(ap, qc->dev);
+
+ /* Cases the state machine will not complete correctly without help */
+ if ((tf->flags & ATA_TFLAG_LBA48) || tf->protocol == ATA_PROT_ATAPI_DMA)
+ {
+ if (tf->flags & ATA_TFLAG_LBA48)
+ len = qc->nsect * 512;
+ else
+ len = qc->nbytes;
+
+ if (tf->flags & ATA_TFLAG_WRITE)
+ len |= 0x06000000;
+ else
+ len |= 0x05000000;
+
+ outl(len, atapi_reg);
+ }
+
+ /* Activate DMA */
+ ata_bmdma_start(qc);
+}
+
+/**
+ * pdc2026x_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * After a DMA completes we need to put the clock back to 33MHz for
+ * PIO timings.
+ */
+
+static void pdc2026x_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_taskfile *tf = &qc->tf;
+
+ int sel66 = ap->port_no ? 0x08: 0x02;
+ /* The clock bits are in the same register for both channels */
+ unsigned long master = ap->host->ports[0]->ioaddr.bmdma_addr;
+ unsigned long clock = master + 0x11;
+ unsigned long atapi_reg = master + 0x20 + (4 * ap->port_no);
+
+ /* Cases the state machine will not complete correctly */
+ if (tf->protocol == ATA_PROT_ATAPI_DMA || ( tf->flags & ATA_TFLAG_LBA48)) {
+ outl(0, atapi_reg);
+ outb(inb(clock) & ~sel66, clock);
+ }
+ /* Check we keep host level locking here */
+ /* Flip back to 33Mhz for PIO */
+ if (adev->dma_mode >= XFER_UDMA_2)
+ outb(inb(clock) & ~sel66, clock);
+
+ ata_bmdma_stop(qc);
+}
+
+/**
+ * pdc2026x_dev_config - device setup hook
+ * @ap: ATA port
+ * @adev: newly found device
+ *
+ * Perform chip specific early setup. We need to lock the transfer
+ * sizes to 8bit to avoid making the state engine on the 2026x cards
+ * barf.
+ */
+
+static void pdc2026x_dev_config(struct ata_port *ap, struct ata_device *adev)
+{
+ adev->max_sectors = 256;
+}
+
+static struct scsi_host_template pdc_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations pdc2024x_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc_set_piomode,
+ .set_dmamode = pdc_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2024x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations pdc2026x_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = pdc_set_piomode,
+ .set_dmamode = pdc_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+ .dev_config = pdc2026x_dev_config,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = pdc2026x_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = pdc2026x_bmdma_start,
+ .bmdma_stop = pdc2026x_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info[3] = {
+ {
+ .sht = &pdc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA2,
+ .port_ops = &pdc2024x_port_ops
+ },
+ {
+ .sht = &pdc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA4,
+ .port_ops = &pdc2026x_port_ops
+ },
+ {
+ .sht = &pdc_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &pdc2026x_port_ops
+ }
+
+ };
+ static struct ata_port_info *port_info[2];
+
+ port_info[0] = port_info[1] = &info[id->driver_data];
+
+ if (dev->device == PCI_DEVICE_ID_PROMISE_20265) {
+ struct pci_dev *bridge = dev->bus->self;
+ /* Don't grab anything behind a Promise I2O RAID */
+ if (bridge && bridge->vendor == PCI_VENDOR_ID_INTEL) {
+ if( bridge->device == PCI_DEVICE_ID_INTEL_I960)
+ return -ENODEV;
+ if( bridge->device == PCI_DEVICE_ID_INTEL_I960RM)
+ return -ENODEV;
+ }
+ }
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static struct pci_device_id pdc[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2},
+ { 0, },
+};
+
+static struct pci_driver pdc_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pdc,
+ .probe = pdc_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init pdc_init(void)
+{
+ return pci_register_driver(&pdc_pci_driver);
+}
+
+
+static void __exit pdc_exit(void)
+{
+ pci_unregister_driver(&pdc_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pdc_init);
+module_exit(pdc_exit);
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
new file mode 100644
index 00000000000..7977f471d5e
--- /dev/null
+++ b/drivers/ata/pata_qdi.c
@@ -0,0 +1,403 @@
+/*
+ * pata_qdi.c - QDI VLB ATA controllers
+ * (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * This driver mostly exists as a proof of concept for non PCI devices under
+ * libata. While the QDI6580 was 'neat' in 1993 it is no longer terribly
+ * useful.
+ *
+ * Tuning code written from the documentation at
+ * http://www.ryston.cz/petr/vlb/qd6500.html
+ * http://www.ryston.cz/petr/vlb/qd6580.html
+ *
+ * Probe code based on drivers/ide/legacy/qd65xx.c
+ * Rewritten from the work of Colten Edwards <pje120@cs.usask.ca> by
+ * Samuel Thibault <samuel.thibault@fnac.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/platform_device.h>
+
+#define DRV_NAME "pata_qdi"
+#define DRV_VERSION "0.2.4"
+
+#define NR_HOST 4 /* Two 6580s */
+
+struct qdi_data {
+ unsigned long timing;
+ u8 clock[2];
+ u8 last;
+ int fast;
+ struct platform_device *platform_dev;
+
+};
+
+static struct ata_host *qdi_host[NR_HOST];
+static struct qdi_data qdi_data[NR_HOST];
+static int nr_qdi_host;
+
+#ifdef MODULE
+static int probe_qdi = 1;
+#else
+static int probe_qdi;
+#endif
+
+static void qdi6500_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing t;
+ struct qdi_data *qdi = ap->host->private_data;
+ int active, recovery;
+ u8 timing;
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+ if (qdi->fast) {
+ active = 8 - FIT(t.active, 1, 8);
+ recovery = 18 - FIT(t.recover, 3, 18);
+ } else {
+ active = 9 - FIT(t.active, 2, 9);
+ recovery = 15 - FIT(t.recover, 0, 15);
+ }
+ timing = (recovery << 4) | active | 0x08;
+
+ qdi->clock[adev->devno] = timing;
+
+ outb(timing, qdi->timing);
+}
+
+static void qdi6580_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct ata_timing t;
+ struct qdi_data *qdi = ap->host->private_data;
+ int active, recovery;
+ u8 timing;
+
+ /* Get the timing data in cycles */
+ ata_timing_compute(adev, adev->pio_mode, &t, 30303, 1000);
+
+ if (qdi->fast) {
+ active = 8 - FIT(t.active, 1, 8);
+ recovery = 18 - FIT(t.recover, 3, 18);
+ } else {
+ active = 9 - FIT(t.active, 2, 9);
+ recovery = 15 - FIT(t.recover, 0, 15);
+ }
+ timing = (recovery << 4) | active | 0x08;
+
+ qdi->clock[adev->devno] = timing;
+
+ outb(timing, qdi->timing);
+
+ /* Clear the FIFO */
+ if (adev->class != ATA_DEV_ATA)
+ outb(0x5F, (qdi->timing & 0xFFF0) + 3);
+}
+
+/**
+ * qdi_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings.
+ */
+
+static unsigned int qdi_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct qdi_data *qdi = ap->host->private_data;
+
+ if (qdi->clock[adev->devno] != qdi->last) {
+ if (adev->pio_mode) {
+ qdi->last = qdi->clock[adev->devno];
+ outb(qdi->clock[adev->devno], qdi->timing);
+ }
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned int buflen, int write_data)
+{
+ struct ata_port *ap = adev->ap;
+ int slop = buflen & 3;
+
+ if (ata_id_has_dword_io(adev->id)) {
+ if (write_data)
+ outsl(ap->ioaddr.data_addr, buf, buflen >> 2);
+ else
+ insl(ap->ioaddr.data_addr, buf, buflen >> 2);
+
+ if (unlikely(slop)) {
+ u32 pad;
+ if (write_data) {
+ memcpy(&pad, buf + buflen - slop, slop);
+ outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
+ } else {
+ pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ memcpy(buf + buflen - slop, &pad, slop);
+ }
+ }
+ } else
+ ata_pio_data_xfer(adev, buf, buflen, write_data);
+}
+
+static struct scsi_host_template qdi_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations qdi6500_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = qdi6500_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = qdi_qc_issue_prot,
+
+ .data_xfer = qdi_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations qdi6580_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = qdi6580_set_piomode,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = ata_bmdma_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = qdi_qc_issue_prot,
+
+ .data_xfer = qdi_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * qdi_init_one - attach a qdi interface
+ * @type: Type to display
+ * @io: I/O port start
+ * @irq: interrupt line
+ * @fast: True if on a > 33Mhz VLB
+ *
+ * Register an ISA bus IDE interface. Such interfaces are PIO and we
+ * assume do not support IRQ sharing.
+ */
+
+static __init int qdi_init_one(unsigned long port, int type, unsigned long io, int irq, int fast)
+{
+ struct ata_probe_ent ae;
+ struct platform_device *pdev;
+ int ret;
+
+ unsigned long ctrl = io + 0x206;
+
+ /*
+ * Fill in a probe structure first of all
+ */
+
+ pdev = platform_device_register_simple(DRV_NAME, nr_qdi_host, NULL, 0);
+ if (pdev == NULL)
+ return -ENOMEM;
+
+ memset(&ae, 0, sizeof(struct ata_probe_ent));
+ INIT_LIST_HEAD(&ae.node);
+ ae.dev = &pdev->dev;
+
+ if (type == 6580) {
+ ae.port_ops = &qdi6580_port_ops;
+ ae.pio_mask = 0x1F;
+ } else {
+ ae.port_ops = &qdi6500_port_ops;
+ ae.pio_mask = 0x07; /* Actually PIO3 !IORDY is possible */
+ }
+
+ ae.sht = &qdi_sht;
+ ae.n_ports = 1;
+ ae.irq = irq;
+ ae.irq_flags = 0;
+ ae.port_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST;
+ ae.port[0].cmd_addr = io;
+ ae.port[0].altstatus_addr = ctrl;
+ ae.port[0].ctl_addr = ctrl;
+ ata_std_ports(&ae.port[0]);
+
+ /*
+ * Hook in a private data structure per channel
+ */
+ ae.private_data = &qdi_data[nr_qdi_host];
+
+ qdi_data[nr_qdi_host].timing = port;
+ qdi_data[nr_qdi_host].fast = fast;
+ qdi_data[nr_qdi_host].platform_dev = pdev;
+
+ printk(KERN_INFO DRV_NAME": qd%d at 0x%lx.\n", type, io);
+ ret = ata_device_add(&ae);
+ if (ret == 0) {
+ platform_device_unregister(pdev);
+ return -ENODEV;
+ }
+
+ qdi_host[nr_qdi_host++] = dev_get_drvdata(&pdev->dev);
+ return 0;
+}
+
+/**
+ * qdi_init - attach qdi interfaces
+ *
+ * Attach qdi IDE interfaces by scanning the ports it may occupy.
+ */
+
+static __init int qdi_init(void)
+{
+ unsigned long flags;
+ static const unsigned long qd_port[2] = { 0x30, 0xB0 };
+ static const unsigned long ide_port[2] = { 0x170, 0x1F0 };
+ static const int ide_irq[2] = { 14, 15 };
+
+ int ct = 0;
+ int i;
+
+ if (probe_qdi == 0)
+ return -ENODEV;
+
+ /*
+ * Check each possible QD65xx base address
+ */
+
+ for (i = 0; i < 2; i++) {
+ unsigned long port = qd_port[i];
+ u8 r, res;
+
+
+ if (request_region(port, 2, "pata_qdi")) {
+ /* Check for a card */
+ local_irq_save(flags);
+ r = inb_p(port);
+ outb_p(0x19, port);
+ res = inb_p(port);
+ outb_p(r, port);
+ local_irq_restore(flags);
+
+ /* Fail */
+ if (res == 0x19)
+ {
+ release_region(port, 2);
+ continue;
+ }
+
+ /* Passes the presence test */
+ r = inb_p(port + 1); /* Check port agrees with port set */
+ if ((r & 2) >> 1 != i) {
+ release_region(port, 2);
+ continue;
+ }
+
+ /* Check card type */
+ if ((r & 0xF0) == 0xC0) {
+ /* QD6500: single channel */
+ if (r & 8) {
+ /* Disabled ? */
+ release_region(port, 2);
+ continue;
+ }
+ ct += qdi_init_one(port, 6500, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
+ }
+ if (((r & 0xF0) == 0xA0) || (r & 0xF0) == 0x50) {
+ /* QD6580: dual channel */
+ if (!request_region(port + 2 , 2, "pata_qdi"))
+ {
+ release_region(port, 2);
+ continue;
+ }
+ res = inb(port + 3);
+ if (res & 1) {
+ /* Single channel mode */
+ ct += qdi_init_one(port, 6580, ide_port[r & 0x01], ide_irq[r & 0x01], r & 0x04);
+ } else {
+ /* Dual channel mode */
+ ct += qdi_init_one(port, 6580, 0x1F0, 14, r & 0x04);
+ ct += qdi_init_one(port + 2, 6580, 0x170, 15, r & 0x04);
+ }
+ }
+ }
+ }
+ if (ct != 0)
+ return 0;
+ return -ENODEV;
+}
+
+static __exit void qdi_exit(void)
+{
+ int i;
+
+ for (i = 0; i < nr_qdi_host; i++) {
+ ata_host_remove(qdi_host[i]);
+ /* Free the control resource. The 6580 dual channel has the resources
+ * claimed as a pair of 2 byte resources so we need no special cases...
+ */
+ release_region(qdi_data[i].timing, 2);
+ platform_device_unregister(qdi_data[i].platform_dev);
+ }
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for qdi ATA");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(qdi_init);
+module_exit(qdi_exit);
+
+module_param(probe_qdi, int, 0);
+
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
new file mode 100644
index 00000000000..c20bcf43ed6
--- /dev/null
+++ b/drivers/ata/pata_radisys.c
@@ -0,0 +1,333 @@
+/*
+ * pata_radisys.c - Intel PATA/SATA controllers
+ *
+ * (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * Some parts based on ata_piix.c by Jeff Garzik and others.
+ *
+ * A PIIX relative, this device has a single ATA channel and no
+ * slave timings, SITRE or PPE. In that sense it is a close relative
+ * of the original PIIX. It does however support UDMA 33/66 per channel
+ * although no other modes/timings. Also lacking is 32bit I/O on the ATA
+ * port.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_radisys"
+#define DRV_VERSION "0.4.1"
+
+/**
+ * radisys_probe_init - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int radisys_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA80;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * radisys_pata_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void radisys_pata_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, radisys_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * radisys_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: um
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void radisys_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u16 idetm_data;
+ int control = 0;
+
+ /*
+ * See Intel Document 298600-004 for the timing programing rules
+ * for PIIX/ICH. Note that the early PIIX does not have the slave
+ * timing port at 0x44. The Radisys is a relative of the PIIX
+ * but not the same so be careful.
+ */
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 }, /* Check me */
+ { 0, 0 },
+ { 1, 1 },
+ { 2, 2 },
+ { 3, 3 }, };
+
+ if (pio > 0)
+ control |= 1; /* TIME1 enable */
+ if (ata_pio_need_iordy(adev))
+ control |= 2; /* IE IORDY */
+
+ pci_read_config_word(dev, 0x40, &idetm_data);
+
+ /* Enable IE and TIME as appropriate. Clear the other
+ drive timing bits */
+ idetm_data &= 0xCCCC;
+ idetm_data |= (control << (4 * adev->devno));
+ idetm_data |= (timings[pio][0] << 12) |
+ (timings[pio][1] << 8);
+ pci_write_config_word(dev, 0x40, idetm_data);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * radisys_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ * @isich: True if the device is an ICH and has IOCFG registers
+ *
+ * Set MWDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void radisys_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ u16 idetm_data;
+ u8 udma_enable;
+
+ static const /* ISP RTC */
+ u8 timings[][2] = { { 0, 0 },
+ { 0, 0 },
+ { 1, 1 },
+ { 2, 2 },
+ { 3, 3 }, };
+
+ /*
+ * MWDMA is driven by the PIO timings. We must also enable
+ * IORDY unconditionally.
+ */
+
+ pci_read_config_word(dev, 0x40, &idetm_data);
+ pci_read_config_byte(dev, 0x48, &udma_enable);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ unsigned int mwdma = adev->dma_mode - XFER_MW_DMA_0;
+ const unsigned int needed_pio[3] = {
+ XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
+ };
+ int pio = needed_pio[mwdma] - XFER_PIO_0;
+ int control = 3; /* IORDY|TIME0 */
+
+ /* If the drive MWDMA is faster than it can do PIO then
+ we must force PIO0 for PIO cycles. */
+
+ if (adev->pio_mode < needed_pio[mwdma])
+ control = 1;
+
+ /* Mask out the relevant control and timing bits we will load. Also
+ clear the other drive TIME register as a precaution */
+
+ idetm_data &= 0xCCCC;
+ idetm_data |= control << (4 * adev->devno);
+ idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
+
+ udma_enable &= ~(1 << adev->devno);
+ } else {
+ u8 udma_mode;
+
+ /* UDMA66 on: UDMA 33 and 66 are switchable via register 0x4A */
+
+ pci_read_config_byte(dev, 0x4A, &udma_mode);
+
+ if (adev->xfer_mode == XFER_UDMA_2)
+ udma_mode &= ~ (1 << adev->devno);
+ else /* UDMA 4 */
+ udma_mode |= (1 << adev->devno);
+
+ pci_write_config_byte(dev, 0x4A, udma_mode);
+
+ udma_enable |= (1 << adev->devno);
+ }
+ pci_write_config_word(dev, 0x40, idetm_data);
+ pci_write_config_byte(dev, 0x48, udma_enable);
+
+ /* Track which port is configured */
+ ap->private_data = adev;
+}
+
+/**
+ * radisys_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Our logic also clears TIME0/TIME1 for the other device so
+ * that, even if we get this wrong, cycles to the other device will
+ * be made PIO0.
+ */
+
+static unsigned int radisys_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+
+ if (adev != ap->private_data) {
+ /* UDMA timing is not shared */
+ if (adev->dma_mode < XFER_UDMA_0) {
+ if (adev->dma_mode)
+ radisys_set_dmamode(ap, adev);
+ else if (adev->pio_mode)
+ radisys_set_piomode(ap, adev);
+ }
+ }
+ return ata_qc_issue_prot(qc);
+}
+
+
+static struct scsi_host_template radisys_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations radisys_pata_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = radisys_set_piomode,
+ .set_dmamode = radisys_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = radisys_pata_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = radisys_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+
+/**
+ * radisys_init_one - Register PIIX ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in radisys_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info info = {
+ .sht = &radisys_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma1-2 */
+ .udma_mask = 0x14, /* UDMA33/66 only */
+ .port_ops = &radisys_pata_ops,
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id radisys_pci_tbl[] = {
+ { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, },
+ { } /* terminate list */
+};
+
+static struct pci_driver radisys_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = radisys_pci_tbl,
+ .probe = radisys_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init radisys_init(void)
+{
+ return pci_register_driver(&radisys_pci_driver);
+}
+
+static void __exit radisys_exit(void)
+{
+ pci_unregister_driver(&radisys_pci_driver);
+}
+
+
+module_init(radisys_init);
+module_exit(radisys_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for Radisys R82600 controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, radisys_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
new file mode 100644
index 00000000000..eccc6fd4503
--- /dev/null
+++ b/drivers/ata/pata_rz1000.c
@@ -0,0 +1,205 @@
+/*
+ * RZ1000/1001 driver based upon
+ *
+ * linux/drivers/ide/pci/rz1000.c Version 0.06 January 12, 2003
+ * Copyright (C) 1995-1998 Linus Torvalds & author (see below)
+ * Principal Author: mlord@pobox.com (Mark Lord)
+ *
+ * See linux/MAINTAINERS for address of current maintainer.
+ *
+ * This file provides support for disabling the buggy read-ahead
+ * mode of the RZ1000 IDE chipset, commonly used on Intel motherboards.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_rz1000"
+#define DRV_VERSION "0.2.2"
+
+
+/**
+ * rz1000_prereset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generics
+ */
+
+static int rz1000_prereset(struct ata_port *ap)
+{
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+/**
+ * rz1000_error_handler - probe reset
+ * @ap: ATA port
+ *
+ * Perform the ATA standard reset sequence
+ */
+
+static void rz1000_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, rz1000_prereset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * rz1000_set_mode - mode setting function
+ * @ap: ATA interface
+ *
+ * Use a non standard set_mode function. We don't want to be tuned. We
+ * would prefer to be BIOS generic but for the fact our hardware is
+ * whacked out.
+ */
+
+static void rz1000_set_mode(struct ata_port *ap)
+{
+ int i;
+
+ for (i = 0; i < ATA_MAX_DEVICES; i++) {
+ struct ata_device *dev = &ap->device[i];
+ if (ata_dev_enabled(dev)) {
+ /* We don't really care */
+ dev->pio_mode = XFER_PIO_0;
+ dev->xfer_mode = XFER_PIO_0;
+ dev->xfer_shift = ATA_SHIFT_PIO;
+ dev->flags |= ATA_DFLAG_PIO;
+ }
+ }
+}
+
+
+static struct scsi_host_template rz1000_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations rz1000_port_ops = {
+ .set_mode = rz1000_set_mode,
+
+ .port_disable = ata_port_disable,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = rz1000_error_handler,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = rz1000_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * rz1000_init_one - Register RZ1000 ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in rz1000_pci_tbl matching with @pdev
+ *
+ * Configure an RZ1000 interface. This doesn't require much special
+ * handling except that we *MUST* kill the chipset readahead or the
+ * user may experience data corruption.
+ */
+
+static int rz1000_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ struct ata_port_info *port_info[2];
+ u16 reg;
+ static struct ata_port_info info = {
+ .sht = &rz1000_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &rz1000_port_ops
+ };
+
+ if (!printed_version++)
+ printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+ /* Be exceptionally paranoid as we must be sure to apply the fix */
+ if (pci_read_config_word(pdev, 0x40, &reg) != 0)
+ goto fail;
+ reg &= 0xDFFF;
+ if (pci_write_config_word(pdev, 0x40, reg) != 0)
+ goto fail;
+ printk(KERN_INFO DRV_NAME ": disabled chipset readahead.\n");
+
+ port_info[0] = &info;
+ port_info[1] = &info;
+ return ata_pci_init_one(pdev, port_info, 2);
+fail:
+ printk(KERN_ERR DRV_NAME ": failed to disable read-ahead on chipset..\n");
+ /* Not safe to use so skip */
+ return -ENODEV;
+}
+
+static struct pci_device_id pata_rz1000[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
+ { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
+ { 0, },
+};
+
+static struct pci_driver rz1000_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = pata_rz1000,
+ .probe = rz1000_init_one,
+ .remove = ata_pci_remove_one
+};
+
+
+static int __init rz1000_init(void)
+{
+ return pci_register_driver(&rz1000_pci_driver);
+}
+
+static void __exit rz1000_exit(void)
+{
+ pci_unregister_driver(&rz1000_pci_driver);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for RZ1000 PCI ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pata_rz1000);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(rz1000_init);
+module_exit(rz1000_exit);
+
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
new file mode 100644
index 00000000000..107e6cd3dc0
--- /dev/null
+++ b/drivers/ata/pata_sc1200.c
@@ -0,0 +1,287 @@
+/*
+ * New ATA layer SC1200 driver Alan Cox <alan@redhat.com>
+ *
+ * TODO: Mode selection filtering
+ * TODO: Can't enable second channel until ATA core has serialize
+ * TODO: Needs custom DMA cleanup code
+ *
+ * Based very heavily on
+ *
+ * linux/drivers/ide/pci/sc1200.c Version 0.91 28-Jan-2003
+ *
+ * Copyright (C) 2000-2002 Mark Lord <mlord@pobox.com>
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Development of this chipset driver was funded
+ * by the nice folks at National Semiconductor.
+ *
+ * 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.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "sc1200"
+#define DRV_VERSION "0.2.3"
+
+#define SC1200_REV_A 0x00
+#define SC1200_REV_B1 0x01
+#define SC1200_REV_B3 0x02
+#define SC1200_REV_C1 0x03
+#define SC1200_REV_D1 0x04
+
+/**
+ * sc1200_clock - PCI clock
+ *
+ * Return the PCI bus clocking for the SC1200 chipset configuration
+ * in use. We return 0 for 33MHz 1 for 48MHz and 2 for 66Mhz
+ */
+
+static int sc1200_clock(void)
+{
+ /* Magic registers that give us the chipset data */
+ u8 chip_id = inb(0x903C);
+ u8 silicon_rev = inb(0x903D);
+ u16 pci_clock;
+
+ if (chip_id == 0x04 && silicon_rev < SC1200_REV_B1)
+ return 0; /* 33 MHz mode */
+
+ /* Clock generator configuration 0x901E its 8/9 are the PCI clocking
+ 0/3 is 33Mhz 1 is 48 2 is 66 */
+
+ pci_clock = inw(0x901E);
+ pci_clock >>= 8;
+ pci_clock &= 0x03;
+ if (pci_clock == 3)
+ pci_clock = 0;
+ return pci_clock;
+}
+
+/**
+ * sc1200_set_piomode - PIO setup
+ * @ap: ATA interface
+ * @adev: device on the interface
+ *
+ * Set our PIO requirements. This is fairly simple on the SC1200
+ */
+
+static void sc1200_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u32 pio_timings[4][5] = {
+ {0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz
+ {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz
+ {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz
+ {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131} // format1, 66Mhz
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 format;
+ unsigned int reg = 0x40 + 0x10 * ap->port_no;
+ int mode = adev->pio_mode - XFER_PIO_0;
+
+ pci_read_config_dword(pdev, reg + 4, &format);
+ format >>= 31;
+ format += sc1200_clock();
+ pci_write_config_dword(pdev, reg + 8 * adev->devno,
+ pio_timings[format][mode]);
+}
+
+/**
+ * sc1200_set_dmamode - DMA timing setup
+ * @ap: ATA interface
+ * @adev: Device being configured
+ *
+ * We cannot mix MWDMA and UDMA without reloading timings each switch
+ * master to slave.
+ */
+
+static void sc1200_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u32 udma_timing[3][3] = {
+ { 0x00921250, 0x00911140, 0x00911030 },
+ { 0x00932470, 0x00922260, 0x00922140 },
+ { 0x009436A1, 0x00933481, 0x00923261 }
+ };
+
+ static const u32 mwdma_timing[3][3] = {
+ { 0x00077771, 0x00012121, 0x00002020 },
+ { 0x000BBBB2, 0x00024241, 0x00013131 },
+ { 0x000FFFF3, 0x00035352, 0x00015151 }
+ };
+
+ int clock = sc1200_clock();
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned int reg = 0x40 + 0x10 * ap->port_no;
+ int mode = adev->dma_mode;
+ u32 format;
+
+ if (mode >= XFER_UDMA_0)
+ format = udma_timing[clock][mode - XFER_UDMA_0];
+ else
+ format = mwdma_timing[clock][mode - XFER_MW_DMA_0];
+
+ if (adev->devno == 0) {
+ u32 timings;
+
+ pci_read_config_dword(pdev, reg + 4, &timings);
+ timings &= 0x80000000UL;
+ timings |= format;
+ pci_write_config_dword(pdev, reg + 4, timings);
+ } else
+ pci_write_config_dword(pdev, reg + 12, format);
+}
+
+/**
+ * sc1200_qc_issue_prot - command issue
+ * @qc: command pending
+ *
+ * Called when the libata layer is about to issue a command. We wrap
+ * this interface so that we can load the correct ATA timings if
+ * neccessary. Specifically we have a problem that there is only
+ * one MWDMA/UDMA bit.
+ */
+
+static unsigned int sc1200_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ata_device *adev = qc->dev;
+ struct ata_device *prev = ap->private_data;
+
+ /* See if the DMA settings could be wrong */
+ if (adev->dma_mode != 0 && adev != prev && prev != NULL) {
+ /* Maybe, but do the channels match MWDMA/UDMA ? */
+ if ((adev->dma_mode >= XFER_UDMA_0 && prev->dma_mode < XFER_UDMA_0) ||
+ (adev->dma_mode < XFER_UDMA_0 && prev->dma_mode >= XFER_UDMA_0))
+ /* Switch the mode bits */
+ sc1200_set_dmamode(ap, adev);
+ }
+
+ return ata_qc_issue_prot(qc);
+}
+
+static struct scsi_host_template sc1200_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations sc1200_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sc1200_set_piomode,
+ .set_dmamode = sc1200_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = ata_bmdma_error_handler,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = sc1200_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * sc1200_init_one - Initialise an SC1200
+ * @dev: PCI device
+ * @id: Entry in match table
+ *
+ * Just throw the needed data at the libata helper and it does all
+ * our work.
+ */
+
+static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &sc1200_sht,
+ .flags = ATA_FLAG_SLAVE_POSS|ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &sc1200_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+
+ /* Can't enable port 2 yet, see top comments */
+ return ata_pci_init_one(dev, port_info, 1);
+}
+
+static struct pci_device_id sc1200[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
+ { 0, },
+};
+
+static struct pci_driver sc1200_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sc1200,
+ .probe = sc1200_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init sc1200_init(void)
+{
+ return pci_register_driver(&sc1200_pci_driver);
+}
+
+
+static void __exit sc1200_exit(void)
+{
+ pci_unregister_driver(&sc1200_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox, Mark Lord");
+MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sc1200);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sc1200_init);
+module_exit(sc1200_exit);
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
new file mode 100644
index 00000000000..a5c8d7e121d
--- /dev/null
+++ b/drivers/ata/pata_serverworks.c
@@ -0,0 +1,591 @@
+/*
+ * ata-serverworks.c - Serverworks PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * serverworks.c
+ *
+ * Copyright (C) 1998-2000 Michel Aubry
+ * Copyright (C) 1998-2000 Andrzej Krzysztofowicz
+ * Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+ * Portions copyright (c) 2001 Sun Microsystems
+ *
+ *
+ * RCC/ServerWorks IDE driver for Linux
+ *
+ * OSB4: `Open South Bridge' IDE Interface (fn 1)
+ * supports UDMA mode 2 (33 MB/s)
+ *
+ * CSB5: `Champion South Bridge' IDE Interface (fn 1)
+ * all revisions support UDMA mode 4 (66 MB/s)
+ * revision A2.0 and up support UDMA mode 5 (100 MB/s)
+ *
+ * *** The CSB5 does not provide ANY register ***
+ * *** to detect 80-conductor cable presence. ***
+ *
+ * CSB6: `Champion South Bridge' IDE Interface (optional: third channel)
+ *
+ * Documentation:
+ * Available under NDA only. Errata info very hard to get.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_serverworks"
+#define DRV_VERSION "0.3.7"
+
+#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
+#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
+
+/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
+ * can overrun their FIFOs when used with the CSB5 */
+
+static const char *csb_bad_ata100[] = {
+ "ST320011A",
+ "ST340016A",
+ "ST360021A",
+ "ST380021A",
+ NULL
+};
+
+/**
+ * dell_cable - Dell serverworks cable detection
+ * @ap: ATA port to do cable detect
+ *
+ * Dell hide the 40/80 pin select for their interfaces in the top two
+ * bits of the subsystem ID.
+ */
+
+static int dell_cable(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * sun_cable - Sun Cobalt 'Alpine' cable detection
+ * @ap: ATA port to do cable select
+ *
+ * Cobalt CSB5 IDE hides the 40/80pin in the top two bits of the
+ * subsystem ID the same as dell. We could use one function but we may
+ * need to extend the Dell one in future
+ */
+
+static int sun_cable(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (pdev->subsystem_device & (1 << (ap->port_no + 14)))
+ return ATA_CBL_PATA80;
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * osb4_cable - OSB4 cable detect
+ * @ap: ATA port to check
+ *
+ * The OSB4 isn't UDMA66 capable so this is easy
+ */
+
+static int osb4_cable(struct ata_port *ap) {
+ return ATA_CBL_PATA40;
+}
+
+/**
+ * csb4_cable - CSB5/6 cable detect
+ * @ap: ATA port to check
+ *
+ * Serverworks default arrangement is to use the drive side detection
+ * only.
+ */
+
+static int csb_cable(struct ata_port *ap) {
+ return ATA_CBL_PATA80;
+}
+
+struct sv_cable_table {
+ int device;
+ int subvendor;
+ int (*cable_detect)(struct ata_port *ap);
+};
+
+/*
+ * Note that we don't copy the old serverworks code because the old
+ * code contains obvious mistakes
+ */
+
+static struct sv_cable_table cable_detect[] = {
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, osb4_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, csb_cable },
+ { }
+};
+
+/**
+ * serverworks_pre_reset - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection according to the device and subvendor
+ * identifications
+ */
+
+static int serverworks_pre_reset(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct sv_cable_table *cb = cable_detect;
+
+ while(cb->device) {
+ if (cb->device == pdev->device &&
+ (cb->subvendor == pdev->subsystem_vendor ||
+ cb->subvendor == PCI_ANY_ID)) {
+ ap->cbl = cb->cable_detect(ap);
+ return ata_std_prereset(ap);
+ }
+ cb++;
+ }
+
+ BUG();
+ return -1; /* kill compiler warning */
+}
+
+static void serverworks_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, serverworks_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * serverworks_is_csb - Check for CSB or OSB
+ * @pdev: PCI device to check
+ *
+ * Returns true if the device being checked is known to be a CSB
+ * series device.
+ */
+
+static u8 serverworks_is_csb(struct pci_dev *pdev)
+{
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE:
+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE:
+ case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2:
+ case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE:
+ return 1;
+ default:
+ break;
+ }
+ return 0;
+}
+
+/**
+ * serverworks_osb4_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Filter the offered modes for the device to apply controller
+ * specific rules. OSB4 requires no UDMA for disks due to a FIFO
+ * bug we hit.
+ */
+
+static unsigned long serverworks_osb4_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ if (adev->class == ATA_DEV_ATA)
+ mask &= ~ATA_MASK_UDMA;
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+
+/**
+ * serverworks_csb_filter - mode selection filter
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Check the blacklist and disable UDMA5 if matched
+ */
+
+static unsigned long serverworks_csb_filter(const struct ata_port *ap, struct ata_device *adev, unsigned long mask)
+{
+ const char *p;
+ char model_num[40];
+ int len, i;
+
+ /* Disk, UDMA */
+ if (adev->class != ATA_DEV_ATA)
+ return ata_pci_default_filter(ap, adev, mask);
+
+ /* Actually do need to check */
+ ata_id_string(adev->id, model_num, ATA_ID_PROD_OFS, sizeof(model_num));
+ /* Precuationary - why not do this in the libata core ?? */
+
+ len = strlen(model_num);
+ while ((len > 0) && (model_num[len - 1] == ' ')) {
+ len--;
+ model_num[len] = 0;
+ }
+
+ for(i = 0; (p = csb_bad_ata100[i]) != NULL; i++) {
+ if (!strncmp(p, model_num, len))
+ mask &= ~(0x1F << ATA_SHIFT_UDMA);
+ }
+ return ata_pci_default_filter(ap, adev, mask);
+}
+
+
+/**
+ * serverworks_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the OSB4/CSB5 timing registers for PIO. The PIO register
+ * load is done as a simple lookup.
+ */
+static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ int offset = 1 + (2 * ap->port_no) - adev->devno;
+ int devbits = (2 * ap->port_no + adev->devno) * 4;
+ u16 csb5_pio;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int pio = adev->pio_mode - XFER_PIO_0;
+
+ pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]);
+
+ /* The OSB4 just requires the timing but the CSB series want the
+ mode number as well */
+ if (serverworks_is_csb(pdev)) {
+ pci_read_config_word(pdev, 0x4A, &csb5_pio);
+ csb5_pio &= ~(0x0F << devbits);
+ pci_write_config_byte(pdev, 0x4A, csb5_pio | (pio << devbits));
+ }
+}
+
+/**
+ * serverworks_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5
+ * chipset. The MWDMA mode values are pulled from a lookup table
+ * while the chipset uses mode number for UDMA.
+ */
+
+static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static const u8 dma_mode[] = { 0x77, 0x21, 0x20 };
+ int offset = 1 + 2 * ap->port_no - adev->devno;
+ int devbits = (2 * ap->port_no + adev->devno);
+ u8 ultra;
+ u8 ultra_cfg;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ pci_read_config_byte(pdev, 0x54, &ultra_cfg);
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ pci_write_config_byte(pdev, 0x44 + offset, 0x20);
+
+ pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra);
+ ultra &= ~(0x0F << (ap->port_no * 4));
+ ultra |= (adev->dma_mode - XFER_UDMA_0)
+ << (ap->port_no * 4);
+ pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra);
+
+ ultra_cfg |= (1 << devbits);
+ } else {
+ pci_write_config_byte(pdev, 0x44 + offset,
+ dma_mode[adev->dma_mode - XFER_MW_DMA_0]);
+ ultra_cfg &= ~(1 << devbits);
+ }
+ pci_write_config_byte(pdev, 0x54, ultra_cfg);
+}
+
+static struct scsi_host_template serverworks_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations serverworks_osb4_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = serverworks_set_piomode,
+ .set_dmamode = serverworks_set_dmamode,
+ .mode_filter = serverworks_osb4_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = serverworks_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations serverworks_csb_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = serverworks_set_piomode,
+ .set_dmamode = serverworks_set_dmamode,
+ .mode_filter = serverworks_csb_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = serverworks_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int serverworks_fixup_osb4(struct pci_dev *pdev)
+{
+ u32 reg;
+ struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
+ if (isa_dev) {
+ pci_read_config_dword(isa_dev, 0x64, &reg);
+ reg &= ~0x00002000; /* disable 600ns interrupt mask */
+ if (!(reg & 0x00004000))
+ printk(KERN_DEBUG DRV_NAME ": UDMA not BIOS enabled.\n");
+ reg |= 0x00004000; /* enable UDMA/33 support */
+ pci_write_config_dword(isa_dev, 0x64, reg);
+ pci_dev_put(isa_dev);
+ return 0;
+ }
+ printk(KERN_WARNING "ata_serverworks: Unable to find bridge.\n");
+ return -ENODEV;
+}
+
+static int serverworks_fixup_csb(struct pci_dev *pdev)
+{
+ u8 rev;
+ u8 btr;
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &rev);
+
+ /* Third Channel Test */
+ if (!(PCI_FUNC(pdev->devfn) & 1)) {
+ struct pci_dev * findev = NULL;
+ u32 reg4c = 0;
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
+ if (findev) {
+ pci_read_config_dword(findev, 0x4C, &reg4c);
+ reg4c &= ~0x000007FF;
+ reg4c |= 0x00000040;
+ reg4c |= 0x00000020;
+ pci_write_config_dword(findev, 0x4C, reg4c);
+ pci_dev_put(findev);
+ }
+ } else {
+ struct pci_dev * findev = NULL;
+ u8 reg41 = 0;
+
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
+ PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
+ if (findev) {
+ pci_read_config_byte(findev, 0x41, &reg41);
+ reg41 &= ~0x40;
+ pci_write_config_byte(findev, 0x41, reg41);
+ pci_dev_put(findev);
+ }
+ }
+ /* setup the UDMA Control register
+ *
+ * 1. clear bit 6 to enable DMA
+ * 2. enable DMA modes with bits 0-1
+ * 00 : legacy
+ * 01 : udma2
+ * 10 : udma2/udma4
+ * 11 : udma2/udma4/udma5
+ */
+ pci_read_config_byte(pdev, 0x5A, &btr);
+ btr &= ~0x40;
+ if (!(PCI_FUNC(pdev->devfn) & 1))
+ btr |= 0x2;
+ else
+ btr |= (rev >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2;
+ pci_write_config_byte(pdev, 0x5A, btr);
+
+ return btr;
+}
+
+static void serverworks_fixup_ht1000(struct pci_dev *pdev)
+{
+ u8 btr;
+ /* Setup HT1000 SouthBridge Controller - Single Channel Only */
+ pci_read_config_byte(pdev, 0x5A, &btr);
+ btr &= ~0x40;
+ btr |= 0x3;
+ pci_write_config_byte(pdev, 0x5A, btr);
+}
+
+
+static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ int ports = 2;
+ static struct ata_port_info info[4] = {
+ { /* OSB4 */
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x07,
+ .port_ops = &serverworks_osb4_port_ops
+ }, { /* OSB4 no UDMA */
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x00,
+ .port_ops = &serverworks_osb4_port_ops
+ }, { /* CSB5 */
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &serverworks_csb_port_ops
+ }, { /* CSB5 - later revisions*/
+ .sht = &serverworks_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &serverworks_csb_port_ops
+ }
+ };
+ static struct ata_port_info *port_info[2];
+ struct ata_port_info *devinfo = &info[id->driver_data];
+
+ /* Force master latency timer to 64 PCI clocks */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
+
+ /* OSB4 : South Bridge and IDE */
+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
+ /* Select non UDMA capable OSB4 if we can't do fixups */
+ if ( serverworks_fixup_osb4(pdev) < 0)
+ devinfo = &info[1];
+ }
+ /* setup CSB5/CSB6 : South Bridge and IDE option RAID */
+ else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) ||
+ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) {
+
+ /* If the returned btr is the newer revision then
+ select the right info block */
+ if (serverworks_fixup_csb(pdev) == 3)
+ devinfo = &info[3];
+
+ /* Is this the 3rd channel CSB6 IDE ? */
+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)
+ ports = 1;
+ }
+ /* setup HT1000E */
+ else if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_HT1000IDE)
+ serverworks_fixup_ht1000(pdev);
+
+ if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE)
+ ata_pci_clear_simplex(pdev);
+
+ port_info[0] = port_info[1] = devinfo;
+ return ata_pci_init_one(pdev, port_info, ports);
+}
+
+static struct pci_device_id serverworks[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
+ { 0, },
+};
+
+static struct pci_driver serverworks_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = serverworks,
+ .probe = serverworks_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init serverworks_init(void)
+{
+ return pci_register_driver(&serverworks_pci_driver);
+}
+
+
+static void __exit serverworks_exit(void)
+{
+ pci_unregister_driver(&serverworks_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, serverworks);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(serverworks_init);
+module_exit(serverworks_exit);
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
new file mode 100644
index 00000000000..c8b2e26db70
--- /dev/null
+++ b/drivers/ata/pata_sil680.c
@@ -0,0 +1,381 @@
+/*
+ * pata_sil680.c - SIL680 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * linux/drivers/ide/pci/siimage.c Version 1.07 Nov 30, 2003
+ *
+ * Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2003 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ *
+ * Documentation publically available.
+ *
+ * If you have strange problems with nVidia chipset systems please
+ * see the SI support documentation and update your system BIOS
+ * if neccessary
+ *
+ * TODO
+ * If we know all our devices are LBA28 (or LBA28 sized) we could use
+ * the command fifo mode.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_sil680"
+#define DRV_VERSION "0.3.2"
+
+/**
+ * sil680_selreg - return register base
+ * @hwif: interface
+ * @r: config offset
+ *
+ * Turn a config register offset into the right address in either
+ * PCI space or MMIO space to access the control register in question
+ * Thankfully this is a configuration operation so isnt performance
+ * criticial.
+ */
+
+static unsigned long sil680_selreg(struct ata_port *ap, int r)
+{
+ unsigned long base = 0xA0 + r;
+ base += (ap->port_no << 4);
+ return base;
+}
+
+/**
+ * sil680_seldev - return register base
+ * @hwif: interface
+ * @r: config offset
+ *
+ * Turn a config register offset into the right address in either
+ * PCI space or MMIO space to access the control register in question
+ * including accounting for the unit shift.
+ */
+
+static unsigned long sil680_seldev(struct ata_port *ap, struct ata_device *adev, int r)
+{
+ unsigned long base = 0xA0 + r;
+ base += (ap->port_no << 4);
+ base |= adev->devno ? 2 : 0;
+ return base;
+}
+
+
+/**
+ * sil680_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. The SIL680 stores this in PCI config
+ * space for us.
+ */
+
+static int sil680_cable_detect(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long addr = sil680_selreg(ap, 0);
+ u8 ata66;
+ pci_read_config_byte(pdev, addr, &ata66);
+ if (ata66 & 1)
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static int sil680_pre_reset(struct ata_port *ap)
+{
+ ap->cbl = sil680_cable_detect(ap);
+ return ata_std_prereset(ap);
+}
+
+/**
+ * sil680_bus_reset - reset the SIL680 bus
+ * @ap: ATA port to reset
+ *
+ * Perform the SIL680 housekeeping when doing an ATA bus reset
+ */
+
+static int sil680_bus_reset(struct ata_port *ap,unsigned int *classes)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long addr = sil680_selreg(ap, 0);
+ u8 reset;
+
+ pci_read_config_byte(pdev, addr, &reset);
+ pci_write_config_byte(pdev, addr, reset | 0x03);
+ udelay(25);
+ pci_write_config_byte(pdev, addr, reset);
+ return ata_std_softreset(ap, classes);
+}
+
+static void sil680_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sil680_pre_reset, sil680_bus_reset, NULL, ata_std_postreset);
+}
+
+/**
+ * sil680_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the SIL680 registers for PIO mode. Note that the task speed
+ * registers are shared between the devices so we must pick the lowest
+ * mode for command work.
+ */
+
+static void sil680_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u16 speed_p[5] = { 0x328A, 0x2283, 0x1104, 0x10C3, 0x10C1 };
+ static u16 speed_t[5] = { 0x328A, 0x1281, 0x1281, 0x10C3, 0x10C1 };
+
+ unsigned long tfaddr = sil680_selreg(ap, 0x02);
+ unsigned long addr = sil680_seldev(ap, adev, 0x04);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int pio = adev->pio_mode - XFER_PIO_0;
+ int lowest_pio = pio;
+ u16 reg;
+
+ struct ata_device *pair = ata_dev_pair(adev);
+
+ if (pair != NULL && adev->pio_mode > pair->pio_mode)
+ lowest_pio = pair->pio_mode - XFER_PIO_0;
+
+ pci_write_config_word(pdev, addr, speed_p[pio]);
+ pci_write_config_word(pdev, tfaddr, speed_t[lowest_pio]);
+
+ pci_read_config_word(pdev, tfaddr-2, &reg);
+ reg &= ~0x0200; /* Clear IORDY */
+ if (ata_pio_need_iordy(adev))
+ reg |= 0x0200; /* Enable IORDY */
+ pci_write_config_word(pdev, tfaddr-2, reg);
+}
+
+/**
+ * sil680_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Program the MWDMA/UDMA modes for the sil680 k
+ * chipset. The MWDMA mode values are pulled from a lookup table
+ * while the chipset uses mode number for UDMA.
+ */
+
+static void sil680_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ static u8 ultra_table[2][7] = {
+ { 0x0C, 0x07, 0x05, 0x04, 0x02, 0x01, 0xFF }, /* 100MHz */
+ { 0x0F, 0x0B, 0x07, 0x05, 0x03, 0x02, 0x01 }, /* 133Mhz */
+ };
+ static u16 dma_table[3] = { 0x2208, 0x10C2, 0x10C1 };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ unsigned long ma = sil680_seldev(ap, adev, 0x08);
+ unsigned long ua = sil680_seldev(ap, adev, 0x0C);
+ unsigned long addr_mask = 0x80 + 4 * ap->port_no;
+ int port_shift = adev->devno * 4;
+ u8 scsc, mode;
+ u16 multi, ultra;
+
+ pci_read_config_byte(pdev, 0x8A, &scsc);
+ pci_read_config_byte(pdev, addr_mask, &mode);
+ pci_read_config_word(pdev, ma, &multi);
+ pci_read_config_word(pdev, ua, &ultra);
+
+ /* Mask timing bits */
+ ultra &= ~0x3F;
+ mode &= ~(0x03 << port_shift);
+
+ /* Extract scsc */
+ scsc = (scsc & 0x30) ? 1: 0;
+
+ if (adev->dma_mode >= XFER_UDMA_0) {
+ multi = 0x10C1;
+ ultra |= ultra_table[scsc][adev->dma_mode - XFER_UDMA_0];
+ mode |= (0x03 << port_shift);
+ } else {
+ multi = dma_table[adev->dma_mode - XFER_MW_DMA_0];
+ mode |= (0x02 << port_shift);
+ }
+ pci_write_config_byte(pdev, addr_mask, mode);
+ pci_write_config_word(pdev, ma, multi);
+ pci_write_config_word(pdev, ua, ultra);
+}
+
+static struct scsi_host_template sil680_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations sil680_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sil680_set_piomode,
+ .set_dmamode = sil680_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sil680_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &sil680_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f,
+ .port_ops = &sil680_port_ops
+ };
+ static struct ata_port_info info_slow = {
+ .sht = &sil680_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &sil680_port_ops
+ };
+ static struct ata_port_info *port_info[2] = {&info, &info};
+ static int printed_version;
+ u32 class_rev = 0;
+ u8 tmpbyte = 0;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ pci_read_config_dword(pdev, PCI_CLASS_REVISION, &class_rev);
+ class_rev &= 0xff;
+ /* FIXME: double check */
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, (class_rev) ? 1 : 255);
+
+ pci_write_config_byte(pdev, 0x80, 0x00);
+ pci_write_config_byte(pdev, 0x84, 0x00);
+
+ pci_read_config_byte(pdev, 0x8A, &tmpbyte);
+
+ printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n",
+ tmpbyte & 1, tmpbyte & 0x30);
+
+ switch(tmpbyte & 0x30) {
+ case 0x00:
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(pdev, 0x8A, tmpbyte|0x10);
+ break;
+ case 0x30:
+ /* if clocking is disabled */
+ /* 133 clock attempt to force it on */
+ pci_write_config_byte(pdev, 0x8A, tmpbyte & ~0x20);
+ break;
+ case 0x10:
+ /* 133 already */
+ break;
+ case 0x20:
+ /* BIOS set PCI x2 clocking */
+ break;
+ }
+
+ pci_read_config_byte(pdev, 0x8A, &tmpbyte);
+ printk(KERN_INFO "sil680: BA5_EN = %d clock = %02X\n",
+ tmpbyte & 1, tmpbyte & 0x30);
+ if ((tmpbyte & 0x30) == 0)
+ port_info[0] = port_info[1] = &info_slow;
+
+ pci_write_config_byte(pdev, 0xA1, 0x72);
+ pci_write_config_word(pdev, 0xA2, 0x328A);
+ pci_write_config_dword(pdev, 0xA4, 0x62DD62DD);
+ pci_write_config_dword(pdev, 0xA8, 0x43924392);
+ pci_write_config_dword(pdev, 0xAC, 0x40094009);
+ pci_write_config_byte(pdev, 0xB1, 0x72);
+ pci_write_config_word(pdev, 0xB2, 0x328A);
+ pci_write_config_dword(pdev, 0xB4, 0x62DD62DD);
+ pci_write_config_dword(pdev, 0xB8, 0x43924392);
+ pci_write_config_dword(pdev, 0xBC, 0x40094009);
+
+ switch(tmpbyte & 0x30) {
+ case 0x00: printk(KERN_INFO "sil680: 100MHz clock.\n");break;
+ case 0x10: printk(KERN_INFO "sil680: 133MHz clock.\n");break;
+ case 0x20: printk(KERN_INFO "sil680: Using PCI clock.\n");break;
+ /* This last case is _NOT_ ok */
+ case 0x30: printk(KERN_ERR "sil680: Clock disabled ?\n");
+ return -EIO;
+ }
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id sil680[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), },
+ { 0, },
+};
+
+static struct pci_driver sil680_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sil680,
+ .probe = sil680_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init sil680_init(void)
+{
+ return pci_register_driver(&sil680_pci_driver);
+}
+
+
+static void __exit sil680_exit(void)
+{
+ pci_unregister_driver(&sil680_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for SI680 PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sil680);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sil680_init);
+module_exit(sil680_exit);
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
new file mode 100644
index 00000000000..17791e2785f
--- /dev/null
+++ b/drivers/ata/pata_sis.c
@@ -0,0 +1,1022 @@
+/*
+ * pata_sis.c - SiS ATA driver
+ *
+ * (C) 2005 Red Hat <alan@redhat.com>
+ *
+ * Based upon linux/drivers/ide/pci/sis5513.c
+ * Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
+ * Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
+ * Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz>
+ * SiS Taiwan : for direct support and hardware.
+ * Daniela Engert : for initial ATA100 advices and numerous others.
+ * John Fremlin, Manfred Spraul, Dave Morgan, Peter Kjellerstedt :
+ * for checking code correctness, providing patches.
+ * Original tests and design on the SiS620 chipset.
+ * ATA100 tests and design on the SiS735 chipset.
+ * ATA16/33 support from specs
+ * ATA133 support for SiS961/962 by L.C. Chang <lcchang@sis.com.tw>
+ *
+ *
+ * TODO
+ * Check MWDMA on drives that don't support MWDMA speed pio cycles ?
+ * More Testing
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/ata.h>
+
+#define DRV_NAME "pata_sis"
+#define DRV_VERSION "0.4.4"
+
+struct sis_chipset {
+ u16 device; /* PCI host ID */
+ struct ata_port_info *info; /* Info block */
+ /* Probably add family, cable detect type etc here to clean
+ up code later */
+};
+
+/**
+ * sis_port_base - return PCI configuration base for dev
+ * @adev: device
+ *
+ * Returns the base of the PCI configuration registers for this port
+ * number.
+ */
+
+static int sis_port_base(struct ata_device *adev)
+{
+ return 0x40 + (4 * adev->ap->port_no) + (2 * adev->devno);
+}
+
+/**
+ * sis_133_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection for the later UDMA133 capable
+ * SiS chipset.
+ */
+
+static int sis_133_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sis_enable_bits[] = {
+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 tmp;
+
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
+ return -ENOENT;
+
+ /* The top bit of this register is the cable detect bit */
+ pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
+ if (tmp & 0x8000)
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * sis_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sis_133_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+/**
+ * sis_66_pre_reset - check for 40/80 pin
+ * @ap: Port
+ *
+ * Perform cable detection on the UDMA66, UDMA100 and early UDMA133
+ * SiS IDE controllers.
+ */
+
+static int sis_66_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sis_enable_bits[] = {
+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 tmp;
+
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return 0;
+ }
+ /* Older chips keep cable detect in bits 4/5 of reg 0x48 */
+ pci_read_config_byte(pdev, 0x48, &tmp);
+ tmp >>= ap->port_no;
+ if (tmp & 0x10)
+ ap->cbl = ATA_CBL_PATA40;
+ else
+ ap->cbl = ATA_CBL_PATA80;
+
+ return ata_std_prereset(ap);
+}
+
+/**
+ * sis_66_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ * @classes:
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_66_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sis_66_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * sis_old_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int sis_old_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sis_enable_bits[] = {
+ { 0x4aU, 1U, 0x02UL, 0x02UL }, /* port 0 */
+ { 0x4aU, 1U, 0x04UL, 0x04UL }, /* port 1 */
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
+ ata_port_disable(ap);
+ printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+ return 0;
+ }
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * sis_old_error_handler - Probe specified port on PATA host controller
+ * @ap: Port to probe
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_old_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sis_old_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * sis_set_fifo - Set RWP fifo bits for this device
+ * @ap: Port
+ * @adev: Device
+ *
+ * SIS chipsets implement prefetch/postwrite bits for each device
+ * on both channels. This functionality is not ATAPI compatible and
+ * must be configured according to the class of device present
+ */
+
+static void sis_set_fifo(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u8 fifoctrl;
+ u8 mask = 0x11;
+
+ mask <<= (2 * ap->port_no);
+ mask <<= adev->devno;
+
+ /* This holds various bits including the FIFO control */
+ pci_read_config_byte(pdev, 0x4B, &fifoctrl);
+ fifoctrl &= ~mask;
+
+ /* Enable for ATA (disk) only */
+ if (adev->class == ATA_DEV_ATA)
+ fifoctrl |= mask;
+ pci_write_config_byte(pdev, 0x4B, fifoctrl);
+}
+
+/**
+ * sis_old_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring for.
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * function handles PIO set up for all chips that are pre ATA100 and
+ * also early ATA100 devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_old_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = sis_port_base(adev);
+ u8 t1, t2;
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ const u8 active[] = { 0x00, 0x07, 0x04, 0x03, 0x01 };
+ const u8 recovery[] = { 0x00, 0x06, 0x04, 0x03, 0x03 };
+
+ sis_set_fifo(ap, adev);
+
+ pci_read_config_byte(pdev, port, &t1);
+ pci_read_config_byte(pdev, port + 1, &t2);
+
+ t1 &= ~0x0F; /* Clear active/recovery timings */
+ t2 &= ~0x07;
+
+ t1 |= active[speed];
+ t2 |= recovery[speed];
+
+ pci_write_config_byte(pdev, port, t1);
+ pci_write_config_byte(pdev, port + 1, t2);
+}
+
+/**
+ * sis_100_set_pioode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring for.
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * function handles PIO set up for ATA100 devices and early ATA133.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_100_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = sis_port_base(adev);
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ const u8 actrec[] = { 0x00, 0x67, 0x44, 0x33, 0x31 };
+
+ sis_set_fifo(ap, adev);
+
+ pci_write_config_byte(pdev, port, actrec[speed]);
+}
+
+/**
+ * sis_133_set_pioode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device we are configuring for.
+ *
+ * Set PIO mode for device, in host controller PCI config space. This
+ * function handles PIO set up for the later ATA133 devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int port = 0x40;
+ u32 t1;
+ u32 reg54;
+ int speed = adev->pio_mode - XFER_PIO_0;
+
+ const u32 timing133[] = {
+ 0x28269000, /* Recovery << 24 | Act << 16 | Ini << 12 */
+ 0x0C266000,
+ 0x04263000,
+ 0x0C0A3000,
+ 0x05093000
+ };
+ const u32 timing100[] = {
+ 0x1E1C6000, /* Recovery << 24 | Act << 16 | Ini << 12 */
+ 0x091C4000,
+ 0x031C2000,
+ 0x09072000,
+ 0x04062000
+ };
+
+ sis_set_fifo(ap, adev);
+
+ /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
+ pci_read_config_dword(pdev, 0x54, &reg54);
+ if (reg54 & 0x40000000)
+ port = 0x70;
+ port += 8 * ap->port_no + 4 * adev->devno;
+
+ pci_read_config_dword(pdev, port, &t1);
+ t1 &= 0xC0C00FFF; /* Mask out timing */
+
+ if (t1 & 0x08) /* 100 or 133 ? */
+ t1 |= timing133[speed];
+ else
+ t1 |= timing100[speed];
+ pci_write_config_byte(pdev, port, t1);
+}
+
+/**
+ * sis_old_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles pre UDMA and UDMA33 devices. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_old_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
+ const u16 udma_bits[] = { 0xE000, 0xC000, 0xA000 };
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* bits 3-0 hold recovery timing bits 8-10 active timing and
+ the higer bits are dependant on the device */
+ timing &= ~ 0x870F;
+ timing |= mwdma_bits[speed];
+ pci_write_config_word(pdev, drive_pci, timing);
+ } else {
+ /* Bit 15 is UDMA on/off, bit 13-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x6000;
+ timing |= udma_bits[speed];
+ }
+}
+
+/**
+ * sis_66_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles UDMA66 and early UDMA100 devices. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_66_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 mwdma_bits[] = { 0x707, 0x202, 0x202 };
+ const u16 udma_bits[] = { 0xF000, 0xD000, 0xB000, 0xA000, 0x9000};
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* bits 3-0 hold recovery timing bits 8-10 active timing and
+ the higer bits are dependant on the device, bit 15 udma */
+ timing &= ~ 0x870F;
+ timing |= mwdma_bits[speed];
+ } else {
+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x6000;
+ timing |= udma_bits[speed];
+ }
+ pci_write_config_word(pdev, drive_pci, timing);
+}
+
+/**
+ * sis_100_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles UDMA66 and early UDMA100 devices.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_100_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 udma_bits[] = { 0x8B00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
+ } else {
+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x0F00;
+ timing |= udma_bits[speed];
+ }
+ pci_write_config_word(pdev, drive_pci, timing);
+}
+
+/**
+ * sis_133_early_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles early SiS 961 bridges. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_early_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int drive_pci = sis_port_base(adev);
+ u16 timing;
+
+ const u16 udma_bits[] = { 0x8F00, 0x8A00, 0x8700, 0x8500, 0x8300, 0x8200, 0x8100};
+
+ pci_read_config_word(pdev, drive_pci, &timing);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ /* NOT SUPPORTED YET: NEED DATA SHEET. DITTO IN OLD DRIVER */
+ } else {
+ /* Bit 15 is UDMA on/off, bit 12-14 are cycle time */
+ speed = adev->dma_mode - XFER_UDMA_0;
+ timing &= ~0x0F00;
+ timing |= udma_bits[speed];
+ }
+ pci_write_config_word(pdev, drive_pci, timing);
+}
+
+/**
+ * sis_133_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: Device to program
+ *
+ * Set UDMA/MWDMA mode for device, in host controller PCI config space.
+ * Handles early SiS 961 bridges. Supports MWDMA as well unlike
+ * the old ide/pci driver.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sis_133_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ int speed = adev->dma_mode - XFER_MW_DMA_0;
+ int port = 0x40;
+ u32 t1;
+ u32 reg54;
+
+ /* bits 4- cycle time 8 - cvs time */
+ const u32 timing_u100[] = { 0x6B0, 0x470, 0x350, 0x140, 0x120, 0x110, 0x000 };
+ const u32 timing_u133[] = { 0x9F0, 0x6A0, 0x470, 0x250, 0x230, 0x220, 0x210 };
+
+ /* If bit 14 is set then the registers are mapped at 0x70 not 0x40 */
+ pci_read_config_dword(pdev, 0x54, &reg54);
+ if (reg54 & 0x40000000)
+ port = 0x70;
+ port += (8 * ap->port_no) + (4 * adev->devno);
+
+ pci_read_config_dword(pdev, port, &t1);
+
+ if (adev->dma_mode < XFER_UDMA_0) {
+ t1 &= ~0x00000004;
+ /* FIXME: need data sheet to add MWDMA here. Also lacking on
+ ide/pci driver */
+ } else {
+ speed = adev->dma_mode - XFER_UDMA_0;
+ /* if & 8 no UDMA133 - need info for ... */
+ t1 &= ~0x00000FF0;
+ t1 |= 0x00000004;
+ if (t1 & 0x08)
+ t1 |= timing_u133[speed];
+ else
+ t1 |= timing_u100[speed];
+ }
+ pci_write_config_dword(pdev, port, t1);
+}
+
+static struct scsi_host_template sis_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static const struct ata_port_operations sis_133_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_133_set_piomode,
+ .set_dmamode = sis_133_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_133_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_133_early_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_100_set_piomode,
+ .set_dmamode = sis_133_early_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_66_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_100_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_100_set_piomode,
+ .set_dmamode = sis_100_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_66_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_66_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_old_set_piomode,
+ .set_dmamode = sis_66_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_66_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations sis_old_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sis_old_set_piomode,
+ .set_dmamode = sis_old_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = sis_old_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static struct ata_port_info sis_info = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07,
+ .udma_mask = 0,
+ .port_ops = &sis_old_ops,
+};
+static struct ata_port_info sis_info33 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07,
+ .udma_mask = ATA_UDMA2, /* UDMA 33 */
+ .port_ops = &sis_old_ops,
+};
+static struct ata_port_info sis_info66 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA4, /* UDMA 66 */
+ .port_ops = &sis_66_ops,
+};
+static struct ata_port_info sis_info100 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA5,
+ .port_ops = &sis_100_ops,
+};
+static struct ata_port_info sis_info100_early = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .udma_mask = ATA_UDMA5,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .port_ops = &sis_66_ops,
+};
+static struct ata_port_info sis_info133 = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sis_133_ops,
+};
+static struct ata_port_info sis_info133_early = {
+ .sht = &sis_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = ATA_UDMA6,
+ .port_ops = &sis_133_early_ops,
+};
+
+
+static void sis_fixup(struct pci_dev *pdev, struct sis_chipset *sis)
+{
+ u16 regw;
+ u8 reg;
+
+ if (sis->info == &sis_info133) {
+ pci_read_config_word(pdev, 0x50, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(pdev, 0x50, regw & ~0x08);
+ pci_read_config_word(pdev, 0x52, &regw);
+ if (regw & 0x08)
+ pci_write_config_word(pdev, 0x52, regw & ~0x08);
+ return;
+ }
+
+ if (sis->info == &sis_info133_early || sis->info == &sis_info100) {
+ /* Fix up latency */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
+ /* Set compatibility bit */
+ pci_read_config_byte(pdev, 0x49, &reg);
+ if (!(reg & 0x01))
+ pci_write_config_byte(pdev, 0x49, reg | 0x01);
+ return;
+ }
+
+ if (sis->info == &sis_info66 || sis->info == &sis_info100_early) {
+ /* Fix up latency */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);
+ /* Set compatibility bit */
+ pci_read_config_byte(pdev, 0x52, &reg);
+ if (!(reg & 0x04))
+ pci_write_config_byte(pdev, 0x52, reg | 0x04);
+ return;
+ }
+
+ if (sis->info == &sis_info33) {
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &reg);
+ if (( reg & 0x0F ) != 0x00)
+ pci_write_config_byte(pdev, PCI_CLASS_PROG, reg & 0xF0);
+ /* Fall through to ATA16 fixup below */
+ }
+
+ if (sis->info == &sis_info || sis->info == &sis_info33) {
+ /* force per drive recovery and active timings
+ needed on ATA_33 and below chips */
+ pci_read_config_byte(pdev, 0x52, &reg);
+ if (!(reg & 0x08))
+ pci_write_config_byte(pdev, 0x52, reg|0x08);
+ return;
+ }
+
+ BUG();
+}
+
+/**
+ * sis_init_one - Register SiS ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in sis_pci_tbl matching with @pdev
+ *
+ * Called from kernel PCI layer. We probe for combined mode (sigh),
+ * and then hand over control to libata, for it to do the rest.
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ static int printed_version;
+ static struct ata_port_info *port_info[2];
+ struct ata_port_info *port;
+ struct pci_dev *host = NULL;
+ struct sis_chipset *chipset = NULL;
+
+ static struct sis_chipset sis_chipsets[] = {
+
+ { 0x0968, &sis_info133 },
+ { 0x0966, &sis_info133 },
+ { 0x0965, &sis_info133 },
+ { 0x0745, &sis_info100 },
+ { 0x0735, &sis_info100 },
+ { 0x0733, &sis_info100 },
+ { 0x0635, &sis_info100 },
+ { 0x0633, &sis_info100 },
+
+ { 0x0730, &sis_info100_early }, /* 100 with ATA 66 layout */
+ { 0x0550, &sis_info100_early }, /* 100 with ATA 66 layout */
+
+ { 0x0640, &sis_info66 },
+ { 0x0630, &sis_info66 },
+ { 0x0620, &sis_info66 },
+ { 0x0540, &sis_info66 },
+ { 0x0530, &sis_info66 },
+
+ { 0x5600, &sis_info33 },
+ { 0x5598, &sis_info33 },
+ { 0x5597, &sis_info33 },
+ { 0x5591, &sis_info33 },
+ { 0x5582, &sis_info33 },
+ { 0x5581, &sis_info33 },
+
+ { 0x5596, &sis_info },
+ { 0x5571, &sis_info },
+ { 0x5517, &sis_info },
+ { 0x5511, &sis_info },
+
+ {0}
+ };
+ static struct sis_chipset sis133_early = {
+ 0x0, &sis_info133_early
+ };
+ static struct sis_chipset sis133 = {
+ 0x0, &sis_info133
+ };
+ static struct sis_chipset sis100_early = {
+ 0x0, &sis_info100_early
+ };
+ static struct sis_chipset sis100 = {
+ 0x0, &sis_info100
+ };
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* We have to find the bridge first */
+
+ for (chipset = &sis_chipsets[0]; chipset->device; chipset++) {
+ host = pci_get_device(PCI_VENDOR_ID_SI, chipset->device, NULL);
+ if (host != NULL) {
+ if (chipset->device == 0x630) { /* SIS630 */
+ u8 host_rev;
+ pci_read_config_byte(host, PCI_REVISION_ID, &host_rev);
+ if (host_rev >= 0x30) /* 630 ET */
+ chipset = &sis100_early;
+ }
+ break;
+ }
+ }
+
+ /* Look for concealed bridges */
+ if (host == NULL) {
+ /* Second check */
+ u32 idemisc;
+ u16 trueid;
+
+ /* Disable ID masking and register remapping then
+ see what the real ID is */
+
+ pci_read_config_dword(pdev, 0x54, &idemisc);
+ pci_write_config_dword(pdev, 0x54, idemisc & 0x7fffffff);
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid);
+ pci_write_config_dword(pdev, 0x54, idemisc);
+
+ switch(trueid) {
+ case 0x5518: /* SIS 962/963 */
+ chipset = &sis133;
+ if ((idemisc & 0x40000000) == 0) {
+ pci_write_config_dword(pdev, 0x54, idemisc | 0x40000000);
+ printk(KERN_INFO "SIS5513: Switching to 5513 register mapping\n");
+ }
+ break;
+ case 0x0180: /* SIS 965/965L */
+ chipset = &sis133;
+ break;
+ case 0x1180: /* SIS 966/966L */
+ chipset = &sis133;
+ break;
+ }
+ }
+
+ /* Further check */
+ if (chipset == NULL) {
+ struct pci_dev *lpc_bridge;
+ u16 trueid;
+ u8 prefctl;
+ u8 idecfg;
+ u8 sbrev;
+
+ /* Try the second unmasking technique */
+ pci_read_config_byte(pdev, 0x4a, &idecfg);
+ pci_write_config_byte(pdev, 0x4a, idecfg | 0x10);
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &trueid);
+ pci_write_config_byte(pdev, 0x4a, idecfg);
+
+ switch(trueid) {
+ case 0x5517:
+ lpc_bridge = pci_get_slot(pdev->bus, 0x10); /* Bus 0 Dev 2 Fn 0 */
+ if (lpc_bridge == NULL)
+ break;
+ pci_read_config_byte(lpc_bridge, PCI_REVISION_ID, &sbrev);
+ pci_read_config_byte(pdev, 0x49, &prefctl);
+ pci_dev_put(lpc_bridge);
+
+ if (sbrev == 0x10 && (prefctl & 0x80)) {
+ chipset = &sis133_early;
+ break;
+ }
+ chipset = &sis100;
+ break;
+ }
+ }
+ pci_dev_put(host);
+
+ /* No chipset info, no support */
+ if (chipset == NULL)
+ return -ENODEV;
+
+ port = chipset->info;
+ port->private_data = chipset;
+
+ sis_fixup(pdev, chipset);
+
+ port_info[0] = port_info[1] = port;
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id sis_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), }, /* SiS 5513 */
+ { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), }, /* SiS 5518 */
+ { }
+};
+
+static struct pci_driver sis_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sis_pci_tbl,
+ .probe = sis_init_one,
+ .remove = ata_pci_remove_one,
+};
+
+static int __init sis_init(void)
+{
+ return pci_register_driver(&sis_pci_driver);
+}
+
+static void __exit sis_exit(void)
+{
+ pci_unregister_driver(&sis_pci_driver);
+}
+
+
+module_init(sis_init);
+module_exit(sis_exit);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("SCSI low-level driver for SiS ATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
new file mode 100644
index 00000000000..5b762acc568
--- /dev/null
+++ b/drivers/ata/pata_sl82c105.c
@@ -0,0 +1,385 @@
+/*
+ * pata_sl82c105.c - SL82C105 PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Based in part on linux/drivers/ide/pci/sl82c105.c
+ * SL82C105/Winbond 553 IDE driver
+ *
+ * and in part on the documentation and errata sheet
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_sl82c105"
+#define DRV_VERSION "0.2.3"
+
+enum {
+ /*
+ * SL82C105 PCI config register 0x40 bits.
+ */
+ CTRL_IDE_IRQB = (1 << 30),
+ CTRL_IDE_IRQA = (1 << 28),
+ CTRL_LEGIRQ = (1 << 11),
+ CTRL_P1F16 = (1 << 5),
+ CTRL_P1EN = (1 << 4),
+ CTRL_P0F16 = (1 << 1),
+ CTRL_P0EN = (1 << 0)
+};
+
+/**
+ * sl82c105_pre_reset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int sl82c105_pre_reset(struct ata_port *ap)
+{
+ static const struct pci_bits sl82c105_enable_bits[] = {
+ { 0x40, 1, 0x01, 0x01 },
+ { 0x40, 1, 0x10, 0x10 }
+ };
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+static void sl82c105_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, sl82c105_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+
+/**
+ * sl82c105_configure_piomode - set chip PIO timing
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @pio: PIO mode
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * so a configure_dmamode call will undo any work we do here and vice
+ * versa
+ */
+
+static void sl82c105_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static u16 pio_timing[5] = {
+ 0x50D, 0x407, 0x304, 0x242, 0x240
+ };
+ u16 dummy;
+ int timing = 0x44 + (8 * ap->port_no) + (4 * adev->devno);
+
+ pci_write_config_word(pdev, timing, pio_timing[pio]);
+ /* Can we lose this oddity of the old driver */
+ pci_read_config_word(pdev, timing, &dummy);
+}
+
+/**
+ * sl82c105_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the PIO mode setup. Our timing registers are shared
+ * but we want to set the PIO timing by default.
+ */
+
+static void sl82c105_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ sl82c105_configure_piomode(ap, adev, adev->pio_mode - XFER_PIO_0);
+}
+
+/**
+ * sl82c105_configure_dmamode - set DMA mode in chip
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Load DMA cycle times into the chip ready for a DMA transfer
+ * to occur.
+ */
+
+static void sl82c105_configure_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ static u16 dma_timing[3] = {
+ 0x707, 0x201, 0x200
+ };
+ u16 dummy;
+ int timing = 0x44 + (8 * ap->port_no) + (4 * adev->devno);
+ int dma = adev->dma_mode - XFER_MW_DMA_0;
+
+ pci_write_config_word(pdev, timing, dma_timing[dma]);
+ /* Can we lose this oddity of the old driver */
+ pci_read_config_word(pdev, timing, &dummy);
+}
+
+/**
+ * sl82c105_set_dmamode - set initial DMA mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Called to do the DMA mode setup. This replaces the PIO timings
+ * for the device in question. Set appropriate PIO timings not DMA
+ * timings at this point.
+ */
+
+static void sl82c105_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ switch(adev->dma_mode) {
+ case XFER_MW_DMA_0:
+ sl82c105_configure_piomode(ap, adev, 1);
+ break;
+ case XFER_MW_DMA_1:
+ sl82c105_configure_piomode(ap, adev, 3);
+ break;
+ case XFER_MW_DMA_2:
+ sl82c105_configure_piomode(ap, adev, 3);
+ break;
+ default:
+ BUG();
+ }
+}
+
+/**
+ * sl82c105_reset_engine - Reset the DMA engine
+ * @ap: ATA interface
+ *
+ * The sl82c105 has some serious problems with the DMA engine
+ * when transfers don't run as expected or ATAPI is used. The
+ * recommended fix is to reset the engine each use using a chip
+ * test register.
+ */
+
+static void sl82c105_reset_engine(struct ata_port *ap)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u16 val;
+
+ pci_read_config_word(pdev, 0x7E, &val);
+ pci_write_config_word(pdev, 0x7E, val | 4);
+ pci_write_config_word(pdev, 0x7E, val & ~4);
+}
+
+/**
+ * sl82c105_bmdma_start - DMA engine begin
+ * @qc: ATA command
+ *
+ * Reset the DMA engine each use as recommended by the errata
+ * document.
+ *
+ * FIXME: if we switch clock at BMDMA start/end we might get better
+ * PIO performance on DMA capable devices.
+ */
+
+static void sl82c105_bmdma_start(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ sl82c105_reset_engine(ap);
+
+ /* Set the clocks for DMA */
+ sl82c105_configure_dmamode(ap, qc->dev);
+ /* Activate DMA */
+ ata_bmdma_start(qc);
+}
+
+/**
+ * sl82c105_bmdma_end - DMA engine stop
+ * @qc: ATA command
+ *
+ * Reset the DMA engine each use as recommended by the errata
+ * document.
+ *
+ * This function is also called to turn off DMA when a timeout occurs
+ * during DMA operation. In both cases we need to reset the engine,
+ * so no actual eng_timeout handler is required.
+ *
+ * We assume bmdma_stop is always called if bmdma_start as called. If
+ * not then we may need to wrap qc_issue.
+ */
+
+static void sl82c105_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+
+ ata_bmdma_stop(qc);
+ sl82c105_reset_engine(ap);
+
+ /* This will redo the initial setup of the DMA device to matching
+ PIO timings */
+ sl82c105_set_dmamode(ap, qc->dev);
+}
+
+static struct scsi_host_template sl82c105_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations sl82c105_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = sl82c105_set_piomode,
+ .set_dmamode = sl82c105_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .error_handler = sl82c105_error_handler,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = sl82c105_bmdma_start,
+ .bmdma_stop = sl82c105_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * sl82c105_bridge_revision - find bridge version
+ * @pdev: PCI device for the ATA function
+ *
+ * Locates the PCI bridge associated with the ATA function and
+ * providing it is a Winbond 553 reports the revision. If it cannot
+ * find a revision or the right device it returns -1
+ */
+
+static int sl82c105_bridge_revision(struct pci_dev *pdev)
+{
+ struct pci_dev *bridge;
+ u8 rev;
+
+ /*
+ * The bridge should be part of the same device, but function 0.
+ */
+ bridge = pci_get_slot(pdev->bus,
+ PCI_DEVFN(PCI_SLOT(pdev->devfn), 0));
+ if (!bridge)
+ return -1;
+
+ /*
+ * Make sure it is a Winbond 553 and is an ISA bridge.
+ */
+ if (bridge->vendor != PCI_VENDOR_ID_WINBOND ||
+ bridge->device != PCI_DEVICE_ID_WINBOND_83C553 ||
+ bridge->class >> 8 != PCI_CLASS_BRIDGE_ISA) {
+ pci_dev_put(bridge);
+ return -1;
+ }
+ /*
+ * We need to find function 0's revision, not function 1
+ */
+ pci_read_config_byte(bridge, PCI_REVISION_ID, &rev);
+
+ pci_dev_put(bridge);
+ return rev;
+}
+
+
+static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info_dma = {
+ .sht = &sl82c105_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &sl82c105_port_ops
+ };
+ static struct ata_port_info info_early = {
+ .sht = &sl82c105_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .port_ops = &sl82c105_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info_early, &info_early };
+ u32 val;
+ int rev;
+
+ rev = sl82c105_bridge_revision(dev);
+
+ if (rev == -1)
+ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Unable to find bridge, disabling DMA.\n");
+ else if (rev <= 5)
+ dev_printk(KERN_WARNING, &dev->dev, "pata_sl82c105: Early bridge revision, no DMA available.\n");
+ else {
+ port_info[0] = &info_dma;
+ port_info[1] = &info_dma;
+ }
+
+ pci_read_config_dword(dev, 0x40, &val);
+ val |= CTRL_P0EN | CTRL_P0F16 | CTRL_P1F16;
+ pci_write_config_dword(dev, 0x40, val);
+
+
+ return ata_pci_init_one(dev, port_info, 1); /* For now */
+}
+
+static struct pci_device_id sl82c105[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
+ { 0, },
+};
+
+static struct pci_driver sl82c105_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sl82c105,
+ .probe = sl82c105_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init sl82c105_init(void)
+{
+ return pci_register_driver(&sl82c105_pci_driver);
+}
+
+
+static void __exit sl82c105_exit(void)
+{
+ pci_unregister_driver(&sl82c105_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Sl82c105");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sl82c105);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(sl82c105_init);
+module_exit(sl82c105_exit);
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
new file mode 100644
index 00000000000..a954ed93a40
--- /dev/null
+++ b/drivers/ata/pata_triflex.c
@@ -0,0 +1,282 @@
+/*
+ * pata_triflex.c - Compaq PATA for new ATA layer
+ * (C) 2005 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * based upon
+ *
+ * triflex.c
+ *
+ * IDE Chipset driver for the Compaq TriFlex IDE controller.
+ *
+ * Known to work with the Compaq Workstation 5x00 series.
+ *
+ * Copyright (C) 2002 Hewlett-Packard Development Group, L.P.
+ * Author: Torben Mathiasen <torben.mathiasen@hp.com>
+ *
+ * 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.
+ *
+ * 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
+ *
+ * Loosely based on the piix & svwks drivers.
+ *
+ * Documentation:
+ * Not publically available.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_triflex"
+#define DRV_VERSION "0.2.5"
+
+/**
+ * triflex_prereset - probe begin
+ * @ap: ATA port
+ *
+ * Set up cable type and use generic probe init
+ */
+
+static int triflex_prereset(struct ata_port *ap)
+{
+ static const struct pci_bits triflex_enable_bits[] = {
+ { 0x80, 1, 0x01, 0x01 },
+ { 0x80, 1, 0x02, 0x02 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
+ return -ENOENT;
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+
+static void triflex_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, triflex_prereset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * triflex_load_timing - timing configuration
+ * @ap: ATA interface
+ * @adev: Device on the bus
+ * @speed: speed to configure
+ *
+ * The Triflex has one set of timings per device per channel. This
+ * means we must do some switching. As the PIO and DMA timings don't
+ * match we have to do some reloading unlike PIIX devices where tuning
+ * tricks can avoid it.
+ */
+
+static void triflex_load_timing(struct ata_port *ap, struct ata_device *adev, int speed)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 timing = 0;
+ u32 triflex_timing, old_triflex_timing;
+ int channel_offset = ap->port_no ? 0x74: 0x70;
+ unsigned int is_slave = (adev->devno != 0);
+
+
+ pci_read_config_dword(pdev, channel_offset, &old_triflex_timing);
+ triflex_timing = old_triflex_timing;
+
+ switch(speed)
+ {
+ case XFER_MW_DMA_2:
+ timing = 0x0103;break;
+ case XFER_MW_DMA_1:
+ timing = 0x0203;break;
+ case XFER_MW_DMA_0:
+ timing = 0x0808;break;
+ case XFER_SW_DMA_2:
+ case XFER_SW_DMA_1:
+ case XFER_SW_DMA_0:
+ timing = 0x0F0F;break;
+ case XFER_PIO_4:
+ timing = 0x0202;break;
+ case XFER_PIO_3:
+ timing = 0x0204;break;
+ case XFER_PIO_2:
+ timing = 0x0404;break;
+ case XFER_PIO_1:
+ timing = 0x0508;break;
+ case XFER_PIO_0:
+ timing = 0x0808;break;
+ default:
+ BUG();
+ }
+ triflex_timing &= ~ (0xFFFF << (16 * is_slave));
+ triflex_timing |= (timing << (16 * is_slave));
+
+ if (triflex_timing != old_triflex_timing)
+ pci_write_config_dword(pdev, channel_offset, triflex_timing);
+}
+
+/**
+ * triflex_set_piomode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * Use the timing loader to set up the PIO mode. We have to do this
+ * because DMA start/stop will only be called once DMA occurs. If there
+ * has been no DMA then the PIO timings are still needed.
+ */
+static void triflex_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ triflex_load_timing(ap, adev, adev->pio_mode);
+}
+
+/**
+ * triflex_dma_start - DMA start callback
+ * @qc: Command in progress
+ *
+ * Usually drivers set the DMA timing at the point the set_dmamode call
+ * is made. Triflex however requires we load new timings on the
+ * transition or keep matching PIO/DMA pairs (ie MWDMA2/PIO4 etc).
+ * We load the DMA timings just before starting DMA and then restore
+ * the PIO timing when the DMA is finished.
+ */
+
+static void triflex_bmdma_start(struct ata_queued_cmd *qc)
+{
+ triflex_load_timing(qc->ap, qc->dev, qc->dev->dma_mode);
+ ata_bmdma_start(qc);
+}
+
+/**
+ * triflex_dma_stop - DMA stop callback
+ * @ap: ATA interface
+ * @adev: ATA device
+ *
+ * We loaded new timings in dma_start, as a result we need to restore
+ * the PIO timings in dma_stop so that the next command issue gets the
+ * right clock values.
+ */
+
+static void triflex_bmdma_stop(struct ata_queued_cmd *qc)
+{
+ ata_bmdma_stop(qc);
+ triflex_load_timing(qc->ap, qc->dev, qc->dev->pio_mode);
+}
+
+static struct scsi_host_template triflex_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations triflex_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = triflex_set_piomode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = triflex_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = triflex_bmdma_start,
+ .bmdma_stop = triflex_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ static struct ata_port_info info = {
+ .sht = &triflex_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &triflex_port_ops
+ };
+ static struct ata_port_info *port_info[2] = { &info, &info };
+ static int printed_version;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &dev->dev, "version " DRV_VERSION "\n");
+
+ return ata_pci_init_one(dev, port_info, 2);
+}
+
+static const struct pci_device_id triflex[] = {
+ { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { 0, },
+};
+
+static struct pci_driver triflex_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = triflex,
+ .probe = triflex_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init triflex_init(void)
+{
+ return pci_register_driver(&triflex_pci_driver);
+}
+
+
+static void __exit triflex_exit(void)
+{
+ pci_unregister_driver(&triflex_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, triflex);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(triflex_init);
+module_exit(triflex_exit);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
new file mode 100644
index 00000000000..7b5dd2343b9
--- /dev/null
+++ b/drivers/ata/pata_via.c
@@ -0,0 +1,565 @@
+/*
+ * pata_via.c - VIA PATA for new ATA layer
+ * (C) 2005-2006 Red Hat Inc
+ * Alan Cox <alan@redhat.com>
+ *
+ * Documentation
+ * Most chipset documentation available under NDA only
+ *
+ * VIA version guide
+ * VIA VT82C561 - early design, uses ata_generic currently
+ * VIA VT82C576 - MWDMA, 33Mhz
+ * VIA VT82C586 - MWDMA, 33Mhz
+ * VIA VT82C586a - Added UDMA to 33Mhz
+ * VIA VT82C586b - UDMA33
+ * VIA VT82C596a - Nonfunctional UDMA66
+ * VIA VT82C596b - Working UDMA66
+ * VIA VT82C686 - Nonfunctional UDMA66
+ * VIA VT82C686a - Working UDMA66
+ * VIA VT82C686b - Updated to UDMA100
+ * VIA VT8231 - UDMA100
+ * VIA VT8233 - UDMA100
+ * VIA VT8233a - UDMA133
+ * VIA VT8233c - UDMA100
+ * VIA VT8235 - UDMA133
+ * VIA VT8237 - UDMA133
+ *
+ * Most registers remain compatible across chips. Others start reserved
+ * and acquire sensible semantics if set to 1 (eg cable detect). A few
+ * exceptions exist, notably around the FIFO settings.
+ *
+ * One additional quirk of the VIA design is that like ALi they use few
+ * PCI IDs for a lot of chips.
+ *
+ * Based heavily on:
+ *
+ * Version 3.38
+ *
+ * VIA IDE driver for Linux. Supported southbridges:
+ *
+ * vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
+ * vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
+ * vt8235, vt8237
+ *
+ * Copyright (c) 2000-2002 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Michel Aubry
+ * Jeff Garzik
+ * Andre Hedrick
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME "pata_via"
+#define DRV_VERSION "0.1.14"
+
+/*
+ * The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
+ * driver.
+ */
+
+enum {
+ VIA_UDMA = 0x007,
+ VIA_UDMA_NONE = 0x000,
+ VIA_UDMA_33 = 0x001,
+ VIA_UDMA_66 = 0x002,
+ VIA_UDMA_100 = 0x003,
+ VIA_UDMA_133 = 0x004,
+ VIA_BAD_PREQ = 0x010, /* Crashes if PREQ# till DDACK# set */
+ VIA_BAD_CLK66 = 0x020, /* 66 MHz clock doesn't work correctly */
+ VIA_SET_FIFO = 0x040, /* Needs to have FIFO split set */
+ VIA_NO_UNMASK = 0x080, /* Doesn't work with IRQ unmasking on */
+ VIA_BAD_ID = 0x100, /* Has wrong vendor ID (0x1107) */
+ VIA_BAD_AST = 0x200, /* Don't touch Address Setup Timing */
+ VIA_NO_ENABLES = 0x400, /* Has no enablebits */
+};
+
+/*
+ * VIA SouthBridge chips.
+ */
+
+static const struct via_isa_bridge {
+ const char *name;
+ u16 id;
+ u8 rev_min;
+ u8 rev_max;
+ u16 flags;
+} via_isa_bridges[] = {
+ { "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
+ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt8233", PCI_DEVICE_ID_VIA_8233_0, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt8231", PCI_DEVICE_ID_VIA_8231, 0x00, 0x2f, VIA_UDMA_100 },
+ { "vt82c686b", PCI_DEVICE_ID_VIA_82C686, 0x40, 0x4f, VIA_UDMA_100 },
+ { "vt82c686a", PCI_DEVICE_ID_VIA_82C686, 0x10, 0x2f, VIA_UDMA_66 },
+ { "vt82c686", PCI_DEVICE_ID_VIA_82C686, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+ { "vt82c596b", PCI_DEVICE_ID_VIA_82C596, 0x10, 0x2f, VIA_UDMA_66 },
+ { "vt82c596a", PCI_DEVICE_ID_VIA_82C596, 0x00, 0x0f, VIA_UDMA_33 | VIA_BAD_CLK66 },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x47, 0x4f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x40, 0x46, VIA_UDMA_33 | VIA_SET_FIFO | VIA_BAD_PREQ },
+ { "vt82c586b", PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586a", PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
+ { "vt82c586", PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
+ { "vt82c576", PCI_DEVICE_ID_VIA_82C576, 0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK | VIA_BAD_ID },
+ { NULL }
+};
+
+/**
+ * via_cable_detect - cable detection
+ * @ap: ATA port
+ *
+ * Perform cable detection. Actually for the VIA case the BIOS
+ * already did this for us. We read the values provided by the
+ * BIOS. If you are using an 8235 in a non-PC configuration you
+ * may need to update this code.
+ *
+ * Hotplug also impacts on this.
+ */
+
+static int via_cable_detect(struct ata_port *ap) {
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ u32 ata66;
+
+ pci_read_config_dword(pdev, 0x50, &ata66);
+ /* Check both the drive cable reporting bits, we might not have
+ two drives */
+ if (ata66 & (0x10100000 >> (16 * ap->port_no)))
+ return ATA_CBL_PATA80;
+ else
+ return ATA_CBL_PATA40;
+}
+
+static int via_pre_reset(struct ata_port *ap)
+{
+ const struct via_isa_bridge *config = ap->host->private_data;
+
+ if (!(config->flags & VIA_NO_ENABLES)) {
+ static const struct pci_bits via_enable_bits[] = {
+ { 0x40, 1, 0x02, 0x02 },
+ { 0x40, 1, 0x01, 0x01 }
+ };
+
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no]))
+ return -ENOENT;
+ }
+
+ if ((config->flags & VIA_UDMA) >= VIA_UDMA_66)
+ ap->cbl = via_cable_detect(ap);
+ else
+ ap->cbl = ATA_CBL_PATA40;
+ return ata_std_prereset(ap);
+}
+
+
+/**
+ * via_error_handler - reset for VIA chips
+ * @ap: ATA port
+ *
+ * Handle the reset callback for the later chips with cable detect
+ */
+
+static void via_error_handler(struct ata_port *ap)
+{
+ ata_bmdma_drive_eh(ap, via_pre_reset, ata_std_softreset, NULL, ata_std_postreset);
+}
+
+/**
+ * via_do_set_mode - set initial PIO mode data
+ * @ap: ATA interface
+ * @adev: ATA device
+ * @mode: ATA mode being programmed
+ * @tdiv: Clocks per PCI clock
+ * @set_ast: Set to program address setup
+ * @udma_type: UDMA mode/format of registers
+ *
+ * Program the VIA registers for DMA and PIO modes. Uses the ata timing
+ * support in order to compute modes.
+ *
+ * FIXME: Hotplug will require we serialize multiple mode changes
+ * on the two channels.
+ */
+
+static void via_do_set_mode(struct ata_port *ap, struct ata_device *adev, int mode, int tdiv, int set_ast, int udma_type)
+{
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+ struct ata_device *peer = ata_dev_pair(adev);
+ struct ata_timing t, p;
+ static int via_clock = 33333; /* Bus clock in kHZ - ought to be tunable one day */
+ unsigned long T = 1000000000 / via_clock;
+ unsigned long UT = T/tdiv;
+ int ut;
+ int offset = 3 - (2*ap->port_no) - adev->devno;
+
+
+ /* Calculate the timing values we require */
+ ata_timing_compute(adev, mode, &t, T, UT);
+
+ /* We share 8bit timing so we must merge the constraints */
+ if (peer) {
+ if (peer->pio_mode) {
+ ata_timing_compute(peer, peer->pio_mode, &p, T, UT);
+ ata_timing_merge(&p, &t, &t, ATA_TIMING_8BIT);
+ }
+ }
+
+ /* Address setup is programmable but breaks on UDMA133 setups */
+ if (set_ast) {
+ u8 setup; /* 2 bits per drive */
+ int shift = 2 * offset;
+
+ pci_read_config_byte(pdev, 0x4C, &setup);
+ setup &= ~(3 << shift);
+ setup |= FIT(t.setup, 1, 4) << shift; /* 1,4 or 1,4 - 1 FIXME */
+ pci_write_config_byte(pdev, 0x4C, setup);
+ }
+
+ /* Load the PIO mode bits */
+ pci_write_config_byte(pdev, 0x4F - ap->port_no,
+ ((FIT(t.act8b, 1, 16) - 1) << 4) | (FIT(t.rec8b, 1, 16) - 1));
+ pci_write_config_byte(pdev, 0x48 + offset,
+ ((FIT(t.active, 1, 16) - 1) << 4) | (FIT(t.recover, 1, 16) - 1));
+
+ /* Load the UDMA bits according to type */
+ switch(udma_type) {
+ default:
+ /* BUG() ? */
+ /* fall through */
+ case 33:
+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 5) - 2)) : 0x03;
+ break;
+ case 66:
+ ut = t.udma ? (0xe8 | (FIT(t.udma, 2, 9) - 2)) : 0x0f;
+ break;
+ case 100:
+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ break;
+ case 133:
+ ut = t.udma ? (0xe0 | (FIT(t.udma, 2, 9) - 2)) : 0x07;
+ break;
+ }
+ /* Set UDMA unless device is not UDMA capable */
+ if (udma_type)
+ pci_write_config_byte(pdev, 0x50 + offset, ut);
+}
+
+static void via_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ const struct via_isa_bridge *config = ap->host->private_data;
+ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
+ int mode = config->flags & VIA_UDMA;
+ static u8 tclock[5] = { 1, 1, 2, 3, 4 };
+ static u8 udma[5] = { 0, 33, 66, 100, 133 };
+
+ via_do_set_mode(ap, adev, adev->pio_mode, tclock[mode], set_ast, udma[mode]);
+}
+
+static void via_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ const struct via_isa_bridge *config = ap->host->private_data;
+ int set_ast = (config->flags & VIA_BAD_AST) ? 0 : 1;
+ int mode = config->flags & VIA_UDMA;
+ static u8 tclock[5] = { 1, 1, 2, 3, 4 };
+ static u8 udma[5] = { 0, 33, 66, 100, 133 };
+
+ via_do_set_mode(ap, adev, adev->dma_mode, tclock[mode], set_ast, udma[mode]);
+}
+
+static struct scsi_host_template via_sht = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .ioctl = ata_scsi_ioctl,
+ .queuecommand = ata_scsi_queuecmd,
+ .can_queue = ATA_DEF_QUEUE,
+ .this_id = ATA_SHT_THIS_ID,
+ .sg_tablesize = LIBATA_MAX_PRD,
+ .max_sectors = ATA_MAX_SECTORS,
+ .cmd_per_lun = ATA_SHT_CMD_PER_LUN,
+ .emulated = ATA_SHT_EMULATED,
+ .use_clustering = ATA_SHT_USE_CLUSTERING,
+ .proc_name = DRV_NAME,
+ .dma_boundary = ATA_DMA_BOUNDARY,
+ .slave_configure = ata_scsi_slave_config,
+ .bios_param = ata_std_bios_param,
+};
+
+static struct ata_port_operations via_port_ops = {
+ .port_disable = ata_port_disable,
+ .set_piomode = via_set_piomode,
+ .set_dmamode = via_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = via_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+static struct ata_port_operations via_port_ops_noirq = {
+ .port_disable = ata_port_disable,
+ .set_piomode = via_set_piomode,
+ .set_dmamode = via_set_dmamode,
+ .mode_filter = ata_pci_default_filter,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = via_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+
+ .data_xfer = ata_pio_data_xfer_noirq,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop
+};
+
+/**
+ * via_init_one - discovery callback
+ * @pdev: PCI device ID
+ * @id: PCI table info
+ *
+ * A VIA IDE interface has been discovered. Figure out what revision
+ * and perform configuration work before handing it to the ATA layer
+ */
+
+static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ /* Early VIA without UDMA support */
+ static struct ata_port_info via_mwdma_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &via_port_ops
+ };
+ /* Ditto with IRQ masking required */
+ static struct ata_port_info via_mwdma_info_borked = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .port_ops = &via_port_ops_noirq,
+ };
+ /* VIA UDMA 33 devices (and borked 66) */
+ static struct ata_port_info via_udma33_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7,
+ .port_ops = &via_port_ops
+ };
+ /* VIA UDMA 66 devices */
+ static struct ata_port_info via_udma66_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x1f,
+ .port_ops = &via_port_ops
+ };
+ /* VIA UDMA 100 devices */
+ static struct ata_port_info via_udma100_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x3f,
+ .port_ops = &via_port_ops
+ };
+ /* UDMA133 with bad AST (All current 133) */
+ static struct ata_port_info via_udma133_info = {
+ .sht = &via_sht,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+ .pio_mask = 0x1f,
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* FIXME: should check north bridge */
+ .port_ops = &via_port_ops
+ };
+ struct ata_port_info *port_info[2], *type;
+ struct pci_dev *isa = NULL;
+ const struct via_isa_bridge *config;
+ static int printed_version;
+ u8 t;
+ u8 enable;
+ u32 timing;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
+
+ /* To find out how the IDE will behave and what features we
+ actually have to look at the bridge not the IDE controller */
+ for (config = via_isa_bridges; config->id; config++)
+ if ((isa = pci_get_device(PCI_VENDOR_ID_VIA +
+ !!(config->flags & VIA_BAD_ID),
+ config->id, NULL))) {
+
+ pci_read_config_byte(isa, PCI_REVISION_ID, &t);
+ if (t >= config->rev_min &&
+ t <= config->rev_max)
+ break;
+ pci_dev_put(isa);
+ }
+
+ if (!config->id) {
+ printk(KERN_WARNING "via: Unknown VIA SouthBridge, disabling.\n");
+ return -ENODEV;
+ }
+ pci_dev_put(isa);
+
+ /* 0x40 low bits indicate enabled channels */
+ pci_read_config_byte(pdev, 0x40 , &enable);
+ enable &= 3;
+ if (enable == 0) {
+ return -ENODEV;
+ }
+
+ /* Initialise the FIFO for the enabled channels. */
+ if (config->flags & VIA_SET_FIFO) {
+ u8 fifo_setting[4] = {0x00, 0x60, 0x00, 0x20};
+ u8 fifo;
+
+ pci_read_config_byte(pdev, 0x43, &fifo);
+
+ /* Clear PREQ# until DDACK# for errata */
+ if (config->flags & VIA_BAD_PREQ)
+ fifo &= 0x7F;
+ else
+ fifo &= 0x9f;
+ /* Turn on FIFO for enabled channels */
+ fifo |= fifo_setting[enable];
+ pci_write_config_byte(pdev, 0x43, fifo);
+ }
+ /* Clock set up */
+ switch(config->flags & VIA_UDMA) {
+ case VIA_UDMA_NONE:
+ if (config->flags & VIA_NO_UNMASK)
+ type = &via_mwdma_info_borked;
+ else
+ type = &via_mwdma_info;
+ break;
+ case VIA_UDMA_33:
+ type = &via_udma33_info;
+ break;
+ case VIA_UDMA_66:
+ type = &via_udma66_info;
+ /* The 66 MHz devices require we enable the clock */
+ pci_read_config_dword(pdev, 0x50, &timing);
+ timing |= 0x80008;
+ pci_write_config_dword(pdev, 0x50, timing);
+ break;
+ case VIA_UDMA_100:
+ type = &via_udma100_info;
+ break;
+ case VIA_UDMA_133:
+ type = &via_udma133_info;
+ break;
+ default:
+ WARN_ON(1);
+ return -ENODEV;
+ }
+
+ if (config->flags & VIA_BAD_CLK66) {
+ /* Disable the 66MHz clock on problem devices */
+ pci_read_config_dword(pdev, 0x50, &timing);
+ timing &= ~0x80008;
+ pci_write_config_dword(pdev, 0x50, timing);
+ }
+
+ /* We have established the device type, now fire it up */
+ type->private_data = (void *)config;
+
+ port_info[0] = port_info[1] = type;
+ return ata_pci_init_one(pdev, port_info, 2);
+}
+
+static const struct pci_device_id via[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410), },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
+ { 0, },
+};
+
+static struct pci_driver via_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = via,
+ .probe = via_init_one,
+ .remove = ata_pci_remove_one
+};
+
+static int __init via_init(void)
+{
+ return pci_register_driver(&via_pci_driver);
+}
+
+
+static void __exit via_exit(void)
+{
+ pci_unregister_driver(&via_pci_driver);
+}
+
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("low-level driver for VIA PATA");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, via);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(via_init);
+module_exit(via_exit);
diff --git a/drivers/scsi/pdc_adma.c b/drivers/ata/pdc_adma.c
index 7ebe8e03aa9..0e23ecb77bc 100644
--- a/drivers/scsi/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -127,7 +127,7 @@ static int adma_ata_init_one (struct pci_dev *pdev,
static irqreturn_t adma_intr (int irq, void *dev_instance,
struct pt_regs *regs);
static int adma_port_start(struct ata_port *ap);
-static void adma_host_stop(struct ata_host_set *host_set);
+static void adma_host_stop(struct ata_host *host);
static void adma_port_stop(struct ata_port *ap);
static void adma_phy_reset(struct ata_port *ap);
static void adma_qc_prep(struct ata_queued_cmd *qc);
@@ -182,8 +182,9 @@ static struct ata_port_info adma_port_info[] = {
/* board_1841_idx */
{
.sht = &adma_ata_sht,
- .host_flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
- ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO,
+ .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+ ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO |
+ ATA_FLAG_PIO_POLLING,
.pio_mask = 0x10, /* pio4 */
.udma_mask = 0x1f, /* udma0-4 */
.port_ops = &adma_ata_ops,
@@ -236,7 +237,7 @@ static void adma_reset_engine(void __iomem *chan)
static void adma_reinit_engine(struct ata_port *ap)
{
struct adma_port_priv *pp = ap->private_data;
- void __iomem *mmio_base = ap->host_set->mmio_base;
+ void __iomem *mmio_base = ap->host->mmio_base;
void __iomem *chan = ADMA_REGS(mmio_base, ap->port_no);
/* mask/clear ATA interrupts */
@@ -264,7 +265,7 @@ static void adma_reinit_engine(struct ata_port *ap)
static inline void adma_enter_reg_mode(struct ata_port *ap)
{
- void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
writew(aPIOMD4, chan + ADMA_CONTROL);
readb(chan + ADMA_STATUS); /* flush */
@@ -411,7 +412,7 @@ static void adma_qc_prep(struct ata_queued_cmd *qc)
static inline void adma_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void __iomem *chan = ADMA_REGS(ap->host_set->mmio_base, ap->port_no);
+ void __iomem *chan = ADMA_REGS(ap->host->mmio_base, ap->port_no);
VPRINTK("ENTER, ap %p\n", ap);
@@ -441,13 +442,13 @@ static unsigned int adma_qc_issue(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
-static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
+static inline unsigned int adma_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0, port_no;
- u8 __iomem *mmio_base = host_set->mmio_base;
+ u8 __iomem *mmio_base = host->mmio_base;
- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
- struct ata_port *ap = host_set->ports[port_no];
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
+ struct ata_port *ap = host->ports[port_no];
struct adma_port_priv *pp;
struct ata_queued_cmd *qc;
void __iomem *chan = ADMA_REGS(mmio_base, port_no);
@@ -475,13 +476,13 @@ static inline unsigned int adma_intr_pkt(struct ata_host_set *host_set)
return handled;
}
-static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
+static inline unsigned int adma_intr_mmio(struct ata_host *host)
{
unsigned int handled = 0, port_no;
- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
struct ata_port *ap;
- ap = host_set->ports[port_no];
+ ap = host->ports[port_no];
if (ap && (!(ap->flags & ATA_FLAG_DISABLED))) {
struct ata_queued_cmd *qc;
struct adma_port_priv *pp = ap->private_data;
@@ -496,7 +497,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
continue;
DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
ap->id, qc->tf.protocol, status);
-
+
/* complete taskfile transaction */
pp->state = adma_state_idle;
qc->err_mask |= ac_err_mask(status);
@@ -510,14 +511,14 @@ static inline unsigned int adma_intr_mmio(struct ata_host_set *host_set)
static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
unsigned int handled = 0;
VPRINTK("ENTER\n");
- spin_lock(&host_set->lock);
- handled = adma_intr_pkt(host_set) | adma_intr_mmio(host_set);
- spin_unlock(&host_set->lock);
+ spin_lock(&host->lock);
+ handled = adma_intr_pkt(host) | adma_intr_mmio(host);
+ spin_unlock(&host->lock);
VPRINTK("EXIT\n");
@@ -543,7 +544,7 @@ static void adma_ata_setup_port(struct ata_ioports *port, unsigned long base)
static int adma_port_start(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct adma_port_priv *pp;
int rc;
@@ -581,10 +582,10 @@ err_out:
static void adma_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct adma_port_priv *pp = ap->private_data;
- adma_reset_engine(ADMA_REGS(ap->host_set->mmio_base, ap->port_no));
+ adma_reset_engine(ADMA_REGS(ap->host->mmio_base, ap->port_no));
if (pp != NULL) {
ap->private_data = NULL;
if (pp->pkt != NULL)
@@ -595,14 +596,14 @@ static void adma_port_stop(struct ata_port *ap)
ata_port_stop(ap);
}
-static void adma_host_stop(struct ata_host_set *host_set)
+static void adma_host_stop(struct ata_host *host)
{
unsigned int port_no;
for (port_no = 0; port_no < ADMA_PORTS; ++port_no)
- adma_reset_engine(ADMA_REGS(host_set->mmio_base, port_no));
+ adma_reset_engine(ADMA_REGS(host->mmio_base, port_no));
- ata_pci_host_stop(host_set);
+ ata_pci_host_stop(host);
}
static void adma_host_init(unsigned int chip_id,
@@ -683,14 +684,14 @@ static int adma_ata_init_one(struct pci_dev *pdev,
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = adma_port_info[board_idx].sht;
- probe_ent->host_flags = adma_port_info[board_idx].host_flags;
+ probe_ent->port_flags = adma_port_info[board_idx].flags;
probe_ent->pio_mask = adma_port_info[board_idx].pio_mask;
probe_ent->mwdma_mask = adma_port_info[board_idx].mwdma_mask;
probe_ent->udma_mask = adma_port_info[board_idx].udma_mask;
probe_ent->port_ops = adma_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
probe_ent->n_ports = ADMA_PORTS;
@@ -721,7 +722,7 @@ err_out:
static int __init adma_ata_init(void)
{
- return pci_module_init(&adma_ata_pci_driver);
+ return pci_register_driver(&adma_ata_pci_driver);
}
static void __exit adma_ata_exit(void)
diff --git a/drivers/scsi/sata_mv.c b/drivers/ata/sata_mv.c
index 4a71578df3c..c01496df4a9 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -342,7 +342,7 @@ static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static void mv_phy_reset(struct ata_port *ap);
static void __mv_phy_reset(struct ata_port *ap, int can_sleep);
-static void mv_host_stop(struct ata_host_set *host_set);
+static void mv_host_stop(struct ata_host *host);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
@@ -463,6 +463,7 @@ static const struct ata_port_operations mv_iie_ops = {
.qc_prep = mv_qc_prep_iie,
.qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = mv_eng_timeout,
@@ -480,35 +481,35 @@ static const struct ata_port_operations mv_iie_ops = {
static const struct ata_port_info mv_port_info[] = {
{ /* chip_504x */
.sht = &mv_sht,
- .host_flags = MV_COMMON_FLAGS,
+ .flags = MV_COMMON_FLAGS,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_508x */
.sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+ .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_5080 */
.sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+ .flags = (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv5_ops,
},
{ /* chip_604x */
.sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv6_ops,
},
{ /* chip_608x */
.sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
@@ -516,14 +517,14 @@ static const struct ata_port_info mv_port_info[] = {
},
{ /* chip_6042 */
.sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &mv_iie_ops,
},
{ /* chip_7042 */
.sht = &mv_sht,
- .host_flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
+ .flags = (MV_COMMON_FLAGS | MV_6XXX_FLAGS |
MV_FLAG_DUAL_HC),
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
@@ -618,12 +619,12 @@ static inline void __iomem *mv_port_base(void __iomem *base, unsigned int port)
static inline void __iomem *mv_ap_base(struct ata_port *ap)
{
- return mv_port_base(ap->host_set->mmio_base, ap->port_no);
+ return mv_port_base(ap->host->mmio_base, ap->port_no);
}
-static inline int mv_get_hc_count(unsigned long host_flags)
+static inline int mv_get_hc_count(unsigned long port_flags)
{
- return ((host_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
+ return ((port_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
}
static void mv_irq_clear(struct ata_port *ap)
@@ -809,7 +810,7 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
/**
* mv_host_stop - Host specific cleanup/stop routine.
- * @host_set: host data structure
+ * @host: host data structure
*
* Disable ints, cleanup host memory, call general purpose
* host_stop.
@@ -817,10 +818,10 @@ static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
* LOCKING:
* Inherited from caller.
*/
-static void mv_host_stop(struct ata_host_set *host_set)
+static void mv_host_stop(struct ata_host *host)
{
- struct mv_host_priv *hpriv = host_set->private_data;
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+ struct mv_host_priv *hpriv = host->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
pci_disable_msi(pdev);
@@ -828,7 +829,7 @@ static void mv_host_stop(struct ata_host_set *host_set)
pci_intx(pdev, 0);
}
kfree(hpriv);
- ata_host_stop(host_set);
+ ata_host_stop(host);
}
static inline void mv_priv_free(struct mv_port_priv *pp, struct device *dev)
@@ -875,8 +876,8 @@ static void mv_edma_cfg(struct mv_host_priv *hpriv, void __iomem *port_mmio)
*/
static int mv_port_start(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
- struct mv_host_priv *hpriv = ap->host_set->private_data;
+ struct device *dev = ap->host->dev;
+ struct mv_host_priv *hpriv = ap->host->private_data;
struct mv_port_priv *pp;
void __iomem *port_mmio = mv_ap_base(ap);
void *mem;
@@ -965,17 +966,17 @@ err_out:
* Stop DMA, cleanup port memory.
*
* LOCKING:
- * This routine uses the host_set lock to protect the DMA stop.
+ * This routine uses the host lock to protect the DMA stop.
*/
static void mv_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct mv_port_priv *pp = ap->private_data;
unsigned long flags;
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(&ap->host->lock, flags);
mv_stop_dma(ap);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
ap->private_data = NULL;
ata_pad_free(ap, dev);
@@ -1330,7 +1331,7 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed)
/**
* mv_host_intr - Handle all interrupts on the given host controller
- * @host_set: host specific structure
+ * @host: host specific structure
* @relevant: port error bits relevant to this host controller
* @hc: which host controller we're to look at
*
@@ -1344,10 +1345,9 @@ static void mv_err_intr(struct ata_port *ap, int reset_allowed)
* LOCKING:
* Inherited from caller.
*/
-static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
- unsigned int hc)
+static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
{
- void __iomem *mmio = host_set->mmio_base;
+ void __iomem *mmio = host->mmio_base;
void __iomem *hc_mmio = mv_hc_base(mmio, hc);
struct ata_queued_cmd *qc;
u32 hc_irq_cause;
@@ -1371,7 +1371,7 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
u8 ata_status = 0;
- struct ata_port *ap = host_set->ports[port];
+ struct ata_port *ap = host->ports[port];
struct mv_port_priv *pp = ap->private_data;
hard_port = mv_hardport_from_port(port); /* range 0..3 */
@@ -1444,15 +1444,15 @@ static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
* reported here.
*
* LOCKING:
- * This routine holds the host_set lock while processing pending
+ * This routine holds the host lock while processing pending
* interrupts.
*/
static irqreturn_t mv_interrupt(int irq, void *dev_instance,
struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
unsigned int hc, handled = 0, n_hcs;
- void __iomem *mmio = host_set->mmio_base;
+ void __iomem *mmio = host->mmio_base;
struct mv_host_priv *hpriv;
u32 irq_stat;
@@ -1465,18 +1465,18 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance,
return IRQ_NONE;
}
- n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
- spin_lock(&host_set->lock);
+ n_hcs = mv_get_hc_count(host->ports[0]->flags);
+ spin_lock(&host->lock);
for (hc = 0; hc < n_hcs; hc++) {
u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
if (relevant) {
- mv_host_intr(host_set, relevant, hc);
+ mv_host_intr(host, relevant, hc);
handled++;
}
}
- hpriv = host_set->private_data;
+ hpriv = host->private_data;
if (IS_60XX(hpriv)) {
/* deal with the interrupt coalescing bits */
if (irq_stat & (TRAN_LO_DONE | TRAN_HI_DONE | PORTS_0_7_COAL_DONE)) {
@@ -1491,12 +1491,12 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance,
readl(mmio + PCI_IRQ_CAUSE_OFS));
DPRINTK("All regs @ PCI error\n");
- mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev));
+ mv_dump_all_regs(mmio, -1, to_pci_dev(host->dev));
writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
handled++;
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
}
@@ -1528,7 +1528,7 @@ static unsigned int mv5_scr_offset(unsigned int sc_reg_in)
static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
{
- void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
+ void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU)
@@ -1539,7 +1539,7 @@ static u32 mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in)
static void mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val)
{
- void __iomem *mmio = mv5_phy_base(ap->host_set->mmio_base, ap->port_no);
+ void __iomem *mmio = mv5_phy_base(ap->host->mmio_base, ap->port_no);
unsigned int ofs = mv5_scr_offset(sc_reg_in);
if (ofs != 0xffffffffU)
@@ -1904,8 +1904,8 @@ static void mv_channel_reset(struct mv_host_priv *hpriv, void __iomem *mmio,
static void mv_stop_and_reset(struct ata_port *ap)
{
- struct mv_host_priv *hpriv = ap->host_set->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
mv_stop_dma(ap);
@@ -1936,7 +1936,7 @@ static inline void __msleep(unsigned int msec, int can_sleep)
static void __mv_phy_reset(struct ata_port *ap, int can_sleep)
{
struct mv_port_priv *pp = ap->private_data;
- struct mv_host_priv *hpriv = ap->host_set->private_data;
+ struct mv_host_priv *hpriv = ap->host->private_data;
void __iomem *port_mmio = mv_ap_base(ap);
struct ata_taskfile tf;
struct ata_device *dev = &ap->device[0];
@@ -1961,8 +1961,7 @@ comreset_retry:
timeout = jiffies + msecs_to_jiffies(200);
do {
sata_scr_read(ap, SCR_STATUS, &sstatus);
- sstatus &= 0x3;
- if ((sstatus == 3) || (sstatus == 0))
+ if (((sstatus & 0x3) == 3) || ((sstatus & 0x3) == 0))
break;
__msleep(1, can_sleep);
@@ -2035,7 +2034,7 @@ static void mv_phy_reset(struct ata_port *ap)
* chip/bus, fail the command, and move on.
*
* LOCKING:
- * This routine holds the host_set lock while failing the command.
+ * This routine holds the host lock while failing the command.
*/
static void mv_eng_timeout(struct ata_port *ap)
{
@@ -2044,18 +2043,17 @@ static void mv_eng_timeout(struct ata_port *ap)
ata_port_printk(ap, KERN_ERR, "Entering mv_eng_timeout\n");
DPRINTK("All regs @ start of eng_timeout\n");
- mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no,
- to_pci_dev(ap->host_set->dev));
+ mv_dump_all_regs(ap->host->mmio_base, ap->port_no,
+ to_pci_dev(ap->host->dev));
qc = ata_qc_from_tag(ap, ap->active_tag);
printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
- ap->host_set->mmio_base, ap, qc, qc->scsicmd,
- &qc->scsicmd->cmnd);
+ ap->host->mmio_base, ap, qc, qc->scsicmd, &qc->scsicmd->cmnd);
- spin_lock_irqsave(&ap->host_set->lock, flags);
+ spin_lock_irqsave(&ap->host->lock, flags);
mv_err_intr(ap, 0);
mv_stop_and_reset(ap);
- spin_unlock_irqrestore(&ap->host_set->lock, flags);
+ spin_unlock_irqrestore(&ap->host->lock, flags);
WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE));
if (qc->flags & ATA_QCFLAG_ACTIVE) {
@@ -2236,7 +2234,7 @@ static int mv_init_host(struct pci_dev *pdev, struct ata_probe_ent *probe_ent,
if (rc)
goto done;
- n_hc = mv_get_hc_count(probe_ent->host_flags);
+ n_hc = mv_get_hc_count(probe_ent->port_flags);
probe_ent->n_ports = MV_PORTS_PER_HC * n_hc;
for (port = 0; port < probe_ent->n_ports; port++)
@@ -2389,13 +2387,13 @@ static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
memset(hpriv, 0, sizeof(*hpriv));
probe_ent->sht = mv_port_info[board_idx].sht;
- probe_ent->host_flags = mv_port_info[board_idx].host_flags;
+ probe_ent->port_flags = mv_port_info[board_idx].flags;
probe_ent->pio_mask = mv_port_info[board_idx].pio_mask;
probe_ent->udma_mask = mv_port_info[board_idx].udma_mask;
probe_ent->port_ops = mv_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
probe_ent->private_data = hpriv;
@@ -2447,7 +2445,7 @@ err_out:
static int __init mv_init(void)
{
- return pci_module_init(&mv_pci_driver);
+ return pci_register_driver(&mv_pci_driver);
}
static void __exit mv_exit(void)
diff --git a/drivers/scsi/sata_nv.c b/drivers/ata/sata_nv.c
index d18e7e0932e..8cd730fe5dd 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -31,7 +31,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -44,7 +43,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_nv"
-#define DRV_VERSION "0.9"
+#define DRV_VERSION "2.0"
enum {
NV_PORTS = 2,
@@ -82,7 +81,7 @@ enum {
};
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static void nv_ck804_host_stop(struct ata_host_set *host_set);
+static void nv_ck804_host_stop(struct ata_host *host);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
struct pt_regs *regs);
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
@@ -258,7 +257,7 @@ static struct ata_port_info nv_port_info[] = {
/* generic */
{
.sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -267,7 +266,7 @@ static struct ata_port_info nv_port_info[] = {
/* nforce2/3 */
{
.sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -276,7 +275,7 @@ static struct ata_port_info nv_port_info[] = {
/* ck804 */
{
.sht = &nv_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = NV_PIO_MASK,
.mwdma_mask = NV_MWDMA_MASK,
.udma_mask = NV_UDMA_MASK,
@@ -293,17 +292,17 @@ MODULE_VERSION(DRV_VERSION);
static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
unsigned int i;
unsigned int handled = 0;
unsigned long flags;
- spin_lock_irqsave(&host_set->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
- for (i = 0; i < host_set->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap;
- ap = host_set->ports[i];
+ ap = host->ports[i];
if (ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
@@ -319,7 +318,7 @@ static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
}
- spin_unlock_irqrestore(&host_set->lock, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
return IRQ_RETVAL(handled);
}
@@ -355,12 +354,12 @@ static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
return 1;
}
-static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
+static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
{
int i, handled = 0;
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
if (ap && !(ap->flags & ATA_FLAG_DISABLED))
handled += nv_host_intr(ap, irq_stat);
@@ -374,14 +373,14 @@ static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
u8 irq_stat;
irqreturn_t ret;
- spin_lock(&host_set->lock);
- irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
- ret = nv_do_interrupt(host_set, irq_stat);
- spin_unlock(&host_set->lock);
+ spin_lock(&host->lock);
+ irq_stat = inb(host->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+ ret = nv_do_interrupt(host, irq_stat);
+ spin_unlock(&host->lock);
return ret;
}
@@ -389,14 +388,14 @@ static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
u8 irq_stat;
irqreturn_t ret;
- spin_lock(&host_set->lock);
- irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
- ret = nv_do_interrupt(host_set, irq_stat);
- spin_unlock(&host_set->lock);
+ spin_lock(&host->lock);
+ irq_stat = readb(host->mmio_base + NV_INT_STATUS_CK804);
+ ret = nv_do_interrupt(host, irq_stat);
+ spin_unlock(&host->lock);
return ret;
}
@@ -419,7 +418,7 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
static void nv_nf2_freeze(struct ata_port *ap)
{
- unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
+ unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -430,7 +429,7 @@ static void nv_nf2_freeze(struct ata_port *ap)
static void nv_nf2_thaw(struct ata_port *ap)
{
- unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr;
+ unsigned long scr_addr = ap->host->ports[0]->ioaddr.scr_addr;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -443,7 +442,7 @@ static void nv_nf2_thaw(struct ata_port *ap)
static void nv_ck804_freeze(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host_set->mmio_base;
+ void __iomem *mmio_base = ap->host->mmio_base;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -454,7 +453,7 @@ static void nv_ck804_freeze(struct ata_port *ap)
static void nv_ck804_thaw(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host_set->mmio_base;
+ void __iomem *mmio_base = ap->host->mmio_base;
int shift = ap->port_no * NV_INT_PORT_SHIFT;
u8 mask;
@@ -485,7 +484,7 @@ static void nv_error_handler(struct ata_port *ap)
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
- struct ata_port_info *ppi;
+ struct ata_port_info *ppi[2];
struct ata_probe_ent *probe_ent;
int pci_dev_busy = 0;
int rc;
@@ -521,8 +520,8 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = -ENOMEM;
- ppi = &nv_port_info[ent->driver_data];
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ ppi[0] = ppi[1] = &nv_port_info[ent->driver_data];
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
goto err_out_regions;
@@ -569,9 +568,9 @@ err_out:
return rc;
}
-static void nv_ck804_host_stop(struct ata_host_set *host_set)
+static void nv_ck804_host_stop(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(host->dev);
u8 regval;
/* disable SATA space for CK804 */
@@ -579,12 +578,12 @@ static void nv_ck804_host_stop(struct ata_host_set *host_set)
regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
- ata_pci_host_stop(host_set);
+ ata_pci_host_stop(host);
}
static int __init nv_init(void)
{
- return pci_module_init(&nv_pci_driver);
+ return pci_register_driver(&nv_pci_driver);
}
static void __exit nv_exit(void)
diff --git a/drivers/scsi/sata_promise.c b/drivers/ata/sata_promise.c
index b2b6ed5216e..d627812ea73 100644
--- a/drivers/scsi/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -104,7 +104,7 @@ static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf)
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_irq_clear(struct ata_port *ap);
static unsigned int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
-static void pdc_host_stop(struct ata_host_set *host_set);
+static void pdc_host_stop(struct ata_host *host);
static struct scsi_host_template pdc_ata_sht = {
@@ -175,7 +175,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_2037x */
{
.sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -185,7 +185,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_20319 */
{
.sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -195,7 +195,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_20619 */
{
.sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SLAVE_POSS,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -205,7 +205,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_20771 */
{
.sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -215,7 +215,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_2057x */
{
.sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -225,7 +225,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_40518 */
{
.sht = &pdc_ata_sht,
- .host_flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
+ .flags = PDC_COMMON_FLAGS | ATA_FLAG_SATA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
@@ -269,8 +269,15 @@ static const struct pci_device_id pdc_ata_pci_tbl[] = {
{ PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20619 },
+/* TODO: remove all associated board_20771 code, as it completely
+ * duplicates board_2037x code, unless reason for separation can be
+ * divined.
+ */
+#if 0
{ PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_20771 },
+#endif
+
{ } /* terminate list */
};
@@ -285,7 +292,7 @@ static struct pci_driver pdc_ata_pci_driver = {
static int pdc_port_start(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct pdc_port_priv *pp;
int rc;
@@ -319,7 +326,7 @@ err_out:
static void pdc_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct pdc_port_priv *pp = ap->private_data;
ap->private_data = NULL;
@@ -329,11 +336,11 @@ static void pdc_port_stop(struct ata_port *ap)
}
-static void pdc_host_stop(struct ata_host_set *host_set)
+static void pdc_host_stop(struct ata_host *host)
{
- struct pdc_host_priv *hp = host_set->private_data;
+ struct pdc_host_priv *hp = host->private_data;
- ata_pci_host_stop(host_set);
+ ata_pci_host_stop(host);
kfree(hp);
}
@@ -436,14 +443,14 @@ static void pdc_qc_prep(struct ata_queued_cmd *qc)
static void pdc_eng_timeout(struct ata_port *ap)
{
- struct ata_host_set *host_set = ap->host_set;
+ struct ata_host *host = ap->host;
u8 drv_stat;
struct ata_queued_cmd *qc;
unsigned long flags;
DPRINTK("ENTER\n");
- spin_lock_irqsave(&host_set->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -466,7 +473,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
break;
}
- spin_unlock_irqrestore(&host_set->lock, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
ata_eh_qc_complete(qc);
DPRINTK("EXIT\n");
}
@@ -502,15 +509,15 @@ static inline unsigned int pdc_host_intr( struct ata_port *ap,
static void pdc_irq_clear(struct ata_port *ap)
{
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
+ struct ata_host *host = ap->host;
+ void __iomem *mmio = host->mmio_base;
readl(mmio + PDC_INT_SEQMASK);
}
static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
struct ata_port *ap;
u32 mask = 0;
unsigned int i, tmp;
@@ -519,12 +526,12 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
VPRINTK("ENTER\n");
- if (!host_set || !host_set->mmio_base) {
+ if (!host || !host->mmio_base) {
VPRINTK("QUICK EXIT\n");
return IRQ_NONE;
}
- mmio_base = host_set->mmio_base;
+ mmio_base = host->mmio_base;
/* reading should also clear interrupts */
mask = readl(mmio_base + PDC_INT_SEQMASK);
@@ -534,7 +541,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
return IRQ_NONE;
}
- spin_lock(&host_set->lock);
+ spin_lock(&host->lock);
mask &= 0xffff; /* only 16 tags possible */
if (!mask) {
@@ -544,9 +551,9 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
writel(mask, mmio_base + PDC_INT_SEQMASK);
- for (i = 0; i < host_set->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
VPRINTK("port %u\n", i);
- ap = host_set->ports[i];
+ ap = host->ports[i];
tmp = mask & (1 << (i + 1));
if (tmp && ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
@@ -561,7 +568,7 @@ static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *r
VPRINTK("EXIT\n");
done_irq:
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
}
@@ -574,8 +581,8 @@ static inline void pdc_packet_start(struct ata_queued_cmd *qc)
VPRINTK("ENTER, ap %p\n", ap);
- writel(0x00000001, ap->host_set->mmio_base + (seq * 4));
- readl(ap->host_set->mmio_base + (seq * 4)); /* flush */
+ writel(0x00000001, ap->host->mmio_base + (seq * 4));
+ readl(ap->host->mmio_base + (seq * 4)); /* flush */
pp->pkt[2] = seq;
wmb(); /* flush PRD, pkt writes */
@@ -736,14 +743,14 @@ static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
probe_ent->private_data = hp;
probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
+ probe_ent->port_flags = pdc_port_info[board_idx].flags;
probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
@@ -817,7 +824,7 @@ err_out:
static int __init pdc_ata_init(void)
{
- return pci_module_init(&pdc_ata_pci_driver);
+ return pci_register_driver(&pdc_ata_pci_driver);
}
diff --git a/drivers/scsi/sata_promise.h b/drivers/ata/sata_promise.h
index 6ee5e190262..6ee5e190262 100644
--- a/drivers/scsi/sata_promise.h
+++ b/drivers/ata/sata_promise.h
diff --git a/drivers/scsi/sata_qstor.c b/drivers/ata/sata_qstor.c
index 98ddc25655f..fa29dfe2a7b 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -116,7 +116,7 @@ static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
static int qs_port_start(struct ata_port *ap);
-static void qs_host_stop(struct ata_host_set *host_set);
+static void qs_host_stop(struct ata_host *host);
static void qs_port_stop(struct ata_port *ap);
static void qs_phy_reset(struct ata_port *ap);
static void qs_qc_prep(struct ata_queued_cmd *qc);
@@ -174,7 +174,7 @@ static const struct ata_port_info qs_port_info[] = {
/* board_2068_idx */
{
.sht = &qs_ata_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SATA_RESET |
//FIXME ATA_FLAG_SRST |
ATA_FLAG_MMIO | ATA_FLAG_PIO_POLLING,
@@ -220,7 +220,7 @@ static void qs_irq_clear(struct ata_port *ap)
static inline void qs_enter_reg_mode(struct ata_port *ap)
{
- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
readb(chan + QS_CCT_CTR0); /* flush */
@@ -228,7 +228,7 @@ static inline void qs_enter_reg_mode(struct ata_port *ap)
static inline void qs_reset_channel_logic(struct ata_port *ap)
{
- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
readb(chan + QS_CCT_CTR0); /* flush */
@@ -342,7 +342,7 @@ static void qs_qc_prep(struct ata_queued_cmd *qc)
static inline void qs_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+ u8 __iomem *chan = ap->host->mmio_base + (ap->port_no * 0x4000);
VPRINTK("ENTER, ap %p\n", ap);
@@ -375,11 +375,11 @@ static unsigned int qs_qc_issue(struct ata_queued_cmd *qc)
return ata_qc_issue_prot(qc);
}
-static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
+static inline unsigned int qs_intr_pkt(struct ata_host *host)
{
unsigned int handled = 0;
u8 sFFE;
- u8 __iomem *mmio_base = host_set->mmio_base;
+ u8 __iomem *mmio_base = host->mmio_base;
do {
u32 sff0 = readl(mmio_base + QS_HST_SFF);
@@ -391,7 +391,7 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
u8 sDST = sff0 >> 16; /* dev status */
u8 sHST = sff1 & 0x3f; /* host status */
unsigned int port_no = (sff1 >> 8) & 0x03;
- struct ata_port *ap = host_set->ports[port_no];
+ struct ata_port *ap = host->ports[port_no];
DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
sff1, sff0, port_no, sHST, sDST);
@@ -421,13 +421,13 @@ static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
return handled;
}
-static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
+static inline unsigned int qs_intr_mmio(struct ata_host *host)
{
unsigned int handled = 0, port_no;
- for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
+ for (port_no = 0; port_no < host->n_ports; ++port_no) {
struct ata_port *ap;
- ap = host_set->ports[port_no];
+ ap = host->ports[port_no];
if (ap &&
!(ap->flags & ATA_FLAG_DISABLED)) {
struct ata_queued_cmd *qc;
@@ -457,14 +457,14 @@ static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
unsigned int handled = 0;
VPRINTK("ENTER\n");
- spin_lock(&host_set->lock);
- handled = qs_intr_pkt(host_set) | qs_intr_mmio(host_set);
- spin_unlock(&host_set->lock);
+ spin_lock(&host->lock);
+ handled = qs_intr_pkt(host) | qs_intr_mmio(host);
+ spin_unlock(&host->lock);
VPRINTK("EXIT\n");
@@ -491,9 +491,9 @@ static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
static int qs_port_start(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct qs_port_priv *pp;
- void __iomem *mmio_base = ap->host_set->mmio_base;
+ void __iomem *mmio_base = ap->host->mmio_base;
void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
u64 addr;
int rc;
@@ -530,7 +530,7 @@ err_out:
static void qs_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct qs_port_priv *pp = ap->private_data;
if (pp != NULL) {
@@ -543,10 +543,10 @@ static void qs_port_stop(struct ata_port *ap)
ata_port_stop(ap);
}
-static void qs_host_stop(struct ata_host_set *host_set)
+static void qs_host_stop(struct ata_host *host)
{
- void __iomem *mmio_base = host_set->mmio_base;
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+ void __iomem *mmio_base = host->mmio_base;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
@@ -673,14 +673,14 @@ static int qs_ata_init_one(struct pci_dev *pdev,
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = qs_port_info[board_idx].sht;
- probe_ent->host_flags = qs_port_info[board_idx].host_flags;
+ probe_ent->port_flags = qs_port_info[board_idx].flags;
probe_ent->pio_mask = qs_port_info[board_idx].pio_mask;
probe_ent->mwdma_mask = qs_port_info[board_idx].mwdma_mask;
probe_ent->udma_mask = qs_port_info[board_idx].udma_mask;
probe_ent->port_ops = qs_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
probe_ent->n_ports = QS_PORTS;
@@ -712,7 +712,7 @@ err_out:
static int __init qs_ata_init(void)
{
- return pci_module_init(&qs_ata_pci_driver);
+ return pci_register_driver(&qs_ata_pci_driver);
}
static void __exit qs_ata_exit(void)
diff --git a/drivers/scsi/sata_sil.c b/drivers/ata/sata_sil.c
index bc9f918a7f2..c63dbabc0cd 100644
--- a/drivers/scsi/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -46,24 +46,26 @@
#include <linux/libata.h>
#define DRV_NAME "sata_sil"
-#define DRV_VERSION "1.0"
+#define DRV_VERSION "2.0"
enum {
/*
* host flags
*/
+ SIL_FLAG_NO_SATA_IRQ = (1 << 28),
SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
SIL_FLAG_MOD15WRITE = (1 << 30),
- SIL_DFL_HOST_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO | ATA_FLAG_HRST_TO_RESUME,
/*
* Controller IDs
*/
sil_3112 = 0,
- sil_3512 = 1,
- sil_3114 = 2,
+ sil_3112_no_sata_irq = 1,
+ sil_3512 = 2,
+ sil_3114 = 3,
/*
* Register offsets
@@ -107,6 +109,9 @@ enum {
};
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
+static int sil_pci_device_resume(struct pci_dev *pdev);
+#endif
static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -123,8 +128,8 @@ static const struct pci_device_id sil_pci_tbl[] = {
{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
{ 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+ { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+ { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
{ } /* terminate list */
};
@@ -138,12 +143,8 @@ static const struct sil_drivelist {
{ "ST330013AS", SIL_QUIRK_MOD15WRITE },
{ "ST340017AS", SIL_QUIRK_MOD15WRITE },
{ "ST360015AS", SIL_QUIRK_MOD15WRITE },
- { "ST380013AS", SIL_QUIRK_MOD15WRITE },
{ "ST380023AS", SIL_QUIRK_MOD15WRITE },
{ "ST3120023AS", SIL_QUIRK_MOD15WRITE },
- { "ST3160023AS", SIL_QUIRK_MOD15WRITE },
- { "ST3120026AS", SIL_QUIRK_MOD15WRITE },
- { "ST3200822AS", SIL_QUIRK_MOD15WRITE },
{ "ST340014ASL", SIL_QUIRK_MOD15WRITE },
{ "ST360014ASL", SIL_QUIRK_MOD15WRITE },
{ "ST380011ASL", SIL_QUIRK_MOD15WRITE },
@@ -158,6 +159,10 @@ static struct pci_driver sil_pci_driver = {
.id_table = sil_pci_tbl,
.probe = sil_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = sil_pci_device_resume,
+#endif
};
static struct scsi_host_template sil_sht = {
@@ -176,6 +181,8 @@ static struct scsi_host_template sil_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil_ops = {
@@ -211,7 +218,17 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3112 */
{
.sht = &sil_sht,
- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_MOD15WRITE,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .mwdma_mask = 0x07, /* mwdma0-2 */
+ .udma_mask = 0x3f, /* udma0-5 */
+ .port_ops = &sil_ops,
+ },
+ /* sil_3112_no_sata_irq */
+ {
+ .sht = &sil_sht,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
+ SIL_FLAG_NO_SATA_IRQ,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -220,7 +237,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3512 */
{
.sht = &sil_sht,
- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -229,7 +246,7 @@ static const struct ata_port_info sil_port_info[] = {
/* sil_3114 */
{
.sht = &sil_sht,
- .host_flags = SIL_DFL_HOST_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
+ .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -278,10 +295,9 @@ static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
static void sil_post_set_mode (struct ata_port *ap)
{
- struct ata_host_set *host_set = ap->host_set;
+ struct ata_host *host = ap->host;
struct ata_device *dev;
- void __iomem *addr =
- host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+ void __iomem *addr = host->mmio_base + sil_port[ap->port_no].xfer_mode;
u32 tmp, dev_mode[2];
unsigned int i;
@@ -358,7 +374,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
* during hardreset makes controllers with broken SIEN
* repeat probing needlessly.
*/
- if (!(ap->flags & ATA_FLAG_FROZEN)) {
+ if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
ata_ehi_hotplugged(&ap->eh_info);
ap->eh_info.serror |= serror;
}
@@ -423,20 +439,24 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
static irqreturn_t sil_interrupt(int irq, void *dev_instance,
struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
- void __iomem *mmio_base = host_set->mmio_base;
+ struct ata_host *host = dev_instance;
+ void __iomem *mmio_base = host->mmio_base;
int handled = 0;
int i;
- spin_lock(&host_set->lock);
+ spin_lock(&host->lock);
- for (i = 0; i < host_set->n_ports; i++) {
- struct ata_port *ap = host_set->ports[i];
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
continue;
+ /* turn off SATA_IRQ if not supported */
+ if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
+ bmdma2 &= ~SIL_DMA_SATA_IRQ;
+
if (bmdma2 == 0xffffffff ||
!(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
continue;
@@ -445,14 +465,14 @@ static irqreturn_t sil_interrupt(int irq, void *dev_instance,
handled = 1;
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
}
static void sil_freeze(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host_set->mmio_base;
+ void __iomem *mmio_base = ap->host->mmio_base;
u32 tmp;
/* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
@@ -467,15 +487,16 @@ static void sil_freeze(struct ata_port *ap)
static void sil_thaw(struct ata_port *ap)
{
- void __iomem *mmio_base = ap->host_set->mmio_base;
+ void __iomem *mmio_base = ap->host->mmio_base;
u32 tmp;
/* clear IRQ */
ata_chk_status(ap);
ata_bmdma_irq_clear(ap);
- /* turn on SATA IRQ */
- writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
+ /* turn on SATA IRQ if supported */
+ if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
+ writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
/* turn on IRQ */
tmp = readl(mmio_base + SIL_SYSCFG);
@@ -544,6 +565,52 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
}
}
+static void sil_init_controller(struct pci_dev *pdev,
+ int n_ports, unsigned long port_flags,
+ void __iomem *mmio_base)
+{
+ u8 cls;
+ u32 tmp;
+ int i;
+
+ /* Initialize FIFO PCI bus arbitration */
+ cls = sil_get_device_cache_line(pdev);
+ if (cls) {
+ cls >>= 3;
+ cls++; /* cls = (line_size/8)+1 */
+ for (i = 0; i < n_ports; i++)
+ writew(cls << 8 | cls,
+ mmio_base + sil_port[i].fifo_cfg);
+ } else
+ dev_printk(KERN_WARNING, &pdev->dev,
+ "cache line size not set. Driver may not function\n");
+
+ /* Apply R_ERR on DMA activate FIS errata workaround */
+ if (port_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
+ int cnt;
+
+ for (i = 0, cnt = 0; i < n_ports; i++) {
+ tmp = readl(mmio_base + sil_port[i].sfis_cfg);
+ if ((tmp & 0x3) != 0x01)
+ continue;
+ if (!cnt)
+ dev_printk(KERN_INFO, &pdev->dev,
+ "Applying R_ERR on DMA activate "
+ "FIS errata fix\n");
+ writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
+ cnt++;
+ }
+ }
+
+ if (n_ports == 4) {
+ /* flip the magic "make 4 ports work" bit */
+ tmp = readl(mmio_base + sil_port[2].bmdma);
+ if ((tmp & SIL_INTR_STEERING) == 0)
+ writel(tmp | SIL_INTR_STEERING,
+ mmio_base + sil_port[2].bmdma);
+ }
+}
+
static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -553,8 +620,6 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
int rc;
unsigned int i;
int pci_dev_busy = 0;
- u32 tmp;
- u8 cls;
if (!printed_version++)
dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
@@ -591,8 +656,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
+ probe_ent->irq_flags = IRQF_SHARED;
+ probe_ent->port_flags = sil_port_info[ent->driver_data].flags;
mmio_base = pci_iomap(pdev, 5, 0);
if (mmio_base == NULL) {
@@ -613,42 +678,8 @@ static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
ata_std_ports(&probe_ent->port[i]);
}
- /* Initialize FIFO PCI bus arbitration */
- cls = sil_get_device_cache_line(pdev);
- if (cls) {
- cls >>= 3;
- cls++; /* cls = (line_size/8)+1 */
- for (i = 0; i < probe_ent->n_ports; i++)
- writew(cls << 8 | cls,
- mmio_base + sil_port[i].fifo_cfg);
- } else
- dev_printk(KERN_WARNING, &pdev->dev,
- "cache line size not set. Driver may not function\n");
-
- /* Apply R_ERR on DMA activate FIS errata workaround */
- if (probe_ent->host_flags & SIL_FLAG_RERR_ON_DMA_ACT) {
- int cnt;
-
- for (i = 0, cnt = 0; i < probe_ent->n_ports; i++) {
- tmp = readl(mmio_base + sil_port[i].sfis_cfg);
- if ((tmp & 0x3) != 0x01)
- continue;
- if (!cnt)
- dev_printk(KERN_INFO, &pdev->dev,
- "Applying R_ERR on DMA activate "
- "FIS errata fix\n");
- writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
- cnt++;
- }
- }
-
- if (ent->driver_data == sil_3114) {
- /* flip the magic "make 4 ports work" bit */
- tmp = readl(mmio_base + sil_port[2].bmdma);
- if ((tmp & SIL_INTR_STEERING) == 0)
- writel(tmp | SIL_INTR_STEERING,
- mmio_base + sil_port[2].bmdma);
- }
+ sil_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
+ mmio_base);
pci_set_master(pdev);
@@ -668,9 +699,23 @@ err_out:
return rc;
}
+#ifdef CONFIG_PM
+static int sil_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+
+ ata_pci_device_do_resume(pdev);
+ sil_init_controller(pdev, host->n_ports, host->ports[0]->flags,
+ host->mmio_base);
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
static int __init sil_init(void)
{
- return pci_module_init(&sil_pci_driver);
+ return pci_register_driver(&sil_pci_driver);
}
static void __exit sil_exit(void)
diff --git a/drivers/scsi/sata_sil24.c b/drivers/ata/sata_sil24.c
index c8b477c6724..39cb07baeba 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -31,7 +31,7 @@
#include <asm/io.h>
#define DRV_NAME "sata_sil24"
-#define DRV_VERSION "0.24"
+#define DRV_VERSION "0.3"
/*
* Port request block (PRB) 32 bytes
@@ -92,6 +92,7 @@ enum {
HOST_CTRL_STOP = (1 << 18), /* latched PCI STOP */
HOST_CTRL_DEVSEL = (1 << 19), /* latched PCI DEVSEL */
HOST_CTRL_REQ64 = (1 << 20), /* latched PCI REQ64 */
+ HOST_CTRL_GLOBAL_RST = (1 << 31), /* global reset */
/*
* Port registers
@@ -315,7 +316,7 @@ struct sil24_port_priv {
struct ata_taskfile tf; /* Cached taskfile registers */
};
-/* ap->host_set->private_data */
+/* ap->host->private_data */
struct sil24_host_priv {
void __iomem *host_base; /* global controller control (128 bytes @BAR0) */
void __iomem *port_base; /* port registers (4 * 8192 bytes @BAR2) */
@@ -336,8 +337,11 @@ static void sil24_error_handler(struct ata_port *ap);
static void sil24_post_internal_cmd(struct ata_queued_cmd *qc);
static int sil24_port_start(struct ata_port *ap);
static void sil24_port_stop(struct ata_port *ap);
-static void sil24_host_stop(struct ata_host_set *host_set);
+static void sil24_host_stop(struct ata_host *host);
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
+#ifdef CONFIG_PM
+static int sil24_pci_device_resume(struct pci_dev *pdev);
+#endif
static const struct pci_device_id sil24_pci_tbl[] = {
{ 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
@@ -353,6 +357,10 @@ static struct pci_driver sil24_pci_driver = {
.id_table = sil24_pci_tbl,
.probe = sil24_init_one,
.remove = ata_pci_remove_one, /* safe? */
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = sil24_pci_device_resume,
+#endif
};
static struct scsi_host_template sil24_sht = {
@@ -372,6 +380,8 @@ static struct scsi_host_template sil24_sht = {
.slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param,
+ .suspend = ata_scsi_device_suspend,
+ .resume = ata_scsi_device_resume,
};
static const struct ata_port_operations sil24_ops = {
@@ -405,7 +415,7 @@ static const struct ata_port_operations sil24_ops = {
};
/*
- * Use bits 30-31 of host_flags to encode available port numbers.
+ * Use bits 30-31 of port_flags to encode available port numbers.
* Current maxium is 4.
*/
#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
@@ -415,7 +425,7 @@ static struct ata_port_info sil24_port_info[] = {
/* sil_3124 */
{
.sht = &sil24_sht,
- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
+ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(4) |
SIL24_FLAG_PCIX_IRQ_WOC,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -425,7 +435,7 @@ static struct ata_port_info sil24_port_info[] = {
/* sil_3132 */
{
.sht = &sil24_sht,
- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
+ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(2),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -434,7 +444,7 @@ static struct ata_port_info sil24_port_info[] = {
/* sil_3131/sil_3531 */
{
.sht = &sil24_sht,
- .host_flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
+ .flags = SIL24_COMMON_FLAGS | SIL24_NPORTS2FLAG(1),
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
.udma_mask = 0x3f, /* udma0-5 */
@@ -607,7 +617,7 @@ static int sil24_hardreset(struct ata_port *ap, unsigned int *class)
/* SStatus oscillates between zero and valid status after
* DEV_RST, debounce it.
*/
- rc = sata_phy_debounce(ap, sata_deb_timing_before_fsrst);
+ rc = sata_phy_debounce(ap, sata_deb_timing_long);
if (rc) {
reason = "PHY debouncing failed";
goto err;
@@ -861,8 +871,8 @@ static inline void sil24_host_intr(struct ata_port *ap)
static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
- struct sil24_host_priv *hpriv = host_set->private_data;
+ struct ata_host *host = dev_instance;
+ struct sil24_host_priv *hpriv = host->private_data;
unsigned handled = 0;
u32 status;
int i;
@@ -878,20 +888,20 @@ static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *
if (!(status & IRQ_STAT_4PORTS))
goto out;
- spin_lock(&host_set->lock);
+ spin_lock(&host->lock);
- for (i = 0; i < host_set->n_ports; i++)
+ for (i = 0; i < host->n_ports; i++)
if (status & (1 << i)) {
- struct ata_port *ap = host_set->ports[i];
+ struct ata_port *ap = host->ports[i];
if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
- sil24_host_intr(host_set->ports[i]);
+ sil24_host_intr(host->ports[i]);
handled++;
} else
printk(KERN_ERR DRV_NAME
": interrupt from disabled port %d\n", i);
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
out:
return IRQ_RETVAL(handled);
}
@@ -931,7 +941,7 @@ static inline void sil24_cblk_free(struct sil24_port_priv *pp, struct device *de
static int sil24_port_start(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct sil24_port_priv *pp;
union sil24_cmd_block *cb;
size_t cb_size = sizeof(*cb) * SIL24_MAX_CMDS;
@@ -970,7 +980,7 @@ err_out:
static void sil24_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct sil24_port_priv *pp = ap->private_data;
sil24_cblk_free(pp, dev);
@@ -978,16 +988,74 @@ static void sil24_port_stop(struct ata_port *ap)
kfree(pp);
}
-static void sil24_host_stop(struct ata_host_set *host_set)
+static void sil24_host_stop(struct ata_host *host)
{
- struct sil24_host_priv *hpriv = host_set->private_data;
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
+ struct sil24_host_priv *hpriv = host->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
pci_iounmap(pdev, hpriv->host_base);
pci_iounmap(pdev, hpriv->port_base);
kfree(hpriv);
}
+static void sil24_init_controller(struct pci_dev *pdev, int n_ports,
+ unsigned long port_flags,
+ void __iomem *host_base,
+ void __iomem *port_base)
+{
+ u32 tmp;
+ int i;
+
+ /* GPIO off */
+ writel(0, host_base + HOST_FLASH_CMD);
+
+ /* clear global reset & mask interrupts during initialization */
+ writel(0, host_base + HOST_CTRL);
+
+ /* init ports */
+ for (i = 0; i < n_ports; i++) {
+ void __iomem *port = port_base + i * PORT_REGS_SIZE;
+
+ /* Initial PHY setting */
+ writel(0x20c, port + PORT_PHY_CFG);
+
+ /* Clear port RST */
+ tmp = readl(port + PORT_CTRL_STAT);
+ if (tmp & PORT_CS_PORT_RST) {
+ writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
+ tmp = ata_wait_register(port + PORT_CTRL_STAT,
+ PORT_CS_PORT_RST,
+ PORT_CS_PORT_RST, 10, 100);
+ if (tmp & PORT_CS_PORT_RST)
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to clear port RST\n");
+ }
+
+ /* Configure IRQ WoC */
+ if (port_flags & SIL24_FLAG_PCIX_IRQ_WOC)
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
+ else
+ writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
+
+ /* Zero error counters. */
+ writel(0x8000, port + PORT_DECODE_ERR_THRESH);
+ writel(0x8000, port + PORT_CRC_ERR_THRESH);
+ writel(0x8000, port + PORT_HSHK_ERR_THRESH);
+ writel(0x0000, port + PORT_DECODE_ERR_CNT);
+ writel(0x0000, port + PORT_CRC_ERR_CNT);
+ writel(0x0000, port + PORT_HSHK_ERR_CNT);
+
+ /* Always use 64bit activation */
+ writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
+
+ /* Clear port multiplier enable and resume bits */
+ writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
+ }
+
+ /* Turn on interrupts */
+ writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+}
+
static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version = 0;
@@ -1033,16 +1101,15 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = pinfo->sht;
- probe_ent->host_flags = pinfo->host_flags;
+ probe_ent->port_flags = pinfo->flags;
probe_ent->pio_mask = pinfo->pio_mask;
probe_ent->mwdma_mask = pinfo->mwdma_mask;
probe_ent->udma_mask = pinfo->udma_mask;
probe_ent->port_ops = pinfo->port_ops;
- probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->host_flags);
+ probe_ent->n_ports = SIL24_FLAG2NPORTS(pinfo->flags);
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
- probe_ent->mmio_base = port_base;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->private_data = hpriv;
hpriv->host_base = host_base;
@@ -1076,70 +1143,29 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
- /* GPIO off */
- writel(0, host_base + HOST_FLASH_CMD);
-
/* Apply workaround for completion IRQ loss on PCI-X errata */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
+ if (probe_ent->port_flags & SIL24_FLAG_PCIX_IRQ_WOC) {
tmp = readl(host_base + HOST_CTRL);
if (tmp & (HOST_CTRL_TRDY | HOST_CTRL_STOP | HOST_CTRL_DEVSEL))
dev_printk(KERN_INFO, &pdev->dev,
"Applying completion IRQ loss on PCI-X "
"errata fix\n");
else
- probe_ent->host_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
+ probe_ent->port_flags &= ~SIL24_FLAG_PCIX_IRQ_WOC;
}
- /* clear global reset & mask interrupts during initialization */
- writel(0, host_base + HOST_CTRL);
-
for (i = 0; i < probe_ent->n_ports; i++) {
- void __iomem *port = port_base + i * PORT_REGS_SIZE;
- unsigned long portu = (unsigned long)port;
+ unsigned long portu =
+ (unsigned long)port_base + i * PORT_REGS_SIZE;
probe_ent->port[i].cmd_addr = portu;
probe_ent->port[i].scr_addr = portu + PORT_SCONTROL;
ata_std_ports(&probe_ent->port[i]);
-
- /* Initial PHY setting */
- writel(0x20c, port + PORT_PHY_CFG);
-
- /* Clear port RST */
- tmp = readl(port + PORT_CTRL_STAT);
- if (tmp & PORT_CS_PORT_RST) {
- writel(PORT_CS_PORT_RST, port + PORT_CTRL_CLR);
- tmp = ata_wait_register(port + PORT_CTRL_STAT,
- PORT_CS_PORT_RST,
- PORT_CS_PORT_RST, 10, 100);
- if (tmp & PORT_CS_PORT_RST)
- dev_printk(KERN_ERR, &pdev->dev,
- "failed to clear port RST\n");
- }
-
- /* Configure IRQ WoC */
- if (probe_ent->host_flags & SIL24_FLAG_PCIX_IRQ_WOC)
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_STAT);
- else
- writel(PORT_CS_IRQ_WOC, port + PORT_CTRL_CLR);
-
- /* Zero error counters. */
- writel(0x8000, port + PORT_DECODE_ERR_THRESH);
- writel(0x8000, port + PORT_CRC_ERR_THRESH);
- writel(0x8000, port + PORT_HSHK_ERR_THRESH);
- writel(0x0000, port + PORT_DECODE_ERR_CNT);
- writel(0x0000, port + PORT_CRC_ERR_CNT);
- writel(0x0000, port + PORT_HSHK_ERR_CNT);
-
- /* Always use 64bit activation */
- writel(PORT_CS_32BIT_ACTV, port + PORT_CTRL_CLR);
-
- /* Clear port multiplier enable and resume bits */
- writel(PORT_CS_PM_EN | PORT_CS_RESUME, port + PORT_CTRL_CLR);
}
- /* Turn on interrupts */
- writel(IRQ_STAT_4PORTS, host_base + HOST_CTRL);
+ sil24_init_controller(pdev, probe_ent->n_ports, probe_ent->port_flags,
+ host_base, port_base);
pci_set_master(pdev);
@@ -1162,9 +1188,29 @@ static int sil24_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
+#ifdef CONFIG_PM
+static int sil24_pci_device_resume(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ struct sil24_host_priv *hpriv = host->private_data;
+
+ ata_pci_device_do_resume(pdev);
+
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND)
+ writel(HOST_CTRL_GLOBAL_RST, hpriv->host_base + HOST_CTRL);
+
+ sil24_init_controller(pdev, host->n_ports, host->ports[0]->flags,
+ hpriv->host_base, hpriv->port_base);
+
+ ata_host_resume(host);
+
+ return 0;
+}
+#endif
+
static int __init sil24_init(void)
{
- return pci_module_init(&sil24_pci_driver);
+ return pci_register_driver(&sil24_pci_driver);
}
static void __exit sil24_exit(void)
diff --git a/drivers/scsi/sata_sis.c b/drivers/ata/sata_sis.c
index 809d337ed64..18d49fff8dc 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -30,7 +30,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -129,7 +128,7 @@ static const struct ata_port_operations sis_ops = {
static struct ata_port_info sis_port_info = {
.sht = &sis_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x7,
.udma_mask = 0x7f,
@@ -159,7 +158,7 @@ static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg,
static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device);
u32 val, val2 = 0;
u8 pmr;
@@ -179,7 +178,7 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device);
u8 pmr;
@@ -196,7 +195,7 @@ static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u32 val, val2 = 0;
u8 pmr;
@@ -218,7 +217,7 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 pmr;
if (sc_reg > SCR_CONTROL)
@@ -241,7 +240,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_probe_ent *probe_ent = NULL;
int rc;
u32 genctl;
- struct ata_port_info *ppi;
+ struct ata_port_info *ppi[2];
int pci_dev_busy = 0;
u8 pmr;
u8 port2_start;
@@ -266,8 +265,8 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out_regions;
- ppi = &sis_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ ppi[0] = ppi[1] = &sis_port_info;
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent) {
rc = -ENOMEM;
goto err_out_regions;
@@ -276,17 +275,17 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* check and see if the SCRs are in IO space or PCI cfg space */
pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
- probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+ probe_ent->port_flags |= SIS_FLAG_CFGSCR;
/* if hardware thinks SCRs are in IO space, but there are
* no IO resources assigned, change to PCI cfg space.
*/
- if ((!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) &&
+ if ((!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) &&
((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
(pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
genctl &= ~GENCTL_IOMAPPED_SCR;
pci_write_config_dword(pdev, SIS_GENCTL, genctl);
- probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+ probe_ent->port_flags |= SIS_FLAG_CFGSCR;
}
pci_read_config_byte(pdev, SIS_PMR, &pmr);
@@ -307,7 +306,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
port2_start = 0x20;
}
- if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
+ if (!(probe_ent->port_flags & SIS_FLAG_CFGSCR)) {
probe_ent->port[0].scr_addr =
pci_resource_start(pdev, SIS_SCR_PCI_BAR);
probe_ent->port[1].scr_addr =
@@ -335,7 +334,7 @@ err_out:
static int __init sis_init(void)
{
- return pci_module_init(&sis_pci_driver);
+ return pci_register_driver(&sis_pci_driver);
}
static void __exit sis_exit(void)
diff --git a/drivers/scsi/sata_svw.c b/drivers/ata/sata_svw.c
index c94b870cf37..d6d6658d832 100644
--- a/drivers/scsi/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -36,7 +36,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -54,7 +53,7 @@
#endif /* CONFIG_PPC_OF */
#define DRV_NAME "sata_svw"
-#define DRV_VERSION "1.8"
+#define DRV_VERSION "2.0"
enum {
/* Taskfile registers offsets */
@@ -170,7 +169,7 @@ static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
@@ -200,7 +199,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
* @qc: Info associated with this ATA transaction.
*
* LOCKING:
- * spin_lock_irqsave(host_set lock)
+ * spin_lock_irqsave(host lock)
*/
static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
@@ -262,14 +261,14 @@ static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
return 0;
/* Find the OF node for the PCI device proper */
- np = pci_device_to_OF_node(to_pci_dev(ap->host_set->dev));
+ np = pci_device_to_OF_node(to_pci_dev(ap->host->dev));
if (np == NULL)
return 0;
/* Match it to a port node */
- index = (ap == ap->host_set->ports[0]) ? 0 : 1;
+ index = (ap == ap->host->ports[0]) ? 0 : 1;
for (np = np->child; np != NULL; np = np->sibling) {
- u32 *reg = (u32 *)get_property(np, "reg", NULL);
+ const u32 *reg = get_property(np, "reg", NULL);
if (!reg)
continue;
if (index == *reg)
@@ -424,12 +423,12 @@ static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *e
writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
probe_ent->sht = &k2_sata_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO;
probe_ent->port_ops = &k2_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
/* We don't care much about the PIO/UDMA masks, but the core won't like us
@@ -489,7 +488,7 @@ static struct pci_driver k2_sata_pci_driver = {
static int __init k2_sata_init(void)
{
- return pci_module_init(&k2_sata_pci_driver);
+ return pci_register_driver(&k2_sata_pci_driver);
}
diff --git a/drivers/scsi/sata_sx4.c b/drivers/ata/sata_sx4.c
index 7f864410f7c..091867e10ea 100644
--- a/drivers/scsi/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -160,7 +160,7 @@ static void pdc_port_stop(struct ata_port *ap);
static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf);
-static void pdc20621_host_stop(struct ata_host_set *host_set);
+static void pdc20621_host_stop(struct ata_host *host);
static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe,
@@ -218,7 +218,7 @@ static const struct ata_port_info pdc_port_info[] = {
/* board_20621 */
{
.sht = &pdc_sata_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_SRST | ATA_FLAG_MMIO |
ATA_FLAG_NO_ATAPI | ATA_FLAG_PIO_POLLING,
.pio_mask = 0x1f, /* pio0-4 */
@@ -244,21 +244,21 @@ static struct pci_driver pdc_sata_pci_driver = {
};
-static void pdc20621_host_stop(struct ata_host_set *host_set)
+static void pdc20621_host_stop(struct ata_host *host)
{
- struct pci_dev *pdev = to_pci_dev(host_set->dev);
- struct pdc_host_priv *hpriv = host_set->private_data;
+ struct pci_dev *pdev = to_pci_dev(host->dev);
+ struct pdc_host_priv *hpriv = host->private_data;
void __iomem *dimm_mmio = hpriv->dimm_mmio;
pci_iounmap(pdev, dimm_mmio);
kfree(hpriv);
- pci_iounmap(pdev, host_set->mmio_base);
+ pci_iounmap(pdev, host->mmio_base);
}
static int pdc_port_start(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct pdc_port_priv *pp;
int rc;
@@ -293,7 +293,7 @@ err_out:
static void pdc_port_stop(struct ata_port *ap)
{
- struct device *dev = ap->host_set->dev;
+ struct device *dev = ap->host->dev;
struct pdc_port_priv *pp = ap->private_data;
ap->private_data = NULL;
@@ -453,8 +453,8 @@ static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
struct scatterlist *sg;
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ struct pdc_host_priv *hpriv = ap->host->private_data;
void __iomem *dimm_mmio = hpriv->dimm_mmio;
unsigned int portno = ap->port_no;
unsigned int i, idx, total_len = 0, sgt_len;
@@ -514,8 +514,8 @@ static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct pdc_port_priv *pp = ap->private_data;
- void __iomem *mmio = ap->host_set->mmio_base;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
+ void __iomem *mmio = ap->host->mmio_base;
+ struct pdc_host_priv *hpriv = ap->host->private_data;
void __iomem *dimm_mmio = hpriv->dimm_mmio;
unsigned int portno = ap->port_no;
unsigned int i;
@@ -565,8 +565,8 @@ static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
u32 pkt_ofs)
{
struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
+ struct ata_host *host = ap->host;
+ void __iomem *mmio = host->mmio_base;
/* hard-code chip #0 */
mmio += PDC_CHIP0_OFS;
@@ -583,7 +583,7 @@ static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
u32 pkt_ofs)
{
struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
+ struct pdc_host_priv *pp = ap->host->private_data;
unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
if (!pp->doing_hdma) {
@@ -601,7 +601,7 @@ static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- struct pdc_host_priv *pp = ap->host_set->private_data;
+ struct pdc_host_priv *pp = ap->host->private_data;
unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
/* if nothing on queue, we're done */
@@ -620,7 +620,7 @@ static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int port_no = ap->port_no;
- struct pdc_host_priv *hpriv = ap->host_set->private_data;
+ struct pdc_host_priv *hpriv = ap->host->private_data;
void *dimm_mmio = hpriv->dimm_mmio;
dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
@@ -638,9 +638,9 @@ static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
static void pdc20621_packet_start(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- struct ata_host_set *host_set = ap->host_set;
+ struct ata_host *host = ap->host;
unsigned int port_no = ap->port_no;
- void __iomem *mmio = host_set->mmio_base;
+ void __iomem *mmio = host->mmio_base;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 seq = (u8) (port_no + 1);
unsigned int port_ofs;
@@ -781,8 +781,8 @@ static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
static void pdc20621_irq_clear(struct ata_port *ap)
{
- struct ata_host_set *host_set = ap->host_set;
- void __iomem *mmio = host_set->mmio_base;
+ struct ata_host *host = ap->host;
+ void __iomem *mmio = host->mmio_base;
mmio += PDC_CHIP0_OFS;
@@ -791,7 +791,7 @@ static void pdc20621_irq_clear(struct ata_port *ap)
static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
struct ata_port *ap;
u32 mask = 0;
unsigned int i, tmp, port_no;
@@ -800,12 +800,12 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
VPRINTK("ENTER\n");
- if (!host_set || !host_set->mmio_base) {
+ if (!host || !host->mmio_base) {
VPRINTK("QUICK EXIT\n");
return IRQ_NONE;
}
- mmio_base = host_set->mmio_base;
+ mmio_base = host->mmio_base;
/* reading should also clear interrupts */
mmio_base += PDC_CHIP0_OFS;
@@ -822,16 +822,16 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
return IRQ_NONE;
}
- spin_lock(&host_set->lock);
+ spin_lock(&host->lock);
for (i = 1; i < 9; i++) {
port_no = i - 1;
if (port_no > 3)
port_no -= 4;
- if (port_no >= host_set->n_ports)
+ if (port_no >= host->n_ports)
ap = NULL;
else
- ap = host_set->ports[port_no];
+ ap = host->ports[port_no];
tmp = mask & (1 << i);
VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
if (tmp && ap &&
@@ -845,7 +845,7 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
}
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
VPRINTK("mask == 0x%x\n", mask);
@@ -857,13 +857,13 @@ static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_re
static void pdc_eng_timeout(struct ata_port *ap)
{
u8 drv_stat;
- struct ata_host_set *host_set = ap->host_set;
+ struct ata_host *host = ap->host;
struct ata_queued_cmd *qc;
unsigned long flags;
DPRINTK("ENTER\n");
- spin_lock_irqsave(&host_set->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
qc = ata_qc_from_tag(ap, ap->active_tag);
@@ -885,7 +885,7 @@ static void pdc_eng_timeout(struct ata_port *ap)
break;
}
- spin_unlock_irqrestore(&host_set->lock, flags);
+ spin_unlock_irqrestore(&host->lock, flags);
ata_eh_qc_complete(qc);
DPRINTK("EXIT\n");
}
@@ -1429,14 +1429,14 @@ static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *
hpriv->dimm_mmio = dimm_mmio;
probe_ent->sht = pdc_port_info[board_idx].sht;
- probe_ent->host_flags = pdc_port_info[board_idx].host_flags;
+ probe_ent->port_flags = pdc_port_info[board_idx].flags;
probe_ent->pio_mask = pdc_port_info[board_idx].pio_mask;
probe_ent->mwdma_mask = pdc_port_info[board_idx].mwdma_mask;
probe_ent->udma_mask = pdc_port_info[board_idx].udma_mask;
probe_ent->port_ops = pdc_port_info[board_idx].port_ops;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
probe_ent->private_data = hpriv;
@@ -1482,7 +1482,7 @@ err_out:
static int __init pdc_sata_init(void)
{
- return pci_module_init(&pdc_sata_pci_driver);
+ return pci_register_driver(&pdc_sata_pci_driver);
}
diff --git a/drivers/scsi/sata_uli.c b/drivers/ata/sata_uli.c
index f668c997e9a..dd76f37be18 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -24,7 +24,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -37,7 +36,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_uli"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "1.0"
enum {
uli_5289 = 0,
@@ -129,7 +128,7 @@ static const struct ata_port_operations uli_ops = {
static struct ata_port_info uli_port_info = {
.sht = &uli_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f, /* pio0-4 */
.udma_mask = 0x7f, /* udma0-6 */
.port_ops = &uli_ops,
@@ -144,13 +143,13 @@ MODULE_VERSION(DRV_VERSION);
static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
{
- struct uli_priv *hpriv = ap->host_set->private_data;
+ struct uli_priv *hpriv = ap->host->private_data;
return hpriv->scr_cfg_addr[ap->port_no] + (4 * sc_reg);
}
static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
u32 val;
@@ -160,7 +159,7 @@ static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
{
- struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
pci_write_config_dword(pdev, cfg_addr, val);
@@ -186,7 +185,7 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi;
+ struct ata_port_info *ppi[2];
int rc;
unsigned int board_idx = (unsigned int) ent->driver_data;
int pci_dev_busy = 0;
@@ -212,8 +211,8 @@ static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto err_out_regions;
- ppi = &uli_port_info;
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ ppi[0] = ppi[1] = &uli_port_info;
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent) {
rc = -ENOMEM;
goto err_out_regions;
@@ -288,7 +287,7 @@ err_out:
static int __init uli_init(void)
{
- return pci_module_init(&uli_pci_driver);
+ return pci_register_driver(&uli_pci_driver);
}
static void __exit uli_exit(void)
diff --git a/drivers/scsi/sata_via.c b/drivers/ata/sata_via.c
index 322890b400a..a72a2389a11 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -47,7 +47,7 @@
#include <asm/io.h>
#define DRV_NAME "sata_via"
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "2.0"
enum board_ids_enum {
vt6420,
@@ -74,8 +74,10 @@ enum {
static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void vt6420_error_handler(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
+ { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
{ 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
@@ -107,7 +109,38 @@ static struct scsi_host_template svia_sht = {
.bios_param = ata_std_bios_param,
};
-static const struct ata_port_operations svia_sata_ops = {
+static const struct ata_port_operations vt6420_sata_ops = {
+ .port_disable = ata_port_disable,
+
+ .tf_load = ata_tf_load,
+ .tf_read = ata_tf_read,
+ .check_status = ata_check_status,
+ .exec_command = ata_exec_command,
+ .dev_select = ata_std_dev_select,
+
+ .bmdma_setup = ata_bmdma_setup,
+ .bmdma_start = ata_bmdma_start,
+ .bmdma_stop = ata_bmdma_stop,
+ .bmdma_status = ata_bmdma_status,
+
+ .qc_prep = ata_qc_prep,
+ .qc_issue = ata_qc_issue_prot,
+ .data_xfer = ata_pio_data_xfer,
+
+ .freeze = ata_bmdma_freeze,
+ .thaw = ata_bmdma_thaw,
+ .error_handler = vt6420_error_handler,
+ .post_internal_cmd = ata_bmdma_post_internal_cmd,
+
+ .irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
+ .port_start = ata_port_start,
+ .port_stop = ata_port_stop,
+ .host_stop = ata_host_stop,
+};
+
+static const struct ata_port_operations vt6421_sata_ops = {
.port_disable = ata_port_disable,
.tf_load = ata_tf_load,
@@ -141,13 +174,13 @@ static const struct ata_port_operations svia_sata_ops = {
.host_stop = ata_host_stop,
};
-static struct ata_port_info svia_port_info = {
+static struct ata_port_info vt6420_port_info = {
.sht = &svia_sht,
- .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY,
.pio_mask = 0x1f,
.mwdma_mask = 0x07,
.udma_mask = 0x7f,
- .port_ops = &svia_sata_ops,
+ .port_ops = &vt6420_sata_ops,
};
MODULE_AUTHOR("Jeff Garzik");
@@ -170,6 +203,81 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
}
+/**
+ * vt6420_prereset - prereset for vt6420
+ * @ap: target ATA port
+ *
+ * SCR registers on vt6420 are pieces of shit and may hang the
+ * whole machine completely if accessed with the wrong timing.
+ * To avoid such catastrophe, vt6420 doesn't provide generic SCR
+ * access operations, but uses SStatus and SControl only during
+ * boot probing in controlled way.
+ *
+ * As the old (pre EH update) probing code is proven to work, we
+ * strictly follow the access pattern.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+static int vt6420_prereset(struct ata_port *ap)
+{
+ struct ata_eh_context *ehc = &ap->eh_context;
+ unsigned long timeout = jiffies + (HZ * 5);
+ u32 sstatus, scontrol;
+ int online;
+
+ /* don't do any SCR stuff if we're not loading */
+ if (!ATA_PFLAG_LOADING)
+ goto skip_scr;
+
+ /* Resume phy. This is the old resume sequence from
+ * __sata_phy_reset().
+ */
+ svia_scr_write(ap, SCR_CONTROL, 0x300);
+ svia_scr_read(ap, SCR_CONTROL); /* flush */
+
+ /* wait for phy to become ready, if necessary */
+ do {
+ msleep(200);
+ if ((svia_scr_read(ap, SCR_STATUS) & 0xf) != 1)
+ break;
+ } while (time_before(jiffies, timeout));
+
+ /* open code sata_print_link_status() */
+ sstatus = svia_scr_read(ap, SCR_STATUS);
+ scontrol = svia_scr_read(ap, SCR_CONTROL);
+
+ online = (sstatus & 0xf) == 0x3;
+
+ ata_port_printk(ap, KERN_INFO,
+ "SATA link %s 1.5 Gbps (SStatus %X SControl %X)\n",
+ online ? "up" : "down", sstatus, scontrol);
+
+ /* SStatus is read one more time */
+ svia_scr_read(ap, SCR_STATUS);
+
+ if (!online) {
+ /* tell EH to bail */
+ ehc->i.action &= ~ATA_EH_RESET_MASK;
+ return 0;
+ }
+
+ skip_scr:
+ /* wait for !BSY */
+ ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+ return 0;
+}
+
+static void vt6420_error_handler(struct ata_port *ap)
+{
+ return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset,
+ NULL, ata_std_postreset);
+}
+
static const unsigned int svia_bar_sizes[] = {
8, 4, 8, 4, 16, 256
};
@@ -210,9 +318,10 @@ static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
{
struct ata_probe_ent *probe_ent;
- struct ata_port_info *ppi = &svia_port_info;
-
- probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+ struct ata_port_info *ppi[2];
+
+ ppi[0] = ppi[1] = &vt6420_port_info;
+ probe_ent = ata_pci_init_native_mode(pdev, ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
if (!probe_ent)
return NULL;
@@ -238,11 +347,11 @@ static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
INIT_LIST_HEAD(&probe_ent->node);
probe_ent->sht = &svia_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
- probe_ent->port_ops = &svia_sata_ops;
+ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY;
+ probe_ent->port_ops = &vt6421_sata_ops;
probe_ent->n_ports = N_PORTS;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->pio_mask = 0x1f;
probe_ent->mwdma_mask = 0x07;
probe_ent->udma_mask = 0x7f;
@@ -335,10 +444,10 @@ static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if ((pci_resource_start(pdev, i) == 0) ||
(pci_resource_len(pdev, i) < bar_sizes[i])) {
dev_printk(KERN_ERR, &pdev->dev,
- "invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
- i,
- pci_resource_start(pdev, i),
- pci_resource_len(pdev, i));
+ "invalid PCI BAR %u (sz 0x%llx, val 0x%llx)\n",
+ i,
+ (unsigned long long)pci_resource_start(pdev, i),
+ (unsigned long long)pci_resource_len(pdev, i));
rc = -ENODEV;
goto err_out_regions;
}
@@ -381,7 +490,7 @@ err_out:
static int __init svia_init(void)
{
- return pci_module_init(&svia_pci_driver);
+ return pci_register_driver(&svia_pci_driver);
}
static void __exit svia_exit(void)
diff --git a/drivers/scsi/sata_vsc.c b/drivers/ata/sata_vsc.c
index 6d0c4f18e65..d0d92f33de5 100644
--- a/drivers/scsi/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -47,7 +47,7 @@
#include <linux/libata.h>
#define DRV_NAME "sata_vsc"
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "2.0"
enum {
/* Interrupt register offsets (from chip base address) */
@@ -123,7 +123,7 @@ static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
void __iomem *mask_addr;
u8 mask;
- mask_addr = ap->host_set->mmio_base +
+ mask_addr = ap->host->mmio_base +
VSC_SATA_INT_MASK_OFFSET + ap->port_no;
mask = readb(mask_addr);
if (ctl & ATA_NIEN)
@@ -206,20 +206,20 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
struct pt_regs *regs)
{
- struct ata_host_set *host_set = dev_instance;
+ struct ata_host *host = dev_instance;
unsigned int i;
unsigned int handled = 0;
u32 int_status;
- spin_lock(&host_set->lock);
+ spin_lock(&host->lock);
- int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+ int_status = readl(host->mmio_base + VSC_SATA_INT_STAT_OFFSET);
- for (i = 0; i < host_set->n_ports; i++) {
+ for (i = 0; i < host->n_ports; i++) {
if (int_status & ((u32) 0xFF << (8 * i))) {
struct ata_port *ap;
- ap = host_set->ports[i];
+ ap = host->ports[i];
if (is_vsc_sata_int_err(i, int_status)) {
u32 err_status;
@@ -259,7 +259,7 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
}
}
- spin_unlock(&host_set->lock);
+ spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
}
@@ -297,7 +297,7 @@ static const struct ata_port_operations vsc_sata_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .data_xfer = ata_pio_data_xfer,
+ .data_xfer = ata_mmio_data_xfer,
.freeze = ata_bmdma_freeze,
.thaw = ata_bmdma_thaw,
.error_handler = ata_bmdma_error_handler,
@@ -395,12 +395,12 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
probe_ent->sht = &vsc_sata_sht;
- probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ probe_ent->port_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
ATA_FLAG_MMIO;
probe_ent->port_ops = &vsc_sata_ops;
probe_ent->n_ports = 4;
probe_ent->irq = pdev->irq;
- probe_ent->irq_flags = SA_SHIRQ;
+ probe_ent->irq_flags = IRQF_SHARED;
probe_ent->mmio_base = mmio_base;
/* We don't care much about the PIO/UDMA masks, but the core won't like us
@@ -443,16 +443,12 @@ err_out:
}
-/*
- * Intel 31244 is supposed to be identical.
- * Compatibility is untested as of yet.
- */
static const struct pci_device_id vsc_sata_pci_tbl[] = {
- { PCI_VENDOR_ID_VITESSE, PCI_DEVICE_ID_VITESSE_VSC7174,
+ { PCI_VENDOR_ID_VITESSE, 0x7174,
PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GD31244,
+ { PCI_VENDOR_ID_INTEL, 0x3200,
PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
- { }
+ { } /* terminate list */
};
@@ -466,7 +462,7 @@ static struct pci_driver vsc_sata_pci_driver = {
static int __init vsc_sata_init(void)
{
- return pci_module_init(&vsc_sata_pci_driver);
+ return pci_register_driver(&vsc_sata_pci_driver);
}
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig
index 01a9f1cb774..cfa5af883e1 100644
--- a/drivers/atm/Kconfig
+++ b/drivers/atm/Kconfig
@@ -398,7 +398,7 @@ config ATM_FORE200E_USE_TASKLET
default n
help
This defers work to be done by the interrupt handler to a
- tasklet instead of hanlding everything at interrupt time. This
+ tasklet instead of handling everything at interrupt time. This
may improve the responsive of the host.
config ATM_FORE200E_TX_RETRY
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index d1387cfe2d3..6cc93de0b71 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -2,7 +2,6 @@
* adummy.c: a dummy ATM driver
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 4b6bf19c39c..4521a249dd5 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -31,6 +31,7 @@
#include <linux/atmdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/poison.h>
#include <asm/atomic.h>
#include <asm/io.h>
@@ -1995,7 +1996,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
}
i += 1;
}
- if (*pointer == 0xdeadbeef) {
+ if (*pointer == ATM_POISON) {
return loader_start (lb, dev, ucode_start);
} else {
// cast needed as there is no %? for pointer differnces
@@ -2257,7 +2258,8 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_
}
PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"
- " IO %lx, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1),
+ " IO %llx, IRQ %u, MEM %p",
+ (unsigned long long)pci_resource_start(pci_dev, 1),
irq, bus_to_virt(pci_resource_start(pci_dev, 0)));
// check IO region
@@ -2285,7 +2287,7 @@ static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_
setup_pci_dev(pci_dev);
// grab (but share) IRQ and install handler
- err = request_irq(irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev);
+ err = request_irq(irq, interrupt_handler, IRQF_SHARED, DEV_LABEL, dev);
if (err < 0) {
PRINTK (KERN_ERR, "request IRQ failed!");
goto out_reset;
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index 84a93063cfe..8296420ceae 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -23,7 +23,6 @@
#ifndef AMBASSADOR_H
#define AMBASSADOR_H
-#include <linux/config.h>
#ifdef CONFIG_ATM_AMBASSADOR_DEBUG
#define DEBUG_AMBASSADOR
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index c13c4d736ef..df359a6c14f 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -4,7 +4,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pci.h>
@@ -1798,7 +1797,7 @@ static int __devinit eni_start(struct atm_dev *dev)
DPRINTK(">eni_start\n");
eni_dev = ENI_DEV(dev);
- if (request_irq(eni_dev->irq,&eni_int,SA_SHIRQ,DEV_LABEL,dev)) {
+ if (request_irq(eni_dev->irq,&eni_int,IRQF_SHARED,DEV_LABEL,dev)) {
printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
dev->number,eni_dev->irq);
error = -EAGAIN;
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 7f7ec288824..38fc054bd67 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -33,6 +33,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pci.h>
+#include <linux/poison.h>
#include <linux/errno.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
@@ -754,7 +755,7 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q)
fs_kfree_skb (skb);
fs_dprintk (FS_DEBUG_ALLOC, "Free trans-d: %p\n", td);
- memset (td, 0x12, sizeof (struct FS_BPENTRY));
+ memset (td, ATM_POISON_FREE, sizeof(struct FS_BPENTRY));
kfree (td);
break;
default:
@@ -951,7 +952,7 @@ static int fs_open(struct atm_vcc *atm_vcc)
it most likely that the chip will notice it. It also prevents us
from having to wait for completion. On the other hand, we may
need to wait for completion anyway, to see if it completed
- succesfully. */
+ successfully. */
switch (atm_vcc->qos.aal) {
case ATM_AAL2:
@@ -1657,9 +1658,10 @@ static int __devinit fs_init (struct fs_dev *dev)
func_enter ();
pci_dev = dev->pci_dev;
- printk (KERN_INFO "found a FireStream %d card, base %08lx, irq%d.\n",
+ printk (KERN_INFO "found a FireStream %d card, base %16llx, irq%d.\n",
IS_FS50(dev)?50:155,
- pci_resource_start(pci_dev, 0), dev->pci_dev->irq);
+ (unsigned long long)pci_resource_start(pci_dev, 0),
+ dev->pci_dev->irq);
if (fs_debug & FS_DEBUG_INIT)
my_hd ((unsigned char *) dev, sizeof (*dev));
@@ -1827,7 +1829,7 @@ static int __devinit fs_init (struct fs_dev *dev)
init_q (dev, &dev->rx_rq[i], RXB_RQ(i), RXRQ_NENTRIES, 1);
dev->irq = pci_dev->irq;
- if (request_irq (dev->irq, fs_irq, SA_SHIRQ, "firestream", dev)) {
+ if (request_irq (dev->irq, fs_irq, IRQF_SHARED, "firestream", dev)) {
printk (KERN_WARNING "couldn't get irq %d for firestream.\n", pci_dev->irq);
/* XXX undo all previous stuff... */
return 1;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 92923bf2723..98622130de5 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -25,7 +25,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -2124,7 +2123,7 @@ fore200e_change_qos(struct atm_vcc* vcc,struct atm_qos* qos, int flags)
static int __devinit
fore200e_irq_request(struct fore200e* fore200e)
{
- if (request_irq(fore200e->irq, fore200e_interrupt, SA_SHIRQ, fore200e->name, fore200e->atm_dev) < 0) {
+ if (request_irq(fore200e->irq, fore200e_interrupt, IRQF_SHARED, fore200e->name, fore200e->atm_dev) < 0) {
printk(FORE200E "unable to reserve IRQ %s for device %s\n",
fore200e_irq_itoa(fore200e->irq), fore200e->name);
diff --git a/drivers/atm/fore200e.h b/drivers/atm/fore200e.h
index 2558eb85323..f9abfdac33e 100644
--- a/drivers/atm/fore200e.h
+++ b/drivers/atm/fore200e.h
@@ -3,7 +3,6 @@
#define _FORE200E_H
#ifdef __KERNEL__
-#include <linux/config.h>
/* rx buffer sizes */
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index fde9334059a..f2511b42dba 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -55,7 +55,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -455,7 +454,7 @@ rate_to_atmf(unsigned rate) /* cps to atm forum format */
return (NONZERO | (exp << 9) | (rate & 0x1ff));
}
-static void __init
+static void __devinit
he_init_rx_lbfp0(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
@@ -486,7 +485,7 @@ he_init_rx_lbfp0(struct he_dev *he_dev)
he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
}
-static void __init
+static void __devinit
he_init_rx_lbfp1(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
@@ -517,7 +516,7 @@ he_init_rx_lbfp1(struct he_dev *he_dev)
he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
}
-static void __init
+static void __devinit
he_init_tx_lbfp(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
@@ -547,7 +546,7 @@ he_init_tx_lbfp(struct he_dev *he_dev)
he_writel(he_dev, lbufd_index - 1, TLBF_T);
}
-static int __init
+static int __devinit
he_init_tpdrq(struct he_dev *he_dev)
{
he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev,
@@ -569,7 +568,7 @@ he_init_tpdrq(struct he_dev *he_dev)
return 0;
}
-static void __init
+static void __devinit
he_init_cs_block(struct he_dev *he_dev)
{
unsigned clock, rate, delta;
@@ -665,7 +664,7 @@ he_init_cs_block(struct he_dev *he_dev)
}
-static int __init
+static int __devinit
he_init_cs_block_rcm(struct he_dev *he_dev)
{
unsigned (*rategrid)[16][16];
@@ -786,7 +785,7 @@ he_init_cs_block_rcm(struct he_dev *he_dev)
return 0;
}
-static int __init
+static int __devinit
he_init_group(struct he_dev *he_dev, int group)
{
int i;
@@ -956,7 +955,7 @@ he_init_group(struct he_dev *he_dev, int group)
return 0;
}
-static int __init
+static int __devinit
he_init_irq(struct he_dev *he_dev)
{
int i;
@@ -1008,7 +1007,7 @@ he_init_irq(struct he_dev *he_dev)
he_writel(he_dev, 0x0, GRP_54_MAP);
he_writel(he_dev, 0x0, GRP_76_MAP);
- if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev)) {
+ if (request_irq(he_dev->pci_dev->irq, he_irq_handler, IRQF_DISABLED|IRQF_SHARED, DEV_LABEL, he_dev)) {
hprintk("irq %d already in use\n", he_dev->pci_dev->irq);
return -EINVAL;
}
@@ -1018,7 +1017,7 @@ he_init_irq(struct he_dev *he_dev)
return 0;
}
-static int __init
+static int __devinit
he_start(struct atm_dev *dev)
{
struct he_dev *he_dev;
@@ -1913,7 +1912,7 @@ he_service_rbrq(struct he_dev *he_dev, int group)
skb->tail = skb->data + skb->len;
#ifdef USE_CHECKSUM_HW
if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) {
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
skb->csum = TCP_CKSUM(skb->data,
he_vcc->pdu_len);
}
@@ -1929,7 +1928,9 @@ he_service_rbrq(struct he_dev *he_dev, int group)
#ifdef notdef
ATM_SKB(skb)->vcc = vcc;
#endif
+ spin_unlock(&he_dev->global_lock);
vcc->push(vcc, skb);
+ spin_lock(&he_dev->global_lock);
atomic_inc(&vcc->stats->rx);
@@ -2283,6 +2284,8 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid)
TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H)));
if (new_tail == he_dev->tpdrq_head) {
+ int slot;
+
hprintk("tpdrq full (cid 0x%x)\n", cid);
/*
* FIXME
@@ -2290,6 +2293,13 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid)
* after service_tbrq, service the backlog
* for now, we just drop the pdu
*/
+ for (slot = 0; slot < TPD_MAXIOV; ++slot) {
+ if (tpd->iovec[slot].addr)
+ pci_unmap_single(he_dev->pci_dev,
+ tpd->iovec[slot].addr,
+ tpd->iovec[slot].len & TPD_LEN_MASK,
+ PCI_DMA_TODEVICE);
+ }
if (tpd->skb) {
if (tpd->vcc->pop)
tpd->vcc->pop(tpd->vcc, tpd->skb);
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 821c81e8cd3..d1113e845f9 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -2735,7 +2735,7 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_
irq = pci_dev->irq;
if (request_irq(irq,
interrupt_handler,
- SA_SHIRQ, /* irqflags guess */
+ IRQF_SHARED, /* irqflags guess */
DEV_LABEL, /* name guess */
dev)) {
PRINTD(DBG_WARN, "request IRQ failed!");
diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h
index e2cc7020fa3..4461229f56a 100644
--- a/drivers/atm/horizon.h
+++ b/drivers/atm/horizon.h
@@ -30,7 +30,6 @@
#ifndef DRIVER_ATM_HORIZON_H
#define DRIVER_ATM_HORIZON_H
-#include <linux/config.h>
#ifdef CONFIG_ATM_HORIZON_DEBUG
#define DEBUG_HORIZON
diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
index 0aabfc2a59d..325325afabe 100644
--- a/drivers/atm/idt77105.c
+++ b/drivers/atm/idt77105.c
@@ -358,7 +358,7 @@ static const struct atmphy_ops idt77105_ops = {
};
-int idt77105_init(struct atm_dev *dev)
+int __devinit idt77105_init(struct atm_dev *dev)
{
dev->phy = &idt77105_ops;
return 0;
diff --git a/drivers/atm/idt77105.h b/drivers/atm/idt77105.h
index 8ba8218aaef..3fd2bc89976 100644
--- a/drivers/atm/idt77105.h
+++ b/drivers/atm/idt77105.h
@@ -76,7 +76,7 @@
#define IDT77105_CTRSEL_RHEC 0x01 /* W, Rx HEC Error Counter */
#ifdef __KERNEL__
-int idt77105_init(struct atm_dev *dev) __init;
+int idt77105_init(struct atm_dev *dev);
#endif
/*
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index b4a76cade64..b0369bb20f0 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -34,8 +34,8 @@ static char const rcsid[] =
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/pci.h>
+#include <linux/poison.h>
#include <linux/skbuff.h>
#include <linux/kernel.h>
#include <linux/vmalloc.h>
@@ -3387,7 +3387,7 @@ init_card(struct atm_dev *dev)
writel(SAR_STAT_TMROF, SAR_REG_STAT);
}
IPRINTK("%s: Request IRQ ... ", card->name);
- if (request_irq(pcidev->irq, idt77252_interrupt, SA_INTERRUPT|SA_SHIRQ,
+ if (request_irq(pcidev->irq, idt77252_interrupt, IRQF_DISABLED|IRQF_SHARED,
card->name, card) != 0) {
printk("%s: can't allocate IRQ.\n", card->name);
deinit_card(card);
@@ -3658,7 +3658,7 @@ probe_sram(struct idt77252_dev *card)
writel(SAR_CMD_WRITE_SRAM | (0 << 2), SAR_REG_CMD);
for (addr = 0x4000; addr < 0x80000; addr += 0x4000) {
- writel(0xdeadbeef, SAR_REG_DR0);
+ writel(ATM_POISON, SAR_REG_DR0);
writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD);
writel(SAR_CMD_READ_SRAM | (0 << 2), SAR_REG_CMD);
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 2e2e50e1167..f20b0b2c06c 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2284,7 +2284,7 @@ static int reset_sar(struct atm_dev *dev)
}
-static int __init ia_init(struct atm_dev *dev)
+static int __devinit ia_init(struct atm_dev *dev)
{
IADEV *iadev;
unsigned long real_base;
@@ -2480,7 +2480,7 @@ static void ia_free_rx(IADEV *iadev)
iadev->rx_dle_dma);
}
-static int __init ia_start(struct atm_dev *dev)
+static int __devinit ia_start(struct atm_dev *dev)
{
IADEV *iadev;
int error;
@@ -2488,7 +2488,7 @@ static int __init ia_start(struct atm_dev *dev)
u32 ctrl_reg;
IF_EVENT(printk(">ia_start\n");)
iadev = INPH_IA_DEV(dev);
- if (request_irq(iadev->irq, &ia_int, SA_SHIRQ, DEV_LABEL, dev)) {
+ if (request_irq(iadev->irq, &ia_int, IRQF_SHARED, DEV_LABEL, dev)) {
printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
dev->number, iadev->irq);
error = -EAGAIN;
diff --git a/drivers/atm/iphase.h b/drivers/atm/iphase.h
index b8d0bd4d6c3..133eefcc047 100644
--- a/drivers/atm/iphase.h
+++ b/drivers/atm/iphase.h
@@ -43,7 +43,6 @@
#ifndef IPHASE_H
#define IPHASE_H
-#include <linux/config.h>
/************************ IADBG DEFINE *********************************/
/* IADebugFlag Bit Map */
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index cac09e353be..fe60a59b7fc 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -2240,7 +2240,7 @@ static int __devinit lanai_dev_open(struct atm_dev *atmdev)
conf2_write(lanai);
reg_write(lanai, TX_FIFO_DEPTH, TxDepth_Reg);
reg_write(lanai, 0, CBR_ICG_Reg); /* CBR defaults to no limit */
- if ((result = request_irq(lanai->pci->irq, lanai_int, SA_SHIRQ,
+ if ((result = request_irq(lanai->pci->irq, lanai_int, IRQF_SHARED,
DEV_LABEL, lanai)) != 0) {
printk(KERN_ERR DEV_LABEL ": can't allocate interrupt\n");
goto error_vcctable;
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 074abc81ec3..b8036899e56 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -36,7 +36,6 @@
/* Header files ***************************************************************/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/atmdev.h>
@@ -626,7 +625,7 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
if (mac[i] == NULL)
nicstar_init_eprom(card->membase);
- if (request_irq(pcidev->irq, &ns_irq_handler, SA_INTERRUPT | SA_SHIRQ, "nicstar", card) != 0)
+ if (request_irq(pcidev->irq, &ns_irq_handler, IRQF_DISABLED | IRQF_SHARED, "nicstar", card) != 0)
{
printk("nicstar%d: can't allocate IRQ %d.\n", i, pcidev->irq);
error = 9;
diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c
index b1d063cc4fb..f04f39c0083 100644
--- a/drivers/atm/suni.c
+++ b/drivers/atm/suni.c
@@ -289,7 +289,7 @@ static const struct atmphy_ops suni_ops = {
};
-int suni_init(struct atm_dev *dev)
+int __devinit suni_init(struct atm_dev *dev)
{
unsigned char mri;
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index f484747f255..2c65e82f0d6 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -3,7 +3,6 @@
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -1271,7 +1270,7 @@ static int __init zatm_start(struct atm_dev *dev)
zatm_dev->rx_map = zatm_dev->tx_map = NULL;
for (i = 0; i < NR_MBX; i++)
zatm_dev->mbx_start[i] = 0;
- error = request_irq(zatm_dev->irq, zatm_int, SA_SHIRQ, DEV_LABEL, dev);
+ error = request_irq(zatm_dev->irq, zatm_int, IRQF_SHARED, DEV_LABEL, dev);
if (error < 0) {
printk(KERN_ERR DEV_LABEL "(itf %d): IRQ%d is already in use\n",
dev->number,zatm_dev->irq);
diff --git a/drivers/atm/zatm.h b/drivers/atm/zatm.h
index 416fe0fda60..ae9165ce15a 100644
--- a/drivers/atm/zatm.h
+++ b/drivers/atm/zatm.h
@@ -6,7 +6,6 @@
#ifndef DRIVER_ATM_ZATM_H
#define DRIVER_ATM_ZATM_H
-#include <linux/config.h>
#include <linux/skbuff.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 80502dc6ed6..0b4e2243693 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -20,7 +20,7 @@ config PREVENT_FIRMWARE_BUILD
config FW_LOADER
tristate "Userspace firmware loading support"
- select HOTPLUG
+ depends on HOTPLUG
---help---
This option is provided for the case where no in-kernel-tree modules
require userspace firmware loading support, but a module built outside
diff --git a/drivers/base/base.h b/drivers/base/base.h
index c3b8dc98b8a..d26644a5953 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -16,7 +16,7 @@ extern int cpu_dev_init(void);
extern int attribute_container_init(void);
extern int bus_add_device(struct device * dev);
-extern void bus_attach_device(struct device * dev);
+extern int bus_attach_device(struct device * dev);
extern void bus_remove_device(struct device * dev);
extern struct bus_type *get_bus(struct bus_type * bus);
extern void put_bus(struct bus_type * bus);
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 050d86d0b87..12173d16bea 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -130,7 +129,7 @@ static struct kobj_type ktype_bus = {
};
-decl_subsys(bus, &ktype_bus, NULL);
+static decl_subsys(bus, &ktype_bus, NULL);
#ifdef CONFIG_HOTPLUG
@@ -372,12 +371,20 @@ int bus_add_device(struct device * dev)
if (bus) {
pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
error = device_add_attrs(bus, dev);
- if (!error) {
- sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
- sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem");
- sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
- }
+ if (error)
+ goto out;
+ error = sysfs_create_link(&bus->devices.kobj,
+ &dev->kobj, dev->bus_id);
+ if (error)
+ goto out;
+ error = sysfs_create_link(&dev->kobj,
+ &dev->bus->subsys.kset.kobj, "subsystem");
+ if (error)
+ goto out;
+ error = sysfs_create_link(&dev->kobj,
+ &dev->bus->subsys.kset.kobj, "bus");
}
+out:
return error;
}
@@ -385,16 +392,24 @@ int bus_add_device(struct device * dev)
* bus_attach_device - add device to bus
* @dev: device tried to attach to a driver
*
+ * - Add device to bus's list of devices.
* - Try to attach to driver.
*/
-void bus_attach_device(struct device * dev)
+int bus_attach_device(struct device * dev)
{
- struct bus_type * bus = dev->bus;
+ struct bus_type *bus = dev->bus;
+ int ret = 0;
if (bus) {
- device_attach(dev);
- klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+ dev->is_registered = 1;
+ ret = device_attach(dev);
+ if (ret >= 0) {
+ klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+ ret = 0;
+ } else
+ dev->is_registered = 0;
}
+ return ret;
}
/**
@@ -413,7 +428,8 @@ void bus_remove_device(struct device * dev)
sysfs_remove_link(&dev->kobj, "bus");
sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
device_remove_attrs(dev->bus, dev);
- klist_remove(&dev->knode_bus);
+ dev->is_registered = 0;
+ klist_del(&dev->knode_bus);
pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
device_release_driver(dev);
put_bus(dev->bus);
@@ -456,10 +472,17 @@ static void driver_remove_attrs(struct bus_type * bus, struct device_driver * dr
* Thanks to drivers making their tables __devinit, we can't allow manual
* bind and unbind from userspace unless CONFIG_HOTPLUG is enabled.
*/
-static void add_bind_files(struct device_driver *drv)
+static int __must_check add_bind_files(struct device_driver *drv)
{
- driver_create_file(drv, &driver_attr_unbind);
- driver_create_file(drv, &driver_attr_bind);
+ int ret;
+
+ ret = driver_create_file(drv, &driver_attr_unbind);
+ if (ret == 0) {
+ ret = driver_create_file(drv, &driver_attr_bind);
+ if (ret)
+ driver_remove_file(drv, &driver_attr_unbind);
+ }
+ return ret;
}
static void remove_bind_files(struct device_driver *drv)
@@ -468,7 +491,7 @@ static void remove_bind_files(struct device_driver *drv)
driver_remove_file(drv, &driver_attr_unbind);
}
#else
-static inline void add_bind_files(struct device_driver *drv) {}
+static inline int add_bind_files(struct device_driver *drv) { return 0; }
static inline void remove_bind_files(struct device_driver *drv) {}
#endif
@@ -477,7 +500,7 @@ static inline void remove_bind_files(struct device_driver *drv) {}
* @drv: driver.
*
*/
-int bus_add_driver(struct device_driver * drv)
+int bus_add_driver(struct device_driver *drv)
{
struct bus_type * bus = get_bus(drv->bus);
int error = 0;
@@ -485,27 +508,39 @@ int bus_add_driver(struct device_driver * drv)
if (bus) {
pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
error = kobject_set_name(&drv->kobj, "%s", drv->name);
- if (error) {
- put_bus(bus);
- return error;
- }
+ if (error)
+ goto out_put_bus;
drv->kobj.kset = &bus->drivers;
- if ((error = kobject_register(&drv->kobj))) {
- put_bus(bus);
- return error;
- }
+ if ((error = kobject_register(&drv->kobj)))
+ goto out_put_bus;
- driver_attach(drv);
+ error = driver_attach(drv);
+ if (error)
+ goto out_unregister;
klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
module_add_driver(drv->owner, drv);
- driver_add_attrs(bus, drv);
- add_bind_files(drv);
+ error = driver_add_attrs(bus, drv);
+ if (error) {
+ /* How the hell do we get out of this pickle? Give up */
+ printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
+ __FUNCTION__, drv->name);
+ }
+ error = add_bind_files(drv);
+ if (error) {
+ /* Ditto */
+ printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
+ __FUNCTION__, drv->name);
+ }
}
return error;
+out_unregister:
+ kobject_unregister(&drv->kobj);
+out_put_bus:
+ put_bus(bus);
+ return error;
}
-
/**
* bus_remove_driver - delete driver from bus's knowledge.
* @drv: driver.
@@ -531,16 +566,21 @@ void bus_remove_driver(struct device_driver * drv)
/* Helper for bus_rescan_devices's iter */
-static int bus_rescan_devices_helper(struct device *dev, void *data)
+static int __must_check bus_rescan_devices_helper(struct device *dev,
+ void *data)
{
+ int ret = 0;
+
if (!dev->driver) {
if (dev->parent) /* Needed for USB */
down(&dev->parent->sem);
- device_attach(dev);
+ ret = device_attach(dev);
if (dev->parent)
up(&dev->parent->sem);
+ if (ret > 0)
+ ret = 0;
}
- return 0;
+ return ret < 0 ? ret : 0;
}
/**
@@ -551,9 +591,9 @@ static int bus_rescan_devices_helper(struct device *dev, void *data)
* attached and rescan it against existing drivers to see if it matches
* any by calling device_attach() for the unbound devices.
*/
-void bus_rescan_devices(struct bus_type * bus)
+int bus_rescan_devices(struct bus_type * bus)
{
- bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
+ return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
}
/**
@@ -565,7 +605,7 @@ void bus_rescan_devices(struct bus_type * bus)
* to use if probing criteria changed during a devices lifetime and
* driver attachment should change accordingly.
*/
-void device_reprobe(struct device *dev)
+int device_reprobe(struct device *dev)
{
if (dev->driver) {
if (dev->parent) /* Needed for USB */
@@ -574,14 +614,14 @@ void device_reprobe(struct device *dev)
if (dev->parent)
up(&dev->parent->sem);
}
-
- bus_rescan_devices_helper(dev, NULL);
+ return bus_rescan_devices_helper(dev, NULL);
}
EXPORT_SYMBOL_GPL(device_reprobe);
-struct bus_type * get_bus(struct bus_type * bus)
+struct bus_type *get_bus(struct bus_type *bus)
{
- return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL;
+ return bus ? container_of(subsys_get(&bus->subsys),
+ struct bus_type, subsys) : NULL;
}
void put_bus(struct bus_type * bus)
@@ -599,12 +639,13 @@ void put_bus(struct bus_type * bus)
*
* Note that kset_find_obj increments bus' reference count.
*/
-
+#if 0
struct bus_type * find_bus(char * name)
{
struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
return k ? to_bus(k) : NULL;
}
+#endif /* 0 */
/**
@@ -655,22 +696,6 @@ static void klist_devices_put(struct klist_node *n)
put_device(dev);
}
-static void klist_drivers_get(struct klist_node *n)
-{
- struct device_driver *drv = container_of(n, struct device_driver,
- knode_bus);
-
- get_driver(drv);
-}
-
-static void klist_drivers_put(struct klist_node *n)
-{
- struct device_driver *drv = container_of(n, struct device_driver,
- knode_bus);
-
- put_driver(drv);
-}
-
/**
* bus_register - register a bus with the system.
* @bus: bus.
@@ -706,7 +731,7 @@ int bus_register(struct bus_type * bus)
goto bus_drivers_fail;
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
- klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put);
+ klist_init(&bus->klist_drivers, NULL, NULL);
bus_add_attrs(bus);
pr_debug("bus type '%s' registered\n", bus->name);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index 9aa12746026..b32b77ff2dc 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -20,6 +19,8 @@
#include <linux/slab.h>
#include "base.h"
+extern struct subsystem devices_subsys;
+
#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr)
#define to_class(obj) container_of(obj, struct class, subsys.kset.kobj)
@@ -198,7 +199,7 @@ static int class_device_create_uevent(struct class_device *class_dev,
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
*/
-struct class *class_create(struct module *owner, char *name)
+struct class *class_create(struct module *owner, const char *name)
{
struct class *cls;
int retval;
@@ -227,7 +228,7 @@ error:
/**
* class_destroy - destroys a struct class structure
- * @cs: pointer to the struct class that is to be destroyed
+ * @cls: pointer to the struct class that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to class_create().
@@ -362,7 +363,7 @@ static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
pr_debug("%s - name = %s\n", __FUNCTION__, class_dev->class_id);
if (class_dev->dev) {
- /* add physical device, backing this device */
+ /* add device, backing this class device (deprecated) */
struct device *dev = class_dev->dev;
char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
@@ -657,9 +658,9 @@ int class_device_register(struct class_device *class_dev)
/**
* class_device_create - creates a class device and registers it with sysfs
- * @cs: pointer to the struct class that this device should be registered to.
+ * @cls: pointer to the struct class that this device should be registered to.
* @parent: pointer to the parent struct class_device of this new device, if any.
- * @dev: the dev_t for the char device to be added.
+ * @devt: the dev_t for the char device to be added.
* @device: a pointer to a struct device that is assiociated with this class device.
* @fmt: string for the class device's name
*
@@ -680,7 +681,8 @@ int class_device_register(struct class_device *class_dev)
struct class_device *class_device_create(struct class *cls,
struct class_device *parent,
dev_t devt,
- struct device *device, char *fmt, ...)
+ struct device *device,
+ const char *fmt, ...)
{
va_list args;
struct class_device *class_dev = NULL;
@@ -764,7 +766,7 @@ void class_device_unregister(struct class_device *class_dev)
/**
* class_device_destroy - removes a class device that was created with class_device_create()
* @cls: the pointer to the struct class that this device was registered * with.
- * @dev: the dev_t of the device that was previously registered.
+ * @devt: the dev_t of the device that was previously registered.
*
* This call unregisters and cleans up a class device that was created with a
* call to class_device_create()
@@ -840,6 +842,7 @@ int class_interface_register(struct class_interface *class_intf)
{
struct class *parent;
struct class_device *class_dev;
+ struct device *dev;
if (!class_intf || !class_intf->class)
return -ENODEV;
@@ -854,6 +857,10 @@ int class_interface_register(struct class_interface *class_intf)
list_for_each_entry(class_dev, &parent->children, node)
class_intf->add(class_dev, class_intf);
}
+ if (class_intf->add_dev) {
+ list_for_each_entry(dev, &parent->devices, node)
+ class_intf->add_dev(dev, class_intf);
+ }
up(&parent->sem);
return 0;
@@ -863,6 +870,7 @@ void class_interface_unregister(struct class_interface *class_intf)
{
struct class * parent = class_intf->class;
struct class_device *class_dev;
+ struct device *dev;
if (!parent)
return;
@@ -873,12 +881,31 @@ void class_interface_unregister(struct class_interface *class_intf)
list_for_each_entry(class_dev, &parent->children, node)
class_intf->remove(class_dev, class_intf);
}
+ if (class_intf->remove_dev) {
+ list_for_each_entry(dev, &parent->devices, node)
+ class_intf->remove_dev(dev, class_intf);
+ }
up(&parent->sem);
class_put(parent);
}
+int virtual_device_parent(struct device *dev)
+{
+ if (!dev->class)
+ return -ENODEV;
+
+ if (!dev->class->virtual_dir) {
+ static struct kobject *virtual_dir = NULL;
+
+ if (!virtual_dir)
+ virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
+ dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
+ }
+ dev->kobj.parent = dev->class->virtual_dir;
+ return 0;
+}
int __init classes_init(void)
{
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 27c2176895d..b224bb43ff6 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -3,12 +3,13 @@
*
* Copyright (c) 2002-3 Patrick Mochel
* Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2006 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2006 Novell, Inc.
*
* This file is released under the GPLv2
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
@@ -93,6 +94,8 @@ static void device_release(struct kobject * kobj)
if (dev->release)
dev->release(dev);
+ else if (dev->class && dev->class->dev_release)
+ dev->class->dev_release(dev);
else {
printk(KERN_ERR "Device '%s' does not have a release() function, "
"it is broken and must be fixed.\n",
@@ -150,17 +153,21 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
"MINOR=%u", MINOR(dev->devt));
}
- /* add bus name of physical device */
+ /* add bus name (same as SUBSYSTEM, deprecated) */
if (dev->bus)
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name);
- /* add driver name of physical device */
- if (dev->driver)
+ /* add driver name (PHYSDEV* values are deprecated)*/
+ if (dev->driver) {
+ add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "DRIVER=%s", dev->driver->name);
add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s", dev->driver->name);
+ }
/* terminate, set to next free slot, shrink available space */
envp[i] = NULL;
@@ -178,6 +185,15 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
}
}
+ if (dev->class && dev->class->dev_uevent) {
+ /* have the class specific function add its stuff */
+ retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
+ if (retval) {
+ pr_debug("%s - dev_uevent() returned %d\n",
+ __FUNCTION__, retval);
+ }
+ }
+
return retval;
}
@@ -194,6 +210,72 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
return count;
}
+static int device_add_groups(struct device *dev)
+{
+ int i;
+ int error = 0;
+
+ if (dev->groups) {
+ for (i = 0; dev->groups[i]; i++) {
+ error = sysfs_create_group(&dev->kobj, dev->groups[i]);
+ if (error) {
+ while (--i >= 0)
+ sysfs_remove_group(&dev->kobj, dev->groups[i]);
+ goto out;
+ }
+ }
+ }
+out:
+ return error;
+}
+
+static void device_remove_groups(struct device *dev)
+{
+ int i;
+ if (dev->groups) {
+ for (i = 0; dev->groups[i]; i++) {
+ sysfs_remove_group(&dev->kobj, dev->groups[i]);
+ }
+ }
+}
+
+static int device_add_attrs(struct device *dev)
+{
+ struct class *class = dev->class;
+ int error = 0;
+ int i;
+
+ if (!class)
+ return 0;
+
+ if (class->dev_attrs) {
+ for (i = 0; attr_name(class->dev_attrs[i]); i++) {
+ error = device_create_file(dev, &class->dev_attrs[i]);
+ if (error)
+ break;
+ }
+ }
+ if (error)
+ while (--i >= 0)
+ device_remove_file(dev, &class->dev_attrs[i]);
+ return error;
+}
+
+static void device_remove_attrs(struct device *dev)
+{
+ struct class *class = dev->class;
+ int i;
+
+ if (!class)
+ return;
+
+ if (class->dev_attrs) {
+ for (i = 0; attr_name(class->dev_attrs[i]); i++)
+ device_remove_file(dev, &class->dev_attrs[i]);
+ }
+}
+
+
static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -237,6 +319,32 @@ void device_remove_file(struct device * dev, struct device_attribute * attr)
}
}
+/**
+ * device_create_bin_file - create sysfs binary attribute file for device.
+ * @dev: device.
+ * @attr: device binary attribute descriptor.
+ */
+int device_create_bin_file(struct device *dev, struct bin_attribute *attr)
+{
+ int error = -EINVAL;
+ if (dev)
+ error = sysfs_create_bin_file(&dev->kobj, attr);
+ return error;
+}
+EXPORT_SYMBOL_GPL(device_create_bin_file);
+
+/**
+ * device_remove_bin_file - remove sysfs binary attribute file
+ * @dev: device.
+ * @attr: device binary attribute descriptor.
+ */
+void device_remove_bin_file(struct device *dev, struct bin_attribute *attr)
+{
+ if (dev)
+ sysfs_remove_bin_file(&dev->kobj, attr);
+}
+EXPORT_SYMBOL_GPL(device_remove_bin_file);
+
static void klist_children_get(struct klist_node *n)
{
struct device *dev = container_of(n, struct device, knode_parent);
@@ -290,12 +398,20 @@ int device_add(struct device *dev)
{
struct device *parent = NULL;
char *class_name = NULL;
+ struct class_interface *class_intf;
int error = -EINVAL;
dev = get_device(dev);
if (!dev || !strlen(dev->bus_id))
goto Error;
+ /* if this is a class device, and has no parent, create one */
+ if ((dev->class) && (dev->parent == NULL)) {
+ error = virtual_device_parent(dev);
+ if (error)
+ goto Error;
+ }
+
parent = get_device(dev->parent);
pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
@@ -308,6 +424,10 @@ int device_add(struct device *dev)
if ((error = kobject_add(&dev->kobj)))
goto Error;
+ /* notify platform of device entry */
+ if (platform_notify)
+ platform_notify(dev);
+
dev->uevent_attr.attr.name = "uevent";
dev->uevent_attr.attr.mode = S_IWUSR;
if (dev->driver)
@@ -341,12 +461,17 @@ int device_add(struct device *dev)
"subsystem");
sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
dev->bus_id);
-
- sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
- class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+ if (parent) {
+ sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
+ class_name = make_class_name(dev->class->name, &dev->kobj);
+ sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+ }
}
+ if ((error = device_add_attrs(dev)))
+ goto AttrsError;
+ if ((error = device_add_groups(dev)))
+ goto GroupError;
if ((error = device_pm_add(dev)))
goto PMError;
if ((error = bus_add_device(dev)))
@@ -357,15 +482,16 @@ int device_add(struct device *dev)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
if (dev->class) {
- /* tie the class to the device */
down(&dev->class->sem);
+ /* tie the class to the device */
list_add_tail(&dev->node, &dev->class->devices);
+
+ /* notify any interfaces that the device is here */
+ list_for_each_entry(class_intf, &dev->class->interfaces, node)
+ if (class_intf->add_dev)
+ class_intf->add_dev(dev, class_intf);
up(&dev->class->sem);
}
-
- /* notify platform of device entry */
- if (platform_notify)
- platform_notify(dev);
Done:
kfree(class_name);
put_device(dev);
@@ -373,6 +499,10 @@ int device_add(struct device *dev)
BusError:
device_pm_remove(dev);
PMError:
+ device_remove_groups(dev);
+ GroupError:
+ device_remove_attrs(dev);
+ AttrsError:
if (dev->devt_attr) {
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
@@ -450,6 +580,7 @@ void device_del(struct device * dev)
{
struct device * parent = dev->parent;
char *class_name = NULL;
+ struct class_interface *class_intf;
if (parent)
klist_del(&dev->knode_parent);
@@ -459,14 +590,23 @@ void device_del(struct device * dev)
sysfs_remove_link(&dev->kobj, "subsystem");
sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id);
class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_remove_link(&dev->kobj, "device");
- sysfs_remove_link(&dev->parent->kobj, class_name);
+ if (parent) {
+ sysfs_remove_link(&dev->kobj, "device");
+ sysfs_remove_link(&dev->parent->kobj, class_name);
+ }
kfree(class_name);
down(&dev->class->sem);
+ /* notify any interfaces that the device is now gone */
+ list_for_each_entry(class_intf, &dev->class->interfaces, node)
+ if (class_intf->remove_dev)
+ class_intf->remove_dev(dev, class_intf);
+ /* remove the device from the class list */
list_del_init(&dev->node);
up(&dev->class->sem);
}
device_remove_file(dev, &dev->uevent_attr);
+ device_remove_groups(dev);
+ device_remove_attrs(dev);
/* Notify the platform of the removal, in case they
* need to do anything...
@@ -560,27 +700,27 @@ static void device_create_release(struct device *dev)
/**
* device_create - creates a device and registers it with sysfs
- * @cs: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct device of this new device, if any.
- * @dev: the dev_t for the char device to be added.
- * @fmt: string for the class device's name
+ * @class: pointer to the struct class that this device should be registered to
+ * @parent: pointer to the parent struct device of this new device, if any
+ * @devt: the dev_t for the char device to be added
+ * @fmt: string for the device's name
+ *
+ * This function can be used by char device classes. A struct device
+ * will be created in sysfs, registered to the specified class.
*
- * This function can be used by char device classes. A struct
- * device will be created in sysfs, registered to the specified
- * class.
* A "dev" file will be created, showing the dev_t for the device, if
* the dev_t is not 0,0.
- * If a pointer to a parent struct device is passed in, the newly
- * created struct device will be a child of that device in sysfs. The
- * pointer to the struct device will be returned from the call. Any
- * further sysfs files that might be required can be created using this
+ * If a pointer to a parent struct device is passed in, the newly created
+ * struct device will be a child of that device in sysfs.
+ * The pointer to the struct device will be returned from the call.
+ * Any further sysfs files that might be required can be created using this
* pointer.
*
* Note: the struct class passed to this function must have previously
* been created with a call to class_create().
*/
struct device *device_create(struct class *class, struct device *parent,
- dev_t devt, char *fmt, ...)
+ dev_t devt, const char *fmt, ...)
{
va_list args;
struct device *dev = NULL;
@@ -588,10 +728,6 @@ struct device *device_create(struct class *class, struct device *parent,
if (class == NULL || IS_ERR(class))
goto error;
- if (parent == NULL) {
- printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__);
- goto error;
- }
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
@@ -621,11 +757,11 @@ EXPORT_SYMBOL_GPL(device_create);
/**
* device_destroy - removes a device that was created with device_create()
- * @class: the pointer to the struct class that this device was registered * with.
- * @dev: the dev_t of the device that was previously registered.
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
*
- * This call unregisters and cleans up a class device that was created with a
- * call to class_device_create()
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
*/
void device_destroy(struct class *class, dev_t devt)
{
@@ -645,3 +781,58 @@ void device_destroy(struct class *class, dev_t devt)
device_unregister(dev);
}
EXPORT_SYMBOL_GPL(device_destroy);
+
+/**
+ * device_rename - renames a device
+ * @dev: the pointer to the struct device to be renamed
+ * @new_name: the new name of the device
+ */
+int device_rename(struct device *dev, char *new_name)
+{
+ char *old_class_name = NULL;
+ char *new_class_name = NULL;
+ char *old_symlink_name = NULL;
+ int error;
+
+ dev = get_device(dev);
+ if (!dev)
+ return -EINVAL;
+
+ pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name);
+
+ if ((dev->class) && (dev->parent))
+ old_class_name = make_class_name(dev->class->name, &dev->kobj);
+
+ if (dev->class) {
+ old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
+ if (!old_symlink_name)
+ return -ENOMEM;
+ strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
+ }
+
+ strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
+
+ error = kobject_rename(&dev->kobj, new_name);
+
+ if (old_class_name) {
+ new_class_name = make_class_name(dev->class->name, &dev->kobj);
+ if (new_class_name) {
+ sysfs_create_link(&dev->parent->kobj, &dev->kobj,
+ new_class_name);
+ sysfs_remove_link(&dev->parent->kobj, old_class_name);
+ }
+ }
+ if (dev->class) {
+ sysfs_remove_link(&dev->class->subsys.kset.kobj,
+ old_symlink_name);
+ sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
+ dev->bus_id);
+ }
+ put_device(dev);
+
+ kfree(old_class_name);
+ kfree(new_class_name);
+ kfree(old_symlink_name);
+
+ return error;
+}
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index dd712b24ec9..4bef76a2f3f 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -8,6 +8,7 @@
#include <linux/cpu.h>
#include <linux/topology.h>
#include <linux/device.h>
+#include <linux/node.h>
#include "base.h"
@@ -57,13 +58,12 @@ static void __devinit register_cpu_control(struct cpu *cpu)
{
sysdev_create_file(&cpu->sysdev, &attr_online);
}
-void unregister_cpu(struct cpu *cpu, struct node *root)
+void unregister_cpu(struct cpu *cpu)
{
int logical_cpu = cpu->sysdev.id;
- if (root)
- sysfs_remove_link(&root->sysdev.kobj,
- kobject_name(&cpu->sysdev.kobj));
+ unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));
+
sysdev_remove_file(&cpu->sysdev, &attr_online);
sysdev_unregister(&cpu->sysdev);
@@ -109,23 +109,21 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL);
*
* Initialize and register the CPU device.
*/
-int __devinit register_cpu(struct cpu *cpu, int num, struct node *root)
+int __devinit register_cpu(struct cpu *cpu, int num)
{
int error;
-
cpu->node_id = cpu_to_node(num);
cpu->sysdev.id = num;
cpu->sysdev.cls = &cpu_sysdev_class;
error = sysdev_register(&cpu->sysdev);
- if (!error && root)
- error = sysfs_create_link(&root->sysdev.kobj,
- &cpu->sysdev.kobj,
- kobject_name(&cpu->sysdev.kobj));
+
if (!error && !cpu->no_control)
register_cpu_control(cpu);
if (!error)
cpu_sys_devices[num] = &cpu->sysdev;
+ if (!error)
+ register_cpu_under_node(num, cpu_to_node(num));
#ifdef CONFIG_KEXEC
if (!error)
@@ -145,5 +143,13 @@ EXPORT_SYMBOL_GPL(get_cpu_sysdev);
int __init cpu_dev_init(void)
{
- return sysdev_class_register(&cpu_sysdev_class);
+ int err;
+
+ err = sysdev_class_register(&cpu_sysdev_class);
+#if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT)
+ if (!err)
+ err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class);
+#endif
+
+ return err;
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 889c7111123..b5f43c3e44f 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -17,6 +17,7 @@
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/kthread.h>
#include "base.h"
#include "power/power.h"
@@ -38,66 +39,73 @@
*
* This function must be called with @dev->sem held.
*/
-void device_bind_driver(struct device * dev)
+int device_bind_driver(struct device *dev)
{
- if (klist_node_attached(&dev->knode_driver))
- return;
+ int ret;
+
+ if (klist_node_attached(&dev->knode_driver)) {
+ printk(KERN_WARNING "%s: device %s already bound\n",
+ __FUNCTION__, kobject_name(&dev->kobj));
+ return 0;
+ }
pr_debug("bound device '%s' to driver '%s'\n",
dev->bus_id, dev->driver->name);
klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
- sysfs_create_link(&dev->driver->kobj, &dev->kobj,
+ ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
kobject_name(&dev->kobj));
- sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver");
+ if (ret == 0) {
+ ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj,
+ "driver");
+ if (ret)
+ sysfs_remove_link(&dev->driver->kobj,
+ kobject_name(&dev->kobj));
+ }
+ return ret;
}
-/**
- * driver_probe_device - attempt to bind device & driver.
- * @drv: driver.
- * @dev: device.
- *
- * First, we call the bus's match function, if one present, which
- * should compare the device IDs the driver supports with the
- * device IDs of the device. Note we don't do this ourselves
- * because we don't know the format of the ID structures, nor what
- * is to be considered a match and what is not.
- *
- * This function returns 1 if a match is found, an error if one
- * occurs (that is not -ENODEV or -ENXIO), and 0 otherwise.
- *
- * This function must be called with @dev->sem held. When called
- * for a USB interface, @dev->parent->sem must be held as well.
- */
-int driver_probe_device(struct device_driver * drv, struct device * dev)
+struct stupid_thread_structure {
+ struct device_driver *drv;
+ struct device *dev;
+};
+
+static atomic_t probe_count = ATOMIC_INIT(0);
+static int really_probe(void *void_data)
{
+ struct stupid_thread_structure *data = void_data;
+ struct device_driver *drv = data->drv;
+ struct device *dev = data->dev;
int ret = 0;
- if (drv->bus->match && !drv->bus->match(dev, drv))
- goto Done;
+ atomic_inc(&probe_count);
+ pr_debug("%s: Probing driver %s with device %s\n",
+ drv->bus->name, drv->name, dev->bus_id);
- pr_debug("%s: Matched Device %s with Driver %s\n",
- drv->bus->name, dev->bus_id, drv->name);
dev->driver = drv;
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret) {
dev->driver = NULL;
- goto ProbeFailed;
+ goto probe_failed;
}
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret) {
dev->driver = NULL;
- goto ProbeFailed;
+ goto probe_failed;
}
}
- device_bind_driver(dev);
+ if (device_bind_driver(dev)) {
+ printk(KERN_ERR "%s: device_bind_driver(%s) failed\n",
+ __FUNCTION__, dev->bus_id);
+ /* How does undo a ->probe? We're screwed. */
+ }
ret = 1;
pr_debug("%s: Bound Device %s to Driver %s\n",
drv->bus->name, dev->bus_id, drv->name);
- goto Done;
+ goto done;
- ProbeFailed:
+probe_failed:
if (ret == -ENODEV || ret == -ENXIO) {
/* Driver matched, but didn't support device
* or device not found.
@@ -110,7 +118,71 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
"%s: probe of %s failed with error %d\n",
drv->name, dev->bus_id, ret);
}
- Done:
+done:
+ kfree(data);
+ atomic_dec(&probe_count);
+ return ret;
+}
+
+/**
+ * driver_probe_done
+ * Determine if the probe sequence is finished or not.
+ *
+ * Should somehow figure out how to use a semaphore, not an atomic variable...
+ */
+int driver_probe_done(void)
+{
+ pr_debug("%s: probe_count = %d\n", __FUNCTION__,
+ atomic_read(&probe_count));
+ if (atomic_read(&probe_count))
+ return -EBUSY;
+ return 0;
+}
+
+/**
+ * driver_probe_device - attempt to bind device & driver together
+ * @drv: driver to bind a device to
+ * @dev: device to try to bind to the driver
+ *
+ * First, we call the bus's match function, if one present, which should
+ * compare the device IDs the driver supports with the device IDs of the
+ * device. Note we don't do this ourselves because we don't know the
+ * format of the ID structures, nor what is to be considered a match and
+ * what is not.
+ *
+ * This function returns 1 if a match is found, an error if one occurs
+ * (that is not -ENODEV or -ENXIO), and 0 otherwise.
+ *
+ * This function must be called with @dev->sem held. When called for a
+ * USB interface, @dev->parent->sem must be held as well.
+ */
+int driver_probe_device(struct device_driver * drv, struct device * dev)
+{
+ struct stupid_thread_structure *data;
+ struct task_struct *probe_task;
+ int ret = 0;
+
+ if (!device_is_registered(dev))
+ return -ENODEV;
+ if (drv->bus->match && !drv->bus->match(dev, drv))
+ goto done;
+
+ pr_debug("%s: Matched Device %s with Driver %s\n",
+ drv->bus->name, dev->bus_id, drv->name);
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ data->drv = drv;
+ data->dev = dev;
+
+ if (drv->multithread_probe) {
+ probe_task = kthread_run(really_probe, data,
+ "probe-%s", dev->bus_id);
+ if (IS_ERR(probe_task))
+ ret = PTR_ERR(probe_task);
+ } else
+ ret = really_probe(data);
+
+done:
return ret;
}
@@ -139,8 +211,9 @@ int device_attach(struct device * dev)
down(&dev->sem);
if (dev->driver) {
- device_bind_driver(dev);
- ret = 1;
+ ret = device_bind_driver(dev);
+ if (ret == 0)
+ ret = 1;
} else
ret = bus_for_each_drv(dev->bus, NULL, dev, __device_attach);
up(&dev->sem);
@@ -182,9 +255,9 @@ static int __driver_attach(struct device * dev, void * data)
* returns 0 and the @dev->driver is set, we've found a
* compatible pair.
*/
-void driver_attach(struct device_driver * drv)
+int driver_attach(struct device_driver * drv)
{
- bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
+ return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
}
/**
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index e2f64f91ed0..33c5cce1560 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -7,6 +7,7 @@
#include <linux/dmapool.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/poison.h>
/*
* Pool allocator ... wraps the dma_alloc_coherent page allocator, so
@@ -35,8 +36,6 @@ struct dma_page { /* cacheable header for 'allocation' bytes */
};
#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000)
-#define POOL_POISON_FREED 0xa7 /* !inuse */
-#define POOL_POISON_ALLOCATED 0xa9 /* !initted */
static DECLARE_MUTEX (pools_lock);
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index b400314e1c6..1214cbd17d8 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -143,20 +142,6 @@ void put_driver(struct device_driver * drv)
kobject_put(&drv->kobj);
}
-static void klist_devices_get(struct klist_node *n)
-{
- struct device *dev = container_of(n, struct device, knode_driver);
-
- get_device(dev);
-}
-
-static void klist_devices_put(struct klist_node *n)
-{
- struct device *dev = container_of(n, struct device, knode_driver);
-
- put_device(dev);
-}
-
/**
* driver_register - register driver with bus
* @drv: driver to register
@@ -176,7 +161,7 @@ int driver_register(struct device_driver * drv)
(drv->bus->shutdown && drv->shutdown)) {
printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);
}
- klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put);
+ klist_init(&drv->klist_devices, NULL, NULL);
init_completion(&drv->unloaded);
return bus_add_driver(drv);
}
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5d6c011183f..14615694ae9 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <linux/kthread.h>
#include <linux/firmware.h>
#include "base.h"
@@ -511,7 +512,6 @@ request_firmware_work_func(void *arg)
WARN_ON(1);
return 0;
}
- daemonize("%s/%s", "firmware", fw_work->name);
ret = _request_firmware(&fw, fw_work->name, fw_work->device,
fw_work->uevent);
if (ret < 0)
@@ -546,9 +546,9 @@ request_firmware_nowait(
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context))
{
+ struct task_struct *task;
struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
GFP_ATOMIC);
- int ret;
if (!fw_work)
return -ENOMEM;
@@ -566,14 +566,14 @@ request_firmware_nowait(
.uevent = uevent,
};
- ret = kernel_thread(request_firmware_work_func, fw_work,
- CLONE_FS | CLONE_FILES);
+ task = kthread_run(request_firmware_work_func, fw_work,
+ "firmware/%s", name);
- if (ret < 0) {
+ if (IS_ERR(task)) {
fw_work->cont(NULL, fw_work->context);
module_put(fw_work->module);
kfree(fw_work);
- return ret;
+ return PTR_ERR(task);
}
return 0;
}
@@ -602,7 +602,7 @@ firmware_class_exit(void)
class_unregister(&firmware_class);
}
-module_init(firmware_class_init);
+fs_initcall(firmware_class_init);
module_exit(firmware_class_exit);
EXPORT_SYMBOL(release_firmware);
diff --git a/drivers/base/hypervisor.c b/drivers/base/hypervisor.c
index 0c85e9d6a44..7080b413ddc 100644
--- a/drivers/base/hypervisor.c
+++ b/drivers/base/hypervisor.c
@@ -1,8 +1,9 @@
/*
* hypervisor.c - /sys/hypervisor subsystem.
*
- * This file is released under the GPLv2
+ * Copyright (C) IBM Corp. 2006
*
+ * This file is released under the GPLv2
*/
#include <linux/kobject.h>
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index dd547af4681..c6b7d9c4b65 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -306,11 +306,13 @@ static ssize_t
memory_probe_store(struct class *class, const char *buf, size_t count)
{
u64 phys_addr;
+ int nid;
int ret;
phys_addr = simple_strtoull(buf, NULL, 0);
- ret = add_memory(phys_addr, PAGES_PER_SECTION << PAGE_SHIFT);
+ nid = memory_add_physaddr_to_nid(phys_addr);
+ ret = add_memory(nid, phys_addr, PAGES_PER_SECTION << PAGE_SHIFT);
if (ret)
count = ret;
diff --git a/drivers/base/node.c b/drivers/base/node.c
index c80c3aeed00..001e6f6b9c1 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -11,6 +11,7 @@
#include <linux/cpumask.h>
#include <linux/topology.h>
#include <linux/nodemask.h>
+#include <linux/cpu.h>
static struct sysdev_class node_class = {
set_kset_name("node"),
@@ -39,24 +40,13 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
int n;
int nid = dev->id;
struct sysinfo i;
- struct page_state ps;
unsigned long inactive;
unsigned long active;
unsigned long free;
si_meminfo_node(&i, nid);
- get_page_state_node(&ps, nid);
__get_zone_counts(&active, &inactive, &free, NODE_DATA(nid));
- /* Check for negative values in these approximate counters */
- if ((long)ps.nr_dirty < 0)
- ps.nr_dirty = 0;
- if ((long)ps.nr_writeback < 0)
- ps.nr_writeback = 0;
- if ((long)ps.nr_mapped < 0)
- ps.nr_mapped = 0;
- if ((long)ps.nr_slab < 0)
- ps.nr_slab = 0;
n = sprintf(buf, "\n"
"Node %d MemTotal: %8lu kB\n"
@@ -64,27 +54,46 @@ static ssize_t node_read_meminfo(struct sys_device * dev, char * buf)
"Node %d MemUsed: %8lu kB\n"
"Node %d Active: %8lu kB\n"
"Node %d Inactive: %8lu kB\n"
+#ifdef CONFIG_HIGHMEM
"Node %d HighTotal: %8lu kB\n"
"Node %d HighFree: %8lu kB\n"
"Node %d LowTotal: %8lu kB\n"
"Node %d LowFree: %8lu kB\n"
+#endif
"Node %d Dirty: %8lu kB\n"
"Node %d Writeback: %8lu kB\n"
+ "Node %d FilePages: %8lu kB\n"
"Node %d Mapped: %8lu kB\n"
- "Node %d Slab: %8lu kB\n",
+ "Node %d AnonPages: %8lu kB\n"
+ "Node %d PageTables: %8lu kB\n"
+ "Node %d NFS_Unstable: %8lu kB\n"
+ "Node %d Bounce: %8lu kB\n"
+ "Node %d Slab: %8lu kB\n"
+ "Node %d SReclaimable: %8lu kB\n"
+ "Node %d SUnreclaim: %8lu kB\n",
nid, K(i.totalram),
nid, K(i.freeram),
nid, K(i.totalram - i.freeram),
nid, K(active),
nid, K(inactive),
+#ifdef CONFIG_HIGHMEM
nid, K(i.totalhigh),
nid, K(i.freehigh),
nid, K(i.totalram - i.totalhigh),
nid, K(i.freeram - i.freehigh),
- nid, K(ps.nr_dirty),
- nid, K(ps.nr_writeback),
- nid, K(ps.nr_mapped),
- nid, K(ps.nr_slab));
+#endif
+ nid, K(node_page_state(nid, NR_FILE_DIRTY)),
+ nid, K(node_page_state(nid, NR_WRITEBACK)),
+ nid, K(node_page_state(nid, NR_FILE_PAGES)),
+ nid, K(node_page_state(nid, NR_FILE_MAPPED)),
+ nid, K(node_page_state(nid, NR_ANON_PAGES)),
+ nid, K(node_page_state(nid, NR_PAGETABLE)),
+ nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
+ nid, K(node_page_state(nid, NR_BOUNCE)),
+ nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
+ node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
+ nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
+ nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)));
n += hugetlb_report_node_meminfo(nid, buf + n);
return n;
}
@@ -94,28 +103,6 @@ static SYSDEV_ATTR(meminfo, S_IRUGO, node_read_meminfo, NULL);
static ssize_t node_read_numastat(struct sys_device * dev, char * buf)
{
- unsigned long numa_hit, numa_miss, interleave_hit, numa_foreign;
- unsigned long local_node, other_node;
- int i, cpu;
- pg_data_t *pg = NODE_DATA(dev->id);
- numa_hit = 0;
- numa_miss = 0;
- interleave_hit = 0;
- numa_foreign = 0;
- local_node = 0;
- other_node = 0;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- struct zone *z = &pg->node_zones[i];
- for_each_online_cpu(cpu) {
- struct per_cpu_pageset *ps = zone_pcp(z,cpu);
- numa_hit += ps->numa_hit;
- numa_miss += ps->numa_miss;
- numa_foreign += ps->numa_foreign;
- interleave_hit += ps->interleave_hit;
- local_node += ps->local_node;
- other_node += ps->other_node;
- }
- }
return sprintf(buf,
"numa_hit %lu\n"
"numa_miss %lu\n"
@@ -123,12 +110,12 @@ static ssize_t node_read_numastat(struct sys_device * dev, char * buf)
"interleave_hit %lu\n"
"local_node %lu\n"
"other_node %lu\n",
- numa_hit,
- numa_miss,
- numa_foreign,
- interleave_hit,
- local_node,
- other_node);
+ node_page_state(dev->id, NUMA_HIT),
+ node_page_state(dev->id, NUMA_MISS),
+ node_page_state(dev->id, NUMA_FOREIGN),
+ node_page_state(dev->id, NUMA_INTERLEAVE_HIT),
+ node_page_state(dev->id, NUMA_LOCAL),
+ node_page_state(dev->id, NUMA_OTHER));
}
static SYSDEV_ATTR(numastat, S_IRUGO, node_read_numastat, NULL);
@@ -190,6 +177,66 @@ void unregister_node(struct node *node)
sysdev_unregister(&node->sysdev);
}
+struct node node_devices[MAX_NUMNODES];
+
+/*
+ * register cpu under node
+ */
+int register_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+ if (node_online(nid)) {
+ struct sys_device *obj = get_cpu_sysdev(cpu);
+ if (!obj)
+ return 0;
+ return sysfs_create_link(&node_devices[nid].sysdev.kobj,
+ &obj->kobj,
+ kobject_name(&obj->kobj));
+ }
+
+ return 0;
+}
+
+int unregister_cpu_under_node(unsigned int cpu, unsigned int nid)
+{
+ if (node_online(nid)) {
+ struct sys_device *obj = get_cpu_sysdev(cpu);
+ if (obj)
+ sysfs_remove_link(&node_devices[nid].sysdev.kobj,
+ kobject_name(&obj->kobj));
+ }
+ return 0;
+}
+
+int register_one_node(int nid)
+{
+ int error = 0;
+ int cpu;
+
+ if (node_online(nid)) {
+ int p_node = parent_node(nid);
+ struct node *parent = NULL;
+
+ if (p_node != nid)
+ parent = &node_devices[p_node];
+
+ error = register_node(&node_devices[nid], nid, parent);
+
+ /* link cpu under this node */
+ for_each_present_cpu(cpu) {
+ if (cpu_to_node(cpu) == nid)
+ register_cpu_under_node(cpu, nid);
+ }
+ }
+
+ return error;
+
+}
+
+void unregister_one_node(int nid)
+{
+ unregister_node(&node_devices[nid]);
+}
+
static int __init register_node_type(void)
{
return sysdev_class_register(&node_class);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 2b8755db76c..940ce41f188 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -505,12 +505,36 @@ static int platform_match(struct device * dev, struct device_driver * drv)
return (strncmp(pdev->name, drv->name, BUS_ID_SIZE) == 0);
}
-static int platform_suspend(struct device * dev, pm_message_t state)
+static int platform_suspend(struct device *dev, pm_message_t mesg)
{
int ret = 0;
if (dev->driver && dev->driver->suspend)
- ret = dev->driver->suspend(dev, state);
+ ret = dev->driver->suspend(dev, mesg);
+
+ return ret;
+}
+
+static int platform_suspend_late(struct device *dev, pm_message_t mesg)
+{
+ struct platform_driver *drv = to_platform_driver(dev->driver);
+ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+ int ret = 0;
+
+ if (dev->driver && drv->suspend_late)
+ ret = drv->suspend_late(pdev, mesg);
+
+ return ret;
+}
+
+static int platform_resume_early(struct device *dev)
+{
+ struct platform_driver *drv = to_platform_driver(dev->driver);
+ struct platform_device *pdev = container_of(dev, struct platform_device, dev);
+ int ret = 0;
+
+ if (dev->driver && drv->resume_early)
+ ret = drv->resume_early(pdev);
return ret;
}
@@ -531,6 +555,8 @@ struct bus_type platform_bus_type = {
.match = platform_match,
.uevent = platform_uevent,
.suspend = platform_suspend,
+ .suspend_late = platform_suspend_late,
+ .resume_early = platform_resume_early,
.resume = platform_resume,
};
EXPORT_SYMBOL_GPL(platform_bus_type);
diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile
index ceeeba2c56c..91f230939c1 100644
--- a/drivers/base/power/Makefile
+++ b/drivers/base/power/Makefile
@@ -1,5 +1,6 @@
obj-y := shutdown.o
obj-$(CONFIG_PM) += main.o suspend.o resume.o runtime.o sysfs.o
+obj-$(CONFIG_PM_TRACE) += trace.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 0d2e101e4f1..fdfa3d0cf6a 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -19,7 +19,6 @@
* ancestral dependencies that the subsystem list maintains.
*/
-#include <linux/config.h>
#include <linux/device.h>
#include "power.h"
diff --git a/drivers/base/power/resume.c b/drivers/base/power/resume.c
index 317edbf0fec..020be36705a 100644
--- a/drivers/base/power/resume.c
+++ b/drivers/base/power/resume.c
@@ -9,6 +9,7 @@
*/
#include <linux/device.h>
+#include <linux/resume-trace.h>
#include "../base.h"
#include "power.h"
@@ -23,6 +24,8 @@ int resume_device(struct device * dev)
{
int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
down(&dev->sem);
if (dev->power.pm_parent
&& dev->power.pm_parent->power.power_state.event) {
@@ -35,12 +38,35 @@ int resume_device(struct device * dev)
dev_dbg(dev,"resuming\n");
error = dev->bus->resume(dev);
}
+ if (dev->class && dev->class->resume) {
+ dev_dbg(dev,"class resume\n");
+ error = dev->class->resume(dev);
+ }
up(&dev->sem);
+ TRACE_RESUME(error);
return error;
}
+static int resume_device_early(struct device * dev)
+{
+ int error = 0;
+ TRACE_DEVICE(dev);
+ TRACE_RESUME(0);
+ if (dev->bus && dev->bus->resume_early) {
+ dev_dbg(dev,"EARLY resume\n");
+ error = dev->bus->resume_early(dev);
+ }
+ TRACE_RESUME(error);
+ return error;
+}
+
+/*
+ * Resume the devices that have either not gone through
+ * the late suspend, or that did go through it but also
+ * went through the early resume
+ */
void dpm_resume(void)
{
down(&dpm_list_sem);
@@ -49,8 +75,7 @@ void dpm_resume(void)
struct device * dev = to_device(entry);
get_device(dev);
- list_del_init(entry);
- list_add_tail(entry, &dpm_active);
+ list_move_tail(entry, &dpm_active);
up(&dpm_list_sem);
if (!dev->power.prev_state.event)
@@ -71,6 +96,7 @@ void dpm_resume(void)
void device_resume(void)
{
+ might_sleep();
down(&dpm_sem);
dpm_resume();
up(&dpm_sem);
@@ -80,12 +106,12 @@ EXPORT_SYMBOL_GPL(device_resume);
/**
- * device_power_up_irq - Power on some devices.
+ * dpm_power_up - Power on some devices.
*
* Walk the dpm_off_irq list and power each device up. This
* is used for devices that required they be powered down with
- * interrupts disabled. As devices are powered on, they are moved to
- * the dpm_suspended list.
+ * interrupts disabled. As devices are powered on, they are moved
+ * to the dpm_active list.
*
* Interrupts must be disabled when calling this.
*/
@@ -96,17 +122,14 @@ void dpm_power_up(void)
struct list_head * entry = dpm_off_irq.next;
struct device * dev = to_device(entry);
- get_device(dev);
- list_del_init(entry);
- list_add_tail(entry, &dpm_active);
- resume_device(dev);
- put_device(dev);
+ list_move_tail(entry, &dpm_off);
+ resume_device_early(dev);
}
}
/**
- * device_pm_power_up - Turn on all devices that need special attention.
+ * device_power_up - Turn on all devices that need special attention.
*
* Power on system devices then devices that required we shut them down
* with interrupts disabled.
diff --git a/drivers/base/power/shutdown.c b/drivers/base/power/shutdown.c
index 8826a5b6673..3483ae4d57f 100644
--- a/drivers/base/power/shutdown.c
+++ b/drivers/base/power/shutdown.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <asm/semaphore.h>
diff --git a/drivers/base/power/suspend.c b/drivers/base/power/suspend.c
index 1a1fe43a305..ece136bf97e 100644
--- a/drivers/base/power/suspend.c
+++ b/drivers/base/power/suspend.c
@@ -34,6 +34,7 @@ static inline char *suspend_verb(u32 event)
switch (event) {
case PM_EVENT_SUSPEND: return "suspend";
case PM_EVENT_FREEZE: return "freeze";
+ case PM_EVENT_PRETHAW: return "prethaw";
default: return "(unknown suspend event)";
}
}
@@ -65,7 +66,19 @@ int suspend_device(struct device * dev, pm_message_t state)
dev->power.prev_state = dev->power.power_state;
- if (dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
+ if (dev->class && dev->class->suspend && !dev->power.power_state.event) {
+ dev_dbg(dev, "class %s%s\n",
+ suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND)
+ && device_may_wakeup(dev))
+ ? ", may wakeup"
+ : ""
+ );
+ error = dev->class->suspend(dev, state);
+ suspend_report_result(dev->class->suspend, error);
+ }
+
+ if (!error && dev->bus && dev->bus->suspend && !dev->power.power_state.event) {
dev_dbg(dev, "%s%s\n",
suspend_verb(state.event),
((state.event == PM_EVENT_SUSPEND)
@@ -81,15 +94,42 @@ int suspend_device(struct device * dev, pm_message_t state)
}
+/*
+ * This is called with interrupts off, only a single CPU
+ * running. We can't do down() on a semaphore (and we don't
+ * need the protection)
+ */
+static int suspend_device_late(struct device *dev, pm_message_t state)
+{
+ int error = 0;
+
+ if (dev->bus && dev->bus->suspend_late && !dev->power.power_state.event) {
+ dev_dbg(dev, "LATE %s%s\n",
+ suspend_verb(state.event),
+ ((state.event == PM_EVENT_SUSPEND)
+ && device_may_wakeup(dev))
+ ? ", may wakeup"
+ : ""
+ );
+ error = dev->bus->suspend_late(dev, state);
+ suspend_report_result(dev->bus->suspend_late, error);
+ }
+ return error;
+}
+
/**
* device_suspend - Save state and stop all devices in system.
* @state: Power state to put each device in.
*
* Walk the dpm_active list, call ->suspend() for each device, and move
- * it to dpm_off.
- * Check the return value for each. If it returns 0, then we move the
- * the device to the dpm_off list. If it returns -EAGAIN, we move it to
- * the dpm_off_irq list. If we get a different error, try and back out.
+ * it to the dpm_off list.
+ *
+ * (For historical reasons, if it returns -EAGAIN, that used to mean
+ * that the device would be called again with interrupts disabled.
+ * These days, we use the "suspend_late()" callback for that, so we
+ * print a warning and consider it an error).
+ *
+ * If we get a different error, try and back out.
*
* If we hit a failure with any of the devices, call device_resume()
* above to bring the suspended devices back to life.
@@ -100,6 +140,7 @@ int device_suspend(pm_message_t state)
{
int error = 0;
+ might_sleep();
down(&dpm_sem);
down(&dpm_list_sem);
while (!list_empty(&dpm_active) && error == 0) {
@@ -115,42 +156,27 @@ int device_suspend(pm_message_t state)
/* Check if the device got removed */
if (!list_empty(&dev->power.entry)) {
- /* Move it to the dpm_off or dpm_off_irq list */
- if (!error) {
- list_del(&dev->power.entry);
- list_add(&dev->power.entry, &dpm_off);
- } else if (error == -EAGAIN) {
- list_del(&dev->power.entry);
- list_add(&dev->power.entry, &dpm_off_irq);
- error = 0;
- }
+ /* Move it to the dpm_off list */
+ if (!error)
+ list_move(&dev->power.entry, &dpm_off);
}
if (error)
printk(KERN_ERR "Could not suspend device %s: "
- "error %d\n", kobject_name(&dev->kobj), error);
+ "error %d%s\n",
+ kobject_name(&dev->kobj), error,
+ error == -EAGAIN ? " (please convert to suspend_late)" : "");
put_device(dev);
}
up(&dpm_list_sem);
- if (error) {
- /* we failed... before resuming, bring back devices from
- * dpm_off_irq list back to main dpm_off list, we do want
- * to call resume() on them, in case they partially suspended
- * despite returning -EAGAIN
- */
- while (!list_empty(&dpm_off_irq)) {
- struct list_head * entry = dpm_off_irq.next;
- list_del(entry);
- list_add(entry, &dpm_off);
- }
+ if (error)
dpm_resume();
- }
+
up(&dpm_sem);
return error;
}
EXPORT_SYMBOL_GPL(device_suspend);
-
/**
* device_power_down - Shut down special devices.
* @state: Power state to enter.
@@ -165,14 +191,17 @@ int device_power_down(pm_message_t state)
int error = 0;
struct device * dev;
- list_for_each_entry_reverse(dev, &dpm_off_irq, power.entry) {
- if ((error = suspend_device(dev, state)))
- break;
+ while (!list_empty(&dpm_off)) {
+ struct list_head * entry = dpm_off.prev;
+
+ dev = to_device(entry);
+ error = suspend_device_late(dev, state);
+ if (error)
+ goto Error;
+ list_move(&dev->power.entry, &dpm_off_irq);
}
- if (error)
- goto Error;
- if ((error = sysdev_suspend(state)))
- goto Error;
+
+ error = sysdev_suspend(state);
Done:
return error;
Error:
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 40d7242a07c..2d47517dbe3 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -7,22 +7,29 @@
#include "power.h"
+#ifdef CONFIG_PM_SYSFS_DEPRECATED
+
/**
* state - Control current power state of device
*
* show() returns the current power state of the device. '0' indicates
- * the device is on. Other values (1-3) indicate the device is in a low
+ * the device is on. Other values (2) indicate the device is in some low
* power state.
*
- * store() sets the current power state, which is an integer value
- * between 0-3. If the device is on ('0'), and the value written is
- * greater than 0, then the device is placed directly into the low-power
- * state (via its driver's ->suspend() method).
- * If the device is currently in a low-power state, and the value is 0,
- * the device is powered back on (via the ->resume() method).
- * If the device is in a low-power state, and a different low-power state
- * is requested, the device is first resumed, then suspended into the new
- * low-power state.
+ * store() sets the current power state, which is an integer valued
+ * 0, 2, or 3. Devices with bus.suspend_late(), or bus.resume_early()
+ * methods fail this operation; those methods couldn't be called.
+ * Otherwise,
+ *
+ * - If the recorded dev->power.power_state.event matches the
+ * target value, nothing is done.
+ * - If the recorded event code is nonzero, the device is reactivated
+ * by calling bus.resume() and/or class.resume().
+ * - If the target value is nonzero, the device is suspended by
+ * calling class.suspend() and/or bus.suspend() with event code
+ * PM_EVENT_SUSPEND.
+ *
+ * This mechanism is DEPRECATED and should only be used for testing.
*/
static ssize_t state_show(struct device * dev, struct device_attribute *attr, char * buf)
@@ -38,6 +45,10 @@ static ssize_t state_store(struct device * dev, struct device_attribute *attr, c
pm_message_t state;
int error = -EINVAL;
+ /* disallow incomplete suspend sequences */
+ if (dev->bus && (dev->bus->suspend_late || dev->bus->resume_early))
+ return error;
+
state.event = PM_EVENT_SUSPEND;
/* Older apps expected to write "3" here - confused with PCI D3 */
if ((n == 1) && !strcmp(buf, "3"))
@@ -57,6 +68,8 @@ static ssize_t state_store(struct device * dev, struct device_attribute *attr, c
static DEVICE_ATTR(state, 0644, state_show, state_store);
+#endif /* CONFIG_PM_SYSFS_DEPRECATED */
+
/*
* wakeup - Report/change current wakeup option for device
*
@@ -130,7 +143,9 @@ static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
static struct attribute * power_attrs[] = {
+#ifdef CONFIG_PM_SYSFS_DEPRECATED
&dev_attr_state.attr,
+#endif
&dev_attr_wakeup.attr,
NULL,
};
diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c
new file mode 100644
index 00000000000..a9ab30fefff
--- /dev/null
+++ b/drivers/base/power/trace.c
@@ -0,0 +1,228 @@
+/*
+ * drivers/base/power/trace.c
+ *
+ * Copyright (C) 2006 Linus Torvalds
+ *
+ * Trace facility for suspend/resume problems, when none of the
+ * devices may be working.
+ */
+
+#include <linux/resume-trace.h>
+#include <linux/rtc.h>
+
+#include <asm/rtc.h>
+
+#include "power.h"
+
+/*
+ * Horrid, horrid, horrid.
+ *
+ * It turns out that the _only_ piece of hardware that actually
+ * keeps its value across a hard boot (and, more importantly, the
+ * POST init sequence) is literally the realtime clock.
+ *
+ * Never mind that an RTC chip has 114 bytes (and often a whole
+ * other bank of an additional 128 bytes) of nice SRAM that is
+ * _designed_ to keep data - the POST will clear it. So we literally
+ * can just use the few bytes of actual time data, which means that
+ * we're really limited.
+ *
+ * It means, for example, that we can't use the seconds at all
+ * (since the time between the hang and the boot might be more
+ * than a minute), and we'd better not depend on the low bits of
+ * the minutes either.
+ *
+ * There are the wday fields etc, but I wouldn't guarantee those
+ * are dependable either. And if the date isn't valid, either the
+ * hw or POST will do strange things.
+ *
+ * So we're left with:
+ * - year: 0-99
+ * - month: 0-11
+ * - day-of-month: 1-28
+ * - hour: 0-23
+ * - min: (0-30)*2
+ *
+ * Giving us a total range of 0-16128000 (0xf61800), ie less
+ * than 24 bits of actual data we can save across reboots.
+ *
+ * And if your box can't boot in less than three minutes,
+ * you're screwed.
+ *
+ * Now, almost 24 bits of data is pitifully small, so we need
+ * to be pretty dense if we want to use it for anything nice.
+ * What we do is that instead of saving off nice readable info,
+ * we save off _hashes_ of information that we can hopefully
+ * regenerate after the reboot.
+ *
+ * In particular, this means that we might be unlucky, and hit
+ * a case where we have a hash collision, and we end up not
+ * being able to tell for certain exactly which case happened.
+ * But that's hopefully unlikely.
+ *
+ * What we do is to take the bits we can fit, and split them
+ * into three parts (16*997*1009 = 16095568), and use the values
+ * for:
+ * - 0-15: user-settable
+ * - 0-996: file + line number
+ * - 0-1008: device
+ */
+#define USERHASH (16)
+#define FILEHASH (997)
+#define DEVHASH (1009)
+
+#define DEVSEED (7919)
+
+static unsigned int dev_hash_value;
+
+static int set_magic_time(unsigned int user, unsigned int file, unsigned int device)
+{
+ unsigned int n = user + USERHASH*(file + FILEHASH*device);
+
+ // June 7th, 2006
+ static struct rtc_time time = {
+ .tm_sec = 0,
+ .tm_min = 0,
+ .tm_hour = 0,
+ .tm_mday = 7,
+ .tm_mon = 5, // June - counting from zero
+ .tm_year = 106,
+ .tm_wday = 3,
+ .tm_yday = 160,
+ .tm_isdst = 1
+ };
+
+ time.tm_year = (n % 100);
+ n /= 100;
+ time.tm_mon = (n % 12);
+ n /= 12;
+ time.tm_mday = (n % 28) + 1;
+ n /= 28;
+ time.tm_hour = (n % 24);
+ n /= 24;
+ time.tm_min = (n % 20) * 3;
+ n /= 20;
+ set_rtc_time(&time);
+ return n ? -1 : 0;
+}
+
+static unsigned int read_magic_time(void)
+{
+ struct rtc_time time;
+ unsigned int val;
+
+ get_rtc_time(&time);
+ printk("Time: %2d:%02d:%02d Date: %02d/%02d/%02d\n",
+ time.tm_hour, time.tm_min, time.tm_sec,
+ time.tm_mon, time.tm_mday, time.tm_year);
+ val = time.tm_year; /* 100 years */
+ if (val > 100)
+ val -= 100;
+ val += time.tm_mon * 100; /* 12 months */
+ val += (time.tm_mday-1) * 100 * 12; /* 28 month-days */
+ val += time.tm_hour * 100 * 12 * 28; /* 24 hours */
+ val += (time.tm_min / 3) * 100 * 12 * 28 * 24; /* 20 3-minute intervals */
+ return val;
+}
+
+/*
+ * This is just the sdbm hash function with a user-supplied
+ * seed and final size parameter.
+ */
+static unsigned int hash_string(unsigned int seed, const char *data, unsigned int mod)
+{
+ unsigned char c;
+ while ((c = *data++) != 0) {
+ seed = (seed << 16) + (seed << 6) - seed + c;
+ }
+ return seed % mod;
+}
+
+void set_trace_device(struct device *dev)
+{
+ dev_hash_value = hash_string(DEVSEED, dev->bus_id, DEVHASH);
+}
+
+/*
+ * We could just take the "tracedata" index into the .tracedata
+ * section instead. Generating a hash of the data gives us a
+ * chance to work across kernel versions, and perhaps more
+ * importantly it also gives us valid/invalid check (ie we will
+ * likely not give totally bogus reports - if the hash matches,
+ * it's not any guarantee, but it's a high _likelihood_ that
+ * the match is valid).
+ */
+void generate_resume_trace(void *tracedata, unsigned int user)
+{
+ unsigned short lineno = *(unsigned short *)tracedata;
+ const char *file = *(const char **)(tracedata + 2);
+ unsigned int user_hash_value, file_hash_value;
+
+ user_hash_value = user % USERHASH;
+ file_hash_value = hash_string(lineno, file, FILEHASH);
+ set_magic_time(user_hash_value, file_hash_value, dev_hash_value);
+}
+
+extern char __tracedata_start, __tracedata_end;
+static int show_file_hash(unsigned int value)
+{
+ int match;
+ char *tracedata;
+
+ match = 0;
+ for (tracedata = &__tracedata_start ; tracedata < &__tracedata_end ; tracedata += 6) {
+ unsigned short lineno = *(unsigned short *)tracedata;
+ const char *file = *(const char **)(tracedata + 2);
+ unsigned int hash = hash_string(lineno, file, FILEHASH);
+ if (hash != value)
+ continue;
+ printk(" hash matches %s:%u\n", file, lineno);
+ match++;
+ }
+ return match;
+}
+
+static int show_dev_hash(unsigned int value)
+{
+ int match = 0;
+ struct list_head * entry = dpm_active.prev;
+
+ while (entry != &dpm_active) {
+ struct device * dev = to_device(entry);
+ unsigned int hash = hash_string(DEVSEED, dev->bus_id, DEVHASH);
+ if (hash == value) {
+ printk(" hash matches device %s\n", dev->bus_id);
+ match++;
+ }
+ entry = entry->prev;
+ }
+ return match;
+}
+
+static unsigned int hash_value_early_read;
+
+static int early_resume_init(void)
+{
+ hash_value_early_read = read_magic_time();
+ return 0;
+}
+
+static int late_resume_init(void)
+{
+ unsigned int val = hash_value_early_read;
+ unsigned int user, file, dev;
+
+ user = val % USERHASH;
+ val = val / USERHASH;
+ file = val % FILEHASH;
+ val = val / FILEHASH;
+ dev = val /* % DEVHASH */;
+
+ printk(" Magic number: %d:%d:%d\n", user, file, dev);
+ show_file_hash(file);
+ show_dev_hash(dev);
+ return 0;
+}
+
+core_initcall(early_resume_init);
+late_initcall(late_resume_init);
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 6858178b3af..04e5db445c7 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -12,7 +12,6 @@
* add themselves as children of the system bus.
*/
-#include <linux/config.h>
#include <linux/sysdev.h>
#include <linux/err.h>
#include <linux/module.h>
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 8c52421cbc5..3ef9d514b91 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -107,7 +107,7 @@ static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
return 0;
}
-static int topology_cpu_callback(struct notifier_block *nfb,
+static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -125,7 +125,7 @@ static int topology_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block topology_cpu_notifier =
+static struct notifier_block __cpuinitdata topology_cpu_notifier =
{
.notifier_call = topology_cpu_callback,
};
@@ -139,7 +139,7 @@ static int __cpuinit topology_sysfs_init(void)
(void *)(long)i);
}
- register_cpu_notifier(&topology_cpu_notifier);
+ register_hotcpu_notifier(&topology_cpu_notifier);
return 0;
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index dd8a1501142..a360215dbce 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -2530,7 +2530,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand);
disk->queue = RequestQueue;
sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
- sprintf(disk->devfs_name, "rd/host%d/target%d", Controller->ControllerNumber, n);
disk->major = MajorNumber;
disk->first_minor = n << DAC960_MaxPartitionsBits;
disk->fops = &DAC960_BlockDeviceOperations;
@@ -3015,7 +3014,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device,
Acquire shared access to the IRQ Channel.
*/
IRQ_Channel = PCI_Device->irq;
- if (request_irq(IRQ_Channel, InterruptHandler, SA_SHIRQ,
+ if (request_irq(IRQ_Channel, InterruptHandler, IRQF_SHARED,
Controller->FullModelName, Controller) < 0)
{
DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
@@ -7116,7 +7115,7 @@ static struct pci_device_id DAC960_id_table[] = {
{
.vendor = PCI_VENDOR_ID_MYLEX,
.device = PCI_DEVICE_ID_MYLEX_DAC960_GEM,
- .subvendor = PCI_ANY_ID,
+ .subvendor = PCI_VENDOR_ID_MYLEX,
.subdevice = PCI_ANY_ID,
.driver_data = (unsigned long) &DAC960_GEM_privdata,
},
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 93d94749310..b5382cedf0c 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -400,6 +400,16 @@ config BLK_DEV_RAM_SIZE
what are you doing. If you are using IBM S/390, then set this to
8192.
+config BLK_DEV_RAM_BLOCKSIZE
+ int "Default RAM disk block size (bytes)"
+ depends on BLK_DEV_RAM
+ default "1024"
+ help
+ The default value is 1024 kilobytes. PAGE_SIZE is a much more
+ efficient choice however. The default is kept to ensure initrd
+ setups function - apparently needed by the rd_load_image routine
+ that supposes the filesystem in the image uses a 1024 blocksize.
+
config BLK_DEV_INITRD
bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support"
depends on BROKEN || !FRV
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 196c0ec9cd5..0b80fbb8dbf 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -43,7 +43,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -1732,13 +1731,10 @@ int acsi_init( void )
struct gendisk *disk = acsi_gendisk[i];
sprintf(disk->disk_name, "ad%c", 'a'+i);
aip = &acsi_info[NDevices];
- sprintf(disk->devfs_name, "ad/target%d/lun%d", aip->target, aip->lun);
disk->major = ACSI_MAJOR;
disk->first_minor = i << 4;
- if (acsi_info[i].type != HARDDISK) {
+ if (acsi_info[i].type != HARDDISK)
disk->minors = 1;
- strcat(disk->devfs_name, "/disc");
- }
disk->fops = &acsi_fops;
disk->private_data = &acsi_info[i];
set_capacity(disk, acsi_info[i].size);
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index 4cb9c133628..4030a8fd118 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -65,7 +65,6 @@ not be guaranteed. There are several ways to assure this:
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#include <asm/pgtable.h>
@@ -1005,11 +1004,6 @@ int slm_init( void )
BufferP = SLMBuffer;
SLMState = IDLE;
- devfs_mk_dir("slm");
- for (i = 0; i < MAX_SLM; i++) {
- devfs_mk_cdev(MKDEV(ACSI_MAJOR, i),
- S_IFCHR|S_IRUSR|S_IWUSR, "slm/%d", i);
- }
return 0;
}
@@ -1032,10 +1026,6 @@ int init_module(void)
void cleanup_module(void)
{
- int i;
- for (i = 0; i < MAX_SLM; i++)
- devfs_remove("slm/%d", i);
- devfs_remove("slm");
if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0)
printk( KERN_ERR "acsi_slm: cleanup_module failed\n");
atari_stram_free( SLMBuffer );
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2a8af685926..2641597c654 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -64,6 +64,7 @@
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include <linux/elevator.h>
+#include <linux/interrupt.h>
#include <asm/setup.h>
#include <asm/uaccess.h>
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 5327f553b4f..1bc1cf9603f 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -162,7 +162,7 @@ aoechr_open(struct inode *inode, struct file *filp)
{
int n, i;
- n = MINOR(inode->i_rdev);
+ n = iminor(inode);
filp->private_data = (void *) (unsigned long) n;
for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 25c3c4a5da8..2cd3391ff87 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -34,7 +34,7 @@
#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
-#include <linux/init.h>
+#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
#include <linux/compat.h>
@@ -48,14 +48,14 @@
#include <linux/completion.h>
#define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "HP CISS Driver (v 2.6.10)"
-#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,10)
+#define DRIVER_NAME "HP CISS Driver (v 3.6.10)"
+#define DRIVER_VERSION CCISS_DRIVER_VERSION(3,6,10)
/* Embedded module documentation macros - see modules.h */
MODULE_AUTHOR("Hewlett-Packard Company");
-MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.10");
+MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 3.6.10");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i P600 P800 P400 P400i E200 E200i");
+ " SA6i P600 P800 P400 P400i E200 E200i E500");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
@@ -64,143 +64,131 @@ MODULE_LICENSE("GPL");
/* define the PCI info for the cards we can control */
static const struct pci_device_id cciss_pci_device_id[] = {
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS,
- 0x0E11, 0x4070, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
- 0x0E11, 0x4080, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
- 0x0E11, 0x4082, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB,
- 0x0E11, 0x4083, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409A, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409B, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409C, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x409D, 0, 0, 0},
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC,
- 0x0E11, 0x4091, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA,
- 0x103C, 0x3225, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3223, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3234, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
- 0x103c, 0x3235, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3211, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3212, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3213, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3214, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD,
- 0x103c, 0x3215, 0, 0, 0},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISS, 0x0E11, 0x4070},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4080},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4082},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSB, 0x0E11, 0x4083},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x4091},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409A},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409B},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409C},
+ {PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_CISSC, 0x0E11, 0x409D},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, 0x103C, 0x3225},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3223},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3234},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3235},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3211},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3212},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3213},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3214},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215},
+ {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3233},
{0,}
};
-MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
-#define NR_PRODUCTS ARRAY_SIZE(products)
+MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
/* board_id = Subsystem Device ID & Vendor ID
* product = Marketing Name for the board
- * access = Address of the struct of function pointers
+ * access = Address of the struct of function pointers
*/
static struct board_type products[] = {
- { 0x40700E11, "Smart Array 5300", &SA5_access },
- { 0x40800E11, "Smart Array 5i", &SA5B_access},
- { 0x40820E11, "Smart Array 532", &SA5B_access},
- { 0x40830E11, "Smart Array 5312", &SA5B_access},
- { 0x409A0E11, "Smart Array 641", &SA5_access},
- { 0x409B0E11, "Smart Array 642", &SA5_access},
- { 0x409C0E11, "Smart Array 6400", &SA5_access},
- { 0x409D0E11, "Smart Array 6400 EM", &SA5_access},
- { 0x40910E11, "Smart Array 6i", &SA5_access},
- { 0x3225103C, "Smart Array P600", &SA5_access},
- { 0x3223103C, "Smart Array P800", &SA5_access},
- { 0x3234103C, "Smart Array P400", &SA5_access},
- { 0x3235103C, "Smart Array P400i", &SA5_access},
- { 0x3211103C, "Smart Array E200i", &SA5_access},
- { 0x3212103C, "Smart Array E200", &SA5_access},
- { 0x3213103C, "Smart Array E200i", &SA5_access},
- { 0x3214103C, "Smart Array E200i", &SA5_access},
- { 0x3215103C, "Smart Array E200i", &SA5_access},
+ {0x40700E11, "Smart Array 5300", &SA5_access},
+ {0x40800E11, "Smart Array 5i", &SA5B_access},
+ {0x40820E11, "Smart Array 532", &SA5B_access},
+ {0x40830E11, "Smart Array 5312", &SA5B_access},
+ {0x409A0E11, "Smart Array 641", &SA5_access},
+ {0x409B0E11, "Smart Array 642", &SA5_access},
+ {0x409C0E11, "Smart Array 6400", &SA5_access},
+ {0x409D0E11, "Smart Array 6400 EM", &SA5_access},
+ {0x40910E11, "Smart Array 6i", &SA5_access},
+ {0x3225103C, "Smart Array P600", &SA5_access},
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
+ {0x3235103C, "Smart Array P400i", &SA5_access},
+ {0x3211103C, "Smart Array E200i", &SA5_access},
+ {0x3212103C, "Smart Array E200", &SA5_access},
+ {0x3213103C, "Smart Array E200i", &SA5_access},
+ {0x3214103C, "Smart Array E200i", &SA5_access},
+ {0x3215103C, "Smart Array E200i", &SA5_access},
+ {0x3233103C, "Smart Array E500", &SA5_access},
};
-/* How long to wait (in millesconds) for board to go into simple mode */
-#define MAX_CONFIG_WAIT 30000
+/* How long to wait (in milliseconds) for board to go into simple mode */
+#define MAX_CONFIG_WAIT 30000
#define MAX_IOCTL_CONFIG_WAIT 1000
/*define how many times we will try a command because of bus resets */
#define MAX_CMD_RETRIES 3
#define READ_AHEAD 1024
-#define NR_CMDS 384 /* #commands that can be outstanding */
+#define NR_CMDS 384 /* #commands that can be outstanding */
#define MAX_CTLR 32
/* Originally cciss driver only supports 8 major numbers */
#define MAX_CTLR_ORIG 8
-
static ctlr_info_t *hba[MAX_CTLR];
static void do_cciss_request(request_queue_t *q);
static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
static int cciss_open(struct inode *inode, struct file *filep);
static int cciss_release(struct inode *inode, struct file *filep);
-static int cciss_ioctl(struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg);
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+ unsigned int cmd, unsigned long arg);
static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo);
static int revalidate_allvol(ctlr_info_t *host);
static int cciss_revalidate(struct gendisk *disk);
static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
-static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all);
+static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
+ int clear_all);
static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
- int withirq, unsigned int *total_size, unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol,
- int withirq, unsigned int total_size,
- unsigned int block_size, InquiryData_struct *inq_buff,
- drive_info_struct *drv);
+ int withirq, unsigned int *total_size,
+ unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
+ unsigned int total_size,
+ unsigned int block_size,
+ InquiryData_struct *inq_buff,
+ drive_info_struct *drv);
static void cciss_getgeometry(int cntl_num);
-static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *, __u32);
-static void start_io( ctlr_info_t *h);
-static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size,
- unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
- unsigned char *scsi3addr, int cmd_type);
-static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
- unsigned int use_unit_num, unsigned int log_unit, __u8 page_code,
- int cmd_type);
+static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
+ __u32);
+static void start_io(ctlr_info_t *h);
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size,
+ unsigned int use_unit_num, unsigned int log_unit,
+ __u8 page_code, unsigned char *scsi3addr, int cmd_type);
+static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size,
+ unsigned int use_unit_num, unsigned int log_unit,
+ __u8 page_code, int cmd_type);
static void fail_all_cmds(unsigned long ctlr);
#ifdef CONFIG_PROC_FS
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data);
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data);
static void cciss_procinit(int i);
#else
-static void cciss_procinit(int i) {}
-#endif /* CONFIG_PROC_FS */
+static void cciss_procinit(int i)
+{
+}
+#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_COMPAT
static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg);
#endif
-static struct block_device_operations cciss_fops = {
- .owner = THIS_MODULE,
- .open = cciss_open,
- .release = cciss_release,
- .ioctl = cciss_ioctl,
- .getgeo = cciss_getgeo,
+static struct block_device_operations cciss_fops = {
+ .owner = THIS_MODULE,
+ .open = cciss_open,
+ .release = cciss_release,
+ .ioctl = cciss_ioctl,
+ .getgeo = cciss_getgeo,
#ifdef CONFIG_COMPAT
- .compat_ioctl = cciss_compat_ioctl,
+ .compat_ioctl = cciss_compat_ioctl,
#endif
- .revalidate_disk= cciss_revalidate,
+ .revalidate_disk = cciss_revalidate,
};
/*
@@ -208,28 +196,29 @@ static struct block_device_operations cciss_fops = {
*/
static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c)
{
- if (*Qptr == NULL) {
- *Qptr = c;
- c->next = c->prev = c;
- } else {
- c->prev = (*Qptr)->prev;
- c->next = (*Qptr);
- (*Qptr)->prev->next = c;
- (*Qptr)->prev = c;
- }
+ if (*Qptr == NULL) {
+ *Qptr = c;
+ c->next = c->prev = c;
+ } else {
+ c->prev = (*Qptr)->prev;
+ c->next = (*Qptr);
+ (*Qptr)->prev->next = c;
+ (*Qptr)->prev = c;
+ }
}
-static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
- CommandList_struct *c)
+static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
+ CommandList_struct *c)
{
- if (c && c->next != c) {
- if (*Qptr == c) *Qptr = c->next;
- c->prev->next = c->next;
- c->next->prev = c->prev;
- } else {
- *Qptr = NULL;
- }
- return c;
+ if (c && c->next != c) {
+ if (*Qptr == c)
+ *Qptr = c->next;
+ c->prev->next = c->next;
+ c->next->prev = c->prev;
+ } else {
+ *Qptr = NULL;
+ }
+ return c;
}
#include "cciss_scsi.c" /* For SCSI tape support */
@@ -242,23 +231,24 @@ static inline CommandList_struct *removeQ(CommandList_struct **Qptr,
#define ENG_GIG 1000000000
#define ENG_GIG_FACTOR (ENG_GIG/512)
#define RAID_UNKNOWN 6
-static const char *raid_label[] = {"0","4","1(1+0)","5","5+1","ADG",
- "UNKNOWN"};
+static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
+ "UNKNOWN"
+};
static struct proc_dir_entry *proc_cciss;
-static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
- int length, int *eof, void *data)
+static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
+ int length, int *eof, void *data)
{
- off_t pos = 0;
- off_t len = 0;
- int size, i, ctlr;
- ctlr_info_t *h = (ctlr_info_t*)data;
- drive_info_struct *drv;
+ off_t pos = 0;
+ off_t len = 0;
+ int size, i, ctlr;
+ ctlr_info_t *h = (ctlr_info_t *) data;
+ drive_info_struct *drv;
unsigned long flags;
- sector_t vol_sz, vol_sz_frac;
+ sector_t vol_sz, vol_sz_frac;
- ctlr = h->ctlr;
+ ctlr = h->ctlr;
/* prevent displaying bogus info during configuration
* or deconfiguration of a logical volume
@@ -266,35 +256,35 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
if (h->busy_configuring) {
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- return -EBUSY;
+ return -EBUSY;
}
h->busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- size = sprintf(buffer, "%s: HP %s Controller\n"
- "Board ID: 0x%08lx\n"
- "Firmware Version: %c%c%c%c\n"
- "IRQ: %d\n"
- "Logical drives: %d\n"
- "Current Q depth: %d\n"
- "Current # commands on controller: %d\n"
- "Max Q depth since init: %d\n"
- "Max # commands on controller since init: %d\n"
- "Max SG entries since init: %d\n\n",
- h->devname,
- h->product_name,
- (unsigned long)h->board_id,
- h->firm_ver[0], h->firm_ver[1], h->firm_ver[2], h->firm_ver[3],
- (unsigned int)h->intr[SIMPLE_MODE_INT],
- h->num_luns,
- h->Qdepth, h->commands_outstanding,
- h->maxQsinceinit, h->max_outstanding, h->maxSG);
-
- pos += size; len += size;
+ size = sprintf(buffer, "%s: HP %s Controller\n"
+ "Board ID: 0x%08lx\n"
+ "Firmware Version: %c%c%c%c\n"
+ "IRQ: %d\n"
+ "Logical drives: %d\n"
+ "Current Q depth: %d\n"
+ "Current # commands on controller: %d\n"
+ "Max Q depth since init: %d\n"
+ "Max # commands on controller since init: %d\n"
+ "Max SG entries since init: %d\n\n",
+ h->devname,
+ h->product_name,
+ (unsigned long)h->board_id,
+ h->firm_ver[0], h->firm_ver[1], h->firm_ver[2],
+ h->firm_ver[3], (unsigned int)h->intr[SIMPLE_MODE_INT],
+ h->num_luns, h->Qdepth, h->commands_outstanding,
+ h->maxQsinceinit, h->max_outstanding, h->maxSG);
+
+ pos += size;
+ len += size;
cciss_proc_tape_report(ctlr, buffer, &pos, &len);
- for(i=0; i<=h->highest_lun; i++) {
+ for (i = 0; i <= h->highest_lun; i++) {
- drv = &h->drv[i];
+ drv = &h->drv[i];
if (drv->heads == 0)
continue;
@@ -305,25 +295,26 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset,
if (drv->raid_level > 5)
drv->raid_level = RAID_UNKNOWN;
- size = sprintf(buffer+len, "cciss/c%dd%d:"
- "\t%4u.%02uGB\tRAID %s\n",
- ctlr, i, (int)vol_sz, (int)vol_sz_frac,
- raid_label[drv->raid_level]);
- pos += size; len += size;
- }
-
- *eof = 1;
- *start = buffer+offset;
- len -= offset;
- if (len>length)
- len = length;
+ size = sprintf(buffer + len, "cciss/c%dd%d:"
+ "\t%4u.%02uGB\tRAID %s\n",
+ ctlr, i, (int)vol_sz, (int)vol_sz_frac,
+ raid_label[drv->raid_level]);
+ pos += size;
+ len += size;
+ }
+
+ *eof = 1;
+ *start = buffer + offset;
+ len -= offset;
+ if (len > length)
+ len = length;
h->busy_configuring = 0;
- return len;
+ return len;
}
-static int
-cciss_proc_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
+static int
+cciss_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
{
unsigned char cmd[80];
int len;
@@ -332,20 +323,23 @@ cciss_proc_write(struct file *file, const char __user *buffer,
int rc;
#endif
- if (count > sizeof(cmd)-1) return -EINVAL;
- if (copy_from_user(cmd, buffer, count)) return -EFAULT;
+ if (count > sizeof(cmd) - 1)
+ return -EINVAL;
+ if (copy_from_user(cmd, buffer, count))
+ return -EFAULT;
cmd[count] = '\0';
len = strlen(cmd); // above 3 lines ensure safety
- if (len && cmd[len-1] == '\n')
+ if (len && cmd[len - 1] == '\n')
cmd[--len] = '\0';
# ifdef CONFIG_CISS_SCSI_TAPE
- if (strcmp("engage scsi", cmd)==0) {
- rc = cciss_engage_scsi(h->ctlr);
- if (rc != 0) return -rc;
- return count;
- }
- /* might be nice to have "disengage" too, but it's not
- safely possible. (only 1 module use count, lock issues.) */
+ if (strcmp("engage scsi", cmd) == 0) {
+ rc = cciss_engage_scsi(h->ctlr);
+ if (rc != 0)
+ return -rc;
+ return count;
+ }
+ /* might be nice to have "disengage" too, but it's not
+ safely possible. (only 1 module use count, lock issues.) */
# endif
return -EINVAL;
}
@@ -358,116 +352,113 @@ static void __devinit cciss_procinit(int i)
{
struct proc_dir_entry *pde;
- if (proc_cciss == NULL) {
- proc_cciss = proc_mkdir("cciss", proc_root_driver);
- if (!proc_cciss)
+ if (proc_cciss == NULL) {
+ proc_cciss = proc_mkdir("cciss", proc_root_driver);
+ if (!proc_cciss)
return;
- }
+ }
- pde = create_proc_read_entry(hba[i]->devname,
- S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
- proc_cciss, cciss_proc_get_info, hba[i]);
+ pde = create_proc_read_entry(hba[i]->devname,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH,
+ proc_cciss, cciss_proc_get_info, hba[i]);
pde->write_proc = cciss_proc_write;
}
-#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PROC_FS */
-/*
- * For operations that cannot sleep, a command block is allocated at init,
+/*
+ * For operations that cannot sleep, a command block is allocated at init,
* and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
- * which ones are free or in use. For operations that can wait for kmalloc
- * to possible sleep, this routine can be called with get_from_pool set to 0.
- * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
- */
-static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool)
+ * which ones are free or in use. For operations that can wait for kmalloc
+ * to possible sleep, this routine can be called with get_from_pool set to 0.
+ * cmd_free() MUST be called with a got_from_pool set to 0 if cmd_alloc was.
+ */
+static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool)
{
CommandList_struct *c;
- int i;
+ int i;
u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
- if (!get_from_pool)
- {
- c = (CommandList_struct *) pci_alloc_consistent(
- h->pdev, sizeof(CommandList_struct), &cmd_dma_handle);
- if(c==NULL)
- return NULL;
+ if (!get_from_pool) {
+ c = (CommandList_struct *) pci_alloc_consistent(h->pdev,
+ sizeof(CommandList_struct), &cmd_dma_handle);
+ if (c == NULL)
+ return NULL;
memset(c, 0, sizeof(CommandList_struct));
c->cmdindex = -1;
- c->err_info = (ErrorInfo_struct *)pci_alloc_consistent(
- h->pdev, sizeof(ErrorInfo_struct),
- &err_dma_handle);
-
- if (c->err_info == NULL)
- {
- pci_free_consistent(h->pdev,
+ c->err_info = (ErrorInfo_struct *)
+ pci_alloc_consistent(h->pdev, sizeof(ErrorInfo_struct),
+ &err_dma_handle);
+
+ if (c->err_info == NULL) {
+ pci_free_consistent(h->pdev,
sizeof(CommandList_struct), c, cmd_dma_handle);
return NULL;
}
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
- } else /* get it out of the controllers pool */
- {
- do {
- i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
- if (i == NR_CMDS)
- return NULL;
- } while(test_and_set_bit(i & (BITS_PER_LONG - 1), h->cmd_pool_bits+(i/BITS_PER_LONG)) != 0);
+ } else { /* get it out of the controllers pool */
+
+ do {
+ i = find_first_zero_bit(h->cmd_pool_bits, NR_CMDS);
+ if (i == NR_CMDS)
+ return NULL;
+ } while (test_and_set_bit
+ (i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: using command buffer %d\n", i);
#endif
- c = h->cmd_pool + i;
+ c = h->cmd_pool + i;
memset(c, 0, sizeof(CommandList_struct));
- cmd_dma_handle = h->cmd_pool_dhandle
- + i*sizeof(CommandList_struct);
+ cmd_dma_handle = h->cmd_pool_dhandle
+ + i * sizeof(CommandList_struct);
c->err_info = h->errinfo_pool + i;
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
- err_dma_handle = h->errinfo_pool_dhandle
- + i*sizeof(ErrorInfo_struct);
- h->nr_allocs++;
+ err_dma_handle = h->errinfo_pool_dhandle
+ + i * sizeof(ErrorInfo_struct);
+ h->nr_allocs++;
c->cmdindex = i;
- }
+ }
c->busaddr = (__u32) cmd_dma_handle;
- temp64.val = (__u64) err_dma_handle;
+ temp64.val = (__u64) err_dma_handle;
c->ErrDesc.Addr.lower = temp64.val32.lower;
c->ErrDesc.Addr.upper = temp64.val32.upper;
c->ErrDesc.Len = sizeof(ErrorInfo_struct);
-
- c->ctlr = h->ctlr;
- return c;
-
+ c->ctlr = h->ctlr;
+ return c;
}
-/*
- * Frees a command block that was previously allocated with cmd_alloc().
+/*
+ * Frees a command block that was previously allocated with cmd_alloc().
*/
static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool)
{
int i;
u64bit temp64;
- if( !got_from_pool)
- {
+ if (!got_from_pool) {
temp64.val32.lower = c->ErrDesc.Addr.lower;
temp64.val32.upper = c->ErrDesc.Addr.upper;
- pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
- c->err_info, (dma_addr_t) temp64.val);
- pci_free_consistent(h->pdev, sizeof(CommandList_struct),
- c, (dma_addr_t) c->busaddr);
- } else
- {
+ pci_free_consistent(h->pdev, sizeof(ErrorInfo_struct),
+ c->err_info, (dma_addr_t) temp64.val);
+ pci_free_consistent(h->pdev, sizeof(CommandList_struct),
+ c, (dma_addr_t) c->busaddr);
+ } else {
i = c - h->cmd_pool;
- clear_bit(i&(BITS_PER_LONG-1), h->cmd_pool_bits+(i/BITS_PER_LONG));
- h->nr_frees++;
- }
+ clear_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG));
+ h->nr_frees++;
+ }
}
static inline ctlr_info_t *get_host(struct gendisk *disk)
{
- return disk->queue->queuedata;
+ return disk->queue->queuedata;
}
static inline drive_info_struct *get_drv(struct gendisk *disk)
@@ -485,7 +476,7 @@ static int cciss_open(struct inode *inode, struct file *filep)
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
if (host->busy_initializing || drv->busy_configuring)
return -EBUSY;
@@ -498,10 +489,10 @@ static int cciss_open(struct inode *inode, struct file *filep)
* for "raw controller".
*/
if (drv->nr_blocks == 0) {
- if (iminor(inode) != 0) { /* not node 0? */
+ if (iminor(inode) != 0) { /* not node 0? */
/* if not node 0 make sure it is a partition = 0 */
if (iminor(inode) & 0x0f) {
- return -ENXIO;
+ return -ENXIO;
/* if it is, make sure we have a LUN ID */
} else if (drv->LunID == 0) {
return -ENXIO;
@@ -514,6 +505,7 @@ static int cciss_open(struct inode *inode, struct file *filep)
host->usage_count++;
return 0;
}
+
/*
* Close. Sync first.
*/
@@ -523,8 +515,9 @@ static int cciss_release(struct inode *inode, struct file *filep)
drive_info_struct *drv = get_drv(inode->i_bdev->bd_disk);
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss_release %s\n", inode->i_bdev->bd_disk->disk_name);
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "cciss_release %s\n",
+ inode->i_bdev->bd_disk->disk_name);
+#endif /* CCISS_DEBUG */
drv->usage_count--;
host->usage_count--;
@@ -542,8 +535,10 @@ static int do_ioctl(struct file *f, unsigned cmd, unsigned long arg)
return ret;
}
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg);
-static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd, unsigned long arg);
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+ unsigned long arg);
+static int cciss_ioctl32_big_passthru(struct file *f, unsigned cmd,
+ unsigned long arg);
static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
{
@@ -575,19 +570,26 @@ static long cciss_compat_ioctl(struct file *f, unsigned cmd, unsigned long arg)
}
}
-static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_passthru(struct file *f, unsigned cmd,
+ unsigned long arg)
{
IOCTL32_Command_struct __user *arg32 =
- (IOCTL32_Command_struct __user *) arg;
+ (IOCTL32_Command_struct __user *) arg;
IOCTL_Command_struct arg64;
IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
int err;
u32 cp;
err = 0;
- err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
- err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
- err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+ err |=
+ copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+ sizeof(arg64.LUN_info));
+ err |=
+ copy_from_user(&arg64.Request, &arg32->Request,
+ sizeof(arg64.Request));
+ err |=
+ copy_from_user(&arg64.error_info, &arg32->error_info,
+ sizeof(arg64.error_info));
err |= get_user(arg64.buf_size, &arg32->buf_size);
err |= get_user(cp, &arg32->buf);
arg64.buf = compat_ptr(cp);
@@ -596,28 +598,38 @@ static int cciss_ioctl32_passthru(struct file *f, unsigned cmd, unsigned long ar
if (err)
return -EFAULT;
- err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long) p);
+ err = do_ioctl(f, CCISS_PASSTHRU, (unsigned long)p);
if (err)
return err;
- err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+ err |=
+ copy_in_user(&arg32->error_info, &p->error_info,
+ sizeof(arg32->error_info));
if (err)
return -EFAULT;
return err;
}
-static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned long arg)
+static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd,
+ unsigned long arg)
{
BIG_IOCTL32_Command_struct __user *arg32 =
- (BIG_IOCTL32_Command_struct __user *) arg;
+ (BIG_IOCTL32_Command_struct __user *) arg;
BIG_IOCTL_Command_struct arg64;
- BIG_IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64));
+ BIG_IOCTL_Command_struct __user *p =
+ compat_alloc_user_space(sizeof(arg64));
int err;
u32 cp;
err = 0;
- err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, sizeof(arg64.LUN_info));
- err |= copy_from_user(&arg64.Request, &arg32->Request, sizeof(arg64.Request));
- err |= copy_from_user(&arg64.error_info, &arg32->error_info, sizeof(arg64.error_info));
+ err |=
+ copy_from_user(&arg64.LUN_info, &arg32->LUN_info,
+ sizeof(arg64.LUN_info));
+ err |=
+ copy_from_user(&arg64.Request, &arg32->Request,
+ sizeof(arg64.Request));
+ err |=
+ copy_from_user(&arg64.error_info, &arg32->error_info,
+ sizeof(arg64.error_info));
err |= get_user(arg64.buf_size, &arg32->buf_size);
err |= get_user(arg64.malloc_size, &arg32->malloc_size);
err |= get_user(cp, &arg32->buf);
@@ -625,12 +637,14 @@ static int cciss_ioctl32_big_passthru(struct file *file, unsigned cmd, unsigned
err |= copy_to_user(p, &arg64, sizeof(arg64));
if (err)
- return -EFAULT;
+ return -EFAULT;
- err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long) p);
+ err = do_ioctl(file, CCISS_BIG_PASSTHRU, (unsigned long)p);
if (err)
return err;
- err |= copy_in_user(&arg32->error_info, &p->error_info, sizeof(arg32->error_info));
+ err |=
+ copy_in_user(&arg32->error_info, &p->error_info,
+ sizeof(arg32->error_info));
if (err)
return -EFAULT;
return err;
@@ -651,10 +665,10 @@ static int cciss_getgeo(struct block_device *bdev, struct hd_geometry *geo)
}
/*
- * ioctl
+ * ioctl
*/
-static int cciss_ioctl(struct inode *inode, struct file *filep,
- unsigned int cmd, unsigned long arg)
+static int cciss_ioctl(struct inode *inode, struct file *filep,
+ unsigned int cmd, unsigned long arg)
{
struct block_device *bdev = inode->i_bdev;
struct gendisk *disk = bdev->bd_disk;
@@ -665,171 +679,193 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss_ioctl: Called with cmd=%x %lx\n", cmd, arg);
-#endif /* CCISS_DEBUG */
-
- switch(cmd) {
+#endif /* CCISS_DEBUG */
+
+ switch (cmd) {
case CCISS_GETPCIINFO:
- {
- cciss_pci_info_struct pciinfo;
-
- if (!arg) return -EINVAL;
- pciinfo.domain = pci_domain_nr(host->pdev->bus);
- pciinfo.bus = host->pdev->bus->number;
- pciinfo.dev_fn = host->pdev->devfn;
- pciinfo.board_id = host->board_id;
- if (copy_to_user(argp, &pciinfo, sizeof( cciss_pci_info_struct )))
- return -EFAULT;
- return(0);
- }
+ {
+ cciss_pci_info_struct pciinfo;
+
+ if (!arg)
+ return -EINVAL;
+ pciinfo.domain = pci_domain_nr(host->pdev->bus);
+ pciinfo.bus = host->pdev->bus->number;
+ pciinfo.dev_fn = host->pdev->devfn;
+ pciinfo.board_id = host->board_id;
+ if (copy_to_user
+ (argp, &pciinfo, sizeof(cciss_pci_info_struct)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_GETINTINFO:
- {
- cciss_coalint_struct intinfo;
- if (!arg) return -EINVAL;
- intinfo.delay = readl(&host->cfgtable->HostWrite.CoalIntDelay);
- intinfo.count = readl(&host->cfgtable->HostWrite.CoalIntCount);
- if (copy_to_user(argp, &intinfo, sizeof( cciss_coalint_struct )))
- return -EFAULT;
- return(0);
- }
+ {
+ cciss_coalint_struct intinfo;
+ if (!arg)
+ return -EINVAL;
+ intinfo.delay =
+ readl(&host->cfgtable->HostWrite.CoalIntDelay);
+ intinfo.count =
+ readl(&host->cfgtable->HostWrite.CoalIntCount);
+ if (copy_to_user
+ (argp, &intinfo, sizeof(cciss_coalint_struct)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_SETINTINFO:
- {
- cciss_coalint_struct intinfo;
- unsigned long flags;
- int i;
-
- if (!arg) return -EINVAL;
- if (!capable(CAP_SYS_ADMIN)) return -EPERM;
- if (copy_from_user(&intinfo, argp, sizeof( cciss_coalint_struct)))
- return -EFAULT;
- if ( (intinfo.delay == 0 ) && (intinfo.count == 0))
-
{
-// printk("cciss_ioctl: delay and count cannot be 0\n");
- return( -EINVAL);
+ cciss_coalint_struct intinfo;
+ unsigned long flags;
+ int i;
+
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (copy_from_user
+ (&intinfo, argp, sizeof(cciss_coalint_struct)))
+ return -EFAULT;
+ if ((intinfo.delay == 0) && (intinfo.count == 0))
+ {
+// printk("cciss_ioctl: delay and count cannot be 0\n");
+ return -EINVAL;
+ }
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ /* Update the field, and then ring the doorbell */
+ writel(intinfo.delay,
+ &(host->cfgtable->HostWrite.CoalIntDelay));
+ writel(intinfo.count,
+ &(host->cfgtable->HostWrite.CoalIntCount));
+ writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+ for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+ if (!(readl(host->vaddr + SA5_DOORBELL)
+ & CFGTBL_ChangeReq))
+ break;
+ /* delay and try again */
+ udelay(1000);
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (i >= MAX_IOCTL_CONFIG_WAIT)
+ return -EAGAIN;
+ return 0;
}
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- /* Update the field, and then ring the doorbell */
- writel( intinfo.delay,
- &(host->cfgtable->HostWrite.CoalIntDelay));
- writel( intinfo.count,
- &(host->cfgtable->HostWrite.CoalIntCount));
- writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
-
- for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
- if (!(readl(host->vaddr + SA5_DOORBELL)
- & CFGTBL_ChangeReq))
- break;
- /* delay and try again */
- udelay(1000);
- }
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- if (i >= MAX_IOCTL_CONFIG_WAIT)
- return -EAGAIN;
- return(0);
- }
case CCISS_GETNODENAME:
- {
- NodeName_type NodeName;
- int i;
-
- if (!arg) return -EINVAL;
- for(i=0;i<16;i++)
- NodeName[i] = readb(&host->cfgtable->ServerName[i]);
- if (copy_to_user(argp, NodeName, sizeof( NodeName_type)))
- return -EFAULT;
- return(0);
- }
+ {
+ NodeName_type NodeName;
+ int i;
+
+ if (!arg)
+ return -EINVAL;
+ for (i = 0; i < 16; i++)
+ NodeName[i] =
+ readb(&host->cfgtable->ServerName[i]);
+ if (copy_to_user(argp, NodeName, sizeof(NodeName_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_SETNODENAME:
- {
- NodeName_type NodeName;
- unsigned long flags;
- int i;
-
- if (!arg) return -EINVAL;
- if (!capable(CAP_SYS_ADMIN)) return -EPERM;
-
- if (copy_from_user(NodeName, argp, sizeof( NodeName_type)))
- return -EFAULT;
-
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
-
- /* Update the field, and then ring the doorbell */
- for(i=0;i<16;i++)
- writeb( NodeName[i], &host->cfgtable->ServerName[i]);
-
- writel( CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
-
- for(i=0;i<MAX_IOCTL_CONFIG_WAIT;i++) {
- if (!(readl(host->vaddr + SA5_DOORBELL)
- & CFGTBL_ChangeReq))
- break;
- /* delay and try again */
- udelay(1000);
- }
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- if (i >= MAX_IOCTL_CONFIG_WAIT)
- return -EAGAIN;
- return(0);
- }
+ {
+ NodeName_type NodeName;
+ unsigned long flags;
+ int i;
+
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (copy_from_user
+ (NodeName, argp, sizeof(NodeName_type)))
+ return -EFAULT;
+
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+
+ /* Update the field, and then ring the doorbell */
+ for (i = 0; i < 16; i++)
+ writeb(NodeName[i],
+ &host->cfgtable->ServerName[i]);
+
+ writel(CFGTBL_ChangeReq, host->vaddr + SA5_DOORBELL);
+
+ for (i = 0; i < MAX_IOCTL_CONFIG_WAIT; i++) {
+ if (!(readl(host->vaddr + SA5_DOORBELL)
+ & CFGTBL_ChangeReq))
+ break;
+ /* delay and try again */
+ udelay(1000);
+ }
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (i >= MAX_IOCTL_CONFIG_WAIT)
+ return -EAGAIN;
+ return 0;
+ }
case CCISS_GETHEARTBEAT:
- {
- Heartbeat_type heartbeat;
-
- if (!arg) return -EINVAL;
- heartbeat = readl(&host->cfgtable->HeartBeat);
- if (copy_to_user(argp, &heartbeat, sizeof( Heartbeat_type)))
- return -EFAULT;
- return(0);
- }
+ {
+ Heartbeat_type heartbeat;
+
+ if (!arg)
+ return -EINVAL;
+ heartbeat = readl(&host->cfgtable->HeartBeat);
+ if (copy_to_user
+ (argp, &heartbeat, sizeof(Heartbeat_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_GETBUSTYPES:
- {
- BusTypes_type BusTypes;
-
- if (!arg) return -EINVAL;
- BusTypes = readl(&host->cfgtable->BusTypes);
- if (copy_to_user(argp, &BusTypes, sizeof( BusTypes_type) ))
- return -EFAULT;
- return(0);
- }
+ {
+ BusTypes_type BusTypes;
+
+ if (!arg)
+ return -EINVAL;
+ BusTypes = readl(&host->cfgtable->BusTypes);
+ if (copy_to_user
+ (argp, &BusTypes, sizeof(BusTypes_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_GETFIRMVER:
- {
- FirmwareVer_type firmware;
+ {
+ FirmwareVer_type firmware;
- if (!arg) return -EINVAL;
- memcpy(firmware, host->firm_ver, 4);
+ if (!arg)
+ return -EINVAL;
+ memcpy(firmware, host->firm_ver, 4);
- if (copy_to_user(argp, firmware, sizeof( FirmwareVer_type)))
- return -EFAULT;
- return(0);
- }
- case CCISS_GETDRIVVER:
- {
- DriverVer_type DriverVer = DRIVER_VERSION;
+ if (copy_to_user
+ (argp, firmware, sizeof(FirmwareVer_type)))
+ return -EFAULT;
+ return 0;
+ }
+ case CCISS_GETDRIVVER:
+ {
+ DriverVer_type DriverVer = DRIVER_VERSION;
- if (!arg) return -EINVAL;
+ if (!arg)
+ return -EINVAL;
- if (copy_to_user(argp, &DriverVer, sizeof( DriverVer_type) ))
- return -EFAULT;
- return(0);
- }
+ if (copy_to_user
+ (argp, &DriverVer, sizeof(DriverVer_type)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_REVALIDVOLS:
if (bdev != bdev->bd_contains || drv != host->drv)
return -ENXIO;
- return revalidate_allvol(host);
-
- case CCISS_GETLUNINFO: {
- LogvolInfo_struct luninfo;
-
- luninfo.LunID = drv->LunID;
- luninfo.num_opens = drv->usage_count;
- luninfo.num_parts = 0;
- if (copy_to_user(argp, &luninfo,
- sizeof(LogvolInfo_struct)))
- return -EFAULT;
- return(0);
- }
+ return revalidate_allvol(host);
+
+ case CCISS_GETLUNINFO:{
+ LogvolInfo_struct luninfo;
+
+ luninfo.LunID = drv->LunID;
+ luninfo.num_opens = drv->usage_count;
+ luninfo.num_parts = 0;
+ if (copy_to_user(argp, &luninfo,
+ sizeof(LogvolInfo_struct)))
+ return -EFAULT;
+ return 0;
+ }
case CCISS_DEREGDISK:
return rebuild_lun_table(host, disk);
@@ -837,278 +873,284 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
return rebuild_lun_table(host, NULL);
case CCISS_PASSTHRU:
- {
- IOCTL_Command_struct iocommand;
- CommandList_struct *c;
- char *buff = NULL;
- u64bit temp64;
- unsigned long flags;
- DECLARE_COMPLETION(wait);
-
- if (!arg) return -EINVAL;
-
- if (!capable(CAP_SYS_RAWIO)) return -EPERM;
-
- if (copy_from_user(&iocommand, argp, sizeof( IOCTL_Command_struct) ))
- return -EFAULT;
- if((iocommand.buf_size < 1) &&
- (iocommand.Request.Type.Direction != XFER_NONE))
- {
- return -EINVAL;
- }
-#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
- /* Check kmalloc limits */
- if(iocommand.buf_size > 128000)
- return -EINVAL;
-#endif
- if(iocommand.buf_size > 0)
{
- buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
- if( buff == NULL)
- return -EFAULT;
- }
- if (iocommand.Request.Type.Direction == XFER_WRITE)
- {
- /* Copy the data into the buffer we created */
- if (copy_from_user(buff, iocommand.buf, iocommand.buf_size))
- {
- kfree(buff);
- return -EFAULT;
- }
- } else {
- memset(buff, 0, iocommand.buf_size);
- }
- if ((c = cmd_alloc(host , 0)) == NULL)
- {
- kfree(buff);
- return -ENOMEM;
- }
- // Fill in the command type
- c->cmd_type = CMD_IOCTL_PEND;
- // Fill in Command Header
- c->Header.ReplyQueue = 0; // unused in simple mode
- if( iocommand.buf_size > 0) // buffer to fill
- {
- c->Header.SGList = 1;
- c->Header.SGTotal= 1;
- } else // no buffers to fill
- {
- c->Header.SGList = 0;
- c->Header.SGTotal= 0;
- }
- c->Header.LUN = iocommand.LUN_info;
- c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag
-
- // Fill in Request block
- c->Request = iocommand.Request;
-
- // Fill in the scatter gather information
- if (iocommand.buf_size > 0 )
- {
- temp64.val = pci_map_single( host->pdev, buff,
- iocommand.buf_size,
- PCI_DMA_BIDIRECTIONAL);
- c->SG[0].Addr.lower = temp64.val32.lower;
- c->SG[0].Addr.upper = temp64.val32.upper;
- c->SG[0].Len = iocommand.buf_size;
- c->SG[0].Ext = 0; // we are not chaining
- }
- c->waiting = &wait;
+ IOCTL_Command_struct iocommand;
+ CommandList_struct *c;
+ char *buff = NULL;
+ u64bit temp64;
+ unsigned long flags;
+ DECLARE_COMPLETION(wait);
- /* Put the request on the tail of the request queue */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- addQ(&host->reqQ, c);
- host->Qdepth++;
- start_io(host);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ if (!arg)
+ return -EINVAL;
- wait_for_completion(&wait);
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
- /* unlock the buffers from DMA */
- temp64.val32.lower = c->SG[0].Addr.lower;
- temp64.val32.upper = c->SG[0].Addr.upper;
- pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
- iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
+ if (copy_from_user
+ (&iocommand, argp, sizeof(IOCTL_Command_struct)))
+ return -EFAULT;
+ if ((iocommand.buf_size < 1) &&
+ (iocommand.Request.Type.Direction != XFER_NONE)) {
+ return -EINVAL;
+ }
+#if 0 /* 'buf_size' member is 16-bits, and always smaller than kmalloc limit */
+ /* Check kmalloc limits */
+ if (iocommand.buf_size > 128000)
+ return -EINVAL;
+#endif
+ if (iocommand.buf_size > 0) {
+ buff = kmalloc(iocommand.buf_size, GFP_KERNEL);
+ if (buff == NULL)
+ return -EFAULT;
+ }
+ if (iocommand.Request.Type.Direction == XFER_WRITE) {
+ /* Copy the data into the buffer we created */
+ if (copy_from_user
+ (buff, iocommand.buf, iocommand.buf_size)) {
+ kfree(buff);
+ return -EFAULT;
+ }
+ } else {
+ memset(buff, 0, iocommand.buf_size);
+ }
+ if ((c = cmd_alloc(host, 0)) == NULL) {
+ kfree(buff);
+ return -ENOMEM;
+ }
+ // Fill in the command type
+ c->cmd_type = CMD_IOCTL_PEND;
+ // Fill in Command Header
+ c->Header.ReplyQueue = 0; // unused in simple mode
+ if (iocommand.buf_size > 0) // buffer to fill
+ {
+ c->Header.SGList = 1;
+ c->Header.SGTotal = 1;
+ } else // no buffers to fill
+ {
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
+ }
+ c->Header.LUN = iocommand.LUN_info;
+ c->Header.Tag.lower = c->busaddr; // use the kernel address the cmd block for tag
- /* Copy the error information out */
- iocommand.error_info = *(c->err_info);
- if ( copy_to_user(argp, &iocommand, sizeof( IOCTL_Command_struct) ) )
- {
- kfree(buff);
- cmd_free(host, c, 0);
- return( -EFAULT);
- }
+ // Fill in Request block
+ c->Request = iocommand.Request;
- if (iocommand.Request.Type.Direction == XFER_READ)
- {
- /* Copy the data out of the buffer we created */
- if (copy_to_user(iocommand.buf, buff, iocommand.buf_size))
- {
- kfree(buff);
+ // Fill in the scatter gather information
+ if (iocommand.buf_size > 0) {
+ temp64.val = pci_map_single(host->pdev, buff,
+ iocommand.buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Addr.lower = temp64.val32.lower;
+ c->SG[0].Addr.upper = temp64.val32.upper;
+ c->SG[0].Len = iocommand.buf_size;
+ c->SG[0].Ext = 0; // we are not chaining
+ }
+ c->waiting = &wait;
+
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&host->reqQ, c);
+ host->Qdepth++;
+ start_io(host);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+
+ wait_for_completion(&wait);
+
+ /* unlock the buffers from DMA */
+ temp64.val32.lower = c->SG[0].Addr.lower;
+ temp64.val32.upper = c->SG[0].Addr.upper;
+ pci_unmap_single(host->pdev, (dma_addr_t) temp64.val,
+ iocommand.buf_size,
+ PCI_DMA_BIDIRECTIONAL);
+
+ /* Copy the error information out */
+ iocommand.error_info = *(c->err_info);
+ if (copy_to_user
+ (argp, &iocommand, sizeof(IOCTL_Command_struct))) {
+ kfree(buff);
cmd_free(host, c, 0);
return -EFAULT;
}
- }
- kfree(buff);
- cmd_free(host, c, 0);
- return(0);
- }
- case CCISS_BIG_PASSTHRU: {
- BIG_IOCTL_Command_struct *ioc;
- CommandList_struct *c;
- unsigned char **buff = NULL;
- int *buff_size = NULL;
- u64bit temp64;
- unsigned long flags;
- BYTE sg_used = 0;
- int status = 0;
- int i;
- DECLARE_COMPLETION(wait);
- __u32 left;
- __u32 sz;
- BYTE __user *data_ptr;
-
- if (!arg)
- return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- ioc = (BIG_IOCTL_Command_struct *)
- kmalloc(sizeof(*ioc), GFP_KERNEL);
- if (!ioc) {
- status = -ENOMEM;
- goto cleanup1;
- }
- if (copy_from_user(ioc, argp, sizeof(*ioc))) {
- status = -EFAULT;
- goto cleanup1;
+
+ if (iocommand.Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ if (copy_to_user
+ (iocommand.buf, buff, iocommand.buf_size)) {
+ kfree(buff);
+ cmd_free(host, c, 0);
+ return -EFAULT;
+ }
+ }
+ kfree(buff);
+ cmd_free(host, c, 0);
+ return 0;
}
- if ((ioc->buf_size < 1) &&
- (ioc->Request.Type.Direction != XFER_NONE)) {
+ case CCISS_BIG_PASSTHRU:{
+ BIG_IOCTL_Command_struct *ioc;
+ CommandList_struct *c;
+ unsigned char **buff = NULL;
+ int *buff_size = NULL;
+ u64bit temp64;
+ unsigned long flags;
+ BYTE sg_used = 0;
+ int status = 0;
+ int i;
+ DECLARE_COMPLETION(wait);
+ __u32 left;
+ __u32 sz;
+ BYTE __user *data_ptr;
+
+ if (!arg)
+ return -EINVAL;
+ if (!capable(CAP_SYS_RAWIO))
+ return -EPERM;
+ ioc = (BIG_IOCTL_Command_struct *)
+ kmalloc(sizeof(*ioc), GFP_KERNEL);
+ if (!ioc) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ if (copy_from_user(ioc, argp, sizeof(*ioc))) {
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if ((ioc->buf_size < 1) &&
+ (ioc->Request.Type.Direction != XFER_NONE)) {
status = -EINVAL;
goto cleanup1;
- }
- /* Check kmalloc limits using all SGs */
- if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
- status = -EINVAL;
- goto cleanup1;
- }
- if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
- status = -EINVAL;
- goto cleanup1;
- }
- buff = kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
- if (!buff) {
- status = -ENOMEM;
- goto cleanup1;
- }
- buff_size = (int *) kmalloc(MAXSGENTRIES * sizeof(int),
- GFP_KERNEL);
- if (!buff_size) {
- status = -ENOMEM;
- goto cleanup1;
- }
- left = ioc->buf_size;
- data_ptr = ioc->buf;
- while (left) {
- sz = (left > ioc->malloc_size) ? ioc->malloc_size : left;
- buff_size[sg_used] = sz;
- buff[sg_used] = kmalloc(sz, GFP_KERNEL);
- if (buff[sg_used] == NULL) {
+ }
+ /* Check kmalloc limits using all SGs */
+ if (ioc->malloc_size > MAX_KMALLOC_SIZE) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ if (ioc->buf_size > ioc->malloc_size * MAXSGENTRIES) {
+ status = -EINVAL;
+ goto cleanup1;
+ }
+ buff =
+ kzalloc(MAXSGENTRIES * sizeof(char *), GFP_KERNEL);
+ if (!buff) {
status = -ENOMEM;
goto cleanup1;
}
- if (ioc->Request.Type.Direction == XFER_WRITE) {
- if (copy_from_user(buff[sg_used], data_ptr, sz)) {
+ buff_size = (int *)kmalloc(MAXSGENTRIES * sizeof(int),
+ GFP_KERNEL);
+ if (!buff_size) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ left = ioc->buf_size;
+ data_ptr = ioc->buf;
+ while (left) {
+ sz = (left >
+ ioc->malloc_size) ? ioc->
+ malloc_size : left;
+ buff_size[sg_used] = sz;
+ buff[sg_used] = kmalloc(sz, GFP_KERNEL);
+ if (buff[sg_used] == NULL) {
status = -ENOMEM;
goto cleanup1;
}
+ if (ioc->Request.Type.Direction == XFER_WRITE) {
+ if (copy_from_user
+ (buff[sg_used], data_ptr, sz)) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ } else {
+ memset(buff[sg_used], 0, sz);
+ }
+ left -= sz;
+ data_ptr += sz;
+ sg_used++;
+ }
+ if ((c = cmd_alloc(host, 0)) == NULL) {
+ status = -ENOMEM;
+ goto cleanup1;
+ }
+ c->cmd_type = CMD_IOCTL_PEND;
+ c->Header.ReplyQueue = 0;
+
+ if (ioc->buf_size > 0) {
+ c->Header.SGList = sg_used;
+ c->Header.SGTotal = sg_used;
} else {
- memset(buff[sg_used], 0, sz);
+ c->Header.SGList = 0;
+ c->Header.SGTotal = 0;
}
- left -= sz;
- data_ptr += sz;
- sg_used++;
- }
- if ((c = cmd_alloc(host , 0)) == NULL) {
- status = -ENOMEM;
- goto cleanup1;
- }
- c->cmd_type = CMD_IOCTL_PEND;
- c->Header.ReplyQueue = 0;
-
- if( ioc->buf_size > 0) {
- c->Header.SGList = sg_used;
- c->Header.SGTotal= sg_used;
- } else {
- c->Header.SGList = 0;
- c->Header.SGTotal= 0;
- }
- c->Header.LUN = ioc->LUN_info;
- c->Header.Tag.lower = c->busaddr;
-
- c->Request = ioc->Request;
- if (ioc->buf_size > 0 ) {
- int i;
- for(i=0; i<sg_used; i++) {
- temp64.val = pci_map_single( host->pdev, buff[i],
- buff_size[i],
+ c->Header.LUN = ioc->LUN_info;
+ c->Header.Tag.lower = c->busaddr;
+
+ c->Request = ioc->Request;
+ if (ioc->buf_size > 0) {
+ int i;
+ for (i = 0; i < sg_used; i++) {
+ temp64.val =
+ pci_map_single(host->pdev, buff[i],
+ buff_size[i],
+ PCI_DMA_BIDIRECTIONAL);
+ c->SG[i].Addr.lower =
+ temp64.val32.lower;
+ c->SG[i].Addr.upper =
+ temp64.val32.upper;
+ c->SG[i].Len = buff_size[i];
+ c->SG[i].Ext = 0; /* we are not chaining */
+ }
+ }
+ c->waiting = &wait;
+ /* Put the request on the tail of the request queue */
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ addQ(&host->reqQ, c);
+ host->Qdepth++;
+ start_io(host);
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ wait_for_completion(&wait);
+ /* unlock the buffers from DMA */
+ for (i = 0; i < sg_used; i++) {
+ temp64.val32.lower = c->SG[i].Addr.lower;
+ temp64.val32.upper = c->SG[i].Addr.upper;
+ pci_unmap_single(host->pdev,
+ (dma_addr_t) temp64.val, buff_size[i],
PCI_DMA_BIDIRECTIONAL);
- c->SG[i].Addr.lower = temp64.val32.lower;
- c->SG[i].Addr.upper = temp64.val32.upper;
- c->SG[i].Len = buff_size[i];
- c->SG[i].Ext = 0; /* we are not chaining */
}
- }
- c->waiting = &wait;
- /* Put the request on the tail of the request queue */
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- addQ(&host->reqQ, c);
- host->Qdepth++;
- start_io(host);
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- wait_for_completion(&wait);
- /* unlock the buffers from DMA */
- for(i=0; i<sg_used; i++) {
- temp64.val32.lower = c->SG[i].Addr.lower;
- temp64.val32.upper = c->SG[i].Addr.upper;
- pci_unmap_single( host->pdev, (dma_addr_t) temp64.val,
- buff_size[i], PCI_DMA_BIDIRECTIONAL);
- }
- /* Copy the error information out */
- ioc->error_info = *(c->err_info);
- if (copy_to_user(argp, ioc, sizeof(*ioc))) {
- cmd_free(host, c, 0);
- status = -EFAULT;
- goto cleanup1;
- }
- if (ioc->Request.Type.Direction == XFER_READ) {
- /* Copy the data out of the buffer we created */
- BYTE __user *ptr = ioc->buf;
- for(i=0; i< sg_used; i++) {
- if (copy_to_user(ptr, buff[i], buff_size[i])) {
- cmd_free(host, c, 0);
- status = -EFAULT;
- goto cleanup1;
+ /* Copy the error information out */
+ ioc->error_info = *(c->err_info);
+ if (copy_to_user(argp, ioc, sizeof(*ioc))) {
+ cmd_free(host, c, 0);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ if (ioc->Request.Type.Direction == XFER_READ) {
+ /* Copy the data out of the buffer we created */
+ BYTE __user *ptr = ioc->buf;
+ for (i = 0; i < sg_used; i++) {
+ if (copy_to_user
+ (ptr, buff[i], buff_size[i])) {
+ cmd_free(host, c, 0);
+ status = -EFAULT;
+ goto cleanup1;
+ }
+ ptr += buff_size[i];
}
- ptr += buff_size[i];
}
+ cmd_free(host, c, 0);
+ status = 0;
+ cleanup1:
+ if (buff) {
+ for (i = 0; i < sg_used; i++)
+ kfree(buff[i]);
+ kfree(buff);
+ }
+ kfree(buff_size);
+ kfree(ioc);
+ return status;
}
- cmd_free(host, c, 0);
- status = 0;
-cleanup1:
- if (buff) {
- for(i=0; i<sg_used; i++)
- kfree(buff[i]);
- kfree(buff);
- }
- kfree(buff_size);
- kfree(ioc);
- return(status);
- }
default:
return -ENOTTY;
}
-
}
/*
@@ -1119,7 +1161,7 @@ cleanup1:
*
* Right now I'm using the getgeometry() function to do this, but this
* function should probably be finer grained and allow you to revalidate one
- * particualar logical volume (instead of all of them on a particular
+ * particular logical volume (instead of all of them on a particular
* controller).
*/
static int revalidate_allvol(ctlr_info_t *host)
@@ -1127,17 +1169,17 @@ static int revalidate_allvol(ctlr_info_t *host)
int ctlr = host->ctlr, i;
unsigned long flags;
- spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- if (host->usage_count > 1) {
- spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- printk(KERN_WARNING "cciss: Device busy for volume"
- " revalidation (usage=%d)\n", host->usage_count);
- return -EBUSY;
- }
- host->usage_count++;
+ spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
+ if (host->usage_count > 1) {
+ spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
+ printk(KERN_WARNING "cciss: Device busy for volume"
+ " revalidation (usage=%d)\n", host->usage_count);
+ return -EBUSY;
+ }
+ host->usage_count++;
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
- for(i=0; i< NWD; i++) {
+ for (i = 0; i < NWD; i++) {
struct gendisk *disk = host->gendisk[i];
if (disk) {
request_queue_t *q = disk->queue;
@@ -1149,22 +1191,22 @@ static int revalidate_allvol(ctlr_info_t *host)
}
}
- /*
- * Set the partition and block size structures for all volumes
- * on this controller to zero. We will reread all of this data
- */
- memset(host->drv, 0, sizeof(drive_info_struct)
- * CISS_MAX_LUN);
- /*
- * Tell the array controller not to give us any interrupts while
- * we check the new geometry. Then turn interrupts back on when
- * we're done.
- */
- host->access.set_intr_mask(host, CCISS_INTR_OFF);
- cciss_getgeometry(ctlr);
- host->access.set_intr_mask(host, CCISS_INTR_ON);
-
- /* Loop through each real device */
+ /*
+ * Set the partition and block size structures for all volumes
+ * on this controller to zero. We will reread all of this data
+ */
+ memset(host->drv, 0, sizeof(drive_info_struct)
+ * CISS_MAX_LUN);
+ /*
+ * Tell the array controller not to give us any interrupts while
+ * we check the new geometry. Then turn interrupts back on when
+ * we're done.
+ */
+ host->access.set_intr_mask(host, CCISS_INTR_OFF);
+ cciss_getgeometry(ctlr);
+ host->access.set_intr_mask(host, CCISS_INTR_ON);
+
+ /* Loop through each real device */
for (i = 0; i < NWD; i++) {
struct gendisk *disk = host->gendisk[i];
drive_info_struct *drv = &(host->drv[i]);
@@ -1176,8 +1218,8 @@ static int revalidate_allvol(ctlr_info_t *host)
set_capacity(disk, drv->nr_blocks);
add_disk(disk);
}
- host->usage_count--;
- return 0;
+ host->usage_count--;
+ return 0;
}
static inline void complete_buffers(struct bio *bio, int status)
@@ -1191,7 +1233,50 @@ static inline void complete_buffers(struct bio *bio, int status)
bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
bio = xbh;
}
+}
+static void cciss_check_queues(ctlr_info_t *h)
+{
+ int start_queue = h->next_to_run;
+ int i;
+
+ /* check to see if we have maxed out the number of commands that can
+ * be placed on the queue. If so then exit. We do this check here
+ * in case the interrupt we serviced was from an ioctl and did not
+ * free any new commands.
+ */
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
+ return;
+
+ /* We have room on the queue for more commands. Now we need to queue
+ * them up. We will also keep track of the next queue to run so
+ * that every queue gets a chance to be started first.
+ */
+ for (i = 0; i < h->highest_lun + 1; i++) {
+ int curr_queue = (start_queue + i) % (h->highest_lun + 1);
+ /* make sure the disk has been added and the drive is real
+ * because this can be called from the middle of init_one.
+ */
+ if (!(h->drv[curr_queue].queue) || !(h->drv[curr_queue].heads))
+ continue;
+ blk_start_queue(h->gendisk[curr_queue]->queue);
+
+ /* check to see if we have maxed out the number of commands
+ * that can be placed on the queue.
+ */
+ if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS) {
+ if (curr_queue == start_queue) {
+ h->next_to_run =
+ (start_queue + 1) % (h->highest_lun + 1);
+ break;
+ } else {
+ h->next_to_run = curr_queue;
+ break;
+ }
+ } else {
+ curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
+ }
+ }
}
static void cciss_softirq_done(struct request *rq)
@@ -1209,7 +1294,7 @@ static void cciss_softirq_done(struct request *rq)
/* command did not need to be retried */
/* unmap the DMA mapping for all the scatter gather elements */
- for(i=0; i<cmd->Header.SGList; i++) {
+ for (i = 0; i < cmd->Header.SGList; i++) {
temp64.val32.lower = cmd->SG[i].Addr.lower;
temp64.val32.upper = cmd->SG[i].Addr.upper;
pci_unmap_page(h->pdev, temp64.val, cmd->SG[i].Len, ddir);
@@ -1219,11 +1304,13 @@ static void cciss_softirq_done(struct request *rq)
#ifdef CCISS_DEBUG
printk("Done with %p\n", rq);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
+ add_disk_randomness(rq->rq_disk);
spin_lock_irqsave(&h->lock, flags);
end_that_request_last(rq, rq->errors);
- cmd_free(h, cmd,1);
+ cmd_free(h, cmd, 1);
+ cciss_check_queues(h);
spin_unlock_irqrestore(&h->lock, flags);
}
@@ -1234,9 +1321,9 @@ static void cciss_softirq_done(struct request *rq)
* will always be left registered with the kernel since it is also the
* controller node. Any changes to disk 0 will show up on the next
* reboot.
-*/
+ */
static void cciss_update_drive_info(int ctlr, int drv_index)
- {
+{
ctlr_info_t *h = hba[ctlr];
struct gendisk *disk;
ReadCapdata_struct *size_buff = NULL;
@@ -1246,13 +1333,13 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
unsigned long flags = 0;
int ret = 0;
- /* if the disk already exists then deregister it before proceeding*/
- if (h->drv[drv_index].raid_level != -1){
+ /* if the disk already exists then deregister it before proceeding */
+ if (h->drv[drv_index].raid_level != -1) {
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
h->drv[drv_index].busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
ret = deregister_disk(h->gendisk[drv_index],
- &h->drv[drv_index], 0);
+ &h->drv[drv_index], 0);
h->drv[drv_index].busy_configuring = 0;
}
@@ -1260,27 +1347,25 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
if (ret)
return;
-
- /* Get information about the disk and modify the driver sturcture */
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
+ /* Get information about the disk and modify the driver structure */
+ size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL)
goto mem_msg;
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
if (inq_buff == NULL)
goto mem_msg;
cciss_read_capacity(ctlr, drv_index, size_buff, 1,
- &total_size, &block_size);
+ &total_size, &block_size);
cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
- inq_buff, &h->drv[drv_index]);
+ inq_buff, &h->drv[drv_index]);
++h->num_luns;
disk = h->gendisk[drv_index];
set_capacity(disk, h->drv[drv_index].nr_blocks);
-
/* if it's the controller it's already added */
- if (drv_index){
+ if (drv_index) {
disk->queue = blk_init_queue(do_cciss_request, &h->lock);
/* Set up queue information */
@@ -1300,17 +1385,17 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
disk->queue->queuedata = hba[ctlr];
blk_queue_hardsect_size(disk->queue,
- hba[ctlr]->drv[drv_index].block_size);
+ hba[ctlr]->drv[drv_index].block_size);
h->drv[drv_index].queue = disk->queue;
add_disk(disk);
}
-freeret:
+ freeret:
kfree(size_buff);
kfree(inq_buff);
return;
-mem_msg:
+ mem_msg:
printk(KERN_ERR "cciss: out of memory\n");
goto freeret;
}
@@ -1320,13 +1405,13 @@ mem_msg:
* where new drives will be added. If the index to be returned is greater
* than the highest_lun index for the controller then highest_lun is set
* to this new index. If there are no available indexes then -1 is returned.
-*/
+ */
static int cciss_find_free_drive_index(int ctlr)
{
int i;
- for (i=0; i < CISS_MAX_LUN; i++){
- if (hba[ctlr]->drv[i].raid_level == -1){
+ for (i = 0; i < CISS_MAX_LUN; i++) {
+ if (hba[ctlr]->drv[i].raid_level == -1) {
if (i > hba[ctlr]->highest_lun)
hba[ctlr]->highest_lun = i;
return i;
@@ -1336,7 +1421,7 @@ static int cciss_find_free_drive_index(int ctlr)
}
/* This function will add and remove logical drives from the Logical
- * drive array of the controller and maintain persistancy of ordering
+ * drive array of the controller and maintain persistency of ordering
* so that mount points are preserved until the next reboot. This allows
* for the removal of logical drives in the middle of the drive array
* without a re-ordering of those drives.
@@ -1344,7 +1429,7 @@ static int cciss_find_free_drive_index(int ctlr)
* h = The controller to perform the operations on
* del_disk = The disk to remove if specified. If the value given
* is NULL then no disk is removed.
-*/
+ */
static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
{
int ctlr = h->ctlr;
@@ -1361,12 +1446,12 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
/* Set busy_configuring flag for this operation */
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
- if (h->num_luns >= CISS_MAX_LUN){
+ if (h->num_luns >= CISS_MAX_LUN) {
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return -EINVAL;
}
- if (h->busy_configuring){
+ if (h->busy_configuring) {
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return -EBUSY;
}
@@ -1376,7 +1461,7 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
* and update the logical drive table. If it is not NULL then
* we will check if the disk is in use or not.
*/
- if (del_disk != NULL){
+ if (del_disk != NULL) {
drv = get_drv(del_disk);
drv->busy_configuring = 1;
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
@@ -1394,61 +1479,67 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
goto mem_msg;
return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0,
- TYPE_CMD);
-
- if (return_code == IO_OK){
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
- listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
- } else{ /* reading number of logical volumes failed */
+ sizeof(ReportLunData_struct), 0,
+ 0, 0, TYPE_CMD);
+
+ if (return_code == IO_OK) {
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[0]))
+ << 24;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[1]))
+ << 16;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[2]))
+ << 8;
+ listlength |=
+ 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
+ } else { /* reading number of logical volumes failed */
printk(KERN_WARNING "cciss: report logical volume"
- " command failed\n");
+ " command failed\n");
listlength = 0;
goto freeret;
}
num_luns = listlength / 8; /* 8 bytes per entry */
- if (num_luns > CISS_MAX_LUN){
+ if (num_luns > CISS_MAX_LUN) {
num_luns = CISS_MAX_LUN;
printk(KERN_WARNING "cciss: more luns configured"
- " on controller than can be handled by"
- " this driver.\n");
+ " on controller than can be handled by"
+ " this driver.\n");
}
/* Compare controller drive array to drivers drive array.
- * Check for updates in the drive information and any new drives
- * on the controller.
- */
- for (i=0; i < num_luns; i++){
+ * Check for updates in the drive information and any new drives
+ * on the controller.
+ */
+ for (i = 0; i < num_luns; i++) {
int j;
drv_found = 0;
- lunid = (0xff &
- (unsigned int)(ld_buff->LUN[i][3])) << 24;
- lunid |= (0xff &
- (unsigned int)(ld_buff->LUN[i][2])) << 16;
- lunid |= (0xff &
- (unsigned int)(ld_buff->LUN[i][1])) << 8;
- lunid |= 0xff &
- (unsigned int)(ld_buff->LUN[i][0]);
+ lunid = (0xff &
+ (unsigned int)(ld_buff->LUN[i][3])) << 24;
+ lunid |= (0xff &
+ (unsigned int)(ld_buff->LUN[i][2])) << 16;
+ lunid |= (0xff &
+ (unsigned int)(ld_buff->LUN[i][1])) << 8;
+ lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
/* Find if the LUN is already in the drive array
* of the controller. If so then update its info
* if not is use. If it does not exist then find
* the first free index and add it.
- */
- for (j=0; j <= h->highest_lun; j++){
- if (h->drv[j].LunID == lunid){
+ */
+ for (j = 0; j <= h->highest_lun; j++) {
+ if (h->drv[j].LunID == lunid) {
drv_index = j;
drv_found = 1;
}
}
/* check if the drive was found already in the array */
- if (!drv_found){
+ if (!drv_found) {
drv_index = cciss_find_free_drive_index(ctlr);
if (drv_index == -1)
goto freeret;
@@ -1456,18 +1547,18 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk)
}
h->drv[drv_index].LunID = lunid;
cciss_update_drive_info(ctlr, drv_index);
- } /* end for */
- } /* end else */
+ } /* end for */
+ } /* end else */
-freeret:
+ freeret:
kfree(ld_buff);
h->busy_configuring = 0;
/* We return -1 here to tell the ACU that we have registered/updated
* all of the drives that we can and to keep it from calling us
* additional times.
- */
+ */
return -1;
-mem_msg:
+ mem_msg:
printk(KERN_ERR "cciss: out of memory\n");
goto freeret;
}
@@ -1483,7 +1574,7 @@ mem_msg:
* clear_all = This flag determines whether or not the disk information
* is going to be completely cleared out and the highest_lun
* reset. Sometimes we want to clear out information about
- * the disk in preperation for re-adding it. In this case
+ * the disk in preparation for re-adding it. In this case
* the highest_lun should be left unchanged and the LunID
* should not be cleared.
*/
@@ -1496,19 +1587,17 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
return -EPERM;
/* make sure logical volume is NOT is use */
- if(clear_all || (h->gendisk[0] == disk)) {
- if (drv->usage_count > 1)
- return -EBUSY;
- }
- else
- if( drv->usage_count > 0 )
- return -EBUSY;
+ if (clear_all || (h->gendisk[0] == disk)) {
+ if (drv->usage_count > 1)
+ return -EBUSY;
+ } else if (drv->usage_count > 0)
+ return -EBUSY;
/* invalidate the devices and deregister the disk. If it is disk
* zero do not deregister it but just zero out it's values. This
* allows us to delete disk zero but keep the controller registered.
- */
- if (h->gendisk[0] != disk){
+ */
+ if (h->gendisk[0] != disk) {
if (disk) {
request_queue_t *q = disk->queue;
if (disk->flags & GENHD_FL_UP)
@@ -1530,91 +1619,90 @@ static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
drv->raid_level = -1; /* This can be used as a flag variable to
* indicate that this element of the drive
* array is free.
- */
-
- if (clear_all){
- /* check to see if it was the last disk */
- if (drv == h->drv + h->highest_lun) {
- /* if so, find the new hightest lun */
- int i, newhighest =-1;
- for(i=0; i<h->highest_lun; i++) {
- /* if the disk has size > 0, it is available */
+ */
+
+ if (clear_all) {
+ /* check to see if it was the last disk */
+ if (drv == h->drv + h->highest_lun) {
+ /* if so, find the new hightest lun */
+ int i, newhighest = -1;
+ for (i = 0; i < h->highest_lun; i++) {
+ /* if the disk has size > 0, it is available */
if (h->drv[i].heads)
- newhighest = i;
+ newhighest = i;
+ }
+ h->highest_lun = newhighest;
}
- h->highest_lun = newhighest;
- }
- drv->LunID = 0;
+ drv->LunID = 0;
}
- return(0);
+ return 0;
}
-static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
- size_t size,
- unsigned int use_unit_num, /* 0: address the controller,
- 1: address logical volume log_unit,
- 2: periph device address is scsi3addr */
- unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr,
- int cmd_type)
+static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: periph device address is scsi3addr */
+ unsigned int log_unit, __u8 page_code,
+ unsigned char *scsi3addr, int cmd_type)
{
- ctlr_info_t *h= hba[ctlr];
+ ctlr_info_t *h = hba[ctlr];
u64bit buff_dma_handle;
int status = IO_OK;
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
- if( buff != NULL) {
+ if (buff != NULL) {
c->Header.SGList = 1;
- c->Header.SGTotal= 1;
+ c->Header.SGTotal = 1;
} else {
c->Header.SGList = 0;
- c->Header.SGTotal= 0;
+ c->Header.SGTotal = 0;
}
c->Header.Tag.lower = c->busaddr;
c->Request.Type.Type = cmd_type;
if (cmd_type == TYPE_CMD) {
- switch(cmd) {
- case CISS_INQUIRY:
+ switch (cmd) {
+ case CISS_INQUIRY:
/* If the logical unit number is 0 then, this is going
- to controller so It's a physical command
- mode = 0 target = 0. So we have nothing to write.
- otherwise, if use_unit_num == 1,
- mode = 1(volume set addressing) target = LUNID
- otherwise, if use_unit_num == 2,
- mode = 0(periph dev addr) target = scsi3addr */
+ to controller so It's a physical command
+ mode = 0 target = 0. So we have nothing to write.
+ otherwise, if use_unit_num == 1,
+ mode = 1(volume set addressing) target = LUNID
+ otherwise, if use_unit_num == 2,
+ mode = 0(periph dev addr) target = scsi3addr */
if (use_unit_num == 1) {
- c->Header.LUN.LogDev.VolId=
- h->drv[log_unit].LunID;
- c->Header.LUN.LogDev.Mode = 1;
+ c->Header.LUN.LogDev.VolId =
+ h->drv[log_unit].LunID;
+ c->Header.LUN.LogDev.Mode = 1;
} else if (use_unit_num == 2) {
- memcpy(c->Header.LUN.LunAddrBytes,scsi3addr,8);
+ memcpy(c->Header.LUN.LunAddrBytes, scsi3addr,
+ 8);
c->Header.LUN.LogDev.Mode = 0;
}
/* are we trying to read a vital product page */
- if(page_code != 0) {
+ if (page_code != 0) {
c->Request.CDB[1] = 0x01;
c->Request.CDB[2] = page_code;
}
c->Request.CDBLen = 6;
- c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
- c->Request.CDB[0] = CISS_INQUIRY;
- c->Request.CDB[4] = size & 0xFF;
- break;
+ c->Request.CDB[0] = CISS_INQUIRY;
+ c->Request.CDB[4] = size & 0xFF;
+ break;
case CISS_REPORT_LOG:
case CISS_REPORT_PHYS:
- /* Talking to controller so It's a physical command
+ /* Talking to controller so It's a physical command
mode = 00 target = 0. Nothing to write.
- */
+ */
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
- c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
+ c->Request.CDB[6] = (size >> 24) & 0xFF; //MSB
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0xFF;
c->Request.CDB[9] = size & 0xFF;
@@ -1628,7 +1716,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
c->Request.Type.Direction = XFER_READ;
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
- break;
+ break;
case CCISS_CACHE_FLUSH:
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1636,32 +1724,32 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
c->Request.Timeout = 0;
c->Request.CDB[0] = BMIC_WRITE;
c->Request.CDB[6] = BMIC_CACHE_FLUSH;
- break;
+ break;
default:
printk(KERN_WARNING
- "cciss%d: Unknown Command 0x%c\n", ctlr, cmd);
- return(IO_ERROR);
+ "cciss%d: Unknown Command 0x%c\n", ctlr, cmd);
+ return IO_ERROR;
}
} else if (cmd_type == TYPE_MSG) {
switch (cmd) {
- case 0: /* ABORT message */
+ case 0: /* ABORT message */
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_WRITE;
c->Request.Timeout = 0;
- c->Request.CDB[0] = cmd; /* abort */
- c->Request.CDB[1] = 0; /* abort a command */
+ c->Request.CDB[0] = cmd; /* abort */
+ c->Request.CDB[1] = 0; /* abort a command */
/* buff contains the tag of the command to abort */
memcpy(&c->Request.CDB[4], buff, 8);
break;
- case 1: /* RESET message */
+ case 1: /* RESET message */
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction = XFER_WRITE;
c->Request.Timeout = 0;
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
- c->Request.CDB[0] = cmd; /* reset */
- c->Request.CDB[1] = 0x04; /* reset a LUN */
+ c->Request.CDB[0] = cmd; /* reset */
+ c->Request.CDB[1] = 0x04; /* reset a LUN */
case 3: /* No-Op message */
c->Request.CDBLen = 1;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1671,168 +1759,164 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
break;
default:
printk(KERN_WARNING
- "cciss%d: unknown message type %d\n",
- ctlr, cmd);
+ "cciss%d: unknown message type %d\n", ctlr, cmd);
return IO_ERROR;
}
} else {
printk(KERN_WARNING
- "cciss%d: unknown command type %d\n", ctlr, cmd_type);
+ "cciss%d: unknown command type %d\n", ctlr, cmd_type);
return IO_ERROR;
}
/* Fill in the scatter gather information */
if (size > 0) {
buff_dma_handle.val = (__u64) pci_map_single(h->pdev,
- buff, size, PCI_DMA_BIDIRECTIONAL);
+ buff, size,
+ PCI_DMA_BIDIRECTIONAL);
c->SG[0].Addr.lower = buff_dma_handle.val32.lower;
c->SG[0].Addr.upper = buff_dma_handle.val32.upper;
c->SG[0].Len = size;
- c->SG[0].Ext = 0; /* we are not chaining */
+ c->SG[0].Ext = 0; /* we are not chaining */
}
return status;
}
-static int sendcmd_withirq(__u8 cmd,
- int ctlr,
- void *buff,
- size_t size,
- unsigned int use_unit_num,
- unsigned int log_unit,
- __u8 page_code,
- int cmd_type)
+
+static int sendcmd_withirq(__u8 cmd,
+ int ctlr,
+ void *buff,
+ size_t size,
+ unsigned int use_unit_num,
+ unsigned int log_unit, __u8 page_code, int cmd_type)
{
ctlr_info_t *h = hba[ctlr];
CommandList_struct *c;
- u64bit buff_dma_handle;
+ u64bit buff_dma_handle;
unsigned long flags;
int return_status;
DECLARE_COMPLETION(wait);
-
- if ((c = cmd_alloc(h , 0)) == NULL)
+
+ if ((c = cmd_alloc(h, 0)) == NULL)
return -ENOMEM;
return_status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
- log_unit, page_code, NULL, cmd_type);
+ log_unit, page_code, NULL, cmd_type);
if (return_status != IO_OK) {
cmd_free(h, c, 0);
return return_status;
}
-resend_cmd2:
+ resend_cmd2:
c->waiting = &wait;
-
+
/* Put the request on the tail of the queue and send it */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
addQ(&h->reqQ, c);
h->Qdepth++;
start_io(h);
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-
+
wait_for_completion(&wait);
- if(c->err_info->CommandStatus != 0)
- { /* an error has occurred */
- switch(c->err_info->CommandStatus)
- {
- case CMD_TARGET_STATUS:
- printk(KERN_WARNING "cciss: cmd %p has "
- " completed with errors\n", c);
- if( c->err_info->ScsiStatus)
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status = %x\n",
- c,
- c->err_info->ScsiStatus);
- }
+ if (c->err_info->CommandStatus != 0) { /* an error has occurred */
+ switch (c->err_info->CommandStatus) {
+ case CMD_TARGET_STATUS:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ " completed with errors\n", c);
+ if (c->err_info->ScsiStatus) {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status = %x\n",
+ c, c->err_info->ScsiStatus);
+ }
break;
- case CMD_DATA_UNDERRUN:
- case CMD_DATA_OVERRUN:
+ case CMD_DATA_UNDERRUN:
+ case CMD_DATA_OVERRUN:
/* expected for inquire and report lun commands */
break;
- case CMD_INVALID:
- printk(KERN_WARNING "cciss: Cmd %p is "
- "reported invalid\n", c);
- return_status = IO_ERROR;
+ case CMD_INVALID:
+ printk(KERN_WARNING "cciss: Cmd %p is "
+ "reported invalid\n", c);
+ return_status = IO_ERROR;
break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cmd %p has "
- "protocol error \n", c);
- return_status = IO_ERROR;
- break;
-case CMD_HARDWARE_ERR:
- printk(KERN_WARNING "cciss: cmd %p had "
- " hardware error\n", c);
- return_status = IO_ERROR;
- break;
- case CMD_CONNECTION_LOST:
- printk(KERN_WARNING "cciss: cmd %p had "
- "connection lost\n", c);
- return_status = IO_ERROR;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "protocol error \n", c);
+ return_status = IO_ERROR;
break;
- case CMD_ABORTED:
- printk(KERN_WARNING "cciss: cmd %p was "
- "aborted\n", c);
- return_status = IO_ERROR;
+ case CMD_HARDWARE_ERR:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ " hardware error\n", c);
+ return_status = IO_ERROR;
break;
- case CMD_ABORT_FAILED:
- printk(KERN_WARNING "cciss: cmd %p reports "
- "abort failed\n", c);
- return_status = IO_ERROR;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ "connection lost\n", c);
+ return_status = IO_ERROR;
break;
- case CMD_UNSOLICITED_ABORT:
- printk(KERN_WARNING
- "cciss%d: unsolicited abort %p\n",
- ctlr, c);
- if (c->retry_count < MAX_CMD_RETRIES) {
- printk(KERN_WARNING
- "cciss%d: retrying %p\n",
- ctlr, c);
- c->retry_count++;
- /* erase the old error information */
- memset(c->err_info, 0,
- sizeof(ErrorInfo_struct));
- return_status = IO_OK;
- INIT_COMPLETION(wait);
- goto resend_cmd2;
- }
- return_status = IO_ERROR;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cmd %p was "
+ "aborted\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cmd %p reports "
+ "abort failed\n", c);
+ return_status = IO_ERROR;
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING
+ "cciss%d: unsolicited abort %p\n", ctlr, c);
+ if (c->retry_count < MAX_CMD_RETRIES) {
+ printk(KERN_WARNING
+ "cciss%d: retrying %p\n", ctlr, c);
+ c->retry_count++;
+ /* erase the old error information */
+ memset(c->err_info, 0,
+ sizeof(ErrorInfo_struct));
+ return_status = IO_OK;
+ INIT_COMPLETION(wait);
+ goto resend_cmd2;
+ }
+ return_status = IO_ERROR;
break;
- default:
- printk(KERN_WARNING "cciss: cmd %p returned "
- "unknown status %x\n", c,
- c->err_info->CommandStatus);
- return_status = IO_ERROR;
+ default:
+ printk(KERN_WARNING "cciss: cmd %p returned "
+ "unknown status %x\n", c,
+ c->err_info->CommandStatus);
+ return_status = IO_ERROR;
}
- }
+ }
/* unlock the buffers from DMA */
buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
- pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
- c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+ pci_unmap_single(h->pdev, (dma_addr_t) buff_dma_handle.val,
+ c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
cmd_free(h, c, 0);
- return(return_status);
-
+ return return_status;
}
+
static void cciss_geometry_inquiry(int ctlr, int logvol,
- int withirq, unsigned int total_size,
- unsigned int block_size, InquiryData_struct *inq_buff,
- drive_info_struct *drv)
+ int withirq, unsigned int total_size,
+ unsigned int block_size,
+ InquiryData_struct *inq_buff,
+ drive_info_struct *drv)
{
int return_code;
memset(inq_buff, 0, sizeof(InquiryData_struct));
if (withirq)
return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
- inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1, TYPE_CMD);
+ inq_buff, sizeof(*inq_buff), 1,
+ logvol, 0xC1, TYPE_CMD);
else
return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff,
- sizeof(*inq_buff), 1, logvol ,0xC1, NULL, TYPE_CMD);
+ sizeof(*inq_buff), 1, logvol, 0xC1, NULL,
+ TYPE_CMD);
if (return_code == IO_OK) {
- if(inq_buff->data_byte[8] == 0xFF) {
+ if (inq_buff->data_byte[8] == 0xFF) {
printk(KERN_WARNING
- "cciss: reading geometry failed, volume "
- "does not support reading geometry\n");
+ "cciss: reading geometry failed, volume "
+ "does not support reading geometry\n");
drv->block_size = block_size;
drv->nr_blocks = total_size;
drv->heads = 255;
- drv->sectors = 32; // Sectors per track
+ drv->sectors = 32; // Sectors per track
drv->cylinders = total_size / 255 / 32;
} else {
unsigned int t;
@@ -1846,37 +1930,42 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
drv->raid_level = inq_buff->data_byte[8];
t = drv->heads * drv->sectors;
if (t > 1) {
- drv->cylinders = total_size/t;
+ drv->cylinders = total_size / t;
}
}
- } else { /* Get geometry failed */
+ } else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed\n");
}
printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n",
- drv->heads, drv->sectors, drv->cylinders);
+ drv->heads, drv->sectors, drv->cylinders);
}
+
static void
cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
- int withirq, unsigned int *total_size, unsigned int *block_size)
+ int withirq, unsigned int *total_size,
+ unsigned int *block_size)
{
int return_code;
memset(buf, 0, sizeof(*buf));
if (withirq)
return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
- ctlr, buf, sizeof(*buf), 1, logvol, 0, TYPE_CMD);
+ ctlr, buf, sizeof(*buf), 1,
+ logvol, 0, TYPE_CMD);
else
return_code = sendcmd(CCISS_READ_CAPACITY,
- ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL, TYPE_CMD);
+ ctlr, buf, sizeof(*buf), 1, logvol, 0,
+ NULL, TYPE_CMD);
if (return_code == IO_OK) {
- *total_size = be32_to_cpu(*((__be32 *) &buf->total_size[0]))+1;
- *block_size = be32_to_cpu(*((__be32 *) &buf->block_size[0]));
- } else { /* read capacity command failed */
+ *total_size =
+ be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
+ *block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
+ } else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n");
*total_size = 0;
*block_size = BLOCK_SIZE;
}
printk(KERN_INFO " blocks= %u block_size= %d\n",
- *total_size, *block_size);
+ *total_size, *block_size);
return;
}
@@ -1885,38 +1974,38 @@ static int cciss_revalidate(struct gendisk *disk)
ctlr_info_t *h = get_host(disk);
drive_info_struct *drv = get_drv(disk);
int logvol;
- int FOUND=0;
+ int FOUND = 0;
unsigned int block_size;
unsigned int total_size;
ReadCapdata_struct *size_buff = NULL;
InquiryData_struct *inq_buff = NULL;
- for(logvol=0; logvol < CISS_MAX_LUN; logvol++)
- {
- if(h->drv[logvol].LunID == drv->LunID) {
- FOUND=1;
+ for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
+ if (h->drv[logvol].LunID == drv->LunID) {
+ FOUND = 1;
break;
}
}
- if (!FOUND) return 1;
+ if (!FOUND)
+ return 1;
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
- {
- printk(KERN_WARNING "cciss: out of memory\n");
- return 1;
- }
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
- if (inq_buff == NULL)
- {
- printk(KERN_WARNING "cciss: out of memory\n");
+ size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
+ return 1;
+ }
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
kfree(size_buff);
- return 1;
- }
+ return 1;
+ }
- cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size, &block_size);
- cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size, inq_buff, drv);
+ cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
+ &block_size);
+ cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
+ inq_buff, drv);
blk_queue_hardsect_size(drv->queue, drv->block_size);
set_capacity(disk, drv->nr_blocks);
@@ -1943,7 +2032,7 @@ static unsigned long pollcomplete(int ctlr)
if (done == FIFO_EMPTY)
schedule_timeout_uninterruptible(1);
else
- return (done);
+ return done;
}
/* Invalid address to tell caller we ran out of time */
return 1;
@@ -1952,28 +2041,28 @@ static unsigned long pollcomplete(int ctlr)
static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
{
/* We get in here if sendcmd() is polling for completions
- and gets some command back that it wasn't expecting --
- something other than that which it just sent down.
- Ordinarily, that shouldn't happen, but it can happen when
+ and gets some command back that it wasn't expecting --
+ something other than that which it just sent down.
+ Ordinarily, that shouldn't happen, but it can happen when
the scsi tape stuff gets into error handling mode, and
- starts using sendcmd() to try to abort commands and
+ starts using sendcmd() to try to abort commands and
reset tape drives. In that case, sendcmd may pick up
completions of commands that were sent to logical drives
- through the block i/o system, or cciss ioctls completing, etc.
+ through the block i/o system, or cciss ioctls completing, etc.
In that case, we need to save those completions for later
processing by the interrupt handler.
- */
+ */
#ifdef CONFIG_CISS_SCSI_TAPE
- struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
+ struct sendcmd_reject_list *srl = &hba[ctlr]->scsi_rejects;
/* If it's not the scsi tape stuff doing error handling, (abort */
/* or reset) then we don't expect anything weird. */
if (cmd != CCISS_RESET_MSG && cmd != CCISS_ABORT_MSG) {
#endif
- printk( KERN_WARNING "cciss cciss%d: SendCmd "
- "Invalid command list address returned! (%lx)\n",
- ctlr, complete);
+ printk(KERN_WARNING "cciss cciss%d: SendCmd "
+ "Invalid command list address returned! (%lx)\n",
+ ctlr, complete);
/* not much we can do. */
#ifdef CONFIG_CISS_SCSI_TAPE
return 1;
@@ -1984,7 +2073,7 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
if (srl->ncompletions >= (NR_CMDS + 2)) {
/* Uh oh. No room to save it for later... */
printk(KERN_WARNING "cciss%d: Sendcmd: Invalid command addr, "
- "reject list overflow, command lost!\n", ctlr);
+ "reject list overflow, command lost!\n", ctlr);
return 1;
}
/* Save it for later */
@@ -1995,340 +2084,327 @@ static int add_sendcmd_reject(__u8 cmd, int ctlr, unsigned long complete)
}
/*
- * Send a command to the controller, and wait for it to complete.
- * Only used at init time.
+ * Send a command to the controller, and wait for it to complete.
+ * Only used at init time.
*/
-static int sendcmd(
- __u8 cmd,
- int ctlr,
- void *buff,
- size_t size,
- unsigned int use_unit_num, /* 0: address the controller,
- 1: address logical volume log_unit,
- 2: periph device address is scsi3addr */
- unsigned int log_unit,
- __u8 page_code,
- unsigned char *scsi3addr,
- int cmd_type)
+static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller,
+ 1: address logical volume log_unit,
+ 2: periph device address is scsi3addr */
+ unsigned int log_unit,
+ __u8 page_code, unsigned char *scsi3addr, int cmd_type)
{
CommandList_struct *c;
int i;
unsigned long complete;
- ctlr_info_t *info_p= hba[ctlr];
+ ctlr_info_t *info_p = hba[ctlr];
u64bit buff_dma_handle;
int status, done = 0;
if ((c = cmd_alloc(info_p, 1)) == NULL) {
printk(KERN_WARNING "cciss: unable to get memory");
- return(IO_ERROR);
+ return IO_ERROR;
}
status = fill_cmd(c, cmd, ctlr, buff, size, use_unit_num,
- log_unit, page_code, scsi3addr, cmd_type);
+ log_unit, page_code, scsi3addr, cmd_type);
if (status != IO_OK) {
cmd_free(info_p, c, 1);
return status;
}
-resend_cmd1:
+ resend_cmd1:
/*
- * Disable interrupt
- */
+ * Disable interrupt
+ */
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: turning intr off\n");
-#endif /* CCISS_DEBUG */
- info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
-
+#endif /* CCISS_DEBUG */
+ info_p->access.set_intr_mask(info_p, CCISS_INTR_OFF);
+
/* Make sure there is room in the command FIFO */
- /* Actually it should be completely empty at this time */
+ /* Actually it should be completely empty at this time */
/* unless we are in here doing error handling for the scsi */
/* tape side of the driver. */
- for (i = 200000; i > 0; i--)
- {
+ for (i = 200000; i > 0; i--) {
/* if fifo isn't full go */
- if (!(info_p->access.fifo_full(info_p)))
- {
-
- break;
- }
- udelay(10);
- printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
- " waiting!\n", ctlr);
- }
- /*
- * Send the cmd
- */
- info_p->access.submit_command(info_p, c);
+ if (!(info_p->access.fifo_full(info_p))) {
+
+ break;
+ }
+ udelay(10);
+ printk(KERN_WARNING "cciss cciss%d: SendCmd FIFO full,"
+ " waiting!\n", ctlr);
+ }
+ /*
+ * Send the cmd
+ */
+ info_p->access.submit_command(info_p, c);
done = 0;
do {
complete = pollcomplete(ctlr);
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "cciss: command completed\n");
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
if (complete == 1) {
- printk( KERN_WARNING
- "cciss cciss%d: SendCmd Timeout out, "
- "No command list address returned!\n",
- ctlr);
+ printk(KERN_WARNING
+ "cciss cciss%d: SendCmd Timeout out, "
+ "No command list address returned!\n", ctlr);
status = IO_ERROR;
done = 1;
break;
}
/* This will need to change for direct lookup completions */
- if ( (complete & CISS_ERROR_BIT)
- && (complete & ~CISS_ERROR_BIT) == c->busaddr)
- {
- /* if data overrun or underun on Report command
- ignore it
- */
+ if ((complete & CISS_ERROR_BIT)
+ && (complete & ~CISS_ERROR_BIT) == c->busaddr) {
+ /* if data overrun or underun on Report command
+ ignore it
+ */
if (((c->Request.CDB[0] == CISS_REPORT_LOG) ||
(c->Request.CDB[0] == CISS_REPORT_PHYS) ||
(c->Request.CDB[0] == CISS_INQUIRY)) &&
- ((c->err_info->CommandStatus ==
- CMD_DATA_OVERRUN) ||
- (c->err_info->CommandStatus ==
- CMD_DATA_UNDERRUN)
- ))
- {
+ ((c->err_info->CommandStatus ==
+ CMD_DATA_OVERRUN) ||
+ (c->err_info->CommandStatus == CMD_DATA_UNDERRUN)
+ )) {
complete = c->busaddr;
} else {
if (c->err_info->CommandStatus ==
- CMD_UNSOLICITED_ABORT) {
+ CMD_UNSOLICITED_ABORT) {
printk(KERN_WARNING "cciss%d: "
- "unsolicited abort %p\n",
- ctlr, c);
+ "unsolicited abort %p\n",
+ ctlr, c);
if (c->retry_count < MAX_CMD_RETRIES) {
printk(KERN_WARNING
- "cciss%d: retrying %p\n",
- ctlr, c);
+ "cciss%d: retrying %p\n",
+ ctlr, c);
c->retry_count++;
/* erase the old error */
/* information */
memset(c->err_info, 0,
- sizeof(ErrorInfo_struct));
+ sizeof
+ (ErrorInfo_struct));
goto resend_cmd1;
} else {
printk(KERN_WARNING
- "cciss%d: retried %p too "
- "many times\n", ctlr, c);
+ "cciss%d: retried %p too "
+ "many times\n", ctlr, c);
status = IO_ERROR;
goto cleanup1;
}
- } else if (c->err_info->CommandStatus == CMD_UNABORTABLE) {
- printk(KERN_WARNING "cciss%d: command could not be aborted.\n", ctlr);
+ } else if (c->err_info->CommandStatus ==
+ CMD_UNABORTABLE) {
+ printk(KERN_WARNING
+ "cciss%d: command could not be aborted.\n",
+ ctlr);
status = IO_ERROR;
goto cleanup1;
}
printk(KERN_WARNING "ciss ciss%d: sendcmd"
- " Error %x \n", ctlr,
- c->err_info->CommandStatus);
+ " Error %x \n", ctlr,
+ c->err_info->CommandStatus);
printk(KERN_WARNING "ciss ciss%d: sendcmd"
- " offensive info\n"
- " size %x\n num %x value %x\n", ctlr,
- c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
- c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
- c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
+ " offensive info\n"
+ " size %x\n num %x value %x\n",
+ ctlr,
+ c->err_info->MoreErrInfo.Invalid_Cmd.
+ offense_size,
+ c->err_info->MoreErrInfo.Invalid_Cmd.
+ offense_num,
+ c->err_info->MoreErrInfo.Invalid_Cmd.
+ offense_value);
status = IO_ERROR;
goto cleanup1;
}
}
/* This will need changing for direct lookup completions */
- if (complete != c->busaddr) {
+ if (complete != c->busaddr) {
if (add_sendcmd_reject(cmd, ctlr, complete) != 0) {
- BUG(); /* we are pretty much hosed if we get here. */
+ BUG(); /* we are pretty much hosed if we get here. */
}
continue;
- } else
+ } else
done = 1;
- } while (!done);
-
-cleanup1:
+ } while (!done);
+
+ cleanup1:
/* unlock the data buffer from DMA */
buff_dma_handle.val32.lower = c->SG[0].Addr.lower;
buff_dma_handle.val32.upper = c->SG[0].Addr.upper;
pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
- c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
+ c->SG[0].Len, PCI_DMA_BIDIRECTIONAL);
#ifdef CONFIG_CISS_SCSI_TAPE
/* if we saved some commands for later, process them now. */
if (info_p->scsi_rejects.ncompletions > 0)
do_cciss_intr(0, info_p, NULL);
#endif
cmd_free(info_p, c, 1);
- return (status);
-}
+ return status;
+}
+
/*
* Map (physical) PCI mem into (virtual) kernel space
*/
static void __iomem *remap_pci_mem(ulong base, ulong size)
{
- ulong page_base = ((ulong) base) & PAGE_MASK;
- ulong page_offs = ((ulong) base) - page_base;
- void __iomem *page_remapped = ioremap(page_base, page_offs+size);
+ ulong page_base = ((ulong) base) & PAGE_MASK;
+ ulong page_offs = ((ulong) base) - page_base;
+ void __iomem *page_remapped = ioremap(page_base, page_offs + size);
- return page_remapped ? (page_remapped + page_offs) : NULL;
+ return page_remapped ? (page_remapped + page_offs) : NULL;
}
-/*
- * Takes jobs of the Q and sends them to the hardware, then puts it on
- * the Q to wait for completion.
- */
-static void start_io( ctlr_info_t *h)
+/*
+ * Takes jobs of the Q and sends them to the hardware, then puts it on
+ * the Q to wait for completion.
+ */
+static void start_io(ctlr_info_t *h)
{
CommandList_struct *c;
-
- while(( c = h->reqQ) != NULL )
- {
+
+ while ((c = h->reqQ) != NULL) {
/* can't do anything if fifo is full */
if ((h->access.fifo_full(h))) {
printk(KERN_WARNING "cciss: fifo full\n");
break;
}
- /* Get the first entry from the Request Q */
+ /* Get the first entry from the Request Q */
removeQ(&(h->reqQ), c);
h->Qdepth--;
-
- /* Tell the controller execute command */
+
+ /* Tell the controller execute command */
h->access.submit_command(h, c);
-
- /* Put job onto the completed Q */
- addQ (&(h->cmpQ), c);
+
+ /* Put job onto the completed Q */
+ addQ(&(h->cmpQ), c);
}
}
+
/* Assumes that CCISS_LOCK(h->ctlr) is held. */
/* Zeros out the error record and then resends the command back */
/* to the controller */
-static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+static inline void resend_cciss_cmd(ctlr_info_t *h, CommandList_struct *c)
{
/* erase the old error information */
memset(c->err_info, 0, sizeof(ErrorInfo_struct));
/* add it to software queue and then send it to the controller */
- addQ(&(h->reqQ),c);
+ addQ(&(h->reqQ), c);
h->Qdepth++;
- if(h->Qdepth > h->maxQsinceinit)
+ if (h->Qdepth > h->maxQsinceinit)
h->maxQsinceinit = h->Qdepth;
start_io(h);
}
-/* checks the status of the job and calls complete buffers to mark all
+/* checks the status of the job and calls complete buffers to mark all
* buffers for the completed job. Note that this function does not need
* to hold the hba/queue lock.
- */
-static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
- int timeout)
+ */
+static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd,
+ int timeout)
{
int status = 1;
int retry_cmd = 0;
-
+
if (timeout)
- status = 0;
+ status = 0;
- if(cmd->err_info->CommandStatus != 0)
- { /* an error has occurred */
- switch(cmd->err_info->CommandStatus)
- {
+ if (cmd->err_info->CommandStatus != 0) { /* an error has occurred */
+ switch (cmd->err_info->CommandStatus) {
unsigned char sense_key;
- case CMD_TARGET_STATUS:
- status = 0;
-
- if( cmd->err_info->ScsiStatus == 0x02)
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has CHECK CONDITION "
- " byte 2 = 0x%x\n", cmd,
- cmd->err_info->SenseInfo[2]
- );
- /* check the sense key */
- sense_key = 0xf &
- cmd->err_info->SenseInfo[2];
- /* no status or recovered error */
- if((sense_key == 0x0) ||
- (sense_key == 0x1))
- {
- status = 1;
- }
- } else
- {
- printk(KERN_WARNING "cciss: cmd %p "
- "has SCSI Status 0x%x\n",
- cmd, cmd->err_info->ScsiStatus);
+ case CMD_TARGET_STATUS:
+ status = 0;
+
+ if (cmd->err_info->ScsiStatus == 0x02) {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has CHECK CONDITION "
+ " byte 2 = 0x%x\n", cmd,
+ cmd->err_info->SenseInfo[2]
+ );
+ /* check the sense key */
+ sense_key = 0xf & cmd->err_info->SenseInfo[2];
+ /* no status or recovered error */
+ if ((sense_key == 0x0) || (sense_key == 0x1)) {
+ status = 1;
}
+ } else {
+ printk(KERN_WARNING "cciss: cmd %p "
+ "has SCSI Status 0x%x\n",
+ cmd, cmd->err_info->ScsiStatus);
+ }
break;
- case CMD_DATA_UNDERRUN:
- printk(KERN_WARNING "cciss: cmd %p has"
- " completed with data underrun "
- "reported\n", cmd);
+ case CMD_DATA_UNDERRUN:
+ printk(KERN_WARNING "cciss: cmd %p has"
+ " completed with data underrun "
+ "reported\n", cmd);
break;
- case CMD_DATA_OVERRUN:
- printk(KERN_WARNING "cciss: cmd %p has"
- " completed with data overrun "
- "reported\n", cmd);
+ case CMD_DATA_OVERRUN:
+ printk(KERN_WARNING "cciss: cmd %p has"
+ " completed with data overrun "
+ "reported\n", cmd);
break;
- case CMD_INVALID:
- printk(KERN_WARNING "cciss: cmd %p is "
- "reported invalid\n", cmd);
- status = 0;
+ case CMD_INVALID:
+ printk(KERN_WARNING "cciss: cmd %p is "
+ "reported invalid\n", cmd);
+ status = 0;
break;
- case CMD_PROTOCOL_ERR:
- printk(KERN_WARNING "cciss: cmd %p has "
- "protocol error \n", cmd);
- status = 0;
- break;
- case CMD_HARDWARE_ERR:
- printk(KERN_WARNING "cciss: cmd %p had "
- " hardware error\n", cmd);
- status = 0;
- break;
- case CMD_CONNECTION_LOST:
- printk(KERN_WARNING "cciss: cmd %p had "
- "connection lost\n", cmd);
- status=0;
+ case CMD_PROTOCOL_ERR:
+ printk(KERN_WARNING "cciss: cmd %p has "
+ "protocol error \n", cmd);
+ status = 0;
break;
- case CMD_ABORTED:
- printk(KERN_WARNING "cciss: cmd %p was "
- "aborted\n", cmd);
- status=0;
+ case CMD_HARDWARE_ERR:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ " hardware error\n", cmd);
+ status = 0;
break;
- case CMD_ABORT_FAILED:
- printk(KERN_WARNING "cciss: cmd %p reports "
- "abort failed\n", cmd);
- status=0;
+ case CMD_CONNECTION_LOST:
+ printk(KERN_WARNING "cciss: cmd %p had "
+ "connection lost\n", cmd);
+ status = 0;
break;
- case CMD_UNSOLICITED_ABORT:
- printk(KERN_WARNING "cciss%d: unsolicited "
- "abort %p\n", h->ctlr, cmd);
- if (cmd->retry_count < MAX_CMD_RETRIES) {
- retry_cmd=1;
- printk(KERN_WARNING
- "cciss%d: retrying %p\n",
- h->ctlr, cmd);
- cmd->retry_count++;
- } else
- printk(KERN_WARNING
- "cciss%d: %p retried too "
- "many times\n", h->ctlr, cmd);
- status=0;
+ case CMD_ABORTED:
+ printk(KERN_WARNING "cciss: cmd %p was "
+ "aborted\n", cmd);
+ status = 0;
+ break;
+ case CMD_ABORT_FAILED:
+ printk(KERN_WARNING "cciss: cmd %p reports "
+ "abort failed\n", cmd);
+ status = 0;
+ break;
+ case CMD_UNSOLICITED_ABORT:
+ printk(KERN_WARNING "cciss%d: unsolicited "
+ "abort %p\n", h->ctlr, cmd);
+ if (cmd->retry_count < MAX_CMD_RETRIES) {
+ retry_cmd = 1;
+ printk(KERN_WARNING
+ "cciss%d: retrying %p\n", h->ctlr, cmd);
+ cmd->retry_count++;
+ } else
+ printk(KERN_WARNING
+ "cciss%d: %p retried too "
+ "many times\n", h->ctlr, cmd);
+ status = 0;
break;
- case CMD_TIMEOUT:
- printk(KERN_WARNING "cciss: cmd %p timedout\n",
- cmd);
- status=0;
+ case CMD_TIMEOUT:
+ printk(KERN_WARNING "cciss: cmd %p timedout\n", cmd);
+ status = 0;
break;
- default:
- printk(KERN_WARNING "cciss: cmd %p returned "
- "unknown status %x\n", cmd,
- cmd->err_info->CommandStatus);
- status=0;
+ default:
+ printk(KERN_WARNING "cciss: cmd %p returned "
+ "unknown status %x\n", cmd,
+ cmd->err_info->CommandStatus);
+ status = 0;
}
}
/* We need to return this command */
- if(retry_cmd) {
- resend_cciss_cmd(h,cmd);
+ if (retry_cmd) {
+ resend_cciss_cmd(h, cmd);
return;
- }
+ }
cmd->rq->completion_data = cmd;
cmd->rq->errors = status;
@@ -2336,12 +2412,12 @@ static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
blk_complete_request(cmd->rq);
}
-/*
- * Get a request and submit it to the controller.
+/*
+ * Get a request and submit it to the controller.
*/
static void do_cciss_request(request_queue_t *q)
{
- ctlr_info_t *h= q->queuedata;
+ ctlr_info_t *h = q->queuedata;
CommandList_struct *c;
int start_blk, seg;
struct request *creq;
@@ -2352,18 +2428,18 @@ static void do_cciss_request(request_queue_t *q)
/* We call start_io here in case there is a command waiting on the
* queue that has not been sent.
- */
+ */
if (blk_queue_plugged(q))
goto startio;
-queue:
+ queue:
creq = elv_next_request(q);
if (!creq)
goto startio;
BUG_ON(creq->nr_phys_segments > MAXSGENTRIES);
- if (( c = cmd_alloc(h, 1)) == NULL)
+ if ((c = cmd_alloc(h, 1)) == NULL)
goto full;
blkdev_dequeue_request(creq);
@@ -2372,81 +2448,82 @@ queue:
c->cmd_type = CMD_RWREQ;
c->rq = creq;
-
- /* fill in the request */
+
+ /* fill in the request */
drv = creq->rq_disk->private_data;
- c->Header.ReplyQueue = 0; // unused in simple mode
+ c->Header.ReplyQueue = 0; // unused in simple mode
/* got command from pool, so use the command block index instead */
/* for direct lookups. */
/* The first 2 bits are reserved for controller error reporting. */
c->Header.Tag.lower = (c->cmdindex << 3);
- c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
- c->Header.LUN.LogDev.VolId= drv->LunID;
+ c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */
+ c->Header.LUN.LogDev.VolId = drv->LunID;
c->Header.LUN.LogDev.Mode = 1;
- c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
- c->Request.Type.Type = TYPE_CMD; // It is a command.
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction =
- (rq_data_dir(creq) == READ) ? XFER_READ: XFER_WRITE;
- c->Request.Timeout = 0; // Don't time out
- c->Request.CDB[0] = (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
+ c->Request.CDBLen = 10; // 12 byte commands not in FW yet;
+ c->Request.Type.Type = TYPE_CMD; // It is a command.
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction =
+ (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
+ c->Request.Timeout = 0; // Don't time out
+ c->Request.CDB[0] =
+ (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
start_blk = creq->sector;
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n",(int) creq->sector,
- (int) creq->nr_sectors);
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
+ (int)creq->nr_sectors);
+#endif /* CCISS_DEBUG */
seg = blk_rq_map_sg(q, creq, tmp_sg);
- /* get the DMA records for the setup */
+ /* get the DMA records for the setup */
if (c->Request.Type.Direction == XFER_READ)
dir = PCI_DMA_FROMDEVICE;
else
dir = PCI_DMA_TODEVICE;
- for (i=0; i<seg; i++)
- {
+ for (i = 0; i < seg; i++) {
c->SG[i].Len = tmp_sg[i].length;
temp64.val = (__u64) pci_map_page(h->pdev, tmp_sg[i].page,
- tmp_sg[i].offset, tmp_sg[i].length,
- dir);
+ tmp_sg[i].offset,
+ tmp_sg[i].length, dir);
c->SG[i].Addr.lower = temp64.val32.lower;
- c->SG[i].Addr.upper = temp64.val32.upper;
- c->SG[i].Ext = 0; // we are not chaining
+ c->SG[i].Addr.upper = temp64.val32.upper;
+ c->SG[i].Ext = 0; // we are not chaining
}
- /* track how many SG entries we are using */
- if( seg > h->maxSG)
- h->maxSG = seg;
+ /* track how many SG entries we are using */
+ if (seg > h->maxSG)
+ h->maxSG = seg;
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n", creq->nr_sectors, seg);
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "cciss: Submitting %d sectors in %d segments\n",
+ creq->nr_sectors, seg);
+#endif /* CCISS_DEBUG */
c->Header.SGList = c->Header.SGTotal = seg;
- c->Request.CDB[1]= 0;
- c->Request.CDB[2]= (start_blk >> 24) & 0xff; //MSB
- c->Request.CDB[3]= (start_blk >> 16) & 0xff;
- c->Request.CDB[4]= (start_blk >> 8) & 0xff;
- c->Request.CDB[5]= start_blk & 0xff;
- c->Request.CDB[6]= 0; // (sect >> 24) & 0xff; MSB
- c->Request.CDB[7]= (creq->nr_sectors >> 8) & 0xff;
- c->Request.CDB[8]= creq->nr_sectors & 0xff;
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
+ c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+ c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+ c->Request.CDB[5] = start_blk & 0xff;
+ c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
+ c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+ c->Request.CDB[8] = creq->nr_sectors & 0xff;
c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
spin_lock_irq(q->queue_lock);
- addQ(&(h->reqQ),c);
+ addQ(&(h->reqQ), c);
h->Qdepth++;
- if(h->Qdepth > h->maxQsinceinit)
- h->maxQsinceinit = h->Qdepth;
+ if (h->Qdepth > h->maxQsinceinit)
+ h->maxQsinceinit = h->Qdepth;
goto queue;
-full:
+ full:
blk_stop_queue(q);
-startio:
+ startio:
/* We will already have the driver lock here so not need
* to lock it.
- */
+ */
start_io(h);
}
@@ -2473,7 +2550,7 @@ static inline unsigned long get_next_completion(ctlr_info_t *h)
static inline int interrupt_pending(ctlr_info_t *h)
{
#ifdef CONFIG_CISS_SCSI_TAPE
- return ( h->access.intr_pending(h)
+ return (h->access.intr_pending(h)
|| (h->scsi_rejects.ncompletions > 0));
#else
return h->access.intr_pending(h);
@@ -2483,11 +2560,11 @@ static inline int interrupt_pending(ctlr_info_t *h)
static inline long interrupt_not_for_us(ctlr_info_t *h)
{
#ifdef CONFIG_CISS_SCSI_TAPE
- return (((h->access.intr_pending(h) == 0) ||
- (h->interrupts_enabled == 0))
- && (h->scsi_rejects.ncompletions == 0));
+ return (((h->access.intr_pending(h) == 0) ||
+ (h->interrupts_enabled == 0))
+ && (h->scsi_rejects.ncompletions == 0));
#else
- return (((h->access.intr_pending(h) == 0) ||
+ return (((h->access.intr_pending(h) == 0) ||
(h->interrupts_enabled == 0)));
#endif
}
@@ -2498,8 +2575,6 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
CommandList_struct *c;
unsigned long flags;
__u32 a, a1, a2;
- int j;
- int start_queue = h->next_to_run;
if (interrupt_not_for_us(h))
return IRQ_NONE;
@@ -2509,12 +2584,14 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
*/
spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags);
while (interrupt_pending(h)) {
- while((a = get_next_completion(h)) != FIFO_EMPTY) {
+ while ((a = get_next_completion(h)) != FIFO_EMPTY) {
a1 = a;
if ((a & 0x04)) {
a2 = (a >> 3);
if (a2 >= NR_CMDS) {
- printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr);
+ printk(KERN_WARNING
+ "cciss: controller cciss%d failed, stopping.\n",
+ h->ctlr);
fail_all_cmds(h->ctlr);
return IRQ_HANDLED;
}
@@ -2523,22 +2600,24 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
a = c->busaddr;
} else {
- a &= ~3;
+ a &= ~3;
if ((c = h->cmpQ) == NULL) {
- printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1);
- continue;
- }
- while(c->busaddr != a) {
- c = c->next;
- if (c == h->cmpQ)
- break;
- }
+ printk(KERN_WARNING
+ "cciss: Completion of %08x ignored\n",
+ a1);
+ continue;
+ }
+ while (c->busaddr != a) {
+ c = c->next;
+ if (c == h->cmpQ)
+ break;
+ }
}
/*
* If we've found the command, take it off the
* completion Q and free it
*/
- if (c->busaddr == a) {
+ if (c->busaddr == a) {
removeQ(&h->cmpQ, c);
if (c->cmd_type == CMD_RWREQ) {
complete_command(h, c, 0);
@@ -2554,130 +2633,79 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
}
}
- /* check to see if we have maxed out the number of commands that can
- * be placed on the queue. If so then exit. We do this check here
- * in case the interrupt we serviced was from an ioctl and did not
- * free any new commands.
- */
- if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- goto cleanup;
-
- /* We have room on the queue for more commands. Now we need to queue
- * them up. We will also keep track of the next queue to run so
- * that every queue gets a chance to be started first.
- */
- for (j=0; j < h->highest_lun + 1; j++){
- int curr_queue = (start_queue + j) % (h->highest_lun + 1);
- /* make sure the disk has been added and the drive is real
- * because this can be called from the middle of init_one.
- */
- if(!(h->drv[curr_queue].queue) ||
- !(h->drv[curr_queue].heads))
- continue;
- blk_start_queue(h->gendisk[curr_queue]->queue);
-
- /* check to see if we have maxed out the number of commands
- * that can be placed on the queue.
- */
- if ((find_first_zero_bit(h->cmd_pool_bits, NR_CMDS)) == NR_CMDS)
- {
- if (curr_queue == start_queue){
- h->next_to_run = (start_queue + 1) % (h->highest_lun + 1);
- goto cleanup;
- } else {
- h->next_to_run = curr_queue;
- goto cleanup;
- }
- } else {
- curr_queue = (curr_queue + 1) % (h->highest_lun + 1);
- }
- }
-
-cleanup:
spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags);
return IRQ_HANDLED;
}
-/*
- * We cannot read the structure directly, for portablity we must use
+
+/*
+ * We cannot read the structure directly, for portability we must use
* the io functions.
- * This is for debug only.
+ * This is for debug only.
*/
#ifdef CCISS_DEBUG
-static void print_cfg_table( CfgTable_struct *tb)
+static void print_cfg_table(CfgTable_struct *tb)
{
int i;
char temp_name[17];
printk("Controller Configuration information\n");
printk("------------------------------------\n");
- for(i=0;i<4;i++)
+ for (i = 0; i < 4; i++)
temp_name[i] = readb(&(tb->Signature[i]));
- temp_name[4]='\0';
- printk(" Signature = %s\n", temp_name);
+ temp_name[4] = '\0';
+ printk(" Signature = %s\n", temp_name);
printk(" Spec Number = %d\n", readl(&(tb->SpecValence)));
- printk(" Transport methods supported = 0x%x\n",
- readl(&(tb-> TransportSupport)));
- printk(" Transport methods active = 0x%x\n",
- readl(&(tb->TransportActive)));
- printk(" Requested transport Method = 0x%x\n",
- readl(&(tb->HostWrite.TransportRequest)));
- printk(" Coalese Interrupt Delay = 0x%x\n",
- readl(&(tb->HostWrite.CoalIntDelay)));
- printk(" Coalese Interrupt Count = 0x%x\n",
- readl(&(tb->HostWrite.CoalIntCount)));
- printk(" Max outstanding commands = 0x%d\n",
- readl(&(tb->CmdsOutMax)));
- printk(" Bus Types = 0x%x\n", readl(&(tb-> BusTypes)));
- for(i=0;i<16;i++)
+ printk(" Transport methods supported = 0x%x\n",
+ readl(&(tb->TransportSupport)));
+ printk(" Transport methods active = 0x%x\n",
+ readl(&(tb->TransportActive)));
+ printk(" Requested transport Method = 0x%x\n",
+ readl(&(tb->HostWrite.TransportRequest)));
+ printk(" Coalesce Interrupt Delay = 0x%x\n",
+ readl(&(tb->HostWrite.CoalIntDelay)));
+ printk(" Coalesce Interrupt Count = 0x%x\n",
+ readl(&(tb->HostWrite.CoalIntCount)));
+ printk(" Max outstanding commands = 0x%d\n",
+ readl(&(tb->CmdsOutMax)));
+ printk(" Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
+ for (i = 0; i < 16; i++)
temp_name[i] = readb(&(tb->ServerName[i]));
temp_name[16] = '\0';
printk(" Server Name = %s\n", temp_name);
- printk(" Heartbeat Counter = 0x%x\n\n\n",
- readl(&(tb->HeartBeat)));
+ printk(" Heartbeat Counter = 0x%x\n\n\n", readl(&(tb->HeartBeat)));
}
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
-static void release_io_mem(ctlr_info_t *c)
-{
- /* if IO mem was not protected do nothing */
- if( c->io_mem_addr == 0)
- return;
- release_region(c->io_mem_addr, c->io_mem_length);
- c->io_mem_addr = 0;
- c->io_mem_length = 0;
-}
-
-static int find_PCI_BAR_index(struct pci_dev *pdev,
- unsigned long pci_bar_addr)
+static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
{
int i, offset, mem_type, bar_type;
- if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
+ if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */
return 0;
offset = 0;
- for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
- bar_type = pci_resource_flags(pdev, i) &
- PCI_BASE_ADDRESS_SPACE;
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE;
if (bar_type == PCI_BASE_ADDRESS_SPACE_IO)
offset += 4;
else {
mem_type = pci_resource_flags(pdev, i) &
- PCI_BASE_ADDRESS_MEM_TYPE_MASK;
+ PCI_BASE_ADDRESS_MEM_TYPE_MASK;
switch (mem_type) {
- case PCI_BASE_ADDRESS_MEM_TYPE_32:
- case PCI_BASE_ADDRESS_MEM_TYPE_1M:
- offset += 4; /* 32 bit */
- break;
- case PCI_BASE_ADDRESS_MEM_TYPE_64:
- offset += 8;
- break;
- default: /* reserved in PCI 2.2 */
- printk(KERN_WARNING "Base address is invalid\n");
- return -1;
+ case PCI_BASE_ADDRESS_MEM_TYPE_32:
+ case PCI_BASE_ADDRESS_MEM_TYPE_1M:
+ offset += 4; /* 32 bit */
+ break;
+ case PCI_BASE_ADDRESS_MEM_TYPE_64:
+ offset += 8;
+ break;
+ default: /* reserved in PCI 2.2 */
+ printk(KERN_WARNING
+ "Base address is invalid\n");
+ return -1;
break;
}
}
- if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
- return i+1;
+ if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0)
+ return i + 1;
}
return -1;
}
@@ -2686,53 +2714,54 @@ static int find_PCI_BAR_index(struct pci_dev *pdev,
* controllers that are capable. If not, we use IO-APIC mode.
*/
-static void __devinit cciss_interrupt_mode(ctlr_info_t *c, struct pci_dev *pdev, __u32 board_id)
+static void __devinit cciss_interrupt_mode(ctlr_info_t *c,
+ struct pci_dev *pdev, __u32 board_id)
{
#ifdef CONFIG_PCI_MSI
- int err;
- struct msix_entry cciss_msix_entries[4] = {{0,0}, {0,1},
- {0,2}, {0,3}};
+ int err;
+ struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1},
+ {0, 2}, {0, 3}
+ };
/* Some boards advertise MSI but don't really support it */
if ((board_id == 0x40700E11) ||
- (board_id == 0x40800E11) ||
- (board_id == 0x40820E11) ||
- (board_id == 0x40830E11))
+ (board_id == 0x40800E11) ||
+ (board_id == 0x40820E11) || (board_id == 0x40830E11))
goto default_int_mode;
- if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
- err = pci_enable_msix(pdev, cciss_msix_entries, 4);
- if (!err) {
- c->intr[0] = cciss_msix_entries[0].vector;
- c->intr[1] = cciss_msix_entries[1].vector;
- c->intr[2] = cciss_msix_entries[2].vector;
- c->intr[3] = cciss_msix_entries[3].vector;
- c->msix_vector = 1;
- return;
- }
- if (err > 0) {
- printk(KERN_WARNING "cciss: only %d MSI-X vectors "
- "available\n", err);
- } else {
- printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
- err);
- }
- }
- if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
- if (!pci_enable_msi(pdev)) {
- c->intr[SIMPLE_MODE_INT] = pdev->irq;
- c->msi_vector = 1;
- return;
- } else {
- printk(KERN_WARNING "cciss: MSI init failed\n");
- c->intr[SIMPLE_MODE_INT] = pdev->irq;
- return;
- }
- }
-default_int_mode:
-#endif /* CONFIG_PCI_MSI */
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+ err = pci_enable_msix(pdev, cciss_msix_entries, 4);
+ if (!err) {
+ c->intr[0] = cciss_msix_entries[0].vector;
+ c->intr[1] = cciss_msix_entries[1].vector;
+ c->intr[2] = cciss_msix_entries[2].vector;
+ c->intr[3] = cciss_msix_entries[3].vector;
+ c->msix_vector = 1;
+ return;
+ }
+ if (err > 0) {
+ printk(KERN_WARNING "cciss: only %d MSI-X vectors "
+ "available\n", err);
+ } else {
+ printk(KERN_WARNING "cciss: MSI-X init failed %d\n",
+ err);
+ }
+ }
+ if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+ if (!pci_enable_msi(pdev)) {
+ c->intr[SIMPLE_MODE_INT] = pdev->irq;
+ c->msi_vector = 1;
+ return;
+ } else {
+ printk(KERN_WARNING "cciss: MSI init failed\n");
+ c->intr[SIMPLE_MODE_INT] = pdev->irq;
+ return;
+ }
+ }
+ default_int_mode:
+#endif /* CONFIG_PCI_MSI */
/* if we get here we're going to use the default interrupt mode */
- c->intr[SIMPLE_MODE_INT] = pdev->irq;
+ c->intr[SIMPLE_MODE_INT] = pdev->irq;
return;
}
@@ -2743,58 +2772,40 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
__u64 cfg_offset;
__u32 cfg_base_addr;
__u64 cfg_base_addr_index;
- int i;
+ int i, err;
/* check to see if controller has been disabled */
/* BEFORE trying to enable it */
- (void) pci_read_config_word(pdev, PCI_COMMAND,&command);
- if(!(command & 0x02))
- {
- printk(KERN_WARNING "cciss: controller appears to be disabled\n");
- return(-1);
+ (void)pci_read_config_word(pdev, PCI_COMMAND, &command);
+ if (!(command & 0x02)) {
+ printk(KERN_WARNING
+ "cciss: controller appears to be disabled\n");
+ return -ENODEV;
}
- if (pci_enable_device(pdev))
- {
+ err = pci_enable_device(pdev);
+ if (err) {
printk(KERN_ERR "cciss: Unable to Enable PCI device\n");
- return( -1);
+ return err;
+ }
+
+ err = pci_request_regions(pdev, "cciss");
+ if (err) {
+ printk(KERN_ERR "cciss: Cannot obtain PCI resources, "
+ "aborting\n");
+ goto err_out_disable_pdev;
}
subsystem_vendor_id = pdev->subsystem_vendor;
subsystem_device_id = pdev->subsystem_device;
board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
- subsystem_vendor_id);
-
- /* search for our IO range so we can protect it */
- for(i=0; i<DEVICE_COUNT_RESOURCE; i++)
- {
- /* is this an IO range */
- if( pci_resource_flags(pdev, i) & 0x01 ) {
- c->io_mem_addr = pci_resource_start(pdev, i);
- c->io_mem_length = pci_resource_end(pdev, i) -
- pci_resource_start(pdev, i) +1;
-#ifdef CCISS_DEBUG
- printk("IO value found base_addr[%d] %lx %lx\n", i,
- c->io_mem_addr, c->io_mem_length);
-#endif /* CCISS_DEBUG */
- /* register the IO range */
- if(!request_region( c->io_mem_addr,
- c->io_mem_length, "cciss"))
- {
- printk(KERN_WARNING "cciss I/O memory range already in use addr=%lx length=%ld\n",
- c->io_mem_addr, c->io_mem_length);
- c->io_mem_addr= 0;
- c->io_mem_length = 0;
- }
- break;
- }
- }
+ subsystem_vendor_id);
#ifdef CCISS_DEBUG
printk("command = %x\n", command);
printk("irq = %x\n", pdev->irq);
printk("board_id = %x\n", board_id);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
/* If the kernel supports MSI/MSI-X we will try to enable that functionality,
* else we use the IO-APIC interrupt assigned to us by system ROM.
@@ -2803,27 +2814,28 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
/*
* Memory base addr is first addr , the second points to the config
- * table
+ * table
*/
- c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
+ c->paddr = pci_resource_start(pdev, 0); /* addressing mode bits already removed */
#ifdef CCISS_DEBUG
printk("address 0 = %x\n", c->paddr);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
c->vaddr = remap_pci_mem(c->paddr, 200);
/* Wait for the board to become ready. (PCI hotplug needs this.)
* We poll for up to 120 secs, once per 100ms. */
- for (i=0; i < 1200; i++) {
+ for (i = 0; i < 1200; i++) {
scratchpad = readl(c->vaddr + SA5_SCRATCHPAD_OFFSET);
if (scratchpad == CCISS_FIRMWARE_READY)
break;
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 10); /* wait 100ms */
+ schedule_timeout(HZ / 10); /* wait 100ms */
}
if (scratchpad != CCISS_FIRMWARE_READY) {
printk(KERN_WARNING "cciss: Board not ready. Timed out.\n");
- return -1;
+ err = -ENODEV;
+ goto err_out_free_res;
}
/* get the address index number */
@@ -2831,103 +2843,108 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
cfg_base_addr &= (__u32) 0x0000ffff;
#ifdef CCISS_DEBUG
printk("cfg base address = %x\n", cfg_base_addr);
-#endif /* CCISS_DEBUG */
- cfg_base_addr_index =
- find_PCI_BAR_index(pdev, cfg_base_addr);
+#endif /* CCISS_DEBUG */
+ cfg_base_addr_index = find_PCI_BAR_index(pdev, cfg_base_addr);
#ifdef CCISS_DEBUG
printk("cfg base address index = %x\n", cfg_base_addr_index);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
if (cfg_base_addr_index == -1) {
printk(KERN_WARNING "cciss: Cannot find cfg_base_addr_index\n");
- release_io_mem(c);
- return -1;
+ err = -ENODEV;
+ goto err_out_free_res;
}
cfg_offset = readl(c->vaddr + SA5_CTMEM_OFFSET);
#ifdef CCISS_DEBUG
printk("cfg offset = %x\n", cfg_offset);
-#endif /* CCISS_DEBUG */
- c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
- cfg_base_addr_index) + cfg_offset,
- sizeof(CfgTable_struct));
+#endif /* CCISS_DEBUG */
+ c->cfgtable = remap_pci_mem(pci_resource_start(pdev,
+ cfg_base_addr_index) +
+ cfg_offset, sizeof(CfgTable_struct));
c->board_id = board_id;
#ifdef CCISS_DEBUG
print_cfg_table(c->cfgtable);
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
- for(i=0; i<NR_PRODUCTS; i++) {
+ for (i = 0; i < ARRAY_SIZE(products); i++) {
if (board_id == products[i].board_id) {
c->product_name = products[i].product_name;
c->access = *(products[i].access);
break;
}
}
- if (i == NR_PRODUCTS) {
+ if (i == ARRAY_SIZE(products)) {
printk(KERN_WARNING "cciss: Sorry, I don't know how"
- " to access the Smart Array controller %08lx\n",
- (unsigned long)board_id);
- return -1;
- }
- if ( (readb(&c->cfgtable->Signature[0]) != 'C') ||
- (readb(&c->cfgtable->Signature[1]) != 'I') ||
- (readb(&c->cfgtable->Signature[2]) != 'S') ||
- (readb(&c->cfgtable->Signature[3]) != 'S') )
- {
+ " to access the Smart Array controller %08lx\n",
+ (unsigned long)board_id);
+ err = -ENODEV;
+ goto err_out_free_res;
+ }
+ if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
+ (readb(&c->cfgtable->Signature[1]) != 'I') ||
+ (readb(&c->cfgtable->Signature[2]) != 'S') ||
+ (readb(&c->cfgtable->Signature[3]) != 'S')) {
printk("Does not appear to be a valid CISS config table\n");
- return -1;
+ err = -ENODEV;
+ goto err_out_free_res;
}
-
#ifdef CONFIG_X86
-{
- /* Need to enable prefetch in the SCSI core for 6400 in x86 */
- __u32 prefetch;
- prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
- prefetch |= 0x100;
- writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
-}
+ {
+ /* Need to enable prefetch in the SCSI core for 6400 in x86 */
+ __u32 prefetch;
+ prefetch = readl(&(c->cfgtable->SCSI_Prefetch));
+ prefetch |= 0x100;
+ writel(prefetch, &(c->cfgtable->SCSI_Prefetch));
+ }
#endif
#ifdef CCISS_DEBUG
printk("Trying to put board into Simple mode\n");
-#endif /* CCISS_DEBUG */
+#endif /* CCISS_DEBUG */
c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
- /* Update the field, and then ring the doorbell */
- writel( CFGTBL_Trans_Simple,
- &(c->cfgtable->HostWrite.TransportRequest));
- writel( CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
+ /* Update the field, and then ring the doorbell */
+ writel(CFGTBL_Trans_Simple, &(c->cfgtable->HostWrite.TransportRequest));
+ writel(CFGTBL_ChangeReq, c->vaddr + SA5_DOORBELL);
/* under certain very rare conditions, this can take awhile.
* (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
* as we enter this code.) */
- for(i=0;i<MAX_CONFIG_WAIT;i++) {
+ for (i = 0; i < MAX_CONFIG_WAIT; i++) {
if (!(readl(c->vaddr + SA5_DOORBELL) & CFGTBL_ChangeReq))
break;
/* delay and try again */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(10);
- }
+ }
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "I counter got to %d %x\n", i, readl(c->vaddr + SA5_DOORBELL));
-#endif /* CCISS_DEBUG */
+ printk(KERN_DEBUG "I counter got to %d %x\n", i,
+ readl(c->vaddr + SA5_DOORBELL));
+#endif /* CCISS_DEBUG */
#ifdef CCISS_DEBUG
- print_cfg_table(c->cfgtable);
-#endif /* CCISS_DEBUG */
+ print_cfg_table(c->cfgtable);
+#endif /* CCISS_DEBUG */
- if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
- {
+ if (!(readl(&(c->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) {
printk(KERN_WARNING "cciss: unable to get board into"
- " simple mode\n");
- return -1;
+ " simple mode\n");
+ err = -ENODEV;
+ goto err_out_free_res;
}
return 0;
+ err_out_free_res:
+ pci_release_regions(pdev);
+
+ err_out_disable_pdev:
+ pci_disable_device(pdev);
+ return err;
}
-/*
- * Gets information about the local volumes attached to the controller.
- */
+/*
+ * Gets information about the local volumes attached to the controller.
+ */
static void cciss_getgeometry(int cntl_num)
{
ReportLunData_struct *ld_buff;
@@ -2938,102 +2955,102 @@ static void cciss_getgeometry(int cntl_num)
int listlength = 0;
__u32 lunid = 0;
int block_size;
- int total_size;
+ int total_size;
ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
- if (ld_buff == NULL)
- {
+ if (ld_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
return;
}
- size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
- {
- printk(KERN_ERR "cciss: out of memory\n");
+ size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (size_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
+ kfree(ld_buff);
+ return;
+ }
+ inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
+ if (inq_buff == NULL) {
+ printk(KERN_ERR "cciss: out of memory\n");
kfree(ld_buff);
- return;
- }
- inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL);
- if (inq_buff == NULL)
- {
- printk(KERN_ERR "cciss: out of memory\n");
- kfree(ld_buff);
kfree(size_buff);
- return;
- }
- /* Get the firmware version */
- return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
- sizeof(InquiryData_struct), 0, 0 ,0, NULL, TYPE_CMD);
- if (return_code == IO_OK)
- {
+ return;
+ }
+ /* Get the firmware version */
+ return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff,
+ sizeof(InquiryData_struct), 0, 0, 0, NULL,
+ TYPE_CMD);
+ if (return_code == IO_OK) {
hba[cntl_num]->firm_ver[0] = inq_buff->data_byte[32];
hba[cntl_num]->firm_ver[1] = inq_buff->data_byte[33];
hba[cntl_num]->firm_ver[2] = inq_buff->data_byte[34];
hba[cntl_num]->firm_ver[3] = inq_buff->data_byte[35];
- } else /* send command failed */
- {
+ } else { /* send command failed */
+
printk(KERN_WARNING "cciss: unable to determine firmware"
- " version of controller\n");
+ " version of controller\n");
}
- /* Get the number of logical volumes */
- return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
- sizeof(ReportLunData_struct), 0, 0, 0, NULL, TYPE_CMD);
+ /* Get the number of logical volumes */
+ return_code = sendcmd(CISS_REPORT_LOG, cntl_num, ld_buff,
+ sizeof(ReportLunData_struct), 0, 0, 0, NULL,
+ TYPE_CMD);
- if( return_code == IO_OK)
- {
+ if (return_code == IO_OK) {
#ifdef CCISS_DEBUG
printk("LUN Data\n--------------------------\n");
-#endif /* CCISS_DEBUG */
-
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
- listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
+#endif /* CCISS_DEBUG */
+
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16;
+ listlength |=
+ (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8;
listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]);
- } else /* reading number of logical volumes failed */
- {
+ } else { /* reading number of logical volumes failed */
+
printk(KERN_WARNING "cciss: report logical volume"
- " command failed\n");
+ " command failed\n");
listlength = 0;
}
- hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
- if (hba[cntl_num]->num_luns > CISS_MAX_LUN)
- {
- printk(KERN_ERR "ciss: only %d number of logical volumes supported\n",
- CISS_MAX_LUN);
+ hba[cntl_num]->num_luns = listlength / 8; // 8 bytes pre entry
+ if (hba[cntl_num]->num_luns > CISS_MAX_LUN) {
+ printk(KERN_ERR
+ "ciss: only %d number of logical volumes supported\n",
+ CISS_MAX_LUN);
hba[cntl_num]->num_luns = CISS_MAX_LUN;
}
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0],
- ld_buff->LUNListLength[1], ld_buff->LUNListLength[2],
- ld_buff->LUNListLength[3], hba[cntl_num]->num_luns);
-#endif /* CCISS_DEBUG */
-
- hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1;
-// for(i=0; i< hba[cntl_num]->num_luns; i++)
- for(i=0; i < CISS_MAX_LUN; i++)
- {
- if (i < hba[cntl_num]->num_luns){
- lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
- << 24;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
- << 16;
- lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
- << 8;
- lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
-
- hba[cntl_num]->drv[i].LunID = lunid;
-
+ printk(KERN_DEBUG "Length = %x %x %x %x = %d\n",
+ ld_buff->LUNListLength[0], ld_buff->LUNListLength[1],
+ ld_buff->LUNListLength[2], ld_buff->LUNListLength[3],
+ hba[cntl_num]->num_luns);
+#endif /* CCISS_DEBUG */
+
+ hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
+// for(i=0; i< hba[cntl_num]->num_luns; i++)
+ for (i = 0; i < CISS_MAX_LUN; i++) {
+ if (i < hba[cntl_num]->num_luns) {
+ lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
+ << 24;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2]))
+ << 16;
+ lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1]))
+ << 8;
+ lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]);
+
+ hba[cntl_num]->drv[i].LunID = lunid;
#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i,
- ld_buff->LUN[i][0], ld_buff->LUN[i][1],
- ld_buff->LUN[i][2], ld_buff->LUN[i][3],
- hba[cntl_num]->drv[i].LunID);
-#endif /* CCISS_DEBUG */
- cciss_read_capacity(cntl_num, i, size_buff, 0,
- &total_size, &block_size);
+ printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i,
+ ld_buff->LUN[i][0], ld_buff->LUN[i][1],
+ ld_buff->LUN[i][2], ld_buff->LUN[i][3],
+ hba[cntl_num]->drv[i].LunID);
+#endif /* CCISS_DEBUG */
+ cciss_read_capacity(cntl_num, i, size_buff, 0,
+ &total_size, &block_size);
cciss_geometry_inquiry(cntl_num, i, 0, total_size,
- block_size, inq_buff, &hba[cntl_num]->drv[i]);
+ block_size, inq_buff,
+ &hba[cntl_num]->drv[i]);
} else {
/* initialize raid_level to indicate a free space */
hba[cntl_num]->drv[i].raid_level = -1;
@@ -3042,7 +3059,7 @@ static void cciss_getgeometry(int cntl_num)
kfree(ld_buff);
kfree(size_buff);
kfree(inq_buff);
-}
+}
/* Function to find the first free pointer into our hba[] array */
/* Returns -1 if no free entries are left. */
@@ -3056,7 +3073,7 @@ static int alloc_cciss_hba(void)
goto out;
}
- for(i=0; i< MAX_CTLR; i++) {
+ for (i = 0; i < MAX_CTLR; i++) {
if (!hba[i]) {
ctlr_info_t *p;
p = kzalloc(sizeof(ctlr_info_t), GFP_KERNEL);
@@ -3069,11 +3086,11 @@ static int alloc_cciss_hba(void)
}
}
printk(KERN_WARNING "cciss: This driver supports a maximum"
- " of %d controllers.\n", MAX_CTLR);
+ " of %d controllers.\n", MAX_CTLR);
goto out;
-Enomem:
+ Enomem:
printk(KERN_ERR "cciss: out of memory.\n");
-out:
+ out:
while (n--)
put_disk(disk[n]);
return -1;
@@ -3096,20 +3113,17 @@ static void free_hba(int i)
* returns the number of block devices registered.
*/
static int __devinit cciss_init_one(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
request_queue_t *q;
int i;
int j;
int rc;
+ int dac;
- printk(KERN_DEBUG "cciss: Device 0x%x has been found at"
- " bus %d dev %d func %d\n",
- pdev->device, pdev->bus->number, PCI_SLOT(pdev->devfn),
- PCI_FUNC(pdev->devfn));
i = alloc_cciss_hba();
- if(i < 0)
- return (-1);
+ if (i < 0)
+ return -1;
hba[i]->busy_initializing = 1;
@@ -3122,11 +3136,11 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
/* configure PCI DMA stuff */
if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK))
- printk("cciss: using DAC cycles\n");
+ dac = 1;
else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
- printk("cciss: not using DAC cycles\n");
+ dac = 0;
else {
- printk("cciss: no suitable DMA available\n");
+ printk(KERN_ERR "cciss: no suitable DMA available\n");
goto clean1;
}
@@ -3138,60 +3152,69 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
if (i < MAX_CTLR_ORIG)
hba[i]->major = COMPAQ_CISS_MAJOR + i;
rc = register_blkdev(hba[i]->major, hba[i]->devname);
- if(rc == -EBUSY || rc == -EINVAL) {
+ if (rc == -EBUSY || rc == -EINVAL) {
printk(KERN_ERR
- "cciss: Unable to get major number %d for %s "
- "on hba %d\n", hba[i]->major, hba[i]->devname, i);
+ "cciss: Unable to get major number %d for %s "
+ "on hba %d\n", hba[i]->major, hba[i]->devname, i);
goto clean1;
- }
- else {
+ } else {
if (i >= MAX_CTLR_ORIG)
hba[i]->major = rc;
}
/* make sure the board interrupts are off */
hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_OFF);
- if( request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
- SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
- hba[i]->devname, hba[i])) {
+ if (request_irq(hba[i]->intr[SIMPLE_MODE_INT], do_cciss_intr,
+ IRQF_DISABLED | IRQF_SHARED, hba[i]->devname, hba[i])) {
printk(KERN_ERR "cciss: Unable to get irq %d for %s\n",
- hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
+ hba[i]->intr[SIMPLE_MODE_INT], hba[i]->devname);
goto clean2;
}
- hba[i]->cmd_pool_bits = kmalloc(((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long), GFP_KERNEL);
- hba[i]->cmd_pool = (CommandList_struct *)pci_alloc_consistent(
- hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
- &(hba[i]->cmd_pool_dhandle));
- hba[i]->errinfo_pool = (ErrorInfo_struct *)pci_alloc_consistent(
- hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
- &(hba[i]->errinfo_pool_dhandle));
- if((hba[i]->cmd_pool_bits == NULL)
- || (hba[i]->cmd_pool == NULL)
- || (hba[i]->errinfo_pool == NULL)) {
- printk( KERN_ERR "cciss: out of memory");
+
+ printk(KERN_INFO "%s: <0x%x> at PCI %s IRQ %d%s using DAC\n",
+ hba[i]->devname, pdev->device, pci_name(pdev),
+ hba[i]->intr[SIMPLE_MODE_INT], dac ? "" : " not");
+
+ hba[i]->cmd_pool_bits =
+ kmalloc(((NR_CMDS + BITS_PER_LONG -
+ 1) / BITS_PER_LONG) * sizeof(unsigned long), GFP_KERNEL);
+ hba[i]->cmd_pool = (CommandList_struct *)
+ pci_alloc_consistent(hba[i]->pdev,
+ NR_CMDS * sizeof(CommandList_struct),
+ &(hba[i]->cmd_pool_dhandle));
+ hba[i]->errinfo_pool = (ErrorInfo_struct *)
+ pci_alloc_consistent(hba[i]->pdev,
+ NR_CMDS * sizeof(ErrorInfo_struct),
+ &(hba[i]->errinfo_pool_dhandle));
+ if ((hba[i]->cmd_pool_bits == NULL)
+ || (hba[i]->cmd_pool == NULL)
+ || (hba[i]->errinfo_pool == NULL)) {
+ printk(KERN_ERR "cciss: out of memory");
goto clean4;
}
#ifdef CONFIG_CISS_SCSI_TAPE
- hba[i]->scsi_rejects.complete =
- kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
- (NR_CMDS + 5), GFP_KERNEL);
+ hba[i]->scsi_rejects.complete =
+ kmalloc(sizeof(hba[i]->scsi_rejects.complete[0]) *
+ (NR_CMDS + 5), GFP_KERNEL);
if (hba[i]->scsi_rejects.complete == NULL) {
- printk( KERN_ERR "cciss: out of memory");
+ printk(KERN_ERR "cciss: out of memory");
goto clean4;
}
#endif
spin_lock_init(&hba[i]->lock);
- /* Initialize the pdev driver private data.
- have it point to hba[i]. */
+ /* Initialize the pdev driver private data.
+ have it point to hba[i]. */
pci_set_drvdata(pdev, hba[i]);
- /* command and error info recs zeroed out before
- they are used */
- memset(hba[i]->cmd_pool_bits, 0, ((NR_CMDS+BITS_PER_LONG-1)/BITS_PER_LONG)*sizeof(unsigned long));
+ /* command and error info recs zeroed out before
+ they are used */
+ memset(hba[i]->cmd_pool_bits, 0,
+ ((NR_CMDS + BITS_PER_LONG -
+ 1) / BITS_PER_LONG) * sizeof(unsigned long));
-#ifdef CCISS_DEBUG
- printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n",i);
-#endif /* CCISS_DEBUG */
+#ifdef CCISS_DEBUG
+ printk(KERN_DEBUG "Scanning for drives on controller cciss%d\n", i);
+#endif /* CCISS_DEBUG */
cciss_getgeometry(i);
@@ -3203,15 +3226,15 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
cciss_procinit(i);
hba[i]->busy_initializing = 0;
- for(j=0; j < NWD; j++) { /* mfm */
+ for (j = 0; j < NWD; j++) { /* mfm */
drive_info_struct *drv = &(hba[i]->drv[j]);
struct gendisk *disk = hba[i]->gendisk[j];
q = blk_init_queue(do_cciss_request, &hba[i]->lock);
if (!q) {
printk(KERN_ERR
- "cciss: unable to allocate queue for disk %d\n",
- j);
+ "cciss: unable to allocate queue for disk %d\n",
+ j);
break;
}
drv->queue = q;
@@ -3231,7 +3254,6 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
q->queuedata = hba[i];
sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
- sprintf(disk->devfs_name, "cciss/host%d/target%d", i, j);
disk->major = hba[i]->major;
disk->first_minor = j << NWD_SHIFT;
disk->fops = &cciss_fops;
@@ -3240,92 +3262,87 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
disk->driverfs_dev = &pdev->dev;
/* we must register the controller even if no disks exist */
/* this is for the online array utilities */
- if(!drv->heads && j)
+ if (!drv->heads && j)
continue;
blk_queue_hardsect_size(q, drv->block_size);
set_capacity(disk, drv->nr_blocks);
add_disk(disk);
}
- return(1);
+ return 1;
-clean4:
+ clean4:
#ifdef CONFIG_CISS_SCSI_TAPE
kfree(hba[i]->scsi_rejects.complete);
#endif
kfree(hba[i]->cmd_pool_bits);
- if(hba[i]->cmd_pool)
+ if (hba[i]->cmd_pool)
pci_free_consistent(hba[i]->pdev,
- NR_CMDS * sizeof(CommandList_struct),
- hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
- if(hba[i]->errinfo_pool)
+ NR_CMDS * sizeof(CommandList_struct),
+ hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
+ if (hba[i]->errinfo_pool)
pci_free_consistent(hba[i]->pdev,
- NR_CMDS * sizeof( ErrorInfo_struct),
- hba[i]->errinfo_pool,
- hba[i]->errinfo_pool_dhandle);
+ NR_CMDS * sizeof(ErrorInfo_struct),
+ hba[i]->errinfo_pool,
+ hba[i]->errinfo_pool_dhandle);
free_irq(hba[i]->intr[SIMPLE_MODE_INT], hba[i]);
-clean2:
+ clean2:
unregister_blkdev(hba[i]->major, hba[i]->devname);
-clean1:
- release_io_mem(hba[i]);
+ clean1:
hba[i]->busy_initializing = 0;
free_hba(i);
- return(-1);
+ return -1;
}
-static void __devexit cciss_remove_one (struct pci_dev *pdev)
+static void __devexit cciss_remove_one(struct pci_dev *pdev)
{
ctlr_info_t *tmp_ptr;
int i, j;
char flush_buf[4];
- int return_code;
+ int return_code;
- if (pci_get_drvdata(pdev) == NULL)
- {
- printk( KERN_ERR "cciss: Unable to remove device \n");
+ if (pci_get_drvdata(pdev) == NULL) {
+ printk(KERN_ERR "cciss: Unable to remove device \n");
return;
}
tmp_ptr = pci_get_drvdata(pdev);
i = tmp_ptr->ctlr;
- if (hba[i] == NULL)
- {
+ if (hba[i] == NULL) {
printk(KERN_ERR "cciss: device appears to "
- "already be removed \n");
+ "already be removed \n");
return;
}
/* Turn board interrupts off and send the flush cache command */
/* sendcmd will turn off interrupt, and send the flush...
- * To write all data in the battery backed cache to disks */
+ * To write all data in the battery backed cache to disks */
memset(flush_buf, 0, 4);
return_code = sendcmd(CCISS_CACHE_FLUSH, i, flush_buf, 4, 0, 0, 0, NULL,
- TYPE_CMD);
- if(return_code != IO_OK)
- {
- printk(KERN_WARNING "Error Flushing cache on controller %d\n",
- i);
+ TYPE_CMD);
+ if (return_code != IO_OK) {
+ printk(KERN_WARNING "Error Flushing cache on controller %d\n",
+ i);
}
free_irq(hba[i]->intr[2], hba[i]);
#ifdef CONFIG_PCI_MSI
- if (hba[i]->msix_vector)
- pci_disable_msix(hba[i]->pdev);
- else if (hba[i]->msi_vector)
- pci_disable_msi(hba[i]->pdev);
-#endif /* CONFIG_PCI_MSI */
+ if (hba[i]->msix_vector)
+ pci_disable_msix(hba[i]->pdev);
+ else if (hba[i]->msi_vector)
+ pci_disable_msi(hba[i]->pdev);
+#endif /* CONFIG_PCI_MSI */
- pci_set_drvdata(pdev, NULL);
iounmap(hba[i]->vaddr);
- cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
+ cciss_unregister_scsi(i); /* unhook from SCSI subsystem */
unregister_blkdev(hba[i]->major, hba[i]->devname);
- remove_proc_entry(hba[i]->devname, proc_cciss);
-
+ remove_proc_entry(hba[i]->devname, proc_cciss);
+
/* remove it from the disk list */
for (j = 0; j < NWD; j++) {
struct gendisk *disk = hba[i]->gendisk[j];
if (disk) {
request_queue_t *q = disk->queue;
- if (disk->flags & GENHD_FL_UP)
+ if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
if (q)
blk_cleanup_queue(q);
@@ -3334,26 +3351,28 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct),
hba[i]->cmd_pool, hba[i]->cmd_pool_dhandle);
- pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof( ErrorInfo_struct),
- hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
+ pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(ErrorInfo_struct),
+ hba[i]->errinfo_pool, hba[i]->errinfo_pool_dhandle);
kfree(hba[i]->cmd_pool_bits);
#ifdef CONFIG_CISS_SCSI_TAPE
kfree(hba[i]->scsi_rejects.complete);
#endif
- release_io_mem(hba[i]);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
free_hba(i);
-}
+}
static struct pci_driver cciss_pci_driver = {
- .name = "cciss",
- .probe = cciss_init_one,
- .remove = __devexit_p(cciss_remove_one),
- .id_table = cciss_pci_device_id, /* id_table */
+ .name = "cciss",
+ .probe = cciss_init_one,
+ .remove = __devexit_p(cciss_remove_one),
+ .id_table = cciss_pci_device_id, /* id_table */
};
/*
* This is it. Register the PCI driver information for the cards we control
- * the OS will call our registered routines when it finds one of our cards.
+ * the OS will call our registered routines when it finds one of our cards.
*/
static int __init cciss_init(void)
{
@@ -3369,12 +3388,10 @@ static void __exit cciss_cleanup(void)
pci_unregister_driver(&cciss_pci_driver);
/* double check that all controller entrys have been removed */
- for (i=0; i< MAX_CTLR; i++)
- {
- if (hba[i] != NULL)
- {
+ for (i = 0; i < MAX_CTLR; i++) {
+ if (hba[i] != NULL) {
printk(KERN_WARNING "cciss: had to remove"
- " controller %d\n", i);
+ " controller %d\n", i);
cciss_remove_one(hba[i]->pdev);
}
}
@@ -3389,21 +3406,21 @@ static void fail_all_cmds(unsigned long ctlr)
unsigned long flags;
printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr);
- h->alive = 0; /* the controller apparently died... */
+ h->alive = 0; /* the controller apparently died... */
spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
- pci_disable_device(h->pdev); /* Make sure it is really dead. */
+ pci_disable_device(h->pdev); /* Make sure it is really dead. */
/* move everything off the request queue onto the completed queue */
- while( (c = h->reqQ) != NULL ) {
+ while ((c = h->reqQ) != NULL) {
removeQ(&(h->reqQ), c);
h->Qdepth--;
- addQ (&(h->cmpQ), c);
+ addQ(&(h->cmpQ), c);
}
/* Now, fail everything on the completed queue with a HW error */
- while( (c = h->cmpQ) != NULL ) {
+ while ((c = h->cmpQ) != NULL) {
removeQ(&h->cmpQ, c);
c->err_info->CommandStatus = CMD_HARDWARE_ERR;
if (c->cmd_type == CMD_RWREQ) {
@@ -3411,8 +3428,8 @@ static void fail_all_cmds(unsigned long ctlr)
} else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
#ifdef CONFIG_CISS_SCSI_TAPE
- else if (c->cmd_type == CMD_SCSI)
- complete_scsi_command(c, 0, 0);
+ else if (c->cmd_type == CMD_SCSI)
+ complete_scsi_command(c, 0, 0);
#endif
}
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index b24fc0553cc..868e0d862b0 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -60,8 +60,6 @@ struct ctlr_info
__u32 board_id;
void __iomem *vaddr;
unsigned long paddr;
- unsigned long io_mem_addr;
- unsigned long io_mem_length;
CfgTable_struct __iomem *cfgtable;
int interrupts_enabled;
int major;
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index afdff32f672..05f79d7393f 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -251,10 +251,6 @@ scsi_cmd_stack_free(int ctlr)
stk->pool = NULL;
}
-/* scsi_device_types comes from scsi.h */
-#define DEVICETYPE(n) (n<0 || n>MAX_SCSI_DEVICE_CODE) ? \
- "Unknown" : scsi_device_types[n]
-
#if 0
static int xmargin=8;
static int amargin=60;
@@ -389,7 +385,7 @@ cciss_scsi_add_entry(int ctlr, int hostno,
time anyway (the scsi layer's inquiries will show that info) */
if (hostno != -1)
printk("cciss%d: %s device c%db%dt%dl%d added.\n",
- ctlr, DEVICETYPE(sd->devtype), hostno,
+ ctlr, scsi_device_type(sd->devtype), hostno,
sd->bus, sd->target, sd->lun);
return 0;
}
@@ -407,7 +403,7 @@ cciss_scsi_remove_entry(int ctlr, int hostno, int entry)
ccissscsi[ctlr].dev[i] = ccissscsi[ctlr].dev[i+1];
ccissscsi[ctlr].ndevices--;
printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
- ctlr, DEVICETYPE(sd.devtype), hostno,
+ ctlr, scsi_device_type(sd.devtype), hostno,
sd.bus, sd.target, sd.lun);
}
@@ -458,7 +454,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
if (found == 0) { /* device no longer present. */
changes++;
/* printk("cciss%d: %s device c%db%dt%dl%d removed.\n",
- ctlr, DEVICETYPE(csd->devtype), hostno,
+ ctlr, scsi_device_type(csd->devtype), hostno,
csd->bus, csd->target, csd->lun); */
cciss_scsi_remove_entry(ctlr, hostno, i);
/* note, i not incremented */
@@ -468,7 +464,7 @@ adjust_cciss_scsi_table(int ctlr, int hostno,
printk("cciss%d: device c%db%dt%dl%d type changed "
"(device type now %s).\n",
ctlr, hostno, csd->bus, csd->target, csd->lun,
- DEVICETYPE(csd->devtype));
+ scsi_device_type(csd->devtype));
csd->devtype = sd[j].devtype;
i++; /* so just move along. */
} else /* device is same as it ever was, */
@@ -1098,7 +1094,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno)
if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) {
printk(KERN_INFO "cciss%d: %s ignored, "
"too many devices.\n", cntl_num,
- DEVICETYPE(devtype));
+ scsi_device_type(devtype));
break;
}
memcpy(&currentsd[ncurrent].scsi3addr[0],
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index b6ea2f0c727..78082edc14b 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -33,7 +33,6 @@
#include <linux/blkpg.h>
#include <linux/timer.h>
#include <linux/proc_fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/init.h>
#include <linux/hdreg.h>
#include <linux/spinlock.h>
@@ -348,7 +347,6 @@ static void __devexit cpqarray_remove_one(int i)
for(j = 0; j < NWD; j++) {
if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
del_gendisk(ida_gendisk[i][j]);
- devfs_remove("ida/c%dd%d",i,j);
put_disk(ida_gendisk[i][j]);
}
blk_cleanup_queue(hba[i]->queue);
@@ -392,7 +390,7 @@ static void __devexit cpqarray_remove_one_eisa (int i)
}
/* pdev is NULL for eisa */
-static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
+static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
{
request_queue_t *q;
int j;
@@ -410,8 +408,7 @@ static int cpqarray_register_ctlr( int i, struct pci_dev *pdev)
}
hba[i]->access.set_intr_mask(hba[i], 0);
if (request_irq(hba[i]->intr, do_ida_intr,
- SA_INTERRUPT|SA_SHIRQ|SA_SAMPLE_RANDOM,
- hba[i]->devname, hba[i]))
+ IRQF_DISABLED|IRQF_SHARED, hba[i]->devname, hba[i]))
{
printk(KERN_ERR "cpqarray: Unable to get irq %d for %s\n",
hba[i]->intr, hba[i]->devname);
@@ -745,7 +742,7 @@ __setup("smart2=", cpqarray_setup);
/*
* Find an EISA controller's signature. Set up an hba if we find it.
*/
-static int cpqarray_eisa_detect(void)
+static int __init cpqarray_eisa_detect(void)
{
int i=0, j;
__u32 board_id;
@@ -1036,6 +1033,8 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
complete_buffers(cmd->rq->bio, ok);
+ add_disk_randomness(cmd->rq->rq_disk);
+
DBGPX(printk("Done with %p\n", cmd->rq););
end_that_request_last(cmd->rq, ok ? 1 : -EIO);
}
@@ -1740,8 +1739,6 @@ static void getgeometry(int ctlr)
(log_index < id_ctlr_buf->nr_drvs)
&& (log_unit < NWD);
log_unit++) {
- struct gendisk *disk = ida_gendisk[ctlr][log_unit];
-
size = sizeof(sense_log_drv_stat_t);
/*
@@ -1806,8 +1803,6 @@ static void getgeometry(int ctlr)
}
- sprintf(disk->devfs_name, "ida/c%dd%d", ctlr, log_unit);
-
info_p->phys_drives =
sense_config_buf->ctlr_phys_drv;
info_p->drv_assign_map
@@ -1843,7 +1838,6 @@ static void __exit cpqarray_exit(void)
}
}
- devfs_remove("ida");
remove_proc_entry("cpqarray", proc_root_driver);
}
diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c
index 3d4261c39f1..40535036e89 100644
--- a/drivers/block/cryptoloop.c
+++ b/drivers/block/cryptoloop.c
@@ -40,11 +40,13 @@ static int
cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
{
int err = -EINVAL;
+ int cipher_len;
+ int mode_len;
char cms[LO_NAME_SIZE]; /* cipher-mode string */
char *cipher;
char *mode;
char *cmsp = cms; /* c-m string pointer */
- struct crypto_tfm *tfm = NULL;
+ struct crypto_blkcipher *tfm;
/* encryption breaks for non sector aligned offsets */
@@ -53,20 +55,39 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
strncpy(cms, info->lo_crypt_name, LO_NAME_SIZE);
cms[LO_NAME_SIZE - 1] = 0;
- cipher = strsep(&cmsp, "-");
- mode = strsep(&cmsp, "-");
-
- if (mode == NULL || strcmp(mode, "cbc") == 0)
- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_CBC |
- CRYPTO_TFM_REQ_MAY_SLEEP);
- else if (strcmp(mode, "ecb") == 0)
- tfm = crypto_alloc_tfm(cipher, CRYPTO_TFM_MODE_ECB |
- CRYPTO_TFM_REQ_MAY_SLEEP);
- if (tfm == NULL)
+
+ cipher = cmsp;
+ cipher_len = strcspn(cmsp, "-");
+
+ mode = cmsp + cipher_len;
+ mode_len = 0;
+ if (*mode) {
+ mode++;
+ mode_len = strcspn(mode, "-");
+ }
+
+ if (!mode_len) {
+ mode = "cbc";
+ mode_len = 3;
+ }
+
+ if (cipher_len + mode_len + 3 > LO_NAME_SIZE)
return -EINVAL;
- err = tfm->crt_u.cipher.cit_setkey(tfm, info->lo_encrypt_key,
- info->lo_encrypt_key_size);
+ memmove(cms, mode, mode_len);
+ cmsp = cms + mode_len;
+ *cmsp++ = '(';
+ memcpy(cmsp, info->lo_crypt_name, cipher_len);
+ cmsp += cipher_len;
+ *cmsp++ = ')';
+ *cmsp = 0;
+
+ tfm = crypto_alloc_blkcipher(cms, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm))
+ return PTR_ERR(tfm);
+
+ err = crypto_blkcipher_setkey(tfm, info->lo_encrypt_key,
+ info->lo_encrypt_key_size);
if (err != 0)
goto out_free_tfm;
@@ -75,99 +96,49 @@ cryptoloop_init(struct loop_device *lo, const struct loop_info64 *info)
return 0;
out_free_tfm:
- crypto_free_tfm(tfm);
+ crypto_free_blkcipher(tfm);
out:
return err;
}
-typedef int (*encdec_ecb_t)(struct crypto_tfm *tfm,
+typedef int (*encdec_cbc_t)(struct blkcipher_desc *desc,
struct scatterlist *sg_out,
struct scatterlist *sg_in,
unsigned int nsg);
-
-static int
-cryptoloop_transfer_ecb(struct loop_device *lo, int cmd,
- struct page *raw_page, unsigned raw_off,
- struct page *loop_page, unsigned loop_off,
- int size, sector_t IV)
-{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
- struct scatterlist sg_out = { NULL, };
- struct scatterlist sg_in = { NULL, };
-
- encdec_ecb_t encdecfunc;
- struct page *in_page, *out_page;
- unsigned in_offs, out_offs;
-
- if (cmd == READ) {
- in_page = raw_page;
- in_offs = raw_off;
- out_page = loop_page;
- out_offs = loop_off;
- encdecfunc = tfm->crt_u.cipher.cit_decrypt;
- } else {
- in_page = loop_page;
- in_offs = loop_off;
- out_page = raw_page;
- out_offs = raw_off;
- encdecfunc = tfm->crt_u.cipher.cit_encrypt;
- }
-
- while (size > 0) {
- const int sz = min(size, LOOP_IV_SECTOR_SIZE);
-
- sg_in.page = in_page;
- sg_in.offset = in_offs;
- sg_in.length = sz;
-
- sg_out.page = out_page;
- sg_out.offset = out_offs;
- sg_out.length = sz;
-
- encdecfunc(tfm, &sg_out, &sg_in, sz);
-
- size -= sz;
- in_offs += sz;
- out_offs += sz;
- }
-
- return 0;
-}
-
-typedef int (*encdec_cbc_t)(struct crypto_tfm *tfm,
- struct scatterlist *sg_out,
- struct scatterlist *sg_in,
- unsigned int nsg, u8 *iv);
-
static int
-cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
- struct page *raw_page, unsigned raw_off,
- struct page *loop_page, unsigned loop_off,
- int size, sector_t IV)
+cryptoloop_transfer(struct loop_device *lo, int cmd,
+ struct page *raw_page, unsigned raw_off,
+ struct page *loop_page, unsigned loop_off,
+ int size, sector_t IV)
{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+ struct crypto_blkcipher *tfm = lo->key_data;
+ struct blkcipher_desc desc = {
+ .tfm = tfm,
+ .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
+ };
struct scatterlist sg_out = { NULL, };
struct scatterlist sg_in = { NULL, };
encdec_cbc_t encdecfunc;
struct page *in_page, *out_page;
unsigned in_offs, out_offs;
+ int err;
if (cmd == READ) {
in_page = raw_page;
in_offs = raw_off;
out_page = loop_page;
out_offs = loop_off;
- encdecfunc = tfm->crt_u.cipher.cit_decrypt_iv;
+ encdecfunc = crypto_blkcipher_crt(tfm)->decrypt;
} else {
in_page = loop_page;
in_offs = loop_off;
out_page = raw_page;
out_offs = raw_off;
- encdecfunc = tfm->crt_u.cipher.cit_encrypt_iv;
+ encdecfunc = crypto_blkcipher_crt(tfm)->encrypt;
}
while (size > 0) {
@@ -183,7 +154,10 @@ cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
sg_out.offset = out_offs;
sg_out.length = sz;
- encdecfunc(tfm, &sg_out, &sg_in, sz, (u8 *)iv);
+ desc.info = iv;
+ err = encdecfunc(&desc, &sg_out, &sg_in, sz);
+ if (err)
+ return err;
IV++;
size -= sz;
@@ -195,32 +169,6 @@ cryptoloop_transfer_cbc(struct loop_device *lo, int cmd,
}
static int
-cryptoloop_transfer(struct loop_device *lo, int cmd,
- struct page *raw_page, unsigned raw_off,
- struct page *loop_page, unsigned loop_off,
- int size, sector_t IV)
-{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
- if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_ECB)
- {
- lo->transfer = cryptoloop_transfer_ecb;
- return cryptoloop_transfer_ecb(lo, cmd, raw_page, raw_off,
- loop_page, loop_off, size, IV);
- }
- if(tfm->crt_cipher.cit_mode == CRYPTO_TFM_MODE_CBC)
- {
- lo->transfer = cryptoloop_transfer_cbc;
- return cryptoloop_transfer_cbc(lo, cmd, raw_page, raw_off,
- loop_page, loop_off, size, IV);
- }
-
- /* This is not supposed to happen */
-
- printk( KERN_ERR "cryptoloop: unsupported cipher mode in cryptoloop_transfer!\n");
- return -EINVAL;
-}
-
-static int
cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
{
return -EINVAL;
@@ -229,9 +177,9 @@ cryptoloop_ioctl(struct loop_device *lo, int cmd, unsigned long arg)
static int
cryptoloop_release(struct loop_device *lo)
{
- struct crypto_tfm *tfm = (struct crypto_tfm *) lo->key_data;
+ struct crypto_blkcipher *tfm = lo->key_data;
if (tfm != NULL) {
- crypto_free_tfm(tfm);
+ crypto_free_blkcipher(tfm);
lo->key_data = NULL;
return 0;
}
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index dff1e67b1dd..ad1d7065a1b 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -177,7 +177,6 @@ static int print_unex = 1;
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/platform_device.h>
#include <linux/buffer_head.h> /* for invalidate_buffers() */
#include <linux/mutex.h>
@@ -224,7 +223,6 @@ static struct completion device_release;
static unsigned short virtual_dma_port = 0x3f0;
irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int set_dor(int fdc, char mask, char data);
-static void register_devfs_entries(int drive) __init;
#define K_64 0x10000 /* 64KB */
@@ -251,18 +249,6 @@ static int irqdma_allocated;
#include <linux/cdrom.h> /* for the compatibility eject ioctl */
#include <linux/completion.h>
-/*
- * Interrupt freeing also means /proc VFS work - dont do it
- * from interrupt context. We push this work into keventd:
- */
-static void fd_free_irq_fn(void *data)
-{
- fd_free_irq();
-}
-
-static DECLARE_WORK(fd_free_irq_work, fd_free_irq_fn, NULL);
-
-
static struct request *current_req;
static struct request_queue *floppy_queue;
static void do_fd_request(request_queue_t * q);
@@ -828,15 +814,6 @@ static int set_dor(int fdc, char mask, char data)
UDRS->select_date = jiffies;
}
}
- /*
- * We should propagate failures to grab the resources back
- * nicely from here. Actually we ought to rewrite the fd
- * driver some day too.
- */
- if (newdor & FLOPPY_MOTOR_MASK)
- floppy_grab_irq_and_dma();
- if (olddor & FLOPPY_MOTOR_MASK)
- floppy_release_irq_and_dma();
return olddor;
}
@@ -894,8 +871,6 @@ static int _lock_fdc(int drive, int interruptible, int line)
line);
return -1;
}
- if (floppy_grab_irq_and_dma() == -1)
- return -EBUSY;
if (test_and_set_bit(0, &fdc_busy)) {
DECLARE_WAITQUEUE(wait, current);
@@ -917,6 +892,8 @@ static int _lock_fdc(int drive, int interruptible, int line)
set_current_state(TASK_RUNNING);
remove_wait_queue(&fdc_wait, &wait);
+
+ flush_scheduled_work();
}
command_status = FD_COMMAND_NONE;
@@ -950,7 +927,6 @@ static inline void unlock_fdc(void)
if (elv_next_request(floppy_queue))
do_fd_request(floppy_queue);
spin_unlock_irqrestore(&floppy_lock, flags);
- floppy_release_irq_and_dma();
wake_up(&fdc_wait);
}
@@ -3676,7 +3652,6 @@ static void __init config_types(void)
first = 0;
}
printk("%s fd%d is %s", prepend, drive, name);
- register_devfs_entries(drive);
}
*UDP = *params;
}
@@ -3697,8 +3672,8 @@ static int floppy_release(struct inode *inode, struct file *filp)
}
if (!UDRS->fd_ref)
opened_bdev[drive] = NULL;
- floppy_release_irq_and_dma();
mutex_unlock(&open_lock);
+
return 0;
}
@@ -3729,9 +3704,6 @@ static int floppy_open(struct inode *inode, struct file *filp)
if (UDRS->fd_ref == -1 || (UDRS->fd_ref && (filp->f_flags & O_EXCL)))
goto out2;
- if (floppy_grab_irq_and_dma())
- goto out2;
-
if (filp->f_flags & O_EXCL)
UDRS->fd_ref = -1;
else
@@ -3808,7 +3780,6 @@ out:
UDRS->fd_ref--;
if (!UDRS->fd_ref)
opened_bdev[drive] = NULL;
- floppy_release_irq_and_dma();
out2:
mutex_unlock(&open_lock);
return res;
@@ -3825,14 +3796,9 @@ static int check_floppy_change(struct gendisk *disk)
return 1;
if (time_after(jiffies, UDRS->last_checked + UDP->checkfreq)) {
- if (floppy_grab_irq_and_dma()) {
- return 1;
- }
-
lock_fdc(drive, 0);
poll_drive(0, 0);
process_fd_request();
- floppy_release_irq_and_dma();
}
if (UTESTF(FD_DISK_CHANGED) ||
@@ -3954,37 +3920,6 @@ static struct block_device_operations floppy_fops = {
.media_changed = check_floppy_change,
.revalidate_disk = floppy_revalidate,
};
-static char *table[] = {
- "", "d360", "h1200", "u360", "u720", "h360", "h720",
- "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410",
- "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743",
- "h880", "u1040", "u1120", "h1600", "u1760", "u1920",
- "u3200", "u3520", "u3840", "u1840", "u800", "u1600",
- NULL
-};
-static int t360[] = { 1, 0 },
- t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 },
- t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13,
- 17, 21, 22, 30, 0 };
-static int *table_sup[] =
- { NULL, t360, t1200, t3in + 5 + 8, t3in + 5, t3in, t3in };
-
-static void __init register_devfs_entries(int drive)
-{
- int base_minor = (drive < 4) ? drive : (124 + drive);
-
- if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
- int i = 0;
- do {
- int minor = base_minor + (table_sup[UDP->cmos][i] << 2);
-
- devfs_mk_bdev(MKDEV(FLOPPY_MAJOR, minor),
- S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |
- S_IWGRP, "floppy/%d%s", drive,
- table[table_sup[UDP->cmos][i]]);
- } while (table_sup[UDP->cmos][i++]);
- }
-}
/*
* Floppy Driver initialization
@@ -4242,6 +4177,11 @@ static int __init floppy_init(void)
int i, unit, drive;
int err, dr;
+#if defined(CONFIG_PPC_MERGE)
+ if (check_legacy_ioport(FDC1))
+ return -ENODEV;
+#endif
+
raw_cmd = NULL;
for (dr = 0; dr < N_DRIVE; dr++) {
@@ -4261,11 +4201,9 @@ static int __init floppy_init(void)
motor_off_timer[dr].function = motor_off_callback;
}
- devfs_mk_dir("floppy");
-
err = register_blkdev(FLOPPY_MAJOR, "fd");
if (err)
- goto out_devfs_remove;
+ goto out_put_disk;
floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
if (!floppy_queue) {
@@ -4301,13 +4239,6 @@ static int __init floppy_init(void)
}
use_virtual_dma = can_use_virtual_dma & 1;
-#if defined(CONFIG_PPC_MERGE)
- if (check_legacy_ioport(FDC1)) {
- del_timer(&fd_timeout);
- err = -ENODEV;
- goto out_unreg_region;
- }
-#endif
fdc_state[0].address = FDC1;
if (fdc_state[0].address == -1) {
del_timer(&fd_timeout);
@@ -4382,7 +4313,6 @@ static int __init floppy_init(void)
fdc = 0;
del_timer(&fd_timeout);
current_drive = 0;
- floppy_release_irq_and_dma();
initialising = 0;
if (have_no_fdc) {
DPRINT("no floppy controllers found\n");
@@ -4424,8 +4354,6 @@ out_unreg_region:
blk_cleanup_queue(floppy_queue);
out_unreg_blkdev:
unregister_blkdev(FLOPPY_MAJOR, "fd");
-out_devfs_remove:
- devfs_remove("floppy");
out_put_disk:
while (dr--) {
del_timer(&motor_off_timer[dr]);
@@ -4542,7 +4470,7 @@ static void floppy_release_irq_and_dma(void)
if (irqdma_allocated) {
fd_disable_dma();
fd_free_dma();
- schedule_work(&fd_free_irq_work);
+ fd_free_irq();
irqdma_allocated = 0;
}
set_dor(0, ~0, 8);
@@ -4586,19 +4514,6 @@ static void floppy_release_irq_and_dma(void)
static char *floppy;
-static void unregister_devfs_entries(int drive)
-{
- int i;
-
- if (UDP->cmos < ARRAY_SIZE(default_drive_params)) {
- i = 0;
- do {
- devfs_remove("floppy/%d%s", drive,
- table[table_sup[UDP->cmos][i]]);
- } while (table_sup[UDP->cmos][i++]);
- }
-}
-
static void __init parse_floppy_cfg_string(char *cfg)
{
char *ptr;
@@ -4635,13 +4550,11 @@ void cleanup_module(void)
if ((allowed_drive_mask & (1 << drive)) &&
fdc_state[FDC(drive)].version != FDC_NONE) {
del_gendisk(disks[drive]);
- unregister_devfs_entries(drive);
device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
platform_device_unregister(&floppy_device[drive]);
}
put_disk(disks[drive]);
}
- devfs_remove("floppy");
del_timer_sync(&fd_timeout);
del_timer_sync(&fd_timer);
@@ -4653,8 +4566,6 @@ void cleanup_module(void)
/* eject disk, if any */
fd_eject(0);
- flush_scheduled_work(); /* fd_free_irq() might be pending */
-
wait_for_completion(&device_release);
}
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 3c74ea729fc..68b0471ad5a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -50,7 +50,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
@@ -63,7 +62,6 @@
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#include <linux/swap.h>
#include <linux/slab.h>
@@ -74,6 +72,7 @@
#include <linux/completion.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
+#include <linux/kthread.h>
#include <asm/uaccess.h>
@@ -210,7 +209,7 @@ static int do_lo_send_aops(struct loop_device *lo, struct bio_vec *bvec,
{
struct file *file = lo->lo_backing_file; /* kudos to NFsckingS */
struct address_space *mapping = file->f_mapping;
- struct address_space_operations *aops = mapping->a_ops;
+ const struct address_space_operations *aops = mapping->a_ops;
pgoff_t index;
unsigned offset, bv_offs;
int len, ret;
@@ -524,15 +523,12 @@ static int loop_make_request(request_queue_t *q, struct bio *old_bio)
goto out;
if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY)))
goto out;
- lo->lo_pending++;
loop_add_bio(lo, old_bio);
+ wake_up(&lo->lo_event);
spin_unlock_irq(&lo->lo_lock);
- complete(&lo->lo_bh_done);
return 0;
out:
- if (lo->lo_pending == 0)
- complete(&lo->lo_bh_done);
spin_unlock_irq(&lo->lo_lock);
bio_io_error(old_bio, old_bio->bi_size);
return 0;
@@ -572,14 +568,18 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
* to avoid blocking in our make_request_fn. it also does loop decrypting
* on reads for block backed loop, as that is too heavy to do from
* b_end_io context where irqs may be disabled.
+ *
+ * Loop explanation: loop_clr_fd() sets lo_state to Lo_rundown before
+ * calling kthread_stop(). Therefore once kthread_should_stop() is
+ * true, make_request will not place any more requests. Therefore
+ * once kthread_should_stop() is true and lo_bio is NULL, we are
+ * done with the loop.
*/
static int loop_thread(void *data)
{
struct loop_device *lo = data;
struct bio *bio;
- daemonize("loop%d", lo->lo_number);
-
/*
* loop can be used in an encrypted device,
* hence, it mustn't be stopped at all
@@ -589,47 +589,21 @@ static int loop_thread(void *data)
set_user_nice(current, -20);
- lo->lo_state = Lo_bound;
- lo->lo_pending = 1;
-
- /*
- * complete it, we are running
- */
- complete(&lo->lo_done);
+ while (!kthread_should_stop() || lo->lo_bio) {
- for (;;) {
- int pending;
+ wait_event_interruptible(lo->lo_event,
+ lo->lo_bio || kthread_should_stop());
- if (wait_for_completion_interruptible(&lo->lo_bh_done))
+ if (!lo->lo_bio)
continue;
-
spin_lock_irq(&lo->lo_lock);
-
- /*
- * could be completed because of tear-down, not pending work
- */
- if (unlikely(!lo->lo_pending)) {
- spin_unlock_irq(&lo->lo_lock);
- break;
- }
-
bio = loop_get_bio(lo);
- lo->lo_pending--;
- pending = lo->lo_pending;
spin_unlock_irq(&lo->lo_lock);
BUG_ON(!bio);
loop_handle_bio(lo, bio);
-
- /*
- * upped both for pending work and tear-down, lo_pending
- * will hit zero then
- */
- if (unlikely(!pending))
- break;
}
- complete(&lo->lo_done);
return 0;
}
@@ -664,7 +638,8 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
lo->lo_backing_file = file;
- lo->lo_blocksize = mapping->host->i_blksize;
+ lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
+ mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
lo->old_gfp_mask = mapping_gfp_mask(mapping);
mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
complete(&p->wait);
@@ -784,7 +759,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
error = -EINVAL;
if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
- struct address_space_operations *aops = mapping->a_ops;
+ const struct address_space_operations *aops = mapping->a_ops;
/*
* If we can't read - sorry. If we only can't write - well,
* it's going to be read-only.
@@ -796,7 +771,9 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
lo_flags |= LO_FLAGS_READ_ONLY;
- lo_blocksize = inode->i_blksize;
+ lo_blocksize = S_ISBLK(inode->i_mode) ?
+ inode->i_bdev->bd_block_size : PAGE_SIZE;
+
error = 0;
} else {
goto out_putf;
@@ -839,12 +816,26 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
set_blocksize(bdev, lo_blocksize);
- error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
- if (error < 0)
- goto out_putf;
- wait_for_completion(&lo->lo_done);
+ lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
+ lo->lo_number);
+ if (IS_ERR(lo->lo_thread)) {
+ error = PTR_ERR(lo->lo_thread);
+ goto out_clr;
+ }
+ lo->lo_state = Lo_bound;
+ wake_up_process(lo->lo_thread);
return 0;
+out_clr:
+ lo->lo_thread = NULL;
+ lo->lo_device = NULL;
+ lo->lo_backing_file = NULL;
+ lo->lo_flags = 0;
+ set_capacity(disks[lo->lo_number], 0);
+ invalidate_bdev(bdev, 0);
+ bd_set_size(bdev, 0);
+ mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
+ lo->lo_state = Lo_unbound;
out_putf:
fput(file);
out:
@@ -906,12 +897,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
spin_lock_irq(&lo->lo_lock);
lo->lo_state = Lo_rundown;
- lo->lo_pending--;
- if (!lo->lo_pending)
- complete(&lo->lo_bh_done);
spin_unlock_irq(&lo->lo_lock);
- wait_for_completion(&lo->lo_done);
+ kthread_stop(lo->lo_thread);
lo->lo_backing_file = NULL;
@@ -924,6 +912,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
lo->lo_sizelimit = 0;
lo->lo_encrypt_key_size = 0;
lo->lo_flags = 0;
+ lo->lo_thread = NULL;
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1277,8 +1266,6 @@ static int __init loop_init(void)
goto out_mem3;
}
- devfs_mk_dir("loop");
-
for (i = 0; i < max_loop; i++) {
struct loop_device *lo = &loop_dev[i];
struct gendisk *disk = disks[i];
@@ -1288,15 +1275,14 @@ static int __init loop_init(void)
if (!lo->lo_queue)
goto out_mem4;
mutex_init(&lo->lo_ctl_mutex);
- init_completion(&lo->lo_done);
- init_completion(&lo->lo_bh_done);
lo->lo_number = i;
+ lo->lo_thread = NULL;
+ init_waitqueue_head(&lo->lo_event);
spin_lock_init(&lo->lo_lock);
disk->major = LOOP_MAJOR;
disk->first_minor = i;
disk->fops = &lo_fops;
sprintf(disk->disk_name, "loop%d", i);
- sprintf(disk->devfs_name, "loop/%d", i);
disk->private_data = lo;
disk->queue = lo->lo_queue;
}
@@ -1310,7 +1296,6 @@ static int __init loop_init(void)
out_mem4:
while (i--)
blk_cleanup_queue(loop_dev[i].lo_queue);
- devfs_remove("loop");
i = max_loop;
out_mem3:
while (i--)
@@ -1333,7 +1318,6 @@ static void loop_exit(void)
blk_cleanup_queue(loop_dev[i].lo_queue);
put_disk(disks[i]);
}
- devfs_remove("loop");
if (unregister_blkdev(LOOP_MAJOR, "loop"))
printk(KERN_WARNING "loop: cannot unregister blkdev\n");
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 8bca4905d7f..bdbade9a5cf 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -7,39 +7,9 @@
* Copyright 1997-2000 Pavel Machek <pavel@ucw.cz>
* Parts copyright 2001 Steven Whitehouse <steve@chygwyn.com>
*
- * (part of code stolen from loop.c)
+ * This file is released under GPLv2 or later.
*
- * 97-3-25 compiled 0-th version, not yet tested it
- * (it did not work, BTW) (later that day) HEY! it works!
- * (bit later) hmm, not that much... 2:00am next day:
- * yes, it works, but it gives something like 50kB/sec
- * 97-4-01 complete rewrite to make it possible for many requests at
- * once to be processed
- * 97-4-11 Making protocol independent of endianity etc.
- * 97-9-13 Cosmetic changes
- * 98-5-13 Attempt to make 64-bit-clean on 64-bit machines
- * 99-1-11 Attempt to make 64-bit-clean on 32-bit machines <ankry@mif.pg.gda.pl>
- * 01-2-27 Fix to store proper blockcount for kernel (calculated using
- * BLOCK_SIZE_BITS, not device blocksize) <aga@permonline.ru>
- * 01-3-11 Make nbd work with new Linux block layer code. It now supports
- * plugging like all the other block devices. Also added in MSG_MORE to
- * reduce number of partial TCP segments sent. <steve@chygwyn.com>
- * 01-12-6 Fix deadlock condition by making queue locks independent of
- * the transmit lock. <steve@chygwyn.com>
- * 02-10-11 Allow hung xmit to be aborted via SIGKILL & various fixes.
- * <Paul.Clements@SteelEye.com> <James.Bottomley@SteelEye.com>
- * 03-06-22 Make nbd work with new linux 2.5 block layer design. This fixes
- * memory corruption from module removal and possible memory corruption
- * from sending/receiving disk data. <ldl@aros.net>
- * 03-06-23 Cosmetic changes. <ldl@aros.net>
- * 03-06-23 Enhance diagnostics support. <ldl@aros.net>
- * 03-06-24 Remove unneeded blksize_bits field from nbd_device struct.
- * <ldl@aros.net>
- * 03-06-24 Cleanup PARANOIA usage & code. <ldl@aros.net>
- * 04-02-19 Remove PARANOIA, plus various cleanups (Paul Clements)
- * possible FIXME: make set_sock / set_blksize / set_size / do_it one syscall
- * why not: would need access_ok and friends, would share yet another
- * structure with userland
+ * (part of code stolen from loop.c)
*/
#include <linux/major.h>
@@ -59,8 +29,6 @@
#include <linux/kernel.h>
#include <net/sock.h>
-#include <linux/devfs_fs_kernel.h>
-
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/types.h>
@@ -82,9 +50,9 @@
#define DBG_RX 0x0200
#define DBG_TX 0x0400
static unsigned int debugflags;
-static unsigned int nbds_max = 16;
#endif /* NDEBUG */
+static unsigned int nbds_max = 16;
static struct nbd_device nbd_dev[MAX_NBD];
/*
@@ -332,6 +300,15 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
lo->disk->disk_name, result);
goto harderror;
}
+
+ if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
+ printk(KERN_ERR "%s: Wrong magic (0x%lx)\n",
+ lo->disk->disk_name,
+ (unsigned long)ntohl(reply.magic));
+ result = -EPROTO;
+ goto harderror;
+ }
+
req = nbd_find_request(lo, reply.handle);
if (unlikely(IS_ERR(req))) {
result = PTR_ERR(req);
@@ -344,13 +321,6 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
goto harderror;
}
- if (ntohl(reply.magic) != NBD_REPLY_MAGIC) {
- printk(KERN_ERR "%s: Wrong magic (0x%lx)\n",
- lo->disk->disk_name,
- (unsigned long)ntohl(reply.magic));
- result = -EPROTO;
- goto harderror;
- }
if (ntohl(reply.error)) {
printk(KERN_ERR "%s: Other side returned error (%d)\n",
lo->disk->disk_name, ntohl(reply.error));
@@ -371,7 +341,8 @@ static struct request *nbd_read_stat(struct nbd_device *lo)
printk(KERN_ERR "%s: Receive data failed (result %d)\n",
lo->disk->disk_name,
result);
- goto harderror;
+ req->errors++;
+ return req;
}
dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
lo->disk->disk_name, req, bvec->bv_len);
@@ -672,7 +643,6 @@ static int __init nbd_init(void)
printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);
dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags);
- devfs_mk_dir("nbd");
for (i = 0; i < nbds_max; i++) {
struct gendisk *disk = nbd_dev[i].disk;
nbd_dev[i].file = NULL;
@@ -690,7 +660,6 @@ static int __init nbd_init(void)
disk->private_data = &nbd_dev[i];
disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "nbd%d", i);
- sprintf(disk->devfs_name, "nbd/%d", i);
set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */
add_disk(disk);
}
@@ -716,7 +685,6 @@ static void __exit nbd_cleanup(void)
put_disk(disk);
}
}
- devfs_remove("nbd");
unregister_blkdev(NBD_MAJOR, "nbd");
printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR);
}
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
index ce94aa11f6a..4b258f7836f 100644
--- a/drivers/block/paride/paride.c
+++ b/drivers/block/paride/paride.c
@@ -21,7 +21,6 @@
#define PI_VERSION "1.06"
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index 852b564e903..1a9dee19efc 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -707,7 +707,7 @@ static int pf_detect(void)
if (pi_init(pf->pi, 0, conf[D_PRT], conf[D_MOD],
conf[D_UNI], conf[D_PRO], conf[D_DLY],
pf_scratch, PI_PF, verbose, pf->name)) {
- if (!pf_probe(pf) && pf->disk) {
+ if (pf->disk && !pf_probe(pf)) {
pf->present = 1;
k++;
} else
diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
index 79b86825403..13f998aa1cd 100644
--- a/drivers/block/paride/pg.c
+++ b/drivers/block/paride/pg.c
@@ -156,7 +156,6 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY};
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtio.h>
@@ -674,25 +673,15 @@ static int __init pg_init(void)
err = PTR_ERR(pg_class);
goto out_chrdev;
}
- devfs_mk_dir("pg");
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
- if (dev->present) {
+ if (dev->present)
class_device_create(pg_class, NULL, MKDEV(major, unit),
NULL, "pg%u", unit);
- err = devfs_mk_cdev(MKDEV(major, unit),
- S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u",
- unit);
- if (err)
- goto out_class;
- }
}
err = 0;
goto out;
-out_class:
- class_device_destroy(pg_class, MKDEV(major, unit));
- class_destroy(pg_class);
out_chrdev:
unregister_chrdev(major, "pg");
out:
@@ -705,13 +694,10 @@ static void __exit pg_exit(void)
for (unit = 0; unit < PG_UNITS; unit++) {
struct pg *dev = &devices[unit];
- if (dev->present) {
+ if (dev->present)
class_device_destroy(pg_class, MKDEV(major, unit));
- devfs_remove("pg/%u", unit);
- }
}
class_destroy(pg_class);
- devfs_remove("pg");
unregister_chrdev(major, name);
for (unit = 0; unit < PG_UNITS; unit++) {
diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
index d2013d36240..35fb2663672 100644
--- a/drivers/block/paride/pt.c
+++ b/drivers/block/paride/pt.c
@@ -141,7 +141,6 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3};
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mtio.h>
@@ -971,32 +970,15 @@ static int __init pt_init(void)
goto out_chrdev;
}
- devfs_mk_dir("pt");
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) {
class_device_create(pt_class, NULL, MKDEV(major, unit),
NULL, "pt%d", unit);
- err = devfs_mk_cdev(MKDEV(major, unit),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "pt/%d", unit);
- if (err) {
- class_device_destroy(pt_class, MKDEV(major, unit));
- goto out_class;
- }
class_device_create(pt_class, NULL, MKDEV(major, unit + 128),
NULL, "pt%dn", unit);
- err = devfs_mk_cdev(MKDEV(major, unit + 128),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "pt/%dn", unit);
- if (err) {
- class_device_destroy(pt_class, MKDEV(major, unit + 128));
- goto out_class;
- }
}
goto out;
-out_class:
- class_destroy(pt_class);
out_chrdev:
unregister_chrdev(major, "pt");
out:
@@ -1009,12 +991,9 @@ static void __exit pt_exit(void)
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present) {
class_device_destroy(pt_class, MKDEV(major, unit));
- devfs_remove("pt/%d", unit);
class_device_destroy(pt_class, MKDEV(major, unit + 128));
- devfs_remove("pt/%dn", unit);
}
class_destroy(pt_class);
- devfs_remove("pt");
unregister_chrdev(major, name);
for (unit = 0; unit < PT_UNITS; unit++)
if (pt[unit].present)
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index a04f60693c3..451b996bba9 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -44,7 +44,6 @@
*************************************************************************/
#include <linux/pktcdvd.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -2578,19 +2577,19 @@ static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cm
case PKT_CTRL_CMD_SETUP:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock(&ctl_mutex);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
ret = pkt_setup_dev(&ctrl_cmd);
mutex_unlock(&ctl_mutex);
break;
case PKT_CTRL_CMD_TEARDOWN:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- mutex_lock(&ctl_mutex);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
ret = pkt_remove_dev(&ctrl_cmd);
mutex_unlock(&ctl_mutex);
break;
case PKT_CTRL_CMD_STATUS:
- mutex_lock(&ctl_mutex);
+ mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING);
pkt_get_status(&ctrl_cmd);
mutex_unlock(&ctl_mutex);
break;
@@ -2612,7 +2611,6 @@ static struct file_operations pkt_ctl_fops = {
static struct miscdevice pkt_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = "pktcdvd",
- .devfs_name = "pktcdvd/control",
.fops = &pkt_ctl_fops
};
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index bea75f2cb21..5537974fb24 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -29,7 +29,6 @@
#define DEVICE_NAME "PS/2 ESDI"
-#include <linux/config.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/wait.h>
@@ -341,9 +340,9 @@ static int __init ps2esdi_geninit(void)
/* try to grab IRQ, and try to grab a slow IRQ if it fails, so we can
share with the SCSI driver */
if (request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
- SA_INTERRUPT | SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
+ IRQF_DISABLED | IRQF_SHARED, "PS/2 ESDI", &ps2esdi_gendisk)
&& request_irq(PS2ESDI_IRQ, ps2esdi_interrupt_handler,
- SA_SHIRQ, "PS/2 ESDI", &ps2esdi_gendisk)
+ IRQF_SHARED, "PS/2 ESDI", &ps2esdi_gendisk)
) {
printk("%s: Unable to get IRQ %d\n", DEVICE_NAME, PS2ESDI_IRQ);
error = -EBUSY;
@@ -421,7 +420,6 @@ static int __init ps2esdi_geninit(void)
disk->major = PS2ESDI_MAJOR;
disk->first_minor = i<<6;
sprintf(disk->disk_name, "ed%c", 'a'+i);
- sprintf(disk->devfs_name, "ed/target%d", i);
disk->fops = &ps2esdi_fops;
ps2esdi_gendisk[i] = disk;
}
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index 940bfd7951e..a3f64bfe6b5 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -42,7 +42,6 @@
* and set blk_size for -ENOSPC, Werner Fink <werner@suse.de>, Apr '99
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/atomic.h>
@@ -50,7 +49,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/pagemap.h>
#include <linux/blkdev.h>
#include <linux/genhd.h>
@@ -86,7 +84,7 @@ int rd_size = CONFIG_BLK_DEV_RAM_SIZE; /* Size of the RAM disks */
* behaviour. The default is still BLOCK_SIZE (needed by rd_load_image that
* supposes the filesystem in the image uses a BLOCK_SIZE blocksize).
*/
-static int rd_blocksize = BLOCK_SIZE; /* blocksize of the RAM disks */
+static int rd_blocksize = CONFIG_BLK_DEV_RAM_BLOCKSIZE;
/*
* Copyright (C) 2000 Linus Torvalds.
@@ -191,7 +189,7 @@ static int ramdisk_set_page_dirty(struct page *page)
return 0;
}
-static struct address_space_operations ramdisk_aops = {
+static const struct address_space_operations ramdisk_aops = {
.readpage = ramdisk_readpage,
.prepare_write = ramdisk_prepare_write,
.commit_write = ramdisk_commit_write,
@@ -412,7 +410,6 @@ static void __exit rd_cleanup(void)
put_disk(rd_disks[i]);
blk_cleanup_queue(rd_queue[i]);
}
- devfs_remove("rd");
unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
}
@@ -442,8 +439,6 @@ static int __init rd_init(void)
goto out;
}
- devfs_mk_dir("rd");
-
for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) {
struct gendisk *disk = rd_disks[i];
@@ -461,7 +456,6 @@ static int __init rd_init(void)
disk->queue = rd_queue[i];
disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "ram%d", i);
- sprintf(disk->devfs_name, "rd/%d", i);
set_capacity(disk, rd_size * 2);
add_disk(rd_disks[i]);
}
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 01f042f6f1c..cc42e762396 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -16,7 +16,6 @@
* handle GCR disks
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -25,7 +24,6 @@
#include <linux/fd.h>
#include <linux/ioctl.h>
#include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@@ -252,8 +250,6 @@ static int floppy_open(struct inode *inode, struct file *filp);
static int floppy_release(struct inode *inode, struct file *filp);
static int floppy_check_change(struct gendisk *disk);
static int floppy_revalidate(struct gendisk *disk);
-static int swim3_add_device(struct device_node *swims);
-int swim3_init(void);
#ifndef CONFIG_PMAC_MEDIABAY
#define check_media_bay(which, what) 1
@@ -1013,117 +1009,63 @@ static struct block_device_operations floppy_fops = {
.revalidate_disk= floppy_revalidate,
};
-int swim3_init(void)
-{
- struct device_node *swim;
- int err = -ENOMEM;
- int i;
-
- devfs_mk_dir("floppy");
-
- swim = find_devices("floppy");
- while (swim && (floppy_count < MAX_FLOPPIES))
- {
- swim3_add_device(swim);
- swim = swim->next;
- }
-
- swim = find_devices("swim3");
- while (swim && (floppy_count < MAX_FLOPPIES))
- {
- swim3_add_device(swim);
- swim = swim->next;
- }
-
- if (!floppy_count)
- return -ENODEV;
-
- for (i = 0; i < floppy_count; i++) {
- disks[i] = alloc_disk(1);
- if (!disks[i])
- goto out;
- }
-
- if (register_blkdev(FLOPPY_MAJOR, "fd")) {
- err = -EBUSY;
- goto out;
- }
-
- swim3_queue = blk_init_queue(do_fd_request, &swim3_lock);
- if (!swim3_queue) {
- err = -ENOMEM;
- goto out_queue;
- }
-
- for (i = 0; i < floppy_count; i++) {
- struct gendisk *disk = disks[i];
- disk->major = FLOPPY_MAJOR;
- disk->first_minor = i;
- disk->fops = &floppy_fops;
- disk->private_data = &floppy_states[i];
- disk->queue = swim3_queue;
- disk->flags |= GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, "fd%d", i);
- sprintf(disk->devfs_name, "floppy/%d", i);
- set_capacity(disk, 2880);
- add_disk(disk);
- }
- return 0;
-
-out_queue:
- unregister_blkdev(FLOPPY_MAJOR, "fd");
-out:
- while (i--)
- put_disk(disks[i]);
- /* shouldn't we do something with results of swim_add_device()? */
- return err;
-}
-
-static int swim3_add_device(struct device_node *swim)
+static int swim3_add_device(struct macio_dev *mdev, int index)
{
+ struct device_node *swim = mdev->ofdev.node;
struct device_node *mediabay;
- struct floppy_state *fs = &floppy_states[floppy_count];
- struct resource res_reg, res_dma;
+ struct floppy_state *fs = &floppy_states[index];
+ int rc = -EBUSY;
- if (of_address_to_resource(swim, 0, &res_reg) ||
- of_address_to_resource(swim, 1, &res_dma)) {
- printk(KERN_ERR "swim3: Can't get addresses\n");
- return -EINVAL;
+ /* Check & Request resources */
+ if (macio_resource_count(mdev) < 2) {
+ printk(KERN_WARNING "ifd%d: no address for %s\n",
+ index, swim->full_name);
+ return -ENXIO;
}
- if (request_mem_region(res_reg.start, res_reg.end - res_reg.start + 1,
- " (reg)") == NULL) {
- printk(KERN_ERR "swim3: Can't request register space\n");
- return -EINVAL;
+ if (macio_irq_count(mdev) < 2) {
+ printk(KERN_WARNING "fd%d: no intrs for device %s\n",
+ index, swim->full_name);
}
- if (request_mem_region(res_dma.start, res_dma.end - res_dma.start + 1,
- " (dma)") == NULL) {
- release_mem_region(res_reg.start,
- res_reg.end - res_reg.start + 1);
- printk(KERN_ERR "swim3: Can't request DMA space\n");
- return -EINVAL;
+ if (macio_request_resource(mdev, 0, "swim3 (mmio)")) {
+ printk(KERN_ERR "fd%d: can't request mmio resource for %s\n",
+ index, swim->full_name);
+ return -EBUSY;
}
-
- if (swim->n_intrs < 2) {
- printk(KERN_INFO "swim3: expecting 2 intrs (n_intrs:%d)\n",
- swim->n_intrs);
- release_mem_region(res_reg.start,
- res_reg.end - res_reg.start + 1);
- release_mem_region(res_dma.start,
- res_dma.end - res_dma.start + 1);
- return -EINVAL;
+ if (macio_request_resource(mdev, 1, "swim3 (dma)")) {
+ printk(KERN_ERR "fd%d: can't request dma resource for %s\n",
+ index, swim->full_name);
+ macio_release_resource(mdev, 0);
+ return -EBUSY;
}
+ dev_set_drvdata(&mdev->ofdev.dev, fs);
- mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ? swim->parent : NULL;
+ mediabay = (strcasecmp(swim->parent->type, "media-bay") == 0) ?
+ swim->parent : NULL;
if (mediabay == NULL)
pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
memset(fs, 0, sizeof(*fs));
spin_lock_init(&fs->lock);
fs->state = idle;
- fs->swim3 = (struct swim3 __iomem *)ioremap(res_reg.start, 0x200);
- fs->dma = (struct dbdma_regs __iomem *)ioremap(res_dma.start, 0x200);
- fs->swim3_intr = swim->intrs[0].line;
- fs->dma_intr = swim->intrs[1].line;
+ fs->swim3 = (struct swim3 __iomem *)
+ ioremap(macio_resource_start(mdev, 0), 0x200);
+ if (fs->swim3 == NULL) {
+ printk("fd%d: couldn't map registers for %s\n",
+ index, swim->full_name);
+ rc = -ENOMEM;
+ goto out_release;
+ }
+ fs->dma = (struct dbdma_regs __iomem *)
+ ioremap(macio_resource_start(mdev, 1), 0x200);
+ if (fs->dma == NULL) {
+ printk("fd%d: couldn't map DMA for %s\n",
+ index, swim->full_name);
+ iounmap(fs->swim3);
+ rc = -ENOMEM;
+ goto out_release;
+ }
+ fs->swim3_intr = macio_irq(mdev, 0);
+ fs->dma_intr = macio_irq(mdev, 1);;
fs->cur_cyl = -1;
fs->cur_sector = -1;
fs->secpercyl = 36;
@@ -1137,15 +1079,16 @@ static int swim3_add_device(struct device_node *swim)
st_le16(&fs->dma_cmd[1].command, DBDMA_STOP);
if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) {
- printk(KERN_ERR "Couldn't get irq %d for SWIM3\n", fs->swim3_intr);
+ printk(KERN_ERR "fd%d: couldn't request irq %d for %s\n",
+ index, fs->swim3_intr, swim->full_name);
pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
+ goto out_unmap;
return -EBUSY;
}
/*
if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) {
printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA",
fs->dma_intr);
- pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0);
return -EBUSY;
}
*/
@@ -1155,8 +1098,90 @@ static int swim3_add_device(struct device_node *swim)
printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count,
mediabay ? "in media bay" : "");
- floppy_count++;
-
+ return 0;
+
+ out_unmap:
+ iounmap(fs->dma);
+ iounmap(fs->swim3);
+
+ out_release:
+ macio_release_resource(mdev, 0);
+ macio_release_resource(mdev, 1);
+
+ return rc;
+}
+
+static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device_id *match)
+{
+ int i, rc;
+ struct gendisk *disk;
+
+ /* Add the drive */
+ rc = swim3_add_device(mdev, floppy_count);
+ if (rc)
+ return rc;
+
+ /* Now create the queue if not there yet */
+ if (swim3_queue == NULL) {
+ /* If we failed, there isn't much we can do as the driver is still
+ * too dumb to remove the device, just bail out
+ */
+ if (register_blkdev(FLOPPY_MAJOR, "fd"))
+ return 0;
+ swim3_queue = blk_init_queue(do_fd_request, &swim3_lock);
+ if (swim3_queue == NULL) {
+ unregister_blkdev(FLOPPY_MAJOR, "fd");
+ return 0;
+ }
+ }
+
+ /* Now register that disk. Same comment about failure handling */
+ i = floppy_count++;
+ disk = disks[i] = alloc_disk(1);
+ if (disk == NULL)
+ return 0;
+
+ disk->major = FLOPPY_MAJOR;
+ disk->first_minor = i;
+ disk->fops = &floppy_fops;
+ disk->private_data = &floppy_states[i];
+ disk->queue = swim3_queue;
+ disk->flags |= GENHD_FL_REMOVABLE;
+ sprintf(disk->disk_name, "fd%d", i);
+ set_capacity(disk, 2880);
+ add_disk(disk);
+
+ return 0;
+}
+
+static struct of_device_id swim3_match[] =
+{
+ {
+ .name = "swim3",
+ },
+ {
+ .compatible = "ohare-swim3"
+ },
+ {
+ .compatible = "swim3"
+ },
+};
+
+static struct macio_driver swim3_driver =
+{
+ .name = "swim3",
+ .match_table = swim3_match,
+ .probe = swim3_attach,
+#if 0
+ .suspend = swim3_suspend,
+ .resume = swim3_resume,
+#endif
+};
+
+
+int swim3_init(void)
+{
+ macio_register_driver(&swim3_driver);
return 0;
}
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 2ae08b343b9..c6beee18a07 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -18,7 +18,6 @@
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <linux/sched.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h>
#include <linux/compiler.h>
#include <linux/workqueue.h>
@@ -1510,7 +1509,6 @@ static int carm_init_disks(struct carm_host *host)
port->disk = disk;
sprintf(disk->disk_name, DRV_NAME "/%u",
(unsigned int) (host->id * CARM_MAX_PORTS) + i);
- sprintf(disk->devfs_name, DRV_NAME "/%u_%u", host->id, i);
disk->major = host->major;
disk->first_minor = i * CARM_MINORS_PER_MAJOR;
disk->fops = &carm_bd_ops;
@@ -1672,15 +1670,13 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (host->flags & FL_DYN_MAJOR)
host->major = rc;
- devfs_mk_dir(DRV_NAME);
-
rc = carm_init_disks(host);
if (rc)
goto err_out_blkdev_disks;
pci_set_master(pdev);
- rc = request_irq(pdev->irq, carm_interrupt, SA_SHIRQ, DRV_NAME, host);
+ rc = request_irq(pdev->irq, carm_interrupt, IRQF_SHARED, DRV_NAME, host);
if (rc) {
printk(KERN_ERR DRV_NAME "(%s): irq alloc failure\n",
pci_name(pdev));
@@ -1694,9 +1690,10 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
DPRINTK("waiting for probe_comp\n");
wait_for_completion(&host->probe_comp);
- printk(KERN_INFO "%s: pci %s, ports %d, io %lx, irq %u, major %d\n",
+ printk(KERN_INFO "%s: pci %s, ports %d, io %llx, irq %u, major %d\n",
host->name, pci_name(pdev), (int) CARM_MAX_PORTS,
- pci_resource_start(pdev, 0), pdev->irq, host->major);
+ (unsigned long long)pci_resource_start(pdev, 0),
+ pdev->irq, host->major);
carm_host_id++;
pci_set_drvdata(pdev, host);
@@ -1738,7 +1735,6 @@ static void carm_remove_one (struct pci_dev *pdev)
free_irq(pdev->irq, host);
carm_free_disks(host);
- devfs_remove(DRV_NAME);
unregister_blkdev(host->major, host->name);
if (host->major == 160)
clear_bit(0, &carm_major_alloc);
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 60e9a9457c6..45a8f402b07 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -24,12 +24,10 @@
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/timer.h>
#include <scsi/scsi.h>
#define DRV_NAME "ub"
-#define DEVFS_NAME DRV_NAME
#define UB_MAJOR 180
@@ -360,7 +358,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct ub_request *urq);
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_end_rq(struct request *rq, int uptodate);
+static void ub_end_rq(struct request *rq, unsigned int status);
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
struct ub_request *urq, struct ub_scsi_cmd *cmd);
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -641,9 +639,15 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
struct ub_request *urq;
int n_elem;
- if (atomic_read(&sc->poison) || lun->changed) {
+ if (atomic_read(&sc->poison)) {
+ blkdev_dequeue_request(rq);
+ ub_end_rq(rq, DID_NO_CONNECT << 16);
+ return 0;
+ }
+
+ if (lun->changed && !blk_pc_request(rq)) {
blkdev_dequeue_request(rq);
- ub_end_rq(rq, 0);
+ ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
return 0;
}
@@ -695,7 +699,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
drop:
ub_put_cmd(lun, cmd);
- ub_end_rq(rq, 0);
+ ub_end_rq(rq, DID_ERROR << 16);
return 0;
}
@@ -763,47 +767,53 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
struct ub_lun *lun = cmd->lun;
struct ub_request *urq = cmd->back;
struct request *rq;
- int uptodate;
+ unsigned int scsi_status;
rq = urq->rq;
if (cmd->error == 0) {
- uptodate = 1;
-
if (blk_pc_request(rq)) {
if (cmd->act_len >= rq->data_len)
rq->data_len = 0;
else
rq->data_len -= cmd->act_len;
}
+ scsi_status = 0;
} else {
- uptodate = 0;
-
if (blk_pc_request(rq)) {
/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
rq->sense_len = UB_SENSE_SIZE;
if (sc->top_sense[0] != 0)
- rq->errors = SAM_STAT_CHECK_CONDITION;
+ scsi_status = SAM_STAT_CHECK_CONDITION;
else
- rq->errors = DID_ERROR << 16;
+ scsi_status = DID_ERROR << 16;
} else {
if (cmd->error == -EIO) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
+ scsi_status = SAM_STAT_CHECK_CONDITION;
}
}
urq->rq = NULL;
ub_put_cmd(lun, cmd);
- ub_end_rq(rq, uptodate);
+ ub_end_rq(rq, scsi_status);
blk_start_queue(lun->disk->queue);
}
-static void ub_end_rq(struct request *rq, int uptodate)
+static void ub_end_rq(struct request *rq, unsigned int scsi_status)
{
+ int uptodate;
+
+ if (scsi_status == 0) {
+ uptodate = 1;
+ } else {
+ uptodate = 0;
+ rq->errors = scsi_status;
+ }
end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
end_that_request_last(rq, uptodate);
}
@@ -2291,7 +2301,6 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
goto err_diskalloc;
sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
- sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
disk->major = UB_MAJOR;
disk->first_minor = lun->id * UB_PARTS_PER_LUN;
disk->fops = &ub_bd_fops;
@@ -2445,7 +2454,6 @@ static int __init ub_init(void)
if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0)
goto err_regblkdev;
- devfs_mk_dir(DEVFS_NAME);
if ((rc = usb_register(&ub_driver)) != 0)
goto err_register;
@@ -2454,7 +2462,6 @@ static int __init ub_init(void)
return 0;
err_register:
- devfs_remove(DEVFS_NAME);
unregister_blkdev(UB_MAJOR, DRV_NAME);
err_regblkdev:
return rc;
@@ -2464,7 +2471,6 @@ static void __exit ub_exit(void)
{
usb_deregister(&ub_driver);
- devfs_remove(DEVFS_NAME);
unregister_blkdev(UB_MAJOR, DRV_NAME);
usb_usual_clear_present(USB_US_TYPE_UB);
}
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index f7d4c65a7b8..5d8925bd904 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -35,7 +35,6 @@
*/
//#define DEBUG /* uncomment if you want debugging info (pr_debug) */
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/bio.h>
@@ -1041,7 +1040,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->win_size = data;
- if (request_irq(dev->irq, mm_interrupt, SA_SHIRQ, "pci-umem", card)) {
+ if (request_irq(dev->irq, mm_interrupt, IRQF_SHARED, "pci-umem", card)) {
printk(KERN_ERR "MM%d: Unable to allocate IRQ\n", card->card_number);
ret = -ENODEV;
@@ -1192,7 +1191,6 @@ static int __init mm_init(void)
for (i = 0; i < num_cards; i++) {
struct gendisk *disk = mm_gendisk[i];
sprintf(disk->disk_name, "umem%c", 'a'+i);
- sprintf(disk->devfs_name, "umem/card%d", i);
spin_lock_init(&cards[i].lock);
disk->major = major_nr;
disk->first_minor = i << MM_SHIFT;
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index b0df4f5ab97..ec5a1b90a0a 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -59,7 +59,6 @@ MODULE_LICENSE("GPL");
* numbers 0-255 we get a maximum of 32 disks.
*/
#define VIOD_GENHD_NAME "iseries/vd"
-#define VIOD_GENHD_DEVFS_NAME "iseries/disc"
#define VIOD_VERS "1.64"
@@ -523,8 +522,6 @@ retry:
else
snprintf(g->disk_name, sizeof(g->disk_name),
VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26));
- snprintf(g->devfs_name, sizeof(g->devfs_name),
- "%s%d", VIOD_GENHD_DEVFS_NAME, dev_no);
g->fops = &viodasd_fops;
g->queue = q;
g->private_data = d;
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index cbce7c5e944..e828e4cbd3e 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -215,7 +215,6 @@ static int __init xd_init(void)
disk->major = XT_DISK_MAJOR;
disk->first_minor = i<<6;
sprintf(disk->disk_name, "xd%c", i+'a');
- sprintf(disk->devfs_name, "xd/target%d", i);
disk->fops = &xd_fops;
disk->private_data = p;
disk->queue = xd_queue;
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index bb5e8d665a2..82ddbdd7bd4 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -354,7 +354,6 @@ z2_init(void)
z2ram_gendisk->first_minor = 0;
z2ram_gendisk->fops = &z2_fops;
sprintf(z2ram_gendisk->disk_name, "z2ram");
- strcpy(z2ram_gendisk->devfs_name, z2ram_gendisk->disk_name);
z2ram_gendisk->queue = z2_queue;
add_disk(z2ram_gendisk);
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 3e7a067cc08..13ba729cdd5 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -235,6 +234,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
data->fw_data = kmalloc(firmware->size, GFP_KERNEL);
if (!data->fw_data) {
BT_ERR("Can't allocate memory for firmware image");
+ release_firmware(firmware);
usb_free_urb(data->urb);
kfree(data->buffer);
kfree(data);
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 8947c8837da..efcc28ec9d9 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -2,7 +2,7 @@
*
* AVM BlueFRITZ! USB driver
*
- * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2006 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +21,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -60,7 +59,6 @@ static struct usb_device_id bfusb_table[] = {
MODULE_DEVICE_TABLE(usb, bfusb_table);
-
#define BFUSB_MAX_BLOCK_SIZE 256
#define BFUSB_BLOCK_TIMEOUT 3000
@@ -71,7 +69,7 @@ MODULE_DEVICE_TABLE(usb, bfusb_table);
#define BFUSB_MAX_BULK_TX 2
#define BFUSB_MAX_BULK_RX 2
-struct bfusb {
+struct bfusb_data {
struct hci_dev *hdev;
unsigned long state;
@@ -93,137 +91,136 @@ struct bfusb {
struct sk_buff_head completed_q;
};
-struct bfusb_scb {
+struct bfusb_data_scb {
struct urb *urb;
};
static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs);
static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs);
-static struct urb *bfusb_get_completed(struct bfusb *bfusb)
+static struct urb *bfusb_get_completed(struct bfusb_data *data)
{
struct sk_buff *skb;
struct urb *urb = NULL;
- BT_DBG("bfusb %p", bfusb);
+ BT_DBG("bfusb %p", data);
- skb = skb_dequeue(&bfusb->completed_q);
+ skb = skb_dequeue(&data->completed_q);
if (skb) {
- urb = ((struct bfusb_scb *) skb->cb)->urb;
+ urb = ((struct bfusb_data_scb *) skb->cb)->urb;
kfree_skb(skb);
}
return urb;
}
-static void bfusb_unlink_urbs(struct bfusb *bfusb)
+static void bfusb_unlink_urbs(struct bfusb_data *data)
{
struct sk_buff *skb;
struct urb *urb;
- BT_DBG("bfusb %p", bfusb);
+ BT_DBG("bfusb %p", data);
- while ((skb = skb_dequeue(&bfusb->pending_q))) {
- urb = ((struct bfusb_scb *) skb->cb)->urb;
+ while ((skb = skb_dequeue(&data->pending_q))) {
+ urb = ((struct bfusb_data_scb *) skb->cb)->urb;
usb_kill_urb(urb);
- skb_queue_tail(&bfusb->completed_q, skb);
+ skb_queue_tail(&data->completed_q, skb);
}
- while ((urb = bfusb_get_completed(bfusb)))
+ while ((urb = bfusb_get_completed(data)))
usb_free_urb(urb);
}
-
-static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
+static int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb)
{
- struct bfusb_scb *scb = (void *) skb->cb;
- struct urb *urb = bfusb_get_completed(bfusb);
+ struct bfusb_data_scb *scb = (void *) skb->cb;
+ struct urb *urb = bfusb_get_completed(data);
int err, pipe;
- BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
+ BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len);
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
- pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
+ pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
- usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, skb->len,
+ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len,
bfusb_tx_complete, skb);
scb->urb = urb;
- skb_queue_tail(&bfusb->pending_q, skb);
+ skb_queue_tail(&data->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk tx submit failed urb %p err %d",
- bfusb->hdev->name, urb, err);
- skb_unlink(skb, &bfusb->pending_q);
+ data->hdev->name, urb, err);
+ skb_unlink(skb, &data->pending_q);
usb_free_urb(urb);
} else
- atomic_inc(&bfusb->pending_tx);
+ atomic_inc(&data->pending_tx);
return err;
}
-static void bfusb_tx_wakeup(struct bfusb *bfusb)
+static void bfusb_tx_wakeup(struct bfusb_data *data)
{
struct sk_buff *skb;
- BT_DBG("bfusb %p", bfusb);
+ BT_DBG("bfusb %p", data);
- if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
- set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
+ if (test_and_set_bit(BFUSB_TX_PROCESS, &data->state)) {
+ set_bit(BFUSB_TX_WAKEUP, &data->state);
return;
}
do {
- clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
+ clear_bit(BFUSB_TX_WAKEUP, &data->state);
- while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
- (skb = skb_dequeue(&bfusb->transmit_q))) {
- if (bfusb_send_bulk(bfusb, skb) < 0) {
- skb_queue_head(&bfusb->transmit_q, skb);
+ while ((atomic_read(&data->pending_tx) < BFUSB_MAX_BULK_TX) &&
+ (skb = skb_dequeue(&data->transmit_q))) {
+ if (bfusb_send_bulk(data, skb) < 0) {
+ skb_queue_head(&data->transmit_q, skb);
break;
}
}
- } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
+ } while (test_bit(BFUSB_TX_WAKEUP, &data->state));
- clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
+ clear_bit(BFUSB_TX_PROCESS, &data->state);
}
static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct bfusb *bfusb = (struct bfusb *) skb->dev;
+ struct bfusb_data *data = (struct bfusb_data *) skb->dev;
- BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
+ BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
- atomic_dec(&bfusb->pending_tx);
+ atomic_dec(&data->pending_tx);
- if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
+ if (!test_bit(HCI_RUNNING, &data->hdev->flags))
return;
if (!urb->status)
- bfusb->hdev->stat.byte_tx += skb->len;
+ data->hdev->stat.byte_tx += skb->len;
else
- bfusb->hdev->stat.err_tx++;
+ data->hdev->stat.err_tx++;
- read_lock(&bfusb->lock);
+ read_lock(&data->lock);
- skb_unlink(skb, &bfusb->pending_q);
- skb_queue_tail(&bfusb->completed_q, skb);
+ skb_unlink(skb, &data->pending_q);
+ skb_queue_tail(&data->completed_q, skb);
- bfusb_tx_wakeup(bfusb);
+ bfusb_tx_wakeup(data);
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
}
-static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
+static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb)
{
- struct bfusb_scb *scb;
+ struct bfusb_data_scb *scb;
struct sk_buff *skb;
int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
@@ -232,28 +229,29 @@ static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
- if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
+ skb = bt_skb_alloc(size, GFP_ATOMIC);
+ if (!skb) {
usb_free_urb(urb);
return -ENOMEM;
}
- skb->dev = (void *) bfusb;
+ skb->dev = (void *) data;
- scb = (struct bfusb_scb *) skb->cb;
+ scb = (struct bfusb_data_scb *) skb->cb;
scb->urb = urb;
- pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
+ pipe = usb_rcvbulkpipe(data->udev, data->bulk_in_ep);
- usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size,
+ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, size,
bfusb_rx_complete, skb);
- skb_queue_tail(&bfusb->pending_q, skb);
+ skb_queue_tail(&data->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk rx submit failed urb %p err %d",
- bfusb->hdev->name, urb, err);
- skb_unlink(skb, &bfusb->pending_q);
+ data->hdev->name, urb, err);
+ skb_unlink(skb, &data->pending_q);
kfree_skb(skb);
usb_free_urb(urb);
}
@@ -261,15 +259,15 @@ static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
return err;
}
-static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
+static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
{
- BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);
if (hdr & 0x10) {
- BT_ERR("%s error in block", bfusb->hdev->name);
- if (bfusb->reassembly)
- kfree_skb(bfusb->reassembly);
- bfusb->reassembly = NULL;
+ BT_ERR("%s error in block", data->hdev->name);
+ if (data->reassembly)
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
return -EIO;
}
@@ -278,46 +276,46 @@ static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *
unsigned char pkt_type;
int pkt_len = 0;
- if (bfusb->reassembly) {
- BT_ERR("%s unexpected start block", bfusb->hdev->name);
- kfree_skb(bfusb->reassembly);
- bfusb->reassembly = NULL;
+ if (data->reassembly) {
+ BT_ERR("%s unexpected start block", data->hdev->name);
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
}
if (len < 1) {
- BT_ERR("%s no packet type found", bfusb->hdev->name);
+ BT_ERR("%s no packet type found", data->hdev->name);
return -EPROTO;
}
- pkt_type = *data++; len--;
+ pkt_type = *buf++; len--;
switch (pkt_type) {
case HCI_EVENT_PKT:
if (len >= HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *hdr = (struct hci_event_hdr *) data;
+ struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
} else {
- BT_ERR("%s event block is too short", bfusb->hdev->name);
+ BT_ERR("%s event block is too short", data->hdev->name);
return -EILSEQ;
}
break;
case HCI_ACLDATA_PKT:
if (len >= HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data;
+ struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
} else {
- BT_ERR("%s data block is too short", bfusb->hdev->name);
+ BT_ERR("%s data block is too short", data->hdev->name);
return -EILSEQ;
}
break;
case HCI_SCODATA_PKT:
if (len >= HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data;
+ struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
} else {
- BT_ERR("%s audio block is too short", bfusb->hdev->name);
+ BT_ERR("%s audio block is too short", data->hdev->name);
return -EILSEQ;
}
break;
@@ -325,27 +323,27 @@ static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
if (!skb) {
- BT_ERR("%s no memory for the packet", bfusb->hdev->name);
+ BT_ERR("%s no memory for the packet", data->hdev->name);
return -ENOMEM;
}
- skb->dev = (void *) bfusb->hdev;
+ skb->dev = (void *) data->hdev;
bt_cb(skb)->pkt_type = pkt_type;
- bfusb->reassembly = skb;
+ data->reassembly = skb;
} else {
- if (!bfusb->reassembly) {
- BT_ERR("%s unexpected continuation block", bfusb->hdev->name);
+ if (!data->reassembly) {
+ BT_ERR("%s unexpected continuation block", data->hdev->name);
return -EIO;
}
}
if (len > 0)
- memcpy(skb_put(bfusb->reassembly, len), data, len);
+ memcpy(skb_put(data->reassembly, len), buf, len);
if (hdr & 0x08) {
- hci_recv_frame(bfusb->reassembly);
- bfusb->reassembly = NULL;
+ hci_recv_frame(data->reassembly);
+ data->reassembly = NULL;
}
return 0;
@@ -354,22 +352,22 @@ static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *
static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct bfusb *bfusb = (struct bfusb *) skb->dev;
+ struct bfusb_data *data = (struct bfusb_data *) skb->dev;
unsigned char *buf = urb->transfer_buffer;
int count = urb->actual_length;
int err, hdr, len;
BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
- read_lock(&bfusb->lock);
+ read_lock(&data->lock);
- if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
+ if (!test_bit(HCI_RUNNING, &data->hdev->flags))
goto unlock;
if (urb->status || !count)
goto resubmit;
- bfusb->hdev->stat.byte_rx += count;
+ data->hdev->stat.byte_rx += count;
skb_put(skb, count);
@@ -388,90 +386,89 @@ static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
if (count < len) {
BT_ERR("%s block extends over URB buffer ranges",
- bfusb->hdev->name);
+ data->hdev->name);
}
if ((hdr & 0xe1) == 0xc1)
- bfusb_recv_block(bfusb, hdr, buf, len);
+ bfusb_recv_block(data, hdr, buf, len);
count -= len;
buf += len;
}
- skb_unlink(skb, &bfusb->pending_q);
+ skb_unlink(skb, &data->pending_q);
kfree_skb(skb);
- bfusb_rx_submit(bfusb, urb);
+ bfusb_rx_submit(data, urb);
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
return;
resubmit:
- urb->dev = bfusb->udev;
+ urb->dev = data->udev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk resubmit failed urb %p err %d",
- bfusb->hdev->name, urb, err);
+ data->hdev->name, urb, err);
}
unlock:
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
}
-
static int bfusb_open(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
unsigned long flags;
int i, err;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&bfusb->lock, flags);
+ write_lock_irqsave(&data->lock, flags);
- err = bfusb_rx_submit(bfusb, NULL);
+ err = bfusb_rx_submit(data, NULL);
if (!err) {
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
- bfusb_rx_submit(bfusb, NULL);
+ bfusb_rx_submit(data, NULL);
} else {
clear_bit(HCI_RUNNING, &hdev->flags);
}
- write_unlock_irqrestore(&bfusb->lock, flags);
+ write_unlock_irqrestore(&data->lock, flags);
return err;
}
static int bfusb_flush(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
- skb_queue_purge(&bfusb->transmit_q);
+ skb_queue_purge(&data->transmit_q);
return 0;
}
static int bfusb_close(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
unsigned long flags;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&bfusb->lock, flags);
- write_unlock_irqrestore(&bfusb->lock, flags);
+ write_lock_irqsave(&data->lock, flags);
+ write_unlock_irqrestore(&data->lock, flags);
- bfusb_unlink_urbs(bfusb);
+ bfusb_unlink_urbs(data);
bfusb_flush(hdev);
return 0;
@@ -480,7 +477,7 @@ static int bfusb_close(struct hci_dev *hdev)
static int bfusb_send_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- struct bfusb *bfusb;
+ struct bfusb_data *data;
struct sk_buff *nskb;
unsigned char buf[3];
int sent = 0, size, count;
@@ -495,7 +492,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- bfusb = (struct bfusb *) hdev->driver_data;
+ data = hdev->driver_data;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
@@ -515,12 +512,13 @@ static int bfusb_send_frame(struct sk_buff *skb)
count = skb->len;
/* Max HCI frame size seems to be 1511 + 1 */
- if (!(nskb = bt_skb_alloc(count + 32, GFP_ATOMIC))) {
+ nskb = bt_skb_alloc(count + 32, GFP_ATOMIC);
+ if (!nskb) {
BT_ERR("Can't allocate memory for new packet");
return -ENOMEM;
}
- nskb->dev = (void *) bfusb;
+ nskb->dev = (void *) data;
while (count) {
size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
@@ -537,18 +535,18 @@ static int bfusb_send_frame(struct sk_buff *skb)
}
/* Don't send frame with multiple size of bulk max packet */
- if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
+ if ((nskb->len % data->bulk_pkt_size) == 0) {
buf[0] = 0xdd;
buf[1] = 0x00;
memcpy(skb_put(nskb, 2), buf, 2);
}
- read_lock(&bfusb->lock);
+ read_lock(&data->lock);
- skb_queue_tail(&bfusb->transmit_q, nskb);
- bfusb_tx_wakeup(bfusb);
+ skb_queue_tail(&data->transmit_q, nskb);
+ bfusb_tx_wakeup(data);
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
kfree_skb(skb);
@@ -557,11 +555,11 @@ static int bfusb_send_frame(struct sk_buff *skb)
static void bfusb_destruct(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
- kfree(bfusb);
+ kfree(data);
}
static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
@@ -569,25 +567,24 @@ static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg
return -ENOIOCTLCMD;
}
-
-static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
+static int bfusb_load_firmware(struct bfusb_data *data, unsigned char *firmware, int count)
{
unsigned char *buf;
int err, pipe, len, size, sent = 0;
- BT_DBG("bfusb %p udev %p", bfusb, bfusb->udev);
+ BT_DBG("bfusb %p udev %p", data, data->udev);
BT_INFO("BlueFRITZ! USB loading firmware");
- pipe = usb_sndctrlpipe(bfusb->udev, 0);
+ pipe = usb_sndctrlpipe(data->udev, 0);
- if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
BT_ERR("Can't change to loading configuration");
return -EBUSY;
}
- bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
+ data->udev->toggle[0] = data->udev->toggle[1] = 0;
buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
if (!buf) {
@@ -595,14 +592,14 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
return -ENOMEM;
}
- pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
+ pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
while (count) {
size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
memcpy(buf, firmware + sent, size);
- err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
+ err = usb_bulk_msg(data->udev, pipe, buf, size,
&len, BFUSB_BLOCK_TIMEOUT);
if (err || (len != size)) {
@@ -614,21 +611,23 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
count -= size;
}
- if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
- &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
+ err = usb_bulk_msg(data->udev, pipe, NULL, 0,
+ &len, BFUSB_BLOCK_TIMEOUT);
+ if (err < 0) {
BT_ERR("Error in null packet request");
goto error;
}
- pipe = usb_sndctrlpipe(bfusb->udev, 0);
+ pipe = usb_sndctrlpipe(data->udev, 0);
- if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
- 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
+ err = usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
BT_ERR("Can't change to running configuration");
goto error;
}
- bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
+ data->udev->toggle[0] = data->udev->toggle[1] = 0;
BT_INFO("BlueFRITZ! USB device ready");
@@ -638,9 +637,9 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
error:
kfree(buf);
- pipe = usb_sndctrlpipe(bfusb->udev, 0);
+ pipe = usb_sndctrlpipe(data->udev, 0);
- usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
return err;
@@ -653,7 +652,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
struct usb_host_endpoint *bulk_out_ep;
struct usb_host_endpoint *bulk_in_ep;
struct hci_dev *hdev;
- struct bfusb *bfusb;
+ struct bfusb_data *data;
BT_DBG("intf %p id %p", intf, id);
@@ -673,23 +672,24 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
}
/* Initialize control structure and load firmware */
- if (!(bfusb = kzalloc(sizeof(struct bfusb), GFP_KERNEL))) {
+ data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
+ if (!data) {
BT_ERR("Can't allocate memory for control structure");
goto done;
}
- bfusb->udev = udev;
- bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
- bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
- bfusb->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
+ data->udev = udev;
+ data->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
+ data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
+ data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
- rwlock_init(&bfusb->lock);
+ rwlock_init(&data->lock);
- bfusb->reassembly = NULL;
+ data->reassembly = NULL;
- skb_queue_head_init(&bfusb->transmit_q);
- skb_queue_head_init(&bfusb->pending_q);
- skb_queue_head_init(&bfusb->completed_q);
+ skb_queue_head_init(&data->transmit_q);
+ skb_queue_head_init(&data->pending_q);
+ skb_queue_head_init(&data->completed_q);
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
@@ -698,7 +698,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
- if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
+ if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
BT_ERR("Firmware loading failed");
goto release;
}
@@ -712,10 +712,10 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
goto error;
}
- bfusb->hdev = hdev;
+ data->hdev = hdev;
hdev->type = HCI_USB;
- hdev->driver_data = bfusb;
+ hdev->driver_data = data;
SET_HCIDEV_DEV(hdev, &intf->dev);
hdev->open = bfusb_open;
@@ -733,7 +733,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
goto error;
}
- usb_set_intfdata(intf, bfusb);
+ usb_set_intfdata(intf, data);
return 0;
@@ -741,7 +741,7 @@ release:
release_firmware(firmware);
error:
- kfree(bfusb);
+ kfree(data);
done:
return -EIO;
@@ -749,8 +749,8 @@ done:
static void bfusb_disconnect(struct usb_interface *intf)
{
- struct bfusb *bfusb = usb_get_intfdata(intf);
- struct hci_dev *hdev = bfusb->hdev;
+ struct bfusb_data *data = usb_get_intfdata(intf);
+ struct hci_dev *hdev = data->hdev;
BT_DBG("intf %p", intf);
@@ -780,7 +780,8 @@ static int __init bfusb_init(void)
BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
- if ((err = usb_register(&bfusb_driver)) < 0)
+ err = usb_register(&bfusb_driver);
+ if (err < 0)
BT_ERR("Failed to register BlueFRITZ! USB driver");
return err;
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 473a13b22b2..8eebf9ca378 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -740,6 +739,7 @@ static int bluecard_open(bluecard_info_t *info)
hdev->type = HCI_PCCARD;
hdev->driver_data = info;
+ SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
hdev->open = bluecard_hci_open;
hdev->close = bluecard_hci_close;
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index 9446960ac74..e0231dc2cb1 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -21,7 +21,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index b94ac2f9f7b..df7bb016df4 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -21,7 +21,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -583,6 +582,7 @@ static int bt3c_open(bt3c_info_t *info)
hdev->type = HCI_PCCARD;
hdev->driver_data = info;
+ SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
hdev->open = bt3c_hci_open;
hdev->close = bt3c_hci_close;
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 9ce4c93467e..746ccca97f6 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -503,6 +502,7 @@ static int btuart_open(btuart_info_t *info)
hdev->type = HCI_PCCARD;
hdev->driver_data = info;
+ SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
hdev->open = btuart_hci_open;
hdev->close = btuart_hci_close;
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index a71a240611e..0e99def8a1e 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -423,6 +422,9 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
nsh.len = skb->len;
s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+ if (!s)
+ return -ENOMEM;
+
skb_reserve(s, NSHL);
memcpy(skb_put(s, skb->len), skb->data, skb->len);
if (skb->len & 0x0001)
@@ -482,6 +484,7 @@ static int dtl1_open(dtl1_info_t *info)
hdev->type = HCI_PCCARD;
hdev->driver_data = info;
+ SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
hdev->open = dtl1_hci_open;
hdev->close = dtl1_hci_close;
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index 7bd4ef90411..d0cface535f 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 4804d474dc8..ad62abbbb73 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -23,7 +23,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 613673b12fa..420b645c4c9 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -23,7 +23,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -192,7 +191,7 @@ static int hci_uart_flush(struct hci_dev *hdev)
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
- if (tty->driver->flush_buffer)
+ if (tty->driver && tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
@@ -242,15 +241,11 @@ static int hci_uart_send_frame(struct sk_buff *skb)
static void hci_uart_destruct(struct hci_dev *hdev)
{
- struct hci_uart *hu;
-
if (!hdev)
return;
BT_DBG("%s", hdev->name);
-
- hu = (struct hci_uart *) hdev->driver_data;
- kfree(hu);
+ kfree(hdev->driver_data);
}
/* ------ LDISC part ------ */
@@ -273,7 +268,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
return -EEXIST;
if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
- BT_ERR("Can't allocate controll structure");
+ BT_ERR("Can't allocate control structure");
return -ENFILE;
}
@@ -291,7 +286,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
- if (tty->driver->flush_buffer)
+ if (tty->driver && tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
return 0;
@@ -361,7 +356,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
*
* Return Value: None
*/
-static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{
struct hci_uart *hu = (void *)tty->disc_data;
@@ -376,7 +371,8 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver->unthrottle)
+ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->driver->unthrottle)
tty->driver->unthrottle(tty);
}
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index 92382e82328..0801af4ad2b 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -31,7 +31,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -68,6 +67,8 @@ static int ignore = 0;
static int ignore_dga = 0;
static int ignore_csr = 0;
static int ignore_sniffer = 0;
+static int disable_scofix = 0;
+static int force_scofix = 0;
static int reset = 0;
#ifdef CONFIG_BT_HCIUSB_SCO
@@ -95,6 +96,9 @@ static struct usb_device_id bluetooth_ids[] = {
/* Ericsson with non-standard id */
{ USB_DEVICE(0x0bdb, 0x1002) },
+ /* Canyon CN-BTU1 with HID interfaces */
+ { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET },
+
{ } /* Terminating entry */
};
@@ -108,9 +112,12 @@ static struct usb_device_id blacklist_ids[] = {
{ USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE },
/* Broadcom BCM2035 */
- { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_BROKEN_ISOC },
+ { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 },
+ /* IBM/Lenovo ThinkPad with Broadcom chip */
+ { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
+
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
@@ -120,8 +127,13 @@ static struct usb_device_id blacklist_ids[] = {
/* ISSC Bluetooth Adapter v3.1 */
{ USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET },
- /* RTX Telecom based adapter with buggy SCO support */
+ /* RTX Telecom based adapters with buggy SCO support */
{ USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC },
+ { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC },
+
+ /* Belkin F8T012 and F8T013 devices */
+ { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU },
+ { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_WRONG_SCO_MTU },
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER },
@@ -130,6 +142,9 @@ static struct usb_device_id blacklist_ids[] = {
/* CSR BlueCore Bluetooth Sniffer */
{ USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER },
+ /* Frontline ComProbe Bluetooth Sniffer */
+ { USB_DEVICE(0x16d3, 0x0002), .driver_info = HCI_SNIFFER },
+
{ } /* Terminating entry */
};
@@ -985,6 +1000,11 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
if (reset || id->driver_info & HCI_RESET)
set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks);
+ if (force_scofix || id->driver_info & HCI_WRONG_SCO_MTU) {
+ if (!disable_scofix)
+ set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
+ }
+
if (id->driver_info & HCI_SNIFFER) {
if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
@@ -1043,10 +1063,81 @@ static void hci_usb_disconnect(struct usb_interface *intf)
hci_free_dev(hdev);
}
+static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct hci_usb *husb = usb_get_intfdata(intf);
+ struct list_head killed;
+ unsigned long flags;
+ int i;
+
+ if (!husb || intf == husb->isoc_iface)
+ return 0;
+
+ hci_suspend_dev(husb->hdev);
+
+ INIT_LIST_HEAD(&killed);
+
+ for (i = 0; i < 4; i++) {
+ struct _urb_queue *q = &husb->pending_q[i];
+ struct _urb *_urb, *_tmp;
+
+ while ((_urb = _urb_dequeue(q))) {
+ /* reset queue since _urb_dequeue sets it to NULL */
+ _urb->queue = q;
+ usb_kill_urb(&_urb->urb);
+ list_add(&_urb->list, &killed);
+ }
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ list_for_each_entry_safe(_urb, _tmp, &killed, list) {
+ list_move_tail(&_urb->list, &q->head);
+ }
+
+ spin_unlock_irqrestore(&q->lock, flags);
+ }
+
+ return 0;
+}
+
+static int hci_usb_resume(struct usb_interface *intf)
+{
+ struct hci_usb *husb = usb_get_intfdata(intf);
+ unsigned long flags;
+ int i, err = 0;
+
+ if (!husb || intf == husb->isoc_iface)
+ return 0;
+
+ for (i = 0; i < 4; i++) {
+ struct _urb_queue *q = &husb->pending_q[i];
+ struct _urb *_urb;
+
+ spin_lock_irqsave(&q->lock, flags);
+
+ list_for_each_entry(_urb, &q->head, list) {
+ err = usb_submit_urb(&_urb->urb, GFP_ATOMIC);
+ if (err)
+ break;
+ }
+
+ spin_unlock_irqrestore(&q->lock, flags);
+
+ if (err)
+ return -EIO;
+ }
+
+ hci_resume_dev(husb->hdev);
+
+ return 0;
+}
+
static struct usb_driver hci_usb_driver = {
.name = "hci_usb",
.probe = hci_usb_probe,
.disconnect = hci_usb_disconnect,
+ .suspend = hci_usb_suspend,
+ .resume = hci_usb_resume,
.id_table = bluetooth_ids,
};
@@ -1082,6 +1173,12 @@ MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001");
module_param(ignore_sniffer, bool, 0644);
MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002");
+module_param(disable_scofix, bool, 0644);
+MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size");
+
+module_param(force_scofix, bool, 0644);
+MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size");
+
module_param(reset, bool, 0644);
MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h
index 37100a6ea1a..963fc55cdc8 100644
--- a/drivers/bluetooth/hci_usb.h
+++ b/drivers/bluetooth/hci_usb.h
@@ -35,6 +35,7 @@
#define HCI_SNIFFER 0x10
#define HCI_BCM92035 0x20
#define HCI_BROKEN_ISOC 0x40
+#define HCI_WRONG_SCO_MTU 0x80
#define HCI_MAX_IFACE_NUM 3
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 85738223ff0..a278d98a915 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -2,9 +2,9 @@
*
* Bluetooth virtual HCI driver
*
- * Copyright (C) 2000-2001 Qualcomm Incorporated
- * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -73,21 +72,21 @@ static int vhci_open_dev(struct hci_dev *hdev)
static int vhci_close_dev(struct hci_dev *hdev)
{
- struct vhci_data *vhci = hdev->driver_data;
+ struct vhci_data *data = hdev->driver_data;
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- skb_queue_purge(&vhci->readq);
+ skb_queue_purge(&data->readq);
return 0;
}
static int vhci_flush(struct hci_dev *hdev)
{
- struct vhci_data *vhci = hdev->driver_data;
+ struct vhci_data *data = hdev->driver_data;
- skb_queue_purge(&vhci->readq);
+ skb_queue_purge(&data->readq);
return 0;
}
@@ -95,7 +94,7 @@ static int vhci_flush(struct hci_dev *hdev)
static int vhci_send_frame(struct sk_buff *skb)
{
struct hci_dev* hdev = (struct hci_dev *) skb->dev;
- struct vhci_data *vhci;
+ struct vhci_data *data;
if (!hdev) {
BT_ERR("Frame for unknown HCI device (hdev=NULL)");
@@ -105,15 +104,15 @@ static int vhci_send_frame(struct sk_buff *skb)
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- vhci = hdev->driver_data;
+ data = hdev->driver_data;
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
- skb_queue_tail(&vhci->readq, skb);
+ skb_queue_tail(&data->readq, skb);
- if (vhci->flags & VHCI_FASYNC)
- kill_fasync(&vhci->fasync, SIGIO, POLL_IN);
+ if (data->flags & VHCI_FASYNC)
+ kill_fasync(&data->fasync, SIGIO, POLL_IN);
- wake_up_interruptible(&vhci->read_wait);
+ wake_up_interruptible(&data->read_wait);
return 0;
}
@@ -123,7 +122,7 @@ static void vhci_destruct(struct hci_dev *hdev)
kfree(hdev->driver_data);
}
-static inline ssize_t vhci_get_user(struct vhci_data *vhci,
+static inline ssize_t vhci_get_user(struct vhci_data *data,
const char __user *buf, size_t count)
{
struct sk_buff *skb;
@@ -140,7 +139,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *vhci,
return -EFAULT;
}
- skb->dev = (void *) vhci->hdev;
+ skb->dev = (void *) data->hdev;
bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
skb_pull(skb, 1);
@@ -149,7 +148,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *vhci,
return count;
}
-static inline ssize_t vhci_put_user(struct vhci_data *vhci,
+static inline ssize_t vhci_put_user(struct vhci_data *data,
struct sk_buff *skb, char __user *buf, int count)
{
char __user *ptr = buf;
@@ -162,42 +161,43 @@ static inline ssize_t vhci_put_user(struct vhci_data *vhci,
total += len;
- vhci->hdev->stat.byte_tx += len;
+ data->hdev->stat.byte_tx += len;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
- vhci->hdev->stat.cmd_tx++;
+ data->hdev->stat.cmd_tx++;
break;
case HCI_ACLDATA_PKT:
- vhci->hdev->stat.acl_tx++;
+ data->hdev->stat.acl_tx++;
break;
case HCI_SCODATA_PKT:
- vhci->hdev->stat.cmd_tx++;
+ data->hdev->stat.cmd_tx++;
break;
};
return total;
}
-static loff_t vhci_llseek(struct file * file, loff_t offset, int origin)
+static loff_t vhci_llseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
-static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, loff_t *pos)
+static ssize_t vhci_read(struct file *file,
+ char __user *buf, size_t count, loff_t *pos)
{
DECLARE_WAITQUEUE(wait, current);
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
struct sk_buff *skb;
ssize_t ret = 0;
- add_wait_queue(&vhci->read_wait, &wait);
+ add_wait_queue(&data->read_wait, &wait);
while (count) {
set_current_state(TASK_INTERRUPTIBLE);
- skb = skb_dequeue(&vhci->readq);
+ skb = skb_dequeue(&data->readq);
if (!skb) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
@@ -214,7 +214,7 @@ static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, lo
}
if (access_ok(VERIFY_WRITE, buf, count))
- ret = vhci_put_user(vhci, skb, buf, count);
+ ret = vhci_put_user(data, skb, buf, count);
else
ret = -EFAULT;
@@ -222,7 +222,7 @@ static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, lo
break;
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&vhci->read_wait, &wait);
+ remove_wait_queue(&data->read_wait, &wait);
return ret;
}
@@ -230,21 +230,21 @@ static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, lo
static ssize_t vhci_write(struct file *file,
const char __user *buf, size_t count, loff_t *pos)
{
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
- return vhci_get_user(vhci, buf, count);
+ return vhci_get_user(data, buf, count);
}
static unsigned int vhci_poll(struct file *file, poll_table *wait)
{
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
- poll_wait(file, &vhci->read_wait, wait);
+ poll_wait(file, &data->read_wait, wait);
- if (!skb_queue_empty(&vhci->readq))
+ if (!skb_queue_empty(&data->readq))
return POLLIN | POLLRDNORM;
return POLLOUT | POLLWRNORM;
@@ -258,27 +258,26 @@ static int vhci_ioctl(struct inode *inode, struct file *file,
static int vhci_open(struct inode *inode, struct file *file)
{
- struct vhci_data *vhci;
+ struct vhci_data *data;
struct hci_dev *hdev;
- vhci = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
- if (!vhci)
+ data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
- skb_queue_head_init(&vhci->readq);
- init_waitqueue_head(&vhci->read_wait);
+ skb_queue_head_init(&data->readq);
+ init_waitqueue_head(&data->read_wait);
hdev = hci_alloc_dev();
if (!hdev) {
- kfree(vhci);
+ kfree(data);
return -ENOMEM;
}
- vhci->hdev = hdev;
+ data->hdev = hdev;
- hdev->type = HCI_VHCI;
- hdev->driver_data = vhci;
- SET_HCIDEV_DEV(hdev, vhci_miscdev.dev);
+ hdev->type = HCI_VIRTUAL;
+ hdev->driver_data = data;
hdev->open = vhci_open_dev;
hdev->close = vhci_close_dev;
@@ -290,20 +289,20 @@ static int vhci_open(struct inode *inode, struct file *file)
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
- kfree(vhci);
+ kfree(data);
hci_free_dev(hdev);
return -EBUSY;
}
- file->private_data = vhci;
+ file->private_data = data;
return nonseekable_open(inode, file);
}
static int vhci_release(struct inode *inode, struct file *file)
{
- struct vhci_data *vhci = file->private_data;
- struct hci_dev *hdev = vhci->hdev;
+ struct vhci_data *data = file->private_data;
+ struct hci_dev *hdev = data->hdev;
if (hci_unregister_dev(hdev) < 0) {
BT_ERR("Can't unregister HCI device %s", hdev->name);
@@ -318,17 +317,17 @@ static int vhci_release(struct inode *inode, struct file *file)
static int vhci_fasync(int fd, struct file *file, int on)
{
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
int err;
- err = fasync_helper(fd, file, on, &vhci->fasync);
+ err = fasync_helper(fd, file, on, &data->fasync);
if (err < 0)
return err;
if (on)
- vhci->flags |= VHCI_FASYNC;
+ data->flags |= VHCI_FASYNC;
else
- vhci->flags &= ~VHCI_FASYNC;
+ data->flags &= ~VHCI_FASYNC;
return 0;
}
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index ec004897b63..ec469497c10 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1918,7 +1918,6 @@ static int __init aztcd_init(void)
azt_disk->first_minor = 0;
azt_disk->fops = &azt_fops;
sprintf(azt_disk->disk_name, "aztcd");
- sprintf(azt_disk->devfs_name, "aztcd");
azt_disk->queue = azt_queue;
add_disk(azt_disk);
azt_invalidate_buffers();
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index 3170eaa2508..d239cf8b20b 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -263,7 +263,6 @@
/* #define ERRLOGMASK (CD_WARNING|CD_OPEN|CD_COUNT_TRACKS|CD_CLOSE) */
/* #define ERRLOGMASK (CD_WARNING|CD_REG_UNREG|CD_DO_IOCTL|CD_OPEN|CD_CLOSE|CD_COUNT_TRACKS) */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/buffer_head.h>
@@ -1838,7 +1837,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s)
init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ);
cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
cgc.cmd[7] = s->type;
- cgc.cmd[9] = cgc.buflen = 0xff;
+ cgc.cmd[9] = cgc.buflen & 0xff;
if ((ret = cdo->generic_packet(cdi, &cgc)))
return ret;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 72ffd64e8b1..37bdb0163f0 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -161,7 +161,6 @@
#include <linux/hdreg.h>
#include <linux/genhd.h>
#include <linux/ioport.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -3142,7 +3141,7 @@ int __init cdu31a_init(void)
if (cdu31a_irq > 0) {
if (request_irq
- (cdu31a_irq, cdu31a_interrupt, SA_INTERRUPT,
+ (cdu31a_irq, cdu31a_interrupt, IRQF_DISABLED,
"cdu31a", NULL)) {
printk(KERN_WARNING PFX "Unable to grab IRQ%d for "
"the CDU31A driver\n", cdu31a_irq);
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index f43a988dd41..9b05ddd2314 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -187,7 +187,6 @@ History:
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/cdrom.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -915,7 +914,7 @@ static void seek(int lba)
cd->dsb = wait_dsb();
}
-uch bcdbin(unsigned char bcd)
+static uch bcdbin(unsigned char bcd)
{ /* stolen from mcd.c! */
return (bcd >> 4) * 10 + (bcd & 0xf);
}
@@ -1533,7 +1532,7 @@ static void __init parse_options(void)
}
}
-static int __cm206_init(void)
+static int __init __cm206_init(void)
{
parse_options();
#if !defined(AUTO_PROBE_MODULE)
@@ -1594,8 +1593,3 @@ __setup("cm206=", cm206_setup);
#endif /* !MODULE */
MODULE_ALIAS_BLOCKDEV_MAJOR(CM206_CDROM_MAJOR);
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c"
- * End:
- */
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index ad5464ab99b..fa708248976 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -266,7 +266,7 @@ repeat:
goto out;
if (req->cmd != READ) {
- printk("GSCD: bad cmd %lu\n", rq_data_dir(req));
+ printk("GSCD: bad cmd %u\n", rq_data_dir(req));
end_request(req, 0);
goto repeat;
}
@@ -955,7 +955,6 @@ static int __init gscd_init(void)
gscd_disk->first_minor = 0;
gscd_disk->fops = &gscd_fops;
sprintf(gscd_disk->disk_name, "gscd");
- sprintf(gscd_disk->devfs_name, "gscd");
if (register_blkdev(MAJOR_NR, "gscd")) {
ret = -EIO;
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index a0b580c22d8..dcd1ab684f3 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -74,7 +74,6 @@ static const char *mcdx_c_version
#include <linux/major.h>
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
#include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
#include "mcdx.h"
@@ -1006,7 +1005,7 @@ static int mcdx_talk(struct s_drive_stuff *stuffp,
/* MODULE STUFF ***********************************************************/
-int __mcdx_init(void)
+static int __init __mcdx_init(void)
{
int i;
int drives = 0;
@@ -1194,7 +1193,7 @@ static int __init mcdx_init_drive(int drive)
}
xtrace(INIT, "init() subscribe irq and i/o\n");
- if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", stuffp)) {
+ if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) {
release_region(stuffp->wreg_data, MCDX_IO_SIZE);
xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index 0b0eab4f40f..25032d7edc5 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -2033,7 +2033,6 @@ static int __init optcd_init(void)
optcd_disk->first_minor = 0;
optcd_disk->fops = &opt_fops;
sprintf(optcd_disk->disk_name, "optcd");
- sprintf(optcd_disk->devfs_name, "optcd");
if (!request_region(optcd_port, 4, "optcd")) {
printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n",
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 05c9e865eca..ba50e5a712f 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -371,7 +371,6 @@
#include <linux/kernel.h>
#include <linux/cdrom.h>
#include <linux/ioport.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/vmalloc.h>
@@ -382,7 +381,6 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <stdarg.h>
-#include <linux/config.h>
#include "sbpcd.h"
#define MAJOR_NR MATSUSHITA_CDROM_MAJOR
@@ -5808,8 +5806,6 @@ int __init sbpcd_init(void)
return -ENOMEM;
}
- devfs_mk_dir("sbp");
-
for (j=0;j<NR_SBPCD;j++)
{
struct cdrom_device_info * sbpcd_infop;
@@ -5871,7 +5867,6 @@ int __init sbpcd_init(void)
disk->fops = &sbpcd_bdops;
strcpy(disk->disk_name, sbpcd_infop->name);
disk->flags = GENHD_FL_CD;
- sprintf(disk->devfs_name, "sbp/c0t%d", p->drv_id);
p->disk = disk;
if (register_cdrom(sbpcd_infop))
{
@@ -5906,7 +5901,6 @@ static void sbpcd_exit(void)
if (D_S[j].drv_id==-1) continue;
del_gendisk(D_S[j].disk);
put_disk(D_S[j].disk);
- devfs_remove("sbp/c0t%d", j);
vfree(D_S[j].sbp_buf);
if (D_S[j].sbp_audsiz>0)
vfree(D_S[j].aud_buf);
@@ -5917,7 +5911,6 @@ static void sbpcd_exit(void)
}
vfree(D_S[j].sbpcd_infop);
}
- devfs_remove("sbp");
msg(DBG_INF, "%s module released.\n", major_name);
}
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index 74b1cadbf16..bf5aef4e555 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -1695,7 +1695,6 @@ static int __init sjcd_init(void)
sjcd_disk->first_minor = 0,
sjcd_disk->fops = &sjcd_fops,
sprintf(sjcd_disk->disk_name, "sjcd");
- sprintf(sjcd_disk->devfs_name, "sjcd");
if (!request_region(sjcd_base, 4,"sjcd")) {
printk
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index e6565992643..30ab56258a9 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1527,7 +1527,7 @@ static int __init sony535_init(void)
}
if (sony535_irq_used > 0) {
if (request_irq(sony535_irq_used, cdu535_interrupt,
- SA_INTERRUPT, CDU535_HANDLE, NULL)) {
+ IRQF_DISABLED, CDU535_HANDLE, NULL)) {
printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME
" driver; polling instead.\n", sony535_irq_used);
sony535_irq_used = 0;
@@ -1589,7 +1589,6 @@ static int __init sony535_init(void)
cdu_disk->first_minor = 0;
cdu_disk->fops = &cdu_fops;
sprintf(cdu_disk->disk_name, "cdu");
- sprintf(cdu_disk->devfs_name, "cdu535");
if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) {
printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n",
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index af6b3bfd169..54ca931e19e 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -49,7 +49,6 @@
#include <asm/iseries/vio.h>
#define VIOCD_DEVICE "iseries/vcd"
-#define VIOCD_DEVICE_DEVFS "iseries/vcd"
#define VIOCD_VERS "1.06"
@@ -688,8 +687,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
gendisk->first_minor = deviceno;
strncpy(gendisk->disk_name, c->name,
sizeof(gendisk->disk_name));
- snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name),
- VIOCD_DEVICE_DEVFS "%d", deviceno);
blk_queue_max_hw_segments(q, 1);
blk_queue_max_phys_segments(q, 1);
blk_queue_max_sectors(q, 4096 / 512);
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 78d928f9d9f..4cc619edf42 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -62,6 +62,23 @@ config HW_CONSOLE
depends on VT && !S390 && !UML
default y
+config VT_HW_CONSOLE_BINDING
+ bool "Support for binding and unbinding console drivers"
+ depends on HW_CONSOLE
+ default n
+ ---help---
+ The virtual terminal is the device that interacts with the physical
+ terminal through console drivers. On these systems, at least one
+ console driver is loaded. In other configurations, additional console
+ drivers may be enabled, such as the framebuffer console. If more than
+ 1 console driver is enabled, setting this to 'y' will allow you to
+ select the console driver that will serve as the backend for the
+ virtual terminals.
+
+ See <file:Documentation/console/console.txt> for more
+ information. For framebuffer console users, please refer to
+ <file:Documentation/fb/fbcon.txt>.
+
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
---help---
@@ -422,6 +439,14 @@ config SGI_MBCS
If you have an SGI Altix with an attached SABrick
say Y or M here, otherwise say N.
+config MSPEC
+ tristate "Memory special operations driver"
+ depends on IA64
+ help
+ If you have an ia64 and you want to enable memory special
+ operations support (formerly known as fetchop), say Y here,
+ otherwise say N.
+
source "drivers/serial/Kconfig"
config UNIX98_PTYS
@@ -478,6 +503,21 @@ config LEGACY_PTY_COUNT
When not in use, each legacy PTY occupies 12 bytes on 32-bit
architectures and 24 bytes on 64-bit architectures.
+config BRIQ_PANEL
+ tristate 'Total Impact briQ front panel driver'
+ depends on PPC_CHRP
+ ---help---
+ The briQ is a small footprint CHRP computer with a frontpanel VFD, a
+ tristate led and two switches. It is the size of a CDROM drive.
+
+ If you have such one and want anything showing on the VFD then you
+ must answer Y here.
+
+ To compile this driver as a module, choose M here: the
+ module will be called briq_panel.
+
+ It's safe to say N here.
+
config PRINTER
tristate "Parallel printer support"
depends on PARPORT
@@ -579,6 +619,13 @@ config HVC_CONSOLE
console. This driver allows each pSeries partition to have a console
which is accessed via the HMC.
+config HVC_ISERIES
+ bool "iSeries Hypervisor Virtual Console support"
+ depends on PPC_ISERIES && !VIOCONS
+ select HVC_DRIVER
+ help
+ iSeries machines support a hypervisor virtual console.
+
config HVC_RTAS
bool "IBM RTAS Console support"
depends on PPC_RTAS
@@ -670,20 +717,7 @@ config NWFLASH
If you're not sure, say N.
-config HW_RANDOM
- tristate "Intel/AMD/VIA HW Random Number Generator support"
- depends on (X86 || IA64) && PCI
- ---help---
- This driver provides kernel-side support for the Random Number
- Generator hardware found on Intel i8xx-based motherboards,
- AMD 76x-based motherboards, and Via Nehemiah CPUs.
-
- Provides a character driver, used to read() entropy data.
-
- To compile this driver as a module, choose M here: the
- module will be called hw_random.
-
- If unsure, say N.
+source "drivers/char/hw_random/Kconfig"
config NVRAM
tristate "/dev/nvram support"
@@ -713,7 +747,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM
+ depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -797,14 +831,6 @@ config DS1302
will get access to the real time clock (or hardware clock) built
into your computer.
-config S3C2410_RTC
- bool "S3C2410 RTC Driver"
- depends on ARCH_S3C2410
- help
- RTC (Realtime Clock) driver for the clock inbuilt into the
- Samsung S3C2410. This can provide periodic interrupt rates
- from 1Hz to 64Hz for user programs, and wakeup from Alarm.
-
config COBALT_LCD
bool "Support for Cobalt LCD"
depends on MIPS_COBALT
@@ -865,6 +891,7 @@ config SONYPI
config TANBAC_TB0219
tristate "TANBAC TB0219 base board support"
depends TANBAC_TB022X
+ select GPIO_VR41XX
menu "Ftape, the floppy tape device driver"
@@ -934,12 +961,36 @@ config MWAVE
config SCx200_GPIO
tristate "NatSemi SCx200 GPIO Support"
depends on SCx200
+ select NSC_GPIO
help
Give userspace access to the GPIO pins on the National
Semiconductor SCx200 processors.
If compiled as a module, it will be called scx200_gpio.
+config PC8736x_GPIO
+ tristate "NatSemi PC8736x GPIO Support"
+ depends on X86
+ default SCx200_GPIO # mostly N
+ select NSC_GPIO # needed for support routines
+ help
+ Give userspace access to the GPIO pins on the National
+ Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip
+ has multiple functional units, inc several managed by
+ hwmon/pc87360 driver. Tested with PC-87366
+
+ If compiled as a module, it will be called pc8736x_gpio.
+
+config NSC_GPIO
+ tristate "NatSemi Base GPIO Support"
+ depends on X86_32
+ # selected by SCx200_GPIO and PC8736x_GPIO
+ # what about 2 selectors differing: m != y
+ help
+ Common support used (and needed) by scx200_gpio and
+ pc8736x_gpio drivers. If those drivers are built as
+ modules, this one will be too, named nsc_gpio
+
config CS5535_GPIO
tristate "AMD CS5535/CS5536 GPIO (Geode Companion Device)"
depends on X86_32
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index fb919bfb282..19114df59bb 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -42,15 +42,18 @@ obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o
obj-$(CONFIG_SX) += sx.o generic_serial.o
obj-$(CONFIG_RIO) += rio/ generic_serial.o
obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o
+obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
+obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_VIOCONS) += viocons.o
obj-$(CONFIG_VIOTAPE) += viotape.o
obj-$(CONFIG_HVCS) += hvcs.o
obj-$(CONFIG_SGI_MBCS) += mbcs.o
+obj-$(CONFIG_BRIQ_PANEL) += briq_panel.o
obj-$(CONFIG_PRINTER) += lp.o
obj-$(CONFIG_TIPAR) += tipar.o
@@ -66,7 +69,6 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
-obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
@@ -75,13 +77,15 @@ endif
obj-$(CONFIG_TOSHIBA) += toshiba.o
obj-$(CONFIG_I8K) += i8k.o
obj-$(CONFIG_DS1620) += ds1620.o
-obj-$(CONFIG_HW_RANDOM) += hw_random.o
+obj-$(CONFIG_HW_RANDOM) += hw_random/
obj-$(CONFIG_FTAPE) += ftape/
obj-$(CONFIG_COBALT_LCD) += lcd.o
obj-$(CONFIG_PPDEV) += ppdev.o
obj-$(CONFIG_NWBUTTON) += nwbutton.o
obj-$(CONFIG_NWFLASH) += nwflash.o
obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
+obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
+obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_TANBAC_TB0219) += tb0219.o
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 46685a54077..22f8cf218cc 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -1,6 +1,7 @@
config AGP
tristate "/dev/agpgart (AGP Support)"
depends on ALPHA || IA64 || PPC || X86
+ depends on PCI
---help---
AGP (Accelerated Graphics Port) is a bus system mainly used to
connect graphics cards to the rest of the system.
@@ -55,9 +56,9 @@ config AGP_AMD
X on AMD Irongate, 761, and 762 chipsets.
config AGP_AMD64
- tristate "AMD Opteron/Athlon64 on-CPU GART support" if !GART_IOMMU
+ tristate "AMD Opteron/Athlon64 on-CPU GART support" if !IOMMU
depends on AGP && X86
- default y if GART_IOMMU
+ default y if IOMMU
help
This option gives you AGP support for the GLX component of
X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs.
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 3c623b67ea1..8b3317fd46c 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -117,7 +117,7 @@ struct agp_bridge_driver {
};
struct agp_bridge_data {
- struct agp_version *version;
+ const struct agp_version *version;
struct agp_bridge_driver *driver;
struct vm_operations_struct *vm_ops;
void *previous_size;
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 1f776651ac6..51d0d562d01 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -118,7 +118,7 @@ static int amd_create_gatt_pages(int nr_tables)
return retval;
}
-/* Since we don't need contigious memory we just try
+/* Since we don't need contiguous memory we just try
* to get the gatt table once
*/
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index ac3c33a2e37..8cd52984cda 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -8,18 +8,15 @@
* work is done in the northbridge(s).
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/agp_backend.h>
#include <linux/mmzone.h>
#include <asm/page.h> /* PAGE_SIZE */
+#include <asm/k8.h>
#include "agp.h"
-/* Will need to be increased if AMD64 ever goes >8-way. */
-#define MAX_HAMMER_GARTS 8
-
/* PTE bits. */
#define GPTE_VALID 1
#define GPTE_COHERENT 2
@@ -53,28 +50,12 @@
#define ULI_X86_64_HTT_FEA_REG 0x50
#define ULI_X86_64_ENU_SCR_REG 0x54
-static int nr_garts;
-static struct pci_dev * hammers[MAX_HAMMER_GARTS];
-
static struct resource *aperture_resource;
static int __initdata agp_try_unsupported = 1;
-#define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++)
-
-static void flush_amd64_tlb(struct pci_dev *dev)
-{
- u32 tmp;
-
- pci_read_config_dword (dev, AMD64_GARTCACHECTL, &tmp);
- tmp |= INVGART;
- pci_write_config_dword (dev, AMD64_GARTCACHECTL, tmp);
-}
-
static void amd64_tlbflush(struct agp_memory *temp)
{
- int gart_iterator;
- for_each_nb()
- flush_amd64_tlb(hammers[gart_iterator]);
+ k8_flush_garts();
}
static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
@@ -153,7 +134,7 @@ static int amd64_fetch_size(void)
u32 temp;
struct aper_size_info_32 *values;
- dev = hammers[0];
+ dev = k8_northbridges[0];
if (dev==NULL)
return 0;
@@ -201,9 +182,6 @@ static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table)
tmp &= ~(DISGARTCPU | DISGARTIO);
pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp);
- /* keep CPU's coherent. */
- flush_amd64_tlb (hammer);
-
return aper_base;
}
@@ -222,13 +200,14 @@ static struct aper_size_info_32 amd_8151_sizes[7] =
static int amd_8151_configure(void)
{
unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real);
- int gart_iterator;
+ int i;
/* Configure AGP regs in each x86-64 host bridge. */
- for_each_nb() {
+ for (i = 0; i < num_k8_northbridges; i++) {
agp_bridge->gart_bus_addr =
- amd64_configure(hammers[gart_iterator],gatt_bus);
+ amd64_configure(k8_northbridges[i], gatt_bus);
}
+ k8_flush_garts();
return 0;
}
@@ -236,12 +215,13 @@ static int amd_8151_configure(void)
static void amd64_cleanup(void)
{
u32 tmp;
- int gart_iterator;
- for_each_nb() {
+ int i;
+ for (i = 0; i < num_k8_northbridges; i++) {
+ struct pci_dev *dev = k8_northbridges[i];
/* disable gart translation */
- pci_read_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, &tmp);
+ pci_read_config_dword (dev, AMD64_GARTAPERTURECTL, &tmp);
tmp &= ~AMD64_GARTEN;
- pci_write_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, tmp);
+ pci_write_config_dword (dev, AMD64_GARTAPERTURECTL, tmp);
}
}
@@ -311,7 +291,7 @@ static int __devinit aperture_valid(u64 aper, u32 size)
/*
* W*s centric BIOS sometimes only set up the aperture in the AGP
* bridge, not the northbridge. On AMD64 this is handled early
- * in aperture.c, but when GART_IOMMU is not enabled or we run
+ * in aperture.c, but when IOMMU is not enabled or we run
* on a 32bit kernel this needs to be redone.
* Unfortunately it is impossible to fix the aperture here because it's too late
* to allocate that much memory. But at least error out cleanly instead of
@@ -361,17 +341,15 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
{
- struct pci_dev *loop_dev = NULL;
- int i = 0;
-
- /* cache pci_devs of northbridges. */
- while ((loop_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev))
- != NULL) {
- if (i == MAX_HAMMER_GARTS) {
- printk(KERN_ERR PFX "Too many northbridges for AGP\n");
- return -1;
- }
- if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) {
+ int i;
+
+ if (cache_k8_northbridges() < 0)
+ return -ENODEV;
+
+ i = 0;
+ for (i = 0; i < num_k8_northbridges; i++) {
+ struct pci_dev *dev = k8_northbridges[i];
+ if (fix_northbridge(dev, pdev, cap_ptr) < 0) {
printk(KERN_ERR PFX "No usable aperture found.\n");
#ifdef __x86_64__
/* should port this to i386 */
@@ -379,10 +357,8 @@ static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr)
#endif
return -1;
}
- hammers[i++] = loop_dev;
}
- nr_garts = i;
- return i == 0 ? -1 : 0;
+ return 0;
}
/* Handle AMD 8151 quirks */
@@ -450,7 +426,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev)
}
/* shadow x86-64 registers into ULi registers */
- pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea);
+ pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &httfea);
/* if x86-64 aperture base is beyond 4G, exit here */
if ((httfea & 0x7fff) >> (32 - 25))
@@ -513,7 +489,7 @@ static int __devinit nforce3_agp_init(struct pci_dev *pdev)
pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp);
/* shadow x86-64 registers into NVIDIA registers */
- pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase);
+ pci_read_config_dword (k8_northbridges[0], AMD64_GARTAPERTUREBASE, &apbase);
/* if x86-64 aperture base is beyond 4G, exit here */
if ( (apbase & 0x7fff) >> (32 - 25) ) {
@@ -754,14 +730,10 @@ static struct pci_driver agp_amd64_pci_driver = {
int __init agp_amd64_init(void)
{
int err = 0;
- static struct pci_device_id amd64nb[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) },
- { },
- };
if (agp_off)
return -EINVAL;
- if (pci_register_driver(&agp_amd64_pci_driver) > 0) {
+ if (pci_register_driver(&agp_amd64_pci_driver) < 0) {
struct pci_dev *dev;
if (!agp_try_unsupported && !agp_try_unsupported_boot) {
printk(KERN_INFO PFX "No supported AGP bridge found.\n");
@@ -774,7 +746,7 @@ int __init agp_amd64_init(void)
}
/* First check that we have at least one AMD64 NB */
- if (!pci_dev_present(amd64nb))
+ if (!pci_dev_present(k8_nb_ids))
return -ENODEV;
/* Look for any AGP bridge */
@@ -802,7 +774,7 @@ static void __exit agp_amd64_cleanup(void)
/* On AMD64 the PCI driver needs to initialize this driver early
for the IOMMU, so it has to be called via a backdoor. */
-#ifndef CONFIG_GART_IOMMU
+#ifndef CONFIG_IOMMU
module_init(agp_amd64_init);
module_exit(agp_amd64_cleanup);
#endif
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index 06fd10ba0c5..f244c668273 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -41,7 +41,6 @@ static struct gatt_mask ati_generic_masks[] =
};
-
typedef struct _ati_page_map {
unsigned long *real;
unsigned long __iomem *remapped;
@@ -141,7 +140,8 @@ static int ati_create_gatt_pages(int nr_tables)
ati_generic_private.num_tables = nr_tables;
ati_generic_private.gatt_pages = tables;
- if (retval != 0) ati_free_gatt_pages();
+ if (retval != 0)
+ ati_free_gatt_pages();
return retval;
}
@@ -219,16 +219,16 @@ static int ati_configure(void)
ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
if (is_r200())
- pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
+ pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
else
pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
/* address to map too */
- /*
+ /*
pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp);
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
- */
+ */
writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/
@@ -245,23 +245,25 @@ static int ati_configure(void)
#ifdef CONFIG_PM
-static int agp_ati_resume(struct pci_dev *dev)
+static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
{
- pci_restore_state(dev);
+ pci_save_state(dev);
+ pci_set_power_state(dev, 3);
- return ati_configure();
+ return 0;
}
-static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
+static int agp_ati_resume(struct pci_dev *dev)
{
- pci_save_state(dev);
+ pci_set_power_state(dev, 0);
+ pci_restore_state(dev);
- return 0;
+ return ati_configure();
}
#endif
/*
- *Since we don't need contigious memory we just try
+ *Since we don't need contiguous memory we just try
* to get the gatt table once
*/
@@ -321,9 +323,9 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
unsigned long __iomem *cur_gatt;
unsigned long addr;
- if (type != 0 || mem->type != 0) {
+ if (type != 0 || mem->type != 0)
return -EINVAL;
- }
+
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
@@ -502,9 +504,8 @@ found:
bridge->dev = pdev;
bridge->capndx = cap_ptr;
-
- bridge->driver = &ati_generic_bridge;
+ bridge->driver = &ati_generic_bridge;
printk(KERN_INFO PFX "Detected Ati %s chipset\n",
devs[j].chipset_name);
@@ -546,8 +547,8 @@ static struct pci_driver agp_ati_pci_driver = {
.probe = agp_ati_probe,
.remove = agp_ati_remove,
#ifdef CONFIG_PM
- .resume = agp_ati_resume,
.suspend = agp_ati_suspend,
+ .resume = agp_ati_resume,
#endif
};
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 509adc40325..d59e037ddd1 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -44,7 +44,7 @@
* past 0.99 at all due to some boolean logic error. */
#define AGPGART_VERSION_MAJOR 0
#define AGPGART_VERSION_MINOR 101
-static struct agp_version agp_current_version =
+static const struct agp_version agp_current_version =
{
.major = AGPGART_VERSION_MAJOR,
.minor = AGPGART_VERSION_MINOR,
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 86a966b6523..30f730ff81c 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -177,7 +177,7 @@ static int efficeon_free_gatt_table(struct agp_bridge_data *bridge)
/*
- * Since we don't need contigious memory we just try
+ * Since we don't need contiguous memory we just try
* to get the gatt table once
*/
@@ -337,13 +337,6 @@ static struct agp_bridge_driver efficeon_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
-
-static int agp_efficeon_resume(struct pci_dev *pdev)
-{
- printk(KERN_DEBUG PFX "agp_efficeon_resume()\n");
- return efficeon_configure();
-}
-
static int __devinit agp_efficeon_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -414,11 +407,18 @@ static void __devexit agp_efficeon_remove(struct pci_dev *pdev)
agp_put_bridge(bridge);
}
+#ifdef CONFIG_PM
static int agp_efficeon_suspend(struct pci_dev *dev, pm_message_t state)
{
return 0;
}
+static int agp_efficeon_resume(struct pci_dev *pdev)
+{
+ printk(KERN_DEBUG PFX "agp_efficeon_resume()\n");
+ return efficeon_configure();
+}
+#endif
static struct pci_device_id agp_efficeon_pci_table[] = {
{
@@ -439,8 +439,10 @@ static struct pci_driver agp_efficeon_pci_driver = {
.id_table = agp_efficeon_pci_table,
.probe = agp_efficeon_probe,
.remove = agp_efficeon_remove,
+#ifdef CONFIG_PM
.suspend = agp_efficeon_suspend,
.resume = agp_efficeon_resume,
+#endif
};
static int __init agp_efficeon_init(void)
diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
index ffcf15c30e9..0f2ed2aa2d8 100644
--- a/drivers/char/agp/frontend.c
+++ b/drivers/char/agp/frontend.c
@@ -151,35 +151,12 @@ static void agp_add_seg_to_client(struct agp_client *client,
client->segments = seg;
}
-/* Originally taken from linux/mm/mmap.c from the array
- * protection_map.
- * The original really should be exported to modules, or
- * some routine which does the conversion for you
- */
-
-static const pgprot_t my_protect_map[16] =
-{
- __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
- __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
-};
-
static pgprot_t agp_convert_mmap_flags(int prot)
{
-#define _trans(x,bit1,bit2) \
-((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
-
unsigned long prot_bits;
- pgprot_t temp;
-
- prot_bits = _trans(prot, PROT_READ, VM_READ) |
- _trans(prot, PROT_WRITE, VM_WRITE) |
- _trans(prot, PROT_EXEC, VM_EXEC);
-
- prot_bits |= VM_SHARED;
- temp = my_protect_map[prot_bits & 0x0000000f];
-
- return temp;
+ prot_bits = calc_vm_prot_bits(prot) | VM_SHARED;
+ return vm_get_page_prot(prot_bits);
}
static int agp_create_segment(struct agp_client *client, struct agp_region *region)
@@ -1059,7 +1036,7 @@ ioctl_out:
return ret_val;
}
-static struct file_operations agp_fops =
+static const struct file_operations agp_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index a92ab53a137..0dcdb363923 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -27,7 +27,6 @@
* TODO:
* - Allocate more than order 0 pages to avoid too much linear map splitting.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -569,25 +568,34 @@ static void agp_v3_parse_one(u32 *requested_mode, u32 *bridge_agpstat, u32 *vga_
*bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
goto done;
+ } else if (*requested_mode & AGPSTAT3_4X) {
+ *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+ *bridge_agpstat |= AGPSTAT3_4X;
+ goto done;
+
} else {
/*
- * If we didn't specify AGPx8, we can only do x4.
- * If the hardware can't do x4, we're up shit creek, and never
- * should have got this far.
+ * If we didn't specify an AGP mode, we see if both
+ * the graphics card, and the bridge can do x8, and use if so.
+ * If not, we fall back to x4 mode.
*/
- *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
- if ((*bridge_agpstat & AGPSTAT3_4X) && (*vga_agpstat & AGPSTAT3_4X))
- *bridge_agpstat |= AGPSTAT3_4X;
- else {
- printk(KERN_INFO PFX "Badness. Don't know which AGP mode to set. "
- "[bridge_agpstat:%x vga_agpstat:%x fell back to:- bridge_agpstat:%x vga_agpstat:%x]\n",
- origbridge, origvga, *bridge_agpstat, *vga_agpstat);
- if (!(*bridge_agpstat & AGPSTAT3_4X))
- printk(KERN_INFO PFX "Bridge couldn't do AGP x4.\n");
- if (!(*vga_agpstat & AGPSTAT3_4X))
- printk(KERN_INFO PFX "Graphic card couldn't do AGP x4.\n");
- return;
+ if ((*bridge_agpstat & AGPSTAT3_8X) && (*vga_agpstat & AGPSTAT3_8X)) {
+ printk(KERN_INFO PFX "No AGP mode specified. Setting to highest mode supported by bridge & card (x8).\n");
+ *bridge_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
+ *vga_agpstat &= ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
+ } else {
+ printk(KERN_INFO PFX "Fell back to AGPx4 mode because");
+ if (!(*bridge_agpstat & AGPSTAT3_8X)) {
+ printk("bridge couldn't do x8. bridge_agpstat:%x (orig=%x)\n", *bridge_agpstat, origbridge);
+ *bridge_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+ *bridge_agpstat |= AGPSTAT3_4X;
+ }
+ if (!(*vga_agpstat & AGPSTAT3_8X)) {
+ printk("graphics card couldn't do x8. vga_agpstat:%x (orig=%x)\n", *vga_agpstat, origvga);
+ *vga_agpstat &= ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+ *vga_agpstat |= AGPSTAT3_4X;
+ }
}
}
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 61ac3809f99..d1ede7db5a1 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -2,14 +2,6 @@
* Intel AGPGART routines.
*/
-/*
- * Intel(R) 855GM/852GM and 865G support added by David Dawes
- * <dawes@tungstengraphics.com>.
- *
- * Intel(R) 915G/915GM support added by Alan Hourihane
- * <alanh@tungstengraphics.com>.
- */
-
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
@@ -17,6 +9,21 @@
#include <linux/agp_backend.h>
#include "agp.h"
+#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
+#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972
+#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980
+#define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982
+#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990
+#define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992
+#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0
+#define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2
+
+#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB)
+
+
/* Intel 815 register */
#define INTEL_815_APCONT 0x51
#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
@@ -40,6 +47,8 @@
#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)
#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
+/* Intel 965G registers */
+#define I965_MSAC 0x62
/* Intel 7505 registers */
#define INTEL_I7505_APSIZE 0x74
@@ -354,6 +363,7 @@ static struct aper_size_info_fixed intel_i830_sizes[] =
/* The 64M mode still requires a 128k gatt */
{64, 16384, 5},
{256, 65536, 6},
+ {512, 131072, 7},
};
static struct _intel_i830_private {
@@ -377,7 +387,11 @@ static void intel_i830_init_gtt_entries(void)
/* We obtain the size of the GTT, which is also stored (for some
* reason) at the top of stolen memory. Then we add 4KB to that
* for the video BIOS popup, which is also stored in there. */
- size = agp_bridge->driver->fetch_size() + 4;
+
+ if (IS_I965)
+ size = 512 + 4;
+ else
+ size = agp_bridge->driver->fetch_size() + 4;
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
@@ -423,7 +437,7 @@ static void intel_i830_init_gtt_entries(void)
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB)
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 )
gtt_entries = MB(48) - KB(size);
else
gtt_entries = 0;
@@ -433,7 +447,7 @@ static void intel_i830_init_gtt_entries(void)
if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB ||
agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB ||
- agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB)
+ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965)
gtt_entries = MB(64) - KB(size);
else
gtt_entries = 0;
@@ -791,6 +805,77 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
return 0;
}
+static int intel_i965_fetch_size(void)
+{
+ struct aper_size_info_fixed *values;
+ u32 offset = 0;
+ u8 temp;
+
+#define I965_512MB_ADDRESS_MASK (3<<1)
+
+ values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
+
+ pci_read_config_byte(intel_i830_private.i830_dev, I965_MSAC, &temp);
+ temp &= I965_512MB_ADDRESS_MASK;
+ switch (temp) {
+ case 0x00:
+ offset = 0; /* 128MB */
+ break;
+ case 0x06:
+ offset = 3; /* 512MB */
+ break;
+ default:
+ case 0x02:
+ offset = 2; /* 256MB */
+ break;
+ }
+
+ agp_bridge->previous_size = agp_bridge->current_size = (void *)(values + offset);
+
+ return values[offset].size;
+}
+
+/* The intel i965 automatically initializes the agp aperture during POST.
++ * Use the memory already set aside for in the GTT.
++ */
+static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
+{
+ int page_order;
+ struct aper_size_info_fixed *size;
+ int num_entries;
+ u32 temp;
+
+ size = agp_bridge->current_size;
+ page_order = size->page_order;
+ num_entries = size->num_entries;
+ agp_bridge->gatt_table_real = NULL;
+
+ pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp);
+
+ temp &= 0xfff00000;
+ intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024);
+
+ if (!intel_i830_private.gtt)
+ return -ENOMEM;
+
+
+ intel_i830_private.registers = ioremap(temp,128 * 4096);
+ if (!intel_i830_private.registers)
+ return -ENOMEM;
+
+ temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000;
+ global_cache_flush(); /* FIXME: ? */
+
+ /* we have to call this as early as possible after the MMIO base address is known */
+ intel_i830_init_gtt_entries();
+
+ agp_bridge->gatt_table = NULL;
+
+ agp_bridge->gatt_bus_addr = temp;
+
+ return 0;
+}
+
static int intel_fetch_size(void)
{
@@ -1307,7 +1392,7 @@ static struct agp_bridge_driver intel_830_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 3,
+ .num_aperture_sizes = 4,
.needs_scratch_page = TRUE,
.configure = intel_i830_configure,
.fetch_size = intel_i830_fetch_size,
@@ -1469,7 +1554,7 @@ static struct agp_bridge_driver intel_915_driver = {
.owner = THIS_MODULE,
.aperture_sizes = intel_i830_sizes,
.size_type = FIXED_APER_SIZE,
- .num_aperture_sizes = 3,
+ .num_aperture_sizes = 4,
.needs_scratch_page = TRUE,
.configure = intel_i915_configure,
.fetch_size = intel_i915_fetch_size,
@@ -1489,6 +1574,29 @@ static struct agp_bridge_driver intel_915_driver = {
.agp_destroy_page = agp_generic_destroy_page,
};
+static struct agp_bridge_driver intel_i965_driver = {
+ .owner = THIS_MODULE,
+ .aperture_sizes = intel_i830_sizes,
+ .size_type = FIXED_APER_SIZE,
+ .num_aperture_sizes = 4,
+ .needs_scratch_page = TRUE,
+ .configure = intel_i915_configure,
+ .fetch_size = intel_i965_fetch_size,
+ .cleanup = intel_i915_cleanup,
+ .tlb_flush = intel_i810_tlbflush,
+ .mask_memory = intel_i810_mask_memory,
+ .masks = intel_i810_masks,
+ .agp_enable = intel_i810_agp_enable,
+ .cache_flush = global_cache_flush,
+ .create_gatt_table = intel_i965_create_gatt_table,
+ .free_gatt_table = intel_i830_free_gatt_table,
+ .insert_memory = intel_i915_insert_entries,
+ .remove_memory = intel_i915_remove_entries,
+ .alloc_by_type = intel_i830_alloc_by_type,
+ .free_by_type = intel_i810_free_by_type,
+ .agp_alloc_page = agp_generic_alloc_page,
+ .agp_destroy_page = agp_generic_destroy_page,
+};
static struct agp_bridge_driver intel_7505_driver = {
.owner = THIS_MODULE,
@@ -1684,6 +1792,35 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev,
bridge->driver = &intel_845_driver;
name = "945GM";
break;
+ case PCI_DEVICE_ID_INTEL_82946GZ_HB:
+ if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG))
+ bridge->driver = &intel_i965_driver;
+ else
+ bridge->driver = &intel_845_driver;
+ name = "946GZ";
+ break;
+ case PCI_DEVICE_ID_INTEL_82965G_1_HB:
+ if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG))
+ bridge->driver = &intel_i965_driver;
+ else
+ bridge->driver = &intel_845_driver;
+ name = "965G";
+ break;
+ case PCI_DEVICE_ID_INTEL_82965Q_HB:
+ if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG))
+ bridge->driver = &intel_i965_driver;
+ else
+ bridge->driver = &intel_845_driver;
+ name = "965Q";
+ break;
+ case PCI_DEVICE_ID_INTEL_82965G_HB:
+ if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG))
+ bridge->driver = &intel_i965_driver;
+ else
+ bridge->driver = &intel_845_driver;
+ name = "965G";
+ break;
+
case PCI_DEVICE_ID_INTEL_7505_0:
bridge->driver = &intel_7505_driver;
name = "E7505";
@@ -1766,6 +1903,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev)
agp_put_bridge(bridge);
}
+#ifdef CONFIG_PM
static int agp_intel_resume(struct pci_dev *pdev)
{
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
@@ -1786,9 +1924,12 @@ static int agp_intel_resume(struct pci_dev *pdev)
intel_i830_configure();
else if (bridge->driver == &intel_810_driver)
intel_i810_configure();
+ else if (bridge->driver == &intel_i965_driver)
+ intel_i915_configure();
return 0;
}
+#endif
static struct pci_device_id agp_intel_pci_table[] = {
#define ID(x) \
@@ -1825,6 +1966,10 @@ static struct pci_device_id agp_intel_pci_table[] = {
ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
ID(PCI_DEVICE_ID_INTEL_82945G_HB),
ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
+ ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
+ ID(PCI_DEVICE_ID_INTEL_82965G_1_HB),
+ ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
+ ID(PCI_DEVICE_ID_INTEL_82965G_HB),
{ }
};
@@ -1835,7 +1980,9 @@ static struct pci_driver agp_intel_pci_driver = {
.id_table = agp_intel_pci_table,
.probe = agp_intel_probe,
.remove = __devexit_p(agp_intel_remove),
+#ifdef CONFIG_PM
.resume = agp_intel_resume,
+#endif
};
static int __init agp_intel_init(void)
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 4c67135c12d..df7f37b2739 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -376,6 +376,29 @@ static void __devexit agp_nvidia_remove(struct pci_dev *pdev)
agp_put_bridge(bridge);
}
+#ifdef CONFIG_PM
+static int agp_nvidia_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ pci_save_state (pdev);
+ pci_set_power_state (pdev, 3);
+
+ return 0;
+}
+
+static int agp_nvidia_resume(struct pci_dev *pdev)
+{
+ /* set power state 0 and restore PCI space */
+ pci_set_power_state (pdev, 0);
+ pci_restore_state(pdev);
+
+ /* reconfigure AGP hardware again */
+ nvidia_configure();
+
+ return 0;
+}
+#endif
+
+
static struct pci_device_id agp_nvidia_pci_table[] = {
{
.class = (PCI_CLASS_BRIDGE_HOST << 8),
@@ -403,6 +426,10 @@ static struct pci_driver agp_nvidia_pci_driver = {
.id_table = agp_nvidia_pci_table,
.probe = agp_nvidia_probe,
.remove = agp_nvidia_remove,
+#ifdef CONFIG_PM
+ .suspend = agp_nvidia_suspend,
+ .resume = agp_nvidia_resume,
+#endif
};
static int __init agp_nvidia_init(void)
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index cfa7922cb43..d73be4c2db8 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -329,9 +329,8 @@ static int __devinit agp_sgi_init(void)
static void __devexit agp_sgi_cleanup(void)
{
- if (sgi_tioca_agp_bridges)
- kfree(sgi_tioca_agp_bridges);
- sgi_tioca_agp_bridges=NULL;
+ kfree(sgi_tioca_agp_bridges);
+ sgi_tioca_agp_bridges = NULL;
}
module_init(agp_sgi_init);
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 1de1b12043b..91b71e750ee 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -601,8 +601,8 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev,
uninorth_node = of_find_node_by_name(NULL, "u3");
}
if (uninorth_node) {
- int *revprop = (int *)
- get_property(uninorth_node, "device-rev", NULL);
+ const int *revprop = get_property(uninorth_node,
+ "device-rev", NULL);
if (revprop != NULL)
uninorth_rev = *revprop & 0x3f;
of_node_put(uninorth_node);
diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
index b8ec25d1747..c149ac9ce9a 100644
--- a/drivers/char/agp/via-agp.c
+++ b/drivers/char/agp/via-agp.c
@@ -9,7 +9,7 @@
#include <linux/agp_backend.h>
#include "agp.h"
-static struct pci_device_id agp_via_pci_table[];
+static const struct pci_device_id agp_via_pci_table[];
#define VIA_GARTCTRL 0x80
#define VIA_APSIZE 0x84
@@ -485,7 +485,7 @@ static int agp_via_resume(struct pci_dev *pdev)
#endif /* CONFIG_PM */
/* must be the same order as name table above */
-static struct pci_device_id agp_via_pci_table[] = {
+static const struct pci_device_id agp_via_pci_table[] = {
#define ID(x) \
{ \
.class = (PCI_CLASS_BRIDGE_HOST << 8), \
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 6602b3156df..9d6713a93ed 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -31,7 +31,6 @@
* ever possible.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#undef SERIAL_PARANOIA_CHECK
@@ -2052,7 +2051,7 @@ static int __init rs_init(void)
/* set ISRs, and then disable the rx interrupts */
request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state);
- request_irq(IRQ_AMIGA_RBF, ser_rx_int, SA_INTERRUPT, "serial RX", state);
+ request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED, "serial RX", state);
/* turn off Rx and Tx interrupts */
custom.intena = IF_RBF | IF_TBE;
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index a370e7a0bad..10a389dafd6 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -112,7 +112,7 @@ static int ac_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static irqreturn_t ac_interrupt(int, void *, struct pt_regs *);
-static struct file_operations ac_fops = {
+static const struct file_operations ac_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ac_read,
@@ -166,11 +166,7 @@ static int ac_register_board(unsigned long physloc, void __iomem *loc,
return boardno + 1;
}
-#ifdef MODULE
-
-#define applicom_init init_module
-
-void cleanup_module(void)
+static void __exit applicom_exit(void)
{
unsigned int i;
@@ -188,9 +184,7 @@ void cleanup_module(void)
}
}
-#endif /* MODULE */
-
-int __init applicom_init(void)
+static int __init applicom_init(void)
{
int i, numisa = 0;
struct pci_dev *dev = NULL;
@@ -215,13 +209,16 @@ int __init applicom_init(void)
RamIO = ioremap(dev->resource[0].start, LEN_RAM_IO);
if (!RamIO) {
- printk(KERN_INFO "ac.o: Failed to ioremap PCI memory space at 0x%lx\n", dev->resource[0].start);
+ printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
+ "space at 0x%llx\n",
+ (unsigned long long)dev->resource[0].start);
pci_disable_device(dev);
return -EIO;
}
- printk(KERN_INFO "Applicom %s found at mem 0x%lx, irq %d\n",
- applicom_pci_devnames[dev->device-1], dev->resource[0].start,
+ printk(KERN_INFO "Applicom %s found at mem 0x%llx, irq %d\n",
+ applicom_pci_devnames[dev->device-1],
+ (unsigned long long)dev->resource[0].start,
dev->irq);
boardno = ac_register_board(dev->resource[0].start, RamIO,0);
@@ -232,7 +229,7 @@ int __init applicom_init(void)
continue;
}
- if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &dummy)) {
+ if (request_irq(dev->irq, &ac_interrupt, IRQF_SHARED, "Applicom PCI", &dummy)) {
printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
iounmap(RamIO);
pci_disable_device(dev);
@@ -279,7 +276,7 @@ int __init applicom_init(void)
printk(KERN_NOTICE "Applicom ISA card found at mem 0x%lx, irq %d\n", mem + (LEN_RAM_IO*i), irq);
if (!numisa) {
- if (request_irq(irq, &ac_interrupt, SA_SHIRQ, "Applicom ISA", &dummy)) {
+ if (request_irq(irq, &ac_interrupt, IRQF_SHARED, "Applicom ISA", &dummy)) {
printk(KERN_WARNING "Could not allocate IRQ %d for ISA Applicom device.\n", irq);
iounmap(RamIO);
apbs[boardno - 1].RamIO = NULL;
@@ -355,10 +352,9 @@ out:
return ret;
}
+module_init(applicom_init);
+module_exit(applicom_exit);
-#ifndef MODULE
-__initcall(applicom_init);
-#endif
static ssize_t ac_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
@@ -851,28 +847,3 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
return 0;
}
-#ifndef MODULE
-static int __init applicom_setup(char *str)
-{
- int ints[4];
-
- (void) get_options(str, 4, ints);
-
- if (ints[0] > 2) {
- printk(KERN_WARNING "Too many arguments to 'applicom=', expected mem,irq only.\n");
- }
-
- if (ints[0] < 2) {
- printk(KERN_INFO"applicom numargs: %d\n", ints[0]);
- return 0;
- }
-
- mem = ints[1];
- irq = ints[2];
- return 1;
-}
-
-__setup("applicom=", applicom_setup);
-
-#endif /* MODULE */
-
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
new file mode 100644
index 00000000000..b8c22255f6a
--- /dev/null
+++ b/drivers/char/briq_panel.c
@@ -0,0 +1,271 @@
+/*
+ * Drivers for the Total Impact PPC based computer "BRIQ"
+ * by Dr. Karsten Jeppesen
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/tty.h>
+#include <linux/timer.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/wait.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+#define BRIQ_PANEL_MINOR 156
+#define BRIQ_PANEL_VFD_IOPORT 0x0390
+#define BRIQ_PANEL_LED_IOPORT 0x0398
+#define BRIQ_PANEL_VER "1.1 (04/20/2002)"
+#define BRIQ_PANEL_MSG0 "Loading Linux"
+
+static int vfd_is_open;
+static unsigned char vfd[40];
+static int vfd_cursor;
+static unsigned char ledpb, led;
+
+static void update_vfd(void)
+{
+ int i;
+
+ /* cursor home */
+ outb(0x02, BRIQ_PANEL_VFD_IOPORT);
+ for (i=0; i<20; i++)
+ outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
+
+ /* cursor to next line */
+ outb(0xc0, BRIQ_PANEL_VFD_IOPORT);
+ for (i=20; i<40; i++)
+ outb(vfd[i], BRIQ_PANEL_VFD_IOPORT + 1);
+
+}
+
+static void set_led(char state)
+{
+ if (state == 'R')
+ led = 0x01;
+ else if (state == 'G')
+ led = 0x02;
+ else if (state == 'Y')
+ led = 0x03;
+ else if (state == 'X')
+ led = 0x00;
+ outb(led, BRIQ_PANEL_LED_IOPORT);
+}
+
+static int briq_panel_open(struct inode *ino, struct file *filep)
+{
+ /* enforce single access */
+ if (vfd_is_open)
+ return -EBUSY;
+ vfd_is_open = 1;
+
+ return 0;
+}
+
+static int briq_panel_release(struct inode *ino, struct file *filep)
+{
+ if (!vfd_is_open)
+ return -ENODEV;
+
+ vfd_is_open = 0;
+
+ return 0;
+}
+
+static ssize_t briq_panel_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned short c;
+ unsigned char cp;
+
+#if 0 /* Can't seek (pread) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+#endif
+
+ if (!vfd_is_open)
+ return -ENODEV;
+
+ c = (inb(BRIQ_PANEL_LED_IOPORT) & 0x000c) | (ledpb & 0x0003);
+ set_led(' ');
+ /* upper button released */
+ if ((!(ledpb & 0x0004)) && (c & 0x0004)) {
+ cp = ' ';
+ ledpb = c;
+ if (copy_to_user(buf, &cp, 1))
+ return -EFAULT;
+ return 1;
+ }
+ /* lower button released */
+ else if ((!(ledpb & 0x0008)) && (c & 0x0008)) {
+ cp = '\r';
+ ledpb = c;
+ if (copy_to_user(buf, &cp, 1))
+ return -EFAULT;
+ return 1;
+ } else {
+ ledpb = c;
+ return 0;
+ }
+}
+
+static void scroll_vfd( void )
+{
+ int i;
+
+ for (i=0; i<20; i++) {
+ vfd[i] = vfd[i+20];
+ vfd[i+20] = ' ';
+ }
+ vfd_cursor = 20;
+}
+
+static ssize_t briq_panel_write(struct file *file, const char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ size_t indx = len;
+ int i, esc = 0;
+
+#if 0 /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+#endif
+
+ if (!vfd_is_open)
+ return -EBUSY;
+
+ for (;;) {
+ char c;
+ if (!indx)
+ break;
+ if (get_user(c, buf))
+ return -EFAULT;
+ if (esc) {
+ set_led(c);
+ esc = 0;
+ } else if (c == 27) {
+ esc = 1;
+ } else if (c == 12) {
+ /* do a form feed */
+ for (i=0; i<40; i++)
+ vfd[i] = ' ';
+ vfd_cursor = 0;
+ } else if (c == 10) {
+ if (vfd_cursor < 20)
+ vfd_cursor = 20;
+ else if (vfd_cursor < 40)
+ vfd_cursor = 40;
+ else if (vfd_cursor < 60)
+ vfd_cursor = 60;
+ if (vfd_cursor > 59)
+ scroll_vfd();
+ } else {
+ /* just a character */
+ if (vfd_cursor > 39)
+ scroll_vfd();
+ vfd[vfd_cursor++] = c;
+ }
+ indx--;
+ buf++;
+ }
+ update_vfd();
+
+ return len;
+}
+
+static struct file_operations briq_panel_fops = {
+ .owner = THIS_MODULE,
+ .read = briq_panel_read,
+ .write = briq_panel_write,
+ .open = briq_panel_open,
+ .release = briq_panel_release,
+};
+
+static struct miscdevice briq_panel_miscdev = {
+ BRIQ_PANEL_MINOR,
+ "briq_panel",
+ &briq_panel_fops
+};
+
+static int __init briq_panel_init(void)
+{
+ struct device_node *root = find_path_device("/");
+ const char *machine;
+ int i;
+
+ machine = get_property(root, "model", NULL);
+ if (!machine || strncmp(machine, "TotalImpact,BRIQ-1", 18) != 0)
+ return -ENODEV;
+
+ printk(KERN_INFO
+ "briq_panel: v%s Dr. Karsten Jeppesen (kj@totalimpact.com)\n",
+ BRIQ_PANEL_VER);
+
+ if (!request_region(BRIQ_PANEL_VFD_IOPORT, 4, "BRIQ Front Panel"))
+ return -EBUSY;
+
+ if (!request_region(BRIQ_PANEL_LED_IOPORT, 2, "BRIQ Front Panel")) {
+ release_region(BRIQ_PANEL_VFD_IOPORT, 4);
+ return -EBUSY;
+ }
+ ledpb = inb(BRIQ_PANEL_LED_IOPORT) & 0x000c;
+
+ if (misc_register(&briq_panel_miscdev) < 0) {
+ release_region(BRIQ_PANEL_VFD_IOPORT, 4);
+ release_region(BRIQ_PANEL_LED_IOPORT, 2);
+ return -EBUSY;
+ }
+
+ outb(0x38, BRIQ_PANEL_VFD_IOPORT); /* Function set */
+ outb(0x01, BRIQ_PANEL_VFD_IOPORT); /* Clear display */
+ outb(0x0c, BRIQ_PANEL_VFD_IOPORT); /* Display on */
+ outb(0x06, BRIQ_PANEL_VFD_IOPORT); /* Entry normal */
+ for (i=0; i<40; i++)
+ vfd[i]=' ';
+#ifndef MODULE
+ vfd[0] = 'L';
+ vfd[1] = 'o';
+ vfd[2] = 'a';
+ vfd[3] = 'd';
+ vfd[4] = 'i';
+ vfd[5] = 'n';
+ vfd[6] = 'g';
+ vfd[7] = ' ';
+ vfd[8] = '.';
+ vfd[9] = '.';
+ vfd[10] = '.';
+#endif /* !MODULE */
+
+ update_vfd();
+
+ return 0;
+}
+
+static void __exit briq_panel_exit(void)
+{
+ misc_deregister(&briq_panel_miscdev);
+ release_region(BRIQ_PANEL_VFD_IOPORT, 4);
+ release_region(BRIQ_PANEL_LED_IOPORT, 2);
+}
+
+module_init(briq_panel_init);
+module_exit(briq_panel_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Karsten Jeppesen <karsten@jeppesens.com>");
+MODULE_DESCRIPTION("Driver for the Total Impact briQ front panel");
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index c85a4fa60da..04a12027a74 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -11,7 +11,6 @@
* Fix bug in inverse translation. Stanislav Voronyi <stas@cnti.uanet.kharkov.ua>, Dec 1998
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kd.h>
#include <linux/errno.h>
diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c
index 46d66037b91..8ce3f34cfc2 100644
--- a/drivers/char/cs5535_gpio.c
+++ b/drivers/char/cs5535_gpio.c
@@ -158,7 +158,7 @@ static int cs5535_gpio_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
-static struct file_operations cs5535_gpio_fops = {
+static const struct file_operations cs5535_gpio_fops = {
.owner = THIS_MODULE,
.write = cs5535_gpio_write,
.read = cs5535_gpio_read,
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index cc7acf877dc..c1c67281750 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -633,7 +633,6 @@ static char rcsid[] =
/*
* Include section
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -2833,9 +2832,8 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
return 0;
}
- if (!tty || !info->xmit_buf || !tmp_buf){
- return 0;
- }
+ if (!info->xmit_buf || !tmp_buf)
+ return 0;
CY_LOCK(info, flags);
while (1) {
@@ -2884,7 +2882,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
CY_LOCK(info, flags);
@@ -4614,7 +4612,7 @@ cy_detect_isa(void)
/* allocate IRQ */
if(request_irq(cy_isa_irq, cyy_interrupt,
- SA_INTERRUPT, "Cyclom-Y", &cy_card[j]))
+ IRQF_DISABLED, "Cyclom-Y", &cy_card[j]))
{
printk("Cyclom-Y/ISA found at 0x%lx ",
(unsigned long) cy_isa_address);
@@ -4787,7 +4785,7 @@ cy_detect_pci(void)
/* allocate IRQ */
if(request_irq(cy_pci_irq, cyy_interrupt,
- SA_SHIRQ, "Cyclom-Y", &cy_card[j]))
+ IRQF_SHARED, "Cyclom-Y", &cy_card[j]))
{
printk("Cyclom-Y/PCI found at 0x%lx ",
(ulong) cy_pci_phys2);
@@ -4967,7 +4965,7 @@ cy_detect_pci(void)
/* allocate IRQ only if board has an IRQ */
if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
if(request_irq(cy_pci_irq, cyz_interrupt,
- SA_SHIRQ, "Cyclades-Z", &cy_card[j]))
+ IRQF_SHARED, "Cyclades-Z", &cy_card[j]))
{
printk("Cyclom-8Zo/PCI found at 0x%lx ",
(ulong) cy_pci_phys2);
@@ -5061,7 +5059,7 @@ cy_detect_pci(void)
/* allocate IRQ only if board has an IRQ */
if( (cy_pci_irq != 0) && (cy_pci_irq != 255) ) {
if(request_irq(cy_pci_irq, cyz_interrupt,
- SA_SHIRQ, "Cyclades-Z", &cy_card[j]))
+ IRQF_SHARED, "Cyclades-Z", &cy_card[j]))
{
printk("Cyclom-Ze/PCI found at 0x%lx ",
(ulong) cy_pci_phys2);
@@ -5251,7 +5249,6 @@ cy_init(void)
cy_serial_driver->owner = THIS_MODULE;
cy_serial_driver->driver_name = "cyclades";
cy_serial_driver->name = "ttyC";
- cy_serial_driver->devfs_name = "tts/C";
cy_serial_driver->major = CYCLADES_MAJOR;
cy_serial_driver->minor_start = 0;
cy_serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
diff --git a/drivers/char/decserial.c b/drivers/char/decserial.c
index aa1440934e9..85f404e25c7 100644
--- a/drivers/char/decserial.c
+++ b/drivers/char/decserial.c
@@ -16,7 +16,6 @@
* console device I strongly recommend to use only one.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <asm/dec/machtype.h>
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 9da0ddb892b..5642ac43e0f 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -38,7 +38,6 @@
#if defined(__linux__)
#if defined(__KERNEL__)
-#include <linux/config.h>
#endif
#include <asm/ioctl.h> /* For _IO* macros */
#define DRM_IOCTL_NR(n) _IOC_NR(n)
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index cb76e5ca9a2..d2a56182bc3 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -44,7 +44,6 @@
* can build the DRM (part of PI DRI). 4/21/2000 S + B */
#include <asm/current.h>
#endif /* __alpha__ */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 611a1173091..ebdb7182c4f 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -130,7 +130,7 @@ static int drm_irq_install(drm_device_t * dev)
/* Install handler */
if (drm_core_check_feature(dev, DRIVER_IRQ_SHARED))
- sh_flags = SA_SHIRQ;
+ sh_flags = IRQF_SHARED;
ret = request_irq(dev->irq, dev->driver->irq_handler,
sh_flags, dev->devname, dev);
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 7e3318e1d1c..5681cae1d40 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -33,7 +33,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include <linux/highmem.h>
#include "drmP.h"
diff --git a/drivers/char/drm/drm_memory.h b/drivers/char/drm/drm_memory.h
index 714d9aedcff..f1b97aff10c 100644
--- a/drivers/char/drm/drm_memory.h
+++ b/drivers/char/drm/drm_memory.h
@@ -33,7 +33,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
#include "drmP.h"
diff --git a/drivers/char/drm/drm_memory_debug.h b/drivers/char/drm/drm_memory_debug.h
index 6543b9a14c4..74581af806e 100644
--- a/drivers/char/drm/drm_memory_debug.h
+++ b/drivers/char/drm/drm_memory_debug.h
@@ -31,7 +31,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include "drmP.h"
typedef struct drm_mem_stats {
@@ -43,7 +42,7 @@ typedef struct drm_mem_stats {
unsigned long bytes_freed;
} drm_mem_stats_t;
-static spinlock_t drm_mem_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(drm_mem_lock);
static unsigned long drm_ram_available = 0; /* In pages */
static unsigned long drm_ram_used = 0;
static drm_mem_stats_t drm_mem_stats[] =
diff --git a/drivers/char/drm/drm_scatter.c b/drivers/char/drm/drm_scatter.c
index ce81bf24820..06ef7ddbe67 100644
--- a/drivers/char/drm/drm_scatter.c
+++ b/drivers/char/drm/drm_scatter.c
@@ -31,7 +31,6 @@
* DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include <linux/vmalloc.h>
#include "drmP.h"
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 0b9f98a7eb1..51ad98c685c 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/kdev_t.h>
#include <linux/err.h>
diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c
index c13f9abb41e..dd45111a485 100644
--- a/drivers/char/drm/ffb_drv.c
+++ b/drivers/char/drm/ffb_drv.c
@@ -4,7 +4,6 @@
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include "ffb.h"
#include "drmP.h"
diff --git a/drivers/char/drm/i810_drv.c b/drivers/char/drm/i810_drv.c
index dfe6ad2b6a6..fabb9a81796 100644
--- a/drivers/char/drm/i810_drv.c
+++ b/drivers/char/drm/i810_drv.c
@@ -30,7 +30,6 @@
* Gareth Hughes <gareth@valinux.com>
*/
-#include <linux/config.h>
#include "drmP.h"
#include "drm.h"
#include "i810_drm.h"
diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c
index 722658188f5..389597e4a62 100644
--- a/drivers/char/drm/i830_drv.c
+++ b/drivers/char/drm/i830_drv.c
@@ -32,7 +32,6 @@
* Keith Whitwell <keith@tungstengraphics.com>
*/
-#include <linux/config.h>
#include "drmP.h"
#include "drm.h"
#include "i830_drm.h"
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 9f4b8ce4c05..a94233bdbc0 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -758,7 +758,9 @@ drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }
+ [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
+ [DRM_IOCTL_NR(DRM_I915_SET_VBLANK_PIPE)] = { i915_vblank_pipe_set, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY },
+ [DRM_IOCTL_NR(DRM_I915_GET_VBLANK_PIPE)] = { i915_vblank_pipe_get, DRM_AUTH },
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 4cb3da57833..5aa3e0e3bb4 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -124,6 +124,8 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
#define DRM_I915_DESTROY_HEAP 0x0c
+#define DRM_I915_SET_VBLANK_PIPE 0x0d
+#define DRM_I915_GET_VBLANK_PIPE 0x0e
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -138,6 +140,8 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
+#define DRM_IOCTL_I915_SET_VBLANK_PIPE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_SET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
+#define DRM_IOCTL_I915_GET_VBLANK_PIPE DRM_IOR( DRM_COMMAND_BASE + DRM_I915_GET_VBLANK_PIPE, drm_i915_vblank_pipe_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -224,4 +228,13 @@ typedef struct drm_i915_mem_destroy_heap {
int region;
} drm_i915_mem_destroy_heap_t;
+/* Allow X server to configure which pipes to monitor for vblank signals
+ */
+#define DRM_I915_VBLANK_PIPE_A 1
+#define DRM_I915_VBLANK_PIPE_B 2
+
+typedef struct drm_i915_vblank_pipe {
+ int pipe;
+} drm_i915_vblank_pipe_t;
+
#endif /* _I915_DRM_H_ */
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 7a65666899e..2d565031c00 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -45,9 +45,10 @@
* 1.2: Add Power Management
* 1.3: Add vblank support
* 1.4: Fix cmdbuffer path, add heap destroy
+ * 1.5: Add vblank pipe configuration
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 4
+#define DRIVER_MINOR 5
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
@@ -96,6 +97,7 @@ typedef struct drm_i915_private {
int allow_batchbuffer;
struct mem_block *agp_heap;
unsigned int sr01, adpa, ppcr, dvob, dvoc, lvds;
+ int vblank_pipe;
} drm_i915_private_t;
extern drm_ioctl_desc_t i915_ioctls[];
@@ -119,6 +121,8 @@ extern irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS);
extern void i915_driver_irq_preinstall(drm_device_t * dev);
extern void i915_driver_irq_postinstall(drm_device_t * dev);
extern void i915_driver_irq_uninstall(drm_device_t * dev);
+extern int i915_vblank_pipe_set(DRM_IOCTL_ARGS);
+extern int i915_vblank_pipe_get(DRM_IOCTL_ARGS);
/* i915_mem.c */
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index a752afd86ab..cd96cfa430d 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -44,7 +44,8 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
u16 temp;
temp = I915_READ16(I915REG_INT_IDENTITY_R);
- temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG);
+
+ temp &= (USER_INT_FLAG | VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG);
DRM_DEBUG("%s flag=%08x\n", __FUNCTION__, temp);
@@ -58,7 +59,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
if (temp & USER_INT_FLAG)
DRM_WAKEUP(&dev_priv->irq_queue);
- if (temp & VSYNC_PIPEA_FLAG) {
+ if (temp & (VSYNC_PIPEA_FLAG | VSYNC_PIPEB_FLAG)) {
atomic_inc(&dev->vbl_received);
DRM_WAKEUP(&dev->vbl_queue);
drm_vbl_send_signals(dev);
@@ -182,6 +183,68 @@ int i915_irq_wait(DRM_IOCTL_ARGS)
return i915_wait_irq(dev, irqwait.irq_seq);
}
+static int i915_enable_interrupt (drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+ u16 flag;
+
+ flag = 0;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_A)
+ flag |= VSYNC_PIPEA_FLAG;
+ if (dev_priv->vblank_pipe & DRM_I915_VBLANK_PIPE_B)
+ flag |= VSYNC_PIPEB_FLAG;
+ if (dev_priv->vblank_pipe & ~(DRM_I915_VBLANK_PIPE_A|DRM_I915_VBLANK_PIPE_B)) {
+ DRM_ERROR("%s called with invalid pipe 0x%x\n",
+ __FUNCTION__, dev_priv->vblank_pipe);
+ return DRM_ERR(EINVAL);
+ }
+ I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | flag);
+ return 0;
+}
+
+/* Set the vblank monitor pipe
+ */
+int i915_vblank_pipe_set(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t pipe;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ DRM_COPY_FROM_USER_IOCTL(pipe, (drm_i915_vblank_pipe_t __user *) data,
+ sizeof(pipe));
+
+ dev_priv->vblank_pipe = pipe.pipe;
+ return i915_enable_interrupt (dev);
+}
+
+int i915_vblank_pipe_get(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_vblank_pipe_t pipe;
+ u16 flag;
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ flag = I915_READ(I915REG_INT_ENABLE_R);
+ pipe.pipe = 0;
+ if (flag & VSYNC_PIPEA_FLAG)
+ pipe.pipe |= DRM_I915_VBLANK_PIPE_A;
+ if (flag & VSYNC_PIPEB_FLAG)
+ pipe.pipe |= DRM_I915_VBLANK_PIPE_B;
+ DRM_COPY_TO_USER_IOCTL((drm_i915_vblank_pipe_t __user *) data, pipe,
+ sizeof(pipe));
+ return 0;
+}
+
/* drm_dma.h hooks
*/
void i915_driver_irq_preinstall(drm_device_t * dev)
@@ -197,7 +260,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- I915_WRITE16(I915REG_INT_ENABLE_R, USER_INT_FLAG | VSYNC_PIPEA_FLAG);
+ i915_enable_interrupt(dev);
DRM_INIT_WAITQUEUE(&dev_priv->irq_queue);
}
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 9f7ed0e0351..e30f556b79f 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -29,7 +29,6 @@
* Gareth Hughes <gareth@valinux.com>
*/
-#include <linux/config.h>
#include "drmP.h"
#include "drm.h"
#include "mga_drm.h"
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index e20450ae220..6108e7587e1 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -29,7 +29,6 @@
* Gareth Hughes <gareth@valinux.com>
*/
-#include <linux/config.h>
#include "drmP.h"
#include "drm.h"
#include "r128_drm.h"
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 7f949c9c969..5ad43ba7b5a 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -39,7 +39,7 @@
static int radeon_do_cleanup_cp(drm_device_t * dev);
/* CP microcode (from ATI) */
-static u32 R200_cp_microcode[][2] = {
+static const u32 R200_cp_microcode[][2] = {
{0x21007000, 0000000000},
{0x20007000, 0000000000},
{0x000000ab, 0x00000004},
@@ -298,7 +298,7 @@ static u32 R200_cp_microcode[][2] = {
{0000000000, 0000000000},
};
-static u32 radeon_cp_microcode[][2] = {
+static const u32 radeon_cp_microcode[][2] = {
{0x21007000, 0000000000},
{0x20007000, 0000000000},
{0x000000b4, 0x00000004},
@@ -557,7 +557,7 @@ static u32 radeon_cp_microcode[][2] = {
{0000000000, 0000000000},
};
-static u32 R300_cp_microcode[][2] = {
+static const u32 R300_cp_microcode[][2] = {
{0x4200e000, 0000000000},
{0x4000e000, 0000000000},
{0x000000af, 0x00000008},
diff --git a/drivers/char/drm/radeon_drm.h b/drivers/char/drm/radeon_drm.h
index c8e279e89c2..8d6350dd536 100644
--- a/drivers/char/drm/radeon_drm.h
+++ b/drivers/char/drm/radeon_drm.h
@@ -161,7 +161,8 @@
#define R200_EMIT_PP_TXCTLALL_3 91
#define R200_EMIT_PP_TXCTLALL_4 92
#define R200_EMIT_PP_TXCTLALL_5 93
-#define RADEON_MAX_STATE_PACKETS 94
+#define R200_EMIT_VAP_PVS_CNTL 94
+#define RADEON_MAX_STATE_PACKETS 95
/* Commands understood by cmd_buffer ioctl. More can be added but
* obviously these can't be removed or changed:
@@ -176,6 +177,7 @@
#define RADEON_CMD_WAIT 8 /* emit hw wait commands -- note:
* doesn't make the cpu wait, just
* the graphics hardware */
+#define RADEON_CMD_VECLINEAR 9 /* another r200 stopgap */
typedef union {
int i;
@@ -192,6 +194,9 @@ typedef union {
unsigned char cmd_type, offset, stride, count;
} vectors;
struct {
+ unsigned char cmd_type, addr_lo, addr_hi, count;
+ } veclinear;
+ struct {
unsigned char cmd_type, buf_idx, pad0, pad1;
} dma;
struct {
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index b04ed1b562b..eb985c2a31e 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -29,7 +29,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include "drmP.h"
#include "drm.h"
#include "radeon_drm.h"
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 78345cee8f8..e5a256f5429 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -38,7 +38,7 @@
#define DRIVER_NAME "radeon"
#define DRIVER_DESC "ATI Radeon"
-#define DRIVER_DATE "20060225"
+#define DRIVER_DATE "20060524"
/* Interface history:
*
@@ -93,9 +93,11 @@
* 1.22- Add support for texture cache flushes (R300_TX_CNTL)
* 1.23- Add new radeon memory map work from benh
* 1.24- Add general-purpose packet for manipulating scratch registers (r300)
+ * 1.25- Add support for r200 vertex programs (R200_EMIT_VAP_PVS_CNTL,
+ * new packet type)
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 24
+#define DRIVER_MINOR 25
#define DRIVER_PATCHLEVEL 0
/*
@@ -884,6 +886,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00
#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14
+#define RADEON_SE_TCL_STATE_FLUSH 0x2284
+
#define SE_VAP_CNTL__TCL_ENA_MASK 0x00000001
#define SE_VAP_CNTL__FORCE_W_TO_ONE_MASK 0x00010000
#define SE_VAP_CNTL__VF_MAX_VTX_NUM__SHIFT 0x00000012
@@ -905,6 +909,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define R200_PP_AFS_0 0x2f80
#define R200_PP_AFS_1 0x2f00 /* same as txcblend_0 */
+#define R200_VAP_PVS_CNTL_1 0x22D0
+
/* Constants */
#define RADEON_MAX_USEC_TIMEOUT 100000 /* 100 ms */
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index c5b8f774a59..39a7f685e3f 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -175,6 +175,14 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
}
break;
+ case R200_EMIT_VAP_CTL:{
+ RING_LOCALS;
+ BEGIN_RING(2);
+ OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
+ ADVANCE_RING();
+ }
+ break;
+
case RADEON_EMIT_RB3D_COLORPITCH:
case RADEON_EMIT_RE_LINE_PATTERN:
case RADEON_EMIT_SE_LINE_WIDTH:
@@ -202,7 +210,6 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_TCL_LIGHT_MODEL_CTL_0:
case R200_EMIT_TFACTOR_0:
case R200_EMIT_VTX_FMT_0:
- case R200_EMIT_VAP_CTL:
case R200_EMIT_MATRIX_SELECT_0:
case R200_EMIT_TEX_PROC_CTL_2:
case R200_EMIT_TCL_UCP_VERT_BLEND_CTL:
@@ -249,6 +256,7 @@ static __inline__ int radeon_check_and_fixup_packets(drm_radeon_private_t *
case R200_EMIT_PP_TXCTLALL_3:
case R200_EMIT_PP_TXCTLALL_4:
case R200_EMIT_PP_TXCTLALL_5:
+ case R200_EMIT_VAP_PVS_CNTL:
/* These packets don't contain memory offsets */
break;
@@ -626,6 +634,7 @@ static struct {
{R200_PP_TXFILTER_3, 8, "R200_PP_TXCTLALL_3"},
{R200_PP_TXFILTER_4, 8, "R200_PP_TXCTLALL_4"},
{R200_PP_TXFILTER_5, 8, "R200_PP_TXCTLALL_5"},
+ {R200_VAP_PVS_CNTL_1, 2, "R200_VAP_PVS_CNTL"},
};
/* ================================================================
@@ -2595,7 +2604,8 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
int stride = header.vectors.stride;
RING_LOCALS;
- BEGIN_RING(3 + sz);
+ BEGIN_RING(5 + sz);
+ OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
OUT_RING(start | (stride << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
@@ -2607,6 +2617,32 @@ static __inline__ int radeon_emit_vectors(drm_radeon_private_t *dev_priv,
return 0;
}
+static __inline__ int radeon_emit_veclinear(drm_radeon_private_t *dev_priv,
+ drm_radeon_cmd_header_t header,
+ drm_radeon_kcmd_buffer_t *cmdbuf)
+{
+ int sz = header.veclinear.count * 4;
+ int start = header.veclinear.addr_lo | (header.veclinear.addr_hi << 8);
+ RING_LOCALS;
+
+ if (!sz)
+ return 0;
+ if (sz * 4 > cmdbuf->bufsz)
+ return DRM_ERR(EINVAL);
+
+ BEGIN_RING(5 + sz);
+ OUT_RING_REG(RADEON_SE_TCL_STATE_FLUSH, 0);
+ OUT_RING(CP_PACKET0(RADEON_SE_TCL_VECTOR_INDX_REG, 0));
+ OUT_RING(start | (1 << RADEON_VEC_INDX_OCTWORD_STRIDE_SHIFT));
+ OUT_RING(CP_PACKET0_TABLE(RADEON_SE_TCL_VECTOR_DATA_REG, (sz - 1)));
+ OUT_RING_TABLE(cmdbuf->buf, sz);
+ ADVANCE_RING();
+
+ cmdbuf->buf += sz * sizeof(int);
+ cmdbuf->bufsz -= sz * sizeof(int);
+ return 0;
+}
+
static int radeon_emit_packet3(drm_device_t * dev,
drm_file_t * filp_priv,
drm_radeon_kcmd_buffer_t *cmdbuf)
@@ -2865,6 +2901,14 @@ static int radeon_cp_cmdbuf(DRM_IOCTL_ARGS)
goto err;
}
break;
+ case RADEON_CMD_VECLINEAR:
+ DRM_DEBUG("RADEON_CMD_VECLINEAR\n");
+ if (radeon_emit_veclinear(dev_priv, header, &cmdbuf)) {
+ DRM_ERROR("radeon_emit_veclinear failed\n");
+ goto err;
+ }
+ break;
+
default:
DRM_ERROR("bad cmd_type %d at %p\n",
header.header.cmd_type,
diff --git a/drivers/char/drm/savage_drv.c b/drivers/char/drm/savage_drv.c
index aa6c0d1a82f..eee52aa92a7 100644
--- a/drivers/char/drm/savage_drv.c
+++ b/drivers/char/drm/savage_drv.c
@@ -23,7 +23,6 @@
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include "drmP.h"
#include "savage_drm.h"
#include "savage_drv.h"
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 6f6d7d613ed..5e9dc86f295 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -25,7 +25,6 @@
*
*/
-#include <linux/config.h>
#include "drmP.h"
#include "sis_drm.h"
#include "sis_drv.h"
diff --git a/drivers/char/drm/tdfx_drv.c b/drivers/char/drm/tdfx_drv.c
index baa4416032a..012ff2e356b 100644
--- a/drivers/char/drm/tdfx_drv.c
+++ b/drivers/char/drm/tdfx_drv.c
@@ -30,7 +30,6 @@
* Gareth Hughes <gareth@valinux.com>
*/
-#include <linux/config.h>
#include "drmP.h"
#include "tdfx_drv.h"
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index b7f17457b42..78a81a4a99c 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -557,7 +557,7 @@ via_init_dmablit(drm_device_t *dev)
blitq->num_outstanding = 0;
blitq->is_active = 0;
blitq->aborting = 0;
- blitq->blit_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&blitq->blit_lock);
for (j=0; j<VIA_NUM_BLIT_SLOTS; ++j) {
DRM_INIT_WAITQUEUE(blitq->blit_queue + j);
}
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index 3f012255d31..b3d364d793d 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -22,7 +22,6 @@
* DEALINGS IN THE SOFTWARE.
*/
-#include <linux/config.h>
#include "drmP.h"
#include "via_drm.h"
#include "via_drv.h"
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index d755cac14bc..21c8229f544 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -281,7 +281,7 @@ static unsigned int ds1286_poll(struct file *file, poll_table *wait)
* The various file operations we support.
*/
-static struct file_operations ds1286_fops = {
+static const struct file_operations ds1286_fops = {
.llseek = no_llseek,
.read = ds1286_read,
.poll = ds1286_poll,
diff --git a/drivers/char/ds1302.c b/drivers/char/ds1302.c
index a75e8609be0..bcdb107aa96 100644
--- a/drivers/char/ds1302.c
+++ b/drivers/char/ds1302.c
@@ -12,7 +12,6 @@
*!
*!***************************************************************************/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -283,7 +282,7 @@ get_rtc_status(char *buf)
/* The various file operations we support. */
-static struct file_operations rtc_fops = {
+static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.ioctl = rtc_ioctl,
};
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 62cda25724e..48cb8f0e8eb 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -2,7 +2,6 @@
* linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620
* thermometer driver (as used in the Rebel.com NetWinder)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/miscdevice.h>
@@ -337,7 +336,7 @@ proc_therm_ds1620_read(char *buf, char **start, off_t offset,
static struct proc_dir_entry *proc_therm_ds1620;
#endif
-static struct file_operations ds1620_fops = {
+static const struct file_operations ds1620_fops = {
.owner = THIS_MODULE,
.open = nonseekable_open,
.read = ds1620_read,
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index e233cf280bc..9b1bf60ffbe 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -33,7 +33,6 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
@@ -484,7 +483,7 @@ static int dsp56k_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations dsp56k_fops = {
+static const struct file_operations dsp56k_fops = {
.owner = THIS_MODULE,
.read = dsp56k_read,
.write = dsp56k_write,
@@ -518,17 +517,9 @@ static int __init dsp56k_init_driver(void)
}
class_device_create(dsp56k_class, NULL, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k");
- err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0),
- S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k");
- if(err)
- goto out_class;
-
printk(banner);
goto out;
-out_class:
- class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
- class_destroy(dsp56k_class);
out_chrdev:
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
out:
@@ -541,7 +532,6 @@ static void __exit dsp56k_cleanup_driver(void)
class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0));
class_destroy(dsp56k_class);
unregister_chrdev(DSP56K_MAJOR, "dsp56k");
- devfs_remove("dsp56k");
}
module_exit(dsp56k_cleanup_driver);
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 87dcaa237f0..5e82c3bad2e 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -62,7 +62,6 @@
#include <linux/init.h> /* for __init, module_{init,exit} */
#include <linux/poll.h> /* for POLLIN, etc. */
#include <linux/dtlk.h> /* local header file for DoubleTalk values */
-#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#ifdef TRACING
@@ -95,7 +94,7 @@ static int dtlk_release(struct inode *, struct file *);
static int dtlk_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg);
-static struct file_operations dtlk_fops =
+static const struct file_operations dtlk_fops =
{
.owner = THIS_MODULE,
.read = dtlk_read,
@@ -337,9 +336,6 @@ static int __init dtlk_init(void)
if (dtlk_dev_probe() == 0)
printk(", MAJOR %d\n", dtlk_major);
- devfs_mk_cdev(MKDEV(dtlk_major, DTLK_MINOR),
- S_IFCHR | S_IRUSR | S_IWUSR, "dtlk");
-
init_timer(&dtlk_timer);
dtlk_timer.function = dtlk_timer_tick;
init_waitqueue_head(&dtlk_process_list);
@@ -357,7 +353,6 @@ static void __exit dtlk_cleanup (void)
dtlk_write_tts(DTLK_CLEAR);
unregister_chrdev(dtlk_major, "dtlk");
- devfs_remove("dtlk");
release_region(dtlk_port_lpc, DTLK_IO_EXTENT);
}
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
index 4aed6696882..abac18b1871 100644
--- a/drivers/char/ec3104_keyb.c
+++ b/drivers/char/ec3104_keyb.c
@@ -26,7 +26,6 @@
* (prumpf@tux.org).
*/
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c
index 0090e7a4fcd..004141d535a 100644
--- a/drivers/char/efirtc.c
+++ b/drivers/char/efirtc.c
@@ -285,7 +285,7 @@ efi_rtc_close(struct inode *inode, struct file *file)
* The various file operations we support.
*/
-static struct file_operations efi_rtc_fops = {
+static const struct file_operations efi_rtc_fops = {
.owner = THIS_MODULE,
.ioctl = efi_rtc_ioctl,
.open = efi_rtc_open,
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 9cad8501d62..86d290e9f30 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -30,7 +30,6 @@
/* See README.epca for change history --DAT*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -80,7 +79,7 @@ static int invalid_lilo_config;
/* The ISA boards do window flipping into the same spaces so its only sane
with a single lock. It's still pretty efficient */
-static spinlock_t epca_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(epca_lock);
/* -----------------------------------------------------------------------
MAXBOARDS is typically 12, but ISA and EISA cards are restricted to
@@ -1232,7 +1231,6 @@ static int __init pc_init(void)
pc_driver->owner = THIS_MODULE;
pc_driver->name = "ttyD";
- pc_driver->devfs_name = "tts/D";
pc_driver->major = DIGI_MAJOR;
pc_driver->minor_start = 0;
pc_driver->type = TTY_DRIVER_TYPE_SERIAL;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 09dc4b01232..afcd83d9984 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -883,7 +883,7 @@ static int startup(struct esp_struct * info)
* Allocate the IRQ
*/
- retval = request_irq(info->irq, rs_interrupt_single, SA_SHIRQ,
+ retval = request_irq(info->irq, rs_interrupt_single, IRQF_SHARED,
"esp serial", info);
if (retval) {
@@ -1212,7 +1212,7 @@ static void rs_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
spin_lock_irqsave(&info->lock, flags);
@@ -1256,7 +1256,7 @@ static int rs_write(struct tty_struct * tty,
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return 0;
while (1) {
@@ -2449,7 +2449,6 @@ static int __init espserial_init(void)
esp_driver->owner = THIS_MODULE;
esp_driver->name = "ttyP";
- esp_driver->devfs_name = "tts/P";
esp_driver->major = ESP_IN_MAJOR;
esp_driver->minor_start = 0;
esp_driver->type = TTY_DRIVER_TYPE_SERIAL;
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index 093fdf98b19..65c9d2ec60b 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -1268,7 +1268,7 @@ static int fdc_grab_irq_and_dma(void)
/* Get fast interrupt handler.
*/
if (request_irq(fdc.irq, ftape_interrupt,
- SA_INTERRUPT, "ft", ftape_id)) {
+ IRQF_DISABLED, "ft", ftape_id)) {
TRACE_ABORT(-EIO, ft_t_bug,
"Unable to grab IRQ%d for ftape driver",
fdc.irq);
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c
index 956b2586e13..8e50bfd35a5 100644
--- a/drivers/char/ftape/lowlevel/ftape-calibr.c
+++ b/drivers/char/ftape/lowlevel/ftape-calibr.c
@@ -24,7 +24,6 @@
* functions.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/jiffies.h>
#include <asm/system.h>
diff --git a/drivers/char/ftape/lowlevel/ftape-ctl.c b/drivers/char/ftape/lowlevel/ftape-ctl.c
index 32e04391179..5d7c1ce92d5 100644
--- a/drivers/char/ftape/lowlevel/ftape-ctl.c
+++ b/drivers/char/ftape/lowlevel/ftape-ctl.c
@@ -25,7 +25,6 @@
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/mman.h>
diff --git a/drivers/char/ftape/lowlevel/ftape-init.c b/drivers/char/ftape/lowlevel/ftape-init.c
index b54260d457c..4998132a81d 100644
--- a/drivers/char/ftape/lowlevel/ftape-init.c
+++ b/drivers/char/ftape/lowlevel/ftape-init.c
@@ -21,7 +21,6 @@
* for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
diff --git a/drivers/char/ftape/lowlevel/ftape-proc.c b/drivers/char/ftape/lowlevel/ftape-proc.c
index c66251e997e..e805b15e0a1 100644
--- a/drivers/char/ftape/lowlevel/ftape-proc.c
+++ b/drivers/char/ftape/lowlevel/ftape-proc.c
@@ -26,7 +26,6 @@
* Old code removed, switched to dynamic proc entry.
*/
-#include <linux/config.h>
#if defined(CONFIG_PROC_FS) && defined(CONFIG_FT_PROC_FS)
diff --git a/drivers/char/ftape/lowlevel/ftape-setup.c b/drivers/char/ftape/lowlevel/ftape-setup.c
index 280a1a55d87..678340acd0b 100644
--- a/drivers/char/ftape/lowlevel/ftape-setup.c
+++ b/drivers/char/ftape/lowlevel/ftape-setup.c
@@ -25,7 +25,6 @@
* "ftape" for Linux.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/mm.h>
diff --git a/drivers/char/ftape/lowlevel/ftape-tracing.h b/drivers/char/ftape/lowlevel/ftape-tracing.h
index fa7cd20ee66..2950810c708 100644
--- a/drivers/char/ftape/lowlevel/ftape-tracing.h
+++ b/drivers/char/ftape/lowlevel/ftape-tracing.h
@@ -28,7 +28,6 @@
* QIC-40/80/3010/3020 floppy-tape driver "ftape" for Linux.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
/*
diff --git a/drivers/char/ftape/lowlevel/ftape_syms.c b/drivers/char/ftape/lowlevel/ftape_syms.c
index 5dc3a380c9b..8e0dc4a07ca 100644
--- a/drivers/char/ftape/lowlevel/ftape_syms.c
+++ b/drivers/char/ftape/lowlevel/ftape_syms.c
@@ -25,7 +25,6 @@
* exports to its high level clients
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/ftape.h>
diff --git a/drivers/char/ftape/zftape/zftape-ctl.c b/drivers/char/ftape/zftape/zftape-ctl.c
index 6c7874e5c19..22ba0f5d00c 100644
--- a/drivers/char/ftape/zftape/zftape-ctl.c
+++ b/drivers/char/ftape/zftape/zftape-ctl.c
@@ -24,7 +24,6 @@
* for the QIC-40/80/3010/3020 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/module.h>
diff --git a/drivers/char/ftape/zftape/zftape-ctl.h b/drivers/char/ftape/zftape/zftape-ctl.h
index 41415989199..8e6f2d7ac74 100644
--- a/drivers/char/ftape/zftape/zftape-ctl.h
+++ b/drivers/char/ftape/zftape/zftape-ctl.h
@@ -27,7 +27,6 @@
* for the QIC-40/80 floppy-tape driver for Linux.
*/
-#include <linux/config.h>
#include <linux/ioctl.h>
#include <linux/mtio.h>
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index 821357ce7e0..164a1aa77a2 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -20,7 +20,6 @@
* to the ftape floppy tape driver for Linux
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -33,7 +32,6 @@
#endif
#include <linux/fcntl.h>
#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/zftape.h>
#include <linux/init.h>
@@ -88,7 +86,7 @@ static ssize_t zft_read (struct file *fp, char __user *buff,
static ssize_t zft_write(struct file *fp, const char __user *buff,
size_t req_len, loff_t *ppos);
-static struct file_operations zft_cdev =
+static const struct file_operations zft_cdev =
{
.owner = THIS_MODULE,
.read = zft_read,
@@ -332,29 +330,11 @@ KERN_INFO
zft_class = class_create(THIS_MODULE, "zft");
for (i = 0; i < 4; i++) {
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i);
- devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "qft%i", i);
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i);
- devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "nqft%i", i);
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i);
- devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "zqft%i", i);
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i);
- devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "nzqft%i", i);
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i);
- devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "rawqft%i", i);
class_device_create(zft_class, NULL, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i);
- devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "nrawqft%i", i);
}
#ifdef CONFIG_ZFT_COMPRESSOR
@@ -380,17 +360,11 @@ static void zft_exit(void)
TRACE(ft_t_info, "successful");
}
for (i = 0; i < 4; i++) {
- devfs_remove("qft%i", i);
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i));
- devfs_remove("nqft%i", i);
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4));
- devfs_remove("zqft%i", i);
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16));
- devfs_remove("nzqft%i", i);
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20));
- devfs_remove("rawqft%i", i);
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32));
- devfs_remove("nrawqft%i", i);
class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36));
}
class_destroy(zft_class);
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 5e59c0b4273..4711d9b3a59 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -746,11 +746,9 @@ void gs_set_termios (struct tty_struct * tty,
gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
}
-#if 0
/* This is an optimization that is only allowed for dumb cards */
/* Smart cards require knowledge of iflags and oflags too: that
might change hardware cooking mode.... */
-#endif
if (old_termios) {
if( (tiosp->c_iflag == old_termios->c_iflag)
&& (tiosp->c_oflag == old_termios->c_oflag)
@@ -774,14 +772,7 @@ void gs_set_termios (struct tty_struct * tty,
if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
}
- baudrate = tiosp->c_cflag & CBAUD;
- if (baudrate & CBAUDEX) {
- baudrate &= ~CBAUDEX;
- if ((baudrate < 1) || (baudrate > 4))
- tiosp->c_cflag &= ~CBAUDEX;
- else
- baudrate += 15;
- }
+ baudrate = tty_get_baud_rate(tty);
baudrate = gs_baudrates[baudrate];
if ((tiosp->c_cflag & CBAUD) == B38400) {
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index 588fca542a9..817dc409ac2 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -43,7 +43,6 @@
#define RTC_VERSION "1.07"
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.h>
@@ -483,7 +482,7 @@ static inline int gen_rtc_proc_init(void) { return 0; }
* The various file operations we support.
*/
-static struct file_operations gen_rtc_fops = {
+static const struct file_operations gen_rtc_fops = {
.owner = THIS_MODULE,
#ifdef CONFIG_GEN_RTC_X
.read = gen_rtc_read,
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index ac626418b32..d69f2ad9a67 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -117,12 +117,12 @@ __setup("hcheck_reboot", hangcheck_parse_reboot);
__setup("hcheck_dump_tasks", hangcheck_parse_dump_tasks);
#endif /* not MODULE */
-#if defined(CONFIG_X86) || defined(CONFIG_S390)
+#if defined(CONFIG_X86_64) || defined(CONFIG_S390)
# define HAVE_MONOTONIC
# define TIMER_FREQ 1000000000ULL
#elif defined(CONFIG_IA64)
# define TIMER_FREQ ((unsigned long long)local_cpu_data->itc_freq)
-#elif defined(CONFIG_PPC64)
+#else
# define TIMER_FREQ (HZ*loops_per_jiffy)
#endif
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 07473cd8412..58b0eb58111 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -11,7 +11,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -396,7 +395,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp)
sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev));
irq_flags = devp->hd_flags & HPET_SHARED_IRQ
- ? SA_SHIRQ : SA_INTERRUPT;
+ ? IRQF_SHARED : IRQF_DISABLED;
if (request_irq(irq, hpet_interrupt, irq_flags,
devp->hd_name, (void *)devp)) {
printk(KERN_ERR "hpet: IRQ %d is not free\n", irq);
@@ -554,7 +553,7 @@ hpet_ioctl_common(struct hpet_dev *devp, int cmd, unsigned long arg, int kernel)
return err;
}
-static struct file_operations hpet_fops = {
+static const struct file_operations hpet_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = hpet_read,
@@ -869,8 +868,8 @@ int hpet_alloc(struct hpet_data *hdp)
do_div(temp, period);
hpetp->hp_tick_freq = temp; /* ticks per second */
- printk(KERN_INFO "hpet%d: at MMIO 0x%lx (virtual 0x%p), IRQ%s",
- hpetp->hp_which, hdp->hd_phys_address, hdp->hd_address,
+ printk(KERN_INFO "hpet%d: at MMIO 0x%lx, IRQ%s",
+ hpetp->hp_which, hdp->hd_phys_address,
hpetp->hp_ntimer > 1 ? "s" : "");
for (i = 0; i < hpetp->hp_ntimer; i++)
printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]);
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index a5c6a9d7ff0..a76d2c40dd5 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/console.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -81,7 +80,8 @@ struct hvc_struct {
struct tty_struct *tty;
unsigned int count;
int do_wakeup;
- char outbuf[N_OUTBUF] __ALIGNED__;
+ char *outbuf;
+ int outbuf_size;
int n_outbuf;
uint32_t vtermno;
struct hv_ops *ops;
@@ -320,10 +320,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
struct kobject *kobjp;
/* Auto increments kobject reference if found. */
- if (!(hp = hvc_get_by_index(tty->index))) {
- printk(KERN_WARNING "hvc_console: tty open failed, no vty associated with tty.\n");
+ if (!(hp = hvc_get_by_index(tty->index)))
return -ENODEV;
- }
spin_lock_irqsave(&hp->lock, flags);
/* Check and then increment for fast path open. */
@@ -347,7 +345,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
spin_unlock_irqrestore(&hp->lock, flags);
/* check error, fallback to non-irq */
if (irq != NO_IRQ)
- rc = request_irq(irq, hvc_handle_interrupt, SA_INTERRUPT, "hvc_console", hp);
+ rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
/*
* If the request_irq() fails and we return an error. The tty layer
@@ -506,7 +504,7 @@ static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count
if (hp->n_outbuf > 0)
hvc_push(hp);
- while (count > 0 && (rsize = N_OUTBUF - hp->n_outbuf) > 0) {
+ while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) {
if (rsize > count)
rsize = count;
memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
@@ -539,7 +537,7 @@ static int hvc_write_room(struct tty_struct *tty)
if (!hp)
return -1;
- return N_OUTBUF - hp->n_outbuf;
+ return hp->outbuf_size - hp->n_outbuf;
}
static int hvc_chars_in_buffer(struct tty_struct *tty)
@@ -669,6 +667,7 @@ int khvcd(void *unused)
do {
poll_mask = 0;
hvc_kicked = 0;
+ try_to_freeze();
wmb();
if (cpus_empty(cpus_in_xmon)) {
spin_lock(&hvc_structs_lock);
@@ -729,12 +728,13 @@ static struct kobj_type hvc_kobj_type = {
};
struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
- struct hv_ops *ops)
+ struct hv_ops *ops, int outbuf_size)
{
struct hvc_struct *hp;
int i;
- hp = kmalloc(sizeof(*hp), GFP_KERNEL);
+ hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
+ GFP_KERNEL);
if (!hp)
return ERR_PTR(-ENOMEM);
@@ -743,6 +743,8 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
hp->vtermno = vtermno;
hp->irq = irq;
hp->ops = ops;
+ hp->outbuf_size = outbuf_size;
+ hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
kobject_init(&hp->kobj);
hp->kobj.ktype = &hvc_kobj_type;
@@ -820,7 +822,6 @@ int __init hvc_init(void)
return -ENOMEM;
drv->owner = THIS_MODULE;
- drv->devfs_name = "hvc/";
drv->driver_name = "hvc";
drv->name = "hvc";
drv->major = HVC_MAJOR;
diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h
index 96b7401319c..8c59818050e 100644
--- a/drivers/char/hvc_console.h
+++ b/drivers/char/hvc_console.h
@@ -56,7 +56,7 @@ extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
/* register a vterm for hvc tty operation (module_init or hotplug add) */
extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
- struct hv_ops *ops);
+ struct hv_ops *ops, int outbuf_size);
/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
extern int __devexit hvc_remove(struct hvc_struct *hp);
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
new file mode 100644
index 00000000000..4747729459c
--- /dev/null
+++ b/drivers/char/hvc_iseries.c
@@ -0,0 +1,594 @@
+/*
+ * iSeries vio driver interface to hvc_console.c
+ *
+ * This code is based heavily on hvc_vio.c and viocons.c
+ *
+ * Copyright (C) 2006 Stephen Rothwell, IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <stdarg.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/console.h>
+
+#include <asm/hvconsole.h>
+#include <asm/vio.h>
+#include <asm/prom.h>
+#include <asm/iseries/vio.h>
+#include <asm/iseries/hv_call.h>
+#include <asm/iseries/hv_lp_config.h>
+#include <asm/iseries/hv_lp_event.h>
+
+#include "hvc_console.h"
+
+#define VTTY_PORTS 10
+
+static DEFINE_SPINLOCK(consolelock);
+static DEFINE_SPINLOCK(consoleloglock);
+
+static const char hvc_driver_name[] = "hvc_console";
+
+#define IN_BUF_SIZE 200
+
+/*
+ * Our port information.
+ */
+static struct port_info {
+ HvLpIndex lp;
+ u64 seq; /* sequence number of last HV send */
+ u64 ack; /* last ack from HV */
+ struct hvc_struct *hp;
+ int in_start;
+ int in_end;
+ unsigned char in_buf[IN_BUF_SIZE];
+} port_info[VTTY_PORTS] = {
+ [ 0 ... VTTY_PORTS - 1 ] = {
+ .lp = HvLpIndexInvalid
+ }
+};
+
+#define viochar_is_console(pi) ((pi) == &port_info[0])
+
+static struct vio_device_id hvc_driver_table[] __devinitdata = {
+ {"serial", "IBM,iSeries-vty"},
+ { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, hvc_driver_table);
+
+static void hvlog(char *fmt, ...)
+{
+ int i;
+ unsigned long flags;
+ va_list args;
+ static char buf[256];
+
+ spin_lock_irqsave(&consoleloglock, flags);
+ va_start(args, fmt);
+ i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
+ va_end(args);
+ buf[i++] = '\r';
+ HvCall_writeLogBuffer(buf, i);
+ spin_unlock_irqrestore(&consoleloglock, flags);
+}
+
+/*
+ * Initialize the common fields in a charLpEvent
+ */
+static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp)
+{
+ struct HvLpEvent *hev = &viochar->event;
+
+ memset(viochar, 0, sizeof(struct viocharlpevent));
+
+ hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
+ HV_LP_EVENT_INT;
+ hev->xType = HvLpEvent_Type_VirtualIo;
+ hev->xSubtype = viomajorsubtype_chario | viochardata;
+ hev->xSourceLp = HvLpConfig_getLpIndex();
+ hev->xTargetLp = lp;
+ hev->xSizeMinus1 = sizeof(struct viocharlpevent);
+ hev->xSourceInstanceId = viopath_sourceinst(lp);
+ hev->xTargetInstanceId = viopath_targetinst(lp);
+}
+
+static int get_chars(uint32_t vtermno, char *buf, int count)
+{
+ struct port_info *pi;
+ int n = 0;
+ unsigned long flags;
+
+ if (vtermno >= VTTY_PORTS)
+ return -EINVAL;
+ if (count == 0)
+ return 0;
+
+ pi = &port_info[vtermno];
+ spin_lock_irqsave(&consolelock, flags);
+
+ if (pi->in_end == 0)
+ goto done;
+
+ n = pi->in_end - pi->in_start;
+ if (n > count)
+ n = count;
+ memcpy(buf, &pi->in_buf[pi->in_start], n);
+ pi->in_start += n;
+ if (pi->in_start == pi->in_end) {
+ pi->in_start = 0;
+ pi->in_end = 0;
+ }
+done:
+ spin_unlock_irqrestore(&consolelock, flags);
+ return n;
+}
+
+static int put_chars(uint32_t vtermno, const char *buf, int count)
+{
+ struct viocharlpevent *viochar;
+ struct port_info *pi;
+ HvLpEvent_Rc hvrc;
+ unsigned long flags;
+ int sent = 0;
+
+ if (vtermno >= VTTY_PORTS)
+ return -EINVAL;
+
+ pi = &port_info[vtermno];
+
+ spin_lock_irqsave(&consolelock, flags);
+
+ if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
+ spin_lock_irqsave(&consoleloglock, flags);
+ HvCall_writeLogBuffer(buf, count);
+ spin_unlock_irqrestore(&consoleloglock, flags);
+ sent = count;
+ goto done;
+ }
+
+ viochar = vio_get_event_buffer(viomajorsubtype_chario);
+ if (viochar == NULL) {
+ hvlog("\n\rviocons: Can't get viochar buffer.");
+ goto done;
+ }
+
+ while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
+ int len;
+
+ len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
+
+ if (viochar_is_console(pi)) {
+ spin_lock_irqsave(&consoleloglock, flags);
+ HvCall_writeLogBuffer(buf, len);
+ spin_unlock_irqrestore(&consoleloglock, flags);
+ }
+
+ init_data_event(viochar, pi->lp);
+
+ viochar->len = len;
+ viochar->event.xCorrelationToken = pi->seq++;
+ viochar->event.xSizeMinus1 =
+ offsetof(struct viocharlpevent, data) + len;
+
+ memcpy(viochar->data, buf, len);
+
+ hvrc = HvCallEvent_signalLpEvent(&viochar->event);
+ if (hvrc)
+ hvlog("\n\rerror sending event! return code %d\n\r",
+ (int)hvrc);
+ sent += len;
+ count -= len;
+ buf += len;
+ }
+
+ vio_free_event_buffer(viomajorsubtype_chario, viochar);
+done:
+ spin_unlock_irqrestore(&consolelock, flags);
+ return sent;
+}
+
+static struct hv_ops hvc_get_put_ops = {
+ .get_chars = get_chars,
+ .put_chars = put_chars,
+};
+
+static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ struct hvc_struct *hp;
+ struct port_info *pi;
+
+ /* probed with invalid parameters. */
+ if (!vdev || !id)
+ return -EPERM;
+
+ if (vdev->unit_address >= VTTY_PORTS)
+ return -ENODEV;
+
+ pi = &port_info[vdev->unit_address];
+
+ hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
+ VIOCHAR_MAX_DATA);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ pi->hp = hp;
+ dev_set_drvdata(&vdev->dev, pi);
+
+ return 0;
+}
+
+static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+{
+ struct port_info *pi = dev_get_drvdata(&vdev->dev);
+ struct hvc_struct *hp = pi->hp;
+
+ return hvc_remove(hp);
+}
+
+static struct vio_driver hvc_vio_driver = {
+ .id_table = hvc_driver_table,
+ .probe = hvc_vio_probe,
+ .remove = hvc_vio_remove,
+ .driver = {
+ .name = hvc_driver_name,
+ .owner = THIS_MODULE,
+ }
+};
+
+static void hvc_open_event(struct HvLpEvent *event)
+{
+ unsigned long flags;
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ u8 port = cevent->virtual_device;
+ struct port_info *pi;
+ int reject = 0;
+
+ if (hvlpevent_is_ack(event)) {
+ if (port >= VTTY_PORTS)
+ return;
+
+ spin_lock_irqsave(&consolelock, flags);
+
+ pi = &port_info[port];
+ if (event->xRc == HvLpEvent_Rc_Good) {
+ pi->seq = pi->ack = 0;
+ /*
+ * This line allows connections from the primary
+ * partition but once one is connected from the
+ * primary partition nothing short of a reboot
+ * of linux will allow access from the hosting
+ * partition again without a required iSeries fix.
+ */
+ pi->lp = event->xTargetLp;
+ }
+
+ spin_unlock_irqrestore(&consolelock, flags);
+ if (event->xRc != HvLpEvent_Rc_Good)
+ printk(KERN_WARNING
+ "hvc: handle_open_event: event->xRc == (%d).\n",
+ event->xRc);
+
+ if (event->xCorrelationToken != 0) {
+ atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
+ atomic_set(aptr, 1);
+ } else
+ printk(KERN_WARNING
+ "hvc: weird...got open ack without atomic\n");
+ return;
+ }
+
+ /* This had better require an ack, otherwise complain */
+ if (!hvlpevent_need_ack(event)) {
+ printk(KERN_WARNING "hvc: viocharopen without ack bit!\n");
+ return;
+ }
+
+ spin_lock_irqsave(&consolelock, flags);
+
+ /* Make sure this is a good virtual tty */
+ if (port >= VTTY_PORTS) {
+ event->xRc = HvLpEvent_Rc_SubtypeError;
+ cevent->subtype_result_code = viorc_openRejected;
+ /*
+ * Flag state here since we can't printk while holding
+ * the consolelock spinlock.
+ */
+ reject = 1;
+ } else {
+ pi = &port_info[port];
+ if ((pi->lp != HvLpIndexInvalid) &&
+ (pi->lp != event->xSourceLp)) {
+ /*
+ * If this is tty is already connected to a different
+ * partition, fail.
+ */
+ event->xRc = HvLpEvent_Rc_SubtypeError;
+ cevent->subtype_result_code = viorc_openRejected;
+ reject = 2;
+ } else {
+ pi->lp = event->xSourceLp;
+ event->xRc = HvLpEvent_Rc_Good;
+ cevent->subtype_result_code = viorc_good;
+ pi->seq = pi->ack = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&consolelock, flags);
+
+ if (reject == 1)
+ printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n");
+ else if (reject == 2)
+ printk(KERN_WARNING "hvc: open rejected: console in exclusive "
+ "use by another partition.\n");
+
+ /* Return the acknowledgement */
+ HvCallEvent_ackLpEvent(event);
+}
+
+/*
+ * Handle a close charLpEvent. This should ONLY be an Interrupt because the
+ * virtual console should never actually issue a close event to the hypervisor
+ * because the virtual console never goes away. A close event coming from the
+ * hypervisor simply means that there are no client consoles connected to the
+ * virtual console.
+ */
+static void hvc_close_event(struct HvLpEvent *event)
+{
+ unsigned long flags;
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ u8 port = cevent->virtual_device;
+
+ if (!hvlpevent_is_int(event)) {
+ printk(KERN_WARNING
+ "hvc: got unexpected close acknowlegement\n");
+ return;
+ }
+
+ if (port >= VTTY_PORTS) {
+ printk(KERN_WARNING
+ "hvc: close message from invalid virtual device.\n");
+ return;
+ }
+
+ /* For closes, just mark the console partition invalid */
+ spin_lock_irqsave(&consolelock, flags);
+
+ if (port_info[port].lp == event->xSourceLp)
+ port_info[port].lp = HvLpIndexInvalid;
+
+ spin_unlock_irqrestore(&consolelock, flags);
+}
+
+static void hvc_data_event(struct HvLpEvent *event)
+{
+ unsigned long flags;
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ struct port_info *pi;
+ int n;
+ u8 port = cevent->virtual_device;
+
+ if (port >= VTTY_PORTS) {
+ printk(KERN_WARNING "hvc: data on invalid virtual device %d\n",
+ port);
+ return;
+ }
+ if (cevent->len == 0)
+ return;
+
+ /*
+ * Change 05/01/2003 - Ryan Arnold: If a partition other than
+ * the current exclusive partition tries to send us data
+ * events then just drop them on the floor because we don't
+ * want his stinking data. He isn't authorized to receive
+ * data because he wasn't the first one to get the console,
+ * therefore he shouldn't be allowed to send data either.
+ * This will work without an iSeries fix.
+ */
+ pi = &port_info[port];
+ if (pi->lp != event->xSourceLp)
+ return;
+
+ spin_lock_irqsave(&consolelock, flags);
+
+ n = IN_BUF_SIZE - pi->in_end;
+ if (n > cevent->len)
+ n = cevent->len;
+ if (n > 0) {
+ memcpy(&pi->in_buf[pi->in_end], cevent->data, n);
+ pi->in_end += n;
+ }
+ spin_unlock_irqrestore(&consolelock, flags);
+ if (n == 0)
+ printk(KERN_WARNING "hvc: input buffer overflow\n");
+}
+
+static void hvc_ack_event(struct HvLpEvent *event)
+{
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+ unsigned long flags;
+ u8 port = cevent->virtual_device;
+
+ if (port >= VTTY_PORTS) {
+ printk(KERN_WARNING "hvc: data on invalid virtual device\n");
+ return;
+ }
+
+ spin_lock_irqsave(&consolelock, flags);
+ port_info[port].ack = event->xCorrelationToken;
+ spin_unlock_irqrestore(&consolelock, flags);
+}
+
+static void hvc_config_event(struct HvLpEvent *event)
+{
+ struct viocharlpevent *cevent = (struct viocharlpevent *)event;
+
+ if (cevent->data[0] == 0x01)
+ printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n",
+ cevent->data[1], cevent->data[2],
+ cevent->data[3], cevent->data[4]);
+ else
+ printk(KERN_WARNING "hvc: unknown config event\n");
+}
+
+static void hvc_handle_event(struct HvLpEvent *event)
+{
+ int charminor;
+
+ if (event == NULL)
+ return;
+
+ charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
+ switch (charminor) {
+ case viocharopen:
+ hvc_open_event(event);
+ break;
+ case viocharclose:
+ hvc_close_event(event);
+ break;
+ case viochardata:
+ hvc_data_event(event);
+ break;
+ case viocharack:
+ hvc_ack_event(event);
+ break;
+ case viocharconfig:
+ hvc_config_event(event);
+ break;
+ default:
+ if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
+ event->xRc = HvLpEvent_Rc_InvalidSubtype;
+ HvCallEvent_ackLpEvent(event);
+ }
+ }
+}
+
+static int send_open(HvLpIndex remoteLp, void *sem)
+{
+ return HvCallEvent_signalLpEventFast(remoteLp,
+ HvLpEvent_Type_VirtualIo,
+ viomajorsubtype_chario | viocharopen,
+ HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
+ viopath_sourceinst(remoteLp),
+ viopath_targetinst(remoteLp),
+ (u64)(unsigned long)sem, VIOVERSION << 16,
+ 0, 0, 0, 0);
+}
+
+static int hvc_vio_init(void)
+{
+ atomic_t wait_flag;
+ int rc;
+
+ /* +2 for fudge */
+ rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
+ viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
+ if (rc)
+ printk(KERN_WARNING "hvc: error opening to primary %d\n", rc);
+
+ if (viopath_hostLp == HvLpIndexInvalid)
+ vio_set_hostlp();
+
+ /*
+ * And if the primary is not the same as the hosting LP, open to the
+ * hosting lp
+ */
+ if ((viopath_hostLp != HvLpIndexInvalid) &&
+ (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
+ printk(KERN_INFO "hvc: open path to hosting (%d)\n",
+ viopath_hostLp);
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
+ VIOCHAR_WINDOW + 2); /* +2 for fudge */
+ if (rc)
+ printk(KERN_WARNING
+ "error opening to partition %d: %d\n",
+ viopath_hostLp, rc);
+ }
+
+ if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0)
+ printk(KERN_WARNING
+ "hvc: error seting handler for console events!\n");
+
+ /*
+ * First, try to open the console to the hosting lp.
+ * Wait on a semaphore for the response.
+ */
+ atomic_set(&wait_flag, 0);
+ if ((viopath_isactive(viopath_hostLp)) &&
+ (send_open(viopath_hostLp, &wait_flag) == 0)) {
+ printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp);
+ while (atomic_read(&wait_flag) == 0)
+ mb();
+ atomic_set(&wait_flag, 0);
+ }
+
+ /*
+ * If we don't have an active console, try the primary
+ */
+ if ((!viopath_isactive(port_info[0].lp)) &&
+ (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
+ (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) {
+ printk(KERN_INFO "hvc: opening console to primary partition\n");
+ while (atomic_read(&wait_flag) == 0)
+ mb();
+ }
+
+ /* Register as a vio device to receive callbacks */
+ rc = vio_register_driver(&hvc_vio_driver);
+
+ return rc;
+}
+module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
+
+static void hvc_vio_exit(void)
+{
+ vio_unregister_driver(&hvc_vio_driver);
+}
+module_exit(hvc_vio_exit);
+
+/* the device tree order defines our numbering */
+static int hvc_find_vtys(void)
+{
+ struct device_node *vty;
+ int num_found = 0;
+
+ for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
+ vty = of_find_node_by_name(vty, "vty")) {
+ uint32_t *vtermno;
+
+ /* We have statically defined space for only a certain number
+ * of console adapters.
+ */
+ if ((num_found >= MAX_NR_HVC_CONSOLES) ||
+ (num_found >= VTTY_PORTS))
+ break;
+
+ vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+ if (!vtermno)
+ continue;
+
+ if (!device_is_compatible(vty, "IBM,iSeries-vty"))
+ continue;
+
+ if (num_found == 0)
+ add_preferred_console("hvc", 0, NULL);
+ hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
+ ++num_found;
+ }
+
+ return num_found;
+}
+console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c
index 57106e02fd2..4b97eaf1860 100644
--- a/drivers/char/hvc_rtas.c
+++ b/drivers/char/hvc_rtas.c
@@ -94,7 +94,7 @@ static int hvc_rtas_init(void)
/* Allocate an hvc_struct for the console device we instantiated
* earlier. Save off hp so that we can return it on exit */
- hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops);
+ hp = hvc_alloc(hvc_rtas_cookie, NO_IRQ, &hvc_rtas_get_put_ops, 16);
if (IS_ERR(hp))
return PTR_ERR(hp);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index 9add81ceb44..cc95941148f 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -90,7 +90,8 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev,
if (!vdev || !id)
return -EPERM;
- hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops);
+ hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops,
+ MAX_VIO_PUT_CHARS);
if (IS_ERR(hp))
return PTR_ERR(hp);
dev_set_drvdata(&vdev->dev, hp);
@@ -140,7 +141,7 @@ static int hvc_find_vtys(void)
for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
vty = of_find_node_by_name(vty, "vty")) {
- uint32_t *vtermno;
+ const uint32_t *vtermno;
/* We have statically defined space for only a certain number
* of console adapters.
@@ -148,7 +149,7 @@ static int hvc_find_vtys(void)
if (num_found >= MAX_NR_HVC_CONSOLES)
break;
- vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+ vtermno = get_property(vty, "reg", NULL);
if (!vtermno)
continue;
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 8d97b391129..4589ff302b0 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -899,7 +899,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
* the conn was registered and now.
*/
if (!(rc = request_irq(irq, &hvcs_handle_interrupt,
- SA_INTERRUPT, "ibmhvcs", hvcsd))) {
+ IRQF_DISABLED, "ibmhvcs", hvcsd))) {
/*
* It is possible the vty-server was removed after the irq was
* requested but before we have time to enable interrupts.
@@ -1320,11 +1320,12 @@ static struct tty_operations hvcs_ops = {
static int hvcs_alloc_index_list(int n)
{
int i;
+
hvcs_index_list = kmalloc(n * sizeof(hvcs_index_count),GFP_KERNEL);
if (!hvcs_index_list)
return -ENOMEM;
hvcs_index_count = n;
- for(i = 0; i < hvcs_index_count; i++)
+ for (i = 0; i < hvcs_index_count; i++)
hvcs_index_list[i] = -1;
return 0;
}
@@ -1332,11 +1333,9 @@ static int hvcs_alloc_index_list(int n)
static void hvcs_free_index_list(void)
{
/* Paranoia check to be thorough. */
- if (hvcs_index_list) {
- kfree(hvcs_index_list);
- hvcs_index_list = NULL;
- hvcs_index_count = 0;
- }
+ kfree(hvcs_index_list);
+ hvcs_index_list = NULL;
+ hvcs_index_count = 0;
}
static int __init hvcs_module_init(void)
@@ -1364,7 +1363,6 @@ static int __init hvcs_module_init(void)
hvcs_tty_driver->driver_name = hvcs_driver_name;
hvcs_tty_driver->name = hvcs_device_node;
- hvcs_tty_driver->devfs_name = hvcs_device_node;
/*
* We'll let the system assign us a major number, indicated by leaving
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index a0370ed752c..a89a95fb5e4 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -311,7 +311,8 @@ static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
/* CD went away; no more connection */
pr_debug("hvsi%i: CD dropped\n", hp->index);
hp->mctrl &= TIOCM_CD;
- if (!(hp->tty->flags & CLOCAL))
+ /* If userland hasn't done an open(2) yet, hp->tty is NULL. */
+ if (hp->tty && !(hp->tty->flags & CLOCAL))
*to_hangup = hp->tty;
}
break;
@@ -986,10 +987,7 @@ static void hvsi_write_worker(void *arg)
start_j = 0;
#endif /* DEBUG */
wake_up_all(&hp->emptyq);
- if (test_bit(TTY_DO_WRITE_WAKEUP, &hp->tty->flags)
- && hp->tty->ldisc.write_wakeup)
- hp->tty->ldisc.write_wakeup(hp->tty);
- wake_up_interruptible(&hp->tty->write_wait);
+ tty_wakeup(hp->tty);
}
out:
@@ -1154,7 +1152,6 @@ static int __init hvsi_init(void)
return -ENOMEM;
hvsi_driver->owner = THIS_MODULE;
- hvsi_driver->devfs_name = "hvsi/";
hvsi_driver->driver_name = "hvsi";
hvsi_driver->name = "hvsi";
hvsi_driver->major = HVSI_MAJOR;
@@ -1169,7 +1166,7 @@ static int __init hvsi_init(void)
struct hvsi_struct *hp = &hvsi_ports[i];
int ret = 1;
- ret = request_irq(hp->virq, hvsi_interrupt, SA_INTERRUPT, "hvsi", hp);
+ ret = request_irq(hp->virq, hvsi_interrupt, IRQF_DISABLED, "hvsi", hp);
if (ret)
printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
hp->virq, ret);
@@ -1277,11 +1274,10 @@ static int __init hvsi_console_init(void)
vty != NULL;
vty = of_find_compatible_node(vty, "serial", "hvterm-protocol")) {
struct hvsi_struct *hp;
- uint32_t *vtermno;
- uint32_t *irq;
+ const uint32_t *vtermno, *irq;
- vtermno = (uint32_t *)get_property(vty, "reg", NULL);
- irq = (uint32_t *)get_property(vty, "interrupts", NULL);
+ vtermno = get_property(vty, "reg", NULL);
+ irq = get_property(vty, "interrupts", NULL);
if (!vtermno || !irq)
continue;
@@ -1300,13 +1296,12 @@ static int __init hvsi_console_init(void)
hp->inbuf_end = hp->inbuf;
hp->state = HVSI_CLOSED;
hp->vtermno = *vtermno;
- hp->virq = virt_irq_create_mapping(irq[0]);
+ hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
- __FUNCTION__, hp->virq);
+ __FUNCTION__, irq[0]);
continue;
- } else
- hp->virq = irq_offset_up(hp->virq);
+ }
hvsi_count++;
}
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c
deleted file mode 100644
index 29dc87e5902..00000000000
--- a/drivers/char/hw_random.c
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- Added support for the AMD Geode LX RNG
- (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
-
- derived from
-
- Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
- (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
-
- derived from
-
- Hardware driver for the AMD 768 Random Number Generator (RNG)
- (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
-
- derived from
-
- Hardware driver for Intel i810 Random Number Generator (RNG)
- Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
- Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
-
- Please read Documentation/hw_random.txt for details on use.
-
- ----------------------------------------------------------
- This software may be used and distributed according to the terms
- of the GNU General Public License, incorporated herein by reference.
-
- */
-
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/random.h>
-#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-
-#ifdef __i386__
-#include <asm/msr.h>
-#include <asm/cpufeature.h>
-#endif
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-
-/*
- * core module and version information
- */
-#define RNG_VERSION "1.0.0"
-#define RNG_MODULE_NAME "hw_random"
-#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
-#define PFX RNG_MODULE_NAME ": "
-
-
-/*
- * debugging macros
- */
-
-/* pr_debug() collapses to a no-op if DEBUG is not defined */
-#define DPRINTK(fmt, args...) pr_debug(PFX "%s: " fmt, __FUNCTION__ , ## args)
-
-
-#undef RNG_NDEBUG /* define to enable lightweight runtime checks */
-#ifdef RNG_NDEBUG
-#define assert(expr) \
- if(!(expr)) { \
- printk(KERN_DEBUG PFX "Assertion failed! %s,%s,%s," \
- "line=%d\n", #expr, __FILE__, __FUNCTION__, __LINE__); \
- }
-#else
-#define assert(expr)
-#endif
-
-#define RNG_MISCDEV_MINOR 183 /* official */
-
-static int rng_dev_open (struct inode *inode, struct file *filp);
-static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
- loff_t * offp);
-
-static int __init intel_init (struct pci_dev *dev);
-static void intel_cleanup(void);
-static unsigned int intel_data_present (void);
-static u32 intel_data_read (void);
-
-static int __init amd_init (struct pci_dev *dev);
-static void amd_cleanup(void);
-static unsigned int amd_data_present (void);
-static u32 amd_data_read (void);
-
-#ifdef __i386__
-static int __init via_init(struct pci_dev *dev);
-static void via_cleanup(void);
-static unsigned int via_data_present (void);
-static u32 via_data_read (void);
-#endif
-
-static int __init geode_init(struct pci_dev *dev);
-static void geode_cleanup(void);
-static unsigned int geode_data_present (void);
-static u32 geode_data_read (void);
-
-struct rng_operations {
- int (*init) (struct pci_dev *dev);
- void (*cleanup) (void);
- unsigned int (*data_present) (void);
- u32 (*data_read) (void);
- unsigned int n_bytes; /* number of bytes per ->data_read */
-};
-static struct rng_operations *rng_ops;
-
-static struct file_operations rng_chrdev_ops = {
- .owner = THIS_MODULE,
- .open = rng_dev_open,
- .read = rng_dev_read,
-};
-
-
-static struct miscdevice rng_miscdev = {
- RNG_MISCDEV_MINOR,
- RNG_MODULE_NAME,
- &rng_chrdev_ops,
-};
-
-enum {
- rng_hw_none,
- rng_hw_intel,
- rng_hw_amd,
-#ifdef __i386__
- rng_hw_via,
-#endif
- rng_hw_geode,
-};
-
-static struct rng_operations rng_vendor_ops[] = {
- /* rng_hw_none */
- { },
-
- /* rng_hw_intel */
- { intel_init, intel_cleanup, intel_data_present,
- intel_data_read, 1 },
-
- /* rng_hw_amd */
- { amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
-
-#ifdef __i386__
- /* rng_hw_via */
- { via_init, via_cleanup, via_data_present, via_data_read, 1 },
-#endif
-
- /* rng_hw_geode */
- { geode_init, geode_cleanup, geode_data_present, geode_data_read, 4 }
-};
-
-/*
- * Data for PCI driver interface
- *
- * This data only exists for exporting the supported
- * PCI ids via MODULE_DEVICE_TABLE. We do not actually
- * register a pci_driver, because someone else might one day
- * want to register another driver on the same PCI id.
- */
-static struct pci_device_id rng_pci_tbl[] = {
- { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
- { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_amd },
-
- { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
- { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
- { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
- { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
- { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
- { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_intel },
-
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, rng_hw_geode },
-
- { 0, }, /* terminate list */
-};
-MODULE_DEVICE_TABLE (pci, rng_pci_tbl);
-
-
-/***********************************************************************
- *
- * Intel RNG operations
- *
- */
-
-/*
- * RNG registers (offsets from rng_mem)
- */
-#define INTEL_RNG_HW_STATUS 0
-#define INTEL_RNG_PRESENT 0x40
-#define INTEL_RNG_ENABLED 0x01
-#define INTEL_RNG_STATUS 1
-#define INTEL_RNG_DATA_PRESENT 0x01
-#define INTEL_RNG_DATA 2
-
-/*
- * Magic address at which Intel PCI bridges locate the RNG
- */
-#define INTEL_RNG_ADDR 0xFFBC015F
-#define INTEL_RNG_ADDR_LEN 3
-
-/* token to our ioremap'd RNG register area */
-static void __iomem *rng_mem;
-
-static inline u8 intel_hwstatus (void)
-{
- assert (rng_mem != NULL);
- return readb (rng_mem + INTEL_RNG_HW_STATUS);
-}
-
-static inline u8 intel_hwstatus_set (u8 hw_status)
-{
- assert (rng_mem != NULL);
- writeb (hw_status, rng_mem + INTEL_RNG_HW_STATUS);
- return intel_hwstatus ();
-}
-
-static unsigned int intel_data_present(void)
-{
- assert (rng_mem != NULL);
-
- return (readb (rng_mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT) ?
- 1 : 0;
-}
-
-static u32 intel_data_read(void)
-{
- assert (rng_mem != NULL);
-
- return readb (rng_mem + INTEL_RNG_DATA);
-}
-
-static int __init intel_init (struct pci_dev *dev)
-{
- int rc;
- u8 hw_status;
-
- DPRINTK ("ENTER\n");
-
- rng_mem = ioremap (INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
- if (rng_mem == NULL) {
- printk (KERN_ERR PFX "cannot ioremap RNG Memory\n");
- rc = -EBUSY;
- goto err_out;
- }
-
- /* Check for Intel 82802 */
- hw_status = intel_hwstatus ();
- if ((hw_status & INTEL_RNG_PRESENT) == 0) {
- printk (KERN_ERR PFX "RNG not detected\n");
- rc = -ENODEV;
- goto err_out_free_map;
- }
-
- /* turn RNG h/w on, if it's off */
- if ((hw_status & INTEL_RNG_ENABLED) == 0)
- hw_status = intel_hwstatus_set (hw_status | INTEL_RNG_ENABLED);
- if ((hw_status & INTEL_RNG_ENABLED) == 0) {
- printk (KERN_ERR PFX "cannot enable RNG, aborting\n");
- rc = -EIO;
- goto err_out_free_map;
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out_free_map:
- iounmap (rng_mem);
- rng_mem = NULL;
-err_out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-static void intel_cleanup(void)
-{
- u8 hw_status;
-
- hw_status = intel_hwstatus ();
- if (hw_status & INTEL_RNG_ENABLED)
- intel_hwstatus_set (hw_status & ~INTEL_RNG_ENABLED);
- else
- printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
- iounmap(rng_mem);
- rng_mem = NULL;
-}
-
-/***********************************************************************
- *
- * AMD RNG operations
- *
- */
-
-static u32 pmbase; /* PMxx I/O base */
-static struct pci_dev *amd_dev;
-
-static unsigned int amd_data_present (void)
-{
- return inl(pmbase + 0xF4) & 1;
-}
-
-
-static u32 amd_data_read (void)
-{
- return inl(pmbase + 0xF0);
-}
-
-static int __init amd_init (struct pci_dev *dev)
-{
- int rc;
- u8 rnen;
-
- DPRINTK ("ENTER\n");
-
- pci_read_config_dword(dev, 0x58, &pmbase);
-
- pmbase &= 0x0000FF00;
-
- if (pmbase == 0)
- {
- printk (KERN_ERR PFX "power management base not set\n");
- rc = -EIO;
- goto err_out;
- }
-
- pci_read_config_byte(dev, 0x40, &rnen);
- rnen |= (1 << 7); /* RNG on */
- pci_write_config_byte(dev, 0x40, rnen);
-
- pci_read_config_byte(dev, 0x41, &rnen);
- rnen |= (1 << 7); /* PMIO enable */
- pci_write_config_byte(dev, 0x41, rnen);
-
- pr_info( PFX "AMD768 system management I/O registers at 0x%X.\n",
- pmbase);
-
- amd_dev = dev;
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-static void amd_cleanup(void)
-{
- u8 rnen;
-
- pci_read_config_byte(amd_dev, 0x40, &rnen);
- rnen &= ~(1 << 7); /* RNG off */
- pci_write_config_byte(amd_dev, 0x40, rnen);
-
- /* FIXME: twiddle pmio, also? */
-}
-
-#ifdef __i386__
-/***********************************************************************
- *
- * VIA RNG operations
- *
- */
-
-enum {
- VIA_STRFILT_CNT_SHIFT = 16,
- VIA_STRFILT_FAIL = (1 << 15),
- VIA_STRFILT_ENABLE = (1 << 14),
- VIA_RAWBITS_ENABLE = (1 << 13),
- VIA_RNG_ENABLE = (1 << 6),
- VIA_XSTORE_CNT_MASK = 0x0F,
-
- VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */
- VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */
- VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF,
- VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */
- VIA_RNG_CHUNK_2_MASK = 0xFFFF,
- VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */
- VIA_RNG_CHUNK_1_MASK = 0xFF,
-};
-
-static u32 via_rng_datum;
-
-/*
- * Investigate using the 'rep' prefix to obtain 32 bits of random data
- * in one insn. The upside is potentially better performance. The
- * downside is that the instruction becomes no longer atomic. Due to
- * this, just like familiar issues with /dev/random itself, the worst
- * case of a 'rep xstore' could potentially pause a cpu for an
- * unreasonably long time. In practice, this condition would likely
- * only occur when the hardware is failing. (or so we hope :))
- *
- * Another possible performance boost may come from simply buffering
- * until we have 4 bytes, thus returning a u32 at a time,
- * instead of the current u8-at-a-time.
- */
-
-static inline u32 xstore(u32 *addr, u32 edx_in)
-{
- u32 eax_out;
-
- asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
- :"=m"(*addr), "=a"(eax_out)
- :"D"(addr), "d"(edx_in));
-
- return eax_out;
-}
-
-static unsigned int via_data_present(void)
-{
- u32 bytes_out;
-
- /* We choose the recommended 1-byte-per-instruction RNG rate,
- * for greater randomness at the expense of speed. Larger
- * values 2, 4, or 8 bytes-per-instruction yield greater
- * speed at lesser randomness.
- *
- * If you change this to another VIA_CHUNK_n, you must also
- * change the ->n_bytes values in rng_vendor_ops[] tables.
- * VIA_CHUNK_8 requires further code changes.
- *
- * A copy of MSR_VIA_RNG is placed in eax_out when xstore
- * completes.
- */
- via_rng_datum = 0; /* paranoia, not really necessary */
- bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
- if (bytes_out == 0)
- return 0;
-
- return 1;
-}
-
-static u32 via_data_read(void)
-{
- return via_rng_datum;
-}
-
-static int __init via_init(struct pci_dev *dev)
-{
- u32 lo, hi, old_lo;
-
- /* Control the RNG via MSR. Tread lightly and pay very close
- * close attention to values written, as the reserved fields
- * are documented to be "undefined and unpredictable"; but it
- * does not say to write them as zero, so I make a guess that
- * we restore the values we find in the register.
- */
- rdmsr(MSR_VIA_RNG, lo, hi);
-
- old_lo = lo;
- lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
- lo &= ~VIA_XSTORE_CNT_MASK;
- lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
- lo |= VIA_RNG_ENABLE;
-
- if (lo != old_lo)
- wrmsr(MSR_VIA_RNG, lo, hi);
-
- /* perhaps-unnecessary sanity check; remove after testing if
- unneeded */
- rdmsr(MSR_VIA_RNG, lo, hi);
- if ((lo & VIA_RNG_ENABLE) == 0) {
- printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static void via_cleanup(void)
-{
- /* do nothing */
-}
-#endif
-
-/***********************************************************************
- *
- * AMD Geode RNG operations
- *
- */
-
-static void __iomem *geode_rng_base = NULL;
-
-#define GEODE_RNG_DATA_REG 0x50
-#define GEODE_RNG_STATUS_REG 0x54
-
-static u32 geode_data_read(void)
-{
- u32 val;
-
- assert(geode_rng_base != NULL);
- val = readl(geode_rng_base + GEODE_RNG_DATA_REG);
- return val;
-}
-
-static unsigned int geode_data_present(void)
-{
- u32 val;
-
- assert(geode_rng_base != NULL);
- val = readl(geode_rng_base + GEODE_RNG_STATUS_REG);
- return val;
-}
-
-static void geode_cleanup(void)
-{
- iounmap(geode_rng_base);
- geode_rng_base = NULL;
-}
-
-static int geode_init(struct pci_dev *dev)
-{
- unsigned long rng_base = pci_resource_start(dev, 0);
-
- if (rng_base == 0)
- return 1;
-
- geode_rng_base = ioremap(rng_base, 0x58);
-
- if (geode_rng_base == NULL) {
- printk(KERN_ERR PFX "Cannot ioremap RNG memory\n");
- return -EBUSY;
- }
-
- return 0;
-}
-
-/***********************************************************************
- *
- * /dev/hwrandom character device handling (major 10, minor 183)
- *
- */
-
-static int rng_dev_open (struct inode *inode, struct file *filp)
-{
- /* enforce read-only access to this chrdev */
- if ((filp->f_mode & FMODE_READ) == 0)
- return -EINVAL;
- if (filp->f_mode & FMODE_WRITE)
- return -EINVAL;
-
- return 0;
-}
-
-
-static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
- loff_t * offp)
-{
- static DEFINE_SPINLOCK(rng_lock);
- unsigned int have_data;
- u32 data = 0;
- ssize_t ret = 0;
-
- while (size) {
- spin_lock(&rng_lock);
-
- have_data = 0;
- if (rng_ops->data_present()) {
- data = rng_ops->data_read();
- have_data = rng_ops->n_bytes;
- }
-
- spin_unlock (&rng_lock);
-
- while (have_data && size) {
- if (put_user((u8)data, buf++)) {
- ret = ret ? : -EFAULT;
- break;
- }
- size--;
- ret++;
- have_data--;
- data>>=8;
- }
-
- if (filp->f_flags & O_NONBLOCK)
- return ret ? : -EAGAIN;
-
- if(need_resched())
- schedule_timeout_interruptible(1);
- else
- udelay(200); /* FIXME: We could poll for 250uS ?? */
-
- if (signal_pending (current))
- return ret ? : -ERESTARTSYS;
- }
- return ret;
-}
-
-
-
-/*
- * rng_init_one - look for and attempt to init a single RNG
- */
-static int __init rng_init_one (struct pci_dev *dev)
-{
- int rc;
-
- DPRINTK ("ENTER\n");
-
- assert(rng_ops != NULL);
-
- rc = rng_ops->init(dev);
- if (rc)
- goto err_out;
-
- rc = misc_register (&rng_miscdev);
- if (rc) {
- printk (KERN_ERR PFX "misc device register failed\n");
- goto err_out_cleanup_hw;
- }
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-
-err_out_cleanup_hw:
- rng_ops->cleanup();
-err_out:
- DPRINTK ("EXIT, returning %d\n", rc);
- return rc;
-}
-
-
-
-MODULE_AUTHOR("The Linux Kernel team");
-MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
-MODULE_LICENSE("GPL");
-
-
-/*
- * rng_init - initialize RNG module
- */
-static int __init rng_init (void)
-{
- int rc;
- struct pci_dev *pdev = NULL;
- const struct pci_device_id *ent;
-
- DPRINTK ("ENTER\n");
-
- /* Probe for Intel, AMD, Geode RNGs */
- for_each_pci_dev(pdev) {
- ent = pci_match_id(rng_pci_tbl, pdev);
- if (ent) {
- rng_ops = &rng_vendor_ops[ent->driver_data];
- goto match;
- }
- }
-
-#ifdef __i386__
- /* Probe for VIA RNG */
- if (cpu_has_xstore) {
- rng_ops = &rng_vendor_ops[rng_hw_via];
- pdev = NULL;
- goto match;
- }
-#endif
-
- DPRINTK ("EXIT, returning -ENODEV\n");
- return -ENODEV;
-
-match:
- rc = rng_init_one (pdev);
- if (rc)
- return rc;
-
- pr_info( RNG_DRIVER_NAME " loaded\n");
-
- DPRINTK ("EXIT, returning 0\n");
- return 0;
-}
-
-
-/*
- * rng_init - shutdown RNG module
- */
-static void __exit rng_cleanup (void)
-{
- DPRINTK ("ENTER\n");
-
- misc_deregister (&rng_miscdev);
-
- if (rng_ops->cleanup)
- rng_ops->cleanup();
-
- DPRINTK ("EXIT\n");
-}
-
-
-module_init (rng_init);
-module_exit (rng_cleanup);
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
new file mode 100644
index 00000000000..9f7635f7517
--- /dev/null
+++ b/drivers/char/hw_random/Kconfig
@@ -0,0 +1,90 @@
+#
+# Hardware Random Number Generator (RNG) configuration
+#
+
+config HW_RANDOM
+ bool "Hardware Random Number Generator Core support"
+ default y
+ ---help---
+ Hardware Random Number Generator Core infrastructure.
+
+ If unsure, say Y.
+
+config HW_RANDOM_INTEL
+ tristate "Intel HW Random Number Generator support"
+ depends on HW_RANDOM && (X86 || IA64) && PCI
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on Intel i8xx-based motherboards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called intel-rng.
+
+ If unsure, say Y.
+
+config HW_RANDOM_AMD
+ tristate "AMD HW Random Number Generator support"
+ depends on HW_RANDOM && X86 && PCI
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on AMD 76x-based motherboards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called amd-rng.
+
+ If unsure, say Y.
+
+config HW_RANDOM_GEODE
+ tristate "AMD Geode HW Random Number Generator support"
+ depends on HW_RANDOM && X86 && PCI
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on the AMD Geode LX.
+
+ To compile this driver as a module, choose M here: the
+ module will be called geode-rng.
+
+ If unsure, say Y.
+
+config HW_RANDOM_VIA
+ tristate "VIA HW Random Number Generator support"
+ depends on HW_RANDOM && X86_32
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on VIA based motherboards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called via-rng.
+
+ If unsure, say Y.
+
+config HW_RANDOM_IXP4XX
+ tristate "Intel IXP4xx NPU HW Random Number Generator support"
+ depends on HW_RANDOM && ARCH_IXP4XX
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random
+ Number Generator hardware found on the Intel IXP4xx NPU.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ixp4xx-rng.
+
+ If unsure, say Y.
+
+config HW_RANDOM_OMAP
+ tristate "OMAP Random Number Generator support"
+ depends on HW_RANDOM && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ default y
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on OMAP16xx and OMAP24xx multimedia
+ processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap-rng.
+
+ If unsure, say Y.
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
new file mode 100644
index 00000000000..e263ae96f94
--- /dev/null
+++ b/drivers/char/hw_random/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for HW Random Number Generator (RNG) device drivers.
+#
+
+obj-$(CONFIG_HW_RANDOM) += core.o
+obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o
+obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o
+obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o
+obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o
+obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
+obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
new file mode 100644
index 00000000000..71e4e0f3fd5
--- /dev/null
+++ b/drivers/char/hw_random/amd-rng.c
@@ -0,0 +1,152 @@
+/*
+ * RNG driver for AMD RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+
+
+#define PFX KBUILD_MODNAME ": "
+
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+ { 0x1022, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+ { 0x1022, 0x746b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+ { 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+static struct pci_dev *amd_pdev;
+
+
+static int amd_rng_data_present(struct hwrng *rng)
+{
+ u32 pmbase = (u32)rng->priv;
+
+ return !!(inl(pmbase + 0xF4) & 1);
+}
+
+static int amd_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ u32 pmbase = (u32)rng->priv;
+
+ *data = inl(pmbase + 0xF0);
+
+ return 4;
+}
+
+static int amd_rng_init(struct hwrng *rng)
+{
+ u8 rnen;
+
+ pci_read_config_byte(amd_pdev, 0x40, &rnen);
+ rnen |= (1 << 7); /* RNG on */
+ pci_write_config_byte(amd_pdev, 0x40, rnen);
+
+ pci_read_config_byte(amd_pdev, 0x41, &rnen);
+ rnen |= (1 << 7); /* PMIO enable */
+ pci_write_config_byte(amd_pdev, 0x41, rnen);
+
+ return 0;
+}
+
+static void amd_rng_cleanup(struct hwrng *rng)
+{
+ u8 rnen;
+
+ pci_read_config_byte(amd_pdev, 0x40, &rnen);
+ rnen &= ~(1 << 7); /* RNG off */
+ pci_write_config_byte(amd_pdev, 0x40, rnen);
+}
+
+
+static struct hwrng amd_rng = {
+ .name = "amd",
+ .init = amd_rng_init,
+ .cleanup = amd_rng_cleanup,
+ .data_present = amd_rng_data_present,
+ .data_read = amd_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+ int err = -ENODEV;
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *ent;
+ u32 pmbase;
+
+ for_each_pci_dev(pdev) {
+ ent = pci_match_id(pci_tbl, pdev);
+ if (ent)
+ goto found;
+ }
+ /* Device not found. */
+ goto out;
+
+found:
+ err = pci_read_config_dword(pdev, 0x58, &pmbase);
+ if (err)
+ goto out;
+ err = -EIO;
+ pmbase &= 0x0000FF00;
+ if (pmbase == 0)
+ goto out;
+ amd_rng.priv = (unsigned long)pmbase;
+ amd_pdev = pdev;
+
+ printk(KERN_INFO "AMD768 RNG detected\n");
+ err = hwrng_register(&amd_rng);
+ if (err) {
+ printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ err);
+ goto out;
+ }
+out:
+ return err;
+}
+
+static void __exit mod_exit(void)
+{
+ hwrng_unregister(&amd_rng);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("The Linux Kernel team");
+MODULE_DESCRIPTION("H/W RNG driver for AMD chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
new file mode 100644
index 00000000000..154a81d328c
--- /dev/null
+++ b/drivers/char/hw_random/core.c
@@ -0,0 +1,354 @@
+/*
+ Added support for the AMD Geode LX RNG
+ (c) Copyright 2004-2005 Advanced Micro Devices, Inc.
+
+ derived from
+
+ Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+
+ derived from
+
+ Hardware driver for the AMD 768 Random Number Generator (RNG)
+ (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+
+ derived from
+
+ Hardware driver for Intel i810 Random Number Generator (RNG)
+ Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+
+ Added generic RNG API
+ Copyright 2006 Michael Buesch <mbuesch@freenet.de>
+ Copyright 2005 (c) MontaVista Software, Inc.
+
+ Please read Documentation/hw_random.txt for details on use.
+
+ ----------------------------------------------------------
+ This software may be used and distributed according to the terms
+ of the GNU General Public License, incorporated herein by reference.
+
+ */
+
+
+#include <linux/device.h>
+#include <linux/hw_random.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/miscdevice.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+
+#define RNG_MODULE_NAME "hw_random"
+#define PFX RNG_MODULE_NAME ": "
+#define RNG_MISCDEV_MINOR 183 /* official */
+
+
+static struct hwrng *current_rng;
+static LIST_HEAD(rng_list);
+static DEFINE_MUTEX(rng_mutex);
+
+
+static inline int hwrng_init(struct hwrng *rng)
+{
+ if (!rng->init)
+ return 0;
+ return rng->init(rng);
+}
+
+static inline void hwrng_cleanup(struct hwrng *rng)
+{
+ if (rng && rng->cleanup)
+ rng->cleanup(rng);
+}
+
+static inline int hwrng_data_present(struct hwrng *rng)
+{
+ if (!rng->data_present)
+ return 1;
+ return rng->data_present(rng);
+}
+
+static inline int hwrng_data_read(struct hwrng *rng, u32 *data)
+{
+ return rng->data_read(rng, data);
+}
+
+
+static int rng_dev_open(struct inode *inode, struct file *filp)
+{
+ /* enforce read-only access to this chrdev */
+ if ((filp->f_mode & FMODE_READ) == 0)
+ return -EINVAL;
+ if (filp->f_mode & FMODE_WRITE)
+ return -EINVAL;
+ return 0;
+}
+
+static ssize_t rng_dev_read(struct file *filp, char __user *buf,
+ size_t size, loff_t *offp)
+{
+ u32 data;
+ ssize_t ret = 0;
+ int i, err = 0;
+ int data_present;
+ int bytes_read;
+
+ while (size) {
+ err = -ERESTARTSYS;
+ if (mutex_lock_interruptible(&rng_mutex))
+ goto out;
+ if (!current_rng) {
+ mutex_unlock(&rng_mutex);
+ err = -ENODEV;
+ goto out;
+ }
+ if (filp->f_flags & O_NONBLOCK) {
+ data_present = hwrng_data_present(current_rng);
+ } else {
+ /* Some RNG require some time between data_reads to gather
+ * new entropy. Poll it.
+ */
+ for (i = 0; i < 20; i++) {
+ data_present = hwrng_data_present(current_rng);
+ if (data_present)
+ break;
+ udelay(10);
+ }
+ }
+ bytes_read = 0;
+ if (data_present)
+ bytes_read = hwrng_data_read(current_rng, &data);
+ mutex_unlock(&rng_mutex);
+
+ err = -EAGAIN;
+ if (!bytes_read && (filp->f_flags & O_NONBLOCK))
+ goto out;
+
+ err = -EFAULT;
+ while (bytes_read && size) {
+ if (put_user((u8)data, buf++))
+ goto out;
+ size--;
+ ret++;
+ bytes_read--;
+ data >>= 8;
+ }
+
+ if (need_resched())
+ schedule_timeout_interruptible(1);
+ err = -ERESTARTSYS;
+ if (signal_pending(current))
+ goto out;
+ }
+out:
+ return ret ? : err;
+}
+
+
+static const struct file_operations rng_chrdev_ops = {
+ .owner = THIS_MODULE,
+ .open = rng_dev_open,
+ .read = rng_dev_read,
+};
+
+static struct miscdevice rng_miscdev = {
+ .minor = RNG_MISCDEV_MINOR,
+ .name = RNG_MODULE_NAME,
+ .fops = &rng_chrdev_ops,
+};
+
+
+static ssize_t hwrng_attr_current_store(struct class_device *class,
+ const char *buf, size_t len)
+{
+ int err;
+ struct hwrng *rng;
+
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return -ERESTARTSYS;
+ err = -ENODEV;
+ list_for_each_entry(rng, &rng_list, list) {
+ if (strcmp(rng->name, buf) == 0) {
+ if (rng == current_rng) {
+ err = 0;
+ break;
+ }
+ err = hwrng_init(rng);
+ if (err)
+ break;
+ hwrng_cleanup(current_rng);
+ current_rng = rng;
+ err = 0;
+ break;
+ }
+ }
+ mutex_unlock(&rng_mutex);
+
+ return err ? : len;
+}
+
+static ssize_t hwrng_attr_current_show(struct class_device *class,
+ char *buf)
+{
+ int err;
+ ssize_t ret;
+ const char *name = "none";
+
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return -ERESTARTSYS;
+ if (current_rng)
+ name = current_rng->name;
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
+ mutex_unlock(&rng_mutex);
+
+ return ret;
+}
+
+static ssize_t hwrng_attr_available_show(struct class_device *class,
+ char *buf)
+{
+ int err;
+ ssize_t ret = 0;
+ struct hwrng *rng;
+
+ err = mutex_lock_interruptible(&rng_mutex);
+ if (err)
+ return -ERESTARTSYS;
+ buf[0] = '\0';
+ list_for_each_entry(rng, &rng_list, list) {
+ strncat(buf, rng->name, PAGE_SIZE - ret - 1);
+ ret += strlen(rng->name);
+ strncat(buf, " ", PAGE_SIZE - ret - 1);
+ ret++;
+ }
+ strncat(buf, "\n", PAGE_SIZE - ret - 1);
+ ret++;
+ mutex_unlock(&rng_mutex);
+
+ return ret;
+}
+
+static CLASS_DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR,
+ hwrng_attr_current_show,
+ hwrng_attr_current_store);
+static CLASS_DEVICE_ATTR(rng_available, S_IRUGO,
+ hwrng_attr_available_show,
+ NULL);
+
+
+static void unregister_miscdev(void)
+{
+ class_device_remove_file(rng_miscdev.class,
+ &class_device_attr_rng_available);
+ class_device_remove_file(rng_miscdev.class,
+ &class_device_attr_rng_current);
+ misc_deregister(&rng_miscdev);
+}
+
+static int register_miscdev(void)
+{
+ int err;
+
+ err = misc_register(&rng_miscdev);
+ if (err)
+ goto out;
+ err = class_device_create_file(rng_miscdev.class,
+ &class_device_attr_rng_current);
+ if (err)
+ goto err_misc_dereg;
+ err = class_device_create_file(rng_miscdev.class,
+ &class_device_attr_rng_available);
+ if (err)
+ goto err_remove_current;
+out:
+ return err;
+
+err_remove_current:
+ class_device_remove_file(rng_miscdev.class,
+ &class_device_attr_rng_current);
+err_misc_dereg:
+ misc_deregister(&rng_miscdev);
+ goto out;
+}
+
+int hwrng_register(struct hwrng *rng)
+{
+ int must_register_misc;
+ int err = -EINVAL;
+ struct hwrng *old_rng, *tmp;
+
+ if (rng->name == NULL ||
+ rng->data_read == NULL)
+ goto out;
+
+ mutex_lock(&rng_mutex);
+
+ /* Must not register two RNGs with the same name. */
+ err = -EEXIST;
+ list_for_each_entry(tmp, &rng_list, list) {
+ if (strcmp(tmp->name, rng->name) == 0)
+ goto out_unlock;
+ }
+
+ must_register_misc = (current_rng == NULL);
+ old_rng = current_rng;
+ if (!old_rng) {
+ err = hwrng_init(rng);
+ if (err)
+ goto out_unlock;
+ current_rng = rng;
+ }
+ err = 0;
+ if (must_register_misc) {
+ err = register_miscdev();
+ if (err) {
+ if (!old_rng) {
+ hwrng_cleanup(rng);
+ current_rng = NULL;
+ }
+ goto out_unlock;
+ }
+ }
+ INIT_LIST_HEAD(&rng->list);
+ list_add_tail(&rng->list, &rng_list);
+out_unlock:
+ mutex_unlock(&rng_mutex);
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(hwrng_register);
+
+void hwrng_unregister(struct hwrng *rng)
+{
+ int err;
+
+ mutex_lock(&rng_mutex);
+
+ list_del(&rng->list);
+ if (current_rng == rng) {
+ hwrng_cleanup(rng);
+ if (list_empty(&rng_list)) {
+ current_rng = NULL;
+ } else {
+ current_rng = list_entry(rng_list.prev, struct hwrng, list);
+ err = hwrng_init(current_rng);
+ if (err)
+ current_rng = NULL;
+ }
+ }
+ if (list_empty(&rng_list))
+ unregister_miscdev();
+
+ mutex_unlock(&rng_mutex);
+}
+EXPORT_SYMBOL_GPL(hwrng_unregister);
+
+
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c
new file mode 100644
index 00000000000..d37ced0d132
--- /dev/null
+++ b/drivers/char/hw_random/geode-rng.c
@@ -0,0 +1,132 @@
+/*
+ * RNG driver for AMD Geode RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+
+
+#define PFX KBUILD_MODNAME ": "
+
+#define GEODE_RNG_DATA_REG 0x50
+#define GEODE_RNG_STATUS_REG 0x54
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LX_AES,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+ { 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+
+static int geode_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ void __iomem *mem = (void __iomem *)rng->priv;
+
+ *data = readl(mem + GEODE_RNG_DATA_REG);
+
+ return 4;
+}
+
+static int geode_rng_data_present(struct hwrng *rng)
+{
+ void __iomem *mem = (void __iomem *)rng->priv;
+
+ return !!(readl(mem + GEODE_RNG_STATUS_REG));
+}
+
+
+static struct hwrng geode_rng = {
+ .name = "geode",
+ .data_present = geode_rng_data_present,
+ .data_read = geode_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+ int err = -ENODEV;
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *ent;
+ void __iomem *mem;
+ unsigned long rng_base;
+
+ for_each_pci_dev(pdev) {
+ ent = pci_match_id(pci_tbl, pdev);
+ if (ent)
+ goto found;
+ }
+ /* Device not found. */
+ goto out;
+
+found:
+ rng_base = pci_resource_start(pdev, 0);
+ if (rng_base == 0)
+ goto out;
+ err = -ENOMEM;
+ mem = ioremap(rng_base, 0x58);
+ if (!mem)
+ goto out;
+ geode_rng.priv = (unsigned long)mem;
+
+ printk(KERN_INFO "AMD Geode RNG detected\n");
+ err = hwrng_register(&geode_rng);
+ if (err) {
+ printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ err);
+ goto err_unmap;
+ }
+out:
+ return err;
+
+err_unmap:
+ iounmap(mem);
+ goto out;
+}
+
+static void __exit mod_exit(void)
+{
+ void __iomem *mem = (void __iomem *)geode_rng.priv;
+
+ hwrng_unregister(&geode_rng);
+ iounmap(mem);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
new file mode 100644
index 00000000000..8efbc9c0e54
--- /dev/null
+++ b/drivers/char/hw_random/intel-rng.c
@@ -0,0 +1,357 @@
+/*
+ * RNG driver for Intel RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+
+
+#define PFX KBUILD_MODNAME ": "
+
+/*
+ * RNG registers
+ */
+#define INTEL_RNG_HW_STATUS 0
+#define INTEL_RNG_PRESENT 0x40
+#define INTEL_RNG_ENABLED 0x01
+#define INTEL_RNG_STATUS 1
+#define INTEL_RNG_DATA_PRESENT 0x01
+#define INTEL_RNG_DATA 2
+
+/*
+ * Magic address at which Intel PCI bridges locate the RNG
+ */
+#define INTEL_RNG_ADDR 0xFFBC015F
+#define INTEL_RNG_ADDR_LEN 3
+
+/*
+ * LPC bridge PCI config space registers
+ */
+#define FWH_DEC_EN1_REG_OLD 0xe3
+#define FWH_DEC_EN1_REG_NEW 0xd9 /* high byte of 16-bit register */
+#define FWH_F8_EN_MASK 0x80
+
+#define BIOS_CNTL_REG_OLD 0x4e
+#define BIOS_CNTL_REG_NEW 0xdc
+#define BIOS_CNTL_WRITE_ENABLE_MASK 0x01
+#define BIOS_CNTL_LOCK_ENABLE_MASK 0x02
+
+/*
+ * Magic address at which Intel Firmware Hubs get accessed
+ */
+#define INTEL_FWH_ADDR 0xffff0000
+#define INTEL_FWH_ADDR_LEN 2
+
+/*
+ * Intel Firmware Hub command codes (write to any address inside the device)
+ */
+#define INTEL_FWH_RESET_CMD 0xff /* aka READ_ARRAY */
+#define INTEL_FWH_READ_ID_CMD 0x90
+
+/*
+ * Intel Firmware Hub Read ID command result addresses
+ */
+#define INTEL_FWH_MANUFACTURER_CODE_ADDRESS 0x000000
+#define INTEL_FWH_DEVICE_CODE_ADDRESS 0x000001
+
+/*
+ * Intel Firmware Hub Read ID command result values
+ */
+#define INTEL_FWH_MANUFACTURER_CODE 0x89
+#define INTEL_FWH_DEVICE_CODE_8M 0xac
+#define INTEL_FWH_DEVICE_CODE_4M 0xad
+
+/*
+ * Data for PCI driver interface
+ *
+ * This data only exists for exporting the supported
+ * PCI ids via MODULE_DEVICE_TABLE. We do not actually
+ * register a pci_driver, because someone else might one day
+ * want to register another driver on the same PCI id.
+ */
+static const struct pci_device_id pci_tbl[] = {
+/* AA
+ { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */
+/* AB
+ { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */
+/* ??
+ { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+/* BAM, CAM, DBM, FBM, GxM
+ { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */
+ { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */
+ { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */
+ { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */
+ { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */
+ { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */
+/* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx
+ { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */
+ { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */
+ { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */
+ { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */
+ { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */
+ { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */
+ { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */
+/* E
+ { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E */
+ { 0, }, /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, pci_tbl);
+
+
+static inline u8 hwstatus_get(void __iomem *mem)
+{
+ return readb(mem + INTEL_RNG_HW_STATUS);
+}
+
+static inline u8 hwstatus_set(void __iomem *mem,
+ u8 hw_status)
+{
+ writeb(hw_status, mem + INTEL_RNG_HW_STATUS);
+ return hwstatus_get(mem);
+}
+
+static int intel_rng_data_present(struct hwrng *rng)
+{
+ void __iomem *mem = (void __iomem *)rng->priv;
+
+ return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT);
+}
+
+static int intel_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ void __iomem *mem = (void __iomem *)rng->priv;
+
+ *data = readb(mem + INTEL_RNG_DATA);
+
+ return 1;
+}
+
+static int intel_rng_init(struct hwrng *rng)
+{
+ void __iomem *mem = (void __iomem *)rng->priv;
+ u8 hw_status;
+ int err = -EIO;
+
+ hw_status = hwstatus_get(mem);
+ /* turn RNG h/w on, if it's off */
+ if ((hw_status & INTEL_RNG_ENABLED) == 0)
+ hw_status = hwstatus_set(mem, hw_status | INTEL_RNG_ENABLED);
+ if ((hw_status & INTEL_RNG_ENABLED) == 0) {
+ printk(KERN_ERR PFX "cannot enable RNG, aborting\n");
+ goto out;
+ }
+ err = 0;
+out:
+ return err;
+}
+
+static void intel_rng_cleanup(struct hwrng *rng)
+{
+ void __iomem *mem = (void __iomem *)rng->priv;
+ u8 hw_status;
+
+ hw_status = hwstatus_get(mem);
+ if (hw_status & INTEL_RNG_ENABLED)
+ hwstatus_set(mem, hw_status & ~INTEL_RNG_ENABLED);
+ else
+ printk(KERN_WARNING PFX "unusual: RNG already disabled\n");
+}
+
+
+static struct hwrng intel_rng = {
+ .name = "intel",
+ .init = intel_rng_init,
+ .cleanup = intel_rng_cleanup,
+ .data_present = intel_rng_data_present,
+ .data_read = intel_rng_data_read,
+};
+
+
+#ifdef CONFIG_SMP
+static char __initdata waitflag;
+
+static void __init intel_init_wait(void *unused)
+{
+ while (waitflag)
+ cpu_relax();
+}
+#endif
+
+static int __init mod_init(void)
+{
+ int err = -ENODEV;
+ unsigned i;
+ struct pci_dev *dev = NULL;
+ void __iomem *mem;
+ unsigned long flags;
+ u8 bios_cntl_off, fwh_dec_en1_off;
+ u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
+ u8 hw_status, mfc, dvc;
+
+ for (i = 0; !dev && pci_tbl[i].vendor; ++i)
+ dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
+
+ if (!dev)
+ goto out; /* Device not found. */
+
+ /* Check for Intel 82802 */
+ if (dev->device < 0x2640) {
+ fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
+ bios_cntl_off = BIOS_CNTL_REG_OLD;
+ } else {
+ fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
+ bios_cntl_off = BIOS_CNTL_REG_NEW;
+ }
+
+ pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
+ pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
+
+ mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
+ if (mem == NULL) {
+ pci_dev_put(dev);
+ err = -EBUSY;
+ goto out;
+ }
+
+ /*
+ * Since the BIOS code/data is going to disappear from its normal
+ * location with the Read ID command, all activity on the system
+ * must be stopped until the state is back to normal.
+ */
+#ifdef CONFIG_SMP
+ set_mb(waitflag, 1);
+ if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
+ set_mb(waitflag, 0);
+ pci_dev_put(dev);
+ printk(KERN_ERR PFX "cannot run on all processors\n");
+ err = -EAGAIN;
+ goto err_unmap;
+ }
+#endif
+ local_irq_save(flags);
+
+ if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(dev,
+ fwh_dec_en1_off,
+ fwh_dec_en1_val | FWH_F8_EN_MASK);
+ if (!(bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+ pci_write_config_byte(dev,
+ bios_cntl_off,
+ bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
+
+ writeb(INTEL_FWH_RESET_CMD, mem);
+ writeb(INTEL_FWH_READ_ID_CMD, mem);
+ mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
+ dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
+ writeb(INTEL_FWH_RESET_CMD, mem);
+
+ if (!(bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+ pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
+ if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
+
+ local_irq_restore(flags);
+#ifdef CONFIG_SMP
+ /* Tell other CPUs to resume. */
+ set_mb(waitflag, 0);
+#endif
+
+ iounmap(mem);
+ pci_dev_put(dev);
+
+ if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
+ (dvc != INTEL_FWH_DEVICE_CODE_8M &&
+ dvc != INTEL_FWH_DEVICE_CODE_4M)) {
+ printk(KERN_ERR PFX "FWH not detected\n");
+ err = -ENODEV;
+ goto out;
+ }
+
+ err = -ENOMEM;
+ mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
+ if (!mem)
+ goto out;
+ intel_rng.priv = (unsigned long)mem;
+
+ /* Check for Random Number Generator */
+ err = -ENODEV;
+ hw_status = hwstatus_get(mem);
+ if ((hw_status & INTEL_RNG_PRESENT) == 0)
+ goto err_unmap;
+
+ printk(KERN_INFO "Intel 82802 RNG detected\n");
+ err = hwrng_register(&intel_rng);
+ if (err) {
+ printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ err);
+ goto err_unmap;
+ }
+out:
+ return err;
+
+err_unmap:
+ iounmap(mem);
+ goto out;
+}
+
+static void __exit mod_exit(void)
+{
+ void __iomem *mem = (void __iomem *)intel_rng.priv;
+
+ hwrng_unregister(&intel_rng);
+ iounmap(mem);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
new file mode 100644
index 00000000000..ef71022423c
--- /dev/null
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -0,0 +1,73 @@
+/*
+ * drivers/char/rng/ixp4xx-rng.c
+ *
+ * RNG driver for Intel IXP4xx family of NPUs
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Fixes by Michael Buesch
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/hw_random.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+
+
+static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+ void __iomem * rng_base = (void __iomem *)rng->priv;
+
+ *buffer = __raw_readl(rng_base);
+
+ return 4;
+}
+
+static struct hwrng ixp4xx_rng_ops = {
+ .name = "ixp4xx",
+ .data_read = ixp4xx_rng_data_read,
+};
+
+static int __init ixp4xx_rng_init(void)
+{
+ void __iomem * rng_base;
+ int err;
+
+ rng_base = ioremap(0x70002100, 4);
+ if (!rng_base)
+ return -ENOMEM;
+ ixp4xx_rng_ops.priv = (unsigned long)rng_base;
+ err = hwrng_register(&ixp4xx_rng_ops);
+ if (err)
+ iounmap(rng_base);
+
+ return err;
+}
+
+static void __exit ixp4xx_rng_exit(void)
+{
+ void __iomem * rng_base = (void __iomem *)ixp4xx_rng_ops.priv;
+
+ hwrng_unregister(&ixp4xx_rng_ops);
+ iounmap(rng_base);
+}
+
+subsys_initcall(ixp4xx_rng_init);
+module_exit(ixp4xx_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for IXP4xx");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
new file mode 100644
index 00000000000..a01d796d1ee
--- /dev/null
+++ b/drivers/char/hw_random/omap-rng.c
@@ -0,0 +1,205 @@
+/*
+ * driver/char/hw_random/omap-rng.c
+ *
+ * RNG driver for TI OMAP CPU family
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * Mostly based on original driver:
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Juha Yrj��<juha.yrjola@nokia.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ *
+ * TODO:
+ *
+ * - Make status updated be interrupt driven so we don't poll
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/random.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+
+#include <asm/io.h>
+
+#define RNG_OUT_REG 0x00 /* Output register */
+#define RNG_STAT_REG 0x04 /* Status register
+ [0] = STAT_BUSY */
+#define RNG_ALARM_REG 0x24 /* Alarm register
+ [7:0] = ALARM_COUNTER */
+#define RNG_CONFIG_REG 0x28 /* Configuration register
+ [11:6] = RESET_COUNT
+ [5:3] = RING2_DELAY
+ [2:0] = RING1_DELAY */
+#define RNG_REV_REG 0x3c /* Revision register
+ [7:0] = REV_NB */
+#define RNG_MASK_REG 0x40 /* Mask and reset register
+ [2] = IT_EN
+ [1] = SOFTRESET
+ [0] = AUTOIDLE */
+#define RNG_SYSSTATUS 0x44 /* System status
+ [0] = RESETDONE */
+
+static void __iomem *rng_base;
+static struct clk *rng_ick;
+static struct platform_device *rng_dev;
+
+static u32 omap_rng_read_reg(int reg)
+{
+ return __raw_readl(rng_base + reg);
+}
+
+static void omap_rng_write_reg(int reg, u32 val)
+{
+ __raw_writel(val, rng_base + reg);
+}
+
+/* REVISIT: Does the status bit really work on 16xx? */
+static int omap_rng_data_present(struct hwrng *rng)
+{
+ return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1;
+}
+
+static int omap_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ *data = omap_rng_read_reg(RNG_OUT_REG);
+
+ return 4;
+}
+
+static struct hwrng omap_rng_ops = {
+ .name = "omap",
+ .data_present = omap_rng_data_present,
+ .data_read = omap_rng_data_read,
+};
+
+static int __init omap_rng_probe(struct platform_device *pdev)
+{
+ struct resource *res, *mem;
+ int ret;
+
+ /*
+ * A bit ugly, and it will never actually happen but there can
+ * be only one RNG and this catches any bork
+ */
+ BUG_ON(rng_dev);
+
+ if (cpu_is_omap24xx()) {
+ rng_ick = clk_get(NULL, "rng_ick");
+ if (IS_ERR(rng_ick)) {
+ dev_err(&pdev->dev, "Could not get rng_ick\n");
+ ret = PTR_ERR(rng_ick);
+ return ret;
+ } else
+ clk_enable(rng_ick);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ if (!res)
+ return -ENOENT;
+
+ mem = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (mem == NULL)
+ return -EBUSY;
+
+ dev_set_drvdata(&pdev->dev, mem);
+ rng_base = (u32 __iomem *)io_p2v(res->start);
+
+ ret = hwrng_register(&omap_rng_ops);
+ if (ret) {
+ release_resource(mem);
+ rng_base = NULL;
+ return ret;
+ }
+
+ dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n",
+ omap_rng_read_reg(RNG_REV_REG));
+ omap_rng_write_reg(RNG_MASK_REG, 0x1);
+
+ rng_dev = pdev;
+
+ return 0;
+}
+
+static int __exit omap_rng_remove(struct platform_device *pdev)
+{
+ struct resource *mem = dev_get_drvdata(&pdev->dev);
+
+ hwrng_unregister(&omap_rng_ops);
+
+ omap_rng_write_reg(RNG_MASK_REG, 0x0);
+
+ if (cpu_is_omap24xx()) {
+ clk_disable(rng_ick);
+ clk_put(rng_ick);
+ }
+
+ release_resource(mem);
+ rng_base = NULL;
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int omap_rng_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ omap_rng_write_reg(RNG_MASK_REG, 0x0);
+ return 0;
+}
+
+static int omap_rng_resume(struct platform_device *pdev)
+{
+ omap_rng_write_reg(RNG_MASK_REG, 0x1);
+ return 0;
+}
+
+#else
+
+#define omap_rng_suspend NULL
+#define omap_rng_resume NULL
+
+#endif
+
+
+static struct platform_driver omap_rng_driver = {
+ .driver = {
+ .name = "omap_rng",
+ .owner = THIS_MODULE,
+ },
+ .probe = omap_rng_probe,
+ .remove = __exit_p(omap_rng_remove),
+ .suspend = omap_rng_suspend,
+ .resume = omap_rng_resume
+};
+
+static int __init omap_rng_init(void)
+{
+ if (!cpu_is_omap16xx() && !cpu_is_omap24xx())
+ return -ENODEV;
+
+ return platform_driver_register(&omap_rng_driver);
+}
+
+static void __exit omap_rng_exit(void)
+{
+ platform_driver_unregister(&omap_rng_driver);
+}
+
+module_init(omap_rng_init);
+module_exit(omap_rng_exit);
+
+MODULE_AUTHOR("Deepak Saxena (and others)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
new file mode 100644
index 00000000000..0e786b617bb
--- /dev/null
+++ b/drivers/char/hw_random/via-rng.c
@@ -0,0 +1,183 @@
+/*
+ * RNG driver for VIA RNGs
+ *
+ * Copyright 2005 (c) MontaVista Software, Inc.
+ *
+ * with the majority of the code coming from:
+ *
+ * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
+ * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for the AMD 768 Random Number Generator (RNG)
+ * (c) Copyright 2001 Red Hat Inc <alan@redhat.com>
+ *
+ * derived from
+ *
+ * Hardware driver for Intel i810 Random Number Generator (RNG)
+ * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
+ * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/hw_random.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+
+
+#define PFX KBUILD_MODNAME ": "
+
+
+enum {
+ VIA_STRFILT_CNT_SHIFT = 16,
+ VIA_STRFILT_FAIL = (1 << 15),
+ VIA_STRFILT_ENABLE = (1 << 14),
+ VIA_RAWBITS_ENABLE = (1 << 13),
+ VIA_RNG_ENABLE = (1 << 6),
+ VIA_XSTORE_CNT_MASK = 0x0F,
+
+ VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */
+ VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */
+ VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF,
+ VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */
+ VIA_RNG_CHUNK_2_MASK = 0xFFFF,
+ VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */
+ VIA_RNG_CHUNK_1_MASK = 0xFF,
+};
+
+/*
+ * Investigate using the 'rep' prefix to obtain 32 bits of random data
+ * in one insn. The upside is potentially better performance. The
+ * downside is that the instruction becomes no longer atomic. Due to
+ * this, just like familiar issues with /dev/random itself, the worst
+ * case of a 'rep xstore' could potentially pause a cpu for an
+ * unreasonably long time. In practice, this condition would likely
+ * only occur when the hardware is failing. (or so we hope :))
+ *
+ * Another possible performance boost may come from simply buffering
+ * until we have 4 bytes, thus returning a u32 at a time,
+ * instead of the current u8-at-a-time.
+ */
+
+static inline u32 xstore(u32 *addr, u32 edx_in)
+{
+ u32 eax_out;
+
+ asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
+ :"=m"(*addr), "=a"(eax_out)
+ :"D"(addr), "d"(edx_in));
+
+ return eax_out;
+}
+
+static int via_rng_data_present(struct hwrng *rng)
+{
+ u32 bytes_out;
+ u32 *via_rng_datum = (u32 *)(&rng->priv);
+
+ /* We choose the recommended 1-byte-per-instruction RNG rate,
+ * for greater randomness at the expense of speed. Larger
+ * values 2, 4, or 8 bytes-per-instruction yield greater
+ * speed at lesser randomness.
+ *
+ * If you change this to another VIA_CHUNK_n, you must also
+ * change the ->n_bytes values in rng_vendor_ops[] tables.
+ * VIA_CHUNK_8 requires further code changes.
+ *
+ * A copy of MSR_VIA_RNG is placed in eax_out when xstore
+ * completes.
+ */
+
+ *via_rng_datum = 0; /* paranoia, not really necessary */
+ bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
+ bytes_out &= VIA_XSTORE_CNT_MASK;
+ if (bytes_out == 0)
+ return 0;
+ return 1;
+}
+
+static int via_rng_data_read(struct hwrng *rng, u32 *data)
+{
+ u32 via_rng_datum = (u32)rng->priv;
+
+ *data = via_rng_datum;
+
+ return 1;
+}
+
+static int via_rng_init(struct hwrng *rng)
+{
+ u32 lo, hi, old_lo;
+
+ /* Control the RNG via MSR. Tread lightly and pay very close
+ * close attention to values written, as the reserved fields
+ * are documented to be "undefined and unpredictable"; but it
+ * does not say to write them as zero, so I make a guess that
+ * we restore the values we find in the register.
+ */
+ rdmsr(MSR_VIA_RNG, lo, hi);
+
+ old_lo = lo;
+ lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
+ lo &= ~VIA_XSTORE_CNT_MASK;
+ lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
+ lo |= VIA_RNG_ENABLE;
+
+ if (lo != old_lo)
+ wrmsr(MSR_VIA_RNG, lo, hi);
+
+ /* perhaps-unnecessary sanity check; remove after testing if
+ unneeded */
+ rdmsr(MSR_VIA_RNG, lo, hi);
+ if ((lo & VIA_RNG_ENABLE) == 0) {
+ printk(KERN_ERR PFX "cannot enable VIA C3 RNG, aborting\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+
+static struct hwrng via_rng = {
+ .name = "via",
+ .init = via_rng_init,
+ .data_present = via_rng_data_present,
+ .data_read = via_rng_data_read,
+};
+
+
+static int __init mod_init(void)
+{
+ int err;
+
+ if (!cpu_has_xstore)
+ return -ENODEV;
+ printk(KERN_INFO "VIA RNG detected\n");
+ err = hwrng_register(&via_rng);
+ if (err) {
+ printk(KERN_ERR PFX "RNG registering failed (%d)\n",
+ err);
+ goto out;
+ }
+out:
+ return err;
+}
+
+static void __exit mod_exit(void)
+{
+ hwrng_unregister(&via_rng);
+}
+
+subsys_initcall(mod_init);
+module_exit(mod_exit);
+
+MODULE_DESCRIPTION("H/W RNG driver for VIA chipsets");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index f3c3aaf4560..353d9f3cf8d 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -80,7 +80,7 @@ static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
-static struct file_operations i8k_fops = {
+static const struct file_operations i8k_fops = {
.open = i8k_open_fs,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index 510b026d7d2..5eabe47b0bc 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -47,7 +47,6 @@
//----------------------
// Mandatory Includes:
//----------------------
-#include <linux/config.h>
#include "ip2types.h"
#include "i2hw.h" // The hardware definitions
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 03db1cb3fa9..7907ae88c2f 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -82,7 +82,6 @@
/************/
/* Includes */
/************/
-#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/string.h>
@@ -91,7 +90,6 @@
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
@@ -235,7 +233,7 @@ static void *DevTableMem[IP2_MAX_BOARDS];
/* This is the driver descriptor for the ip2ipl device, which is used to
* download the loadware to the boards.
*/
-static struct file_operations ip2_ipl = {
+static const struct file_operations ip2_ipl = {
.owner = THIS_MODULE,
.read = ip2_ipl_read,
.write = ip2_ipl_write,
@@ -305,7 +303,7 @@ static struct class *ip2_class;
// Some functions to keep track of what irq's we have
-static int __init
+static int
is_valid_irq(int irq)
{
int *i = Valid_Irqs;
@@ -316,14 +314,14 @@ is_valid_irq(int irq)
return (*i);
}
-static void __init
+static void
mark_requested_irq( char irq )
{
rirqs[iindx++] = irq;
}
#ifdef MODULE
-static int __init
+static int
clear_requested_irq( char irq )
{
int i;
@@ -337,7 +335,7 @@ clear_requested_irq( char irq )
}
#endif
-static int __init
+static int
have_requested_irq( char irq )
{
// array init to zeros so 0 irq will not be requested as a side effect
@@ -414,9 +412,7 @@ cleanup_module(void)
/* free io addresses and Tibet */
release_region( ip2config.addr[i], 8 );
class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i));
- devfs_remove("ip2/ipl%d", i);
class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
- devfs_remove("ip2/stat%d", i);
}
/* Disable and remove interrupt handler. */
if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) {
@@ -425,7 +421,6 @@ cleanup_module(void)
}
}
class_destroy(ip2_class);
- devfs_remove("ip2");
if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) {
printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err);
}
@@ -496,8 +491,8 @@ static struct tty_operations ip2_ops = {
/* initialisation of the devices and driver structures, and registers itself */
/* with the relevant kernel modules. */
/******************************************************************************/
-/* SA_INTERRUPT- if set blocks all interrupts else only this line */
-/* SA_SHIRQ - for shared irq PCI or maybe EISA only */
+/* IRQF_DISABLED - if set blocks all interrupts else only this line */
+/* IRQF_SHARED - for shared irq PCI or maybe EISA only */
/* SA_RANDOM - can be source for cert. random number generators */
#define IP2_SA_FLAGS 0
@@ -675,7 +670,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
ip2_tty_driver->owner = THIS_MODULE;
ip2_tty_driver->name = "ttyF";
- ip2_tty_driver->devfs_name = "tts/F";
ip2_tty_driver->driver_name = pcDriver_name;
ip2_tty_driver->major = IP2_TTY_MAJOR;
ip2_tty_driver->minor_start = 0;
@@ -683,7 +677,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL;
ip2_tty_driver->init_termios = tty_std_termios;
ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
- ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(ip2_tty_driver, &ip2_ops);
ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 );
@@ -724,26 +718,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
class_device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i),
NULL, "ipl%d", i);
- err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i),
- S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
- "ip2/ipl%d", i);
- if (err) {
- class_device_destroy(ip2_class,
- MKDEV(IP2_IPL_MAJOR, 4 * i));
- goto out_class;
- }
-
class_device_create(ip2_class, NULL,
MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
NULL, "stat%d", i);
- err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
- S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
- "ip2/stat%d", i);
- if (err) {
- class_device_destroy(ip2_class,
- MKDEV(IP2_IPL_MAJOR, 4 * i + 1));
- goto out_class;
- }
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
@@ -776,7 +753,7 @@ retry:
if (have_requested_irq(ip2config.irq[i]))
continue;
rc = request_irq( ip2config.irq[i], ip2_interrupt,
- IP2_SA_FLAGS | (ip2config.type[i] == PCI ? SA_SHIRQ : 0),
+ IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0),
pcName, (void *)&pcName);
if (rc) {
printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc);
@@ -818,7 +795,7 @@ EXPORT_SYMBOL(ip2_loadmain);
/* the board, the channel structures are initialized, and the board details */
/* are reported on the console. */
/******************************************************************************/
-static void __init
+static void
ip2_init_board( int boardnum )
{
int i;
@@ -961,7 +938,7 @@ err_initialize:
/* EISA motherboard, or no valid board ID is selected it returns 0. Otherwise */
/* it returns the base address of the controller. */
/******************************************************************************/
-static unsigned short __init
+static unsigned short
find_eisa_board( int start_slot )
{
int i, j;
@@ -3209,3 +3186,10 @@ ip2trace (unsigned short pn, unsigned char cat, unsigned char label, unsigned lo
MODULE_LICENSE("GPL");
+
+static struct pci_device_id ip2main_pci_tbl[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_IP2EX) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, ip2main_pci_tbl);
diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c
index 3acdac3c967..a48da02aad2 100644
--- a/drivers/char/ip27-rtc.c
+++ b/drivers/char/ip27-rtc.c
@@ -196,7 +196,7 @@ static int rtc_release(struct inode *inode, struct file *file)
* The various file operations we support.
*/
-static struct file_operations rtc_fops = {
+static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.ioctl = rtc_ioctl,
.open = rtc_open,
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index e1c95374984..68d7c61a864 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -31,7 +31,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
@@ -40,7 +39,6 @@
#include <linux/poll.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/ipmi.h>
#include <linux/mutex.h>
#include <linux/init.h>
@@ -767,7 +765,7 @@ static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
}
#endif
-static struct file_operations ipmi_fops = {
+static const struct file_operations ipmi_fops = {
.owner = THIS_MODULE,
.ioctl = ipmi_ioctl,
#ifdef CONFIG_COMPAT
@@ -804,9 +802,6 @@ static void ipmi_new_smi(int if_num, struct device *device)
dev_t dev = MKDEV(ipmi_major, if_num);
struct ipmi_reg_list *entry;
- devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
- "ipmidev/%d", if_num);
-
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
if (!entry) {
printk(KERN_ERR "ipmi_devintf: Unable to create the"
@@ -836,7 +831,6 @@ static void ipmi_smi_gone(int if_num)
}
class_device_destroy(ipmi_class, dev);
mutex_unlock(&reg_list_mutex);
- devfs_remove("ipmidev/%d", if_num);
}
static struct ipmi_smi_watcher smi_watcher =
@@ -872,8 +866,6 @@ static __init int init_ipmi_devintf(void)
ipmi_major = rv;
}
- devfs_mk_dir(DEVICE_NAME);
-
rv = ipmi_smi_watcher_register(&smi_watcher);
if (rv) {
unregister_chrdev(ipmi_major, DEVICE_NAME);
@@ -898,7 +890,6 @@ static __exit void cleanup_ipmi(void)
mutex_unlock(&reg_list_mutex);
class_destroy(ipmi_class);
ipmi_smi_watcher_unregister(&smi_watcher);
- devfs_remove(DEVICE_NAME);
unregister_chrdev(ipmi_major, DEVICE_NAME);
}
module_exit(cleanup_ipmi);
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 9f2f8fdec69..843d34c8627 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -31,7 +31,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <asm/system.h>
@@ -57,8 +56,7 @@ static int ipmi_init_msghandler(void);
static int initialized = 0;
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_ipmi_root = NULL;
-EXPORT_SYMBOL(proc_ipmi_root);
+static struct proc_dir_entry *proc_ipmi_root = NULL;
#endif /* CONFIG_PROC_FS */
#define MAX_EVENTS_IN_QUEUE 25
@@ -936,11 +934,8 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
if (val) {
/* Deliver any queued events. */
- list_for_each_entry_safe(msg, msg2, &intf->waiting_events,
- link) {
- list_del(&msg->link);
- list_add_tail(&msg->link, &msgs);
- }
+ list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
+ list_move_tail(&msg->link, &msgs);
intf->waiting_events_count = 0;
}
@@ -3433,6 +3428,7 @@ struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
rv = kmalloc(sizeof(struct ipmi_recv_msg), GFP_ATOMIC);
if (rv) {
+ rv->user = NULL;
rv->done = free_recv_msg;
atomic_inc(&recv_msg_inuse_count);
}
@@ -3677,7 +3673,7 @@ static void send_panic_events(char *str)
}
#endif /* CONFIG_IPMI_PANIC_EVENT */
-static int has_paniced = 0;
+static int has_panicked = 0;
static int panic_event(struct notifier_block *this,
unsigned long event,
@@ -3686,9 +3682,9 @@ static int panic_event(struct notifier_block *this,
int i;
ipmi_smi_t intf;
- if (has_paniced)
+ if (has_panicked)
return NOTIFY_DONE;
- has_paniced = 1;
+ has_panicked = 1;
/* For every registered interface, set it to run to completion. */
for (i = 0; i < MAX_IPMI_INTERFACES; i++) {
@@ -3742,11 +3738,8 @@ static int ipmi_init_msghandler(void)
proc_ipmi_root->owner = THIS_MODULE;
#endif /* CONFIG_PROC_FS */
- init_timer(&ipmi_timer);
- ipmi_timer.data = 0;
- ipmi_timer.function = ipmi_timeout;
- ipmi_timer.expires = jiffies + IPMI_TIMEOUT_JIFFIES;
- add_timer(&ipmi_timer);
+ setup_timer(&ipmi_timer, ipmi_timeout, 0);
+ mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index d0b5c08e7b4..8d941db8345 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -31,7 +31,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/proc_fs.h>
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 02a7dd7a8a5..abca98beac1 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -38,7 +38,6 @@
* and drives the real SMI state machine.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <asm/system.h>
@@ -55,23 +54,6 @@
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <asm/irq.h>
-#ifdef CONFIG_HIGH_RES_TIMERS
-#include <linux/hrtime.h>
-# if defined(schedule_next_int)
-/* Old high-res timer code, do translations. */
-# define get_arch_cycles(a) quick_update_jiffies_sub(a)
-# define arch_cycles_per_jiffy cycles_per_jiffies
-# endif
-static inline void add_usec_to_timer(struct timer_list *t, long v)
-{
- t->arch_cycle_expires += nsec_to_arch_cycle(v * 1000);
- while (t->arch_cycle_expires >= arch_cycles_per_jiffy)
- {
- t->expires++;
- t->arch_cycle_expires -= arch_cycles_per_jiffy;
- }
-}
-#endif
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
#include <linux/ipmi_smi.h>
@@ -243,8 +225,6 @@ static int register_xaction_notifier(struct notifier_block * nb)
return atomic_notifier_chain_register(&xaction_notifier_list, nb);
}
-static void si_restart_short_timer(struct smi_info *smi_info);
-
static void deliver_recv_msg(struct smi_info *smi_info,
struct ipmi_smi_msg *msg)
{
@@ -422,10 +402,10 @@ static void handle_flags(struct smi_info *smi_info)
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
- } else if (smi_info->msg_flags & OEM_DATA_AVAIL) {
- if (smi_info->oem_data_avail_handler)
- if (smi_info->oem_data_avail_handler(smi_info))
- goto retry;
+ } else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
+ smi_info->oem_data_avail_handler) {
+ if (smi_info->oem_data_avail_handler(smi_info))
+ goto retry;
} else {
smi_info->si_state = SI_NORMAL;
}
@@ -768,7 +748,6 @@ static void sender(void *send_info,
&& (smi_info->curr_msg == NULL))
{
start_next_msg(smi_info);
- si_restart_short_timer(smi_info);
}
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
}
@@ -809,7 +788,7 @@ static int ipmi_thread(void *data)
/* do nothing */
}
else if (smi_result == SI_SM_CALL_WITH_DELAY)
- udelay(1);
+ schedule();
else
schedule_timeout_interruptible(1);
}
@@ -833,37 +812,6 @@ static void request_events(void *send_info)
static int initialized = 0;
-/* Must be called with interrupts off and with the si_lock held. */
-static void si_restart_short_timer(struct smi_info *smi_info)
-{
-#if defined(CONFIG_HIGH_RES_TIMERS)
- unsigned long flags;
- unsigned long jiffies_now;
- unsigned long seq;
-
- if (del_timer(&(smi_info->si_timer))) {
- /* If we don't delete the timer, then it will go off
- immediately, anyway. So we only process if we
- actually delete the timer. */
-
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- jiffies_now = jiffies;
- smi_info->si_timer.expires = jiffies_now;
- smi_info->si_timer.arch_cycle_expires
- = get_arch_cycles(jiffies_now);
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
- add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
-
- add_timer(&(smi_info->si_timer));
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->timeout_restarts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
- }
-#endif
-}
-
static void smi_timeout(unsigned long data)
{
struct smi_info *smi_info = (struct smi_info *) data;
@@ -904,31 +852,15 @@ static void smi_timeout(unsigned long data)
/* If the state machine asks for a short delay, then shorten
the timer timeout. */
if (smi_result == SI_SM_CALL_WITH_DELAY) {
-#if defined(CONFIG_HIGH_RES_TIMERS)
- unsigned long seq;
-#endif
spin_lock_irqsave(&smi_info->count_lock, flags);
smi_info->short_timeouts++;
spin_unlock_irqrestore(&smi_info->count_lock, flags);
-#if defined(CONFIG_HIGH_RES_TIMERS)
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- smi_info->si_timer.expires = jiffies;
- smi_info->si_timer.arch_cycle_expires
- = get_arch_cycles(smi_info->si_timer.expires);
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- add_usec_to_timer(&smi_info->si_timer, SI_SHORT_TIMEOUT_USEC);
-#else
smi_info->si_timer.expires = jiffies + 1;
-#endif
} else {
spin_lock_irqsave(&smi_info->count_lock, flags);
smi_info->long_timeouts++;
spin_unlock_irqrestore(&smi_info->count_lock, flags);
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
-#if defined(CONFIG_HIGH_RES_TIMERS)
- smi_info->si_timer.arch_cycle_expires = 0;
-#endif
}
do_add_timer:
@@ -1109,7 +1041,7 @@ static int std_irq_setup(struct smi_info *info)
if (info->si_type == SI_BT) {
rv = request_irq(info->irq,
si_bt_irq_handler,
- SA_INTERRUPT,
+ IRQF_DISABLED,
DEVICE_NAME,
info);
if (!rv)
@@ -1119,7 +1051,7 @@ static int std_irq_setup(struct smi_info *info)
} else
rv = request_irq(info->irq,
si_irq_handler,
- SA_INTERRUPT,
+ IRQF_DISABLED,
DEVICE_NAME,
info);
if (rv) {
@@ -2549,6 +2481,7 @@ static __devinit int init_ipmi_si(void)
#ifdef CONFIG_PCI
pci_unregister_driver(&ipmi_pci_driver);
#endif
+ driver_unregister(&ipmi_driver);
printk("ipmi_si: Unable to find any System Interface(s)\n");
return -ENODEV;
} else {
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 8f886717097..accaaf1a6b6 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -31,7 +31,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ipmi.h>
@@ -808,7 +807,7 @@ static int ipmi_close(struct inode *ino, struct file *filep)
return 0;
}
-static struct file_operations ipmi_wdog_fops = {
+static const struct file_operations ipmi_wdog_fops = {
.owner = THIS_MODULE,
.read = ipmi_read,
.poll = ipmi_poll,
@@ -949,9 +948,10 @@ static int wdog_reboot_handler(struct notifier_block *this,
/* Disable the WDT if we are shutting down. */
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
panic_halt_ipmi_set_timeout();
- } else {
+ } else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
/* Set a long timer to let the reboot happens, but
- reboot if it hangs. */
+ reboot if it hangs, but only if the watchdog
+ timer was already running. */
timeout = 120;
pretimeout = 0;
ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
@@ -973,16 +973,17 @@ static int wdog_panic_handler(struct notifier_block *this,
{
static int panic_event_handled = 0;
- /* On a panic, if we have a panic timeout, make sure that the thing
- reboots, even if it hangs during that panic. */
- if (watchdog_user && !panic_event_handled) {
- /* Make sure the panic doesn't hang, and make sure we
- do this only once. */
+ /* On a panic, if we have a panic timeout, make sure to extend
+ the watchdog timer to a reasonable value to complete the
+ panic, if the watchdog timer is running. Plus the
+ pretimeout is meaningless at panic time. */
+ if (watchdog_user && !panic_event_handled &&
+ ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
+ /* Make sure we do this only once. */
panic_event_handled = 1;
timeout = 255;
pretimeout = 0;
- ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
panic_halt_ipmi_set_timeout();
}
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index e9ebabaf8cb..913be23e0a2 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -245,7 +245,7 @@ static int lock_card(struct isi_board *card)
printk(KERN_WARNING "ISICOM: Failed to lock Card (0x%lx)\n",
card->base);
- return 0; /* Failed to aquire the card! */
+ return 0; /* Failed to acquire the card! */
}
static int lock_card_at_interrupt(struct isi_board *card)
@@ -262,7 +262,7 @@ static int lock_card_at_interrupt(struct isi_board *card)
spin_unlock_irqrestore(&card->card_lock, card->flags);
}
/* Failing in interrupt is an acceptable event */
- return 0; /* Failed to aquire the card! */
+ return 0; /* Failed to acquire the card! */
}
static void unlock_card(struct isi_board *card)
@@ -1145,7 +1145,7 @@ static int isicom_write(struct tty_struct *tty, const unsigned char *buf,
if (isicom_paranoia_check(port, tty->name, "isicom_write"))
return 0;
- if (!tty || !port->xmit_buf)
+ if (!port->xmit_buf)
return 0;
spin_lock_irqsave(&card->card_lock, flags);
@@ -1180,7 +1180,7 @@ static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
return;
- if (!tty || !port->xmit_buf)
+ if (!port->xmit_buf)
return;
spin_lock_irqsave(&card->card_lock, flags);
@@ -1581,7 +1581,6 @@ static int __devinit isicom_register_tty_driver(void)
isicom_normal->owner = THIS_MODULE;
isicom_normal->name = "ttyM";
- isicom_normal->devfs_name = "isicom/";
isicom_normal->major = ISICOM_NMAJOR;
isicom_normal->minor_start = 0;
isicom_normal->type = TTY_DRIVER_TYPE_SERIAL;
@@ -1615,14 +1614,14 @@ static int __devinit isicom_register_isr(struct pci_dev *pdev,
const unsigned int index)
{
struct isi_board *board = pci_get_drvdata(pdev);
- unsigned long irqflags = SA_INTERRUPT;
+ unsigned long irqflags = IRQF_DISABLED;
int retval = -EINVAL;
if (!board->base)
goto end;
if (board->isa == NO)
- irqflags |= SA_SHIRQ;
+ irqflags |= IRQF_SHARED;
retval = request_irq(board->irq, isicom_interrupt, irqflags,
ISICOM_NAME, board);
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index ef20c1fc9c4..6b4d82a4565 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -26,7 +26,6 @@
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -39,16 +38,14 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/device.h>
#include <linux/wait.h>
+#include <linux/eisa.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_PCI
#include <linux/pci.h>
-#endif
/*****************************************************************************/
@@ -137,6 +134,10 @@ static stlconf_t stli_brdconf[] = {
static int stli_nrbrds = ARRAY_SIZE(stli_brdconf);
+/* stli_lock must NOT be taken holding brd_lock */
+static spinlock_t stli_lock; /* TTY logic lock */
+static spinlock_t brd_lock; /* Board logic lock */
+
/*
* There is some experimental EISA board detection code in this driver.
* By default it is disabled, but for those that want to try it out,
@@ -173,14 +174,6 @@ static char *stli_serialname = "ttyE";
static struct tty_driver *stli_serial;
-/*
- * We will need to allocate a temporary write buffer for chars that
- * come direct from user space. The problem is that a copy from user
- * space might cause a page fault (typically on a system that is
- * swapping!). All ports will share one buffer - since if the system
- * is already swapping a shared buffer won't make things any worse.
- */
-static char *stli_tmpwritebuf;
#define STLI_TXBUFSIZE 4096
@@ -288,7 +281,6 @@ static char *stli_brdnames[] = {
/*****************************************************************************/
-#ifdef MODULE
/*
* Define some string labels for arguments passed from the module
* load line. These allow for easy board definitions, and easy
@@ -387,8 +379,6 @@ MODULE_PARM_DESC(board2, "Board 2 config -> name[,ioaddr[,memaddr]");
module_param_array(board3, charp, NULL, 0);
MODULE_PARM_DESC(board3, "Board 3 config -> name[,ioaddr[,memaddr]");
-#endif
-
/*
* Set up a default memory address table for EISA board probing.
* The default addresses are all bellow 1Mbyte, which has to be the
@@ -419,7 +409,7 @@ static int stli_eisamempsize = ARRAY_SIZE(stli_eisamemprobeaddrs);
#endif
static struct pci_device_id istallion_pci_tbl[] = {
- { PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA), },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
@@ -622,16 +612,6 @@ MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
#define MINOR2BRD(min) (((min) & 0xc0) >> 6)
#define MINOR2PORT(min) ((min) & 0x3f)
-/*
- * Define a baud rate table that converts termios baud rate selector
- * into the actual baud rate value. All baud rate calculations are based
- * on the actual baud rate required.
- */
-static unsigned int stli_baudrates[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
-};
-
/*****************************************************************************/
/*
@@ -649,14 +629,8 @@ static unsigned int stli_baudrates[] = {
* Prototype all functions in this driver!
*/
-#ifdef MODULE
-static void stli_argbrds(void);
static int stli_parsebrd(stlconf_t *confp, char **argp);
-
-static unsigned long stli_atol(char *str);
-#endif
-
-int stli_init(void);
+static int stli_init(void);
static int stli_open(struct tty_struct *tty, struct file *filp);
static void stli_close(struct tty_struct *tty, struct file *filp);
static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count);
@@ -682,7 +656,7 @@ static int stli_startbrd(stlibrd_t *brdp);
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp);
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp);
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg);
-static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp);
+static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp);
static void stli_poll(unsigned long arg);
static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp);
static int stli_initopen(stlibrd_t *brdp, stliport_t *portp);
@@ -693,7 +667,8 @@ static void stli_dohangup(void *arg);
static int stli_setport(stliport_t *portp);
static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
-static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp);
+static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback);
+static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp);
static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp);
static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts);
static long stli_mktiocm(unsigned long sigvalue);
@@ -763,7 +738,7 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp);
* will give access to the shared memory on the Stallion intelligent
* board. This is also a very useful debugging tool.
*/
-static struct file_operations stli_fsiomem = {
+static const struct file_operations stli_fsiomem = {
.owner = THIS_MODULE,
.read = stli_memread,
.write = stli_memwrite,
@@ -791,26 +766,14 @@ static int stli_timeron;
static struct class *istallion_class;
-#ifdef MODULE
-
/*
* Loadable module initialization stuff.
*/
static int __init istallion_module_init(void)
{
- unsigned long flags;
-
-#ifdef DEBUG
- printk("init_module()\n");
-#endif
-
- save_flags(flags);
- cli();
stli_init();
- restore_flags(flags);
-
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -819,56 +782,43 @@ static void __exit istallion_module_exit(void)
{
stlibrd_t *brdp;
stliport_t *portp;
- unsigned long flags;
int i, j;
-#ifdef DEBUG
- printk("cleanup_module()\n");
-#endif
-
printk(KERN_INFO "Unloading %s: version %s\n", stli_drvtitle,
stli_drvversion);
- save_flags(flags);
- cli();
-
-/*
- * Free up all allocated resources used by the ports. This includes
- * memory and interrupts.
- */
+ /*
+ * Free up all allocated resources used by the ports. This includes
+ * memory and interrupts.
+ */
if (stli_timeron) {
stli_timeron = 0;
- del_timer(&stli_timerlist);
+ del_timer_sync(&stli_timerlist);
}
i = tty_unregister_driver(stli_serial);
if (i) {
printk("STALLION: failed to un-register tty driver, "
"errno=%d\n", -i);
- restore_flags(flags);
return;
}
put_tty_driver(stli_serial);
- for (i = 0; i < 4; i++) {
- devfs_remove("staliomem/%d", i);
+ for (i = 0; i < 4; i++)
class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- }
- devfs_remove("staliomem");
class_destroy(istallion_class);
if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
printk("STALLION: failed to un-register serial memory device, "
"errno=%d\n", -i);
- kfree(stli_tmpwritebuf);
kfree(stli_txcookbuf);
for (i = 0; (i < stli_nrbrds); i++) {
- if ((brdp = stli_brds[i]) == (stlibrd_t *) NULL)
+ if ((brdp = stli_brds[i]) == NULL)
continue;
for (j = 0; (j < STL_MAXPORTS); j++) {
portp = brdp->ports[j];
- if (portp != (stliport_t *) NULL) {
- if (portp->tty != (struct tty_struct *) NULL)
+ if (portp != NULL) {
+ if (portp->tty != NULL)
tty_hangup(portp->tty);
kfree(portp);
}
@@ -878,10 +828,8 @@ static void __exit istallion_module_exit(void)
if (brdp->iosize > 0)
release_region(brdp->iobase, brdp->iosize);
kfree(brdp);
- stli_brds[i] = (stlibrd_t *) NULL;
+ stli_brds[i] = NULL;
}
-
- restore_flags(flags);
}
module_init(istallion_module_init);
@@ -895,19 +843,15 @@ module_exit(istallion_module_exit);
static void stli_argbrds(void)
{
- stlconf_t conf;
- stlibrd_t *brdp;
- int i;
-
-#ifdef DEBUG
- printk("stli_argbrds()\n");
-#endif
+ stlconf_t conf;
+ stlibrd_t *brdp;
+ int i;
for (i = stli_nrbrds; i < ARRAY_SIZE(stli_brdsp); i++) {
memset(&conf, 0, sizeof(conf));
if (stli_parsebrd(&conf, stli_brdsp[i]) == 0)
continue;
- if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
+ if ((brdp = stli_allocbrd()) == NULL)
continue;
stli_nrbrds = i + 1;
brdp->brdnr = i;
@@ -926,9 +870,9 @@ static void stli_argbrds(void)
static unsigned long stli_atol(char *str)
{
- unsigned long val;
- int base, c;
- char *sp;
+ unsigned long val;
+ int base, c;
+ char *sp;
val = 0;
sp = str;
@@ -962,15 +906,11 @@ static unsigned long stli_atol(char *str)
static int stli_parsebrd(stlconf_t *confp, char **argp)
{
- char *sp;
- int i;
-
-#ifdef DEBUG
- printk("stli_parsebrd(confp=%x,argp=%x)\n", (int) confp, (int) argp);
-#endif
+ char *sp;
+ int i;
- if ((argp[0] == (char *) NULL) || (*argp[0] == 0))
- return(0);
+ if (argp[0] == NULL || *argp[0] == 0)
+ return 0;
for (sp = argp[0], i = 0; ((*sp != 0) && (i < 25)); sp++, i++)
*sp = TOLOWER(*sp);
@@ -985,47 +925,40 @@ static int stli_parsebrd(stlconf_t *confp, char **argp)
}
confp->brdtype = stli_brdstr[i].type;
- if ((argp[1] != (char *) NULL) && (*argp[1] != 0))
+ if (argp[1] != NULL && *argp[1] != 0)
confp->ioaddr1 = stli_atol(argp[1]);
- if ((argp[2] != (char *) NULL) && (*argp[2] != 0))
+ if (argp[2] != NULL && *argp[2] != 0)
confp->memaddr = stli_atol(argp[2]);
return(1);
}
-#endif
-
/*****************************************************************************/
static int stli_open(struct tty_struct *tty, struct file *filp)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- unsigned int minordev;
- int brdnr, portnr, rc;
-
-#ifdef DEBUG
- printk("stli_open(tty=%x,filp=%x): device=%s\n", (int) tty,
- (int) filp, tty->name);
-#endif
+ stlibrd_t *brdp;
+ stliport_t *portp;
+ unsigned int minordev;
+ int brdnr, portnr, rc;
minordev = tty->index;
brdnr = MINOR2BRD(minordev);
if (brdnr >= stli_nrbrds)
- return(-ENODEV);
+ return -ENODEV;
brdp = stli_brds[brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
if ((brdp->state & BST_STARTED) == 0)
- return(-ENODEV);
+ return -ENODEV;
portnr = MINOR2PORT(minordev);
if ((portnr < 0) || (portnr > brdp->nrports))
- return(-ENODEV);
+ return -ENODEV;
portp = brdp->ports[portnr];
- if (portp == (stliport_t *) NULL)
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
if (portp->devnr < 1)
- return(-ENODEV);
+ return -ENODEV;
/*
@@ -1037,8 +970,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
if (portp->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&portp->close_wait);
if (portp->flags & ASYNC_HUP_NOTIFY)
- return(-EAGAIN);
- return(-ERESTARTSYS);
+ return -EAGAIN;
+ return -ERESTARTSYS;
}
/*
@@ -1054,7 +987,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_INITIALIZING, &portp->state));
if (signal_pending(current))
- return(-ERESTARTSYS);
+ return -ERESTARTSYS;
if ((portp->flags & ASYNC_INITIALIZED) == 0) {
set_bit(ST_INITIALIZING, &portp->state);
@@ -1065,7 +998,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
clear_bit(ST_INITIALIZING, &portp->state);
wake_up_interruptible(&portp->raw_wait);
if (rc < 0)
- return(rc);
+ return rc;
}
/*
@@ -1077,8 +1010,8 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
if (portp->flags & ASYNC_CLOSING) {
interruptible_sleep_on(&portp->close_wait);
if (portp->flags & ASYNC_HUP_NOTIFY)
- return(-EAGAIN);
- return(-ERESTARTSYS);
+ return -EAGAIN;
+ return -ERESTARTSYS;
}
/*
@@ -1088,38 +1021,33 @@ static int stli_open(struct tty_struct *tty, struct file *filp)
*/
if (!(filp->f_flags & O_NONBLOCK)) {
if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0)
- return(rc);
+ return rc;
}
portp->flags |= ASYNC_NORMAL_ACTIVE;
- return(0);
+ return 0;
}
/*****************************************************************************/
static void stli_close(struct tty_struct *tty, struct file *filp)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- unsigned long flags;
-
-#ifdef DEBUG
- printk("stli_close(tty=%x,filp=%x)\n", (int) tty, (int) filp);
-#endif
+ stlibrd_t *brdp;
+ stliport_t *portp;
+ unsigned long flags;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&stli_lock, flags);
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&stli_lock, flags);
return;
}
if ((tty->count == 1) && (portp->refcount != 1))
portp->refcount = 1;
if (portp->refcount-- > 1) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&stli_lock, flags);
return;
}
@@ -1134,6 +1062,8 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
if (tty == stli_txcooktty)
stli_flushchars(tty);
tty->closing = 1;
+ spin_unlock_irqrestore(&stli_lock, flags);
+
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, portp->closing_wait);
@@ -1157,7 +1087,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
stli_flushbuffer(tty);
tty->closing = 0;
- portp->tty = (struct tty_struct *) NULL;
+ portp->tty = NULL;
if (portp->openwaitcnt) {
if (portp->close_delay)
@@ -1167,7 +1097,6 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&portp->close_wait);
- restore_flags(flags);
}
/*****************************************************************************/
@@ -1182,45 +1111,41 @@ static void stli_close(struct tty_struct *tty, struct file *filp)
static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
{
- struct tty_struct *tty;
- asynotify_t nt;
- asyport_t aport;
- int rc;
-
-#ifdef DEBUG
- printk("stli_initopen(brdp=%x,portp=%x)\n", (int) brdp, (int) portp);
-#endif
+ struct tty_struct *tty;
+ asynotify_t nt;
+ asyport_t aport;
+ int rc;
if ((rc = stli_rawopen(brdp, portp, 0, 1)) < 0)
- return(rc);
+ return rc;
memset(&nt, 0, sizeof(asynotify_t));
nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK);
nt.signal = SG_DCD;
if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt,
sizeof(asynotify_t), 0)) < 0)
- return(rc);
+ return rc;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
- return(-ENODEV);
+ if (tty == NULL)
+ return -ENODEV;
stli_mkasyport(portp, &aport, tty->termios);
if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport,
sizeof(asyport_t), 0)) < 0)
- return(rc);
+ return rc;
set_bit(ST_GETSIGS, &portp->state);
if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig,
sizeof(asysigs_t), 1)) < 0)
- return(rc);
+ return rc;
if (test_and_clear_bit(ST_GETSIGS, &portp->state))
portp->sigs = stli_mktiocm(portp->asig.sigvalue);
stli_mkasysigs(&portp->asig, 1, 1);
if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
sizeof(asysigs_t), 0)) < 0)
- return(rc);
+ return rc;
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -1234,22 +1159,15 @@ static int stli_initopen(stlibrd_t *brdp, stliport_t *portp)
static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
{
- volatile cdkhdr_t *hdrp;
- volatile cdkctrl_t *cp;
- volatile unsigned char *bits;
- unsigned long flags;
- int rc;
-
-#ifdef DEBUG
- printk("stli_rawopen(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
- (int) brdp, (int) portp, (int) arg, wait);
-#endif
+ cdkhdr_t __iomem *hdrp;
+ cdkctrl_t __iomem *cp;
+ unsigned char __iomem *bits;
+ unsigned long flags;
+ int rc;
/*
* Send a message to the slave to open this port.
*/
- save_flags(flags);
- cli();
/*
* Slave is already closing this port. This can happen if a hangup
@@ -1260,7 +1178,6 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CLOSING, &portp->state));
if (signal_pending(current)) {
- restore_flags(flags);
return -ERESTARTSYS;
}
@@ -1269,19 +1186,20 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
* memory. Once the message is in set the service bits to say that
* this port wants service.
*/
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
- cp->openarg = arg;
- cp->open = 1;
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+ cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+ writel(arg, &cp->openarg);
+ writeb(1, &cp->open);
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
portp->portidx;
- *bits |= portp->portbit;
+ writeb(readb(bits) | portp->portbit, bits);
EBRDDISABLE(brdp);
if (wait == 0) {
- restore_flags(flags);
- return(0);
+ spin_unlock_irqrestore(&brd_lock, flags);
+ return 0;
}
/*
@@ -1290,15 +1208,16 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
*/
rc = 0;
set_bit(ST_OPENING, &portp->state);
+ spin_unlock_irqrestore(&brd_lock, flags);
+
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_OPENING, &portp->state));
if (signal_pending(current))
rc = -ERESTARTSYS;
- restore_flags(flags);
if ((rc == 0) && (portp->rc != 0))
rc = -EIO;
- return(rc);
+ return rc;
}
/*****************************************************************************/
@@ -1311,19 +1230,11 @@ static int stli_rawopen(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, i
static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg, int wait)
{
- volatile cdkhdr_t *hdrp;
- volatile cdkctrl_t *cp;
- volatile unsigned char *bits;
- unsigned long flags;
- int rc;
-
-#ifdef DEBUG
- printk("stli_rawclose(brdp=%x,portp=%x,arg=%x,wait=%d)\n",
- (int) brdp, (int) portp, (int) arg, wait);
-#endif
-
- save_flags(flags);
- cli();
+ cdkhdr_t __iomem *hdrp;
+ cdkctrl_t __iomem *cp;
+ unsigned char __iomem *bits;
+ unsigned long flags;
+ int rc;
/*
* Slave is already closing this port. This can happen if a hangup
@@ -1333,7 +1244,6 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CLOSING, &portp->state));
if (signal_pending(current)) {
- restore_flags(flags);
return -ERESTARTSYS;
}
}
@@ -1341,21 +1251,22 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
/*
* Write the close command into shared memory.
*/
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
- cp->closearg = arg;
- cp->close = 1;
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+ cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+ writel(arg, &cp->closearg);
+ writeb(1, &cp->close);
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
portp->portidx;
- *bits |= portp->portbit;
+ writeb(readb(bits) |portp->portbit, bits);
EBRDDISABLE(brdp);
set_bit(ST_CLOSING, &portp->state);
- if (wait == 0) {
- restore_flags(flags);
- return(0);
- }
+ spin_unlock_irqrestore(&brd_lock, flags);
+
+ if (wait == 0)
+ return 0;
/*
* Slave is in action, so now we must wait for the open acknowledgment
@@ -1366,11 +1277,10 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
!test_bit(ST_CLOSING, &portp->state));
if (signal_pending(current))
rc = -ERESTARTSYS;
- restore_flags(flags);
if ((rc == 0) && (portp->rc != 0))
rc = -EIO;
- return(rc);
+ return rc;
}
/*****************************************************************************/
@@ -1384,36 +1294,21 @@ static int stli_rawclose(stlibrd_t *brdp, stliport_t *portp, unsigned long arg,
static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
{
- unsigned long flags;
-
-#ifdef DEBUG
- printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
- "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
- (int) arg, size, copyback);
-#endif
-
- save_flags(flags);
- cli();
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CMDING, &portp->state));
- if (signal_pending(current)) {
- restore_flags(flags);
+ if (signal_pending(current))
return -ERESTARTSYS;
- }
stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
wait_event_interruptible(portp->raw_wait,
!test_bit(ST_CMDING, &portp->state));
- if (signal_pending(current)) {
- restore_flags(flags);
+ if (signal_pending(current))
return -ERESTARTSYS;
- }
- restore_flags(flags);
if (portp->rc != 0)
- return(-EIO);
- return(0);
+ return -EIO;
+ return 0;
}
/*****************************************************************************/
@@ -1425,22 +1320,18 @@ static int stli_cmdwait(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, v
static int stli_setport(stliport_t *portp)
{
- stlibrd_t *brdp;
- asyport_t aport;
-
-#ifdef DEBUG
- printk("stli_setport(portp=%x)\n", (int) portp);
-#endif
+ stlibrd_t *brdp;
+ asyport_t aport;
- if (portp == (stliport_t *) NULL)
- return(-ENODEV);
- if (portp->tty == (struct tty_struct *) NULL)
- return(-ENODEV);
- if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds))
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
+ if (portp->tty == NULL)
+ return -ENODEV;
+ if (portp->brdnr < 0 && portp->brdnr >= stli_nrbrds)
+ return -ENODEV;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
stli_mkasyport(portp, &aport, portp->tty->termios);
return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));
@@ -1455,13 +1346,8 @@ static int stli_setport(stliport_t *portp)
static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *filp)
{
- unsigned long flags;
- int rc, doclocal;
-
-#ifdef DEBUG
- printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n",
- (int) brdp, (int) portp, (int) filp);
-#endif
+ unsigned long flags;
+ int rc, doclocal;
rc = 0;
doclocal = 0;
@@ -1469,11 +1355,11 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
if (portp->tty->termios->c_cflag & CLOCAL)
doclocal++;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&stli_lock, flags);
portp->openwaitcnt++;
if (! tty_hung_up_p(filp))
portp->refcount--;
+ spin_unlock_irqrestore(&stli_lock, flags);
for (;;) {
stli_mkasysigs(&portp->asig, 1, 1);
@@ -1499,12 +1385,13 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
interruptible_sleep_on(&portp->open_wait);
}
+ spin_lock_irqsave(&stli_lock, flags);
if (! tty_hung_up_p(filp))
portp->refcount++;
portp->openwaitcnt--;
- restore_flags(flags);
+ spin_unlock_irqrestore(&stli_lock, flags);
- return(rc);
+ return rc;
}
/*****************************************************************************/
@@ -1517,46 +1404,38 @@ static int stli_waitcarrier(stlibrd_t *brdp, stliport_t *portp, struct file *fil
static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
- volatile cdkasy_t *ap;
- volatile cdkhdr_t *hdrp;
- volatile unsigned char *bits;
- unsigned char *shbuf, *chbuf;
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned int len, stlen, head, tail, size;
- unsigned long flags;
-
-#ifdef DEBUG
- printk("stli_write(tty=%x,buf=%x,count=%d)\n",
- (int) tty, (int) buf, count);
-#endif
+ cdkasy_t __iomem *ap;
+ cdkhdr_t __iomem *hdrp;
+ unsigned char __iomem *bits;
+ unsigned char __iomem *shbuf;
+ unsigned char *chbuf;
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned int len, stlen, head, tail, size;
+ unsigned long flags;
- if ((tty == (struct tty_struct *) NULL) ||
- (stli_tmpwritebuf == (char *) NULL))
- return(0);
if (tty == stli_txcooktty)
stli_flushchars(tty);
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return(0);
+ if (portp == NULL)
+ return 0;
if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return(0);
+ return 0;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(0);
+ if (brdp == NULL)
+ return 0;
chbuf = (unsigned char *) buf;
/*
* All data is now local, shove as much as possible into shared memory.
*/
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
- head = (unsigned int) ap->txq.head;
- tail = (unsigned int) ap->txq.tail;
- if (tail != ((unsigned int) ap->txq.tail))
- tail = (unsigned int) ap->txq.tail;
+ ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+ head = (unsigned int) readw(&ap->txq.head);
+ tail = (unsigned int) readw(&ap->txq.tail);
+ if (tail != ((unsigned int) readw(&ap->txq.tail)))
+ tail = (unsigned int) readw(&ap->txq.tail);
size = portp->txsize;
if (head >= tail) {
len = size - (head - tail) - 1;
@@ -1568,11 +1447,11 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
len = MIN(len, count);
count = 0;
- shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);
+ shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->txoffset);
while (len > 0) {
stlen = MIN(len, stlen);
- memcpy((shbuf + head), chbuf, stlen);
+ memcpy_toio(shbuf + head, chbuf, stlen);
chbuf += stlen;
len -= stlen;
count += stlen;
@@ -1583,20 +1462,19 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
}
}
- ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
- ap->txq.head = head;
+ ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+ writew(head, &ap->txq.head);
if (test_bit(ST_TXBUSY, &portp->state)) {
- if (ap->changed.data & DT_TXEMPTY)
- ap->changed.data &= ~DT_TXEMPTY;
+ if (readl(&ap->changed.data) & DT_TXEMPTY)
+ writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data);
}
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
portp->portidx;
- *bits |= portp->portbit;
+ writeb(readb(bits) | portp->portbit, bits);
set_bit(ST_TXBUSY, &portp->state);
EBRDDISABLE(brdp);
-
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
return(count);
}
@@ -1613,14 +1491,8 @@ static int stli_write(struct tty_struct *tty, const unsigned char *buf, int coun
static void stli_putchar(struct tty_struct *tty, unsigned char ch)
{
-#ifdef DEBUG
- printk("stli_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
if (tty != stli_txcooktty) {
- if (stli_txcooktty != (struct tty_struct *) NULL)
+ if (stli_txcooktty != NULL)
stli_flushchars(stli_txcooktty);
stli_txcooktty = tty;
}
@@ -1640,29 +1512,26 @@ static void stli_putchar(struct tty_struct *tty, unsigned char ch)
static void stli_flushchars(struct tty_struct *tty)
{
- volatile cdkhdr_t *hdrp;
- volatile unsigned char *bits;
- volatile cdkasy_t *ap;
- struct tty_struct *cooktty;
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned int len, stlen, head, tail, size, count, cooksize;
- unsigned char *buf, *shbuf;
- unsigned long flags;
-
-#ifdef DEBUG
- printk("stli_flushchars(tty=%x)\n", (int) tty);
-#endif
+ cdkhdr_t __iomem *hdrp;
+ unsigned char __iomem *bits;
+ cdkasy_t __iomem *ap;
+ struct tty_struct *cooktty;
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned int len, stlen, head, tail, size, count, cooksize;
+ unsigned char *buf;
+ unsigned char __iomem *shbuf;
+ unsigned long flags;
cooksize = stli_txcooksize;
cooktty = stli_txcooktty;
stli_txcooksize = 0;
stli_txcookrealsize = 0;
- stli_txcooktty = (struct tty_struct *) NULL;
+ stli_txcooktty = NULL;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
- if (cooktty == (struct tty_struct *) NULL)
+ if (cooktty == NULL)
return;
if (tty != cooktty)
tty = cooktty;
@@ -1670,23 +1539,22 @@ static void stli_flushchars(struct tty_struct *tty)
return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
return;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
- head = (unsigned int) ap->txq.head;
- tail = (unsigned int) ap->txq.tail;
- if (tail != ((unsigned int) ap->txq.tail))
- tail = (unsigned int) ap->txq.tail;
+ ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+ head = (unsigned int) readw(&ap->txq.head);
+ tail = (unsigned int) readw(&ap->txq.tail);
+ if (tail != ((unsigned int) readw(&ap->txq.tail)))
+ tail = (unsigned int) readw(&ap->txq.tail);
size = portp->txsize;
if (head >= tail) {
len = size - (head - tail) - 1;
@@ -1703,7 +1571,7 @@ static void stli_flushchars(struct tty_struct *tty)
while (len > 0) {
stlen = MIN(len, stlen);
- memcpy((shbuf + head), buf, stlen);
+ memcpy_toio(shbuf + head, buf, stlen);
buf += stlen;
len -= stlen;
count += stlen;
@@ -1714,73 +1582,66 @@ static void stli_flushchars(struct tty_struct *tty)
}
}
- ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
- ap->txq.head = head;
+ ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+ writew(head, &ap->txq.head);
if (test_bit(ST_TXBUSY, &portp->state)) {
- if (ap->changed.data & DT_TXEMPTY)
- ap->changed.data &= ~DT_TXEMPTY;
+ if (readl(&ap->changed.data) & DT_TXEMPTY)
+ writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data);
}
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
portp->portidx;
- *bits |= portp->portbit;
+ writeb(readb(bits) | portp->portbit, bits);
set_bit(ST_TXBUSY, &portp->state);
EBRDDISABLE(brdp);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
static int stli_writeroom(struct tty_struct *tty)
{
- volatile cdkasyrq_t *rp;
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned int head, tail, len;
- unsigned long flags;
-
-#ifdef DEBUG
- printk("stli_writeroom(tty=%x)\n", (int) tty);
-#endif
+ cdkasyrq_t __iomem *rp;
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned int head, tail, len;
+ unsigned long flags;
- if (tty == (struct tty_struct *) NULL)
- return(0);
if (tty == stli_txcooktty) {
if (stli_txcookrealsize != 0) {
len = stli_txcookrealsize - stli_txcooksize;
- return(len);
+ return len;
}
}
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return(0);
+ if (portp == NULL)
+ return 0;
if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return(0);
+ return 0;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(0);
+ if (brdp == NULL)
+ return 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
- head = (unsigned int) rp->head;
- tail = (unsigned int) rp->tail;
- if (tail != ((unsigned int) rp->tail))
- tail = (unsigned int) rp->tail;
+ rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
+ head = (unsigned int) readw(&rp->head);
+ tail = (unsigned int) readw(&rp->tail);
+ if (tail != ((unsigned int) readw(&rp->tail)))
+ tail = (unsigned int) readw(&rp->tail);
len = (head >= tail) ? (portp->txsize - (head - tail)) : (tail - head);
len--;
EBRDDISABLE(brdp);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
if (tty == stli_txcooktty) {
stli_txcookrealsize = len;
len -= stli_txcooksize;
}
- return(len);
+ return len;
}
/*****************************************************************************/
@@ -1795,44 +1656,37 @@ static int stli_writeroom(struct tty_struct *tty)
static int stli_charsinbuffer(struct tty_struct *tty)
{
- volatile cdkasyrq_t *rp;
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned int head, tail, len;
- unsigned long flags;
-
-#ifdef DEBUG
- printk("stli_charsinbuffer(tty=%x)\n", (int) tty);
-#endif
+ cdkasyrq_t __iomem *rp;
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned int head, tail, len;
+ unsigned long flags;
- if (tty == (struct tty_struct *) NULL)
- return(0);
if (tty == stli_txcooktty)
stli_flushchars(tty);
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return(0);
+ if (portp == NULL)
+ return 0;
if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return(0);
+ return 0;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(0);
+ if (brdp == NULL)
+ return 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
- head = (unsigned int) rp->head;
- tail = (unsigned int) rp->tail;
- if (tail != ((unsigned int) rp->tail))
- tail = (unsigned int) rp->tail;
+ rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->txq;
+ head = (unsigned int) readw(&rp->head);
+ tail = (unsigned int) readw(&rp->tail);
+ if (tail != ((unsigned int) readw(&rp->tail)))
+ tail = (unsigned int) readw(&rp->tail);
len = (head >= tail) ? (head - tail) : (portp->txsize - (tail - head));
if ((len == 0) && test_bit(ST_TXBUSY, &portp->state))
len = 1;
EBRDDISABLE(brdp);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
- return(len);
+ return len;
}
/*****************************************************************************/
@@ -1843,12 +1697,8 @@ static int stli_charsinbuffer(struct tty_struct *tty)
static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
{
- struct serial_struct sio;
- stlibrd_t *brdp;
-
-#ifdef DEBUG
- printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);
-#endif
+ struct serial_struct sio;
+ stlibrd_t *brdp;
memset(&sio, 0, sizeof(struct serial_struct));
sio.type = PORT_UNKNOWN;
@@ -1863,7 +1713,7 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
sio.hub6 = 0;
brdp = stli_brds[portp->brdnr];
- if (brdp != (stlibrd_t *) NULL)
+ if (brdp != NULL)
sio.port = brdp->iobase;
return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ?
@@ -1880,12 +1730,8 @@ static int stli_getserial(stliport_t *portp, struct serial_struct __user *sp)
static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
{
- struct serial_struct sio;
- int rc;
-
-#ifdef DEBUG
- printk("stli_setserial(portp=%p,sp=%p)\n", portp, sp);
-#endif
+ struct serial_struct sio;
+ int rc;
if (copy_from_user(&sio, sp, sizeof(struct serial_struct)))
return -EFAULT;
@@ -1894,7 +1740,7 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
(sio.close_delay != portp->close_delay) ||
((sio.flags & ~ASYNC_USR_MASK) !=
(portp->flags & ~ASYNC_USR_MASK)))
- return(-EPERM);
+ return -EPERM;
}
portp->flags = (portp->flags & ~ASYNC_USR_MASK) |
@@ -1905,8 +1751,8 @@ static int stli_setserial(stliport_t *portp, struct serial_struct __user *sp)
portp->custom_divisor = sio.custom_divisor;
if ((rc = stli_setport(portp)) < 0)
- return(rc);
- return(0);
+ return rc;
+ return 0;
}
/*****************************************************************************/
@@ -1917,19 +1763,19 @@ static int stli_tiocmget(struct tty_struct *tty, struct file *file)
stlibrd_t *brdp;
int rc;
- if (portp == (stliport_t *) NULL)
- return(-ENODEV);
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return(0);
+ if (portp == NULL)
+ return -ENODEV;
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ return 0;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(0);
+ if (brdp == NULL)
+ return 0;
if (tty->flags & (1 << TTY_IO_ERROR))
- return(-EIO);
+ return -EIO;
if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS,
&portp->asig, sizeof(asysigs_t), 1)) < 0)
- return(rc);
+ return rc;
return stli_mktiocm(portp->asig.sigvalue);
}
@@ -1941,15 +1787,15 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
stlibrd_t *brdp;
int rts = -1, dtr = -1;
- if (portp == (stliport_t *) NULL)
- return(-ENODEV);
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return(0);
+ if (portp == NULL)
+ return -ENODEV;
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ return 0;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(0);
+ if (brdp == NULL)
+ return 0;
if (tty->flags & (1 << TTY_IO_ERROR))
- return(-EIO);
+ return -EIO;
if (set & TIOCM_RTS)
rts = 1;
@@ -1968,32 +1814,25 @@ static int stli_tiocmset(struct tty_struct *tty, struct file *file,
static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned int ival;
- int rc;
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned int ival;
+ int rc;
void __user *argp = (void __user *)arg;
-#ifdef DEBUG
- printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n",
- (int) tty, (int) file, cmd, (int) arg);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return(-ENODEV);
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return(-ENODEV);
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return(0);
+ if (portp == NULL)
+ return -ENODEV;
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
+ return 0;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(0);
+ if (brdp == NULL)
+ return 0;
if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
(cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) {
if (tty->flags & (1 << TTY_IO_ERROR))
- return(-EIO);
+ return -EIO;
}
rc = 0;
@@ -2040,7 +1879,7 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
break;
}
- return(rc);
+ return rc;
}
/*****************************************************************************/
@@ -2052,24 +1891,20 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm
static void stli_settermios(struct tty_struct *tty, struct termios *old)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- struct termios *tiosp;
- asyport_t aport;
-
-#ifdef DEBUG
- printk("stli_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);
-#endif
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ struct termios *tiosp;
+ asyport_t aport;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
return;
tiosp = tty->termios;
@@ -2102,18 +1937,9 @@ static void stli_settermios(struct tty_struct *tty, struct termios *old)
static void stli_throttle(struct tty_struct *tty)
{
- stliport_t *portp;
-
-#ifdef DEBUG
- printk("stli_throttle(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
+ stliport_t *portp = tty->driver_data;
+ if (portp == NULL)
return;
- portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return;
-
set_bit(ST_RXSTOP, &portp->state);
}
@@ -2127,88 +1953,30 @@ static void stli_throttle(struct tty_struct *tty)
static void stli_unthrottle(struct tty_struct *tty)
{
- stliport_t *portp;
-
-#ifdef DEBUG
- printk("stli_unthrottle(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ stliport_t *portp = tty->driver_data;
+ if (portp == NULL)
return;
-
clear_bit(ST_RXSTOP, &portp->state);
}
/*****************************************************************************/
/*
- * Stop the transmitter. Basically to do this we will just turn TX
- * interrupts off.
+ * Stop the transmitter.
*/
static void stli_stop(struct tty_struct *tty)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- asyctrl_t actrl;
-
-#ifdef DEBUG
- printk("stli_stop(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return;
- brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return;
-
- memset(&actrl, 0, sizeof(asyctrl_t));
- actrl.txctrl = CT_STOPFLOW;
-#if 0
- stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
-#endif
}
/*****************************************************************************/
/*
- * Start the transmitter again. Just turn TX interrupts back on.
+ * Start the transmitter again.
*/
static void stli_start(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- asyctrl_t actrl;
-
-#ifdef DEBUG
- printk("stli_start(tty=%x)\n", (int) tty);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
- portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
- return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
- return;
- brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return;
-
- memset(&actrl, 0, sizeof(asyctrl_t));
- actrl.txctrl = CT_STARTFLOW;
-#if 0
- stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
-#endif
}
/*****************************************************************************/
@@ -2224,22 +1992,9 @@ static void stli_start(struct tty_struct *tty)
static void stli_dohangup(void *arg)
{
- stliport_t *portp;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_dohangup(portp=%x)\n", (int) arg);
-#endif
-
- /*
- * FIXME: There's a module removal race here: tty_hangup
- * calls schedule_work which will call into this
- * driver later.
- */
- portp = (stliport_t *) arg;
- if (portp != (stliport_t *) NULL) {
- if (portp->tty != (struct tty_struct *) NULL) {
- tty_hangup(portp->tty);
- }
+ stliport_t *portp = (stliport_t *) arg;
+ if (portp->tty != NULL) {
+ tty_hangup(portp->tty);
}
}
@@ -2254,31 +2009,25 @@ static void stli_dohangup(void *arg)
static void stli_hangup(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned long flags;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_hangup(tty=%x)\n", (int) tty);
-#endif
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned long flags;
- if (tty == (struct tty_struct *) NULL)
- return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
return;
portp->flags &= ~ASYNC_INITIALIZED;
- save_flags(flags);
- cli();
- if (! test_bit(ST_CLOSING, &portp->state))
+ if (!test_bit(ST_CLOSING, &portp->state))
stli_rawclose(brdp, portp, 0, 0);
+
+ spin_lock_irqsave(&stli_lock, flags);
if (tty->termios->c_cflag & HUPCL) {
stli_mkasysigs(&portp->asig, 0, 0);
if (test_bit(ST_CMDING, &portp->state)) {
@@ -2290,14 +2039,15 @@ static void stli_hangup(struct tty_struct *tty)
&portp->asig, sizeof(asysigs_t), 0);
}
}
- restore_flags(flags);
clear_bit(ST_TXBUSY, &portp->state);
clear_bit(ST_RXSTOP, &portp->state);
set_bit(TTY_IO_ERROR, &tty->flags);
- portp->tty = (struct tty_struct *) NULL;
+ portp->tty = NULL;
portp->flags &= ~ASYNC_NORMAL_ACTIVE;
portp->refcount = 0;
+ spin_unlock_irqrestore(&stli_lock, flags);
+
wake_up_interruptible(&portp->open_wait);
}
@@ -2312,29 +2062,22 @@ static void stli_hangup(struct tty_struct *tty)
static void stli_flushbuffer(struct tty_struct *tty)
{
- stliport_t *portp;
- stlibrd_t *brdp;
- unsigned long ftype, flags;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_flushbuffer(tty=%x)\n", (int) tty);
-#endif
+ stliport_t *portp;
+ stlibrd_t *brdp;
+ unsigned long ftype, flags;
- if (tty == (struct tty_struct *) NULL)
- return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
if (tty == stli_txcooktty) {
- stli_txcooktty = (struct tty_struct *) NULL;
+ stli_txcooktty = NULL;
stli_txcooksize = 0;
stli_txcookrealsize = 0;
}
@@ -2346,15 +2089,10 @@ static void stli_flushbuffer(struct tty_struct *tty)
ftype |= FLUSHRX;
clear_bit(ST_DOFLUSHRX, &portp->state);
}
- stli_sendcmd(brdp, portp, A_FLUSH, &ftype,
- sizeof(unsigned long), 0);
+ __stli_sendcmd(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0);
}
- restore_flags(flags);
-
- wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
+ spin_unlock_irqrestore(&brd_lock, flags);
+ tty_wakeup(tty);
}
/*****************************************************************************/
@@ -2364,55 +2102,31 @@ static void stli_breakctl(struct tty_struct *tty, int state)
stlibrd_t *brdp;
stliport_t *portp;
long arg;
- /* long savestate, savetime; */
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_breakctl(tty=%x,state=%d)\n", (int) tty, state);
-#endif
- if (tty == (struct tty_struct *) NULL)
- return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
return;
-/*
- * Due to a bug in the tty send_break() code we need to preserve
- * the current process state and timeout...
- savetime = current->timeout;
- savestate = current->state;
- */
-
arg = (state == -1) ? BREAKON : BREAKOFF;
stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);
-
-/*
- *
- current->timeout = savetime;
- current->state = savestate;
- */
}
/*****************************************************************************/
static void stli_waituntilsent(struct tty_struct *tty, int timeout)
{
- stliport_t *portp;
- unsigned long tend;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_waituntilsent(tty=%x,timeout=%x)\n", (int) tty, timeout);
-#endif
+ stliport_t *portp;
+ unsigned long tend;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
if (timeout == 0)
@@ -2436,19 +2150,13 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
stliport_t *portp;
asyctrl_t actrl;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_sendxchar(tty=%x,ch=%x)\n", (int) tty, ch);
-#endif
-
- if (tty == (struct tty_struct *) NULL)
- return;
portp = tty->driver_data;
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
return;
- if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds))
+ if (portp->brdnr < 0 || portp->brdnr >= stli_nrbrds)
return;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
return;
memset(&actrl, 0, sizeof(asyctrl_t));
@@ -2460,7 +2168,6 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
actrl.txctrl = CT_SENDCHR;
actrl.tximdch = ch;
}
-
stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);
}
@@ -2476,17 +2183,17 @@ static void stli_sendxchar(struct tty_struct *tty, char ch)
static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *pos)
{
- char *sp, *uart;
- int rc, cnt;
+ char *sp, *uart;
+ int rc, cnt;
rc = stli_portcmdstats(portp);
uart = "UNKNOWN";
if (brdp->state & BST_STARTED) {
switch (stli_comstats.hwid) {
- case 0: uart = "2681"; break;
- case 1: uart = "SC26198"; break;
- default: uart = "CD1400"; break;
+ case 0: uart = "2681"; break;
+ case 1: uart = "SC26198"; break;
+ default:uart = "CD1400"; break;
}
}
@@ -2537,17 +2244,11 @@ static int stli_portinfo(stlibrd_t *brdp, stliport_t *portp, int portnr, char *p
static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- stlibrd_t *brdp;
- stliport_t *portp;
- int brdnr, portnr, totalport;
- int curoff, maxoff;
- char *pos;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_readproc(page=%x,start=%x,off=%x,count=%d,eof=%x,"
- "data=%x\n", (int) page, (int) start, (int) off, count,
- (int) eof, (int) data);
-#endif
+ stlibrd_t *brdp;
+ stliport_t *portp;
+ int brdnr, portnr, totalport;
+ int curoff, maxoff;
+ char *pos;
pos = page;
totalport = 0;
@@ -2568,7 +2269,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
*/
for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
brdp = stli_brds[brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
continue;
if (brdp->state == 0)
continue;
@@ -2583,7 +2284,7 @@ static int stli_readproc(char *page, char **start, off_t off, int count, int *eo
for (portnr = 0; (portnr < brdp->nrports); portnr++,
totalport++) {
portp = brdp->ports[portnr];
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
continue;
if (off >= (curoff += MAXLINE))
continue;
@@ -2610,49 +2311,54 @@ stli_readdone:
* a poll routine that does not have user context. Therefore you cannot
* copy back directly into user space, or to the kernel stack of a
* process. This routine does not sleep, so can be called from anywhere.
+ *
+ * The caller must hold the brd_lock (see also stli_sendcmd the usual
+ * entry point)
*/
-static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+static void __stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
{
- volatile cdkhdr_t *hdrp;
- volatile cdkctrl_t *cp;
- volatile unsigned char *bits;
- unsigned long flags;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_sendcmd(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d,"
- "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd,
- (int) arg, size, copyback);
-#endif
+ cdkhdr_t __iomem *hdrp;
+ cdkctrl_t __iomem *cp;
+ unsigned char __iomem *bits;
+ unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
if (test_bit(ST_CMDING, &portp->state)) {
printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n",
(int) cmd);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
return;
}
EBRDENABLE(brdp);
- cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
+ cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl;
if (size > 0) {
- memcpy((void *) &(cp->args[0]), arg, size);
+ memcpy_toio((void __iomem *) &(cp->args[0]), arg, size);
if (copyback) {
portp->argp = arg;
portp->argsize = size;
}
}
- cp->status = 0;
- cp->cmd = cmd;
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset +
+ writel(0, &cp->status);
+ writel(cmd, &cp->cmd);
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset +
portp->portidx;
- *bits |= portp->portbit;
+ writeb(readb(bits) | portp->portbit, bits);
set_bit(ST_CMDING, &portp->state);
EBRDDISABLE(brdp);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
+}
+
+static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&brd_lock, flags);
+ __stli_sendcmd(brdp, portp, cmd, arg, size, copyback);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -2667,28 +2373,23 @@ static void stli_sendcmd(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd,
static void stli_read(stlibrd_t *brdp, stliport_t *portp)
{
- volatile cdkasyrq_t *rp;
- volatile char *shbuf;
+ cdkasyrq_t __iomem *rp;
+ char __iomem *shbuf;
struct tty_struct *tty;
- unsigned int head, tail, size;
- unsigned int len, stlen;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_read(brdp=%x,portp=%d)\n",
- (int) brdp, (int) portp);
-#endif
+ unsigned int head, tail, size;
+ unsigned int len, stlen;
if (test_bit(ST_RXSTOP, &portp->state))
return;
tty = portp->tty;
- if (tty == (struct tty_struct *) NULL)
+ if (tty == NULL)
return;
- rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
- head = (unsigned int) rp->head;
- if (head != ((unsigned int) rp->head))
- head = (unsigned int) rp->head;
- tail = (unsigned int) rp->tail;
+ rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
+ head = (unsigned int) readw(&rp->head);
+ if (head != ((unsigned int) readw(&rp->head)))
+ head = (unsigned int) readw(&rp->head);
+ tail = (unsigned int) readw(&rp->tail);
size = portp->rxsize;
if (head >= tail) {
len = head - tail;
@@ -2699,12 +2400,15 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
}
len = tty_buffer_request_room(tty, len);
- /* FIXME : iomap ? */
- shbuf = (volatile char *) EBRDGETMEMPTR(brdp, portp->rxoffset);
+
+ shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->rxoffset);
while (len > 0) {
+ unsigned char *cptr;
+
stlen = MIN(len, stlen);
- tty_insert_flip_string(tty, (char *)(shbuf + tail), stlen);
+ tty_prepare_flip_string(tty, &cptr, stlen);
+ memcpy_fromio(cptr, shbuf + tail, stlen);
len -= stlen;
tail += stlen;
if (tail >= size) {
@@ -2712,8 +2416,8 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
stlen = head;
}
}
- rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
- rp->tail = tail;
+ rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq;
+ writew(tail, &rp->tail);
if (head != tail)
set_bit(ST_RXING, &portp->state);
@@ -2729,9 +2433,9 @@ static void stli_read(stlibrd_t *brdp, stliport_t *portp)
* difficult to deal with them here.
*/
-static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
+static void stli_dodelaycmd(stliport_t *portp, cdkctrl_t __iomem *cp)
{
- int cmd;
+ int cmd;
if (test_bit(ST_DOSIGS, &portp->state)) {
if (test_bit(ST_DOFLUSHTX, &portp->state) &&
@@ -2746,10 +2450,10 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
clear_bit(ST_DOFLUSHTX, &portp->state);
clear_bit(ST_DOFLUSHRX, &portp->state);
clear_bit(ST_DOSIGS, &portp->state);
- memcpy((void *) &(cp->args[0]), (void *) &portp->asig,
+ memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &portp->asig,
sizeof(asysigs_t));
- cp->status = 0;
- cp->cmd = cmd;
+ writel(0, &cp->status);
+ writel(cmd, &cp->cmd);
set_bit(ST_CMDING, &portp->state);
} else if (test_bit(ST_DOFLUSHTX, &portp->state) ||
test_bit(ST_DOFLUSHRX, &portp->state)) {
@@ -2757,9 +2461,9 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
cmd |= ((test_bit(ST_DOFLUSHRX, &portp->state)) ? FLUSHRX : 0);
clear_bit(ST_DOFLUSHTX, &portp->state);
clear_bit(ST_DOFLUSHRX, &portp->state);
- memcpy((void *) &(cp->args[0]), (void *) &cmd, sizeof(int));
- cp->status = 0;
- cp->cmd = A_FLUSH;
+ memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &cmd, sizeof(int));
+ writel(0, &cp->status);
+ writel(A_FLUSH, &cp->cmd);
set_bit(ST_CMDING, &portp->state);
}
}
@@ -2779,30 +2483,25 @@ static void stli_dodelaycmd(stliport_t *portp, volatile cdkctrl_t *cp)
static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
{
- volatile cdkasy_t *ap;
- volatile cdkctrl_t *cp;
- struct tty_struct *tty;
- asynotify_t nt;
- unsigned long oldsigs;
- int rc, donerx;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_hostcmd(brdp=%x,channr=%d)\n",
- (int) brdp, channr);
-#endif
-
- ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
+ cdkasy_t __iomem *ap;
+ cdkctrl_t __iomem *cp;
+ struct tty_struct *tty;
+ asynotify_t nt;
+ unsigned long oldsigs;
+ int rc, donerx;
+
+ ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
cp = &ap->ctrl;
/*
* Check if we are waiting for an open completion message.
*/
if (test_bit(ST_OPENING, &portp->state)) {
- rc = (int) cp->openarg;
- if ((cp->open == 0) && (rc != 0)) {
+ rc = readl(&cp->openarg);
+ if (readb(&cp->open) == 0 && rc != 0) {
if (rc > 0)
rc--;
- cp->openarg = 0;
+ writel(0, &cp->openarg);
portp->rc = rc;
clear_bit(ST_OPENING, &portp->state);
wake_up_interruptible(&portp->raw_wait);
@@ -2813,11 +2512,11 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
* Check if we are waiting for a close completion message.
*/
if (test_bit(ST_CLOSING, &portp->state)) {
- rc = (int) cp->closearg;
- if ((cp->close == 0) && (rc != 0)) {
+ rc = (int) readl(&cp->closearg);
+ if (readb(&cp->close) == 0 && rc != 0) {
if (rc > 0)
rc--;
- cp->closearg = 0;
+ writel(0, &cp->closearg);
portp->rc = rc;
clear_bit(ST_CLOSING, &portp->state);
wake_up_interruptible(&portp->raw_wait);
@@ -2829,16 +2528,16 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
* need to copy out the command results associated with this command.
*/
if (test_bit(ST_CMDING, &portp->state)) {
- rc = cp->status;
- if ((cp->cmd == 0) && (rc != 0)) {
+ rc = readl(&cp->status);
+ if (readl(&cp->cmd) == 0 && rc != 0) {
if (rc > 0)
rc--;
- if (portp->argp != (void *) NULL) {
- memcpy(portp->argp, (void *) &(cp->args[0]),
+ if (portp->argp != NULL) {
+ memcpy_fromio(portp->argp, (void __iomem *) &(cp->args[0]),
portp->argsize);
- portp->argp = (void *) NULL;
+ portp->argp = NULL;
}
- cp->status = 0;
+ writel(0, &cp->status);
portp->rc = rc;
clear_bit(ST_CMDING, &portp->state);
stli_dodelaycmd(portp, cp);
@@ -2877,18 +2576,15 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
if (nt.data & DT_TXEMPTY)
clear_bit(ST_TXBUSY, &portp->state);
if (nt.data & (DT_TXEMPTY | DT_TXLOW)) {
- if (tty != (struct tty_struct *) NULL) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup) {
- (tty->ldisc.write_wakeup)(tty);
- EBRDENABLE(brdp);
- }
+ if (tty != NULL) {
+ tty_wakeup(tty);
+ EBRDENABLE(brdp);
wake_up_interruptible(&tty->write_wait);
}
}
if ((nt.data & DT_RXBREAK) && (portp->rxmarkmsk & BRKINT)) {
- if (tty != (struct tty_struct *) NULL) {
+ if (tty != NULL) {
tty_insert_flip_char(tty, 0, TTY_BREAK);
if (portp->flags & ASYNC_SAK) {
do_SAK(tty);
@@ -2932,14 +2628,14 @@ static int stli_hostcmd(stlibrd_t *brdp, stliport_t *portp)
* at the cdk header structure.
*/
-static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
+static void stli_brdpoll(stlibrd_t *brdp, cdkhdr_t __iomem *hdrp)
{
- stliport_t *portp;
- unsigned char hostbits[(STL_MAXCHANS / 8) + 1];
- unsigned char slavebits[(STL_MAXCHANS / 8) + 1];
- unsigned char *slavep;
- int bitpos, bitat, bitsize;
- int channr, nrdevs, slavebitchange;
+ stliport_t *portp;
+ unsigned char hostbits[(STL_MAXCHANS / 8) + 1];
+ unsigned char slavebits[(STL_MAXCHANS / 8) + 1];
+ unsigned char __iomem *slavep;
+ int bitpos, bitat, bitsize;
+ int channr, nrdevs, slavebitchange;
bitsize = brdp->bitsize;
nrdevs = brdp->nrdevs;
@@ -2951,7 +2647,7 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
* 8 service bits at a time in the inner loop, so we can bypass
* the lot if none of them want service.
*/
- memcpy(&hostbits[0], (((unsigned char *) hdrp) + brdp->hostoffset),
+ memcpy_fromio(&hostbits[0], (((unsigned char __iomem *) hdrp) + brdp->hostoffset),
bitsize);
memset(&slavebits[0], 0, bitsize);
@@ -2978,11 +2674,11 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
* service may initiate more slave requests.
*/
if (slavebitchange) {
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- slavep = ((unsigned char *) hdrp) + brdp->slaveoffset;
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ slavep = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset;
for (bitpos = 0; (bitpos < bitsize); bitpos++) {
- if (slavebits[bitpos])
- slavep[bitpos] &= ~slavebits[bitpos];
+ if (readb(slavebits + bitpos))
+ writeb(readb(slavep + bitpos) & ~slavebits[bitpos], slavebits + bitpos);
}
}
}
@@ -3000,9 +2696,9 @@ static void stli_brdpoll(stlibrd_t *brdp, volatile cdkhdr_t *hdrp)
static void stli_poll(unsigned long arg)
{
- volatile cdkhdr_t *hdrp;
- stlibrd_t *brdp;
- int brdnr;
+ cdkhdr_t __iomem *hdrp;
+ stlibrd_t *brdp;
+ int brdnr;
stli_timerlist.expires = STLI_TIMEOUT;
add_timer(&stli_timerlist);
@@ -3012,16 +2708,18 @@ static void stli_poll(unsigned long arg)
*/
for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) {
brdp = stli_brds[brdnr];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
continue;
if ((brdp->state & BST_STARTED) == 0)
continue;
+ spin_lock(&brd_lock);
EBRDENABLE(brdp);
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
- if (hdrp->hostreq)
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ if (readb(&hdrp->hostreq))
stli_brdpoll(brdp, hdrp);
EBRDDISABLE(brdp);
+ spin_unlock(&brd_lock);
}
}
@@ -3034,25 +2732,12 @@ static void stli_poll(unsigned long arg)
static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tiosp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_mkasyport(portp=%x,pp=%x,tiosp=%d)\n",
- (int) portp, (int) pp, (int) tiosp);
-#endif
-
memset(pp, 0, sizeof(asyport_t));
/*
* Start of by setting the baud, char size, parity and stop bit info.
*/
- pp->baudout = tiosp->c_cflag & CBAUD;
- if (pp->baudout & CBAUDEX) {
- pp->baudout &= ~CBAUDEX;
- if ((pp->baudout < 1) || (pp->baudout > 4))
- tiosp->c_cflag &= ~CBAUDEX;
- else
- pp->baudout += 15;
- }
- pp->baudout = stli_baudrates[pp->baudout];
+ pp->baudout = tty_get_baud_rate(portp->tty);
if ((tiosp->c_cflag & CBAUD) == B38400) {
if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
pp->baudout = 57600;
@@ -3157,11 +2842,6 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_mkasysigs(sp=%x,dtr=%d,rts=%d)\n",
- (int) sp, dtr, rts);
-#endif
-
memset(sp, 0, sizeof(asysigs_t));
if (dtr >= 0) {
sp->signal |= SG_DTR;
@@ -3182,13 +2862,7 @@ static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts)
static long stli_mktiocm(unsigned long sigvalue)
{
- long tiocm;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_mktiocm(sigvalue=%x)\n", (int) sigvalue);
-#endif
-
- tiocm = 0;
+ long tiocm = 0;
tiocm |= ((sigvalue & SG_DCD) ? TIOCM_CD : 0);
tiocm |= ((sigvalue & SG_CTS) ? TIOCM_CTS : 0);
tiocm |= ((sigvalue & SG_RI) ? TIOCM_RI : 0);
@@ -3210,10 +2884,6 @@ static int stli_initports(stlibrd_t *brdp)
stliport_t *portp;
int i, panelnr, panelport;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_initports(brdp=%x)\n", (int) brdp);
-#endif
-
for (i = 0, panelnr = 0, panelport = 0; (i < brdp->nrports); i++) {
portp = kzalloc(sizeof(stliport_t), GFP_KERNEL);
if (!portp) {
@@ -3240,7 +2910,7 @@ static int stli_initports(stlibrd_t *brdp)
brdp->ports[i] = portp;
}
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -3253,10 +2923,6 @@ static void stli_ecpinit(stlibrd_t *brdp)
{
unsigned long memconf;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpinit(brdp=%d)\n", (int) brdp);
-#endif
-
outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
udelay(10);
outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
@@ -3270,9 +2936,6 @@ static void stli_ecpinit(stlibrd_t *brdp)
static void stli_ecpenable(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpenable(brdp=%x)\n", (int) brdp);
-#endif
outb(ECP_ATENABLE, (brdp->iobase + ECP_ATCONFR));
}
@@ -3280,9 +2943,6 @@ static void stli_ecpenable(stlibrd_t *brdp)
static void stli_ecpdisable(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpdisable(brdp=%x)\n", (int) brdp);
-#endif
outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
}
@@ -3290,13 +2950,8 @@ static void stli_ecpdisable(stlibrd_t *brdp)
static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
- unsigned char val;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
- (int) offset);
-#endif
+ void *ptr;
+ unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3316,10 +2971,6 @@ static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_ecpreset(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpreset(brdp=%x)\n", (int) brdp);
-#endif
-
outb(ECP_ATSTOP, (brdp->iobase + ECP_ATCONFR));
udelay(10);
outb(ECP_ATDISABLE, (brdp->iobase + ECP_ATCONFR));
@@ -3330,9 +2981,6 @@ static void stli_ecpreset(stlibrd_t *brdp)
static void stli_ecpintr(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpintr(brdp=%x)\n", (int) brdp);
-#endif
outb(0x1, brdp->iobase);
}
@@ -3346,10 +2994,6 @@ static void stli_ecpeiinit(stlibrd_t *brdp)
{
unsigned long memconf;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpeiinit(brdp=%x)\n", (int) brdp);
-#endif
-
outb(0x1, (brdp->iobase + ECP_EIBRDENAB));
outb(ECP_EISTOP, (brdp->iobase + ECP_EICONFR));
udelay(10);
@@ -3383,11 +3027,6 @@ static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line
void *ptr;
unsigned char val;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecpeigetmemptr(brdp=%x,offset=%x,line=%d)\n",
- (int) brdp, (int) offset, line);
-#endif
-
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
@@ -3437,8 +3076,8 @@ static void stli_ecpmcdisable(stlibrd_t *brdp)
static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
- unsigned char val;
+ void *ptr;
+ unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3472,10 +3111,6 @@ static void stli_ecpmcreset(stlibrd_t *brdp)
static void stli_ecppciinit(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecppciinit(brdp=%x)\n", (int) brdp);
-#endif
-
outb(ECP_PCISTOP, (brdp->iobase + ECP_PCICONFR));
udelay(10);
outb(0, (brdp->iobase + ECP_PCICONFR));
@@ -3489,11 +3124,6 @@ static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int lin
void *ptr;
unsigned char val;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_ecppcigetmemptr(brdp=%x,offset=%x,line=%d)\n",
- (int) brdp, (int) offset, line);
-#endif
-
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
"range at line=%d(%d), board=%d\n",
@@ -3528,10 +3158,6 @@ static void stli_onbinit(stlibrd_t *brdp)
{
unsigned long memconf;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbinit(brdp=%d)\n", (int) brdp);
-#endif
-
outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
udelay(10);
outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
@@ -3547,9 +3173,6 @@ static void stli_onbinit(stlibrd_t *brdp)
static void stli_onbenable(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbenable(brdp=%x)\n", (int) brdp);
-#endif
outb((brdp->enabval | ONB_ATENABLE), (brdp->iobase + ONB_ATCONFR));
}
@@ -3557,9 +3180,6 @@ static void stli_onbenable(stlibrd_t *brdp)
static void stli_onbdisable(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbdisable(brdp=%x)\n", (int) brdp);
-#endif
outb((brdp->enabval | ONB_ATDISABLE), (brdp->iobase + ONB_ATCONFR));
}
@@ -3569,11 +3189,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
void *ptr;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
- (int) offset);
-#endif
-
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
"range at line=%d(%d), brd=%d\n",
@@ -3589,11 +3204,6 @@ static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_onbreset(stlibrd_t *brdp)
{
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbreset(brdp=%x)\n", (int) brdp);
-#endif
-
outb(ONB_ATSTOP, (brdp->iobase + ONB_ATCONFR));
udelay(10);
outb(ONB_ATDISABLE, (brdp->iobase + ONB_ATCONFR));
@@ -3610,10 +3220,6 @@ static void stli_onbeinit(stlibrd_t *brdp)
{
unsigned long memconf;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbeinit(brdp=%d)\n", (int) brdp);
-#endif
-
outb(0x1, (brdp->iobase + ONB_EIBRDENAB));
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
@@ -3632,9 +3238,6 @@ static void stli_onbeinit(stlibrd_t *brdp)
static void stli_onbeenable(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbeenable(brdp=%x)\n", (int) brdp);
-#endif
outb(ONB_EIENABLE, (brdp->iobase + ONB_EICONFR));
}
@@ -3642,9 +3245,6 @@ static void stli_onbeenable(stlibrd_t *brdp)
static void stli_onbedisable(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbedisable(brdp=%x)\n", (int) brdp);
-#endif
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
}
@@ -3652,13 +3252,8 @@ static void stli_onbedisable(stlibrd_t *brdp)
static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
- unsigned char val;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_onbegetmemptr(brdp=%x,offset=%x,line=%d)\n",
- (int) brdp, (int) offset, line);
-#endif
+ void *ptr;
+ unsigned char val;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3681,11 +3276,6 @@ static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_onbereset(stlibrd_t *brdp)
{
-
-#ifdef DEBUG
- printk(KERN_ERR "stli_onbereset(brdp=%x)\n", (int) brdp);
-#endif
-
outb(ONB_EISTOP, (brdp->iobase + ONB_EICONFR));
udelay(10);
outb(ONB_EIDISABLE, (brdp->iobase + ONB_EICONFR));
@@ -3700,11 +3290,6 @@ static void stli_onbereset(stlibrd_t *brdp)
static void stli_bbyinit(stlibrd_t *brdp)
{
-
-#ifdef DEBUG
- printk(KERN_ERR "stli_bbyinit(brdp=%d)\n", (int) brdp);
-#endif
-
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
outb(0, (brdp->iobase + BBY_ATCONFR));
@@ -3717,24 +3302,13 @@ static void stli_bbyinit(stlibrd_t *brdp)
static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
- unsigned char val;
+ void *ptr;
+ unsigned char val;
-#ifdef DEBUG
- printk(KERN_ERR "stli_bbygetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
- (int) offset);
-#endif
+ BUG_ON(offset > brdp->memsize);
- if (offset > brdp->memsize) {
- printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
- "range at line=%d(%d), brd=%d\n",
- (int) offset, line, __LINE__, brdp->brdnr);
- ptr = NULL;
- val = 0;
- } else {
- ptr = brdp->membase + (offset % BBY_PAGESIZE);
- val = (unsigned char) (offset / BBY_PAGESIZE);
- }
+ ptr = brdp->membase + (offset % BBY_PAGESIZE);
+ val = (unsigned char) (offset / BBY_PAGESIZE);
outb(val, (brdp->iobase + BBY_ATCONFR));
return(ptr);
}
@@ -3743,11 +3317,6 @@ static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
static void stli_bbyreset(stlibrd_t *brdp)
{
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_bbyreset(brdp=%x)\n", (int) brdp);
-#endif
-
outb(BBY_ATSTOP, (brdp->iobase + BBY_ATCONFR));
udelay(10);
outb(0, (brdp->iobase + BBY_ATCONFR));
@@ -3762,11 +3331,6 @@ static void stli_bbyreset(stlibrd_t *brdp)
static void stli_stalinit(stlibrd_t *brdp)
{
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_stalinit(brdp=%d)\n", (int) brdp);
-#endif
-
outb(0x1, brdp->iobase);
mdelay(1000);
}
@@ -3775,36 +3339,18 @@ static void stli_stalinit(stlibrd_t *brdp)
static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_stalgetmemptr(brdp=%x,offset=%x)\n", (int) brdp,
- (int) offset);
-#endif
-
- if (offset > brdp->memsize) {
- printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
- "range at line=%d(%d), brd=%d\n",
- (int) offset, line, __LINE__, brdp->brdnr);
- ptr = NULL;
- } else {
- ptr = brdp->membase + (offset % STAL_PAGESIZE);
- }
- return(ptr);
+ BUG_ON(offset > brdp->memsize);
+ return brdp->membase + (offset % STAL_PAGESIZE);
}
/*****************************************************************************/
static void stli_stalreset(stlibrd_t *brdp)
{
- volatile unsigned long *vecp;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_stalreset(brdp=%x)\n", (int) brdp);
-#endif
+ u32 __iomem *vecp;
- vecp = (volatile unsigned long *) (brdp->membase + 0x30);
- *vecp = 0xffff0000;
+ vecp = (u32 __iomem *) (brdp->membase + 0x30);
+ writel(0xffff0000, vecp);
outb(0, brdp->iobase);
mdelay(1000);
}
@@ -3818,15 +3364,11 @@ static void stli_stalreset(stlibrd_t *brdp)
static int stli_initecp(stlibrd_t *brdp)
{
- cdkecpsig_t sig;
- cdkecpsig_t *sigsp;
- unsigned int status, nxtid;
- char *name;
- int panelnr, nrports;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_initecp(brdp=%x)\n", (int) brdp);
-#endif
+ cdkecpsig_t sig;
+ cdkecpsig_t __iomem *sigsp;
+ unsigned int status, nxtid;
+ char *name;
+ int panelnr, nrports;
if (!request_region(brdp->iobase, brdp->iosize, "istallion"))
return -EIO;
@@ -3834,7 +3376,7 @@ static int stli_initecp(stlibrd_t *brdp)
if ((brdp->iobase == 0) || (brdp->memaddr == 0))
{
release_region(brdp->iobase, brdp->iosize);
- return(-ENODEV);
+ return -ENODEV;
}
brdp->iosize = ECP_IOSIZE;
@@ -3903,7 +3445,7 @@ static int stli_initecp(stlibrd_t *brdp)
default:
release_region(brdp->iobase, brdp->iosize);
- return(-EINVAL);
+ return -EINVAL;
}
/*
@@ -3915,10 +3457,10 @@ static int stli_initecp(stlibrd_t *brdp)
EBRDINIT(brdp);
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == (void *) NULL)
+ if (brdp->membase == NULL)
{
release_region(brdp->iobase, brdp->iosize);
- return(-ENOMEM);
+ return -ENOMEM;
}
/*
@@ -3927,23 +3469,14 @@ static int stli_initecp(stlibrd_t *brdp)
* this is, and what it is connected to it.
*/
EBRDENABLE(brdp);
- sigsp = (cdkecpsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
- memcpy(&sig, sigsp, sizeof(cdkecpsig_t));
+ sigsp = (cdkecpsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+ memcpy_fromio(&sig, sigsp, sizeof(cdkecpsig_t));
EBRDDISABLE(brdp);
-#if 0
- printk("%s(%d): sig-> magic=%x rom=%x panel=%x,%x,%x,%x,%x,%x,%x,%x\n",
- __FILE__, __LINE__, (int) sig.magic, sig.romver, sig.panelid[0],
- (int) sig.panelid[1], (int) sig.panelid[2],
- (int) sig.panelid[3], (int) sig.panelid[4],
- (int) sig.panelid[5], (int) sig.panelid[6],
- (int) sig.panelid[7]);
-#endif
-
- if (sig.magic != ECP_MAGIC)
+ if (sig.magic != cpu_to_le32(ECP_MAGIC))
{
release_region(brdp->iobase, brdp->iosize);
- return(-ENODEV);
+ return -ENODEV;
}
/*
@@ -3967,7 +3500,7 @@ static int stli_initecp(stlibrd_t *brdp)
brdp->state |= BST_FOUND;
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -3979,20 +3512,16 @@ static int stli_initecp(stlibrd_t *brdp)
static int stli_initonb(stlibrd_t *brdp)
{
- cdkonbsig_t sig;
- cdkonbsig_t *sigsp;
- char *name;
- int i;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_initonb(brdp=%x)\n", (int) brdp);
-#endif
+ cdkonbsig_t sig;
+ cdkonbsig_t __iomem *sigsp;
+ char *name;
+ int i;
/*
* Do a basic sanity check on the IO and memory addresses.
*/
- if ((brdp->iobase == 0) || (brdp->memaddr == 0))
- return(-ENODEV);
+ if (brdp->iobase == 0 || brdp->memaddr == 0)
+ return -ENODEV;
brdp->iosize = ONB_IOSIZE;
@@ -4010,7 +3539,6 @@ static int stli_initonb(stlibrd_t *brdp)
case BRD_ONBOARD2:
case BRD_ONBOARD2_32:
case BRD_ONBOARDRS:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ONB_MEMSIZE;
brdp->pagesize = ONB_ATPAGESIZE;
brdp->init = stli_onbinit;
@@ -4028,7 +3556,6 @@ static int stli_initonb(stlibrd_t *brdp)
break;
case BRD_ONBOARDE:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = ONB_EIMEMSIZE;
brdp->pagesize = ONB_EIPAGESIZE;
brdp->init = stli_onbeinit;
@@ -4044,7 +3571,6 @@ static int stli_initonb(stlibrd_t *brdp)
case BRD_BRUMBY4:
case BRD_BRUMBY8:
case BRD_BRUMBY16:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = BBY_MEMSIZE;
brdp->pagesize = BBY_PAGESIZE;
brdp->init = stli_bbyinit;
@@ -4058,7 +3584,6 @@ static int stli_initonb(stlibrd_t *brdp)
break;
case BRD_STALLION:
- brdp->membase = (void *) brdp->memaddr;
brdp->memsize = STAL_MEMSIZE;
brdp->pagesize = STAL_PAGESIZE;
brdp->init = stli_stalinit;
@@ -4073,7 +3598,7 @@ static int stli_initonb(stlibrd_t *brdp)
default:
release_region(brdp->iobase, brdp->iosize);
- return(-EINVAL);
+ return -EINVAL;
}
/*
@@ -4085,10 +3610,10 @@ static int stli_initonb(stlibrd_t *brdp)
EBRDINIT(brdp);
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == (void *) NULL)
+ if (brdp->membase == NULL)
{
release_region(brdp->iobase, brdp->iosize);
- return(-ENOMEM);
+ return -ENOMEM;
}
/*
@@ -4097,21 +3622,17 @@ static int stli_initonb(stlibrd_t *brdp)
* this is, and how many ports.
*/
EBRDENABLE(brdp);
- sigsp = (cdkonbsig_t *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
- memcpy(&sig, sigsp, sizeof(cdkonbsig_t));
+ sigsp = (cdkonbsig_t __iomem *) EBRDGETMEMPTR(brdp, CDK_SIGADDR);
+ memcpy_fromio(&sig, sigsp, sizeof(cdkonbsig_t));
EBRDDISABLE(brdp);
-#if 0
- printk("%s(%d): sig-> magic=%x:%x:%x:%x romver=%x amask=%x:%x:%x\n",
- __FILE__, __LINE__, sig.magic0, sig.magic1, sig.magic2,
- sig.magic3, sig.romver, sig.amask0, sig.amask1, sig.amask2);
-#endif
-
- if ((sig.magic0 != ONB_MAGIC0) || (sig.magic1 != ONB_MAGIC1) ||
- (sig.magic2 != ONB_MAGIC2) || (sig.magic3 != ONB_MAGIC3))
+ if (sig.magic0 != cpu_to_le16(ONB_MAGIC0) ||
+ sig.magic1 != cpu_to_le16(ONB_MAGIC1) ||
+ sig.magic2 != cpu_to_le16(ONB_MAGIC2) ||
+ sig.magic3 != cpu_to_le16(ONB_MAGIC3))
{
release_region(brdp->iobase, brdp->iosize);
- return(-ENODEV);
+ return -ENODEV;
}
/*
@@ -4132,7 +3653,7 @@ static int stli_initonb(stlibrd_t *brdp)
brdp->state |= BST_FOUND;
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4145,31 +3666,25 @@ static int stli_initonb(stlibrd_t *brdp)
static int stli_startbrd(stlibrd_t *brdp)
{
- volatile cdkhdr_t *hdrp;
- volatile cdkmem_t *memp;
- volatile cdkasy_t *ap;
- unsigned long flags;
- stliport_t *portp;
- int portnr, nrdevs, i, rc;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_startbrd(brdp=%x)\n", (int) brdp);
-#endif
-
- rc = 0;
-
- save_flags(flags);
- cli();
+ cdkhdr_t __iomem *hdrp;
+ cdkmem_t __iomem *memp;
+ cdkasy_t __iomem *ap;
+ unsigned long flags;
+ stliport_t *portp;
+ int portnr, nrdevs, i, rc = 0;
+ u32 memoff;
+
+ spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
+ hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR);
nrdevs = hdrp->nrdevs;
#if 0
printk("%s(%d): CDK version %d.%d.%d --> "
"nrdevs=%d memp=%x hostp=%x slavep=%x\n",
- __FILE__, __LINE__, hdrp->ver_release, hdrp->ver_modification,
- hdrp->ver_fix, nrdevs, (int) hdrp->memp, (int) hdrp->hostp,
- (int) hdrp->slavep);
+ __FILE__, __LINE__, readb(&hdrp->ver_release), readb(&hdrp->ver_modification),
+ readb(&hdrp->ver_fix), nrdevs, (int) readl(&hdrp->memp), readl(&hdrp->hostp),
+ readl(&hdrp->slavep));
#endif
if (nrdevs < (brdp->nrports + 1)) {
@@ -4181,14 +3696,14 @@ static int stli_startbrd(stlibrd_t *brdp)
brdp->hostoffset = hdrp->hostp - CDK_CDKADDR;
brdp->slaveoffset = hdrp->slavep - CDK_CDKADDR;
brdp->bitsize = (nrdevs + 7) / 8;
- memp = (volatile cdkmem_t *) hdrp->memp;
- if (((unsigned long) memp) > brdp->memsize) {
+ memoff = readl(&hdrp->memp);
+ if (memoff > brdp->memsize) {
printk(KERN_ERR "STALLION: corrupted shared memory region?\n");
rc = -EIO;
goto stli_donestartup;
}
- memp = (volatile cdkmem_t *) EBRDGETMEMPTR(brdp, (unsigned long) memp);
- if (memp->dtype != TYP_ASYNCTRL) {
+ memp = (cdkmem_t __iomem *) EBRDGETMEMPTR(brdp, memoff);
+ if (readw(&memp->dtype) != TYP_ASYNCTRL) {
printk(KERN_ERR "STALLION: no slave control device found\n");
goto stli_donestartup;
}
@@ -4200,19 +3715,19 @@ static int stli_startbrd(stlibrd_t *brdp)
* change pages while reading memory map.
*/
for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++, memp++) {
- if (memp->dtype != TYP_ASYNC)
+ if (readw(&memp->dtype) != TYP_ASYNC)
break;
portp = brdp->ports[portnr];
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
break;
portp->devnr = i;
- portp->addr = memp->offset;
+ portp->addr = readl(&memp->offset);
portp->reqbit = (unsigned char) (0x1 << (i * 8 / nrdevs));
portp->portidx = (unsigned char) (i / 8);
portp->portbit = (unsigned char) (0x1 << (i % 8));
}
- hdrp->slavereq = 0xff;
+ writeb(0xff, &hdrp->slavereq);
/*
* For each port setup a local copy of the RX and TX buffer offsets
@@ -4221,22 +3736,22 @@ static int stli_startbrd(stlibrd_t *brdp)
*/
for (i = 1, portnr = 0; (i < nrdevs); i++, portnr++) {
portp = brdp->ports[portnr];
- if (portp == (stliport_t *) NULL)
+ if (portp == NULL)
break;
if (portp->addr == 0)
break;
- ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr);
- if (ap != (volatile cdkasy_t *) NULL) {
- portp->rxsize = ap->rxq.size;
- portp->txsize = ap->txq.size;
- portp->rxoffset = ap->rxq.offset;
- portp->txoffset = ap->txq.offset;
+ ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr);
+ if (ap != NULL) {
+ portp->rxsize = readw(&ap->rxq.size);
+ portp->txsize = readw(&ap->txq.size);
+ portp->rxoffset = readl(&ap->rxq.offset);
+ portp->txoffset = readl(&ap->txq.offset);
}
}
stli_donestartup:
EBRDDISABLE(brdp);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
if (rc == 0)
brdp->state |= BST_STARTED;
@@ -4247,7 +3762,7 @@ stli_donestartup:
add_timer(&stli_timerlist);
}
- return(rc);
+ return rc;
}
/*****************************************************************************/
@@ -4258,10 +3773,6 @@ stli_donestartup:
static int __init stli_brdinit(stlibrd_t *brdp)
{
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_brdinit(brdp=%x)\n", (int) brdp);
-#endif
-
stli_brds[brdp->brdnr] = brdp;
switch (brdp->brdtype) {
@@ -4289,11 +3800,11 @@ static int __init stli_brdinit(stlibrd_t *brdp)
case BRD_ECHPCI:
printk(KERN_ERR "STALLION: %s board type not supported in "
"this driver\n", stli_brdnames[brdp->brdtype]);
- return(ENODEV);
+ return -ENODEV;
default:
printk(KERN_ERR "STALLION: board=%d is unknown board "
"type=%d\n", brdp->brdnr, brdp->brdtype);
- return(ENODEV);
+ return -ENODEV;
}
if ((brdp->state & BST_FOUND) == 0) {
@@ -4301,7 +3812,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
"io=%x mem=%x\n",
stli_brdnames[brdp->brdtype], brdp->brdnr,
brdp->iobase, (int) brdp->memaddr);
- return(ENODEV);
+ return -ENODEV;
}
stli_initports(brdp);
@@ -4309,7 +3820,7 @@ static int __init stli_brdinit(stlibrd_t *brdp)
"nrpanels=%d nrports=%d\n", stli_brdnames[brdp->brdtype],
brdp->brdnr, brdp->iobase, (int) brdp->memaddr,
brdp->nrpanels, brdp->nrports);
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4321,14 +3832,10 @@ static int __init stli_brdinit(stlibrd_t *brdp)
static int stli_eisamemprobe(stlibrd_t *brdp)
{
- cdkecpsig_t ecpsig, *ecpsigp;
- cdkonbsig_t onbsig, *onbsigp;
+ cdkecpsig_t ecpsig, __iomem *ecpsigp;
+ cdkonbsig_t onbsig, __iomem *onbsigp;
int i, foundit;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_eisamemprobe(brdp=%x)\n", (int) brdp);
-#endif
-
/*
* First up we reset the board, to get it into a known state. There
* is only 2 board types here we need to worry about. Don;t use the
@@ -4352,7 +3859,7 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
mdelay(1);
stli_onbeenable(brdp);
} else {
- return(-ENODEV);
+ return -ENODEV;
}
foundit = 0;
@@ -4364,25 +3871,24 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
*/
for (i = 0; (i < stli_eisamempsize); i++) {
brdp->memaddr = stli_eisamemprobeaddrs[i];
- brdp->membase = (void *) brdp->memaddr;
brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
- if (brdp->membase == (void *) NULL)
+ if (brdp->membase == NULL)
continue;
if (brdp->brdtype == BRD_ECPE) {
- ecpsigp = (cdkecpsig_t *) stli_ecpeigetmemptr(brdp,
+ ecpsigp = (cdkecpsig_t __iomem *) stli_ecpeigetmemptr(brdp,
CDK_SIGADDR, __LINE__);
- memcpy(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
- if (ecpsig.magic == ECP_MAGIC)
+ memcpy_fromio(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
+ if (ecpsig.magic == cpu_to_le32(ECP_MAGIC))
foundit = 1;
} else {
- onbsigp = (cdkonbsig_t *) stli_onbegetmemptr(brdp,
+ onbsigp = (cdkonbsig_t __iomem *) stli_onbegetmemptr(brdp,
CDK_SIGADDR, __LINE__);
- memcpy(&onbsig, onbsigp, sizeof(cdkonbsig_t));
- if ((onbsig.magic0 == ONB_MAGIC0) &&
- (onbsig.magic1 == ONB_MAGIC1) &&
- (onbsig.magic2 == ONB_MAGIC2) &&
- (onbsig.magic3 == ONB_MAGIC3))
+ memcpy_fromio(&onbsig, onbsigp, sizeof(cdkonbsig_t));
+ if ((onbsig.magic0 == cpu_to_le16(ONB_MAGIC0)) &&
+ (onbsig.magic1 == cpu_to_le16(ONB_MAGIC1)) &&
+ (onbsig.magic2 == cpu_to_le16(ONB_MAGIC2)) &&
+ (onbsig.magic3 == cpu_to_le16(ONB_MAGIC3)))
foundit = 1;
}
@@ -4406,9 +3912,9 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
printk(KERN_ERR "STALLION: failed to probe shared memory "
"region for %s in EISA slot=%d\n",
stli_brdnames[brdp->brdtype], (brdp->iobase >> 12));
- return(-ENODEV);
+ return -ENODEV;
}
- return(0);
+ return 0;
}
static int stli_getbrdnr(void)
@@ -4439,22 +3945,16 @@ static int stli_getbrdnr(void)
static int stli_findeisabrds(void)
{
- stlibrd_t *brdp;
- unsigned int iobase, eid;
- int i;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_findeisabrds()\n");
-#endif
+ stlibrd_t *brdp;
+ unsigned int iobase, eid;
+ int i;
/*
- * Firstly check if this is an EISA system. Do this by probing for
- * the system board EISA ID. If this is not an EISA system then
+ * Firstly check if this is an EISA system. If this is not an EISA system then
* don't bother going any further!
*/
- outb(0xff, 0xc80);
- if (inb(0xc80) == 0xff)
- return(0);
+ if (EISA_bus)
+ return 0;
/*
* Looks like an EISA system, so go searching for EISA boards.
@@ -4472,7 +3972,7 @@ static int stli_findeisabrds(void)
*/
for (i = 0; (i < STL_MAXBRDS); i++) {
brdp = stli_brds[i];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
continue;
if (brdp->iobase == iobase)
break;
@@ -4484,10 +3984,10 @@ static int stli_findeisabrds(void)
* We have found a Stallion board and it is not configured already.
* Allocate a board structure and initialize it.
*/
- if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
- return(-ENOMEM);
+ if ((brdp = stli_allocbrd()) == NULL)
+ return -ENOMEM;
if ((brdp->brdnr = stli_getbrdnr()) < 0)
- return(-ENOMEM);
+ return -ENOMEM;
eid = inb(iobase + 0xc82);
if (eid == ECP_EISAID)
brdp->brdtype = BRD_ECPE;
@@ -4502,7 +4002,7 @@ static int stli_findeisabrds(void)
stli_brdinit(brdp);
}
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4523,32 +4023,18 @@ static int stli_findeisabrds(void)
static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
{
- stlibrd_t *brdp;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_initpcibrd(brdtype=%d,busnr=%x,devnr=%x)\n",
- brdtype, dev->bus->number, dev->devfn);
-#endif
+ stlibrd_t *brdp;
if (pci_enable_device(devp))
- return(-EIO);
- if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
- return(-ENOMEM);
+ return -EIO;
+ if ((brdp = stli_allocbrd()) == NULL)
+ return -ENOMEM;
if ((brdp->brdnr = stli_getbrdnr()) < 0) {
printk(KERN_INFO "STALLION: too many boards found, "
"maximum supported %d\n", STL_MAXBRDS);
- return(0);
+ return 0;
}
brdp->brdtype = brdtype;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "%s(%d): BAR[]=%lx,%lx,%lx,%lx\n", __FILE__, __LINE__,
- pci_resource_start(devp, 0),
- pci_resource_start(devp, 1),
- pci_resource_start(devp, 2),
- pci_resource_start(devp, 3));
-#endif
-
/*
* We have all resources from the board, so lets setup the actual
* board structure now.
@@ -4557,7 +4043,7 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
brdp->memaddr = pci_resource_start(devp, 2);
stli_brdinit(brdp);
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4569,20 +4055,12 @@ static int stli_initpcibrd(int brdtype, struct pci_dev *devp)
static int stli_findpcibrds(void)
{
- struct pci_dev *dev = NULL;
- int rc;
+ struct pci_dev *dev = NULL;
-#ifdef DEBUG
- printk("stli_findpcibrds()\n");
-#endif
-
- while ((dev = pci_find_device(PCI_VENDOR_ID_STALLION,
- PCI_DEVICE_ID_ECRA, dev))) {
- if ((rc = stli_initpcibrd(BRD_ECPPCI, dev)))
- return(rc);
+ while ((dev = pci_get_device(PCI_VENDOR_ID_STALLION, PCI_DEVICE_ID_ECRA, dev))) {
+ stli_initpcibrd(BRD_ECPPCI, dev);
}
-
- return(0);
+ return 0;
}
#endif
@@ -4595,17 +4073,16 @@ static int stli_findpcibrds(void)
static stlibrd_t *stli_allocbrd(void)
{
- stlibrd_t *brdp;
+ stlibrd_t *brdp;
brdp = kzalloc(sizeof(stlibrd_t), GFP_KERNEL);
if (!brdp) {
printk(KERN_ERR "STALLION: failed to allocate memory "
- "(size=%d)\n", sizeof(stlibrd_t));
+ "(size=%Zd)\n", sizeof(stlibrd_t));
return NULL;
}
-
brdp->magic = STLI_BOARDMAGIC;
- return(brdp);
+ return brdp;
}
/*****************************************************************************/
@@ -4617,13 +4094,9 @@ static stlibrd_t *stli_allocbrd(void)
static int stli_initbrds(void)
{
- stlibrd_t *brdp, *nxtbrdp;
- stlconf_t *confp;
- int i, j;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_initbrds()\n");
-#endif
+ stlibrd_t *brdp, *nxtbrdp;
+ stlconf_t *confp;
+ int i, j;
if (stli_nrbrds > STL_MAXBRDS) {
printk(KERN_INFO "STALLION: too many boards in configuration "
@@ -4638,11 +4111,9 @@ static int stli_initbrds(void)
*/
for (i = 0; (i < stli_nrbrds); i++) {
confp = &stli_brdconf[i];
-#ifdef MODULE
stli_parsebrd(confp, stli_brdsp[i]);
-#endif
- if ((brdp = stli_allocbrd()) == (stlibrd_t *) NULL)
- return(-ENOMEM);
+ if ((brdp = stli_allocbrd()) == NULL)
+ return -ENOMEM;
brdp->brdnr = i;
brdp->brdtype = confp->brdtype;
brdp->iobase = confp->ioaddr1;
@@ -4654,9 +4125,7 @@ static int stli_initbrds(void)
* Static configuration table done, so now use dynamic methods to
* see if any more boards should be configured.
*/
-#ifdef MODULE
stli_argbrds();
-#endif
if (STLI_EISAPROBE)
stli_findeisabrds();
#ifdef CONFIG_PCI
@@ -4672,11 +4141,11 @@ static int stli_initbrds(void)
if (stli_nrbrds > 1) {
for (i = 0; (i < stli_nrbrds); i++) {
brdp = stli_brds[i];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
continue;
for (j = i + 1; (j < stli_nrbrds); j++) {
nxtbrdp = stli_brds[j];
- if (nxtbrdp == (stlibrd_t *) NULL)
+ if (nxtbrdp == NULL)
continue;
if ((brdp->membase >= nxtbrdp->membase) &&
(brdp->membase <= (nxtbrdp->membase +
@@ -4691,7 +4160,7 @@ static int stli_initbrds(void)
if (stli_shared == 0) {
for (i = 0; (i < stli_nrbrds); i++) {
brdp = stli_brds[i];
- if (brdp == (stlibrd_t *) NULL)
+ if (brdp == NULL)
continue;
if (brdp->state & BST_FOUND) {
EBRDENABLE(brdp);
@@ -4701,7 +4170,7 @@ static int stli_initbrds(void)
}
}
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4714,48 +4183,55 @@ static int stli_initbrds(void)
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp)
{
- unsigned long flags;
- void *memptr;
- stlibrd_t *brdp;
- int brdnr, size, n;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_memread(fp=%x,buf=%x,count=%x,offp=%x)\n",
- (int) fp, (int) buf, count, (int) offp);
-#endif
+ unsigned long flags;
+ void *memptr;
+ stlibrd_t *brdp;
+ int brdnr, size, n;
+ void *p;
+ loff_t off = *offp;
brdnr = iminor(fp->f_dentry->d_inode);
if (brdnr >= stli_nrbrds)
- return(-ENODEV);
+ return -ENODEV;
brdp = stli_brds[brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
if (brdp->state == 0)
- return(-ENODEV);
- if (fp->f_pos >= brdp->memsize)
- return(0);
+ return -ENODEV;
+ if (off >= brdp->memsize || off + count < off)
+ return 0;
- size = MIN(count, (brdp->memsize - fp->f_pos));
+ size = MIN(count, (brdp->memsize - off));
+
+ /*
+ * Copy the data a page at a time
+ */
+
+ p = (void *)__get_free_page(GFP_KERNEL);
+ if(p == NULL)
+ return -ENOMEM;
- save_flags(flags);
- cli();
- EBRDENABLE(brdp);
while (size > 0) {
- memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos);
- n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize)));
- if (copy_to_user(buf, memptr, n)) {
+ spin_lock_irqsave(&brd_lock, flags);
+ EBRDENABLE(brdp);
+ memptr = (void *) EBRDGETMEMPTR(brdp, off);
+ n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = MIN(n, PAGE_SIZE);
+ memcpy_fromio(p, memptr, n);
+ EBRDDISABLE(brdp);
+ spin_unlock_irqrestore(&brd_lock, flags);
+ if (copy_to_user(buf, p, n)) {
count = -EFAULT;
goto out;
}
- fp->f_pos += n;
+ off += n;
buf += n;
size -= n;
}
out:
- EBRDDISABLE(brdp);
- restore_flags(flags);
-
- return(count);
+ *offp = off;
+ free_page((unsigned long)p);
+ return count;
}
/*****************************************************************************/
@@ -4764,54 +4240,65 @@ out:
* Code to handle an "staliomem" write operation. This device is the
* contents of the board shared memory. It is used for down loading
* the slave image (and debugging :-)
+ *
+ * FIXME: copy under lock
*/
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp)
{
- unsigned long flags;
- void *memptr;
- stlibrd_t *brdp;
- char __user *chbuf;
- int brdnr, size, n;
-
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_memwrite(fp=%x,buf=%x,count=%x,offp=%x)\n",
- (int) fp, (int) buf, count, (int) offp);
-#endif
+ unsigned long flags;
+ void *memptr;
+ stlibrd_t *brdp;
+ char __user *chbuf;
+ int brdnr, size, n;
+ void *p;
+ loff_t off = *offp;
brdnr = iminor(fp->f_dentry->d_inode);
+
if (brdnr >= stli_nrbrds)
- return(-ENODEV);
+ return -ENODEV;
brdp = stli_brds[brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
if (brdp->state == 0)
- return(-ENODEV);
- if (fp->f_pos >= brdp->memsize)
- return(0);
+ return -ENODEV;
+ if (off >= brdp->memsize || off + count < off)
+ return 0;
chbuf = (char __user *) buf;
- size = MIN(count, (brdp->memsize - fp->f_pos));
+ size = MIN(count, (brdp->memsize - off));
+
+ /*
+ * Copy the data a page at a time
+ */
+
+ p = (void *)__get_free_page(GFP_KERNEL);
+ if(p == NULL)
+ return -ENOMEM;
- save_flags(flags);
- cli();
- EBRDENABLE(brdp);
while (size > 0) {
- memptr = (void *) EBRDGETMEMPTR(brdp, fp->f_pos);
- n = MIN(size, (brdp->pagesize - (((unsigned long) fp->f_pos) % brdp->pagesize)));
- if (copy_from_user(memptr, chbuf, n)) {
- count = -EFAULT;
+ n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
+ n = MIN(n, PAGE_SIZE);
+ if (copy_from_user(p, chbuf, n)) {
+ if (count == 0)
+ count = -EFAULT;
goto out;
}
- fp->f_pos += n;
+ spin_lock_irqsave(&brd_lock, flags);
+ EBRDENABLE(brdp);
+ memptr = (void *) EBRDGETMEMPTR(brdp, off);
+ memcpy_toio(memptr, p, n);
+ EBRDDISABLE(brdp);
+ spin_unlock_irqrestore(&brd_lock, flags);
+ off += n;
chbuf += n;
size -= n;
}
out:
- EBRDDISABLE(brdp);
- restore_flags(flags);
-
- return(count);
+ free_page((unsigned long) p);
+ *offp = off;
+ return count;
}
/*****************************************************************************/
@@ -4822,16 +4309,16 @@ out:
static int stli_getbrdstats(combrd_t __user *bp)
{
- stlibrd_t *brdp;
- int i;
+ stlibrd_t *brdp;
+ int i;
if (copy_from_user(&stli_brdstats, bp, sizeof(combrd_t)))
return -EFAULT;
if (stli_brdstats.brd >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
brdp = stli_brds[stli_brdstats.brd];
- if (brdp == (stlibrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
memset(&stli_brdstats, 0, sizeof(combrd_t));
stli_brdstats.brd = brdp->brdnr;
@@ -4850,7 +4337,7 @@ static int stli_getbrdstats(combrd_t __user *bp)
if (copy_to_user(bp, &stli_brdstats, sizeof(combrd_t)))
return -EFAULT;
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4861,19 +4348,19 @@ static int stli_getbrdstats(combrd_t __user *bp)
static stliport_t *stli_getport(int brdnr, int panelnr, int portnr)
{
- stlibrd_t *brdp;
- int i;
+ stlibrd_t *brdp;
+ int i;
- if ((brdnr < 0) || (brdnr >= STL_MAXBRDS))
- return((stliport_t *) NULL);
+ if (brdnr < 0 || brdnr >= STL_MAXBRDS)
+ return NULL;
brdp = stli_brds[brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return((stliport_t *) NULL);
+ if (brdp == NULL)
+ return NULL;
for (i = 0; (i < panelnr); i++)
portnr += brdp->panels[i];
if ((portnr < 0) || (portnr >= brdp->nrports))
- return((stliport_t *) NULL);
- return(brdp->ports[portnr]);
+ return NULL;
+ return brdp->ports[portnr];
}
/*****************************************************************************/
@@ -4892,16 +4379,16 @@ static int stli_portcmdstats(stliport_t *portp)
memset(&stli_comstats, 0, sizeof(comstats_t));
- if (portp == (stliport_t *) NULL)
- return(-ENODEV);
+ if (portp == NULL)
+ return -ENODEV;
brdp = stli_brds[portp->brdnr];
- if (brdp == (stlibrd_t *) NULL)
- return(-ENODEV);
+ if (brdp == NULL)
+ return -ENODEV;
if (brdp->state & BST_STARTED) {
if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS,
&stli_cdkstats, sizeof(asystats_t), 1)) < 0)
- return(rc);
+ return rc;
} else {
memset(&stli_cdkstats, 0, sizeof(asystats_t));
}
@@ -4912,13 +4399,12 @@ static int stli_portcmdstats(stliport_t *portp)
stli_comstats.state = portp->state;
stli_comstats.flags = portp->flags;
- save_flags(flags);
- cli();
- if (portp->tty != (struct tty_struct *) NULL) {
+ spin_lock_irqsave(&brd_lock, flags);
+ if (portp->tty != NULL) {
if (portp->tty->driver_data == portp) {
stli_comstats.ttystate = portp->tty->flags;
- stli_comstats.rxbuffered = -1 /*portp->tty->flip.count*/;
- if (portp->tty->termios != (struct termios *) NULL) {
+ stli_comstats.rxbuffered = -1;
+ if (portp->tty->termios != NULL) {
stli_comstats.cflags = portp->tty->termios->c_cflag;
stli_comstats.iflags = portp->tty->termios->c_iflag;
stli_comstats.oflags = portp->tty->termios->c_oflag;
@@ -4926,7 +4412,7 @@ static int stli_portcmdstats(stliport_t *portp)
}
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
stli_comstats.txtotal = stli_cdkstats.txchars;
stli_comstats.rxtotal = stli_cdkstats.rxchars + stli_cdkstats.ringover;
@@ -4948,7 +4434,7 @@ static int stli_portcmdstats(stliport_t *portp)
stli_comstats.hwid = stli_cdkstats.hwid;
stli_comstats.signals = stli_mktiocm(stli_cdkstats.signals);
- return(0);
+ return 0;
}
/*****************************************************************************/
@@ -4961,8 +4447,8 @@ static int stli_portcmdstats(stliport_t *portp)
static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
{
- stlibrd_t *brdp;
- int rc;
+ stlibrd_t *brdp;
+ int rc;
if (!portp) {
if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t)))
@@ -4992,8 +4478,8 @@ static int stli_getportstats(stliport_t *portp, comstats_t __user *cp)
static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
{
- stlibrd_t *brdp;
- int rc;
+ stlibrd_t *brdp;
+ int rc;
if (!portp) {
if (copy_from_user(&stli_comstats, cp, sizeof(comstats_t)))
@@ -5031,7 +4517,7 @@ static int stli_clrportstats(stliport_t *portp, comstats_t __user *cp)
static int stli_getportstruct(stliport_t __user *arg)
{
- stliport_t *portp;
+ stliport_t *portp;
if (copy_from_user(&stli_dummyport, arg, sizeof(stliport_t)))
return -EFAULT;
@@ -5052,7 +4538,7 @@ static int stli_getportstruct(stliport_t __user *arg)
static int stli_getbrdstruct(stlibrd_t __user *arg)
{
- stlibrd_t *brdp;
+ stlibrd_t *brdp;
if (copy_from_user(&stli_dummybrd, arg, sizeof(stlibrd_t)))
return -EFAULT;
@@ -5076,15 +4562,10 @@ static int stli_getbrdstruct(stlibrd_t __user *arg)
static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
{
- stlibrd_t *brdp;
- int brdnr, rc, done;
+ stlibrd_t *brdp;
+ int brdnr, rc, done;
void __user *argp = (void __user *)arg;
-#ifdef DEBUG
- printk(KERN_DEBUG "stli_memioctl(ip=%x,fp=%x,cmd=%x,arg=%x)\n",
- (int) ip, (int) fp, cmd, (int) arg);
-#endif
-
/*
* First up handle the board independent ioctls.
*/
@@ -5115,7 +4596,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
}
if (done)
- return(rc);
+ return rc;
/*
* Now handle the board specific ioctls. These all depend on the
@@ -5123,12 +4604,12 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
*/
brdnr = iminor(ip);
if (brdnr >= STL_MAXBRDS)
- return(-ENODEV);
+ return -ENODEV;
brdp = stli_brds[brdnr];
if (!brdp)
- return(-ENODEV);
+ return -ENODEV;
if (brdp->state == 0)
- return(-ENODEV);
+ return -ENODEV;
switch (cmd) {
case STL_BINTR:
@@ -5152,8 +4633,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
rc = -ENOIOCTLCMD;
break;
}
-
- return(rc);
+ return rc;
}
static struct tty_operations stli_ops = {
@@ -5182,11 +4662,14 @@ static struct tty_operations stli_ops = {
/*****************************************************************************/
-int __init stli_init(void)
+static int __init stli_init(void)
{
int i;
printk(KERN_INFO "%s: version %s\n", stli_drvtitle, stli_drvversion);
+ spin_lock_init(&stli_lock);
+ spin_lock_init(&brd_lock);
+
stli_initbrds();
stli_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
@@ -5196,10 +4679,6 @@ int __init stli_init(void)
/*
* Allocate a temporary write buffer.
*/
- stli_tmpwritebuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
- if (!stli_tmpwritebuf)
- printk(KERN_ERR "STALLION: failed to allocate memory "
- "(size=%d)\n", STLI_TXBUFSIZE);
stli_txcookbuf = kmalloc(STLI_TXBUFSIZE, GFP_KERNEL);
if (!stli_txcookbuf)
printk(KERN_ERR "STALLION: failed to allocate memory "
@@ -5213,16 +4692,11 @@ int __init stli_init(void)
printk(KERN_ERR "STALLION: failed to register serial memory "
"device\n");
- devfs_mk_dir("staliomem");
istallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++) {
- devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "staliomem/%d", i);
+ for (i = 0; i < 4; i++)
class_device_create(istallion_class, NULL,
MKDEV(STL_SIOMEMMAJOR, i),
NULL, "staliomem%d", i);
- }
/*
* Set up the tty driver structure and register us as a driver.
@@ -5243,7 +4717,7 @@ int __init stli_init(void)
printk(KERN_ERR "STALLION: failed to register serial driver\n");
return -EBUSY;
}
- return(0);
+ return 0;
}
/*****************************************************************************/
diff --git a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c
index d1ed6ac950d..cde562d70c4 100644
--- a/drivers/char/ite_gpio.c
+++ b/drivers/char/ite_gpio.c
@@ -357,7 +357,7 @@ DEB(printk("interrupt 0x%x %d\n",ITE_GPAISR, i));
}
}
-static struct file_operations ite_gpio_fops = {
+static const struct file_operations ite_gpio_fops = {
.owner = THIS_MODULE,
.ioctl = ite_gpio_ioctl,
.open = ite_gpio_open,
@@ -397,7 +397,7 @@ int __init ite_gpio_init(void)
init_waitqueue_head(&ite_gpio_wait[i]);
}
- if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, SA_SHIRQ, "gpio", 0) < 0) {
+ if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, IRQF_SHARED, "gpio", 0) < 0) {
misc_deregister(&ite_gpio_miscdev);
release_region(ite_gpio_base, 0x1c);
return 0;
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 5755b7e5f18..3e90aac3751 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -24,7 +24,6 @@
* 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/tty.h>
@@ -39,6 +38,7 @@
#include <linux/vt_kern.h>
#include <linux/sysrq.h>
#include <linux/input.h>
+#include <linux/reboot.h>
static void kbd_disconnect(struct input_handle *handle);
extern void ctrl_alt_del(void);
@@ -107,7 +107,6 @@ const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
-static struct kbd_struct kbd0;
int spawnpid, spawnsig;
@@ -150,6 +149,7 @@ unsigned char kbd_sysrq_xlate[KEY_MAX + 1] =
"230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
"\r\000/"; /* 0x60 - 0x6f */
static int sysrq_down;
+static int sysrq_alt_use;
#endif
static int sysrq_alt;
@@ -222,13 +222,13 @@ static void kd_nosound(unsigned long ignored)
{
struct list_head *node;
- list_for_each(node,&kbd_handler.h_list) {
+ list_for_each(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node);
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit))
- input_event(handle->dev, EV_SND, SND_TONE, 0);
+ input_inject_event(handle, EV_SND, SND_TONE, 0);
if (test_bit(SND_BELL, handle->dev->sndbit))
- input_event(handle->dev, EV_SND, SND_BELL, 0);
+ input_inject_event(handle, EV_SND, SND_BELL, 0);
}
}
}
@@ -246,11 +246,11 @@ void kd_mksound(unsigned int hz, unsigned int ticks)
struct input_handle *handle = to_handle_h(node);
if (test_bit(EV_SND, handle->dev->evbit)) {
if (test_bit(SND_TONE, handle->dev->sndbit)) {
- input_event(handle->dev, EV_SND, SND_TONE, hz);
+ input_inject_event(handle, EV_SND, SND_TONE, hz);
break;
}
if (test_bit(SND_BELL, handle->dev->sndbit)) {
- input_event(handle->dev, EV_SND, SND_BELL, 1);
+ input_inject_event(handle, EV_SND, SND_BELL, 1);
break;
}
}
@@ -271,15 +271,15 @@ int kbd_rate(struct kbd_repeat *rep)
unsigned int d = 0;
unsigned int p = 0;
- list_for_each(node,&kbd_handler.h_list) {
+ list_for_each(node, &kbd_handler.h_list) {
struct input_handle *handle = to_handle_h(node);
struct input_dev *dev = handle->dev;
if (test_bit(EV_REP, dev->evbit)) {
if (rep->delay > 0)
- input_event(dev, EV_REP, REP_DELAY, rep->delay);
+ input_inject_event(handle, EV_REP, REP_DELAY, rep->delay);
if (rep->period > 0)
- input_event(dev, EV_REP, REP_PERIOD, rep->period);
+ input_inject_event(handle, EV_REP, REP_PERIOD, rep->period);
d = dev->rep[REP_DELAY];
p = dev->rep[REP_PERIOD];
}
@@ -672,7 +672,7 @@ static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struc
*/
static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
{
- static unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
+ static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
value = ret_diacr[value];
k_deadunicode(vc, value, up_flag, regs);
}
@@ -709,8 +709,8 @@ static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct
static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
{
- static const char *pad_chars = "0123456789+-*/\015,.?()#";
- static const char *app_map = "pqrstuvwxylSRQMnnmPQS";
+ static const char pad_chars[] = "0123456789+-*/\015,.?()#";
+ static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
if (up_flag)
return; /* no action, if this is a key release */
@@ -987,7 +987,7 @@ static inline unsigned char getleds(void)
* interrupt routines for this thing allows us to easily mask
* this when we don't want any of the above to happen.
* This allows for easy and efficient race-condition prevention
- * for kbd_refresh_leds => input_event(dev, EV_LED, ...) => ...
+ * for kbd_start => input_inject_event(dev, EV_LED, ...) => ...
*/
static void kbd_bh(unsigned long dummy)
@@ -997,11 +997,11 @@ static void kbd_bh(unsigned long dummy)
if (leds != ledstate) {
list_for_each(node, &kbd_handler.h_list) {
- struct input_handle * handle = to_handle_h(node);
- input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
- input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02));
- input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04));
- input_sync(handle->dev);
+ struct input_handle *handle = to_handle_h(node);
+ input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+ input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
+ input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
}
}
@@ -1010,23 +1010,6 @@ static void kbd_bh(unsigned long dummy)
DECLARE_TASKLET_DISABLED(keyboard_tasklet, kbd_bh, 0);
-/*
- * This allows a newly plugged keyboard to pick the LED state.
- */
-static void kbd_refresh_leds(struct input_handle *handle)
-{
- unsigned char leds = ledstate;
-
- tasklet_disable(&keyboard_tasklet);
- if (leds != 0xff) {
- input_event(handle->dev, EV_LED, LED_SCROLLL, !!(leds & 0x01));
- input_event(handle->dev, EV_LED, LED_NUML, !!(leds & 0x02));
- input_event(handle->dev, EV_LED, LED_CAPSL, !!(leds & 0x04));
- input_sync(handle->dev);
- }
- tasklet_enable(&keyboard_tasklet);
-}
-
#if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(CONFIG_ALPHA) ||\
defined(CONFIG_MIPS) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) ||\
defined(CONFIG_PARISC) || defined(CONFIG_SUPERH) ||\
@@ -1035,14 +1018,14 @@ static void kbd_refresh_leds(struct input_handle *handle)
#define HW_RAW(dev) (test_bit(EV_MSC, dev->evbit) && test_bit(MSC_RAW, dev->mscbit) &&\
((dev)->id.bustype == BUS_I8042) && ((dev)->id.vendor == 0x0001) && ((dev)->id.product == 0x0001))
-static unsigned short x86_keycodes[256] =
+static const unsigned short x86_keycodes[256] =
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
80, 81, 82, 83, 84,118, 86, 87, 88,115,120,119,121,112,123, 92,
- 284,285,309,298,312, 91,327,328,329,331,333,335,336,337,338,339,
+ 284,285,309, 0,312, 91,327,328,329,331,333,335,336,337,338,339,
367,288,302,304,350, 89,334,326,267,126,268,269,125,347,348,349,
360,261,262,263,268,376,100,101,321,316,373,286,289,102,351,355,
103,104,105,275,287,279,306,106,274,107,294,364,358,363,362,361,
@@ -1064,36 +1047,55 @@ extern void sun_do_break(void);
static int emulate_raw(struct vc_data *vc, unsigned int keycode,
unsigned char up_flag)
{
- if (keycode > 255 || !x86_keycodes[keycode])
- return -1;
+ int code;
switch (keycode) {
case KEY_PAUSE:
put_queue(vc, 0xe1);
put_queue(vc, 0x1d | up_flag);
put_queue(vc, 0x45 | up_flag);
- return 0;
- case KEY_HANGUEL:
- if (!up_flag) put_queue(vc, 0xf1);
- return 0;
+ break;
+
+ case KEY_HANGEUL:
+ if (!up_flag)
+ put_queue(vc, 0xf2);
+ break;
+
case KEY_HANJA:
- if (!up_flag) put_queue(vc, 0xf2);
- return 0;
- }
+ if (!up_flag)
+ put_queue(vc, 0xf1);
+ break;
- if (keycode == KEY_SYSRQ && sysrq_alt) {
- put_queue(vc, 0x54 | up_flag);
- return 0;
- }
+ case KEY_SYSRQ:
+ /*
+ * Real AT keyboards (that's what we're trying
+ * to emulate here emit 0xe0 0x2a 0xe0 0x37 when
+ * pressing PrtSc/SysRq alone, but simply 0x54
+ * when pressing Alt+PrtSc/SysRq.
+ */
+ if (sysrq_alt) {
+ put_queue(vc, 0x54 | up_flag);
+ } else {
+ put_queue(vc, 0xe0);
+ put_queue(vc, 0x2a | up_flag);
+ put_queue(vc, 0xe0);
+ put_queue(vc, 0x37 | up_flag);
+ }
+ break;
+
+ default:
+ if (keycode > 255)
+ return -1;
- if (x86_keycodes[keycode] & 0x100)
- put_queue(vc, 0xe0);
+ code = x86_keycodes[keycode];
+ if (!code)
+ return -1;
- put_queue(vc, (x86_keycodes[keycode] & 0x7f) | up_flag);
+ if (code & 0x100)
+ put_queue(vc, 0xe0);
+ put_queue(vc, (code & 0x7f) | up_flag);
- if (keycode == KEY_SYSRQ) {
- put_queue(vc, 0xe0);
- put_queue(vc, 0x37 | up_flag);
+ break;
}
return 0;
@@ -1142,7 +1144,7 @@ static void kbd_keycode(unsigned int keycode, int down,
kbd = kbd_table + fg_console;
if (keycode == KEY_LEFTALT || keycode == KEY_RIGHTALT)
- sysrq_alt = down;
+ sysrq_alt = down ? keycode : 0;
#ifdef CONFIG_SPARC
if (keycode == KEY_STOP)
sparc_l1_a_state = down;
@@ -1162,9 +1164,14 @@ static void kbd_keycode(unsigned int keycode, int down,
#ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */
if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) {
- sysrq_down = down;
+ if (!sysrq_down) {
+ sysrq_down = down;
+ sysrq_alt_use = sysrq_alt;
+ }
return;
}
+ if (sysrq_down && !down && keycode == sysrq_alt_use)
+ sysrq_down = 0;
if (sysrq_down && down && !rep) {
handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
return;
@@ -1290,16 +1297,15 @@ static struct input_handle *kbd_connect(struct input_handler *handler,
if (i == BTN_MISC && !test_bit(EV_SND, dev->evbit))
return NULL;
- if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL)))
+ handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
+ if (!handle)
return NULL;
- memset(handle, 0, sizeof(struct input_handle));
handle->dev = dev;
handle->handler = handler;
handle->name = "kbd";
input_open_device(handle);
- kbd_refresh_leds(handle);
return handle;
}
@@ -1310,6 +1316,24 @@ static void kbd_disconnect(struct input_handle *handle)
kfree(handle);
}
+/*
+ * Start keyboard handler on the new keyboard by refreshing LED state to
+ * match the rest of the system.
+ */
+static void kbd_start(struct input_handle *handle)
+{
+ unsigned char leds = ledstate;
+
+ tasklet_disable(&keyboard_tasklet);
+ if (leds != 0xff) {
+ input_inject_event(handle, EV_LED, LED_SCROLLL, !!(leds & 0x01));
+ input_inject_event(handle, EV_LED, LED_NUML, !!(leds & 0x02));
+ input_inject_event(handle, EV_LED, LED_CAPSL, !!(leds & 0x04));
+ input_inject_event(handle, EV_SYN, SYN_REPORT, 0);
+ }
+ tasklet_enable(&keyboard_tasklet);
+}
+
static struct input_device_id kbd_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
@@ -1330,6 +1354,7 @@ static struct input_handler kbd_handler = {
.event = kbd_event,
.connect = kbd_connect,
.disconnect = kbd_disconnect,
+ .start = kbd_start,
.name = "kbd",
.id_table = kbd_ids,
};
@@ -1338,15 +1363,15 @@ int __init kbd_init(void)
{
int i;
- kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS;
- kbd0.ledmode = LED_SHOW_FLAGS;
- kbd0.lockstate = KBD_DEFLOCK;
- kbd0.slockstate = 0;
- kbd0.modeflags = KBD_DEFMODE;
- kbd0.kbdmode = VC_XLATE;
-
- for (i = 0 ; i < MAX_NR_CONSOLES ; i++)
- kbd_table[i] = kbd0;
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ kbd_table[i].ledflagstate = KBD_DEFLEDS;
+ kbd_table[i].default_ledflagstate = KBD_DEFLEDS;
+ kbd_table[i].ledmode = LED_SHOW_FLAGS;
+ kbd_table[i].lockstate = KBD_DEFLOCK;
+ kbd_table[i].slockstate = 0;
+ kbd_table[i].modeflags = KBD_DEFMODE;
+ kbd_table[i].kbdmode = VC_XLATE;
+ }
input_register_handler(&kbd_handler);
diff --git a/drivers/char/lcd.c b/drivers/char/lcd.c
index 29963d8be66..da601fd6c07 100644
--- a/drivers/char/lcd.c
+++ b/drivers/char/lcd.c
@@ -14,7 +14,6 @@
#define RTC_IO_EXTENT 0x10 /*Only really two ports, but... */
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
@@ -599,7 +598,7 @@ static ssize_t lcd_read(struct file *file, char *buf,
* The various file operations we support.
*/
-static struct file_operations lcd_fops = {
+static const struct file_operations lcd_fops = {
.read = lcd_read,
.ioctl = lcd_ioctl,
.open = lcd_open,
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index e5726052529..1ecea7d448f 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -114,13 +114,11 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
@@ -668,7 +666,7 @@ static int lp_ioctl(struct inode *inode, struct file *file,
return retval;
}
-static struct file_operations lp_fops = {
+static const struct file_operations lp_fops = {
.owner = THIS_MODULE,
.write = lp_write,
.ioctl = lp_ioctl,
@@ -807,8 +805,6 @@ static int lp_register(int nr, struct parport *port)
class_device_create(lp_class, NULL, MKDEV(LP_MAJOR, nr), NULL,
"lp%d", nr);
- devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO,
- "printers/%d", nr);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
(port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
@@ -907,11 +903,10 @@ static int __init lp_init (void)
return -EIO;
}
- devfs_mk_dir("printers");
lp_class = class_create(THIS_MODULE, "printer");
if (IS_ERR(lp_class)) {
err = PTR_ERR(lp_class);
- goto out_devfs;
+ goto out_reg;
}
if (parport_register_driver (&lp_driver)) {
@@ -932,8 +927,7 @@ static int __init lp_init (void)
out_class:
class_destroy(lp_class);
-out_devfs:
- devfs_remove("printers");
+out_reg:
unregister_chrdev(LP_MAJOR, "lp");
return err;
}
@@ -981,10 +975,8 @@ static void lp_cleanup_module (void)
if (lp_table[offset].dev == NULL)
continue;
parport_unregister_device(lp_table[offset].dev);
- devfs_remove("printers/%d", offset);
class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset));
}
- devfs_remove("printers");
class_destroy(lp_class);
}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index c268ee04b2a..0385650f607 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -10,7 +10,6 @@
* MOATB Core Services driver.
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -593,7 +592,7 @@ static int mbcs_intr_alloc(struct cx_dev *dev)
getdma->intrHostDest = sn_irq->irq_xtalkaddr;
getdma->intrVector = sn_irq->irq_irq;
if (request_irq(sn_irq->irq_irq,
- (void *)mbcs_completion_intr_handler, SA_SHIRQ,
+ (void *)mbcs_completion_intr_handler, IRQF_SHARED,
"MBCS get intr", (void *)soft)) {
tiocx_irq_free(soft->get_sn_irq);
return -EAGAIN;
@@ -609,7 +608,7 @@ static int mbcs_intr_alloc(struct cx_dev *dev)
putdma->intrHostDest = sn_irq->irq_xtalkaddr;
putdma->intrVector = sn_irq->irq_irq;
if (request_irq(sn_irq->irq_irq,
- (void *)mbcs_completion_intr_handler, SA_SHIRQ,
+ (void *)mbcs_completion_intr_handler, IRQF_SHARED,
"MBCS put intr", (void *)soft)) {
tiocx_irq_free(soft->put_sn_irq);
free_irq(soft->get_sn_irq->irq_irq, soft);
@@ -629,7 +628,7 @@ static int mbcs_intr_alloc(struct cx_dev *dev)
algo->intrHostDest = sn_irq->irq_xtalkaddr;
algo->intrVector = sn_irq->irq_irq;
if (request_irq(sn_irq->irq_irq,
- (void *)mbcs_completion_intr_handler, SA_SHIRQ,
+ (void *)mbcs_completion_intr_handler, IRQF_SHARED,
"MBCS algo intr", (void *)soft)) {
tiocx_irq_free(soft->algo_sn_irq);
free_irq(soft->put_sn_irq->irq_irq, soft);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 1fa9fa157c1..6511012cbdc 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -8,7 +8,6 @@
* Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
*/
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
@@ -20,7 +19,6 @@
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
@@ -97,7 +95,7 @@ static inline int valid_phys_addr_range(unsigned long addr, size_t count)
return 1;
}
-static inline int valid_mmap_phys_addr_range(unsigned long addr, size_t size)
+static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
{
return 1;
}
@@ -240,13 +238,42 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
}
#endif
+#ifndef CONFIG_MMU
+static unsigned long get_unmapped_area_mem(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ if (!valid_mmap_phys_addr_range(pgoff, len))
+ return (unsigned long) -EINVAL;
+ return pgoff;
+}
+
+/* can't do an in-place private mapping if there's no MMU */
+static inline int private_mapping_ok(struct vm_area_struct *vma)
+{
+ return vma->vm_flags & VM_MAYSHARE;
+}
+#else
+#define get_unmapped_area_mem NULL
+
+static inline int private_mapping_ok(struct vm_area_struct *vma)
+{
+ return 1;
+}
+#endif
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
size_t size = vma->vm_end - vma->vm_start;
- if (!valid_mmap_phys_addr_range(vma->vm_pgoff << PAGE_SHIFT, size))
+ if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
return -EINVAL;
+ if (!private_mapping_ok(vma))
+ return -ENOSYS;
+
vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
size,
vma->vm_page_prot);
@@ -524,7 +551,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
return virtr + wrote;
}
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
static ssize_t read_port(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
@@ -778,31 +805,33 @@ static int open_port(struct inode * inode, struct file * filp)
#define open_kmem open_mem
#define open_oldmem open_mem
-static struct file_operations mem_fops = {
+static const struct file_operations mem_fops = {
.llseek = memory_lseek,
.read = read_mem,
.write = write_mem,
.mmap = mmap_mem,
.open = open_mem,
+ .get_unmapped_area = get_unmapped_area_mem,
};
-static struct file_operations kmem_fops = {
+static const struct file_operations kmem_fops = {
.llseek = memory_lseek,
.read = read_kmem,
.write = write_kmem,
.mmap = mmap_kmem,
.open = open_kmem,
+ .get_unmapped_area = get_unmapped_area_mem,
};
-static struct file_operations null_fops = {
+static const struct file_operations null_fops = {
.llseek = null_lseek,
.read = read_null,
.write = write_null,
.splice_write = splice_write_null,
};
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
-static struct file_operations port_fops = {
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
+static const struct file_operations port_fops = {
.llseek = memory_lseek,
.read = read_port,
.write = write_port,
@@ -810,25 +839,29 @@ static struct file_operations port_fops = {
};
#endif
-static struct file_operations zero_fops = {
+static const struct file_operations zero_fops = {
.llseek = zero_lseek,
.read = read_zero,
.write = write_zero,
.mmap = mmap_zero,
};
+/*
+ * capabilities for /dev/zero
+ * - permits private mappings, "copies" are taken of the source of zeros
+ */
static struct backing_dev_info zero_bdi = {
.capabilities = BDI_CAP_MAP_COPY,
};
-static struct file_operations full_fops = {
+static const struct file_operations full_fops = {
.llseek = full_lseek,
.read = read_full,
.write = write_full,
};
#ifdef CONFIG_CRASH_DUMP
-static struct file_operations oldmem_fops = {
+static const struct file_operations oldmem_fops = {
.read = read_oldmem,
.open = open_oldmem,
};
@@ -855,7 +888,7 @@ static ssize_t kmsg_write(struct file * file, const char __user * buf,
return ret;
}
-static struct file_operations kmsg_fops = {
+static const struct file_operations kmsg_fops = {
.write = kmsg_write,
};
@@ -864,14 +897,18 @@ static int memory_open(struct inode * inode, struct file * filp)
switch (iminor(inode)) {
case 1:
filp->f_op = &mem_fops;
+ filp->f_mapping->backing_dev_info =
+ &directly_mappable_cdev_bdi;
break;
case 2:
filp->f_op = &kmem_fops;
+ filp->f_mapping->backing_dev_info =
+ &directly_mappable_cdev_bdi;
break;
case 3:
filp->f_op = &null_fops;
break;
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
case 4:
filp->f_op = &port_fops;
break;
@@ -905,7 +942,7 @@ static int memory_open(struct inode * inode, struct file * filp)
return 0;
}
-static struct file_operations memory_fops = {
+static const struct file_operations memory_fops = {
.open = memory_open, /* just a selector for the real open */
};
@@ -918,7 +955,7 @@ static const struct {
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
#endif
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
@@ -941,13 +978,10 @@ static int __init chr_dev_init(void)
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
mem_class = class_create(THIS_MODULE, "mem");
- for (i = 0; i < ARRAY_SIZE(devlist); i++) {
+ for (i = 0; i < ARRAY_SIZE(devlist); i++)
class_device_create(mem_class, NULL,
MKDEV(MEM_MAJOR, devlist[i].minor),
NULL, devlist[i].name);
- devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor),
- S_IFCHR | devlist[i].mode, devlist[i].name);
- }
return 0;
}
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 96eb2a709e2..62ebe09656e 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -34,7 +34,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/errno.h>
@@ -44,7 +43,6 @@
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -115,7 +113,7 @@ static int misc_seq_open(struct inode *inode, struct file *file)
return seq_open(file, &misc_seq_ops);
}
-static struct file_operations misc_proc_fops = {
+static const struct file_operations misc_proc_fops = {
.owner = THIS_MODULE,
.open = misc_seq_open,
.read = seq_read,
@@ -178,7 +176,7 @@ fail:
*/
static struct class *misc_class;
-static struct file_operations misc_fops = {
+static const struct file_operations misc_fops = {
.owner = THIS_MODULE,
.open = misc_open,
};
@@ -204,7 +202,7 @@ int misc_register(struct miscdevice * misc)
{
struct miscdevice *c;
dev_t dev;
- int err;
+ int err = 0;
down(&misc_sem);
list_for_each_entry(c, &misc_list, list) {
@@ -228,10 +226,6 @@ int misc_register(struct miscdevice * misc)
if (misc->minor < DYNAMIC_MINORS)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
- if (misc->devfs_name[0] == '\0') {
- snprintf(misc->devfs_name, sizeof(misc->devfs_name),
- "misc/%s", misc->name);
- }
dev = MKDEV(MISC_MAJOR, misc->minor);
misc->class = class_device_create(misc_class, NULL, dev, misc->dev,
@@ -241,13 +235,6 @@ int misc_register(struct miscdevice * misc)
goto out;
}
- err = devfs_mk_cdev(dev, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP,
- misc->devfs_name);
- if (err) {
- class_device_destroy(misc_class, dev);
- goto out;
- }
-
/*
* Add it to the front, so that later devices can "override"
* earlier defaults
@@ -278,7 +265,6 @@ int misc_deregister(struct miscdevice * misc)
down(&misc_sem);
list_del(&misc->list);
class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
- devfs_remove(misc->devfs_name);
if (i < DYNAMIC_MINORS && i>0) {
misc_minors[i>>3] &= ~(1 << (misc->minor & 7));
}
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 1b05fa68899..1f0f2b6dae2 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/mm.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/mmtimer.h>
#include <linux/miscdevice.h>
#include <linux/posix-timers.h>
@@ -64,7 +63,7 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma);
*/
static unsigned long mmtimer_femtoperiod = 0;
-static struct file_operations mmtimer_fops = {
+static const struct file_operations mmtimer_fops = {
.owner = THIS_MODULE,
.mmap = mmtimer_mmap,
.ioctl = mmtimer_ioctl,
@@ -329,7 +328,6 @@ static int mmtimer_mmap(struct file *file, struct vm_area_struct *vma)
if (PAGE_SIZE > (1 << 16))
return -ENOSYS;
- vma->vm_flags |= (VM_IO | VM_SHM | VM_LOCKED );
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
mmtimer_addr = __pa(RTC_COUNTER_ADDR);
@@ -689,13 +687,12 @@ static int __init mmtimer_init(void)
mmtimer_femtoperiod = ((unsigned long)1E15 + sn_rtc_cycles_per_second /
2) / sn_rtc_cycles_per_second;
- if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, SA_PERCPU_IRQ, MMTIMER_NAME, NULL)) {
+ if (request_irq(SGI_MMTIMER_VECTOR, mmtimer_interrupt, IRQF_PERCPU, MMTIMER_NAME, NULL)) {
printk(KERN_WARNING "%s: unable to allocate interrupt.",
MMTIMER_NAME);
return -1;
}
- strcpy(mmtimer_miscdev.devfs_name, MMTIMER_NAME);
if (misc_register(&mmtimer_miscdev)) {
printk(KERN_ERR "%s: failed to register device\n",
MMTIMER_NAME);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index f43c2e04ead..a369dd6877d 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -29,7 +29,6 @@
* version : 5.1
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
@@ -143,6 +142,7 @@ typedef struct _moxa_board_conf {
static moxa_board_conf moxa_boards[MAX_BOARDS];
static void __iomem *moxaBaseAddr[MAX_BOARDS];
+static int loadstat[MAX_BOARDS];
struct moxa_str {
int type;
@@ -301,7 +301,7 @@ static struct tty_operations moxa_ops = {
.tiocmset = moxa_tiocmset,
};
-static spinlock_t moxa_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(moxa_lock);
#ifdef CONFIG_PCI
static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf * board)
@@ -342,7 +342,6 @@ static int __init moxa_init(void)
init_MUTEX(&moxaBuffSem);
moxaDriver->owner = THIS_MODULE;
moxaDriver->name = "ttyMX";
- moxaDriver->devfs_name = "tts/a";
moxaDriver->major = ttymajor;
moxaDriver->minor_start = 0;
moxaDriver->type = TTY_DRIVER_TYPE_SERIAL;
@@ -1690,6 +1689,8 @@ int MoxaDriverPoll(void)
if (moxaCard == 0)
return (-1);
for (card = 0; card < MAX_BOARDS; card++) {
+ if (loadstat[card] == 0)
+ continue;
if ((ports = moxa_boards[card].numPorts) == 0)
continue;
if (readb(moxaIntPend[card]) == 0xff) {
@@ -2905,6 +2906,7 @@ static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
}
break;
}
+ loadstat[cardno] = 1;
return (0);
}
@@ -2922,7 +2924,7 @@ static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
len1 = len >> 1;
ptr = (ushort *) moxaBuff;
for (i = 0; i < len1; i++)
- usum += *(ptr + i);
+ usum += le16_to_cpu(*(ptr + i));
retry = 0;
do {
len1 = len >> 1;
@@ -2994,7 +2996,7 @@ static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPor
wlen = len >> 1;
uptr = (ushort *) moxaBuff;
for (i = 0; i < wlen; i++)
- usum += uptr[i];
+ usum += le16_to_cpu(uptr[i]);
retry = 0;
j = 0;
do {
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
new file mode 100644
index 00000000000..5426b1e5595
--- /dev/null
+++ b/drivers/char/mspec.c
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2001-2006 Silicon Graphics, Inc. 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 published by the Free Software Foundation.
+ */
+
+/*
+ * SN Platform Special Memory (mspec) Support
+ *
+ * This driver exports the SN special memory (mspec) facility to user
+ * processes.
+ * There are three types of memory made available thru this driver:
+ * fetchops, uncached and cached.
+ *
+ * Fetchops are atomic memory operations that are implemented in the
+ * memory controller on SGI SN hardware.
+ *
+ * Uncached are used for memory write combining feature of the ia64
+ * cpu.
+ *
+ * Cached are used for areas of memory that are used as cached addresses
+ * on our partition and used as uncached addresses from other partitions.
+ * Due to a design constraint of the SN2 Shub, you can not have processors
+ * on the same FSB perform both a cached and uncached reference to the
+ * same cache line. These special memory cached regions prevent the
+ * kernel from ever dropping in a TLB entry and therefore prevent the
+ * processor from ever speculating a cache line from this page.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/numa.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/atomic.h>
+#include <asm/tlbflush.h>
+#include <asm/uncached.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/mspec.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/io.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/shubio.h>
+
+
+#define FETCHOP_ID "SGI Fetchop,"
+#define CACHED_ID "Cached,"
+#define UNCACHED_ID "Uncached"
+#define REVISION "4.0"
+#define MSPEC_BASENAME "mspec"
+
+/*
+ * Page types allocated by the device.
+ */
+enum {
+ MSPEC_FETCHOP = 1,
+ MSPEC_CACHED,
+ MSPEC_UNCACHED
+};
+
+static int is_sn2;
+
+/*
+ * One of these structures is allocated when an mspec region is mmaped. The
+ * structure is pointed to by the vma->vm_private_data field in the vma struct.
+ * This structure is used to record the addresses of the mspec pages.
+ */
+struct vma_data {
+ atomic_t refcnt; /* Number of vmas sharing the data. */
+ spinlock_t lock; /* Serialize access to the vma. */
+ int count; /* Number of pages allocated. */
+ int type; /* Type of pages allocated. */
+ unsigned long maddr[0]; /* Array of MSPEC addresses. */
+};
+
+/* used on shub2 to clear FOP cache in the HUB */
+static unsigned long scratch_page[MAX_NUMNODES];
+#define SH2_AMO_CACHE_ENTRIES 4
+
+static inline int
+mspec_zero_block(unsigned long addr, int len)
+{
+ int status;
+
+ if (is_sn2) {
+ if (is_shub2()) {
+ int nid;
+ void *p;
+ int i;
+
+ nid = nasid_to_cnodeid(get_node_number(__pa(addr)));
+ p = (void *)TO_AMO(scratch_page[nid]);
+
+ for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) {
+ FETCHOP_LOAD_OP(p, FETCHOP_LOAD);
+ p += FETCHOP_VAR_SIZE;
+ }
+ }
+
+ status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len,
+ BTE_WACQUIRE | BTE_ZERO_FILL, NULL);
+ } else {
+ memset((char *) addr, 0, len);
+ status = 0;
+ }
+ return status;
+}
+
+/*
+ * mspec_open
+ *
+ * Called when a device mapping is created by a means other than mmap
+ * (via fork, etc.). Increments the reference count on the underlying
+ * mspec data so it is not freed prematurely.
+ */
+static void
+mspec_open(struct vm_area_struct *vma)
+{
+ struct vma_data *vdata;
+
+ vdata = vma->vm_private_data;
+ atomic_inc(&vdata->refcnt);
+}
+
+/*
+ * mspec_close
+ *
+ * Called when unmapping a device mapping. Frees all mspec pages
+ * belonging to the vma.
+ */
+static void
+mspec_close(struct vm_area_struct *vma)
+{
+ struct vma_data *vdata;
+ int i, pages, result, vdata_size;
+
+ vdata = vma->vm_private_data;
+ if (!atomic_dec_and_test(&vdata->refcnt))
+ return;
+
+ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
+ for (i = 0; i < pages; i++) {
+ if (vdata->maddr[i] == 0)
+ continue;
+ /*
+ * Clear the page before sticking it back
+ * into the pool.
+ */
+ result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE);
+ if (!result)
+ uncached_free_page(vdata->maddr[i]);
+ else
+ printk(KERN_WARNING "mspec_close(): "
+ "failed to zero page %i\n",
+ result);
+ }
+
+ if (vdata_size <= PAGE_SIZE)
+ kfree(vdata);
+ else
+ vfree(vdata);
+}
+
+
+/*
+ * mspec_nopfn
+ *
+ * Creates a mspec page and maps it to user space.
+ */
+static unsigned long
+mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
+{
+ unsigned long paddr, maddr;
+ unsigned long pfn;
+ int index;
+ struct vma_data *vdata = vma->vm_private_data;
+
+ index = (address - vma->vm_start) >> PAGE_SHIFT;
+ maddr = (volatile unsigned long) vdata->maddr[index];
+ if (maddr == 0) {
+ maddr = uncached_alloc_page(numa_node_id());
+ if (maddr == 0)
+ return NOPFN_OOM;
+
+ spin_lock(&vdata->lock);
+ if (vdata->maddr[index] == 0) {
+ vdata->count++;
+ vdata->maddr[index] = maddr;
+ } else {
+ uncached_free_page(maddr);
+ maddr = vdata->maddr[index];
+ }
+ spin_unlock(&vdata->lock);
+ }
+
+ if (vdata->type == MSPEC_FETCHOP)
+ paddr = TO_AMO(maddr);
+ else
+ paddr = __pa(TO_CAC(maddr));
+
+ pfn = paddr >> PAGE_SHIFT;
+
+ return pfn;
+}
+
+static struct vm_operations_struct mspec_vm_ops = {
+ .open = mspec_open,
+ .close = mspec_close,
+ .nopfn = mspec_nopfn
+};
+
+/*
+ * mspec_mmap
+ *
+ * Called when mmaping the device. Initializes the vma with a fault handler
+ * and private data structure necessary to allocate, track, and free the
+ * underlying pages.
+ */
+static int
+mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
+{
+ struct vma_data *vdata;
+ int pages, vdata_size;
+
+ if (vma->vm_pgoff != 0)
+ return -EINVAL;
+
+ if ((vma->vm_flags & VM_SHARED) == 0)
+ return -EINVAL;
+
+ if ((vma->vm_flags & VM_WRITE) == 0)
+ return -EPERM;
+
+ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
+ if (vdata_size <= PAGE_SIZE)
+ vdata = kmalloc(vdata_size, GFP_KERNEL);
+ else
+ vdata = vmalloc(vdata_size);
+ if (!vdata)
+ return -ENOMEM;
+ memset(vdata, 0, vdata_size);
+
+ vdata->type = type;
+ spin_lock_init(&vdata->lock);
+ vdata->refcnt = ATOMIC_INIT(1);
+ vma->vm_private_data = vdata;
+
+ vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP);
+ if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_ops = &mspec_vm_ops;
+
+ return 0;
+}
+
+static int
+fetchop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return mspec_mmap(file, vma, MSPEC_FETCHOP);
+}
+
+static int
+cached_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return mspec_mmap(file, vma, MSPEC_CACHED);
+}
+
+static int
+uncached_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return mspec_mmap(file, vma, MSPEC_UNCACHED);
+}
+
+static struct file_operations fetchop_fops = {
+ .owner = THIS_MODULE,
+ .mmap = fetchop_mmap
+};
+
+static struct miscdevice fetchop_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sgi_fetchop",
+ .fops = &fetchop_fops
+};
+
+static struct file_operations cached_fops = {
+ .owner = THIS_MODULE,
+ .mmap = cached_mmap
+};
+
+static struct miscdevice cached_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mspec_cached",
+ .fops = &cached_fops
+};
+
+static struct file_operations uncached_fops = {
+ .owner = THIS_MODULE,
+ .mmap = uncached_mmap
+};
+
+static struct miscdevice uncached_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mspec_uncached",
+ .fops = &uncached_fops
+};
+
+/*
+ * mspec_init
+ *
+ * Called at boot time to initialize the mspec facility.
+ */
+static int __init
+mspec_init(void)
+{
+ int ret;
+ int nid;
+
+ /*
+ * The fetchop device only works on SN2 hardware, uncached and cached
+ * memory drivers should both be valid on all ia64 hardware
+ */
+ if (ia64_platform_is("sn2")) {
+ is_sn2 = 1;
+ if (is_shub2()) {
+ ret = -ENOMEM;
+ for_each_online_node(nid) {
+ int actual_nid;
+ int nasid;
+ unsigned long phys;
+
+ scratch_page[nid] = uncached_alloc_page(nid);
+ if (scratch_page[nid] == 0)
+ goto free_scratch_pages;
+ phys = __pa(scratch_page[nid]);
+ nasid = get_node_number(phys);
+ actual_nid = nasid_to_cnodeid(nasid);
+ if (actual_nid != nid)
+ goto free_scratch_pages;
+ }
+ }
+
+ ret = misc_register(&fetchop_miscdev);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: failed to register device %i\n",
+ FETCHOP_ID, ret);
+ goto free_scratch_pages;
+ }
+ }
+ ret = misc_register(&cached_miscdev);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device %i\n",
+ CACHED_ID, ret);
+ if (is_sn2)
+ misc_deregister(&fetchop_miscdev);
+ goto free_scratch_pages;
+ }
+ ret = misc_register(&uncached_miscdev);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device %i\n",
+ UNCACHED_ID, ret);
+ misc_deregister(&cached_miscdev);
+ if (is_sn2)
+ misc_deregister(&fetchop_miscdev);
+ goto free_scratch_pages;
+ }
+
+ printk(KERN_INFO "%s %s initialized devices: %s %s %s\n",
+ MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "",
+ CACHED_ID, UNCACHED_ID);
+
+ return 0;
+
+ free_scratch_pages:
+ for_each_node(nid) {
+ if (scratch_page[nid] != 0)
+ uncached_free_page(scratch_page[nid]);
+ }
+ return ret;
+}
+
+static void __exit
+mspec_exit(void)
+{
+ int nid;
+
+ misc_deregister(&uncached_miscdev);
+ misc_deregister(&cached_miscdev);
+ if (is_sn2) {
+ misc_deregister(&fetchop_miscdev);
+
+ for_each_node(nid) {
+ if (scratch_page[nid] != 0)
+ uncached_free_page(scratch_page[nid]);
+ }
+ }
+}
+
+module_init(mspec_init);
+module_exit(mspec_exit);
+
+MODULE_AUTHOR("Silicon Graphics, Inc. <linux-altix@sgi.com>");
+MODULE_DESCRIPTION("Driver for SGI SN special memory operations");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index d1fe05e8388..4e4865e90e5 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -46,7 +46,6 @@
* First release to the public
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/unistd.h>
#include <linux/delay.h>
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index d3ba2f860ef..39a2e661ff5 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -454,7 +454,7 @@ static int register_serial_portandirq(unsigned int port, int irq)
}
-static struct file_operations mwave_fops = {
+static const struct file_operations mwave_fops = {
.owner = THIS_MODULE,
.read = mwave_read,
.write = mwave_write,
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 0fb2fb9fb02..556abd3e0d0 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -9,7 +9,7 @@
* 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.
+ * (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
@@ -36,7 +36,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/autoconf.h>
#include <linux/errno.h>
@@ -71,8 +70,8 @@
#define MXSERMAJOR 174
#define MXSERCUMAJOR 175
-#define MXSER_EVENT_TXLOW 1
-#define MXSER_EVENT_HANGUP 2
+#define MXSER_EVENT_TXLOW 1
+#define MXSER_EVENT_HANGUP 2
#define MXSER_BOARDS 4 /* Max. boards */
#define MXSER_PORTS 32 /* Max. ports */
@@ -92,9 +91,10 @@
#define UART_MCR_AFE 0x20
#define UART_LSR_SPECIAL 0x1E
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|IXON|IXOFF))
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\
+ IXON|IXOFF))
-#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
+#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED)
#define C168_ASIC_ID 1
#define C104_ASIC_ID 2
@@ -152,27 +152,27 @@ static char *mxser_brdname[] = {
};
static int mxser_numports[] = {
- 8, // C168-ISA
- 4, // C104-ISA
- 4, // CI104J
- 8, // C168-PCI
- 4, // C104-PCI
- 2, // C102-ISA
- 2, // CI132
- 4, // CI134
- 2, // CP132
- 4, // CP114
- 4, // CT114
- 2, // CP102
- 4, // CP104U
- 8, // CP168U
- 2, // CP132U
- 4, // CP134U
- 4, // CP104JU
- 8, // RC7000
- 8, // CP118U
- 2, // CP102UL
- 2, // CP102U
+ 8, /* C168-ISA */
+ 4, /* C104-ISA */
+ 4, /* CI104J */
+ 8, /* C168-PCI */
+ 4, /* C104-PCI */
+ 2, /* C102-ISA */
+ 2, /* CI132 */
+ 4, /* CI134 */
+ 2, /* CP132 */
+ 4, /* CP114 */
+ 4, /* CT114 */
+ 2, /* CP102 */
+ 4, /* CP104U */
+ 8, /* CP168U */
+ 2, /* CP132U */
+ 4, /* CP134U */
+ 4, /* CP104JU */
+ 8, /* RC7000 */
+ 8, /* CP118U */
+ 2, /* CP102UL */
+ 2, /* CP102U */
};
#define UART_TYPE_NUM 2
@@ -182,7 +182,7 @@ static const unsigned int Gmoxa_uart_id[UART_TYPE_NUM] = {
MOXA_MUST_MU860_HWID
};
-// This is only for PCI
+/* This is only for PCI */
#define UART_INFO_NUM 3
struct mxpciuart_info {
int type;
@@ -231,7 +231,7 @@ MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
typedef struct _moxa_pci_info {
unsigned short busNum;
unsigned short devNum;
- struct pci_dev *pdev; // add by Victor Yu. 06-23-2003
+ struct pci_dev *pdev; /* add by Victor Yu. 06-23-2003 */
} moxa_pci_info;
static int ioaddr[MXSER_BOARDS] = { 0, 0, 0, 0 };
@@ -280,6 +280,7 @@ struct mxser_mon_ext {
int fifo[32];
int iftype[32];
};
+
struct mxser_hwconf {
int board_type;
int ports;
@@ -290,9 +291,9 @@ struct mxser_hwconf {
int ioaddr[MXSER_PORTS_PER_BOARD];
int baud_base[MXSER_PORTS_PER_BOARD];
moxa_pci_info pciInfo;
- int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002
- int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 09-04-2002
- int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; // add by Victor Yu. 01-05-2004
+ int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+ int MaxCanSetBaudRate[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 09-04-2002 */
+ int opmode_ioaddr[MXSER_PORTS_PER_BOARD]; /* add by Victor Yu. 01-05-2004 */
};
struct mxser_struct {
@@ -334,9 +335,9 @@ struct mxser_struct {
wait_queue_head_t delta_msr_wait;
struct async_icount icount; /* kernel counters for the 4 input interrupts */
int timeout;
- int IsMoxaMustChipFlag; // add by Victor Yu. 08-30-2002
- int MaxCanSetBaudRate; // add by Victor Yu. 09-04-2002
- int opmode_ioaddr; // add by Victor Yu. 01-05-2004
+ int IsMoxaMustChipFlag; /* add by Victor Yu. 08-30-2002 */
+ int MaxCanSetBaudRate; /* add by Victor Yu. 09-04-2002 */
+ int opmode_ioaddr; /* add by Victor Yu. 01-05-2004 */
unsigned char stop_rx;
unsigned char ldisc_stop_rx;
long realbaud;
@@ -345,7 +346,6 @@ struct mxser_struct {
spinlock_t slock;
};
-
struct mxser_mstatus {
tcflag_t cflag;
int cts;
@@ -358,7 +358,7 @@ static struct mxser_mstatus GMStatus[MXSER_PORTS];
static int mxserBoardCAP[MXSER_BOARDS] = {
0, 0, 0, 0
- /* 0x180, 0x280, 0x200, 0x320 */
+ /* 0x180, 0x280, 0x200, 0x320 */
};
static struct tty_driver *mxvar_sdriver;
@@ -386,7 +386,7 @@ static struct mxser_hwconf mxsercfg[MXSER_BOARDS];
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
static int mxser_init(void);
-//static void mxser_poll(unsigned long);
+/* static void mxser_poll(unsigned long); */
static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
static int mxser_get_PCI_conf(int, int, int, struct mxser_hwconf *);
static void mxser_do_softint(void *);
@@ -440,18 +440,18 @@ static int CheckIsMoxaMust(int io)
SET_MOXA_MUST_XON1_VALUE(io, 0x11);
if ((hwid = inb(io + UART_MCR)) != 0) {
outb(oldmcr, io + UART_MCR);
- return (MOXA_OTHER_UART);
+ return MOXA_OTHER_UART;
}
GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
for (i = 0; i < UART_TYPE_NUM; i++) {
if (hwid == Gmoxa_uart_id[i])
- return (int) hwid;
+ return (int)hwid;
}
return MOXA_OTHER_UART;
}
-// above is modified by Victor Yu. 08-15-2002
+/* above is modified by Victor Yu. 08-15-2002 */
static struct tty_operations mxser_ops = {
.open = mxser_open,
@@ -504,7 +504,6 @@ static void __exit mxser_module_exit(void)
else
printk(KERN_ERR "Couldn't unregister MOXA Smartio/Industio family serial driver\n");
-
for (i = 0; i < MXSER_BOARDS; i++) {
struct pci_dev *pdev;
@@ -513,7 +512,7 @@ static void __exit mxser_module_exit(void)
else {
pdev = mxsercfg[i].pciInfo.pdev;
free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
- if (pdev != NULL) { //PCI
+ if (pdev != NULL) { /* PCI */
release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
} else {
@@ -524,7 +523,6 @@ static void __exit mxser_module_exit(void)
}
if (verbose)
printk(KERN_DEBUG "Done.\n");
-
}
static void process_txrx_fifo(struct mxser_struct *info)
@@ -558,8 +556,10 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
/*if (verbose) */ {
- printk(KERN_DEBUG " ttyM%d - ttyM%d ", n, n + hwconf->ports - 1);
- printk(" max. baud rate = %d bps.\n", hwconf->MaxCanSetBaudRate[0]);
+ printk(KERN_DEBUG " ttyM%d - ttyM%d ",
+ n, n + hwconf->ports - 1);
+ printk(" max. baud rate = %d bps.\n",
+ hwconf->MaxCanSetBaudRate[0]);
}
for (i = 0; i < hwconf->ports; i++, n++, info++) {
@@ -568,12 +568,12 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
info->irq = hwconf->irq;
info->vector = hwconf->vector;
info->vectormask = hwconf->vector_mask;
- info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; // add by Victor Yu. 01-05-2004
+ info->opmode_ioaddr = hwconf->opmode_ioaddr[i]; /* add by Victor Yu. 01-05-2004 */
info->stop_rx = 0;
info->ldisc_stop_rx = 0;
info->IsMoxaMustChipFlag = hwconf->IsMoxaMustChipFlag;
- //Enhance mode enabled here
+ /* Enhance mode enabled here */
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
ENABLE_MOXA_MUST_ENCHANCE_MODE(info->base);
}
@@ -606,22 +606,25 @@ static int mxser_initbrd(int board, struct mxser_hwconf *hwconf)
/* before set INT ISR, disable all int */
for (i = 0; i < hwconf->ports; i++) {
- outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0, hwconf->ioaddr[i] + UART_IER);
+ outb(inb(hwconf->ioaddr[i] + UART_IER) & 0xf0,
+ hwconf->ioaddr[i] + UART_IER);
}
n = board * MXSER_PORTS_PER_BOARD;
info = &mxvar_table[n];
- retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info), "mxser", info);
+ retval = request_irq(hwconf->irq, mxser_interrupt, IRQ_T(info),
+ "mxser", info);
if (retval) {
- printk(KERN_ERR "Board %d: %s", board, mxser_brdname[hwconf->board_type - 1]);
- printk(" Request irq fail,IRQ (%d) may be conflit with another device.\n", info->irq);
+ printk(KERN_ERR "Board %d: %s",
+ board, mxser_brdname[hwconf->board_type - 1]);
+ printk(" Request irq failed, IRQ (%d) may conflict with"
+ " another device.\n", info->irq);
return retval;
}
return 0;
}
-
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
{
mxsercfg[board] = *hwconf;
@@ -631,26 +634,27 @@ static void mxser_getcfg(int board, struct mxser_hwconf *hwconf)
static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxser_hwconf *hwconf)
{
int i, j;
-// unsigned int val;
+ /* unsigned int val; */
unsigned int ioaddress;
struct pci_dev *pdev = hwconf->pciInfo.pdev;
- //io address
+ /* io address */
hwconf->board_type = board_type;
hwconf->ports = mxser_numports[board_type - 1];
ioaddress = pci_resource_start(pdev, 2);
- request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2), "mxser(IO)");
+ request_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2),
+ "mxser(IO)");
- for (i = 0; i < hwconf->ports; i++) {
+ for (i = 0; i < hwconf->ports; i++)
hwconf->ioaddr[i] = ioaddress + 8 * i;
- }
- //vector
+ /* vector */
ioaddress = pci_resource_start(pdev, 3);
- request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3), "mxser(vector)");
+ request_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3),
+ "mxser(vector)");
hwconf->vector = ioaddress;
- //irq
+ /* irq */
hwconf->irq = hwconf->pciInfo.pdev->irq;
hwconf->IsMoxaMustChipFlag = CheckIsMoxaMust(hwconf->ioaddr[0]);
@@ -663,7 +667,7 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs
if (Gpci_uart_info[j].type == hwconf->IsMoxaMustChipFlag) {
hwconf->MaxCanSetBaudRate[i] = Gpci_uart_info[j].max_baud;
- //exception....CP-102
+ /* exception....CP-102 */
if (board_type == MXSER_BOARD_CP102)
hwconf->MaxCanSetBaudRate[i] = 921600;
break;
@@ -678,15 +682,15 @@ static int mxser_get_PCI_conf(int busnum, int devnum, int board_type, struct mxs
else
hwconf->opmode_ioaddr[i] = ioaddress + 0x0c;
}
- outb(0, ioaddress + 4); // default set to RS232 mode
- outb(0, ioaddress + 0x0c); //default set to RS232 mode
+ outb(0, ioaddress + 4); /* default set to RS232 mode */
+ outb(0, ioaddress + 0x0c); /* default set to RS232 mode */
}
for (i = 0; i < hwconf->ports; i++) {
hwconf->vector_mask |= (1 << i);
hwconf->baud_base[i] = 921600;
}
- return (0);
+ return 0;
}
#endif
@@ -707,7 +711,8 @@ static int mxser_init(void)
mxsercfg[i].board_type = -1;
}
- printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n", MXSER_VERSION);
+ printk(KERN_INFO "MOXA Smartio/Industio family driver version %s\n",
+ MXSER_VERSION);
/* Initialize the tty_driver structure */
memset(mxvar_sdriver, 0, sizeof(struct tty_driver));
@@ -719,7 +724,7 @@ static int mxser_init(void)
mxvar_sdriver->type = TTY_DRIVER_TYPE_SERIAL;
mxvar_sdriver->subtype = SERIAL_TYPE_NORMAL;
mxvar_sdriver->init_termios = tty_std_termios;
- mxvar_sdriver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(mxvar_sdriver, &mxser_ops);
mxvar_sdriver->ttys = mxvar_tty;
@@ -739,23 +744,29 @@ static int mxser_init(void)
/* Start finding ISA boards here */
for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
int cap;
+
if (!(cap = mxserBoardCAP[b]))
continue;
retval = mxser_get_ISA_conf(cap, &hwconf);
if (retval != 0)
- printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+ printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
if (retval <= 0) {
if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt vector, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address,board not configured\n");
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
continue;
}
@@ -765,35 +776,43 @@ static int mxser_init(void)
hwconf.pciInfo.pdev = NULL;
mxser_getcfg(m, &hwconf);
- //init mxsercfg first, or mxsercfg data is not correct on ISR.
- //mxser_initbrd will hook ISR.
+ /*
+ * init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(m, &hwconf) < 0)
continue;
-
m++;
}
/* Start finding ISA boards from module arg */
for (b = 0; b < MXSER_BOARDS && m < MXSER_BOARDS; b++) {
int cap;
+
if (!(cap = ioaddr[b]))
continue;
retval = mxser_get_ISA_conf(cap, &hwconf);
if (retval != 0)
- printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n", mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
+ printk(KERN_INFO "Found MOXA %s board (CAP=0x%x)\n",
+ mxser_brdname[hwconf.board_type - 1], ioaddr[b]);
if (retval <= 0) {
if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+ printk(KERN_ERR "Invalid interrupt vector, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address,board not configured\n");
+ printk(KERN_ERR "Invalid I/O address, "
+ "board not configured\n");
continue;
}
@@ -803,8 +822,11 @@ static int mxser_init(void)
hwconf.pciInfo.pdev = NULL;
mxser_getcfg(m, &hwconf);
- //init mxsercfg first, or mxsercfg data is not correct on ISR.
- //mxser_initbrd will hook ISR.
+ /*
+ * init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(m, &hwconf) < 0)
continue;
@@ -817,7 +839,8 @@ static int mxser_init(void)
index = 0;
b = 0;
while (b < n) {
- pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev);
+ pdev = pci_find_device(mxser_pcibrds[b].vendor,
+ mxser_pcibrds[b].device, pdev);
if (pdev == NULL) {
b++;
continue;
@@ -825,30 +848,48 @@ static int mxser_init(void)
hwconf.pciInfo.busNum = busnum = pdev->bus->number;
hwconf.pciInfo.devNum = devnum = PCI_SLOT(pdev->devfn) << 3;
hwconf.pciInfo.pdev = pdev;
- printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n", mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1], busnum, devnum >> 3);
+ printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
+ mxser_brdname[(int) (mxser_pcibrds[b].driver_data) - 1],
+ busnum, devnum >> 3);
index++;
- if (m >= MXSER_BOARDS) {
- printk(KERN_ERR "Too many Smartio/Industio family boards find (maximum %d),board not configured\n", MXSER_BOARDS);
- } else {
+ if (m >= MXSER_BOARDS)
+ printk(KERN_ERR
+ "Too many Smartio/Industio family boards find "
+ "(maximum %d), board not configured\n",
+ MXSER_BOARDS);
+ else {
if (pci_enable_device(pdev)) {
- printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ printk(KERN_ERR "Moxa SmartI/O PCI enable "
+ "fail !\n");
continue;
}
- retval = mxser_get_PCI_conf(busnum, devnum, (int) mxser_pcibrds[b].driver_data, &hwconf);
+ retval = mxser_get_PCI_conf(busnum, devnum,
+ (int)mxser_pcibrds[b].driver_data,
+ &hwconf);
if (retval < 0) {
if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR
+ "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR "Invalid interrupt number,board not configured\n");
+ printk(KERN_ERR
+ "Invalid interrupt number, "
+ "board not configured\n");
else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR "Invalid interrupt vector,board not configured\n");
+ printk(KERN_ERR
+ "Invalid interrupt vector, "
+ "board not configured\n");
else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR "Invalid I/O address,board not configured\n");
+ printk(KERN_ERR
+ "Invalid I/O address, "
+ "board not configured\n");
continue;
}
mxser_getcfg(m, &hwconf);
- //init mxsercfg first, or mxsercfg data is not correct on ISR.
- //mxser_initbrd will hook ISR.
+ /* init mxsercfg first,
+ * or mxsercfg data is not correct on ISR.
+ */
+ /* mxser_initbrd will hook ISR. */
if (mxser_initbrd(m, &hwconf) < 0)
continue;
m++;
@@ -858,7 +899,8 @@ static int mxser_init(void)
retval = tty_register_driver(mxvar_sdriver);
if (retval) {
- printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family driver !\n");
+ printk(KERN_ERR "Couldn't install MOXA Smartio/Industio family"
+ " driver !\n");
put_tty_driver(mxvar_sdriver);
for (i = 0; i < MXSER_BOARDS; i++) {
@@ -866,7 +908,7 @@ static int mxser_init(void)
continue;
else {
free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]);
- //todo: release io, vector
+ /* todo: release io, vector */
}
}
return retval;
@@ -877,7 +919,7 @@ static int mxser_init(void)
static void mxser_do_softint(void *private_)
{
- struct mxser_struct *info = (struct mxser_struct *) private_;
+ struct mxser_struct *info = private_;
struct tty_struct *tty;
tty = info->tty;
@@ -926,7 +968,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
return -ENODEV;
info = mxvar_table + line;
if (!info->base)
- return (-ENODEV);
+ return -ENODEV;
tty->driver_data = info;
info->tty = tty;
@@ -935,11 +977,11 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
*/
retval = mxser_startup(info);
if (retval)
- return (retval);
+ return retval;
retval = mxser_block_til_ready(tty, filp, info);
if (retval)
- return (retval);
+ return retval;
info->count++;
@@ -953,13 +995,13 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
info->session = current->signal->session;
info->pgrp = process_group(current);
- clear_bit(TTY_DONT_FLIP, &tty->flags);
- //status = mxser_get_msr(info->base, 0, info->port);
- //mxser_check_modem_status(info, status);
+ /*
+ status = mxser_get_msr(info->base, 0, info->port);
+ mxser_check_modem_status(info, status);
+ */
-/* unmark here for very high baud rate (ex. 921600 bps) used
-*/
+/* unmark here for very high baud rate (ex. 921600 bps) used */
tty->low_latency = 1;
return 0;
}
@@ -972,7 +1014,7 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
*/
static void mxser_close(struct tty_struct *tty, struct file *filp)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long timeout;
unsigned long flags;
@@ -997,11 +1039,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk(KERN_ERR "mxser_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count);
+ printk(KERN_ERR "mxser_close: bad serial port count; "
+ "tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
- printk(KERN_ERR "mxser_close: bad serial port count for ttys%d: %d\n", info->port, info->count);
+ printk(KERN_ERR "mxser_close: bad serial port count for "
+ "ttys%d: %d\n", info->port, info->count);
info->count = 0;
}
if (info->count) {
@@ -1056,7 +1100,7 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
ld = tty_ldisc_ref(tty);
if (ld) {
- if(ld->flush_buffer)
+ if (ld->flush_buffer)
ld->flush_buffer(tty);
tty_ldisc_deref(ld);
}
@@ -1078,31 +1122,34 @@ static void mxser_close(struct tty_struct *tty, struct file *filp)
static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
int c, total = 0;
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if (!tty || !info->xmit_buf)
- return (0);
+ if (!info->xmit_buf)
+ return 0;
while (1) {
- c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head));
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
memcpy(info->xmit_buf + info->xmit_head, buf, c);
spin_lock_irqsave(&info->slock, flags);
- info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
+ info->xmit_head = (info->xmit_head + c) &
+ (SERIAL_XMIT_SIZE - 1);
info->xmit_cnt += c;
spin_unlock_irqrestore(&info->slock, flags);
buf += c;
count -= c;
total += c;
-
}
if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {
- if (!tty->hw_stopped || (info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ (info->IsMoxaMustChipFlag)) {
spin_lock_irqsave(&info->slock, flags);
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
@@ -1114,10 +1161,10 @@ static int mxser_write(struct tty_struct *tty, const unsigned char *buf, int cou
static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
@@ -1129,7 +1176,9 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
info->xmit_cnt++;
spin_unlock_irqrestore(&info->slock, flags);
if (!tty->stopped && !(info->IER & UART_IER_THRI)) {
- if (!tty->hw_stopped || (info->type == PORT_16550A) || info->IsMoxaMustChipFlag) {
+ if (!tty->hw_stopped ||
+ (info->type == PORT_16550A) ||
+ info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
@@ -1141,10 +1190,16 @@ static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
static void mxser_flush_chars(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf || (tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)))
+ if (info->xmit_cnt <= 0 ||
+ tty->stopped ||
+ !info->xmit_buf ||
+ (tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)
+ ))
return;
spin_lock_irqsave(&info->slock, flags);
@@ -1157,24 +1212,24 @@ static void mxser_flush_chars(struct tty_struct *tty)
static int mxser_write_room(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
int ret;
ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
if (ret < 0)
ret = 0;
- return (ret);
+ return ret;
}
static int mxser_chars_in_buffer(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
return info->xmit_cnt;
}
static void mxser_flush_buffer(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
char fcr;
unsigned long flags;
@@ -1184,7 +1239,8 @@ static void mxser_flush_buffer(struct tty_struct *tty)
/* below added by shinhay */
fcr = inb(info->base + UART_FCR);
- outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
outb(fcr, info->base + UART_FCR);
spin_unlock_irqrestore(&info->slock, flags);
@@ -1197,7 +1253,7 @@ static void mxser_flush_buffer(struct tty_struct *tty)
static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
int retval;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser;
@@ -1206,9 +1262,9 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
void __user *argp = (void __user *)arg;
if (tty->index == MXSER_PORTS)
- return (mxser_ioctl_special(cmd, argp));
+ return mxser_ioctl_special(cmd, argp);
- // following add by Victor Yu. 01-05-2004
+ /* following add by Victor Yu. 01-05-2004 */
if (cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE) {
int opmode, p;
static unsigned char ModeMask[] = { 0xfc, 0xf3, 0xcf, 0x3f };
@@ -1219,7 +1275,10 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
if (cmd == MOXA_SET_OP_MODE) {
if (get_user(opmode, (int __user *) argp))
return -EFAULT;
- if (opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE)
+ if (opmode != RS232_MODE &&
+ opmode != RS485_2WIRE_MODE &&
+ opmode != RS422_MODE &&
+ opmode != RS485_4WIRE_MODE)
return -EFAULT;
mask = ModeMask[p];
shiftbit = p * 2;
@@ -1236,36 +1295,36 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
}
return 0;
}
- // above add by Victor Yu. 01-05-2004
+ /* above add by Victor Yu. 01-05-2004 */
if ((cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
if (tty->flags & (1 << TTY_IO_ERROR))
- return (-EIO);
+ return -EIO;
}
switch (cmd) {
case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
- return (retval);
+ return retval;
tty_wait_until_sent(tty, 0);
if (!arg)
mxser_send_break(info, HZ / 4); /* 1/4 second */
- return (0);
+ return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
- return (retval);
+ return retval;
tty_wait_until_sent(tty, 0);
mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
- return (0);
+ return 0;
case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
case TIOCSSOFTCAR:
if (get_user(templ, (unsigned long __user *) argp))
return -EFAULT;
arg = templ;
tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return (0);
+ return 0;
case TIOCGSERIAL:
return mxser_get_serial_info(info, argp);
case TIOCSSERIAL:
@@ -1278,7 +1337,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
* (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
* Caller should use TIOCGICOUNT to see which one it was
*/
- case TIOCMIWAIT:{
+ case TIOCMIWAIT: {
DECLARE_WAITQUEUE(wait, current);
int ret;
spin_lock_irqsave(&info->slock, flags);
@@ -1292,7 +1351,14 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
spin_unlock_irqrestore(&info->slock, flags);
set_current_state(TASK_INTERRUPTIBLE);
- if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ if (((arg & TIOCM_RNG) &&
+ (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) &&
+ (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) &&
+ (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) &&
+ (cnow.cts != cprev.cts))) {
ret = 0;
break;
}
@@ -1338,21 +1404,18 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
put_user(cnow.dsr, &p_cuser->dsr);
put_user(cnow.rng, &p_cuser->rng);
put_user(cnow.dcd, &p_cuser->dcd);
-
-/* */
return 0;
case MOXA_HighSpeedOn:
- return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *) argp);
-
- case MOXA_SDS_RSTICOUNTER:{
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
+ case MOXA_SDS_RSTICOUNTER: {
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
return 0;
}
-// (above) added by James.
+/* (above) added by James. */
case MOXA_ASPP_SETBAUD:{
long baud;
- if (get_user(baud, (long __user *) argp))
+ if (get_user(baud, (long __user *)argp))
return -EFAULT;
mxser_set_baud(info, baud);
return 0;
@@ -1377,9 +1440,10 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
return 0;
}
- case MOXA_ASPP_MON:{
+ case MOXA_ASPP_MON: {
int mcr, status;
-// info->mon_data.ser_param = tty->termios->c_cflag;
+
+ /* info->mon_data.ser_param = tty->termios->c_cflag; */
status = mxser_get_msr(info->base, 1, info->port, info);
mxser_check_modem_status(info, status);
@@ -1400,25 +1464,25 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, unsigned int c
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
- if (copy_to_user(argp, &info->mon_data, sizeof(struct mxser_mon)))
+ if (copy_to_user(argp, &info->mon_data,
+ sizeof(struct mxser_mon)))
return -EFAULT;
return 0;
-
}
- case MOXA_ASPP_LSTATUS:{
- if (copy_to_user(argp, &info->err_shadow, sizeof(unsigned char)))
+ case MOXA_ASPP_LSTATUS: {
+ if (copy_to_user(argp, &info->err_shadow,
+ sizeof(unsigned char)))
return -EFAULT;
info->err_shadow = 0;
return 0;
-
}
- case MOXA_SET_BAUD_METHOD:{
+ case MOXA_SET_BAUD_METHOD: {
int method;
- if (get_user(method, (int __user *) argp))
+
+ if (get_user(method, (int __user *)argp))
return -EFAULT;
mxser_set_baud_method[info->port] = method;
if (copy_to_user(argp, &method, sizeof(int)))
@@ -1442,7 +1506,8 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
switch (cmd) {
case MOXA_GET_CONF:
- if (copy_to_user(argp, mxsercfg, sizeof(struct mxser_hwconf) * 4))
+ if (copy_to_user(argp, mxsercfg,
+ sizeof(struct mxser_hwconf) * 4))
return -EFAULT;
return 0;
case MOXA_GET_MAJOR:
@@ -1461,11 +1526,11 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
if (mxvar_table[i].base)
result |= (1 << i);
}
- return put_user(result, (unsigned long __user *) argp);
+ return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
return -EFAULT;
- return (0);
+ return 0;
case MOXA_GETMSTATUS:
for (i = 0; i < MXSER_PORTS; i++) {
GMStatus[i].ri = 0;
@@ -1498,22 +1563,26 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
else
GMStatus[i].cts = 0;
}
- if (copy_to_user(argp, GMStatus, sizeof(struct mxser_mstatus) * MXSER_PORTS))
+ if (copy_to_user(argp, GMStatus,
+ sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
return 0;
- case MOXA_ASPP_MON_EXT:{
+ case MOXA_ASPP_MON_EXT: {
int status;
int opmode, p;
int shiftbit;
unsigned cflag, iflag;
for (i = 0; i < MXSER_PORTS; i++) {
-
if (!mxvar_table[i].base)
continue;
- status = mxser_get_msr(mxvar_table[i].base, 0, i, &(mxvar_table[i]));
-// mxser_check_modem_status(&mxvar_table[i], status);
+ status = mxser_get_msr(mxvar_table[i].base, 0,
+ i, &(mxvar_table[i]));
+ /*
+ mxser_check_modem_status(&mxvar_table[i],
+ status);
+ */
if (status & UART_MSR_TERI)
mxvar_table[i].icount.rng++;
if (status & UART_MSR_DDSR)
@@ -1578,75 +1647,76 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
return 0;
}
-
static void mxser_stoprx(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
- //unsigned long flags;
-
+ struct mxser_struct *info = tty->driver_data;
+ /* unsigned long flags; */
info->ldisc_stop_rx = 1;
if (I_IXOFF(tty)) {
-
- //MX_LOCK(&info->slock);
- // following add by Victor Yu. 09-02-2002
+ /* MX_LOCK(&info->slock); */
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
info->IER &= ~MOXA_MUST_RECV_ISR;
outb(info->IER, info->base + UART_IER);
} else {
- // above add by Victor Yu. 09-02-2002
-
+ /* above add by Victor Yu. 09-02-2002 */
info->x_char = STOP_CHAR(tty);
- // outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
+ /* mask by Victor Yu. 09-02-2002 */
+ /* outb(info->IER, 0); */
outb(0, info->base + UART_IER);
info->IER |= UART_IER_THRI;
- outb(info->IER, info->base + UART_IER); /* force Tx interrupt */
- } // add by Victor Yu. 09-02-2002
- //MX_UNLOCK(&info->slock);
+ /* force Tx interrupt */
+ outb(info->IER, info->base + UART_IER);
+ } /* add by Victor Yu. 09-02-2002 */
+ /* MX_UNLOCK(&info->slock); */
}
if (info->tty->termios->c_cflag & CRTSCTS) {
- //MX_LOCK(&info->slock);
+ /* MX_LOCK(&info->slock); */
info->MCR &= ~UART_MCR_RTS;
outb(info->MCR, info->base + UART_MCR);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
}
static void mxser_startrx(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
- //unsigned long flags;
+ struct mxser_struct *info = tty->driver_data;
+ /* unsigned long flags; */
info->ldisc_stop_rx = 0;
if (I_IXOFF(tty)) {
if (info->x_char)
info->x_char = 0;
else {
- //MX_LOCK(&info->slock);
+ /* MX_LOCK(&info->slock); */
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
info->IER |= MOXA_MUST_RECV_ISR;
outb(info->IER, info->base + UART_IER);
} else {
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
info->x_char = START_CHAR(tty);
- // outb(info->IER, 0); // mask by Victor Yu. 09-02-2002
- outb(0, info->base + UART_IER); // add by Victor Yu. 09-02-2002
- info->IER |= UART_IER_THRI; /* force Tx interrupt */
+ /* mask by Victor Yu. 09-02-2002 */
+ /* outb(info->IER, 0); */
+ /* add by Victor Yu. 09-02-2002 */
+ outb(0, info->base + UART_IER);
+ /* force Tx interrupt */
+ info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
- } // add by Victor Yu. 09-02-2002
- //MX_UNLOCK(&info->slock);
+ } /* add by Victor Yu. 09-02-2002 */
+ /* MX_UNLOCK(&info->slock); */
}
}
if (info->tty->termios->c_cflag & CRTSCTS) {
- //MX_LOCK(&info->slock);
+ /* MX_LOCK(&info->slock); */
info->MCR |= UART_MCR_RTS;
outb(info->MCR, info->base + UART_MCR);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
}
@@ -1656,48 +1726,53 @@ static void mxser_startrx(struct tty_struct *tty)
*/
static void mxser_throttle(struct tty_struct *tty)
{
- //struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
- //unsigned long flags;
- //MX_LOCK(&info->slock);
+ /* struct mxser_struct *info = tty->driver_data; */
+ /* unsigned long flags; */
+
+ /* MX_LOCK(&info->slock); */
mxser_stoprx(tty);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
static void mxser_unthrottle(struct tty_struct *tty)
{
- //struct mxser_struct *info = (struct mxser_struct *)tty->driver_data;
- //unsigned long flags;
- //MX_LOCK(&info->slock);
+ /* struct mxser_struct *info = tty->driver_data; */
+ /* unsigned long flags; */
+
+ /* MX_LOCK(&info->slock); */
mxser_startrx(tty);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
}
static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
- if ((tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
+ if ((tty->termios->c_cflag != old_termios->c_cflag) ||
+ (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) {
mxser_change_speed(info, old_termios);
- if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS)) {
tty->hw_stopped = 0;
mxser_start(tty);
}
}
/* Handle sw stopped */
- if ((old_termios->c_iflag & IXON) && !(tty->termios->c_iflag & IXON)) {
+ if ((old_termios->c_iflag & IXON) &&
+ !(tty->termios->c_iflag & IXON)) {
tty->stopped = 0;
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
spin_unlock_irqrestore(&info->slock, flags);
}
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
mxser_start(tty);
}
@@ -1711,7 +1786,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct termios *old_termio
*/
static void mxser_stop(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
@@ -1724,7 +1799,7 @@ static void mxser_stop(struct tty_struct *tty)
static void mxser_start(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
@@ -1740,7 +1815,7 @@ static void mxser_start(struct tty_struct *tty)
*/
static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
int lsr;
@@ -1777,7 +1852,8 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
if (!timeout || timeout > 2 * info->timeout)
timeout = 2 * info->timeout;
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
- printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+ printk(KERN_DEBUG "In rs_wait_until_sent(%d) check=%lu...",
+ timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
while (!((lsr = inb(info->base + UART_LSR)) & UART_LSR_TEMT)) {
@@ -1803,7 +1879,7 @@ static void mxser_wait_until_sent(struct tty_struct *tty, int timeout)
*/
void mxser_hangup(struct tty_struct *tty)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
mxser_flush_buffer(tty);
mxser_shutdown(info);
@@ -1815,24 +1891,26 @@ void mxser_hangup(struct tty_struct *tty)
}
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
/*
* mxser_rs_break() --- routine which turns the break handling on or off
*/
static void mxser_rs_break(struct tty_struct *tty, int break_state)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
spin_lock_irqsave(&info->slock, flags);
if (break_state == -1)
- outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+ info->base + UART_LCR);
else
- outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+ info->base + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
}
-// (above) added by James.
+/* (above) added by James. */
/*
@@ -1848,7 +1926,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
int handled = IRQ_NONE;
port = NULL;
- //spin_lock(&gm_lock);
+ /* spin_lock(&gm_lock); */
for (i = 0; i < MXSER_BOARDS; i++) {
if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
@@ -1857,29 +1935,25 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
- if (i == MXSER_BOARDS) {
+ if (i == MXSER_BOARDS)
goto irq_stop;
- }
- if (port == 0) {
+ if (port == 0)
goto irq_stop;
- }
max = mxser_numports[mxsercfg[i].board_type - 1];
while (1) {
irqbits = inb(port->vector) & port->vectormask;
- if (irqbits == port->vectormask) {
+ if (irqbits == port->vectormask)
break;
- }
handled = IRQ_HANDLED;
for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
- if (irqbits == port->vectormask) {
+ if (irqbits == port->vectormask)
break;
- }
if (bits & irqbits)
continue;
info = port + i;
- // following add by Victor Yu. 09-13-2002
+ /* following add by Victor Yu. 09-13-2002 */
iir = inb(info->base + UART_IIR);
if (iir & UART_IIR_NO_INT)
continue;
@@ -1890,9 +1964,9 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
inb(info->base + UART_MSR);
continue;
}
- // above add by Victor Yu. 09-13-2002
+ /* above add by Victor Yu. 09-13-2002 */
/*
- if ( info->tty->flip.count < TTY_FLIPBUF_SIZE/4 ){
+ if (info->tty->flip.count < TTY_FLIPBUF_SIZE / 4) {
info->IER |= MOXA_MUST_RECV_ISR;
outb(info->IER, info->base + UART_IER);
}
@@ -1908,18 +1982,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = inb(info->base + UART_LSR) & info->read_status_mask;
*/
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
status = inb(info->base + UART_LSR);
- if (status & UART_LSR_PE) {
+ if (status & UART_LSR_PE)
info->err_shadow |= NPPI_NOTIFY_PARITY;
- }
- if (status & UART_LSR_FE) {
+ if (status & UART_LSR_FE)
info->err_shadow |= NPPI_NOTIFY_FRAMING;
- }
- if (status & UART_LSR_OE) {
+ if (status & UART_LSR_OE)
info->err_shadow |= NPPI_NOTIFY_HW_OVERRUN;
- }
if (status & UART_LSR_BI)
info->err_shadow |= NPPI_NOTIFY_BREAK;
@@ -1930,11 +2001,14 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
continue;
}
*/
- if (iir == MOXA_MUST_IIR_GDA || iir == MOXA_MUST_IIR_RDA || iir == MOXA_MUST_IIR_RTO || iir == MOXA_MUST_IIR_LSR)
+ if (iir == MOXA_MUST_IIR_GDA ||
+ iir == MOXA_MUST_IIR_RDA ||
+ iir == MOXA_MUST_IIR_RTO ||
+ iir == MOXA_MUST_IIR_LSR)
mxser_receive_chars(info, &status);
} else {
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
status &= info->read_status_mask;
if (status & UART_LSR_DR)
@@ -1944,13 +2018,13 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (msr & UART_MSR_ANY_DELTA) {
mxser_check_modem_status(info, msr);
}
- // following add by Victor Yu. 09-13-2002
+ /* following add by Victor Yu. 09-13-2002 */
if (info->IsMoxaMustChipFlag) {
if ((iir == 0x02) && (status & UART_LSR_THRE)) {
mxser_transmit_chars(info);
}
} else {
- // above add by Victor Yu. 09-13-2002
+ /* above add by Victor Yu. 09-13-2002 */
if (status & UART_LSR_THRE) {
/* 8-2-99 by William
@@ -1966,7 +2040,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
irq_stop:
- //spin_unlock(&gm_lock);
+ /* spin_unlock(&gm_lock); */
return handled;
}
@@ -1984,56 +2058,58 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status)
recv_room = tty->receive_room;
if ((recv_room == 0) && (!info->ldisc_stop_rx)) {
- //mxser_throttle(tty);
+ /* mxser_throttle(tty); */
mxser_stoprx(tty);
- //return;
+ /* return; */
}
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) {
if (*status & UART_LSR_SPECIAL) {
goto intr_old;
}
- // following add by Victor Yu. 02-11-2004
- if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID && (*status & MOXA_MUST_LSR_RERR))
+ /* following add by Victor Yu. 02-11-2004 */
+ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU860_HWID &&
+ (*status & MOXA_MUST_LSR_RERR))
goto intr_old;
- // above add by Victor Yu. 02-14-2004
+ /* above add by Victor Yu. 02-14-2004 */
if (*status & MOXA_MUST_LSR_RERR)
goto intr_old;
gdl = inb(info->base + MOXA_MUST_GDL_REGISTER);
- if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID) // add by Victor Yu. 02-11-2004
+ /* add by Victor Yu. 02-11-2004 */
+ if (info->IsMoxaMustChipFlag == MOXA_MUST_MU150_HWID)
gdl &= MOXA_MUST_GDL_MASK;
if (gdl >= recv_room) {
if (!info->ldisc_stop_rx) {
- //mxser_throttle(tty);
+ /* mxser_throttle(tty); */
mxser_stoprx(tty);
}
- //return;
+ /* return; */
}
while (gdl--) {
ch = inb(info->base + UART_RX);
tty_insert_flip_char(tty, ch, 0);
cnt++;
/*
- if((cnt>=HI_WATER) && (info->stop_rx==0)){
+ if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
mxser_stoprx(tty);
- info->stop_rx=1;
+ info->stop_rx = 1;
break;
} */
}
goto end_intr;
}
-intr_old:
- // above add by Victor Yu. 09-02-2002
+ intr_old:
+ /* above add by Victor Yu. 09-02-2002 */
do {
if (max-- < 0)
break;
/*
- if((cnt>=HI_WATER) && (info->stop_rx==0)){
+ if ((cnt >= HI_WATER) && (info->stop_rx == 0)) {
mxser_stoprx(tty);
info->stop_rx=1;
break;
@@ -2041,11 +2117,11 @@ intr_old:
*/
ch = inb(info->base + UART_RX);
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag && (*status & UART_LSR_OE) /*&& !(*status&UART_LSR_DR) */ )
outb(0x23, info->base + UART_FCR);
*status &= info->read_status_mask;
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
if (*status & info->ignore_status_mask) {
if (++ignored > 100)
break;
@@ -2080,7 +2156,7 @@ intr_old:
cnt++;
if (cnt >= recv_room) {
if (!info->ldisc_stop_rx) {
- //mxser_throttle(tty);
+ /* mxser_throttle(tty); */
mxser_stoprx(tty);
}
break;
@@ -2088,21 +2164,20 @@ intr_old:
}
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag)
break;
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
/* mask by Victor Yu. 09-02-2002
*status = inb(info->base + UART_LSR) & info->read_status_mask;
*/
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
*status = inb(info->base + UART_LSR);
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
} while (*status & UART_LSR_DR);
-end_intr: // add by Victor Yu. 09-02-2002
-
+end_intr: /* add by Victor Yu. 09-02-2002 */
mxvar_log.rxcnt[info->port] += cnt;
info->mon_data.rxcnt += cnt;
info->mon_data.up_rxcnt += cnt;
@@ -2137,7 +2212,10 @@ static void mxser_transmit_chars(struct mxser_struct *info)
return;
}
- if ((info->xmit_cnt <= 0) || info->tty->stopped || (info->tty->hw_stopped && (info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag))) {
+ if ((info->xmit_cnt <= 0) || info->tty->stopped ||
+ (info->tty->hw_stopped &&
+ (info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag))) {
info->IER &= ~UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
spin_unlock_irqrestore(&info->slock, flags);
@@ -2147,17 +2225,18 @@ static void mxser_transmit_chars(struct mxser_struct *info)
cnt = info->xmit_cnt;
count = info->xmit_fifo_size;
do {
- outb(info->xmit_buf[info->xmit_tail++], info->base + UART_TX);
+ outb(info->xmit_buf[info->xmit_tail++],
+ info->base + UART_TX);
info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE - 1);
if (--info->xmit_cnt <= 0)
break;
} while (--count > 0);
mxvar_log.txcnt[info->port] += (cnt - info->xmit_cnt);
-// added by James 03-12-2004.
+/* added by James 03-12-2004. */
info->mon_data.txcnt += (cnt - info->xmit_cnt);
info->mon_data.up_txcnt += (cnt - info->xmit_cnt);
-// (above) added by James.
+/* (above) added by James. */
/* added by casper 1/11/2000 */
info->icount.tx += (cnt - info->xmit_cnt);
@@ -2188,7 +2267,6 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
info->mon_data.modem_status = status;
wake_up_interruptible(&info->delta_msr_wait);
-
if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
@@ -2200,7 +2278,8 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
if (status & UART_MSR_CTS) {
info->tty->hw_stopped = 0;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2209,7 +2288,8 @@ static void mxser_check_modem_status(struct mxser_struct *info, int status)
} else {
if (!(status & UART_MSR_CTS)) {
info->tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER &= ~UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2231,7 +2311,7 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
*/
if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE;
- return (0);
+ return 0;
}
if (tty->termios->c_cflag & CLOCAL)
@@ -2254,7 +2334,8 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
info->blocked_open++;
while (1) {
spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
+ outb(inb(info->base + UART_MCR) |
+ UART_MCR_DTR | UART_MCR_RTS, info->base + UART_MCR);
spin_unlock_irqrestore(&info->slock, flags);
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {
@@ -2264,7 +2345,9 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
retval = -ERESTARTSYS;
break;
}
- if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD)))
+ if (!(info->flags & ASYNC_CLOSING) &&
+ (do_clocal ||
+ (inb(info->base + UART_MSR) & UART_MSR_DCD)))
break;
if (signal_pending(current)) {
retval = -ERESTARTSYS;
@@ -2278,27 +2361,26 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, stru
info->count++;
info->blocked_open--;
if (retval)
- return (retval);
+ return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
- return (0);
+ return 0;
}
static int mxser_startup(struct mxser_struct *info)
{
-
unsigned long page;
unsigned long flags;
page = __get_free_page(GFP_KERNEL);
if (!page)
- return (-ENOMEM);
+ return -ENOMEM;
spin_lock_irqsave(&info->slock, flags);
if (info->flags & ASYNC_INITIALIZED) {
free_page(page);
spin_unlock_irqrestore(&info->slock, flags);
- return (0);
+ return 0;
}
if (!info->base || !info->type) {
@@ -2306,7 +2388,7 @@ static int mxser_startup(struct mxser_struct *info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
free_page(page);
spin_unlock_irqrestore(&info->slock, flags);
- return (0);
+ return 0;
}
if (info->xmit_buf)
free_page(page);
@@ -2318,9 +2400,12 @@ static int mxser_startup(struct mxser_struct *info)
* (they will be reenabled in mxser_change_speed())
*/
if (info->IsMoxaMustChipFlag)
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
else
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
/*
* At this point there's no way the LSR could still be 0xFF;
@@ -2332,9 +2417,9 @@ static int mxser_startup(struct mxser_struct *info)
if (capable(CAP_SYS_ADMIN)) {
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- return (0);
+ return 0;
} else
- return (-ENODEV);
+ return -ENODEV;
}
/*
@@ -2356,12 +2441,12 @@ static int mxser_startup(struct mxser_struct *info)
* Finally, enable interrupts
*/
info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI;
-// info->IER = UART_IER_RLSI | UART_IER_RDI;
+ /* info->IER = UART_IER_RLSI | UART_IER_RDI; */
- // following add by Victor Yu. 08-30-2002
+ /* following add by Victor Yu. 08-30-2002 */
if (info->IsMoxaMustChipFlag)
info->IER |= MOXA_MUST_IER_EGDAI;
- // above add by Victor Yu. 08-30-2002
+ /* above add by Victor Yu. 08-30-2002 */
outb(info->IER, info->base + UART_IER); /* enable interrupts */
/*
@@ -2383,7 +2468,7 @@ static int mxser_startup(struct mxser_struct *info)
mxser_change_speed(info, NULL);
info->flags |= ASYNC_INITIALIZED;
- return (0);
+ return 0;
}
/*
@@ -2421,12 +2506,15 @@ static void mxser_shutdown(struct mxser_struct *info)
outb(info->MCR, info->base + UART_MCR);
/* clear Rx/Tx FIFO's */
- // following add by Victor Yu. 08-30-2002
+ /* following add by Victor Yu. 08-30-2002 */
if (info->IsMoxaMustChipFlag)
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
+ outb((UART_FCR_CLEAR_RCVR |
+ UART_FCR_CLEAR_XMIT |
+ MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
else
- // above add by Victor Yu. 08-30-2002
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
+ /* above add by Victor Yu. 08-30-2002 */
+ outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->base + UART_FCR);
/* read data port to reset things */
(void) inb(info->base + UART_RX);
@@ -2436,11 +2524,10 @@ static void mxser_shutdown(struct mxser_struct *info)
info->flags &= ~ASYNC_INITIALIZED;
- // following add by Victor Yu. 09-23-2002
- if (info->IsMoxaMustChipFlag) {
+ /* following add by Victor Yu. 09-23-2002 */
+ if (info->IsMoxaMustChipFlag)
SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
- }
- // above add by Victor Yu. 09-23-2002
+ /* above add by Victor Yu. 09-23-2002 */
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -2457,14 +2544,12 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
long baud;
unsigned long flags;
-
if (!info->tty || !info->tty->termios)
return ret;
cflag = info->tty->termios->c_cflag;
if (!(info->base))
return ret;
-
#ifndef B921600
#define B921600 (B460800 +1)
#endif
@@ -2559,9 +2644,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
cval |= 0x04;
if (cflag & PARENB)
cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD)) {
+ if (!(cflag & PARODD))
cval |= UART_LCR_EPAR;
- }
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
@@ -2574,13 +2658,12 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
- // following add by Victor Yu. 08-30-2002
+ /* following add by Victor Yu. 08-30-2002 */
if (info->IsMoxaMustChipFlag) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
SET_MOXA_MUST_FIFO_VALUE(info);
} else {
- // above add by Victor Yu. 08-30-2002
-
+ /* above add by Victor Yu. 08-30-2002 */
switch (info->rx_trigger) {
case 1:
fcr |= UART_FCR_TRIGGER_1;
@@ -2606,22 +2689,24 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
info->IER |= UART_IER_MSI;
if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
info->MCR |= UART_MCR_AFE;
- //status = mxser_get_msr(info->base, 0, info->port);
-/* save_flags(flags);
+ /* status = mxser_get_msr(info->base, 0, info->port); */
+/*
+ save_flags(flags);
cli();
status = inb(baseaddr + UART_MSR);
- restore_flags(flags);*/
- //mxser_check_modem_status(info, status);
+ restore_flags(flags);
+*/
+ /* mxser_check_modem_status(info, status); */
} else {
- //status = mxser_get_msr(info->base, 0, info->port);
-
- //MX_LOCK(&info->slock);
+ /* status = mxser_get_msr(info->base, 0, info->port); */
+ /* MX_LOCK(&info->slock); */
status = inb(info->base + UART_MSR);
- //MX_UNLOCK(&info->slock);
+ /* MX_UNLOCK(&info->slock); */
if (info->tty->hw_stopped) {
if (status & UART_MSR_CTS) {
info->tty->hw_stopped = 0;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER |= UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2630,7 +2715,8 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
} else {
if (!(status & UART_MSR_CTS)) {
info->tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
+ if ((info->type != PORT_16550A) &&
+ (!info->IsMoxaMustChipFlag)) {
info->IER &= ~UART_IER_THRI;
outb(info->IER, info->base + UART_IER);
}
@@ -2668,11 +2754,17 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty)) {
- info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
- info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
+ info->ignore_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
+ info->read_status_mask |=
+ UART_LSR_OE |
+ UART_LSR_PE |
+ UART_LSR_FE;
}
}
- // following add by Victor Yu. 09-02-2002
+ /* following add by Victor Yu. 09-02-2002 */
if (info->IsMoxaMustChipFlag) {
spin_lock_irqsave(&info->slock, flags);
SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
@@ -2698,7 +2790,7 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
*/
spin_unlock_irqrestore(&info->slock, flags);
}
- // above add by Victor Yu. 09-02-2002
+ /* above add by Victor Yu. 09-02-2002 */
outb(fcr, info->base + UART_FCR); /* set fcr */
@@ -2729,10 +2821,8 @@ static int mxser_set_baud(struct mxser_struct *info, long newspd)
quot = (2 * info->baud_base / 269);
} else if (newspd) {
quot = info->baud_base / newspd;
-
if (quot == 0)
quot = 1;
-
} else {
quot = 0;
}
@@ -2765,8 +2855,6 @@ static int mxser_set_baud(struct mxser_struct *info, long newspd)
return ret;
}
-
-
/*
* ------------------------------------------------------------
* friends of mxser_ioctl()
@@ -2777,7 +2865,7 @@ static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct
struct serial_struct tmp;
if (!retinfo)
- return (-EFAULT);
+ return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
tmp.type = info->type;
tmp.line = info->port;
@@ -2791,7 +2879,7 @@ static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct
tmp.hub6 = 0;
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
- return (0);
+ return 0;
}
static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
@@ -2801,29 +2889,37 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
int retval = 0;
if (!new_info || !info->base)
- return (-EFAULT);
+ return -EFAULT;
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- if ((new_serial.irq != info->irq) || (new_serial.port != info->base) || (new_serial.custom_divisor != info->custom_divisor) || (new_serial.baud_base != info->baud_base))
- return (-EPERM);
+ if ((new_serial.irq != info->irq) ||
+ (new_serial.port != info->base) ||
+ (new_serial.custom_divisor != info->custom_divisor) ||
+ (new_serial.baud_base != info->baud_base))
+ return -EPERM;
flags = info->flags & ASYNC_SPD_MASK;
if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
- return (-EPERM);
- info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK));
+ if ((new_serial.baud_base != info->baud_base) ||
+ (new_serial.close_delay != info->close_delay) ||
+ ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
+ return -EPERM;
+ info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+ (new_serial.flags & ASYNC_USR_MASK));
} else {
/*
* OK, past this point, all the error checking has been done.
* At this point, we start making changes.....
*/
- info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS));
+ info->flags = ((info->flags & ~ASYNC_FLAGS) |
+ (new_serial.flags & ASYNC_FLAGS));
info->close_delay = new_serial.close_delay * HZ / 100;
info->closing_wait = new_serial.closing_wait * HZ / 100;
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->tty->low_latency = 0; //(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency =
+ (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+ info->tty->low_latency = 0; /* (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; */
}
/* added by casper, 3/17/2000, for mouse */
@@ -2831,7 +2927,6 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
process_txrx_fifo(info);
- /* */
if (info->flags & ASYNC_INITIALIZED) {
if (flags != (info->flags & ASYNC_SPD_MASK)) {
mxser_change_speed(info, NULL);
@@ -2839,7 +2934,7 @@ static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct
} else {
retval = mxser_startup(info);
}
- return (retval);
+ return retval;
}
/*
@@ -2876,25 +2971,27 @@ static void mxser_send_break(struct mxser_struct *info, int duration)
return;
set_current_state(TASK_INTERRUPTIBLE);
spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->base + UART_LCR) | UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) | UART_LCR_SBC,
+ info->base + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
schedule_timeout(duration);
spin_lock_irqsave(&info->slock, flags);
- outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC, info->base + UART_LCR);
+ outb(inb(info->base + UART_LCR) & ~UART_LCR_SBC,
+ info->base + UART_LCR);
spin_unlock_irqrestore(&info->slock, flags);
}
static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned char control, status;
unsigned long flags;
if (tty->index == MXSER_PORTS)
- return (-ENOIOCTLCMD);
+ return -ENOIOCTLCMD;
if (tty->flags & (1 << TTY_IO_ERROR))
- return (-EIO);
+ return -EIO;
control = info->MCR;
@@ -2904,12 +3001,16 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file)
mxser_check_modem_status(info, status);
spin_unlock_irqrestore(&info->slock, flags);
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) |
- ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
+ ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) |
+ ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) |
+ ((status & UART_MSR_RI) ? TIOCM_RNG : 0) |
+ ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) |
+ ((status & UART_MSR_CTS) ? TIOCM_CTS : 0);
}
static int mxser_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear)
{
- struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
+ struct mxser_struct *info = tty->driver_data;
unsigned long flags;
@@ -2968,38 +3069,36 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
hwconf->board_type = MXSER_BOARD_CI104J;
hwconf->ports = 4;
} else
- return (0);
+ return 0;
irq = 0;
if (hwconf->ports == 2) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
if (irq != (regs[9] & 0xFF00))
- return (MXSER_ERR_IRQ_CONFLIT);
+ return MXSER_ERR_IRQ_CONFLIT;
} else if (hwconf->ports == 4) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if (irq != regs[9])
- return (MXSER_ERR_IRQ_CONFLIT);
+ return MXSER_ERR_IRQ_CONFLIT;
} else if (hwconf->ports == 8) {
irq = regs[9] & 0xF000;
irq = irq | (irq >> 4);
irq = irq | (irq >> 8);
if ((irq != regs[9]) || (irq != regs[10]))
- return (MXSER_ERR_IRQ_CONFLIT);
+ return MXSER_ERR_IRQ_CONFLIT;
}
- if (!irq) {
- return (MXSER_ERR_IRQ);
- }
- hwconf->irq = ((int) (irq & 0xF000) >> 12);
+ if (!irq)
+ return MXSER_ERR_IRQ;
+ hwconf->irq = ((int)(irq & 0xF000) >> 12);
for (i = 0; i < 8; i++)
hwconf->ioaddr[i] = (int) regs[i + 1] & 0xFFF8;
- if ((regs[12] & 0x80) == 0) {
- return (MXSER_ERR_VECTOR);
- }
- hwconf->vector = (int) regs[11]; /* interrupt vector */
+ if ((regs[12] & 0x80) == 0)
+ return MXSER_ERR_VECTOR;
+ hwconf->vector = (int)regs[11]; /* interrupt vector */
if (id == 1)
hwconf->vector_mask = 0x00FF;
else
@@ -3007,10 +3106,10 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
for (i = 7, bits = 0x0100; i >= 0; i--, bits <<= 1) {
if (regs[12] & bits) {
hwconf->baud_base[i] = 921600;
- hwconf->MaxCanSetBaudRate[i] = 921600; // add by Victor Yu. 09-04-2002
+ hwconf->MaxCanSetBaudRate[i] = 921600; /* add by Victor Yu. 09-04-2002 */
} else {
hwconf->baud_base[i] = 115200;
- hwconf->MaxCanSetBaudRate[i] = 115200; // add by Victor Yu. 09-04-2002
+ hwconf->MaxCanSetBaudRate[i] = 115200; /* add by Victor Yu. 09-04-2002 */
}
}
scratch2 = inb(cap + UART_LCR) & (~UART_LCR_DLAB);
@@ -3030,7 +3129,7 @@ static int mxser_get_ISA_conf(int cap, struct mxser_hwconf *hwconf)
hwconf->ports = 4;
request_region(hwconf->ioaddr[0], 8 * hwconf->ports, "mxser(IO)");
request_region(hwconf->vector, 1, "mxser(vector)");
- return (hwconf->ports);
+ return hwconf->ports;
}
#define CHIP_SK 0x01 /* Serial Data Clock in Eprom */
@@ -3053,7 +3152,7 @@ static int mxser_read_register(int port, unsigned short *regs)
id = mxser_program_mode(port);
if (id < 0)
- return (id);
+ return id;
for (i = 0; i < 14; i++) {
k = (i & 0x3F) | 0x180;
for (j = 0x100; j > 0; j >>= 1) {
@@ -3066,7 +3165,7 @@ static int mxser_read_register(int port, unsigned short *regs)
outb(CHIP_CS | CHIP_SK, port); /* A? bit of read */
}
}
- (void) inb(port);
+ (void)inb(port);
value = 0;
for (k = 0, j = 0x8000; k < 16; k++, j >>= 1) {
outb(CHIP_CS, port);
@@ -3078,28 +3177,33 @@ static int mxser_read_register(int port, unsigned short *regs)
outb(0, port);
}
mxser_normal_mode(port);
- return (id);
+ return id;
}
static int mxser_program_mode(int port)
{
int id, i, j, n;
- //unsigned long flags;
+ /* unsigned long flags; */
spin_lock(&gm_lock);
outb(0, port);
outb(0, port);
outb(0, port);
- (void) inb(port);
- (void) inb(port);
+ (void)inb(port);
+ (void)inb(port);
outb(0, port);
- (void) inb(port);
- //restore_flags(flags);
+ (void)inb(port);
+ /* restore_flags(flags); */
spin_unlock(&gm_lock);
id = inb(port + 1) & 0x1F;
- if ((id != C168_ASIC_ID) && (id != C104_ASIC_ID) && (id != C102_ASIC_ID) && (id != CI132_ASIC_ID) && (id != CI134_ASIC_ID) && (id != CI104J_ASIC_ID))
- return (-1);
+ if ((id != C168_ASIC_ID) &&
+ (id != C104_ASIC_ID) &&
+ (id != C102_ASIC_ID) &&
+ (id != CI132_ASIC_ID) &&
+ (id != CI134_ASIC_ID) &&
+ (id != CI104J_ASIC_ID))
+ return -1;
for (i = 0, j = 0; i < 4; i++) {
n = inb(port + 2);
if (n == 'M') {
@@ -3112,7 +3216,7 @@ static int mxser_program_mode(int port)
}
if (j != 2)
id = -2;
- return (id);
+ return id;
}
static void mxser_normal_mode(int port)
@@ -3130,7 +3234,7 @@ static void mxser_normal_mode(int port)
if ((n & 0x61) == 0x60)
break;
if ((n & 1) == 1)
- (void) inb(port);
+ (void)inb(port);
}
outb(0x00, port + 4);
}
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 9f54733f162..337a87f86a3 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -81,7 +81,6 @@
#define HDLC_MAGIC 0x239e
#define HDLC_VERSION "$Revision: 4.8 $"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index c48de09d68f..203dc2b661d 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -951,7 +951,8 @@ static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
{
queue_the_message:
- pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
+ pMsg = kmalloc(sizeof(struct r3964_message),
+ error_code?GFP_ATOMIC:GFP_KERNEL);
TRACE_M("add_msg - kmalloc %p",pMsg);
if(pMsg==NULL) {
return;
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index b9371d5bf79..603b9ade5eb 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -1132,7 +1132,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)
* buffer, and once to drain the space from the (physical) beginning of
* the buffer to head pointer.
*
- * Called under the tty->atomic_read_lock sem and with TTY_DONT_FLIP set
+ * Called under the tty->atomic_read_lock sem
*
*/
@@ -1271,7 +1271,6 @@ do_it_again:
}
add_wait_queue(&tty->read_wait, &wait);
- set_bit(TTY_DONT_FLIP, &tty->flags);
while (nr) {
/* First test for status change. */
if (tty->packet && tty->link->ctrl_status) {
@@ -1315,9 +1314,7 @@ do_it_again:
break;
}
n_tty_set_room(tty);
- clear_bit(TTY_DONT_FLIP, &tty->flags);
timeout = schedule_timeout(timeout);
- set_bit(TTY_DONT_FLIP, &tty->flags);
continue;
}
__set_current_state(TASK_RUNNING);
@@ -1394,7 +1391,6 @@ do_it_again:
if (time)
timeout = time;
}
- clear_bit(TTY_DONT_FLIP, &tty->flags);
mutex_unlock(&tty->atomic_read_lock);
remove_wait_queue(&tty->read_wait, &wait);
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
new file mode 100644
index 00000000000..7719bd75810
--- /dev/null
+++ b/drivers/char/nsc_gpio.c
@@ -0,0 +1,140 @@
+/* linux/drivers/char/nsc_gpio.c
+
+ National Semiconductor common GPIO device-file/VFS methods.
+ Allows a user space process to control the GPIO pins.
+
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
+ Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
+*/
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/nsc_gpio.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define NAME "nsc_gpio"
+
+void nsc_gpio_dump(struct nsc_gpio_ops *amp, unsigned index)
+{
+ /* retrieve current config w/o changing it */
+ u32 config = amp->gpio_config(index, ~0, 0);
+
+ /* user requested via 'v' command, so its INFO */
+ dev_info(amp->dev, "io%02u: 0x%04x %s %s %s %s %s %s %s\tio:%d/%d\n",
+ index, config,
+ (config & 1) ? "OE" : "TS", /* output-enabled/tristate */
+ (config & 2) ? "PP" : "OD", /* push pull / open drain */
+ (config & 4) ? "PUE" : "PUD", /* pull up enabled/disabled */
+ (config & 8) ? "LOCKED" : "", /* locked / unlocked */
+ (config & 16) ? "LEVEL" : "EDGE",/* level/edge input */
+ (config & 32) ? "HI" : "LO", /* trigger on rise/fall edge */
+ (config & 64) ? "DEBOUNCE" : "", /* debounce */
+
+ amp->gpio_get(index), amp->gpio_current(index));
+}
+
+ssize_t nsc_gpio_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ unsigned m = iminor(file->f_dentry->d_inode);
+ struct nsc_gpio_ops *amp = file->private_data;
+ struct device *dev = amp->dev;
+ size_t i;
+ int err = 0;
+
+ for (i = 0; i < len; ++i) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ switch (c) {
+ case '0':
+ amp->gpio_set(m, 0);
+ break;
+ case '1':
+ amp->gpio_set(m, 1);
+ break;
+ case 'O':
+ dev_dbg(dev, "GPIO%d output enabled\n", m);
+ amp->gpio_config(m, ~1, 1);
+ break;
+ case 'o':
+ dev_dbg(dev, "GPIO%d output disabled\n", m);
+ amp->gpio_config(m, ~1, 0);
+ break;
+ case 'T':
+ dev_dbg(dev, "GPIO%d output is push pull\n", m);
+ amp->gpio_config(m, ~2, 2);
+ break;
+ case 't':
+ dev_dbg(dev, "GPIO%d output is open drain\n", m);
+ amp->gpio_config(m, ~2, 0);
+ break;
+ case 'P':
+ dev_dbg(dev, "GPIO%d pull up enabled\n", m);
+ amp->gpio_config(m, ~4, 4);
+ break;
+ case 'p':
+ dev_dbg(dev, "GPIO%d pull up disabled\n", m);
+ amp->gpio_config(m, ~4, 0);
+ break;
+ case 'v':
+ /* View Current pin settings */
+ amp->gpio_dump(amp, m);
+ break;
+ case '\n':
+ /* end of settings string, do nothing */
+ break;
+ default:
+ dev_err(dev, "io%2d bad setting: chr<0x%2x>\n",
+ m, (int)c);
+ err++;
+ }
+ }
+ if (err)
+ return -EINVAL; /* full string handled, report error */
+
+ return len;
+}
+
+ssize_t nsc_gpio_read(struct file *file, char __user * buf,
+ size_t len, loff_t * ppos)
+{
+ unsigned m = iminor(file->f_dentry->d_inode);
+ int value;
+ struct nsc_gpio_ops *amp = file->private_data;
+
+ value = amp->gpio_get(m);
+ if (put_user(value ? '1' : '0', buf))
+ return -EFAULT;
+
+ return 1;
+}
+
+/* common file-ops routines for both scx200_gpio and pc87360_gpio */
+EXPORT_SYMBOL(nsc_gpio_write);
+EXPORT_SYMBOL(nsc_gpio_read);
+EXPORT_SYMBOL(nsc_gpio_dump);
+
+static int __init nsc_gpio_init(void)
+{
+ printk(KERN_DEBUG NAME " initializing\n");
+ return 0;
+}
+
+static void __exit nsc_gpio_cleanup(void)
+{
+ printk(KERN_DEBUG NAME " cleanup\n");
+}
+
+module_init(nsc_gpio_init);
+module_exit(nsc_gpio_cleanup);
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("NatSemi GPIO Common Methods");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 3556ccd7757..a39f19c35a6 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -37,7 +37,6 @@
#define NVRAM_VERSION "1.2"
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/nvram.h>
@@ -438,7 +437,7 @@ nvram_read_proc(char *buffer, char **start, off_t offset,
#endif /* CONFIG_PROC_FS */
-static struct file_operations nvram_fops = {
+static const struct file_operations nvram_fops = {
.owner = THIS_MODULE,
.llseek = nvram_llseek,
.read = nvram_read,
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
index 4083b781adb..7c57ebfa864 100644
--- a/drivers/char/nwbutton.c
+++ b/drivers/char/nwbutton.c
@@ -4,7 +4,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -184,7 +183,7 @@ static int button_read (struct file *filp, char __user *buffer,
* attempts to perform these operations on the device.
*/
-static struct file_operations button_fops = {
+static const struct file_operations button_fops = {
.owner = THIS_MODULE,
.read = button_read,
};
@@ -224,7 +223,7 @@ static int __init nwbutton_init(void)
return -EBUSY;
}
- if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, SA_INTERRUPT,
+ if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, IRQF_DISABLED,
"nwbutton", NULL)) {
printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n",
IRQ_NETWINDER_BUTTON);
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index 8865387d344..206cf6f5069 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -642,7 +642,7 @@ static void kick_open(void)
udelay(25);
}
-static struct file_operations flash_fops =
+static const struct file_operations flash_fops =
{
.owner = THIS_MODULE,
.llseek = flash_llseek,
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
new file mode 100644
index 00000000000..ecfaf180e5b
--- /dev/null
+++ b/drivers/char/pc8736x_gpio.c
@@ -0,0 +1,347 @@
+/* linux/drivers/char/pc8736x_gpio.c
+
+ National Semiconductor PC8736x GPIO driver. Allows a user space
+ process to play with the GPIO pins.
+
+ Copyright (c) 2005,2006 Jim Cromie <jim.cromie@gmail.com>
+
+ adapted from linux/drivers/char/scx200_gpio.c
+ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>,
+*/
+
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/cdev.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/mutex.h>
+#include <linux/nsc_gpio.h>
+#include <linux/platform_device.h>
+#include <asm/uaccess.h>
+
+#define DEVNAME "pc8736x_gpio"
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("NatSemi/Winbond PC-8736x GPIO Pin Driver");
+MODULE_LICENSE("GPL");
+
+static int major; /* default to dynamic major */
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "Major device number");
+
+static DEFINE_MUTEX(pc8736x_gpio_config_lock);
+static unsigned pc8736x_gpio_base;
+static u8 pc8736x_gpio_shadow[4];
+
+#define SIO_BASE1 0x2E /* 1st command-reg to check */
+#define SIO_BASE2 0x4E /* alt command-reg to check */
+
+#define SIO_SID 0x20 /* SuperI/O ID Register */
+#define SIO_SID_VALUE 0xe9 /* Expected value in SuperI/O ID Register */
+
+#define SIO_CF1 0x21 /* chip config, bit0 is chip enable */
+
+#define PC8736X_GPIO_RANGE 16 /* ioaddr range */
+#define PC8736X_GPIO_CT 32 /* minors matching 4 8 bit ports */
+
+#define SIO_UNIT_SEL 0x7 /* unit select reg */
+#define SIO_UNIT_ACT 0x30 /* unit enable */
+#define SIO_GPIO_UNIT 0x7 /* unit number of GPIO */
+#define SIO_VLM_UNIT 0x0D
+#define SIO_TMS_UNIT 0x0E
+
+/* config-space addrs to read/write each unit's runtime addr */
+#define SIO_BASE_HADDR 0x60
+#define SIO_BASE_LADDR 0x61
+
+/* GPIO config-space pin-control addresses */
+#define SIO_GPIO_PIN_SELECT 0xF0
+#define SIO_GPIO_PIN_CONFIG 0xF1
+#define SIO_GPIO_PIN_EVENT 0xF2
+
+static unsigned char superio_cmd = 0;
+static unsigned char selected_device = 0xFF; /* bogus start val */
+
+/* GPIO port runtime access, functionality */
+static int port_offset[] = { 0, 4, 8, 10 }; /* non-uniform offsets ! */
+/* static int event_capable[] = { 1, 1, 0, 0 }; ports 2,3 are hobbled */
+
+#define PORT_OUT 0
+#define PORT_IN 1
+#define PORT_EVT_EN 2
+#define PORT_EVT_STST 3
+
+static struct platform_device *pdev; /* use in dev_*() */
+
+static inline void superio_outb(int addr, int val)
+{
+ outb_p(addr, superio_cmd);
+ outb_p(val, superio_cmd + 1);
+}
+
+static inline int superio_inb(int addr)
+{
+ outb_p(addr, superio_cmd);
+ return inb_p(superio_cmd + 1);
+}
+
+static int pc8736x_superio_present(void)
+{
+ /* try the 2 possible values, read a hardware reg to verify */
+ superio_cmd = SIO_BASE1;
+ if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+ return superio_cmd;
+
+ superio_cmd = SIO_BASE2;
+ if (superio_inb(SIO_SID) == SIO_SID_VALUE)
+ return superio_cmd;
+
+ return 0;
+}
+
+static void device_select(unsigned devldn)
+{
+ superio_outb(SIO_UNIT_SEL, devldn);
+ selected_device = devldn;
+}
+
+static void select_pin(unsigned iminor)
+{
+ /* select GPIO port/pin from device minor number */
+ device_select(SIO_GPIO_UNIT);
+ superio_outb(SIO_GPIO_PIN_SELECT,
+ ((iminor << 1) & 0xF0) | (iminor & 0x7));
+}
+
+static inline u32 pc8736x_gpio_configure_fn(unsigned index, u32 mask, u32 bits,
+ u32 func_slct)
+{
+ u32 config, new_config;
+
+ mutex_lock(&pc8736x_gpio_config_lock);
+
+ device_select(SIO_GPIO_UNIT);
+ select_pin(index);
+
+ /* read current config value */
+ config = superio_inb(func_slct);
+
+ /* set new config */
+ new_config = (config & mask) | bits;
+ superio_outb(func_slct, new_config);
+
+ mutex_unlock(&pc8736x_gpio_config_lock);
+
+ return config;
+}
+
+static u32 pc8736x_gpio_configure(unsigned index, u32 mask, u32 bits)
+{
+ return pc8736x_gpio_configure_fn(index, mask, bits,
+ SIO_GPIO_PIN_CONFIG);
+}
+
+static int pc8736x_gpio_get(unsigned minor)
+{
+ int port, bit, val;
+
+ port = minor >> 3;
+ bit = minor & 7;
+ val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN);
+ val >>= bit;
+ val &= 1;
+
+ dev_dbg(&pdev->dev, "_gpio_get(%d from %x bit %d) == val %d\n",
+ minor, pc8736x_gpio_base + port_offset[port] + PORT_IN, bit,
+ val);
+
+ return val;
+}
+
+static void pc8736x_gpio_set(unsigned minor, int val)
+{
+ int port, bit, curval;
+
+ minor &= 0x1f;
+ port = minor >> 3;
+ bit = minor & 7;
+ curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+
+ dev_dbg(&pdev->dev, "addr:%x cur:%x bit-pos:%d cur-bit:%x + new:%d -> bit-new:%d\n",
+ pc8736x_gpio_base + port_offset[port] + PORT_OUT,
+ curval, bit, (curval & ~(1 << bit)), val, (val << bit));
+
+ val = (curval & ~(1 << bit)) | (val << bit);
+
+ dev_dbg(&pdev->dev, "gpio_set(minor:%d port:%d bit:%d)"
+ " %2x -> %2x\n", minor, port, bit, curval, val);
+
+ outb_p(val, pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+
+ curval = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_OUT);
+ val = inb_p(pc8736x_gpio_base + port_offset[port] + PORT_IN);
+
+ dev_dbg(&pdev->dev, "wrote %x, read: %x\n", curval, val);
+ pc8736x_gpio_shadow[port] = val;
+}
+
+static int pc8736x_gpio_current(unsigned minor)
+{
+ int port, bit;
+ minor &= 0x1f;
+ port = minor >> 3;
+ bit = minor & 7;
+ return ((pc8736x_gpio_shadow[port] >> bit) & 0x01);
+}
+
+static void pc8736x_gpio_change(unsigned index)
+{
+ pc8736x_gpio_set(index, !pc8736x_gpio_current(index));
+}
+
+static struct nsc_gpio_ops pc8736x_gpio_ops = {
+ .owner = THIS_MODULE,
+ .gpio_config = pc8736x_gpio_configure,
+ .gpio_dump = nsc_gpio_dump,
+ .gpio_get = pc8736x_gpio_get,
+ .gpio_set = pc8736x_gpio_set,
+ .gpio_change = pc8736x_gpio_change,
+ .gpio_current = pc8736x_gpio_current
+};
+
+static int pc8736x_gpio_open(struct inode *inode, struct file *file)
+{
+ unsigned m = iminor(inode);
+ file->private_data = &pc8736x_gpio_ops;
+
+ dev_dbg(&pdev->dev, "open %d\n", m);
+
+ if (m >= PC8736X_GPIO_CT)
+ return -EINVAL;
+ return nonseekable_open(inode, file);
+}
+
+static const struct file_operations pc8736x_gpio_fileops = {
+ .owner = THIS_MODULE,
+ .open = pc8736x_gpio_open,
+ .write = nsc_gpio_write,
+ .read = nsc_gpio_read,
+};
+
+static void __init pc8736x_init_shadow(void)
+{
+ int port;
+
+ /* read the current values driven on the GPIO signals */
+ for (port = 0; port < 4; ++port)
+ pc8736x_gpio_shadow[port]
+ = inb_p(pc8736x_gpio_base + port_offset[port]
+ + PORT_OUT);
+
+}
+
+static struct cdev pc8736x_gpio_cdev;
+
+static int __init pc8736x_gpio_init(void)
+{
+ int rc;
+ dev_t devid;
+
+ pdev = platform_device_alloc(DEVNAME, 0);
+ if (!pdev)
+ return -ENOMEM;
+
+ rc = platform_device_add(pdev);
+ if (rc) {
+ rc = -ENODEV;
+ goto undo_platform_dev_alloc;
+ }
+ dev_info(&pdev->dev, "NatSemi pc8736x GPIO Driver Initializing\n");
+
+ if (!pc8736x_superio_present()) {
+ rc = -ENODEV;
+ dev_err(&pdev->dev, "no device found\n");
+ goto undo_platform_dev_add;
+ }
+ pc8736x_gpio_ops.dev = &pdev->dev;
+
+ /* Verify that chip and it's GPIO unit are both enabled.
+ My BIOS does this, so I take minimum action here
+ */
+ rc = superio_inb(SIO_CF1);
+ if (!(rc & 0x01)) {
+ rc = -ENODEV;
+ dev_err(&pdev->dev, "device not enabled\n");
+ goto undo_platform_dev_add;
+ }
+ device_select(SIO_GPIO_UNIT);
+ if (!superio_inb(SIO_UNIT_ACT)) {
+ rc = -ENODEV;
+ dev_err(&pdev->dev, "GPIO unit not enabled\n");
+ goto undo_platform_dev_add;
+ }
+
+ /* read the GPIO unit base addr that chip responds to */
+ pc8736x_gpio_base = (superio_inb(SIO_BASE_HADDR) << 8
+ | superio_inb(SIO_BASE_LADDR));
+
+ if (!request_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE, DEVNAME)) {
+ rc = -ENODEV;
+ dev_err(&pdev->dev, "GPIO ioport %x busy\n",
+ pc8736x_gpio_base);
+ goto undo_platform_dev_add;
+ }
+ dev_info(&pdev->dev, "GPIO ioport %x reserved\n", pc8736x_gpio_base);
+
+ if (major) {
+ devid = MKDEV(major, 0);
+ rc = register_chrdev_region(devid, PC8736X_GPIO_CT, DEVNAME);
+ } else {
+ rc = alloc_chrdev_region(&devid, 0, PC8736X_GPIO_CT, DEVNAME);
+ major = MAJOR(devid);
+ }
+
+ if (rc < 0) {
+ dev_err(&pdev->dev, "register-chrdev failed: %d\n", rc);
+ goto undo_request_region;
+ }
+ if (!major) {
+ major = rc;
+ dev_dbg(&pdev->dev, "got dynamic major %d\n", major);
+ }
+
+ pc8736x_init_shadow();
+
+ /* ignore minor errs, and succeed */
+ cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops);
+ cdev_add(&pc8736x_gpio_cdev, devid, PC8736X_GPIO_CT);
+
+ return 0;
+
+undo_request_region:
+ release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE);
+undo_platform_dev_add:
+ platform_device_del(pdev);
+undo_platform_dev_alloc:
+ platform_device_put(pdev);
+
+ return rc;
+}
+
+static void __exit pc8736x_gpio_cleanup(void)
+{
+ dev_dbg(&pdev->dev, "cleanup\n");
+
+ cdev_del(&pc8736x_gpio_cdev);
+ unregister_chrdev_region(MKDEV(major,0), PC8736X_GPIO_CT);
+ release_region(pc8736x_gpio_base, PC8736X_GPIO_RANGE);
+
+ platform_device_del(pdev);
+ platform_device_put(pdev);
+}
+
+module_init(pc8736x_gpio_init);
+module_exit(pc8736x_gpio_cleanup);
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index eab5394da66..50d20aafeb1 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -149,12 +149,7 @@ struct cm4000_dev {
#define ZERO_DEV(dev) \
memset(&dev->atr_csum,0, \
sizeof(struct cm4000_dev) - \
- /*link*/ sizeof(struct pcmcia_device *) - \
- /*node*/ sizeof(dev_node_t) - \
- /*atr*/ MAX_ATR*sizeof(char) - \
- /*rbuf*/ 512*sizeof(char) - \
- /*sbuf*/ 512*sizeof(char) - \
- /*queue*/ 4*sizeof(wait_queue_head_t))
+ offsetof(struct cm4000_dev, atr_csum))
static struct pcmcia_device *dev_table[CM4000_MAX_DEV];
static struct class *cmm_class;
@@ -1943,7 +1938,7 @@ static void cm4000_detach(struct pcmcia_device *link)
return;
}
-static struct file_operations cm4000_fops = {
+static const struct file_operations cm4000_fops = {
.owner = THIS_MODULE,
.read = cmm_read,
.write = cmm_write,
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 47a8465bf95..55cf4be4297 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -688,7 +688,7 @@ static void reader_detach(struct pcmcia_device *link)
return;
}
-static struct file_operations reader_fops = {
+static const struct file_operations reader_fops = {
.owner = THIS_MODULE,
.read = cm4040_read,
.write = cm4040_write,
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 0c141c295fb..00f574cbb0d 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -1174,8 +1174,12 @@ static void dcd_change(MGSLPC_INFO *info)
else
info->input_signal_events.dcd_down++;
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, info->netdev);
+ if (info->netcount) {
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
@@ -1582,7 +1586,7 @@ static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
return;
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
return;
spin_lock_irqsave(&info->lock,flags);
@@ -1649,7 +1653,7 @@ static int mgslpc_write(struct tty_struct * tty,
__FILE__,__LINE__,info->device_name,count);
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_write") ||
- !tty || !info->tx_buf)
+ !info->tx_buf)
goto cleanup;
if (info->params.mode == MGSL_MODE_HDLC) {
@@ -4251,8 +4255,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->lock, flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index bee6c47b45b..520d2cf82bc 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -60,7 +60,6 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/ioctl.h>
#include <linux/parport.h>
#include <linux/ctype.h>
@@ -740,7 +739,7 @@ static unsigned int pp_poll (struct file * file, poll_table * wait)
static struct class *ppdev_class;
-static struct file_operations pp_fops = {
+static const struct file_operations pp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = pp_read,
@@ -770,7 +769,7 @@ static struct parport_driver pp_driver = {
static int __init ppdev_init (void)
{
- int i, err = 0;
+ int err = 0;
if (register_chrdev (PP_MAJOR, CHRDEV, &pp_fops)) {
printk (KERN_WARNING CHRDEV ": unable to get major %d\n",
@@ -782,11 +781,6 @@ static int __init ppdev_init (void)
err = PTR_ERR(ppdev_class);
goto out_chrdev;
}
- devfs_mk_dir("parports");
- for (i = 0; i < PARPORT_MAX; i++) {
- devfs_mk_cdev(MKDEV(PP_MAJOR, i),
- S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i);
- }
if (parport_register_driver(&pp_driver)) {
printk (KERN_WARNING CHRDEV ": unable to register with parport\n");
goto out_class;
@@ -796,9 +790,6 @@ static int __init ppdev_init (void)
goto out;
out_class:
- for (i = 0; i < PARPORT_MAX; i++)
- devfs_remove("parports/%d", i);
- devfs_remove("parports");
class_destroy(ppdev_class);
out_chrdev:
unregister_chrdev(PP_MAJOR, CHRDEV);
@@ -808,12 +799,8 @@ out:
static void __exit ppdev_cleanup (void)
{
- int i;
/* Clean up all parport stuff */
- for (i = 0; i < PARPORT_MAX; i++)
- devfs_remove("parports/%d", i);
parport_unregister_driver(&pp_driver);
- devfs_remove("parports");
class_destroy(ppdev_class);
unregister_chrdev (PP_MAJOR, CHRDEV);
}
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 9b5a2c0e700..34dd4c38110 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h> /* For EXPORT_SYMBOL */
#include <linux/errno.h>
@@ -24,7 +23,6 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/sysctl.h>
#include <asm/uaccess.h>
@@ -101,7 +99,7 @@ static void pty_unthrottle(struct tty_struct * tty)
*
* FIXME: Our pty_write method is called with our ldisc lock held but
* not our partners. We can't just take the other one blindly without
- * risking deadlocks. There is also the small matter of TTY_DONT_FLIP
+ * risking deadlocks.
*/
static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count)
{
@@ -265,7 +263,6 @@ static void __init legacy_pty_init(void)
pty_driver->owner = THIS_MODULE;
pty_driver->driver_name = "pty_master";
pty_driver->name = "pty";
- pty_driver->devfs_name = "pty/m";
pty_driver->major = PTY_MASTER_MAJOR;
pty_driver->minor_start = 0;
pty_driver->type = TTY_DRIVER_TYPE_PTY;
@@ -283,7 +280,6 @@ static void __init legacy_pty_init(void)
pty_slave_driver->owner = THIS_MODULE;
pty_slave_driver->driver_name = "pty_slave";
pty_slave_driver->name = "ttyp";
- pty_slave_driver->devfs_name = "pty/s";
pty_slave_driver->major = PTY_SLAVE_MAJOR;
pty_slave_driver->minor_start = 0;
pty_slave_driver->type = TTY_DRIVER_TYPE_PTY;
@@ -351,7 +347,6 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
static void __init unix98_pty_init(void)
{
- devfs_mk_dir("pts");
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
if (!ptm_driver)
panic("Couldn't allocate Unix98 ptm driver");
@@ -372,7 +367,7 @@ static void __init unix98_pty_init(void)
ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
ptm_driver->init_termios.c_lflag = 0;
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
+ TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
tty_set_operations(ptm_driver, &pty_ops);
ptm_driver->ioctl = pty_unix98_ioctl;
@@ -387,7 +382,7 @@ static void __init unix98_pty_init(void)
pts_driver->init_termios = tty_std_termios;
pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
- TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM;
+ TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
pts_driver->other = ptm_driver;
tty_set_operations(pts_driver, &pty_ops);
diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c
index 601d09baf9d..9d134e98d2a 100644
--- a/drivers/char/qtronix.c
+++ b/drivers/char/qtronix.c
@@ -33,7 +33,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
/*
* NOTE:
@@ -145,7 +144,7 @@ void __init init_qtronix_990P_kbd(void)
cir_port_init(cir);
retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler,
- (unsigned long )(SA_INTERRUPT|SA_SHIRQ),
+ (unsigned long )(IRQF_DISABLED|IRQF_SHARED),
(const char *)"Qtronix IR Keyboard", (void *)cir);
if (retval) {
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 58f3512c52e..4c3a5ca9d8f 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -224,7 +224,6 @@
*/
#include <linux/utsname.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/major.h>
@@ -417,7 +416,7 @@ static struct entropy_store input_pool = {
.poolinfo = &poolinfo_table[0],
.name = "input",
.limit = 1,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(&input_pool.lock),
.pool = input_pool_data
};
@@ -426,7 +425,7 @@ static struct entropy_store blocking_pool = {
.name = "blocking",
.limit = 1,
.pull = &input_pool,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(&blocking_pool.lock),
.pool = blocking_pool_data
};
@@ -434,7 +433,7 @@ static struct entropy_store nonblocking_pool = {
.poolinfo = &poolinfo_table[1],
.name = "nonblocking",
.pull = &input_pool,
- .lock = SPIN_LOCK_UNLOCKED,
+ .lock = __SPIN_LOCK_UNLOCKED(&nonblocking_pool.lock),
.pool = nonblocking_pool_data
};
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 15a7b408652..c596a08c07b 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/module.h>
@@ -31,7 +30,7 @@ struct raw_device_data {
static struct class *raw_class;
static struct raw_device_data raw_devices[MAX_RAW_MINORS];
static DEFINE_MUTEX(raw_mutex);
-static struct file_operations raw_ctl_fops; /* forward declaration */
+static const struct file_operations raw_ctl_fops; /* forward declaration */
/*
* Open/close code for raw IO.
@@ -262,7 +261,7 @@ static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf,
}
-static struct file_operations raw_fops = {
+static const struct file_operations raw_fops = {
.read = generic_file_read,
.aio_read = generic_file_aio_read,
.write = raw_file_write,
@@ -275,7 +274,7 @@ static struct file_operations raw_fops = {
.owner = THIS_MODULE,
};
-static struct file_operations raw_ctl_fops = {
+static const struct file_operations raw_ctl_fops = {
.ioctl = raw_ctl_ioctl,
.open = raw_open,
.owner = THIS_MODULE,
@@ -288,50 +287,39 @@ static struct cdev raw_cdev = {
static int __init raw_init(void)
{
- int i;
dev_t dev = MKDEV(RAW_MAJOR, 0);
+ int ret;
- if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw"))
+ ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw");
+ if (ret)
goto error;
cdev_init(&raw_cdev, &raw_fops);
- if (cdev_add(&raw_cdev, dev, MAX_RAW_MINORS)) {
+ ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS);
+ if (ret) {
kobject_put(&raw_cdev.kobj);
- unregister_chrdev_region(dev, MAX_RAW_MINORS);
- goto error;
+ goto error_region;
}
raw_class = class_create(THIS_MODULE, "raw");
if (IS_ERR(raw_class)) {
printk(KERN_ERR "Error creating raw class.\n");
cdev_del(&raw_cdev);
- unregister_chrdev_region(dev, MAX_RAW_MINORS);
- goto error;
+ ret = PTR_ERR(raw_class);
+ goto error_region;
}
class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
- devfs_mk_cdev(MKDEV(RAW_MAJOR, 0),
- S_IFCHR | S_IRUGO | S_IWUGO,
- "raw/rawctl");
- for (i = 1; i < MAX_RAW_MINORS; i++)
- devfs_mk_cdev(MKDEV(RAW_MAJOR, i),
- S_IFCHR | S_IRUGO | S_IWUGO,
- "raw/raw%d", i);
return 0;
+error_region:
+ unregister_chrdev_region(dev, MAX_RAW_MINORS);
error:
- printk(KERN_ERR "error register raw device\n");
- return 1;
+ return ret;
}
static void __exit raw_exit(void)
{
- int i;
-
- for (i = 1; i < MAX_RAW_MINORS; i++)
- devfs_remove("raw/raw%d", i);
- devfs_remove("raw/rawctl");
- devfs_remove("raw");
class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0));
class_destroy(raw_class);
cdev_del(&raw_cdev);
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index aa43436d5d1..3fa80aaf452 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -33,7 +33,6 @@
* */
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
#include <linux/kernel.h>
@@ -244,7 +243,7 @@ static struct real_driver rio_real_driver = {
*
*/
-static struct file_operations rio_fw_fops = {
+static const struct file_operations rio_fw_fops = {
.owner = THIS_MODULE,
.ioctl = rio_fw_ioctl,
};
@@ -1120,7 +1119,7 @@ static int __init rio_init(void)
for (i = 0; i < p->RIONumHosts; i++) {
hp = &p->RIOHosts[i];
if (hp->Ivec) {
- int mode = SA_SHIRQ;
+ int mode = IRQF_SHARED;
if (hp->Ivec & 0x8000) {
mode = 0;
hp->Ivec &= 0x7fff;
diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h
index 55b9c97e847..dc3f005614a 100644
--- a/drivers/char/rio/rio_linux.h
+++ b/drivers/char/rio/rio_linux.h
@@ -23,7 +23,6 @@
* Version 1.0 -- July, 1999.
*
*/
-#include <linux/config.h>
#define RIO_NBOARDS 4
#define RIO_PORTSPERBOARD 128
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c
index 12e34bc3f7c..99f3df02b61 100644
--- a/drivers/char/rio/rioinit.c
+++ b/drivers/char/rio/rioinit.c
@@ -33,7 +33,6 @@
static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3";
#endif
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index eec1fea0cb9..0bd09040a5c 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -546,7 +546,7 @@ static void RIOReceive(struct rio_info *p, struct Port *PortP)
** run out of space it will be set to the offset of the
** next byte to copy from the packet data area. The packet
** length field is decremented by the number of bytes that
- ** we succesfully removed from the packet. When this reaches
+ ** we successfully removed from the packet. When this reaches
** zero, we reset the offset pointer to be zero, and free
** the packet from the front of the queue.
*/
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 657c0d88f48..f1c94f771af 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -625,7 +625,7 @@ static inline int rc_setup_board(struct riscom_board * bp)
if (bp->flags & RC_BOARD_ACTIVE)
return 0;
- error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT,
+ error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
"RISCom/8", NULL);
if (error)
return error;
@@ -1634,7 +1634,6 @@ static inline int rc_init_drivers(void)
memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
- riscom_driver->devfs_name = "tts/L";
riscom_driver->major = RISCOM8_NORMAL_MAJOR;
riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;
riscom_driver->subtype = SERIAL_TYPE_NORMAL;
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 7edc6a4dbdc..0ac13188132 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -324,35 +324,15 @@ static void rp_do_receive(struct r_port *info,
CHANNEL_t * cp, unsigned int ChanStatus)
{
unsigned int CharNStat;
- int ToRecv, wRecv, space = 0, count;
- unsigned char *cbuf, *chead;
- char *fbuf, *fhead;
- struct tty_ldisc *ld;
-
- ld = tty_ldisc_ref(tty);
+ int ToRecv, wRecv, space;
+ unsigned char *cbuf;
ToRecv = sGetRxCnt(cp);
- space = tty->receive_room;
- if (space > 2 * TTY_FLIPBUF_SIZE)
- space = 2 * TTY_FLIPBUF_SIZE;
- count = 0;
#ifdef ROCKET_DEBUG_INTR
- printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space);
+ printk(KERN_INFO "rp_do_receive(%d)...", ToRecv);
#endif
-
- /*
- * determine how many we can actually read in. If we can't
- * read any in then we have a software overrun condition.
- */
- if (ToRecv > space)
- ToRecv = space;
-
- ToRecv = tty_prepare_flip_string_flags(tty, &chead, &fhead, ToRecv);
- if (ToRecv <= 0)
- goto done;
-
- cbuf = chead;
- fbuf = fhead;
+ if (ToRecv == 0)
+ return;
/*
* if status indicates there are errored characters in the
@@ -380,6 +360,8 @@ static void rp_do_receive(struct r_port *info,
info->read_status_mask);
#endif
while (ToRecv) {
+ char flag;
+
CharNStat = sInW(sGetTxRxDataIO(cp));
#ifdef ROCKET_DEBUG_RECEIVE
printk(KERN_INFO "%x...", CharNStat);
@@ -392,17 +374,16 @@ static void rp_do_receive(struct r_port *info,
}
CharNStat &= info->read_status_mask;
if (CharNStat & STMBREAKH)
- *fbuf++ = TTY_BREAK;
+ flag = TTY_BREAK;
else if (CharNStat & STMPARITYH)
- *fbuf++ = TTY_PARITY;
+ flag = TTY_PARITY;
else if (CharNStat & STMFRAMEH)
- *fbuf++ = TTY_FRAME;
+ flag = TTY_FRAME;
else if (CharNStat & STMRCVROVRH)
- *fbuf++ = TTY_OVERRUN;
+ flag = TTY_OVERRUN;
else
- *fbuf++ = TTY_NORMAL;
- *cbuf++ = CharNStat & 0xff;
- count++;
+ flag = TTY_NORMAL;
+ tty_insert_flip_char(tty, CharNStat & 0xff, flag);
ToRecv--;
}
@@ -422,20 +403,23 @@ static void rp_do_receive(struct r_port *info,
* characters at time by doing repeated word IO
* transfer.
*/
+ space = tty_prepare_flip_string(tty, &cbuf, ToRecv);
+ if (space < ToRecv) {
+#ifdef ROCKET_DEBUG_RECEIVE
+ printk(KERN_INFO "rp_do_receive:insufficient space ToRecv=%d space=%d\n", ToRecv, space);
+#endif
+ if (space <= 0)
+ return;
+ ToRecv = space;
+ }
wRecv = ToRecv >> 1;
if (wRecv)
sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv);
if (ToRecv & 1)
cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp));
- memset(fbuf, TTY_NORMAL, ToRecv);
- cbuf += ToRecv;
- fbuf += ToRecv;
- count += ToRecv;
}
/* Push the data up to the tty layer */
- ld->receive_buf(tty, chead, fhead, count);
-done:
- tty_ldisc_deref(ld);
+ tty_flip_buffer_push(tty);
}
/*
@@ -2442,8 +2426,7 @@ static int __init rp_init(void)
*/
rocket_driver->owner = THIS_MODULE;
- rocket_driver->flags = TTY_DRIVER_NO_DEVFS;
- rocket_driver->devfs_name = "tts/R";
+ rocket_driver->flags = TTY_DRIVER_DYNAMIC_DEV;
rocket_driver->name = "ttyR";
rocket_driver->driver_name = "Comtrol RocketPort";
rocket_driver->major = TTY_ROCKET_MAJOR;
@@ -2454,7 +2437,7 @@ static int __init rp_init(void)
rocket_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
#ifdef ROCKET_SOFT_FLOW
- rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ rocket_driver->flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
#endif
tty_set_operations(rocket_driver, &rocket_ops);
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index f6686fcce80..656f8c0ca52 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -46,13 +46,12 @@
* 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
* 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
* CONFIG_HPET_EMULATE_RTC
+ * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly.
* 1.12ac Alan Cox: Allow read access to the day of week register
*/
#define RTC_VERSION "1.12ac"
-#define RTC_IO_EXTENT 0x8
-
/*
* Note that *all* calls to CMOS_READ and CMOS_WRITE are done with
* interrupts disabled. Due to the index-port/data-port (0x70/0x71)
@@ -61,7 +60,6 @@
* this driver.)
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -211,17 +209,18 @@ static const unsigned char days_in_mo[] =
*/
static inline unsigned char rtc_is_updating(void)
{
+ unsigned long flags;
unsigned char uip;
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
return uip;
}
#ifdef RTC_IRQ
/*
- * A very tiny interrupt handler. It runs with SA_INTERRUPT set,
+ * A very tiny interrupt handler. It runs with IRQF_DISABLED set,
* but there is possibility of conflicting with the set_rtc_mmss()
* call (the rtc irq and the timer irq can easily run at the same
* time in two different CPUs). So we need to serialize
@@ -338,7 +337,15 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
if (rtc_has_irq == 0)
return -EIO;
- if (count < sizeof(unsigned))
+ /*
+ * Historically this function used to assume that sizeof(unsigned long)
+ * is the same in userspace and kernelspace. This lead to problems
+ * for configurations with multiple ABIs such a the MIPS o32 and 64
+ * ABIs supported on the same kernel. So now we support read of both
+ * 4 and 8 bytes and assume that's the sizeof(unsigned long) in the
+ * userspace ABI.
+ */
+ if (count != sizeof(unsigned int) && count != sizeof(unsigned long))
return -EINVAL;
add_wait_queue(&rtc_wait, &wait);
@@ -369,10 +376,12 @@ static ssize_t rtc_read(struct file *file, char __user *buf,
schedule();
} while (1);
- if (count < sizeof(unsigned long))
- retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
+ if (count == sizeof(unsigned int))
+ retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int);
else
retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long);
+ if (!retval)
+ retval = count;
out:
current->state = TASK_RUNNING;
remove_wait_queue(&rtc_wait, &wait);
@@ -878,7 +887,7 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg)
* The various file operations we support.
*/
-static struct file_operations rtc_fops = {
+static const struct file_operations rtc_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_read,
@@ -897,7 +906,7 @@ static struct miscdevice rtc_dev = {
.fops = &rtc_fops,
};
-static struct file_operations rtc_proc_fops = {
+static const struct file_operations rtc_proc_fops = {
.owner = THIS_MODULE,
.open = rtc_proc_open,
.read = seq_read,
@@ -924,11 +933,14 @@ static int __init rtc_init(void)
struct sparc_isa_device *isa_dev;
#endif
#endif
+#ifndef __sparc__
+ void *r;
+#endif
#ifdef __sparc__
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if(strcmp(edev->prom_name, "rtc") == 0) {
+ if(strcmp(edev->prom_node->name, "rtc") == 0) {
rtc_port = edev->resource[0].start;
rtc_irq = edev->irqs[0];
goto found;
@@ -938,7 +950,7 @@ static int __init rtc_init(void)
#ifdef __sparc_v9__
for_each_isa(isa_br) {
for_each_isadev(isa_dev, isa_br) {
- if (strcmp(isa_dev->prom_name, "rtc") == 0) {
+ if (strcmp(isa_dev->prom_node->name, "rtc") == 0) {
rtc_port = isa_dev->resource.start;
rtc_irq = isa_dev->irq;
goto found;
@@ -959,14 +971,19 @@ found:
* XXX Interrupt pin #7 in Espresso is shared between RTC and
* PCI Slot 2 INTA# (and some INTx# in Slot 1).
*/
- if (request_irq(rtc_irq, rtc_interrupt, SA_SHIRQ, "rtc", (void *)&rtc_port)) {
+ if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) {
printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq);
return -EIO;
}
no_irq:
#else
- if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc")) {
- printk(KERN_ERR "rtc: I/O port %d is not free.\n", RTC_PORT (0));
+ if (RTC_IOMAPPED)
+ r = request_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ else
+ r = request_mem_region(RTC_PORT(0), RTC_IO_EXTENT, "rtc");
+ if (!r) {
+ printk(KERN_ERR "rtc: I/O resource %lx is not free.\n",
+ (long)(RTC_PORT(0)));
return -EIO;
}
@@ -977,10 +994,13 @@ no_irq:
rtc_int_handler_ptr = rtc_interrupt;
}
- if(request_irq(RTC_IRQ, rtc_int_handler_ptr, SA_INTERRUPT, "rtc", NULL)) {
+ if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) {
/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
- release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ else
+ release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
return -EIO;
}
hpet_rtc_timer_init();
@@ -1080,7 +1100,10 @@ static void __exit rtc_exit (void)
if (rtc_has_irq)
free_irq (rtc_irq, &rtc_port);
#else
- release_region (RTC_PORT (0), RTC_IO_EXTENT);
+ if (RTC_IOMAPPED)
+ release_region(RTC_PORT(0), RTC_IO_EXTENT);
+ else
+ release_mem_region(RTC_PORT(0), RTC_IO_EXTENT);
#ifdef RTC_IRQ
if (rtc_has_irq)
free_irq (RTC_IRQ, NULL);
@@ -1223,7 +1246,7 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
void rtc_get_rtc_time(struct rtc_time *rtc_tm)
{
- unsigned long uip_watchdog = jiffies;
+ unsigned long uip_watchdog = jiffies, flags;
unsigned char ctrl;
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
@@ -1239,10 +1262,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
* Once the read clears, read the RTC time (again via ioctl). Easy.
*/
- while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) {
- barrier();
+ while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100)
cpu_relax();
- }
/*
* Only the values that we read from the RTC are set. We leave
@@ -1250,7 +1271,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
* RTC has RTC_DAY_OF_WEEK, we should usually ignore it, as it is
* only updated by the RTC when initially set to a non-zero value.
*/
- spin_lock_irq(&rtc_lock);
+ spin_lock_irqsave(&rtc_lock, flags);
rtc_tm->tm_sec = CMOS_READ(RTC_SECONDS);
rtc_tm->tm_min = CMOS_READ(RTC_MINUTES);
rtc_tm->tm_hour = CMOS_READ(RTC_HOURS);
@@ -1264,7 +1285,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
real_year = CMOS_READ(RTC_DEC_YEAR);
#endif
ctrl = CMOS_READ(RTC_CONTROL);
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irqrestore(&rtc_lock, flags);
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
deleted file mode 100644
index b0038b19b50..00000000000
--- a/drivers/char/s3c2410-rtc.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* drivers/char/s3c2410_rtc.c
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- * http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 Internal RTC Driver
- *
- * Changelog:
- * 08-Nov-2004 BJD Initial creation
- * 12-Nov-2004 BJD Added periodic IRQ and PM code
- * 22-Nov-2004 BJD Sign-test on alarm code to check for <0
- * 10-Mar-2005 LCVR Changed S3C2410_VA_RTC to S3C24XX_VA_RTC
-*/
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/clk.h>
-
-#include <asm/hardware.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/rtc.h>
-
-#include <asm/mach/time.h>
-
-#include <asm/arch/regs-rtc.h>
-
-/* need this for the RTC_AF definitions */
-#include <linux/mc146818rtc.h>
-
-#undef S3C24XX_VA_RTC
-#define S3C24XX_VA_RTC s3c2410_rtc_base
-
-static struct resource *s3c2410_rtc_mem;
-
-static void __iomem *s3c2410_rtc_base;
-static int s3c2410_rtc_alarmno = NO_IRQ;
-static int s3c2410_rtc_tickno = NO_IRQ;
-static int s3c2410_rtc_freq = 1;
-
-static DEFINE_SPINLOCK(s3c2410_rtc_pie_lock);
-
-/* IRQ Handlers */
-
-static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
-{
- rtc_update(1, RTC_AF | RTC_IRQF);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r)
-{
- rtc_update(1, RTC_PF | RTC_IRQF);
- return IRQ_HANDLED;
-}
-
-/* Update control registers */
-static void s3c2410_rtc_setaie(int to)
-{
- unsigned int tmp;
-
- pr_debug("%s: aie=%d\n", __FUNCTION__, to);
-
- tmp = readb(S3C2410_RTCALM);
-
- if (to)
- tmp |= S3C2410_RTCALM_ALMEN;
- else
- tmp &= ~S3C2410_RTCALM_ALMEN;
-
-
- writeb(tmp, S3C2410_RTCALM);
-}
-
-static void s3c2410_rtc_setpie(int to)
-{
- unsigned int tmp;
-
- pr_debug("%s: pie=%d\n", __FUNCTION__, to);
-
- spin_lock_irq(&s3c2410_rtc_pie_lock);
- tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
-
- if (to)
- tmp |= S3C2410_TICNT_ENABLE;
-
- writeb(tmp, S3C2410_TICNT);
- spin_unlock_irq(&s3c2410_rtc_pie_lock);
-}
-
-static void s3c2410_rtc_setfreq(int freq)
-{
- unsigned int tmp;
-
- spin_lock_irq(&s3c2410_rtc_pie_lock);
- tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
-
- s3c2410_rtc_freq = freq;
-
- tmp |= (128 / freq)-1;
-
- writeb(tmp, S3C2410_TICNT);
- spin_unlock_irq(&s3c2410_rtc_pie_lock);
-}
-
-/* Time read/write */
-
-static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
-{
- unsigned int have_retried = 0;
-
- retry_get_time:
- rtc_tm->tm_min = readb(S3C2410_RTCMIN);
- rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
- rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
- rtc_tm->tm_mon = readb(S3C2410_RTCMON);
- rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
- rtc_tm->tm_sec = readb(S3C2410_RTCSEC);
-
- /* the only way to work out wether the system was mid-update
- * when we read it is to check the second counter, and if it
- * is zero, then we re-try the entire read
- */
-
- if (rtc_tm->tm_sec == 0 && !have_retried) {
- have_retried = 1;
- goto retry_get_time;
- }
-
- pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
- rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
- rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
-
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
-
- rtc_tm->tm_year += 100;
- rtc_tm->tm_mon -= 1;
-
- return 0;
-}
-
-
-static int s3c2410_rtc_settime(struct rtc_time *tm)
-{
- /* the rtc gets round the y2k problem by just not supporting it */
-
- if (tm->tm_year < 100)
- return -EINVAL;
-
- writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC);
- writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN);
- writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
- writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
- writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
- writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);
-
- return 0;
-}
-
-static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
-{
- struct rtc_time *alm_tm = &alrm->time;
- unsigned int alm_en;
-
- alm_tm->tm_sec = readb(S3C2410_ALMSEC);
- alm_tm->tm_min = readb(S3C2410_ALMMIN);
- alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
- alm_tm->tm_mon = readb(S3C2410_ALMMON);
- alm_tm->tm_mday = readb(S3C2410_ALMDATE);
- alm_tm->tm_year = readb(S3C2410_ALMYEAR);
-
- alm_en = readb(S3C2410_RTCALM);
-
- pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
- alm_en,
- alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
- alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
-
-
- /* decode the alarm enable field */
-
- if (alm_en & S3C2410_RTCALM_SECEN) {
- BCD_TO_BIN(alm_tm->tm_sec);
- } else {
- alm_tm->tm_sec = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_MINEN) {
- BCD_TO_BIN(alm_tm->tm_min);
- } else {
- alm_tm->tm_min = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_HOUREN) {
- BCD_TO_BIN(alm_tm->tm_hour);
- } else {
- alm_tm->tm_hour = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_DAYEN) {
- BCD_TO_BIN(alm_tm->tm_mday);
- } else {
- alm_tm->tm_mday = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_MONEN) {
- BCD_TO_BIN(alm_tm->tm_mon);
- alm_tm->tm_mon -= 1;
- } else {
- alm_tm->tm_mon = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_YEAREN) {
- BCD_TO_BIN(alm_tm->tm_year);
- } else {
- alm_tm->tm_year = 0xffff;
- }
-
- /* todo - set alrm->enabled ? */
-
- return 0;
-}
-
-static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
-{
- struct rtc_time *tm = &alrm->time;
- unsigned int alrm_en;
-
- pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
- alrm->enabled,
- tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
- tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
-
- if (alrm->enabled || 1) {
- alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
- writeb(0x00, S3C2410_RTCALM);
-
- if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
- alrm_en |= S3C2410_RTCALM_SECEN;
- writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
- }
-
- if (tm->tm_min < 60 && tm->tm_min >= 0) {
- alrm_en |= S3C2410_RTCALM_MINEN;
- writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
- }
-
- if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
- alrm_en |= S3C2410_RTCALM_HOUREN;
- writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
- }
-
- pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
-
- writeb(alrm_en, S3C2410_RTCALM);
- enable_irq_wake(s3c2410_rtc_alarmno);
- } else {
- alrm_en = readb(S3C2410_RTCALM);
- alrm_en &= ~S3C2410_RTCALM_ALMEN;
- writeb(alrm_en, S3C2410_RTCALM);
- disable_irq_wake(s3c2410_rtc_alarmno);
- }
-
- return 0;
-}
-
-static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case RTC_AIE_OFF:
- case RTC_AIE_ON:
- s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
- return 0;
-
- case RTC_PIE_OFF:
- case RTC_PIE_ON:
- s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
- return 0;
-
- case RTC_IRQP_READ:
- return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg);
-
- case RTC_IRQP_SET:
- if (arg < 1 || arg > 64)
- return -EINVAL;
-
- if (!capable(CAP_SYS_RESOURCE))
- return -EACCES;
-
- /* check for power of 2 */
-
- if ((arg & (arg-1)) != 0)
- return -EINVAL;
-
- pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
-
- s3c2410_rtc_setfreq(arg);
- return 0;
-
- case RTC_UIE_ON:
- case RTC_UIE_OFF:
- return -EINVAL;
- }
-
- return -EINVAL;
-}
-
-static int s3c2410_rtc_proc(char *buf)
-{
- unsigned int rtcalm = readb(S3C2410_RTCALM);
- unsigned int ticnt = readb (S3C2410_TICNT);
- char *p = buf;
-
- p += sprintf(p, "alarm_IRQ\t: %s\n",
- (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
- p += sprintf(p, "periodic_IRQ\t: %s\n",
- (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
- p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq);
-
- return p - buf;
-}
-
-static int s3c2410_rtc_open(void)
-{
- int ret;
-
- ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq,
- SA_INTERRUPT, "s3c2410-rtc alarm", NULL);
-
- if (ret)
- printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno);
-
- ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq,
- SA_INTERRUPT, "s3c2410-rtc tick", NULL);
-
- if (ret) {
- printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno);
- goto tick_err;
- }
-
- return ret;
-
- tick_err:
- free_irq(s3c2410_rtc_alarmno, NULL);
- return ret;
-}
-
-static void s3c2410_rtc_release(void)
-{
- /* do not clear AIE here, it may be needed for wake */
-
- s3c2410_rtc_setpie(0);
- free_irq(s3c2410_rtc_alarmno, NULL);
- free_irq(s3c2410_rtc_tickno, NULL);
-}
-
-static struct rtc_ops s3c2410_rtcops = {
- .owner = THIS_MODULE,
- .open = s3c2410_rtc_open,
- .release = s3c2410_rtc_release,
- .ioctl = s3c2410_rtc_ioctl,
- .read_time = s3c2410_rtc_gettime,
- .set_time = s3c2410_rtc_settime,
- .read_alarm = s3c2410_rtc_getalarm,
- .set_alarm = s3c2410_rtc_setalarm,
- .proc = s3c2410_rtc_proc,
-};
-
-static void s3c2410_rtc_enable(struct platform_device *pdev, int en)
-{
- unsigned int tmp;
-
- if (s3c2410_rtc_base == NULL)
- return;
-
- if (!en) {
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);
-
- tmp = readb(S3C2410_TICNT);
- writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
- } else {
- /* re-enable the device, and check it is ok */
-
- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
- dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
-
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
- }
-
- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
- dev_info(&pdev->dev, "removing S3C2410_RTCCON_CNTSEL\n");
-
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
- }
-
- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
- dev_info(&pdev->dev, "removing S3C2410_RTCCON_CLKRST\n");
-
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
- }
- }
-}
-
-static int s3c2410_rtc_remove(struct platform_device *dev)
-{
- unregister_rtc(&s3c2410_rtcops);
-
- s3c2410_rtc_setpie(0);
- s3c2410_rtc_setaie(0);
-
- if (s3c2410_rtc_mem != NULL) {
- pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n");
- iounmap(s3c2410_rtc_base);
- release_resource(s3c2410_rtc_mem);
- kfree(s3c2410_rtc_mem);
- }
-
- return 0;
-}
-
-static int s3c2410_rtc_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int ret;
-
- pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
-
- /* find the IRQs */
-
- s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
- if (s3c2410_rtc_tickno < 0) {
- dev_err(&pdev->dev, "no irq for rtc tick\n");
- return -ENOENT;
- }
-
- s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
- if (s3c2410_rtc_alarmno < 0) {
- dev_err(&pdev->dev, "no irq for alarm\n");
- return -ENOENT;
- }
-
- pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
- s3c2410_rtc_tickno, s3c2410_rtc_alarmno);
-
- /* get the memory region */
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get memory region resource\n");
- return -ENOENT;
- }
-
- s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,
- pdev->name);
-
- if (s3c2410_rtc_mem == NULL) {
- dev_err(&pdev->dev, "failed to reserve memory region\n");
- ret = -ENOENT;
- goto exit_err;
- }
-
- s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
- if (s3c2410_rtc_base == NULL) {
- dev_err(&pdev->dev, "failed ioremap()\n");
- ret = -EINVAL;
- goto exit_err;
- }
-
- s3c2410_rtc_mem = res;
- pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);
-
- pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
-
- /* check to see if everything is setup correctly */
-
- s3c2410_rtc_enable(pdev, 1);
-
- pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
-
- s3c2410_rtc_setfreq(s3c2410_rtc_freq);
-
- /* register RTC and exit */
-
- register_rtc(&s3c2410_rtcops);
- return 0;
-
- exit_err:
- dev_err(&pdev->dev, "error %d during initialisation\n", ret);
-
- return ret;
-}
-
-#ifdef CONFIG_PM
-
-/* S3C2410 RTC Power management control */
-
-static struct timespec s3c2410_rtc_delta;
-
-static int ticnt_save;
-
-static int s3c2410_rtc_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
- /* save TICNT for anyone using periodic interrupts */
-
- ticnt_save = readb(S3C2410_TICNT);
-
- /* calculate time delta for suspend */
-
- s3c2410_rtc_gettime(&tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- save_time_delta(&s3c2410_rtc_delta, &time);
- s3c2410_rtc_enable(pdev, 0);
-
- return 0;
-}
-
-static int s3c2410_rtc_resume(struct platform_device *pdev)
-{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
- s3c2410_rtc_enable(pdev, 1);
- s3c2410_rtc_gettime(&tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- restore_time_delta(&s3c2410_rtc_delta, &time);
-
- writeb(ticnt_save, S3C2410_TICNT);
- return 0;
-}
-#else
-#define s3c2410_rtc_suspend NULL
-#define s3c2410_rtc_resume NULL
-#endif
-
-static struct platform_driver s3c2410_rtcdrv = {
- .probe = s3c2410_rtc_probe,
- .remove = s3c2410_rtc_remove,
- .suspend = s3c2410_rtc_suspend,
- .resume = s3c2410_rtc_resume,
- .driver = {
- .name = "s3c2410-rtc",
- .owner = THIS_MODULE,
- },
-};
-
-static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";
-
-static int __init s3c2410_rtc_init(void)
-{
- printk(banner);
- return platform_driver_register(&s3c2410_rtcdrv);
-}
-
-static void __exit s3c2410_rtc_exit(void)
-{
- platform_driver_unregister(&s3c2410_rtcdrv);
-}
-
-module_init(s3c2410_rtc_init);
-module_exit(s3c2410_rtc_exit);
-
-MODULE_DESCRIPTION("S3C24XX RTC Driver");
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c
index 664a6e97eb1..99e5272e3c5 100644
--- a/drivers/char/scx200_gpio.c
+++ b/drivers/char/scx200_gpio.c
@@ -1,96 +1,57 @@
-/* linux/drivers/char/scx200_gpio.c
+/* linux/drivers/char/scx200_gpio.c
National Semiconductor SCx200 GPIO driver. Allows a user space
process to play with the GPIO pins.
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> */
-#include <linux/config.h>
+#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
+#include <linux/types.h>
+#include <linux/cdev.h>
+
#include <linux/scx200_gpio.h>
+#include <linux/nsc_gpio.h>
+
+#define DRVNAME "scx200_gpio"
-#define NAME "scx200_gpio"
+static struct platform_device *pdev;
MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
-MODULE_DESCRIPTION("NatSemi SCx200 GPIO Pin Driver");
+MODULE_DESCRIPTION("NatSemi/AMD SCx200 GPIO Pin Driver");
MODULE_LICENSE("GPL");
static int major = 0; /* default to dynamic major */
module_param(major, int, 0);
MODULE_PARM_DESC(major, "Major device number");
-static ssize_t scx200_gpio_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- unsigned m = iminor(file->f_dentry->d_inode);
- size_t i;
-
- for (i = 0; i < len; ++i) {
- char c;
- if (get_user(c, data+i))
- return -EFAULT;
- switch (c)
- {
- case '0':
- scx200_gpio_set(m, 0);
- break;
- case '1':
- scx200_gpio_set(m, 1);
- break;
- case 'O':
- printk(KERN_INFO NAME ": GPIO%d output enabled\n", m);
- scx200_gpio_configure(m, ~1, 1);
- break;
- case 'o':
- printk(KERN_INFO NAME ": GPIO%d output disabled\n", m);
- scx200_gpio_configure(m, ~1, 0);
- break;
- case 'T':
- printk(KERN_INFO NAME ": GPIO%d output is push pull\n", m);
- scx200_gpio_configure(m, ~2, 2);
- break;
- case 't':
- printk(KERN_INFO NAME ": GPIO%d output is open drain\n", m);
- scx200_gpio_configure(m, ~2, 0);
- break;
- case 'P':
- printk(KERN_INFO NAME ": GPIO%d pull up enabled\n", m);
- scx200_gpio_configure(m, ~4, 4);
- break;
- case 'p':
- printk(KERN_INFO NAME ": GPIO%d pull up disabled\n", m);
- scx200_gpio_configure(m, ~4, 0);
- break;
- }
- }
-
- return len;
-}
+#define MAX_PINS 32 /* 64 later, when known ok */
-static ssize_t scx200_gpio_read(struct file *file, char __user *buf,
- size_t len, loff_t *ppos)
-{
- unsigned m = iminor(file->f_dentry->d_inode);
- int value;
-
- value = scx200_gpio_get(m);
- if (put_user(value ? '1' : '0', buf))
- return -EFAULT;
-
- return 1;
-}
+struct nsc_gpio_ops scx200_gpio_ops = {
+ .owner = THIS_MODULE,
+ .gpio_config = scx200_gpio_configure,
+ .gpio_dump = nsc_gpio_dump,
+ .gpio_get = scx200_gpio_get,
+ .gpio_set = scx200_gpio_set,
+ .gpio_change = scx200_gpio_change,
+ .gpio_current = scx200_gpio_current
+};
+EXPORT_SYMBOL_GPL(scx200_gpio_ops);
static int scx200_gpio_open(struct inode *inode, struct file *file)
{
unsigned m = iminor(inode);
- if (m > 63)
+ file->private_data = &scx200_gpio_ops;
+
+ if (m >= MAX_PINS)
return -EINVAL;
return nonseekable_open(inode, file);
}
@@ -100,50 +61,71 @@ static int scx200_gpio_release(struct inode *inode, struct file *file)
return 0;
}
-
-static struct file_operations scx200_gpio_fops = {
+static const struct file_operations scx200_gpio_fileops = {
.owner = THIS_MODULE,
- .write = scx200_gpio_write,
- .read = scx200_gpio_read,
+ .write = nsc_gpio_write,
+ .read = nsc_gpio_read,
.open = scx200_gpio_open,
.release = scx200_gpio_release,
};
+static struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
+
static int __init scx200_gpio_init(void)
{
- int r;
-
- printk(KERN_DEBUG NAME ": NatSemi SCx200 GPIO Driver\n");
+ int rc;
+ dev_t devid;
if (!scx200_gpio_present()) {
- printk(KERN_ERR NAME ": no SCx200 gpio pins available\n");
+ printk(KERN_ERR DRVNAME ": no SCx200 gpio present\n");
return -ENODEV;
}
- r = register_chrdev(major, NAME, &scx200_gpio_fops);
- if (r < 0) {
- printk(KERN_ERR NAME ": unable to register character device\n");
- return r;
+ /* support dev_dbg() with pdev->dev */
+ pdev = platform_device_alloc(DRVNAME, 0);
+ if (!pdev)
+ return -ENOMEM;
+
+ rc = platform_device_add(pdev);
+ if (rc)
+ goto undo_malloc;
+
+ /* nsc_gpio uses dev_dbg(), so needs this */
+ scx200_gpio_ops.dev = &pdev->dev;
+
+ if (major) {
+ devid = MKDEV(major, 0);
+ rc = register_chrdev_region(devid, MAX_PINS, "scx200_gpio");
+ } else {
+ rc = alloc_chrdev_region(&devid, 0, MAX_PINS, "scx200_gpio");
+ major = MAJOR(devid);
}
- if (!major) {
- major = r;
- printk(KERN_DEBUG NAME ": got dynamic major %d\n", major);
+ if (rc < 0) {
+ dev_err(&pdev->dev, "SCx200 chrdev_region err: %d\n", rc);
+ goto undo_platform_device_add;
}
- return 0;
+ cdev_init(&scx200_gpio_cdev, &scx200_gpio_fileops);
+ cdev_add(&scx200_gpio_cdev, devid, MAX_PINS);
+
+ return 0; /* succeed */
+
+undo_platform_device_add:
+ platform_device_del(pdev);
+undo_malloc:
+ platform_device_put(pdev);
+
+ return rc;
}
static void __exit scx200_gpio_cleanup(void)
{
- unregister_chrdev(major, NAME);
+ cdev_del(&scx200_gpio_cdev);
+ /* cdev_put(&scx200_gpio_cdev); */
+
+ unregister_chrdev_region(MKDEV(major, 0), MAX_PINS);
+ platform_device_unregister(pdev);
}
module_init(scx200_gpio_init);
module_exit(scx200_gpio_cleanup);
-
-/*
- Local variables:
- compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
- c-basic-offset: 8
- End:
-*/
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 71093a9fc46..74cff839c85 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -33,7 +33,7 @@ extern void poke_blanked_console(void);
/* Variables for selection control. */
/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons; /* must not be disallocated */
+struct vc_data *sel_cons; /* must not be deallocated */
static volatile int sel_start = -1; /* cleared by clear_selection */
static int sel_end;
static int sel_buffer_lth;
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 037c940ac71..21a710cb4bb 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -44,7 +44,6 @@
* - replace bottom half handler with task queue handler
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -2235,7 +2234,6 @@ scrn[1] = '\0';
/* Initialize the tty_driver structure */
cy_serial_driver->owner = THIS_MODULE;
- cy_serial_driver->devfs_name = "tts/";
cy_serial_driver->name = "ttyS";
cy_serial_driver->major = TTY_MAJOR;
cy_serial_driver->minor_start = 64;
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 56c8243cdb7..07e0b75f233 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -105,7 +105,7 @@ scdrv_open(struct inode *inode, struct file *file)
/* hook this subchannel up to the system controller interrupt */
rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt,
- SA_SHIRQ | SA_INTERRUPT,
+ IRQF_SHARED | IRQF_DISABLED,
SYSCTL_BASENAME, sd);
if (rv) {
ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
@@ -347,7 +347,7 @@ scdrv_poll(struct file *file, struct poll_table_struct *wait)
return mask;
}
-static struct file_operations scdrv_fops = {
+static const struct file_operations scdrv_fops = {
.owner = THIS_MODULE,
.read = scdrv_read,
.write = scdrv_write,
@@ -374,7 +374,12 @@ scdrv_init(void)
struct sysctl_data_s *scd;
void *salbuf;
dev_t first_dev, dev;
- nasid_t event_nasid = ia64_sn_get_console_nasid();
+ nasid_t event_nasid;
+
+ if (!ia64_platform_is("sn2"))
+ return -ENODEV;
+
+ event_nasid = ia64_sn_get_console_nasid();
if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
SYSCTL_BASENAME) < 0) {
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index e234d50e142..d12d4f629ce 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -220,20 +220,7 @@ scdrv_dispatch_event(char *event, int len)
" Sending SIGPWR to init...\n");
/* give a SIGPWR signal to init proc */
-
- /* first find init's task */
- read_lock(&tasklist_lock);
- for_each_process(p) {
- if (p->pid == 1)
- break;
- }
- if (p) {
- force_sig(SIGPWR, p);
- } else {
- printk(KERN_ERR "Failed to signal init!\n");
- snsc_shutting_down = 0; /* so can try again (?) */
- }
- read_unlock(&tasklist_lock);
+ kill_proc(1, SIGPWR, 0);
} else {
/* print to system log */
printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
@@ -310,7 +297,7 @@ scdrv_event_init(struct sysctl_data_s *scd)
/* hook event subchannel up to the system controller interrupt */
rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt,
- SA_SHIRQ | SA_INTERRUPT,
+ IRQF_SHARED | IRQF_DISABLED,
"system controller events", event_sd);
if (rv) {
printk(KERN_WARNING "%s: irq request failed (%d)\n",
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index 43dfd8689dc..d4e434d694b 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -33,7 +33,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/pci.h>
@@ -1107,7 +1106,7 @@ static int sonypi_misc_ioctl(struct inode *ip, struct file *fp,
return ret;
}
-static struct file_operations sonypi_misc_fops = {
+static const struct file_operations sonypi_misc_fops = {
.owner = THIS_MODULE,
.read = sonypi_misc_read,
.poll = sonypi_misc_poll,
@@ -1283,7 +1282,7 @@ static int __devinit sonypi_setup_irq(struct sonypi_device *dev,
while (irq_list->irq) {
if (!request_irq(irq_list->irq, sonypi_irq,
- SA_SHIRQ, "sonypi", sonypi_irq)) {
+ IRQF_SHARED, "sonypi", sonypi_irq)) {
dev->irq = irq_list->irq;
dev->bits = irq_list->bits;
return 0;
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 5343e9fc6ab..c0ef0f0e580 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -75,7 +75,6 @@
* Documentation/specialix.txt
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/io.h>
@@ -1016,9 +1015,9 @@ static inline int sx_setup_board(struct specialix_board * bp)
return 0;
if (bp->flags & SX_BOARD_IS_PCI)
- error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT | SA_SHIRQ, "specialix IO8+", bp);
+ error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED | IRQF_SHARED, "specialix IO8+", bp);
else
- error = request_irq(bp->irq, sx_interrupt, SA_INTERRUPT, "specialix IO8+", bp);
+ error = request_irq(bp->irq, sx_interrupt, IRQF_DISABLED, "specialix IO8+", bp);
if (error)
return error;
@@ -1088,24 +1087,16 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
spin_unlock_irqrestore(&bp->lock, flags);
dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
- baud = C_BAUD(tty);
+ baud = tty_get_baud_rate(tty);
- if (baud & CBAUDEX) {
- baud &= ~CBAUDEX;
- if (baud < 1 || baud > 2)
- port->tty->termios->c_cflag &= ~CBAUDEX;
- else
- baud += 15;
- }
- if (baud == 15) {
+ if (baud == 38400) {
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
baud ++;
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
baud += 2;
}
-
- if (!baud_table[baud]) {
+ if (!baud) {
/* Drop DTR & exit */
dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
if (!SX_CRTSCTS (tty)) {
@@ -1135,7 +1126,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
"This is an untested option, please be carefull.\n",
port_No (port), tmp);
else
- tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
+ tmp = (((SX_OSCFREQ + baud/2) / baud +
CD186x_TPC/2) / CD186x_TPC);
if ((tmp < 0x10) && time_before(again, jiffies)) {
@@ -1683,7 +1674,7 @@ static int sx_write(struct tty_struct * tty,
bp = port_Board(port);
- if (!tty || !port->xmit_buf || !tmp_buf) {
+ if (!port->xmit_buf || !tmp_buf) {
func_exit();
return 0;
}
@@ -1733,7 +1724,7 @@ static void sx_put_char(struct tty_struct * tty, unsigned char ch)
return;
}
dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
- if (!tty || !port->xmit_buf) {
+ if (!port->xmit_buf) {
func_exit();
return;
}
@@ -2477,7 +2468,7 @@ static int __init specialix_init(void)
#endif
for (i = 0; i < SX_NBOARD; i++)
- sx_board[i].lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&sx_board[i].lock);
if (sx_init_drivers()) {
func_exit();
@@ -2585,6 +2576,12 @@ static void __exit specialix_exit_module(void)
func_exit();
}
+static struct pci_device_id specialx_pci_tbl[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, specialx_pci_tbl);
+
module_init(specialix_init_module);
module_exit(specialix_exit_module);
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index a9c5a7230f8..3beb2203d24 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -26,7 +26,6 @@
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -40,7 +39,6 @@
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/device.h>
#include <linux/delay.h>
@@ -141,15 +139,6 @@ static char *stl_drvversion = "5.6.0";
static struct tty_driver *stl_serial;
/*
- * We will need to allocate a temporary write buffer for chars that
- * come direct from user space. The problem is that a copy from user
- * space might cause a page fault (typically on a system that is
- * swapping!). All ports will share one buffer - since if the system
- * is already swapping a shared buffer won't make things any worse.
- */
-static char *stl_tmpwritebuf;
-
-/*
* Define a local default termios struct. All ports will be created
* with this termios initially. Basically all it defines is a raw port
* at 9600, 8 data bits, 1 stop bit.
@@ -363,6 +352,14 @@ static unsigned char stl_vecmap[] = {
};
/*
+ * Lock ordering is that you may not take stallion_lock holding
+ * brd_lock.
+ */
+
+static spinlock_t brd_lock; /* Guard the board mapping */
+static spinlock_t stallion_lock; /* Guard the tty driver */
+
+/*
* Set up enable and disable macros for the ECH boards. They require
* the secondary io address space to be activated and deactivated.
* This way all ECH boards can share their secondary io region.
@@ -710,7 +707,7 @@ static unsigned int sc26198_baudtable[] = {
* Define the driver info for a user level control device. Used mainly
* to get at port stats - only not using the port device itself.
*/
-static struct file_operations stl_fsiomem = {
+static const struct file_operations stl_fsiomem = {
.owner = THIS_MODULE,
.ioctl = stl_memioctl,
};
@@ -725,17 +722,7 @@ static struct class *stallion_class;
static int __init stallion_module_init(void)
{
- unsigned long flags;
-
-#ifdef DEBUG
- printk("init_module()\n");
-#endif
-
- save_flags(flags);
- cli();
stl_init();
- restore_flags(flags);
-
return 0;
}
@@ -746,7 +733,6 @@ static void __exit stallion_module_exit(void)
stlbrd_t *brdp;
stlpanel_t *panelp;
stlport_t *portp;
- unsigned long flags;
int i, j, k;
#ifdef DEBUG
@@ -756,9 +742,6 @@ static void __exit stallion_module_exit(void)
printk(KERN_INFO "Unloading %s: version %s\n", stl_drvtitle,
stl_drvversion);
- save_flags(flags);
- cli();
-
/*
* Free up all allocated resources used by the ports. This includes
* memory and interrupts. As part of this process we will also do
@@ -770,21 +753,15 @@ static void __exit stallion_module_exit(void)
if (i) {
printk("STALLION: failed to un-register tty driver, "
"errno=%d\n", -i);
- restore_flags(flags);
return;
}
- for (i = 0; i < 4; i++) {
- devfs_remove("staliomem/%d", i);
+ for (i = 0; i < 4; i++)
class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i));
- }
- devfs_remove("staliomem");
if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem")))
printk("STALLION: failed to un-register serial memory device, "
"errno=%d\n", -i);
class_destroy(stallion_class);
- kfree(stl_tmpwritebuf);
-
for (i = 0; (i < stl_nrbrds); i++) {
if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL)
continue;
@@ -814,8 +791,6 @@ static void __exit stallion_module_exit(void)
kfree(brdp);
stl_brds[i] = (stlbrd_t *) NULL;
}
-
- restore_flags(flags);
}
module_init(stallion_module_init);
@@ -948,7 +923,7 @@ static stlbrd_t *stl_allocbrd(void)
brdp = kzalloc(sizeof(stlbrd_t), GFP_KERNEL);
if (!brdp) {
- printk("STALLION: failed to allocate memory (size=%d)\n",
+ printk("STALLION: failed to allocate memory (size=%Zd)\n",
sizeof(stlbrd_t));
return NULL;
}
@@ -1066,16 +1041,17 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
rc = 0;
doclocal = 0;
+ spin_lock_irqsave(&stallion_lock, flags);
+
if (portp->tty->termios->c_cflag & CLOCAL)
doclocal++;
- save_flags(flags);
- cli();
portp->openwaitcnt++;
if (! tty_hung_up_p(filp))
portp->refcount--;
for (;;) {
+ /* Takes brd_lock internally */
stl_setsignals(portp, 1, 1);
if (tty_hung_up_p(filp) ||
((portp->flags & ASYNC_INITIALIZED) == 0)) {
@@ -1093,13 +1069,14 @@ static int stl_waitcarrier(stlport_t *portp, struct file *filp)
rc = -ERESTARTSYS;
break;
}
+ /* FIXME */
interruptible_sleep_on(&portp->open_wait);
}
if (! tty_hung_up_p(filp))
portp->refcount++;
portp->openwaitcnt--;
- restore_flags(flags);
+ spin_unlock_irqrestore(&stallion_lock, flags);
return rc;
}
@@ -1119,16 +1096,15 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
if (portp == (stlport_t *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&stallion_lock, flags);
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&stallion_lock, flags);
return;
}
if ((tty->count == 1) && (portp->refcount != 1))
portp->refcount = 1;
if (portp->refcount-- > 1) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&stallion_lock, flags);
return;
}
@@ -1142,11 +1118,18 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
* (The sc26198 has no "end-of-data" interrupt only empty FIFO)
*/
tty->closing = 1;
+
+ spin_unlock_irqrestore(&stallion_lock, flags);
+
if (portp->closing_wait != ASYNC_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, portp->closing_wait);
stl_waituntilsent(tty, (HZ / 2));
+
+ spin_lock_irqsave(&stallion_lock, flags);
portp->flags &= ~ASYNC_INITIALIZED;
+ spin_unlock_irqrestore(&stallion_lock, flags);
+
stl_disableintrs(portp);
if (tty->termios->c_cflag & HUPCL)
stl_setsignals(portp, 0, 0);
@@ -1173,7 +1156,6 @@ static void stl_close(struct tty_struct *tty, struct file *filp)
portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
wake_up_interruptible(&portp->close_wait);
- restore_flags(flags);
}
/*****************************************************************************/
@@ -1195,9 +1177,6 @@ static int stl_write(struct tty_struct *tty, const unsigned char *buf, int count
(int) tty, (int) buf, count);
#endif
- if ((tty == (struct tty_struct *) NULL) ||
- (stl_tmpwritebuf == (char *) NULL))
- return 0;
portp = tty->driver_data;
if (portp == (stlport_t *) NULL)
return 0;
@@ -1302,11 +1281,6 @@ static void stl_flushchars(struct tty_struct *tty)
if (portp->tx.buf == (char *) NULL)
return;
-#if 0
- if (tty->stopped || tty->hw_stopped ||
- (portp->tx.head == portp->tx.tail))
- return;
-#endif
stl_startrxtx(portp, -1, 1);
}
@@ -1977,12 +1951,14 @@ static int stl_eiointr(stlbrd_t *brdp)
unsigned int iobase;
int handled = 0;
+ spin_lock(&brd_lock);
panelp = brdp->panels[0];
iobase = panelp->iobase;
while (inb(brdp->iostatus) & EIO_INTRPEND) {
handled = 1;
(* panelp->isr)(panelp, iobase);
}
+ spin_unlock(&brd_lock);
return handled;
}
@@ -2168,7 +2144,7 @@ static int __init stl_initports(stlbrd_t *brdp, stlpanel_t *panelp)
portp = kzalloc(sizeof(stlport_t), GFP_KERNEL);
if (!portp) {
printk("STALLION: failed to allocate memory "
- "(size=%d)\n", sizeof(stlport_t));
+ "(size=%Zd)\n", sizeof(stlport_t));
break;
}
@@ -2304,7 +2280,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
if (!panelp) {
printk(KERN_WARNING "STALLION: failed to allocate memory "
- "(size=%d)\n", sizeof(stlpanel_t));
+ "(size=%Zd)\n", sizeof(stlpanel_t));
return -ENOMEM;
}
@@ -2326,7 +2302,7 @@ static inline int stl_initeio(stlbrd_t *brdp)
brdp->nrpanels = 1;
brdp->state |= BRD_FOUND;
brdp->hwid = status;
- if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) {
+ if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, brdp->irq);
rc = -ENODEV;
@@ -2478,7 +2454,7 @@ static inline int stl_initech(stlbrd_t *brdp)
panelp = kzalloc(sizeof(stlpanel_t), GFP_KERNEL);
if (!panelp) {
printk("STALLION: failed to allocate memory "
- "(size=%d)\n", sizeof(stlpanel_t));
+ "(size=%Zd)\n", sizeof(stlpanel_t));
break;
}
panelp->magic = STL_PANELMAGIC;
@@ -2536,7 +2512,7 @@ static inline int stl_initech(stlbrd_t *brdp)
outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl);
brdp->state |= BRD_FOUND;
- if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) {
+ if (request_irq(brdp->irq, stl_intr, IRQF_SHARED, name, brdp) != 0) {
printk("STALLION: failed to register interrupt "
"routine for %s irq=%d\n", name, brdp->irq);
i = -ENODEV;
@@ -2879,8 +2855,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
portp->stats.lflags = 0;
portp->stats.rxbuffered = 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&stallion_lock, flags);
if (portp->tty != (struct tty_struct *) NULL) {
if (portp->tty->driver_data == portp) {
portp->stats.ttystate = portp->tty->flags;
@@ -2894,7 +2869,7 @@ static int stl_getportstats(stlport_t *portp, comstats_t __user *cp)
}
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&stallion_lock, flags);
head = portp->tx.head;
tail = portp->tx.tail;
@@ -3049,6 +3024,9 @@ static int __init stl_init(void)
int i;
printk(KERN_INFO "%s: version %s\n", stl_drvtitle, stl_drvversion);
+ spin_lock_init(&stallion_lock);
+ spin_lock_init(&brd_lock);
+
stl_initbrds();
stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS);
@@ -3056,35 +3034,21 @@ static int __init stl_init(void)
return -1;
/*
- * Allocate a temporary write buffer.
- */
- stl_tmpwritebuf = kmalloc(STL_TXBUFSIZE, GFP_KERNEL);
- if (!stl_tmpwritebuf)
- printk("STALLION: failed to allocate memory (size=%d)\n",
- STL_TXBUFSIZE);
-
-/*
* Set up a character driver for per board stuff. This is mainly used
* to do stats ioctls on the ports.
*/
if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
printk("STALLION: failed to register serial board device\n");
- devfs_mk_dir("staliomem");
stallion_class = class_create(THIS_MODULE, "staliomem");
- for (i = 0; i < 4; i++) {
- devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
- S_IFCHR|S_IRUSR|S_IWUSR,
- "staliomem/%d", i);
+ for (i = 0; i < 4; i++)
class_device_create(stallion_class, NULL,
MKDEV(STL_SIOMEMMAJOR, i), NULL,
"staliomem%d", i);
- }
stl_serial->owner = THIS_MODULE;
stl_serial->driver_name = stl_drvname;
stl_serial->name = "ttyE";
- stl_serial->devfs_name = "tts/E";
stl_serial->major = STL_SERIALMAJOR;
stl_serial->minor_start = 0;
stl_serial->type = TTY_DRIVER_TYPE_SERIAL;
@@ -3147,11 +3111,13 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
unsigned int gfrcr;
int chipmask, i, j;
int nrchips, uartaddr, ioaddr;
+ unsigned long flags;
#ifdef DEBUG
printk("stl_panelinit(brdp=%x,panelp=%x)\n", (int) brdp, (int) panelp);
#endif
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(panelp->brdnr, panelp->pagenr);
/*
@@ -3189,6 +3155,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
}
BRDDISABLE(panelp->brdnr);
+ spin_unlock_irqrestore(&brd_lock, flags);
return chipmask;
}
@@ -3200,6 +3167,7 @@ static int stl_cd1400panelinit(stlbrd_t *brdp, stlpanel_t *panelp)
static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *portp)
{
+ unsigned long flags;
#ifdef DEBUG
printk("stl_cd1400portinit(brdp=%x,panelp=%x,portp=%x)\n",
(int) brdp, (int) panelp, (int) portp);
@@ -3209,6 +3177,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
(portp == (stlport_t *) NULL))
return;
+ spin_lock_irqsave(&brd_lock, flags);
portp->ioaddr = panelp->iobase + (((brdp->brdtype == BRD_ECHPCI) ||
(portp->portnr < 8)) ? 0 : EREG_BANKSIZE);
portp->uartaddr = (portp->portnr & 0x04) << 5;
@@ -3219,6 +3188,7 @@ static void stl_cd1400portinit(stlbrd_t *brdp, stlpanel_t *panelp, stlport_t *po
stl_cd1400setreg(portp, LIVR, (portp->portnr << 3));
portp->hwid = stl_cd1400getreg(portp, GFRCR);
BRDDISABLE(portp->brdnr);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3428,8 +3398,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x3));
srer = stl_cd1400getreg(portp, SRER);
@@ -3466,7 +3435,7 @@ static void stl_cd1400setport(stlport_t *portp, struct termios *tiosp)
portp->sigs &= ~TIOCM_CD;
stl_cd1400setreg(portp, SRER, ((srer & ~sreroff) | sreron));
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3492,8 +3461,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
if (rts > 0)
msvr2 = MSVR2_RTS;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
if (rts >= 0)
@@ -3501,7 +3469,7 @@ static void stl_cd1400setsignals(stlport_t *portp, int dtr, int rts)
if (dtr >= 0)
stl_cd1400setreg(portp, MSVR1, msvr1);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3520,14 +3488,13 @@ static int stl_cd1400getsignals(stlport_t *portp)
printk("stl_cd1400getsignals(portp=%x)\n", (int) portp);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
msvr1 = stl_cd1400getreg(portp, MSVR1);
msvr2 = stl_cd1400getreg(portp, MSVR2);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
sigs = 0;
sigs |= (msvr1 & MSVR1_DCD) ? TIOCM_CD : 0;
@@ -3569,15 +3536,14 @@ static void stl_cd1400enablerxtx(stlport_t *portp, int rx, int tx)
else if (rx > 0)
ccr |= CCR_RXENABLE;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
stl_cd1400ccrwait(portp);
stl_cd1400setreg(portp, CCR, ccr);
stl_cd1400ccrwait(portp);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3609,8 +3575,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
else if (rx > 0)
sreron |= SRER_RXDATA;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
stl_cd1400setreg(portp, SRER,
@@ -3618,7 +3583,7 @@ static void stl_cd1400startrxtx(stlport_t *portp, int rx, int tx)
BRDDISABLE(portp->brdnr);
if (tx > 0)
set_bit(ASYI_TXBUSY, &portp->istate);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3634,13 +3599,12 @@ static void stl_cd1400disableintrs(stlport_t *portp)
#ifdef DEBUG
printk("stl_cd1400disableintrs(portp=%x)\n", (int) portp);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
stl_cd1400setreg(portp, SRER, 0);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3653,8 +3617,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
printk("stl_cd1400sendbreak(portp=%x,len=%d)\n", (int) portp, len);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
stl_cd1400setreg(portp, SRER,
@@ -3664,7 +3627,7 @@ static void stl_cd1400sendbreak(stlport_t *portp, int len)
portp->brklen = len;
if (len == 1)
portp->stats.txbreaks++;
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3688,8 +3651,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
if (tty == (struct tty_struct *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
@@ -3729,7 +3691,7 @@ static void stl_cd1400flowctrl(stlport_t *portp, int state)
}
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3753,8 +3715,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
if (tty == (struct tty_struct *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
if (state) {
@@ -3769,7 +3730,7 @@ static void stl_cd1400sendflow(stlport_t *portp, int state)
stl_cd1400ccrwait(portp);
}
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3785,8 +3746,7 @@ static void stl_cd1400flush(stlport_t *portp)
if (portp == (stlport_t *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_cd1400setreg(portp, CAR, (portp->portnr & 0x03));
stl_cd1400ccrwait(portp);
@@ -3794,7 +3754,7 @@ static void stl_cd1400flush(stlport_t *portp)
stl_cd1400ccrwait(portp);
portp->tx.tail = portp->tx.head;
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -3833,6 +3793,7 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
(int) panelp, iobase);
#endif
+ spin_lock(&brd_lock);
outb(SVRR, iobase);
svrtype = inb(iobase + EREG_DATA);
if (panelp->nrports > 4) {
@@ -3846,6 +3807,8 @@ static void stl_cd1400eiointr(stlpanel_t *panelp, unsigned int iobase)
stl_cd1400txisr(panelp, iobase);
else if (svrtype & SVRR_MDM)
stl_cd1400mdmisr(panelp, iobase);
+
+ spin_unlock(&brd_lock);
}
/*****************************************************************************/
@@ -4433,8 +4396,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
tiosp->c_cc[VSTART], tiosp->c_cc[VSTOP]);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_sc26198setreg(portp, IMR, 0);
stl_sc26198updatereg(portp, MR0, mr0);
@@ -4461,7 +4423,7 @@ static void stl_sc26198setport(stlport_t *portp, struct termios *tiosp)
portp->imr = (portp->imr & ~imroff) | imron;
stl_sc26198setreg(portp, IMR, portp->imr);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4491,13 +4453,12 @@ static void stl_sc26198setsignals(stlport_t *portp, int dtr, int rts)
else if (rts > 0)
iopioron |= IPR_RTS;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_sc26198setreg(portp, IOPIOR,
((stl_sc26198getreg(portp, IOPIOR) & ~iopioroff) | iopioron));
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4516,12 +4477,11 @@ static int stl_sc26198getsignals(stlport_t *portp)
printk("stl_sc26198getsignals(portp=%x)\n", (int) portp);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
ipr = stl_sc26198getreg(portp, IPR);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
sigs = 0;
sigs |= (ipr & IPR_DCD) ? 0 : TIOCM_CD;
@@ -4558,13 +4518,12 @@ static void stl_sc26198enablerxtx(stlport_t *portp, int rx, int tx)
else if (rx > 0)
ccr |= CR_RXENABLE;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_sc26198setreg(portp, SCCR, ccr);
BRDDISABLE(portp->brdnr);
portp->crenable = ccr;
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4593,15 +4552,14 @@ static void stl_sc26198startrxtx(stlport_t *portp, int rx, int tx)
else if (rx > 0)
imr |= IR_RXRDY | IR_RXBREAK | IR_RXWATCHDOG;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_sc26198setreg(portp, IMR, imr);
BRDDISABLE(portp->brdnr);
portp->imr = imr;
if (tx > 0)
set_bit(ASYI_TXBUSY, &portp->istate);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4618,13 +4576,12 @@ static void stl_sc26198disableintrs(stlport_t *portp)
printk("stl_sc26198disableintrs(portp=%x)\n", (int) portp);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
portp->imr = 0;
stl_sc26198setreg(portp, IMR, 0);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4637,8 +4594,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
printk("stl_sc26198sendbreak(portp=%x,len=%d)\n", (int) portp, len);
#endif
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
if (len == 1) {
stl_sc26198setreg(portp, SCCR, CR_TXSTARTBREAK);
@@ -4647,7 +4603,7 @@ static void stl_sc26198sendbreak(stlport_t *portp, int len)
stl_sc26198setreg(portp, SCCR, CR_TXSTOPBREAK);
}
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4672,8 +4628,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
if (tty == (struct tty_struct *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
if (state) {
@@ -4719,7 +4674,7 @@ static void stl_sc26198flowctrl(stlport_t *portp, int state)
}
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4744,8 +4699,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
if (tty == (struct tty_struct *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
if (state) {
mr0 = stl_sc26198getreg(portp, MR0);
@@ -4765,7 +4719,7 @@ static void stl_sc26198sendflow(stlport_t *portp, int state)
stl_sc26198setreg(portp, MR0, mr0);
}
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4781,14 +4735,13 @@ static void stl_sc26198flush(stlport_t *portp)
if (portp == (stlport_t *) NULL)
return;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
stl_sc26198setreg(portp, SCCR, CR_TXRESET);
stl_sc26198setreg(portp, SCCR, portp->crenable);
BRDDISABLE(portp->brdnr);
portp->tx.tail = portp->tx.head;
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
}
/*****************************************************************************/
@@ -4815,12 +4768,11 @@ static int stl_sc26198datastate(stlport_t *portp)
if (test_bit(ASYI_TXBUSY, &portp->istate))
return 1;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&brd_lock, flags);
BRDENABLE(portp->brdnr, portp->pagenr);
sr = stl_sc26198getreg(portp, SR);
BRDDISABLE(portp->brdnr);
- restore_flags(flags);
+ spin_unlock_irqrestore(&brd_lock, flags);
return (sr & SR_TXEMPTY) ? 0 : 1;
}
@@ -4878,6 +4830,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
stlport_t *portp;
unsigned int iack;
+ spin_lock(&brd_lock);
+
/*
* Work around bug in sc26198 chip... Cannot have A6 address
* line of UART high, else iack will be returned as 0.
@@ -4893,6 +4847,8 @@ static void stl_sc26198intr(stlpanel_t *panelp, unsigned int iobase)
stl_sc26198txisr(portp);
else
stl_sc26198otherisr(portp, iack);
+
+ spin_unlock(&brd_lock);
}
/*****************************************************************************/
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 3b474723027..e1cd2bc4b1e 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -410,7 +410,7 @@ static struct real_driver sx_real_driver = {
*
*/
-static struct file_operations sx_fw_fops = {
+static const struct file_operations sx_fw_fops = {
.owner = THIS_MODULE,
.ioctl = sx_fw_ioctl,
};
@@ -1993,7 +1993,7 @@ static int sx_init_board (struct sx_board *board)
if(board->irq > 0) {
/* fixed irq, probably PCI */
if(sx_irqmask & (1 << board->irq)) { /* may we use this irq? */
- if(request_irq(board->irq, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board)) {
+ if(request_irq(board->irq, sx_interrupt, IRQF_SHARED | IRQF_DISABLED, "sx", board)) {
printk(KERN_ERR "sx: Cannot allocate irq %d.\n", board->irq);
board->irq = 0;
}
@@ -2005,7 +2005,7 @@ static int sx_init_board (struct sx_board *board)
int irqmask = sx_irqmask & (IS_SX_BOARD(board) ? SX_ISA_IRQ_MASK : SI2_ISA_IRQ_MASK);
for(irqnr = 15; irqnr > 0; irqnr--)
if(irqmask & (1 << irqnr))
- if(! request_irq(irqnr, sx_interrupt, SA_SHIRQ | SA_INTERRUPT, "sx", board))
+ if(! request_irq(irqnr, sx_interrupt, IRQF_SHARED | IRQF_DISABLED, "sx", board))
break;
if(! irqnr)
printk(KERN_ERR "sx: Cannot allocate IRQ.\n");
@@ -2320,7 +2320,7 @@ static int sx_init_portstructs (int nboards, int nports)
#ifdef NEW_WRITE_LOCKING
port->gs.port_write_mutex = MUTEX;
#endif
- port->gs.driver_lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&port->gs.driver_lock);
/*
* Initializing wait queue
*/
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index fee2aca3f6a..78b1b1a2732 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -1344,8 +1344,12 @@ static void mgsl_isr_io_pin( struct mgsl_struct *info )
} else
info->input_signal_events.dcd_down++;
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(status & MISCSTATUS_DCD, info->netdev);
+ if (info->netcount) {
+ if (status & MISCSTATUS_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
@@ -7844,8 +7848,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->irq_spinlock, flags);
usc_get_serial_signals(info);
spin_unlock_irqrestore(&info->irq_spinlock, flags);
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
@@ -8150,7 +8156,7 @@ static int __devinit synclink_init_one (struct pci_dev *dev,
info->bus_type = MGSL_BUS_TYPE_PCI;
info->io_addr_size = 8;
- info->irq_flags = SA_SHIRQ;
+ info->irq_flags = IRQF_SHARED;
if (dev->device == 0x0210) {
/* Version 1 PCI9030 based universal PCI adapter */
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index b4d1f4eea43..2f07b085536 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -46,7 +46,6 @@
//#define DBGRBUF(info) dump_rbufs(info)
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
@@ -101,6 +100,7 @@ MODULE_LICENSE("GPL");
static struct pci_device_id pci_table[] = {
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{0,}, /* terminate list */
@@ -391,8 +391,8 @@ static MGSL_PARAMS default_params = {
#define DESC_LIST_SIZE 4096
#define MASK_PARITY BIT1
-#define MASK_FRAMING BIT2
-#define MASK_BREAK BIT3
+#define MASK_FRAMING BIT0
+#define MASK_BREAK BIT14
#define MASK_OVERRUN BIT4
#define GSR 0x00 /* global status */
@@ -870,7 +870,7 @@ static int write(struct tty_struct *tty,
goto cleanup;
DBGINFO(("%s write count=%d\n", info->device_name, count));
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
goto cleanup;
if (count > info->max_frame_size) {
@@ -924,7 +924,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
if (sanity_check(info, tty->name, "put_char"))
return;
DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
return;
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active && (info->tx_count < info->max_frame_size))
@@ -1497,8 +1497,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->lock, flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- hdlc_set_carrier(info->signals & SerialSignal_DCD, dev);
-
+ if (info->signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
@@ -1798,17 +1800,17 @@ static void rx_async(struct slgt_info *info)
stat = 0;
- if ((status = *(p+1) & (BIT9 + BIT8))) {
- if (status & BIT9)
+ if ((status = *(p+1) & (BIT1 + BIT0))) {
+ if (status & BIT1)
icount->parity++;
- else if (status & BIT8)
+ else if (status & BIT0)
icount->frame++;
/* discard char if tty control flags say so */
if (status & info->ignore_status_mask)
continue;
- if (status & BIT9)
+ if (status & BIT1)
stat = TTY_PARITY;
- else if (status & BIT8)
+ else if (status & BIT0)
stat = TTY_FRAME;
}
if (tty) {
@@ -1997,8 +1999,12 @@ static void dcd_change(struct slgt_info *info)
info->input_signal_events.dcd_down++;
}
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev);
+ if (info->netcount) {
+ if (info->signals & SerialSignal_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
wake_up_interruptible(&info->status_event_wait_q);
wake_up_interruptible(&info->event_wait_q);
@@ -2515,7 +2521,8 @@ static int set_txidle(struct slgt_info *info, int idle_mode)
DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
spin_lock_irqsave(&info->lock,flags);
info->idle_mode = idle_mode;
- tx_set_idle(info);
+ if (info->params.mode != MGSL_MODE_ASYNC)
+ tx_set_idle(info);
spin_unlock_irqrestore(&info->lock,flags);
return 0;
}
@@ -3076,7 +3083,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
static int alloc_tmp_rbuf(struct slgt_info *info)
{
- info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+ info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL);
if (info->tmp_rbuf == NULL)
return -ENOMEM;
return 0;
@@ -3276,6 +3283,9 @@ static void add_device(struct slgt_info *info)
case SYNCLINK_GT_DEVICE_ID:
devstr = "GT";
break;
+ case SYNCLINK_GT2_DEVICE_ID:
+ devstr = "GT2";
+ break;
case SYNCLINK_GT4_DEVICE_ID:
devstr = "GT4";
break;
@@ -3339,7 +3349,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
info->phys_reg_addr = pci_resource_start(pdev,0);
info->bus_type = MGSL_BUS_TYPE_PCI;
- info->irq_flags = SA_SHIRQ;
+ info->irq_flags = IRQF_SHARED;
info->init_error = -1; /* assume error, set to 0 on successful init */
}
@@ -3353,7 +3363,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
int i;
int port_count = 1;
- if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+ if (pdev->device == SYNCLINK_GT2_DEVICE_ID)
+ port_count = 2;
+ else if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
port_count = 4;
/* allocate device instances for all ports */
@@ -3940,8 +3952,6 @@ static void async_mode(struct slgt_info *info)
msc_set_vcr(info);
- tx_set_idle(info);
-
/* SCR (serial control)
*
* 15 1=tx req on FIFO half empty
@@ -4012,7 +4022,7 @@ static void hdlc_mode(struct slgt_info *info)
case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
}
- switch (info->params.crc_type)
+ switch (info->params.crc_type & HDLC_CRC_MASK)
{
case HDLC_CRC_16_CCITT: val |= BIT9; break;
case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4073,7 +4083,7 @@ static void hdlc_mode(struct slgt_info *info)
case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
}
- switch (info->params.crc_type)
+ switch (info->params.crc_type & HDLC_CRC_MASK)
{
case HDLC_CRC_16_CCITT: val |= BIT9; break;
case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -4175,17 +4185,38 @@ static void hdlc_mode(struct slgt_info *info)
*/
static void tx_set_idle(struct slgt_info *info)
{
- unsigned char val = 0xff;
+ unsigned char val;
+ unsigned short tcr;
- switch(info->idle_mode)
- {
- case HDLC_TXIDLE_FLAGS: val = 0x7e; break;
- case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
- case HDLC_TXIDLE_ZEROS: val = 0x00; break;
- case HDLC_TXIDLE_ONES: val = 0xff; break;
- case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
- case HDLC_TXIDLE_SPACE: val = 0x00; break;
- case HDLC_TXIDLE_MARK: val = 0xff; break;
+ /* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits
+ * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits
+ */
+ tcr = rd_reg16(info, TCR);
+ if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) {
+ /* disable preamble, set idle size to 16 bits */
+ tcr = (tcr & ~(BIT6 + BIT5)) | BIT4;
+ /* MSB of 16 bit idle specified in tx preamble register (TPR) */
+ wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff));
+ } else if (!(tcr & BIT6)) {
+ /* preamble is disabled, set idle size to 8 bits */
+ tcr &= ~(BIT5 + BIT4);
+ }
+ wr_reg16(info, TCR, tcr);
+
+ if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) {
+ /* LSB of custom tx idle specified in tx idle register */
+ val = (unsigned char)(info->idle_mode & 0xff);
+ } else {
+ /* standard 8 bit idle patterns */
+ switch(info->idle_mode)
+ {
+ case HDLC_TXIDLE_FLAGS: val = 0x7e; break;
+ case HDLC_TXIDLE_ALT_ZEROS_ONES:
+ case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+ case HDLC_TXIDLE_ZEROS:
+ case HDLC_TXIDLE_SPACE: val = 0x00; break;
+ default: val = 0xff;
+ }
}
wr_reg8(info, TIR, val);
@@ -4313,6 +4344,12 @@ static int rx_get_frame(struct slgt_info *info)
unsigned long flags;
struct tty_struct *tty = info->tty;
unsigned char addr_field = 0xff;
+ unsigned int crc_size = 0;
+
+ switch (info->params.crc_type & HDLC_CRC_MASK) {
+ case HDLC_CRC_16_CCITT: crc_size = 2; break;
+ case HDLC_CRC_32_CCITT: crc_size = 4; break;
+ }
check_again:
@@ -4357,7 +4394,7 @@ check_again:
status = desc_status(info->rbufs[end]);
/* ignore CRC bit if not using CRC (bit is undefined) */
- if (info->params.crc_type == HDLC_CRC_NONE)
+ if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE)
status &= ~BIT1;
if (framesize == 0 ||
@@ -4366,34 +4403,34 @@ check_again:
goto check_again;
}
- if (framesize < 2 || status & (BIT1+BIT0)) {
- if (framesize < 2 || (status & BIT0))
- info->icount.rxshort++;
- else
- info->icount.rxcrc++;
+ if (framesize < (2 + crc_size) || status & BIT0) {
+ info->icount.rxshort++;
framesize = 0;
+ } else if (status & BIT1) {
+ info->icount.rxcrc++;
+ if (!(info->params.crc_type & HDLC_CRC_RETURN_EX))
+ framesize = 0;
+ }
#ifdef CONFIG_HDLC
- {
- struct net_device_stats *stats = hdlc_stats(info->netdev);
- stats->rx_errors++;
- stats->rx_frame_errors++;
- }
-#endif
- } else {
- /* adjust frame size for CRC, if any */
- if (info->params.crc_type == HDLC_CRC_16_CCITT)
- framesize -= 2;
- else if (info->params.crc_type == HDLC_CRC_32_CCITT)
- framesize -= 4;
+ if (framesize == 0) {
+ struct net_device_stats *stats = hdlc_stats(info->netdev);
+ stats->rx_errors++;
+ stats->rx_frame_errors++;
}
+#endif
DBGBH(("%s rx frame status=%04X size=%d\n",
info->device_name, status, framesize));
DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
if (framesize) {
- if (framesize > info->max_frame_size)
+ if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
+ framesize -= crc_size;
+ crc_size = 0;
+ }
+
+ if (framesize > info->max_frame_size + crc_size)
info->icount.rxlong++;
else {
/* copy dma buffer(s) to contiguous temp buffer */
@@ -4413,6 +4450,11 @@ check_again:
i = 0;
}
+ if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
+ *p = (status & BIT1) ? RX_CRC_ERROR : RX_OK;
+ framesize++;
+ }
+
#ifdef CONFIG_HDLC
if (info->netcount)
hdlcdev_rx(info,info->tmp_rbuf, framesize);
@@ -4671,13 +4713,13 @@ static int loopback_test(struct slgt_info *info)
static int adapter_test(struct slgt_info *info)
{
DBGINFO(("testing %s\n", info->device_name));
- if ((info->init_error = register_test(info)) < 0) {
+ if (register_test(info) < 0) {
printk("register test failure %s addr=%08X\n",
info->device_name, info->phys_reg_addr);
- } else if ((info->init_error = irq_test(info)) < 0) {
+ } else if (irq_test(info) < 0) {
printk("IRQ test failure %s IRQ=%d\n",
info->device_name, info->irq_level);
- } else if ((info->init_error = loopback_test(info)) < 0) {
+ } else if (loopback_test(info) < 0) {
printk("loopback test failure %s\n", info->device_name);
}
return info->init_error;
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 85874013111..66f3754fbbd 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -34,7 +34,6 @@
#define MAX_DEVICES 12
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -988,7 +987,7 @@ static int write(struct tty_struct *tty,
if (sanity_check(info, tty->name, "write"))
goto cleanup;
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
goto cleanup;
if (info->params.mode == MGSL_MODE_HDLC) {
@@ -1067,7 +1066,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
if (sanity_check(info, tty->name, "put_char"))
return;
- if (!tty || !info->tx_buf)
+ if (!info->tx_buf)
return;
spin_lock_irqsave(&info->lock,flags);
@@ -1753,8 +1752,10 @@ static int hdlcdev_open(struct net_device *dev)
spin_lock_irqsave(&info->lock, flags);
get_signals(info);
spin_unlock_irqrestore(&info->lock, flags);
- hdlc_set_carrier(info->serial_signals & SerialSignal_DCD, dev);
-
+ if (info->serial_signals & SerialSignal_DCD)
+ netif_carrier_on(dev);
+ else
+ netif_carrier_off(dev);
return 0;
}
@@ -2523,8 +2524,12 @@ void isr_io_pin( SLMP_INFO *info, u16 status )
} else
info->input_signal_events.dcd_down++;
#ifdef CONFIG_HDLC
- if (info->netcount)
- hdlc_set_carrier(status & SerialSignal_DCD, info->netdev);
+ if (info->netcount) {
+ if (status & SerialSignal_DCD)
+ netif_carrier_on(info->netdev);
+ else
+ netif_carrier_off(info->netdev);
+ }
#endif
}
if (status & MISCSTATUS_CTS_LATCHED)
@@ -3836,7 +3841,7 @@ static SLMP_INFO *alloc_dev(int adapter_num, int port_num, struct pci_dev *pdev)
info->phys_statctrl_base &= ~(PAGE_SIZE-1);
info->bus_type = MGSL_BUS_TYPE_PCI;
- info->irq_flags = SA_SHIRQ;
+ info->irq_flags = IRQF_SHARED;
init_timer(&info->tx_timer);
info->tx_timer.data = (unsigned long)info;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 35082dc12ea..0ad6cb081db 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -12,7 +12,6 @@
* based upon discusions in irc://irc.openprojects.net/#kernelnewbies
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
@@ -148,12 +147,13 @@ static struct sysrq_key_op sysrq_mountro_op = {
.enable_mask = SYSRQ_ENABLE_REMOUNT,
};
-#ifdef CONFIG_DEBUG_MUTEXES
+#ifdef CONFIG_LOCKDEP
static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs,
struct tty_struct *tty)
{
- mutex_debug_show_all_locks();
+ debug_show_all_locks();
}
+
static struct sysrq_key_op sysrq_showlocks_op = {
.handler = sysrq_handle_showlocks,
.help_msg = "show-all-locks(D)",
@@ -208,7 +208,7 @@ static void send_sig_all(int sig)
struct task_struct *p;
for_each_process(p) {
- if (p->mm && p->pid != 1)
+ if (p->mm && !is_init(p))
/* Not swapper, init nor kernel thread */
force_sig(sig, p);
}
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index a80c8321087..bb1bad4c18f 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -255,7 +255,7 @@ static int tanbac_tb0219_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations tb0219_fops = {
+static const struct file_operations tb0219_fops = {
.owner = THIS_MODULE,
.read = tanbac_tb0219_read,
.write = tanbac_tb0219_write,
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 079db5a935a..d30dc09dbbc 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -42,7 +42,6 @@
*/
#undef DEBUG /* change to #define to get debugging
* output - for pr_debug() */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -56,7 +55,6 @@
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/bitops.h>
-#include <linux/devfs_fs_kernel.h> /* DevFs support */
#include <linux/parport.h> /* Our code depend on parport */
#include <linux/device.h>
@@ -383,7 +381,7 @@ tipar_ioctl(struct inode *inode, struct file *file,
/* ----- kernel module registering ------------------------------------ */
-static struct file_operations tipar_fops = {
+static const struct file_operations tipar_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = tipar_read,
@@ -443,12 +441,6 @@ tipar_register(int nr, struct parport *port)
class_device_create(tipar_class, NULL, MKDEV(TIPAR_MAJOR,
TIPAR_MINOR + nr), NULL, "par%d", nr);
- /* Use devfs, tree: /dev/ticables/par/[0..2] */
- err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
- S_IFCHR | S_IRUGO | S_IWUGO,
- "ticables/par/%d", nr);
- if (err)
- goto out_class;
/* Display informations */
pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq ==
@@ -460,11 +452,7 @@ tipar_register(int nr, struct parport *port)
pr_info("tipar%d: link cable not found\n", nr);
err = 0;
- goto out;
-out_class:
- class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr));
- class_destroy(tipar_class);
out:
return err;
}
@@ -507,9 +495,6 @@ tipar_init_module(void)
goto out;
}
- /* Use devfs with tree: /dev/ticables/par/[0..2] */
- devfs_mk_dir("ticables/par");
-
tipar_class = class_create(THIS_MODULE, "ticables");
if (IS_ERR(tipar_class)) {
err = PTR_ERR(tipar_class);
@@ -528,7 +513,6 @@ out_class:
class_destroy(tipar_class);
out_chrdev:
- devfs_remove("ticables/par");
unregister_chrdev(TIPAR_MAJOR, "tipar");
out:
return err;
@@ -549,10 +533,8 @@ tipar_cleanup_module(void)
continue;
parport_unregister_device(table[i].dev);
class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i));
- devfs_remove("ticables/par/%d", i);
}
class_destroy(tipar_class);
- devfs_remove("ticables/par");
pr_info("tipar: module unloaded\n");
}
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index f58ad7f6826..d2c5ba4e83b 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -27,7 +27,6 @@
* MPCBL0010 ATCA computer.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
@@ -209,7 +208,7 @@ static int tlclk_open(struct inode *inode, struct file *filp)
/* This device is wired through the FPGA IO space of the ATCA blade
* we can't share this IRQ */
result = request_irq(telclk_interrupt, &tlclk_interrupt,
- SA_INTERRUPT, "telco_clock", tlclk_interrupt);
+ IRQF_DISABLED, "telco_clock", tlclk_interrupt);
if (result == -EBUSY) {
printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n");
return -EBUSY;
@@ -248,7 +247,7 @@ static ssize_t tlclk_write(struct file *filp, const char __user *buf, size_t cou
return 0;
}
-static struct file_operations tlclk_fops = {
+static const struct file_operations tlclk_fops = {
.read = tlclk_read,
.write = tlclk_write,
.open = tlclk_open,
@@ -343,7 +342,7 @@ static ssize_t store_received_ref_clk3b(struct device *d,
val = (unsigned char)tmp;
spin_lock_irqsave(&event_lock, flags);
- SET_PORT_BITS(TLCLK_REG1, 0xef, val << 1);
+ SET_PORT_BITS(TLCLK_REG1, 0xdf, val << 1);
spin_unlock_irqrestore(&event_lock, flags);
return strnlen(buf, count);
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index e2fb234dee4..dd36fd04a84 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -92,7 +92,7 @@ static int tosh_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
-static struct file_operations tosh_fops = {
+static const struct file_operations tosh_fops = {
.owner = THIS_MODULE,
.ioctl = tosh_ioctl,
};
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 6889e7db3af..a082a2e3425 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1141,6 +1141,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
put_device(dev);
clear_bit(chip->dev_num, dev_mask);
kfree(chip);
+ kfree(devname);
return NULL;
}
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 58a258cec15..ad8ffe49256 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -116,7 +116,7 @@ static u8 tpm_atml_status(struct tpm_chip *chip)
return ioread8(chip->vendor.iobase + 1);
}
-static struct file_operations atmel_ops = {
+static const struct file_operations atmel_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
diff --git a/drivers/char/tpm/tpm_atmel.h b/drivers/char/tpm/tpm_atmel.h
index 2e68eeb8a2c..aefd683c60b 100644
--- a/drivers/char/tpm/tpm_atmel.h
+++ b/drivers/char/tpm/tpm_atmel.h
@@ -37,7 +37,7 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
{
struct device_node *dn;
unsigned long address, size;
- unsigned int *reg;
+ const unsigned int *reg;
int reglen;
int naddrc;
int nsizec;
@@ -52,7 +52,7 @@ static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
return NULL;
}
- reg = (unsigned int *) get_property(dn, "reg", &reglen);
+ reg = get_property(dn, "reg", &reglen);
naddrc = prom_n_addr_cells(dn);
nsizec = prom_n_size_cells(dn);
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index adfff21beb2..1353b5a6bae 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -338,7 +338,7 @@ static struct attribute *inf_attrs[] = {
static struct attribute_group inf_attr_grp = {.attrs = inf_attrs };
-static struct file_operations inf_ops = {
+static const struct file_operations inf_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 4c8bc06c7d9..26287aace87 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -226,7 +226,7 @@ static u8 tpm_nsc_status(struct tpm_chip *chip)
return inb(chip->vendor.base + NSC_STATUS);
}
-static struct file_operations nsc_ops = {
+static const struct file_operations nsc_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 8ea70625f7e..ee7ac6f43c6 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -330,7 +330,7 @@ out_err:
return rc;
}
-static struct file_operations tis_ops = {
+static const struct file_operations tis_ops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
@@ -424,6 +424,7 @@ static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
iowrite32(interrupt,
chip->vendor.iobase +
TPM_INT_STATUS(chip->vendor.locality));
+ ioread32(chip->vendor.iobase + TPM_INT_STATUS(chip->vendor.locality));
return IRQ_HANDLED;
}
@@ -431,23 +432,19 @@ static int interrupts = 1;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
-static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
- const struct pnp_device_id *pnp_id)
+static int tpm_tis_init(struct device *dev, resource_size_t start,
+ resource_size_t len)
{
u32 vendor, intfcaps, intmask;
int rc, i;
- unsigned long start, len;
struct tpm_chip *chip;
- start = pnp_mem_start(pnp_dev, 0);
- len = pnp_mem_len(pnp_dev, 0);
-
if (!start)
start = TIS_MEM_BASE;
if (!len)
len = TIS_MEM_LEN;
- if (!(chip = tpm_register_hardware(&pnp_dev->dev, &tpm_tis)))
+ if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
return -ENODEV;
chip->vendor.iobase = ioremap(start, len);
@@ -464,7 +461,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- dev_info(&pnp_dev->dev,
+ dev_info(dev,
"1.2 TPM (device-id 0x%X, rev-id %d)\n",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
@@ -472,26 +469,26 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
intfcaps =
ioread32(chip->vendor.iobase +
TPM_INTF_CAPS(chip->vendor.locality));
- dev_dbg(&pnp_dev->dev, "TPM interface capabilities (0x%x):\n",
+ dev_dbg(dev, "TPM interface capabilities (0x%x):\n",
intfcaps);
if (intfcaps & TPM_INTF_BURST_COUNT_STATIC)
- dev_dbg(&pnp_dev->dev, "\tBurst Count Static\n");
+ dev_dbg(dev, "\tBurst Count Static\n");
if (intfcaps & TPM_INTF_CMD_READY_INT)
- dev_dbg(&pnp_dev->dev, "\tCommand Ready Int Support\n");
+ dev_dbg(dev, "\tCommand Ready Int Support\n");
if (intfcaps & TPM_INTF_INT_EDGE_FALLING)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Falling\n");
+ dev_dbg(dev, "\tInterrupt Edge Falling\n");
if (intfcaps & TPM_INTF_INT_EDGE_RISING)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Edge Rising\n");
+ dev_dbg(dev, "\tInterrupt Edge Rising\n");
if (intfcaps & TPM_INTF_INT_LEVEL_LOW)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Level Low\n");
+ dev_dbg(dev, "\tInterrupt Level Low\n");
if (intfcaps & TPM_INTF_INT_LEVEL_HIGH)
- dev_dbg(&pnp_dev->dev, "\tInterrupt Level High\n");
+ dev_dbg(dev, "\tInterrupt Level High\n");
if (intfcaps & TPM_INTF_LOCALITY_CHANGE_INT)
- dev_dbg(&pnp_dev->dev, "\tLocality Change Int Support\n");
+ dev_dbg(dev, "\tLocality Change Int Support\n");
if (intfcaps & TPM_INTF_STS_VALID_INT)
- dev_dbg(&pnp_dev->dev, "\tSts Valid Int Support\n");
+ dev_dbg(dev, "\tSts Valid Int Support\n");
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
- dev_dbg(&pnp_dev->dev, "\tData Avail Int Support\n");
+ dev_dbg(dev, "\tData Avail Int Support\n");
if (request_locality(chip, 0) != 0) {
rc = -ENODEV;
@@ -522,7 +519,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
iowrite8(i, chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
if (request_irq
- (i, tis_int_probe, SA_SHIRQ,
+ (i, tis_int_probe, IRQF_SHARED,
chip->vendor.miscdev.name, chip) != 0) {
dev_info(chip->dev,
"Unable to request irq: %d for probe\n",
@@ -557,7 +554,7 @@ static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
if (request_irq
- (chip->vendor.irq, tis_int_handler, SA_SHIRQ,
+ (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
chip->vendor.miscdev.name, chip) != 0) {
dev_info(chip->dev,
"Unable to request irq: %d for use\n",
@@ -594,6 +591,16 @@ out_err:
return rc;
}
+static int __devinit tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
+ const struct pnp_device_id *pnp_id)
+{
+ resource_size_t start, len;
+ start = pnp_mem_start(pnp_dev, 0);
+ len = pnp_mem_len(pnp_dev, 0);
+
+ return tpm_tis_init(&pnp_dev->dev, start, len);
+}
+
static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
{
return tpm_pm_suspend(&dev->dev, msg);
@@ -628,8 +635,36 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
sizeof(tpm_pnp_tbl[TIS_HID_USR_IDX].id), 0444);
MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
+static struct device_driver tis_drv = {
+ .name = "tpm_tis",
+ .bus = &platform_bus_type,
+ .owner = THIS_MODULE,
+ .suspend = tpm_pm_suspend,
+ .resume = tpm_pm_resume,
+};
+
+static struct platform_device *pdev;
+
+static int force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force device probe rather than using ACPI entry");
static int __init init_tis(void)
{
+ int rc;
+
+ if (force) {
+ rc = driver_register(&tis_drv);
+ if (rc < 0)
+ return rc;
+ if (IS_ERR(pdev=platform_device_register_simple("tpm_tis", -1, NULL, 0)))
+ return PTR_ERR(pdev);
+ if((rc=tpm_tis_init(&pdev->dev, 0, 0)) != 0) {
+ platform_device_unregister(pdev);
+ driver_unregister(&tis_drv);
+ }
+ return rc;
+ }
+
return pnp_register_driver(&tis_pnp_driver);
}
@@ -654,7 +689,11 @@ static void __exit cleanup_tis(void)
tpm_remove_hardware(chip->dev);
}
spin_unlock(&tis_lock);
- pnp_unregister_driver(&tis_pnp_driver);
+ if (force) {
+ platform_device_unregister(pdev);
+ driver_unregister(&tis_drv);
+ } else
+ pnp_unregister_driver(&tis_pnp_driver);
}
module_init(init_tis);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 8b2a5996986..333741770f1 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -65,7 +65,6 @@
* alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/major.h>
#include <linux/errno.h>
@@ -102,7 +101,6 @@
#include <linux/kbd_kern.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/kmod.h>
@@ -131,6 +129,7 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
/* Semaphore to protect creating and releasing a tty. This is shared with
vt.c for deeply disgusting hack reasons */
DEFINE_MUTEX(tty_mutex);
+EXPORT_SYMBOL(tty_mutex);
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
@@ -155,19 +154,31 @@ int tty_ioctl(struct inode * inode, struct file * file,
static int tty_fasync(int fd, struct file * filp, int on);
static void release_mem(struct tty_struct *tty, int idx);
+/**
+ * alloc_tty_struct - allocate a tty object
+ *
+ * Return a new empty tty structure. The data fields have not
+ * been initialized in any way but has been zeroed
+ *
+ * Locking: none
+ */
static struct tty_struct *alloc_tty_struct(void)
{
- struct tty_struct *tty;
-
- tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
- if (tty)
- memset(tty, 0, sizeof(struct tty_struct));
- return tty;
+ return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
}
static void tty_buffer_free_all(struct tty_struct *);
+/**
+ * free_tty_struct - free a disused tty
+ * @tty: tty struct to free
+ *
+ * Free the write buffers, tty queue and tty memory itself.
+ *
+ * Locking: none. Must be called after tty is definitely unused
+ */
+
static inline void free_tty_struct(struct tty_struct *tty)
{
kfree(tty->write_buf);
@@ -177,6 +188,17 @@ static inline void free_tty_struct(struct tty_struct *tty)
#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
+/**
+ * tty_name - return tty naming
+ * @tty: tty structure
+ * @buf: buffer for output
+ *
+ * Convert a tty structure into a name. The name reflects the kernel
+ * naming policy and if udev is in use may not reflect user space
+ *
+ * Locking: none
+ */
+
char *tty_name(struct tty_struct *tty, char *buf)
{
if (!tty) /* Hmm. NULL pointer. That's fun. */
@@ -237,6 +259,28 @@ static int check_tty_count(struct tty_struct *tty, const char *routine)
* Tty buffer allocation management
*/
+
+/**
+ * tty_buffer_free_all - free buffers used by a tty
+ * @tty: tty to free from
+ *
+ * Remove all the buffers pending on a tty whether queued with data
+ * or in the free ring. Must be called when the tty is no longer in use
+ *
+ * Locking: none
+ */
+
+
+/**
+ * tty_buffer_free_all - free buffers used by a tty
+ * @tty: tty to free from
+ *
+ * Remove all the buffers pending on a tty whether queued with data
+ * or in the free ring. Must be called when the tty is no longer in use
+ *
+ * Locking: none
+ */
+
static void tty_buffer_free_all(struct tty_struct *tty)
{
struct tty_buffer *thead;
@@ -249,40 +293,77 @@ static void tty_buffer_free_all(struct tty_struct *tty)
kfree(thead);
}
tty->buf.tail = NULL;
+ tty->buf.memory_used = 0;
}
+/**
+ * tty_buffer_init - prepare a tty buffer structure
+ * @tty: tty to initialise
+ *
+ * Set up the initial state of the buffer management for a tty device.
+ * Must be called before the other tty buffer functions are used.
+ *
+ * Locking: none
+ */
+
static void tty_buffer_init(struct tty_struct *tty)
{
spin_lock_init(&tty->buf.lock);
tty->buf.head = NULL;
tty->buf.tail = NULL;
tty->buf.free = NULL;
+ tty->buf.memory_used = 0;
}
-static struct tty_buffer *tty_buffer_alloc(size_t size)
+/**
+ * tty_buffer_alloc - allocate a tty buffer
+ * @tty: tty device
+ * @size: desired size (characters)
+ *
+ * Allocate a new tty buffer to hold the desired number of characters.
+ * Return NULL if out of memory or the allocation would exceed the
+ * per device queue
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
+
+static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size)
{
- struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
+ struct tty_buffer *p;
+
+ if (tty->buf.memory_used + size > 65536)
+ return NULL;
+ p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
if(p == NULL)
return NULL;
p->used = 0;
p->size = size;
p->next = NULL;
- p->active = 0;
p->commit = 0;
p->read = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
-/* printk("Flip create %p\n", p); */
+ tty->buf.memory_used += size;
return p;
}
-/* Must be called with the tty_read lock held. This needs to acquire strategy
- code to decide if we should kfree or relink a given expired buffer */
+/**
+ * tty_buffer_free - free a tty buffer
+ * @tty: tty owning the buffer
+ * @b: the buffer to free
+ *
+ * Free a tty buffer, or add it to the free list according to our
+ * internal strategy
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
{
/* Dumb strategy for now - should keep some stats */
-/* printk("Flip dispose %p\n", b); */
+ tty->buf.memory_used -= b->size;
+ WARN_ON(tty->buf.memory_used < 0);
+
if(b->size >= 512)
kfree(b);
else {
@@ -291,6 +372,18 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
}
}
+/**
+ * tty_buffer_find - find a free tty buffer
+ * @tty: tty owning the buffer
+ * @size: characters wanted
+ *
+ * Locate an existing suitable tty buffer or if we are lacking one then
+ * allocate a new one. We round our buffers off in 256 character chunks
+ * to get better allocation behaviour.
+ *
+ * Locking: Caller must hold tty->buf.lock
+ */
+
static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
{
struct tty_buffer **tbh = &tty->buf.free;
@@ -302,20 +395,28 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
t->used = 0;
t->commit = 0;
t->read = 0;
- /* DEBUG ONLY */
-/* memset(t->data, '*', size); */
-/* printk("Flip recycle %p\n", t); */
+ tty->buf.memory_used += t->size;
return t;
}
tbh = &((*tbh)->next);
}
/* Round the buffer size out */
size = (size + 0xFF) & ~ 0xFF;
- return tty_buffer_alloc(size);
+ return tty_buffer_alloc(tty, size);
/* Should possibly check if this fails for the largest buffer we
have queued and recycle that ? */
}
+/**
+ * tty_buffer_request_room - grow tty buffer if needed
+ * @tty: tty structure
+ * @size: size desired
+ *
+ * Make at least size bytes of linear space available for the tty
+ * buffer. If we fail return the size we managed to find.
+ *
+ * Locking: Takes tty->buf.lock
+ */
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
struct tty_buffer *b, *n;
@@ -327,10 +428,9 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
- if ((b = tty->buf.tail) != NULL) {
+ if ((b = tty->buf.tail) != NULL)
left = b->size - b->used;
- b->active = 1;
- } else
+ else
left = 0;
if (left < size) {
@@ -338,12 +438,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
if ((n = tty_buffer_find(tty, size)) != NULL) {
if (b != NULL) {
b->next = n;
- b->active = 0;
b->commit = b->used;
} else
tty->buf.head = n;
tty->buf.tail = n;
- n->active = 1;
} else
size = left;
}
@@ -353,6 +451,18 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
}
EXPORT_SYMBOL_GPL(tty_buffer_request_room);
+/**
+ * tty_insert_flip_string - Add characters to the tty buffer
+ * @tty: tty structure
+ * @chars: characters
+ * @size: size
+ *
+ * Queue a series of bytes to the tty buffering. All the characters
+ * passed are marked as without error. Returns the number added.
+ *
+ * Locking: Called functions may take tty->buf.lock
+ */
+
int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
size_t size)
{
@@ -368,14 +478,27 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
tb->used += space;
copied += space;
chars += space;
- }
- /* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
- while (unlikely(size > copied));
+ /* There is a small chance that we need to split the data over
+ several buffers. If this is the case we must loop */
+ } while (unlikely(size > copied));
return copied;
}
EXPORT_SYMBOL(tty_insert_flip_string);
+/**
+ * tty_insert_flip_string_flags - Add characters to the tty buffer
+ * @tty: tty structure
+ * @chars: characters
+ * @flags: flag bytes
+ * @size: size
+ *
+ * Queue a series of bytes to the tty buffering. For each character
+ * the flags array indicates the status of the character. Returns the
+ * number added.
+ *
+ * Locking: Called functions may take tty->buf.lock
+ */
+
int tty_insert_flip_string_flags(struct tty_struct *tty,
const unsigned char *chars, const char *flags, size_t size)
{
@@ -392,33 +515,48 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
copied += space;
chars += space;
flags += space;
- }
- /* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
- while (unlikely(size > copied));
+ /* There is a small chance that we need to split the data over
+ several buffers. If this is the case we must loop */
+ } while (unlikely(size > copied));
return copied;
}
EXPORT_SYMBOL(tty_insert_flip_string_flags);
+/**
+ * tty_schedule_flip - push characters to ldisc
+ * @tty: tty to push from
+ *
+ * Takes any pending buffers and transfers their ownership to the
+ * ldisc side of the queue. It then schedules those characters for
+ * processing by the line discipline.
+ *
+ * Locking: Takes tty->buf.lock
+ */
+
void tty_schedule_flip(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL) {
- tty->buf.tail->active = 0;
+ if (tty->buf.tail != NULL)
tty->buf.tail->commit = tty->buf.tail->used;
- }
spin_unlock_irqrestore(&tty->buf.lock, flags);
schedule_delayed_work(&tty->buf.work, 1);
}
EXPORT_SYMBOL(tty_schedule_flip);
-/*
+/**
+ * tty_prepare_flip_string - make room for characters
+ * @tty: tty
+ * @chars: return pointer for character write area
+ * @size: desired size
+ *
* Prepare a block of space in the buffer for data. Returns the length
* available and buffer pointer to the space which is now allocated and
* accounted for as ready for normal characters. This is used for drivers
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
+ *
+ * Locking: May call functions taking tty->buf.lock
*/
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
@@ -435,12 +573,20 @@ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_
EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
-/*
+/**
+ * tty_prepare_flip_string_flags - make room for characters
+ * @tty: tty
+ * @chars: return pointer for character write area
+ * @flags: return pointer for status flag write area
+ * @size: desired size
+ *
* Prepare a block of space in the buffer for data. Returns the length
* available and buffer pointer to the space which is now allocated and
* accounted for as ready for characters. This is used for drivers
* that need their own block copy routines into the buffer. There is no
* guarantee the buffer is a DMA target!
+ *
+ * Locking: May call functions taking tty->buf.lock
*/
int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
@@ -459,17 +605,23 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
-/*
+/**
+ * tty_set_termios_ldisc - set ldisc field
+ * @tty: tty structure
+ * @num: line discipline number
+ *
* This is probably overkill for real world processors but
* they are not on hot paths so a little discipline won't do
* any harm.
+ *
+ * Locking: takes termios_sem
*/
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
{
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_line = num;
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
}
/*
@@ -482,6 +634,19 @@ static DEFINE_SPINLOCK(tty_ldisc_lock);
static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */
+/**
+ * tty_register_ldisc - install a line discipline
+ * @disc: ldisc number
+ * @new_ldisc: pointer to the ldisc object
+ *
+ * Installs a new line discipline into the kernel. The discipline
+ * is set up as unreferenced and then made available to the kernel
+ * from this point onwards.
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
{
unsigned long flags;
@@ -501,6 +666,18 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
}
EXPORT_SYMBOL(tty_register_ldisc);
+/**
+ * tty_unregister_ldisc - unload a line discipline
+ * @disc: ldisc number
+ * @new_ldisc: pointer to the ldisc object
+ *
+ * Remove a line discipline from the kernel providing it is not
+ * currently in use.
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
int tty_unregister_ldisc(int disc)
{
unsigned long flags;
@@ -520,6 +697,19 @@ int tty_unregister_ldisc(int disc)
}
EXPORT_SYMBOL(tty_unregister_ldisc);
+/**
+ * tty_ldisc_get - take a reference to an ldisc
+ * @disc: ldisc number
+ *
+ * Takes a reference to a line discipline. Deals with refcounts and
+ * module locking counts. Returns NULL if the discipline is not available.
+ * Returns a pointer to the discipline and bumps the ref count if it is
+ * available
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
struct tty_ldisc *tty_ldisc_get(int disc)
{
unsigned long flags;
@@ -548,6 +738,17 @@ struct tty_ldisc *tty_ldisc_get(int disc)
EXPORT_SYMBOL_GPL(tty_ldisc_get);
+/**
+ * tty_ldisc_put - drop ldisc reference
+ * @disc: ldisc number
+ *
+ * Drop a reference to a line discipline. Manage refcounts and
+ * module usage counts
+ *
+ * Locking:
+ * takes tty_ldisc_lock to guard against ldisc races
+ */
+
void tty_ldisc_put(int disc)
{
struct tty_ldisc *ld;
@@ -565,6 +766,19 @@ void tty_ldisc_put(int disc)
EXPORT_SYMBOL_GPL(tty_ldisc_put);
+/**
+ * tty_ldisc_assign - set ldisc on a tty
+ * @tty: tty to assign
+ * @ld: line discipline
+ *
+ * Install an instance of a line discipline into a tty structure. The
+ * ldisc must have a reference count above zero to ensure it remains/
+ * The tty instance refcount starts at zero.
+ *
+ * Locking:
+ * Caller must hold references
+ */
+
static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
{
tty->ldisc = *ld;
@@ -579,6 +793,8 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
* the tty ldisc. Return 0 on failure or 1 on success. This is
* used to implement both the waiting and non waiting versions
* of tty_ldisc_ref
+ *
+ * Locking: takes tty_ldisc_lock
*/
static int tty_ldisc_try(struct tty_struct *tty)
@@ -610,6 +826,8 @@ static int tty_ldisc_try(struct tty_struct *tty)
* must also be careful not to hold other locks that will deadlock
* against a discipline change, such as an existing ldisc reference
* (which we check for)
+ *
+ * Locking: call functions take tty_ldisc_lock
*/
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
@@ -630,6 +848,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
* Dereference the line discipline for the terminal and take a
* reference to it. If the line discipline is in flux then
* return NULL. Can be called from IRQ and timer functions.
+ *
+ * Locking: called functions take tty_ldisc_lock
*/
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
@@ -647,6 +867,8 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
*
* Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
* be called in IRQ context.
+ *
+ * Locking: takes tty_ldisc_lock
*/
void tty_ldisc_deref(struct tty_ldisc *ld)
@@ -691,6 +913,9 @@ static void tty_ldisc_enable(struct tty_struct *tty)
*
* Set the discipline of a tty line. Must be called from a process
* context.
+ *
+ * Locking: takes tty_ldisc_lock.
+ * called functions take termios_sem
*/
static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
@@ -784,11 +1009,8 @@ restart:
}
clear_bit(TTY_LDISC, &tty->flags);
- clear_bit(TTY_DONT_FLIP, &tty->flags);
- if (o_tty) {
+ if (o_tty)
clear_bit(TTY_LDISC, &o_tty->flags);
- clear_bit(TTY_DONT_FLIP, &o_tty->flags);
- }
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
/*
@@ -857,9 +1079,17 @@ restart:
return retval;
}
-/*
- * This routine returns a tty driver structure, given a device number
+/**
+ * get_tty_driver - find device of a tty
+ * @dev_t: device identifier
+ * @index: returns the index of the tty
+ *
+ * This routine returns a tty driver structure, given a device number
+ * and also passes back the index number.
+ *
+ * Locking: caller must hold tty_mutex
*/
+
static struct tty_driver *get_tty_driver(dev_t device, int *index)
{
struct tty_driver *p;
@@ -874,11 +1104,17 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
return NULL;
}
-/*
- * If we try to write to, or set the state of, a terminal and we're
- * not in the foreground, send a SIGTTOU. If the signal is blocked or
- * ignored, go ahead and perform the operation. (POSIX 7.2)
+/**
+ * tty_check_change - check for POSIX terminal changes
+ * @tty: tty to check
+ *
+ * If we try to write to, or set the state of, a terminal and we're
+ * not in the foreground, send a SIGTTOU. If the signal is blocked or
+ * ignored, go ahead and perform the operation. (POSIX 7.2)
+ *
+ * Locking: none
*/
+
int tty_check_change(struct tty_struct * tty)
{
if (current->signal->tty != tty)
@@ -923,7 +1159,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
-static struct file_operations tty_fops = {
+static const struct file_operations tty_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
@@ -935,7 +1171,7 @@ static struct file_operations tty_fops = {
};
#ifdef CONFIG_UNIX98_PTYS
-static struct file_operations ptmx_fops = {
+static const struct file_operations ptmx_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = tty_write,
@@ -947,7 +1183,7 @@ static struct file_operations ptmx_fops = {
};
#endif
-static struct file_operations console_fops = {
+static const struct file_operations console_fops = {
.llseek = no_llseek,
.read = tty_read,
.write = redirected_tty_write,
@@ -958,7 +1194,7 @@ static struct file_operations console_fops = {
.fasync = tty_fasync,
};
-static struct file_operations hung_up_tty_fops = {
+static const struct file_operations hung_up_tty_fops = {
.llseek = no_llseek,
.read = hung_up_tty_read,
.write = hung_up_tty_write,
@@ -1016,10 +1252,27 @@ void tty_ldisc_flush(struct tty_struct *tty)
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
-/*
- * This can be called by the "eventd" kernel thread. That is process synchronous,
- * but doesn't hold any locks, so we need to make sure we have the appropriate
- * locks for what we're doing..
+/**
+ * do_tty_hangup - actual handler for hangup events
+ * @data: tty device
+ *
+ * This can be called by the "eventd" kernel thread. That is process
+ * synchronous but doesn't hold any locks, so we need to make sure we
+ * have the appropriate locks for what we're doing.
+ *
+ * The hangup event clears any pending redirections onto the hung up
+ * device. It ensures future writes will error and it does the needed
+ * line discipline hangup and signal delivery. The tty object itself
+ * remains intact.
+ *
+ * Locking:
+ * BKL
+ * redirect lock for undoing redirection
+ * file list lock for manipulating list of ttys
+ * tty_ldisc_lock from called functions
+ * termios_sem resetting termios data
+ * tasklist_lock to walk task list for hangup event
+ *
*/
static void do_tty_hangup(void *data)
{
@@ -1086,9 +1339,9 @@ static void do_tty_hangup(void *data)
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
{
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
*tty->termios = tty->driver->init_termios;
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
}
/* Defer ldisc switch */
@@ -1144,6 +1397,14 @@ static void do_tty_hangup(void *data)
fput(f);
}
+/**
+ * tty_hangup - trigger a hangup event
+ * @tty: tty to hangup
+ *
+ * A carrier loss (virtual or otherwise) has occurred on this like
+ * schedule a hangup sequence to run after this event.
+ */
+
void tty_hangup(struct tty_struct * tty)
{
#ifdef TTY_DEBUG_HANGUP
@@ -1156,6 +1417,15 @@ void tty_hangup(struct tty_struct * tty)
EXPORT_SYMBOL(tty_hangup);
+/**
+ * tty_vhangup - process vhangup
+ * @tty: tty to hangup
+ *
+ * The user has asked via system call for the terminal to be hung up.
+ * We do this synchronously so that when the syscall returns the process
+ * is complete. That guarantee is neccessary for security reasons.
+ */
+
void tty_vhangup(struct tty_struct * tty)
{
#ifdef TTY_DEBUG_HANGUP
@@ -1167,6 +1437,14 @@ void tty_vhangup(struct tty_struct * tty)
}
EXPORT_SYMBOL(tty_vhangup);
+/**
+ * tty_hung_up_p - was tty hung up
+ * @filp: file pointer of tty
+ *
+ * Return true if the tty has been subject to a vhangup or a carrier
+ * loss
+ */
+
int tty_hung_up_p(struct file * filp)
{
return (filp->f_op == &hung_up_tty_fops);
@@ -1174,19 +1452,28 @@ int tty_hung_up_p(struct file * filp)
EXPORT_SYMBOL(tty_hung_up_p);
-/*
- * This function is typically called only by the session leader, when
- * it wants to disassociate itself from its controlling tty.
+/**
+ * disassociate_ctty - disconnect controlling tty
+ * @on_exit: true if exiting so need to "hang up" the session
*
- * It performs the following functions:
+ * This function is typically called only by the session leader, when
+ * it wants to disassociate itself from its controlling tty.
+ *
+ * It performs the following functions:
* (1) Sends a SIGHUP and SIGCONT to the foreground process group
* (2) Clears the tty from being controlling the session
* (3) Clears the controlling tty for all processes in the
* session group.
*
- * The argument on_exit is set to 1 if called when a process is
- * exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ * The argument on_exit is set to 1 if called when a process is
+ * exiting; it is 0 if called by the ioctl TIOCNOTTY.
+ *
+ * Locking: tty_mutex is taken to protect current->signal->tty
+ * BKL is taken for hysterical raisins
+ * Tasklist lock is taken (under tty_mutex) to walk process
+ * lists for the session.
*/
+
void disassociate_ctty(int on_exit)
{
struct tty_struct *tty;
@@ -1233,6 +1520,25 @@ void disassociate_ctty(int on_exit)
unlock_kernel();
}
+
+/**
+ * stop_tty - propogate flow control
+ * @tty: tty to stop
+ *
+ * Perform flow control to the driver. For PTY/TTY pairs we
+ * must also propogate the TIOCKPKT status. May be called
+ * on an already stopped device and will not re-call the driver
+ * method.
+ *
+ * This functionality is used by both the line disciplines for
+ * halting incoming flow and by the driver. It may therefore be
+ * called from any context, may be under the tty atomic_write_lock
+ * but not always.
+ *
+ * Locking:
+ * Broken. Relies on BKL which is unsafe here.
+ */
+
void stop_tty(struct tty_struct *tty)
{
if (tty->stopped)
@@ -1249,6 +1555,19 @@ void stop_tty(struct tty_struct *tty)
EXPORT_SYMBOL(stop_tty);
+/**
+ * start_tty - propogate flow control
+ * @tty: tty to start
+ *
+ * Start a tty that has been stopped if at all possible. Perform
+ * any neccessary wakeups and propogate the TIOCPKT status. If this
+ * is the tty was previous stopped and is being started then the
+ * driver start method is invoked and the line discipline woken.
+ *
+ * Locking:
+ * Broken. Relies on BKL which is unsafe here.
+ */
+
void start_tty(struct tty_struct *tty)
{
if (!tty->stopped || tty->flow_stopped)
@@ -1269,6 +1588,23 @@ void start_tty(struct tty_struct *tty)
EXPORT_SYMBOL(start_tty);
+/**
+ * tty_read - read method for tty device files
+ * @file: pointer to tty file
+ * @buf: user buffer
+ * @count: size of user buffer
+ * @ppos: unused
+ *
+ * Perform the read system call function on this terminal device. Checks
+ * for hung up devices before calling the line discipline method.
+ *
+ * Locking:
+ * Locks the line discipline internally while needed
+ * For historical reasons the line discipline read method is
+ * invoked under the BKL. This will go away in time so do not rely on it
+ * in new code. Multiple read calls may be outstanding in parallel.
+ */
+
static ssize_t tty_read(struct file * file, char __user * buf, size_t count,
loff_t *ppos)
{
@@ -1313,6 +1649,7 @@ static inline ssize_t do_tty_write(
ssize_t ret = 0, written = 0;
unsigned int chunk;
+ /* FIXME: O_NDELAY ... */
if (mutex_lock_interruptible(&tty->atomic_write_lock)) {
return -ERESTARTSYS;
}
@@ -1329,6 +1666,9 @@ static inline ssize_t do_tty_write(
* layer has problems with bigger chunks. It will
* claim to be able to handle more characters than
* it actually does.
+ *
+ * FIXME: This can probably go away now except that 64K chunks
+ * are too likely to fail unless switched to vmalloc...
*/
chunk = 2048;
if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
@@ -1386,6 +1726,24 @@ static inline ssize_t do_tty_write(
}
+/**
+ * tty_write - write method for tty device file
+ * @file: tty file pointer
+ * @buf: user data to write
+ * @count: bytes to write
+ * @ppos: unused
+ *
+ * Write data to a tty device via the line discipline.
+ *
+ * Locking:
+ * Locks the line discipline as required
+ * Writes to the tty driver are serialized by the atomic_write_lock
+ * and are then processed in chunks to the device. The line discipline
+ * write method will not be involked in parallel for each device
+ * The line discipline write method is called under the big
+ * kernel lock for historical reasons. New code should not rely on this.
+ */
+
static ssize_t tty_write(struct file * file, const char __user * buf, size_t count,
loff_t *ppos)
{
@@ -1433,7 +1791,18 @@ ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t
static char ptychar[] = "pqrstuvwxyzabcde";
-static inline void pty_line_name(struct tty_driver *driver, int index, char *p)
+/**
+ * pty_line_name - generate name for a pty
+ * @driver: the tty driver in use
+ * @index: the minor number
+ * @p: output buffer of at least 6 bytes
+ *
+ * Generate a name from a driver reference and write it to the output
+ * buffer.
+ *
+ * Locking: None
+ */
+static void pty_line_name(struct tty_driver *driver, int index, char *p)
{
int i = index + driver->name_base;
/* ->name is initialized to "ttyp", but "tty" is expected */
@@ -1442,24 +1811,53 @@ static inline void pty_line_name(struct tty_driver *driver, int index, char *p)
ptychar[i >> 4 & 0xf], i & 0xf);
}
-static inline void tty_line_name(struct tty_driver *driver, int index, char *p)
+/**
+ * pty_line_name - generate name for a tty
+ * @driver: the tty driver in use
+ * @index: the minor number
+ * @p: output buffer of at least 7 bytes
+ *
+ * Generate a name from a driver reference and write it to the output
+ * buffer.
+ *
+ * Locking: None
+ */
+static void tty_line_name(struct tty_driver *driver, int index, char *p)
{
sprintf(p, "%s%d", driver->name, index + driver->name_base);
}
-/*
+/**
+ * init_dev - initialise a tty device
+ * @driver: tty driver we are opening a device on
+ * @idx: device index
+ * @tty: returned tty structure
+ *
+ * Prepare a tty device. This may not be a "new" clean device but
+ * could also be an active device. The pty drivers require special
+ * handling because of this.
+ *
+ * Locking:
+ * The function is called under the tty_mutex, which
+ * protects us from the tty struct or driver itself going away.
+ *
+ * On exit the tty device has the line discipline attached and
+ * a reference count of 1. If a pair was created for pty/tty use
+ * and the other was a pty master then it too has a reference count of 1.
+ *
* WSH 06/09/97: Rewritten to remove races and properly clean up after a
* failed open. The new code protects the open with a mutex, so it's
* really quite straightforward. The mutex locking can probably be
* relaxed for the (most common) case of reopening a tty.
*/
+
static int init_dev(struct tty_driver *driver, int idx,
struct tty_struct **ret_tty)
{
struct tty_struct *tty, *o_tty;
struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
- int retval=0;
+ int retval = 0;
/* check whether we're reopening an existing tty */
if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
@@ -1667,16 +2065,27 @@ fail_no_mem:
/* call the tty release_mem routine to clean out this slot */
release_mem_out:
- printk(KERN_INFO "init_dev: ldisc open failed, "
- "clearing slot %d\n", idx);
+ if (printk_ratelimit())
+ printk(KERN_INFO "init_dev: ldisc open failed, "
+ "clearing slot %d\n", idx);
release_mem(tty, idx);
goto end_init;
}
-/*
- * Releases memory associated with a tty structure, and clears out the
- * driver table slots.
+/**
+ * release_mem - release tty structure memory
+ *
+ * Releases memory associated with a tty structure, and clears out the
+ * driver table slots. This function is called when a device is no longer
+ * in use. It also gets called when setup of a device fails.
+ *
+ * Locking:
+ * tty_mutex - sometimes only
+ * takes the file list lock internally when working on the list
+ * of ttys that the driver keeps.
+ * FIXME: should we require tty_mutex is held here ??
*/
+
static void release_mem(struct tty_struct *tty, int idx)
{
struct tty_struct *o_tty;
@@ -1955,7 +2364,6 @@ static void release_dev(struct file * filp)
* race with the set_ldisc code path.
*/
clear_bit(TTY_LDISC, &tty->flags);
- clear_bit(TTY_DONT_FLIP, &tty->flags);
cancel_delayed_work(&tty->buf.work);
/*
@@ -2018,18 +2426,27 @@ static void release_dev(struct file * filp)
}
-/*
- * tty_open and tty_release keep up the tty count that contains the
- * number of opens done on a tty. We cannot use the inode-count, as
- * different inodes might point to the same tty.
+/**
+ * tty_open - open a tty device
+ * @inode: inode of device file
+ * @filp: file pointer to tty
+ *
+ * tty_open and tty_release keep up the tty count that contains the
+ * number of opens done on a tty. We cannot use the inode-count, as
+ * different inodes might point to the same tty.
*
- * Open-counting is needed for pty masters, as well as for keeping
- * track of serial lines: DTR is dropped when the last close happens.
- * (This is not done solely through tty->count, now. - Ted 1/27/92)
+ * Open-counting is needed for pty masters, as well as for keeping
+ * track of serial lines: DTR is dropped when the last close happens.
+ * (This is not done solely through tty->count, now. - Ted 1/27/92)
*
- * The termios state of a pty is reset on first open so that
- * settings don't persist across reuse.
+ * The termios state of a pty is reset on first open so that
+ * settings don't persist across reuse.
+ *
+ * Locking: tty_mutex protects current->signal->tty, get_tty_driver and
+ * init_dev work. tty->count should protect the rest.
+ * task_lock is held to update task details for sessions
*/
+
static int tty_open(struct inode * inode, struct file * filp)
{
struct tty_struct *tty;
@@ -2144,6 +2561,18 @@ got_driver:
}
#ifdef CONFIG_UNIX98_PTYS
+/**
+ * ptmx_open - open a unix 98 pty master
+ * @inode: inode of device file
+ * @filp: file pointer to tty
+ *
+ * Allocate a unix98 pty master device from the ptmx driver.
+ *
+ * Locking: tty_mutex protects theinit_dev work. tty->count should
+ protect the rest.
+ * allocated_ptys_lock handles the list of free pty numbers
+ */
+
static int ptmx_open(struct inode * inode, struct file * filp)
{
struct tty_struct *tty;
@@ -2203,6 +2632,18 @@ out:
}
#endif
+/**
+ * tty_release - vfs callback for close
+ * @inode: inode of tty
+ * @filp: file pointer for handle to tty
+ *
+ * Called the last time each file handle is closed that references
+ * this tty. There may however be several such references.
+ *
+ * Locking:
+ * Takes bkl. See release_dev
+ */
+
static int tty_release(struct inode * inode, struct file * filp)
{
lock_kernel();
@@ -2211,7 +2652,18 @@ static int tty_release(struct inode * inode, struct file * filp)
return 0;
}
-/* No kernel lock held - fine */
+/**
+ * tty_poll - check tty status
+ * @filp: file being polled
+ * @wait: poll wait structures to update
+ *
+ * Call the line discipline polling method to obtain the poll
+ * status of the device.
+ *
+ * Locking: locks called line discipline but ldisc poll method
+ * may be re-entered freely by other callers.
+ */
+
static unsigned int tty_poll(struct file * filp, poll_table * wait)
{
struct tty_struct * tty;
@@ -2255,6 +2707,23 @@ static int tty_fasync(int fd, struct file * filp, int on)
return 0;
}
+/**
+ * tiocsti - fake input character
+ * @tty: tty to fake input into
+ * @p: pointer to character
+ *
+ * Fake input to a tty device. Does the neccessary locking and
+ * input management.
+ *
+ * FIXME: does not honour flow control ??
+ *
+ * Locking:
+ * Called functions take tty_ldisc_lock
+ * current->signal->tty check is safe without locks
+ *
+ * FIXME: may race normal receive processing
+ */
+
static int tiocsti(struct tty_struct *tty, char __user *p)
{
char ch, mbz = 0;
@@ -2270,13 +2739,45 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
return 0;
}
+/**
+ * tiocgwinsz - implement window query ioctl
+ * @tty; tty
+ * @arg: user buffer for result
+ *
+ * Copies the kernel idea of the window size into the user buffer.
+ *
+ * Locking: tty->termios_sem is taken to ensure the winsize data
+ * is consistent.
+ */
+
static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
{
- if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
- return -EFAULT;
- return 0;
+ int err;
+
+ mutex_lock(&tty->termios_mutex);
+ err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
+ mutex_unlock(&tty->termios_mutex);
+
+ return err ? -EFAULT: 0;
}
+/**
+ * tiocswinsz - implement window size set ioctl
+ * @tty; tty
+ * @arg: user buffer for result
+ *
+ * Copies the user idea of the window size to the kernel. Traditionally
+ * this is just advisory information but for the Linux console it
+ * actually has driver level meaning and triggers a VC resize.
+ *
+ * Locking:
+ * Called function use the console_sem is used to ensure we do
+ * not try and resize the console twice at once.
+ * The tty->termios_sem is used to ensure we don't double
+ * resize and get confused. Lock order - tty->termios.sem before
+ * console sem
+ */
+
static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize __user * arg)
{
@@ -2284,17 +2785,18 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
+
+ mutex_lock(&tty->termios_mutex);
if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
- return 0;
+ goto done;
+
#ifdef CONFIG_VT
if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
- int rc;
-
- acquire_console_sem();
- rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row);
- release_console_sem();
- if (rc)
- return -ENXIO;
+ if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col,
+ tmp_ws.ws_row)) {
+ mutex_unlock(&tty->termios_mutex);
+ return -ENXIO;
+ }
}
#endif
if (tty->pgrp > 0)
@@ -2303,9 +2805,20 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
kill_pg(real_tty->pgrp, SIGWINCH, 1);
tty->winsize = tmp_ws;
real_tty->winsize = tmp_ws;
+done:
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
+/**
+ * tioccons - allow admin to move logical console
+ * @file: the file to become console
+ *
+ * Allow the adminstrator to move the redirected console device
+ *
+ * Locking: uses redirect_lock to guard the redirect information
+ */
+
static int tioccons(struct file *file)
{
if (!capable(CAP_SYS_ADMIN))
@@ -2331,6 +2844,17 @@ static int tioccons(struct file *file)
return 0;
}
+/**
+ * fionbio - non blocking ioctl
+ * @file: file to set blocking value
+ * @p: user parameter
+ *
+ * Historical tty interfaces had a blocking control ioctl before
+ * the generic functionality existed. This piece of history is preserved
+ * in the expected tty API of posix OS's.
+ *
+ * Locking: none, the open fle handle ensures it won't go away.
+ */
static int fionbio(struct file *file, int __user *p)
{
@@ -2346,9 +2870,24 @@ static int fionbio(struct file *file, int __user *p)
return 0;
}
+/**
+ * tiocsctty - set controlling tty
+ * @tty: tty structure
+ * @arg: user argument
+ *
+ * This ioctl is used to manage job control. It permits a session
+ * leader to set this tty as the controlling tty for the session.
+ *
+ * Locking:
+ * Takes tasklist lock internally to walk sessions
+ * Takes task_lock() when updating signal->tty
+ * Takes tty_mutex() to protect tty instance
+ *
+ */
+
static int tiocsctty(struct tty_struct *tty, int arg)
{
- task_t *p;
+ struct task_struct *p;
if (current->signal->leader &&
(current->signal->session == tty->session))
@@ -2377,15 +2916,29 @@ static int tiocsctty(struct tty_struct *tty, int arg)
} else
return -EPERM;
}
+ mutex_lock(&tty_mutex);
task_lock(current);
current->signal->tty = tty;
task_unlock(current);
+ mutex_unlock(&tty_mutex);
current->signal->tty_old_pgrp = 0;
tty->session = current->signal->session;
tty->pgrp = process_group(current);
return 0;
}
+/**
+ * tiocgpgrp - get process group
+ * @tty: tty passed by user
+ * @real_tty: tty side of the tty pased by the user if a pty else the tty
+ * @p: returned pid
+ *
+ * Obtain the process group of the tty. If there is no process group
+ * return an error.
+ *
+ * Locking: none. Reference to ->signal->tty is safe.
+ */
+
static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
/*
@@ -2397,6 +2950,18 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
return put_user(real_tty->pgrp, p);
}
+/**
+ * tiocspgrp - attempt to set process group
+ * @tty: tty passed by user
+ * @real_tty: tty side device matching tty passed by user
+ * @p: pid pointer
+ *
+ * Set the process group of the tty to the session passed. Only
+ * permitted where the tty session is our session.
+ *
+ * Locking: None
+ */
+
static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
pid_t pgrp;
@@ -2420,6 +2985,18 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
return 0;
}
+/**
+ * tiocgsid - get session id
+ * @tty: tty passed by user
+ * @real_tty: tty side of the tty pased by the user if a pty else the tty
+ * @p: pointer to returned session id
+ *
+ * Obtain the session id of the tty. If there is no session
+ * return an error.
+ *
+ * Locking: none. Reference to ->signal->tty is safe.
+ */
+
static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
/*
@@ -2433,6 +3010,16 @@ static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t _
return put_user(real_tty->session, p);
}
+/**
+ * tiocsetd - set line discipline
+ * @tty: tty device
+ * @p: pointer to user data
+ *
+ * Set the line discipline according to user request.
+ *
+ * Locking: see tty_set_ldisc, this function is just a helper
+ */
+
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
int ldisc;
@@ -2442,20 +3029,47 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
return tty_set_ldisc(tty, ldisc);
}
+/**
+ * send_break - performed time break
+ * @tty: device to break on
+ * @duration: timeout in mS
+ *
+ * Perform a timed break on hardware that lacks its own driver level
+ * timed break functionality.
+ *
+ * Locking:
+ * atomic_write_lock serializes
+ *
+ */
+
static int send_break(struct tty_struct *tty, unsigned int duration)
{
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -EINTR;
tty->driver->break_ctl(tty, -1);
if (!signal_pending(current)) {
msleep_interruptible(duration);
}
tty->driver->break_ctl(tty, 0);
+ mutex_unlock(&tty->atomic_write_lock);
if (signal_pending(current))
return -EINTR;
return 0;
}
-static int
-tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
+/**
+ * tiocmget - get modem status
+ * @tty: tty device
+ * @file: user file pointer
+ * @p: pointer to result
+ *
+ * Obtain the modem status bits from the tty driver if the feature
+ * is supported. Return -EINVAL if it is not available.
+ *
+ * Locking: none (up to the driver)
+ */
+
+static int tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
{
int retval = -EINVAL;
@@ -2468,8 +3082,20 @@ tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
return retval;
}
-static int
-tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
+/**
+ * tiocmset - set modem status
+ * @tty: tty device
+ * @file: user file pointer
+ * @cmd: command - clear bits, set bits or set all
+ * @p: pointer to desired bits
+ *
+ * Set the modem status bits from the tty driver if the feature
+ * is supported. Return -EINVAL if it is not available.
+ *
+ * Locking: none (up to the driver)
+ */
+
+static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
unsigned __user *p)
{
int retval = -EINVAL;
@@ -2518,6 +3144,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
+ /* CHECKME: is this safe as one end closes ? */
+
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -2585,6 +3213,7 @@ int tty_ioctl(struct inode * inode, struct file * file,
clear_bit(TTY_EXCLUSIVE, &tty->flags);
return 0;
case TIOCNOTTY:
+ /* FIXME: taks lock or tty_mutex ? */
if (current->signal->tty != tty)
return -ENOTTY;
if (current->signal->leader)
@@ -2621,10 +3250,9 @@ int tty_ioctl(struct inode * inode, struct file * file,
tty->driver->break_ctl(tty, 0);
return 0;
case TCSBRK: /* SVID version: non-zero arg --> no break */
- /*
- * XXX is the above comment correct, or the
- * code below correct? Is this ioctl used at
- * all by anyone?
+ /* non-zero arg means wait for all output data
+ * to be sent (performed above) but don't send break.
+ * This is used by the tcdrain() termios function.
*/
if (!arg)
return send_break(tty, 250);
@@ -2766,9 +3394,16 @@ void do_SAK(struct tty_struct *tty)
EXPORT_SYMBOL(do_SAK);
-/*
- * This routine is called out of the software interrupt to flush data
- * from the buffer chain to the line discipline.
+/**
+ * flush_to_ldisc
+ * @private_: tty structure passed from work queue.
+ *
+ * This routine is called out of the software interrupt to flush data
+ * from the buffer chain to the line discipline.
+ *
+ * Locking: holds tty->buf.lock to guard buffer list. Drops the lock
+ * while invoking the line discipline receive_buf method. The
+ * receive_buf method is single threaded for each tty instance.
*/
static void flush_to_ldisc(void *private_)
@@ -2776,8 +3411,7 @@ static void flush_to_ldisc(void *private_)
struct tty_struct *tty = (struct tty_struct *) private_;
unsigned long flags;
struct tty_ldisc *disc;
- struct tty_buffer *tbuf;
- int count;
+ struct tty_buffer *tbuf, *head;
char *char_buf;
unsigned char *flag_buf;
@@ -2785,32 +3419,37 @@ static void flush_to_ldisc(void *private_)
if (disc == NULL) /* !TTY_LDISC */
return;
- if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
- /*
- * Do it after the next timer tick:
- */
- schedule_delayed_work(&tty->buf.work, 1);
- goto out;
- }
spin_lock_irqsave(&tty->buf.lock, flags);
- while((tbuf = tty->buf.head) != NULL) {
- while ((count = tbuf->commit - tbuf->read) != 0) {
- char_buf = tbuf->char_buf_ptr + tbuf->read;
- flag_buf = tbuf->flag_buf_ptr + tbuf->read;
- tbuf->read += count;
+ head = tty->buf.head;
+ if (head != NULL) {
+ tty->buf.head = NULL;
+ for (;;) {
+ int count = head->commit - head->read;
+ if (!count) {
+ if (head->next == NULL)
+ break;
+ tbuf = head;
+ head = head->next;
+ tty_buffer_free(tty, tbuf);
+ continue;
+ }
+ if (!tty->receive_room) {
+ schedule_delayed_work(&tty->buf.work, 1);
+ break;
+ }
+ if (count > tty->receive_room)
+ count = tty->receive_room;
+ char_buf = head->char_buf_ptr + head->read;
+ flag_buf = head->flag_buf_ptr + head->read;
+ head->read += count;
spin_unlock_irqrestore(&tty->buf.lock, flags);
disc->receive_buf(tty, char_buf, flag_buf, count);
spin_lock_irqsave(&tty->buf.lock, flags);
}
- if (tbuf->active)
- break;
- tty->buf.head = tbuf->next;
- if (tty->buf.head == NULL)
- tty->buf.tail = NULL;
- tty_buffer_free(tty, tbuf);
+ tty->buf.head = head;
}
spin_unlock_irqrestore(&tty->buf.lock, flags);
-out:
+
tty_ldisc_deref(disc);
}
@@ -2840,6 +3479,8 @@ static int n_baud_table = ARRAY_SIZE(baud_table);
* Convert termios baud rate data into a speed. This should be called
* with the termios lock held if this termios is a terminal termios
* structure. May change the termios data.
+ *
+ * Locking: none
*/
int tty_termios_baud_rate(struct termios *termios)
@@ -2868,6 +3509,8 @@ EXPORT_SYMBOL(tty_termios_baud_rate);
* Returns the baud rate as an integer for this terminal. The
* termios lock must be held by the caller and the terminal bit
* flags may be updated.
+ *
+ * Locking: none
*/
int tty_get_baud_rate(struct tty_struct *tty)
@@ -2897,16 +3540,16 @@ EXPORT_SYMBOL(tty_get_baud_rate);
*
* In the event of the queue being busy for flipping the work will be
* held off and retried later.
+ *
+ * Locking: tty buffer lock. Driver locks in low latency mode.
*/
void tty_flip_buffer_push(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
- if (tty->buf.tail != NULL) {
- tty->buf.tail->active = 0;
+ if (tty->buf.tail != NULL)
tty->buf.tail->commit = tty->buf.tail->used;
- }
spin_unlock_irqrestore(&tty->buf.lock, flags);
if (tty->low_latency)
@@ -2918,9 +3561,16 @@ void tty_flip_buffer_push(struct tty_struct *tty)
EXPORT_SYMBOL(tty_flip_buffer_push);
-/*
- * This subroutine initializes a tty structure.
+/**
+ * initialize_tty_struct
+ * @tty: tty to initialize
+ *
+ * This subroutine initializes a tty structure that has been newly
+ * allocated.
+ *
+ * Locking: none - tty in question must not be exposed at this point
*/
+
static void initialize_tty_struct(struct tty_struct *tty)
{
memset(tty, 0, sizeof(struct tty_struct));
@@ -2932,7 +3582,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty_buffer_init(tty);
INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
init_MUTEX(&tty->buf.pty_sem);
- init_MUTEX(&tty->termios_sem);
+ mutex_init(&tty->termios_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
@@ -2946,6 +3596,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
/*
* The default put_char routine if the driver did not define one.
*/
+
static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
{
tty->driver->write(tty, &ch, 1);
@@ -2954,19 +3605,23 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
static struct class *tty_class;
/**
- * tty_register_device - register a tty device
- * @driver: the tty driver that describes the tty device
- * @index: the index in the tty driver for this tty device
- * @device: a struct device that is associated with this tty device.
- * This field is optional, if there is no known struct device for this
- * tty device it can be set to NULL safely.
+ * tty_register_device - register a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ * @device: a struct device that is associated with this tty device.
+ * This field is optional, if there is no known struct device
+ * for this tty device it can be set to NULL safely.
*
- * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error).
+ * Returns a pointer to the class device (or ERR_PTR(-EFOO) on error).
*
- * This call is required to be made to register an individual tty device if
- * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set. If that
- * bit is not set, this function should not be called.
+ * This call is required to be made to register an individual tty device
+ * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If
+ * that bit is not set, this function should not be called by a tty
+ * driver.
+ *
+ * Locking: ??
*/
+
struct class_device *tty_register_device(struct tty_driver *driver,
unsigned index, struct device *device)
{
@@ -2979,9 +3634,6 @@ struct class_device *tty_register_device(struct tty_driver *driver,
return ERR_PTR(-EINVAL);
}
- devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
- "%s%d", driver->devfs_name, index + driver->name_base);
-
if (driver->type == TTY_DRIVER_TYPE_PTY)
pty_line_name(driver, index, name);
else
@@ -2991,16 +3643,18 @@ struct class_device *tty_register_device(struct tty_driver *driver,
}
/**
- * tty_unregister_device - unregister a tty device
- * @driver: the tty driver that describes the tty device
- * @index: the index in the tty driver for this tty device
+ * tty_unregister_device - unregister a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
*
- * If a tty device is registered with a call to tty_register_device() then
- * this function must be made when the tty device is gone.
+ * If a tty device is registered with a call to tty_register_device() then
+ * this function must be called when the tty device is gone.
+ *
+ * Locking: ??
*/
+
void tty_unregister_device(struct tty_driver *driver, unsigned index)
{
- devfs_remove("%s%d", driver->devfs_name, index + driver->name_base);
class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index);
}
@@ -3109,7 +3763,6 @@ int tty_register_driver(struct tty_driver *driver)
driver->cdev.owner = driver->owner;
error = cdev_add(&driver->cdev, dev, driver->num);
if (error) {
- cdev_del(&driver->cdev);
unregister_chrdev_region(dev, driver->num);
driver->ttys = NULL;
driver->termios = driver->termios_locked = NULL;
@@ -3122,7 +3775,7 @@ int tty_register_driver(struct tty_driver *driver)
list_add(&driver->tty_drivers, &tty_drivers);
- if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
+ if ( !(driver->flags & TTY_DRIVER_DYNAMIC_DEV) ) {
for(i = 0; i < driver->num; i++)
tty_register_device(driver, i, NULL);
}
@@ -3165,7 +3818,7 @@ int tty_unregister_driver(struct tty_driver *driver)
driver->termios_locked[i] = NULL;
kfree(tp);
}
- if (!(driver->flags & TTY_DRIVER_NO_DEVFS))
+ if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
p = driver->ttys;
@@ -3241,14 +3894,12 @@ static int __init tty_init(void)
if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
panic("Couldn't register /dev/tty driver\n");
- devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
cdev_init(&console_cdev, &console_fops);
if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
panic("Couldn't register /dev/console driver\n");
- devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
#ifdef CONFIG_UNIX98_PTYS
@@ -3256,7 +3907,6 @@ static int __init tty_init(void)
if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
panic("Couldn't register /dev/ptmx driver\n");
- devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
#endif
@@ -3265,7 +3915,6 @@ static int __init tty_init(void)
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
- devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0");
class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
vty_init();
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index f19cf9d7792..3b6fa7b0be8 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -36,6 +37,18 @@
#define TERMIOS_WAIT 2
#define TERMIOS_TERMIO 4
+
+/**
+ * tty_wait_until_sent - wait for I/O to finish
+ * @tty: tty we are waiting for
+ * @timeout: how long we will wait
+ *
+ * Wait for characters pending in a tty driver to hit the wire, or
+ * for a timeout to occur (eg due to flow control)
+ *
+ * Locking: none
+ */
+
void tty_wait_until_sent(struct tty_struct * tty, long timeout)
{
DECLARE_WAITQUEUE(wait, current);
@@ -94,6 +107,18 @@ static void unset_locked_termios(struct termios *termios,
old->c_cc[i] : termios->c_cc[i];
}
+/**
+ * change_termios - update termios values
+ * @tty: tty to update
+ * @new_termios: desired new value
+ *
+ * Perform updates to the termios values set on this terminal. There
+ * is a bit of layering violation here with n_tty in terms of the
+ * internal knowledge of this function.
+ *
+ * Locking: termios_sem
+ */
+
static void change_termios(struct tty_struct * tty, struct termios * new_termios)
{
int canon_change;
@@ -107,7 +132,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
@@ -152,9 +177,22 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
(ld->set_termios)(tty, &old_termios);
tty_ldisc_deref(ld);
}
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
}
+/**
+ * set_termios - set termios values for a tty
+ * @tty: terminal device
+ * @arg: user data
+ * @opt: option information
+ *
+ * Helper function to prepare termios data and run neccessary other
+ * functions before using change_termios to do the actual changes.
+ *
+ * Locking:
+ * Called functions take ldisc and termios_sem locks
+ */
+
static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
{
struct termios tmp_termios;
@@ -247,13 +285,13 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
{
struct sgttyb tmp;
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
tmp.sg_ispeed = 0;
tmp.sg_ospeed = 0;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -284,6 +322,17 @@ static void set_sgflags(struct termios * termios, int flags)
}
}
+/**
+ * set_sgttyb - set legacy terminal values
+ * @tty: tty structure
+ * @sgttyb: pointer to old style terminal structure
+ *
+ * Updates a terminal from the legacy BSD style terminal information
+ * structure.
+ *
+ * Locking: termios_sem
+ */
+
static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
{
int retval;
@@ -297,12 +346,12 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
return -EFAULT;
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
termios = *tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
change_termios(tty, &termios);
return 0;
}
@@ -369,22 +418,33 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
}
#endif
-/*
- * Send a high priority character to the tty.
+/**
+ * send_prio_char - send priority character
+ *
+ * Send a high priority character to the tty even if stopped
+ *
+ * Locking: none for xchar method, write ordering for write method.
*/
-static void send_prio_char(struct tty_struct *tty, char ch)
+
+static int send_prio_char(struct tty_struct *tty, char ch)
{
int was_stopped = tty->stopped;
if (tty->driver->send_xchar) {
tty->driver->send_xchar(tty, ch);
- return;
+ return 0;
}
+
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -ERESTARTSYS;
+
if (was_stopped)
start_tty(tty);
tty->driver->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
+ mutex_unlock(&tty->atomic_write_lock);
+ return 0;
}
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
@@ -458,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
- send_prio_char(tty, STOP_CHAR(tty));
+ return send_prio_char(tty, STOP_CHAR(tty));
break;
case TCION:
if (START_CHAR(tty) != __DISABLED_CHAR)
- send_prio_char(tty, START_CHAR(tty));
+ return send_prio_char(tty, START_CHAR(tty));
break;
default:
return -EINVAL;
@@ -537,11 +597,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
return 0;
default:
return -ENOIOCTLCMD;
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 3c1dafaa344..bd7a98c6ea7 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -21,12 +21,10 @@
* - making it shorter - scr_readw are macros which expand in PRETTY long code
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/errno.h>
#include <linux/tty.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
@@ -467,7 +465,7 @@ vcs_open(struct inode *inode, struct file *filp)
return 0;
}
-static struct file_operations vcs_fops = {
+static const struct file_operations vcs_fops = {
.llseek = vcs_lseek,
.read = vcs_read,
.write = vcs_write,
@@ -476,23 +474,16 @@ static struct file_operations vcs_fops = {
static struct class *vc_class;
-void vcs_make_devfs(struct tty_struct *tty)
+void vcs_make_sysfs(struct tty_struct *tty)
{
- devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1),
- S_IFCHR|S_IRUSR|S_IWUSR,
- "vcc/%u", tty->index + 1);
- devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129),
- S_IFCHR|S_IRUSR|S_IWUSR,
- "vcc/a%u", tty->index + 1);
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
NULL, "vcs%u", tty->index + 1);
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
NULL, "vcsa%u", tty->index + 1);
}
-void vcs_remove_devfs(struct tty_struct *tty)
+
+void vcs_remove_sysfs(struct tty_struct *tty)
{
- devfs_remove("vcc/%u", tty->index + 1);
- devfs_remove("vcc/a%u", tty->index + 1);
class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
}
@@ -503,8 +494,6 @@ int __init vcs_init(void)
panic("unable to get major %d for vcs device", VCS_MAJOR);
vc_class = class_create(THIS_MODULE, "vc");
- devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0");
- devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0");
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
return 0;
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 4e536038874..f3efeaf2826 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -25,7 +25,6 @@
* 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/config.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/errno.h>
@@ -44,7 +43,6 @@
#include <linux/sysrq.h>
#include <asm/iseries/vio.h>
-
#include <asm/iseries/hv_lp_event.h>
#include <asm/iseries/hv_call_event.h>
#include <asm/iseries/hv_lp_config.h>
@@ -68,35 +66,6 @@ static int vio_sysrq_pressed;
extern int sysrq_enabled;
#endif
-/*
- * The structure of the events that flow between us and OS/400. You can't
- * mess with this unless the OS/400 side changes too
- */
-struct viocharlpevent {
- struct HvLpEvent event;
- u32 reserved;
- u16 version;
- u16 subtype_result_code;
- u8 virtual_device;
- u8 len;
- u8 data[VIOCHAR_MAX_DATA];
-};
-
-#define VIOCHAR_WINDOW 10
-#define VIOCHAR_HIGHWATERMARK 3
-
-enum viocharsubtype {
- viocharopen = 0x0001,
- viocharclose = 0x0002,
- viochardata = 0x0003,
- viocharack = 0x0004,
- viocharconfig = 0x0005
-};
-
-enum viochar_rc {
- viochar_rc_ebusy = 1
-};
-
#define VIOCHAR_NUM_BUF 16
/*
@@ -1152,7 +1121,6 @@ static int __init viocons_init2(void)
viotty_driver = alloc_tty_driver(VTTY_PORTS);
viotty_driver->owner = THIS_MODULE;
viotty_driver->driver_name = "vioconsole";
- viotty_driver->devfs_name = "vcs/";
viotty_driver->name = "tty";
viotty_driver->name_base = 1;
viotty_driver->major = TTY_MAJOR;
@@ -1185,6 +1153,7 @@ static int __init viocons_init(void)
port_info[i].magic = VIOTTY_MAGIC;
}
HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
+ add_preferred_console("viocons", 0, NULL);
register_console(&viocons_early);
return 0;
}
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index 11c7e9de595..73c78bf75d7 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -31,7 +31,6 @@
* the OS/400 partition. The format of the messages is defined in
* iseries/vio.h
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -43,7 +42,6 @@
#include <linux/dma-mapping.h>
#include <linux/fs.h>
#include <linux/cdev.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/major.h>
#include <linux/completion.h>
#include <linux/proc_fs.h>
@@ -246,7 +244,6 @@ static struct device *tape_device[VIOTAPE_MAX_TAPE];
*/
static struct {
unsigned char cur_part;
- int dev_handle;
unsigned char part_stat_rwi[MAX_PARTITIONS];
} state[VIOTAPE_MAX_TAPE];
@@ -295,7 +292,7 @@ static int proc_viotape_open(struct inode *inode, struct file *file)
return single_open(file, proc_viotape_show, NULL);
}
-static struct file_operations proc_viotape_operations = {
+static const struct file_operations proc_viotape_operations = {
.open = proc_viotape_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -943,7 +940,6 @@ static void vioHandleTapeEvent(struct HvLpEvent *event)
static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
{
- char tapename[32];
int i = vdev->unit_address;
int j;
@@ -959,15 +955,9 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
"iseries!vt%d", i);
class_device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80),
NULL, "iseries!nvt%d", i);
- devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR,
- "iseries/vt%d", i);
- devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80),
- S_IFCHR | S_IRUSR | S_IWUSR, "iseries/nvt%d", i);
- sprintf(tapename, "iseries/vt%d", i);
- state[i].dev_handle = devfs_register_tape(tapename);
- printk(VIOTAPE_KERN_INFO "tape %s is iSeries "
+ printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries "
"resource %10.10s type %4.4s, model %3.3s\n",
- tapename, viotape_unitinfo[i].rsrcname,
+ i, viotape_unitinfo[i].rsrcname,
viotape_unitinfo[i].type, viotape_unitinfo[i].model);
return 0;
}
@@ -976,9 +966,6 @@ static int viotape_remove(struct vio_dev *vdev)
{
int i = vdev->unit_address;
- devfs_remove("iseries/nvt%d", i);
- devfs_remove("iseries/vt%d", i);
- devfs_unregister_tape(state[i].dev_handle);
class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80));
class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i));
return 0;
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index fd00822ac14..bfe5ea948f6 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -14,7 +14,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
#include <linux/kernel.h>
@@ -147,7 +146,6 @@ static int scc_init_drivers(void)
scc_driver->owner = THIS_MODULE;
scc_driver->driver_name = "scc";
scc_driver->name = "ttyS";
- scc_driver->devfs_name = "tts/";
scc_driver->major = TTY_MAJOR;
scc_driver->minor_start = SCC_MINOR_BASE;
scc_driver->type = TTY_DRIVER_TYPE_SERIAL;
@@ -205,13 +203,13 @@ static int mvme147_scc_init(void)
port->datap = port->ctrlp + 1;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
"SCC-A TX", port);
- request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-A status", port);
- request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
"SCC-A RX", port);
- request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
"SCC-A special cond", port);
{
SCC_ACCESS_INIT(port);
@@ -232,13 +230,13 @@ static int mvme147_scc_init(void)
port->datap = port->ctrlp + 1;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
"SCC-B TX", port);
- request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-B status", port);
- request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
"SCC-B RX", port);
- request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
"SCC-B special cond", port);
{
SCC_ACCESS_INIT(port);
@@ -275,13 +273,13 @@ static int mvme162_scc_init(void)
port->datap = port->ctrlp + 2;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
"SCC-A TX", port);
- request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-A status", port);
- request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
"SCC-A RX", port);
- request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
"SCC-A special cond", port);
{
SCC_ACCESS_INIT(port);
@@ -302,13 +300,13 @@ static int mvme162_scc_init(void)
port->datap = port->ctrlp + 2;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
"SCC-B TX", port);
- request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-B status", port);
- request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
"SCC-B RX", port);
- request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
"SCC-B special cond", port);
{
@@ -343,13 +341,13 @@ static int bvme6000_scc_init(void)
port->datap = port->ctrlp + 4;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED,
"SCC-A TX", port);
- request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-A status", port);
- request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED,
"SCC-A RX", port);
- request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED,
"SCC-A special cond", port);
{
SCC_ACCESS_INIT(port);
@@ -370,13 +368,13 @@ static int bvme6000_scc_init(void)
port->datap = port->ctrlp + 4;
port->port_a = &scc_ports[0];
port->port_b = &scc_ports[1];
- request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED,
"SCC-B TX", port);
- request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED,
"SCC-B status", port);
- request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED,
"SCC-B RX", port);
- request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, SA_INTERRUPT,
+ request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED,
"SCC-B special cond", port);
{
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 05e6e814d86..8116a47b80f 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -33,6 +33,7 @@
#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/irq.h>
#include <asm/vr41xx/vr41xx.h>
MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
@@ -605,7 +606,7 @@ static int gpio_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations gpio_fops = {
+static const struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.read = gpio_read,
.write = gpio_write,
@@ -689,9 +690,9 @@ static int __devinit giu_probe(struct platform_device *dev)
for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
if (i < GIU_IRQ(GIUINT_HIGH_OFFSET))
- irq_desc[i].handler = &giuint_low_irq_type;
+ irq_desc[i].chip = &giuint_low_irq_type;
else
- irq_desc[i].handler = &giuint_high_irq_type;
+ irq_desc[i].chip = &giuint_high_irq_type;
}
return cascade_irq(GIUINT_IRQ, giu_get_irq);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 6c94879e0b9..fb75da940b5 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -63,6 +63,13 @@
*
* Removed console_lock, enabled interrupts across all console operations
* 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
*/
#include <linux/module.h>
@@ -79,7 +86,6 @@
#include <linux/mm.h>
#include <linux/console.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
#include <linux/tiocl.h>
@@ -87,7 +93,6 @@
#include <linux/consolemap.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
-#include <linux/config.h>
#include <linux/workqueue.h>
#include <linux/bootmem.h>
#include <linux/pm.h>
@@ -98,7 +103,22 @@
#include <asm/system.h>
#include <asm/uaccess.h>
+#define MAX_NR_CON_DRIVER 16
+
+#define CON_DRIVER_FLAG_MODULE 1
+#define CON_DRIVER_FLAG_INIT 2
+
+struct con_driver {
+ const struct consw *con;
+ const char *desc;
+ struct class_device *class_dev;
+ int node;
+ int first;
+ int last;
+ int flag;
+};
+static struct con_driver registered_con_driver[MAX_NR_CON_DRIVER];
const struct consw *conswitchp;
/* A bitmap for codes <32. A bit of 1 indicates that the code
@@ -115,8 +135,8 @@ const struct consw *conswitchp;
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
-extern void vcs_make_devfs(struct tty_struct *tty);
-extern void vcs_remove_devfs(struct tty_struct *tty);
+extern void vcs_make_sysfs(struct tty_struct *tty);
+extern void vcs_remove_sysfs(struct tty_struct *tty);
extern void console_map_init(void);
#ifdef CONFIG_PROM_CONSOLE
@@ -717,7 +737,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
visual_init(vc, currcons, 1);
if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc);
- vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+ if (!vc->vc_kmalloced)
+ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
kfree(vc);
vc_cons[currcons].d = NULL;
@@ -865,14 +886,24 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
return err;
}
+int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
+{
+ int rc;
+
+ acquire_console_sem();
+ rc = vc_resize(vc, cols, lines);
+ release_console_sem();
+ return rc;
+}
-void vc_disallocate(unsigned int currcons)
+void vc_deallocate(unsigned int currcons)
{
WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) {
struct vc_data *vc = vc_cons[currcons].d;
vc->vc_sw->con_deinit(vc);
+ module_put(vc->vc_sw->owner);
if (vc->vc_kmalloced)
kfree(vc->vc_screenbuf);
if (currcons >= MIN_NR_CONSOLES)
@@ -1991,17 +2022,23 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
/* Do no translation at all in control states */
if (vc->vc_state != ESnormal) {
tc = c;
- } else if (vc->vc_utf) {
+ } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
/* Combine UTF-8 into Unicode */
- /* Incomplete characters silently ignored */
+ /* Malformed sequences as sequences of replacement glyphs */
+rescan_last_byte:
if(c > 0x7f) {
- if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) {
- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
- vc->vc_utf_count--;
- if (vc->vc_utf_count == 0)
- tc = c = vc->vc_utf_char;
- else continue;
+ if (vc->vc_utf_count) {
+ if ((c & 0xc0) == 0x80) {
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ if (--vc->vc_utf_count) {
+ vc->vc_npar++;
+ continue;
+ }
+ tc = c = vc->vc_utf_char;
+ } else
+ goto replacement_glyph;
} else {
+ vc->vc_npar = 0;
if ((c & 0xe0) == 0xc0) {
vc->vc_utf_count = 1;
vc->vc_utf_char = (c & 0x1f);
@@ -2018,14 +2055,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
vc->vc_utf_count = 5;
vc->vc_utf_char = (c & 0x01);
} else
- vc->vc_utf_count = 0;
+ goto replacement_glyph;
continue;
}
} else {
+ if (vc->vc_utf_count)
+ goto replacement_glyph;
tc = c;
- vc->vc_utf_count = 0;
}
- } else { /* no utf */
+ } else { /* no utf or alternate charset mode */
tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
@@ -2040,31 +2078,33 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
* direct-to-font zone in UTF-8 mode.
*/
ok = tc && (c >= 32 ||
- (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
+ !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+ vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
&& (c != 127 || vc->vc_disp_ctrl)
&& (c != 128+27);
if (vc->vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
tc = conv_uni_to_pc(vc, tc);
- if ( tc == -4 ) {
+ if (tc & ~charmask) {
+ if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(vc, 0xfffd);
-
- /* One reason for the -4 can be that we just
- did a clear_unimap();
- try at least to show something. */
- if (tc == -4)
- tc = c;
- } else if ( tc == -3 ) {
- /* Bad hash table -- hope for the best */
- tc = c;
- }
- if (tc & ~charmask)
- continue; /* Conversion failed */
+replacement_glyph:
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (!(tc & ~charmask))
+ goto display_glyph;
+ } else if ( tc != -3 )
+ continue; /* nothing to display */
+ /* no hash table or no replacement --
+ * hope for the best */
+ if ( c & ~charmask )
+ tc = '?';
+ else
+ tc = c;
+ }
+display_glyph:
if (vc->vc_need_wrap || vc->vc_decim)
FLUSH
if (vc->vc_need_wrap) {
@@ -2088,6 +2128,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
vc->vc_x++;
draw_to = (vc->vc_pos += 2);
}
+ if (vc->vc_utf_count) {
+ if (vc->vc_npar) {
+ vc->vc_npar--;
+ goto display_glyph;
+ }
+ vc->vc_utf_count = 0;
+ c = orig;
+ goto rescan_last_byte;
+ }
continue;
}
FLUSH
@@ -2484,7 +2533,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
release_console_sem();
- vcs_make_devfs(tty);
+ vcs_make_sysfs(tty);
return ret;
}
}
@@ -2497,7 +2546,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
* and taking a ref against the tty while we're in the process of forgetting
* about it and cleaning things up.
*
- * This is because vcs_remove_devfs() can sleep and will drop the BKL.
+ * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
*/
static void con_close(struct tty_struct *tty, struct file *filp)
{
@@ -2510,7 +2559,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
vc->vc_tty = NULL;
tty->driver_data = NULL;
release_console_sem();
- vcs_remove_devfs(tty);
+ vcs_remove_sysfs(tty);
mutex_unlock(&tty_mutex);
/*
* tty_mutex is released, but we still hold BKL, so there is
@@ -2557,7 +2606,7 @@ static int __init con_init(void)
{
const char *display_desc = NULL;
struct vc_data *vc;
- unsigned int currcons = 0;
+ unsigned int currcons = 0, i;
acquire_console_sem();
@@ -2569,6 +2618,22 @@ static int __init con_init(void)
return 0;
}
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con_driver = &registered_con_driver[i];
+
+ if (con_driver->con == NULL) {
+ con_driver->con = conswitchp;
+ con_driver->desc = display_desc;
+ con_driver->flag = CON_DRIVER_FLAG_INIT;
+ con_driver->first = 0;
+ con_driver->last = MAX_NR_CONSOLES - 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ con_driver_map[i] = conswitchp;
+
init_timer(&console_timer);
console_timer.function = blank_screen_t;
if (blankinterval) {
@@ -2632,7 +2697,6 @@ int __init vty_init(void)
if (!console_driver)
panic("Couldn't allocate console driver\n");
console_driver->owner = THIS_MODULE;
- console_driver->devfs_name = "vc/";
console_driver->name = "tty";
console_driver->name_base = 1;
console_driver->major = TTY_MAJOR;
@@ -2656,38 +2720,53 @@ int __init vty_init(void)
}
#ifndef VT_SINGLE_DRIVER
+#include <linux/device.h>
-/*
- * If we support more console drivers, this function is used
- * when a driver wants to take over some existing consoles
- * and become default driver for newly opened ones.
- */
+static struct class *vtconsole_class;
-int take_over_console(const struct consw *csw, int first, int last, int deflt)
+static int bind_con_driver(const struct consw *csw, int first, int last,
+ int deflt)
{
- int i, j = -1;
- const char *desc;
- struct module *owner;
+ struct module *owner = csw->owner;
+ const char *desc = NULL;
+ struct con_driver *con_driver;
+ int i, j = -1, k = -1, retval = -ENODEV;
- owner = csw->owner;
if (!try_module_get(owner))
return -ENODEV;
acquire_console_sem();
- desc = csw->con_startup();
- if (!desc) {
- release_console_sem();
- module_put(owner);
- return -ENODEV;
+ /* check if driver is registered */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = &registered_con_driver[i];
+
+ if (con_driver->con == csw) {
+ desc = con_driver->desc;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval)
+ goto err;
+
+ if (!(con_driver->flag & CON_DRIVER_FLAG_INIT)) {
+ csw->con_startup();
+ con_driver->flag |= CON_DRIVER_FLAG_INIT;
}
+
if (deflt) {
if (conswitchp)
module_put(conswitchp->owner);
+
__module_get(owner);
conswitchp = csw;
}
+ first = max(first, con_driver->first);
+ last = min(last, con_driver->last);
+
for (i = first; i <= last; i++) {
int old_was_color;
struct vc_data *vc = vc_cons[i].d;
@@ -2701,15 +2780,17 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
continue;
j = i;
- if (CON_IS_VISIBLE(vc))
+
+ if (CON_IS_VISIBLE(vc)) {
+ k = i;
save_screen(vc);
+ }
+
old_was_color = vc->vc_can_do_color;
vc->vc_sw->con_deinit(vc);
vc->vc_origin = (unsigned long)vc->vc_screenbuf;
- vc->vc_visible_origin = vc->vc_origin;
- vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
- vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
visual_init(vc, i, 0);
+ set_origin(vc);
update_attr(vc);
/* If the console changed between mono <-> color, then
@@ -2718,36 +2799,506 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
*/
if (old_was_color != vc->vc_can_do_color)
clear_buffer_attributes(vc);
-
- if (CON_IS_VISIBLE(vc))
- update_screen(vc);
}
+
printk("Console: switching ");
if (!deflt)
printk("consoles %d-%d ", first+1, last+1);
- if (j >= 0)
+ if (j >= 0) {
+ struct vc_data *vc = vc_cons[j].d;
+
printk("to %s %s %dx%d\n",
- vc_cons[j].d->vc_can_do_color ? "colour" : "mono",
- desc, vc_cons[j].d->vc_cols, vc_cons[j].d->vc_rows);
- else
+ vc->vc_can_do_color ? "colour" : "mono",
+ desc, vc->vc_cols, vc->vc_rows);
+
+ if (k >= 0) {
+ vc = vc_cons[k].d;
+ update_screen(vc);
+ }
+ } else
printk("to %s\n", desc);
+ retval = 0;
+err:
release_console_sem();
+ module_put(owner);
+ return retval;
+};
+
+#ifdef CONFIG_VT_HW_CONSOLE_BINDING
+static int con_is_graphics(const struct consw *csw, int first, int last)
+{
+ int i, retval = 0;
+
+ for (i = first; i <= last; i++) {
+ struct vc_data *vc = vc_cons[i].d;
+
+ if (vc && vc->vc_mode == KD_GRAPHICS) {
+ retval = 1;
+ break;
+ }
+ }
+ return retval;
+}
+
+static int unbind_con_driver(const struct consw *csw, int first, int last,
+ int deflt)
+{
+ struct module *owner = csw->owner;
+ const struct consw *defcsw = NULL;
+ struct con_driver *con_driver = NULL, *con_back = NULL;
+ int i, retval = -ENODEV;
+
+ if (!try_module_get(owner))
+ return -ENODEV;
+
+ acquire_console_sem();
+
+ /* check if driver is registered and if it is unbindable */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = &registered_con_driver[i];
+
+ if (con_driver->con == csw &&
+ con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval) {
+ release_console_sem();
+ goto err;
+ }
+
+ retval = -ENODEV;
+
+ /* check if backup driver exists */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_back = &registered_con_driver[i];
+
+ if (con_back->con &&
+ !(con_back->flag & CON_DRIVER_FLAG_MODULE)) {
+ defcsw = con_back->con;
+ retval = 0;
+ break;
+ }
+ }
+
+ if (retval) {
+ release_console_sem();
+ goto err;
+ }
+
+ if (!con_is_bound(csw)) {
+ release_console_sem();
+ goto err;
+ }
+
+ first = max(first, con_driver->first);
+ last = min(last, con_driver->last);
+
+ for (i = first; i <= last; i++) {
+ if (con_driver_map[i] == csw) {
+ module_put(csw->owner);
+ con_driver_map[i] = NULL;
+ }
+ }
+
+ if (!con_is_bound(defcsw)) {
+ const struct consw *defconsw = conswitchp;
+
+ defcsw->con_startup();
+ con_back->flag |= CON_DRIVER_FLAG_INIT;
+ /*
+ * vgacon may change the default driver to point
+ * to dummycon, we restore it here...
+ */
+ conswitchp = defconsw;
+ }
+
+ if (!con_is_bound(csw))
+ con_driver->flag &= ~CON_DRIVER_FLAG_INIT;
+
+ release_console_sem();
+ /* ignore return value, binding should not fail */
+ bind_con_driver(defcsw, first, last, deflt);
+err:
module_put(owner);
+ return retval;
+
+}
+
+static int vt_bind(struct con_driver *con)
+{
+ const struct consw *defcsw = NULL, *csw = NULL;
+ int i, more = 1, first = -1, last = -1, deflt = 0;
+
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+ con_is_graphics(con->con, con->first, con->last))
+ goto err;
+
+ csw = con->con;
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con = &registered_con_driver[i];
+
+ if (con->con && !(con->flag & CON_DRIVER_FLAG_MODULE)) {
+ defcsw = con->con;
+ break;
+ }
+ }
+
+ if (!defcsw)
+ goto err;
+
+ while (more) {
+ more = 0;
+
+ for (i = con->first; i <= con->last; i++) {
+ if (con_driver_map[i] == defcsw) {
+ if (first == -1)
+ first = i;
+ last = i;
+ more = 1;
+ } else if (first != -1)
+ break;
+ }
+
+ if (first == 0 && last == MAX_NR_CONSOLES -1)
+ deflt = 1;
+
+ if (first != -1)
+ bind_con_driver(csw, first, last, deflt);
+
+ first = -1;
+ last = -1;
+ deflt = 0;
+ }
+
+err:
return 0;
}
-void give_up_console(const struct consw *csw)
+static int vt_unbind(struct con_driver *con)
+{
+ const struct consw *csw = NULL;
+ int i, more = 1, first = -1, last = -1, deflt = 0;
+
+ if (!con->con || !(con->flag & CON_DRIVER_FLAG_MODULE) ||
+ con_is_graphics(con->con, con->first, con->last))
+ goto err;
+
+ csw = con->con;
+
+ while (more) {
+ more = 0;
+
+ for (i = con->first; i <= con->last; i++) {
+ if (con_driver_map[i] == csw) {
+ if (first == -1)
+ first = i;
+ last = i;
+ more = 1;
+ } else if (first != -1)
+ break;
+ }
+
+ if (first == 0 && last == MAX_NR_CONSOLES -1)
+ deflt = 1;
+
+ if (first != -1)
+ unbind_con_driver(csw, first, last, deflt);
+
+ first = -1;
+ last = -1;
+ deflt = 0;
+ }
+
+err:
+ return 0;
+}
+#else
+static inline int vt_bind(struct con_driver *con)
+{
+ return 0;
+}
+static inline int vt_unbind(struct con_driver *con)
+{
+ return 0;
+}
+#endif /* CONFIG_VT_HW_CONSOLE_BINDING */
+
+static ssize_t store_bind(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct con_driver *con = class_get_devdata(class_device);
+ int bind = simple_strtoul(buf, NULL, 0);
+
+ if (bind)
+ vt_bind(con);
+ else
+ vt_unbind(con);
+
+ return count;
+}
+
+static ssize_t show_bind(struct class_device *class_device, char *buf)
+{
+ struct con_driver *con = class_get_devdata(class_device);
+ int bind = con_is_bound(con->con);
+
+ return snprintf(buf, PAGE_SIZE, "%i\n", bind);
+}
+
+static ssize_t show_name(struct class_device *class_device, char *buf)
+{
+ struct con_driver *con = class_get_devdata(class_device);
+
+ return snprintf(buf, PAGE_SIZE, "%s %s\n",
+ (con->flag & CON_DRIVER_FLAG_MODULE) ? "(M)" : "(S)",
+ con->desc);
+
+}
+
+static struct class_device_attribute class_device_attrs[] = {
+ __ATTR(bind, S_IRUGO|S_IWUSR, show_bind, store_bind),
+ __ATTR(name, S_IRUGO, show_name, NULL),
+};
+
+static int vtconsole_init_class_device(struct con_driver *con)
{
int i;
- for(i = 0; i < MAX_NR_CONSOLES; i++)
+ class_set_devdata(con->class_dev, con);
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_create_file(con->class_dev,
+ &class_device_attrs[i]);
+
+ return 0;
+}
+
+static void vtconsole_deinit_class_device(struct con_driver *con)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_remove_file(con->class_dev,
+ &class_device_attrs[i]);
+}
+
+/**
+ * con_is_bound - checks if driver is bound to the console
+ * @csw: console driver
+ *
+ * RETURNS: zero if unbound, nonzero if bound
+ *
+ * Drivers can call this and if zero, they should release
+ * all resources allocated on con_startup()
+ */
+int con_is_bound(const struct consw *csw)
+{
+ int i, bound = 0;
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (con_driver_map[i] == csw) {
- module_put(csw->owner);
- con_driver_map[i] = NULL;
+ bound = 1;
+ break;
+ }
+ }
+
+ return bound;
+}
+EXPORT_SYMBOL(con_is_bound);
+
+/**
+ * register_con_driver - register console driver to console layer
+ * @csw: console driver
+ * @first: the first console to take over, minimum value is 0
+ * @last: the last console to take over, maximum value is MAX_NR_CONSOLES -1
+ *
+ * DESCRIPTION: This function registers a console driver which can later
+ * bind to a range of consoles specified by @first and @last. It will
+ * also initialize the console driver by calling con_startup().
+ */
+int register_con_driver(const struct consw *csw, int first, int last)
+{
+ struct module *owner = csw->owner;
+ struct con_driver *con_driver;
+ const char *desc;
+ int i, retval = 0;
+
+ if (!try_module_get(owner))
+ return -ENODEV;
+
+ acquire_console_sem();
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = &registered_con_driver[i];
+
+ /* already registered */
+ if (con_driver->con == csw)
+ retval = -EINVAL;
+ }
+
+ if (retval)
+ goto err;
+
+ desc = csw->con_startup();
+
+ if (!desc)
+ goto err;
+
+ retval = -EINVAL;
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ con_driver = &registered_con_driver[i];
+
+ if (con_driver->con == NULL) {
+ con_driver->con = csw;
+ con_driver->desc = desc;
+ con_driver->node = i;
+ con_driver->flag = CON_DRIVER_FLAG_MODULE |
+ CON_DRIVER_FLAG_INIT;
+ con_driver->first = first;
+ con_driver->last = last;
+ retval = 0;
+ break;
}
+ }
+
+ if (retval)
+ goto err;
+
+ con_driver->class_dev = class_device_create(vtconsole_class, NULL,
+ MKDEV(0, con_driver->node),
+ NULL, "vtcon%i",
+ con_driver->node);
+
+ if (IS_ERR(con_driver->class_dev)) {
+ printk(KERN_WARNING "Unable to create class_device for %s; "
+ "errno = %ld\n", con_driver->desc,
+ PTR_ERR(con_driver->class_dev));
+ con_driver->class_dev = NULL;
+ } else {
+ vtconsole_init_class_device(con_driver);
+ }
+err:
+ release_console_sem();
+ module_put(owner);
+ return retval;
+}
+EXPORT_SYMBOL(register_con_driver);
+
+/**
+ * unregister_con_driver - unregister console driver from console layer
+ * @csw: console driver
+ *
+ * DESCRIPTION: All drivers that registers to the console layer must
+ * call this function upon exit, or if the console driver is in a state
+ * where it won't be able to handle console services, such as the
+ * framebuffer console without loaded framebuffer drivers.
+ *
+ * The driver must unbind first prior to unregistration.
+ */
+int unregister_con_driver(const struct consw *csw)
+{
+ int i, retval = -ENODEV;
+
+ acquire_console_sem();
+
+ /* cannot unregister a bound driver */
+ if (con_is_bound(csw))
+ goto err;
+
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con_driver = &registered_con_driver[i];
+
+ if (con_driver->con == csw &&
+ con_driver->flag & CON_DRIVER_FLAG_MODULE) {
+ vtconsole_deinit_class_device(con_driver);
+ class_device_destroy(vtconsole_class,
+ MKDEV(0, con_driver->node));
+ con_driver->con = NULL;
+ con_driver->desc = NULL;
+ con_driver->class_dev = NULL;
+ con_driver->node = 0;
+ con_driver->flag = 0;
+ con_driver->first = 0;
+ con_driver->last = 0;
+ retval = 0;
+ break;
+ }
+ }
+err:
+ release_console_sem();
+ return retval;
+}
+EXPORT_SYMBOL(unregister_con_driver);
+
+/*
+ * If we support more console drivers, this function is used
+ * when a driver wants to take over some existing consoles
+ * and become default driver for newly opened ones.
+ *
+ * take_over_console is basically a register followed by unbind
+ */
+int take_over_console(const struct consw *csw, int first, int last, int deflt)
+{
+ int err;
+
+ err = register_con_driver(csw, first, last);
+
+ if (!err)
+ bind_con_driver(csw, first, last, deflt);
+
+ return err;
+}
+
+/*
+ * give_up_console is a wrapper to unregister_con_driver. It will only
+ * work if driver is fully unbound.
+ */
+void give_up_console(const struct consw *csw)
+{
+ unregister_con_driver(csw);
+}
+
+static int __init vtconsole_class_init(void)
+{
+ int i;
+
+ vtconsole_class = class_create(THIS_MODULE, "vtconsole");
+ if (IS_ERR(vtconsole_class)) {
+ printk(KERN_WARNING "Unable to create vt console class; "
+ "errno = %ld\n", PTR_ERR(vtconsole_class));
+ vtconsole_class = NULL;
+ }
+
+ /* Add system drivers to sysfs */
+ for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
+ struct con_driver *con = &registered_con_driver[i];
+
+ if (con->con && !con->class_dev) {
+ con->class_dev =
+ class_device_create(vtconsole_class, NULL,
+ MKDEV(0, con->node), NULL,
+ "vtcon%i", con->node);
+
+ if (IS_ERR(con->class_dev)) {
+ printk(KERN_WARNING "Unable to create "
+ "class_device for %s; errno = %ld\n",
+ con->desc, PTR_ERR(con->class_dev));
+ con->class_dev = NULL;
+ } else {
+ vtconsole_init_class_device(con);
+ }
+ }
+ }
+
+ return 0;
}
+postcore_initcall(vtconsole_class_init);
#endif
@@ -3249,6 +3800,7 @@ EXPORT_SYMBOL(default_blu);
EXPORT_SYMBOL(update_region);
EXPORT_SYMBOL(redraw_screen);
EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(vc_lock_resize);
EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook);
EXPORT_SYMBOL(console_blanked);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 24011e7c81f..a53e382cc10 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -10,7 +10,6 @@
* Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -97,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str
if (!perm)
return -EPERM;
if (!i && v == K_NOSUCHMAP) {
- /* disallocate map */
+ /* deallocate map */
key_map = key_maps[s];
if (s && key_map) {
key_maps[s] = NULL;
@@ -820,20 +819,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (arg > MAX_NR_CONSOLES)
return -ENXIO;
if (arg == 0) {
- /* disallocate all unused consoles, but leave 0 */
+ /* deallocate all unused consoles, but leave 0 */
acquire_console_sem();
for (i=1; i<MAX_NR_CONSOLES; i++)
if (! VT_BUSY(i))
- vc_disallocate(i);
+ vc_deallocate(i);
release_console_sem();
} else {
- /* disallocate a single console, if possible */
+ /* deallocate a single console, if possible */
arg--;
if (VT_BUSY(arg))
return -EBUSY;
if (arg) { /* leave 0 */
acquire_console_sem();
- vc_disallocate(arg);
+ vc_deallocate(arg);
release_console_sem();
}
}
@@ -848,11 +847,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
return -EFAULT;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- acquire_console_sem();
- vc_resize(vc_cons[i].d, cc, ll);
- release_console_sem();
- }
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ vc_lock_resize(vc_cons[i].d, cc, ll);
return 0;
}
@@ -1012,6 +1008,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
return -EPERM;
vt_dont_switch = 0;
return 0;
+ case VT_GETHIFONTMASK:
+ return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg);
default:
return -ENOIOCTLCMD;
}
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index d53f664a4dd..77ab7e020da 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -45,7 +45,7 @@ config WATCHDOG_NOWAYOUT
comment "Watchdog Device Drivers"
depends on WATCHDOG
-# Architecture Independant
+# Architecture Independent
config SOFT_WATCHDOG
tristate "Software watchdog"
@@ -127,7 +127,7 @@ config S3C2410_WATCHDOG
enabled.
The driver is limited by the speed of the system's PCLK
- signal, so with reasonbaly fast systems (PCLK around 50-66MHz)
+ signal, so with reasonably fast systems (PCLK around 50-66MHz)
then watchdog intervals of over approximately 20seconds are
unavailable.
@@ -165,6 +165,13 @@ config EP93XX_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called ep93xx_wdt.
+config OMAP_WATCHDOG
+ tristate "OMAP Watchdog"
+ depends on WATCHDOG && (ARCH_OMAP16XX || ARCH_OMAP24XX)
+ help
+ Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
+ enable the OMAP1610/OMAP1710 watchdog timer.
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -423,7 +430,7 @@ config SBC_EPX_C3_WATCHDOG
is no way to know if writing to its IO address will corrupt
your system or have any real effect. The only way to be sure
that this driver does what you want is to make sure you
- are runnning it on an EPX-C3 from Winsystems with the watchdog
+ are running it on an EPX-C3 from Winsystems with the watchdog
timer at IO address 0x1ee and 0x1ef. It will write to both those
IO ports. Basically, the assumption is made that if you compile
this driver into your kernel and/or load it as a module, that you
@@ -472,7 +479,7 @@ config INDYDOG
tristate "Indy/I2 Hardware Watchdog"
depends on WATCHDOG && SGI_IP22
help
- Hardwaredriver for the Indy's/I2's watchdog. This is a
+ Hardware driver for the Indy's/I2's watchdog. This is a
watchdog timer that will reboot the machine after a 60 second
timer expired and no process has written to /dev/watchdog during
that time.
@@ -510,6 +517,14 @@ config SH_WDT
To compile this driver as a module, choose M here: the
module will be called shwdt.
+config SH_WDT_MMAP
+ bool "Allow mmap of SH WDT"
+ default n
+ depends on SH_WDT
+ help
+ If you say Y here, user applications will be able to mmap the
+ WDT/CPG registers.
+#
# SPARC64 Architecture
config WATCHDOG_CP1XXX
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 6ab77b61a64..5099f8be8cc 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o
+obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
index 7289f4af93d..c77fe3cf285 100644
--- a/drivers/char/watchdog/acquirewdt.c
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -231,7 +231,7 @@ static int acq_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations acq_fops = {
+static const struct file_operations acq_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = acq_write,
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
index 194a3fd36b9..8069be445ed 100644
--- a/drivers/char/watchdog/advantechwdt.c
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -227,7 +227,7 @@ advwdt_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations advwdt_fops = {
+static const struct file_operations advwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = advwdt_write,
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index 8338ca300e2..c5c94e4c949 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -362,7 +362,7 @@ static int __init ali_find_watchdog(void)
* Kernel Interfaces
*/
-static struct file_operations ali_fops = {
+static const struct file_operations ali_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ali_write,
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
index c05ac188a4d..ffd7684f999 100644
--- a/drivers/char/watchdog/alim7101_wdt.c
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -281,7 +281,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
}
}
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner= THIS_MODULE,
.llseek= no_llseek,
.write= fop_write,
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c
index ac83bc4b019..cc266715ea3 100644
--- a/drivers/char/watchdog/at91_wdt.c
+++ b/drivers/char/watchdog/at91_wdt.c
@@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -17,14 +16,15 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
-#define WDT_DEFAULT_TIME 5 /* 5 seconds */
-#define WDT_MAX_TIME 256 /* 256 seconds */
+#define WDT_DEFAULT_TIME 5 /* seconds */
+#define WDT_MAX_TIME 256 /* seconds */
static int wdt_time = WDT_DEFAULT_TIME;
static int nowayout = WATCHDOG_NOWAYOUT;
@@ -32,8 +32,10 @@ static int nowayout = WATCHDOG_NOWAYOUT;
module_param(wdt_time, int, 0);
MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+#endif
static unsigned long at91wdt_busy;
@@ -138,7 +140,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_SETTIMEOUT:
if (get_user(new_value, p))
return -EFAULT;
-
+
if (at91_wdt_settimeout(new_value))
return -EINVAL;
@@ -181,7 +183,7 @@ static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, l
/* ......................................................................... */
-static struct file_operations at91wdt_fops = {
+static const struct file_operations at91wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = at91_wdt_ioctl,
@@ -196,27 +198,84 @@ static struct miscdevice at91wdt_miscdev = {
.fops = &at91wdt_fops,
};
-static int __init at91_wdt_init(void)
+static int __init at91wdt_probe(struct platform_device *pdev)
{
int res;
- /* Check that the heartbeat value is within range; if not reset to the default */
- if (at91_wdt_settimeout(wdt_time)) {
- at91_wdt_settimeout(WDT_DEFAULT_TIME);
- printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
- }
+ if (at91wdt_miscdev.dev)
+ return -EBUSY;
+ at91wdt_miscdev.dev = &pdev->dev;
res = misc_register(&at91wdt_miscdev);
if (res)
return res;
- printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout);
+ printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
return 0;
}
+static int __exit at91wdt_remove(struct platform_device *pdev)
+{
+ int res;
+
+ res = misc_deregister(&at91wdt_miscdev);
+ if (!res)
+ at91wdt_miscdev.dev = NULL;
+
+ return res;
+}
+
+static void at91wdt_shutdown(struct platform_device *pdev)
+{
+ at91_wdt_stop();
+}
+
+#ifdef CONFIG_PM
+
+static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
+{
+ at91_wdt_stop();
+ return 0;
+}
+
+static int at91wdt_resume(struct platform_device *pdev)
+{
+ if (at91wdt_busy)
+ at91_wdt_start();
+ return 0;
+}
+
+#else
+#define at91wdt_suspend NULL
+#define at91wdt_resume NULL
+#endif
+
+static struct platform_driver at91wdt_driver = {
+ .probe = at91wdt_probe,
+ .remove = __exit_p(at91wdt_remove),
+ .shutdown = at91wdt_shutdown,
+ .suspend = at91wdt_suspend,
+ .resume = at91wdt_resume,
+ .driver = {
+ .name = "at91_wdt",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_wdt_init(void)
+{
+ /* Check that the heartbeat value is within range; if not reset to the default */
+ if (at91_wdt_settimeout(wdt_time)) {
+ at91_wdt_settimeout(WDT_DEFAULT_TIME);
+ pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
+ }
+
+ return platform_driver_register(&at91wdt_driver);
+}
+
static void __exit at91_wdt_exit(void)
{
- misc_deregister(&at91wdt_miscdev);
+ platform_driver_unregister(&at91wdt_driver);
}
module_init(at91_wdt_init);
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index b6640606b44..e3cefc538b4 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -14,7 +14,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
@@ -146,7 +145,7 @@ static int booke_wdt_open (struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations booke_wdt_fops = {
+static const struct file_operations booke_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = booke_wdt_write,
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index 3e8410b5a65..04c7e49918d 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -198,7 +198,7 @@ static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t c
return count;
}
-static struct file_operations cpu5wdt_fops = {
+static const struct file_operations cpu5wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = cpu5wdt_ioctl,
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
index 9021dbb7829..77c8a955ae9 100644
--- a/drivers/char/watchdog/ep93xx_wdt.c
+++ b/drivers/char/watchdog/ep93xx_wdt.c
@@ -187,7 +187,7 @@ static int ep93xx_wdt_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations ep93xx_wdt_fops = {
+static const struct file_operations ep93xx_wdt_fops = {
.owner = THIS_MODULE,
.write = ep93xx_wdt_write,
.ioctl = ep93xx_wdt_ioctl,
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index 25c2f257561..62dbccb2f6d 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -40,7 +40,6 @@
* Added Matt Domsch's nowayout module option.
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -357,7 +356,7 @@ static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
*/
-static struct file_operations eurwdt_fops = {
+static const struct file_operations eurwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = eurwdt_write,
@@ -421,7 +420,7 @@ static int __init eurwdt_init(void)
goto out;
}
- ret = request_irq(irq, eurwdt_interrupt, SA_INTERRUPT, "eurwdt", NULL);
+ ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
if(ret) {
printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
goto outmisc;
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
index 93785f13242..870539eabbf 100644
--- a/drivers/char/watchdog/i6300esb.c
+++ b/drivers/char/watchdog/i6300esb.c
@@ -337,7 +337,7 @@ static int esb_notify_sys (struct notifier_block *this, unsigned long code, void
* Kernel Interfaces
*/
-static struct file_operations esb_fops = {
+static const struct file_operations esb_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = esb_write,
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
index fa2ba9ebe42..8385dd36eef 100644
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -205,6 +205,23 @@ static int tco_timer_set_heartbeat (int t)
return 0;
}
+static int tco_timer_get_timeleft (int *time_left)
+{
+ unsigned char val;
+
+ spin_lock(&tco_lock);
+
+ /* read the TCO Timer */
+ val = inb (TCO1_RLD);
+ val &= 0x3f;
+
+ spin_unlock(&tco_lock);
+
+ *time_left = (int)((val * 6) / 10);
+
+ return 0;
+}
+
/*
* /dev/watchdog handling
*/
@@ -272,6 +289,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
{
int new_options, retval = -EINVAL;
int new_heartbeat;
+ int time_left;
void __user *argp = (void __user *)arg;
int __user *p = argp;
static struct watchdog_info ident = {
@@ -320,7 +338,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
return -EFAULT;
if (tco_timer_set_heartbeat(new_heartbeat))
- return -EINVAL;
+ return -EINVAL;
tco_timer_keepalive ();
/* Fall */
@@ -329,6 +347,14 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
+ case WDIOC_GETTIMELEFT:
+ {
+ if (tco_timer_get_timeleft(&time_left))
+ return -EINVAL;
+
+ return put_user(time_left, p);
+ }
+
default:
return -ENOIOCTLCMD;
}
@@ -352,7 +378,7 @@ static int i8xx_tco_notify_sys (struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations i8xx_tco_fops = {
+static const struct file_operations i8xx_tco_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = i8xx_tco_write,
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
index cf60329eec8..fd95f732779 100644
--- a/drivers/char/watchdog/ib700wdt.c
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -31,7 +31,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
@@ -256,7 +255,7 @@ ibwdt_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations ibwdt_fops = {
+static const struct file_operations ibwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ibwdt_write,
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
index 294c474ae48..26ceee7a4df 100644
--- a/drivers/char/watchdog/ibmasr.c
+++ b/drivers/char/watchdog/ibmasr.c
@@ -10,7 +10,6 @@
* of the GNU Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -323,7 +322,7 @@ static int asr_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations asr_fops = {
+static const struct file_operations asr_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = asr_write,
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
index b4b94daba67..dacc1c20a31 100644
--- a/drivers/char/watchdog/indydog.c
+++ b/drivers/char/watchdog/indydog.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -155,7 +154,7 @@ static int indydog_notify_sys(struct notifier_block *this, unsigned long code, v
return NOTIFY_DONE;
}
-static struct file_operations indydog_fops = {
+static const struct file_operations indydog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = indydog_write,
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index 0cfb9b9c4a4..692908819e2 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -16,7 +16,6 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -169,7 +168,7 @@ ixp2000_wdt_release(struct inode *inode, struct file *file)
}
-static struct file_operations ixp2000_wdt_fops =
+static const struct file_operations ixp2000_wdt_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
index 3800835ca8f..9db5cf2c38c 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -13,7 +13,6 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -163,7 +162,7 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file)
}
-static struct file_operations ixp4xx_wdt_fops =
+static const struct file_operations ixp4xx_wdt_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index a9a20aad61e..23734e07fb2 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -28,7 +28,6 @@
* Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -389,7 +388,7 @@ static int zf_notify_sys(struct notifier_block *this, unsigned long code,
-static struct file_operations zf_fops = {
+static const struct file_operations zf_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = zf_write,
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index d8dede57540..ae943324d25 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
@@ -191,7 +190,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
return 0;
}
-static struct file_operations mixcomwd_fops=
+static const struct file_operations mixcomwd_fops=
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
index 5d6f5061603..a480903ee1a 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -15,7 +15,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -130,7 +129,7 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
}
}
-static struct file_operations mpc83xx_wdt_fops = {
+static const struct file_operations mpc83xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpc83xx_wdt_write,
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index b2fc71e2085..35dd9e6e114 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -9,7 +9,6 @@
* or implied.
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -133,7 +132,7 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
return 0;
}
-static struct file_operations mpc8xx_wdt_fops = {
+static const struct file_operations mpc8xx_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpc8xx_wdt_write,
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index 2c2c5177320..54b3c56ead0 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -21,7 +21,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
@@ -298,7 +297,7 @@ static void mpcore_wdt_shutdown(struct platform_device *dev)
/*
* Kernel Interfaces
*/
-static struct file_operations mpcore_wdt_fops = {
+static const struct file_operations mpcore_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mpcore_wdt_write,
@@ -356,7 +355,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
goto err_misc;
}
- ret = request_irq(wdt->irq, mpcore_wdt_fire, SA_INTERRUPT, "mpcore_wdt", wdt);
+ ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, "mpcore_wdt", wdt);
if (ret) {
dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq);
goto err_irq;
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index f1b9cf89f15..5c8fab345b4 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -15,7 +15,6 @@
* or implied.
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -167,7 +166,7 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
return 0;
}
-static struct file_operations mv64x60_wdt_fops = {
+static const struct file_operations mv64x60_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = mv64x60_wdt_write,
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
new file mode 100644
index 00000000000..8f90b90a502
--- /dev/null
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -0,0 +1,391 @@
+/*
+ * linux/drivers/char/watchdog/omap_wdt.c
+ *
+ * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ *
+ * Author: MontaVista Software, Inc.
+ * <gdavis@mvista.com> or <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * History:
+ *
+ * 20030527: George G. Davis <gdavis@mvista.com>
+ * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
+ * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
+ * Based on SoftDog driver by Alan Cox <alan@redhat.com>
+ *
+ * Copyright (c) 2004 Texas Instruments.
+ * 1. Modified to support OMAP1610 32-KHz watchdog timer
+ * 2. Ported to 2.6 kernel
+ *
+ * Copyright (c) 2005 David Brownell
+ * Use the driver model and standard identifiers; handle bigger timeouts.
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/bitops.h>
+
+#include <asm/arch/prcm.h>
+
+#include "omap_wdt.h"
+
+static unsigned timer_margin;
+module_param(timer_margin, uint, 0);
+MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
+
+static int omap_wdt_users;
+static struct clk *armwdt_ck = NULL;
+static struct clk *mpu_wdt_ick = NULL;
+static struct clk *mpu_wdt_fck = NULL;
+
+static unsigned int wdt_trgr_pattern = 0x1234;
+
+static void omap_wdt_ping(void)
+{
+ /* wait for posted write to complete */
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ cpu_relax();
+ wdt_trgr_pattern = ~wdt_trgr_pattern;
+ omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+ /* wait for posted write to complete */
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ cpu_relax();
+ /* reloaded WCRR from WLDR */
+}
+
+static void omap_wdt_enable(void)
+{
+ /* Sequence to enable the watchdog */
+ omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ cpu_relax();
+ omap_writel(0x4444, OMAP_WATCHDOG_SPR);
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ cpu_relax();
+}
+
+static void omap_wdt_disable(void)
+{
+ /* sequence required to disable watchdog */
+ omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ cpu_relax();
+ omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ cpu_relax();
+}
+
+static void omap_wdt_adjust_timeout(unsigned new_timeout)
+{
+ if (new_timeout < TIMER_MARGIN_MIN)
+ new_timeout = TIMER_MARGIN_DEFAULT;
+ if (new_timeout > TIMER_MARGIN_MAX)
+ new_timeout = TIMER_MARGIN_MAX;
+ timer_margin = new_timeout;
+}
+
+static void omap_wdt_set_timeout(void)
+{
+ u32 pre_margin = GET_WLDR_VAL(timer_margin);
+
+ /* just count up at 32 KHz */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ cpu_relax();
+ omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ cpu_relax();
+}
+
+/*
+ * Allow only one task to hold it open
+ */
+
+static int omap_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+ return -EBUSY;
+
+ if (cpu_is_omap16xx())
+ clk_enable(armwdt_ck); /* Enable the clock */
+
+ if (cpu_is_omap24xx()) {
+ clk_enable(mpu_wdt_ick); /* Enable the interface clock */
+ clk_enable(mpu_wdt_fck); /* Enable the functional clock */
+ }
+
+ /* initialize prescaler */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ cpu_relax();
+ omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ cpu_relax();
+
+ omap_wdt_set_timeout();
+ omap_wdt_enable();
+ return 0;
+}
+
+static int omap_wdt_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer unless NOWAYOUT is defined.
+ */
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ omap_wdt_disable();
+
+ if (cpu_is_omap16xx()) {
+ clk_disable(armwdt_ck); /* Disable the clock */
+ clk_put(armwdt_ck);
+ armwdt_ck = NULL;
+ }
+
+ if (cpu_is_omap24xx()) {
+ clk_disable(mpu_wdt_ick); /* Disable the clock */
+ clk_disable(mpu_wdt_fck); /* Disable the clock */
+ clk_put(mpu_wdt_ick);
+ clk_put(mpu_wdt_fck);
+ mpu_wdt_ick = NULL;
+ mpu_wdt_fck = NULL;
+ }
+#else
+ printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
+#endif
+ omap_wdt_users = 0;
+ return 0;
+}
+
+static ssize_t
+omap_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* Refresh LOAD_TIME. */
+ if (len)
+ omap_wdt_ping();
+ return len;
+}
+
+static int
+omap_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_margin;
+ static struct watchdog_info ident = {
+ .identity = "OMAP Watchdog",
+ .options = WDIOF_SETTIMEOUT,
+ .firmware_version = 0,
+ };
+
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident));
+ case WDIOC_GETSTATUS:
+ return put_user(0, (int __user *)arg);
+ case WDIOC_GETBOOTSTATUS:
+ if (cpu_is_omap16xx())
+ return put_user(omap_readw(ARM_SYSST),
+ (int __user *)arg);
+ if (cpu_is_omap24xx())
+ return put_user(omap_prcm_get_reset_sources(),
+ (int __user *)arg);
+ case WDIOC_KEEPALIVE:
+ omap_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)arg))
+ return -EFAULT;
+ omap_wdt_adjust_timeout(new_margin);
+
+ omap_wdt_disable();
+ omap_wdt_set_timeout();
+ omap_wdt_enable();
+
+ omap_wdt_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timer_margin, (int __user *)arg);
+ }
+}
+
+static struct file_operations omap_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = omap_wdt_write,
+ .ioctl = omap_wdt_ioctl,
+ .open = omap_wdt_open,
+ .release = omap_wdt_release,
+};
+
+static struct miscdevice omap_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &omap_wdt_fops
+};
+
+static int __init omap_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res, *mem;
+ int ret;
+
+ /* reserve static register mappings */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ mem = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (mem == NULL)
+ return -EBUSY;
+
+ platform_set_drvdata(pdev, mem);
+
+ omap_wdt_users = 0;
+
+ if (cpu_is_omap16xx()) {
+ armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+ if (IS_ERR(armwdt_ck)) {
+ ret = PTR_ERR(armwdt_ck);
+ armwdt_ck = NULL;
+ goto fail;
+ }
+ }
+
+ if (cpu_is_omap24xx()) {
+ mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+ if (IS_ERR(mpu_wdt_ick)) {
+ ret = PTR_ERR(mpu_wdt_ick);
+ mpu_wdt_ick = NULL;
+ goto fail;
+ }
+ mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+ if (IS_ERR(mpu_wdt_fck)) {
+ ret = PTR_ERR(mpu_wdt_fck);
+ mpu_wdt_fck = NULL;
+ goto fail;
+ }
+ }
+
+ omap_wdt_disable();
+ omap_wdt_adjust_timeout(timer_margin);
+
+ omap_wdt_miscdev.dev = &pdev->dev;
+ ret = misc_register(&omap_wdt_miscdev);
+ if (ret)
+ goto fail;
+
+ pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+
+ /* autogate OCP interface clock */
+ omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+ return 0;
+
+fail:
+ if (armwdt_ck)
+ clk_put(armwdt_ck);
+ if (mpu_wdt_ick)
+ clk_put(mpu_wdt_ick);
+ if (mpu_wdt_fck)
+ clk_put(mpu_wdt_fck);
+ release_resource(mem);
+ return ret;
+}
+
+static void omap_wdt_shutdown(struct platform_device *pdev)
+{
+ omap_wdt_disable();
+}
+
+static int omap_wdt_remove(struct platform_device *pdev)
+{
+ struct resource *mem = platform_get_drvdata(pdev);
+ misc_deregister(&omap_wdt_miscdev);
+ release_resource(mem);
+ if (armwdt_ck)
+ clk_put(armwdt_ck);
+ if (mpu_wdt_ick)
+ clk_put(mpu_wdt_ick);
+ if (mpu_wdt_fck)
+ clk_put(mpu_wdt_fck);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* REVISIT ... not clear this is the best way to handle system suspend; and
+ * it's very inappropriate for selective device suspend (e.g. suspending this
+ * through sysfs rather than by stopping the watchdog daemon). Also, this
+ * may not play well enough with NOWAYOUT...
+ */
+
+static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (omap_wdt_users)
+ omap_wdt_disable();
+ return 0;
+}
+
+static int omap_wdt_resume(struct platform_device *pdev)
+{
+ if (omap_wdt_users) {
+ omap_wdt_enable();
+ omap_wdt_ping();
+ }
+ return 0;
+}
+
+#else
+#define omap_wdt_suspend NULL
+#define omap_wdt_resume NULL
+#endif
+
+static struct platform_driver omap_wdt_driver = {
+ .probe = omap_wdt_probe,
+ .remove = omap_wdt_remove,
+ .shutdown = omap_wdt_shutdown,
+ .suspend = omap_wdt_suspend,
+ .resume = omap_wdt_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "omap_wdt",
+ },
+};
+
+static int __init omap_wdt_init(void)
+{
+ return platform_driver_register(&omap_wdt_driver);
+}
+
+static void __exit omap_wdt_exit(void)
+{
+ platform_driver_unregister(&omap_wdt_driver);
+}
+
+module_init(omap_wdt_init);
+module_exit(omap_wdt_exit);
+
+MODULE_AUTHOR("George G. Davis");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/omap_wdt.h b/drivers/char/watchdog/omap_wdt.h
new file mode 100644
index 00000000000..52a532a5114
--- /dev/null
+++ b/drivers/char/watchdog/omap_wdt.h
@@ -0,0 +1,64 @@
+/*
+ * linux/drivers/char/watchdog/omap_wdt.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * OMAP Watchdog timer register definitions
+ *
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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 _OMAP_WATCHDOG_H
+#define _OMAP_WATCHDOG_H
+
+#define OMAP1610_WATCHDOG_BASE 0xfffeb000
+#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
+#else
+#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
+#define RM_RSTST_WKUP 0
+#endif
+
+#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
+#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
+#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
+#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
+#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
+#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
+#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
+#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
+
+/* Using the prescaler, the OMAP watchdog could go for many
+ * months before firing. These limits work without scaling,
+ * with the 60 second default assumed by most tools and docs.
+ */
+#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
+#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
+#define TIMER_MARGIN_MIN 1
+
+#define PTV 0 /* prescale */
+#define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
+
+#endif /* _OMAP_WATCHDOG_H */
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 6d44ca68312..cd7d1b6a5d9 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -740,7 +740,7 @@ static int pcwd_notify_sys(struct notifier_block *this, unsigned long code, void
* Kernel Interfaces
*/
-static struct file_operations pcwd_fops = {
+static const struct file_operations pcwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pcwd_write,
@@ -755,7 +755,7 @@ static struct miscdevice pcwd_miscdev = {
.fops = &pcwd_fops,
};
-static struct file_operations pcwd_temp_fops = {
+static const struct file_operations pcwd_temp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = pcwd_temp_read,
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index 2451edbefec..c7cfd6dbfe1 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -21,7 +21,7 @@
*/
/*
- * A bells and whistles driver is available from:
+ * A bells and whistles driver is available from:
* http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/
*
* More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
@@ -390,6 +390,24 @@ static int pcipcwd_get_temperature(int *temperature)
return 0;
}
+static int pcipcwd_get_timeleft(int *time_left)
+{
+ int msb;
+ int lsb;
+
+ /* Read the time that's left before rebooting */
+ /* Note: if the board is not yet armed then we will read 0xFFFF */
+ send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+ *time_left = (msb << 8) + lsb;
+
+ if (debug >= VERBOSE)
+ printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
+ *time_left);
+
+ return 0;
+}
+
/*
* /dev/watchdog handling
*/
@@ -512,6 +530,16 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
+ case WDIOC_GETTIMELEFT:
+ {
+ int time_left;
+
+ if (pcipcwd_get_timeleft(&time_left))
+ return -EFAULT;
+
+ return put_user(time_left, p);
+ }
+
default:
return -ENOIOCTLCMD;
}
@@ -597,7 +625,7 @@ static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, v
* Kernel Interfaces
*/
-static struct file_operations pcipcwd_fops = {
+static const struct file_operations pcipcwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = pcipcwd_write,
@@ -612,7 +640,7 @@ static struct miscdevice pcipcwd_miscdev = {
.fops = &pcipcwd_fops,
};
-static struct file_operations pcipcwd_temp_fops = {
+static const struct file_operations pcipcwd_temp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = pcipcwd_temp_read,
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 3fdfda9324f..b7ae73dcdd0 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -24,7 +24,6 @@
* http://www.berkprod.com/ or http://www.pcwatchdog.com/
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -317,6 +316,19 @@ static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temp
return 0;
}
+static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left)
+{
+ unsigned char msb, lsb;
+
+ /* Read the time that's left before rebooting */
+ /* Note: if the board is not yet armed then we will read 0xFFFF */
+ usb_pcwd_send_command(usb_pcwd, CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
+
+ *time_left = (msb << 8) + lsb;
+
+ return 0;
+}
+
/*
* /dev/watchdog handling
*/
@@ -422,6 +434,16 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
+ case WDIOC_GETTIMELEFT:
+ {
+ int time_left;
+
+ if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
+ return -EFAULT;
+
+ return put_user(time_left, p);
+ }
+
default:
return -ENOIOCTLCMD;
}
@@ -501,7 +523,7 @@ static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations usb_pcwd_fops = {
+static const struct file_operations usb_pcwd_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = usb_pcwd_write,
@@ -516,7 +538,7 @@ static struct miscdevice usb_pcwd_miscdev = {
.fops = &usb_pcwd_fops,
};
-static struct file_operations usb_pcwd_temperature_fops = {
+static const struct file_operations usb_pcwd_temperature_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = usb_pcwd_temperature_read,
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 1ea04e9b2b0..be978e8ed75 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -37,7 +37,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
@@ -320,7 +319,7 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
/* kernel interface */
-static struct file_operations s3c2410wdt_fops = {
+static const struct file_operations s3c2410wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = s3c2410wdt_write,
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
index 522a9370db9..1fc16d99578 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -17,7 +17,6 @@
*
* 27/11/2000 Initial release
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -136,7 +135,7 @@ static int sa1100dog_ioctl(struct inode *inode, struct file *file,
return ret;
}
-static struct file_operations sa1100dog_fops =
+static const struct file_operations sa1100dog_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index ed0bd55fbfc..4663c2fd53c 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -282,7 +282,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
}
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = fop_write,
diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c
index c6cbf808d8c..41fc6f80c49 100644
--- a/drivers/char/watchdog/sbc8360.c
+++ b/drivers/char/watchdog/sbc8360.c
@@ -36,7 +36,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
@@ -201,7 +200,7 @@ static int wd_margin = 0xB;
static int wd_multiplier = 2;
static int nowayout = WATCHDOG_NOWAYOUT;
-module_param(timeout, int, 27);
+module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout,
@@ -306,7 +305,7 @@ static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations sbc8360_fops = {
+static const struct file_operations sbc8360_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sbc8360_write,
@@ -408,7 +407,7 @@ module_exit(sbc8360_exit);
MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
MODULE_DESCRIPTION("SBC8360 watchdog driver");
MODULE_LICENSE("GPL");
-MODULE_VERSION("1.0");
+MODULE_VERSION("1.01");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
/* end of sbc8360.c */
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
index 837b1ec3ffe..bfc475dabe6 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -15,7 +15,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -155,7 +154,7 @@ static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code,
return NOTIFY_DONE;
}
-static struct file_operations epx_c3_fops = {
+static const struct file_operations epx_c3_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = epx_c3_write,
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 20b88f9b7be..7c3cf293a5a 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
@@ -293,7 +292,7 @@ static struct notifier_block sc1200wdt_notifier =
.notifier_call = sc1200wdt_notify_sys,
};
-static struct file_operations sc1200wdt_fops =
+static const struct file_operations sc1200wdt_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 4ee9974ad8c..2c7c9db71be 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -336,7 +336,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
}
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = fop_write,
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index b4a102a2d7e..c561299a553 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -17,7 +17,6 @@
of any nature resulting due to the use of this software. This
software is provided AS-IS with no warranties. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -195,7 +194,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
}
}
-static struct file_operations scx200_wdt_fops = {
+static const struct file_operations scx200_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = scx200_wdt_write,
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
index 1f4cab55b2e..e5b8c64f1d6 100644
--- a/drivers/char/watchdog/shwdt.c
+++ b/drivers/char/watchdog/shwdt.c
@@ -17,7 +17,6 @@
* Added expect close support, made emulated timeout runtime changeable
* general cleanups, add some ioctls
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -28,7 +27,7 @@
#include <linux/notifier.h>
#include <linux/ioport.h>
#include <linux/fs.h>
-
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/watchdog.h>
@@ -126,7 +125,6 @@ static void sh_wdt_start(void)
/**
* sh_wdt_stop - Stop the Watchdog
- *
* Stops the watchdog.
*/
static void sh_wdt_stop(void)
@@ -142,22 +140,20 @@ static void sh_wdt_stop(void)
/**
* sh_wdt_keepalive - Keep the Userspace Watchdog Alive
- *
* The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
*/
-static void sh_wdt_keepalive(void)
+static inline void sh_wdt_keepalive(void)
{
next_heartbeat = jiffies + (heartbeat * HZ);
}
/**
* sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
- *
* Set the Userspace Watchdog heartbeat
*/
static int sh_wdt_set_heartbeat(int t)
{
- if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
+ if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */
return -EINVAL;
heartbeat = t;
@@ -166,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t)
/**
* sh_wdt_ping - Ping the Watchdog
- *
* @data: Unused
*
* Clears overflow bit, resets timer counter.
@@ -183,14 +178,13 @@ static void sh_wdt_ping(unsigned long data)
sh_wdt_write_cnt(0);
mod_timer(&timer, next_ping_period(clock_division_ratio));
- } else {
- printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
- }
+ } else
+ printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
+ "the watchdog\n");
}
/**
* sh_wdt_open - Open the Device
- *
* @inode: inode of device
* @file: file handle of device
*
@@ -210,7 +204,6 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
/**
* sh_wdt_close - Close the Device
- *
* @inode: inode of device
* @file: file handle of device
*
@@ -221,7 +214,8 @@ static int sh_wdt_close(struct inode *inode, struct file *file)
if (shwdt_expect_close == 42) {
sh_wdt_stop();
} else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ printk(KERN_CRIT PFX "Unexpected close, not "
+ "stopping watchdog!\n");
sh_wdt_keepalive();
}
@@ -233,7 +227,6 @@ static int sh_wdt_close(struct inode *inode, struct file *file)
/**
* sh_wdt_write - Write to Device
- *
* @file: file handle of device
* @buf: buffer to write
* @count: length of buffer
@@ -265,8 +258,56 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf,
}
/**
- * sh_wdt_ioctl - Query Device
+ * sh_wdt_mmap - map WDT/CPG registers into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ *
+ * A simple mmap() implementation for the corner cases where the counter
+ * needs to be mapped in userspace directly. Due to the relatively small
+ * size of the area, neighbouring registers not necessarily tied to the
+ * CPG will also be accessible through the register page, so this remains
+ * configurable for users that really know what they're doing.
*
+ * Additionaly, the register page maps in the CPG register base relative
+ * to the nearest page-aligned boundary, which requires that userspace do
+ * the appropriate CPU subtype math for calculating the page offset for
+ * the counter value.
+ */
+static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int ret = -ENOSYS;
+
+#ifdef CONFIG_SH_WDT_MMAP
+ unsigned long addr;
+
+ /* Only support the simple cases where we map in a register page. */
+ if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
+ return -EINVAL;
+
+ /*
+ * Pick WTCNT as the start, it's usually the first register after the
+ * FRQCR, and neither one are generally page-aligned out of the box.
+ */
+ addr = WTCNT & ~(PAGE_SIZE - 1);
+
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
+ PAGE_SIZE, vma->vm_page_prot)) {
+ printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n",
+ __FUNCTION__);
+ return -EAGAIN;
+ }
+
+ ret = 0;
+#endif
+
+ return ret;
+}
+
+/**
+ * sh_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device
* @cmd: watchdog command
@@ -327,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
/**
* sh_wdt_notify_sys - Notifier Handler
- *
* @this: notifier block
* @code: notifier event
* @unused: unused
@@ -338,24 +378,25 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
static int sh_wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{
- if (code == SYS_DOWN || code == SYS_HALT) {
+ if (code == SYS_DOWN || code == SYS_HALT)
sh_wdt_stop();
- }
return NOTIFY_DONE;
}
-static struct file_operations sh_wdt_fops = {
+static const struct file_operations sh_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sh_wdt_write,
.ioctl = sh_wdt_ioctl,
.open = sh_wdt_open,
.release = sh_wdt_close,
+ .mmap = sh_wdt_mmap,
};
static struct watchdog_info sh_wdt_info = {
- .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "SH WDT",
};
@@ -372,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev = {
/**
* sh_wdt_init - Initialize module
- *
* Registers the device and notifier handler. Actual device
* initialization is handled by sh_wdt_open().
*/
@@ -382,15 +422,15 @@ static int __init sh_wdt_init(void)
if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
clock_division_ratio = WTCSR_CKS_4096;
- printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
- clock_division_ratio);
+ printk(KERN_INFO PFX "clock_division_ratio value must "
+ "be 0x5<=x<=0x7, using %d\n", clock_division_ratio);
}
- if (sh_wdt_set_heartbeat(heartbeat))
- {
+ rc = sh_wdt_set_heartbeat(heartbeat);
+ if (unlikely(rc)) {
heartbeat = WATCHDOG_HEARTBEAT;
- printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n",
- heartbeat);
+ printk(KERN_INFO PFX "heartbeat value must "
+ "be 1<=x<=3600, using %d\n", heartbeat);
}
init_timer(&timer);
@@ -398,15 +438,16 @@ static int __init sh_wdt_init(void)
timer.data = 0;
rc = register_reboot_notifier(&sh_wdt_notifier);
- if (rc) {
- printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc);
+ if (unlikely(rc)) {
+ printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n",
+ rc);
return rc;
}
rc = misc_register(&sh_wdt_miscdev);
- if (rc) {
- printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
- sh_wdt_miscdev.minor, rc);
+ if (unlikely(rc)) {
+ printk(KERN_ERR PFX "Can't register miscdev on "
+ "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc);
unregister_reboot_notifier(&sh_wdt_notifier);
return rc;
}
@@ -419,7 +460,6 @@ static int __init sh_wdt_init(void)
/**
* sh_wdt_exit - Deinitialize module
- *
* Unregisters the device and notifier handler. Actual device
* deinitialization is handled by sh_wdt_close().
*/
@@ -435,14 +475,13 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(clock_division_ratio, int, 0);
-MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
+MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
module_init(sh_wdt_init);
module_exit(sh_wdt_exit);
-
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index a91edaf3a35..ef8da517545 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -38,7 +38,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
@@ -244,7 +243,7 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations softdog_fops = {
+static const struct file_operations softdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = softdog_write,
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index d15ca9a3986..13f16d41c2f 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -274,7 +274,7 @@ wdt_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt_write,
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
index 52a8bd0a598..ccf6c091594 100644
--- a/drivers/char/watchdog/w83877f_wdt.c
+++ b/drivers/char/watchdog/w83877f_wdt.c
@@ -299,7 +299,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
}
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = fop_write,
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
index a7ff64c8921..98f4e17db70 100644
--- a/drivers/char/watchdog/w83977f_wdt.c
+++ b/drivers/char/watchdog/w83977f_wdt.c
@@ -17,7 +17,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -450,7 +449,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
return NOTIFY_DONE;
}
-static struct file_operations wdt_fops=
+static const struct file_operations wdt_fops=
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
index 7cf6c9bbf48..2bb6a9d6ad2 100644
--- a/drivers/char/watchdog/wafer5823wdt.c
+++ b/drivers/char/watchdog/wafer5823wdt.c
@@ -222,7 +222,7 @@ static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, vo
* Kernel Interfaces
*/
-static struct file_operations wafwdt_fops = {
+static const struct file_operations wafwdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wafwdt_write,
diff --git a/drivers/char/watchdog/wd501p.h b/drivers/char/watchdog/wd501p.h
index 84e60eb7433..a4504f40394 100644
--- a/drivers/char/watchdog/wd501p.h
+++ b/drivers/char/watchdog/wd501p.h
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#define WDT_COUNT0 (io+0)
#define WDT_COUNT1 (io+1)
diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c
index dacfe31cacc..5c38cdf4173 100644
--- a/drivers/char/watchdog/wdrtas.c
+++ b/drivers/char/watchdog/wdrtas.c
@@ -26,7 +26,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -521,7 +520,7 @@ wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr)
/*** initialization stuff */
-static struct file_operations wdrtas_fops = {
+static const struct file_operations wdrtas_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdrtas_write,
@@ -536,7 +535,7 @@ static struct miscdevice wdrtas_miscdev = {
.fops = &wdrtas_fops,
};
-static struct file_operations wdrtas_temp_fops = {
+static const struct file_operations wdrtas_temp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = wdrtas_temp_read,
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
index ec7e401228e..70be81e39a6 100644
--- a/drivers/char/watchdog/wdt.c
+++ b/drivers/char/watchdog/wdt.c
@@ -31,7 +31,6 @@
* Matt Domsch : Added nowayout module option
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -495,7 +494,7 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
*/
-static struct file_operations wdt_fops = {
+static const struct file_operations wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdt_write,
@@ -511,7 +510,7 @@ static struct miscdevice wdt_miscdev = {
};
#ifdef CONFIG_WDT_501
-static struct file_operations wdt_temp_fops = {
+static const struct file_operations wdt_temp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = wdt_temp_read,
@@ -581,7 +580,7 @@ static int __init wdt_init(void)
goto out;
}
- ret = request_irq(irq, wdt_interrupt, SA_INTERRUPT, "wdt501p", NULL);
+ ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL);
if(ret) {
printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
goto outreg;
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c
index 52825a1f177..6555fb844f2 100644
--- a/drivers/char/watchdog/wdt285.c
+++ b/drivers/char/watchdog/wdt285.c
@@ -178,7 +178,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return ret;
}
-static struct file_operations watchdog_fops = {
+static const struct file_operations watchdog_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = watchdog_write,
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index 3843900e94c..a0935bc775f 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -24,7 +24,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -419,7 +418,7 @@ static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
return NOTIFY_DONE;
}
-static struct file_operations wdt977_fops=
+static const struct file_operations wdt977_fops=
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index 4b3311993d4..5918ca2c9c3 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -35,7 +35,6 @@
* Matt Domsch : nowayout module option
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -544,7 +543,7 @@ static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
*/
-static struct file_operations wdtpci_fops = {
+static const struct file_operations wdtpci_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = wdtpci_write,
@@ -560,7 +559,7 @@ static struct miscdevice wdtpci_miscdev = {
};
#ifdef CONFIG_WDT_501_PCI
-static struct file_operations wdtpci_temp_fops = {
+static const struct file_operations wdtpci_temp_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = wdtpci_temp_read,
@@ -618,7 +617,7 @@ static int __devinit wdtpci_init_one (struct pci_dev *dev,
goto out_pci;
}
- if (request_irq (irq, wdtpci_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ if (request_irq (irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED,
"wdt_pci", &wdtpci_miscdev)) {
printk (KERN_ERR PFX "IRQ %d is not free\n", irq);
goto out_reg;
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
new file mode 100644
index 00000000000..a5222547022
--- /dev/null
+++ b/drivers/clocksource/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
+obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
+obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
new file mode 100644
index 00000000000..7ad3be8c0f4
--- /dev/null
+++ b/drivers/clocksource/acpi_pm.c
@@ -0,0 +1,177 @@
+/*
+ * linux/drivers/clocksource/acpi_pm.c
+ *
+ * This file contains the ACPI PM based clocksource.
+ *
+ * This code was largely moved from the i386 timer_pm.c file
+ * which was (C) Dominik Brodowski <linux@brodo.de> 2003
+ * and contained the following comments:
+ *
+ * Driver to use the Power Management Timer (PMTMR) available in some
+ * southbridges as primary timing source for the Linux kernel.
+ *
+ * Based on parts of linux/drivers/acpi/hardware/hwtimer.c, timer_pit.c,
+ * timer_hpet.c, and on Arjan van de Ven's implementation for 2.4.
+ *
+ * This file is licensed under the GPL v2.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/* Number of PMTMR ticks expected during calibration run */
+#define PMTMR_TICKS_PER_SEC 3579545
+
+/*
+ * The I/O port the PMTMR resides at.
+ * The location is detected during setup_arch(),
+ * in arch/i386/acpi/boot.c
+ */
+u32 pmtmr_ioport __read_mostly;
+
+#define ACPI_PM_MASK CLOCKSOURCE_MASK(24) /* limit it to 24 bits */
+
+static inline u32 read_pmtmr(void)
+{
+ /* mask the output to 24 bits */
+ return inl(pmtmr_ioport) & ACPI_PM_MASK;
+}
+
+static cycle_t acpi_pm_read_verified(void)
+{
+ u32 v1 = 0, v2 = 0, v3 = 0;
+
+ /*
+ * It has been reported that because of various broken
+ * chipsets (ICH4, PIIX4 and PIIX4E) where the ACPI PM clock
+ * source is not latched, you must read it multiple
+ * times to ensure a safe value is read:
+ */
+ do {
+ v1 = read_pmtmr();
+ v2 = read_pmtmr();
+ v3 = read_pmtmr();
+ } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+ || (v3 > v1 && v3 < v2));
+
+ return (cycle_t)v2;
+}
+
+static cycle_t acpi_pm_read(void)
+{
+ return (cycle_t)read_pmtmr();
+}
+
+static struct clocksource clocksource_acpi_pm = {
+ .name = "acpi_pm",
+ .rating = 200,
+ .read = acpi_pm_read,
+ .mask = (cycle_t)ACPI_PM_MASK,
+ .mult = 0, /*to be caluclated*/
+ .shift = 22,
+ .is_continuous = 1,
+};
+
+
+#ifdef CONFIG_PCI
+static int acpi_pm_good;
+static int __init acpi_pm_good_setup(char *__str)
+{
+ acpi_pm_good = 1;
+ return 1;
+}
+__setup("acpi_pm_good", acpi_pm_good_setup);
+
+static inline void acpi_pm_need_workaround(void)
+{
+ clocksource_acpi_pm.read = acpi_pm_read_verified;
+ clocksource_acpi_pm.rating = 110;
+}
+
+/*
+ * PIIX4 Errata:
+ *
+ * The power management timer may return improper results when read.
+ * Although the timer value settles properly after incrementing,
+ * while incrementing there is a 3 ns window every 69.8 ns where the
+ * timer value is indeterminate (a 4.2% chance that the data will be
+ * incorrect when read). As a result, the ACPI free running count up
+ * timer specification is violated due to erroneous reads.
+ */
+static void __devinit acpi_pm_check_blacklist(struct pci_dev *dev)
+{
+ u8 rev;
+
+ if (acpi_pm_good)
+ return;
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+ /* the bug has been fixed in PIIX4M */
+ if (rev < 3) {
+ printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
+ " Due to workarounds for a bug,\n"
+ "* this clock source is slow. Consider trying"
+ " other clock sources\n");
+
+ acpi_pm_need_workaround();
+ }
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3,
+ acpi_pm_check_blacklist);
+
+static void __devinit acpi_pm_check_graylist(struct pci_dev *dev)
+{
+ if (acpi_pm_good)
+ return;
+
+ printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to"
+ " workarounds for a bug,\n"
+ "* this clock source is slow. If you are sure your timer"
+ " does not have\n"
+ "* this bug, please use \"acpi_pm_good\" to disable the"
+ " workaround\n");
+
+ acpi_pm_need_workaround();
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
+ acpi_pm_check_graylist);
+#endif
+
+
+static int __init init_acpi_pm_clocksource(void)
+{
+ u32 value1, value2;
+ unsigned int i;
+
+ if (!pmtmr_ioport)
+ return -ENODEV;
+
+ clocksource_acpi_pm.mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC,
+ clocksource_acpi_pm.shift);
+
+ /* "verify" this timing source: */
+ value1 = read_pmtmr();
+ for (i = 0; i < 10000; i++) {
+ value2 = read_pmtmr();
+ if (value2 == value1)
+ continue;
+ if (value2 > value1)
+ goto pm_good;
+ if ((value2 < value1) && ((value2) < 0xFFF))
+ goto pm_good;
+ printk(KERN_INFO "PM-Timer had inconsistent results:"
+ " 0x%#x, 0x%#x - aborting.\n", value1, value2);
+ return -EINVAL;
+ }
+ printk(KERN_INFO "PM-Timer had no reasonable result:"
+ " 0x%#x - aborting.\n", value1);
+ return -ENODEV;
+
+pm_good:
+ return clocksource_register(&clocksource_acpi_pm);
+}
+
+module_init(init_acpi_pm_clocksource);
diff --git a/drivers/clocksource/cyclone.c b/drivers/clocksource/cyclone.c
new file mode 100644
index 00000000000..bf4d3d50d1c
--- /dev/null
+++ b/drivers/clocksource/cyclone.c
@@ -0,0 +1,119 @@
+#include <linux/clocksource.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/timex.h>
+#include <linux/init.h>
+
+#include <asm/pgtable.h>
+#include <asm/io.h>
+
+#include "mach_timer.h"
+
+#define CYCLONE_CBAR_ADDR 0xFEB00CD0 /* base address ptr */
+#define CYCLONE_PMCC_OFFSET 0x51A0 /* offset to control register */
+#define CYCLONE_MPCS_OFFSET 0x51A8 /* offset to select register */
+#define CYCLONE_MPMC_OFFSET 0x51D0 /* offset to count register */
+#define CYCLONE_TIMER_FREQ 99780000 /* 100Mhz, but not really */
+#define CYCLONE_TIMER_MASK CLOCKSOURCE_MASK(32) /* 32 bit mask */
+
+int use_cyclone = 0;
+static void __iomem *cyclone_ptr;
+
+static cycle_t read_cyclone(void)
+{
+ return (cycle_t)readl(cyclone_ptr);
+}
+
+static struct clocksource clocksource_cyclone = {
+ .name = "cyclone",
+ .rating = 250,
+ .read = read_cyclone,
+ .mask = CYCLONE_TIMER_MASK,
+ .mult = 10,
+ .shift = 0,
+ .is_continuous = 1,
+};
+
+static int __init init_cyclone_clocksource(void)
+{
+ unsigned long base; /* saved value from CBAR */
+ unsigned long offset;
+ u32 __iomem* volatile cyclone_timer; /* Cyclone MPMC0 register */
+ u32 __iomem* reg;
+ int i;
+
+ /* make sure we're on a summit box: */
+ if (!use_cyclone)
+ return -ENODEV;
+
+ printk(KERN_INFO "Summit chipset: Starting Cyclone Counter.\n");
+
+ /* find base address: */
+ offset = CYCLONE_CBAR_ADDR;
+ reg = ioremap_nocache(offset, sizeof(reg));
+ if (!reg) {
+ printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n");
+ return -ENODEV;
+ }
+ /* even on 64bit systems, this is only 32bits: */
+ base = readl(reg);
+ if (!base) {
+ printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n");
+ return -ENODEV;
+ }
+ iounmap(reg);
+
+ /* setup PMCC: */
+ offset = base + CYCLONE_PMCC_OFFSET;
+ reg = ioremap_nocache(offset, sizeof(reg));
+ if (!reg) {
+ printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n");
+ return -ENODEV;
+ }
+ writel(0x00000001,reg);
+ iounmap(reg);
+
+ /* setup MPCS: */
+ offset = base + CYCLONE_MPCS_OFFSET;
+ reg = ioremap_nocache(offset, sizeof(reg));
+ if (!reg) {
+ printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n");
+ return -ENODEV;
+ }
+ writel(0x00000001,reg);
+ iounmap(reg);
+
+ /* map in cyclone_timer: */
+ offset = base + CYCLONE_MPMC_OFFSET;
+ cyclone_timer = ioremap_nocache(offset, sizeof(u64));
+ if (!cyclone_timer) {
+ printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n");
+ return -ENODEV;
+ }
+
+ /* quick test to make sure its ticking: */
+ for (i = 0; i < 3; i++){
+ u32 old = readl(cyclone_timer);
+ int stall = 100;
+
+ while (stall--)
+ barrier();
+
+ if (readl(cyclone_timer) == old) {
+ printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n");
+ iounmap(cyclone_timer);
+ cyclone_timer = NULL;
+ return -ENODEV;
+ }
+ }
+ cyclone_ptr = cyclone_timer;
+
+ /* sort out mult/shift values: */
+ clocksource_cyclone.shift = 22;
+ clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
+ clocksource_cyclone.shift);
+
+ return clocksource_register(&clocksource_cyclone);
+}
+
+module_init(init_cyclone_clocksource);
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
new file mode 100644
index 00000000000..d418b829721
--- /dev/null
+++ b/drivers/clocksource/scx200_hrt.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2006 Jim Cromie
+ *
+ * This is a clocksource driver for the Geode SCx200's 1 or 27 MHz
+ * high-resolution timer. The Geode SC-1100 (at least) has a buggy
+ * time stamp counter (TSC), which loses time unless 'idle=poll' is
+ * given as a boot-arg. In its absence, the Generic Timekeeping code
+ * will detect and de-rate the bad TSC, allowing this timer to take
+ * over timekeeping duties.
+ *
+ * Based on work by John Stultz, and Ted Phelps (in a 2.6.12-rc6 patch)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/clocksource.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/scx200.h>
+
+#define NAME "scx200_hrt"
+
+static int mhz27;
+module_param(mhz27, int, 0); /* load time only */
+MODULE_PARM_DESC(mhz27, "count at 27.0 MHz (default is 1.0 MHz)");
+
+static int ppm;
+module_param(ppm, int, 0); /* load time only */
+MODULE_PARM_DESC(ppm, "+-adjust to actual XO freq (ppm)");
+
+/* HiRes Timer configuration register address */
+#define SCx200_TMCNFG_OFFSET (SCx200_TIMER_OFFSET + 5)
+
+/* and config settings */
+#define HR_TMEN (1 << 0) /* timer interrupt enable */
+#define HR_TMCLKSEL (1 << 1) /* 1|0 counts at 27|1 MHz */
+#define HR_TM27MPD (1 << 2) /* 1 turns off input clock (power-down) */
+
+/* The base timer frequency, * 27 if selected */
+#define HRT_FREQ 1000000
+
+static cycle_t read_hrt(void)
+{
+ /* Read the timer value */
+ return (cycle_t) inl(scx200_cb_base + SCx200_TIMER_OFFSET);
+}
+
+#define HRT_SHIFT_1 22
+#define HRT_SHIFT_27 26
+
+static struct clocksource cs_hrt = {
+ .name = "scx200_hrt",
+ .rating = 250,
+ .read = read_hrt,
+ .mask = CLOCKSOURCE_MASK(32),
+ .is_continuous = 1,
+ /* mult, shift are set based on mhz27 flag */
+};
+
+static int __init init_hrt_clocksource(void)
+{
+ /* Make sure scx200 has initializedd the configuration block */
+ if (!scx200_cb_present())
+ return -ENODEV;
+
+ /* Reserve the timer's ISA io-region for ourselves */
+ if (!request_region(scx200_cb_base + SCx200_TIMER_OFFSET,
+ SCx200_TIMER_SIZE,
+ "NatSemi SCx200 High-Resolution Timer")) {
+ printk(KERN_WARNING NAME ": unable to lock timer region\n");
+ return -ENODEV;
+ }
+
+ /* write timer config */
+ outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0,
+ scx200_cb_base + SCx200_TMCNFG_OFFSET);
+
+ if (mhz27) {
+ cs_hrt.shift = HRT_SHIFT_27;
+ cs_hrt.mult = clocksource_hz2mult((HRT_FREQ + ppm) * 27,
+ cs_hrt.shift);
+ } else {
+ cs_hrt.shift = HRT_SHIFT_1;
+ cs_hrt.mult = clocksource_hz2mult(HRT_FREQ + ppm,
+ cs_hrt.shift);
+ }
+ printk(KERN_INFO "enabling scx200 high-res timer (%s MHz +%d ppm)\n",
+ mhz27 ? "27":"1", ppm);
+
+ return clocksource_register(&cs_hrt);
+}
+
+module_init(init_hrt_clocksource);
+
+MODULE_AUTHOR("Jim Cromie <jim.cromie@gmail.com>");
+MODULE_DESCRIPTION("clocksource on SCx200 HiRes Timer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index 498aa37bca2..3ece6923134 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -51,6 +51,7 @@ void proc_fork_connector(struct task_struct *task)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -58,7 +59,8 @@ void proc_fork_connector(struct task_struct *task)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp); /* get high res monotonic timestamp */
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_FORK;
ev->event_data.fork.parent_pid = task->real_parent->pid;
ev->event_data.fork.parent_tgid = task->real_parent->tgid;
@@ -76,6 +78,7 @@ void proc_exec_connector(struct task_struct *task)
{
struct cn_msg *msg;
struct proc_event *ev;
+ struct timespec ts;
__u8 buffer[CN_PROC_MSG_SIZE];
if (atomic_read(&proc_event_num_listeners) < 1)
@@ -84,7 +87,8 @@ void proc_exec_connector(struct task_struct *task)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_EXEC;
ev->event_data.exec.process_pid = task->pid;
ev->event_data.exec.process_tgid = task->tgid;
@@ -100,6 +104,7 @@ void proc_id_connector(struct task_struct *task, int which_id)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -118,7 +123,8 @@ void proc_id_connector(struct task_struct *task, int which_id)
} else
return;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
memcpy(&msg->id, &cn_proc_event_id, sizeof(msg->id));
msg->ack = 0; /* not used */
@@ -131,6 +137,7 @@ void proc_exit_connector(struct task_struct *task)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -138,7 +145,8 @@ void proc_exit_connector(struct task_struct *task)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
get_seq(&msg->seq, &ev->cpu);
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->what = PROC_EVENT_EXIT;
ev->event_data.exit.process_pid = task->pid;
ev->event_data.exit.process_tgid = task->tgid;
@@ -164,6 +172,7 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
struct cn_msg *msg;
struct proc_event *ev;
__u8 buffer[CN_PROC_MSG_SIZE];
+ struct timespec ts;
if (atomic_read(&proc_event_num_listeners) < 1)
return;
@@ -171,7 +180,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
msg = (struct cn_msg*)buffer;
ev = (struct proc_event*)msg->data;
msg->seq = rcvd_seq;
- ktime_get_ts(&ev->timestamp);
+ ktime_get_ts(&ts); /* get high res monotonic timestamp */
+ ev->timestamp_ns = timespec_to_ns(&ts);
ev->cpu = -1;
ev->what = PROC_EVENT_NONE;
ev->event_data.ack.err = err;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 44d1eca83a7..d35a9f06ab7 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -15,7 +15,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -33,7 +32,7 @@
#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_CORE, "cpufreq-core", msg)
/**
- * The "cpufreq driver" - the arch- or hardware-dependend low
+ * The "cpufreq driver" - the arch- or hardware-dependent low
* level driver of CPUFreq support, and its spinlock. This lock
* also protects the cpufreq_cpu_data array.
*/
@@ -285,39 +284,69 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition);
* SYSFS INTERFACE *
*********************************************************************/
+static struct cpufreq_governor *__find_governor(const char *str_governor)
+{
+ struct cpufreq_governor *t;
+
+ list_for_each_entry(t, &cpufreq_governor_list, governor_list)
+ if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN))
+ return t;
+
+ return NULL;
+}
+
/**
* cpufreq_parse_governor - parse a governor string
*/
static int cpufreq_parse_governor (char *str_governor, unsigned int *policy,
struct cpufreq_governor **governor)
{
+ int err = -EINVAL;
+
if (!cpufreq_driver)
- return -EINVAL;
+ goto out;
+
if (cpufreq_driver->setpolicy) {
if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_PERFORMANCE;
- return 0;
+ err = 0;
} else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) {
*policy = CPUFREQ_POLICY_POWERSAVE;
- return 0;
+ err = 0;
}
- return -EINVAL;
- } else {
+ } else if (cpufreq_driver->target) {
struct cpufreq_governor *t;
+
mutex_lock(&cpufreq_governor_mutex);
- if (!cpufreq_driver || !cpufreq_driver->target)
- goto out;
- list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
- if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) {
- *governor = t;
+
+ t = __find_governor(str_governor);
+
+ if (t == NULL) {
+ char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor);
+
+ if (name) {
+ int ret;
+
mutex_unlock(&cpufreq_governor_mutex);
- return 0;
+ ret = request_module(name);
+ mutex_lock(&cpufreq_governor_mutex);
+
+ if (ret == 0)
+ t = __find_governor(str_governor);
}
+
+ kfree(name);
}
-out:
+
+ if (t != NULL) {
+ *governor = t;
+ err = 0;
+ }
+
mutex_unlock(&cpufreq_governor_mutex);
}
- return -EINVAL;
+ out:
+ return err;
}
@@ -365,10 +394,12 @@ static ssize_t store_##file_name \
if (ret != 1) \
return -EINVAL; \
\
+ lock_cpu_hotplug(); \
mutex_lock(&policy->lock); \
ret = __cpufreq_set_policy(policy, &new_policy); \
policy->user_policy.object = policy->object; \
mutex_unlock(&policy->lock); \
+ unlock_cpu_hotplug(); \
\
return ret ? ret : count; \
}
@@ -424,6 +455,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
if (cpufreq_parse_governor(str_governor, &new_policy.policy, &new_policy.governor))
return -EINVAL;
+ lock_cpu_hotplug();
+
/* Do not use cpufreq_set_policy here or the user_policy.max
will be wrongly overridden */
mutex_lock(&policy->lock);
@@ -433,6 +466,8 @@ static ssize_t store_scaling_governor (struct cpufreq_policy * policy,
policy->user_policy.governor = policy->governor;
mutex_unlock(&policy->lock);
+ unlock_cpu_hotplug();
+
return ret ? ret : count;
}
@@ -1194,20 +1229,18 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
*********************************************************************/
+/* Must be called with lock_cpu_hotplug held */
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
int retval = -EINVAL;
- 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);
- unlock_cpu_hotplug();
-
return retval;
}
EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
@@ -1222,17 +1255,23 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
if (!policy)
return -EINVAL;
+ lock_cpu_hotplug();
mutex_lock(&policy->lock);
ret = __cpufreq_driver_target(policy, target_freq, relation);
mutex_unlock(&policy->lock);
+ unlock_cpu_hotplug();
cpufreq_cpu_put(policy);
return ret;
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
+/*
+ * Locking: Must be called with the lock_cpu_hotplug() lock held
+ * when "event" is CPUFREQ_GOV_LIMITS
+ */
static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
{
@@ -1254,43 +1293,23 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
}
-int cpufreq_governor(unsigned int cpu, unsigned int event)
-{
- int ret = 0;
- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
-
- if (!policy)
- return -EINVAL;
-
- mutex_lock(&policy->lock);
- ret = __cpufreq_governor(policy, event);
- mutex_unlock(&policy->lock);
-
- cpufreq_cpu_put(policy);
- return ret;
-}
-EXPORT_SYMBOL_GPL(cpufreq_governor);
-
-
int cpufreq_register_governor(struct cpufreq_governor *governor)
{
- struct cpufreq_governor *t;
+ int err;
if (!governor)
return -EINVAL;
mutex_lock(&cpufreq_governor_mutex);
- list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
- if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) {
- mutex_unlock(&cpufreq_governor_mutex);
- return -EBUSY;
- }
+ err = -EBUSY;
+ if (__find_governor(governor->name) == NULL) {
+ err = 0;
+ list_add(&governor->governor_list, &cpufreq_governor_list);
}
- list_add(&governor->governor_list, &cpufreq_governor_list);
mutex_unlock(&cpufreq_governor_mutex);
- return 0;
+ return err;
}
EXPORT_SYMBOL_GPL(cpufreq_register_governor);
@@ -1339,6 +1358,9 @@ int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu)
EXPORT_SYMBOL(cpufreq_get_policy);
+/*
+ * Locking: Must be called with the lock_cpu_hotplug() lock held
+ */
static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_policy *policy)
{
int ret = 0;
@@ -1349,6 +1371,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli
memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo));
+ if (policy->min > data->min && policy->min > policy->max) {
+ ret = -EINVAL;
+ goto error_out;
+ }
+
/* verify the cpu speed can be set within this limit */
ret = cpufreq_driver->verify(policy);
if (ret)
@@ -1433,6 +1460,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
if (!data)
return -EINVAL;
+ lock_cpu_hotplug();
+
/* lock this CPU */
mutex_lock(&data->lock);
@@ -1443,6 +1472,8 @@ int cpufreq_set_policy(struct cpufreq_policy *policy)
data->user_policy.governor = data->governor;
mutex_unlock(&data->lock);
+
+ unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
@@ -1466,6 +1497,7 @@ int cpufreq_update_policy(unsigned int cpu)
if (!data)
return -ENODEV;
+ lock_cpu_hotplug();
mutex_lock(&data->lock);
dprintk("updating policy for CPU %u\n", cpu);
@@ -1491,12 +1523,13 @@ int cpufreq_update_policy(unsigned int cpu)
ret = __cpufreq_set_policy(data, &policy);
mutex_unlock(&data->lock);
-
+ unlock_cpu_hotplug();
cpufreq_cpu_put(data);
return ret;
}
EXPORT_SYMBOL(cpufreq_update_policy);
+#ifdef CONFIG_HOTPLUG_CPU
static int cpufreq_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
@@ -1532,10 +1565,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
return NOTIFY_OK;
}
-static struct notifier_block cpufreq_cpu_notifier =
+static struct notifier_block __cpuinitdata cpufreq_cpu_notifier =
{
.notifier_call = cpufreq_cpu_callback,
};
+#endif /* CONFIG_HOTPLUG_CPU */
/*********************************************************************
* REGISTER / UNREGISTER CPUFREQ DRIVER *
@@ -1596,7 +1630,7 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
}
if (!ret) {
- register_cpu_notifier(&cpufreq_cpu_notifier);
+ register_hotcpu_notifier(&cpufreq_cpu_notifier);
dprintk("driver %s up and running\n", driver_data->name);
cpufreq_debug_enable_ratelimit();
}
@@ -1628,7 +1662,7 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
dprintk("unregistering driver %s\n", driver->name);
sysdev_driver_unregister(&cpu_sysdev_class, &cpufreq_sysdev_driver);
- unregister_cpu_notifier(&cpufreq_cpu_notifier);
+ unregister_hotcpu_notifier(&cpufreq_cpu_notifier);
spin_lock_irqsave(&cpufreq_driver_lock, flags);
cpufreq_driver = NULL;
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index b3ebc8f0197..c4c578defab 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -525,7 +525,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
case CPUFREQ_GOV_LIMITS:
- lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur)
__cpufreq_driver_target(
@@ -536,7 +535,6 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
this_dbs_info->cur_policy,
policy->min, CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
- unlock_cpu_hotplug();
break;
}
return 0;
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 693e540481b..bf8aa45d4f0 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -12,22 +12,11 @@
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/smp.h>
#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ctype.h>
#include <linux/cpufreq.h>
-#include <linux/sysctl.h>
-#include <linux/types.h>
-#include <linux/fs.h>
-#include <linux/sysfs.h>
#include <linux/cpu.h>
-#include <linux/sched.h>
-#include <linux/kmod.h>
-#include <linux/workqueue.h>
#include <linux/jiffies.h>
#include <linux/kernel_stat.h>
-#include <linux/percpu.h>
#include <linux/mutex.h>
/*
@@ -56,17 +45,20 @@ static unsigned int def_sampling_rate;
#define MIN_SAMPLING_RATE (def_sampling_rate / MIN_SAMPLING_RATE_RATIO)
#define MAX_SAMPLING_RATE (500 * def_sampling_rate)
#define DEF_SAMPLING_RATE_LATENCY_MULTIPLIER (1000)
-#define DEF_SAMPLING_DOWN_FACTOR (1)
-#define MAX_SAMPLING_DOWN_FACTOR (10)
#define TRANSITION_LATENCY_LIMIT (10 * 1000)
static void do_dbs_timer(void *data);
struct cpu_dbs_info_s {
+ cputime64_t prev_cpu_idle;
+ cputime64_t prev_cpu_wall;
struct cpufreq_policy *cur_policy;
- unsigned int prev_cpu_idle_up;
- unsigned int prev_cpu_idle_down;
+ struct work_struct work;
unsigned int enable;
+ struct cpufreq_frequency_table *freq_table;
+ unsigned int freq_lo;
+ unsigned int freq_lo_jiffies;
+ unsigned int freq_hi_jiffies;
};
static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
@@ -80,31 +72,96 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
* cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
* is recursive for the same process. -Venki
*/
-static DEFINE_MUTEX (dbs_mutex);
-static DECLARE_WORK (dbs_work, do_dbs_timer, NULL);
+static DEFINE_MUTEX(dbs_mutex);
-static struct workqueue_struct *dbs_workq;
+static struct workqueue_struct *kondemand_wq;
-struct dbs_tuners {
+static struct dbs_tuners {
unsigned int sampling_rate;
- unsigned int sampling_down_factor;
unsigned int up_threshold;
unsigned int ignore_nice;
-};
-
-static struct dbs_tuners dbs_tuners_ins = {
+ unsigned int powersave_bias;
+} dbs_tuners_ins = {
.up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
- .sampling_down_factor = DEF_SAMPLING_DOWN_FACTOR,
.ignore_nice = 0,
+ .powersave_bias = 0,
};
-static inline unsigned int get_cpu_idle_time(unsigned int cpu)
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
+{
+ cputime64_t retval;
+
+ retval = cputime64_add(kstat_cpu(cpu).cpustat.idle,
+ kstat_cpu(cpu).cpustat.iowait);
+
+ if (dbs_tuners_ins.ignore_nice)
+ retval = cputime64_add(retval, kstat_cpu(cpu).cpustat.nice);
+
+ return retval;
+}
+
+/*
+ * Find right freq to be set now with powersave_bias on.
+ * Returns the freq_hi to be used right now and will set freq_hi_jiffies,
+ * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
+ */
+static unsigned int powersave_bias_target(struct cpufreq_policy *policy,
+ unsigned int freq_next,
+ unsigned int relation)
+{
+ unsigned int freq_req, freq_reduc, freq_avg;
+ unsigned int freq_hi, freq_lo;
+ unsigned int index = 0;
+ unsigned int jiffies_total, jiffies_hi, jiffies_lo;
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu);
+
+ if (!dbs_info->freq_table) {
+ dbs_info->freq_lo = 0;
+ dbs_info->freq_lo_jiffies = 0;
+ return freq_next;
+ }
+
+ cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
+ relation, &index);
+ freq_req = dbs_info->freq_table[index].frequency;
+ freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000;
+ freq_avg = freq_req - freq_reduc;
+
+ /* Find freq bounds for freq_avg in freq_table */
+ index = 0;
+ cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
+ CPUFREQ_RELATION_H, &index);
+ freq_lo = dbs_info->freq_table[index].frequency;
+ index = 0;
+ cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
+ CPUFREQ_RELATION_L, &index);
+ freq_hi = dbs_info->freq_table[index].frequency;
+
+ /* Find out how long we have to be in hi and lo freqs */
+ if (freq_hi == freq_lo) {
+ dbs_info->freq_lo = 0;
+ dbs_info->freq_lo_jiffies = 0;
+ return freq_lo;
+ }
+ jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+ jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
+ jiffies_hi += ((freq_hi - freq_lo) / 2);
+ jiffies_hi /= (freq_hi - freq_lo);
+ jiffies_lo = jiffies_total - jiffies_hi;
+ dbs_info->freq_lo = freq_lo;
+ dbs_info->freq_lo_jiffies = jiffies_lo;
+ dbs_info->freq_hi_jiffies = jiffies_hi;
+ return freq_hi;
+}
+
+static void ondemand_powersave_bias_init(void)
{
- return kstat_cpu(cpu).cpustat.idle +
- kstat_cpu(cpu).cpustat.iowait +
- ( dbs_tuners_ins.ignore_nice ?
- kstat_cpu(cpu).cpustat.nice :
- 0);
+ int i;
+ for_each_online_cpu(i) {
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, i);
+ dbs_info->freq_table = cpufreq_frequency_get_table(i);
+ dbs_info->freq_lo = 0;
+ }
}
/************************** sysfs interface ************************/
@@ -133,35 +190,16 @@ static ssize_t show_##file_name \
return sprintf(buf, "%u\n", dbs_tuners_ins.object); \
}
show_one(sampling_rate, sampling_rate);
-show_one(sampling_down_factor, sampling_down_factor);
show_one(up_threshold, up_threshold);
show_one(ignore_nice_load, ignore_nice);
-
-static ssize_t store_sampling_down_factor(struct cpufreq_policy *unused,
- const char *buf, size_t count)
-{
- unsigned int input;
- int ret;
- ret = sscanf (buf, "%u", &input);
- if (ret != 1 )
- return -EINVAL;
-
- if (input > MAX_SAMPLING_DOWN_FACTOR || input < 1)
- return -EINVAL;
-
- mutex_lock(&dbs_mutex);
- dbs_tuners_ins.sampling_down_factor = input;
- mutex_unlock(&dbs_mutex);
-
- return count;
-}
+show_one(powersave_bias, powersave_bias);
static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
const char *buf, size_t count)
{
unsigned int input;
int ret;
- ret = sscanf (buf, "%u", &input);
+ ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex);
if (ret != 1 || input > MAX_SAMPLING_RATE || input < MIN_SAMPLING_RATE) {
@@ -180,7 +218,7 @@ static ssize_t store_up_threshold(struct cpufreq_policy *unused,
{
unsigned int input;
int ret;
- ret = sscanf (buf, "%u", &input);
+ ret = sscanf(buf, "%u", &input);
mutex_lock(&dbs_mutex);
if (ret != 1 || input > MAX_FREQUENCY_UP_THRESHOLD ||
@@ -203,7 +241,7 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
unsigned int j;
- ret = sscanf (buf, "%u", &input);
+ ret = sscanf(buf, "%u", &input);
if ( ret != 1 )
return -EINVAL;
@@ -217,34 +255,55 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
}
dbs_tuners_ins.ignore_nice = input;
- /* we need to re-evaluate prev_cpu_idle_up and prev_cpu_idle_down */
+ /* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
- struct cpu_dbs_info_s *j_dbs_info;
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
- j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
- j_dbs_info->prev_cpu_idle_down = j_dbs_info->prev_cpu_idle_up;
+ struct cpu_dbs_info_s *dbs_info;
+ dbs_info = &per_cpu(cpu_dbs_info, j);
+ dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
+ dbs_info->prev_cpu_wall = get_jiffies_64();
}
mutex_unlock(&dbs_mutex);
return count;
}
+static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+
+ if (ret != 1)
+ return -EINVAL;
+
+ if (input > 1000)
+ input = 1000;
+
+ mutex_lock(&dbs_mutex);
+ dbs_tuners_ins.powersave_bias = input;
+ ondemand_powersave_bias_init();
+ mutex_unlock(&dbs_mutex);
+
+ return count;
+}
+
#define define_one_rw(_name) \
static struct freq_attr _name = \
__ATTR(_name, 0644, show_##_name, store_##_name)
define_one_rw(sampling_rate);
-define_one_rw(sampling_down_factor);
define_one_rw(up_threshold);
define_one_rw(ignore_nice_load);
+define_one_rw(powersave_bias);
static struct attribute * dbs_attributes[] = {
&sampling_rate_max.attr,
&sampling_rate_min.attr,
&sampling_rate.attr,
- &sampling_down_factor.attr,
&up_threshold.attr,
&ignore_nice_load.attr,
+ &powersave_bias.attr,
NULL
};
@@ -255,26 +314,30 @@ static struct attribute_group dbs_attr_group = {
/************************** sysfs end ************************/
-static void dbs_check_cpu(int cpu)
+static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
{
- unsigned int idle_ticks, up_idle_ticks, total_ticks;
- unsigned int freq_next;
- unsigned int freq_down_sampling_rate;
- static int down_skip[NR_CPUS];
- struct cpu_dbs_info_s *this_dbs_info;
+ unsigned int idle_ticks, total_ticks;
+ unsigned int load;
+ cputime64_t cur_jiffies;
struct cpufreq_policy *policy;
unsigned int j;
- this_dbs_info = &per_cpu(cpu_dbs_info, cpu);
if (!this_dbs_info->enable)
return;
+ this_dbs_info->freq_lo = 0;
policy = this_dbs_info->cur_policy;
+ cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
+ total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
+ this_dbs_info->prev_cpu_wall);
+ this_dbs_info->prev_cpu_wall = cur_jiffies;
+ if (!total_ticks)
+ return;
/*
* Every sampling_rate, we check, if current idle time is less
* than 20% (default), then we try to increase frequency
- * Every sampling_rate*sampling_down_factor, we look for a the lowest
+ * Every sampling_rate, we look for a the lowest
* frequency which can sustain the load while keeping idle time over
* 30%. If such a frequency exist, we try to decrease to this frequency.
*
@@ -283,123 +346,118 @@ static void dbs_check_cpu(int cpu)
* 5% (default) of current frequency
*/
- /* Check for frequency increase */
+ /* Get Idle Time */
idle_ticks = UINT_MAX;
for_each_cpu_mask(j, policy->cpus) {
- unsigned int tmp_idle_ticks, total_idle_ticks;
+ cputime64_t total_idle_ticks;
+ unsigned int tmp_idle_ticks;
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
total_idle_ticks = get_cpu_idle_time(j);
- tmp_idle_ticks = total_idle_ticks -
- j_dbs_info->prev_cpu_idle_up;
- j_dbs_info->prev_cpu_idle_up = total_idle_ticks;
+ tmp_idle_ticks = (unsigned int) cputime64_sub(total_idle_ticks,
+ j_dbs_info->prev_cpu_idle);
+ j_dbs_info->prev_cpu_idle = total_idle_ticks;
if (tmp_idle_ticks < idle_ticks)
idle_ticks = tmp_idle_ticks;
}
+ load = (100 * (total_ticks - idle_ticks)) / total_ticks;
- /* Scale idle ticks by 100 and compare with up and down ticks */
- idle_ticks *= 100;
- up_idle_ticks = (100 - dbs_tuners_ins.up_threshold) *
- usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
-
- if (idle_ticks < up_idle_ticks) {
- down_skip[cpu] = 0;
- for_each_cpu_mask(j, policy->cpus) {
- struct cpu_dbs_info_s *j_dbs_info;
-
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
- j_dbs_info->prev_cpu_idle_down =
- j_dbs_info->prev_cpu_idle_up;
- }
+ /* Check for frequency increase */
+ if (load > dbs_tuners_ins.up_threshold) {
/* if we are already at full speed then break out early */
- if (policy->cur == policy->max)
- return;
-
- __cpufreq_driver_target(policy, policy->max,
- CPUFREQ_RELATION_H);
+ if (!dbs_tuners_ins.powersave_bias) {
+ if (policy->cur == policy->max)
+ return;
+
+ __cpufreq_driver_target(policy, policy->max,
+ CPUFREQ_RELATION_H);
+ } else {
+ int freq = powersave_bias_target(policy, policy->max,
+ CPUFREQ_RELATION_H);
+ __cpufreq_driver_target(policy, freq,
+ CPUFREQ_RELATION_L);
+ }
return;
}
/* Check for frequency decrease */
- down_skip[cpu]++;
- if (down_skip[cpu] < dbs_tuners_ins.sampling_down_factor)
- return;
-
- idle_ticks = UINT_MAX;
- for_each_cpu_mask(j, policy->cpus) {
- unsigned int tmp_idle_ticks, total_idle_ticks;
- struct cpu_dbs_info_s *j_dbs_info;
-
- j_dbs_info = &per_cpu(cpu_dbs_info, j);
- /* Check for frequency decrease */
- total_idle_ticks = j_dbs_info->prev_cpu_idle_up;
- tmp_idle_ticks = total_idle_ticks -
- j_dbs_info->prev_cpu_idle_down;
- j_dbs_info->prev_cpu_idle_down = total_idle_ticks;
-
- if (tmp_idle_ticks < idle_ticks)
- idle_ticks = tmp_idle_ticks;
- }
-
- down_skip[cpu] = 0;
/* if we cannot reduce the frequency anymore, break out early */
if (policy->cur == policy->min)
return;
- /* Compute how many ticks there are between two measurements */
- freq_down_sampling_rate = dbs_tuners_ins.sampling_rate *
- dbs_tuners_ins.sampling_down_factor;
- total_ticks = usecs_to_jiffies(freq_down_sampling_rate);
-
/*
* The optimal frequency is the frequency that is the lowest that
* can support the current CPU usage without triggering the up
* policy. To be safe, we focus 10 points under the threshold.
*/
- freq_next = ((total_ticks - idle_ticks) * 100) / total_ticks;
- freq_next = (freq_next * policy->cur) /
+ if (load < (dbs_tuners_ins.up_threshold - 10)) {
+ unsigned int freq_next = (policy->cur * load) /
(dbs_tuners_ins.up_threshold - 10);
-
- if (freq_next < policy->min)
- freq_next = policy->min;
-
- if (freq_next <= ((policy->cur * 95) / 100))
- __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L);
+ if (!dbs_tuners_ins.powersave_bias) {
+ __cpufreq_driver_target(policy, freq_next,
+ CPUFREQ_RELATION_L);
+ } else {
+ int freq = powersave_bias_target(policy, freq_next,
+ CPUFREQ_RELATION_L);
+ __cpufreq_driver_target(policy, freq,
+ CPUFREQ_RELATION_L);
+ }
+ }
}
+/* Sampling types */
+enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
+
static void do_dbs_timer(void *data)
{
- int i;
- lock_cpu_hotplug();
- mutex_lock(&dbs_mutex);
- for_each_online_cpu(i)
- dbs_check_cpu(i);
- queue_delayed_work(dbs_workq, &dbs_work,
- usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
- mutex_unlock(&dbs_mutex);
- unlock_cpu_hotplug();
-}
+ unsigned int cpu = smp_processor_id();
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ /* We want all CPUs to do sampling nearly on same jiffy */
+ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+ delay -= jiffies % delay;
-static inline void dbs_timer_init(void)
-{
- INIT_WORK(&dbs_work, do_dbs_timer, NULL);
- if (!dbs_workq)
- dbs_workq = create_singlethread_workqueue("ondemand");
- if (!dbs_workq) {
- printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n");
+ if (!dbs_info->enable)
return;
+ /* Common NORMAL_SAMPLE setup */
+ INIT_WORK(&dbs_info->work, do_dbs_timer, (void *)DBS_NORMAL_SAMPLE);
+ if (!dbs_tuners_ins.powersave_bias ||
+ (unsigned long) data == DBS_NORMAL_SAMPLE) {
+ lock_cpu_hotplug();
+ dbs_check_cpu(dbs_info);
+ unlock_cpu_hotplug();
+ if (dbs_info->freq_lo) {
+ /* Setup timer for SUB_SAMPLE */
+ INIT_WORK(&dbs_info->work, do_dbs_timer,
+ (void *)DBS_SUB_SAMPLE);
+ delay = dbs_info->freq_hi_jiffies;
+ }
+ } else {
+ __cpufreq_driver_target(dbs_info->cur_policy,
+ dbs_info->freq_lo,
+ CPUFREQ_RELATION_H);
}
- queue_delayed_work(dbs_workq, &dbs_work,
- usecs_to_jiffies(dbs_tuners_ins.sampling_rate));
- return;
+ queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
+}
+
+static inline void dbs_timer_init(unsigned int cpu)
+{
+ struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, cpu);
+ /* We want all CPUs to do sampling nearly on same jiffy */
+ int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
+ delay -= jiffies % delay;
+
+ ondemand_powersave_bias_init();
+ INIT_WORK(&dbs_info->work, do_dbs_timer, NULL);
+ queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
}
-static inline void dbs_timer_exit(void)
+static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
{
- if (dbs_workq)
- cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work);
+ dbs_info->enable = 0;
+ cancel_delayed_work(&dbs_info->work);
+ flush_workqueue(kondemand_wq);
}
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
@@ -413,8 +471,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
switch (event) {
case CPUFREQ_GOV_START:
- if ((!cpu_online(cpu)) ||
- (!policy->cur))
+ if ((!cpu_online(cpu)) || (!policy->cur))
return -EINVAL;
if (policy->cpuinfo.transition_latency >
@@ -427,18 +484,26 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
break;
mutex_lock(&dbs_mutex);
+ dbs_enable++;
+ if (dbs_enable == 1) {
+ kondemand_wq = create_workqueue("kondemand");
+ if (!kondemand_wq) {
+ printk(KERN_ERR "Creation of kondemand failed\n");
+ dbs_enable--;
+ mutex_unlock(&dbs_mutex);
+ return -ENOSPC;
+ }
+ }
for_each_cpu_mask(j, policy->cpus) {
struct cpu_dbs_info_s *j_dbs_info;
j_dbs_info = &per_cpu(cpu_dbs_info, j);
j_dbs_info->cur_policy = policy;
- j_dbs_info->prev_cpu_idle_up = get_cpu_idle_time(j);
- j_dbs_info->prev_cpu_idle_down
- = j_dbs_info->prev_cpu_idle_up;
+ j_dbs_info->prev_cpu_idle = get_cpu_idle_time(j);
+ j_dbs_info->prev_cpu_wall = get_jiffies_64();
}
this_dbs_info->enable = 1;
sysfs_create_group(&policy->kobj, &dbs_attr_group);
- dbs_enable++;
/*
* Start the timerschedule work, when this governor
* is used for first time
@@ -457,50 +522,44 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
def_sampling_rate = MIN_STAT_SAMPLING_RATE;
dbs_tuners_ins.sampling_rate = def_sampling_rate;
- dbs_timer_init();
}
+ dbs_timer_init(policy->cpu);
mutex_unlock(&dbs_mutex);
break;
case CPUFREQ_GOV_STOP:
mutex_lock(&dbs_mutex);
- this_dbs_info->enable = 0;
+ dbs_timer_exit(this_dbs_info);
sysfs_remove_group(&policy->kobj, &dbs_attr_group);
dbs_enable--;
- /*
- * Stop the timerschedule work, when this governor
- * is used for first time
- */
if (dbs_enable == 0)
- dbs_timer_exit();
+ destroy_workqueue(kondemand_wq);
mutex_unlock(&dbs_mutex);
break;
case CPUFREQ_GOV_LIMITS:
- lock_cpu_hotplug();
mutex_lock(&dbs_mutex);
if (policy->max < this_dbs_info->cur_policy->cur)
- __cpufreq_driver_target(
- this_dbs_info->cur_policy,
- policy->max, CPUFREQ_RELATION_H);
+ __cpufreq_driver_target(this_dbs_info->cur_policy,
+ policy->max,
+ CPUFREQ_RELATION_H);
else if (policy->min > this_dbs_info->cur_policy->cur)
- __cpufreq_driver_target(
- this_dbs_info->cur_policy,
- policy->min, CPUFREQ_RELATION_L);
+ __cpufreq_driver_target(this_dbs_info->cur_policy,
+ policy->min,
+ CPUFREQ_RELATION_L);
mutex_unlock(&dbs_mutex);
- unlock_cpu_hotplug();
break;
}
return 0;
}
static struct cpufreq_governor cpufreq_gov_dbs = {
- .name = "ondemand",
- .governor = cpufreq_governor_dbs,
- .owner = THIS_MODULE,
+ .name = "ondemand",
+ .governor = cpufreq_governor_dbs,
+ .owner = THIS_MODULE,
};
static int __init cpufreq_gov_dbs_init(void)
@@ -510,21 +569,15 @@ static int __init cpufreq_gov_dbs_init(void)
static void __exit cpufreq_gov_dbs_exit(void)
{
- /* Make sure that the scheduled work is indeed not running.
- Assumes the timer has been cancelled first. */
- if (dbs_workq) {
- flush_workqueue(dbs_workq);
- destroy_workqueue(dbs_workq);
- }
-
cpufreq_unregister_governor(&cpufreq_gov_dbs);
}
-MODULE_AUTHOR ("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
-MODULE_DESCRIPTION ("'cpufreq_ondemand' - A dynamic cpufreq governor for "
- "Low Latency Frequency Transition capable processors");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>");
+MODULE_AUTHOR("Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>");
+MODULE_DESCRIPTION("'cpufreq_ondemand' - A dynamic cpufreq governor for "
+ "Low Latency Frequency Transition capable processors");
+MODULE_LICENSE("GPL");
module_init(cpufreq_gov_dbs_init);
module_exit(cpufreq_gov_dbs_exit);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index c576c0b3f45..c2ecc599dc5 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sysdev.h>
#include <linux/cpu.h>
@@ -350,13 +349,11 @@ __init cpufreq_stats_init(void)
return ret;
}
- register_cpu_notifier(&cpufreq_stat_cpu_notifier);
- lock_cpu_hotplug();
+ register_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
for_each_online_cpu(cpu) {
cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_ONLINE,
(void *)(long)cpu);
}
- unlock_cpu_hotplug();
return 0;
}
static void
@@ -368,7 +365,7 @@ __exit cpufreq_stats_exit(void)
CPUFREQ_POLICY_NOTIFIER);
cpufreq_unregister_notifier(&notifier_trans_block,
CPUFREQ_TRANSITION_NOTIFIER);
- unregister_cpu_notifier(&cpufreq_stat_cpu_notifier);
+ unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
lock_cpu_hotplug();
for_each_online_cpu(cpu) {
cpufreq_stat_cpu_callback(&cpufreq_stat_cpu_notifier, CPU_DEAD,
diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c
index 071ee4f1bbf..a06c204589c 100644
--- a/drivers/cpufreq/cpufreq_userspace.c
+++ b/drivers/cpufreq/cpufreq_userspace.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/smp.h>
@@ -19,6 +18,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/cpufreq.h>
+#include <linux/cpu.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/sysfs.h>
@@ -71,6 +71,7 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
dprintk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
+ lock_cpu_hotplug();
mutex_lock(&userspace_mutex);
if (!cpu_is_managed[policy->cpu])
goto err;
@@ -93,6 +94,7 @@ static int cpufreq_set(unsigned int freq, struct cpufreq_policy *policy)
err:
mutex_unlock(&userspace_mutex);
+ unlock_cpu_hotplug();
return ret;
}
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index 4263935443c..adb554153f6 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -2,22 +2,53 @@ menu "Hardware crypto devices"
config CRYPTO_DEV_PADLOCK
tristate "Support for VIA PadLock ACE"
- depends on CRYPTO && X86_32
+ depends on X86_32
+ select CRYPTO_ALGAPI
+ default m
help
Some VIA processors come with an integrated crypto engine
(so called VIA PadLock ACE, Advanced Cryptography Engine)
- that provides instructions for very fast {en,de}cryption
- with some algorithms.
+ that provides instructions for very fast cryptographic
+ operations with supported algorithms.
The instructions are used only when the CPU supports them.
- Otherwise software encryption is used. If you are unsure,
- say Y.
+ Otherwise software encryption is used.
+
+ Selecting M for this option will compile a helper module
+ padlock.ko that should autoload all below configured
+ algorithms. Don't worry if your hardware does not support
+ some or all of them. In such case padlock.ko will
+ simply write a single line into the kernel log informing
+ about its failure but everything will keep working fine.
+
+ If you are unsure, say M. The compiled module will be
+ called padlock.ko
config CRYPTO_DEV_PADLOCK_AES
- bool "Support for AES in VIA PadLock"
+ tristate "PadLock driver for AES algorithm"
depends on CRYPTO_DEV_PADLOCK
- default y
+ select CRYPTO_BLKCIPHER
+ default m
help
Use VIA PadLock for AES algorithm.
+ Available in VIA C3 and newer CPUs.
+
+ If unsure say M. The compiled module will be
+ called padlock-aes.ko
+
+config CRYPTO_DEV_PADLOCK_SHA
+ tristate "PadLock driver for SHA1 and SHA256 algorithms"
+ depends on CRYPTO_DEV_PADLOCK
+ select CRYPTO_SHA1
+ select CRYPTO_SHA256
+ default m
+ help
+ Use VIA PadLock for SHA1/SHA256 algorithms.
+
+ Available in VIA C7 and newer processors.
+
+ If unsure say M. The compiled module will be
+ called padlock-sha.ko
+
endmenu
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 45426ca19a2..4c3d0ec1cf8 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -1,7 +1,3 @@
-
obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o
-
-padlock-objs-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
-
-padlock-objs := padlock-generic.o $(padlock-objs-y)
-
+obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
+obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index 5158a9db4bc..d4501dc7e65 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -43,11 +43,11 @@
* ---------------------------------------------------------------------------
*/
+#include <crypto/algapi.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/crypto.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <asm/byteorder.h>
@@ -59,16 +59,31 @@
#define AES_EXTENDED_KEY_SIZE 64 /* in uint32_t units */
#define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
+/* Control word. */
+struct cword {
+ unsigned int __attribute__ ((__packed__))
+ rounds:4,
+ algo:3,
+ keygen:1,
+ interm:1,
+ encdec:1,
+ ksize:2;
+} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
+
+/* Whenever making any changes to the following
+ * structure *make sure* you keep E, d_data
+ * and cword aligned on 16 Bytes boundaries!!! */
struct aes_ctx {
- uint32_t e_data[AES_EXTENDED_KEY_SIZE];
- uint32_t d_data[AES_EXTENDED_KEY_SIZE];
struct {
struct cword encrypt;
struct cword decrypt;
} cword;
- uint32_t *E;
- uint32_t *D;
+ u32 *D;
int key_length;
+ u32 E[AES_EXTENDED_KEY_SIZE]
+ __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
+ u32 d_data[AES_EXTENDED_KEY_SIZE]
+ __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
};
/* ====== Key management routines ====== */
@@ -282,25 +297,37 @@ aes_hw_extkey_available(uint8_t key_len)
return 0;
}
-static inline struct aes_ctx *aes_ctx(void *ctx)
+static inline struct aes_ctx *aes_ctx_common(void *ctx)
{
+ unsigned long addr = (unsigned long)ctx;
unsigned long align = PADLOCK_ALIGNMENT;
if (align <= crypto_tfm_ctx_alignment())
align = 1;
- return (struct aes_ctx *)ALIGN((unsigned long)ctx, align);
+ return (struct aes_ctx *)ALIGN(addr, align);
}
-static int
-aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags)
+static inline struct aes_ctx *aes_ctx(struct crypto_tfm *tfm)
{
- struct aes_ctx *ctx = aes_ctx(ctx_arg);
+ return aes_ctx_common(crypto_tfm_ctx(tfm));
+}
+
+static inline struct aes_ctx *blk_aes_ctx(struct crypto_blkcipher *tfm)
+{
+ return aes_ctx_common(crypto_blkcipher_ctx(tfm));
+}
+
+static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct aes_ctx *ctx = aes_ctx(tfm);
const __le32 *key = (const __le32 *)in_key;
+ u32 *flags = &tfm->crt_flags;
uint32_t i, t, u, v, w;
uint32_t P[AES_EXTENDED_KEY_SIZE];
uint32_t rounds;
- if (key_len != 16 && key_len != 24 && key_len != 32) {
+ if (key_len % 8) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
@@ -312,8 +339,7 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t
* itself we must supply the plain key for both encryption
* and decryption.
*/
- ctx->E = ctx->e_data;
- ctx->D = ctx->e_data;
+ ctx->D = ctx->E;
E_KEY[0] = le32_to_cpu(key[0]);
E_KEY[1] = le32_to_cpu(key[1]);
@@ -414,94 +440,224 @@ static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
return iv;
}
-static void
-aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
+static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
- struct aes_ctx *ctx = aes_ctx(ctx_arg);
+ struct aes_ctx *ctx = aes_ctx(tfm);
padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1);
}
-static void
-aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
+static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
- struct aes_ctx *ctx = aes_ctx(ctx_arg);
+ struct aes_ctx *ctx = aes_ctx(tfm);
padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
}
-static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
+static struct crypto_alg aes_alg = {
+ .cra_name = "aes",
+ .cra_driver_name = "aes-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = aes_set_key,
+ .cia_encrypt = aes_encrypt,
+ .cia_decrypt = aes_decrypt,
+ }
+ }
+};
+
+static int ecb_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
- padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt,
- nbytes / AES_BLOCK_SIZE);
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
+ ctx->E, &ctx->cword.encrypt,
+ nbytes / AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
}
-static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
+static int ecb_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
- padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt,
- nbytes / AES_BLOCK_SIZE);
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ padlock_xcrypt_ecb(walk.src.virt.addr, walk.dst.virt.addr,
+ ctx->D, &ctx->cword.decrypt,
+ nbytes / AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
}
-static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
-{
- struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
- u8 *iv;
+static struct crypto_alg ecb_aes_alg = {
+ .cra_name = "ecb(aes)",
+ .cra_driver_name = "ecb-aes-padlock",
+ .cra_priority = PADLOCK_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
+ .cra_type = &crypto_blkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
+ .cra_u = {
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = ecb_aes_encrypt,
+ .decrypt = ecb_aes_decrypt,
+ }
+ }
+};
- iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info,
- &ctx->cword.encrypt, nbytes / AES_BLOCK_SIZE);
- memcpy(desc->info, iv, AES_BLOCK_SIZE);
+static int cbc_aes_encrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
+{
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ u8 *iv = padlock_xcrypt_cbc(walk.src.virt.addr,
+ walk.dst.virt.addr, ctx->E,
+ walk.iv, &ctx->cword.encrypt,
+ nbytes / AES_BLOCK_SIZE);
+ memcpy(walk.iv, iv, AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ return err;
}
-static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
- const u8 *in, unsigned int nbytes)
+static int cbc_aes_decrypt(struct blkcipher_desc *desc,
+ struct scatterlist *dst, struct scatterlist *src,
+ unsigned int nbytes)
{
- struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
- padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt,
- nbytes / AES_BLOCK_SIZE);
- return nbytes & ~(AES_BLOCK_SIZE - 1);
+ struct aes_ctx *ctx = blk_aes_ctx(desc->tfm);
+ struct blkcipher_walk walk;
+ int err;
+
+ blkcipher_walk_init(&walk, dst, src, nbytes);
+ err = blkcipher_walk_virt(desc, &walk);
+
+ while ((nbytes = walk.nbytes)) {
+ padlock_xcrypt_cbc(walk.src.virt.addr, walk.dst.virt.addr,
+ ctx->D, walk.iv, &ctx->cword.decrypt,
+ nbytes / AES_BLOCK_SIZE);
+ nbytes &= AES_BLOCK_SIZE - 1;
+ err = blkcipher_walk_done(desc, &walk, nbytes);
+ }
+
+ return err;
}
-static struct crypto_alg aes_alg = {
- .cra_name = "aes",
- .cra_driver_name = "aes-padlock",
- .cra_priority = 300,
- .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+static struct crypto_alg cbc_aes_alg = {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "cbc-aes-padlock",
+ .cra_priority = PADLOCK_COMPOSITE_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
.cra_alignmask = PADLOCK_ALIGNMENT - 1,
+ .cra_type = &crypto_blkcipher_type,
.cra_module = THIS_MODULE,
- .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
+ .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list),
.cra_u = {
- .cipher = {
- .cia_min_keysize = AES_MIN_KEY_SIZE,
- .cia_max_keysize = AES_MAX_KEY_SIZE,
- .cia_setkey = aes_set_key,
- .cia_encrypt = aes_encrypt,
- .cia_decrypt = aes_decrypt,
- .cia_encrypt_ecb = aes_encrypt_ecb,
- .cia_decrypt_ecb = aes_decrypt_ecb,
- .cia_encrypt_cbc = aes_encrypt_cbc,
- .cia_decrypt_cbc = aes_decrypt_cbc,
+ .blkcipher = {
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .setkey = aes_set_key,
+ .encrypt = cbc_aes_encrypt,
+ .decrypt = cbc_aes_decrypt,
}
}
};
-int __init padlock_init_aes(void)
+static int __init padlock_init(void)
{
- printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
+ int ret;
+
+ if (!cpu_has_xcrypt) {
+ printk(KERN_ERR PFX "VIA PadLock not detected.\n");
+ return -ENODEV;
+ }
+
+ if (!cpu_has_xcrypt_enabled) {
+ printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+ return -ENODEV;
+ }
gen_tabs();
- return crypto_register_alg(&aes_alg);
+ if ((ret = crypto_register_alg(&aes_alg)))
+ goto aes_err;
+
+ if ((ret = crypto_register_alg(&ecb_aes_alg)))
+ goto ecb_aes_err;
+
+ if ((ret = crypto_register_alg(&cbc_aes_alg)))
+ goto cbc_aes_err;
+
+ printk(KERN_NOTICE PFX "Using VIA PadLock ACE for AES algorithm.\n");
+
+out:
+ return ret;
+
+cbc_aes_err:
+ crypto_unregister_alg(&ecb_aes_alg);
+ecb_aes_err:
+ crypto_unregister_alg(&aes_alg);
+aes_err:
+ printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
+ goto out;
}
-void __exit padlock_fini_aes(void)
+static void __exit padlock_fini(void)
{
+ crypto_unregister_alg(&cbc_aes_alg);
+ crypto_unregister_alg(&ecb_aes_alg);
crypto_unregister_alg(&aes_alg);
}
+
+module_init(padlock_init);
+module_exit(padlock_fini);
+
+MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Ludvig");
+
+MODULE_ALIAS("aes-padlock");
diff --git a/drivers/crypto/padlock-generic.c b/drivers/crypto/padlock-generic.c
deleted file mode 100644
index 18cf0e8274a..00000000000
--- a/drivers/crypto/padlock-generic.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for VIA PadLock hardware crypto engine.
- *
- * Copyright (c) 2004 Michal Ludvig <michal@logix.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/crypto.h>
-#include <asm/byteorder.h>
-#include "padlock.h"
-
-static int __init
-padlock_init(void)
-{
- int ret = -ENOSYS;
-
- if (!cpu_has_xcrypt) {
- printk(KERN_ERR PFX "VIA PadLock not detected.\n");
- return -ENODEV;
- }
-
- if (!cpu_has_xcrypt_enabled) {
- printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
- return -ENODEV;
- }
-
-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
- if ((ret = padlock_init_aes())) {
- printk(KERN_ERR PFX "VIA PadLock AES initialization failed.\n");
- return ret;
- }
-#endif
-
- if (ret == -ENOSYS)
- printk(KERN_ERR PFX "Hmm, VIA PadLock was compiled without any algorithm.\n");
-
- return ret;
-}
-
-static void __exit
-padlock_fini(void)
-{
-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
- padlock_fini_aes();
-#endif
-}
-
-module_init(padlock_init);
-module_exit(padlock_fini);
-
-MODULE_DESCRIPTION("VIA PadLock crypto engine support.");
-MODULE_LICENSE("Dual BSD/GPL");
-MODULE_AUTHOR("Michal Ludvig");
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
new file mode 100644
index 00000000000..a781fd23b60
--- /dev/null
+++ b/drivers/crypto/padlock-sha.c
@@ -0,0 +1,318 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for VIA PadLock hardware crypto engine.
+ *
+ * Copyright (c) 2006 Michal Ludvig <michal@logix.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/cryptohash.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include "padlock.h"
+
+#define SHA1_DEFAULT_FALLBACK "sha1-generic"
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_HMAC_BLOCK_SIZE 64
+
+#define SHA256_DEFAULT_FALLBACK "sha256-generic"
+#define SHA256_DIGEST_SIZE 32
+#define SHA256_HMAC_BLOCK_SIZE 64
+
+struct padlock_sha_ctx {
+ char *data;
+ size_t used;
+ int bypass;
+ void (*f_sha_padlock)(const char *in, char *out, int count);
+ struct hash_desc fallback;
+};
+
+static inline struct padlock_sha_ctx *ctx(struct crypto_tfm *tfm)
+{
+ return crypto_tfm_ctx(tfm);
+}
+
+/* We'll need aligned address on the stack */
+#define NEAREST_ALIGNED(ptr) \
+ ((void *)ALIGN((size_t)(ptr), PADLOCK_ALIGNMENT))
+
+static struct crypto_alg sha1_alg, sha256_alg;
+
+static void padlock_sha_bypass(struct crypto_tfm *tfm)
+{
+ if (ctx(tfm)->bypass)
+ return;
+
+ crypto_hash_init(&ctx(tfm)->fallback);
+ if (ctx(tfm)->data && ctx(tfm)->used) {
+ struct scatterlist sg;
+
+ sg_set_buf(&sg, ctx(tfm)->data, ctx(tfm)->used);
+ crypto_hash_update(&ctx(tfm)->fallback, &sg, sg.length);
+ }
+
+ ctx(tfm)->used = 0;
+ ctx(tfm)->bypass = 1;
+}
+
+static void padlock_sha_init(struct crypto_tfm *tfm)
+{
+ ctx(tfm)->used = 0;
+ ctx(tfm)->bypass = 0;
+}
+
+static void padlock_sha_update(struct crypto_tfm *tfm,
+ const uint8_t *data, unsigned int length)
+{
+ /* Our buffer is always one page. */
+ if (unlikely(!ctx(tfm)->bypass &&
+ (ctx(tfm)->used + length > PAGE_SIZE)))
+ padlock_sha_bypass(tfm);
+
+ if (unlikely(ctx(tfm)->bypass)) {
+ struct scatterlist sg;
+ sg_set_buf(&sg, (uint8_t *)data, length);
+ crypto_hash_update(&ctx(tfm)->fallback, &sg, length);
+ return;
+ }
+
+ memcpy(ctx(tfm)->data + ctx(tfm)->used, data, length);
+ ctx(tfm)->used += length;
+}
+
+static inline void padlock_output_block(uint32_t *src,
+ uint32_t *dst, size_t count)
+{
+ while (count--)
+ *dst++ = swab32(*src++);
+}
+
+static void padlock_do_sha1(const char *in, char *out, int count)
+{
+ /* We can't store directly to *out as it may be unaligned. */
+ /* BTW Don't reduce the buffer size below 128 Bytes!
+ * PadLock microcode needs it that big. */
+ char buf[128+16];
+ char *result = NEAREST_ALIGNED(buf);
+
+ ((uint32_t *)result)[0] = 0x67452301;
+ ((uint32_t *)result)[1] = 0xEFCDAB89;
+ ((uint32_t *)result)[2] = 0x98BADCFE;
+ ((uint32_t *)result)[3] = 0x10325476;
+ ((uint32_t *)result)[4] = 0xC3D2E1F0;
+
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xc8" /* rep xsha1 */
+ : "+S"(in), "+D"(result)
+ : "c"(count), "a"(0));
+
+ padlock_output_block((uint32_t *)result, (uint32_t *)out, 5);
+}
+
+static void padlock_do_sha256(const char *in, char *out, int count)
+{
+ /* We can't store directly to *out as it may be unaligned. */
+ /* BTW Don't reduce the buffer size below 128 Bytes!
+ * PadLock microcode needs it that big. */
+ char buf[128+16];
+ char *result = NEAREST_ALIGNED(buf);
+
+ ((uint32_t *)result)[0] = 0x6A09E667;
+ ((uint32_t *)result)[1] = 0xBB67AE85;
+ ((uint32_t *)result)[2] = 0x3C6EF372;
+ ((uint32_t *)result)[3] = 0xA54FF53A;
+ ((uint32_t *)result)[4] = 0x510E527F;
+ ((uint32_t *)result)[5] = 0x9B05688C;
+ ((uint32_t *)result)[6] = 0x1F83D9AB;
+ ((uint32_t *)result)[7] = 0x5BE0CD19;
+
+ asm volatile (".byte 0xf3,0x0f,0xa6,0xd0" /* rep xsha256 */
+ : "+S"(in), "+D"(result)
+ : "c"(count), "a"(0));
+
+ padlock_output_block((uint32_t *)result, (uint32_t *)out, 8);
+}
+
+static void padlock_sha_final(struct crypto_tfm *tfm, uint8_t *out)
+{
+ if (unlikely(ctx(tfm)->bypass)) {
+ crypto_hash_final(&ctx(tfm)->fallback, out);
+ ctx(tfm)->bypass = 0;
+ return;
+ }
+
+ /* Pass the input buffer to PadLock microcode... */
+ ctx(tfm)->f_sha_padlock(ctx(tfm)->data, out, ctx(tfm)->used);
+
+ ctx(tfm)->used = 0;
+}
+
+static int padlock_cra_init(struct crypto_tfm *tfm)
+{
+ const char *fallback_driver_name = tfm->__crt_alg->cra_name;
+ struct crypto_hash *fallback_tfm;
+
+ /* For now we'll allocate one page. This
+ * could eventually be configurable one day. */
+ ctx(tfm)->data = (char *)__get_free_page(GFP_KERNEL);
+ if (!ctx(tfm)->data)
+ return -ENOMEM;
+
+ /* Allocate a fallback and abort if it failed. */
+ fallback_tfm = crypto_alloc_hash(fallback_driver_name, 0,
+ CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK);
+ if (IS_ERR(fallback_tfm)) {
+ printk(KERN_WARNING PFX "Fallback driver '%s' could not be loaded!\n",
+ fallback_driver_name);
+ free_page((unsigned long)(ctx(tfm)->data));
+ return PTR_ERR(fallback_tfm);
+ }
+
+ ctx(tfm)->fallback.tfm = fallback_tfm;
+ return 0;
+}
+
+static int padlock_sha1_cra_init(struct crypto_tfm *tfm)
+{
+ ctx(tfm)->f_sha_padlock = padlock_do_sha1;
+
+ return padlock_cra_init(tfm);
+}
+
+static int padlock_sha256_cra_init(struct crypto_tfm *tfm)
+{
+ ctx(tfm)->f_sha_padlock = padlock_do_sha256;
+
+ return padlock_cra_init(tfm);
+}
+
+static void padlock_cra_exit(struct crypto_tfm *tfm)
+{
+ if (ctx(tfm)->data) {
+ free_page((unsigned long)(ctx(tfm)->data));
+ ctx(tfm)->data = NULL;
+ }
+
+ crypto_free_hash(ctx(tfm)->fallback.tfm);
+ ctx(tfm)->fallback.tfm = NULL;
+}
+
+static struct crypto_alg sha1_alg = {
+ .cra_name = "sha1",
+ .cra_driver_name = "sha1-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA1_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(sha1_alg.cra_list),
+ .cra_init = padlock_sha1_cra_init,
+ .cra_exit = padlock_cra_exit,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize = SHA1_DIGEST_SIZE,
+ .dia_init = padlock_sha_init,
+ .dia_update = padlock_sha_update,
+ .dia_final = padlock_sha_final,
+ }
+ }
+};
+
+static struct crypto_alg sha256_alg = {
+ .cra_name = "sha256",
+ .cra_driver_name = "sha256-padlock",
+ .cra_priority = PADLOCK_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_TYPE_DIGEST |
+ CRYPTO_ALG_NEED_FALLBACK,
+ .cra_blocksize = SHA256_HMAC_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct padlock_sha_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(sha256_alg.cra_list),
+ .cra_init = padlock_sha256_cra_init,
+ .cra_exit = padlock_cra_exit,
+ .cra_u = {
+ .digest = {
+ .dia_digestsize = SHA256_DIGEST_SIZE,
+ .dia_init = padlock_sha_init,
+ .dia_update = padlock_sha_update,
+ .dia_final = padlock_sha_final,
+ }
+ }
+};
+
+static void __init padlock_sha_check_fallbacks(void)
+{
+ if (!crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK))
+ printk(KERN_WARNING PFX
+ "Couldn't load fallback module for sha1.\n");
+
+ if (!crypto_has_hash("sha256", 0, CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_NEED_FALLBACK))
+ printk(KERN_WARNING PFX
+ "Couldn't load fallback module for sha256.\n");
+}
+
+static int __init padlock_init(void)
+{
+ int rc = -ENODEV;
+
+ if (!cpu_has_phe) {
+ printk(KERN_ERR PFX "VIA PadLock Hash Engine not detected.\n");
+ return -ENODEV;
+ }
+
+ if (!cpu_has_phe_enabled) {
+ printk(KERN_ERR PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
+ return -ENODEV;
+ }
+
+ padlock_sha_check_fallbacks();
+
+ rc = crypto_register_alg(&sha1_alg);
+ if (rc)
+ goto out;
+
+ rc = crypto_register_alg(&sha256_alg);
+ if (rc)
+ goto out_unreg1;
+
+ printk(KERN_NOTICE PFX "Using VIA PadLock ACE for SHA1/SHA256 algorithms.\n");
+
+ return 0;
+
+out_unreg1:
+ crypto_unregister_alg(&sha1_alg);
+out:
+ printk(KERN_ERR PFX "VIA PadLock SHA1/SHA256 initialization failed.\n");
+ return rc;
+}
+
+static void __exit padlock_fini(void)
+{
+ crypto_unregister_alg(&sha1_alg);
+ crypto_unregister_alg(&sha256_alg);
+}
+
+module_init(padlock_init);
+module_exit(padlock_fini);
+
+MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Ludvig");
+
+MODULE_ALIAS("sha1-padlock");
+MODULE_ALIAS("sha256-padlock");
diff --git a/drivers/crypto/padlock.c b/drivers/crypto/padlock.c
new file mode 100644
index 00000000000..d6d7dd5bb98
--- /dev/null
+++ b/drivers/crypto/padlock.c
@@ -0,0 +1,58 @@
+/*
+ * Cryptographic API.
+ *
+ * Support for VIA PadLock hardware crypto engine.
+ *
+ * Copyright (c) 2006 Michal Ludvig <michal@logix.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/crypto.h>
+#include <linux/cryptohash.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/scatterlist.h>
+#include "padlock.h"
+
+static int __init padlock_init(void)
+{
+ int success = 0;
+
+ if (crypto_has_cipher("aes-padlock", 0, 0))
+ success++;
+
+ if (crypto_has_hash("sha1-padlock", 0, 0))
+ success++;
+
+ if (crypto_has_hash("sha256-padlock", 0, 0))
+ success++;
+
+ if (!success) {
+ printk(KERN_WARNING PFX "No VIA PadLock drivers have been loaded.\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_NOTICE PFX "%d drivers are available.\n", success);
+
+ return 0;
+}
+
+static void __exit padlock_fini(void)
+{
+}
+
+module_init(padlock_init);
+module_exit(padlock_fini);
+
+MODULE_DESCRIPTION("Load all configured PadLock algorithms.");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Michal Ludvig");
+
diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h
index b78489bc298..b728e4518bd 100644
--- a/drivers/crypto/padlock.h
+++ b/drivers/crypto/padlock.h
@@ -15,22 +15,9 @@
#define PADLOCK_ALIGNMENT 16
-/* Control word. */
-struct cword {
- unsigned int __attribute__ ((__packed__))
- rounds:4,
- algo:3,
- keygen:1,
- interm:1,
- encdec:1,
- ksize:2;
-} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
-
#define PFX "padlock: "
-#ifdef CONFIG_CRYPTO_DEV_PADLOCK_AES
-int padlock_init_aes(void);
-void padlock_fini_aes(void);
-#endif
+#define PADLOCK_CRA_PRIORITY 300
+#define PADLOCK_COMPOSITE_PRIORITY 400
#endif /* _CRYPTO_PADLOCK_H */
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index 5829143558e..15278044295 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -166,8 +166,8 @@ static struct dma_chan *dma_client_chan_alloc(struct dma_client *client)
}
/**
- * dma_client_chan_free - release a DMA channel
- * @chan: &dma_chan
+ * dma_chan_cleanup - release a DMA channel's resources
+ * @kref: kernel reference structure that contains the DMA channel device
*/
void dma_chan_cleanup(struct kref *kref)
{
@@ -199,7 +199,7 @@ static void dma_client_chan_free(struct dma_chan *chan)
* dma_chans_rebalance - reallocate channels to clients
*
* When the number of DMA channel in the system changes,
- * channels need to be rebalanced among clients
+ * channels need to be rebalanced among clients.
*/
static void dma_chans_rebalance(void)
{
@@ -264,7 +264,7 @@ struct dma_client *dma_async_client_register(dma_event_callback event_callback)
/**
* dma_async_client_unregister - unregister a client and free the &dma_client
- * @client:
+ * @client: &dma_client to free
*
* Force frees any allocated DMA channels, frees the &dma_client memory
*/
@@ -306,7 +306,7 @@ void dma_async_client_chan_request(struct dma_client *client,
}
/**
- * dma_async_device_register -
+ * dma_async_device_register - registers DMA devices found
* @device: &dma_device
*/
int dma_async_device_register(struct dma_device *device)
@@ -348,8 +348,8 @@ int dma_async_device_register(struct dma_device *device)
}
/**
- * dma_async_device_unregister -
- * @device: &dma_device
+ * dma_async_device_cleanup - function called when all references are released
+ * @kref: kernel reference object
*/
static void dma_async_device_cleanup(struct kref *kref)
{
@@ -359,7 +359,11 @@ static void dma_async_device_cleanup(struct kref *kref)
complete(&device->done);
}
-void dma_async_device_unregister(struct dma_device* device)
+/**
+ * dma_async_device_unregister - unregisters DMA devices
+ * @device: &dma_device
+ */
+void dma_async_device_unregister(struct dma_device *device)
{
struct dma_chan *chan;
unsigned long flags;
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index 0fdf7fbd649..dbd4d6c3698 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -217,7 +217,7 @@ static void ioat_dma_free_chan_resources(struct dma_chan *chan)
/**
* do_ioat_dma_memcpy - actual function that initiates a IOAT DMA transaction
- * @chan: IOAT DMA channel handle
+ * @ioat_chan: IOAT DMA channel handle
* @dest: DMA destination address
* @src: DMA source address
* @len: transaction length in bytes
@@ -383,7 +383,7 @@ static dma_cookie_t ioat_dma_memcpy_buf_to_pg(struct dma_chan *chan,
* @dest_off: offset into that page
* @src_pg: pointer to the page to copy from
* @src_off: offset into that page
- * @len: transaction length in bytes. This is guaranteed to not make a copy
+ * @len: transaction length in bytes. This is guaranteed not to make a copy
* across a page boundary.
*/
@@ -407,7 +407,7 @@ static dma_cookie_t ioat_dma_memcpy_pg_to_pg(struct dma_chan *chan,
}
/**
- * ioat_dma_memcpy_issue_pending - push potentially unrecognoized appended descriptors to hw
+ * ioat_dma_memcpy_issue_pending - push potentially unrecognized appended descriptors to hw
* @chan: DMA channel handle
*/
@@ -510,6 +510,8 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *chan)
* ioat_dma_is_complete - poll the status of a IOAT DMA transaction
* @chan: IOAT DMA channel handle
* @cookie: DMA transaction identifier
+ * @done: if not %NULL, updated with last completed transaction
+ * @used: if not %NULL, updated with last used transaction
*/
static enum dma_status ioat_dma_is_complete(struct dma_chan *chan,
@@ -739,7 +741,7 @@ static int __devinit ioat_probe(struct pci_dev *pdev,
device->msi = 0;
}
#endif
- err = request_irq(pdev->irq, &ioat_do_interrupt, SA_SHIRQ, "ioat",
+ err = request_irq(pdev->irq, &ioat_do_interrupt, IRQF_SHARED, "ioat",
device);
if (err)
goto err_irq;
@@ -824,10 +826,9 @@ static int __init ioat_init_module(void)
{
/* it's currently unsafe to unload this module */
/* if forced, worst case is that rmmod hangs */
- if (THIS_MODULE != NULL)
- THIS_MODULE->unsafe = 1;
+ __unsafe(THIS_MODULE);
- return pci_module_init(&ioat_pci_drv);
+ return pci_register_driver(&ioat_pci_drv);
}
module_init(ioat_init_module);
diff --git a/drivers/dma/ioatdma_registers.h b/drivers/dma/ioatdma_registers.h
index 41a21ab2b00..a30c7349075 100644
--- a/drivers/dma/ioatdma_registers.h
+++ b/drivers/dma/ioatdma_registers.h
@@ -76,7 +76,7 @@
#define IOAT_CHANSTS_OFFSET 0x04 /* 64-bit Channel Status Register */
#define IOAT_CHANSTS_OFFSET_LOW 0x04
#define IOAT_CHANSTS_OFFSET_HIGH 0x08
-#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR 0xFFFFFFFFFFFFFFC0
+#define IOAT_CHANSTS_COMPLETED_DESCRIPTOR_ADDR 0xFFFFFFFFFFFFFFC0UL
#define IOAT_CHANSTS_SOFT_ERR 0x0000000000000010
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS 0x0000000000000007
#define IOAT_CHANSTS_DMA_TRANSFER_STATUS_ACTIVE 0x0
diff --git a/drivers/dma/iovlock.c b/drivers/dma/iovlock.c
index 5ed327e453a..d637555a833 100644
--- a/drivers/dma/iovlock.c
+++ b/drivers/dma/iovlock.c
@@ -31,7 +31,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
-int num_pages_spanned(struct iovec *iov)
+static int num_pages_spanned(struct iovec *iov)
{
return
((PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) -
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index 53423ad6d4a..f79f6b587bf 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -20,6 +19,9 @@
#include <linux/slab.h>
#include "edac_mc.h"
+#define AMD76X_REVISION " Ver: 2.0.1 " __DATE__
+#define EDAC_MOD_STR "amd76x_edac"
+
#define amd76x_printk(level, fmt, arg...) \
edac_printk(level, "amd76x", fmt, ##arg)
@@ -102,15 +104,18 @@ static const struct amd76x_dev_info amd76x_devs[] = {
static void amd76x_get_error_info(struct mem_ctl_info *mci,
struct amd76x_error_info *info)
{
- pci_read_config_dword(mci->pdev, AMD76X_ECC_MODE_STATUS,
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+ pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS,
&info->ecc_mode_status);
if (info->ecc_mode_status & BIT(8))
- pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS,
+ pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
(u32) BIT(8), (u32) BIT(8));
if (info->ecc_mode_status & BIT(9))
- pci_write_bits32(mci->pdev, AMD76X_ECC_MODE_STATUS,
+ pci_write_bits32(pdev, AMD76X_ECC_MODE_STATUS,
(u32) BIT(9), (u32) BIT(9));
}
@@ -176,6 +181,38 @@ static void amd76x_check(struct mem_ctl_info *mci)
amd76x_process_error_info(mci, &info, 1);
}
+static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
+ enum edac_type edac_mode)
+{
+ struct csrow_info *csrow;
+ u32 mba, mba_base, mba_mask, dms;
+ int index;
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+
+ /* find the DRAM Chip Select Base address and mask */
+ pci_read_config_dword(pdev,
+ AMD76X_MEM_BASE_ADDR + (index * 4),
+ &mba);
+
+ if (!(mba & BIT(0)))
+ continue;
+
+ mba_base = mba & 0xff800000UL;
+ mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
+ pci_read_config_dword(pdev, AMD76X_DRAM_MODE_STATUS, &dms);
+ csrow->first_page = mba_base >> PAGE_SHIFT;
+ csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
+ csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
+ csrow->page_mask = mba_mask >> PAGE_SHIFT;
+ csrow->grain = csrow->nr_pages << PAGE_SHIFT;
+ csrow->mtype = MEM_RDDR;
+ csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
+ csrow->edac_mode = edac_mode;
+ }
+}
+
/**
* amd76x_probe1 - Perform set up for detected device
* @pdev; PCI device detected
@@ -187,15 +224,13 @@ static void amd76x_check(struct mem_ctl_info *mci)
*/
static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
{
- int rc = -ENODEV;
- int index;
- struct mem_ctl_info *mci = NULL;
- enum edac_type ems_modes[] = {
+ static const enum edac_type ems_modes[] = {
EDAC_NONE,
EDAC_EC,
EDAC_SECDED,
EDAC_SECDED
};
+ struct mem_ctl_info *mci = NULL;
u32 ems;
u32 ems_mode;
struct amd76x_error_info discard;
@@ -206,53 +241,28 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS);
if (mci == NULL) {
- rc = -ENOMEM;
- goto fail;
+ return -ENOMEM;
}
debugf0("%s(): mci = %p\n", __func__, mci);
- mci->pdev = pdev;
+ mci->dev = &pdev->dev;
mci->mtype_cap = MEM_FLAG_RDDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
mci->edac_cap = ems_mode ?
(EDAC_FLAG_EC | EDAC_FLAG_SECDED) : EDAC_FLAG_NONE;
mci->mod_name = EDAC_MOD_STR;
- mci->mod_ver = "$Revision: 1.4.2.5 $";
+ mci->mod_ver = AMD76X_REVISION;
mci->ctl_name = amd76x_devs[dev_idx].ctl_name;
mci->edac_check = amd76x_check;
mci->ctl_page_to_phys = NULL;
- for (index = 0; index < mci->nr_csrows; index++) {
- struct csrow_info *csrow = &mci->csrows[index];
- u32 mba;
- u32 mba_base;
- u32 mba_mask;
- u32 dms;
-
- /* find the DRAM Chip Select Base address and mask */
- pci_read_config_dword(mci->pdev,
- AMD76X_MEM_BASE_ADDR + (index * 4), &mba);
-
- if (!(mba & BIT(0)))
- continue;
-
- mba_base = mba & 0xff800000UL;
- mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
- pci_read_config_dword(mci->pdev, AMD76X_DRAM_MODE_STATUS,
- &dms);
- csrow->first_page = mba_base >> PAGE_SHIFT;
- csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
- csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
- csrow->page_mask = mba_mask >> PAGE_SHIFT;
- csrow->grain = csrow->nr_pages << PAGE_SHIFT;
- csrow->mtype = MEM_RDDR;
- csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
- csrow->edac_mode = ems_modes[ems_mode];
- }
-
+ amd76x_init_csrows(mci, pdev, ems_modes[ems_mode]);
amd76x_get_error_info(mci, &discard); /* clear counters */
- if (edac_mc_add_mc(mci)) {
+ /* Here we assume that we will never see multiple instances of this
+ * type of memory controller. The ID is therefore hardcoded to 0.
+ */
+ if (edac_mc_add_mc(mci,0)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
@@ -262,9 +272,8 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
return 0;
fail:
- if (mci != NULL)
- edac_mc_free(mci);
- return rc;
+ edac_mc_free(mci);
+ return -ENODEV;
}
/* returns count (>= 0), or negative on error */
@@ -291,7 +300,7 @@ static void __devexit amd76x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
- if ((mci = edac_mc_del_mc(pdev)) == NULL)
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
edac_mc_free(mci);
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index fce31936e6d..c82bc0ed7f1 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -25,6 +24,9 @@
#include <linux/slab.h>
#include "edac_mc.h"
+#define E752X_REVISION " Ver: 2.0.1 " __DATE__
+#define EDAC_MOD_STR "e752x_edac"
+
static int force_function_unhide;
#define e752x_printk(level, fmt, arg...) \
@@ -763,22 +765,174 @@ static void e752x_check(struct mem_ctl_info *mci)
e752x_process_error_info(mci, &info, 1);
}
-static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
+/* Return 1 if dual channel mode is active. Else return 0. */
+static inline int dual_channel_active(u16 ddrcsr)
+{
+ return (((ddrcsr >> 12) & 3) == 3);
+}
+
+static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
+ u16 ddrcsr)
+{
+ struct csrow_info *csrow;
+ unsigned long last_cumul_size;
+ int index, mem_dev, drc_chan;
+ int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
+ int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
+ u8 value;
+ u32 dra, drc, cumul_size;
+
+ pci_read_config_dword(pdev, E752X_DRA, &dra);
+ pci_read_config_dword(pdev, E752X_DRC, &drc);
+ drc_chan = dual_channel_active(ddrcsr);
+ drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
+ drc_ddim = (drc >> 20) & 0x3;
+
+ /* The dram row boundary (DRB) reg values are boundary address for
+ * each DRAM row with a granularity of 64 or 128MB (single/dual
+ * channel operation). DRB regs are cumulative; therefore DRB7 will
+ * contain the total memory contained in all eight rows.
+ */
+ for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
+ /* mem_dev 0=x8, 1=x4 */
+ mem_dev = (dra >> (index * 4 + 2)) & 0x3;
+ csrow = &mci->csrows[index];
+
+ mem_dev = (mem_dev == 2);
+ pci_read_config_byte(pdev, E752X_DRB + index, &value);
+ /* convert a 128 or 64 MiB DRB to a page size. */
+ cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
+ debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+ cumul_size);
+ if (cumul_size == last_cumul_size)
+ continue; /* not populated */
+
+ csrow->first_page = last_cumul_size;
+ csrow->last_page = cumul_size - 1;
+ csrow->nr_pages = cumul_size - last_cumul_size;
+ last_cumul_size = cumul_size;
+ csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
+ csrow->mtype = MEM_RDDR; /* only one type supported */
+ csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
+
+ /*
+ * if single channel or x8 devices then SECDED
+ * if dual channel and x4 then S4ECD4ED
+ */
+ if (drc_ddim) {
+ if (drc_chan && mem_dev) {
+ csrow->edac_mode = EDAC_S4ECD4ED;
+ mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
+ } else {
+ csrow->edac_mode = EDAC_SECDED;
+ mci->edac_cap |= EDAC_FLAG_SECDED;
+ }
+ } else
+ csrow->edac_mode = EDAC_NONE;
+ }
+}
+
+static void e752x_init_mem_map_table(struct pci_dev *pdev,
+ struct e752x_pvt *pvt)
{
- int rc = -ENODEV;
int index;
+ u8 value, last, row, stat8;
+
+ last = 0;
+ row = 0;
+
+ for (index = 0; index < 8; index += 2) {
+ pci_read_config_byte(pdev, E752X_DRB + index, &value);
+ /* test if there is a dimm in this slot */
+ if (value == last) {
+ /* no dimm in the slot, so flag it as empty */
+ pvt->map[index] = 0xff;
+ pvt->map[index + 1] = 0xff;
+ } else { /* there is a dimm in the slot */
+ pvt->map[index] = row;
+ row++;
+ last = value;
+ /* test the next value to see if the dimm is double
+ * sided
+ */
+ pci_read_config_byte(pdev, E752X_DRB + index + 1,
+ &value);
+ pvt->map[index + 1] = (value == last) ?
+ 0xff : /* the dimm is single sided,
+ so flag as empty */
+ row; /* this is a double sided dimm
+ to save the next row # */
+ row++;
+ last = value;
+ }
+ }
+
+ /* set the map type. 1 = normal, 0 = reversed */
+ pci_read_config_byte(pdev, E752X_DRM, &stat8);
+ pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
+}
+
+/* Return 0 on success or 1 on failure. */
+static int e752x_get_devs(struct pci_dev *pdev, int dev_idx,
+ struct e752x_pvt *pvt)
+{
+ struct pci_dev *dev;
+
+ pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
+ pvt->dev_info->err_dev,
+ pvt->bridge_ck);
+
+ if (pvt->bridge_ck == NULL)
+ pvt->bridge_ck = pci_scan_single_device(pdev->bus,
+ PCI_DEVFN(0, 1));
+
+ if (pvt->bridge_ck == NULL) {
+ e752x_printk(KERN_ERR, "error reporting device not found:"
+ "vendor %x device 0x%x (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
+ return 1;
+ }
+
+ dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
+ NULL);
+
+ if (dev == NULL)
+ goto fail;
+
+ pvt->dev_d0f0 = dev;
+ pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
+
+ return 0;
+
+fail:
+ pci_dev_put(pvt->bridge_ck);
+ return 1;
+}
+
+static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
+{
+ struct pci_dev *dev;
+
+ dev = pvt->dev_d0f1;
+ /* Turn off error disable & SMI in case the BIOS turned it on */
+ pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
+ pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
+ pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00);
+ pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
+ pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
+ pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
+ pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
+ pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
+}
+
+static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
+{
u16 pci_data;
u8 stat8;
- struct mem_ctl_info *mci = NULL;
- struct e752x_pvt *pvt = NULL;
+ struct mem_ctl_info *mci;
+ struct e752x_pvt *pvt;
u16 ddrcsr;
- u32 drc;
int drc_chan; /* Number of channels 0=1chan,1=2chan */
- int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
- int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
- u32 dra;
- unsigned long last_cumul_size;
- struct pci_dev *dev = NULL;
struct e752x_error_info discard;
debugf0("%s(): mci\n", __func__);
@@ -792,25 +946,20 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
if (!force_function_unhide && !(stat8 & (1 << 5))) {
printk(KERN_INFO "Contact your BIOS vendor to see if the "
"E752x error registers can be safely un-hidden\n");
- goto fail;
+ return -ENOMEM;
}
stat8 |= (1 << 5);
pci_write_config_byte(pdev, E752X_DEVPRES1, stat8);
- /* need to find out the number of channels */
- pci_read_config_dword(pdev, E752X_DRC, &drc);
pci_read_config_word(pdev, E752X_DDRCSR, &ddrcsr);
/* FIXME: should check >>12 or 0xf, true for all? */
/* Dual channel = 1, Single channel = 0 */
- drc_chan = (((ddrcsr >> 12) & 3) == 3);
- drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
- drc_ddim = (drc >> 20) & 0x3;
+ drc_chan = dual_channel_active(ddrcsr);
mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1);
if (mci == NULL) {
- rc = -ENOMEM;
- goto fail;
+ return -ENOMEM;
}
debugf3("%s(): init mci\n", __func__);
@@ -819,159 +968,54 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
EDAC_FLAG_S4ECD4ED;
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
- mci->mod_ver = "$Revision: 1.5.2.11 $";
- mci->pdev = pdev;
+ mci->mod_ver = E752X_REVISION;
+ mci->dev = &pdev->dev;
debugf3("%s(): init pvt\n", __func__);
pvt = (struct e752x_pvt *) mci->pvt_info;
pvt->dev_info = &e752x_devs[dev_idx];
- pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev,
- pvt->bridge_ck);
-
- if (pvt->bridge_ck == NULL)
- pvt->bridge_ck = pci_scan_single_device(pdev->bus,
- PCI_DEVFN(0, 1));
+ pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
- if (pvt->bridge_ck == NULL) {
- e752x_printk(KERN_ERR, "error reporting device not found:"
- "vendor %x device 0x%x (broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].err_dev);
- goto fail;
+ if (e752x_get_devs(pdev, dev_idx, pvt)) {
+ edac_mc_free(mci);
+ return -ENODEV;
}
- pvt->mc_symmetric = ((ddrcsr & 0x10) != 0);
debugf3("%s(): more mci init\n", __func__);
mci->ctl_name = pvt->dev_info->ctl_name;
mci->edac_check = e752x_check;
mci->ctl_page_to_phys = ctl_page_to_phys;
- /* find out the device types */
- pci_read_config_dword(pdev, E752X_DRA, &dra);
-
- /*
- * The dram row boundary (DRB) reg values are boundary address for
- * each DRAM row with a granularity of 64 or 128MB (single/dual
- * channel operation). DRB regs are cumulative; therefore DRB7 will
- * contain the total memory contained in all eight rows.
- */
- for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
- u8 value;
- u32 cumul_size;
-
- /* mem_dev 0=x8, 1=x4 */
- int mem_dev = (dra >> (index * 4 + 2)) & 0x3;
- struct csrow_info *csrow = &mci->csrows[index];
-
- mem_dev = (mem_dev == 2);
- pci_read_config_byte(mci->pdev, E752X_DRB + index, &value);
- /* convert a 128 or 64 MiB DRB to a page size. */
- cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
- debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
- cumul_size);
-
- if (cumul_size == last_cumul_size)
- continue; /* not populated */
-
- csrow->first_page = last_cumul_size;
- csrow->last_page = cumul_size - 1;
- csrow->nr_pages = cumul_size - last_cumul_size;
- last_cumul_size = cumul_size;
- csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
- csrow->mtype = MEM_RDDR; /* only one type supported */
- csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
-
- /*
- * if single channel or x8 devices then SECDED
- * if dual channel and x4 then S4ECD4ED
- */
- if (drc_ddim) {
- if (drc_chan && mem_dev) {
- csrow->edac_mode = EDAC_S4ECD4ED;
- mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
- } else {
- csrow->edac_mode = EDAC_SECDED;
- mci->edac_cap |= EDAC_FLAG_SECDED;
- }
- } else
- csrow->edac_mode = EDAC_NONE;
- }
-
- /* Fill in the memory map table */
- {
- u8 value;
- u8 last = 0;
- u8 row = 0;
-
- for (index = 0; index < 8; index += 2) {
- pci_read_config_byte(mci->pdev, E752X_DRB + index,
- &value);
-
- /* test if there is a dimm in this slot */
- if (value == last) {
- /* no dimm in the slot, so flag it as empty */
- pvt->map[index] = 0xff;
- pvt->map[index + 1] = 0xff;
- } else { /* there is a dimm in the slot */
- pvt->map[index] = row;
- row++;
- last = value;
- /* test the next value to see if the dimm is
- double sided */
- pci_read_config_byte(mci->pdev,
- E752X_DRB + index + 1,
- &value);
- pvt->map[index + 1] = (value == last) ?
- 0xff : /* the dimm is single sided,
- * so flag as empty
- */
- row; /* this is a double sided dimm
- * to save the next row #
- */
- row++;
- last = value;
- }
- }
- }
+ e752x_init_csrows(mci, pdev, ddrcsr);
+ e752x_init_mem_map_table(pdev, pvt);
/* set the map type. 1 = normal, 0 = reversed */
- pci_read_config_byte(mci->pdev, E752X_DRM, &stat8);
+ pci_read_config_byte(pdev, E752X_DRM, &stat8);
pvt->map_type = ((stat8 & 0x0f) > ((stat8 >> 4) & 0x0f));
mci->edac_cap |= EDAC_FLAG_NONE;
debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
/* load the top of low memory, remap base, and remap limit vars */
- pci_read_config_word(mci->pdev, E752X_TOLM, &pci_data);
+ pci_read_config_word(pdev, E752X_TOLM, &pci_data);
pvt->tolm = ((u32) pci_data) << 4;
- pci_read_config_word(mci->pdev, E752X_REMAPBASE, &pci_data);
+ pci_read_config_word(pdev, E752X_REMAPBASE, &pci_data);
pvt->remapbase = ((u32) pci_data) << 14;
- pci_read_config_word(mci->pdev, E752X_REMAPLIMIT, &pci_data);
+ pci_read_config_word(pdev, E752X_REMAPLIMIT, &pci_data);
pvt->remaplimit = ((u32) pci_data) << 14;
e752x_printk(KERN_INFO,
"tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
pvt->remapbase, pvt->remaplimit);
- if (edac_mc_add_mc(mci)) {
+ /* Here we assume that we will never see multiple instances of this
+ * type of memory controller. The ID is therefore hardcoded to 0.
+ */
+ if (edac_mc_add_mc(mci,0)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
- dev = pci_get_device(PCI_VENDOR_ID_INTEL, e752x_devs[dev_idx].ctl_dev,
- NULL);
- pvt->dev_d0f0 = dev;
- /* find the error reporting device and clear errors */
- dev = pvt->dev_d0f1 = pci_dev_get(pvt->bridge_ck);
- /* Turn off error disable & SMI in case the BIOS turned it on */
- pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
- pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
- pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00);
- pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
- pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
- pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
- pci_write_config_byte(dev, E752X_DRAM_ERRMASK, 0x00);
- pci_write_config_byte(dev, E752X_DRAM_SMICMD, 0x00);
-
+ e752x_init_error_reporting_regs(pvt);
e752x_get_error_info(mci, &discard); /* clear other MCH errors */
/* get this far and it's successful */
@@ -979,20 +1023,12 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
return 0;
fail:
- if (mci) {
- if (pvt->dev_d0f0)
- pci_dev_put(pvt->dev_d0f0);
-
- if (pvt->dev_d0f1)
- pci_dev_put(pvt->dev_d0f1);
-
- if (pvt->bridge_ck)
- pci_dev_put(pvt->bridge_ck);
-
- edac_mc_free(mci);
- }
+ pci_dev_put(pvt->dev_d0f0);
+ pci_dev_put(pvt->dev_d0f1);
+ pci_dev_put(pvt->bridge_ck);
+ edac_mc_free(mci);
- return rc;
+ return -ENODEV;
}
/* returns count (>= 0), or negative on error */
@@ -1015,7 +1051,7 @@ static void __devexit e752x_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
- if ((mci = edac_mc_del_mc(pdev)) == NULL)
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
pvt = (struct e752x_pvt *) mci->pvt_info;
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index a9518d3e4be..310d91b41c9 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -30,6 +29,9 @@
#include <linux/slab.h>
#include "edac_mc.h"
+#define E7XXX_REVISION " Ver: 2.0.1 " __DATE__
+#define EDAC_MOD_STR "e7xxx_edac"
+
#define e7xxx_printk(level, fmt, arg...) \
edac_printk(level, "e7xxx", fmt, ##arg)
@@ -333,99 +335,61 @@ static void e7xxx_check(struct mem_ctl_info *mci)
e7xxx_process_error_info(mci, &info, 1);
}
-static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
+/* Return 1 if dual channel mode is active. Else return 0. */
+static inline int dual_channel_active(u32 drc, int dev_idx)
{
- int rc = -ENODEV;
- int index;
- u16 pci_data;
- struct mem_ctl_info *mci = NULL;
- struct e7xxx_pvt *pvt = NULL;
- u32 drc;
- int drc_chan = 1; /* Number of channels 0=1chan,1=2chan */
- int drc_drbg = 1; /* DRB granularity 0=32mb,1=64mb */
- int drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
- u32 dra;
- unsigned long last_cumul_size;
- struct e7xxx_error_info discard;
-
- debugf0("%s(): mci\n", __func__);
+ return (dev_idx == E7501) ? ((drc >> 22) & 0x1) : 1;
+}
- /* need to find out the number of channels */
- pci_read_config_dword(pdev, E7XXX_DRC, &drc);
+/* Return DRB granularity (0=32mb, 1=64mb). */
+static inline int drb_granularity(u32 drc, int dev_idx)
+{
/* only e7501 can be single channel */
- if (dev_idx == E7501) {
- drc_chan = ((drc >> 22) & 0x1);
- drc_drbg = (drc >> 18) & 0x3;
- }
-
- drc_ddim = (drc >> 20) & 0x3;
- mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
-
- if (mci == NULL) {
- rc = -ENOMEM;
- goto fail;
- }
-
- debugf3("%s(): init mci\n", __func__);
- mci->mtype_cap = MEM_FLAG_RDDR;
- mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
- EDAC_FLAG_S4ECD4ED;
- /* FIXME - what if different memory types are in different csrows? */
- mci->mod_name = EDAC_MOD_STR;
- mci->mod_ver = "$Revision: 1.5.2.9 $";
- mci->pdev = pdev;
+ return (dev_idx == E7501) ? ((drc >> 18) & 0x3) : 1;
+}
- debugf3("%s(): init pvt\n", __func__);
- pvt = (struct e7xxx_pvt *) mci->pvt_info;
- pvt->dev_info = &e7xxx_devs[dev_idx];
- pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
- pvt->dev_info->err_dev,
- pvt->bridge_ck);
- if (!pvt->bridge_ck) {
- e7xxx_printk(KERN_ERR, "error reporting device not found:"
- "vendor %x device 0x%x (broken BIOS?)\n",
- PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev);
- goto fail;
- }
-
- debugf3("%s(): more mci init\n", __func__);
- mci->ctl_name = pvt->dev_info->ctl_name;
- mci->edac_check = e7xxx_check;
- mci->ctl_page_to_phys = ctl_page_to_phys;
+static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
+ int dev_idx, u32 drc)
+{
+ unsigned long last_cumul_size;
+ int index;
+ u8 value;
+ u32 dra, cumul_size;
+ int drc_chan, drc_drbg, drc_ddim, mem_dev;
+ struct csrow_info *csrow;
- /* find out the device types */
pci_read_config_dword(pdev, E7XXX_DRA, &dra);
+ drc_chan = dual_channel_active(drc, dev_idx);
+ drc_drbg = drb_granularity(drc, dev_idx);
+ drc_ddim = (drc >> 20) & 0x3;
+ last_cumul_size = 0;
- /*
- * The dram row boundary (DRB) reg values are boundary address
+ /* The dram row boundary (DRB) reg values are boundary address
* for each DRAM row with a granularity of 32 or 64MB (single/dual
* channel operation). DRB regs are cumulative; therefore DRB7 will
* contain the total memory contained in all eight rows.
*/
- for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
- u8 value;
- u32 cumul_size;
+ for (index = 0; index < mci->nr_csrows; index++) {
/* mem_dev 0=x8, 1=x4 */
- int mem_dev = (dra >> (index * 4 + 3)) & 0x1;
- struct csrow_info *csrow = &mci->csrows[index];
+ mem_dev = (dra >> (index * 4 + 3)) & 0x1;
+ csrow = &mci->csrows[index];
- pci_read_config_byte(mci->pdev, E7XXX_DRB + index, &value);
+ pci_read_config_byte(pdev, E7XXX_DRB + index, &value);
/* convert a 64 or 32 MiB DRB to a page size. */
cumul_size = value << (25 + drc_drbg - PAGE_SHIFT);
debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
cumul_size);
-
if (cumul_size == last_cumul_size)
- continue; /* not populated */
+ continue; /* not populated */
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
- csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
- csrow->mtype = MEM_RDDR; /* only one type supported */
+ csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
+ csrow->mtype = MEM_RDDR; /* only one type supported */
csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
/*
@@ -443,16 +407,61 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
} else
csrow->edac_mode = EDAC_NONE;
}
+}
- mci->edac_cap |= EDAC_FLAG_NONE;
+static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ u16 pci_data;
+ struct mem_ctl_info *mci = NULL;
+ struct e7xxx_pvt *pvt = NULL;
+ u32 drc;
+ int drc_chan;
+ struct e7xxx_error_info discard;
+
+ debugf0("%s(): mci\n", __func__);
+ pci_read_config_dword(pdev, E7XXX_DRC, &drc);
+
+ drc_chan = dual_channel_active(drc, dev_idx);
+ mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1);
+
+ if (mci == NULL)
+ return -ENOMEM;
+
+ debugf3("%s(): init mci\n", __func__);
+ mci->mtype_cap = MEM_FLAG_RDDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
+ EDAC_FLAG_S4ECD4ED;
+ /* FIXME - what if different memory types are in different csrows? */
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = E7XXX_REVISION;
+ mci->dev = &pdev->dev;
+ debugf3("%s(): init pvt\n", __func__);
+ pvt = (struct e7xxx_pvt *) mci->pvt_info;
+ pvt->dev_info = &e7xxx_devs[dev_idx];
+ pvt->bridge_ck = pci_get_device(PCI_VENDOR_ID_INTEL,
+ pvt->dev_info->err_dev,
+ pvt->bridge_ck);
+ if (!pvt->bridge_ck) {
+ e7xxx_printk(KERN_ERR, "error reporting device not found:"
+ "vendor %x device 0x%x (broken BIOS?)\n",
+ PCI_VENDOR_ID_INTEL, e7xxx_devs[dev_idx].err_dev);
+ goto fail0;
+ }
+
+ debugf3("%s(): more mci init\n", __func__);
+ mci->ctl_name = pvt->dev_info->ctl_name;
+ mci->edac_check = e7xxx_check;
+ mci->ctl_page_to_phys = ctl_page_to_phys;
+ e7xxx_init_csrows(mci, pdev, dev_idx, drc);
+ mci->edac_cap |= EDAC_FLAG_NONE;
debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
/* load the top of low memory, remap base, and remap limit vars */
- pci_read_config_word(mci->pdev, E7XXX_TOLM, &pci_data);
+ pci_read_config_word(pdev, E7XXX_TOLM, &pci_data);
pvt->tolm = ((u32) pci_data) << 4;
- pci_read_config_word(mci->pdev, E7XXX_REMAPBASE, &pci_data);
+ pci_read_config_word(pdev, E7XXX_REMAPBASE, &pci_data);
pvt->remapbase = ((u32) pci_data) << 14;
- pci_read_config_word(mci->pdev, E7XXX_REMAPLIMIT, &pci_data);
+ pci_read_config_word(pdev, E7XXX_REMAPLIMIT, &pci_data);
pvt->remaplimit = ((u32) pci_data) << 14;
e7xxx_printk(KERN_INFO,
"tolm = %x, remapbase = %x, remaplimit = %x\n", pvt->tolm,
@@ -461,23 +470,25 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
/* clear any pending errors, or initial state bits */
e7xxx_get_error_info(mci, &discard);
- if (edac_mc_add_mc(mci) != 0) {
+ /* Here we assume that we will never see multiple instances of this
+ * type of memory controller. The ID is therefore hardcoded to 0.
+ */
+ if (edac_mc_add_mc(mci,0)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
- goto fail;
+ goto fail1;
}
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
-fail:
- if (mci != NULL) {
- if(pvt != NULL && pvt->bridge_ck)
- pci_dev_put(pvt->bridge_ck);
- edac_mc_free(mci);
- }
+fail1:
+ pci_dev_put(pvt->bridge_ck);
+
+fail0:
+ edac_mc_free(mci);
- return rc;
+ return -ENODEV;
}
/* returns count (>= 0), or negative on error */
@@ -498,7 +509,7 @@ static void __devexit e7xxx_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
- if ((mci = edac_mc_del_mc(pdev)) == NULL)
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
pvt = (struct e7xxx_pvt *) mci->pvt_info;
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index ea06e3a4dc3..4bde30bb3be 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -1,6 +1,6 @@
/*
* edac_mc kernel module
- * (C) 2005 Linux Networx (http://lnxi.com)
+ * (C) 2005, 2006 Linux Networx (http://lnxi.com)
* This file may be distributed under the terms of the
* GNU General Public License.
*
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
@@ -34,13 +33,8 @@
#include <asm/edac.h>
#include "edac_mc.h"
-#define EDAC_MC_VERSION "Ver: 2.0.0 " __DATE__
+#define EDAC_MC_VERSION "Ver: 2.0.1 " __DATE__
-/* For now, disable the EDAC sysfs code. The sysfs interface that EDAC
- * presents to user space needs more thought, and is likely to change
- * substantially.
- */
-#define DISABLE_EDAC_SYSFS
#ifdef CONFIG_EDAC_DEBUG
/* Values of 0 to 4 will generate output */
@@ -54,35 +48,23 @@ static int log_ce = 1;
static int panic_on_ue;
static int poll_msec = 1000;
-static int check_pci_parity = 0; /* default YES check PCI parity */
-static int panic_on_pci_parity; /* default no panic on PCI Parity */
-static atomic_t pci_parity_count = ATOMIC_INIT(0);
-
/* lock to memory controller's control array */
static DECLARE_MUTEX(mem_ctls_mutex);
static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
static struct task_struct *edac_thread;
-/* Structure of the whitelist and blacklist arrays */
-struct edac_pci_device_list {
- unsigned int vendor; /* Vendor ID */
- unsigned int device; /* Deviice ID */
-};
-
-#define MAX_LISTED_PCI_DEVICES 32
-
-/* List of PCI devices (vendor-id:device-id) that should be skipped */
-static struct edac_pci_device_list pci_blacklist[MAX_LISTED_PCI_DEVICES];
-static int pci_blacklist_count;
+#ifdef CONFIG_PCI
+static int check_pci_parity = 0; /* default YES check PCI parity */
+static int panic_on_pci_parity; /* default no panic on PCI Parity */
+static atomic_t pci_parity_count = ATOMIC_INIT(0);
-/* List of PCI devices (vendor-id:device-id) that should be scanned */
-static struct edac_pci_device_list pci_whitelist[MAX_LISTED_PCI_DEVICES];
-static int pci_whitelist_count ;
+static struct kobject edac_pci_kobj; /* /sys/devices/system/edac/pci */
+static struct completion edac_pci_kobj_complete;
+#endif /* CONFIG_PCI */
/* START sysfs data and methods */
-#ifndef DISABLE_EDAC_SYSFS
static const char *mem_types[] = {
[MEM_EMPTY] = "Empty",
@@ -127,35 +109,24 @@ static struct sysdev_class edac_class = {
set_kset_name("edac"),
};
-/* sysfs objects:
+/* sysfs object:
* /sys/devices/system/edac/mc
- * /sys/devices/system/edac/pci
*/
static struct kobject edac_memctrl_kobj;
-static struct kobject edac_pci_kobj;
/* We use these to wait for the reference counts on edac_memctrl_kobj and
* edac_pci_kobj to reach 0.
*/
static struct completion edac_memctrl_kobj_complete;
-static struct completion edac_pci_kobj_complete;
/*
* /sys/devices/system/edac/mc;
* data structures and methods
*/
-#if 0
-static ssize_t memctrl_string_show(void *ptr, char *buffer)
-{
- char *value = (char*) ptr;
- return sprintf(buffer, "%s\n", value);
-}
-#endif
-
static ssize_t memctrl_int_show(void *ptr, char *buffer)
{
int *value = (int*) ptr;
- return sprintf(buffer, "%d\n", *value);
+ return sprintf(buffer, "%u\n", *value);
}
static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
@@ -221,11 +192,6 @@ struct memctrl_dev_attribute attr_##_name = { \
.store = _store, \
};
-/* cwrow<id> attribute f*/
-#if 0
-MEMCTRL_STRING_ATTR(mc_version,EDAC_MC_VERSION,S_IRUGO,memctrl_string_show,NULL);
-#endif
-
/* csrow<id> control files */
MEMCTRL_ATTR(panic_on_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
MEMCTRL_ATTR(log_ue,S_IRUGO|S_IWUSR,memctrl_int_show,memctrl_int_store);
@@ -254,8 +220,6 @@ static struct kobj_type ktype_memctrl = {
.default_attrs = (struct attribute **) memctrl_attr,
};
-#endif /* DISABLE_EDAC_SYSFS */
-
/* Initialize the main sysfs entries for edac:
* /sys/devices/system/edac
*
@@ -265,11 +229,6 @@ static struct kobj_type ktype_memctrl = {
* !0 FAILURE
*/
static int edac_sysfs_memctrl_setup(void)
-#ifdef DISABLE_EDAC_SYSFS
-{
- return 0;
-}
-#else
{
int err=0;
@@ -301,7 +260,6 @@ static int edac_sysfs_memctrl_setup(void)
return err;
}
-#endif /* DISABLE_EDAC_SYSFS */
/*
* MC teardown:
@@ -309,7 +267,6 @@ static int edac_sysfs_memctrl_setup(void)
*/
static void edac_sysfs_memctrl_teardown(void)
{
-#ifndef DISABLE_EDAC_SYSFS
debugf0("MC: " __FILE__ ": %s()\n", __func__);
/* Unregister the MC's kobject and wait for reference count to reach
@@ -321,142 +278,9 @@ static void edac_sysfs_memctrl_teardown(void)
/* Unregister the 'edac' object */
sysdev_class_unregister(&edac_class);
-#endif /* DISABLE_EDAC_SYSFS */
}
-#ifndef DISABLE_EDAC_SYSFS
-
-/*
- * /sys/devices/system/edac/pci;
- * data structures and methods
- */
-
-struct list_control {
- struct edac_pci_device_list *list;
- int *count;
-};
-
-#if 0
-/* Output the list as: vendor_id:device:id<,vendor_id:device_id> */
-static ssize_t edac_pci_list_string_show(void *ptr, char *buffer)
-{
- struct list_control *listctl;
- struct edac_pci_device_list *list;
- char *p = buffer;
- int len=0;
- int i;
-
- listctl = ptr;
- list = listctl->list;
-
- for (i = 0; i < *(listctl->count); i++, list++ ) {
- if (len > 0)
- len += snprintf(p + len, (PAGE_SIZE-len), ",");
-
- len += snprintf(p + len,
- (PAGE_SIZE-len),
- "%x:%x",
- list->vendor,list->device);
- }
-
- len += snprintf(p + len,(PAGE_SIZE-len), "\n");
- return (ssize_t) len;
-}
-
-/**
- *
- * Scan string from **s to **e looking for one 'vendor:device' tuple
- * where each field is a hex value
- *
- * return 0 if an entry is NOT found
- * return 1 if an entry is found
- * fill in *vendor_id and *device_id with values found
- *
- * In both cases, make sure *s has been moved forward toward *e
- */
-static int parse_one_device(const char **s,const char **e,
- unsigned int *vendor_id, unsigned int *device_id)
-{
- const char *runner, *p;
-
- /* if null byte, we are done */
- if (!**s) {
- (*s)++; /* keep *s moving */
- return 0;
- }
-
- /* skip over newlines & whitespace */
- if ((**s == '\n') || isspace(**s)) {
- (*s)++;
- return 0;
- }
-
- if (!isxdigit(**s)) {
- (*s)++;
- return 0;
- }
-
- /* parse vendor_id */
- runner = *s;
-
- while (runner < *e) {
- /* scan for vendor:device delimiter */
- if (*runner == ':') {
- *vendor_id = simple_strtol((char*) *s, (char**) &p, 16);
- runner = p + 1;
- break;
- }
-
- runner++;
- }
-
- if (!isxdigit(*runner)) {
- *s = ++runner;
- return 0;
- }
-
- /* parse device_id */
- if (runner < *e) {
- *device_id = simple_strtol((char*)runner, (char**)&p, 16);
- runner = p;
- }
-
- *s = runner;
- return 1;
-}
-
-static ssize_t edac_pci_list_string_store(void *ptr, const char *buffer,
- size_t count)
-{
- struct list_control *listctl;
- struct edac_pci_device_list *list;
- unsigned int vendor_id, device_id;
- const char *s, *e;
- int *index;
-
- s = (char*)buffer;
- e = s + count;
- listctl = ptr;
- list = listctl->list;
- index = listctl->count;
- *index = 0;
-
- while (*index < MAX_LISTED_PCI_DEVICES) {
- if (parse_one_device(&s,&e,&vendor_id,&device_id)) {
- list[ *index ].vendor = vendor_id;
- list[ *index ].device = device_id;
- (*index)++;
- }
-
- /* check for all data consume */
- if (s >= e)
- break;
- }
-
- return count;
-}
-
-#endif
+#ifdef CONFIG_PCI
static ssize_t edac_pci_int_show(void *ptr, char *buffer)
{
int *value = ptr;
@@ -524,31 +348,6 @@ struct edac_pci_dev_attribute edac_pci_attr_##_name = { \
.store = _store, \
};
-#if 0
-static struct list_control pci_whitelist_control = {
- .list = pci_whitelist,
- .count = &pci_whitelist_count
-};
-
-static struct list_control pci_blacklist_control = {
- .list = pci_blacklist,
- .count = &pci_blacklist_count
-};
-
-/* whitelist attribute */
-EDAC_PCI_STRING_ATTR(pci_parity_whitelist,
- &pci_whitelist_control,
- S_IRUGO|S_IWUSR,
- edac_pci_list_string_show,
- edac_pci_list_string_store);
-
-EDAC_PCI_STRING_ATTR(pci_parity_blacklist,
- &pci_blacklist_control,
- S_IRUGO|S_IWUSR,
- edac_pci_list_string_show,
- edac_pci_list_string_store);
-#endif
-
/* PCI Parity control files */
EDAC_PCI_ATTR(check_pci_parity, S_IRUGO|S_IWUSR, edac_pci_int_show,
edac_pci_int_store);
@@ -577,18 +376,11 @@ static struct kobj_type ktype_edac_pci = {
.default_attrs = (struct attribute **) edac_pci_attr,
};
-#endif /* DISABLE_EDAC_SYSFS */
-
/**
* edac_sysfs_pci_setup()
*
*/
static int edac_sysfs_pci_setup(void)
-#ifdef DISABLE_EDAC_SYSFS
-{
- return 0;
-}
-#else
{
int err;
@@ -612,146 +404,291 @@ static int edac_sysfs_pci_setup(void)
return err;
}
-#endif /* DISABLE_EDAC_SYSFS */
static void edac_sysfs_pci_teardown(void)
{
-#ifndef DISABLE_EDAC_SYSFS
debugf0("%s()\n", __func__);
init_completion(&edac_pci_kobj_complete);
kobject_unregister(&edac_pci_kobj);
wait_for_completion(&edac_pci_kobj_complete);
-#endif
}
-#ifndef DISABLE_EDAC_SYSFS
-/* EDAC sysfs CSROW data structures and methods */
-
-/* Set of more detailed csrow<id> attribute show/store functions */
-static ssize_t csrow_ch0_dimm_label_show(struct csrow_info *csrow, char *data)
+static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
{
- ssize_t size = 0;
+ int where;
+ u16 status;
+
+ where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
+ pci_read_config_word(dev, where, &status);
+
+ /* If we get back 0xFFFF then we must suspect that the card has been
+ * pulled but the Linux PCI layer has not yet finished cleaning up.
+ * We don't want to report on such devices
+ */
+
+ if (status == 0xFFFF) {
+ u32 sanity;
+
+ pci_read_config_dword(dev, 0, &sanity);
- if (csrow->nr_channels > 0) {
- size = snprintf(data, EDAC_MC_LABEL_LEN,"%s\n",
- csrow->channels[0].label);
+ if (sanity == 0xFFFFFFFF)
+ return 0;
}
- return size;
+ status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
+ PCI_STATUS_PARITY;
+
+ if (status)
+ /* reset only the bits we are interested in */
+ pci_write_config_word(dev, where, status);
+
+ return status;
}
-static ssize_t csrow_ch1_dimm_label_show(struct csrow_info *csrow, char *data)
+typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
+
+/* Clear any PCI parity errors logged by this device. */
+static void edac_pci_dev_parity_clear(struct pci_dev *dev)
{
- ssize_t size = 0;
+ u8 header_type;
- if (csrow->nr_channels > 0) {
- size = snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
- csrow->channels[1].label);
- }
+ get_pci_parity_status(dev, 0);
- return size;
+ /* read the device TYPE, looking for bridges */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
+ get_pci_parity_status(dev, 1);
}
-static ssize_t csrow_ch0_dimm_label_store(struct csrow_info *csrow,
- const char *data, size_t size)
+/*
+ * PCI Parity polling
+ *
+ */
+static void edac_pci_dev_parity_test(struct pci_dev *dev)
{
- ssize_t max_size = 0;
+ u16 status;
+ u8 header_type;
+
+ /* read the STATUS register on this device
+ */
+ status = get_pci_parity_status(dev, 0);
+
+ debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id );
+
+ /* check the status reg for errors */
+ if (status) {
+ if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Signaled System Error on %s\n",
+ pci_name(dev));
+
+ if (status & (PCI_STATUS_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Master Data Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+
+ if (status & (PCI_STATUS_DETECTED_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI,
+ "Detected Parity Error on %s\n",
+ pci_name(dev));
- if (csrow->nr_channels > 0) {
- max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1);
- strncpy(csrow->channels[0].label, data, max_size);
- csrow->channels[0].label[max_size] = '\0';
+ atomic_inc(&pci_parity_count);
+ }
}
- return size;
+ /* read the device TYPE, looking for bridges */
+ pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+ debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id );
+
+ if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
+ /* On bridges, need to examine secondary status register */
+ status = get_pci_parity_status(dev, 1);
+
+ debugf2("PCI SEC_STATUS= 0x%04x %s\n",
+ status, dev->dev.bus_id );
+
+ /* check the secondary status reg for errors */
+ if (status) {
+ if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Signaled System Error on %s\n",
+ pci_name(dev));
+
+ if (status & (PCI_STATUS_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Master Data Parity Error on "
+ "%s\n", pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+
+ if (status & (PCI_STATUS_DETECTED_PARITY)) {
+ edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
+ "Detected Parity Error on %s\n",
+ pci_name(dev));
+
+ atomic_inc(&pci_parity_count);
+ }
+ }
+ }
}
-static ssize_t csrow_ch1_dimm_label_store(struct csrow_info *csrow,
- const char *data, size_t size)
+/*
+ * pci_dev parity list iterator
+ * Scan the PCI device list for one iteration, looking for SERRORs
+ * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
+ */
+static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
{
- ssize_t max_size = 0;
+ struct pci_dev *dev = NULL;
- if (csrow->nr_channels > 1) {
- max_size = min((ssize_t)size,(ssize_t)EDAC_MC_LABEL_LEN-1);
- strncpy(csrow->channels[1].label, data, max_size);
- csrow->channels[1].label[max_size] = '\0';
+ /* request for kernel access to the next PCI device, if any,
+ * and while we are looking at it have its reference count
+ * bumped until we are done with it
+ */
+ while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ fn(dev);
}
-
- return max_size;
}
-static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data)
+static void do_pci_parity_check(void)
{
- return sprintf(data,"%u\n", csrow->ue_count);
+ unsigned long flags;
+ int before_count;
+
+ debugf3("%s()\n", __func__);
+
+ if (!check_pci_parity)
+ return;
+
+ before_count = atomic_read(&pci_parity_count);
+
+ /* scan all PCI devices looking for a Parity Error on devices and
+ * bridges
+ */
+ local_irq_save(flags);
+ edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
+ local_irq_restore(flags);
+
+ /* Only if operator has selected panic on PCI Error */
+ if (panic_on_pci_parity) {
+ /* If the count is different 'after' from 'before' */
+ if (before_count != atomic_read(&pci_parity_count))
+ panic("EDAC: PCI Parity Error");
+ }
}
-static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data)
+static inline void clear_pci_parity_errors(void)
{
- return sprintf(data,"%u\n", csrow->ce_count);
+ /* Clear any PCI bus parity errors that devices initially have logged
+ * in their registers.
+ */
+ edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
}
-static ssize_t csrow_ch0_ce_count_show(struct csrow_info *csrow, char *data)
-{
- ssize_t size = 0;
+#else /* CONFIG_PCI */
- if (csrow->nr_channels > 0) {
- size = sprintf(data,"%u\n", csrow->channels[0].ce_count);
- }
+/* pre-process these away */
+#define do_pci_parity_check()
+#define clear_pci_parity_errors()
+#define edac_sysfs_pci_teardown()
+#define edac_sysfs_pci_setup() (0)
- return size;
-}
+#endif /* CONFIG_PCI */
-static ssize_t csrow_ch1_ce_count_show(struct csrow_info *csrow, char *data)
-{
- ssize_t size = 0;
+/* EDAC sysfs CSROW data structures and methods
+ */
- if (csrow->nr_channels > 1) {
- size = sprintf(data,"%u\n", csrow->channels[1].ce_count);
- }
+/* Set of more default csrow<id> attribute show/store functions */
+static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data, int private)
+{
+ return sprintf(data,"%u\n", csrow->ue_count);
+}
- return size;
+static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data, int private)
+{
+ return sprintf(data,"%u\n", csrow->ce_count);
}
-static ssize_t csrow_size_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_size_show(struct csrow_info *csrow, char *data, int private)
{
return sprintf(data,"%u\n", PAGES_TO_MiB(csrow->nr_pages));
}
-static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data, int private)
{
return sprintf(data,"%s\n", mem_types[csrow->mtype]);
}
-static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data, int private)
{
return sprintf(data,"%s\n", dev_types[csrow->dtype]);
}
-static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data)
+static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data, int private)
{
return sprintf(data,"%s\n", edac_caps[csrow->edac_mode]);
}
+/* show/store functions for DIMM Label attributes */
+static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
+ char *data, int channel)
+{
+ return snprintf(data, EDAC_MC_LABEL_LEN,"%s",
+ csrow->channels[channel].label);
+}
+
+static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
+ const char *data,
+ size_t count,
+ int channel)
+{
+ ssize_t max_size = 0;
+
+ max_size = min((ssize_t)count,(ssize_t)EDAC_MC_LABEL_LEN-1);
+ strncpy(csrow->channels[channel].label, data, max_size);
+ csrow->channels[channel].label[max_size] = '\0';
+
+ return max_size;
+}
+
+/* show function for dynamic chX_ce_count attribute */
+static ssize_t channel_ce_count_show(struct csrow_info *csrow,
+ char *data,
+ int channel)
+{
+ return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
+}
+
+/* csrow specific attribute structure */
struct csrowdev_attribute {
struct attribute attr;
- ssize_t (*show)(struct csrow_info *,char *);
- ssize_t (*store)(struct csrow_info *, const char *,size_t);
+ ssize_t (*show)(struct csrow_info *,char *,int);
+ ssize_t (*store)(struct csrow_info *, const char *,size_t,int);
+ int private;
};
#define to_csrow(k) container_of(k, struct csrow_info, kobj)
#define to_csrowdev_attr(a) container_of(a, struct csrowdev_attribute, attr)
-/* Set of show/store higher level functions for csrow objects */
-static ssize_t csrowdev_show(struct kobject *kobj, struct attribute *attr,
- char *buffer)
+/* Set of show/store higher level functions for default csrow attributes */
+static ssize_t csrowdev_show(struct kobject *kobj,
+ struct attribute *attr,
+ char *buffer)
{
struct csrow_info *csrow = to_csrow(kobj);
struct csrowdev_attribute *csrowdev_attr = to_csrowdev_attr(attr);
if (csrowdev_attr->show)
- return csrowdev_attr->show(csrow, buffer);
-
+ return csrowdev_attr->show(csrow,
+ buffer,
+ csrowdev_attr->private);
return -EIO;
}
@@ -762,8 +699,10 @@ static ssize_t csrowdev_store(struct kobject *kobj, struct attribute *attr,
struct csrowdev_attribute * csrowdev_attr = to_csrowdev_attr(attr);
if (csrowdev_attr->store)
- return csrowdev_attr->store(csrow, buffer, count);
-
+ return csrowdev_attr->store(csrow,
+ buffer,
+ count,
+ csrowdev_attr->private);
return -EIO;
}
@@ -772,69 +711,157 @@ static struct sysfs_ops csrowfs_ops = {
.store = csrowdev_store
};
-#define CSROWDEV_ATTR(_name,_mode,_show,_store) \
+#define CSROWDEV_ATTR(_name,_mode,_show,_store,_private) \
struct csrowdev_attribute attr_##_name = { \
.attr = {.name = __stringify(_name), .mode = _mode }, \
.show = _show, \
.store = _store, \
+ .private = _private, \
};
-/* cwrow<id>/attribute files */
-CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL);
-CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL);
-CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL);
-CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL);
-CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL);
-CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL);
-CSROWDEV_ATTR(ch0_ce_count,S_IRUGO,csrow_ch0_ce_count_show,NULL);
-CSROWDEV_ATTR(ch1_ce_count,S_IRUGO,csrow_ch1_ce_count_show,NULL);
-
-/* control/attribute files */
-CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
- csrow_ch0_dimm_label_show,
- csrow_ch0_dimm_label_store);
-CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
- csrow_ch1_dimm_label_show,
- csrow_ch1_dimm_label_store);
+/* default cwrow<id>/attribute files */
+CSROWDEV_ATTR(size_mb,S_IRUGO,csrow_size_show,NULL,0);
+CSROWDEV_ATTR(dev_type,S_IRUGO,csrow_dev_type_show,NULL,0);
+CSROWDEV_ATTR(mem_type,S_IRUGO,csrow_mem_type_show,NULL,0);
+CSROWDEV_ATTR(edac_mode,S_IRUGO,csrow_edac_mode_show,NULL,0);
+CSROWDEV_ATTR(ue_count,S_IRUGO,csrow_ue_count_show,NULL,0);
+CSROWDEV_ATTR(ce_count,S_IRUGO,csrow_ce_count_show,NULL,0);
-/* Attributes of the CSROW<id> object */
-static struct csrowdev_attribute *csrow_attr[] = {
+/* default attributes of the CSROW<id> object */
+static struct csrowdev_attribute *default_csrow_attr[] = {
&attr_dev_type,
&attr_mem_type,
&attr_edac_mode,
&attr_size_mb,
&attr_ue_count,
&attr_ce_count,
- &attr_ch0_ce_count,
- &attr_ch1_ce_count,
- &attr_ch0_dimm_label,
- &attr_ch1_dimm_label,
NULL,
};
-/* No memory to release */
+
+/* possible dynamic channel DIMM Label attribute files */
+CSROWDEV_ATTR(ch0_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 0 );
+CSROWDEV_ATTR(ch1_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 1 );
+CSROWDEV_ATTR(ch2_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 2 );
+CSROWDEV_ATTR(ch3_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 3 );
+CSROWDEV_ATTR(ch4_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 4 );
+CSROWDEV_ATTR(ch5_dimm_label,S_IRUGO|S_IWUSR,
+ channel_dimm_label_show,
+ channel_dimm_label_store,
+ 5 );
+
+/* Total possible dynamic DIMM Label attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_dimm_attr[] = {
+ &attr_ch0_dimm_label,
+ &attr_ch1_dimm_label,
+ &attr_ch2_dimm_label,
+ &attr_ch3_dimm_label,
+ &attr_ch4_dimm_label,
+ &attr_ch5_dimm_label
+};
+
+/* possible dynamic channel ce_count attribute files */
+CSROWDEV_ATTR(ch0_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 0 );
+CSROWDEV_ATTR(ch1_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 1 );
+CSROWDEV_ATTR(ch2_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 2 );
+CSROWDEV_ATTR(ch3_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 3 );
+CSROWDEV_ATTR(ch4_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 4 );
+CSROWDEV_ATTR(ch5_ce_count,S_IRUGO|S_IWUSR,
+ channel_ce_count_show,
+ NULL,
+ 5 );
+
+/* Total possible dynamic ce_count attribute file table */
+static struct csrowdev_attribute *dynamic_csrow_ce_count_attr[] = {
+ &attr_ch0_ce_count,
+ &attr_ch1_ce_count,
+ &attr_ch2_ce_count,
+ &attr_ch3_ce_count,
+ &attr_ch4_ce_count,
+ &attr_ch5_ce_count
+};
+
+
+#define EDAC_NR_CHANNELS 6
+
+/* Create dynamic CHANNEL files, indexed by 'chan', under specifed CSROW */
+static int edac_create_channel_files(struct kobject *kobj, int chan)
+{
+ int err=-ENODEV;
+
+ if (chan >= EDAC_NR_CHANNELS)
+ return err;
+
+ /* create the DIMM label attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *) dynamic_csrow_dimm_attr[chan]);
+
+ if (!err) {
+ /* create the CE Count attribute file */
+ err = sysfs_create_file(kobj,
+ (struct attribute *) dynamic_csrow_ce_count_attr[chan]);
+ } else {
+ debugf1("%s() dimm labels and ce_count files created", __func__);
+ }
+
+ return err;
+}
+
+/* No memory to release for this kobj */
static void edac_csrow_instance_release(struct kobject *kobj)
{
struct csrow_info *cs;
- debugf1("%s()\n", __func__);
cs = container_of(kobj, struct csrow_info, kobj);
complete(&cs->kobj_complete);
}
+/* the kobj_type instance for a CSROW */
static struct kobj_type ktype_csrow = {
.release = edac_csrow_instance_release,
.sysfs_ops = &csrowfs_ops,
- .default_attrs = (struct attribute **) csrow_attr,
+ .default_attrs = (struct attribute **) default_csrow_attr,
};
/* Create a CSROW object under specifed edac_mc_device */
-static int edac_create_csrow_object(struct kobject *edac_mci_kobj,
- struct csrow_info *csrow, int index)
+static int edac_create_csrow_object(
+ struct kobject *edac_mci_kobj,
+ struct csrow_info *csrow,
+ int index)
{
int err = 0;
+ int chan;
- debugf0("%s()\n", __func__);
memset(&csrow->kobj, 0, sizeof(csrow->kobj));
/* generate ..../edac/mc/mc<id>/csrow<index> */
@@ -844,21 +871,27 @@ static int edac_create_csrow_object(struct kobject *edac_mci_kobj,
/* name this instance of csrow<id> */
err = kobject_set_name(&csrow->kobj,"csrow%d",index);
+ if (err)
+ goto error_exit;
+ /* Instanstiate the csrow object */
+ err = kobject_register(&csrow->kobj);
if (!err) {
- /* Instanstiate the csrow object */
- err = kobject_register(&csrow->kobj);
-
- if (err)
- debugf0("Failed to register CSROW%d\n",index);
- else
- debugf0("Registered CSROW%d\n",index);
+ /* Create the dyanmic attribute files on this csrow,
+ * namely, the DIMM labels and the channel ce_count
+ */
+ for (chan = 0; chan < csrow->nr_channels; chan++) {
+ err = edac_create_channel_files(&csrow->kobj,chan);
+ if (err)
+ break;
+ }
}
+error_exit:
return err;
}
-/* sysfs data structures and methods for the MCI kobjects */
+/* default sysfs methods and data structures for the main MCI kobject */
static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
const char *data, size_t count)
@@ -884,6 +917,7 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
return count;
}
+/* default attribute files for the MCI object */
static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
{
return sprintf(data,"%d\n", mci->ue_count);
@@ -909,71 +943,11 @@ static ssize_t mci_seconds_show(struct mem_ctl_info *mci, char *data)
return sprintf(data,"%ld\n", (jiffies - mci->start_time) / HZ);
}
-static ssize_t mci_mod_name_show(struct mem_ctl_info *mci, char *data)
-{
- return sprintf(data,"%s %s\n", mci->mod_name, mci->mod_ver);
-}
-
static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
{
return sprintf(data,"%s\n", mci->ctl_name);
}
-static int mci_output_edac_cap(char *buf, unsigned long edac_cap)
-{
- char *p = buf;
- int bit_idx;
-
- for (bit_idx = 0; bit_idx < 8 * sizeof(edac_cap); bit_idx++) {
- if ((edac_cap >> bit_idx) & 0x1)
- p += sprintf(p, "%s ", edac_caps[bit_idx]);
- }
-
- return p - buf;
-}
-
-static ssize_t mci_edac_capability_show(struct mem_ctl_info *mci, char *data)
-{
- char *p = data;
-
- p += mci_output_edac_cap(p,mci->edac_ctl_cap);
- p += sprintf(p, "\n");
- return p - data;
-}
-
-static ssize_t mci_edac_current_capability_show(struct mem_ctl_info *mci,
- char *data)
-{
- char *p = data;
-
- p += mci_output_edac_cap(p,mci->edac_cap);
- p += sprintf(p, "\n");
- return p - data;
-}
-
-static int mci_output_mtype_cap(char *buf, unsigned long mtype_cap)
-{
- char *p = buf;
- int bit_idx;
-
- for (bit_idx = 0; bit_idx < 8 * sizeof(mtype_cap); bit_idx++) {
- if ((mtype_cap >> bit_idx) & 0x1)
- p += sprintf(p, "%s ", mem_types[bit_idx]);
- }
-
- return p - buf;
-}
-
-static ssize_t mci_supported_mem_type_show(struct mem_ctl_info *mci,
- char *data)
-{
- char *p = data;
-
- p += mci_output_mtype_cap(p,mci->mtype_cap);
- p += sprintf(p, "\n");
- return p - data;
-}
-
static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
{
int total_pages, csrow_idx;
@@ -1000,6 +974,7 @@ struct mcidev_attribute {
#define to_mci(k) container_of(k, struct mem_ctl_info, edac_mci_kobj)
#define to_mcidev_attr(a) container_of(a, struct mcidev_attribute, attr)
+/* MCI show/store functions for top most object */
static ssize_t mcidev_show(struct kobject *kobj, struct attribute *attr,
char *buffer)
{
@@ -1036,31 +1011,21 @@ struct mcidev_attribute mci_attr_##_name = { \
.store = _store, \
};
-/* Control file */
+/* default Control file */
MCIDEV_ATTR(reset_counters,S_IWUSR,NULL,mci_reset_counters_store);
-/* Attribute files */
+/* default Attribute files */
MCIDEV_ATTR(mc_name,S_IRUGO,mci_ctl_name_show,NULL);
-MCIDEV_ATTR(module_name,S_IRUGO,mci_mod_name_show,NULL);
-MCIDEV_ATTR(edac_capability,S_IRUGO,mci_edac_capability_show,NULL);
MCIDEV_ATTR(size_mb,S_IRUGO,mci_size_mb_show,NULL);
MCIDEV_ATTR(seconds_since_reset,S_IRUGO,mci_seconds_show,NULL);
MCIDEV_ATTR(ue_noinfo_count,S_IRUGO,mci_ue_noinfo_show,NULL);
MCIDEV_ATTR(ce_noinfo_count,S_IRUGO,mci_ce_noinfo_show,NULL);
MCIDEV_ATTR(ue_count,S_IRUGO,mci_ue_count_show,NULL);
MCIDEV_ATTR(ce_count,S_IRUGO,mci_ce_count_show,NULL);
-MCIDEV_ATTR(edac_current_capability,S_IRUGO,
- mci_edac_current_capability_show,NULL);
-MCIDEV_ATTR(supported_mem_type,S_IRUGO,
- mci_supported_mem_type_show,NULL);
static struct mcidev_attribute *mci_attr[] = {
&mci_attr_reset_counters,
- &mci_attr_module_name,
&mci_attr_mc_name,
- &mci_attr_edac_capability,
- &mci_attr_edac_current_capability,
- &mci_attr_supported_mem_type,
&mci_attr_size_mb,
&mci_attr_seconds_since_reset,
&mci_attr_ue_noinfo_count,
@@ -1088,7 +1053,6 @@ static struct kobj_type ktype_mci = {
.default_attrs = (struct attribute **) mci_attr,
};
-#endif /* DISABLE_EDAC_SYSFS */
#define EDAC_DEVICE_SYMLINK "device"
@@ -1101,11 +1065,6 @@ static struct kobj_type ktype_mci = {
* !0 Failure
*/
static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
-#ifdef DISABLE_EDAC_SYSFS
-{
- return 0;
-}
-#else
{
int i;
int err;
@@ -1117,7 +1076,6 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* set the name of the mc<id> object */
err = kobject_set_name(edac_mci_kobj,"mc%d",mci->mc_idx);
-
if (err)
return err;
@@ -1127,14 +1085,12 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* register the mc<id> kobject */
err = kobject_register(edac_mci_kobj);
-
if (err)
return err;
/* create a symlink for the device */
- err = sysfs_create_link(edac_mci_kobj, &mci->pdev->dev.kobj,
+ err = sysfs_create_link(edac_mci_kobj, &mci->dev->kobj,
EDAC_DEVICE_SYMLINK);
-
if (err)
goto fail0;
@@ -1147,7 +1103,6 @@ static int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* Only expose populated CSROWs */
if (csrow->nr_pages > 0) {
err = edac_create_csrow_object(edac_mci_kobj,csrow,i);
-
if (err)
goto fail1;
}
@@ -1171,14 +1126,12 @@ fail0:
wait_for_completion(&mci->kobj_complete);
return err;
}
-#endif /* DISABLE_EDAC_SYSFS */
/*
* remove a Memory Controller instance
*/
static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
{
-#ifndef DISABLE_EDAC_SYSFS
int i;
debugf0("%s()\n", __func__);
@@ -1196,7 +1149,6 @@ static void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
init_completion(&mci->kobj_complete);
kobject_unregister(&mci->edac_mci_kobj);
wait_for_completion(&mci->kobj_complete);
-#endif /* DISABLE_EDAC_SYSFS */
}
/* END OF sysfs data and methods */
@@ -1238,7 +1190,7 @@ void edac_mc_dump_mci(struct mem_ctl_info *mci)
debugf4("\tmci->edac_check = %p\n", mci->edac_check);
debugf3("\tmci->nr_csrows = %d, csrows = %p\n",
mci->nr_csrows, mci->csrows);
- debugf3("\tpdev = %p\n", mci->pdev);
+ debugf3("\tdev = %p\n", mci->dev);
debugf3("\tmod_name:ctl_name = %s:%s\n",
mci->mod_name, mci->ctl_name);
debugf3("\tpvt_info = %p\n\n", mci->pvt_info);
@@ -1363,7 +1315,7 @@ void edac_mc_free(struct mem_ctl_info *mci)
}
EXPORT_SYMBOL_GPL(edac_mc_free);
-static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev)
+static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
{
struct mem_ctl_info *mci;
struct list_head *item;
@@ -1373,54 +1325,53 @@ static struct mem_ctl_info *find_mci_by_pdev(struct pci_dev *pdev)
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
- if (mci->pdev == pdev)
+ if (mci->dev == dev)
return mci;
}
return NULL;
}
-static int add_mc_to_global_list(struct mem_ctl_info *mci)
+/* Return 0 on success, 1 on failure.
+ * Before calling this function, caller must
+ * assign a unique value to mci->mc_idx.
+ */
+static int add_mc_to_global_list (struct mem_ctl_info *mci)
{
struct list_head *item, *insert_before;
struct mem_ctl_info *p;
- int i;
- if (list_empty(&mc_devices)) {
- mci->mc_idx = 0;
- insert_before = &mc_devices;
- } else {
- if (find_mci_by_pdev(mci->pdev)) {
- edac_printk(KERN_WARNING, EDAC_MC,
- "%s (%s) %s %s already assigned %d\n",
- mci->pdev->dev.bus_id,
- pci_name(mci->pdev), mci->mod_name,
- mci->ctl_name, mci->mc_idx);
- return 1;
- }
+ insert_before = &mc_devices;
- insert_before = NULL;
- i = 0;
+ if (unlikely((p = find_mci_by_dev(mci->dev)) != NULL))
+ goto fail0;
- list_for_each(item, &mc_devices) {
- p = list_entry(item, struct mem_ctl_info, link);
+ list_for_each(item, &mc_devices) {
+ p = list_entry(item, struct mem_ctl_info, link);
- if (p->mc_idx != i) {
- insert_before = item;
- break;
- }
+ if (p->mc_idx >= mci->mc_idx) {
+ if (unlikely(p->mc_idx == mci->mc_idx))
+ goto fail1;
- i++;
+ insert_before = item;
+ break;
}
-
- mci->mc_idx = i;
-
- if (insert_before == NULL)
- insert_before = &mc_devices;
}
list_add_tail_rcu(&mci->link, insert_before);
return 0;
+
+fail0:
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "%s (%s) %s %s already assigned %d\n", p->dev->bus_id,
+ dev_name(p->dev), p->mod_name, p->ctl_name, p->mc_idx);
+ return 1;
+
+fail1:
+ edac_printk(KERN_WARNING, EDAC_MC,
+ "bug in low-level driver: attempt to assign\n"
+ " duplicate mc_idx %d in %s()\n", p->mc_idx, __func__);
+ return 1;
}
static void complete_mc_list_del(struct rcu_head *head)
@@ -1444,6 +1395,7 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
* edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
* create sysfs entries associated with mci structure
* @mci: pointer to the mci structure to be added to the list
+ * @mc_idx: A unique numeric identifier to be assigned to the 'mci' structure.
*
* Return:
* 0 Success
@@ -1451,9 +1403,10 @@ static void del_mc_from_global_list(struct mem_ctl_info *mci)
*/
/* FIXME - should a warning be printed if no error detection? correction? */
-int edac_mc_add_mc(struct mem_ctl_info *mci)
+int edac_mc_add_mc(struct mem_ctl_info *mci, int mc_idx)
{
debugf0("%s()\n", __func__);
+ mci->mc_idx = mc_idx;
#ifdef CONFIG_EDAC_DEBUG
if (edac_debug_level >= 3)
edac_mc_dump_mci(mci);
@@ -1486,8 +1439,8 @@ int edac_mc_add_mc(struct mem_ctl_info *mci)
}
/* Report action taken */
- edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: PCI %s\n",
- mci->mod_name, mci->ctl_name, pci_name(mci->pdev));
+ edac_mc_printk(mci, KERN_INFO, "Giving out device to %s %s: DEV %s\n",
+ mci->mod_name, mci->ctl_name, dev_name(mci->dev));
up(&mem_ctls_mutex);
return 0;
@@ -1504,18 +1457,18 @@ EXPORT_SYMBOL_GPL(edac_mc_add_mc);
/**
* edac_mc_del_mc: Remove sysfs entries for specified mci structure and
* remove mci structure from global list
- * @pdev: Pointer to 'struct pci_dev' representing mci structure to remove.
+ * @pdev: Pointer to 'struct device' representing mci structure to remove.
*
* Return pointer to removed mci structure, or NULL if device not found.
*/
-struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev)
+struct mem_ctl_info * edac_mc_del_mc(struct device *dev)
{
struct mem_ctl_info *mci;
debugf0("MC: %s()\n", __func__);
down(&mem_ctls_mutex);
- if ((mci = find_mci_by_pdev(pdev)) == NULL) {
+ if ((mci = find_mci_by_dev(dev)) == NULL) {
up(&mem_ctls_mutex);
return NULL;
}
@@ -1524,8 +1477,8 @@ struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev)
del_mc_from_global_list(mci);
up(&mem_ctls_mutex);
edac_printk(KERN_INFO, EDAC_MC,
- "Removed device %d for %s %s: PCI %s\n", mci->mc_idx,
- mci->mod_name, mci->ctl_name, pci_name(mci->pdev));
+ "Removed device %d for %s %s: DEV %s\n", mci->mc_idx,
+ mci->mod_name, mci->ctl_name, dev_name(mci->dev));
return mci;
}
EXPORT_SYMBOL_GPL(edac_mc_del_mc);
@@ -1739,244 +1692,6 @@ void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
}
EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
-#ifdef CONFIG_PCI
-
-static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
-{
- int where;
- u16 status;
-
- where = secondary ? PCI_SEC_STATUS : PCI_STATUS;
- pci_read_config_word(dev, where, &status);
-
- /* If we get back 0xFFFF then we must suspect that the card has been
- * pulled but the Linux PCI layer has not yet finished cleaning up.
- * We don't want to report on such devices
- */
-
- if (status == 0xFFFF) {
- u32 sanity;
-
- pci_read_config_dword(dev, 0, &sanity);
-
- if (sanity == 0xFFFFFFFF)
- return 0;
- }
-
- status &= PCI_STATUS_DETECTED_PARITY | PCI_STATUS_SIG_SYSTEM_ERROR |
- PCI_STATUS_PARITY;
-
- if (status)
- /* reset only the bits we are interested in */
- pci_write_config_word(dev, where, status);
-
- return status;
-}
-
-typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
-
-/* Clear any PCI parity errors logged by this device. */
-static void edac_pci_dev_parity_clear(struct pci_dev *dev)
-{
- u8 header_type;
-
- get_pci_parity_status(dev, 0);
-
- /* read the device TYPE, looking for bridges */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE)
- get_pci_parity_status(dev, 1);
-}
-
-/*
- * PCI Parity polling
- *
- */
-static void edac_pci_dev_parity_test(struct pci_dev *dev)
-{
- u16 status;
- u8 header_type;
-
- /* read the STATUS register on this device
- */
- status = get_pci_parity_status(dev, 0);
-
- debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id );
-
- /* check the status reg for errors */
- if (status) {
- if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Signaled System Error on %s\n",
- pci_name(dev));
-
- if (status & (PCI_STATUS_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Master Data Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
-
- if (status & (PCI_STATUS_DETECTED_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI,
- "Detected Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
- }
-
- /* read the device TYPE, looking for bridges */
- pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
-
- debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id );
-
- if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
- /* On bridges, need to examine secondary status register */
- status = get_pci_parity_status(dev, 1);
-
- debugf2("PCI SEC_STATUS= 0x%04x %s\n",
- status, dev->dev.bus_id );
-
- /* check the secondary status reg for errors */
- if (status) {
- if (status & (PCI_STATUS_SIG_SYSTEM_ERROR))
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Signaled System Error on %s\n",
- pci_name(dev));
-
- if (status & (PCI_STATUS_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Master Data Parity Error on "
- "%s\n", pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
-
- if (status & (PCI_STATUS_DETECTED_PARITY)) {
- edac_printk(KERN_CRIT, EDAC_PCI, "Bridge "
- "Detected Parity Error on %s\n",
- pci_name(dev));
-
- atomic_inc(&pci_parity_count);
- }
- }
- }
-}
-
-/*
- * check_dev_on_list: Scan for a PCI device on a white/black list
- * @list: an EDAC &edac_pci_device_list white/black list pointer
- * @free_index: index of next free entry on the list
- * @pci_dev: PCI Device pointer
- *
- * see if list contains the device.
- *
- * Returns: 0 not found
- * 1 found on list
- */
-static int check_dev_on_list(struct edac_pci_device_list *list,
- int free_index, struct pci_dev *dev)
-{
- int i;
- int rc = 0; /* Assume not found */
- unsigned short vendor=dev->vendor;
- unsigned short device=dev->device;
-
- /* Scan the list, looking for a vendor/device match */
- for (i = 0; i < free_index; i++, list++ ) {
- if ((list->vendor == vendor ) && (list->device == device )) {
- rc = 1;
- break;
- }
- }
-
- return rc;
-}
-
-/*
- * pci_dev parity list iterator
- * Scan the PCI device list for one iteration, looking for SERRORs
- * Master Parity ERRORS or Parity ERRORs on primary or secondary devices
- */
-static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
-{
- struct pci_dev *dev = NULL;
-
- /* request for kernel access to the next PCI device, if any,
- * and while we are looking at it have its reference count
- * bumped until we are done with it
- */
- while((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- /* if whitelist exists then it has priority, so only scan
- * those devices on the whitelist
- */
- if (pci_whitelist_count > 0 ) {
- if (check_dev_on_list(pci_whitelist,
- pci_whitelist_count, dev))
- fn(dev);
- } else {
- /*
- * if no whitelist, then check if this devices is
- * blacklisted
- */
- if (!check_dev_on_list(pci_blacklist,
- pci_blacklist_count, dev))
- fn(dev);
- }
- }
-}
-
-static void do_pci_parity_check(void)
-{
- unsigned long flags;
- int before_count;
-
- debugf3("%s()\n", __func__);
-
- if (!check_pci_parity)
- return;
-
- before_count = atomic_read(&pci_parity_count);
-
- /* scan all PCI devices looking for a Parity Error on devices and
- * bridges
- */
- local_irq_save(flags);
- edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
- local_irq_restore(flags);
-
- /* Only if operator has selected panic on PCI Error */
- if (panic_on_pci_parity) {
- /* If the count is different 'after' from 'before' */
- if (before_count != atomic_read(&pci_parity_count))
- panic("EDAC: PCI Parity Error");
- }
-}
-
-static inline void clear_pci_parity_errors(void)
-{
- /* Clear any PCI bus parity errors that devices initially have logged
- * in their registers.
- */
- edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
-}
-
-#else /* CONFIG_PCI */
-
-static inline void do_pci_parity_check(void)
-{
- /* no-op */
-}
-
-static inline void clear_pci_parity_errors(void)
-{
- /* no-op */
-}
-
-#endif /* CONFIG_PCI */
/*
* Iterate over all MC instances and check for ECC, et al, errors
@@ -2096,10 +1811,12 @@ MODULE_DESCRIPTION("Core library routines for MC reporting");
module_param(panic_on_ue, int, 0644);
MODULE_PARM_DESC(panic_on_ue, "Panic on uncorrected error: 0=off 1=on");
+#ifdef CONFIG_PCI
module_param(check_pci_parity, int, 0644);
MODULE_PARM_DESC(check_pci_parity, "Check for PCI bus parity errors: 0=off 1=on");
module_param(panic_on_pci_parity, int, 0644);
MODULE_PARM_DESC(panic_on_pci_parity, "Panic on PCI Bus Parity error: 0=off 1=on");
+#endif
module_param(log_ue, int, 0644);
MODULE_PARM_DESC(log_ue, "Log uncorrectable error to console: 0=off 1=on");
module_param(log_ce, int, 0644);
diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h
index 8d9e83909b9..a1cfd4e3c97 100644
--- a/drivers/edac/edac_mc.h
+++ b/drivers/edac/edac_mc.h
@@ -18,7 +18,6 @@
#ifndef _EDAC_MC_H_
#define _EDAC_MC_H_
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
@@ -30,6 +29,7 @@
#include <linux/rcupdate.h>
#include <linux/completion.h>
#include <linux/kobject.h>
+#include <linux/platform_device.h>
#define EDAC_MC_LABEL_LEN 31
#define MC_PROC_NAME_MAX_LEN 7
@@ -79,15 +79,17 @@ extern int edac_debug_level;
#endif /* !CONFIG_EDAC_DEBUG */
-#define edac_xstr(s) edac_str(s)
-#define edac_str(s) #s
-#define EDAC_MOD_STR edac_xstr(KBUILD_BASENAME)
-
#define BIT(x) (1 << (x))
#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \
PCI_DEVICE_ID_ ## vend ## _ ## dev
+#if defined(CONFIG_X86) && defined(CONFIG_PCI)
+#define dev_name(dev) pci_name(to_pci_dev(dev))
+#else
+#define dev_name(dev) to_platform_device(dev)->name
+#endif
+
/* memory devices */
enum dev_type {
DEV_UNKNOWN = 0,
@@ -327,10 +329,10 @@ struct mem_ctl_info {
struct csrow_info *csrows;
/*
* FIXME - what about controllers on other busses? - IDs must be
- * unique. pdev pointer should be sufficiently unique, but
+ * unique. dev pointer should be sufficiently unique, but
* BUS:SLOT.FUNC numbers may not be unique.
*/
- struct pci_dev *pdev;
+ struct device *dev;
const char *mod_name;
const char *mod_ver;
const char *ctl_name;
@@ -353,6 +355,8 @@ struct mem_ctl_info {
struct completion kobj_complete;
};
+#ifdef CONFIG_PCI
+
/* write all or some bits in a byte-register*/
static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value,
u8 mask)
@@ -401,14 +405,16 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
pci_write_config_dword(pdev, offset, value);
}
+#endif /* CONFIG_PCI */
+
#ifdef CONFIG_EDAC_DEBUG
void edac_mc_dump_channel(struct channel_info *chan);
void edac_mc_dump_mci(struct mem_ctl_info *mci);
void edac_mc_dump_csrow(struct csrow_info *csrow);
#endif /* CONFIG_EDAC_DEBUG */
-extern int edac_mc_add_mc(struct mem_ctl_info *mci);
-extern struct mem_ctl_info * edac_mc_del_mc(struct pci_dev *pdev);
+extern int edac_mc_add_mc(struct mem_ctl_info *mci,int mc_idx);
+extern struct mem_ctl_info * edac_mc_del_mc(struct device *dev);
extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
unsigned long page);
extern void edac_mc_scrub_block(unsigned long page, unsigned long offset,
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index fd342163cf9..e4bb298e613 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -9,7 +9,6 @@
* by Thayne Harbaugh of Linux Networx. (http://lnxi.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -17,6 +16,9 @@
#include <linux/slab.h>
#include "edac_mc.h"
+#define I82860_REVISION " Ver: 2.0.1 " __DATE__
+#define EDAC_MOD_STR "i82860_edac"
+
#define i82860_printk(level, fmt, arg...) \
edac_printk(level, "i82860", fmt, ##arg)
@@ -63,17 +65,21 @@ static struct pci_dev *mci_pdev = NULL; /* init dev: in case that AGP code
static void i82860_get_error_info(struct mem_ctl_info *mci,
struct i82860_error_info *info)
{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+
/*
* This is a mess because there is no atomic way to read all the
* registers at once and the registers can transition from CE being
* overwritten by UE.
*/
- pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts);
- pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
- pci_read_config_word(mci->pdev, I82860_DERRCTL_STS, &info->derrsyn);
- pci_read_config_word(mci->pdev, I82860_ERRSTS, &info->errsts2);
+ pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts);
+ pci_read_config_dword(pdev, I82860_EAP, &info->eap);
+ pci_read_config_word(pdev, I82860_DERRCTL_STS, &info->derrsyn);
+ pci_read_config_word(pdev, I82860_ERRSTS, &info->errsts2);
- pci_write_bits16(mci->pdev, I82860_ERRSTS, 0x0003, 0x0003);
+ pci_write_bits16(pdev, I82860_ERRSTS, 0x0003, 0x0003);
/*
* If the error is the same for both reads then the first set of reads
@@ -84,8 +90,8 @@ static void i82860_get_error_info(struct mem_ctl_info *mci,
return;
if ((info->errsts ^ info->errsts2) & 0x0003) {
- pci_read_config_dword(mci->pdev, I82860_EAP, &info->eap);
- pci_read_config_word(mci->pdev, I82860_DERRCTL_STS,
+ pci_read_config_dword(pdev, I82860_EAP, &info->eap);
+ pci_read_config_word(pdev, I82860_DERRCTL_STS,
&info->derrsyn);
}
}
@@ -127,15 +133,50 @@ static void i82860_check(struct mem_ctl_info *mci)
i82860_process_error_info(mci, &info, 1);
}
-static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
+static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
{
- int rc = -ENODEV;
- int index;
- struct mem_ctl_info *mci = NULL;
unsigned long last_cumul_size;
- struct i82860_error_info discard;
+ u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
+ u16 value;
+ u32 cumul_size;
+ struct csrow_info *csrow;
+ int index;
+
+ pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim);
+ mchcfg_ddim = mchcfg_ddim & 0x180;
+ last_cumul_size = 0;
+
+ /* The group row boundary (GRA) reg values are boundary address
+ * for each DRAM row with a granularity of 16MB. GRA regs are
+ * cumulative; therefore GRA15 will contain the total memory contained
+ * in all eight rows.
+ */
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+ pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
+ cumul_size = (value & I82860_GBA_MASK) <<
+ (I82860_GBA_SHIFT - PAGE_SHIFT);
+ debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
+ cumul_size);
- u16 mchcfg_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
+ if (cumul_size == last_cumul_size)
+ continue; /* not populated */
+
+ csrow->first_page = last_cumul_size;
+ csrow->last_page = cumul_size - 1;
+ csrow->nr_pages = cumul_size - last_cumul_size;
+ last_cumul_size = cumul_size;
+ csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
+ csrow->mtype = MEM_RMBS;
+ csrow->dtype = DEV_UNKNOWN;
+ csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
+ }
+}
+
+static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ struct mem_ctl_info *mci;
+ struct i82860_error_info discard;
/* RDRAM has channels but these don't map onto the abstractions that
edac uses.
@@ -151,67 +192,35 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
return -ENOMEM;
debugf3("%s(): init mci\n", __func__);
- mci->pdev = pdev;
+ mci->dev = &pdev->dev;
mci->mtype_cap = MEM_FLAG_DDR;
-
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
/* I"m not sure about this but I think that all RDRAM is SECDED */
mci->edac_cap = EDAC_FLAG_SECDED;
- /* adjust FLAGS */
-
mci->mod_name = EDAC_MOD_STR;
- mci->mod_ver = "$Revision: 1.1.2.6 $";
+ mci->mod_ver = I82860_REVISION;
mci->ctl_name = i82860_devs[dev_idx].ctl_name;
mci->edac_check = i82860_check;
mci->ctl_page_to_phys = NULL;
+ i82860_init_csrows(mci, pdev);
+ i82860_get_error_info(mci, &discard); /* clear counters */
- pci_read_config_word(mci->pdev, I82860_MCHCFG, &mchcfg_ddim);
- mchcfg_ddim = mchcfg_ddim & 0x180;
-
- /*
- * The group row boundary (GRA) reg values are boundary address
- * for each DRAM row with a granularity of 16MB. GRA regs are
- * cumulative; therefore GRA15 will contain the total memory contained
- * in all eight rows.
+ /* Here we assume that we will never see multiple instances of this
+ * type of memory controller. The ID is therefore hardcoded to 0.
*/
- for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
- u16 value;
- u32 cumul_size;
- struct csrow_info *csrow = &mci->csrows[index];
-
- pci_read_config_word(mci->pdev, I82860_GBA + index * 2,
- &value);
-
- cumul_size = (value & I82860_GBA_MASK) <<
- (I82860_GBA_SHIFT - PAGE_SHIFT);
- debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
- cumul_size);
-
- if (cumul_size == last_cumul_size)
- continue; /* not populated */
-
- csrow->first_page = last_cumul_size;
- csrow->last_page = cumul_size - 1;
- csrow->nr_pages = cumul_size - last_cumul_size;
- last_cumul_size = cumul_size;
- csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
- csrow->mtype = MEM_RMBS;
- csrow->dtype = DEV_UNKNOWN;
- csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
+ if (edac_mc_add_mc(mci,0)) {
+ debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
+ goto fail;
}
- i82860_get_error_info(mci, &discard); /* clear counters */
+ /* get this far and it's successful */
+ debugf3("%s(): success\n", __func__);
- if (edac_mc_add_mc(mci)) {
- debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
- edac_mc_free(mci);
- } else {
- /* get this far and it's successful */
- debugf3("%s(): success\n", __func__);
- rc = 0;
- }
+ return 0;
- return rc;
+fail:
+ edac_mc_free(mci);
+ return -ENODEV;
}
/* returns count (>= 0), or negative on error */
@@ -240,7 +249,7 @@ static void __devexit i82860_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
- if ((mci = edac_mc_del_mc(pdev)) == NULL)
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
edac_mc_free(mci);
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 0aec92698f1..161fe09a6d3 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -13,7 +13,6 @@
* Note: E7210 appears same as D82875P - zhenyu.z.wang at intel.com
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -21,6 +20,9 @@
#include <linux/slab.h>
#include "edac_mc.h"
+#define I82875P_REVISION " Ver: 2.0.1 " __DATE__
+#define EDAC_MOD_STR "i82875p_edac"
+
#define i82875p_printk(level, fmt, arg...) \
edac_printk(level, "i82875p", fmt, ##arg)
@@ -185,18 +187,22 @@ static int i82875p_registered = 1;
static void i82875p_get_error_info(struct mem_ctl_info *mci,
struct i82875p_error_info *info)
{
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+
/*
* This is a mess because there is no atomic way to read all the
* registers at once and the registers can transition from CE being
* overwritten by UE.
*/
- pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts);
- pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap);
- pci_read_config_byte(mci->pdev, I82875P_DES, &info->des);
- pci_read_config_byte(mci->pdev, I82875P_DERRSYN, &info->derrsyn);
- pci_read_config_word(mci->pdev, I82875P_ERRSTS, &info->errsts2);
+ pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
+ pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
+ pci_read_config_byte(pdev, I82875P_DES, &info->des);
+ pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
+ pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
- pci_write_bits16(mci->pdev, I82875P_ERRSTS, 0x0081, 0x0081);
+ pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
/*
* If the error is the same then we can for both reads then
@@ -208,9 +214,9 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
return;
if ((info->errsts ^ info->errsts2) & 0x0081) {
- pci_read_config_dword(mci->pdev, I82875P_EAP, &info->eap);
- pci_read_config_byte(mci->pdev, I82875P_DES, &info->des);
- pci_read_config_byte(mci->pdev, I82875P_DERRSYN,
+ pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
+ pci_read_config_byte(pdev, I82875P_DES, &info->des);
+ pci_read_config_byte(pdev, I82875P_DERRSYN,
&info->derrsyn);
}
}
@@ -259,116 +265,109 @@ static void i82875p_check(struct mem_ctl_info *mci)
extern int pci_proc_attach_device(struct pci_dev *);
#endif
-static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
+/* Return 0 on success or 1 on failure. */
+static int i82875p_setup_overfl_dev(struct pci_dev *pdev,
+ struct pci_dev **ovrfl_pdev, void __iomem **ovrfl_window)
{
- int rc = -ENODEV;
- int index;
- struct mem_ctl_info *mci = NULL;
- struct i82875p_pvt *pvt = NULL;
- unsigned long last_cumul_size;
- struct pci_dev *ovrfl_pdev;
- void __iomem *ovrfl_window = NULL;
- u32 drc;
- u32 drc_chan; /* Number of channels 0=1chan,1=2chan */
- u32 nr_chans;
- u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
- struct i82875p_error_info discard;
+ struct pci_dev *dev;
+ void __iomem *window;
- debugf0("%s()\n", __func__);
- ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
+ *ovrfl_pdev = NULL;
+ *ovrfl_window = NULL;
+ dev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
- if (!ovrfl_pdev) {
- /*
- * Intel tells BIOS developers to hide device 6 which
+ if (dev == NULL) {
+ /* Intel tells BIOS developers to hide device 6 which
* configures the overflow device access containing
* the DRBs - this is where we expose device 6.
* http://www.x86-secret.com/articles/tweak/pat/patsecrets-2.htm
*/
pci_write_bits8(pdev, 0xf4, 0x2, 0x2);
- ovrfl_pdev =
- pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0));
+ dev = pci_scan_single_device(pdev->bus, PCI_DEVFN(6, 0));
- if (!ovrfl_pdev)
- return -ENODEV;
+ if (dev == NULL)
+ return 1;
}
+ *ovrfl_pdev = dev;
+
#ifdef CONFIG_PROC_FS
- if (!ovrfl_pdev->procent && pci_proc_attach_device(ovrfl_pdev)) {
- i82875p_printk(KERN_ERR,
- "%s(): Failed to attach overflow device\n", __func__);
- return -ENODEV;
+ if ((dev->procent == NULL) && pci_proc_attach_device(dev)) {
+ i82875p_printk(KERN_ERR, "%s(): Failed to attach overflow "
+ "device\n", __func__);
+ return 1;
}
-#endif
- /* CONFIG_PROC_FS */
- if (pci_enable_device(ovrfl_pdev)) {
- i82875p_printk(KERN_ERR,
- "%s(): Failed to enable overflow device\n", __func__);
- return -ENODEV;
+#endif /* CONFIG_PROC_FS */
+ if (pci_enable_device(dev)) {
+ i82875p_printk(KERN_ERR, "%s(): Failed to enable overflow "
+ "device\n", __func__);
+ return 1;
}
- if (pci_request_regions(ovrfl_pdev, pci_name(ovrfl_pdev))) {
+ if (pci_request_regions(dev, pci_name(dev))) {
#ifdef CORRECT_BIOS
goto fail0;
#endif
}
/* cache is irrelevant for PCI bus reads/writes */
- ovrfl_window = ioremap_nocache(pci_resource_start(ovrfl_pdev, 0),
- pci_resource_len(ovrfl_pdev, 0));
+ window = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
- if (!ovrfl_window) {
+ if (window == NULL) {
i82875p_printk(KERN_ERR, "%s(): Failed to ioremap bar6\n",
- __func__);
+ __func__);
goto fail1;
}
- /* need to find out the number of channels */
- drc = readl(ovrfl_window + I82875P_DRC);
- drc_chan = ((drc >> 21) & 0x1);
- nr_chans = drc_chan + 1;
+ *ovrfl_window = window;
+ return 0;
- drc_ddim = (drc >> 18) & 0x1;
- mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
- nr_chans);
+fail1:
+ pci_release_regions(dev);
- if (!mci) {
- rc = -ENOMEM;
- goto fail2;
- }
+#ifdef CORRECT_BIOS
+fail0:
+ pci_disable_device(dev);
+#endif
+ /* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
+ return 1;
+}
- debugf3("%s(): init mci\n", __func__);
- mci->pdev = pdev;
- mci->mtype_cap = MEM_FLAG_DDR;
- mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
- mci->edac_cap = EDAC_FLAG_UNKNOWN;
- /* adjust FLAGS */
- mci->mod_name = EDAC_MOD_STR;
- mci->mod_ver = "$Revision: 1.5.2.11 $";
- mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
- mci->edac_check = i82875p_check;
- mci->ctl_page_to_phys = NULL;
- debugf3("%s(): init pvt\n", __func__);
- pvt = (struct i82875p_pvt *) mci->pvt_info;
- pvt->ovrfl_pdev = ovrfl_pdev;
- pvt->ovrfl_window = ovrfl_window;
+/* Return 1 if dual channel mode is active. Else return 0. */
+static inline int dual_channel_active(u32 drc)
+{
+ return (drc >> 21) & 0x1;
+}
- /*
- * The dram row boundary (DRB) reg values are boundary address
+
+static void i82875p_init_csrows(struct mem_ctl_info *mci,
+ struct pci_dev *pdev, void __iomem *ovrfl_window, u32 drc)
+{
+ struct csrow_info *csrow;
+ unsigned long last_cumul_size;
+ u8 value;
+ u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
+ u32 cumul_size;
+ int index;
+
+ drc_ddim = (drc >> 18) & 0x1;
+ last_cumul_size = 0;
+
+ /* The dram row boundary (DRB) reg values are boundary address
* for each DRAM row with a granularity of 32 or 64MB (single/dual
* channel operation). DRB regs are cumulative; therefore DRB7 will
* contain the total memory contained in all eight rows.
*/
- for (last_cumul_size = index = 0; index < mci->nr_csrows; index++) {
- u8 value;
- u32 cumul_size;
- struct csrow_info *csrow = &mci->csrows[index];
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
value = readb(ovrfl_window + I82875P_DRB + index);
cumul_size = value << (I82875P_DRB_SHIFT - PAGE_SHIFT);
debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
cumul_size);
-
if (cumul_size == last_cumul_size)
continue; /* not populated */
@@ -376,35 +375,75 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
- csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
+ csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
csrow->mtype = MEM_DDR;
csrow->dtype = DEV_UNKNOWN;
csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
}
+}
+
+static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ int rc = -ENODEV;
+ struct mem_ctl_info *mci;
+ struct i82875p_pvt *pvt;
+ struct pci_dev *ovrfl_pdev;
+ void __iomem *ovrfl_window;
+ u32 drc;
+ u32 nr_chans;
+ struct i82875p_error_info discard;
+
+ debugf0("%s()\n", __func__);
+ ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
+
+ if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
+ return -ENODEV;
+ drc = readl(ovrfl_window + I82875P_DRC);
+ nr_chans = dual_channel_active(drc) + 1;
+ mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
+ nr_chans);
+
+ if (!mci) {
+ rc = -ENOMEM;
+ goto fail0;
+ }
+ debugf3("%s(): init mci\n", __func__);
+ mci->dev = &pdev->dev;
+ mci->mtype_cap = MEM_FLAG_DDR;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+ mci->edac_cap = EDAC_FLAG_UNKNOWN;
+ mci->mod_name = EDAC_MOD_STR;
+ mci->mod_ver = I82875P_REVISION;
+ mci->ctl_name = i82875p_devs[dev_idx].ctl_name;
+ mci->edac_check = i82875p_check;
+ mci->ctl_page_to_phys = NULL;
+ debugf3("%s(): init pvt\n", __func__);
+ pvt = (struct i82875p_pvt *) mci->pvt_info;
+ pvt->ovrfl_pdev = ovrfl_pdev;
+ pvt->ovrfl_window = ovrfl_window;
+ i82875p_init_csrows(mci, pdev, ovrfl_window, drc);
i82875p_get_error_info(mci, &discard); /* clear counters */
- if (edac_mc_add_mc(mci)) {
+ /* Here we assume that we will never see multiple instances of this
+ * type of memory controller. The ID is therefore hardcoded to 0.
+ */
+ if (edac_mc_add_mc(mci,0)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
- goto fail3;
+ goto fail1;
}
/* get this far and it's successful */
debugf3("%s(): success\n", __func__);
return 0;
-fail3:
+fail1:
edac_mc_free(mci);
-fail2:
+fail0:
iounmap(ovrfl_window);
-
-fail1:
pci_release_regions(ovrfl_pdev);
-#ifdef CORRECT_BIOS
-fail0:
-#endif
pci_disable_device(ovrfl_pdev);
/* NOTE: the ovrfl proc entry and pci_dev are intentionally left */
return rc;
@@ -437,7 +476,7 @@ static void __devexit i82875p_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
- if ((mci = edac_mc_del_mc(pdev)) == NULL)
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
pvt = (struct i82875p_pvt *) mci->pvt_info;
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index 2c29fafe67c..a49cf0a3939 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -15,7 +15,6 @@
* references to this document given in []
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -23,6 +22,9 @@
#include <linux/slab.h>
#include "edac_mc.h"
+#define R82600_REVISION " Ver: 2.0.1 " __DATE__
+#define EDAC_MOD_STR "r82600_edac"
+
#define r82600_printk(level, fmt, arg...) \
edac_printk(level, "r82600", fmt, ##arg)
@@ -134,17 +136,20 @@ static unsigned int disable_hardware_scrub = 0;
static void r82600_get_error_info (struct mem_ctl_info *mci,
struct r82600_error_info *info)
{
- pci_read_config_dword(mci->pdev, R82600_EAP, &info->eapr);
+ struct pci_dev *pdev;
+
+ pdev = to_pci_dev(mci->dev);
+ pci_read_config_dword(pdev, R82600_EAP, &info->eapr);
if (info->eapr & BIT(0))
/* Clear error to allow next error to be reported [p.62] */
- pci_write_bits32(mci->pdev, R82600_EAP,
+ pci_write_bits32(pdev, R82600_EAP,
((u32) BIT(0) & (u32) BIT(1)),
((u32) BIT(0) & (u32) BIT(1)));
if (info->eapr & BIT(1))
/* Clear error to allow next error to be reported [p.62] */
- pci_write_bits32(mci->pdev, R82600_EAP,
+ pci_write_bits32(pdev, R82600_EAP,
((u32) BIT(0) & (u32) BIT(1)),
((u32) BIT(0) & (u32) BIT(1)));
}
@@ -200,25 +205,72 @@ static void r82600_check(struct mem_ctl_info *mci)
r82600_process_error_info(mci, &info, 1);
}
-static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
+static inline int ecc_enabled(u8 dramcr)
+{
+ return dramcr & BIT(5);
+}
+
+static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
+ u8 dramcr)
{
- int rc = -ENODEV;
+ struct csrow_info *csrow;
int index;
- struct mem_ctl_info *mci = NULL;
+ u8 drbar; /* SDRAM Row Boundry Address Register */
+ u32 row_high_limit, row_high_limit_last;
+ u32 reg_sdram, ecc_on, row_base;
+
+ ecc_on = ecc_enabled(dramcr);
+ reg_sdram = dramcr & BIT(4);
+ row_high_limit_last = 0;
+
+ for (index = 0; index < mci->nr_csrows; index++) {
+ csrow = &mci->csrows[index];
+
+ /* find the DRAM Chip Select Base address and mask */
+ pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
+
+ debugf1("%s() Row=%d DRBA = %#0x\n", __func__, index, drbar);
+
+ row_high_limit = ((u32) drbar << 24);
+/* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */
+
+ debugf1("%s() Row=%d, Boundry Address=%#0x, Last = %#0x\n",
+ __func__, index, row_high_limit, row_high_limit_last);
+
+ /* Empty row [p.57] */
+ if (row_high_limit == row_high_limit_last)
+ continue;
+
+ row_base = row_high_limit_last;
+
+ csrow->first_page = row_base >> PAGE_SHIFT;
+ csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
+ csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
+ /* Error address is top 19 bits - so granularity is *
+ * 14 bits */
+ csrow->grain = 1 << 14;
+ csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
+ /* FIXME - check that this is unknowable with this chipset */
+ csrow->dtype = DEV_UNKNOWN;
+
+ /* Mode is global on 82600 */
+ csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
+ row_high_limit_last = row_high_limit;
+ }
+}
+
+static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
+{
+ struct mem_ctl_info *mci;
u8 dramcr;
- u32 ecc_on;
- u32 reg_sdram;
u32 eapr;
u32 scrub_disabled;
u32 sdram_refresh_rate;
- u32 row_high_limit_last = 0;
struct r82600_error_info discard;
debugf0("%s()\n", __func__);
pci_read_config_byte(pdev, R82600_DRAMC, &dramcr);
pci_read_config_dword(pdev, R82600_EAP, &eapr);
- ecc_on = dramcr & BIT(5);
- reg_sdram = dramcr & BIT(4);
scrub_disabled = eapr & BIT(31);
sdram_refresh_rate = dramcr & (BIT(0) | BIT(1));
debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
@@ -226,13 +278,11 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS);
- if (mci == NULL) {
- rc = -ENOMEM;
- goto fail;
- }
+ if (mci == NULL)
+ return -ENOMEM;
debugf0("%s(): mci = %p\n", __func__, mci);
- mci->pdev = pdev;
+ mci->dev = &pdev->dev;
mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_DDR;
mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
/* FIXME try to work out if the chip leads have been used for COM2
@@ -245,7 +295,7 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
* is possible. */
mci->edac_cap = EDAC_FLAG_NONE | EDAC_FLAG_EC | EDAC_FLAG_SECDED;
- if (ecc_on) {
+ if (ecc_enabled(dramcr)) {
if (scrub_disabled)
debugf3("%s(): mci = %p - Scrubbing disabled! EAP: "
"%#0x\n", __func__, mci, eapr);
@@ -253,53 +303,17 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
mci->edac_cap = EDAC_FLAG_NONE;
mci->mod_name = EDAC_MOD_STR;
- mci->mod_ver = "$Revision: 1.1.2.6 $";
+ mci->mod_ver = R82600_REVISION;
mci->ctl_name = "R82600";
mci->edac_check = r82600_check;
mci->ctl_page_to_phys = NULL;
-
- for (index = 0; index < mci->nr_csrows; index++) {
- struct csrow_info *csrow = &mci->csrows[index];
- u8 drbar; /* sDram Row Boundry Address Register */
- u32 row_high_limit;
- u32 row_base;
-
- /* find the DRAM Chip Select Base address and mask */
- pci_read_config_byte(mci->pdev, R82600_DRBA + index, &drbar);
-
- debugf1("MC%d: %s() Row=%d DRBA = %#0x\n", mci->mc_idx,
- __func__, index, drbar);
-
- row_high_limit = ((u32) drbar << 24);
-/* row_high_limit = ((u32)drbar << 24) | 0xffffffUL; */
-
- debugf1("MC%d: %s() Row=%d, Boundry Address=%#0x, Last = "
- "%#0x \n", mci->mc_idx, __func__, index,
- row_high_limit, row_high_limit_last);
-
- /* Empty row [p.57] */
- if (row_high_limit == row_high_limit_last)
- continue;
-
- row_base = row_high_limit_last;
- csrow->first_page = row_base >> PAGE_SHIFT;
- csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
- csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
- /* Error address is top 19 bits - so granularity is *
- * 14 bits */
- csrow->grain = 1 << 14;
- csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
- /* FIXME - check that this is unknowable with this chipset */
- csrow->dtype = DEV_UNKNOWN;
-
- /* Mode is global on 82600 */
- csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
- row_high_limit_last = row_high_limit;
- }
-
+ r82600_init_csrows(mci, pdev, dramcr);
r82600_get_error_info(mci, &discard); /* clear counters */
- if (edac_mc_add_mc(mci)) {
+ /* Here we assume that we will never see multiple instances of this
+ * type of memory controller. The ID is therefore hardcoded to 0.
+ */
+ if (edac_mc_add_mc(mci,0)) {
debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
goto fail;
}
@@ -309,17 +323,15 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
if (disable_hardware_scrub) {
debugf3("%s(): Disabling Hardware Scrub (scrub on error)\n",
__func__);
- pci_write_bits32(mci->pdev, R82600_EAP, BIT(31), BIT(31));
+ pci_write_bits32(pdev, R82600_EAP, BIT(31), BIT(31));
}
debugf3("%s(): success\n", __func__);
return 0;
fail:
- if (mci)
- edac_mc_free(mci);
-
- return rc;
+ edac_mc_free(mci);
+ return -ENODEV;
}
/* returns count (>= 0), or negative on error */
@@ -338,7 +350,7 @@ static void __devexit r82600_remove_one(struct pci_dev *pdev)
debugf0("%s()\n", __func__);
- if ((mci = edac_mc_del_mc(pdev)) == NULL)
+ if ((mci = edac_mc_del_mc(&pdev->dev)) == NULL)
return;
edac_mc_free(mci);
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index 6078e2f5881..3a365e159d8 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -128,9 +128,23 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv)
return 0;
}
+static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct eisa_device *edev = to_eisa_device(dev);
+ int i = 0;
+ int length = 0;
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
+ envp[i] = NULL;
+ return 0;
+}
+
struct bus_type eisa_bus_type = {
.name = "eisa",
.match = eisa_bus_match,
+ .uevent = eisa_bus_uevent,
};
int eisa_driver_register (struct eisa_driver *edrv)
@@ -160,6 +174,14 @@ static ssize_t eisa_show_state (struct device *dev, struct device_attribute *att
static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL);
+static ssize_t eisa_show_modalias (struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct eisa_device *edev = to_eisa_device (dev);
+ return sprintf (buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
+}
+
+static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL);
+
static int __init eisa_init_device (struct eisa_root_device *root,
struct eisa_device *edev,
int slot)
@@ -209,6 +231,7 @@ static int __init eisa_register_device (struct eisa_device *edev)
device_create_file (&edev->dev, &dev_attr_signature);
device_create_file (&edev->dev, &dev_attr_enabled);
+ device_create_file (&edev->dev, &dev_attr_modalias);
return 0;
}
diff --git a/drivers/eisa/virtual_root.c b/drivers/eisa/virtual_root.c
index 0f97a0cb0ff..9b4fcac03ad 100644
--- a/drivers/eisa/virtual_root.c
+++ b/drivers/eisa/virtual_root.c
@@ -7,7 +7,6 @@
* This code is released under the GPL version 2.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/eisa.h>
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index 66d03f242d3..1a159e8843c 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -429,7 +429,7 @@ static inline void fcp_scsi_receive(fc_channel *fc, int token, int status, fc_hd
if (fcmd->data) {
if (SCpnt->use_sg)
- dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->buffer,
+ dma_unmap_sg(fc->dev, (struct scatterlist *)SCpnt->request_buffer,
SCpnt->use_sg,
SCpnt->sc_data_direction);
else
@@ -810,7 +810,7 @@ static int fcp_scsi_queue_it(fc_channel *fc, Scsi_Cmnd *SCpnt, fcp_cmnd *fcmd, i
SCpnt->request_bufflen,
SCpnt->sc_data_direction);
} else {
- struct scatterlist *sg = (struct scatterlist *)SCpnt->buffer;
+ struct scatterlist *sg = (struct scatterlist *)SCpnt->request_buffer;
int nents;
FCD(("XXX: Use_sg %d %d\n", SCpnt->use_sg, sg->length))
diff --git a/drivers/fc4/fc_syms.c b/drivers/fc4/fc_syms.c
index ed85dfcef69..8700a8076d0 100644
--- a/drivers/fc4/fc_syms.c
+++ b/drivers/fc4/fc_syms.c
@@ -2,7 +2,6 @@
* We should not even be trying to compile this if we are not doing
* a module.
*/
-#include <linux/config.h>
#include <linux/module.h>
#ifdef CONFIG_MODULES
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
index cf8768b8d1f..3b07e0ca81c 100644
--- a/drivers/fc4/soc.c
+++ b/drivers/fc4/soc.c
@@ -637,7 +637,7 @@ static inline void soc_init(struct sbus_dev *sdev, int no)
irq = sdev->irqs[0];
- if (request_irq (irq, soc_intr, SA_SHIRQ, "SOC", (void *)s)) {
+ if (request_irq (irq, soc_intr, IRQF_SHARED, "SOC", (void *)s)) {
soc_printk ("Cannot order irq %d to go\n", irq);
socs = s->next;
return;
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
index f52d1e5bd5a..2b75edc5859 100644
--- a/drivers/fc4/socal.c
+++ b/drivers/fc4/socal.c
@@ -761,7 +761,7 @@ static inline void socal_init(struct sbus_dev *sdev, int no)
irq = sdev->irqs[0];
- if (request_irq (irq, socal_intr, SA_SHIRQ, "SOCAL", (void *)s)) {
+ if (request_irq (irq, socal_intr, IRQF_SHARED, "SOCAL", (void *)s)) {
socal_printk ("Cannot order irq %d to go\n", irq);
socals = s->next;
return;
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 1e371a510dd..731c3d5da0d 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -6,8 +6,7 @@
menu "Firmware Drivers"
config EDD
- tristate "BIOS Enhanced Disk Drive calls determine boot disk (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on !IA64
help
Say Y or M here if you want to enable BIOS Enhanced Disk Drive
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index fdb8b042e64..23b08668545 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/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/string.h>
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 948bd7e1445..b8b596d5778 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -123,6 +123,26 @@ static void __init dmi_save_devices(struct dmi_header *dm)
dev->type = *d++ & 0x7f;
dev->name = dmi_string(dm, *d);
dev->device_data = NULL;
+ list_add(&dev->list, &dmi_devices);
+ }
+}
+
+static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
+{
+ int i, count = *(u8 *)(dm + 1);
+ struct dmi_device *dev;
+
+ for (i = 1; i <= count; i++) {
+ dev = dmi_alloc(sizeof(*dev));
+ if (!dev) {
+ printk(KERN_ERR
+ "dmi_save_oem_strings_devices: out of memory.\n");
+ break;
+ }
+
+ dev->type = DMI_DEV_TYPE_OEM_STRING;
+ dev->name = dmi_string(dm, i);
+ dev->device_data = NULL;
list_add(&dev->list, &dmi_devices);
}
@@ -181,6 +201,9 @@ static void __init dmi_decode(struct dmi_header *dm)
case 10: /* Onboard Devices Information */
dmi_save_devices(dm);
break;
+ case 11: /* OEM Strings */
+ dmi_save_oem_strings_devices(dm);
+ break;
case 38: /* IPMI Device Information */
dmi_save_ipmi_device(dm);
}
@@ -255,10 +278,15 @@ void __init dmi_scan_machine(void)
/**
* dmi_check_system - check system DMI data
* @list: array of dmi_system_id structures to match against
+ * All non-null elements of the list must match
+ * their slot's (field index's) data (i.e., each
+ * list string must be a substring of the specified
+ * DMI slot's string data) to be considered a
+ * successful match.
*
* Walk the blacklist table running matching functions until someone
* returns non zero or we hit the end. Callback function is called for
- * each successfull match. Returns the number of matches.
+ * each successful match. Returns the number of matches.
*/
int dmi_check_system(struct dmi_system_id *list)
{
@@ -287,7 +315,7 @@ EXPORT_SYMBOL(dmi_check_system);
/**
* dmi_get_system_info - return DMI data value
- * @field: data index (see enum dmi_filed)
+ * @field: data index (see enum dmi_field)
*
* Returns one DMI data value, can be used to perform
* complex DMI data checks.
@@ -301,13 +329,13 @@ EXPORT_SYMBOL(dmi_get_system_info);
/**
* dmi_find_device - find onboard device by type/name
* @type: device type or %DMI_DEV_TYPE_ANY to match all device types
- * @desc: device name string or %NULL to match all
+ * @name: device name string or %NULL to match all
* @from: previous device found in search, or %NULL for new search.
*
* Iterates through the list of known onboard devices. If a device is
* found with a matching @vendor and @device, a pointer to its device
* structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
+ * A new search is initiated by passing %NULL as the @from argument.
* If @from is not %NULL, searches continue from next device.
*/
struct dmi_device * dmi_find_device(int type, const char *name,
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 9b7e4d52ffd..8ebce1c03ad 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -66,7 +66,6 @@
*/
#include <linux/capability.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/init.h>
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index c37baf9448b..c2ad72fefd9 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -11,7 +11,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/acpi.h>
#include <linux/console.h>
#include <linux/efi.h>
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 0e31a0c496e..9b88b25b6ed 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -53,7 +53,7 @@ config SENSORS_ADM1021
config SENSORS_ADM1025
tristate "Analog Devices ADM1025 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1025
@@ -94,6 +94,16 @@ config SENSORS_ADM9240
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_K8TEMP
+ tristate "AMD K8 processor sensor"
+ depends on HWMON && X86 && PCI && EXPERIMENTAL
+ help
+ If you say yes here you get support for the temperature
+ sensor(s) inside your AMD K8 CPU.
+
+ This driver can also be built as a module. If so, the module
+ will be called k8temp.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on HWMON && I2C && EXPERIMENTAL
@@ -121,7 +131,7 @@ config SENSORS_ATXP1
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for Dallas Semiconductor
DS1621 and DS1625 sensor chips.
@@ -141,7 +151,7 @@ config SENSORS_F71805F
config SENSORS_FSCHER
tristate "FSC Hermes"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -151,7 +161,7 @@ config SENSORS_FSCHER
config SENSORS_FSCPOS
tristate "FSC Poseidon"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -171,7 +181,7 @@ config SENSORS_GL518SM
config SENSORS_GL520SM
tristate "Genesys Logic GL520SM"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for Genesys Logic GL520SM
@@ -186,15 +196,15 @@ config SENSORS_IT87
select I2C_ISA
select HWMON_VID
help
- If you say yes here you get support for ITE IT87xx sensor chips
- and clones: SiS960.
+ If you say yes here you get support for ITE IT8705F, IT8712F,
+ IT8716F and IT8718F sensor chips, and the SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
config SENSORS_LM63
tristate "National Semiconductor LM63"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for the National Semiconductor
LM63 remote diode digital temperature sensor with integrated fan
@@ -231,7 +241,7 @@ config SENSORS_LM75
config SENSORS_LM77
tristate "National Semiconductor LM77"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for National Semiconductor LM77
sensor chips.
@@ -241,7 +251,7 @@ config SENSORS_LM77
config SENSORS_LM78
tristate "National Semiconductor LM78 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select I2C_ISA
select HWMON_VID
help
@@ -284,7 +294,7 @@ config SENSORS_LM85
config SENSORS_LM87
tristate "National Semiconductor LM87"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
@@ -309,7 +319,7 @@ config SENSORS_LM90
config SENSORS_LM92
tristate "National Semiconductor LM92 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for National Semiconductor LM92
and Maxim MAX6635 sensor chips.
@@ -319,7 +329,7 @@ config SENSORS_LM92
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for MAX1619 sensor chip.
@@ -354,7 +364,7 @@ config SENSORS_SIS5595
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select I2C_ISA
help
If you say yes here you get support for the integrated fan
@@ -407,8 +417,19 @@ config SENSORS_VIA686A
This driver can also be built as a module. If so, the module
will be called via686a.
+config SENSORS_VT1211
+ tristate "VIA VT1211"
+ depends on HWMON && EXPERIMENTAL
+ select HWMON_VID
+ help
+ If you say yes here then you get support for hardware monitoring
+ features of the VIA VT1211 Super-I/O chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called vt1211.
+
config SENSORS_VT8231
- tristate "VT8231"
+ tristate "VIA VT8231"
depends on HWMON && I2C && PCI && EXPERIMENTAL
select HWMON_VID
select I2C_ISA
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 31415843a91..af01cc64f7d 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
+obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM70) += lm70.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
@@ -45,6 +46,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
+obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 59122cc0a50..e5cb0fdab9b 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -26,6 +26,7 @@
#include <linux/jiffies.h>
#include <linux/mutex.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
@@ -64,17 +65,17 @@
#define ABIT_UGURU_IN_SENSOR 0
#define ABIT_UGURU_TEMP_SENSOR 1
#define ABIT_UGURU_NC 2
-/* Timeouts / Retries, if these turn out to need a lot of fiddling we could
- convert them to params. */
-/* 250 was determined by trial and error, 200 works most of the time, but not
- always. I assume this is cpu-speed independent, since the ISA-bus and not
- the CPU should be the bottleneck. Note that 250 sometimes is still not
- enough (only reported on AN7 mb) this is handled by a higher layer. */
-#define ABIT_UGURU_WAIT_TIMEOUT 250
+/* In many cases we need to wait for the uGuru to reach a certain status, most
+ of the time it will reach this status within 30 - 90 ISA reads, and thus we
+ can best busy wait. This define gives the total amount of reads to try. */
+#define ABIT_UGURU_WAIT_TIMEOUT 125
+/* However sometimes older versions of the uGuru seem to be distracted and they
+ do not respond for a long time. To handle this we sleep before each of the
+ last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. */
+#define ABIT_UGURU_WAIT_TIMEOUT_SLEEP 5
/* Normally all expected status in abituguru_ready, are reported after the
- first read, but sometimes not and we need to poll, 5 polls was not enough
- 50 sofar is. */
-#define ABIT_UGURU_READY_TIMEOUT 50
+ first read, but sometimes not and we need to poll. */
+#define ABIT_UGURU_READY_TIMEOUT 5
/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */
#define ABIT_UGURU_MAX_RETRIES 3
#define ABIT_UGURU_RETRY_DELAY (HZ/5)
@@ -142,6 +143,14 @@ static const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 };
static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Set to one to force detection.");
+static int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
+module_param_array(bank1_types, int, NULL, 0);
+MODULE_PARM_DESC(bank1_types, "Bank1 sensortype autodetection override:\n"
+ " -1 autodetect\n"
+ " 0 volt sensor\n"
+ " 1 temp sensor\n"
+ " 2 not connected");
static int fan_sensors;
module_param(fan_sensors, int, 0);
MODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru "
@@ -218,6 +227,10 @@ static int abituguru_wait(struct abituguru_data *data, u8 state)
timeout--;
if (timeout == 0)
return -EBUSY;
+ /* sleep a bit before our last few tries, see the comment on
+ this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. */
+ if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP)
+ msleep(0);
}
return 0;
}
@@ -248,6 +261,7 @@ static int abituguru_ready(struct abituguru_data *data)
"CMD reg does not hold 0xAC after ready command\n");
return -EIO;
}
+ msleep(0);
}
/* After this the ABIT_UGURU_DATA port should contain
@@ -260,6 +274,7 @@ static int abituguru_ready(struct abituguru_data *data)
"state != more input after ready command\n");
return -EIO;
}
+ msleep(0);
}
data->uguru_ready = 1;
@@ -323,7 +338,8 @@ static int abituguru_read(struct abituguru_data *data,
/* And read the data */
for (i = 0; i < count; i++) {
if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
- ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for "
+ ABIT_UGURU_DEBUG(retries ? 1 : 3,
+ "timeout exceeded waiting for "
"read state (bank: %d, sensor: %d)\n",
(int)bank_addr, (int)sensor_addr);
break;
@@ -342,7 +358,9 @@ static int abituguru_read(struct abituguru_data *data,
static int abituguru_write(struct abituguru_data *data,
u8 bank_addr, u8 sensor_addr, u8 *buf, int count)
{
- int i;
+ /* We use the ready timeout as we have to wait for 0xAC just like the
+ ready function */
+ int i, timeout = ABIT_UGURU_READY_TIMEOUT;
/* Send the address */
i = abituguru_send_address(data, bank_addr, sensor_addr,
@@ -362,7 +380,8 @@ static int abituguru_write(struct abituguru_data *data,
}
/* Now we need to wait till the chip is ready to be read again,
- don't ask why */
+ so that we can read 0xAC as confirmation that our write has
+ succeeded. */
if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) {
ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state "
"after write (bank: %d, sensor: %d)\n", (int)bank_addr,
@@ -371,11 +390,15 @@ static int abituguru_write(struct abituguru_data *data,
}
/* Cmd port MUST be read now and should contain 0xAC */
- if (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
- ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after write "
- "(bank: %d, sensor: %d)\n", (int)bank_addr,
- (int)sensor_addr);
- return -EIO;
+ while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) {
+ timeout--;
+ if (timeout == 0) {
+ ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after "
+ "write (bank: %d, sensor: %d)\n",
+ (int)bank_addr, (int)sensor_addr);
+ return -EIO;
+ }
+ msleep(0);
}
/* Last put the chip back in ready state */
@@ -395,7 +418,16 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
u8 sensor_addr)
{
u8 val, buf[3];
- int ret = ABIT_UGURU_NC;
+ int i, ret = -ENODEV; /* error is the most common used retval :| */
+
+ /* If overriden by the user return the user selected type */
+ if (bank1_types[sensor_addr] >= ABIT_UGURU_IN_SENSOR &&
+ bank1_types[sensor_addr] <= ABIT_UGURU_NC) {
+ ABIT_UGURU_DEBUG(2, "assuming sensor type %d for bank1 sensor "
+ "%d because of \"bank1_types\" module param\n",
+ bank1_types[sensor_addr], (int)sensor_addr);
+ return bank1_types[sensor_addr];
+ }
/* First read the sensor and the current settings */
if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val,
@@ -422,7 +454,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
buf[2] = 250;
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
buf, 3) != 3)
- return -ENODEV;
+ goto abituguru_detect_bank1_sensor_type_exit;
/* Now we need 20 ms to give the uguru time to read the sensors
and raise a voltage alarm */
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -430,21 +462,16 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
/* Check for alarm and check the alarm is a volt low alarm. */
if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
- return -ENODEV;
+ goto abituguru_detect_bank1_sensor_type_exit;
if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
sensor_addr, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
- return -ENODEV;
+ goto abituguru_detect_bank1_sensor_type_exit;
if (buf[0] & ABIT_UGURU_VOLT_LOW_ALARM_FLAG) {
- /* Restore original settings */
- if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
- sensor_addr,
- data->bank1_settings[sensor_addr],
- 3) != 3)
- return -ENODEV;
ABIT_UGURU_DEBUG(2, " found volt sensor\n");
- return ABIT_UGURU_IN_SENSOR;
+ ret = ABIT_UGURU_IN_SENSOR;
+ goto abituguru_detect_bank1_sensor_type_exit;
} else
ABIT_UGURU_DEBUG(2, " alarm raised during volt "
"sensor test, but volt low flag not set\n");
@@ -460,7 +487,7 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
buf[2] = 10;
if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
buf, 3) != 3)
- return -ENODEV;
+ goto abituguru_detect_bank1_sensor_type_exit;
/* Now we need 50 ms to give the uguru time to read the sensors
and raise a temp alarm */
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -468,15 +495,16 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
/* Check for alarm and check the alarm is a temp high alarm. */
if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
- return -ENODEV;
+ goto abituguru_detect_bank1_sensor_type_exit;
if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) {
if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1,
sensor_addr, buf, 3,
ABIT_UGURU_MAX_RETRIES) != 3)
- return -ENODEV;
+ goto abituguru_detect_bank1_sensor_type_exit;
if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) {
- ret = ABIT_UGURU_TEMP_SENSOR;
ABIT_UGURU_DEBUG(2, " found temp sensor\n");
+ ret = ABIT_UGURU_TEMP_SENSOR;
+ goto abituguru_detect_bank1_sensor_type_exit;
} else
ABIT_UGURU_DEBUG(2, " alarm raised during temp "
"sensor test, but temp high flag not set\n");
@@ -484,11 +512,23 @@ abituguru_detect_bank1_sensor_type(struct abituguru_data *data,
ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor "
"test\n");
- /* Restore original settings */
- if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr,
- data->bank1_settings[sensor_addr], 3) != 3)
+ ret = ABIT_UGURU_NC;
+abituguru_detect_bank1_sensor_type_exit:
+ /* Restore original settings, failing here is really BAD, it has been
+ reported that some BIOS-es hang when entering the uGuru menu with
+ invalid settings present in the uGuru, so we try this 3 times. */
+ for (i = 0; i < 3; i++)
+ if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2,
+ sensor_addr, data->bank1_settings[sensor_addr],
+ 3) == 3)
+ break;
+ if (i == 3) {
+ printk(KERN_ERR ABIT_UGURU_NAME
+ ": Fatal error could not restore original settings. "
+ "This should never happen please report this to the "
+ "abituguru maintainer (see MAINTAINERS)\n");
return -ENODEV;
-
+ }
return ret;
}
@@ -514,7 +554,7 @@ abituguru_detect_no_bank2_sensors(struct abituguru_data *data)
{
int i;
- if (fan_sensors) {
+ if (fan_sensors > 0 && fan_sensors <= ABIT_UGURU_MAX_BANK2_SENSORS) {
data->bank2_sensors = fan_sensors;
ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of "
"\"fan_sensors\" module param\n",
@@ -568,7 +608,7 @@ abituguru_detect_no_pwms(struct abituguru_data *data)
{
int i, j;
- if (pwms) {
+ if (pwms > 0 && pwms <= ABIT_UGURU_MAX_PWMS) {
data->pwms = pwms;
ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of "
"\"pwms\" module param\n", (int)data->pwms);
@@ -1288,7 +1328,7 @@ static struct abituguru_data *abituguru_update_device(struct device *dev)
data->update_timeouts = 0;
LEAVE_UPDATE:
/* handle timeout condition */
- if (err == -EBUSY) {
+ if (!success && (err == -EBUSY || err >= 0)) {
/* No overflow please */
if (data->update_timeouts < 255u)
data->update_timeouts++;
@@ -1314,13 +1354,39 @@ LEAVE_UPDATE:
return NULL;
}
+#ifdef CONFIG_PM
+static int abituguru_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct abituguru_data *data = platform_get_drvdata(pdev);
+ /* make sure all communications with the uguru are done and no new
+ ones are started */
+ mutex_lock(&data->update_lock);
+ return 0;
+}
+
+static int abituguru_resume(struct platform_device *pdev)
+{
+ struct abituguru_data *data = platform_get_drvdata(pdev);
+ /* See if the uGuru is still ready */
+ if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT)
+ data->uguru_ready = 0;
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+#else
+#define abituguru_suspend NULL
+#define abituguru_resume NULL
+#endif /* CONFIG_PM */
+
static struct platform_driver abituguru_driver = {
.driver = {
.owner = THIS_MODULE,
.name = ABIT_UGURU_NAME,
},
- .probe = abituguru_probe,
- .remove = __devexit_p(abituguru_remove),
+ .probe = abituguru_probe,
+ .remove = __devexit_p(abituguru_remove),
+ .suspend = abituguru_suspend,
+ .resume = abituguru_resume,
};
static int __init abituguru_detect(void)
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index 2b6e74dd4a8..c466329b2ef 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -190,6 +190,21 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1021_detect);
}
+static struct attribute *adm1021_attributes[] = {
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group adm1021_group = {
+ .attrs = adm1021_attributes,
+};
+
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
@@ -287,22 +302,19 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
adm1021_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
+ goto error2;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error2;
+ goto error3;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+error3:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
error2:
i2c_detach_client(new_client);
error1:
@@ -326,6 +338,7 @@ static int adm1021_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1021_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index a4c859c9fbf..8c562885b54 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -315,6 +315,49 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1025_detect);
}
+static struct attribute *adm1025_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ NULL
+};
+
+static const struct attribute_group adm1025_group = {
+ .attrs = adm1025_attributes,
+};
+
+static struct attribute *adm1025_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ NULL
+};
+
+static const struct attribute_group adm1025_group_opt = {
+ .attrs = adm1025_attributes_opt,
+};
+
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
@@ -415,46 +458,31 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
adm1025_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group)))
goto exit_detach;
- }
-
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_vrm);
/* Pin 11 is either in4 (+12V) or VID4 */
if (!(config & 0x20)) {
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
}
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1025_group);
+ sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -511,6 +539,8 @@ static int adm1025_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 6d4f8b8d358..b4618b2705f 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -323,15 +323,6 @@ static int adm1026_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1026_detect);
}
-static int adm1026_detach_client(struct i2c_client *client)
-{
- struct adm1026_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
- i2c_detach_client(client);
- kfree(data);
- return 0;
-}
-
static int adm1026_read_value(struct i2c_client *client, u8 reg)
{
int res;
@@ -1450,6 +1441,135 @@ static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+static struct attribute *adm1026_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in10_max.dev_attr.attr,
+ &sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ &sensor_dev_attr_in11_max.dev_attr.attr,
+ &sensor_dev_attr_in11_min.dev_attr.attr,
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_in12_max.dev_attr.attr,
+ &sensor_dev_attr_in12_min.dev_attr.attr,
+ &sensor_dev_attr_in13_input.dev_attr.attr,
+ &sensor_dev_attr_in13_max.dev_attr.attr,
+ &sensor_dev_attr_in13_min.dev_attr.attr,
+ &sensor_dev_attr_in14_input.dev_attr.attr,
+ &sensor_dev_attr_in14_max.dev_attr.attr,
+ &sensor_dev_attr_in14_min.dev_attr.attr,
+ &sensor_dev_attr_in15_input.dev_attr.attr,
+ &sensor_dev_attr_in15_max.dev_attr.attr,
+ &sensor_dev_attr_in15_min.dev_attr.attr,
+ &sensor_dev_attr_in16_input.dev_attr.attr,
+ &sensor_dev_attr_in16_max.dev_attr.attr,
+ &sensor_dev_attr_in16_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_div.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_div.dev_attr.attr,
+ &sensor_dev_attr_fan5_min.dev_attr.attr,
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_div.dev_attr.attr,
+ &sensor_dev_attr_fan6_min.dev_attr.attr,
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_div.dev_attr.attr,
+ &sensor_dev_attr_fan7_min.dev_attr.attr,
+ &sensor_dev_attr_fan8_input.dev_attr.attr,
+ &sensor_dev_attr_fan8_div.dev_attr.attr,
+ &sensor_dev_attr_fan8_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_offset.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &dev_attr_temp1_crit_enable.attr,
+ &dev_attr_temp2_crit_enable.attr,
+ &dev_attr_temp3_crit_enable.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_alarm_mask.attr,
+ &dev_attr_gpio.attr,
+ &dev_attr_gpio_mask.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm3.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3_enable.attr,
+ &dev_attr_temp1_auto_point1_pwm.attr,
+ &dev_attr_temp2_auto_point1_pwm.attr,
+ &dev_attr_temp3_auto_point1_pwm.attr,
+ &dev_attr_temp1_auto_point2_pwm.attr,
+ &dev_attr_temp2_auto_point2_pwm.attr,
+ &dev_attr_temp3_auto_point2_pwm.attr,
+ &dev_attr_analog_out.attr,
+ NULL
+};
+
+static const struct attribute_group adm1026_group = {
+ .attrs = adm1026_attributes,
+};
+
static int adm1026_detect(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -1554,145 +1674,20 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
adm1026_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
+ goto exitdetach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exitdetach;
+ goto exitremove;
}
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_auto_point1_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_auto_point1_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_auto_point1_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_auto_point2_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_auto_point2_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_auto_point2_temp.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_vrm);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_alarm_mask);
- device_create_file(&new_client->dev, &dev_attr_gpio);
- device_create_file(&new_client->dev, &dev_attr_gpio_mask);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm3);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm);
- device_create_file(&new_client->dev, &dev_attr_analog_out);
return 0;
/* Error out and cleanup code */
+exitremove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1026_group);
exitdetach:
i2c_detach_client(new_client);
exitfree:
@@ -1700,6 +1695,17 @@ exitfree:
exit:
return err;
}
+
+static int adm1026_detach_client(struct i2c_client *client)
+{
+ struct adm1026_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+}
+
static int __init sm_adm1026_init(void)
{
return i2c_add_driver(&adm1026_driver);
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 3bf2da621ae..122683fc91d 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -730,6 +730,61 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1031_detect);
}
+static struct attribute *adm1031_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_auto_fan1_channel.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_crit.attr,
+
+ &dev_attr_auto_temp1_off.attr,
+ &dev_attr_auto_temp1_min.attr,
+ &dev_attr_auto_temp1_max.attr,
+
+ &dev_attr_auto_temp2_off.attr,
+ &dev_attr_auto_temp2_min.attr,
+ &dev_attr_auto_temp2_max.attr,
+
+ &dev_attr_auto_fan1_min_pwm.attr,
+
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group adm1031_group = {
+ .attrs = adm1031_attributes,
+};
+
+static struct attribute *adm1031_attributes_opt[] = {
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_auto_fan2_channel.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_min.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_crit.attr,
+ &dev_attr_auto_temp3_off.attr,
+ &dev_attr_auto_temp3_min.attr,
+ &dev_attr_auto_temp3_max.attr,
+ &dev_attr_auto_fan2_min_pwm.attr,
+ NULL
+};
+
+static const struct attribute_group adm1031_group_opt = {
+ .attrs = adm1031_attributes_opt,
+};
+
/* This function is called by i2c_probe */
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -789,57 +844,26 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
adm1031_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group)))
goto exit_detach;
- }
-
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
-
- device_create_file(&new_client->dev, &dev_attr_auto_temp1_off);
- device_create_file(&new_client->dev, &dev_attr_auto_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_auto_temp1_max);
-
- device_create_file(&new_client->dev, &dev_attr_auto_temp2_off);
- device_create_file(&new_client->dev, &dev_attr_auto_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_auto_temp2_max);
-
- device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm);
-
- device_create_file(&new_client->dev, &dev_attr_alarms);
if (kind == adm1031) {
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev,
- &dev_attr_auto_fan2_channel);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
- device_create_file(&new_client->dev, &dev_attr_auto_temp3_off);
- device_create_file(&new_client->dev, &dev_attr_auto_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_auto_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm);
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &adm1031_group_opt)))
+ goto exit_remove;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
}
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1031_group);
+ sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -854,6 +878,8 @@ static int adm1031_detach_client(struct i2c_client *client)
int ret;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1031_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
if ((ret = i2c_detach_client(client)) != 0) {
return ret;
}
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 43f6991b588..377961c4a41 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -465,6 +465,45 @@ static ssize_t chassis_clear(struct device *dev,
}
static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
+static struct attribute *adm9240_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &dev_attr_temp1_input.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_aout_output.attr,
+ &dev_attr_chassis_clear.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group adm9240_group = {
+ .attrs = adm9240_attributes,
+};
+
/*** sensor chip detect and driver install ***/
@@ -548,72 +587,19 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
adm9240_init_client(new_client);
/* populate sysfs filesystem */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan2_div.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_aout_output);
- device_create_file(&new_client->dev, &dev_attr_chassis_clear);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -635,6 +621,7 @@ static int adm9240_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm9240_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 65b2709f750..57b1c7b7ac3 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -298,12 +298,6 @@ sysfs_in(4);
sysfs_in(5);
sysfs_in(6);
-#define device_create_file_in(client, offset) do { \
- device_create_file(&client->dev, &dev_attr_in##offset##_input); \
- device_create_file(&client->dev, &dev_attr_in##offset##_min); \
- device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
/* 3 Fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr)
{
@@ -341,7 +335,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
@@ -421,12 +415,6 @@ sysfs_fan(1);
sysfs_fan(2);
sysfs_fan(3);
-#define device_create_file_fan(client, offset) do { \
- device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
/* 4 Temp. Sensors */
static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
{
@@ -515,12 +503,6 @@ sysfs_temp(3);
sysfs_temp(4);
/* VID */
-#define device_create_file_temp(client, num) do { \
- device_create_file(&client->dev, &dev_attr_temp##num##_input); \
- device_create_file(&client->dev, &dev_attr_temp##num##_max); \
- device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \
-} while (0)
-
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
@@ -528,8 +510,6 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
/* VRM */
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
@@ -549,8 +529,6 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const
/* Alarms */
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm);
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -559,8 +537,6 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms)
/* 1 PWM */
static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
@@ -607,10 +583,65 @@ static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable1, set_pwm_enable1);
-#define device_create_file_pwm1(client) do { \
- device_create_file(&new_client->dev, &dev_attr_pwm1); \
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \
-} while (0)
+
+static struct attribute *asb100_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_max_hyst.attr,
+ &dev_attr_temp4_input.attr,
+ &dev_attr_temp4_max.attr,
+ &dev_attr_temp4_max_hyst.attr,
+
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+
+ NULL
+};
+
+static const struct attribute_group asb100_group = {
+ .attrs = asb100_attributes,
+};
/* This function is called when:
asb100_driver is inserted (when this module is loaded), for each
@@ -810,38 +841,19 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
+ goto ERROR3;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto ERROR3;
+ goto ERROR4;
}
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- device_create_file_temp(new_client, 3);
- device_create_file_temp(new_client, 4);
-
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
-
- device_create_file_alarms(new_client);
-
- device_create_file_pwm1(new_client);
-
return 0;
+ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &asb100_group);
ERROR3:
i2c_detach_client(data->lm75[1]);
i2c_detach_client(data->lm75[0]);
@@ -861,8 +873,10 @@ static int asb100_detach_client(struct i2c_client *client)
int err;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &asb100_group);
+ }
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 728a1e8b919..0ccdd0750c4 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -27,6 +27,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
@@ -116,8 +117,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
{
struct atxp1_data *data;
struct i2c_client *client;
- char vid;
- char cvid;
+ int vid, cvid;
unsigned int vcore;
client = to_i2c_client(dev);
@@ -251,6 +251,17 @@ static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *att
*/
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
+static struct attribute *atxp1_attributes[] = {
+ &dev_attr_gpio1.attr,
+ &dev_attr_gpio2.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group atxp1_group = {
+ .attrs = atxp1_attributes,
+};
+
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
{
@@ -320,21 +331,23 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_free;
}
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_gpio1);
- device_create_file(&new_client->dev, &dev_attr_gpio2);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-
dev_info(&new_client->dev, "Using VRM: %d.%d\n",
data->vrm / 10, data->vrm % 10);
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -349,6 +362,7 @@ static int atxp1_detach_client(struct i2c_client * client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &atxp1_group);
err = i2c_detach_client(client);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 478eb4bb857..c849c0c6ee9 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -29,6 +29,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include "lm75.h"
/* Addresses to scan */
@@ -178,6 +179,18 @@ static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static struct attribute *ds1621_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group ds1621_group = {
+ .attrs = ds1621_attributes,
+};
+
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
{
@@ -253,21 +266,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
ds1621_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
-
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
+ exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -282,6 +293,7 @@ static int ds1621_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &ds1621_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index fd72440faf7..de17a72149d 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1,7 +1,7 @@
/*
* f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated
* hardware monitoring features
- * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
*
* The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
* complete hardware monitoring features: voltage, fan and temperature
@@ -31,6 +31,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
static struct platform_device *pdev;
@@ -147,7 +148,7 @@ struct f71805f_data {
u8 temp_high[3];
u8 temp_hyst[3];
u8 temp_mode;
- u8 alarms[3];
+ unsigned long alarms;
};
static inline long in_from_reg(u8 reg)
@@ -311,10 +312,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
data->temp[nr] = f71805f_read8(data,
F71805F_REG_TEMP(nr));
}
- for (nr = 0; nr < 3; nr++) {
- data->alarms[nr] = f71805f_read8(data,
- F71805F_REG_STATUS(nr));
- }
+ data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0))
+ + (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8)
+ + (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16);
data->last_updated = jiffies;
data->valid = 1;
@@ -557,8 +557,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%d\n", data->alarms[0] |
- ((data->alarms[1] & 0x01) << 8));
+ return sprintf(buf, "%lu\n", data->alarms & 0x1ff);
}
static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
@@ -566,7 +565,7 @@ static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%d\n", data->alarms[2] & 0x07);
+ return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07);
}
static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
@@ -574,7 +573,17 @@ static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07);
+ return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71805f_data *data = f71805f_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1);
}
static ssize_t show_name(struct device *dev, struct device_attribute
@@ -585,88 +594,189 @@ static ssize_t show_name(struct device *dev, struct device_attribute
return sprintf(buf, "%s\n", data->name);
}
-static struct device_attribute f71805f_dev_attr[] = {
- __ATTR(in0_input, S_IRUGO, show_in0, NULL),
- __ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max),
- __ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min),
- __ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL),
- __ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL),
- __ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL),
- __ATTR(name, S_IRUGO, show_name, NULL),
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL);
+static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max);
+static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 4);
+static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 5);
+static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in6_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 6);
+static SENSOR_DEVICE_ATTR(in6_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in7_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 7);
+static SENSOR_DEVICE_ATTR(in7_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 8);
+static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 8);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+ show_fan_min, set_fan_min, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+ show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp_hyst, set_temp_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+ show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp_hyst, set_temp_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+ show_temp_max, set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp_hyst, set_temp_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL);
+static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL);
+static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *f71805f_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in0_min.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_type.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
+
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
+ &dev_attr_alarms_in.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &dev_attr_alarms_temp.attr,
+ &dev_attr_alarms_fan.attr,
+
+ &dev_attr_name.attr,
+ NULL
};
-static struct sensor_device_attribute f71805f_sensor_attr[] = {
- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
- SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 1),
- SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 1),
- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
- SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 2),
- SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 2),
- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
- SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 3),
- SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 3),
- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
- SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 4),
- SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 4),
- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
- SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 5),
- SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 5),
- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
- SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 6),
- SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 6),
- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
- SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 7),
- SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 7),
- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
- SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 8),
- SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 8),
-
- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
- SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
- show_temp_max, set_temp_max, 0),
- SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
- show_temp_hyst, set_temp_hyst, 0),
- SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
- SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
- show_temp_max, set_temp_max, 1),
- SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
- show_temp_hyst, set_temp_hyst, 1),
- SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
- SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
- SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
- show_temp_max, set_temp_max, 2),
- SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
- show_temp_hyst, set_temp_hyst, 2),
- SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+static const struct attribute_group f71805f_group = {
+ .attrs = f71805f_attributes,
};
-static struct sensor_device_attribute f71805f_fan_attr[] = {
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
- SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR,
- show_fan_min, set_fan_min, 0),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR,
- show_fan_min, set_fan_min, 1),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR,
- show_fan_min, set_fan_min, 2),
+static struct attribute *f71805f_attributes_fan[3][4] = {
+ {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group f71805f_group_fan[3] = {
+ { .attrs = f71805f_attributes_fan[0] },
+ { .attrs = f71805f_attributes_fan[1] },
+ { .attrs = f71805f_attributes_fan[2] },
};
/*
@@ -714,43 +824,35 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
- goto exit_free;
- }
-
/* Initialize the F71805F chip */
f71805f_init_device(data);
/* Register sysfs interface files */
- for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) {
- err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]);
- if (err)
- goto exit_class;
- }
- for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) {
- err = device_create_file(&pdev->dev,
- &f71805f_sensor_attr[i].dev_attr);
- if (err)
- goto exit_class;
- }
- for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) {
- if (!(data->fan_enabled & (1 << (i / 2))))
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
+ goto exit_free;
+ for (i = 0; i < 3; i++) {
+ if (!(data->fan_enabled & (1 << i)))
continue;
- err = device_create_file(&pdev->dev,
- &f71805f_fan_attr[i].dev_attr);
- if (err)
- goto exit_class;
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &f71805f_group_fan[i])))
+ goto exit_remove_files;
+ }
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+ goto exit_remove_files;
}
return 0;
-exit_class:
- dev_err(&pdev->dev, "Sysfs interface creation failed\n");
- hwmon_device_unregister(data->class_dev);
+exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
+ for (i = 0; i < 3; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
exit_free:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
exit:
return err;
@@ -759,9 +861,13 @@ exit:
static int __devexit f71805f_remove(struct platform_device *pdev)
{
struct f71805f_data *data = platform_get_drvdata(pdev);
+ int i;
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
+ for (i = 0; i < 3; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
kfree(data);
return 0;
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index 6bc76b40763..19717752cfc 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -34,6 +34,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -240,47 +241,45 @@ sysfs_alarms(FSCHER_REG_EVENTS)
sysfs_control(FSCHER_REG_CONTROL)
sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET)
-#define device_create_file_fan(client, offset) \
-do { \
- device_create_file(&client->dev, &dev_attr_fan##offset##_status); \
- device_create_file(&client->dev, &dev_attr_pwm##offset); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-} while (0)
-
-#define device_create_file_temp(client, offset) \
-do { \
- device_create_file(&client->dev, &dev_attr_temp##offset##_status); \
- device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-} while (0)
-
-#define device_create_file_in(client, offset) \
-do { \
- device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-} while (0)
-
-#define device_create_file_revision(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_revision); \
-} while (0)
-
-#define device_create_file_alarms(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_alarms); \
-} while (0)
-
-#define device_create_file_control(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_control); \
-} while (0)
-
-#define device_create_file_watchdog(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_watchdog_status); \
- device_create_file(&client->dev, &dev_attr_watchdog_control); \
- device_create_file(&client->dev, &dev_attr_watchdog_preset); \
-} while (0)
-
+static struct attribute *fscher_attributes[] = {
+ &dev_attr_revision.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_control.attr,
+
+ &dev_attr_watchdog_status.attr,
+ &dev_attr_watchdog_control.attr,
+ &dev_attr_watchdog_preset.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+
+ &dev_attr_fan1_status.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_fan2_status.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_fan3_status.attr,
+ &dev_attr_fan3_div.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_pwm3.attr,
+
+ &dev_attr_temp1_status.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_status.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_status.attr,
+ &dev_attr_temp3_input.attr,
+ NULL
+};
+
+static const struct attribute_group fscher_group = {
+ .attrs = fscher_attributes,
+};
+
/*
* Real code
*/
@@ -342,31 +341,19 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
fscher_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file_revision(new_client);
- device_create_file_alarms(new_client);
- device_create_file_control(new_client);
- device_create_file_watchdog(new_client);
-
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- device_create_file_temp(new_client, 3);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -381,6 +368,7 @@ static int fscher_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &fscher_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 6dc4846b9ee..ea506a77f9c 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -38,6 +38,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -432,6 +433,44 @@ static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL);
static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
+static struct attribute *fscpos_attributes[] = {
+ &dev_attr_event.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+
+ &dev_attr_wdog_control.attr,
+ &dev_attr_wdog_preset.attr,
+ &dev_attr_wdog_state.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_status.attr,
+ &dev_attr_temp1_reset.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_status.attr,
+ &dev_attr_temp2_reset.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_status.attr,
+ &dev_attr_temp3_reset.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_status.attr,
+ &dev_attr_fan1_ripple.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_status.attr,
+ &dev_attr_fan2_ripple.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_status.attr,
+ &dev_attr_fan3_ripple.attr,
+ NULL
+};
+
+static const struct attribute_group fscpos_group = {
+ .attrs = fscpos_attributes,
+};
+
static int fscpos_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
@@ -497,42 +536,19 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_event);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_wdog_control);
- device_create_file(&new_client->dev, &dev_attr_wdog_preset);
- device_create_file(&new_client->dev, &dev_attr_wdog_state);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_status);
- device_create_file(&new_client->dev, &dev_attr_temp1_reset);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_status);
- device_create_file(&new_client->dev, &dev_attr_temp2_reset);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_status);
- device_create_file(&new_client->dev, &dev_attr_temp3_reset);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_status);
- device_create_file(&new_client->dev, &dev_attr_fan1_ripple);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_status);
- device_create_file(&new_client->dev, &dev_attr_fan2_ripple);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_status);
- device_create_file(&new_client->dev, &dev_attr_fan3_ripple);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -547,6 +563,7 @@ static int fscpos_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &fscpos_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 6606aabdb49..c103640455a 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -44,6 +44,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -340,6 +341,42 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO,
static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO,
show_beep_mask, set_beep_mask);
+static struct attribute *gl518_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_auto.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+ NULL
+};
+
+static const struct attribute_group gl518_group = {
+ .attrs = gl518_attributes,
+};
+
/*
* Real code
*/
@@ -420,43 +457,19 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
gl518_init_client((struct i2c_client *) new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_fan1_auto);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_beep_enable);
- device_create_file(&new_client->dev, &dev_attr_beep_mask);
-
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
-
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &gl518_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -490,6 +503,7 @@ static int gl518_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &gl518_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 14e810f3c2c..ebe7b9aaa91 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -30,6 +30,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Type of the extra sensor */
static unsigned short extra_sensor_type;
@@ -190,55 +191,29 @@ static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL);
#define sysfs_vid(n) \
sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
-#define device_create_file_vid(client, n) \
-device_create_file(&client->dev, &dev_attr_cpu##n##_vid)
-
#define sysfs_in(n) \
sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
-#define device_create_file_in(client, n) \
-({device_create_file(&client->dev, &dev_attr_in##n##_input); \
-device_create_file(&client->dev, &dev_attr_in##n##_min); \
-device_create_file(&client->dev, &dev_attr_in##n##_max);})
-
#define sysfs_fan(n) \
sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
-#define device_create_file_fan(client, n) \
-({device_create_file(&client->dev, &dev_attr_fan##n##_input); \
-device_create_file(&client->dev, &dev_attr_fan##n##_min); \
-device_create_file(&client->dev, &dev_attr_fan##n##_div);})
-
#define sysfs_fan_off(n) \
sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
-#define device_create_file_fan_off(client, n) \
-device_create_file(&client->dev, &dev_attr_fan##n##_off)
-
#define sysfs_temp(n) \
sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
-#define device_create_file_temp(client, n) \
-({device_create_file(&client->dev, &dev_attr_temp##n##_input); \
-device_create_file(&client->dev, &dev_attr_temp##n##_max); \
-device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);})
-
#define sysfs_alarms() \
sysfs_ro(alarms, , GL520_REG_ALARMS) \
sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
-#define device_create_file_alarms(client) \
-({device_create_file(&client->dev, &dev_attr_alarms); \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask);})
-
sysfs_vid(0)
@@ -511,6 +486,59 @@ static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data,
return count;
}
+static struct attribute *gl520_attributes[] = {
+ &dev_attr_cpu0_vid.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_off.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+ NULL
+};
+
+static const struct attribute_group gl520_group = {
+ .attrs = gl520_attributes,
+};
+
+static struct attribute *gl520_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ NULL
+};
+
+static const struct attribute_group gl520_group_opt = {
+ .attrs = gl520_attributes_opt,
+};
+
/*
* Real code
@@ -572,33 +600,39 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
gl520_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group)))
goto exit_detach;
- }
-
- device_create_file_vid(new_client, 0);
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- if (!data->two_temps)
- device_create_file_in(new_client, 4);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan_off(new_client, 1);
+ if (data->two_temps) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_max_hyst)))
+ goto exit_remove_files;
+ } else {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove_files;
+ }
- device_create_file_temp(new_client, 1);
- if (data->two_temps)
- device_create_file_temp(new_client, 2);
- device_create_file_alarms(new_client);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -652,6 +686,8 @@ static int gl520_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 42b632889dd..8e7b5607f5a 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -587,7 +587,9 @@ static int __init hdaps_init(void)
input_set_abs_params(hdaps_idev, ABS_Y,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
- input_register_device(hdaps_idev);
+ ret = input_register_device(hdaps_idev);
+ if (ret)
+ goto out_idev;
/* start up our timer for the input device */
init_timer(&hdaps_timer);
@@ -598,6 +600,8 @@ static int __init hdaps_init(void)
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
return 0;
+out_idev:
+ input_free_device(hdaps_idev);
out_group:
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
out_device:
diff --git a/drivers/hwmon/hwmon-vid.c b/drivers/hwmon/hwmon-vid.c
index a6764ff0080..9d67320e684 100644
--- a/drivers/hwmon/hwmon-vid.c
+++ b/drivers/hwmon/hwmon-vid.c
@@ -22,7 +22,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hwmon-vid.h>
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 06df92b3ee4..323ef06719c 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -4,10 +4,12 @@
Supports: IT8705F Super I/O chip w/LPC interface
IT8712F Super I/O chip w/LPC interface & SMBus
+ IT8716F Super I/O chip w/LPC interface
+ IT8718F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com>
- Largely inspired by lm78.c of the same package
+ Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.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
@@ -24,13 +26,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/*
- djg@pdp8.net David Gesswein 7/18/01
- Modified to fix bug with not all alarms enabled.
- Added ability to read battery voltage and select temperature sensor
- type at module load time.
-*/
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -42,6 +37,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
@@ -50,12 +46,13 @@ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
static unsigned short isa_address;
/* Insmod parameters */
-I2C_CLIENT_INSMOD_2(it87, it8712);
+I2C_CLIENT_INSMOD_4(it87, it8712, it8716, it8718);
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
#define VAL 0x2f /* The value to read/write */
#define PME 0x04 /* The device with the fan registers in it */
+#define GPIO 0x07 /* The device with the IT8718F VID value in it */
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */
@@ -77,10 +74,10 @@ static int superio_inw(int reg)
}
static inline void
-superio_select(void)
+superio_select(int ldn)
{
outb(DEV, REG);
- outb(PME, VAL);
+ outb(ldn, VAL);
}
static inline void
@@ -99,20 +96,27 @@ superio_exit(void)
outb(0x02, VAL);
}
+/* Logical device 4 registers */
#define IT8712F_DEVID 0x8712
#define IT8705F_DEVID 0x8705
+#define IT8716F_DEVID 0x8716
+#define IT8718F_DEVID 0x8718
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
+/* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
+#define IT87_SIO_VID_REG 0xfc /* VID value */
+
/* Update battery voltage after every reading if true */
static int update_vbat;
/* Not all BIOSes properly configure the PWM registers */
static int fix_pwm_polarity;
-/* Chip Type */
-
+/* Values read from Super-I/O config space */
static u16 chip_type;
+static u8 vid_value;
/* Many IT87 constants specified below */
@@ -131,13 +135,21 @@ static u16 chip_type;
#define IT87_REG_ALARM2 0x02
#define IT87_REG_ALARM3 0x03
+/* The IT8718F has the VID value in a different register, in Super-I/O
+ configuration space. */
#define IT87_REG_VID 0x0a
+/* Warning: register 0x0b is used for something completely different in
+ new chips/revisions. I suspect only 16-bit tachometer mode will work
+ for these. */
#define IT87_REG_FAN_DIV 0x0b
+#define IT87_REG_FAN_16BIT 0x0c
/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
#define IT87_REG_FAN(nr) (0x0d + (nr))
#define IT87_REG_FAN_MIN(nr) (0x10 + (nr))
+#define IT87_REG_FANX(nr) (0x18 + (nr))
+#define IT87_REG_FANX_MIN(nr) (0x1b + (nr))
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr))
@@ -169,7 +181,16 @@ static inline u8 FAN_TO_REG(long rpm, int div)
254);
}
+static inline u16 FAN16_TO_REG(long rpm)
+{
+ if (rpm == 0)
+ return 0xffff;
+ return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+}
+
#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
+/* The divider is fixed to 2 in 16-bit mode */
+#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2))
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\
((val)+500)/1000),-128,127))
@@ -181,7 +202,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
static int DIV_TO_REG(int val)
{
int answer = 0;
- while ((val >>= 1) != 0)
+ while (answer < 7 && (val >>= 1))
answer++;
return answer;
}
@@ -203,10 +224,11 @@ struct it87_data {
unsigned long last_updated; /* In jiffies */
u8 in[9]; /* Register value */
- u8 in_max[9]; /* Register value */
- u8 in_min[9]; /* Register value */
- u8 fan[3]; /* Register value */
- u8 fan_min[3]; /* Register value */
+ u8 in_max[8]; /* Register value */
+ u8 in_min[8]; /* Register value */
+ u8 has_fan; /* Bitfield, fans enabled */
+ u16 fan[3]; /* Register values, possibly combined */
+ u16 fan_min[3]; /* Register values, possibly combined */
u8 temp[3]; /* Register value */
u8 temp_high[3]; /* Register value */
u8 temp_low[3]; /* Register value */
@@ -243,6 +265,7 @@ static struct i2c_driver it87_driver = {
static struct i2c_driver it87_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "it87-isa",
},
.attach_adapter = it87_isa_attach_adapter,
@@ -544,15 +567,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
- int val = simple_strtol(buf, NULL, 10);
- int i, min[3];
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int min;
u8 old;
mutex_lock(&data->update_lock);
old = it87_read_value(client, IT87_REG_FAN_DIV);
- for (i = 0; i < 3; i++)
- min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i]));
+ /* Save fan min limit */
+ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
switch (nr) {
case 0:
@@ -572,10 +595,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
val |= 0x1 << 6;
it87_write_value(client, IT87_REG_FAN_DIV, val);
- for (i = 0; i < 3; i++) {
- data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
- it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
- }
+ /* Restore fan min limit */
+ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+ it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+
mutex_unlock(&data->update_lock);
return count;
}
@@ -656,6 +679,59 @@ show_pwm_offset(1);
show_pwm_offset(2);
show_pwm_offset(3);
+/* A different set of callbacks for 16-bit fans */
+static ssize_t show_fan16(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct it87_data *data = it87_update_device(dev);
+ return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr]));
+}
+
+static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct it87_data *data = it87_update_device(dev);
+ return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr]));
+}
+
+static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct it87_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = FAN16_TO_REG(val);
+ it87_write_value(client, IT87_REG_FAN_MIN(nr),
+ data->fan_min[nr] & 0xff);
+ it87_write_value(client, IT87_REG_FANX_MIN(nr),
+ data->fan_min[nr] >> 8);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* We want to use the same sysfs file names as 8-bit fans, but we need
+ different variable names, so we have to use SENSOR_ATTR instead of
+ SENSOR_DEVICE_ATTR. */
+#define show_fan16_offset(offset) \
+static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
+ = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan16, NULL, offset - 1); \
+static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
+ = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan16_min, set_fan16_min, offset - 1)
+
+show_fan16_offset(1);
+show_fan16_offset(2);
+show_fan16_offset(3);
+
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -683,8 +759,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm)
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -693,8 +767,88 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
+
+static struct attribute *it87_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_type.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group it87_group = {
+ .attrs = it87_attributes,
+};
+
+static struct attribute *it87_attributes_opt[] = {
+ &sensor_dev_attr_fan1_input16.dev_attr.attr,
+ &sensor_dev_attr_fan1_min16.dev_attr.attr,
+ &sensor_dev_attr_fan2_input16.dev_attr.attr,
+ &sensor_dev_attr_fan2_min16.dev_attr.attr,
+ &sensor_dev_attr_fan3_input16.dev_attr.attr,
+ &sensor_dev_attr_fan3_min16.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group it87_group_opt = {
+ .attrs = it87_attributes_opt,
+};
/* This function is called when:
* it87_driver is inserted (when this module is loaded), for each
@@ -720,10 +874,12 @@ static int __init it87_find(unsigned short *address)
superio_enter();
chip_type = superio_inw(DEVID);
if (chip_type != IT8712F_DEVID
+ && chip_type != IT8716F_DEVID
+ && chip_type != IT8718F_DEVID
&& chip_type != IT8705F_DEVID)
goto exit;
- superio_select();
+ superio_select(PME);
if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
pr_info("it87: Device not activated, skipping\n");
goto exit;
@@ -739,6 +895,21 @@ static int __init it87_find(unsigned short *address)
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
chip_type, *address, superio_inb(DEVREV) & 0x0f);
+ /* Read GPIO config and VID value from LDN 7 (GPIO) */
+ if (chip_type != IT8705F_DEVID) {
+ int reg;
+
+ superio_select(GPIO);
+ if (chip_type == it8718)
+ vid_value = superio_inb(IT87_SIO_VID_REG);
+
+ reg = superio_inb(IT87_SIO_PINX2_REG);
+ if (reg & (1 << 0))
+ pr_info("it87: in3 is VCC (+5V)\n");
+ if (reg & (1 << 1))
+ pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
+ }
+
exit:
superio_exit();
return err;
@@ -799,8 +970,19 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
i = it87_read_value(new_client, IT87_REG_CHIPID);
if (i == 0x90) {
kind = it87;
- if ((is_isa) && (chip_type == IT8712F_DEVID))
- kind = it8712;
+ if (is_isa) {
+ switch (chip_type) {
+ case IT8712F_DEVID:
+ kind = it8712;
+ break;
+ case IT8716F_DEVID:
+ kind = it8716;
+ break;
+ case IT8718F_DEVID:
+ kind = it8718;
+ break;
+ }
+ }
}
else {
if (kind == 0)
@@ -817,6 +999,10 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
name = "it87";
} else if (kind == it8712) {
name = "it8712";
+ } else if (kind == it8716) {
+ name = "it8716";
+ } else if (kind == it8718) {
+ name = "it8718";
}
/* Fill in the remaining client fields and put it into the global list */
@@ -841,76 +1027,103 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
it87_init_client(new_client, data);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
goto ERROR3;
+
+ /* Do not create fan files for disabled fans */
+ if (data->type == it8716 || data->type == it8718) {
+ /* 16-bit tachometers */
+ if (data->has_fan & (1 << 0)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_input16.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_min16.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 1)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_input16.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_min16.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 2)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_input16.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_min16.dev_attr)))
+ goto ERROR4;
+ }
+ } else {
+ /* 8-bit tachometers with clock divider */
+ if (data->has_fan & (1 << 0)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_input.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_min.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_div.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 1)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_input.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_min.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_div.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 2)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_input.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_min.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_div.dev_attr)))
+ goto ERROR4;
+ }
}
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_alarms);
if (enable_pwm_interface) {
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm1_enable.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm2_enable.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm3_enable.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm1.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm2.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm3.dev_attr)))
+ goto ERROR4;
}
- if (data->type == it8712) {
+ if (data->type == it8712 || data->type == it8716
+ || data->type == it8718) {
data->vrm = vid_which_vrm();
- device_create_file_vrm(new_client);
- device_create_file_vid(new_client);
+ /* VID reading from Super-I/O config space if available */
+ data->vid = vid_value;
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_vrm))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid)))
+ goto ERROR4;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
}
return 0;
+ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &it87_group);
+ sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -928,6 +1141,8 @@ static int it87_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &it87_group);
+ sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
if ((err = i2c_detach_client(client)))
return err;
@@ -1044,6 +1259,22 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
data->manual_pwm_ctl[i] = 0xff;
}
+ /* Some chips seem to have default value 0xff for all limit
+ * registers. For low voltage limits it makes no sense and triggers
+ * alarms, so change to 0 instead. For high temperature limits, it
+ * means -1 degree C, which surprisingly doesn't trigger an alarm,
+ * but is still confusing, so change to 127 degrees C. */
+ for (i = 0; i < 8; i++) {
+ tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
+ if (tmp == 0xff)
+ it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
+ }
+ for (i = 0; i < 3; i++) {
+ tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+ if (tmp == 0xff)
+ it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
+ }
+
/* Check if temperature channnels are reset manually or by some reason */
tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
if ((tmp & 0x3f) == 0) {
@@ -1067,6 +1298,18 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
data->fan_main_ctrl |= 0x70;
it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
}
+ data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
+
+ /* Set tachometers to 16-bit mode if needed */
+ if (data->type == it8716 || data->type == it8718) {
+ tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
+ if (~tmp & 0x07 & data->has_fan) {
+ dev_dbg(&client->dev,
+ "Setting fan1-3 to 16-bit mode\n");
+ it87_write_value(client, IT87_REG_FAN_16BIT,
+ tmp | 0x07);
+ }
+ }
/* Set current fan mode registers and the default settings for the
* other mode registers */
@@ -1117,18 +1360,26 @@ static struct it87_data *it87_update_device(struct device *dev)
data->in_max[i] =
it87_read_value(client, IT87_REG_VIN_MAX(i));
}
+ /* in8 (battery) has no limit registers */
data->in[8] =
it87_read_value(client, IT87_REG_VIN(8));
- /* Temperature sensor doesn't have limit registers, set
- to min and max value */
- data->in_min[8] = 0;
- data->in_max[8] = 255;
for (i = 0; i < 3; i++) {
- data->fan[i] =
- it87_read_value(client, IT87_REG_FAN(i));
+ /* Skip disabled fans */
+ if (!(data->has_fan & (1 << i)))
+ continue;
+
data->fan_min[i] =
it87_read_value(client, IT87_REG_FAN_MIN(i));
+ data->fan[i] = it87_read_value(client,
+ IT87_REG_FAN(i));
+ /* Add high byte if in 16-bit mode */
+ if (data->type == it8716 || data->type == it8718) {
+ data->fan[i] |= it87_read_value(client,
+ IT87_REG_FANX(i)) << 8;
+ data->fan_min[i] |= it87_read_value(client,
+ IT87_REG_FANX_MIN(i)) << 8;
+ }
}
for (i = 0; i < 3; i++) {
data->temp[i] =
@@ -1139,10 +1390,14 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(client, IT87_REG_TEMP_LOW(i));
}
- i = it87_read_value(client, IT87_REG_FAN_DIV);
- data->fan_div[0] = i & 0x07;
- data->fan_div[1] = (i >> 3) & 0x07;
- data->fan_div[2] = (i & 0x40) ? 3 : 1;
+ /* Newer chips don't have clock dividers */
+ if ((data->has_fan & 0x07) && data->type != it8716
+ && data->type != it8718) {
+ i = it87_read_value(client, IT87_REG_FAN_DIV);
+ data->fan_div[0] = i & 0x07;
+ data->fan_div[1] = (i >> 3) & 0x07;
+ data->fan_div[2] = (i & 0x40) ? 3 : 1;
+ }
data->alarms =
it87_read_value(client, IT87_REG_ALARM1) |
@@ -1152,9 +1407,11 @@ static struct it87_data *it87_update_device(struct device *dev)
data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability */
- if (data->type == it8712) {
+ if (data->type == it8712 || data->type == it8716) {
data->vid = it87_read_value(client, IT87_REG_VID);
- data->vid &= 0x1f;
+ /* The older IT8712F revisions had only 5 VID pins,
+ but we assume it is always safe to read 6 bits. */
+ data->vid &= 0x3f;
}
data->last_updated = jiffies;
data->valid = 1;
@@ -1192,8 +1449,9 @@ static void __exit sm_it87_exit(void)
}
-MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>");
-MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
+MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
+ "Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
module_param(fix_pwm_polarity, bool, 0);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
new file mode 100644
index 00000000000..f58b64ed09e
--- /dev/null
+++ b/drivers/hwmon/k8temp.c
@@ -0,0 +1,294 @@
+/*
+ * k8temp.c - Linux kernel module for hardware monitoring
+ *
+ * Copyright (C) 2006 Rudolf Marek <r.marek@sh.cvut.cz>
+ *
+ * Inspired from the w83785 and amd756 drivers.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000)
+#define REG_TEMP 0xe4
+#define SEL_PLACE 0x40
+#define SEL_CORE 0x04
+
+struct k8temp_data {
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ const char *name;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* registers values */
+ u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
+ u32 temp[2][2]; /* core, place */
+};
+
+static struct k8temp_data *k8temp_update_device(struct device *dev)
+{
+ struct k8temp_data *data = dev_get_drvdata(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u8 tmp;
+
+ mutex_lock(&data->update_lock);
+
+ if (!data->valid
+ || time_after(jiffies, data->last_updated + HZ)) {
+ pci_read_config_byte(pdev, REG_TEMP, &tmp);
+ tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
+
+ if (data->sensorsp & SEL_PLACE) {
+ tmp |= SEL_PLACE; /* Select sensor 1, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP,
+ &data->temp[0][1]);
+ }
+
+ if (data->sensorsp & SEL_CORE) {
+ tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */
+ tmp |= SEL_CORE;
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP,
+ &data->temp[1][0]);
+
+ if (data->sensorsp & SEL_PLACE) {
+ tmp |= SEL_PLACE; /* Select sensor 1, core1 */
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP,
+ &data->temp[1][1]);
+ }
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct k8temp_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr =
+ to_sensor_dev_attr_2(devattr);
+ int core = attr->nr;
+ int place = attr->index;
+ struct k8temp_data *data = k8temp_update_device(dev);
+
+ return sprintf(buf, "%d\n",
+ TEMP_FROM_REG(data->temp[core][place]));
+}
+
+/* core, place */
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct pci_device_id k8temp_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, k8temp_ids);
+
+static int __devinit k8temp_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err;
+ u8 scfg;
+ u32 temp;
+ struct k8temp_data *data;
+ u32 cpuid = cpuid_eax(1);
+
+ /* this feature should be available since SH-C0 core */
+ if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pci_read_config_byte(pdev, REG_TEMP, &scfg);
+ scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+ pci_read_config_byte(pdev, REG_TEMP, &scfg);
+
+ if (scfg & (SEL_PLACE | SEL_CORE)) {
+ dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n");
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ scfg |= (SEL_PLACE | SEL_CORE);
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+
+ /* now we know if we can change core and/or sensor */
+ pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp);
+
+ if (data->sensorsp & SEL_PLACE) {
+ scfg &= ~SEL_CORE; /* Select sensor 1, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+ pci_read_config_dword(pdev, REG_TEMP, &temp);
+ scfg |= SEL_CORE; /* prepare for next selection */
+ if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
+ data->sensorsp &= ~SEL_PLACE;
+ }
+
+ if (data->sensorsp & SEL_CORE) {
+ scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+ pci_read_config_dword(pdev, REG_TEMP, &temp);
+ if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
+ data->sensorsp &= ~SEL_CORE;
+ }
+
+ data->name = "k8temp";
+ mutex_init(&data->update_lock);
+ dev_set_drvdata(&pdev->dev, data);
+
+ /* Register sysfs hooks */
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ /* sensor can be changed and reports something */
+ if (data->sensorsp & SEL_PLACE) {
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ /* core can be changed and reports something */
+ if (data->sensorsp & SEL_CORE) {
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ if (err)
+ goto exit_remove;
+ if (data->sensorsp & SEL_PLACE)
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp4_input.
+ dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ goto exit_remove;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp4_input.dev_attr);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+exit_free:
+ dev_set_drvdata(&pdev->dev, NULL);
+ kfree(data);
+exit:
+ return err;
+}
+
+static void __devexit k8temp_remove(struct pci_dev *pdev)
+{
+ struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
+
+ hwmon_device_unregister(data->class_dev);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp4_input.dev_attr);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ dev_set_drvdata(&pdev->dev, NULL);
+ kfree(data);
+}
+
+static struct pci_driver k8temp_driver = {
+ .name = "k8temp",
+ .id_table = k8temp_ids,
+ .probe = k8temp_probe,
+ .remove = __devexit_p(k8temp_remove),
+};
+
+static int __init k8temp_init(void)
+{
+ return pci_register_driver(&k8temp_driver);
+}
+
+static void __exit k8temp_exit(void)
+{
+ pci_unregister_driver(&k8temp_driver);
+}
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+MODULE_DESCRIPTION("AMD K8 core temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(k8temp_init)
+module_exit(k8temp_exit)
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 071f0fc6ade..d69f3cf0712 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -1,7 +1,7 @@
/*
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
* with integrated fan control
- * Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2006 Jean Delvare <khali@linux-fr.org>
* Based on the lm90 driver.
*
* The LM63 is a sensor chip made by National Semiconductor. It measures
@@ -46,6 +46,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -330,6 +331,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
return sprintf(buf, "%u\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
set_fan, 1);
@@ -350,8 +361,52 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
set_temp2_crit_hyst);
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *lm63_attributes[] = {
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &dev_attr_temp2_crit_hyst.attr,
+
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group lm63_group = {
+ .attrs = lm63_attributes,
+};
+
+static struct attribute *lm63_attributes_fan1[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm63_group_fan1 = {
+ .attrs = lm63_attributes_fan1,
+};
+
/*
* Real code
*/
@@ -438,37 +493,26 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
lm63_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm63_group)))
goto exit_detach;
+ if (data->config & 0x04) { /* tachometer enabled */
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm63_group_fan1)))
+ goto exit_remove_files;
}
- if (data->config & 0x04) { /* tachometer enabled */
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_min.dev_attr);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -518,6 +562,8 @@ static int lm63_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm63_group);
+ sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index fc25b90ec24..7c65b8bb6d7 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -112,6 +112,18 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm75_detect);
}
+static struct attribute *lm75_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm75_group = {
+ .attrs = lm75_attributes,
+};
+
/* This function is called by i2c_probe */
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -199,18 +211,19 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
lm75_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
-
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -223,6 +236,7 @@ static int lm75_detach_client(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm75_group);
i2c_detach_client(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 459cc977380..dd969f1e841 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -212,6 +212,23 @@ static int lm77_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm77_detect);
}
+static struct attribute *lm77_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_crit_hyst.attr,
+ &dev_attr_temp1_min_hyst.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm77_group = {
+ .attrs = lm77_attributes,
+};
+
/* This function is called by i2c_probe */
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -317,22 +334,19 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
lm77_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -345,6 +359,7 @@ static int lm77_detach_client(struct i2c_client *client)
{
struct lm77_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm77_group);
i2c_detach_client(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index 94be3d797e6..ac1b746df6d 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -175,6 +175,7 @@ static struct i2c_driver lm78_driver = {
static struct i2c_driver lm78_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "lm78-isa",
},
.attach_adapter = lm78_isa_attach_adapter,
@@ -358,7 +359,7 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
@@ -481,6 +482,50 @@ static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
return lm78_detect(adapter, isa_address, -1);
}
+static struct attribute *lm78_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_cpu0_vid.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm78_group = {
+ .attrs = lm78_attributes,
+};
+
/* This function is called by i2c_probe */
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -615,50 +660,19 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
+ goto ERROR3;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto ERROR3;
+ goto ERROR4;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_min);
- device_create_file(&new_client->dev, &dev_attr_fan3_div);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-
return 0;
+ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &lm78_group);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -676,6 +690,7 @@ static int lm78_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm78_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index f72120d08c4..064516d824a 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -253,7 +253,7 @@ set_fan(min2, fan_min[1], LM80_REG_FAN_MIN(2), fan_div[1]);
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
@@ -394,6 +394,48 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm80_detect);
}
+static struct attribute *lm80_attributes[] = {
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_max.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp1_crit_hyst.attr,
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm80_group = {
+ .attrs = lm80_attributes,
+};
+
static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i, cur;
@@ -452,48 +494,19 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
+ goto error_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error_detach;
+ goto error_remove;
}
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+error_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm80_group);
error_detach:
i2c_detach_client(new_client);
error_free:
@@ -508,7 +521,7 @@ static int lm80_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
-
+ sysfs_remove_group(&client->dev.kobj, &lm80_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 2137d7879df..feb87b41e98 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -1,7 +1,7 @@
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
*
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
* a sensor chip made by National Semiconductor. It reports up to four
@@ -40,6 +40,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -191,6 +192,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm83_data *data = lm83_update_device(dev);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
@@ -208,8 +219,64 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
set_temp, 8);
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
+/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *lm83_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group lm83_group = {
+ .attrs = lm83_attributes,
+};
+
+static struct attribute *lm83_attributes_opt[] = {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm83_group_opt = {
+ .attrs = lm83_attributes_opt,
+};
+
/*
* Real code
*/
@@ -318,59 +385,32 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_free;
/*
- * Initialize the LM83 chip
- * (Nothing to do for this one.)
- */
-
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto exit_detach;
- }
-
- /*
+ * Register sysfs hooks
* The LM82 can only monitor one external diode which is
* at the same register as the LM83 temp3 entry - so we
* declare 1 and 3 common, and then 2 and 4 only for the LM83.
*/
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_input.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_max.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_crit.dev_attr);
-
- device_create_file(&new_client->dev, &dev_attr_alarms);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
+ goto exit_detach;
if (kind == lm83) {
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_input.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_max.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_crit.dev_attr);
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm83_group_opt)))
+ goto exit_remove_files;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -385,6 +425,8 @@ static int lm83_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm83_group);
+ sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 342e9663119..2c3293cf69d 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -1025,6 +1025,89 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm85_detect);
}
+static struct attribute *lm85_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan4_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan4_min.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm3.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3_enable.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp3_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_pwm1_auto_channels.attr,
+ &dev_attr_pwm2_auto_channels.attr,
+ &dev_attr_pwm3_auto_channels.attr,
+ &dev_attr_pwm1_auto_pwm_min.attr,
+ &dev_attr_pwm2_auto_pwm_min.attr,
+ &dev_attr_pwm3_auto_pwm_min.attr,
+ &dev_attr_pwm1_auto_pwm_minctl.attr,
+ &dev_attr_pwm2_auto_pwm_minctl.attr,
+ &dev_attr_pwm3_auto_pwm_minctl.attr,
+ &dev_attr_pwm1_auto_pwm_freq.attr,
+ &dev_attr_pwm2_auto_pwm_freq.attr,
+ &dev_attr_pwm3_auto_pwm_freq.attr,
+ &dev_attr_temp1_auto_temp_off.attr,
+ &dev_attr_temp2_auto_temp_off.attr,
+ &dev_attr_temp3_auto_temp_off.attr,
+ &dev_attr_temp1_auto_temp_min.attr,
+ &dev_attr_temp2_auto_temp_min.attr,
+ &dev_attr_temp3_auto_temp_min.attr,
+ &dev_attr_temp1_auto_temp_max.attr,
+ &dev_attr_temp2_auto_temp_max.attr,
+ &dev_attr_temp3_auto_temp_max.attr,
+ &dev_attr_temp1_auto_temp_crit.attr,
+ &dev_attr_temp2_auto_temp_crit.attr,
+ &dev_attr_temp3_auto_temp_crit.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm85_group = {
+ .attrs = lm85_attributes,
+};
+
+static struct attribute *lm85_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm85_group_opt = {
+ .attrs = lm85_attributes_opt,
+};
+
static int lm85_detect(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -1163,87 +1246,33 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
lm85_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm85_group)))
goto ERROR2;
- }
-
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan4_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan3_min);
- device_create_file(&new_client->dev, &dev_attr_fan4_min);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm3);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_vrm);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit);
/* The ADT7463 has an optional VRM 10 mode where pin 21 is used
as a sixth digital VID input rather than an analog input. */
data->vid = lm85_read_value(new_client, LM85_REG_VID);
- if (!(kind == adt7463 && (data->vid & 0x80))) {
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
+ if (!(kind == adt7463 && (data->vid & 0x80)))
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto ERROR3;
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
}
return 0;
/* Error out and cleanup code */
+ ERROR3:
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
ERROR2:
i2c_detach_client(new_client);
ERROR1:
@@ -1256,6 +1285,8 @@ static int lm85_detach_client(struct i2c_client *client)
{
struct lm85_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
i2c_detach_client(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index e229daf666d..3ce825489e3 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -421,7 +421,7 @@ static void set_fan_min(struct device *dev, const char *buf, int nr)
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan clock divider. This follows the principle
- of least suprise; the user doesn't expect the fan minimum to change just
+ of least surprise; the user doesn't expect the fan minimum to change just
because the divider changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
@@ -542,6 +542,78 @@ static int lm87_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm87_detect);
}
+static struct attribute *lm87_attributes[] = {
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_crit.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_aout_output.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm87_group = {
+ .attrs = lm87_attributes,
+};
+
+static struct attribute *lm87_attributes_opt[] = {
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+
+ &dev_attr_in7_input.attr,
+ &dev_attr_in7_min.attr,
+ &dev_attr_in7_max.attr,
+
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_min.attr,
+ &dev_attr_temp3_crit.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm87_group_opt = {
+ .attrs = lm87_attributes_opt,
+};
+
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
@@ -609,77 +681,90 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
data->in_scale[7] = 1875;
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
goto exit_detach;
- }
-
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
if (data->channel & CHAN_NO_FAN(0)) {
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in6_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_max)))
+ goto exit_remove;
} else {
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_div)))
+ goto exit_remove;
}
+
if (data->channel & CHAN_NO_FAN(1)) {
- device_create_file(&new_client->dev, &dev_attr_in7_input);
- device_create_file(&new_client->dev, &dev_attr_in7_min);
- device_create_file(&new_client->dev, &dev_attr_in7_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in7_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in7_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in7_max)))
+ goto exit_remove;
} else {
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_div)))
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
-
if (data->channel & CHAN_TEMP3) {
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_crit)))
+ goto exit_remove;
} else {
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in0_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in0_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in0_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_max)))
+ goto exit_remove;
}
if (!(data->channel & CHAN_NO_VID)) {
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_vrm);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_vrm)))
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_aout_output);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -732,6 +817,8 @@ static int lm87_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm87_group);
+ sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index d9eeaf7585b..6882ce75fee 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1,7 +1,7 @@
/*
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
*
* Based on the lm83 driver. The LM90 is a sensor chip made by National
* Semiconductor. It reports up to two temperatures (its own plus up to
@@ -79,6 +79,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -327,6 +328,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm90_data *data = lm90_update_device(dev);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
@@ -344,8 +355,45 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
set_temphyst, 3);
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *lm90_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group lm90_group = {
+ .attrs = lm90_attributes,
+};
+
/* pec used for ADM1032 only */
static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
char *buf)
@@ -569,39 +617,25 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
lm90_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
+ goto exit_detach;
+ if (new_client->flags & I2C_CLIENT_PEC) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pec)))
+ goto exit_remove_files;
+ }
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_crit_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit_hyst.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
- if (new_client->flags & I2C_CLIENT_PEC)
- device_create_file(&new_client->dev, &dev_attr_pec);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
+ device_remove_file(&new_client->dev, &dev_attr_pec);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -634,6 +668,8 @@ static int lm90_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm90_group);
+ device_remove_file(&client->dev, &dev_attr_pec);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 197f77226dc..30b536333f1 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -288,6 +288,23 @@ static int max6635_check(struct i2c_client *client)
return 1;
}
+static struct attribute *lm92_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp1_crit_hyst.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_min_hyst.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm92_group = {
+ .attrs = lm92_attributes,
+};
+
/* The following function does more than just detection. If detection
succeeds, it also registers the new chip. */
static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -359,23 +376,19 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
lm92_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -397,6 +410,7 @@ static int lm92_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm92_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index b4135b5971f..2f58f651f03 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -34,6 +34,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
@@ -172,6 +173,22 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2,
set_temp_hyst2);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *max1619_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_crit.attr,
+ &dev_attr_temp2_crit_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group max1619_group = {
+ .attrs = max1619_attributes,
+};
+
/*
* Real code
*/
@@ -273,22 +290,19 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
max1619_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -318,6 +332,7 @@ static int max1619_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &max1619_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index ae05e483a77..3b8b81984ad 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -238,6 +238,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev);
static struct i2c_driver pc87360_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "pc87360",
},
.attach_adapter = pc87360_detect,
@@ -327,6 +328,12 @@ static struct sensor_device_attribute fan_min[] = {
SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
};
+#define FAN_UNIT_ATTRS(X) \
+ &fan_input[X].dev_attr.attr, \
+ &fan_status[X].dev_attr.attr, \
+ &fan_div[X].dev_attr.attr, \
+ &fan_min[X].dev_attr.attr
+
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -359,6 +366,19 @@ static struct sensor_device_attribute pwm[] = {
SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
};
+static struct attribute * pc8736x_fan_attr_array[] = {
+ FAN_UNIT_ATTRS(0),
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+ &pwm[0].dev_attr.attr,
+ &pwm[1].dev_attr.attr,
+ &pwm[2].dev_attr.attr,
+ NULL
+};
+static const struct attribute_group pc8736x_fan_group = {
+ .attrs = pc8736x_fan_attr_array,
+};
+
static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -471,6 +491,61 @@ static struct sensor_device_attribute in_max[] = {
SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
};
+#define VIN_UNIT_ATTRS(X) \
+ &in_input[X].dev_attr.attr, \
+ &in_status[X].dev_attr.attr, \
+ &in_min[X].dev_attr.attr, \
+ &in_max[X].dev_attr.attr
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ data->vrm = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->in_alarms);
+}
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+
+static struct attribute *pc8736x_vin_attr_array[] = {
+ VIN_UNIT_ATTRS(0),
+ VIN_UNIT_ATTRS(1),
+ VIN_UNIT_ATTRS(2),
+ VIN_UNIT_ATTRS(3),
+ VIN_UNIT_ATTRS(4),
+ VIN_UNIT_ATTRS(5),
+ VIN_UNIT_ATTRS(6),
+ VIN_UNIT_ATTRS(7),
+ VIN_UNIT_ATTRS(8),
+ VIN_UNIT_ATTRS(9),
+ VIN_UNIT_ATTRS(10),
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms_in.attr,
+ NULL
+};
+static const struct attribute_group pc8736x_vin_group = {
+ .attrs = pc8736x_vin_attr_array,
+};
+
static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -589,33 +664,22 @@ static struct sensor_device_attribute therm_crit[] = {
show_therm_crit, set_therm_crit, 2+11),
};
-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pc87360_data *data = pc87360_update_device(dev);
- return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
-}
-static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
-
-static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pc87360_data *data = pc87360_update_device(dev);
- return sprintf(buf, "%u\n", data->vrm);
-}
-static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
- data->vrm = simple_strtoul(buf, NULL, 10);
- return count;
-}
-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
-
-static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pc87360_data *data = pc87360_update_device(dev);
- return sprintf(buf, "%u\n", data->in_alarms);
-}
-static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+#define THERM_UNIT_ATTRS(X) \
+ &therm_input[X].dev_attr.attr, \
+ &therm_status[X].dev_attr.attr, \
+ &therm_min[X].dev_attr.attr, \
+ &therm_max[X].dev_attr.attr, \
+ &therm_crit[X].dev_attr.attr
+
+static struct attribute * pc8736x_therm_attr_array[] = {
+ THERM_UNIT_ATTRS(0),
+ THERM_UNIT_ATTRS(1),
+ THERM_UNIT_ATTRS(2),
+ NULL
+};
+static const struct attribute_group pc8736x_therm_group = {
+ .attrs = pc8736x_therm_attr_array,
+};
static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
@@ -735,6 +799,25 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att
}
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
+#define TEMP_UNIT_ATTRS(X) \
+ &temp_input[X].dev_attr.attr, \
+ &temp_status[X].dev_attr.attr, \
+ &temp_min[X].dev_attr.attr, \
+ &temp_max[X].dev_attr.attr, \
+ &temp_crit[X].dev_attr.attr
+
+static struct attribute * pc8736x_temp_attr_array[] = {
+ TEMP_UNIT_ATTRS(0),
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
+ /* include the few miscellaneous atts here */
+ &dev_attr_alarms_temp.attr,
+ NULL
+};
+static const struct attribute_group pc8736x_temp_group = {
+ .attrs = pc8736x_temp_attr_array,
+};
+
/*
* Device detection, registration and update
*/
@@ -935,60 +1018,69 @@ static int pc87360_detect(struct i2c_adapter *adapter)
pc87360_init_client(client, use_thermistors);
}
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* Register all-or-nothing sysfs groups */
+
+ if (data->innr &&
+ (err = sysfs_create_group(&client->dev.kobj,
+ &pc8736x_vin_group)))
goto ERROR3;
- }
- if (data->innr) {
- for (i = 0; i < 11; i++) {
- device_create_file(dev, &in_input[i].dev_attr);
- device_create_file(dev, &in_min[i].dev_attr);
- device_create_file(dev, &in_max[i].dev_attr);
- device_create_file(dev, &in_status[i].dev_attr);
- }
- device_create_file(dev, &dev_attr_cpu0_vid);
- device_create_file(dev, &dev_attr_vrm);
- device_create_file(dev, &dev_attr_alarms_in);
- }
+ if (data->innr == 14 &&
+ (err = sysfs_create_group(&client->dev.kobj,
+ &pc8736x_therm_group)))
+ goto ERROR3;
+
+ /* create device attr-files for varying sysfs groups */
if (data->tempnr) {
for (i = 0; i < data->tempnr; i++) {
- device_create_file(dev, &temp_input[i].dev_attr);
- device_create_file(dev, &temp_min[i].dev_attr);
- device_create_file(dev, &temp_max[i].dev_attr);
- device_create_file(dev, &temp_crit[i].dev_attr);
- device_create_file(dev, &temp_status[i].dev_attr);
- }
- device_create_file(dev, &dev_attr_alarms_temp);
- }
-
- if (data->innr == 14) {
- for (i = 0; i < 3; i++) {
- device_create_file(dev, &therm_input[i].dev_attr);
- device_create_file(dev, &therm_min[i].dev_attr);
- device_create_file(dev, &therm_max[i].dev_attr);
- device_create_file(dev, &therm_crit[i].dev_attr);
- device_create_file(dev, &therm_status[i].dev_attr);
+ if ((err = device_create_file(dev,
+ &temp_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_min[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_max[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_crit[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_status[i].dev_attr)))
+ goto ERROR3;
}
+ if ((err = device_create_file(dev, &dev_attr_alarms_temp)))
+ goto ERROR3;
}
for (i = 0; i < data->fannr; i++) {
- if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
- device_create_file(dev, &fan_input[i].dev_attr);
- device_create_file(dev, &fan_min[i].dev_attr);
- device_create_file(dev, &fan_div[i].dev_attr);
- device_create_file(dev, &fan_status[i].dev_attr);
- }
- if (FAN_CONFIG_CONTROL(data->fan_conf, i))
- device_create_file(dev, &pwm[i].dev_attr);
+ if (FAN_CONFIG_MONITOR(data->fan_conf, i)
+ && ((err = device_create_file(dev,
+ &fan_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &fan_min[i].dev_attr))
+ || (err = device_create_file(dev,
+ &fan_div[i].dev_attr))
+ || (err = device_create_file(dev,
+ &fan_status[i].dev_attr))))
+ goto ERROR3;
+
+ if (FAN_CONFIG_CONTROL(data->fan_conf, i)
+ && (err = device_create_file(dev, &pwm[i].dev_attr)))
+ goto ERROR3;
}
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
return 0;
ERROR3:
+ /* can still remove groups whose members were added individually */
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
+
i2c_detach_client(client);
ERROR2:
for (i = 0; i < 3; i++) {
@@ -1008,6 +1100,11 @@ static int pc87360_detach_client(struct i2c_client *client)
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
+
if ((i = i2c_detach_client(client)))
return i;
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 6f3fda73f70..95a4b5d9eaf 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -61,6 +61,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
@@ -200,6 +201,7 @@ static void sis5595_init_client(struct i2c_client *client);
static struct i2c_driver sis5595_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "sis5595",
},
.attach_adapter = sis5595_detect,
@@ -380,7 +382,7 @@ static ssize_t show_fan_div(struct device *dev, char *buf, int nr)
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
@@ -472,6 +474,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
return sprintf(buf, "%d\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *sis5595_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group sis5595_group = {
+ .attrs = sis5595_attributes,
+};
+
+static struct attribute *sis5595_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ NULL
+};
+
+static const struct attribute_group sis5595_group_opt = {
+ .attrs = sis5595_attributes_opt,
+};
/* This is called when the module is loaded */
static int sis5595_detect(struct i2c_adapter *adapter)
@@ -565,43 +611,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
}
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
+ goto exit_detach;
+ if (data->maxins == 4) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove_files;
+ } else {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp1_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp1_max_hyst)))
+ goto exit_remove_files;
+ }
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- if (data->maxins == 4) {
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- }
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- if (data->maxins == 3) {
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- }
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -618,6 +658,8 @@ static int sis5595_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index b6086186d22..72b0e2d8650 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -176,9 +176,6 @@ sysfs_temp(2);
sysfs_temp(3);
sysfs_temp(4);
-#define device_create_file_temp(client, num) \
- device_create_file(&client->dev, &dev_attr_temp##num##_input)
-
/* FAN: 1 RPM/bit
REG: count of 90kHz pulses / revolution */
static int fan_from_reg(u16 reg)
@@ -205,8 +202,22 @@ sysfs_fan(2);
sysfs_fan(3);
sysfs_fan(4);
-#define device_create_file_fan(client, num) \
- device_create_file(&client->dev, &dev_attr_fan##num##_input)
+static struct attribute *smsc47b397_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp4_input.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan4_input.attr,
+
+ NULL
+};
+
+static const struct attribute_group smsc47b397_group = {
+ .attrs = smsc47b397_attributes,
+};
static int smsc47b397_detach_client(struct i2c_client *client)
{
@@ -214,6 +225,7 @@ static int smsc47b397_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
if ((err = i2c_detach_client(client)))
return err;
@@ -228,6 +240,7 @@ static int smsc47b397_detect(struct i2c_adapter *adapter);
static struct i2c_driver smsc47b397_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "smsc47b397",
},
.attach_adapter = smsc47b397_detect,
@@ -267,24 +280,19 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
if ((err = i2c_attach_client(new_client)))
goto error_free;
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group)))
+ goto error_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error_detach;
+ goto error_remove;
}
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- device_create_file_temp(new_client, 3);
- device_create_file_temp(new_client, 4);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
- device_create_file_fan(new_client, 4);
-
return 0;
+error_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
error_detach:
i2c_detach_client(new_client);
error_free:
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 7732aec5459..47132fd26b1 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -35,6 +35,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
/* Address is autodetected, there is no default value */
@@ -128,6 +129,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
static struct i2c_driver smsc47m1_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "smsc47m1",
},
.attach_adapter = smsc47m1_detect,
@@ -207,7 +209,7 @@ static ssize_t set_fan_min(struct device *dev, const char *buf,
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan clock divider. This follows the principle
- of least suprise; the user doesn't expect the fan minimum to change just
+ of least surprise; the user doesn't expect the fan minimum to change just
because the divider changed. */
static ssize_t set_fan_div(struct device *dev, const char *buf,
size_t count, int nr)
@@ -346,6 +348,30 @@ fan_present(2);
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+/* Almost all sysfs files may or may not be created depending on the chip
+ setup so we create them individually. It is still convenient to define a
+ group to remove them all at once. */
+static struct attribute *smsc47m1_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm2_enable.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group smsc47m1_group = {
+ .attrs = smsc47m1_attributes,
+};
+
static int __init smsc47m1_find(unsigned short *addr)
{
u8 val;
@@ -428,7 +454,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
== 0x04;
if (!(fan1 || fan2 || pwm1 || pwm2)) {
- dev_warn(&new_client->dev, "Device is not configured, will not use\n");
+ dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
+ "will not use\n", new_client->addr);
err = -ENODEV;
goto error_free;
}
@@ -445,46 +472,62 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
smsc47m1_update_device(&new_client->dev, 1);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto error_detach;
- }
-
if (fan1) {
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_div)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
"skipping\n");
if (fan2) {
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_div)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
"skipping\n");
if (pwm1) {
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm1))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm1_enable)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
"skipping\n");
if (pwm2) {
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm2))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm2_enable)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
"skipping\n");
- device_create_file(&new_client->dev, &dev_attr_alarms);
+ if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
+ goto error_remove_files;
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_remove_files;
+ }
return 0;
-error_detach:
+error_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
i2c_detach_client(new_client);
error_free:
kfree(data);
@@ -499,6 +542,7 @@ static int smsc47m1_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index bdc4570acf9..a6833f43739 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -30,6 +30,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
+#include <linux/sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -370,6 +371,75 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
+static struct attribute *smsc47m192_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_offset.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ NULL
+};
+
+static const struct attribute_group smsc47m192_group = {
+ .attrs = smsc47m192_attributes,
+};
+
+static struct attribute *smsc47m192_attributes_in4[] = {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group smsc47m192_group_in4 = {
+ .attrs = smsc47m192_attributes_in4,
+};
+
/* This function is called when:
* smsc47m192_driver is inserted (when this module is loaded), for each
available adapter
@@ -471,80 +541,28 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
smsc47m192_init_client(client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
goto exit_detach;
- }
-
- device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
/* Pin 110 is either in4 (+12V) or VID4 */
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
if (!(config & 0x20)) {
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_alarm.dev_attr);
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &smsc47m192_group_in4)))
+ goto exit_remove_files;
+ }
+
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
- device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp1_offset.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp2_offset.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp2_input_fault.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp3_offset.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp3_input_fault.dev_attr);
- device_create_file(&client->dev, &dev_attr_cpu0_vid);
- device_create_file(&client->dev, &dev_attr_vrm);
return 0;
+exit_remove_files:
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
exit_detach:
i2c_detach_client(client);
exit_free:
@@ -559,6 +577,8 @@ static int smsc47m192_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 166298f1f19..f8acada0537 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -40,6 +40,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
@@ -570,10 +571,53 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *via686a_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp3_max_hyst.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group via686a_group = {
+ .attrs = via686a_attributes,
+};
+
/* The driver. I choose to use type i2c_driver, as at is identical to both
smbus_driver and isa_driver, and clients could be of either kind */
static struct i2c_driver via686a_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "via686a",
},
.attach_adapter = via686a_detect,
@@ -649,46 +693,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
via686a_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -704,6 +721,7 @@ static int via686a_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &via686a_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
new file mode 100644
index 00000000000..25cc56003d7
--- /dev/null
+++ b/drivers/hwmon/vt1211.c
@@ -0,0 +1,1355 @@
+/*
+ * vt1211.c - driver for the VIA VT1211 Super-I/O chip integrated hardware
+ * monitoring features
+ * Copyright (C) 2006 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the driver for kernel 2.4 by Mark D. Studebaker
+ * and its port to kernel 2.6 by Lars Ekman.
+ *
+ * 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/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+static int uch_config = -1;
+module_param(uch_config, int, 0);
+MODULE_PARM_DESC(uch_config, "Initialize the universal channel configuration");
+
+static int int_mode = -1;
+module_param(int_mode, int, 0);
+MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "vt1211"
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows.
+ *
+ * Sensor Voltage Mode Temp Mode Notes (from the datasheet)
+ * -------- ------------ --------- --------------------------
+ * Reading 1 temp1 Intel thermal diode
+ * Reading 3 temp2 Internal thermal diode
+ * UCH1/Reading2 in0 temp3 NTC type thermistor
+ * UCH2 in1 temp4 +2.5V
+ * UCH3 in2 temp5 VccP
+ * UCH4 in3 temp6 +5V
+ * UCH5 in4 temp7 +12V
+ * 3.3V in5 Internal VDD (+3.3V)
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-5 (ix) */
+#define VT1211_REG_IN(ix) (0x21 + (ix))
+#define VT1211_REG_IN_MIN(ix) ((ix) == 0 ? 0x3e : 0x2a + 2 * (ix))
+#define VT1211_REG_IN_MAX(ix) ((ix) == 0 ? 0x3d : 0x29 + 2 * (ix))
+
+/* Temperatures (temp) numbered 0-6 (ix) */
+static u8 regtemp[] = {0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
+static u8 regtempmax[] = {0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31};
+static u8 regtemphyst[] = {0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32};
+
+/* Fans numbered 0-1 (ix) */
+#define VT1211_REG_FAN(ix) (0x29 + (ix))
+#define VT1211_REG_FAN_MIN(ix) (0x3b + (ix))
+#define VT1211_REG_FAN_DIV 0x47
+
+/* PWMs numbered 0-1 (ix) */
+/* Auto points numbered 0-3 (ap) */
+#define VT1211_REG_PWM(ix) (0x60 + (ix))
+#define VT1211_REG_PWM_CLK 0x50
+#define VT1211_REG_PWM_CTL 0x51
+#define VT1211_REG_PWM_AUTO_TEMP(ap) (0x55 - (ap))
+#define VT1211_REG_PWM_AUTO_PWM(ix, ap) (0x58 + 2 * (ix) - (ap))
+
+/* Miscellaneous registers */
+#define VT1211_REG_CONFIG 0x40
+#define VT1211_REG_ALARM1 0x41
+#define VT1211_REG_ALARM2 0x42
+#define VT1211_REG_VID 0x45
+#define VT1211_REG_UCH_CONFIG 0x4a
+#define VT1211_REG_TEMP1_CONFIG 0x4b
+#define VT1211_REG_TEMP2_CONFIG 0x4c
+
+/* In, temp & fan alarm bits */
+static const u8 bitalarmin[] = {11, 0, 1, 3, 8, 2, 9};
+static const u8 bitalarmtemp[] = {4, 15, 11, 0, 1, 3, 8};
+static const u8 bitalarmfan[] = {6, 7};
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct vt1211_data {
+ unsigned short addr;
+ const char *name;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* Register values */
+ u8 in[6];
+ u8 in_max[6];
+ u8 in_min[6];
+ u8 temp[7];
+ u8 temp_max[7];
+ u8 temp_hyst[7];
+ u8 fan[2];
+ u8 fan_min[2];
+ u8 fan_div[2];
+ u8 fan_ctl;
+ u8 pwm[2];
+ u8 pwm_ctl[2];
+ u8 pwm_clk;
+ u8 pwm_auto_temp[4];
+ u8 pwm_auto_pwm[2][4];
+ u8 vid; /* Read once at init time */
+ u8 vrm;
+ u8 uch_config; /* Read once at init time */
+ u16 alarms;
+};
+
+/* ix = [0-5] */
+#define ISVOLT(ix, uch_config) ((ix) > 4 ? 1 : \
+ !(((uch_config) >> ((ix) + 2)) & 1))
+
+/* ix = [0-6] */
+#define ISTEMP(ix, uch_config) ((ix) < 2 ? 1 : \
+ ((uch_config) >> (ix)) & 1)
+
+/* in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the
+ driver according to the VT1211 BIOS porting guide */
+#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \
+ (((reg) - 3) * 15882 + 479) / 958 : \
+ (((reg) - 3) * 10000 + 479) / 958)
+#define IN_TO_REG(ix, val) (SENSORS_LIMIT((ix) == 5 ? \
+ ((val) * 958 + 7941) / 15882 + 3 : \
+ ((val) * 958 + 5000) / 10000 + 3, 0, 255))
+
+/* temp1 (ix = 0) is an intel thermal diode which is scaled in user space.
+ temp2 (ix = 1) is the internal temp diode so it's scaled in the driver
+ according to some measurements that I took on an EPIA M10000.
+ temp3-7 are thermistor based so the driver returns the voltage measured at
+ the pin (range 0V - 2.2V). */
+#define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \
+ (ix) == 1 ? (reg) < 51 ? 0 : \
+ ((reg) - 51) * 1000 : \
+ ((253 - (reg)) * 2200 + 105) / 210)
+#define TEMP_TO_REG(ix, val) SENSORS_LIMIT( \
+ ((ix) == 0 ? ((val) + 500) / 1000 : \
+ (ix) == 1 ? ((val) + 500) / 1000 + 51 : \
+ 253 - ((val) * 210 + 1100) / 2200), 0, 255)
+
+#define DIV_FROM_REG(reg) (1 << (reg))
+
+#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \
+ 1310720 / (reg) / DIV_FROM_REG(div))
+#define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \
+ SENSORS_LIMIT((1310720 / (val) / \
+ DIV_FROM_REG(div)), 1, 254))
+
+/* ---------------------------------------------------------------------
+ * Super-I/O constants and functions
+ * --------------------------------------------------------------------- */
+
+/* Configuration & data index port registers */
+#define SIO_REG_CIP 0x2e
+#define SIO_REG_DIP 0x2f
+
+/* Configuration registers */
+#define SIO_VT1211_LDN 0x07 /* logical device number */
+#define SIO_VT1211_DEVID 0x20 /* device ID */
+#define SIO_VT1211_DEVREV 0x21 /* device revision */
+#define SIO_VT1211_ACTIVE 0x30 /* HW monitor active */
+#define SIO_VT1211_BADDR 0x60 /* base I/O address */
+#define SIO_VT1211_ID 0x3c /* VT1211 device ID */
+
+/* VT1211 logical device numbers */
+#define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */
+
+static inline void superio_outb(int reg, int val)
+{
+ outb(reg, SIO_REG_CIP);
+ outb(val, SIO_REG_DIP);
+}
+
+static inline int superio_inb(int reg)
+{
+ outb(reg, SIO_REG_CIP);
+ return inb(SIO_REG_DIP);
+}
+
+static inline void superio_select(int ldn)
+{
+ outb(SIO_VT1211_LDN, SIO_REG_CIP);
+ outb(ldn, SIO_REG_DIP);
+}
+
+static inline void superio_enter(void)
+{
+ outb(0x87, SIO_REG_CIP);
+ outb(0x87, SIO_REG_CIP);
+}
+
+static inline void superio_exit(void)
+{
+ outb(0xaa, SIO_REG_CIP);
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static inline u8 vt1211_read8(struct vt1211_data *data, u8 reg)
+{
+ return inb(data->addr + reg);
+}
+
+static inline void vt1211_write8(struct vt1211_data *data, u8 reg, u8 val)
+{
+ outb(val, data->addr + reg);
+}
+
+static struct vt1211_data *vt1211_update_device(struct device *dev)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ int ix, val;
+
+ mutex_lock(&data->update_lock);
+
+ /* registers cache is refreshed after 1 second */
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ /* read VID */
+ data->vid = vt1211_read8(data, VT1211_REG_VID) & 0x1f;
+
+ /* voltage (in) registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ if (ISVOLT(ix, data->uch_config)) {
+ data->in[ix] = vt1211_read8(data,
+ VT1211_REG_IN(ix));
+ data->in_min[ix] = vt1211_read8(data,
+ VT1211_REG_IN_MIN(ix));
+ data->in_max[ix] = vt1211_read8(data,
+ VT1211_REG_IN_MAX(ix));
+ }
+ }
+
+ /* temp registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+ if (ISTEMP(ix, data->uch_config)) {
+ data->temp[ix] = vt1211_read8(data,
+ regtemp[ix]);
+ data->temp_max[ix] = vt1211_read8(data,
+ regtempmax[ix]);
+ data->temp_hyst[ix] = vt1211_read8(data,
+ regtemphyst[ix]);
+ }
+ }
+
+ /* fan & pwm registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+ data->fan[ix] = vt1211_read8(data,
+ VT1211_REG_FAN(ix));
+ data->fan_min[ix] = vt1211_read8(data,
+ VT1211_REG_FAN_MIN(ix));
+ data->pwm[ix] = vt1211_read8(data,
+ VT1211_REG_PWM(ix));
+ }
+ val = vt1211_read8(data, VT1211_REG_FAN_DIV);
+ data->fan_div[0] = (val >> 4) & 3;
+ data->fan_div[1] = (val >> 6) & 3;
+ data->fan_ctl = val & 0xf;
+
+ val = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = val & 0xf;
+ data->pwm_ctl[1] = (val >> 4) & 0xf;
+
+ data->pwm_clk = vt1211_read8(data, VT1211_REG_PWM_CLK);
+
+ /* pwm & temp auto point registers */
+ data->pwm_auto_pwm[0][1] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(0, 1));
+ data->pwm_auto_pwm[0][2] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(0, 2));
+ data->pwm_auto_pwm[1][1] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(1, 1));
+ data->pwm_auto_pwm[1][2] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(1, 2));
+ for (ix = 0; ix < ARRAY_SIZE(data->pwm_auto_temp); ix++) {
+ data->pwm_auto_temp[ix] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_TEMP(ix));
+ }
+
+ /* alarm registers */
+ data->alarms = (vt1211_read8(data, VT1211_REG_ALARM2) << 8) |
+ vt1211_read8(data, VT1211_REG_ALARM1);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs interfaces
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_IN_INPUT 0
+#define SHOW_SET_IN_MIN 1
+#define SHOW_SET_IN_MAX 2
+#define SHOW_IN_ALARM 3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_IN_INPUT:
+ res = IN_FROM_REG(ix, data->in[ix]);
+ break;
+ case SHOW_SET_IN_MIN:
+ res = IN_FROM_REG(ix, data->in_min[ix]);
+ break;
+ case SHOW_SET_IN_MAX:
+ res = IN_FROM_REG(ix, data->in_max[ix]);
+ break;
+ case SHOW_IN_ALARM:
+ res = (data->alarms >> bitalarmin[ix]) & 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SHOW_SET_IN_MIN:
+ data->in_min[ix] = IN_TO_REG(ix, val);
+ vt1211_write8(data, VT1211_REG_IN_MIN(ix), data->in_min[ix]);
+ break;
+ case SHOW_SET_IN_MAX:
+ data->in_max[ix] = IN_TO_REG(ix, val);
+ vt1211_write8(data, VT1211_REG_IN_MAX(ix), data->in_max[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs interfaces
+ * ix = [0-6]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_TEMP_INPUT 0
+#define SHOW_SET_TEMP_MAX 1
+#define SHOW_SET_TEMP_MAX_HYST 2
+#define SHOW_TEMP_ALARM 3
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_TEMP_INPUT:
+ res = TEMP_FROM_REG(ix, data->temp[ix]);
+ break;
+ case SHOW_SET_TEMP_MAX:
+ res = TEMP_FROM_REG(ix, data->temp_max[ix]);
+ break;
+ case SHOW_SET_TEMP_MAX_HYST:
+ res = TEMP_FROM_REG(ix, data->temp_hyst[ix]);
+ break;
+ case SHOW_TEMP_ALARM:
+ res = (data->alarms >> bitalarmtemp[ix]) & 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SHOW_SET_TEMP_MAX:
+ data->temp_max[ix] = TEMP_TO_REG(ix, val);
+ vt1211_write8(data, regtempmax[ix],
+ data->temp_max[ix]);
+ break;
+ case SHOW_SET_TEMP_MAX_HYST:
+ data->temp_hyst[ix] = TEMP_TO_REG(ix, val);
+ vt1211_write8(data, regtemphyst[ix],
+ data->temp_hyst[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs interfaces
+ * ix = [0-1]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_FAN_INPUT 0
+#define SHOW_SET_FAN_MIN 1
+#define SHOW_SET_FAN_DIV 2
+#define SHOW_FAN_ALARM 3
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_FAN_INPUT:
+ res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]);
+ break;
+ case SHOW_SET_FAN_MIN:
+ res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]);
+ break;
+ case SHOW_SET_FAN_DIV:
+ res = DIV_FROM_REG(data->fan_div[ix]);
+ break;
+ case SHOW_FAN_ALARM:
+ res = (data->alarms >> bitalarmfan[ix]) & 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ int reg;
+
+ mutex_lock(&data->update_lock);
+
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
+ data->fan_div[0] = (reg >> 4) & 3;
+ data->fan_div[1] = (reg >> 6) & 3;
+ data->fan_ctl = reg & 0xf;
+
+ switch (fn) {
+ case SHOW_SET_FAN_MIN:
+ data->fan_min[ix] = RPM_TO_REG(val, data->fan_div[ix]);
+ vt1211_write8(data, VT1211_REG_FAN_MIN(ix),
+ data->fan_min[ix]);
+ break;
+ case SHOW_SET_FAN_DIV:
+ switch (val) {
+ case 1: data->fan_div[ix] = 0; break;
+ case 2: data->fan_div[ix] = 1; break;
+ case 4: data->fan_div[ix] = 2; break;
+ case 8: data->fan_div[ix] = 3; break;
+ default:
+ count = -EINVAL;
+ dev_warn(dev, "fan div value %ld not "
+ "supported. Choose one of 1, 2, "
+ "4, or 8.\n", val);
+ goto EXIT;
+ }
+ vt1211_write8(data, VT1211_REG_FAN_DIV,
+ ((data->fan_div[1] << 6) |
+ (data->fan_div[0] << 4) |
+ data->fan_ctl));
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+EXIT:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs interfaces
+ * ix = [0-1]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_PWM 0
+#define SHOW_SET_PWM_ENABLE 1
+#define SHOW_SET_PWM_FREQ 2
+#define SHOW_SET_PWM_AUTO_CHANNELS_TEMP 3
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_PWM:
+ res = data->pwm[ix];
+ break;
+ case SHOW_SET_PWM_ENABLE:
+ res = ((data->pwm_ctl[ix] >> 3) & 1) ? 2 : 0;
+ break;
+ case SHOW_SET_PWM_FREQ:
+ res = 90000 >> (data->pwm_clk & 7);
+ break;
+ case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
+ res = (data->pwm_ctl[ix] & 7) + 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ int tmp, reg;
+
+ mutex_lock(&data->update_lock);
+
+ switch (fn) {
+ case SHOW_SET_PWM_ENABLE:
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
+ data->fan_div[0] = (reg >> 4) & 3;
+ data->fan_div[1] = (reg >> 6) & 3;
+ data->fan_ctl = reg & 0xf;
+ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = reg & 0xf;
+ data->pwm_ctl[1] = (reg >> 4) & 0xf;
+ switch (val) {
+ case 0:
+ data->pwm_ctl[ix] &= 7;
+ /* disable SmartGuardian if both PWM outputs are
+ * disabled */
+ if ((data->pwm_ctl[ix ^ 1] & 1) == 0) {
+ data->fan_ctl &= 0xe;
+ }
+ break;
+ case 2:
+ data->pwm_ctl[ix] |= 8;
+ data->fan_ctl |= 1;
+ break;
+ default:
+ count = -EINVAL;
+ dev_warn(dev, "pwm mode %ld not supported. "
+ "Choose one of 0 or 2.\n", val);
+ goto EXIT;
+ }
+ vt1211_write8(data, VT1211_REG_PWM_CTL,
+ ((data->pwm_ctl[1] << 4) |
+ data->pwm_ctl[0]));
+ vt1211_write8(data, VT1211_REG_FAN_DIV,
+ ((data->fan_div[1] << 6) |
+ (data->fan_div[0] << 4) |
+ data->fan_ctl));
+ break;
+ case SHOW_SET_PWM_FREQ:
+ val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000);
+ /* calculate tmp = log2(val) */
+ tmp = 0;
+ for (val >>= 1; val > 0; val >>= 1) {
+ tmp++;
+ }
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_PWM_CLK);
+ data->pwm_clk = (reg & 0xf8) | tmp;
+ vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk);
+ break;
+ case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
+ if ((val < 1) || (val > 7)) {
+ count = -EINVAL;
+ dev_warn(dev, "temp channel %ld not supported. "
+ "Choose a value between 1 and 7.\n", val);
+ goto EXIT;
+ }
+ if (!ISTEMP(val - 1, data->uch_config)) {
+ count = -EINVAL;
+ dev_warn(dev, "temp channel %ld is not available.\n",
+ val);
+ goto EXIT;
+ }
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = reg & 0xf;
+ data->pwm_ctl[1] = (reg >> 4) & 0xf;
+ data->pwm_ctl[ix] = (data->pwm_ctl[ix] & 8) | (val - 1);
+ vt1211_write8(data, VT1211_REG_PWM_CTL,
+ ((data->pwm_ctl[1] << 4) | data->pwm_ctl[0]));
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+EXIT:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM auto point definitions
+ * ix = [0-1]
+ * ap = [0-3]
+ * --------------------------------------------------------------------- */
+
+/*
+ * pwm[ix+1]_auto_point[ap+1]_temp mapping table:
+ * Note that there is only a single set of temp auto points that controls both
+ * PWM controllers. We still create 2 sets of sysfs files to make it look
+ * more consistent even though they map to the same registers.
+ *
+ * ix ap : description
+ * -------------------
+ * 0 0 : pwm1/2 off temperature (pwm_auto_temp[0])
+ * 0 1 : pwm1/2 low speed temperature (pwm_auto_temp[1])
+ * 0 2 : pwm1/2 high speed temperature (pwm_auto_temp[2])
+ * 0 3 : pwm1/2 full speed temperature (pwm_auto_temp[3])
+ * 1 0 : pwm1/2 off temperature (pwm_auto_temp[0])
+ * 1 1 : pwm1/2 low speed temperature (pwm_auto_temp[1])
+ * 1 2 : pwm1/2 high speed temperature (pwm_auto_temp[2])
+ * 1 3 : pwm1/2 full speed temperature (pwm_auto_temp[3])
+ */
+
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7,
+ data->pwm_auto_temp[ap]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ int reg;
+
+ mutex_lock(&data->update_lock);
+
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = reg & 0xf;
+ data->pwm_ctl[1] = (reg >> 4) & 0xf;
+
+ data->pwm_auto_temp[ap] = TEMP_TO_REG(data->pwm_ctl[ix] & 7, val);
+ vt1211_write8(data, VT1211_REG_PWM_AUTO_TEMP(ap),
+ data->pwm_auto_temp[ap]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+ * pwm[ix+1]_auto_point[ap+1]_pwm mapping table:
+ * Note that the PWM auto points 0 & 3 are hard-wired in the VT1211 and can't
+ * be changed.
+ *
+ * ix ap : description
+ * -------------------
+ * 0 0 : pwm1 off (pwm_auto_pwm[0][0], hard-wired to 0)
+ * 0 1 : pwm1 low speed duty cycle (pwm_auto_pwm[0][1])
+ * 0 2 : pwm1 high speed duty cycle (pwm_auto_pwm[0][2])
+ * 0 3 : pwm1 full speed (pwm_auto_pwm[0][3], hard-wired to 255)
+ * 1 0 : pwm2 off (pwm_auto_pwm[1][0], hard-wired to 0)
+ * 1 1 : pwm2 low speed duty cycle (pwm_auto_pwm[1][1])
+ * 1 2 : pwm2 high speed duty cycle (pwm_auto_pwm[1][2])
+ * 1 3 : pwm2 full speed (pwm_auto_pwm[1][3], hard-wired to 255)
+*/
+
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+
+ return sprintf(buf, "%d\n", data->pwm_auto_pwm[ix][ap]);
+}
+
+static ssize_t set_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ if ((val < 0) || (val > 255)) {
+ dev_err(dev, "pwm value %ld is out of range. "
+ "Choose a value between 0 and 255." , val);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->pwm_auto_pwm[ix][ap] = val;
+ vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
+ data->pwm_auto_pwm[ix][ap]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs interfaces (VRM, VID, name, and (legacy) alarms)
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
+
+ data->vrm = val;
+
+ return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t show_alarms(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+
+ return sprintf(buf, "%d\n", data->alarms);
+}
+
+/* ---------------------------------------------------------------------
+ * Device attribute structs
+ * --------------------------------------------------------------------- */
+
+#define SENSOR_ATTR_IN_INPUT(ix) \
+ SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \
+ show_in, NULL, SHOW_IN_INPUT, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_input[] = {
+ SENSOR_ATTR_IN_INPUT(0),
+ SENSOR_ATTR_IN_INPUT(1),
+ SENSOR_ATTR_IN_INPUT(2),
+ SENSOR_ATTR_IN_INPUT(3),
+ SENSOR_ATTR_IN_INPUT(4),
+ SENSOR_ATTR_IN_INPUT(5),
+};
+
+#define SENSOR_ATTR_IN_MIN(ix) \
+ SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SHOW_SET_IN_MIN, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_min[] = {
+ SENSOR_ATTR_IN_MIN(0),
+ SENSOR_ATTR_IN_MIN(1),
+ SENSOR_ATTR_IN_MIN(2),
+ SENSOR_ATTR_IN_MIN(3),
+ SENSOR_ATTR_IN_MIN(4),
+ SENSOR_ATTR_IN_MIN(5),
+};
+
+#define SENSOR_ATTR_IN_MAX(ix) \
+ SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SHOW_SET_IN_MAX, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_max[] = {
+ SENSOR_ATTR_IN_MAX(0),
+ SENSOR_ATTR_IN_MAX(1),
+ SENSOR_ATTR_IN_MAX(2),
+ SENSOR_ATTR_IN_MAX(3),
+ SENSOR_ATTR_IN_MAX(4),
+ SENSOR_ATTR_IN_MAX(5),
+};
+
+#define SENSOR_ATTR_IN_ALARM(ix) \
+ SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \
+ show_in, NULL, SHOW_IN_ALARM, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_alarm[] = {
+ SENSOR_ATTR_IN_ALARM(0),
+ SENSOR_ATTR_IN_ALARM(1),
+ SENSOR_ATTR_IN_ALARM(2),
+ SENSOR_ATTR_IN_ALARM(3),
+ SENSOR_ATTR_IN_ALARM(4),
+ SENSOR_ATTR_IN_ALARM(5),
+};
+
+#define SENSOR_ATTR_TEMP_INPUT(ix) \
+ SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \
+ show_temp, NULL, SHOW_TEMP_INPUT, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_input[] = {
+ SENSOR_ATTR_TEMP_INPUT(1),
+ SENSOR_ATTR_TEMP_INPUT(2),
+ SENSOR_ATTR_TEMP_INPUT(3),
+ SENSOR_ATTR_TEMP_INPUT(4),
+ SENSOR_ATTR_TEMP_INPUT(5),
+ SENSOR_ATTR_TEMP_INPUT(6),
+ SENSOR_ATTR_TEMP_INPUT(7),
+};
+
+#define SENSOR_ATTR_TEMP_MAX(ix) \
+ SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_max[] = {
+ SENSOR_ATTR_TEMP_MAX(1),
+ SENSOR_ATTR_TEMP_MAX(2),
+ SENSOR_ATTR_TEMP_MAX(3),
+ SENSOR_ATTR_TEMP_MAX(4),
+ SENSOR_ATTR_TEMP_MAX(5),
+ SENSOR_ATTR_TEMP_MAX(6),
+ SENSOR_ATTR_TEMP_MAX(7),
+};
+
+#define SENSOR_ATTR_TEMP_MAX_HYST(ix) \
+ SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_max_hyst[] = {
+ SENSOR_ATTR_TEMP_MAX_HYST(1),
+ SENSOR_ATTR_TEMP_MAX_HYST(2),
+ SENSOR_ATTR_TEMP_MAX_HYST(3),
+ SENSOR_ATTR_TEMP_MAX_HYST(4),
+ SENSOR_ATTR_TEMP_MAX_HYST(5),
+ SENSOR_ATTR_TEMP_MAX_HYST(6),
+ SENSOR_ATTR_TEMP_MAX_HYST(7),
+};
+
+#define SENSOR_ATTR_TEMP_ALARM(ix) \
+ SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+ show_temp, NULL, SHOW_TEMP_ALARM, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_alarm[] = {
+ SENSOR_ATTR_TEMP_ALARM(1),
+ SENSOR_ATTR_TEMP_ALARM(2),
+ SENSOR_ATTR_TEMP_ALARM(3),
+ SENSOR_ATTR_TEMP_ALARM(4),
+ SENSOR_ATTR_TEMP_ALARM(5),
+ SENSOR_ATTR_TEMP_ALARM(6),
+ SENSOR_ATTR_TEMP_ALARM(7),
+};
+
+#define SENSOR_ATTR_FAN(ix) \
+ SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \
+ show_fan, NULL, SHOW_FAN_INPUT, ix-1), \
+ SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \
+ SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \
+ SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+ show_fan, NULL, SHOW_FAN_ALARM, ix-1)
+
+#define SENSOR_ATTR_PWM(ix) \
+ SENSOR_ATTR_2(pwm##ix, S_IRUGO, \
+ show_pwm, NULL, SHOW_PWM, ix-1), \
+ SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \
+ SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1)
+
+#define SENSOR_ATTR_PWM_FREQ(ix) \
+ SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1)
+
+#define SENSOR_ATTR_PWM_FREQ_RO(ix) \
+ SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+ show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp, \
+ ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \
+ show_pwm_auto_point_temp, NULL, \
+ ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \
+ show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \
+ ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \
+ show_pwm_auto_point_pwm, NULL, \
+ ap-1, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = {
+ SENSOR_ATTR_FAN(1),
+ SENSOR_ATTR_FAN(2),
+ SENSOR_ATTR_PWM(1),
+ SENSOR_ATTR_PWM(2),
+ SENSOR_ATTR_PWM_FREQ(1),
+ SENSOR_ATTR_PWM_FREQ_RO(2),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4),
+};
+
+static struct device_attribute vt1211_sysfs_misc[] = {
+ __ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm),
+ __ATTR(cpu0_vid, S_IRUGO, show_vid, NULL),
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR(alarms, S_IRUGO, show_alarms, NULL),
+};
+
+/* ---------------------------------------------------------------------
+ * Device registration and initialization
+ * --------------------------------------------------------------------- */
+
+static void __devinit vt1211_init_device(struct vt1211_data *data)
+{
+ /* set VRM */
+ data->vrm = vid_which_vrm();
+
+ /* Read (and initialize) UCH config */
+ data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG);
+ if (uch_config > -1) {
+ data->uch_config = (data->uch_config & 0x83) |
+ (uch_config << 2);
+ vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config);
+ }
+
+ /* Initialize the interrupt mode (if request at module load time).
+ * The VT1211 implements 3 different modes for clearing interrupts:
+ * 0: Clear INT when status register is read. Regenerate INT as long
+ * as temp stays above hysteresis limit.
+ * 1: Clear INT when status register is read. DON'T regenerate INT
+ * until temp falls below hysteresis limit and exceeds hot limit
+ * again.
+ * 2: Clear INT when temp falls below max limit.
+ *
+ * The driver only allows to force mode 0 since that's the only one
+ * that makes sense for 'sensors' */
+ if (int_mode == 0) {
+ vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0);
+ vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0);
+ }
+
+ /* Fill in some hard wired values into our data struct */
+ data->pwm_auto_pwm[0][3] = 255;
+ data->pwm_auto_pwm[1][3] = 255;
+}
+
+static void vt1211_remove_sysfs(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {
+ device_remove_file(dev,
+ &vt1211_sysfs_in_input[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_in_min[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_in_max[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_in_alarm[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_input[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_max[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_max_hyst[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_alarm[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
+ device_remove_file(dev,
+ &vt1211_sysfs_fan_pwm[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
+ device_remove_file(dev, &vt1211_sysfs_misc[i]);
+ }
+}
+
+static int __devinit vt1211_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct vt1211_data *data;
+ struct resource *res;
+ int i, err;
+
+ if (!(data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ dev_err(dev, "Out of memory\n");
+ goto EXIT;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ data->addr = res->start;
+ data->name = DRVNAME;
+ mutex_init(&data->update_lock);
+
+ platform_set_drvdata(pdev, data);
+
+ /* Initialize the VT1211 chip */
+ vt1211_init_device(data);
+
+ /* Create sysfs interface files */
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {
+ if (ISVOLT(i, data->uch_config)) {
+ if ((err = device_create_file(dev,
+ &vt1211_sysfs_in_input[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_in_min[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_in_max[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_in_alarm[i].dev_attr))) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {
+ if (ISTEMP(i, data->uch_config)) {
+ if ((err = device_create_file(dev,
+ &vt1211_sysfs_temp_input[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_temp_max[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_temp_max_hyst[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_temp_alarm[i].dev_attr))) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
+ err = device_create_file(dev,
+ &vt1211_sysfs_fan_pwm[i].dev_attr);
+ if (err) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
+ err = device_create_file(dev,
+ &vt1211_sysfs_misc[i]);
+ if (err) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+
+ /* Register device */
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ dev_err(dev, "Class registration failed (%d)\n", err);
+ goto EXIT_DEV_REMOVE_SILENT;
+ }
+
+ return 0;
+
+EXIT_DEV_REMOVE:
+ dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
+EXIT_DEV_REMOVE_SILENT:
+ vt1211_remove_sysfs(pdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+EXIT:
+ return err;
+}
+
+static int __devexit vt1211_remove(struct platform_device *pdev)
+{
+ struct vt1211_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->class_dev);
+ vt1211_remove_sysfs(pdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+
+ return 0;
+}
+
+static struct platform_driver vt1211_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = vt1211_probe,
+ .remove = __devexit_p(vt1211_remove),
+};
+
+static int __init vt1211_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + 0x7f,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n",
+ err);
+ goto EXIT;
+ }
+
+ res.name = pdev->name;
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto EXIT_DEV_PUT;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto EXIT_DEV_PUT;
+ }
+
+ return 0;
+
+EXIT_DEV_PUT:
+ platform_device_put(pdev);
+EXIT:
+ return err;
+}
+
+static int __init vt1211_find(unsigned short *address)
+{
+ int err = -ENODEV;
+
+ superio_enter();
+
+ if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) {
+ goto EXIT;
+ }
+
+ superio_select(SIO_VT1211_LDN_HWMON);
+
+ if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) {
+ printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
+ "skipping\n");
+ goto EXIT;
+ }
+
+ *address = ((superio_inb(SIO_VT1211_BADDR) << 8) |
+ (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00;
+ if (*address == 0) {
+ printk(KERN_WARNING DRVNAME ": Base address is not set, "
+ "skipping\n");
+ goto EXIT;
+ }
+
+ err = 0;
+ printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
+ "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV));
+
+EXIT:
+ superio_exit();
+ return err;
+}
+
+static int __init vt1211_init(void)
+{
+ int err;
+ unsigned short address = 0;
+
+ err = vt1211_find(&address);
+ if (err) {
+ goto EXIT;
+ }
+
+ if ((uch_config < -1) || (uch_config > 31)) {
+ err = -EINVAL;
+ printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. "
+ "Choose a value between 0 and 31.\n", uch_config);
+ goto EXIT;
+ }
+
+ if ((int_mode < -1) || (int_mode > 0)) {
+ err = -EINVAL;
+ printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. "
+ "Only mode 0 is supported.\n", int_mode);
+ goto EXIT;
+ }
+
+ err = platform_driver_register(&vt1211_driver);
+ if (err) {
+ goto EXIT;
+ }
+
+ /* Sets global pdev as a side effect */
+ err = vt1211_device_add(address);
+ if (err) {
+ goto EXIT_DRV_UNREGISTER;
+ }
+
+ return 0;
+
+EXIT_DRV_UNREGISTER:
+ platform_driver_unregister(&vt1211_driver);
+EXIT:
+ return err;
+}
+
+static void __exit vt1211_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&vt1211_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("VT1211 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(vt1211_init);
+module_exit(vt1211_exit);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 686f3deb309..93f93d4fb8a 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -451,37 +451,6 @@ define_temperature_sysfs(4);
define_temperature_sysfs(5);
define_temperature_sysfs(6);
-#define CFG_INFO_TEMP(id) { &sensor_dev_attr_temp##id##_input.dev_attr, \
- &sensor_dev_attr_temp##id##_max_hyst.dev_attr, \
- &sensor_dev_attr_temp##id##_max.dev_attr }
-#define CFG_INFO_VOLT(id) { &sensor_dev_attr_in##id##_input.dev_attr, \
- &sensor_dev_attr_in##id##_min.dev_attr, \
- &sensor_dev_attr_in##id##_max.dev_attr }
-
-struct str_device_attr_table {
- struct device_attribute *input;
- struct device_attribute *min;
- struct device_attribute *max;
-};
-
-static struct str_device_attr_table cfg_info_temp[] = {
- { &dev_attr_temp1_input, &dev_attr_temp1_max_hyst, &dev_attr_temp1_max },
- CFG_INFO_TEMP(2),
- CFG_INFO_TEMP(3),
- CFG_INFO_TEMP(4),
- CFG_INFO_TEMP(5),
- CFG_INFO_TEMP(6)
-};
-
-static struct str_device_attr_table cfg_info_volt[] = {
- CFG_INFO_VOLT(0),
- CFG_INFO_VOLT(1),
- CFG_INFO_VOLT(2),
- CFG_INFO_VOLT(3),
- CFG_INFO_VOLT(4),
- { &dev_attr_in5_input, &dev_attr_in5_min, &dev_attr_in5_max }
-};
-
/* Fans */
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -585,8 +554,110 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *vt8231_attributes_temps[6][4] = {
+ {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_max.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group vt8231_group_temps[6] = {
+ { .attrs = vt8231_attributes_temps[0] },
+ { .attrs = vt8231_attributes_temps[1] },
+ { .attrs = vt8231_attributes_temps[2] },
+ { .attrs = vt8231_attributes_temps[3] },
+ { .attrs = vt8231_attributes_temps[4] },
+ { .attrs = vt8231_attributes_temps[5] },
+};
+
+static struct attribute *vt8231_attributes_volts[6][4] = {
+ {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ NULL
+ }, {
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group vt8231_group_volts[6] = {
+ { .attrs = vt8231_attributes_volts[0] },
+ { .attrs = vt8231_attributes_volts[1] },
+ { .attrs = vt8231_attributes_volts[2] },
+ { .attrs = vt8231_attributes_volts[3] },
+ { .attrs = vt8231_attributes_volts[4] },
+ { .attrs = vt8231_attributes_volts[5] },
+};
+
+static struct attribute *vt8231_attributes[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group vt8231_group = {
+ .attrs = vt8231_attributes,
+};
+
static struct i2c_driver vt8231_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "vt8231",
},
.attach_adapter = vt8231_detect,
@@ -670,43 +741,43 @@ int vt8231_detect(struct i2c_adapter *adapter)
vt8231_init_client(client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
goto exit_detach;
- }
/* Must update device information to find out the config field */
data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
- for (i = 0; i < ARRAY_SIZE(cfg_info_temp); i++) {
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
if (ISTEMP(i, data->uch_config)) {
- device_create_file(&client->dev,
- cfg_info_temp[i].input);
- device_create_file(&client->dev, cfg_info_temp[i].max);
- device_create_file(&client->dev, cfg_info_temp[i].min);
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &vt8231_group_temps[i])))
+ goto exit_remove_files;
}
}
- for (i = 0; i < ARRAY_SIZE(cfg_info_volt); i++) {
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
if (ISVOLT(i, data->uch_config)) {
- device_create_file(&client->dev,
- cfg_info_volt[i].input);
- device_create_file(&client->dev, cfg_info_volt[i].max);
- device_create_file(&client->dev, cfg_info_volt[i].min);
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &vt8231_group_volts[i])))
+ goto exit_remove_files;
}
}
- device_create_file(&client->dev, &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan2_div.dev_attr);
-
- device_create_file(&client->dev, &dev_attr_alarms);
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
return 0;
+exit_remove_files:
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group);
exit_detach:
i2c_detach_client(client);
exit_free:
@@ -719,10 +790,18 @@ exit_release:
static int vt8231_detach_client(struct i2c_client *client)
{
struct vt8231_data *data = i2c_get_clientdata(client);
- int err;
+ int err, i;
hwmon_device_unregister(data->class_dev);
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+
if ((err = i2c_detach_client(client))) {
return err;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 40301bc6ce1..833faa275ff 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -2,6 +2,9 @@
w83627ehf - Driver for the hardware monitoring functionality of
the Winbond W83627EHF Super-I/O chip
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2006 Yuan Mu (Winbond),
+ Rudolf Marek <r.marek@sh.cvut.cz>
+ David Hubbard <david.c.hubbard@gmail.com>
Shamelessly ripped from the w83627hf driver
Copyright (C) 2003 Mark Studebaker
@@ -29,8 +32,8 @@
Supports the following chips:
- Chip #vin #fan #pwm #temp chip_id man_id
- w83627ehf 10 5 - 3 0x88 0x5ca3
+ Chip #vin #fan #pwm #temp chip_id man_id
+ w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3
*/
#include <linux/module.h>
@@ -145,10 +148,44 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
#define W83627EHF_REG_ALARM2 0x45A
#define W83627EHF_REG_ALARM3 0x45B
+/* SmartFan registers */
+/* DC or PWM output fan configuration */
+static const u8 W83627EHF_REG_PWM_ENABLE[] = {
+ 0x04, /* SYS FAN0 output mode and PWM mode */
+ 0x04, /* CPU FAN0 output mode and PWM mode */
+ 0x12, /* AUX FAN mode */
+ 0x62, /* CPU fan1 mode */
+};
+
+static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
+static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
+
+/* FAN Duty Cycle, be used to control */
+static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
+static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
+static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
+
+
+/* Advanced Fan control, some values are common for all fans */
+static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
+static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
+
/*
* Conversions
*/
+/* 1 is PWM mode, output in ms */
+static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+ return mode ? 100 * reg : 400 * reg;
+}
+
+static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+ return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
+ (msec + 200) / 400), 1, 255);
+}
+
static inline unsigned int
fan_from_reg(u8 reg, unsigned int div)
{
@@ -170,12 +207,12 @@ temp1_from_reg(s8 reg)
}
static inline s8
-temp1_to_reg(int temp)
+temp1_to_reg(int temp, int min, int max)
{
- if (temp <= -128000)
- return -128;
- if (temp >= 127000)
- return 127;
+ if (temp <= min)
+ return min / 1000;
+ if (temp >= max)
+ return max / 1000;
if (temp < 0)
return (temp - 500) / 1000;
return (temp + 500) / 1000;
@@ -223,6 +260,16 @@ struct w83627ehf_data {
s16 temp_max[2];
s16 temp_max_hyst[2];
u32 alarms;
+
+ u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
+ u8 pwm_enable[4]; /* 1->manual
+ 2->thermal cruise (also called SmartFan I) */
+ u8 pwm[4];
+ u8 target_temp[4];
+ u8 tolerance[4];
+
+ u8 fan_min_output[4]; /* minimum fan speed */
+ u8 fan_stop_time[4];
};
static inline int is_word_sized(u16 reg)
@@ -349,6 +396,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83627ehf_data *data = i2c_get_clientdata(client);
+ int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
int i;
mutex_lock(&data->update_lock);
@@ -416,6 +464,34 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
}
}
+ for (i = 0; i < 4; i++) {
+ /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
+ if (i != 1) {
+ pwmcfg = w83627ehf_read_value(client,
+ W83627EHF_REG_PWM_ENABLE[i]);
+ tolerance = w83627ehf_read_value(client,
+ W83627EHF_REG_TOLERANCE[i]);
+ }
+ data->pwm_mode[i] =
+ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
+ ? 0 : 1;
+ data->pwm_enable[i] =
+ ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+ & 3) + 1;
+ data->pwm[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_PWM[i]);
+ data->fan_min_output[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_MIN_OUTPUT[i]);
+ data->fan_stop_time[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_STOP_TIME[i]);
+ data->target_temp[i] =
+ w83627ehf_read_value(client,
+ W83627EHF_REG_TARGET[i]) &
+ (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
+ data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
+ & 0x0f;
+ }
+
/* Measured temperatures and limits */
data->temp1 = w83627ehf_read_value(client,
W83627EHF_REG_TEMP1);
@@ -546,14 +622,6 @@ static struct sensor_device_attribute sda_in_max[] = {
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
};
-static void device_create_file_in(struct device *dev, int i)
-{
- device_create_file(dev, &sda_in_input[i].dev_attr);
- device_create_file(dev, &sda_in_alarm[i].dev_attr);
- device_create_file(dev, &sda_in_min[i].dev_attr);
- device_create_file(dev, &sda_in_max[i].dev_attr);
-}
-
#define show_fan_reg(reg) \
static ssize_t \
show_##reg(struct device *dev, struct device_attribute *attr, \
@@ -681,14 +749,6 @@ static struct sensor_device_attribute sda_fan_div[] = {
SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
};
-static void device_create_file_fan(struct device *dev, int i)
-{
- device_create_file(dev, &sda_fan_input[i].dev_attr);
- device_create_file(dev, &sda_fan_alarm[i].dev_attr);
- device_create_file(dev, &sda_fan_div[i].dev_attr);
- device_create_file(dev, &sda_fan_min[i].dev_attr);
-}
-
#define show_temp1_reg(reg) \
static ssize_t \
show_##reg(struct device *dev, struct device_attribute *attr, \
@@ -711,7 +771,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
- data->temp1_##reg = temp1_to_reg(val); \
+ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
data->temp1_##reg); \
mutex_unlock(&data->update_lock); \
@@ -777,10 +837,309 @@ static struct sensor_device_attribute sda_temp[] = {
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
};
+#define show_pwm_reg(reg) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", data->reg[nr]); \
+}
+
+show_pwm_reg(pwm_mode)
+show_pwm_reg(pwm_enable)
+show_pwm_reg(pwm)
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u16 reg;
+
+ if (val > 1)
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ data->pwm_mode[nr] = val;
+ reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
+ if (!val)
+ reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
+ w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = val;
+ w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u16 reg;
+
+ if (!val || (val > 2)) /* only modes 1 and 2 are supported */
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ data->pwm_enable[nr] = val;
+ reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
+ reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
+ w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+
+#define show_tol_temp(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
+}
+
+show_tol_temp(tolerance)
+show_tol_temp(target_temp)
+
+static ssize_t
+store_target_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
+
+ mutex_lock(&data->update_lock);
+ data->target_temp[nr] = val;
+ w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u16 reg;
+ /* Limit the temp to 0C - 15C */
+ u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
+
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
+ data->tolerance[nr] = val;
+ if (nr == 1)
+ reg = (reg & 0x0f) | (val << 4);
+ else
+ reg = (reg & 0xf0) | val;
+ w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static struct sensor_device_attribute sda_pwm[] = {
+ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+ SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
+};
+
+static struct sensor_device_attribute sda_pwm_mode[] = {
+ SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 0),
+ SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 1),
+ SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 2),
+ SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 3),
+};
+
+static struct sensor_device_attribute sda_pwm_enable[] = {
+ SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 0),
+ SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 1),
+ SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 2),
+ SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 3),
+};
+
+static struct sensor_device_attribute sda_target_temp[] = {
+ SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 0),
+ SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 1),
+ SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 2),
+ SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 3),
+};
+
+static struct sensor_device_attribute sda_tolerance[] = {
+ SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 0),
+ SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 1),
+ SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 2),
+ SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 3),
+};
+
+/* Smart Fan registers */
+
+#define fan_functions(reg, REG) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", data->reg[nr]); \
+}\
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{\
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
+ mutex_lock(&data->update_lock); \
+ data->reg[nr] = val; \
+ w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+}
+
+fan_functions(fan_min_output, FAN_MIN_OUTPUT)
+
+#define fan_time_functions(reg, REG) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", \
+ step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
+} \
+\
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
+ data->pwm_mode[nr]); \
+ mutex_lock(&data->update_lock); \
+ data->reg[nr] = val; \
+ w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+} \
+
+fan_time_functions(fan_stop_time, FAN_STOP_TIME)
+
+
+static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
+ SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 3),
+ SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 3),
+};
+
+static struct sensor_device_attribute sda_sf3_arrays[] = {
+ SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 0),
+ SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 1),
+ SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 2),
+ SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 0),
+ SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 1),
+ SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 2),
+};
+
/*
* Driver and client management
*/
+static void w83627ehf_device_remove_files(struct device *dev)
+{
+ /* some entries in the following arrays may not have been used in
+ * device_create_file(), but device_remove_file() will ignore them */
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
+ device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
+ device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
+ for (i = 0; i < 10; i++) {
+ device_remove_file(dev, &sda_in_input[i].dev_attr);
+ device_remove_file(dev, &sda_in_alarm[i].dev_attr);
+ device_remove_file(dev, &sda_in_min[i].dev_attr);
+ device_remove_file(dev, &sda_in_max[i].dev_attr);
+ }
+ for (i = 0; i < 5; i++) {
+ device_remove_file(dev, &sda_fan_input[i].dev_attr);
+ device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
+ device_remove_file(dev, &sda_fan_div[i].dev_attr);
+ device_remove_file(dev, &sda_fan_min[i].dev_attr);
+ }
+ for (i = 0; i < 4; i++) {
+ device_remove_file(dev, &sda_pwm[i].dev_attr);
+ device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
+ device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
+ device_remove_file(dev, &sda_target_temp[i].dev_attr);
+ device_remove_file(dev, &sda_tolerance[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
+ device_remove_file(dev, &sda_temp[i].dev_attr);
+}
+
static struct i2c_driver w83627ehf_driver;
static void w83627ehf_init_client(struct i2c_client *client)
@@ -810,6 +1169,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
struct i2c_client *client;
struct w83627ehf_data *data;
struct device *dev;
+ u8 fan4pin, fan5pin;
int i, err = 0;
if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
@@ -848,35 +1208,87 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
data->fan_min[i] = w83627ehf_read_value(client,
W83627EHF_REG_FAN_MIN[i]);
+ /* fan4 and fan5 share some pins with the GPIO and serial flash */
+
+ superio_enter();
+ fan5pin = superio_inb(0x24) & 0x2;
+ fan4pin = superio_inb(0x29) & 0x6;
+ superio_exit();
+
/* It looks like fan4 and fan5 pins can be alternatively used
as fan on/off switches */
+
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
- if (i & (1 << 2))
+ if ((i & (1 << 2)) && (!fan4pin))
data->has_fan |= (1 << 3);
- if (i & (1 << 0))
+ if ((i & (1 << 0)) && (!fan5pin))
data->has_fan |= (1 << 4);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto exit_detach;
- }
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
+ if ((err = device_create_file(dev,
+ &sda_sf3_arrays[i].dev_attr)))
+ goto exit_remove;
+
+ /* if fan4 is enabled create the sf3 files for it */
+ if (data->has_fan & (1 << 3))
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
+ if ((err = device_create_file(dev,
+ &sda_sf3_arrays_fan4[i].dev_attr)))
+ goto exit_remove;
+ }
for (i = 0; i < 10; i++)
- device_create_file_in(dev, i);
+ if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_in_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_in_min[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_in_max[i].dev_attr)))
+ goto exit_remove;
for (i = 0; i < 5; i++) {
- if (data->has_fan & (1 << i))
- device_create_file_fan(dev, i);
+ if (data->has_fan & (1 << i)) {
+ if ((err = device_create_file(dev,
+ &sda_fan_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_fan_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_fan_div[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_fan_min[i].dev_attr)))
+ goto exit_remove;
+ if (i < 4 && /* w83627ehf only has 4 pwm */
+ ((err = device_create_file(dev,
+ &sda_pwm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_pwm_mode[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_pwm_enable[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_target_temp[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_tolerance[i].dev_attr))))
+ goto exit_remove;
+ }
}
+
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
- device_create_file(dev, &sda_temp[i].dev_attr);
+ if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
+ goto exit_remove;
+
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
return 0;
-exit_detach:
+exit_remove:
+ w83627ehf_device_remove_files(dev);
i2c_detach_client(client);
exit_free:
kfree(data);
@@ -892,6 +1304,7 @@ static int w83627ehf_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ w83627ehf_device_remove_files(&client->dev);
if ((err = i2c_detach_client(client)))
return err;
@@ -903,6 +1316,7 @@ static int w83627ehf_detach_client(struct i2c_client *client)
static struct i2c_driver w83627ehf_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "w83627ehf",
},
.attach_adapter = w83627ehf_detect,
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 71fb7f1af8f..dfdc29c7712 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -339,6 +339,7 @@ static void w83627hf_init_client(struct i2c_client *client);
static struct i2c_driver w83627hf_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "w83627hf",
},
.attach_adapter = w83627hf_detect,
@@ -511,13 +512,6 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
show_regs_in_max0, store_regs_in_max0);
-#define device_create_file_in(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -575,12 +569,6 @@ sysfs_fan_min_offset(2);
sysfs_fan_offset(3);
sysfs_fan_min_offset(3);
-#define device_create_file_fan(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
-} while (0)
-
#define show_temp_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -655,13 +643,6 @@ sysfs_temp_offsets(1);
sysfs_temp_offsets(2);
sysfs_temp_offsets(3);
-#define device_create_file_temp(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
-} while (0)
-
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -669,8 +650,6 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -691,8 +670,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm)
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -701,8 +678,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms)
#define show_beep_reg(REG, reg) \
static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
@@ -765,12 +740,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
-#define device_create_file_beep(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask); \
-} while (0)
-
static ssize_t
show_fan_div_reg(struct device *dev, char *buf, int nr)
{
@@ -781,7 +750,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr)
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
@@ -836,11 +805,6 @@ sysfs_fan_div(1);
sysfs_fan_div(2);
sysfs_fan_div(3);
-#define device_create_file_fan_div(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
static ssize_t
show_pwm_reg(struct device *dev, char *buf, int nr)
{
@@ -895,11 +859,6 @@ sysfs_pwm(1);
sysfs_pwm(2);
sysfs_pwm(3);
-#define device_create_file_pwm(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset); \
-} while (0)
-
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
@@ -971,12 +930,6 @@ sysfs_sensor(1);
sysfs_sensor(2);
sysfs_sensor(3);
-#define device_create_file_sensor(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
-} while (0)
-
-
static int __init w83627hf_find(int sioaddr, unsigned short *addr)
{
u16 val;
@@ -1008,6 +961,85 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr)
return 0;
}
+static struct attribute *w83627hf_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in7_input.attr,
+ &dev_attr_in7_min.attr,
+ &dev_attr_in7_max.attr,
+ &dev_attr_in8_input.attr,
+ &dev_attr_in8_min.attr,
+ &dev_attr_in8_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_type.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp2_type.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+
+ NULL
+};
+
+static const struct attribute_group w83627hf_group = {
+ .attrs = w83627hf_attributes,
+};
+
+static struct attribute *w83627hf_attributes_opt[] = {
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_max_hyst.attr,
+ &dev_attr_temp3_type.attr,
+
+ &dev_attr_pwm3.attr,
+
+ NULL
+};
+
+static const struct attribute_group w83627hf_group_opt = {
+ .attrs = w83627hf_attributes_opt,
+};
+
static int w83627hf_detect(struct i2c_adapter *adapter)
{
int val, kind;
@@ -1107,62 +1139,72 @@ static int w83627hf_detect(struct i2c_adapter *adapter)
data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* Register common device attributes */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
goto ERROR3;
- }
-
- device_create_file_in(new_client, 0);
- if (kind != w83697hf)
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- if (kind == w83627hf || kind == w83697hf) {
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
- }
- device_create_file_in(new_client, 7);
- device_create_file_in(new_client, 8);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- if (kind != w83697hf)
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- if (kind != w83697hf)
- device_create_file_temp(new_client, 3);
- if (kind != w83697hf && data->vid != 0xff) {
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
- }
+ /* Register chip-specific device attributes */
+ if (kind == w83627hf || kind == w83697hf)
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in5_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_max)))
+ goto ERROR4;
- device_create_file_fan_div(new_client, 1);
- device_create_file_fan_div(new_client, 2);
if (kind != w83697hf)
- device_create_file_fan_div(new_client, 3);
-
- device_create_file_alarms(new_client);
-
- device_create_file_beep(new_client);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in1_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_div))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max_hyst))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_type)))
+ goto ERROR4;
+
+ if (kind != w83697hf && data->vid != 0xff)
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_vrm)))
+ goto ERROR4;
- device_create_file_pwm(new_client, 1);
- device_create_file_pwm(new_client, 2);
if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
- device_create_file_pwm(new_client, 3);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm3)))
+ goto ERROR4;
- device_create_file_sensor(new_client, 1);
- device_create_file_sensor(new_client, 2);
- if (kind != w83697hf)
- device_create_file_sensor(new_client, 3);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
+ }
return 0;
+ ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -1180,6 +1222,9 @@ static int w83627hf_detach_client(struct i2c_client *client)
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index e4c700356c4..a4584ec6984 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -41,6 +41,7 @@
#include <linux/i2c-isa.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
+#include <linux/sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <asm/io.h>
@@ -288,6 +289,7 @@ static struct i2c_driver w83781d_driver = {
static struct i2c_driver w83781d_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "w83781d-isa",
},
.attach_adapter = w83781d_isa_attach_adapter,
@@ -359,13 +361,6 @@ sysfs_in_offsets(6);
sysfs_in_offsets(7);
sysfs_in_offsets(8);
-#define device_create_file_in(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -420,12 +415,6 @@ sysfs_fan_min_offset(2);
sysfs_fan_offset(3);
sysfs_fan_min_offset(3);
-#define device_create_file_fan(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
-} while (0)
-
#define show_temp_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -496,13 +485,6 @@ sysfs_temp_offsets(1);
sysfs_temp_offsets(2);
sysfs_temp_offsets(3);
-#define device_create_file_temp(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
-} while (0)
-
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -510,10 +492,8 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
-static
-DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -534,10 +514,8 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
return count;
}
-static
-DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm);
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -545,10 +523,8 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%u\n", data->alarms);
}
-static
-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
@@ -614,12 +590,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_re
sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
-#define device_create_file_beep(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask); \
-} while (0)
-
static ssize_t
show_fan_div_reg(struct device *dev, char *buf, int nr)
{
@@ -630,7 +600,7 @@ show_fan_div_reg(struct device *dev, char *buf, int nr)
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
store_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr)
@@ -685,11 +655,6 @@ sysfs_fan_div(1);
sysfs_fan_div(2);
sysfs_fan_div(3);
-#define device_create_file_fan_div(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
static ssize_t
show_pwm_reg(struct device *dev, char *buf, int nr)
{
@@ -786,16 +751,6 @@ sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */
sysfs_pwm(3);
sysfs_pwm(4);
-#define device_create_file_pwm(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset); \
-} while (0)
-
-#define device_create_file_pwmenable(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \
-} while (0)
-
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
@@ -864,11 +819,6 @@ sysfs_sensor(1);
sysfs_sensor(2);
sysfs_sensor(3);
-#define device_create_file_sensor(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
-} while (0)
-
/* This function is called when:
* w83781d_driver is inserted (when this module is loaded), for each
available adapter
@@ -993,11 +943,69 @@ ERROR_SC_0:
return err;
}
+#define IN_UNIT_ATTRS(X) \
+ &dev_attr_in##X##_input.attr, \
+ &dev_attr_in##X##_min.attr, \
+ &dev_attr_in##X##_max.attr
+
+#define FAN_UNIT_ATTRS(X) \
+ &dev_attr_fan##X##_input.attr, \
+ &dev_attr_fan##X##_min.attr, \
+ &dev_attr_fan##X##_div.attr
+
+#define TEMP_UNIT_ATTRS(X) \
+ &dev_attr_temp##X##_input.attr, \
+ &dev_attr_temp##X##_max.attr, \
+ &dev_attr_temp##X##_max_hyst.attr
+
+static struct attribute* w83781d_attributes[] = {
+ IN_UNIT_ATTRS(0),
+ IN_UNIT_ATTRS(2),
+ IN_UNIT_ATTRS(3),
+ IN_UNIT_ATTRS(4),
+ IN_UNIT_ATTRS(5),
+ IN_UNIT_ATTRS(6),
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+ FAN_UNIT_ATTRS(3),
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_mask.attr,
+ &dev_attr_beep_enable.attr,
+ NULL
+};
+static const struct attribute_group w83781d_group = {
+ .attrs = w83781d_attributes,
+};
+
+static struct attribute *w83781d_attributes_opt[] = {
+ IN_UNIT_ATTRS(1),
+ IN_UNIT_ATTRS(7),
+ IN_UNIT_ATTRS(8),
+ TEMP_UNIT_ATTRS(3),
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3.attr,
+ &dev_attr_pwm4.attr,
+ &dev_attr_temp1_type.attr,
+ &dev_attr_temp2_type.attr,
+ &dev_attr_temp3_type.attr,
+ NULL
+};
+static const struct attribute_group w83781d_group_opt = {
+ .attrs = w83781d_attributes_opt,
+};
+
static int
w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i = 0, val1 = 0, val2;
- struct i2c_client *new_client;
+ struct i2c_client *client;
+ struct device *dev;
struct w83781d_data *data;
int err;
const char *client_name = "";
@@ -1074,13 +1082,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
goto ERROR1;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
mutex_init(&data->lock);
- new_client->adapter = adapter;
- new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
- new_client->flags = 0;
+ client->adapter = adapter;
+ client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
+ client->flags = 0;
+ dev = &client->dev;
/* Now, we do the remaining detection. */
@@ -1089,20 +1098,18 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
force_*=... parameter, and the Winbond will be reset to the right
bank. */
if (kind < 0) {
- if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) {
- dev_dbg(&new_client->dev, "Detection failed at step "
- "3\n");
+ if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
+ dev_dbg(dev, "Detection failed at step 3\n");
err = -ENODEV;
goto ERROR2;
}
- val1 = w83781d_read_value(new_client, W83781D_REG_BANK);
- val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
+ val1 = w83781d_read_value(client, W83781D_REG_BANK);
+ val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
/* Check for Winbond or Asus ID if in bank 0 */
if ((!(val1 & 0x07)) &&
(((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
|| ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
- dev_dbg(&new_client->dev, "Detection failed at step "
- "4\n");
+ dev_dbg(dev, "Detection failed at step 4\n");
err = -ENODEV;
goto ERROR2;
}
@@ -1111,9 +1118,8 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
((val1 & 0x80) && (val2 == 0x5c)))) {
if (w83781d_read_value
- (new_client, W83781D_REG_I2C_ADDR) != address) {
- dev_dbg(&new_client->dev, "Detection failed "
- "at step 5\n");
+ (client, W83781D_REG_I2C_ADDR) != address) {
+ dev_dbg(dev, "Detection failed at step 5\n");
err = -ENODEV;
goto ERROR2;
}
@@ -1122,27 +1128,26 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
/* We have either had a force parameter, or we have already detected the
Winbond. Put it now into bank 0 and Vendor ID High Byte */
- w83781d_write_value(new_client, W83781D_REG_BANK,
- (w83781d_read_value(new_client,
- W83781D_REG_BANK) & 0x78) |
- 0x80);
+ w83781d_write_value(client, W83781D_REG_BANK,
+ (w83781d_read_value(client, W83781D_REG_BANK)
+ & 0x78) | 0x80);
/* Determine the chip type. */
if (kind <= 0) {
/* get vendor ID */
- val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
+ val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
if (val2 == 0x5c)
vendid = winbond;
else if (val2 == 0x12)
vendid = asus;
else {
- dev_dbg(&new_client->dev, "Chip was made by neither "
+ dev_dbg(dev, "Chip was made by neither "
"Winbond nor Asus?\n");
err = -ENODEV;
goto ERROR2;
}
- val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID);
+ val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
kind = w83781d;
else if (val1 == 0x30 && vendid == winbond)
@@ -1156,7 +1161,7 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
kind = as99127f;
else {
if (kind == 0)
- dev_warn(&new_client->dev, "Ignoring 'force' "
+ dev_warn(dev, "Ignoring 'force' "
"parameter for unknown chip at "
"adapter %d, address 0x%02x\n",
i2c_adapter_id(adapter), address);
@@ -1178,20 +1183,20 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Fill in the remaining client fields and put into the global list */
- strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+ strlcpy(client->name, client_name, I2C_NAME_SIZE);
data->type = kind;
data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto ERROR2;
/* attach secondary i2c lm75-like clients */
if (!is_isa) {
if ((err = w83781d_detect_subclients(adapter, address,
- kind, new_client)))
+ kind, client)))
goto ERROR3;
} else {
data->lm75[0] = NULL;
@@ -1199,11 +1204,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Initialize the chip */
- w83781d_init_client(new_client);
+ w83781d_init_client(client);
/* A few vars need to be filled upon startup */
for (i = 1; i <= 3; i++) {
- data->fan_min[i - 1] = w83781d_read_value(new_client,
+ data->fan_min[i - 1] = w83781d_read_value(client,
W83781D_REG_FAN_MIN(i));
}
if (kind != w83781d && kind != as99127f)
@@ -1211,65 +1216,68 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
data->pwmenable[i] = 1;
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
goto ERROR4;
- }
- device_create_file_in(new_client, 0);
- if (kind != w83783s)
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev, &dev_attr_in1_input))
+ || (err = device_create_file(dev, &dev_attr_in1_min))
+ || (err = device_create_file(dev, &dev_attr_in1_max)))
+ goto ERROR4;
+ }
if (kind != as99127f && kind != w83781d && kind != w83783s) {
- device_create_file_in(new_client, 7);
- device_create_file_in(new_client, 8);
+ if ((err = device_create_file(dev, &dev_attr_in7_input))
+ || (err = device_create_file(dev, &dev_attr_in7_min))
+ || (err = device_create_file(dev, &dev_attr_in7_max))
+ || (err = device_create_file(dev, &dev_attr_in8_input))
+ || (err = device_create_file(dev, &dev_attr_in8_min))
+ || (err = device_create_file(dev, &dev_attr_in8_max)))
+ goto ERROR4;
+ }
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev, &dev_attr_temp3_input))
+ || (err = device_create_file(dev, &dev_attr_temp3_max))
+ || (err = device_create_file(dev,
+ &dev_attr_temp3_max_hyst)))
+ goto ERROR4;
}
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- if (kind != w83783s)
- device_create_file_temp(new_client, 3);
-
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
-
- device_create_file_fan_div(new_client, 1);
- device_create_file_fan_div(new_client, 2);
- device_create_file_fan_div(new_client, 3);
-
- device_create_file_alarms(new_client);
-
- device_create_file_beep(new_client);
if (kind != w83781d && kind != as99127f) {
- device_create_file_pwm(new_client, 1);
- device_create_file_pwm(new_client, 2);
- device_create_file_pwmenable(new_client, 2);
+ if ((err = device_create_file(dev, &dev_attr_pwm1))
+ || (err = device_create_file(dev, &dev_attr_pwm2))
+ || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
+ goto ERROR4;
}
if (kind == w83782d && !is_isa) {
- device_create_file_pwm(new_client, 3);
- device_create_file_pwm(new_client, 4);
+ if ((err = device_create_file(dev, &dev_attr_pwm3))
+ || (err = device_create_file(dev, &dev_attr_pwm4)))
+ goto ERROR4;
}
if (kind != as99127f && kind != w83781d) {
- device_create_file_sensor(new_client, 1);
- device_create_file_sensor(new_client, 2);
- if (kind != w83783s)
- device_create_file_sensor(new_client, 3);
+ if ((err = device_create_file(dev, &dev_attr_temp1_type))
+ || (err = device_create_file(dev,
+ &dev_attr_temp2_type)))
+ goto ERROR4;
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev,
+ &dev_attr_temp3_type)))
+ goto ERROR4;
+ }
+ }
+
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
}
return 0;
ERROR4:
+ sysfs_remove_group(&dev->kobj, &w83781d_group);
+ sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
+
if (data->lm75[1]) {
i2c_detach_client(data->lm75[1]);
kfree(data->lm75[1]);
@@ -1279,7 +1287,7 @@ ERROR4:
kfree(data->lm75[0]);
}
ERROR3:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
ERROR2:
kfree(data);
ERROR1:
@@ -1296,9 +1304,11 @@ w83781d_detach_client(struct i2c_client *client)
int err;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
-
+ sysfs_remove_group(&client->dev.kobj, &w83781d_group);
+ sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
+ }
if (i2c_is_isa_client(client))
release_region(client->addr, W83781D_EXTENT);
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index eec43abd57f..d965d074cd6 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -27,9 +27,9 @@
The w83791d chip appears to be part way between the 83781d and the
83792d. Thus, this file is derived from both the w83792d.c and
- w83781d.c files, but its output is more along the lines of the
- 83781d (which means there are no changes to the user-mode sensors
- program which treats the 83791d as an 83781d).
+ w83781d.c files.
+
+ The w83791g chip is the same as the w83791d but lead-free.
*/
#include <linux/config.h>
@@ -1172,6 +1172,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
(w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
(w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
+ /* Extract global beep enable flag */
data->beep_enable =
(data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 4ef884c216e..4e108262576 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -35,7 +35,6 @@
w83792d 9 7 7 3 0x7a 0x5ca3 yes no
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -44,6 +43,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
@@ -382,41 +382,6 @@ static ssize_t store_in_##reg (struct device *dev, \
store_in_reg(MIN, min);
store_in_reg(MAX, max);
-static struct sensor_device_attribute sda_in_input[] = {
- SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
-};
-static struct sensor_device_attribute sda_in_min[] = {
- SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
- SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
- SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
- SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
- SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
- SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
- SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
- SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
- SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
-};
-static struct sensor_device_attribute sda_in_max[] = {
- SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
- SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
- SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
- SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
- SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
- SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
- SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
- SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
- SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
-};
-
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -463,7 +428,7 @@ show_fan_div(struct device *dev, struct device_attribute *attr,
/* Note: we save and restore the fan minimum here, because its value is
determined in part by the fan divisor. This follows the principle of
- least suprise; the user doesn't expect the fan minimum to change just
+ least surprise; the user doesn't expect the fan minimum to change just
because the divisor changed. */
static ssize_t
store_fan_div(struct device *dev, struct device_attribute *attr,
@@ -500,35 +465,6 @@ store_fan_div(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_fan_input[] = {
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3),
- SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4),
- SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5),
- SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6),
- SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7),
-};
-static struct sensor_device_attribute sda_fan_min[] = {
- SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1),
- SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2),
- SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3),
- SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4),
- SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5),
- SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6),
- SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7),
-};
-static struct sensor_device_attribute sda_fan_div[] = {
- SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1),
- SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2),
- SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3),
- SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4),
- SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5),
- SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6),
- SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7),
-};
-
-
/* read/write the temperature1, includes measured value and limits */
static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
@@ -596,24 +532,6 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_temp_input[] = {
- SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
- SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
- SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
-};
-
-static struct sensor_device_attribute_2 sda_temp_max[] = {
- SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1),
- SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2),
- SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2),
-};
-
-static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
- SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2),
- SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4),
- SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4),
-};
-
/* get reatime status of all sensors items: voltage, temp, fan */
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -622,9 +540,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%d\n", data->alarms);
}
-static
-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -716,21 +631,6 @@ store_pwmenable(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_pwm[] = {
- SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
- SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
- SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
-};
-static struct sensor_device_attribute sda_pwm_enable[] = {
- SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
- show_pwmenable, store_pwmenable, 1),
- SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
- show_pwmenable, store_pwmenable, 2),
- SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
- show_pwmenable, store_pwmenable, 3),
-};
-
-
static ssize_t
show_pwm_mode(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -768,16 +668,6 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_pwm_mode[] = {
- SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 0),
- SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 1),
- SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 2),
-};
-
-
static ssize_t
show_regs_chassis(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -786,8 +676,6 @@ show_regs_chassis(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", data->chassis);
}
-static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
-
static ssize_t
show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -816,9 +704,6 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
- show_chassis_clear, store_chassis_clear);
-
/* For Smart Fan I / Thermal Cruise */
static ssize_t
show_thermal_cruise(struct device *dev, struct device_attribute *attr,
@@ -854,15 +739,6 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_thermal_cruise[] = {
- SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
- show_thermal_cruise, store_thermal_cruise, 1),
- SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
- show_thermal_cruise, store_thermal_cruise, 2),
- SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
- show_thermal_cruise, store_thermal_cruise, 3),
-};
-
/* For Smart Fan I/Thermal Cruise and Smart Fan II */
static ssize_t
show_tolerance(struct device *dev, struct device_attribute *attr,
@@ -902,15 +778,6 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_tolerance[] = {
- SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO,
- show_tolerance, store_tolerance, 1),
- SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO,
- show_tolerance, store_tolerance, 2),
- SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO,
- show_tolerance, store_tolerance, 3),
-};
-
/* For Smart Fan II */
static ssize_t
show_sf2_point(struct device *dev, struct device_attribute *attr,
@@ -947,36 +814,6 @@ store_sf2_point(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_sf2_point[] = {
- SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 1, 1),
- SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 2, 1),
- SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 3, 1),
- SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 4, 1),
-
- SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 1, 2),
- SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 2, 2),
- SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 3, 2),
- SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 4, 2),
-
- SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 1, 3),
- SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 2, 3),
- SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 3, 3),
- SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 4, 3),
-};
-
-
static ssize_t
show_sf2_level(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1017,29 +854,6 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_sf2_level[] = {
- SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 1, 1),
- SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 2, 1),
- SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 3, 1),
-
- SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 1, 2),
- SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 2, 2),
- SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 3, 2),
-
- SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 1, 3),
- SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 2, 3),
- SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 3, 3),
-};
-
/* This function is called when:
* w83792d_driver is inserted (when this module is loaded), for each
available adapter
@@ -1140,12 +954,297 @@ ERROR_SC_0:
return err;
}
-static void device_create_file_fan(struct device *dev, int i)
-{
- device_create_file(dev, &sda_fan_input[i].dev_attr);
- device_create_file(dev, &sda_fan_div[i].dev_attr);
- device_create_file(dev, &sda_fan_min[i].dev_attr);
-}
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+ show_temp1, store_temp1, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23,
+ store_temp23, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23,
+ store_temp23, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp1, store_temp1, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 0, 4);
+static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 1, 4);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
+static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
+ show_chassis_clear, store_chassis_clear);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ show_pwmenable, store_pwmenable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+ show_pwmenable, store_pwmenable, 2);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+ show_pwmenable, store_pwmenable, 3);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
+ show_pwm_mode, store_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
+ show_pwm_mode, store_pwm_mode, 1);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
+ show_pwm_mode, store_pwm_mode, 2);
+static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 1);
+static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 2);
+static SENSOR_DEVICE_ATTR(tolerance3, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 3);
+static SENSOR_DEVICE_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
+ show_thermal_cruise, store_thermal_cruise, 1);
+static SENSOR_DEVICE_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
+ show_thermal_cruise, store_thermal_cruise, 2);
+static SENSOR_DEVICE_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
+ show_thermal_cruise, store_thermal_cruise, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 1, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 2, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 3, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 4, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 1, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 2, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 3, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 4, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 1, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 2, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 3, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 4, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 1, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 2, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 3, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 1, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 2, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 3, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 1, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 2, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 3, 3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 7);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 2);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 3);
+static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 4);
+static SENSOR_DEVICE_ATTR(fan5_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 5);
+static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 6);
+static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 7);
+
+static struct attribute *w83792d_attributes_fan[4][4] = {
+ {
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_div.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_div.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_min.dev_attr.attr,
+ &sensor_dev_attr_fan6_div.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_min.dev_attr.attr,
+ &sensor_dev_attr_fan7_div.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group w83792d_group_fan[4] = {
+ { .attrs = w83792d_attributes_fan[0] },
+ { .attrs = w83792d_attributes_fan[1] },
+ { .attrs = w83792d_attributes_fan[2] },
+ { .attrs = w83792d_attributes_fan[3] },
+};
+
+static struct attribute *w83792d_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm3_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_chassis.attr,
+ &dev_attr_chassis_clear.attr,
+ &sensor_dev_attr_tolerance1.dev_attr.attr,
+ &sensor_dev_attr_thermal_cruise1.dev_attr.attr,
+ &sensor_dev_attr_tolerance2.dev_attr.attr,
+ &sensor_dev_attr_thermal_cruise2.dev_attr.attr,
+ &sensor_dev_attr_tolerance3.dev_attr.attr,
+ &sensor_dev_attr_thermal_cruise3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point1_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point2_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point3_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point4_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point1_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point2_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point3_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point4_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point1_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point2_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point3_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point4_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_level1_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_level2_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_level3_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_level1_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_level2_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_level3_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_level1_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_level2_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_level3_fan3.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group w83792d_group = {
+ .attrs = w83792d_attributes,
+};
static int
w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -1269,59 +1368,46 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&dev->kobj, &w83792d_group)))
goto ERROR3;
- }
- for (i = 0; i < 9; i++) {
- device_create_file(dev, &sda_in_input[i].dev_attr);
- device_create_file(dev, &sda_in_max[i].dev_attr);
- device_create_file(dev, &sda_in_min[i].dev_attr);
- }
- for (i = 0; i < 3; i++)
- device_create_file_fan(dev, i);
/* Read GPIO enable register to check if pins for fan 4,5 are used as
GPIO */
val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN);
+
if (!(val1 & 0x40))
- device_create_file_fan(dev, 3);
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[0])))
+ goto exit_remove_files;
+
if (!(val1 & 0x20))
- device_create_file_fan(dev, 4);
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[1])))
+ goto exit_remove_files;
val1 = w83792d_read_value(client, W83792D_REG_PIN);
if (val1 & 0x40)
- device_create_file_fan(dev, 5);
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[2])))
+ goto exit_remove_files;
+
if (val1 & 0x04)
- device_create_file_fan(dev, 6);
-
- for (i = 0; i < 3; i++) {
- device_create_file(dev, &sda_temp_input[i].dev_attr);
- device_create_file(dev, &sda_temp_max[i].dev_attr);
- device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
- device_create_file(dev, &sda_thermal_cruise[i].dev_attr);
- device_create_file(dev, &sda_tolerance[i].dev_attr);
- }
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[3])))
+ goto exit_remove_files;
- for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) {
- device_create_file(dev, &sda_pwm[i].dev_attr);
- device_create_file(dev, &sda_pwm_enable[i].dev_attr);
- device_create_file(dev, &sda_pwm_mode[i].dev_attr);
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
- device_create_file(dev, &dev_attr_alarms);
- device_create_file(dev, &dev_attr_chassis);
- device_create_file(dev, &dev_attr_chassis_clear);
-
- for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++)
- device_create_file(dev, &sda_sf2_point[i].dev_attr);
-
- for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++)
- device_create_file(dev, &sda_sf2_level[i].dev_attr);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&dev->kobj, &w83792d_group);
+ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+ sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
ERROR3:
if (data->lm75[0] != NULL) {
i2c_detach_client(data->lm75[0]);
@@ -1343,11 +1429,16 @@ static int
w83792d_detach_client(struct i2c_client *client)
{
struct w83792d_data *data = i2c_get_clientdata(client);
- int err;
+ int err, i;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83792d_group);
+ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+ sysfs_remove_group(&client->dev.kobj,
+ &w83792d_group_fan[i]);
+ }
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 3f2bac125fb..a3fcace412f 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -236,21 +236,30 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
* Nothing yet, assume it is already started.
*/
+ err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ if (err)
+ goto exit_remove;
+
/* Register sysfs hooks */
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
-
return 0;
-exit_detach:
+exit_remove:
+ device_remove_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
i2c_detach_client(new_client);
exit_free:
kfree(data);
@@ -264,7 +273,10 @@ static int w83l785ts_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
-
+ device_remove_file(&client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 24383afdda7..11935f66fcd 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -1,5 +1,5 @@
#
-# Character device configuration
+# I2C subsystem configuration
#
menu "I2C support"
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index 30408015d23..c034820615b 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -53,12 +53,6 @@ config I2C_ALGO8XX
tristate "MPC8xx CPM I2C interface"
depends on 8xx && I2C
-config I2C_ALGO_SIBYTE
- tristate "SiByte SMBus interface"
- depends on SIBYTE_SB1xxx_SOC && I2C
- help
- Supports the SiByte SOC on-chip I2C interfaces (2 channels).
-
config I2C_ALGO_SGI
tristate "I2C SGI interfaces"
depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index 867fe1f6740..208be04a3db 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
-obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o
obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index df05df1a0ef..21c36bfb5e6 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -76,17 +76,15 @@ static inline void scllo(struct i2c_algo_bit_data *adap)
* Raise scl line, and do checking for delays. This is necessary for slower
* devices.
*/
-static inline int sclhi(struct i2c_algo_bit_data *adap)
+static int sclhi(struct i2c_algo_bit_data *adap)
{
unsigned long start;
setscl(adap,1);
/* Not all adapters have scl sense line... */
- if (adap->getscl == NULL ) {
- udelay(adap->udelay);
- return 0;
- }
+ if (!adap->getscl)
+ goto done;
start=jiffies;
while (! getscl(adap) ) {
@@ -101,6 +99,8 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
cond_resched();
}
DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
+
+done:
udelay(adap->udelay);
return 0;
}
@@ -121,7 +121,6 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap)
DEBPROTO(printk(" Sr "));
setsda(adap,1);
sclhi(adap);
- udelay(adap->udelay);
sdalo(adap);
scllo(adap);
@@ -306,7 +305,7 @@ bailout:
* 0 chip did not answer
* -x transmission error
*/
-static inline int try_address(struct i2c_adapter *i2c_adap,
+static int try_address(struct i2c_adapter *i2c_adap,
unsigned char addr, int retries)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
@@ -354,15 +353,11 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
return (retval<0)? retval : -EFAULT;
/* got a better one ?? */
}
-#if 0
- /* from asm/delay.h */
- __delay(adap->mdelay * (loops_per_sec / 1000) );
-#endif
}
return wrcount;
}
-static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int inval;
int rdcount=0; /* counts bytes read */
@@ -372,7 +367,6 @@ static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
while (count > 0) {
inval = i2c_inb(i2c_adap);
-/*printk("%#02x ",inval); if ( ! (count % 16) ) printk("\n"); */
if (inval>=0) {
*temp = inval;
rdcount++;
@@ -413,7 +407,7 @@ static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
* -x an error occurred (like: -EREMOTEIO if the device did not answer, or
* -ETIMEDOUT, for example if the lines are stuck...)
*/
-static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
unsigned short flags = msg->flags;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
@@ -518,7 +512,7 @@ static u32 bit_func(struct i2c_adapter *adap)
/* -----exported algorithm data: ------------------------------------- */
-static struct i2c_algorithm i2c_bit_algo = {
+static const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
@@ -544,8 +538,7 @@ int i2c_bit_add_bus(struct i2c_adapter *adap)
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
- i2c_add_adapter(adap);
- return 0;
+ return i2c_add_adapter(adap);
}
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
index 2db7bfc8522..70d8eefb5ef 100644
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -742,10 +742,8 @@ int i2c_iic_add_bus(struct i2c_adapter *adap)
adap->retries = 3; /* be replaced by defines */
adap->flags = 0;
- i2c_add_adapter(adap);
iic_init(iic_adap);
-
- return 0;
+ return i2c_add_adapter(adap);
}
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index 82946acab4c..9081c9fbcd2 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -355,7 +355,7 @@ static int pca_init(struct i2c_algo_pca_data *adap)
return 0;
}
-static struct i2c_algorithm pca_algo = {
+static const struct i2c_algorithm pca_algo = {
.master_xfer = pca_xfer,
.functionality = pca_func,
};
@@ -374,10 +374,10 @@ int i2c_pca_add_bus(struct i2c_adapter *adap)
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
- rval = pca_init(pca_adap);
+ if ((rval = pca_init(pca_adap)))
+ return rval;
- if (!rval)
- i2c_add_adapter(adap);
+ rval = i2c_add_adapter(adap);
return rval;
}
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 6e498df1f71..3b200339896 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -458,7 +458,7 @@ static u32 pcf_func(struct i2c_adapter *adap)
/* -----exported algorithm data: ------------------------------------- */
-static struct i2c_algorithm pcf_algo = {
+static const struct i2c_algorithm pcf_algo = {
.master_xfer = pcf_xfer,
.functionality = pcf_func,
};
@@ -479,9 +479,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap)
adap->timeout = 100; /* default values, should */
adap->retries = 3; /* be replaced by defines */
- rval = pcf_init_8584(pcf_adap);
- if (!rval)
- i2c_add_adapter(adap);
+ if ((rval = pcf_init_8584(pcf_adap)))
+ return rval;
+
+ rval = i2c_add_adapter(adap);
+
return rval;
}
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
index 932c4fa86c7..490d99997fd 100644
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -157,7 +157,7 @@ static u32 sgi_func(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm sgi_algo = {
+static const struct i2c_algorithm sgi_algo = {
.master_xfer = sgi_xfer,
.functionality = sgi_func,
};
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
deleted file mode 100644
index 3df3f09995c..00000000000
--- a/drivers/i2c/algos/i2c-algo-sibyte.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-algo-sibyte.c i2c driver algorithms for bit-shift adapters */
-/* ------------------------------------------------------------------------- */
-/* Copyright (C) 2001,2002,2003 Broadcom Corporation
- Copyright (C) 1995-2000 Simon G. Vogl
-
- 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. */
-/* ------------------------------------------------------------------------- */
-
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl>. */
-
-/* Ported for SiByte SOCs by Broadcom Corporation. */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_smbus.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-sibyte.h>
-
-/* ----- global defines ----------------------------------------------- */
-#define SMB_CSR(a,r) ((long)(a->reg_base + r))
-
-/* ----- global variables --------------------------------------------- */
-
-/* module parameters:
- */
-static int bit_scan; /* have a look at what's hanging 'round */
-
-
-static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data * data)
-{
- struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
- int data_bytes = 0;
- int error;
-
- while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- switch (size) {
- case I2C_SMBUS_QUICK:
- csr_out32((V_SMB_ADDR(addr) | (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
- V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
- break;
- case I2C_SMBUS_BYTE:
- if (read_write == I2C_SMBUS_READ) {
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
- SMB_CSR(adap, R_SMB_START));
- data_bytes = 1;
- } else {
- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
- SMB_CSR(adap, R_SMB_START));
- }
- break;
- case I2C_SMBUS_BYTE_DATA:
- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
- if (read_write == I2C_SMBUS_READ) {
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
- SMB_CSR(adap, R_SMB_START));
- data_bytes = 1;
- } else {
- csr_out32(V_SMB_LB(data->byte), SMB_CSR(adap, R_SMB_DATA));
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
- SMB_CSR(adap, R_SMB_START));
- }
- break;
- case I2C_SMBUS_WORD_DATA:
- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
- if (read_write == I2C_SMBUS_READ) {
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
- SMB_CSR(adap, R_SMB_START));
- data_bytes = 2;
- } else {
- csr_out32(V_SMB_LB(data->word & 0xff), SMB_CSR(adap, R_SMB_DATA));
- csr_out32(V_SMB_MB(data->word >> 8), SMB_CSR(adap, R_SMB_DATA));
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
- SMB_CSR(adap, R_SMB_START));
- }
- break;
- default:
- return -1; /* XXXKW better error code? */
- }
-
- while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
- if (error & M_SMB_ERROR) {
- /* Clear error bit by writing a 1 */
- csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
- return -1; /* XXXKW better error code? */
- }
-
- if (data_bytes == 1)
- data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
- if (data_bytes == 2)
- data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
-
- return 0;
-}
-
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-static u32 bit_func(struct i2c_adapter *adap)
-{
- return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
-}
-
-
-/* -----exported algorithm data: ------------------------------------- */
-
-static struct i2c_algorithm i2c_sibyte_algo = {
- .smbus_xfer = smbus_xfer,
- .algo_control = algo_control, /* ioctl */
- .functionality = bit_func,
-};
-
-/*
- * registering functions to load algorithms at runtime
- */
-int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
-{
- int i;
- struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
-
- /* register new adapter to i2c module... */
- i2c_adap->algo = &i2c_sibyte_algo;
-
- /* Set the frequency to 100 kHz */
- csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
- csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
-
- /* scan bus */
- if (bit_scan) {
- union i2c_smbus_data data;
- int rc;
- printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
- i2c_adap->name);
- for (i = 0x00; i < 0x7f; i++) {
- /* XXXKW is this a realistic probe? */
- rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
- I2C_SMBUS_BYTE_DATA, &data);
- if (!rc) {
- printk("(%02x)",i);
- } else
- printk(".");
- }
- printk("\n");
- }
-
- i2c_add_adapter(i2c_adap);
-
- return 0;
-}
-
-
-int i2c_sibyte_del_bus(struct i2c_adapter *adap)
-{
- int res;
-
- if ((res = i2c_del_adapter(adap)) < 0)
- return res;
-
- return 0;
-}
-
-int __init i2c_algo_sibyte_init (void)
-{
- printk("i2c-algo-sibyte.o: i2c SiByte algorithm module\n");
- return 0;
-}
-
-
-EXPORT_SYMBOL(i2c_sibyte_add_bus);
-EXPORT_SYMBOL(i2c_sibyte_del_bus);
-
-#ifdef MODULE
-MODULE_AUTHOR("Kip Walker, Broadcom Corp.");
-MODULE_DESCRIPTION("SiByte I2C-Bus algorithm");
-module_param(bit_scan, int, 0);
-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
- return i2c_algo_sibyte_init();
-}
-
-void cleanup_module(void)
-{
-}
-#endif
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 884320e7040..0d9667921f6 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -75,11 +75,11 @@ config I2C_AMD8111
will be called i2c-amd8111.
config I2C_AU1550
- tristate "Au1550 SMBus interface"
- depends on I2C && SOC_AU1550
+ tristate "Au1550/Au1200 SMBus interface"
+ depends on I2C && (SOC_AU1550 || SOC_AU1200)
help
If you say yes to this option, support will be included for the
- Au1550 SMBus interface.
+ Au1550 and Au1200 SMBus interface.
This driver can also be built as a module. If so, the module
will be called i2c-au1550.
@@ -196,7 +196,7 @@ config I2C_IBM_IIC
config I2C_IOP3XX
tristate "Intel IOP3xx and IXP4xx on-chip I2C interface"
- depends on (ARCH_IOP3XX || ARCH_IXP4XX) && I2C
+ depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX) && I2C
help
Say Y here if you want to use the IIC bus controller on
the Intel IOP3xx I/O Processors or IXP4xx Network Processors.
@@ -287,6 +287,16 @@ config I2C_OCORES
This driver can also be built as a module. If so, the module
will be called i2c-ocores.
+config I2C_OMAP
+ tristate "OMAP I2C adapter"
+ depends on I2C && ARCH_OMAP
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Texas Instruments OMAP1/2 family of processors.
+ Like OMAP1510/1610/1710/5912 and OMAP242x.
+ For details see http://www.ti.com/omap.
+
config I2C_PARPORT
tristate "Parallel port adapter"
depends on I2C && PARPORT
@@ -482,19 +492,19 @@ config I2C_VIA
will be called i2c-via.
config I2C_VIAPRO
- tristate "VIA 82C596/82C686/823x"
+ tristate "VIA 82C596/82C686/82xx"
depends on I2C && PCI
help
If you say yes to this option, support will be included for the VIA
- 82C596/82C686/823x I2C interfaces. Specifically, the following
+ 82C596/82C686/82xx I2C interfaces. Specifically, the following
chipsets are supported:
- 82C596A/B
- 82C686A/B
- 8231
- 8233
- 8233A
- 8235
- 8237
+ VT82C596A/B
+ VT82C686A/B
+ VT8231
+ VT8233/A
+ VT8235
+ VT8237R/A
+ VT8251
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ac56df53155..493c87289b6 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index d3ef46aeeb3..e75d339a348 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -468,7 +468,7 @@ static u32 ali1535_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = ali1535_access,
.functionality = ali1535_func,
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index e6f63208fc4..33fbb47100a 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -367,7 +367,7 @@ static void ali1563_shutdown(struct pci_dev *dev)
release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
}
-static struct i2c_algorithm ali1563_algorithm = {
+static const struct i2c_algorithm ali1563_algorithm = {
.smbus_xfer = ali1563_access,
.functionality = ali1563_func,
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 7a5c0941dbc..3f11b6e1a34 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -463,7 +463,7 @@ static u32 ali15x3_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = ali15x3_access,
.functionality = ali15x3_func,
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 1750dedaf4b..2d21afdc5b1 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -294,7 +294,7 @@ static u32 amd756_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = amd756_access,
.functionality = amd756_func,
};
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index e5ef560e686..0fbc7186c91 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -316,7 +316,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = amd8111_access,
.functionality = amd8111_func,
};
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index d06edce03bf..d7e7c359fc3 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -34,8 +34,7 @@
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1550.h>
+#include <asm/mach-au1x00/au1xxx.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include "i2c-au1550.h"
@@ -118,13 +117,19 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
/* Reset the FIFOs, clear events.
*/
- sp->psc_smbpcr = PSC_SMBPCR_DC;
+ stat = sp->psc_smbstat;
sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
au_sync();
- do {
- stat = sp->psc_smbpcr;
+
+ if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
+ sp->psc_smbpcr = PSC_SMBPCR_DC;
au_sync();
- } while ((stat & PSC_SMBPCR_DC) != 0);
+ do {
+ stat = sp->psc_smbpcr;
+ au_sync();
+ } while ((stat & PSC_SMBPCR_DC) != 0);
+ udelay(50);
+ }
/* Write out the i2c chip address and specify operation
*/
@@ -279,10 +284,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
static u32
au1550_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm au1550_algo = {
+static const struct i2c_algorithm au1550_algo = {
.master_xfer = au1550_xfer,
.functionality = au1550_func,
};
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 59f8308c235..caa8e5c8bfb 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -196,7 +196,6 @@ static struct i2c_algo_pcf_data pcf_isa_data = {
.getclock = pcf_isa_getclock,
.waitforpin = pcf_isa_waitforpin,
.udelay = 10,
- .mdelay = 10,
.timeout = 100,
};
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index e0cb3b0f92f..457d48a0ab9 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -99,7 +99,6 @@ static struct i2c_algo_bit_data hydra_bit_data = {
.getsda = hydra_bit_getsda,
.getscl = hydra_bit_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = HZ
};
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 3e0d04d5a80..bbb2fbee836 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -434,7 +434,7 @@ static u32 i801_func(struct i2c_adapter *adapter)
| (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = i801_access,
.functionality = i801_func,
};
@@ -488,15 +488,15 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
dev_err(&dev->dev, "SMBus base address uninitialized, "
"upgrade BIOS\n");
err = -ENODEV;
- goto exit_disable;
+ goto exit;
}
err = pci_request_region(dev, SMBBAR, i801_driver.name);
if (err) {
dev_err(&dev->dev, "Failed to request SMBus region "
- "0x%lx-0x%lx\n", i801_smba,
- pci_resource_end(dev, SMBBAR));
- goto exit_disable;
+ "0x%lx-0x%Lx\n", i801_smba,
+ (unsigned long long)pci_resource_end(dev, SMBBAR));
+ goto exit;
}
pci_read_config_byte(I801_dev, SMBHSTCFG, &temp);
@@ -520,11 +520,12 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id
err = i2c_add_adapter(&i801_adapter);
if (err) {
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
- goto exit_disable;
+ goto exit_release;
}
+ return 0;
-exit_disable:
- pci_disable_device(dev);
+exit_release:
+ pci_release_region(dev, SMBBAR);
exit:
return err;
}
@@ -533,7 +534,10 @@ static void __devexit i801_remove(struct pci_dev *dev)
{
i2c_del_adapter(&i801_adapter);
pci_release_region(dev, SMBBAR);
- pci_disable_device(dev);
+ /*
+ * do not call pci_disable_device(dev) since it can cause hard hangs on
+ * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
+ */
}
static struct pci_driver i801_driver = {
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
index 748be30f2ba..b66fb6bb187 100644
--- a/drivers/i2c/busses/i2c-i810.c
+++ b/drivers/i2c/busses/i2c-i810.c
@@ -166,7 +166,6 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = {
.getsda = bit_i810i2c_getsda,
.getscl = bit_i810i2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT,
};
@@ -182,7 +181,6 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = {
.getsda = bit_i810ddc_getsda,
.getscl = bit_i810ddc_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT,
};
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 87fae937e66..5bccb5d6831 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -28,7 +28,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -626,7 +625,7 @@ static u32 iic_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
-static struct i2c_algorithm iic_algo = {
+static const struct i2c_algorithm iic_algo = {
.master_xfer = iic_xfer,
.functionality = iic_func
};
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index d00a02fc23e..4436c89be58 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -21,12 +21,14 @@
* - Make it work with IXP46x chips
* - Cleanup function names, coding style, etc
*
+ * - writing to slave address causes latchup on iop331.
+ * fix: driver refuses to address self.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2.
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -74,26 +76,22 @@ iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
}
static void
-iop3xx_i2c_set_slave_addr(struct i2c_algo_iop3xx_data *iop3xx_adap)
-{
- __raw_writel(MYSAR, iop3xx_adap->ioaddr + SAR_OFFSET);
-}
-
-static void
iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
{
u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
/*
* Every time unit enable is asserted, GPOD needs to be cleared
- * on IOP321 to avoid data corruption on the bus.
+ * on IOP3XX to avoid data corruption on the bus.
*/
-#ifdef CONFIG_ARCH_IOP321
-#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
-#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
-
- *IOP321_GPOD &= (iop3xx_adap->id == 0) ? ~IOP321_GPOD_I2C0 :
- ~IOP321_GPOD_I2C1;
+#ifdef CONFIG_PLAT_IOP
+ if (iop3xx_adap->id == 0) {
+ gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+ } else {
+ gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+ }
#endif
/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->SR_enabled =
@@ -249,6 +247,13 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
int status;
int rc;
+ /* avoid writing to my slave address (hangs on 80331),
+ * forbidden in Intel developer manual
+ */
+ if (msg->addr == MYSAR) {
+ return -EBUSY;
+ }
+
__raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
@@ -398,7 +403,7 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm iop3xx_i2c_algo = {
+static const struct i2c_algorithm iop3xx_i2c_algo = {
.master_xfer = iop3xx_i2c_master_xfer,
.algo_control = iop3xx_i2c_algo_control,
.functionality = iop3xx_i2c_func,
@@ -499,7 +504,6 @@ iop3xx_i2c_probe(struct platform_device *pdev)
spin_lock_init(&adapter_data->lock);
iop3xx_i2c_reset(adapter_data);
- iop3xx_i2c_set_slave_addr(adapter_data);
iop3xx_i2c_enable(adapter_data);
platform_set_drvdata(pdev, new_adapter);
diff --git a/drivers/i2c/busses/i2c-iop3xx.h b/drivers/i2c/busses/i2c-iop3xx.h
index e46ebaea7b1..8485861f6a3 100644
--- a/drivers/i2c/busses/i2c-iop3xx.h
+++ b/drivers/i2c/busses/i2c-iop3xx.h
@@ -80,7 +80,7 @@
#define IOP3XX_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
#define IOP3XX_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
-#define MYSAR 0x02 /* SWAG a suitable slave address */
+#define MYSAR 0 /* default slave address */
#define I2C_ERR 321
#define I2C_ERR_BERR (I2C_ERR+0)
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index c3e1d3e888d..4380653748a 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -43,7 +43,7 @@
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
-static struct i2c_algorithm isa_algorithm = {
+static const struct i2c_algorithm isa_algorithm = {
.functionality = isa_func,
};
@@ -89,9 +89,14 @@ int i2c_isa_add_driver(struct i2c_driver *driver)
dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
/* Now look for clients */
- driver->attach_adapter(&isa_adapter);
-
- return 0;
+ res = driver->attach_adapter(&isa_adapter);
+ if (res) {
+ dev_err(&isa_adapter.dev,
+ "Driver %s failed to attach adapter, unregistering\n",
+ driver->driver.name);
+ driver_unregister(&driver->driver);
+ }
+ return res;
}
int i2c_isa_del_driver(struct i2c_driver *driver)
@@ -125,6 +130,8 @@ int i2c_isa_del_driver(struct i2c_driver *driver)
static int __init i2c_isa_init(void)
{
+ int err;
+
mutex_init(&isa_adapter.clist_lock);
INIT_LIST_HEAD(&isa_adapter.clients);
@@ -133,8 +140,16 @@ static int __init i2c_isa_init(void)
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
isa_adapter.dev.driver = &i2c_adapter_driver;
isa_adapter.dev.release = &i2c_adapter_dev_release;
- device_register(&isa_adapter.dev);
- device_create_file(&isa_adapter.dev, &dev_attr_name);
+ err = device_register(&isa_adapter.dev);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to register device\n");
+ goto exit;
+ }
+ err = device_create_file(&isa_adapter.dev, &dev_attr_name);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to create name file\n");
+ goto exit_unregister;
+ }
/* Add this adapter to the i2c_adapter class */
memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
@@ -142,11 +157,24 @@ static int __init i2c_isa_init(void)
isa_adapter.class_dev.class = &i2c_adapter_class;
strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
BUS_ID_SIZE);
- class_device_register(&isa_adapter.class_dev);
+ err = class_device_register(&isa_adapter.class_dev);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to register class device\n");
+ goto exit_remove_name;
+ }
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
return 0;
+
+exit_remove_name:
+ device_remove_file(&isa_adapter.dev, &dev_attr_name);
+exit_unregister:
+ init_completion(&isa_adapter.dev_released); /* Needed? */
+ device_unregister(&isa_adapter.dev);
+ wait_for_completion(&isa_adapter.dev_released);
+exit:
+ return err;
}
static void __exit i2c_isa_exit(void)
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index cd6f45d186a..dd3f4cd3aa6 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -114,7 +114,6 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
drv_data->algo_data.getsda = ixp2000_bit_getsda;
drv_data->algo_data.getscl = ixp2000_bit_getscl;
drv_data->algo_data.udelay = 6;
- drv_data->algo_data.mdelay = 6;
drv_data->algo_data.timeout = 100;
drv_data->adapter.id = I2C_HW_B_IXP2000,
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 2ed07112d68..ab573254a8a 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -122,7 +122,6 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
drv_data->algo_data.getsda = ixp4xx_bit_getsda;
drv_data->algo_data.getscl = ixp4xx_bit_getscl;
drv_data->algo_data.udelay = 10;
- drv_data->algo_data.mdelay = 10;
drv_data->algo_data.timeout = 100;
drv_data->adapter.id = I2C_HW_B_IXP4XX;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 2721e4c8184..155a986de51 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -13,7 +13,6 @@
* warranty of any kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -273,7 +272,7 @@ static u32 mpc_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm mpc_algo = {
+static const struct i2c_algorithm mpc_algo = {
.master_xfer = mpc_xfer,
.functionality = mpc_functionality,
};
@@ -319,7 +318,7 @@ static int fsl_i2c_probe(struct platform_device *pdev)
if (i2c->irq != 0)
if ((result = request_irq(i2c->irq, mpc_i2c_isr,
- SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
+ IRQF_SHARED, "i2c-mpc", i2c)) < 0) {
printk(KERN_ERR
"i2c-mpc - failed to attach interrupt\n");
goto fail_irq;
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index ac5cde1bbd2..eacbaf745b6 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -431,7 +431,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return num;
}
-static struct i2c_algorithm mv64xxx_i2c_algo = {
+static const struct i2c_algorithm mv64xxx_i2c_algo = {
.master_xfer = mv64xxx_i2c_xfer,
.functionality = mv64xxx_i2c_functionality,
};
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 604b49e22df..e0292e414ab 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -109,7 +109,7 @@ static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
static u32 nforce2_func(struct i2c_adapter *adapter);
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = nforce2_access,
.functionality = nforce2_func,
};
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 592824087c4..952a28d485c 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -199,7 +199,7 @@ static u32 ocores_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm ocores_algorithm = {
+static const struct i2c_algorithm ocores_algorithm = {
.master_xfer = ocores_xfer,
.functionality = ocores_func,
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
new file mode 100644
index 00000000000..81d87d2c2a2
--- /dev/null
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -0,0 +1,676 @@
+/*
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Updated to work with multiple I2C interfaces on 24xx by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Cleaned up by Juha Yrjölä <juha.yrjola@nokia.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.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+#define OMAP_I2C_REV_REG 0x00
+#define OMAP_I2C_IE_REG 0x04
+#define OMAP_I2C_STAT_REG 0x08
+#define OMAP_I2C_IV_REG 0x0c
+#define OMAP_I2C_SYSS_REG 0x10
+#define OMAP_I2C_BUF_REG 0x14
+#define OMAP_I2C_CNT_REG 0x18
+#define OMAP_I2C_DATA_REG 0x1c
+#define OMAP_I2C_SYSC_REG 0x20
+#define OMAP_I2C_CON_REG 0x24
+#define OMAP_I2C_OA_REG 0x28
+#define OMAP_I2C_SA_REG 0x2c
+#define OMAP_I2C_PSC_REG 0x30
+#define OMAP_I2C_SCLL_REG 0x34
+#define OMAP_I2C_SCLH_REG 0x38
+#define OMAP_I2C_SYSTEST_REG 0x3c
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+#endif
+
+/* I2C System Status register (OMAP_I2C_SYSS): */
+#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
+
+/* I2C System Configuration Register (OMAP_I2C_SYSC): */
+#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+
+/* REVISIT: Use platform_data instead of module parameters */
+/* Fast Mode = 400 kHz, Standard = 100 kHz */
+static int clock = 100; /* Default: 100 kHz */
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
+
+struct omap_i2c_dev {
+ struct device *dev;
+ void __iomem *base; /* virtual */
+ int irq;
+ struct clk *iclk; /* Interface clock */
+ struct clk *fclk; /* Functional clock */
+ struct completion cmd_complete;
+ struct resource *ioarea;
+ u16 cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ unsigned rev1:1;
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+{
+ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ dev->iclk = clk_get(dev->dev, "i2c_ick");
+ if (IS_ERR(dev->iclk)) {
+ dev->iclk = NULL;
+ return -ENODEV;
+ }
+ }
+
+ dev->fclk = clk_get(dev->dev, "i2c_fck");
+ if (IS_ERR(dev->fclk)) {
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+ dev->fclk = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
+{
+ clk_put(dev->fclk);
+ dev->fclk = NULL;
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+}
+
+static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_enable(dev->iclk);
+ clk_enable(dev->fclk);
+}
+
+static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_disable(dev->iclk);
+ clk_disable(dev->fclk);
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+ u16 psc = 0;
+ unsigned long fclk_rate = 12000000;
+ unsigned long timeout;
+
+ if (!dev->rev1) {
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+ /* For some reason we need to set the EN bit before the
+ * reset done bit gets set. */
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+ OMAP_I2C_SYSS_RDONE)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting"
+ "for controller reset\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+ if (cpu_class_is_omap1()) {
+ struct clk *armxor_ck;
+
+ armxor_ck = clk_get(NULL, "armxor_ck");
+ if (IS_ERR(armxor_ck))
+ dev_warn(dev->dev, "Could not get armxor_ck\n");
+ else {
+ fclk_rate = clk_get_rate(armxor_ck);
+ clk_put(armxor_ck);
+ }
+ /* TRM for 5912 says the I2C clock must be prescaled to be
+ * between 7 - 12 MHz. The XOR input clock is typically
+ * 12, 13 or 19.2 MHz. So we should have code that produces:
+ *
+ * XOR MHz Divider Prescaler
+ * 12 1 0
+ * 13 2 1
+ * 19.2 2 1
+ */
+ if (fclk_rate > 16000000)
+ psc = (fclk_rate + 8000000) / 12000000;
+ }
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+ /* Enable interrupts */
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
+ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL));
+ return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int r;
+ u16 w;
+
+ dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+ if (stop)
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ omap_i2c_init(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (likely(!dev->cmd_err))
+ return 0;
+
+ /* We have an error */
+ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+ OMAP_I2C_STAT_XUDF)) {
+ omap_i2c_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int r;
+
+ omap_i2c_enable_clocks(dev);
+
+ /* REVISIT: initialize and use adap->retries. This is an optional
+ * feature */
+ if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+ goto out;
+
+ for (i = 0; i < num; i++) {
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (r == 0)
+ r = num;
+out:
+ omap_i2c_disable_clocks(dev);
+ return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
+{
+ dev->cmd_err |= err;
+ complete(&dev->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
+{
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+}
+
+static irqreturn_t
+omap_i2c_rev1_isr(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 iv, w;
+
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x00: /* None */
+ break;
+ case 0x01: /* Arbitration lost */
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ break;
+ case 0x03: /* Register access ready */
+ omap_i2c_complete_cmd(dev, 0);
+ break;
+ case 0x04: /* Receive data ready */
+ if (dev->buf_len) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+ break;
+ case 0x05: /* Transmit data ready */
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+ break;
+ default:
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+omap_i2c_isr(int this_irq, void *dev_id, struct pt_regs *regs)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 bits;
+ u16 stat, w;
+ int count = 0;
+
+ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+ dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+
+ if (stat & OMAP_I2C_STAT_ARDY) {
+ omap_i2c_complete_cmd(dev, 0);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_RRDY) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ if (dev->buf_len) {
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data"
+ "requested\n");
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_XRDY) {
+ w = 0;
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no"
+ "data to send\n");
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err(dev->dev, "Receive overrun\n");
+ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ }
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err(dev->dev, "Transmit overflow\n");
+ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ }
+ if (stat & OMAP_I2C_STAT_NACK) {
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
+ }
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static int
+omap_i2c_probe(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ if (clock > 200)
+ clock = 400; /* Fast mode */
+ else
+ clock = 100; /* Standard mode */
+
+ dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ dev->dev = &pdev->dev;
+ dev->irq = irq->start;
+ dev->base = (void __iomem *) IO_ADDRESS(mem->start);
+ platform_set_drvdata(pdev, dev);
+
+ if ((r = omap_i2c_get_clocks(dev)) != 0)
+ goto err_free_mem;
+
+ omap_i2c_enable_clocks(dev);
+
+ if (cpu_is_omap15xx())
+ dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_init(dev);
+
+ r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
+ 0, pdev->name, dev);
+
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+ r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
+ pdev->id, r >> 4, r & 0xf, clock);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ r = i2c_add_adapter(adap);
+ if (r) {
+ dev_err(dev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ omap_i2c_disable_clocks(dev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ omap_i2c_disable_clocks(dev);
+ omap_i2c_put_clocks(dev);
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+err_release_region:
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int
+omap_i2c_remove(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_irq(dev->irq, dev);
+ i2c_del_adapter(&dev->adapter);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ omap_i2c_put_clocks(dev);
+ kfree(dev);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver omap_i2c_driver = {
+ .probe = omap_i2c_probe,
+ .remove = omap_i2c_remove,
+ .driver = {
+ .name = "i2c_omap",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+ return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index e09ebbb2f9f..5eb2bd294fd 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -103,7 +103,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 50,
- .mdelay = 50,
.timeout = HZ,
};
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 934bd55bae1..48a829431c7 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -138,7 +138,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 60,
- .mdelay = 60,
.timeout = HZ,
};
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 8f2f65b793b..30c7a1b38cb 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -376,7 +376,7 @@ static u32 piix4_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = piix4_access,
.functionality = piix4_func,
};
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index df786eb5529..a508cb962d2 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -20,7 +20,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -149,8 +148,6 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
- if (num != 1)
- return -EINVAL;
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
@@ -167,7 +164,7 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len);
bail:
pmac_i2c_close(bus);
- return rc < 0 ? rc : msgs->len;
+ return rc < 0 ? rc : 1;
}
static u32 i2c_powermac_func(struct i2c_adapter * adapter)
@@ -178,7 +175,7 @@ static u32 i2c_powermac_func(struct i2c_adapter * adapter)
}
/* For now, we only handle smbus */
-static struct i2c_algorithm i2c_powermac_algorithm = {
+static const struct i2c_algorithm i2c_powermac_algorithm = {
.smbus_xfer = i2c_powermac_smbus_xfer,
.master_xfer = i2c_powermac_master_xfer,
.functionality = i2c_powermac_func,
@@ -210,7 +207,8 @@ static int i2c_powermac_probe(struct device *dev)
struct pmac_i2c_bus *bus = dev->platform_data;
struct device_node *parent = NULL;
struct i2c_adapter *adapter;
- char name[32], *basename;
+ char name[32];
+ const char *basename;
int rc;
if (bus == NULL)
diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
index 9479525892e..7745e21874a 100644
--- a/drivers/i2c/busses/i2c-prosavage.c
+++ b/drivers/i2c/busses/i2c-prosavage.c
@@ -180,7 +180,6 @@ static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iom
p->algo.getsda = bit_s3via_getsda;
p->algo.getscl = bit_s3via_getscl;
p->algo.udelay = CYCLE_DELAY;
- p->algo.mdelay = CYCLE_DELAY;
p->algo.timeout = TIMEOUT;
p->algo.data = p;
p->mmvga = mmvga;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 5155010b455..cd4ad98ad51 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -926,7 +926,7 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm i2c_pxa_algorithm = {
+static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer = i2c_pxa_xfer,
.functionality = i2c_pxa_functionality,
};
@@ -968,7 +968,7 @@ static int i2c_pxa_probe(struct platform_device *dev)
#endif
pxa_set_cken(CKEN14_I2C, 1);
- ret = request_irq(IRQ_I2C, i2c_pxa_handler, SA_INTERRUPT,
+ ret = request_irq(IRQ_I2C, i2c_pxa_handler, IRQF_DISABLED,
"pxa2xx-i2c", i2c);
if (ret)
goto out;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index f7d40f8e5f5..9ebe429a0a0 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -20,7 +20,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -567,7 +566,7 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
/* i2c bus registration info */
-static struct i2c_algorithm s3c24xx_i2c_algorithm = {
+static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
@@ -829,7 +828,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
goto out;
}
- ret = request_irq(res->start, s3c24xx_i2c_irq, SA_INTERRUPT,
+ ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED,
pdev->name, i2c);
if (ret != 0) {
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index 0c8518298e4..209f47ea175 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -140,7 +140,6 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = {
.getsda = bit_savi2c_getsda,
.getscl = bit_savi2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
index fa503ed9f86..0ca599d3b40 100644
--- a/drivers/i2c/busses/i2c-sibyte.c
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2004 Steven J. Hill
* Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 1995-2000 Simon G. Vogl
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -17,11 +18,162 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c-algo-sibyte.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_smbus.h>
+
+struct i2c_algo_sibyte_data {
+ void *data; /* private data */
+ int bus; /* which bus */
+ void *reg_base; /* CSR base */
+};
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+/* ----- global variables --------------------------------------------- */
+
+/* module parameters:
+ */
+static int bit_scan; /* have a look at what's hanging 'round */
+module_param(bit_scan, int, 0);
+MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+ int data_bytes = 0;
+ int error;
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ csr_out32((V_SMB_ADDR(addr) |
+ (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_LB(data->byte),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 2;
+ } else {
+ csr_out32(V_SMB_LB(data->word & 0xff),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32(V_SMB_MB(data->word >> 8),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ default:
+ return -1; /* XXXKW better error code? */
+ }
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+ if (error & M_SMB_ERROR) {
+ /* Clear error bit by writing a 1 */
+ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+ return -1; /* XXXKW better error code? */
+ }
+
+ if (data_bytes == 1)
+ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+ if (data_bytes == 2)
+ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+ return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm i2c_sibyte_algo = {
+ .smbus_xfer = smbus_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+ int i;
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+ /* register new adapter to i2c module... */
+ i2c_adap->algo = &i2c_sibyte_algo;
+
+ /* Set the frequency to 100 kHz */
+ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+ /* scan bus */
+ if (bit_scan) {
+ union i2c_smbus_data data;
+ int rc;
+ printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
+ i2c_adap->name);
+ for (i = 0x00; i < 0x7f; i++) {
+ /* XXXKW is this a realistic probe? */
+ rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (!rc) {
+ printk("(%02x)",i);
+ } else
+ printk(".");
+ }
+ printk("\n");
+ }
+
+ return i2c_add_adapter(i2c_adap);
+}
+
+
static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
{ NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
{ NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
@@ -58,13 +210,13 @@ static int __init i2c_sibyte_init(void)
static void __exit i2c_sibyte_exit(void)
{
- i2c_sibyte_del_bus(&sibyte_board_adapter[0]);
- i2c_sibyte_del_bus(&sibyte_board_adapter[1]);
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ i2c_del_adapter(&sibyte_board_adapter[1]);
}
module_init(i2c_sibyte_init);
module_exit(i2c_sibyte_exit);
-MODULE_AUTHOR("Kip Walker <kwalker@broadcom.com>, Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index b57ab74d23e..38bbfd840b6 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -358,7 +358,7 @@ static u32 sis5595_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis5595_access,
.functionality = sis5595_func,
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index acb75e28241..dec0bafb52a 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -450,7 +450,7 @@ exit:
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis630_access,
.functionality = sis630_func,
};
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 1a73c0532fc..7fd07fbac33 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -242,7 +242,7 @@ static u32 sis96x_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis96x_access,
.functionality = sis96x_func,
};
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 73f481e93a3..a54adc50d16 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -27,6 +27,10 @@
#include <linux/errno.h>
#include <linux/i2c.h>
+static unsigned short chip_addr;
+module_param(chip_addr, ushort, S_IRUGO);
+MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
+
static u8 stub_pointer;
static u8 stub_bytes[256];
static u16 stub_words[256];
@@ -37,6 +41,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
{
s32 ret;
+ if (addr != chip_addr)
+ return -ENODEV;
+
switch (size) {
case I2C_SMBUS_QUICK:
@@ -108,7 +115,7 @@ static u32 stub_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.functionality = stub_func,
.smbus_xfer = stub_xfer,
};
@@ -122,7 +129,17 @@ static struct i2c_adapter stub_adapter = {
static int __init i2c_stub_init(void)
{
- printk(KERN_INFO "i2c-stub loaded\n");
+ if (!chip_addr) {
+ printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+ return -ENODEV;
+ }
+ if (chip_addr < 0x03 || chip_addr > 0x77) {
+ printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
+ chip_addr);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
return i2c_add_adapter(&stub_adapter);
}
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 484bbacfce6..910e200ad50 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -81,7 +81,6 @@ static struct i2c_algo_bit_data bit_data = {
.getsda = bit_via_getsda,
.getscl = bit_via_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = HZ
};
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 47e52bf2c5e..efc6bbf0cc0 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -34,6 +34,8 @@
VT8233A 0x3147 yes?
VT8235 0x3177 yes
VT8237R 0x3227 yes
+ VT8237A 0x3337 yes
+ VT8251 0x3287 yes
Note: we assume there can only be one device, with one SMBus interface.
*/
@@ -297,7 +299,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
return func;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = vt596_access,
.functionality = vt596_func,
};
@@ -381,7 +383,9 @@ found:
dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
switch (pdev->device) {
+ case PCI_DEVICE_ID_VIA_8251:
case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
case PCI_DEVICE_ID_VIA_8235:
case PCI_DEVICE_ID_VIA_8233A:
case PCI_DEVICE_ID_VIA_8233_0:
@@ -432,8 +436,12 @@ static struct pci_device_id vt596_ids[] = {
.driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
.driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+ .driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
.driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+ .driver_data = SMBBA3 },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
index b675773b0cc..6c8d2518338 100644
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ b/drivers/i2c/busses/i2c-voodoo3.c
@@ -160,7 +160,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
.getsda = bit_vooi2c_getsda,
.getscl = bit_vooi2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
@@ -177,7 +176,6 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = {
.getsda = bit_vooddc_getsda,
.getscl = bit_vooddc_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index 22a3eda0416..32aab0d34ee 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -184,21 +184,21 @@ static void scx200_acb_machine(struct scx200_acb_iface *iface, u8 status)
break;
case state_read:
- /* Set ACK if receiving the last byte */
- if (iface->len == 1)
+ /* Set ACK if _next_ byte will be the last one */
+ if (iface->len == 2)
outb(inb(ACBCTL1) | ACBCTL1_ACK, ACBCTL1);
else
outb(inb(ACBCTL1) & ~ACBCTL1_ACK, ACBCTL1);
- *iface->ptr++ = inb(ACBSDA);
- --iface->len;
-
- if (iface->len == 0) {
+ if (iface->len == 1) {
iface->result = 0;
iface->state = state_idle;
outb(inb(ACBCTL1) | ACBCTL1_STOP, ACBCTL1);
}
+ *iface->ptr++ = inb(ACBSDA);
+ --iface->len;
+
break;
case state_write:
@@ -232,7 +232,7 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface)
unsigned long timeout;
timeout = jiffies + POLL_TIMEOUT;
- while (time_before(jiffies, timeout)) {
+ while (1) {
status = inb(ACBST);
/* Reset the status register to avoid the hang */
@@ -242,7 +242,10 @@ static void scx200_acb_poll(struct scx200_acb_iface *iface)
scx200_acb_machine(iface, status);
return;
}
- yield();
+ if (time_after(jiffies, timeout))
+ break;
+ cpu_relax();
+ cond_resched();
}
dev_err(&iface->adapter.dev, "timeout in state %s\n",
@@ -307,8 +310,12 @@ static s32 scx200_acb_smbus_xfer(struct i2c_adapter *adapter,
buffer = (u8 *)&cur_word;
break;
- case I2C_SMBUS_BLOCK_DATA:
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ if (rw == I2C_SMBUS_READ)
+ data->block[0] = I2C_SMBUS_BLOCK_MAX; /* For now */
len = data->block[0];
+ if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
+ return -EINVAL;
buffer = &data->block[1];
break;
@@ -372,11 +379,11 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
+ I2C_FUNC_SMBUS_I2C_BLOCK;
}
/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm scx200_acb_algorithm = {
+static const struct i2c_algorithm scx200_acb_algorithm = {
.smbus_xfer = scx200_acb_smbus_xfer,
.functionality = scx200_acb_func,
};
diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
index 27fbfecc414..8b65a5cf825 100644
--- a/drivers/i2c/busses/scx200_i2c.c
+++ b/drivers/i2c/busses/scx200_i2c.c
@@ -21,7 +21,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -72,12 +71,12 @@ static int scx200_i2c_getsda(void *data)
*/
static struct i2c_algo_bit_data scx200_i2c_data = {
- NULL,
- scx200_i2c_setsda,
- scx200_i2c_setscl,
- scx200_i2c_getsda,
- scx200_i2c_getscl,
- 10, 10, 100, /* waits, timeout */
+ .setsda = scx200_i2c_setsda,
+ .setscl = scx200_i2c_setscl,
+ .getsda = scx200_i2c_getsda,
+ .getscl = scx200_i2c_getscl,
+ .udelay = 10,
+ .timeout = 100,
};
static struct i2c_adapter scx200_i2c_ops = {
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 13c108269a6..cec3a0c3894 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -209,10 +209,14 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* create the sysfs eeprom file */
- sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
+ err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
+ if (err)
+ goto exit_detach;
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
@@ -223,6 +227,8 @@ static int eeprom_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
+
err = i2c_detach_client(client);
if (err)
return err;
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index e6f1ab7b913..182f0495346 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -21,7 +21,6 @@
#undef DEBUG
#undef VERBOSE
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -31,7 +30,7 @@
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
@@ -909,7 +908,7 @@ static int otg_bind(struct isp1301 *isp)
if (otg_dev)
status = request_irq(otg_dev->resource[1].start, omap_otg_irq,
- SA_INTERRUPT, DRIVER_NAME, isp);
+ IRQF_DISABLED, DRIVER_NAME, isp);
else
status = -ENODEV;
@@ -1579,7 +1578,7 @@ fail1:
}
status = request_irq(isp->irq, isp1301_irq,
- SA_SAMPLE_RANDOM, DRIVER_NAME, isp);
+ IRQF_SAMPLE_RANDOM, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
isp->irq, status);
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 88d2ddee449..76645c14297 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -199,8 +199,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
mutex_init(&data->update_lock);
/* Init fake client data */
- /* set the client data to the i2c_client so that it will get freed */
- i2c_set_clientdata(fake_client, fake_client);
+ i2c_set_clientdata(fake_client, NULL);
fake_client->addr = address | 1;
fake_client->adapter = adapter;
fake_client->driver = &max6875_driver;
@@ -214,13 +213,17 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_kfree2;
if ((err = i2c_attach_client(fake_client)) != 0)
- goto exit_detach;
+ goto exit_detach1;
- sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
+ err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
+ if (err)
+ goto exit_detach2;
return 0;
-exit_detach:
+exit_detach2:
+ i2c_detach_client(fake_client);
+exit_detach1:
i2c_detach_client(real_client);
exit_kfree2:
kfree(fake_client);
@@ -229,14 +232,24 @@ exit_kfree1:
return err;
}
+/* Will be called for both the real client and the fake client */
static int max6875_detach_client(struct i2c_client *client)
{
int err;
+ struct max6875_data *data = i2c_get_clientdata(client);
+
+ /* data is NULL for the fake client */
+ if (data)
+ sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
err = i2c_detach_client(client);
if (err)
return err;
- kfree(i2c_get_clientdata(client));
+
+ if (data) /* real client */
+ kfree(data);
+ else /* fake client */
+ kfree(client);
return 0;
}
diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c
index 54b6e6a4bee..f43c4e79b55 100644
--- a/drivers/i2c/chips/pca9539.c
+++ b/drivers/i2c/chips/pca9539.c
@@ -134,11 +134,13 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
new_client->driver = &pca9539_driver;
new_client->flags = 0;
- /* Detection: the pca9539 only has 8 registers (0-7).
- A read of 7 should succeed, but a read of 8 should fail. */
- if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
- (i2c_smbus_read_byte_data(new_client, 8) >= 0))
- goto exit_kfree;
+ if (kind < 0) {
+ /* Detection: the pca9539 only has 8 registers (0-7).
+ A read of 7 should succeed, but a read of 8 should fail. */
+ if ((i2c_smbus_read_byte_data(new_client, 7) < 0) ||
+ (i2c_smbus_read_byte_data(new_client, 8) >= 0))
+ goto exit_kfree;
+ }
strlcpy(new_client->name, "pca9539", I2C_NAME_SIZE);
@@ -146,11 +148,16 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = i2c_attach_client(new_client)))
goto exit_kfree;
- /* Register sysfs hooks (don't care about failure) */
- sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group);
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&new_client->dev.kobj,
+ &pca9539_defattr_group);
+ if (err)
+ goto exit_detach;
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
@@ -161,6 +168,8 @@ static int pca9539_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index c3e6449c448..32b25427eab 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -105,6 +105,16 @@ static ssize_t set_write(struct device *dev, struct device_attribute *attr, cons
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+static struct attribute *pcf8574_attributes[] = {
+ &dev_attr_read.attr,
+ &dev_attr_write.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8574_attr_group = {
+ .attrs = pcf8574_attributes,
+};
+
/*
* Real code
*/
@@ -166,13 +176,13 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
pcf8574_init_client(new_client);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_read);
- device_create_file(&new_client->dev, &dev_attr_write);
+ err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
+ if (err)
+ goto exit_detach;
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
-
+ exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -183,6 +193,8 @@ static int pcf8574_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index 925a6b371fd..4dc36376eb3 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -158,6 +158,28 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
show_out0_enable, set_out0_enable);
+static struct attribute *pcf8591_attributes[] = {
+ &dev_attr_out0_enable.attr,
+ &dev_attr_out0_output.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8591_attr_group = {
+ .attrs = pcf8591_attributes,
+};
+
+static struct attribute *pcf8591_attributes_opt[] = {
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8591_attr_group_opt = {
+ .attrs = pcf8591_attributes_opt,
+};
+
/*
* Real code
*/
@@ -211,24 +233,31 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
pcf8591_init_client(new_client);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_out0_enable);
- device_create_file(&new_client->dev, &dev_attr_out0_output);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
+ err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group);
+ if (err)
+ goto exit_detach;
/* Register input2 if not in "two differential inputs" mode */
- if (input_mode != 3 )
- device_create_file(&new_client->dev, &dev_attr_in2_input);
-
+ if (input_mode != 3) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in2_input)))
+ goto exit_sysfs_remove;
+ }
+
/* Register input3 only in "four single ended inputs" mode */
- if (input_mode == 0)
- device_create_file(&new_client->dev, &dev_attr_in3_input);
-
+ if (input_mode == 0) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in3_input)))
+ goto exit_sysfs_remove;
+ }
+
return 0;
-
- /* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
+exit_sysfs_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt);
+ sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group);
+exit_detach:
+ i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
@@ -239,6 +268,9 @@ static int pcf8591_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 179b1e022d8..6a757821717 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -44,13 +43,12 @@
/*-------------------------------------------------------------------------*/
#define DRIVER_VERSION "2 May 2005"
-#define DRIVER_NAME (tps65010_driver.name)
+#define DRIVER_NAME (tps65010_driver.driver.name)
MODULE_DESCRIPTION("TPS6501x Power Management Driver");
MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END };
-static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
@@ -101,7 +99,7 @@ struct tps65010 {
/* not currently tracking GPIO state */
};
-#define POWER_POLL_DELAY msecs_to_jiffies(800)
+#define POWER_POLL_DELAY msecs_to_jiffies(5000)
/*-------------------------------------------------------------------------*/
@@ -307,7 +305,7 @@ static int dbg_show(struct seq_file *s, void *_)
static int dbg_tps_open(struct inode *inode, struct file *file)
{
- return single_open(file, dbg_show, inode->u.generic_ip);
+ return single_open(file, dbg_show, inode->i_private);
}
static struct file_operations debug_fops = {
@@ -521,15 +519,18 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
goto fail1;
}
+ /* the IRQ is active low, but many gpio lines can't support that
+ * so this driver can use falling-edge triggers instead.
+ */
+ irqflags = IRQF_SAMPLE_RANDOM;
#ifdef CONFIG_ARM
- irqflags = SA_SAMPLE_RANDOM | SA_TRIGGER_LOW;
if (machine_is_omap_h2()) {
tps->model = TPS65010;
omap_cfg_reg(W4_GPIO58);
tps->irq = OMAP_GPIO_IRQ(58);
omap_request_gpio(58);
omap_set_gpio_direction(58, 1);
- irqflags |= SA_TRIGGER_FALLING;
+ irqflags |= IRQF_TRIGGER_FALLING;
}
if (machine_is_omap_osk()) {
tps->model = TPS65010;
@@ -537,15 +538,13 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
omap_request_gpio(OMAP_MPUIO(1));
omap_set_gpio_direction(OMAP_MPUIO(1), 1);
- irqflags |= SA_TRIGGER_FALLING;
+ irqflags |= IRQF_TRIGGER_FALLING;
}
if (machine_is_omap_h3()) {
tps->model = TPS65013;
// FIXME set up this board's IRQ ...
}
-#else
- irqflags = SA_SAMPLE_RANDOM;
#endif
if (tps->irq > 0) {
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a45155f799d..01233f0f777 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -183,15 +183,21 @@ int i2c_add_adapter(struct i2c_adapter *adap)
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.driver = &i2c_adapter_driver;
adap->dev.release = &i2c_adapter_dev_release;
- device_register(&adap->dev);
- device_create_file(&adap->dev, &dev_attr_name);
+ res = device_register(&adap->dev);
+ if (res)
+ goto out_list;
+ res = device_create_file(&adap->dev, &dev_attr_name);
+ if (res)
+ goto out_unregister;
/* Add this adapter to the i2c_adapter class */
memset(&adap->class_dev, 0x00, sizeof(struct class_device));
adap->class_dev.dev = &adap->dev;
adap->class_dev.class = &i2c_adapter_class;
strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
- class_device_register(&adap->class_dev);
+ res = class_device_register(&adap->class_dev);
+ if (res)
+ goto out_remove_name;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
@@ -206,6 +212,17 @@ int i2c_add_adapter(struct i2c_adapter *adap)
out_unlock:
mutex_unlock(&core_lists);
return res;
+
+out_remove_name:
+ device_remove_file(&adap->dev, &dev_attr_name);
+out_unregister:
+ init_completion(&adap->dev_released); /* Needed? */
+ device_unregister(&adap->dev);
+ wait_for_completion(&adap->dev_released);
+out_list:
+ list_del(&adap->list);
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ goto out_unlock;
}
@@ -394,14 +411,14 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
int i2c_attach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
+ int res = 0;
mutex_lock(&adapter->clist_lock);
if (__i2c_check_addr(client->adapter, client->addr)) {
- mutex_unlock(&adapter->clist_lock);
- return -EBUSY;
+ res = -EBUSY;
+ goto out_unlock;
}
list_add_tail(&client->list,&adapter->clients);
- mutex_unlock(&adapter->clist_lock);
if (adapter->client_register) {
if (adapter->client_register(client)) {
@@ -422,10 +439,26 @@ int i2c_attach_client(struct i2c_client *client)
"%d-%04x", i2c_adapter_id(adapter), client->addr);
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
client->name, client->dev.bus_id);
- device_register(&client->dev);
- device_create_file(&client->dev, &dev_attr_client_name);
-
- return 0;
+ res = device_register(&client->dev);
+ if (res)
+ goto out_list;
+ res = device_create_file(&client->dev, &dev_attr_client_name);
+ if (res)
+ goto out_unregister;
+
+out_unlock:
+ mutex_unlock(&adapter->clist_lock);
+ return res;
+
+out_unregister:
+ init_completion(&client->released); /* Needed? */
+ device_unregister(&client->dev);
+ wait_for_completion(&client->released);
+out_list:
+ list_del(&client->list);
+ dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
+ "(%d)\n", client->name, client->addr, res);
+ goto out_unlock;
}
@@ -674,11 +707,16 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
/* Finally call the custom detection function */
err = found_proc(adapter, addr, kind);
-
/* -ENODEV can be returned if there is a chip at the given address
but it isn't supported by this chip driver. We catch it here as
this isn't an error. */
- return (err == -ENODEV) ? 0 : err;
+ if (err == -ENODEV)
+ err = 0;
+
+ if (err)
+ dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
+ addr, err);
+ return err;
}
int i2c_probe(struct i2c_adapter *adapter,
@@ -756,9 +794,9 @@ int i2c_probe(struct i2c_adapter *adapter,
"parameter for adapter %d, "
"addr 0x%02x\n", adap_id,
address_data->ignore[j + 1]);
+ ignore = 1;
+ break;
}
- ignore = 1;
- break;
}
if (ignore)
continue;
@@ -868,7 +906,7 @@ s32 i2c_smbus_read_byte(struct i2c_client *client)
I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
return -1;
else
- return 0x0FF & data.byte;
+ return data.byte;
}
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
@@ -884,7 +922,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
return -1;
else
- return 0x0FF & data.byte;
+ return data.byte;
}
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
@@ -903,7 +941,7 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
return -1;
else
- return 0x0FFFF & data.word;
+ return data.word;
}
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
@@ -1006,7 +1044,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
else {
msg[0].len=3;
msgbuf0[1] = data->word & 0xff;
- msgbuf0[2] = (data->word >> 8) & 0xff;
+ msgbuf0[2] = data->word >> 8;
}
break;
case I2C_SMBUS_PROC_CALL:
@@ -1015,7 +1053,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
msg[0].len = 3;
msg[1].len = 2;
msgbuf0[1] = data->word & 0xff;
- msgbuf0[2] = (data->word >> 8) & 0xff;
+ msgbuf0[2] = data->word >> 8;
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 58ccddd5c23..3f869033ed7 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -32,43 +32,35 @@
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
-#include <linux/platform_device.h>
#include <asm/uaccess.h>
-static struct i2c_client i2cdev_client_template;
+static struct i2c_driver i2cdev_driver;
struct i2c_dev {
- int minor;
+ struct list_head list;
struct i2c_adapter *adap;
struct class_device *class_dev;
};
-#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
#define I2C_MINORS 256
-static struct i2c_dev *i2c_dev_array[I2C_MINORS];
-static DEFINE_SPINLOCK(i2c_dev_array_lock);
+static LIST_HEAD(i2c_dev_list);
+static DEFINE_SPINLOCK(i2c_dev_list_lock);
static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
struct i2c_dev *i2c_dev;
- spin_lock(&i2c_dev_array_lock);
- i2c_dev = i2c_dev_array[index];
- spin_unlock(&i2c_dev_array_lock);
- return i2c_dev;
-}
-
-static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
-{
- struct i2c_dev *i2c_dev = NULL;
-
- spin_lock(&i2c_dev_array_lock);
- if ((i2c_dev_array[adap->nr]) &&
- (i2c_dev_array[adap->nr]->adap == adap))
- i2c_dev = i2c_dev_array[adap->nr];
- spin_unlock(&i2c_dev_array_lock);
+ spin_lock(&i2c_dev_list_lock);
+ list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
+ if (i2c_dev->adap->nr == index)
+ goto found;
+ }
+ i2c_dev = NULL;
+found:
+ spin_unlock(&i2c_dev_list_lock);
return i2c_dev;
}
@@ -76,30 +68,28 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
+ if (adap->nr >= I2C_MINORS) {
+ printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
+ adap->nr);
+ return ERR_PTR(-ENODEV);
+ }
+
i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
return ERR_PTR(-ENOMEM);
+ i2c_dev->adap = adap;
- spin_lock(&i2c_dev_array_lock);
- if (i2c_dev_array[adap->nr]) {
- spin_unlock(&i2c_dev_array_lock);
- dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n");
- goto error;
- }
- i2c_dev->minor = adap->nr;
- i2c_dev_array[adap->nr] = i2c_dev;
- spin_unlock(&i2c_dev_array_lock);
+ spin_lock(&i2c_dev_list_lock);
+ list_add_tail(&i2c_dev->list, &i2c_dev_list);
+ spin_unlock(&i2c_dev_list_lock);
return i2c_dev;
-error:
- kfree(i2c_dev);
- return ERR_PTR(-ENODEV);
}
static void return_i2c_dev(struct i2c_dev *i2c_dev)
{
- spin_lock(&i2c_dev_array_lock);
- i2c_dev_array[i2c_dev->minor] = NULL;
- spin_unlock(&i2c_dev_array_lock);
+ spin_lock(&i2c_dev_list_lock);
+ list_del(&i2c_dev->list);
+ spin_unlock(&i2c_dev_list_lock);
}
static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
@@ -375,12 +365,13 @@ static int i2cdev_open(struct inode *inode, struct file *file)
if (!adap)
return -ENODEV;
- client = kmalloc(sizeof(*client), GFP_KERNEL);
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
- memcpy(client, &i2cdev_client_template, sizeof(*client));
+ snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
+ client->driver = &i2cdev_driver;
/* registered with adapter, passed as client to user */
client->adapter = adap;
@@ -415,41 +406,47 @@ static struct class *i2c_dev_class;
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
- struct device *dev;
+ int res;
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
- pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
- adap->name, i2c_dev->minor);
-
/* register this i2c device with the driver core */
- i2c_dev->adap = adap;
- dev = &adap->dev;
i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
- MKDEV(I2C_MAJOR, i2c_dev->minor),
- dev, "i2c-%d", i2c_dev->minor);
- if (!i2c_dev->class_dev)
+ MKDEV(I2C_MAJOR, adap->nr),
+ &adap->dev, "i2c-%d",
+ adap->nr);
+ if (!i2c_dev->class_dev) {
+ res = -ENODEV;
goto error;
- class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
+ }
+ res = class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
+ if (res)
+ goto error_destroy;
+
+ pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+ adap->name, adap->nr);
return 0;
+error_destroy:
+ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
kfree(i2c_dev);
- return -ENODEV;
+ return res;
}
static int i2cdev_detach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
- i2c_dev = i2c_dev_get_by_adapter(adap);
- if (!i2c_dev)
- return -ENODEV;
+ i2c_dev = i2c_dev_get_by_minor(adap->nr);
+ if (!i2c_dev) /* attach_adapter must have failed */
+ return 0;
+ class_device_remove_file(i2c_dev->class_dev, &class_device_attr_name);
return_i2c_dev(i2c_dev);
- class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
+ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
kfree(i2c_dev);
pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
@@ -471,12 +468,6 @@ static struct i2c_driver i2cdev_driver = {
.detach_client = i2cdev_detach_client,
};
-static struct i2c_client i2cdev_client_template = {
- .name = "I2C /dev entry",
- .addr = -1,
- .driver = &i2cdev_driver,
-};
-
static int __init i2c_dev_init(void)
{
int res;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index d633081fa4c..b6fb167e20f 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -682,6 +682,7 @@ config BLK_DEV_SVWKS
config BLK_DEV_SGIIOC4
tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support"
depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4
+ select IDEPCI_SHARE_IRQ
help
This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4
chipset, which has one channel and can support two devices.
@@ -773,13 +774,6 @@ config BLK_DEV_IDEDMA_PMAC
to transfer data to and from memory. Saying Y is safe and improves
performance.
-config BLK_DEV_IDE_PMAC_BLINK
- bool "Blink laptop LED on drive activity"
- depends on BLK_DEV_IDE_PMAC && ADB_PMU
- help
- This option enables the use of the sleep LED as a hard drive
- activity LED.
-
config BLK_DEV_IDE_SWARM
tristate "IDE for Sibyte evaluation boards"
depends on SIBYTE_SB1xxx_SOC
diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
index 308897e57e4..8a1c27f2869 100644
--- a/drivers/ide/arm/icside.c
+++ b/drivers/ide/arm/icside.c
@@ -6,7 +6,6 @@
* Please note that this platform does not support 32-bit IDE IO.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/module.h>
#include <linux/ioport.h>
diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c
index cd15e626051..5797e0b5a13 100644
--- a/drivers/ide/cris/ide-cris.c
+++ b/drivers/ide/cris/ide-cris.c
@@ -19,7 +19,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/timer.h>
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index fb91cb8bf2d..15955996a1f 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -5,7 +5,6 @@
#include <linux/init.h>
#include <linux/ide.h>
-#include <linux/config.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 6de3cd3d6e8..654d4cd0984 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -301,7 +301,6 @@
#define IDECD_VERSION "4.61"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -395,7 +394,8 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
* we cannot reliably check if drive can auto-close
*/
if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24)
- log = 0;
+ break;
+ log = 1;
break;
case UNIT_ATTENTION:
/*
@@ -417,6 +417,11 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
struct request *failed_command,
struct request_sense *sense)
{
+ unsigned long sector;
+ unsigned long bio_sectors;
+ unsigned long valid;
+ struct cdrom_info *info = drive->driver_data;
+
if (!cdrom_log_sense(drive, failed_command, sense))
return;
@@ -429,6 +434,37 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
if (sense->sense_key == 0x05 && sense->asc == 0x24)
return;
+ if (sense->error_code == 0x70) { /* Current Error */
+ switch(sense->sense_key) {
+ case MEDIUM_ERROR:
+ case VOLUME_OVERFLOW:
+ case ILLEGAL_REQUEST:
+ if (!sense->valid)
+ break;
+ if (failed_command == NULL ||
+ !blk_fs_request(failed_command))
+ break;
+ sector = (sense->information[0] << 24) |
+ (sense->information[1] << 16) |
+ (sense->information[2] << 8) |
+ (sense->information[3]);
+
+ bio_sectors = bio_sectors(failed_command->bio);
+ if (bio_sectors < 4)
+ bio_sectors = 4;
+ if (drive->queue->hardsect_size == 2048)
+ sector <<= 2; /* Device sector size is 2K */
+ sector &= ~(bio_sectors -1);
+ valid = (sector - failed_command->sector) << 9;
+
+ if (valid < 0)
+ valid = 0;
+ if (sector < get_capacity(info->disk) &&
+ drive->probed_capacity - sector < 4 * 75) {
+ set_capacity(info->disk, sector);
+ }
+ }
+ }
#if VERBOSE_IDE_CD_ERRORS
{
int i;
@@ -609,17 +645,23 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
sense = failed->sense;
failed->sense_len = rq->sense_len;
}
-
+ cdrom_analyze_sense_data(drive, failed, sense);
/*
* now end failed request
*/
- spin_lock_irqsave(&ide_lock, flags);
- end_that_request_chunk(failed, 0, failed->data_len);
- end_that_request_last(failed, 0);
- spin_unlock_irqrestore(&ide_lock, flags);
- }
-
- cdrom_analyze_sense_data(drive, failed, sense);
+ if (blk_fs_request(failed)) {
+ if (ide_end_dequeued_request(drive, failed, 0,
+ failed->hard_nr_sectors))
+ BUG();
+ } else {
+ spin_lock_irqsave(&ide_lock, flags);
+ end_that_request_chunk(failed, 0,
+ failed->data_len);
+ end_that_request_last(failed, 0);
+ spin_unlock_irqrestore(&ide_lock, flags);
+ }
+ } else
+ cdrom_analyze_sense_data(drive, NULL, sense);
}
if (!rq->current_nr_sectors && blk_fs_request(rq))
@@ -633,6 +675,13 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
ide_end_request(drive, uptodate, nsectors);
}
+static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat)
+{
+ if (stat & 0x80)
+ return;
+ ide_dump_status(drive, msg, stat);
+}
+
/* Returns 0 if the request should be continued.
Returns 1 if the request was ended. */
static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
@@ -761,16 +810,16 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
sense_key == DATA_PROTECT) {
/* No point in retrying after an illegal
request or data protect error.*/
- ide_dump_status (drive, "command error", stat);
+ ide_dump_status_no_sense (drive, "command error", stat);
do_end_request = 1;
} else if (sense_key == MEDIUM_ERROR) {
/* No point in re-trying a zillion times on a bad
* sector... If we got here the error is not correctable */
- ide_dump_status (drive, "media error (bad sector)", stat);
+ ide_dump_status_no_sense (drive, "media error (bad sector)", stat);
do_end_request = 1;
} else if (sense_key == BLANK_CHECK) {
/* Disk appears blank ?? */
- ide_dump_status (drive, "media error (blank)", stat);
+ ide_dump_status_no_sense (drive, "media error (blank)", stat);
do_end_request = 1;
} else if ((err & ~ABRT_ERR) != 0) {
/* Go to the default handler
@@ -782,13 +831,27 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
do_end_request = 1;
}
- if (do_end_request)
- cdrom_end_request(drive, 0);
-
- /* If we got a CHECK_CONDITION status,
- queue a request sense command. */
- if ((stat & ERR_STAT) != 0)
- cdrom_queue_request_sense(drive, NULL, NULL);
+ /* End a request through request sense analysis when we have
+ sense data. We need this in order to perform end of media
+ processing */
+
+ if (do_end_request) {
+ if (stat & ERR_STAT) {
+ unsigned long flags;
+ spin_lock_irqsave(&ide_lock, flags);
+ blkdev_dequeue_request(rq);
+ HWGROUP(drive)->rq = NULL;
+ spin_unlock_irqrestore(&ide_lock, flags);
+
+ cdrom_queue_request_sense(drive, rq->sense, rq);
+ } else
+ cdrom_end_request(drive, 0);
+ } else {
+ /* If we got a CHECK_CONDITION status,
+ queue a request sense command. */
+ if (stat & ERR_STAT)
+ cdrom_queue_request_sense(drive, NULL, NULL);
+ }
} else {
blk_dump_rq_flags(rq, "ide-cd: bad rq");
cdrom_end_request(drive, 0);
@@ -1491,8 +1554,7 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
}
-static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
+static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
{
struct request_sense sense;
int retries = 10;
@@ -2220,6 +2282,9 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
toc->capacity = 0x1fffff;
set_capacity(info->disk, toc->capacity * sectors_per_frame);
+ /* Save a private copy of te TOC capacity for error handling */
+ drive->probed_capacity = toc->capacity * sectors_per_frame;
+
blk_queue_hardsect_size(drive->queue,
sectors_per_frame << SECTOR_BITS);
@@ -2342,6 +2407,7 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
if (!stat && (last_written > toc->capacity)) {
toc->capacity = last_written;
set_capacity(info->disk, toc->capacity * sectors_per_frame);
+ drive->probed_capacity = toc->capacity * sectors_per_frame;
}
/* Remember that we've read this stuff. */
@@ -2698,14 +2764,11 @@ int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr)
* any other way to detect this...
*/
if (sense.sense_key == NOT_READY) {
- if (sense.asc == 0x3a) {
- if (sense.ascq == 1)
- return CDS_NO_DISC;
- else if (sense.ascq == 0 || sense.ascq == 2)
- return CDS_TRAY_OPEN;
- }
+ if (sense.asc == 0x3a && sense.ascq == 1)
+ return CDS_NO_DISC;
+ else
+ return CDS_TRAY_OPEN;
}
-
return CDS_DRIVE_NOT_READY;
}
@@ -3463,8 +3526,6 @@ static int ide_cd_probe(ide_drive_t *drive)
drive->driver_data = info;
g->minors = 1;
- snprintf(g->devfs_name, sizeof(g->devfs_name),
- "%s/cd", drive->devfs_name);
g->driverfs_dev = &drive->gendev;
g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
if (ide_cdrom_setup(drive)) {
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index a5017de72da..7cf3eb02352 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -37,7 +37,7 @@
* Version 1.15 convert all calls to ide_raw_taskfile
* since args will return register content.
* Version 1.16 added suspend-resume-checkpower
- * Version 1.17 do flush on standy, do flush on ATA < ATA6
+ * Version 1.17 do flush on standby, do flush on ATA < ATA6
* fix wcache setup.
*/
@@ -47,7 +47,6 @@
//#define DEBUG
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -777,7 +776,7 @@ static void update_ordered(ide_drive_t *drive)
* not available so we don't need to recheck that.
*/
capacity = idedisk_capacity(drive);
- barrier = ide_id_has_flush_cache(id) &&
+ barrier = ide_id_has_flush_cache(id) && !drive->noflush &&
(drive->addressing == 0 || capacity <= (1ULL << 28) ||
ide_id_has_flush_cache_ext(id));
@@ -1018,7 +1017,6 @@ static void ide_disk_release(struct kref *kref)
struct gendisk *g = idkp->disk;
drive->driver_data = NULL;
- drive->devfs_name[0] = '\0';
g->private_data = NULL;
put_disk(g);
kfree(idkp);
@@ -1222,7 +1220,6 @@ static int ide_disk_probe(ide_drive_t *drive)
drive->attach = 1;
g->minors = 1 << PARTN_BITS;
- strcpy(g->devfs_name, drive->devfs_name);
g->driverfs_dev = &drive->gendev;
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
set_capacity(g, idedisk_capacity(drive));
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 783a2475ee8..7c3a13e1cf6 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -74,7 +74,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -751,7 +750,7 @@ void ide_dma_verbose(ide_drive_t *drive)
goto bug_dma_off;
printk(", DMA");
} else if (id->field_valid & 1) {
- printk(", BUG");
+ goto bug_dma_off;
}
return;
bug_dma_off:
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index a1179e92496..adbe9f76a50 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -82,7 +82,6 @@
#define IDEFLOPPY_VERSION "0.99.newide"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -839,7 +838,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive)
"transferred\n", pc->actually_transferred);
clear_bit(PC_DMA_IN_PROGRESS, &pc->flags);
- local_irq_enable();
+ local_irq_enable_in_hardirq();
if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) {
/* Error detected */
@@ -1284,7 +1283,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
rq->rq_status,
- rq->rq_disk ? rq->rq_disk->disk_name ? "?",
+ rq->rq_disk ? rq->rq_disk->disk_name : "?",
rq->flags, rq->errors);
debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
"current_nr_sectors: %d\n", (long)rq->sector,
@@ -2176,7 +2175,6 @@ static int ide_floppy_probe(ide_drive_t *drive)
g->minors = 1 << PARTN_BITS;
g->driverfs_dev = &drive->gendev;
- strcpy(g->devfs_name, drive->devfs_name);
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
g->fops = &idefloppy_ops;
drive->attach = 1;
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 4f2f138de2c..fb6795236e7 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -24,7 +24,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -223,6 +222,63 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
}
/**
+ * ide_end_dequeued_request - complete an IDE I/O
+ * @drive: IDE device for the I/O
+ * @uptodate:
+ * @nr_sectors: number of sectors completed
+ *
+ * Complete an I/O that is no longer on the request queue. This
+ * typically occurs when we pull the request and issue a REQUEST_SENSE.
+ * We must still finish the old request but we must not tamper with the
+ * queue in the meantime.
+ *
+ * NOTE: This path does not handle barrier, but barrier is not supported
+ * on ide-cd anyway.
+ */
+
+int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, int nr_sectors)
+{
+ unsigned long flags;
+ int ret = 1;
+
+ spin_lock_irqsave(&ide_lock, flags);
+
+ BUG_ON(!(rq->flags & REQ_STARTED));
+
+ /*
+ * if failfast is set on a request, override number of sectors and
+ * complete the whole request right now
+ */
+ if (blk_noretry_request(rq) && end_io_error(uptodate))
+ nr_sectors = rq->hard_nr_sectors;
+
+ if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors)
+ rq->errors = -EIO;
+
+ /*
+ * decide whether to reenable DMA -- 3 is a random magic for now,
+ * if we DMA timeout more than 3 times, just stay in PIO
+ */
+ if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {
+ drive->state = 0;
+ HWGROUP(drive)->hwif->ide_dma_on(drive);
+ }
+
+ if (!end_that_request_first(rq, uptodate, nr_sectors)) {
+ add_disk_randomness(rq->rq_disk);
+ if (blk_rq_tagged(rq))
+ blk_queue_end_tag(drive->queue, rq);
+ end_that_request_last(rq, uptodate);
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(ide_end_dequeued_request);
+
+
+/**
* ide_complete_pm_request - end the current Power Management request
* @drive: target drive
* @rq: request
@@ -448,7 +504,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8
}
}
- if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ)
+ if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ && hwif->err_stops_fifo == 0)
try_to_flush_leftover_data(drive);
if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
@@ -637,7 +693,7 @@ static ide_startstop_t drive_cmd_intr (ide_drive_t *drive)
u8 stat = hwif->INB(IDE_STATUS_REG);
int retries = 10;
- local_irq_enable();
+ local_irq_enable_in_hardirq();
if ((stat & DRQ_STAT) && args && args[3]) {
u8 io_32bit = drive->io_32bit;
drive->io_32bit = 0;
@@ -902,7 +958,7 @@ static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
printk(KERN_WARNING "%s: bus not ready on wakeup\n", drive->name);
SELECT_DRIVE(drive);
HWIF(drive)->OUTB(8, HWIF(drive)->io_ports[IDE_CONTROL_OFFSET]);
- rc = ide_wait_not_busy(HWIF(drive), 10000);
+ rc = ide_wait_not_busy(HWIF(drive), 100000);
if (rc)
printk(KERN_WARNING "%s: drive not ready on wakeup\n", drive->name);
}
@@ -1230,7 +1286,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
disable_irq_nosync(hwif->irq);
spin_unlock(&ide_lock);
- local_irq_enable();
+ local_irq_enable_in_hardirq();
/* allow other IRQs while we start this request */
startstop = start_request(drive, rq);
spin_lock_irq(&ide_lock);
@@ -1575,7 +1631,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
spin_unlock(&ide_lock);
if (drive->unmask)
- local_irq_enable();
+ local_irq_enable_in_hardirq();
/* service this interrupt, may set handler for next interrupt */
startstop = handler(drive);
spin_lock_irq(&ide_lock);
@@ -1608,7 +1664,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
* Initialize a request before we fill it in and send it down to
* ide_do_drive_cmd. Commands must be set up by this function. Right
* now it doesn't do a lot, but if that changes abusers will have a
- * nasty suprise.
+ * nasty surprise.
*/
void ide_init_drive_cmd (struct request *rq)
@@ -1649,7 +1705,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
{
unsigned long flags;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
int where = ELEVATOR_INSERT_BACK, err;
int must_wait = (action == ide_wait || action == ide_head_wait);
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 97a49e77a8f..77703acaec1 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -6,7 +6,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -24,6 +23,7 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/bitops.h>
+#include <linux/nmi.h>
#include <asm/byteorder.h>
#include <asm/irq.h>
@@ -597,6 +597,10 @@ u8 eighty_ninty_three (ide_drive_t *drive)
{
if(HWIF(drive)->udma_four == 0)
return 0;
+
+ /* Check for SATA but only if we are ATA5 or higher */
+ if (drive->id->hw_config == 0 && (drive->id->major_rev_num & 0x7FE0))
+ return 1;
if (!(drive->id->hw_config & 0x6000))
return 0;
#ifndef CONFIG_IDEDMA_IVB
@@ -1240,6 +1244,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
if (stat == 0xff)
return -ENODEV;
touch_softlockup_watchdog();
+ touch_nmi_watchdog();
}
return -EBUSY;
}
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 16a143133f9..1feff23487d 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -485,7 +484,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
unsigned long flags;
u8 err = 0;
- local_irq_set(flags);
+ local_irq_save(flags);
printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
if (stat & BUSY_STAT)
printk("Busy ");
@@ -567,7 +566,7 @@ static u8 ide_dump_atapi_status(ide_drive_t *drive, const char *msg, u8 stat)
status.all = stat;
error.all = 0;
- local_irq_set(flags);
+ local_irq_save(flags);
printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
if (status.b.bsy)
printk("Busy ");
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 9ebf8ae2a5e..9cadf0106c6 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -33,7 +33,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -47,7 +46,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/spinlock.h>
#include <linux/kmod.h>
#include <linux/pci.h>
@@ -1006,7 +1004,7 @@ static int ide_init_queue(ide_drive_t *drive)
* and irq serialization situations. This is somewhat complex because
* it handles static as well as dynamic (PCMCIA) IDE interfaces.
*
- * The SA_INTERRUPT in sa_flags means ide_intr() is always entered with
+ * The IRQF_DISABLED in sa_flags means ide_intr() is always entered with
* interrupts completely disabled. This can be bad for interrupt latency,
* but anything else has led to problems on some machines. We re-enable
* interrupts as much as we can safely do in most places.
@@ -1092,15 +1090,15 @@ static int init_irq (ide_hwif_t *hwif)
* Allocate the irq, if not already obtained for another hwif
*/
if (!match || match->irq != hwif->irq) {
- int sa = SA_INTERRUPT;
+ int sa = IRQF_DISABLED;
#if defined(__mc68000__) || defined(CONFIG_APUS)
- sa = SA_SHIRQ;
+ sa = IRQF_SHARED;
#endif /* __mc68000__ || CONFIG_APUS */
if (IDE_CHIPSET_IS_PCI(hwif->chipset)) {
- sa = SA_SHIRQ;
+ sa = IRQF_SHARED;
#ifndef CONFIG_IDEPCI_SHARE_IRQ
- sa |= SA_INTERRUPT;
+ sa |= IRQF_DISABLED;
#endif /* CONFIG_IDEPCI_SHARE_IRQ */
}
@@ -1279,10 +1277,6 @@ static void drive_release_dev (struct device *dev)
ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);
spin_lock_irq(&ide_lock);
- if (drive->devfs_name[0] != '\0') {
- devfs_remove(drive->devfs_name);
- drive->devfs_name[0] = '\0';
- }
ide_remove_drive_from_hwgroup(drive);
kfree(drive->id);
drive->id = NULL;
@@ -1316,12 +1310,6 @@ static void init_gendisk (ide_hwif_t *hwif)
drive->gendev.bus = &ide_bus_type;
drive->gendev.driver_data = drive;
drive->gendev.release = drive_release_dev;
- if (drive->present) {
- sprintf(drive->devfs_name, "ide/host%d/bus%d/target%d/lun%d",
- (hwif->channel && hwif->mate) ?
- hwif->mate->index : hwif->index,
- hwif->channel, unit, drive->lun);
- }
}
blk_register_region(MKDEV(hwif->major, 0), MAX_DRIVES << PARTN_BITS,
THIS_MODULE, ata_probe, ata_lock, hwif);
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 84665e2ba3c..41b74b13a00 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/uaccess.h>
@@ -377,6 +376,8 @@ static int proc_ide_read_media
break;
case ide_floppy:media = "floppy\n";
break;
+ case ide_optical:media = "optical\n";
+ break;
default: media = "UNKNOWN\n";
break;
}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index f04791a58df..7067ab99792 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -424,7 +424,6 @@
#define IDETAPE_VERSION "1.19"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -435,7 +434,6 @@
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/major.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/errno.h>
#include <linux/genhd.h>
#include <linux/slab.h>
@@ -2646,21 +2644,23 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape)
return __idetape_kmalloc_stage(tape, 0, 0);
}
-static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
+static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
+ int ret = 0;
while (n) {
#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
printk(KERN_ERR "ide-tape: bh == NULL in "
"idetape_copy_stage_from_user\n");
- return;
+ return 1;
}
#endif /* IDETAPE_DEBUG_BUGS */
count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n);
- copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count);
+ if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count))
+ ret = 1;
n -= count;
atomic_add(count, &bh->b_count);
buf += count;
@@ -2671,23 +2671,26 @@ static void idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t
}
}
tape->bh = bh;
+ return ret;
}
-static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
+static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n)
{
struct idetape_bh *bh = tape->bh;
int count;
+ int ret = 0;
while (n) {
#if IDETAPE_DEBUG_BUGS
if (bh == NULL) {
printk(KERN_ERR "ide-tape: bh == NULL in "
"idetape_copy_stage_to_user\n");
- return;
+ return 1;
}
#endif /* IDETAPE_DEBUG_BUGS */
count = min(tape->b_count, n);
- copy_to_user(buf, tape->b_data, count);
+ if (copy_to_user(buf, tape->b_data, count))
+ ret = 1;
n -= count;
tape->b_data += count;
tape->b_count -= count;
@@ -2700,6 +2703,7 @@ static void idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf,
}
}
}
+ return ret;
}
static void idetape_init_merge_stage (idetape_tape_t *tape)
@@ -3719,6 +3723,7 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
ssize_t bytes_read,temp, actually_read = 0, rc;
+ ssize_t ret = 0;
#if IDETAPE_DEBUG_LOG
if (tape->debug_level >= 3)
@@ -3737,7 +3742,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
return (0);
if (tape->merge_stage_size) {
actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count);
- idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read))
+ ret = -EFAULT;
buf += actually_read;
tape->merge_stage_size -= actually_read;
count -= actually_read;
@@ -3746,7 +3752,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
bytes_read = idetape_add_chrdev_read_request(drive, tape->capabilities.ctl);
if (bytes_read <= 0)
goto finish;
- idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read))
+ ret = -EFAULT;
buf += bytes_read;
count -= bytes_read;
actually_read += bytes_read;
@@ -3756,7 +3763,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf,
if (bytes_read <= 0)
goto finish;
temp = min((unsigned long)count, (unsigned long)bytes_read);
- idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp);
+ if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp))
+ ret = -EFAULT;
actually_read += temp;
tape->merge_stage_size = bytes_read-temp;
}
@@ -3769,7 +3777,8 @@ finish:
idetape_space_over_filemarks(drive, MTFSF, 1);
return 0;
}
- return actually_read;
+
+ return (ret) ? ret : actually_read;
}
static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
@@ -3777,7 +3786,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
{
struct ide_tape_obj *tape = ide_tape_f(file);
ide_drive_t *drive = tape->drive;
- ssize_t retval, actually_written = 0;
+ ssize_t actually_written = 0;
+ ssize_t ret = 0;
/* The drive is write protected. */
if (tape->write_prot)
@@ -3813,7 +3823,7 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
* some drives (Seagate STT3401A) will return an error.
*/
if (drive->dsc_overlap) {
- retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
+ ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh);
if (retval < 0) {
__idetape_kfree_stage(tape->merge_stage);
tape->merge_stage = NULL;
@@ -3834,12 +3844,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
#endif /* IDETAPE_DEBUG_BUGS */
actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count);
- idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written);
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written))
+ ret = -EFAULT;
buf += actually_written;
tape->merge_stage_size += actually_written;
count -= actually_written;
if (tape->merge_stage_size == tape->stage_size) {
+ ssize_t retval;
tape->merge_stage_size = 0;
retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
if (retval <= 0)
@@ -3847,7 +3859,9 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
}
while (count >= tape->stage_size) {
- idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size);
+ ssize_t retval;
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size))
+ ret = -EFAULT;
buf += tape->stage_size;
count -= tape->stage_size;
retval = idetape_add_chrdev_write_request(drive, tape->capabilities.ctl);
@@ -3857,10 +3871,11 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf,
}
if (count) {
actually_written += count;
- idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count);
+ if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count))
+ ret = -EFAULT;
tape->merge_stage_size += count;
}
- return (actually_written);
+ return (ret) ? ret : actually_written;
}
static int idetape_write_filemark (ide_drive_t *drive)
@@ -4709,9 +4724,6 @@ static void ide_tape_release(struct kref *kref)
MKDEV(IDETAPE_MAJOR, tape->minor));
class_device_destroy(idetape_sysfs_class,
MKDEV(IDETAPE_MAJOR, tape->minor + 128));
- devfs_remove("%s/mt", drive->devfs_name);
- devfs_remove("%s/mtn", drive->devfs_name);
- devfs_unregister_tape(g->number);
idetape_devs[tape->minor] = NULL;
g->private_data = NULL;
put_disk(g);
@@ -4885,14 +4897,6 @@ static int ide_tape_probe(ide_drive_t *drive)
class_device_create(idetape_sysfs_class, NULL,
MKDEV(IDETAPE_MAJOR, minor + 128), &drive->gendev, "n%s", tape->name);
- devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor),
- S_IFCHR | S_IRUGO | S_IWUGO,
- "%s/mt", drive->devfs_name);
- devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128),
- S_IFCHR | S_IRUGO | S_IWUGO,
- "%s/mtn", drive->devfs_name);
-
- g->number = devfs_register_tape(drive->devfs_name);
g->fops = &idetape_block_ops;
ide_register_region(g);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index a839b2a8f6f..97a9244312f 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -27,7 +27,6 @@
* request.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -223,7 +222,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive)
ide_hwif_t *hwif = HWIF(drive);
u8 stat;
- local_irq_enable();
+ local_irq_enable_in_hardirq();
if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) {
return ide_error(drive, "task_no_data_intr", stat);
/* calls ide_end_drive_cmd */
diff --git a/drivers/ide/ide-timing.h b/drivers/ide/ide-timing.h
index 2fcfac6e967..c0864b1e922 100644
--- a/drivers/ide/ide-timing.h
+++ b/drivers/ide/ide-timing.h
@@ -220,6 +220,12 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
return -EINVAL;
/*
+ * Copy the timing from the table.
+ */
+
+ *t = *s;
+
+/*
* If the drive is an EIDE drive, it can tell us it needs extended
* PIO/MWDMA cycle timing.
*/
@@ -247,7 +253,7 @@ static int ide_timing_compute(ide_drive_t *drive, short speed, struct ide_timing
* Convert the timing to bus clock counts.
*/
- ide_timing_quantize(s, t, T, UT);
+ ide_timing_quantize(t, t, T, UT);
/*
* Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 59fe358048b..9c8468de1a7 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -130,7 +130,6 @@
#define _IDE_C /* Tell ide.h it's really us */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -147,7 +146,6 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ide.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/completion.h>
#include <linux/reboot.h>
#include <linux/cdrom.h>
@@ -592,13 +590,8 @@ void ide_unregister(unsigned int index)
goto abort;
for (unit = 0; unit < MAX_DRIVES; ++unit) {
drive = &hwif->drives[unit];
- if (!drive->present) {
- if (drive->devfs_name[0] != '\0') {
- devfs_remove(drive->devfs_name);
- drive->devfs_name[0] = '\0';
- }
+ if (!drive->present)
continue;
- }
spin_unlock_irq(&ide_lock);
device_unregister(&drive->gendev);
wait_for_completion(&drive->gendev_rel_comp);
@@ -1214,7 +1207,7 @@ int system_bus_clock (void)
EXPORT_SYMBOL(system_bus_clock);
-static int generic_ide_suspend(struct device *dev, pm_message_t state)
+static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
{
ide_drive_t *drive = dev->driver_data;
struct request rq;
@@ -1228,7 +1221,9 @@ static int generic_ide_suspend(struct device *dev, pm_message_t state)
rq.special = &args;
rq.end_io_data = &rqpm;
rqpm.pm_step = ide_pm_state_start_suspend;
- rqpm.pm_state = state.event;
+ if (mesg.event == PM_EVENT_PRETHAW)
+ mesg.event = PM_EVENT_FREEZE;
+ rqpm.pm_state = mesg.event;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
@@ -1546,7 +1541,7 @@ static int __init ide_setup(char *s)
const char *hd_words[] = {
"none", "noprobe", "nowerr", "cdrom", "serialize",
"autotune", "noautotune", "minus8", "swapdata", "bswap",
- "minus11", "remap", "remap63", "scsi", NULL };
+ "noflush", "remap", "remap63", "scsi", NULL };
unit = s[2] - 'a';
hw = unit / MAX_DRIVES;
unit = unit % MAX_DRIVES;
@@ -1585,6 +1580,9 @@ static int __init ide_setup(char *s)
case -10: /* "bswap" */
drive->bswap = 1;
goto done;
+ case -11: /* noflush */
+ drive->noflush = 1;
+ goto done;
case -12: /* "remap" */
drive->remap_0_to_1 = 1;
goto done;
@@ -1996,7 +1994,6 @@ EXPORT_SYMBOL_GPL(ide_bus_type);
static int __init ide_init(void)
{
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
- devfs_mk_dir("ide");
system_bus_speed = ide_system_bus_speed();
bus_register(&ide_bus_type);
@@ -2074,7 +2071,6 @@ void cleanup_module (void)
#ifdef CONFIG_PROC_FS
proc_ide_destroy();
#endif
- devfs_remove("ide");
bus_unregister(&ide_bus_type);
}
diff --git a/drivers/ide/legacy/ali14xx.c b/drivers/ide/legacy/ali14xx.c
index fb88711812e..9c544467cb7 100644
--- a/drivers/ide/legacy/ali14xx.c
+++ b/drivers/ide/legacy/ali14xx.c
@@ -40,7 +40,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/ide/legacy/dtc2278.c b/drivers/ide/legacy/dtc2278.c
index 20eb5b872ca..3b1d33baaa2 100644
--- a/drivers/ide/legacy/dtc2278.c
+++ b/drivers/ide/legacy/dtc2278.c
@@ -7,7 +7,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c
index 3fac3e9ec47..64d42619ab0 100644
--- a/drivers/ide/legacy/gayle.c
+++ b/drivers/ide/legacy/gayle.c
@@ -8,7 +8,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index 6439dec6688..aebecd8f51c 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -691,7 +691,7 @@ static struct block_device_operations hd_fops = {
};
/*
- * This is the hard disk IRQ description. The SA_INTERRUPT in sa_flags
+ * This is the hard disk IRQ description. The IRQF_DISABLED in sa_flags
* means we run the IRQ-handler with interrupts disabled: this is bad for
* interrupt latency, but anything else has led to problems on some
* machines.
@@ -806,7 +806,7 @@ static int __init hd_init(void)
p->cyl, p->head, p->sect);
}
- if (request_irq(HD_IRQ, hd_interrupt, SA_INTERRUPT, "hd", NULL)) {
+ if (request_irq(HD_IRQ, hd_interrupt, IRQF_DISABLED, "hd", NULL)) {
printk("hd: unable to get IRQ%d for the hard disk driver\n",
HD_IRQ);
goto out1;
diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c
index a77fb249d5c..c48e87e512d 100644
--- a/drivers/ide/legacy/ht6560b.c
+++ b/drivers/ide/legacy/ht6560b.c
@@ -39,7 +39,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index 90cac609d9c..d655da74914 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -11,7 +11,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
diff --git a/drivers/ide/legacy/qd65xx.c b/drivers/ide/legacy/qd65xx.c
index 563fab0098b..d3c3bc2640e 100644
--- a/drivers/ide/legacy/qd65xx.c
+++ b/drivers/ide/legacy/qd65xx.c
@@ -28,7 +28,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/ide/legacy/umc8672.c b/drivers/ide/legacy/umc8672.c
index cdbdb2ff9f1..6e2c58c5f6a 100644
--- a/drivers/ide/legacy/umc8672.c
+++ b/drivers/ide/legacy/umc8672.c
@@ -40,7 +40,6 @@
#define REALLY_SLOW_IO /* some systems can safely undef this */
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/ide/mips/au1xxx-ide.c b/drivers/ide/mips/au1xxx-ide.c
index 71f27e955d8..c7854ea57b5 100644
--- a/drivers/ide/mips/au1xxx-ide.c
+++ b/drivers/ide/mips/au1xxx-ide.c
@@ -476,13 +476,13 @@ static int auide_dma_lostirq(ide_drive_t *drive)
return 0;
}
-static void auide_ddma_tx_callback(int irq, void *param, struct pt_regs *regs)
+static void auide_ddma_tx_callback(int irq, void *param)
{
_auide_hwif *ahwif = (_auide_hwif*)param;
ahwif->drive->waiting_for_dma = 0;
}
-static void auide_ddma_rx_callback(int irq, void *param, struct pt_regs *regs)
+static void auide_ddma_rx_callback(int irq, void *param)
{
_auide_hwif *ahwif = (_auide_hwif*)param;
ahwif->drive->waiting_for_dma = 0;
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index c743e68c33a..f286079d233 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/delay.h>
@@ -22,7 +21,7 @@ struct chipset_bus_clock_list_entry {
u8 ultra_settings;
};
-static struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
+static const struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
{ XFER_UDMA_6, 0x31, 0x07 },
{ XFER_UDMA_5, 0x31, 0x06 },
{ XFER_UDMA_4, 0x31, 0x05 },
@@ -42,7 +41,7 @@ static struct chipset_bus_clock_list_entry aec6xxx_33_base [] = {
{ 0, 0x00, 0x00 }
};
-static struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
+static const struct chipset_bus_clock_list_entry aec6xxx_34_base [] = {
{ XFER_UDMA_6, 0x41, 0x06 },
{ XFER_UDMA_5, 0x41, 0x05 },
{ XFER_UDMA_4, 0x41, 0x04 },
@@ -254,7 +253,8 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+ (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
}
if (bus_speed <= 33)
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 8b24b4f2a83..d419e4bb54f 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -731,7 +730,7 @@ static unsigned int __devinit ata66_ali15x3 (ide_hwif_t *hwif)
if(m5229_revision <= 0x20)
tmpbyte = (tmpbyte & (~0x02)) | 0x01;
- else if (m5229_revision == 0xc7)
+ else if (m5229_revision == 0xc7 || m5229_revision == 0xc8)
tmpbyte |= 0x03;
else
tmpbyte |= 0x01;
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 6e9dbf4d807..2b0ea8b6608 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -16,7 +16,6 @@
* the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -75,6 +74,7 @@ static struct amd_ide_chip {
{ 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_NVIDIA_NFORCE_MCP61_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_AMD_CS5536_IDE, 0x40, AMD_UDMA_100 },
{ 0 }
};
@@ -490,7 +490,8 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
/* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
/* 17 */ DECLARE_NV_DEV("NFORCE-MCP61"),
- /* 18 */ DECLARE_AMD_DEV("AMD5536"),
+ /* 18 */ DECLARE_NV_DEV("NFORCE-MCP65"),
+ /* 19 */ DECLARE_AMD_DEV("AMD5536"),
};
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -528,7 +529,8 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
{ 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_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18 },
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index 900efd1da58..d55b938b1ae 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -6,7 +6,6 @@
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -319,6 +318,20 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
hwif->drives[0].autodma = hwif->autodma;
}
+static void __devinit init_hwif_sb600_legacy(ide_hwif_t *hwif)
+{
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.name = "ATIIXP",
@@ -327,6 +340,12 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
.bootable = ON_BOARD,
+ },{ /* 1 */
+ .name = "ATI SB600 SATA Legacy IDE",
+ .init_hwif = init_hwif_sb600_legacy,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
}
};
@@ -349,6 +368,7 @@ static struct pci_device_id atiixp_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, PCI_ANY_ID, PCI_ANY_ID, (PCI_CLASS_STORAGE_IDE<<8)|0x8a, 0xffff05, 1},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
diff --git a/drivers/ide/pci/cmd640.c b/drivers/ide/pci/cmd640.c
index 11d035f1983..61b5f9c0b2f 100644
--- a/drivers/ide/pci/cmd640.c
+++ b/drivers/ide/pci/cmd640.c
@@ -103,7 +103,6 @@
//#define CMD640_DUMP_REGS
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c
index 3d9c7afc869..20c32716bbc 100644
--- a/drivers/ide/pci/cmd64x.c
+++ b/drivers/ide/pci/cmd64x.c
@@ -14,7 +14,6 @@
* Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
@@ -190,14 +189,6 @@ static int cmd64x_get_info (char *buffer, char **addr, off_t offset, int count)
#endif /* defined(DISPLAY_CMD64X_TIMINGS) && defined(CONFIG_PROC_FS) */
/*
- * Registers and masks for easy access by drive index:
- */
-#if 0
-static u8 prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
-static u8 prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
-#endif
-
-/*
* This routine writes the prepared setup/active/recovery counts
* for a drive into the cmd646 chipset registers to active them.
*/
@@ -606,13 +597,6 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
class_rev &= 0xff;
-#ifdef __i386__
- if (dev->resource[PCI_ROM_RESOURCE].start) {
- pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start);
- }
-#endif
-
switch(dev->device) {
case PCI_DEVICE_ID_CMD_643:
break;
diff --git a/drivers/ide/pci/cs5520.c b/drivers/ide/pci/cs5520.c
index ea3c52cc8ac..079f7c86726 100644
--- a/drivers/ide/pci/cs5520.c
+++ b/drivers/ide/pci/cs5520.c
@@ -32,7 +32,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 09269e574b3..380bb28c7c5 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -14,7 +14,6 @@
* CS5530 documentation available from National Semiconductor.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/cs5535.c b/drivers/ide/pci/cs5535.c
index 6eb305197f3..5c5aec28e67 100644
--- a/drivers/ide/pci/cs5535.c
+++ b/drivers/ide/pci/cs5535.c
@@ -23,7 +23,6 @@
* CS5535 documentation available from AMD
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/ide.h>
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 9f41ecd5633..120929fbe7a 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -44,7 +44,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index f82e8210972..78810ba982e 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -180,6 +180,36 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = {
.channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
+ },{ /* 15 */
+ .name = "JMB361",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 16 */
+ .name = "JMB363",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 17 */
+ .name = "JMB365",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 18 */
+ .name = "JMB366",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
+ },{ /* 19 */
+ .name = "JMB368",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = OFF_BOARD,
}
};
@@ -212,6 +242,9 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
(!(PCI_FUNC(dev->devfn) & 1)))
goto out;
+ if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1)
+ goto out;
+
pci_read_config_word(dev, PCI_COMMAND, &command);
if (!(command & PCI_COMMAND_IO)) {
printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
@@ -239,6 +272,11 @@ static struct pci_device_id generic_pci_tbl[] = {
{ PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
{ PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
{ PCI_VENDOR_ID_NETCELL,PCI_DEVICE_ID_REVOLUTION, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 17},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 18},
+ { PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 19},
/* Must come last. If you add entries adjust this table appropriately and the init_one code */
{ PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
{ 0, },
diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c
index be334da7a75..b46cb042290 100644
--- a/drivers/ide/pci/hpt34x.c
+++ b/drivers/ide/pci/hpt34x.c
@@ -24,7 +24,6 @@
* Non-bootable card or HPT343 :: pcicmd == 0x05
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -176,7 +175,7 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha
pci_write_config_dword(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n",
- dev->resource[PCI_ROM_RESOURCE].start);
+ (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
}
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0xF0);
} else {
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 940bdd4c578..e993a51f250 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -55,7 +55,6 @@
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
index 93462926b9d..0fc89fafad6 100644
--- a/drivers/ide/pci/it8172.c
+++ b/drivers/ide/pci/it8172.c
@@ -28,7 +28,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 38f41b377ff..e9bad185968 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -62,7 +62,6 @@
* - Move to libata once it grows up
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -499,9 +498,14 @@ static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
- config_it821x_chipset_for_pio(drive, !speed);
- it821x_tune_chipset(drive, speed);
- return ide_dma_enable(drive);
+ if (speed) {
+ config_it821x_chipset_for_pio(drive, 0);
+ it821x_tune_chipset(drive, speed);
+
+ return ide_dma_enable(drive);
+ }
+
+ return 0;
}
/**
@@ -651,6 +655,8 @@ static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
}
ide_set_hwifdata(hwif, idev);
+ hwif->atapi_dma = 1;
+
pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
if(conf & 1) {
idev->smart = 1;
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index fcd5142f5cf..d95714bcee4 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -9,7 +9,6 @@
* Inspired by an earlier effort from David S. Miller <davem@redhat.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index acd63173199..6c097e80b4d 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -14,7 +14,6 @@
* Released under terms of General Public License
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -313,8 +312,8 @@ static unsigned int __devinit init_chipset_pdcnew(struct pci_dev *dev, const cha
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_dword(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
- name, dev->resource[PCI_ROM_RESOURCE].start);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+ (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
}
#ifdef CONFIG_PPC_PMAC
@@ -338,6 +337,8 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
hwif->ultra_mask = 0x7f;
hwif->mwdma_mask = 0x07;
+ hwif->err_stops_fifo = 1;
+
hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index 7ce5bf78368..b46022a11be 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -28,7 +28,6 @@
* Released under terms of General Public License
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -101,31 +100,6 @@ static const char *pdc_quirk_drives[] = {
#define MC1 0x02 /* DMA"C" timing */
#define MC0 0x01 /* DMA"C" timing */
-#if 0
- unsigned long bibma = pci_resource_start(dev, 4);
- u8 hi = 0, lo = 0;
-
- u8 sc1c = inb_p((u16)bibma + 0x1c);
- u8 sc1e = inb_p((u16)bibma + 0x1e);
- u8 sc1f = inb_p((u16)bibma + 0x1f);
-
- p += sprintf(p, "Host Mode : %s\n",
- (sc1f & 0x08) ? "Tri-Stated" : "Normal");
- p += sprintf(p, "Bus Clocking : %s\n",
- ((sc1f & 0xC0) == 0xC0) ? "100 External" :
- ((sc1f & 0x80) == 0x80) ? "66 External" :
- ((sc1f & 0x40) == 0x40) ? "33 External" : "33 PCI Internal");
- p += sprintf(p, "IO pad select : %s mA\n",
- ((sc1c & 0x03) == 0x03) ? "10" :
- ((sc1c & 0x02) == 0x02) ? "8" :
- ((sc1c & 0x01) == 0x01) ? "6" :
- ((sc1c & 0x00) == 0x00) ? "4" : "??");
- hi = sc1e >> 4;
- lo = sc1e & 0xf;
- p += sprintf(p, "Status Polling Period : %d\n", hi);
- p += sprintf(p, "Interrupt Check Status Polling Delay : %d\n", lo);
-#endif
-
static u8 pdc202xx_ratemask (ide_drive_t *drive)
{
u8 mode;
@@ -370,7 +344,6 @@ chipset_is_set:
if (!(speed)) {
/* restore original pci-config space */
pci_write_config_dword(dev, drive_pci, drive_conf);
- hwif->tuneproc(drive, 5);
return 0;
}
@@ -415,8 +388,6 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
if (drive->addressing == 1) {
struct request *rq = HWGROUP(drive)->rq;
ide_hwif_t *hwif = HWIF(drive);
-// struct pci_dev *dev = hwif->pci_dev;
-// unsgned long high_16 = pci_resource_start(dev, 4);
unsigned long high_16 = hwif->dma_master;
unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
u32 word_count = 0;
@@ -436,7 +407,6 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
{
if (drive->addressing == 1) {
ide_hwif_t *hwif = HWIF(drive);
-// unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
unsigned long high_16 = hwif->dma_master;
unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
u8 clock = 0;
@@ -453,8 +423,6 @@ static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
static int pdc202xx_old_ide_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = HWIF(drive);
-// struct pci_dev *dev = hwif->pci_dev;
-// unsigned long high_16 = pci_resource_start(dev, 4);
unsigned long high_16 = hwif->dma_master;
u8 dma_stat = hwif->INB(hwif->dma_status);
u8 sc1d = hwif->INB((high_16 + 0x001d));
@@ -492,12 +460,7 @@ static int pdc202xx_ide_dma_timeout(ide_drive_t *drive)
static void pdc202xx_reset_host (ide_hwif_t *hwif)
{
-#ifdef CONFIG_BLK_DEV_IDEDMA
-// unsigned long high_16 = hwif->dma_base - (8*(hwif->channel));
unsigned long high_16 = hwif->dma_master;
-#else /* !CONFIG_BLK_DEV_IDEDMA */
- unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4);
-#endif /* CONFIG_BLK_DEV_IDEDMA */
u8 udma_speed_flag = hwif->INB(high_16|0x001f);
hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f));
@@ -516,98 +479,20 @@ static void pdc202xx_reset (ide_drive_t *drive)
pdc202xx_reset_host(hwif);
pdc202xx_reset_host(mate);
-#if 0
- /*
- * FIXME: Have to kick all the drives again :-/
- * What a pain in the ACE!
- */
- if (hwif->present) {
- u16 hunit = 0;
- for (hunit = 0; hunit < MAX_DRIVES; ++hunit) {
- ide_drive_t *hdrive = &hwif->drives[hunit];
- if (hdrive->present) {
- if (hwif->ide_dma_check)
- hwif->ide_dma_check(hdrive);
- else
- hwif->tuneproc(hdrive, 5);
- }
- }
- }
- if (mate->present) {
- u16 munit = 0;
- for (munit = 0; munit < MAX_DRIVES; ++munit) {
- ide_drive_t *mdrive = &mate->drives[munit];
- if (mdrive->present) {
- if (mate->ide_dma_check)
- mate->ide_dma_check(mdrive);
- else
- mate->tuneproc(mdrive, 5);
- }
- }
- }
-#else
hwif->tuneproc(drive, 5);
-#endif
-}
-
-/*
- * Since SUN Cobalt is attempting to do this operation, I should disclose
- * this has been a long time ago Thu Jul 27 16:40:57 2000 was the patch date
- * HOTSWAP ATA Infrastructure.
- */
-static int pdc202xx_tristate (ide_drive_t * drive, int state)
-{
- ide_hwif_t *hwif = HWIF(drive);
-// unsigned long high_16 = hwif->dma_base - (8*(hwif->channel));
- unsigned long high_16 = hwif->dma_master;
- u8 sc1f = hwif->INB(high_16|0x001f);
-
- if (!hwif)
- return -EINVAL;
-
-// hwif->bus_state = state;
-
- if (state) {
- hwif->OUTB(sc1f | 0x08, (high_16|0x001f));
- } else {
- hwif->OUTB(sc1f & ~0x08, (high_16|0x001f));
- }
- return 0;
}
-static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_pdc202xx(struct pci_dev *dev,
+ const char *name)
{
+ /* This doesn't appear needed */
if (dev->resource[PCI_ROM_RESOURCE].start) {
pci_write_config_dword(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n",
- name, dev->resource[PCI_ROM_RESOURCE].start);
+ printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name,
+ (unsigned long)dev->resource[PCI_ROM_RESOURCE].start);
}
- /*
- * software reset - this is required because the bios
- * will set UDMA timing on if the hdd supports it. The
- * user may want to turn udma off. A bug in the pdc20262
- * is that it cannot handle a downgrade in timing from
- * UDMA to DMA. Disk accesses after issuing a set
- * feature command will result in errors. A software
- * reset leaves the timing registers intact,
- * but resets the drives.
- */
-#if 0
- if ((dev->device == PCI_DEVICE_ID_PROMISE_20267) ||
- (dev->device == PCI_DEVICE_ID_PROMISE_20265) ||
- (dev->device == PCI_DEVICE_ID_PROMISE_20263) ||
- (dev->device == PCI_DEVICE_ID_PROMISE_20262)) {
- unsigned long high_16 = pci_resource_start(dev, 4);
- byte udma_speed_flag = inb(high_16 + 0x001f);
- outb(udma_speed_flag | 0x10, high_16 + 0x001f);
- mdelay(100);
- outb(udma_speed_flag & ~0x10, high_16 + 0x001f);
- mdelay(2000); /* 2 seconds ?! */
- }
-
-#endif
return dev->irq;
}
@@ -624,10 +509,8 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->tuneproc = &config_chipset_for_pio;
hwif->quirkproc = &pdc202xx_quirkproc;
- if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) {
- hwif->busproc = &pdc202xx_tristate;
+ if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246)
hwif->resetproc = &pdc202xx_reset;
- }
hwif->speedproc = &pdc202xx_tune_chipset;
@@ -637,6 +520,8 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
+ hwif->err_stops_fifo = 1;
+
hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate;
hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq;
hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout;
@@ -725,19 +610,6 @@ static int __devinit init_setup_pdc202ata4(struct pci_dev *dev,
"mirror fixed.\n", d->name);
}
}
-
-#if 0
- if (dev->device == PCI_DEVICE_ID_PROMISE_20262)
- if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
- (tmp & e->mask) != e->val))
-
- if (d->enablebits[0].reg != d->enablebits[1].reg) {
- d->enablebits[0].reg = d->enablebits[1].reg;
- d->enablebits[0].mask = d->enablebits[1].mask;
- d->enablebits[0].val = d->enablebits[1].val;
- }
-#endif
-
return ide_setup_pci_device(dev, d);
}
@@ -752,22 +624,6 @@ static int __devinit init_setup_pdc20265(struct pci_dev *dev,
"attached to I2O RAID controller.\n");
return -ENODEV;
}
-
-#if 0
- {
- u8 pri = 0, sec = 0;
-
- if (e->reg && (pci_read_config_byte(dev, e->reg, &tmp) ||
- (tmp & e->mask) != e->val))
-
- if (d->enablebits[0].reg != d->enablebits[1].reg) {
- d->enablebits[0].reg = d->enablebits[1].reg;
- d->enablebits[0].mask = d->enablebits[1].mask;
- d->enablebits[0].val = d->enablebits[1].val;
- }
- }
-#endif
-
return ide_setup_pci_device(dev, d);
}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index e9b83e1a302..50332ddd5dd 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -90,7 +90,6 @@
* ICH3 errata #18 - Don't use native mode
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -222,6 +221,8 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
unsigned long flags;
u16 master_data;
u8 slave_data;
+ static DEFINE_SPINLOCK(tune_lock);
+
/* ISP RTC */
u8 timings[][2] = { { 0, 0 },
{ 0, 0 },
@@ -230,7 +231,13 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
{ 2, 3 }, };
pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
- spin_lock_irqsave(&ide_lock, flags);
+
+ /*
+ * Master vs slave is synchronized above us but the slave register is
+ * shared by the two hwifs so the corner case of two slave timeouts in
+ * parallel must be locked.
+ */
+ spin_lock_irqsave(&tune_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
if (is_slave) {
master_data = master_data | 0x4000;
@@ -250,7 +257,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
pci_write_config_word(dev, master_port, master_data);
if (is_slave)
pci_write_config_byte(dev, slave_port, slave_data);
- spin_unlock_irqrestore(&ide_lock, flags);
+ spin_unlock_irqrestore(&tune_lock, flags);
}
/**
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 24e21b2838c..fc2b5496b6d 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -11,7 +11,6 @@
* Available from National Semiconductor
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -395,7 +394,6 @@ static int sc1200_resume (struct pci_dev *dev)
{
ide_hwif_t *hwif = NULL;
-printk("SC1200: resume\n");
pci_set_power_state(dev, PCI_D0); // bring chip back from sleep state
dev->current_state = PM_EVENT_ON;
pci_enable_device(dev);
@@ -405,7 +403,6 @@ printk("SC1200: resume\n");
while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) {
unsigned int basereg, r, d, format;
sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data;
-printk("%s: SC1200: resume\n", hwif->name);
//
// Restore timing registers: this may be unnecessary if BIOS also does it
@@ -493,7 +490,7 @@ static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_devic
}
static struct pci_device_id sc1200_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, sc1200_pci_tbl);
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 0d3073f4eab..f063d954236 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -29,7 +29,6 @@
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -123,11 +122,11 @@ static u8 svwks_csb_check (struct pci_dev *dev)
}
static int svwks_tune_chipset (ide_drive_t *drive, u8 xferspeed)
{
- u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
- u8 dma_modes[] = { 0x77, 0x21, 0x20 };
- u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
- u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
- u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
+ static const u8 udma_modes[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05 };
+ static const u8 dma_modes[] = { 0x77, 0x21, 0x20 };
+ static const u8 pio_modes[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 };
+ static const u8 drive_pci[] = { 0x41, 0x40, 0x43, 0x42 };
+ static const u8 drive_pci2[] = { 0x45, 0x44, 0x47, 0x46 };
ide_hwif_t *hwif = HWIF(drive);
struct pci_dev *dev = hwif->pci_dev;
@@ -392,16 +391,6 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
}
outb_p(0x06, 0x0c00);
dev->irq = inb_p(0x0c01);
-#if 0
- printk("%s: device class (0x%04x)\n",
- name, dev->class);
- if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) {
- dev->class &= ~0x000F0F00;
- // dev->class |= ~0x00000400;
- dev->class |= ~0x00010100;
- /**/
- }
-#endif
} else {
struct pci_dev * findev = NULL;
u8 reg41 = 0;
@@ -452,7 +441,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
pci_write_config_byte(dev, 0x5A, btr);
}
- return (dev->irq) ? dev->irq : 0;
+ return dev->irq;
}
static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
@@ -500,11 +489,6 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
- /* Per Specified Design by OEM, and ASIC Architect */
- if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
- return 1;
-
/* Server Works */
if (dev->subsystem_vendor == PCI_VENDOR_ID_SERVERWORKS)
return ata66_svwks_svwks (hwif);
@@ -517,10 +501,14 @@ static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN)
return ata66_svwks_cobalt (hwif);
+ /* Per Specified Design by OEM, and ASIC Architect */
+ if ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) ||
+ (dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2))
+ return 1;
+
return 0;
}
-#undef CAN_SW_DMA
static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
{
u8 dma_stat = 0;
@@ -537,9 +525,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
hwif->ultra_mask = 0x3f;
hwif->mwdma_mask = 0x07;
-#ifdef CAN_SW_DMA
- hwif->swdma_mask = 0x07;
-#endif /* CAN_SW_DMA */
hwif->autodma = 0;
@@ -562,8 +547,6 @@ static void __devinit init_hwif_svwks (ide_hwif_t *hwif)
hwif->drives[1].autodma = (dma_stat & 0x40);
hwif->drives[0].autotune = (!(dma_stat & 0x20));
hwif->drives[1].autotune = (!(dma_stat & 0x40));
-// hwif->drives[0].autodma = hwif->autodma;
-// hwif->drives[1].autodma = hwif->autodma;
}
/*
@@ -593,11 +576,6 @@ static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
if (dev->resource[0].start == 0x01f1)
d->bootable = ON_BOARD;
}
-#if 0
- if ((IDE_PCI_DEVID_EQ(d->devid, DEVID_CSB6) &&
- (!(PCI_FUNC(dev->devfn) & 1)))
- d->autodma = AUTODMA;
-#endif
d->channels = ((dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE ||
dev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) &&
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index e125032bb40..d8a0d87df73 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -367,12 +367,13 @@ sgiioc4_INB(unsigned long port)
static void __devinit
ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
{
+ void __iomem *virt_dma_base;
int num_ports = sizeof (ioc4_dma_regs_t);
printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
dma_base, dma_base + num_ports - 1);
- if (!request_region(dma_base, num_ports, hwif->name)) {
+ if (!request_mem_region(dma_base, num_ports, hwif->name)) {
printk(KERN_ERR
"%s(%s) -- ERROR, Addresses 0x%p to 0x%p "
"ALREADY in use\n",
@@ -381,13 +382,21 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
goto dma_alloc_failure;
}
- hwif->dma_base = dma_base;
+ virt_dma_base = ioremap(dma_base, num_ports);
+ if (virt_dma_base == NULL) {
+ printk(KERN_ERR
+ "%s(%s) -- ERROR, Unable to map addresses 0x%lx to 0x%lx\n",
+ __FUNCTION__, hwif->name, dma_base, dma_base + num_ports - 1);
+ goto dma_remap_failure;
+ }
+ hwif->dma_base = (unsigned long) virt_dma_base;
+
hwif->dmatable_cpu = pci_alloc_consistent(hwif->pci_dev,
IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
&hwif->dmatable_dma);
if (!hwif->dmatable_cpu)
- goto dma_alloc_failure;
+ goto dma_pci_alloc_failure;
hwif->sg_max_nents = IOC4_PRD_ENTRIES;
@@ -411,6 +420,12 @@ dma_base2alloc_failure:
printk(KERN_INFO
"Changing from DMA to PIO mode for Drive %s\n", hwif->name);
+dma_pci_alloc_failure:
+ iounmap(virt_dma_base);
+
+dma_remap_failure:
+ release_mem_region(dma_base, num_ports);
+
dma_alloc_failure:
/* Disable DMA because we couldnot allocate any DMA maps */
hwif->autodma = 0;
@@ -607,18 +622,15 @@ ide_init_sgiioc4(ide_hwif_t * hwif)
hwif->ide_dma_lostirq = &sgiioc4_ide_dma_lostirq;
hwif->ide_dma_timeout = &__ide_dma_timeout;
- /*
- * The IOC4 uses MMIO rather than Port IO.
- * It also needs special workarounds for INB.
- */
- default_hwif_mmiops(hwif);
hwif->INB = &sgiioc4_INB;
}
static int __devinit
sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
{
- unsigned long base, ctl, dma_base, irqport;
+ unsigned long cmd_base, dma_base, irqport;
+ unsigned long bar0, cmd_phys_base, ctl;
+ void __iomem *virt_base;
ide_hwif_t *hwif;
int h;
@@ -636,23 +648,32 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
}
/* Get the CmdBlk and CtrlBlk Base Registers */
- base = pci_resource_start(dev, 0) + IOC4_CMD_OFFSET;
- ctl = pci_resource_start(dev, 0) + IOC4_CTRL_OFFSET;
- irqport = pci_resource_start(dev, 0) + IOC4_INTR_OFFSET;
+ bar0 = pci_resource_start(dev, 0);
+ virt_base = ioremap(bar0, pci_resource_len(dev, 0));
+ if (virt_base == NULL) {
+ printk(KERN_ERR "%s: Unable to remap BAR 0 address: 0x%lx\n",
+ d->name, bar0);
+ return -ENOMEM;
+ }
+ cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET;
+ ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET;
+ irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET;
dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET;
- if (!request_region(base, IOC4_CMD_CTL_BLK_SIZE, hwif->name)) {
+ cmd_phys_base = bar0 + IOC4_CMD_OFFSET;
+ if (!request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE,
+ hwif->name)) {
printk(KERN_ERR
- "%s : %s -- ERROR, Port Addresses "
+ "%s : %s -- ERROR, Addresses "
"0x%p to 0x%p ALREADY in use\n",
- __FUNCTION__, hwif->name, (void *) base,
- (void *) base + IOC4_CMD_CTL_BLK_SIZE);
+ __FUNCTION__, hwif->name, (void *) cmd_phys_base,
+ (void *) cmd_phys_base + IOC4_CMD_CTL_BLK_SIZE);
return -ENOMEM;
}
- if (hwif->io_ports[IDE_DATA_OFFSET] != base) {
+ if (hwif->io_ports[IDE_DATA_OFFSET] != cmd_base) {
/* Initialize the IO registers */
- sgiioc4_init_hwif_ports(&hwif->hw, base, ctl, irqport);
+ sgiioc4_init_hwif_ports(&hwif->hw, cmd_base, ctl, irqport);
memcpy(hwif->io_ports, hwif->hw.io_ports,
sizeof (hwif->io_ports));
hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET];
@@ -665,6 +686,9 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev, ide_pci_device_t * d)
hwif->cds = (struct ide_pci_device_s *) d;
hwif->gendev.parent = &dev->dev;/* setup proper ancestral information */
+ /* The IOC4 uses MMIO rather than Port IO. */
+ default_hwif_mmiops(hwif);
+
/* Initializing chipset IRQ Registers */
hwif->OUTL(0x03, irqport + IOC4_INTR_SET * 4);
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index f1ca154dd52..20b392948f3 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -27,7 +27,6 @@
* if neccessary
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -38,9 +37,6 @@
#include <asm/io.h>
-#undef SIIMAGE_VIRTUAL_DMAPIO
-#undef SIIMAGE_LARGE_DMA
-
/**
* pdev_is_sata - check if device is SATA
* @pdev: PCI device to check
@@ -461,36 +457,6 @@ static int siimage_io_ide_dma_test_irq (ide_drive_t *drive)
return 0;
}
-#if 0
-/**
- * siimage_mmio_ide_dma_count - DMA bytes done
- * @drive
- *
- * If we are doing VDMA the CMD680 requires a little bit
- * of more careful handling and we have to read the counts
- * off ourselves. For non VDMA life is normal.
- */
-
-static int siimage_mmio_ide_dma_count (ide_drive_t *drive)
-{
-#ifdef SIIMAGE_VIRTUAL_DMAPIO
- struct request *rq = HWGROUP(drive)->rq;
- ide_hwif_t *hwif = HWIF(drive);
- u32 count = (rq->nr_sectors * SECTOR_SIZE);
- u32 rcount = 0;
- unsigned long addr = siimage_selreg(hwif, 0x1C);
-
- hwif->OUTL(count, addr);
- rcount = hwif->INL(addr);
-
- printk("\n%s: count = %d, rcount = %d, nr_sectors = %lu\n",
- drive->name, count, rcount, rq->nr_sectors);
-
-#endif /* SIIMAGE_VIRTUAL_DMAPIO */
- return __ide_dma_count(drive);
-}
-#endif
-
/**
* siimage_mmio_ide_dma_test_irq - check we caused an IRQ
* @drive: drive we are testing
@@ -512,12 +478,10 @@ static int siimage_mmio_ide_dma_test_irq (ide_drive_t *drive)
u32 sata_error = hwif->INL(SATA_ERROR_REG);
hwif->OUTL(sata_error, SATA_ERROR_REG);
watchdog = (sata_error & 0x00680000) ? 1 : 0;
-#if 1
printk(KERN_WARNING "%s: sata_error = 0x%08x, "
"watchdog = %d, %s\n",
drive->name, sata_error, watchdog,
__FUNCTION__);
-#endif
} else {
watchdog = (ext_stat & 0x8000) ? 1 : 0;
@@ -863,7 +827,7 @@ static unsigned int __devinit init_chipset_siimage(struct pci_dev *dev, const ch
* time.
*
* The hardware supports buffered taskfiles and also some rather nice
- * extended PRD tables. Unfortunately right now we don't.
+ * extended PRD tables. For better SI3112 support use the libata driver
*/
static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
@@ -900,9 +864,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
* so we can't currently use it sanely since we want to
* use LBA48 mode.
*/
-// base += 0x10;
-// hwif->no_lba48 = 1;
-
hw.io_ports[IDE_DATA_OFFSET] = base;
hw.io_ports[IDE_ERROR_OFFSET] = base + 1;
hw.io_ports[IDE_NSECTOR_OFFSET] = base + 2;
@@ -936,15 +897,8 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
base = (unsigned long) addr;
-#ifdef SIIMAGE_LARGE_DMA
-/* Watch the brackets - even Ken and Dennis get some language design wrong */
- hwif->dma_base = base + (ch ? 0x18 : 0x10);
- hwif->dma_base2 = base + (ch ? 0x08 : 0x00);
- hwif->dma_prdtable = hwif->dma_base2 + 4;
-#else /* ! SIIMAGE_LARGE_DMA */
hwif->dma_base = base + (ch ? 0x08 : 0x00);
hwif->dma_base2 = base + (ch ? 0x18 : 0x10);
-#endif /* SIIMAGE_LARGE_DMA */
hwif->mmio = 2;
}
@@ -1052,9 +1006,16 @@ static void __devinit init_hwif_siimage(ide_hwif_t *hwif)
hwif->reset_poll = &siimage_reset_poll;
hwif->pre_reset = &siimage_pre_reset;
- if(is_sata(hwif))
+ if(is_sata(hwif)) {
+ static int first = 1;
+
hwif->busproc = &siimage_busproc;
+ if (first) {
+ printk(KERN_INFO "siimage: For full SATA support you should use the libata sata_sil module.\n");
+ first = 0;
+ }
+ }
if (!hwif->dma_base) {
hwif->drives[0].autotune = 1;
hwif->drives[1].autotune = 1;
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index 8e9d87701ce..f03196c5db3 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -44,7 +44,6 @@
* 962/963.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -87,6 +86,8 @@ static const struct {
u8 chipset_family;
u8 flags;
} SiSHostChipInfo[] = {
+ { "SiS968", PCI_DEVICE_ID_SI_968, ATA_133 },
+ { "SiS966", PCI_DEVICE_ID_SI_966, ATA_133 },
{ "SiS965", PCI_DEVICE_ID_SI_965, ATA_133 },
{ "SiS745", PCI_DEVICE_ID_SI_745, ATA_100 },
{ "SiS735", PCI_DEVICE_ID_SI_735, ATA_100 },
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 8a5c7b286b2..0b4b6049851 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -13,7 +13,6 @@
* -- Benjamin Herrenschmidt (01/11/03) benh@kernel.crashing.org
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -447,7 +446,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
printk(" %s: Winbond 553 bridge revision %d, BM-DMA disabled\n",
hwif->name, rev);
} else {
-#ifdef CONFIG_BLK_DEV_IDEDMA
dma_state |= 0x60;
hwif->atapi_dma = 1;
@@ -468,7 +466,6 @@ static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
}
hwif->OUTB(dma_state, hwif->dma_base + 2);
}
@@ -489,7 +486,7 @@ static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_dev
}
static struct pci_device_id sl82c105_pci_tbl[] = {
- { PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, sl82c105_pci_tbl);
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 5112c726633..4a1853af3bb 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -72,7 +71,8 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
u16 master_data;
u8 slave_data;
/* ISP RTC */
- u8 timings[][2] = { { 0, 0 },
+ static const u8 timings[][2]= {
+ { 0, 0 },
{ 0, 0 },
{ 1, 0 },
{ 2, 1 },
@@ -119,7 +119,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
pci_read_config_word(dev, 0x4a, &reg4a);
switch(speed) {
-#ifdef CONFIG_BLK_DEV_IDEDMA
case XFER_UDMA_4: u_speed = 4 << (drive->dn * 4); break;
case XFER_UDMA_3: u_speed = 3 << (drive->dn * 4); break;
case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break;
@@ -128,7 +127,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
case XFER_MW_DMA_2:
case XFER_MW_DMA_1:
case XFER_SW_DMA_2: break;
-#endif /* CONFIG_BLK_DEV_IDEDMA */
case XFER_PIO_4:
case XFER_PIO_3:
case XFER_PIO_2:
@@ -156,7 +154,6 @@ static int slc90e66_tune_chipset (ide_drive_t *drive, u8 xferspeed)
return (ide_config_drive_speed(drive, speed));
}
-#ifdef CONFIG_BLK_DEV_IDEDMA
static int slc90e66_config_drive_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, slc90e66_ratemask(drive));
@@ -194,7 +191,6 @@ fast_ata_pio:
/* IORDY not supported */
return 0;
}
-#endif /* CONFIG_BLK_DEV_IDEDMA */
static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
{
@@ -222,7 +218,6 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
-#ifdef CONFIG_BLK_DEV_IDEDMA
if (!(hwif->udma_four))
/* bit[0(1)]: 0:80, 1:40 */
hwif->udma_four = (reg47 & mask) ? 0 : 1;
@@ -232,7 +227,6 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
hwif->autodma = 1;
hwif->drives[0].autodma = hwif->autodma;
hwif->drives[1].autodma = hwif->autodma;
-#endif /* !CONFIG_BLK_DEV_IDEDMA */
}
static ide_pci_device_t slc90e66_chipset __devinitdata = {
@@ -250,7 +244,7 @@ static int __devinit slc90e66_init_one(struct pci_dev *dev, const struct pci_dev
}
static struct pci_device_id slc90e66_pci_tbl[] = {
- { PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_1), 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, slc90e66_pci_tbl);
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index f96b56838f3..56d84931d6d 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -27,7 +27,6 @@
* Not publically available.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/trm290.c b/drivers/ide/pci/trm290.c
index fe80295974e..2a282529bfc 100644
--- a/drivers/ide/pci/trm290.c
+++ b/drivers/ide/pci/trm290.c
@@ -128,7 +128,6 @@
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 3e677c4f8c2..9b7589e8e93 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -6,7 +6,7 @@
*
* vt82c576, vt82c586, vt82c586a, vt82c586b, vt82c596a, vt82c596b,
* vt82c686, vt82c686a, vt82c686b, vt8231, vt8233, vt8233c, vt8233a,
- * vt8235, vt8237
+ * vt8235, vt8237, vt8237a
*
* Copyright (c) 2000-2002 Vojtech Pavlik
*
@@ -26,7 +26,6 @@
* the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -82,6 +81,7 @@ static struct via_isa_bridge {
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
+ { "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8233a", PCI_DEVICE_ID_VIA_8233A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
{ "vt8233c", PCI_DEVICE_ID_VIA_8233C_0, 0x00, 0x2f, VIA_UDMA_100 },
diff --git a/drivers/ide/ppc/mpc8xx.c b/drivers/ide/ppc/mpc8xx.c
index b80c6135ae9..0ac9da3a737 100644
--- a/drivers/ide/ppc/mpc8xx.c
+++ b/drivers/ide/ppc/mpc8xx.c
@@ -11,7 +11,6 @@
* by Mathew Locke <mattl@mvista.com>
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index ffca8b63ee7..31ad79f52df 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -22,7 +22,6 @@
* big table
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -421,107 +420,6 @@ static void pmac_ide_kauai_selectproc(ide_drive_t *drive);
#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
/*
- * Below is the code for blinking the laptop LED along with hard
- * disk activity.
- */
-
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
-
-/* Set to 50ms minimum led-on time (also used to limit frequency
- * of requests sent to the PMU
- */
-#define PMU_HD_BLINK_TIME (HZ/50)
-
-static struct adb_request pmu_blink_on, pmu_blink_off;
-static spinlock_t pmu_blink_lock;
-static unsigned long pmu_blink_stoptime;
-static int pmu_blink_ledstate;
-static struct timer_list pmu_blink_timer;
-static int pmu_ide_blink_enabled;
-
-
-static void
-pmu_hd_blink_timeout(unsigned long data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&pmu_blink_lock, flags);
-
- /* We may have been triggered again in a racy way, check
- * that we really want to switch it off
- */
- if (time_after(pmu_blink_stoptime, jiffies))
- goto done;
-
- /* Previous req. not complete, try 100ms more */
- if (pmu_blink_off.complete == 0)
- mod_timer(&pmu_blink_timer, jiffies + PMU_HD_BLINK_TIME);
- else if (pmu_blink_ledstate) {
- pmu_request(&pmu_blink_off, NULL, 4, 0xee, 4, 0, 0);
- pmu_blink_ledstate = 0;
- }
-done:
- spin_unlock_irqrestore(&pmu_blink_lock, flags);
-}
-
-static void
-pmu_hd_kick_blink(void *data, int rw)
-{
- unsigned long flags;
-
- pmu_blink_stoptime = jiffies + PMU_HD_BLINK_TIME;
- wmb();
- mod_timer(&pmu_blink_timer, pmu_blink_stoptime);
- /* Fast path when LED is already ON */
- if (pmu_blink_ledstate == 1)
- return;
- spin_lock_irqsave(&pmu_blink_lock, flags);
- if (pmu_blink_on.complete && !pmu_blink_ledstate) {
- pmu_request(&pmu_blink_on, NULL, 4, 0xee, 4, 0, 1);
- pmu_blink_ledstate = 1;
- }
- spin_unlock_irqrestore(&pmu_blink_lock, flags);
-}
-
-static int
-pmu_hd_blink_init(void)
-{
- struct device_node *dt;
- const char *model;
-
- /* Currently, I only enable this feature on KeyLargo based laptops,
- * older laptops may support it (at least heathrow/paddington) but
- * I don't feel like loading those venerable old machines with so
- * much additional interrupt & PMU activity...
- */
- if (pmu_get_model() != PMU_KEYLARGO_BASED)
- return 0;
-
- dt = of_find_node_by_path("/");
- if (dt == NULL)
- return 0;
- model = (const char *)get_property(dt, "model", NULL);
- if (model == NULL)
- return 0;
- if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
- strncmp(model, "iBook", strlen("iBook")) != 0) {
- of_node_put(dt);
- return 0;
- }
- of_node_put(dt);
-
- pmu_blink_on.complete = 1;
- pmu_blink_off.complete = 1;
- spin_lock_init(&pmu_blink_lock);
- init_timer(&pmu_blink_timer);
- pmu_blink_timer.function = pmu_hd_blink_timeout;
-
- return 1;
-}
-
-#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
-
-/*
* N.B. this can't be an initfunc, because the media-bay task can
* call ide_[un]register at any time.
*/
@@ -1192,23 +1090,6 @@ pmac_ide_do_suspend(ide_hwif_t *hwif)
pmif->timings[0] = 0;
pmif->timings[1] = 0;
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
- /* Note: This code will be called for every hwif, thus we'll
- * try several time to stop the LED blinker timer, but that
- * should be harmless
- */
- if (pmu_ide_blink_enabled) {
- unsigned long flags;
-
- /* Make sure we don't hit the PMU blink */
- spin_lock_irqsave(&pmu_blink_lock, flags);
- if (pmu_blink_ledstate)
- del_timer(&pmu_blink_timer);
- pmu_blink_ledstate = 0;
- spin_unlock_irqrestore(&pmu_blink_lock, flags);
- }
-#endif /* CONFIG_BLK_DEV_IDE_PMAC_BLINK */
-
disable_irq(pmif->irq);
/* The media bay will handle itself just fine */
@@ -1273,7 +1154,7 @@ static int
pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
{
struct device_node *np = pmif->node;
- int *bidp;
+ const int *bidp;
pmif->cable_80 = 0;
pmif->broken_dma = pmif->broken_dma_warn = 0;
@@ -1295,14 +1176,14 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
pmif->broken_dma = 1;
}
- bidp = (int *)get_property(np, "AAPL,bus-id", NULL);
+ bidp = get_property(np, "AAPL,bus-id", NULL);
pmif->aapl_bus_id = bidp ? *bidp : 0;
/* Get cable type from device-tree */
if (pmif->kind == controller_kl_ata4 || pmif->kind == controller_un_ata6
|| pmif->kind == controller_k2_ata6
|| pmif->kind == controller_sh_ata6) {
- char* cable = get_property(np, "cable-type", NULL);
+ const char* cable = get_property(np, "cable-type", NULL);
if (cable && !strncmp(cable, "80-", 3))
pmif->cable_80 = 1;
}
@@ -1376,13 +1257,6 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->selectproc = pmac_ide_selectproc;
hwif->speedproc = pmac_ide_tune_chipset;
-#ifdef CONFIG_BLK_DEV_IDE_PMAC_BLINK
- pmu_ide_blink_enabled = pmu_hd_blink_init();
-
- if (pmu_ide_blink_enabled)
- hwif->led_act = pmu_hd_kick_blink;
-#endif
-
printk(KERN_INFO "ide%d: Found Apple %s controller, bus ID %d%s, irq %d\n",
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
pmif->mediabay ? " (mediabay)" : "", hwif->irq);
@@ -1452,7 +1326,7 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
if (macio_irq_count(mdev) == 0) {
printk(KERN_WARNING "ide%d: no intrs for device %s, using 13\n",
i, mdev->ofdev.node->full_name);
- irq = 13;
+ irq = irq_create_mapping(NULL, 13);
} else
irq = macio_irq(mdev, 0);
@@ -1495,15 +1369,16 @@ pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
}
static int
-pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t state)
+pmac_ide_macio_suspend(struct macio_dev *mdev, pm_message_t mesg)
{
ide_hwif_t *hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
int rc = 0;
- if (state.event != mdev->ofdev.dev.power.power_state.event && state.event >= PM_EVENT_SUSPEND) {
+ if (mesg.event != mdev->ofdev.dev.power.power_state.event
+ && mesg.event == PM_EVENT_SUSPEND) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
- mdev->ofdev.dev.power.power_state = state;
+ mdev->ofdev.dev.power.power_state = mesg;
}
return rc;
@@ -1599,15 +1474,16 @@ pmac_ide_pci_attach(struct pci_dev *pdev, const struct pci_device_id *id)
}
static int
-pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+pmac_ide_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
ide_hwif_t *hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
int rc = 0;
- if (state.event != pdev->dev.power.power_state.event && state.event >= 2) {
+ if (mesg.event != pdev->dev.power.power_state.event
+ && mesg.event == PM_EVENT_SUSPEND) {
rc = pmac_ide_do_suspend(hwif);
if (rc == 0)
- pdev->dev.power.power_state = state;
+ pdev->dev.power.power_state = mesg;
}
return rc;
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index c11e3b2e67a..eb0945284ac 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -18,7 +18,6 @@
* configuration of all PCI IDE interfaces present in a system.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 79b81be6797..186737539cf 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -4,7 +4,7 @@ menu "IEEE 1394 (FireWire) support"
config IEEE1394
tristate "IEEE 1394 (FireWire) support"
- depends on (PCI || BROKEN) && (BROKEN || !FRV)
+ depends on PCI || BROKEN
select NET
help
IEEE 1394 describes a high performance serial bus, which is also
diff --git a/drivers/ieee1394/config_roms.c b/drivers/ieee1394/config_roms.c
index 1017fd71724..e2de6fa0c9f 100644
--- a/drivers/ieee1394/config_roms.c
+++ b/drivers/ieee1394/config_roms.c
@@ -9,7 +9,6 @@
* directory of the kernel sources for details.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include "csr1212.h"
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 85c2d4ca0de..87532dd4337 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -83,7 +83,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 5bda15904a0..2d5b57be98c 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -1074,8 +1074,7 @@ static inline int update_partial_datagram(struct list_head *pdgl, struct list_he
/* Move list entry to beginnig of list so that oldest partial
* datagrams percolate to the end of the list */
- list_del(lh);
- list_add(lh, pdgl);
+ list_move(lh, pdgl);
return 0;
}
diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c
index 25b22609e79..694da82d820 100644
--- a/drivers/ieee1394/highlevel.c
+++ b/drivers/ieee1394/highlevel.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/bitops.h>
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 2d47b11777a..4feead4a35c 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -10,7 +10,6 @@
* directory of the kernel sources for details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -103,11 +102,19 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
* driver specific parts, enable the controller and make it available
* to the general subsystem using hpsb_add_host().
*
- * Return Value: a pointer to the &hpsb_host if succesful, %NULL if
+ * Return Value: a pointer to the &hpsb_host if successful, %NULL if
* no memory was available.
*/
static DEFINE_MUTEX(host_num_alloc);
+/*
+ * The pending_packet_queue is special in that it's processed
+ * from hardirq context too (such as hpsb_bus_reset()). Hence
+ * split the lock class from the usual networking skb-head
+ * lock class by using a separate key for it:
+ */
+static struct lock_class_key pending_packet_queue_key;
+
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
struct device *dev)
{
@@ -129,6 +136,8 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
h->driver = drv;
skb_queue_head_init(&h->pending_packet_queue);
+ lockdep_set_class(&h->pending_packet_queue.lock,
+ &pending_packet_queue_key);
INIT_LIST_HEAD(&h->addr_space);
for (i = 2; i < 16; i++)
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 49354de9fb8..f43739c5cab 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index e7b55e895f5..0ecbf335c64 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -139,7 +139,7 @@ int hpsb_bus_reset(struct hpsb_host *host);
/*
* Hand over received selfid packet to the core. Complement check (second
- * quadlet is complement of first) is expected to be done and succesful.
+ * quadlet is complement of first) is expected to be done and successful.
*/
void hpsb_selfid_received(struct hpsb_host *host, quadlet_t sid);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 948f1b8c423..d541b508a15 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -8,8 +8,8 @@
* directory of the kernel sources for details.
*/
+#include <linux/bitmap.h>
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
@@ -334,10 +334,12 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribut
static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
+/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
+ * here, therefore displayed values may be occasionally wrong. */
static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
- return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);
+ return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
}
static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 3d278412e1c..448df277337 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -82,7 +82,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
@@ -590,11 +589,11 @@ static void ohci_initialize(struct ti_ohci *ohci)
buf = reg_read(ohci, OHCI1394_Version);
sprintf (irq_buf, "%d", ohci->dev->irq);
PRINT(KERN_INFO, "OHCI-1394 %d.%d (PCI): IRQ=[%s] "
- "MMIO=[%lx-%lx] Max Packet=[%d] IR/IT contexts=[%d/%d]",
+ "MMIO=[%llx-%llx] Max Packet=[%d] IR/IT contexts=[%d/%d]",
((((buf) >> 16) & 0xf) + (((buf) >> 20) & 0xf) * 10),
((((buf) >> 4) & 0xf) + ((buf) & 0xf) * 10), irq_buf,
- pci_resource_start(ohci->dev, 0),
- pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
+ (unsigned long long)pci_resource_start(ohci->dev, 0),
+ (unsigned long long)pci_resource_start(ohci->dev, 0) + OHCI1394_REGISTER_SIZE - 1,
ohci->max_packet_size,
ohci->nb_iso_rcv_ctx, ohci->nb_iso_xmit_ctx);
@@ -3217,7 +3216,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
{
struct hpsb_host *host;
struct ti_ohci *ohci; /* shortcut to currently handled device */
- unsigned long ohci_base;
+ resource_size_t ohci_base;
if (pci_enable_device(dev))
FAIL(-ENXIO, "Failed to enable OHCI hardware");
@@ -3270,15 +3269,16 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
* clearly says it's 2kb, so this shouldn't be a problem. */
ohci_base = pci_resource_start(dev, 0);
if (pci_resource_len(dev, 0) < OHCI1394_REGISTER_SIZE)
- PRINT(KERN_WARNING, "PCI resource length of %lx too small!",
- pci_resource_len(dev, 0));
+ PRINT(KERN_WARNING, "PCI resource length of 0x%llx too small!",
+ (unsigned long long)pci_resource_len(dev, 0));
/* Seems PCMCIA handles this internally. Not sure why. Seems
* pretty bogus to force a driver to special case this. */
#ifndef PCMCIA
if (!request_mem_region (ohci_base, OHCI1394_REGISTER_SIZE, OHCI1394_DRIVER_NAME))
- FAIL(-ENOMEM, "MMIO resource (0x%lx - 0x%lx) unavailable",
- ohci_base, ohci_base + OHCI1394_REGISTER_SIZE);
+ FAIL(-ENOMEM, "MMIO resource (0x%llx - 0x%llx) unavailable",
+ (unsigned long long)ohci_base,
+ (unsigned long long)ohci_base + OHCI1394_REGISTER_SIZE);
#endif
ohci->init_state = OHCI_INIT_HAVE_MEM_REGION;
@@ -3392,12 +3392,12 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
spin_lock_init(&ohci->event_lock);
/*
- * interrupts are disabled, all right, but... due to SA_SHIRQ we
+ * interrupts are disabled, all right, but... due to IRQF_SHARED we
* might get called anyway. We'll see no event, of course, but
* we need to get to that "no event", so enough should be initialized
* by that point.
*/
- if (request_irq(dev->irq, ohci_irq_handler, SA_SHIRQ,
+ if (request_irq(dev->irq, ohci_irq_handler, IRQF_SHARED,
OHCI1394_DRIVER_NAME, ohci))
FAIL(-ENOMEM, "Failed to allocate shared interrupt %d", dev->irq);
@@ -3552,6 +3552,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
+ pci_save_state(pdev);
+
#ifdef CONFIG_PPC_PMAC
if (machine_is(powermac)) {
struct device_node *of_node;
@@ -3563,8 +3565,6 @@ static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
}
#endif
- pci_save_state(pdev);
-
return 0;
}
diff --git a/drivers/ieee1394/oui2c.sh b/drivers/ieee1394/oui2c.sh
index d50dc7a2d08..b9d0e8f10ab 100644
--- a/drivers/ieee1394/oui2c.sh
+++ b/drivers/ieee1394/oui2c.sh
@@ -3,7 +3,6 @@
cat <<EOF
/* Generated file for OUI database */
-#include <linux/config.h>
#ifdef CONFIG_IEEE1394_OUI_DB
struct oui_list_struct {
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index e29dfd280be..b4f146f2c95 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -30,7 +30,6 @@
* Enhancements in async and iso send code
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
@@ -138,7 +137,6 @@ static struct i2c_algo_bit_data bit_data = {
.getsda = bit_getsda,
.getscl = bit_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = 100,
};
@@ -1254,7 +1252,7 @@ static int __devinit add_card(struct pci_dev *dev,
sprintf (irq_buf, "%d", dev->irq);
- if (!request_irq(dev->irq, lynx_irq_handler, SA_SHIRQ,
+ if (!request_irq(dev->irq, lynx_irq_handler, IRQF_SHARED,
PCILYNX_DRIVER_NAME, lynx)) {
PRINT(KERN_INFO, lynx->id, "allocated interrupt %s", irq_buf);
lynx->state = have_intr;
diff --git a/drivers/ieee1394/pcilynx.h b/drivers/ieee1394/pcilynx.h
index d631aa8383a..ec27321f672 100644
--- a/drivers/ieee1394/pcilynx.h
+++ b/drivers/ieee1394/pcilynx.h
@@ -1,7 +1,6 @@
#ifndef __PCILYNX_H__
#define __PCILYNX_H__
-#include <linux/config.h>
#define PCILYNX_DRIVER_NAME "pcilynx"
#define PCILYNX_MAJOR 177
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 20ce539580f..571ea68c0cf 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -132,8 +132,7 @@ static void free_pending_request(struct pending_request *req)
static void __queue_complete_req(struct pending_request *req)
{
struct file_info *fi = req->file_info;
- list_del(&req->list);
- list_add_tail(&req->list, &fi->req_complete);
+ list_move_tail(&req->list, &fi->req_complete);
up(&fi->complete_sem);
wake_up_interruptible(&fi->poll_wait_complete);
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 1d5ceb7ecc8..b08755e2e68 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -38,7 +38,6 @@
* but the code needs additional debugging.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/string.h>
@@ -2516,6 +2515,9 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_8 = 1;
if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
sdev->fix_capacity = 1;
+ if (scsi_id->ne->guid_vendor_id == 0x0010b9 && /* Maxtor's OUI */
+ (sdev->type == TYPE_DISK || sdev->type == TYPE_RBC))
+ sdev->allow_restart = 1;
return 0;
}
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index 295d0f8c3d0..c6e3f02bc6d 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -28,7 +28,6 @@
* ENOTTY for unsupported ioctl request
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index ba2d6505e9a..9edfacee7d8 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -14,7 +14,7 @@ config INFINIBAND_USER_MAD
---help---
Userspace InfiniBand Management Datagram (MAD) support. This
is the kernel side of the userspace MAD support, which allows
- userspace processes to send and receive MADs. You will also
+ userspace processes to send and receive MADs. You will also
need libibumad from <http://www.openib.org>.
config INFINIBAND_USER_ACCESS
@@ -36,9 +36,13 @@ config INFINIBAND_ADDR_TRANS
source "drivers/infiniband/hw/mthca/Kconfig"
source "drivers/infiniband/hw/ipath/Kconfig"
+source "drivers/infiniband/hw/ehca/Kconfig"
+source "drivers/infiniband/hw/amso1100/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
source "drivers/infiniband/ulp/srp/Kconfig"
+source "drivers/infiniband/ulp/iser/Kconfig"
+
endmenu
diff --git a/drivers/infiniband/Makefile b/drivers/infiniband/Makefile
index eea27322a22..2b5d1098ef4 100644
--- a/drivers/infiniband/Makefile
+++ b/drivers/infiniband/Makefile
@@ -1,5 +1,8 @@
obj-$(CONFIG_INFINIBAND) += core/
obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/
-obj-$(CONFIG_IPATH_CORE) += hw/ipath/
+obj-$(CONFIG_INFINIBAND_IPATH) += hw/ipath/
+obj-$(CONFIG_INFINIBAND_EHCA) += hw/ehca/
+obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/
obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/
obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/
+obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index 68e73ec2d1f..163d991eb8c 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -1,7 +1,7 @@
infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := ib_addr.o rdma_cm.o
obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \
- ib_cm.o $(infiniband-y)
+ ib_cm.o iw_cm.o $(infiniband-y)
obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o
obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o
@@ -14,6 +14,8 @@ ib_sa-y := sa_query.o
ib_cm-y := cm.o
+iw_cm-y := iwcm.o
+
rdma_cm-y := cma.o
ib_addr-y := addr.o
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index d294bbc42f0..60d3fbdd216 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -35,6 +35,7 @@
#include <net/arp.h>
#include <net/neighbour.h>
#include <net/route.h>
+#include <net/netevent.h>
#include <rdma/ib_addr.h>
MODULE_AUTHOR("Sean Hefty");
@@ -60,12 +61,15 @@ static LIST_HEAD(req_list);
static DECLARE_WORK(work, process_req, NULL);
static struct workqueue_struct *addr_wq;
-static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
- unsigned char *dst_dev_addr)
+int rdma_copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
+ const unsigned char *dst_dev_addr)
{
switch (dev->type) {
case ARPHRD_INFINIBAND:
- dev_addr->dev_type = IB_NODE_CA;
+ dev_addr->dev_type = RDMA_NODE_IB_CA;
+ break;
+ case ARPHRD_ETHER:
+ dev_addr->dev_type = RDMA_NODE_RNIC;
break;
default:
return -EADDRNOTAVAIL;
@@ -77,18 +81,19 @@ static int copy_addr(struct rdma_dev_addr *dev_addr, struct net_device *dev,
memcpy(dev_addr->dst_dev_addr, dst_dev_addr, MAX_ADDR_LEN);
return 0;
}
+EXPORT_SYMBOL(rdma_copy_addr);
int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
{
struct net_device *dev;
- u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
int ret;
dev = ip_dev_find(ip);
if (!dev)
return -EADDRNOTAVAIL;
- ret = copy_addr(dev_addr, dev, NULL);
+ ret = rdma_copy_addr(dev_addr, dev, NULL);
dev_put(dev);
return ret;
}
@@ -160,7 +165,7 @@ static int addr_resolve_remote(struct sockaddr_in *src_in,
/* If the device does ARP internally, return 'done' */
if (rt->idev->dev->flags & IFF_NOARP) {
- copy_addr(addr, rt->idev->dev, NULL);
+ rdma_copy_addr(addr, rt->idev->dev, NULL);
goto put;
}
@@ -180,7 +185,7 @@ static int addr_resolve_remote(struct sockaddr_in *src_in,
src_in->sin_addr.s_addr = rt->rt_src;
}
- ret = copy_addr(addr, neigh->dev, neigh->ha);
+ ret = rdma_copy_addr(addr, neigh->dev, neigh->ha);
release:
neigh_release(neigh);
put:
@@ -234,7 +239,7 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
{
struct net_device *dev;
u32 src_ip = src_in->sin_addr.s_addr;
- u32 dst_ip = dst_in->sin_addr.s_addr;
+ __be32 dst_ip = dst_in->sin_addr.s_addr;
int ret;
dev = ip_dev_find(dst_ip);
@@ -244,7 +249,7 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
if (ZERONET(src_ip)) {
src_in->sin_family = dst_in->sin_family;
src_in->sin_addr.s_addr = dst_ip;
- ret = copy_addr(addr, dev, dev->dev_addr);
+ ret = rdma_copy_addr(addr, dev, dev->dev_addr);
} else if (LOOPBACK(src_ip)) {
ret = rdma_translate_ip((struct sockaddr *)dst_in, addr);
if (!ret)
@@ -326,25 +331,22 @@ void rdma_addr_cancel(struct rdma_dev_addr *addr)
}
EXPORT_SYMBOL(rdma_addr_cancel);
-static int addr_arp_recv(struct sk_buff *skb, struct net_device *dev,
- struct packet_type *pkt, struct net_device *orig_dev)
+static int netevent_callback(struct notifier_block *self, unsigned long event,
+ void *ctx)
{
- struct arphdr *arp_hdr;
-
- arp_hdr = (struct arphdr *) skb->nh.raw;
+ if (event == NETEVENT_NEIGH_UPDATE) {
+ struct neighbour *neigh = ctx;
- if (arp_hdr->ar_op == htons(ARPOP_REQUEST) ||
- arp_hdr->ar_op == htons(ARPOP_REPLY))
- set_timeout(jiffies);
-
- kfree_skb(skb);
+ if (neigh->dev->type == ARPHRD_INFINIBAND &&
+ (neigh->nud_state & NUD_VALID)) {
+ set_timeout(jiffies);
+ }
+ }
return 0;
}
-static struct packet_type addr_arp = {
- .type = __constant_htons(ETH_P_ARP),
- .func = addr_arp_recv,
- .af_packet_priv = (void*) 1,
+static struct notifier_block nb = {
+ .notifier_call = netevent_callback
};
static int addr_init(void)
@@ -353,13 +355,13 @@ static int addr_init(void)
if (!addr_wq)
return -ENOMEM;
- dev_add_pack(&addr_arp);
+ register_netevent_notifier(&nb);
return 0;
}
static void addr_cleanup(void)
{
- dev_remove_pack(&addr_arp);
+ unregister_netevent_notifier(&nb);
destroy_workqueue(addr_wq);
}
diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c
index e05ca2cdc73..20e9f64e67a 100644
--- a/drivers/infiniband/core/cache.c
+++ b/drivers/infiniband/core/cache.c
@@ -62,12 +62,13 @@ struct ib_update_work {
static inline int start_port(struct ib_device *device)
{
- return device->node_type == IB_NODE_SWITCH ? 0 : 1;
+ return (device->node_type == RDMA_NODE_IB_SWITCH) ? 0 : 1;
}
static inline int end_port(struct ib_device *device)
{
- return device->node_type == IB_NODE_SWITCH ? 0 : device->phys_port_cnt;
+ return (device->node_type == RDMA_NODE_IB_SWITCH) ?
+ 0 : device->phys_port_cnt;
}
int ib_get_cached_gid(struct ib_device *device,
@@ -301,7 +302,8 @@ static void ib_cache_event(struct ib_event_handler *handler,
event->event == IB_EVENT_PORT_ACTIVE ||
event->event == IB_EVENT_LID_CHANGE ||
event->event == IB_EVENT_PKEY_CHANGE ||
- event->event == IB_EVENT_SM_CHANGE) {
+ event->event == IB_EVENT_SM_CHANGE ||
+ event->event == IB_EVENT_CLIENT_REREGISTER) {
work = kmalloc(sizeof *work, GFP_ATOMIC);
if (work) {
INIT_WORK(&work->work, ib_cache_task, work);
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index 450adfe0a4f..f35fcc4c063 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
+ * Copyright (c) 2004-2006 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
@@ -41,6 +41,7 @@
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/random.h>
#include <linux/rbtree.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -73,6 +74,7 @@ static struct ib_cm {
struct rb_root remote_id_table;
struct rb_root remote_sidr_table;
struct idr local_id_table;
+ __be32 random_id_operand;
struct workqueue_struct *wq;
} cm;
@@ -177,7 +179,7 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv,
if (IS_ERR(ah))
return PTR_ERR(ah);
- m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
+ m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn,
cm_id_priv->av.pkey_index,
0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA,
GFP_ATOMIC);
@@ -299,15 +301,17 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av)
static int cm_alloc_id(struct cm_id_private *cm_id_priv)
{
unsigned long flags;
- int ret;
+ int ret, id;
static int next_id;
do {
spin_lock_irqsave(&cm.lock, flags);
- ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++,
- (__force int *) &cm_id_priv->id.local_id);
+ ret = idr_get_new_above(&cm.local_id_table, cm_id_priv,
+ next_id++, &id);
spin_unlock_irqrestore(&cm.lock, flags);
} while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) );
+
+ cm_id_priv->id.local_id = (__force __be32) (id ^ cm.random_id_operand);
return ret;
}
@@ -316,7 +320,8 @@ static void cm_free_id(__be32 local_id)
unsigned long flags;
spin_lock_irqsave(&cm.lock, flags);
- idr_remove(&cm.local_id_table, (__force int) local_id);
+ idr_remove(&cm.local_id_table,
+ (__force int) (local_id ^ cm.random_id_operand));
spin_unlock_irqrestore(&cm.lock, flags);
}
@@ -324,7 +329,8 @@ static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id)
{
struct cm_id_private *cm_id_priv;
- cm_id_priv = idr_find(&cm.local_id_table, (__force int) local_id);
+ cm_id_priv = idr_find(&cm.local_id_table,
+ (__force int) (local_id ^ cm.random_id_operand));
if (cm_id_priv) {
if (cm_id_priv->id.remote_id == remote_id)
atomic_inc(&cm_id_priv->refcount);
@@ -679,6 +685,8 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
{
int wait_time;
+ cm_cleanup_timewait(cm_id_priv->timewait_info);
+
/*
* The cm_id could be destroyed by the user before we exit timewait.
* To protect against this, we search for the cm_id after exiting
@@ -701,7 +709,7 @@ static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
}
}
-void ib_destroy_cm_id(struct ib_cm_id *cm_id)
+static void cm_destroy_id(struct ib_cm_id *cm_id, int err)
{
struct cm_id_private *cm_id_priv;
struct cm_work *work;
@@ -735,12 +743,22 @@ retest:
sizeof cm_id_priv->av.port->cm_dev->ca_guid,
NULL, 0);
break;
+ case IB_CM_REQ_RCVD:
+ if (err == -ENOMEM) {
+ /* Do not reject to allow future retries. */
+ cm_reset_to_idle(cm_id_priv);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ } else {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ib_send_cm_rej(cm_id, IB_CM_REJ_CONSUMER_DEFINED,
+ NULL, 0, NULL, 0);
+ }
+ break;
case IB_CM_MRA_REQ_RCVD:
case IB_CM_REP_SENT:
case IB_CM_MRA_REP_RCVD:
ib_cancel_mad(cm_id_priv->av.port->mad_agent, cm_id_priv->msg);
/* Fall through */
- case IB_CM_REQ_RCVD:
case IB_CM_MRA_REQ_SENT:
case IB_CM_REP_RCVD:
case IB_CM_MRA_REP_SENT:
@@ -775,6 +793,11 @@ retest:
kfree(cm_id_priv->private_data);
kfree(cm_id_priv);
}
+
+void ib_destroy_cm_id(struct ib_cm_id *cm_id)
+{
+ cm_destroy_id(cm_id, 0);
+}
EXPORT_SYMBOL(ib_destroy_cm_id);
int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask,
@@ -960,8 +983,10 @@ int ib_send_cm_req(struct ib_cm_id *cm_id,
cm_id_priv->timewait_info = cm_create_timewait_info(cm_id_priv->
id.local_id);
- if (IS_ERR(cm_id_priv->timewait_info))
+ if (IS_ERR(cm_id_priv->timewait_info)) {
+ ret = PTR_ERR(cm_id_priv->timewait_info);
goto out;
+ }
ret = cm_init_av_by_path(param->primary_path, &cm_id_priv->av);
if (ret)
@@ -1163,7 +1188,7 @@ static void cm_process_work(struct cm_id_private *cm_id_priv,
}
cm_deref_id(cm_id_priv);
if (ret)
- ib_destroy_cm_id(&cm_id_priv->id);
+ cm_destroy_id(&cm_id_priv->id, ret);
}
static void cm_format_mra(struct cm_mra_msg *mra_msg,
@@ -1337,7 +1362,7 @@ static int cm_req_handler(struct cm_work *work)
id.local_id);
if (IS_ERR(cm_id_priv->timewait_info)) {
ret = PTR_ERR(cm_id_priv->timewait_info);
- goto error1;
+ goto destroy;
}
cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id;
cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid;
@@ -1346,7 +1371,8 @@ static int cm_req_handler(struct cm_work *work)
listen_cm_id_priv = cm_match_req(work, cm_id_priv);
if (!listen_cm_id_priv) {
ret = -EINVAL;
- goto error2;
+ kfree(cm_id_priv->timewait_info);
+ goto destroy;
}
cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler;
@@ -1356,12 +1382,22 @@ static int cm_req_handler(struct cm_work *work)
cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]);
ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av);
- if (ret)
- goto error3;
+ if (ret) {
+ ib_get_cached_gid(work->port->cm_dev->device,
+ work->port->port_num, 0, &work->path[0].sgid);
+ ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID,
+ &work->path[0].sgid, sizeof work->path[0].sgid,
+ NULL, 0);
+ goto rejected;
+ }
if (req_msg->alt_local_lid) {
ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av);
- if (ret)
- goto error3;
+ if (ret) {
+ ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID,
+ &work->path[0].sgid,
+ sizeof work->path[0].sgid, NULL, 0);
+ goto rejected;
+ }
}
cm_id_priv->tid = req_msg->hdr.tid;
cm_id_priv->timeout_ms = cm_convert_to_ms(
@@ -1383,12 +1419,11 @@ static int cm_req_handler(struct cm_work *work)
cm_deref_id(listen_cm_id_priv);
return 0;
-error3: atomic_dec(&cm_id_priv->refcount);
+rejected:
+ atomic_dec(&cm_id_priv->refcount);
cm_deref_id(listen_cm_id_priv);
- cm_cleanup_timewait(cm_id_priv->timewait_info);
-error2: kfree(cm_id_priv->timewait_info);
- cm_id_priv->timewait_info = NULL;
-error1: ib_destroy_cm_id(&cm_id_priv->id);
+destroy:
+ ib_destroy_cm_id(cm_id);
return ret;
}
@@ -2055,8 +2090,9 @@ static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg)
spin_unlock_irqrestore(&cm.lock, flags);
return NULL;
}
- cm_id_priv = idr_find(&cm.local_id_table,
- (__force int) timewait_info->work.local_id);
+ cm_id_priv = idr_find(&cm.local_id_table, (__force int)
+ (timewait_info->work.local_id ^
+ cm.random_id_operand));
if (cm_id_priv) {
if (cm_id_priv->id.remote_id == remote_id)
atomic_inc(&cm_id_priv->refcount);
@@ -3108,7 +3144,8 @@ static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv,
qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
IB_ACCESS_REMOTE_WRITE;
if (cm_id_priv->responder_resources)
- qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ;
+ qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ |
+ IB_ACCESS_REMOTE_ATOMIC;
qp_attr->pkey_index = cm_id_priv->av.pkey_index;
qp_attr->port_num = cm_id_priv->av.port->port_num;
ret = 0;
@@ -3152,6 +3189,7 @@ static int cm_init_qp_rtr_attr(struct cm_id_private *cm_id_priv,
}
if (cm_id_priv->alt_av.ah_attr.dlid) {
*qp_attr_mask |= IB_QP_ALT_PATH;
+ qp_attr->alt_port_num = cm_id_priv->alt_av.port->port_num;
qp_attr->alt_ah_attr = cm_id_priv->alt_av.ah_attr;
}
ret = 0;
@@ -3244,6 +3282,9 @@ static void cm_add_one(struct ib_device *device)
int ret;
u8 i;
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) *
device->phys_port_cnt, GFP_KERNEL);
if (!cm_dev)
@@ -3331,6 +3372,7 @@ static int __init ib_cm_init(void)
cm.remote_qp_table = RB_ROOT;
cm.remote_sidr_table = RB_ROOT;
idr_init(&cm.local_id_table);
+ get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand);
idr_pre_get(&cm.local_id_table, GFP_KERNEL);
cm.wq = create_workqueue("ib_cm");
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index a76834edf60..1178bd434d1 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -35,6 +35,7 @@
#include <linux/mutex.h>
#include <linux/random.h>
#include <linux/idr.h>
+#include <linux/inetdevice.h>
#include <net/tcp.h>
@@ -43,13 +44,14 @@
#include <rdma/ib_cache.h>
#include <rdma/ib_cm.h>
#include <rdma/ib_sa.h>
+#include <rdma/iw_cm.h>
MODULE_AUTHOR("Sean Hefty");
MODULE_DESCRIPTION("Generic RDMA CM Agent");
MODULE_LICENSE("Dual BSD/GPL");
#define CMA_CM_RESPONSE_TIMEOUT 20
-#define CMA_MAX_CM_RETRIES 3
+#define CMA_MAX_CM_RETRIES 15
static void cma_add_one(struct ib_device *device);
static void cma_remove_one(struct ib_device *device);
@@ -60,6 +62,7 @@ static struct ib_client cma_client = {
.remove = cma_remove_one
};
+static struct ib_sa_client sa_client;
static LIST_HEAD(dev_list);
static LIST_HEAD(listen_any_list);
static DEFINE_MUTEX(lock);
@@ -124,6 +127,7 @@ struct rdma_id_private {
int query_id;
union {
struct ib_cm_id *ib;
+ struct iw_cm_id *iw;
} cm_id;
u32 seq_num;
@@ -259,37 +263,35 @@ static void cma_detach_from_dev(struct rdma_id_private *id_priv)
id_priv->cma_dev = NULL;
}
-static int cma_acquire_ib_dev(struct rdma_id_private *id_priv)
+static int cma_acquire_dev(struct rdma_id_private *id_priv)
{
+ enum rdma_node_type dev_type = id_priv->id.route.addr.dev_addr.dev_type;
struct cma_device *cma_dev;
- union ib_gid *gid;
+ union ib_gid gid;
int ret = -ENODEV;
- gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
+ switch (rdma_node_get_transport(dev_type)) {
+ case RDMA_TRANSPORT_IB:
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ break;
+ case RDMA_TRANSPORT_IWARP:
+ iw_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ break;
+ default:
+ return -ENODEV;
+ }
- mutex_lock(&lock);
list_for_each_entry(cma_dev, &dev_list, list) {
- ret = ib_find_cached_gid(cma_dev->device, gid,
+ ret = ib_find_cached_gid(cma_dev->device, &gid,
&id_priv->id.port_num, NULL);
if (!ret) {
cma_attach_to_dev(id_priv, cma_dev);
break;
}
}
- mutex_unlock(&lock);
return ret;
}
-static int cma_acquire_dev(struct rdma_id_private *id_priv)
-{
- switch (id_priv->id.route.addr.dev_addr.dev_type) {
- case IB_NODE_CA:
- return cma_acquire_ib_dev(id_priv);
- default:
- return -ENODEV;
- }
-}
-
static void cma_deref_id(struct rdma_id_private *id_priv)
{
if (atomic_dec_and_test(&id_priv->refcount))
@@ -347,6 +349,16 @@ static int cma_init_ib_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
IB_QP_PKEY_INDEX | IB_QP_PORT);
}
+static int cma_init_iw_qp(struct rdma_id_private *id_priv, struct ib_qp *qp)
+{
+ struct ib_qp_attr qp_attr;
+
+ qp_attr.qp_state = IB_QPS_INIT;
+ qp_attr.qp_access_flags = IB_ACCESS_LOCAL_WRITE;
+
+ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE | IB_QP_ACCESS_FLAGS);
+}
+
int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
struct ib_qp_init_attr *qp_init_attr)
{
@@ -362,10 +374,13 @@ int rdma_create_qp(struct rdma_cm_id *id, struct ib_pd *pd,
if (IS_ERR(qp))
return PTR_ERR(qp);
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
ret = cma_init_ib_qp(id_priv, qp);
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = cma_init_iw_qp(id_priv, qp);
+ break;
default:
ret = -ENOSYS;
break;
@@ -451,13 +466,17 @@ int rdma_init_qp_attr(struct rdma_cm_id *id, struct ib_qp_attr *qp_attr,
int ret;
id_priv = container_of(id, struct rdma_id_private, id);
- switch (id_priv->id.device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
+ case RDMA_TRANSPORT_IB:
ret = ib_cm_init_qp_attr(id_priv->cm_id.ib, qp_attr,
qp_attr_mask);
if (qp_attr->qp_state == IB_QPS_RTR)
qp_attr->rq_psn = id_priv->seq_num;
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = iw_cm_init_qp_attr(id_priv->cm_id.iw, qp_attr,
+ qp_attr_mask);
+ break;
default:
ret = -ENOSYS;
break;
@@ -476,7 +495,7 @@ static inline int cma_zero_addr(struct sockaddr *addr)
else {
ip6 = &((struct sockaddr_in6 *) addr)->sin6_addr;
return (ip6->s6_addr32[0] | ip6->s6_addr32[1] |
- ip6->s6_addr32[3] | ip6->s6_addr32[4]) == 0;
+ ip6->s6_addr32[2] | ip6->s6_addr32[3]) == 0;
}
}
@@ -590,8 +609,8 @@ static int cma_notify_user(struct rdma_id_private *id_priv,
static void cma_cancel_route(struct rdma_id_private *id_priv)
{
- switch (id_priv->id.device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
+ case RDMA_TRANSPORT_IB:
if (id_priv->query)
ib_sa_cancel_query(id_priv->query_id, id_priv->query);
break;
@@ -611,11 +630,15 @@ static void cma_destroy_listen(struct rdma_id_private *id_priv)
cma_exch(id_priv, CMA_DESTROYING);
if (id_priv->cma_dev) {
- switch (id_priv->id.device->node_type) {
- case IB_NODE_CA:
- if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
+ switch (rdma_node_get_transport(id_priv->id.device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
ib_destroy_cm_id(id_priv->cm_id.ib);
break;
+ case RDMA_TRANSPORT_IWARP:
+ if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
+ iw_destroy_cm_id(id_priv->cm_id.iw);
+ break;
default:
break;
}
@@ -689,19 +712,25 @@ void rdma_destroy_id(struct rdma_cm_id *id)
state = cma_exch(id_priv, CMA_DESTROYING);
cma_cancel_operation(id_priv, state);
+ mutex_lock(&lock);
if (id_priv->cma_dev) {
- switch (id->device->node_type) {
- case IB_NODE_CA:
- if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
+ mutex_unlock(&lock);
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ if (id_priv->cm_id.ib && !IS_ERR(id_priv->cm_id.ib))
ib_destroy_cm_id(id_priv->cm_id.ib);
break;
+ case RDMA_TRANSPORT_IWARP:
+ if (id_priv->cm_id.iw && !IS_ERR(id_priv->cm_id.iw))
+ iw_destroy_cm_id(id_priv->cm_id.iw);
+ break;
default:
break;
}
- mutex_lock(&lock);
+ mutex_lock(&lock);
cma_detach_from_dev(id_priv);
- mutex_unlock(&lock);
}
+ mutex_unlock(&lock);
cma_release_port(id_priv);
cma_deref_id(id_priv);
@@ -812,6 +841,7 @@ static int cma_ib_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
cma_modify_qp_err(&id_priv->id);
status = ib_event->param.rej_rcvd.reason;
event = RDMA_CM_EVENT_REJECTED;
+ private_data_len = IB_CM_REJ_PRIVATE_DATA_SIZE;
break;
default:
printk(KERN_ERR "RDMA CMA: unexpected IB CM event: %d",
@@ -868,7 +898,7 @@ static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
ib_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid);
ib_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid);
ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey));
- rt->addr.dev_addr.dev_type = IB_NODE_CA;
+ rt->addr.dev_addr.dev_type = RDMA_NODE_IB_CA;
id_priv = container_of(id, struct rdma_id_private, id);
id_priv->state = CMA_CONNECT;
@@ -897,7 +927,9 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
}
atomic_inc(&conn_id->dev_remove);
- ret = cma_acquire_ib_dev(conn_id);
+ mutex_lock(&lock);
+ ret = cma_acquire_dev(conn_id);
+ mutex_unlock(&lock);
if (ret) {
ret = -ENODEV;
cma_release_remove(conn_id);
@@ -981,6 +1013,130 @@ static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr,
}
}
+static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event)
+{
+ struct rdma_id_private *id_priv = iw_id->context;
+ enum rdma_cm_event_type event = 0;
+ struct sockaddr_in *sin;
+ int ret = 0;
+
+ atomic_inc(&id_priv->dev_remove);
+
+ switch (iw_event->event) {
+ case IW_CM_EVENT_CLOSE:
+ event = RDMA_CM_EVENT_DISCONNECTED;
+ break;
+ case IW_CM_EVENT_CONNECT_REPLY:
+ sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+ *sin = iw_event->local_addr;
+ sin = (struct sockaddr_in *) &id_priv->id.route.addr.dst_addr;
+ *sin = iw_event->remote_addr;
+ if (iw_event->status)
+ event = RDMA_CM_EVENT_REJECTED;
+ else
+ event = RDMA_CM_EVENT_ESTABLISHED;
+ break;
+ case IW_CM_EVENT_ESTABLISHED:
+ event = RDMA_CM_EVENT_ESTABLISHED;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ ret = cma_notify_user(id_priv, event, iw_event->status,
+ iw_event->private_data,
+ iw_event->private_data_len);
+ if (ret) {
+ /* Destroy the CM ID by returning a non-zero value. */
+ id_priv->cm_id.iw = NULL;
+ cma_exch(id_priv, CMA_DESTROYING);
+ cma_release_remove(id_priv);
+ rdma_destroy_id(&id_priv->id);
+ return ret;
+ }
+
+ cma_release_remove(id_priv);
+ return ret;
+}
+
+static int iw_conn_req_handler(struct iw_cm_id *cm_id,
+ struct iw_cm_event *iw_event)
+{
+ struct rdma_cm_id *new_cm_id;
+ struct rdma_id_private *listen_id, *conn_id;
+ struct sockaddr_in *sin;
+ struct net_device *dev = NULL;
+ int ret;
+
+ listen_id = cm_id->context;
+ atomic_inc(&listen_id->dev_remove);
+ if (!cma_comp(listen_id, CMA_LISTEN)) {
+ ret = -ECONNABORTED;
+ goto out;
+ }
+
+ /* Create a new RDMA id for the new IW CM ID */
+ new_cm_id = rdma_create_id(listen_id->id.event_handler,
+ listen_id->id.context,
+ RDMA_PS_TCP);
+ if (!new_cm_id) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ conn_id = container_of(new_cm_id, struct rdma_id_private, id);
+ atomic_inc(&conn_id->dev_remove);
+ conn_id->state = CMA_CONNECT;
+
+ dev = ip_dev_find(iw_event->local_addr.sin_addr.s_addr);
+ if (!dev) {
+ ret = -EADDRNOTAVAIL;
+ cma_release_remove(conn_id);
+ rdma_destroy_id(new_cm_id);
+ goto out;
+ }
+ ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL);
+ if (ret) {
+ cma_release_remove(conn_id);
+ rdma_destroy_id(new_cm_id);
+ goto out;
+ }
+
+ mutex_lock(&lock);
+ ret = cma_acquire_dev(conn_id);
+ mutex_unlock(&lock);
+ if (ret) {
+ cma_release_remove(conn_id);
+ rdma_destroy_id(new_cm_id);
+ goto out;
+ }
+
+ conn_id->cm_id.iw = cm_id;
+ cm_id->context = conn_id;
+ cm_id->cm_handler = cma_iw_handler;
+
+ sin = (struct sockaddr_in *) &new_cm_id->route.addr.src_addr;
+ *sin = iw_event->local_addr;
+ sin = (struct sockaddr_in *) &new_cm_id->route.addr.dst_addr;
+ *sin = iw_event->remote_addr;
+
+ ret = cma_notify_user(conn_id, RDMA_CM_EVENT_CONNECT_REQUEST, 0,
+ iw_event->private_data,
+ iw_event->private_data_len);
+ if (ret) {
+ /* User wants to destroy the CM ID */
+ conn_id->cm_id.iw = NULL;
+ cma_exch(conn_id, CMA_DESTROYING);
+ cma_release_remove(conn_id);
+ rdma_destroy_id(&conn_id->id);
+ }
+
+out:
+ if (dev)
+ dev_put(dev);
+ cma_release_remove(listen_id);
+ return ret;
+}
+
static int cma_ib_listen(struct rdma_id_private *id_priv)
{
struct ib_cm_compare_data compare_data;
@@ -1010,6 +1166,30 @@ static int cma_ib_listen(struct rdma_id_private *id_priv)
return ret;
}
+static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog)
+{
+ int ret;
+ struct sockaddr_in *sin;
+
+ id_priv->cm_id.iw = iw_create_cm_id(id_priv->id.device,
+ iw_conn_req_handler,
+ id_priv);
+ if (IS_ERR(id_priv->cm_id.iw))
+ return PTR_ERR(id_priv->cm_id.iw);
+
+ sin = (struct sockaddr_in *) &id_priv->id.route.addr.src_addr;
+ id_priv->cm_id.iw->local_addr = *sin;
+
+ ret = iw_cm_listen(id_priv->cm_id.iw, backlog);
+
+ if (ret) {
+ iw_destroy_cm_id(id_priv->cm_id.iw);
+ id_priv->cm_id.iw = NULL;
+ }
+
+ return ret;
+}
+
static int cma_listen_handler(struct rdma_cm_id *id,
struct rdma_cm_event *event)
{
@@ -1086,12 +1266,17 @@ int rdma_listen(struct rdma_cm_id *id, int backlog)
id_priv->backlog = backlog;
if (id->device) {
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
ret = cma_ib_listen(id_priv);
if (ret)
goto err;
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = cma_iw_listen(id_priv, backlog);
+ if (ret)
+ goto err;
+ break;
default:
ret = -ENOSYS;
goto err;
@@ -1134,12 +1319,12 @@ static int cma_query_ib_route(struct rdma_id_private *id_priv, int timeout_ms,
struct ib_sa_path_rec path_rec;
memset(&path_rec, 0, sizeof path_rec);
- path_rec.sgid = *ib_addr_get_sgid(addr);
- path_rec.dgid = *ib_addr_get_dgid(addr);
+ ib_addr_get_sgid(addr, &path_rec.sgid);
+ ib_addr_get_dgid(addr, &path_rec.dgid);
path_rec.pkey = cpu_to_be16(ib_addr_get_pkey(addr));
path_rec.numb_path = 1;
- id_priv->query_id = ib_sa_path_rec_get(id_priv->id.device,
+ id_priv->query_id = ib_sa_path_rec_get(&sa_client, id_priv->id.device,
id_priv->id.port_num, &path_rec,
IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID |
IB_SA_PATH_REC_PKEY | IB_SA_PATH_REC_NUMB_PATH,
@@ -1230,6 +1415,23 @@ err:
}
EXPORT_SYMBOL(rdma_set_ib_paths);
+static int cma_resolve_iw_route(struct rdma_id_private *id_priv, int timeout_ms)
+{
+ struct cma_work *work;
+
+ work = kzalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return -ENOMEM;
+
+ work->id = id_priv;
+ INIT_WORK(&work->work, cma_work_handler, work);
+ work->old_state = CMA_ROUTE_QUERY;
+ work->new_state = CMA_ROUTE_RESOLVED;
+ work->event.event = RDMA_CM_EVENT_ROUTE_RESOLVED;
+ queue_work(cma_wq, &work->work);
+ return 0;
+}
+
int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
{
struct rdma_id_private *id_priv;
@@ -1240,10 +1442,13 @@ int rdma_resolve_route(struct rdma_cm_id *id, int timeout_ms)
return -EINVAL;
atomic_inc(&id_priv->refcount);
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
ret = cma_resolve_ib_route(id_priv, timeout_ms);
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = cma_resolve_iw_route(id_priv, timeout_ms);
+ break;
default:
ret = -ENOSYS;
break;
@@ -1263,7 +1468,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
{
struct cma_device *cma_dev;
struct ib_port_attr port_attr;
- union ib_gid *gid;
+ union ib_gid gid;
u16 pkey;
int ret;
u8 p;
@@ -1284,8 +1489,7 @@ static int cma_bind_loopback(struct rdma_id_private *id_priv)
}
port_found:
- gid = ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr);
- ret = ib_get_cached_gid(cma_dev->device, p, 0, gid);
+ ret = ib_get_cached_gid(cma_dev->device, p, 0, &gid);
if (ret)
goto out;
@@ -1293,6 +1497,7 @@ port_found:
if (ret)
goto out;
+ ib_addr_set_sgid(&id_priv->id.route.addr.dev_addr, &gid);
ib_addr_set_pkey(&id_priv->id.route.addr.dev_addr, pkey);
id_priv->id.port_num = p;
cma_attach_to_dev(id_priv, cma_dev);
@@ -1308,16 +1513,26 @@ static void addr_handler(int status, struct sockaddr *src_addr,
enum rdma_cm_event_type event;
atomic_inc(&id_priv->dev_remove);
- if (!id_priv->cma_dev && !status)
+
+ /*
+ * Grab mutex to block rdma_destroy_id() from removing the device while
+ * we're trying to acquire it.
+ */
+ mutex_lock(&lock);
+ if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED)) {
+ mutex_unlock(&lock);
+ goto out;
+ }
+
+ if (!status && !id_priv->cma_dev)
status = cma_acquire_dev(id_priv);
+ mutex_unlock(&lock);
if (status) {
- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_BOUND))
+ if (!cma_comp_exch(id_priv, CMA_ADDR_RESOLVED, CMA_ADDR_BOUND))
goto out;
event = RDMA_CM_EVENT_ADDR_ERROR;
} else {
- if (!cma_comp_exch(id_priv, CMA_ADDR_QUERY, CMA_ADDR_RESOLVED))
- goto out;
memcpy(&id_priv->id.route.addr.src_addr, src_addr,
ip_addr_size(src_addr));
event = RDMA_CM_EVENT_ADDR_RESOLVED;
@@ -1339,6 +1554,7 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
{
struct cma_work *work;
struct sockaddr_in *src_in, *dst_in;
+ union ib_gid gid;
int ret;
work = kzalloc(sizeof *work, GFP_KERNEL);
@@ -1351,8 +1567,8 @@ static int cma_resolve_loopback(struct rdma_id_private *id_priv)
goto err;
}
- ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr,
- ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr));
+ ib_addr_get_sgid(&id_priv->id.route.addr.dev_addr, &gid);
+ ib_addr_set_dgid(&id_priv->id.route.addr.dev_addr, &gid);
if (cma_zero_addr(&id_priv->id.route.addr.src_addr)) {
src_in = (struct sockaddr_in *)&id_priv->id.route.addr.src_addr;
@@ -1490,7 +1706,7 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv)
hlist_for_each_entry(cur_id, node, &bind_list->owners, node) {
if (cma_any_addr(&cur_id->id.route.addr.src_addr))
return -EADDRNOTAVAIL;
-
+
cur_sin = (struct sockaddr_in *) &cur_id->id.route.addr.src_addr;
if (sin->sin_addr.s_addr == cur_sin->sin_addr.s_addr)
return -EADDRINUSE;
@@ -1540,8 +1756,11 @@ int rdma_bind_addr(struct rdma_cm_id *id, struct sockaddr *addr)
if (!cma_any_addr(addr)) {
ret = rdma_translate_ip(addr, &id->route.addr.dev_addr);
- if (!ret)
+ if (!ret) {
+ mutex_lock(&lock);
ret = cma_acquire_dev(id_priv);
+ mutex_unlock(&lock);
+ }
if (ret)
goto err;
}
@@ -1647,6 +1866,47 @@ out:
return ret;
}
+static int cma_connect_iw(struct rdma_id_private *id_priv,
+ struct rdma_conn_param *conn_param)
+{
+ struct iw_cm_id *cm_id;
+ struct sockaddr_in* sin;
+ int ret;
+ struct iw_cm_conn_param iw_param;
+
+ cm_id = iw_create_cm_id(id_priv->id.device, cma_iw_handler, id_priv);
+ if (IS_ERR(cm_id)) {
+ ret = PTR_ERR(cm_id);
+ goto out;
+ }
+
+ id_priv->cm_id.iw = cm_id;
+
+ sin = (struct sockaddr_in*) &id_priv->id.route.addr.src_addr;
+ cm_id->local_addr = *sin;
+
+ sin = (struct sockaddr_in*) &id_priv->id.route.addr.dst_addr;
+ cm_id->remote_addr = *sin;
+
+ ret = cma_modify_qp_rtr(&id_priv->id);
+ if (ret) {
+ iw_destroy_cm_id(cm_id);
+ return ret;
+ }
+
+ iw_param.ord = conn_param->initiator_depth;
+ iw_param.ird = conn_param->responder_resources;
+ iw_param.private_data = conn_param->private_data;
+ iw_param.private_data_len = conn_param->private_data_len;
+ if (id_priv->id.qp)
+ iw_param.qpn = id_priv->qp_num;
+ else
+ iw_param.qpn = conn_param->qp_num;
+ ret = iw_cm_connect(cm_id, &iw_param);
+out:
+ return ret;
+}
+
int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
{
struct rdma_id_private *id_priv;
@@ -1662,10 +1922,13 @@ int rdma_connect(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
id_priv->srq = conn_param->srq;
}
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
ret = cma_connect_ib(id_priv, conn_param);
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = cma_connect_iw(id_priv, conn_param);
+ break;
default:
ret = -ENOSYS;
break;
@@ -1706,6 +1969,28 @@ static int cma_accept_ib(struct rdma_id_private *id_priv,
return ib_send_cm_rep(id_priv->cm_id.ib, &rep);
}
+static int cma_accept_iw(struct rdma_id_private *id_priv,
+ struct rdma_conn_param *conn_param)
+{
+ struct iw_cm_conn_param iw_param;
+ int ret;
+
+ ret = cma_modify_qp_rtr(&id_priv->id);
+ if (ret)
+ return ret;
+
+ iw_param.ord = conn_param->initiator_depth;
+ iw_param.ird = conn_param->responder_resources;
+ iw_param.private_data = conn_param->private_data;
+ iw_param.private_data_len = conn_param->private_data_len;
+ if (id_priv->id.qp) {
+ iw_param.qpn = id_priv->qp_num;
+ } else
+ iw_param.qpn = conn_param->qp_num;
+
+ return iw_cm_accept(id_priv->cm_id.iw, &iw_param);
+}
+
int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
{
struct rdma_id_private *id_priv;
@@ -1721,13 +2006,16 @@ int rdma_accept(struct rdma_cm_id *id, struct rdma_conn_param *conn_param)
id_priv->srq = conn_param->srq;
}
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
if (conn_param)
ret = cma_accept_ib(id_priv, conn_param);
else
ret = cma_rep_recv(id_priv);
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = cma_accept_iw(id_priv, conn_param);
+ break;
default:
ret = -ENOSYS;
break;
@@ -1754,12 +2042,16 @@ int rdma_reject(struct rdma_cm_id *id, const void *private_data,
if (!cma_comp(id_priv, CMA_CONNECT))
return -EINVAL;
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
ret = ib_send_cm_rej(id_priv->cm_id.ib,
IB_CM_REJ_CONSUMER_DEFINED, NULL, 0,
private_data, private_data_len);
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = iw_cm_reject(id_priv->cm_id.iw,
+ private_data, private_data_len);
+ break;
default:
ret = -ENOSYS;
break;
@@ -1778,17 +2070,20 @@ int rdma_disconnect(struct rdma_cm_id *id)
!cma_comp(id_priv, CMA_DISCONNECT))
return -EINVAL;
- ret = cma_modify_qp_err(id);
- if (ret)
- goto out;
-
- switch (id->device->node_type) {
- case IB_NODE_CA:
+ switch (rdma_node_get_transport(id->device->node_type)) {
+ case RDMA_TRANSPORT_IB:
+ ret = cma_modify_qp_err(id);
+ if (ret)
+ goto out;
/* Initiate or respond to a disconnect. */
if (ib_send_cm_dreq(id_priv->cm_id.ib, NULL, 0))
ib_send_cm_drep(id_priv->cm_id.ib, NULL, 0);
break;
+ case RDMA_TRANSPORT_IWARP:
+ ret = iw_cm_disconnect(id_priv->cm_id.iw, 0);
+ break;
default:
+ ret = -EINVAL;
break;
}
out:
@@ -1905,12 +2200,15 @@ static int cma_init(void)
if (!cma_wq)
return -ENOMEM;
+ ib_sa_register_client(&sa_client);
+
ret = ib_register_client(&cma_client);
if (ret)
goto err;
return 0;
err:
+ ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq);
return ret;
}
@@ -1918,6 +2216,7 @@ err:
static void cma_cleanup(void)
{
ib_unregister_client(&cma_client);
+ ib_sa_unregister_client(&sa_client);
destroy_workqueue(cma_wq);
idr_destroy(&sdp_ps);
idr_destroy(&tcp_ps);
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index b2f3cb91d9b..63d2a39fb82 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -385,7 +385,7 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client)
EXPORT_SYMBOL(ib_get_client_data);
/**
- * ib_set_client_data - Get IB client context
+ * ib_set_client_data - Set IB client context
* @device:Device to set context for
* @client:Client to set context for
* @data:Context to set
@@ -505,7 +505,7 @@ int ib_query_port(struct ib_device *device,
u8 port_num,
struct ib_port_attr *port_attr)
{
- if (device->node_type == IB_NODE_SWITCH) {
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
if (port_num)
return -EINVAL;
} else if (port_num < 1 || port_num > device->phys_port_cnt)
@@ -580,7 +580,7 @@ int ib_modify_port(struct ib_device *device,
u8 port_num, int port_modify_mask,
struct ib_port_modify *port_modify)
{
- if (device->node_type == IB_NODE_SWITCH) {
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
if (port_num)
return -EINVAL;
} else if (port_num < 1 || port_num > device->phys_port_cnt)
diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c
index 615fe9cc6c5..86a3b2d401d 100644
--- a/drivers/infiniband/core/fmr_pool.c
+++ b/drivers/infiniband/core/fmr_pool.c
@@ -426,7 +426,7 @@ EXPORT_SYMBOL(ib_flush_fmr_pool);
struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
u64 *page_list,
int list_len,
- u64 *io_virtual_address)
+ u64 io_virtual_address)
{
struct ib_fmr_pool *pool = pool_handle;
struct ib_pool_fmr *fmr;
@@ -440,7 +440,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
fmr = ib_fmr_cache_lookup(pool,
page_list,
list_len,
- *io_virtual_address);
+ io_virtual_address);
if (fmr) {
/* found in cache */
++fmr->ref_count;
@@ -464,7 +464,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
spin_unlock_irqrestore(&pool->pool_lock, flags);
result = ib_map_phys_fmr(fmr->fmr, page_list, list_len,
- *io_virtual_address);
+ io_virtual_address);
if (result) {
spin_lock_irqsave(&pool->pool_lock, flags);
@@ -481,7 +481,7 @@ struct ib_pool_fmr *ib_fmr_pool_map_phys(struct ib_fmr_pool *pool_handle,
fmr->ref_count = 1;
if (pool->cache_bucket) {
- fmr->io_virtual_address = *io_virtual_address;
+ fmr->io_virtual_address = io_virtual_address;
fmr->page_list_len = list_len;
memcpy(fmr->page_list, page_list, list_len * sizeof(*page_list));
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
new file mode 100644
index 00000000000..c3fb304a4e8
--- /dev/null
+++ b/drivers/infiniband/core/iwcm.c
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved.
+ * Copyright (c) 2004 Topspin Corporation. All rights reserved.
+ * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ * Copyright (c) 2005 Network Appliance, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+
+#include <rdma/iw_cm.h>
+#include <rdma/ib_addr.h>
+
+#include "iwcm.h"
+
+MODULE_AUTHOR("Tom Tucker");
+MODULE_DESCRIPTION("iWARP CM");
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct workqueue_struct *iwcm_wq;
+struct iwcm_work {
+ struct work_struct work;
+ struct iwcm_id_private *cm_id;
+ struct list_head list;
+ struct iw_cm_event event;
+ struct list_head free_list;
+};
+
+/*
+ * The following services provide a mechanism for pre-allocating iwcm_work
+ * elements. The design pre-allocates them based on the cm_id type:
+ * LISTENING IDS: Get enough elements preallocated to handle the
+ * listen backlog.
+ * ACTIVE IDS: 4: CONNECT_REPLY, ESTABLISHED, DISCONNECT, CLOSE
+ * PASSIVE IDS: 3: ESTABLISHED, DISCONNECT, CLOSE
+ *
+ * Allocating them in connect and listen avoids having to deal
+ * with allocation failures on the event upcall from the provider (which
+ * is called in the interrupt context).
+ *
+ * One exception is when creating the cm_id for incoming connection requests.
+ * There are two cases:
+ * 1) in the event upcall, cm_event_handler(), for a listening cm_id. If
+ * the backlog is exceeded, then no more connection request events will
+ * be processed. cm_event_handler() returns -ENOMEM in this case. Its up
+ * to the provider to reject the connectino request.
+ * 2) in the connection request workqueue handler, cm_conn_req_handler().
+ * If work elements cannot be allocated for the new connect request cm_id,
+ * then IWCM will call the provider reject method. This is ok since
+ * cm_conn_req_handler() runs in the workqueue thread context.
+ */
+
+static struct iwcm_work *get_work(struct iwcm_id_private *cm_id_priv)
+{
+ struct iwcm_work *work;
+
+ if (list_empty(&cm_id_priv->work_free_list))
+ return NULL;
+ work = list_entry(cm_id_priv->work_free_list.next, struct iwcm_work,
+ free_list);
+ list_del_init(&work->free_list);
+ return work;
+}
+
+static void put_work(struct iwcm_work *work)
+{
+ list_add(&work->free_list, &work->cm_id->work_free_list);
+}
+
+static void dealloc_work_entries(struct iwcm_id_private *cm_id_priv)
+{
+ struct list_head *e, *tmp;
+
+ list_for_each_safe(e, tmp, &cm_id_priv->work_free_list)
+ kfree(list_entry(e, struct iwcm_work, free_list));
+}
+
+static int alloc_work_entries(struct iwcm_id_private *cm_id_priv, int count)
+{
+ struct iwcm_work *work;
+
+ BUG_ON(!list_empty(&cm_id_priv->work_free_list));
+ while (count--) {
+ work = kmalloc(sizeof(struct iwcm_work), GFP_KERNEL);
+ if (!work) {
+ dealloc_work_entries(cm_id_priv);
+ return -ENOMEM;
+ }
+ work->cm_id = cm_id_priv;
+ INIT_LIST_HEAD(&work->list);
+ put_work(work);
+ }
+ return 0;
+}
+
+/*
+ * Save private data from incoming connection requests in the
+ * cm_id_priv so the low level driver doesn't have to. Adjust
+ * the event ptr to point to the local copy.
+ */
+static int copy_private_data(struct iwcm_id_private *cm_id_priv,
+ struct iw_cm_event *event)
+{
+ void *p;
+
+ p = kmalloc(event->private_data_len, GFP_ATOMIC);
+ if (!p)
+ return -ENOMEM;
+ memcpy(p, event->private_data, event->private_data_len);
+ event->private_data = p;
+ return 0;
+}
+
+/*
+ * Release a reference on cm_id. If the last reference is being removed
+ * and iw_destroy_cm_id is waiting, wake up the waiting thread.
+ */
+static int iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
+{
+ int ret = 0;
+
+ BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
+ if (atomic_dec_and_test(&cm_id_priv->refcount)) {
+ BUG_ON(!list_empty(&cm_id_priv->work_list));
+ if (waitqueue_active(&cm_id_priv->destroy_comp.wait)) {
+ BUG_ON(cm_id_priv->state != IW_CM_STATE_DESTROYING);
+ BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY,
+ &cm_id_priv->flags));
+ ret = 1;
+ }
+ complete(&cm_id_priv->destroy_comp);
+ }
+
+ return ret;
+}
+
+static void add_ref(struct iw_cm_id *cm_id)
+{
+ struct iwcm_id_private *cm_id_priv;
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ atomic_inc(&cm_id_priv->refcount);
+}
+
+static void rem_ref(struct iw_cm_id *cm_id)
+{
+ struct iwcm_id_private *cm_id_priv;
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ iwcm_deref_id(cm_id_priv);
+}
+
+static int cm_event_handler(struct iw_cm_id *cm_id, struct iw_cm_event *event);
+
+struct iw_cm_id *iw_create_cm_id(struct ib_device *device,
+ iw_cm_handler cm_handler,
+ void *context)
+{
+ struct iwcm_id_private *cm_id_priv;
+
+ cm_id_priv = kzalloc(sizeof(*cm_id_priv), GFP_KERNEL);
+ if (!cm_id_priv)
+ return ERR_PTR(-ENOMEM);
+
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ cm_id_priv->id.device = device;
+ cm_id_priv->id.cm_handler = cm_handler;
+ cm_id_priv->id.context = context;
+ cm_id_priv->id.event_handler = cm_event_handler;
+ cm_id_priv->id.add_ref = add_ref;
+ cm_id_priv->id.rem_ref = rem_ref;
+ spin_lock_init(&cm_id_priv->lock);
+ atomic_set(&cm_id_priv->refcount, 1);
+ init_waitqueue_head(&cm_id_priv->connect_wait);
+ init_completion(&cm_id_priv->destroy_comp);
+ INIT_LIST_HEAD(&cm_id_priv->work_list);
+ INIT_LIST_HEAD(&cm_id_priv->work_free_list);
+
+ return &cm_id_priv->id;
+}
+EXPORT_SYMBOL(iw_create_cm_id);
+
+
+static int iwcm_modify_qp_err(struct ib_qp *qp)
+{
+ struct ib_qp_attr qp_attr;
+
+ if (!qp)
+ return -EINVAL;
+
+ qp_attr.qp_state = IB_QPS_ERR;
+ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
+}
+
+/*
+ * This is really the RDMAC CLOSING state. It is most similar to the
+ * IB SQD QP state.
+ */
+static int iwcm_modify_qp_sqd(struct ib_qp *qp)
+{
+ struct ib_qp_attr qp_attr;
+
+ BUG_ON(qp == NULL);
+ qp_attr.qp_state = IB_QPS_SQD;
+ return ib_modify_qp(qp, &qp_attr, IB_QP_STATE);
+}
+
+/*
+ * CM_ID <-- CLOSING
+ *
+ * Block if a passive or active connection is currenlty being processed. Then
+ * process the event as follows:
+ * - If we are ESTABLISHED, move to CLOSING and modify the QP state
+ * based on the abrupt flag
+ * - If the connection is already in the CLOSING or IDLE state, the peer is
+ * disconnecting concurrently with us and we've already seen the
+ * DISCONNECT event -- ignore the request and return 0
+ * - Disconnect on a listening endpoint returns -EINVAL
+ */
+int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt)
+{
+ struct iwcm_id_private *cm_id_priv;
+ unsigned long flags;
+ int ret = 0;
+ struct ib_qp *qp = NULL;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ /* Wait if we're currently in a connect or accept downcall */
+ wait_event(cm_id_priv->connect_wait,
+ !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->state) {
+ case IW_CM_STATE_ESTABLISHED:
+ cm_id_priv->state = IW_CM_STATE_CLOSING;
+
+ /* QP could be <nul> for user-mode client */
+ if (cm_id_priv->qp)
+ qp = cm_id_priv->qp;
+ else
+ ret = -EINVAL;
+ break;
+ case IW_CM_STATE_LISTEN:
+ ret = -EINVAL;
+ break;
+ case IW_CM_STATE_CLOSING:
+ /* remote peer closed first */
+ case IW_CM_STATE_IDLE:
+ /* accept or connect returned !0 */
+ break;
+ case IW_CM_STATE_CONN_RECV:
+ /*
+ * App called disconnect before/without calling accept after
+ * connect_request event delivered.
+ */
+ break;
+ case IW_CM_STATE_CONN_SENT:
+ /* Can only get here if wait above fails */
+ default:
+ BUG();
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ if (qp) {
+ if (abrupt)
+ ret = iwcm_modify_qp_err(qp);
+ else
+ ret = iwcm_modify_qp_sqd(qp);
+
+ /*
+ * If both sides are disconnecting the QP could
+ * already be in ERR or SQD states
+ */
+ ret = 0;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(iw_cm_disconnect);
+
+/*
+ * CM_ID <-- DESTROYING
+ *
+ * Clean up all resources associated with the connection and release
+ * the initial reference taken by iw_create_cm_id.
+ */
+static void destroy_cm_id(struct iw_cm_id *cm_id)
+{
+ struct iwcm_id_private *cm_id_priv;
+ unsigned long flags;
+ int ret;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ /*
+ * Wait if we're currently in a connect or accept downcall. A
+ * listening endpoint should never block here.
+ */
+ wait_event(cm_id_priv->connect_wait,
+ !test_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags));
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->state) {
+ case IW_CM_STATE_LISTEN:
+ cm_id_priv->state = IW_CM_STATE_DESTROYING;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ /* destroy the listening endpoint */
+ ret = cm_id->device->iwcm->destroy_listen(cm_id);
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ break;
+ case IW_CM_STATE_ESTABLISHED:
+ cm_id_priv->state = IW_CM_STATE_DESTROYING;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ /* Abrupt close of the connection */
+ (void)iwcm_modify_qp_err(cm_id_priv->qp);
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ break;
+ case IW_CM_STATE_IDLE:
+ case IW_CM_STATE_CLOSING:
+ cm_id_priv->state = IW_CM_STATE_DESTROYING;
+ break;
+ case IW_CM_STATE_CONN_RECV:
+ /*
+ * App called destroy before/without calling accept after
+ * receiving connection request event notification.
+ */
+ cm_id_priv->state = IW_CM_STATE_DESTROYING;
+ break;
+ case IW_CM_STATE_CONN_SENT:
+ case IW_CM_STATE_DESTROYING:
+ default:
+ BUG();
+ break;
+ }
+ if (cm_id_priv->qp) {
+ cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp);
+ cm_id_priv->qp = NULL;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ (void)iwcm_deref_id(cm_id_priv);
+}
+
+/*
+ * This function is only called by the application thread and cannot
+ * be called by the event thread. The function will wait for all
+ * references to be released on the cm_id and then kfree the cm_id
+ * object.
+ */
+void iw_destroy_cm_id(struct iw_cm_id *cm_id)
+{
+ struct iwcm_id_private *cm_id_priv;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ BUG_ON(test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags));
+
+ destroy_cm_id(cm_id);
+
+ wait_for_completion(&cm_id_priv->destroy_comp);
+
+ dealloc_work_entries(cm_id_priv);
+
+ kfree(cm_id_priv);
+}
+EXPORT_SYMBOL(iw_destroy_cm_id);
+
+/*
+ * CM_ID <-- LISTEN
+ *
+ * Start listening for connect requests. Generates one CONNECT_REQUEST
+ * event for each inbound connect request.
+ */
+int iw_cm_listen(struct iw_cm_id *cm_id, int backlog)
+{
+ struct iwcm_id_private *cm_id_priv;
+ unsigned long flags;
+ int ret = 0;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+
+ ret = alloc_work_entries(cm_id_priv, backlog);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->state) {
+ case IW_CM_STATE_IDLE:
+ cm_id_priv->state = IW_CM_STATE_LISTEN;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = cm_id->device->iwcm->create_listen(cm_id, backlog);
+ if (ret)
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(iw_cm_listen);
+
+/*
+ * CM_ID <-- IDLE
+ *
+ * Rejects an inbound connection request. No events are generated.
+ */
+int iw_cm_reject(struct iw_cm_id *cm_id,
+ const void *private_data,
+ u8 private_data_len)
+{
+ struct iwcm_id_private *cm_id_priv;
+ unsigned long flags;
+ int ret;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ if (cm_id_priv->state != IW_CM_STATE_CONN_RECV) {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
+ return -EINVAL;
+ }
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ ret = cm_id->device->iwcm->reject(cm_id, private_data,
+ private_data_len);
+
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
+
+ return ret;
+}
+EXPORT_SYMBOL(iw_cm_reject);
+
+/*
+ * CM_ID <-- ESTABLISHED
+ *
+ * Accepts an inbound connection request and generates an ESTABLISHED
+ * event. Callers of iw_cm_disconnect and iw_destroy_cm_id will block
+ * until the ESTABLISHED event is received from the provider.
+ */
+int iw_cm_accept(struct iw_cm_id *cm_id,
+ struct iw_cm_conn_param *iw_param)
+{
+ struct iwcm_id_private *cm_id_priv;
+ struct ib_qp *qp;
+ unsigned long flags;
+ int ret;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ if (cm_id_priv->state != IW_CM_STATE_CONN_RECV) {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
+ return -EINVAL;
+ }
+ /* Get the ib_qp given the QPN */
+ qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
+ if (!qp) {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return -EINVAL;
+ }
+ cm_id->device->iwcm->add_ref(qp);
+ cm_id_priv->qp = qp;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ ret = cm_id->device->iwcm->accept(cm_id, iw_param);
+ if (ret) {
+ /* An error on accept precludes provider events */
+ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ if (cm_id_priv->qp) {
+ cm_id->device->iwcm->rem_ref(qp);
+ cm_id_priv->qp = NULL;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(iw_cm_accept);
+
+/*
+ * Active Side: CM_ID <-- CONN_SENT
+ *
+ * If successful, results in the generation of a CONNECT_REPLY
+ * event. iw_cm_disconnect and iw_cm_destroy will block until the
+ * CONNECT_REPLY event is received from the provider.
+ */
+int iw_cm_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+ struct iwcm_id_private *cm_id_priv;
+ int ret = 0;
+ unsigned long flags;
+ struct ib_qp *qp;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+
+ ret = alloc_work_entries(cm_id_priv, 4);
+ if (ret)
+ return ret;
+
+ set_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+
+ if (cm_id_priv->state != IW_CM_STATE_IDLE) {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
+ return -EINVAL;
+ }
+
+ /* Get the ib_qp given the QPN */
+ qp = cm_id->device->iwcm->get_qp(cm_id->device, iw_param->qpn);
+ if (!qp) {
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return -EINVAL;
+ }
+ cm_id->device->iwcm->add_ref(qp);
+ cm_id_priv->qp = qp;
+ cm_id_priv->state = IW_CM_STATE_CONN_SENT;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ ret = cm_id->device->iwcm->connect(cm_id, iw_param);
+ if (ret) {
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ if (cm_id_priv->qp) {
+ cm_id->device->iwcm->rem_ref(qp);
+ cm_id_priv->qp = NULL;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ wake_up_all(&cm_id_priv->connect_wait);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(iw_cm_connect);
+
+/*
+ * Passive Side: new CM_ID <-- CONN_RECV
+ *
+ * Handles an inbound connect request. The function creates a new
+ * iw_cm_id to represent the new connection and inherits the client
+ * callback function and other attributes from the listening parent.
+ *
+ * The work item contains a pointer to the listen_cm_id and the event. The
+ * listen_cm_id contains the client cm_handler, context and
+ * device. These are copied when the device is cloned. The event
+ * contains the new four tuple.
+ *
+ * An error on the child should not affect the parent, so this
+ * function does not return a value.
+ */
+static void cm_conn_req_handler(struct iwcm_id_private *listen_id_priv,
+ struct iw_cm_event *iw_event)
+{
+ unsigned long flags;
+ struct iw_cm_id *cm_id;
+ struct iwcm_id_private *cm_id_priv;
+ int ret;
+
+ /*
+ * The provider should never generate a connection request
+ * event with a bad status.
+ */
+ BUG_ON(iw_event->status);
+
+ /*
+ * We could be destroying the listening id. If so, ignore this
+ * upcall.
+ */
+ spin_lock_irqsave(&listen_id_priv->lock, flags);
+ if (listen_id_priv->state != IW_CM_STATE_LISTEN) {
+ spin_unlock_irqrestore(&listen_id_priv->lock, flags);
+ return;
+ }
+ spin_unlock_irqrestore(&listen_id_priv->lock, flags);
+
+ cm_id = iw_create_cm_id(listen_id_priv->id.device,
+ listen_id_priv->id.cm_handler,
+ listen_id_priv->id.context);
+ /* If the cm_id could not be created, ignore the request */
+ if (IS_ERR(cm_id))
+ return;
+
+ cm_id->provider_data = iw_event->provider_data;
+ cm_id->local_addr = iw_event->local_addr;
+ cm_id->remote_addr = iw_event->remote_addr;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ cm_id_priv->state = IW_CM_STATE_CONN_RECV;
+
+ ret = alloc_work_entries(cm_id_priv, 3);
+ if (ret) {
+ iw_cm_reject(cm_id, NULL, 0);
+ iw_destroy_cm_id(cm_id);
+ return;
+ }
+
+ /* Call the client CM handler */
+ ret = cm_id->cm_handler(cm_id, iw_event);
+ if (ret) {
+ set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
+ destroy_cm_id(cm_id);
+ if (atomic_read(&cm_id_priv->refcount)==0)
+ kfree(cm_id);
+ }
+
+ if (iw_event->private_data_len)
+ kfree(iw_event->private_data);
+}
+
+/*
+ * Passive Side: CM_ID <-- ESTABLISHED
+ *
+ * The provider generated an ESTABLISHED event which means that
+ * the MPA negotion has completed successfully and we are now in MPA
+ * FPDU mode.
+ *
+ * This event can only be received in the CONN_RECV state. If the
+ * remote peer closed, the ESTABLISHED event would be received followed
+ * by the CLOSE event. If the app closes, it will block until we wake
+ * it up after processing this event.
+ */
+static int cm_conn_est_handler(struct iwcm_id_private *cm_id_priv,
+ struct iw_cm_event *iw_event)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+
+ /*
+ * We clear the CONNECT_WAIT bit here to allow the callback
+ * function to call iw_cm_disconnect. Calling iw_destroy_cm_id
+ * from a callback handler is not allowed.
+ */
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_RECV);
+ cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
+ wake_up_all(&cm_id_priv->connect_wait);
+
+ return ret;
+}
+
+/*
+ * Active Side: CM_ID <-- ESTABLISHED
+ *
+ * The app has called connect and is waiting for the established event to
+ * post it's requests to the server. This event will wake up anyone
+ * blocked in iw_cm_disconnect or iw_destroy_id.
+ */
+static int cm_conn_rep_handler(struct iwcm_id_private *cm_id_priv,
+ struct iw_cm_event *iw_event)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ /*
+ * Clear the connect wait bit so a callback function calling
+ * iw_cm_disconnect will not wait and deadlock this thread
+ */
+ clear_bit(IWCM_F_CONNECT_WAIT, &cm_id_priv->flags);
+ BUG_ON(cm_id_priv->state != IW_CM_STATE_CONN_SENT);
+ if (iw_event->status == IW_CM_EVENT_STATUS_ACCEPTED) {
+ cm_id_priv->id.local_addr = iw_event->local_addr;
+ cm_id_priv->id.remote_addr = iw_event->remote_addr;
+ cm_id_priv->state = IW_CM_STATE_ESTABLISHED;
+ } else {
+ /* REJECTED or RESET */
+ cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp);
+ cm_id_priv->qp = NULL;
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
+
+ if (iw_event->private_data_len)
+ kfree(iw_event->private_data);
+
+ /* Wake up waiters on connect complete */
+ wake_up_all(&cm_id_priv->connect_wait);
+
+ return ret;
+}
+
+/*
+ * CM_ID <-- CLOSING
+ *
+ * If in the ESTABLISHED state, move to CLOSING.
+ */
+static void cm_disconnect_handler(struct iwcm_id_private *cm_id_priv,
+ struct iw_cm_event *iw_event)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ if (cm_id_priv->state == IW_CM_STATE_ESTABLISHED)
+ cm_id_priv->state = IW_CM_STATE_CLOSING;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+}
+
+/*
+ * CM_ID <-- IDLE
+ *
+ * If in the ESTBLISHED or CLOSING states, the QP will have have been
+ * moved by the provider to the ERR state. Disassociate the CM_ID from
+ * the QP, move to IDLE, and remove the 'connected' reference.
+ *
+ * If in some other state, the cm_id was destroyed asynchronously.
+ * This is the last reference that will result in waking up
+ * the app thread blocked in iw_destroy_cm_id.
+ */
+static int cm_close_handler(struct iwcm_id_private *cm_id_priv,
+ struct iw_cm_event *iw_event)
+{
+ unsigned long flags;
+ int ret = 0;
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+
+ if (cm_id_priv->qp) {
+ cm_id_priv->id.device->iwcm->rem_ref(cm_id_priv->qp);
+ cm_id_priv->qp = NULL;
+ }
+ switch (cm_id_priv->state) {
+ case IW_CM_STATE_ESTABLISHED:
+ case IW_CM_STATE_CLOSING:
+ cm_id_priv->state = IW_CM_STATE_IDLE;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ ret = cm_id_priv->id.cm_handler(&cm_id_priv->id, iw_event);
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ break;
+ case IW_CM_STATE_DESTROYING:
+ break;
+ default:
+ BUG();
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ return ret;
+}
+
+static int process_event(struct iwcm_id_private *cm_id_priv,
+ struct iw_cm_event *iw_event)
+{
+ int ret = 0;
+
+ switch (iw_event->event) {
+ case IW_CM_EVENT_CONNECT_REQUEST:
+ cm_conn_req_handler(cm_id_priv, iw_event);
+ break;
+ case IW_CM_EVENT_CONNECT_REPLY:
+ ret = cm_conn_rep_handler(cm_id_priv, iw_event);
+ break;
+ case IW_CM_EVENT_ESTABLISHED:
+ ret = cm_conn_est_handler(cm_id_priv, iw_event);
+ break;
+ case IW_CM_EVENT_DISCONNECT:
+ cm_disconnect_handler(cm_id_priv, iw_event);
+ break;
+ case IW_CM_EVENT_CLOSE:
+ ret = cm_close_handler(cm_id_priv, iw_event);
+ break;
+ default:
+ BUG();
+ }
+
+ return ret;
+}
+
+/*
+ * Process events on the work_list for the cm_id. If the callback
+ * function requests that the cm_id be deleted, a flag is set in the
+ * cm_id flags to indicate that when the last reference is
+ * removed, the cm_id is to be destroyed. This is necessary to
+ * distinguish between an object that will be destroyed by the app
+ * thread asleep on the destroy_comp list vs. an object destroyed
+ * here synchronously when the last reference is removed.
+ */
+static void cm_work_handler(void *arg)
+{
+ struct iwcm_work *work = arg, lwork;
+ struct iwcm_id_private *cm_id_priv = work->cm_id;
+ unsigned long flags;
+ int empty;
+ int ret = 0;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ empty = list_empty(&cm_id_priv->work_list);
+ while (!empty) {
+ work = list_entry(cm_id_priv->work_list.next,
+ struct iwcm_work, list);
+ list_del_init(&work->list);
+ empty = list_empty(&cm_id_priv->work_list);
+ lwork = *work;
+ put_work(work);
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+
+ ret = process_event(cm_id_priv, &work->event);
+ if (ret) {
+ set_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags);
+ destroy_cm_id(&cm_id_priv->id);
+ }
+ BUG_ON(atomic_read(&cm_id_priv->refcount)==0);
+ if (iwcm_deref_id(cm_id_priv))
+ return;
+
+ if (atomic_read(&cm_id_priv->refcount)==0 &&
+ test_bit(IWCM_F_CALLBACK_DESTROY, &cm_id_priv->flags)) {
+ dealloc_work_entries(cm_id_priv);
+ kfree(cm_id_priv);
+ return;
+ }
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+}
+
+/*
+ * This function is called on interrupt context. Schedule events on
+ * the iwcm_wq thread to allow callback functions to downcall into
+ * the CM and/or block. Events are queued to a per-CM_ID
+ * work_list. If this is the first event on the work_list, the work
+ * element is also queued on the iwcm_wq thread.
+ *
+ * Each event holds a reference on the cm_id. Until the last posted
+ * event has been delivered and processed, the cm_id cannot be
+ * deleted.
+ *
+ * Returns:
+ * 0 - the event was handled.
+ * -ENOMEM - the event was not handled due to lack of resources.
+ */
+static int cm_event_handler(struct iw_cm_id *cm_id,
+ struct iw_cm_event *iw_event)
+{
+ struct iwcm_work *work;
+ struct iwcm_id_private *cm_id_priv;
+ unsigned long flags;
+ int ret = 0;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ work = get_work(cm_id_priv);
+ if (!work) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ INIT_WORK(&work->work, cm_work_handler, work);
+ work->cm_id = cm_id_priv;
+ work->event = *iw_event;
+
+ if ((work->event.event == IW_CM_EVENT_CONNECT_REQUEST ||
+ work->event.event == IW_CM_EVENT_CONNECT_REPLY) &&
+ work->event.private_data_len) {
+ ret = copy_private_data(cm_id_priv, &work->event);
+ if (ret) {
+ put_work(work);
+ goto out;
+ }
+ }
+
+ atomic_inc(&cm_id_priv->refcount);
+ if (list_empty(&cm_id_priv->work_list)) {
+ list_add_tail(&work->list, &cm_id_priv->work_list);
+ queue_work(iwcm_wq, &work->work);
+ } else
+ list_add_tail(&work->list, &cm_id_priv->work_list);
+out:
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return ret;
+}
+
+static int iwcm_init_qp_init_attr(struct iwcm_id_private *cm_id_priv,
+ struct ib_qp_attr *qp_attr,
+ int *qp_attr_mask)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->state) {
+ case IW_CM_STATE_IDLE:
+ case IW_CM_STATE_CONN_SENT:
+ case IW_CM_STATE_CONN_RECV:
+ case IW_CM_STATE_ESTABLISHED:
+ *qp_attr_mask = IB_QP_STATE | IB_QP_ACCESS_FLAGS;
+ qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE|
+ IB_ACCESS_REMOTE_READ;
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return ret;
+}
+
+static int iwcm_init_qp_rts_attr(struct iwcm_id_private *cm_id_priv,
+ struct ib_qp_attr *qp_attr,
+ int *qp_attr_mask)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
+ switch (cm_id_priv->state) {
+ case IW_CM_STATE_IDLE:
+ case IW_CM_STATE_CONN_SENT:
+ case IW_CM_STATE_CONN_RECV:
+ case IW_CM_STATE_ESTABLISHED:
+ *qp_attr_mask = 0;
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ return ret;
+}
+
+int iw_cm_init_qp_attr(struct iw_cm_id *cm_id,
+ struct ib_qp_attr *qp_attr,
+ int *qp_attr_mask)
+{
+ struct iwcm_id_private *cm_id_priv;
+ int ret;
+
+ cm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
+ switch (qp_attr->qp_state) {
+ case IB_QPS_INIT:
+ case IB_QPS_RTR:
+ ret = iwcm_init_qp_init_attr(cm_id_priv,
+ qp_attr, qp_attr_mask);
+ break;
+ case IB_QPS_RTS:
+ ret = iwcm_init_qp_rts_attr(cm_id_priv,
+ qp_attr, qp_attr_mask);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL(iw_cm_init_qp_attr);
+
+static int __init iw_cm_init(void)
+{
+ iwcm_wq = create_singlethread_workqueue("iw_cm_wq");
+ if (!iwcm_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __exit iw_cm_cleanup(void)
+{
+ destroy_workqueue(iwcm_wq);
+}
+
+module_init(iw_cm_init);
+module_exit(iw_cm_cleanup);
diff --git a/drivers/infiniband/core/iwcm.h b/drivers/infiniband/core/iwcm.h
new file mode 100644
index 00000000000..3f6cc82564c
--- /dev/null
+++ b/drivers/infiniband/core/iwcm.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005 Network Appliance, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef IWCM_H
+#define IWCM_H
+
+enum iw_cm_state {
+ IW_CM_STATE_IDLE, /* unbound, inactive */
+ IW_CM_STATE_LISTEN, /* listen waiting for connect */
+ IW_CM_STATE_CONN_RECV, /* inbound waiting for user accept */
+ IW_CM_STATE_CONN_SENT, /* outbound waiting for peer accept */
+ IW_CM_STATE_ESTABLISHED, /* established */
+ IW_CM_STATE_CLOSING, /* disconnect */
+ IW_CM_STATE_DESTROYING /* object being deleted */
+};
+
+struct iwcm_id_private {
+ struct iw_cm_id id;
+ enum iw_cm_state state;
+ unsigned long flags;
+ struct ib_qp *qp;
+ struct completion destroy_comp;
+ wait_queue_head_t connect_wait;
+ struct list_head work_list;
+ spinlock_t lock;
+ atomic_t refcount;
+ struct list_head work_free_list;
+};
+
+#define IWCM_F_CALLBACK_DESTROY 1
+#define IWCM_F_CONNECT_WAIT 2
+
+#endif /* IWCM_H */
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index b38e02a5db3..493f4c65c7a 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -167,6 +167,15 @@ static int is_vendor_method_in_use(
return 0;
}
+int ib_response_mad(struct ib_mad *mad)
+{
+ return ((mad->mad_hdr.method & IB_MGMT_METHOD_RESP) ||
+ (mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) ||
+ ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_BM) &&
+ (mad->mad_hdr.attr_mod & IB_BM_ATTR_MOD_RESP)));
+}
+EXPORT_SYMBOL(ib_response_mad);
+
/*
* ib_register_mad_agent - Register to send/receive MADs
*/
@@ -570,13 +579,6 @@ int ib_unregister_mad_agent(struct ib_mad_agent *mad_agent)
}
EXPORT_SYMBOL(ib_unregister_mad_agent);
-static inline int response_mad(struct ib_mad *mad)
-{
- /* Trap represses are responses although response bit is reset */
- return ((mad->mad_hdr.method == IB_MGMT_METHOD_TRAP_REPRESS) ||
- (mad->mad_hdr.method & IB_MGMT_METHOD_RESP));
-}
-
static void dequeue_mad(struct ib_mad_list_head *mad_list)
{
struct ib_mad_queue *mad_queue;
@@ -723,7 +725,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
switch (ret)
{
case IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY:
- if (response_mad(&mad_priv->mad.mad) &&
+ if (ib_response_mad(&mad_priv->mad.mad) &&
mad_agent_priv->agent.recv_handler) {
local->mad_priv = mad_priv;
local->recv_mad_agent = mad_agent_priv;
@@ -1244,8 +1246,8 @@ static int find_vendor_oui(struct ib_mad_mgmt_vendor_class *vendor_class,
int i;
for (i = 0; i < MAX_MGMT_OUI; i++)
- /* Is there matching OUI for this vendor class ? */
- if (!memcmp(vendor_class->oui[i], oui, 3))
+ /* Is there matching OUI for this vendor class ? */
+ if (!memcmp(vendor_class->oui[i], oui, 3))
return i;
return -1;
@@ -1551,7 +1553,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv,
unsigned long flags;
spin_lock_irqsave(&port_priv->reg_lock, flags);
- if (response_mad(mad)) {
+ if (ib_response_mad(mad)) {
u32 hi_tid;
struct ib_mad_agent_private *entry;
@@ -1775,11 +1777,9 @@ ib_find_send_mad(struct ib_mad_agent_private *mad_agent_priv,
void ib_mark_mad_done(struct ib_mad_send_wr_private *mad_send_wr)
{
mad_send_wr->timeout = 0;
- if (mad_send_wr->refcount == 1) {
- list_del(&mad_send_wr->agent_list);
- list_add_tail(&mad_send_wr->agent_list,
+ if (mad_send_wr->refcount == 1)
+ list_move_tail(&mad_send_wr->agent_list,
&mad_send_wr->mad_agent_priv->done_list);
- }
}
static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
@@ -1801,7 +1801,7 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv,
}
/* Complete corresponding request */
- if (response_mad(mad_recv_wc->recv_buf.mad)) {
+ if (ib_response_mad(mad_recv_wc->recv_buf.mad)) {
spin_lock_irqsave(&mad_agent_priv->lock, flags);
mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc);
if (!mad_send_wr) {
@@ -2098,8 +2098,7 @@ retry:
queued_send_wr = container_of(mad_list,
struct ib_mad_send_wr_private,
mad_list);
- list_del(&mad_list->list);
- list_add_tail(&mad_list->list, &send_queue->list);
+ list_move_tail(&mad_list->list, &send_queue->list);
}
spin_unlock_irqrestore(&send_queue->lock, flags);
@@ -2238,7 +2237,7 @@ static void cancel_mads(struct ib_mad_agent_private *mad_agent_priv)
list_for_each_entry_safe(mad_send_wr, temp_mad_send_wr,
&mad_agent_priv->send_list, agent_list) {
if (mad_send_wr->status == IB_WC_SUCCESS) {
- mad_send_wr->status = IB_WC_WR_FLUSH_ERR;
+ mad_send_wr->status = IB_WC_WR_FLUSH_ERR;
mad_send_wr->refcount -= (mad_send_wr->timeout > 0);
}
}
@@ -2529,10 +2528,10 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info,
}
}
sg_list.addr = dma_map_single(qp_info->port_priv->
- device->dma_device,
+ device->dma_device,
&mad_priv->grh,
sizeof *mad_priv -
- sizeof mad_priv->header,
+ sizeof mad_priv->header,
DMA_FROM_DEVICE);
pci_unmap_addr_set(&mad_priv->header, mapping, sg_list.addr);
recv_wr.wr_id = (unsigned long)&mad_priv->header.mad_list;
@@ -2607,7 +2606,7 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv)
struct ib_qp *qp;
attr = kmalloc(sizeof *attr, GFP_KERNEL);
- if (!attr) {
+ if (!attr) {
printk(KERN_ERR PFX "Couldn't kmalloc ib_qp_attr\n");
return -ENOMEM;
}
@@ -2877,7 +2876,10 @@ static void ib_mad_init_device(struct ib_device *device)
{
int start, end, i;
- if (device->node_type == IB_NODE_SWITCH) {
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
start = 0;
end = 0;
} else {
@@ -2924,7 +2926,7 @@ static void ib_mad_remove_device(struct ib_device *device)
{
int i, num_ports, cur_port;
- if (device->node_type == IB_NODE_SWITCH) {
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
num_ports = 1;
cur_port = 0;
} else {
@@ -2985,10 +2987,7 @@ error1:
static void __exit ib_mad_cleanup_module(void)
{
ib_unregister_client(&mad_client);
-
- if (kmem_cache_destroy(ib_mad_cache)) {
- printk(KERN_DEBUG PFX "Failed to destroy ib_mad cache\n");
- }
+ kmem_cache_destroy(ib_mad_cache);
}
module_init(ib_mad_init_module);
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h
index d147f3bad2c..d06b59083f6 100644
--- a/drivers/infiniband/core/mad_priv.h
+++ b/drivers/infiniband/core/mad_priv.h
@@ -38,8 +38,8 @@
#define __IB_MAD_PRIV_H__
#include <linux/completion.h>
+#include <linux/err.h>
#include <linux/pci.h>
-#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <rdma/ib_mad.h>
#include <rdma/ib_smi.h>
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c
index d4704e054e3..1ef79d015a1 100644
--- a/drivers/infiniband/core/mad_rmpp.c
+++ b/drivers/infiniband/core/mad_rmpp.c
@@ -33,8 +33,6 @@
* $Id: mad_rmpp.c 1921 2005-03-02 22:58:44Z sean.hefty $
*/
-#include <linux/dma-mapping.h>
-
#include "mad_priv.h"
#include "mad_rmpp.h"
@@ -60,6 +58,7 @@ struct mad_rmpp_recv {
int last_ack;
int seg_num;
int newwin;
+ int repwin;
__be64 tid;
u32 src_qp;
@@ -170,6 +169,32 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent,
return msg;
}
+static void ack_ds_ack(struct ib_mad_agent_private *agent,
+ struct ib_mad_recv_wc *recv_wc)
+{
+ struct ib_mad_send_buf *msg;
+ struct ib_rmpp_mad *rmpp_mad;
+ int ret;
+
+ msg = alloc_response_msg(&agent->agent, recv_wc);
+ if (IS_ERR(msg))
+ return;
+
+ rmpp_mad = msg->mad;
+ memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len);
+
+ rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP;
+ ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE);
+ rmpp_mad->rmpp_hdr.seg_num = 0;
+ rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(1);
+
+ ret = ib_post_send_mad(msg, NULL);
+ if (ret) {
+ ib_destroy_ah(msg->ah);
+ ib_free_send_mad(msg);
+ }
+}
+
void ib_rmpp_send_handler(struct ib_mad_send_wc *mad_send_wc)
{
struct ib_rmpp_mad *rmpp_mad = mad_send_wc->send_buf->mad;
@@ -271,6 +296,7 @@ create_rmpp_recv(struct ib_mad_agent_private *agent,
rmpp_recv->newwin = 1;
rmpp_recv->seg_num = 1;
rmpp_recv->last_ack = 0;
+ rmpp_recv->repwin = 1;
mad_hdr = &mad_recv_wc->recv_buf.mad->mad_hdr;
rmpp_recv->tid = mad_hdr->tid;
@@ -365,7 +391,7 @@ static inline int window_size(struct ib_mad_agent_private *agent)
static struct ib_mad_recv_buf * find_seg_location(struct list_head *rmpp_list,
int seg_num)
{
- struct ib_mad_recv_buf *seg_buf;
+ struct ib_mad_recv_buf *seg_buf;
int cur_seg_num;
list_for_each_entry_reverse(seg_buf, rmpp_list, list) {
@@ -591,6 +617,16 @@ static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr,
break;
}
+static void process_ds_ack(struct ib_mad_agent_private *agent,
+ struct ib_mad_recv_wc *mad_recv_wc, int newwin)
+{
+ struct mad_rmpp_recv *rmpp_recv;
+
+ rmpp_recv = find_rmpp_recv(agent, mad_recv_wc);
+ if (rmpp_recv && rmpp_recv->state == RMPP_STATE_COMPLETE)
+ rmpp_recv->repwin = newwin;
+}
+
static void process_rmpp_ack(struct ib_mad_agent_private *agent,
struct ib_mad_recv_wc *mad_recv_wc)
{
@@ -616,8 +652,18 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
spin_lock_irqsave(&agent->lock, flags);
mad_send_wr = ib_find_send_mad(agent, mad_recv_wc);
- if (!mad_send_wr)
- goto out; /* Unmatched ACK */
+ if (!mad_send_wr) {
+ if (!seg_num)
+ process_ds_ack(agent, mad_recv_wc, newwin);
+ goto out; /* Unmatched or DS RMPP ACK */
+ }
+
+ if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) &&
+ (mad_send_wr->timeout)) {
+ spin_unlock_irqrestore(&agent->lock, flags);
+ ack_ds_ack(agent, mad_recv_wc);
+ return; /* Repeated ACK for DS RMPP transaction */
+ }
if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) ||
(!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS))
@@ -656,6 +702,9 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
if (mad_send_wr->refcount == 1)
ib_reset_mad_timeout(mad_send_wr,
mad_send_wr->send_buf.timeout_ms);
+ spin_unlock_irqrestore(&agent->lock, flags);
+ ack_ds_ack(agent, mad_recv_wc);
+ return;
} else if (mad_send_wr->refcount == 1 &&
mad_send_wr->seg_num < mad_send_wr->newwin &&
mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) {
@@ -665,8 +714,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent,
goto out;
mad_send_wr->refcount++;
- list_del(&mad_send_wr->agent_list);
- list_add_tail(&mad_send_wr->agent_list,
+ list_move_tail(&mad_send_wr->agent_list,
&mad_send_wr->mad_agent_priv->send_list);
}
out:
@@ -773,6 +821,39 @@ out:
return NULL;
}
+static int init_newwin(struct ib_mad_send_wr_private *mad_send_wr)
+{
+ struct ib_mad_agent_private *agent = mad_send_wr->mad_agent_priv;
+ struct ib_mad_hdr *mad_hdr = mad_send_wr->send_buf.mad;
+ struct mad_rmpp_recv *rmpp_recv;
+ struct ib_ah_attr ah_attr;
+ unsigned long flags;
+ int newwin = 1;
+
+ if (!(mad_hdr->method & IB_MGMT_METHOD_RESP))
+ goto out;
+
+ spin_lock_irqsave(&agent->lock, flags);
+ list_for_each_entry(rmpp_recv, &agent->rmpp_list, list) {
+ if (rmpp_recv->tid != mad_hdr->tid ||
+ rmpp_recv->mgmt_class != mad_hdr->mgmt_class ||
+ rmpp_recv->class_version != mad_hdr->class_version ||
+ (rmpp_recv->method & IB_MGMT_METHOD_RESP))
+ continue;
+
+ if (ib_query_ah(mad_send_wr->send_buf.ah, &ah_attr))
+ continue;
+
+ if (rmpp_recv->slid == ah_attr.dlid) {
+ newwin = rmpp_recv->repwin;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&agent->lock, flags);
+out:
+ return newwin;
+}
+
int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
{
struct ib_rmpp_mad *rmpp_mad;
@@ -788,7 +869,7 @@ int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr)
return IB_RMPP_RESULT_INTERNAL;
}
- mad_send_wr->newwin = 1;
+ mad_send_wr->newwin = init_newwin(mad_send_wr);
/* We need to wait for the final ACK even if there isn't a response */
mad_send_wr->refcount += (mad_send_wr->timeout == 0);
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index e911c99ff84..1706d3c7e95 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Voltaire, Inc.  All rights reserved.
+ * Copyright (c) 2006 Intel Corporation. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -75,6 +76,7 @@ struct ib_sa_device {
struct ib_sa_query {
void (*callback)(struct ib_sa_query *, int, struct ib_sa_mad *);
void (*release)(struct ib_sa_query *);
+ struct ib_sa_client *client;
struct ib_sa_port *port;
struct ib_mad_send_buf *mad_buf;
struct ib_sa_sm_ah *sm_ah;
@@ -405,7 +407,8 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event
event->event == IB_EVENT_PORT_ACTIVE ||
event->event == IB_EVENT_LID_CHANGE ||
event->event == IB_EVENT_PKEY_CHANGE ||
- event->event == IB_EVENT_SM_CHANGE) {
+ event->event == IB_EVENT_SM_CHANGE ||
+ event->event == IB_EVENT_CLIENT_REREGISTER) {
struct ib_sa_device *sa_dev;
sa_dev = container_of(handler, typeof(*sa_dev), event_handler);
@@ -414,6 +417,31 @@ static void ib_sa_event(struct ib_event_handler *handler, struct ib_event *event
}
}
+void ib_sa_register_client(struct ib_sa_client *client)
+{
+ atomic_set(&client->users, 1);
+ init_completion(&client->comp);
+}
+EXPORT_SYMBOL(ib_sa_register_client);
+
+static inline void ib_sa_client_get(struct ib_sa_client *client)
+{
+ atomic_inc(&client->users);
+}
+
+static inline void ib_sa_client_put(struct ib_sa_client *client)
+{
+ if (atomic_dec_and_test(&client->users))
+ complete(&client->comp);
+}
+
+void ib_sa_unregister_client(struct ib_sa_client *client)
+{
+ ib_sa_client_put(client);
+ wait_for_completion(&client->comp);
+}
+EXPORT_SYMBOL(ib_sa_unregister_client);
+
/**
* ib_sa_cancel_query - try to cancel an SA query
* @id:ID of query to cancel
@@ -488,13 +516,13 @@ static void init_mad(struct ib_sa_mad *mad, struct ib_mad_agent *agent)
spin_unlock_irqrestore(&tid_lock, flags);
}
-static int send_mad(struct ib_sa_query *query, int timeout_ms)
+static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
{
unsigned long flags;
int ret, id;
retry:
- if (!idr_pre_get(&query_idr, GFP_ATOMIC))
+ if (!idr_pre_get(&query_idr, gfp_mask))
return -ENOMEM;
spin_lock_irqsave(&idr_lock, flags);
ret = idr_get_new(&query_idr, query, &id);
@@ -556,6 +584,7 @@ static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
/**
* ib_sa_path_rec_get - Start a Path get query
+ * @client:SA client
* @device:device to send query on
* @port_num: port number to send query on
* @rec:Path Record to send in query
@@ -578,7 +607,8 @@ static void ib_sa_path_rec_release(struct ib_sa_query *sa_query)
* error code. Otherwise it is a query ID that can be used to cancel
* the query.
*/
-int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
+int ib_sa_path_rec_get(struct ib_sa_client *client,
+ struct ib_device *device, u8 port_num,
struct ib_sa_path_rec *rec,
ib_sa_comp_mask comp_mask,
int timeout_ms, gfp_t gfp_mask,
@@ -613,8 +643,10 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
goto err1;
}
- query->callback = callback;
- query->context = context;
+ ib_sa_client_get(client);
+ query->sa_query.client = client;
+ query->callback = callback;
+ query->context = context;
mad = query->sa_query.mad_buf->mad;
init_mad(mad, agent);
@@ -630,7 +662,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -638,6 +670,7 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
err2:
*sa_query = NULL;
+ ib_sa_client_put(query->sa_query.client);
ib_free_send_mad(query->sa_query.mad_buf);
err1:
@@ -670,6 +703,7 @@ static void ib_sa_service_rec_release(struct ib_sa_query *sa_query)
/**
* ib_sa_service_rec_query - Start Service Record operation
+ * @client:SA client
* @device:device to send request on
* @port_num: port number to send request on
* @method:SA method - should be get, set, or delete
@@ -694,7 +728,8 @@ static void ib_sa_service_rec_release(struct ib_sa_query *sa_query)
* error code. Otherwise it is a request ID that can be used to cancel
* the query.
*/
-int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
+int ib_sa_service_rec_query(struct ib_sa_client *client,
+ struct ib_device *device, u8 port_num, u8 method,
struct ib_sa_service_rec *rec,
ib_sa_comp_mask comp_mask,
int timeout_ms, gfp_t gfp_mask,
@@ -734,8 +769,10 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
goto err1;
}
- query->callback = callback;
- query->context = context;
+ ib_sa_client_get(client);
+ query->sa_query.client = client;
+ query->callback = callback;
+ query->context = context;
mad = query->sa_query.mad_buf->mad;
init_mad(mad, agent);
@@ -752,7 +789,7 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -760,6 +797,7 @@ int ib_sa_service_rec_query(struct ib_device *device, u8 port_num, u8 method,
err2:
*sa_query = NULL;
+ ib_sa_client_put(query->sa_query.client);
ib_free_send_mad(query->sa_query.mad_buf);
err1:
@@ -790,7 +828,8 @@ static void ib_sa_mcmember_rec_release(struct ib_sa_query *sa_query)
kfree(container_of(sa_query, struct ib_sa_mcmember_query, sa_query));
}
-int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
+int ib_sa_mcmember_rec_query(struct ib_sa_client *client,
+ struct ib_device *device, u8 port_num,
u8 method,
struct ib_sa_mcmember_rec *rec,
ib_sa_comp_mask comp_mask,
@@ -826,8 +865,10 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
goto err1;
}
- query->callback = callback;
- query->context = context;
+ ib_sa_client_get(client);
+ query->sa_query.client = client;
+ query->callback = callback;
+ query->context = context;
mad = query->sa_query.mad_buf->mad;
init_mad(mad, agent);
@@ -844,7 +885,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
*sa_query = &query->sa_query;
- ret = send_mad(&query->sa_query, timeout_ms);
+ ret = send_mad(&query->sa_query, timeout_ms, gfp_mask);
if (ret < 0)
goto err2;
@@ -852,6 +893,7 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
err2:
*sa_query = NULL;
+ ib_sa_client_put(query->sa_query.client);
ib_free_send_mad(query->sa_query.mad_buf);
err1:
@@ -886,8 +928,9 @@ static void send_handler(struct ib_mad_agent *agent,
idr_remove(&query_idr, query->id);
spin_unlock_irqrestore(&idr_lock, flags);
- ib_free_send_mad(mad_send_wc->send_buf);
+ ib_free_send_mad(mad_send_wc->send_buf);
kref_put(&query->sm_ah->ref, free_sm_ah);
+ ib_sa_client_put(query->client);
query->release(query);
}
@@ -918,7 +961,10 @@ static void ib_sa_add_one(struct ib_device *device)
struct ib_sa_device *sa_dev;
int s, e, i;
- if (device->node_type == IB_NODE_SWITCH)
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
+ if (device->node_type == RDMA_NODE_IB_SWITCH)
s = e = 0;
else {
s = 1;
diff --git a/drivers/infiniband/core/smi.c b/drivers/infiniband/core/smi.c
index 35852e794e2..54b81e17ad5 100644
--- a/drivers/infiniband/core/smi.c
+++ b/drivers/infiniband/core/smi.c
@@ -64,7 +64,7 @@ int smi_handle_dr_smp_send(struct ib_smp *smp,
/* C14-9:2 */
if (hop_ptr && hop_ptr < hop_cnt) {
- if (node_type != IB_NODE_SWITCH)
+ if (node_type != RDMA_NODE_IB_SWITCH)
return 0;
/* smp->return_path set when received */
@@ -77,7 +77,7 @@ int smi_handle_dr_smp_send(struct ib_smp *smp,
if (hop_ptr == hop_cnt) {
/* smp->return_path set when received */
smp->hop_ptr++;
- return (node_type == IB_NODE_SWITCH ||
+ return (node_type == RDMA_NODE_IB_SWITCH ||
smp->dr_dlid == IB_LID_PERMISSIVE);
}
@@ -95,7 +95,7 @@ int smi_handle_dr_smp_send(struct ib_smp *smp,
/* C14-13:2 */
if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
- if (node_type != IB_NODE_SWITCH)
+ if (node_type != RDMA_NODE_IB_SWITCH)
return 0;
smp->hop_ptr--;
@@ -107,7 +107,7 @@ int smi_handle_dr_smp_send(struct ib_smp *smp,
if (hop_ptr == 1) {
smp->hop_ptr--;
/* C14-13:3 -- SMPs destined for SM shouldn't be here */
- return (node_type == IB_NODE_SWITCH ||
+ return (node_type == RDMA_NODE_IB_SWITCH ||
smp->dr_slid == IB_LID_PERMISSIVE);
}
@@ -142,7 +142,7 @@ int smi_handle_dr_smp_recv(struct ib_smp *smp,
/* C14-9:2 -- intermediate hop */
if (hop_ptr && hop_ptr < hop_cnt) {
- if (node_type != IB_NODE_SWITCH)
+ if (node_type != RDMA_NODE_IB_SWITCH)
return 0;
smp->return_path[hop_ptr] = port_num;
@@ -156,7 +156,7 @@ int smi_handle_dr_smp_recv(struct ib_smp *smp,
smp->return_path[hop_ptr] = port_num;
/* smp->hop_ptr updated when sending */
- return (node_type == IB_NODE_SWITCH ||
+ return (node_type == RDMA_NODE_IB_SWITCH ||
smp->dr_dlid == IB_LID_PERMISSIVE);
}
@@ -175,7 +175,7 @@ int smi_handle_dr_smp_recv(struct ib_smp *smp,
/* C14-13:2 */
if (2 <= hop_ptr && hop_ptr <= hop_cnt) {
- if (node_type != IB_NODE_SWITCH)
+ if (node_type != RDMA_NODE_IB_SWITCH)
return 0;
/* smp->hop_ptr updated when sending */
@@ -190,7 +190,7 @@ int smi_handle_dr_smp_recv(struct ib_smp *smp,
return 1;
}
/* smp->hop_ptr updated when sending */
- return (node_type == IB_NODE_SWITCH);
+ return (node_type == RDMA_NODE_IB_SWITCH);
}
/* C14-13:4 -- hop_ptr = 0 -> give to SM */
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index 21f9282c1b2..709323c14c5 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -68,7 +68,7 @@ struct port_table_attribute {
int index;
};
-static inline int ibdev_is_alive(const struct ib_device *dev)
+static inline int ibdev_is_alive(const struct ib_device *dev)
{
return dev->reg_state == IB_DEV_REGISTERED;
}
@@ -589,10 +589,11 @@ static ssize_t show_node_type(struct class_device *cdev, char *buf)
return -ENODEV;
switch (dev->node_type) {
- case IB_NODE_CA: return sprintf(buf, "%d: CA\n", dev->node_type);
- case IB_NODE_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type);
- case IB_NODE_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type);
- default: return sprintf(buf, "%d: <unknown>\n", dev->node_type);
+ case RDMA_NODE_IB_CA: return sprintf(buf, "%d: CA\n", dev->node_type);
+ case RDMA_NODE_RNIC: return sprintf(buf, "%d: RNIC\n", dev->node_type);
+ case RDMA_NODE_IB_SWITCH: return sprintf(buf, "%d: switch\n", dev->node_type);
+ case RDMA_NODE_IB_ROUTER: return sprintf(buf, "%d: router\n", dev->node_type);
+ default: return sprintf(buf, "%d: <unknown>\n", dev->node_type);
}
}
@@ -708,7 +709,7 @@ int ib_device_register_sysfs(struct ib_device *device)
if (ret)
goto err_put;
- if (device->node_type == IB_NODE_SWITCH) {
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
ret = add_port(device, 0);
if (ret)
goto err_put;
diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c
index c1c6fda9452..ad4f4d5c292 100644
--- a/drivers/infiniband/core/ucm.c
+++ b/drivers/infiniband/core/ucm.c
@@ -309,9 +309,9 @@ static int ib_ucm_event_process(struct ib_cm_event *evt,
info = evt->param.apr_rcvd.apr_info;
break;
case IB_CM_SIDR_REQ_RECEIVED:
- uvt->resp.u.sidr_req_resp.pkey =
+ uvt->resp.u.sidr_req_resp.pkey =
evt->param.sidr_req_rcvd.pkey;
- uvt->resp.u.sidr_req_resp.port =
+ uvt->resp.u.sidr_req_resp.port =
evt->param.sidr_req_rcvd.port;
uvt->data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE;
break;
@@ -1237,7 +1237,7 @@ static struct class ucm_class = {
static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
{
struct ib_ucm_device *dev;
-
+
dev = container_of(class_dev, struct ib_ucm_device, class_dev);
return sprintf(buf, "%s\n", dev->ib_dev->name);
}
@@ -1247,7 +1247,8 @@ static void ib_ucm_add_one(struct ib_device *device)
{
struct ib_ucm_device *ucm_dev;
- if (!device->alloc_ucontext)
+ if (!device->alloc_ucontext ||
+ rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
return;
ucm_dev = kzalloc(sizeof *ucm_dev, GFP_KERNEL);
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c
index afe70a549c2..807fbd6b841 100644
--- a/drivers/infiniband/core/user_mad.c
+++ b/drivers/infiniband/core/user_mad.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
- * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -112,8 +112,10 @@ struct ib_umad_device {
struct ib_umad_file {
struct ib_umad_port *port;
struct list_head recv_list;
+ struct list_head send_list;
struct list_head port_list;
spinlock_t recv_lock;
+ spinlock_t send_lock;
wait_queue_head_t recv_wait;
struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS];
int agents_dead;
@@ -177,12 +179,21 @@ static int queue_packet(struct ib_umad_file *file,
return ret;
}
+static void dequeue_send(struct ib_umad_file *file,
+ struct ib_umad_packet *packet)
+ {
+ spin_lock_irq(&file->send_lock);
+ list_del(&packet->list);
+ spin_unlock_irq(&file->send_lock);
+ }
+
static void send_handler(struct ib_mad_agent *agent,
struct ib_mad_send_wc *send_wc)
{
struct ib_umad_file *file = agent->context;
struct ib_umad_packet *packet = send_wc->send_buf->context[0];
+ dequeue_send(file, packet);
ib_destroy_ah(packet->msg->ah);
ib_free_send_mad(packet->msg);
@@ -370,6 +381,51 @@ static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf)
return 0;
}
+static int same_destination(struct ib_user_mad_hdr *hdr1,
+ struct ib_user_mad_hdr *hdr2)
+{
+ if (!hdr1->grh_present && !hdr2->grh_present)
+ return (hdr1->lid == hdr2->lid);
+
+ if (hdr1->grh_present && hdr2->grh_present)
+ return !memcmp(hdr1->gid, hdr2->gid, 16);
+
+ return 0;
+}
+
+static int is_duplicate(struct ib_umad_file *file,
+ struct ib_umad_packet *packet)
+{
+ struct ib_umad_packet *sent_packet;
+ struct ib_mad_hdr *sent_hdr, *hdr;
+
+ hdr = (struct ib_mad_hdr *) packet->mad.data;
+ list_for_each_entry(sent_packet, &file->send_list, list) {
+ sent_hdr = (struct ib_mad_hdr *) sent_packet->mad.data;
+
+ if ((hdr->tid != sent_hdr->tid) ||
+ (hdr->mgmt_class != sent_hdr->mgmt_class))
+ continue;
+
+ /*
+ * No need to be overly clever here. If two new operations have
+ * the same TID, reject the second as a duplicate. This is more
+ * restrictive than required by the spec.
+ */
+ if (!ib_response_mad((struct ib_mad *) hdr)) {
+ if (!ib_response_mad((struct ib_mad *) sent_hdr))
+ return 1;
+ continue;
+ } else if (!ib_response_mad((struct ib_mad *) sent_hdr))
+ continue;
+
+ if (same_destination(&packet->mad.hdr, &sent_packet->mad.hdr))
+ return 1;
+ }
+
+ return 0;
+}
+
static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
size_t count, loff_t *pos)
{
@@ -379,7 +435,6 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
struct ib_ah_attr ah_attr;
struct ib_ah *ah;
struct ib_rmpp_mad *rmpp_mad;
- u8 method;
__be64 *tid;
int ret, data_len, hdr_len, copy_offset, rmpp_active;
@@ -473,28 +528,36 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf,
}
/*
- * If userspace is generating a request that will generate a
- * response, we need to make sure the high-order part of the
- * transaction ID matches the agent being used to send the
- * MAD.
+ * Set the high-order part of the transaction ID to make MADs from
+ * different agents unique, and allow routing responses back to the
+ * original requestor.
*/
- method = ((struct ib_mad_hdr *) packet->msg->mad)->method;
-
- if (!(method & IB_MGMT_METHOD_RESP) &&
- method != IB_MGMT_METHOD_TRAP_REPRESS &&
- method != IB_MGMT_METHOD_SEND) {
+ if (!ib_response_mad(packet->msg->mad)) {
tid = &((struct ib_mad_hdr *) packet->msg->mad)->tid;
*tid = cpu_to_be64(((u64) agent->hi_tid) << 32 |
(be64_to_cpup(tid) & 0xffffffff));
+ rmpp_mad->mad_hdr.tid = *tid;
+ }
+
+ spin_lock_irq(&file->send_lock);
+ ret = is_duplicate(file, packet);
+ if (!ret)
+ list_add_tail(&packet->list, &file->send_list);
+ spin_unlock_irq(&file->send_lock);
+ if (ret) {
+ ret = -EINVAL;
+ goto err_msg;
}
ret = ib_post_send_mad(packet->msg, NULL);
if (ret)
- goto err_msg;
+ goto err_send;
up_read(&file->port->mutex);
return count;
+err_send:
+ dequeue_send(file, packet);
err_msg:
ib_free_send_mad(packet->msg);
err_ah:
@@ -657,7 +720,9 @@ static int ib_umad_open(struct inode *inode, struct file *filp)
}
spin_lock_init(&file->recv_lock);
+ spin_lock_init(&file->send_lock);
INIT_LIST_HEAD(&file->recv_list);
+ INIT_LIST_HEAD(&file->send_list);
init_waitqueue_head(&file->recv_wait);
file->port = port;
@@ -967,7 +1032,10 @@ static void ib_umad_add_one(struct ib_device *device)
struct ib_umad_device *umad_dev;
int s, e, i;
- if (device->node_type == IB_NODE_SWITCH)
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
+ if (device->node_type == RDMA_NODE_IB_SWITCH)
s = e = 0;
else {
s = 1;
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
index bb9bee56a82..102a59c033f 100644
--- a/drivers/infiniband/core/uverbs.h
+++ b/drivers/infiniband/core/uverbs.h
@@ -42,6 +42,7 @@
#include <linux/kref.h>
#include <linux/idr.h>
#include <linux/mutex.h>
+#include <linux/completion.h>
#include <rdma/ib_verbs.h>
#include <rdma/ib_user_verbs.h>
@@ -69,6 +70,7 @@
struct ib_uverbs_device {
struct kref ref;
+ struct completion comp;
int devnum;
struct cdev *dev;
struct class_device *class_dev;
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 76bf61e9b55..b72c7f69ca9 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -42,6 +42,13 @@
#include "uverbs.h"
+static struct lock_class_key pd_lock_key;
+static struct lock_class_key mr_lock_key;
+static struct lock_class_key cq_lock_key;
+static struct lock_class_key qp_lock_key;
+static struct lock_class_key ah_lock_key;
+static struct lock_class_key srq_lock_key;
+
#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
do { \
(udata)->inbuf = (void __user *) (ibuf); \
@@ -76,12 +83,13 @@
*/
static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
- struct ib_ucontext *context)
+ struct ib_ucontext *context, struct lock_class_key *key)
{
uobj->user_handle = user_handle;
uobj->context = context;
kref_init(&uobj->ref);
init_rwsem(&uobj->mutex);
+ lockdep_set_class(&uobj->mutex, key);
uobj->live = 0;
}
@@ -147,7 +155,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
}
static struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
- struct ib_ucontext *context)
+ struct ib_ucontext *context, int nested)
{
struct ib_uobject *uobj;
@@ -155,7 +163,10 @@ static struct ib_uobject *idr_read_uobj(struct idr *idr, int id,
if (!uobj)
return NULL;
- down_read(&uobj->mutex);
+ if (nested)
+ down_read_nested(&uobj->mutex, SINGLE_DEPTH_NESTING);
+ else
+ down_read(&uobj->mutex);
if (!uobj->live) {
put_uobj_read(uobj);
return NULL;
@@ -182,17 +193,18 @@ static struct ib_uobject *idr_write_uobj(struct idr *idr, int id,
return uobj;
}
-static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context)
+static void *idr_read_obj(struct idr *idr, int id, struct ib_ucontext *context,
+ int nested)
{
struct ib_uobject *uobj;
- uobj = idr_read_uobj(idr, id, context);
+ uobj = idr_read_uobj(idr, id, context, nested);
return uobj ? uobj->object : NULL;
}
static struct ib_pd *idr_read_pd(int pd_handle, struct ib_ucontext *context)
{
- return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context);
+ return idr_read_obj(&ib_uverbs_pd_idr, pd_handle, context, 0);
}
static void put_pd_read(struct ib_pd *pd)
@@ -200,9 +212,9 @@ static void put_pd_read(struct ib_pd *pd)
put_uobj_read(pd->uobject);
}
-static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context)
+static struct ib_cq *idr_read_cq(int cq_handle, struct ib_ucontext *context, int nested)
{
- return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context);
+ return idr_read_obj(&ib_uverbs_cq_idr, cq_handle, context, nested);
}
static void put_cq_read(struct ib_cq *cq)
@@ -212,7 +224,7 @@ static void put_cq_read(struct ib_cq *cq)
static struct ib_ah *idr_read_ah(int ah_handle, struct ib_ucontext *context)
{
- return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context);
+ return idr_read_obj(&ib_uverbs_ah_idr, ah_handle, context, 0);
}
static void put_ah_read(struct ib_ah *ah)
@@ -222,7 +234,7 @@ static void put_ah_read(struct ib_ah *ah)
static struct ib_qp *idr_read_qp(int qp_handle, struct ib_ucontext *context)
{
- return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context);
+ return idr_read_obj(&ib_uverbs_qp_idr, qp_handle, context, 0);
}
static void put_qp_read(struct ib_qp *qp)
@@ -232,7 +244,7 @@ static void put_qp_read(struct ib_qp *qp)
static struct ib_srq *idr_read_srq(int srq_handle, struct ib_ucontext *context)
{
- return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context);
+ return idr_read_obj(&ib_uverbs_srq_idr, srq_handle, context, 0);
}
static void put_srq_read(struct ib_srq *srq)
@@ -470,7 +482,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, 0, file->ucontext);
+ init_uobj(uobj, 0, file->ucontext, &pd_lock_key);
down_write(&uobj->mutex);
pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
@@ -591,7 +603,7 @@ ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, 0, file->ucontext);
+ init_uobj(&obj->uobject, 0, file->ucontext, &mr_lock_key);
down_write(&obj->uobject.mutex);
/*
@@ -770,7 +782,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, cmd.user_handle, file->ucontext);
+ init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &cq_lock_key);
down_write(&obj->uobject.mutex);
if (cmd.comp_channel >= 0) {
@@ -829,7 +841,6 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
err_copy:
idr_remove_uobj(&ib_uverbs_cq_idr, &obj->uobject);
-
err_free:
ib_destroy_cq(cq);
@@ -859,7 +870,7 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
(unsigned long) cmd.response + sizeof resp,
in_len - sizeof cmd, out_len - sizeof resp);
- cq = idr_read_cq(cmd.cq_handle, file->ucontext);
+ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
if (!cq)
return -EINVAL;
@@ -867,11 +878,10 @@ ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file,
if (ret)
goto out;
- memset(&resp, 0, sizeof resp);
resp.cqe = cq->cqe;
if (copy_to_user((void __user *) (unsigned long) cmd.response,
- &resp, sizeof resp))
+ &resp, sizeof resp.cqe))
ret = -EFAULT;
out:
@@ -886,7 +896,6 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
{
struct ib_uverbs_poll_cq cmd;
struct ib_uverbs_poll_cq_resp *resp;
- struct ib_uobject *uobj;
struct ib_cq *cq;
struct ib_wc *wc;
int ret = 0;
@@ -907,16 +916,15 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
goto out_wc;
}
- uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
- if (!uobj) {
+ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+ if (!cq) {
ret = -EINVAL;
goto out;
}
- cq = uobj->object;
resp->count = ib_poll_cq(cq, cmd.ne, wc);
- put_uobj_read(uobj);
+ put_cq_read(cq);
for (i = 0; i < resp->count; i++) {
resp->wc[i].wr_id = wc[i].wr_id;
@@ -951,21 +959,19 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file,
int out_len)
{
struct ib_uverbs_req_notify_cq cmd;
- struct ib_uobject *uobj;
struct ib_cq *cq;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
- uobj = idr_read_uobj(&ib_uverbs_cq_idr, cmd.cq_handle, file->ucontext);
- if (!uobj)
+ cq = idr_read_cq(cmd.cq_handle, file->ucontext, 0);
+ if (!cq)
return -EINVAL;
- cq = uobj->object;
ib_req_notify_cq(cq, cmd.solicited_only ?
IB_CQ_SOLICITED : IB_CQ_NEXT_COMP);
- put_uobj_read(uobj);
+ put_cq_read(cq);
return in_len;
}
@@ -1051,13 +1057,14 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext);
+ init_uobj(&obj->uevent.uobject, cmd.user_handle, file->ucontext, &qp_lock_key);
down_write(&obj->uevent.uobject.mutex);
- pd = idr_read_pd(cmd.pd_handle, file->ucontext);
- scq = idr_read_cq(cmd.send_cq_handle, file->ucontext);
- rcq = idr_read_cq(cmd.recv_cq_handle, file->ucontext);
srq = cmd.is_srq ? idr_read_srq(cmd.srq_handle, file->ucontext) : NULL;
+ pd = idr_read_pd(cmd.pd_handle, file->ucontext);
+ scq = idr_read_cq(cmd.send_cq_handle, file->ucontext, 0);
+ rcq = cmd.recv_cq_handle == cmd.send_cq_handle ?
+ scq : idr_read_cq(cmd.recv_cq_handle, file->ucontext, 1);
if (!pd || !scq || !rcq || (cmd.is_srq && !srq)) {
ret = -EINVAL;
@@ -1125,7 +1132,8 @@ ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
put_pd_read(pd);
put_cq_read(scq);
- put_cq_read(rcq);
+ if (rcq != scq)
+ put_cq_read(rcq);
if (srq)
put_srq_read(srq);
@@ -1150,7 +1158,7 @@ err_put:
put_pd_read(pd);
if (scq)
put_cq_read(scq);
- if (rcq)
+ if (rcq && rcq != scq)
put_cq_read(rcq);
if (srq)
put_srq_read(srq);
@@ -1264,6 +1272,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
int out_len)
{
struct ib_uverbs_modify_qp cmd;
+ struct ib_udata udata;
struct ib_qp *qp;
struct ib_qp_attr *attr;
int ret;
@@ -1271,6 +1280,9 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
+ INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
+ out_len);
+
attr = kmalloc(sizeof *attr, GFP_KERNEL);
if (!attr)
return -ENOMEM;
@@ -1327,7 +1339,7 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
attr->alt_ah_attr.port_num = cmd.alt_dest.port_num;
- ret = ib_modify_qp(qp, attr, cmd.attr_mask);
+ ret = qp->device->modify_qp(qp, attr, cmd.attr_mask, &udata);
put_qp_read(qp);
@@ -1530,7 +1542,6 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
out_put:
put_qp_read(qp);
-out:
while (wr) {
if (is_ud && wr->wr.ud.ah)
put_ah_read(wr->wr.ud.ah);
@@ -1539,6 +1550,7 @@ out:
wr = next;
}
+out:
kfree(user_wr);
return ret ? ret : in_len;
@@ -1664,7 +1676,6 @@ ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file,
break;
}
-
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
ret = -EFAULT;
@@ -1714,7 +1725,6 @@ ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file,
break;
}
-
if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp))
ret = -EFAULT;
@@ -1751,7 +1761,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
if (!uobj)
return -ENOMEM;
- init_uobj(uobj, cmd.user_handle, file->ucontext);
+ init_uobj(uobj, cmd.user_handle, file->ucontext, &ah_lock_key);
down_write(&uobj->mutex);
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
@@ -1775,7 +1785,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file,
ah = ib_create_ah(pd, &attr);
if (IS_ERR(ah)) {
ret = PTR_ERR(ah);
- goto err;
+ goto err_put;
}
ah->uobject = uobj;
@@ -1811,6 +1821,9 @@ err_copy:
err_destroy:
ib_destroy_ah(ah);
+err_put:
+ put_pd_read(pd);
+
err:
put_uobj_write(uobj);
return ret;
@@ -1963,7 +1976,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
if (!obj)
return -ENOMEM;
- init_uobj(&obj->uobject, 0, file->ucontext);
+ init_uobj(&obj->uobject, cmd.user_handle, file->ucontext, &srq_lock_key);
down_write(&obj->uobject.mutex);
pd = idr_read_pd(cmd.pd_handle, file->ucontext);
@@ -1984,7 +1997,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file,
srq = pd->device->create_srq(pd, &attr, &udata);
if (IS_ERR(srq)) {
ret = PTR_ERR(srq);
- goto err;
+ goto err_put;
}
srq->device = pd->device;
@@ -2029,6 +2042,9 @@ err_copy:
err_destroy:
ib_destroy_srq(srq);
+err_put:
+ put_pd_read(pd);
+
err:
put_uobj_write(&obj->uobject);
return ret;
@@ -2039,6 +2055,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
int out_len)
{
struct ib_uverbs_modify_srq cmd;
+ struct ib_udata udata;
struct ib_srq *srq;
struct ib_srq_attr attr;
int ret;
@@ -2046,6 +2063,9 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
+ INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd,
+ out_len);
+
srq = idr_read_srq(cmd.srq_handle, file->ucontext);
if (!srq)
return -EINVAL;
@@ -2053,7 +2073,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file,
attr.max_wr = cmd.max_wr;
attr.srq_limit = cmd.srq_limit;
- ret = ib_modify_srq(srq, &attr, cmd.attr_mask);
+ ret = srq->device->modify_srq(srq, &attr, cmd.attr_mask, &udata);
put_srq_read(srq);
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e57d3c50f75..4e16314e8e6 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -122,7 +122,7 @@ static void ib_uverbs_release_dev(struct kref *ref)
struct ib_uverbs_device *dev =
container_of(ref, struct ib_uverbs_device, ref);
- kfree(dev);
+ complete(&dev->comp);
}
void ib_uverbs_release_ucq(struct ib_uverbs_file *file,
@@ -188,7 +188,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
idr_remove_uobj(&ib_uverbs_ah_idr, uobj);
ib_destroy_ah(ah);
- list_del(&uobj->list);
kfree(uobj);
}
@@ -200,7 +199,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
idr_remove_uobj(&ib_uverbs_qp_idr, uobj);
ib_uverbs_detach_umcast(qp, uqp);
ib_destroy_qp(qp);
- list_del(&uobj->list);
ib_uverbs_release_uevent(file, &uqp->uevent);
kfree(uqp);
}
@@ -213,7 +211,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
idr_remove_uobj(&ib_uverbs_cq_idr, uobj);
ib_destroy_cq(cq);
- list_del(&uobj->list);
ib_uverbs_release_ucq(file, ev_file, ucq);
kfree(ucq);
}
@@ -225,7 +222,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
idr_remove_uobj(&ib_uverbs_srq_idr, uobj);
ib_destroy_srq(srq);
- list_del(&uobj->list);
ib_uverbs_release_uevent(file, uevent);
kfree(uevent);
}
@@ -243,7 +239,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
memobj = container_of(uobj, struct ib_umem_object, uobject);
ib_umem_release_on_close(mrdev, &memobj->umem);
- list_del(&uobj->list);
kfree(memobj);
}
@@ -252,7 +247,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file,
idr_remove_uobj(&ib_uverbs_pd_idr, uobj);
ib_dealloc_pd(pd);
- list_del(&uobj->list);
kfree(uobj);
}
@@ -746,6 +740,7 @@ static void ib_uverbs_add_one(struct ib_device *device)
return;
kref_init(&uverbs_dev->ref);
+ init_completion(&uverbs_dev->comp);
spin_lock(&map_lock);
uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
@@ -799,6 +794,8 @@ err_cdev:
err:
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+ wait_for_completion(&uverbs_dev->comp);
+ kfree(uverbs_dev);
return;
}
@@ -818,7 +815,10 @@ static void ib_uverbs_remove_one(struct ib_device *device)
spin_unlock(&map_lock);
clear_bit(uverbs_dev->devnum, dev_map);
+
kref_put(&uverbs_dev->ref, ib_uverbs_release_dev);
+ wait_for_completion(&uverbs_dev->comp);
+ kfree(uverbs_dev);
}
static int uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 468999c3880..8b5dd3649bb 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -79,6 +79,23 @@ enum ib_rate mult_to_ib_rate(int mult)
}
EXPORT_SYMBOL(mult_to_ib_rate);
+enum rdma_transport_type
+rdma_node_get_transport(enum rdma_node_type node_type)
+{
+ switch (node_type) {
+ case RDMA_NODE_IB_CA:
+ case RDMA_NODE_IB_SWITCH:
+ case RDMA_NODE_IB_ROUTER:
+ return RDMA_TRANSPORT_IB;
+ case RDMA_NODE_RNIC:
+ return RDMA_TRANSPORT_IWARP;
+ default:
+ BUG();
+ return 0;
+ }
+}
+EXPORT_SYMBOL(rdma_node_get_transport);
+
/* Protection domains */
struct ib_pd *ib_alloc_pd(struct ib_device *device)
@@ -231,7 +248,7 @@ int ib_modify_srq(struct ib_srq *srq,
struct ib_srq_attr *srq_attr,
enum ib_srq_attr_mask srq_attr_mask)
{
- return srq->device->modify_srq(srq, srq_attr, srq_attr_mask);
+ return srq->device->modify_srq(srq, srq_attr, srq_attr_mask, NULL);
}
EXPORT_SYMBOL(ib_modify_srq);
@@ -547,7 +564,7 @@ int ib_modify_qp(struct ib_qp *qp,
struct ib_qp_attr *qp_attr,
int qp_attr_mask)
{
- return qp->device->modify_qp(qp, qp_attr, qp_attr_mask);
+ return qp->device->modify_qp(qp, qp_attr, qp_attr_mask, NULL);
}
EXPORT_SYMBOL(ib_modify_qp);
diff --git a/drivers/infiniband/hw/amso1100/Kbuild b/drivers/infiniband/hw/amso1100/Kbuild
new file mode 100644
index 00000000000..06964c4af84
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/Kbuild
@@ -0,0 +1,8 @@
+ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o
+
+iw_c2-y := c2.o c2_provider.o c2_rnic.o c2_alloc.o c2_mq.o c2_ae.o c2_vq.o \
+ c2_intr.o c2_cq.o c2_qp.o c2_cm.o c2_mm.o c2_pd.o
diff --git a/drivers/infiniband/hw/amso1100/Kconfig b/drivers/infiniband/hw/amso1100/Kconfig
new file mode 100644
index 00000000000..809cb14ac6d
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/Kconfig
@@ -0,0 +1,15 @@
+config INFINIBAND_AMSO1100
+ tristate "Ammasso 1100 HCA support"
+ depends on PCI && INET && INFINIBAND
+ ---help---
+ This is a low-level driver for the Ammasso 1100 host
+ channel adapter (HCA).
+
+config INFINIBAND_AMSO1100_DEBUG
+ bool "Verbose debugging output"
+ depends on INFINIBAND_AMSO1100
+ default n
+ ---help---
+ This option causes the amso1100 driver to produce a bunch of
+ debug messages. Select this if you are developing the driver
+ or trying to diagnose a problem.
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
new file mode 100644
index 00000000000..9e9120f3601
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -0,0 +1,1255 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include <rdma/ib_smi.h>
+#include "c2.h"
+#include "c2_provider.h"
+
+MODULE_AUTHOR("Tom Tucker <tom@opengridcomputing.com>");
+MODULE_DESCRIPTION("Ammasso AMSO1100 Low-level iWARP Driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+
+static int debug = -1; /* defaults above */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static int c2_up(struct net_device *netdev);
+static int c2_down(struct net_device *netdev);
+static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+static void c2_tx_interrupt(struct net_device *netdev);
+static void c2_rx_interrupt(struct net_device *netdev);
+static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void c2_tx_timeout(struct net_device *netdev);
+static int c2_change_mtu(struct net_device *netdev, int new_mtu);
+static void c2_reset(struct c2_port *c2_port);
+static struct net_device_stats *c2_get_stats(struct net_device *netdev);
+
+static struct pci_device_id c2_pci_table[] = {
+ { PCI_DEVICE(0x18b8, 0xb001) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, c2_pci_table);
+
+static void c2_print_macaddr(struct net_device *netdev)
+{
+ pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, "
+ "IRQ %u\n", netdev->name,
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5],
+ netdev->irq);
+}
+
+static void c2_set_rxbufsize(struct c2_port *c2_port)
+{
+ struct net_device *netdev = c2_port->netdev;
+
+ if (netdev->mtu > RX_BUF_SIZE)
+ c2_port->rx_buf_size =
+ netdev->mtu + ETH_HLEN + sizeof(struct c2_rxp_hdr) +
+ NET_IP_ALIGN;
+ else
+ c2_port->rx_buf_size = sizeof(struct c2_rxp_hdr) + RX_BUF_SIZE;
+}
+
+/*
+ * Allocate TX ring elements and chain them together.
+ * One-to-one association of adapter descriptors with ring elements.
+ */
+static int c2_tx_ring_alloc(struct c2_ring *tx_ring, void *vaddr,
+ dma_addr_t base, void __iomem * mmio_txp_ring)
+{
+ struct c2_tx_desc *tx_desc;
+ struct c2_txp_desc __iomem *txp_desc;
+ struct c2_element *elem;
+ int i;
+
+ tx_ring->start = kmalloc(sizeof(*elem) * tx_ring->count, GFP_KERNEL);
+ if (!tx_ring->start)
+ return -ENOMEM;
+
+ elem = tx_ring->start;
+ tx_desc = vaddr;
+ txp_desc = mmio_txp_ring;
+ for (i = 0; i < tx_ring->count; i++, elem++, tx_desc++, txp_desc++) {
+ tx_desc->len = 0;
+ tx_desc->status = 0;
+
+ /* Set TXP_HTXD_UNINIT */
+ __raw_writeq(cpu_to_be64(0x1122334455667788ULL),
+ (void __iomem *) txp_desc + C2_TXP_ADDR);
+ __raw_writew(0, (void __iomem *) txp_desc + C2_TXP_LEN);
+ __raw_writew(cpu_to_be16(TXP_HTXD_UNINIT),
+ (void __iomem *) txp_desc + C2_TXP_FLAGS);
+
+ elem->skb = NULL;
+ elem->ht_desc = tx_desc;
+ elem->hw_desc = txp_desc;
+
+ if (i == tx_ring->count - 1) {
+ elem->next = tx_ring->start;
+ tx_desc->next_offset = base;
+ } else {
+ elem->next = elem + 1;
+ tx_desc->next_offset =
+ base + (i + 1) * sizeof(*tx_desc);
+ }
+ }
+
+ tx_ring->to_use = tx_ring->to_clean = tx_ring->start;
+
+ return 0;
+}
+
+/*
+ * Allocate RX ring elements and chain them together.
+ * One-to-one association of adapter descriptors with ring elements.
+ */
+static int c2_rx_ring_alloc(struct c2_ring *rx_ring, void *vaddr,
+ dma_addr_t base, void __iomem * mmio_rxp_ring)
+{
+ struct c2_rx_desc *rx_desc;
+ struct c2_rxp_desc __iomem *rxp_desc;
+ struct c2_element *elem;
+ int i;
+
+ rx_ring->start = kmalloc(sizeof(*elem) * rx_ring->count, GFP_KERNEL);
+ if (!rx_ring->start)
+ return -ENOMEM;
+
+ elem = rx_ring->start;
+ rx_desc = vaddr;
+ rxp_desc = mmio_rxp_ring;
+ for (i = 0; i < rx_ring->count; i++, elem++, rx_desc++, rxp_desc++) {
+ rx_desc->len = 0;
+ rx_desc->status = 0;
+
+ /* Set RXP_HRXD_UNINIT */
+ __raw_writew(cpu_to_be16(RXP_HRXD_OK),
+ (void __iomem *) rxp_desc + C2_RXP_STATUS);
+ __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_COUNT);
+ __raw_writew(0, (void __iomem *) rxp_desc + C2_RXP_LEN);
+ __raw_writeq(cpu_to_be64(0x99aabbccddeeffULL),
+ (void __iomem *) rxp_desc + C2_RXP_ADDR);
+ __raw_writew(cpu_to_be16(RXP_HRXD_UNINIT),
+ (void __iomem *) rxp_desc + C2_RXP_FLAGS);
+
+ elem->skb = NULL;
+ elem->ht_desc = rx_desc;
+ elem->hw_desc = rxp_desc;
+
+ if (i == rx_ring->count - 1) {
+ elem->next = rx_ring->start;
+ rx_desc->next_offset = base;
+ } else {
+ elem->next = elem + 1;
+ rx_desc->next_offset =
+ base + (i + 1) * sizeof(*rx_desc);
+ }
+ }
+
+ rx_ring->to_use = rx_ring->to_clean = rx_ring->start;
+
+ return 0;
+}
+
+/* Setup buffer for receiving */
+static inline int c2_rx_alloc(struct c2_port *c2_port, struct c2_element *elem)
+{
+ struct c2_dev *c2dev = c2_port->c2dev;
+ struct c2_rx_desc *rx_desc = elem->ht_desc;
+ struct sk_buff *skb;
+ dma_addr_t mapaddr;
+ u32 maplen;
+ struct c2_rxp_hdr *rxp_hdr;
+
+ skb = dev_alloc_skb(c2_port->rx_buf_size);
+ if (unlikely(!skb)) {
+ pr_debug("%s: out of memory for receive\n",
+ c2_port->netdev->name);
+ return -ENOMEM;
+ }
+
+ /* Zero out the rxp hdr in the sk_buff */
+ memset(skb->data, 0, sizeof(*rxp_hdr));
+
+ skb->dev = c2_port->netdev;
+
+ maplen = c2_port->rx_buf_size;
+ mapaddr =
+ pci_map_single(c2dev->pcidev, skb->data, maplen,
+ PCI_DMA_FROMDEVICE);
+
+ /* Set the sk_buff RXP_header to RXP_HRXD_READY */
+ rxp_hdr = (struct c2_rxp_hdr *) skb->data;
+ rxp_hdr->flags = RXP_HRXD_READY;
+
+ __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
+ __raw_writew(cpu_to_be16((u16) maplen - sizeof(*rxp_hdr)),
+ elem->hw_desc + C2_RXP_LEN);
+ __raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_RXP_ADDR);
+ __raw_writew(cpu_to_be16(RXP_HRXD_READY), elem->hw_desc + C2_RXP_FLAGS);
+
+ elem->skb = skb;
+ elem->mapaddr = mapaddr;
+ elem->maplen = maplen;
+ rx_desc->len = maplen;
+
+ return 0;
+}
+
+/*
+ * Allocate buffers for the Rx ring
+ * For receive: rx_ring.to_clean is next received frame
+ */
+static int c2_rx_fill(struct c2_port *c2_port)
+{
+ struct c2_ring *rx_ring = &c2_port->rx_ring;
+ struct c2_element *elem;
+ int ret = 0;
+
+ elem = rx_ring->start;
+ do {
+ if (c2_rx_alloc(c2_port, elem)) {
+ ret = 1;
+ break;
+ }
+ } while ((elem = elem->next) != rx_ring->start);
+
+ rx_ring->to_clean = rx_ring->start;
+ return ret;
+}
+
+/* Free all buffers in RX ring, assumes receiver stopped */
+static void c2_rx_clean(struct c2_port *c2_port)
+{
+ struct c2_dev *c2dev = c2_port->c2dev;
+ struct c2_ring *rx_ring = &c2_port->rx_ring;
+ struct c2_element *elem;
+ struct c2_rx_desc *rx_desc;
+
+ elem = rx_ring->start;
+ do {
+ rx_desc = elem->ht_desc;
+ rx_desc->len = 0;
+
+ __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
+ __raw_writew(0, elem->hw_desc + C2_RXP_COUNT);
+ __raw_writew(0, elem->hw_desc + C2_RXP_LEN);
+ __raw_writeq(cpu_to_be64(0x99aabbccddeeffULL),
+ elem->hw_desc + C2_RXP_ADDR);
+ __raw_writew(cpu_to_be16(RXP_HRXD_UNINIT),
+ elem->hw_desc + C2_RXP_FLAGS);
+
+ if (elem->skb) {
+ pci_unmap_single(c2dev->pcidev, elem->mapaddr,
+ elem->maplen, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(elem->skb);
+ elem->skb = NULL;
+ }
+ } while ((elem = elem->next) != rx_ring->start);
+}
+
+static inline int c2_tx_free(struct c2_dev *c2dev, struct c2_element *elem)
+{
+ struct c2_tx_desc *tx_desc = elem->ht_desc;
+
+ tx_desc->len = 0;
+
+ pci_unmap_single(c2dev->pcidev, elem->mapaddr, elem->maplen,
+ PCI_DMA_TODEVICE);
+
+ if (elem->skb) {
+ dev_kfree_skb_any(elem->skb);
+ elem->skb = NULL;
+ }
+
+ return 0;
+}
+
+/* Free all buffers in TX ring, assumes transmitter stopped */
+static void c2_tx_clean(struct c2_port *c2_port)
+{
+ struct c2_ring *tx_ring = &c2_port->tx_ring;
+ struct c2_element *elem;
+ struct c2_txp_desc txp_htxd;
+ int retry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c2_port->tx_lock, flags);
+
+ elem = tx_ring->start;
+
+ do {
+ retry = 0;
+ do {
+ txp_htxd.flags =
+ readw(elem->hw_desc + C2_TXP_FLAGS);
+
+ if (txp_htxd.flags == TXP_HTXD_READY) {
+ retry = 1;
+ __raw_writew(0,
+ elem->hw_desc + C2_TXP_LEN);
+ __raw_writeq(0,
+ elem->hw_desc + C2_TXP_ADDR);
+ __raw_writew(cpu_to_be16(TXP_HTXD_DONE),
+ elem->hw_desc + C2_TXP_FLAGS);
+ c2_port->netstats.tx_dropped++;
+ break;
+ } else {
+ __raw_writew(0,
+ elem->hw_desc + C2_TXP_LEN);
+ __raw_writeq(cpu_to_be64(0x1122334455667788ULL),
+ elem->hw_desc + C2_TXP_ADDR);
+ __raw_writew(cpu_to_be16(TXP_HTXD_UNINIT),
+ elem->hw_desc + C2_TXP_FLAGS);
+ }
+
+ c2_tx_free(c2_port->c2dev, elem);
+
+ } while ((elem = elem->next) != tx_ring->start);
+ } while (retry);
+
+ c2_port->tx_avail = c2_port->tx_ring.count - 1;
+ c2_port->c2dev->cur_tx = tx_ring->to_use - tx_ring->start;
+
+ if (c2_port->tx_avail > MAX_SKB_FRAGS + 1)
+ netif_wake_queue(c2_port->netdev);
+
+ spin_unlock_irqrestore(&c2_port->tx_lock, flags);
+}
+
+/*
+ * Process transmit descriptors marked 'DONE' by the firmware,
+ * freeing up their unneeded sk_buffs.
+ */
+static void c2_tx_interrupt(struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+ struct c2_dev *c2dev = c2_port->c2dev;
+ struct c2_ring *tx_ring = &c2_port->tx_ring;
+ struct c2_element *elem;
+ struct c2_txp_desc txp_htxd;
+
+ spin_lock(&c2_port->tx_lock);
+
+ for (elem = tx_ring->to_clean; elem != tx_ring->to_use;
+ elem = elem->next) {
+ txp_htxd.flags =
+ be16_to_cpu(readw(elem->hw_desc + C2_TXP_FLAGS));
+
+ if (txp_htxd.flags != TXP_HTXD_DONE)
+ break;
+
+ if (netif_msg_tx_done(c2_port)) {
+ /* PCI reads are expensive in fast path */
+ txp_htxd.len =
+ be16_to_cpu(readw(elem->hw_desc + C2_TXP_LEN));
+ pr_debug("%s: tx done slot %3Zu status 0x%x len "
+ "%5u bytes\n",
+ netdev->name, elem - tx_ring->start,
+ txp_htxd.flags, txp_htxd.len);
+ }
+
+ c2_tx_free(c2dev, elem);
+ ++(c2_port->tx_avail);
+ }
+
+ tx_ring->to_clean = elem;
+
+ if (netif_queue_stopped(netdev)
+ && c2_port->tx_avail > MAX_SKB_FRAGS + 1)
+ netif_wake_queue(netdev);
+
+ spin_unlock(&c2_port->tx_lock);
+}
+
+static void c2_rx_error(struct c2_port *c2_port, struct c2_element *elem)
+{
+ struct c2_rx_desc *rx_desc = elem->ht_desc;
+ struct c2_rxp_hdr *rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data;
+
+ if (rxp_hdr->status != RXP_HRXD_OK ||
+ rxp_hdr->len > (rx_desc->len - sizeof(*rxp_hdr))) {
+ pr_debug("BAD RXP_HRXD\n");
+ pr_debug(" rx_desc : %p\n", rx_desc);
+ pr_debug(" index : %Zu\n",
+ elem - c2_port->rx_ring.start);
+ pr_debug(" len : %u\n", rx_desc->len);
+ pr_debug(" rxp_hdr : %p [PA %p]\n", rxp_hdr,
+ (void *) __pa((unsigned long) rxp_hdr));
+ pr_debug(" flags : 0x%x\n", rxp_hdr->flags);
+ pr_debug(" status: 0x%x\n", rxp_hdr->status);
+ pr_debug(" len : %u\n", rxp_hdr->len);
+ pr_debug(" rsvd : 0x%x\n", rxp_hdr->rsvd);
+ }
+
+ /* Setup the skb for reuse since we're dropping this pkt */
+ elem->skb->tail = elem->skb->data = elem->skb->head;
+
+ /* Zero out the rxp hdr in the sk_buff */
+ memset(elem->skb->data, 0, sizeof(*rxp_hdr));
+
+ /* Write the descriptor to the adapter's rx ring */
+ __raw_writew(0, elem->hw_desc + C2_RXP_STATUS);
+ __raw_writew(0, elem->hw_desc + C2_RXP_COUNT);
+ __raw_writew(cpu_to_be16((u16) elem->maplen - sizeof(*rxp_hdr)),
+ elem->hw_desc + C2_RXP_LEN);
+ __raw_writeq(cpu_to_be64(elem->mapaddr), elem->hw_desc + C2_RXP_ADDR);
+ __raw_writew(cpu_to_be16(RXP_HRXD_READY), elem->hw_desc + C2_RXP_FLAGS);
+
+ pr_debug("packet dropped\n");
+ c2_port->netstats.rx_dropped++;
+}
+
+static void c2_rx_interrupt(struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+ struct c2_dev *c2dev = c2_port->c2dev;
+ struct c2_ring *rx_ring = &c2_port->rx_ring;
+ struct c2_element *elem;
+ struct c2_rx_desc *rx_desc;
+ struct c2_rxp_hdr *rxp_hdr;
+ struct sk_buff *skb;
+ dma_addr_t mapaddr;
+ u32 maplen, buflen;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c2dev->lock, flags);
+
+ /* Begin where we left off */
+ rx_ring->to_clean = rx_ring->start + c2dev->cur_rx;
+
+ for (elem = rx_ring->to_clean; elem->next != rx_ring->to_clean;
+ elem = elem->next) {
+ rx_desc = elem->ht_desc;
+ mapaddr = elem->mapaddr;
+ maplen = elem->maplen;
+ skb = elem->skb;
+ rxp_hdr = (struct c2_rxp_hdr *) skb->data;
+
+ if (rxp_hdr->flags != RXP_HRXD_DONE)
+ break;
+ buflen = rxp_hdr->len;
+
+ /* Sanity check the RXP header */
+ if (rxp_hdr->status != RXP_HRXD_OK ||
+ buflen > (rx_desc->len - sizeof(*rxp_hdr))) {
+ c2_rx_error(c2_port, elem);
+ continue;
+ }
+
+ /*
+ * Allocate and map a new skb for replenishing the host
+ * RX desc
+ */
+ if (c2_rx_alloc(c2_port, elem)) {
+ c2_rx_error(c2_port, elem);
+ continue;
+ }
+
+ /* Unmap the old skb */
+ pci_unmap_single(c2dev->pcidev, mapaddr, maplen,
+ PCI_DMA_FROMDEVICE);
+
+ prefetch(skb->data);
+
+ /*
+ * Skip past the leading 8 bytes comprising of the
+ * "struct c2_rxp_hdr", prepended by the adapter
+ * to the usual Ethernet header ("struct ethhdr"),
+ * to the start of the raw Ethernet packet.
+ *
+ * Fix up the various fields in the sk_buff before
+ * passing it up to netif_rx(). The transfer size
+ * (in bytes) specified by the adapter len field of
+ * the "struct rxp_hdr_t" does NOT include the
+ * "sizeof(struct c2_rxp_hdr)".
+ */
+ skb->data += sizeof(*rxp_hdr);
+ skb->tail = skb->data + buflen;
+ skb->len = buflen;
+ skb->dev = netdev;
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ netif_rx(skb);
+
+ netdev->last_rx = jiffies;
+ c2_port->netstats.rx_packets++;
+ c2_port->netstats.rx_bytes += buflen;
+ }
+
+ /* Save where we left off */
+ rx_ring->to_clean = elem;
+ c2dev->cur_rx = elem - rx_ring->start;
+ C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
+
+ spin_unlock_irqrestore(&c2dev->lock, flags);
+}
+
+/*
+ * Handle netisr0 TX & RX interrupts.
+ */
+static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned int netisr0, dmaisr;
+ int handled = 0;
+ struct c2_dev *c2dev = (struct c2_dev *) dev_id;
+
+ /* Process CCILNET interrupts */
+ netisr0 = readl(c2dev->regs + C2_NISR0);
+ if (netisr0) {
+
+ /*
+ * There is an issue with the firmware that always
+ * provides the status of RX for both TX & RX
+ * interrupts. So process both queues here.
+ */
+ c2_rx_interrupt(c2dev->netdev);
+ c2_tx_interrupt(c2dev->netdev);
+
+ /* Clear the interrupt */
+ writel(netisr0, c2dev->regs + C2_NISR0);
+ handled++;
+ }
+
+ /* Process RNIC interrupts */
+ dmaisr = readl(c2dev->regs + C2_DISR);
+ if (dmaisr) {
+ writel(dmaisr, c2dev->regs + C2_DISR);
+ c2_rnic_interrupt(c2dev);
+ handled++;
+ }
+
+ if (handled) {
+ return IRQ_HANDLED;
+ } else {
+ return IRQ_NONE;
+ }
+}
+
+static int c2_up(struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+ struct c2_dev *c2dev = c2_port->c2dev;
+ struct c2_element *elem;
+ struct c2_rxp_hdr *rxp_hdr;
+ struct in_device *in_dev;
+ size_t rx_size, tx_size;
+ int ret, i;
+ unsigned int netimr0;
+
+ if (netif_msg_ifup(c2_port))
+ pr_debug("%s: enabling interface\n", netdev->name);
+
+ /* Set the Rx buffer size based on MTU */
+ c2_set_rxbufsize(c2_port);
+
+ /* Allocate DMA'able memory for Tx/Rx host descriptor rings */
+ rx_size = c2_port->rx_ring.count * sizeof(struct c2_rx_desc);
+ tx_size = c2_port->tx_ring.count * sizeof(struct c2_tx_desc);
+
+ c2_port->mem_size = tx_size + rx_size;
+ c2_port->mem = pci_alloc_consistent(c2dev->pcidev, c2_port->mem_size,
+ &c2_port->dma);
+ if (c2_port->mem == NULL) {
+ pr_debug("Unable to allocate memory for "
+ "host descriptor rings\n");
+ return -ENOMEM;
+ }
+
+ memset(c2_port->mem, 0, c2_port->mem_size);
+
+ /* Create the Rx host descriptor ring */
+ if ((ret =
+ c2_rx_ring_alloc(&c2_port->rx_ring, c2_port->mem, c2_port->dma,
+ c2dev->mmio_rxp_ring))) {
+ pr_debug("Unable to create RX ring\n");
+ goto bail0;
+ }
+
+ /* Allocate Rx buffers for the host descriptor ring */
+ if (c2_rx_fill(c2_port)) {
+ pr_debug("Unable to fill RX ring\n");
+ goto bail1;
+ }
+
+ /* Create the Tx host descriptor ring */
+ if ((ret = c2_tx_ring_alloc(&c2_port->tx_ring, c2_port->mem + rx_size,
+ c2_port->dma + rx_size,
+ c2dev->mmio_txp_ring))) {
+ pr_debug("Unable to create TX ring\n");
+ goto bail1;
+ }
+
+ /* Set the TX pointer to where we left off */
+ c2_port->tx_avail = c2_port->tx_ring.count - 1;
+ c2_port->tx_ring.to_use = c2_port->tx_ring.to_clean =
+ c2_port->tx_ring.start + c2dev->cur_tx;
+
+ /* missing: Initialize MAC */
+
+ BUG_ON(c2_port->tx_ring.to_use != c2_port->tx_ring.to_clean);
+
+ /* Reset the adapter, ensures the driver is in sync with the RXP */
+ c2_reset(c2_port);
+
+ /* Reset the READY bit in the sk_buff RXP headers & adapter HRXDQ */
+ for (i = 0, elem = c2_port->rx_ring.start; i < c2_port->rx_ring.count;
+ i++, elem++) {
+ rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data;
+ rxp_hdr->flags = 0;
+ __raw_writew(cpu_to_be16(RXP_HRXD_READY),
+ elem->hw_desc + C2_RXP_FLAGS);
+ }
+
+ /* Enable network packets */
+ netif_start_queue(netdev);
+
+ /* Enable IRQ */
+ writel(0, c2dev->regs + C2_IDIS);
+ netimr0 = readl(c2dev->regs + C2_NIMR0);
+ netimr0 &= ~(C2_PCI_HTX_INT | C2_PCI_HRX_INT);
+ writel(netimr0, c2dev->regs + C2_NIMR0);
+
+ /* Tell the stack to ignore arp requests for ipaddrs bound to
+ * other interfaces. This is needed to prevent the host stack
+ * from responding to arp requests to the ipaddr bound on the
+ * rdma interface.
+ */
+ in_dev = in_dev_get(netdev);
+ in_dev->cnf.arp_ignore = 1;
+ in_dev_put(in_dev);
+
+ return 0;
+
+ bail1:
+ c2_rx_clean(c2_port);
+ kfree(c2_port->rx_ring.start);
+
+ bail0:
+ pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem,
+ c2_port->dma);
+
+ return ret;
+}
+
+static int c2_down(struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+ struct c2_dev *c2dev = c2_port->c2dev;
+
+ if (netif_msg_ifdown(c2_port))
+ pr_debug("%s: disabling interface\n",
+ netdev->name);
+
+ /* Wait for all the queued packets to get sent */
+ c2_tx_interrupt(netdev);
+
+ /* Disable network packets */
+ netif_stop_queue(netdev);
+
+ /* Disable IRQs by clearing the interrupt mask */
+ writel(1, c2dev->regs + C2_IDIS);
+ writel(0, c2dev->regs + C2_NIMR0);
+
+ /* missing: Stop transmitter */
+
+ /* missing: Stop receiver */
+
+ /* Reset the adapter, ensures the driver is in sync with the RXP */
+ c2_reset(c2_port);
+
+ /* missing: Turn off LEDs here */
+
+ /* Free all buffers in the host descriptor rings */
+ c2_tx_clean(c2_port);
+ c2_rx_clean(c2_port);
+
+ /* Free the host descriptor rings */
+ kfree(c2_port->rx_ring.start);
+ kfree(c2_port->tx_ring.start);
+ pci_free_consistent(c2dev->pcidev, c2_port->mem_size, c2_port->mem,
+ c2_port->dma);
+
+ return 0;
+}
+
+static void c2_reset(struct c2_port *c2_port)
+{
+ struct c2_dev *c2dev = c2_port->c2dev;
+ unsigned int cur_rx = c2dev->cur_rx;
+
+ /* Tell the hardware to quiesce */
+ C2_SET_CUR_RX(c2dev, cur_rx | C2_PCI_HRX_QUI);
+
+ /*
+ * The hardware will reset the C2_PCI_HRX_QUI bit once
+ * the RXP is quiesced. Wait 2 seconds for this.
+ */
+ ssleep(2);
+
+ cur_rx = C2_GET_CUR_RX(c2dev);
+
+ if (cur_rx & C2_PCI_HRX_QUI)
+ pr_debug("c2_reset: failed to quiesce the hardware!\n");
+
+ cur_rx &= ~C2_PCI_HRX_QUI;
+
+ c2dev->cur_rx = cur_rx;
+
+ pr_debug("Current RX: %u\n", c2dev->cur_rx);
+}
+
+static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+ struct c2_dev *c2dev = c2_port->c2dev;
+ struct c2_ring *tx_ring = &c2_port->tx_ring;
+ struct c2_element *elem;
+ dma_addr_t mapaddr;
+ u32 maplen;
+ unsigned long flags;
+ unsigned int i;
+
+ spin_lock_irqsave(&c2_port->tx_lock, flags);
+
+ if (unlikely(c2_port->tx_avail < (skb_shinfo(skb)->nr_frags + 1))) {
+ netif_stop_queue(netdev);
+ spin_unlock_irqrestore(&c2_port->tx_lock, flags);
+
+ pr_debug("%s: Tx ring full when queue awake!\n",
+ netdev->name);
+ return NETDEV_TX_BUSY;
+ }
+
+ maplen = skb_headlen(skb);
+ mapaddr =
+ pci_map_single(c2dev->pcidev, skb->data, maplen, PCI_DMA_TODEVICE);
+
+ elem = tx_ring->to_use;
+ elem->skb = skb;
+ elem->mapaddr = mapaddr;
+ elem->maplen = maplen;
+
+ /* Tell HW to xmit */
+ __raw_writeq(cpu_to_be64(mapaddr), elem->hw_desc + C2_TXP_ADDR);
+ __raw_writew(cpu_to_be16(maplen), elem->hw_desc + C2_TXP_LEN);
+ __raw_writew(cpu_to_be16(TXP_HTXD_READY), elem->hw_desc + C2_TXP_FLAGS);
+
+ c2_port->netstats.tx_packets++;
+ c2_port->netstats.tx_bytes += maplen;
+
+ /* Loop thru additional data fragments and queue them */
+ if (skb_shinfo(skb)->nr_frags) {
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ maplen = frag->size;
+ mapaddr =
+ pci_map_page(c2dev->pcidev, frag->page,
+ frag->page_offset, maplen,
+ PCI_DMA_TODEVICE);
+
+ elem = elem->next;
+ elem->skb = NULL;
+ elem->mapaddr = mapaddr;
+ elem->maplen = maplen;
+
+ /* Tell HW to xmit */
+ __raw_writeq(cpu_to_be64(mapaddr),
+ elem->hw_desc + C2_TXP_ADDR);
+ __raw_writew(cpu_to_be16(maplen),
+ elem->hw_desc + C2_TXP_LEN);
+ __raw_writew(cpu_to_be16(TXP_HTXD_READY),
+ elem->hw_desc + C2_TXP_FLAGS);
+
+ c2_port->netstats.tx_packets++;
+ c2_port->netstats.tx_bytes += maplen;
+ }
+ }
+
+ tx_ring->to_use = elem->next;
+ c2_port->tx_avail -= (skb_shinfo(skb)->nr_frags + 1);
+
+ if (c2_port->tx_avail <= MAX_SKB_FRAGS + 1) {
+ netif_stop_queue(netdev);
+ if (netif_msg_tx_queued(c2_port))
+ pr_debug("%s: transmit queue full\n",
+ netdev->name);
+ }
+
+ spin_unlock_irqrestore(&c2_port->tx_lock, flags);
+
+ netdev->trans_start = jiffies;
+
+ return NETDEV_TX_OK;
+}
+
+static struct net_device_stats *c2_get_stats(struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+
+ return &c2_port->netstats;
+}
+
+static void c2_tx_timeout(struct net_device *netdev)
+{
+ struct c2_port *c2_port = netdev_priv(netdev);
+
+ if (netif_msg_timer(c2_port))
+ pr_debug("%s: tx timeout\n", netdev->name);
+
+ c2_tx_clean(c2_port);
+}
+
+static int c2_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int ret = 0;
+
+ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+ return -EINVAL;
+
+ netdev->mtu = new_mtu;
+
+ if (netif_running(netdev)) {
+ c2_down(netdev);
+
+ c2_up(netdev);
+ }
+
+ return ret;
+}
+
+/* Initialize network device */
+static struct net_device *c2_devinit(struct c2_dev *c2dev,
+ void __iomem * mmio_addr)
+{
+ struct c2_port *c2_port = NULL;
+ struct net_device *netdev = alloc_etherdev(sizeof(*c2_port));
+
+ if (!netdev) {
+ pr_debug("c2_port etherdev alloc failed");
+ return NULL;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
+
+ netdev->open = c2_up;
+ netdev->stop = c2_down;
+ netdev->hard_start_xmit = c2_xmit_frame;
+ netdev->get_stats = c2_get_stats;
+ netdev->tx_timeout = c2_tx_timeout;
+ netdev->change_mtu = c2_change_mtu;
+ netdev->watchdog_timeo = C2_TX_TIMEOUT;
+ netdev->irq = c2dev->pcidev->irq;
+
+ c2_port = netdev_priv(netdev);
+ c2_port->netdev = netdev;
+ c2_port->c2dev = c2dev;
+ c2_port->msg_enable = netif_msg_init(debug, default_msg);
+ c2_port->tx_ring.count = C2_NUM_TX_DESC;
+ c2_port->rx_ring.count = C2_NUM_RX_DESC;
+
+ spin_lock_init(&c2_port->tx_lock);
+
+ /* Copy our 48-bit ethernet hardware address */
+ memcpy_fromio(netdev->dev_addr, mmio_addr + C2_REGS_ENADDR, 6);
+
+ /* Validate the MAC address */
+ if (!is_valid_ether_addr(netdev->dev_addr)) {
+ pr_debug("Invalid MAC Address\n");
+ c2_print_macaddr(netdev);
+ free_netdev(netdev);
+ return NULL;
+ }
+
+ c2dev->netdev = netdev;
+
+ return netdev;
+}
+
+static int __devinit c2_probe(struct pci_dev *pcidev,
+ const struct pci_device_id *ent)
+{
+ int ret = 0, i;
+ unsigned long reg0_start, reg0_flags, reg0_len;
+ unsigned long reg2_start, reg2_flags, reg2_len;
+ unsigned long reg4_start, reg4_flags, reg4_len;
+ unsigned kva_map_size;
+ struct net_device *netdev = NULL;
+ struct c2_dev *c2dev = NULL;
+ void __iomem *mmio_regs = NULL;
+
+ printk(KERN_INFO PFX "AMSO1100 Gigabit Ethernet driver v%s loaded\n",
+ DRV_VERSION);
+
+ /* Enable PCI device */
+ ret = pci_enable_device(pcidev);
+ if (ret) {
+ printk(KERN_ERR PFX "%s: Unable to enable PCI device\n",
+ pci_name(pcidev));
+ goto bail0;
+ }
+
+ reg0_start = pci_resource_start(pcidev, BAR_0);
+ reg0_len = pci_resource_len(pcidev, BAR_0);
+ reg0_flags = pci_resource_flags(pcidev, BAR_0);
+
+ reg2_start = pci_resource_start(pcidev, BAR_2);
+ reg2_len = pci_resource_len(pcidev, BAR_2);
+ reg2_flags = pci_resource_flags(pcidev, BAR_2);
+
+ reg4_start = pci_resource_start(pcidev, BAR_4);
+ reg4_len = pci_resource_len(pcidev, BAR_4);
+ reg4_flags = pci_resource_flags(pcidev, BAR_4);
+
+ pr_debug("BAR0 size = 0x%lX bytes\n", reg0_len);
+ pr_debug("BAR2 size = 0x%lX bytes\n", reg2_len);
+ pr_debug("BAR4 size = 0x%lX bytes\n", reg4_len);
+
+ /* Make sure PCI base addr are MMIO */
+ if (!(reg0_flags & IORESOURCE_MEM) ||
+ !(reg2_flags & IORESOURCE_MEM) || !(reg4_flags & IORESOURCE_MEM)) {
+ printk(KERN_ERR PFX "PCI regions not an MMIO resource\n");
+ ret = -ENODEV;
+ goto bail1;
+ }
+
+ /* Check for weird/broken PCI region reporting */
+ if ((reg0_len < C2_REG0_SIZE) ||
+ (reg2_len < C2_REG2_SIZE) || (reg4_len < C2_REG4_SIZE)) {
+ printk(KERN_ERR PFX "Invalid PCI region sizes\n");
+ ret = -ENODEV;
+ goto bail1;
+ }
+
+ /* Reserve PCI I/O and memory resources */
+ ret = pci_request_regions(pcidev, DRV_NAME);
+ if (ret) {
+ printk(KERN_ERR PFX "%s: Unable to request regions\n",
+ pci_name(pcidev));
+ goto bail1;
+ }
+
+ if ((sizeof(dma_addr_t) > 4)) {
+ ret = pci_set_dma_mask(pcidev, DMA_64BIT_MASK);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "64b DMA configuration failed\n");
+ goto bail2;
+ }
+ } else {
+ ret = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
+ if (ret < 0) {
+ printk(KERN_ERR PFX "32b DMA configuration failed\n");
+ goto bail2;
+ }
+ }
+
+ /* Enables bus-mastering on the device */
+ pci_set_master(pcidev);
+
+ /* Remap the adapter PCI registers in BAR4 */
+ mmio_regs = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET,
+ sizeof(struct c2_adapter_pci_regs));
+ if (mmio_regs == 0UL) {
+ printk(KERN_ERR PFX
+ "Unable to remap adapter PCI registers in BAR4\n");
+ ret = -EIO;
+ goto bail2;
+ }
+
+ /* Validate PCI regs magic */
+ for (i = 0; i < sizeof(c2_magic); i++) {
+ if (c2_magic[i] != readb(mmio_regs + C2_REGS_MAGIC + i)) {
+ printk(KERN_ERR PFX "Downlevel Firmware boot loader "
+ "[%d/%Zd: got 0x%x, exp 0x%x]. Use the cc_flash "
+ "utility to update your boot loader\n",
+ i + 1, sizeof(c2_magic),
+ readb(mmio_regs + C2_REGS_MAGIC + i),
+ c2_magic[i]);
+ printk(KERN_ERR PFX "Adapter not claimed\n");
+ iounmap(mmio_regs);
+ ret = -EIO;
+ goto bail2;
+ }
+ }
+
+ /* Validate the adapter version */
+ if (be32_to_cpu(readl(mmio_regs + C2_REGS_VERS)) != C2_VERSION) {
+ printk(KERN_ERR PFX "Version mismatch "
+ "[fw=%u, c2=%u], Adapter not claimed\n",
+ be32_to_cpu(readl(mmio_regs + C2_REGS_VERS)),
+ C2_VERSION);
+ ret = -EINVAL;
+ iounmap(mmio_regs);
+ goto bail2;
+ }
+
+ /* Validate the adapter IVN */
+ if (be32_to_cpu(readl(mmio_regs + C2_REGS_IVN)) != C2_IVN) {
+ printk(KERN_ERR PFX "Downlevel FIrmware level. You should be using "
+ "the OpenIB device support kit. "
+ "[fw=0x%x, c2=0x%x], Adapter not claimed\n",
+ be32_to_cpu(readl(mmio_regs + C2_REGS_IVN)),
+ C2_IVN);
+ ret = -EINVAL;
+ iounmap(mmio_regs);
+ goto bail2;
+ }
+
+ /* Allocate hardware structure */
+ c2dev = (struct c2_dev *) ib_alloc_device(sizeof(*c2dev));
+ if (!c2dev) {
+ printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n",
+ pci_name(pcidev));
+ ret = -ENOMEM;
+ iounmap(mmio_regs);
+ goto bail2;
+ }
+
+ memset(c2dev, 0, sizeof(*c2dev));
+ spin_lock_init(&c2dev->lock);
+ c2dev->pcidev = pcidev;
+ c2dev->cur_tx = 0;
+
+ /* Get the last RX index */
+ c2dev->cur_rx =
+ (be32_to_cpu(readl(mmio_regs + C2_REGS_HRX_CUR)) -
+ 0xffffc000) / sizeof(struct c2_rxp_desc);
+
+ /* Request an interrupt line for the driver */
+ ret = request_irq(pcidev->irq, c2_interrupt, SA_SHIRQ, DRV_NAME, c2dev);
+ if (ret) {
+ printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n",
+ pci_name(pcidev), pcidev->irq);
+ iounmap(mmio_regs);
+ goto bail3;
+ }
+
+ /* Set driver specific data */
+ pci_set_drvdata(pcidev, c2dev);
+
+ /* Initialize network device */
+ if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) {
+ iounmap(mmio_regs);
+ goto bail4;
+ }
+
+ /* Save off the actual size prior to unmapping mmio_regs */
+ kva_map_size = be32_to_cpu(readl(mmio_regs + C2_REGS_PCI_WINSIZE));
+
+ /* Unmap the adapter PCI registers in BAR4 */
+ iounmap(mmio_regs);
+
+ /* Register network device */
+ ret = register_netdev(netdev);
+ if (ret) {
+ printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n",
+ ret);
+ goto bail5;
+ }
+
+ /* Disable network packets */
+ netif_stop_queue(netdev);
+
+ /* Remap the adapter HRXDQ PA space to kernel VA space */
+ c2dev->mmio_rxp_ring = ioremap_nocache(reg4_start + C2_RXP_HRXDQ_OFFSET,
+ C2_RXP_HRXDQ_SIZE);
+ if (c2dev->mmio_rxp_ring == 0UL) {
+ printk(KERN_ERR PFX "Unable to remap MMIO HRXDQ region\n");
+ ret = -EIO;
+ goto bail6;
+ }
+
+ /* Remap the adapter HTXDQ PA space to kernel VA space */
+ c2dev->mmio_txp_ring = ioremap_nocache(reg4_start + C2_TXP_HTXDQ_OFFSET,
+ C2_TXP_HTXDQ_SIZE);
+ if (c2dev->mmio_txp_ring == 0UL) {
+ printk(KERN_ERR PFX "Unable to remap MMIO HTXDQ region\n");
+ ret = -EIO;
+ goto bail7;
+ }
+
+ /* Save off the current RX index in the last 4 bytes of the TXP Ring */
+ C2_SET_CUR_RX(c2dev, c2dev->cur_rx);
+
+ /* Remap the PCI registers in adapter BAR0 to kernel VA space */
+ c2dev->regs = ioremap_nocache(reg0_start, reg0_len);
+ if (c2dev->regs == 0UL) {
+ printk(KERN_ERR PFX "Unable to remap BAR0\n");
+ ret = -EIO;
+ goto bail8;
+ }
+
+ /* Remap the PCI registers in adapter BAR4 to kernel VA space */
+ c2dev->pa = reg4_start + C2_PCI_REGS_OFFSET;
+ c2dev->kva = ioremap_nocache(reg4_start + C2_PCI_REGS_OFFSET,
+ kva_map_size);
+ if (c2dev->kva == 0UL) {
+ printk(KERN_ERR PFX "Unable to remap BAR4\n");
+ ret = -EIO;
+ goto bail9;
+ }
+
+ /* Print out the MAC address */
+ c2_print_macaddr(netdev);
+
+ ret = c2_rnic_init(c2dev);
+ if (ret) {
+ printk(KERN_ERR PFX "c2_rnic_init failed: %d\n", ret);
+ goto bail10;
+ }
+
+ c2_register_device(c2dev);
+
+ return 0;
+
+ bail10:
+ iounmap(c2dev->kva);
+
+ bail9:
+ iounmap(c2dev->regs);
+
+ bail8:
+ iounmap(c2dev->mmio_txp_ring);
+
+ bail7:
+ iounmap(c2dev->mmio_rxp_ring);
+
+ bail6:
+ unregister_netdev(netdev);
+
+ bail5:
+ free_netdev(netdev);
+
+ bail4:
+ free_irq(pcidev->irq, c2dev);
+
+ bail3:
+ ib_dealloc_device(&c2dev->ibdev);
+
+ bail2:
+ pci_release_regions(pcidev);
+
+ bail1:
+ pci_disable_device(pcidev);
+
+ bail0:
+ return ret;
+}
+
+static void __devexit c2_remove(struct pci_dev *pcidev)
+{
+ struct c2_dev *c2dev = pci_get_drvdata(pcidev);
+ struct net_device *netdev = c2dev->netdev;
+
+ /* Unregister with OpenIB */
+ c2_unregister_device(c2dev);
+
+ /* Clean up the RNIC resources */
+ c2_rnic_term(c2dev);
+
+ /* Remove network device from the kernel */
+ unregister_netdev(netdev);
+
+ /* Free network device */
+ free_netdev(netdev);
+
+ /* Free the interrupt line */
+ free_irq(pcidev->irq, c2dev);
+
+ /* missing: Turn LEDs off here */
+
+ /* Unmap adapter PA space */
+ iounmap(c2dev->kva);
+ iounmap(c2dev->regs);
+ iounmap(c2dev->mmio_txp_ring);
+ iounmap(c2dev->mmio_rxp_ring);
+
+ /* Free the hardware structure */
+ ib_dealloc_device(&c2dev->ibdev);
+
+ /* Release reserved PCI I/O and memory resources */
+ pci_release_regions(pcidev);
+
+ /* Disable PCI device */
+ pci_disable_device(pcidev);
+
+ /* Clear driver specific data */
+ pci_set_drvdata(pcidev, NULL);
+}
+
+static struct pci_driver c2_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = c2_pci_table,
+ .probe = c2_probe,
+ .remove = __devexit_p(c2_remove),
+};
+
+static int __init c2_init_module(void)
+{
+ return pci_module_init(&c2_pci_driver);
+}
+
+static void __exit c2_exit_module(void)
+{
+ pci_unregister_driver(&c2_pci_driver);
+}
+
+module_init(c2_init_module);
+module_exit(c2_exit_module);
diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/infiniband/hw/amso1100/c2.h
new file mode 100644
index 00000000000..1b17dcdd050
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2.h
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __C2_H
+#define __C2_H
+
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/idr.h>
+#include <asm/semaphore.h>
+
+#include "c2_provider.h"
+#include "c2_mq.h"
+#include "c2_status.h"
+
+#define DRV_NAME "c2"
+#define DRV_VERSION "1.1"
+#define PFX DRV_NAME ": "
+
+#define BAR_0 0
+#define BAR_2 2
+#define BAR_4 4
+
+#define RX_BUF_SIZE (1536 + 8)
+#define ETH_JUMBO_MTU 9000
+#define C2_MAGIC "CEPHEUS"
+#define C2_VERSION 4
+#define C2_IVN (18 & 0x7fffffff)
+
+#define C2_REG0_SIZE (16 * 1024)
+#define C2_REG2_SIZE (2 * 1024 * 1024)
+#define C2_REG4_SIZE (256 * 1024 * 1024)
+#define C2_NUM_TX_DESC 341
+#define C2_NUM_RX_DESC 256
+#define C2_PCI_REGS_OFFSET (0x10000)
+#define C2_RXP_HRXDQ_OFFSET (((C2_REG4_SIZE)/2))
+#define C2_RXP_HRXDQ_SIZE (4096)
+#define C2_TXP_HTXDQ_OFFSET (((C2_REG4_SIZE)/2) + C2_RXP_HRXDQ_SIZE)
+#define C2_TXP_HTXDQ_SIZE (4096)
+#define C2_TX_TIMEOUT (6*HZ)
+
+/* CEPHEUS */
+static const u8 c2_magic[] = {
+ 0x43, 0x45, 0x50, 0x48, 0x45, 0x55, 0x53
+};
+
+enum adapter_pci_regs {
+ C2_REGS_MAGIC = 0x0000,
+ C2_REGS_VERS = 0x0008,
+ C2_REGS_IVN = 0x000C,
+ C2_REGS_PCI_WINSIZE = 0x0010,
+ C2_REGS_Q0_QSIZE = 0x0014,
+ C2_REGS_Q0_MSGSIZE = 0x0018,
+ C2_REGS_Q0_POOLSTART = 0x001C,
+ C2_REGS_Q0_SHARED = 0x0020,
+ C2_REGS_Q1_QSIZE = 0x0024,
+ C2_REGS_Q1_MSGSIZE = 0x0028,
+ C2_REGS_Q1_SHARED = 0x0030,
+ C2_REGS_Q2_QSIZE = 0x0034,
+ C2_REGS_Q2_MSGSIZE = 0x0038,
+ C2_REGS_Q2_SHARED = 0x0040,
+ C2_REGS_ENADDR = 0x004C,
+ C2_REGS_RDMA_ENADDR = 0x0054,
+ C2_REGS_HRX_CUR = 0x006C,
+};
+
+struct c2_adapter_pci_regs {
+ char reg_magic[8];
+ u32 version;
+ u32 ivn;
+ u32 pci_window_size;
+ u32 q0_q_size;
+ u32 q0_msg_size;
+ u32 q0_pool_start;
+ u32 q0_shared;
+ u32 q1_q_size;
+ u32 q1_msg_size;
+ u32 q1_pool_start;
+ u32 q1_shared;
+ u32 q2_q_size;
+ u32 q2_msg_size;
+ u32 q2_pool_start;
+ u32 q2_shared;
+ u32 log_start;
+ u32 log_size;
+ u8 host_enaddr[8];
+ u8 rdma_enaddr[8];
+ u32 crash_entry;
+ u32 crash_ready[2];
+ u32 fw_txd_cur;
+ u32 fw_hrxd_cur;
+ u32 fw_rxd_cur;
+};
+
+enum pci_regs {
+ C2_HISR = 0x0000,
+ C2_DISR = 0x0004,
+ C2_HIMR = 0x0008,
+ C2_DIMR = 0x000C,
+ C2_NISR0 = 0x0010,
+ C2_NISR1 = 0x0014,
+ C2_NIMR0 = 0x0018,
+ C2_NIMR1 = 0x001C,
+ C2_IDIS = 0x0020,
+};
+
+enum {
+ C2_PCI_HRX_INT = 1 << 8,
+ C2_PCI_HTX_INT = 1 << 17,
+ C2_PCI_HRX_QUI = 1 << 31,
+};
+
+/*
+ * Cepheus registers in BAR0.
+ */
+struct c2_pci_regs {
+ u32 hostisr;
+ u32 dmaisr;
+ u32 hostimr;
+ u32 dmaimr;
+ u32 netisr0;
+ u32 netisr1;
+ u32 netimr0;
+ u32 netimr1;
+ u32 int_disable;
+};
+
+/* TXP flags */
+enum c2_txp_flags {
+ TXP_HTXD_DONE = 0,
+ TXP_HTXD_READY = 1 << 0,
+ TXP_HTXD_UNINIT = 1 << 1,
+};
+
+/* RXP flags */
+enum c2_rxp_flags {
+ RXP_HRXD_UNINIT = 0,
+ RXP_HRXD_READY = 1 << 0,
+ RXP_HRXD_DONE = 1 << 1,
+};
+
+/* RXP status */
+enum c2_rxp_status {
+ RXP_HRXD_ZERO = 0,
+ RXP_HRXD_OK = 1 << 0,
+ RXP_HRXD_BUF_OV = 1 << 1,
+};
+
+/* TXP descriptor fields */
+enum txp_desc {
+ C2_TXP_FLAGS = 0x0000,
+ C2_TXP_LEN = 0x0002,
+ C2_TXP_ADDR = 0x0004,
+};
+
+/* RXP descriptor fields */
+enum rxp_desc {
+ C2_RXP_FLAGS = 0x0000,
+ C2_RXP_STATUS = 0x0002,
+ C2_RXP_COUNT = 0x0004,
+ C2_RXP_LEN = 0x0006,
+ C2_RXP_ADDR = 0x0008,
+};
+
+struct c2_txp_desc {
+ u16 flags;
+ u16 len;
+ u64 addr;
+} __attribute__ ((packed));
+
+struct c2_rxp_desc {
+ u16 flags;
+ u16 status;
+ u16 count;
+ u16 len;
+ u64 addr;
+} __attribute__ ((packed));
+
+struct c2_rxp_hdr {
+ u16 flags;
+ u16 status;
+ u16 len;
+ u16 rsvd;
+} __attribute__ ((packed));
+
+struct c2_tx_desc {
+ u32 len;
+ u32 status;
+ dma_addr_t next_offset;
+};
+
+struct c2_rx_desc {
+ u32 len;
+ u32 status;
+ dma_addr_t next_offset;
+};
+
+struct c2_alloc {
+ u32 last;
+ u32 max;
+ spinlock_t lock;
+ unsigned long *table;
+};
+
+struct c2_array {
+ struct {
+ void **page;
+ int used;
+ } *page_list;
+};
+
+/*
+ * The MQ shared pointer pool is organized as a linked list of
+ * chunks. Each chunk contains a linked list of free shared pointers
+ * that can be allocated to a given user mode client.
+ *
+ */
+struct sp_chunk {
+ struct sp_chunk *next;
+ dma_addr_t dma_addr;
+ DECLARE_PCI_UNMAP_ADDR(mapping);
+ u16 head;
+ u16 shared_ptr[0];
+};
+
+struct c2_pd_table {
+ u32 last;
+ u32 max;
+ spinlock_t lock;
+ unsigned long *table;
+};
+
+struct c2_qp_table {
+ struct idr idr;
+ spinlock_t lock;
+ int last;
+};
+
+struct c2_element {
+ struct c2_element *next;
+ void *ht_desc; /* host descriptor */
+ void __iomem *hw_desc; /* hardware descriptor */
+ struct sk_buff *skb;
+ dma_addr_t mapaddr;
+ u32 maplen;
+};
+
+struct c2_ring {
+ struct c2_element *to_clean;
+ struct c2_element *to_use;
+ struct c2_element *start;
+ unsigned long count;
+};
+
+struct c2_dev {
+ struct ib_device ibdev;
+ void __iomem *regs;
+ void __iomem *mmio_txp_ring; /* remapped adapter memory for hw rings */
+ void __iomem *mmio_rxp_ring;
+ spinlock_t lock;
+ struct pci_dev *pcidev;
+ struct net_device *netdev;
+ struct net_device *pseudo_netdev;
+ unsigned int cur_tx;
+ unsigned int cur_rx;
+ u32 adapter_handle;
+ int device_cap_flags;
+ void __iomem *kva; /* KVA device memory */
+ unsigned long pa; /* PA device memory */
+ void **qptr_array;
+
+ kmem_cache_t *host_msg_cache;
+
+ struct list_head cca_link; /* adapter list */
+ struct list_head eh_wakeup_list; /* event wakeup list */
+ wait_queue_head_t req_vq_wo;
+
+ /* Cached RNIC properties */
+ struct ib_device_attr props;
+
+ struct c2_pd_table pd_table;
+ struct c2_qp_table qp_table;
+ int ports; /* num of GigE ports */
+ int devnum;
+ spinlock_t vqlock; /* sync vbs req MQ */
+
+ /* Verbs Queues */
+ struct c2_mq req_vq; /* Verbs Request MQ */
+ struct c2_mq rep_vq; /* Verbs Reply MQ */
+ struct c2_mq aeq; /* Async Events MQ */
+
+ /* Kernel client MQs */
+ struct sp_chunk *kern_mqsp_pool;
+
+ /* Device updates these values when posting messages to a host
+ * target queue */
+ u16 req_vq_shared;
+ u16 rep_vq_shared;
+ u16 aeq_shared;
+ u16 irq_claimed;
+
+ /*
+ * Shared host target pages for user-accessible MQs.
+ */
+ int hthead; /* index of first free entry */
+ void *htpages; /* kernel vaddr */
+ int htlen; /* length of htpages memory */
+ void *htuva; /* user mapped vaddr */
+ spinlock_t htlock; /* serialize allocation */
+
+ u64 adapter_hint_uva; /* access to the activity FIFO */
+
+ // spinlock_t aeq_lock;
+ // spinlock_t rnic_lock;
+
+ u16 *hint_count;
+ dma_addr_t hint_count_dma;
+ u16 hints_read;
+
+ int init; /* TRUE if it's ready */
+ char ae_cache_name[16];
+ char vq_cache_name[16];
+};
+
+struct c2_port {
+ u32 msg_enable;
+ struct c2_dev *c2dev;
+ struct net_device *netdev;
+
+ spinlock_t tx_lock;
+ u32 tx_avail;
+ struct c2_ring tx_ring;
+ struct c2_ring rx_ring;
+
+ void *mem; /* PCI memory for host rings */
+ dma_addr_t dma;
+ unsigned long mem_size;
+
+ u32 rx_buf_size;
+
+ struct net_device_stats netstats;
+};
+
+/*
+ * Activity FIFO registers in BAR0.
+ */
+#define PCI_BAR0_HOST_HINT 0x100
+#define PCI_BAR0_ADAPTER_HINT 0x2000
+
+/*
+ * Ammasso PCI vendor id and Cepheus PCI device id.
+ */
+#define CQ_ARMED 0x01
+#define CQ_WAIT_FOR_DMA 0x80
+
+/*
+ * The format of a hint is as follows:
+ * Lower 16 bits are the count of hints for the queue.
+ * Next 15 bits are the qp_index
+ * Upper most bit depends on who reads it:
+ * If read by producer, then it means Full (1) or Not-Full (0)
+ * If read by consumer, then it means Empty (1) or Not-Empty (0)
+ */
+#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
+#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
+#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
+
+
+/*
+ * The following defines the offset in SDRAM for the c2_adapter_pci_regs_t
+ * struct.
+ */
+#define C2_ADAPTER_PCI_REGS_OFFSET 0x10000
+
+#ifndef readq
+static inline u64 readq(const void __iomem * addr)
+{
+ u64 ret = readl(addr + 4);
+ ret <<= 32;
+ ret |= readl(addr);
+
+ return ret;
+}
+#endif
+
+#ifndef writeq
+static inline void __raw_writeq(u64 val, void __iomem * addr)
+{
+ __raw_writel((u32) (val), addr);
+ __raw_writel((u32) (val >> 32), (addr + 4));
+}
+#endif
+
+#define C2_SET_CUR_RX(c2dev, cur_rx) \
+ __raw_writel(cpu_to_be32(cur_rx), c2dev->mmio_txp_ring + 4092)
+
+#define C2_GET_CUR_RX(c2dev) \
+ be32_to_cpu(readl(c2dev->mmio_txp_ring + 4092))
+
+static inline struct c2_dev *to_c2dev(struct ib_device *ibdev)
+{
+ return container_of(ibdev, struct c2_dev, ibdev);
+}
+
+static inline int c2_errno(void *reply)
+{
+ switch (c2_wr_get_result(reply)) {
+ case C2_OK:
+ return 0;
+ case CCERR_NO_BUFS:
+ case CCERR_INSUFFICIENT_RESOURCES:
+ case CCERR_ZERO_RDMA_READ_RESOURCES:
+ return -ENOMEM;
+ case CCERR_MR_IN_USE:
+ case CCERR_QP_IN_USE:
+ return -EBUSY;
+ case CCERR_ADDR_IN_USE:
+ return -EADDRINUSE;
+ case CCERR_ADDR_NOT_AVAIL:
+ return -EADDRNOTAVAIL;
+ case CCERR_CONN_RESET:
+ return -ECONNRESET;
+ case CCERR_NOT_IMPLEMENTED:
+ case CCERR_INVALID_WQE:
+ return -ENOSYS;
+ case CCERR_QP_NOT_PRIVILEGED:
+ return -EPERM;
+ case CCERR_STACK_ERROR:
+ return -EPROTO;
+ case CCERR_ACCESS_VIOLATION:
+ case CCERR_BASE_AND_BOUNDS_VIOLATION:
+ return -EFAULT;
+ case CCERR_STAG_STATE_NOT_INVALID:
+ case CCERR_INVALID_ADDRESS:
+ case CCERR_INVALID_CQ:
+ case CCERR_INVALID_EP:
+ case CCERR_INVALID_MODIFIER:
+ case CCERR_INVALID_MTU:
+ case CCERR_INVALID_PD_ID:
+ case CCERR_INVALID_QP:
+ case CCERR_INVALID_RNIC:
+ case CCERR_INVALID_STAG:
+ return -EINVAL;
+ default:
+ return -EAGAIN;
+ }
+}
+
+/* Device */
+extern int c2_register_device(struct c2_dev *c2dev);
+extern void c2_unregister_device(struct c2_dev *c2dev);
+extern int c2_rnic_init(struct c2_dev *c2dev);
+extern void c2_rnic_term(struct c2_dev *c2dev);
+extern void c2_rnic_interrupt(struct c2_dev *c2dev);
+extern int c2_del_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask);
+extern int c2_add_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask);
+
+/* QPs */
+extern int c2_alloc_qp(struct c2_dev *c2dev, struct c2_pd *pd,
+ struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp);
+extern void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp);
+extern struct ib_qp *c2_get_qp(struct ib_device *device, int qpn);
+extern int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
+ struct ib_qp_attr *attr, int attr_mask);
+extern int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
+ int ord, int ird);
+extern int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+ struct ib_send_wr **bad_wr);
+extern int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+ struct ib_recv_wr **bad_wr);
+extern void __devinit c2_init_qp_table(struct c2_dev *c2dev);
+extern void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev);
+extern void c2_set_qp_state(struct c2_qp *, int);
+extern struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn);
+
+/* PDs */
+extern int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd);
+extern void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd);
+extern int __devinit c2_init_pd_table(struct c2_dev *c2dev);
+extern void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev);
+
+/* CQs */
+extern int c2_init_cq(struct c2_dev *c2dev, int entries,
+ struct c2_ucontext *ctx, struct c2_cq *cq);
+extern void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq);
+extern void c2_cq_event(struct c2_dev *c2dev, u32 mq_index);
+extern void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index);
+extern int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry);
+extern int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify);
+
+/* CM */
+extern int c2_llp_connect(struct iw_cm_id *cm_id,
+ struct iw_cm_conn_param *iw_param);
+extern int c2_llp_accept(struct iw_cm_id *cm_id,
+ struct iw_cm_conn_param *iw_param);
+extern int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata,
+ u8 pdata_len);
+extern int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog);
+extern int c2_llp_service_destroy(struct iw_cm_id *cm_id);
+
+/* MM */
+extern int c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
+ int page_size, int pbl_depth, u32 length,
+ u32 off, u64 *va, enum c2_acf acf,
+ struct c2_mr *mr);
+extern int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index);
+
+/* AE */
+extern void c2_ae_event(struct c2_dev *c2dev, u32 mq_index);
+
+/* MQSP Allocator */
+extern int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
+ struct sp_chunk **root);
+extern void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root);
+extern u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
+ dma_addr_t *dma_addr, gfp_t gfp_mask);
+extern void c2_free_mqsp(u16 * mqsp);
+#endif
diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c
new file mode 100644
index 00000000000..3aae4978e1c
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_ae.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "c2.h"
+#include <rdma/iw_cm.h>
+#include "c2_status.h"
+#include "c2_ae.h"
+
+static int c2_convert_cm_status(u32 c2_status)
+{
+ switch (c2_status) {
+ case C2_CONN_STATUS_SUCCESS:
+ return 0;
+ case C2_CONN_STATUS_REJECTED:
+ return -ENETRESET;
+ case C2_CONN_STATUS_REFUSED:
+ return -ECONNREFUSED;
+ case C2_CONN_STATUS_TIMEDOUT:
+ return -ETIMEDOUT;
+ case C2_CONN_STATUS_NETUNREACH:
+ return -ENETUNREACH;
+ case C2_CONN_STATUS_HOSTUNREACH:
+ return -EHOSTUNREACH;
+ case C2_CONN_STATUS_INVALID_RNIC:
+ return -EINVAL;
+ case C2_CONN_STATUS_INVALID_QP:
+ return -EINVAL;
+ case C2_CONN_STATUS_INVALID_QP_STATE:
+ return -EINVAL;
+ case C2_CONN_STATUS_ADDR_NOT_AVAIL:
+ return -EADDRNOTAVAIL;
+ default:
+ printk(KERN_ERR PFX
+ "%s - Unable to convert CM status: %d\n",
+ __FUNCTION__, c2_status);
+ return -EIO;
+ }
+}
+
+#ifdef DEBUG
+static const char* to_event_str(int event)
+{
+ static const char* event_str[] = {
+ "CCAE_REMOTE_SHUTDOWN",
+ "CCAE_ACTIVE_CONNECT_RESULTS",
+ "CCAE_CONNECTION_REQUEST",
+ "CCAE_LLP_CLOSE_COMPLETE",
+ "CCAE_TERMINATE_MESSAGE_RECEIVED",
+ "CCAE_LLP_CONNECTION_RESET",
+ "CCAE_LLP_CONNECTION_LOST",
+ "CCAE_LLP_SEGMENT_SIZE_INVALID",
+ "CCAE_LLP_INVALID_CRC",
+ "CCAE_LLP_BAD_FPDU",
+ "CCAE_INVALID_DDP_VERSION",
+ "CCAE_INVALID_RDMA_VERSION",
+ "CCAE_UNEXPECTED_OPCODE",
+ "CCAE_INVALID_DDP_QUEUE_NUMBER",
+ "CCAE_RDMA_READ_NOT_ENABLED",
+ "CCAE_RDMA_WRITE_NOT_ENABLED",
+ "CCAE_RDMA_READ_TOO_SMALL",
+ "CCAE_NO_L_BIT",
+ "CCAE_TAGGED_INVALID_STAG",
+ "CCAE_TAGGED_BASE_BOUNDS_VIOLATION",
+ "CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION",
+ "CCAE_TAGGED_INVALID_PD",
+ "CCAE_WRAP_ERROR",
+ "CCAE_BAD_CLOSE",
+ "CCAE_BAD_LLP_CLOSE",
+ "CCAE_INVALID_MSN_RANGE",
+ "CCAE_INVALID_MSN_GAP",
+ "CCAE_IRRQ_OVERFLOW",
+ "CCAE_IRRQ_MSN_GAP",
+ "CCAE_IRRQ_MSN_RANGE",
+ "CCAE_IRRQ_INVALID_STAG",
+ "CCAE_IRRQ_BASE_BOUNDS_VIOLATION",
+ "CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION",
+ "CCAE_IRRQ_INVALID_PD",
+ "CCAE_IRRQ_WRAP_ERROR",
+ "CCAE_CQ_SQ_COMPLETION_OVERFLOW",
+ "CCAE_CQ_RQ_COMPLETION_ERROR",
+ "CCAE_QP_SRQ_WQE_ERROR",
+ "CCAE_QP_LOCAL_CATASTROPHIC_ERROR",
+ "CCAE_CQ_OVERFLOW",
+ "CCAE_CQ_OPERATION_ERROR",
+ "CCAE_SRQ_LIMIT_REACHED",
+ "CCAE_QP_RQ_LIMIT_REACHED",
+ "CCAE_SRQ_CATASTROPHIC_ERROR",
+ "CCAE_RNIC_CATASTROPHIC_ERROR"
+ };
+
+ if (event < CCAE_REMOTE_SHUTDOWN ||
+ event > CCAE_RNIC_CATASTROPHIC_ERROR)
+ return "<invalid event>";
+
+ event -= CCAE_REMOTE_SHUTDOWN;
+ return event_str[event];
+}
+
+static const char *to_qp_state_str(int state)
+{
+ switch (state) {
+ case C2_QP_STATE_IDLE:
+ return "C2_QP_STATE_IDLE";
+ case C2_QP_STATE_CONNECTING:
+ return "C2_QP_STATE_CONNECTING";
+ case C2_QP_STATE_RTS:
+ return "C2_QP_STATE_RTS";
+ case C2_QP_STATE_CLOSING:
+ return "C2_QP_STATE_CLOSING";
+ case C2_QP_STATE_TERMINATE:
+ return "C2_QP_STATE_TERMINATE";
+ case C2_QP_STATE_ERROR:
+ return "C2_QP_STATE_ERROR";
+ default:
+ return "<invalid QP state>";
+ };
+}
+#endif
+
+void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
+{
+ struct c2_mq *mq = c2dev->qptr_array[mq_index];
+ union c2wr *wr;
+ void *resource_user_context;
+ struct iw_cm_event cm_event;
+ struct ib_event ib_event;
+ enum c2_resource_indicator resource_indicator;
+ enum c2_event_id event_id;
+ unsigned long flags;
+ int status;
+
+ /*
+ * retreive the message
+ */
+ wr = c2_mq_consume(mq);
+ if (!wr)
+ return;
+
+ memset(&ib_event, 0, sizeof(ib_event));
+ memset(&cm_event, 0, sizeof(cm_event));
+
+ event_id = c2_wr_get_id(wr);
+ resource_indicator = be32_to_cpu(wr->ae.ae_generic.resource_type);
+ resource_user_context =
+ (void *) (unsigned long) wr->ae.ae_generic.user_context;
+
+ status = cm_event.status = c2_convert_cm_status(c2_wr_get_result(wr));
+
+ pr_debug("event received c2_dev=%p, event_id=%d, "
+ "resource_indicator=%d, user_context=%p, status = %d\n",
+ c2dev, event_id, resource_indicator, resource_user_context,
+ status);
+
+ switch (resource_indicator) {
+ case C2_RES_IND_QP:{
+
+ struct c2_qp *qp = (struct c2_qp *)resource_user_context;
+ struct iw_cm_id *cm_id = qp->cm_id;
+ struct c2wr_ae_active_connect_results *res;
+
+ if (!cm_id) {
+ pr_debug("event received, but cm_id is <nul>, qp=%p!\n",
+ qp);
+ goto ignore_it;
+ }
+ pr_debug("%s: event = %s, user_context=%llx, "
+ "resource_type=%x, "
+ "resource=%x, qp_state=%s\n",
+ __FUNCTION__,
+ to_event_str(event_id),
+ (unsigned long long) be64_to_cpu(wr->ae.ae_generic.user_context),
+ be32_to_cpu(wr->ae.ae_generic.resource_type),
+ be32_to_cpu(wr->ae.ae_generic.resource),
+ to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state)));
+
+ c2_set_qp_state(qp, be32_to_cpu(wr->ae.ae_generic.qp_state));
+
+ switch (event_id) {
+ case CCAE_ACTIVE_CONNECT_RESULTS:
+ res = &wr->ae.ae_active_connect_results;
+ cm_event.event = IW_CM_EVENT_CONNECT_REPLY;
+ cm_event.local_addr.sin_addr.s_addr = res->laddr;
+ cm_event.remote_addr.sin_addr.s_addr = res->raddr;
+ cm_event.local_addr.sin_port = res->lport;
+ cm_event.remote_addr.sin_port = res->rport;
+ if (status == 0) {
+ cm_event.private_data_len =
+ be32_to_cpu(res->private_data_length);
+ cm_event.private_data = res->private_data;
+ } else {
+ spin_lock_irqsave(&qp->lock, flags);
+ if (qp->cm_id) {
+ qp->cm_id->rem_ref(qp->cm_id);
+ qp->cm_id = NULL;
+ }
+ spin_unlock_irqrestore(&qp->lock, flags);
+ cm_event.private_data_len = 0;
+ cm_event.private_data = NULL;
+ }
+ if (cm_id->event_handler)
+ cm_id->event_handler(cm_id, &cm_event);
+ break;
+ case CCAE_TERMINATE_MESSAGE_RECEIVED:
+ case CCAE_CQ_SQ_COMPLETION_OVERFLOW:
+ ib_event.device = &c2dev->ibdev;
+ ib_event.element.qp = &qp->ibqp;
+ ib_event.event = IB_EVENT_QP_REQ_ERR;
+
+ if (qp->ibqp.event_handler)
+ qp->ibqp.event_handler(&ib_event,
+ qp->ibqp.
+ qp_context);
+ break;
+ case CCAE_BAD_CLOSE:
+ case CCAE_LLP_CLOSE_COMPLETE:
+ case CCAE_LLP_CONNECTION_RESET:
+ case CCAE_LLP_CONNECTION_LOST:
+ BUG_ON(cm_id->event_handler==(void*)0x6b6b6b6b);
+
+ spin_lock_irqsave(&qp->lock, flags);
+ if (qp->cm_id) {
+ qp->cm_id->rem_ref(qp->cm_id);
+ qp->cm_id = NULL;
+ }
+ spin_unlock_irqrestore(&qp->lock, flags);
+ cm_event.event = IW_CM_EVENT_CLOSE;
+ cm_event.status = 0;
+ if (cm_id->event_handler)
+ cm_id->event_handler(cm_id, &cm_event);
+ break;
+ default:
+ BUG_ON(1);
+ pr_debug("%s:%d Unexpected event_id=%d on QP=%p, "
+ "CM_ID=%p\n",
+ __FUNCTION__, __LINE__,
+ event_id, qp, cm_id);
+ break;
+ }
+ break;
+ }
+
+ case C2_RES_IND_EP:{
+
+ struct c2wr_ae_connection_request *req =
+ &wr->ae.ae_connection_request;
+ struct iw_cm_id *cm_id =
+ (struct iw_cm_id *)resource_user_context;
+
+ pr_debug("C2_RES_IND_EP event_id=%d\n", event_id);
+ if (event_id != CCAE_CONNECTION_REQUEST) {
+ pr_debug("%s: Invalid event_id: %d\n",
+ __FUNCTION__, event_id);
+ break;
+ }
+ cm_event.event = IW_CM_EVENT_CONNECT_REQUEST;
+ cm_event.provider_data = (void*)(unsigned long)req->cr_handle;
+ cm_event.local_addr.sin_addr.s_addr = req->laddr;
+ cm_event.remote_addr.sin_addr.s_addr = req->raddr;
+ cm_event.local_addr.sin_port = req->lport;
+ cm_event.remote_addr.sin_port = req->rport;
+ cm_event.private_data_len =
+ be32_to_cpu(req->private_data_length);
+ cm_event.private_data = req->private_data;
+
+ if (cm_id->event_handler)
+ cm_id->event_handler(cm_id, &cm_event);
+ break;
+ }
+
+ case C2_RES_IND_CQ:{
+ struct c2_cq *cq =
+ (struct c2_cq *) resource_user_context;
+
+ pr_debug("IB_EVENT_CQ_ERR\n");
+ ib_event.device = &c2dev->ibdev;
+ ib_event.element.cq = &cq->ibcq;
+ ib_event.event = IB_EVENT_CQ_ERR;
+
+ if (cq->ibcq.event_handler)
+ cq->ibcq.event_handler(&ib_event,
+ cq->ibcq.cq_context);
+ }
+
+ default:
+ printk("Bad resource indicator = %d\n",
+ resource_indicator);
+ break;
+ }
+
+ ignore_it:
+ c2_mq_free(mq);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_ae.h b/drivers/infiniband/hw/amso1100/c2_ae.h
new file mode 100644
index 00000000000..3a065c33b83
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_ae.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_AE_H_
+#define _C2_AE_H_
+
+/*
+ * WARNING: If you change this file, also bump C2_IVN_BASE
+ * in common/include/clustercore/c2_ivn.h.
+ */
+
+/*
+ * Asynchronous Event Identifiers
+ *
+ * These start at 0x80 only so it's obvious from inspection that
+ * they are not work-request statuses. This isn't critical.
+ *
+ * NOTE: these event id's must fit in eight bits.
+ */
+enum c2_event_id {
+ CCAE_REMOTE_SHUTDOWN = 0x80,
+ CCAE_ACTIVE_CONNECT_RESULTS,
+ CCAE_CONNECTION_REQUEST,
+ CCAE_LLP_CLOSE_COMPLETE,
+ CCAE_TERMINATE_MESSAGE_RECEIVED,
+ CCAE_LLP_CONNECTION_RESET,
+ CCAE_LLP_CONNECTION_LOST,
+ CCAE_LLP_SEGMENT_SIZE_INVALID,
+ CCAE_LLP_INVALID_CRC,
+ CCAE_LLP_BAD_FPDU,
+ CCAE_INVALID_DDP_VERSION,
+ CCAE_INVALID_RDMA_VERSION,
+ CCAE_UNEXPECTED_OPCODE,
+ CCAE_INVALID_DDP_QUEUE_NUMBER,
+ CCAE_RDMA_READ_NOT_ENABLED,
+ CCAE_RDMA_WRITE_NOT_ENABLED,
+ CCAE_RDMA_READ_TOO_SMALL,
+ CCAE_NO_L_BIT,
+ CCAE_TAGGED_INVALID_STAG,
+ CCAE_TAGGED_BASE_BOUNDS_VIOLATION,
+ CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION,
+ CCAE_TAGGED_INVALID_PD,
+ CCAE_WRAP_ERROR,
+ CCAE_BAD_CLOSE,
+ CCAE_BAD_LLP_CLOSE,
+ CCAE_INVALID_MSN_RANGE,
+ CCAE_INVALID_MSN_GAP,
+ CCAE_IRRQ_OVERFLOW,
+ CCAE_IRRQ_MSN_GAP,
+ CCAE_IRRQ_MSN_RANGE,
+ CCAE_IRRQ_INVALID_STAG,
+ CCAE_IRRQ_BASE_BOUNDS_VIOLATION,
+ CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION,
+ CCAE_IRRQ_INVALID_PD,
+ CCAE_IRRQ_WRAP_ERROR,
+ CCAE_CQ_SQ_COMPLETION_OVERFLOW,
+ CCAE_CQ_RQ_COMPLETION_ERROR,
+ CCAE_QP_SRQ_WQE_ERROR,
+ CCAE_QP_LOCAL_CATASTROPHIC_ERROR,
+ CCAE_CQ_OVERFLOW,
+ CCAE_CQ_OPERATION_ERROR,
+ CCAE_SRQ_LIMIT_REACHED,
+ CCAE_QP_RQ_LIMIT_REACHED,
+ CCAE_SRQ_CATASTROPHIC_ERROR,
+ CCAE_RNIC_CATASTROPHIC_ERROR
+/* WARNING If you add more id's, make sure their values fit in eight bits. */
+};
+
+/*
+ * Resource Indicators and Identifiers
+ */
+enum c2_resource_indicator {
+ C2_RES_IND_QP = 1,
+ C2_RES_IND_EP,
+ C2_RES_IND_CQ,
+ C2_RES_IND_SRQ,
+};
+
+#endif /* _C2_AE_H_ */
diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/infiniband/hw/amso1100/c2_alloc.c
new file mode 100644
index 00000000000..028a60bbfca
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_alloc.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/bitmap.h>
+
+#include "c2.h"
+
+static int c2_alloc_mqsp_chunk(struct c2_dev *c2dev, gfp_t gfp_mask,
+ struct sp_chunk **head)
+{
+ int i;
+ struct sp_chunk *new_head;
+
+ new_head = (struct sp_chunk *) __get_free_page(gfp_mask);
+ if (new_head == NULL)
+ return -ENOMEM;
+
+ new_head->dma_addr = dma_map_single(c2dev->ibdev.dma_device, new_head,
+ PAGE_SIZE, DMA_FROM_DEVICE);
+ pci_unmap_addr_set(new_head, mapping, new_head->dma_addr);
+
+ new_head->next = NULL;
+ new_head->head = 0;
+
+ /* build list where each index is the next free slot */
+ for (i = 0;
+ i < (PAGE_SIZE - sizeof(struct sp_chunk) -
+ sizeof(u16)) / sizeof(u16) - 1;
+ i++) {
+ new_head->shared_ptr[i] = i + 1;
+ }
+ /* terminate list */
+ new_head->shared_ptr[i] = 0xFFFF;
+
+ *head = new_head;
+ return 0;
+}
+
+int c2_init_mqsp_pool(struct c2_dev *c2dev, gfp_t gfp_mask,
+ struct sp_chunk **root)
+{
+ return c2_alloc_mqsp_chunk(c2dev, gfp_mask, root);
+}
+
+void c2_free_mqsp_pool(struct c2_dev *c2dev, struct sp_chunk *root)
+{
+ struct sp_chunk *next;
+
+ while (root) {
+ next = root->next;
+ dma_unmap_single(c2dev->ibdev.dma_device,
+ pci_unmap_addr(root, mapping), PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ __free_page((struct page *) root);
+ root = next;
+ }
+}
+
+u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
+ dma_addr_t *dma_addr, gfp_t gfp_mask)
+{
+ u16 mqsp;
+
+ while (head) {
+ mqsp = head->head;
+ if (mqsp != 0xFFFF) {
+ head->head = head->shared_ptr[mqsp];
+ break;
+ } else if (head->next == NULL) {
+ if (c2_alloc_mqsp_chunk(c2dev, gfp_mask, &head->next) ==
+ 0) {
+ head = head->next;
+ mqsp = head->head;
+ head->head = head->shared_ptr[mqsp];
+ break;
+ } else
+ return NULL;
+ } else
+ head = head->next;
+ }
+ if (head) {
+ *dma_addr = head->dma_addr +
+ ((unsigned long) &(head->shared_ptr[mqsp]) -
+ (unsigned long) head);
+ pr_debug("%s addr %p dma_addr %llx\n", __FUNCTION__,
+ &(head->shared_ptr[mqsp]), (unsigned long long) *dma_addr);
+ return &(head->shared_ptr[mqsp]);
+ }
+ return NULL;
+}
+
+void c2_free_mqsp(u16 * mqsp)
+{
+ struct sp_chunk *head;
+ u16 idx;
+
+ /* The chunk containing this ptr begins at the page boundary */
+ head = (struct sp_chunk *) ((unsigned long) mqsp & PAGE_MASK);
+
+ /* Link head to new mqsp */
+ *mqsp = head->head;
+
+ /* Compute the shared_ptr index */
+ idx = ((unsigned long) mqsp & ~PAGE_MASK) >> 1;
+ idx -= (unsigned long) &(((struct sp_chunk *) 0)->shared_ptr[0]) >> 1;
+
+ /* Point this index at the head */
+ head->shared_ptr[idx] = head->head;
+
+ /* Point head at this index */
+ head->head = idx;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_cm.c b/drivers/infiniband/hw/amso1100/c2_cm.c
new file mode 100644
index 00000000000..75b93e9b881
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_cm.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "c2.h"
+#include "c2_wr.h"
+#include "c2_vq.h"
+#include <rdma/iw_cm.h>
+
+int c2_llp_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+ struct c2_dev *c2dev = to_c2dev(cm_id->device);
+ struct ib_qp *ibqp;
+ struct c2_qp *qp;
+ struct c2wr_qp_connect_req *wr; /* variable size needs a malloc. */
+ struct c2_vq_req *vq_req;
+ int err;
+
+ ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
+ if (!ibqp)
+ return -EINVAL;
+ qp = to_c2qp(ibqp);
+
+ /* Associate QP <--> CM_ID */
+ cm_id->provider_data = qp;
+ cm_id->add_ref(cm_id);
+ qp->cm_id = cm_id;
+
+ /*
+ * only support the max private_data length
+ */
+ if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
+ err = -EINVAL;
+ goto bail0;
+ }
+ /*
+ * Set the rdma read limits
+ */
+ err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
+ if (err)
+ goto bail0;
+
+ /*
+ * Create and send a WR_QP_CONNECT...
+ */
+ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+ if (!wr) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ c2_wr_set_id(wr, CCWR_QP_CONNECT);
+ wr->hdr.context = 0;
+ wr->rnic_handle = c2dev->adapter_handle;
+ wr->qp_handle = qp->adapter_handle;
+
+ wr->remote_addr = cm_id->remote_addr.sin_addr.s_addr;
+ wr->remote_port = cm_id->remote_addr.sin_port;
+
+ /*
+ * Move any private data from the callers's buf into
+ * the WR.
+ */
+ if (iw_param->private_data) {
+ wr->private_data_length =
+ cpu_to_be32(iw_param->private_data_len);
+ memcpy(&wr->private_data[0], iw_param->private_data,
+ iw_param->private_data_len);
+ } else
+ wr->private_data_length = 0;
+
+ /*
+ * Send WR to adapter. NOTE: There is no synch reply from
+ * the adapter.
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) wr);
+ vq_req_free(c2dev, vq_req);
+
+ bail1:
+ kfree(wr);
+ bail0:
+ if (err) {
+ /*
+ * If we fail, release reference on QP and
+ * disassociate QP from CM_ID
+ */
+ cm_id->provider_data = NULL;
+ qp->cm_id = NULL;
+ cm_id->rem_ref(cm_id);
+ }
+ return err;
+}
+
+int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog)
+{
+ struct c2_dev *c2dev;
+ struct c2wr_ep_listen_create_req wr;
+ struct c2wr_ep_listen_create_rep *reply;
+ struct c2_vq_req *vq_req;
+ int err;
+
+ c2dev = to_c2dev(cm_id->device);
+ if (c2dev == NULL)
+ return -EINVAL;
+
+ /*
+ * Allocate verbs request.
+ */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ /*
+ * Build the WR
+ */
+ c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE);
+ wr.hdr.context = (u64) (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.local_addr = cm_id->local_addr.sin_addr.s_addr;
+ wr.local_port = cm_id->local_addr.sin_port;
+ wr.backlog = cpu_to_be32(backlog);
+ wr.user_context = (u64) (unsigned long) cm_id;
+
+ /*
+ * Reference the request struct. Dereferenced in the int handler.
+ */
+ vq_req_get(c2dev, vq_req);
+
+ /*
+ * Send WR to adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ /*
+ * Wait for reply from adapter
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail0;
+
+ /*
+ * Process reply
+ */
+ reply =
+ (struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ if ((err = c2_errno(reply)) != 0)
+ goto bail1;
+
+ /*
+ * Keep the adapter handle. Used in subsequent destroy
+ */
+ cm_id->provider_data = (void*)(unsigned long) reply->ep_handle;
+
+ /*
+ * free vq stuff
+ */
+ vq_repbuf_free(c2dev, reply);
+ vq_req_free(c2dev, vq_req);
+
+ return 0;
+
+ bail1:
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+
+int c2_llp_service_destroy(struct iw_cm_id *cm_id)
+{
+
+ struct c2_dev *c2dev;
+ struct c2wr_ep_listen_destroy_req wr;
+ struct c2wr_ep_listen_destroy_rep *reply;
+ struct c2_vq_req *vq_req;
+ int err;
+
+ c2dev = to_c2dev(cm_id->device);
+ if (c2dev == NULL)
+ return -EINVAL;
+
+ /*
+ * Allocate verbs request.
+ */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ /*
+ * Build the WR
+ */
+ c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.ep_handle = (u32)(unsigned long)cm_id->provider_data;
+
+ /*
+ * reference the request struct. dereferenced in the int handler.
+ */
+ vq_req_get(c2dev, vq_req);
+
+ /*
+ * Send WR to adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ /*
+ * Wait for reply from adapter
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail0;
+
+ /*
+ * Process reply
+ */
+ reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+ if ((err = c2_errno(reply)) != 0)
+ goto bail1;
+
+ bail1:
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+ struct c2_dev *c2dev = to_c2dev(cm_id->device);
+ struct c2_qp *qp;
+ struct ib_qp *ibqp;
+ struct c2wr_cr_accept_req *wr; /* variable length WR */
+ struct c2_vq_req *vq_req;
+ struct c2wr_cr_accept_rep *reply; /* VQ Reply msg ptr. */
+ int err;
+
+ ibqp = c2_get_qp(cm_id->device, iw_param->qpn);
+ if (!ibqp)
+ return -EINVAL;
+ qp = to_c2qp(ibqp);
+
+ /* Set the RDMA read limits */
+ err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);
+ if (err)
+ goto bail0;
+
+ /* Allocate verbs request. */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+ vq_req->qp = qp;
+ vq_req->cm_id = cm_id;
+ vq_req->event = IW_CM_EVENT_ESTABLISHED;
+
+ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+ if (!wr) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ /* Build the WR */
+ c2_wr_set_id(wr, CCWR_CR_ACCEPT);
+ wr->hdr.context = (unsigned long) vq_req;
+ wr->rnic_handle = c2dev->adapter_handle;
+ wr->ep_handle = (u32) (unsigned long) cm_id->provider_data;
+ wr->qp_handle = qp->adapter_handle;
+
+ /* Replace the cr_handle with the QP after accept */
+ cm_id->provider_data = qp;
+ cm_id->add_ref(cm_id);
+ qp->cm_id = cm_id;
+
+ cm_id->provider_data = qp;
+
+ /* Validate private_data length */
+ if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
+ err = -EINVAL;
+ goto bail1;
+ }
+
+ if (iw_param->private_data) {
+ wr->private_data_length = cpu_to_be32(iw_param->private_data_len);
+ memcpy(&wr->private_data[0],
+ iw_param->private_data, iw_param->private_data_len);
+ } else
+ wr->private_data_length = 0;
+
+ /* Reference the request struct. Dereferenced in the int handler. */
+ vq_req_get(c2dev, vq_req);
+
+ /* Send WR to adapter */
+ err = vq_send_wr(c2dev, (union c2wr *) wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail1;
+ }
+
+ /* Wait for reply from adapter */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail1;
+
+ /* Check that reply is present */
+ reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ err = c2_errno(reply);
+ vq_repbuf_free(c2dev, reply);
+
+ if (!err)
+ c2_set_qp_state(qp, C2_QP_STATE_RTS);
+ bail1:
+ kfree(wr);
+ vq_req_free(c2dev, vq_req);
+ bail0:
+ if (err) {
+ /*
+ * If we fail, release reference on QP and
+ * disassociate QP from CM_ID
+ */
+ cm_id->provider_data = NULL;
+ qp->cm_id = NULL;
+ cm_id->rem_ref(cm_id);
+ }
+ return err;
+}
+
+int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+ struct c2_dev *c2dev;
+ struct c2wr_cr_reject_req wr;
+ struct c2_vq_req *vq_req;
+ struct c2wr_cr_reject_rep *reply;
+ int err;
+
+ c2dev = to_c2dev(cm_id->device);
+
+ /*
+ * Allocate verbs request.
+ */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ /*
+ * Build the WR
+ */
+ c2_wr_set_id(&wr, CCWR_CR_REJECT);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.ep_handle = (u32) (unsigned long) cm_id->provider_data;
+
+ /*
+ * reference the request struct. dereferenced in the int handler.
+ */
+ vq_req_get(c2dev, vq_req);
+
+ /*
+ * Send WR to adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ /*
+ * Wait for reply from adapter
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail0;
+
+ /*
+ * Process reply
+ */
+ reply = (struct c2wr_cr_reject_rep *) (unsigned long)
+ vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+ err = c2_errno(reply);
+ /*
+ * free vq stuff
+ */
+ vq_repbuf_free(c2dev, reply);
+
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/infiniband/hw/amso1100/c2_cq.c
new file mode 100644
index 00000000000..9d7bcc5ade9
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_cq.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include "c2.h"
+#include "c2_vq.h"
+#include "c2_status.h"
+
+#define C2_CQ_MSG_SIZE ((sizeof(struct c2wr_ce) + 32-1) & ~(32-1))
+
+static struct c2_cq *c2_cq_get(struct c2_dev *c2dev, int cqn)
+{
+ struct c2_cq *cq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c2dev->lock, flags);
+ cq = c2dev->qptr_array[cqn];
+ if (!cq) {
+ spin_unlock_irqrestore(&c2dev->lock, flags);
+ return NULL;
+ }
+ atomic_inc(&cq->refcount);
+ spin_unlock_irqrestore(&c2dev->lock, flags);
+ return cq;
+}
+
+static void c2_cq_put(struct c2_cq *cq)
+{
+ if (atomic_dec_and_test(&cq->refcount))
+ wake_up(&cq->wait);
+}
+
+void c2_cq_event(struct c2_dev *c2dev, u32 mq_index)
+{
+ struct c2_cq *cq;
+
+ cq = c2_cq_get(c2dev, mq_index);
+ if (!cq) {
+ printk("discarding events on destroyed CQN=%d\n", mq_index);
+ return;
+ }
+
+ (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
+ c2_cq_put(cq);
+}
+
+void c2_cq_clean(struct c2_dev *c2dev, struct c2_qp *qp, u32 mq_index)
+{
+ struct c2_cq *cq;
+ struct c2_mq *q;
+
+ cq = c2_cq_get(c2dev, mq_index);
+ if (!cq)
+ return;
+
+ spin_lock_irq(&cq->lock);
+ q = &cq->mq;
+ if (q && !c2_mq_empty(q)) {
+ u16 priv = q->priv;
+ struct c2wr_ce *msg;
+
+ while (priv != be16_to_cpu(*q->shared)) {
+ msg = (struct c2wr_ce *)
+ (q->msg_pool.host + priv * q->msg_size);
+ if (msg->qp_user_context == (u64) (unsigned long) qp) {
+ msg->qp_user_context = (u64) 0;
+ }
+ priv = (priv + 1) % q->q_size;
+ }
+ }
+ spin_unlock_irq(&cq->lock);
+ c2_cq_put(cq);
+}
+
+static inline enum ib_wc_status c2_cqe_status_to_openib(u8 status)
+{
+ switch (status) {
+ case C2_OK:
+ return IB_WC_SUCCESS;
+ case CCERR_FLUSHED:
+ return IB_WC_WR_FLUSH_ERR;
+ case CCERR_BASE_AND_BOUNDS_VIOLATION:
+ return IB_WC_LOC_PROT_ERR;
+ case CCERR_ACCESS_VIOLATION:
+ return IB_WC_LOC_ACCESS_ERR;
+ case CCERR_TOTAL_LENGTH_TOO_BIG:
+ return IB_WC_LOC_LEN_ERR;
+ case CCERR_INVALID_WINDOW:
+ return IB_WC_MW_BIND_ERR;
+ default:
+ return IB_WC_GENERAL_ERR;
+ }
+}
+
+
+static inline int c2_poll_one(struct c2_dev *c2dev,
+ struct c2_cq *cq, struct ib_wc *entry)
+{
+ struct c2wr_ce *ce;
+ struct c2_qp *qp;
+ int is_recv = 0;
+
+ ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
+ if (!ce) {
+ return -EAGAIN;
+ }
+
+ /*
+ * if the qp returned is null then this qp has already
+ * been freed and we are unable process the completion.
+ * try pulling the next message
+ */
+ while ((qp =
+ (struct c2_qp *) (unsigned long) ce->qp_user_context) == NULL) {
+ c2_mq_free(&cq->mq);
+ ce = (struct c2wr_ce *) c2_mq_consume(&cq->mq);
+ if (!ce)
+ return -EAGAIN;
+ }
+
+ entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
+ entry->wr_id = ce->hdr.context;
+ entry->qp_num = ce->handle;
+ entry->wc_flags = 0;
+ entry->slid = 0;
+ entry->sl = 0;
+ entry->src_qp = 0;
+ entry->dlid_path_bits = 0;
+ entry->pkey_index = 0;
+
+ switch (c2_wr_get_id(ce)) {
+ case C2_WR_TYPE_SEND:
+ entry->opcode = IB_WC_SEND;
+ break;
+ case C2_WR_TYPE_RDMA_WRITE:
+ entry->opcode = IB_WC_RDMA_WRITE;
+ break;
+ case C2_WR_TYPE_RDMA_READ:
+ entry->opcode = IB_WC_RDMA_READ;
+ break;
+ case C2_WR_TYPE_BIND_MW:
+ entry->opcode = IB_WC_BIND_MW;
+ break;
+ case C2_WR_TYPE_RECV:
+ entry->byte_len = be32_to_cpu(ce->bytes_rcvd);
+ entry->opcode = IB_WC_RECV;
+ is_recv = 1;
+ break;
+ default:
+ break;
+ }
+
+ /* consume the WQEs */
+ if (is_recv)
+ c2_mq_lconsume(&qp->rq_mq, 1);
+ else
+ c2_mq_lconsume(&qp->sq_mq,
+ be32_to_cpu(c2_wr_get_wqe_count(ce)) + 1);
+
+ /* free the message */
+ c2_mq_free(&cq->mq);
+
+ return 0;
+}
+
+int c2_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
+{
+ struct c2_dev *c2dev = to_c2dev(ibcq->device);
+ struct c2_cq *cq = to_c2cq(ibcq);
+ unsigned long flags;
+ int npolled, err;
+
+ spin_lock_irqsave(&cq->lock, flags);
+
+ for (npolled = 0; npolled < num_entries; ++npolled) {
+
+ err = c2_poll_one(c2dev, cq, entry + npolled);
+ if (err)
+ break;
+ }
+
+ spin_unlock_irqrestore(&cq->lock, flags);
+
+ return npolled;
+}
+
+int c2_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
+{
+ struct c2_mq_shared __iomem *shared;
+ struct c2_cq *cq;
+
+ cq = to_c2cq(ibcq);
+ shared = cq->mq.peer;
+
+ if (notify == IB_CQ_NEXT_COMP)
+ writeb(C2_CQ_NOTIFICATION_TYPE_NEXT, &shared->notification_type);
+ else if (notify == IB_CQ_SOLICITED)
+ writeb(C2_CQ_NOTIFICATION_TYPE_NEXT_SE, &shared->notification_type);
+ else
+ return -EINVAL;
+
+ writeb(CQ_WAIT_FOR_DMA | CQ_ARMED, &shared->armed);
+
+ /*
+ * Now read back shared->armed to make the PCI
+ * write synchronous. This is necessary for
+ * correct cq notification semantics.
+ */
+ readb(&shared->armed);
+
+ return 0;
+}
+
+static void c2_free_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq)
+{
+
+ dma_unmap_single(c2dev->ibdev.dma_device, pci_unmap_addr(mq, mapping),
+ mq->q_size * mq->msg_size, DMA_FROM_DEVICE);
+ free_pages((unsigned long) mq->msg_pool.host,
+ get_order(mq->q_size * mq->msg_size));
+}
+
+static int c2_alloc_cq_buf(struct c2_dev *c2dev, struct c2_mq *mq, int q_size,
+ int msg_size)
+{
+ unsigned long pool_start;
+
+ pool_start = __get_free_pages(GFP_KERNEL,
+ get_order(q_size * msg_size));
+ if (!pool_start)
+ return -ENOMEM;
+
+ c2_mq_rep_init(mq,
+ 0, /* index (currently unknown) */
+ q_size,
+ msg_size,
+ (u8 *) pool_start,
+ NULL, /* peer (currently unknown) */
+ C2_MQ_HOST_TARGET);
+
+ mq->host_dma = dma_map_single(c2dev->ibdev.dma_device,
+ (void *)pool_start,
+ q_size * msg_size, DMA_FROM_DEVICE);
+ pci_unmap_addr_set(mq, mapping, mq->host_dma);
+
+ return 0;
+}
+
+int c2_init_cq(struct c2_dev *c2dev, int entries,
+ struct c2_ucontext *ctx, struct c2_cq *cq)
+{
+ struct c2wr_cq_create_req wr;
+ struct c2wr_cq_create_rep *reply;
+ unsigned long peer_pa;
+ struct c2_vq_req *vq_req;
+ int err;
+
+ might_sleep();
+
+ cq->ibcq.cqe = entries - 1;
+ cq->is_kernel = !ctx;
+
+ /* Allocate a shared pointer */
+ cq->mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &cq->mq.shared_dma, GFP_KERNEL);
+ if (!cq->mq.shared)
+ return -ENOMEM;
+
+ /* Allocate pages for the message pool */
+ err = c2_alloc_cq_buf(c2dev, &cq->mq, entries + 1, C2_CQ_MSG_SIZE);
+ if (err)
+ goto bail0;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_CQ_CREATE);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.msg_size = cpu_to_be32(cq->mq.msg_size);
+ wr.depth = cpu_to_be32(cq->mq.q_size);
+ wr.shared_ht = cpu_to_be64(cq->mq.shared_dma);
+ wr.msg_pool = cpu_to_be64(cq->mq.host_dma);
+ wr.user_context = (u64) (unsigned long) (cq);
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail2;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail2;
+
+ reply = (struct c2wr_cq_create_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail2;
+ }
+
+ if ((err = c2_errno(reply)) != 0)
+ goto bail3;
+
+ cq->adapter_handle = reply->cq_handle;
+ cq->mq.index = be32_to_cpu(reply->mq_index);
+
+ peer_pa = c2dev->pa + be32_to_cpu(reply->adapter_shared);
+ cq->mq.peer = ioremap_nocache(peer_pa, PAGE_SIZE);
+ if (!cq->mq.peer) {
+ err = -ENOMEM;
+ goto bail3;
+ }
+
+ vq_repbuf_free(c2dev, reply);
+ vq_req_free(c2dev, vq_req);
+
+ spin_lock_init(&cq->lock);
+ atomic_set(&cq->refcount, 1);
+ init_waitqueue_head(&cq->wait);
+
+ /*
+ * Use the MQ index allocated by the adapter to
+ * store the CQ in the qptr_array
+ */
+ cq->cqn = cq->mq.index;
+ c2dev->qptr_array[cq->cqn] = cq;
+
+ return 0;
+
+ bail3:
+ vq_repbuf_free(c2dev, reply);
+ bail2:
+ vq_req_free(c2dev, vq_req);
+ bail1:
+ c2_free_cq_buf(c2dev, &cq->mq);
+ bail0:
+ c2_free_mqsp(cq->mq.shared);
+
+ return err;
+}
+
+void c2_free_cq(struct c2_dev *c2dev, struct c2_cq *cq)
+{
+ int err;
+ struct c2_vq_req *vq_req;
+ struct c2wr_cq_destroy_req wr;
+ struct c2wr_cq_destroy_rep *reply;
+
+ might_sleep();
+
+ /* Clear CQ from the qptr array */
+ spin_lock_irq(&c2dev->lock);
+ c2dev->qptr_array[cq->mq.index] = NULL;
+ atomic_dec(&cq->refcount);
+ spin_unlock_irq(&c2dev->lock);
+
+ wait_event(cq->wait, !atomic_read(&cq->refcount));
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req) {
+ goto bail0;
+ }
+
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_CQ_DESTROY);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.cq_handle = cq->adapter_handle;
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail1;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail1;
+
+ reply = (struct c2wr_cq_destroy_rep *) (unsigned long) (vq_req->reply_msg);
+
+ vq_repbuf_free(c2dev, reply);
+ bail1:
+ vq_req_free(c2dev, vq_req);
+ bail0:
+ if (cq->is_kernel) {
+ c2_free_cq_buf(c2dev, &cq->mq);
+ }
+
+ return;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_intr.c b/drivers/infiniband/hw/amso1100/c2_intr.c
new file mode 100644
index 00000000000..0d0bc33ca30
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_intr.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "c2.h"
+#include <rdma/iw_cm.h>
+#include "c2_vq.h"
+
+static void handle_mq(struct c2_dev *c2dev, u32 index);
+static void handle_vq(struct c2_dev *c2dev, u32 mq_index);
+
+/*
+ * Handle RNIC interrupts
+ */
+void c2_rnic_interrupt(struct c2_dev *c2dev)
+{
+ unsigned int mq_index;
+
+ while (c2dev->hints_read != be16_to_cpu(*c2dev->hint_count)) {
+ mq_index = readl(c2dev->regs + PCI_BAR0_HOST_HINT);
+ if (mq_index & 0x80000000) {
+ break;
+ }
+
+ c2dev->hints_read++;
+ handle_mq(c2dev, mq_index);
+ }
+
+}
+
+/*
+ * Top level MQ handler
+ */
+static void handle_mq(struct c2_dev *c2dev, u32 mq_index)
+{
+ if (c2dev->qptr_array[mq_index] == NULL) {
+ pr_debug(KERN_INFO "handle_mq: stray activity for mq_index=%d\n",
+ mq_index);
+ return;
+ }
+
+ switch (mq_index) {
+ case (0):
+ /*
+ * An index of 0 in the activity queue
+ * indicates the req vq now has messages
+ * available...
+ *
+ * Wake up any waiters waiting on req VQ
+ * message availability.
+ */
+ wake_up(&c2dev->req_vq_wo);
+ break;
+ case (1):
+ handle_vq(c2dev, mq_index);
+ break;
+ case (2):
+ /* We have to purge the VQ in case there are pending
+ * accept reply requests that would result in the
+ * generation of an ESTABLISHED event. If we don't
+ * generate these first, a CLOSE event could end up
+ * being delivered before the ESTABLISHED event.
+ */
+ handle_vq(c2dev, 1);
+
+ c2_ae_event(c2dev, mq_index);
+ break;
+ default:
+ /* There is no event synchronization between CQ events
+ * and AE or CM events. In fact, CQE could be
+ * delivered for all of the I/O up to and including the
+ * FLUSH for a peer disconenct prior to the ESTABLISHED
+ * event being delivered to the app. The reason for this
+ * is that CM events are delivered on a thread, while AE
+ * and CM events are delivered on interrupt context.
+ */
+ c2_cq_event(c2dev, mq_index);
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Handles verbs WR replies.
+ */
+static void handle_vq(struct c2_dev *c2dev, u32 mq_index)
+{
+ void *adapter_msg, *reply_msg;
+ struct c2wr_hdr *host_msg;
+ struct c2wr_hdr tmp;
+ struct c2_mq *reply_vq;
+ struct c2_vq_req *req;
+ struct iw_cm_event cm_event;
+ int err;
+
+ reply_vq = (struct c2_mq *) c2dev->qptr_array[mq_index];
+
+ /*
+ * get next msg from mq_index into adapter_msg.
+ * don't free it yet.
+ */
+ adapter_msg = c2_mq_consume(reply_vq);
+ if (adapter_msg == NULL) {
+ return;
+ }
+
+ host_msg = vq_repbuf_alloc(c2dev);
+
+ /*
+ * If we can't get a host buffer, then we'll still
+ * wakeup the waiter, we just won't give him the msg.
+ * It is assumed the waiter will deal with this...
+ */
+ if (!host_msg) {
+ pr_debug("handle_vq: no repbufs!\n");
+
+ /*
+ * just copy the WR header into a local variable.
+ * this allows us to still demux on the context
+ */
+ host_msg = &tmp;
+ memcpy(host_msg, adapter_msg, sizeof(tmp));
+ reply_msg = NULL;
+ } else {
+ memcpy(host_msg, adapter_msg, reply_vq->msg_size);
+ reply_msg = host_msg;
+ }
+
+ /*
+ * consume the msg from the MQ
+ */
+ c2_mq_free(reply_vq);
+
+ /*
+ * wakeup the waiter.
+ */
+ req = (struct c2_vq_req *) (unsigned long) host_msg->context;
+ if (req == NULL) {
+ /*
+ * We should never get here, as the adapter should
+ * never send us a reply that we're not expecting.
+ */
+ vq_repbuf_free(c2dev, host_msg);
+ pr_debug("handle_vq: UNEXPECTEDLY got NULL req\n");
+ return;
+ }
+
+ err = c2_errno(reply_msg);
+ if (!err) switch (req->event) {
+ case IW_CM_EVENT_ESTABLISHED:
+ c2_set_qp_state(req->qp,
+ C2_QP_STATE_RTS);
+ case IW_CM_EVENT_CLOSE:
+
+ /*
+ * Move the QP to RTS if this is
+ * the established event
+ */
+ cm_event.event = req->event;
+ cm_event.status = 0;
+ cm_event.local_addr = req->cm_id->local_addr;
+ cm_event.remote_addr = req->cm_id->remote_addr;
+ cm_event.private_data = NULL;
+ cm_event.private_data_len = 0;
+ req->cm_id->event_handler(req->cm_id, &cm_event);
+ break;
+ default:
+ break;
+ }
+
+ req->reply_msg = (u64) (unsigned long) (reply_msg);
+ atomic_set(&req->reply_ready, 1);
+ wake_up(&req->wait_object);
+
+ /*
+ * If the request was cancelled, then this put will
+ * free the vq_req memory...and reply_msg!!!
+ */
+ vq_req_put(c2dev, req);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_mm.c b/drivers/infiniband/hw/amso1100/c2_mm.c
new file mode 100644
index 00000000000..1e4f46493fc
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_mm.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "c2.h"
+#include "c2_vq.h"
+
+#define PBL_VIRT 1
+#define PBL_PHYS 2
+
+/*
+ * Send all the PBL messages to convey the remainder of the PBL
+ * Wait for the adapter's reply on the last one.
+ * This is indicated by setting the MEM_PBL_COMPLETE in the flags.
+ *
+ * NOTE: vq_req is _not_ freed by this function. The VQ Host
+ * Reply buffer _is_ freed by this function.
+ */
+static int
+send_pbl_messages(struct c2_dev *c2dev, u32 stag_index,
+ unsigned long va, u32 pbl_depth,
+ struct c2_vq_req *vq_req, int pbl_type)
+{
+ u32 pbe_count; /* amt that fits in a PBL msg */
+ u32 count; /* amt in this PBL MSG. */
+ struct c2wr_nsmr_pbl_req *wr; /* PBL WR ptr */
+ struct c2wr_nsmr_pbl_rep *reply; /* reply ptr */
+ int err, pbl_virt, pbl_index, i;
+
+ switch (pbl_type) {
+ case PBL_VIRT:
+ pbl_virt = 1;
+ break;
+ case PBL_PHYS:
+ pbl_virt = 0;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ pbe_count = (c2dev->req_vq.msg_size -
+ sizeof(struct c2wr_nsmr_pbl_req)) / sizeof(u64);
+ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+ if (!wr) {
+ return -ENOMEM;
+ }
+ c2_wr_set_id(wr, CCWR_NSMR_PBL);
+
+ /*
+ * Only the last PBL message will generate a reply from the verbs,
+ * so we set the context to 0 indicating there is no kernel verbs
+ * handler blocked awaiting this reply.
+ */
+ wr->hdr.context = 0;
+ wr->rnic_handle = c2dev->adapter_handle;
+ wr->stag_index = stag_index; /* already swapped */
+ wr->flags = 0;
+ pbl_index = 0;
+ while (pbl_depth) {
+ count = min(pbe_count, pbl_depth);
+ wr->addrs_length = cpu_to_be32(count);
+
+ /*
+ * If this is the last message, then reference the
+ * vq request struct cuz we're gonna wait for a reply.
+ * also make this PBL msg as the last one.
+ */
+ if (count == pbl_depth) {
+ /*
+ * reference the request struct. dereferenced in the
+ * int handler.
+ */
+ vq_req_get(c2dev, vq_req);
+ wr->flags = cpu_to_be32(MEM_PBL_COMPLETE);
+
+ /*
+ * This is the last PBL message.
+ * Set the context to our VQ Request Object so we can
+ * wait for the reply.
+ */
+ wr->hdr.context = (unsigned long) vq_req;
+ }
+
+ /*
+ * If pbl_virt is set then va is a virtual address
+ * that describes a virtually contiguous memory
+ * allocation. The wr needs the start of each virtual page
+ * to be converted to the corresponding physical address
+ * of the page. If pbl_virt is not set then va is an array
+ * of physical addresses and there is no conversion to do.
+ * Just fill in the wr with what is in the array.
+ */
+ for (i = 0; i < count; i++) {
+ if (pbl_virt) {
+ va += PAGE_SIZE;
+ } else {
+ wr->paddrs[i] =
+ cpu_to_be64(((u64 *)va)[pbl_index + i]);
+ }
+ }
+
+ /*
+ * Send WR to adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) wr);
+ if (err) {
+ if (count <= pbe_count) {
+ vq_req_put(c2dev, vq_req);
+ }
+ goto bail0;
+ }
+ pbl_depth -= count;
+ pbl_index += count;
+ }
+
+ /*
+ * Now wait for the reply...
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail0;
+ }
+
+ /*
+ * Process reply
+ */
+ reply = (struct c2wr_nsmr_pbl_rep *) (unsigned long) vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ err = c2_errno(reply);
+
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ kfree(wr);
+ return err;
+}
+
+#define C2_PBL_MAX_DEPTH 131072
+int
+c2_nsmr_register_phys_kern(struct c2_dev *c2dev, u64 *addr_list,
+ int page_size, int pbl_depth, u32 length,
+ u32 offset, u64 *va, enum c2_acf acf,
+ struct c2_mr *mr)
+{
+ struct c2_vq_req *vq_req;
+ struct c2wr_nsmr_register_req *wr;
+ struct c2wr_nsmr_register_rep *reply;
+ u16 flags;
+ int i, pbe_count, count;
+ int err;
+
+ if (!va || !length || !addr_list || !pbl_depth)
+ return -EINTR;
+
+ /*
+ * Verify PBL depth is within rnic max
+ */
+ if (pbl_depth > C2_PBL_MAX_DEPTH) {
+ return -EINTR;
+ }
+
+ /*
+ * allocate verbs request object
+ */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+ if (!wr) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ /*
+ * build the WR
+ */
+ c2_wr_set_id(wr, CCWR_NSMR_REGISTER);
+ wr->hdr.context = (unsigned long) vq_req;
+ wr->rnic_handle = c2dev->adapter_handle;
+
+ flags = (acf | MEM_VA_BASED | MEM_REMOTE);
+
+ /*
+ * compute how many pbes can fit in the message
+ */
+ pbe_count = (c2dev->req_vq.msg_size -
+ sizeof(struct c2wr_nsmr_register_req)) / sizeof(u64);
+
+ if (pbl_depth <= pbe_count) {
+ flags |= MEM_PBL_COMPLETE;
+ }
+ wr->flags = cpu_to_be16(flags);
+ wr->stag_key = 0; //stag_key;
+ wr->va = cpu_to_be64(*va);
+ wr->pd_id = mr->pd->pd_id;
+ wr->pbe_size = cpu_to_be32(page_size);
+ wr->length = cpu_to_be32(length);
+ wr->pbl_depth = cpu_to_be32(pbl_depth);
+ wr->fbo = cpu_to_be32(offset);
+ count = min(pbl_depth, pbe_count);
+ wr->addrs_length = cpu_to_be32(count);
+
+ /*
+ * fill out the PBL for this message
+ */
+ for (i = 0; i < count; i++) {
+ wr->paddrs[i] = cpu_to_be64(addr_list[i]);
+ }
+
+ /*
+ * regerence the request struct
+ */
+ vq_req_get(c2dev, vq_req);
+
+ /*
+ * send the WR to the adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail1;
+ }
+
+ /*
+ * wait for reply from adapter
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail1;
+ }
+
+ /*
+ * process reply
+ */
+ reply =
+ (struct c2wr_nsmr_register_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+ if ((err = c2_errno(reply))) {
+ goto bail2;
+ }
+ //*p_pb_entries = be32_to_cpu(reply->pbl_depth);
+ mr->ibmr.lkey = mr->ibmr.rkey = be32_to_cpu(reply->stag_index);
+ vq_repbuf_free(c2dev, reply);
+
+ /*
+ * if there are still more PBEs we need to send them to
+ * the adapter and wait for a reply on the final one.
+ * reuse vq_req for this purpose.
+ */
+ pbl_depth -= count;
+ if (pbl_depth) {
+
+ vq_req->reply_msg = (unsigned long) NULL;
+ atomic_set(&vq_req->reply_ready, 0);
+ err = send_pbl_messages(c2dev,
+ cpu_to_be32(mr->ibmr.lkey),
+ (unsigned long) &addr_list[i],
+ pbl_depth, vq_req, PBL_PHYS);
+ if (err) {
+ goto bail1;
+ }
+ }
+
+ vq_req_free(c2dev, vq_req);
+ kfree(wr);
+
+ return err;
+
+ bail2:
+ vq_repbuf_free(c2dev, reply);
+ bail1:
+ kfree(wr);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+int c2_stag_dealloc(struct c2_dev *c2dev, u32 stag_index)
+{
+ struct c2_vq_req *vq_req; /* verbs request object */
+ struct c2wr_stag_dealloc_req wr; /* work request */
+ struct c2wr_stag_dealloc_rep *reply; /* WR reply */
+ int err;
+
+
+ /*
+ * allocate verbs request object
+ */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req) {
+ return -ENOMEM;
+ }
+
+ /*
+ * Build the WR
+ */
+ c2_wr_set_id(&wr, CCWR_STAG_DEALLOC);
+ wr.hdr.context = (u64) (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.stag_index = cpu_to_be32(stag_index);
+
+ /*
+ * reference the request struct. dereferenced in the int handler.
+ */
+ vq_req_get(c2dev, vq_req);
+
+ /*
+ * Send WR to adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ /*
+ * Wait for reply from adapter
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail0;
+ }
+
+ /*
+ * Process reply
+ */
+ reply = (struct c2wr_stag_dealloc_rep *) (unsigned long) vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ err = c2_errno(reply);
+
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_mq.c b/drivers/infiniband/hw/amso1100/c2_mq.c
new file mode 100644
index 00000000000..b88a7559210
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_mq.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "c2.h"
+#include "c2_mq.h"
+
+void *c2_mq_alloc(struct c2_mq *q)
+{
+ BUG_ON(q->magic != C2_MQ_MAGIC);
+ BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
+
+ if (c2_mq_full(q)) {
+ return NULL;
+ } else {
+#ifdef DEBUG
+ struct c2wr_hdr *m =
+ (struct c2wr_hdr *) (q->msg_pool.host + q->priv * q->msg_size);
+#ifdef CCMSGMAGIC
+ BUG_ON(m->magic != be32_to_cpu(~CCWR_MAGIC));
+ m->magic = cpu_to_be32(CCWR_MAGIC);
+#endif
+ return m;
+#else
+ return q->msg_pool.host + q->priv * q->msg_size;
+#endif
+ }
+}
+
+void c2_mq_produce(struct c2_mq *q)
+{
+ BUG_ON(q->magic != C2_MQ_MAGIC);
+ BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
+
+ if (!c2_mq_full(q)) {
+ q->priv = (q->priv + 1) % q->q_size;
+ q->hint_count++;
+ /* Update peer's offset. */
+ __raw_writew(cpu_to_be16(q->priv), &q->peer->shared);
+ }
+}
+
+void *c2_mq_consume(struct c2_mq *q)
+{
+ BUG_ON(q->magic != C2_MQ_MAGIC);
+ BUG_ON(q->type != C2_MQ_HOST_TARGET);
+
+ if (c2_mq_empty(q)) {
+ return NULL;
+ } else {
+#ifdef DEBUG
+ struct c2wr_hdr *m = (struct c2wr_hdr *)
+ (q->msg_pool.host + q->priv * q->msg_size);
+#ifdef CCMSGMAGIC
+ BUG_ON(m->magic != be32_to_cpu(CCWR_MAGIC));
+#endif
+ return m;
+#else
+ return q->msg_pool.host + q->priv * q->msg_size;
+#endif
+ }
+}
+
+void c2_mq_free(struct c2_mq *q)
+{
+ BUG_ON(q->magic != C2_MQ_MAGIC);
+ BUG_ON(q->type != C2_MQ_HOST_TARGET);
+
+ if (!c2_mq_empty(q)) {
+
+#ifdef CCMSGMAGIC
+ {
+ struct c2wr_hdr __iomem *m = (struct c2wr_hdr __iomem *)
+ (q->msg_pool.adapter + q->priv * q->msg_size);
+ __raw_writel(cpu_to_be32(~CCWR_MAGIC), &m->magic);
+ }
+#endif
+ q->priv = (q->priv + 1) % q->q_size;
+ /* Update peer's offset. */
+ __raw_writew(cpu_to_be16(q->priv), &q->peer->shared);
+ }
+}
+
+
+void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count)
+{
+ BUG_ON(q->magic != C2_MQ_MAGIC);
+ BUG_ON(q->type != C2_MQ_ADAPTER_TARGET);
+
+ while (wqe_count--) {
+ BUG_ON(c2_mq_empty(q));
+ *q->shared = cpu_to_be16((be16_to_cpu(*q->shared)+1) % q->q_size);
+ }
+}
+
+#if 0
+u32 c2_mq_count(struct c2_mq *q)
+{
+ s32 count;
+
+ if (q->type == C2_MQ_HOST_TARGET)
+ count = be16_to_cpu(*q->shared) - q->priv;
+ else
+ count = q->priv - be16_to_cpu(*q->shared);
+
+ if (count < 0)
+ count += q->q_size;
+
+ return (u32) count;
+}
+#endif /* 0 */
+
+void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+ u8 __iomem *pool_start, u16 __iomem *peer, u32 type)
+{
+ BUG_ON(!q->shared);
+
+ /* This code assumes the byte swapping has already been done! */
+ q->index = index;
+ q->q_size = q_size;
+ q->msg_size = msg_size;
+ q->msg_pool.adapter = pool_start;
+ q->peer = (struct c2_mq_shared __iomem *) peer;
+ q->magic = C2_MQ_MAGIC;
+ q->type = type;
+ q->priv = 0;
+ q->hint_count = 0;
+ return;
+}
+void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+ u8 *pool_start, u16 __iomem *peer, u32 type)
+{
+ BUG_ON(!q->shared);
+
+ /* This code assumes the byte swapping has already been done! */
+ q->index = index;
+ q->q_size = q_size;
+ q->msg_size = msg_size;
+ q->msg_pool.host = pool_start;
+ q->peer = (struct c2_mq_shared __iomem *) peer;
+ q->magic = C2_MQ_MAGIC;
+ q->type = type;
+ q->priv = 0;
+ q->hint_count = 0;
+ return;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_mq.h b/drivers/infiniband/hw/amso1100/c2_mq.h
new file mode 100644
index 00000000000..9185bbb2165
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_mq.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _C2_MQ_H_
+#define _C2_MQ_H_
+#include <linux/kernel.h>
+#include <linux/dma-mapping.h>
+#include "c2_wr.h"
+
+enum c2_shared_regs {
+
+ C2_SHARED_ARMED = 0x10,
+ C2_SHARED_NOTIFY = 0x18,
+ C2_SHARED_SHARED = 0x40,
+};
+
+struct c2_mq_shared {
+ u16 unused1;
+ u8 armed;
+ u8 notification_type;
+ u32 unused2;
+ u16 shared;
+ /* Pad to 64 bytes. */
+ u8 pad[64 - sizeof(u16) - 2 * sizeof(u8) - sizeof(u32) - sizeof(u16)];
+};
+
+enum c2_mq_type {
+ C2_MQ_HOST_TARGET = 1,
+ C2_MQ_ADAPTER_TARGET = 2,
+};
+
+/*
+ * c2_mq_t is for kernel-mode MQs like the VQs Cand the AEQ.
+ * c2_user_mq_t (which is the same format) is for user-mode MQs...
+ */
+#define C2_MQ_MAGIC 0x4d512020 /* 'MQ ' */
+struct c2_mq {
+ u32 magic;
+ union {
+ u8 *host;
+ u8 __iomem *adapter;
+ } msg_pool;
+ dma_addr_t host_dma;
+ DECLARE_PCI_UNMAP_ADDR(mapping);
+ u16 hint_count;
+ u16 priv;
+ struct c2_mq_shared __iomem *peer;
+ u16 *shared;
+ dma_addr_t shared_dma;
+ u32 q_size;
+ u32 msg_size;
+ u32 index;
+ enum c2_mq_type type;
+};
+
+static __inline__ int c2_mq_empty(struct c2_mq *q)
+{
+ return q->priv == be16_to_cpu(*q->shared);
+}
+
+static __inline__ int c2_mq_full(struct c2_mq *q)
+{
+ return q->priv == (be16_to_cpu(*q->shared) + q->q_size - 1) % q->q_size;
+}
+
+extern void c2_mq_lconsume(struct c2_mq *q, u32 wqe_count);
+extern void *c2_mq_alloc(struct c2_mq *q);
+extern void c2_mq_produce(struct c2_mq *q);
+extern void *c2_mq_consume(struct c2_mq *q);
+extern void c2_mq_free(struct c2_mq *q);
+extern void c2_mq_req_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+ u8 __iomem *pool_start, u16 __iomem *peer, u32 type);
+extern void c2_mq_rep_init(struct c2_mq *q, u32 index, u32 q_size, u32 msg_size,
+ u8 *pool_start, u16 __iomem *peer, u32 type);
+
+#endif /* _C2_MQ_H_ */
diff --git a/drivers/infiniband/hw/amso1100/c2_pd.c b/drivers/infiniband/hw/amso1100/c2_pd.c
new file mode 100644
index 00000000000..00c709926c8
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_pd.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+
+#include "c2.h"
+#include "c2_provider.h"
+
+int c2_pd_alloc(struct c2_dev *c2dev, int privileged, struct c2_pd *pd)
+{
+ u32 obj;
+ int ret = 0;
+
+ spin_lock(&c2dev->pd_table.lock);
+ obj = find_next_zero_bit(c2dev->pd_table.table, c2dev->pd_table.max,
+ c2dev->pd_table.last);
+ if (obj >= c2dev->pd_table.max)
+ obj = find_first_zero_bit(c2dev->pd_table.table,
+ c2dev->pd_table.max);
+ if (obj < c2dev->pd_table.max) {
+ pd->pd_id = obj;
+ __set_bit(obj, c2dev->pd_table.table);
+ c2dev->pd_table.last = obj+1;
+ if (c2dev->pd_table.last >= c2dev->pd_table.max)
+ c2dev->pd_table.last = 0;
+ } else
+ ret = -ENOMEM;
+ spin_unlock(&c2dev->pd_table.lock);
+ return ret;
+}
+
+void c2_pd_free(struct c2_dev *c2dev, struct c2_pd *pd)
+{
+ spin_lock(&c2dev->pd_table.lock);
+ __clear_bit(pd->pd_id, c2dev->pd_table.table);
+ spin_unlock(&c2dev->pd_table.lock);
+}
+
+int __devinit c2_init_pd_table(struct c2_dev *c2dev)
+{
+
+ c2dev->pd_table.last = 0;
+ c2dev->pd_table.max = c2dev->props.max_pd;
+ spin_lock_init(&c2dev->pd_table.lock);
+ c2dev->pd_table.table = kmalloc(BITS_TO_LONGS(c2dev->props.max_pd) *
+ sizeof(long), GFP_KERNEL);
+ if (!c2dev->pd_table.table)
+ return -ENOMEM;
+ bitmap_zero(c2dev->pd_table.table, c2dev->props.max_pd);
+ return 0;
+}
+
+void __devexit c2_cleanup_pd_table(struct c2_dev *c2dev)
+{
+ kfree(c2dev->pd_table.table);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
new file mode 100644
index 00000000000..da98d9f7142
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/if_arp.h>
+#include <linux/vmalloc.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+
+#include <rdma/ib_smi.h>
+#include <rdma/ib_user_verbs.h>
+#include "c2.h"
+#include "c2_provider.h"
+#include "c2_user.h"
+
+static int c2_query_device(struct ib_device *ibdev,
+ struct ib_device_attr *props)
+{
+ struct c2_dev *c2dev = to_c2dev(ibdev);
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ *props = c2dev->props;
+ return 0;
+}
+
+static int c2_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ props->max_mtu = IB_MTU_4096;
+ props->lid = 0;
+ props->lmc = 0;
+ props->sm_lid = 0;
+ props->sm_sl = 0;
+ props->state = IB_PORT_ACTIVE;
+ props->phys_state = 0;
+ props->port_cap_flags =
+ IB_PORT_CM_SUP |
+ IB_PORT_REINIT_SUP |
+ IB_PORT_VENDOR_CLASS_SUP | IB_PORT_BOOT_MGMT_SUP;
+ props->gid_tbl_len = 1;
+ props->pkey_tbl_len = 1;
+ props->qkey_viol_cntr = 0;
+ props->active_width = 1;
+ props->active_speed = 1;
+
+ return 0;
+}
+
+static int c2_modify_port(struct ib_device *ibdev,
+ u8 port, int port_modify_mask,
+ struct ib_port_modify *props)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return 0;
+}
+
+static int c2_query_pkey(struct ib_device *ibdev,
+ u8 port, u16 index, u16 * pkey)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ *pkey = 0;
+ return 0;
+}
+
+static int c2_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ struct c2_dev *c2dev = to_c2dev(ibdev);
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ memset(&(gid->raw[0]), 0, sizeof(gid->raw));
+ memcpy(&(gid->raw[0]), c2dev->pseudo_netdev->dev_addr, 6);
+
+ return 0;
+}
+
+/* Allocate the user context data structure. This keeps track
+ * of all objects associated with a particular user-mode client.
+ */
+static struct ib_ucontext *c2_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct c2_ucontext *context;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ context = kmalloc(sizeof(*context), GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ return &context->ibucontext;
+}
+
+static int c2_dealloc_ucontext(struct ib_ucontext *context)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ kfree(context);
+ return 0;
+}
+
+static int c2_mmap_uar(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return -ENOSYS;
+}
+
+static struct ib_pd *c2_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct c2_pd *pd;
+ int err;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ pd = kmalloc(sizeof(*pd), GFP_KERNEL);
+ if (!pd)
+ return ERR_PTR(-ENOMEM);
+
+ err = c2_pd_alloc(to_c2dev(ibdev), !context, pd);
+ if (err) {
+ kfree(pd);
+ return ERR_PTR(err);
+ }
+
+ if (context) {
+ if (ib_copy_to_udata(udata, &pd->pd_id, sizeof(__u32))) {
+ c2_pd_free(to_c2dev(ibdev), pd);
+ kfree(pd);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
+ return &pd->ibpd;
+}
+
+static int c2_dealloc_pd(struct ib_pd *pd)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ c2_pd_free(to_c2dev(pd->device), to_c2pd(pd));
+ kfree(pd);
+
+ return 0;
+}
+
+static struct ib_ah *c2_ah_create(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return ERR_PTR(-ENOSYS);
+}
+
+static int c2_ah_destroy(struct ib_ah *ah)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return -ENOSYS;
+}
+
+static void c2_add_ref(struct ib_qp *ibqp)
+{
+ struct c2_qp *qp;
+ BUG_ON(!ibqp);
+ qp = to_c2qp(ibqp);
+ atomic_inc(&qp->refcount);
+}
+
+static void c2_rem_ref(struct ib_qp *ibqp)
+{
+ struct c2_qp *qp;
+ BUG_ON(!ibqp);
+ qp = to_c2qp(ibqp);
+ if (atomic_dec_and_test(&qp->refcount))
+ wake_up(&qp->wait);
+}
+
+struct ib_qp *c2_get_qp(struct ib_device *device, int qpn)
+{
+ struct c2_dev* c2dev = to_c2dev(device);
+ struct c2_qp *qp;
+
+ qp = c2_find_qpn(c2dev, qpn);
+ pr_debug("%s Returning QP=%p for QPN=%d, device=%p, refcount=%d\n",
+ __FUNCTION__, qp, qpn, device,
+ (qp?atomic_read(&qp->refcount):0));
+
+ return (qp?&qp->ibqp:NULL);
+}
+
+static struct ib_qp *c2_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ struct c2_qp *qp;
+ int err;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ switch (init_attr->qp_type) {
+ case IB_QPT_RC:
+ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+ if (!qp) {
+ pr_debug("%s: Unable to allocate QP\n", __FUNCTION__);
+ return ERR_PTR(-ENOMEM);
+ }
+ spin_lock_init(&qp->lock);
+ if (pd->uobject) {
+ /* userspace specific */
+ }
+
+ err = c2_alloc_qp(to_c2dev(pd->device),
+ to_c2pd(pd), init_attr, qp);
+
+ if (err && pd->uobject) {
+ /* userspace specific */
+ }
+
+ break;
+ default:
+ pr_debug("%s: Invalid QP type: %d\n", __FUNCTION__,
+ init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ break;
+ }
+
+ if (err) {
+ kfree(qp);
+ return ERR_PTR(err);
+ }
+
+ return &qp->ibqp;
+}
+
+static int c2_destroy_qp(struct ib_qp *ib_qp)
+{
+ struct c2_qp *qp = to_c2qp(ib_qp);
+
+ pr_debug("%s:%u qp=%p,qp->state=%d\n",
+ __FUNCTION__, __LINE__,ib_qp,qp->state);
+ c2_free_qp(to_c2dev(ib_qp->device), qp);
+ kfree(qp);
+ return 0;
+}
+
+static struct ib_cq *c2_create_cq(struct ib_device *ibdev, int entries,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ struct c2_cq *cq;
+ int err;
+
+ cq = kmalloc(sizeof(*cq), GFP_KERNEL);
+ if (!cq) {
+ pr_debug("%s: Unable to allocate CQ\n", __FUNCTION__);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ err = c2_init_cq(to_c2dev(ibdev), entries, NULL, cq);
+ if (err) {
+ pr_debug("%s: error initializing CQ\n", __FUNCTION__);
+ kfree(cq);
+ return ERR_PTR(err);
+ }
+
+ return &cq->ibcq;
+}
+
+static int c2_destroy_cq(struct ib_cq *ib_cq)
+{
+ struct c2_cq *cq = to_c2cq(ib_cq);
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ c2_free_cq(to_c2dev(ib_cq->device), cq);
+ kfree(cq);
+
+ return 0;
+}
+
+static inline u32 c2_convert_access(int acc)
+{
+ return (acc & IB_ACCESS_REMOTE_WRITE ? C2_ACF_REMOTE_WRITE : 0) |
+ (acc & IB_ACCESS_REMOTE_READ ? C2_ACF_REMOTE_READ : 0) |
+ (acc & IB_ACCESS_LOCAL_WRITE ? C2_ACF_LOCAL_WRITE : 0) |
+ C2_ACF_LOCAL_READ | C2_ACF_WINDOW_BIND;
+}
+
+static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
+ struct ib_phys_buf *buffer_list,
+ int num_phys_buf, int acc, u64 * iova_start)
+{
+ struct c2_mr *mr;
+ u64 *page_list;
+ u32 total_len;
+ int err, i, j, k, page_shift, pbl_depth;
+
+ pbl_depth = 0;
+ total_len = 0;
+
+ page_shift = PAGE_SHIFT;
+ /*
+ * If there is only 1 buffer we assume this could
+ * be a map of all phy mem...use a 32k page_shift.
+ */
+ if (num_phys_buf == 1)
+ page_shift += 3;
+
+ for (i = 0; i < num_phys_buf; i++) {
+
+ if (buffer_list[i].addr & ~PAGE_MASK) {
+ pr_debug("Unaligned Memory Buffer: 0x%x\n",
+ (unsigned int) buffer_list[i].addr);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!buffer_list[i].size) {
+ pr_debug("Invalid Buffer Size\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ total_len += buffer_list[i].size;
+ pbl_depth += ALIGN(buffer_list[i].size,
+ (1 << page_shift)) >> page_shift;
+ }
+
+ page_list = vmalloc(sizeof(u64) * pbl_depth);
+ if (!page_list) {
+ pr_debug("couldn't vmalloc page_list of size %zd\n",
+ (sizeof(u64) * pbl_depth));
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0, j = 0; i < num_phys_buf; i++) {
+
+ int naddrs;
+
+ naddrs = ALIGN(buffer_list[i].size,
+ (1 << page_shift)) >> page_shift;
+ for (k = 0; k < naddrs; k++)
+ page_list[j++] = (buffer_list[i].addr +
+ (k << page_shift));
+ }
+
+ mr = kmalloc(sizeof(*mr), GFP_KERNEL);
+ if (!mr) {
+ vfree(page_list);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ mr->pd = to_c2pd(ib_pd);
+ pr_debug("%s - page shift %d, pbl_depth %d, total_len %u, "
+ "*iova_start %llx, first pa %llx, last pa %llx\n",
+ __FUNCTION__, page_shift, pbl_depth, total_len,
+ (unsigned long long) *iova_start,
+ (unsigned long long) page_list[0],
+ (unsigned long long) page_list[pbl_depth-1]);
+ err = c2_nsmr_register_phys_kern(to_c2dev(ib_pd->device), page_list,
+ (1 << page_shift), pbl_depth,
+ total_len, 0, iova_start,
+ c2_convert_access(acc), mr);
+ vfree(page_list);
+ if (err) {
+ kfree(mr);
+ return ERR_PTR(err);
+ }
+
+ return &mr->ibmr;
+}
+
+static struct ib_mr *c2_get_dma_mr(struct ib_pd *pd, int acc)
+{
+ struct ib_phys_buf bl;
+ u64 kva = 0;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ /* AMSO1100 limit */
+ bl.size = 0xffffffff;
+ bl.addr = 0;
+ return c2_reg_phys_mr(pd, &bl, 1, acc, &kva);
+}
+
+static struct ib_mr *c2_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+ int acc, struct ib_udata *udata)
+{
+ u64 *pages;
+ u64 kva = 0;
+ int shift, n, len;
+ int i, j, k;
+ int err = 0;
+ struct ib_umem_chunk *chunk;
+ struct c2_pd *c2pd = to_c2pd(pd);
+ struct c2_mr *c2mr;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ shift = ffs(region->page_size) - 1;
+
+ c2mr = kmalloc(sizeof(*c2mr), GFP_KERNEL);
+ if (!c2mr)
+ return ERR_PTR(-ENOMEM);
+ c2mr->pd = c2pd;
+
+ n = 0;
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ n += chunk->nents;
+
+ pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
+ if (!pages) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ i = 0;
+ list_for_each_entry(chunk, &region->chunk_list, list) {
+ for (j = 0; j < chunk->nmap; ++j) {
+ len = sg_dma_len(&chunk->page_list[j]) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] =
+ sg_dma_address(&chunk->page_list[j]) +
+ (region->page_size * k);
+ }
+ }
+ }
+
+ kva = (u64)region->virt_base;
+ err = c2_nsmr_register_phys_kern(to_c2dev(pd->device),
+ pages,
+ region->page_size,
+ i,
+ region->length,
+ region->offset,
+ &kva,
+ c2_convert_access(acc),
+ c2mr);
+ kfree(pages);
+ if (err) {
+ kfree(c2mr);
+ return ERR_PTR(err);
+ }
+ return &c2mr->ibmr;
+
+err:
+ kfree(c2mr);
+ return ERR_PTR(err);
+}
+
+static int c2_dereg_mr(struct ib_mr *ib_mr)
+{
+ struct c2_mr *mr = to_c2mr(ib_mr);
+ int err;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ err = c2_stag_dealloc(to_c2dev(ib_mr->device), ib_mr->lkey);
+ if (err)
+ pr_debug("c2_stag_dealloc failed: %d\n", err);
+ else
+ kfree(mr);
+
+ return err;
+}
+
+static ssize_t show_rev(struct class_device *cdev, char *buf)
+{
+ struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev);
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return sprintf(buf, "%x\n", dev->props.hw_ver);
+}
+
+static ssize_t show_fw_ver(struct class_device *cdev, char *buf)
+{
+ struct c2_dev *dev = container_of(cdev, struct c2_dev, ibdev.class_dev);
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return sprintf(buf, "%x.%x.%x\n",
+ (int) (dev->props.fw_ver >> 32),
+ (int) (dev->props.fw_ver >> 16) & 0xffff,
+ (int) (dev->props.fw_ver & 0xffff));
+}
+
+static ssize_t show_hca(struct class_device *cdev, char *buf)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return sprintf(buf, "AMSO1100\n");
+}
+
+static ssize_t show_board(struct class_device *cdev, char *buf)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return sprintf(buf, "%.*s\n", 32, "AMSO1100 Board ID");
+}
+
+static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL);
+static CLASS_DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
+static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL);
+static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL);
+
+static struct class_device_attribute *c2_class_attributes[] = {
+ &class_device_attr_hw_rev,
+ &class_device_attr_fw_ver,
+ &class_device_attr_hca_type,
+ &class_device_attr_board_id
+};
+
+static int c2_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_udata *udata)
+{
+ int err;
+
+ err =
+ c2_qp_modify(to_c2dev(ibqp->device), to_c2qp(ibqp), attr,
+ attr_mask);
+
+ return err;
+}
+
+static int c2_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return -ENOSYS;
+}
+
+static int c2_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return -ENOSYS;
+}
+
+static int c2_process_mad(struct ib_device *ibdev,
+ int mad_flags,
+ u8 port_num,
+ struct ib_wc *in_wc,
+ struct ib_grh *in_grh,
+ struct ib_mad *in_mad, struct ib_mad *out_mad)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return -ENOSYS;
+}
+
+static int c2_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ /* Request a connection */
+ return c2_llp_connect(cm_id, iw_param);
+}
+
+static int c2_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ /* Accept the new connection */
+ return c2_llp_accept(cm_id, iw_param);
+}
+
+static int c2_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)
+{
+ int err;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ err = c2_llp_reject(cm_id, pdata, pdata_len);
+ return err;
+}
+
+static int c2_service_create(struct iw_cm_id *cm_id, int backlog)
+{
+ int err;
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ err = c2_llp_service_create(cm_id, backlog);
+ pr_debug("%s:%u err=%d\n",
+ __FUNCTION__, __LINE__,
+ err);
+ return err;
+}
+
+static int c2_service_destroy(struct iw_cm_id *cm_id)
+{
+ int err;
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+
+ err = c2_llp_service_destroy(cm_id);
+
+ return err;
+}
+
+static int c2_pseudo_up(struct net_device *netdev)
+{
+ struct in_device *ind;
+ struct c2_dev *c2dev = netdev->priv;
+
+ ind = in_dev_get(netdev);
+ if (!ind)
+ return 0;
+
+ pr_debug("adding...\n");
+ for_ifa(ind) {
+#ifdef DEBUG
+ u8 *ip = (u8 *) & ifa->ifa_address;
+
+ pr_debug("%s: %d.%d.%d.%d\n",
+ ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
+#endif
+ c2_add_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
+ }
+ endfor_ifa(ind);
+ in_dev_put(ind);
+
+ return 0;
+}
+
+static int c2_pseudo_down(struct net_device *netdev)
+{
+ struct in_device *ind;
+ struct c2_dev *c2dev = netdev->priv;
+
+ ind = in_dev_get(netdev);
+ if (!ind)
+ return 0;
+
+ pr_debug("deleting...\n");
+ for_ifa(ind) {
+#ifdef DEBUG
+ u8 *ip = (u8 *) & ifa->ifa_address;
+
+ pr_debug("%s: %d.%d.%d.%d\n",
+ ifa->ifa_label, ip[0], ip[1], ip[2], ip[3]);
+#endif
+ c2_del_addr(c2dev, ifa->ifa_address, ifa->ifa_mask);
+ }
+ endfor_ifa(ind);
+ in_dev_put(ind);
+
+ return 0;
+}
+
+static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ int ret = 0;
+
+ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+ return -EINVAL;
+
+ netdev->mtu = new_mtu;
+
+ /* TODO: Tell rnic about new rmda interface mtu */
+ return ret;
+}
+
+static void setup(struct net_device *netdev)
+{
+ SET_MODULE_OWNER(netdev);
+ netdev->open = c2_pseudo_up;
+ netdev->stop = c2_pseudo_down;
+ netdev->hard_start_xmit = c2_pseudo_xmit_frame;
+ netdev->get_stats = NULL;
+ netdev->tx_timeout = NULL;
+ netdev->set_mac_address = NULL;
+ netdev->change_mtu = c2_pseudo_change_mtu;
+ netdev->watchdog_timeo = 0;
+ netdev->type = ARPHRD_ETHER;
+ netdev->mtu = 1500;
+ netdev->hard_header_len = ETH_HLEN;
+ netdev->addr_len = ETH_ALEN;
+ netdev->tx_queue_len = 0;
+ netdev->flags |= IFF_NOARP;
+ return;
+}
+
+static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev)
+{
+ char name[IFNAMSIZ];
+ struct net_device *netdev;
+
+ /* change ethxxx to iwxxx */
+ strcpy(name, "iw");
+ strcat(name, &c2dev->netdev->name[3]);
+ netdev = alloc_netdev(sizeof(*netdev), name, setup);
+ if (!netdev) {
+ printk(KERN_ERR PFX "%s - etherdev alloc failed",
+ __FUNCTION__);
+ return NULL;
+ }
+
+ netdev->priv = c2dev;
+
+ SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
+
+ memcpy_fromio(netdev->dev_addr, c2dev->kva + C2_REGS_RDMA_ENADDR, 6);
+
+ /* Print out the MAC address */
+ pr_debug("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X\n",
+ netdev->name,
+ netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
+ netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
+
+#if 0
+ /* Disable network packets */
+ netif_stop_queue(netdev);
+#endif
+ return netdev;
+}
+
+int c2_register_device(struct c2_dev *dev)
+{
+ int ret;
+ int i;
+
+ /* Register pseudo network device */
+ dev->pseudo_netdev = c2_pseudo_netdev_init(dev);
+ if (dev->pseudo_netdev) {
+ ret = register_netdev(dev->pseudo_netdev);
+ if (ret) {
+ printk(KERN_ERR PFX
+ "Unable to register netdev, ret = %d\n", ret);
+ free_netdev(dev->pseudo_netdev);
+ return ret;
+ }
+ }
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ strlcpy(dev->ibdev.name, "amso%d", IB_DEVICE_NAME_MAX);
+ dev->ibdev.owner = THIS_MODULE;
+ dev->ibdev.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POST_SEND) |
+ (1ull << IB_USER_VERBS_CMD_POST_RECV);
+
+ dev->ibdev.node_type = RDMA_NODE_RNIC;
+ memset(&dev->ibdev.node_guid, 0, sizeof(dev->ibdev.node_guid));
+ memcpy(&dev->ibdev.node_guid, dev->pseudo_netdev->dev_addr, 6);
+ dev->ibdev.phys_port_cnt = 1;
+ dev->ibdev.dma_device = &dev->pcidev->dev;
+ dev->ibdev.class_dev.dev = &dev->pcidev->dev;
+ dev->ibdev.query_device = c2_query_device;
+ dev->ibdev.query_port = c2_query_port;
+ dev->ibdev.modify_port = c2_modify_port;
+ dev->ibdev.query_pkey = c2_query_pkey;
+ dev->ibdev.query_gid = c2_query_gid;
+ dev->ibdev.alloc_ucontext = c2_alloc_ucontext;
+ dev->ibdev.dealloc_ucontext = c2_dealloc_ucontext;
+ dev->ibdev.mmap = c2_mmap_uar;
+ dev->ibdev.alloc_pd = c2_alloc_pd;
+ dev->ibdev.dealloc_pd = c2_dealloc_pd;
+ dev->ibdev.create_ah = c2_ah_create;
+ dev->ibdev.destroy_ah = c2_ah_destroy;
+ dev->ibdev.create_qp = c2_create_qp;
+ dev->ibdev.modify_qp = c2_modify_qp;
+ dev->ibdev.destroy_qp = c2_destroy_qp;
+ dev->ibdev.create_cq = c2_create_cq;
+ dev->ibdev.destroy_cq = c2_destroy_cq;
+ dev->ibdev.poll_cq = c2_poll_cq;
+ dev->ibdev.get_dma_mr = c2_get_dma_mr;
+ dev->ibdev.reg_phys_mr = c2_reg_phys_mr;
+ dev->ibdev.reg_user_mr = c2_reg_user_mr;
+ dev->ibdev.dereg_mr = c2_dereg_mr;
+
+ dev->ibdev.alloc_fmr = NULL;
+ dev->ibdev.unmap_fmr = NULL;
+ dev->ibdev.dealloc_fmr = NULL;
+ dev->ibdev.map_phys_fmr = NULL;
+
+ dev->ibdev.attach_mcast = c2_multicast_attach;
+ dev->ibdev.detach_mcast = c2_multicast_detach;
+ dev->ibdev.process_mad = c2_process_mad;
+
+ dev->ibdev.req_notify_cq = c2_arm_cq;
+ dev->ibdev.post_send = c2_post_send;
+ dev->ibdev.post_recv = c2_post_receive;
+
+ dev->ibdev.iwcm = kmalloc(sizeof(*dev->ibdev.iwcm), GFP_KERNEL);
+ dev->ibdev.iwcm->add_ref = c2_add_ref;
+ dev->ibdev.iwcm->rem_ref = c2_rem_ref;
+ dev->ibdev.iwcm->get_qp = c2_get_qp;
+ dev->ibdev.iwcm->connect = c2_connect;
+ dev->ibdev.iwcm->accept = c2_accept;
+ dev->ibdev.iwcm->reject = c2_reject;
+ dev->ibdev.iwcm->create_listen = c2_service_create;
+ dev->ibdev.iwcm->destroy_listen = c2_service_destroy;
+
+ ret = ib_register_device(&dev->ibdev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(c2_class_attributes); ++i) {
+ ret = class_device_create_file(&dev->ibdev.class_dev,
+ c2_class_attributes[i]);
+ if (ret) {
+ unregister_netdev(dev->pseudo_netdev);
+ free_netdev(dev->pseudo_netdev);
+ ib_unregister_device(&dev->ibdev);
+ return ret;
+ }
+ }
+
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ return 0;
+}
+
+void c2_unregister_device(struct c2_dev *dev)
+{
+ pr_debug("%s:%u\n", __FUNCTION__, __LINE__);
+ unregister_netdev(dev->pseudo_netdev);
+ free_netdev(dev->pseudo_netdev);
+ ib_unregister_device(&dev->ibdev);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.h b/drivers/infiniband/hw/amso1100/c2_provider.h
new file mode 100644
index 00000000000..fc906223220
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_provider.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef C2_PROVIDER_H
+#define C2_PROVIDER_H
+#include <linux/inetdevice.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_pack.h>
+
+#include "c2_mq.h"
+#include <rdma/iw_cm.h>
+
+#define C2_MPT_FLAG_ATOMIC (1 << 14)
+#define C2_MPT_FLAG_REMOTE_WRITE (1 << 13)
+#define C2_MPT_FLAG_REMOTE_READ (1 << 12)
+#define C2_MPT_FLAG_LOCAL_WRITE (1 << 11)
+#define C2_MPT_FLAG_LOCAL_READ (1 << 10)
+
+struct c2_buf_list {
+ void *buf;
+ DECLARE_PCI_UNMAP_ADDR(mapping)
+};
+
+
+/* The user context keeps track of objects allocated for a
+ * particular user-mode client. */
+struct c2_ucontext {
+ struct ib_ucontext ibucontext;
+};
+
+struct c2_mtt;
+
+/* All objects associated with a PD are kept in the
+ * associated user context if present.
+ */
+struct c2_pd {
+ struct ib_pd ibpd;
+ u32 pd_id;
+};
+
+struct c2_mr {
+ struct ib_mr ibmr;
+ struct c2_pd *pd;
+};
+
+struct c2_av;
+
+enum c2_ah_type {
+ C2_AH_ON_HCA,
+ C2_AH_PCI_POOL,
+ C2_AH_KMALLOC
+};
+
+struct c2_ah {
+ struct ib_ah ibah;
+};
+
+struct c2_cq {
+ struct ib_cq ibcq;
+ spinlock_t lock;
+ atomic_t refcount;
+ int cqn;
+ int is_kernel;
+ wait_queue_head_t wait;
+
+ u32 adapter_handle;
+ struct c2_mq mq;
+};
+
+struct c2_wq {
+ spinlock_t lock;
+};
+struct iw_cm_id;
+struct c2_qp {
+ struct ib_qp ibqp;
+ struct iw_cm_id *cm_id;
+ spinlock_t lock;
+ atomic_t refcount;
+ wait_queue_head_t wait;
+ int qpn;
+
+ u32 adapter_handle;
+ u32 send_sgl_depth;
+ u32 recv_sgl_depth;
+ u32 rdma_write_sgl_depth;
+ u8 state;
+
+ struct c2_mq sq_mq;
+ struct c2_mq rq_mq;
+};
+
+struct c2_cr_query_attrs {
+ u32 local_addr;
+ u32 remote_addr;
+ u16 local_port;
+ u16 remote_port;
+};
+
+static inline struct c2_pd *to_c2pd(struct ib_pd *ibpd)
+{
+ return container_of(ibpd, struct c2_pd, ibpd);
+}
+
+static inline struct c2_ucontext *to_c2ucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct c2_ucontext, ibucontext);
+}
+
+static inline struct c2_mr *to_c2mr(struct ib_mr *ibmr)
+{
+ return container_of(ibmr, struct c2_mr, ibmr);
+}
+
+
+static inline struct c2_ah *to_c2ah(struct ib_ah *ibah)
+{
+ return container_of(ibah, struct c2_ah, ibah);
+}
+
+static inline struct c2_cq *to_c2cq(struct ib_cq *ibcq)
+{
+ return container_of(ibcq, struct c2_cq, ibcq);
+}
+
+static inline struct c2_qp *to_c2qp(struct ib_qp *ibqp)
+{
+ return container_of(ibqp, struct c2_qp, ibqp);
+}
+
+static inline int is_rnic_addr(struct net_device *netdev, u32 addr)
+{
+ struct in_device *ind;
+ int ret = 0;
+
+ ind = in_dev_get(netdev);
+ if (!ind)
+ return 0;
+
+ for_ifa(ind) {
+ if (ifa->ifa_address == addr) {
+ ret = 1;
+ break;
+ }
+ }
+ endfor_ifa(ind);
+ in_dev_put(ind);
+ return ret;
+}
+#endif /* C2_PROVIDER_H */
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
new file mode 100644
index 00000000000..12261132b07
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 2004 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include "c2.h"
+#include "c2_vq.h"
+#include "c2_status.h"
+
+#define C2_MAX_ORD_PER_QP 128
+#define C2_MAX_IRD_PER_QP 128
+
+#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
+#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
+#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
+
+#define NO_SUPPORT -1
+static const u8 c2_opcode[] = {
+ [IB_WR_SEND] = C2_WR_TYPE_SEND,
+ [IB_WR_SEND_WITH_IMM] = NO_SUPPORT,
+ [IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE,
+ [IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT,
+ [IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ,
+ [IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT,
+ [IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT,
+};
+
+static int to_c2_state(enum ib_qp_state ib_state)
+{
+ switch (ib_state) {
+ case IB_QPS_RESET:
+ return C2_QP_STATE_IDLE;
+ case IB_QPS_RTS:
+ return C2_QP_STATE_RTS;
+ case IB_QPS_SQD:
+ return C2_QP_STATE_CLOSING;
+ case IB_QPS_SQE:
+ return C2_QP_STATE_CLOSING;
+ case IB_QPS_ERR:
+ return C2_QP_STATE_ERROR;
+ default:
+ return -1;
+ }
+}
+
+static int to_ib_state(enum c2_qp_state c2_state)
+{
+ switch (c2_state) {
+ case C2_QP_STATE_IDLE:
+ return IB_QPS_RESET;
+ case C2_QP_STATE_CONNECTING:
+ return IB_QPS_RTR;
+ case C2_QP_STATE_RTS:
+ return IB_QPS_RTS;
+ case C2_QP_STATE_CLOSING:
+ return IB_QPS_SQD;
+ case C2_QP_STATE_ERROR:
+ return IB_QPS_ERR;
+ case C2_QP_STATE_TERMINATE:
+ return IB_QPS_SQE;
+ default:
+ return -1;
+ }
+}
+
+static const char *to_ib_state_str(int ib_state)
+{
+ static const char *state_str[] = {
+ "IB_QPS_RESET",
+ "IB_QPS_INIT",
+ "IB_QPS_RTR",
+ "IB_QPS_RTS",
+ "IB_QPS_SQD",
+ "IB_QPS_SQE",
+ "IB_QPS_ERR"
+ };
+ if (ib_state < IB_QPS_RESET ||
+ ib_state > IB_QPS_ERR)
+ return "<invalid IB QP state>";
+
+ ib_state -= IB_QPS_RESET;
+ return state_str[ib_state];
+}
+
+void c2_set_qp_state(struct c2_qp *qp, int c2_state)
+{
+ int new_state = to_ib_state(c2_state);
+
+ pr_debug("%s: qp[%p] state modify %s --> %s\n",
+ __FUNCTION__,
+ qp,
+ to_ib_state_str(qp->state),
+ to_ib_state_str(new_state));
+ qp->state = new_state;
+}
+
+#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
+
+int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
+ struct ib_qp_attr *attr, int attr_mask)
+{
+ struct c2wr_qp_modify_req wr;
+ struct c2wr_qp_modify_rep *reply;
+ struct c2_vq_req *vq_req;
+ unsigned long flags;
+ u8 next_state;
+ int err;
+
+ pr_debug("%s:%d qp=%p, %s --> %s\n",
+ __FUNCTION__, __LINE__,
+ qp,
+ to_ib_state_str(qp->state),
+ to_ib_state_str(attr->qp_state));
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ c2_wr_set_id(&wr, CCWR_QP_MODIFY);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.qp_handle = qp->adapter_handle;
+ wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+ wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+ wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+ wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+
+ if (attr_mask & IB_QP_STATE) {
+ /* Ensure the state is valid */
+ if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR)
+ return -EINVAL;
+
+ wr.next_qp_state = cpu_to_be32(to_c2_state(attr->qp_state));
+
+ if (attr->qp_state == IB_QPS_ERR) {
+ spin_lock_irqsave(&qp->lock, flags);
+ if (qp->cm_id && qp->state == IB_QPS_RTS) {
+ pr_debug("Generating CLOSE event for QP-->ERR, "
+ "qp=%p, cm_id=%p\n",qp,qp->cm_id);
+ /* Generate an CLOSE event */
+ vq_req->cm_id = qp->cm_id;
+ vq_req->event = IW_CM_EVENT_CLOSE;
+ }
+ spin_unlock_irqrestore(&qp->lock, flags);
+ }
+ next_state = attr->qp_state;
+
+ } else if (attr_mask & IB_QP_CUR_STATE) {
+
+ if (attr->cur_qp_state != IB_QPS_RTR &&
+ attr->cur_qp_state != IB_QPS_RTS &&
+ attr->cur_qp_state != IB_QPS_SQD &&
+ attr->cur_qp_state != IB_QPS_SQE)
+ return -EINVAL;
+ else
+ wr.next_qp_state =
+ cpu_to_be32(to_c2_state(attr->cur_qp_state));
+
+ next_state = attr->cur_qp_state;
+
+ } else {
+ err = 0;
+ goto bail0;
+ }
+
+ /* reference the request struct */
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail0;
+
+ reply = (struct c2wr_qp_modify_rep *) (unsigned long) vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ err = c2_errno(reply);
+ if (!err)
+ qp->state = next_state;
+#ifdef DEBUG
+ else
+ pr_debug("%s: c2_errno=%d\n", __FUNCTION__, err);
+#endif
+ /*
+ * If we're going to error and generating the event here, then
+ * we need to remove the reference because there will be no
+ * close event generated by the adapter
+ */
+ spin_lock_irqsave(&qp->lock, flags);
+ if (vq_req->event==IW_CM_EVENT_CLOSE && qp->cm_id) {
+ qp->cm_id->rem_ref(qp->cm_id);
+ qp->cm_id = NULL;
+ }
+ spin_unlock_irqrestore(&qp->lock, flags);
+
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+
+ pr_debug("%s:%d qp=%p, cur_state=%s\n",
+ __FUNCTION__, __LINE__,
+ qp,
+ to_ib_state_str(qp->state));
+ return err;
+}
+
+int c2_qp_set_read_limits(struct c2_dev *c2dev, struct c2_qp *qp,
+ int ord, int ird)
+{
+ struct c2wr_qp_modify_req wr;
+ struct c2wr_qp_modify_rep *reply;
+ struct c2_vq_req *vq_req;
+ int err;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ c2_wr_set_id(&wr, CCWR_QP_MODIFY);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.qp_handle = qp->adapter_handle;
+ wr.ord = cpu_to_be32(ord);
+ wr.ird = cpu_to_be32(ird);
+ wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+ wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+ wr.next_qp_state = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
+
+ /* reference the request struct */
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail0;
+
+ reply = (struct c2wr_qp_modify_rep *) (unsigned long)
+ vq_req->reply_msg;
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ err = c2_errno(reply);
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+static int destroy_qp(struct c2_dev *c2dev, struct c2_qp *qp)
+{
+ struct c2_vq_req *vq_req;
+ struct c2wr_qp_destroy_req wr;
+ struct c2wr_qp_destroy_rep *reply;
+ unsigned long flags;
+ int err;
+
+ /*
+ * Allocate a verb request message
+ */
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req) {
+ return -ENOMEM;
+ }
+
+ /*
+ * Initialize the WR
+ */
+ c2_wr_set_id(&wr, CCWR_QP_DESTROY);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.qp_handle = qp->adapter_handle;
+
+ /*
+ * reference the request struct. dereferenced in the int handler.
+ */
+ vq_req_get(c2dev, vq_req);
+
+ spin_lock_irqsave(&qp->lock, flags);
+ if (qp->cm_id && qp->state == IB_QPS_RTS) {
+ pr_debug("destroy_qp: generating CLOSE event for QP-->ERR, "
+ "qp=%p, cm_id=%p\n",qp,qp->cm_id);
+ /* Generate an CLOSE event */
+ vq_req->qp = qp;
+ vq_req->cm_id = qp->cm_id;
+ vq_req->event = IW_CM_EVENT_CLOSE;
+ }
+ spin_unlock_irqrestore(&qp->lock, flags);
+
+ /*
+ * Send WR to adapter
+ */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ /*
+ * Wait for reply from adapter
+ */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail0;
+ }
+
+ /*
+ * Process reply
+ */
+ reply = (struct c2wr_qp_destroy_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ spin_lock_irqsave(&qp->lock, flags);
+ if (qp->cm_id) {
+ qp->cm_id->rem_ref(qp->cm_id);
+ qp->cm_id = NULL;
+ }
+ spin_unlock_irqrestore(&qp->lock, flags);
+
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+static int c2_alloc_qpn(struct c2_dev *c2dev, struct c2_qp *qp)
+{
+ int ret;
+
+ do {
+ spin_lock_irq(&c2dev->qp_table.lock);
+ ret = idr_get_new_above(&c2dev->qp_table.idr, qp,
+ c2dev->qp_table.last++, &qp->qpn);
+ spin_unlock_irq(&c2dev->qp_table.lock);
+ } while ((ret == -EAGAIN) &&
+ idr_pre_get(&c2dev->qp_table.idr, GFP_KERNEL));
+ return ret;
+}
+
+static void c2_free_qpn(struct c2_dev *c2dev, int qpn)
+{
+ spin_lock_irq(&c2dev->qp_table.lock);
+ idr_remove(&c2dev->qp_table.idr, qpn);
+ spin_unlock_irq(&c2dev->qp_table.lock);
+}
+
+struct c2_qp *c2_find_qpn(struct c2_dev *c2dev, int qpn)
+{
+ unsigned long flags;
+ struct c2_qp *qp;
+
+ spin_lock_irqsave(&c2dev->qp_table.lock, flags);
+ qp = idr_find(&c2dev->qp_table.idr, qpn);
+ spin_unlock_irqrestore(&c2dev->qp_table.lock, flags);
+ return qp;
+}
+
+int c2_alloc_qp(struct c2_dev *c2dev,
+ struct c2_pd *pd,
+ struct ib_qp_init_attr *qp_attrs, struct c2_qp *qp)
+{
+ struct c2wr_qp_create_req wr;
+ struct c2wr_qp_create_rep *reply;
+ struct c2_vq_req *vq_req;
+ struct c2_cq *send_cq = to_c2cq(qp_attrs->send_cq);
+ struct c2_cq *recv_cq = to_c2cq(qp_attrs->recv_cq);
+ unsigned long peer_pa;
+ u32 q_size, msg_size, mmap_size;
+ void __iomem *mmap;
+ int err;
+
+ err = c2_alloc_qpn(c2dev, qp);
+ if (err)
+ return err;
+ qp->ibqp.qp_num = qp->qpn;
+ qp->ibqp.qp_type = IB_QPT_RC;
+
+ /* Allocate the SQ and RQ shared pointers */
+ qp->sq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &qp->sq_mq.shared_dma, GFP_KERNEL);
+ if (!qp->sq_mq.shared) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ qp->rq_mq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &qp->rq_mq.shared_dma, GFP_KERNEL);
+ if (!qp->rq_mq.shared) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ /* Allocate the verbs request */
+ vq_req = vq_req_alloc(c2dev);
+ if (vq_req == NULL) {
+ err = -ENOMEM;
+ goto bail2;
+ }
+
+ /* Initialize the work request */
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_QP_CREATE);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+ wr.sq_cq_handle = send_cq->adapter_handle;
+ wr.rq_cq_handle = recv_cq->adapter_handle;
+ wr.sq_depth = cpu_to_be32(qp_attrs->cap.max_send_wr + 1);
+ wr.rq_depth = cpu_to_be32(qp_attrs->cap.max_recv_wr + 1);
+ wr.srq_handle = 0;
+ wr.flags = cpu_to_be32(QP_RDMA_READ | QP_RDMA_WRITE | QP_MW_BIND |
+ QP_ZERO_STAG | QP_RDMA_READ_RESPONSE);
+ wr.send_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
+ wr.recv_sgl_depth = cpu_to_be32(qp_attrs->cap.max_recv_sge);
+ wr.rdma_write_sgl_depth = cpu_to_be32(qp_attrs->cap.max_send_sge);
+ wr.shared_sq_ht = cpu_to_be64(qp->sq_mq.shared_dma);
+ wr.shared_rq_ht = cpu_to_be64(qp->rq_mq.shared_dma);
+ wr.ord = cpu_to_be32(C2_MAX_ORD_PER_QP);
+ wr.ird = cpu_to_be32(C2_MAX_IRD_PER_QP);
+ wr.pd_id = pd->pd_id;
+ wr.user_context = (unsigned long) qp;
+
+ vq_req_get(c2dev, vq_req);
+
+ /* Send the WR to the adapter */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail3;
+ }
+
+ /* Wait for the verb reply */
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail3;
+ }
+
+ /* Process the reply */
+ reply = (struct c2wr_qp_create_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail3;
+ }
+
+ if ((err = c2_wr_get_result(reply)) != 0) {
+ goto bail4;
+ }
+
+ /* Fill in the kernel QP struct */
+ atomic_set(&qp->refcount, 1);
+ qp->adapter_handle = reply->qp_handle;
+ qp->state = IB_QPS_RESET;
+ qp->send_sgl_depth = qp_attrs->cap.max_send_sge;
+ qp->rdma_write_sgl_depth = qp_attrs->cap.max_send_sge;
+ qp->recv_sgl_depth = qp_attrs->cap.max_recv_sge;
+
+ /* Initialize the SQ MQ */
+ q_size = be32_to_cpu(reply->sq_depth);
+ msg_size = be32_to_cpu(reply->sq_msg_size);
+ peer_pa = c2dev->pa + be32_to_cpu(reply->sq_mq_start);
+ mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
+ mmap = ioremap_nocache(peer_pa, mmap_size);
+ if (!mmap) {
+ err = -ENOMEM;
+ goto bail5;
+ }
+
+ c2_mq_req_init(&qp->sq_mq,
+ be32_to_cpu(reply->sq_mq_index),
+ q_size,
+ msg_size,
+ mmap + sizeof(struct c2_mq_shared), /* pool start */
+ mmap, /* peer */
+ C2_MQ_ADAPTER_TARGET);
+
+ /* Initialize the RQ mq */
+ q_size = be32_to_cpu(reply->rq_depth);
+ msg_size = be32_to_cpu(reply->rq_msg_size);
+ peer_pa = c2dev->pa + be32_to_cpu(reply->rq_mq_start);
+ mmap_size = PAGE_ALIGN(sizeof(struct c2_mq_shared) + msg_size * q_size);
+ mmap = ioremap_nocache(peer_pa, mmap_size);
+ if (!mmap) {
+ err = -ENOMEM;
+ goto bail6;
+ }
+
+ c2_mq_req_init(&qp->rq_mq,
+ be32_to_cpu(reply->rq_mq_index),
+ q_size,
+ msg_size,
+ mmap + sizeof(struct c2_mq_shared), /* pool start */
+ mmap, /* peer */
+ C2_MQ_ADAPTER_TARGET);
+
+ vq_repbuf_free(c2dev, reply);
+ vq_req_free(c2dev, vq_req);
+
+ return 0;
+
+ bail6:
+ iounmap(qp->sq_mq.peer);
+ bail5:
+ destroy_qp(c2dev, qp);
+ bail4:
+ vq_repbuf_free(c2dev, reply);
+ bail3:
+ vq_req_free(c2dev, vq_req);
+ bail2:
+ c2_free_mqsp(qp->rq_mq.shared);
+ bail1:
+ c2_free_mqsp(qp->sq_mq.shared);
+ bail0:
+ c2_free_qpn(c2dev, qp->qpn);
+ return err;
+}
+
+void c2_free_qp(struct c2_dev *c2dev, struct c2_qp *qp)
+{
+ struct c2_cq *send_cq;
+ struct c2_cq *recv_cq;
+
+ send_cq = to_c2cq(qp->ibqp.send_cq);
+ recv_cq = to_c2cq(qp->ibqp.recv_cq);
+
+ /*
+ * Lock CQs here, so that CQ polling code can do QP lookup
+ * without taking a lock.
+ */
+ spin_lock_irq(&send_cq->lock);
+ if (send_cq != recv_cq)
+ spin_lock(&recv_cq->lock);
+
+ c2_free_qpn(c2dev, qp->qpn);
+
+ if (send_cq != recv_cq)
+ spin_unlock(&recv_cq->lock);
+ spin_unlock_irq(&send_cq->lock);
+
+ /*
+ * Destory qp in the rnic...
+ */
+ destroy_qp(c2dev, qp);
+
+ /*
+ * Mark any unreaped CQEs as null and void.
+ */
+ c2_cq_clean(c2dev, qp, send_cq->cqn);
+ if (send_cq != recv_cq)
+ c2_cq_clean(c2dev, qp, recv_cq->cqn);
+ /*
+ * Unmap the MQs and return the shared pointers
+ * to the message pool.
+ */
+ iounmap(qp->sq_mq.peer);
+ iounmap(qp->rq_mq.peer);
+ c2_free_mqsp(qp->sq_mq.shared);
+ c2_free_mqsp(qp->rq_mq.shared);
+
+ atomic_dec(&qp->refcount);
+ wait_event(qp->wait, !atomic_read(&qp->refcount));
+}
+
+/*
+ * Function: move_sgl
+ *
+ * Description:
+ * Move an SGL from the user's work request struct into a CCIL Work Request
+ * message, swapping to WR byte order and ensure the total length doesn't
+ * overflow.
+ *
+ * IN:
+ * dst - ptr to CCIL Work Request message SGL memory.
+ * src - ptr to the consumers SGL memory.
+ *
+ * OUT: none
+ *
+ * Return:
+ * CCIL status codes.
+ */
+static int
+move_sgl(struct c2_data_addr * dst, struct ib_sge *src, int count, u32 * p_len,
+ u8 * actual_count)
+{
+ u32 tot = 0; /* running total */
+ u8 acount = 0; /* running total non-0 len sge's */
+
+ while (count > 0) {
+ /*
+ * If the addition of this SGE causes the
+ * total SGL length to exceed 2^32-1, then
+ * fail-n-bail.
+ *
+ * If the current total plus the next element length
+ * wraps, then it will go negative and be less than the
+ * current total...
+ */
+ if ((tot + src->length) < tot) {
+ return -EINVAL;
+ }
+ /*
+ * Bug: 1456 (as well as 1498 & 1643)
+ * Skip over any sge's supplied with len=0
+ */
+ if (src->length) {
+ tot += src->length;
+ dst->stag = cpu_to_be32(src->lkey);
+ dst->to = cpu_to_be64(src->addr);
+ dst->length = cpu_to_be32(src->length);
+ dst++;
+ acount++;
+ }
+ src++;
+ count--;
+ }
+
+ if (acount == 0) {
+ /*
+ * Bug: 1476 (as well as 1498, 1456 and 1643)
+ * Setup the SGL in the WR to make it easier for the RNIC.
+ * This way, the FW doesn't have to deal with special cases.
+ * Setting length=0 should be sufficient.
+ */
+ dst->stag = 0;
+ dst->to = 0;
+ dst->length = 0;
+ }
+
+ *p_len = tot;
+ *actual_count = acount;
+ return 0;
+}
+
+/*
+ * Function: c2_activity (private function)
+ *
+ * Description:
+ * Post an mq index to the host->adapter activity fifo.
+ *
+ * IN:
+ * c2dev - ptr to c2dev structure
+ * mq_index - mq index to post
+ * shared - value most recently written to shared
+ *
+ * OUT:
+ *
+ * Return:
+ * none
+ */
+static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared)
+{
+ /*
+ * First read the register to see if the FIFO is full, and if so,
+ * spin until it's not. This isn't perfect -- there is no
+ * synchronization among the clients of the register, but in
+ * practice it prevents multiple CPU from hammering the bus
+ * with PCI RETRY. Note that when this does happen, the card
+ * cannot get on the bus and the card and system hang in a
+ * deadlock -- thus the need for this code. [TOT]
+ */
+ while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(0);
+ }
+
+ __raw_writel(C2_HINT_MAKE(mq_index, shared),
+ c2dev->regs + PCI_BAR0_ADAPTER_HINT);
+}
+
+/*
+ * Function: qp_wr_post
+ *
+ * Description:
+ * This in-line function allocates a MQ msg, then moves the host-copy of
+ * the completed WR into msg. Then it posts the message.
+ *
+ * IN:
+ * q - ptr to user MQ.
+ * wr - ptr to host-copy of the WR.
+ * qp - ptr to user qp
+ * size - Number of bytes to post. Assumed to be divisible by 4.
+ *
+ * OUT: none
+ *
+ * Return:
+ * CCIL status codes.
+ */
+static int qp_wr_post(struct c2_mq *q, union c2wr * wr, struct c2_qp *qp, u32 size)
+{
+ union c2wr *msg;
+
+ msg = c2_mq_alloc(q);
+ if (msg == NULL) {
+ return -EINVAL;
+ }
+#ifdef CCMSGMAGIC
+ ((c2wr_hdr_t *) wr)->magic = cpu_to_be32(CCWR_MAGIC);
+#endif
+
+ /*
+ * Since all header fields in the WR are the same as the
+ * CQE, set the following so the adapter need not.
+ */
+ c2_wr_set_result(wr, CCERR_PENDING);
+
+ /*
+ * Copy the wr down to the adapter
+ */
+ memcpy((void *) msg, (void *) wr, size);
+
+ c2_mq_produce(q);
+ return 0;
+}
+
+
+int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
+ struct ib_send_wr **bad_wr)
+{
+ struct c2_dev *c2dev = to_c2dev(ibqp->device);
+ struct c2_qp *qp = to_c2qp(ibqp);
+ union c2wr wr;
+ int err = 0;
+
+ u32 flags;
+ u32 tot_len;
+ u8 actual_sge_count;
+ u32 msg_size;
+
+ if (qp->state > IB_QPS_RTS)
+ return -EINVAL;
+
+ while (ib_wr) {
+
+ flags = 0;
+ wr.sqwr.sq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
+ if (ib_wr->send_flags & IB_SEND_SIGNALED) {
+ flags |= SQ_SIGNALED;
+ }
+
+ switch (ib_wr->opcode) {
+ case IB_WR_SEND:
+ if (ib_wr->send_flags & IB_SEND_SOLICITED) {
+ c2_wr_set_id(&wr, C2_WR_TYPE_SEND_SE);
+ msg_size = sizeof(struct c2wr_send_req);
+ } else {
+ c2_wr_set_id(&wr, C2_WR_TYPE_SEND);
+ msg_size = sizeof(struct c2wr_send_req);
+ }
+
+ wr.sqwr.send.remote_stag = 0;
+ msg_size += sizeof(struct c2_data_addr) * ib_wr->num_sge;
+ if (ib_wr->num_sge > qp->send_sgl_depth) {
+ err = -EINVAL;
+ break;
+ }
+ if (ib_wr->send_flags & IB_SEND_FENCE) {
+ flags |= SQ_READ_FENCE;
+ }
+ err = move_sgl((struct c2_data_addr *) & (wr.sqwr.send.data),
+ ib_wr->sg_list,
+ ib_wr->num_sge,
+ &tot_len, &actual_sge_count);
+ wr.sqwr.send.sge_len = cpu_to_be32(tot_len);
+ c2_wr_set_sge_count(&wr, actual_sge_count);
+ break;
+ case IB_WR_RDMA_WRITE:
+ c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_WRITE);
+ msg_size = sizeof(struct c2wr_rdma_write_req) +
+ (sizeof(struct c2_data_addr) * ib_wr->num_sge);
+ if (ib_wr->num_sge > qp->rdma_write_sgl_depth) {
+ err = -EINVAL;
+ break;
+ }
+ if (ib_wr->send_flags & IB_SEND_FENCE) {
+ flags |= SQ_READ_FENCE;
+ }
+ wr.sqwr.rdma_write.remote_stag =
+ cpu_to_be32(ib_wr->wr.rdma.rkey);
+ wr.sqwr.rdma_write.remote_to =
+ cpu_to_be64(ib_wr->wr.rdma.remote_addr);
+ err = move_sgl((struct c2_data_addr *)
+ & (wr.sqwr.rdma_write.data),
+ ib_wr->sg_list,
+ ib_wr->num_sge,
+ &tot_len, &actual_sge_count);
+ wr.sqwr.rdma_write.sge_len = cpu_to_be32(tot_len);
+ c2_wr_set_sge_count(&wr, actual_sge_count);
+ break;
+ case IB_WR_RDMA_READ:
+ c2_wr_set_id(&wr, C2_WR_TYPE_RDMA_READ);
+ msg_size = sizeof(struct c2wr_rdma_read_req);
+
+ /* IWarp only suppots 1 sge for RDMA reads */
+ if (ib_wr->num_sge > 1) {
+ err = -EINVAL;
+ break;
+ }
+
+ /*
+ * Move the local and remote stag/to/len into the WR.
+ */
+ wr.sqwr.rdma_read.local_stag =
+ cpu_to_be32(ib_wr->sg_list->lkey);
+ wr.sqwr.rdma_read.local_to =
+ cpu_to_be64(ib_wr->sg_list->addr);
+ wr.sqwr.rdma_read.remote_stag =
+ cpu_to_be32(ib_wr->wr.rdma.rkey);
+ wr.sqwr.rdma_read.remote_to =
+ cpu_to_be64(ib_wr->wr.rdma.remote_addr);
+ wr.sqwr.rdma_read.length =
+ cpu_to_be32(ib_wr->sg_list->length);
+ break;
+ default:
+ /* error */
+ msg_size = 0;
+ err = -EINVAL;
+ break;
+ }
+
+ /*
+ * If we had an error on the last wr build, then
+ * break out. Possible errors include bogus WR
+ * type, and a bogus SGL length...
+ */
+ if (err) {
+ break;
+ }
+
+ /*
+ * Store flags
+ */
+ c2_wr_set_flags(&wr, flags);
+
+ /*
+ * Post the puppy!
+ */
+ err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size);
+ if (err) {
+ break;
+ }
+
+ /*
+ * Enqueue mq index to activity FIFO.
+ */
+ c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count);
+
+ ib_wr = ib_wr->next;
+ }
+
+ if (err)
+ *bad_wr = ib_wr;
+ return err;
+}
+
+int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
+ struct ib_recv_wr **bad_wr)
+{
+ struct c2_dev *c2dev = to_c2dev(ibqp->device);
+ struct c2_qp *qp = to_c2qp(ibqp);
+ union c2wr wr;
+ int err = 0;
+
+ if (qp->state > IB_QPS_RTS)
+ return -EINVAL;
+
+ /*
+ * Try and post each work request
+ */
+ while (ib_wr) {
+ u32 tot_len;
+ u8 actual_sge_count;
+
+ if (ib_wr->num_sge > qp->recv_sgl_depth) {
+ err = -EINVAL;
+ break;
+ }
+
+ /*
+ * Create local host-copy of the WR
+ */
+ wr.rqwr.rq_hdr.user_hdr.hdr.context = ib_wr->wr_id;
+ c2_wr_set_id(&wr, CCWR_RECV);
+ c2_wr_set_flags(&wr, 0);
+
+ /* sge_count is limited to eight bits. */
+ BUG_ON(ib_wr->num_sge >= 256);
+ err = move_sgl((struct c2_data_addr *) & (wr.rqwr.data),
+ ib_wr->sg_list,
+ ib_wr->num_sge, &tot_len, &actual_sge_count);
+ c2_wr_set_sge_count(&wr, actual_sge_count);
+
+ /*
+ * If we had an error on the last wr build, then
+ * break out. Possible errors include bogus WR
+ * type, and a bogus SGL length...
+ */
+ if (err) {
+ break;
+ }
+
+ err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size);
+ if (err) {
+ break;
+ }
+
+ /*
+ * Enqueue mq index to activity FIFO
+ */
+ c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count);
+
+ ib_wr = ib_wr->next;
+ }
+
+ if (err)
+ *bad_wr = ib_wr;
+ return err;
+}
+
+void __devinit c2_init_qp_table(struct c2_dev *c2dev)
+{
+ spin_lock_init(&c2dev->qp_table.lock);
+ idr_init(&c2dev->qp_table.idr);
+}
+
+void __devexit c2_cleanup_qp_table(struct c2_dev *c2dev)
+{
+ idr_destroy(&c2dev->qp_table.idr);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
new file mode 100644
index 00000000000..e37c5688c21
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
@@ -0,0 +1,664 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_vlan.h>
+#include <linux/crc32.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/inet.h>
+#include <linux/vmalloc.h>
+
+#include <linux/route.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <rdma/ib_smi.h>
+#include "c2.h"
+#include "c2_vq.h"
+
+/* Device capabilities */
+#define C2_MIN_PAGESIZE 1024
+
+#define C2_MAX_MRS 32768
+#define C2_MAX_QPS 16000
+#define C2_MAX_WQE_SZ 256
+#define C2_MAX_QP_WR ((128*1024)/C2_MAX_WQE_SZ)
+#define C2_MAX_SGES 4
+#define C2_MAX_SGE_RD 1
+#define C2_MAX_CQS 32768
+#define C2_MAX_CQES 4096
+#define C2_MAX_PDS 16384
+
+/*
+ * Send the adapter INIT message to the amso1100
+ */
+static int c2_adapter_init(struct c2_dev *c2dev)
+{
+ struct c2wr_init_req wr;
+ int err;
+
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_INIT);
+ wr.hdr.context = 0;
+ wr.hint_count = cpu_to_be64(c2dev->hint_count_dma);
+ wr.q0_host_shared = cpu_to_be64(c2dev->req_vq.shared_dma);
+ wr.q1_host_shared = cpu_to_be64(c2dev->rep_vq.shared_dma);
+ wr.q1_host_msg_pool = cpu_to_be64(c2dev->rep_vq.host_dma);
+ wr.q2_host_shared = cpu_to_be64(c2dev->aeq.shared_dma);
+ wr.q2_host_msg_pool = cpu_to_be64(c2dev->aeq.host_dma);
+
+ /* Post the init message */
+ err = vq_send_wr(c2dev, (union c2wr *) & wr);
+
+ return err;
+}
+
+/*
+ * Send the adapter TERM message to the amso1100
+ */
+static void c2_adapter_term(struct c2_dev *c2dev)
+{
+ struct c2wr_init_req wr;
+
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_TERM);
+ wr.hdr.context = 0;
+
+ /* Post the init message */
+ vq_send_wr(c2dev, (union c2wr *) & wr);
+ c2dev->init = 0;
+
+ return;
+}
+
+/*
+ * Query the adapter
+ */
+static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props)
+{
+ struct c2_vq_req *vq_req;
+ struct c2wr_rnic_query_req wr;
+ struct c2wr_rnic_query_rep *reply;
+ int err;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ c2_wr_set_id(&wr, CCWR_RNIC_QUERY);
+ wr.hdr.context = (unsigned long) vq_req;
+ wr.rnic_handle = c2dev->adapter_handle;
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) &wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail1;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail1;
+
+ reply =
+ (struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply)
+ err = -ENOMEM;
+
+ err = c2_errno(reply);
+ if (err)
+ goto bail2;
+
+ props->fw_ver =
+ ((u64)be32_to_cpu(reply->fw_ver_major) << 32) |
+ ((be32_to_cpu(reply->fw_ver_minor) && 0xFFFF) << 16) |
+ (be32_to_cpu(reply->fw_ver_patch) && 0xFFFF);
+ memcpy(&props->sys_image_guid, c2dev->netdev->dev_addr, 6);
+ props->max_mr_size = 0xFFFFFFFF;
+ props->page_size_cap = ~(C2_MIN_PAGESIZE-1);
+ props->vendor_id = be32_to_cpu(reply->vendor_id);
+ props->vendor_part_id = be32_to_cpu(reply->part_number);
+ props->hw_ver = be32_to_cpu(reply->hw_version);
+ props->max_qp = be32_to_cpu(reply->max_qps);
+ props->max_qp_wr = be32_to_cpu(reply->max_qp_depth);
+ props->device_cap_flags = c2dev->device_cap_flags;
+ props->max_sge = C2_MAX_SGES;
+ props->max_sge_rd = C2_MAX_SGE_RD;
+ props->max_cq = be32_to_cpu(reply->max_cqs);
+ props->max_cqe = be32_to_cpu(reply->max_cq_depth);
+ props->max_mr = be32_to_cpu(reply->max_mrs);
+ props->max_pd = be32_to_cpu(reply->max_pds);
+ props->max_qp_rd_atom = be32_to_cpu(reply->max_qp_ird);
+ props->max_ee_rd_atom = 0;
+ props->max_res_rd_atom = be32_to_cpu(reply->max_global_ird);
+ props->max_qp_init_rd_atom = be32_to_cpu(reply->max_qp_ord);
+ props->max_ee_init_rd_atom = 0;
+ props->atomic_cap = IB_ATOMIC_NONE;
+ props->max_ee = 0;
+ props->max_rdd = 0;
+ props->max_mw = be32_to_cpu(reply->max_mws);
+ props->max_raw_ipv6_qp = 0;
+ props->max_raw_ethy_qp = 0;
+ props->max_mcast_grp = 0;
+ props->max_mcast_qp_attach = 0;
+ props->max_total_mcast_qp_attach = 0;
+ props->max_ah = 0;
+ props->max_fmr = 0;
+ props->max_map_per_fmr = 0;
+ props->max_srq = 0;
+ props->max_srq_wr = 0;
+ props->max_srq_sge = 0;
+ props->max_pkeys = 0;
+ props->local_ca_ack_delay = 0;
+
+ bail2:
+ vq_repbuf_free(c2dev, reply);
+
+ bail1:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+/*
+ * Add an IP address to the RNIC interface
+ */
+int c2_add_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask)
+{
+ struct c2_vq_req *vq_req;
+ struct c2wr_rnic_setconfig_req *wr;
+ struct c2wr_rnic_setconfig_rep *reply;
+ struct c2_netaddr netaddr;
+ int err, len;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ len = sizeof(struct c2_netaddr);
+ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+ if (!wr) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);
+ wr->hdr.context = (unsigned long) vq_req;
+ wr->rnic_handle = c2dev->adapter_handle;
+ wr->option = cpu_to_be32(C2_CFG_ADD_ADDR);
+
+ netaddr.ip_addr = inaddr;
+ netaddr.netmask = inmask;
+ netaddr.mtu = 0;
+
+ memcpy(wr->data, &netaddr, len);
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail1;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail1;
+
+ reply =
+ (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ err = c2_errno(reply);
+ vq_repbuf_free(c2dev, reply);
+
+ bail1:
+ kfree(wr);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+/*
+ * Delete an IP address from the RNIC interface
+ */
+int c2_del_addr(struct c2_dev *c2dev, u32 inaddr, u32 inmask)
+{
+ struct c2_vq_req *vq_req;
+ struct c2wr_rnic_setconfig_req *wr;
+ struct c2wr_rnic_setconfig_rep *reply;
+ struct c2_netaddr netaddr;
+ int err, len;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (!vq_req)
+ return -ENOMEM;
+
+ len = sizeof(struct c2_netaddr);
+ wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
+ if (!wr) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ c2_wr_set_id(wr, CCWR_RNIC_SETCONFIG);
+ wr->hdr.context = (unsigned long) vq_req;
+ wr->rnic_handle = c2dev->adapter_handle;
+ wr->option = cpu_to_be32(C2_CFG_DEL_ADDR);
+
+ netaddr.ip_addr = inaddr;
+ netaddr.netmask = inmask;
+ netaddr.mtu = 0;
+
+ memcpy(wr->data, &netaddr, len);
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, (union c2wr *) wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail1;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err)
+ goto bail1;
+
+ reply =
+ (struct c2wr_rnic_setconfig_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ err = c2_errno(reply);
+ vq_repbuf_free(c2dev, reply);
+
+ bail1:
+ kfree(wr);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+/*
+ * Open a single RNIC instance to use with all
+ * low level openib calls
+ */
+static int c2_rnic_open(struct c2_dev *c2dev)
+{
+ struct c2_vq_req *vq_req;
+ union c2wr wr;
+ struct c2wr_rnic_open_rep *reply;
+ int err;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (vq_req == NULL) {
+ return -ENOMEM;
+ }
+
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_RNIC_OPEN);
+ wr.rnic_open.req.hdr.context = (unsigned long) (vq_req);
+ wr.rnic_open.req.flags = cpu_to_be16(RNIC_PRIV_MODE);
+ wr.rnic_open.req.port_num = cpu_to_be16(0);
+ wr.rnic_open.req.user_context = (unsigned long) c2dev;
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, &wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail0;
+ }
+
+ reply = (struct c2wr_rnic_open_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ if ((err = c2_errno(reply)) != 0) {
+ goto bail1;
+ }
+
+ c2dev->adapter_handle = reply->rnic_handle;
+
+ bail1:
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+/*
+ * Close the RNIC instance
+ */
+static int c2_rnic_close(struct c2_dev *c2dev)
+{
+ struct c2_vq_req *vq_req;
+ union c2wr wr;
+ struct c2wr_rnic_close_rep *reply;
+ int err;
+
+ vq_req = vq_req_alloc(c2dev);
+ if (vq_req == NULL) {
+ return -ENOMEM;
+ }
+
+ memset(&wr, 0, sizeof(wr));
+ c2_wr_set_id(&wr, CCWR_RNIC_CLOSE);
+ wr.rnic_close.req.hdr.context = (unsigned long) vq_req;
+ wr.rnic_close.req.rnic_handle = c2dev->adapter_handle;
+
+ vq_req_get(c2dev, vq_req);
+
+ err = vq_send_wr(c2dev, &wr);
+ if (err) {
+ vq_req_put(c2dev, vq_req);
+ goto bail0;
+ }
+
+ err = vq_wait_for_reply(c2dev, vq_req);
+ if (err) {
+ goto bail0;
+ }
+
+ reply = (struct c2wr_rnic_close_rep *) (unsigned long) (vq_req->reply_msg);
+ if (!reply) {
+ err = -ENOMEM;
+ goto bail0;
+ }
+
+ if ((err = c2_errno(reply)) != 0) {
+ goto bail1;
+ }
+
+ c2dev->adapter_handle = 0;
+
+ bail1:
+ vq_repbuf_free(c2dev, reply);
+ bail0:
+ vq_req_free(c2dev, vq_req);
+ return err;
+}
+
+/*
+ * Called by c2_probe to initialize the RNIC. This principally
+ * involves initalizing the various limits and resouce pools that
+ * comprise the RNIC instance.
+ */
+int c2_rnic_init(struct c2_dev *c2dev)
+{
+ int err;
+ u32 qsize, msgsize;
+ void *q1_pages;
+ void *q2_pages;
+ void __iomem *mmio_regs;
+
+ /* Device capabilities */
+ c2dev->device_cap_flags =
+ (IB_DEVICE_RESIZE_MAX_WR |
+ IB_DEVICE_CURR_QP_STATE_MOD |
+ IB_DEVICE_SYS_IMAGE_GUID |
+ IB_DEVICE_ZERO_STAG |
+ IB_DEVICE_SEND_W_INV | IB_DEVICE_MEM_WINDOW);
+
+ /* Allocate the qptr_array */
+ c2dev->qptr_array = vmalloc(C2_MAX_CQS * sizeof(void *));
+ if (!c2dev->qptr_array) {
+ return -ENOMEM;
+ }
+
+ /* Inialize the qptr_array */
+ memset(c2dev->qptr_array, 0, C2_MAX_CQS * sizeof(void *));
+ c2dev->qptr_array[0] = (void *) &c2dev->req_vq;
+ c2dev->qptr_array[1] = (void *) &c2dev->rep_vq;
+ c2dev->qptr_array[2] = (void *) &c2dev->aeq;
+
+ /* Initialize data structures */
+ init_waitqueue_head(&c2dev->req_vq_wo);
+ spin_lock_init(&c2dev->vqlock);
+ spin_lock_init(&c2dev->lock);
+
+ /* Allocate MQ shared pointer pool for kernel clients. User
+ * mode client pools are hung off the user context
+ */
+ err = c2_init_mqsp_pool(c2dev, GFP_KERNEL, &c2dev->kern_mqsp_pool);
+ if (err) {
+ goto bail0;
+ }
+
+ /* Allocate shared pointers for Q0, Q1, and Q2 from
+ * the shared pointer pool.
+ */
+
+ c2dev->hint_count = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &c2dev->hint_count_dma,
+ GFP_KERNEL);
+ c2dev->req_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &c2dev->req_vq.shared_dma,
+ GFP_KERNEL);
+ c2dev->rep_vq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &c2dev->rep_vq.shared_dma,
+ GFP_KERNEL);
+ c2dev->aeq.shared = c2_alloc_mqsp(c2dev, c2dev->kern_mqsp_pool,
+ &c2dev->aeq.shared_dma, GFP_KERNEL);
+ if (!c2dev->hint_count || !c2dev->req_vq.shared ||
+ !c2dev->rep_vq.shared || !c2dev->aeq.shared) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+
+ mmio_regs = c2dev->kva;
+ /* Initialize the Verbs Request Queue */
+ c2_mq_req_init(&c2dev->req_vq, 0,
+ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_QSIZE)),
+ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_MSGSIZE)),
+ mmio_regs +
+ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_POOLSTART)),
+ mmio_regs +
+ be32_to_cpu(readl(mmio_regs + C2_REGS_Q0_SHARED)),
+ C2_MQ_ADAPTER_TARGET);
+
+ /* Initialize the Verbs Reply Queue */
+ qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_QSIZE));
+ msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_MSGSIZE));
+ q1_pages = kmalloc(qsize * msgsize, GFP_KERNEL);
+ if (!q1_pages) {
+ err = -ENOMEM;
+ goto bail1;
+ }
+ c2dev->rep_vq.host_dma = dma_map_single(c2dev->ibdev.dma_device,
+ (void *)q1_pages, qsize * msgsize,
+ DMA_FROM_DEVICE);
+ pci_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma);
+ pr_debug("%s rep_vq va %p dma %llx\n", __FUNCTION__, q1_pages,
+ (unsigned long long) c2dev->rep_vq.host_dma);
+ c2_mq_rep_init(&c2dev->rep_vq,
+ 1,
+ qsize,
+ msgsize,
+ q1_pages,
+ mmio_regs +
+ be32_to_cpu(readl(mmio_regs + C2_REGS_Q1_SHARED)),
+ C2_MQ_HOST_TARGET);
+
+ /* Initialize the Asynchronus Event Queue */
+ qsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_QSIZE));
+ msgsize = be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_MSGSIZE));
+ q2_pages = kmalloc(qsize * msgsize, GFP_KERNEL);
+ if (!q2_pages) {
+ err = -ENOMEM;
+ goto bail2;
+ }
+ c2dev->aeq.host_dma = dma_map_single(c2dev->ibdev.dma_device,
+ (void *)q2_pages, qsize * msgsize,
+ DMA_FROM_DEVICE);
+ pci_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma);
+ pr_debug("%s aeq va %p dma %llx\n", __FUNCTION__, q1_pages,
+ (unsigned long long) c2dev->rep_vq.host_dma);
+ c2_mq_rep_init(&c2dev->aeq,
+ 2,
+ qsize,
+ msgsize,
+ q2_pages,
+ mmio_regs +
+ be32_to_cpu(readl(mmio_regs + C2_REGS_Q2_SHARED)),
+ C2_MQ_HOST_TARGET);
+
+ /* Initialize the verbs request allocator */
+ err = vq_init(c2dev);
+ if (err)
+ goto bail3;
+
+ /* Enable interrupts on the adapter */
+ writel(0, c2dev->regs + C2_IDIS);
+
+ /* create the WR init message */
+ err = c2_adapter_init(c2dev);
+ if (err)
+ goto bail4;
+ c2dev->init++;
+
+ /* open an adapter instance */
+ err = c2_rnic_open(c2dev);
+ if (err)
+ goto bail4;
+
+ /* Initialize cached the adapter limits */
+ if (c2_rnic_query(c2dev, &c2dev->props))
+ goto bail5;
+
+ /* Initialize the PD pool */
+ err = c2_init_pd_table(c2dev);
+ if (err)
+ goto bail5;
+
+ /* Initialize the QP pool */
+ c2_init_qp_table(c2dev);
+ return 0;
+
+ bail5:
+ c2_rnic_close(c2dev);
+ bail4:
+ vq_term(c2dev);
+ bail3:
+ dma_unmap_single(c2dev->ibdev.dma_device,
+ pci_unmap_addr(&c2dev->aeq, mapping),
+ c2dev->aeq.q_size * c2dev->aeq.msg_size,
+ DMA_FROM_DEVICE);
+ kfree(q2_pages);
+ bail2:
+ dma_unmap_single(c2dev->ibdev.dma_device,
+ pci_unmap_addr(&c2dev->rep_vq, mapping),
+ c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,
+ DMA_FROM_DEVICE);
+ kfree(q1_pages);
+ bail1:
+ c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);
+ bail0:
+ vfree(c2dev->qptr_array);
+
+ return err;
+}
+
+/*
+ * Called by c2_remove to cleanup the RNIC resources.
+ */
+void c2_rnic_term(struct c2_dev *c2dev)
+{
+
+ /* Close the open adapter instance */
+ c2_rnic_close(c2dev);
+
+ /* Send the TERM message to the adapter */
+ c2_adapter_term(c2dev);
+
+ /* Disable interrupts on the adapter */
+ writel(1, c2dev->regs + C2_IDIS);
+
+ /* Free the QP pool */
+ c2_cleanup_qp_table(c2dev);
+
+ /* Free the PD pool */
+ c2_cleanup_pd_table(c2dev);
+
+ /* Free the verbs request allocator */
+ vq_term(c2dev);
+
+ /* Unmap and free the asynchronus event queue */
+ dma_unmap_single(c2dev->ibdev.dma_device,
+ pci_unmap_addr(&c2dev->aeq, mapping),
+ c2dev->aeq.q_size * c2dev->aeq.msg_size,
+ DMA_FROM_DEVICE);
+ kfree(c2dev->aeq.msg_pool.host);
+
+ /* Unmap and free the verbs reply queue */
+ dma_unmap_single(c2dev->ibdev.dma_device,
+ pci_unmap_addr(&c2dev->rep_vq, mapping),
+ c2dev->rep_vq.q_size * c2dev->rep_vq.msg_size,
+ DMA_FROM_DEVICE);
+ kfree(c2dev->rep_vq.msg_pool.host);
+
+ /* Free the MQ shared pointer pool */
+ c2_free_mqsp_pool(c2dev, c2dev->kern_mqsp_pool);
+
+ /* Free the qptr_array */
+ vfree(c2dev->qptr_array);
+
+ return;
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_status.h b/drivers/infiniband/hw/amso1100/c2_status.h
new file mode 100644
index 00000000000..6ee4aa92d87
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_status.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_STATUS_H_
+#define _C2_STATUS_H_
+
+/*
+ * Verbs Status Codes
+ */
+enum c2_status {
+ C2_OK = 0, /* This must be zero */
+ CCERR_INSUFFICIENT_RESOURCES = 1,
+ CCERR_INVALID_MODIFIER = 2,
+ CCERR_INVALID_MODE = 3,
+ CCERR_IN_USE = 4,
+ CCERR_INVALID_RNIC = 5,
+ CCERR_INTERRUPTED_OPERATION = 6,
+ CCERR_INVALID_EH = 7,
+ CCERR_INVALID_CQ = 8,
+ CCERR_CQ_EMPTY = 9,
+ CCERR_NOT_IMPLEMENTED = 10,
+ CCERR_CQ_DEPTH_TOO_SMALL = 11,
+ CCERR_PD_IN_USE = 12,
+ CCERR_INVALID_PD = 13,
+ CCERR_INVALID_SRQ = 14,
+ CCERR_INVALID_ADDRESS = 15,
+ CCERR_INVALID_NETMASK = 16,
+ CCERR_INVALID_QP = 17,
+ CCERR_INVALID_QP_STATE = 18,
+ CCERR_TOO_MANY_WRS_POSTED = 19,
+ CCERR_INVALID_WR_TYPE = 20,
+ CCERR_INVALID_SGL_LENGTH = 21,
+ CCERR_INVALID_SQ_DEPTH = 22,
+ CCERR_INVALID_RQ_DEPTH = 23,
+ CCERR_INVALID_ORD = 24,
+ CCERR_INVALID_IRD = 25,
+ CCERR_QP_ATTR_CANNOT_CHANGE = 26,
+ CCERR_INVALID_STAG = 27,
+ CCERR_QP_IN_USE = 28,
+ CCERR_OUTSTANDING_WRS = 29,
+ CCERR_STAG_IN_USE = 30,
+ CCERR_INVALID_STAG_INDEX = 31,
+ CCERR_INVALID_SGL_FORMAT = 32,
+ CCERR_ADAPTER_TIMEOUT = 33,
+ CCERR_INVALID_CQ_DEPTH = 34,
+ CCERR_INVALID_PRIVATE_DATA_LENGTH = 35,
+ CCERR_INVALID_EP = 36,
+ CCERR_MR_IN_USE = CCERR_STAG_IN_USE,
+ CCERR_FLUSHED = 38,
+ CCERR_INVALID_WQE = 39,
+ CCERR_LOCAL_QP_CATASTROPHIC_ERROR = 40,
+ CCERR_REMOTE_TERMINATION_ERROR = 41,
+ CCERR_BASE_AND_BOUNDS_VIOLATION = 42,
+ CCERR_ACCESS_VIOLATION = 43,
+ CCERR_INVALID_PD_ID = 44,
+ CCERR_WRAP_ERROR = 45,
+ CCERR_INV_STAG_ACCESS_ERROR = 46,
+ CCERR_ZERO_RDMA_READ_RESOURCES = 47,
+ CCERR_QP_NOT_PRIVILEGED = 48,
+ CCERR_STAG_STATE_NOT_INVALID = 49,
+ CCERR_INVALID_PAGE_SIZE = 50,
+ CCERR_INVALID_BUFFER_SIZE = 51,
+ CCERR_INVALID_PBE = 52,
+ CCERR_INVALID_FBO = 53,
+ CCERR_INVALID_LENGTH = 54,
+ CCERR_INVALID_ACCESS_RIGHTS = 55,
+ CCERR_PBL_TOO_BIG = 56,
+ CCERR_INVALID_VA = 57,
+ CCERR_INVALID_REGION = 58,
+ CCERR_INVALID_WINDOW = 59,
+ CCERR_TOTAL_LENGTH_TOO_BIG = 60,
+ CCERR_INVALID_QP_ID = 61,
+ CCERR_ADDR_IN_USE = 62,
+ CCERR_ADDR_NOT_AVAIL = 63,
+ CCERR_NET_DOWN = 64,
+ CCERR_NET_UNREACHABLE = 65,
+ CCERR_CONN_ABORTED = 66,
+ CCERR_CONN_RESET = 67,
+ CCERR_NO_BUFS = 68,
+ CCERR_CONN_TIMEDOUT = 69,
+ CCERR_CONN_REFUSED = 70,
+ CCERR_HOST_UNREACHABLE = 71,
+ CCERR_INVALID_SEND_SGL_DEPTH = 72,
+ CCERR_INVALID_RECV_SGL_DEPTH = 73,
+ CCERR_INVALID_RDMA_WRITE_SGL_DEPTH = 74,
+ CCERR_INSUFFICIENT_PRIVILEGES = 75,
+ CCERR_STACK_ERROR = 76,
+ CCERR_INVALID_VERSION = 77,
+ CCERR_INVALID_MTU = 78,
+ CCERR_INVALID_IMAGE = 79,
+ CCERR_PENDING = 98, /* not an error; user internally by adapter */
+ CCERR_DEFER = 99, /* not an error; used internally by adapter */
+ CCERR_FAILED_WRITE = 100,
+ CCERR_FAILED_ERASE = 101,
+ CCERR_FAILED_VERIFICATION = 102,
+ CCERR_NOT_FOUND = 103,
+
+};
+
+/*
+ * CCAE_ACTIVE_CONNECT_RESULTS status result codes.
+ */
+enum c2_connect_status {
+ C2_CONN_STATUS_SUCCESS = C2_OK,
+ C2_CONN_STATUS_NO_MEM = CCERR_INSUFFICIENT_RESOURCES,
+ C2_CONN_STATUS_TIMEDOUT = CCERR_CONN_TIMEDOUT,
+ C2_CONN_STATUS_REFUSED = CCERR_CONN_REFUSED,
+ C2_CONN_STATUS_NETUNREACH = CCERR_NET_UNREACHABLE,
+ C2_CONN_STATUS_HOSTUNREACH = CCERR_HOST_UNREACHABLE,
+ C2_CONN_STATUS_INVALID_RNIC = CCERR_INVALID_RNIC,
+ C2_CONN_STATUS_INVALID_QP = CCERR_INVALID_QP,
+ C2_CONN_STATUS_INVALID_QP_STATE = CCERR_INVALID_QP_STATE,
+ C2_CONN_STATUS_REJECTED = CCERR_CONN_RESET,
+ C2_CONN_STATUS_ADDR_NOT_AVAIL = CCERR_ADDR_NOT_AVAIL,
+};
+
+/*
+ * Flash programming status codes.
+ */
+enum c2_flash_status {
+ C2_FLASH_STATUS_SUCCESS = 0x0000,
+ C2_FLASH_STATUS_VERIFY_ERR = 0x0002,
+ C2_FLASH_STATUS_IMAGE_ERR = 0x0004,
+ C2_FLASH_STATUS_ECLBS = 0x0400,
+ C2_FLASH_STATUS_PSLBS = 0x0800,
+ C2_FLASH_STATUS_VPENS = 0x1000,
+};
+
+#endif /* _C2_STATUS_H_ */
diff --git a/drivers/infiniband/hw/amso1100/c2_user.h b/drivers/infiniband/hw/amso1100/c2_user.h
new file mode 100644
index 00000000000..7e9e7ad6546
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_user.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef C2_USER_H
+#define C2_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct c2_alloc_ucontext_resp {
+ __u32 qp_tab_size;
+ __u32 uarc_size;
+};
+
+struct c2_alloc_pd_resp {
+ __u32 pdn;
+ __u32 reserved;
+};
+
+struct c2_create_cq {
+ __u32 lkey;
+ __u32 pdn;
+ __u64 arm_db_page;
+ __u64 set_db_page;
+ __u32 arm_db_index;
+ __u32 set_db_index;
+};
+
+struct c2_create_cq_resp {
+ __u32 cqn;
+ __u32 reserved;
+};
+
+struct c2_create_qp {
+ __u32 lkey;
+ __u32 reserved;
+ __u64 sq_db_page;
+ __u64 rq_db_page;
+ __u32 sq_db_index;
+ __u32 rq_db_index;
+};
+
+#endif /* C2_USER_H */
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/infiniband/hw/amso1100/c2_vq.c
new file mode 100644
index 00000000000..40caeb5f41b
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_vq.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "c2_vq.h"
+#include "c2_provider.h"
+
+/*
+ * Verbs Request Objects:
+ *
+ * VQ Request Objects are allocated by the kernel verbs handlers.
+ * They contain a wait object, a refcnt, an atomic bool indicating that the
+ * adapter has replied, and a copy of the verb reply work request.
+ * A pointer to the VQ Request Object is passed down in the context
+ * field of the work request message, and reflected back by the adapter
+ * in the verbs reply message. The function handle_vq() in the interrupt
+ * path will use this pointer to:
+ * 1) append a copy of the verbs reply message
+ * 2) mark that the reply is ready
+ * 3) wake up the kernel verbs handler blocked awaiting the reply.
+ *
+ *
+ * The kernel verbs handlers do a "get" to put a 2nd reference on the
+ * VQ Request object. If the kernel verbs handler exits before the adapter
+ * can respond, this extra reference will keep the VQ Request object around
+ * until the adapter's reply can be processed. The reason we need this is
+ * because a pointer to this object is stuffed into the context field of
+ * the verbs work request message, and reflected back in the reply message.
+ * It is used in the interrupt handler (handle_vq()) to wake up the appropriate
+ * kernel verb handler that is blocked awaiting the verb reply.
+ * So handle_vq() will do a "put" on the object when it's done accessing it.
+ * NOTE: If we guarantee that the kernel verb handler will never bail before
+ * getting the reply, then we don't need these refcnts.
+ *
+ *
+ * VQ Request objects are freed by the kernel verbs handlers only
+ * after the verb has been processed, or when the adapter fails and
+ * does not reply.
+ *
+ *
+ * Verbs Reply Buffers:
+ *
+ * VQ Reply bufs are local host memory copies of a
+ * outstanding Verb Request reply
+ * message. The are always allocated by the kernel verbs handlers, and _may_ be
+ * freed by either the kernel verbs handler -or- the interrupt handler. The
+ * kernel verbs handler _must_ free the repbuf, then free the vq request object
+ * in that order.
+ */
+
+int vq_init(struct c2_dev *c2dev)
+{
+ sprintf(c2dev->vq_cache_name, "c2-vq:dev%c",
+ (char) ('0' + c2dev->devnum));
+ c2dev->host_msg_cache =
+ kmem_cache_create(c2dev->vq_cache_name, c2dev->rep_vq.msg_size, 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (c2dev->host_msg_cache == NULL) {
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void vq_term(struct c2_dev *c2dev)
+{
+ kmem_cache_destroy(c2dev->host_msg_cache);
+}
+
+/* vq_req_alloc - allocate a VQ Request Object and initialize it.
+ * The refcnt is set to 1.
+ */
+struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev)
+{
+ struct c2_vq_req *r;
+
+ r = kmalloc(sizeof(struct c2_vq_req), GFP_KERNEL);
+ if (r) {
+ init_waitqueue_head(&r->wait_object);
+ r->reply_msg = (u64) NULL;
+ r->event = 0;
+ r->cm_id = NULL;
+ r->qp = NULL;
+ atomic_set(&r->refcnt, 1);
+ atomic_set(&r->reply_ready, 0);
+ }
+ return r;
+}
+
+
+/* vq_req_free - free the VQ Request Object. It is assumed the verbs handler
+ * has already free the VQ Reply Buffer if it existed.
+ */
+void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *r)
+{
+ r->reply_msg = (u64) NULL;
+ if (atomic_dec_and_test(&r->refcnt)) {
+ kfree(r);
+ }
+}
+
+/* vq_req_get - reference a VQ Request Object. Done
+ * only in the kernel verbs handlers.
+ */
+void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *r)
+{
+ atomic_inc(&r->refcnt);
+}
+
+
+/* vq_req_put - dereference and potentially free a VQ Request Object.
+ *
+ * This is only called by handle_vq() on the
+ * interrupt when it is done processing
+ * a verb reply message. If the associated
+ * kernel verbs handler has already bailed,
+ * then this put will actually free the VQ
+ * Request object _and_ the VQ Reply Buffer
+ * if it exists.
+ */
+void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *r)
+{
+ if (atomic_dec_and_test(&r->refcnt)) {
+ if (r->reply_msg != (u64) NULL)
+ vq_repbuf_free(c2dev,
+ (void *) (unsigned long) r->reply_msg);
+ kfree(r);
+ }
+}
+
+
+/*
+ * vq_repbuf_alloc - allocate a VQ Reply Buffer.
+ */
+void *vq_repbuf_alloc(struct c2_dev *c2dev)
+{
+ return kmem_cache_alloc(c2dev->host_msg_cache, SLAB_ATOMIC);
+}
+
+/*
+ * vq_send_wr - post a verbs request message to the Verbs Request Queue.
+ * If a message is not available in the MQ, then block until one is available.
+ * NOTE: handle_mq() on the interrupt context will wake up threads blocked here.
+ * When the adapter drains the Verbs Request Queue,
+ * it inserts MQ index 0 in to the
+ * adapter->host activity fifo and interrupts the host.
+ */
+int vq_send_wr(struct c2_dev *c2dev, union c2wr *wr)
+{
+ void *msg;
+ wait_queue_t __wait;
+
+ /*
+ * grab adapter vq lock
+ */
+ spin_lock(&c2dev->vqlock);
+
+ /*
+ * allocate msg
+ */
+ msg = c2_mq_alloc(&c2dev->req_vq);
+
+ /*
+ * If we cannot get a msg, then we'll wait
+ * When a messages are available, the int handler will wake_up()
+ * any waiters.
+ */
+ while (msg == NULL) {
+ pr_debug("%s:%d no available msg in VQ, waiting...\n",
+ __FUNCTION__, __LINE__);
+ init_waitqueue_entry(&__wait, current);
+ add_wait_queue(&c2dev->req_vq_wo, &__wait);
+ spin_unlock(&c2dev->vqlock);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!c2_mq_full(&c2dev->req_vq)) {
+ break;
+ }
+ if (!signal_pending(current)) {
+ schedule_timeout(1 * HZ); /* 1 second... */
+ continue;
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&c2dev->req_vq_wo, &__wait);
+ return -EINTR;
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&c2dev->req_vq_wo, &__wait);
+ spin_lock(&c2dev->vqlock);
+ msg = c2_mq_alloc(&c2dev->req_vq);
+ }
+
+ /*
+ * copy wr into adapter msg
+ */
+ memcpy(msg, wr, c2dev->req_vq.msg_size);
+
+ /*
+ * post msg
+ */
+ c2_mq_produce(&c2dev->req_vq);
+
+ /*
+ * release adapter vq lock
+ */
+ spin_unlock(&c2dev->vqlock);
+ return 0;
+}
+
+
+/*
+ * vq_wait_for_reply - block until the adapter posts a Verb Reply Message.
+ */
+int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req)
+{
+ if (!wait_event_timeout(req->wait_object,
+ atomic_read(&req->reply_ready),
+ 60*HZ))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/*
+ * vq_repbuf_free - Free a Verbs Reply Buffer.
+ */
+void vq_repbuf_free(struct c2_dev *c2dev, void *reply)
+{
+ kmem_cache_free(c2dev->host_msg_cache, reply);
+}
diff --git a/drivers/infiniband/hw/amso1100/c2_vq.h b/drivers/infiniband/hw/amso1100/c2_vq.h
new file mode 100644
index 00000000000..33805627a60
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_vq.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_VQ_H_
+#define _C2_VQ_H_
+#include <linux/sched.h>
+#include "c2.h"
+#include "c2_wr.h"
+#include "c2_provider.h"
+
+struct c2_vq_req {
+ u64 reply_msg; /* ptr to reply msg */
+ wait_queue_head_t wait_object; /* wait object for vq reqs */
+ atomic_t reply_ready; /* set when reply is ready */
+ atomic_t refcnt; /* used to cancel WRs... */
+ int event;
+ struct iw_cm_id *cm_id;
+ struct c2_qp *qp;
+};
+
+extern int vq_init(struct c2_dev *c2dev);
+extern void vq_term(struct c2_dev *c2dev);
+
+extern struct c2_vq_req *vq_req_alloc(struct c2_dev *c2dev);
+extern void vq_req_free(struct c2_dev *c2dev, struct c2_vq_req *req);
+extern void vq_req_get(struct c2_dev *c2dev, struct c2_vq_req *req);
+extern void vq_req_put(struct c2_dev *c2dev, struct c2_vq_req *req);
+extern int vq_send_wr(struct c2_dev *c2dev, union c2wr * wr);
+
+extern void *vq_repbuf_alloc(struct c2_dev *c2dev);
+extern void vq_repbuf_free(struct c2_dev *c2dev, void *reply);
+
+extern int vq_wait_for_reply(struct c2_dev *c2dev, struct c2_vq_req *req);
+#endif /* _C2_VQ_H_ */
diff --git a/drivers/infiniband/hw/amso1100/c2_wr.h b/drivers/infiniband/hw/amso1100/c2_wr.h
new file mode 100644
index 00000000000..3ec6c43bb0e
--- /dev/null
+++ b/drivers/infiniband/hw/amso1100/c2_wr.h
@@ -0,0 +1,1520 @@
+/*
+ * Copyright (c) 2005 Ammasso, Inc. All rights reserved.
+ * Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _C2_WR_H_
+#define _C2_WR_H_
+
+#ifdef CCDEBUG
+#define CCWR_MAGIC 0xb07700b0
+#endif
+
+#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
+
+/* Maximum allowed size in bytes of private_data exchange
+ * on connect.
+ */
+#define C2_MAX_PRIVATE_DATA_SIZE 200
+
+/*
+ * These types are shared among the adapter, host, and CCIL consumer.
+ */
+enum c2_cq_notification_type {
+ C2_CQ_NOTIFICATION_TYPE_NONE = 1,
+ C2_CQ_NOTIFICATION_TYPE_NEXT,
+ C2_CQ_NOTIFICATION_TYPE_NEXT_SE
+};
+
+enum c2_setconfig_cmd {
+ C2_CFG_ADD_ADDR = 1,
+ C2_CFG_DEL_ADDR = 2,
+ C2_CFG_ADD_ROUTE = 3,
+ C2_CFG_DEL_ROUTE = 4
+};
+
+enum c2_getconfig_cmd {
+ C2_GETCONFIG_ROUTES = 1,
+ C2_GETCONFIG_ADDRS
+};
+
+/*
+ * CCIL Work Request Identifiers
+ */
+enum c2wr_ids {
+ CCWR_RNIC_OPEN = 1,
+ CCWR_RNIC_QUERY,
+ CCWR_RNIC_SETCONFIG,
+ CCWR_RNIC_GETCONFIG,
+ CCWR_RNIC_CLOSE,
+ CCWR_CQ_CREATE,
+ CCWR_CQ_QUERY,
+ CCWR_CQ_MODIFY,
+ CCWR_CQ_DESTROY,
+ CCWR_QP_CONNECT,
+ CCWR_PD_ALLOC,
+ CCWR_PD_DEALLOC,
+ CCWR_SRQ_CREATE,
+ CCWR_SRQ_QUERY,
+ CCWR_SRQ_MODIFY,
+ CCWR_SRQ_DESTROY,
+ CCWR_QP_CREATE,
+ CCWR_QP_QUERY,
+ CCWR_QP_MODIFY,
+ CCWR_QP_DESTROY,
+ CCWR_NSMR_STAG_ALLOC,
+ CCWR_NSMR_REGISTER,
+ CCWR_NSMR_PBL,
+ CCWR_STAG_DEALLOC,
+ CCWR_NSMR_REREGISTER,
+ CCWR_SMR_REGISTER,
+ CCWR_MR_QUERY,
+ CCWR_MW_ALLOC,
+ CCWR_MW_QUERY,
+ CCWR_EP_CREATE,
+ CCWR_EP_GETOPT,
+ CCWR_EP_SETOPT,
+ CCWR_EP_DESTROY,
+ CCWR_EP_BIND,
+ CCWR_EP_CONNECT,
+ CCWR_EP_LISTEN,
+ CCWR_EP_SHUTDOWN,
+ CCWR_EP_LISTEN_CREATE,
+ CCWR_EP_LISTEN_DESTROY,
+ CCWR_EP_QUERY,
+ CCWR_CR_ACCEPT,
+ CCWR_CR_REJECT,
+ CCWR_CONSOLE,
+ CCWR_TERM,
+ CCWR_FLASH_INIT,
+ CCWR_FLASH,
+ CCWR_BUF_ALLOC,
+ CCWR_BUF_FREE,
+ CCWR_FLASH_WRITE,
+ CCWR_INIT, /* WARNING: Don't move this ever again! */
+
+
+
+ /* Add new IDs here */
+
+
+
+ /*
+ * WARNING: CCWR_LAST must always be the last verbs id defined!
+ * All the preceding IDs are fixed, and must not change.
+ * You can add new IDs, but must not remove or reorder
+ * any IDs. If you do, YOU will ruin any hope of
+ * compatability between versions.
+ */
+ CCWR_LAST,
+
+ /*
+ * Start over at 1 so that arrays indexed by user wr id's
+ * begin at 1. This is OK since the verbs and user wr id's
+ * are always used on disjoint sets of queues.
+ */
+ /*
+ * The order of the CCWR_SEND_XX verbs must
+ * match the order of the RDMA_OPs
+ */
+ CCWR_SEND = 1,
+ CCWR_SEND_INV,
+ CCWR_SEND_SE,
+ CCWR_SEND_SE_INV,
+ CCWR_RDMA_WRITE,
+ CCWR_RDMA_READ,
+ CCWR_RDMA_READ_INV,
+ CCWR_MW_BIND,
+ CCWR_NSMR_FASTREG,
+ CCWR_STAG_INVALIDATE,
+ CCWR_RECV,
+ CCWR_NOP,
+ CCWR_UNIMPL,
+/* WARNING: This must always be the last user wr id defined! */
+};
+#define RDMA_SEND_OPCODE_FROM_WR_ID(x) (x+2)
+
+/*
+ * SQ/RQ Work Request Types
+ */
+enum c2_wr_type {
+ C2_WR_TYPE_SEND = CCWR_SEND,
+ C2_WR_TYPE_SEND_SE = CCWR_SEND_SE,
+ C2_WR_TYPE_SEND_INV = CCWR_SEND_INV,
+ C2_WR_TYPE_SEND_SE_INV = CCWR_SEND_SE_INV,
+ C2_WR_TYPE_RDMA_WRITE = CCWR_RDMA_WRITE,
+ C2_WR_TYPE_RDMA_READ = CCWR_RDMA_READ,
+ C2_WR_TYPE_RDMA_READ_INV_STAG = CCWR_RDMA_READ_INV,
+ C2_WR_TYPE_BIND_MW = CCWR_MW_BIND,
+ C2_WR_TYPE_FASTREG_NSMR = CCWR_NSMR_FASTREG,
+ C2_WR_TYPE_INV_STAG = CCWR_STAG_INVALIDATE,
+ C2_WR_TYPE_RECV = CCWR_RECV,
+ C2_WR_TYPE_NOP = CCWR_NOP,
+};
+
+struct c2_netaddr {
+ u32 ip_addr;
+ u32 netmask;
+ u32 mtu;
+};
+
+struct c2_route {
+ u32 ip_addr; /* 0 indicates the default route */
+ u32 netmask; /* netmask associated with dst */
+ u32 flags;
+ union {
+ u32 ipaddr; /* address of the nexthop interface */
+ u8 enaddr[6];
+ } nexthop;
+};
+
+/*
+ * A Scatter Gather Entry.
+ */
+struct c2_data_addr {
+ u32 stag;
+ u32 length;
+ u64 to;
+};
+
+/*
+ * MR and MW flags used by the consumer, RI, and RNIC.
+ */
+enum c2_mm_flags {
+ MEM_REMOTE = 0x0001, /* allow mw binds with remote access. */
+ MEM_VA_BASED = 0x0002, /* Not Zero-based */
+ MEM_PBL_COMPLETE = 0x0004, /* PBL array is complete in this msg */
+ MEM_LOCAL_READ = 0x0008, /* allow local reads */
+ MEM_LOCAL_WRITE = 0x0010, /* allow local writes */
+ MEM_REMOTE_READ = 0x0020, /* allow remote reads */
+ MEM_REMOTE_WRITE = 0x0040, /* allow remote writes */
+ MEM_WINDOW_BIND = 0x0080, /* binds allowed */
+ MEM_SHARED = 0x0100, /* set if MR is shared */
+ MEM_STAG_VALID = 0x0200 /* set if STAG is in valid state */
+};
+
+/*
+ * CCIL API ACF flags defined in terms of the low level mem flags.
+ * This minimizes translation needed in the user API
+ */
+enum c2_acf {
+ C2_ACF_LOCAL_READ = MEM_LOCAL_READ,
+ C2_ACF_LOCAL_WRITE = MEM_LOCAL_WRITE,
+ C2_ACF_REMOTE_READ = MEM_REMOTE_READ,
+ C2_ACF_REMOTE_WRITE = MEM_REMOTE_WRITE,
+ C2_ACF_WINDOW_BIND = MEM_WINDOW_BIND
+};
+
+/*
+ * Image types of objects written to flash
+ */
+#define C2_FLASH_IMG_BITFILE 1
+#define C2_FLASH_IMG_OPTION_ROM 2
+#define C2_FLASH_IMG_VPD 3
+
+/*
+ * to fix bug 1815 we define the max size allowable of the
+ * terminate message (per the IETF spec).Refer to the IETF
+ * protocal specification, section 12.1.6, page 64)
+ * The message is prefixed by 20 types of DDP info.
+ *
+ * Then the message has 6 bytes for the terminate control
+ * and DDP segment length info plus a DDP header (either
+ * 14 or 18 byts) plus 28 bytes for the RDMA header.
+ * Thus the max size in:
+ * 20 + (6 + 18 + 28) = 72
+ */
+#define C2_MAX_TERMINATE_MESSAGE_SIZE (72)
+
+/*
+ * Build String Length. It must be the same as C2_BUILD_STR_LEN in ccil_api.h
+ */
+#define WR_BUILD_STR_LEN 64
+
+/*
+ * WARNING: All of these structs need to align any 64bit types on
+ * 64 bit boundaries! 64bit types include u64 and u64.
+ */
+
+/*
+ * Clustercore Work Request Header. Be sensitive to field layout
+ * and alignment.
+ */
+struct c2wr_hdr {
+ /* wqe_count is part of the cqe. It is put here so the
+ * adapter can write to it while the wr is pending without
+ * clobbering part of the wr. This word need not be dma'd
+ * from the host to adapter by libccil, but we copy it anyway
+ * to make the memcpy to the adapter better aligned.
+ */
+ u32 wqe_count;
+
+ /* Put these fields next so that later 32- and 64-bit
+ * quantities are naturally aligned.
+ */
+ u8 id;
+ u8 result; /* adapter -> host */
+ u8 sge_count; /* host -> adapter */
+ u8 flags; /* host -> adapter */
+
+ u64 context;
+#ifdef CCMSGMAGIC
+ u32 magic;
+ u32 pad;
+#endif
+} __attribute__((packed));
+
+/*
+ *------------------------ RNIC ------------------------
+ */
+
+/*
+ * WR_RNIC_OPEN
+ */
+
+/*
+ * Flags for the RNIC WRs
+ */
+enum c2_rnic_flags {
+ RNIC_IRD_STATIC = 0x0001,
+ RNIC_ORD_STATIC = 0x0002,
+ RNIC_QP_STATIC = 0x0004,
+ RNIC_SRQ_SUPPORTED = 0x0008,
+ RNIC_PBL_BLOCK_MODE = 0x0010,
+ RNIC_SRQ_MODEL_ARRIVAL = 0x0020,
+ RNIC_CQ_OVF_DETECTED = 0x0040,
+ RNIC_PRIV_MODE = 0x0080
+};
+
+struct c2wr_rnic_open_req {
+ struct c2wr_hdr hdr;
+ u64 user_context;
+ u16 flags; /* See enum c2_rnic_flags */
+ u16 port_num;
+} __attribute__((packed));
+
+struct c2wr_rnic_open_rep {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+} __attribute__((packed));
+
+union c2wr_rnic_open {
+ struct c2wr_rnic_open_req req;
+ struct c2wr_rnic_open_rep rep;
+} __attribute__((packed));
+
+struct c2wr_rnic_query_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+} __attribute__((packed));
+
+/*
+ * WR_RNIC_QUERY
+ */
+struct c2wr_rnic_query_rep {
+ struct c2wr_hdr hdr;
+ u64 user_context;
+ u32 vendor_id;
+ u32 part_number;
+ u32 hw_version;
+ u32 fw_ver_major;
+ u32 fw_ver_minor;
+ u32 fw_ver_patch;
+ char fw_ver_build_str[WR_BUILD_STR_LEN];
+ u32 max_qps;
+ u32 max_qp_depth;
+ u32 max_srq_depth;
+ u32 max_send_sgl_depth;
+ u32 max_rdma_sgl_depth;
+ u32 max_cqs;
+ u32 max_cq_depth;
+ u32 max_cq_event_handlers;
+ u32 max_mrs;
+ u32 max_pbl_depth;
+ u32 max_pds;
+ u32 max_global_ird;
+ u32 max_global_ord;
+ u32 max_qp_ird;
+ u32 max_qp_ord;
+ u32 flags;
+ u32 max_mws;
+ u32 pbe_range_low;
+ u32 pbe_range_high;
+ u32 max_srqs;
+ u32 page_size;
+} __attribute__((packed));
+
+union c2wr_rnic_query {
+ struct c2wr_rnic_query_req req;
+ struct c2wr_rnic_query_rep rep;
+} __attribute__((packed));
+
+/*
+ * WR_RNIC_GETCONFIG
+ */
+
+struct c2wr_rnic_getconfig_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 option; /* see c2_getconfig_cmd_t */
+ u64 reply_buf;
+ u32 reply_buf_len;
+} __attribute__((packed)) ;
+
+struct c2wr_rnic_getconfig_rep {
+ struct c2wr_hdr hdr;
+ u32 option; /* see c2_getconfig_cmd_t */
+ u32 count_len; /* length of the number of addresses configured */
+} __attribute__((packed)) ;
+
+union c2wr_rnic_getconfig {
+ struct c2wr_rnic_getconfig_req req;
+ struct c2wr_rnic_getconfig_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ * WR_RNIC_SETCONFIG
+ */
+struct c2wr_rnic_setconfig_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 option; /* See c2_setconfig_cmd_t */
+ /* variable data and pad. See c2_netaddr and c2_route */
+ u8 data[0];
+} __attribute__((packed)) ;
+
+struct c2wr_rnic_setconfig_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_rnic_setconfig {
+ struct c2wr_rnic_setconfig_req req;
+ struct c2wr_rnic_setconfig_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ * WR_RNIC_CLOSE
+ */
+struct c2wr_rnic_close_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_rnic_close_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_rnic_close {
+ struct c2wr_rnic_close_req req;
+ struct c2wr_rnic_close_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ CQ ------------------------
+ */
+struct c2wr_cq_create_req {
+ struct c2wr_hdr hdr;
+ u64 shared_ht;
+ u64 user_context;
+ u64 msg_pool;
+ u32 rnic_handle;
+ u32 msg_size;
+ u32 depth;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_create_rep {
+ struct c2wr_hdr hdr;
+ u32 mq_index;
+ u32 adapter_shared;
+ u32 cq_handle;
+} __attribute__((packed)) ;
+
+union c2wr_cq_create {
+ struct c2wr_cq_create_req req;
+ struct c2wr_cq_create_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_modify_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 cq_handle;
+ u32 new_depth;
+ u64 new_msg_pool;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_modify_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_cq_modify {
+ struct c2wr_cq_modify_req req;
+ struct c2wr_cq_modify_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_destroy_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 cq_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_cq_destroy_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_cq_destroy {
+ struct c2wr_cq_destroy_req req;
+ struct c2wr_cq_destroy_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ PD ------------------------
+ */
+struct c2wr_pd_alloc_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_pd_alloc_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_pd_alloc {
+ struct c2wr_pd_alloc_req req;
+ struct c2wr_pd_alloc_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_pd_dealloc_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_pd_dealloc_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_pd_dealloc {
+ struct c2wr_pd_dealloc_req req;
+ struct c2wr_pd_dealloc_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ SRQ ------------------------
+ */
+struct c2wr_srq_create_req {
+ struct c2wr_hdr hdr;
+ u64 shared_ht;
+ u64 user_context;
+ u32 rnic_handle;
+ u32 srq_depth;
+ u32 srq_limit;
+ u32 sgl_depth;
+ u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_srq_create_rep {
+ struct c2wr_hdr hdr;
+ u32 srq_depth;
+ u32 sgl_depth;
+ u32 msg_size;
+ u32 mq_index;
+ u32 mq_start;
+ u32 srq_handle;
+} __attribute__((packed)) ;
+
+union c2wr_srq_create {
+ struct c2wr_srq_create_req req;
+ struct c2wr_srq_create_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_srq_destroy_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 srq_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_srq_destroy_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_srq_destroy {
+ struct c2wr_srq_destroy_req req;
+ struct c2wr_srq_destroy_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ QP ------------------------
+ */
+enum c2wr_qp_flags {
+ QP_RDMA_READ = 0x00000001, /* RDMA read enabled? */
+ QP_RDMA_WRITE = 0x00000002, /* RDMA write enabled? */
+ QP_MW_BIND = 0x00000004, /* MWs enabled */
+ QP_ZERO_STAG = 0x00000008, /* enabled? */
+ QP_REMOTE_TERMINATION = 0x00000010, /* remote end terminated */
+ QP_RDMA_READ_RESPONSE = 0x00000020 /* Remote RDMA read */
+ /* enabled? */
+};
+
+struct c2wr_qp_create_req {
+ struct c2wr_hdr hdr;
+ u64 shared_sq_ht;
+ u64 shared_rq_ht;
+ u64 user_context;
+ u32 rnic_handle;
+ u32 sq_cq_handle;
+ u32 rq_cq_handle;
+ u32 sq_depth;
+ u32 rq_depth;
+ u32 srq_handle;
+ u32 srq_limit;
+ u32 flags; /* see enum c2wr_qp_flags */
+ u32 send_sgl_depth;
+ u32 recv_sgl_depth;
+ u32 rdma_write_sgl_depth;
+ u32 ord;
+ u32 ird;
+ u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_create_rep {
+ struct c2wr_hdr hdr;
+ u32 sq_depth;
+ u32 rq_depth;
+ u32 send_sgl_depth;
+ u32 recv_sgl_depth;
+ u32 rdma_write_sgl_depth;
+ u32 ord;
+ u32 ird;
+ u32 sq_msg_size;
+ u32 sq_mq_index;
+ u32 sq_mq_start;
+ u32 rq_msg_size;
+ u32 rq_mq_index;
+ u32 rq_mq_start;
+ u32 qp_handle;
+} __attribute__((packed)) ;
+
+union c2wr_qp_create {
+ struct c2wr_qp_create_req req;
+ struct c2wr_qp_create_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_query_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 qp_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_query_rep {
+ struct c2wr_hdr hdr;
+ u64 user_context;
+ u32 rnic_handle;
+ u32 sq_depth;
+ u32 rq_depth;
+ u32 send_sgl_depth;
+ u32 rdma_write_sgl_depth;
+ u32 recv_sgl_depth;
+ u32 ord;
+ u32 ird;
+ u16 qp_state;
+ u16 flags; /* see c2wr_qp_flags_t */
+ u32 qp_id;
+ u32 local_addr;
+ u32 remote_addr;
+ u16 local_port;
+ u16 remote_port;
+ u32 terminate_msg_length; /* 0 if not present */
+ u8 data[0];
+ /* Terminate Message in-line here. */
+} __attribute__((packed)) ;
+
+union c2wr_qp_query {
+ struct c2wr_qp_query_req req;
+ struct c2wr_qp_query_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_modify_req {
+ struct c2wr_hdr hdr;
+ u64 stream_msg;
+ u32 stream_msg_length;
+ u32 rnic_handle;
+ u32 qp_handle;
+ u32 next_qp_state;
+ u32 ord;
+ u32 ird;
+ u32 sq_depth;
+ u32 rq_depth;
+ u32 llp_ep_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_modify_rep {
+ struct c2wr_hdr hdr;
+ u32 ord;
+ u32 ird;
+ u32 sq_depth;
+ u32 rq_depth;
+ u32 sq_msg_size;
+ u32 sq_mq_index;
+ u32 sq_mq_start;
+ u32 rq_msg_size;
+ u32 rq_mq_index;
+ u32 rq_mq_start;
+} __attribute__((packed)) ;
+
+union c2wr_qp_modify {
+ struct c2wr_qp_modify_req req;
+ struct c2wr_qp_modify_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_destroy_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 qp_handle;
+} __attribute__((packed)) ;
+
+struct c2wr_qp_destroy_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_qp_destroy {
+ struct c2wr_qp_destroy_req req;
+ struct c2wr_qp_destroy_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ * The CCWR_QP_CONNECT msg is posted on the verbs request queue. It can
+ * only be posted when a QP is in IDLE state. After the connect request is
+ * submitted to the LLP, the adapter moves the QP to CONNECT_PENDING state.
+ * No synchronous reply from adapter to this WR. The results of
+ * connection are passed back in an async event CCAE_ACTIVE_CONNECT_RESULTS
+ * See c2wr_ae_active_connect_results_t
+ */
+struct c2wr_qp_connect_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 qp_handle;
+ u32 remote_addr;
+ u16 remote_port;
+ u16 pad;
+ u32 private_data_length;
+ u8 private_data[0]; /* Private data in-line. */
+} __attribute__((packed)) ;
+
+struct c2wr_qp_connect {
+ struct c2wr_qp_connect_req req;
+ /* no synchronous reply. */
+} __attribute__((packed)) ;
+
+
+/*
+ *------------------------ MM ------------------------
+ */
+
+struct c2wr_nsmr_stag_alloc_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 pbl_depth;
+ u32 pd_id;
+ u32 flags;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_stag_alloc_rep {
+ struct c2wr_hdr hdr;
+ u32 pbl_depth;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_stag_alloc {
+ struct c2wr_nsmr_stag_alloc_req req;
+ struct c2wr_nsmr_stag_alloc_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_register_req {
+ struct c2wr_hdr hdr;
+ u64 va;
+ u32 rnic_handle;
+ u16 flags;
+ u8 stag_key;
+ u8 pad;
+ u32 pd_id;
+ u32 pbl_depth;
+ u32 pbe_size;
+ u32 fbo;
+ u32 length;
+ u32 addrs_length;
+ /* array of paddrs (must be aligned on a 64bit boundary) */
+ u64 paddrs[0];
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_register_rep {
+ struct c2wr_hdr hdr;
+ u32 pbl_depth;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_register {
+ struct c2wr_nsmr_register_req req;
+ struct c2wr_nsmr_register_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_pbl_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 flags;
+ u32 stag_index;
+ u32 addrs_length;
+ /* array of paddrs (must be aligned on a 64bit boundary) */
+ u64 paddrs[0];
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_pbl_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_pbl {
+ struct c2wr_nsmr_pbl_req req;
+ struct c2wr_nsmr_pbl_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_mr_query_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+struct c2wr_mr_query_rep {
+ struct c2wr_hdr hdr;
+ u8 stag_key;
+ u8 pad[3];
+ u32 pd_id;
+ u32 flags;
+ u32 pbl_depth;
+} __attribute__((packed)) ;
+
+union c2wr_mr_query {
+ struct c2wr_mr_query_req req;
+ struct c2wr_mr_query_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_query_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_query_rep {
+ struct c2wr_hdr hdr;
+ u8 stag_key;
+ u8 pad[3];
+ u32 pd_id;
+ u32 flags;
+} __attribute__((packed)) ;
+
+union c2wr_mw_query {
+ struct c2wr_mw_query_req req;
+ struct c2wr_mw_query_rep rep;
+} __attribute__((packed)) ;
+
+
+struct c2wr_stag_dealloc_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+struct c2wr_stag_dealloc_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed)) ;
+
+union c2wr_stag_dealloc {
+ struct c2wr_stag_dealloc_req req;
+ struct c2wr_stag_dealloc_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_reregister_req {
+ struct c2wr_hdr hdr;
+ u64 va;
+ u32 rnic_handle;
+ u16 flags;
+ u8 stag_key;
+ u8 pad;
+ u32 stag_index;
+ u32 pd_id;
+ u32 pbl_depth;
+ u32 pbe_size;
+ u32 fbo;
+ u32 length;
+ u32 addrs_length;
+ u32 pad1;
+ /* array of paddrs (must be aligned on a 64bit boundary) */
+ u64 paddrs[0];
+} __attribute__((packed)) ;
+
+struct c2wr_nsmr_reregister_rep {
+ struct c2wr_hdr hdr;
+ u32 pbl_depth;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_nsmr_reregister {
+ struct c2wr_nsmr_reregister_req req;
+ struct c2wr_nsmr_reregister_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_smr_register_req {
+ struct c2wr_hdr hdr;
+ u64 va;
+ u32 rnic_handle;
+ u16 flags;
+ u8 stag_key;
+ u8 pad;
+ u32 stag_index;
+ u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_smr_register_rep {
+ struct c2wr_hdr hdr;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_smr_register {
+ struct c2wr_smr_register_req req;
+ struct c2wr_smr_register_rep rep;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_alloc_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 pd_id;
+} __attribute__((packed)) ;
+
+struct c2wr_mw_alloc_rep {
+ struct c2wr_hdr hdr;
+ u32 stag_index;
+} __attribute__((packed)) ;
+
+union c2wr_mw_alloc {
+ struct c2wr_mw_alloc_req req;
+ struct c2wr_mw_alloc_rep rep;
+} __attribute__((packed)) ;
+
+/*
+ *------------------------ WRs -----------------------
+ */
+
+struct c2wr_user_hdr {
+ struct c2wr_hdr hdr; /* Has status and WR Type */
+} __attribute__((packed)) ;
+
+enum c2_qp_state {
+ C2_QP_STATE_IDLE = 0x01,
+ C2_QP_STATE_CONNECTING = 0x02,
+ C2_QP_STATE_RTS = 0x04,
+ C2_QP_STATE_CLOSING = 0x08,
+ C2_QP_STATE_TERMINATE = 0x10,
+ C2_QP_STATE_ERROR = 0x20,
+};
+
+/* Completion queue entry. */
+struct c2wr_ce {
+ struct c2wr_hdr hdr; /* Has status and WR Type */
+ u64 qp_user_context; /* c2_user_qp_t * */
+ u32 qp_state; /* Current QP State */
+ u32 handle; /* QPID or EP Handle */
+ u32 bytes_rcvd; /* valid for RECV WCs */
+ u32 stag;
+} __attribute__((packed)) ;
+
+
+/*
+ * Flags used for all post-sq WRs. These must fit in the flags
+ * field of the struct c2wr_hdr (eight bits).
+ */
+enum {
+ SQ_SIGNALED = 0x01,
+ SQ_READ_FENCE = 0x02,
+ SQ_FENCE = 0x04,
+};
+
+/*
+ * Common fields for all post-sq WRs. Namely the standard header and a
+ * secondary header with fields common to all post-sq WRs.
+ */
+struct c2_sq_hdr {
+ struct c2wr_user_hdr user_hdr;
+} __attribute__((packed));
+
+/*
+ * Same as above but for post-rq WRs.
+ */
+struct c2_rq_hdr {
+ struct c2wr_user_hdr user_hdr;
+} __attribute__((packed));
+
+/*
+ * use the same struct for all sends.
+ */
+struct c2wr_send_req {
+ struct c2_sq_hdr sq_hdr;
+ u32 sge_len;
+ u32 remote_stag;
+ u8 data[0]; /* SGE array */
+} __attribute__((packed));
+
+union c2wr_send {
+ struct c2wr_send_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_rdma_write_req {
+ struct c2_sq_hdr sq_hdr;
+ u64 remote_to;
+ u32 remote_stag;
+ u32 sge_len;
+ u8 data[0]; /* SGE array */
+} __attribute__((packed));
+
+union c2wr_rdma_write {
+ struct c2wr_rdma_write_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_rdma_read_req {
+ struct c2_sq_hdr sq_hdr;
+ u64 local_to;
+ u64 remote_to;
+ u32 local_stag;
+ u32 remote_stag;
+ u32 length;
+} __attribute__((packed));
+
+union c2wr_rdma_read {
+ struct c2wr_rdma_read_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_mw_bind_req {
+ struct c2_sq_hdr sq_hdr;
+ u64 va;
+ u8 stag_key;
+ u8 pad[3];
+ u32 mw_stag_index;
+ u32 mr_stag_index;
+ u32 length;
+ u32 flags;
+} __attribute__((packed));
+
+union c2wr_mw_bind {
+ struct c2wr_mw_bind_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_nsmr_fastreg_req {
+ struct c2_sq_hdr sq_hdr;
+ u64 va;
+ u8 stag_key;
+ u8 pad[3];
+ u32 stag_index;
+ u32 pbe_size;
+ u32 fbo;
+ u32 length;
+ u32 addrs_length;
+ /* array of paddrs (must be aligned on a 64bit boundary) */
+ u64 paddrs[0];
+} __attribute__((packed));
+
+union c2wr_nsmr_fastreg {
+ struct c2wr_nsmr_fastreg_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_stag_invalidate_req {
+ struct c2_sq_hdr sq_hdr;
+ u8 stag_key;
+ u8 pad[3];
+ u32 stag_index;
+} __attribute__((packed));
+
+union c2wr_stag_invalidate {
+ struct c2wr_stag_invalidate_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+union c2wr_sqwr {
+ struct c2_sq_hdr sq_hdr;
+ struct c2wr_send_req send;
+ struct c2wr_send_req send_se;
+ struct c2wr_send_req send_inv;
+ struct c2wr_send_req send_se_inv;
+ struct c2wr_rdma_write_req rdma_write;
+ struct c2wr_rdma_read_req rdma_read;
+ struct c2wr_mw_bind_req mw_bind;
+ struct c2wr_nsmr_fastreg_req nsmr_fastreg;
+ struct c2wr_stag_invalidate_req stag_inv;
+} __attribute__((packed));
+
+
+/*
+ * RQ WRs
+ */
+struct c2wr_rqwr {
+ struct c2_rq_hdr rq_hdr;
+ u8 data[0]; /* array of SGEs */
+} __attribute__((packed));
+
+union c2wr_recv {
+ struct c2wr_rqwr req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+/*
+ * All AEs start with this header. Most AEs only need to convey the
+ * information in the header. Some, like LLP connection events, need
+ * more info. The union typdef c2wr_ae_t has all the possible AEs.
+ *
+ * hdr.context is the user_context from the rnic_open WR. NULL If this
+ * is not affiliated with an rnic
+ *
+ * hdr.id is the AE identifier (eg; CCAE_REMOTE_SHUTDOWN,
+ * CCAE_LLP_CLOSE_COMPLETE)
+ *
+ * resource_type is one of: C2_RES_IND_QP, C2_RES_IND_CQ, C2_RES_IND_SRQ
+ *
+ * user_context is the context passed down when the host created the resource.
+ */
+struct c2wr_ae_hdr {
+ struct c2wr_hdr hdr;
+ u64 user_context; /* user context for this res. */
+ u32 resource_type; /* see enum c2_resource_indicator */
+ u32 resource; /* handle for resource */
+ u32 qp_state; /* current QP State */
+} __attribute__((packed));
+
+/*
+ * After submitting the CCAE_ACTIVE_CONNECT_RESULTS message on the AEQ,
+ * the adapter moves the QP into RTS state
+ */
+struct c2wr_ae_active_connect_results {
+ struct c2wr_ae_hdr ae_hdr;
+ u32 laddr;
+ u32 raddr;
+ u16 lport;
+ u16 rport;
+ u32 private_data_length;
+ u8 private_data[0]; /* data is in-line in the msg. */
+} __attribute__((packed));
+
+/*
+ * When connections are established by the stack (and the private data
+ * MPA frame is received), the adapter will generate an event to the host.
+ * The details of the connection, any private data, and the new connection
+ * request handle is passed up via the CCAE_CONNECTION_REQUEST msg on the
+ * AE queue:
+ */
+struct c2wr_ae_connection_request {
+ struct c2wr_ae_hdr ae_hdr;
+ u32 cr_handle; /* connreq handle (sock ptr) */
+ u32 laddr;
+ u32 raddr;
+ u16 lport;
+ u16 rport;
+ u32 private_data_length;
+ u8 private_data[0]; /* data is in-line in the msg. */
+} __attribute__((packed));
+
+union c2wr_ae {
+ struct c2wr_ae_hdr ae_generic;
+ struct c2wr_ae_active_connect_results ae_active_connect_results;
+ struct c2wr_ae_connection_request ae_connection_request;
+} __attribute__((packed));
+
+struct c2wr_init_req {
+ struct c2wr_hdr hdr;
+ u64 hint_count;
+ u64 q0_host_shared;
+ u64 q1_host_shared;
+ u64 q1_host_msg_pool;
+ u64 q2_host_shared;
+ u64 q2_host_msg_pool;
+} __attribute__((packed));
+
+struct c2wr_init_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_init {
+ struct c2wr_init_req req;
+ struct c2wr_init_rep rep;
+} __attribute__((packed));
+
+/*
+ * For upgrading flash.
+ */
+
+struct c2wr_flash_init_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+} __attribute__((packed));
+
+struct c2wr_flash_init_rep {
+ struct c2wr_hdr hdr;
+ u32 adapter_flash_buf_offset;
+ u32 adapter_flash_len;
+} __attribute__((packed));
+
+union c2wr_flash_init {
+ struct c2wr_flash_init_req req;
+ struct c2wr_flash_init_rep rep;
+} __attribute__((packed));
+
+struct c2wr_flash_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 len;
+} __attribute__((packed));
+
+struct c2wr_flash_rep {
+ struct c2wr_hdr hdr;
+ u32 status;
+} __attribute__((packed));
+
+union c2wr_flash {
+ struct c2wr_flash_req req;
+ struct c2wr_flash_rep rep;
+} __attribute__((packed));
+
+struct c2wr_buf_alloc_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 size;
+} __attribute__((packed));
+
+struct c2wr_buf_alloc_rep {
+ struct c2wr_hdr hdr;
+ u32 offset; /* 0 if mem not available */
+ u32 size; /* 0 if mem not available */
+} __attribute__((packed));
+
+union c2wr_buf_alloc {
+ struct c2wr_buf_alloc_req req;
+ struct c2wr_buf_alloc_rep rep;
+} __attribute__((packed));
+
+struct c2wr_buf_free_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 offset; /* Must match value from alloc */
+ u32 size; /* Must match value from alloc */
+} __attribute__((packed));
+
+struct c2wr_buf_free_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_buf_free {
+ struct c2wr_buf_free_req req;
+ struct c2wr_ce rep;
+} __attribute__((packed));
+
+struct c2wr_flash_write_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 offset;
+ u32 size;
+ u32 type;
+ u32 flags;
+} __attribute__((packed));
+
+struct c2wr_flash_write_rep {
+ struct c2wr_hdr hdr;
+ u32 status;
+} __attribute__((packed));
+
+union c2wr_flash_write {
+ struct c2wr_flash_write_req req;
+ struct c2wr_flash_write_rep rep;
+} __attribute__((packed));
+
+/*
+ * Messages for LLP connection setup.
+ */
+
+/*
+ * Listen Request. This allocates a listening endpoint to allow passive
+ * connection setup. Newly established LLP connections are passed up
+ * via an AE. See c2wr_ae_connection_request_t
+ */
+struct c2wr_ep_listen_create_req {
+ struct c2wr_hdr hdr;
+ u64 user_context; /* returned in AEs. */
+ u32 rnic_handle;
+ u32 local_addr; /* local addr, or 0 */
+ u16 local_port; /* 0 means "pick one" */
+ u16 pad;
+ u32 backlog; /* tradional tcp listen bl */
+} __attribute__((packed));
+
+struct c2wr_ep_listen_create_rep {
+ struct c2wr_hdr hdr;
+ u32 ep_handle; /* handle to new listening ep */
+ u16 local_port; /* resulting port... */
+ u16 pad;
+} __attribute__((packed));
+
+union c2wr_ep_listen_create {
+ struct c2wr_ep_listen_create_req req;
+ struct c2wr_ep_listen_create_rep rep;
+} __attribute__((packed));
+
+struct c2wr_ep_listen_destroy_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 ep_handle;
+} __attribute__((packed));
+
+struct c2wr_ep_listen_destroy_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_ep_listen_destroy {
+ struct c2wr_ep_listen_destroy_req req;
+ struct c2wr_ep_listen_destroy_rep rep;
+} __attribute__((packed));
+
+struct c2wr_ep_query_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 ep_handle;
+} __attribute__((packed));
+
+struct c2wr_ep_query_rep {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 local_addr;
+ u32 remote_addr;
+ u16 local_port;
+ u16 remote_port;
+} __attribute__((packed));
+
+union c2wr_ep_query {
+ struct c2wr_ep_query_req req;
+ struct c2wr_ep_query_rep rep;
+} __attribute__((packed));
+
+
+/*
+ * The host passes this down to indicate acceptance of a pending iWARP
+ * connection. The cr_handle was obtained from the CONNECTION_REQUEST
+ * AE passed up by the adapter. See c2wr_ae_connection_request_t.
+ */
+struct c2wr_cr_accept_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 qp_handle; /* QP to bind to this LLP conn */
+ u32 ep_handle; /* LLP handle to accept */
+ u32 private_data_length;
+ u8 private_data[0]; /* data in-line in msg. */
+} __attribute__((packed));
+
+/*
+ * adapter sends reply when private data is successfully submitted to
+ * the LLP.
+ */
+struct c2wr_cr_accept_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_cr_accept {
+ struct c2wr_cr_accept_req req;
+ struct c2wr_cr_accept_rep rep;
+} __attribute__((packed));
+
+/*
+ * The host sends this down if a given iWARP connection request was
+ * rejected by the consumer. The cr_handle was obtained from a
+ * previous c2wr_ae_connection_request_t AE sent by the adapter.
+ */
+struct c2wr_cr_reject_req {
+ struct c2wr_hdr hdr;
+ u32 rnic_handle;
+ u32 ep_handle; /* LLP handle to reject */
+} __attribute__((packed));
+
+/*
+ * Dunno if this is needed, but we'll add it for now. The adapter will
+ * send the reject_reply after the LLP endpoint has been destroyed.
+ */
+struct c2wr_cr_reject_rep {
+ struct c2wr_hdr hdr;
+} __attribute__((packed));
+
+union c2wr_cr_reject {
+ struct c2wr_cr_reject_req req;
+ struct c2wr_cr_reject_rep rep;
+} __attribute__((packed));
+
+/*
+ * console command. Used to implement a debug console over the verbs
+ * request and reply queues.
+ */
+
+/*
+ * Console request message. It contains:
+ * - message hdr with id = CCWR_CONSOLE
+ * - the physaddr/len of host memory to be used for the reply.
+ * - the command string. eg: "netstat -s" or "zoneinfo"
+ */
+struct c2wr_console_req {
+ struct c2wr_hdr hdr; /* id = CCWR_CONSOLE */
+ u64 reply_buf; /* pinned host buf for reply */
+ u32 reply_buf_len; /* length of reply buffer */
+ u8 command[0]; /* NUL terminated ascii string */
+ /* containing the command req */
+} __attribute__((packed));
+
+/*
+ * flags used in the console reply.
+ */
+enum c2_console_flags {
+ CONS_REPLY_TRUNCATED = 0x00000001 /* reply was truncated */
+} __attribute__((packed));
+
+/*
+ * Console reply message.
+ * hdr.result contains the c2_status_t error if the reply was _not_ generated,
+ * or C2_OK if the reply was generated.
+ */
+struct c2wr_console_rep {
+ struct c2wr_hdr hdr; /* id = CCWR_CONSOLE */
+ u32 flags;
+} __attribute__((packed));
+
+union c2wr_console {
+ struct c2wr_console_req req;
+ struct c2wr_console_rep rep;
+} __attribute__((packed));
+
+
+/*
+ * Giant union with all WRs. Makes life easier...
+ */
+union c2wr {
+ struct c2wr_hdr hdr;
+ struct c2wr_user_hdr user_hdr;
+ union c2wr_rnic_open rnic_open;
+ union c2wr_rnic_query rnic_query;
+ union c2wr_rnic_getconfig rnic_getconfig;
+ union c2wr_rnic_setconfig rnic_setconfig;
+ union c2wr_rnic_close rnic_close;
+ union c2wr_cq_create cq_create;
+ union c2wr_cq_modify cq_modify;
+ union c2wr_cq_destroy cq_destroy;
+ union c2wr_pd_alloc pd_alloc;
+ union c2wr_pd_dealloc pd_dealloc;
+ union c2wr_srq_create srq_create;
+ union c2wr_srq_destroy srq_destroy;
+ union c2wr_qp_create qp_create;
+ union c2wr_qp_query qp_query;
+ union c2wr_qp_modify qp_modify;
+ union c2wr_qp_destroy qp_destroy;
+ struct c2wr_qp_connect qp_connect;
+ union c2wr_nsmr_stag_alloc nsmr_stag_alloc;
+ union c2wr_nsmr_register nsmr_register;
+ union c2wr_nsmr_pbl nsmr_pbl;
+ union c2wr_mr_query mr_query;
+ union c2wr_mw_query mw_query;
+ union c2wr_stag_dealloc stag_dealloc;
+ union c2wr_sqwr sqwr;
+ struct c2wr_rqwr rqwr;
+ struct c2wr_ce ce;
+ union c2wr_ae ae;
+ union c2wr_init init;
+ union c2wr_ep_listen_create ep_listen_create;
+ union c2wr_ep_listen_destroy ep_listen_destroy;
+ union c2wr_cr_accept cr_accept;
+ union c2wr_cr_reject cr_reject;
+ union c2wr_console console;
+ union c2wr_flash_init flash_init;
+ union c2wr_flash flash;
+ union c2wr_buf_alloc buf_alloc;
+ union c2wr_buf_free buf_free;
+ union c2wr_flash_write flash_write;
+} __attribute__((packed));
+
+
+/*
+ * Accessors for the wr fields that are packed together tightly to
+ * reduce the wr message size. The wr arguments are void* so that
+ * either a struct c2wr*, a struct c2wr_hdr*, or a pointer to any of the types
+ * in the struct c2wr union can be passed in.
+ */
+static __inline__ u8 c2_wr_get_id(void *wr)
+{
+ return ((struct c2wr_hdr *) wr)->id;
+}
+static __inline__ void c2_wr_set_id(void *wr, u8 id)
+{
+ ((struct c2wr_hdr *) wr)->id = id;
+}
+static __inline__ u8 c2_wr_get_result(void *wr)
+{
+ return ((struct c2wr_hdr *) wr)->result;
+}
+static __inline__ void c2_wr_set_result(void *wr, u8 result)
+{
+ ((struct c2wr_hdr *) wr)->result = result;
+}
+static __inline__ u8 c2_wr_get_flags(void *wr)
+{
+ return ((struct c2wr_hdr *) wr)->flags;
+}
+static __inline__ void c2_wr_set_flags(void *wr, u8 flags)
+{
+ ((struct c2wr_hdr *) wr)->flags = flags;
+}
+static __inline__ u8 c2_wr_get_sge_count(void *wr)
+{
+ return ((struct c2wr_hdr *) wr)->sge_count;
+}
+static __inline__ void c2_wr_set_sge_count(void *wr, u8 sge_count)
+{
+ ((struct c2wr_hdr *) wr)->sge_count = sge_count;
+}
+static __inline__ u32 c2_wr_get_wqe_count(void *wr)
+{
+ return ((struct c2wr_hdr *) wr)->wqe_count;
+}
+static __inline__ void c2_wr_set_wqe_count(void *wr, u32 wqe_count)
+{
+ ((struct c2wr_hdr *) wr)->wqe_count = wqe_count;
+}
+
+#endif /* _C2_WR_H_ */
diff --git a/drivers/infiniband/hw/ehca/Kconfig b/drivers/infiniband/hw/ehca/Kconfig
new file mode 100644
index 00000000000..922389b6439
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/Kconfig
@@ -0,0 +1,16 @@
+config INFINIBAND_EHCA
+ tristate "eHCA support"
+ depends on IBMEBUS && INFINIBAND
+ ---help---
+ This driver supports the IBM pSeries eHCA InfiniBand adapter.
+
+ To compile the driver as a module, choose M here. The module
+ will be called ib_ehca.
+
+config INFINIBAND_EHCA_SCALING
+ bool "Scaling support (EXPERIMENTAL)"
+ depends on IBMEBUS && INFINIBAND_EHCA && HOTPLUG_CPU && EXPERIMENTAL
+ ---help---
+ eHCA scaling support schedules the CQ callbacks to different CPUs.
+
+ To enable this feature choose Y here.
diff --git a/drivers/infiniband/hw/ehca/Makefile b/drivers/infiniband/hw/ehca/Makefile
new file mode 100644
index 00000000000..74d284e46a4
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/Makefile
@@ -0,0 +1,16 @@
+# Authors: Heiko J Schick <schickhj@de.ibm.com>
+# Christoph Raisch <raisch@de.ibm.com>
+# Joachim Fenkes <fenkes@de.ibm.com>
+#
+# Copyright (c) 2005 IBM Corporation
+#
+# All rights reserved.
+#
+# This source code is distributed under a dual license of GPL v2.0 and OpenIB BSD.
+
+obj-$(CONFIG_INFINIBAND_EHCA) += ib_ehca.o
+
+ib_ehca-objs = ehca_main.o ehca_hca.o ehca_mcast.o ehca_pd.o ehca_av.o ehca_eq.o \
+ ehca_cq.o ehca_qp.o ehca_sqp.o ehca_mrmw.o ehca_reqs.o ehca_irq.o \
+ ehca_uverbs.o ipz_pt_fn.o hcp_if.o hcp_phyp.o
+
diff --git a/drivers/infiniband/hw/ehca/ehca_av.c b/drivers/infiniband/hw/ehca/ehca_av.c
new file mode 100644
index 00000000000..3bac197f901
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_av.c
@@ -0,0 +1,271 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * adress vector functions
+ *
+ * Authors: Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Khadija Souissi <souissik@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <asm/current.h>
+
+#include "ehca_tools.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+
+static struct kmem_cache *av_cache;
+
+struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
+{
+ int ret;
+ struct ehca_av *av;
+ struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
+ ib_device);
+
+ av = kmem_cache_alloc(av_cache, SLAB_KERNEL);
+ if (!av) {
+ ehca_err(pd->device, "Out of memory pd=%p ah_attr=%p",
+ pd, ah_attr);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ av->av.sl = ah_attr->sl;
+ av->av.dlid = ah_attr->dlid;
+ av->av.slid_path_bits = ah_attr->src_path_bits;
+
+ if (ehca_static_rate < 0) {
+ int ah_mult = ib_rate_to_mult(ah_attr->static_rate);
+ int ehca_mult =
+ ib_rate_to_mult(shca->sport[ah_attr->port_num].rate );
+
+ if (ah_mult >= ehca_mult)
+ av->av.ipd = 0;
+ else
+ av->av.ipd = (ah_mult > 0) ?
+ ((ehca_mult - 1) / ah_mult) : 0;
+ } else
+ av->av.ipd = ehca_static_rate;
+
+ av->av.lnh = ah_attr->ah_flags;
+ av->av.grh.word_0 = EHCA_BMASK_SET(GRH_IPVERSION_MASK, 6);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_TCLASS_MASK,
+ ah_attr->grh.traffic_class);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
+ ah_attr->grh.flow_label);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
+ ah_attr->grh.hop_limit);
+ av->av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1B);
+ /* set sgid in grh.word_1 */
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ int rc;
+ struct ib_port_attr port_attr;
+ union ib_gid gid;
+ memset(&port_attr, 0, sizeof(port_attr));
+ rc = ehca_query_port(pd->device, ah_attr->port_num,
+ &port_attr);
+ if (rc) { /* invalid port number */
+ ret = -EINVAL;
+ ehca_err(pd->device, "Invalid port number "
+ "ehca_query_port() returned %x "
+ "pd=%p ah_attr=%p", rc, pd, ah_attr);
+ goto create_ah_exit1;
+ }
+ memset(&gid, 0, sizeof(gid));
+ rc = ehca_query_gid(pd->device,
+ ah_attr->port_num,
+ ah_attr->grh.sgid_index, &gid);
+ if (rc) {
+ ret = -EINVAL;
+ ehca_err(pd->device, "Failed to retrieve sgid "
+ "ehca_query_gid() returned %x "
+ "pd=%p ah_attr=%p", rc, pd, ah_attr);
+ goto create_ah_exit1;
+ }
+ memcpy(&av->av.grh.word_1, &gid, sizeof(gid));
+ }
+ /* for the time being we use a hard coded PMTU of 2048 Bytes */
+ av->av.pmtu = 4;
+
+ /* dgid comes in grh.word_3 */
+ memcpy(&av->av.grh.word_3, &ah_attr->grh.dgid,
+ sizeof(ah_attr->grh.dgid));
+
+ return &av->ib_ah;
+
+create_ah_exit1:
+ kmem_cache_free(av_cache, av);
+
+ return ERR_PTR(ret);
+}
+
+int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
+{
+ struct ehca_av *av;
+ struct ehca_ud_av new_ehca_av;
+ struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ u32 cur_pid = current->tgid;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ memset(&new_ehca_av, 0, sizeof(new_ehca_av));
+ new_ehca_av.sl = ah_attr->sl;
+ new_ehca_av.dlid = ah_attr->dlid;
+ new_ehca_av.slid_path_bits = ah_attr->src_path_bits;
+ new_ehca_av.ipd = ah_attr->static_rate;
+ new_ehca_av.lnh = EHCA_BMASK_SET(GRH_FLAG_MASK,
+ (ah_attr->ah_flags & IB_AH_GRH) > 0);
+ new_ehca_av.grh.word_0 = EHCA_BMASK_SET(GRH_TCLASS_MASK,
+ ah_attr->grh.traffic_class);
+ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_FLOWLABEL_MASK,
+ ah_attr->grh.flow_label);
+ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_HOPLIMIT_MASK,
+ ah_attr->grh.hop_limit);
+ new_ehca_av.grh.word_0 |= EHCA_BMASK_SET(GRH_NEXTHEADER_MASK, 0x1b);
+
+ /* set sgid in grh.word_1 */
+ if (ah_attr->ah_flags & IB_AH_GRH) {
+ int rc;
+ struct ib_port_attr port_attr;
+ union ib_gid gid;
+ memset(&port_attr, 0, sizeof(port_attr));
+ rc = ehca_query_port(ah->device, ah_attr->port_num,
+ &port_attr);
+ if (rc) { /* invalid port number */
+ ehca_err(ah->device, "Invalid port number "
+ "ehca_query_port() returned %x "
+ "ah=%p ah_attr=%p port_num=%x",
+ rc, ah, ah_attr, ah_attr->port_num);
+ return -EINVAL;
+ }
+ memset(&gid, 0, sizeof(gid));
+ rc = ehca_query_gid(ah->device,
+ ah_attr->port_num,
+ ah_attr->grh.sgid_index, &gid);
+ if (rc) {
+ ehca_err(ah->device, "Failed to retrieve sgid "
+ "ehca_query_gid() returned %x "
+ "ah=%p ah_attr=%p port_num=%x "
+ "sgid_index=%x",
+ rc, ah, ah_attr, ah_attr->port_num,
+ ah_attr->grh.sgid_index);
+ return -EINVAL;
+ }
+ memcpy(&new_ehca_av.grh.word_1, &gid, sizeof(gid));
+ }
+
+ new_ehca_av.pmtu = 4; /* see also comment in create_ah() */
+
+ memcpy(&new_ehca_av.grh.word_3, &ah_attr->grh.dgid,
+ sizeof(ah_attr->grh.dgid));
+
+ av = container_of(ah, struct ehca_av, ib_ah);
+ av->av = new_ehca_av;
+
+ return 0;
+}
+
+int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr)
+{
+ struct ehca_av *av = container_of(ah, struct ehca_av, ib_ah);
+ struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ u32 cur_pid = current->tgid;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ memcpy(&ah_attr->grh.dgid, &av->av.grh.word_3,
+ sizeof(ah_attr->grh.dgid));
+ ah_attr->sl = av->av.sl;
+
+ ah_attr->dlid = av->av.dlid;
+
+ ah_attr->src_path_bits = av->av.slid_path_bits;
+ ah_attr->static_rate = av->av.ipd;
+ ah_attr->ah_flags = EHCA_BMASK_GET(GRH_FLAG_MASK, av->av.lnh);
+ ah_attr->grh.traffic_class = EHCA_BMASK_GET(GRH_TCLASS_MASK,
+ av->av.grh.word_0);
+ ah_attr->grh.hop_limit = EHCA_BMASK_GET(GRH_HOPLIMIT_MASK,
+ av->av.grh.word_0);
+ ah_attr->grh.flow_label = EHCA_BMASK_GET(GRH_FLOWLABEL_MASK,
+ av->av.grh.word_0);
+
+ return 0;
+}
+
+int ehca_destroy_ah(struct ib_ah *ah)
+{
+ struct ehca_pd *my_pd = container_of(ah->pd, struct ehca_pd, ib_pd);
+ u32 cur_pid = current->tgid;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(ah->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ kmem_cache_free(av_cache, container_of(ah, struct ehca_av, ib_ah));
+
+ return 0;
+}
+
+int ehca_init_av_cache(void)
+{
+ av_cache = kmem_cache_create("ehca_cache_av",
+ sizeof(struct ehca_av), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!av_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_av_cache(void)
+{
+ if (av_cache)
+ kmem_cache_destroy(av_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
new file mode 100644
index 00000000000..1c722032319
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -0,0 +1,346 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Struct definition for eHCA internal structures
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_CLASSES_H__
+#define __EHCA_CLASSES_H__
+
+#include "ehca_classes.h"
+#include "ipz_pt_fn.h"
+
+struct ehca_module;
+struct ehca_qp;
+struct ehca_cq;
+struct ehca_eq;
+struct ehca_mr;
+struct ehca_mw;
+struct ehca_pd;
+struct ehca_av;
+
+#ifdef CONFIG_PPC64
+#include "ehca_classes_pSeries.h"
+#endif
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "ehca_irq.h"
+
+struct ehca_eq {
+ u32 length;
+ struct ipz_queue ipz_queue;
+ struct ipz_eq_handle ipz_eq_handle;
+ struct work_struct work;
+ struct h_galpas galpas;
+ int is_initialized;
+ struct ehca_pfeq pf;
+ spinlock_t spinlock;
+ struct tasklet_struct interrupt_task;
+ u32 ist;
+};
+
+struct ehca_sport {
+ struct ib_cq *ibcq_aqp1;
+ struct ib_qp *ibqp_aqp1;
+ enum ib_rate rate;
+ enum ib_port_state port_state;
+};
+
+struct ehca_shca {
+ struct ib_device ib_device;
+ struct ibmebus_dev *ibmebus_dev;
+ u8 num_ports;
+ int hw_level;
+ struct list_head shca_list;
+ struct ipz_adapter_handle ipz_hca_handle;
+ struct ehca_sport sport[2];
+ struct ehca_eq eq;
+ struct ehca_eq neq;
+ struct ehca_mr *maxmr;
+ struct ehca_pd *pd;
+ struct h_galpas galpas;
+};
+
+struct ehca_pd {
+ struct ib_pd ib_pd;
+ struct ipz_pd fw_pd;
+ u32 ownpid;
+};
+
+struct ehca_qp {
+ struct ib_qp ib_qp;
+ u32 qp_type;
+ struct ipz_queue ipz_squeue;
+ struct ipz_queue ipz_rqueue;
+ struct h_galpas galpas;
+ u32 qkey;
+ u32 real_qp_num;
+ u32 token;
+ spinlock_t spinlock_s;
+ spinlock_t spinlock_r;
+ u32 sq_max_inline_data_size;
+ struct ipz_qp_handle ipz_qp_handle;
+ struct ehca_pfqp pf;
+ struct ib_qp_init_attr init_attr;
+ u64 uspace_squeue;
+ u64 uspace_rqueue;
+ u64 uspace_fwh;
+ struct ehca_cq *send_cq;
+ struct ehca_cq *recv_cq;
+ unsigned int sqerr_purgeflag;
+ struct hlist_node list_entries;
+};
+
+/* must be power of 2 */
+#define QP_HASHTAB_LEN 8
+
+struct ehca_cq {
+ struct ib_cq ib_cq;
+ struct ipz_queue ipz_queue;
+ struct h_galpas galpas;
+ spinlock_t spinlock;
+ u32 cq_number;
+ u32 token;
+ u32 nr_of_entries;
+ struct ipz_cq_handle ipz_cq_handle;
+ struct ehca_pfcq pf;
+ spinlock_t cb_lock;
+ u64 uspace_queue;
+ u64 uspace_fwh;
+ struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
+ struct list_head entry;
+ u32 nr_callbacks;
+ spinlock_t task_lock;
+ u32 ownpid;
+};
+
+enum ehca_mr_flag {
+ EHCA_MR_FLAG_FMR = 0x80000000, /* FMR, created with ehca_alloc_fmr */
+ EHCA_MR_FLAG_MAXMR = 0x40000000, /* max-MR */
+};
+
+struct ehca_mr {
+ union {
+ struct ib_mr ib_mr; /* must always be first in ehca_mr */
+ struct ib_fmr ib_fmr; /* must always be first in ehca_mr */
+ } ib;
+ spinlock_t mrlock;
+
+ enum ehca_mr_flag flags;
+ u32 num_pages; /* number of MR pages */
+ u32 num_4k; /* number of 4k "page" portions to form MR */
+ int acl; /* ACL (stored here for usage in reregister) */
+ u64 *start; /* virtual start address (stored here for */
+ /* usage in reregister) */
+ u64 size; /* size (stored here for usage in reregister) */
+ u32 fmr_page_size; /* page size for FMR */
+ u32 fmr_max_pages; /* max pages for FMR */
+ u32 fmr_max_maps; /* max outstanding maps for FMR */
+ u32 fmr_map_cnt; /* map counter for FMR */
+ /* fw specific data */
+ struct ipz_mrmw_handle ipz_mr_handle; /* MR handle for h-calls */
+ struct h_galpas galpas;
+ /* data for userspace bridge */
+ u32 nr_of_pages;
+ void *pagearray;
+};
+
+struct ehca_mw {
+ struct ib_mw ib_mw; /* gen2 mw, must always be first in ehca_mw */
+ spinlock_t mwlock;
+
+ u8 never_bound; /* indication MW was never bound */
+ struct ipz_mrmw_handle ipz_mw_handle; /* MW handle for h-calls */
+ struct h_galpas galpas;
+};
+
+enum ehca_mr_pgi_type {
+ EHCA_MR_PGI_PHYS = 1, /* type of ehca_reg_phys_mr,
+ * ehca_rereg_phys_mr,
+ * ehca_reg_internal_maxmr */
+ EHCA_MR_PGI_USER = 2, /* type of ehca_reg_user_mr */
+ EHCA_MR_PGI_FMR = 3 /* type of ehca_map_phys_fmr */
+};
+
+struct ehca_mr_pginfo {
+ enum ehca_mr_pgi_type type;
+ u64 num_pages;
+ u64 page_cnt;
+ u64 num_4k; /* number of 4k "page" portions */
+ u64 page_4k_cnt; /* counter for 4k "page" portions */
+ u64 next_4k; /* next 4k "page" portion in buffer/chunk/listelem */
+
+ /* type EHCA_MR_PGI_PHYS section */
+ int num_phys_buf;
+ struct ib_phys_buf *phys_buf_array;
+ u64 next_buf;
+
+ /* type EHCA_MR_PGI_USER section */
+ struct ib_umem *region;
+ struct ib_umem_chunk *next_chunk;
+ u64 next_nmap;
+
+ /* type EHCA_MR_PGI_FMR section */
+ u64 *page_list;
+ u64 next_listelem;
+ /* next_4k also used within EHCA_MR_PGI_FMR */
+};
+
+/* output parameters for MR/FMR hipz calls */
+struct ehca_mr_hipzout_parms {
+ struct ipz_mrmw_handle handle;
+ u32 lkey;
+ u32 rkey;
+ u64 len;
+ u64 vaddr;
+ u32 acl;
+};
+
+/* output parameters for MW hipz calls */
+struct ehca_mw_hipzout_parms {
+ struct ipz_mrmw_handle handle;
+ u32 rkey;
+};
+
+struct ehca_av {
+ struct ib_ah ib_ah;
+ struct ehca_ud_av av;
+};
+
+struct ehca_ucontext {
+ struct ib_ucontext ib_ucontext;
+};
+
+struct ehca_module *ehca_module_new(void);
+
+int ehca_module_delete(struct ehca_module *me);
+
+int ehca_eq_ctor(struct ehca_eq *eq);
+
+int ehca_eq_dtor(struct ehca_eq *eq);
+
+struct ehca_shca *ehca_shca_new(void);
+
+int ehca_shca_delete(struct ehca_shca *me);
+
+struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
+
+int ehca_init_pd_cache(void);
+void ehca_cleanup_pd_cache(void);
+int ehca_init_cq_cache(void);
+void ehca_cleanup_cq_cache(void);
+int ehca_init_qp_cache(void);
+void ehca_cleanup_qp_cache(void);
+int ehca_init_av_cache(void);
+void ehca_cleanup_av_cache(void);
+int ehca_init_mrmw_cache(void);
+void ehca_cleanup_mrmw_cache(void);
+
+extern spinlock_t ehca_qp_idr_lock;
+extern spinlock_t ehca_cq_idr_lock;
+extern struct idr ehca_qp_idr;
+extern struct idr ehca_cq_idr;
+
+extern int ehca_static_rate;
+extern int ehca_port_act_time;
+extern int ehca_use_hp_mr;
+
+struct ipzu_queue_resp {
+ u64 queue; /* points to first queue entry */
+ u32 qe_size; /* queue entry size */
+ u32 act_nr_of_sg;
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state;
+ u32 dummy; /* padding for 8 byte alignment */
+};
+
+struct ehca_create_cq_resp {
+ u32 cq_number;
+ u32 token;
+ struct ipzu_queue_resp ipz_queue;
+ struct h_galpas galpas;
+};
+
+struct ehca_create_qp_resp {
+ u32 qp_num;
+ u32 token;
+ u32 qp_type;
+ u32 qkey;
+ /* qp_num assigned by ehca: sqp0/1 may have got different numbers */
+ u32 real_qp_num;
+ u32 dummy; /* padding for 8 byte alignment */
+ struct ipzu_queue_resp ipz_squeue;
+ struct ipzu_queue_resp ipz_rqueue;
+ struct h_galpas galpas;
+};
+
+struct ehca_alloc_cq_parms {
+ u32 nr_cqe;
+ u32 act_nr_of_entries;
+ u32 act_pages;
+ struct ipz_eq_handle eq_handle;
+};
+
+struct ehca_alloc_qp_parms {
+ int servicetype;
+ int sigtype;
+ int daqp_ctrl;
+ int max_send_sge;
+ int max_recv_sge;
+ int ud_av_l_key_ctl;
+
+ u16 act_nr_send_wqes;
+ u16 act_nr_recv_wqes;
+ u8 act_nr_recv_sges;
+ u8 act_nr_send_sges;
+
+ u32 nr_rq_pages;
+ u32 nr_sq_pages;
+
+ struct ipz_eq_handle ipz_eq_handle;
+ struct ipz_pd pd;
+};
+
+int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp);
+int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int qp_num);
+struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int qp_num);
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
new file mode 100644
index 00000000000..5665f213b81
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_classes_pSeries.h
@@ -0,0 +1,236 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * pSeries interface definitions
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_CLASSES_PSERIES_H__
+#define __EHCA_CLASSES_PSERIES_H__
+
+#include "hcp_phyp.h"
+#include "ipz_pt_fn.h"
+
+
+struct ehca_pfqp {
+ struct ipz_qpt sqpt;
+ struct ipz_qpt rqpt;
+};
+
+struct ehca_pfcq {
+ struct ipz_qpt qpt;
+ u32 cqnr;
+};
+
+struct ehca_pfeq {
+ struct ipz_qpt qpt;
+ struct h_galpa galpa;
+ u32 eqnr;
+};
+
+struct ipz_adapter_handle {
+ u64 handle;
+};
+
+struct ipz_cq_handle {
+ u64 handle;
+};
+
+struct ipz_eq_handle {
+ u64 handle;
+};
+
+struct ipz_qp_handle {
+ u64 handle;
+};
+struct ipz_mrmw_handle {
+ u64 handle;
+};
+
+struct ipz_pd {
+ u32 value;
+};
+
+struct hcp_modify_qp_control_block {
+ u32 qkey; /* 00 */
+ u32 rdd; /* reliable datagram domain */
+ u32 send_psn; /* 02 */
+ u32 receive_psn; /* 03 */
+ u32 prim_phys_port; /* 04 */
+ u32 alt_phys_port; /* 05 */
+ u32 prim_p_key_idx; /* 06 */
+ u32 alt_p_key_idx; /* 07 */
+ u32 rdma_atomic_ctrl; /* 08 */
+ u32 qp_state; /* 09 */
+ u32 reserved_10; /* 10 */
+ u32 rdma_nr_atomic_resp_res; /* 11 */
+ u32 path_migration_state; /* 12 */
+ u32 rdma_atomic_outst_dest_qp; /* 13 */
+ u32 dest_qp_nr; /* 14 */
+ u32 min_rnr_nak_timer_field; /* 15 */
+ u32 service_level; /* 16 */
+ u32 send_grh_flag; /* 17 */
+ u32 retry_count; /* 18 */
+ u32 timeout; /* 19 */
+ u32 path_mtu; /* 20 */
+ u32 max_static_rate; /* 21 */
+ u32 dlid; /* 22 */
+ u32 rnr_retry_count; /* 23 */
+ u32 source_path_bits; /* 24 */
+ u32 traffic_class; /* 25 */
+ u32 hop_limit; /* 26 */
+ u32 source_gid_idx; /* 27 */
+ u32 flow_label; /* 28 */
+ u32 reserved_29; /* 29 */
+ union { /* 30 */
+ u64 dw[2];
+ u8 byte[16];
+ } dest_gid;
+ u32 service_level_al; /* 34 */
+ u32 send_grh_flag_al; /* 35 */
+ u32 retry_count_al; /* 36 */
+ u32 timeout_al; /* 37 */
+ u32 max_static_rate_al; /* 38 */
+ u32 dlid_al; /* 39 */
+ u32 rnr_retry_count_al; /* 40 */
+ u32 source_path_bits_al; /* 41 */
+ u32 traffic_class_al; /* 42 */
+ u32 hop_limit_al; /* 43 */
+ u32 source_gid_idx_al; /* 44 */
+ u32 flow_label_al; /* 45 */
+ u32 reserved_46; /* 46 */
+ u32 reserved_47; /* 47 */
+ union { /* 48 */
+ u64 dw[2];
+ u8 byte[16];
+ } dest_gid_al;
+ u32 max_nr_outst_send_wr; /* 52 */
+ u32 max_nr_outst_recv_wr; /* 53 */
+ u32 disable_ete_credit_check; /* 54 */
+ u32 qp_number; /* 55 */
+ u64 send_queue_handle; /* 56 */
+ u64 recv_queue_handle; /* 58 */
+ u32 actual_nr_sges_in_sq_wqe; /* 60 */
+ u32 actual_nr_sges_in_rq_wqe; /* 61 */
+ u32 qp_enable; /* 62 */
+ u32 curr_srq_limit; /* 63 */
+ u64 qp_aff_asyn_ev_log_reg; /* 64 */
+ u64 shared_rq_hndl; /* 66 */
+ u64 trigg_doorbell_qp_hndl; /* 68 */
+ u32 reserved_70_127[58]; /* 70 */
+};
+
+#define MQPCB_MASK_QKEY EHCA_BMASK_IBM(0,0)
+#define MQPCB_MASK_SEND_PSN EHCA_BMASK_IBM(2,2)
+#define MQPCB_MASK_RECEIVE_PSN EHCA_BMASK_IBM(3,3)
+#define MQPCB_MASK_PRIM_PHYS_PORT EHCA_BMASK_IBM(4,4)
+#define MQPCB_PRIM_PHYS_PORT EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_ALT_PHYS_PORT EHCA_BMASK_IBM(5,5)
+#define MQPCB_MASK_PRIM_P_KEY_IDX EHCA_BMASK_IBM(6,6)
+#define MQPCB_PRIM_P_KEY_IDX EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_ALT_P_KEY_IDX EHCA_BMASK_IBM(7,7)
+#define MQPCB_MASK_RDMA_ATOMIC_CTRL EHCA_BMASK_IBM(8,8)
+#define MQPCB_MASK_QP_STATE EHCA_BMASK_IBM(9,9)
+#define MQPCB_QP_STATE EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES EHCA_BMASK_IBM(11,11)
+#define MQPCB_MASK_PATH_MIGRATION_STATE EHCA_BMASK_IBM(12,12)
+#define MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP EHCA_BMASK_IBM(13,13)
+#define MQPCB_MASK_DEST_QP_NR EHCA_BMASK_IBM(14,14)
+#define MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD EHCA_BMASK_IBM(15,15)
+#define MQPCB_MASK_SERVICE_LEVEL EHCA_BMASK_IBM(16,16)
+#define MQPCB_MASK_SEND_GRH_FLAG EHCA_BMASK_IBM(17,17)
+#define MQPCB_MASK_RETRY_COUNT EHCA_BMASK_IBM(18,18)
+#define MQPCB_MASK_TIMEOUT EHCA_BMASK_IBM(19,19)
+#define MQPCB_MASK_PATH_MTU EHCA_BMASK_IBM(20,20)
+#define MQPCB_PATH_MTU EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_MAX_STATIC_RATE EHCA_BMASK_IBM(21,21)
+#define MQPCB_MAX_STATIC_RATE EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_DLID EHCA_BMASK_IBM(22,22)
+#define MQPCB_DLID EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_RNR_RETRY_COUNT EHCA_BMASK_IBM(23,23)
+#define MQPCB_RNR_RETRY_COUNT EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_SOURCE_PATH_BITS EHCA_BMASK_IBM(24,24)
+#define MQPCB_SOURCE_PATH_BITS EHCA_BMASK_IBM(25,31)
+#define MQPCB_MASK_TRAFFIC_CLASS EHCA_BMASK_IBM(25,25)
+#define MQPCB_TRAFFIC_CLASS EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_HOP_LIMIT EHCA_BMASK_IBM(26,26)
+#define MQPCB_HOP_LIMIT EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_SOURCE_GID_IDX EHCA_BMASK_IBM(27,27)
+#define MQPCB_SOURCE_GID_IDX EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_FLOW_LABEL EHCA_BMASK_IBM(28,28)
+#define MQPCB_FLOW_LABEL EHCA_BMASK_IBM(12,31)
+#define MQPCB_MASK_DEST_GID EHCA_BMASK_IBM(30,30)
+#define MQPCB_MASK_SERVICE_LEVEL_AL EHCA_BMASK_IBM(31,31)
+#define MQPCB_SERVICE_LEVEL_AL EHCA_BMASK_IBM(28,31)
+#define MQPCB_MASK_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(32,32)
+#define MQPCB_SEND_GRH_FLAG_AL EHCA_BMASK_IBM(31,31)
+#define MQPCB_MASK_RETRY_COUNT_AL EHCA_BMASK_IBM(33,33)
+#define MQPCB_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_TIMEOUT_AL EHCA_BMASK_IBM(34,34)
+#define MQPCB_TIMEOUT_AL EHCA_BMASK_IBM(27,31)
+#define MQPCB_MASK_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(35,35)
+#define MQPCB_MAX_STATIC_RATE_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_DLID_AL EHCA_BMASK_IBM(36,36)
+#define MQPCB_DLID_AL EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(37,37)
+#define MQPCB_RNR_RETRY_COUNT_AL EHCA_BMASK_IBM(29,31)
+#define MQPCB_MASK_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(38,38)
+#define MQPCB_SOURCE_PATH_BITS_AL EHCA_BMASK_IBM(25,31)
+#define MQPCB_MASK_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(39,39)
+#define MQPCB_TRAFFIC_CLASS_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_HOP_LIMIT_AL EHCA_BMASK_IBM(40,40)
+#define MQPCB_HOP_LIMIT_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(41,41)
+#define MQPCB_SOURCE_GID_IDX_AL EHCA_BMASK_IBM(24,31)
+#define MQPCB_MASK_FLOW_LABEL_AL EHCA_BMASK_IBM(42,42)
+#define MQPCB_FLOW_LABEL_AL EHCA_BMASK_IBM(12,31)
+#define MQPCB_MASK_DEST_GID_AL EHCA_BMASK_IBM(44,44)
+#define MQPCB_MASK_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(45,45)
+#define MQPCB_MAX_NR_OUTST_SEND_WR EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(46,46)
+#define MQPCB_MAX_NR_OUTST_RECV_WR EHCA_BMASK_IBM(16,31)
+#define MQPCB_MASK_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(47,47)
+#define MQPCB_DISABLE_ETE_CREDIT_CHECK EHCA_BMASK_IBM(31,31)
+#define MQPCB_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define MQPCB_MASK_QP_ENABLE EHCA_BMASK_IBM(48,48)
+#define MQPCB_QP_ENABLE EHCA_BMASK_IBM(31,31)
+#define MQPCB_MASK_CURR_SQR_LIMIT EHCA_BMASK_IBM(49,49)
+#define MQPCB_CURR_SQR_LIMIT EHCA_BMASK_IBM(15,31)
+#define MQPCB_MASK_QP_AFF_ASYN_EV_LOG_REG EHCA_BMASK_IBM(50,50)
+#define MQPCB_MASK_SHARED_RQ_HNDL EHCA_BMASK_IBM(51,51)
+
+#endif /* __EHCA_CLASSES_PSERIES_H__ */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
new file mode 100644
index 00000000000..458fe19648a
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -0,0 +1,427 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Completion queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ *
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/current.h>
+
+#include "ehca_iverbs.h"
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "hcp_if.h"
+
+static struct kmem_cache *cq_cache;
+
+int ehca_cq_assign_qp(struct ehca_cq *cq, struct ehca_qp *qp)
+{
+ unsigned int qp_num = qp->real_qp_num;
+ unsigned int key = qp_num & (QP_HASHTAB_LEN-1);
+ unsigned long spl_flags;
+
+ spin_lock_irqsave(&cq->spinlock, spl_flags);
+ hlist_add_head(&qp->list_entries, &cq->qp_hashtab[key]);
+ spin_unlock_irqrestore(&cq->spinlock, spl_flags);
+
+ ehca_dbg(cq->ib_cq.device, "cq_num=%x real_qp_num=%x",
+ cq->cq_number, qp_num);
+
+ return 0;
+}
+
+int ehca_cq_unassign_qp(struct ehca_cq *cq, unsigned int real_qp_num)
+{
+ int ret = -EINVAL;
+ unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
+ struct hlist_node *iter;
+ struct ehca_qp *qp;
+ unsigned long spl_flags;
+
+ spin_lock_irqsave(&cq->spinlock, spl_flags);
+ hlist_for_each(iter, &cq->qp_hashtab[key]) {
+ qp = hlist_entry(iter, struct ehca_qp, list_entries);
+ if (qp->real_qp_num == real_qp_num) {
+ hlist_del(iter);
+ ehca_dbg(cq->ib_cq.device,
+ "removed qp from cq .cq_num=%x real_qp_num=%x",
+ cq->cq_number, real_qp_num);
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cq->spinlock, spl_flags);
+ if (ret)
+ ehca_err(cq->ib_cq.device,
+ "qp not found cq_num=%x real_qp_num=%x",
+ cq->cq_number, real_qp_num);
+
+ return ret;
+}
+
+struct ehca_qp* ehca_cq_get_qp(struct ehca_cq *cq, int real_qp_num)
+{
+ struct ehca_qp *ret = NULL;
+ unsigned int key = real_qp_num & (QP_HASHTAB_LEN-1);
+ struct hlist_node *iter;
+ struct ehca_qp *qp;
+ hlist_for_each(iter, &cq->qp_hashtab[key]) {
+ qp = hlist_entry(iter, struct ehca_qp, list_entries);
+ if (qp->real_qp_num == real_qp_num) {
+ ret = qp;
+ break;
+ }
+ }
+ return ret;
+}
+
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
+{
+ static const u32 additional_cqe = 20;
+ struct ib_cq *cq;
+ struct ehca_cq *my_cq;
+ struct ehca_shca *shca =
+ container_of(device, struct ehca_shca, ib_device);
+ struct ipz_adapter_handle adapter_handle;
+ struct ehca_alloc_cq_parms param; /* h_call's out parameters */
+ struct h_galpa gal;
+ void *vpage;
+ u32 counter;
+ u64 rpage, cqx_fec, h_ret;
+ int ipz_rc, ret, i;
+ unsigned long flags;
+
+ if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
+ return ERR_PTR(-EINVAL);
+
+ my_cq = kmem_cache_alloc(cq_cache, SLAB_KERNEL);
+ if (!my_cq) {
+ ehca_err(device, "Out of memory for ehca_cq struct device=%p",
+ device);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(my_cq, 0, sizeof(struct ehca_cq));
+ memset(&param, 0, sizeof(struct ehca_alloc_cq_parms));
+
+ spin_lock_init(&my_cq->spinlock);
+ spin_lock_init(&my_cq->cb_lock);
+ spin_lock_init(&my_cq->task_lock);
+ my_cq->ownpid = current->tgid;
+
+ cq = &my_cq->ib_cq;
+
+ adapter_handle = shca->ipz_hca_handle;
+ param.eq_handle = shca->eq.ipz_eq_handle;
+
+ do {
+ if (!idr_pre_get(&ehca_cq_idr, GFP_KERNEL)) {
+ cq = ERR_PTR(-ENOMEM);
+ ehca_err(device, "Can't reserve idr nr. device=%p",
+ device);
+ goto create_cq_exit1;
+ }
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ ret = idr_get_new(&ehca_cq_idr, my_cq, &my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ } while (ret == -EAGAIN);
+
+ if (ret) {
+ cq = ERR_PTR(-ENOMEM);
+ ehca_err(device, "Can't allocate new idr entry. device=%p",
+ device);
+ goto create_cq_exit1;
+ }
+
+ /*
+ * CQs maximum depth is 4GB-64, but we need additional 20 as buffer
+ * for receiving errors CQEs.
+ */
+ param.nr_cqe = cqe + additional_cqe;
+ h_ret = hipz_h_alloc_resource_cq(adapter_handle, my_cq, &param);
+
+ if (h_ret != H_SUCCESS) {
+ ehca_err(device, "hipz_h_alloc_resource_cq() failed "
+ "h_ret=%lx device=%p", h_ret, device);
+ cq = ERR_PTR(ehca2ib_return_code(h_ret));
+ goto create_cq_exit2;
+ }
+
+ ipz_rc = ipz_queue_ctor(&my_cq->ipz_queue, param.act_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_cqe), 0);
+ if (!ipz_rc) {
+ ehca_err(device, "ipz_queue_ctor() failed ipz_rc=%x device=%p",
+ ipz_rc, device);
+ cq = ERR_PTR(-EINVAL);
+ goto create_cq_exit3;
+ }
+
+ for (counter = 0; counter < param.act_pages; counter++) {
+ vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
+ if (!vpage) {
+ ehca_err(device, "ipz_qpageit_get_inc() "
+ "returns NULL device=%p", device);
+ cq = ERR_PTR(-EAGAIN);
+ goto create_cq_exit4;
+ }
+ rpage = virt_to_abs(vpage);
+
+ h_ret = hipz_h_register_rpage_cq(adapter_handle,
+ my_cq->ipz_cq_handle,
+ &my_cq->pf,
+ 0,
+ 0,
+ rpage,
+ 1,
+ my_cq->galpas.
+ kernel);
+
+ if (h_ret < H_SUCCESS) {
+ ehca_err(device, "hipz_h_register_rpage_cq() failed "
+ "ehca_cq=%p cq_num=%x h_ret=%lx counter=%i "
+ "act_pages=%i", my_cq, my_cq->cq_number,
+ h_ret, counter, param.act_pages);
+ cq = ERR_PTR(-EINVAL);
+ goto create_cq_exit4;
+ }
+
+ if (counter == (param.act_pages - 1)) {
+ vpage = ipz_qpageit_get_inc(&my_cq->ipz_queue);
+ if ((h_ret != H_SUCCESS) || vpage) {
+ ehca_err(device, "Registration of pages not "
+ "complete ehca_cq=%p cq_num=%x "
+ "h_ret=%lx", my_cq, my_cq->cq_number,
+ h_ret);
+ cq = ERR_PTR(-EAGAIN);
+ goto create_cq_exit4;
+ }
+ } else {
+ if (h_ret != H_PAGE_REGISTERED) {
+ ehca_err(device, "Registration of page failed "
+ "ehca_cq=%p cq_num=%x h_ret=%lx"
+ "counter=%i act_pages=%i",
+ my_cq, my_cq->cq_number,
+ h_ret, counter, param.act_pages);
+ cq = ERR_PTR(-ENOMEM);
+ goto create_cq_exit4;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&my_cq->ipz_queue);
+
+ gal = my_cq->galpas.kernel;
+ cqx_fec = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_fec));
+ ehca_dbg(device, "ehca_cq=%p cq_num=%x CQX_FEC=%lx",
+ my_cq, my_cq->cq_number, cqx_fec);
+
+ my_cq->ib_cq.cqe = my_cq->nr_of_entries =
+ param.act_nr_of_entries - additional_cqe;
+ my_cq->cq_number = (my_cq->ipz_cq_handle.handle) & 0xffff;
+
+ for (i = 0; i < QP_HASHTAB_LEN; i++)
+ INIT_HLIST_HEAD(&my_cq->qp_hashtab[i]);
+
+ if (context) {
+ struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
+ struct ehca_create_cq_resp resp;
+ struct vm_area_struct *vma;
+ memset(&resp, 0, sizeof(resp));
+ resp.cq_number = my_cq->cq_number;
+ resp.token = my_cq->token;
+ resp.ipz_queue.qe_size = ipz_queue->qe_size;
+ resp.ipz_queue.act_nr_of_sg = ipz_queue->act_nr_of_sg;
+ resp.ipz_queue.queue_length = ipz_queue->queue_length;
+ resp.ipz_queue.pagesize = ipz_queue->pagesize;
+ resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
+ ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
+ ipz_queue->queue_length,
+ (void**)&resp.ipz_queue.queue,
+ &vma);
+ if (ret) {
+ ehca_err(device, "Could not mmap queue pages");
+ cq = ERR_PTR(ret);
+ goto create_cq_exit4;
+ }
+ my_cq->uspace_queue = resp.ipz_queue.queue;
+ resp.galpas = my_cq->galpas;
+ ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
+ (void**)&resp.galpas.kernel.fw_handle,
+ &vma);
+ if (ret) {
+ ehca_err(device, "Could not mmap fw_handle");
+ cq = ERR_PTR(ret);
+ goto create_cq_exit5;
+ }
+ my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
+ if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
+ ehca_err(device, "Copy to udata failed.");
+ goto create_cq_exit6;
+ }
+ }
+
+ return cq;
+
+create_cq_exit6:
+ ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
+
+create_cq_exit5:
+ ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
+
+create_cq_exit4:
+ ipz_queue_dtor(&my_cq->ipz_queue);
+
+create_cq_exit3:
+ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
+ if (h_ret != H_SUCCESS)
+ ehca_err(device, "hipz_h_destroy_cq() failed ehca_cq=%p "
+ "cq_num=%x h_ret=%lx", my_cq, my_cq->cq_number, h_ret);
+
+create_cq_exit2:
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ idr_remove(&ehca_cq_idr, my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+create_cq_exit1:
+ kmem_cache_free(cq_cache, my_cq);
+
+ return cq;
+}
+
+int ehca_destroy_cq(struct ib_cq *cq)
+{
+ u64 h_ret;
+ int ret;
+ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ int cq_num = my_cq->cq_number;
+ struct ib_device *device = cq->device;
+ struct ehca_shca *shca = container_of(device, struct ehca_shca,
+ ib_device);
+ struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ while (my_cq->nr_callbacks)
+ yield();
+
+ idr_remove(&ehca_cq_idr, my_cq->token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+ ehca_err(device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_cq->ownpid);
+ return -EINVAL;
+ }
+
+ /* un-mmap if vma alloc */
+ if (my_cq->uspace_queue ) {
+ ret = ehca_munmap(my_cq->uspace_queue,
+ my_cq->ipz_queue.queue_length);
+ if (ret)
+ ehca_err(device, "Could not munmap queue ehca_cq=%p "
+ "cq_num=%x", my_cq, cq_num);
+ ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
+ if (ret)
+ ehca_err(device, "Could not munmap fwh ehca_cq=%p "
+ "cq_num=%x", my_cq, cq_num);
+ }
+
+ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
+ if (h_ret == H_R_STATE) {
+ /* cq in err: read err data and destroy it forcibly */
+ ehca_dbg(device, "ehca_cq=%p cq_num=%x ressource=%lx in err "
+ "state. Try to delete it forcibly.",
+ my_cq, cq_num, my_cq->ipz_cq_handle.handle);
+ ehca_error_data(shca, my_cq, my_cq->ipz_cq_handle.handle);
+ h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 1);
+ if (h_ret == H_SUCCESS)
+ ehca_dbg(device, "cq_num=%x deleted successfully.",
+ cq_num);
+ }
+ if (h_ret != H_SUCCESS) {
+ ehca_err(device, "hipz_h_destroy_cq() failed h_ret=%lx "
+ "ehca_cq=%p cq_num=%x", h_ret, my_cq, cq_num);
+ return ehca2ib_return_code(h_ret);
+ }
+ ipz_queue_dtor(&my_cq->ipz_queue);
+ kmem_cache_free(cq_cache, my_cq);
+
+ return 0;
+}
+
+int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
+{
+ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ u32 cur_pid = current->tgid;
+
+ if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+ ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_cq->ownpid);
+ return -EINVAL;
+ }
+
+ /* TODO: proper resize needs to be done */
+ ehca_err(cq->device, "not implemented yet");
+
+ return -EFAULT;
+}
+
+int ehca_init_cq_cache(void)
+{
+ cq_cache = kmem_cache_create("ehca_cache_cq",
+ sizeof(struct ehca_cq), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!cq_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_cq_cache(void)
+{
+ if (cq_cache)
+ kmem_cache_destroy(cq_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
new file mode 100644
index 00000000000..5281dec66f1
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -0,0 +1,185 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Event queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ *
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "ehca_iverbs.h"
+#include "ehca_qes.h"
+#include "hcp_if.h"
+#include "ipz_pt_fn.h"
+
+int ehca_create_eq(struct ehca_shca *shca,
+ struct ehca_eq *eq,
+ const enum ehca_eq_type type, const u32 length)
+{
+ u64 ret;
+ u32 nr_pages;
+ u32 i;
+ void *vpage;
+ struct ib_device *ib_dev = &shca->ib_device;
+
+ spin_lock_init(&eq->spinlock);
+ eq->is_initialized = 0;
+
+ if (type != EHCA_EQ && type != EHCA_NEQ) {
+ ehca_err(ib_dev, "Invalid EQ type %x. eq=%p", type, eq);
+ return -EINVAL;
+ }
+ if (!length) {
+ ehca_err(ib_dev, "EQ length must not be zero. eq=%p", eq);
+ return -EINVAL;
+ }
+
+ ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
+ &eq->pf,
+ type,
+ length,
+ &eq->ipz_eq_handle,
+ &eq->length,
+ &nr_pages, &eq->ist);
+
+ if (ret != H_SUCCESS) {
+ ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq);
+ return -EINVAL;
+ }
+
+ ret = ipz_queue_ctor(&eq->ipz_queue, nr_pages,
+ EHCA_PAGESIZE, sizeof(struct ehca_eqe), 0);
+ if (!ret) {
+ ehca_err(ib_dev, "Can't allocate EQ pages eq=%p", eq);
+ goto create_eq_exit1;
+ }
+
+ for (i = 0; i < nr_pages; i++) {
+ u64 rpage;
+
+ if (!(vpage = ipz_qpageit_get_inc(&eq->ipz_queue))) {
+ ret = H_RESOURCE;
+ goto create_eq_exit2;
+ }
+
+ rpage = virt_to_abs(vpage);
+ ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
+ eq->ipz_eq_handle,
+ &eq->pf,
+ 0, 0, rpage, 1);
+
+ if (i == (nr_pages - 1)) {
+ /* last page */
+ vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
+ if (ret != H_SUCCESS || vpage)
+ goto create_eq_exit2;
+ } else {
+ if (ret != H_PAGE_REGISTERED || !vpage)
+ goto create_eq_exit2;
+ }
+ }
+
+ ipz_qeit_reset(&eq->ipz_queue);
+
+ /* register interrupt handlers and initialize work queues */
+ if (type == EHCA_EQ) {
+ ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_eq,
+ SA_INTERRUPT, "ehca_eq",
+ (void *)shca);
+ if (ret < 0)
+ ehca_err(ib_dev, "Can't map interrupt handler.");
+
+ tasklet_init(&eq->interrupt_task, ehca_tasklet_eq, (long)shca);
+ } else if (type == EHCA_NEQ) {
+ ret = ibmebus_request_irq(NULL, eq->ist, ehca_interrupt_neq,
+ SA_INTERRUPT, "ehca_neq",
+ (void *)shca);
+ if (ret < 0)
+ ehca_err(ib_dev, "Can't map interrupt handler.");
+
+ tasklet_init(&eq->interrupt_task, ehca_tasklet_neq, (long)shca);
+ }
+
+ eq->is_initialized = 1;
+
+ return 0;
+
+create_eq_exit2:
+ ipz_queue_dtor(&eq->ipz_queue);
+
+create_eq_exit1:
+ hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
+
+ return -EINVAL;
+}
+
+void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq)
+{
+ unsigned long flags;
+ void *eqe;
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ eqe = ipz_eqit_eq_get_inc_valid(&eq->ipz_queue);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ return eqe;
+}
+
+int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq)
+{
+ unsigned long flags;
+ u64 h_ret;
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ ibmebus_free_irq(NULL, eq->ist, (void *)shca);
+
+ h_ret = hipz_h_destroy_eq(shca->ipz_hca_handle, eq);
+
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't free EQ resources.");
+ return -EINVAL;
+ }
+ ipz_queue_dtor(&eq->ipz_queue);
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_hca.c b/drivers/infiniband/hw/ehca/ehca_hca.c
new file mode 100644
index 00000000000..5eae6ac4842
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_hca.c
@@ -0,0 +1,241 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HCA query functions
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props)
+{
+ int ret = 0;
+ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
+ ib_device);
+ struct hipz_query_hca *rblock;
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't query device properties");
+ ret = -EINVAL;
+ goto query_device1;
+ }
+
+ memset(props, 0, sizeof(struct ib_device_attr));
+ props->fw_ver = rblock->hw_ver;
+ props->max_mr_size = rblock->max_mr_size;
+ props->vendor_id = rblock->vendor_id >> 8;
+ props->vendor_part_id = rblock->vendor_part_id >> 16;
+ props->hw_ver = rblock->hw_ver;
+ props->max_qp = min_t(int, rblock->max_qp, INT_MAX);
+ props->max_qp_wr = min_t(int, rblock->max_wqes_wq, INT_MAX);
+ props->max_sge = min_t(int, rblock->max_sge, INT_MAX);
+ props->max_sge_rd = min_t(int, rblock->max_sge_rd, INT_MAX);
+ props->max_cq = min_t(int, rblock->max_cq, INT_MAX);
+ props->max_cqe = min_t(int, rblock->max_cqe, INT_MAX);
+ props->max_mr = min_t(int, rblock->max_mr, INT_MAX);
+ props->max_mw = min_t(int, rblock->max_mw, INT_MAX);
+ props->max_pd = min_t(int, rblock->max_pd, INT_MAX);
+ props->max_ah = min_t(int, rblock->max_ah, INT_MAX);
+ props->max_fmr = min_t(int, rblock->max_mr, INT_MAX);
+ props->max_srq = 0;
+ props->max_srq_wr = 0;
+ props->max_srq_sge = 0;
+ props->max_pkeys = 16;
+ props->local_ca_ack_delay
+ = rblock->local_ca_ack_delay;
+ props->max_raw_ipv6_qp
+ = min_t(int, rblock->max_raw_ipv6_qp, INT_MAX);
+ props->max_raw_ethy_qp
+ = min_t(int, rblock->max_raw_ethy_qp, INT_MAX);
+ props->max_mcast_grp
+ = min_t(int, rblock->max_mcast_grp, INT_MAX);
+ props->max_mcast_qp_attach
+ = min_t(int, rblock->max_mcast_qp_attach, INT_MAX);
+ props->max_total_mcast_qp_attach
+ = min_t(int, rblock->max_total_mcast_qp_attach, INT_MAX);
+
+query_device1:
+ kfree(rblock);
+
+ return ret;
+}
+
+int ehca_query_port(struct ib_device *ibdev,
+ u8 port, struct ib_port_attr *props)
+{
+ int ret = 0;
+ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
+ ib_device);
+ struct hipz_query_port *rblock;
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_port1;
+ }
+
+ memset(props, 0, sizeof(struct ib_port_attr));
+ props->state = rblock->state;
+
+ switch (rblock->max_mtu) {
+ case 0x1:
+ props->active_mtu = props->max_mtu = IB_MTU_256;
+ break;
+ case 0x2:
+ props->active_mtu = props->max_mtu = IB_MTU_512;
+ break;
+ case 0x3:
+ props->active_mtu = props->max_mtu = IB_MTU_1024;
+ break;
+ case 0x4:
+ props->active_mtu = props->max_mtu = IB_MTU_2048;
+ break;
+ case 0x5:
+ props->active_mtu = props->max_mtu = IB_MTU_4096;
+ break;
+ default:
+ ehca_err(&shca->ib_device, "Unknown MTU size: %x.",
+ rblock->max_mtu);
+ break;
+ }
+
+ props->gid_tbl_len = rblock->gid_tbl_len;
+ props->max_msg_sz = rblock->max_msg_sz;
+ props->bad_pkey_cntr = rblock->bad_pkey_cntr;
+ props->qkey_viol_cntr = rblock->qkey_viol_cntr;
+ props->pkey_tbl_len = rblock->pkey_tbl_len;
+ props->lid = rblock->lid;
+ props->sm_lid = rblock->sm_lid;
+ props->lmc = rblock->lmc;
+ props->sm_sl = rblock->sm_sl;
+ props->subnet_timeout = rblock->subnet_timeout;
+ props->init_type_reply = rblock->init_type_reply;
+
+ props->active_width = IB_WIDTH_12X;
+ props->active_speed = 0x1;
+
+query_port1:
+ kfree(rblock);
+
+ return ret;
+}
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey)
+{
+ int ret = 0;
+ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca, ib_device);
+ struct hipz_query_port *rblock;
+
+ if (index > 16) {
+ ehca_err(&shca->ib_device, "Invalid index: %x.", index);
+ return -EINVAL;
+ }
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_pkey1;
+ }
+
+ memcpy(pkey, &rblock->pkey_entries + index, sizeof(u16));
+
+query_pkey1:
+ kfree(rblock);
+
+ return ret;
+}
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port,
+ int index, union ib_gid *gid)
+{
+ int ret = 0;
+ struct ehca_shca *shca = container_of(ibdev, struct ehca_shca,
+ ib_device);
+ struct hipz_query_port *rblock;
+
+ if (index > 255) {
+ ehca_err(&shca->ib_device, "Invalid index: %x.", index);
+ return -EINVAL;
+ }
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ if (hipz_h_query_port(shca->ipz_hca_handle, port, rblock) != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't query port properties");
+ ret = -EINVAL;
+ goto query_gid1;
+ }
+
+ memcpy(&gid->raw[0], &rblock->gid_prefix, sizeof(u64));
+ memcpy(&gid->raw[8], &rblock->guid_entries[index], sizeof(u64));
+
+query_gid1:
+ kfree(rblock);
+
+ return ret;
+}
+
+int ehca_modify_port(struct ib_device *ibdev,
+ u8 port, int port_modify_mask,
+ struct ib_port_modify *props)
+{
+ /* Not implemented yet */
+ return -EFAULT;
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
new file mode 100644
index 00000000000..2a65b5be197
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -0,0 +1,762 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Functions for EQs, NEQs and interrupts
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ehca_classes.h"
+#include "ehca_irq.h"
+#include "ehca_iverbs.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+#include "hipz_fns.h"
+
+#define EQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
+#define EQE_CQ_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define EQE_EE_IDENTIFIER EHCA_BMASK_IBM(2,7)
+#define EQE_CQ_NUMBER EHCA_BMASK_IBM(8,31)
+#define EQE_QP_NUMBER EHCA_BMASK_IBM(8,31)
+#define EQE_QP_TOKEN EHCA_BMASK_IBM(32,63)
+#define EQE_CQ_TOKEN EHCA_BMASK_IBM(32,63)
+
+#define NEQE_COMPLETION_EVENT EHCA_BMASK_IBM(1,1)
+#define NEQE_EVENT_CODE EHCA_BMASK_IBM(2,7)
+#define NEQE_PORT_NUMBER EHCA_BMASK_IBM(8,15)
+#define NEQE_PORT_AVAILABILITY EHCA_BMASK_IBM(16,16)
+
+#define ERROR_DATA_LENGTH EHCA_BMASK_IBM(52,63)
+#define ERROR_DATA_TYPE EHCA_BMASK_IBM(0,7)
+
+#ifdef CONFIG_INFINIBAND_EHCA_SCALING
+
+static void queue_comp_task(struct ehca_cq *__cq);
+
+static struct ehca_comp_pool* pool;
+static struct notifier_block comp_pool_callback_nb;
+
+#endif
+
+static inline void comp_event_callback(struct ehca_cq *cq)
+{
+ if (!cq->ib_cq.comp_handler)
+ return;
+
+ spin_lock(&cq->cb_lock);
+ cq->ib_cq.comp_handler(&cq->ib_cq, cq->ib_cq.cq_context);
+ spin_unlock(&cq->cb_lock);
+
+ return;
+}
+
+static void print_error_data(struct ehca_shca * shca, void* data,
+ u64* rblock, int length)
+{
+ u64 type = EHCA_BMASK_GET(ERROR_DATA_TYPE, rblock[2]);
+ u64 resource = rblock[1];
+
+ switch (type) {
+ case 0x1: /* Queue Pair */
+ {
+ struct ehca_qp *qp = (struct ehca_qp*)data;
+
+ /* only print error data if AER is set */
+ if (rblock[6] == 0)
+ return;
+
+ ehca_err(&shca->ib_device,
+ "QP 0x%x (resource=%lx) has errors.",
+ qp->ib_qp.qp_num, resource);
+ break;
+ }
+ case 0x4: /* Completion Queue */
+ {
+ struct ehca_cq *cq = (struct ehca_cq*)data;
+
+ ehca_err(&shca->ib_device,
+ "CQ 0x%x (resource=%lx) has errors.",
+ cq->cq_number, resource);
+ break;
+ }
+ default:
+ ehca_err(&shca->ib_device,
+ "Unknown errror type: %lx on %s.",
+ type, shca->ib_device.name);
+ break;
+ }
+
+ ehca_err(&shca->ib_device, "Error data is available: %lx.", resource);
+ ehca_err(&shca->ib_device, "EHCA ----- error data begin "
+ "---------------------------------------------------");
+ ehca_dmp(rblock, length, "resource=%lx", resource);
+ ehca_err(&shca->ib_device, "EHCA ----- error data end "
+ "----------------------------------------------------");
+
+ return;
+}
+
+int ehca_error_data(struct ehca_shca *shca, void *data,
+ u64 resource)
+{
+
+ unsigned long ret;
+ u64 *rblock;
+ unsigned long block_count;
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Cannot allocate rblock memory.");
+ ret = -ENOMEM;
+ goto error_data1;
+ }
+
+ ret = hipz_h_error_data(shca->ipz_hca_handle,
+ resource,
+ rblock,
+ &block_count);
+
+ if (ret == H_R_STATE) {
+ ehca_err(&shca->ib_device,
+ "No error data is available: %lx.", resource);
+ }
+ else if (ret == H_SUCCESS) {
+ int length;
+
+ length = EHCA_BMASK_GET(ERROR_DATA_LENGTH, rblock[0]);
+
+ if (length > PAGE_SIZE)
+ length = PAGE_SIZE;
+
+ print_error_data(shca, data, rblock, length);
+ }
+ else {
+ ehca_err(&shca->ib_device,
+ "Error data could not be fetched: %lx", resource);
+ }
+
+ kfree(rblock);
+
+error_data1:
+ return ret;
+
+}
+
+static void qp_event_callback(struct ehca_shca *shca,
+ u64 eqe,
+ enum ib_event_type event_type)
+{
+ struct ib_event event;
+ struct ehca_qp *qp;
+ unsigned long flags;
+ u32 token = EHCA_BMASK_GET(EQE_QP_TOKEN, eqe);
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+
+ if (!qp)
+ return;
+
+ ehca_error_data(shca, qp, qp->ipz_qp_handle.handle);
+
+ if (!qp->ib_qp.event_handler)
+ return;
+
+ event.device = &shca->ib_device;
+ event.event = event_type;
+ event.element.qp = &qp->ib_qp;
+
+ qp->ib_qp.event_handler(&event, qp->ib_qp.qp_context);
+
+ return;
+}
+
+static void cq_event_callback(struct ehca_shca *shca,
+ u64 eqe)
+{
+ struct ehca_cq *cq;
+ unsigned long flags;
+ u32 token = EHCA_BMASK_GET(EQE_CQ_TOKEN, eqe);
+
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, token);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ if (!cq)
+ return;
+
+ ehca_error_data(shca, cq, cq->ipz_cq_handle.handle);
+
+ return;
+}
+
+static void parse_identifier(struct ehca_shca *shca, u64 eqe)
+{
+ u8 identifier = EHCA_BMASK_GET(EQE_EE_IDENTIFIER, eqe);
+
+ switch (identifier) {
+ case 0x02: /* path migrated */
+ qp_event_callback(shca, eqe, IB_EVENT_PATH_MIG);
+ break;
+ case 0x03: /* communication established */
+ qp_event_callback(shca, eqe, IB_EVENT_COMM_EST);
+ break;
+ case 0x04: /* send queue drained */
+ qp_event_callback(shca, eqe, IB_EVENT_SQ_DRAINED);
+ break;
+ case 0x05: /* QP error */
+ case 0x06: /* QP error */
+ qp_event_callback(shca, eqe, IB_EVENT_QP_FATAL);
+ break;
+ case 0x07: /* CQ error */
+ case 0x08: /* CQ error */
+ cq_event_callback(shca, eqe);
+ break;
+ case 0x09: /* MRMWPTE error */
+ ehca_err(&shca->ib_device, "MRMWPTE error.");
+ break;
+ case 0x0A: /* port event */
+ ehca_err(&shca->ib_device, "Port event.");
+ break;
+ case 0x0B: /* MR access error */
+ ehca_err(&shca->ib_device, "MR access error.");
+ break;
+ case 0x0C: /* EQ error */
+ ehca_err(&shca->ib_device, "EQ error.");
+ break;
+ case 0x0D: /* P/Q_Key mismatch */
+ ehca_err(&shca->ib_device, "P/Q_Key mismatch.");
+ break;
+ case 0x10: /* sampling complete */
+ ehca_err(&shca->ib_device, "Sampling complete.");
+ break;
+ case 0x11: /* unaffiliated access error */
+ ehca_err(&shca->ib_device, "Unaffiliated access error.");
+ break;
+ case 0x12: /* path migrating error */
+ ehca_err(&shca->ib_device, "Path migration error.");
+ break;
+ case 0x13: /* interface trace stopped */
+ ehca_err(&shca->ib_device, "Interface trace stopped.");
+ break;
+ case 0x14: /* first error capture info available */
+ default:
+ ehca_err(&shca->ib_device, "Unknown identifier: %x on %s.",
+ identifier, shca->ib_device.name);
+ break;
+ }
+
+ return;
+}
+
+static void parse_ec(struct ehca_shca *shca, u64 eqe)
+{
+ struct ib_event event;
+ u8 ec = EHCA_BMASK_GET(NEQE_EVENT_CODE, eqe);
+ u8 port = EHCA_BMASK_GET(NEQE_PORT_NUMBER, eqe);
+
+ switch (ec) {
+ case 0x30: /* port availability change */
+ if (EHCA_BMASK_GET(NEQE_PORT_AVAILABILITY, eqe)) {
+ ehca_info(&shca->ib_device,
+ "port %x is active.", port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ACTIVE;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+ ib_dispatch_event(&event);
+ } else {
+ ehca_info(&shca->ib_device,
+ "port %x is inactive.", port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ERR;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+ ib_dispatch_event(&event);
+ }
+ break;
+ case 0x31:
+ /* port configuration change
+ * disruptive change is caused by
+ * LID, PKEY or SM change
+ */
+ ehca_warn(&shca->ib_device,
+ "disruptive port %x configuration change", port);
+
+ ehca_info(&shca->ib_device,
+ "port %x is inactive.", port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ERR;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+ ib_dispatch_event(&event);
+
+ ehca_info(&shca->ib_device,
+ "port %x is active.", port);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ACTIVE;
+ event.element.port_num = port;
+ shca->sport[port - 1].port_state = IB_PORT_ACTIVE;
+ ib_dispatch_event(&event);
+ break;
+ case 0x32: /* adapter malfunction */
+ ehca_err(&shca->ib_device, "Adapter malfunction.");
+ break;
+ case 0x33: /* trace stopped */
+ ehca_err(&shca->ib_device, "Traced stopped.");
+ break;
+ default:
+ ehca_err(&shca->ib_device, "Unknown event code: %x on %s.",
+ ec, shca->ib_device.name);
+ break;
+ }
+
+ return;
+}
+
+static inline void reset_eq_pending(struct ehca_cq *cq)
+{
+ u64 CQx_EP;
+ struct h_galpa gal = cq->galpas.kernel;
+
+ hipz_galpa_store_cq(gal, cqx_ep, 0x0);
+ CQx_EP = hipz_galpa_load(gal, CQTEMM_OFFSET(cqx_ep));
+
+ return;
+}
+
+irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)dev_id;
+
+ tasklet_hi_schedule(&shca->neq.interrupt_task);
+
+ return IRQ_HANDLED;
+}
+
+void ehca_tasklet_neq(unsigned long data)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)data;
+ struct ehca_eqe *eqe;
+ u64 ret;
+
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
+
+ while (eqe) {
+ if (!EHCA_BMASK_GET(NEQE_COMPLETION_EVENT, eqe->entry))
+ parse_ec(shca, eqe->entry);
+
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->neq);
+ }
+
+ ret = hipz_h_reset_event(shca->ipz_hca_handle,
+ shca->neq.ipz_eq_handle, 0xFFFFFFFFFFFFFFFFL);
+
+ if (ret != H_SUCCESS)
+ ehca_err(&shca->ib_device, "Can't clear notification events.");
+
+ return;
+}
+
+irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)dev_id;
+
+ tasklet_hi_schedule(&shca->eq.interrupt_task);
+
+ return IRQ_HANDLED;
+}
+
+void ehca_tasklet_eq(unsigned long data)
+{
+ struct ehca_shca *shca = (struct ehca_shca*)data;
+ struct ehca_eqe *eqe;
+ int int_state;
+ int query_cnt = 0;
+
+ do {
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+
+ if ((shca->hw_level >= 2) && eqe)
+ int_state = 1;
+ else
+ int_state = 0;
+
+ while ((int_state == 1) || eqe) {
+ while (eqe) {
+ u64 eqe_value = eqe->entry;
+
+ ehca_dbg(&shca->ib_device,
+ "eqe_value=%lx", eqe_value);
+
+ /* TODO: better structure */
+ if (EHCA_BMASK_GET(EQE_COMPLETION_EVENT,
+ eqe_value)) {
+ unsigned long flags;
+ u32 token;
+ struct ehca_cq *cq;
+
+ ehca_dbg(&shca->ib_device,
+ "... completion event");
+ token =
+ EHCA_BMASK_GET(EQE_CQ_TOKEN,
+ eqe_value);
+ spin_lock_irqsave(&ehca_cq_idr_lock,
+ flags);
+ cq = idr_find(&ehca_cq_idr, token);
+
+ if (cq == NULL) {
+ spin_unlock(&ehca_cq_idr_lock);
+ break;
+ }
+
+ reset_eq_pending(cq);
+#ifdef CONFIG_INFINIBAND_EHCA_SCALING
+ queue_comp_task(cq);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock,
+ flags);
+#else
+ spin_unlock_irqrestore(&ehca_cq_idr_lock,
+ flags);
+ comp_event_callback(cq);
+#endif
+ } else {
+ ehca_dbg(&shca->ib_device,
+ "... non completion event");
+ parse_identifier(shca, eqe_value);
+ }
+ eqe =
+ (struct ehca_eqe *)ehca_poll_eq(shca,
+ &shca->eq);
+ }
+
+ if (shca->hw_level >= 2) {
+ int_state =
+ hipz_h_query_int_state(shca->ipz_hca_handle,
+ shca->eq.ist);
+ query_cnt++;
+ iosync();
+ if (query_cnt >= 100) {
+ query_cnt = 0;
+ int_state = 0;
+ }
+ }
+ eqe = (struct ehca_eqe *)ehca_poll_eq(shca, &shca->eq);
+
+ }
+ } while (int_state != 0);
+
+ return;
+}
+
+#ifdef CONFIG_INFINIBAND_EHCA_SCALING
+
+static inline int find_next_online_cpu(struct ehca_comp_pool* pool)
+{
+ unsigned long flags_last_cpu;
+
+ if (ehca_debug_level)
+ ehca_dmp(&cpu_online_map, sizeof(cpumask_t), "");
+
+ spin_lock_irqsave(&pool->last_cpu_lock, flags_last_cpu);
+ pool->last_cpu = next_cpu(pool->last_cpu, cpu_online_map);
+ if (pool->last_cpu == NR_CPUS)
+ pool->last_cpu = first_cpu(cpu_online_map);
+ spin_unlock_irqrestore(&pool->last_cpu_lock, flags_last_cpu);
+
+ return pool->last_cpu;
+}
+
+static void __queue_comp_task(struct ehca_cq *__cq,
+ struct ehca_cpu_comp_task *cct)
+{
+ unsigned long flags_cct;
+ unsigned long flags_cq;
+
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+ spin_lock_irqsave(&__cq->task_lock, flags_cq);
+
+ if (__cq->nr_callbacks == 0) {
+ __cq->nr_callbacks++;
+ list_add_tail(&__cq->entry, &cct->cq_list);
+ cct->cq_jobs++;
+ wake_up(&cct->wait_queue);
+ }
+ else
+ __cq->nr_callbacks++;
+
+ spin_unlock_irqrestore(&__cq->task_lock, flags_cq);
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+}
+
+static void queue_comp_task(struct ehca_cq *__cq)
+{
+ int cpu;
+ int cpu_id;
+ struct ehca_cpu_comp_task *cct;
+
+ cpu = get_cpu();
+ cpu_id = find_next_online_cpu(pool);
+
+ BUG_ON(!cpu_online(cpu_id));
+
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
+
+ if (cct->cq_jobs > 0) {
+ cpu_id = find_next_online_cpu(pool);
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu_id);
+ }
+
+ __queue_comp_task(__cq, cct);
+
+ put_cpu();
+
+ return;
+}
+
+static void run_comp_task(struct ehca_cpu_comp_task* cct)
+{
+ struct ehca_cq *cq;
+ unsigned long flags_cct;
+ unsigned long flags_cq;
+
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+
+ while (!list_empty(&cct->cq_list)) {
+ cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+ comp_event_callback(cq);
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+
+ spin_lock_irqsave(&cq->task_lock, flags_cq);
+ cq->nr_callbacks--;
+ if (cq->nr_callbacks == 0) {
+ list_del_init(cct->cq_list.next);
+ cct->cq_jobs--;
+ }
+ spin_unlock_irqrestore(&cq->task_lock, flags_cq);
+
+ }
+
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+
+ return;
+}
+
+static int comp_task(void *__cct)
+{
+ struct ehca_cpu_comp_task* cct = __cct;
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ while(!kthread_should_stop()) {
+ add_wait_queue(&cct->wait_queue, &wait);
+
+ if (list_empty(&cct->cq_list))
+ schedule();
+ else
+ __set_current_state(TASK_RUNNING);
+
+ remove_wait_queue(&cct->wait_queue, &wait);
+
+ if (!list_empty(&cct->cq_list))
+ run_comp_task(__cct);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ __set_current_state(TASK_RUNNING);
+
+ return 0;
+}
+
+static struct task_struct *create_comp_task(struct ehca_comp_pool *pool,
+ int cpu)
+{
+ struct ehca_cpu_comp_task *cct;
+
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+ spin_lock_init(&cct->task_lock);
+ INIT_LIST_HEAD(&cct->cq_list);
+ init_waitqueue_head(&cct->wait_queue);
+ cct->task = kthread_create(comp_task, cct, "ehca_comp/%d", cpu);
+
+ return cct->task;
+}
+
+static void destroy_comp_task(struct ehca_comp_pool *pool,
+ int cpu)
+{
+ struct ehca_cpu_comp_task *cct;
+ struct task_struct *task;
+ unsigned long flags_cct;
+
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+
+ task = cct->task;
+ cct->task = NULL;
+ cct->cq_jobs = 0;
+
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+
+ if (task)
+ kthread_stop(task);
+
+ return;
+}
+
+static void take_over_work(struct ehca_comp_pool *pool,
+ int cpu)
+{
+ struct ehca_cpu_comp_task *cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+ LIST_HEAD(list);
+ struct ehca_cq *cq;
+ unsigned long flags_cct;
+
+ spin_lock_irqsave(&cct->task_lock, flags_cct);
+
+ list_splice_init(&cct->cq_list, &list);
+
+ while(!list_empty(&list)) {
+ cq = list_entry(cct->cq_list.next, struct ehca_cq, entry);
+
+ list_del(&cq->entry);
+ __queue_comp_task(cq, per_cpu_ptr(pool->cpu_comp_tasks,
+ smp_processor_id()));
+ }
+
+ spin_unlock_irqrestore(&cct->task_lock, flags_cct);
+
+}
+
+static int comp_pool_callback(struct notifier_block *nfb,
+ unsigned long action,
+ void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct ehca_cpu_comp_task *cct;
+
+ switch (action) {
+ case CPU_UP_PREPARE:
+ ehca_gen_dbg("CPU: %x (CPU_PREPARE)", cpu);
+ if(!create_comp_task(pool, cpu)) {
+ ehca_gen_err("Can't create comp_task for cpu: %x", cpu);
+ return NOTIFY_BAD;
+ }
+ break;
+ case CPU_UP_CANCELED:
+ ehca_gen_dbg("CPU: %x (CPU_CANCELED)", cpu);
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+ kthread_bind(cct->task, any_online_cpu(cpu_online_map));
+ destroy_comp_task(pool, cpu);
+ break;
+ case CPU_ONLINE:
+ ehca_gen_dbg("CPU: %x (CPU_ONLINE)", cpu);
+ cct = per_cpu_ptr(pool->cpu_comp_tasks, cpu);
+ kthread_bind(cct->task, cpu);
+ wake_up_process(cct->task);
+ break;
+ case CPU_DOWN_PREPARE:
+ ehca_gen_dbg("CPU: %x (CPU_DOWN_PREPARE)", cpu);
+ break;
+ case CPU_DOWN_FAILED:
+ ehca_gen_dbg("CPU: %x (CPU_DOWN_FAILED)", cpu);
+ break;
+ case CPU_DEAD:
+ ehca_gen_dbg("CPU: %x (CPU_DEAD)", cpu);
+ destroy_comp_task(pool, cpu);
+ take_over_work(pool, cpu);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+#endif
+
+int ehca_create_comp_pool(void)
+{
+#ifdef CONFIG_INFINIBAND_EHCA_SCALING
+ int cpu;
+ struct task_struct *task;
+
+ pool = kzalloc(sizeof(struct ehca_comp_pool), GFP_KERNEL);
+ if (pool == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&pool->last_cpu_lock);
+ pool->last_cpu = any_online_cpu(cpu_online_map);
+
+ pool->cpu_comp_tasks = alloc_percpu(struct ehca_cpu_comp_task);
+ if (pool->cpu_comp_tasks == NULL) {
+ kfree(pool);
+ return -EINVAL;
+ }
+
+ for_each_online_cpu(cpu) {
+ task = create_comp_task(pool, cpu);
+ if (task) {
+ kthread_bind(task, cpu);
+ wake_up_process(task);
+ }
+ }
+
+ comp_pool_callback_nb.notifier_call = comp_pool_callback;
+ comp_pool_callback_nb.priority =0;
+ register_cpu_notifier(&comp_pool_callback_nb);
+#endif
+
+ return 0;
+}
+
+void ehca_destroy_comp_pool(void)
+{
+#ifdef CONFIG_INFINIBAND_EHCA_SCALING
+ int i;
+
+ unregister_cpu_notifier(&comp_pool_callback_nb);
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (cpu_online(i))
+ destroy_comp_task(pool, i);
+ }
+#endif
+
+ return;
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h
new file mode 100644
index 00000000000..85bf1fe16fe
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_irq.h
@@ -0,0 +1,77 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Function definitions and structs for EQs, NEQs and interrupts
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Khadija Souissi <souissi@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_IRQ_H
+#define __EHCA_IRQ_H
+
+
+struct ehca_shca;
+
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <asm/atomic.h>
+
+int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource);
+
+irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs);
+void ehca_tasklet_neq(unsigned long data);
+
+irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs);
+void ehca_tasklet_eq(unsigned long data);
+
+struct ehca_cpu_comp_task {
+ wait_queue_head_t wait_queue;
+ struct list_head cq_list;
+ struct task_struct *task;
+ spinlock_t task_lock;
+ int cq_jobs;
+};
+
+struct ehca_comp_pool {
+ struct ehca_cpu_comp_task *cpu_comp_tasks;
+ int last_cpu;
+ spinlock_t last_cpu_lock;
+};
+
+int ehca_create_comp_pool(void);
+void ehca_destroy_comp_pool(void);
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_iverbs.h b/drivers/infiniband/hw/ehca/ehca_iverbs.h
new file mode 100644
index 00000000000..319c39d47f3
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_iverbs.h
@@ -0,0 +1,182 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Function definitions for internal functions
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Dietmar Decker <ddecker@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EHCA_IVERBS_H__
+#define __EHCA_IVERBS_H__
+
+#include "ehca_classes.h"
+
+int ehca_query_device(struct ib_device *ibdev, struct ib_device_attr *props);
+
+int ehca_query_port(struct ib_device *ibdev, u8 port,
+ struct ib_port_attr *props);
+
+int ehca_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 * pkey);
+
+int ehca_query_gid(struct ib_device *ibdev, u8 port, int index,
+ union ib_gid *gid);
+
+int ehca_modify_port(struct ib_device *ibdev, u8 port, int port_modify_mask,
+ struct ib_port_modify *props);
+
+struct ib_pd *ehca_alloc_pd(struct ib_device *device,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int ehca_dealloc_pd(struct ib_pd *pd);
+
+struct ib_ah *ehca_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr);
+
+int ehca_modify_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
+
+int ehca_query_ah(struct ib_ah *ah, struct ib_ah_attr *ah_attr);
+
+int ehca_destroy_ah(struct ib_ah *ah);
+
+struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags);
+
+struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags, u64 *iova_start);
+
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags, struct ib_udata *udata);
+
+int ehca_rereg_phys_mr(struct ib_mr *mr,
+ int mr_rereg_mask,
+ struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf, int mr_access_flags, u64 *iova_start);
+
+int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr);
+
+int ehca_dereg_mr(struct ib_mr *mr);
+
+struct ib_mw *ehca_alloc_mw(struct ib_pd *pd);
+
+int ehca_bind_mw(struct ib_qp *qp, struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind);
+
+int ehca_dealloc_mw(struct ib_mw *mw);
+
+struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
+ int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr);
+
+int ehca_map_phys_fmr(struct ib_fmr *fmr,
+ u64 *page_list, int list_len, u64 iova);
+
+int ehca_unmap_fmr(struct list_head *fmr_list);
+
+int ehca_dealloc_fmr(struct ib_fmr *fmr);
+
+enum ehca_eq_type {
+ EHCA_EQ = 0, /* Event Queue */
+ EHCA_NEQ /* Notification Event Queue */
+};
+
+int ehca_create_eq(struct ehca_shca *shca, struct ehca_eq *eq,
+ enum ehca_eq_type type, const u32 length);
+
+int ehca_destroy_eq(struct ehca_shca *shca, struct ehca_eq *eq);
+
+void *ehca_poll_eq(struct ehca_shca *shca, struct ehca_eq *eq);
+
+
+struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
+
+int ehca_destroy_cq(struct ib_cq *cq);
+
+int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata);
+
+int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc);
+
+int ehca_peek_cq(struct ib_cq *cq, int wc_cnt);
+
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify);
+
+struct ib_qp *ehca_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata);
+
+int ehca_destroy_qp(struct ib_qp *qp);
+
+int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata);
+
+int ehca_query_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr);
+
+int ehca_post_send(struct ib_qp *qp, struct ib_send_wr *send_wr,
+ struct ib_send_wr **bad_send_wr);
+
+int ehca_post_recv(struct ib_qp *qp, struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr);
+
+u64 ehca_define_sqp(struct ehca_shca *shca, struct ehca_qp *ibqp,
+ struct ib_qp_init_attr *qp_init_attr);
+
+int ehca_attach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
+
+int ehca_detach_mcast(struct ib_qp *qp, union ib_gid *gid, u16 lid);
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata);
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context);
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
+void ehca_poll_eqs(unsigned long data);
+
+int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
+ struct vm_area_struct **vma);
+
+int ehca_mmap_register(u64 physical,void **mapped,
+ struct vm_area_struct **vma);
+
+int ehca_munmap(unsigned long addr, size_t len);
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
new file mode 100644
index 00000000000..2380994418a
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -0,0 +1,818 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * module start stop, hca detection
+ *
+ * Authors: Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Joachim Fenkes <fenkes@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
+MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
+MODULE_VERSION("SVNEHCA_0016");
+
+int ehca_open_aqp1 = 0;
+int ehca_debug_level = 0;
+int ehca_hw_level = 0;
+int ehca_nr_ports = 2;
+int ehca_use_hp_mr = 0;
+int ehca_port_act_time = 30;
+int ehca_poll_all_eqs = 1;
+int ehca_static_rate = -1;
+
+module_param_named(open_aqp1, ehca_open_aqp1, int, 0);
+module_param_named(debug_level, ehca_debug_level, int, 0);
+module_param_named(hw_level, ehca_hw_level, int, 0);
+module_param_named(nr_ports, ehca_nr_ports, int, 0);
+module_param_named(use_hp_mr, ehca_use_hp_mr, int, 0);
+module_param_named(port_act_time, ehca_port_act_time, int, 0);
+module_param_named(poll_all_eqs, ehca_poll_all_eqs, int, 0);
+module_param_named(static_rate, ehca_static_rate, int, 0);
+
+MODULE_PARM_DESC(open_aqp1,
+ "AQP1 on startup (0: no (default), 1: yes)");
+MODULE_PARM_DESC(debug_level,
+ "debug level"
+ " (0: no debug traces (default), 1: with debug traces)");
+MODULE_PARM_DESC(hw_level,
+ "hardware level"
+ " (0: autosensing (default), 1: v. 0.20, 2: v. 0.21)");
+MODULE_PARM_DESC(nr_ports,
+ "number of connected ports (default: 2)");
+MODULE_PARM_DESC(use_hp_mr,
+ "high performance MRs (0: no (default), 1: yes)");
+MODULE_PARM_DESC(port_act_time,
+ "time to wait for port activation (default: 30 sec)");
+MODULE_PARM_DESC(poll_all_eqs,
+ "polls all event queues periodically"
+ " (0: no, 1: yes (default))");
+MODULE_PARM_DESC(static_rate,
+ "set permanent static rate (default: disabled)");
+
+spinlock_t ehca_qp_idr_lock;
+spinlock_t ehca_cq_idr_lock;
+DEFINE_IDR(ehca_qp_idr);
+DEFINE_IDR(ehca_cq_idr);
+
+static struct list_head shca_list; /* list of all registered ehcas */
+static spinlock_t shca_list_lock;
+
+static struct timer_list poll_eqs_timer;
+
+static int ehca_create_slab_caches(void)
+{
+ int ret;
+
+ ret = ehca_init_pd_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create PD SLAB cache.");
+ return ret;
+ }
+
+ ret = ehca_init_cq_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create CQ SLAB cache.");
+ goto create_slab_caches2;
+ }
+
+ ret = ehca_init_qp_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create QP SLAB cache.");
+ goto create_slab_caches3;
+ }
+
+ ret = ehca_init_av_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create AV SLAB cache.");
+ goto create_slab_caches4;
+ }
+
+ ret = ehca_init_mrmw_cache();
+ if (ret) {
+ ehca_gen_err("Cannot create MR&MW SLAB cache.");
+ goto create_slab_caches5;
+ }
+
+ return 0;
+
+create_slab_caches5:
+ ehca_cleanup_av_cache();
+
+create_slab_caches4:
+ ehca_cleanup_qp_cache();
+
+create_slab_caches3:
+ ehca_cleanup_cq_cache();
+
+create_slab_caches2:
+ ehca_cleanup_pd_cache();
+
+ return ret;
+}
+
+static void ehca_destroy_slab_caches(void)
+{
+ ehca_cleanup_mrmw_cache();
+ ehca_cleanup_av_cache();
+ ehca_cleanup_qp_cache();
+ ehca_cleanup_cq_cache();
+ ehca_cleanup_pd_cache();
+}
+
+#define EHCA_HCAAVER EHCA_BMASK_IBM(32,39)
+#define EHCA_REVID EHCA_BMASK_IBM(40,63)
+
+int ehca_sense_attributes(struct ehca_shca *shca)
+{
+ int ret = 0;
+ u64 h_ret;
+ struct hipz_query_hca *rblock;
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_gen_err("Cannot allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ h_ret = hipz_h_query_hca(shca->ipz_hca_handle, rblock);
+ if (h_ret != H_SUCCESS) {
+ ehca_gen_err("Cannot query device properties. h_ret=%lx",
+ h_ret);
+ ret = -EPERM;
+ goto num_ports1;
+ }
+
+ if (ehca_nr_ports == 1)
+ shca->num_ports = 1;
+ else
+ shca->num_ports = (u8)rblock->num_ports;
+
+ ehca_gen_dbg(" ... found %x ports", rblock->num_ports);
+
+ if (ehca_hw_level == 0) {
+ u32 hcaaver;
+ u32 revid;
+
+ hcaaver = EHCA_BMASK_GET(EHCA_HCAAVER, rblock->hw_ver);
+ revid = EHCA_BMASK_GET(EHCA_REVID, rblock->hw_ver);
+
+ ehca_gen_dbg(" ... hardware version=%x:%x", hcaaver, revid);
+
+ if ((hcaaver == 1) && (revid == 0))
+ shca->hw_level = 0;
+ else if ((hcaaver == 1) && (revid == 1))
+ shca->hw_level = 1;
+ else if ((hcaaver == 1) && (revid == 2))
+ shca->hw_level = 2;
+ }
+ ehca_gen_dbg(" ... hardware level=%x", shca->hw_level);
+
+ shca->sport[0].rate = IB_RATE_30_GBPS;
+ shca->sport[1].rate = IB_RATE_30_GBPS;
+
+num_ports1:
+ kfree(rblock);
+ return ret;
+}
+
+static int init_node_guid(struct ehca_shca *shca)
+{
+ int ret = 0;
+ struct hipz_query_hca *rblock;
+
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!rblock) {
+ ehca_err(&shca->ib_device, "Can't allocate rblock memory.");
+ return -ENOMEM;
+ }
+
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "Can't query device properties");
+ ret = -EINVAL;
+ goto init_node_guid1;
+ }
+
+ memcpy(&shca->ib_device.node_guid, &rblock->node_guid, sizeof(u64));
+
+init_node_guid1:
+ kfree(rblock);
+ return ret;
+}
+
+int ehca_register_device(struct ehca_shca *shca)
+{
+ int ret;
+
+ ret = init_node_guid(shca);
+ if (ret)
+ return ret;
+
+ strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
+ shca->ib_device.owner = THIS_MODULE;
+
+ shca->ib_device.uverbs_abi_ver = 5;
+ shca->ib_device.uverbs_cmd_mask =
+ (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
+ (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
+ (1ull << IB_USER_VERBS_CMD_REG_MR) |
+ (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
+ (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
+ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
+
+ shca->ib_device.node_type = RDMA_NODE_IB_CA;
+ shca->ib_device.phys_port_cnt = shca->num_ports;
+ shca->ib_device.dma_device = &shca->ibmebus_dev->ofdev.dev;
+ shca->ib_device.query_device = ehca_query_device;
+ shca->ib_device.query_port = ehca_query_port;
+ shca->ib_device.query_gid = ehca_query_gid;
+ shca->ib_device.query_pkey = ehca_query_pkey;
+ /* shca->in_device.modify_device = ehca_modify_device */
+ shca->ib_device.modify_port = ehca_modify_port;
+ shca->ib_device.alloc_ucontext = ehca_alloc_ucontext;
+ shca->ib_device.dealloc_ucontext = ehca_dealloc_ucontext;
+ shca->ib_device.alloc_pd = ehca_alloc_pd;
+ shca->ib_device.dealloc_pd = ehca_dealloc_pd;
+ shca->ib_device.create_ah = ehca_create_ah;
+ /* shca->ib_device.modify_ah = ehca_modify_ah; */
+ shca->ib_device.query_ah = ehca_query_ah;
+ shca->ib_device.destroy_ah = ehca_destroy_ah;
+ shca->ib_device.create_qp = ehca_create_qp;
+ shca->ib_device.modify_qp = ehca_modify_qp;
+ shca->ib_device.query_qp = ehca_query_qp;
+ shca->ib_device.destroy_qp = ehca_destroy_qp;
+ shca->ib_device.post_send = ehca_post_send;
+ shca->ib_device.post_recv = ehca_post_recv;
+ shca->ib_device.create_cq = ehca_create_cq;
+ shca->ib_device.destroy_cq = ehca_destroy_cq;
+ shca->ib_device.resize_cq = ehca_resize_cq;
+ shca->ib_device.poll_cq = ehca_poll_cq;
+ /* shca->ib_device.peek_cq = ehca_peek_cq; */
+ shca->ib_device.req_notify_cq = ehca_req_notify_cq;
+ /* shca->ib_device.req_ncomp_notif = ehca_req_ncomp_notif; */
+ shca->ib_device.get_dma_mr = ehca_get_dma_mr;
+ shca->ib_device.reg_phys_mr = ehca_reg_phys_mr;
+ shca->ib_device.reg_user_mr = ehca_reg_user_mr;
+ shca->ib_device.query_mr = ehca_query_mr;
+ shca->ib_device.dereg_mr = ehca_dereg_mr;
+ shca->ib_device.rereg_phys_mr = ehca_rereg_phys_mr;
+ shca->ib_device.alloc_mw = ehca_alloc_mw;
+ shca->ib_device.bind_mw = ehca_bind_mw;
+ shca->ib_device.dealloc_mw = ehca_dealloc_mw;
+ shca->ib_device.alloc_fmr = ehca_alloc_fmr;
+ shca->ib_device.map_phys_fmr = ehca_map_phys_fmr;
+ shca->ib_device.unmap_fmr = ehca_unmap_fmr;
+ shca->ib_device.dealloc_fmr = ehca_dealloc_fmr;
+ shca->ib_device.attach_mcast = ehca_attach_mcast;
+ shca->ib_device.detach_mcast = ehca_detach_mcast;
+ /* shca->ib_device.process_mad = ehca_process_mad; */
+ shca->ib_device.mmap = ehca_mmap;
+
+ ret = ib_register_device(&shca->ib_device);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "ib_register_device() failed ret=%x", ret);
+
+ return ret;
+}
+
+static int ehca_create_aqp1(struct ehca_shca *shca, u32 port)
+{
+ struct ehca_sport *sport = &shca->sport[port - 1];
+ struct ib_cq *ibcq;
+ struct ib_qp *ibqp;
+ struct ib_qp_init_attr qp_init_attr;
+ int ret;
+
+ if (sport->ibcq_aqp1) {
+ ehca_err(&shca->ib_device, "AQP1 CQ is already created.");
+ return -EPERM;
+ }
+
+ ibcq = ib_create_cq(&shca->ib_device, NULL, NULL, (void*)(-1), 10);
+ if (IS_ERR(ibcq)) {
+ ehca_err(&shca->ib_device, "Cannot create AQP1 CQ.");
+ return PTR_ERR(ibcq);
+ }
+ sport->ibcq_aqp1 = ibcq;
+
+ if (sport->ibqp_aqp1) {
+ ehca_err(&shca->ib_device, "AQP1 QP is already created.");
+ ret = -EPERM;
+ goto create_aqp1;
+ }
+
+ memset(&qp_init_attr, 0, sizeof(struct ib_qp_init_attr));
+ qp_init_attr.send_cq = ibcq;
+ qp_init_attr.recv_cq = ibcq;
+ qp_init_attr.sq_sig_type = IB_SIGNAL_ALL_WR;
+ qp_init_attr.cap.max_send_wr = 100;
+ qp_init_attr.cap.max_recv_wr = 100;
+ qp_init_attr.cap.max_send_sge = 2;
+ qp_init_attr.cap.max_recv_sge = 1;
+ qp_init_attr.qp_type = IB_QPT_GSI;
+ qp_init_attr.port_num = port;
+ qp_init_attr.qp_context = NULL;
+ qp_init_attr.event_handler = NULL;
+ qp_init_attr.srq = NULL;
+
+ ibqp = ib_create_qp(&shca->pd->ib_pd, &qp_init_attr);
+ if (IS_ERR(ibqp)) {
+ ehca_err(&shca->ib_device, "Cannot create AQP1 QP.");
+ ret = PTR_ERR(ibqp);
+ goto create_aqp1;
+ }
+ sport->ibqp_aqp1 = ibqp;
+
+ return 0;
+
+create_aqp1:
+ ib_destroy_cq(sport->ibcq_aqp1);
+ return ret;
+}
+
+static int ehca_destroy_aqp1(struct ehca_sport *sport)
+{
+ int ret;
+
+ ret = ib_destroy_qp(sport->ibqp_aqp1);
+ if (ret) {
+ ehca_gen_err("Cannot destroy AQP1 QP. ret=%x", ret);
+ return ret;
+ }
+
+ ret = ib_destroy_cq(sport->ibcq_aqp1);
+ if (ret)
+ ehca_gen_err("Cannot destroy AQP1 CQ. ret=%x", ret);
+
+ return ret;
+}
+
+static ssize_t ehca_show_debug_level(struct device_driver *ddp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ehca_debug_level);
+}
+
+static ssize_t ehca_store_debug_level(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+ int value = (*buf) - '0';
+ if (value >= 0 && value <= 9)
+ ehca_debug_level = value;
+ return 1;
+}
+
+DRIVER_ATTR(debug_level, S_IRUSR | S_IWUSR,
+ ehca_show_debug_level, ehca_store_debug_level);
+
+void ehca_create_driver_sysfs(struct ibmebus_driver *drv)
+{
+ driver_create_file(&drv->driver, &driver_attr_debug_level);
+}
+
+void ehca_remove_driver_sysfs(struct ibmebus_driver *drv)
+{
+ driver_remove_file(&drv->driver, &driver_attr_debug_level);
+}
+
+#define EHCA_RESOURCE_ATTR(name) \
+static ssize_t ehca_show_##name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct ehca_shca *shca; \
+ struct hipz_query_hca *rblock; \
+ int data; \
+ \
+ shca = dev->driver_data; \
+ \
+ rblock = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL); \
+ if (!rblock) { \
+ dev_err(dev, "Can't allocate rblock memory."); \
+ return 0; \
+ } \
+ \
+ if (hipz_h_query_hca(shca->ipz_hca_handle, rblock) != H_SUCCESS) { \
+ dev_err(dev, "Can't query device properties"); \
+ kfree(rblock); \
+ return 0; \
+ } \
+ \
+ data = rblock->name; \
+ kfree(rblock); \
+ \
+ if ((strcmp(#name, "num_ports") == 0) && (ehca_nr_ports == 1)) \
+ return snprintf(buf, 256, "1\n"); \
+ else \
+ return snprintf(buf, 256, "%d\n", data); \
+ \
+} \
+static DEVICE_ATTR(name, S_IRUGO, ehca_show_##name, NULL);
+
+EHCA_RESOURCE_ATTR(num_ports);
+EHCA_RESOURCE_ATTR(hw_ver);
+EHCA_RESOURCE_ATTR(max_eq);
+EHCA_RESOURCE_ATTR(cur_eq);
+EHCA_RESOURCE_ATTR(max_cq);
+EHCA_RESOURCE_ATTR(cur_cq);
+EHCA_RESOURCE_ATTR(max_qp);
+EHCA_RESOURCE_ATTR(cur_qp);
+EHCA_RESOURCE_ATTR(max_mr);
+EHCA_RESOURCE_ATTR(cur_mr);
+EHCA_RESOURCE_ATTR(max_mw);
+EHCA_RESOURCE_ATTR(cur_mw);
+EHCA_RESOURCE_ATTR(max_pd);
+EHCA_RESOURCE_ATTR(max_ah);
+
+static ssize_t ehca_show_adapter_handle(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ehca_shca *shca = dev->driver_data;
+
+ return sprintf(buf, "%lx\n", shca->ipz_hca_handle.handle);
+
+}
+static DEVICE_ATTR(adapter_handle, S_IRUGO, ehca_show_adapter_handle, NULL);
+
+
+void ehca_create_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_create_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
+ device_create_file(&dev->ofdev.dev, &dev_attr_num_ports);
+ device_create_file(&dev->ofdev.dev, &dev_attr_hw_ver);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_eq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_eq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_cq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_cq);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_qp);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_qp);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_mr);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mr);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_mw);
+ device_create_file(&dev->ofdev.dev, &dev_attr_cur_mw);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_pd);
+ device_create_file(&dev->ofdev.dev, &dev_attr_max_ah);
+}
+
+void ehca_remove_device_sysfs(struct ibmebus_dev *dev)
+{
+ device_remove_file(&dev->ofdev.dev, &dev_attr_adapter_handle);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_num_ports);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_hw_ver);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_eq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_eq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_cq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_cq);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_qp);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_qp);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mr);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mr);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_mw);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_cur_mw);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_pd);
+ device_remove_file(&dev->ofdev.dev, &dev_attr_max_ah);
+}
+
+static int __devinit ehca_probe(struct ibmebus_dev *dev,
+ const struct of_device_id *id)
+{
+ struct ehca_shca *shca;
+ u64 *handle;
+ struct ib_pd *ibpd;
+ int ret;
+
+ handle = (u64 *)get_property(dev->ofdev.node, "ibm,hca-handle", NULL);
+ if (!handle) {
+ ehca_gen_err("Cannot get eHCA handle for adapter: %s.",
+ dev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ if (!(*handle)) {
+ ehca_gen_err("Wrong eHCA handle for adapter: %s.",
+ dev->ofdev.node->full_name);
+ return -ENODEV;
+ }
+
+ shca = (struct ehca_shca *)ib_alloc_device(sizeof(*shca));
+ if (!shca) {
+ ehca_gen_err("Cannot allocate shca memory.");
+ return -ENOMEM;
+ }
+
+ shca->ibmebus_dev = dev;
+ shca->ipz_hca_handle.handle = *handle;
+ dev->ofdev.dev.driver_data = shca;
+
+ ret = ehca_sense_attributes(shca);
+ if (ret < 0) {
+ ehca_gen_err("Cannot sense eHCA attributes.");
+ goto probe1;
+ }
+
+ ret = ehca_register_device(shca);
+ if (ret) {
+ ehca_gen_err("Cannot register Infiniband device");
+ goto probe1;
+ }
+
+ /* create event queues */
+ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
+ if (ret) {
+ ehca_err(&shca->ib_device, "Cannot create EQ.");
+ goto probe2;
+ }
+
+ ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);
+ if (ret) {
+ ehca_err(&shca->ib_device, "Cannot create NEQ.");
+ goto probe3;
+ }
+
+ /* create internal protection domain */
+ ibpd = ehca_alloc_pd(&shca->ib_device, (void*)(-1), NULL);
+ if (IS_ERR(ibpd)) {
+ ehca_err(&shca->ib_device, "Cannot create internal PD.");
+ ret = PTR_ERR(ibpd);
+ goto probe4;
+ }
+
+ shca->pd = container_of(ibpd, struct ehca_pd, ib_pd);
+ shca->pd->ib_pd.device = &shca->ib_device;
+
+ /* create internal max MR */
+ ret = ehca_reg_internal_maxmr(shca, shca->pd, &shca->maxmr);
+
+ if (ret) {
+ ehca_err(&shca->ib_device, "Cannot create internal MR ret=%x",
+ ret);
+ goto probe5;
+ }
+
+ /* create AQP1 for port 1 */
+ if (ehca_open_aqp1 == 1) {
+ shca->sport[0].port_state = IB_PORT_DOWN;
+ ret = ehca_create_aqp1(shca, 1);
+ if (ret) {
+ ehca_err(&shca->ib_device,
+ "Cannot create AQP1 for port 1.");
+ goto probe6;
+ }
+ }
+
+ /* create AQP1 for port 2 */
+ if ((ehca_open_aqp1 == 1) && (shca->num_ports == 2)) {
+ shca->sport[1].port_state = IB_PORT_DOWN;
+ ret = ehca_create_aqp1(shca, 2);
+ if (ret) {
+ ehca_err(&shca->ib_device,
+ "Cannot create AQP1 for port 2.");
+ goto probe7;
+ }
+ }
+
+ ehca_create_device_sysfs(dev);
+
+ spin_lock(&shca_list_lock);
+ list_add(&shca->shca_list, &shca_list);
+ spin_unlock(&shca_list_lock);
+
+ return 0;
+
+probe7:
+ ret = ehca_destroy_aqp1(&shca->sport[0]);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy AQP1 for port 1. ret=%x", ret);
+
+probe6:
+ ret = ehca_dereg_internal_maxmr(shca);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy internal MR. ret=%x", ret);
+
+probe5:
+ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy internal PD. ret=%x", ret);
+
+probe4:
+ ret = ehca_destroy_eq(shca, &shca->neq);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy NEQ. ret=%x", ret);
+
+probe3:
+ ret = ehca_destroy_eq(shca, &shca->eq);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy EQ. ret=%x", ret);
+
+probe2:
+ ib_unregister_device(&shca->ib_device);
+
+probe1:
+ ib_dealloc_device(&shca->ib_device);
+
+ return -EINVAL;
+}
+
+static int __devexit ehca_remove(struct ibmebus_dev *dev)
+{
+ struct ehca_shca *shca = dev->ofdev.dev.driver_data;
+ int ret;
+
+ ehca_remove_device_sysfs(dev);
+
+ if (ehca_open_aqp1 == 1) {
+ int i;
+ for (i = 0; i < shca->num_ports; i++) {
+ ret = ehca_destroy_aqp1(&shca->sport[i]);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy AQP1 for port %x "
+ "ret=%x", ret, i);
+ }
+ }
+
+ ib_unregister_device(&shca->ib_device);
+
+ ret = ehca_dereg_internal_maxmr(shca);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy internal MR. ret=%x", ret);
+
+ ret = ehca_dealloc_pd(&shca->pd->ib_pd);
+ if (ret)
+ ehca_err(&shca->ib_device,
+ "Cannot destroy internal PD. ret=%x", ret);
+
+ ret = ehca_destroy_eq(shca, &shca->eq);
+ if (ret)
+ ehca_err(&shca->ib_device, "Cannot destroy EQ. ret=%x", ret);
+
+ ret = ehca_destroy_eq(shca, &shca->neq);
+ if (ret)
+ ehca_err(&shca->ib_device, "Canot destroy NEQ. ret=%x", ret);
+
+ ib_dealloc_device(&shca->ib_device);
+
+ spin_lock(&shca_list_lock);
+ list_del(&shca->shca_list);
+ spin_unlock(&shca_list_lock);
+
+ return ret;
+}
+
+static struct of_device_id ehca_device_table[] =
+{
+ {
+ .name = "lhca",
+ .compatible = "IBM,lhca",
+ },
+ {},
+};
+
+static struct ibmebus_driver ehca_driver = {
+ .name = "ehca",
+ .id_table = ehca_device_table,
+ .probe = ehca_probe,
+ .remove = ehca_remove,
+};
+
+void ehca_poll_eqs(unsigned long data)
+{
+ struct ehca_shca *shca;
+
+ spin_lock(&shca_list_lock);
+ list_for_each_entry(shca, &shca_list, shca_list) {
+ if (shca->eq.is_initialized)
+ ehca_tasklet_eq((unsigned long)(void*)shca);
+ }
+ mod_timer(&poll_eqs_timer, jiffies + HZ);
+ spin_unlock(&shca_list_lock);
+}
+
+int __init ehca_module_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "eHCA Infiniband Device Driver "
+ "(Rel.: SVNEHCA_0016)\n");
+ idr_init(&ehca_qp_idr);
+ idr_init(&ehca_cq_idr);
+ spin_lock_init(&ehca_qp_idr_lock);
+ spin_lock_init(&ehca_cq_idr_lock);
+
+ INIT_LIST_HEAD(&shca_list);
+ spin_lock_init(&shca_list_lock);
+
+ if ((ret = ehca_create_comp_pool())) {
+ ehca_gen_err("Cannot create comp pool.");
+ return ret;
+ }
+
+ if ((ret = ehca_create_slab_caches())) {
+ ehca_gen_err("Cannot create SLAB caches");
+ ret = -ENOMEM;
+ goto module_init1;
+ }
+
+ if ((ret = ibmebus_register_driver(&ehca_driver))) {
+ ehca_gen_err("Cannot register eHCA device driver");
+ ret = -EINVAL;
+ goto module_init2;
+ }
+
+ ehca_create_driver_sysfs(&ehca_driver);
+
+ if (ehca_poll_all_eqs != 1) {
+ ehca_gen_err("WARNING!!!");
+ ehca_gen_err("It is possible to lose interrupts.");
+ } else {
+ init_timer(&poll_eqs_timer);
+ poll_eqs_timer.function = ehca_poll_eqs;
+ poll_eqs_timer.expires = jiffies + HZ;
+ add_timer(&poll_eqs_timer);
+ }
+
+ return 0;
+
+module_init2:
+ ehca_destroy_slab_caches();
+
+module_init1:
+ ehca_destroy_comp_pool();
+ return ret;
+};
+
+void __exit ehca_module_exit(void)
+{
+ if (ehca_poll_all_eqs == 1)
+ del_timer_sync(&poll_eqs_timer);
+
+ ehca_remove_driver_sysfs(&ehca_driver);
+ ibmebus_unregister_driver(&ehca_driver);
+
+ ehca_destroy_slab_caches();
+
+ ehca_destroy_comp_pool();
+
+ idr_destroy(&ehca_cq_idr);
+ idr_destroy(&ehca_qp_idr);
+};
+
+module_init(ehca_module_init);
+module_exit(ehca_module_exit);
diff --git a/drivers/infiniband/hw/ehca/ehca_mcast.c b/drivers/infiniband/hw/ehca/ehca_mcast.c
new file mode 100644
index 00000000000..32a870660bf
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_mcast.c
@@ -0,0 +1,131 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * mcast functions
+ *
+ * Authors: Khadija Souissi <souissik@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+
+#define MAX_MC_LID 0xFFFE
+#define MIN_MC_LID 0xC000 /* Multicast limits */
+#define EHCA_VALID_MULTICAST_GID(gid) ((gid)[0] == 0xFF)
+#define EHCA_VALID_MULTICAST_LID(lid) \
+ (((lid) >= MIN_MC_LID) && ((lid) <= MAX_MC_LID))
+
+int ehca_attach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
+ ib_device);
+ union ib_gid my_gid;
+ u64 subnet_prefix, interface_id, h_ret;
+
+ if (ibqp->qp_type != IB_QPT_UD) {
+ ehca_err(ibqp->device, "invalid qp_type=%x", ibqp->qp_type);
+ return -EINVAL;
+ }
+
+ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
+ ehca_err(ibqp->device, "invalid mulitcast gid");
+ return -EINVAL;
+ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
+ ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid);
+ return -EINVAL;
+ }
+
+ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+
+ subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
+ interface_id = be64_to_cpu(my_gid.global.interface_id);
+ h_ret = hipz_h_attach_mcqp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ my_qp->galpas.kernel,
+ lid, subnet_prefix, interface_id);
+ if (h_ret != H_SUCCESS)
+ ehca_err(ibqp->device,
+ "ehca_qp=%p qp_num=%x hipz_h_attach_mcqp() failed "
+ "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+
+ return ehca2ib_return_code(h_ret);
+}
+
+int ehca_detach_mcast(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
+{
+ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ struct ehca_shca *shca = container_of(ibqp->pd->device,
+ struct ehca_shca, ib_device);
+ union ib_gid my_gid;
+ u64 subnet_prefix, interface_id, h_ret;
+
+ if (ibqp->qp_type != IB_QPT_UD) {
+ ehca_err(ibqp->device, "invalid qp_type %x", ibqp->qp_type);
+ return -EINVAL;
+ }
+
+ if (!(EHCA_VALID_MULTICAST_GID(gid->raw))) {
+ ehca_err(ibqp->device, "invalid mulitcast gid");
+ return -EINVAL;
+ } else if ((lid < MIN_MC_LID) || (lid > MAX_MC_LID)) {
+ ehca_err(ibqp->device, "invalid mulitcast lid=%x", lid);
+ return -EINVAL;
+ }
+
+ memcpy(&my_gid.raw, gid->raw, sizeof(union ib_gid));
+
+ subnet_prefix = be64_to_cpu(my_gid.global.subnet_prefix);
+ interface_id = be64_to_cpu(my_gid.global.interface_id);
+ h_ret = hipz_h_detach_mcqp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ my_qp->galpas.kernel,
+ lid, subnet_prefix, interface_id);
+ if (h_ret != H_SUCCESS)
+ ehca_err(ibqp->device,
+ "ehca_qp=%p qp_num=%x hipz_h_detach_mcqp() failed "
+ "h_ret=%lx", my_qp, ibqp->qp_num, h_ret);
+
+ return ehca2ib_return_code(h_ret);
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
new file mode 100644
index 00000000000..5ca65441e1d
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -0,0 +1,2261 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * MR/MW functions
+ *
+ * Authors: Dietmar Decker <ddecker@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/current.h>
+
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "hcp_if.h"
+#include "hipz_hw.h"
+
+static struct kmem_cache *mr_cache;
+static struct kmem_cache *mw_cache;
+
+static struct ehca_mr *ehca_mr_new(void)
+{
+ struct ehca_mr *me;
+
+ me = kmem_cache_alloc(mr_cache, SLAB_KERNEL);
+ if (me) {
+ memset(me, 0, sizeof(struct ehca_mr));
+ spin_lock_init(&me->mrlock);
+ } else
+ ehca_gen_err("alloc failed");
+
+ return me;
+}
+
+static void ehca_mr_delete(struct ehca_mr *me)
+{
+ kmem_cache_free(mr_cache, me);
+}
+
+static struct ehca_mw *ehca_mw_new(void)
+{
+ struct ehca_mw *me;
+
+ me = kmem_cache_alloc(mw_cache, SLAB_KERNEL);
+ if (me) {
+ memset(me, 0, sizeof(struct ehca_mw));
+ spin_lock_init(&me->mwlock);
+ } else
+ ehca_gen_err("alloc failed");
+
+ return me;
+}
+
+static void ehca_mw_delete(struct ehca_mw *me)
+{
+ kmem_cache_free(mw_cache, me);
+}
+
+/*----------------------------------------------------------------------*/
+
+struct ib_mr *ehca_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
+{
+ struct ib_mr *ib_mr;
+ int ret;
+ struct ehca_mr *e_maxmr;
+ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ struct ehca_shca *shca =
+ container_of(pd->device, struct ehca_shca, ib_device);
+
+ if (shca->maxmr) {
+ e_maxmr = ehca_mr_new();
+ if (!e_maxmr) {
+ ehca_err(&shca->ib_device, "out of memory");
+ ib_mr = ERR_PTR(-ENOMEM);
+ goto get_dma_mr_exit0;
+ }
+
+ ret = ehca_reg_maxmr(shca, e_maxmr, (u64*)KERNELBASE,
+ mr_access_flags, e_pd,
+ &e_maxmr->ib.ib_mr.lkey,
+ &e_maxmr->ib.ib_mr.rkey);
+ if (ret) {
+ ib_mr = ERR_PTR(ret);
+ goto get_dma_mr_exit0;
+ }
+ ib_mr = &e_maxmr->ib.ib_mr;
+ } else {
+ ehca_err(&shca->ib_device, "no internal max-MR exist!");
+ ib_mr = ERR_PTR(-EINVAL);
+ goto get_dma_mr_exit0;
+ }
+
+get_dma_mr_exit0:
+ if (IS_ERR(ib_mr))
+ ehca_err(&shca->ib_device, "rc=%lx pd=%p mr_access_flags=%x ",
+ PTR_ERR(ib_mr), pd, mr_access_flags);
+ return ib_mr;
+} /* end ehca_get_dma_mr() */
+
+/*----------------------------------------------------------------------*/
+
+struct ib_mr *ehca_reg_phys_mr(struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags,
+ u64 *iova_start)
+{
+ struct ib_mr *ib_mr;
+ int ret;
+ struct ehca_mr *e_mr;
+ struct ehca_shca *shca =
+ container_of(pd->device, struct ehca_shca, ib_device);
+ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
+
+ u64 size;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 num_pages_mr;
+ u32 num_pages_4k; /* 4k portion "pages" */
+
+ if ((num_phys_buf <= 0) || !phys_buf_array) {
+ ehca_err(pd->device, "bad input values: num_phys_buf=%x "
+ "phys_buf_array=%p", num_phys_buf, phys_buf_array);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_phys_mr_exit0;
+ }
+ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
+ /*
+ * Remote Write Access requires Local Write Access
+ * Remote Atomic Access requires Local Write Access
+ */
+ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_phys_mr_exit0;
+ }
+
+ /* check physical buffer list and calculate size */
+ ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array, num_phys_buf,
+ iova_start, &size);
+ if (ret) {
+ ib_mr = ERR_PTR(ret);
+ goto reg_phys_mr_exit0;
+ }
+ if ((size == 0) ||
+ (((u64)iova_start + size) < (u64)iova_start)) {
+ ehca_err(pd->device, "bad input values: size=%lx iova_start=%p",
+ size, iova_start);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_phys_mr_exit0;
+ }
+
+ e_mr = ehca_mr_new();
+ if (!e_mr) {
+ ehca_err(pd->device, "out of memory");
+ ib_mr = ERR_PTR(-ENOMEM);
+ goto reg_phys_mr_exit0;
+ }
+
+ /* determine number of MR pages */
+ num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size +
+ PAGE_SIZE - 1) / PAGE_SIZE);
+ num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
+
+ /* register MR on HCA */
+ if (ehca_mr_is_maxmr(size, iova_start)) {
+ e_mr->flags |= EHCA_MR_FLAG_MAXMR;
+ ret = ehca_reg_maxmr(shca, e_mr, iova_start, mr_access_flags,
+ e_pd, &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (ret) {
+ ib_mr = ERR_PTR(ret);
+ goto reg_phys_mr_exit1;
+ }
+ } else {
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.num_phys_buf = num_phys_buf;
+ pginfo.phys_buf_array = phys_buf_array;
+ pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
+ EHCA_PAGESIZE);
+
+ ret = ehca_reg_mr(shca, e_mr, iova_start, size, mr_access_flags,
+ e_pd, &pginfo, &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (ret) {
+ ib_mr = ERR_PTR(ret);
+ goto reg_phys_mr_exit1;
+ }
+ }
+
+ /* successful registration of all pages */
+ return &e_mr->ib.ib_mr;
+
+reg_phys_mr_exit1:
+ ehca_mr_delete(e_mr);
+reg_phys_mr_exit0:
+ if (IS_ERR(ib_mr))
+ ehca_err(pd->device, "rc=%lx pd=%p phys_buf_array=%p "
+ "num_phys_buf=%x mr_access_flags=%x iova_start=%p",
+ PTR_ERR(ib_mr), pd, phys_buf_array,
+ num_phys_buf, mr_access_flags, iova_start);
+ return ib_mr;
+} /* end ehca_reg_phys_mr() */
+
+/*----------------------------------------------------------------------*/
+
+struct ib_mr *ehca_reg_user_mr(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags,
+ struct ib_udata *udata)
+{
+ struct ib_mr *ib_mr;
+ struct ehca_mr *e_mr;
+ struct ehca_shca *shca =
+ container_of(pd->device, struct ehca_shca, ib_device);
+ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ int ret;
+ u32 num_pages_mr;
+ u32 num_pages_4k; /* 4k portion "pages" */
+
+ if (!pd) {
+ ehca_gen_err("bad pd=%p", pd);
+ return ERR_PTR(-EFAULT);
+ }
+ if (!region) {
+ ehca_err(pd->device, "bad input values: region=%p", region);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
+ /*
+ * Remote Write Access requires Local Write Access
+ * Remote Atomic Access requires Local Write Access
+ */
+ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+ if (region->page_size != PAGE_SIZE) {
+ ehca_err(pd->device, "page size not supported, "
+ "region->page_size=%x", region->page_size);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+
+ if ((region->length == 0) ||
+ ((region->virt_base + region->length) < region->virt_base)) {
+ ehca_err(pd->device, "bad input values: length=%lx "
+ "virt_base=%lx", region->length, region->virt_base);
+ ib_mr = ERR_PTR(-EINVAL);
+ goto reg_user_mr_exit0;
+ }
+
+ e_mr = ehca_mr_new();
+ if (!e_mr) {
+ ehca_err(pd->device, "out of memory");
+ ib_mr = ERR_PTR(-ENOMEM);
+ goto reg_user_mr_exit0;
+ }
+
+ /* determine number of MR pages */
+ num_pages_mr = (((region->virt_base % PAGE_SIZE) + region->length +
+ PAGE_SIZE - 1) / PAGE_SIZE);
+ num_pages_4k = (((region->virt_base % EHCA_PAGESIZE) + region->length +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
+
+ /* register MR on HCA */
+ pginfo.type = EHCA_MR_PGI_USER;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.region = region;
+ pginfo.next_4k = region->offset / EHCA_PAGESIZE;
+ pginfo.next_chunk = list_prepare_entry(pginfo.next_chunk,
+ (&region->chunk_list),
+ list);
+
+ ret = ehca_reg_mr(shca, e_mr, (u64*)region->virt_base,
+ region->length, mr_access_flags, e_pd, &pginfo,
+ &e_mr->ib.ib_mr.lkey, &e_mr->ib.ib_mr.rkey);
+ if (ret) {
+ ib_mr = ERR_PTR(ret);
+ goto reg_user_mr_exit1;
+ }
+
+ /* successful registration of all pages */
+ return &e_mr->ib.ib_mr;
+
+reg_user_mr_exit1:
+ ehca_mr_delete(e_mr);
+reg_user_mr_exit0:
+ if (IS_ERR(ib_mr))
+ ehca_err(pd->device, "rc=%lx pd=%p region=%p mr_access_flags=%x"
+ " udata=%p",
+ PTR_ERR(ib_mr), pd, region, mr_access_flags, udata);
+ return ib_mr;
+} /* end ehca_reg_user_mr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_rereg_phys_mr(struct ib_mr *mr,
+ int mr_rereg_mask,
+ struct ib_pd *pd,
+ struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ int mr_access_flags,
+ u64 *iova_start)
+{
+ int ret;
+
+ struct ehca_shca *shca =
+ container_of(mr->device, struct ehca_shca, ib_device);
+ struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
+ struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
+ u64 new_size;
+ u64 *new_start;
+ u32 new_acl;
+ struct ehca_pd *new_pd;
+ u32 tmp_lkey, tmp_rkey;
+ unsigned long sl_flags;
+ u32 num_pages_mr = 0;
+ u32 num_pages_4k = 0; /* 4k portion "pages" */
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 cur_pid = current->tgid;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ (my_pd->ownpid != cur_pid)) {
+ ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ if (!(mr_rereg_mask & IB_MR_REREG_TRANS)) {
+ /* TODO not supported, because PHYP rereg hCall needs pages */
+ ehca_err(mr->device, "rereg without IB_MR_REREG_TRANS not "
+ "supported yet, mr_rereg_mask=%x", mr_rereg_mask);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ if (mr_rereg_mask & IB_MR_REREG_PD) {
+ if (!pd) {
+ ehca_err(mr->device, "rereg with bad pd, pd=%p "
+ "mr_rereg_mask=%x", pd, mr_rereg_mask);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ }
+
+ if ((mr_rereg_mask &
+ ~(IB_MR_REREG_TRANS | IB_MR_REREG_PD | IB_MR_REREG_ACCESS)) ||
+ (mr_rereg_mask == 0)) {
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ /* check other parameters */
+ if (e_mr == shca->maxmr) {
+ /* should be impossible, however reject to be sure */
+ ehca_err(mr->device, "rereg internal max-MR impossible, mr=%p "
+ "shca->maxmr=%p mr->lkey=%x",
+ mr, shca->maxmr, mr->lkey);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ if (mr_rereg_mask & IB_MR_REREG_TRANS) { /* transl., i.e. addr/size */
+ if (e_mr->flags & EHCA_MR_FLAG_FMR) {
+ ehca_err(mr->device, "not supported for FMR, mr=%p "
+ "flags=%x", mr, e_mr->flags);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ if (!phys_buf_array || num_phys_buf <= 0) {
+ ehca_err(mr->device, "bad input values: mr_rereg_mask=%x"
+ " phys_buf_array=%p num_phys_buf=%x",
+ mr_rereg_mask, phys_buf_array, num_phys_buf);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+ }
+ if ((mr_rereg_mask & IB_MR_REREG_ACCESS) && /* change ACL */
+ (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)))) {
+ /*
+ * Remote Write Access requires Local Write Access
+ * Remote Atomic Access requires Local Write Access
+ */
+ ehca_err(mr->device, "bad input values: mr_rereg_mask=%x "
+ "mr_access_flags=%x", mr_rereg_mask, mr_access_flags);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit0;
+ }
+
+ /* set requested values dependent on rereg request */
+ spin_lock_irqsave(&e_mr->mrlock, sl_flags);
+ new_start = e_mr->start; /* new == old address */
+ new_size = e_mr->size; /* new == old length */
+ new_acl = e_mr->acl; /* new == old access control */
+ new_pd = container_of(mr->pd,struct ehca_pd,ib_pd); /*new == old PD*/
+
+ if (mr_rereg_mask & IB_MR_REREG_TRANS) {
+ new_start = iova_start; /* change address */
+ /* check physical buffer list and calculate size */
+ ret = ehca_mr_chk_buf_and_calc_size(phys_buf_array,
+ num_phys_buf, iova_start,
+ &new_size);
+ if (ret)
+ goto rereg_phys_mr_exit1;
+ if ((new_size == 0) ||
+ (((u64)iova_start + new_size) < (u64)iova_start)) {
+ ehca_err(mr->device, "bad input values: new_size=%lx "
+ "iova_start=%p", new_size, iova_start);
+ ret = -EINVAL;
+ goto rereg_phys_mr_exit1;
+ }
+ num_pages_mr = ((((u64)new_start % PAGE_SIZE) + new_size +
+ PAGE_SIZE - 1) / PAGE_SIZE);
+ num_pages_4k = ((((u64)new_start % EHCA_PAGESIZE) + new_size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.num_phys_buf = num_phys_buf;
+ pginfo.phys_buf_array = phys_buf_array;
+ pginfo.next_4k = (((u64)iova_start & ~PAGE_MASK) /
+ EHCA_PAGESIZE);
+ }
+ if (mr_rereg_mask & IB_MR_REREG_ACCESS)
+ new_acl = mr_access_flags;
+ if (mr_rereg_mask & IB_MR_REREG_PD)
+ new_pd = container_of(pd, struct ehca_pd, ib_pd);
+
+ ret = ehca_rereg_mr(shca, e_mr, new_start, new_size, new_acl,
+ new_pd, &pginfo, &tmp_lkey, &tmp_rkey);
+ if (ret)
+ goto rereg_phys_mr_exit1;
+
+ /* successful reregistration */
+ if (mr_rereg_mask & IB_MR_REREG_PD)
+ mr->pd = pd;
+ mr->lkey = tmp_lkey;
+ mr->rkey = tmp_rkey;
+
+rereg_phys_mr_exit1:
+ spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
+rereg_phys_mr_exit0:
+ if (ret)
+ ehca_err(mr->device, "ret=%x mr=%p mr_rereg_mask=%x pd=%p "
+ "phys_buf_array=%p num_phys_buf=%x mr_access_flags=%x "
+ "iova_start=%p",
+ ret, mr, mr_rereg_mask, pd, phys_buf_array,
+ num_phys_buf, mr_access_flags, iova_start);
+ return ret;
+} /* end ehca_rereg_phys_mr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr)
+{
+ int ret = 0;
+ u64 h_ret;
+ struct ehca_shca *shca =
+ container_of(mr->device, struct ehca_shca, ib_device);
+ struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
+ struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
+ u32 cur_pid = current->tgid;
+ unsigned long sl_flags;
+ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ (my_pd->ownpid != cur_pid)) {
+ ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ ret = -EINVAL;
+ goto query_mr_exit0;
+ }
+
+ if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
+ ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p "
+ "e_mr->flags=%x", mr, e_mr, e_mr->flags);
+ ret = -EINVAL;
+ goto query_mr_exit0;
+ }
+
+ memset(mr_attr, 0, sizeof(struct ib_mr_attr));
+ spin_lock_irqsave(&e_mr->mrlock, sl_flags);
+
+ h_ret = hipz_h_query_mr(shca->ipz_hca_handle, e_mr, &hipzout);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(mr->device, "hipz_mr_query failed, h_ret=%lx mr=%p "
+ "hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ h_ret, mr, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle, mr->lkey);
+ ret = ehca_mrmw_map_hrc_query_mr(h_ret);
+ goto query_mr_exit1;
+ }
+ mr_attr->pd = mr->pd;
+ mr_attr->device_virt_addr = hipzout.vaddr;
+ mr_attr->size = hipzout.len;
+ mr_attr->lkey = hipzout.lkey;
+ mr_attr->rkey = hipzout.rkey;
+ ehca_mrmw_reverse_map_acl(&hipzout.acl, &mr_attr->mr_access_flags);
+
+query_mr_exit1:
+ spin_unlock_irqrestore(&e_mr->mrlock, sl_flags);
+query_mr_exit0:
+ if (ret)
+ ehca_err(mr->device, "ret=%x mr=%p mr_attr=%p",
+ ret, mr, mr_attr);
+ return ret;
+} /* end ehca_query_mr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_dereg_mr(struct ib_mr *mr)
+{
+ int ret = 0;
+ u64 h_ret;
+ struct ehca_shca *shca =
+ container_of(mr->device, struct ehca_shca, ib_device);
+ struct ehca_mr *e_mr = container_of(mr, struct ehca_mr, ib.ib_mr);
+ struct ehca_pd *my_pd = container_of(mr->pd, struct ehca_pd, ib_pd);
+ u32 cur_pid = current->tgid;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ (my_pd->ownpid != cur_pid)) {
+ ehca_err(mr->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ ret = -EINVAL;
+ goto dereg_mr_exit0;
+ }
+
+ if ((e_mr->flags & EHCA_MR_FLAG_FMR)) {
+ ehca_err(mr->device, "not supported for FMR, mr=%p e_mr=%p "
+ "e_mr->flags=%x", mr, e_mr, e_mr->flags);
+ ret = -EINVAL;
+ goto dereg_mr_exit0;
+ } else if (e_mr == shca->maxmr) {
+ /* should be impossible, however reject to be sure */
+ ehca_err(mr->device, "dereg internal max-MR impossible, mr=%p "
+ "shca->maxmr=%p mr->lkey=%x",
+ mr, shca->maxmr, mr->lkey);
+ ret = -EINVAL;
+ goto dereg_mr_exit0;
+ }
+
+ /* TODO: BUSY: MR still has bound window(s) */
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(mr->device, "hipz_free_mr failed, h_ret=%lx shca=%p "
+ "e_mr=%p hca_hndl=%lx mr_hndl=%lx mr->lkey=%x",
+ h_ret, shca, e_mr, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle, mr->lkey);
+ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ goto dereg_mr_exit0;
+ }
+
+ /* successful deregistration */
+ ehca_mr_delete(e_mr);
+
+dereg_mr_exit0:
+ if (ret)
+ ehca_err(mr->device, "ret=%x mr=%p", ret, mr);
+ return ret;
+} /* end ehca_dereg_mr() */
+
+/*----------------------------------------------------------------------*/
+
+struct ib_mw *ehca_alloc_mw(struct ib_pd *pd)
+{
+ struct ib_mw *ib_mw;
+ u64 h_ret;
+ struct ehca_mw *e_mw;
+ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ struct ehca_shca *shca =
+ container_of(pd->device, struct ehca_shca, ib_device);
+ struct ehca_mw_hipzout_parms hipzout = {{0},0};
+
+ e_mw = ehca_mw_new();
+ if (!e_mw) {
+ ib_mw = ERR_PTR(-ENOMEM);
+ goto alloc_mw_exit0;
+ }
+
+ h_ret = hipz_h_alloc_resource_mw(shca->ipz_hca_handle, e_mw,
+ e_pd->fw_pd, &hipzout);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(pd->device, "hipz_mw_allocate failed, h_ret=%lx "
+ "shca=%p hca_hndl=%lx mw=%p",
+ h_ret, shca, shca->ipz_hca_handle.handle, e_mw);
+ ib_mw = ERR_PTR(ehca_mrmw_map_hrc_alloc(h_ret));
+ goto alloc_mw_exit1;
+ }
+ /* successful MW allocation */
+ e_mw->ipz_mw_handle = hipzout.handle;
+ e_mw->ib_mw.rkey = hipzout.rkey;
+ return &e_mw->ib_mw;
+
+alloc_mw_exit1:
+ ehca_mw_delete(e_mw);
+alloc_mw_exit0:
+ if (IS_ERR(ib_mw))
+ ehca_err(pd->device, "rc=%lx pd=%p", PTR_ERR(ib_mw), pd);
+ return ib_mw;
+} /* end ehca_alloc_mw() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_bind_mw(struct ib_qp *qp,
+ struct ib_mw *mw,
+ struct ib_mw_bind *mw_bind)
+{
+ /* TODO: not supported up to now */
+ ehca_gen_err("bind MW currently not supported by HCAD");
+
+ return -EPERM;
+} /* end ehca_bind_mw() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_dealloc_mw(struct ib_mw *mw)
+{
+ u64 h_ret;
+ struct ehca_shca *shca =
+ container_of(mw->device, struct ehca_shca, ib_device);
+ struct ehca_mw *e_mw = container_of(mw, struct ehca_mw, ib_mw);
+
+ h_ret = hipz_h_free_resource_mw(shca->ipz_hca_handle, e_mw);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(mw->device, "hipz_free_mw failed, h_ret=%lx shca=%p "
+ "mw=%p rkey=%x hca_hndl=%lx mw_hndl=%lx",
+ h_ret, shca, mw, mw->rkey, shca->ipz_hca_handle.handle,
+ e_mw->ipz_mw_handle.handle);
+ return ehca_mrmw_map_hrc_free_mw(h_ret);
+ }
+ /* successful deallocation */
+ ehca_mw_delete(e_mw);
+ return 0;
+} /* end ehca_dealloc_mw() */
+
+/*----------------------------------------------------------------------*/
+
+struct ib_fmr *ehca_alloc_fmr(struct ib_pd *pd,
+ int mr_access_flags,
+ struct ib_fmr_attr *fmr_attr)
+{
+ struct ib_fmr *ib_fmr;
+ struct ehca_shca *shca =
+ container_of(pd->device, struct ehca_shca, ib_device);
+ struct ehca_pd *e_pd = container_of(pd, struct ehca_pd, ib_pd);
+ struct ehca_mr *e_fmr;
+ int ret;
+ u32 tmp_lkey, tmp_rkey;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+
+ /* check other parameters */
+ if (((mr_access_flags & IB_ACCESS_REMOTE_WRITE) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE)) ||
+ ((mr_access_flags & IB_ACCESS_REMOTE_ATOMIC) &&
+ !(mr_access_flags & IB_ACCESS_LOCAL_WRITE))) {
+ /*
+ * Remote Write Access requires Local Write Access
+ * Remote Atomic Access requires Local Write Access
+ */
+ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+ if (mr_access_flags & IB_ACCESS_MW_BIND) {
+ ehca_err(pd->device, "bad input values: mr_access_flags=%x",
+ mr_access_flags);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+ if ((fmr_attr->max_pages == 0) || (fmr_attr->max_maps == 0)) {
+ ehca_err(pd->device, "bad input values: fmr_attr->max_pages=%x "
+ "fmr_attr->max_maps=%x fmr_attr->page_shift=%x",
+ fmr_attr->max_pages, fmr_attr->max_maps,
+ fmr_attr->page_shift);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+ if (((1 << fmr_attr->page_shift) != EHCA_PAGESIZE) &&
+ ((1 << fmr_attr->page_shift) != PAGE_SIZE)) {
+ ehca_err(pd->device, "unsupported fmr_attr->page_shift=%x",
+ fmr_attr->page_shift);
+ ib_fmr = ERR_PTR(-EINVAL);
+ goto alloc_fmr_exit0;
+ }
+
+ e_fmr = ehca_mr_new();
+ if (!e_fmr) {
+ ib_fmr = ERR_PTR(-ENOMEM);
+ goto alloc_fmr_exit0;
+ }
+ e_fmr->flags |= EHCA_MR_FLAG_FMR;
+
+ /* register MR on HCA */
+ ret = ehca_reg_mr(shca, e_fmr, NULL,
+ fmr_attr->max_pages * (1 << fmr_attr->page_shift),
+ mr_access_flags, e_pd, &pginfo,
+ &tmp_lkey, &tmp_rkey);
+ if (ret) {
+ ib_fmr = ERR_PTR(ret);
+ goto alloc_fmr_exit1;
+ }
+
+ /* successful */
+ e_fmr->fmr_page_size = 1 << fmr_attr->page_shift;
+ e_fmr->fmr_max_pages = fmr_attr->max_pages;
+ e_fmr->fmr_max_maps = fmr_attr->max_maps;
+ e_fmr->fmr_map_cnt = 0;
+ return &e_fmr->ib.ib_fmr;
+
+alloc_fmr_exit1:
+ ehca_mr_delete(e_fmr);
+alloc_fmr_exit0:
+ if (IS_ERR(ib_fmr))
+ ehca_err(pd->device, "rc=%lx pd=%p mr_access_flags=%x "
+ "fmr_attr=%p", PTR_ERR(ib_fmr), pd,
+ mr_access_flags, fmr_attr);
+ return ib_fmr;
+} /* end ehca_alloc_fmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_map_phys_fmr(struct ib_fmr *fmr,
+ u64 *page_list,
+ int list_len,
+ u64 iova)
+{
+ int ret;
+ struct ehca_shca *shca =
+ container_of(fmr->device, struct ehca_shca, ib_device);
+ struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
+ struct ehca_pd *e_pd = container_of(fmr->pd, struct ehca_pd, ib_pd);
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ u32 tmp_lkey, tmp_rkey;
+
+ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
+ ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x",
+ e_fmr, e_fmr->flags);
+ ret = -EINVAL;
+ goto map_phys_fmr_exit0;
+ }
+ ret = ehca_fmr_check_page_list(e_fmr, page_list, list_len);
+ if (ret)
+ goto map_phys_fmr_exit0;
+ if (iova % e_fmr->fmr_page_size) {
+ /* only whole-numbered pages */
+ ehca_err(fmr->device, "bad iova, iova=%lx fmr_page_size=%x",
+ iova, e_fmr->fmr_page_size);
+ ret = -EINVAL;
+ goto map_phys_fmr_exit0;
+ }
+ if (e_fmr->fmr_map_cnt >= e_fmr->fmr_max_maps) {
+ /* HCAD does not limit the maps, however trace this anyway */
+ ehca_info(fmr->device, "map limit exceeded, fmr=%p "
+ "e_fmr->fmr_map_cnt=%x e_fmr->fmr_max_maps=%x",
+ fmr, e_fmr->fmr_map_cnt, e_fmr->fmr_max_maps);
+ }
+
+ pginfo.type = EHCA_MR_PGI_FMR;
+ pginfo.num_pages = list_len;
+ pginfo.num_4k = list_len * (e_fmr->fmr_page_size / EHCA_PAGESIZE);
+ pginfo.page_list = page_list;
+ pginfo.next_4k = ((iova & (e_fmr->fmr_page_size-1)) /
+ EHCA_PAGESIZE);
+
+ ret = ehca_rereg_mr(shca, e_fmr, (u64*)iova,
+ list_len * e_fmr->fmr_page_size,
+ e_fmr->acl, e_pd, &pginfo, &tmp_lkey, &tmp_rkey);
+ if (ret)
+ goto map_phys_fmr_exit0;
+
+ /* successful reregistration */
+ e_fmr->fmr_map_cnt++;
+ e_fmr->ib.ib_fmr.lkey = tmp_lkey;
+ e_fmr->ib.ib_fmr.rkey = tmp_rkey;
+ return 0;
+
+map_phys_fmr_exit0:
+ if (ret)
+ ehca_err(fmr->device, "ret=%x fmr=%p page_list=%p list_len=%x "
+ "iova=%lx",
+ ret, fmr, page_list, list_len, iova);
+ return ret;
+} /* end ehca_map_phys_fmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_unmap_fmr(struct list_head *fmr_list)
+{
+ int ret = 0;
+ struct ib_fmr *ib_fmr;
+ struct ehca_shca *shca = NULL;
+ struct ehca_shca *prev_shca;
+ struct ehca_mr *e_fmr;
+ u32 num_fmr = 0;
+ u32 unmap_fmr_cnt = 0;
+
+ /* check all FMR belong to same SHCA, and check internal flag */
+ list_for_each_entry(ib_fmr, fmr_list, list) {
+ prev_shca = shca;
+ if (!ib_fmr) {
+ ehca_gen_err("bad fmr=%p in list", ib_fmr);
+ ret = -EINVAL;
+ goto unmap_fmr_exit0;
+ }
+ shca = container_of(ib_fmr->device, struct ehca_shca,
+ ib_device);
+ e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
+ if ((shca != prev_shca) && prev_shca) {
+ ehca_err(&shca->ib_device, "SHCA mismatch, shca=%p "
+ "prev_shca=%p e_fmr=%p",
+ shca, prev_shca, e_fmr);
+ ret = -EINVAL;
+ goto unmap_fmr_exit0;
+ }
+ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
+ ehca_err(&shca->ib_device, "not a FMR, e_fmr=%p "
+ "e_fmr->flags=%x", e_fmr, e_fmr->flags);
+ ret = -EINVAL;
+ goto unmap_fmr_exit0;
+ }
+ num_fmr++;
+ }
+
+ /* loop over all FMRs to unmap */
+ list_for_each_entry(ib_fmr, fmr_list, list) {
+ unmap_fmr_cnt++;
+ e_fmr = container_of(ib_fmr, struct ehca_mr, ib.ib_fmr);
+ shca = container_of(ib_fmr->device, struct ehca_shca,
+ ib_device);
+ ret = ehca_unmap_one_fmr(shca, e_fmr);
+ if (ret) {
+ /* unmap failed, stop unmapping of rest of FMRs */
+ ehca_err(&shca->ib_device, "unmap of one FMR failed, "
+ "stop rest, e_fmr=%p num_fmr=%x "
+ "unmap_fmr_cnt=%x lkey=%x", e_fmr, num_fmr,
+ unmap_fmr_cnt, e_fmr->ib.ib_fmr.lkey);
+ goto unmap_fmr_exit0;
+ }
+ }
+
+unmap_fmr_exit0:
+ if (ret)
+ ehca_gen_err("ret=%x fmr_list=%p num_fmr=%x unmap_fmr_cnt=%x",
+ ret, fmr_list, num_fmr, unmap_fmr_cnt);
+ return ret;
+} /* end ehca_unmap_fmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_dealloc_fmr(struct ib_fmr *fmr)
+{
+ int ret;
+ u64 h_ret;
+ struct ehca_shca *shca =
+ container_of(fmr->device, struct ehca_shca, ib_device);
+ struct ehca_mr *e_fmr = container_of(fmr, struct ehca_mr, ib.ib_fmr);
+
+ if (!(e_fmr->flags & EHCA_MR_FLAG_FMR)) {
+ ehca_err(fmr->device, "not a FMR, e_fmr=%p e_fmr->flags=%x",
+ e_fmr, e_fmr->flags);
+ ret = -EINVAL;
+ goto free_fmr_exit0;
+ }
+
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(fmr->device, "hipz_free_mr failed, h_ret=%lx e_fmr=%p "
+ "hca_hndl=%lx fmr_hndl=%lx fmr->lkey=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle, fmr->lkey);
+ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ goto free_fmr_exit0;
+ }
+ /* successful deregistration */
+ ehca_mr_delete(e_fmr);
+ return 0;
+
+free_fmr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x fmr=%p", ret, fmr);
+ return ret;
+} /* end ehca_dealloc_fmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey, /*OUT*/
+ u32 *rkey) /*OUT*/
+{
+ int ret;
+ u64 h_ret;
+ u32 hipz_acl;
+ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+ if (ehca_use_hp_mr == 1)
+ hipz_acl |= 0x00000001;
+
+ h_ret = hipz_h_alloc_resource_mr(shca->ipz_hca_handle, e_mr,
+ (u64)iova_start, size, hipz_acl,
+ e_pd->fw_pd, &hipzout);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_alloc_mr failed, h_ret=%lx "
+ "hca_hndl=%lx", h_ret, shca->ipz_hca_handle.handle);
+ ret = ehca_mrmw_map_hrc_alloc(h_ret);
+ goto ehca_reg_mr_exit0;
+ }
+
+ e_mr->ipz_mr_handle = hipzout.handle;
+
+ ret = ehca_reg_mr_rpages(shca, e_mr, pginfo);
+ if (ret)
+ goto ehca_reg_mr_exit1;
+
+ /* successful registration */
+ e_mr->num_pages = pginfo->num_pages;
+ e_mr->num_4k = pginfo->num_4k;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
+ *lkey = hipzout.lkey;
+ *rkey = hipzout.rkey;
+ return 0;
+
+ehca_reg_mr_exit1:
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "h_ret=%lx shca=%p e_mr=%p "
+ "iova_start=%p size=%lx acl=%x e_pd=%p lkey=%x "
+ "pginfo=%p num_pages=%lx num_4k=%lx ret=%x",
+ h_ret, shca, e_mr, iova_start, size, acl, e_pd,
+ hipzout.lkey, pginfo, pginfo->num_pages,
+ pginfo->num_4k, ret);
+ ehca_err(&shca->ib_device, "internal error in ehca_reg_mr, "
+ "not recoverable");
+ }
+ehca_reg_mr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+ "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
+ "num_pages=%lx num_4k=%lx",
+ ret, shca, e_mr, iova_start, size, acl, e_pd, pginfo,
+ pginfo->num_pages, pginfo->num_4k);
+ return ret;
+} /* end ehca_reg_mr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_mr_rpages(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo)
+{
+ int ret = 0;
+ u64 h_ret;
+ u32 rnum;
+ u64 rpage;
+ u32 i;
+ u64 *kpage;
+
+ kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!kpage) {
+ ehca_err(&shca->ib_device, "kpage alloc failed");
+ ret = -ENOMEM;
+ goto ehca_reg_mr_rpages_exit0;
+ }
+
+ /* max 512 pages per shot */
+ for (i = 0; i < ((pginfo->num_4k + 512 - 1) / 512); i++) {
+
+ if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+ rnum = pginfo->num_4k % 512; /* last shot */
+ if (rnum == 0)
+ rnum = 512; /* last shot is full */
+ } else
+ rnum = 512;
+
+ if (rnum > 1) {
+ ret = ehca_set_pagebuf(e_mr, pginfo, rnum, kpage);
+ if (ret) {
+ ehca_err(&shca->ib_device, "ehca_set_pagebuf "
+ "bad rc, ret=%x rnum=%x kpage=%p",
+ ret, rnum, kpage);
+ ret = -EFAULT;
+ goto ehca_reg_mr_rpages_exit1;
+ }
+ rpage = virt_to_abs(kpage);
+ if (!rpage) {
+ ehca_err(&shca->ib_device, "kpage=%p i=%x",
+ kpage, i);
+ ret = -EFAULT;
+ goto ehca_reg_mr_rpages_exit1;
+ }
+ } else { /* rnum==1 */
+ ret = ehca_set_pagebuf_1(e_mr, pginfo, &rpage);
+ if (ret) {
+ ehca_err(&shca->ib_device, "ehca_set_pagebuf_1 "
+ "bad rc, ret=%x i=%x", ret, i);
+ ret = -EFAULT;
+ goto ehca_reg_mr_rpages_exit1;
+ }
+ }
+
+ h_ret = hipz_h_register_rpage_mr(shca->ipz_hca_handle, e_mr,
+ 0, /* pagesize 4k */
+ 0, rpage, rnum);
+
+ if (i == ((pginfo->num_4k + 512 - 1) / 512) - 1) {
+ /*
+ * check for 'registration complete'==H_SUCCESS
+ * and for 'page registered'==H_PAGE_REGISTERED
+ */
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "last "
+ "hipz_reg_rpage_mr failed, h_ret=%lx "
+ "e_mr=%p i=%x hca_hndl=%lx mr_hndl=%lx"
+ " lkey=%x", h_ret, e_mr, i,
+ shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle,
+ e_mr->ib.ib_mr.lkey);
+ ret = ehca_mrmw_map_hrc_rrpg_last(h_ret);
+ break;
+ } else
+ ret = 0;
+ } else if (h_ret != H_PAGE_REGISTERED) {
+ ehca_err(&shca->ib_device, "hipz_reg_rpage_mr failed, "
+ "h_ret=%lx e_mr=%p i=%x lkey=%x hca_hndl=%lx "
+ "mr_hndl=%lx", h_ret, e_mr, i,
+ e_mr->ib.ib_mr.lkey,
+ shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle);
+ ret = ehca_mrmw_map_hrc_rrpg_notlast(h_ret);
+ break;
+ } else
+ ret = 0;
+ } /* end for(i) */
+
+
+ehca_reg_mr_rpages_exit1:
+ kfree(kpage);
+ehca_reg_mr_rpages_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p pginfo=%p "
+ "num_pages=%lx num_4k=%lx", ret, shca, e_mr, pginfo,
+ pginfo->num_pages, pginfo->num_4k);
+ return ret;
+} /* end ehca_reg_mr_rpages() */
+
+/*----------------------------------------------------------------------*/
+
+inline int ehca_rereg_mr_rereg1(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ u32 acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey, /*OUT*/
+ u32 *rkey) /*OUT*/
+{
+ int ret;
+ u64 h_ret;
+ u32 hipz_acl;
+ u64 *kpage;
+ u64 rpage;
+ struct ehca_mr_pginfo pginfo_save;
+ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+
+ kpage = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!kpage) {
+ ehca_err(&shca->ib_device, "kpage alloc failed");
+ ret = -ENOMEM;
+ goto ehca_rereg_mr_rereg1_exit0;
+ }
+
+ pginfo_save = *pginfo;
+ ret = ehca_set_pagebuf(e_mr, pginfo, pginfo->num_4k, kpage);
+ if (ret) {
+ ehca_err(&shca->ib_device, "set pagebuf failed, e_mr=%p "
+ "pginfo=%p type=%x num_pages=%lx num_4k=%lx kpage=%p",
+ e_mr, pginfo, pginfo->type, pginfo->num_pages,
+ pginfo->num_4k,kpage);
+ goto ehca_rereg_mr_rereg1_exit1;
+ }
+ rpage = virt_to_abs(kpage);
+ if (!rpage) {
+ ehca_err(&shca->ib_device, "kpage=%p", kpage);
+ ret = -EFAULT;
+ goto ehca_rereg_mr_rereg1_exit1;
+ }
+ h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_mr,
+ (u64)iova_start, size, hipz_acl,
+ e_pd->fw_pd, rpage, &hipzout);
+ if (h_ret != H_SUCCESS) {
+ /*
+ * reregistration unsuccessful, try it again with the 3 hCalls,
+ * e.g. this is required in case H_MR_CONDITION
+ * (MW bound or MR is shared)
+ */
+ ehca_warn(&shca->ib_device, "hipz_h_reregister_pmr failed "
+ "(Rereg1), h_ret=%lx e_mr=%p", h_ret, e_mr);
+ *pginfo = pginfo_save;
+ ret = -EAGAIN;
+ } else if ((u64*)hipzout.vaddr != iova_start) {
+ ehca_err(&shca->ib_device, "PHYP changed iova_start in "
+ "rereg_pmr, iova_start=%p iova_start_out=%lx e_mr=%p "
+ "mr_handle=%lx lkey=%x lkey_out=%x", iova_start,
+ hipzout.vaddr, e_mr, e_mr->ipz_mr_handle.handle,
+ e_mr->ib.ib_mr.lkey, hipzout.lkey);
+ ret = -EFAULT;
+ } else {
+ /*
+ * successful reregistration
+ * note: start and start_out are identical for eServer HCAs
+ */
+ e_mr->num_pages = pginfo->num_pages;
+ e_mr->num_4k = pginfo->num_4k;
+ e_mr->start = iova_start;
+ e_mr->size = size;
+ e_mr->acl = acl;
+ *lkey = hipzout.lkey;
+ *rkey = hipzout.rkey;
+ }
+
+ehca_rereg_mr_rereg1_exit1:
+ kfree(kpage);
+ehca_rereg_mr_rereg1_exit0:
+ if ( ret && (ret != -EAGAIN) )
+ ehca_err(&shca->ib_device, "ret=%x lkey=%x rkey=%x "
+ "pginfo=%p num_pages=%lx num_4k=%lx",
+ ret, *lkey, *rkey, pginfo, pginfo->num_pages,
+ pginfo->num_4k);
+ return ret;
+} /* end ehca_rereg_mr_rereg1() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_rereg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey,
+ u32 *rkey)
+{
+ int ret = 0;
+ u64 h_ret;
+ int rereg_1_hcall = 1; /* 1: use hipz_h_reregister_pmr directly */
+ int rereg_3_hcall = 0; /* 1: use 3 hipz calls for reregistration */
+
+ /* first determine reregistration hCall(s) */
+ if ((pginfo->num_4k > 512) || (e_mr->num_4k > 512) ||
+ (pginfo->num_4k > e_mr->num_4k)) {
+ ehca_dbg(&shca->ib_device, "Rereg3 case, pginfo->num_4k=%lx "
+ "e_mr->num_4k=%x", pginfo->num_4k, e_mr->num_4k);
+ rereg_1_hcall = 0;
+ rereg_3_hcall = 1;
+ }
+
+ if (e_mr->flags & EHCA_MR_FLAG_MAXMR) { /* check for max-MR */
+ rereg_1_hcall = 0;
+ rereg_3_hcall = 1;
+ e_mr->flags &= ~EHCA_MR_FLAG_MAXMR;
+ ehca_err(&shca->ib_device, "Rereg MR for max-MR! e_mr=%p",
+ e_mr);
+ }
+
+ if (rereg_1_hcall) {
+ ret = ehca_rereg_mr_rereg1(shca, e_mr, iova_start, size,
+ acl, e_pd, pginfo, lkey, rkey);
+ if (ret) {
+ if (ret == -EAGAIN)
+ rereg_3_hcall = 1;
+ else
+ goto ehca_rereg_mr_exit0;
+ }
+ }
+
+ if (rereg_3_hcall) {
+ struct ehca_mr save_mr;
+
+ /* first deregister old MR */
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_mr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+ "h_ret=%lx e_mr=%p hca_hndl=%lx mr_hndl=%lx "
+ "mr->lkey=%x",
+ h_ret, e_mr, shca->ipz_hca_handle.handle,
+ e_mr->ipz_mr_handle.handle,
+ e_mr->ib.ib_mr.lkey);
+ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ goto ehca_rereg_mr_exit0;
+ }
+ /* clean ehca_mr_t, without changing struct ib_mr and lock */
+ save_mr = *e_mr;
+ ehca_mr_deletenew(e_mr);
+
+ /* set some MR values */
+ e_mr->flags = save_mr.flags;
+ e_mr->fmr_page_size = save_mr.fmr_page_size;
+ e_mr->fmr_max_pages = save_mr.fmr_max_pages;
+ e_mr->fmr_max_maps = save_mr.fmr_max_maps;
+ e_mr->fmr_map_cnt = save_mr.fmr_map_cnt;
+
+ ret = ehca_reg_mr(shca, e_mr, iova_start, size, acl,
+ e_pd, pginfo, lkey, rkey);
+ if (ret) {
+ u32 offset = (u64)(&e_mr->flags) - (u64)e_mr;
+ memcpy(&e_mr->flags, &(save_mr.flags),
+ sizeof(struct ehca_mr) - offset);
+ goto ehca_rereg_mr_exit0;
+ }
+ }
+
+ehca_rereg_mr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x shca=%p e_mr=%p "
+ "iova_start=%p size=%lx acl=%x e_pd=%p pginfo=%p "
+ "num_pages=%lx lkey=%x rkey=%x rereg_1_hcall=%x "
+ "rereg_3_hcall=%x", ret, shca, e_mr, iova_start, size,
+ acl, e_pd, pginfo, pginfo->num_pages, *lkey, *rkey,
+ rereg_1_hcall, rereg_3_hcall);
+ return ret;
+} /* end ehca_rereg_mr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_unmap_one_fmr(struct ehca_shca *shca,
+ struct ehca_mr *e_fmr)
+{
+ int ret = 0;
+ u64 h_ret;
+ int rereg_1_hcall = 1; /* 1: use hipz_mr_reregister directly */
+ int rereg_3_hcall = 0; /* 1: use 3 hipz calls for unmapping */
+ struct ehca_pd *e_pd =
+ container_of(e_fmr->ib.ib_fmr.pd, struct ehca_pd, ib_pd);
+ struct ehca_mr save_fmr;
+ u32 tmp_lkey, tmp_rkey;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+
+ /* first check if reregistration hCall can be used for unmap */
+ if (e_fmr->fmr_max_pages > 512) {
+ rereg_1_hcall = 0;
+ rereg_3_hcall = 1;
+ }
+
+ if (rereg_1_hcall) {
+ /*
+ * note: after using rereg hcall with len=0,
+ * rereg hcall must be used again for registering pages
+ */
+ h_ret = hipz_h_reregister_pmr(shca->ipz_hca_handle, e_fmr, 0,
+ 0, 0, e_pd->fw_pd, 0, &hipzout);
+ if (h_ret != H_SUCCESS) {
+ /*
+ * should not happen, because length checked above,
+ * FMRs are not shared and no MW bound to FMRs
+ */
+ ehca_err(&shca->ib_device, "hipz_reregister_pmr failed "
+ "(Rereg1), h_ret=%lx e_fmr=%p hca_hndl=%lx "
+ "mr_hndl=%lx lkey=%x lkey_out=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey, hipzout.lkey);
+ rereg_3_hcall = 1;
+ } else {
+ /* successful reregistration */
+ e_fmr->start = NULL;
+ e_fmr->size = 0;
+ tmp_lkey = hipzout.lkey;
+ tmp_rkey = hipzout.rkey;
+ }
+ }
+
+ if (rereg_3_hcall) {
+ struct ehca_mr save_mr;
+
+ /* first free old FMR */
+ h_ret = hipz_h_free_resource_mr(shca->ipz_hca_handle, e_fmr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_free_mr failed, "
+ "h_ret=%lx e_fmr=%p hca_hndl=%lx mr_hndl=%lx "
+ "lkey=%x",
+ h_ret, e_fmr, shca->ipz_hca_handle.handle,
+ e_fmr->ipz_mr_handle.handle,
+ e_fmr->ib.ib_fmr.lkey);
+ ret = ehca_mrmw_map_hrc_free_mr(h_ret);
+ goto ehca_unmap_one_fmr_exit0;
+ }
+ /* clean ehca_mr_t, without changing lock */
+ save_fmr = *e_fmr;
+ ehca_mr_deletenew(e_fmr);
+
+ /* set some MR values */
+ e_fmr->flags = save_fmr.flags;
+ e_fmr->fmr_page_size = save_fmr.fmr_page_size;
+ e_fmr->fmr_max_pages = save_fmr.fmr_max_pages;
+ e_fmr->fmr_max_maps = save_fmr.fmr_max_maps;
+ e_fmr->fmr_map_cnt = save_fmr.fmr_map_cnt;
+ e_fmr->acl = save_fmr.acl;
+
+ pginfo.type = EHCA_MR_PGI_FMR;
+ pginfo.num_pages = 0;
+ pginfo.num_4k = 0;
+ ret = ehca_reg_mr(shca, e_fmr, NULL,
+ (e_fmr->fmr_max_pages * e_fmr->fmr_page_size),
+ e_fmr->acl, e_pd, &pginfo, &tmp_lkey,
+ &tmp_rkey);
+ if (ret) {
+ u32 offset = (u64)(&e_fmr->flags) - (u64)e_fmr;
+ memcpy(&e_fmr->flags, &(save_mr.flags),
+ sizeof(struct ehca_mr) - offset);
+ goto ehca_unmap_one_fmr_exit0;
+ }
+ }
+
+ehca_unmap_one_fmr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x tmp_lkey=%x tmp_rkey=%x "
+ "fmr_max_pages=%x rereg_1_hcall=%x rereg_3_hcall=%x",
+ ret, tmp_lkey, tmp_rkey, e_fmr->fmr_max_pages,
+ rereg_1_hcall, rereg_3_hcall);
+ return ret;
+} /* end ehca_unmap_one_fmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_smr(struct ehca_shca *shca,
+ struct ehca_mr *e_origmr,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey, /*OUT*/
+ u32 *rkey) /*OUT*/
+{
+ int ret = 0;
+ u64 h_ret;
+ u32 hipz_acl;
+ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+
+ h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
+ (u64)iova_start, hipz_acl, e_pd->fw_pd,
+ &hipzout);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+ "shca=%p e_origmr=%p e_newmr=%p iova_start=%p acl=%x "
+ "e_pd=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ h_ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd,
+ shca->ipz_hca_handle.handle,
+ e_origmr->ipz_mr_handle.handle,
+ e_origmr->ib.ib_mr.lkey);
+ ret = ehca_mrmw_map_hrc_reg_smr(h_ret);
+ goto ehca_reg_smr_exit0;
+ }
+ /* successful registration */
+ e_newmr->num_pages = e_origmr->num_pages;
+ e_newmr->num_4k = e_origmr->num_4k;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
+ e_newmr->ipz_mr_handle = hipzout.handle;
+ *lkey = hipzout.lkey;
+ *rkey = hipzout.rkey;
+ return 0;
+
+ehca_reg_smr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x shca=%p e_origmr=%p "
+ "e_newmr=%p iova_start=%p acl=%x e_pd=%p",
+ ret, shca, e_origmr, e_newmr, iova_start, acl, e_pd);
+ return ret;
+} /* end ehca_reg_smr() */
+
+/*----------------------------------------------------------------------*/
+
+/* register internal max-MR to internal SHCA */
+int ehca_reg_internal_maxmr(
+ struct ehca_shca *shca,
+ struct ehca_pd *e_pd,
+ struct ehca_mr **e_maxmr) /*OUT*/
+{
+ int ret;
+ struct ehca_mr *e_mr;
+ u64 *iova_start;
+ u64 size_maxmr;
+ struct ehca_mr_pginfo pginfo={0,0,0,0,0,0,0,NULL,0,NULL,NULL,0,NULL,0};
+ struct ib_phys_buf ib_pbuf;
+ u32 num_pages_mr;
+ u32 num_pages_4k; /* 4k portion "pages" */
+
+ e_mr = ehca_mr_new();
+ if (!e_mr) {
+ ehca_err(&shca->ib_device, "out of memory");
+ ret = -ENOMEM;
+ goto ehca_reg_internal_maxmr_exit0;
+ }
+ e_mr->flags |= EHCA_MR_FLAG_MAXMR;
+
+ /* register internal max-MR on HCA */
+ size_maxmr = (u64)high_memory - PAGE_OFFSET;
+ iova_start = (u64*)KERNELBASE;
+ ib_pbuf.addr = 0;
+ ib_pbuf.size = size_maxmr;
+ num_pages_mr = ((((u64)iova_start % PAGE_SIZE) + size_maxmr +
+ PAGE_SIZE - 1) / PAGE_SIZE);
+ num_pages_4k = ((((u64)iova_start % EHCA_PAGESIZE) + size_maxmr +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE);
+
+ pginfo.type = EHCA_MR_PGI_PHYS;
+ pginfo.num_pages = num_pages_mr;
+ pginfo.num_4k = num_pages_4k;
+ pginfo.num_phys_buf = 1;
+ pginfo.phys_buf_array = &ib_pbuf;
+
+ ret = ehca_reg_mr(shca, e_mr, iova_start, size_maxmr, 0, e_pd,
+ &pginfo, &e_mr->ib.ib_mr.lkey,
+ &e_mr->ib.ib_mr.rkey);
+ if (ret) {
+ ehca_err(&shca->ib_device, "reg of internal max MR failed, "
+ "e_mr=%p iova_start=%p size_maxmr=%lx num_pages_mr=%x "
+ "num_pages_4k=%x", e_mr, iova_start, size_maxmr,
+ num_pages_mr, num_pages_4k);
+ goto ehca_reg_internal_maxmr_exit1;
+ }
+
+ /* successful registration of all pages */
+ e_mr->ib.ib_mr.device = e_pd->ib_pd.device;
+ e_mr->ib.ib_mr.pd = &e_pd->ib_pd;
+ e_mr->ib.ib_mr.uobject = NULL;
+ atomic_inc(&(e_pd->ib_pd.usecnt));
+ atomic_set(&(e_mr->ib.ib_mr.usecnt), 0);
+ *e_maxmr = e_mr;
+ return 0;
+
+ehca_reg_internal_maxmr_exit1:
+ ehca_mr_delete(e_mr);
+ehca_reg_internal_maxmr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x shca=%p e_pd=%p e_maxmr=%p",
+ ret, shca, e_pd, e_maxmr);
+ return ret;
+} /* end ehca_reg_internal_maxmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_reg_maxmr(struct ehca_shca *shca,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey,
+ u32 *rkey)
+{
+ u64 h_ret;
+ struct ehca_mr *e_origmr = shca->maxmr;
+ u32 hipz_acl;
+ struct ehca_mr_hipzout_parms hipzout = {{0},0,0,0,0,0};
+
+ ehca_mrmw_map_acl(acl, &hipz_acl);
+ ehca_mrmw_set_pgsize_hipz_acl(&hipz_acl);
+
+ h_ret = hipz_h_register_smr(shca->ipz_hca_handle, e_newmr, e_origmr,
+ (u64)iova_start, hipz_acl, e_pd->fw_pd,
+ &hipzout);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_reg_smr failed, h_ret=%lx "
+ "e_origmr=%p hca_hndl=%lx mr_hndl=%lx lkey=%x",
+ h_ret, e_origmr, shca->ipz_hca_handle.handle,
+ e_origmr->ipz_mr_handle.handle,
+ e_origmr->ib.ib_mr.lkey);
+ return ehca_mrmw_map_hrc_reg_smr(h_ret);
+ }
+ /* successful registration */
+ e_newmr->num_pages = e_origmr->num_pages;
+ e_newmr->num_4k = e_origmr->num_4k;
+ e_newmr->start = iova_start;
+ e_newmr->size = e_origmr->size;
+ e_newmr->acl = acl;
+ e_newmr->ipz_mr_handle = hipzout.handle;
+ *lkey = hipzout.lkey;
+ *rkey = hipzout.rkey;
+ return 0;
+} /* end ehca_reg_maxmr() */
+
+/*----------------------------------------------------------------------*/
+
+int ehca_dereg_internal_maxmr(struct ehca_shca *shca)
+{
+ int ret;
+ struct ehca_mr *e_maxmr;
+ struct ib_pd *ib_pd;
+
+ if (!shca->maxmr) {
+ ehca_err(&shca->ib_device, "bad call, shca=%p", shca);
+ ret = -EINVAL;
+ goto ehca_dereg_internal_maxmr_exit0;
+ }
+
+ e_maxmr = shca->maxmr;
+ ib_pd = e_maxmr->ib.ib_mr.pd;
+ shca->maxmr = NULL; /* remove internal max-MR indication from SHCA */
+
+ ret = ehca_dereg_mr(&e_maxmr->ib.ib_mr);
+ if (ret) {
+ ehca_err(&shca->ib_device, "dereg internal max-MR failed, "
+ "ret=%x e_maxmr=%p shca=%p lkey=%x",
+ ret, e_maxmr, shca, e_maxmr->ib.ib_mr.lkey);
+ shca->maxmr = e_maxmr;
+ goto ehca_dereg_internal_maxmr_exit0;
+ }
+
+ atomic_dec(&ib_pd->usecnt);
+
+ehca_dereg_internal_maxmr_exit0:
+ if (ret)
+ ehca_err(&shca->ib_device, "ret=%x shca=%p shca->maxmr=%p",
+ ret, shca, shca->maxmr);
+ return ret;
+} /* end ehca_dereg_internal_maxmr() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * check physical buffer array of MR verbs for validness and
+ * calculates MR size
+ */
+int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ u64 *iova_start,
+ u64 *size)
+{
+ struct ib_phys_buf *pbuf = phys_buf_array;
+ u64 size_count = 0;
+ u32 i;
+
+ if (num_phys_buf == 0) {
+ ehca_gen_err("bad phys buf array len, num_phys_buf=0");
+ return -EINVAL;
+ }
+ /* check first buffer */
+ if (((u64)iova_start & ~PAGE_MASK) != (pbuf->addr & ~PAGE_MASK)) {
+ ehca_gen_err("iova_start/addr mismatch, iova_start=%p "
+ "pbuf->addr=%lx pbuf->size=%lx",
+ iova_start, pbuf->addr, pbuf->size);
+ return -EINVAL;
+ }
+ if (((pbuf->addr + pbuf->size) % PAGE_SIZE) &&
+ (num_phys_buf > 1)) {
+ ehca_gen_err("addr/size mismatch in 1st buf, pbuf->addr=%lx "
+ "pbuf->size=%lx", pbuf->addr, pbuf->size);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_phys_buf; i++) {
+ if ((i > 0) && (pbuf->addr % PAGE_SIZE)) {
+ ehca_gen_err("bad address, i=%x pbuf->addr=%lx "
+ "pbuf->size=%lx",
+ i, pbuf->addr, pbuf->size);
+ return -EINVAL;
+ }
+ if (((i > 0) && /* not 1st */
+ (i < (num_phys_buf - 1)) && /* not last */
+ (pbuf->size % PAGE_SIZE)) || (pbuf->size == 0)) {
+ ehca_gen_err("bad size, i=%x pbuf->size=%lx",
+ i, pbuf->size);
+ return -EINVAL;
+ }
+ size_count += pbuf->size;
+ pbuf++;
+ }
+
+ *size = size_count;
+ return 0;
+} /* end ehca_mr_chk_buf_and_calc_size() */
+
+/*----------------------------------------------------------------------*/
+
+/* check page list of map FMR verb for validness */
+int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
+ u64 *page_list,
+ int list_len)
+{
+ u32 i;
+ u64 *page;
+
+ if ((list_len == 0) || (list_len > e_fmr->fmr_max_pages)) {
+ ehca_gen_err("bad list_len, list_len=%x "
+ "e_fmr->fmr_max_pages=%x fmr=%p",
+ list_len, e_fmr->fmr_max_pages, e_fmr);
+ return -EINVAL;
+ }
+
+ /* each page must be aligned */
+ page = page_list;
+ for (i = 0; i < list_len; i++) {
+ if (*page % e_fmr->fmr_page_size) {
+ ehca_gen_err("bad page, i=%x *page=%lx page=%p fmr=%p "
+ "fmr_page_size=%x", i, *page, page, e_fmr,
+ e_fmr->fmr_page_size);
+ return -EINVAL;
+ }
+ page++;
+ }
+
+ return 0;
+} /* end ehca_fmr_check_page_list() */
+
+/*----------------------------------------------------------------------*/
+
+/* setup page buffer from page info */
+int ehca_set_pagebuf(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage)
+{
+ int ret = 0;
+ struct ib_umem_chunk *prev_chunk;
+ struct ib_umem_chunk *chunk;
+ struct ib_phys_buf *pbuf;
+ u64 *fmrlist;
+ u64 num4k, pgaddr, offs4k;
+ u32 i = 0;
+ u32 j = 0;
+
+ if (pginfo->type == EHCA_MR_PGI_PHYS) {
+ /* loop over desired phys_buf_array entries */
+ while (i < number) {
+ pbuf = pginfo->phys_buf_array + pginfo->next_buf;
+ num4k = ((pbuf->addr % EHCA_PAGESIZE) + pbuf->size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
+ offs4k = (pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
+ while (pginfo->next_4k < offs4k + num4k) {
+ /* sanity check */
+ if ((pginfo->page_cnt >= pginfo->num_pages) ||
+ (pginfo->page_4k_cnt >= pginfo->num_4k)) {
+ ehca_gen_err("page_cnt >= num_pages, "
+ "page_cnt=%lx "
+ "num_pages=%lx "
+ "page_4k_cnt=%lx "
+ "num_4k=%lx i=%x",
+ pginfo->page_cnt,
+ pginfo->num_pages,
+ pginfo->page_4k_cnt,
+ pginfo->num_4k, i);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ *kpage = phys_to_abs(
+ (pbuf->addr & EHCA_PAGEMASK)
+ + (pginfo->next_4k * EHCA_PAGESIZE));
+ if ( !(*kpage) && pbuf->addr ) {
+ ehca_gen_err("pbuf->addr=%lx "
+ "pbuf->size=%lx "
+ "next_4k=%lx", pbuf->addr,
+ pbuf->size,
+ pginfo->next_4k);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if (pginfo->next_4k %
+ (PAGE_SIZE / EHCA_PAGESIZE) == 0)
+ (pginfo->page_cnt)++;
+ kpage++;
+ i++;
+ if (i >= number) break;
+ }
+ if (pginfo->next_4k >= offs4k + num4k) {
+ (pginfo->next_buf)++;
+ pginfo->next_4k = 0;
+ }
+ }
+ } else if (pginfo->type == EHCA_MR_PGI_USER) {
+ /* loop over desired chunk entries */
+ chunk = pginfo->next_chunk;
+ prev_chunk = pginfo->next_chunk;
+ list_for_each_entry_continue(chunk,
+ (&(pginfo->region->chunk_list)),
+ list) {
+ for (i = pginfo->next_nmap; i < chunk->nmap; ) {
+ pgaddr = ( page_to_pfn(chunk->page_list[i].page)
+ << PAGE_SHIFT );
+ *kpage = phys_to_abs(pgaddr +
+ (pginfo->next_4k *
+ EHCA_PAGESIZE));
+ if ( !(*kpage) ) {
+ ehca_gen_err("pgaddr=%lx "
+ "chunk->page_list[i]=%lx "
+ "i=%x next_4k=%lx mr=%p",
+ pgaddr,
+ (u64)sg_dma_address(
+ &chunk->
+ page_list[i]),
+ i, pginfo->next_4k, e_mr);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ kpage++;
+ if (pginfo->next_4k %
+ (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_nmap)++;
+ pginfo->next_4k = 0;
+ i++;
+ }
+ j++;
+ if (j >= number) break;
+ }
+ if ((pginfo->next_nmap >= chunk->nmap) &&
+ (j >= number)) {
+ pginfo->next_nmap = 0;
+ prev_chunk = chunk;
+ break;
+ } else if (pginfo->next_nmap >= chunk->nmap) {
+ pginfo->next_nmap = 0;
+ prev_chunk = chunk;
+ } else if (j >= number)
+ break;
+ else
+ prev_chunk = chunk;
+ }
+ pginfo->next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->region->chunk_list)),
+ list);
+ } else if (pginfo->type == EHCA_MR_PGI_FMR) {
+ /* loop over desired page_list entries */
+ fmrlist = pginfo->page_list + pginfo->next_listelem;
+ for (i = 0; i < number; i++) {
+ *kpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
+ pginfo->next_4k * EHCA_PAGESIZE);
+ if ( !(*kpage) ) {
+ ehca_gen_err("*fmrlist=%lx fmrlist=%p "
+ "next_listelem=%lx next_4k=%lx",
+ *fmrlist, fmrlist,
+ pginfo->next_listelem,
+ pginfo->next_4k);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ kpage++;
+ if (pginfo->next_4k %
+ (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_listelem)++;
+ fmrlist++;
+ pginfo->next_4k = 0;
+ }
+ }
+ } else {
+ ehca_gen_err("bad pginfo->type=%x", pginfo->type);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_exit0;
+ }
+
+ehca_set_pagebuf_exit0:
+ if (ret)
+ ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
+ "num_4k=%lx next_buf=%lx next_4k=%lx number=%x "
+ "kpage=%p page_cnt=%lx page_4k_cnt=%lx i=%x "
+ "next_listelem=%lx region=%p next_chunk=%p "
+ "next_nmap=%lx", ret, e_mr, pginfo, pginfo->type,
+ pginfo->num_pages, pginfo->num_4k,
+ pginfo->next_buf, pginfo->next_4k, number, kpage,
+ pginfo->page_cnt, pginfo->page_4k_cnt, i,
+ pginfo->next_listelem, pginfo->region,
+ pginfo->next_chunk, pginfo->next_nmap);
+ return ret;
+} /* end ehca_set_pagebuf() */
+
+/*----------------------------------------------------------------------*/
+
+/* setup 1 page from page info page buffer */
+int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u64 *rpage)
+{
+ int ret = 0;
+ struct ib_phys_buf *tmp_pbuf;
+ u64 *fmrlist;
+ struct ib_umem_chunk *chunk;
+ struct ib_umem_chunk *prev_chunk;
+ u64 pgaddr, num4k, offs4k;
+
+ if (pginfo->type == EHCA_MR_PGI_PHYS) {
+ /* sanity check */
+ if ((pginfo->page_cnt >= pginfo->num_pages) ||
+ (pginfo->page_4k_cnt >= pginfo->num_4k)) {
+ ehca_gen_err("page_cnt >= num_pages, page_cnt=%lx "
+ "num_pages=%lx page_4k_cnt=%lx num_4k=%lx",
+ pginfo->page_cnt, pginfo->num_pages,
+ pginfo->page_4k_cnt, pginfo->num_4k);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ tmp_pbuf = pginfo->phys_buf_array + pginfo->next_buf;
+ num4k = ((tmp_pbuf->addr % EHCA_PAGESIZE) + tmp_pbuf->size +
+ EHCA_PAGESIZE - 1) / EHCA_PAGESIZE;
+ offs4k = (tmp_pbuf->addr & ~PAGE_MASK) / EHCA_PAGESIZE;
+ *rpage = phys_to_abs((tmp_pbuf->addr & EHCA_PAGEMASK) +
+ (pginfo->next_4k * EHCA_PAGESIZE));
+ if ( !(*rpage) && tmp_pbuf->addr ) {
+ ehca_gen_err("tmp_pbuf->addr=%lx"
+ " tmp_pbuf->size=%lx next_4k=%lx",
+ tmp_pbuf->addr, tmp_pbuf->size,
+ pginfo->next_4k);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if (pginfo->next_4k % (PAGE_SIZE / EHCA_PAGESIZE) == 0)
+ (pginfo->page_cnt)++;
+ if (pginfo->next_4k >= offs4k + num4k) {
+ (pginfo->next_buf)++;
+ pginfo->next_4k = 0;
+ }
+ } else if (pginfo->type == EHCA_MR_PGI_USER) {
+ chunk = pginfo->next_chunk;
+ prev_chunk = pginfo->next_chunk;
+ list_for_each_entry_continue(chunk,
+ (&(pginfo->region->chunk_list)),
+ list) {
+ pgaddr = ( page_to_pfn(chunk->page_list[
+ pginfo->next_nmap].page)
+ << PAGE_SHIFT);
+ *rpage = phys_to_abs(pgaddr +
+ (pginfo->next_4k * EHCA_PAGESIZE));
+ if ( !(*rpage) ) {
+ ehca_gen_err("pgaddr=%lx chunk->page_list[]=%lx"
+ " next_nmap=%lx next_4k=%lx mr=%p",
+ pgaddr, (u64)sg_dma_address(
+ &chunk->page_list[
+ pginfo->
+ next_nmap]),
+ pginfo->next_nmap, pginfo->next_4k,
+ e_mr);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if (pginfo->next_4k %
+ (PAGE_SIZE / EHCA_PAGESIZE) == 0) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_nmap)++;
+ pginfo->next_4k = 0;
+ }
+ if (pginfo->next_nmap >= chunk->nmap) {
+ pginfo->next_nmap = 0;
+ prev_chunk = chunk;
+ }
+ break;
+ }
+ pginfo->next_chunk =
+ list_prepare_entry(prev_chunk,
+ (&(pginfo->region->chunk_list)),
+ list);
+ } else if (pginfo->type == EHCA_MR_PGI_FMR) {
+ fmrlist = pginfo->page_list + pginfo->next_listelem;
+ *rpage = phys_to_abs((*fmrlist & EHCA_PAGEMASK) +
+ pginfo->next_4k * EHCA_PAGESIZE);
+ if ( !(*rpage) ) {
+ ehca_gen_err("*fmrlist=%lx fmrlist=%p "
+ "next_listelem=%lx next_4k=%lx",
+ *fmrlist, fmrlist, pginfo->next_listelem,
+ pginfo->next_4k);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+ (pginfo->page_4k_cnt)++;
+ (pginfo->next_4k)++;
+ if (pginfo->next_4k %
+ (e_mr->fmr_page_size / EHCA_PAGESIZE) == 0) {
+ (pginfo->page_cnt)++;
+ (pginfo->next_listelem)++;
+ pginfo->next_4k = 0;
+ }
+ } else {
+ ehca_gen_err("bad pginfo->type=%x", pginfo->type);
+ ret = -EFAULT;
+ goto ehca_set_pagebuf_1_exit0;
+ }
+
+ehca_set_pagebuf_1_exit0:
+ if (ret)
+ ehca_gen_err("ret=%x e_mr=%p pginfo=%p type=%x num_pages=%lx "
+ "num_4k=%lx next_buf=%lx next_4k=%lx rpage=%p "
+ "page_cnt=%lx page_4k_cnt=%lx next_listelem=%lx "
+ "region=%p next_chunk=%p next_nmap=%lx", ret, e_mr,
+ pginfo, pginfo->type, pginfo->num_pages,
+ pginfo->num_4k, pginfo->next_buf, pginfo->next_4k,
+ rpage, pginfo->page_cnt, pginfo->page_4k_cnt,
+ pginfo->next_listelem, pginfo->region,
+ pginfo->next_chunk, pginfo->next_nmap);
+ return ret;
+} /* end ehca_set_pagebuf_1() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * check MR if it is a max-MR, i.e. uses whole memory
+ * in case it's a max-MR 1 is returned, else 0
+ */
+int ehca_mr_is_maxmr(u64 size,
+ u64 *iova_start)
+{
+ /* a MR is treated as max-MR only if it fits following: */
+ if ((size == ((u64)high_memory - PAGE_OFFSET)) &&
+ (iova_start == (void*)KERNELBASE)) {
+ ehca_gen_dbg("this is a max-MR");
+ return 1;
+ } else
+ return 0;
+} /* end ehca_mr_is_maxmr() */
+
+/*----------------------------------------------------------------------*/
+
+/* map access control for MR/MW. This routine is used for MR and MW. */
+void ehca_mrmw_map_acl(int ib_acl,
+ u32 *hipz_acl)
+{
+ *hipz_acl = 0;
+ if (ib_acl & IB_ACCESS_REMOTE_READ)
+ *hipz_acl |= HIPZ_ACCESSCTRL_R_READ;
+ if (ib_acl & IB_ACCESS_REMOTE_WRITE)
+ *hipz_acl |= HIPZ_ACCESSCTRL_R_WRITE;
+ if (ib_acl & IB_ACCESS_REMOTE_ATOMIC)
+ *hipz_acl |= HIPZ_ACCESSCTRL_R_ATOMIC;
+ if (ib_acl & IB_ACCESS_LOCAL_WRITE)
+ *hipz_acl |= HIPZ_ACCESSCTRL_L_WRITE;
+ if (ib_acl & IB_ACCESS_MW_BIND)
+ *hipz_acl |= HIPZ_ACCESSCTRL_MW_BIND;
+} /* end ehca_mrmw_map_acl() */
+
+/*----------------------------------------------------------------------*/
+
+/* sets page size in hipz access control for MR/MW. */
+void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl) /*INOUT*/
+{
+ return; /* HCA supports only 4k */
+} /* end ehca_mrmw_set_pgsize_hipz_acl() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * reverse map access control for MR/MW.
+ * This routine is used for MR and MW.
+ */
+void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
+ int *ib_acl) /*OUT*/
+{
+ *ib_acl = 0;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_R_READ)
+ *ib_acl |= IB_ACCESS_REMOTE_READ;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_R_WRITE)
+ *ib_acl |= IB_ACCESS_REMOTE_WRITE;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_R_ATOMIC)
+ *ib_acl |= IB_ACCESS_REMOTE_ATOMIC;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_L_WRITE)
+ *ib_acl |= IB_ACCESS_LOCAL_WRITE;
+ if (*hipz_acl & HIPZ_ACCESSCTRL_MW_BIND)
+ *ib_acl |= IB_ACCESS_MW_BIND;
+} /* end ehca_mrmw_reverse_map_acl() */
+
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * map HIPZ rc to IB retcodes for MR/MW allocations
+ * Used for hipz_mr_reg_alloc and hipz_mw_alloc.
+ */
+int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_SUCCESS: /* successful completion */
+ return 0;
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RT_PARM: /* invalid resource type */
+ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+ case H_MLENGTH_PARM: /* invalid memory length */
+ case H_MEM_ACCESS_PARM: /* invalid access controls */
+ case H_CONSTRAINED: /* resource constraint */
+ return -EINVAL;
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_alloc() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * map HIPZ rc to IB retcodes for MR register rpage
+ * Used for hipz_h_register_rpage_mr at registering last page
+ */
+int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_SUCCESS: /* registration complete */
+ return 0;
+ case H_PAGE_REGISTERED: /* page registered */
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+/* case H_QT_PARM: invalid queue type */
+ case H_PARAMETER: /*
+ * invalid logical address,
+ * or count zero or greater 512
+ */
+ case H_TABLE_FULL: /* page table full */
+ case H_HARDWARE: /* HCA not operational */
+ return -EINVAL;
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_rrpg_last() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * map HIPZ rc to IB retcodes for MR register rpage
+ * Used for hipz_h_register_rpage_mr at registering one page, but not last page
+ */
+int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_PAGE_REGISTERED: /* page registered */
+ return 0;
+ case H_SUCCESS: /* registration complete */
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+/* case H_QT_PARM: invalid queue type */
+ case H_PARAMETER: /*
+ * invalid logical address,
+ * or count zero or greater 512
+ */
+ case H_TABLE_FULL: /* page table full */
+ case H_HARDWARE: /* HCA not operational */
+ return -EINVAL;
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_rrpg_notlast() */
+
+/*----------------------------------------------------------------------*/
+
+/* map HIPZ rc to IB retcodes for MR query. Used for hipz_mr_query. */
+int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_SUCCESS: /* successful completion */
+ return 0;
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ return -EINVAL;
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_query_mr() */
+
+/*----------------------------------------------------------------------*/
+/*----------------------------------------------------------------------*/
+
+/*
+ * map HIPZ rc to IB retcodes for freeing MR resource
+ * Used for hipz_h_free_resource_mr
+ */
+int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_SUCCESS: /* resource freed */
+ return 0;
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ case H_R_STATE: /* invalid resource state */
+ case H_HARDWARE: /* HCA not operational */
+ return -EINVAL;
+ case H_RESOURCE: /* Resource in use */
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_free_mr() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * map HIPZ rc to IB retcodes for freeing MW resource
+ * Used for hipz_h_free_resource_mw
+ */
+int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_SUCCESS: /* resource freed */
+ return 0;
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ case H_R_STATE: /* invalid resource state */
+ case H_HARDWARE: /* HCA not operational */
+ return -EINVAL;
+ case H_RESOURCE: /* Resource in use */
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_free_mw() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * map HIPZ rc to IB retcodes for SMR registrations
+ * Used for hipz_h_register_smr.
+ */
+int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc)
+{
+ switch (hipz_rc) {
+ case H_SUCCESS: /* successful completion */
+ return 0;
+ case H_ADAPTER_PARM: /* invalid adapter handle */
+ case H_RH_PARM: /* invalid resource handle */
+ case H_MEM_PARM: /* invalid MR virtual address */
+ case H_MEM_ACCESS_PARM: /* invalid access controls */
+ case H_NOT_ENOUGH_RESOURCES: /* insufficient resources */
+ return -EINVAL;
+ case H_BUSY: /* long busy */
+ return -EBUSY;
+ default:
+ return -EINVAL;
+ }
+} /* end ehca_mrmw_map_hrc_reg_smr() */
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * MR destructor and constructor
+ * used in Reregister MR verb, sets all fields in ehca_mr_t to 0,
+ * except struct ib_mr and spinlock
+ */
+void ehca_mr_deletenew(struct ehca_mr *mr)
+{
+ mr->flags = 0;
+ mr->num_pages = 0;
+ mr->num_4k = 0;
+ mr->acl = 0;
+ mr->start = NULL;
+ mr->fmr_page_size = 0;
+ mr->fmr_max_pages = 0;
+ mr->fmr_max_maps = 0;
+ mr->fmr_map_cnt = 0;
+ memset(&mr->ipz_mr_handle, 0, sizeof(mr->ipz_mr_handle));
+ memset(&mr->galpas, 0, sizeof(mr->galpas));
+ mr->nr_of_pages = 0;
+ mr->pagearray = NULL;
+} /* end ehca_mr_deletenew() */
+
+int ehca_init_mrmw_cache(void)
+{
+ mr_cache = kmem_cache_create("ehca_cache_mr",
+ sizeof(struct ehca_mr), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!mr_cache)
+ return -ENOMEM;
+ mw_cache = kmem_cache_create("ehca_cache_mw",
+ sizeof(struct ehca_mw), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!mw_cache) {
+ kmem_cache_destroy(mr_cache);
+ mr_cache = NULL;
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void ehca_cleanup_mrmw_cache(void)
+{
+ if (mr_cache)
+ kmem_cache_destroy(mr_cache);
+ if (mw_cache)
+ kmem_cache_destroy(mw_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.h b/drivers/infiniband/hw/ehca/ehca_mrmw.h
new file mode 100644
index 00000000000..d936e40a574
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.h
@@ -0,0 +1,140 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * MR/MW declarations and inline functions
+ *
+ * Authors: Dietmar Decker <ddecker@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _EHCA_MRMW_H_
+#define _EHCA_MRMW_H_
+
+int ehca_reg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int acl,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_reg_mr_rpages(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo);
+
+int ehca_rereg_mr(struct ehca_shca *shca,
+ struct ehca_mr *e_mr,
+ u64 *iova_start,
+ u64 size,
+ int mr_access_flags,
+ struct ehca_pd *e_pd,
+ struct ehca_mr_pginfo *pginfo,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_unmap_one_fmr(struct ehca_shca *shca,
+ struct ehca_mr *e_fmr);
+
+int ehca_reg_smr(struct ehca_shca *shca,
+ struct ehca_mr *e_origmr,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_reg_internal_maxmr(struct ehca_shca *shca,
+ struct ehca_pd *e_pd,
+ struct ehca_mr **maxmr);
+
+int ehca_reg_maxmr(struct ehca_shca *shca,
+ struct ehca_mr *e_newmr,
+ u64 *iova_start,
+ int acl,
+ struct ehca_pd *e_pd,
+ u32 *lkey,
+ u32 *rkey);
+
+int ehca_dereg_internal_maxmr(struct ehca_shca *shca);
+
+int ehca_mr_chk_buf_and_calc_size(struct ib_phys_buf *phys_buf_array,
+ int num_phys_buf,
+ u64 *iova_start,
+ u64 *size);
+
+int ehca_fmr_check_page_list(struct ehca_mr *e_fmr,
+ u64 *page_list,
+ int list_len);
+
+int ehca_set_pagebuf(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u32 number,
+ u64 *kpage);
+
+int ehca_set_pagebuf_1(struct ehca_mr *e_mr,
+ struct ehca_mr_pginfo *pginfo,
+ u64 *rpage);
+
+int ehca_mr_is_maxmr(u64 size,
+ u64 *iova_start);
+
+void ehca_mrmw_map_acl(int ib_acl,
+ u32 *hipz_acl);
+
+void ehca_mrmw_set_pgsize_hipz_acl(u32 *hipz_acl);
+
+void ehca_mrmw_reverse_map_acl(const u32 *hipz_acl,
+ int *ib_acl);
+
+int ehca_mrmw_map_hrc_alloc(const u64 hipz_rc);
+
+int ehca_mrmw_map_hrc_rrpg_last(const u64 hipz_rc);
+
+int ehca_mrmw_map_hrc_rrpg_notlast(const u64 hipz_rc);
+
+int ehca_mrmw_map_hrc_query_mr(const u64 hipz_rc);
+
+int ehca_mrmw_map_hrc_free_mr(const u64 hipz_rc);
+
+int ehca_mrmw_map_hrc_free_mw(const u64 hipz_rc);
+
+int ehca_mrmw_map_hrc_reg_smr(const u64 hipz_rc);
+
+void ehca_mr_deletenew(struct ehca_mr *mr);
+
+#endif /*_EHCA_MRMW_H_*/
diff --git a/drivers/infiniband/hw/ehca/ehca_pd.c b/drivers/infiniband/hw/ehca/ehca_pd.c
new file mode 100644
index 00000000000..2c3cdc6f7b3
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_pd.c
@@ -0,0 +1,114 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * PD functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/current.h>
+
+#include "ehca_tools.h"
+#include "ehca_iverbs.h"
+
+static struct kmem_cache *pd_cache;
+
+struct ib_pd *ehca_alloc_pd(struct ib_device *device,
+ struct ib_ucontext *context, struct ib_udata *udata)
+{
+ struct ehca_pd *pd;
+
+ pd = kmem_cache_alloc(pd_cache, SLAB_KERNEL);
+ if (!pd) {
+ ehca_err(device, "device=%p context=%p out of memory",
+ device, context);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(pd, 0, sizeof(struct ehca_pd));
+ pd->ownpid = current->tgid;
+
+ /*
+ * Kernel PD: when device = -1, 0
+ * User PD: when context != -1
+ */
+ if (!context) {
+ /*
+ * Kernel PDs after init reuses always
+ * the one created in ehca_shca_reopen()
+ */
+ struct ehca_shca *shca = container_of(device, struct ehca_shca,
+ ib_device);
+ pd->fw_pd.value = shca->pd->fw_pd.value;
+ } else
+ pd->fw_pd.value = (u64)pd;
+
+ return &pd->ib_pd;
+}
+
+int ehca_dealloc_pd(struct ib_pd *pd)
+{
+ u32 cur_pid = current->tgid;
+ struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(pd->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ kmem_cache_free(pd_cache,
+ container_of(pd, struct ehca_pd, ib_pd));
+
+ return 0;
+}
+
+int ehca_init_pd_cache(void)
+{
+ pd_cache = kmem_cache_create("ehca_cache_pd",
+ sizeof(struct ehca_pd), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!pd_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_pd_cache(void)
+{
+ if (pd_cache)
+ kmem_cache_destroy(pd_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_qes.h b/drivers/infiniband/hw/ehca/ehca_qes.h
new file mode 100644
index 00000000000..8707d297ce4
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_qes.h
@@ -0,0 +1,259 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Hardware request structures
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef _EHCA_QES_H_
+#define _EHCA_QES_H_
+
+#include "ehca_tools.h"
+
+/* virtual scatter gather entry to specify remote adresses with length */
+struct ehca_vsgentry {
+ u64 vaddr;
+ u32 lkey;
+ u32 length;
+};
+
+#define GRH_FLAG_MASK EHCA_BMASK_IBM(7,7)
+#define GRH_IPVERSION_MASK EHCA_BMASK_IBM(0,3)
+#define GRH_TCLASS_MASK EHCA_BMASK_IBM(4,12)
+#define GRH_FLOWLABEL_MASK EHCA_BMASK_IBM(13,31)
+#define GRH_PAYLEN_MASK EHCA_BMASK_IBM(32,47)
+#define GRH_NEXTHEADER_MASK EHCA_BMASK_IBM(48,55)
+#define GRH_HOPLIMIT_MASK EHCA_BMASK_IBM(56,63)
+
+/*
+ * Unreliable Datagram Address Vector Format
+ * see IBTA Vol1 chapter 8.3 Global Routing Header
+ */
+struct ehca_ud_av {
+ u8 sl;
+ u8 lnh;
+ u16 dlid;
+ u8 reserved1;
+ u8 reserved2;
+ u8 reserved3;
+ u8 slid_path_bits;
+ u8 reserved4;
+ u8 ipd;
+ u8 reserved5;
+ u8 pmtu;
+ u32 reserved6;
+ u64 reserved7;
+ union {
+ struct {
+ u64 word_0; /* always set to 6 */
+ /*should be 0x1B for IB transport */
+ u64 word_1;
+ u64 word_2;
+ u64 word_3;
+ u64 word_4;
+ } grh;
+ struct {
+ u32 wd_0;
+ u32 wd_1;
+ /* DWord_1 --> SGID */
+
+ u32 sgid_wd3;
+ u32 sgid_wd2;
+
+ u32 sgid_wd1;
+ u32 sgid_wd0;
+ /* DWord_3 --> DGID */
+
+ u32 dgid_wd3;
+ u32 dgid_wd2;
+
+ u32 dgid_wd1;
+ u32 dgid_wd0;
+ } grh_l;
+ };
+};
+
+/* maximum number of sg entries allowed in a WQE */
+#define MAX_WQE_SG_ENTRIES 252
+
+#define WQE_OPTYPE_SEND 0x80
+#define WQE_OPTYPE_RDMAREAD 0x40
+#define WQE_OPTYPE_RDMAWRITE 0x20
+#define WQE_OPTYPE_CMPSWAP 0x10
+#define WQE_OPTYPE_FETCHADD 0x08
+#define WQE_OPTYPE_BIND 0x04
+
+#define WQE_WRFLAG_REQ_SIGNAL_COM 0x80
+#define WQE_WRFLAG_FENCE 0x40
+#define WQE_WRFLAG_IMM_DATA_PRESENT 0x20
+#define WQE_WRFLAG_SOLIC_EVENT 0x10
+
+#define WQEF_CACHE_HINT 0x80
+#define WQEF_CACHE_HINT_RD_WR 0x40
+#define WQEF_TIMED_WQE 0x20
+#define WQEF_PURGE 0x08
+#define WQEF_HIGH_NIBBLE 0xF0
+
+#define MW_BIND_ACCESSCTRL_R_WRITE 0x40
+#define MW_BIND_ACCESSCTRL_R_READ 0x20
+#define MW_BIND_ACCESSCTRL_R_ATOMIC 0x10
+
+struct ehca_wqe {
+ u64 work_request_id;
+ u8 optype;
+ u8 wr_flag;
+ u16 pkeyi;
+ u8 wqef;
+ u8 nr_of_data_seg;
+ u16 wqe_provided_slid;
+ u32 destination_qp_number;
+ u32 resync_psn_sqp;
+ u32 local_ee_context_qkey;
+ u32 immediate_data;
+ union {
+ struct {
+ u64 remote_virtual_adress;
+ u32 rkey;
+ u32 reserved;
+ u64 atomic_1st_op_dma_len;
+ u64 atomic_2nd_op;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
+
+ } nud;
+ struct {
+ u64 ehca_ud_av_ptr;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
+ } ud_avp;
+ struct {
+ struct ehca_ud_av ud_av;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES -
+ 2];
+ } ud_av;
+ struct {
+ u64 reserved0;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ struct ehca_vsgentry sg_list[MAX_WQE_SG_ENTRIES];
+ } all_rcv;
+
+ struct {
+ u64 reserved;
+ u32 rkey;
+ u32 old_rkey;
+ u64 reserved1;
+ u64 reserved2;
+ u64 virtual_address;
+ u32 reserved3;
+ u32 length;
+ u32 reserved4;
+ u16 reserved5;
+ u8 reserved6;
+ u8 lr_ctl;
+ u32 lkey;
+ u32 reserved7;
+ u64 reserved8;
+ u64 reserved9;
+ u64 reserved10;
+ u64 reserved11;
+ } bind;
+ struct {
+ u64 reserved12;
+ u64 reserved13;
+ u32 size;
+ u32 start;
+ } inline_data;
+ } u;
+
+};
+
+#define WC_SEND_RECEIVE EHCA_BMASK_IBM(0,0)
+#define WC_IMM_DATA EHCA_BMASK_IBM(1,1)
+#define WC_GRH_PRESENT EHCA_BMASK_IBM(2,2)
+#define WC_SE_BIT EHCA_BMASK_IBM(3,3)
+#define WC_STATUS_ERROR_BIT 0x80000000
+#define WC_STATUS_REMOTE_ERROR_FLAGS 0x0000F800
+#define WC_STATUS_PURGE_BIT 0x10
+
+struct ehca_cqe {
+ u64 work_request_id;
+ u8 optype;
+ u8 w_completion_flags;
+ u16 reserved1;
+ u32 nr_bytes_transferred;
+ u32 immediate_data;
+ u32 local_qp_number;
+ u8 freed_resource_count;
+ u8 service_level;
+ u16 wqe_count;
+ u32 qp_token;
+ u32 qkey_ee_token;
+ u32 remote_qp_number;
+ u16 dlid;
+ u16 rlid;
+ u16 reserved2;
+ u16 pkey_index;
+ u32 cqe_timestamp;
+ u32 wqe_timestamp;
+ u8 wqe_timestamp_valid;
+ u8 reserved3;
+ u8 reserved4;
+ u8 cqe_flags;
+ u32 status;
+};
+
+struct ehca_eqe {
+ u64 entry;
+};
+
+struct ehca_mrte {
+ u64 starting_va;
+ u64 length; /* length of memory region in bytes*/
+ u32 pd;
+ u8 key_instance;
+ u8 pagesize;
+ u8 mr_control;
+ u8 local_remote_access_ctrl;
+ u8 reserved[0x20 - 0x18];
+ u64 at_pointer[4];
+};
+#endif /*_EHCA_QES_H_*/
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
new file mode 100644
index 00000000000..4394123cdbd
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -0,0 +1,1507 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * QP functions
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <asm/current.h>
+
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+#include "hipz_fns.h"
+
+static struct kmem_cache *qp_cache;
+
+/*
+ * attributes not supported by query qp
+ */
+#define QP_ATTR_QUERY_NOT_SUPPORTED (IB_QP_MAX_DEST_RD_ATOMIC | \
+ IB_QP_MAX_QP_RD_ATOMIC | \
+ IB_QP_ACCESS_FLAGS | \
+ IB_QP_EN_SQD_ASYNC_NOTIFY)
+
+/*
+ * ehca (internal) qp state values
+ */
+enum ehca_qp_state {
+ EHCA_QPS_RESET = 1,
+ EHCA_QPS_INIT = 2,
+ EHCA_QPS_RTR = 3,
+ EHCA_QPS_RTS = 5,
+ EHCA_QPS_SQD = 6,
+ EHCA_QPS_SQE = 8,
+ EHCA_QPS_ERR = 128
+};
+
+/*
+ * qp state transitions as defined by IB Arch Rel 1.1 page 431
+ */
+enum ib_qp_statetrans {
+ IB_QPST_ANY2RESET,
+ IB_QPST_ANY2ERR,
+ IB_QPST_RESET2INIT,
+ IB_QPST_INIT2RTR,
+ IB_QPST_INIT2INIT,
+ IB_QPST_RTR2RTS,
+ IB_QPST_RTS2SQD,
+ IB_QPST_RTS2RTS,
+ IB_QPST_SQD2RTS,
+ IB_QPST_SQE2RTS,
+ IB_QPST_SQD2SQD,
+ IB_QPST_MAX /* nr of transitions, this must be last!!! */
+};
+
+/*
+ * ib2ehca_qp_state maps IB to ehca qp_state
+ * returns ehca qp state corresponding to given ib qp state
+ */
+static inline enum ehca_qp_state ib2ehca_qp_state(enum ib_qp_state ib_qp_state)
+{
+ switch (ib_qp_state) {
+ case IB_QPS_RESET:
+ return EHCA_QPS_RESET;
+ case IB_QPS_INIT:
+ return EHCA_QPS_INIT;
+ case IB_QPS_RTR:
+ return EHCA_QPS_RTR;
+ case IB_QPS_RTS:
+ return EHCA_QPS_RTS;
+ case IB_QPS_SQD:
+ return EHCA_QPS_SQD;
+ case IB_QPS_SQE:
+ return EHCA_QPS_SQE;
+ case IB_QPS_ERR:
+ return EHCA_QPS_ERR;
+ default:
+ ehca_gen_err("invalid ib_qp_state=%x", ib_qp_state);
+ return -EINVAL;
+ }
+}
+
+/*
+ * ehca2ib_qp_state maps ehca to IB qp_state
+ * returns ib qp state corresponding to given ehca qp state
+ */
+static inline enum ib_qp_state ehca2ib_qp_state(enum ehca_qp_state
+ ehca_qp_state)
+{
+ switch (ehca_qp_state) {
+ case EHCA_QPS_RESET:
+ return IB_QPS_RESET;
+ case EHCA_QPS_INIT:
+ return IB_QPS_INIT;
+ case EHCA_QPS_RTR:
+ return IB_QPS_RTR;
+ case EHCA_QPS_RTS:
+ return IB_QPS_RTS;
+ case EHCA_QPS_SQD:
+ return IB_QPS_SQD;
+ case EHCA_QPS_SQE:
+ return IB_QPS_SQE;
+ case EHCA_QPS_ERR:
+ return IB_QPS_ERR;
+ default:
+ ehca_gen_err("invalid ehca_qp_state=%x", ehca_qp_state);
+ return -EINVAL;
+ }
+}
+
+/*
+ * ehca_qp_type used as index for req_attr and opt_attr of
+ * struct ehca_modqp_statetrans
+ */
+enum ehca_qp_type {
+ QPT_RC = 0,
+ QPT_UC = 1,
+ QPT_UD = 2,
+ QPT_SQP = 3,
+ QPT_MAX
+};
+
+/*
+ * ib2ehcaqptype maps Ib to ehca qp_type
+ * returns ehca qp type corresponding to ib qp type
+ */
+static inline enum ehca_qp_type ib2ehcaqptype(enum ib_qp_type ibqptype)
+{
+ switch (ibqptype) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ return QPT_SQP;
+ case IB_QPT_RC:
+ return QPT_RC;
+ case IB_QPT_UC:
+ return QPT_UC;
+ case IB_QPT_UD:
+ return QPT_UD;
+ default:
+ ehca_gen_err("Invalid ibqptype=%x", ibqptype);
+ return -EINVAL;
+ }
+}
+
+static inline enum ib_qp_statetrans get_modqp_statetrans(int ib_fromstate,
+ int ib_tostate)
+{
+ int index = -EINVAL;
+ switch (ib_tostate) {
+ case IB_QPS_RESET:
+ index = IB_QPST_ANY2RESET;
+ break;
+ case IB_QPS_INIT:
+ switch (ib_fromstate) {
+ case IB_QPS_RESET:
+ index = IB_QPST_RESET2INIT;
+ break;
+ case IB_QPS_INIT:
+ index = IB_QPST_INIT2INIT;
+ break;
+ }
+ break;
+ case IB_QPS_RTR:
+ if (ib_fromstate == IB_QPS_INIT)
+ index = IB_QPST_INIT2RTR;
+ break;
+ case IB_QPS_RTS:
+ switch (ib_fromstate) {
+ case IB_QPS_RTR:
+ index = IB_QPST_RTR2RTS;
+ break;
+ case IB_QPS_RTS:
+ index = IB_QPST_RTS2RTS;
+ break;
+ case IB_QPS_SQD:
+ index = IB_QPST_SQD2RTS;
+ break;
+ case IB_QPS_SQE:
+ index = IB_QPST_SQE2RTS;
+ break;
+ }
+ break;
+ case IB_QPS_SQD:
+ if (ib_fromstate == IB_QPS_RTS)
+ index = IB_QPST_RTS2SQD;
+ break;
+ case IB_QPS_SQE:
+ break;
+ case IB_QPS_ERR:
+ index = IB_QPST_ANY2ERR;
+ break;
+ default:
+ break;
+ }
+ return index;
+}
+
+enum ehca_service_type {
+ ST_RC = 0,
+ ST_UC = 1,
+ ST_RD = 2,
+ ST_UD = 3
+};
+
+/*
+ * ibqptype2servicetype returns hcp service type corresponding to given
+ * ib qp type used by create_qp()
+ */
+static inline int ibqptype2servicetype(enum ib_qp_type ibqptype)
+{
+ switch (ibqptype) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ return ST_UD;
+ case IB_QPT_RC:
+ return ST_RC;
+ case IB_QPT_UC:
+ return ST_UC;
+ case IB_QPT_UD:
+ return ST_UD;
+ case IB_QPT_RAW_IPV6:
+ return -EINVAL;
+ case IB_QPT_RAW_ETY:
+ return -EINVAL;
+ default:
+ ehca_gen_err("Invalid ibqptype=%x", ibqptype);
+ return -EINVAL;
+ }
+}
+
+/*
+ * init_qp_queues initializes/constructs r/squeue and registers queue pages.
+ */
+static inline int init_qp_queues(struct ehca_shca *shca,
+ struct ehca_qp *my_qp,
+ int nr_sq_pages,
+ int nr_rq_pages,
+ int swqe_size,
+ int rwqe_size,
+ int nr_send_sges, int nr_receive_sges)
+{
+ int ret, cnt, ipz_rc;
+ void *vpage;
+ u64 rpage, h_ret;
+ struct ib_device *ib_dev = &shca->ib_device;
+ struct ipz_adapter_handle ipz_hca_handle = shca->ipz_hca_handle;
+
+ ipz_rc = ipz_queue_ctor(&my_qp->ipz_squeue,
+ nr_sq_pages,
+ EHCA_PAGESIZE, swqe_size, nr_send_sges);
+ if (!ipz_rc) {
+ ehca_err(ib_dev,"Cannot allocate page for squeue. ipz_rc=%x",
+ ipz_rc);
+ return -EBUSY;
+ }
+
+ ipz_rc = ipz_queue_ctor(&my_qp->ipz_rqueue,
+ nr_rq_pages,
+ EHCA_PAGESIZE, rwqe_size, nr_receive_sges);
+ if (!ipz_rc) {
+ ehca_err(ib_dev, "Cannot allocate page for rqueue. ipz_rc=%x",
+ ipz_rc);
+ ret = -EBUSY;
+ goto init_qp_queues0;
+ }
+ /* register SQ pages */
+ for (cnt = 0; cnt < nr_sq_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(&my_qp->ipz_squeue);
+ if (!vpage) {
+ ehca_err(ib_dev, "SQ ipz_qpageit_get_inc() "
+ "failed p_vpage= %p", vpage);
+ ret = -EINVAL;
+ goto init_qp_queues1;
+ }
+ rpage = virt_to_abs(vpage);
+
+ h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf, 0, 0,
+ rpage, 1,
+ my_qp->galpas.kernel);
+ if (h_ret < H_SUCCESS) {
+ ehca_err(ib_dev, "SQ hipz_qp_register_rpage()"
+ " failed rc=%lx", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ }
+
+ ipz_qeit_reset(&my_qp->ipz_squeue);
+
+ /* register RQ pages */
+ for (cnt = 0; cnt < nr_rq_pages; cnt++) {
+ vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
+ if (!vpage) {
+ ehca_err(ib_dev, "RQ ipz_qpageit_get_inc() "
+ "failed p_vpage = %p", vpage);
+ ret = -EINVAL;
+ goto init_qp_queues1;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ h_ret = hipz_h_register_rpage_qp(ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf, 0, 1,
+ rpage, 1,my_qp->galpas.kernel);
+ if (h_ret < H_SUCCESS) {
+ ehca_err(ib_dev, "RQ hipz_qp_register_rpage() failed "
+ "rc=%lx", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ if (cnt == (nr_rq_pages - 1)) { /* last page! */
+ if (h_ret != H_SUCCESS) {
+ ehca_err(ib_dev, "RQ hipz_qp_register_rpage() "
+ "h_ret= %lx ", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ vpage = ipz_qpageit_get_inc(&my_qp->ipz_rqueue);
+ if (vpage) {
+ ehca_err(ib_dev, "ipz_qpageit_get_inc() "
+ "should not succeed vpage=%p", vpage);
+ ret = -EINVAL;
+ goto init_qp_queues1;
+ }
+ } else {
+ if (h_ret != H_PAGE_REGISTERED) {
+ ehca_err(ib_dev, "RQ hipz_qp_register_rpage() "
+ "h_ret= %lx ", h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto init_qp_queues1;
+ }
+ }
+ }
+
+ ipz_qeit_reset(&my_qp->ipz_rqueue);
+
+ return 0;
+
+init_qp_queues1:
+ ipz_queue_dtor(&my_qp->ipz_rqueue);
+init_qp_queues0:
+ ipz_queue_dtor(&my_qp->ipz_squeue);
+ return ret;
+}
+
+struct ib_qp *ehca_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
+{
+ static int da_rc_msg_size[]={ 128, 256, 512, 1024, 2048, 4096 };
+ static int da_ud_sq_msg_size[]={ 128, 384, 896, 1920, 3968 };
+ struct ehca_qp *my_qp;
+ struct ehca_pd *my_pd = container_of(pd, struct ehca_pd, ib_pd);
+ struct ehca_shca *shca = container_of(pd->device, struct ehca_shca,
+ ib_device);
+ struct ib_ucontext *context = NULL;
+ u64 h_ret;
+ int max_send_sge, max_recv_sge, ret;
+
+ /* h_call's out parameters */
+ struct ehca_alloc_qp_parms parms;
+ u32 swqe_size = 0, rwqe_size = 0;
+ u8 daqp_completion, isdaqp;
+ unsigned long flags;
+
+ if (init_attr->sq_sig_type != IB_SIGNAL_REQ_WR &&
+ init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
+ ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",
+ init_attr->sq_sig_type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* save daqp completion bits */
+ daqp_completion = init_attr->qp_type & 0x60;
+ /* save daqp bit */
+ isdaqp = (init_attr->qp_type & 0x80) ? 1 : 0;
+ init_attr->qp_type = init_attr->qp_type & 0x1F;
+
+ if (init_attr->qp_type != IB_QPT_UD &&
+ init_attr->qp_type != IB_QPT_SMI &&
+ init_attr->qp_type != IB_QPT_GSI &&
+ init_attr->qp_type != IB_QPT_UC &&
+ init_attr->qp_type != IB_QPT_RC) {
+ ehca_err(pd->device, "wrong QP Type=%x", init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ }
+ if ((init_attr->qp_type != IB_QPT_RC && init_attr->qp_type != IB_QPT_UD)
+ && isdaqp) {
+ ehca_err(pd->device, "unsupported LL QP Type=%x",
+ init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ } else if (init_attr->qp_type == IB_QPT_RC && isdaqp &&
+ (init_attr->cap.max_send_wr > 255 ||
+ init_attr->cap.max_recv_wr > 255 )) {
+ ehca_err(pd->device, "Invalid Number of max_sq_wr =%x "
+ "or max_rq_wr=%x for QP Type=%x",
+ init_attr->cap.max_send_wr,
+ init_attr->cap.max_recv_wr,init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ } else if (init_attr->qp_type == IB_QPT_UD && isdaqp &&
+ init_attr->cap.max_send_wr > 255) {
+ ehca_err(pd->device,
+ "Invalid Number of max_send_wr=%x for UD QP_TYPE=%x",
+ init_attr->cap.max_send_wr, init_attr->qp_type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (pd->uobject && udata)
+ context = pd->uobject->context;
+
+ my_qp = kmem_cache_alloc(qp_cache, SLAB_KERNEL);
+ if (!my_qp) {
+ ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ memset(my_qp, 0, sizeof(struct ehca_qp));
+ memset (&parms, 0, sizeof(struct ehca_alloc_qp_parms));
+ spin_lock_init(&my_qp->spinlock_s);
+ spin_lock_init(&my_qp->spinlock_r);
+
+ my_qp->recv_cq =
+ container_of(init_attr->recv_cq, struct ehca_cq, ib_cq);
+ my_qp->send_cq =
+ container_of(init_attr->send_cq, struct ehca_cq, ib_cq);
+
+ my_qp->init_attr = *init_attr;
+
+ do {
+ if (!idr_pre_get(&ehca_qp_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ ehca_err(pd->device, "Can't reserve idr resources.");
+ goto create_qp_exit0;
+ }
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ ret = idr_get_new(&ehca_qp_idr, my_qp, &my_qp->token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ } while (ret == -EAGAIN);
+
+ if (ret) {
+ ret = -ENOMEM;
+ ehca_err(pd->device, "Can't allocate new idr entry.");
+ goto create_qp_exit0;
+ }
+
+ parms.servicetype = ibqptype2servicetype(init_attr->qp_type);
+ if (parms.servicetype < 0) {
+ ret = -EINVAL;
+ ehca_err(pd->device, "Invalid qp_type=%x", init_attr->qp_type);
+ goto create_qp_exit0;
+ }
+
+ if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR)
+ parms.sigtype = HCALL_SIGT_EVERY;
+ else
+ parms.sigtype = HCALL_SIGT_BY_WQE;
+
+ /* UD_AV CIRCUMVENTION */
+ max_send_sge = init_attr->cap.max_send_sge;
+ max_recv_sge = init_attr->cap.max_recv_sge;
+ if (IB_QPT_UD == init_attr->qp_type ||
+ IB_QPT_GSI == init_attr->qp_type ||
+ IB_QPT_SMI == init_attr->qp_type) {
+ max_send_sge += 2;
+ max_recv_sge += 2;
+ }
+
+ parms.ipz_eq_handle = shca->eq.ipz_eq_handle;
+ parms.daqp_ctrl = isdaqp | daqp_completion;
+ parms.pd = my_pd->fw_pd;
+ parms.max_recv_sge = max_recv_sge;
+ parms.max_send_sge = max_send_sge;
+
+ h_ret = hipz_h_alloc_resource_qp(shca->ipz_hca_handle, my_qp, &parms);
+
+ if (h_ret != H_SUCCESS) {
+ ehca_err(pd->device, "h_alloc_resource_qp() failed h_ret=%lx",
+ h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto create_qp_exit1;
+ }
+
+ switch (init_attr->qp_type) {
+ case IB_QPT_RC:
+ if (isdaqp == 0) {
+ swqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
+ (parms.act_nr_send_sges)]);
+ rwqe_size = offsetof(struct ehca_wqe, u.nud.sg_list[
+ (parms.act_nr_recv_sges)]);
+ } else { /* for daqp we need to use msg size, not wqe size */
+ swqe_size = da_rc_msg_size[max_send_sge];
+ rwqe_size = da_rc_msg_size[max_recv_sge];
+ parms.act_nr_send_sges = 1;
+ parms.act_nr_recv_sges = 1;
+ }
+ break;
+ case IB_QPT_UC:
+ swqe_size = offsetof(struct ehca_wqe,
+ u.nud.sg_list[parms.act_nr_send_sges]);
+ rwqe_size = offsetof(struct ehca_wqe,
+ u.nud.sg_list[parms.act_nr_recv_sges]);
+ break;
+
+ case IB_QPT_UD:
+ case IB_QPT_GSI:
+ case IB_QPT_SMI:
+ /* UD circumvention */
+ parms.act_nr_recv_sges -= 2;
+ parms.act_nr_send_sges -= 2;
+ if (isdaqp) {
+ swqe_size = da_ud_sq_msg_size[max_send_sge];
+ rwqe_size = da_rc_msg_size[max_recv_sge];
+ parms.act_nr_send_sges = 1;
+ parms.act_nr_recv_sges = 1;
+ } else {
+ swqe_size = offsetof(struct ehca_wqe,
+ u.ud_av.sg_list[parms.act_nr_send_sges]);
+ rwqe_size = offsetof(struct ehca_wqe,
+ u.ud_av.sg_list[parms.act_nr_recv_sges]);
+ }
+
+ if (IB_QPT_GSI == init_attr->qp_type ||
+ IB_QPT_SMI == init_attr->qp_type) {
+ parms.act_nr_send_wqes = init_attr->cap.max_send_wr;
+ parms.act_nr_recv_wqes = init_attr->cap.max_recv_wr;
+ parms.act_nr_send_sges = init_attr->cap.max_send_sge;
+ parms.act_nr_recv_sges = init_attr->cap.max_recv_sge;
+ my_qp->real_qp_num =
+ (init_attr->qp_type == IB_QPT_SMI) ? 0 : 1;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ /* initializes r/squeue and registers queue pages */
+ ret = init_qp_queues(shca, my_qp,
+ parms.nr_sq_pages, parms.nr_rq_pages,
+ swqe_size, rwqe_size,
+ parms.act_nr_send_sges, parms.act_nr_recv_sges);
+ if (ret) {
+ ehca_err(pd->device,
+ "Couldn't initialize r/squeue and pages ret=%x", ret);
+ goto create_qp_exit2;
+ }
+
+ my_qp->ib_qp.pd = &my_pd->ib_pd;
+ my_qp->ib_qp.device = my_pd->ib_pd.device;
+
+ my_qp->ib_qp.recv_cq = init_attr->recv_cq;
+ my_qp->ib_qp.send_cq = init_attr->send_cq;
+
+ my_qp->ib_qp.qp_num = my_qp->real_qp_num;
+ my_qp->ib_qp.qp_type = init_attr->qp_type;
+
+ my_qp->qp_type = init_attr->qp_type;
+ my_qp->ib_qp.srq = init_attr->srq;
+
+ my_qp->ib_qp.qp_context = init_attr->qp_context;
+ my_qp->ib_qp.event_handler = init_attr->event_handler;
+
+ init_attr->cap.max_inline_data = 0; /* not supported yet */
+ init_attr->cap.max_recv_sge = parms.act_nr_recv_sges;
+ init_attr->cap.max_recv_wr = parms.act_nr_recv_wqes;
+ init_attr->cap.max_send_sge = parms.act_nr_send_sges;
+ init_attr->cap.max_send_wr = parms.act_nr_send_wqes;
+
+ /* NOTE: define_apq0() not supported yet */
+ if (init_attr->qp_type == IB_QPT_GSI) {
+ h_ret = ehca_define_sqp(shca, my_qp, init_attr);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(pd->device, "ehca_define_sqp() failed rc=%lx",
+ h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto create_qp_exit3;
+ }
+ }
+ if (init_attr->send_cq) {
+ struct ehca_cq *cq = container_of(init_attr->send_cq,
+ struct ehca_cq, ib_cq);
+ ret = ehca_cq_assign_qp(cq, my_qp);
+ if (ret) {
+ ehca_err(pd->device, "Couldn't assign qp to send_cq ret=%x",
+ ret);
+ goto create_qp_exit3;
+ }
+ my_qp->send_cq = cq;
+ }
+ /* copy queues, galpa data to user space */
+ if (context && udata) {
+ struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
+ struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
+ struct ehca_create_qp_resp resp;
+ struct vm_area_struct * vma;
+ memset(&resp, 0, sizeof(resp));
+
+ resp.qp_num = my_qp->real_qp_num;
+ resp.token = my_qp->token;
+ resp.qp_type = my_qp->qp_type;
+ resp.qkey = my_qp->qkey;
+ resp.real_qp_num = my_qp->real_qp_num;
+ /* rqueue properties */
+ resp.ipz_rqueue.qe_size = ipz_rqueue->qe_size;
+ resp.ipz_rqueue.act_nr_of_sg = ipz_rqueue->act_nr_of_sg;
+ resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
+ resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
+ resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
+ ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
+ ipz_rqueue->queue_length,
+ (void**)&resp.ipz_rqueue.queue,
+ &vma);
+ if (ret) {
+ ehca_err(pd->device, "Could not mmap rqueue pages");
+ goto create_qp_exit3;
+ }
+ my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
+ /* squeue properties */
+ resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
+ resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
+ resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
+ resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
+ resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
+ ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
+ ipz_squeue->queue_length,
+ (void**)&resp.ipz_squeue.queue,
+ &vma);
+ if (ret) {
+ ehca_err(pd->device, "Could not mmap squeue pages");
+ goto create_qp_exit4;
+ }
+ my_qp->uspace_squeue = resp.ipz_squeue.queue;
+ /* fw_handle */
+ resp.galpas = my_qp->galpas;
+ ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
+ (void**)&resp.galpas.kernel.fw_handle,
+ &vma);
+ if (ret) {
+ ehca_err(pd->device, "Could not mmap fw_handle");
+ goto create_qp_exit5;
+ }
+ my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
+
+ if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
+ ehca_err(pd->device, "Copy to udata failed");
+ ret = -EINVAL;
+ goto create_qp_exit6;
+ }
+ }
+
+ return &my_qp->ib_qp;
+
+create_qp_exit6:
+ ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
+
+create_qp_exit5:
+ ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
+
+create_qp_exit4:
+ ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
+
+create_qp_exit3:
+ ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(&my_qp->ipz_squeue);
+
+create_qp_exit2:
+ hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
+
+create_qp_exit1:
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ idr_remove(&ehca_qp_idr, my_qp->token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+create_qp_exit0:
+ kmem_cache_free(qp_cache, my_qp);
+ return ERR_PTR(ret);
+}
+
+/*
+ * prepare_sqe_rts called by internal_modify_qp() at trans sqe -> rts
+ * set purge bit of bad wqe and subsequent wqes to avoid reentering sqe
+ * returns total number of bad wqes in bad_wqe_cnt
+ */
+static int prepare_sqe_rts(struct ehca_qp *my_qp, struct ehca_shca *shca,
+ int *bad_wqe_cnt)
+{
+ u64 h_ret;
+ struct ipz_queue *squeue;
+ void *bad_send_wqe_p, *bad_send_wqe_v;
+ void *squeue_start_p, *squeue_end_p;
+ void *squeue_start_v, *squeue_end_v;
+ struct ehca_wqe *wqe;
+ int qp_num = my_qp->ib_qp.qp_num;
+
+ /* get send wqe pointer */
+ h_ret = hipz_h_disable_and_get_wqe(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle, &my_qp->pf,
+ &bad_send_wqe_p, NULL, 2);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device, "hipz_h_disable_and_get_wqe() failed"
+ " ehca_qp=%p qp_num=%x h_ret=%lx",
+ my_qp, qp_num, h_ret);
+ return ehca2ib_return_code(h_ret);
+ }
+ bad_send_wqe_p = (void*)((u64)bad_send_wqe_p & (~(1L<<63)));
+ ehca_dbg(&shca->ib_device, "qp_num=%x bad_send_wqe_p=%p",
+ qp_num, bad_send_wqe_p);
+ /* convert wqe pointer to vadr */
+ bad_send_wqe_v = abs_to_virt((u64)bad_send_wqe_p);
+ if (ehca_debug_level)
+ ehca_dmp(bad_send_wqe_v, 32, "qp_num=%x bad_wqe", qp_num);
+ squeue = &my_qp->ipz_squeue;
+ squeue_start_p = (void*)virt_to_abs(ipz_qeit_calc(squeue, 0L));
+ squeue_end_p = squeue_start_p+squeue->queue_length;
+ squeue_start_v = abs_to_virt((u64)squeue_start_p);
+ squeue_end_v = abs_to_virt((u64)squeue_end_p);
+ ehca_dbg(&shca->ib_device, "qp_num=%x squeue_start_v=%p squeue_end_v=%p",
+ qp_num, squeue_start_v, squeue_end_v);
+
+ /* loop sets wqe's purge bit */
+ wqe = (struct ehca_wqe*)bad_send_wqe_v;
+ *bad_wqe_cnt = 0;
+ while (wqe->optype != 0xff && wqe->wqef != 0xff) {
+ if (ehca_debug_level)
+ ehca_dmp(wqe, 32, "qp_num=%x wqe", qp_num);
+ wqe->nr_of_data_seg = 0; /* suppress data access */
+ wqe->wqef = WQEF_PURGE; /* WQE to be purged */
+ wqe = (struct ehca_wqe*)((u8*)wqe+squeue->qe_size);
+ *bad_wqe_cnt = (*bad_wqe_cnt)+1;
+ if ((void*)wqe >= squeue_end_v) {
+ wqe = squeue_start_v;
+ }
+ }
+ /*
+ * bad wqe will be reprocessed and ignored when pol_cq() is called,
+ * i.e. nr of wqes with flush error status is one less
+ */
+ ehca_dbg(&shca->ib_device, "qp_num=%x flusherr_wqe_cnt=%x",
+ qp_num, (*bad_wqe_cnt)-1);
+ wqe->wqef = 0;
+
+ return 0;
+}
+
+/*
+ * internal_modify_qp with circumvention to handle aqp0 properly
+ * smi_reset2init indicates if this is an internal reset-to-init-call for
+ * smi. This flag must always be zero if called from ehca_modify_qp()!
+ * This internal func was intorduced to avoid recursion of ehca_modify_qp()!
+ */
+static int internal_modify_qp(struct ib_qp *ibqp,
+ struct ib_qp_attr *attr,
+ int attr_mask, int smi_reset2init)
+{
+ enum ib_qp_state qp_cur_state, qp_new_state;
+ int cnt, qp_attr_idx, ret = 0;
+ enum ib_qp_statetrans statetrans;
+ struct hcp_modify_qp_control_block *mqpcb;
+ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ struct ehca_shca *shca =
+ container_of(ibqp->pd->device, struct ehca_shca, ib_device);
+ u64 update_mask;
+ u64 h_ret;
+ int bad_wqe_cnt = 0;
+ int squeue_locked = 0;
+ unsigned long spl_flags = 0;
+
+ /* do query_qp to obtain current attr values */
+ mqpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (mqpcb == NULL) {
+ ehca_err(ibqp->device, "Could not get zeroed page for mqpcb "
+ "ehca_qp=%p qp_num=%x ", my_qp, ibqp->qp_num);
+ return -ENOMEM;
+ }
+
+ h_ret = hipz_h_query_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ mqpcb, my_qp->galpas.kernel);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(ibqp->device, "hipz_h_query_qp() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%lx",
+ my_qp, ibqp->qp_num, h_ret);
+ ret = ehca2ib_return_code(h_ret);
+ goto modify_qp_exit1;
+ }
+
+ qp_cur_state = ehca2ib_qp_state(mqpcb->qp_state);
+
+ if (qp_cur_state == -EINVAL) { /* invalid qp state */
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid current ehca_qp_state=%x "
+ "ehca_qp=%p qp_num=%x",
+ mqpcb->qp_state, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+ /*
+ * circumvention to set aqp0 initial state to init
+ * as expected by IB spec
+ */
+ if (smi_reset2init == 0 &&
+ ibqp->qp_type == IB_QPT_SMI &&
+ qp_cur_state == IB_QPS_RESET &&
+ (attr_mask & IB_QP_STATE) &&
+ attr->qp_state == IB_QPS_INIT) { /* RESET -> INIT */
+ struct ib_qp_attr smiqp_attr = {
+ .qp_state = IB_QPS_INIT,
+ .port_num = my_qp->init_attr.port_num,
+ .pkey_index = 0,
+ .qkey = 0
+ };
+ int smiqp_attr_mask = IB_QP_STATE | IB_QP_PORT |
+ IB_QP_PKEY_INDEX | IB_QP_QKEY;
+ int smirc = internal_modify_qp(
+ ibqp, &smiqp_attr, smiqp_attr_mask, 1);
+ if (smirc) {
+ ehca_err(ibqp->device, "SMI RESET -> INIT failed. "
+ "ehca_modify_qp() rc=%x", smirc);
+ ret = H_PARAMETER;
+ goto modify_qp_exit1;
+ }
+ qp_cur_state = IB_QPS_INIT;
+ ehca_dbg(ibqp->device, "SMI RESET -> INIT succeeded");
+ }
+ /* is transmitted current state equal to "real" current state */
+ if ((attr_mask & IB_QP_CUR_STATE) &&
+ qp_cur_state != attr->cur_qp_state) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device,
+ "Invalid IB_QP_CUR_STATE attr->curr_qp_state=%x <>"
+ " actual cur_qp_state=%x. ehca_qp=%p qp_num=%x",
+ attr->cur_qp_state, qp_cur_state, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ ehca_dbg(ibqp->device,"ehca_qp=%p qp_num=%x current qp_state=%x "
+ "new qp_state=%x attribute_mask=%x",
+ my_qp, ibqp->qp_num, qp_cur_state, attr->qp_state, attr_mask);
+
+ qp_new_state = attr_mask & IB_QP_STATE ? attr->qp_state : qp_cur_state;
+ if (!smi_reset2init &&
+ !ib_modify_qp_is_ok(qp_cur_state, qp_new_state, ibqp->qp_type,
+ attr_mask)) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device,
+ "Invalid qp transition new_state=%x cur_state=%x "
+ "ehca_qp=%p qp_num=%x attr_mask=%x", qp_new_state,
+ qp_cur_state, my_qp, ibqp->qp_num, attr_mask);
+ goto modify_qp_exit1;
+ }
+
+ if ((mqpcb->qp_state = ib2ehca_qp_state(qp_new_state)))
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_STATE, 1);
+ else {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid new qp state=%x "
+ "ehca_qp=%p qp_num=%x",
+ qp_new_state, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ /* retrieve state transition struct to get req and opt attrs */
+ statetrans = get_modqp_statetrans(qp_cur_state, qp_new_state);
+ if (statetrans < 0) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "<INVALID STATE CHANGE> qp_cur_state=%x "
+ "new_qp_state=%x State_xsition=%x ehca_qp=%p "
+ "qp_num=%x", qp_cur_state, qp_new_state,
+ statetrans, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ qp_attr_idx = ib2ehcaqptype(ibqp->qp_type);
+
+ if (qp_attr_idx < 0) {
+ ret = qp_attr_idx;
+ ehca_err(ibqp->device,
+ "Invalid QP type=%x ehca_qp=%p qp_num=%x",
+ ibqp->qp_type, my_qp, ibqp->qp_num);
+ goto modify_qp_exit1;
+ }
+
+ ehca_dbg(ibqp->device,
+ "ehca_qp=%p qp_num=%x <VALID STATE CHANGE> qp_state_xsit=%x",
+ my_qp, ibqp->qp_num, statetrans);
+
+ /* sqe -> rts: set purge bit of bad wqe before actual trans */
+ if ((my_qp->qp_type == IB_QPT_UD ||
+ my_qp->qp_type == IB_QPT_GSI ||
+ my_qp->qp_type == IB_QPT_SMI) &&
+ statetrans == IB_QPST_SQE2RTS) {
+ /* mark next free wqe if kernel */
+ if (my_qp->uspace_squeue == 0) {
+ struct ehca_wqe *wqe;
+ /* lock send queue */
+ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
+ squeue_locked = 1;
+ /* mark next free wqe */
+ wqe = (struct ehca_wqe*)
+ ipz_qeit_get(&my_qp->ipz_squeue);
+ wqe->optype = wqe->wqef = 0xff;
+ ehca_dbg(ibqp->device, "qp_num=%x next_free_wqe=%p",
+ ibqp->qp_num, wqe);
+ }
+ ret = prepare_sqe_rts(my_qp, shca, &bad_wqe_cnt);
+ if (ret) {
+ ehca_err(ibqp->device, "prepare_sqe_rts() failed "
+ "ehca_qp=%p qp_num=%x ret=%x",
+ my_qp, ibqp->qp_num, ret);
+ goto modify_qp_exit2;
+ }
+ }
+
+ /*
+ * enable RDMA_Atomic_Control if reset->init und reliable con
+ * this is necessary since gen2 does not provide that flag,
+ * but pHyp requires it
+ */
+ if (statetrans == IB_QPST_RESET2INIT &&
+ (ibqp->qp_type == IB_QPT_RC || ibqp->qp_type == IB_QPT_UC)) {
+ mqpcb->rdma_atomic_ctrl = 3;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RDMA_ATOMIC_CTRL, 1);
+ }
+ /* circ. pHyp requires #RDMA/Atomic Resp Res for UC INIT -> RTR */
+ if (statetrans == IB_QPST_INIT2RTR &&
+ (ibqp->qp_type == IB_QPT_UC) &&
+ !(attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)) {
+ mqpcb->rdma_nr_atomic_resp_res = 1; /* default to 1 */
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
+ }
+
+ if (attr_mask & IB_QP_PKEY_INDEX) {
+ mqpcb->prim_p_key_idx = attr->pkey_index;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_P_KEY_IDX, 1);
+ }
+ if (attr_mask & IB_QP_PORT) {
+ if (attr->port_num < 1 || attr->port_num > shca->num_ports) {
+ ret = -EINVAL;
+ ehca_err(ibqp->device, "Invalid port=%x. "
+ "ehca_qp=%p qp_num=%x num_ports=%x",
+ attr->port_num, my_qp, ibqp->qp_num,
+ shca->num_ports);
+ goto modify_qp_exit2;
+ }
+ mqpcb->prim_phys_port = attr->port_num;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PRIM_PHYS_PORT, 1);
+ }
+ if (attr_mask & IB_QP_QKEY) {
+ mqpcb->qkey = attr->qkey;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_QKEY, 1);
+ }
+ if (attr_mask & IB_QP_AV) {
+ int ah_mult = ib_rate_to_mult(attr->ah_attr.static_rate);
+ int ehca_mult = ib_rate_to_mult(shca->sport[my_qp->
+ init_attr.port_num].rate);
+
+ mqpcb->dlid = attr->ah_attr.dlid;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID, 1);
+ mqpcb->source_path_bits = attr->ah_attr.src_path_bits;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS, 1);
+ mqpcb->service_level = attr->ah_attr.sl;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL, 1);
+
+ if (ah_mult < ehca_mult)
+ mqpcb->max_static_rate = (ah_mult > 0) ?
+ ((ehca_mult - 1) / ah_mult) : 0;
+ else
+ mqpcb->max_static_rate = 0;
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE, 1);
+
+ /*
+ * only if GRH is TRUE we might consider SOURCE_GID_IDX
+ * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
+ */
+ if (attr->ah_attr.ah_flags == IB_AH_GRH) {
+ mqpcb->send_grh_flag = 1 << 31;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG, 1);
+ mqpcb->source_gid_idx = attr->ah_attr.grh.sgid_index;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX, 1);
+
+ for (cnt = 0; cnt < 16; cnt++)
+ mqpcb->dest_gid.byte[cnt] =
+ attr->ah_attr.grh.dgid.raw[cnt];
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_GID, 1);
+ mqpcb->flow_label = attr->ah_attr.grh.flow_label;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL, 1);
+ mqpcb->hop_limit = attr->ah_attr.grh.hop_limit;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT, 1);
+ mqpcb->traffic_class = attr->ah_attr.grh.traffic_class;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS, 1);
+ }
+ }
+
+ if (attr_mask & IB_QP_PATH_MTU) {
+ mqpcb->path_mtu = attr->path_mtu;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_PATH_MTU, 1);
+ }
+ if (attr_mask & IB_QP_TIMEOUT) {
+ mqpcb->timeout = attr->timeout;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_TIMEOUT, 1);
+ }
+ if (attr_mask & IB_QP_RETRY_CNT) {
+ mqpcb->retry_count = attr->retry_cnt;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RETRY_COUNT, 1);
+ }
+ if (attr_mask & IB_QP_RNR_RETRY) {
+ mqpcb->rnr_retry_count = attr->rnr_retry;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RNR_RETRY_COUNT, 1);
+ }
+ if (attr_mask & IB_QP_RQ_PSN) {
+ mqpcb->receive_psn = attr->rq_psn;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_RECEIVE_PSN, 1);
+ }
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+ mqpcb->rdma_nr_atomic_resp_res = attr->max_dest_rd_atomic < 3 ?
+ attr->max_dest_rd_atomic : 2;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_RDMA_NR_ATOMIC_RESP_RES, 1);
+ }
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ mqpcb->rdma_atomic_outst_dest_qp = attr->max_rd_atomic < 3 ?
+ attr->max_rd_atomic : 2;
+ update_mask |=
+ EHCA_BMASK_SET
+ (MQPCB_MASK_RDMA_ATOMIC_OUTST_DEST_QP, 1);
+ }
+ if (attr_mask & IB_QP_ALT_PATH) {
+ int ah_mult = ib_rate_to_mult(attr->alt_ah_attr.static_rate);
+ int ehca_mult = ib_rate_to_mult(
+ shca->sport[my_qp->init_attr.port_num].rate);
+
+ mqpcb->dlid_al = attr->alt_ah_attr.dlid;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DLID_AL, 1);
+ mqpcb->source_path_bits_al = attr->alt_ah_attr.src_path_bits;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_PATH_BITS_AL, 1);
+ mqpcb->service_level_al = attr->alt_ah_attr.sl;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SERVICE_LEVEL_AL, 1);
+
+ if (ah_mult < ehca_mult)
+ mqpcb->max_static_rate = (ah_mult > 0) ?
+ ((ehca_mult - 1) / ah_mult) : 0;
+ else
+ mqpcb->max_static_rate_al = 0;
+
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_MAX_STATIC_RATE_AL, 1);
+
+ /*
+ * only if GRH is TRUE we might consider SOURCE_GID_IDX
+ * and DEST_GID otherwise phype will return H_ATTR_PARM!!!
+ */
+ if (attr->alt_ah_attr.ah_flags == IB_AH_GRH) {
+ mqpcb->send_grh_flag_al = 1 << 31;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SEND_GRH_FLAG_AL, 1);
+ mqpcb->source_gid_idx_al =
+ attr->alt_ah_attr.grh.sgid_index;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_SOURCE_GID_IDX_AL, 1);
+
+ for (cnt = 0; cnt < 16; cnt++)
+ mqpcb->dest_gid_al.byte[cnt] =
+ attr->alt_ah_attr.grh.dgid.raw[cnt];
+
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_DEST_GID_AL, 1);
+ mqpcb->flow_label_al = attr->alt_ah_attr.grh.flow_label;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_FLOW_LABEL_AL, 1);
+ mqpcb->hop_limit_al = attr->alt_ah_attr.grh.hop_limit;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_HOP_LIMIT_AL, 1);
+ mqpcb->traffic_class_al =
+ attr->alt_ah_attr.grh.traffic_class;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_TRAFFIC_CLASS_AL, 1);
+ }
+ }
+
+ if (attr_mask & IB_QP_MIN_RNR_TIMER) {
+ mqpcb->min_rnr_nak_timer_field = attr->min_rnr_timer;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_MIN_RNR_NAK_TIMER_FIELD, 1);
+ }
+
+ if (attr_mask & IB_QP_SQ_PSN) {
+ mqpcb->send_psn = attr->sq_psn;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_SEND_PSN, 1);
+ }
+
+ if (attr_mask & IB_QP_DEST_QPN) {
+ mqpcb->dest_qp_nr = attr->dest_qp_num;
+ update_mask |= EHCA_BMASK_SET(MQPCB_MASK_DEST_QP_NR, 1);
+ }
+
+ if (attr_mask & IB_QP_PATH_MIG_STATE) {
+ mqpcb->path_migration_state = attr->path_mig_state;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_PATH_MIGRATION_STATE, 1);
+ }
+
+ if (attr_mask & IB_QP_CAP) {
+ mqpcb->max_nr_outst_send_wr = attr->cap.max_send_wr+1;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_SEND_WR, 1);
+ mqpcb->max_nr_outst_recv_wr = attr->cap.max_recv_wr+1;
+ update_mask |=
+ EHCA_BMASK_SET(MQPCB_MASK_MAX_NR_OUTST_RECV_WR, 1);
+ /* no support for max_send/recv_sge yet */
+ }
+
+ if (ehca_debug_level)
+ ehca_dmp(mqpcb, 4*70, "qp_num=%x", ibqp->qp_num);
+
+ h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb, my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ ehca_err(ibqp->device, "hipz_h_modify_qp() failed rc=%lx "
+ "ehca_qp=%p qp_num=%x",h_ret, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
+
+ if ((my_qp->qp_type == IB_QPT_UD ||
+ my_qp->qp_type == IB_QPT_GSI ||
+ my_qp->qp_type == IB_QPT_SMI) &&
+ statetrans == IB_QPST_SQE2RTS) {
+ /* doorbell to reprocessing wqes */
+ iosync(); /* serialize GAL register access */
+ hipz_update_sqa(my_qp, bad_wqe_cnt-1);
+ ehca_gen_dbg("doorbell for %x wqes", bad_wqe_cnt);
+ }
+
+ if (statetrans == IB_QPST_RESET2INIT ||
+ statetrans == IB_QPST_INIT2INIT) {
+ mqpcb->qp_enable = 1;
+ mqpcb->qp_state = EHCA_QPS_INIT;
+ update_mask = 0;
+ update_mask = EHCA_BMASK_SET(MQPCB_MASK_QP_ENABLE, 1);
+
+ h_ret = hipz_h_modify_qp(shca->ipz_hca_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ update_mask,
+ mqpcb,
+ my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ ehca_err(ibqp->device, "ENABLE in context of "
+ "RESET_2_INIT failed! Maybe you didn't get "
+ "a LID h_ret=%lx ehca_qp=%p qp_num=%x",
+ h_ret, my_qp, ibqp->qp_num);
+ goto modify_qp_exit2;
+ }
+ }
+
+ if (statetrans == IB_QPST_ANY2RESET) {
+ ipz_qeit_reset(&my_qp->ipz_rqueue);
+ ipz_qeit_reset(&my_qp->ipz_squeue);
+ }
+
+ if (attr_mask & IB_QP_QKEY)
+ my_qp->qkey = attr->qkey;
+
+modify_qp_exit2:
+ if (squeue_locked) { /* this means: sqe -> rts */
+ spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
+ my_qp->sqerr_purgeflag = 1;
+ }
+
+modify_qp_exit1:
+ kfree(mqpcb);
+
+ return ret;
+}
+
+int ehca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata)
+{
+ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
+ ib_pd);
+ u32 cur_pid = current->tgid;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(ibqp->pd->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ return internal_modify_qp(ibqp, attr, attr_mask, 0);
+}
+
+int ehca_query_qp(struct ib_qp *qp,
+ struct ib_qp_attr *qp_attr,
+ int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr)
+{
+ struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
+ struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
+ ib_pd);
+ struct ehca_shca *shca = container_of(qp->device, struct ehca_shca,
+ ib_device);
+ struct ipz_adapter_handle adapter_handle = shca->ipz_hca_handle;
+ struct hcp_modify_qp_control_block *qpcb;
+ u32 cur_pid = current->tgid;
+ int cnt, ret = 0;
+ u64 h_ret;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(qp->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ if (qp_attr_mask & QP_ATTR_QUERY_NOT_SUPPORTED) {
+ ehca_err(qp->device,"Invalid attribute mask "
+ "ehca_qp=%p qp_num=%x qp_attr_mask=%x ",
+ my_qp, qp->qp_num, qp_attr_mask);
+ return -EINVAL;
+ }
+
+ qpcb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL );
+ if (!qpcb) {
+ ehca_err(qp->device,"Out of memory for qpcb "
+ "ehca_qp=%p qp_num=%x", my_qp, qp->qp_num);
+ return -ENOMEM;
+ }
+
+ h_ret = hipz_h_query_qp(adapter_handle,
+ my_qp->ipz_qp_handle,
+ &my_qp->pf,
+ qpcb, my_qp->galpas.kernel);
+
+ if (h_ret != H_SUCCESS) {
+ ret = ehca2ib_return_code(h_ret);
+ ehca_err(qp->device,"hipz_h_query_qp() failed "
+ "ehca_qp=%p qp_num=%x h_ret=%lx",
+ my_qp, qp->qp_num, h_ret);
+ goto query_qp_exit1;
+ }
+
+ qp_attr->cur_qp_state = ehca2ib_qp_state(qpcb->qp_state);
+ qp_attr->qp_state = qp_attr->cur_qp_state;
+
+ if (qp_attr->cur_qp_state == -EINVAL) {
+ ret = -EINVAL;
+ ehca_err(qp->device,"Got invalid ehca_qp_state=%x "
+ "ehca_qp=%p qp_num=%x",
+ qpcb->qp_state, my_qp, qp->qp_num);
+ goto query_qp_exit1;
+ }
+
+ if (qp_attr->qp_state == IB_QPS_SQD)
+ qp_attr->sq_draining = 1;
+
+ qp_attr->qkey = qpcb->qkey;
+ qp_attr->path_mtu = qpcb->path_mtu;
+ qp_attr->path_mig_state = qpcb->path_migration_state;
+ qp_attr->rq_psn = qpcb->receive_psn;
+ qp_attr->sq_psn = qpcb->send_psn;
+ qp_attr->min_rnr_timer = qpcb->min_rnr_nak_timer_field;
+ qp_attr->cap.max_send_wr = qpcb->max_nr_outst_send_wr-1;
+ qp_attr->cap.max_recv_wr = qpcb->max_nr_outst_recv_wr-1;
+ /* UD_AV CIRCUMVENTION */
+ if (my_qp->qp_type == IB_QPT_UD) {
+ qp_attr->cap.max_send_sge =
+ qpcb->actual_nr_sges_in_sq_wqe - 2;
+ qp_attr->cap.max_recv_sge =
+ qpcb->actual_nr_sges_in_rq_wqe - 2;
+ } else {
+ qp_attr->cap.max_send_sge =
+ qpcb->actual_nr_sges_in_sq_wqe;
+ qp_attr->cap.max_recv_sge =
+ qpcb->actual_nr_sges_in_rq_wqe;
+ }
+
+ qp_attr->cap.max_inline_data = my_qp->sq_max_inline_data_size;
+ qp_attr->dest_qp_num = qpcb->dest_qp_nr;
+
+ qp_attr->pkey_index =
+ EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->prim_p_key_idx);
+
+ qp_attr->port_num =
+ EHCA_BMASK_GET(MQPCB_PRIM_PHYS_PORT, qpcb->prim_phys_port);
+
+ qp_attr->timeout = qpcb->timeout;
+ qp_attr->retry_cnt = qpcb->retry_count;
+ qp_attr->rnr_retry = qpcb->rnr_retry_count;
+
+ qp_attr->alt_pkey_index =
+ EHCA_BMASK_GET(MQPCB_PRIM_P_KEY_IDX, qpcb->alt_p_key_idx);
+
+ qp_attr->alt_port_num = qpcb->alt_phys_port;
+ qp_attr->alt_timeout = qpcb->timeout_al;
+
+ /* primary av */
+ qp_attr->ah_attr.sl = qpcb->service_level;
+
+ if (qpcb->send_grh_flag) {
+ qp_attr->ah_attr.ah_flags = IB_AH_GRH;
+ }
+
+ qp_attr->ah_attr.static_rate = qpcb->max_static_rate;
+ qp_attr->ah_attr.dlid = qpcb->dlid;
+ qp_attr->ah_attr.src_path_bits = qpcb->source_path_bits;
+ qp_attr->ah_attr.port_num = qp_attr->port_num;
+
+ /* primary GRH */
+ qp_attr->ah_attr.grh.traffic_class = qpcb->traffic_class;
+ qp_attr->ah_attr.grh.hop_limit = qpcb->hop_limit;
+ qp_attr->ah_attr.grh.sgid_index = qpcb->source_gid_idx;
+ qp_attr->ah_attr.grh.flow_label = qpcb->flow_label;
+
+ for (cnt = 0; cnt < 16; cnt++)
+ qp_attr->ah_attr.grh.dgid.raw[cnt] =
+ qpcb->dest_gid.byte[cnt];
+
+ /* alternate AV */
+ qp_attr->alt_ah_attr.sl = qpcb->service_level_al;
+ if (qpcb->send_grh_flag_al) {
+ qp_attr->alt_ah_attr.ah_flags = IB_AH_GRH;
+ }
+
+ qp_attr->alt_ah_attr.static_rate = qpcb->max_static_rate_al;
+ qp_attr->alt_ah_attr.dlid = qpcb->dlid_al;
+ qp_attr->alt_ah_attr.src_path_bits = qpcb->source_path_bits_al;
+
+ /* alternate GRH */
+ qp_attr->alt_ah_attr.grh.traffic_class = qpcb->traffic_class_al;
+ qp_attr->alt_ah_attr.grh.hop_limit = qpcb->hop_limit_al;
+ qp_attr->alt_ah_attr.grh.sgid_index = qpcb->source_gid_idx_al;
+ qp_attr->alt_ah_attr.grh.flow_label = qpcb->flow_label_al;
+
+ for (cnt = 0; cnt < 16; cnt++)
+ qp_attr->alt_ah_attr.grh.dgid.raw[cnt] =
+ qpcb->dest_gid_al.byte[cnt];
+
+ /* return init attributes given in ehca_create_qp */
+ if (qp_init_attr)
+ *qp_init_attr = my_qp->init_attr;
+
+ if (ehca_debug_level)
+ ehca_dmp(qpcb, 4*70, "qp_num=%x", qp->qp_num);
+
+query_qp_exit1:
+ kfree(qpcb);
+
+ return ret;
+}
+
+int ehca_destroy_qp(struct ib_qp *ibqp)
+{
+ struct ehca_qp *my_qp = container_of(ibqp, struct ehca_qp, ib_qp);
+ struct ehca_shca *shca = container_of(ibqp->device, struct ehca_shca,
+ ib_device);
+ struct ehca_pd *my_pd = container_of(my_qp->ib_qp.pd, struct ehca_pd,
+ ib_pd);
+ u32 cur_pid = current->tgid;
+ u32 qp_num = ibqp->qp_num;
+ int ret;
+ u64 h_ret;
+ u8 port_num;
+ enum ib_qp_type qp_type;
+ unsigned long flags;
+
+ if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
+ my_pd->ownpid != cur_pid) {
+ ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+ cur_pid, my_pd->ownpid);
+ return -EINVAL;
+ }
+
+ if (my_qp->send_cq) {
+ ret = ehca_cq_unassign_qp(my_qp->send_cq,
+ my_qp->real_qp_num);
+ if (ret) {
+ ehca_err(ibqp->device, "Couldn't unassign qp from "
+ "send_cq ret=%x qp_num=%x cq_num=%x", ret,
+ my_qp->ib_qp.qp_num, my_qp->send_cq->cq_number);
+ return ret;
+ }
+ }
+
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ idr_remove(&ehca_qp_idr, my_qp->token);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ /* un-mmap if vma alloc */
+ if (my_qp->uspace_rqueue) {
+ ret = ehca_munmap(my_qp->uspace_rqueue,
+ my_qp->ipz_rqueue.queue_length);
+ if (ret)
+ ehca_err(ibqp->device, "Could not munmap rqueue "
+ "qp_num=%x", qp_num);
+ ret = ehca_munmap(my_qp->uspace_squeue,
+ my_qp->ipz_squeue.queue_length);
+ if (ret)
+ ehca_err(ibqp->device, "Could not munmap squeue "
+ "qp_num=%x", qp_num);
+ ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
+ if (ret)
+ ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
+ qp_num);
+ }
+
+ h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
+ if (h_ret != H_SUCCESS) {
+ ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
+ "ehca_qp=%p qp_num=%x", h_ret, my_qp, qp_num);
+ return ehca2ib_return_code(h_ret);
+ }
+
+ port_num = my_qp->init_attr.port_num;
+ qp_type = my_qp->init_attr.qp_type;
+
+ /* no support for IB_QPT_SMI yet */
+ if (qp_type == IB_QPT_GSI) {
+ struct ib_event event;
+ ehca_info(ibqp->device, "device %s: port %x is inactive.",
+ shca->ib_device.name, port_num);
+ event.device = &shca->ib_device;
+ event.event = IB_EVENT_PORT_ERR;
+ event.element.port_num = port_num;
+ shca->sport[port_num - 1].port_state = IB_PORT_DOWN;
+ ib_dispatch_event(&event);
+ }
+
+ ipz_queue_dtor(&my_qp->ipz_rqueue);
+ ipz_queue_dtor(&my_qp->ipz_squeue);
+ kmem_cache_free(qp_cache, my_qp);
+ return 0;
+}
+
+int ehca_init_qp_cache(void)
+{
+ qp_cache = kmem_cache_create("ehca_cache_qp",
+ sizeof(struct ehca_qp), 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!qp_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void ehca_cleanup_qp_cache(void)
+{
+ if (qp_cache)
+ kmem_cache_destroy(qp_cache);
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_reqs.c b/drivers/infiniband/hw/ehca/ehca_reqs.c
new file mode 100644
index 00000000000..b46bda1bf85
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_reqs.c
@@ -0,0 +1,653 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * post_send/recv, poll_cq, req_notify
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <asm-powerpc/system.h>
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+#include "hipz_fns.h"
+
+static inline int ehca_write_rwqe(struct ipz_queue *ipz_rqueue,
+ struct ehca_wqe *wqe_p,
+ struct ib_recv_wr *recv_wr)
+{
+ u8 cnt_ds;
+ if (unlikely((recv_wr->num_sge < 0) ||
+ (recv_wr->num_sge > ipz_rqueue->act_nr_of_sg))) {
+ ehca_gen_err("Invalid number of WQE SGE. "
+ "num_sqe=%x max_nr_of_sg=%x",
+ recv_wr->num_sge, ipz_rqueue->act_nr_of_sg);
+ return -EINVAL; /* invalid SG list length */
+ }
+
+ /* clear wqe header until sglist */
+ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
+
+ wqe_p->work_request_id = recv_wr->wr_id;
+ wqe_p->nr_of_data_seg = recv_wr->num_sge;
+
+ for (cnt_ds = 0; cnt_ds < recv_wr->num_sge; cnt_ds++) {
+ wqe_p->u.all_rcv.sg_list[cnt_ds].vaddr =
+ recv_wr->sg_list[cnt_ds].addr;
+ wqe_p->u.all_rcv.sg_list[cnt_ds].lkey =
+ recv_wr->sg_list[cnt_ds].lkey;
+ wqe_p->u.all_rcv.sg_list[cnt_ds].length =
+ recv_wr->sg_list[cnt_ds].length;
+ }
+
+ if (ehca_debug_level) {
+ ehca_gen_dbg("RECEIVE WQE written into ipz_rqueue=%p", ipz_rqueue);
+ ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "recv wqe");
+ }
+
+ return 0;
+}
+
+#if defined(DEBUG_GSI_SEND_WR)
+
+/* need ib_mad struct */
+#include <rdma/ib_mad.h>
+
+static void trace_send_wr_ud(const struct ib_send_wr *send_wr)
+{
+ int idx;
+ int j;
+ while (send_wr) {
+ struct ib_mad_hdr *mad_hdr = send_wr->wr.ud.mad_hdr;
+ struct ib_sge *sge = send_wr->sg_list;
+ ehca_gen_dbg("send_wr#%x wr_id=%lx num_sge=%x "
+ "send_flags=%x opcode=%x",idx, send_wr->wr_id,
+ send_wr->num_sge, send_wr->send_flags,
+ send_wr->opcode);
+ if (mad_hdr) {
+ ehca_gen_dbg("send_wr#%x mad_hdr base_version=%x "
+ "mgmt_class=%x class_version=%x method=%x "
+ "status=%x class_specific=%x tid=%lx "
+ "attr_id=%x resv=%x attr_mod=%x",
+ idx, mad_hdr->base_version,
+ mad_hdr->mgmt_class,
+ mad_hdr->class_version, mad_hdr->method,
+ mad_hdr->status, mad_hdr->class_specific,
+ mad_hdr->tid, mad_hdr->attr_id,
+ mad_hdr->resv,
+ mad_hdr->attr_mod);
+ }
+ for (j = 0; j < send_wr->num_sge; j++) {
+ u8 *data = (u8 *) abs_to_virt(sge->addr);
+ ehca_gen_dbg("send_wr#%x sge#%x addr=%p length=%x "
+ "lkey=%x",
+ idx, j, data, sge->length, sge->lkey);
+ /* assume length is n*16 */
+ ehca_dmp(data, sge->length, "send_wr#%x sge#%x",
+ idx, j);
+ sge++;
+ } /* eof for j */
+ idx++;
+ send_wr = send_wr->next;
+ } /* eof while send_wr */
+}
+
+#endif /* DEBUG_GSI_SEND_WR */
+
+static inline int ehca_write_swqe(struct ehca_qp *qp,
+ struct ehca_wqe *wqe_p,
+ const struct ib_send_wr *send_wr)
+{
+ u32 idx;
+ u64 dma_length;
+ struct ehca_av *my_av;
+ u32 remote_qkey = send_wr->wr.ud.remote_qkey;
+
+ if (unlikely((send_wr->num_sge < 0) ||
+ (send_wr->num_sge > qp->ipz_squeue.act_nr_of_sg))) {
+ ehca_gen_err("Invalid number of WQE SGE. "
+ "num_sqe=%x max_nr_of_sg=%x",
+ send_wr->num_sge, qp->ipz_squeue.act_nr_of_sg);
+ return -EINVAL; /* invalid SG list length */
+ }
+
+ /* clear wqe header until sglist */
+ memset(wqe_p, 0, offsetof(struct ehca_wqe, u.ud_av.sg_list));
+
+ wqe_p->work_request_id = send_wr->wr_id;
+
+ switch (send_wr->opcode) {
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_IMM:
+ wqe_p->optype = WQE_OPTYPE_SEND;
+ break;
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ wqe_p->optype = WQE_OPTYPE_RDMAWRITE;
+ break;
+ case IB_WR_RDMA_READ:
+ wqe_p->optype = WQE_OPTYPE_RDMAREAD;
+ break;
+ default:
+ ehca_gen_err("Invalid opcode=%x", send_wr->opcode);
+ return -EINVAL; /* invalid opcode */
+ }
+
+ wqe_p->wqef = (send_wr->opcode) & WQEF_HIGH_NIBBLE;
+
+ wqe_p->wr_flag = 0;
+
+ if (send_wr->send_flags & IB_SEND_SIGNALED)
+ wqe_p->wr_flag |= WQE_WRFLAG_REQ_SIGNAL_COM;
+
+ if (send_wr->opcode == IB_WR_SEND_WITH_IMM ||
+ send_wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) {
+ /* this might not work as long as HW does not support it */
+ wqe_p->immediate_data = be32_to_cpu(send_wr->imm_data);
+ wqe_p->wr_flag |= WQE_WRFLAG_IMM_DATA_PRESENT;
+ }
+
+ wqe_p->nr_of_data_seg = send_wr->num_sge;
+
+ switch (qp->qp_type) {
+ case IB_QPT_SMI:
+ case IB_QPT_GSI:
+ /* no break is intential here */
+ case IB_QPT_UD:
+ /* IB 1.2 spec C10-15 compliance */
+ if (send_wr->wr.ud.remote_qkey & 0x80000000)
+ remote_qkey = qp->qkey;
+
+ wqe_p->destination_qp_number = send_wr->wr.ud.remote_qpn << 8;
+ wqe_p->local_ee_context_qkey = remote_qkey;
+ if (!send_wr->wr.ud.ah) {
+ ehca_gen_err("wr.ud.ah is NULL. qp=%p", qp);
+ return -EINVAL;
+ }
+ my_av = container_of(send_wr->wr.ud.ah, struct ehca_av, ib_ah);
+ wqe_p->u.ud_av.ud_av = my_av->av;
+
+ /*
+ * omitted check of IB_SEND_INLINE
+ * since HW does not support it
+ */
+ for (idx = 0; idx < send_wr->num_sge; idx++) {
+ wqe_p->u.ud_av.sg_list[idx].vaddr =
+ send_wr->sg_list[idx].addr;
+ wqe_p->u.ud_av.sg_list[idx].lkey =
+ send_wr->sg_list[idx].lkey;
+ wqe_p->u.ud_av.sg_list[idx].length =
+ send_wr->sg_list[idx].length;
+ } /* eof for idx */
+ if (qp->qp_type == IB_QPT_SMI ||
+ qp->qp_type == IB_QPT_GSI)
+ wqe_p->u.ud_av.ud_av.pmtu = 1;
+ if (qp->qp_type == IB_QPT_GSI) {
+ wqe_p->pkeyi = send_wr->wr.ud.pkey_index;
+#ifdef DEBUG_GSI_SEND_WR
+ trace_send_wr_ud(send_wr);
+#endif /* DEBUG_GSI_SEND_WR */
+ }
+ break;
+
+ case IB_QPT_UC:
+ if (send_wr->send_flags & IB_SEND_FENCE)
+ wqe_p->wr_flag |= WQE_WRFLAG_FENCE;
+ /* no break is intentional here */
+ case IB_QPT_RC:
+ /* TODO: atomic not implemented */
+ wqe_p->u.nud.remote_virtual_adress =
+ send_wr->wr.rdma.remote_addr;
+ wqe_p->u.nud.rkey = send_wr->wr.rdma.rkey;
+
+ /*
+ * omitted checking of IB_SEND_INLINE
+ * since HW does not support it
+ */
+ dma_length = 0;
+ for (idx = 0; idx < send_wr->num_sge; idx++) {
+ wqe_p->u.nud.sg_list[idx].vaddr =
+ send_wr->sg_list[idx].addr;
+ wqe_p->u.nud.sg_list[idx].lkey =
+ send_wr->sg_list[idx].lkey;
+ wqe_p->u.nud.sg_list[idx].length =
+ send_wr->sg_list[idx].length;
+ dma_length += send_wr->sg_list[idx].length;
+ } /* eof idx */
+ wqe_p->u.nud.atomic_1st_op_dma_len = dma_length;
+
+ break;
+
+ default:
+ ehca_gen_err("Invalid qptype=%x", qp->qp_type);
+ return -EINVAL;
+ }
+
+ if (ehca_debug_level) {
+ ehca_gen_dbg("SEND WQE written into queue qp=%p ", qp);
+ ehca_dmp( wqe_p, 16*(6 + wqe_p->nr_of_data_seg), "send wqe");
+ }
+ return 0;
+}
+
+/* map_ib_wc_status converts raw cqe_status to ib_wc_status */
+static inline void map_ib_wc_status(u32 cqe_status,
+ enum ib_wc_status *wc_status)
+{
+ if (unlikely(cqe_status & WC_STATUS_ERROR_BIT)) {
+ switch (cqe_status & 0x3F) {
+ case 0x01:
+ case 0x21:
+ *wc_status = IB_WC_LOC_LEN_ERR;
+ break;
+ case 0x02:
+ case 0x22:
+ *wc_status = IB_WC_LOC_QP_OP_ERR;
+ break;
+ case 0x03:
+ case 0x23:
+ *wc_status = IB_WC_LOC_EEC_OP_ERR;
+ break;
+ case 0x04:
+ case 0x24:
+ *wc_status = IB_WC_LOC_PROT_ERR;
+ break;
+ case 0x05:
+ case 0x25:
+ *wc_status = IB_WC_WR_FLUSH_ERR;
+ break;
+ case 0x06:
+ *wc_status = IB_WC_MW_BIND_ERR;
+ break;
+ case 0x07: /* remote error - look into bits 20:24 */
+ switch ((cqe_status
+ & WC_STATUS_REMOTE_ERROR_FLAGS) >> 11) {
+ case 0x0:
+ /*
+ * PSN Sequence Error!
+ * couldn't find a matching status!
+ */
+ *wc_status = IB_WC_GENERAL_ERR;
+ break;
+ case 0x1:
+ *wc_status = IB_WC_REM_INV_REQ_ERR;
+ break;
+ case 0x2:
+ *wc_status = IB_WC_REM_ACCESS_ERR;
+ break;
+ case 0x3:
+ *wc_status = IB_WC_REM_OP_ERR;
+ break;
+ case 0x4:
+ *wc_status = IB_WC_REM_INV_RD_REQ_ERR;
+ break;
+ }
+ break;
+ case 0x08:
+ *wc_status = IB_WC_RETRY_EXC_ERR;
+ break;
+ case 0x09:
+ *wc_status = IB_WC_RNR_RETRY_EXC_ERR;
+ break;
+ case 0x0A:
+ case 0x2D:
+ *wc_status = IB_WC_REM_ABORT_ERR;
+ break;
+ case 0x0B:
+ case 0x2E:
+ *wc_status = IB_WC_INV_EECN_ERR;
+ break;
+ case 0x0C:
+ case 0x2F:
+ *wc_status = IB_WC_INV_EEC_STATE_ERR;
+ break;
+ case 0x0D:
+ *wc_status = IB_WC_BAD_RESP_ERR;
+ break;
+ case 0x10:
+ /* WQE purged */
+ *wc_status = IB_WC_WR_FLUSH_ERR;
+ break;
+ default:
+ *wc_status = IB_WC_FATAL_ERR;
+
+ }
+ } else
+ *wc_status = IB_WC_SUCCESS;
+}
+
+int ehca_post_send(struct ib_qp *qp,
+ struct ib_send_wr *send_wr,
+ struct ib_send_wr **bad_send_wr)
+{
+ struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
+ struct ib_send_wr *cur_send_wr;
+ struct ehca_wqe *wqe_p;
+ int wqe_cnt = 0;
+ int ret = 0;
+ unsigned long spl_flags;
+
+ /* LOCK the QUEUE */
+ spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
+
+ /* loop processes list of send reqs */
+ for (cur_send_wr = send_wr; cur_send_wr != NULL;
+ cur_send_wr = cur_send_wr->next) {
+ u64 start_offset = my_qp->ipz_squeue.current_q_offset;
+ /* get pointer next to free WQE */
+ wqe_p = ipz_qeit_get_inc(&my_qp->ipz_squeue);
+ if (unlikely(!wqe_p)) {
+ /* too many posted work requests: queue overflow */
+ if (bad_send_wr)
+ *bad_send_wr = cur_send_wr;
+ if (wqe_cnt == 0) {
+ ret = -ENOMEM;
+ ehca_err(qp->device, "Too many posted WQEs "
+ "qp_num=%x", qp->qp_num);
+ }
+ goto post_send_exit0;
+ }
+ /* write a SEND WQE into the QUEUE */
+ ret = ehca_write_swqe(my_qp, wqe_p, cur_send_wr);
+ /*
+ * if something failed,
+ * reset the free entry pointer to the start value
+ */
+ if (unlikely(ret)) {
+ my_qp->ipz_squeue.current_q_offset = start_offset;
+ *bad_send_wr = cur_send_wr;
+ if (wqe_cnt == 0) {
+ ret = -EINVAL;
+ ehca_err(qp->device, "Could not write WQE "
+ "qp_num=%x", qp->qp_num);
+ }
+ goto post_send_exit0;
+ }
+ wqe_cnt++;
+ ehca_dbg(qp->device, "ehca_qp=%p qp_num=%x wqe_cnt=%d",
+ my_qp, qp->qp_num, wqe_cnt);
+ } /* eof for cur_send_wr */
+
+post_send_exit0:
+ /* UNLOCK the QUEUE */
+ spin_unlock_irqrestore(&my_qp->spinlock_s, spl_flags);
+ iosync(); /* serialize GAL register access */
+ hipz_update_sqa(my_qp, wqe_cnt);
+ return ret;
+}
+
+int ehca_post_recv(struct ib_qp *qp,
+ struct ib_recv_wr *recv_wr,
+ struct ib_recv_wr **bad_recv_wr)
+{
+ struct ehca_qp *my_qp = container_of(qp, struct ehca_qp, ib_qp);
+ struct ib_recv_wr *cur_recv_wr;
+ struct ehca_wqe *wqe_p;
+ int wqe_cnt = 0;
+ int ret = 0;
+ unsigned long spl_flags;
+
+ /* LOCK the QUEUE */
+ spin_lock_irqsave(&my_qp->spinlock_r, spl_flags);
+
+ /* loop processes list of send reqs */
+ for (cur_recv_wr = recv_wr; cur_recv_wr != NULL;
+ cur_recv_wr = cur_recv_wr->next) {
+ u64 start_offset = my_qp->ipz_rqueue.current_q_offset;
+ /* get pointer next to free WQE */
+ wqe_p = ipz_qeit_get_inc(&my_qp->ipz_rqueue);
+ if (unlikely(!wqe_p)) {
+ /* too many posted work requests: queue overflow */
+ if (bad_recv_wr)
+ *bad_recv_wr = cur_recv_wr;
+ if (wqe_cnt == 0) {
+ ret = -ENOMEM;
+ ehca_err(qp->device, "Too many posted WQEs "
+ "qp_num=%x", qp->qp_num);
+ }
+ goto post_recv_exit0;
+ }
+ /* write a RECV WQE into the QUEUE */
+ ret = ehca_write_rwqe(&my_qp->ipz_rqueue, wqe_p, cur_recv_wr);
+ /*
+ * if something failed,
+ * reset the free entry pointer to the start value
+ */
+ if (unlikely(ret)) {
+ my_qp->ipz_rqueue.current_q_offset = start_offset;
+ *bad_recv_wr = cur_recv_wr;
+ if (wqe_cnt == 0) {
+ ret = -EINVAL;
+ ehca_err(qp->device, "Could not write WQE "
+ "qp_num=%x", qp->qp_num);
+ }
+ goto post_recv_exit0;
+ }
+ wqe_cnt++;
+ ehca_gen_dbg("ehca_qp=%p qp_num=%x wqe_cnt=%d",
+ my_qp, qp->qp_num, wqe_cnt);
+ } /* eof for cur_recv_wr */
+
+post_recv_exit0:
+ spin_unlock_irqrestore(&my_qp->spinlock_r, spl_flags);
+ iosync(); /* serialize GAL register access */
+ hipz_update_rqa(my_qp, wqe_cnt);
+ return ret;
+}
+
+/*
+ * ib_wc_opcode table converts ehca wc opcode to ib
+ * Since we use zero to indicate invalid opcode, the actual ib opcode must
+ * be decremented!!!
+ */
+static const u8 ib_wc_opcode[255] = {
+ [0x01] = IB_WC_RECV+1,
+ [0x02] = IB_WC_RECV_RDMA_WITH_IMM+1,
+ [0x04] = IB_WC_BIND_MW+1,
+ [0x08] = IB_WC_FETCH_ADD+1,
+ [0x10] = IB_WC_COMP_SWAP+1,
+ [0x20] = IB_WC_RDMA_WRITE+1,
+ [0x40] = IB_WC_RDMA_READ+1,
+ [0x80] = IB_WC_SEND+1
+};
+
+/* internal function to poll one entry of cq */
+static inline int ehca_poll_cq_one(struct ib_cq *cq, struct ib_wc *wc)
+{
+ int ret = 0;
+ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ struct ehca_cqe *cqe;
+ int cqe_count = 0;
+
+poll_cq_one_read_cqe:
+ cqe = (struct ehca_cqe *)
+ ipz_qeit_get_inc_valid(&my_cq->ipz_queue);
+ if (!cqe) {
+ ret = -EAGAIN;
+ ehca_dbg(cq->device, "Completion queue is empty ehca_cq=%p "
+ "cq_num=%x ret=%x", my_cq, my_cq->cq_number, ret);
+ goto poll_cq_one_exit0;
+ }
+
+ /* prevents loads being reordered across this point */
+ rmb();
+
+ cqe_count++;
+ if (unlikely(cqe->status & WC_STATUS_PURGE_BIT)) {
+ struct ehca_qp *qp=ehca_cq_get_qp(my_cq, cqe->local_qp_number);
+ int purgeflag;
+ unsigned long spl_flags;
+ if (!qp) {
+ ehca_err(cq->device, "cq_num=%x qp_num=%x "
+ "could not find qp -> ignore cqe",
+ my_cq->cq_number, cqe->local_qp_number);
+ ehca_dmp(cqe, 64, "cq_num=%x qp_num=%x",
+ my_cq->cq_number, cqe->local_qp_number);
+ /* ignore this purged cqe */
+ goto poll_cq_one_read_cqe;
+ }
+ spin_lock_irqsave(&qp->spinlock_s, spl_flags);
+ purgeflag = qp->sqerr_purgeflag;
+ spin_unlock_irqrestore(&qp->spinlock_s, spl_flags);
+
+ if (purgeflag) {
+ ehca_dbg(cq->device, "Got CQE with purged bit qp_num=%x "
+ "src_qp=%x",
+ cqe->local_qp_number, cqe->remote_qp_number);
+ if (ehca_debug_level)
+ ehca_dmp(cqe, 64, "qp_num=%x src_qp=%x",
+ cqe->local_qp_number,
+ cqe->remote_qp_number);
+ /*
+ * ignore this to avoid double cqes of bad wqe
+ * that caused sqe and turn off purge flag
+ */
+ qp->sqerr_purgeflag = 0;
+ goto poll_cq_one_read_cqe;
+ }
+ }
+
+ /* tracing cqe */
+ if (ehca_debug_level) {
+ ehca_dbg(cq->device,
+ "Received COMPLETION ehca_cq=%p cq_num=%x -----",
+ my_cq, my_cq->cq_number);
+ ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+ ehca_dbg(cq->device,
+ "ehca_cq=%p cq_num=%x -------------------------",
+ my_cq, my_cq->cq_number);
+ }
+
+ /* we got a completion! */
+ wc->wr_id = cqe->work_request_id;
+
+ /* eval ib_wc_opcode */
+ wc->opcode = ib_wc_opcode[cqe->optype]-1;
+ if (unlikely(wc->opcode == -1)) {
+ ehca_err(cq->device, "Invalid cqe->OPType=%x cqe->status=%x "
+ "ehca_cq=%p cq_num=%x",
+ cqe->optype, cqe->status, my_cq, my_cq->cq_number);
+ /* dump cqe for other infos */
+ ehca_dmp(cqe, 64, "ehca_cq=%p cq_num=%x",
+ my_cq, my_cq->cq_number);
+ /* update also queue adder to throw away this entry!!! */
+ goto poll_cq_one_exit0;
+ }
+ /* eval ib_wc_status */
+ if (unlikely(cqe->status & WC_STATUS_ERROR_BIT)) {
+ /* complete with errors */
+ map_ib_wc_status(cqe->status, &wc->status);
+ wc->vendor_err = wc->status;
+ } else
+ wc->status = IB_WC_SUCCESS;
+
+ wc->qp_num = cqe->local_qp_number;
+ wc->byte_len = cqe->nr_bytes_transferred;
+ wc->pkey_index = cqe->pkey_index;
+ wc->slid = cqe->rlid;
+ wc->dlid_path_bits = cqe->dlid;
+ wc->src_qp = cqe->remote_qp_number;
+ wc->wc_flags = cqe->w_completion_flags;
+ wc->imm_data = cpu_to_be32(cqe->immediate_data);
+ wc->sl = cqe->service_level;
+
+ if (wc->status != IB_WC_SUCCESS)
+ ehca_dbg(cq->device,
+ "ehca_cq=%p cq_num=%x WARNING unsuccessful cqe "
+ "OPType=%x status=%x qp_num=%x src_qp=%x wr_id=%lx "
+ "cqe=%p", my_cq, my_cq->cq_number, cqe->optype,
+ cqe->status, cqe->local_qp_number,
+ cqe->remote_qp_number, cqe->work_request_id, cqe);
+
+poll_cq_one_exit0:
+ if (cqe_count > 0)
+ hipz_update_feca(my_cq, cqe_count);
+
+ return ret;
+}
+
+int ehca_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
+{
+ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+ int nr;
+ struct ib_wc *current_wc = wc;
+ int ret = 0;
+ unsigned long spl_flags;
+
+ if (num_entries < 1) {
+ ehca_err(cq->device, "Invalid num_entries=%d ehca_cq=%p "
+ "cq_num=%x", num_entries, my_cq, my_cq->cq_number);
+ ret = -EINVAL;
+ goto poll_cq_exit0;
+ }
+
+ spin_lock_irqsave(&my_cq->spinlock, spl_flags);
+ for (nr = 0; nr < num_entries; nr++) {
+ ret = ehca_poll_cq_one(cq, current_wc);
+ if (ret)
+ break;
+ current_wc++;
+ } /* eof for nr */
+ spin_unlock_irqrestore(&my_cq->spinlock, spl_flags);
+ if (ret == -EAGAIN || !ret)
+ ret = nr;
+
+poll_cq_exit0:
+ return ret;
+}
+
+int ehca_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify cq_notify)
+{
+ struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
+
+ switch (cq_notify) {
+ case IB_CQ_SOLICITED:
+ hipz_set_cqx_n0(my_cq, 1);
+ break;
+ case IB_CQ_NEXT_COMP:
+ hipz_set_cqx_n1(my_cq, 1);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_sqp.c b/drivers/infiniband/hw/ehca/ehca_sqp.c
new file mode 100644
index 00000000000..9f16e9c7939
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_sqp.c
@@ -0,0 +1,111 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * SQP functions
+ *
+ * Authors: Khadija Souissi <souissi@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <linux/module.h>
+#include <linux/err.h>
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+#include "ehca_iverbs.h"
+#include "hcp_if.h"
+
+
+/**
+ * ehca_define_sqp - Defines special queue pair 1 (GSI QP). When special queue
+ * pair is created successfully, the corresponding port gets active.
+ *
+ * Define Special Queue pair 0 (SMI QP) is still not supported.
+ *
+ * @qp_init_attr: Queue pair init attributes with port and queue pair type
+ */
+
+u64 ehca_define_sqp(struct ehca_shca *shca,
+ struct ehca_qp *ehca_qp,
+ struct ib_qp_init_attr *qp_init_attr)
+{
+ u32 pma_qp_nr, bma_qp_nr;
+ u64 ret;
+ u8 port = qp_init_attr->port_num;
+ int counter;
+
+ shca->sport[port - 1].port_state = IB_PORT_DOWN;
+
+ switch (qp_init_attr->qp_type) {
+ case IB_QPT_SMI:
+ /* function not supported yet */
+ break;
+ case IB_QPT_GSI:
+ ret = hipz_h_define_aqp1(shca->ipz_hca_handle,
+ ehca_qp->ipz_qp_handle,
+ ehca_qp->galpas.kernel,
+ (u32) qp_init_attr->port_num,
+ &pma_qp_nr, &bma_qp_nr);
+
+ if (ret != H_SUCCESS) {
+ ehca_err(&shca->ib_device,
+ "Can't define AQP1 for port %x. rc=%lx",
+ port, ret);
+ return ret;
+ }
+ break;
+ default:
+ ehca_err(&shca->ib_device, "invalid qp_type=%x",
+ qp_init_attr->qp_type);
+ return H_PARAMETER;
+ }
+
+ for (counter = 0;
+ shca->sport[port - 1].port_state != IB_PORT_ACTIVE &&
+ counter < ehca_port_act_time;
+ counter++) {
+ ehca_dbg(&shca->ib_device, "... wait until port %x is active",
+ port);
+ msleep_interruptible(1000);
+ }
+
+ if (counter == ehca_port_act_time) {
+ ehca_err(&shca->ib_device, "Port %x is not active.", port);
+ return H_HARDWARE;
+ }
+
+ return H_SUCCESS;
+}
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
new file mode 100644
index 00000000000..9f56bb846d9
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -0,0 +1,172 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * auxiliary functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Khadija Souissi <souissik@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef EHCA_TOOLS_H
+#define EHCA_TOOLS_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/kthread.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/version.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/device.h>
+
+#include <asm/abs_addr.h>
+#include <asm/ibmebus.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+
+extern int ehca_debug_level;
+
+#define ehca_dbg(ib_dev, format, arg...) \
+ do { \
+ if (unlikely(ehca_debug_level)) \
+ dev_printk(KERN_DEBUG, (ib_dev)->dma_device, \
+ "PU%04x EHCA_DBG:%s " format "\n", \
+ get_paca()->paca_index, __FUNCTION__, \
+ ## arg); \
+ } while (0)
+
+#define ehca_info(ib_dev, format, arg...) \
+ dev_info((ib_dev)->dma_device, "PU%04x EHCA_INFO:%s " format "\n", \
+ get_paca()->paca_index, __FUNCTION__, ## arg)
+
+#define ehca_warn(ib_dev, format, arg...) \
+ dev_warn((ib_dev)->dma_device, "PU%04x EHCA_WARN:%s " format "\n", \
+ get_paca()->paca_index, __FUNCTION__, ## arg)
+
+#define ehca_err(ib_dev, format, arg...) \
+ dev_err((ib_dev)->dma_device, "PU%04x EHCA_ERR:%s " format "\n", \
+ get_paca()->paca_index, __FUNCTION__, ## arg)
+
+/* use this one only if no ib_dev available */
+#define ehca_gen_dbg(format, arg...) \
+ do { \
+ if (unlikely(ehca_debug_level)) \
+ printk(KERN_DEBUG "PU%04x EHCA_DBG:%s " format "\n",\
+ get_paca()->paca_index, __FUNCTION__, ## arg); \
+ } while (0)
+
+#define ehca_gen_warn(format, arg...) \
+ do { \
+ if (unlikely(ehca_debug_level)) \
+ printk(KERN_INFO "PU%04x EHCA_WARN:%s " format "\n",\
+ get_paca()->paca_index, __FUNCTION__, ## arg); \
+ } while (0)
+
+#define ehca_gen_err(format, arg...) \
+ printk(KERN_ERR "PU%04x EHCA_ERR:%s " format "\n", \
+ get_paca()->paca_index, __FUNCTION__, ## arg)
+
+/**
+ * ehca_dmp - printk a memory block, whose length is n*8 bytes.
+ * Each line has the following layout:
+ * <format string> adr=X ofs=Y <8 bytes hex> <8 bytes hex>
+ */
+#define ehca_dmp(adr, len, format, args...) \
+ do { \
+ unsigned int x; \
+ unsigned int l = (unsigned int)(len); \
+ unsigned char *deb = (unsigned char*)(adr); \
+ for (x = 0; x < l; x += 16) { \
+ printk("EHCA_DMP:%s" format \
+ " adr=%p ofs=%04x %016lx %016lx\n", \
+ __FUNCTION__, ##args, deb, x, \
+ *((u64 *)&deb[0]), *((u64 *)&deb[8])); \
+ deb += 16; \
+ } \
+ } while (0)
+
+/* define a bitmask, little endian version */
+#define EHCA_BMASK(pos,length) (((pos)<<16)+(length))
+
+/* define a bitmask, the ibm way... */
+#define EHCA_BMASK_IBM(from,to) (((63-to)<<16)+((to)-(from)+1))
+
+/* internal function, don't use */
+#define EHCA_BMASK_SHIFTPOS(mask) (((mask)>>16)&0xffff)
+
+/* internal function, don't use */
+#define EHCA_BMASK_MASK(mask) (0xffffffffffffffffULL >> ((64-(mask))&0xffff))
+
+/**
+ * EHCA_BMASK_SET - return value shifted and masked by mask
+ * variable|=EHCA_BMASK_SET(MY_MASK,0x4711) ORs the bits in variable
+ * variable&=~EHCA_BMASK_SET(MY_MASK,-1) clears the bits from the mask
+ * in variable
+ */
+#define EHCA_BMASK_SET(mask,value) \
+ ((EHCA_BMASK_MASK(mask) & ((u64)(value)))<<EHCA_BMASK_SHIFTPOS(mask))
+
+/**
+ * EHCA_BMASK_GET - extract a parameter from value by mask
+ */
+#define EHCA_BMASK_GET(mask,value) \
+ (EHCA_BMASK_MASK(mask)& (((u64)(value))>>EHCA_BMASK_SHIFTPOS(mask)))
+
+
+/* Converts ehca to ib return code */
+static inline int ehca2ib_return_code(u64 ehca_rc)
+{
+ switch (ehca_rc) {
+ case H_SUCCESS:
+ return 0;
+ case H_BUSY:
+ return -EBUSY;
+ case H_NO_MEM:
+ return -ENOMEM;
+ default:
+ return -EINVAL;
+ }
+}
+
+
+#endif /* EHCA_TOOLS_H */
diff --git a/drivers/infiniband/hw/ehca/ehca_uverbs.c b/drivers/infiniband/hw/ehca/ehca_uverbs.c
new file mode 100644
index 00000000000..e08764e4aef
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ehca_uverbs.c
@@ -0,0 +1,392 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * userspace support verbs
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/current.h>
+
+#include "ehca_classes.h"
+#include "ehca_iverbs.h"
+#include "ehca_mrmw.h"
+#include "ehca_tools.h"
+#include "hcp_if.h"
+
+struct ib_ucontext *ehca_alloc_ucontext(struct ib_device *device,
+ struct ib_udata *udata)
+{
+ struct ehca_ucontext *my_context;
+
+ my_context = kzalloc(sizeof *my_context, GFP_KERNEL);
+ if (!my_context) {
+ ehca_err(device, "Out of memory device=%p", device);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return &my_context->ib_ucontext;
+}
+
+int ehca_dealloc_ucontext(struct ib_ucontext *context)
+{
+ kfree(container_of(context, struct ehca_ucontext, ib_ucontext));
+ return 0;
+}
+
+struct page *ehca_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ struct page *mypage = NULL;
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 cur_pid = current->tgid;
+ unsigned long flags;
+ struct ehca_cq *cq;
+ struct ehca_qp *qp;
+ struct ehca_pd *pd;
+ u64 offset;
+ void *vaddr;
+
+ switch (q_type) {
+ case 1: /* CQ */
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!cq) {
+ ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+
+ if (cq->ownpid != cur_pid) {
+ ehca_err(cq->ib_cq.device,
+ "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ if (rsrc_type == 2) {
+ ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
+ ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
+ offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ break;
+
+ case 2: /* QP */
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!qp) {
+ ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid != cur_pid) {
+ ehca_err(qp->ib_qp.device,
+ "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return NOPAGE_SIGBUS;
+ }
+
+ if (rsrc_type == 2) { /* rqueue */
+ ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
+ ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
+ offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ } else if (rsrc_type == 3) { /* squeue */
+ ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
+ offset = address - vma->vm_start;
+ vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
+ ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
+ offset, vaddr);
+ mypage = virt_to_page(vaddr);
+ }
+ break;
+
+ default:
+ ehca_gen_err("bad queue type %x", q_type);
+ return NOPAGE_SIGBUS;
+ }
+
+ if (!mypage) {
+ ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
+ return NOPAGE_SIGBUS;
+ }
+ get_page(mypage);
+
+ return mypage;
+}
+
+static struct vm_operations_struct ehcau_vm_ops = {
+ .nopage = ehca_nopage,
+};
+
+int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
+ u32 idr_handle = fileoffset >> 32;
+ u32 q_type = (fileoffset >> 28) & 0xF; /* CQ, QP,... */
+ u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
+ u32 cur_pid = current->tgid;
+ u32 ret;
+ u64 vsize, physical;
+ unsigned long flags;
+ struct ehca_cq *cq;
+ struct ehca_qp *qp;
+ struct ehca_pd *pd;
+
+ switch (q_type) {
+ case 1: /* CQ */
+ spin_lock_irqsave(&ehca_cq_idr_lock, flags);
+ cq = idr_find(&ehca_cq_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!cq)
+ return -EINVAL;
+
+ if (cq->ownpid != cur_pid) {
+ ehca_err(cq->ib_cq.device,
+ "Invalid caller pid=%x ownpid=%x",
+ cur_pid, cq->ownpid);
+ return -ENOMEM;
+ }
+
+ if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
+ return -EINVAL;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ return -EINVAL;
+ }
+
+ physical = cq->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ ehca_dbg(cq->ib_cq.device,
+ "vsize=%lx physical=%lx", vsize, physical);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret) {
+ ehca_err(cq->ib_cq.device,
+ "remap_pfn_range() failed ret=%x",
+ ret);
+ return -ENOMEM;
+ }
+ break;
+
+ case 2: /* cq queue_addr */
+ ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ break;
+
+ default:
+ ehca_err(cq->ib_cq.device, "bad resource type %x",
+ rsrc_type);
+ return -EINVAL;
+ }
+ break;
+
+ case 2: /* QP */
+ spin_lock_irqsave(&ehca_qp_idr_lock, flags);
+ qp = idr_find(&ehca_qp_idr, idr_handle);
+ spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+
+ /* make sure this mmap really belongs to the authorized user */
+ if (!qp)
+ return -EINVAL;
+
+ pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
+ if (pd->ownpid != cur_pid) {
+ ehca_err(qp->ib_qp.device,
+ "Invalid caller pid=%x ownpid=%x",
+ cur_pid, pd->ownpid);
+ return -ENOMEM;
+ }
+
+ if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
+ return -EINVAL;
+
+ switch (rsrc_type) {
+ case 1: /* galpa fw handle */
+ ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vsize = vma->vm_end - vma->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
+ vma->vm_end - vma->vm_start);
+ return -EINVAL;
+ }
+
+ physical = qp->galpas.user.fw_handle;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_flags |= VM_IO | VM_RESERVED;
+
+ ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
+ vsize, physical);
+ ret = remap_pfn_range(vma, vma->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ vma->vm_page_prot);
+ if (ret) {
+ ehca_err(qp->ib_qp.device,
+ "remap_pfn_range() failed ret=%x",
+ ret);
+ return -ENOMEM;
+ }
+ break;
+
+ case 2: /* qp rqueue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ break;
+
+ case 3: /* qp squeue_addr */
+ ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_ops = &ehcau_vm_ops;
+ break;
+
+ default:
+ ehca_err(qp->ib_qp.device, "bad resource type %x",
+ rsrc_type);
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ ehca_gen_err("bad queue type %x", q_type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
+ struct vm_area_struct **vma)
+{
+ down_write(&current->mm->mmap_sem);
+ *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS,
+ foffset);
+ up_write(&current->mm->mmap_sem);
+ if (!(*mapped)) {
+ ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
+ foffset, length);
+ return -EINVAL;
+ }
+
+ *vma = find_vma(current->mm, (u64)*mapped);
+ if (!(*vma)) {
+ down_write(&current->mm->mmap_sem);
+ do_munmap(current->mm, 0, length);
+ up_write(&current->mm->mmap_sem);
+ ehca_gen_err("couldn't find vma queue=%p", *mapped);
+ return -EINVAL;
+ }
+ (*vma)->vm_flags |= VM_RESERVED;
+ (*vma)->vm_ops = &ehcau_vm_ops;
+
+ return 0;
+}
+
+int ehca_mmap_register(u64 physical, void **mapped,
+ struct vm_area_struct **vma)
+{
+ int ret;
+ unsigned long vsize;
+ /* ehca hw supports only 4k page */
+ ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
+ if (ret) {
+ ehca_gen_err("could'nt mmap physical=%lx", physical);
+ return ret;
+ }
+
+ (*vma)->vm_flags |= VM_RESERVED;
+ vsize = (*vma)->vm_end - (*vma)->vm_start;
+ if (vsize != EHCA_PAGESIZE) {
+ ehca_gen_err("invalid vsize=%lx",
+ (*vma)->vm_end - (*vma)->vm_start);
+ return -EINVAL;
+ }
+
+ (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
+ (*vma)->vm_flags |= VM_IO | VM_RESERVED;
+
+ ret = remap_pfn_range((*vma), (*vma)->vm_start,
+ physical >> PAGE_SHIFT, vsize,
+ (*vma)->vm_page_prot);
+ if (ret) {
+ ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+ return -ENOMEM;
+ }
+
+ return 0;
+
+}
+
+int ehca_munmap(unsigned long addr, size_t len) {
+ int ret = 0;
+ struct mm_struct *mm = current->mm;
+ if (mm) {
+ down_write(&mm->mmap_sem);
+ ret = do_munmap(mm, addr, len);
+ up_write(&mm->mmap_sem);
+ }
+ return ret;
+}
diff --git a/drivers/infiniband/hw/ehca/hcp_if.c b/drivers/infiniband/hw/ehca/hcp_if.c
new file mode 100644
index 00000000000..3fb46e67df8
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hcp_if.c
@@ -0,0 +1,874 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Firmware Infiniband Interface code for POWER
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Gerd Bayer <gerd.bayer@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm/hvcall.h>
+#include "ehca_tools.h"
+#include "hcp_if.h"
+#include "hcp_phyp.h"
+#include "hipz_fns.h"
+#include "ipz_pt_fn.h"
+
+#define H_ALL_RES_QP_ENHANCED_OPS EHCA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_PTE_PIN EHCA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_SERVICE_TYPE EHCA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_LL_RQ_CQE_POSTING EHCA_BMASK_IBM(18, 18)
+#define H_ALL_RES_QP_LL_SQ_CQE_POSTING EHCA_BMASK_IBM(19, 21)
+#define H_ALL_RES_QP_SIGNALING_TYPE EHCA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_UD_AV_LKEY_CTRL EHCA_BMASK_IBM(31, 31)
+#define H_ALL_RES_QP_RESOURCE_TYPE EHCA_BMASK_IBM(56, 63)
+
+#define H_ALL_RES_QP_MAX_OUTST_SEND_WR EHCA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_MAX_OUTST_RECV_WR EHCA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_MAX_SEND_SGE EHCA_BMASK_IBM(32, 39)
+#define H_ALL_RES_QP_MAX_RECV_SGE EHCA_BMASK_IBM(40, 47)
+
+#define H_ALL_RES_QP_ACT_OUTST_SEND_WR EHCA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_OUTST_RECV_WR EHCA_BMASK_IBM(48, 63)
+#define H_ALL_RES_QP_ACT_SEND_SGE EHCA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_RECV_SGE EHCA_BMASK_IBM(24, 31)
+
+#define H_ALL_RES_QP_SQUEUE_SIZE_PAGES EHCA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_RQUEUE_SIZE_PAGES EHCA_BMASK_IBM(32, 63)
+
+/* direct access qp controls */
+#define DAQP_CTRL_ENABLE 0x01
+#define DAQP_CTRL_SEND_COMP 0x20
+#define DAQP_CTRL_RECV_COMP 0x40
+
+static u32 get_longbusy_msecs(int longbusy_rc)
+{
+ switch (longbusy_rc) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+static long ehca_plpar_hcall_norets(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7)
+{
+ long ret;
+ int i, sleep_msecs;
+
+ ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
+ "arg5=%lx arg6=%lx arg7=%lx",
+ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+
+ for (i = 0; i < 5; i++) {
+ ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7);
+
+ if (H_IS_LONG_BUSY(ret)) {
+ sleep_msecs = get_longbusy_msecs(ret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (ret < H_SUCCESS)
+ ehca_gen_err("opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx ",
+ opcode, ret,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7);
+
+ ehca_gen_dbg("opcode=%lx ret=%lx", opcode, ret);
+ return ret;
+
+ }
+
+ return H_BUSY;
+}
+
+static long ehca_plpar_hcall9(unsigned long opcode,
+ unsigned long *outs, /* array of 9 outputs */
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9)
+{
+ long ret;
+ int i, sleep_msecs;
+
+ ehca_gen_dbg("opcode=%lx arg1=%lx arg2=%lx arg3=%lx arg4=%lx "
+ "arg5=%lx arg6=%lx arg7=%lx arg8=%lx arg9=%lx",
+ opcode, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
+ arg8, arg9);
+
+ for (i = 0; i < 5; i++) {
+ ret = plpar_hcall9(opcode, outs,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9);
+
+ if (H_IS_LONG_BUSY(ret)) {
+ sleep_msecs = get_longbusy_msecs(ret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (ret < H_SUCCESS)
+ ehca_gen_err("opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
+ " arg9=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx out8=%lx"
+ " out9=%lx",
+ opcode, ret,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9,
+ outs[0], outs[1], outs[2], outs[3],
+ outs[4], outs[5], outs[6], outs[7],
+ outs[8]);
+
+ ehca_gen_dbg("opcode=%lx ret=%lx out1=%lx out2=%lx out3=%lx "
+ "out4=%lx out5=%lx out6=%lx out7=%lx out8=%lx "
+ "out9=%lx",
+ opcode, ret, outs[0], outs[1], outs[2], outs[3],
+ outs[4], outs[5], outs[6], outs[7], outs[8]);
+ return ret;
+
+ }
+
+ return H_BUSY;
+}
+u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_pfeq *pfeq,
+ const u32 neq_control,
+ const u32 number_of_entries,
+ struct ipz_eq_handle *eq_handle,
+ u32 *act_nr_of_entries,
+ u32 *act_pages,
+ u32 *eq_ist)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+ u64 allocate_controls;
+
+ /* resource type */
+ allocate_controls = 3ULL;
+
+ /* ISN is associated */
+ if (neq_control != 1)
+ allocate_controls = (1ULL << (63 - 7)) | allocate_controls;
+ else /* notification event queue */
+ allocate_controls = (1ULL << 63) | allocate_controls;
+
+ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
+ adapter_handle.handle, /* r4 */
+ allocate_controls, /* r5 */
+ number_of_entries, /* r6 */
+ 0, 0, 0, 0, 0, 0);
+ eq_handle->handle = outs[0];
+ *act_nr_of_entries = (u32)outs[3];
+ *act_pages = (u32)outs[4];
+ *eq_ist = (u32)outs[5];
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ ehca_gen_err("Not enough resource - ret=%lx ", ret);
+
+ return ret;
+}
+
+u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
+ struct ipz_eq_handle eq_handle,
+ const u64 event_mask)
+{
+ return ehca_plpar_hcall_norets(H_RESET_EVENTS,
+ adapter_handle.handle, /* r4 */
+ eq_handle.handle, /* r5 */
+ event_mask, /* r6 */
+ 0, 0, 0, 0);
+}
+
+u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ struct ehca_alloc_cq_parms *param)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
+ adapter_handle.handle, /* r4 */
+ 2, /* r5 */
+ param->eq_handle.handle, /* r6 */
+ cq->token, /* r7 */
+ param->nr_cqe, /* r8 */
+ 0, 0, 0, 0);
+ cq->ipz_cq_handle.handle = outs[0];
+ param->act_nr_of_entries = (u32)outs[3];
+ param->act_pages = (u32)outs[4];
+
+ if (ret == H_SUCCESS)
+ hcp_galpas_ctor(&cq->galpas, outs[5], outs[6]);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ ehca_gen_err("Not enough resources. ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp,
+ struct ehca_alloc_qp_parms *parms)
+{
+ u64 ret;
+ u64 allocate_controls;
+ u64 max_r10_reg;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+ u16 max_nr_receive_wqes = qp->init_attr.cap.max_recv_wr + 1;
+ u16 max_nr_send_wqes = qp->init_attr.cap.max_send_wr + 1;
+ int daqp_ctrl = parms->daqp_ctrl;
+
+ allocate_controls =
+ EHCA_BMASK_SET(H_ALL_RES_QP_ENHANCED_OPS,
+ (daqp_ctrl & DAQP_CTRL_ENABLE) ? 1 : 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_PTE_PIN, 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SERVICE_TYPE, parms->servicetype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_SIGNALING_TYPE, parms->sigtype)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_LL_RQ_CQE_POSTING,
+ (daqp_ctrl & DAQP_CTRL_RECV_COMP) ? 1 : 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_LL_SQ_CQE_POSTING,
+ (daqp_ctrl & DAQP_CTRL_SEND_COMP) ? 1 : 0)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_UD_AV_LKEY_CTRL,
+ parms->ud_av_l_key_ctl)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_RESOURCE_TYPE, 1);
+
+ max_r10_reg =
+ EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_SEND_WR,
+ max_nr_send_wqes)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_OUTST_RECV_WR,
+ max_nr_receive_wqes)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_SEND_SGE,
+ parms->max_send_sge)
+ | EHCA_BMASK_SET(H_ALL_RES_QP_MAX_RECV_SGE,
+ parms->max_recv_sge);
+
+ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
+ adapter_handle.handle, /* r4 */
+ allocate_controls, /* r5 */
+ qp->send_cq->ipz_cq_handle.handle,
+ qp->recv_cq->ipz_cq_handle.handle,
+ parms->ipz_eq_handle.handle,
+ ((u64)qp->token << 32) | parms->pd.value,
+ max_r10_reg, /* r10 */
+ parms->ud_av_l_key_ctl, /* r11 */
+ 0);
+ qp->ipz_qp_handle.handle = outs[0];
+ qp->real_qp_num = (u32)outs[1];
+ parms->act_nr_send_sges =
+ (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_SEND_WR, outs[2]);
+ parms->act_nr_recv_wqes =
+ (u16)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_OUTST_RECV_WR, outs[2]);
+ parms->act_nr_send_sges =
+ (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_SEND_SGE, outs[3]);
+ parms->act_nr_recv_sges =
+ (u8)EHCA_BMASK_GET(H_ALL_RES_QP_ACT_RECV_SGE, outs[3]);
+ parms->nr_sq_pages =
+ (u32)EHCA_BMASK_GET(H_ALL_RES_QP_SQUEUE_SIZE_PAGES, outs[4]);
+ parms->nr_rq_pages =
+ (u32)EHCA_BMASK_GET(H_ALL_RES_QP_RQUEUE_SIZE_PAGES, outs[4]);
+
+ if (ret == H_SUCCESS)
+ hcp_galpas_ctor(&qp->galpas, outs[6], outs[6]);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ ehca_gen_err("Not enough resources. ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
+ const u8 port_id,
+ struct hipz_query_port *query_port_response_block)
+{
+ u64 ret;
+ u64 r_cb = virt_to_abs(query_port_response_block);
+
+ if (r_cb & (EHCA_PAGESIZE-1)) {
+ ehca_gen_err("response block not page aligned");
+ return H_PARAMETER;
+ }
+
+ ret = ehca_plpar_hcall_norets(H_QUERY_PORT,
+ adapter_handle.handle, /* r4 */
+ port_id, /* r5 */
+ r_cb, /* r6 */
+ 0, 0, 0, 0);
+
+ if (ehca_debug_level)
+ ehca_dmp(query_port_response_block, 64, "response_block");
+
+ return ret;
+}
+
+u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
+ struct hipz_query_hca *query_hca_rblock)
+{
+ u64 r_cb = virt_to_abs(query_hca_rblock);
+
+ if (r_cb & (EHCA_PAGESIZE-1)) {
+ ehca_gen_err("response_block=%p not page aligned",
+ query_hca_rblock);
+ return H_PARAMETER;
+ }
+
+ return ehca_plpar_hcall_norets(H_QUERY_HCA,
+ adapter_handle.handle, /* r4 */
+ r_cb, /* r5 */
+ 0, 0, 0, 0, 0);
+}
+
+u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 logical_address_of_page,
+ u64 count)
+{
+ return ehca_plpar_hcall_norets(H_REGISTER_RPAGES,
+ adapter_handle.handle, /* r4 */
+ queue_type | pagesize << 8, /* r5 */
+ resource_handle, /* r6 */
+ logical_address_of_page, /* r7 */
+ count, /* r8 */
+ 0, 0);
+}
+
+u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_eq_handle eq_handle,
+ struct ehca_pfeq *pfeq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count)
+{
+ if (count != 1) {
+ ehca_gen_err("Ppage counter=%lx", count);
+ return H_PARAMETER;
+ }
+ return hipz_h_register_rpage(adapter_handle,
+ pagesize,
+ queue_type,
+ eq_handle.handle,
+ logical_address_of_page, count);
+}
+
+u64 hipz_h_query_int_state(const struct ipz_adapter_handle adapter_handle,
+ u32 ist)
+{
+ u64 ret;
+ ret = ehca_plpar_hcall_norets(H_QUERY_INT_STATE,
+ adapter_handle.handle, /* r4 */
+ ist, /* r5 */
+ 0, 0, 0, 0, 0);
+
+ if (ret != H_SUCCESS && ret != H_BUSY)
+ ehca_gen_err("Could not query interrupt state.");
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_cq_handle cq_handle,
+ struct ehca_pfcq *pfcq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa gal)
+{
+ if (count != 1) {
+ ehca_gen_err("Page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ return hipz_h_register_rpage(adapter_handle, pagesize, queue_type,
+ cq_handle.handle, logical_address_of_page,
+ count);
+}
+
+u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa galpa)
+{
+ if (count != 1) {
+ ehca_gen_err("Page counter=%lx", count);
+ return H_PARAMETER;
+ }
+
+ return hipz_h_register_rpage(adapter_handle,pagesize,queue_type,
+ qp_handle.handle,logical_address_of_page,
+ count);
+}
+
+u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ void **log_addr_next_sq_wqe2processed,
+ void **log_addr_next_rq_wqe2processed,
+ int dis_and_get_function_code)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
+ adapter_handle.handle, /* r4 */
+ dis_and_get_function_code, /* r5 */
+ qp_handle.handle, /* r6 */
+ 0, 0, 0, 0, 0, 0);
+ if (log_addr_next_sq_wqe2processed)
+ *log_addr_next_sq_wqe2processed = (void*)outs[0];
+ if (log_addr_next_rq_wqe2processed)
+ *log_addr_next_rq_wqe2processed = (void*)outs[1];
+
+ return ret;
+}
+
+u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u64 update_mask,
+ struct hcp_modify_qp_control_block *mqpcb,
+ struct h_galpa gal)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+ ret = ehca_plpar_hcall9(H_MODIFY_QP, outs,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ update_mask, /* r6 */
+ virt_to_abs(mqpcb), /* r7 */
+ 0, 0, 0, 0, 0);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ ehca_gen_err("Insufficient resources ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ struct hcp_modify_qp_control_block *qqpcb,
+ struct h_galpa gal)
+{
+ return ehca_plpar_hcall_norets(H_QUERY_QP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ virt_to_abs(qqpcb), /* r6 */
+ 0, 0, 0, 0);
+}
+
+u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = hcp_galpas_dtor(&qp->galpas);
+ if (ret) {
+ ehca_gen_err("Could not destruct qp->galpas");
+ return H_RESOURCE;
+ }
+ ret = ehca_plpar_hcall9(H_DISABLE_AND_GETC, outs,
+ adapter_handle.handle, /* r4 */
+ /* function code */
+ 1, /* r5 */
+ qp->ipz_qp_handle.handle, /* r6 */
+ 0, 0, 0, 0, 0, 0);
+ if (ret == H_HARDWARE)
+ ehca_gen_err("HCA not operational. ret=%lx", ret);
+
+ ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ qp->ipz_qp_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0);
+
+ if (ret == H_RESOURCE)
+ ehca_gen_err("Resource still in use. ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port)
+{
+ return ehca_plpar_hcall_norets(H_DEFINE_AQP0,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ port, /* r6 */
+ 0, 0, 0, 0);
+}
+
+u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port, u32 * pma_qp_nr,
+ u32 * bma_qp_nr)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_DEFINE_AQP1, outs,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ port, /* r6 */
+ 0, 0, 0, 0, 0, 0);
+ *pma_qp_nr = (u32)outs[0];
+ *bma_qp_nr = (u32)outs[1];
+
+ if (ret == H_ALIAS_EXIST)
+ ehca_gen_err("AQP1 already exists. ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id)
+{
+ u64 ret;
+
+ ret = ehca_plpar_hcall_norets(H_ATTACH_MCQP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ mcg_dlid, /* r6 */
+ interface_id, /* r7 */
+ subnet_prefix, /* r8 */
+ 0, 0);
+
+ if (ret == H_NOT_ENOUGH_RESOURCES)
+ ehca_gen_err("Not enough resources. ret=%lx", ret);
+
+ return ret;
+}
+
+u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id)
+{
+ return ehca_plpar_hcall_norets(H_DETACH_MCQP,
+ adapter_handle.handle, /* r4 */
+ qp_handle.handle, /* r5 */
+ mcg_dlid, /* r6 */
+ interface_id, /* r7 */
+ subnet_prefix, /* r8 */
+ 0, 0);
+}
+
+u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ u8 force_flag)
+{
+ u64 ret;
+
+ ret = hcp_galpas_dtor(&cq->galpas);
+ if (ret) {
+ ehca_gen_err("Could not destruct cp->galpas");
+ return H_RESOURCE;
+ }
+
+ ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ cq->ipz_cq_handle.handle, /* r5 */
+ force_flag != 0 ? 1L : 0L, /* r6 */
+ 0, 0, 0, 0);
+
+ if (ret == H_RESOURCE)
+ ehca_gen_err("H_FREE_RESOURCE failed ret=%lx ", ret);
+
+ return ret;
+}
+
+u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_eq *eq)
+{
+ u64 ret;
+
+ ret = hcp_galpas_dtor(&eq->galpas);
+ if (ret) {
+ ehca_gen_err("Could not destruct eq->galpas");
+ return H_RESOURCE;
+ }
+
+ ret = ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ eq->ipz_eq_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0);
+
+ if (ret == H_RESOURCE)
+ ehca_gen_err("Resource in use. ret=%lx ", ret);
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
+ adapter_handle.handle, /* r4 */
+ 5, /* r5 */
+ vaddr, /* r6 */
+ length, /* r7 */
+ (((u64)access_ctrl) << 32ULL), /* r8 */
+ pd.value, /* r9 */
+ 0, 0, 0);
+ outparms->handle.handle = outs[0];
+ outparms->lkey = (u32)outs[2];
+ outparms->rkey = (u32)outs[3];
+
+ return ret;
+}
+
+u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count)
+{
+ u64 ret;
+
+ if ((count > 1) && (logical_address_of_page & (EHCA_PAGESIZE-1))) {
+ ehca_gen_err("logical_address_of_page not on a 4k boundary "
+ "adapter_handle=%lx mr=%p mr_handle=%lx "
+ "pagesize=%x queue_type=%x "
+ "logical_address_of_page=%lx count=%lx",
+ adapter_handle.handle, mr,
+ mr->ipz_mr_handle.handle, pagesize, queue_type,
+ logical_address_of_page, count);
+ ret = H_PARAMETER;
+ } else
+ ret = hipz_h_register_rpage(adapter_handle, pagesize,
+ queue_type,
+ mr->ipz_mr_handle.handle,
+ logical_address_of_page, count);
+ return ret;
+}
+
+u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_QUERY_MR, outs,
+ adapter_handle.handle, /* r4 */
+ mr->ipz_mr_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0, 0, 0);
+ outparms->len = outs[0];
+ outparms->vaddr = outs[1];
+ outparms->acl = outs[4] >> 32;
+ outparms->lkey = (u32)(outs[5] >> 32);
+ outparms->rkey = (u32)(outs[5] & (0xffffffff));
+
+ return ret;
+}
+
+u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr)
+{
+ return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ mr->ipz_mr_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0);
+}
+
+u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr_in,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ const u64 mr_addr_cb,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_REREGISTER_PMR, outs,
+ adapter_handle.handle, /* r4 */
+ mr->ipz_mr_handle.handle, /* r5 */
+ vaddr_in, /* r6 */
+ length, /* r7 */
+ /* r8 */
+ ((((u64)access_ctrl) << 32ULL) | pd.value),
+ mr_addr_cb, /* r9 */
+ 0, 0, 0);
+ outparms->vaddr = outs[1];
+ outparms->lkey = (u32)outs[2];
+ outparms->rkey = (u32)outs[3];
+
+ return ret;
+}
+
+u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const struct ehca_mr *orig_mr,
+ const u64 vaddr_in,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_REGISTER_SMR, outs,
+ adapter_handle.handle, /* r4 */
+ orig_mr->ipz_mr_handle.handle, /* r5 */
+ vaddr_in, /* r6 */
+ (((u64)access_ctrl) << 32ULL), /* r7 */
+ pd.value, /* r8 */
+ 0, 0, 0, 0);
+ outparms->handle.handle = outs[0];
+ outparms->lkey = (u32)outs[2];
+ outparms->rkey = (u32)outs[3];
+
+ return ret;
+}
+
+u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ const struct ipz_pd pd,
+ struct ehca_mw_hipzout_parms *outparms)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_ALLOC_RESOURCE, outs,
+ adapter_handle.handle, /* r4 */
+ 6, /* r5 */
+ pd.value, /* r6 */
+ 0, 0, 0, 0, 0, 0);
+ outparms->handle.handle = outs[0];
+ outparms->rkey = (u32)outs[3];
+
+ return ret;
+}
+
+u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ struct ehca_mw_hipzout_parms *outparms)
+{
+ u64 ret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ ret = ehca_plpar_hcall9(H_QUERY_MW, outs,
+ adapter_handle.handle, /* r4 */
+ mw->ipz_mw_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0, 0, 0);
+ outparms->rkey = (u32)outs[3];
+
+ return ret;
+}
+
+u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw)
+{
+ return ehca_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle.handle, /* r4 */
+ mw->ipz_mw_handle.handle, /* r5 */
+ 0, 0, 0, 0, 0);
+}
+
+u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
+ const u64 ressource_handle,
+ void *rblock,
+ unsigned long *byte_count)
+{
+ u64 r_cb = virt_to_abs(rblock);
+
+ if (r_cb & (EHCA_PAGESIZE-1)) {
+ ehca_gen_err("rblock not page aligned.");
+ return H_PARAMETER;
+ }
+
+ return ehca_plpar_hcall_norets(H_ERROR_DATA,
+ adapter_handle.handle,
+ ressource_handle,
+ r_cb,
+ 0, 0, 0, 0);
+}
diff --git a/drivers/infiniband/hw/ehca/hcp_if.h b/drivers/infiniband/hw/ehca/hcp_if.h
new file mode 100644
index 00000000000..587ebd47095
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hcp_if.h
@@ -0,0 +1,261 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Firmware Infiniband Interface code for POWER
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Gerd Bayer <gerd.bayer@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HCP_IF_H__
+#define __HCP_IF_H__
+
+#include "ehca_classes.h"
+#include "ehca_tools.h"
+#include "hipz_hw.h"
+
+/*
+ * hipz_h_alloc_resource_eq allocates EQ resources in HW and FW, initalize
+ * resources, create the empty EQPT (ring).
+ */
+u64 hipz_h_alloc_resource_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_pfeq *pfeq,
+ const u32 neq_control,
+ const u32 number_of_entries,
+ struct ipz_eq_handle *eq_handle,
+ u32 * act_nr_of_entries,
+ u32 * act_pages,
+ u32 * eq_ist);
+
+u64 hipz_h_reset_event(const struct ipz_adapter_handle adapter_handle,
+ struct ipz_eq_handle eq_handle,
+ const u64 event_mask);
+/*
+ * hipz_h_allocate_resource_cq allocates CQ resources in HW and FW, initialize
+ * resources, create the empty CQPT (ring).
+ */
+u64 hipz_h_alloc_resource_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ struct ehca_alloc_cq_parms *param);
+
+
+/*
+ * hipz_h_alloc_resource_qp allocates QP resources in HW and FW,
+ * initialize resources, create empty QPPTs (2 rings).
+ */
+u64 hipz_h_alloc_resource_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp,
+ struct ehca_alloc_qp_parms *parms);
+
+u64 hipz_h_query_port(const struct ipz_adapter_handle adapter_handle,
+ const u8 port_id,
+ struct hipz_query_port *query_port_response_block);
+
+u64 hipz_h_query_hca(const struct ipz_adapter_handle adapter_handle,
+ struct hipz_query_hca *query_hca_rblock);
+
+/*
+ * hipz_h_register_rpage internal function in hcp_if.h for all
+ * hcp_H_REGISTER_RPAGE calls.
+ */
+u64 hipz_h_register_rpage(const struct ipz_adapter_handle adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 logical_address_of_page,
+ u64 count);
+
+u64 hipz_h_register_rpage_eq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_eq_handle eq_handle,
+ struct ehca_pfeq *pfeq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count);
+
+u64 hipz_h_query_int_state(const struct ipz_adapter_handle
+ hcp_adapter_handle,
+ u32 ist);
+
+u64 hipz_h_register_rpage_cq(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_cq_handle cq_handle,
+ struct ehca_pfcq *pfcq,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa gal);
+
+u64 hipz_h_register_rpage_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count,
+ const struct h_galpa galpa);
+
+u64 hipz_h_disable_and_get_wqe(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ void **log_addr_next_sq_wqe_tb_processed,
+ void **log_addr_next_rq_wqe_tb_processed,
+ int dis_and_get_function_code);
+enum hcall_sigt {
+ HCALL_SIGT_NO_CQE = 0,
+ HCALL_SIGT_BY_WQE = 1,
+ HCALL_SIGT_EVERY = 2
+};
+
+u64 hipz_h_modify_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ const u64 update_mask,
+ struct hcp_modify_qp_control_block *mqpcb,
+ struct h_galpa gal);
+
+u64 hipz_h_query_qp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct ehca_pfqp *pfqp,
+ struct hcp_modify_qp_control_block *qqpcb,
+ struct h_galpa gal);
+
+u64 hipz_h_destroy_qp(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_qp *qp);
+
+u64 hipz_h_define_aqp0(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port);
+
+u64 hipz_h_define_aqp1(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u32 port, u32 * pma_qp_nr,
+ u32 * bma_qp_nr);
+
+u64 hipz_h_attach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id);
+
+u64 hipz_h_detach_mcqp(const struct ipz_adapter_handle adapter_handle,
+ const struct ipz_qp_handle qp_handle,
+ struct h_galpa gal,
+ u16 mcg_dlid,
+ u64 subnet_prefix, u64 interface_id);
+
+u64 hipz_h_destroy_cq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_cq *cq,
+ u8 force_flag);
+
+u64 hipz_h_destroy_eq(const struct ipz_adapter_handle adapter_handle,
+ struct ehca_eq *eq);
+
+/*
+ * hipz_h_alloc_resource_mr allocates MR resources in HW and FW, initialize
+ * resources.
+ */
+u64 hipz_h_alloc_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/* hipz_h_register_rpage_mr registers MR resource pages in HW and FW */
+u64 hipz_h_register_rpage_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 logical_address_of_page,
+ const u64 count);
+
+/* hipz_h_query_mr queries MR in HW and FW */
+u64 hipz_h_query_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/* hipz_h_free_resource_mr frees MR resources in HW and FW */
+u64 hipz_h_free_resource_mr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr);
+
+/* hipz_h_reregister_pmr reregisters MR in HW and FW */
+u64 hipz_h_reregister_pmr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const u64 vaddr_in,
+ const u64 length,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ const u64 mr_addr_cb,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/* hipz_h_register_smr register shared MR in HW and FW */
+u64 hipz_h_register_smr(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mr *mr,
+ const struct ehca_mr *orig_mr,
+ const u64 vaddr_in,
+ const u32 access_ctrl,
+ const struct ipz_pd pd,
+ struct ehca_mr_hipzout_parms *outparms);
+
+/*
+ * hipz_h_alloc_resource_mw allocates MW resources in HW and FW, initialize
+ * resources.
+ */
+u64 hipz_h_alloc_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ const struct ipz_pd pd,
+ struct ehca_mw_hipzout_parms *outparms);
+
+/* hipz_h_query_mw queries MW in HW and FW */
+u64 hipz_h_query_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw,
+ struct ehca_mw_hipzout_parms *outparms);
+
+/* hipz_h_free_resource_mw frees MW resources in HW and FW */
+u64 hipz_h_free_resource_mw(const struct ipz_adapter_handle adapter_handle,
+ const struct ehca_mw *mw);
+
+u64 hipz_h_error_data(const struct ipz_adapter_handle adapter_handle,
+ const u64 ressource_handle,
+ void *rblock,
+ unsigned long *byte_count);
+
+#endif /* __HCP_IF_H__ */
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.c b/drivers/infiniband/hw/ehca/hcp_phyp.c
new file mode 100644
index 00000000000..0b1a4772c78
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.c
@@ -0,0 +1,80 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * load store abstraction for ehca register access with tracing
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ehca_classes.h"
+#include "hipz_hw.h"
+
+int hcall_map_page(u64 physaddr, u64 *mapaddr)
+{
+ *mapaddr = (u64)(ioremap(physaddr, EHCA_PAGESIZE));
+ return 0;
+}
+
+int hcall_unmap_page(u64 mapaddr)
+{
+ iounmap((volatile void __iomem*)mapaddr);
+ return 0;
+}
+
+int hcp_galpas_ctor(struct h_galpas *galpas,
+ u64 paddr_kernel, u64 paddr_user)
+{
+ int ret = hcall_map_page(paddr_kernel, &galpas->kernel.fw_handle);
+ if (ret)
+ return ret;
+
+ galpas->user.fw_handle = paddr_user;
+
+ return 0;
+}
+
+int hcp_galpas_dtor(struct h_galpas *galpas)
+{
+ if (galpas->kernel.fw_handle) {
+ int ret = hcall_unmap_page(galpas->kernel.fw_handle);
+ if (ret)
+ return ret;
+ }
+
+ galpas->user.fw_handle = galpas->kernel.fw_handle = 0;
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/ehca/hcp_phyp.h b/drivers/infiniband/hw/ehca/hcp_phyp.h
new file mode 100644
index 00000000000..5305c2a3ed9
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hcp_phyp.h
@@ -0,0 +1,90 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * Firmware calls
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Waleri Fomin <fomin@de.ibm.com>
+ * Gerd Bayer <gerd.bayer@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HCP_PHYP_H__
+#define __HCP_PHYP_H__
+
+
+/*
+ * eHCA page (mapped into memory)
+ * resource to access eHCA register pages in CPU address space
+*/
+struct h_galpa {
+ u64 fw_handle;
+ /* for pSeries this is a 64bit memory address where
+ I/O memory is mapped into CPU address space (kv) */
+};
+
+/*
+ * resource to access eHCA address space registers, all types
+ */
+struct h_galpas {
+ u32 pid; /*PID of userspace galpa checking */
+ struct h_galpa user; /* user space accessible resource,
+ set to 0 if unused */
+ struct h_galpa kernel; /* kernel space accessible resource,
+ set to 0 if unused */
+};
+
+static inline u64 hipz_galpa_load(struct h_galpa galpa, u32 offset)
+{
+ u64 addr = galpa.fw_handle + offset;
+ return *(volatile u64 __force *)addr;
+}
+
+static inline void hipz_galpa_store(struct h_galpa galpa, u32 offset, u64 value)
+{
+ u64 addr = galpa.fw_handle + offset;
+ *(volatile u64 __force *)addr = value;
+}
+
+int hcp_galpas_ctor(struct h_galpas *galpas,
+ u64 paddr_kernel, u64 paddr_user);
+
+int hcp_galpas_dtor(struct h_galpas *galpas);
+
+int hcall_map_page(u64 physaddr, u64 * mapaddr);
+
+int hcall_unmap_page(u64 mapaddr);
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/hipz_fns.h b/drivers/infiniband/hw/ehca/hipz_fns.h
new file mode 100644
index 00000000000..9dac93d0214
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hipz_fns.h
@@ -0,0 +1,68 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HW abstraction register functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HIPZ_FNS_H__
+#define __HIPZ_FNS_H__
+
+#include "ehca_classes.h"
+#include "hipz_hw.h"
+
+#include "hipz_fns_core.h"
+
+#define hipz_galpa_store_eq(gal, offset, value) \
+ hipz_galpa_store(gal, EQTEMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_eq(gal, offset) \
+ hipz_galpa_load(gal, EQTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_qped(gal, offset, value) \
+ hipz_galpa_store(gal, QPEDMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_qped(gal, offset) \
+ hipz_galpa_load(gal, QPEDMM_OFFSET(offset))
+
+#define hipz_galpa_store_mrmw(gal, offset, value) \
+ hipz_galpa_store(gal, MRMWMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_mrmw(gal, offset) \
+ hipz_galpa_load(gal, MRMWMM_OFFSET(offset))
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/hipz_fns_core.h b/drivers/infiniband/hw/ehca/hipz_fns_core.h
new file mode 100644
index 00000000000..20898a15344
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hipz_fns_core.h
@@ -0,0 +1,100 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * HW abstraction register functions
+ *
+ * Authors: Christoph Raisch <raisch@de.ibm.com>
+ * Heiko J Schick <schickhj@de.ibm.com>
+ * Hoang-Nam Nguyen <hnguyen@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HIPZ_FNS_CORE_H__
+#define __HIPZ_FNS_CORE_H__
+
+#include "hcp_phyp.h"
+#include "hipz_hw.h"
+
+#define hipz_galpa_store_cq(gal, offset, value) \
+ hipz_galpa_store(gal, CQTEMM_OFFSET(offset), value)
+
+#define hipz_galpa_load_cq(gal, offset) \
+ hipz_galpa_load(gal, CQTEMM_OFFSET(offset))
+
+#define hipz_galpa_store_qp(gal,offset, value) \
+ hipz_galpa_store(gal, QPTEMM_OFFSET(offset), value)
+#define hipz_galpa_load_qp(gal, offset) \
+ hipz_galpa_load(gal,QPTEMM_OFFSET(offset))
+
+static inline void hipz_update_sqa(struct ehca_qp *qp, u16 nr_wqes)
+{
+ /* ringing doorbell :-) */
+ hipz_galpa_store_qp(qp->galpas.kernel, qpx_sqa,
+ EHCA_BMASK_SET(QPX_SQADDER, nr_wqes));
+}
+
+static inline void hipz_update_rqa(struct ehca_qp *qp, u16 nr_wqes)
+{
+ /* ringing doorbell :-) */
+ hipz_galpa_store_qp(qp->galpas.kernel, qpx_rqa,
+ EHCA_BMASK_SET(QPX_RQADDER, nr_wqes));
+}
+
+static inline void hipz_update_feca(struct ehca_cq *cq, u32 nr_cqes)
+{
+ hipz_galpa_store_cq(cq->galpas.kernel, cqx_feca,
+ EHCA_BMASK_SET(CQX_FECADDER, nr_cqes));
+}
+
+static inline void hipz_set_cqx_n0(struct ehca_cq *cq, u32 value)
+{
+ u64 cqx_n0_reg;
+
+ hipz_galpa_store_cq(cq->galpas.kernel, cqx_n0,
+ EHCA_BMASK_SET(CQX_N0_GENERATE_SOLICITED_COMP_EVENT,
+ value));
+ cqx_n0_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n0);
+}
+
+static inline void hipz_set_cqx_n1(struct ehca_cq *cq, u32 value)
+{
+ u64 cqx_n1_reg;
+
+ hipz_galpa_store_cq(cq->galpas.kernel, cqx_n1,
+ EHCA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, value));
+ cqx_n1_reg = hipz_galpa_load_cq(cq->galpas.kernel, cqx_n1);
+}
+
+#endif /* __HIPZ_FNC_CORE_H__ */
diff --git a/drivers/infiniband/hw/ehca/hipz_hw.h b/drivers/infiniband/hw/ehca/hipz_hw.h
new file mode 100644
index 00000000000..3fc92b031c5
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/hipz_hw.h
@@ -0,0 +1,388 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * eHCA register definitions
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HIPZ_HW_H__
+#define __HIPZ_HW_H__
+
+#include "ehca_tools.h"
+
+/* QP Table Entry Memory Map */
+struct hipz_qptemm {
+ u64 qpx_hcr;
+ u64 qpx_c;
+ u64 qpx_herr;
+ u64 qpx_aer;
+/* 0x20*/
+ u64 qpx_sqa;
+ u64 qpx_sqc;
+ u64 qpx_rqa;
+ u64 qpx_rqc;
+/* 0x40*/
+ u64 qpx_st;
+ u64 qpx_pmstate;
+ u64 qpx_pmfa;
+ u64 qpx_pkey;
+/* 0x60*/
+ u64 qpx_pkeya;
+ u64 qpx_pkeyb;
+ u64 qpx_pkeyc;
+ u64 qpx_pkeyd;
+/* 0x80*/
+ u64 qpx_qkey;
+ u64 qpx_dqp;
+ u64 qpx_dlidp;
+ u64 qpx_portp;
+/* 0xa0*/
+ u64 qpx_slidp;
+ u64 qpx_slidpp;
+ u64 qpx_dlida;
+ u64 qpx_porta;
+/* 0xc0*/
+ u64 qpx_slida;
+ u64 qpx_slidpa;
+ u64 qpx_slvl;
+ u64 qpx_ipd;
+/* 0xe0*/
+ u64 qpx_mtu;
+ u64 qpx_lato;
+ u64 qpx_rlimit;
+ u64 qpx_rnrlimit;
+/* 0x100*/
+ u64 qpx_t;
+ u64 qpx_sqhp;
+ u64 qpx_sqptp;
+ u64 qpx_nspsn;
+/* 0x120*/
+ u64 qpx_nspsnhwm;
+ u64 reserved1;
+ u64 qpx_sdsi;
+ u64 qpx_sdsbc;
+/* 0x140*/
+ u64 qpx_sqwsize;
+ u64 qpx_sqwts;
+ u64 qpx_lsn;
+ u64 qpx_nssn;
+/* 0x160 */
+ u64 qpx_mor;
+ u64 qpx_cor;
+ u64 qpx_sqsize;
+ u64 qpx_erc;
+/* 0x180*/
+ u64 qpx_rnrrc;
+ u64 qpx_ernrwt;
+ u64 qpx_rnrresp;
+ u64 qpx_lmsna;
+/* 0x1a0 */
+ u64 qpx_sqhpc;
+ u64 qpx_sqcptp;
+ u64 qpx_sigt;
+ u64 qpx_wqecnt;
+/* 0x1c0*/
+ u64 qpx_rqhp;
+ u64 qpx_rqptp;
+ u64 qpx_rqsize;
+ u64 qpx_nrr;
+/* 0x1e0*/
+ u64 qpx_rdmac;
+ u64 qpx_nrpsn;
+ u64 qpx_lapsn;
+ u64 qpx_lcr;
+/* 0x200*/
+ u64 qpx_rwc;
+ u64 qpx_rwva;
+ u64 qpx_rdsi;
+ u64 qpx_rdsbc;
+/* 0x220*/
+ u64 qpx_rqwsize;
+ u64 qpx_crmsn;
+ u64 qpx_rdd;
+ u64 qpx_larpsn;
+/* 0x240*/
+ u64 qpx_pd;
+ u64 qpx_scqn;
+ u64 qpx_rcqn;
+ u64 qpx_aeqn;
+/* 0x260*/
+ u64 qpx_aaelog;
+ u64 qpx_ram;
+ u64 qpx_rdmaqe0;
+ u64 qpx_rdmaqe1;
+/* 0x280*/
+ u64 qpx_rdmaqe2;
+ u64 qpx_rdmaqe3;
+ u64 qpx_nrpsnhwm;
+/* 0x298*/
+ u64 reserved[(0x400 - 0x298) / 8];
+/* 0x400 extended data */
+ u64 reserved_ext[(0x500 - 0x400) / 8];
+/* 0x500 */
+ u64 reserved2[(0x1000 - 0x500) / 8];
+/* 0x1000 */
+};
+
+#define QPX_SQADDER EHCA_BMASK_IBM(48,63)
+#define QPX_RQADDER EHCA_BMASK_IBM(48,63)
+
+#define QPTEMM_OFFSET(x) offsetof(struct hipz_qptemm,x)
+
+/* MRMWPT Entry Memory Map */
+struct hipz_mrmwmm {
+ /* 0x00 */
+ u64 mrx_hcr;
+
+ u64 mrx_c;
+ u64 mrx_herr;
+ u64 mrx_aer;
+ /* 0x20 */
+ u64 mrx_pp;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ /* 0x40 */
+ u64 reserved4[(0x200 - 0x40) / 8];
+ /* 0x200 */
+ u64 mrx_ctl[64];
+
+};
+
+#define MRMWMM_OFFSET(x) offsetof(struct hipz_mrmwmm,x)
+
+struct hipz_qpedmm {
+ /* 0x00 */
+ u64 reserved0[(0x400) / 8];
+ /* 0x400 */
+ u64 qpedx_phh;
+ u64 qpedx_ppsgp;
+ /* 0x410 */
+ u64 qpedx_ppsgu;
+ u64 qpedx_ppdgp;
+ /* 0x420 */
+ u64 qpedx_ppdgu;
+ u64 qpedx_aph;
+ /* 0x430 */
+ u64 qpedx_apsgp;
+ u64 qpedx_apsgu;
+ /* 0x440 */
+ u64 qpedx_apdgp;
+ u64 qpedx_apdgu;
+ /* 0x450 */
+ u64 qpedx_apav;
+ u64 qpedx_apsav;
+ /* 0x460 */
+ u64 qpedx_hcr;
+ u64 reserved1[4];
+ /* 0x488 */
+ u64 qpedx_rrl0;
+ /* 0x490 */
+ u64 qpedx_rrrkey0;
+ u64 qpedx_rrva0;
+ /* 0x4a0 */
+ u64 reserved2;
+ u64 qpedx_rrl1;
+ /* 0x4b0 */
+ u64 qpedx_rrrkey1;
+ u64 qpedx_rrva1;
+ /* 0x4c0 */
+ u64 reserved3;
+ u64 qpedx_rrl2;
+ /* 0x4d0 */
+ u64 qpedx_rrrkey2;
+ u64 qpedx_rrva2;
+ /* 0x4e0 */
+ u64 reserved4;
+ u64 qpedx_rrl3;
+ /* 0x4f0 */
+ u64 qpedx_rrrkey3;
+ u64 qpedx_rrva3;
+};
+
+#define QPEDMM_OFFSET(x) offsetof(struct hipz_qpedmm,x)
+
+/* CQ Table Entry Memory Map */
+struct hipz_cqtemm {
+ u64 cqx_hcr;
+ u64 cqx_c;
+ u64 cqx_herr;
+ u64 cqx_aer;
+/* 0x20 */
+ u64 cqx_ptp;
+ u64 cqx_tp;
+ u64 cqx_fec;
+ u64 cqx_feca;
+/* 0x40 */
+ u64 cqx_ep;
+ u64 cqx_eq;
+/* 0x50 */
+ u64 reserved1;
+ u64 cqx_n0;
+/* 0x60 */
+ u64 cqx_n1;
+ u64 reserved2[(0x1000 - 0x60) / 8];
+/* 0x1000 */
+};
+
+#define CQX_FEC_CQE_CNT EHCA_BMASK_IBM(32,63)
+#define CQX_FECADDER EHCA_BMASK_IBM(32,63)
+#define CQX_N0_GENERATE_SOLICITED_COMP_EVENT EHCA_BMASK_IBM(0,0)
+#define CQX_N1_GENERATE_COMP_EVENT EHCA_BMASK_IBM(0,0)
+
+#define CQTEMM_OFFSET(x) offsetof(struct hipz_cqtemm,x)
+
+/* EQ Table Entry Memory Map */
+struct hipz_eqtemm {
+ u64 eqx_hcr;
+ u64 eqx_c;
+
+ u64 eqx_herr;
+ u64 eqx_aer;
+/* 0x20 */
+ u64 eqx_ptp;
+ u64 eqx_tp;
+ u64 eqx_ssba;
+ u64 eqx_psba;
+
+/* 0x40 */
+ u64 eqx_cec;
+ u64 eqx_meql;
+ u64 eqx_xisbi;
+ u64 eqx_xisc;
+/* 0x60 */
+ u64 eqx_it;
+
+};
+
+#define EQTEMM_OFFSET(x) offsetof(struct hipz_eqtemm,x)
+
+/* access control defines for MR/MW */
+#define HIPZ_ACCESSCTRL_L_WRITE 0x00800000
+#define HIPZ_ACCESSCTRL_R_WRITE 0x00400000
+#define HIPZ_ACCESSCTRL_R_READ 0x00200000
+#define HIPZ_ACCESSCTRL_R_ATOMIC 0x00100000
+#define HIPZ_ACCESSCTRL_MW_BIND 0x00080000
+
+/* query hca response block */
+struct hipz_query_hca {
+ u32 cur_reliable_dg;
+ u32 cur_qp;
+ u32 cur_cq;
+ u32 cur_eq;
+ u32 cur_mr;
+ u32 cur_mw;
+ u32 cur_ee_context;
+ u32 cur_mcast_grp;
+ u32 cur_qp_attached_mcast_grp;
+ u32 reserved1;
+ u32 cur_ipv6_qp;
+ u32 cur_eth_qp;
+ u32 cur_hp_mr;
+ u32 reserved2[3];
+ u32 max_rd_domain;
+ u32 max_qp;
+ u32 max_cq;
+ u32 max_eq;
+ u32 max_mr;
+ u32 max_hp_mr;
+ u32 max_mw;
+ u32 max_mrwpte;
+ u32 max_special_mrwpte;
+ u32 max_rd_ee_context;
+ u32 max_mcast_grp;
+ u32 max_total_mcast_qp_attach;
+ u32 max_mcast_qp_attach;
+ u32 max_raw_ipv6_qp;
+ u32 max_raw_ethy_qp;
+ u32 internal_clock_frequency;
+ u32 max_pd;
+ u32 max_ah;
+ u32 max_cqe;
+ u32 max_wqes_wq;
+ u32 max_partitions;
+ u32 max_rr_ee_context;
+ u32 max_rr_qp;
+ u32 max_rr_hca;
+ u32 max_act_wqs_ee_context;
+ u32 max_act_wqs_qp;
+ u32 max_sge;
+ u32 max_sge_rd;
+ u32 memory_page_size_supported;
+ u64 max_mr_size;
+ u32 local_ca_ack_delay;
+ u32 num_ports;
+ u32 vendor_id;
+ u32 vendor_part_id;
+ u32 hw_ver;
+ u64 node_guid;
+ u64 hca_cap_indicators;
+ u32 data_counter_register_size;
+ u32 max_shared_rq;
+ u32 max_isns_eq;
+ u32 max_neq;
+} __attribute__ ((packed));
+
+/* query port response block */
+struct hipz_query_port {
+ u32 state;
+ u32 bad_pkey_cntr;
+ u32 lmc;
+ u32 lid;
+ u32 subnet_timeout;
+ u32 qkey_viol_cntr;
+ u32 sm_sl;
+ u32 sm_lid;
+ u32 capability_mask;
+ u32 init_type_reply;
+ u32 pkey_tbl_len;
+ u32 gid_tbl_len;
+ u64 gid_prefix;
+ u32 port_nr;
+ u16 pkey_entries[16];
+ u8 reserved1[32];
+ u32 trent_size;
+ u32 trbuf_size;
+ u64 max_msg_sz;
+ u32 max_mtu;
+ u32 vl_cap;
+ u8 reserved2[1900];
+ u64 guid_entries[255];
+} __attribute__ ((packed));
+
+#endif
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.c b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
new file mode 100644
index 00000000000..e028ff1588c
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.c
@@ -0,0 +1,149 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * internal queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ehca_tools.h"
+#include "ipz_pt_fn.h"
+
+void *ipz_qpageit_get_inc(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->pagesize;
+ if (queue->current_q_offset > queue->queue_length) {
+ queue->current_q_offset -= queue->pagesize;
+ ret = NULL;
+ }
+ if (((u64)ret) % EHCA_PAGESIZE) {
+ ehca_gen_err("ERROR!! not at PAGE-Boundary");
+ return NULL;
+ }
+ return ret;
+}
+
+void *ipz_qeit_eq_get_inc(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
+
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset > last_entry_in_q) {
+ queue->current_q_offset = 0;
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+
+ return ret;
+}
+
+int ipz_queue_ctor(struct ipz_queue *queue,
+ const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size, const u32 nr_of_sg)
+{
+ int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
+ int f;
+
+ if (pagesize > PAGE_SIZE) {
+ ehca_gen_err("FATAL ERROR: pagesize=%x is greater "
+ "than kernel page size", pagesize);
+ return 0;
+ }
+ if (!pages_per_kpage) {
+ ehca_gen_err("FATAL ERROR: invalid kernel page size. "
+ "pages_per_kpage=%x", pages_per_kpage);
+ return 0;
+ }
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->queue_pages = vmalloc(nr_of_pages * sizeof(void *));
+ if (!queue->queue_pages) {
+ ehca_gen_err("ERROR!! didn't get the memory");
+ return 0;
+ }
+ memset(queue->queue_pages, 0, nr_of_pages * sizeof(void *));
+ /*
+ * allocate pages for queue:
+ * outer loop allocates whole kernel pages (page aligned) and
+ * inner loop divides a kernel page into smaller hca queue pages
+ */
+ f = 0;
+ while (f < nr_of_pages) {
+ u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+ int k;
+ if (!kpage)
+ goto ipz_queue_ctor_exit0; /*NOMEM*/
+ for (k = 0; k < pages_per_kpage && f < nr_of_pages; k++) {
+ (queue->queue_pages)[f] = (struct ipz_page *)kpage;
+ kpage += EHCA_PAGESIZE;
+ f++;
+ }
+ }
+
+ queue->current_q_offset = 0;
+ queue->qe_size = qe_size;
+ queue->act_nr_of_sg = nr_of_sg;
+ queue->pagesize = pagesize;
+ queue->toggle_state = 1;
+ return 1;
+
+ ipz_queue_ctor_exit0:
+ ehca_gen_err("Couldn't get alloc pages queue=%p f=%x nr_of_pages=%x",
+ queue, f, nr_of_pages);
+ for (f = 0; f < nr_of_pages; f += pages_per_kpage) {
+ if (!(queue->queue_pages)[f])
+ break;
+ free_page((unsigned long)(queue->queue_pages)[f]);
+ }
+ return 0;
+}
+
+int ipz_queue_dtor(struct ipz_queue *queue)
+{
+ int pages_per_kpage = PAGE_SIZE >> EHCA_PAGESHIFT;
+ int g;
+ int nr_pages;
+
+ if (!queue || !queue->queue_pages) {
+ ehca_gen_dbg("queue or queue_pages is NULL");
+ return 0;
+ }
+ nr_pages = queue->queue_length / queue->pagesize;
+ for (g = 0; g < nr_pages; g += pages_per_kpage)
+ free_page((unsigned long)(queue->queue_pages)[g]);
+ vfree(queue->queue_pages);
+
+ return 1;
+}
diff --git a/drivers/infiniband/hw/ehca/ipz_pt_fn.h b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
new file mode 100644
index 00000000000..2f13509d525
--- /dev/null
+++ b/drivers/infiniband/hw/ehca/ipz_pt_fn.h
@@ -0,0 +1,247 @@
+/*
+ * IBM eServer eHCA Infiniband device driver for Linux on POWER
+ *
+ * internal queue handling
+ *
+ * Authors: Waleri Fomin <fomin@de.ibm.com>
+ * Reinhard Ernst <rernst@de.ibm.com>
+ * Christoph Raisch <raisch@de.ibm.com>
+ *
+ * Copyright (c) 2005 IBM Corporation
+ *
+ * All rights reserved.
+ *
+ * This source code is distributed under a dual license of GPL v2.0 and OpenIB
+ * BSD.
+ *
+ * OpenIB BSD License
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __IPZ_PT_FN_H__
+#define __IPZ_PT_FN_H__
+
+#define EHCA_PAGESHIFT 12
+#define EHCA_PAGESIZE 4096UL
+#define EHCA_PAGEMASK (~(EHCA_PAGESIZE-1))
+#define EHCA_PT_ENTRIES 512UL
+
+#include "ehca_tools.h"
+#include "ehca_qes.h"
+
+/* struct generic ehca page */
+struct ipz_page {
+ u8 entries[EHCA_PAGESIZE];
+};
+
+/* struct generic queue in linux kernel virtual memory (kv) */
+struct ipz_queue {
+ u64 current_q_offset; /* current queue entry */
+
+ struct ipz_page **queue_pages; /* array of pages belonging to queue */
+ u32 qe_size; /* queue entry size */
+ u32 act_nr_of_sg;
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state; /* toggle flag - per page */
+ u32 dummy3; /* 64 bit alignment */
+};
+
+/*
+ * return current Queue Entry for a certain q_offset
+ * returns address (kv) of Queue Entry
+ */
+static inline void *ipz_qeit_calc(struct ipz_queue *queue, u64 q_offset)
+{
+ struct ipz_page *current_page;
+ if (q_offset >= queue->queue_length)
+ return NULL;
+ current_page = (queue->queue_pages)[q_offset >> EHCA_PAGESHIFT];
+ return &current_page->entries[q_offset & (EHCA_PAGESIZE - 1)];
+}
+
+/*
+ * return current Queue Entry
+ * returns address (kv) of Queue Entry
+ */
+static inline void *ipz_qeit_get(struct ipz_queue *queue)
+{
+ return ipz_qeit_calc(queue, queue->current_q_offset);
+}
+
+/*
+ * return current Queue Page , increment Queue Page iterator from
+ * page to page in struct ipz_queue, last increment will return 0! and
+ * NOT wrap
+ * returns address (kv) of Queue Page
+ * warning don't use in parallel with ipz_QE_get_inc()
+ */
+void *ipz_qpageit_get_inc(struct ipz_queue *queue);
+
+/*
+ * return current Queue Entry, increment Queue Entry iterator by one
+ * step in struct ipz_queue, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * warning don't use in parallel with ipz_qpageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ */
+static inline void *ipz_qeit_get_inc(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset >= queue->queue_length) {
+ queue->current_q_offset = 0;
+ /* toggle the valid flag */
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+
+ return ret;
+}
+
+/*
+ * return current Queue Entry, increment Queue Entry iterator by one
+ * step in struct ipz_queue, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * returns 0 and does not increment, if wrong valid state
+ * warning don't use in parallel with ipz_qpageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ */
+static inline void *ipz_qeit_get_inc_valid(struct ipz_queue *queue)
+{
+ struct ehca_cqe *cqe = ipz_qeit_get(queue);
+ u32 cqe_flags = cqe->cqe_flags;
+
+ if ((cqe_flags >> 7) != (queue->toggle_state & 1))
+ return NULL;
+
+ ipz_qeit_get_inc(queue);
+ return cqe;
+}
+
+/*
+ * returns and resets Queue Entry iterator
+ * returns address (kv) of first Queue Entry
+ */
+static inline void *ipz_qeit_reset(struct ipz_queue *queue)
+{
+ queue->current_q_offset = 0;
+ return ipz_qeit_get(queue);
+}
+
+/* struct generic page table */
+struct ipz_pt {
+ u64 entries[EHCA_PT_ENTRIES];
+};
+
+/* struct page table for a queue, only to be used in pf */
+struct ipz_qpt {
+ /* queue page tables (kv), use u64 because we know the element length */
+ u64 *qpts;
+ u32 n_qpts;
+ u32 n_ptes; /* number of page table entries */
+ u64 *current_pte_addr;
+};
+
+/*
+ * constructor for a ipz_queue_t, placement new for ipz_queue_t,
+ * new for all dependent datastructors
+ * all QP Tables are the same
+ * flow:
+ * allocate+pin queue
+ * see ipz_qpt_ctor()
+ * returns true if ok, false if out of memory
+ */
+int ipz_queue_ctor(struct ipz_queue *queue, const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size,
+ const u32 nr_of_sg);
+
+/*
+ * destructor for a ipz_queue_t
+ * -# free queue
+ * see ipz_queue_ctor()
+ * returns true if ok, false if queue was NULL-ptr of free failed
+ */
+int ipz_queue_dtor(struct ipz_queue *queue);
+
+/*
+ * constructor for a ipz_qpt_t,
+ * placement new for struct ipz_queue, new for all dependent datastructors
+ * all QP Tables are the same,
+ * flow:
+ * -# allocate+pin queue
+ * -# initialise ptcb
+ * -# allocate+pin PTs
+ * -# link PTs to a ring, according to HCA Arch, set bit62 id needed
+ * -# the ring must have room for exactly nr_of_PTEs
+ * see ipz_qpt_ctor()
+ */
+void ipz_qpt_ctor(struct ipz_qpt *qpt,
+ const u32 nr_of_qes,
+ const u32 pagesize,
+ const u32 qe_size,
+ const u8 lowbyte, const u8 toggle,
+ u32 * act_nr_of_QEs, u32 * act_nr_of_pages);
+
+/*
+ * return current Queue Entry, increment Queue Entry iterator by one
+ * step in struct ipz_queue, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * warning don't use in parallel with ipz_qpageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ * fix EQ page problems
+ */
+void *ipz_qeit_eq_get_inc(struct ipz_queue *queue);
+
+/*
+ * return current Event Queue Entry, increment Queue Entry iterator
+ * by one step in struct ipz_queue if valid, will wrap in ringbuffer
+ * returns address (kv) of Queue Entry BEFORE increment
+ * returns 0 and does not increment, if wrong valid state
+ * warning don't use in parallel with ipz_queue_QPageit_get_inc()
+ * warning unpredictable results may occur if steps>act_nr_of_queue_entries
+ */
+static inline void *ipz_eqit_eq_get_inc_valid(struct ipz_queue *queue)
+{
+ void *ret = ipz_qeit_get(queue);
+ u32 qe = *(u8 *) ret;
+ if ((qe >> 7) != (queue->toggle_state & 1))
+ return NULL;
+ ipz_qeit_eq_get_inc(queue); /* this is a good one */
+ return ret;
+}
+
+/* returns address (GX) of first queue entry */
+static inline u64 ipz_qpt_get_firstpage(struct ipz_qpt *qpt)
+{
+ return be64_to_cpu(qpt->qpts[0]);
+}
+
+/* returns address (kv) of first page of queue page table */
+static inline void *ipz_qpt_get_qpt(struct ipz_qpt *qpt)
+{
+ return qpt->qpts;
+}
+
+#endif /* __IPZ_PT_FN_H__ */
diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/infiniband/hw/ipath/Kconfig
index 9ea67c409b6..574a678e7fd 100644
--- a/drivers/infiniband/hw/ipath/Kconfig
+++ b/drivers/infiniband/hw/ipath/Kconfig
@@ -1,16 +1,9 @@
-config IPATH_CORE
- tristate "PathScale InfiniPath Driver"
- depends on 64BIT && PCI_MSI && NET
- ---help---
- This is a low-level driver for PathScale InfiniPath host channel
- adapters (HCAs) based on the HT-400 and PE-800 chips.
-
config INFINIBAND_IPATH
- tristate "PathScale InfiniPath Verbs Driver"
- depends on IPATH_CORE && INFINIBAND
+ tristate "QLogic InfiniPath Driver"
+ depends on PCI_MSI && 64BIT && INFINIBAND
---help---
- This is a driver that provides InfiniBand verbs support for
- PathScale InfiniPath host channel adapters (HCAs). This
- allows these devices to be used with both kernel upper level
- protocols such as IP-over-InfiniBand as well as with userspace
- applications (in conjunction with InfiniBand userspace access).
+ This is a driver for QLogic InfiniPath host channel adapters,
+ including InfiniBand verbs support. This driver allows these
+ devices to be used with both kernel upper level protocols such
+ as IP-over-InfiniBand as well as with userspace applications
+ (in conjunction with InfiniBand userspace access).
diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/infiniband/hw/ipath/Makefile
index b4d084abfd2..5e29cb0095e 100644
--- a/drivers/infiniband/hw/ipath/Makefile
+++ b/drivers/infiniband/hw/ipath/Makefile
@@ -1,36 +1,35 @@
-EXTRA_CFLAGS += -DIPATH_IDSTR='"PathScale kernel.org driver"' \
+EXTRA_CFLAGS += -DIPATH_IDSTR='"QLogic kernel.org driver"' \
-DIPATH_KERN_TYPE=0
-obj-$(CONFIG_IPATH_CORE) += ipath_core.o
obj-$(CONFIG_INFINIBAND_IPATH) += ib_ipath.o
-ipath_core-y := \
+ib_ipath-y := \
+ ipath_cq.o \
ipath_diag.o \
ipath_driver.o \
ipath_eeprom.o \
ipath_file_ops.o \
ipath_fs.o \
- ipath_ht400.o \
+ ipath_iba6110.o \
+ ipath_iba6120.o \
ipath_init_chip.o \
ipath_intr.o \
- ipath_layer.o \
- ipath_pe800.o \
- ipath_stats.o \
- ipath_sysfs.o \
- ipath_user_pages.o
-
-ipath_core-$(CONFIG_X86_64) += ipath_wc_x86_64.o
-
-ib_ipath-y := \
- ipath_cq.o \
ipath_keys.o \
+ ipath_layer.o \
ipath_mad.o \
+ ipath_mmap.o \
ipath_mr.o \
ipath_qp.o \
ipath_rc.o \
ipath_ruc.o \
ipath_srq.o \
+ ipath_stats.o \
+ ipath_sysfs.o \
ipath_uc.o \
ipath_ud.o \
- ipath_verbs.o \
- ipath_verbs_mcast.o
+ ipath_user_pages.o \
+ ipath_verbs_mcast.o \
+ ipath_verbs.o
+
+ib_ipath-$(CONFIG_X86_64) += ipath_wc_x86_64.o
+ib_ipath-$(CONFIG_PPC64) += ipath_wc_ppc64.o
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index 48a55247b83..54139d39818 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -38,7 +39,8 @@
* to communicate between kernel and user code.
*/
-/* This is the IEEE-assigned OUI for PathScale, Inc. */
+
+/* This is the IEEE-assigned OUI for QLogic Inc. InfiniPath */
#define IPATH_SRC_OUI_1 0x00
#define IPATH_SRC_OUI_2 0x11
#define IPATH_SRC_OUI_3 0x75
@@ -96,17 +98,17 @@ struct infinipath_stats {
__u64 sps_hwerrs;
/* number of times IB link changed state unexpectedly */
__u64 sps_iblink;
- /* no longer used; left for compatibility */
- __u64 sps_unused3;
+ /* kernel receive interrupts that didn't read intstat */
+ __u64 sps_fastrcvint;
/* number of kernel (port0) packets received */
__u64 sps_port0pkts;
/* number of "ethernet" packets sent by driver */
__u64 sps_ether_spkts;
/* number of "ethernet" packets received by driver */
__u64 sps_ether_rpkts;
- /* number of SMA packets sent by driver */
+ /* number of SMA packets sent by driver. Obsolete. */
__u64 sps_sma_spkts;
- /* number of SMA packets received by driver */
+ /* number of SMA packets received by driver. Obsolete. */
__u64 sps_sma_rpkts;
/* number of times all ports rcvhdrq was full and packet dropped */
__u64 sps_hdrqfull;
@@ -121,8 +123,7 @@ struct infinipath_stats {
__u64 sps_ports;
/* list of pkeys (other than default) accepted (0 means not set) */
__u16 sps_pkeys[4];
- /* lids for up to 4 infinipaths, indexed by infinipath # */
- __u16 sps_lid[4];
+ __u16 sps_unused16[4]; /* available; maintaining compatible layout */
/* number of user ports per chip (not IB ports) */
__u32 sps_nports;
/* not our interrupt, or already handled */
@@ -137,11 +138,10 @@ struct infinipath_stats {
__u64 sps_pageunlocks;
/*
* Number of packets dropped in kernel other than errors (ether
- * packets if ipath not configured, sma/mad, etc.)
+ * packets if ipath not configured, etc.)
*/
__u64 sps_krdrops;
- /* mlids for up to 4 infinipaths, indexed by infinipath # */
- __u16 sps_mlid[4];
+ __u64 sps_txeparity; /* PIO buffer parity error, recovered */
/* pad for future growth */
__u64 __sps_pad[45];
};
@@ -154,8 +154,6 @@ struct infinipath_stats {
#define IPATH_STATUS_DISABLED 0x2 /* hardware disabled */
/* Device has been disabled via admin request */
#define IPATH_STATUS_ADMIN_DISABLED 0x4
-#define IPATH_STATUS_OIB_SMA 0x8 /* ipath_mad kernel SMA running */
-#define IPATH_STATUS_SMA 0x10 /* user SMA running */
/* Chip has been found and initted */
#define IPATH_STATUS_CHIP_PRESENT 0x20
/* IB link is at ACTIVE, usable for data traffic */
@@ -188,6 +186,9 @@ typedef enum _ipath_ureg {
#define IPATH_RUNTIME_PCIE 0x2
#define IPATH_RUNTIME_FORCE_WC_ORDER 0x4
#define IPATH_RUNTIME_RCVHDR_COPY 0x8
+#define IPATH_RUNTIME_MASTER 0x10
+#define IPATH_RUNTIME_PBC_REWRITE 0x20
+#define IPATH_RUNTIME_LOOSE_DMA_ALIGN 0x40
/*
* This structure is returned by ipath_userinit() immediately after
@@ -205,7 +206,8 @@ struct ipath_base_info {
/* version of software, for feature checking. */
__u32 spi_sw_version;
/* InfiniPath port assigned, goes into sent packets */
- __u32 spi_port;
+ __u16 spi_port;
+ __u16 spi_subport;
/*
* IB MTU, packets IB data must be less than this.
* The MTU is in bytes, and will be a multiple of 4 bytes.
@@ -221,7 +223,7 @@ struct ipath_base_info {
__u32 spi_tidcnt;
/* size of the TID Eager list in infinipath, in entries */
__u32 spi_tidegrcnt;
- /* size of a single receive header queue entry. */
+ /* size of a single receive header queue entry in words. */
__u32 spi_rcvhdrent_size;
/*
* Count of receive header queue entries allocated.
@@ -310,6 +312,15 @@ struct ipath_base_info {
__u32 spi_rcv_egrchunksize;
/* total size of mmap to cover full rcvegrbuffers */
__u32 spi_rcv_egrbuftotlen;
+ __u32 spi_filler_for_align;
+ /* address of readonly memory copy of the rcvhdrq tail register. */
+ __u64 spi_rcvhdr_tailaddr;
+
+ /* shared memory pages for subports if IPATH_RUNTIME_MASTER is set */
+ __u64 spi_subport_uregbase;
+ __u64 spi_subport_rcvegrbuf;
+ __u64 spi_subport_rcvhdr_base;
+
} __attribute__ ((aligned(8)));
@@ -328,12 +339,12 @@ struct ipath_base_info {
/*
* Minor version differences are always compatible
- * a within a major version, however if if user software is larger
+ * a within a major version, however if user software is larger
* than driver software, some new features and/or structure fields
* may not be implemented; the user code must deal with this if it
- * cares, or it must abort after initialization reports the difference
+ * cares, or it must abort after initialization reports the difference.
*/
-#define IPATH_USER_SWMINOR 2
+#define IPATH_USER_SWMINOR 3
#define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
@@ -342,9 +353,9 @@ struct ipath_base_info {
/*
* Similarly, this is the kernel version going back to the user. It's
* slightly different, in that we want to tell if the driver was built as
- * part of a PathScale release, or from the driver from OpenIB, kernel.org,
- * or a standard distribution, for support reasons. The high bit is 0 for
- * non-PathScale, and 1 for PathScale-built/supplied.
+ * part of a QLogic release, or from the driver from openfabrics.org,
+ * kernel.org, or a standard distribution, for support reasons.
+ * The high bit is 0 for non-QLogic and 1 for QLogic-built/supplied.
*
* It's returned by the driver to the user code during initialization in the
* spi_sw_version field of ipath_base_info, so the user code can in turn
@@ -380,12 +391,15 @@ struct ipath_user_info {
__u32 spu_rcvhdrsize;
/*
- * cache line aligned (64 byte) user address to
- * which the rcvhdrtail register will be written by infinipath
- * whenever it changes, so that no chip registers are read in
- * the performance path.
+ * If two or more processes wish to share a port, each process
+ * must set the spu_subport_cnt and spu_subport_id to the same
+ * values. The only restriction on the spu_subport_id is that
+ * it be unique for a given node.
*/
- __u64 spu_rcvhdraddr;
+ __u16 spu_subport_cnt;
+ __u16 spu_subport_id;
+
+ __u32 spu_unused; /* kept for compatible layout */
/*
* address of struct base_info to write to
@@ -398,19 +412,25 @@ struct ipath_user_info {
#define IPATH_CMD_MIN 16
-#define IPATH_CMD_USER_INIT 16 /* set up userspace */
+#define __IPATH_CMD_USER_INIT 16 /* old set up userspace (for old user code) */
#define IPATH_CMD_PORT_INFO 17 /* find out what resources we got */
#define IPATH_CMD_RECV_CTRL 18 /* control receipt of packets */
#define IPATH_CMD_TID_UPDATE 19 /* update expected TID entries */
#define IPATH_CMD_TID_FREE 20 /* free expected TID entries */
#define IPATH_CMD_SET_PART_KEY 21 /* add partition key */
+#define IPATH_CMD_SLAVE_INFO 22 /* return info on slave processes */
+#define IPATH_CMD_ASSIGN_PORT 23 /* allocate HCA and port */
+#define IPATH_CMD_USER_INIT 24 /* set up userspace */
-#define IPATH_CMD_MAX 21
+#define IPATH_CMD_MAX 24
struct ipath_port_info {
__u32 num_active; /* number of active units */
__u32 unit; /* unit (chip) assigned to caller */
- __u32 port; /* port on unit assigned to caller */
+ __u16 port; /* port on unit assigned to caller */
+ __u16 subport; /* subport on unit assigned to caller */
+ __u16 num_ports; /* number of ports available on unit */
+ __u16 num_subports; /* number of subport slaves opened on port */
};
struct ipath_tid_info {
@@ -441,6 +461,8 @@ struct ipath_cmd {
__u32 recv_ctrl;
/* partition key to set */
__u16 part_key;
+ /* user address of __u32 bitmask of active slaves */
+ __u64 slave_mask_addr;
} cmd;
};
@@ -469,19 +491,18 @@ struct __ipath_sendpkt {
struct ipath_iovec sps_iov[4];
};
-/* Passed into SMA special file's ->read and ->write methods. */
-struct ipath_sma_pkt
-{
- __u32 unit; /* unit on which to send packet */
- __u64 data; /* address of payload in userspace */
- __u32 len; /* length of payload */
+/* Passed into diag data special file's ->write method. */
+struct ipath_diag_pkt {
+ __u32 unit;
+ __u64 data;
+ __u32 len;
};
/*
* Data layout in I2C flash (for GUID, etc.)
* All fields are little-endian binary unless otherwise stated
*/
-#define IPATH_FLASH_VERSION 1
+#define IPATH_FLASH_VERSION 2
struct ipath_flash {
/* flash layout version (IPATH_FLASH_VERSION) */
__u8 if_fversion;
@@ -489,14 +510,14 @@ struct ipath_flash {
__u8 if_csum;
/*
* valid length (in use, protected by if_csum), including
- * if_fversion and if_sum themselves)
+ * if_fversion and if_csum themselves)
*/
__u8 if_length;
/* the GUID, in network order */
__u8 if_guid[8];
/* number of GUIDs to use, starting from if_guid */
__u8 if_numguid;
- /* the board serial number, in ASCII */
+ /* the (last 10 characters of) board serial number, in ASCII */
char if_serial[12];
/* board mfg date (YYYYMMDD ASCII) */
char if_mfgdate[8];
@@ -508,8 +529,10 @@ struct ipath_flash {
__u8 if_powerhour[2];
/* ASCII free-form comment field */
char if_comment[32];
- /* 78 bytes used, min flash size is 128 bytes */
- __u8 if_future[50];
+ /* Backwards compatible prefix for longer QLogic Serial Numbers */
+ char if_sprefix[4];
+ /* 82 bytes used, min flash size is 128 bytes */
+ __u8 if_future[46];
};
/*
@@ -601,16 +624,124 @@ struct infinipath_counters {
/* K_PktFlags bits */
#define INFINIPATH_KPF_INTR 0x1
+#define INFINIPATH_KPF_SUBPORT_MASK 0x3
+#define INFINIPATH_KPF_SUBPORT_SHIFT 1
+
+#define INFINIPATH_MAX_SUBPORT 4
/* SendPIO per-buffer control */
-#define INFINIPATH_SP_LENGTHP1_MASK 0x3FF
-#define INFINIPATH_SP_LENGTHP1_SHIFT 0
-#define INFINIPATH_SP_INTR 0x80000000
-#define INFINIPATH_SP_TEST 0x40000000
-#define INFINIPATH_SP_TESTEBP 0x20000000
+#define INFINIPATH_SP_TEST 0x40
+#define INFINIPATH_SP_TESTEBP 0x20
/* SendPIOAvail bits */
#define INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT 1
#define INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT 0
+/* infinipath header format */
+struct ipath_header {
+ /*
+ * Version - 4 bits, Port - 4 bits, TID - 10 bits and Offset -
+ * 14 bits before ECO change ~28 Dec 03. After that, Vers 4,
+ * Port 4, TID 11, offset 13.
+ */
+ __le32 ver_port_tid_offset;
+ __le16 chksum;
+ __le16 pkt_flags;
+};
+
+/* infinipath user message header format.
+ * This structure contains the first 4 fields common to all protocols
+ * that employ infinipath.
+ */
+struct ipath_message_header {
+ __be16 lrh[4];
+ __be32 bth[3];
+ /* fields below this point are in host byte order */
+ struct ipath_header iph;
+ __u8 sub_opcode;
+};
+
+/* infinipath ethernet header format */
+struct ether_header {
+ __be16 lrh[4];
+ __be32 bth[3];
+ struct ipath_header iph;
+ __u8 sub_opcode;
+ __u8 cmd;
+ __be16 lid;
+ __u16 mac[3];
+ __u8 frag_num;
+ __u8 seq_num;
+ __le32 len;
+ /* MUST be of word size due to PIO write requirements */
+ __le32 csum;
+ __le16 csum_offset;
+ __le16 flags;
+ __u16 first_2_bytes;
+ __u8 unused[2]; /* currently unused */
+};
+
+
+/* IB - LRH header consts */
+#define IPATH_LRH_GRH 0x0003 /* 1. word of IB LRH - next header: GRH */
+#define IPATH_LRH_BTH 0x0002 /* 1. word of IB LRH - next header: BTH */
+
+/* misc. */
+#define SIZE_OF_CRC 1
+
+#define IPATH_DEFAULT_P_KEY 0xFFFF
+#define IPATH_PERMISSIVE_LID 0xFFFF
+#define IPATH_AETH_CREDIT_SHIFT 24
+#define IPATH_AETH_CREDIT_MASK 0x1F
+#define IPATH_AETH_CREDIT_INVAL 0x1F
+#define IPATH_PSN_MASK 0xFFFFFF
+#define IPATH_MSN_MASK 0xFFFFFF
+#define IPATH_QPN_MASK 0xFFFFFF
+#define IPATH_MULTICAST_LID_BASE 0xC000
+#define IPATH_MULTICAST_QPN 0xFFFFFF
+
+/* Receive Header Queue: receive type (from infinipath) */
+#define RCVHQ_RCV_TYPE_EXPECTED 0
+#define RCVHQ_RCV_TYPE_EAGER 1
+#define RCVHQ_RCV_TYPE_NON_KD 2
+#define RCVHQ_RCV_TYPE_ERROR 3
+
+
+/* sub OpCodes - ith4x */
+#define IPATH_ITH4X_OPCODE_ENCAP 0x81
+#define IPATH_ITH4X_OPCODE_LID_ARP 0x82
+
+#define IPATH_HEADER_QUEUE_WORDS 9
+
+/* functions for extracting fields from rcvhdrq entries for the driver.
+ */
+static inline __u32 ipath_hdrget_err_flags(const __le32 * rbuf)
+{
+ return __le32_to_cpu(rbuf[1]);
+}
+
+static inline __u32 ipath_hdrget_rcv_type(const __le32 * rbuf)
+{
+ return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_RCVTYPE_SHIFT)
+ & INFINIPATH_RHF_RCVTYPE_MASK;
+}
+
+static inline __u32 ipath_hdrget_length_in_bytes(const __le32 * rbuf)
+{
+ return ((__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_LENGTH_SHIFT)
+ & INFINIPATH_RHF_LENGTH_MASK) << 2;
+}
+
+static inline __u32 ipath_hdrget_index(const __le32 * rbuf)
+{
+ return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_EGRINDEX_SHIFT)
+ & INFINIPATH_RHF_EGRINDEX_MASK;
+}
+
+static inline __u32 ipath_hdrget_ipath_ver(__le32 hdrword)
+{
+ return (__le32_to_cpu(hdrword) >> INFINIPATH_I_VERS_SHIFT)
+ & INFINIPATH_I_VERS_MASK;
+}
+
#endif /* _IPATH_COMMON_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index 7ece1135ddf..87462e0cb4d 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -41,20 +42,29 @@
* @entry: work completion entry to add
* @sig: true if @entry is a solicitated entry
*
- * This may be called with one of the qp->s_lock or qp->r_rq.lock held.
+ * This may be called with qp->s_lock held.
*/
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
{
+ struct ipath_cq_wc *wc;
unsigned long flags;
+ u32 head;
u32 next;
spin_lock_irqsave(&cq->lock, flags);
- if (cq->head == cq->ibcq.cqe)
+ /*
+ * Note that the head pointer might be writable by user processes.
+ * Take care to verify it is a sane value.
+ */
+ wc = cq->queue;
+ head = wc->head;
+ if (head >= (unsigned) cq->ibcq.cqe) {
+ head = cq->ibcq.cqe;
next = 0;
- else
- next = cq->head + 1;
- if (unlikely(next == cq->tail)) {
+ } else
+ next = head + 1;
+ if (unlikely(next == wc->tail)) {
spin_unlock_irqrestore(&cq->lock, flags);
if (cq->ibcq.event_handler) {
struct ib_event ev;
@@ -66,8 +76,8 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
}
return;
}
- cq->queue[cq->head] = *entry;
- cq->head = next;
+ wc->queue[head] = *entry;
+ wc->head = next;
if (cq->notify == IB_CQ_NEXT_COMP ||
(cq->notify == IB_CQ_SOLICITED && solicited)) {
@@ -100,20 +110,27 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
{
struct ipath_cq *cq = to_icq(ibcq);
+ struct ipath_cq_wc *wc;
unsigned long flags;
int npolled;
+ u32 tail;
spin_lock_irqsave(&cq->lock, flags);
+ wc = cq->queue;
+ tail = wc->tail;
+ if (tail > (u32) cq->ibcq.cqe)
+ tail = (u32) cq->ibcq.cqe;
for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
- if (cq->tail == cq->head)
+ if (tail == wc->head)
break;
- *entry = cq->queue[cq->tail];
- if (cq->tail == cq->ibcq.cqe)
- cq->tail = 0;
+ *entry = wc->queue[tail];
+ if (tail >= cq->ibcq.cqe)
+ tail = 0;
else
- cq->tail++;
+ tail++;
}
+ wc->tail = tail;
spin_unlock_irqrestore(&cq->lock, flags);
@@ -157,29 +174,81 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
struct ib_ucontext *context,
struct ib_udata *udata)
{
+ struct ipath_ibdev *dev = to_idev(ibdev);
struct ipath_cq *cq;
- struct ib_wc *wc;
+ struct ipath_cq_wc *wc;
struct ib_cq *ret;
- /*
- * Need to use vmalloc() if we want to support large #s of
- * entries.
- */
+ if (entries < 1 || entries > ib_ipath_max_cqes) {
+ ret = ERR_PTR(-EINVAL);
+ goto done;
+ }
+
+ /* Allocate the completion queue structure. */
cq = kmalloc(sizeof(*cq), GFP_KERNEL);
if (!cq) {
ret = ERR_PTR(-ENOMEM);
- goto bail;
+ goto done;
}
/*
- * Need to use vmalloc() if we want to support large #s of entries.
+ * Allocate the completion queue entries and head/tail pointers.
+ * This is allocated separately so that it can be resized and
+ * also mapped into user space.
+ * We need to use vmalloc() in order to support mmap and large
+ * numbers of entries.
*/
- wc = vmalloc(sizeof(*wc) * (entries + 1));
+ wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * entries);
if (!wc) {
- kfree(cq);
ret = ERR_PTR(-ENOMEM);
- goto bail;
+ goto bail_cq;
}
+
+ /*
+ * Return the address of the WC as the offset to mmap.
+ * See ipath_mmap() for details.
+ */
+ if (udata && udata->outlen >= sizeof(__u64)) {
+ struct ipath_mmap_info *ip;
+ __u64 offset = (__u64) wc;
+ int err;
+
+ err = ib_copy_to_udata(udata, &offset, sizeof(offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_wc;
+ }
+
+ /* Allocate info for ipath_mmap(). */
+ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
+ if (!ip) {
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_wc;
+ }
+ cq->ip = ip;
+ ip->context = context;
+ ip->obj = wc;
+ kref_init(&ip->ref);
+ ip->mmap_cnt = 0;
+ ip->size = PAGE_ALIGN(sizeof(*wc) +
+ sizeof(struct ib_wc) * entries);
+ spin_lock_irq(&dev->pending_lock);
+ ip->next = dev->pending_mmaps;
+ dev->pending_mmaps = ip;
+ spin_unlock_irq(&dev->pending_lock);
+ } else
+ cq->ip = NULL;
+
+ spin_lock(&dev->n_cqs_lock);
+ if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
+ spin_unlock(&dev->n_cqs_lock);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_wc;
+ }
+
+ dev->n_cqs_allocated++;
+ spin_unlock(&dev->n_cqs_lock);
+
/*
* ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
* The number of entries should be >= the number requested or return
@@ -190,13 +259,21 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
cq->triggered = 0;
spin_lock_init(&cq->lock);
tasklet_init(&cq->comptask, send_complete, (unsigned long)cq);
- cq->head = 0;
- cq->tail = 0;
+ wc->head = 0;
+ wc->tail = 0;
cq->queue = wc;
ret = &cq->ibcq;
-bail:
+ goto done;
+
+bail_wc:
+ vfree(wc);
+
+bail_cq:
+ kfree(cq);
+
+done:
return ret;
}
@@ -210,10 +287,17 @@ bail:
*/
int ipath_destroy_cq(struct ib_cq *ibcq)
{
+ struct ipath_ibdev *dev = to_idev(ibcq->device);
struct ipath_cq *cq = to_icq(ibcq);
tasklet_kill(&cq->comptask);
- vfree(cq->queue);
+ spin_lock(&dev->n_cqs_lock);
+ dev->n_cqs_allocated--;
+ spin_unlock(&dev->n_cqs_lock);
+ if (cq->ip)
+ kref_put(&cq->ip->ref, ipath_release_mmap_info);
+ else
+ vfree(cq->queue);
kfree(cq);
return 0;
@@ -237,7 +321,7 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
spin_lock_irqsave(&cq->lock, flags);
/*
* Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow
- * any other transitions.
+ * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2).
*/
if (cq->notify != IB_CQ_NEXT_COMP)
cq->notify = notify;
@@ -245,49 +329,96 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
return 0;
}
+/**
+ * ipath_resize_cq - change the size of the CQ
+ * @ibcq: the completion queue
+ *
+ * Returns 0 for success.
+ */
int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
{
struct ipath_cq *cq = to_icq(ibcq);
- struct ib_wc *wc, *old_wc;
- u32 n;
+ struct ipath_cq_wc *old_wc;
+ struct ipath_cq_wc *wc;
+ u32 head, tail, n;
int ret;
+ if (cqe < 1 || cqe > ib_ipath_max_cqes) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
/*
* Need to use vmalloc() if we want to support large #s of entries.
*/
- wc = vmalloc(sizeof(*wc) * (cqe + 1));
+ wc = vmalloc_user(sizeof(*wc) + sizeof(struct ib_wc) * cqe);
if (!wc) {
ret = -ENOMEM;
goto bail;
}
+ /*
+ * Return the address of the WC as the offset to mmap.
+ * See ipath_mmap() for details.
+ */
+ if (udata && udata->outlen >= sizeof(__u64)) {
+ __u64 offset = (__u64) wc;
+
+ ret = ib_copy_to_udata(udata, &offset, sizeof(offset));
+ if (ret)
+ goto bail;
+ }
+
spin_lock_irq(&cq->lock);
- if (cq->head < cq->tail)
- n = cq->ibcq.cqe + 1 + cq->head - cq->tail;
+ /*
+ * Make sure head and tail are sane since they
+ * might be user writable.
+ */
+ old_wc = cq->queue;
+ head = old_wc->head;
+ if (head > (u32) cq->ibcq.cqe)
+ head = (u32) cq->ibcq.cqe;
+ tail = old_wc->tail;
+ if (tail > (u32) cq->ibcq.cqe)
+ tail = (u32) cq->ibcq.cqe;
+ if (head < tail)
+ n = cq->ibcq.cqe + 1 + head - tail;
else
- n = cq->head - cq->tail;
+ n = head - tail;
if (unlikely((u32)cqe < n)) {
spin_unlock_irq(&cq->lock);
vfree(wc);
ret = -EOVERFLOW;
goto bail;
}
- for (n = 0; cq->tail != cq->head; n++) {
- wc[n] = cq->queue[cq->tail];
- if (cq->tail == cq->ibcq.cqe)
- cq->tail = 0;
+ for (n = 0; tail != head; n++) {
+ wc->queue[n] = old_wc->queue[tail];
+ if (tail == (u32) cq->ibcq.cqe)
+ tail = 0;
else
- cq->tail++;
+ tail++;
}
cq->ibcq.cqe = cqe;
- cq->head = n;
- cq->tail = 0;
- old_wc = cq->queue;
+ wc->head = n;
+ wc->tail = 0;
cq->queue = wc;
spin_unlock_irq(&cq->lock);
vfree(old_wc);
+ if (cq->ip) {
+ struct ipath_ibdev *dev = to_idev(ibcq->device);
+ struct ipath_mmap_info *ip = cq->ip;
+
+ ip->obj = wc;
+ ip->size = PAGE_ALIGN(sizeof(*wc) +
+ sizeof(struct ib_wc) * cqe);
+ spin_lock_irq(&dev->pending_lock);
+ ip->next = dev->pending_mmaps;
+ dev->pending_mmaps = ip;
+ spin_unlock_irq(&dev->pending_lock);
+ }
+
ret = 0;
bail:
diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/infiniband/hw/ipath/ipath_debug.h
index 46762387f5f..df69f0d80b8 100644
--- a/drivers/infiniband/hw/ipath/ipath_debug.h
+++ b/drivers/infiniband/hw/ipath/ipath_debug.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -59,7 +60,6 @@
#define __IPATH_USER_SEND 0x1000 /* use user mode send */
#define __IPATH_KERNEL_SEND 0x2000 /* use kernel mode send */
#define __IPATH_EPKTDBG 0x4000 /* print ethernet packet data */
-#define __IPATH_SMADBG 0x8000 /* sma packet debug */
#define __IPATH_IPATHDBG 0x10000 /* Ethernet (IPATH) gen debug */
#define __IPATH_IPATHWARN 0x20000 /* Ethernet (IPATH) warnings */
#define __IPATH_IPATHERR 0x40000 /* Ethernet (IPATH) errors */
@@ -83,7 +83,6 @@
/* print mmap/nopage stuff, not using VDBG any more */
#define __IPATH_MMDBG 0x0
#define __IPATH_EPKTDBG 0x0 /* print ethernet packet data */
-#define __IPATH_SMADBG 0x0 /* process startup (init)/exit messages */
#define __IPATH_IPATHDBG 0x0 /* Ethernet (IPATH) table dump on */
#define __IPATH_IPATHWARN 0x0 /* Ethernet (IPATH) warnings on */
#define __IPATH_IPATHERR 0x0 /* Ethernet (IPATH) errors on */
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 28ddceb260e..29958b6e021 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -40,13 +41,13 @@
* through the /sys/bus/pci resource mmap interface.
*/
+#include <linux/io.h>
#include <linux/pci.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
-#include "ipath_common.h"
#include "ipath_kernel.h"
-#include "ips_common.h"
-#include "ipath_layer.h"
+#include "ipath_common.h"
int ipath_diag_inuse;
static int diag_set_link;
@@ -66,18 +67,20 @@ static struct file_operations diag_file_ops = {
.release = ipath_diag_release
};
-static struct cdev *diag_cdev;
-static struct class_device *diag_class_dev;
-
-int ipath_diag_init(void)
+int ipath_diag_add(struct ipath_devdata *dd)
{
- return ipath_cdev_init(IPATH_DIAG_MINOR, "ipath_diag",
- &diag_file_ops, &diag_cdev, &diag_class_dev);
+ char name[16];
+
+ snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
+
+ return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
+ &diag_file_ops, &dd->diag_cdev,
+ &dd->diag_class_dev);
}
-void ipath_diag_cleanup(void)
+void ipath_diag_remove(struct ipath_devdata *dd)
{
- ipath_cdev_cleanup(&diag_cdev, &diag_class_dev);
+ ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev);
}
/**
@@ -101,8 +104,7 @@ static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
int ret;
/* not very efficient, but it works for now */
- if (reg_addr < dd->ipath_kregbase ||
- reg_end > dd->ipath_kregend) {
+ if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
ret = -EINVAL;
goto bail;
}
@@ -113,7 +115,7 @@ static int ipath_read_umem64(struct ipath_devdata *dd, void __user *uaddr,
goto bail;
}
reg_addr++;
- uaddr++;
+ uaddr += sizeof(u64);
}
ret = 0;
bail:
@@ -139,8 +141,7 @@ static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
int ret;
/* not very efficient, but it works for now */
- if (reg_addr < dd->ipath_kregbase ||
- reg_end > dd->ipath_kregend) {
+ if (reg_addr < dd->ipath_kregbase || reg_end > dd->ipath_kregend) {
ret = -EINVAL;
goto bail;
}
@@ -153,7 +154,7 @@ static int ipath_write_umem64(struct ipath_devdata *dd, void __iomem *caddr,
writeq(data, reg_addr);
reg_addr++;
- uaddr++;
+ uaddr += sizeof(u64);
}
ret = 0;
bail:
@@ -191,7 +192,8 @@ static int ipath_read_umem32(struct ipath_devdata *dd, void __user *uaddr,
}
reg_addr++;
- uaddr++;
+ uaddr += sizeof(u32);
+
}
ret = 0;
bail:
@@ -230,7 +232,7 @@ static int ipath_write_umem32(struct ipath_devdata *dd, void __iomem *caddr,
writel(data, reg_addr);
reg_addr++;
- uaddr++;
+ uaddr += sizeof(u32);
}
ret = 0;
bail:
@@ -239,59 +241,197 @@ bail:
static int ipath_diag_open(struct inode *in, struct file *fp)
{
+ int unit = iminor(in) - IPATH_DIAG_MINOR_BASE;
struct ipath_devdata *dd;
- int unit = 0; /* XXX this is bogus */
- unsigned long flags;
int ret;
- dd = ipath_lookup(unit);
-
mutex_lock(&ipath_mutex);
- spin_lock_irqsave(&ipath_devs_lock, flags);
if (ipath_diag_inuse) {
ret = -EBUSY;
goto bail;
}
- list_for_each_entry(dd, &ipath_dev_list, ipath_list) {
- /*
- * we need at least one infinipath device to be present
- * (don't use INITTED, because we want to be able to open
- * even if device is in freeze mode, which cleared INITTED).
- * There is a small amount of risk to this, which is why we
- * also verify kregbase is set.
- */
-
- if (!(dd->ipath_flags & IPATH_PRESENT) ||
- !dd->ipath_kregbase)
- continue;
-
- ipath_diag_inuse = 1;
- diag_set_link = 0;
- ret = 0;
+ dd = ipath_lookup(unit);
+
+ if (dd == NULL || !(dd->ipath_flags & IPATH_PRESENT) ||
+ !dd->ipath_kregbase) {
+ ret = -ENODEV;
goto bail;
}
- ret = -ENODEV;
-
-bail:
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
+ fp->private_data = dd;
+ ipath_diag_inuse = 1;
+ diag_set_link = 0;
+ ret = 0;
/* Only expose a way to reset the device if we
make it into diag mode. */
- if (ret == 0)
- ipath_expose_reset(&dd->pcidev->dev);
+ ipath_expose_reset(&dd->pcidev->dev);
+bail:
mutex_unlock(&ipath_mutex);
return ret;
}
-static int ipath_diag_release(struct inode *i, struct file *f)
+static ssize_t ipath_diagpkt_write(struct file *fp,
+ const char __user *data,
+ size_t count, loff_t *off);
+
+static struct file_operations diagpkt_file_ops = {
+ .owner = THIS_MODULE,
+ .write = ipath_diagpkt_write,
+};
+
+static struct cdev *diagpkt_cdev;
+static struct class_device *diagpkt_class_dev;
+
+int __init ipath_diagpkt_add(void)
+{
+ return ipath_cdev_init(IPATH_DIAGPKT_MINOR,
+ "ipath_diagpkt", &diagpkt_file_ops,
+ &diagpkt_cdev, &diagpkt_class_dev);
+}
+
+void __exit ipath_diagpkt_remove(void)
+{
+ ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev);
+}
+
+/**
+ * ipath_diagpkt_write - write an IB packet
+ * @fp: the diag data device file pointer
+ * @data: ipath_diag_pkt structure saying where to get the packet
+ * @count: size of data to write
+ * @off: unused by this code
+ */
+static ssize_t ipath_diagpkt_write(struct file *fp,
+ const char __user *data,
+ size_t count, loff_t *off)
+{
+ u32 __iomem *piobuf;
+ u32 plen, clen, pbufn;
+ struct ipath_diag_pkt dp;
+ u32 *tmpbuf = NULL;
+ struct ipath_devdata *dd;
+ ssize_t ret = 0;
+ u64 val;
+
+ if (count < sizeof(dp)) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ if (copy_from_user(&dp, data, sizeof(dp))) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ /* send count must be an exact number of dwords */
+ if (dp.len & 3) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ clen = dp.len >> 2;
+
+ dd = ipath_lookup(dp.unit);
+ if (!dd || !(dd->ipath_flags & IPATH_PRESENT) ||
+ !dd->ipath_kregbase) {
+ ipath_cdbg(VERBOSE, "illegal unit %u for diag data send\n",
+ dp.unit);
+ ret = -ENODEV;
+ goto bail;
+ }
+
+ if (ipath_diag_inuse && !diag_set_link &&
+ !(dd->ipath_flags & IPATH_LINKACTIVE)) {
+ diag_set_link = 1;
+ ipath_cdbg(VERBOSE, "Trying to set to set link active for "
+ "diag pkt\n");
+ ipath_set_linkstate(dd, IPATH_IB_LINKARM);
+ ipath_set_linkstate(dd, IPATH_IB_LINKACTIVE);
+ }
+
+ if (!(dd->ipath_flags & IPATH_INITTED)) {
+ /* no hardware, freeze, etc. */
+ ipath_cdbg(VERBOSE, "unit %u not usable\n", dd->ipath_unit);
+ ret = -ENODEV;
+ goto bail;
+ }
+ val = dd->ipath_lastibcstat & IPATH_IBSTATE_MASK;
+ if (val != IPATH_IBSTATE_INIT && val != IPATH_IBSTATE_ARM &&
+ val != IPATH_IBSTATE_ACTIVE) {
+ ipath_cdbg(VERBOSE, "unit %u not ready (state %llx)\n",
+ dd->ipath_unit, (unsigned long long) val);
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ /* need total length before first word written */
+ /* +1 word is for the qword padding */
+ plen = sizeof(u32) + dp.len;
+
+ if ((plen + 4) > dd->ipath_ibmaxlen) {
+ ipath_dbg("Pkt len 0x%x > ibmaxlen %x\n",
+ plen - 4, dd->ipath_ibmaxlen);
+ ret = -EINVAL;
+ goto bail; /* before writing pbc */
+ }
+ tmpbuf = vmalloc(plen);
+ if (!tmpbuf) {
+ dev_info(&dd->pcidev->dev, "Unable to allocate tmp buffer, "
+ "failing\n");
+ ret = -ENOMEM;
+ goto bail;
+ }
+
+ if (copy_from_user(tmpbuf,
+ (const void __user *) (unsigned long) dp.data,
+ dp.len)) {
+ ret = -EFAULT;
+ goto bail;
+ }
+
+ piobuf = ipath_getpiobuf(dd, &pbufn);
+ if (!piobuf) {
+ ipath_cdbg(VERBOSE, "No PIO buffers avail unit for %u\n",
+ dd->ipath_unit);
+ ret = -EBUSY;
+ goto bail;
+ }
+
+ plen >>= 2; /* in dwords */
+
+ if (ipath_debug & __IPATH_PKTDBG)
+ ipath_cdbg(VERBOSE, "unit %u 0x%x+1w pio%d\n",
+ dd->ipath_unit, plen - 1, pbufn);
+
+ /* we have to flush after the PBC for correctness on some cpus
+ * or WC buffer can be written out of order */
+ writeq(plen, piobuf);
+ ipath_flush_wc();
+ /* copy all by the trigger word, then flush, so it's written
+ * to chip before trigger word, then write trigger word, then
+ * flush again, so packet is sent. */
+ __iowrite32_copy(piobuf + 2, tmpbuf, clen - 1);
+ ipath_flush_wc();
+ __raw_writel(tmpbuf[clen - 1], piobuf + clen + 1);
+ ipath_flush_wc();
+
+ ret = sizeof(dp);
+
+bail:
+ vfree(tmpbuf);
+ return ret;
+}
+
+static int ipath_diag_release(struct inode *in, struct file *fp)
{
mutex_lock(&ipath_mutex);
ipath_diag_inuse = 0;
+ fp->private_data = NULL;
mutex_unlock(&ipath_mutex);
return 0;
}
@@ -299,17 +439,10 @@ static int ipath_diag_release(struct inode *i, struct file *f)
static ssize_t ipath_diag_read(struct file *fp, char __user *data,
size_t count, loff_t *off)
{
- int unit = 0; /* XXX provide for reads on other units some day */
- struct ipath_devdata *dd;
+ struct ipath_devdata *dd = fp->private_data;
void __iomem *kreg_base;
ssize_t ret;
- dd = ipath_lookup(unit);
- if (!dd) {
- ret = -ENODEV;
- goto bail;
- }
-
kreg_base = dd->ipath_kregbase;
if (count == 0)
@@ -328,23 +461,16 @@ static ssize_t ipath_diag_read(struct file *fp, char __user *data,
ret = count;
}
-bail:
return ret;
}
static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
size_t count, loff_t *off)
{
- int unit = 0; /* XXX this is bogus */
- struct ipath_devdata *dd;
+ struct ipath_devdata *dd = fp->private_data;
void __iomem *kreg_base;
ssize_t ret;
- dd = ipath_lookup(unit);
- if (!dd) {
- ret = -ENODEV;
- goto bail;
- }
kreg_base = dd->ipath_kregbase;
if (count == 0)
@@ -363,6 +489,5 @@ static ssize_t ipath_diag_write(struct file *fp, const char __user *data,
ret = count;
}
-bail:
return ret;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index dddcdae736a..12cefa658f3 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -38,8 +39,8 @@
#include <linux/vmalloc.h>
#include "ipath_kernel.h"
-#include "ips_common.h"
-#include "ipath_layer.h"
+#include "ipath_verbs.h"
+#include "ipath_common.h"
static void ipath_update_pio_bufs(struct ipath_devdata *);
@@ -50,22 +51,20 @@ const char *ipath_get_unit_name(int unit)
return iname;
}
-EXPORT_SYMBOL_GPL(ipath_get_unit_name);
-
-#define DRIVER_LOAD_MSG "PathScale " IPATH_DRV_NAME " loaded: "
+#define DRIVER_LOAD_MSG "QLogic " IPATH_DRV_NAME " loaded: "
#define PFX IPATH_DRV_NAME ": "
/*
* The size has to be longer than this string, so we can append
* board/chip information to it in the init code.
*/
-const char ipath_core_version[] = IPATH_IDSTR "\n";
+const char ib_ipath_version[] = IPATH_IDSTR "\n";
static struct idr unit_table;
DEFINE_SPINLOCK(ipath_devs_lock);
LIST_HEAD(ipath_dev_list);
-wait_queue_head_t ipath_sma_state_wait;
+wait_queue_head_t ipath_state_wait;
unsigned ipath_debug = __IPATH_INFO;
@@ -74,8 +73,8 @@ MODULE_PARM_DESC(debug, "mask for debug prints");
EXPORT_SYMBOL_GPL(ipath_debug);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("PathScale <support@pathscale.com>");
-MODULE_DESCRIPTION("Pathscale InfiniPath driver");
+MODULE_AUTHOR("QLogic <support@pathscale.com>");
+MODULE_DESCRIPTION("QLogic InfiniPath driver");
const char *ipath_ibcstatus_str[] = {
"Disabled",
@@ -96,16 +95,6 @@ const char *ipath_ibcstatus_str[] = {
"RecovIdle",
};
-/*
- * These variables are initialized in the chip-specific files
- * but are defined here.
- */
-u16 ipath_gpio_sda_num, ipath_gpio_scl_num;
-u64 ipath_gpio_sda, ipath_gpio_scl;
-u64 infinipath_i_bitsextant;
-ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
-u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
-
static void __devexit ipath_remove_one(struct pci_dev *);
static int __devinit ipath_init_one(struct pci_dev *,
const struct pci_device_id *);
@@ -130,14 +119,6 @@ static struct pci_driver ipath_driver = {
.id_table = ipath_pci_tbl,
};
-/*
- * This is where port 0's rcvhdrtail register is written back; we also
- * want nothing else sharing the cache line, so make it a cache line
- * in size. Used for all units.
- */
-volatile __le64 *ipath_port0_rcvhdrtail;
-dma_addr_t ipath_port0_rcvhdrtail_dma;
-static int port0_rcvhdrtail_refs;
static inline void read_bars(struct ipath_devdata *dd, struct pci_dev *dev,
u32 *bar0, u32 *bar1)
@@ -170,14 +151,13 @@ static void ipath_free_devdata(struct pci_dev *pdev,
list_del(&dd->ipath_list);
spin_unlock_irqrestore(&ipath_devs_lock, flags);
}
- dma_free_coherent(&pdev->dev, sizeof(*dd), dd, dd->ipath_dma_addr);
+ vfree(dd);
}
static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
{
unsigned long flags;
struct ipath_devdata *dd;
- dma_addr_t dma_addr;
int ret;
if (!idr_pre_get(&unit_table, GFP_KERNEL)) {
@@ -185,15 +165,12 @@ static struct ipath_devdata *ipath_alloc_devdata(struct pci_dev *pdev)
goto bail;
}
- dd = dma_alloc_coherent(&pdev->dev, sizeof(*dd), &dma_addr,
- GFP_KERNEL);
-
+ dd = vmalloc(sizeof(*dd));
if (!dd) {
dd = ERR_PTR(-ENOMEM);
goto bail;
}
-
- dd->ipath_dma_addr = dma_addr;
+ memset(dd, 0, sizeof(*dd));
dd->ipath_unit = -1;
spin_lock_irqsave(&ipath_devs_lock, flags);
@@ -271,47 +248,6 @@ int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp)
return nunits;
}
-static int init_port0_rcvhdrtail(struct pci_dev *pdev)
-{
- int ret;
-
- mutex_lock(&ipath_mutex);
-
- if (!ipath_port0_rcvhdrtail) {
- ipath_port0_rcvhdrtail =
- dma_alloc_coherent(&pdev->dev,
- IPATH_PORT0_RCVHDRTAIL_SIZE,
- &ipath_port0_rcvhdrtail_dma,
- GFP_KERNEL);
-
- if (!ipath_port0_rcvhdrtail) {
- ret = -ENOMEM;
- goto bail;
- }
- }
- port0_rcvhdrtail_refs++;
- ret = 0;
-
-bail:
- mutex_unlock(&ipath_mutex);
-
- return ret;
-}
-
-static void cleanup_port0_rcvhdrtail(struct pci_dev *pdev)
-{
- mutex_lock(&ipath_mutex);
-
- if (!--port0_rcvhdrtail_refs) {
- dma_free_coherent(&pdev->dev, IPATH_PORT0_RCVHDRTAIL_SIZE,
- (void *) ipath_port0_rcvhdrtail,
- ipath_port0_rcvhdrtail_dma);
- ipath_port0_rcvhdrtail = NULL;
- }
-
- mutex_unlock(&ipath_mutex);
-}
-
/*
* These next two routines are placeholders in case we don't have per-arch
* code for controlling write combining. If explicit control of write
@@ -336,20 +272,12 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
u32 bar0 = 0, bar1 = 0;
u8 rev;
- ret = init_port0_rcvhdrtail(pdev);
- if (ret < 0) {
- printk(KERN_ERR IPATH_DRV_NAME
- ": Could not allocate port0_rcvhdrtail: error %d\n",
- -ret);
- goto bail;
- }
-
dd = ipath_alloc_devdata(pdev);
if (IS_ERR(dd)) {
ret = PTR_ERR(dd);
printk(KERN_ERR IPATH_DRV_NAME
": Could not allocate devdata: error %d\n", -ret);
- goto bail_rcvhdrtail;
+ goto bail;
}
ipath_cdbg(VERBOSE, "initializing unit #%u\n", dd->ipath_unit);
@@ -424,12 +352,29 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
*/
ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (ret) {
- dev_info(&pdev->dev, "pci_set_dma_mask unit %u "
- "fails: %d\n", dd->ipath_unit, ret);
+ dev_info(&pdev->dev,
+ "Unable to set DMA mask for unit %u: %d\n",
+ dd->ipath_unit, ret);
goto bail_regions;
}
- else
+ else {
ipath_dbg("No 64bit DMA mask, used 32 bit mask\n");
+ ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ if (ret)
+ dev_info(&pdev->dev,
+ "Unable to set DMA consistent mask "
+ "for unit %u: %d\n",
+ dd->ipath_unit, ret);
+
+ }
+ }
+ else {
+ ret = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ if (ret)
+ dev_info(&pdev->dev,
+ "Unable to set DMA consistent mask "
+ "for unit %u: %d\n",
+ dd->ipath_unit, ret);
}
pci_set_master(pdev);
@@ -446,13 +391,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
/* setup the chip-specific functions, as early as possible. */
switch (ent->device) {
case PCI_DEVICE_ID_INFINIPATH_HT:
- ipath_init_ht400_funcs(dd);
+ ipath_init_iba6110_funcs(dd);
break;
case PCI_DEVICE_ID_INFINIPATH_PE800:
- ipath_init_pe800_funcs(dd);
+ ipath_init_iba6120_funcs(dd);
break;
default:
- ipath_dev_err(dd, "Found unknown PathScale deviceid 0x%x, "
+ ipath_dev_err(dd, "Found unknown QLogic deviceid 0x%x, "
"failing\n", ent->device);
return -ENODEV;
}
@@ -460,10 +405,10 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
for (j = 0; j < 6; j++) {
if (!pdev->resource[j].start)
continue;
- ipath_cdbg(VERBOSE, "BAR %d start %lx, end %lx, len %lx\n",
- j, pdev->resource[j].start,
- pdev->resource[j].end,
- pci_resource_len(pdev, j));
+ ipath_cdbg(VERBOSE, "BAR %d start %llx, end %llx, len %llx\n",
+ j, (unsigned long long)pdev->resource[j].start,
+ (unsigned long long)pdev->resource[j].end,
+ (unsigned long long)pci_resource_len(pdev, j));
}
if (!addr) {
@@ -483,7 +428,13 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
}
dd->ipath_pcirev = rev;
+#if defined(__powerpc__)
+ /* There isn't a generic way to specify writethrough mappings */
+ dd->ipath_kregbase = __ioremap(addr, len,
+ (_PAGE_NO_CACHE|_PAGE_WRITETHRU));
+#else
dd->ipath_kregbase = ioremap_nocache(addr, len);
+#endif
if (!dd->ipath_kregbase) {
ipath_dbg("Unable to map io addr %llx to kvirt, failing\n",
@@ -495,23 +446,23 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
((void __iomem *)dd->ipath_kregbase + len);
dd->ipath_physaddr = addr; /* used for io_remap, etc. */
/* for user mmap */
- dd->ipath_kregvirt = (u64 __iomem *) phys_to_virt(addr);
- ipath_cdbg(VERBOSE, "mapped io addr %llx to kregbase %p "
- "kregvirt %p\n", addr, dd->ipath_kregbase,
- dd->ipath_kregvirt);
+ ipath_cdbg(VERBOSE, "mapped io addr %llx to kregbase %p\n",
+ addr, dd->ipath_kregbase);
/*
* clear ipath_flags here instead of in ipath_init_chip as it is set
* by ipath_setup_htconfig.
*/
dd->ipath_flags = 0;
+ dd->ipath_lli_counter = 0;
+ dd->ipath_lli_errors = 0;
if (dd->ipath_f_bus(dd, pdev))
ipath_dev_err(dd, "Failed to setup config space; "
"continuing anyway\n");
/*
- * set up our interrupt handler; SA_SHIRQ probably not needed,
+ * set up our interrupt handler; IRQF_SHARED probably not needed,
* since MSI interrupts shouldn't be shared but won't hurt for now.
* check 0 irq after we return from chip-specific bus setup, since
* that can affect this due to setup
@@ -520,7 +471,7 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ipath_dev_err(dd, "irq is 0, BIOS error? Interrupts won't "
"work\n");
else {
- ret = request_irq(pdev->irq, ipath_intr, SA_SHIRQ,
+ ret = request_irq(pdev->irq, ipath_intr, IRQF_SHARED,
IPATH_DRV_NAME, dd);
if (ret) {
ipath_dev_err(dd, "Couldn't setup irq handler, "
@@ -545,7 +496,8 @@ static int __devinit ipath_init_one(struct pci_dev *pdev,
ipath_device_create_group(&pdev->dev, dd);
ipathfs_add_device(dd);
ipath_user_add(dd);
- ipath_layer_add(dd);
+ ipath_diag_add(dd);
+ ipath_register_ib_device(dd);
goto bail;
@@ -561,40 +513,155 @@ bail_disable:
bail_devdata:
ipath_free_devdata(pdev, dd);
-bail_rcvhdrtail:
- cleanup_port0_rcvhdrtail(pdev);
-
bail:
return ret;
}
+static void __devexit cleanup_device(struct ipath_devdata *dd)
+{
+ int port;
+
+ ipath_shutdown_device(dd);
+
+ if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
+ /* can't do anything more with chip; needs re-init */
+ *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
+ if (dd->ipath_kregbase) {
+ /*
+ * if we haven't already cleaned up before these are
+ * to ensure any register reads/writes "fail" until
+ * re-init
+ */
+ dd->ipath_kregbase = NULL;
+ dd->ipath_uregbase = 0;
+ dd->ipath_sregbase = 0;
+ dd->ipath_cregbase = 0;
+ dd->ipath_kregsize = 0;
+ }
+ ipath_disable_wc(dd);
+ }
+
+ if (dd->ipath_pioavailregs_dma) {
+ dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+ (void *) dd->ipath_pioavailregs_dma,
+ dd->ipath_pioavailregs_phys);
+ dd->ipath_pioavailregs_dma = NULL;
+ }
+ if (dd->ipath_dummy_hdrq) {
+ dma_free_coherent(&dd->pcidev->dev,
+ dd->ipath_pd[0]->port_rcvhdrq_size,
+ dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
+ dd->ipath_dummy_hdrq = NULL;
+ }
+
+ if (dd->ipath_pageshadow) {
+ struct page **tmpp = dd->ipath_pageshadow;
+ dma_addr_t *tmpd = dd->ipath_physshadow;
+ int i, cnt = 0;
+
+ ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
+ "locked\n");
+ for (port = 0; port < dd->ipath_cfgports; port++) {
+ int port_tidbase = port * dd->ipath_rcvtidcnt;
+ int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
+ for (i = port_tidbase; i < maxtid; i++) {
+ if (!tmpp[i])
+ continue;
+ pci_unmap_page(dd->pcidev, tmpd[i],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ ipath_release_user_pages(&tmpp[i], 1);
+ tmpp[i] = NULL;
+ cnt++;
+ }
+ }
+ if (cnt) {
+ ipath_stats.sps_pageunlocks += cnt;
+ ipath_cdbg(VERBOSE, "There were still %u expTID "
+ "entries locked\n", cnt);
+ }
+ if (ipath_stats.sps_pagelocks ||
+ ipath_stats.sps_pageunlocks)
+ ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
+ "unlocked via ipath_m{un}lock\n",
+ (unsigned long long)
+ ipath_stats.sps_pagelocks,
+ (unsigned long long)
+ ipath_stats.sps_pageunlocks);
+
+ ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
+ dd->ipath_pageshadow);
+ vfree(dd->ipath_pageshadow);
+ dd->ipath_pageshadow = NULL;
+ }
+
+ /*
+ * free any resources still in use (usually just kernel ports)
+ * at unload; we do for portcnt, not cfgports, because cfgports
+ * could have changed while we were loaded.
+ */
+ for (port = 0; port < dd->ipath_portcnt; port++) {
+ struct ipath_portdata *pd = dd->ipath_pd[port];
+ dd->ipath_pd[port] = NULL;
+ ipath_free_pddata(dd, pd);
+ }
+ kfree(dd->ipath_pd);
+ /*
+ * debuggability, in case some cleanup path tries to use it
+ * after this
+ */
+ dd->ipath_pd = NULL;
+}
+
static void __devexit ipath_remove_one(struct pci_dev *pdev)
{
- struct ipath_devdata *dd;
+ struct ipath_devdata *dd = pci_get_drvdata(pdev);
- ipath_cdbg(VERBOSE, "removing, pdev=%p\n", pdev);
- if (!pdev)
- return;
+ ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd);
- dd = pci_get_drvdata(pdev);
- ipath_layer_del(dd);
- ipath_user_del(dd);
+ if (dd->verbs_dev)
+ ipath_unregister_ib_device(dd->verbs_dev);
+
+ ipath_diag_remove(dd);
+ ipath_user_remove(dd);
ipathfs_remove_device(dd);
ipath_device_remove_group(&pdev->dev, dd);
+
ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, "
"unit %u\n", dd, (u32) dd->ipath_unit);
- if (dd->ipath_kregbase) {
- ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n",
- dd->ipath_kregbase);
- iounmap((volatile void __iomem *) dd->ipath_kregbase);
- dd->ipath_kregbase = NULL;
- }
+
+ cleanup_device(dd);
+
+ /*
+ * turn off rcv, send, and interrupts for all ports, all drivers
+ * should also hard reset the chip here?
+ * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
+ * for all versions of the driver, if they were allocated
+ */
+ if (pdev->irq) {
+ ipath_cdbg(VERBOSE,
+ "unit %u free_irq of irq %x\n",
+ dd->ipath_unit, pdev->irq);
+ free_irq(pdev->irq, dd);
+ } else
+ ipath_dbg("irq is 0, not doing free_irq "
+ "for unit %u\n", dd->ipath_unit);
+ /*
+ * we check for NULL here, because it's outside
+ * the kregbase check, and we need to call it
+ * after the free_irq. Thus it's possible that
+ * the function pointers were never initialized.
+ */
+ if (dd->ipath_f_cleanup)
+ /* clean up chip-specific stuff */
+ dd->ipath_f_cleanup(dd);
+
+ ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", dd->ipath_kregbase);
+ iounmap((volatile void __iomem *) dd->ipath_kregbase);
pci_release_regions(pdev);
ipath_cdbg(VERBOSE, "calling pci_disable_device\n");
pci_disable_device(pdev);
ipath_free_devdata(pdev, dd);
- cleanup_port0_rcvhdrtail(pdev);
}
/* general driver use */
@@ -652,21 +719,23 @@ void ipath_disarm_piobufs(struct ipath_devdata *dd, unsigned first,
*
* wait up to msecs milliseconds for IB link state change to occur for
* now, take the easy polling route. Currently used only by
- * ipath_layer_set_linkstate. Returns 0 if state reached, otherwise
+ * ipath_set_linkstate. Returns 0 if state reached, otherwise
* -ETIMEDOUT state can have multiple states set, for any of several
* transitions.
*/
-int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state, int msecs)
+static int ipath_wait_linkstate(struct ipath_devdata *dd, u32 state,
+ int msecs)
{
- dd->ipath_sma_state_wanted = state;
- wait_event_interruptible_timeout(ipath_sma_state_wait,
+ dd->ipath_state_wanted = state;
+ wait_event_interruptible_timeout(ipath_state_wait,
(dd->ipath_flags & state),
msecs_to_jiffies(msecs));
- dd->ipath_sma_state_wanted = 0;
+ dd->ipath_state_wanted = 0;
if (!(dd->ipath_flags & state)) {
u64 val;
- ipath_cdbg(SMA, "Didn't reach linkstate %s within %u ms\n",
+ ipath_cdbg(VERBOSE, "Didn't reach linkstate %s within %u"
+ " ms\n",
/* test INIT ahead of DOWN, both can be set */
(state & IPATH_LINKINIT) ? "INIT" :
((state & IPATH_LINKDOWN) ? "DOWN" :
@@ -799,8 +868,8 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
int err)
{
- return dd->ipath_port0_skbs ?
- (void *)dd->ipath_port0_skbs[bufnum]->data : NULL;
+ return dd->ipath_port0_skbinfo ?
+ (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
}
/**
@@ -822,85 +891,69 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd,
*/
/*
- * We need 4 extra bytes for unaligned transfer copying
+ * We need 2 extra bytes for ipath_ether data sent in the
+ * key header. In order to keep everything dword aligned,
+ * we'll reserve 4 bytes.
*/
+ len = dd->ipath_ibmaxlen + 4;
+
if (dd->ipath_flags & IPATH_4BYTE_TID) {
- /* we need a 4KB multiple alignment, and there is no way
+ /* We need a 2KB multiple alignment, and there is no way
* to do it except to allocate extra and then skb_reserve
* enough to bring it up to the right alignment.
*/
- len = dd->ipath_ibmaxlen + 4 + (1 << 11) - 1;
+ len += 2047;
}
- else
- len = dd->ipath_ibmaxlen + 4;
+
skb = __dev_alloc_skb(len, gfp_mask);
if (!skb) {
ipath_dev_err(dd, "Failed to allocate skbuff, length %u\n",
len);
goto bail;
}
+
+ skb_reserve(skb, 4);
+
if (dd->ipath_flags & IPATH_4BYTE_TID) {
- u32 una = ((1 << 11) - 1) & (unsigned long)(skb->data + 4);
+ u32 una = (unsigned long)skb->data & 2047;
if (una)
- skb_reserve(skb, 4 + (1 << 11) - una);
- else
- skb_reserve(skb, 4);
- } else
- skb_reserve(skb, 4);
+ skb_reserve(skb, 2048 - una);
+ }
bail:
return skb;
}
-/**
- * ipath_rcv_layer - receive a packet for the layered (ethernet) driver
- * @dd: the infinipath device
- * @etail: the sk_buff number
- * @tlen: the total packet length
- * @hdr: the ethernet header
- *
- * Separate routine for better overall optimization
- */
-static void ipath_rcv_layer(struct ipath_devdata *dd, u32 etail,
- u32 tlen, struct ether_header *hdr)
+static void ipath_rcv_hdrerr(struct ipath_devdata *dd,
+ u32 eflags,
+ u32 l,
+ u32 etail,
+ u64 *rc)
{
- u32 elen;
- u8 pad, *bthbytes;
- struct sk_buff *skb, *nskb;
-
- if (dd->ipath_port0_skbs && hdr->sub_opcode == OPCODE_ENCAP) {
- /*
- * Allocate a new sk_buff to replace the one we give
- * to the network stack.
- */
- nskb = ipath_alloc_skb(dd, GFP_ATOMIC);
- if (!nskb) {
- /* count OK packets that we drop */
- ipath_stats.sps_krdrops++;
- return;
+ char emsg[128];
+ struct ipath_message_header *hdr;
+
+ get_rhf_errstring(eflags, emsg, sizeof emsg);
+ hdr = (struct ipath_message_header *)&rc[1];
+ ipath_cdbg(PKT, "RHFerrs %x hdrqtail=%x typ=%u "
+ "tlen=%x opcode=%x egridx=%x: %s\n",
+ eflags, l,
+ ipath_hdrget_rcv_type((__le32 *) rc),
+ ipath_hdrget_length_in_bytes((__le32 *) rc),
+ be32_to_cpu(hdr->bth[0]) >> 24,
+ etail, emsg);
+
+ /* Count local link integrity errors. */
+ if (eflags & (INFINIPATH_RHF_H_ICRCERR | INFINIPATH_RHF_H_VCRCERR)) {
+ u8 n = (dd->ipath_ibcctrl >>
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
+
+ if (++dd->ipath_lli_counter > n) {
+ dd->ipath_lli_counter = 0;
+ dd->ipath_lli_errors++;
}
-
- bthbytes = (u8 *) hdr->bth;
- pad = (bthbytes[1] >> 4) & 3;
- /* +CRC32 */
- elen = tlen - (sizeof(*hdr) + pad + sizeof(u32));
-
- skb = dd->ipath_port0_skbs[etail];
- dd->ipath_port0_skbs[etail] = nskb;
- skb_put(skb, elen);
-
- dd->ipath_f_put_tid(dd, etail + (u64 __iomem *)
- ((char __iomem *) dd->ipath_kregbase
- + dd->ipath_rcvegrbase), 0,
- virt_to_phys(nskb->data));
-
- __ipath_layer_rcv(dd, hdr, skb);
-
- /* another ether packet received */
- ipath_stats.sps_ether_rpkts++;
}
- else if (hdr->sub_opcode == OPCODE_LID_ARP)
- __ipath_layer_rcv_lid(dd, hdr);
}
/*
@@ -916,10 +969,9 @@ void ipath_kreceive(struct ipath_devdata *dd)
const u32 rsize = dd->ipath_rcvhdrentsize; /* words */
const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */
u32 etail = -1, l, hdrqtail;
- struct ips_message_header *hdr;
- u32 eflags, i, etype, tlen, pkttot = 0;
+ struct ipath_message_header *hdr;
+ u32 eflags, i, etype, tlen, pkttot = 0, updegr=0, reloop=0;
static u64 totcalls; /* stats, may eventually remove */
- char emsg[128];
if (!dd->ipath_hdrqtailptr) {
ipath_dev_err(dd,
@@ -931,24 +983,18 @@ void ipath_kreceive(struct ipath_devdata *dd)
if (test_and_set_bit(0, &dd->ipath_rcv_pending))
goto bail;
- if (dd->ipath_port0head ==
- (u32)le64_to_cpu(*dd->ipath_hdrqtailptr))
+ l = dd->ipath_port0head;
+ hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
+ if (l == hdrqtail)
goto done;
-gotmore:
- /*
- * read only once at start. If in flood situation, this helps
- * performance slightly. If more arrive while we are processing,
- * we'll come back here and do them
- */
- hdrqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
-
- for (i = 0, l = dd->ipath_port0head; l != hdrqtail; i++) {
+reloop:
+ for (i = 0; l != hdrqtail; i++) {
u32 qp;
u8 *bthbytes;
rc = (u64 *) (dd->ipath_pd[0]->port_rcvhdrq + (l << 2));
- hdr = (struct ips_message_header *)&rc[1];
+ hdr = (struct ipath_message_header *)&rc[1];
/*
* could make a network order version of IPATH_KD_QP, and
* do the obvious shift before masking to speed this up.
@@ -956,10 +1002,10 @@ gotmore:
qp = ntohl(hdr->bth[1]) & 0xffffff;
bthbytes = (u8 *) hdr->bth;
- eflags = ips_get_hdr_err_flags((__le32 *) rc);
- etype = ips_get_rcv_type((__le32 *) rc);
+ eflags = ipath_hdrget_err_flags((__le32 *) rc);
+ etype = ipath_hdrget_rcv_type((__le32 *) rc);
/* total length */
- tlen = ips_get_length_in_bytes((__le32 *) rc);
+ tlen = ipath_hdrget_length_in_bytes((__le32 *) rc);
ebuf = NULL;
if (etype != RCVHQ_RCV_TYPE_EXPECTED) {
/*
@@ -969,7 +1015,7 @@ gotmore:
* set ebuf (so we try to copy data) unless the
* length requires it.
*/
- etail = ips_get_index((__le32 *) rc);
+ etail = ipath_hdrget_index((__le32 *) rc);
if (tlen > sizeof(*hdr) ||
etype == RCVHQ_RCV_TYPE_NON_KD)
ebuf = ipath_get_egrbuf(dd, etail, 0);
@@ -981,60 +1027,31 @@ gotmore:
*/
if (etype != RCVHQ_RCV_TYPE_NON_KD && etype !=
- RCVHQ_RCV_TYPE_ERROR && ips_get_ipath_ver(
+ RCVHQ_RCV_TYPE_ERROR && ipath_hdrget_ipath_ver(
hdr->iph.ver_port_tid_offset) !=
IPS_PROTO_VERSION) {
ipath_cdbg(PKT, "Bad InfiniPath protocol version "
"%x\n", etype);
}
- if (eflags & ~(INFINIPATH_RHF_H_TIDERR |
- INFINIPATH_RHF_H_IHDRERR)) {
- get_rhf_errstring(eflags, emsg, sizeof emsg);
- ipath_cdbg(PKT, "RHFerrs %x hdrqtail=%x typ=%u "
- "tlen=%x opcode=%x egridx=%x: %s\n",
- eflags, l, etype, tlen, bthbytes[0],
- ips_get_index((__le32 *) rc), emsg);
- } else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
- int ret = __ipath_verbs_rcv(dd, rc + 1,
- ebuf, tlen);
- if (ret == -ENODEV)
- ipath_cdbg(VERBOSE,
- "received IB packet, "
- "not SMA (QP=%x)\n", qp);
- } else if (etype == RCVHQ_RCV_TYPE_EAGER) {
- if (qp == IPATH_KD_QP &&
- bthbytes[0] == ipath_layer_rcv_opcode &&
- ebuf)
- ipath_rcv_layer(dd, etail, tlen,
- (struct ether_header *)hdr);
- else
- ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
- "qp=%x), len %x; ignored\n",
- etype, bthbytes[0], qp, tlen);
+ if (unlikely(eflags))
+ ipath_rcv_hdrerr(dd, eflags, l, etail, rc);
+ else if (etype == RCVHQ_RCV_TYPE_NON_KD) {
+ ipath_ib_rcv(dd->verbs_dev, rc + 1, ebuf, tlen);
+ if (dd->ipath_lli_counter)
+ dd->ipath_lli_counter--;
+ ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
+ "qp=%x), len %x; ignored\n",
+ etype, bthbytes[0], qp, tlen);
}
+ else if (etype == RCVHQ_RCV_TYPE_EAGER)
+ ipath_cdbg(PKT, "typ %x, opcode %x (eager, "
+ "qp=%x), len %x; ignored\n",
+ etype, bthbytes[0], qp, tlen);
else if (etype == RCVHQ_RCV_TYPE_EXPECTED)
ipath_dbg("Bug: Expected TID, opcode %x; ignored\n",
be32_to_cpu(hdr->bth[0]) & 0xff);
- else if (eflags & (INFINIPATH_RHF_H_TIDERR |
- INFINIPATH_RHF_H_IHDRERR)) {
- /*
- * This is a type 3 packet, only the LRH is in the
- * rcvhdrq, the rest of the header is in the eager
- * buffer.
- */
- u8 opcode;
- if (ebuf) {
- bthbytes = (u8 *) ebuf;
- opcode = *bthbytes;
- }
- else
- opcode = 0;
- get_rhf_errstring(eflags, emsg, sizeof emsg);
- ipath_dbg("Err %x (%s), opcode %x, egrbuf %x, "
- "len %x\n", eflags, emsg, opcode, etail,
- tlen);
- } else {
+ else {
/*
* error packet, type of error unknown.
* Probably type 3, but we don't know, so don't
@@ -1054,25 +1071,50 @@ gotmore:
l += rsize;
if (l >= maxcnt)
l = 0;
+ if (etype != RCVHQ_RCV_TYPE_EXPECTED)
+ updegr = 1;
/*
- * update for each packet, to help prevent overflows if we
- * have lots of packets.
+ * update head regs on last packet, and every 16 packets.
+ * Reduce bus traffic, while still trying to prevent
+ * rcvhdrq overflows, for when the queue is nearly full
*/
- (void)ipath_write_ureg(dd, ur_rcvhdrhead,
- dd->ipath_rhdrhead_intr_off | l, 0);
- if (etype != RCVHQ_RCV_TYPE_EXPECTED)
- (void)ipath_write_ureg(dd, ur_rcvegrindexhead,
- etail, 0);
+ if (l == hdrqtail || (i && !(i&0xf))) {
+ u64 lval;
+ if (l == hdrqtail)
+ /* request IBA6120 interrupt only on last */
+ lval = dd->ipath_rhdrhead_intr_off | l;
+ else
+ lval = l;
+ (void)ipath_write_ureg(dd, ur_rcvhdrhead, lval, 0);
+ if (updegr) {
+ (void)ipath_write_ureg(dd, ur_rcvegrindexhead,
+ etail, 0);
+ updegr = 0;
+ }
+ }
+ }
+
+ if (!dd->ipath_rhdrhead_intr_off && !reloop) {
+ /* IBA6110 workaround; we can have a race clearing chip
+ * interrupt with another interrupt about to be delivered,
+ * and can clear it before it is delivered on the GPIO
+ * workaround. By doing the extra check here for the
+ * in-memory tail register updating while we were doing
+ * earlier packets, we "almost" guarantee we have covered
+ * that case.
+ */
+ u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
+ if (hqtail != hdrqtail) {
+ hdrqtail = hqtail;
+ reloop = 1; /* loop 1 extra time at most */
+ goto reloop;
+ }
}
pkttot += i;
dd->ipath_port0head = l;
- if (hdrqtail != (u32)le64_to_cpu(*dd->ipath_hdrqtailptr))
- /* more arrived while we handled first batch */
- goto gotmore;
-
if (pkttot > ipath_stats.sps_maxpkts_call)
ipath_stats.sps_maxpkts_call = pkttot;
ipath_stats.sps_port0pkts += pkttot;
@@ -1226,7 +1268,7 @@ int ipath_setrcvhdrsize(struct ipath_devdata *dd, unsigned rhdrsize)
*
* do appropriate marking as busy, etc.
* returns buffer number if one found (>=0), negative number is error.
- * Used by ipath_sma_send_pkt and ipath_layer_send
+ * Used by ipath_layer_send
*/
u32 __iomem *ipath_getpiobuf(struct ipath_devdata *dd, u32 * pbufnum)
{
@@ -1332,13 +1374,6 @@ rescan:
goto bail;
}
- if (updated)
- /*
- * ran out of bufs, now some (at least this one we just
- * got) are now available, so tell the layered driver.
- */
- __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE);
-
/*
* set next starting place. Since it's just an optimization,
* it doesn't matter who wins on this, so no locking
@@ -1369,26 +1404,20 @@ bail:
* @dd: the infinipath device
* @pd: the port data
*
- * this *must* be physically contiguous memory, and for now,
- * that limits it to what kmalloc can do.
+ * this must be contiguous memory (from an i/o perspective), and must be
+ * DMA'able (which means for some systems, it will go through an IOMMU,
+ * or be forced into a low address range).
*/
int ipath_create_rcvhdrq(struct ipath_devdata *dd,
struct ipath_portdata *pd)
{
- int ret = 0, amt;
+ int ret = 0;
- amt = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
- sizeof(u32), PAGE_SIZE);
if (!pd->port_rcvhdrq) {
- /*
- * not using REPEAT isn't viable; at 128KB, we can easily
- * fail this. The problem with REPEAT is we can block here
- * "forever". There isn't an inbetween, unfortunately. We
- * could reduce the risk by never freeing the rcvhdrq except
- * at unload, but even then, the first time a port is used,
- * we could delay for some time...
- */
+ dma_addr_t phys_hdrqtail;
gfp_t gfp_flags = GFP_USER | __GFP_COMP;
+ int amt = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
+ sizeof(u32), PAGE_SIZE);
pd->port_rcvhdrq = dma_alloc_coherent(
&dd->pcidev->dev, amt, &pd->port_rcvhdrq_phys,
@@ -1401,6 +1430,19 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
ret = -ENOMEM;
goto bail;
}
+ pd->port_rcvhdrtail_kvaddr = dma_alloc_coherent(
+ &dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail, GFP_KERNEL);
+ if (!pd->port_rcvhdrtail_kvaddr) {
+ ipath_dev_err(dd, "attempt to allocate 1 page "
+ "for port %u rcvhdrqtailaddr failed\n",
+ pd->port_port);
+ ret = -ENOMEM;
+ dma_free_coherent(&dd->pcidev->dev, amt,
+ pd->port_rcvhdrq, pd->port_rcvhdrq_phys);
+ pd->port_rcvhdrq = NULL;
+ goto bail;
+ }
+ pd->port_rcvhdrqtailaddr_phys = phys_hdrqtail;
pd->port_rcvhdrq_size = amt;
@@ -1410,20 +1452,29 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
(unsigned long) pd->port_rcvhdrq_phys,
(unsigned long) pd->port_rcvhdrq_size,
pd->port_port);
- } else {
- /*
- * clear for security, sanity, and/or debugging, each
- * time we reuse
- */
- memset(pd->port_rcvhdrq, 0, amt);
+
+ ipath_cdbg(VERBOSE, "port %d hdrtailaddr, %llx physical\n",
+ pd->port_port,
+ (unsigned long long) phys_hdrqtail);
}
+ else
+ ipath_cdbg(VERBOSE, "reuse port %d rcvhdrq @%p %llx phys; "
+ "hdrtailaddr@%p %llx physical\n",
+ pd->port_port, pd->port_rcvhdrq,
+ (unsigned long long) pd->port_rcvhdrq_phys,
+ pd->port_rcvhdrtail_kvaddr, (unsigned long long)
+ pd->port_rcvhdrqtailaddr_phys);
+
+ /* clear for security and sanity on each use */
+ memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
+ memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
/*
* tell chip each time we init it, even if we are re-using previous
- * memory (we zero it at process close)
+ * memory (we zero the register at process close)
*/
- ipath_cdbg(VERBOSE, "writing port %d rcvhdraddr as %lx\n",
- pd->port_port, (unsigned long) pd->port_rcvhdrq_phys);
+ ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
+ pd->port_port, pd->port_rcvhdrqtailaddr_phys);
ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
pd->port_port, pd->port_rcvhdrq_phys);
@@ -1503,7 +1554,7 @@ int ipath_waitfor_mdio_cmdready(struct ipath_devdata *dd)
return ret;
}
-void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
+static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
{
static const char *what[4] = {
[0] = "DOWN",
@@ -1511,20 +1562,206 @@ void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
[INFINIPATH_IBCC_LINKCMD_ARMED] = "ARMED",
[INFINIPATH_IBCC_LINKCMD_ACTIVE] = "ACTIVE"
};
- ipath_cdbg(SMA, "Trying to move unit %u to %s, current ltstate "
+ int linkcmd = (which >> INFINIPATH_IBCC_LINKCMD_SHIFT) &
+ INFINIPATH_IBCC_LINKCMD_MASK;
+
+ ipath_cdbg(VERBOSE, "Trying to move unit %u to %s, current ltstate "
"is %s\n", dd->ipath_unit,
- what[(which >> INFINIPATH_IBCC_LINKCMD_SHIFT) &
- INFINIPATH_IBCC_LINKCMD_MASK],
+ what[linkcmd],
ipath_ibcstatus_str[
(ipath_read_kreg64
(dd, dd->ipath_kregs->kr_ibcstatus) >>
INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]);
+ /* flush all queued sends when going to DOWN or INIT, to be sure that
+ * they don't block MAD packets */
+ if (!linkcmd || linkcmd == INFINIPATH_IBCC_LINKCMD_INIT) {
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ INFINIPATH_S_ABORT);
+ ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
+ (unsigned)(dd->ipath_piobcnt2k +
+ dd->ipath_piobcnt4k) -
+ dd->ipath_lastport_piobuf);
+ }
ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
dd->ipath_ibcctrl | which);
}
+int ipath_set_linkstate(struct ipath_devdata *dd, u8 newstate)
+{
+ u32 lstate;
+ int ret;
+
+ switch (newstate) {
+ case IPATH_IB_LINKDOWN:
+ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL <<
+ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+ /* don't wait */
+ ret = 0;
+ goto bail;
+
+ case IPATH_IB_LINKDOWN_SLEEP:
+ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP <<
+ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+ /* don't wait */
+ ret = 0;
+ goto bail;
+
+ case IPATH_IB_LINKDOWN_DISABLE:
+ ipath_set_ib_lstate(dd,
+ INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
+ INFINIPATH_IBCC_LINKINITCMD_SHIFT);
+ /* don't wait */
+ ret = 0;
+ goto bail;
+
+ case IPATH_IB_LINKINIT:
+ if (dd->ipath_flags & IPATH_LINKINIT) {
+ ret = 0;
+ goto bail;
+ }
+ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT <<
+ INFINIPATH_IBCC_LINKCMD_SHIFT);
+ lstate = IPATH_LINKINIT;
+ break;
+
+ case IPATH_IB_LINKARM:
+ if (dd->ipath_flags & IPATH_LINKARMED) {
+ ret = 0;
+ goto bail;
+ }
+ if (!(dd->ipath_flags &
+ (IPATH_LINKINIT | IPATH_LINKACTIVE))) {
+ ret = -EINVAL;
+ goto bail;
+ }
+ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED <<
+ INFINIPATH_IBCC_LINKCMD_SHIFT);
+ /*
+ * Since the port can transition to ACTIVE by receiving
+ * a non VL 15 packet, wait for either state.
+ */
+ lstate = IPATH_LINKARMED | IPATH_LINKACTIVE;
+ break;
+
+ case IPATH_IB_LINKACTIVE:
+ if (dd->ipath_flags & IPATH_LINKACTIVE) {
+ ret = 0;
+ goto bail;
+ }
+ if (!(dd->ipath_flags & IPATH_LINKARMED)) {
+ ret = -EINVAL;
+ goto bail;
+ }
+ ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE <<
+ INFINIPATH_IBCC_LINKCMD_SHIFT);
+ lstate = IPATH_LINKACTIVE;
+ break;
+
+ default:
+ ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
+ ret = -EINVAL;
+ goto bail;
+ }
+ ret = ipath_wait_linkstate(dd, lstate, 2000);
+
+bail:
+ return ret;
+}
+
+/**
+ * ipath_set_mtu - set the MTU
+ * @dd: the infinipath device
+ * @arg: the new MTU
+ *
+ * we can handle "any" incoming size, the issue here is whether we
+ * need to restrict our outgoing size. For now, we don't do any
+ * sanity checking on this, and we don't deal with what happens to
+ * programs that are already running when the size changes.
+ * NOTE: changing the MTU will usually cause the IBC to go back to
+ * link initialize (IPATH_IBSTATE_INIT) state...
+ */
+int ipath_set_mtu(struct ipath_devdata *dd, u16 arg)
+{
+ u32 piosize;
+ int changed = 0;
+ int ret;
+
+ /*
+ * mtu is IB data payload max. It's the largest power of 2 less
+ * than piosize (or even larger, since it only really controls the
+ * largest we can receive; we can send the max of the mtu and
+ * piosize). We check that it's one of the valid IB sizes.
+ */
+ if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&
+ arg != 4096) {
+ ipath_dbg("Trying to set invalid mtu %u, failing\n", arg);
+ ret = -EINVAL;
+ goto bail;
+ }
+ if (dd->ipath_ibmtu == arg) {
+ ret = 0; /* same as current */
+ goto bail;
+ }
+
+ piosize = dd->ipath_ibmaxlen;
+ dd->ipath_ibmtu = arg;
+
+ if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) {
+ /* Only if it's not the initial value (or reset to it) */
+ if (piosize != dd->ipath_init_ibmaxlen) {
+ dd->ipath_ibmaxlen = piosize;
+ changed = 1;
+ }
+ } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) {
+ piosize = arg + IPATH_PIO_MAXIBHDR;
+ ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x "
+ "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize,
+ arg);
+ dd->ipath_ibmaxlen = piosize;
+ changed = 1;
+ }
+
+ if (changed) {
+ /*
+ * set the IBC maxpktlength to the size of our pio
+ * buffers in words
+ */
+ u64 ibc = dd->ipath_ibcctrl;
+ ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK <<
+ INFINIPATH_IBCC_MAXPKTLEN_SHIFT);
+
+ piosize = piosize - 2 * sizeof(u32); /* ignore pbc */
+ dd->ipath_ibmaxlen = piosize;
+ piosize /= sizeof(u32); /* in words */
+ /*
+ * for ICRC, which we only send in diag test pkt mode, and
+ * we don't need to worry about that for mtu
+ */
+ piosize += 1;
+
+ ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
+ dd->ipath_ibcctrl = ibc;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+ dd->ipath_ibcctrl);
+ dd->ipath_f_tidtemplate(dd);
+ }
+
+ ret = 0;
+
+bail:
+ return ret;
+}
+
+int ipath_set_lid(struct ipath_devdata *dd, u32 arg, u8 lmc)
+{
+ dd->ipath_lid = arg;
+ dd->ipath_lmc = lmc;
+
+ return 0;
+}
+
/**
* ipath_read_kreg64_port - read a device's per-port 64-bit kernel register
* @dd: the infinipath device
@@ -1628,17 +1865,10 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
INFINIPATH_IBCC_LINKINITCMD_SHIFT);
- /*
- * we are shutting down, so tell the layered driver. We don't do
- * this on just a link state change, much like ethernet, a cable
- * unplug, etc. doesn't change driver state
- */
- ipath_layer_intr(dd, IPATH_LAYER_INT_IF_DOWN);
-
/* disable IBC */
dd->ipath_control &= ~INFINIPATH_C_LINKENABLE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
- dd->ipath_control);
+ dd->ipath_control | INFINIPATH_C_FREEZEMODE);
/*
* clear SerdesEnable and turn the leds off; do this here because
@@ -1667,82 +1897,82 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
/**
* ipath_free_pddata - free a port's allocated data
* @dd: the infinipath device
- * @port: the port
- * @freehdrq: free the port data structure if true
+ * @pd: the portdata structure
*
- * when closing, free up any allocated data for a port, if the
- * reference count goes to zero
- * Note: this also optionally frees the portdata itself!
- * Any changes here have to be matched up with the reinit case
- * of ipath_init_chip(), which calls this routine on reinit after reset.
+ * free up any allocated data for a port
+ * This should not touch anything that would affect a simultaneous
+ * re-allocation of port data, because it is called after ipath_mutex
+ * is released (and can be called from reinit as well).
+ * It should never change any chip state, or global driver state.
+ * (The only exception to global state is freeing the port0 port0_skbs.)
*/
-void ipath_free_pddata(struct ipath_devdata *dd, u32 port, int freehdrq)
+void ipath_free_pddata(struct ipath_devdata *dd, struct ipath_portdata *pd)
{
- struct ipath_portdata *pd = dd->ipath_pd[port];
-
if (!pd)
return;
- if (freehdrq)
- /*
- * only clear and free portdata if we are going to also
- * release the hdrq, otherwise we leak the hdrq on each
- * open/close cycle
- */
- dd->ipath_pd[port] = NULL;
- if (freehdrq && pd->port_rcvhdrq) {
+
+ if (pd->port_rcvhdrq) {
ipath_cdbg(VERBOSE, "free closed port %d rcvhdrq @ %p "
"(size=%lu)\n", pd->port_port, pd->port_rcvhdrq,
(unsigned long) pd->port_rcvhdrq_size);
dma_free_coherent(&dd->pcidev->dev, pd->port_rcvhdrq_size,
pd->port_rcvhdrq, pd->port_rcvhdrq_phys);
pd->port_rcvhdrq = NULL;
+ if (pd->port_rcvhdrtail_kvaddr) {
+ dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+ pd->port_rcvhdrtail_kvaddr,
+ pd->port_rcvhdrqtailaddr_phys);
+ pd->port_rcvhdrtail_kvaddr = NULL;
+ }
}
- if (port && pd->port_rcvegrbuf) {
- /* always free this */
- if (pd->port_rcvegrbuf) {
- unsigned e;
-
- for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) {
- void *base = pd->port_rcvegrbuf[e];
- size_t size = pd->port_rcvegrbuf_size;
-
- ipath_cdbg(VERBOSE, "egrbuf free(%p, %lu), "
- "chunk %u/%u\n", base,
- (unsigned long) size,
- e, pd->port_rcvegrbuf_chunks);
- dma_free_coherent(
- &dd->pcidev->dev, size, base,
- pd->port_rcvegrbuf_phys[e]);
- }
- vfree(pd->port_rcvegrbuf);
- pd->port_rcvegrbuf = NULL;
- vfree(pd->port_rcvegrbuf_phys);
- pd->port_rcvegrbuf_phys = NULL;
+ if (pd->port_port && pd->port_rcvegrbuf) {
+ unsigned e;
+
+ for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) {
+ void *base = pd->port_rcvegrbuf[e];
+ size_t size = pd->port_rcvegrbuf_size;
+
+ ipath_cdbg(VERBOSE, "egrbuf free(%p, %lu), "
+ "chunk %u/%u\n", base,
+ (unsigned long) size,
+ e, pd->port_rcvegrbuf_chunks);
+ dma_free_coherent(&dd->pcidev->dev, size,
+ base, pd->port_rcvegrbuf_phys[e]);
}
+ kfree(pd->port_rcvegrbuf);
+ pd->port_rcvegrbuf = NULL;
+ kfree(pd->port_rcvegrbuf_phys);
+ pd->port_rcvegrbuf_phys = NULL;
pd->port_rcvegrbuf_chunks = 0;
- } else if (port == 0 && dd->ipath_port0_skbs) {
+ } else if (pd->port_port == 0 && dd->ipath_port0_skbinfo) {
unsigned e;
- struct sk_buff **skbs = dd->ipath_port0_skbs;
+ struct ipath_skbinfo *skbinfo = dd->ipath_port0_skbinfo;
- dd->ipath_port0_skbs = NULL;
- ipath_cdbg(VERBOSE, "free closed port %d ipath_port0_skbs "
- "@ %p\n", pd->port_port, skbs);
+ dd->ipath_port0_skbinfo = NULL;
+ ipath_cdbg(VERBOSE, "free closed port %d "
+ "ipath_port0_skbinfo @ %p\n", pd->port_port,
+ skbinfo);
for (e = 0; e < dd->ipath_rcvegrcnt; e++)
- if (skbs[e])
- dev_kfree_skb(skbs[e]);
- vfree(skbs);
- }
- if (freehdrq) {
- kfree(pd->port_tid_pg_list);
- kfree(pd);
+ if (skbinfo[e].skb) {
+ pci_unmap_single(dd->pcidev, skbinfo[e].phys,
+ dd->ipath_ibmaxlen,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skbinfo[e].skb);
+ }
+ vfree(skbinfo);
}
+ kfree(pd->port_tid_pg_list);
+ vfree(pd->subport_uregbase);
+ vfree(pd->subport_rcvegrbuf);
+ vfree(pd->subport_rcvhdr_base);
+ kfree(pd);
}
static int __init infinipath_init(void)
{
int ret;
- ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ipath_core_version);
+ ipath_dbg(KERN_INFO DRIVER_LOAD_MSG "%s", ib_ipath_version);
/*
* These must be called before the driver is registered with
@@ -1775,8 +2005,18 @@ static int __init infinipath_init(void)
goto bail_group;
}
+ ret = ipath_diagpkt_add();
+ if (ret < 0) {
+ printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
+ "diag data device: error %d\n", -ret);
+ goto bail_ipathfs;
+ }
+
goto bail;
+bail_ipathfs:
+ ipath_exit_ipathfs();
+
bail_group:
ipath_driver_remove_group(&ipath_driver.driver);
@@ -1790,139 +2030,12 @@ bail:
return ret;
}
-static void cleanup_device(struct ipath_devdata *dd)
-{
- int port;
-
- ipath_shutdown_device(dd);
-
- if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
- /* can't do anything more with chip; needs re-init */
- *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
- if (dd->ipath_kregbase) {
- /*
- * if we haven't already cleaned up before these are
- * to ensure any register reads/writes "fail" until
- * re-init
- */
- dd->ipath_kregbase = NULL;
- dd->ipath_kregvirt = NULL;
- dd->ipath_uregbase = 0;
- dd->ipath_sregbase = 0;
- dd->ipath_cregbase = 0;
- dd->ipath_kregsize = 0;
- }
- ipath_disable_wc(dd);
- }
-
- if (dd->ipath_pioavailregs_dma) {
- dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
- (void *) dd->ipath_pioavailregs_dma,
- dd->ipath_pioavailregs_phys);
- dd->ipath_pioavailregs_dma = NULL;
- }
-
- if (dd->ipath_pageshadow) {
- struct page **tmpp = dd->ipath_pageshadow;
- int i, cnt = 0;
-
- ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
- "locked\n");
- for (port = 0; port < dd->ipath_cfgports; port++) {
- int port_tidbase = port * dd->ipath_rcvtidcnt;
- int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
- for (i = port_tidbase; i < maxtid; i++) {
- if (!tmpp[i])
- continue;
- ipath_release_user_pages(&tmpp[i], 1);
- tmpp[i] = NULL;
- cnt++;
- }
- }
- if (cnt) {
- ipath_stats.sps_pageunlocks += cnt;
- ipath_cdbg(VERBOSE, "There were still %u expTID "
- "entries locked\n", cnt);
- }
- if (ipath_stats.sps_pagelocks ||
- ipath_stats.sps_pageunlocks)
- ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
- "unlocked via ipath_m{un}lock\n",
- (unsigned long long)
- ipath_stats.sps_pagelocks,
- (unsigned long long)
- ipath_stats.sps_pageunlocks);
-
- ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
- dd->ipath_pageshadow);
- vfree(dd->ipath_pageshadow);
- dd->ipath_pageshadow = NULL;
- }
-
- /*
- * free any resources still in use (usually just kernel ports)
- * at unload
- */
- for (port = 0; port < dd->ipath_cfgports; port++)
- ipath_free_pddata(dd, port, 1);
- kfree(dd->ipath_pd);
- /*
- * debuggability, in case some cleanup path tries to use it
- * after this
- */
- dd->ipath_pd = NULL;
-}
-
static void __exit infinipath_cleanup(void)
{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
ipath_exit_ipathfs();
ipath_driver_remove_group(&ipath_driver.driver);
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- /*
- * turn off rcv, send, and interrupts for all ports, all drivers
- * should also hard reset the chip here?
- * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
- * for all versions of the driver, if they were allocated
- */
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
- if (dd->ipath_kregbase)
- cleanup_device(dd);
-
- if (dd->pcidev) {
- if (dd->pcidev->irq) {
- ipath_cdbg(VERBOSE,
- "unit %u free_irq of irq %x\n",
- dd->ipath_unit, dd->pcidev->irq);
- free_irq(dd->pcidev->irq, dd);
- } else
- ipath_dbg("irq is 0, not doing free_irq "
- "for unit %u\n", dd->ipath_unit);
-
- /*
- * we check for NULL here, because it's outside
- * the kregbase check, and we need to call it
- * after the free_irq. Thus it's possible that
- * the function pointers were never initialized.
- */
- if (dd->ipath_f_cleanup)
- /* clean up chip-specific stuff */
- dd->ipath_f_cleanup(dd);
-
- dd->pcidev = NULL;
- }
- spin_lock_irqsave(&ipath_devs_lock, flags);
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
pci_unregister_driver(&ipath_driver);
@@ -1988,5 +2101,22 @@ bail:
return ret;
}
+int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
+{
+ u64 val;
+ if ( new_pol_inv > INFINIPATH_XGXS_RX_POL_MASK ) {
+ return -1;
+ }
+ if ( dd->ipath_rx_pol_inv != new_pol_inv ) {
+ dd->ipath_rx_pol_inv = new_pol_inv;
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+ val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
+ INFINIPATH_XGXS_RX_POL_SHIFT);
+ val |= ((u64)dd->ipath_rx_pol_inv) <<
+ INFINIPATH_XGXS_RX_POL_SHIFT;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
+ }
+ return 0;
+}
module_init(infinipath_init);
module_exit(infinipath_cleanup);
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index a2f1ceafcca..a4019a6b756 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -99,9 +100,9 @@ static int i2c_gpio_set(struct ipath_devdata *dd,
gpioval = &dd->ipath_gpio_out;
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
if (line == i2c_line_scl)
- mask = ipath_gpio_scl;
+ mask = dd->ipath_gpio_scl;
else
- mask = ipath_gpio_sda;
+ mask = dd->ipath_gpio_sda;
if (new_line_state == i2c_line_high)
/* tri-state the output rather than force high */
@@ -118,12 +119,12 @@ static int i2c_gpio_set(struct ipath_devdata *dd,
write_val = 0x0UL;
if (line == i2c_line_scl) {
- write_val <<= ipath_gpio_scl_num;
- *gpioval = *gpioval & ~(1UL << ipath_gpio_scl_num);
+ write_val <<= dd->ipath_gpio_scl_num;
+ *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_scl_num);
*gpioval |= write_val;
} else {
- write_val <<= ipath_gpio_sda_num;
- *gpioval = *gpioval & ~(1UL << ipath_gpio_sda_num);
+ write_val <<= dd->ipath_gpio_sda_num;
+ *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_sda_num);
*gpioval |= write_val;
}
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval);
@@ -156,9 +157,9 @@ static int i2c_gpio_get(struct ipath_devdata *dd,
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
/* config line to be an input */
if (line == i2c_line_scl)
- mask = ipath_gpio_scl;
+ mask = dd->ipath_gpio_scl;
else
- mask = ipath_gpio_sda;
+ mask = dd->ipath_gpio_sda;
write_val = read_val & ~mask;
ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val);
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
@@ -186,6 +187,7 @@ bail:
static void i2c_wait_for_writes(struct ipath_devdata *dd)
{
(void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+ rmb();
}
static void scl_out(struct ipath_devdata *dd, u8 bit)
@@ -600,8 +602,31 @@ void ipath_get_eeprom_info(struct ipath_devdata *dd)
guid = *(__be64 *) ifp->if_guid;
dd->ipath_guid = guid;
dd->ipath_nguid = ifp->if_numguid;
- memcpy(dd->ipath_serial, ifp->if_serial,
- sizeof(ifp->if_serial));
+ /*
+ * Things are slightly complicated by the desire to transparently
+ * support both the Pathscale 10-digit serial number and the QLogic
+ * 13-character version.
+ */
+ if ((ifp->if_fversion > 1) && ifp->if_sprefix[0]
+ && ((u8 *)ifp->if_sprefix)[0] != 0xFF) {
+ /* This board has a Serial-prefix, which is stored
+ * elsewhere for backward-compatibility.
+ */
+ char *snp = dd->ipath_serial;
+ int len;
+ memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
+ snp[sizeof ifp->if_sprefix] = '\0';
+ len = strlen(snp);
+ snp += len;
+ len = (sizeof dd->ipath_serial) - len;
+ if (len > sizeof ifp->if_serial) {
+ len = sizeof ifp->if_serial;
+ }
+ memcpy(snp, ifp->if_serial, len);
+ } else
+ memcpy(dd->ipath_serial, ifp->if_serial,
+ sizeof ifp->if_serial);
+
ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n",
(unsigned long long) be64_to_cpu(dd->ipath_guid));
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index ada267e41f6..a9ddc6911f6 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -38,8 +39,13 @@
#include <asm/pgtable.h>
#include "ipath_kernel.h"
-#include "ips_common.h"
-#include "ipath_layer.h"
+#include "ipath_common.h"
+
+/*
+ * mmap64 doesn't allow all 64 bits for 32-bit applications
+ * so only use the low 43 bits.
+ */
+#define MMAP64_MASK 0x7FFFFFFFFFFUL
static int ipath_open(struct inode *, struct file *);
static int ipath_close(struct inode *, struct file *);
@@ -57,18 +63,35 @@ static struct file_operations ipath_file_ops = {
.mmap = ipath_mmap
};
-static int ipath_get_base_info(struct ipath_portdata *pd,
+static int ipath_get_base_info(struct file *fp,
void __user *ubase, size_t ubase_size)
{
+ struct ipath_portdata *pd = port_fp(fp);
int ret = 0;
struct ipath_base_info *kinfo = NULL;
struct ipath_devdata *dd = pd->port_dd;
+ unsigned subport_cnt;
+ int shared, master;
+ size_t sz;
+
+ subport_cnt = pd->port_subport_cnt;
+ if (!subport_cnt) {
+ shared = 0;
+ master = 0;
+ subport_cnt = 1;
+ } else {
+ shared = 1;
+ master = !subport_fp(fp);
+ }
- if (ubase_size < sizeof(*kinfo)) {
+ sz = sizeof(*kinfo);
+ /* If port sharing is not requested, allow the old size structure */
+ if (!shared)
+ sz -= 3 * sizeof(u64);
+ if (ubase_size < sz) {
ipath_cdbg(PROC,
- "Base size %lu, need %lu (version mismatch?)\n",
- (unsigned long) ubase_size,
- (unsigned long) sizeof(*kinfo));
+ "Base size %zu, need %zu (version mismatch?)\n",
+ ubase_size, sz);
ret = -EINVAL;
goto bail;
}
@@ -95,7 +118,9 @@ static int ipath_get_base_info(struct ipath_portdata *pd,
kinfo->spi_rcv_egrperchunk = pd->port_rcvegrbufs_perchunk;
kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen /
pd->port_rcvegrbuf_chunks;
- kinfo->spi_tidcnt = dd->ipath_rcvtidcnt;
+ kinfo->spi_tidcnt = dd->ipath_rcvtidcnt / subport_cnt;
+ if (master)
+ kinfo->spi_tidcnt += dd->ipath_rcvtidcnt % subport_cnt;
/*
* for this use, may be ipath_cfgports summed over all chips that
* are are configured and present
@@ -118,30 +143,75 @@ static int ipath_get_base_info(struct ipath_portdata *pd,
* page_address() macro worked, but in 2.6.11, even that returns the
* full 64 bit address (upper bits all 1's). So far, using the
* physical addresses (or chip offsets, for chip mapping) works, but
- * no doubt some future kernel release will chang that, and we'll be
- * on to yet another method of dealing with this
+ * no doubt some future kernel release will change that, and we'll be
+ * on to yet another method of dealing with this.
*/
kinfo->spi_rcvhdr_base = (u64) pd->port_rcvhdrq_phys;
+ kinfo->spi_rcvhdr_tailaddr = (u64) pd->port_rcvhdrqtailaddr_phys;
kinfo->spi_rcv_egrbufs = (u64) pd->port_rcvegr_phys;
kinfo->spi_pioavailaddr = (u64) dd->ipath_pioavailregs_phys;
kinfo->spi_status = (u64) kinfo->spi_pioavailaddr +
(void *) dd->ipath_statusp -
(void *) dd->ipath_pioavailregs_dma;
- kinfo->spi_piobufbase = (u64) pd->port_piobufs;
- kinfo->__spi_uregbase =
- dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+ if (!shared) {
+ kinfo->spi_piocnt = dd->ipath_pbufsport;
+ kinfo->spi_piobufbase = (u64) pd->port_piobufs;
+ kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
+ dd->ipath_palign * pd->port_port;
+ } else if (master) {
+ kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
+ (dd->ipath_pbufsport % subport_cnt);
+ /* Master's PIO buffers are after all the slave's */
+ kinfo->spi_piobufbase = (u64) pd->port_piobufs +
+ dd->ipath_palign *
+ (dd->ipath_pbufsport - kinfo->spi_piocnt);
+ kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
+ dd->ipath_palign * pd->port_port;
+ } else {
+ unsigned slave = subport_fp(fp) - 1;
+
+ kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt;
+ kinfo->spi_piobufbase = (u64) pd->port_piobufs +
+ dd->ipath_palign * kinfo->spi_piocnt * slave;
+ kinfo->__spi_uregbase = ((u64) pd->subport_uregbase +
+ PAGE_SIZE * slave) & MMAP64_MASK;
- kinfo->spi_pioindex = dd->ipath_pbufsport * (pd->port_port - 1);
- kinfo->spi_piocnt = dd->ipath_pbufsport;
+ kinfo->spi_rcvhdr_base = ((u64) pd->subport_rcvhdr_base +
+ pd->port_rcvhdrq_size * slave) & MMAP64_MASK;
+ kinfo->spi_rcvhdr_tailaddr =
+ (u64) pd->port_rcvhdrqtailaddr_phys & MMAP64_MASK;
+ kinfo->spi_rcv_egrbufs = ((u64) pd->subport_rcvegrbuf +
+ dd->ipath_rcvegrcnt * dd->ipath_rcvegrbufsize * slave) &
+ MMAP64_MASK;
+ }
+
+ kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) /
+ dd->ipath_palign;
kinfo->spi_pioalign = dd->ipath_palign;
kinfo->spi_qpair = IPATH_KD_QP;
kinfo->spi_piosize = dd->ipath_ibmaxlen;
kinfo->spi_mtu = dd->ipath_ibmaxlen; /* maxlen, not ibmtu */
kinfo->spi_port = pd->port_port;
+ kinfo->spi_subport = subport_fp(fp);
kinfo->spi_sw_version = IPATH_KERN_SWVERSION;
kinfo->spi_hw_version = dd->ipath_revision;
+ if (master) {
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_MASTER;
+ kinfo->spi_subport_uregbase =
+ (u64) pd->subport_uregbase & MMAP64_MASK;
+ kinfo->spi_subport_rcvegrbuf =
+ (u64) pd->subport_rcvegrbuf & MMAP64_MASK;
+ kinfo->spi_subport_rcvhdr_base =
+ (u64) pd->subport_rcvhdr_base & MMAP64_MASK;
+ ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n",
+ kinfo->spi_port, kinfo->spi_runtime_flags,
+ (unsigned long long) kinfo->spi_subport_uregbase,
+ (unsigned long long) kinfo->spi_subport_rcvegrbuf,
+ (unsigned long long) kinfo->spi_subport_rcvhdr_base);
+ }
+
if (copy_to_user(ubase, kinfo, sizeof(*kinfo)))
ret = -EFAULT;
@@ -153,6 +223,7 @@ bail:
/**
* ipath_tid_update - update a port TID
* @pd: the port
+ * @fp: the ipath device file
* @ti: the TID information
*
* The new implementation as of Oct 2004 is that the driver assigns
@@ -175,11 +246,11 @@ bail:
* virtually contiguous pages, that should change to improve
* performance.
*/
-static int ipath_tid_update(struct ipath_portdata *pd,
+static int ipath_tid_update(struct ipath_portdata *pd, struct file *fp,
const struct ipath_tid_info *ti)
{
int ret = 0, ntids;
- u32 tid, porttid, cnt, i, tidcnt;
+ u32 tid, porttid, cnt, i, tidcnt, tidoff;
u16 *tidlist;
struct ipath_devdata *dd = pd->port_dd;
u64 physaddr;
@@ -187,6 +258,7 @@ static int ipath_tid_update(struct ipath_portdata *pd,
u64 __iomem *tidbase;
unsigned long tidmap[8];
struct page **pagep = NULL;
+ unsigned subport = subport_fp(fp);
if (!dd->ipath_pageshadow) {
ret = -ENOMEM;
@@ -203,20 +275,34 @@ static int ipath_tid_update(struct ipath_portdata *pd,
ret = -EFAULT;
goto done;
}
- tidcnt = dd->ipath_rcvtidcnt;
- if (cnt >= tidcnt) {
+ porttid = pd->port_port * dd->ipath_rcvtidcnt;
+ if (!pd->port_subport_cnt) {
+ tidcnt = dd->ipath_rcvtidcnt;
+ tid = pd->port_tidcursor;
+ tidoff = 0;
+ } else if (!subport) {
+ tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
+ (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
+ tidoff = dd->ipath_rcvtidcnt - tidcnt;
+ porttid += tidoff;
+ tid = tidcursor_fp(fp);
+ } else {
+ tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
+ tidoff = tidcnt * (subport - 1);
+ porttid += tidoff;
+ tid = tidcursor_fp(fp);
+ }
+ if (cnt > tidcnt) {
/* make sure it all fits in port_tid_pg_list */
dev_info(&dd->pcidev->dev, "Process tried to allocate %u "
"TIDs, only trying max (%u)\n", cnt, tidcnt);
cnt = tidcnt;
}
- pagep = (struct page **)pd->port_tid_pg_list;
- tidlist = (u16 *) (&pagep[cnt]);
+ pagep = &((struct page **) pd->port_tid_pg_list)[tidoff];
+ tidlist = &((u16 *) &pagep[dd->ipath_rcvtidcnt])[tidoff];
memset(tidmap, 0, sizeof(tidmap));
- tid = pd->port_tidcursor;
/* before decrement; chip actual # */
- porttid = pd->port_port * tidcnt;
ntids = tidcnt;
tidbase = (u64 __iomem *) (((char __iomem *) dd->ipath_kregbase) +
dd->ipath_rcvtidbase +
@@ -273,16 +359,19 @@ static int ipath_tid_update(struct ipath_portdata *pd,
ret = -ENOMEM;
break;
}
- tidlist[i] = tid;
+ tidlist[i] = tid + tidoff;
ipath_cdbg(VERBOSE, "Updating idx %u to TID %u, "
- "vaddr %lx\n", i, tid, vaddr);
+ "vaddr %lx\n", i, tid + tidoff, vaddr);
/* we "know" system pages and TID pages are same size */
dd->ipath_pageshadow[porttid + tid] = pagep[i];
+ dd->ipath_physshadow[porttid + tid] = ipath_map_page(
+ dd->pcidev, pagep[i], 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
/*
* don't need atomic or it's overhead
*/
__set_bit(tid, tidmap);
- physaddr = page_to_phys(pagep[i]);
+ physaddr = dd->ipath_physshadow[porttid + tid];
ipath_stats.sps_pagelocks++;
ipath_cdbg(VERBOSE,
"TID %u, vaddr %lx, physaddr %llx pgp %p\n",
@@ -316,6 +405,9 @@ static int ipath_tid_update(struct ipath_portdata *pd,
tid);
dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
dd->ipath_tidinvalid);
+ pci_unmap_page(dd->pcidev,
+ dd->ipath_physshadow[porttid + tid],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
dd->ipath_pageshadow[porttid + tid] = NULL;
ipath_stats.sps_pageunlocks++;
}
@@ -340,7 +432,10 @@ static int ipath_tid_update(struct ipath_portdata *pd,
}
if (tid == tidcnt)
tid = 0;
- pd->port_tidcursor = tid;
+ if (!pd->port_subport_cnt)
+ pd->port_tidcursor = tid;
+ else
+ tidcursor_fp(fp) = tid;
}
done:
@@ -353,6 +448,7 @@ done:
/**
* ipath_tid_free - free a port TID
* @pd: the port
+ * @subport: the subport
* @ti: the TID info
*
* right now we are unlocking one page at a time, but since
@@ -366,7 +462,7 @@ done:
* they pass in to us.
*/
-static int ipath_tid_free(struct ipath_portdata *pd,
+static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
const struct ipath_tid_info *ti)
{
int ret = 0;
@@ -387,11 +483,20 @@ static int ipath_tid_free(struct ipath_portdata *pd,
}
porttid = pd->port_port * dd->ipath_rcvtidcnt;
+ if (!pd->port_subport_cnt)
+ tidcnt = dd->ipath_rcvtidcnt;
+ else if (!subport) {
+ tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
+ (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
+ porttid += dd->ipath_rcvtidcnt - tidcnt;
+ } else {
+ tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
+ porttid += tidcnt * (subport - 1);
+ }
tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
dd->ipath_rcvtidbase +
porttid * sizeof(*tidbase));
- tidcnt = dd->ipath_rcvtidcnt;
limit = sizeof(tidmap) * BITS_PER_BYTE;
if (limit > tidcnt)
/* just in case size changes in future */
@@ -416,6 +521,9 @@ static int ipath_tid_free(struct ipath_portdata *pd,
pd->port_pid, tid);
dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
dd->ipath_tidinvalid);
+ pci_unmap_page(dd->pcidev,
+ dd->ipath_physshadow[porttid + tid],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
ipath_release_user_pages(
&dd->ipath_pageshadow[porttid + tid], 1);
dd->ipath_pageshadow[porttid + tid] = NULL;
@@ -456,7 +564,7 @@ static int ipath_set_part_key(struct ipath_portdata *pd, u16 key)
u16 lkey = key & 0x7FFF;
int ret;
- if (lkey == (IPS_DEFAULT_P_KEY & 0x7FFF)) {
+ if (lkey == (IPATH_DEFAULT_P_KEY & 0x7FFF)) {
/* nothing to do; this key always valid */
ret = 0;
goto bail;
@@ -580,20 +688,24 @@ bail:
/**
* ipath_manage_rcvq - manage a port's receive queue
* @pd: the port
+ * @subport: the subport
* @start_stop: action to carry out
*
* start_stop == 0 disables receive on the port, for use in queue
* overflow conditions. start_stop==1 re-enables, to be used to
* re-init the software copy of the head register
*/
-static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
+static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
+ int start_stop)
{
struct ipath_devdata *dd = pd->port_dd;
u64 tval;
- ipath_cdbg(PROC, "%sabling rcv for unit %u port %u\n",
+ ipath_cdbg(PROC, "%sabling rcv for unit %u port %u:%u\n",
start_stop ? "en" : "dis", dd->ipath_unit,
- pd->port_port);
+ pd->port_port, subport);
+ if (subport)
+ goto bail;
/* atomically clear receive enable port. */
if (start_stop) {
/*
@@ -608,7 +720,7 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
* updated and correct itself, even in the face of software
* bugs.
*/
- *pd->port_rcvhdrtail_kvaddr = 0;
+ *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
&dd->ipath_rcvctrl);
} else
@@ -629,6 +741,7 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
tval = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
}
/* always; new head should be equal to new tail; see above */
+bail:
return 0;
}
@@ -686,6 +799,36 @@ static void ipath_clean_part_key(struct ipath_portdata *pd,
}
}
+/*
+ * Initialize the port data with the receive buffer sizes
+ * so this can be done while the master port is locked.
+ * Otherwise, there is a race with a slave opening the port
+ * and seeing these fields uninitialized.
+ */
+static void init_user_egr_sizes(struct ipath_portdata *pd)
+{
+ struct ipath_devdata *dd = pd->port_dd;
+ unsigned egrperchunk, egrcnt, size;
+
+ /*
+ * to avoid wasting a lot of memory, we allocate 32KB chunks of
+ * physically contiguous memory, advance through it until used up
+ * and then allocate more. Of course, we need memory to store those
+ * extra pointers, now. Started out with 256KB, but under heavy
+ * memory pressure (creating large files and then copying them over
+ * NFS while doing lots of MPI jobs), we hit some allocation
+ * failures, even though we can sleep... (2.6.10) Still get
+ * failures at 64K. 32K is the lowest we can go without wasting
+ * additional memory.
+ */
+ size = 0x8000;
+ egrperchunk = size / dd->ipath_rcvegrbufsize;
+ egrcnt = dd->ipath_rcvegrcnt;
+ pd->port_rcvegrbuf_chunks = (egrcnt + egrperchunk - 1) / egrperchunk;
+ pd->port_rcvegrbufs_perchunk = egrperchunk;
+ pd->port_rcvegrbuf_size = size;
+}
+
/**
* ipath_create_user_egr - allocate eager TID buffers
* @pd: the port to allocate TID buffers for
@@ -701,9 +844,18 @@ static void ipath_clean_part_key(struct ipath_portdata *pd,
static int ipath_create_user_egr(struct ipath_portdata *pd)
{
struct ipath_devdata *dd = pd->port_dd;
- unsigned e, egrcnt, alloced, egrperchunk, chunk, egrsize, egroff;
+ unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
size_t size;
int ret;
+ gfp_t gfp_flags;
+
+ /*
+ * GFP_USER, but without GFP_FS, so buffer cache can be
+ * coalesced (we hope); otherwise, even at order 4,
+ * heavy filesystem activity makes these fail, and we can
+ * use compound pages.
+ */
+ gfp_flags = __GFP_WAIT | __GFP_IO | __GFP_COMP;
egrcnt = dd->ipath_rcvegrcnt;
/* TID number offset for this port */
@@ -712,44 +864,23 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
"offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
- /*
- * to avoid wasting a lot of memory, we allocate 32KB chunks of
- * physically contiguous memory, advance through it until used up
- * and then allocate more. Of course, we need memory to store those
- * extra pointers, now. Started out with 256KB, but under heavy
- * memory pressure (creating large files and then copying them over
- * NFS while doing lots of MPI jobs), we hit some allocation
- * failures, even though we can sleep... (2.6.10) Still get
- * failures at 64K. 32K is the lowest we can go without waiting
- * more memory again. It seems likely that the coalescing in
- * free_pages, etc. still has issues (as it has had previously
- * during 2.6.x development).
- */
- size = 0x8000;
- alloced = ALIGN(egrsize * egrcnt, size);
- egrperchunk = size / egrsize;
- chunk = (egrcnt + egrperchunk - 1) / egrperchunk;
- pd->port_rcvegrbuf_chunks = chunk;
- pd->port_rcvegrbufs_perchunk = egrperchunk;
- pd->port_rcvegrbuf_size = size;
- pd->port_rcvegrbuf = vmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]));
+ chunk = pd->port_rcvegrbuf_chunks;
+ egrperchunk = pd->port_rcvegrbufs_perchunk;
+ size = pd->port_rcvegrbuf_size;
+ pd->port_rcvegrbuf = kmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]),
+ GFP_KERNEL);
if (!pd->port_rcvegrbuf) {
ret = -ENOMEM;
goto bail;
}
pd->port_rcvegrbuf_phys =
- vmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]));
+ kmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]),
+ GFP_KERNEL);
if (!pd->port_rcvegrbuf_phys) {
ret = -ENOMEM;
goto bail_rcvegrbuf;
}
for (e = 0; e < pd->port_rcvegrbuf_chunks; e++) {
- /*
- * GFP_USER, but without GFP_FS, so buffer cache can be
- * coalesced (we hope); otherwise, even at order 4,
- * heavy filesystem activity makes these fail
- */
- gfp_t gfp_flags = __GFP_WAIT | __GFP_IO | __GFP_COMP;
pd->port_rcvegrbuf[e] = dma_alloc_coherent(
&dd->pcidev->dev, size, &pd->port_rcvegrbuf_phys[e],
@@ -783,154 +914,63 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
bail_rcvegrbuf_phys:
for (e = 0; e < pd->port_rcvegrbuf_chunks &&
- pd->port_rcvegrbuf[e]; e++)
+ pd->port_rcvegrbuf[e]; e++) {
dma_free_coherent(&dd->pcidev->dev, size,
pd->port_rcvegrbuf[e],
pd->port_rcvegrbuf_phys[e]);
- vfree(pd->port_rcvegrbuf_phys);
+ }
+ kfree(pd->port_rcvegrbuf_phys);
pd->port_rcvegrbuf_phys = NULL;
bail_rcvegrbuf:
- vfree(pd->port_rcvegrbuf);
+ kfree(pd->port_rcvegrbuf);
pd->port_rcvegrbuf = NULL;
bail:
return ret;
}
-static int ipath_do_user_init(struct ipath_portdata *pd,
- const struct ipath_user_info *uinfo)
+
+/* common code for the mappings on dma_alloc_coherent mem */
+static int ipath_mmap_mem(struct vm_area_struct *vma,
+ struct ipath_portdata *pd, unsigned len, int write_ok,
+ void *kvaddr, char *what)
{
- int ret = 0;
struct ipath_devdata *dd = pd->port_dd;
- u64 physaddr, uaddr, off, atmp;
- struct page *pagep;
- u32 head32;
- u64 head;
+ unsigned long pfn;
+ int ret;
- /* for now, if major version is different, bail */
- if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
+ if ((vma->vm_end - vma->vm_start) > len) {
dev_info(&dd->pcidev->dev,
- "User major version %d not same as driver "
- "major %d\n", uinfo->spu_userversion >> 16,
- IPATH_USER_SWMAJOR);
- ret = -ENODEV;
- goto done;
- }
-
- if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR)
- ipath_dbg("User minor version %d not same as driver "
- "minor %d\n", uinfo->spu_userversion & 0xffff,
- IPATH_USER_SWMINOR);
-
- if (uinfo->spu_rcvhdrsize) {
- ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
- if (ret)
- goto done;
+ "FAIL on %s: len %lx > %x\n", what,
+ vma->vm_end - vma->vm_start, len);
+ ret = -EFAULT;
+ goto bail;
}
- /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
-
- /* set up for the rcvhdr Q tail register writeback to user memory */
- if (!uinfo->spu_rcvhdraddr ||
- !access_ok(VERIFY_WRITE, (u64 __user *) (unsigned long)
- uinfo->spu_rcvhdraddr, sizeof(u64))) {
- ipath_dbg("Port %d rcvhdrtail addr %llx not valid\n",
- pd->port_port,
- (unsigned long long) uinfo->spu_rcvhdraddr);
- ret = -EINVAL;
- goto done;
- }
+ if (!write_ok) {
+ if (vma->vm_flags & VM_WRITE) {
+ dev_info(&dd->pcidev->dev,
+ "%s must be mapped readonly\n", what);
+ ret = -EPERM;
+ goto bail;
+ }
- off = offset_in_page(uinfo->spu_rcvhdraddr);
- uaddr = PAGE_MASK & (unsigned long) uinfo->spu_rcvhdraddr;
- ret = ipath_get_user_pages_nocopy(uaddr, &pagep);
- if (ret) {
- dev_info(&dd->pcidev->dev, "Failed to lookup and lock "
- "address %llx for rcvhdrtail: errno %d\n",
- (unsigned long long) uinfo->spu_rcvhdraddr, -ret);
- goto done;
+ /* don't allow them to later change with mprotect */
+ vma->vm_flags &= ~VM_MAYWRITE;
}
- ipath_stats.sps_pagelocks++;
- pd->port_rcvhdrtail_uaddr = uaddr;
- pd->port_rcvhdrtail_pagep = pagep;
- pd->port_rcvhdrtail_kvaddr =
- page_address(pagep);
- pd->port_rcvhdrtail_kvaddr += off;
- physaddr = page_to_phys(pagep) + off;
- ipath_cdbg(VERBOSE, "port %d user addr %llx hdrtailaddr, %llx "
- "physical (off=%llx)\n",
- pd->port_port,
- (unsigned long long) uinfo->spu_rcvhdraddr,
- (unsigned long long) physaddr, (unsigned long long) off);
- ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
- pd->port_port, physaddr);
- atmp = ipath_read_kreg64_port(dd,
- dd->ipath_kregs->kr_rcvhdrtailaddr,
- pd->port_port);
- if (physaddr != atmp) {
- ipath_dev_err(dd,
- "Catastrophic software error, "
- "RcvHdrTailAddr%u written as %llx, "
- "read back as %llx\n", pd->port_port,
- (unsigned long long) physaddr,
- (unsigned long long) atmp);
- ret = -EINVAL;
- goto done;
- }
-
- /* for right now, kernel piobufs are at end, so port 1 is at 0 */
- pd->port_piobufs = dd->ipath_piobufbase +
- dd->ipath_pbufsport * (pd->port_port -
- 1) * dd->ipath_palign;
- ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
- pd->port_port, pd->port_piobufs);
- /*
- * Now allocate the rcvhdr Q and eager TIDs; skip the TID
- * array for time being. If pd->port_port > chip-supported,
- * we need to do extra stuff here to handle by handling overflow
- * through port 0, someday
- */
- ret = ipath_create_rcvhdrq(dd, pd);
- if (!ret)
- ret = ipath_create_user_egr(pd);
+ pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
+ ret = remap_pfn_range(vma, vma->vm_start, pfn,
+ len, vma->vm_page_prot);
if (ret)
- goto done;
- /* enable receives now */
- /* atomically set enable bit for this port */
- set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
- &dd->ipath_rcvctrl);
-
- /*
- * set the head registers for this port to the current values
- * of the tail pointers, since we don't know if they were
- * updated on last use of the port.
- */
- head32 = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
- head = (u64) head32;
- ipath_write_ureg(dd, ur_rcvhdrhead, head, pd->port_port);
- head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
- ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
- dd->ipath_lastegrheads[pd->port_port] = -1;
- dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
- ipath_cdbg(VERBOSE, "Wrote port%d head %llx, egrhead %x from "
- "tail regs\n", pd->port_port,
- (unsigned long long) head, head32);
- pd->port_tidcursor = 0; /* start at beginning after open */
- /*
- * now enable the port; the tail registers will be written to memory
- * by the chip as soon as it sees the write to
- * dd->ipath_kregs->kr_rcvctrl. The update only happens on
- * transition from 0 to 1, so clear it first, then set it as part of
- * enabling the port. This will (very briefly) affect any other
- * open ports, but it shouldn't be long enough to be an issue.
- */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl);
-
-done:
+ dev_info(&dd->pcidev->dev, "%s port%u mmap of %lx, %x "
+ "bytes r%c failed: %d\n", what, pd->port_port,
+ pfn, len, write_ok?'w':'o', ret);
+ else
+ ipath_cdbg(VERBOSE, "%s port%u mmaped %lx, %x bytes "
+ "r%c\n", what, pd->port_port, pfn, len,
+ write_ok?'w':'o');
+bail:
return ret;
}
@@ -940,8 +980,11 @@ static int mmap_ureg(struct vm_area_struct *vma, struct ipath_devdata *dd,
unsigned long phys;
int ret;
- /* it's the real hardware, so io_remap works */
-
+ /*
+ * This is real hardware, so use io_remap. This is the mechanism
+ * for the user process to update the head registers for their port
+ * in the chip.
+ */
if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) {
dev_info(&dd->pcidev->dev, "FAIL mmap userreg: reqlen "
"%lx > PAGE\n", vma->vm_end - vma->vm_start);
@@ -961,44 +1004,45 @@ static int mmap_ureg(struct vm_area_struct *vma, struct ipath_devdata *dd,
static int mmap_piobufs(struct vm_area_struct *vma,
struct ipath_devdata *dd,
- struct ipath_portdata *pd)
+ struct ipath_portdata *pd,
+ unsigned piobufs, unsigned piocnt)
{
unsigned long phys;
int ret;
/*
- * When we map the PIO buffers, we want to map them as writeonly, no
- * read possible.
+ * When we map the PIO buffers in the chip, we want to map them as
+ * writeonly, no read possible. This prevents access to previous
+ * process data, and catches users who might try to read the i/o
+ * space due to a bug.
*/
-
- if ((vma->vm_end - vma->vm_start) >
- (dd->ipath_pbufsport * dd->ipath_palign)) {
+ if ((vma->vm_end - vma->vm_start) > (piocnt * dd->ipath_palign)) {
dev_info(&dd->pcidev->dev, "FAIL mmap piobufs: "
"reqlen %lx > PAGE\n",
vma->vm_end - vma->vm_start);
- ret = -EFAULT;
+ ret = -EINVAL;
goto bail;
}
- phys = dd->ipath_physaddr + pd->port_piobufs;
+ phys = dd->ipath_physaddr + piobufs;
+
/*
- * Do *NOT* mark this as non-cached (PWT bit), or we don't get the
+ * Don't mark this as non-cached, or we don't get the
* write combining behavior we want on the PIO buffers!
- * vma->vm_page_prot =
- * pgprot_noncached(vma->vm_page_prot);
*/
- if (vma->vm_flags & VM_READ) {
- dev_info(&dd->pcidev->dev,
- "Can't map piobufs as readable (flags=%lx)\n",
- vma->vm_flags);
- ret = -EPERM;
- goto bail;
- }
-
- /* don't allow them to later change to readable with mprotect */
+#if defined(__powerpc__)
+ /* There isn't a generic way to specify writethrough mappings */
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE;
+ pgprot_val(vma->vm_page_prot) |= _PAGE_WRITETHRU;
+ pgprot_val(vma->vm_page_prot) &= ~_PAGE_GUARDED;
+#endif
- vma->vm_flags &= ~VM_MAYWRITE;
+ /*
+ * don't allow them to later change to readable with mprotect (for when
+ * not initially mapped readable, as is normally the case)
+ */
+ vma->vm_flags &= ~VM_MAYREAD;
vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND;
ret = io_remap_pfn_range(vma, vma->vm_start, phys >> PAGE_SHIFT,
@@ -1014,14 +1058,9 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
struct ipath_devdata *dd = pd->port_dd;
unsigned long start, size;
size_t total_size, i;
- dma_addr_t *phys;
+ unsigned long pfn;
int ret;
- if (!pd->port_rcvegrbuf) {
- ret = -EFAULT;
- goto bail;
- }
-
size = pd->port_rcvegrbuf_size;
total_size = pd->port_rcvegrbuf_chunks * size;
if ((vma->vm_end - vma->vm_start) > total_size) {
@@ -1029,7 +1068,7 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
"reqlen %lx > actual %lx\n",
vma->vm_end - vma->vm_start,
(unsigned long) total_size);
- ret = -EFAULT;
+ ret = -EINVAL;
goto bail;
}
@@ -1039,16 +1078,15 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
ret = -EPERM;
goto bail;
}
-
- start = vma->vm_start;
- phys = pd->port_rcvegrbuf_phys;
-
/* don't allow them to later change to writeable with mprotect */
vma->vm_flags &= ~VM_MAYWRITE;
+ start = vma->vm_start;
+
for (i = 0; i < pd->port_rcvegrbuf_chunks; i++, start += size) {
- ret = remap_pfn_range(vma, start, phys[i] >> PAGE_SHIFT,
- size, vma->vm_page_prot);
+ pfn = virt_to_phys(pd->port_rcvegrbuf[i]) >> PAGE_SHIFT;
+ ret = remap_pfn_range(vma, start, pfn, size,
+ vma->vm_page_prot);
if (ret < 0)
goto bail;
}
@@ -1058,74 +1096,118 @@ bail:
return ret;
}
-static int mmap_rcvhdrq(struct vm_area_struct *vma,
- struct ipath_portdata *pd)
+/*
+ * ipath_file_vma_nopage - handle a VMA page fault.
+ */
+static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
{
- struct ipath_devdata *dd = pd->port_dd;
- size_t total_size;
- int ret;
+ unsigned long offset = address - vma->vm_start;
+ struct page *page = NOPAGE_SIGBUS;
+ void *pageptr;
/*
- * kmalloc'ed memory, physically contiguous; this is from
- * spi_rcvhdr_base; we allow user to map read-write so they can
- * write hdrq entries to allow protocol code to directly poll
- * whether a hdrq entry has been written.
+ * Convert the vmalloc address into a struct page.
*/
- total_size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
- sizeof(u32), PAGE_SIZE);
- if ((vma->vm_end - vma->vm_start) > total_size) {
- dev_info(&dd->pcidev->dev,
- "FAIL on rcvhdrq: reqlen %lx > actual %lx\n",
- vma->vm_end - vma->vm_start,
- (unsigned long) total_size);
- ret = -EFAULT;
- goto bail;
- }
-
- ret = remap_pfn_range(vma, vma->vm_start,
- pd->port_rcvhdrq_phys >> PAGE_SHIFT,
- vma->vm_end - vma->vm_start,
- vma->vm_page_prot);
-bail:
- return ret;
+ pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
+ page = vmalloc_to_page(pageptr);
+ if (!page)
+ goto out;
+
+ /* Increment the reference count. */
+ get_page(page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+out:
+ return page;
}
-static int mmap_pioavailregs(struct vm_area_struct *vma,
- struct ipath_portdata *pd)
+static struct vm_operations_struct ipath_file_vm_ops = {
+ .nopage = ipath_file_vma_nopage,
+};
+
+static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
+ struct ipath_portdata *pd, unsigned subport)
{
- struct ipath_devdata *dd = pd->port_dd;
+ unsigned long len;
+ struct ipath_devdata *dd;
+ void *addr;
+ size_t size;
int ret;
+ /* If the port is not shared, all addresses should be physical */
+ if (!pd->port_subport_cnt) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ dd = pd->port_dd;
+ size = pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size;
+
/*
- * when we map the PIO bufferavail registers, we want to map them as
- * readonly, no write possible.
- *
- * kmalloc'ed memory, physically contiguous, one page only, readonly
+ * Master has all the slave uregbase, rcvhdrq, and
+ * rcvegrbufs mmapped.
*/
-
- if ((vma->vm_end - vma->vm_start) > PAGE_SIZE) {
- dev_info(&dd->pcidev->dev, "FAIL on pioavailregs_dma: "
- "reqlen %lx > actual %lx\n",
- vma->vm_end - vma->vm_start,
- (unsigned long) PAGE_SIZE);
- ret = -EFAULT;
+ if (subport == 0) {
+ unsigned num_slaves = pd->port_subport_cnt - 1;
+
+ if (pgaddr == ((u64) pd->subport_uregbase & MMAP64_MASK)) {
+ addr = pd->subport_uregbase;
+ size = PAGE_SIZE * num_slaves;
+ } else if (pgaddr == ((u64) pd->subport_rcvhdr_base &
+ MMAP64_MASK)) {
+ addr = pd->subport_rcvhdr_base;
+ size = pd->port_rcvhdrq_size * num_slaves;
+ } else if (pgaddr == ((u64) pd->subport_rcvegrbuf &
+ MMAP64_MASK)) {
+ addr = pd->subport_rcvegrbuf;
+ size *= num_slaves;
+ } else {
+ ret = -EINVAL;
+ goto bail;
+ }
+ } else if (pgaddr == (((u64) pd->subport_uregbase +
+ PAGE_SIZE * (subport - 1)) & MMAP64_MASK)) {
+ addr = pd->subport_uregbase + PAGE_SIZE * (subport - 1);
+ size = PAGE_SIZE;
+ } else if (pgaddr == (((u64) pd->subport_rcvhdr_base +
+ pd->port_rcvhdrq_size * (subport - 1)) &
+ MMAP64_MASK)) {
+ addr = pd->subport_rcvhdr_base +
+ pd->port_rcvhdrq_size * (subport - 1);
+ size = pd->port_rcvhdrq_size;
+ } else if (pgaddr == (((u64) pd->subport_rcvegrbuf +
+ size * (subport - 1)) & MMAP64_MASK)) {
+ addr = pd->subport_rcvegrbuf + size * (subport - 1);
+ /* rcvegrbufs are read-only on the slave */
+ if (vma->vm_flags & VM_WRITE) {
+ dev_info(&dd->pcidev->dev,
+ "Can't map eager buffers as "
+ "writable (flags=%lx)\n", vma->vm_flags);
+ ret = -EPERM;
+ goto bail;
+ }
+ /*
+ * Don't allow permission to later change to writeable
+ * with mprotect.
+ */
+ vma->vm_flags &= ~VM_MAYWRITE;
+ } else {
+ ret = -EINVAL;
goto bail;
}
-
- if (vma->vm_flags & VM_WRITE) {
- dev_info(&dd->pcidev->dev,
- "Can't map pioavailregs as writable (flags=%lx)\n",
- vma->vm_flags);
- ret = -EPERM;
+ len = vma->vm_end - vma->vm_start;
+ if (len > size) {
+ ipath_cdbg(MM, "FAIL: reqlen %lx > %zx\n", len, size);
+ ret = -EINVAL;
goto bail;
}
- /* don't allow them to later change with mprotect */
- vma->vm_flags &= ~VM_MAYWRITE;
+ vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
+ vma->vm_ops = &ipath_file_vm_ops;
+ vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+ ret = 0;
- ret = remap_pfn_range(vma, vma->vm_start,
- dd->ipath_pioavailregs_phys >> PAGE_SHIFT,
- PAGE_SIZE, vma->vm_page_prot);
bail:
return ret;
}
@@ -1145,41 +1227,99 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
struct ipath_portdata *pd;
struct ipath_devdata *dd;
u64 pgaddr, ureg;
+ unsigned piobufs, piocnt;
int ret;
pd = port_fp(fp);
+ if (!pd) {
+ ret = -EINVAL;
+ goto bail;
+ }
dd = pd->port_dd;
+
/*
* This is the ipath_do_user_init() code, mapping the shared buffers
* into the user process. The address referred to by vm_pgoff is the
- * virtual, not physical, address; we only do one mmap for each
- * space mapped.
+ * file offset passed via mmap(). For shared ports, this is the
+ * kernel vmalloc() address of the pages to share with the master.
+ * For non-shared or master ports, this is a physical address.
+ * We only do one mmap for each space mapped.
*/
pgaddr = vma->vm_pgoff << PAGE_SHIFT;
/*
- * note that ureg does *NOT* have the kregvirt as part of it, to be
- * sure that for 32 bit programs, we don't end up trying to map a >
- * 44 address. Has to match ipath_get_base_info() code that sets
- * __spi_uregbase
+ * Check for 0 in case one of the allocations failed, but user
+ * called mmap anyway.
*/
+ if (!pgaddr) {
+ ret = -EINVAL;
+ goto bail;
+ }
- ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
-
- ipath_cdbg(MM, "ushare: pgaddr %llx vm_start=%lx, vmlen %lx\n",
+ ipath_cdbg(MM, "pgaddr %llx vm_start=%lx len %lx port %u:%u:%u\n",
(unsigned long long) pgaddr, vma->vm_start,
- vma->vm_end - vma->vm_start);
+ vma->vm_end - vma->vm_start, dd->ipath_unit,
+ pd->port_port, subport_fp(fp));
+
+ /*
+ * Physical addresses must fit in 40 bits for our hardware.
+ * Check for kernel virtual addresses first, anything else must
+ * match a HW or memory address.
+ */
+ if (pgaddr >= (1ULL<<40)) {
+ ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
+ goto bail;
+ }
+
+ if (!pd->port_subport_cnt) {
+ /* port is not shared */
+ ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+ piocnt = dd->ipath_pbufsport;
+ piobufs = pd->port_piobufs;
+ } else if (!subport_fp(fp)) {
+ /* caller is the master */
+ ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+ piocnt = (dd->ipath_pbufsport / pd->port_subport_cnt) +
+ (dd->ipath_pbufsport % pd->port_subport_cnt);
+ piobufs = pd->port_piobufs +
+ dd->ipath_palign * (dd->ipath_pbufsport - piocnt);
+ } else {
+ unsigned slave = subport_fp(fp) - 1;
+
+ /* caller is a slave */
+ ureg = 0;
+ piocnt = dd->ipath_pbufsport / pd->port_subport_cnt;
+ piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave;
+ }
if (pgaddr == ureg)
ret = mmap_ureg(vma, dd, ureg);
- else if (pgaddr == pd->port_piobufs)
- ret = mmap_piobufs(vma, dd, pd);
- else if (pgaddr == (u64) pd->port_rcvegr_phys)
+ else if (pgaddr == piobufs)
+ ret = mmap_piobufs(vma, dd, pd, piobufs, piocnt);
+ else if (pgaddr == dd->ipath_pioavailregs_phys)
+ /* in-memory copy of pioavail registers */
+ ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
+ (void *) dd->ipath_pioavailregs_dma,
+ "pioavail registers");
+ else if (subport_fp(fp))
+ /* Subports don't mmap the physical receive buffers */
+ ret = -EINVAL;
+ else if (pgaddr == pd->port_rcvegr_phys)
ret = mmap_rcvegrbufs(vma, pd);
else if (pgaddr == (u64) pd->port_rcvhdrq_phys)
- ret = mmap_rcvhdrq(vma, pd);
- else if (pgaddr == dd->ipath_pioavailregs_phys)
- ret = mmap_pioavailregs(vma, pd);
+ /*
+ * The rcvhdrq itself; readonly except on HT (so have
+ * to allow writable mapping), multiple pages, contiguous
+ * from an i/o perspective.
+ */
+ ret = ipath_mmap_mem(vma, pd, pd->port_rcvhdrq_size, 1,
+ pd->port_rcvhdrq,
+ "rcvhdrq");
+ else if (pgaddr == (u64) pd->port_rcvhdrqtailaddr_phys)
+ /* in-memory copy of rcvhdrq tail register */
+ ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
+ pd->port_rcvhdrtail_kvaddr,
+ "rcvhdrq tail");
else
ret = -EINVAL;
@@ -1187,9 +1327,10 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
if (ret < 0)
dev_info(&dd->pcidev->dev,
- "Failure %d on addr %lx, off %lx\n",
- -ret, vma->vm_start, vma->vm_pgoff);
-
+ "Failure %d on off %llx len %lx\n",
+ -ret, (unsigned long long)pgaddr,
+ vma->vm_end - vma->vm_start);
+bail:
return ret;
}
@@ -1199,9 +1340,12 @@ static unsigned int ipath_poll(struct file *fp,
struct ipath_portdata *pd;
u32 head, tail;
int bit;
+ unsigned pollflag = 0;
struct ipath_devdata *dd;
pd = port_fp(fp);
+ if (!pd)
+ goto bail;
dd = pd->port_dd;
bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT;
@@ -1224,7 +1368,7 @@ static unsigned int ipath_poll(struct file *fp,
if (tail == head) {
set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
- if(dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
+ if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
(void)ipath_write_ureg(dd, ur_rcvhdrhead,
dd->ipath_rhdrhead_intr_off
| head, pd->port_port);
@@ -1235,9 +1379,12 @@ static unsigned int ipath_poll(struct file *fp,
clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
pd->port_rcvwait_to++;
}
+ else
+ pollflag = POLLIN | POLLRDNORM;
}
else {
/* it's already happened; don't do wait_event overhead */
+ pollflag = POLLIN | POLLRDNORM;
pd->port_rcvnowait++;
}
@@ -1245,18 +1392,80 @@ static unsigned int ipath_poll(struct file *fp,
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
- return 0;
+bail:
+ return pollflag;
+}
+
+static int init_subports(struct ipath_devdata *dd,
+ struct ipath_portdata *pd,
+ const struct ipath_user_info *uinfo)
+{
+ int ret = 0;
+ unsigned num_slaves;
+ size_t size;
+
+ /* Old user binaries don't know about subports */
+ if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR)
+ goto bail;
+ /*
+ * If the user is requesting zero or one port,
+ * skip the subport allocation.
+ */
+ if (uinfo->spu_subport_cnt <= 1)
+ goto bail;
+ if (uinfo->spu_subport_cnt > 4) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ num_slaves = uinfo->spu_subport_cnt - 1;
+ pd->subport_uregbase = vmalloc(PAGE_SIZE * num_slaves);
+ if (!pd->subport_uregbase) {
+ ret = -ENOMEM;
+ goto bail;
+ }
+ /* Note: pd->port_rcvhdrq_size isn't initialized yet. */
+ size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
+ sizeof(u32), PAGE_SIZE) * num_slaves;
+ pd->subport_rcvhdr_base = vmalloc(size);
+ if (!pd->subport_rcvhdr_base) {
+ ret = -ENOMEM;
+ goto bail_ureg;
+ }
+
+ pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks *
+ pd->port_rcvegrbuf_size *
+ num_slaves);
+ if (!pd->subport_rcvegrbuf) {
+ ret = -ENOMEM;
+ goto bail_rhdr;
+ }
+
+ pd->port_subport_cnt = uinfo->spu_subport_cnt;
+ pd->port_subport_id = uinfo->spu_subport_id;
+ pd->active_slaves = 1;
+ goto bail;
+
+bail_rhdr:
+ vfree(pd->subport_rcvhdr_base);
+bail_ureg:
+ vfree(pd->subport_uregbase);
+ pd->subport_uregbase = NULL;
+bail:
+ return ret;
}
static int try_alloc_port(struct ipath_devdata *dd, int port,
- struct file *fp)
+ struct file *fp,
+ const struct ipath_user_info *uinfo)
{
+ struct ipath_portdata *pd;
int ret;
- if (!dd->ipath_pd[port]) {
- void *p, *ptmp;
+ if (!(pd = dd->ipath_pd[port])) {
+ void *ptmp;
- p = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
+ pd = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
/*
* Allocate memory for use in ipath_tid_update() just once
@@ -1266,34 +1475,36 @@ static int try_alloc_port(struct ipath_devdata *dd, int port,
ptmp = kmalloc(dd->ipath_rcvtidcnt * sizeof(u16) +
dd->ipath_rcvtidcnt * sizeof(struct page **),
GFP_KERNEL);
- if (!p || !ptmp) {
+ if (!pd || !ptmp) {
ipath_dev_err(dd, "Unable to allocate portdata "
"memory, failing open\n");
ret = -ENOMEM;
- kfree(p);
+ kfree(pd);
kfree(ptmp);
goto bail;
}
- dd->ipath_pd[port] = p;
+ dd->ipath_pd[port] = pd;
dd->ipath_pd[port]->port_port = port;
dd->ipath_pd[port]->port_dd = dd;
dd->ipath_pd[port]->port_tid_pg_list = ptmp;
init_waitqueue_head(&dd->ipath_pd[port]->port_wait);
}
- if (!dd->ipath_pd[port]->port_cnt) {
- dd->ipath_pd[port]->port_cnt = 1;
- fp->private_data = (void *) dd->ipath_pd[port];
+ if (!pd->port_cnt) {
+ pd->userversion = uinfo->spu_userversion;
+ init_user_egr_sizes(pd);
+ if ((ret = init_subports(dd, pd, uinfo)) != 0)
+ goto bail;
ipath_cdbg(PROC, "%s[%u] opened unit:port %u:%u\n",
current->comm, current->pid, dd->ipath_unit,
port);
- dd->ipath_pd[port]->port_pid = current->pid;
- strncpy(dd->ipath_pd[port]->port_comm, current->comm,
- sizeof(dd->ipath_pd[port]->port_comm));
+ pd->port_cnt = 1;
+ port_fp(fp) = pd;
+ pd->port_pid = current->pid;
+ strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm));
ipath_stats.sps_ports++;
ret = 0;
- goto bail;
- }
- ret = -EBUSY;
+ } else
+ ret = -EBUSY;
bail:
return ret;
@@ -1309,7 +1520,8 @@ static inline int usable(struct ipath_devdata *dd)
| IPATH_LINKUNK));
}
-static int find_free_port(int unit, struct file *fp)
+static int find_free_port(int unit, struct file *fp,
+ const struct ipath_user_info *uinfo)
{
struct ipath_devdata *dd = ipath_lookup(unit);
int ret, i;
@@ -1324,8 +1536,8 @@ static int find_free_port(int unit, struct file *fp)
goto bail;
}
- for (i = 0; i < dd->ipath_cfgports; i++) {
- ret = try_alloc_port(dd, i, fp);
+ for (i = 1; i < dd->ipath_cfgports; i++) {
+ ret = try_alloc_port(dd, i, fp, uinfo);
if (ret != -EBUSY)
goto bail;
}
@@ -1335,26 +1547,27 @@ bail:
return ret;
}
-static int find_best_unit(struct file *fp)
+static int find_best_unit(struct file *fp,
+ const struct ipath_user_info *uinfo)
{
int ret = 0, i, prefunit = -1, devmax;
int maxofallports, npresent, nup;
int ndev;
- (void) ipath_count_units(&npresent, &nup, &maxofallports);
+ devmax = ipath_count_units(&npresent, &nup, &maxofallports);
/*
* This code is present to allow a knowledgeable person to
* specify the layout of processes to processors before opening
* this driver, and then we'll assign the process to the "closest"
- * HT-400 to that processor (we assume reasonable connectivity,
+ * InfiniPath chip to that processor (we assume reasonable connectivity,
* for now). This code assumes that if affinity has been set
* before this point, that at most one cpu is set; for now this
* is reasonable. I check for both cpus_empty() and cpus_full(),
* in case some kernel variant sets none of the bits when no
* affinity is set. 2.6.11 and 12 kernels have all present
* cpus set. Some day we'll have to fix it up further to handle
- * a cpu subset. This algorithm fails for two HT-400's connected
+ * a cpu subset. This algorithm fails for two HT chips connected
* in tunnel fashion. Eventually this needs real topology
* information. There may be some issues with dual core numbering
* as well. This needs more work prior to release.
@@ -1388,8 +1601,6 @@ static int find_best_unit(struct file *fp)
if (prefunit != -1)
devmax = prefunit + 1;
- else
- devmax = ipath_count_units(NULL, NULL, NULL);
recheck:
for (i = 1; i < maxofallports; i++) {
for (ndev = prefunit != -1 ? prefunit : 0; ndev < devmax;
@@ -1404,7 +1615,7 @@ recheck:
* next.
*/
continue;
- ret = try_alloc_port(dd, i, fp);
+ ret = try_alloc_port(dd, i, fp, uinfo);
if (!ret)
goto done;
}
@@ -1440,22 +1651,183 @@ done:
return ret;
}
+static int find_shared_port(struct file *fp,
+ const struct ipath_user_info *uinfo)
+{
+ int devmax, ndev, i;
+ int ret = 0;
+
+ devmax = ipath_count_units(NULL, NULL, NULL);
+
+ for (ndev = 0; ndev < devmax; ndev++) {
+ struct ipath_devdata *dd = ipath_lookup(ndev);
+
+ if (!dd)
+ continue;
+ for (i = 1; i < dd->ipath_cfgports; i++) {
+ struct ipath_portdata *pd = dd->ipath_pd[i];
+
+ /* Skip ports which are not yet open */
+ if (!pd || !pd->port_cnt)
+ continue;
+ /* Skip port if it doesn't match the requested one */
+ if (pd->port_subport_id != uinfo->spu_subport_id)
+ continue;
+ /* Verify the sharing process matches the master */
+ if (pd->port_subport_cnt != uinfo->spu_subport_cnt ||
+ pd->userversion != uinfo->spu_userversion ||
+ pd->port_cnt >= pd->port_subport_cnt) {
+ ret = -EINVAL;
+ goto done;
+ }
+ port_fp(fp) = pd;
+ subport_fp(fp) = pd->port_cnt++;
+ tidcursor_fp(fp) = 0;
+ pd->active_slaves |= 1 << subport_fp(fp);
+ ipath_cdbg(PROC,
+ "%s[%u] %u sharing %s[%u] unit:port %u:%u\n",
+ current->comm, current->pid,
+ subport_fp(fp),
+ pd->port_comm, pd->port_pid,
+ dd->ipath_unit, pd->port_port);
+ ret = 1;
+ goto done;
+ }
+ }
+
+done:
+ return ret;
+}
+
static int ipath_open(struct inode *in, struct file *fp)
{
- int ret, minor;
+ /* The real work is performed later in ipath_assign_port() */
+ fp->private_data = kzalloc(sizeof(struct ipath_filedata), GFP_KERNEL);
+ return fp->private_data ? 0 : -ENOMEM;
+}
+
+
+/* Get port early, so can set affinity prior to memory allocation */
+static int ipath_assign_port(struct file *fp,
+ const struct ipath_user_info *uinfo)
+{
+ int ret;
+ int i_minor;
+ unsigned swminor;
+
+ /* Check to be sure we haven't already initialized this file */
+ if (port_fp(fp)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* for now, if major version is different, bail */
+ if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
+ ipath_dbg("User major version %d not same as driver "
+ "major %d\n", uinfo->spu_userversion >> 16,
+ IPATH_USER_SWMAJOR);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ swminor = uinfo->spu_userversion & 0xffff;
+ if (swminor != IPATH_USER_SWMINOR)
+ ipath_dbg("User minor version %d not same as driver "
+ "minor %d\n", swminor, IPATH_USER_SWMINOR);
mutex_lock(&ipath_mutex);
- minor = iminor(in);
+ if (swminor == IPATH_USER_SWMINOR && uinfo->spu_subport_cnt &&
+ (ret = find_shared_port(fp, uinfo))) {
+ mutex_unlock(&ipath_mutex);
+ if (ret > 0)
+ ret = 0;
+ goto done;
+ }
+
+ i_minor = iminor(fp->f_dentry->d_inode) - IPATH_USER_MINOR_BASE;
ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n",
- (long)in->i_rdev, minor);
+ (long)fp->f_dentry->d_inode->i_rdev, i_minor);
- if (minor)
- ret = find_free_port(minor - 1, fp);
+ if (i_minor)
+ ret = find_free_port(i_minor - 1, fp, uinfo);
else
- ret = find_best_unit(fp);
+ ret = find_best_unit(fp, uinfo);
mutex_unlock(&ipath_mutex);
+
+done:
+ return ret;
+}
+
+
+static int ipath_do_user_init(struct file *fp,
+ const struct ipath_user_info *uinfo)
+{
+ int ret;
+ struct ipath_portdata *pd;
+ struct ipath_devdata *dd;
+ u32 head32;
+
+ pd = port_fp(fp);
+ dd = pd->port_dd;
+
+ if (uinfo->spu_rcvhdrsize) {
+ ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
+ if (ret)
+ goto done;
+ }
+
+ /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
+
+ /* for right now, kernel piobufs are at end, so port 1 is at 0 */
+ pd->port_piobufs = dd->ipath_piobufbase +
+ dd->ipath_pbufsport * (pd->port_port - 1) * dd->ipath_palign;
+ ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
+ pd->port_port, pd->port_piobufs);
+
+ /*
+ * Now allocate the rcvhdr Q and eager TIDs; skip the TID
+ * array for time being. If pd->port_port > chip-supported,
+ * we need to do extra stuff here to handle by handling overflow
+ * through port 0, someday
+ */
+ ret = ipath_create_rcvhdrq(dd, pd);
+ if (!ret)
+ ret = ipath_create_user_egr(pd);
+ if (ret)
+ goto done;
+
+ /*
+ * set the eager head register for this port to the current values
+ * of the tail pointers, since we don't know if they were
+ * updated on last use of the port.
+ */
+ head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
+ ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
+ dd->ipath_lastegrheads[pd->port_port] = -1;
+ dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
+ ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
+ pd->port_port, head32);
+ pd->port_tidcursor = 0; /* start at beginning after open */
+ /*
+ * now enable the port; the tail registers will be written to memory
+ * by the chip as soon as it sees the write to
+ * dd->ipath_kregs->kr_rcvctrl. The update only happens on
+ * transition from 0 to 1, so clear it first, then set it as part of
+ * enabling the port. This will (very briefly) affect any other
+ * open ports, but it shouldn't be long enough to be an issue.
+ * We explictly set the in-memory copy to 0 beforehand, so we don't
+ * have to wait to be sure the DMA update has happened.
+ */
+ *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
+ set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+ &dd->ipath_rcvctrl);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl);
+done:
return ret;
}
@@ -1478,6 +1850,8 @@ static void unlock_expected_tids(struct ipath_portdata *pd)
if (!dd->ipath_pageshadow[i])
continue;
+ pci_unmap_page(dd->pcidev, dd->ipath_physshadow[i],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
ipath_release_user_pages_on_close(&dd->ipath_pageshadow[i],
1);
dd->ipath_pageshadow[i] = NULL;
@@ -1498,6 +1872,7 @@ static void unlock_expected_tids(struct ipath_portdata *pd)
static int ipath_close(struct inode *in, struct file *fp)
{
int ret = 0;
+ struct ipath_filedata *fd;
struct ipath_portdata *pd;
struct ipath_devdata *dd;
unsigned port;
@@ -1507,9 +1882,24 @@ static int ipath_close(struct inode *in, struct file *fp)
mutex_lock(&ipath_mutex);
- pd = port_fp(fp);
- port = pd->port_port;
+ fd = (struct ipath_filedata *) fp->private_data;
fp->private_data = NULL;
+ pd = fd->pd;
+ if (!pd) {
+ mutex_unlock(&ipath_mutex);
+ goto bail;
+ }
+ if (--pd->port_cnt) {
+ /*
+ * XXX If the master closes the port before the slave(s),
+ * revoke the mmap for the eager receive queue so
+ * the slave(s) don't wait for receive data forever.
+ */
+ pd->active_slaves &= ~(1 << fd->subport);
+ mutex_unlock(&ipath_mutex);
+ goto bail;
+ }
+ port = pd->port_port;
dd = pd->port_dd;
if (pd->port_hdrqfull) {
@@ -1536,70 +1926,79 @@ static int ipath_close(struct inode *in, struct file *fp)
}
if (dd->ipath_kregbase) {
- if (pd->port_rcvhdrtail_uaddr) {
- pd->port_rcvhdrtail_uaddr = 0;
- pd->port_rcvhdrtail_kvaddr = NULL;
- ipath_release_user_pages_on_close(
- &pd->port_rcvhdrtail_pagep, 1);
- pd->port_rcvhdrtail_pagep = NULL;
- ipath_stats.sps_pageunlocks++;
- }
- ipath_write_kreg_port(
- dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
- port, 0ULL);
- ipath_write_kreg_port(
- dd, dd->ipath_kregs->kr_rcvhdraddr,
- pd->port_port, 0);
+ int i;
+ /* atomically clear receive enable port. */
+ clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
+ &dd->ipath_rcvctrl);
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl);
+ /* and read back from chip to be sure that nothing
+ * else is in flight when we do the rest */
+ (void)ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
/* clean up the pkeys for this port user */
ipath_clean_part_key(pd, dd);
+ /*
+ * be paranoid, and never write 0's to these, just use an
+ * unused part of the port 0 tail page. Of course,
+ * rcvhdraddr points to a large chunk of memory, so this
+ * could still trash things, but at least it won't trash
+ * page 0, and by disabling the port, it should stop "soon",
+ * even if a packet or two is in already in flight after we
+ * disabled the port.
+ */
+ ipath_write_kreg_port(dd,
+ dd->ipath_kregs->kr_rcvhdrtailaddr, port,
+ dd->ipath_dummy_hdrq_phys);
+ ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
+ pd->port_port, dd->ipath_dummy_hdrq_phys);
- if (port < dd->ipath_cfgports) {
- int i = dd->ipath_pbufsport * (port - 1);
- ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
+ i = dd->ipath_pbufsport * (port - 1);
+ ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
- /* atomically clear receive enable port. */
- clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
- &dd->ipath_rcvctrl);
- ipath_write_kreg(
- dd,
- dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl);
-
- if (dd->ipath_pageshadow)
- unlock_expected_tids(pd);
- ipath_stats.sps_ports--;
- ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
- pd->port_comm, pd->port_pid,
- dd->ipath_unit, port);
- }
+ dd->ipath_f_clear_tids(dd, pd->port_port);
+
+ if (dd->ipath_pageshadow)
+ unlock_expected_tids(pd);
+ ipath_stats.sps_ports--;
+ ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
+ pd->port_comm, pd->port_pid,
+ dd->ipath_unit, port);
}
- pd->port_cnt = 0;
pd->port_pid = 0;
-
- dd->ipath_f_clear_tids(dd, pd->port_port);
-
- ipath_free_pddata(dd, pd->port_port, 0);
-
+ dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
mutex_unlock(&ipath_mutex);
+ ipath_free_pddata(dd, pd); /* after releasing the mutex */
+bail:
+ kfree(fd);
return ret;
}
-static int ipath_port_info(struct ipath_portdata *pd,
+static int ipath_port_info(struct ipath_portdata *pd, u16 subport,
struct ipath_port_info __user *uinfo)
{
struct ipath_port_info info;
int nup;
int ret;
+ size_t sz;
(void) ipath_count_units(NULL, &nup, NULL);
info.num_active = nup;
info.unit = pd->port_dd->ipath_unit;
info.port = pd->port_port;
+ info.subport = subport;
+ /* Don't return new fields if old library opened the port. */
+ if ((pd->userversion & 0xffff) == IPATH_USER_SWMINOR) {
+ /* Number of user ports available for this device. */
+ info.num_ports = pd->port_dd->ipath_cfgports - 1;
+ info.num_subports = pd->port_subport_cnt;
+ sz = sizeof(info);
+ } else
+ sz = sizeof(info) - 2 * sizeof(u16);
- if (copy_to_user(uinfo, &info, sizeof(info))) {
+ if (copy_to_user(uinfo, &info, sz)) {
ret = -EFAULT;
goto bail;
}
@@ -1609,6 +2008,16 @@ bail:
return ret;
}
+static int ipath_get_slave_info(struct ipath_portdata *pd,
+ void __user *slave_mask_addr)
+{
+ int ret = 0;
+
+ if (copy_to_user(slave_mask_addr, &pd->active_slaves, sizeof(u32)))
+ ret = -EFAULT;
+ return ret;
+}
+
static ssize_t ipath_write(struct file *fp, const char __user *data,
size_t count, loff_t *off)
{
@@ -1635,6 +2044,8 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
consumed = sizeof(cmd.type);
switch (cmd.type) {
+ case IPATH_CMD_ASSIGN_PORT:
+ case __IPATH_CMD_USER_INIT:
case IPATH_CMD_USER_INIT:
copy = sizeof(cmd.cmd.user_info);
dest = &cmd.cmd.user_info;
@@ -1661,6 +2072,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
dest = &cmd.cmd.part_key;
src = &ucmd->cmd.part_key;
break;
+ case IPATH_CMD_SLAVE_INFO:
+ copy = sizeof(cmd.cmd.slave_mask_addr);
+ dest = &cmd.cmd.slave_mask_addr;
+ src = &ucmd->cmd.slave_mask_addr;
+ break;
default:
ret = -EINVAL;
goto bail;
@@ -1678,34 +2094,55 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
consumed += copy;
pd = port_fp(fp);
+ if (!pd && cmd.type != __IPATH_CMD_USER_INIT &&
+ cmd.type != IPATH_CMD_ASSIGN_PORT) {
+ ret = -EINVAL;
+ goto bail;
+ }
switch (cmd.type) {
+ case IPATH_CMD_ASSIGN_PORT:
+ ret = ipath_assign_port(fp, &cmd.cmd.user_info);
+ if (ret)
+ goto bail;
+ break;
+ case __IPATH_CMD_USER_INIT:
+ /* backwards compatibility, get port first */
+ ret = ipath_assign_port(fp, &cmd.cmd.user_info);
+ if (ret)
+ goto bail;
+ /* and fall through to current version. */
case IPATH_CMD_USER_INIT:
- ret = ipath_do_user_init(pd, &cmd.cmd.user_info);
- if (ret < 0)
+ ret = ipath_do_user_init(fp, &cmd.cmd.user_info);
+ if (ret)
goto bail;
ret = ipath_get_base_info(
- pd, (void __user *) (unsigned long)
+ fp, (void __user *) (unsigned long)
cmd.cmd.user_info.spu_base_info,
cmd.cmd.user_info.spu_base_info_size);
break;
case IPATH_CMD_RECV_CTRL:
- ret = ipath_manage_rcvq(pd, cmd.cmd.recv_ctrl);
+ ret = ipath_manage_rcvq(pd, subport_fp(fp), cmd.cmd.recv_ctrl);
break;
case IPATH_CMD_PORT_INFO:
- ret = ipath_port_info(pd,
+ ret = ipath_port_info(pd, subport_fp(fp),
(struct ipath_port_info __user *)
(unsigned long) cmd.cmd.port_info);
break;
case IPATH_CMD_TID_UPDATE:
- ret = ipath_tid_update(pd, &cmd.cmd.tid_info);
+ ret = ipath_tid_update(pd, fp, &cmd.cmd.tid_info);
break;
case IPATH_CMD_TID_FREE:
- ret = ipath_tid_free(pd, &cmd.cmd.tid_info);
+ ret = ipath_tid_free(pd, subport_fp(fp), &cmd.cmd.tid_info);
break;
case IPATH_CMD_SET_PART_KEY:
ret = ipath_set_part_key(pd, cmd.cmd.part_key);
break;
+ case IPATH_CMD_SLAVE_INFO:
+ ret = ipath_get_slave_info(pd,
+ (void __user *) (unsigned long)
+ cmd.cmd.slave_mask_addr);
+ break;
}
if (ret >= 0)
@@ -1859,19 +2296,12 @@ int ipath_user_add(struct ipath_devdata *dd)
"error %d\n", -ret);
goto bail;
}
- ret = ipath_diag_init();
- if (ret < 0) {
- ipath_dev_err(dd, "Unable to set up diag support: "
- "error %d\n", -ret);
- goto bail_sma;
- }
-
ret = init_cdev(0, "ipath", &ipath_file_ops, &wildcard_cdev,
&wildcard_class_dev);
if (ret < 0) {
ipath_dev_err(dd, "Could not create wildcard "
"minor: error %d\n", -ret);
- goto bail_diag;
+ goto bail_user;
}
atomic_set(&user_setup, 1);
@@ -1880,31 +2310,28 @@ int ipath_user_add(struct ipath_devdata *dd)
snprintf(name, sizeof(name), "ipath%d", dd->ipath_unit);
ret = init_cdev(dd->ipath_unit + 1, name, &ipath_file_ops,
- &dd->cdev, &dd->class_dev);
+ &dd->user_cdev, &dd->user_class_dev);
if (ret < 0)
ipath_dev_err(dd, "Could not create user minor %d, %s\n",
dd->ipath_unit + 1, name);
goto bail;
-bail_diag:
- ipath_diag_cleanup();
-bail_sma:
+bail_user:
user_cleanup();
bail:
return ret;
}
-void ipath_user_del(struct ipath_devdata *dd)
+void ipath_user_remove(struct ipath_devdata *dd)
{
- cleanup_cdev(&dd->cdev, &dd->class_dev);
+ cleanup_cdev(&dd->user_cdev, &dd->user_class_dev);
if (atomic_dec_return(&user_count) == 0) {
if (atomic_read(&user_setup) == 0)
goto bail;
cleanup_cdev(&wildcard_cdev, &wildcard_class_dev);
- ipath_diag_cleanup();
user_cleanup();
atomic_set(&user_setup, 0);
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 63de3046aff..a507d0b5be6 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -31,7 +32,6 @@
*/
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mount.h>
@@ -61,10 +61,9 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->u.generic_ip = data;
+ inode->i_private = data;
if ((mode & S_IFMT) == S_IFDIR) {
inode->i_op = &simple_dir_inode_operations;
inode->i_nlink++;
@@ -119,7 +118,7 @@ static ssize_t atomic_counters_read(struct file *file, char __user *buf,
u16 i;
struct ipath_devdata *dd;
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
for (i = 0; i < NUM_COUNTERS; i++)
counters[i] = ipath_snap_cntr(dd, i);
@@ -139,7 +138,7 @@ static ssize_t atomic_node_info_read(struct file *file, char __user *buf,
struct ipath_devdata *dd;
u64 guid;
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
guid = be64_to_cpu(dd->ipath_guid);
@@ -178,7 +177,7 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
u32 tmp, tmp2;
struct ipath_devdata *dd;
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
/* so we only initialize non-zero fields. */
memset(portinfo, 0, sizeof portinfo);
@@ -191,8 +190,8 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
portinfo[4] = (dd->ipath_lid << 16);
/*
- * Notimpl yet SMLID (should we store this in the driver, in case
- * SMA dies?) CapabilityMask is 0, we don't support any of these
+ * Notimpl yet SMLID.
+ * CapabilityMask is 0, we don't support any of these
* DiagCode is 0; we don't store any diag info for now Notimpl yet
* M_KeyLeasePeriod (we don't support M_Key)
*/
@@ -325,7 +324,7 @@ static ssize_t flash_read(struct file *file, char __user *buf,
goto bail;
}
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
if (ipath_eeprom_read(dd, pos, tmp, count)) {
ipath_dev_err(dd, "failed to read from flash\n");
ret = -ENXIO;
@@ -357,19 +356,16 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
pos = *ppos;
- if ( pos < 0) {
+ if (pos != 0) {
ret = -EINVAL;
goto bail;
}
- if (pos >= sizeof(struct ipath_flash)) {
- ret = 0;
+ if (count != sizeof(struct ipath_flash)) {
+ ret = -EINVAL;
goto bail;
}
- if (count > sizeof(struct ipath_flash) - pos)
- count = sizeof(struct ipath_flash) - pos;
-
tmp = kmalloc(count, GFP_KERNEL);
if (!tmp) {
ret = -ENOMEM;
@@ -381,7 +377,7 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
goto bail_tmp;
}
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
if (ipath_eeprom_write(dd, pos, tmp, count)) {
ret = -ENXIO;
ipath_dev_err(dd, "failed to write to flash\n");
diff --git a/drivers/infiniband/hw/ipath/ipath_ht400.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index fac0a2b74de..9e4e8d4c6e2 100644
--- a/drivers/infiniband/hw/ipath/ipath_ht400.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -32,7 +33,7 @@
/*
* This file contains all of the code that is specific to the InfiniPath
- * HT-400 chip.
+ * HT chip.
*/
#include <linux/pci.h>
@@ -42,7 +43,7 @@
#include "ipath_registers.h"
/*
- * This lists the InfiniPath HT400 registers, in the actual chip layout.
+ * This lists the InfiniPath registers, in the actual chip layout.
* This structure should never be directly accessed.
*
* The names are in InterCap form because they're taken straight from
@@ -251,8 +252,8 @@ static const struct ipath_cregs ipath_ht_cregs = {
};
/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK 0x1FF
-#define INFINIPATH_I_RCVAVAIL_MASK 0x1FF
+#define INFINIPATH_I_RCVURG_MASK ((1U<<9)-1)
+#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<9)-1)
/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
#define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0
@@ -337,7 +338,7 @@ static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
if (crcbits) {
u16 ctrl0, ctrl1;
snprintf(bitsmsg, sizeof bitsmsg,
- "[HT%s lane %s CRC (%llx); ignore till reload]",
+ "[HT%s lane %s CRC (%llx); powercycle to completely clear]",
!(crcbits & _IPATH_HTLINK1_CRCBITS) ?
"0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
? "1 (B)" : "0+1 (A+B)"),
@@ -388,17 +389,28 @@ static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
_IPATH_HTLINK1_CRCBITS)));
}
+/* 6110 specific hardware errors... */
+static const struct ipath_hwerror_msgs ipath_6110_hwerror_msgs[] = {
+ INFINIPATH_HWE_MSG(HTCBUSIREQPARITYERR, "HTC Ireq Parity"),
+ INFINIPATH_HWE_MSG(HTCBUSTREQPARITYERR, "HTC Treq Parity"),
+ INFINIPATH_HWE_MSG(HTCBUSTRESPPARITYERR, "HTC Tresp Parity"),
+ INFINIPATH_HWE_MSG(HTCMISCERR5, "HT core Misc5"),
+ INFINIPATH_HWE_MSG(HTCMISCERR6, "HT core Misc6"),
+ INFINIPATH_HWE_MSG(HTCMISCERR7, "HT core Misc7"),
+ INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
+ INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
+};
+
/**
- * ipath_ht_handle_hwerrors - display hardware errors
+ * ipath_ht_handle_hwerrors - display hardware errors.
* @dd: the infinipath device
* @msg: the output buffer
* @msgl: the size of the output buffer
*
- * Use same msg buffer as regular errors to avoid
- * excessive stack use. Most hardware errors are catastrophic, but for
- * right now, we'll print them and continue.
- * We reuse the same message buffer as ipath_handle_errors() to avoid
- * excessive stack usage.
+ * Use same msg buffer as regular errors to avoid excessive stack
+ * use. Most hardware errors are catastrophic, but for right now,
+ * we'll print them and continue. We reuse the same message buffer as
+ * ipath_handle_errors() to avoid excessive stack usage.
*/
static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
size_t msgl)
@@ -439,19 +451,49 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* make sure we get this much out, unless told to be quiet,
* or it's occurred within the last 5 seconds
*/
- if ((hwerrs & ~dd->ipath_lasthwerror) ||
+ if ((hwerrs & ~(dd->ipath_lasthwerror |
+ ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
(ipath_debug & __IPATH_VERBDBG))
dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
"(cleared)\n", (unsigned long long) hwerrs);
dd->ipath_lasthwerror |= hwerrs;
- if (hwerrs & ~infinipath_hwe_bitsextant)
+ if (hwerrs & ~dd->ipath_hwe_bitsextant)
ipath_dev_err(dd, "hwerror interrupt with unknown errors "
"%llx set\n", (unsigned long long)
- (hwerrs & ~infinipath_hwe_bitsextant));
+ (hwerrs & ~dd->ipath_hwe_bitsextant));
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if (ctrl & INFINIPATH_C_FREEZEMODE) {
+ /*
+ * parity errors in send memory are recoverable,
+ * just cancel the send (if indicated in * sendbuffererror),
+ * count the occurrence, unfreeze (if no other handled
+ * hardware error bits are set), and continue. They can
+ * occur if a processor speculative read is done to the PIO
+ * buffer while we are sending a packet, for example.
+ */
+ if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
+ ipath_stats.sps_txeparity++;
+ ipath_dbg("Recovering from TXE parity error (%llu), "
+ "hwerrstatus=%llx\n",
+ (unsigned long long) ipath_stats.sps_txeparity,
+ (unsigned long long) hwerrs);
+ ipath_disarm_senderrbufs(dd);
+ hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
+ if (!hwerrs) { /* else leave in freeze mode */
+ ipath_write_kreg(dd,
+ dd->ipath_kregs->kr_control,
+ dd->ipath_control);
+ return;
+ }
+ }
if (hwerrs) {
/*
* if any set that we aren't ignoring; only
@@ -460,8 +502,9 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* times.
*/
if (dd->ipath_flags & IPATH_INITTED) {
- ipath_dev_err(dd, "Fatal Error (freeze "
- "mode), no longer usable\n");
+ ipath_dev_err(dd, "Fatal Hardware Error (freeze "
+ "mode), no longer usable, SN %.16s\n",
+ dd->ipath_serial);
isfatal = 1;
}
*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
@@ -497,46 +540,18 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
bits);
strlcat(msg, bitsmsg, msgl);
}
- if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
- if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
- if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
- strlcat(msg, "[IB2IPATH Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
- strlcat(msg, "[IPATH2IB Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR)
- strlcat(msg, "[HTC Ireq Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR)
- strlcat(msg, "[HTC Treq Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR)
- strlcat(msg, "[HTC Tresp Parity]", msgl);
+
+ ipath_format_hwerrors(hwerrs,
+ ipath_6110_hwerror_msgs,
+ sizeof(ipath_6110_hwerror_msgs) /
+ sizeof(ipath_6110_hwerror_msgs[0]),
+ msg, msgl);
if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
hwerr_crcbits(dd, hwerrs, msg, msgl);
- if (hwerrs & INFINIPATH_HWE_HTCMISCERR5)
- strlcat(msg, "[HT core Misc5]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCMISCERR6)
- strlcat(msg, "[HT core Misc6]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCMISCERR7)
- strlcat(msg, "[HT core Misc7]", msgl);
if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
- strlcat(msg, "[Memory BIST test failed, HT-400 unusable]",
+ strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
msgl);
/* ignore from now on, so disable until driver reloaded */
dd->ipath_hwerrmask &= ~INFINIPATH_HWE_MEMBISTFAILED;
@@ -552,7 +567,7 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
if (hwerrs & _IPATH_PLL_FAIL) {
snprintf(bitsmsg, sizeof bitsmsg,
- "[PLL failed (%llx), HT-400 unusable]",
+ "[PLL failed (%llx), InfiniPath hardware unusable]",
(unsigned long long) (hwerrs & _IPATH_PLL_FAIL));
strlcat(msg, bitsmsg, msgl);
/* ignore from now on, so disable until driver reloaded */
@@ -571,11 +586,6 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
dd->ipath_hwerrmask);
}
- if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
- strlcat(msg, "[Rx Dsync]", msgl);
- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
- strlcat(msg, "[SerDes PLL]", msgl);
-
ipath_dev_err(dd, "%s hardware error\n", msg);
if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
/*
@@ -609,18 +619,18 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
break;
case 5:
/*
- * HT-460 original production board; two production levels, with
+ * original production board; two production levels, with
* different serial number ranges. See ipath_ht_early_init() for
* case where we enable IPATH_GPIO_INTR for later serial # range.
*/
- n = "InfiniPath_HT-460";
+ n = "InfiniPath_QHT7040";
break;
case 6:
n = "OEM_Board_3";
break;
case 7:
- /* HT-460 small form factor production board */
- n = "InfiniPath_HT-465";
+ /* small form factor production board */
+ n = "InfiniPath_QHT7140";
break;
case 8:
n = "LS/X-1";
@@ -632,7 +642,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
n = "OEM_Board_2";
break;
case 11:
- n = "InfiniPath_HT-470";
+ n = "InfiniPath_HT-470"; /* obsoleted */
break;
case 12:
n = "OEM_Board_4";
@@ -640,7 +650,7 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
default: /* don't know, just print the number */
ipath_dev_err(dd, "Don't yet know about board "
"with ID %u\n", boardrev);
- snprintf(name, namelen, "Unknown_InfiniPath_HT-4xx_%u",
+ snprintf(name, namelen, "Unknown_InfiniPath_QHT7xxx_%u",
boardrev);
break;
}
@@ -649,11 +659,10 @@ static int ipath_ht_boardname(struct ipath_devdata *dd, char *name,
if (dd->ipath_majrev != 3 || (dd->ipath_minrev < 2 || dd->ipath_minrev > 3)) {
/*
- * This version of the driver only supports the HT-400
- * Rev 3.2
+ * This version of the driver only supports Rev 3.2 and 3.3
*/
ipath_dev_err(dd,
- "Unsupported HT-400 revision %u.%u!\n",
+ "Unsupported InfiniPath hardware revision %u.%u!\n",
dd->ipath_majrev, dd->ipath_minrev);
ret = 1;
goto bail;
@@ -737,11 +746,10 @@ static void ipath_check_htlink(struct ipath_devdata *dd)
static int ipath_setup_ht_reset(struct ipath_devdata *dd)
{
- ipath_dbg("No reset possible for HT-400\n");
+ ipath_dbg("No reset possible for this InfiniPath hardware\n");
return 0;
}
-#define HT_CAPABILITY_ID 0x08 /* HT capabilities not defined in kernel */
#define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */
#define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */
@@ -924,7 +932,7 @@ static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev,
/*
* kernels with CONFIG_PCI_MSI set the vector in the irq field of
- * struct pci_device, so we use that to program the HT-400 internal
+ * struct pci_device, so we use that to program the internal
* interrupt register (not config space) with that value. The BIOS
* must still have done the basic MSI setup.
*/
@@ -972,7 +980,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
* do this early, before we ever enable errors or hardware errors,
* mostly to avoid causing the chip to enter freeze mode.
*/
- pos = pci_find_capability(pdev, HT_CAPABILITY_ID);
+ pos = pci_find_capability(pdev, PCI_CAP_ID_HT);
if (!pos) {
ipath_dev_err(dd, "Couldn't find HyperTransport "
"capability; no interrupts\n");
@@ -995,7 +1003,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
else if (cap_type == HT_INTR_DISC_CONFIG)
ihandler = set_int_handler(dd, pdev, pos);
} while ((pos = pci_find_next_capability(pdev, pos,
- HT_CAPABILITY_ID)));
+ PCI_CAP_ID_HT)));
if (!ihandler) {
ipath_dev_err(dd, "Couldn't find interrupt handler in "
@@ -1012,7 +1020,7 @@ bail:
* @dd: the infinipath device
*
* Called during driver unload.
- * This is currently a nop for the HT-400, not for all chips
+ * This is currently a nop for the HT chip, not for all chips
*/
static void ipath_setup_ht_cleanup(struct ipath_devdata *dd)
{
@@ -1080,21 +1088,21 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
}
-static void ipath_init_ht_variables(void)
+static void ipath_init_ht_variables(struct ipath_devdata *dd)
{
- ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
- ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
- ipath_gpio_sda = IPATH_GPIO_SDA;
- ipath_gpio_scl = IPATH_GPIO_SCL;
+ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+ dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+ dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+ dd->ipath_gpio_scl = IPATH_GPIO_SCL;
- infinipath_i_bitsextant =
+ dd->ipath_i_bitsextant =
(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
(INFINIPATH_I_RCVAVAIL_MASK <<
INFINIPATH_I_RCVAVAIL_SHIFT) |
INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
- infinipath_e_bitsextant =
+ dd->ipath_e_bitsextant =
INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
@@ -1112,7 +1120,7 @@ static void ipath_init_ht_variables(void)
INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
INFINIPATH_E_HARDWARE;
- infinipath_hwe_bitsextant =
+ dd->ipath_hwe_bitsextant =
(INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
(INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
@@ -1141,8 +1149,8 @@ static void ipath_init_ht_variables(void)
INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
- infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
- infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+ dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+ dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
}
/**
@@ -1289,6 +1297,15 @@ static int ipath_ht_bringup_serdes(struct ipath_devdata *dd)
val &= ~INFINIPATH_XGXS_RESET;
change = 1;
}
+ if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
+ INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
+ /* need to compensate for Tx inversion in partner */
+ val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
+ INFINIPATH_XGXS_RX_POL_SHIFT);
+ val |= dd->ipath_rx_pol_inv <<
+ INFINIPATH_XGXS_RX_POL_SHIFT;
+ change = 1;
+ }
if (change)
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
@@ -1469,7 +1486,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
/*
- * For HT-400, we allocate a somewhat overly large eager buffer,
+ * For HT, we allocate a somewhat overly large eager buffer,
* such that we can guarantee that we can receive the largest
* packet that we can send out. To truly support a 4KB MTU,
* we need to bump this to a large value. To date, other than
@@ -1530,7 +1547,7 @@ static int ipath_ht_early_init(struct ipath_devdata *dd)
if(dd->ipath_boardrev == 5 && dd->ipath_serial[0] == '1' &&
dd->ipath_serial[1] == '2' && dd->ipath_serial[2] == '8') {
/*
- * Later production HT-460 has same changes as HT-465, so
+ * Later production QHT7040 has same changes as QHT7140, so
* can use GPIO interrupts. They have serial #'s starting
* with 128, rather than 112.
*/
@@ -1559,20 +1576,19 @@ static int ipath_ht_get_base_info(struct ipath_portdata *pd, void *kbase)
}
/**
- * ipath_init_ht400_funcs - set up the chip-specific function pointers
+ * ipath_init_iba6110_funcs - set up the chip-specific function pointers
* @dd: the infinipath device
*
* This is global, and is called directly at init to set up the
* chip-specific function pointers for later use.
*/
-void ipath_init_ht400_funcs(struct ipath_devdata *dd)
+void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
{
dd->ipath_f_intrsetup = ipath_ht_intconfig;
dd->ipath_f_bus = ipath_setup_ht_config;
dd->ipath_f_reset = ipath_setup_ht_reset;
dd->ipath_f_get_boardname = ipath_ht_boardname;
dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors;
- dd->ipath_f_init_hwerrors = ipath_ht_init_hwerrors;
dd->ipath_f_early_init = ipath_ht_early_init;
dd->ipath_f_handle_hwerrors = ipath_ht_handle_hwerrors;
dd->ipath_f_quiet_serdes = ipath_ht_quiet_serdes;
@@ -1599,5 +1615,5 @@ void ipath_init_ht400_funcs(struct ipath_devdata *dd)
* do very early init that is needed before ipath_f_bus is
* called
*/
- ipath_init_ht_variables();
+ ipath_init_ht_variables(dd);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_pe800.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index 02e8c75b24f..a72ab9de386 100644
--- a/drivers/infiniband/hw/ipath/ipath_pe800.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -31,7 +32,7 @@
*/
/*
* This file contains all of the code that is specific to the
- * InfiniPath PE-800 chip.
+ * InfiniPath PCIe chip.
*/
#include <linux/interrupt.h>
@@ -44,9 +45,9 @@
/*
* This file contains all the chip-specific register information and
- * access functions for the PathScale PE800, the PCI-Express chip.
+ * access functions for the QLogic InfiniPath PCI-Express chip.
*
- * This lists the InfiniPath PE800 registers, in the actual chip layout.
+ * This lists the InfiniPath registers, in the actual chip layout.
* This structure should never be directly accessed.
*/
struct _infinipath_do_not_use_kernel_regs {
@@ -212,7 +213,6 @@ static const struct ipath_kregs ipath_pe_kregs = {
.kr_rcvhdraddr = IPATH_KREG_OFFSET(RcvHdrAddr0),
.kr_rcvhdrtailaddr = IPATH_KREG_OFFSET(RcvHdrTailAddr0),
- /* This group is pe-800-specific; and used only in this file */
/* The rcvpktled register controls one of the debug port signals, so
* a packet activity LED can be connected to it. */
.kr_rcvpktledcnt = IPATH_KREG_OFFSET(RcvPktLEDCnt),
@@ -263,8 +263,8 @@ static const struct ipath_cregs ipath_pe_cregs = {
};
/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK 0x1F
-#define INFINIPATH_I_RCVAVAIL_MASK 0x1F
+#define INFINIPATH_I_RCVURG_MASK ((1U<<5)-1)
+#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<5)-1)
/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x000000000000003fULL
@@ -294,6 +294,33 @@ static const struct ipath_cregs ipath_pe_cregs = {
#define IPATH_GPIO_SCL (1ULL << \
(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+/*
+ * Rev2 silicon allows suppressing check for ArmLaunch errors.
+ * this can speed up short packet sends on systems that do
+ * not guaranteee write-order.
+ */
+#define INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR (1ULL<<63)
+
+/* 6120 specific hardware errors... */
+static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
+ INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
+ INFINIPATH_HWE_MSG(PCIECPLTIMEOUT, "PCIe completion timeout"),
+ /*
+ * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
+ * parity or memory parity error failures, because most likely we
+ * won't be able to talk to the core of the chip. Nonetheless, we
+ * might see them, if they are in parts of the PCIe core that aren't
+ * essential.
+ */
+ INFINIPATH_HWE_MSG(PCIE1PLLFAILED, "PCIePLL1"),
+ INFINIPATH_HWE_MSG(PCIE0PLLFAILED, "PCIePLL0"),
+ INFINIPATH_HWE_MSG(PCIEBUSPARITYXTLH, "PCIe XTLH core parity"),
+ INFINIPATH_HWE_MSG(PCIEBUSPARITYXADM, "PCIe ADM TX core parity"),
+ INFINIPATH_HWE_MSG(PCIEBUSPARITYRADM, "PCIe ADM RX core parity"),
+ INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
+ INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
+};
+
/**
* ipath_pe_handle_hwerrors - display hardware errors.
* @dd: the infinipath device
@@ -343,19 +370,49 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* make sure we get this much out, unless told to be quiet,
* or it's occurred within the last 5 seconds
*/
- if ((hwerrs & ~dd->ipath_lasthwerror) ||
+ if ((hwerrs & ~(dd->ipath_lasthwerror |
+ ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
(ipath_debug & __IPATH_VERBDBG))
dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
"(cleared)\n", (unsigned long long) hwerrs);
dd->ipath_lasthwerror |= hwerrs;
- if (hwerrs & ~infinipath_hwe_bitsextant)
+ if (hwerrs & ~dd->ipath_hwe_bitsextant)
ipath_dev_err(dd, "hwerror interrupt with unknown errors "
"%llx set\n", (unsigned long long)
- (hwerrs & ~infinipath_hwe_bitsextant));
+ (hwerrs & ~dd->ipath_hwe_bitsextant));
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if (ctrl & INFINIPATH_C_FREEZEMODE) {
+ /*
+ * parity errors in send memory are recoverable,
+ * just cancel the send (if indicated in * sendbuffererror),
+ * count the occurrence, unfreeze (if no other handled
+ * hardware error bits are set), and continue. They can
+ * occur if a processor speculative read is done to the PIO
+ * buffer while we are sending a packet, for example.
+ */
+ if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
+ ipath_stats.sps_txeparity++;
+ ipath_dbg("Recovering from TXE parity error (%llu), "
+ "hwerrstatus=%llx\n",
+ (unsigned long long) ipath_stats.sps_txeparity,
+ (unsigned long long) hwerrs);
+ ipath_disarm_senderrbufs(dd);
+ hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
+ if (!hwerrs) { /* else leave in freeze mode */
+ ipath_write_kreg(dd,
+ dd->ipath_kregs->kr_control,
+ dd->ipath_control);
+ return;
+ }
+ }
if (hwerrs) {
/*
* if any set that we aren't ignoring only make the
@@ -363,8 +420,9 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* and we get here multiple times
*/
if (dd->ipath_flags & IPATH_INITTED) {
- ipath_dev_err(dd, "Fatal Error (freeze "
- "mode), no longer usable\n");
+ ipath_dev_err(dd, "Fatal Hardware Error (freeze "
+ "mode), no longer usable, SN %.16s\n",
+ dd->ipath_serial);
isfatal = 1;
}
/*
@@ -378,16 +436,15 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
} else {
ipath_dbg("Clearing freezemode on ignored hardware "
"error\n");
- ctrl &= ~INFINIPATH_C_FREEZEMODE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
- ctrl);
+ dd->ipath_control);
}
}
*msg = '\0';
if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
- strlcat(msg, "[Memory BIST test failed, PE-800 unusable]",
+ strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
msgl);
/* ignore from now on, so disable until driver reloaded */
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
@@ -395,24 +452,13 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
dd->ipath_hwerrmask);
}
- if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
- if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
+
+ ipath_format_hwerrors(hwerrs,
+ ipath_6120_hwerror_msgs,
+ sizeof(ipath_6120_hwerror_msgs)/
+ sizeof(ipath_6120_hwerror_msgs[0]),
+ msg, msgl);
+
if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
<< INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
bits = (u32) ((hwerrs >>
@@ -422,17 +468,13 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
- if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
- strlcat(msg, "[IB2IPATH Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
- strlcat(msg, "[IPATH2IB Parity]", msgl);
#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
INFINIPATH_HWE_COREPLL_RFSLIP )
if (hwerrs & _IPATH_PLL_FAIL) {
snprintf(bitsmsg, sizeof bitsmsg,
- "[PLL failed (%llx), PE-800 unusable]",
+ "[PLL failed (%llx), InfiniPath hardware unusable]",
(unsigned long long) hwerrs & _IPATH_PLL_FAIL);
strlcat(msg, bitsmsg, msgl);
/* ignore from now on, so disable until driver reloaded */
@@ -451,34 +493,6 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
dd->ipath_hwerrmask);
}
- if (hwerrs & INFINIPATH_HWE_PCIEPOISONEDTLP)
- strlcat(msg, "[PCIe Poisoned TLP]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT)
- strlcat(msg, "[PCIe completion timeout]", msgl);
-
- /*
- * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
- * parity or memory parity error failures, because most likely we
- * won't be able to talk to the core of the chip. Nonetheless, we
- * might see them, if they are in parts of the PCIe core that aren't
- * essential.
- */
- if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED)
- strlcat(msg, "[PCIePLL1]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED)
- strlcat(msg, "[PCIePLL0]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH)
- strlcat(msg, "[PCIe XTLH core parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM)
- strlcat(msg, "[PCIe ADM TX core parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM)
- strlcat(msg, "[PCIe ADM RX core parity]", msgl);
-
- if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
- strlcat(msg, "[Rx Dsync]", msgl);
- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
- strlcat(msg, "[SerDes PLL]", msgl);
-
ipath_dev_err(dd, "%s hardware error\n", msg);
if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) {
/*
@@ -510,30 +524,36 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
n = "InfiniPath_Emulation";
break;
case 1:
- n = "InfiniPath_PE-800-Bringup";
+ n = "InfiniPath_QLE7140-Bringup";
break;
case 2:
- n = "InfiniPath_PE-880";
+ n = "InfiniPath_QLE7140";
break;
case 3:
- n = "InfiniPath_PE-850";
+ n = "InfiniPath_QMI7140";
break;
case 4:
- n = "InfiniPath_PE-860";
+ n = "InfiniPath_QEM7140";
+ break;
+ case 5:
+ n = "InfiniPath_QMH7140";
+ break;
+ case 6:
+ n = "InfiniPath_QLE7142";
break;
default:
ipath_dev_err(dd,
"Don't yet know about board with ID %u\n",
boardrev);
- snprintf(name, namelen, "Unknown_InfiniPath_PE-8xx_%u",
+ snprintf(name, namelen, "Unknown_InfiniPath_PCIe_%u",
boardrev);
break;
}
if (n)
snprintf(name, namelen, "%s", n);
- if (dd->ipath_majrev != 4 || dd->ipath_minrev != 1) {
- ipath_dev_err(dd, "Unsupported PE-800 revision %u.%u!\n",
+ if (dd->ipath_majrev != 4 || !dd->ipath_minrev || dd->ipath_minrev>2) {
+ ipath_dev_err(dd, "Unsupported InfiniPath hardware revision %u.%u!\n",
dd->ipath_majrev, dd->ipath_minrev);
ret = 1;
} else
@@ -567,9 +587,12 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
if (!dd->ipath_boardrev) // no PLL for Emulator
val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
- /* workaround bug 9460 in internal interface bus parity checking */
- val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
-
+ if (dd->ipath_minrev < 2) {
+ /* workaround bug 9460 in internal interface bus parity
+ * checking. Fixed (HW bug 9490) in Rev2.
+ */
+ val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
+ }
dd->ipath_hwerrmask = val;
}
@@ -579,8 +602,8 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
*/
static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
{
- u64 val, tmp, config1;
- int ret = 0, change = 0;
+ u64 val, tmp, config1, prev_val;
+ int ret = 0;
ipath_dbg("Trying to bringup serdes\n");
@@ -637,6 +660,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+ prev_val = val;
if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
val &=
@@ -644,13 +668,30 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
INFINIPATH_XGXS_MDIOADDR_SHIFT);
/* MDIO address 3 */
val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
- change = 1;
}
if (val & INFINIPATH_XGXS_RESET) {
val &= ~INFINIPATH_XGXS_RESET;
- change = 1;
}
- if (change)
+ if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
+ INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
+ /* need to compensate for Tx inversion in partner */
+ val &= ~(INFINIPATH_XGXS_RX_POL_MASK <<
+ INFINIPATH_XGXS_RX_POL_SHIFT);
+ val |= dd->ipath_rx_pol_inv <<
+ INFINIPATH_XGXS_RX_POL_SHIFT;
+ }
+ if (dd->ipath_minrev >= 2) {
+ /* Rev 2. can tolerate multiple writes to PBC, and
+ * allowing them can provide lower latency on some
+ * CPUs, but this feature is off by default, only
+ * turned on by setting D63 of XGXSconfig reg.
+ * May want to make this conditional more
+ * fine-grained in future. This is not exactly
+ * related to XGXS, but where the bit ended up.
+ */
+ val |= INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR;
+ }
+ if (val != prev_val)
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
@@ -704,9 +745,25 @@ static void ipath_pe_quiet_serdes(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
}
-/* this is not yet needed on the PE800, so just return 0. */
static int ipath_pe_intconfig(struct ipath_devdata *dd)
{
+ u64 val;
+ u32 chiprev;
+
+ /*
+ * If the chip supports added error indication via GPIO pins,
+ * enable interrupts on those bits so the interrupt routine
+ * can count the events. Also set flag so interrupt routine
+ * can know they are expected.
+ */
+ chiprev = dd->ipath_revision >> INFINIPATH_R_CHIPREVMINOR_SHIFT;
+ if ((chiprev & INFINIPATH_R_CHIPREVMINOR_MASK) > 1) {
+ /* Rev2+ reports extra errors via internal GPIO pins */
+ dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
+ val |= IPATH_GPIO_ERRINTR_MASK;
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
+ }
return 0;
}
@@ -758,8 +815,8 @@ static void ipath_setup_pe_setextled(struct ipath_devdata *dd, u64 lst,
*
* This is called during driver unload.
* We do the pci_disable_msi here, not in generic code, because it
- * isn't used for the HT-400. If we do end up needing pci_enable_msi
- * at some point in the future for HT-400, we'll move the call back
+ * isn't used for the HT chips. If we do end up needing pci_enable_msi
+ * at some point in the future for HT, we'll move the call back
* into the main init_one code.
*/
static void ipath_setup_pe_cleanup(struct ipath_devdata *dd)
@@ -779,10 +836,10 @@ static void ipath_setup_pe_cleanup(struct ipath_devdata *dd)
* late in 2.6.16).
* All that can be done is to edit the kernel source to remove the quirk
* check until that is fixed.
- * We do not need to call enable_msi() for our HyperTransport chip (HT-400),
- * even those it uses MSI, and we want to avoid the quirk warning, so
- * So we call enable_msi only for the PE-800. If we do end up needing
- * pci_enable_msi at some point in the future for HT-400, we'll move the
+ * We do not need to call enable_msi() for our HyperTransport chip,
+ * even though it uses MSI, and we want to avoid the quirk warning, so
+ * So we call enable_msi only for PCIe. If we do end up needing
+ * pci_enable_msi at some point in the future for HT, we'll move the
* call back into the main init_one code.
* We save the msi lo and hi values, so we can restore them after
* chip reset (the kernel PCI infrastructure doesn't yet handle that
@@ -840,21 +897,23 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
return 0;
}
-static void ipath_init_pe_variables(void)
+static void ipath_init_pe_variables(struct ipath_devdata *dd)
{
/*
* bits for selecting i2c direction and values,
* used for I2C serial flash
*/
- ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
- ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
- ipath_gpio_sda = IPATH_GPIO_SDA;
- ipath_gpio_scl = IPATH_GPIO_SCL;
+ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+ dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+ dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+ dd->ipath_gpio_scl = IPATH_GPIO_SCL;
/* variables for sanity checking interrupt and errors */
- infinipath_hwe_bitsextant =
+ dd->ipath_hwe_bitsextant =
(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
+ (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
(INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<
INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |
INFINIPATH_HWE_PCIE1PLLFAILED |
@@ -870,13 +929,13 @@ static void ipath_init_pe_variables(void)
INFINIPATH_HWE_SERDESPLLFAILED |
INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
- infinipath_i_bitsextant =
+ dd->ipath_i_bitsextant =
(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
(INFINIPATH_I_RCVAVAIL_MASK <<
INFINIPATH_I_RCVAVAIL_SHIFT) |
INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
- infinipath_e_bitsextant =
+ dd->ipath_e_bitsextant =
INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
@@ -894,8 +953,8 @@ static void ipath_init_pe_variables(void)
INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
INFINIPATH_E_HARDWARE;
- infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
- infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+ dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+ dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
}
/* setup the MSI stuff again after a reset. I'd like to just call
@@ -970,8 +1029,7 @@ static int ipath_setup_pe_reset(struct ipath_devdata *dd)
int ret;
/* Use ERROR so it shows up in logs, etc. */
- ipath_dev_err(dd, "Resetting PE-800 unit %u\n",
- dd->ipath_unit);
+ ipath_dev_err(dd, "Resetting InfiniPath unit %u\n", dd->ipath_unit);
/* keep chip from being accessed in a few places */
dd->ipath_flags &= ~(IPATH_INITTED|IPATH_PRESENT);
val = dd->ipath_control | INFINIPATH_C_RESET;
@@ -1070,6 +1128,45 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
mmiowb();
spin_unlock_irqrestore(&dd->ipath_tid_lock, flags);
}
+/**
+ * ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher
+ * @dd: the infinipath device
+ * @tidptr: pointer to the expected TID (in chip) to udpate
+ * @tidtype: 0 for eager, 1 for expected
+ * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
+ *
+ * This exists as a separate routine to allow for selection of the
+ * appropriate "flavor". The static calls in cleanup just use the
+ * revision-agnostic form, as they are not performance critical.
+ */
+static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr,
+ u32 type, unsigned long pa)
+{
+ u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
+
+ if (pa != dd->ipath_tidinvalid) {
+ if (pa & ((1U << 11) - 1)) {
+ dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
+ "not 2KB aligned!\n", pa);
+ return;
+ }
+ pa >>= 11;
+ /* paranoia check */
+ if (pa & (7<<29))
+ ipath_dev_err(dd,
+ "BUG: Physical page address 0x%lx "
+ "has bits set in 31-29\n", pa);
+
+ if (type == 0)
+ pa |= dd->ipath_tidtemplate;
+ else /* for now, always full 4KB page */
+ pa |= 2 << 29;
+ }
+ if (dd->ipath_kregbase)
+ writel(pa, tidp32);
+ mmiowb();
+}
+
/**
* ipath_pe_clear_tid - clear all TID entries for a port, expected and eager
@@ -1077,7 +1174,7 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
* @port: the port
*
* clear all TID entries for a port, expected and eager.
- * Used from ipath_close(). On PE800, TIDs are only 32 bits,
+ * Used from ipath_close(). On this chip, TIDs are only 32 bits,
* not 64, but they are still on 64 bit boundaries, so tidbase
* is declared as u64 * for the pointer math, even though we write 32 bits
*/
@@ -1147,9 +1244,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
dd->ipath_flags |= IPATH_4BYTE_TID;
/*
- * For openib, we need to be able to handle an IB header of 96 bytes
- * or 24 dwords. HT-400 has arbitrary sized receive buffers, so we
- * made them the same size as the PIO buffers. The PE-800 does not
+ * For openfabrics, we need to be able to handle an IB header of
+ * 24 dwords. HT chip has arbitrary sized receive buffers, so we
+ * made them the same size as the PIO buffers. This chip does not
* handle arbitrary size buffers, so we need the header large enough
* to handle largest IB header, but still have room for a 2KB MTU
* standard IB packet.
@@ -1157,11 +1254,10 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
dd->ipath_rcvhdrentsize = 24;
dd->ipath_rcvhdrsize = IPATH_DFLT_RCVHDRSIZE;
- /* For HT-400, we allocate a somewhat overly large eager buffer,
- * such that we can guarantee that we can receive the largest packet
- * that we can send out. To truly support a 4KB MTU, we need to
- * bump this to a larger value. We'll do this when I get around to
- * testing 4KB sends on the PE-800, which I have not yet done.
+ /*
+ * To truly support a 4KB MTU (for usermode), we need to
+ * bump this to a larger value. For now, we use them for
+ * the kernel only.
*/
dd->ipath_rcvegrbufsize = 2048;
/*
@@ -1174,9 +1270,9 @@ static int ipath_pe_early_init(struct ipath_devdata *dd)
dd->ipath_init_ibmaxlen = dd->ipath_ibmaxlen;
/*
- * For PE-800, we can request a receive interrupt for 1 or
+ * We can request a receive interrupt for 1 or
* more packets from current offset. For now, we set this
- * up for a single packet, to match the HT-400 behavior.
+ * up for a single packet.
*/
dd->ipath_rhdrhead_intr_off = 1ULL<<32;
@@ -1192,7 +1288,7 @@ int __attribute__((weak)) ipath_unordered_wc(void)
/**
* ipath_init_pe_get_base_info - set chip-specific flags for user code
- * @dd: the infinipath device
+ * @pd: the infinipath port
* @kbase: ipath_base_info pointer
*
* We set the PCIE flag because the lower bandwidth on PCIe vs
@@ -1201,6 +1297,7 @@ int __attribute__((weak)) ipath_unordered_wc(void)
static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
{
struct ipath_base_info *kinfo = kbase;
+ struct ipath_devdata *dd;
if (ipath_unordered_wc()) {
kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER;
@@ -1209,19 +1306,31 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
else
ipath_cdbg(PROC, "Not Intel processor, WC ordered\n");
- kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
+ if (pd == NULL)
+ goto done;
+ dd = pd->port_dd;
+
+ if (dd != NULL && dd->ipath_minrev >= 2) {
+ ipath_cdbg(PROC, "IBA6120 Rev2, allow multiple PBC write\n");
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PBC_REWRITE;
+ ipath_cdbg(PROC, "IBA6120 Rev2, allow loose DMA alignment\n");
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_LOOSE_DMA_ALIGN;
+ }
+
+done:
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
return 0;
}
/**
- * ipath_init_pe800_funcs - set up the chip-specific function pointers
+ * ipath_init_iba6120_funcs - set up the chip-specific function pointers
* @dd: the infinipath device
*
* This is global, and is called directly at init to set up the
* chip-specific function pointers for later use.
*/
-void ipath_init_pe800_funcs(struct ipath_devdata *dd)
+void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
{
dd->ipath_f_intrsetup = ipath_pe_intconfig;
dd->ipath_f_bus = ipath_setup_pe_config;
@@ -1233,7 +1342,10 @@ void ipath_init_pe800_funcs(struct ipath_devdata *dd)
dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
dd->ipath_f_clear_tids = ipath_pe_clear_tids;
- dd->ipath_f_put_tid = ipath_pe_put_tid;
+ if (dd->ipath_minrev >= 2)
+ dd->ipath_f_put_tid = ipath_pe_put_tid_2;
+ else
+ dd->ipath_f_put_tid = ipath_pe_put_tid;
dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
dd->ipath_f_setextled = ipath_setup_pe_setextled;
dd->ipath_f_get_base_info = ipath_pe_get_base_info;
@@ -1248,6 +1360,6 @@ void ipath_init_pe800_funcs(struct ipath_devdata *dd)
dd->ipath_kregs = &ipath_pe_kregs;
dd->ipath_cregs = &ipath_pe_cregs;
- ipath_init_pe_variables();
+ ipath_init_pe_variables(dd);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index dc83250d26a..d819cca524c 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -35,7 +36,7 @@
#include <linux/vmalloc.h>
#include "ipath_kernel.h"
-#include "ips_common.h"
+#include "ipath_common.h"
/*
* min buffers we want to have per port, after driver
@@ -52,8 +53,8 @@ module_param_named(cfgports, ipath_cfgports, ushort, S_IRUGO);
MODULE_PARM_DESC(cfgports, "Set max number of ports to use");
/*
- * Number of buffers reserved for driver (layered drivers and SMA
- * send). Reserved at end of buffer list. Initialized based on
+ * Number of buffers reserved for driver (verbs and layered drivers.)
+ * Reserved at end of buffer list. Initialized based on
* number of PIO buffers if not set via module interface.
* The problem with this is that it's global, but we'll use different
* numbers for different chip types. So the default value is not
@@ -79,7 +80,7 @@ MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver");
*
* Allocate the eager TID buffers and program them into infinipath.
* We use the network layer alloc_skb() allocator to allocate the
- * memory, and either use the buffers as is for things like SMA
+ * memory, and either use the buffers as is for things like verbs
* packets, or pass the buffers up to the ipath layered driver and
* thence the network layer, replacing them as we do so (see
* ipath_rcv_layer()).
@@ -87,13 +88,13 @@ MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver");
static int create_port0_egr(struct ipath_devdata *dd)
{
unsigned e, egrcnt;
- struct sk_buff **skbs;
+ struct ipath_skbinfo *skbinfo;
int ret;
egrcnt = dd->ipath_rcvegrcnt;
- skbs = vmalloc(sizeof(*dd->ipath_port0_skbs) * egrcnt);
- if (skbs == NULL) {
+ skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
+ if (skbinfo == NULL) {
ipath_dev_err(dd, "allocation error for eager TID "
"skb array\n");
ret = -ENOMEM;
@@ -108,12 +109,13 @@ static int create_port0_egr(struct ipath_devdata *dd)
* 4 bytes so that the data buffer stays word aligned.
* See ipath_kreceive() for more details.
*/
- skbs[e] = ipath_alloc_skb(dd, GFP_KERNEL);
- if (!skbs[e]) {
+ skbinfo[e].skb = ipath_alloc_skb(dd, GFP_KERNEL);
+ if (!skbinfo[e].skb) {
ipath_dev_err(dd, "SKB allocation error for "
"eager TID %u\n", e);
while (e != 0)
- dev_kfree_skb(skbs[--e]);
+ dev_kfree_skb(skbinfo[--e].skb);
+ vfree(skbinfo);
ret = -ENOMEM;
goto bail;
}
@@ -122,14 +124,17 @@ static int create_port0_egr(struct ipath_devdata *dd)
* After loop above, so we can test non-NULL to see if ready
* to use at receive, etc.
*/
- dd->ipath_port0_skbs = skbs;
+ dd->ipath_port0_skbinfo = skbinfo;
for (e = 0; e < egrcnt; e++) {
- unsigned long phys =
- virt_to_phys(dd->ipath_port0_skbs[e]->data);
+ dd->ipath_port0_skbinfo[e].phys =
+ ipath_map_single(dd->pcidev,
+ dd->ipath_port0_skbinfo[e].skb->data,
+ dd->ipath_ibmaxlen, PCI_DMA_FROMDEVICE);
dd->ipath_f_put_tid(dd, e + (u64 __iomem *)
((char __iomem *) dd->ipath_kregbase +
- dd->ipath_rcvegrbase), 0, phys);
+ dd->ipath_rcvegrbase), 0,
+ dd->ipath_port0_skbinfo[e].phys);
}
ret = 0;
@@ -238,7 +243,11 @@ static int init_chip_first(struct ipath_devdata *dd,
"only supports %u\n", ipath_cfgports,
dd->ipath_portcnt);
}
- dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_cfgports,
+ /*
+ * Allocate full portcnt array, rather than just cfgports, because
+ * cleanup iterates across all possible ports.
+ */
+ dd->ipath_pd = kzalloc(sizeof(*dd->ipath_pd) * dd->ipath_portcnt,
GFP_KERNEL);
if (!dd->ipath_pd) {
@@ -275,7 +284,7 @@ static int init_chip_first(struct ipath_devdata *dd,
pd->port_port = 0;
pd->port_cnt = 1;
/* The port 0 pkey table is used by the layer interface. */
- pd->port_pkeys[0] = IPS_DEFAULT_P_KEY;
+ pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY;
dd->ipath_rcvtidcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
dd->ipath_rcvtidbase =
@@ -409,17 +418,8 @@ static int init_pioavailregs(struct ipath_devdata *dd)
/* and its length */
dd->ipath_freezelen = L1_CACHE_BYTES - sizeof(dd->ipath_statusp[0]);
- if (dd->ipath_unit * 64 > (IPATH_PORT0_RCVHDRTAIL_SIZE - 64)) {
- ipath_dev_err(dd, "unit %u too large for port 0 "
- "rcvhdrtail buffer size\n", dd->ipath_unit);
- ret = -ENODEV;
- }
- else
- ret = 0;
+ ret = 0;
- /* so we can get current tail in ipath_kreceive(), per chip */
- dd->ipath_hdrqtailptr = &ipath_port0_rcvhdrtail[
- dd->ipath_unit * (64 / sizeof(*ipath_port0_rcvhdrtail))];
done:
return ret;
}
@@ -435,16 +435,33 @@ done:
*/
static void init_shadow_tids(struct ipath_devdata *dd)
{
- dd->ipath_pageshadow = (struct page **)
- vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ struct page **pages;
+ dma_addr_t *addrs;
+
+ pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
sizeof(struct page *));
- if (!dd->ipath_pageshadow)
+ if (!pages) {
ipath_dev_err(dd, "failed to allocate shadow page * "
"array, no expected sends!\n");
- else
- memset(dd->ipath_pageshadow, 0,
- dd->ipath_cfgports * dd->ipath_rcvtidcnt *
- sizeof(struct page *));
+ dd->ipath_pageshadow = NULL;
+ return;
+ }
+
+ addrs = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ sizeof(dma_addr_t));
+ if (!addrs) {
+ ipath_dev_err(dd, "failed to allocate shadow dma handle "
+ "array, no expected sends!\n");
+ vfree(dd->ipath_pageshadow);
+ dd->ipath_pageshadow = NULL;
+ return;
+ }
+
+ memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ sizeof(struct page *));
+
+ dd->ipath_pageshadow = pages;
+ dd->ipath_physshadow = addrs;
}
static void enable_chip(struct ipath_devdata *dd,
@@ -453,9 +470,9 @@ static void enable_chip(struct ipath_devdata *dd,
u32 val;
int i;
- if (!reinit) {
- init_waitqueue_head(&ipath_sma_state_wait);
- }
+ if (!reinit)
+ init_waitqueue_head(&ipath_state_wait);
+
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
@@ -652,8 +669,9 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
{
int ret = 0, i;
u32 val32, kpiobufs;
- u64 val, atmp;
+ u64 val;
struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
+ gfp_t gfp_flags = GFP_USER | __GFP_COMP;
ret = init_housekeeping(dd, &pd, reinit);
if (ret)
@@ -693,7 +711,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2)
/ (sizeof(u64) * BITS_PER_BYTE / 2);
if (ipath_kpiobufs == 0) {
- /* not set by user, or set explictly to default */
+ /* not set by user (this is default) */
if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128)
kpiobufs = 32;
else
@@ -775,24 +793,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
goto done;
}
- val = ipath_port0_rcvhdrtail_dma + dd->ipath_unit * 64;
-
- /* verify that the alignment requirement was met */
- ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
- 0, val);
- atmp = ipath_read_kreg64_port(
- dd, dd->ipath_kregs->kr_rcvhdrtailaddr, 0);
- if (val != atmp) {
- ipath_dev_err(dd, "Catastrophic software error, "
- "RcvHdrTailAddr0 written as %llx, "
- "read back as %llx from %x\n",
- (unsigned long long) val,
- (unsigned long long) atmp,
- dd->ipath_kregs->kr_rcvhdrtailaddr);
- ret = -EINVAL;
- goto done;
- }
-
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvbthqp, IPATH_KD_QP);
/*
@@ -836,25 +836,45 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
/* clear any interrups up to this point (ints still not enabled) */
ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, -1LL);
- ipath_stats.sps_lid[dd->ipath_unit] = dd->ipath_lid;
-
/*
* Set up the port 0 (kernel) rcvhdr q and egr TIDs. If doing
* re-init, the simplest way to handle this is to free
* existing, and re-allocate.
*/
- if (reinit)
- ipath_free_pddata(dd, 0, 0);
+ if (reinit) {
+ struct ipath_portdata *pd = dd->ipath_pd[0];
+ dd->ipath_pd[0] = NULL;
+ ipath_free_pddata(dd, pd);
+ }
dd->ipath_f_tidtemplate(dd);
ret = ipath_create_rcvhdrq(dd, pd);
- if (!ret)
+ if (!ret) {
+ dd->ipath_hdrqtailptr =
+ (volatile __le64 *)pd->port_rcvhdrtail_kvaddr;
ret = create_port0_egr(dd);
+ }
if (ret)
ipath_dev_err(dd, "failed to allocate port 0 (kernel) "
"rcvhdrq and/or egr bufs\n");
else
enable_chip(dd, pd, reinit);
+
+ if (!ret && !reinit) {
+ /* used when we close a port, for DMA already in flight at close */
+ dd->ipath_dummy_hdrq = dma_alloc_coherent(
+ &dd->pcidev->dev, pd->port_rcvhdrq_size,
+ &dd->ipath_dummy_hdrq_phys,
+ gfp_flags);
+ if (!dd->ipath_dummy_hdrq ) {
+ dev_info(&dd->pcidev->dev,
+ "Couldn't allocate 0x%lx bytes for dummy hdrq\n",
+ pd->port_rcvhdrq_size);
+ /* fallback to just 0'ing */
+ dd->ipath_dummy_hdrq_phys = 0UL;
+ }
+ }
+
/*
* cause retrigger of pending interrupts ignored during init,
* even if we had errors
@@ -950,6 +970,7 @@ static int ipath_set_kpiobufs(const char *str, struct kernel_param *kp)
dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - val;
}
+ ipath_kpiobufs = val;
ret = 0;
bail:
spin_unlock_irqrestore(&ipath_devs_lock, flags);
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 3e72a1fe3d7..6bee53ce5f3 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -33,31 +34,21 @@
#include <linux/pci.h>
#include "ipath_kernel.h"
-#include "ips_common.h"
-#include "ipath_layer.h"
+#include "ipath_verbs.h"
+#include "ipath_common.h"
-#define E_SUM_PKTERRS \
- (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \
- INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \
- INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN | \
- INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RMINPKTLEN | \
- INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \
- INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP)
-
-#define E_SUM_ERRS \
- (INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \
- INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
- INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNSUPVL | \
- INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
- INFINIPATH_E_INVALIDADDR)
-
-static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
+/*
+ * Called when we might have an error that is specific to a particular
+ * PIO buffer, and may need to cancel that buffer, so it can be re-used.
+ */
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
{
- unsigned long sbuf[4];
- u64 ignore_this_time = 0;
u32 piobcnt;
-
- /* if possible that sendbuffererror could be valid */
+ unsigned long sbuf[4];
+ /*
+ * it's possible that sendbuffererror could have bits set; might
+ * have already done this as a result of hardware error handling
+ */
piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
/* read these before writing errorclear */
sbuf[0] = ipath_read_kreg64(
@@ -73,36 +64,58 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
int i;
+ if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG)) {
+ __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
+ "SendbufErrs %lx %lx", sbuf[0],
+ sbuf[1]);
+ if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
+ printk(" %lx %lx ", sbuf[2], sbuf[3]);
+ printk("\n");
+ }
- ipath_cdbg(PKT, "SendbufErrs %lx %lx ", sbuf[0], sbuf[1]);
- if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
- printk("%lx %lx ", sbuf[2], sbuf[3]);
- for (i = 0; i < piobcnt; i++) {
- if (test_bit(i, sbuf)) {
- u32 __iomem *piobuf;
- if (i < dd->ipath_piobcnt2k)
- piobuf = (u32 __iomem *)
- (dd->ipath_pio2kbase +
- i * dd->ipath_palign);
- else
- piobuf = (u32 __iomem *)
- (dd->ipath_pio4kbase +
- (i - dd->ipath_piobcnt2k) *
- dd->ipath_4kalign);
-
- ipath_cdbg(PKT,
- "PIObuf[%u] @%p pbc is %x; ",
- i, piobuf, readl(piobuf));
-
+ for (i = 0; i < piobcnt; i++)
+ if (test_bit(i, sbuf))
ipath_disarm_piobufs(dd, i, 1);
- }
- }
- if (ipath_debug & __IPATH_PKTDBG)
- printk("\n");
+ dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */
}
- if ((errs & (INFINIPATH_E_SDROPPEDDATAPKT |
- INFINIPATH_E_SDROPPEDSMPPKT |
- INFINIPATH_E_SMINPKTLEN)) &&
+}
+
+
+/* These are all rcv-related errors which we want to count for stats */
+#define E_SUM_PKTERRS \
+ (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \
+ INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \
+ INFINIPATH_E_RLONGPKTLEN | INFINIPATH_E_RSHORTPKTLEN | \
+ INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RMINPKTLEN | \
+ INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \
+ INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP)
+
+/* These are all send-related errors which we want to count for stats */
+#define E_SUM_ERRS \
+ (INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \
+ INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
+ INFINIPATH_E_SMAXPKTLEN | INFINIPATH_E_SUNSUPVL | \
+ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
+ INFINIPATH_E_INVALIDADDR)
+
+/*
+ * these are errors that can occur when the link changes state while
+ * a packet is being sent or received. This doesn't cover things
+ * like EBP or VCRC that can be the result of a sending having the
+ * link change state, so we receive a "known bad" packet.
+ */
+#define E_SUM_LINK_PKTERRS \
+ (INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
+ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
+ INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RMINPKTLEN | \
+ INFINIPATH_E_RUNEXPCHAR)
+
+static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
+{
+ u64 ignore_this_time = 0;
+
+ ipath_disarm_senderrbufs(dd);
+ if ((errs & E_SUM_LINK_PKTERRS) &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
/*
* This can happen when SMA is trying to bring the link
@@ -111,16 +124,90 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
* valid. We don't want to confuse people, so we just
* don't print them, except at debug
*/
- ipath_dbg("Ignoring pktsend errors %llx, because not "
- "yet active\n", (unsigned long long) errs);
- ignore_this_time = INFINIPATH_E_SDROPPEDDATAPKT |
- INFINIPATH_E_SDROPPEDSMPPKT |
- INFINIPATH_E_SMINPKTLEN;
+ ipath_dbg("Ignoring packet errors %llx, because link not "
+ "ACTIVE\n", (unsigned long long) errs);
+ ignore_this_time = errs & E_SUM_LINK_PKTERRS;
}
return ignore_this_time;
}
+/* generic hw error messages... */
+#define INFINIPATH_HWE_TXEMEMPARITYERR_MSG(a) \
+ { \
+ .mask = ( INFINIPATH_HWE_TXEMEMPARITYERR_##a << \
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT ), \
+ .msg = "TXE " #a " Memory Parity" \
+ }
+#define INFINIPATH_HWE_RXEMEMPARITYERR_MSG(a) \
+ { \
+ .mask = ( INFINIPATH_HWE_RXEMEMPARITYERR_##a << \
+ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT ), \
+ .msg = "RXE " #a " Memory Parity" \
+ }
+
+static const struct ipath_hwerror_msgs ipath_generic_hwerror_msgs[] = {
+ INFINIPATH_HWE_MSG(IBCBUSFRSPCPARITYERR, "IPATH2IB Parity"),
+ INFINIPATH_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2IPATH Parity"),
+
+ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOBUF),
+ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOPBC),
+ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOLAUNCHFIFO),
+
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(RCVBUF),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(LOOKUPQ),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EAGERTID),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EXPTID),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(FLAGBUF),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(DATAINFO),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(HDRINFO),
+};
+
+/**
+ * ipath_format_hwmsg - format a single hwerror message
+ * @msg message buffer
+ * @msgl length of message buffer
+ * @hwmsg message to add to message buffer
+ */
+static void ipath_format_hwmsg(char *msg, size_t msgl, const char *hwmsg)
+{
+ strlcat(msg, "[", msgl);
+ strlcat(msg, hwmsg, msgl);
+ strlcat(msg, "]", msgl);
+}
+
+/**
+ * ipath_format_hwerrors - format hardware error messages for display
+ * @hwerrs hardware errors bit vector
+ * @hwerrmsgs hardware error descriptions
+ * @nhwerrmsgs number of hwerrmsgs
+ * @msg message buffer
+ * @msgl message buffer length
+ */
+void ipath_format_hwerrors(u64 hwerrs,
+ const struct ipath_hwerror_msgs *hwerrmsgs,
+ size_t nhwerrmsgs,
+ char *msg, size_t msgl)
+{
+ int i;
+ const int glen =
+ sizeof(ipath_generic_hwerror_msgs) /
+ sizeof(ipath_generic_hwerror_msgs[0]);
+
+ for (i=0; i<glen; i++) {
+ if (hwerrs & ipath_generic_hwerror_msgs[i].mask) {
+ ipath_format_hwmsg(msg, msgl,
+ ipath_generic_hwerror_msgs[i].msg);
+ }
+ }
+
+ for (i=0; i<nhwerrmsgs; i++) {
+ if (hwerrs & hwerrmsgs[i].mask) {
+ ipath_format_hwmsg(msg, msgl, hwerrmsgs[i].msg);
+ }
+ }
+}
+
/* return the strings for the most common link states */
static char *ib_linkstate(u32 linkstate)
{
@@ -156,7 +243,29 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
*/
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
lstate = val & IPATH_IBSTATE_MASK;
- if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
+
+ /*
+ * this is confusing enough when it happens that I want to always put it
+ * on the console and in the logs. If it was a requested state change,
+ * we'll have already cleared the flags, so we won't print this warning
+ */
+ if ((lstate != IPATH_IBSTATE_ARM && lstate != IPATH_IBSTATE_ACTIVE)
+ && (dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE))) {
+ dev_info(&dd->pcidev->dev, "Link state changed from %s to %s\n",
+ (dd->ipath_flags & IPATH_LINKARMED) ? "ARM" : "ACTIVE",
+ ib_linkstate(lstate));
+ /*
+ * Flush all queued sends when link went to DOWN or INIT,
+ * to be sure that they don't block SMA and other MAD packets
+ */
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ INFINIPATH_S_ABORT);
+ ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
+ (unsigned)(dd->ipath_piobcnt2k +
+ dd->ipath_piobcnt4k) -
+ dd->ipath_lastport_piobuf);
+ }
+ else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
lstate == IPATH_IBSTATE_ACTIVE) {
/*
* only print at SMA if there is a change, debug if not
@@ -168,7 +277,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
ib_linkstate(lstate));
}
else
- ipath_cdbg(SMA, "Unit %u link state %s, last "
+ ipath_cdbg(VERBOSE, "Unit %u link state %s, last "
"was %s\n", dd->ipath_unit,
ib_linkstate(lstate),
ib_linkstate((unsigned)
@@ -180,7 +289,7 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
if (lstate == IPATH_IBSTATE_INIT ||
lstate == IPATH_IBSTATE_ARM ||
lstate == IPATH_IBSTATE_ACTIVE)
- ipath_cdbg(SMA, "Unit %u link state down"
+ ipath_cdbg(VERBOSE, "Unit %u link state down"
" (state 0x%x), from %s\n",
dd->ipath_unit,
(u32)val & IPATH_IBSTATE_MASK,
@@ -229,13 +338,14 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
| IPATH_LINKACTIVE |
IPATH_LINKARMED);
*dd->ipath_statusp &= ~IPATH_STATUS_IB_READY;
+ dd->ipath_lli_counter = 0;
if (!noprint) {
if (((dd->ipath_lastibcstat >>
INFINIPATH_IBCS_LINKSTATE_SHIFT) &
INFINIPATH_IBCS_LINKSTATE_MASK)
== INFINIPATH_IBCS_L_STATE_ACTIVE)
/* if from up to down be more vocal */
- ipath_cdbg(SMA,
+ ipath_cdbg(VERBOSE,
"Unit %u link now down (%s)\n",
dd->ipath_unit,
ipath_ibcstatus_str[ltstate]);
@@ -255,8 +365,6 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
*dd->ipath_statusp |=
IPATH_STATUS_IB_READY | IPATH_STATUS_IB_CONF;
dd->ipath_f_setextled(dd, lstate, ltstate);
-
- __ipath_layer_intr(dd, IPATH_LAYER_INT_IF_UP);
} else if ((val & IPATH_IBSTATE_MASK) == IPATH_IBSTATE_INIT) {
/*
* set INIT and DOWN. Down is checked by most of the other
@@ -350,7 +458,7 @@ static unsigned handle_frequent_errors(struct ipath_devdata *dd,
return supp_msgs;
}
-static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
+static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
{
char msg[512];
u64 ignore_this_time = 0;
@@ -372,13 +480,26 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg);
}
- if (!noprint && (errs & ~infinipath_e_bitsextant))
+ if (!noprint && (errs & ~dd->ipath_e_bitsextant))
ipath_dev_err(dd, "error interrupt with unknown errors "
"%llx set\n", (unsigned long long)
- (errs & ~infinipath_e_bitsextant));
+ (errs & ~dd->ipath_e_bitsextant));
if (errs & E_SUM_ERRS)
ignore_this_time = handle_e_sum_errs(dd, errs);
+ else if ((errs & E_SUM_LINK_PKTERRS) &&
+ !(dd->ipath_flags & IPATH_LINKACTIVE)) {
+ /*
+ * This can happen when SMA is trying to bring the link
+ * up, but the IB link changes state at the "wrong" time.
+ * The IB logic then complains that the packet isn't
+ * valid. We don't want to confuse people, so we just
+ * don't print them, except at debug
+ */
+ ipath_dbg("Ignoring packet errors %llx, because link not "
+ "ACTIVE\n", (unsigned long long) errs);
+ ignore_this_time = errs & E_SUM_LINK_PKTERRS;
+ }
if (supp_msgs == 250000) {
/*
@@ -397,7 +518,7 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
if ((dd->ipath_maskederrs & ~dd->ipath_ignorederrs) &
~(INFINIPATH_E_RRCVEGRFULL | INFINIPATH_E_RRCVHDRFULL))
ipath_dev_err(dd, "Disabling error(s) %llx because "
- "occuring too frequently (%s)\n",
+ "occurring too frequently (%s)\n",
(unsigned long long)
(dd->ipath_maskederrs &
~dd->ipath_ignorederrs), msg);
@@ -433,8 +554,16 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
~(INFINIPATH_E_HARDWARE |
INFINIPATH_E_IBSTATUSCHANGED);
}
+
+ /* likely due to cancel, so suppress */
+ if ((errs & (INFINIPATH_E_SPKTLEN | INFINIPATH_E_SPIOARMLAUNCH)) &&
+ dd->ipath_lastcancel > jiffies) {
+ ipath_dbg("Suppressed armlaunch/spktlen after error send cancel\n");
+ errs &= ~(INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SPKTLEN);
+ }
+
if (!errs)
- return;
+ return 0;
if (!noprint)
/*
@@ -484,7 +613,7 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* don't report same point multiple times,
* except kernel
*/
- tl = (u32) * pd->port_rcvhdrtail_kvaddr;
+ tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
if (tl == dd->ipath_lastrcvhdrqtails[i])
continue;
hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
@@ -493,10 +622,10 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
continue;
if (hd == (tl + 1) ||
(!hd && tl == dd->ipath_hdrqlast)) {
- dd->ipath_lastrcvhdrqtails[i] = tl;
- pd->port_hdrqfull++;
if (i == 0)
chkerrpkts = 1;
+ dd->ipath_lastrcvhdrqtails[i] = tl;
+ pd->port_hdrqfull++;
}
}
}
@@ -551,16 +680,14 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
if (!noprint && *msg)
ipath_dev_err(dd, "%s error\n", msg);
- if (dd->ipath_sma_state_wanted & dd->ipath_flags) {
- ipath_cdbg(VERBOSE, "sma wanted state %x, iflags now %x, "
- "waking\n", dd->ipath_sma_state_wanted,
+ if (dd->ipath_state_wanted & dd->ipath_flags) {
+ ipath_cdbg(VERBOSE, "driver wanted state %x, iflags now %x, "
+ "waking\n", dd->ipath_state_wanted,
dd->ipath_flags);
- wake_up_interruptible(&ipath_sma_state_wait);
+ wake_up_interruptible(&ipath_state_wait);
}
- if (chkerrpkts)
- /* process possible error packets in hdrq */
- ipath_kreceive(dd);
+ return chkerrpkts;
}
/* this is separate to allow for better optimization of ipath_intr() */
@@ -663,11 +790,7 @@ static void handle_layer_pioavail(struct ipath_devdata *dd)
{
int ret;
- ret = __ipath_layer_intr(dd, IPATH_LAYER_INT_SEND_CONTINUE);
- if (ret > 0)
- goto set;
-
- ret = __ipath_verbs_piobufavail(dd);
+ ret = ipath_ib_piobufavail(dd->verbs_dev);
if (ret > 0)
goto set;
@@ -678,32 +801,32 @@ set:
dd->ipath_sendctrl);
}
-static void handle_rcv(struct ipath_devdata *dd, u32 istat)
+/*
+ * Handle receive interrupts for user ports; this means a user
+ * process was waiting for a packet to arrive, and didn't want
+ * to poll
+ */
+static void handle_urcv(struct ipath_devdata *dd, u32 istat)
{
u64 portr;
int i;
int rcvdint = 0;
portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
- infinipath_i_rcvavail_mask)
+ dd->ipath_i_rcvavail_mask)
| ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
- infinipath_i_rcvurg_mask);
- for (i = 0; i < dd->ipath_cfgports; i++) {
+ dd->ipath_i_rcvurg_mask);
+ for (i = 1; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
- if (portr & (1 << i) && pd &&
- pd->port_cnt) {
- if (i == 0)
- ipath_kreceive(dd);
- else if (test_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag)) {
- int rcbit;
- clear_bit(IPATH_PORT_WAITING_RCV,
- &pd->port_flag);
- rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT;
- clear_bit(1UL << rcbit, &dd->ipath_rcvctrl);
- wake_up_interruptible(&pd->port_wait);
- rcvdint = 1;
- }
+ if (portr & (1 << i) && pd && pd->port_cnt &&
+ test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) {
+ int rcbit;
+ clear_bit(IPATH_PORT_WAITING_RCV,
+ &pd->port_flag);
+ rcbit = i + INFINIPATH_R_INTRAVAIL_SHIFT;
+ clear_bit(1UL << rcbit, &dd->ipath_rcvctrl);
+ wake_up_interruptible(&pd->port_wait);
+ rcvdint = 1;
}
}
if (rcvdint) {
@@ -719,16 +842,19 @@ static void handle_rcv(struct ipath_devdata *dd, u32 istat)
irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
{
struct ipath_devdata *dd = data;
- u32 istat;
+ u32 istat, chk0rcv = 0;
ipath_err_t estat = 0;
- static unsigned unexpected = 0;
irqreturn_t ret;
+ u32 oldhead, curtail;
+ static unsigned unexpected = 0;
+ static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) |
+ (1U<<INFINIPATH_I_RCVURG_SHIFT);
+
+ ipath_stats.sps_ints++;
- if(!(dd->ipath_flags & IPATH_PRESENT)) {
- /* this is mostly so we don't try to touch the chip while
- * it is being reset */
+ if (!(dd->ipath_flags & IPATH_PRESENT)) {
/*
- * This return value is perhaps odd, but we do not want the
+ * This return value is not great, but we do not want the
* interrupt core code to remove our interrupt handler
* because we don't appear to be handling an interrupt
* during a chip reset.
@@ -736,7 +862,51 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
return IRQ_HANDLED;
}
+ /*
+ * this needs to be flags&initted, not statusp, so we keep
+ * taking interrupts even after link goes down, etc.
+ * Also, we *must* clear the interrupt at some point, or we won't
+ * take it again, which can be real bad for errors, etc...
+ */
+
+ if (!(dd->ipath_flags & IPATH_INITTED)) {
+ ipath_bad_intr(dd, &unexpected);
+ ret = IRQ_NONE;
+ goto bail;
+ }
+
+ /*
+ * We try to avoid reading the interrupt status register, since
+ * that's a PIO read, and stalls the processor for up to about
+ * ~0.25 usec. The idea is that if we processed a port0 packet,
+ * we blindly clear the port 0 receive interrupt bits, and nothing
+ * else, then return. If other interrupts are pending, the chip
+ * will re-interrupt us as soon as we write the intclear register.
+ * We then won't process any more kernel packets (if not the 2nd
+ * time, then the 3rd or 4th) and we'll then handle the other
+ * interrupts. We clear the interrupts first so that we don't
+ * lose intr for later packets that arrive while we are processing.
+ */
+ oldhead = dd->ipath_port0head;
+ curtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
+ if (oldhead != curtail) {
+ if (dd->ipath_flags & IPATH_GPIO_INTR) {
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+ (u64) (1 << IPATH_GPIO_PORT0_BIT));
+ istat = port0rbits | INFINIPATH_I_GPIO;
+ }
+ else
+ istat = port0rbits;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
+ ipath_kreceive(dd);
+ if (oldhead != dd->ipath_port0head) {
+ ipath_stats.sps_fastrcvint++;
+ goto done;
+ }
+ }
+
istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
+
if (unlikely(!istat)) {
ipath_stats.sps_nullintr++;
ret = IRQ_NONE; /* not our interrupt, or already handled */
@@ -749,31 +919,17 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
goto bail;
}
- ipath_stats.sps_ints++;
-
- /*
- * this needs to be flags&initted, not statusp, so we keep
- * taking interrupts even after link goes down, etc.
- * Also, we *must* clear the interrupt at some point, or we won't
- * take it again, which can be real bad for errors, etc...
- */
-
- if (!(dd->ipath_flags & IPATH_INITTED)) {
- ipath_bad_intr(dd, &unexpected);
- ret = IRQ_NONE;
- goto bail;
- }
if (unexpected)
unexpected = 0;
- ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat);
-
- if (istat & ~infinipath_i_bitsextant)
+ if (unlikely(istat & ~dd->ipath_i_bitsextant))
ipath_dev_err(dd,
"interrupt with unknown interrupts %x set\n",
- istat & (u32) ~ infinipath_i_bitsextant);
+ istat & (u32) ~ dd->ipath_i_bitsextant);
+ else
+ ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat);
- if (istat & INFINIPATH_I_ERROR) {
+ if (unlikely(istat & INFINIPATH_I_ERROR)) {
ipath_stats.sps_errints++;
estat = ipath_read_kreg64(dd,
dd->ipath_kregs->kr_errorstatus);
@@ -788,43 +944,117 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
ipath_dev_err(dd, "Read of error status failed "
"(all bits set); ignoring\n");
else
- handle_errors(dd, estat);
+ if (handle_errors(dd, estat))
+ /* force calling ipath_kreceive() */
+ chk0rcv = 1;
}
if (istat & INFINIPATH_I_GPIO) {
- if (unlikely(!(dd->ipath_flags & IPATH_GPIO_INTR))) {
- u32 gpiostatus;
- gpiostatus = ipath_read_kreg32(
- dd, dd->ipath_kregs->kr_gpio_status);
- ipath_dbg("Unexpected GPIO interrupt bits %x\n",
- gpiostatus);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
- gpiostatus);
- }
- else {
- /* Clear GPIO status bit 2 */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
- (u64) (1 << 2));
+ /*
+ * GPIO interrupts fall in two broad classes:
+ * GPIO_2 indicates (on some HT4xx boards) that a packet
+ * has arrived for Port 0. Checking for this
+ * is controlled by flag IPATH_GPIO_INTR.
+ * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
+ * that we need to count. Checking for this
+ * is controlled by flag IPATH_GPIO_ERRINTRS.
+ */
+ u32 gpiostatus;
+ u32 to_clear = 0;
+
+ gpiostatus = ipath_read_kreg32(
+ dd, dd->ipath_kregs->kr_gpio_status);
+ /* First the error-counter case.
+ */
+ if ((gpiostatus & IPATH_GPIO_ERRINTR_MASK) &&
+ (dd->ipath_flags & IPATH_GPIO_ERRINTRS)) {
+ /* want to clear the bits we see asserted. */
+ to_clear |= (gpiostatus & IPATH_GPIO_ERRINTR_MASK);
/*
- * Packets are available in the port 0 rcv queue.
- * Eventually this needs to be generalized to check
- * IPATH_GPIO_INTR, and the specific GPIO bit, if
- * GPIO interrupts are used for anything else.
+ * Count appropriately, clear bits out of our copy,
+ * as they have been "handled".
*/
- ipath_kreceive(dd);
+ if (gpiostatus & (1 << IPATH_GPIO_RXUVL_BIT)) {
+ ipath_dbg("FlowCtl on UnsupVL\n");
+ dd->ipath_rxfc_unsupvl_errs++;
+ }
+ if (gpiostatus & (1 << IPATH_GPIO_OVRUN_BIT)) {
+ ipath_dbg("Overrun Threshold exceeded\n");
+ dd->ipath_overrun_thresh_errs++;
+ }
+ if (gpiostatus & (1 << IPATH_GPIO_LLI_BIT)) {
+ ipath_dbg("Local Link Integrity error\n");
+ dd->ipath_lli_errs++;
+ }
+ gpiostatus &= ~IPATH_GPIO_ERRINTR_MASK;
+ }
+ /* Now the Port0 Receive case */
+ if ((gpiostatus & (1 << IPATH_GPIO_PORT0_BIT)) &&
+ (dd->ipath_flags & IPATH_GPIO_INTR)) {
+ /*
+ * GPIO status bit 2 is set, and we expected it.
+ * clear it and indicate in p0bits.
+ * This probably only happens if a Port0 pkt
+ * arrives at _just_ the wrong time, and we
+ * handle that by seting chk0rcv;
+ */
+ to_clear |= (1 << IPATH_GPIO_PORT0_BIT);
+ gpiostatus &= ~(1 << IPATH_GPIO_PORT0_BIT);
+ chk0rcv = 1;
+ }
+ if (unlikely(gpiostatus)) {
+ /*
+ * Some unexpected bits remain. If they could have
+ * caused the interrupt, complain and clear.
+ * MEA: this is almost certainly non-ideal.
+ * we should look into auto-disable of unexpected
+ * GPIO interrupts, possibly on a "three strikes"
+ * basis.
+ */
+ u32 mask;
+ mask = ipath_read_kreg32(
+ dd, dd->ipath_kregs->kr_gpio_mask);
+ if (mask & gpiostatus) {
+ ipath_dbg("Unexpected GPIO IRQ bits %x\n",
+ gpiostatus & mask);
+ to_clear |= (gpiostatus & mask);
+ }
+ }
+ if (to_clear) {
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+ (u64) to_clear);
}
}
+ chk0rcv |= istat & port0rbits;
/*
- * clear the ones we will deal with on this round
- * We clear it early, mostly for receive interrupts, so we
- * know the chip will have seen this by the time we process
- * the queue, and will re-interrupt if necessary. The processor
- * itself won't take the interrupt again until we return.
+ * Clear the interrupt bits we found set, unless they are receive
+ * related, in which case we already cleared them above, and don't
+ * want to clear them again, because we might lose an interrupt.
+ * Clear it early, so we "know" know the chip will have seen this by
+ * the time we process the queue, and will re-interrupt if necessary.
+ * The processor itself won't take the interrupt again until we return.
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
+ /*
+ * handle port0 receive before checking for pio buffers available,
+ * since receives can overflow; piobuf waiters can afford a few
+ * extra cycles, since they were waiting anyway, and user's waiting
+ * for receive are at the bottom.
+ */
+ if (chk0rcv) {
+ ipath_kreceive(dd);
+ istat &= ~port0rbits;
+ }
+
+ if (istat & ((dd->ipath_i_rcvavail_mask <<
+ INFINIPATH_I_RCVAVAIL_SHIFT)
+ | (dd->ipath_i_rcvurg_mask <<
+ INFINIPATH_I_RCVURG_SHIFT)))
+ handle_urcv(dd, istat);
+
if (istat & INFINIPATH_I_SPIOBUFAVAIL) {
clear_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
@@ -836,17 +1066,7 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
handle_layer_pioavail(dd);
}
- /*
- * we check for both transition from empty to non-empty, and urgent
- * packets (those with the interrupt bit set in the header)
- */
-
- if (istat & ((infinipath_i_rcvavail_mask <<
- INFINIPATH_I_RCVAVAIL_SHIFT)
- | (infinipath_i_rcvurg_mask <<
- INFINIPATH_I_RCVURG_SHIFT)))
- handle_rcv(dd, istat);
-
+done:
ret = IRQ_HANDLED;
bail:
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 5d92d57b6f5..d7540b71b45 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -1,6 +1,7 @@
#ifndef _IPATH_KERNEL_H
#define _IPATH_KERNEL_H
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -38,6 +39,8 @@
*/
#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include "ipath_common.h"
@@ -61,9 +64,7 @@ struct ipath_portdata {
/* rcvhdrq base, needs mmap before useful */
void *port_rcvhdrq;
/* kernel virtual address where hdrqtail is updated */
- u64 *port_rcvhdrtail_kvaddr;
- /* page * used for uaddr */
- struct page *port_rcvhdrtail_pagep;
+ void *port_rcvhdrtail_kvaddr;
/*
* temp buffer for expected send setup, allocated at open, instead
* of each setup call
@@ -78,14 +79,10 @@ struct ipath_portdata {
dma_addr_t port_rcvegr_phys;
/* mmap of hdrq, must fit in 44 bits */
dma_addr_t port_rcvhdrq_phys;
+ dma_addr_t port_rcvhdrqtailaddr_phys;
/*
- * the actual user address that we ipath_mlock'ed, so we can
- * ipath_munlock it at close
- */
- unsigned long port_rcvhdrtail_uaddr;
- /*
- * number of opens on this instance (0 or 1; ignoring forks, dup,
- * etc. for now)
+ * number of opens (including slave subports) on this instance
+ * (ignoring forks, dup, etc. for now)
*/
int port_cnt;
/*
@@ -94,6 +91,10 @@ struct ipath_portdata {
*/
/* instead of calculating it */
unsigned port_port;
+ /* non-zero if port is being shared. */
+ u16 port_subport_cnt;
+ /* non-zero if port is being shared. */
+ u16 port_subport_id;
/* chip offset of PIO buffers for this port */
u32 port_piobufs;
/* how many alloc_pages() chunks in port_rcvegrbuf_pages */
@@ -126,6 +127,16 @@ struct ipath_portdata {
u16 port_pkeys[4];
/* so file ops can get at unit */
struct ipath_devdata *port_dd;
+ /* A page of memory for rcvhdrhead, rcvegrhead, rcvegrtail * N */
+ void *subport_uregbase;
+ /* An array of pages for the eager receive buffers * N */
+ void *subport_rcvegrbuf;
+ /* An array of pages for the eager header queue entries * N */
+ void *subport_rcvhdr_base;
+ /* The version of the library which opened this port */
+ u32 userversion;
+ /* Bitmask of active slaves */
+ u32 active_slaves;
};
struct sk_buff;
@@ -137,10 +148,9 @@ struct _ipath_layer {
void *l_arg;
};
-/* Verbs layer interface */
-struct _verbs_layer {
- void *l_arg;
- struct timer_list l_timer;
+struct ipath_skbinfo {
+ struct sk_buff *skb;
+ dma_addr_t phys;
};
struct ipath_devdata {
@@ -158,20 +168,14 @@ struct ipath_devdata {
/* base of memory alloced for ipath_kregbase, for free */
u64 *ipath_kregalloc;
/*
- * version of kregbase that doesn't have high bits set (for 32 bit
- * programs, so mmap64 44 bit works)
- */
- u64 __iomem *ipath_kregvirt;
- /*
* virtual address where port0 rcvhdrqtail updated for this unit.
* only written to by the chip, not the driver.
*/
volatile __le64 *ipath_hdrqtailptr;
- dma_addr_t ipath_dma_addr;
/* ipath_cfgports pointers */
struct ipath_portdata **ipath_pd;
/* sk_buffs used by port 0 eager receive queue */
- struct sk_buff **ipath_port0_skbs;
+ struct ipath_skbinfo *ipath_port0_skbinfo;
/* kvirt address of 1st 2k pio buffer */
void __iomem *ipath_pio2kbase;
/* kvirt address of 1st 4k pio buffer */
@@ -209,7 +213,8 @@ struct ipath_devdata {
void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64);
/* fill out chip-specific fields */
int (*ipath_f_get_base_info)(struct ipath_portdata *, void *);
- struct _verbs_layer verbs_layer;
+ struct ipath_ibdev *verbs_dev;
+ struct timer_list verbs_timer;
/* total dwords sent (summed from counter) */
u64 ipath_sword;
/* total dwords rcvd (summed from counter) */
@@ -252,7 +257,7 @@ struct ipath_devdata {
u64 ipath_tidtemplate;
/* value to write to free TIDs */
u64 ipath_tidinvalid;
- /* PE-800 rcv interrupt setup */
+ /* IBA6120 rcv interrupt setup */
u64 ipath_rhdrhead_intr_off;
/* size of memory at ipath_kregbase */
@@ -261,8 +266,8 @@ struct ipath_devdata {
u32 ipath_pioavregs;
/* IPATH_POLL, etc. */
u32 ipath_flags;
- /* ipath_flags sma is waiting for */
- u32 ipath_sma_state_wanted;
+ /* ipath_flags driver is waiting for */
+ u32 ipath_state_wanted;
/* last buffer for user use, first buf for kernel use is this
* index. */
u32 ipath_lastport_piobuf;
@@ -322,10 +327,6 @@ struct ipath_devdata {
u32 ipath_pcibar0;
/* so we can rewrite it after a chip reset */
u32 ipath_pcibar1;
- /* sequential tries for SMA send and no bufs */
- u32 ipath_nosma_bufs;
- /* duration (seconds) ipath_nosma_bufs set */
- u32 ipath_nosma_secs;
/* HT/PCI Vendor ID (here for NodeInfo) */
u16 ipath_vendorid;
@@ -335,12 +336,16 @@ struct ipath_devdata {
u8 ipath_ht_slave_off;
/* for write combining settings */
unsigned long ipath_wc_cookie;
+ unsigned long ipath_wc_base;
+ unsigned long ipath_wc_len;
/* ref count for each pkey */
atomic_t ipath_pkeyrefs[4];
/* shadow copy of all exptids physaddr; used only by funcsim */
u64 *ipath_tidsimshadow;
/* shadow copy of struct page *'s for exp tid pages */
struct page **ipath_pageshadow;
+ /* shadow copy of dma handles for exp tid pages */
+ dma_addr_t *ipath_physshadow;
/* lock to workaround chip bug 9437 */
spinlock_t ipath_tid_lock;
@@ -354,13 +359,17 @@ struct ipath_devdata {
char *ipath_freezemsg;
/* pci access data structure */
struct pci_dev *pcidev;
- struct cdev *cdev;
- struct class_device *class_dev;
+ struct cdev *user_cdev;
+ struct cdev *diag_cdev;
+ struct class_device *user_class_dev;
+ struct class_device *diag_class_dev;
/* timer used to prevent stats overflow, error throttling, etc. */
struct timer_list ipath_stats_timer;
/* check for stale messages in rcv queue */
/* only allow one intr at a time. */
unsigned long ipath_rcv_pending;
+ void *ipath_dummy_hdrq; /* used after port close */
+ dma_addr_t ipath_dummy_hdrq_phys;
/*
* Shadow copies of registers; size indicates read access size.
@@ -418,6 +427,9 @@ struct ipath_devdata {
unsigned long ipath_rcvctrl;
/* shadow kr_sendctrl */
unsigned long ipath_sendctrl;
+ /* ports waiting for PIOavail intr */
+ unsigned long ipath_portpiowait;
+ unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
/* value we put in kr_rcvhdrcnt */
u32 ipath_rcvhdrcnt;
@@ -481,8 +493,6 @@ struct ipath_devdata {
u32 ipath_htwidth;
/* HT speed (200,400,800,1000) from HT config */
u32 ipath_htspeed;
- /* ports waiting for PIOavail intr */
- unsigned long ipath_portpiowait;
/*
* number of sequential ibcstatus change for polling active/quiet
* (i.e., link not coming up).
@@ -500,8 +510,11 @@ struct ipath_devdata {
u16 ipath_lid;
/* list of pkeys programmed; 0 if not set */
u16 ipath_pkeys[4];
- /* ASCII serial number, from flash */
- u8 ipath_serial[12];
+ /*
+ * ASCII serial number, from flash, large enough for original
+ * all digit strings, and longer QLogic serial number format
+ */
+ u8 ipath_serial[16];
/* human readable board version */
u8 ipath_boardversion[80];
/* chip major rev, from ipath_revision */
@@ -516,34 +529,64 @@ struct ipath_devdata {
u8 ipath_pci_cacheline;
/* LID mask control */
u8 ipath_lmc;
-};
+ /* Rx Polarity inversion (compensate for ~tx on partner) */
+ u8 ipath_rx_pol_inv;
+
+ /* local link integrity counter */
+ u32 ipath_lli_counter;
+ /* local link integrity errors */
+ u32 ipath_lli_errors;
+ /*
+ * Above counts only cases where _successive_ LocalLinkIntegrity
+ * errors were seen in the receive headers of kern-packets.
+ * Below are the three (monotonically increasing) counters
+ * maintained via GPIO interrupts on iba6120-rev2.
+ */
+ u32 ipath_rxfc_unsupvl_errs;
+ u32 ipath_overrun_thresh_errs;
+ u32 ipath_lli_errs;
-extern volatile __le64 *ipath_port0_rcvhdrtail;
-extern dma_addr_t ipath_port0_rcvhdrtail_dma;
+ /*
+ * Not all devices managed by a driver instance are the same
+ * type, so these fields must be per-device.
+ */
+ u64 ipath_i_bitsextant;
+ ipath_err_t ipath_e_bitsextant;
+ ipath_err_t ipath_hwe_bitsextant;
+
+ /*
+ * Below should be computable from number of ports,
+ * since they are never modified.
+ */
+ u32 ipath_i_rcvavail_mask;
+ u32 ipath_i_rcvurg_mask;
-#define IPATH_PORT0_RCVHDRTAIL_SIZE PAGE_SIZE
+ /*
+ * Register bits for selecting i2c direction and values, used for
+ * I2C serial flash.
+ */
+ u16 ipath_gpio_sda_num;
+ u16 ipath_gpio_scl_num;
+ u64 ipath_gpio_sda;
+ u64 ipath_gpio_scl;
+};
+/* Private data for file operations */
+struct ipath_filedata {
+ struct ipath_portdata *pd;
+ unsigned subport;
+ unsigned tidcursor;
+};
extern struct list_head ipath_dev_list;
extern spinlock_t ipath_devs_lock;
extern struct ipath_devdata *ipath_lookup(int unit);
-extern u16 ipath_layer_rcv_opcode;
-extern int __ipath_layer_intr(struct ipath_devdata *, u32);
-extern int ipath_layer_intr(struct ipath_devdata *, u32);
-extern int __ipath_layer_rcv(struct ipath_devdata *, void *,
- struct sk_buff *);
-extern int __ipath_layer_rcv_lid(struct ipath_devdata *, void *);
-extern int __ipath_verbs_piobufavail(struct ipath_devdata *);
-extern int __ipath_verbs_rcv(struct ipath_devdata *, void *, void *, u32);
-
-void ipath_layer_add(struct ipath_devdata *);
-void ipath_layer_del(struct ipath_devdata *);
-
int ipath_init_chip(struct ipath_devdata *, int);
int ipath_enable_wc(struct ipath_devdata *dd);
void ipath_disable_wc(struct ipath_devdata *dd);
int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp);
void ipath_shutdown_device(struct ipath_devdata *);
+void ipath_disarm_senderrbufs(struct ipath_devdata *);
struct file_operations;
int ipath_cdev_init(int minor, char *name, struct file_operations *fops,
@@ -551,14 +594,13 @@ int ipath_cdev_init(int minor, char *name, struct file_operations *fops,
void ipath_cdev_cleanup(struct cdev **cdevp,
struct class_device **class_devp);
-int ipath_diag_init(void);
-void ipath_diag_cleanup(void);
-void ipath_diag_bringup_link(struct ipath_devdata *);
+int ipath_diag_add(struct ipath_devdata *);
+void ipath_diag_remove(struct ipath_devdata *);
-extern wait_queue_head_t ipath_sma_state_wait;
+extern wait_queue_head_t ipath_state_wait;
int ipath_user_add(struct ipath_devdata *dd);
-void ipath_user_del(struct ipath_devdata *dd);
+void ipath_user_remove(struct ipath_devdata *dd);
struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t);
@@ -582,19 +624,25 @@ void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
unsigned cnt);
int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *);
-void ipath_free_pddata(struct ipath_devdata *, u32, int);
+void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
int ipath_parse_ushort(const char *str, unsigned short *valp);
-int ipath_wait_linkstate(struct ipath_devdata *, u32, int);
-void ipath_set_ib_lstate(struct ipath_devdata *, int);
void ipath_kreceive(struct ipath_devdata *);
int ipath_setrcvhdrsize(struct ipath_devdata *, unsigned);
int ipath_reset_device(int);
void ipath_get_faststats(unsigned long);
+int ipath_set_linkstate(struct ipath_devdata *, u8);
+int ipath_set_mtu(struct ipath_devdata *, u16);
+int ipath_set_lid(struct ipath_devdata *, u32, u8);
+int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
/* for use in system calls, where we want to know device type, etc. */
-#define port_fp(fp) ((struct ipath_portdata *) (fp)->private_data)
+#define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
+#define subport_fp(fp) \
+ ((struct ipath_filedata *)(fp)->private_data)->subport
+#define tidcursor_fp(fp) \
+ ((struct ipath_filedata *)(fp)->private_data)->tidcursor
/*
* values for ipath_flags
@@ -634,6 +682,15 @@ void ipath_get_faststats(unsigned long);
/* can miss port0 rx interrupts */
#define IPATH_POLL_RX_INTR 0x40000
#define IPATH_DISABLED 0x80000 /* administratively disabled */
+ /* Use GPIO interrupts for new counters */
+#define IPATH_GPIO_ERRINTRS 0x100000
+
+/* Bits in GPIO for the added interrupts */
+#define IPATH_GPIO_PORT0_BIT 2
+#define IPATH_GPIO_RXUVL_BIT 3
+#define IPATH_GPIO_OVRUN_BIT 4
+#define IPATH_GPIO_LLI_BIT 5
+#define IPATH_GPIO_ERRINTR_MASK 0x38
/* portdata flag bit offsets */
/* waiting for a packet to arrive */
@@ -646,10 +703,8 @@ void ipath_free_data(struct ipath_portdata *dd);
int ipath_waitfor_mdio_cmdready(struct ipath_devdata *);
int ipath_waitfor_complete(struct ipath_devdata *, ipath_kreg, u64, u64 *);
u32 __iomem *ipath_getpiobuf(struct ipath_devdata *, u32 *);
-/* init PE-800-specific func */
-void ipath_init_pe800_funcs(struct ipath_devdata *);
-/* init HT-400-specific func */
-void ipath_init_ht400_funcs(struct ipath_devdata *);
+void ipath_init_iba6120_funcs(struct ipath_devdata *);
+void ipath_init_iba6110_funcs(struct ipath_devdata *);
void ipath_get_eeprom_info(struct ipath_devdata *);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
@@ -720,13 +775,8 @@ u64 ipath_read_kreg64_port(const struct ipath_devdata *, ipath_kreg,
* @port: port number
*
* Return the contents of a register that is virtualized to be per port.
- * Prints a debug message and returns -1 on errors (not distinguishable from
- * valid contents at runtime; we may add a separate error variable at some
- * point).
- *
- * This is normally not used by the kernel, but may be for debugging, and
- * has a different implementation than user mode, which is why it's not in
- * _common.h.
+ * Returns -1 on errors (not distinguishable from valid contents at
+ * runtime; we may add a separate error variable at some point).
*/
static inline u32 ipath_read_ureg32(const struct ipath_devdata *dd,
ipath_ureg regno, int port)
@@ -810,7 +860,7 @@ static inline u32 ipath_read_creg32(const struct ipath_devdata *dd,
struct device_driver;
-extern const char ipath_core_version[];
+extern const char ib_ipath_version[];
int ipath_driver_create_group(struct device_driver *);
void ipath_driver_remove_group(struct device_driver *);
@@ -819,12 +869,22 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *);
void ipath_device_remove_group(struct device *, struct ipath_devdata *);
int ipath_expose_reset(struct device *);
+int ipath_diagpkt_add(void);
+void ipath_diagpkt_remove(void);
+
int ipath_init_ipathfs(void);
void ipath_exit_ipathfs(void);
int ipathfs_add_device(struct ipath_devdata *);
int ipathfs_remove_device(struct ipath_devdata *);
/*
+ * dma_addr wrappers - all 0's invalid for hw
+ */
+dma_addr_t ipath_map_page(struct pci_dev *, struct page *, unsigned long,
+ size_t, int);
+dma_addr_t ipath_map_single(struct pci_dev *, void *, size_t, int);
+
+/*
* Flush write combining store buffers (if present) and perform a write
* barrier.
*/
@@ -840,11 +900,12 @@ const char *ipath_get_unit_name(int unit);
extern struct mutex ipath_mutex;
-#define IPATH_DRV_NAME "ipath_core"
+#define IPATH_DRV_NAME "ib_ipath"
#define IPATH_MAJOR 233
-#define IPATH_SMA_MINOR 128
-#define IPATH_DIAG_MINOR 129
-#define IPATH_NMINORS 130
+#define IPATH_USER_MINOR_BASE 0
+#define IPATH_DIAGPKT_MINOR 127
+#define IPATH_DIAG_MINOR_BASE 129
+#define IPATH_NMINORS 255
#define ipath_dev_err(dd,fmt,...) \
do { \
@@ -880,4 +941,20 @@ extern struct mutex ipath_mutex;
#endif /* _IPATH_DEBUGGING */
+/*
+ * this is used for formatting hw error messages...
+ */
+struct ipath_hwerror_msgs {
+ u64 mask;
+ const char *msg;
+};
+
+#define INFINIPATH_HWE_MSG(a, b) { .mask = INFINIPATH_HWE_##a, .msg = b }
+
+/* in ipath_intr.c... */
+void ipath_format_hwerrors(u64 hwerrs,
+ const struct ipath_hwerror_msgs *hwerrmsgs,
+ size_t nhwerrmsgs,
+ char *msg, size_t lmsg);
+
#endif /* _IPATH_KERNEL_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index 5ae8761f9dd..9a6cbd05adc 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -33,6 +34,7 @@
#include <asm/io.h>
#include "ipath_verbs.h"
+#include "ipath_kernel.h"
/**
* ipath_alloc_lkey - allocate an lkey
@@ -59,7 +61,7 @@ int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr)
r = (r + 1) & (rkt->max - 1);
if (r == n) {
spin_unlock_irqrestore(&rkt->lock, flags);
- _VERBS_INFO("LKEY table full\n");
+ ipath_dbg(KERN_INFO "LKEY table full\n");
ret = 0;
goto bail;
}
@@ -116,10 +118,12 @@ void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey)
* Check the IB SGE for validity and initialize our internal version
* of it.
*/
-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
+int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
struct ib_sge *sge, int acc)
{
+ struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
struct ipath_mregion *mr;
+ unsigned n, m;
size_t off;
int ret;
@@ -137,7 +141,8 @@ int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
goto bail;
}
mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
- if (unlikely(mr == NULL || mr->lkey != sge->lkey)) {
+ if (unlikely(mr == NULL || mr->lkey != sge->lkey ||
+ qp->ibqp.pd != mr->pd)) {
ret = 0;
goto bail;
}
@@ -151,20 +156,22 @@ int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
}
off += mr->offset;
- isge->mr = mr;
- isge->m = 0;
- isge->n = 0;
- while (off >= mr->map[isge->m]->segs[isge->n].length) {
- off -= mr->map[isge->m]->segs[isge->n].length;
- isge->n++;
- if (isge->n >= IPATH_SEGSZ) {
- isge->m++;
- isge->n = 0;
+ m = 0;
+ n = 0;
+ while (off >= mr->map[m]->segs[n].length) {
+ off -= mr->map[m]->segs[n].length;
+ n++;
+ if (n >= IPATH_SEGSZ) {
+ m++;
+ n = 0;
}
}
- isge->vaddr = mr->map[isge->m]->segs[isge->n].vaddr + off;
- isge->length = mr->map[isge->m]->segs[isge->n].length - off;
+ isge->mr = mr;
+ isge->vaddr = mr->map[m]->segs[n].vaddr + off;
+ isge->length = mr->map[m]->segs[n].length - off;
isge->sge_length = sge->length;
+ isge->m = m;
+ isge->n = n;
ret = 1;
@@ -183,17 +190,35 @@ bail:
*
* Return 1 if successful, otherwise 0.
*/
-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
+int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
u32 len, u64 vaddr, u32 rkey, int acc)
{
+ struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_lkey_table *rkt = &dev->lk_table;
struct ipath_sge *sge = &ss->sge;
struct ipath_mregion *mr;
+ unsigned n, m;
size_t off;
int ret;
+ /*
+ * We use RKEY == zero for physical addresses
+ * (see ipath_get_dma_mr).
+ */
+ if (rkey == 0) {
+ sge->mr = NULL;
+ sge->vaddr = phys_to_virt(vaddr);
+ sge->length = len;
+ sge->sge_length = len;
+ ss->sg_list = NULL;
+ ss->num_sge = 1;
+ ret = 1;
+ goto bail;
+ }
+
mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
- if (unlikely(mr == NULL || mr->lkey != rkey)) {
+ if (unlikely(mr == NULL || mr->lkey != rkey ||
+ qp->ibqp.pd != mr->pd)) {
ret = 0;
goto bail;
}
@@ -206,20 +231,22 @@ int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
}
off += mr->offset;
- sge->mr = mr;
- sge->m = 0;
- sge->n = 0;
- while (off >= mr->map[sge->m]->segs[sge->n].length) {
- off -= mr->map[sge->m]->segs[sge->n].length;
- sge->n++;
- if (sge->n >= IPATH_SEGSZ) {
- sge->m++;
- sge->n = 0;
+ m = 0;
+ n = 0;
+ while (off >= mr->map[m]->segs[n].length) {
+ off -= mr->map[m]->segs[n].length;
+ n++;
+ if (n >= IPATH_SEGSZ) {
+ m++;
+ n = 0;
}
}
- sge->vaddr = mr->map[sge->m]->segs[sge->n].vaddr + off;
- sge->length = mr->map[sge->m]->segs[sge->n].length - off;
+ sge->mr = mr;
+ sge->vaddr = mr->map[m]->segs[n].vaddr + off;
+ sge->length = mr->map[m]->segs[n].length - off;
sge->sge_length = len;
+ sge->m = m;
+ sge->n = n;
ss->sg_list = NULL;
ss->num_sge = 1;
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.c b/drivers/infiniband/hw/ipath/ipath_layer.c
index 9ec4ac77b87..e46aa4ed2a7 100644
--- a/drivers/infiniband/hw/ipath/ipath_layer.c
+++ b/drivers/infiniband/hw/ipath/ipath_layer.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -40,27 +41,21 @@
#include <asm/byteorder.h>
#include "ipath_kernel.h"
-#include "ips_common.h"
#include "ipath_layer.h"
+#include "ipath_verbs.h"
+#include "ipath_common.h"
/* Acquire before ipath_devs_lock. */
static DEFINE_MUTEX(ipath_layer_mutex);
-static int ipath_verbs_registered;
-
u16 ipath_layer_rcv_opcode;
static int (*layer_intr)(void *, u32);
static int (*layer_rcv)(void *, void *, struct sk_buff *);
static int (*layer_rcv_lid)(void *, void *);
-static int (*verbs_piobufavail)(void *);
-static void (*verbs_rcv)(void *, void *, void *, u32);
static void *(*layer_add_one)(int, struct ipath_devdata *);
static void (*layer_remove_one)(void *);
-static void *(*verbs_add_one)(int, struct ipath_devdata *);
-static void (*verbs_remove_one)(void *);
-static void (*verbs_timer_cb)(void *);
int __ipath_layer_intr(struct ipath_devdata *dd, u32 arg)
{
@@ -106,288 +101,16 @@ int __ipath_layer_rcv_lid(struct ipath_devdata *dd, void *hdr)
return ret;
}
-int __ipath_verbs_piobufavail(struct ipath_devdata *dd)
-{
- int ret = -ENODEV;
-
- if (dd->verbs_layer.l_arg && verbs_piobufavail)
- ret = verbs_piobufavail(dd->verbs_layer.l_arg);
-
- return ret;
-}
-
-int __ipath_verbs_rcv(struct ipath_devdata *dd, void *rc, void *ebuf,
- u32 tlen)
-{
- int ret = -ENODEV;
-
- if (dd->verbs_layer.l_arg && verbs_rcv) {
- verbs_rcv(dd->verbs_layer.l_arg, rc, ebuf, tlen);
- ret = 0;
- }
-
- return ret;
-}
-
-int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 newstate)
-{
- u32 lstate;
- int ret;
-
- switch (newstate) {
- case IPATH_IB_LINKDOWN:
- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_POLL <<
- INFINIPATH_IBCC_LINKINITCMD_SHIFT);
- /* don't wait */
- ret = 0;
- goto bail;
-
- case IPATH_IB_LINKDOWN_SLEEP:
- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKINITCMD_SLEEP <<
- INFINIPATH_IBCC_LINKINITCMD_SHIFT);
- /* don't wait */
- ret = 0;
- goto bail;
-
- case IPATH_IB_LINKDOWN_DISABLE:
- ipath_set_ib_lstate(dd,
- INFINIPATH_IBCC_LINKINITCMD_DISABLE <<
- INFINIPATH_IBCC_LINKINITCMD_SHIFT);
- /* don't wait */
- ret = 0;
- goto bail;
-
- case IPATH_IB_LINKINIT:
- if (dd->ipath_flags & IPATH_LINKINIT) {
- ret = 0;
- goto bail;
- }
- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_INIT <<
- INFINIPATH_IBCC_LINKCMD_SHIFT);
- lstate = IPATH_LINKINIT;
- break;
-
- case IPATH_IB_LINKARM:
- if (dd->ipath_flags & IPATH_LINKARMED) {
- ret = 0;
- goto bail;
- }
- if (!(dd->ipath_flags &
- (IPATH_LINKINIT | IPATH_LINKACTIVE))) {
- ret = -EINVAL;
- goto bail;
- }
- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ARMED <<
- INFINIPATH_IBCC_LINKCMD_SHIFT);
- /*
- * Since the port can transition to ACTIVE by receiving
- * a non VL 15 packet, wait for either state.
- */
- lstate = IPATH_LINKARMED | IPATH_LINKACTIVE;
- break;
-
- case IPATH_IB_LINKACTIVE:
- if (dd->ipath_flags & IPATH_LINKACTIVE) {
- ret = 0;
- goto bail;
- }
- if (!(dd->ipath_flags & IPATH_LINKARMED)) {
- ret = -EINVAL;
- goto bail;
- }
- ipath_set_ib_lstate(dd, INFINIPATH_IBCC_LINKCMD_ACTIVE <<
- INFINIPATH_IBCC_LINKCMD_SHIFT);
- lstate = IPATH_LINKACTIVE;
- break;
-
- default:
- ipath_dbg("Invalid linkstate 0x%x requested\n", newstate);
- ret = -EINVAL;
- goto bail;
- }
- ret = ipath_wait_linkstate(dd, lstate, 2000);
-
-bail:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_linkstate);
-
-/**
- * ipath_layer_set_mtu - set the MTU
- * @dd: the infinipath device
- * @arg: the new MTU
- *
- * we can handle "any" incoming size, the issue here is whether we
- * need to restrict our outgoing size. For now, we don't do any
- * sanity checking on this, and we don't deal with what happens to
- * programs that are already running when the size changes.
- * NOTE: changing the MTU will usually cause the IBC to go back to
- * link initialize (IPATH_IBSTATE_INIT) state...
- */
-int ipath_layer_set_mtu(struct ipath_devdata *dd, u16 arg)
-{
- u32 piosize;
- int changed = 0;
- int ret;
-
- /*
- * mtu is IB data payload max. It's the largest power of 2 less
- * than piosize (or even larger, since it only really controls the
- * largest we can receive; we can send the max of the mtu and
- * piosize). We check that it's one of the valid IB sizes.
- */
- if (arg != 256 && arg != 512 && arg != 1024 && arg != 2048 &&
- arg != 4096) {
- ipath_dbg("Trying to set invalid mtu %u, failing\n", arg);
- ret = -EINVAL;
- goto bail;
- }
- if (dd->ipath_ibmtu == arg) {
- ret = 0; /* same as current */
- goto bail;
- }
-
- piosize = dd->ipath_ibmaxlen;
- dd->ipath_ibmtu = arg;
-
- if (arg >= (piosize - IPATH_PIO_MAXIBHDR)) {
- /* Only if it's not the initial value (or reset to it) */
- if (piosize != dd->ipath_init_ibmaxlen) {
- dd->ipath_ibmaxlen = piosize;
- changed = 1;
- }
- } else if ((arg + IPATH_PIO_MAXIBHDR) != dd->ipath_ibmaxlen) {
- piosize = arg + IPATH_PIO_MAXIBHDR;
- ipath_cdbg(VERBOSE, "ibmaxlen was 0x%x, setting to 0x%x "
- "(mtu 0x%x)\n", dd->ipath_ibmaxlen, piosize,
- arg);
- dd->ipath_ibmaxlen = piosize;
- changed = 1;
- }
-
- if (changed) {
- /*
- * set the IBC maxpktlength to the size of our pio
- * buffers in words
- */
- u64 ibc = dd->ipath_ibcctrl;
- ibc &= ~(INFINIPATH_IBCC_MAXPKTLEN_MASK <<
- INFINIPATH_IBCC_MAXPKTLEN_SHIFT);
-
- piosize = piosize - 2 * sizeof(u32); /* ignore pbc */
- dd->ipath_ibmaxlen = piosize;
- piosize /= sizeof(u32); /* in words */
- /*
- * for ICRC, which we only send in diag test pkt mode, and
- * we don't need to worry about that for mtu
- */
- piosize += 1;
-
- ibc |= piosize << INFINIPATH_IBCC_MAXPKTLEN_SHIFT;
- dd->ipath_ibcctrl = ibc;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
- dd->ipath_ibcctrl);
- dd->ipath_f_tidtemplate(dd);
- }
-
- ret = 0;
-
-bail:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_mtu);
-
-int ipath_set_sps_lid(struct ipath_devdata *dd, u32 arg, u8 lmc)
+void ipath_layer_lid_changed(struct ipath_devdata *dd)
{
- ipath_stats.sps_lid[dd->ipath_unit] = arg;
- dd->ipath_lid = arg;
- dd->ipath_lmc = lmc;
-
mutex_lock(&ipath_layer_mutex);
if (dd->ipath_layer.l_arg && layer_intr)
layer_intr(dd->ipath_layer.l_arg, IPATH_LAYER_INT_LID);
mutex_unlock(&ipath_layer_mutex);
-
- return 0;
}
-EXPORT_SYMBOL_GPL(ipath_set_sps_lid);
-
-int ipath_layer_set_guid(struct ipath_devdata *dd, __be64 guid)
-{
- /* XXX - need to inform anyone who cares this just happened. */
- dd->ipath_guid = guid;
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_guid);
-
-__be64 ipath_layer_get_guid(struct ipath_devdata *dd)
-{
- return dd->ipath_guid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_guid);
-
-u32 ipath_layer_get_nguid(struct ipath_devdata *dd)
-{
- return dd->ipath_nguid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_nguid);
-
-int ipath_layer_query_device(struct ipath_devdata *dd, u32 * vendor,
- u32 * boardrev, u32 * majrev, u32 * minrev)
-{
- *vendor = dd->ipath_vendorid;
- *boardrev = dd->ipath_boardrev;
- *majrev = dd->ipath_majrev;
- *minrev = dd->ipath_minrev;
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_query_device);
-
-u32 ipath_layer_get_flags(struct ipath_devdata *dd)
-{
- return dd->ipath_flags;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_flags);
-
-struct device *ipath_layer_get_device(struct ipath_devdata *dd)
-{
- return &dd->pcidev->dev;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_device);
-
-u16 ipath_layer_get_deviceid(struct ipath_devdata *dd)
-{
- return dd->ipath_deviceid;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_deviceid);
-
-u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd)
-{
- return dd->ipath_lastibcstat;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_lastibcstat);
-
-u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd)
-{
- return dd->ipath_ibmtu;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_ibmtu);
-
void ipath_layer_add(struct ipath_devdata *dd)
{
mutex_lock(&ipath_layer_mutex);
@@ -396,14 +119,10 @@ void ipath_layer_add(struct ipath_devdata *dd)
dd->ipath_layer.l_arg =
layer_add_one(dd->ipath_unit, dd);
- if (verbs_add_one)
- dd->verbs_layer.l_arg =
- verbs_add_one(dd->ipath_unit, dd);
-
mutex_unlock(&ipath_layer_mutex);
}
-void ipath_layer_del(struct ipath_devdata *dd)
+void ipath_layer_remove(struct ipath_devdata *dd)
{
mutex_lock(&ipath_layer_mutex);
@@ -412,11 +131,6 @@ void ipath_layer_del(struct ipath_devdata *dd)
dd->ipath_layer.l_arg = NULL;
}
- if (dd->verbs_layer.l_arg && verbs_remove_one) {
- verbs_remove_one(dd->verbs_layer.l_arg);
- dd->verbs_layer.l_arg = NULL;
- }
-
mutex_unlock(&ipath_layer_mutex);
}
@@ -448,9 +162,6 @@ int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
if (dd->ipath_layer.l_arg)
continue;
- if (!(*dd->ipath_statusp & IPATH_STATUS_SMA))
- *dd->ipath_statusp |= IPATH_STATUS_OIB_SMA;
-
spin_unlock_irqrestore(&ipath_devs_lock, flags);
dd->ipath_layer.l_arg = l_add(dd->ipath_unit, dd);
spin_lock_irqsave(&ipath_devs_lock, flags);
@@ -494,107 +205,6 @@ void ipath_layer_unregister(void)
EXPORT_SYMBOL_GPL(ipath_layer_unregister);
-static void __ipath_verbs_timer(unsigned long arg)
-{
- struct ipath_devdata *dd = (struct ipath_devdata *) arg;
-
- /*
- * If port 0 receive packet interrupts are not available, or
- * can be missed, poll the receive queue
- */
- if (dd->ipath_flags & IPATH_POLL_RX_INTR)
- ipath_kreceive(dd);
-
- /* Handle verbs layer timeouts. */
- if (dd->verbs_layer.l_arg && verbs_timer_cb)
- verbs_timer_cb(dd->verbs_layer.l_arg);
-
- mod_timer(&dd->verbs_layer.l_timer, jiffies + 1);
-}
-
-/**
- * ipath_verbs_register - verbs layer registration
- * @l_piobufavail: callback for when PIO buffers become available
- * @l_rcv: callback for receiving a packet
- * @l_timer_cb: timer callback
- * @ipath_devdata: device data structure is put here
- */
-int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *),
- void (*l_remove)(void *arg),
- int (*l_piobufavail) (void *arg),
- void (*l_rcv) (void *arg, void *rhdr,
- void *data, u32 tlen),
- void (*l_timer_cb) (void *arg))
-{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- mutex_lock(&ipath_layer_mutex);
-
- verbs_add_one = l_add;
- verbs_remove_one = l_remove;
- verbs_piobufavail = l_piobufavail;
- verbs_rcv = l_rcv;
- verbs_timer_cb = l_timer_cb;
-
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- if (!(dd->ipath_flags & IPATH_INITTED))
- continue;
-
- if (dd->verbs_layer.l_arg)
- continue;
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- dd->verbs_layer.l_arg = l_add(dd->ipath_unit, dd);
- spin_lock_irqsave(&ipath_devs_lock, flags);
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- mutex_unlock(&ipath_layer_mutex);
-
- ipath_verbs_registered = 1;
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_verbs_register);
-
-void ipath_verbs_unregister(void)
-{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- mutex_lock(&ipath_layer_mutex);
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- *dd->ipath_statusp &= ~IPATH_STATUS_OIB_SMA;
-
- if (dd->verbs_layer.l_arg && verbs_remove_one) {
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
- verbs_remove_one(dd->verbs_layer.l_arg);
- spin_lock_irqsave(&ipath_devs_lock, flags);
- dd->verbs_layer.l_arg = NULL;
- }
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
- verbs_add_one = NULL;
- verbs_remove_one = NULL;
- verbs_piobufavail = NULL;
- verbs_rcv = NULL;
- verbs_timer_cb = NULL;
-
- ipath_verbs_registered = 0;
-
- mutex_unlock(&ipath_layer_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ipath_verbs_unregister);
-
int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
{
int ret;
@@ -607,7 +217,7 @@ int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
goto bail;
}
- ret = ipath_setrcvhdrsize(dd, NUM_OF_EXTRA_WORDS_IN_HEADER_QUEUE);
+ ret = ipath_setrcvhdrsize(dd, IPATH_HEADER_QUEUE_WORDS);
if (ret < 0)
goto bail;
@@ -616,9 +226,9 @@ int ipath_layer_open(struct ipath_devdata *dd, u32 * pktmax)
if (*dd->ipath_statusp & IPATH_STATUS_IB_READY)
intval |= IPATH_LAYER_INT_IF_UP;
- if (ipath_stats.sps_lid[dd->ipath_unit])
+ if (dd->ipath_lid)
intval |= IPATH_LAYER_INT_LID;
- if (ipath_stats.sps_mlid[dd->ipath_unit])
+ if (dd->ipath_mlid)
intval |= IPATH_LAYER_INT_BCAST;
/*
* do this on open, in case low level is already up and
@@ -683,385 +293,6 @@ u16 ipath_layer_get_bcast(struct ipath_devdata *dd)
EXPORT_SYMBOL_GPL(ipath_layer_get_bcast);
-u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd)
-{
- return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_cr_errpkey);
-
-static void update_sge(struct ipath_sge_state *ss, u32 length)
-{
- struct ipath_sge *sge = &ss->sge;
-
- sge->vaddr += length;
- sge->length -= length;
- sge->sge_length -= length;
- if (sge->sge_length == 0) {
- if (--ss->num_sge)
- *sge = *ss->sg_list++;
- } else if (sge->length == 0 && sge->mr != NULL) {
- if (++sge->n >= IPATH_SEGSZ) {
- if (++sge->m >= sge->mr->mapsz)
- return;
- sge->n = 0;
- }
- sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;
- sge->length = sge->mr->map[sge->m]->segs[sge->n].length;
- }
-}
-
-#ifdef __LITTLE_ENDIAN
-static inline u32 get_upper_bits(u32 data, u32 shift)
-{
- return data >> shift;
-}
-
-static inline u32 set_upper_bits(u32 data, u32 shift)
-{
- return data << shift;
-}
-
-static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
-{
- data <<= ((sizeof(u32) - n) * BITS_PER_BYTE);
- data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
- return data;
-}
-#else
-static inline u32 get_upper_bits(u32 data, u32 shift)
-{
- return data << shift;
-}
-
-static inline u32 set_upper_bits(u32 data, u32 shift)
-{
- return data >> shift;
-}
-
-static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
-{
- data >>= ((sizeof(u32) - n) * BITS_PER_BYTE);
- data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
- return data;
-}
-#endif
-
-static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
- u32 length)
-{
- u32 extra = 0;
- u32 data = 0;
- u32 last;
-
- while (1) {
- u32 len = ss->sge.length;
- u32 off;
-
- BUG_ON(len == 0);
- if (len > length)
- len = length;
- if (len > ss->sge.sge_length)
- len = ss->sge.sge_length;
- /* If the source address is not aligned, try to align it. */
- off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
- if (off) {
- u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr &
- ~(sizeof(u32) - 1));
- u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE);
- u32 y;
-
- y = sizeof(u32) - off;
- if (len > y)
- len = y;
- if (len + extra >= sizeof(u32)) {
- data |= set_upper_bits(v, extra *
- BITS_PER_BYTE);
- len = sizeof(u32) - extra;
- if (len == length) {
- last = data;
- break;
- }
- __raw_writel(data, piobuf);
- piobuf++;
- extra = 0;
- data = 0;
- } else {
- /* Clear unused upper bytes */
- data |= clear_upper_bytes(v, len, extra);
- if (len == length) {
- last = data;
- break;
- }
- extra += len;
- }
- } else if (extra) {
- /* Source address is aligned. */
- u32 *addr = (u32 *) ss->sge.vaddr;
- int shift = extra * BITS_PER_BYTE;
- int ushift = 32 - shift;
- u32 l = len;
-
- while (l >= sizeof(u32)) {
- u32 v = *addr;
-
- data |= set_upper_bits(v, shift);
- __raw_writel(data, piobuf);
- data = get_upper_bits(v, ushift);
- piobuf++;
- addr++;
- l -= sizeof(u32);
- }
- /*
- * We still have 'extra' number of bytes leftover.
- */
- if (l) {
- u32 v = *addr;
-
- if (l + extra >= sizeof(u32)) {
- data |= set_upper_bits(v, shift);
- len -= l + extra - sizeof(u32);
- if (len == length) {
- last = data;
- break;
- }
- __raw_writel(data, piobuf);
- piobuf++;
- extra = 0;
- data = 0;
- } else {
- /* Clear unused upper bytes */
- data |= clear_upper_bytes(v, l,
- extra);
- if (len == length) {
- last = data;
- break;
- }
- extra += l;
- }
- } else if (len == length) {
- last = data;
- break;
- }
- } else if (len == length) {
- u32 w;
-
- /*
- * Need to round up for the last dword in the
- * packet.
- */
- w = (len + 3) >> 2;
- __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
- piobuf += w - 1;
- last = ((u32 *) ss->sge.vaddr)[w - 1];
- break;
- } else {
- u32 w = len >> 2;
-
- __iowrite32_copy(piobuf, ss->sge.vaddr, w);
- piobuf += w;
-
- extra = len & (sizeof(u32) - 1);
- if (extra) {
- u32 v = ((u32 *) ss->sge.vaddr)[w];
-
- /* Clear unused upper bytes */
- data = clear_upper_bytes(v, extra, 0);
- }
- }
- update_sge(ss, len);
- length -= len;
- }
- /* Update address before sending packet. */
- update_sge(ss, length);
- /* must flush early everything before trigger word */
- ipath_flush_wc();
- __raw_writel(last, piobuf);
- /* be sure trigger word is written */
- ipath_flush_wc();
-}
-
-/**
- * ipath_verbs_send - send a packet from the verbs layer
- * @dd: the infinipath device
- * @hdrwords: the number of works in the header
- * @hdr: the packet header
- * @len: the length of the packet in bytes
- * @ss: the SGE to send
- *
- * This is like ipath_sma_send_pkt() in that we need to be able to send
- * packets after the chip is initialized (MADs) but also like
- * ipath_layer_send_hdr() since its used by the verbs layer.
- */
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
- u32 *hdr, u32 len, struct ipath_sge_state *ss)
-{
- u32 __iomem *piobuf;
- u32 plen;
- int ret;
-
- /* +1 is for the qword padding of pbc */
- plen = hdrwords + ((len + 3) >> 2) + 1;
- if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
- ipath_dbg("packet len 0x%x too long, failing\n", plen);
- ret = -EINVAL;
- goto bail;
- }
-
- /* Get a PIO buffer to use. */
- piobuf = ipath_getpiobuf(dd, NULL);
- if (unlikely(piobuf == NULL)) {
- ret = -EBUSY;
- goto bail;
- }
-
- /*
- * Write len to control qword, no flags.
- * We have to flush after the PBC for correctness on some cpus
- * or WC buffer can be written out of order.
- */
- writeq(plen, piobuf);
- ipath_flush_wc();
- piobuf += 2;
- if (len == 0) {
- /*
- * If there is just the header portion, must flush before
- * writing last word of header for correctness, and after
- * the last header word (trigger word).
- */
- __iowrite32_copy(piobuf, hdr, hdrwords - 1);
- ipath_flush_wc();
- __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
- ipath_flush_wc();
- ret = 0;
- goto bail;
- }
-
- __iowrite32_copy(piobuf, hdr, hdrwords);
- piobuf += hdrwords;
-
- /* The common case is aligned and contained in one segment. */
- if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
- !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
- u32 w;
- u32 *addr = (u32 *) ss->sge.vaddr;
-
- /* Update address before sending packet. */
- update_sge(ss, len);
- /* Need to round up for the last dword in the packet. */
- w = (len + 3) >> 2;
- __iowrite32_copy(piobuf, addr, w - 1);
- /* must flush early everything before trigger word */
- ipath_flush_wc();
- __raw_writel(addr[w - 1], piobuf + w - 1);
- /* be sure trigger word is written */
- ipath_flush_wc();
- ret = 0;
- goto bail;
- }
- copy_io(piobuf, ss, len);
- ret = 0;
-
-bail:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_verbs_send);
-
-int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
- u64 *rwords, u64 *spkts, u64 *rpkts,
- u64 *xmit_wait)
-{
- int ret;
-
- if (!(dd->ipath_flags & IPATH_INITTED)) {
- /* no hardware, freeze, etc. */
- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
- ret = -EINVAL;
- goto bail;
- }
- *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
- *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
- *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
- *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt);
-
- ret = 0;
-
-bail:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_snapshot_counters);
-
-/**
- * ipath_layer_get_counters - get various chip counters
- * @dd: the infinipath device
- * @cntrs: counters are placed here
- *
- * Return the counters needed by recv_pma_get_portcounters().
- */
-int ipath_layer_get_counters(struct ipath_devdata *dd,
- struct ipath_layer_counters *cntrs)
-{
- int ret;
-
- if (!(dd->ipath_flags & IPATH_INITTED)) {
- /* no hardware, freeze, etc. */
- ipath_dbg("unit %u not usable\n", dd->ipath_unit);
- ret = -EINVAL;
- goto bail;
- }
- cntrs->symbol_error_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
- cntrs->link_error_recovery_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
- cntrs->link_downed_counter =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
- cntrs->port_rcv_errors =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errrcvflowctrlcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlinkcnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt);
- cntrs->port_rcv_remphys_errors =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
- cntrs->port_xmit_discards =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
- cntrs->port_xmit_data =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
- cntrs->port_rcv_data =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
- cntrs->port_xmit_packets =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
- cntrs->port_rcv_packets =
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
-
- ret = 0;
-
-bail:
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_counters);
-
-int ipath_layer_want_buffer(struct ipath_devdata *dd)
-{
- set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- dd->ipath_sendctrl);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_want_buffer);
-
int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr)
{
int ret = 0;
@@ -1086,10 +317,10 @@ int ipath_layer_send_hdr(struct ipath_devdata *dd, struct ether_header *hdr)
}
vlsllnh = *((__be16 *) hdr);
- if (vlsllnh != htons(IPS_LRH_BTH)) {
+ if (vlsllnh != htons(IPATH_LRH_BTH)) {
ipath_dbg("Warning: lrh[0] wrong (%x, not %x); "
"not sending\n", be16_to_cpu(vlsllnh),
- IPS_LRH_BTH);
+ IPATH_LRH_BTH);
ret = -EINVAL;
}
if (ret)
@@ -1133,389 +364,3 @@ int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd)
}
EXPORT_SYMBOL_GPL(ipath_layer_set_piointbufavail_int);
-
-int ipath_layer_enable_timer(struct ipath_devdata *dd)
-{
- /*
- * HT-400 has a design flaw where the chip and kernel idea
- * of the tail register don't always agree, and therefore we won't
- * get an interrupt on the next packet received.
- * If the board supports per packet receive interrupts, use it.
- * Otherwise, the timer function periodically checks for packets
- * to cover this case.
- * Either way, the timer is needed for verbs layer related
- * processing.
- */
- if (dd->ipath_flags & IPATH_GPIO_INTR) {
- ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect,
- 0x2074076542310ULL);
- /* Enable GPIO bit 2 interrupt */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
- (u64) (1 << 2));
- }
-
- init_timer(&dd->verbs_layer.l_timer);
- dd->verbs_layer.l_timer.function = __ipath_verbs_timer;
- dd->verbs_layer.l_timer.data = (unsigned long)dd;
- dd->verbs_layer.l_timer.expires = jiffies + 1;
- add_timer(&dd->verbs_layer.l_timer);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_enable_timer);
-
-int ipath_layer_disable_timer(struct ipath_devdata *dd)
-{
- /* Disable GPIO bit 2 interrupt */
- if (dd->ipath_flags & IPATH_GPIO_INTR)
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0);
-
- del_timer_sync(&dd->verbs_layer.l_timer);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_disable_timer);
-
-/**
- * ipath_layer_set_verbs_flags - set the verbs layer flags
- * @dd: the infinipath device
- * @flags: the flags to set
- */
-int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags)
-{
- struct ipath_devdata *ss;
- unsigned long lflags;
-
- spin_lock_irqsave(&ipath_devs_lock, lflags);
-
- list_for_each_entry(ss, &ipath_dev_list, ipath_list) {
- if (!(ss->ipath_flags & IPATH_INITTED))
- continue;
- if ((flags & IPATH_VERBS_KERNEL_SMA) &&
- !(*ss->ipath_statusp & IPATH_STATUS_SMA))
- *ss->ipath_statusp |= IPATH_STATUS_OIB_SMA;
- else
- *ss->ipath_statusp &= ~IPATH_STATUS_OIB_SMA;
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, lflags);
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_verbs_flags);
-
-/**
- * ipath_layer_get_npkeys - return the size of the PKEY table for port 0
- * @dd: the infinipath device
- */
-unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd)
-{
- return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys);
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_npkeys);
-
-/**
- * ipath_layer_get_pkey - return the indexed PKEY from the port 0 PKEY table
- * @dd: the infinipath device
- * @index: the PKEY index
- */
-unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index)
-{
- unsigned ret;
-
- if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys))
- ret = 0;
- else
- ret = dd->ipath_pd[0]->port_pkeys[index];
-
- return ret;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_pkey);
-
-/**
- * ipath_layer_get_pkeys - return the PKEY table for port 0
- * @dd: the infinipath device
- * @pkeys: the pkey table is placed here
- */
-int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
-{
- struct ipath_portdata *pd = dd->ipath_pd[0];
-
- memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_pkeys);
-
-/**
- * rm_pkey - decrecment the reference count for the given PKEY
- * @dd: the infinipath device
- * @key: the PKEY index
- *
- * Return true if this was the last reference and the hardware table entry
- * needs to be changed.
- */
-static int rm_pkey(struct ipath_devdata *dd, u16 key)
-{
- int i;
- int ret;
-
- for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
- if (dd->ipath_pkeys[i] != key)
- continue;
- if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
- dd->ipath_pkeys[i] = 0;
- ret = 1;
- goto bail;
- }
- break;
- }
-
- ret = 0;
-
-bail:
- return ret;
-}
-
-/**
- * add_pkey - add the given PKEY to the hardware table
- * @dd: the infinipath device
- * @key: the PKEY
- *
- * Return an error code if unable to add the entry, zero if no change,
- * or 1 if the hardware PKEY register needs to be updated.
- */
-static int add_pkey(struct ipath_devdata *dd, u16 key)
-{
- int i;
- u16 lkey = key & 0x7FFF;
- int any = 0;
- int ret;
-
- if (lkey == 0x7FFF) {
- ret = 0;
- goto bail;
- }
-
- /* Look for an empty slot or a matching PKEY. */
- for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
- if (!dd->ipath_pkeys[i]) {
- any++;
- continue;
- }
- /* If it matches exactly, try to increment the ref count */
- if (dd->ipath_pkeys[i] == key) {
- if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
- ret = 0;
- goto bail;
- }
- /* Lost the race. Look for an empty slot below. */
- atomic_dec(&dd->ipath_pkeyrefs[i]);
- any++;
- }
- /*
- * It makes no sense to have both the limited and unlimited
- * PKEY set at the same time since the unlimited one will
- * disable the limited one.
- */
- if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
- ret = -EEXIST;
- goto bail;
- }
- }
- if (!any) {
- ret = -EBUSY;
- goto bail;
- }
- for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
- if (!dd->ipath_pkeys[i] &&
- atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
- /* for ipathstats, etc. */
- ipath_stats.sps_pkeys[i] = lkey;
- dd->ipath_pkeys[i] = key;
- ret = 1;
- goto bail;
- }
- }
- ret = -EBUSY;
-
-bail:
- return ret;
-}
-
-/**
- * ipath_layer_set_pkeys - set the PKEY table for port 0
- * @dd: the infinipath device
- * @pkeys: the PKEY table
- */
-int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 * pkeys)
-{
- struct ipath_portdata *pd;
- int i;
- int changed = 0;
-
- pd = dd->ipath_pd[0];
-
- for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
- u16 key = pkeys[i];
- u16 okey = pd->port_pkeys[i];
-
- if (key == okey)
- continue;
- /*
- * The value of this PKEY table entry is changing.
- * Remove the old entry in the hardware's array of PKEYs.
- */
- if (okey & 0x7FFF)
- changed |= rm_pkey(dd, okey);
- if (key & 0x7FFF) {
- int ret = add_pkey(dd, key);
-
- if (ret < 0)
- key = 0;
- else
- changed |= ret;
- }
- pd->port_pkeys[i] = key;
- }
- if (changed) {
- u64 pkey;
-
- pkey = (u64) dd->ipath_pkeys[0] |
- ((u64) dd->ipath_pkeys[1] << 16) |
- ((u64) dd->ipath_pkeys[2] << 32) |
- ((u64) dd->ipath_pkeys[3] << 48);
- ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
- (unsigned long long) pkey);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
- pkey);
- }
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_pkeys);
-
-/**
- * ipath_layer_get_linkdowndefaultstate - get the default linkdown state
- * @dd: the infinipath device
- *
- * Returns zero if the default is POLL, 1 if the default is SLEEP.
- */
-int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd)
-{
- return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_linkdowndefaultstate);
-
-/**
- * ipath_layer_set_linkdowndefaultstate - set the default linkdown state
- * @dd: the infinipath device
- * @sleep: the new state
- *
- * Note that this will only take effect when the link state changes.
- */
-int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd,
- int sleep)
-{
- if (sleep)
- dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
- else
- dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
- dd->ipath_ibcctrl);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_linkdowndefaultstate);
-
-int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd)
-{
- return (dd->ipath_ibcctrl >>
- INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
- INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_phyerrthreshold);
-
-/**
- * ipath_layer_set_phyerrthreshold - set the physical error threshold
- * @dd: the infinipath device
- * @n: the new threshold
- *
- * Note that this will only take effect when the link state changes.
- */
-int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
-{
- unsigned v;
-
- v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
- INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
- if (v != n) {
- dd->ipath_ibcctrl &=
- ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
- INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
- dd->ipath_ibcctrl |=
- (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
- dd->ipath_ibcctrl);
- }
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_phyerrthreshold);
-
-int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd)
-{
- return (dd->ipath_ibcctrl >>
- INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
- INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_get_overrunthreshold);
-
-/**
- * ipath_layer_set_overrunthreshold - set the overrun threshold
- * @dd: the infinipath device
- * @n: the new threshold
- *
- * Note that this will only take effect when the link state changes.
- */
-int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
-{
- unsigned v;
-
- v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
- INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
- if (v != n) {
- dd->ipath_ibcctrl &=
- ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
- INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
- dd->ipath_ibcctrl |=
- (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
- dd->ipath_ibcctrl);
- }
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ipath_layer_set_overrunthreshold);
-
-int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name,
- size_t namelen)
-{
- return dd->ipath_f_get_boardname(dd, name, namelen);
-}
-EXPORT_SYMBOL_GPL(ipath_layer_get_boardname);
-
-u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd)
-{
- return dd->ipath_rcvhdrentsize;
-}
-EXPORT_SYMBOL_GPL(ipath_layer_get_rcvhdrentsize);
diff --git a/drivers/infiniband/hw/ipath/ipath_layer.h b/drivers/infiniband/hw/ipath/ipath_layer.h
index 6fefd15bd2d..3854a4eae68 100644
--- a/drivers/infiniband/hw/ipath/ipath_layer.h
+++ b/drivers/infiniband/hw/ipath/ipath_layer.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -39,71 +40,9 @@
*/
struct sk_buff;
-struct ipath_sge_state;
struct ipath_devdata;
struct ether_header;
-struct ipath_layer_counters {
- u64 symbol_error_counter;
- u64 link_error_recovery_counter;
- u64 link_downed_counter;
- u64 port_rcv_errors;
- u64 port_rcv_remphys_errors;
- u64 port_xmit_discards;
- u64 port_xmit_data;
- u64 port_rcv_data;
- u64 port_xmit_packets;
- u64 port_rcv_packets;
-};
-
-/*
- * A segment is a linear region of low physical memory.
- * XXX Maybe we should use phys addr here and kmap()/kunmap().
- * Used by the verbs layer.
- */
-struct ipath_seg {
- void *vaddr;
- size_t length;
-};
-
-/* The number of ipath_segs that fit in a page. */
-#define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg))
-
-struct ipath_segarray {
- struct ipath_seg segs[IPATH_SEGSZ];
-};
-
-struct ipath_mregion {
- u64 user_base; /* User's address for this region */
- u64 iova; /* IB start address of this region */
- size_t length;
- u32 lkey;
- u32 offset; /* offset (bytes) to start of region */
- int access_flags;
- u32 max_segs; /* number of ipath_segs in all the arrays */
- u32 mapsz; /* size of the map array */
- struct ipath_segarray *map[0]; /* the segments */
-};
-
-/*
- * These keep track of the copy progress within a memory region.
- * Used by the verbs layer.
- */
-struct ipath_sge {
- struct ipath_mregion *mr;
- void *vaddr; /* current pointer into the segment */
- u32 sge_length; /* length of the SGE */
- u32 length; /* remaining length of the segment */
- u16 m; /* current index: mr->map[m] */
- u16 n; /* current index: mr->map[m]->segs[n] */
-};
-
-struct ipath_sge_state {
- struct ipath_sge *sg_list; /* next SGE to be used if any */
- struct ipath_sge sge; /* progress state for the current SGE */
- u8 num_sge;
-};
-
int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
void (*l_remove)(void *),
int (*l_intr)(void *, u32),
@@ -111,60 +50,14 @@ int ipath_layer_register(void *(*l_add)(int, struct ipath_devdata *),
struct sk_buff *),
u16 rcv_opcode,
int (*l_rcv_lid)(void *, void *));
-int ipath_verbs_register(void *(*l_add)(int, struct ipath_devdata *),
- void (*l_remove)(void *arg),
- int (*l_piobufavail)(void *arg),
- void (*l_rcv)(void *arg, void *rhdr,
- void *data, u32 tlen),
- void (*l_timer_cb)(void *arg));
void ipath_layer_unregister(void);
-void ipath_verbs_unregister(void);
int ipath_layer_open(struct ipath_devdata *, u32 * pktmax);
u16 ipath_layer_get_lid(struct ipath_devdata *dd);
int ipath_layer_get_mac(struct ipath_devdata *dd, u8 *);
u16 ipath_layer_get_bcast(struct ipath_devdata *dd);
-u32 ipath_layer_get_cr_errpkey(struct ipath_devdata *dd);
-int ipath_layer_set_linkstate(struct ipath_devdata *dd, u8 state);
-int ipath_layer_set_mtu(struct ipath_devdata *, u16);
-int ipath_set_sps_lid(struct ipath_devdata *, u32, u8);
int ipath_layer_send_hdr(struct ipath_devdata *dd,
struct ether_header *hdr);
-int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
- u32 * hdr, u32 len, struct ipath_sge_state *ss);
int ipath_layer_set_piointbufavail_int(struct ipath_devdata *dd);
-int ipath_layer_get_boardname(struct ipath_devdata *dd, char *name,
- size_t namelen);
-int ipath_layer_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
- u64 *rwords, u64 *spkts, u64 *rpkts,
- u64 *xmit_wait);
-int ipath_layer_get_counters(struct ipath_devdata *dd,
- struct ipath_layer_counters *cntrs);
-int ipath_layer_want_buffer(struct ipath_devdata *dd);
-int ipath_layer_set_guid(struct ipath_devdata *, __be64 guid);
-__be64 ipath_layer_get_guid(struct ipath_devdata *);
-u32 ipath_layer_get_nguid(struct ipath_devdata *);
-int ipath_layer_query_device(struct ipath_devdata *, u32 * vendor,
- u32 * boardrev, u32 * majrev, u32 * minrev);
-u32 ipath_layer_get_flags(struct ipath_devdata *dd);
-struct device *ipath_layer_get_device(struct ipath_devdata *dd);
-u16 ipath_layer_get_deviceid(struct ipath_devdata *dd);
-u64 ipath_layer_get_lastibcstat(struct ipath_devdata *dd);
-u32 ipath_layer_get_ibmtu(struct ipath_devdata *dd);
-int ipath_layer_enable_timer(struct ipath_devdata *dd);
-int ipath_layer_disable_timer(struct ipath_devdata *dd);
-int ipath_layer_set_verbs_flags(struct ipath_devdata *dd, unsigned flags);
-unsigned ipath_layer_get_npkeys(struct ipath_devdata *dd);
-unsigned ipath_layer_get_pkey(struct ipath_devdata *dd, unsigned index);
-int ipath_layer_get_pkeys(struct ipath_devdata *dd, u16 *pkeys);
-int ipath_layer_set_pkeys(struct ipath_devdata *dd, u16 *pkeys);
-int ipath_layer_get_linkdowndefaultstate(struct ipath_devdata *dd);
-int ipath_layer_set_linkdowndefaultstate(struct ipath_devdata *dd,
- int sleep);
-int ipath_layer_get_phyerrthreshold(struct ipath_devdata *dd);
-int ipath_layer_set_phyerrthreshold(struct ipath_devdata *dd, unsigned n);
-int ipath_layer_get_overrunthreshold(struct ipath_devdata *dd);
-int ipath_layer_set_overrunthreshold(struct ipath_devdata *dd, unsigned n);
-u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd);
/* ipath_ether interrupt values */
#define IPATH_LAYER_INT_IF_UP 0x2
@@ -173,9 +66,6 @@ u32 ipath_layer_get_rcvhdrentsize(struct ipath_devdata *dd);
#define IPATH_LAYER_INT_SEND_CONTINUE 0x10
#define IPATH_LAYER_INT_BCAST 0x40
-/* _verbs_layer.l_flags */
-#define IPATH_VERBS_KERNEL_SMA 0x1
-
extern unsigned ipath_debug; /* debugging bit mask */
#endif /* _IPATH_LAYER_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index 1a9d0a2c33c..25908b02fbe 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -34,7 +35,7 @@
#include "ipath_kernel.h"
#include "ipath_verbs.h"
-#include "ips_common.h"
+#include "ipath_common.h"
#define IB_SMP_UNSUP_VERSION __constant_htons(0x0004)
#define IB_SMP_UNSUP_METHOD __constant_htons(0x0008)
@@ -84,9 +85,10 @@ static int recv_subn_get_nodeinfo(struct ib_smp *smp,
{
struct nodeinfo *nip = (struct nodeinfo *)&smp->data;
struct ipath_devdata *dd = to_idev(ibdev)->dd;
- u32 vendor, boardid, majrev, minrev;
+ u32 vendor, majrev, minrev;
- if (smp->attr_mod)
+ /* GUID 0 is illegal */
+ if (smp->attr_mod || (dd->ipath_guid == 0))
smp->status |= IB_SMP_INVALID_FIELD;
nip->base_version = 1;
@@ -100,13 +102,15 @@ static int recv_subn_get_nodeinfo(struct ib_smp *smp,
nip->num_ports = ibdev->phys_port_cnt;
/* This is already in network order */
nip->sys_guid = to_idev(ibdev)->sys_image_guid;
- nip->node_guid = ipath_layer_get_guid(dd);
+ nip->node_guid = dd->ipath_guid;
nip->port_guid = nip->sys_guid;
- nip->partition_cap = cpu_to_be16(ipath_layer_get_npkeys(dd));
- nip->device_id = cpu_to_be16(ipath_layer_get_deviceid(dd));
- ipath_layer_query_device(dd, &vendor, &boardid, &majrev, &minrev);
+ nip->partition_cap = cpu_to_be16(ipath_get_npkeys(dd));
+ nip->device_id = cpu_to_be16(dd->ipath_deviceid);
+ majrev = dd->ipath_majrev;
+ minrev = dd->ipath_minrev;
nip->revision = cpu_to_be32((majrev << 16) | minrev);
nip->local_port_num = port;
+ vendor = dd->ipath_vendorid;
nip->vendor_id[0] = 0;
nip->vendor_id[1] = vendor >> 8;
nip->vendor_id[2] = vendor;
@@ -128,15 +132,96 @@ static int recv_subn_get_guidinfo(struct ib_smp *smp,
* We only support one GUID for now. If this changes, the
* portinfo.guid_cap field needs to be updated too.
*/
- if (startgx == 0)
- /* The first is a copy of the read-only HW GUID. */
- *p = ipath_layer_get_guid(to_idev(ibdev)->dd);
- else
+ if (startgx == 0) {
+ __be64 g = to_idev(ibdev)->dd->ipath_guid;
+ if (g == 0)
+ /* GUID 0 is illegal */
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else
+ /* The first is a copy of the read-only HW GUID. */
+ *p = g;
+ } else
smp->status |= IB_SMP_INVALID_FIELD;
return reply(smp);
}
+
+static int get_overrunthreshold(struct ipath_devdata *dd)
+{
+ return (dd->ipath_ibcctrl >>
+ INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
+ INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
+}
+
+/**
+ * set_overrunthreshold - set the overrun threshold
+ * @dd: the infinipath device
+ * @n: the new threshold
+ *
+ * Note that this will only take effect when the link state changes.
+ */
+static int set_overrunthreshold(struct ipath_devdata *dd, unsigned n)
+{
+ unsigned v;
+
+ v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT) &
+ INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK;
+ if (v != n) {
+ dd->ipath_ibcctrl &=
+ ~(INFINIPATH_IBCC_OVERRUNTHRESHOLD_MASK <<
+ INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT);
+ dd->ipath_ibcctrl |=
+ (u64) n << INFINIPATH_IBCC_OVERRUNTHRESHOLD_SHIFT;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+ dd->ipath_ibcctrl);
+ }
+ return 0;
+}
+
+static int get_phyerrthreshold(struct ipath_devdata *dd)
+{
+ return (dd->ipath_ibcctrl >>
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
+}
+
+/**
+ * set_phyerrthreshold - set the physical error threshold
+ * @dd: the infinipath device
+ * @n: the new threshold
+ *
+ * Note that this will only take effect when the link state changes.
+ */
+static int set_phyerrthreshold(struct ipath_devdata *dd, unsigned n)
+{
+ unsigned v;
+
+ v = (dd->ipath_ibcctrl >> INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT) &
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK;
+ if (v != n) {
+ dd->ipath_ibcctrl &=
+ ~(INFINIPATH_IBCC_PHYERRTHRESHOLD_MASK <<
+ INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT);
+ dd->ipath_ibcctrl |=
+ (u64) n << INFINIPATH_IBCC_PHYERRTHRESHOLD_SHIFT;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+ dd->ipath_ibcctrl);
+ }
+ return 0;
+}
+
+/**
+ * get_linkdowndefaultstate - get the default linkdown state
+ * @dd: the infinipath device
+ *
+ * Returns zero if the default is POLL, 1 if the default is SLEEP.
+ */
+static int get_linkdowndefaultstate(struct ipath_devdata *dd)
+{
+ return !!(dd->ipath_ibcctrl & INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE);
+}
+
static int recv_subn_get_portinfo(struct ib_smp *smp,
struct ib_device *ibdev, u8 port)
{
@@ -163,7 +248,7 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
(dev->mkeyprot_resv_lmc >> 6) == 0)
pip->mkey = dev->mkey;
pip->gid_prefix = dev->gid_prefix;
- lid = ipath_layer_get_lid(dev->dd);
+ lid = dev->dd->ipath_lid;
pip->lid = lid ? cpu_to_be16(lid) : IB_LID_PERMISSIVE;
pip->sm_lid = cpu_to_be16(dev->sm_lid);
pip->cap_mask = cpu_to_be32(dev->port_cap_flags);
@@ -174,14 +259,14 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
pip->link_width_supported = 3; /* 1x or 4x */
pip->link_width_active = 2; /* 4x */
pip->linkspeed_portstate = 0x10; /* 2.5Gbps */
- ibcstat = ipath_layer_get_lastibcstat(dev->dd);
+ ibcstat = dev->dd->ipath_lastibcstat;
pip->linkspeed_portstate |= ((ibcstat >> 4) & 0x3) + 1;
pip->portphysstate_linkdown =
(ipath_cvt_physportstate[ibcstat & 0xf] << 4) |
- (ipath_layer_get_linkdowndefaultstate(dev->dd) ? 1 : 2);
+ (get_linkdowndefaultstate(dev->dd) ? 1 : 2);
pip->mkeyprot_resv_lmc = dev->mkeyprot_resv_lmc;
pip->linkspeedactive_enabled = 0x11; /* 2.5Gbps, 2.5Gbps */
- switch (ipath_layer_get_ibmtu(dev->dd)) {
+ switch (dev->dd->ipath_ibmtu) {
case 4096:
mtu = IB_MTU_4096;
break;
@@ -214,8 +299,8 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
pip->mkey_violations = cpu_to_be16(dev->mkey_violations);
/* P_KeyViolations are counted by hardware. */
pip->pkey_violations =
- cpu_to_be16((ipath_layer_get_cr_errpkey(dev->dd) -
- dev->n_pkey_violations) & 0xFFFF);
+ cpu_to_be16((ipath_get_cr_errpkey(dev->dd) -
+ dev->z_pkey_violations) & 0xFFFF);
pip->qkey_violations = cpu_to_be16(dev->qkey_violations);
/* Only the hardware GUID is supported for now */
pip->guid_cap = 1;
@@ -223,8 +308,8 @@ static int recv_subn_get_portinfo(struct ib_smp *smp,
/* 32.768 usec. response time (guessing) */
pip->resv_resptimevalue = 3;
pip->localphyerrors_overrunerrors =
- (ipath_layer_get_phyerrthreshold(dev->dd) << 4) |
- ipath_layer_get_overrunthreshold(dev->dd);
+ (get_phyerrthreshold(dev->dd) << 4) |
+ get_overrunthreshold(dev->dd);
/* pip->max_credit_hint; */
/* pip->link_roundtrip_latency[3]; */
@@ -234,6 +319,20 @@ bail:
return ret;
}
+/**
+ * get_pkeys - return the PKEY table for port 0
+ * @dd: the infinipath device
+ * @pkeys: the pkey table is placed here
+ */
+static int get_pkeys(struct ipath_devdata *dd, u16 * pkeys)
+{
+ struct ipath_portdata *pd = dd->ipath_pd[0];
+
+ memcpy(pkeys, pd->port_pkeys, sizeof(pd->port_pkeys));
+
+ return 0;
+}
+
static int recv_subn_get_pkeytable(struct ib_smp *smp,
struct ib_device *ibdev)
{
@@ -246,9 +345,9 @@ static int recv_subn_get_pkeytable(struct ib_smp *smp,
memset(smp->data, 0, sizeof(smp->data));
if (startpx == 0) {
struct ipath_ibdev *dev = to_idev(ibdev);
- unsigned i, n = ipath_layer_get_npkeys(dev->dd);
+ unsigned i, n = ipath_get_npkeys(dev->dd);
- ipath_layer_get_pkeys(dev->dd, p);
+ get_pkeys(dev->dd, p);
for (i = 0; i < n; i++)
q[i] = cpu_to_be16(p[i]);
@@ -266,6 +365,24 @@ static int recv_subn_set_guidinfo(struct ib_smp *smp,
}
/**
+ * set_linkdowndefaultstate - set the default linkdown state
+ * @dd: the infinipath device
+ * @sleep: the new state
+ *
+ * Note that this will only take effect when the link state changes.
+ */
+static int set_linkdowndefaultstate(struct ipath_devdata *dd, int sleep)
+{
+ if (sleep)
+ dd->ipath_ibcctrl |= INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
+ else
+ dd->ipath_ibcctrl &= ~INFINIPATH_IBCC_LINKDOWNDEFAULTSTATE;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_ibcctrl,
+ dd->ipath_ibcctrl);
+ return 0;
+}
+
+/**
* recv_subn_set_portinfo - set port information
* @smp: the incoming SM packet
* @ibdev: the infiniband device
@@ -287,7 +404,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
u8 state;
u16 lstate;
u32 mtu;
- int ret;
+ int ret, ore;
if (be32_to_cpu(smp->attr_mod) > ibdev->phys_port_cnt)
goto err;
@@ -301,11 +418,11 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
dev->mkey_lease_period = be16_to_cpu(pip->mkey_lease_period);
lid = be16_to_cpu(pip->lid);
- if (lid != ipath_layer_get_lid(dev->dd)) {
+ if (lid != dev->dd->ipath_lid) {
/* Must be a valid unicast LID address. */
- if (lid == 0 || lid >= IPS_MULTICAST_LID_BASE)
+ if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE)
goto err;
- ipath_set_sps_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7);
+ ipath_set_lid(dev->dd, lid, pip->mkeyprot_resv_lmc & 7);
event.event = IB_EVENT_LID_CHANGE;
ib_dispatch_event(&event);
}
@@ -313,7 +430,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
smlid = be16_to_cpu(pip->sm_lid);
if (smlid != dev->sm_lid) {
/* Must be a valid unicast LID address. */
- if (smlid == 0 || smlid >= IPS_MULTICAST_LID_BASE)
+ if (smlid == 0 || smlid >= IPATH_MULTICAST_LID_BASE)
goto err;
dev->sm_lid = smlid;
event.event = IB_EVENT_SM_CHANGE;
@@ -339,11 +456,11 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
case 0: /* NOP */
break;
case 1: /* SLEEP */
- if (ipath_layer_set_linkdowndefaultstate(dev->dd, 1))
+ if (set_linkdowndefaultstate(dev->dd, 1))
goto err;
break;
case 2: /* POLL */
- if (ipath_layer_set_linkdowndefaultstate(dev->dd, 0))
+ if (set_linkdowndefaultstate(dev->dd, 0))
goto err;
break;
default:
@@ -373,7 +490,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
/* XXX We have already partially updated our state! */
goto err;
}
- ipath_layer_set_mtu(dev->dd, mtu);
+ ipath_set_mtu(dev->dd, mtu);
dev->sm_sl = pip->neighbormtu_mastersmsl & 0xF;
@@ -389,20 +506,16 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
* later.
*/
if (pip->pkey_violations == 0)
- dev->n_pkey_violations =
- ipath_layer_get_cr_errpkey(dev->dd);
+ dev->z_pkey_violations = ipath_get_cr_errpkey(dev->dd);
if (pip->qkey_violations == 0)
dev->qkey_violations = 0;
- if (ipath_layer_set_phyerrthreshold(
- dev->dd,
- (pip->localphyerrors_overrunerrors >> 4) & 0xF))
+ ore = pip->localphyerrors_overrunerrors;
+ if (set_phyerrthreshold(dev->dd, (ore >> 4) & 0xF))
goto err;
- if (ipath_layer_set_overrunthreshold(
- dev->dd,
- (pip->localphyerrors_overrunerrors & 0xF)))
+ if (set_overrunthreshold(dev->dd, (ore & 0xF)))
goto err;
dev->subnet_timeout = pip->clientrereg_resv_subnetto & 0x1F;
@@ -420,7 +533,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
* is down or is being set to down.
*/
state = pip->linkspeed_portstate & 0xF;
- flags = ipath_layer_get_flags(dev->dd);
+ flags = dev->dd->ipath_flags;
lstate = (pip->portphysstate_linkdown >> 4) & 0xF;
if (lstate && !(state == IB_PORT_DOWN || state == IB_PORT_NOP))
goto err;
@@ -436,7 +549,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
/* FALLTHROUGH */
case IB_PORT_DOWN:
if (lstate == 0)
- if (ipath_layer_get_linkdowndefaultstate(dev->dd))
+ if (get_linkdowndefaultstate(dev->dd))
lstate = IPATH_IB_LINKDOWN_SLEEP;
else
lstate = IPATH_IB_LINKDOWN;
@@ -448,7 +561,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
lstate = IPATH_IB_LINKDOWN_DISABLE;
else
goto err;
- ipath_layer_set_linkstate(dev->dd, lstate);
+ ipath_set_linkstate(dev->dd, lstate);
if (flags & IPATH_LINKACTIVE) {
event.event = IB_EVENT_PORT_ERR;
ib_dispatch_event(&event);
@@ -457,7 +570,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
case IB_PORT_ARMED:
if (!(flags & (IPATH_LINKINIT | IPATH_LINKACTIVE)))
break;
- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKARM);
+ ipath_set_linkstate(dev->dd, IPATH_IB_LINKARM);
if (flags & IPATH_LINKACTIVE) {
event.event = IB_EVENT_PORT_ERR;
ib_dispatch_event(&event);
@@ -466,7 +579,7 @@ static int recv_subn_set_portinfo(struct ib_smp *smp,
case IB_PORT_ACTIVE:
if (!(flags & IPATH_LINKARMED))
break;
- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
+ ipath_set_linkstate(dev->dd, IPATH_IB_LINKACTIVE);
event.event = IB_EVENT_PORT_ACTIVE;
ib_dispatch_event(&event);
break;
@@ -490,6 +603,152 @@ done:
return ret;
}
+/**
+ * rm_pkey - decrecment the reference count for the given PKEY
+ * @dd: the infinipath device
+ * @key: the PKEY index
+ *
+ * Return true if this was the last reference and the hardware table entry
+ * needs to be changed.
+ */
+static int rm_pkey(struct ipath_devdata *dd, u16 key)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
+ if (dd->ipath_pkeys[i] != key)
+ continue;
+ if (atomic_dec_and_test(&dd->ipath_pkeyrefs[i])) {
+ dd->ipath_pkeys[i] = 0;
+ ret = 1;
+ goto bail;
+ }
+ break;
+ }
+
+ ret = 0;
+
+bail:
+ return ret;
+}
+
+/**
+ * add_pkey - add the given PKEY to the hardware table
+ * @dd: the infinipath device
+ * @key: the PKEY
+ *
+ * Return an error code if unable to add the entry, zero if no change,
+ * or 1 if the hardware PKEY register needs to be updated.
+ */
+static int add_pkey(struct ipath_devdata *dd, u16 key)
+{
+ int i;
+ u16 lkey = key & 0x7FFF;
+ int any = 0;
+ int ret;
+
+ if (lkey == 0x7FFF) {
+ ret = 0;
+ goto bail;
+ }
+
+ /* Look for an empty slot or a matching PKEY. */
+ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
+ if (!dd->ipath_pkeys[i]) {
+ any++;
+ continue;
+ }
+ /* If it matches exactly, try to increment the ref count */
+ if (dd->ipath_pkeys[i] == key) {
+ if (atomic_inc_return(&dd->ipath_pkeyrefs[i]) > 1) {
+ ret = 0;
+ goto bail;
+ }
+ /* Lost the race. Look for an empty slot below. */
+ atomic_dec(&dd->ipath_pkeyrefs[i]);
+ any++;
+ }
+ /*
+ * It makes no sense to have both the limited and unlimited
+ * PKEY set at the same time since the unlimited one will
+ * disable the limited one.
+ */
+ if ((dd->ipath_pkeys[i] & 0x7FFF) == lkey) {
+ ret = -EEXIST;
+ goto bail;
+ }
+ }
+ if (!any) {
+ ret = -EBUSY;
+ goto bail;
+ }
+ for (i = 0; i < ARRAY_SIZE(dd->ipath_pkeys); i++) {
+ if (!dd->ipath_pkeys[i] &&
+ atomic_inc_return(&dd->ipath_pkeyrefs[i]) == 1) {
+ /* for ipathstats, etc. */
+ ipath_stats.sps_pkeys[i] = lkey;
+ dd->ipath_pkeys[i] = key;
+ ret = 1;
+ goto bail;
+ }
+ }
+ ret = -EBUSY;
+
+bail:
+ return ret;
+}
+
+/**
+ * set_pkeys - set the PKEY table for port 0
+ * @dd: the infinipath device
+ * @pkeys: the PKEY table
+ */
+static int set_pkeys(struct ipath_devdata *dd, u16 *pkeys)
+{
+ struct ipath_portdata *pd;
+ int i;
+ int changed = 0;
+
+ pd = dd->ipath_pd[0];
+
+ for (i = 0; i < ARRAY_SIZE(pd->port_pkeys); i++) {
+ u16 key = pkeys[i];
+ u16 okey = pd->port_pkeys[i];
+
+ if (key == okey)
+ continue;
+ /*
+ * The value of this PKEY table entry is changing.
+ * Remove the old entry in the hardware's array of PKEYs.
+ */
+ if (okey & 0x7FFF)
+ changed |= rm_pkey(dd, okey);
+ if (key & 0x7FFF) {
+ int ret = add_pkey(dd, key);
+
+ if (ret < 0)
+ key = 0;
+ else
+ changed |= ret;
+ }
+ pd->port_pkeys[i] = key;
+ }
+ if (changed) {
+ u64 pkey;
+
+ pkey = (u64) dd->ipath_pkeys[0] |
+ ((u64) dd->ipath_pkeys[1] << 16) |
+ ((u64) dd->ipath_pkeys[2] << 32) |
+ ((u64) dd->ipath_pkeys[3] << 48);
+ ipath_cdbg(VERBOSE, "p0 new pkey reg %llx\n",
+ (unsigned long long) pkey);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_partitionkey,
+ pkey);
+ }
+ return 0;
+}
+
static int recv_subn_set_pkeytable(struct ib_smp *smp,
struct ib_device *ibdev)
{
@@ -497,13 +756,12 @@ static int recv_subn_set_pkeytable(struct ib_smp *smp,
__be16 *p = (__be16 *) smp->data;
u16 *q = (u16 *) smp->data;
struct ipath_ibdev *dev = to_idev(ibdev);
- unsigned i, n = ipath_layer_get_npkeys(dev->dd);
+ unsigned i, n = ipath_get_npkeys(dev->dd);
for (i = 0; i < n; i++)
q[i] = be16_to_cpu(p[i]);
- if (startpx != 0 ||
- ipath_layer_set_pkeys(dev->dd, q) != 0)
+ if (startpx != 0 || set_pkeys(dev->dd, q) != 0)
smp->status |= IB_SMP_INVALID_FIELD;
return recv_subn_get_pkeytable(smp, ibdev);
@@ -610,6 +868,9 @@ struct ib_pma_portcounters {
#define IB_PMA_SEL_PORT_RCV_ERRORS __constant_htons(0x0008)
#define IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS __constant_htons(0x0010)
#define IB_PMA_SEL_PORT_XMIT_DISCARDS __constant_htons(0x0040)
+#define IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS __constant_htons(0x0200)
+#define IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS __constant_htons(0x0400)
+#define IB_PMA_SEL_PORT_VL15_DROPPED __constant_htons(0x0800)
#define IB_PMA_SEL_PORT_XMIT_DATA __constant_htons(0x1000)
#define IB_PMA_SEL_PORT_RCV_DATA __constant_htons(0x2000)
#define IB_PMA_SEL_PORT_XMIT_PACKETS __constant_htons(0x4000)
@@ -838,24 +1099,28 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
pmp->data;
struct ipath_ibdev *dev = to_idev(ibdev);
- struct ipath_layer_counters cntrs;
+ struct ipath_verbs_counters cntrs;
u8 port_select = p->port_select;
- ipath_layer_get_counters(dev->dd, &cntrs);
+ ipath_get_counters(dev->dd, &cntrs);
/* Adjust counters for any resets done. */
- cntrs.symbol_error_counter -= dev->n_symbol_error_counter;
+ cntrs.symbol_error_counter -= dev->z_symbol_error_counter;
cntrs.link_error_recovery_counter -=
- dev->n_link_error_recovery_counter;
- cntrs.link_downed_counter -= dev->n_link_downed_counter;
+ dev->z_link_error_recovery_counter;
+ cntrs.link_downed_counter -= dev->z_link_downed_counter;
cntrs.port_rcv_errors += dev->rcv_errors;
- cntrs.port_rcv_errors -= dev->n_port_rcv_errors;
- cntrs.port_rcv_remphys_errors -= dev->n_port_rcv_remphys_errors;
- cntrs.port_xmit_discards -= dev->n_port_xmit_discards;
- cntrs.port_xmit_data -= dev->n_port_xmit_data;
- cntrs.port_rcv_data -= dev->n_port_rcv_data;
- cntrs.port_xmit_packets -= dev->n_port_xmit_packets;
- cntrs.port_rcv_packets -= dev->n_port_rcv_packets;
+ cntrs.port_rcv_errors -= dev->z_port_rcv_errors;
+ cntrs.port_rcv_remphys_errors -= dev->z_port_rcv_remphys_errors;
+ cntrs.port_xmit_discards -= dev->z_port_xmit_discards;
+ cntrs.port_xmit_data -= dev->z_port_xmit_data;
+ cntrs.port_rcv_data -= dev->z_port_rcv_data;
+ cntrs.port_xmit_packets -= dev->z_port_xmit_packets;
+ cntrs.port_rcv_packets -= dev->z_port_rcv_packets;
+ cntrs.local_link_integrity_errors -=
+ dev->z_local_link_integrity_errors;
+ cntrs.excessive_buffer_overrun_errors -=
+ dev->z_excessive_buffer_overrun_errors;
memset(pmp->data, 0, sizeof(pmp->data));
@@ -893,6 +1158,16 @@ static int recv_pma_get_portcounters(struct ib_perf *pmp,
else
p->port_xmit_discards =
cpu_to_be16((u16)cntrs.port_xmit_discards);
+ if (cntrs.local_link_integrity_errors > 0xFUL)
+ cntrs.local_link_integrity_errors = 0xFUL;
+ if (cntrs.excessive_buffer_overrun_errors > 0xFUL)
+ cntrs.excessive_buffer_overrun_errors = 0xFUL;
+ p->lli_ebor_errors = (cntrs.local_link_integrity_errors << 4) |
+ cntrs.excessive_buffer_overrun_errors;
+ if (dev->n_vl15_dropped > 0xFFFFUL)
+ p->vl15_dropped = __constant_cpu_to_be16(0xFFFF);
+ else
+ p->vl15_dropped = cpu_to_be16((u16)dev->n_vl15_dropped);
if (cntrs.port_xmit_data > 0xFFFFFFFFUL)
p->port_xmit_data = __constant_cpu_to_be32(0xFFFFFFFF);
else
@@ -924,14 +1199,14 @@ static int recv_pma_get_portcounters_ext(struct ib_perf *pmp,
u64 swords, rwords, spkts, rpkts, xwait;
u8 port_select = p->port_select;
- ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
- &rpkts, &xwait);
+ ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
+ &rpkts, &xwait);
/* Adjust counters for any resets done. */
- swords -= dev->n_port_xmit_data;
- rwords -= dev->n_port_rcv_data;
- spkts -= dev->n_port_xmit_packets;
- rpkts -= dev->n_port_rcv_packets;
+ swords -= dev->z_port_xmit_data;
+ rwords -= dev->z_port_rcv_data;
+ spkts -= dev->z_port_xmit_packets;
+ rpkts -= dev->z_port_rcv_packets;
memset(pmp->data, 0, sizeof(pmp->data));
@@ -958,46 +1233,57 @@ static int recv_pma_set_portcounters(struct ib_perf *pmp,
struct ib_pma_portcounters *p = (struct ib_pma_portcounters *)
pmp->data;
struct ipath_ibdev *dev = to_idev(ibdev);
- struct ipath_layer_counters cntrs;
+ struct ipath_verbs_counters cntrs;
/*
* Since the HW doesn't support clearing counters, we save the
* current count and subtract it from future responses.
*/
- ipath_layer_get_counters(dev->dd, &cntrs);
+ ipath_get_counters(dev->dd, &cntrs);
if (p->counter_select & IB_PMA_SEL_SYMBOL_ERROR)
- dev->n_symbol_error_counter = cntrs.symbol_error_counter;
+ dev->z_symbol_error_counter = cntrs.symbol_error_counter;
if (p->counter_select & IB_PMA_SEL_LINK_ERROR_RECOVERY)
- dev->n_link_error_recovery_counter =
+ dev->z_link_error_recovery_counter =
cntrs.link_error_recovery_counter;
if (p->counter_select & IB_PMA_SEL_LINK_DOWNED)
- dev->n_link_downed_counter = cntrs.link_downed_counter;
+ dev->z_link_downed_counter = cntrs.link_downed_counter;
if (p->counter_select & IB_PMA_SEL_PORT_RCV_ERRORS)
- dev->n_port_rcv_errors =
+ dev->z_port_rcv_errors =
cntrs.port_rcv_errors + dev->rcv_errors;
if (p->counter_select & IB_PMA_SEL_PORT_RCV_REMPHYS_ERRORS)
- dev->n_port_rcv_remphys_errors =
+ dev->z_port_rcv_remphys_errors =
cntrs.port_rcv_remphys_errors;
if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DISCARDS)
- dev->n_port_xmit_discards = cntrs.port_xmit_discards;
+ dev->z_port_xmit_discards = cntrs.port_xmit_discards;
+
+ if (p->counter_select & IB_PMA_SEL_LOCAL_LINK_INTEGRITY_ERRORS)
+ dev->z_local_link_integrity_errors =
+ cntrs.local_link_integrity_errors;
+
+ if (p->counter_select & IB_PMA_SEL_EXCESSIVE_BUFFER_OVERRUNS)
+ dev->z_excessive_buffer_overrun_errors =
+ cntrs.excessive_buffer_overrun_errors;
+
+ if (p->counter_select & IB_PMA_SEL_PORT_VL15_DROPPED)
+ dev->n_vl15_dropped = 0;
if (p->counter_select & IB_PMA_SEL_PORT_XMIT_DATA)
- dev->n_port_xmit_data = cntrs.port_xmit_data;
+ dev->z_port_xmit_data = cntrs.port_xmit_data;
if (p->counter_select & IB_PMA_SEL_PORT_RCV_DATA)
- dev->n_port_rcv_data = cntrs.port_rcv_data;
+ dev->z_port_rcv_data = cntrs.port_rcv_data;
if (p->counter_select & IB_PMA_SEL_PORT_XMIT_PACKETS)
- dev->n_port_xmit_packets = cntrs.port_xmit_packets;
+ dev->z_port_xmit_packets = cntrs.port_xmit_packets;
if (p->counter_select & IB_PMA_SEL_PORT_RCV_PACKETS)
- dev->n_port_rcv_packets = cntrs.port_rcv_packets;
+ dev->z_port_rcv_packets = cntrs.port_rcv_packets;
return recv_pma_get_portcounters(pmp, ibdev, port);
}
@@ -1010,20 +1296,20 @@ static int recv_pma_set_portcounters_ext(struct ib_perf *pmp,
struct ipath_ibdev *dev = to_idev(ibdev);
u64 swords, rwords, spkts, rpkts, xwait;
- ipath_layer_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
- &rpkts, &xwait);
+ ipath_snapshot_counters(dev->dd, &swords, &rwords, &spkts,
+ &rpkts, &xwait);
if (p->counter_select & IB_PMA_SELX_PORT_XMIT_DATA)
- dev->n_port_xmit_data = swords;
+ dev->z_port_xmit_data = swords;
if (p->counter_select & IB_PMA_SELX_PORT_RCV_DATA)
- dev->n_port_rcv_data = rwords;
+ dev->z_port_rcv_data = rwords;
if (p->counter_select & IB_PMA_SELX_PORT_XMIT_PACKETS)
- dev->n_port_xmit_packets = spkts;
+ dev->z_port_xmit_packets = spkts;
if (p->counter_select & IB_PMA_SELX_PORT_RCV_PACKETS)
- dev->n_port_rcv_packets = rpkts;
+ dev->z_port_rcv_packets = rpkts;
if (p->counter_select & IB_PMA_SELX_PORT_UNI_XMIT_PACKETS)
dev->n_unicast_xmit = 0;
@@ -1272,32 +1558,8 @@ int ipath_process_mad(struct ib_device *ibdev, int mad_flags, u8 port_num,
struct ib_wc *in_wc, struct ib_grh *in_grh,
struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- struct ipath_ibdev *dev = to_idev(ibdev);
int ret;
- /*
- * Snapshot current HW counters to "clear" them.
- * This should be done when the driver is loaded except that for
- * some reason we get a zillion errors when brining up the link.
- */
- if (dev->rcv_errors == 0) {
- struct ipath_layer_counters cntrs;
-
- ipath_layer_get_counters(to_idev(ibdev)->dd, &cntrs);
- dev->rcv_errors++;
- dev->n_symbol_error_counter = cntrs.symbol_error_counter;
- dev->n_link_error_recovery_counter =
- cntrs.link_error_recovery_counter;
- dev->n_link_downed_counter = cntrs.link_downed_counter;
- dev->n_port_rcv_errors = cntrs.port_rcv_errors + 1;
- dev->n_port_rcv_remphys_errors =
- cntrs.port_rcv_remphys_errors;
- dev->n_port_xmit_discards = cntrs.port_xmit_discards;
- dev->n_port_xmit_data = cntrs.port_xmit_data;
- dev->n_port_rcv_data = cntrs.port_rcv_data;
- dev->n_port_xmit_packets = cntrs.port_xmit_packets;
- dev->n_port_rcv_packets = cntrs.port_rcv_packets;
- }
switch (in_mad->mad_hdr.mgmt_class) {
case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE:
case IB_MGMT_CLASS_SUBN_LID_ROUTED:
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
new file mode 100644
index 00000000000..11b7378ff21
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <asm/pgtable.h>
+
+#include "ipath_verbs.h"
+
+/**
+ * ipath_release_mmap_info - free mmap info structure
+ * @ref: a pointer to the kref within struct ipath_mmap_info
+ */
+void ipath_release_mmap_info(struct kref *ref)
+{
+ struct ipath_mmap_info *ip =
+ container_of(ref, struct ipath_mmap_info, ref);
+
+ vfree(ip->obj);
+ kfree(ip);
+}
+
+/*
+ * open and close keep track of how many times the CQ is mapped,
+ * to avoid releasing it.
+ */
+static void ipath_vma_open(struct vm_area_struct *vma)
+{
+ struct ipath_mmap_info *ip = vma->vm_private_data;
+
+ kref_get(&ip->ref);
+ ip->mmap_cnt++;
+}
+
+static void ipath_vma_close(struct vm_area_struct *vma)
+{
+ struct ipath_mmap_info *ip = vma->vm_private_data;
+
+ ip->mmap_cnt--;
+ kref_put(&ip->ref, ipath_release_mmap_info);
+}
+
+static struct vm_operations_struct ipath_vm_ops = {
+ .open = ipath_vma_open,
+ .close = ipath_vma_close,
+};
+
+/**
+ * ipath_mmap - create a new mmap region
+ * @context: the IB user context of the process making the mmap() call
+ * @vma: the VMA to be initialized
+ * Return zero if the mmap is OK. Otherwise, return an errno.
+ */
+int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
+{
+ struct ipath_ibdev *dev = to_idev(context->device);
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long size = vma->vm_end - vma->vm_start;
+ struct ipath_mmap_info *ip, **pp;
+ int ret = -EINVAL;
+
+ /*
+ * Search the device's list of objects waiting for a mmap call.
+ * Normally, this list is very short since a call to create a
+ * CQ, QP, or SRQ is soon followed by a call to mmap().
+ */
+ spin_lock_irq(&dev->pending_lock);
+ for (pp = &dev->pending_mmaps; (ip = *pp); pp = &ip->next) {
+ /* Only the creator is allowed to mmap the object */
+ if (context != ip->context || (void *) offset != ip->obj)
+ continue;
+ /* Don't allow a mmap larger than the object. */
+ if (size > ip->size)
+ break;
+
+ *pp = ip->next;
+ spin_unlock_irq(&dev->pending_lock);
+
+ ret = remap_vmalloc_range(vma, ip->obj, 0);
+ if (ret)
+ goto done;
+ vma->vm_ops = &ipath_vm_ops;
+ vma->vm_private_data = ip;
+ ipath_vma_open(vma);
+ goto done;
+ }
+ spin_unlock_irq(&dev->pending_lock);
+done:
+ return ret;
+}
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index 69ffec66d45..a0673c1eef7 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -35,6 +36,18 @@
#include "ipath_verbs.h"
+/* Fast memory region */
+struct ipath_fmr {
+ struct ib_fmr ibfmr;
+ u8 page_shift;
+ struct ipath_mregion mr; /* must be last */
+};
+
+static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr)
+{
+ return container_of(ibfmr, struct ipath_fmr, ibfmr);
+}
+
/**
* ipath_get_dma_mr - get a DMA memory region
* @pd: protection domain for this memory region
@@ -125,6 +138,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
goto bail;
}
+ mr->mr.pd = pd;
mr->mr.user_base = *iova_start;
mr->mr.iova = *iova_start;
mr->mr.length = 0;
@@ -169,6 +183,11 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
int n, m, i;
struct ib_mr *ret;
+ if (region->length == 0) {
+ ret = ERR_PTR(-EINVAL);
+ goto bail;
+ }
+
n = 0;
list_for_each_entry(chunk, &region->chunk_list, list)
n += chunk->nents;
@@ -179,6 +198,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
goto bail;
}
+ mr->mr.pd = pd;
mr->mr.user_base = region->user_base;
mr->mr.iova = region->virt_base;
mr->mr.length = region->length;
@@ -271,6 +291,7 @@ struct ib_fmr *ipath_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
* Resources are allocated but no valid mapping (RKEY can't be
* used).
*/
+ fmr->mr.pd = pd;
fmr->mr.user_base = 0;
fmr->mr.iova = 0;
fmr->mr.length = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 9f8855d970c..46c1c89bf6a 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -34,7 +35,7 @@
#include <linux/vmalloc.h>
#include "ipath_verbs.h"
-#include "ips_common.h"
+#include "ipath_kernel.h"
#define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE)
#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
@@ -43,19 +44,6 @@
#define find_next_offset(map, off) find_next_zero_bit((map)->page, \
BITS_PER_PAGE, off)
-#define TRANS_INVALID 0
-#define TRANS_ANY2RST 1
-#define TRANS_RST2INIT 2
-#define TRANS_INIT2INIT 3
-#define TRANS_INIT2RTR 4
-#define TRANS_RTR2RTS 5
-#define TRANS_RTS2RTS 6
-#define TRANS_SQERR2RTS 7
-#define TRANS_ANY2ERR 8
-#define TRANS_RTS2SQD 9 /* XXX Wait for expected ACKs & signal event */
-#define TRANS_SQD2SQD 10 /* error if not drained & parameter change */
-#define TRANS_SQD2RTS 11 /* error if not drained */
-
/*
* Convert the AETH credit code into the number of credits.
*/
@@ -286,7 +274,7 @@ void ipath_free_all_qps(struct ipath_qp_table *qpt)
free_qpn(qpt, qp->ibqp.qp_num);
if (!atomic_dec_and_test(&qp->refcount) ||
!ipath_destroy_qp(&qp->ibqp))
- _VERBS_INFO("QP memory leak!\n");
+ ipath_dbg(KERN_INFO "QP memory leak!\n");
qp = nqp;
}
}
@@ -332,10 +320,11 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->remote_qpn = 0;
qp->qkey = 0;
qp->qp_access_flags = 0;
+ clear_bit(IPATH_S_BUSY, &qp->s_flags);
qp->s_hdrwords = 0;
qp->s_psn = 0;
qp->r_psn = 0;
- atomic_set(&qp->msn, 0);
+ qp->r_msn = 0;
if (qp->ibqp.qp_type == IB_QPT_RC) {
qp->s_state = IB_OPCODE_RC_SEND_LAST;
qp->r_state = IB_OPCODE_RC_SEND_LAST;
@@ -344,7 +333,9 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->r_state = IB_OPCODE_UC_SEND_LAST;
}
qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
- qp->s_nak_state = 0;
+ qp->r_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
+ qp->r_nak_state = 0;
+ qp->r_wrid_valid = 0;
qp->s_rnr_timeout = 0;
qp->s_head = 0;
qp->s_tail = 0;
@@ -352,26 +343,30 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->s_last = 0;
qp->s_ssn = 1;
qp->s_lsn = 0;
- qp->r_rq.head = 0;
- qp->r_rq.tail = 0;
+ qp->s_wait_credit = 0;
+ if (qp->r_rq.wq) {
+ qp->r_rq.wq->head = 0;
+ qp->r_rq.wq->tail = 0;
+ }
qp->r_reuse_sge = 0;
}
/**
* ipath_error_qp - put a QP into an error state
* @qp: the QP to put into an error state
+ * @err: the receive completion error to signal if a RWQE is active
*
* Flushes both send and receive work queues.
- * QP r_rq.lock and s_lock should be held.
+ * QP s_lock should be held and interrupts disabled.
*/
-static void ipath_error_qp(struct ipath_qp *qp)
+void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
- _VERBS_INFO("QP%d/%d in error state\n",
- qp->ibqp.qp_num, qp->remote_qpn);
+ ipath_dbg(KERN_INFO "QP%d/%d in error state\n",
+ qp->ibqp.qp_num, qp->remote_qpn);
spin_lock(&dev->pending_lock);
/* XXX What if its already removed by the timeout code? */
@@ -381,7 +376,6 @@ static void ipath_error_qp(struct ipath_qp *qp)
list_del_init(&qp->piowait);
spin_unlock(&dev->pending_lock);
- wc.status = IB_WC_WR_FLUSH_ERR;
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
@@ -393,6 +387,12 @@ static void ipath_error_qp(struct ipath_qp *qp)
wc.sl = 0;
wc.dlid_path_bits = 0;
wc.port_num = 0;
+ if (qp->r_wrid_valid) {
+ qp->r_wrid_valid = 0;
+ wc.status = err;
+ ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
+ }
+ wc.status = IB_WC_WR_FLUSH_ERR;
while (qp->s_last != qp->s_head) {
struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
@@ -407,12 +407,31 @@ static void ipath_error_qp(struct ipath_qp *qp)
qp->s_hdrwords = 0;
qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
- wc.opcode = IB_WC_RECV;
- while (qp->r_rq.tail != qp->r_rq.head) {
- wc.wr_id = get_rwqe_ptr(&qp->r_rq, qp->r_rq.tail)->wr_id;
- if (++qp->r_rq.tail >= qp->r_rq.size)
- qp->r_rq.tail = 0;
- ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+ if (qp->r_rq.wq) {
+ struct ipath_rwq *wq;
+ u32 head;
+ u32 tail;
+
+ spin_lock(&qp->r_rq.lock);
+
+ /* sanity check pointers before trusting them */
+ wq = qp->r_rq.wq;
+ head = wq->head;
+ if (head >= qp->r_rq.size)
+ head = 0;
+ tail = wq->tail;
+ if (tail >= qp->r_rq.size)
+ tail = 0;
+ wc.opcode = IB_WC_RECV;
+ while (tail != head) {
+ wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id;
+ if (++tail >= qp->r_rq.size)
+ tail = 0;
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+ }
+ wq->tail = tail;
+
+ spin_unlock(&qp->r_rq.lock);
}
}
@@ -421,11 +440,12 @@ static void ipath_error_qp(struct ipath_qp *qp)
* @ibqp: the queue pair who's attributes we're modifying
* @attr: the new attributes
* @attr_mask: the mask of attributes to modify
+ * @udata: user data for ipathverbs.so
*
* Returns 0 on success, otherwise returns an errno.
*/
int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
- int attr_mask)
+ int attr_mask, struct ib_udata *udata)
{
struct ipath_ibdev *dev = to_idev(ibqp->device);
struct ipath_qp *qp = to_iqp(ibqp);
@@ -433,8 +453,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
unsigned long flags;
int ret;
- spin_lock_irqsave(&qp->r_rq.lock, flags);
- spin_lock(&qp->s_lock);
+ spin_lock_irqsave(&qp->s_lock, flags);
cur_state = attr_mask & IB_QP_CUR_STATE ?
attr->cur_qp_state : qp->state;
@@ -444,26 +463,53 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
attr_mask))
goto inval;
- if (attr_mask & IB_QP_AV)
+ if (attr_mask & IB_QP_AV) {
if (attr->ah_attr.dlid == 0 ||
- attr->ah_attr.dlid >= IPS_MULTICAST_LID_BASE)
+ attr->ah_attr.dlid >= IPATH_MULTICAST_LID_BASE)
+ goto inval;
+
+ if ((attr->ah_attr.ah_flags & IB_AH_GRH) &&
+ (attr->ah_attr.grh.sgid_index > 1))
goto inval;
+ }
if (attr_mask & IB_QP_PKEY_INDEX)
- if (attr->pkey_index >= ipath_layer_get_npkeys(dev->dd))
+ if (attr->pkey_index >= ipath_get_npkeys(dev->dd))
goto inval;
if (attr_mask & IB_QP_MIN_RNR_TIMER)
if (attr->min_rnr_timer > 31)
goto inval;
+ if (attr_mask & IB_QP_PORT)
+ if (attr->port_num == 0 ||
+ attr->port_num > ibqp->device->phys_port_cnt)
+ goto inval;
+
+ if (attr_mask & IB_QP_PATH_MTU)
+ if (attr->path_mtu > IB_MTU_4096)
+ goto inval;
+
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC)
+ if (attr->max_dest_rd_atomic > 1)
+ goto inval;
+
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC)
+ if (attr->max_rd_atomic > 1)
+ goto inval;
+
+ if (attr_mask & IB_QP_PATH_MIG_STATE)
+ if (attr->path_mig_state != IB_MIG_MIGRATED &&
+ attr->path_mig_state != IB_MIG_REARM)
+ goto inval;
+
switch (new_state) {
case IB_QPS_RESET:
ipath_reset_qp(qp);
break;
case IB_QPS_ERR:
- ipath_error_qp(qp);
+ ipath_error_qp(qp, IB_WC_GENERAL_ERR);
break;
default:
@@ -478,7 +524,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->remote_qpn = attr->dest_qp_num;
if (attr_mask & IB_QP_SQ_PSN) {
- qp->s_next_psn = attr->sq_psn;
+ qp->s_psn = qp->s_next_psn = attr->sq_psn;
qp->s_last_psn = qp->s_next_psn - 1;
}
@@ -505,34 +551,22 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
}
if (attr_mask & IB_QP_MIN_RNR_TIMER)
- qp->s_min_rnr_timer = attr->min_rnr_timer;
+ qp->r_min_rnr_timer = attr->min_rnr_timer;
+
+ if (attr_mask & IB_QP_TIMEOUT)
+ qp->timeout = attr->timeout;
if (attr_mask & IB_QP_QKEY)
qp->qkey = attr->qkey;
- if (attr_mask & IB_QP_PKEY_INDEX)
- qp->s_pkey_index = attr->pkey_index;
-
qp->state = new_state;
- spin_unlock(&qp->s_lock);
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
-
- /*
- * If QP1 changed to the RTS state, try to move to the link to INIT
- * even if it was ACTIVE so the SM will reinitialize the SMA's
- * state.
- */
- if (qp->ibqp.qp_num == 1 && new_state == IB_QPS_RTS) {
- struct ipath_ibdev *dev = to_idev(ibqp->device);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN);
- }
ret = 0;
goto bail;
inval:
- spin_unlock(&qp->s_lock);
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
ret = -EINVAL;
bail:
@@ -554,7 +588,7 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
attr->dest_qp_num = qp->remote_qpn;
attr->qp_access_flags = qp->qp_access_flags;
attr->cap.max_send_wr = qp->s_size - 1;
- attr->cap.max_recv_wr = qp->r_rq.size - 1;
+ attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1;
attr->cap.max_send_sge = qp->s_max_sge;
attr->cap.max_recv_sge = qp->r_rq.max_sge;
attr->cap.max_inline_data = 0;
@@ -566,9 +600,9 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
attr->sq_draining = 0;
attr->max_rd_atomic = 1;
attr->max_dest_rd_atomic = 1;
- attr->min_rnr_timer = qp->s_min_rnr_timer;
+ attr->min_rnr_timer = qp->r_min_rnr_timer;
attr->port_num = 1;
- attr->timeout = 0;
+ attr->timeout = qp->timeout;
attr->retry_cnt = qp->s_retry_cnt;
attr->rnr_retry = qp->s_rnr_retry;
attr->alt_port_num = 0;
@@ -580,9 +614,10 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
init_attr->recv_cq = qp->ibqp.recv_cq;
init_attr->srq = qp->ibqp.srq;
init_attr->cap = attr->cap;
- init_attr->sq_sig_type =
- (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR))
- ? IB_SIGNAL_REQ_WR : 0;
+ if (qp->s_flags & (1 << IPATH_S_SIGNAL_REQ_WR))
+ init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
+ else
+ init_attr->sq_sig_type = IB_SIGNAL_ALL_WR;
init_attr->qp_type = qp->ibqp.qp_type;
init_attr->port_num = 1;
return 0;
@@ -593,31 +628,37 @@ int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
* @qp: the queue pair to compute the AETH for
*
* Returns the AETH.
- *
- * The QP s_lock should be held.
*/
__be32 ipath_compute_aeth(struct ipath_qp *qp)
{
- u32 aeth = atomic_read(&qp->msn) & IPS_MSN_MASK;
+ u32 aeth = qp->r_msn & IPATH_MSN_MASK;
- if (qp->s_nak_state) {
- aeth |= qp->s_nak_state << IPS_AETH_CREDIT_SHIFT;
- } else if (qp->ibqp.srq) {
+ if (qp->ibqp.srq) {
/*
* Shared receive queues don't generate credits.
* Set the credit field to the invalid value.
*/
- aeth |= IPS_AETH_CREDIT_INVAL << IPS_AETH_CREDIT_SHIFT;
+ aeth |= IPATH_AETH_CREDIT_INVAL << IPATH_AETH_CREDIT_SHIFT;
} else {
u32 min, max, x;
u32 credits;
-
+ struct ipath_rwq *wq = qp->r_rq.wq;
+ u32 head;
+ u32 tail;
+
+ /* sanity check pointers before trusting them */
+ head = wq->head;
+ if (head >= qp->r_rq.size)
+ head = 0;
+ tail = wq->tail;
+ if (tail >= qp->r_rq.size)
+ tail = 0;
/*
* Compute the number of credits available (RWQEs).
* XXX Not holding the r_rq.lock here so there is a small
* chance that the pair of reads are not atomic.
*/
- credits = qp->r_rq.head - qp->r_rq.tail;
+ credits = head - tail;
if ((int)credits < 0)
credits += qp->r_rq.size;
/*
@@ -637,7 +678,7 @@ __be32 ipath_compute_aeth(struct ipath_qp *qp)
else
min = x;
}
- aeth |= x << IPS_AETH_CREDIT_SHIFT;
+ aeth |= x << IPATH_AETH_CREDIT_SHIFT;
}
return cpu_to_be32(aeth);
}
@@ -663,12 +704,22 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
size_t sz;
struct ib_qp *ret;
- if (init_attr->cap.max_send_sge > 255 ||
- init_attr->cap.max_recv_sge > 255) {
+ if (init_attr->cap.max_send_sge > ib_ipath_max_sges ||
+ init_attr->cap.max_recv_sge > ib_ipath_max_sges ||
+ init_attr->cap.max_send_wr > ib_ipath_max_qp_wrs ||
+ init_attr->cap.max_recv_wr > ib_ipath_max_qp_wrs) {
ret = ERR_PTR(-ENOMEM);
goto bail;
}
+ if (init_attr->cap.max_send_sge +
+ init_attr->cap.max_recv_sge +
+ init_attr->cap.max_send_wr +
+ init_attr->cap.max_recv_wr == 0) {
+ ret = ERR_PTR(-EINVAL);
+ goto bail;
+ }
+
switch (init_attr->qp_type) {
case IB_QPT_UC:
case IB_QPT_RC:
@@ -684,20 +735,38 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
case IB_QPT_UD:
case IB_QPT_SMI:
case IB_QPT_GSI:
- qp = kmalloc(sizeof(*qp), GFP_KERNEL);
+ sz = sizeof(*qp);
+ if (init_attr->srq) {
+ struct ipath_srq *srq = to_isrq(init_attr->srq);
+
+ sz += sizeof(*qp->r_sg_list) *
+ srq->rq.max_sge;
+ } else
+ sz += sizeof(*qp->r_sg_list) *
+ init_attr->cap.max_recv_sge;
+ qp = kmalloc(sz, GFP_KERNEL);
if (!qp) {
ret = ERR_PTR(-ENOMEM);
- goto bail;
+ goto bail_swq;
}
- qp->r_rq.size = init_attr->cap.max_recv_wr + 1;
- sz = sizeof(struct ipath_sge) *
- init_attr->cap.max_recv_sge +
- sizeof(struct ipath_rwqe);
- qp->r_rq.wq = vmalloc(qp->r_rq.size * sz);
- if (!qp->r_rq.wq) {
- kfree(qp);
- ret = ERR_PTR(-ENOMEM);
- goto bail;
+ if (init_attr->srq) {
+ sz = 0;
+ qp->r_rq.size = 0;
+ qp->r_rq.max_sge = 0;
+ qp->r_rq.wq = NULL;
+ init_attr->cap.max_recv_wr = 0;
+ init_attr->cap.max_recv_sge = 0;
+ } else {
+ qp->r_rq.size = init_attr->cap.max_recv_wr + 1;
+ qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
+ sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) +
+ sizeof(struct ipath_rwqe);
+ qp->r_rq.wq = vmalloc_user(sizeof(struct ipath_rwq) +
+ qp->r_rq.size * sz);
+ if (!qp->r_rq.wq) {
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_qp;
+ }
}
/*
@@ -708,9 +777,7 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
spin_lock_init(&qp->r_rq.lock);
atomic_set(&qp->refcount, 0);
init_waitqueue_head(&qp->wait);
- tasklet_init(&qp->s_task,
- init_attr->qp_type == IB_QPT_RC ?
- ipath_do_rc_send : ipath_do_uc_send,
+ tasklet_init(&qp->s_task, ipath_do_ruc_send,
(unsigned long)qp);
INIT_LIST_HEAD(&qp->piowait);
INIT_LIST_HEAD(&qp->timerwait);
@@ -718,25 +785,19 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
qp->s_wq = swq;
qp->s_size = init_attr->cap.max_send_wr + 1;
qp->s_max_sge = init_attr->cap.max_send_sge;
- qp->r_rq.max_sge = init_attr->cap.max_recv_sge;
- qp->s_flags = init_attr->sq_sig_type == IB_SIGNAL_REQ_WR ?
- 1 << IPATH_S_SIGNAL_REQ_WR : 0;
+ if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR)
+ qp->s_flags = 1 << IPATH_S_SIGNAL_REQ_WR;
+ else
+ qp->s_flags = 0;
dev = to_idev(ibpd->device);
err = ipath_alloc_qpn(&dev->qp_table, qp,
init_attr->qp_type);
if (err) {
- vfree(swq);
- vfree(qp->r_rq.wq);
- kfree(qp);
ret = ERR_PTR(err);
- goto bail;
+ goto bail_rwq;
}
+ qp->ip = NULL;
ipath_reset_qp(qp);
-
- /* Tell the core driver that the kernel SMA is present. */
- if (init_attr->qp_type == IB_QPT_SMI)
- ipath_layer_set_verbs_flags(dev->dd,
- IPATH_VERBS_KERNEL_SMA);
break;
default:
@@ -747,8 +808,63 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
init_attr->cap.max_inline_data = 0;
+ /*
+ * Return the address of the RWQ as the offset to mmap.
+ * See ipath_mmap() for details.
+ */
+ if (udata && udata->outlen >= sizeof(__u64)) {
+ struct ipath_mmap_info *ip;
+ __u64 offset = (__u64) qp->r_rq.wq;
+ int err;
+
+ err = ib_copy_to_udata(udata, &offset, sizeof(offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_rwq;
+ }
+
+ if (qp->r_rq.wq) {
+ /* Allocate info for ipath_mmap(). */
+ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
+ if (!ip) {
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_rwq;
+ }
+ qp->ip = ip;
+ ip->context = ibpd->uobject->context;
+ ip->obj = qp->r_rq.wq;
+ kref_init(&ip->ref);
+ ip->mmap_cnt = 0;
+ ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
+ qp->r_rq.size * sz);
+ spin_lock_irq(&dev->pending_lock);
+ ip->next = dev->pending_mmaps;
+ dev->pending_mmaps = ip;
+ spin_unlock_irq(&dev->pending_lock);
+ }
+ }
+
+ spin_lock(&dev->n_qps_lock);
+ if (dev->n_qps_allocated == ib_ipath_max_qps) {
+ spin_unlock(&dev->n_qps_lock);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_ip;
+ }
+
+ dev->n_qps_allocated++;
+ spin_unlock(&dev->n_qps_lock);
+
ret = &qp->ibqp;
+ goto bail;
+bail_ip:
+ kfree(qp->ip);
+bail_rwq:
+ vfree(qp->r_rq.wq);
+bail_qp:
+ kfree(qp);
+bail_swq:
+ vfree(swq);
bail:
return ret;
}
@@ -768,15 +884,12 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
struct ipath_ibdev *dev = to_idev(ibqp->device);
unsigned long flags;
- /* Tell the core driver that the kernel SMA is gone. */
- if (qp->ibqp.qp_type == IB_QPT_SMI)
- ipath_layer_set_verbs_flags(dev->dd, 0);
-
- spin_lock_irqsave(&qp->r_rq.lock, flags);
- spin_lock(&qp->s_lock);
+ spin_lock_irqsave(&qp->s_lock, flags);
qp->state = IB_QPS_ERR;
- spin_unlock(&qp->s_lock);
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ spin_lock(&dev->n_qps_lock);
+ dev->n_qps_allocated--;
+ spin_unlock(&dev->n_qps_lock);
/* Stop the sending tasklet. */
tasklet_kill(&qp->s_task);
@@ -797,8 +910,11 @@ int ipath_destroy_qp(struct ib_qp *ibqp)
if (atomic_read(&qp->refcount) != 0)
ipath_free_qp(&dev->qp_table, qp);
+ if (qp->ip)
+ kref_put(&qp->ip->ref, ipath_release_mmap_info);
+ else
+ vfree(qp->r_rq.wq);
vfree(qp->s_wq);
- vfree(qp->r_rq.wq);
kfree(qp);
return 0;
}
@@ -850,8 +966,8 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
- _VERBS_INFO("Send queue error on QP%d/%d: err: %d\n",
- qp->ibqp.qp_num, qp->remote_qpn, wc->status);
+ ipath_dbg(KERN_INFO "Send queue error on QP%d/%d: err: %d\n",
+ qp->ibqp.qp_num, qp->remote_qpn, wc->status);
spin_lock(&dev->pending_lock);
/* XXX What if its already removed by the timeout code? */
@@ -888,18 +1004,18 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc)
*/
void ipath_get_credit(struct ipath_qp *qp, u32 aeth)
{
- u32 credit = (aeth >> IPS_AETH_CREDIT_SHIFT) & IPS_AETH_CREDIT_MASK;
+ u32 credit = (aeth >> IPATH_AETH_CREDIT_SHIFT) & IPATH_AETH_CREDIT_MASK;
/*
* If the credit is invalid, we can send
* as many packets as we like. Otherwise, we have to
* honor the credit field.
*/
- if (credit == IPS_AETH_CREDIT_INVAL) {
+ if (credit == IPATH_AETH_CREDIT_INVAL)
qp->s_lsn = (u32) -1;
- } else if (qp->s_lsn != (u32) -1) {
+ else if (qp->s_lsn != (u32) -1) {
/* Compute new LSN (i.e., MSN + credit) */
- credit = (aeth + credit_table[credit]) & IPS_MSN_MASK;
+ credit = (aeth + credit_table[credit]) & IPATH_MSN_MASK;
if (ipath_cmp24(credit, qp->s_lsn) > 0)
qp->s_lsn = credit;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index 493b1821a93..a504cf67f27 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -31,7 +32,7 @@
*/
#include "ipath_verbs.h"
-#include "ips_common.h"
+#include "ipath_kernel.h"
/* cut down ridiculously long IB macro names */
#define OP(x) IB_OPCODE_RC_##x
@@ -41,14 +42,14 @@
* @qp: the QP who's SGE we're restarting
* @wqe: the work queue to initialize the QP's SGE from
*
- * The QP s_lock should be held.
+ * The QP s_lock should be held and interrupts disabled.
*/
static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
{
struct ipath_ibdev *dev;
u32 len;
- len = ((qp->s_psn - wqe->psn) & IPS_PSN_MASK) *
+ len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) *
ib_mtu_enum_to_int(qp->path_mtu);
qp->s_sge.sge = wqe->sg_list[0];
qp->s_sge.sg_list = wqe->sg_list + 1;
@@ -72,11 +73,10 @@ static void ipath_init_restart(struct ipath_qp *qp, struct ipath_swqe *wqe)
* Return bth0 if constructed; otherwise, return 0.
* Note the QP s_lock must be held.
*/
-static inline u32 ipath_make_rc_ack(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu)
+u32 ipath_make_rc_ack(struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 pmtu)
{
- struct ipath_sge_state *ss;
u32 hwords;
u32 len;
u32 bth0;
@@ -90,13 +90,12 @@ static inline u32 ipath_make_rc_ack(struct ipath_qp *qp,
*/
switch (qp->s_ack_state) {
case OP(RDMA_READ_REQUEST):
- ss = &qp->s_rdma_sge;
+ qp->s_cur_sge = &qp->s_rdma_sge;
len = qp->s_rdma_len;
if (len > pmtu) {
len = pmtu;
qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST);
- }
- else
+ } else
qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY);
qp->s_rdma_len -= len;
bth0 = qp->s_ack_state << 24;
@@ -108,7 +107,7 @@ static inline u32 ipath_make_rc_ack(struct ipath_qp *qp,
qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE);
/* FALLTHROUGH */
case OP(RDMA_READ_RESPONSE_MIDDLE):
- ss = &qp->s_rdma_sge;
+ qp->s_cur_sge = &qp->s_rdma_sge;
len = qp->s_rdma_len;
if (len > pmtu)
len = pmtu;
@@ -127,41 +126,50 @@ static inline u32 ipath_make_rc_ack(struct ipath_qp *qp,
* We have to prevent new requests from changing
* the r_sge state while a ipath_verbs_send()
* is in progress.
- * Changing r_state allows the receiver
- * to continue processing new packets.
- * We do it here now instead of above so
- * that we are sure the packet was sent before
- * changing the state.
*/
- qp->r_state = OP(RDMA_READ_RESPONSE_LAST);
qp->s_ack_state = OP(ACKNOWLEDGE);
- return 0;
+ bth0 = 0;
+ goto bail;
case OP(COMPARE_SWAP):
case OP(FETCH_ADD):
- ss = NULL;
+ qp->s_cur_sge = NULL;
len = 0;
- qp->r_state = OP(SEND_LAST);
- qp->s_ack_state = OP(ACKNOWLEDGE);
- bth0 = IB_OPCODE_ATOMIC_ACKNOWLEDGE << 24;
+ /*
+ * Set the s_ack_state so the receive interrupt handler
+ * won't try to send an ACK (out of order) until this one
+ * is actually sent.
+ */
+ qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
+ bth0 = OP(ATOMIC_ACKNOWLEDGE) << 24;
ohdr->u.at.aeth = ipath_compute_aeth(qp);
- ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->s_ack_atomic);
+ ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data);
hwords += sizeof(ohdr->u.at) / 4;
break;
default:
/* Send a regular ACK. */
- ss = NULL;
+ qp->s_cur_sge = NULL;
len = 0;
- qp->s_ack_state = OP(ACKNOWLEDGE);
- bth0 = qp->s_ack_state << 24;
- ohdr->u.aeth = ipath_compute_aeth(qp);
+ /*
+ * Set the s_ack_state so the receive interrupt handler
+ * won't try to send an ACK (out of order) until this one
+ * is actually sent.
+ */
+ qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST);
+ bth0 = OP(ACKNOWLEDGE) << 24;
+ if (qp->s_nak_state)
+ ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
+ (qp->s_nak_state <<
+ IPATH_AETH_CREDIT_SHIFT));
+ else
+ ohdr->u.aeth = ipath_compute_aeth(qp);
hwords++;
}
qp->s_hdrwords = hwords;
- qp->s_cur_sge = ss;
qp->s_cur_size = len;
+bail:
return bth0;
}
@@ -174,11 +182,11 @@ static inline u32 ipath_make_rc_ack(struct ipath_qp *qp,
* @bth2p: pointer to the BTH PSN word
*
* Return 1 if constructed; otherwise, return 0.
- * Note the QP s_lock must be held.
+ * Note the QP s_lock must be held and interrupts disabled.
*/
-static inline int ipath_make_rc_req(struct ipath_qp *qp,
- struct ipath_other_headers *ohdr,
- u32 pmtu, u32 *bth0p, u32 *bth2p)
+int ipath_make_rc_req(struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 pmtu, u32 *bth0p, u32 *bth2p)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_sge_state *ss;
@@ -193,6 +201,18 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_rnr_timeout)
goto done;
+ /* Limit the number of packets sent without an ACK. */
+ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
+ qp->s_wait_credit = 1;
+ dev->n_rc_stalls++;
+ spin_lock(&dev->pending_lock);
+ if (list_empty(&qp->timerwait))
+ list_add_tail(&qp->timerwait,
+ &dev->pending[dev->pending_index]);
+ spin_unlock(&dev->pending_lock);
+ goto done;
+ }
+
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
bth0 = 0;
@@ -213,7 +233,7 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
/* Check if send work queue is empty. */
if (qp->s_tail == qp->s_head)
goto done;
- qp->s_psn = wqe->psn = qp->s_next_psn;
+ wqe->psn = qp->s_next_psn;
newreq = 1;
}
/*
@@ -257,7 +277,7 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
break;
case IB_WR_RDMA_WRITE:
- if (newreq)
+ if (newreq && qp->s_lsn != (u32) -1)
qp->s_lsn++;
/* FALLTHROUGH */
case IB_WR_RDMA_WRITE_WITH_IMM:
@@ -283,8 +303,7 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
else {
qp->s_state =
OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE);
- /* Immediate data comes
- * after RETH */
+ /* Immediate data comes after RETH */
ohdr->u.rc.imm_data = wqe->wr.imm_data;
hwords += 1;
if (wqe->wr.send_flags & IB_SEND_SOLICITED)
@@ -304,7 +323,8 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_state = OP(RDMA_READ_REQUEST);
hwords += sizeof(ohdr->u.rc.reth) / 4;
if (newreq) {
- qp->s_lsn++;
+ if (qp->s_lsn != (u32) -1)
+ qp->s_lsn++;
/*
* Adjust s_next_psn to count the
* expected number of responses.
@@ -335,7 +355,8 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
wqe->wr.wr.atomic.compare_add);
hwords += sizeof(struct ib_atomic_eth) / 4;
if (newreq) {
- qp->s_lsn++;
+ if (qp->s_lsn != (u32) -1)
+ qp->s_lsn++;
wqe->lpsn = wqe->psn;
}
if (++qp->s_cur == qp->s_size)
@@ -352,9 +373,14 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
if (qp->s_tail >= qp->s_size)
qp->s_tail = 0;
}
- bth2 |= qp->s_psn++ & IPS_PSN_MASK;
+ bth2 |= qp->s_psn++ & IPATH_PSN_MASK;
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
qp->s_next_psn = qp->s_psn;
+ /*
+ * Put the QP on the pending list so lost ACKs will cause
+ * a retry. More than one request can be pending so the
+ * QP may already be on the dev->pending list.
+ */
spin_lock(&dev->pending_lock);
if (list_empty(&qp->timerwait))
list_add_tail(&qp->timerwait,
@@ -364,8 +390,8 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
case OP(RDMA_READ_RESPONSE_FIRST):
/*
- * This case can only happen if a send is restarted. See
- * ipath_restart_rc().
+ * This case can only happen if a send is restarted.
+ * See ipath_restart_rc().
*/
ipath_init_restart(qp, wqe);
/* FALLTHROUGH */
@@ -373,18 +399,12 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_state = OP(SEND_MIDDLE);
/* FALLTHROUGH */
case OP(SEND_MIDDLE):
- bth2 = qp->s_psn++ & IPS_PSN_MASK;
+ bth2 = qp->s_psn++ & IPATH_PSN_MASK;
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
qp->s_next_psn = qp->s_psn;
ss = &qp->s_sge;
len = qp->s_len;
if (len > pmtu) {
- /*
- * Request an ACK every 1/2 MB to avoid retransmit
- * timeouts.
- */
- if (((wqe->length - len) % (512 * 1024)) == 0)
- bth2 |= 1 << 31;
len = pmtu;
break;
}
@@ -415,18 +435,12 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_state = OP(RDMA_WRITE_MIDDLE);
/* FALLTHROUGH */
case OP(RDMA_WRITE_MIDDLE):
- bth2 = qp->s_psn++ & IPS_PSN_MASK;
+ bth2 = qp->s_psn++ & IPATH_PSN_MASK;
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
qp->s_next_psn = qp->s_psn;
ss = &qp->s_sge;
len = qp->s_len;
if (len > pmtu) {
- /*
- * Request an ACK every 1/2 MB to avoid retransmit
- * timeouts.
- */
- if (((wqe->length - len) % (512 * 1024)) == 0)
- bth2 |= 1 << 31;
len = pmtu;
break;
}
@@ -452,7 +466,7 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
* See ipath_restart_rc().
*/
ipath_init_restart(qp, wqe);
- len = ((qp->s_psn - wqe->psn) & IPS_PSN_MASK) * pmtu;
+ len = ((qp->s_psn - wqe->psn) & IPATH_PSN_MASK) * pmtu;
ohdr->u.rc.reth.vaddr =
cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len);
ohdr->u.rc.reth.rkey =
@@ -460,7 +474,7 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
ohdr->u.rc.reth.length = cpu_to_be32(qp->s_len);
qp->s_state = OP(RDMA_READ_REQUEST);
hwords += sizeof(ohdr->u.rc.reth) / 4;
- bth2 = qp->s_psn++ & IPS_PSN_MASK;
+ bth2 = qp->s_psn++ & IPATH_PSN_MASK;
if ((int)(qp->s_psn - qp->s_next_psn) > 0)
qp->s_next_psn = qp->s_psn;
ss = NULL;
@@ -484,6 +498,8 @@ static inline int ipath_make_rc_req(struct ipath_qp *qp,
*/
goto done;
}
+ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0)
+ bth2 |= 1 << 31; /* Request ACK. */
qp->s_len -= len;
qp->s_hdrwords = hwords;
qp->s_cur_sge = ss;
@@ -496,189 +512,169 @@ done:
return 0;
}
-static inline void ipath_make_rc_grh(struct ipath_qp *qp,
- struct ib_global_route *grh,
- u32 nwords)
-{
- struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
-
- /* GRH header size in 32-bit words. */
- qp->s_hdrwords += 10;
- qp->s_hdr.u.l.grh.version_tclass_flow =
- cpu_to_be32((6 << 28) |
- (grh->traffic_class << 20) |
- grh->flow_label);
- qp->s_hdr.u.l.grh.paylen =
- cpu_to_be16(((qp->s_hdrwords - 12) + nwords +
- SIZE_OF_CRC) << 2);
- /* next_hdr is defined by C8-7 in ch. 8.4.1 */
- qp->s_hdr.u.l.grh.next_hdr = 0x1B;
- qp->s_hdr.u.l.grh.hop_limit = grh->hop_limit;
- /* The SGID is 32-bit aligned. */
- qp->s_hdr.u.l.grh.sgid.global.subnet_prefix = dev->gid_prefix;
- qp->s_hdr.u.l.grh.sgid.global.interface_id =
- ipath_layer_get_guid(dev->dd);
- qp->s_hdr.u.l.grh.dgid = grh->dgid;
-}
-
/**
- * ipath_do_rc_send - perform a send on an RC QP
- * @data: contains a pointer to the QP
+ * send_rc_ack - Construct an ACK packet and send it
+ * @qp: a pointer to the QP
*
- * Process entries in the send work queue until credit or queue is
- * exhausted. Only allow one CPU to send a packet per QP (tasklet).
- * Otherwise, after we drop the QP s_lock, two threads could send
- * packets out of order.
+ * This is called from ipath_rc_rcv() and only uses the receive
+ * side QP state.
+ * Note that RDMA reads are handled in the send side QP state and tasklet.
*/
-void ipath_do_rc_send(unsigned long data)
+static void send_rc_ack(struct ipath_qp *qp)
{
- struct ipath_qp *qp = (struct ipath_qp *)data;
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
- unsigned long flags;
u16 lrh0;
- u32 nwords;
- u32 extra_bytes;
u32 bth0;
- u32 bth2;
- u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+ u32 hwords;
+ struct ipath_ib_header hdr;
struct ipath_other_headers *ohdr;
- if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags))
- goto bail;
-
- if (unlikely(qp->remote_ah_attr.dlid ==
- ipath_layer_get_lid(dev->dd))) {
- struct ib_wc wc;
-
- /*
- * Pass in an uninitialized ib_wc to be consistent with
- * other places where ipath_ruc_loopback() is called.
- */
- ipath_ruc_loopback(qp, &wc);
- goto clear;
- }
-
- ohdr = &qp->s_hdr.u.oth;
- if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
- ohdr = &qp->s_hdr.u.l.oth;
-
-again:
- /* Check for a constructed packet to be sent. */
- if (qp->s_hdrwords != 0) {
- /*
- * If no PIO bufs are available, return. An interrupt will
- * call ipath_ib_piobufavail() when one is available.
- */
- _VERBS_INFO("h %u %p\n", qp->s_hdrwords, &qp->s_hdr);
- _VERBS_INFO("d %u %p %u %p %u %u %u %u\n", qp->s_cur_size,
- qp->s_cur_sge->sg_list,
- qp->s_cur_sge->num_sge,
- qp->s_cur_sge->sge.vaddr,
- qp->s_cur_sge->sge.sge_length,
- qp->s_cur_sge->sge.length,
- qp->s_cur_sge->sge.m,
- qp->s_cur_sge->sge.n);
- if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
- (u32 *) &qp->s_hdr, qp->s_cur_size,
- qp->s_cur_sge)) {
- ipath_no_bufs_available(qp, dev);
- goto bail;
- }
- dev->n_unicast_xmit++;
- /* Record that we sent the packet and s_hdr is empty. */
- qp->s_hdrwords = 0;
- }
-
- /*
- * The lock is needed to synchronize between setting
- * qp->s_ack_state, resend timer, and post_send().
- */
- spin_lock_irqsave(&qp->s_lock, flags);
-
- /* Sending responses has higher priority over sending requests. */
- if (qp->s_ack_state != OP(ACKNOWLEDGE) &&
- (bth0 = ipath_make_rc_ack(qp, ohdr, pmtu)) != 0)
- bth2 = qp->s_ack_psn++ & IPS_PSN_MASK;
- else if (!ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2))
- goto done;
-
- spin_unlock_irqrestore(&qp->s_lock, flags);
-
/* Construct the header. */
- extra_bytes = (4 - qp->s_cur_size) & 3;
- nwords = (qp->s_cur_size + extra_bytes) >> 2;
- lrh0 = IPS_LRH_BTH;
+ ohdr = &hdr.u.oth;
+ lrh0 = IPATH_LRH_BTH;
+ /* header size in 32-bit words LRH+BTH+AETH = (8+12+4)/4. */
+ hwords = 6;
if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
- ipath_make_rc_grh(qp, &qp->remote_ah_attr.grh, nwords);
- lrh0 = IPS_LRH_GRH;
+ hwords += ipath_make_grh(dev, &hdr.u.l.grh,
+ &qp->remote_ah_attr.grh,
+ hwords, 0);
+ ohdr = &hdr.u.l.oth;
+ lrh0 = IPATH_LRH_GRH;
}
+ /* read pkey_index w/o lock (its atomic) */
+ bth0 = ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ if (qp->r_nak_state)
+ ohdr->u.aeth = cpu_to_be32((qp->r_msn & IPATH_MSN_MASK) |
+ (qp->r_nak_state <<
+ IPATH_AETH_CREDIT_SHIFT));
+ else
+ ohdr->u.aeth = ipath_compute_aeth(qp);
+ if (qp->r_ack_state >= OP(COMPARE_SWAP)) {
+ bth0 |= OP(ATOMIC_ACKNOWLEDGE) << 24;
+ ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->r_atomic_data);
+ hwords += sizeof(ohdr->u.at.atomic_ack_eth) / 4;
+ } else
+ bth0 |= OP(ACKNOWLEDGE) << 24;
lrh0 |= qp->remote_ah_attr.sl << 4;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
- SIZE_OF_CRC);
- qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd));
- bth0 |= ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
- bth0 |= extra_bytes << 20;
+ hdr.lrh[0] = cpu_to_be16(lrh0);
+ hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC);
+ hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
ohdr->bth[0] = cpu_to_be32(bth0);
ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
- ohdr->bth[2] = cpu_to_be32(bth2);
+ ohdr->bth[2] = cpu_to_be32(qp->r_ack_psn & IPATH_PSN_MASK);
- /* Check for more work to do. */
- goto again;
+ /*
+ * If we can send the ACK, clear the ACK state.
+ */
+ if (ipath_verbs_send(dev->dd, hwords, (u32 *) &hdr, 0, NULL) == 0) {
+ qp->r_ack_state = OP(ACKNOWLEDGE);
+ dev->n_unicast_xmit++;
+ } else {
+ /*
+ * We are out of PIO buffers at the moment.
+ * Pass responsibility for sending the ACK to the
+ * send tasklet so that when a PIO buffer becomes
+ * available, the ACK is sent ahead of other outgoing
+ * packets.
+ */
+ dev->n_rc_qacks++;
+ spin_lock_irq(&qp->s_lock);
+ /* Don't coalesce if a RDMA read or atomic is pending. */
+ if (qp->s_ack_state == OP(ACKNOWLEDGE) ||
+ qp->s_ack_state < OP(RDMA_READ_REQUEST)) {
+ qp->s_ack_state = qp->r_ack_state;
+ qp->s_nak_state = qp->r_nak_state;
+ qp->s_ack_psn = qp->r_ack_psn;
+ qp->r_ack_state = OP(ACKNOWLEDGE);
+ }
+ spin_unlock_irq(&qp->s_lock);
-done:
- spin_unlock_irqrestore(&qp->s_lock, flags);
-clear:
- clear_bit(IPATH_S_BUSY, &qp->s_flags);
-bail:
- return;
+ /* Call ipath_do_rc_send() in another thread. */
+ tasklet_hi_schedule(&qp->s_task);
+ }
}
-static void send_rc_ack(struct ipath_qp *qp)
+/**
+ * reset_psn - reset the QP state to send starting from PSN
+ * @qp: the QP
+ * @psn: the packet sequence number to restart at
+ *
+ * This is called from ipath_rc_rcv() to process an incoming RC ACK
+ * for the given QP.
+ * Called at interrupt level with the QP s_lock held.
+ */
+static void reset_psn(struct ipath_qp *qp, u32 psn)
{
- struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
- u16 lrh0;
- u32 bth0;
- struct ipath_other_headers *ohdr;
+ u32 n = qp->s_last;
+ struct ipath_swqe *wqe = get_swqe_ptr(qp, n);
+ u32 opcode;
- /* Construct the header. */
- ohdr = &qp->s_hdr.u.oth;
- lrh0 = IPS_LRH_BTH;
- /* header size in 32-bit words LRH+BTH+AETH = (8+12+4)/4. */
- qp->s_hdrwords = 6;
- if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
- ipath_make_rc_grh(qp, &qp->remote_ah_attr.grh, 0);
- ohdr = &qp->s_hdr.u.l.oth;
- lrh0 = IPS_LRH_GRH;
+ qp->s_cur = n;
+
+ /*
+ * If we are starting the request from the beginning,
+ * let the normal send code handle initialization.
+ */
+ if (ipath_cmp24(psn, wqe->psn) <= 0) {
+ qp->s_state = OP(SEND_LAST);
+ goto done;
}
- bth0 = ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
- ohdr->u.aeth = ipath_compute_aeth(qp);
- if (qp->s_ack_state >= OP(COMPARE_SWAP)) {
- bth0 |= IB_OPCODE_ATOMIC_ACKNOWLEDGE << 24;
- ohdr->u.at.atomic_ack_eth = cpu_to_be64(qp->s_ack_atomic);
- qp->s_hdrwords += sizeof(ohdr->u.at.atomic_ack_eth) / 4;
+
+ /* Find the work request opcode corresponding to the given PSN. */
+ opcode = wqe->wr.opcode;
+ for (;;) {
+ int diff;
+
+ if (++n == qp->s_size)
+ n = 0;
+ if (n == qp->s_tail)
+ break;
+ wqe = get_swqe_ptr(qp, n);
+ diff = ipath_cmp24(psn, wqe->psn);
+ if (diff < 0)
+ break;
+ qp->s_cur = n;
+ /*
+ * If we are starting the request from the beginning,
+ * let the normal send code handle initialization.
+ */
+ if (diff == 0) {
+ qp->s_state = OP(SEND_LAST);
+ goto done;
+ }
+ opcode = wqe->wr.opcode;
}
- else
- bth0 |= OP(ACKNOWLEDGE) << 24;
- lrh0 |= qp->remote_ah_attr.sl << 4;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
- qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + SIZE_OF_CRC);
- qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd));
- ohdr->bth[0] = cpu_to_be32(bth0);
- ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
- ohdr->bth[2] = cpu_to_be32(qp->s_ack_psn & IPS_PSN_MASK);
/*
- * If we can send the ACK, clear the ACK state.
+ * Set the state to restart in the middle of a request.
+ * Don't change the s_sge, s_cur_sge, or s_cur_size.
+ * See ipath_do_rc_send().
*/
- if (ipath_verbs_send(dev->dd, qp->s_hdrwords, (u32 *) &qp->s_hdr,
- 0, NULL) == 0) {
- qp->s_ack_state = OP(ACKNOWLEDGE);
- dev->n_rc_qacks++;
- dev->n_unicast_xmit++;
+ switch (opcode) {
+ case IB_WR_SEND:
+ case IB_WR_SEND_WITH_IMM:
+ qp->s_state = OP(RDMA_READ_RESPONSE_FIRST);
+ break;
+
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ qp->s_state = OP(RDMA_READ_RESPONSE_LAST);
+ break;
+
+ case IB_WR_RDMA_READ:
+ qp->s_state = OP(RDMA_READ_RESPONSE_MIDDLE);
+ break;
+
+ default:
+ /*
+ * This case shouldn't happen since its only
+ * one PSN per req.
+ */
+ qp->s_state = OP(SEND_LAST);
}
+done:
+ qp->s_psn = psn;
}
/**
@@ -687,13 +683,12 @@ static void send_rc_ack(struct ipath_qp *qp)
* @psn: packet sequence number for the request
* @wc: the work completion request
*
- * The QP s_lock should be held.
+ * The QP s_lock should be held and interrupts disabled.
*/
void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
{
struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
struct ipath_ibdev *dev;
- u32 n;
/*
* If there are no requests pending, we are done.
@@ -735,62 +730,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
else
dev->n_rc_resends += (int)qp->s_psn - (int)psn;
- /*
- * If we are starting the request from the beginning, let the normal
- * send code handle initialization.
- */
- qp->s_cur = qp->s_last;
- if (ipath_cmp24(psn, wqe->psn) <= 0) {
- qp->s_state = OP(SEND_LAST);
- qp->s_psn = wqe->psn;
- } else {
- n = qp->s_cur;
- for (;;) {
- if (++n == qp->s_size)
- n = 0;
- if (n == qp->s_tail) {
- if (ipath_cmp24(psn, qp->s_next_psn) >= 0) {
- qp->s_cur = n;
- wqe = get_swqe_ptr(qp, n);
- }
- break;
- }
- wqe = get_swqe_ptr(qp, n);
- if (ipath_cmp24(psn, wqe->psn) < 0)
- break;
- qp->s_cur = n;
- }
- qp->s_psn = psn;
-
- /*
- * Reset the state to restart in the middle of a request.
- * Don't change the s_sge, s_cur_sge, or s_cur_size.
- * See ipath_do_rc_send().
- */
- switch (wqe->wr.opcode) {
- case IB_WR_SEND:
- case IB_WR_SEND_WITH_IMM:
- qp->s_state = OP(RDMA_READ_RESPONSE_FIRST);
- break;
-
- case IB_WR_RDMA_WRITE:
- case IB_WR_RDMA_WRITE_WITH_IMM:
- qp->s_state = OP(RDMA_READ_RESPONSE_LAST);
- break;
-
- case IB_WR_RDMA_READ:
- qp->s_state =
- OP(RDMA_READ_RESPONSE_MIDDLE);
- break;
-
- default:
- /*
- * This case shouldn't happen since its only
- * one PSN per req.
- */
- qp->s_state = OP(SEND_LAST);
- }
- }
+ reset_psn(qp, psn);
done:
tasklet_hi_schedule(&qp->s_task);
@@ -799,66 +739,13 @@ bail:
return;
}
-/**
- * reset_psn - reset the QP state to send starting from PSN
- * @qp: the QP
- * @psn: the packet sequence number to restart at
- *
- * This is called from ipath_rc_rcv() to process an incoming RC ACK
- * for the given QP.
- * Called at interrupt level with the QP s_lock held.
- */
-static void reset_psn(struct ipath_qp *qp, u32 psn)
+static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
{
- struct ipath_swqe *wqe;
- u32 n;
-
- n = qp->s_cur;
- wqe = get_swqe_ptr(qp, n);
- for (;;) {
- if (++n == qp->s_size)
- n = 0;
- if (n == qp->s_tail) {
- if (ipath_cmp24(psn, qp->s_next_psn) >= 0) {
- qp->s_cur = n;
- wqe = get_swqe_ptr(qp, n);
- }
- break;
- }
- wqe = get_swqe_ptr(qp, n);
- if (ipath_cmp24(psn, wqe->psn) < 0)
- break;
- qp->s_cur = n;
- }
- qp->s_psn = psn;
-
- /*
- * Set the state to restart in the middle of a
- * request. Don't change the s_sge, s_cur_sge, or
- * s_cur_size. See ipath_do_rc_send().
- */
- switch (wqe->wr.opcode) {
- case IB_WR_SEND:
- case IB_WR_SEND_WITH_IMM:
- qp->s_state = OP(RDMA_READ_RESPONSE_FIRST);
- break;
-
- case IB_WR_RDMA_WRITE:
- case IB_WR_RDMA_WRITE_WITH_IMM:
- qp->s_state = OP(RDMA_READ_RESPONSE_LAST);
- break;
-
- case IB_WR_RDMA_READ:
- qp->s_state = OP(RDMA_READ_RESPONSE_MIDDLE);
- break;
-
- default:
- /*
- * This case shouldn't happen since its only
- * one PSN per req.
- */
- qp->s_state = OP(SEND_LAST);
+ if (qp->s_wait_credit) {
+ qp->s_wait_credit = 0;
+ tasklet_hi_schedule(&qp->s_task);
}
+ qp->s_last_psn = psn;
}
/**
@@ -867,9 +754,9 @@ static void reset_psn(struct ipath_qp *qp, u32 psn)
* @psn: the packet sequence number of the ACK
* @opcode: the opcode of the request that resulted in the ACK
*
- * This is called from ipath_rc_rcv() to process an incoming RC ACK
+ * This is called from ipath_rc_rcv_resp() to process an incoming RC ACK
* for the given QP.
- * Called at interrupt level with the QP s_lock held.
+ * Called at interrupt level with the QP s_lock held and interrupts disabled.
* Returns 1 if OK, 0 if current operation should be aborted (NAK).
*/
static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
@@ -929,7 +816,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* The last valid PSN seen is the previous
* request's.
*/
- qp->s_last_psn = wqe->psn - 1;
+ update_last_psn(qp, wqe->psn - 1);
/* Retry this request. */
ipath_restart_rc(qp, wqe->psn, &wc);
/*
@@ -988,7 +875,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
ipath_get_credit(qp, aeth);
qp->s_rnr_retry = qp->s_rnr_retry_cnt;
qp->s_retry = qp->s_retry_cnt;
- qp->s_last_psn = psn;
+ update_last_psn(qp, psn);
ret = 1;
goto bail;
@@ -1006,35 +893,25 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
if (qp->s_last == qp->s_tail)
goto bail;
- /* The last valid PSN seen is the previous request's. */
- qp->s_last_psn = wqe->psn - 1;
+ /* The last valid PSN is the previous PSN. */
+ update_last_psn(qp, psn - 1);
dev->n_rc_resends += (int)qp->s_psn - (int)psn;
- /*
- * If we are starting the request from the beginning, let
- * the normal send code handle initialization.
- */
- qp->s_cur = qp->s_last;
- wqe = get_swqe_ptr(qp, qp->s_cur);
- if (ipath_cmp24(psn, wqe->psn) <= 0) {
- qp->s_state = OP(SEND_LAST);
- qp->s_psn = wqe->psn;
- } else
- reset_psn(qp, psn);
+ reset_psn(qp, psn);
qp->s_rnr_timeout =
- ib_ipath_rnr_table[(aeth >> IPS_AETH_CREDIT_SHIFT) &
- IPS_AETH_CREDIT_MASK];
+ ib_ipath_rnr_table[(aeth >> IPATH_AETH_CREDIT_SHIFT) &
+ IPATH_AETH_CREDIT_MASK];
ipath_insert_rnr_queue(qp);
goto bail;
case 3: /* NAK */
/* The last valid PSN seen is the previous request's. */
if (qp->s_last != qp->s_tail)
- qp->s_last_psn = wqe->psn - 1;
- switch ((aeth >> IPS_AETH_CREDIT_SHIFT) &
- IPS_AETH_CREDIT_MASK) {
+ update_last_psn(qp, wqe->psn - 1);
+ switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
+ IPATH_AETH_CREDIT_MASK) {
case 0: /* PSN sequence error */
dev->n_seq_naks++;
/*
@@ -1182,32 +1059,33 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
goto ack_done;
}
rdma_read:
- if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST)))
- goto ack_done;
- if (unlikely(tlen != (hdrsize + pmtu + 4)))
- goto ack_done;
- if (unlikely(pmtu >= qp->s_len))
- goto ack_done;
- /* We got a response so update the timeout. */
- if (unlikely(qp->s_last == qp->s_tail ||
- get_swqe_ptr(qp, qp->s_last)->wr.opcode !=
- IB_WR_RDMA_READ))
- goto ack_done;
- spin_lock(&dev->pending_lock);
- if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait))
- list_move_tail(&qp->timerwait,
- &dev->pending[dev->pending_index]);
- spin_unlock(&dev->pending_lock);
- /*
- * Update the RDMA receive state but do the copy w/o holding the
- * locks and blocking interrupts. XXX Yet another place that
- * affects relaxed RDMA order since we don't want s_sge modified.
- */
- qp->s_len -= pmtu;
- qp->s_last_psn = psn;
- spin_unlock_irqrestore(&qp->s_lock, flags);
- ipath_copy_sge(&qp->s_sge, data, pmtu);
- goto bail;
+ if (unlikely(qp->s_state != OP(RDMA_READ_REQUEST)))
+ goto ack_done;
+ if (unlikely(tlen != (hdrsize + pmtu + 4)))
+ goto ack_done;
+ if (unlikely(pmtu >= qp->s_len))
+ goto ack_done;
+ /* We got a response so update the timeout. */
+ if (unlikely(qp->s_last == qp->s_tail ||
+ get_swqe_ptr(qp, qp->s_last)->wr.opcode !=
+ IB_WR_RDMA_READ))
+ goto ack_done;
+ spin_lock(&dev->pending_lock);
+ if (qp->s_rnr_timeout == 0 && !list_empty(&qp->timerwait))
+ list_move_tail(&qp->timerwait,
+ &dev->pending[dev->pending_index]);
+ spin_unlock(&dev->pending_lock);
+ /*
+ * Update the RDMA receive state but do the copy w/o
+ * holding the locks and blocking interrupts.
+ * XXX Yet another place that affects relaxed RDMA order
+ * since we don't want s_sge modified.
+ */
+ qp->s_len -= pmtu;
+ update_last_psn(qp, psn);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ ipath_copy_sge(&qp->s_sge, data, pmtu);
+ goto bail;
case OP(RDMA_READ_RESPONSE_LAST):
/* ACKs READ req. */
@@ -1230,18 +1108,12 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
* ICRC (4).
*/
if (unlikely(tlen <= (hdrsize + pad + 8))) {
- /*
- * XXX Need to generate an error CQ
- * entry.
- */
+ /* XXX Need to generate an error CQ entry. */
goto ack_done;
}
tlen -= hdrsize + pad + 8;
if (unlikely(tlen != qp->s_len)) {
- /*
- * XXX Need to generate an error CQ
- * entry.
- */
+ /* XXX Need to generate an error CQ entry. */
goto ack_done;
}
if (!header_in_data)
@@ -1254,9 +1126,12 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
if (do_rc_ack(qp, aeth, psn, OP(RDMA_READ_RESPONSE_LAST))) {
/*
* Change the state so we contimue
- * processing new requests.
+ * processing new requests and wake up the
+ * tasklet if there are posted sends.
*/
qp->s_state = OP(SEND_LAST);
+ if (qp->s_tail != qp->s_head)
+ tasklet_hi_schedule(&qp->s_task);
}
goto ack_done;
}
@@ -1302,18 +1177,16 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
* Don't queue the NAK if a RDMA read, atomic, or
* NAK is pending though.
*/
- spin_lock(&qp->s_lock);
- if ((qp->s_ack_state >= OP(RDMA_READ_REQUEST) &&
- qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE) ||
- qp->s_nak_state != 0) {
- spin_unlock(&qp->s_lock);
+ if (qp->s_ack_state != OP(ACKNOWLEDGE) ||
+ qp->r_nak_state != 0)
goto done;
+ if (qp->r_ack_state < OP(COMPARE_SWAP)) {
+ qp->r_ack_state = OP(SEND_ONLY);
+ qp->r_nak_state = IB_NAK_PSN_ERROR;
+ /* Use the expected PSN. */
+ qp->r_ack_psn = qp->r_psn;
}
- qp->s_ack_state = OP(SEND_ONLY);
- qp->s_nak_state = IB_NAK_PSN_ERROR;
- /* Use the expected PSN. */
- qp->s_ack_psn = qp->r_psn;
- goto resched;
+ goto send_ack;
}
/*
@@ -1327,27 +1200,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
* send the earliest so that RDMA reads can be restarted at
* the requester's expected PSN.
*/
- spin_lock(&qp->s_lock);
- if (qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE &&
- ipath_cmp24(psn, qp->s_ack_psn) >= 0) {
- if (qp->s_ack_state < IB_OPCODE_RDMA_READ_REQUEST)
- qp->s_ack_psn = psn;
- spin_unlock(&qp->s_lock);
- goto done;
- }
- switch (opcode) {
- case OP(RDMA_READ_REQUEST):
- /*
- * We have to be careful to not change s_rdma_sge
- * while ipath_do_rc_send() is using it and not
- * holding the s_lock.
- */
- if (qp->s_ack_state != OP(ACKNOWLEDGE) &&
- qp->s_ack_state >= IB_OPCODE_RDMA_READ_REQUEST) {
- spin_unlock(&qp->s_lock);
- dev->n_rdma_dup_busy++;
- goto done;
- }
+ if (opcode == OP(RDMA_READ_REQUEST)) {
/* RETH comes after BTH */
if (!header_in_data)
reth = &ohdr->u.rc.reth;
@@ -1355,6 +1208,22 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
reth = (struct ib_reth *)data;
data += sizeof(*reth);
}
+ /*
+ * If we receive a duplicate RDMA request, it means the
+ * requester saw a sequence error and needs to restart
+ * from an earlier point. We can abort the current
+ * RDMA read send in that case.
+ */
+ spin_lock_irq(&qp->s_lock);
+ if (qp->s_ack_state != OP(ACKNOWLEDGE) &&
+ (qp->s_hdrwords || ipath_cmp24(psn, qp->s_ack_psn) >= 0)) {
+ /*
+ * We are already sending earlier requested data.
+ * Don't abort it to send later out of sequence data.
+ */
+ spin_unlock_irq(&qp->s_lock);
+ goto done;
+ }
qp->s_rdma_len = be32_to_cpu(reth->length);
if (qp->s_rdma_len != 0) {
u32 rkey = be32_to_cpu(reth->rkey);
@@ -1365,11 +1234,13 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
* Address range must be a subset of the original
* request and start on pmtu boundaries.
*/
- ok = ipath_rkey_ok(dev, &qp->s_rdma_sge,
+ ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
qp->s_rdma_len, vaddr, rkey,
IB_ACCESS_REMOTE_READ);
- if (unlikely(!ok))
+ if (unlikely(!ok)) {
+ spin_unlock_irq(&qp->s_lock);
goto done;
+ }
} else {
qp->s_rdma_sge.sg_list = NULL;
qp->s_rdma_sge.num_sge = 0;
@@ -1378,31 +1249,58 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
qp->s_rdma_sge.sge.length = 0;
qp->s_rdma_sge.sge.sge_length = 0;
}
- break;
+ qp->s_ack_state = opcode;
+ qp->s_ack_psn = psn;
+ spin_unlock_irq(&qp->s_lock);
+ tasklet_hi_schedule(&qp->s_task);
+ goto send_ack;
+ }
+
+ /*
+ * A pending RDMA read will ACK anything before it so
+ * ignore earlier duplicate requests.
+ */
+ if (qp->s_ack_state != OP(ACKNOWLEDGE))
+ goto done;
+ /*
+ * If an ACK is pending, don't replace the pending ACK
+ * with an earlier one since the later one will ACK the earlier.
+ * Also, if we already have a pending atomic, send it.
+ */
+ if (qp->r_ack_state != OP(ACKNOWLEDGE) &&
+ (ipath_cmp24(psn, qp->r_ack_psn) <= 0 ||
+ qp->r_ack_state >= OP(COMPARE_SWAP)))
+ goto send_ack;
+ switch (opcode) {
case OP(COMPARE_SWAP):
case OP(FETCH_ADD):
/*
- * Check for the PSN of the last atomic operations
+ * Check for the PSN of the last atomic operation
* performed and resend the result if found.
*/
- if ((psn & IPS_PSN_MASK) != qp->r_atomic_psn) {
- spin_unlock(&qp->s_lock);
+ if ((psn & IPATH_PSN_MASK) != qp->r_atomic_psn)
goto done;
- }
- qp->s_ack_atomic = qp->r_atomic_data;
break;
}
- qp->s_ack_state = opcode;
- qp->s_nak_state = 0;
- qp->s_ack_psn = psn;
-resched:
+ qp->r_ack_state = opcode;
+ qp->r_nak_state = 0;
+ qp->r_ack_psn = psn;
+send_ack:
return 0;
done:
return 1;
}
+static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
+{
+ spin_lock_irq(&qp->s_lock);
+ qp->state = IB_QPS_ERR;
+ ipath_error_qp(qp, err);
+ spin_unlock_irq(&qp->s_lock);
+}
+
/**
* ipath_rc_rcv - process an incoming RC packet
* @dev: the device this packet came in on
@@ -1424,13 +1322,16 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
u32 hdrsize;
u32 psn;
u32 pad;
- unsigned long flags;
struct ib_wc wc;
u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
int diff;
struct ib_reth *reth;
int header_in_data;
+ /* Validate the SLID. See Ch. 9.6.1.5 */
+ if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
+ goto done;
+
/* Check for GRH */
if (!has_grh) {
ohdr = &hdr->u.oth;
@@ -1445,19 +1346,13 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* the eager header buffer size to 56 bytes so the last 4
* bytes of the BTH header (PSN) is in the data buffer.
*/
- header_in_data =
- ipath_layer_get_rcvhdrentsize(dev->dd) == 16;
+ header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
if (header_in_data) {
psn = be32_to_cpu(((__be32 *) data)[0]);
data += sizeof(__be32);
} else
psn = be32_to_cpu(ohdr->bth[2]);
}
- /*
- * The opcode is in the low byte when its in network order
- * (top byte when in host order).
- */
- opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
/*
* Process responses (ACKs) before anything else. Note that the
@@ -1465,22 +1360,21 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* queue rather than the expected receive packet sequence number.
* In other words, this QP is the requester.
*/
+ opcode = be32_to_cpu(ohdr->bth[0]) >> 24;
if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) &&
opcode <= OP(ATOMIC_ACKNOWLEDGE)) {
ipath_rc_rcv_resp(dev, ohdr, data, tlen, qp, opcode, psn,
hdrsize, pmtu, header_in_data);
- goto bail;
+ goto done;
}
- spin_lock_irqsave(&qp->r_rq.lock, flags);
-
/* Compute 24 bits worth of difference. */
diff = ipath_cmp24(psn, qp->r_psn);
if (unlikely(diff)) {
if (ipath_rc_rcv_error(dev, ohdr, data, qp, opcode,
psn, diff, header_in_data))
goto done;
- goto resched;
+ goto send_ack;
}
/* Check for opcode sequence errors. */
@@ -1492,22 +1386,18 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
opcode == OP(SEND_LAST_WITH_IMMEDIATE))
break;
nack_inv:
- /*
- * A NAK will ACK earlier sends and RDMA writes. Don't queue the
- * NAK if a RDMA read, atomic, or NAK is pending though.
- */
- spin_lock(&qp->s_lock);
- if (qp->s_ack_state >= OP(RDMA_READ_REQUEST) &&
- qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE) {
- spin_unlock(&qp->s_lock);
- goto done;
- }
- /* XXX Flush WQEs */
- qp->state = IB_QPS_ERR;
- qp->s_ack_state = OP(SEND_ONLY);
- qp->s_nak_state = IB_NAK_INVALID_REQUEST;
- qp->s_ack_psn = qp->r_psn;
- goto resched;
+ /*
+ * A NAK will ACK earlier sends and RDMA writes.
+ * Don't queue the NAK if a RDMA read, atomic, or NAK
+ * is pending though.
+ */
+ if (qp->r_ack_state >= OP(COMPARE_SWAP))
+ goto send_ack;
+ ipath_rc_error(qp, IB_WC_REM_INV_REQ_ERR);
+ qp->r_ack_state = OP(SEND_ONLY);
+ qp->r_nak_state = IB_NAK_INVALID_REQUEST;
+ qp->r_ack_psn = qp->r_psn;
+ goto send_ack;
case OP(RDMA_WRITE_FIRST):
case OP(RDMA_WRITE_MIDDLE):
@@ -1517,20 +1407,6 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
break;
goto nack_inv;
- case OP(RDMA_READ_REQUEST):
- case OP(COMPARE_SWAP):
- case OP(FETCH_ADD):
- /*
- * Drop all new requests until a response has been sent. A
- * new request then ACKs the RDMA response we sent. Relaxed
- * ordering would allow new requests to be processed but we
- * would need to keep a queue of rwqe's for all that are in
- * progress. Note that we can't RNR NAK this request since
- * the RDMA READ or atomic response is already queued to be
- * sent (unless we implement a response send queue).
- */
- goto done;
-
default:
if (opcode == OP(SEND_MIDDLE) ||
opcode == OP(SEND_LAST) ||
@@ -1539,6 +1415,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
opcode == OP(RDMA_WRITE_LAST) ||
opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE))
goto nack_inv;
+ /*
+ * Note that it is up to the requester to not send a new
+ * RDMA read or atomic operation before receiving an ACK
+ * for the previous operation.
+ */
break;
}
@@ -1555,17 +1436,12 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* Don't queue the NAK if a RDMA read or atomic
* is pending though.
*/
- spin_lock(&qp->s_lock);
- if (qp->s_ack_state >=
- OP(RDMA_READ_REQUEST) &&
- qp->s_ack_state != IB_OPCODE_ACKNOWLEDGE) {
- spin_unlock(&qp->s_lock);
- goto done;
- }
- qp->s_ack_state = OP(SEND_ONLY);
- qp->s_nak_state = IB_RNR_NAK | qp->s_min_rnr_timer;
- qp->s_ack_psn = qp->r_psn;
- goto resched;
+ if (qp->r_ack_state >= OP(COMPARE_SWAP))
+ goto send_ack;
+ qp->r_ack_state = OP(SEND_ONLY);
+ qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer;
+ qp->r_ack_psn = qp->r_psn;
+ goto send_ack;
}
qp->r_rcv_len = 0;
/* FALLTHROUGH */
@@ -1622,10 +1498,10 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
if (unlikely(wc.byte_len > qp->r_len))
goto nack_inv;
ipath_copy_sge(&qp->r_sge, data, tlen);
- atomic_inc(&qp->msn);
- if (opcode == OP(RDMA_WRITE_LAST) ||
- opcode == OP(RDMA_WRITE_ONLY))
+ qp->r_msn++;
+ if (!qp->r_wrid_valid)
break;
+ qp->r_wrid_valid = 0;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
@@ -1663,32 +1539,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int ok;
/* Check rkey & NAK */
- ok = ipath_rkey_ok(dev, &qp->r_sge,
+ ok = ipath_rkey_ok(qp, &qp->r_sge,
qp->r_len, vaddr, rkey,
IB_ACCESS_REMOTE_WRITE);
- if (unlikely(!ok)) {
- nack_acc:
- /*
- * A NAK will ACK earlier sends and RDMA
- * writes. Don't queue the NAK if a RDMA
- * read, atomic, or NAK is pending though.
- */
- spin_lock(&qp->s_lock);
- if (qp->s_ack_state >=
- OP(RDMA_READ_REQUEST) &&
- qp->s_ack_state !=
- IB_OPCODE_ACKNOWLEDGE) {
- spin_unlock(&qp->s_lock);
- goto done;
- }
- /* XXX Flush WQEs */
- qp->state = IB_QPS_ERR;
- qp->s_ack_state = OP(RDMA_WRITE_ONLY);
- qp->s_nak_state =
- IB_NAK_REMOTE_ACCESS_ERROR;
- qp->s_ack_psn = qp->r_psn;
- goto resched;
- }
+ if (unlikely(!ok))
+ goto nack_acc;
} else {
qp->r_sge.sg_list = NULL;
qp->r_sge.sge.mr = NULL;
@@ -1715,12 +1570,10 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
reth = (struct ib_reth *)data;
data += sizeof(*reth);
}
- spin_lock(&qp->s_lock);
- if (qp->s_ack_state != OP(ACKNOWLEDGE) &&
- qp->s_ack_state >= IB_OPCODE_RDMA_READ_REQUEST) {
- spin_unlock(&qp->s_lock);
- goto done;
- }
+ if (unlikely(!(qp->qp_access_flags &
+ IB_ACCESS_REMOTE_READ)))
+ goto nack_acc;
+ spin_lock_irq(&qp->s_lock);
qp->s_rdma_len = be32_to_cpu(reth->length);
if (qp->s_rdma_len != 0) {
u32 rkey = be32_to_cpu(reth->rkey);
@@ -1728,11 +1581,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int ok;
/* Check rkey & NAK */
- ok = ipath_rkey_ok(dev, &qp->s_rdma_sge,
+ ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
qp->s_rdma_len, vaddr, rkey,
IB_ACCESS_REMOTE_READ);
if (unlikely(!ok)) {
- spin_unlock(&qp->s_lock);
+ spin_unlock_irq(&qp->s_lock);
goto nack_acc;
}
/*
@@ -1749,21 +1602,25 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
qp->s_rdma_sge.sge.length = 0;
qp->s_rdma_sge.sge.sge_length = 0;
}
- if (unlikely(!(qp->qp_access_flags &
- IB_ACCESS_REMOTE_READ)))
- goto nack_acc;
/*
* We need to increment the MSN here instead of when we
* finish sending the result since a duplicate request would
* increment it more than once.
*/
- atomic_inc(&qp->msn);
+ qp->r_msn++;
+
qp->s_ack_state = opcode;
- qp->s_nak_state = 0;
qp->s_ack_psn = psn;
+ spin_unlock_irq(&qp->s_lock);
+
qp->r_psn++;
qp->r_state = opcode;
- goto rdmadone;
+ qp->r_nak_state = 0;
+
+ /* Call ipath_do_rc_send() in another thread. */
+ tasklet_hi_schedule(&qp->s_task);
+
+ goto done;
case OP(COMPARE_SWAP):
case OP(FETCH_ADD): {
@@ -1783,7 +1640,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto nack_inv;
rkey = be32_to_cpu(ateth->rkey);
/* Check rkey & NAK */
- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge,
+ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge,
sizeof(u64), vaddr, rkey,
IB_ACCESS_REMOTE_ATOMIC)))
goto nack_acc;
@@ -1792,7 +1649,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto nack_acc;
/* Perform atomic OP and save result. */
sdata = be64_to_cpu(ateth->swap_data);
- spin_lock(&dev->pending_lock);
+ spin_lock_irq(&dev->pending_lock);
qp->r_atomic_data = *(u64 *) qp->r_sge.sge.vaddr;
if (opcode == OP(FETCH_ADD))
*(u64 *) qp->r_sge.sge.vaddr =
@@ -1800,9 +1657,9 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
else if (qp->r_atomic_data ==
be64_to_cpu(ateth->compare_data))
*(u64 *) qp->r_sge.sge.vaddr = sdata;
- spin_unlock(&dev->pending_lock);
- atomic_inc(&qp->msn);
- qp->r_atomic_psn = psn & IPS_PSN_MASK;
+ spin_unlock_irq(&dev->pending_lock);
+ qp->r_msn++;
+ qp->r_atomic_psn = psn & IPATH_PSN_MASK;
psn |= 1 << 31;
break;
}
@@ -1813,44 +1670,38 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
}
qp->r_psn++;
qp->r_state = opcode;
+ qp->r_nak_state = 0;
/* Send an ACK if requested or required. */
if (psn & (1 << 31)) {
/*
* Coalesce ACKs unless there is a RDMA READ or
* ATOMIC pending.
*/
- spin_lock(&qp->s_lock);
- if (qp->s_ack_state == OP(ACKNOWLEDGE) ||
- qp->s_ack_state < IB_OPCODE_RDMA_READ_REQUEST) {
- qp->s_ack_state = opcode;
- qp->s_nak_state = 0;
- qp->s_ack_psn = psn;
- qp->s_ack_atomic = qp->r_atomic_data;
- goto resched;
+ if (qp->r_ack_state < OP(COMPARE_SWAP)) {
+ qp->r_ack_state = opcode;
+ qp->r_ack_psn = psn;
}
- spin_unlock(&qp->s_lock);
+ goto send_ack;
}
-done:
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
- goto bail;
+ goto done;
-resched:
+nack_acc:
/*
- * Try to send ACK right away but not if ipath_do_rc_send() is
- * active.
+ * A NAK will ACK earlier sends and RDMA writes.
+ * Don't queue the NAK if a RDMA read, atomic, or NAK
+ * is pending though.
*/
- if (qp->s_hdrwords == 0 &&
- (qp->s_ack_state < IB_OPCODE_RDMA_READ_REQUEST ||
- qp->s_ack_state >= IB_OPCODE_COMPARE_SWAP))
+ if (qp->r_ack_state < OP(COMPARE_SWAP)) {
+ ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
+ qp->r_ack_state = OP(RDMA_WRITE_ONLY);
+ qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
+ qp->r_ack_psn = qp->r_psn;
+ }
+send_ack:
+ /* Send ACK right away unless the send tasklet has a pending ACK. */
+ if (qp->s_ack_state == OP(ACKNOWLEDGE))
send_rc_ack(qp);
-rdmadone:
- spin_unlock(&qp->s_lock);
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
-
- /* Call ipath_do_rc_send() in another thread. */
- tasklet_hi_schedule(&qp->s_task);
-
-bail:
+done:
return;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
index 402126eb79c..dffc76016d3 100644
--- a/drivers/infiniband/hw/ipath/ipath_registers.h
+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -35,8 +36,7 @@
/*
* This file should only be included by kernel source, and by the diags. It
- * defines the registers, and their contents, for the InfiniPath HT-400
- * chip.
+ * defines the registers, and their contents, for InfiniPath chips.
*/
/*
@@ -134,10 +134,24 @@
#define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40
#define INFINIPATH_HWE_RXEMEMPARITYERR_MASK 0x7FULL
#define INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT 44
-#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL
-#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
#define INFINIPATH_HWE_IBCBUSTOSPCPARITYERR 0x4000000000000000ULL
#define INFINIPATH_HWE_IBCBUSFRSPCPARITYERR 0x8000000000000000ULL
+/* txe mem parity errors (shift by INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) */
+#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF 0x1ULL
+#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC 0x2ULL
+#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOLAUNCHFIFO 0x4ULL
+/* rxe mem parity errors (shift by INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) */
+#define INFINIPATH_HWE_RXEMEMPARITYERR_RCVBUF 0x01ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_LOOKUPQ 0x02ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x04ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_EXPTID 0x08ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_FLAGBUF 0x10ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_DATAINFO 0x20ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_HDRINFO 0x40ULL
+/* waldo specific -- find the rest in ipath_6110.c */
+#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL
+/* monty specific -- find the rest in ipath_6120.c */
+#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
/* kr_hwdiagctrl bits */
#define INFINIPATH_DC_FORCETXEMEMPARITYERR_MASK 0xFULL
@@ -209,9 +223,9 @@
/* combination link status states that we use with some frequency */
#define IPATH_IBSTATE_MASK ((INFINIPATH_IBCS_LINKTRAININGSTATE_MASK \
- << INFINIPATH_IBCS_LINKSTATE_SHIFT) | \
+ << INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | \
(INFINIPATH_IBCS_LINKSTATE_MASK \
- <<INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT))
+ <<INFINIPATH_IBCS_LINKSTATE_SHIFT))
#define IPATH_IBSTATE_INIT ((INFINIPATH_IBCS_L_STATE_INIT \
<< INFINIPATH_IBCS_LINKSTATE_SHIFT) | \
(INFINIPATH_IBCS_LT_STATE_LINKUP \
@@ -282,10 +296,12 @@
#define INFINIPATH_XGXS_RESET 0x7ULL
#define INFINIPATH_XGXS_MDIOADDR_MASK 0xfULL
#define INFINIPATH_XGXS_MDIOADDR_SHIFT 4
+#define INFINIPATH_XGXS_RX_POL_SHIFT 19
+#define INFINIPATH_XGXS_RX_POL_MASK 0xfULL
#define INFINIPATH_RT_ADDR_MASK 0xFFFFFFFFFFULL /* 40 bits valid */
-/* TID entries (memory), HT400-only */
+/* TID entries (memory), HT-only */
#define INFINIPATH_RT_VALID 0x8000000000000000ULL
#define INFINIPATH_RT_ADDR_SHIFT 0
#define INFINIPATH_RT_BUFSIZE_MASK 0x3FFF
@@ -300,6 +316,17 @@
typedef u64 ipath_err_t;
+/* The following change with the type of device, so
+ * need to be part of the ipath_devdata struct, or
+ * we could have problems plugging in devices of
+ * different types (e.g. one HT, one PCIE)
+ * in one system, to be managed by one driver.
+ * On the other hand, this file is may also be included
+ * by other code, so leave the declarations here
+ * temporarily. Minor footprint issue if common-model
+ * linker used, none if C89+ linker used.
+ */
+
/* mask of defined bits for various registers */
extern u64 infinipath_i_bitsextant;
extern ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
@@ -308,13 +335,6 @@ extern ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
extern u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
/*
- * register bits for selecting i2c direction and values, used for I2C serial
- * flash
- */
-extern u16 ipath_gpio_sda_num, ipath_gpio_scl_num;
-extern u64 ipath_gpio_sda, ipath_gpio_scl;
-
-/*
* These are the infinipath general register numbers (not offsets).
* The kernel registers are used directly, those beyond the kernel
* registers are calculated from one of the base registers. The use of
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index d38f4f3cfd1..f7530512045 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -31,6 +32,7 @@
*/
#include "ipath_verbs.h"
+#include "ipath_kernel.h"
/*
* Convert the AETH RNR timeout code into the number of milliseconds.
@@ -104,6 +106,52 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
spin_unlock_irqrestore(&dev->pending_lock, flags);
}
+static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
+{
+ int user = to_ipd(qp->ibqp.pd)->user;
+ int i, j, ret;
+ struct ib_wc wc;
+
+ qp->r_len = 0;
+ for (i = j = 0; i < wqe->num_sge; i++) {
+ if (wqe->sg_list[i].length == 0)
+ continue;
+ /* Check LKEY */
+ if ((user && wqe->sg_list[i].lkey == 0) ||
+ !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
+ IB_ACCESS_LOCAL_WRITE))
+ goto bad_lkey;
+ qp->r_len += wqe->sg_list[i].length;
+ j++;
+ }
+ qp->r_sge.sge = qp->r_sg_list[0];
+ qp->r_sge.sg_list = qp->r_sg_list + 1;
+ qp->r_sge.num_sge = j;
+ ret = 1;
+ goto bail;
+
+bad_lkey:
+ wc.wr_id = wqe->wr_id;
+ wc.status = IB_WC_LOC_PROT_ERR;
+ wc.opcode = IB_WC_RECV;
+ wc.vendor_err = 0;
+ wc.byte_len = 0;
+ wc.imm_data = 0;
+ wc.qp_num = qp->ibqp.qp_num;
+ wc.src_qp = 0;
+ wc.wc_flags = 0;
+ wc.pkey_index = 0;
+ wc.slid = 0;
+ wc.sl = 0;
+ wc.dlid_path_bits = 0;
+ wc.port_num = 0;
+ /* Signal solicited completion event. */
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+ ret = 0;
+bail:
+ return ret;
+}
+
/**
* ipath_get_rwqe - copy the next RWQE into the QP's RWQE
* @qp: the QP
@@ -111,74 +159,77 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
*
* Return 0 if no RWQE is available, otherwise return 1.
*
- * Called at interrupt level with the QP r_rq.lock held.
+ * Can be called from interrupt level.
*/
int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
{
+ unsigned long flags;
struct ipath_rq *rq;
+ struct ipath_rwq *wq;
struct ipath_srq *srq;
struct ipath_rwqe *wqe;
+ void (*handler)(struct ib_event *, void *);
+ u32 tail;
int ret;
- if (!qp->ibqp.srq) {
+ if (qp->ibqp.srq) {
+ srq = to_isrq(qp->ibqp.srq);
+ handler = srq->ibsrq.event_handler;
+ rq = &srq->rq;
+ } else {
+ srq = NULL;
+ handler = NULL;
rq = &qp->r_rq;
- if (unlikely(rq->tail == rq->head)) {
+ }
+
+ spin_lock_irqsave(&rq->lock, flags);
+ wq = rq->wq;
+ tail = wq->tail;
+ /* Validate tail before using it since it is user writable. */
+ if (tail >= rq->size)
+ tail = 0;
+ do {
+ if (unlikely(tail == wq->head)) {
+ spin_unlock_irqrestore(&rq->lock, flags);
ret = 0;
goto bail;
}
- wqe = get_rwqe_ptr(rq, rq->tail);
- qp->r_wr_id = wqe->wr_id;
- if (!wr_id_only) {
- qp->r_sge.sge = wqe->sg_list[0];
- qp->r_sge.sg_list = wqe->sg_list + 1;
- qp->r_sge.num_sge = wqe->num_sge;
- qp->r_len = wqe->length;
- }
- if (++rq->tail >= rq->size)
- rq->tail = 0;
- ret = 1;
- goto bail;
- }
-
- srq = to_isrq(qp->ibqp.srq);
- rq = &srq->rq;
- spin_lock(&rq->lock);
- if (unlikely(rq->tail == rq->head)) {
- spin_unlock(&rq->lock);
- ret = 0;
- goto bail;
- }
- wqe = get_rwqe_ptr(rq, rq->tail);
+ wqe = get_rwqe_ptr(rq, tail);
+ if (++tail >= rq->size)
+ tail = 0;
+ } while (!wr_id_only && !init_sge(qp, wqe));
qp->r_wr_id = wqe->wr_id;
- if (!wr_id_only) {
- qp->r_sge.sge = wqe->sg_list[0];
- qp->r_sge.sg_list = wqe->sg_list + 1;
- qp->r_sge.num_sge = wqe->num_sge;
- qp->r_len = wqe->length;
- }
- if (++rq->tail >= rq->size)
- rq->tail = 0;
- if (srq->ibsrq.event_handler) {
- struct ib_event ev;
+ wq->tail = tail;
+
+ ret = 1;
+ if (handler) {
u32 n;
- if (rq->head < rq->tail)
- n = rq->size + rq->head - rq->tail;
+ /*
+ * validate head pointer value and compute
+ * the number of remaining WQEs.
+ */
+ n = wq->head;
+ if (n >= rq->size)
+ n = 0;
+ if (n < tail)
+ n += rq->size - tail;
else
- n = rq->head - rq->tail;
+ n -= tail;
if (n < srq->limit) {
+ struct ib_event ev;
+
srq->limit = 0;
- spin_unlock(&rq->lock);
+ spin_unlock_irqrestore(&rq->lock, flags);
ev.device = qp->ibqp.device;
ev.element.srq = qp->ibqp.srq;
ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
- srq->ibsrq.event_handler(&ev,
- srq->ibsrq.srq_context);
- } else
- spin_unlock(&rq->lock);
- } else
- spin_unlock(&rq->lock);
- ret = 1;
+ handler(&ev, srq->ibsrq.srq_context);
+ goto bail;
+ }
+ }
+ spin_unlock_irqrestore(&rq->lock, flags);
+ qp->r_wrid_valid = 1;
bail:
return ret;
@@ -187,7 +238,6 @@ bail:
/**
* ipath_ruc_loopback - handle UC and RC lookback requests
* @sqp: the loopback QP
- * @wc: the work completion entry
*
* This is called from ipath_do_uc_send() or ipath_do_rc_send() to
* forward a WQE addressed to the same HCA.
@@ -196,13 +246,14 @@ bail:
* receive interrupts since this is a connected protocol and all packets
* will pass through here.
*/
-void ipath_ruc_loopback(struct ipath_qp *sqp, struct ib_wc *wc)
+static void ipath_ruc_loopback(struct ipath_qp *sqp)
{
struct ipath_ibdev *dev = to_idev(sqp->ibqp.device);
struct ipath_qp *qp;
struct ipath_swqe *wqe;
struct ipath_sge *sge;
unsigned long flags;
+ struct ib_wc wc;
u64 sdata;
qp = ipath_lookup_qpn(&dev->qp_table, sqp->remote_qpn);
@@ -233,8 +284,8 @@ again:
wqe = get_swqe_ptr(sqp, sqp->s_last);
spin_unlock_irqrestore(&sqp->s_lock, flags);
- wc->wc_flags = 0;
- wc->imm_data = 0;
+ wc.wc_flags = 0;
+ wc.imm_data = 0;
sqp->s_sge.sge = wqe->sg_list[0];
sqp->s_sge.sg_list = wqe->sg_list + 1;
@@ -242,68 +293,63 @@ again:
sqp->s_len = wqe->length;
switch (wqe->wr.opcode) {
case IB_WR_SEND_WITH_IMM:
- wc->wc_flags = IB_WC_WITH_IMM;
- wc->imm_data = wqe->wr.imm_data;
+ wc.wc_flags = IB_WC_WITH_IMM;
+ wc.imm_data = wqe->wr.imm_data;
/* FALLTHROUGH */
case IB_WR_SEND:
- spin_lock_irqsave(&qp->r_rq.lock, flags);
if (!ipath_get_rwqe(qp, 0)) {
rnr_nak:
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
/* Handle RNR NAK */
if (qp->ibqp.qp_type == IB_QPT_UC)
goto send_comp;
if (sqp->s_rnr_retry == 0) {
- wc->status = IB_WC_RNR_RETRY_EXC_ERR;
+ wc.status = IB_WC_RNR_RETRY_EXC_ERR;
goto err;
}
if (sqp->s_rnr_retry_cnt < 7)
sqp->s_rnr_retry--;
dev->n_rnr_naks++;
sqp->s_rnr_timeout =
- ib_ipath_rnr_table[sqp->s_min_rnr_timer];
+ ib_ipath_rnr_table[sqp->r_min_rnr_timer];
ipath_insert_rnr_queue(sqp);
goto done;
}
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
break;
case IB_WR_RDMA_WRITE_WITH_IMM:
- wc->wc_flags = IB_WC_WITH_IMM;
- wc->imm_data = wqe->wr.imm_data;
- spin_lock_irqsave(&qp->r_rq.lock, flags);
+ wc.wc_flags = IB_WC_WITH_IMM;
+ wc.imm_data = wqe->wr.imm_data;
if (!ipath_get_rwqe(qp, 1))
goto rnr_nak;
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
/* FALLTHROUGH */
case IB_WR_RDMA_WRITE:
if (wqe->length == 0)
break;
- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, wqe->length,
+ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
IB_ACCESS_REMOTE_WRITE))) {
acc_err:
- wc->status = IB_WC_REM_ACCESS_ERR;
+ wc.status = IB_WC_REM_ACCESS_ERR;
err:
- wc->wr_id = wqe->wr.wr_id;
- wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc->vendor_err = 0;
- wc->byte_len = 0;
- wc->qp_num = sqp->ibqp.qp_num;
- wc->src_qp = sqp->remote_qpn;
- wc->pkey_index = 0;
- wc->slid = sqp->remote_ah_attr.dlid;
- wc->sl = sqp->remote_ah_attr.sl;
- wc->dlid_path_bits = 0;
- wc->port_num = 0;
- ipath_sqerror_qp(sqp, wc);
+ wc.wr_id = wqe->wr.wr_id;
+ wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
+ wc.vendor_err = 0;
+ wc.byte_len = 0;
+ wc.qp_num = sqp->ibqp.qp_num;
+ wc.src_qp = sqp->remote_qpn;
+ wc.pkey_index = 0;
+ wc.slid = sqp->remote_ah_attr.dlid;
+ wc.sl = sqp->remote_ah_attr.sl;
+ wc.dlid_path_bits = 0;
+ wc.port_num = 0;
+ ipath_sqerror_qp(sqp, &wc);
goto done;
}
break;
case IB_WR_RDMA_READ:
- if (unlikely(!ipath_rkey_ok(dev, &sqp->s_sge, wqe->length,
+ if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
IB_ACCESS_REMOTE_READ)))
@@ -318,7 +364,7 @@ again:
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, sizeof(u64),
+ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
IB_ACCESS_REMOTE_ATOMIC)))
@@ -373,22 +419,22 @@ again:
goto send_comp;
if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM)
- wc->opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
else
- wc->opcode = IB_WC_RECV;
- wc->wr_id = qp->r_wr_id;
- wc->status = IB_WC_SUCCESS;
- wc->vendor_err = 0;
- wc->byte_len = wqe->length;
- wc->qp_num = qp->ibqp.qp_num;
- wc->src_qp = qp->remote_qpn;
+ wc.opcode = IB_WC_RECV;
+ wc.wr_id = qp->r_wr_id;
+ wc.status = IB_WC_SUCCESS;
+ wc.vendor_err = 0;
+ wc.byte_len = wqe->length;
+ wc.qp_num = qp->ibqp.qp_num;
+ wc.src_qp = qp->remote_qpn;
/* XXX do we know which pkey matched? Only needed for GSI. */
- wc->pkey_index = 0;
- wc->slid = qp->remote_ah_attr.dlid;
- wc->sl = qp->remote_ah_attr.sl;
- wc->dlid_path_bits = 0;
+ wc.pkey_index = 0;
+ wc.slid = qp->remote_ah_attr.dlid;
+ wc.sl = qp->remote_ah_attr.sl;
+ wc.dlid_path_bits = 0;
/* Signal completion event if the solicited bit is set. */
- ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
wqe->wr.send_flags & IB_SEND_SOLICITED);
send_comp:
@@ -396,19 +442,19 @@ send_comp:
if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &sqp->s_flags) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- wc->wr_id = wqe->wr.wr_id;
- wc->status = IB_WC_SUCCESS;
- wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
- wc->vendor_err = 0;
- wc->byte_len = wqe->length;
- wc->qp_num = sqp->ibqp.qp_num;
- wc->src_qp = 0;
- wc->pkey_index = 0;
- wc->slid = 0;
- wc->sl = 0;
- wc->dlid_path_bits = 0;
- wc->port_num = 0;
- ipath_cq_enter(to_icq(sqp->ibqp.send_cq), wc, 0);
+ wc.wr_id = wqe->wr.wr_id;
+ wc.status = IB_WC_SUCCESS;
+ wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
+ wc.vendor_err = 0;
+ wc.byte_len = wqe->length;
+ wc.qp_num = sqp->ibqp.qp_num;
+ wc.src_qp = 0;
+ wc.pkey_index = 0;
+ wc.slid = 0;
+ wc.sl = 0;
+ wc.dlid_path_bits = 0;
+ wc.port_num = 0;
+ ipath_cq_enter(to_icq(sqp->ibqp.send_cq), &wc, 0);
}
/* Update s_last now that we are finished with the SWQE */
@@ -423,6 +469,15 @@ done:
wake_up(&qp->wait);
}
+static int want_buffer(struct ipath_devdata *dd)
+{
+ set_bit(IPATH_S_PIOINTBUFAVAIL, &dd->ipath_sendctrl);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ dd->ipath_sendctrl);
+
+ return 0;
+}
+
/**
* ipath_no_bufs_available - tell the layer driver we need buffers
* @qp: the QP that caused the problem
@@ -439,7 +494,7 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
list_add_tail(&qp->piowait, &dev->piowait);
spin_unlock_irqrestore(&dev->pending_lock, flags);
/*
- * Note that as soon as ipath_layer_want_buffer() is called and
+ * Note that as soon as want_buffer() is called and
* possibly before it returns, ipath_ib_piobufavail()
* could be called. If we are still in the tasklet function,
* tasklet_hi_schedule() will not call us until the next time
@@ -449,16 +504,16 @@ void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev)
*/
clear_bit(IPATH_S_BUSY, &qp->s_flags);
tasklet_unlock(&qp->s_task);
- ipath_layer_want_buffer(dev->dd);
+ want_buffer(dev->dd);
dev->n_piowait++;
}
/**
- * ipath_post_rc_send - post RC and UC sends
+ * ipath_post_ruc_send - post RC and UC sends
* @qp: the QP to post on
* @wr: the work request to send
*/
-int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
+int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
{
struct ipath_swqe *wqe;
unsigned long flags;
@@ -519,8 +574,7 @@ int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
}
if (wr->sg_list[i].length == 0)
continue;
- if (!ipath_lkey_ok(&to_idev(qp->ibqp.device)->lk_table,
- &wqe->sg_list[j], &wr->sg_list[i],
+ if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
acc)) {
spin_unlock_irqrestore(&qp->s_lock, flags);
ret = -EINVAL;
@@ -533,13 +587,148 @@ int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
qp->s_head = next;
spin_unlock_irqrestore(&qp->s_lock, flags);
- if (qp->ibqp.qp_type == IB_QPT_UC)
- ipath_do_uc_send((unsigned long) qp);
- else
- ipath_do_rc_send((unsigned long) qp);
+ ipath_do_ruc_send((unsigned long) qp);
ret = 0;
bail:
return ret;
}
+
+/**
+ * ipath_make_grh - construct a GRH header
+ * @dev: a pointer to the ipath device
+ * @hdr: a pointer to the GRH header being constructed
+ * @grh: the global route address to send to
+ * @hwords: the number of 32 bit words of header being sent
+ * @nwords: the number of 32 bit words of data being sent
+ *
+ * Return the size of the header in 32 bit words.
+ */
+u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
+ struct ib_global_route *grh, u32 hwords, u32 nwords)
+{
+ hdr->version_tclass_flow =
+ cpu_to_be32((6 << 28) |
+ (grh->traffic_class << 20) |
+ grh->flow_label);
+ hdr->paylen = cpu_to_be16((hwords - 2 + nwords + SIZE_OF_CRC) << 2);
+ /* next_hdr is defined by C8-7 in ch. 8.4.1 */
+ hdr->next_hdr = 0x1B;
+ hdr->hop_limit = grh->hop_limit;
+ /* The SGID is 32-bit aligned. */
+ hdr->sgid.global.subnet_prefix = dev->gid_prefix;
+ hdr->sgid.global.interface_id = dev->dd->ipath_guid;
+ hdr->dgid = grh->dgid;
+
+ /* GRH header size in 32-bit words. */
+ return sizeof(struct ib_grh) / sizeof(u32);
+}
+
+/**
+ * ipath_do_ruc_send - perform a send on an RC or UC QP
+ * @data: contains a pointer to the QP
+ *
+ * Process entries in the send work queue until credit or queue is
+ * exhausted. Only allow one CPU to send a packet per QP (tasklet).
+ * Otherwise, after we drop the QP s_lock, two threads could send
+ * packets out of order.
+ */
+void ipath_do_ruc_send(unsigned long data)
+{
+ struct ipath_qp *qp = (struct ipath_qp *)data;
+ struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
+ unsigned long flags;
+ u16 lrh0;
+ u32 nwords;
+ u32 extra_bytes;
+ u32 bth0;
+ u32 bth2;
+ u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
+ struct ipath_other_headers *ohdr;
+
+ if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags))
+ goto bail;
+
+ if (unlikely(qp->remote_ah_attr.dlid == dev->dd->ipath_lid)) {
+ ipath_ruc_loopback(qp);
+ goto clear;
+ }
+
+ ohdr = &qp->s_hdr.u.oth;
+ if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
+ ohdr = &qp->s_hdr.u.l.oth;
+
+again:
+ /* Check for a constructed packet to be sent. */
+ if (qp->s_hdrwords != 0) {
+ /*
+ * If no PIO bufs are available, return. An interrupt will
+ * call ipath_ib_piobufavail() when one is available.
+ */
+ if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
+ (u32 *) &qp->s_hdr, qp->s_cur_size,
+ qp->s_cur_sge)) {
+ ipath_no_bufs_available(qp, dev);
+ goto bail;
+ }
+ dev->n_unicast_xmit++;
+ /* Record that we sent the packet and s_hdr is empty. */
+ qp->s_hdrwords = 0;
+ }
+
+ /*
+ * The lock is needed to synchronize between setting
+ * qp->s_ack_state, resend timer, and post_send().
+ */
+ spin_lock_irqsave(&qp->s_lock, flags);
+
+ /* Sending responses has higher priority over sending requests. */
+ if (qp->s_ack_state != IB_OPCODE_RC_ACKNOWLEDGE &&
+ (bth0 = ipath_make_rc_ack(qp, ohdr, pmtu)) != 0)
+ bth2 = qp->s_ack_psn++ & IPATH_PSN_MASK;
+ else if (!((qp->ibqp.qp_type == IB_QPT_RC) ?
+ ipath_make_rc_req(qp, ohdr, pmtu, &bth0, &bth2) :
+ ipath_make_uc_req(qp, ohdr, pmtu, &bth0, &bth2))) {
+ /*
+ * Clear the busy bit before unlocking to avoid races with
+ * adding new work queue items and then failing to process
+ * them.
+ */
+ clear_bit(IPATH_S_BUSY, &qp->s_flags);
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+ goto bail;
+ }
+
+ spin_unlock_irqrestore(&qp->s_lock, flags);
+
+ /* Construct the header. */
+ extra_bytes = (4 - qp->s_cur_size) & 3;
+ nwords = (qp->s_cur_size + extra_bytes) >> 2;
+ lrh0 = IPATH_LRH_BTH;
+ if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
+ qp->s_hdrwords += ipath_make_grh(dev, &qp->s_hdr.u.l.grh,
+ &qp->remote_ah_attr.grh,
+ qp->s_hdrwords, nwords);
+ lrh0 = IPATH_LRH_GRH;
+ }
+ lrh0 |= qp->remote_ah_attr.sl << 4;
+ qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
+ qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
+ qp->s_hdr.lrh[2] = cpu_to_be16(qp->s_hdrwords + nwords +
+ SIZE_OF_CRC);
+ qp->s_hdr.lrh[3] = cpu_to_be16(dev->dd->ipath_lid);
+ bth0 |= ipath_get_pkey(dev->dd, qp->s_pkey_index);
+ bth0 |= extra_bytes << 20;
+ ohdr->bth[0] = cpu_to_be32(bth0);
+ ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
+ ohdr->bth[2] = cpu_to_be32(bth2);
+
+ /* Check for more work to do. */
+ goto again;
+
+clear:
+ clear_bit(IPATH_S_BUSY, &qp->s_flags);
+bail:
+ return;
+}
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
index 01c4c6c5611..94033503400 100644
--- a/drivers/infiniband/hw/ipath/ipath_srq.c
+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -47,66 +48,39 @@ int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
struct ib_recv_wr **bad_wr)
{
struct ipath_srq *srq = to_isrq(ibsrq);
- struct ipath_ibdev *dev = to_idev(ibsrq->device);
+ struct ipath_rwq *wq;
unsigned long flags;
int ret;
for (; wr; wr = wr->next) {
struct ipath_rwqe *wqe;
u32 next;
- int i, j;
+ int i;
- if (wr->num_sge > srq->rq.max_sge) {
+ if ((unsigned) wr->num_sge > srq->rq.max_sge) {
*bad_wr = wr;
ret = -ENOMEM;
goto bail;
}
spin_lock_irqsave(&srq->rq.lock, flags);
- next = srq->rq.head + 1;
+ wq = srq->rq.wq;
+ next = wq->head + 1;
if (next >= srq->rq.size)
next = 0;
- if (next == srq->rq.tail) {
+ if (next == wq->tail) {
spin_unlock_irqrestore(&srq->rq.lock, flags);
*bad_wr = wr;
ret = -ENOMEM;
goto bail;
}
- wqe = get_rwqe_ptr(&srq->rq, srq->rq.head);
+ wqe = get_rwqe_ptr(&srq->rq, wq->head);
wqe->wr_id = wr->wr_id;
- wqe->sg_list[0].mr = NULL;
- wqe->sg_list[0].vaddr = NULL;
- wqe->sg_list[0].length = 0;
- wqe->sg_list[0].sge_length = 0;
- wqe->length = 0;
- for (i = 0, j = 0; i < wr->num_sge; i++) {
- /* Check LKEY */
- if (to_ipd(srq->ibsrq.pd)->user &&
- wr->sg_list[i].lkey == 0) {
- spin_unlock_irqrestore(&srq->rq.lock,
- flags);
- *bad_wr = wr;
- ret = -EINVAL;
- goto bail;
- }
- if (wr->sg_list[i].length == 0)
- continue;
- if (!ipath_lkey_ok(&dev->lk_table,
- &wqe->sg_list[j],
- &wr->sg_list[i],
- IB_ACCESS_LOCAL_WRITE)) {
- spin_unlock_irqrestore(&srq->rq.lock,
- flags);
- *bad_wr = wr;
- ret = -EINVAL;
- goto bail;
- }
- wqe->length += wr->sg_list[i].length;
- j++;
- }
- wqe->num_sge = j;
- srq->rq.head = next;
+ wqe->num_sge = wr->num_sge;
+ for (i = 0; i < wr->num_sge; i++)
+ wqe->sg_list[i] = wr->sg_list[i];
+ wq->head = next;
spin_unlock_irqrestore(&srq->rq.lock, flags);
}
ret = 0;
@@ -125,46 +99,104 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
struct ib_srq_init_attr *srq_init_attr,
struct ib_udata *udata)
{
+ struct ipath_ibdev *dev = to_idev(ibpd->device);
struct ipath_srq *srq;
u32 sz;
struct ib_srq *ret;
- if (srq_init_attr->attr.max_sge < 1) {
+ if (srq_init_attr->attr.max_wr == 0) {
+ ret = ERR_PTR(-EINVAL);
+ goto done;
+ }
+
+ if ((srq_init_attr->attr.max_sge > ib_ipath_max_srq_sges) ||
+ (srq_init_attr->attr.max_wr > ib_ipath_max_srq_wrs)) {
ret = ERR_PTR(-EINVAL);
- goto bail;
+ goto done;
}
srq = kmalloc(sizeof(*srq), GFP_KERNEL);
if (!srq) {
ret = ERR_PTR(-ENOMEM);
- goto bail;
+ goto done;
}
/*
* Need to use vmalloc() if we want to support large #s of entries.
*/
srq->rq.size = srq_init_attr->attr.max_wr + 1;
- sz = sizeof(struct ipath_sge) * srq_init_attr->attr.max_sge +
+ srq->rq.max_sge = srq_init_attr->attr.max_sge;
+ sz = sizeof(struct ib_sge) * srq->rq.max_sge +
sizeof(struct ipath_rwqe);
- srq->rq.wq = vmalloc(srq->rq.size * sz);
+ srq->rq.wq = vmalloc_user(sizeof(struct ipath_rwq) + srq->rq.size * sz);
if (!srq->rq.wq) {
- kfree(srq);
ret = ERR_PTR(-ENOMEM);
- goto bail;
+ goto bail_srq;
}
/*
+ * Return the address of the RWQ as the offset to mmap.
+ * See ipath_mmap() for details.
+ */
+ if (udata && udata->outlen >= sizeof(__u64)) {
+ struct ipath_mmap_info *ip;
+ __u64 offset = (__u64) srq->rq.wq;
+ int err;
+
+ err = ib_copy_to_udata(udata, &offset, sizeof(offset));
+ if (err) {
+ ret = ERR_PTR(err);
+ goto bail_wq;
+ }
+
+ /* Allocate info for ipath_mmap(). */
+ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
+ if (!ip) {
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_wq;
+ }
+ srq->ip = ip;
+ ip->context = ibpd->uobject->context;
+ ip->obj = srq->rq.wq;
+ kref_init(&ip->ref);
+ ip->mmap_cnt = 0;
+ ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
+ srq->rq.size * sz);
+ spin_lock_irq(&dev->pending_lock);
+ ip->next = dev->pending_mmaps;
+ dev->pending_mmaps = ip;
+ spin_unlock_irq(&dev->pending_lock);
+ } else
+ srq->ip = NULL;
+
+ /*
* ib_create_srq() will initialize srq->ibsrq.
*/
spin_lock_init(&srq->rq.lock);
- srq->rq.head = 0;
- srq->rq.tail = 0;
- srq->rq.max_sge = srq_init_attr->attr.max_sge;
+ srq->rq.wq->head = 0;
+ srq->rq.wq->tail = 0;
srq->limit = srq_init_attr->attr.srq_limit;
+ spin_lock(&dev->n_srqs_lock);
+ if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
+ spin_unlock(&dev->n_srqs_lock);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_wq;
+ }
+
+ dev->n_srqs_allocated++;
+ spin_unlock(&dev->n_srqs_lock);
+
ret = &srq->ibsrq;
+ goto done;
-bail:
+bail_wq:
+ vfree(srq->rq.wq);
+
+bail_srq:
+ kfree(srq);
+
+done:
return ret;
}
@@ -173,76 +205,130 @@ bail:
* @ibsrq: the SRQ to modify
* @attr: the new attributes of the SRQ
* @attr_mask: indicates which attributes to modify
+ * @udata: user data for ipathverbs.so
*/
int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
- enum ib_srq_attr_mask attr_mask)
+ enum ib_srq_attr_mask attr_mask,
+ struct ib_udata *udata)
{
struct ipath_srq *srq = to_isrq(ibsrq);
- unsigned long flags;
- int ret;
+ int ret = 0;
- if (attr_mask & IB_SRQ_LIMIT) {
- spin_lock_irqsave(&srq->rq.lock, flags);
- srq->limit = attr->srq_limit;
- spin_unlock_irqrestore(&srq->rq.lock, flags);
- }
if (attr_mask & IB_SRQ_MAX_WR) {
- u32 size = attr->max_wr + 1;
- struct ipath_rwqe *wq, *p;
- u32 n;
- u32 sz;
+ struct ipath_rwq *owq;
+ struct ipath_rwq *wq;
+ struct ipath_rwqe *p;
+ u32 sz, size, n, head, tail;
- if (attr->max_sge < srq->rq.max_sge) {
+ /* Check that the requested sizes are below the limits. */
+ if ((attr->max_wr > ib_ipath_max_srq_wrs) ||
+ ((attr_mask & IB_SRQ_LIMIT) ?
+ attr->srq_limit : srq->limit) > attr->max_wr) {
ret = -EINVAL;
goto bail;
}
sz = sizeof(struct ipath_rwqe) +
- attr->max_sge * sizeof(struct ipath_sge);
- wq = vmalloc(size * sz);
+ srq->rq.max_sge * sizeof(struct ib_sge);
+ size = attr->max_wr + 1;
+ wq = vmalloc_user(sizeof(struct ipath_rwq) + size * sz);
if (!wq) {
ret = -ENOMEM;
goto bail;
}
- spin_lock_irqsave(&srq->rq.lock, flags);
- if (srq->rq.head < srq->rq.tail)
- n = srq->rq.size + srq->rq.head - srq->rq.tail;
+ /*
+ * Return the address of the RWQ as the offset to mmap.
+ * See ipath_mmap() for details.
+ */
+ if (udata && udata->inlen >= sizeof(__u64)) {
+ __u64 offset_addr;
+ __u64 offset = (__u64) wq;
+
+ ret = ib_copy_from_udata(&offset_addr, udata,
+ sizeof(offset_addr));
+ if (ret) {
+ vfree(wq);
+ goto bail;
+ }
+ udata->outbuf = (void __user *) offset_addr;
+ ret = ib_copy_to_udata(udata, &offset,
+ sizeof(offset));
+ if (ret) {
+ vfree(wq);
+ goto bail;
+ }
+ }
+
+ spin_lock_irq(&srq->rq.lock);
+ /*
+ * validate head pointer value and compute
+ * the number of remaining WQEs.
+ */
+ owq = srq->rq.wq;
+ head = owq->head;
+ if (head >= srq->rq.size)
+ head = 0;
+ tail = owq->tail;
+ if (tail >= srq->rq.size)
+ tail = 0;
+ n = head;
+ if (n < tail)
+ n += srq->rq.size - tail;
else
- n = srq->rq.head - srq->rq.tail;
- if (size <= n || size <= srq->limit) {
- spin_unlock_irqrestore(&srq->rq.lock, flags);
+ n -= tail;
+ if (size <= n) {
+ spin_unlock_irq(&srq->rq.lock);
vfree(wq);
ret = -EINVAL;
goto bail;
}
n = 0;
- p = wq;
- while (srq->rq.tail != srq->rq.head) {
+ p = wq->wq;
+ while (tail != head) {
struct ipath_rwqe *wqe;
int i;
- wqe = get_rwqe_ptr(&srq->rq, srq->rq.tail);
+ wqe = get_rwqe_ptr(&srq->rq, tail);
p->wr_id = wqe->wr_id;
- p->length = wqe->length;
p->num_sge = wqe->num_sge;
for (i = 0; i < wqe->num_sge; i++)
p->sg_list[i] = wqe->sg_list[i];
n++;
p = (struct ipath_rwqe *)((char *) p + sz);
- if (++srq->rq.tail >= srq->rq.size)
- srq->rq.tail = 0;
+ if (++tail >= srq->rq.size)
+ tail = 0;
}
- vfree(srq->rq.wq);
srq->rq.wq = wq;
srq->rq.size = size;
- srq->rq.head = n;
- srq->rq.tail = 0;
- srq->rq.max_sge = attr->max_sge;
- spin_unlock_irqrestore(&srq->rq.lock, flags);
- }
+ wq->head = n;
+ wq->tail = 0;
+ if (attr_mask & IB_SRQ_LIMIT)
+ srq->limit = attr->srq_limit;
+ spin_unlock_irq(&srq->rq.lock);
- ret = 0;
+ vfree(owq);
+
+ if (srq->ip) {
+ struct ipath_mmap_info *ip = srq->ip;
+ struct ipath_ibdev *dev = to_idev(srq->ibsrq.device);
+
+ ip->obj = wq;
+ ip->size = PAGE_ALIGN(sizeof(struct ipath_rwq) +
+ size * sz);
+ spin_lock_irq(&dev->pending_lock);
+ ip->next = dev->pending_mmaps;
+ dev->pending_mmaps = ip;
+ spin_unlock_irq(&dev->pending_lock);
+ }
+ } else if (attr_mask & IB_SRQ_LIMIT) {
+ spin_lock_irq(&srq->rq.lock);
+ if (attr->srq_limit >= srq->rq.size)
+ ret = -EINVAL;
+ else
+ srq->limit = attr->srq_limit;
+ spin_unlock_irq(&srq->rq.lock);
+ }
bail:
return ret;
@@ -265,8 +351,15 @@ int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr)
int ipath_destroy_srq(struct ib_srq *ibsrq)
{
struct ipath_srq *srq = to_isrq(ibsrq);
+ struct ipath_ibdev *dev = to_idev(ibsrq->device);
- vfree(srq->rq.wq);
+ spin_lock(&dev->n_srqs_lock);
+ dev->n_srqs_allocated--;
+ spin_unlock(&dev->n_srqs_lock);
+ if (srq->ip)
+ kref_put(&srq->ip->ref, ipath_release_mmap_info);
+ else
+ vfree(srq->rq.wq);
kfree(srq);
return 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/infiniband/hw/ipath/ipath_stats.c
index fe209137ee7..30a825928fc 100644
--- a/drivers/infiniband/hw/ipath/ipath_stats.c
+++ b/drivers/infiniband/hw/ipath/ipath_stats.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -185,7 +186,6 @@ static void ipath_qcheck(struct ipath_devdata *dd)
dd->ipath_port0head,
(unsigned long long)
ipath_stats.sps_port0pkts);
- ipath_kreceive(dd);
}
dd->ipath_lastport0rcv_cnt = ipath_stats.sps_port0pkts;
}
@@ -271,33 +271,6 @@ void ipath_get_faststats(unsigned long opaque)
}
}
- if (dd->ipath_nosma_bufs) {
- dd->ipath_nosma_secs += 5;
- if (dd->ipath_nosma_secs >= 30) {
- ipath_cdbg(SMA, "No SMA bufs avail %u seconds; "
- "cancelling pending sends\n",
- dd->ipath_nosma_secs);
- /*
- * issue an abort as well, in case we have a packet
- * stuck in launch fifo. This could corrupt an
- * outgoing user packet in the worst case,
- * but this is a pretty catastrophic, anyway.
- */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- INFINIPATH_S_ABORT);
- ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
- dd->ipath_piobcnt2k +
- dd->ipath_piobcnt4k -
- dd->ipath_lastport_piobuf);
- /* start again, if necessary */
- dd->ipath_nosma_secs = 0;
- } else
- ipath_cdbg(SMA, "No SMA bufs avail %u tries, "
- "after %u seconds\n",
- dd->ipath_nosma_bufs,
- dd->ipath_nosma_secs);
- }
-
done:
mod_timer(&dd->ipath_stats_timer, jiffies + HZ * 5);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index f323791cc49..182de34f9f4 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -34,8 +35,7 @@
#include <linux/pci.h>
#include "ipath_kernel.h"
-#include "ips_common.h"
-#include "ipath_layer.h"
+#include "ipath_common.h"
/**
* ipath_parse_ushort - parse an unsigned short value in an arbitrary base
@@ -75,7 +75,7 @@ bail:
static ssize_t show_version(struct device_driver *dev, char *buf)
{
/* The string printed here is already newline-terminated. */
- return scnprintf(buf, PAGE_SIZE, "%s", ipath_core_version);
+ return scnprintf(buf, PAGE_SIZE, "%s", ib_ipath_version);
}
static ssize_t show_num_units(struct device_driver *dev, char *buf)
@@ -84,99 +84,6 @@ static ssize_t show_num_units(struct device_driver *dev, char *buf)
ipath_count_units(NULL, NULL, NULL));
}
-#define DRIVER_STAT(name, attr) \
- static ssize_t show_stat_##name(struct device_driver *dev, \
- char *buf) \
- { \
- return scnprintf( \
- buf, PAGE_SIZE, "%llu\n", \
- (unsigned long long) ipath_stats.sps_ ##attr); \
- } \
- static DRIVER_ATTR(name, S_IRUGO, show_stat_##name, NULL)
-
-DRIVER_STAT(intrs, ints);
-DRIVER_STAT(err_intrs, errints);
-DRIVER_STAT(errs, errs);
-DRIVER_STAT(pkt_errs, pkterrs);
-DRIVER_STAT(crc_errs, crcerrs);
-DRIVER_STAT(hw_errs, hwerrs);
-DRIVER_STAT(ib_link, iblink);
-DRIVER_STAT(port0_pkts, port0pkts);
-DRIVER_STAT(ether_spkts, ether_spkts);
-DRIVER_STAT(ether_rpkts, ether_rpkts);
-DRIVER_STAT(sma_spkts, sma_spkts);
-DRIVER_STAT(sma_rpkts, sma_rpkts);
-DRIVER_STAT(hdrq_full, hdrqfull);
-DRIVER_STAT(etid_full, etidfull);
-DRIVER_STAT(no_piobufs, nopiobufs);
-DRIVER_STAT(ports, ports);
-DRIVER_STAT(pkey0, pkeys[0]);
-DRIVER_STAT(pkey1, pkeys[1]);
-DRIVER_STAT(pkey2, pkeys[2]);
-DRIVER_STAT(pkey3, pkeys[3]);
-/* XXX fix the following when dynamic table of devices used */
-DRIVER_STAT(lid0, lid[0]);
-DRIVER_STAT(lid1, lid[1]);
-DRIVER_STAT(lid2, lid[2]);
-DRIVER_STAT(lid3, lid[3]);
-
-DRIVER_STAT(nports, nports);
-DRIVER_STAT(null_intr, nullintr);
-DRIVER_STAT(max_pkts_call, maxpkts_call);
-DRIVER_STAT(avg_pkts_call, avgpkts_call);
-DRIVER_STAT(page_locks, pagelocks);
-DRIVER_STAT(page_unlocks, pageunlocks);
-DRIVER_STAT(krdrops, krdrops);
-/* XXX fix the following when dynamic table of devices used */
-DRIVER_STAT(mlid0, mlid[0]);
-DRIVER_STAT(mlid1, mlid[1]);
-DRIVER_STAT(mlid2, mlid[2]);
-DRIVER_STAT(mlid3, mlid[3]);
-
-static struct attribute *driver_stat_attributes[] = {
- &driver_attr_intrs.attr,
- &driver_attr_err_intrs.attr,
- &driver_attr_errs.attr,
- &driver_attr_pkt_errs.attr,
- &driver_attr_crc_errs.attr,
- &driver_attr_hw_errs.attr,
- &driver_attr_ib_link.attr,
- &driver_attr_port0_pkts.attr,
- &driver_attr_ether_spkts.attr,
- &driver_attr_ether_rpkts.attr,
- &driver_attr_sma_spkts.attr,
- &driver_attr_sma_rpkts.attr,
- &driver_attr_hdrq_full.attr,
- &driver_attr_etid_full.attr,
- &driver_attr_no_piobufs.attr,
- &driver_attr_ports.attr,
- &driver_attr_pkey0.attr,
- &driver_attr_pkey1.attr,
- &driver_attr_pkey2.attr,
- &driver_attr_pkey3.attr,
- &driver_attr_lid0.attr,
- &driver_attr_lid1.attr,
- &driver_attr_lid2.attr,
- &driver_attr_lid3.attr,
- &driver_attr_nports.attr,
- &driver_attr_null_intr.attr,
- &driver_attr_max_pkts_call.attr,
- &driver_attr_avg_pkts_call.attr,
- &driver_attr_page_locks.attr,
- &driver_attr_page_unlocks.attr,
- &driver_attr_krdrops.attr,
- &driver_attr_mlid0.attr,
- &driver_attr_mlid1.attr,
- &driver_attr_mlid2.attr,
- &driver_attr_mlid3.attr,
- NULL
-};
-
-static struct attribute_group driver_stat_attr_group = {
- .name = "stats",
- .attrs = driver_stat_attributes
-};
-
static ssize_t show_status(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -200,8 +107,8 @@ static const char *ipath_status_str[] = {
"Initted",
"Disabled",
"Admin_Disabled",
- "OIB_SMA",
- "SMA",
+ "", /* This used to be the old "OIB_SMA" status. */
+ "", /* This used to be the old "SMA" status. */
"Present",
"IB_link_up",
"IB_configured",
@@ -272,23 +179,23 @@ static ssize_t store_lid(struct device *dev,
size_t count)
{
struct ipath_devdata *dd = dev_get_drvdata(dev);
- u16 lid;
+ u16 lid = 0;
int ret;
ret = ipath_parse_ushort(buf, &lid);
if (ret < 0)
goto invalid;
- if (lid == 0 || lid >= 0xc000) {
+ if (lid == 0 || lid >= IPATH_MULTICAST_LID_BASE) {
ret = -EINVAL;
goto invalid;
}
- ipath_set_sps_lid(dd, lid, 0);
+ ipath_set_lid(dd, lid, 0);
goto bail;
invalid:
- ipath_dev_err(dd, "attempt to set invalid LID\n");
+ ipath_dev_err(dd, "attempt to set invalid LID 0x%x\n", lid);
bail:
return ret;
}
@@ -313,14 +220,12 @@ static ssize_t store_mlid(struct device *dev,
int ret;
ret = ipath_parse_ushort(buf, &mlid);
- if (ret < 0)
+ if (ret < 0 || mlid < IPATH_MULTICAST_LID_BASE)
goto invalid;
unit = dd->ipath_unit;
dd->ipath_mlid = mlid;
- ipath_stats.sps_mlid[unit] = mlid;
- ipath_layer_intr(dd, IPATH_LAYER_INT_BCAST);
goto bail;
invalid:
@@ -352,7 +257,7 @@ static ssize_t store_guid(struct device *dev,
struct ipath_devdata *dd = dev_get_drvdata(dev);
ssize_t ret;
unsigned short guid[8];
- __be64 nguid;
+ __be64 new_guid;
u8 *ng;
int i;
@@ -361,7 +266,7 @@ static ssize_t store_guid(struct device *dev,
&guid[4], &guid[5], &guid[6], &guid[7]) != 8)
goto invalid;
- ng = (u8 *) &nguid;
+ ng = (u8 *) &new_guid;
for (i = 0; i < 8; i++) {
if (guid[i] > 0xff)
@@ -369,7 +274,10 @@ static ssize_t store_guid(struct device *dev,
ng[i] = guid[i];
}
- dd->ipath_guid = nguid;
+ if (new_guid == 0)
+ goto invalid;
+
+ dd->ipath_guid = new_guid;
dd->ipath_nguid = 1;
ret = strlen(buf);
@@ -392,6 +300,16 @@ static ssize_t show_nguid(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid);
}
+static ssize_t show_nports(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+ /* Return the number of user ports available. */
+ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_cfgports - 1);
+}
+
static ssize_t show_serial(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -560,7 +478,7 @@ static ssize_t store_link_state(struct device *dev,
if (ret < 0)
goto invalid;
- r = ipath_layer_set_linkstate(dd, state);
+ r = ipath_set_linkstate(dd, state);
if (r < 0) {
ret = r;
goto bail;
@@ -595,7 +513,7 @@ static ssize_t store_mtu(struct device *dev,
if (ret < 0)
goto invalid;
- r = ipath_layer_set_mtu(dd, mtu);
+ r = ipath_set_mtu(dd, mtu);
if (r < 0)
ret = r;
@@ -656,6 +574,33 @@ bail:
return ret;
}
+static ssize_t store_rx_pol_inv(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+ int ret, r;
+ u16 val;
+
+ ret = ipath_parse_ushort(buf, &val);
+ if (ret < 0)
+ goto invalid;
+
+ r = ipath_set_rx_pol_inv(dd, val);
+ if (r < 0) {
+ ret = r;
+ goto bail;
+ }
+
+ goto bail;
+invalid:
+ ipath_dev_err(dd, "attempt to set invalid Rx Polarity invert\n");
+bail:
+ return ret;
+}
+
+
static DRIVER_ATTR(num_units, S_IRUGO, show_num_units, NULL);
static DRIVER_ATTR(version, S_IRUGO, show_version, NULL);
@@ -676,12 +621,14 @@ static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu);
static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled);
static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL);
+static DEVICE_ATTR(nports, S_IRUGO, show_nports, NULL);
static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset);
static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
static DEVICE_ATTR(status_str, S_IRUGO, show_status_str, NULL);
static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
static DEVICE_ATTR(unit, S_IRUGO, show_unit, NULL);
+static DEVICE_ATTR(rx_pol_inv, S_IWUSR, NULL, store_rx_pol_inv);
static struct attribute *dev_attributes[] = {
&dev_attr_guid.attr,
@@ -690,12 +637,14 @@ static struct attribute *dev_attributes[] = {
&dev_attr_mlid.attr,
&dev_attr_mtu.attr,
&dev_attr_nguid.attr,
+ &dev_attr_nports.attr,
&dev_attr_serial.attr,
&dev_attr_status.attr,
&dev_attr_status_str.attr,
&dev_attr_boardversion.attr,
&dev_attr_unit.attr,
&dev_attr_enabled.attr,
+ &dev_attr_rx_pol_inv.attr,
NULL
};
@@ -734,20 +683,12 @@ int ipath_driver_create_group(struct device_driver *drv)
int ret;
ret = sysfs_create_group(&drv->kobj, &driver_attr_group);
- if (ret)
- goto bail;
- ret = sysfs_create_group(&drv->kobj, &driver_stat_attr_group);
- if (ret)
- sysfs_remove_group(&drv->kobj, &driver_attr_group);
-
-bail:
return ret;
}
void ipath_driver_remove_group(struct device_driver *drv)
{
- sysfs_remove_group(&drv->kobj, &driver_stat_attr_group);
sysfs_remove_group(&drv->kobj, &driver_attr_group);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 0d6dbc0a541..e636cfd67a8 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -31,7 +32,7 @@
*/
#include "ipath_verbs.h"
-#include "ips_common.h"
+#include "ipath_kernel.h"
/* cut down ridiculously long IB macro names */
#define OP(x) IB_OPCODE_UC_##x
@@ -61,90 +62,40 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
}
/**
- * ipath_do_uc_send - do a send on a UC queue
- * @data: contains a pointer to the QP to send on
+ * ipath_make_uc_req - construct a request packet (SEND, RDMA write)
+ * @qp: a pointer to the QP
+ * @ohdr: a pointer to the IB header being constructed
+ * @pmtu: the path MTU
+ * @bth0p: pointer to the BTH opcode word
+ * @bth2p: pointer to the BTH PSN word
*
- * Process entries in the send work queue until the queue is exhausted.
- * Only allow one CPU to send a packet per QP (tasklet).
- * Otherwise, after we drop the QP lock, two threads could send
- * packets out of order.
- * This is similar to ipath_do_rc_send() below except we don't have
- * timeouts or resends.
+ * Return 1 if constructed; otherwise, return 0.
+ * Note the QP s_lock must be held and interrupts disabled.
*/
-void ipath_do_uc_send(unsigned long data)
+int ipath_make_uc_req(struct ipath_qp *qp,
+ struct ipath_other_headers *ohdr,
+ u32 pmtu, u32 *bth0p, u32 *bth2p)
{
- struct ipath_qp *qp = (struct ipath_qp *)data;
- struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_swqe *wqe;
- unsigned long flags;
- u16 lrh0;
u32 hwords;
- u32 nwords;
- u32 extra_bytes;
u32 bth0;
- u32 bth2;
- u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
u32 len;
- struct ipath_other_headers *ohdr;
struct ib_wc wc;
- if (test_and_set_bit(IPATH_S_BUSY, &qp->s_flags))
- goto bail;
-
- if (unlikely(qp->remote_ah_attr.dlid ==
- ipath_layer_get_lid(dev->dd))) {
- /* Pass in an uninitialized ib_wc to save stack space. */
- ipath_ruc_loopback(qp, &wc);
- clear_bit(IPATH_S_BUSY, &qp->s_flags);
- goto bail;
- }
-
- ohdr = &qp->s_hdr.u.oth;
- if (qp->remote_ah_attr.ah_flags & IB_AH_GRH)
- ohdr = &qp->s_hdr.u.l.oth;
-
-again:
- /* Check for a constructed packet to be sent. */
- if (qp->s_hdrwords != 0) {
- /*
- * If no PIO bufs are available, return.
- * An interrupt will call ipath_ib_piobufavail()
- * when one is available.
- */
- if (ipath_verbs_send(dev->dd, qp->s_hdrwords,
- (u32 *) &qp->s_hdr,
- qp->s_cur_size,
- qp->s_cur_sge)) {
- ipath_no_bufs_available(qp, dev);
- goto bail;
- }
- dev->n_unicast_xmit++;
- /* Record that we sent the packet and s_hdr is empty. */
- qp->s_hdrwords = 0;
- }
-
- lrh0 = IPS_LRH_BTH;
- /* header size in 32-bit words LRH+BTH = (8+12)/4. */
- hwords = 5;
-
- /*
- * The lock is needed to synchronize between
- * setting qp->s_ack_state and post_send().
- */
- spin_lock_irqsave(&qp->s_lock, flags);
-
if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_SEND_OK))
goto done;
- bth0 = ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
+ /* header size in 32-bit words LRH+BTH = (8+12)/4. */
+ hwords = 5;
+ bth0 = 0;
- /* Send a request. */
+ /* Get the next send request. */
wqe = get_swqe_ptr(qp, qp->s_last);
switch (qp->s_state) {
default:
/*
- * Signal the completion of the last send (if there is
- * one).
+ * Signal the completion of the last send
+ * (if there is one).
*/
if (qp->s_last != qp->s_tail)
complete_last_send(qp, wqe, &wc);
@@ -257,61 +208,16 @@ again:
}
break;
}
- bth2 = qp->s_next_psn++ & IPS_PSN_MASK;
qp->s_len -= len;
- bth0 |= qp->s_state << 24;
-
- spin_unlock_irqrestore(&qp->s_lock, flags);
-
- /* Construct the header. */
- extra_bytes = (4 - len) & 3;
- nwords = (len + extra_bytes) >> 2;
- if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) {
- /* Header size in 32-bit words. */
- hwords += 10;
- lrh0 = IPS_LRH_GRH;
- qp->s_hdr.u.l.grh.version_tclass_flow =
- cpu_to_be32((6 << 28) |
- (qp->remote_ah_attr.grh.traffic_class
- << 20) |
- qp->remote_ah_attr.grh.flow_label);
- qp->s_hdr.u.l.grh.paylen =
- cpu_to_be16(((hwords - 12) + nwords +
- SIZE_OF_CRC) << 2);
- /* next_hdr is defined by C8-7 in ch. 8.4.1 */
- qp->s_hdr.u.l.grh.next_hdr = 0x1B;
- qp->s_hdr.u.l.grh.hop_limit =
- qp->remote_ah_attr.grh.hop_limit;
- /* The SGID is 32-bit aligned. */
- qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
- dev->gid_prefix;
- qp->s_hdr.u.l.grh.sgid.global.interface_id =
- ipath_layer_get_guid(dev->dd);
- qp->s_hdr.u.l.grh.dgid = qp->remote_ah_attr.grh.dgid;
- }
qp->s_hdrwords = hwords;
qp->s_cur_sge = &qp->s_sge;
qp->s_cur_size = len;
- lrh0 |= qp->remote_ah_attr.sl << 4;
- qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
- /* DEST LID */
- qp->s_hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid);
- qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
- qp->s_hdr.lrh[3] = cpu_to_be16(ipath_layer_get_lid(dev->dd));
- bth0 |= extra_bytes << 20;
- ohdr->bth[0] = cpu_to_be32(bth0);
- ohdr->bth[1] = cpu_to_be32(qp->remote_qpn);
- ohdr->bth[2] = cpu_to_be32(bth2);
-
- /* Check for more work to do. */
- goto again;
+ *bth0p = bth0 | (qp->s_state << 24);
+ *bth2p = qp->s_next_psn++ & IPATH_PSN_MASK;
+ return 1;
done:
- spin_unlock_irqrestore(&qp->s_lock, flags);
- clear_bit(IPATH_S_BUSY, &qp->s_flags);
-
-bail:
- return;
+ return 0;
}
/**
@@ -335,12 +241,15 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
u32 hdrsize;
u32 psn;
u32 pad;
- unsigned long flags;
struct ib_wc wc;
u32 pmtu = ib_mtu_enum_to_int(qp->path_mtu);
struct ib_reth *reth;
int header_in_data;
+ /* Validate the SLID. See Ch. 9.6.1.5 */
+ if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
+ goto done;
+
/* Check for GRH */
if (!has_grh) {
ohdr = &hdr->u.oth;
@@ -356,8 +265,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* size to 56 bytes so the last 4 bytes of
* the BTH header (PSN) is in the data buffer.
*/
- header_in_data =
- ipath_layer_get_rcvhdrentsize(dev->dd) == 16;
+ header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
if (header_in_data) {
psn = be32_to_cpu(((__be32 *) data)[0]);
data += sizeof(__be32);
@@ -373,8 +281,6 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
wc.imm_data = 0;
wc.wc_flags = 0;
- spin_lock_irqsave(&qp->r_rq.lock, flags);
-
/* Compare the PSN verses the expected PSN. */
if (unlikely(ipath_cmp24(psn, qp->r_psn) != 0)) {
/*
@@ -535,12 +441,13 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
if (qp->r_len != 0) {
u32 rkey = be32_to_cpu(reth->rkey);
u64 vaddr = be64_to_cpu(reth->vaddr);
+ int ok;
/* Check rkey */
- if (unlikely(!ipath_rkey_ok(
- dev, &qp->r_sge, qp->r_len,
- vaddr, rkey,
- IB_ACCESS_REMOTE_WRITE))) {
+ ok = ipath_rkey_ok(qp, &qp->r_sge, qp->r_len,
+ vaddr, rkey,
+ IB_ACCESS_REMOTE_WRITE);
+ if (unlikely(!ok)) {
dev->n_pkt_drops++;
goto done;
}
@@ -558,8 +465,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
}
if (opcode == OP(RDMA_WRITE_ONLY))
goto rdma_last;
- else if (opcode ==
- OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+ else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
goto rdma_last_imm;
/* FALLTHROUGH */
case OP(RDMA_WRITE_MIDDLE):
@@ -592,9 +498,9 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
dev->n_pkt_drops++;
goto done;
}
- if (qp->r_reuse_sge) {
+ if (qp->r_reuse_sge)
qp->r_reuse_sge = 0;
- } else if (!ipath_get_rwqe(qp, 1)) {
+ else if (!ipath_get_rwqe(qp, 1)) {
dev->n_pkt_drops++;
goto done;
}
@@ -631,15 +537,11 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
default:
/* Drop packet for unknown opcodes. */
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
dev->n_pkt_drops++;
- goto bail;
+ goto done;
}
qp->r_psn++;
qp->r_state = opcode;
done:
- spin_unlock_irqrestore(&qp->r_rq.lock, flags);
-
-bail:
return;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index e606daf8321..49f1102af8b 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -33,7 +34,52 @@
#include <rdma/ib_smi.h>
#include "ipath_verbs.h"
-#include "ips_common.h"
+#include "ipath_kernel.h"
+
+static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
+ u32 *lengthp, struct ipath_sge_state *ss)
+{
+ int user = to_ipd(qp->ibqp.pd)->user;
+ int i, j, ret;
+ struct ib_wc wc;
+
+ *lengthp = 0;
+ for (i = j = 0; i < wqe->num_sge; i++) {
+ if (wqe->sg_list[i].length == 0)
+ continue;
+ /* Check LKEY */
+ if ((user && wqe->sg_list[i].lkey == 0) ||
+ !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
+ &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
+ goto bad_lkey;
+ *lengthp += wqe->sg_list[i].length;
+ j++;
+ }
+ ss->num_sge = j;
+ ret = 1;
+ goto bail;
+
+bad_lkey:
+ wc.wr_id = wqe->wr_id;
+ wc.status = IB_WC_LOC_PROT_ERR;
+ wc.opcode = IB_WC_RECV;
+ wc.vendor_err = 0;
+ wc.byte_len = 0;
+ wc.imm_data = 0;
+ wc.qp_num = qp->ibqp.qp_num;
+ wc.src_qp = 0;
+ wc.wc_flags = 0;
+ wc.pkey_index = 0;
+ wc.slid = 0;
+ wc.sl = 0;
+ wc.dlid_path_bits = 0;
+ wc.port_num = 0;
+ /* Signal solicited completion event. */
+ ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1);
+ ret = 0;
+bail:
+ return ret;
+}
/**
* ipath_ud_loopback - handle send on loopback QPs
@@ -45,6 +91,8 @@
*
* This is called from ipath_post_ud_send() to forward a WQE addressed
* to the same HCA.
+ * Note that the receive interrupt handler may be calling ipath_ud_rcv()
+ * while this is being called.
*/
static void ipath_ud_loopback(struct ipath_qp *sqp,
struct ipath_sge_state *ss,
@@ -59,7 +107,11 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
struct ipath_srq *srq;
struct ipath_sge_state rsge;
struct ipath_sge *sge;
+ struct ipath_rwq *wq;
struct ipath_rwqe *wqe;
+ void (*handler)(struct ib_event *, void *);
+ u32 tail;
+ u32 rlen;
qp = ipath_lookup_qpn(&dev->qp_table, wr->wr.ud.remote_qpn);
if (!qp)
@@ -93,6 +145,13 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
wc->imm_data = 0;
}
+ if (wr->num_sge > 1) {
+ rsge.sg_list = kmalloc((wr->num_sge - 1) *
+ sizeof(struct ipath_sge),
+ GFP_ATOMIC);
+ } else
+ rsge.sg_list = NULL;
+
/*
* Get the next work request entry to find where to put the data.
* Note that it is safe to drop the lock after changing rq->tail
@@ -100,37 +159,52 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
*/
if (qp->ibqp.srq) {
srq = to_isrq(qp->ibqp.srq);
+ handler = srq->ibsrq.event_handler;
rq = &srq->rq;
} else {
srq = NULL;
+ handler = NULL;
rq = &qp->r_rq;
}
+
spin_lock_irqsave(&rq->lock, flags);
- if (rq->tail == rq->head) {
- spin_unlock_irqrestore(&rq->lock, flags);
- dev->n_pkt_drops++;
- goto done;
+ wq = rq->wq;
+ tail = wq->tail;
+ while (1) {
+ if (unlikely(tail == wq->head)) {
+ spin_unlock_irqrestore(&rq->lock, flags);
+ dev->n_pkt_drops++;
+ goto bail_sge;
+ }
+ wqe = get_rwqe_ptr(rq, tail);
+ if (++tail >= rq->size)
+ tail = 0;
+ if (init_sge(qp, wqe, &rlen, &rsge))
+ break;
+ wq->tail = tail;
}
/* Silently drop packets which are too big. */
- wqe = get_rwqe_ptr(rq, rq->tail);
- if (wc->byte_len > wqe->length) {
+ if (wc->byte_len > rlen) {
spin_unlock_irqrestore(&rq->lock, flags);
dev->n_pkt_drops++;
- goto done;
+ goto bail_sge;
}
+ wq->tail = tail;
wc->wr_id = wqe->wr_id;
- rsge.sge = wqe->sg_list[0];
- rsge.sg_list = wqe->sg_list + 1;
- rsge.num_sge = wqe->num_sge;
- if (++rq->tail >= rq->size)
- rq->tail = 0;
- if (srq && srq->ibsrq.event_handler) {
+ if (handler) {
u32 n;
- if (rq->head < rq->tail)
- n = rq->size + rq->head - rq->tail;
+ /*
+ * validate head pointer value and compute
+ * the number of remaining WQEs.
+ */
+ n = wq->head;
+ if (n >= rq->size)
+ n = 0;
+ if (n < tail)
+ n += rq->size - tail;
else
- n = rq->head - rq->tail;
+ n -= tail;
if (n < srq->limit) {
struct ib_event ev;
@@ -139,12 +213,12 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
ev.device = qp->ibqp.device;
ev.element.srq = qp->ibqp.srq;
ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
- srq->ibsrq.event_handler(&ev,
- srq->ibsrq.srq_context);
+ handler(&ev, srq->ibsrq.srq_context);
} else
spin_unlock_irqrestore(&rq->lock, flags);
} else
spin_unlock_irqrestore(&rq->lock, flags);
+
ah_attr = &to_iah(wr->wr.ud.ah)->attr;
if (ah_attr->ah_flags & IB_AH_GRH) {
ipath_copy_sge(&rsge, &ah_attr->grh, sizeof(struct ib_grh));
@@ -185,7 +259,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
wc->src_qp = sqp->ibqp.qp_num;
/* XXX do we know which pkey matched? Only needed for GSI. */
wc->pkey_index = 0;
- wc->slid = ipath_layer_get_lid(dev->dd) |
+ wc->slid = dev->dd->ipath_lid |
(ah_attr->src_path_bits &
((1 << (dev->mkeyprot_resv_lmc & 7)) - 1));
wc->sl = ah_attr->sl;
@@ -195,6 +269,8 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), wc,
wr->send_flags & IB_SEND_SOLICITED);
+bail_sge:
+ kfree(rsge.sg_list);
done:
if (atomic_dec_and_test(&qp->refcount))
wake_up(&qp->wait);
@@ -265,7 +341,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
if (wr->sg_list[i].length == 0)
continue;
- if (!ipath_lkey_ok(&dev->lk_table, ss.num_sge ?
+ if (!ipath_lkey_ok(qp, ss.num_sge ?
sg_list + ss.num_sge - 1 : &ss.sge,
&wr->sg_list[i], 0)) {
ret = -EINVAL;
@@ -274,6 +350,11 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
len += wr->sg_list[i].length;
ss.num_sge++;
}
+ /* Check for invalid packet size. */
+ if (len > dev->dd->ipath_ibmtu) {
+ ret = -EINVAL;
+ goto bail;
+ }
extra_bytes = (4 - len) & 3;
nwords = (len + extra_bytes) >> 2;
@@ -283,8 +364,8 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
ret = -EINVAL;
goto bail;
}
- if (ah_attr->dlid >= IPS_MULTICAST_LID_BASE) {
- if (ah_attr->dlid != IPS_PERMISSIVE_LID)
+ if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE) {
+ if (ah_attr->dlid != IPATH_PERMISSIVE_LID)
dev->n_multicast_xmit++;
else
dev->n_unicast_xmit++;
@@ -292,7 +373,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
dev->n_unicast_xmit++;
lid = ah_attr->dlid &
~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
- if (unlikely(lid == ipath_layer_get_lid(dev->dd))) {
+ if (unlikely(lid == dev->dd->ipath_lid)) {
/*
* Pass in an uninitialized ib_wc to save stack
* space.
@@ -304,7 +385,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
if (ah_attr->ah_flags & IB_AH_GRH) {
/* Header size in 32-bit words. */
hwords = 17;
- lrh0 = IPS_LRH_GRH;
+ lrh0 = IPATH_LRH_GRH;
ohdr = &qp->s_hdr.u.l.oth;
qp->s_hdr.u.l.grh.version_tclass_flow =
cpu_to_be32((6 << 28) |
@@ -321,7 +402,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
qp->s_hdr.u.l.grh.sgid.global.subnet_prefix =
dev->gid_prefix;
qp->s_hdr.u.l.grh.sgid.global.interface_id =
- ipath_layer_get_guid(dev->dd);
+ dev->dd->ipath_guid;
qp->s_hdr.u.l.grh.dgid = ah_attr->grh.dgid;
/*
* Don't worry about sending to locally attached multicast
@@ -330,7 +411,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
} else {
/* Header size in 32-bit words. */
hwords = 7;
- lrh0 = IPS_LRH_BTH;
+ lrh0 = IPATH_LRH_BTH;
ohdr = &qp->s_hdr.u.oth;
}
if (wr->opcode == IB_WR_SEND_WITH_IMM) {
@@ -351,7 +432,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
qp->s_hdr.lrh[0] = cpu_to_be16(lrh0);
qp->s_hdr.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */
qp->s_hdr.lrh[2] = cpu_to_be16(hwords + nwords + SIZE_OF_CRC);
- lid = ipath_layer_get_lid(dev->dd);
+ lid = dev->dd->ipath_lid;
if (lid) {
lid |= ah_attr->src_path_bits &
((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
@@ -361,18 +442,18 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
if (wr->send_flags & IB_SEND_SOLICITED)
bth0 |= 1 << 23;
bth0 |= extra_bytes << 20;
- bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPS_DEFAULT_P_KEY :
- ipath_layer_get_pkey(dev->dd, qp->s_pkey_index);
+ bth0 |= qp->ibqp.qp_type == IB_QPT_SMI ? IPATH_DEFAULT_P_KEY :
+ ipath_get_pkey(dev->dd, qp->s_pkey_index);
ohdr->bth[0] = cpu_to_be32(bth0);
/*
* Use the multicast QP if the destination LID is a multicast LID.
*/
- ohdr->bth[1] = ah_attr->dlid >= IPS_MULTICAST_LID_BASE &&
- ah_attr->dlid != IPS_PERMISSIVE_LID ?
- __constant_cpu_to_be32(IPS_MULTICAST_QPN) :
+ ohdr->bth[1] = ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
+ ah_attr->dlid != IPATH_PERMISSIVE_LID ?
+ __constant_cpu_to_be32(IPATH_MULTICAST_QPN) :
cpu_to_be32(wr->wr.ud.remote_qpn);
/* XXX Could lose a PSN count but not worth locking */
- ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPS_PSN_MASK);
+ ohdr->bth[2] = cpu_to_be32(qp->s_next_psn++ & IPATH_PSN_MASK);
/*
* Qkeys with the high order bit set mean use the
* qkey from the QP context instead of the WR (see 10.2.5).
@@ -427,13 +508,9 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int opcode;
u32 hdrsize;
u32 pad;
- unsigned long flags;
struct ib_wc wc;
u32 qkey;
u32 src_qp;
- struct ipath_rq *rq;
- struct ipath_srq *srq;
- struct ipath_rwqe *wqe;
u16 dlid;
int header_in_data;
@@ -452,8 +529,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
* the eager header buffer size to 56 bytes so the last 12
* bytes of the IB header is in the data buffer.
*/
- header_in_data =
- ipath_layer_get_rcvhdrentsize(dev->dd) == 16;
+ header_in_data = dev->dd->ipath_rcvhdrentsize == 16;
if (header_in_data) {
qkey = be32_to_cpu(((__be32 *) data)[1]);
src_qp = be32_to_cpu(((__be32 *) data)[2]);
@@ -463,7 +539,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
src_qp = be32_to_cpu(ohdr->u.ud.deth[1]);
}
}
- src_qp &= IPS_QPN_MASK;
+ src_qp &= IPATH_QPN_MASK;
/*
* Check that the permissive LID is only used on QP0
@@ -541,56 +617,28 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
/*
* Get the next work request entry to find where to put the data.
- * Note that it is safe to drop the lock after changing rq->tail
- * since ipath_post_receive() won't fill the empty slot.
*/
- if (qp->ibqp.srq) {
- srq = to_isrq(qp->ibqp.srq);
- rq = &srq->rq;
- } else {
- srq = NULL;
- rq = &qp->r_rq;
- }
- spin_lock_irqsave(&rq->lock, flags);
- if (rq->tail == rq->head) {
- spin_unlock_irqrestore(&rq->lock, flags);
- dev->n_pkt_drops++;
+ if (qp->r_reuse_sge)
+ qp->r_reuse_sge = 0;
+ else if (!ipath_get_rwqe(qp, 0)) {
+ /*
+ * Count VL15 packets dropped due to no receive buffer.
+ * Otherwise, count them as buffer overruns since usually,
+ * the HW will be able to receive packets even if there are
+ * no QPs with posted receive buffers.
+ */
+ if (qp->ibqp.qp_num == 0)
+ dev->n_vl15_dropped++;
+ else
+ dev->rcv_errors++;
goto bail;
}
/* Silently drop packets which are too big. */
- wqe = get_rwqe_ptr(rq, rq->tail);
- if (wc.byte_len > wqe->length) {
- spin_unlock_irqrestore(&rq->lock, flags);
+ if (wc.byte_len > qp->r_len) {
+ qp->r_reuse_sge = 1;
dev->n_pkt_drops++;
goto bail;
}
- wc.wr_id = wqe->wr_id;
- qp->r_sge.sge = wqe->sg_list[0];
- qp->r_sge.sg_list = wqe->sg_list + 1;
- qp->r_sge.num_sge = wqe->num_sge;
- if (++rq->tail >= rq->size)
- rq->tail = 0;
- if (srq && srq->ibsrq.event_handler) {
- u32 n;
-
- if (rq->head < rq->tail)
- n = rq->size + rq->head - rq->tail;
- else
- n = rq->head - rq->tail;
- if (n < srq->limit) {
- struct ib_event ev;
-
- srq->limit = 0;
- spin_unlock_irqrestore(&rq->lock, flags);
- ev.device = qp->ibqp.device;
- ev.element.srq = qp->ibqp.srq;
- ev.event = IB_EVENT_SRQ_LIMIT_REACHED;
- srq->ibsrq.event_handler(&ev,
- srq->ibsrq.srq_context);
- } else
- spin_unlock_irqrestore(&rq->lock, flags);
- } else
- spin_unlock_irqrestore(&rq->lock, flags);
if (has_grh) {
ipath_copy_sge(&qp->r_sge, &hdr->u.l.grh,
sizeof(struct ib_grh));
@@ -599,6 +647,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
ipath_skip_sge(&qp->r_sge, sizeof(struct ib_grh));
ipath_copy_sge(&qp->r_sge, data,
wc.byte_len - sizeof(struct ib_grh));
+ wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
@@ -612,7 +661,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
/*
* Save the LMC lower bits if the destination LID is a unicast LID.
*/
- wc.dlid_path_bits = dlid >= IPS_MULTICAST_LID_BASE ? 0 :
+ wc.dlid_path_bits = dlid >= IPATH_MULTICAST_LID_BASE ? 0 :
dlid & ((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
/* Signal completion event if the solicited bit is set. */
ipath_cq_enter(to_icq(qp->ibqp.recv_cq), &wc,
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 2bb08afc86d..413754b1d8a 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -57,17 +58,6 @@ static int __get_user_pages(unsigned long start_page, size_t num_pages,
size_t got;
int ret;
-#if 0
- /*
- * XXX - causes MPI programs to fail, haven't had time to check
- * yet
- */
- if (!capable(CAP_IPC_LOCK)) {
- ret = -EPERM;
- goto bail;
- }
-#endif
-
lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >>
PAGE_SHIFT;
@@ -100,6 +90,62 @@ bail:
}
/**
+ * ipath_map_page - a safety wrapper around pci_map_page()
+ *
+ * A dma_addr of all 0's is interpreted by the chip as "disabled".
+ * Unfortunately, it can also be a valid dma_addr returned on some
+ * architectures.
+ *
+ * The powerpc iommu assigns dma_addrs in ascending order, so we don't
+ * have to bother with retries or mapping a dummy page to insure we
+ * don't just get the same mapping again.
+ *
+ * I'm sure we won't be so lucky with other iommu's, so FIXME.
+ */
+dma_addr_t ipath_map_page(struct pci_dev *hwdev, struct page *page,
+ unsigned long offset, size_t size, int direction)
+{
+ dma_addr_t phys;
+
+ phys = pci_map_page(hwdev, page, offset, size, direction);
+
+ if (phys == 0) {
+ pci_unmap_page(hwdev, phys, size, direction);
+ phys = pci_map_page(hwdev, page, offset, size, direction);
+ /*
+ * FIXME: If we get 0 again, we should keep this page,
+ * map another, then free the 0 page.
+ */
+ }
+
+ return phys;
+}
+
+/**
+ * ipath_map_single - a safety wrapper around pci_map_single()
+ *
+ * Same idea as ipath_map_page().
+ */
+dma_addr_t ipath_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
+ int direction)
+{
+ dma_addr_t phys;
+
+ phys = pci_map_single(hwdev, ptr, size, direction);
+
+ if (phys == 0) {
+ pci_unmap_single(hwdev, phys, size, direction);
+ phys = pci_map_single(hwdev, ptr, size, direction);
+ /*
+ * FIXME: If we get 0 again, we should keep this page,
+ * map another, then free the 0 page.
+ */
+ }
+
+ return phys;
+}
+
+/**
* ipath_get_user_pages - lock user pages into memory
* @start_page: the start page
* @num_pages: the number of pages
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index 28fdbdaa789..42eaed88c28 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -32,14 +33,12 @@
#include <rdma/ib_mad.h>
#include <rdma/ib_user_verbs.h>
+#include <linux/io.h>
#include <linux/utsname.h>
#include "ipath_kernel.h"
#include "ipath_verbs.h"
-#include "ips_common.h"
-
-/* Not static, because we don't want the compiler removing it */
-const char ipath_verbs_version[] = "ipath_verbs " IPATH_IDSTR;
+#include "ipath_common.h"
static unsigned int ib_ipath_qp_table_size = 251;
module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO);
@@ -51,13 +50,66 @@ module_param_named(lkey_table_size, ib_ipath_lkey_table_size, uint,
MODULE_PARM_DESC(lkey_table_size,
"LKEY table size in bits (2^n, 1 <= n <= 23)");
-unsigned int ib_ipath_debug; /* debug mask */
-module_param_named(debug, ib_ipath_debug, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(debug, "Verbs debug mask");
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("PathScale <support@pathscale.com>");
-MODULE_DESCRIPTION("Pathscale InfiniPath driver");
+static unsigned int ib_ipath_max_pds = 0xFFFF;
+module_param_named(max_pds, ib_ipath_max_pds, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_pds,
+ "Maximum number of protection domains to support");
+
+static unsigned int ib_ipath_max_ahs = 0xFFFF;
+module_param_named(max_ahs, ib_ipath_max_ahs, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_ahs, "Maximum number of address handles to support");
+
+unsigned int ib_ipath_max_cqes = 0x2FFFF;
+module_param_named(max_cqes, ib_ipath_max_cqes, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_cqes,
+ "Maximum number of completion queue entries to support");
+
+unsigned int ib_ipath_max_cqs = 0x1FFFF;
+module_param_named(max_cqs, ib_ipath_max_cqs, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_cqs, "Maximum number of completion queues to support");
+
+unsigned int ib_ipath_max_qp_wrs = 0x3FFF;
+module_param_named(max_qp_wrs, ib_ipath_max_qp_wrs, uint,
+ S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support");
+
+unsigned int ib_ipath_max_qps = 16384;
+module_param_named(max_qps, ib_ipath_max_qps, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support");
+
+unsigned int ib_ipath_max_sges = 0x60;
+module_param_named(max_sges, ib_ipath_max_sges, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support");
+
+unsigned int ib_ipath_max_mcast_grps = 16384;
+module_param_named(max_mcast_grps, ib_ipath_max_mcast_grps, uint,
+ S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_mcast_grps,
+ "Maximum number of multicast groups to support");
+
+unsigned int ib_ipath_max_mcast_qp_attached = 16;
+module_param_named(max_mcast_qp_attached, ib_ipath_max_mcast_qp_attached,
+ uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_mcast_qp_attached,
+ "Maximum number of attached QPs to support");
+
+unsigned int ib_ipath_max_srqs = 1024;
+module_param_named(max_srqs, ib_ipath_max_srqs, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_srqs, "Maximum number of SRQs to support");
+
+unsigned int ib_ipath_max_srq_sges = 128;
+module_param_named(max_srq_sges, ib_ipath_max_srq_sges,
+ uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_srq_sges, "Maximum number of SRQ SGEs to support");
+
+unsigned int ib_ipath_max_srq_wrs = 0x1FFFF;
+module_param_named(max_srq_wrs, ib_ipath_max_srq_wrs,
+ uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support");
+
+static unsigned int ib_ipath_disable_sma;
+module_param_named(disable_sma, ib_ipath_disable_sma, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(ib_ipath_disable_sma, "Disable the SMA");
const int ib_ipath_state_ops[IB_QPS_ERR + 1] = {
[IB_QPS_RESET] = 0,
@@ -71,6 +123,16 @@ const int ib_ipath_state_ops[IB_QPS_ERR + 1] = {
[IB_QPS_ERR] = 0,
};
+struct ipath_ucontext {
+ struct ib_ucontext ibucontext;
+};
+
+static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext
+ *ibucontext)
+{
+ return container_of(ibucontext, struct ipath_ucontext, ibucontext);
+}
+
/*
* Translate ib_wr_opcode into ib_wc_opcode.
*/
@@ -137,10 +199,6 @@ void ipath_skip_sge(struct ipath_sge_state *ss, u32 length)
{
struct ipath_sge *sge = &ss->sge;
- while (length > sge->sge_length) {
- length -= sge->sge_length;
- ss->sge = *ss->sg_list++;
- }
while (length) {
u32 len = sge->length;
@@ -193,7 +251,7 @@ static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
switch (qp->ibqp.qp_type) {
case IB_QPT_UC:
case IB_QPT_RC:
- err = ipath_post_rc_send(qp, wr);
+ err = ipath_post_ruc_send(qp, wr);
break;
case IB_QPT_SMI:
@@ -227,11 +285,12 @@ static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
struct ib_recv_wr **bad_wr)
{
struct ipath_qp *qp = to_iqp(ibqp);
+ struct ipath_rwq *wq = qp->r_rq.wq;
unsigned long flags;
int ret;
/* Check that state is OK to post receive. */
- if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK)) {
+ if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK) || !wq) {
*bad_wr = wr;
ret = -EINVAL;
goto bail;
@@ -240,59 +299,31 @@ static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
for (; wr; wr = wr->next) {
struct ipath_rwqe *wqe;
u32 next;
- int i, j;
+ int i;
- if (wr->num_sge > qp->r_rq.max_sge) {
+ if ((unsigned) wr->num_sge > qp->r_rq.max_sge) {
*bad_wr = wr;
ret = -ENOMEM;
goto bail;
}
spin_lock_irqsave(&qp->r_rq.lock, flags);
- next = qp->r_rq.head + 1;
+ next = wq->head + 1;
if (next >= qp->r_rq.size)
next = 0;
- if (next == qp->r_rq.tail) {
+ if (next == wq->tail) {
spin_unlock_irqrestore(&qp->r_rq.lock, flags);
*bad_wr = wr;
ret = -ENOMEM;
goto bail;
}
- wqe = get_rwqe_ptr(&qp->r_rq, qp->r_rq.head);
+ wqe = get_rwqe_ptr(&qp->r_rq, wq->head);
wqe->wr_id = wr->wr_id;
- wqe->sg_list[0].mr = NULL;
- wqe->sg_list[0].vaddr = NULL;
- wqe->sg_list[0].length = 0;
- wqe->sg_list[0].sge_length = 0;
- wqe->length = 0;
- for (i = 0, j = 0; i < wr->num_sge; i++) {
- /* Check LKEY */
- if (to_ipd(qp->ibqp.pd)->user &&
- wr->sg_list[i].lkey == 0) {
- spin_unlock_irqrestore(&qp->r_rq.lock,
- flags);
- *bad_wr = wr;
- ret = -EINVAL;
- goto bail;
- }
- if (wr->sg_list[i].length == 0)
- continue;
- if (!ipath_lkey_ok(
- &to_idev(qp->ibqp.device)->lk_table,
- &wqe->sg_list[j], &wr->sg_list[i],
- IB_ACCESS_LOCAL_WRITE)) {
- spin_unlock_irqrestore(&qp->r_rq.lock,
- flags);
- *bad_wr = wr;
- ret = -EINVAL;
- goto bail;
- }
- wqe->length += wr->sg_list[i].length;
- j++;
- }
- wqe->num_sge = j;
- qp->r_rq.head = next;
+ wqe->num_sge = wr->num_sge;
+ for (i = 0; i < wr->num_sge; i++)
+ wqe->sg_list[i] = wr->sg_list[i];
+ wq->head = next;
spin_unlock_irqrestore(&qp->r_rq.lock, flags);
}
ret = 0;
@@ -327,6 +358,9 @@ static void ipath_qp_rcv(struct ipath_ibdev *dev,
switch (qp->ibqp.qp_type) {
case IB_QPT_SMI:
case IB_QPT_GSI:
+ if (ib_ipath_disable_sma)
+ break;
+ /* FALLTHROUGH */
case IB_QPT_UD:
ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp);
break;
@@ -345,7 +379,7 @@ static void ipath_qp_rcv(struct ipath_ibdev *dev,
}
/**
- * ipath_ib_rcv - process and incoming packet
+ * ipath_ib_rcv - process an incoming packet
* @arg: the device pointer
* @rhdr: the header of the packet
* @data: the packet data
@@ -354,9 +388,9 @@ static void ipath_qp_rcv(struct ipath_ibdev *dev,
* This is called from ipath_kreceive() to process an incoming packet at
* interrupt level. Tlen is the length of the header + data + CRC in bytes.
*/
-static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
+void ipath_ib_rcv(struct ipath_ibdev *dev, void *rhdr, void *data,
+ u32 tlen)
{
- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
struct ipath_ib_header *hdr = rhdr;
struct ipath_other_headers *ohdr;
struct ipath_qp *qp;
@@ -375,9 +409,9 @@ static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
/* Check for a valid destination LID (see ch. 7.11.1). */
lid = be16_to_cpu(hdr->lrh[1]);
- if (lid < IPS_MULTICAST_LID_BASE) {
+ if (lid < IPATH_MULTICAST_LID_BASE) {
lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1);
- if (unlikely(lid != ipath_layer_get_lid(dev->dd))) {
+ if (unlikely(lid != dev->dd->ipath_lid)) {
dev->rcv_errors++;
goto bail;
}
@@ -385,9 +419,9 @@ static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
/* Check for GRH */
lnh = be16_to_cpu(hdr->lrh[0]) & 3;
- if (lnh == IPS_LRH_BTH)
+ if (lnh == IPATH_LRH_BTH)
ohdr = &hdr->u.oth;
- else if (lnh == IPS_LRH_GRH)
+ else if (lnh == IPATH_LRH_GRH)
ohdr = &hdr->u.l.oth;
else {
dev->rcv_errors++;
@@ -399,8 +433,8 @@ static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
dev->opstats[opcode].n_packets++;
/* Get the destination QP number. */
- qp_num = be32_to_cpu(ohdr->bth[1]) & IPS_QPN_MASK;
- if (qp_num == IPS_MULTICAST_QPN) {
+ qp_num = be32_to_cpu(ohdr->bth[1]) & IPATH_QPN_MASK;
+ if (qp_num == IPATH_MULTICAST_QPN) {
struct ipath_mcast *mcast;
struct ipath_mcast_qp *p;
@@ -411,7 +445,7 @@ static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
}
dev->n_multicast_rcv++;
list_for_each_entry_rcu(p, &mcast->qp_list, list)
- ipath_qp_rcv(dev, hdr, lnh == IPS_LRH_GRH, data,
+ ipath_qp_rcv(dev, hdr, lnh == IPATH_LRH_GRH, data,
tlen, p->qp);
/*
* Notify ipath_multicast_detach() if it is waiting for us
@@ -423,7 +457,7 @@ static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen)
qp = ipath_lookup_qpn(&dev->qp_table, qp_num);
if (qp) {
dev->n_unicast_rcv++;
- ipath_qp_rcv(dev, hdr, lnh == IPS_LRH_GRH, data,
+ ipath_qp_rcv(dev, hdr, lnh == IPATH_LRH_GRH, data,
tlen, qp);
/*
* Notify ipath_destroy_qp() if it is waiting
@@ -445,9 +479,8 @@ bail:;
* This is called from ipath_do_rcv_timer() at interrupt level to check for
* QPs which need retransmits and to collect performance numbers.
*/
-static void ipath_ib_timer(void *arg)
+void ipath_ib_timer(struct ipath_ibdev *dev)
{
- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
struct ipath_qp *resend = NULL;
struct list_head *last;
struct ipath_qp *qp;
@@ -489,19 +522,19 @@ static void ipath_ib_timer(void *arg)
if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED &&
--dev->pma_sample_start == 0) {
dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING;
- ipath_layer_snapshot_counters(dev->dd, &dev->ipath_sword,
- &dev->ipath_rword,
- &dev->ipath_spkts,
- &dev->ipath_rpkts,
- &dev->ipath_xmit_wait);
+ ipath_snapshot_counters(dev->dd, &dev->ipath_sword,
+ &dev->ipath_rword,
+ &dev->ipath_spkts,
+ &dev->ipath_rpkts,
+ &dev->ipath_xmit_wait);
}
if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) {
if (dev->pma_sample_interval == 0) {
u64 ta, tb, tc, td, te;
dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE;
- ipath_layer_snapshot_counters(dev->dd, &ta, &tb,
- &tc, &td, &te);
+ ipath_snapshot_counters(dev->dd, &ta, &tb,
+ &tc, &td, &te);
dev->ipath_sword = ta - dev->ipath_sword;
dev->ipath_rword = tb - dev->ipath_rword;
@@ -531,6 +564,365 @@ static void ipath_ib_timer(void *arg)
}
}
+static void update_sge(struct ipath_sge_state *ss, u32 length)
+{
+ struct ipath_sge *sge = &ss->sge;
+
+ sge->vaddr += length;
+ sge->length -= length;
+ sge->sge_length -= length;
+ if (sge->sge_length == 0) {
+ if (--ss->num_sge)
+ *sge = *ss->sg_list++;
+ } else if (sge->length == 0 && sge->mr != NULL) {
+ if (++sge->n >= IPATH_SEGSZ) {
+ if (++sge->m >= sge->mr->mapsz)
+ return;
+ sge->n = 0;
+ }
+ sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr;
+ sge->length = sge->mr->map[sge->m]->segs[sge->n].length;
+ }
+}
+
+#ifdef __LITTLE_ENDIAN
+static inline u32 get_upper_bits(u32 data, u32 shift)
+{
+ return data >> shift;
+}
+
+static inline u32 set_upper_bits(u32 data, u32 shift)
+{
+ return data << shift;
+}
+
+static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
+{
+ data <<= ((sizeof(u32) - n) * BITS_PER_BYTE);
+ data >>= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
+ return data;
+}
+#else
+static inline u32 get_upper_bits(u32 data, u32 shift)
+{
+ return data << shift;
+}
+
+static inline u32 set_upper_bits(u32 data, u32 shift)
+{
+ return data >> shift;
+}
+
+static inline u32 clear_upper_bytes(u32 data, u32 n, u32 off)
+{
+ data >>= ((sizeof(u32) - n) * BITS_PER_BYTE);
+ data <<= ((sizeof(u32) - n - off) * BITS_PER_BYTE);
+ return data;
+}
+#endif
+
+static void copy_io(u32 __iomem *piobuf, struct ipath_sge_state *ss,
+ u32 length)
+{
+ u32 extra = 0;
+ u32 data = 0;
+ u32 last;
+
+ while (1) {
+ u32 len = ss->sge.length;
+ u32 off;
+
+ BUG_ON(len == 0);
+ if (len > length)
+ len = length;
+ if (len > ss->sge.sge_length)
+ len = ss->sge.sge_length;
+ /* If the source address is not aligned, try to align it. */
+ off = (unsigned long)ss->sge.vaddr & (sizeof(u32) - 1);
+ if (off) {
+ u32 *addr = (u32 *)((unsigned long)ss->sge.vaddr &
+ ~(sizeof(u32) - 1));
+ u32 v = get_upper_bits(*addr, off * BITS_PER_BYTE);
+ u32 y;
+
+ y = sizeof(u32) - off;
+ if (len > y)
+ len = y;
+ if (len + extra >= sizeof(u32)) {
+ data |= set_upper_bits(v, extra *
+ BITS_PER_BYTE);
+ len = sizeof(u32) - extra;
+ if (len == length) {
+ last = data;
+ break;
+ }
+ __raw_writel(data, piobuf);
+ piobuf++;
+ extra = 0;
+ data = 0;
+ } else {
+ /* Clear unused upper bytes */
+ data |= clear_upper_bytes(v, len, extra);
+ if (len == length) {
+ last = data;
+ break;
+ }
+ extra += len;
+ }
+ } else if (extra) {
+ /* Source address is aligned. */
+ u32 *addr = (u32 *) ss->sge.vaddr;
+ int shift = extra * BITS_PER_BYTE;
+ int ushift = 32 - shift;
+ u32 l = len;
+
+ while (l >= sizeof(u32)) {
+ u32 v = *addr;
+
+ data |= set_upper_bits(v, shift);
+ __raw_writel(data, piobuf);
+ data = get_upper_bits(v, ushift);
+ piobuf++;
+ addr++;
+ l -= sizeof(u32);
+ }
+ /*
+ * We still have 'extra' number of bytes leftover.
+ */
+ if (l) {
+ u32 v = *addr;
+
+ if (l + extra >= sizeof(u32)) {
+ data |= set_upper_bits(v, shift);
+ len -= l + extra - sizeof(u32);
+ if (len == length) {
+ last = data;
+ break;
+ }
+ __raw_writel(data, piobuf);
+ piobuf++;
+ extra = 0;
+ data = 0;
+ } else {
+ /* Clear unused upper bytes */
+ data |= clear_upper_bytes(v, l,
+ extra);
+ if (len == length) {
+ last = data;
+ break;
+ }
+ extra += l;
+ }
+ } else if (len == length) {
+ last = data;
+ break;
+ }
+ } else if (len == length) {
+ u32 w;
+
+ /*
+ * Need to round up for the last dword in the
+ * packet.
+ */
+ w = (len + 3) >> 2;
+ __iowrite32_copy(piobuf, ss->sge.vaddr, w - 1);
+ piobuf += w - 1;
+ last = ((u32 *) ss->sge.vaddr)[w - 1];
+ break;
+ } else {
+ u32 w = len >> 2;
+
+ __iowrite32_copy(piobuf, ss->sge.vaddr, w);
+ piobuf += w;
+
+ extra = len & (sizeof(u32) - 1);
+ if (extra) {
+ u32 v = ((u32 *) ss->sge.vaddr)[w];
+
+ /* Clear unused upper bytes */
+ data = clear_upper_bytes(v, extra, 0);
+ }
+ }
+ update_sge(ss, len);
+ length -= len;
+ }
+ /* Update address before sending packet. */
+ update_sge(ss, length);
+ /* must flush early everything before trigger word */
+ ipath_flush_wc();
+ __raw_writel(last, piobuf);
+ /* be sure trigger word is written */
+ ipath_flush_wc();
+}
+
+/**
+ * ipath_verbs_send - send a packet
+ * @dd: the infinipath device
+ * @hdrwords: the number of words in the header
+ * @hdr: the packet header
+ * @len: the length of the packet in bytes
+ * @ss: the SGE to send
+ */
+int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
+ u32 *hdr, u32 len, struct ipath_sge_state *ss)
+{
+ u32 __iomem *piobuf;
+ u32 plen;
+ int ret;
+
+ /* +1 is for the qword padding of pbc */
+ plen = hdrwords + ((len + 3) >> 2) + 1;
+ if (unlikely((plen << 2) > dd->ipath_ibmaxlen)) {
+ ipath_dbg("packet len 0x%x too long, failing\n", plen);
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ /* Get a PIO buffer to use. */
+ piobuf = ipath_getpiobuf(dd, NULL);
+ if (unlikely(piobuf == NULL)) {
+ ret = -EBUSY;
+ goto bail;
+ }
+
+ /*
+ * Write len to control qword, no flags.
+ * We have to flush after the PBC for correctness on some cpus
+ * or WC buffer can be written out of order.
+ */
+ writeq(plen, piobuf);
+ ipath_flush_wc();
+ piobuf += 2;
+ if (len == 0) {
+ /*
+ * If there is just the header portion, must flush before
+ * writing last word of header for correctness, and after
+ * the last header word (trigger word).
+ */
+ __iowrite32_copy(piobuf, hdr, hdrwords - 1);
+ ipath_flush_wc();
+ __raw_writel(hdr[hdrwords - 1], piobuf + hdrwords - 1);
+ ipath_flush_wc();
+ ret = 0;
+ goto bail;
+ }
+
+ __iowrite32_copy(piobuf, hdr, hdrwords);
+ piobuf += hdrwords;
+
+ /* The common case is aligned and contained in one segment. */
+ if (likely(ss->num_sge == 1 && len <= ss->sge.length &&
+ !((unsigned long)ss->sge.vaddr & (sizeof(u32) - 1)))) {
+ u32 w;
+ u32 *addr = (u32 *) ss->sge.vaddr;
+
+ /* Update address before sending packet. */
+ update_sge(ss, len);
+ /* Need to round up for the last dword in the packet. */
+ w = (len + 3) >> 2;
+ __iowrite32_copy(piobuf, addr, w - 1);
+ /* must flush early everything before trigger word */
+ ipath_flush_wc();
+ __raw_writel(addr[w - 1], piobuf + w - 1);
+ /* be sure trigger word is written */
+ ipath_flush_wc();
+ ret = 0;
+ goto bail;
+ }
+ copy_io(piobuf, ss, len);
+ ret = 0;
+
+bail:
+ return ret;
+}
+
+int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
+ u64 *rwords, u64 *spkts, u64 *rpkts,
+ u64 *xmit_wait)
+{
+ int ret;
+
+ if (!(dd->ipath_flags & IPATH_INITTED)) {
+ /* no hardware, freeze, etc. */
+ ipath_dbg("unit %u not usable\n", dd->ipath_unit);
+ ret = -EINVAL;
+ goto bail;
+ }
+ *swords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
+ *rwords = ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+ *spkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
+ *rpkts = ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+ *xmit_wait = ipath_snap_cntr(dd, dd->ipath_cregs->cr_sendstallcnt);
+
+ ret = 0;
+
+bail:
+ return ret;
+}
+
+/**
+ * ipath_get_counters - get various chip counters
+ * @dd: the infinipath device
+ * @cntrs: counters are placed here
+ *
+ * Return the counters needed by recv_pma_get_portcounters().
+ */
+int ipath_get_counters(struct ipath_devdata *dd,
+ struct ipath_verbs_counters *cntrs)
+{
+ int ret;
+
+ if (!(dd->ipath_flags & IPATH_INITTED)) {
+ /* no hardware, freeze, etc. */
+ ipath_dbg("unit %u not usable\n", dd->ipath_unit);
+ ret = -EINVAL;
+ goto bail;
+ }
+ cntrs->symbol_error_counter =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_ibsymbolerrcnt);
+ cntrs->link_error_recovery_counter =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkerrrecovcnt);
+ /*
+ * The link downed counter counts when the other side downs the
+ * connection. We add in the number of times we downed the link
+ * due to local link integrity errors to compensate.
+ */
+ cntrs->link_downed_counter =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_iblinkdowncnt);
+ cntrs->port_rcv_errors =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_rxdroppktcnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvovflcnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_portovflcnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_err_rlencnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_invalidrlencnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
+ dd->ipath_rxfc_unsupvl_errs;
+ cntrs->port_rcv_remphys_errors =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
+ cntrs->port_xmit_discards =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_unsupvlcnt);
+ cntrs->port_xmit_data =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordsendcnt);
+ cntrs->port_rcv_data =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_wordrcvcnt);
+ cntrs->port_xmit_packets =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
+ cntrs->port_rcv_packets =
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
+ cntrs->local_link_integrity_errors =
+ (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
+ dd->ipath_lli_errs : dd->ipath_lli_errors;
+ cntrs->excessive_buffer_overrun_errors = dd->ipath_overrun_thresh_errs;
+
+ ret = 0;
+
+bail:
+ return ret;
+}
+
/**
* ipath_ib_piobufavail - callback when a PIO buffer is available
* @arg: the device pointer
@@ -541,9 +933,8 @@ static void ipath_ib_timer(void *arg)
* QPs waiting for buffers (for now, just do a tasklet_hi_schedule and
* return zero).
*/
-static int ipath_ib_piobufavail(void *arg)
+int ipath_ib_piobufavail(struct ipath_ibdev *dev)
{
- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
struct ipath_qp *qp;
unsigned long flags;
@@ -567,40 +958,39 @@ static int ipath_query_device(struct ib_device *ibdev,
struct ib_device_attr *props)
{
struct ipath_ibdev *dev = to_idev(ibdev);
- u32 vendor, boardrev, majrev, minrev;
memset(props, 0, sizeof(*props));
props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR |
IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT |
IB_DEVICE_SYS_IMAGE_GUID;
- ipath_layer_query_device(dev->dd, &vendor, &boardrev,
- &majrev, &minrev);
- props->vendor_id = vendor;
- props->vendor_part_id = boardrev;
- props->hw_ver = boardrev << 16 | majrev << 8 | minrev;
+ props->page_size_cap = PAGE_SIZE;
+ props->vendor_id = dev->dd->ipath_vendorid;
+ props->vendor_part_id = dev->dd->ipath_deviceid;
+ props->hw_ver = dev->dd->ipath_pcirev;
props->sys_image_guid = dev->sys_image_guid;
props->max_mr_size = ~0ull;
- props->max_qp = 0xffff;
- props->max_qp_wr = 0xffff;
- props->max_sge = 255;
- props->max_cq = 0xffff;
- props->max_cqe = 0xffff;
- props->max_mr = 0xffff;
- props->max_pd = 0xffff;
+ props->max_qp = ib_ipath_max_qps;
+ props->max_qp_wr = ib_ipath_max_qp_wrs;
+ props->max_sge = ib_ipath_max_sges;
+ props->max_cq = ib_ipath_max_cqs;
+ props->max_ah = ib_ipath_max_ahs;
+ props->max_cqe = ib_ipath_max_cqes;
+ props->max_mr = dev->lk_table.max;
+ props->max_pd = ib_ipath_max_pds;
props->max_qp_rd_atom = 1;
props->max_qp_init_rd_atom = 1;
/* props->max_res_rd_atom */
- props->max_srq = 0xffff;
- props->max_srq_wr = 0xffff;
- props->max_srq_sge = 255;
+ props->max_srq = ib_ipath_max_srqs;
+ props->max_srq_wr = ib_ipath_max_srq_wrs;
+ props->max_srq_sge = ib_ipath_max_srq_sges;
/* props->local_ca_ack_delay */
props->atomic_cap = IB_ATOMIC_HCA;
- props->max_pkeys = ipath_layer_get_npkeys(dev->dd);
- props->max_mcast_grp = 0xffff;
- props->max_mcast_qp_attach = 0xffff;
+ props->max_pkeys = ipath_get_npkeys(dev->dd);
+ props->max_mcast_grp = ib_ipath_max_mcast_grps;
+ props->max_mcast_qp_attach = ib_ipath_max_mcast_qp_attached;
props->max_total_mcast_qp_attach = props->max_mcast_qp_attach *
props->max_mcast_grp;
@@ -623,12 +1013,17 @@ const u8 ipath_cvt_physportstate[16] = {
[INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6,
};
+u32 ipath_get_cr_errpkey(struct ipath_devdata *dd)
+{
+ return ipath_read_creg32(dd, dd->ipath_cregs->cr_errpkey);
+}
+
static int ipath_query_port(struct ib_device *ibdev,
u8 port, struct ib_port_attr *props)
{
struct ipath_ibdev *dev = to_idev(ibdev);
enum ib_mtu mtu;
- u16 lid = ipath_layer_get_lid(dev->dd);
+ u16 lid = dev->dd->ipath_lid;
u64 ibcstat;
memset(props, 0, sizeof(*props));
@@ -636,17 +1031,17 @@ static int ipath_query_port(struct ib_device *ibdev,
props->lmc = dev->mkeyprot_resv_lmc & 7;
props->sm_lid = dev->sm_lid;
props->sm_sl = dev->sm_sl;
- ibcstat = ipath_layer_get_lastibcstat(dev->dd);
+ ibcstat = dev->dd->ipath_lastibcstat;
props->state = ((ibcstat >> 4) & 0x3) + 1;
/* See phys_state_show() */
props->phys_state = ipath_cvt_physportstate[
- ipath_layer_get_lastibcstat(dev->dd) & 0xf];
+ dev->dd->ipath_lastibcstat & 0xf];
props->port_cap_flags = dev->port_cap_flags;
props->gid_tbl_len = 1;
- props->max_msg_sz = 4096;
- props->pkey_tbl_len = ipath_layer_get_npkeys(dev->dd);
- props->bad_pkey_cntr = ipath_layer_get_cr_errpkey(dev->dd) -
- dev->n_pkey_violations;
+ props->max_msg_sz = 0x80000000;
+ props->pkey_tbl_len = ipath_get_npkeys(dev->dd);
+ props->bad_pkey_cntr = ipath_get_cr_errpkey(dev->dd) -
+ dev->z_pkey_violations;
props->qkey_viol_cntr = dev->qkey_violations;
props->active_width = IB_WIDTH_4X;
/* See rate_show() */
@@ -655,7 +1050,7 @@ static int ipath_query_port(struct ib_device *ibdev,
props->init_type_reply = 0;
props->max_mtu = IB_MTU_4096;
- switch (ipath_layer_get_ibmtu(dev->dd)) {
+ switch (dev->dd->ipath_ibmtu) {
case 4096:
mtu = IB_MTU_4096;
break;
@@ -714,7 +1109,7 @@ static int ipath_modify_port(struct ib_device *ibdev,
dev->port_cap_flags |= props->set_port_cap_mask;
dev->port_cap_flags &= ~props->clr_port_cap_mask;
if (port_modify_mask & IB_PORT_SHUTDOWN)
- ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN);
+ ipath_set_linkstate(dev->dd, IPATH_IB_LINKDOWN);
if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR)
dev->qkey_violations = 0;
return 0;
@@ -731,7 +1126,7 @@ static int ipath_query_gid(struct ib_device *ibdev, u8 port,
goto bail;
}
gid->global.subnet_prefix = dev->gid_prefix;
- gid->global.interface_id = ipath_layer_get_guid(dev->dd);
+ gid->global.interface_id = dev->dd->ipath_guid;
ret = 0;
@@ -743,15 +1138,34 @@ static struct ib_pd *ipath_alloc_pd(struct ib_device *ibdev,
struct ib_ucontext *context,
struct ib_udata *udata)
{
+ struct ipath_ibdev *dev = to_idev(ibdev);
struct ipath_pd *pd;
struct ib_pd *ret;
+ /*
+ * This is actually totally arbitrary. Some correctness tests
+ * assume there's a maximum number of PDs that can be allocated.
+ * We don't actually have this limit, but we fail the test if
+ * we allow allocations of more than we report for this value.
+ */
+
pd = kmalloc(sizeof *pd, GFP_KERNEL);
if (!pd) {
ret = ERR_PTR(-ENOMEM);
goto bail;
}
+ spin_lock(&dev->n_pds_lock);
+ if (dev->n_pds_allocated == ib_ipath_max_pds) {
+ spin_unlock(&dev->n_pds_lock);
+ kfree(pd);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail;
+ }
+
+ dev->n_pds_allocated++;
+ spin_unlock(&dev->n_pds_lock);
+
/* ib_alloc_pd() will initialize pd->ibpd. */
pd->user = udata != NULL;
@@ -764,6 +1178,11 @@ bail:
static int ipath_dealloc_pd(struct ib_pd *ibpd)
{
struct ipath_pd *pd = to_ipd(ibpd);
+ struct ipath_ibdev *dev = to_idev(ibpd->device);
+
+ spin_lock(&dev->n_pds_lock);
+ dev->n_pds_allocated--;
+ spin_unlock(&dev->n_pds_lock);
kfree(pd);
@@ -782,21 +1201,45 @@ static struct ib_ah *ipath_create_ah(struct ib_pd *pd,
{
struct ipath_ah *ah;
struct ib_ah *ret;
+ struct ipath_ibdev *dev = to_idev(pd->device);
+ unsigned long flags;
/* A multicast address requires a GRH (see ch. 8.4.1). */
- if (ah_attr->dlid >= IPS_MULTICAST_LID_BASE &&
- ah_attr->dlid != IPS_PERMISSIVE_LID &&
+ if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
+ ah_attr->dlid != IPATH_PERMISSIVE_LID &&
!(ah_attr->ah_flags & IB_AH_GRH)) {
ret = ERR_PTR(-EINVAL);
goto bail;
}
+ if (ah_attr->dlid == 0) {
+ ret = ERR_PTR(-EINVAL);
+ goto bail;
+ }
+
+ if (ah_attr->port_num < 1 ||
+ ah_attr->port_num > pd->device->phys_port_cnt) {
+ ret = ERR_PTR(-EINVAL);
+ goto bail;
+ }
+
ah = kmalloc(sizeof *ah, GFP_ATOMIC);
if (!ah) {
ret = ERR_PTR(-ENOMEM);
goto bail;
}
+ spin_lock_irqsave(&dev->n_ahs_lock, flags);
+ if (dev->n_ahs_allocated == ib_ipath_max_ahs) {
+ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+ kfree(ah);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail;
+ }
+
+ dev->n_ahs_allocated++;
+ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
+
/* ib_create_ah() will initialize ah->ibah. */
ah->attr = *ah_attr;
@@ -814,7 +1257,13 @@ bail:
*/
static int ipath_destroy_ah(struct ib_ah *ibah)
{
+ struct ipath_ibdev *dev = to_idev(ibah->device);
struct ipath_ah *ah = to_iah(ibah);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->n_ahs_lock, flags);
+ dev->n_ahs_allocated--;
+ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
kfree(ah);
@@ -830,25 +1279,50 @@ static int ipath_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr)
return 0;
}
+/**
+ * ipath_get_npkeys - return the size of the PKEY table for port 0
+ * @dd: the infinipath device
+ */
+unsigned ipath_get_npkeys(struct ipath_devdata *dd)
+{
+ return ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys);
+}
+
+/**
+ * ipath_get_pkey - return the indexed PKEY from the port 0 PKEY table
+ * @dd: the infinipath device
+ * @index: the PKEY index
+ */
+unsigned ipath_get_pkey(struct ipath_devdata *dd, unsigned index)
+{
+ unsigned ret;
+
+ if (index >= ARRAY_SIZE(dd->ipath_pd[0]->port_pkeys))
+ ret = 0;
+ else
+ ret = dd->ipath_pd[0]->port_pkeys[index];
+
+ return ret;
+}
+
static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index,
u16 *pkey)
{
struct ipath_ibdev *dev = to_idev(ibdev);
int ret;
- if (index >= ipath_layer_get_npkeys(dev->dd)) {
+ if (index >= ipath_get_npkeys(dev->dd)) {
ret = -EINVAL;
goto bail;
}
- *pkey = ipath_layer_get_pkey(dev->dd, index);
+ *pkey = ipath_get_pkey(dev->dd, index);
ret = 0;
bail:
return ret;
}
-
/**
* ipath_alloc_ucontext - allocate a ucontest
* @ibdev: the infiniband device
@@ -881,25 +1355,102 @@ static int ipath_dealloc_ucontext(struct ib_ucontext *context)
static int ipath_verbs_register_sysfs(struct ib_device *dev);
+static void __verbs_timer(unsigned long arg)
+{
+ struct ipath_devdata *dd = (struct ipath_devdata *) arg;
+
+ /*
+ * If port 0 receive packet interrupts are not available, or
+ * can be missed, poll the receive queue
+ */
+ if (dd->ipath_flags & IPATH_POLL_RX_INTR)
+ ipath_kreceive(dd);
+
+ /* Handle verbs layer timeouts. */
+ ipath_ib_timer(dd->verbs_dev);
+
+ mod_timer(&dd->verbs_timer, jiffies + 1);
+}
+
+static int enable_timer(struct ipath_devdata *dd)
+{
+ /*
+ * Early chips had a design flaw where the chip and kernel idea
+ * of the tail register don't always agree, and therefore we won't
+ * get an interrupt on the next packet received.
+ * If the board supports per packet receive interrupts, use it.
+ * Otherwise, the timer function periodically checks for packets
+ * to cover this case.
+ * Either way, the timer is needed for verbs layer related
+ * processing.
+ */
+ if (dd->ipath_flags & IPATH_GPIO_INTR) {
+ u64 val;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect,
+ 0x2074076542310ULL);
+ /* Enable GPIO bit 2 interrupt */
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
+ val |= (u64) (1 << IPATH_GPIO_PORT0_BIT);
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
+ }
+
+ init_timer(&dd->verbs_timer);
+ dd->verbs_timer.function = __verbs_timer;
+ dd->verbs_timer.data = (unsigned long)dd;
+ dd->verbs_timer.expires = jiffies + 1;
+ add_timer(&dd->verbs_timer);
+
+ return 0;
+}
+
+static int disable_timer(struct ipath_devdata *dd)
+{
+ /* Disable GPIO bit 2 interrupt */
+ if (dd->ipath_flags & IPATH_GPIO_INTR) {
+ u64 val;
+ /* Disable GPIO bit 2 interrupt */
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
+ val &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
+ /*
+ * We might want to undo changes to debugportselect,
+ * but how?
+ */
+ }
+
+ del_timer_sync(&dd->verbs_timer);
+
+ return 0;
+}
+
/**
* ipath_register_ib_device - register our device with the infiniband core
- * @unit: the device number to register
* @dd: the device data structure
* Return the allocated ipath_ibdev pointer or NULL on error.
*/
-static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
+int ipath_register_ib_device(struct ipath_devdata *dd)
{
+ struct ipath_verbs_counters cntrs;
struct ipath_ibdev *idev;
struct ib_device *dev;
int ret;
idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev);
- if (idev == NULL)
+ if (idev == NULL) {
+ ret = -ENOMEM;
goto bail;
+ }
dev = &idev->ibdev;
/* Only need to initialize non-zero fields. */
+ spin_lock_init(&idev->n_pds_lock);
+ spin_lock_init(&idev->n_ahs_lock);
+ spin_lock_init(&idev->n_cqs_lock);
+ spin_lock_init(&idev->n_qps_lock);
+ spin_lock_init(&idev->n_srqs_lock);
+ spin_lock_init(&idev->n_mcast_grps_lock);
+
spin_lock_init(&idev->qp_table.lock);
spin_lock_init(&idev->lk_table.lock);
idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE);
@@ -939,20 +1490,39 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
idev->pma_counter_select[5] = IB_PMA_PORT_XMIT_WAIT;
idev->link_width_enabled = 3; /* 1x or 4x */
+ /* Snapshot current HW counters to "clear" them. */
+ ipath_get_counters(dd, &cntrs);
+ idev->z_symbol_error_counter = cntrs.symbol_error_counter;
+ idev->z_link_error_recovery_counter =
+ cntrs.link_error_recovery_counter;
+ idev->z_link_downed_counter = cntrs.link_downed_counter;
+ idev->z_port_rcv_errors = cntrs.port_rcv_errors;
+ idev->z_port_rcv_remphys_errors =
+ cntrs.port_rcv_remphys_errors;
+ idev->z_port_xmit_discards = cntrs.port_xmit_discards;
+ idev->z_port_xmit_data = cntrs.port_xmit_data;
+ idev->z_port_rcv_data = cntrs.port_rcv_data;
+ idev->z_port_xmit_packets = cntrs.port_xmit_packets;
+ idev->z_port_rcv_packets = cntrs.port_rcv_packets;
+ idev->z_local_link_integrity_errors =
+ cntrs.local_link_integrity_errors;
+ idev->z_excessive_buffer_overrun_errors =
+ cntrs.excessive_buffer_overrun_errors;
+
/*
* The system image GUID is supposed to be the same for all
* IB HCAs in a single system but since there can be other
* device types in the system, we can't be sure this is unique.
*/
if (!sys_image_guid)
- sys_image_guid = ipath_layer_get_guid(dd);
+ sys_image_guid = dd->ipath_guid;
idev->sys_image_guid = sys_image_guid;
- idev->ib_unit = unit;
+ idev->ib_unit = dd->ipath_unit;
idev->dd = dd;
strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX);
dev->owner = THIS_MODULE;
- dev->node_guid = ipath_layer_get_guid(dd);
+ dev->node_guid = dd->ipath_guid;
dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION;
dev->uverbs_cmd_mask =
(1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
@@ -984,9 +1554,9 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
(1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
(1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
(1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
- dev->node_type = IB_NODE_CA;
+ dev->node_type = RDMA_NODE_IB_CA;
dev->phys_port_cnt = 1;
- dev->dma_device = ipath_layer_get_device(dd);
+ dev->dma_device = &dd->pcidev->dev;
dev->class_dev.dev = dev->dma_device;
dev->query_device = ipath_query_device;
dev->modify_device = ipath_modify_device;
@@ -1028,9 +1598,10 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
dev->attach_mcast = ipath_multicast_attach;
dev->detach_mcast = ipath_multicast_detach;
dev->process_mad = ipath_process_mad;
+ dev->mmap = ipath_mmap;
snprintf(dev->node_desc, sizeof(dev->node_desc),
- IPATH_IDSTR " %s kernel_SMA", system_utsname.nodename);
+ IPATH_IDSTR " %s", system_utsname.nodename);
ret = ib_register_device(dev);
if (ret)
@@ -1039,7 +1610,7 @@ static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd)
if (ipath_verbs_register_sysfs(dev))
goto err_class;
- ipath_layer_enable_timer(dd);
+ enable_timer(dd);
goto bail;
@@ -1051,37 +1622,32 @@ err_lk:
kfree(idev->qp_table.table);
err_qp:
ib_dealloc_device(dev);
- _VERBS_ERROR("ib_ipath%d cannot register verbs (%d)!\n",
- unit, -ret);
+ ipath_dev_err(dd, "cannot register verbs: %d!\n", -ret);
idev = NULL;
bail:
- return idev;
+ dd->verbs_dev = idev;
+ return ret;
}
-static void ipath_unregister_ib_device(void *arg)
+void ipath_unregister_ib_device(struct ipath_ibdev *dev)
{
- struct ipath_ibdev *dev = (struct ipath_ibdev *) arg;
struct ib_device *ibdev = &dev->ibdev;
- ipath_layer_disable_timer(dev->dd);
+ disable_timer(dev->dd);
ib_unregister_device(ibdev);
if (!list_empty(&dev->pending[0]) ||
!list_empty(&dev->pending[1]) ||
!list_empty(&dev->pending[2]))
- _VERBS_ERROR("ipath%d pending list not empty!\n",
- dev->ib_unit);
+ ipath_dev_err(dev->dd, "pending list not empty!\n");
if (!list_empty(&dev->piowait))
- _VERBS_ERROR("ipath%d piowait list not empty!\n",
- dev->ib_unit);
+ ipath_dev_err(dev->dd, "piowait list not empty!\n");
if (!list_empty(&dev->rnrwait))
- _VERBS_ERROR("ipath%d rnrwait list not empty!\n",
- dev->ib_unit);
+ ipath_dev_err(dev->dd, "rnrwait list not empty!\n");
if (!ipath_mcast_tree_empty())
- _VERBS_ERROR("ipath%d multicast table memory leak!\n",
- dev->ib_unit);
+ ipath_dev_err(dev->dd, "multicast table memory leak!\n");
/*
* Note that ipath_unregister_ib_device() can be called before all
* the QPs are destroyed!
@@ -1092,28 +1658,12 @@ static void ipath_unregister_ib_device(void *arg)
ib_dealloc_device(ibdev);
}
-static int __init ipath_verbs_init(void)
-{
- return ipath_verbs_register(ipath_register_ib_device,
- ipath_unregister_ib_device,
- ipath_ib_piobufavail, ipath_ib_rcv,
- ipath_ib_timer);
-}
-
-static void __exit ipath_verbs_cleanup(void)
-{
- ipath_verbs_unregister();
-}
-
static ssize_t show_rev(struct class_device *cdev, char *buf)
{
struct ipath_ibdev *dev =
container_of(cdev, struct ipath_ibdev, ibdev.class_dev);
- int vendor, boardrev, majrev, minrev;
- ipath_layer_query_device(dev->dd, &vendor, &boardrev,
- &majrev, &minrev);
- return sprintf(buf, "%d.%d\n", majrev, minrev);
+ return sprintf(buf, "%x\n", dev->dd->ipath_pcirev);
}
static ssize_t show_hca(struct class_device *cdev, char *buf)
@@ -1122,7 +1672,7 @@ static ssize_t show_hca(struct class_device *cdev, char *buf)
container_of(cdev, struct ipath_ibdev, ibdev.class_dev);
int ret;
- ret = ipath_layer_get_boardname(dev->dd, buf, 128);
+ ret = dev->dd->ipath_f_get_boardname(dev->dd, buf, 128);
if (ret < 0)
goto bail;
strcat(buf, "\n");
@@ -1149,6 +1699,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf)
"RC OTH NAKs %d\n"
"RC timeouts %d\n"
"RC RDMA dup %d\n"
+ "RC stalls %d\n"
"piobuf wait %d\n"
"no piobuf %d\n"
"PKT drops %d\n"
@@ -1156,7 +1707,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf)
dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks,
dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks,
dev->n_other_naks, dev->n_timeouts,
- dev->n_rdma_dup_busy, dev->n_piowait,
+ dev->n_rdma_dup_busy, dev->n_rc_stalls, dev->n_piowait,
dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs);
for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) {
const struct ipath_opcode_stats *si = &dev->opstats[i];
@@ -1199,6 +1750,3 @@ static int ipath_verbs_register_sysfs(struct ib_device *dev)
bail:
return ret;
}
-
-module_init(ipath_verbs_init);
-module_exit(ipath_verbs_cleanup);
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 4f8d59300e9..8039f6e5f0c 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -37,10 +38,10 @@
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
+#include <linux/kref.h>
#include <rdma/ib_pack.h>
#include "ipath_layer.h"
-#include "verbs_debug.h"
#define QPN_MAX (1 << 24)
#define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE)
@@ -49,7 +50,7 @@
* Increment this value if any changes that break userspace ABI
* compatibility are made.
*/
-#define IPATH_UVERBS_ABI_VERSION 1
+#define IPATH_UVERBS_ABI_VERSION 2
/*
* Define an ib_cq_notify value that is not valid so we know when CQ
@@ -148,19 +149,7 @@ struct ipath_mcast {
struct list_head qp_list;
wait_queue_head_t wait;
atomic_t refcount;
-};
-
-/* Memory region */
-struct ipath_mr {
- struct ib_mr ibmr;
- struct ipath_mregion mr; /* must be last */
-};
-
-/* Fast memory region */
-struct ipath_fmr {
- struct ib_fmr ibfmr;
- u8 page_shift;
- struct ipath_mregion mr; /* must be last */
+ int n_attached;
};
/* Protection domain */
@@ -176,58 +165,90 @@ struct ipath_ah {
};
/*
- * Quick description of our CQ/QP locking scheme:
- *
- * We have one global lock that protects dev->cq/qp_table. Each
- * struct ipath_cq/qp also has its own lock. An individual qp lock
- * may be taken inside of an individual cq lock. Both cqs attached to
- * a qp may be locked, with the send cq locked first. No other
- * nesting should be done.
- *
- * Each struct ipath_cq/qp also has an atomic_t ref count. The
- * pointer from the cq/qp_table to the struct counts as one reference.
- * This reference also is good for access through the consumer API, so
- * modifying the CQ/QP etc doesn't need to take another reference.
- * Access because of a completion being polled does need a reference.
- *
- * Finally, each struct ipath_cq/qp has a wait_queue_head_t for the
- * destroy function to sleep on.
- *
- * This means that access from the consumer API requires nothing but
- * taking the struct's lock.
- *
- * Access because of a completion event should go as follows:
- * - lock cq/qp_table and look up struct
- * - increment ref count in struct
- * - drop cq/qp_table lock
- * - lock struct, do your thing, and unlock struct
- * - decrement ref count; if zero, wake up waiters
- *
- * To destroy a CQ/QP, we can do the following:
- * - lock cq/qp_table, remove pointer, unlock cq/qp_table lock
- * - decrement ref count
- * - wait_event until ref count is zero
- *
- * It is the consumer's responsibilty to make sure that no QP
- * operations (WQE posting or state modification) are pending when the
- * QP is destroyed. Also, the consumer must make sure that calls to
- * qp_modify are serialized.
- *
- * Possible optimizations (wait for profile data to see if/where we
- * have locks bouncing between CPUs):
- * - split cq/qp table lock into n separate (cache-aligned) locks,
- * indexed (say) by the page in the table
+ * This structure is used by ipath_mmap() to validate an offset
+ * when an mmap() request is made. The vm_area_struct then uses
+ * this as its vm_private_data.
+ */
+struct ipath_mmap_info {
+ struct ipath_mmap_info *next;
+ struct ib_ucontext *context;
+ void *obj;
+ struct kref ref;
+ unsigned size;
+ unsigned mmap_cnt;
+};
+
+/*
+ * This structure is used to contain the head pointer, tail pointer,
+ * and completion queue entries as a single memory allocation so
+ * it can be mmap'ed into user space.
*/
+struct ipath_cq_wc {
+ u32 head; /* index of next entry to fill */
+ u32 tail; /* index of next ib_poll_cq() entry */
+ struct ib_wc queue[1]; /* this is actually size ibcq.cqe + 1 */
+};
+/*
+ * The completion queue structure.
+ */
struct ipath_cq {
struct ib_cq ibcq;
struct tasklet_struct comptask;
spinlock_t lock;
u8 notify;
u8 triggered;
- u32 head; /* new records added to the head */
- u32 tail; /* poll_cq() reads from here. */
- struct ib_wc *queue; /* this is actually ibcq.cqe + 1 */
+ struct ipath_cq_wc *queue;
+ struct ipath_mmap_info *ip;
+};
+
+/*
+ * A segment is a linear region of low physical memory.
+ * XXX Maybe we should use phys addr here and kmap()/kunmap().
+ * Used by the verbs layer.
+ */
+struct ipath_seg {
+ void *vaddr;
+ size_t length;
+};
+
+/* The number of ipath_segs that fit in a page. */
+#define IPATH_SEGSZ (PAGE_SIZE / sizeof (struct ipath_seg))
+
+struct ipath_segarray {
+ struct ipath_seg segs[IPATH_SEGSZ];
+};
+
+struct ipath_mregion {
+ struct ib_pd *pd; /* shares refcnt of ibmr.pd */
+ u64 user_base; /* User's address for this region */
+ u64 iova; /* IB start address of this region */
+ size_t length;
+ u32 lkey;
+ u32 offset; /* offset (bytes) to start of region */
+ int access_flags;
+ u32 max_segs; /* number of ipath_segs in all the arrays */
+ u32 mapsz; /* size of the map array */
+ struct ipath_segarray *map[0]; /* the segments */
+};
+
+/*
+ * These keep track of the copy progress within a memory region.
+ * Used by the verbs layer.
+ */
+struct ipath_sge {
+ struct ipath_mregion *mr;
+ void *vaddr; /* current pointer into the segment */
+ u32 sge_length; /* length of the SGE */
+ u32 length; /* remaining length of the segment */
+ u16 m; /* current index: mr->map[m] */
+ u16 n; /* current index: mr->map[m]->segs[n] */
+};
+
+/* Memory region */
+struct ipath_mr {
+ struct ib_mr ibmr;
+ struct ipath_mregion mr; /* must be last */
};
/*
@@ -246,32 +267,50 @@ struct ipath_swqe {
/*
* Receive work request queue entry.
- * The size of the sg_list is determined when the QP is created and stored
- * in qp->r_max_sge.
+ * The size of the sg_list is determined when the QP (or SRQ) is created
+ * and stored in qp->r_rq.max_sge (or srq->rq.max_sge).
*/
struct ipath_rwqe {
u64 wr_id;
- u32 length; /* total length of data in sg_list */
u8 num_sge;
- struct ipath_sge sg_list[0];
+ struct ib_sge sg_list[0];
};
-struct ipath_rq {
- spinlock_t lock;
+/*
+ * This structure is used to contain the head pointer, tail pointer,
+ * and receive work queue entries as a single memory allocation so
+ * it can be mmap'ed into user space.
+ * Note that the wq array elements are variable size so you can't
+ * just index into the array to get the N'th element;
+ * use get_rwqe_ptr() instead.
+ */
+struct ipath_rwq {
u32 head; /* new work requests posted to the head */
u32 tail; /* receives pull requests from here. */
+ struct ipath_rwqe wq[0];
+};
+
+struct ipath_rq {
+ struct ipath_rwq *wq;
+ spinlock_t lock;
u32 size; /* size of RWQE array */
u8 max_sge;
- struct ipath_rwqe *wq; /* RWQE array */
};
struct ipath_srq {
struct ib_srq ibsrq;
struct ipath_rq rq;
+ struct ipath_mmap_info *ip;
/* send signal when number of RWQEs < limit */
u32 limit;
};
+struct ipath_sge_state {
+ struct ipath_sge *sg_list; /* next SGE to be used if any */
+ struct ipath_sge sge; /* progress state for the current SGE */
+ u8 num_sge;
+};
+
/*
* Variables prefixed with s_ are for the requester (sender).
* Variables prefixed with r_ are for the responder (receiver).
@@ -291,6 +330,7 @@ struct ipath_qp {
atomic_t refcount;
wait_queue_head_t wait;
struct tasklet_struct s_task;
+ struct ipath_mmap_info *ip;
struct ipath_sge_state *s_cur_sge;
struct ipath_sge_state s_sge; /* current send request data */
/* current RDMA read send data */
@@ -305,32 +345,37 @@ struct ipath_qp {
u32 s_next_psn; /* PSN for next request */
u32 s_last_psn; /* last response PSN processed */
u32 s_psn; /* current packet sequence number */
+ u32 s_ack_psn; /* PSN for RDMA_READ */
u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */
- u32 s_ack_psn; /* PSN for next ACK or RDMA_READ */
- u64 s_ack_atomic; /* data for atomic ACK */
+ u32 r_ack_psn; /* PSN for next ACK or atomic ACK */
u64 r_wr_id; /* ID for current receive WQE */
u64 r_atomic_data; /* data for last atomic op */
u32 r_atomic_psn; /* PSN of last atomic op */
u32 r_len; /* total length of r_sge */
u32 r_rcv_len; /* receive data len processed */
u32 r_psn; /* expected rcv packet sequence number */
+ u32 r_msn; /* message sequence number */
u8 state; /* QP state */
u8 s_state; /* opcode of last packet sent */
u8 s_ack_state; /* opcode of packet to ACK */
u8 s_nak_state; /* non-zero if NAK is pending */
u8 r_state; /* opcode of last packet received */
+ u8 r_ack_state; /* opcode of packet to ACK */
+ u8 r_nak_state; /* non-zero if NAK is pending */
+ u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */
u8 r_reuse_sge; /* for UC receive errors */
u8 r_sge_inx; /* current index into sg_list */
- u8 s_max_sge; /* size of s_wq->sg_list */
+ u8 r_wrid_valid; /* r_wrid set but CQ entry not yet made */
u8 qp_access_flags;
+ u8 s_max_sge; /* size of s_wq->sg_list */
u8 s_retry_cnt; /* number of times to retry */
u8 s_rnr_retry_cnt;
- u8 s_min_rnr_timer;
u8 s_retry; /* requester retry counter */
u8 s_rnr_retry; /* requester RNR retry counter */
+ u8 s_wait_credit; /* limit number of unacked packets sent */
u8 s_pkey_index; /* PKEY index to use */
+ u8 timeout; /* Timeout for this QP */
enum ib_mtu path_mtu;
- atomic_t msn; /* message sequence number */
u32 remote_qpn;
u32 qkey; /* QKEY for this QP (for UD or RD) */
u32 s_size; /* send work queue size */
@@ -341,7 +386,8 @@ struct ipath_qp {
u32 s_ssn; /* SSN of tail entry */
u32 s_lsn; /* limit sequence number (credit) */
struct ipath_swqe *s_wq; /* send work queue */
- struct ipath_rq r_rq; /* receive work queue */
+ struct ipath_rq r_rq; /* receive work queue */
+ struct ipath_sge r_sg_list[0]; /* verified SGEs */
};
/*
@@ -350,6 +396,8 @@ struct ipath_qp {
#define IPATH_S_BUSY 0
#define IPATH_S_SIGNAL_REQ_WR 1
+#define IPATH_PSN_CREDIT 2048
+
/*
* Since struct ipath_swqe is not a fixed size, we can't simply index into
* struct ipath_qp.s_wq. This function does the array index computation.
@@ -365,15 +413,15 @@ static inline struct ipath_swqe *get_swqe_ptr(struct ipath_qp *qp,
/*
* Since struct ipath_rwqe is not a fixed size, we can't simply index into
- * struct ipath_rq.wq. This function does the array index computation.
+ * struct ipath_rwq.wq. This function does the array index computation.
*/
static inline struct ipath_rwqe *get_rwqe_ptr(struct ipath_rq *rq,
unsigned n)
{
return (struct ipath_rwqe *)
- ((char *) rq->wq +
+ ((char *) rq->wq->wq +
(sizeof(struct ipath_rwqe) +
- rq->max_sge * sizeof(struct ipath_sge)) * n);
+ rq->max_sge * sizeof(struct ib_sge)) * n);
}
/*
@@ -413,6 +461,7 @@ struct ipath_ibdev {
struct ib_device ibdev;
struct list_head dev_list;
struct ipath_devdata *dd;
+ struct ipath_mmap_info *pending_mmaps;
int ib_unit; /* This is the device number */
u16 sm_lid; /* in host order */
u8 sm_sl;
@@ -431,6 +480,20 @@ struct ipath_ibdev {
__be64 sys_image_guid; /* in network order */
__be64 gid_prefix; /* in network order */
__be64 mkey;
+
+ u32 n_pds_allocated; /* number of PDs allocated for device */
+ spinlock_t n_pds_lock;
+ u32 n_ahs_allocated; /* number of AHs allocated for device */
+ spinlock_t n_ahs_lock;
+ u32 n_cqs_allocated; /* number of CQs allocated for device */
+ spinlock_t n_cqs_lock;
+ u32 n_qps_allocated; /* number of QPs allocated for device */
+ spinlock_t n_qps_lock;
+ u32 n_srqs_allocated; /* number of SRQs allocated for device */
+ spinlock_t n_srqs_lock;
+ u32 n_mcast_grps_allocated; /* number of mcast groups allocated */
+ spinlock_t n_mcast_grps_lock;
+
u64 ipath_sword; /* total dwords sent (sample result) */
u64 ipath_rword; /* total dwords received (sample result) */
u64 ipath_spkts; /* total packets sent (sample result) */
@@ -442,17 +505,19 @@ struct ipath_ibdev {
u64 n_unicast_rcv; /* total unicast packets received */
u64 n_multicast_xmit; /* total multicast packets sent */
u64 n_multicast_rcv; /* total multicast packets received */
- u64 n_symbol_error_counter; /* starting count for PMA */
- u64 n_link_error_recovery_counter; /* starting count for PMA */
- u64 n_link_downed_counter; /* starting count for PMA */
- u64 n_port_rcv_errors; /* starting count for PMA */
- u64 n_port_rcv_remphys_errors; /* starting count for PMA */
- u64 n_port_xmit_discards; /* starting count for PMA */
- u64 n_port_xmit_data; /* starting count for PMA */
- u64 n_port_rcv_data; /* starting count for PMA */
- u64 n_port_xmit_packets; /* starting count for PMA */
- u64 n_port_rcv_packets; /* starting count for PMA */
- u32 n_pkey_violations; /* starting count for PMA */
+ u64 z_symbol_error_counter; /* starting count for PMA */
+ u64 z_link_error_recovery_counter; /* starting count for PMA */
+ u64 z_link_downed_counter; /* starting count for PMA */
+ u64 z_port_rcv_errors; /* starting count for PMA */
+ u64 z_port_rcv_remphys_errors; /* starting count for PMA */
+ u64 z_port_xmit_discards; /* starting count for PMA */
+ u64 z_port_xmit_data; /* starting count for PMA */
+ u64 z_port_rcv_data; /* starting count for PMA */
+ u64 z_port_xmit_packets; /* starting count for PMA */
+ u64 z_port_rcv_packets; /* starting count for PMA */
+ u32 z_pkey_violations; /* starting count for PMA */
+ u32 z_local_link_integrity_errors; /* starting count for PMA */
+ u32 z_excessive_buffer_overrun_errors; /* starting count for PMA */
u32 n_rc_resends;
u32 n_rc_acks;
u32 n_rc_qacks;
@@ -461,7 +526,9 @@ struct ipath_ibdev {
u32 n_rnr_naks;
u32 n_other_naks;
u32 n_timeouts;
+ u32 n_rc_stalls;
u32 n_pkt_drops;
+ u32 n_vl15_dropped;
u32 n_wqe_errs;
u32 n_rdma_dup_busy;
u32 n_piowait;
@@ -482,8 +549,19 @@ struct ipath_ibdev {
struct ipath_opcode_stats opstats[128];
};
-struct ipath_ucontext {
- struct ib_ucontext ibucontext;
+struct ipath_verbs_counters {
+ u64 symbol_error_counter;
+ u64 link_error_recovery_counter;
+ u64 link_downed_counter;
+ u64 port_rcv_errors;
+ u64 port_rcv_remphys_errors;
+ u64 port_xmit_discards;
+ u64 port_xmit_data;
+ u64 port_rcv_data;
+ u64 port_xmit_packets;
+ u64 port_rcv_packets;
+ u32 local_link_integrity_errors;
+ u32 excessive_buffer_overrun_errors;
};
static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
@@ -491,11 +569,6 @@ static inline struct ipath_mr *to_imr(struct ib_mr *ibmr)
return container_of(ibmr, struct ipath_mr, ibmr);
}
-static inline struct ipath_fmr *to_ifmr(struct ib_fmr *ibfmr)
-{
- return container_of(ibfmr, struct ipath_fmr, ibfmr);
-}
-
static inline struct ipath_pd *to_ipd(struct ib_pd *ibpd)
{
return container_of(ibpd, struct ipath_pd, ibpd);
@@ -533,12 +606,6 @@ int ipath_process_mad(struct ib_device *ibdev,
struct ib_grh *in_grh,
struct ib_mad *in_mad, struct ib_mad *out_mad);
-static inline struct ipath_ucontext *to_iucontext(struct ib_ucontext
- *ibucontext)
-{
- return container_of(ibucontext, struct ipath_ucontext, ibucontext);
-}
-
/*
* Compare the lower 24 bits of the two values.
* Returns an integer <, ==, or > than zero.
@@ -550,6 +617,13 @@ static inline int ipath_cmp24(u32 a, u32 b)
struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid);
+int ipath_snapshot_counters(struct ipath_devdata *dd, u64 *swords,
+ u64 *rwords, u64 *spkts, u64 *rpkts,
+ u64 *xmit_wait);
+
+int ipath_get_counters(struct ipath_devdata *dd,
+ struct ipath_verbs_counters *cntrs);
+
int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid);
@@ -566,8 +640,10 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
int ipath_destroy_qp(struct ib_qp *ibqp);
+void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
+
int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
- int attr_mask);
+ int attr_mask, struct ib_udata *udata);
int ipath_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_qp_init_attr *init_attr);
@@ -580,23 +656,16 @@ void ipath_sqerror_qp(struct ipath_qp *qp, struct ib_wc *wc);
void ipath_get_credit(struct ipath_qp *qp, u32 aeth);
-void ipath_do_rc_send(unsigned long data);
-
-void ipath_do_uc_send(unsigned long data);
+int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
+ u32 *hdr, u32 len, struct ipath_sge_state *ss);
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
- u32 len, u64 vaddr, u32 rkey, int acc);
-
-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
- struct ib_sge *sge, int acc);
-
void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
-int ipath_post_rc_send(struct ipath_qp *qp, struct ib_send_wr *wr);
+int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr);
void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int has_grh, void *data, u32 tlen, struct ipath_qp *qp);
@@ -616,10 +685,10 @@ int ipath_alloc_lkey(struct ipath_lkey_table *rkt,
void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey);
-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
+int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
struct ib_sge *sge, int acc);
-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
+int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
u32 len, u64 vaddr, u32 rkey, int acc);
int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
@@ -630,7 +699,8 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
struct ib_udata *udata);
int ipath_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
- enum ib_srq_attr_mask attr_mask);
+ enum ib_srq_attr_mask attr_mask,
+ struct ib_udata *udata);
int ipath_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr);
@@ -672,13 +742,45 @@ int ipath_unmap_fmr(struct list_head *fmr_list);
int ipath_dealloc_fmr(struct ib_fmr *ibfmr);
+void ipath_release_mmap_info(struct kref *ref);
+
+int ipath_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
+
void ipath_no_bufs_available(struct ipath_qp *qp, struct ipath_ibdev *dev);
void ipath_insert_rnr_queue(struct ipath_qp *qp);
int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only);
-void ipath_ruc_loopback(struct ipath_qp *sqp, struct ib_wc *wc);
+u32 ipath_make_grh(struct ipath_ibdev *dev, struct ib_grh *hdr,
+ struct ib_global_route *grh, u32 hwords, u32 nwords);
+
+void ipath_do_ruc_send(unsigned long data);
+
+u32 ipath_make_rc_ack(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
+ u32 pmtu);
+
+int ipath_make_rc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
+ u32 pmtu, u32 *bth0p, u32 *bth2p);
+
+int ipath_make_uc_req(struct ipath_qp *qp, struct ipath_other_headers *ohdr,
+ u32 pmtu, u32 *bth0p, u32 *bth2p);
+
+int ipath_register_ib_device(struct ipath_devdata *);
+
+void ipath_unregister_ib_device(struct ipath_ibdev *);
+
+void ipath_ib_rcv(struct ipath_ibdev *, void *, void *, u32);
+
+int ipath_ib_piobufavail(struct ipath_ibdev *);
+
+void ipath_ib_timer(struct ipath_ibdev *);
+
+unsigned ipath_get_npkeys(struct ipath_devdata *);
+
+u32 ipath_get_cr_errpkey(struct ipath_devdata *);
+
+unsigned ipath_get_pkey(struct ipath_devdata *, unsigned);
extern const enum ib_wc_opcode ib_ipath_wc_opcode[];
@@ -688,6 +790,26 @@ extern const int ib_ipath_state_ops[];
extern unsigned int ib_ipath_lkey_table_size;
+extern unsigned int ib_ipath_max_cqes;
+
+extern unsigned int ib_ipath_max_cqs;
+
+extern unsigned int ib_ipath_max_qp_wrs;
+
+extern unsigned int ib_ipath_max_qps;
+
+extern unsigned int ib_ipath_max_sges;
+
+extern unsigned int ib_ipath_max_mcast_grps;
+
+extern unsigned int ib_ipath_max_mcast_qp_attached;
+
+extern unsigned int ib_ipath_max_srqs;
+
+extern unsigned int ib_ipath_max_srq_sges;
+
+extern unsigned int ib_ipath_max_srq_wrs;
+
extern const u32 ib_ipath_rnr_table[];
#endif /* IPATH_VERBS_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
index 10b31d2c4f2..085e28b939e 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -92,6 +93,7 @@ static struct ipath_mcast *ipath_mcast_alloc(union ib_gid *mgid)
INIT_LIST_HEAD(&mcast->qp_list);
init_waitqueue_head(&mcast->wait);
atomic_set(&mcast->refcount, 0);
+ mcast->n_attached = 0;
bail:
return mcast;
@@ -157,7 +159,8 @@ bail:
* the table but the QP was added. Return ESRCH if the QP was already
* attached and neither structure was added.
*/
-static int ipath_mcast_add(struct ipath_mcast *mcast,
+static int ipath_mcast_add(struct ipath_ibdev *dev,
+ struct ipath_mcast *mcast,
struct ipath_mcast_qp *mqp)
{
struct rb_node **n = &mcast_tree.rb_node;
@@ -188,34 +191,52 @@ static int ipath_mcast_add(struct ipath_mcast *mcast,
/* Search the QP list to see if this is already there. */
list_for_each_entry_rcu(p, &tmcast->qp_list, list) {
if (p->qp == mqp->qp) {
- spin_unlock_irqrestore(&mcast_lock, flags);
ret = ESRCH;
goto bail;
}
}
+ if (tmcast->n_attached == ib_ipath_max_mcast_qp_attached) {
+ ret = ENOMEM;
+ goto bail;
+ }
+
+ tmcast->n_attached++;
+
list_add_tail_rcu(&mqp->list, &tmcast->qp_list);
- spin_unlock_irqrestore(&mcast_lock, flags);
ret = EEXIST;
goto bail;
}
+ spin_lock(&dev->n_mcast_grps_lock);
+ if (dev->n_mcast_grps_allocated == ib_ipath_max_mcast_grps) {
+ spin_unlock(&dev->n_mcast_grps_lock);
+ ret = ENOMEM;
+ goto bail;
+ }
+
+ dev->n_mcast_grps_allocated++;
+ spin_unlock(&dev->n_mcast_grps_lock);
+
+ mcast->n_attached++;
+
list_add_tail_rcu(&mqp->list, &mcast->qp_list);
atomic_inc(&mcast->refcount);
rb_link_node(&mcast->rb_node, pn, n);
rb_insert_color(&mcast->rb_node, &mcast_tree);
- spin_unlock_irqrestore(&mcast_lock, flags);
-
ret = 0;
bail:
+ spin_unlock_irqrestore(&mcast_lock, flags);
+
return ret;
}
int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct ipath_qp *qp = to_iqp(ibqp);
+ struct ipath_ibdev *dev = to_idev(ibqp->device);
struct ipath_mcast *mcast;
struct ipath_mcast_qp *mqp;
int ret;
@@ -235,7 +256,7 @@ int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
ret = -ENOMEM;
goto bail;
}
- switch (ipath_mcast_add(mcast, mqp)) {
+ switch (ipath_mcast_add(dev, mcast, mqp)) {
case ESRCH:
/* Neither was used: can't attach the same QP twice. */
ipath_mcast_qp_free(mqp);
@@ -245,6 +266,12 @@ int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
case EEXIST: /* The mcast wasn't used */
ipath_mcast_free(mcast);
break;
+ case ENOMEM:
+ /* Exceeded the maximum number of mcast groups. */
+ ipath_mcast_qp_free(mqp);
+ ipath_mcast_free(mcast);
+ ret = -ENOMEM;
+ goto bail;
default:
break;
}
@@ -258,6 +285,7 @@ bail:
int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct ipath_qp *qp = to_iqp(ibqp);
+ struct ipath_ibdev *dev = to_idev(ibqp->device);
struct ipath_mcast *mcast = NULL;
struct ipath_mcast_qp *p, *tmp;
struct rb_node *n;
@@ -272,7 +300,7 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
while (1) {
if (n == NULL) {
spin_unlock_irqrestore(&mcast_lock, flags);
- ret = 0;
+ ret = -EINVAL;
goto bail;
}
@@ -296,6 +324,7 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
* link until we are sure there are no list walkers.
*/
list_del_rcu(&p->list);
+ mcast->n_attached--;
/* If this was the last attached QP, remove the GID too. */
if (list_empty(&mcast->qp_list)) {
@@ -319,6 +348,9 @@ int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
atomic_dec(&mcast->refcount);
wait_event(mcast->wait, !atomic_read(&mcast->refcount));
ipath_mcast_free(mcast);
+ spin_lock(&dev->n_mcast_grps_lock);
+ dev->n_mcast_grps_allocated--;
+ spin_unlock(&dev->n_mcast_grps_lock);
}
ret = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
new file mode 100644
index 00000000000..0095bb70f34
--- /dev/null
+++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * This file is conditionally built on PowerPC only. Otherwise weak symbol
+ * versions of the functions exported from here are used.
+ */
+
+#include "ipath_kernel.h"
+
+/**
+ * ipath_enable_wc - enable write combining for MMIO writes to the device
+ * @dd: infinipath device
+ *
+ * Nothing to do on PowerPC, so just return without error.
+ */
+int ipath_enable_wc(struct ipath_devdata *dd)
+{
+ return 0;
+}
+
+/**
+ * ipath_unordered_wc - indicate whether write combining is unordered
+ *
+ * Because our performance depends on our ability to do write
+ * combining mmio writes in the most efficient way, we need to
+ * know if we are on a processor that may reorder stores when
+ * write combining.
+ */
+int ipath_unordered_wc(void)
+{
+ return 1;
+}
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
index adc5322f15c..04696e62da8 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2006 QLogic, Inc. All rights reserved.
* Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
@@ -122,6 +123,8 @@ int ipath_enable_wc(struct ipath_devdata *dd)
ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, "
"cookie is %d\n", cookie);
dd->ipath_wc_cookie = cookie;
+ dd->ipath_wc_base = (unsigned long) pioaddr;
+ dd->ipath_wc_len = (unsigned long) piolen;
}
}
@@ -135,9 +138,16 @@ int ipath_enable_wc(struct ipath_devdata *dd)
void ipath_disable_wc(struct ipath_devdata *dd)
{
if (dd->ipath_wc_cookie) {
+ int r;
ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n");
- mtrr_del(dd->ipath_wc_cookie, 0, 0);
- dd->ipath_wc_cookie = 0;
+ r = mtrr_del(dd->ipath_wc_cookie, dd->ipath_wc_base,
+ dd->ipath_wc_len);
+ if (r < 0)
+ dev_info(&dd->pcidev->dev,
+ "mtrr_del(%lx, %lx, %lx) failed: %d\n",
+ dd->ipath_wc_cookie, dd->ipath_wc_base,
+ dd->ipath_wc_len, r);
+ dd->ipath_wc_cookie = 0; /* even on failure */
}
}
diff --git a/drivers/infiniband/hw/ipath/ips_common.h b/drivers/infiniband/hw/ipath/ips_common.h
deleted file mode 100644
index ab7cbbbfd03..00000000000
--- a/drivers/infiniband/hw/ipath/ips_common.h
+++ /dev/null
@@ -1,263 +0,0 @@
-#ifndef IPS_COMMON_H
-#define IPS_COMMON_H
-/*
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "ipath_common.h"
-
-struct ipath_header {
- /*
- * Version - 4 bits, Port - 4 bits, TID - 10 bits and Offset -
- * 14 bits before ECO change ~28 Dec 03. After that, Vers 4,
- * Port 3, TID 11, offset 14.
- */
- __le32 ver_port_tid_offset;
- __le16 chksum;
- __le16 pkt_flags;
-};
-
-struct ips_message_header {
- __be16 lrh[4];
- __be32 bth[3];
- /* fields below this point are in host byte order */
- struct ipath_header iph;
- __u8 sub_opcode;
- __u8 flags;
- __u16 src_rank;
- /* 24 bits. The upper 8 bit is available for other use */
- union {
- struct {
- unsigned ack_seq_num:24;
- unsigned port:4;
- unsigned unused:4;
- };
- __u32 ack_seq_num_org;
- };
- __u8 expected_tid_session_id;
- __u8 tinylen; /* to aid MPI */
- union {
- __u16 tag; /* to aid MPI */
- __u16 mqhdr; /* for PSM MQ */
- };
- union {
- __u32 mpi[4]; /* to aid MPI */
- __u32 data[4];
- __u64 mq[2]; /* for PSM MQ */
- struct {
- __u16 mtu;
- __u8 major_ver;
- __u8 minor_ver;
- __u32 not_used; //free
- __u32 run_id;
- __u32 client_ver;
- };
- };
-};
-
-struct ether_header {
- __be16 lrh[4];
- __be32 bth[3];
- struct ipath_header iph;
- __u8 sub_opcode;
- __u8 cmd;
- __be16 lid;
- __u16 mac[3];
- __u8 frag_num;
- __u8 seq_num;
- __le32 len;
- /* MUST be of word size due to PIO write requirements */
- __le32 csum;
- __le16 csum_offset;
- __le16 flags;
- __u16 first_2_bytes;
- __u8 unused[2]; /* currently unused */
-};
-
-/*
- * The PIO buffer used for sending infinipath messages must only be written
- * in 32-bit words, all the data must be written, and no writes can occur
- * after the last word is written (which transfers "ownership" of the buffer
- * to the chip and triggers the message to be sent).
- * Since the Linux sk_buff structure can be recursive, non-aligned, and
- * any number of bytes in each segment, we use the following structure
- * to keep information about the overall state of the copy operation.
- * This is used to save the information needed to store the checksum
- * in the right place before sending the last word to the hardware and
- * to buffer the last 0-3 bytes of non-word sized segments.
- */
-struct copy_data_s {
- struct ether_header *hdr;
- /* addr of PIO buf to write csum to */
- __u32 __iomem *csum_pio;
- __u32 __iomem *to; /* addr of PIO buf to write data to */
- __u32 device; /* which device to allocate PIO bufs from */
- __s32 error; /* set if there is an error. */
- __s32 extra; /* amount of data saved in u.buf below */
- __u32 len; /* total length to send in bytes */
- __u32 flen; /* frament length in words */
- __u32 csum; /* partial IP checksum */
- __u32 pos; /* position for partial checksum */
- __u32 offset; /* offset to where data currently starts */
- __s32 checksum_calc; /* set to 1 when csum has been calculated */
- struct sk_buff *skb;
- union {
- __u32 w;
- __u8 buf[4];
- } u;
-};
-
-/* IB - LRH header consts */
-#define IPS_LRH_GRH 0x0003 /* 1. word of IB LRH - next header: GRH */
-#define IPS_LRH_BTH 0x0002 /* 1. word of IB LRH - next header: BTH */
-
-#define IPS_OFFSET 0
-
-/*
- * defines the cut-off point between the header queue and eager/expected
- * TID queue
- */
-#define NUM_OF_EXTRA_WORDS_IN_HEADER_QUEUE \
- ((sizeof(struct ips_message_header) - \
- offsetof(struct ips_message_header, iph)) >> 2)
-
-/* OpCodes */
-#define OPCODE_IPS 0xC0
-#define OPCODE_ITH4X 0xC1
-
-/* OpCode 30 is use by stand-alone test programs */
-#define OPCODE_RAW_DATA 0xDE
-/* last OpCode (31) is reserved for test */
-#define OPCODE_TEST 0xDF
-
-/* sub OpCodes - ips */
-#define OPCODE_SEQ_DATA 0x01
-#define OPCODE_SEQ_CTRL 0x02
-
-#define OPCODE_SEQ_MQ_DATA 0x03
-#define OPCODE_SEQ_MQ_CTRL 0x04
-
-#define OPCODE_ACK 0x10
-#define OPCODE_NAK 0x11
-
-#define OPCODE_ERR_CHK 0x20
-#define OPCODE_ERR_CHK_PLS 0x21
-
-#define OPCODE_STARTUP 0x30
-#define OPCODE_STARTUP_ACK 0x31
-#define OPCODE_STARTUP_NAK 0x32
-
-#define OPCODE_STARTUP_EXT 0x34
-#define OPCODE_STARTUP_ACK_EXT 0x35
-#define OPCODE_STARTUP_NAK_EXT 0x36
-
-#define OPCODE_TIDS_RELEASE 0x40
-#define OPCODE_TIDS_RELEASE_CONFIRM 0x41
-
-#define OPCODE_CLOSE 0x50
-#define OPCODE_CLOSE_ACK 0x51
-/*
- * like OPCODE_CLOSE, but no complaint if other side has already closed.
- * Used when doing abort(), MPI_Abort(), etc.
- */
-#define OPCODE_ABORT 0x52
-
-/* sub OpCodes - ith4x */
-#define OPCODE_ENCAP 0x81
-#define OPCODE_LID_ARP 0x82
-
-/* Receive Header Queue: receive type (from infinipath) */
-#define RCVHQ_RCV_TYPE_EXPECTED 0
-#define RCVHQ_RCV_TYPE_EAGER 1
-#define RCVHQ_RCV_TYPE_NON_KD 2
-#define RCVHQ_RCV_TYPE_ERROR 3
-
-/* misc. */
-#define SIZE_OF_CRC 1
-
-#define EAGER_TID_ID INFINIPATH_I_TID_MASK
-
-#define IPS_DEFAULT_P_KEY 0xFFFF
-
-#define IPS_PERMISSIVE_LID 0xFFFF
-#define IPS_MULTICAST_LID_BASE 0xC000
-
-#define IPS_AETH_CREDIT_SHIFT 24
-#define IPS_AETH_CREDIT_MASK 0x1F
-#define IPS_AETH_CREDIT_INVAL 0x1F
-
-#define IPS_PSN_MASK 0xFFFFFF
-#define IPS_MSN_MASK 0xFFFFFF
-#define IPS_QPN_MASK 0xFFFFFF
-#define IPS_MULTICAST_QPN 0xFFFFFF
-
-/* functions for extracting fields from rcvhdrq entries */
-static inline __u32 ips_get_hdr_err_flags(const __le32 * rbuf)
-{
- return __le32_to_cpu(rbuf[1]);
-}
-
-static inline __u32 ips_get_index(const __le32 * rbuf)
-{
- return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_EGRINDEX_SHIFT)
- & INFINIPATH_RHF_EGRINDEX_MASK;
-}
-
-static inline __u32 ips_get_rcv_type(const __le32 * rbuf)
-{
- return (__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_RCVTYPE_SHIFT)
- & INFINIPATH_RHF_RCVTYPE_MASK;
-}
-
-static inline __u32 ips_get_length_in_bytes(const __le32 * rbuf)
-{
- return ((__le32_to_cpu(rbuf[0]) >> INFINIPATH_RHF_LENGTH_SHIFT)
- & INFINIPATH_RHF_LENGTH_MASK) << 2;
-}
-
-static inline void *ips_get_first_protocol_header(const __u32 * rbuf)
-{
- return (void *)&rbuf[2];
-}
-
-static inline struct ips_message_header *ips_get_ips_header(const __u32 *
- rbuf)
-{
- return (struct ips_message_header *)&rbuf[2];
-}
-
-static inline __u32 ips_get_ipath_ver(__le32 hdrword)
-{
- return (__le32_to_cpu(hdrword) >> INFINIPATH_I_VERS_SHIFT)
- & INFINIPATH_I_VERS_MASK;
-}
-
-#endif /* IPS_COMMON_H */
diff --git a/drivers/infiniband/hw/ipath/verbs_debug.h b/drivers/infiniband/hw/ipath/verbs_debug.h
deleted file mode 100644
index 40d693cf3f9..00000000000
--- a/drivers/infiniband/hw/ipath/verbs_debug.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * COPYING in the main directory of this source tree, or the
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _VERBS_DEBUG_H
-#define _VERBS_DEBUG_H
-
-/*
- * This file contains tracing code for the ib_ipath kernel module.
- */
-#ifndef _VERBS_DEBUGGING /* tracing enabled or not */
-#define _VERBS_DEBUGGING 1
-#endif
-
-extern unsigned ib_ipath_debug;
-
-#define _VERBS_ERROR(fmt,...) \
- do { \
- printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \
- } while(0)
-
-#define _VERBS_UNIT_ERROR(unit,fmt,...) \
- do { \
- printk(KERN_ERR "%s: " fmt, "ib_ipath", ##__VA_ARGS__); \
- } while(0)
-
-#if _VERBS_DEBUGGING
-
-/*
- * Mask values for debugging. The scheme allows us to compile out any
- * of the debug tracing stuff, and if compiled in, to enable or
- * disable dynamically.
- * This can be set at modprobe time also:
- * modprobe ib_path ib_ipath_debug=3
- */
-
-#define __VERBS_INFO 0x1 /* generic low verbosity stuff */
-#define __VERBS_DBG 0x2 /* generic debug */
-#define __VERBS_VDBG 0x4 /* verbose debug */
-#define __VERBS_SMADBG 0x8000 /* sma packet debug */
-
-#define _VERBS_INFO(fmt,...) \
- do { \
- if (unlikely(ib_ipath_debug&__VERBS_INFO)) \
- printk(KERN_INFO "%s: " fmt,"ib_ipath", \
- ##__VA_ARGS__); \
- } while(0)
-
-#define _VERBS_DBG(fmt,...) \
- do { \
- if (unlikely(ib_ipath_debug&__VERBS_DBG)) \
- printk(KERN_DEBUG "%s: " fmt, __func__, \
- ##__VA_ARGS__); \
- } while(0)
-
-#define _VERBS_VDBG(fmt,...) \
- do { \
- if (unlikely(ib_ipath_debug&__VERBS_VDBG)) \
- printk(KERN_DEBUG "%s: " fmt, __func__, \
- ##__VA_ARGS__); \
- } while(0)
-
-#define _VERBS_SMADBG(fmt,...) \
- do { \
- if (unlikely(ib_ipath_debug&__VERBS_SMADBG)) \
- printk(KERN_DEBUG "%s: " fmt, __func__, \
- ##__VA_ARGS__); \
- } while(0)
-
-#else /* ! _VERBS_DEBUGGING */
-
-#define _VERBS_INFO(fmt,...)
-#define _VERBS_DBG(fmt,...)
-#define _VERBS_VDBG(fmt,...)
-#define _VERBS_SMADBG(fmt,...)
-
-#endif /* _VERBS_DEBUGGING */
-
-#endif /* _VERBS_DEBUG_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_allocator.c b/drivers/infiniband/hw/mthca/mthca_allocator.c
index 9ba3211cef7..f930e55b58f 100644
--- a/drivers/infiniband/hw/mthca/mthca_allocator.c
+++ b/drivers/infiniband/hw/mthca/mthca_allocator.c
@@ -41,9 +41,11 @@
/* Trivial bitmap-based allocator */
u32 mthca_alloc(struct mthca_alloc *alloc)
{
+ unsigned long flags;
u32 obj;
- spin_lock(&alloc->lock);
+ spin_lock_irqsave(&alloc->lock, flags);
+
obj = find_next_zero_bit(alloc->table, alloc->max, alloc->last);
if (obj >= alloc->max) {
alloc->top = (alloc->top + alloc->max) & alloc->mask;
@@ -56,19 +58,24 @@ u32 mthca_alloc(struct mthca_alloc *alloc)
} else
obj = -1;
- spin_unlock(&alloc->lock);
+ spin_unlock_irqrestore(&alloc->lock, flags);
return obj;
}
void mthca_free(struct mthca_alloc *alloc, u32 obj)
{
+ unsigned long flags;
+
obj &= alloc->max - 1;
- spin_lock(&alloc->lock);
+
+ spin_lock_irqsave(&alloc->lock, flags);
+
clear_bit(obj, alloc->table);
alloc->last = min(alloc->last, obj);
alloc->top = (alloc->top + alloc->max) & alloc->mask;
- spin_unlock(&alloc->lock);
+
+ spin_unlock_irqrestore(&alloc->lock, flags);
}
int mthca_alloc_init(struct mthca_alloc *alloc, u32 num, u32 mask,
@@ -108,14 +115,15 @@ void mthca_alloc_cleanup(struct mthca_alloc *alloc)
* serialize access to the array.
*/
+#define MTHCA_ARRAY_MASK (PAGE_SIZE / sizeof (void *) - 1)
+
void *mthca_array_get(struct mthca_array *array, int index)
{
int p = (index * sizeof (void *)) >> PAGE_SHIFT;
- if (array->page_list[p].page) {
- int i = index & (PAGE_SIZE / sizeof (void *) - 1);
- return array->page_list[p].page[i];
- } else
+ if (array->page_list[p].page)
+ return array->page_list[p].page[index & MTHCA_ARRAY_MASK];
+ else
return NULL;
}
@@ -130,8 +138,7 @@ int mthca_array_set(struct mthca_array *array, int index, void *value)
if (!array->page_list[p].page)
return -ENOMEM;
- array->page_list[p].page[index & (PAGE_SIZE / sizeof (void *) - 1)] =
- value;
+ array->page_list[p].page[index & MTHCA_ARRAY_MASK] = value;
++array->page_list[p].used;
return 0;
@@ -144,7 +151,8 @@ void mthca_array_clear(struct mthca_array *array, int index)
if (--array->page_list[p].used == 0) {
free_page((unsigned long) array->page_list[p].page);
array->page_list[p].page = NULL;
- }
+ } else
+ array->page_list[p].page[index & MTHCA_ARRAY_MASK] = NULL;
if (array->page_list[p].used < 0)
pr_debug("Array %p index %d page %d with ref count %d < 0\n",
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index b12aa03be25..69599455aca 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -90,7 +90,7 @@ static enum ib_rate tavor_rate_to_ib(u8 mthca_rate, u8 port_rate)
case MTHCA_RATE_TAVOR_1X: return IB_RATE_2_5_GBPS;
case MTHCA_RATE_TAVOR_1X_DDR: return IB_RATE_5_GBPS;
case MTHCA_RATE_TAVOR_4X: return IB_RATE_10_GBPS;
- default: return port_rate;
+ default: return mult_to_ib_rate(port_rate);
}
}
@@ -303,9 +303,10 @@ int mthca_ah_query(struct ib_ah *ibah, struct ib_ah_attr *attr)
memset(attr, 0, sizeof *attr);
attr->dlid = be16_to_cpu(ah->av->dlid);
attr->sl = be32_to_cpu(ah->av->sl_tclass_flowlabel) >> 28;
- attr->static_rate = ah->av->msg_sr & 0x7;
- attr->src_path_bits = ah->av->g_slid & 0x7F;
attr->port_num = be32_to_cpu(ah->av->port_pd) >> 24;
+ attr->static_rate = mthca_rate_to_ib(dev, ah->av->msg_sr & 0x7,
+ attr->port_num);
+ attr->src_path_bits = ah->av->g_slid & 0x7F;
attr->ah_flags = mthca_ah_grh_present(ah) ? IB_AH_GRH : 0;
if (attr->ah_flags) {
diff --git a/drivers/infiniband/hw/mthca/mthca_catas.c b/drivers/infiniband/hw/mthca/mthca_catas.c
index c3bec7490f5..cd044ea2dfa 100644
--- a/drivers/infiniband/hw/mthca/mthca_catas.c
+++ b/drivers/infiniband/hw/mthca/mthca_catas.c
@@ -34,6 +34,7 @@
#include <linux/jiffies.h>
#include <linux/timer.h>
+#include <linux/workqueue.h>
#include "mthca_dev.h"
@@ -48,9 +49,41 @@ enum {
static DEFINE_SPINLOCK(catas_lock);
+static LIST_HEAD(catas_list);
+static struct workqueue_struct *catas_wq;
+static struct work_struct catas_work;
+
+static int catas_reset_disable;
+module_param_named(catas_reset_disable, catas_reset_disable, int, 0644);
+MODULE_PARM_DESC(catas_reset_disable, "disable reset on catastrophic event if nonzero");
+
+static void catas_reset(void *work_ptr)
+{
+ struct mthca_dev *dev, *tmpdev;
+ LIST_HEAD(tlist);
+ int ret;
+
+ mutex_lock(&mthca_device_mutex);
+
+ spin_lock_irq(&catas_lock);
+ list_splice_init(&catas_list, &tlist);
+ spin_unlock_irq(&catas_lock);
+
+ list_for_each_entry_safe(dev, tmpdev, &tlist, catas_err.list) {
+ ret = __mthca_restart_one(dev->pdev);
+ if (ret)
+ mthca_err(dev, "Reset failed (%d)\n", ret);
+ else
+ mthca_dbg(dev, "Reset succeeded\n");
+ }
+
+ mutex_unlock(&mthca_device_mutex);
+}
+
static void handle_catas(struct mthca_dev *dev)
{
struct ib_event event;
+ unsigned long flags;
const char *type;
int i;
@@ -82,6 +115,14 @@ static void handle_catas(struct mthca_dev *dev)
for (i = 0; i < dev->catas_err.size; ++i)
mthca_err(dev, " buf[%02x]: %08x\n",
i, swab32(readl(dev->catas_err.map + i)));
+
+ if (catas_reset_disable)
+ return;
+
+ spin_lock_irqsave(&catas_lock, flags);
+ list_add(&dev->catas_err.list, &catas_list);
+ queue_work(catas_wq, &catas_work);
+ spin_unlock_irqrestore(&catas_lock, flags);
}
static void poll_catas(unsigned long dev_ptr)
@@ -135,6 +176,7 @@ void mthca_start_catas_poll(struct mthca_dev *dev)
dev->catas_err.timer.data = (unsigned long) dev;
dev->catas_err.timer.function = poll_catas;
dev->catas_err.timer.expires = jiffies + MTHCA_CATAS_POLL_INTERVAL;
+ INIT_LIST_HEAD(&dev->catas_err.list);
add_timer(&dev->catas_err.timer);
}
@@ -153,4 +195,24 @@ void mthca_stop_catas_poll(struct mthca_dev *dev)
dev->catas_err.addr),
dev->catas_err.size * 4);
}
+
+ spin_lock_irq(&catas_lock);
+ list_del(&dev->catas_err.list);
+ spin_unlock_irq(&catas_lock);
+}
+
+int __init mthca_catas_init(void)
+{
+ INIT_WORK(&catas_work, catas_reset, NULL);
+
+ catas_wq = create_singlethread_workqueue("mthca_catas");
+ if (!catas_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mthca_catas_cleanup(void)
+{
+ destroy_workqueue(catas_wq);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index d0f7731802c..99a94d71093 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -34,7 +34,7 @@
* $Id: mthca_cmd.c 1349 2004-12-16 21:09:43Z roland $
*/
-#include <linux/sched.h>
+#include <linux/completion.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <asm/io.h>
@@ -778,11 +778,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
((dev->fw_ver & 0xffff0000ull) >> 16) |
((dev->fw_ver & 0x0000ffffull) << 16);
+ MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
+ dev->cmd.max_cmds = 1 << lg;
+
mthca_dbg(dev, "FW version %012llx, max commands %d\n",
(unsigned long long) dev->fw_ver, dev->cmd.max_cmds);
- MTHCA_GET(lg, outbox, QUERY_FW_MAX_CMD_OFFSET);
- dev->cmd.max_cmds = 1 << lg;
MTHCA_GET(dev->catas_err.addr, outbox, QUERY_FW_ERR_START_OFFSET);
MTHCA_GET(dev->catas_err.size, outbox, QUERY_FW_ERR_SIZE_OFFSET);
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 3e27a084257..e393681ba7d 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -544,11 +544,11 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
wq = &(*cur_qp)->rq;
wqe = be32_to_cpu(cqe->wqe);
wqe_index = wqe >> wq->wqe_shift;
- /*
- * WQE addr == base - 1 might be reported in receive completion
- * with error instead of (rq size - 1) by Sinai FW 1.0.800 and
- * Arbel FW 5.1.400. This bug should be fixed in later FW revs.
- */
+ /*
+ * WQE addr == base - 1 might be reported in receive completion
+ * with error instead of (rq size - 1) by Sinai FW 1.0.800 and
+ * Arbel FW 5.1.400. This bug should be fixed in later FW revs.
+ */
if (unlikely(wqe_index < 0))
wqe_index = wq->max - 1;
entry->wr_id = (*cur_qp)->wrid[wqe_index];
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index f8160b8de09..fe5cecf70fe 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -45,6 +45,7 @@
#include <linux/dma-mapping.h>
#include <linux/timer.h>
#include <linux/mutex.h>
+#include <linux/list.h>
#include <asm/semaphore.h>
@@ -283,8 +284,11 @@ struct mthca_catas_err {
unsigned long stop;
u32 size;
struct timer_list timer;
+ struct list_head list;
};
+extern struct mutex mthca_device_mutex;
+
struct mthca_dev {
struct ib_device ib_dev;
struct pci_dev *pdev;
@@ -450,6 +454,9 @@ void mthca_unregister_device(struct mthca_dev *dev);
void mthca_start_catas_poll(struct mthca_dev *dev);
void mthca_stop_catas_poll(struct mthca_dev *dev);
+int __mthca_restart_one(struct pci_dev *pdev);
+int mthca_catas_init(void);
+void mthca_catas_cleanup(void);
int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar);
void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
@@ -506,7 +513,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
struct ib_srq_attr *attr, struct mthca_srq *srq);
void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq);
int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
- enum ib_srq_attr_mask attr_mask);
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);
int mthca_query_srq(struct ib_srq *srq, struct ib_srq_attr *srq_attr);
int mthca_max_srq_sge(struct mthca_dev *dev);
void mthca_srq_event(struct mthca_dev *dev, u32 srqn,
@@ -521,7 +528,8 @@ void mthca_qp_event(struct mthca_dev *dev, u32 qpn,
enum ib_event_type event_type);
int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_mask,
struct ib_qp_init_attr *qp_init_attr);
-int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask);
+int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata);
int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr);
int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index d536217e700..a29b1b6d82b 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -900,7 +900,7 @@ int __devinit mthca_init_eq_table(struct mthca_dev *dev)
mthca_is_memfree(dev) ?
mthca_arbel_interrupt :
mthca_tavor_interrupt,
- SA_SHIRQ, DRV_NAME, dev);
+ IRQF_SHARED, DRV_NAME, dev);
if (err)
goto err_out_cmd;
dev->eq_table.have_irq = 1;
diff --git a/drivers/infiniband/hw/mthca/mthca_mad.c b/drivers/infiniband/hw/mthca/mthca_mad.c
index d9bc030bccc..45e106f1480 100644
--- a/drivers/infiniband/hw/mthca/mthca_mad.c
+++ b/drivers/infiniband/hw/mthca/mthca_mad.c
@@ -119,7 +119,7 @@ static void smp_snoop(struct ib_device *ibdev,
mthca_update_rate(to_mdev(ibdev), port_num);
update_sm_ah(to_mdev(ibdev), port_num,
- be16_to_cpu(pinfo->lid),
+ be16_to_cpu(pinfo->sm_lid),
pinfo->neighbormtu_mastersmsl & 0xf);
event.device = ibdev;
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index 9b9ff7bff35..47ea0214836 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -34,7 +34,6 @@
* $Id: mthca_main.c 1396 2004-12-28 04:10:27Z roland $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -81,6 +80,8 @@ static int tune_pci = 0;
module_param(tune_pci, int, 0444);
MODULE_PARM_DESC(tune_pci, "increase PCI burst from the default set by BIOS if nonzero");
+struct mutex mthca_device_mutex;
+
static const char mthca_version[] __devinitdata =
DRV_NAME ": Mellanox InfiniBand HCA driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -172,8 +173,9 @@ static int __devinit mthca_dev_lim(struct mthca_dev *mdev, struct mthca_dev_lim
if (dev_lim->uar_size > pci_resource_len(mdev->pdev, 2)) {
mthca_err(mdev, "HCA reported UAR size of 0x%x bigger than "
- "PCI resource 2 size of 0x%lx, aborting.\n",
- dev_lim->uar_size, pci_resource_len(mdev->pdev, 2));
+ "PCI resource 2 size of 0x%llx, aborting.\n",
+ dev_lim->uar_size,
+ (unsigned long long)pci_resource_len(mdev->pdev, 2));
return -ENODEV;
}
@@ -967,39 +969,26 @@ static struct {
} mthca_hca_table[] = {
[TAVOR] = { .latest_fw = MTHCA_FW_VER(3, 4, 0),
.flags = 0 },
- [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 400),
+ [ARBEL_COMPAT] = { .latest_fw = MTHCA_FW_VER(4, 7, 600),
.flags = MTHCA_FLAG_PCIE },
- [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 0),
+ [ARBEL_NATIVE] = { .latest_fw = MTHCA_FW_VER(5, 1, 400),
.flags = MTHCA_FLAG_MEMFREE |
MTHCA_FLAG_PCIE },
- [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 0, 800),
+ [SINAI] = { .latest_fw = MTHCA_FW_VER(1, 1, 0),
.flags = MTHCA_FLAG_MEMFREE |
MTHCA_FLAG_PCIE |
MTHCA_FLAG_SINAI_OPT }
};
-static int __devinit mthca_init_one(struct pci_dev *pdev,
- const struct pci_device_id *id)
+static int __mthca_init_one(struct pci_dev *pdev, int hca_type)
{
- static int mthca_version_printed = 0;
int ddr_hidden = 0;
int err;
struct mthca_dev *mdev;
- if (!mthca_version_printed) {
- printk(KERN_INFO "%s", mthca_version);
- ++mthca_version_printed;
- }
-
printk(KERN_INFO PFX "Initializing %s\n",
pci_name(pdev));
- if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) {
- printk(KERN_ERR PFX "%s has invalid driver data %lx\n",
- pci_name(pdev), id->driver_data);
- return -ENODEV;
- }
-
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable PCI device, "
@@ -1065,7 +1054,7 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
mdev->pdev = pdev;
- mdev->mthca_flags = mthca_hca_table[id->driver_data].flags;
+ mdev->mthca_flags = mthca_hca_table[hca_type].flags;
if (ddr_hidden)
mdev->mthca_flags |= MTHCA_FLAG_DDR_HIDDEN;
@@ -1099,13 +1088,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
if (err)
goto err_cmd;
- if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
+ if (mdev->fw_ver < mthca_hca_table[hca_type].latest_fw) {
mthca_warn(mdev, "HCA FW version %d.%d.%d is old (%d.%d.%d is current).\n",
(int) (mdev->fw_ver >> 32), (int) (mdev->fw_ver >> 16) & 0xffff,
(int) (mdev->fw_ver & 0xffff),
- (int) (mthca_hca_table[id->driver_data].latest_fw >> 32),
- (int) (mthca_hca_table[id->driver_data].latest_fw >> 16) & 0xffff,
- (int) (mthca_hca_table[id->driver_data].latest_fw & 0xffff));
+ (int) (mthca_hca_table[hca_type].latest_fw >> 32),
+ (int) (mthca_hca_table[hca_type].latest_fw >> 16) & 0xffff,
+ (int) (mthca_hca_table[hca_type].latest_fw & 0xffff));
mthca_warn(mdev, "If you have problems, try updating your HCA FW.\n");
}
@@ -1122,6 +1111,7 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
goto err_unregister;
pci_set_drvdata(pdev, mdev);
+ mdev->hca_type = hca_type;
return 0;
@@ -1166,7 +1156,7 @@ err_disable_pdev:
return err;
}
-static void __devexit mthca_remove_one(struct pci_dev *pdev)
+static void __mthca_remove_one(struct pci_dev *pdev)
{
struct mthca_dev *mdev = pci_get_drvdata(pdev);
u8 status;
@@ -1211,6 +1201,51 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
}
}
+int __mthca_restart_one(struct pci_dev *pdev)
+{
+ struct mthca_dev *mdev;
+
+ mdev = pci_get_drvdata(pdev);
+ if (!mdev)
+ return -ENODEV;
+ __mthca_remove_one(pdev);
+ return __mthca_init_one(pdev, mdev->hca_type);
+}
+
+static int __devinit mthca_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static int mthca_version_printed = 0;
+ int ret;
+
+ mutex_lock(&mthca_device_mutex);
+
+ if (!mthca_version_printed) {
+ printk(KERN_INFO "%s", mthca_version);
+ ++mthca_version_printed;
+ }
+
+ if (id->driver_data >= ARRAY_SIZE(mthca_hca_table)) {
+ printk(KERN_ERR PFX "%s has invalid driver data %lx\n",
+ pci_name(pdev), id->driver_data);
+ mutex_unlock(&mthca_device_mutex);
+ return -ENODEV;
+ }
+
+ ret = __mthca_init_one(pdev, id->driver_data);
+
+ mutex_unlock(&mthca_device_mutex);
+
+ return ret;
+}
+
+static void __devexit mthca_remove_one(struct pci_dev *pdev)
+{
+ mutex_lock(&mthca_device_mutex);
+ __mthca_remove_one(pdev);
+ mutex_unlock(&mthca_device_mutex);
+}
+
static struct pci_device_id mthca_pci_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MELLANOX, PCI_DEVICE_ID_MELLANOX_TAVOR),
.driver_data = TAVOR },
@@ -1248,13 +1283,24 @@ static int __init mthca_init(void)
{
int ret;
+ mutex_init(&mthca_device_mutex);
+ ret = mthca_catas_init();
+ if (ret)
+ return ret;
+
ret = pci_register_driver(&mthca_driver);
- return ret < 0 ? ret : 0;
+ if (ret < 0) {
+ mthca_catas_cleanup();
+ return ret;
+ }
+
+ return 0;
}
static void __exit mthca_cleanup(void)
{
pci_unregister_driver(&mthca_driver);
+ mthca_catas_cleanup();
}
module_init(mthca_init);
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 230ae21db8f..981fe2eebdf 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1287,12 +1287,8 @@ int mthca_register_device(struct mthca_dev *dev)
(1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
(1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
(1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) |
- (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) |
- (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
- (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
- (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
- (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
- dev->ib_dev.node_type = IB_NODE_CA;
+ (1ull << IB_USER_VERBS_CMD_DETACH_MCAST);
+ dev->ib_dev.node_type = RDMA_NODE_IB_CA;
dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
dev->ib_dev.dma_device = &dev->pdev->dev;
dev->ib_dev.class_dev.dev = &dev->pdev->dev;
@@ -1316,6 +1312,11 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.modify_srq = mthca_modify_srq;
dev->ib_dev.query_srq = mthca_query_srq;
dev->ib_dev.destroy_srq = mthca_destroy_srq;
+ dev->ib_dev.uverbs_cmd_mask |=
+ (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
if (mthca_is_memfree(dev))
dev->ib_dev.post_srq_recv = mthca_arbel_post_srq_recv;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 8de2887ba15..9a5bece3fa5 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -136,8 +136,8 @@ struct mthca_ah {
* We have one global lock that protects dev->cq/qp_table. Each
* struct mthca_cq/qp also has its own lock. An individual qp lock
* may be taken inside of an individual cq lock. Both cqs attached to
- * a qp may be locked, with the send cq locked first. No other
- * nesting should be done.
+ * a qp may be locked, with the cq with the lower cqn locked first.
+ * No other nesting should be done.
*
* Each struct mthca_cq/qp also has an ref count, protected by the
* corresponding table lock. The pointer from the cq/qp_table to the
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 16c387d8170..5e5c58b9920 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -99,6 +99,10 @@ enum {
MTHCA_QP_BIT_RSC = 1 << 3
};
+enum {
+ MTHCA_SEND_DOORBELL_FENCE = 1 << 5
+};
+
struct mthca_qp_path {
__be32 port_pkey;
u8 rnr_retry;
@@ -222,9 +226,8 @@ static void *get_send_wqe(struct mthca_qp *qp, int n)
(PAGE_SIZE - 1));
}
-static void mthca_wq_init(struct mthca_wq *wq)
+static void mthca_wq_reset(struct mthca_wq *wq)
{
- spin_lock_init(&wq->lock);
wq->next_ind = 0;
wq->last_comp = wq->max - 1;
wq->head = 0;
@@ -405,7 +408,7 @@ static void to_ib_ah_attr(struct mthca_dev *dev, struct ib_ah_attr *ib_ah_attr,
ib_ah_attr->sl = be32_to_cpu(path->sl_tclass_flowlabel) >> 28;
ib_ah_attr->src_path_bits = path->g_mylmc & 0x7f;
ib_ah_attr->static_rate = mthca_rate_to_ib(dev,
- path->static_rate & 0x7,
+ path->static_rate & 0xf,
ib_ah_attr->port_num);
ib_ah_attr->ah_flags = (path->g_mylmc & (1 << 7)) ? IB_AH_GRH : 0;
if (ib_ah_attr->ah_flags) {
@@ -469,10 +472,14 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
if (qp->transport == RC || qp->transport == UC) {
to_ib_ah_attr(dev, &qp_attr->ah_attr, &context->pri_path);
to_ib_ah_attr(dev, &qp_attr->alt_ah_attr, &context->alt_path);
+ qp_attr->alt_pkey_index =
+ be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
+ qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
}
- qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
- qp_attr->alt_pkey_index = be32_to_cpu(context->alt_path.port_pkey) & 0x7f;
+ qp_attr->pkey_index = be32_to_cpu(context->pri_path.port_pkey) & 0x7f;
+ qp_attr->port_num =
+ (be32_to_cpu(context->pri_path.port_pkey) >> 24) & 0x3;
/* qp_attr->en_sqd_async_notify is only applicable in modify qp */
qp_attr->sq_draining = mthca_state == MTHCA_QP_STATE_DRAINING;
@@ -483,11 +490,9 @@ int mthca_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, int qp_attr_m
1 << ((be32_to_cpu(context->params2) >> 21) & 0x7);
qp_attr->min_rnr_timer =
(be32_to_cpu(context->rnr_nextrecvpsn) >> 24) & 0x1f;
- qp_attr->port_num = qp_attr->ah_attr.port_num;
qp_attr->timeout = context->pri_path.ackto >> 3;
qp_attr->retry_cnt = (be32_to_cpu(context->params1) >> 16) & 0x7;
qp_attr->rnr_retry = context->pri_path.rnr_retry >> 5;
- qp_attr->alt_port_num = qp_attr->alt_ah_attr.port_num;
qp_attr->alt_timeout = context->alt_path.ackto >> 3;
qp_init_attr->cap = qp_attr->cap;
@@ -524,7 +529,8 @@ static int mthca_path_set(struct mthca_dev *dev, struct ib_ah_attr *ah,
return 0;
}
-int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
+int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask,
+ struct ib_udata *udata)
{
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
@@ -839,16 +845,15 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
* entries and reinitialize the QP.
*/
if (new_state == IB_QPS_RESET && !qp->ibqp.uobject) {
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn,
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq), qp->qpn,
- qp->ibqp.srq ? to_msrq(qp->ibqp.srq) : NULL);
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq), qp->qpn, NULL);
- mthca_wq_init(&qp->sq);
+ mthca_wq_reset(&qp->sq);
qp->sq.last = get_send_wqe(qp, qp->sq.max - 1);
- mthca_wq_init(&qp->rq);
+ mthca_wq_reset(&qp->rq);
qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1);
if (mthca_is_memfree(dev)) {
@@ -1112,8 +1117,11 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
qp->atomic_rd_en = 0;
qp->resp_depth = 0;
qp->sq_policy = send_policy;
- mthca_wq_init(&qp->sq);
- mthca_wq_init(&qp->rq);
+ mthca_wq_reset(&qp->sq);
+ mthca_wq_reset(&qp->rq);
+
+ spin_lock_init(&qp->sq.lock);
+ spin_lock_init(&qp->rq.lock);
ret = mthca_map_memfree(dev, qp);
if (ret)
@@ -1257,6 +1265,32 @@ int mthca_alloc_qp(struct mthca_dev *dev,
return 0;
}
+static void mthca_lock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq)
+{
+ if (send_cq == recv_cq)
+ spin_lock_irq(&send_cq->lock);
+ else if (send_cq->cqn < recv_cq->cqn) {
+ spin_lock_irq(&send_cq->lock);
+ spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
+ } else {
+ spin_lock_irq(&recv_cq->lock);
+ spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
+ }
+}
+
+static void mthca_unlock_cqs(struct mthca_cq *send_cq, struct mthca_cq *recv_cq)
+{
+ if (send_cq == recv_cq)
+ spin_unlock_irq(&send_cq->lock);
+ else if (send_cq->cqn < recv_cq->cqn) {
+ spin_unlock(&recv_cq->lock);
+ spin_unlock_irq(&send_cq->lock);
+ } else {
+ spin_unlock(&send_cq->lock);
+ spin_unlock_irq(&recv_cq->lock);
+ }
+}
+
int mthca_alloc_sqp(struct mthca_dev *dev,
struct mthca_pd *pd,
struct mthca_cq *send_cq,
@@ -1309,17 +1343,13 @@ int mthca_alloc_sqp(struct mthca_dev *dev,
* Lock CQs here, so that CQ polling code can do QP lookup
* without taking a lock.
*/
- spin_lock_irq(&send_cq->lock);
- if (send_cq != recv_cq)
- spin_lock(&recv_cq->lock);
+ mthca_lock_cqs(send_cq, recv_cq);
spin_lock(&dev->qp_table.lock);
mthca_array_clear(&dev->qp_table.qp, mqpn);
spin_unlock(&dev->qp_table.lock);
- if (send_cq != recv_cq)
- spin_unlock(&recv_cq->lock);
- spin_unlock_irq(&send_cq->lock);
+ mthca_unlock_cqs(send_cq, recv_cq);
err_out:
dma_free_coherent(&dev->pdev->dev, sqp->header_buf_size,
@@ -1353,9 +1383,7 @@ void mthca_free_qp(struct mthca_dev *dev,
* Lock CQs here, so that CQ polling code can do QP lookup
* without taking a lock.
*/
- spin_lock_irq(&send_cq->lock);
- if (send_cq != recv_cq)
- spin_lock(&recv_cq->lock);
+ mthca_lock_cqs(send_cq, recv_cq);
spin_lock(&dev->qp_table.lock);
mthca_array_clear(&dev->qp_table.qp,
@@ -1363,9 +1391,7 @@ void mthca_free_qp(struct mthca_dev *dev,
--qp->refcount;
spin_unlock(&dev->qp_table.lock);
- if (send_cq != recv_cq)
- spin_unlock(&recv_cq->lock);
- spin_unlock_irq(&send_cq->lock);
+ mthca_unlock_cqs(send_cq, recv_cq);
wait_event(qp->wait, !get_qp_refcount(dev, qp));
@@ -1500,7 +1526,7 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int i;
int size;
int size0 = 0;
- u32 f0 = 0;
+ u32 f0;
int ind;
u8 op0 = 0;
@@ -1684,6 +1710,8 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
if (!size0) {
size0 = size;
op0 = mthca_opcode[wr->opcode];
+ f0 = wr->send_flags & IB_SEND_FENCE ?
+ MTHCA_SEND_DOORBELL_FENCE : 0;
}
++ind;
@@ -1841,7 +1869,7 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
int i;
int size;
int size0 = 0;
- u32 f0 = 0;
+ u32 f0;
int ind;
u8 op0 = 0;
@@ -2049,6 +2077,8 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
if (!size0) {
size0 = size;
op0 = mthca_opcode[wr->opcode];
+ f0 = wr->send_flags & IB_SEND_FENCE ?
+ MTHCA_SEND_DOORBELL_FENCE : 0;
}
++ind;
diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c
index f4fddd5327f..91934f2d9db 100644
--- a/drivers/infiniband/hw/mthca/mthca_reset.c
+++ b/drivers/infiniband/hw/mthca/mthca_reset.c
@@ -32,7 +32,6 @@
* $Id: mthca_reset.c 1349 2004-12-16 21:09:43Z roland $
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index fab417c5cf4..0f316c87bf6 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -358,7 +358,7 @@ void mthca_free_srq(struct mthca_dev *dev, struct mthca_srq *srq)
}
int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
- enum ib_srq_attr_mask attr_mask)
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
{
struct mthca_dev *dev = to_mdev(ibsrq->device);
struct mthca_srq *srq = to_msrq(ibsrq);
@@ -370,7 +370,8 @@ int mthca_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
return -EINVAL;
if (attr_mask & IB_SRQ_LIMIT) {
- if (attr->srq_limit > srq->max)
+ u32 max_wr = mthca_is_memfree(dev) ? srq->max - 1 : srq->max;
+ if (attr->srq_limit > max_wr)
return -EINVAL;
mutex_lock(&srq->mutex);
diff --git a/drivers/infiniband/hw/mthca/mthca_uar.c b/drivers/infiniband/hw/mthca/mthca_uar.c
index 8e9219842be..8b728486410 100644
--- a/drivers/infiniband/hw/mthca/mthca_uar.c
+++ b/drivers/infiniband/hw/mthca/mthca_uar.c
@@ -60,7 +60,7 @@ int mthca_init_uar_table(struct mthca_dev *dev)
ret = mthca_alloc_init(&dev->uar_table.alloc,
dev->limits.num_uars,
dev->limits.num_uars - 1,
- dev->limits.reserved_uars);
+ dev->limits.reserved_uars + 1);
if (ret)
return ret;
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index 13d6d01c72c..d74653d7de1 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -6,8 +6,7 @@ config INFINIBAND_IPOIB
transports IP packets over InfiniBand so you can use your IB
device as a fancy NIC.
- The IPoIB protocol is defined by the IETF ipoib working
- group: <http://www.ietf.org/html.charters/ipoib-charter.html>.
+ See Documentation/infiniband/ipoib.txt for more information
config INFINIBAND_IPOIB_DEBUG
bool "IP-over-InfiniBand debugging" if EMBEDDED
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 491d2afaf5b..0b8a79d53a0 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -42,7 +42,6 @@
#include <linux/netdevice.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
-#include <linux/config.h>
#include <linux/kref.h>
#include <linux/if_infiniband.h>
#include <linux/mutex.h>
@@ -213,6 +212,7 @@ struct ipoib_path {
struct ipoib_neigh {
struct ipoib_ah *ah;
+ union ib_gid dgid;
struct sk_buff_head queue;
struct neighbour *neighbour;
@@ -336,6 +336,8 @@ static inline void ipoib_unregister_debugfs(void) { }
extern int ipoib_sendq_size;
extern int ipoib_recvq_size;
+extern struct ib_sa_client ipoib_sa_client;
+
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
extern int ipoib_debug_level;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index 5dde380e8db..f1cb83688b3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -141,7 +141,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file)
return ret;
seq = file->private_data;
- seq->private = inode->u.generic_ip;
+ seq->private = inode->i_private;
return 0;
}
@@ -247,7 +247,7 @@ static int ipoib_path_open(struct inode *inode, struct file *file)
return ret;
seq = file->private_data;
- seq->private = inode->u.generic_ip;
+ seq->private = inode->i_private;
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 5033666b148..f426a69d9a4 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -169,117 +169,129 @@ static int ipoib_ib_post_receives(struct net_device *dev)
return 0;
}
-static void ipoib_ib_handle_wc(struct net_device *dev,
- struct ib_wc *wc)
+static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- unsigned int wr_id = wc->wr_id;
+ unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
+ struct sk_buff *skb;
+ dma_addr_t addr;
- ipoib_dbg_data(priv, "called: id %d, op %d, status: %d\n",
+ ipoib_dbg_data(priv, "recv completion: id %d, op %d, status: %d\n",
wr_id, wc->opcode, wc->status);
- if (wr_id & IPOIB_OP_RECV) {
- wr_id &= ~IPOIB_OP_RECV;
-
- if (wr_id < ipoib_recvq_size) {
- struct sk_buff *skb = priv->rx_ring[wr_id].skb;
- dma_addr_t addr = priv->rx_ring[wr_id].mapping;
-
- if (unlikely(wc->status != IB_WC_SUCCESS)) {
- if (wc->status != IB_WC_WR_FLUSH_ERR)
- ipoib_warn(priv, "failed recv event "
- "(status=%d, wrid=%d vend_err %x)\n",
- wc->status, wr_id, wc->vendor_err);
- dma_unmap_single(priv->ca->dma_device, addr,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
- dev_kfree_skb_any(skb);
- priv->rx_ring[wr_id].skb = NULL;
- return;
- }
+ if (unlikely(wr_id >= ipoib_recvq_size)) {
+ ipoib_warn(priv, "recv completion event with wrid %d (> %d)\n",
+ wr_id, ipoib_recvq_size);
+ return;
+ }
- /*
- * If we can't allocate a new RX buffer, dump
- * this packet and reuse the old buffer.
- */
- if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
- ++priv->stats.rx_dropped;
- goto repost;
- }
+ skb = priv->rx_ring[wr_id].skb;
+ addr = priv->rx_ring[wr_id].mapping;
- ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
- wc->byte_len, wc->slid);
+ if (unlikely(wc->status != IB_WC_SUCCESS)) {
+ if (wc->status != IB_WC_WR_FLUSH_ERR)
+ ipoib_warn(priv, "failed recv event "
+ "(status=%d, wrid=%d vend_err %x)\n",
+ wc->status, wr_id, wc->vendor_err);
+ dma_unmap_single(priv->ca->dma_device, addr,
+ IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ priv->rx_ring[wr_id].skb = NULL;
+ return;
+ }
- dma_unmap_single(priv->ca->dma_device, addr,
- IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
+ /*
+ * If we can't allocate a new RX buffer, dump
+ * this packet and reuse the old buffer.
+ */
+ if (unlikely(ipoib_alloc_rx_skb(dev, wr_id))) {
+ ++priv->stats.rx_dropped;
+ goto repost;
+ }
- skb_put(skb, wc->byte_len);
- skb_pull(skb, IB_GRH_BYTES);
+ ipoib_dbg_data(priv, "received %d bytes, SLID 0x%04x\n",
+ wc->byte_len, wc->slid);
- if (wc->slid != priv->local_lid ||
- wc->src_qp != priv->qp->qp_num) {
- skb->protocol = ((struct ipoib_header *) skb->data)->proto;
- skb->mac.raw = skb->data;
- skb_pull(skb, IPOIB_ENCAP_LEN);
+ dma_unmap_single(priv->ca->dma_device, addr,
+ IPOIB_BUF_SIZE, DMA_FROM_DEVICE);
- dev->last_rx = jiffies;
- ++priv->stats.rx_packets;
- priv->stats.rx_bytes += skb->len;
+ skb_put(skb, wc->byte_len);
+ skb_pull(skb, IB_GRH_BYTES);
- skb->dev = dev;
- /* XXX get correct PACKET_ type here */
- skb->pkt_type = PACKET_HOST;
- netif_rx_ni(skb);
- } else {
- ipoib_dbg_data(priv, "dropping loopback packet\n");
- dev_kfree_skb_any(skb);
- }
+ if (wc->slid != priv->local_lid ||
+ wc->src_qp != priv->qp->qp_num) {
+ skb->protocol = ((struct ipoib_header *) skb->data)->proto;
+ skb->mac.raw = skb->data;
+ skb_pull(skb, IPOIB_ENCAP_LEN);
- repost:
- if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
- ipoib_warn(priv, "ipoib_ib_post_receive failed "
- "for buf %d\n", wr_id);
- } else
- ipoib_warn(priv, "completion event with wrid %d\n",
- wr_id);
+ dev->last_rx = jiffies;
+ ++priv->stats.rx_packets;
+ priv->stats.rx_bytes += skb->len;
+ skb->dev = dev;
+ /* XXX get correct PACKET_ type here */
+ skb->pkt_type = PACKET_HOST;
+ netif_rx_ni(skb);
} else {
- struct ipoib_tx_buf *tx_req;
- unsigned long flags;
+ ipoib_dbg_data(priv, "dropping loopback packet\n");
+ dev_kfree_skb_any(skb);
+ }
- if (wr_id >= ipoib_sendq_size) {
- ipoib_warn(priv, "completion event with wrid %d (> %d)\n",
- wr_id, ipoib_sendq_size);
- return;
- }
+repost:
+ if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
+ ipoib_warn(priv, "ipoib_ib_post_receive failed "
+ "for buf %d\n", wr_id);
+}
- ipoib_dbg_data(priv, "send complete, wrid %d\n", wr_id);
+static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ unsigned int wr_id = wc->wr_id;
+ struct ipoib_tx_buf *tx_req;
+ unsigned long flags;
- tx_req = &priv->tx_ring[wr_id];
+ ipoib_dbg_data(priv, "send completion: id %d, op %d, status: %d\n",
+ wr_id, wc->opcode, wc->status);
- dma_unmap_single(priv->ca->dma_device,
- pci_unmap_addr(tx_req, mapping),
- tx_req->skb->len,
- DMA_TO_DEVICE);
+ if (unlikely(wr_id >= ipoib_sendq_size)) {
+ ipoib_warn(priv, "send completion event with wrid %d (> %d)\n",
+ wr_id, ipoib_sendq_size);
+ return;
+ }
- ++priv->stats.tx_packets;
- priv->stats.tx_bytes += tx_req->skb->len;
+ tx_req = &priv->tx_ring[wr_id];
- dev_kfree_skb_any(tx_req->skb);
+ dma_unmap_single(priv->ca->dma_device,
+ pci_unmap_addr(tx_req, mapping),
+ tx_req->skb->len,
+ DMA_TO_DEVICE);
- spin_lock_irqsave(&priv->tx_lock, flags);
- ++priv->tx_tail;
- if (netif_queue_stopped(dev) &&
- test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) &&
- priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1)
- netif_wake_queue(dev);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
+ ++priv->stats.tx_packets;
+ priv->stats.tx_bytes += tx_req->skb->len;
- if (wc->status != IB_WC_SUCCESS &&
- wc->status != IB_WC_WR_FLUSH_ERR)
- ipoib_warn(priv, "failed send event "
- "(status=%d, wrid=%d vend_err %x)\n",
- wc->status, wr_id, wc->vendor_err);
- }
+ dev_kfree_skb_any(tx_req->skb);
+
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ ++priv->tx_tail;
+ if (netif_queue_stopped(dev) &&
+ test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags) &&
+ priv->tx_head - priv->tx_tail <= ipoib_sendq_size >> 1)
+ netif_wake_queue(dev);
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+
+ if (wc->status != IB_WC_SUCCESS &&
+ wc->status != IB_WC_WR_FLUSH_ERR)
+ ipoib_warn(priv, "failed send event "
+ "(status=%d, wrid=%d vend_err %x)\n",
+ wc->status, wr_id, wc->vendor_err);
+}
+
+static void ipoib_ib_handle_wc(struct net_device *dev, struct ib_wc *wc)
+{
+ if (wc->wr_id & IPOIB_OP_RECV)
+ ipoib_ib_handle_rx_wc(dev, wc);
+ else
+ ipoib_ib_handle_tx_wc(dev, wc);
}
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr)
@@ -320,7 +332,7 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
struct ipoib_tx_buf *tx_req;
dma_addr_t addr;
- if (skb->len > dev->mtu + INFINIBAND_ALEN) {
+ if (unlikely(skb->len > dev->mtu + INFINIBAND_ALEN)) {
ipoib_warn(priv, "packet len %d (> %d) too long to send, dropping\n",
skb->len, dev->mtu + INFINIBAND_ALEN);
++priv->stats.tx_dropped;
@@ -619,8 +631,10 @@ void ipoib_ib_dev_flush(void *_dev)
* The device could have been brought down between the start and when
* we get here, don't bring it back up if it's not configured up
*/
- if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+ if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) {
ipoib_ib_dev_up(dev);
+ ipoib_mcast_restart_task(dev);
+ }
mutex_lock(&priv->vlan_mutex);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 1c6ea1c682a..1eaf00e9862 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -40,7 +40,6 @@
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/kernel.h>
#include <linux/if_arp.h> /* For ARPHRD_xxx */
@@ -82,6 +81,8 @@ static const u8 ipv4_bcast_addr[] = {
struct workqueue_struct *ipoib_workqueue;
+struct ib_sa_client ipoib_sa_client;
+
static void ipoib_add_one(struct ib_device *device);
static void ipoib_remove_one(struct ib_device *device);
@@ -336,7 +337,8 @@ void ipoib_flush_paths(struct net_device *dev)
struct ipoib_path *path, *tp;
LIST_HEAD(remove_list);
- spin_lock_irq(&priv->lock);
+ spin_lock_irq(&priv->tx_lock);
+ spin_lock(&priv->lock);
list_splice(&priv->path_list, &remove_list);
INIT_LIST_HEAD(&priv->path_list);
@@ -347,12 +349,15 @@ void ipoib_flush_paths(struct net_device *dev)
list_for_each_entry_safe(path, tp, &remove_list, list) {
if (path->query)
ib_sa_cancel_query(path->query_id, path->query);
- spin_unlock_irq(&priv->lock);
+ spin_unlock(&priv->lock);
+ spin_unlock_irq(&priv->tx_lock);
wait_for_completion(&path->done);
path_free(dev, path);
- spin_lock_irq(&priv->lock);
+ spin_lock_irq(&priv->tx_lock);
+ spin_lock(&priv->lock);
}
- spin_unlock_irq(&priv->lock);
+ spin_unlock(&priv->lock);
+ spin_unlock_irq(&priv->tx_lock);
}
static void path_rec_completion(int status,
@@ -404,6 +409,8 @@ static void path_rec_completion(int status,
list_for_each_entry(neigh, &path->neigh_list, list) {
kref_get(&path->ah->ref);
neigh->ah = path->ah;
+ memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
+ sizeof(union ib_gid));
while ((skb = __skb_dequeue(&neigh->queue)))
__skb_queue_tail(&skqueue, skb);
@@ -457,7 +464,7 @@ static int path_rec_start(struct net_device *dev,
init_completion(&path->done);
path->query_id =
- ib_sa_path_rec_get(priv->ca, priv->port,
+ ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port,
&path->pathrec,
IB_SA_PATH_REC_DGID |
IB_SA_PATH_REC_SGID |
@@ -510,6 +517,8 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
if (path->ah) {
kref_get(&path->ah->ref);
neigh->ah = path->ah;
+ memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw,
+ sizeof(union ib_gid));
ipoib_send(dev, skb, path->ah,
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
@@ -611,7 +620,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct ipoib_neigh *neigh;
unsigned long flags;
- if (!spin_trylock_irqsave(&priv->tx_lock, flags))
+ if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags)))
return NETDEV_TX_LOCKED;
/*
@@ -624,7 +633,7 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- if (skb->dst && skb->dst->neighbour) {
+ if (likely(skb->dst && skb->dst->neighbour)) {
if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) {
ipoib_path_lookup(skb, dev);
goto out;
@@ -633,6 +642,25 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
neigh = *to_ipoib_neigh(skb->dst->neighbour);
if (likely(neigh->ah)) {
+ if (unlikely(memcmp(&neigh->dgid.raw,
+ skb->dst->neighbour->ha + 4,
+ sizeof(union ib_gid)))) {
+ spin_lock(&priv->lock);
+ /*
+ * It's safe to call ipoib_put_ah() inside
+ * priv->lock here, because we know that
+ * path->ah will always hold one more reference,
+ * so ipoib_put_ah() will never do more than
+ * decrement the ref count.
+ */
+ ipoib_put_ah(neigh->ah);
+ list_del(&neigh->list);
+ ipoib_neigh_free(neigh);
+ spin_unlock(&priv->lock);
+ ipoib_path_lookup(skb, dev);
+ goto out;
+ }
+
ipoib_send(dev, skb, neigh->ah,
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
goto out;
@@ -1084,13 +1112,16 @@ static void ipoib_add_one(struct ib_device *device)
struct ipoib_dev_priv *priv;
int s, e, p;
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
dev_list = kmalloc(sizeof *dev_list, GFP_KERNEL);
if (!dev_list)
return;
INIT_LIST_HEAD(dev_list);
- if (device->node_type == IB_NODE_SWITCH) {
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
s = 0;
e = 0;
} else {
@@ -1114,6 +1145,9 @@ static void ipoib_remove_one(struct ib_device *device)
struct ipoib_dev_priv *priv, *tmp;
struct list_head *dev_list;
+ if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB)
+ return;
+
dev_list = ib_get_client_data(device, &ipoib_client);
list_for_each_entry_safe(priv, tmp, dev_list, list) {
@@ -1158,13 +1192,16 @@ static int __init ipoib_init_module(void)
goto err_fs;
}
+ ib_sa_register_client(&ipoib_sa_client);
+
ret = ib_register_client(&ipoib_client);
if (ret)
- goto err_wq;
+ goto err_sa;
return 0;
-err_wq:
+err_sa:
+ ib_sa_unregister_client(&ipoib_sa_client);
destroy_workqueue(ipoib_workqueue);
err_fs:
@@ -1176,6 +1213,7 @@ err_fs:
static void __exit ipoib_cleanup_module(void)
{
ib_unregister_client(&ipoib_client);
+ ib_sa_unregister_client(&ipoib_sa_client);
ipoib_unregister_debugfs();
destroy_workqueue(ipoib_workqueue);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index 216471fa01c..3faa1820f0e 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -264,6 +264,10 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
if (!ah) {
ipoib_warn(priv, "ib_address_create failed\n");
} else {
+ spin_lock_irq(&priv->lock);
+ mcast->ah = ah;
+ spin_unlock_irq(&priv->lock);
+
ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT
" AV %p, LID 0x%04x, SL %d\n",
IPOIB_GID_ARG(mcast->mcmember.mgid),
@@ -271,10 +275,6 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
be16_to_cpu(mcast->mcmember.mlid),
mcast->mcmember.sl);
}
-
- spin_lock_irq(&priv->lock);
- mcast->ah = ah;
- spin_unlock_irq(&priv->lock);
}
/* actually send any queued packets */
@@ -326,6 +326,7 @@ ipoib_mcast_sendonly_join_complete(int status,
/* Clear the busy flag so we try again */
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+ mcast->query = NULL;
}
complete(&mcast->done);
@@ -360,7 +361,7 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
init_completion(&mcast->done);
- ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec,
+ ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port, &rec,
IB_SA_MCMEMBER_REC_MGID |
IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_PKEY |
@@ -471,22 +472,32 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
if (create) {
comp_mask |=
- IB_SA_MCMEMBER_REC_QKEY |
- IB_SA_MCMEMBER_REC_SL |
- IB_SA_MCMEMBER_REC_FLOW_LABEL |
- IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;
+ IB_SA_MCMEMBER_REC_QKEY |
+ IB_SA_MCMEMBER_REC_MTU_SELECTOR |
+ IB_SA_MCMEMBER_REC_MTU |
+ IB_SA_MCMEMBER_REC_TRAFFIC_CLASS |
+ IB_SA_MCMEMBER_REC_RATE_SELECTOR |
+ IB_SA_MCMEMBER_REC_RATE |
+ IB_SA_MCMEMBER_REC_SL |
+ IB_SA_MCMEMBER_REC_FLOW_LABEL |
+ IB_SA_MCMEMBER_REC_HOP_LIMIT;
rec.qkey = priv->broadcast->mcmember.qkey;
+ rec.mtu_selector = IB_SA_EQ;
+ rec.mtu = priv->broadcast->mcmember.mtu;
+ rec.traffic_class = priv->broadcast->mcmember.traffic_class;
+ rec.rate_selector = IB_SA_EQ;
+ rec.rate = priv->broadcast->mcmember.rate;
rec.sl = priv->broadcast->mcmember.sl;
rec.flow_label = priv->broadcast->mcmember.flow_label;
- rec.traffic_class = priv->broadcast->mcmember.traffic_class;
+ rec.hop_limit = priv->broadcast->mcmember.hop_limit;
}
init_completion(&mcast->done);
- ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, comp_mask,
- mcast->backoff * 1000, GFP_ATOMIC,
- ipoib_mcast_join_complete,
+ ret = ib_sa_mcmember_rec_set(&ipoib_sa_client, priv->ca, priv->port,
+ &rec, comp_mask, mcast->backoff * 1000,
+ GFP_ATOMIC, ipoib_mcast_join_complete,
mcast, &mcast->query);
if (ret < 0) {
@@ -527,7 +538,7 @@ void ipoib_mcast_join_task(void *dev_ptr)
priv->local_rate = attr.active_speed *
ib_width_enum_to_int(attr.active_width);
} else
- ipoib_warn(priv, "ib_query_port failed\n");
+ ipoib_warn(priv, "ib_query_port failed\n");
}
if (!priv->broadcast) {
@@ -680,7 +691,7 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
* Just make one shot at leaving and don't wait for a reply;
* if we fail, too bad.
*/
- ret = ib_sa_mcmember_rec_delete(priv->ca, priv->port, &rec,
+ ret = ib_sa_mcmember_rec_delete(&ipoib_sa_client, priv->ca, priv->port, &rec,
IB_SA_MCMEMBER_REC_MGID |
IB_SA_MCMEMBER_REC_PORT_GID |
IB_SA_MCMEMBER_REC_PKEY |
@@ -794,7 +805,7 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
}
if (priv->broadcast) {
- rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
+ rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree);
list_add_tail(&priv->broadcast->list, &remove_list);
priv->broadcast = NULL;
}
@@ -864,8 +875,7 @@ void ipoib_mcast_restart_task(void *dev_ptr)
if (mcast) {
/* Destroy the send only entry */
- list_del(&mcast->list);
- list_add_tail(&mcast->list, &remove_list);
+ list_move_tail(&mcast->list, &remove_list);
rb_replace_node(&mcast->rb_node,
&nmcast->rb_node,
@@ -890,8 +900,7 @@ void ipoib_mcast_restart_task(void *dev_ptr)
rb_erase(&mcast->rb_node, &priv->multicast_tree);
/* Move to the remove list */
- list_del(&mcast->list);
- list_add_tail(&mcast->list, &remove_list);
+ list_move_tail(&mcast->list, &remove_list);
}
}
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
new file mode 100644
index 00000000000..aecbb9083f0
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -0,0 +1,12 @@
+config INFINIBAND_ISER
+ tristate "iSCSI Extensions for RDMA (iSER)"
+ depends on INFINIBAND && SCSI && INET
+ select SCSI_ISCSI_ATTRS
+ ---help---
+ Support for the iSCSI Extensions for RDMA (iSER) Protocol
+ over InfiniBand. This allows you to access storage devices
+ that speak iSCSI over iSER over InfiniBand.
+
+ The iSER protocol is defined by IETF.
+ See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
+ and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
diff --git a/drivers/infiniband/ulp/iser/Makefile b/drivers/infiniband/ulp/iser/Makefile
new file mode 100644
index 00000000000..fe6cd15f231
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_INFINIBAND_ISER) += ib_iser.o
+
+ib_iser-y := iser_verbs.o iser_initiator.o iser_memory.o \
+ iscsi_iser.o
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
new file mode 100644
index 00000000000..eb6f98d8228
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -0,0 +1,660 @@
+/*
+ * iSCSI Initiator over iSER Data-Path
+ *
+ * Copyright (C) 2004 Dmitry Yusupov
+ * Copyright (C) 2004 Alex Aizman
+ * Copyright (C) 2005 Mike Christie
+ * Copyright (c) 2005, 2006 Voltaire, Inc. All rights reserved.
+ * maintained by openib-general@openib.org
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Credits:
+ * Christoph Hellwig
+ * FUJITA Tomonori
+ * Arne Redlich
+ * Zhenyu Wang
+ * Modified by:
+ * Erez Zilber
+ *
+ *
+ * $Id: iscsi_iser.c 6965 2006-05-07 11:36:20Z ogerlitz $
+ */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/hardirq.h>
+#include <linux/kfifo.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/ioctl.h>
+#include <linux/cdev.h>
+#include <linux/in.h>
+#include <linux/net.h>
+#include <linux/scatterlist.h>
+#include <linux/delay.h>
+
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "iscsi_iser.h"
+
+static unsigned int iscsi_max_lun = 512;
+module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO);
+
+int iser_debug_level = 0;
+
+MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover "
+ "v" DRV_VER " (" DRV_DATE ")");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz");
+
+module_param_named(debug_level, iser_debug_level, int, 0644);
+MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)");
+
+struct iser_global ig;
+
+void
+iscsi_iser_recv(struct iscsi_conn *conn,
+ struct iscsi_hdr *hdr, char *rx_data, int rx_data_len)
+{
+ int rc = 0;
+ uint32_t ret_itt;
+ int datalen;
+ int ahslen;
+
+ /* verify PDU length */
+ datalen = ntoh24(hdr->dlength);
+ if (datalen != rx_data_len) {
+ printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n",
+ datalen, rx_data_len);
+ rc = ISCSI_ERR_DATALEN;
+ goto error;
+ }
+
+ /* read AHS */
+ ahslen = hdr->hlength * 4;
+
+ /* verify itt (itt encoding: age+cid+itt) */
+ rc = iscsi_verify_itt(conn, hdr, &ret_itt);
+
+ if (!rc)
+ rc = iscsi_complete_pdu(conn, hdr, rx_data, rx_data_len);
+
+ if (rc && rc != ISCSI_ERR_NO_SCSI_CMD)
+ goto error;
+
+ return;
+error:
+ iscsi_conn_failure(conn, rc);
+}
+
+
+/**
+ * iscsi_iser_cmd_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands
+ *
+ **/
+static void
+iscsi_iser_cmd_init(struct iscsi_cmd_task *ctask)
+{
+ struct iscsi_iser_conn *iser_conn = ctask->conn->dd_data;
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct scsi_cmnd *sc = ctask->sc;
+
+ iser_ctask->command_sent = 0;
+ iser_ctask->iser_conn = iser_conn;
+
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ BUG_ON(ctask->total_length == 0);
+
+ debug_scsi("cmd [itt %x total %d imm %d unsol_data %d\n",
+ ctask->itt, ctask->total_length, ctask->imm_count,
+ ctask->unsol_count);
+ }
+
+ iser_ctask_rdma_init(iser_ctask);
+}
+
+/**
+ * iscsi_mtask_xmit - xmit management(immediate) task
+ * @conn: iscsi connection
+ * @mtask: task management task
+ *
+ * Notes:
+ * The function can return -EAGAIN in which case caller must
+ * call it again later, or recover. '0' return code means successful
+ * xmit.
+ *
+ **/
+static int
+iscsi_iser_mtask_xmit(struct iscsi_conn *conn,
+ struct iscsi_mgmt_task *mtask)
+{
+ int error = 0;
+
+ debug_scsi("mtask deq [cid %d itt 0x%x]\n", conn->id, mtask->itt);
+
+ error = iser_send_control(conn, mtask);
+
+ /* since iser xmits control with zero copy, mtasks can not be recycled
+ * right after sending them.
+ * The recycling scheme is based on whether a response is expected
+ * - if yes, the mtask is recycled at iscsi_complete_pdu
+ * - if no, the mtask is recycled at iser_snd_completion
+ */
+ if (error && error != -EAGAIN)
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+
+ return error;
+}
+
+static int
+iscsi_iser_ctask_xmit_unsol_data(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask)
+{
+ struct iscsi_data hdr;
+ int error = 0;
+
+ /* Send data-out PDUs while there's still unsolicited data to send */
+ while (ctask->unsol_count > 0) {
+ iscsi_prep_unsolicit_data_pdu(ctask, &hdr);
+ debug_scsi("Sending data-out: itt 0x%x, data count %d\n",
+ hdr.itt, ctask->data_count);
+
+ /* the buffer description has been passed with the command */
+ /* Send the command */
+ error = iser_send_data_out(conn, ctask, &hdr);
+ if (error) {
+ ctask->unsol_datasn--;
+ goto iscsi_iser_ctask_xmit_unsol_data_exit;
+ }
+ ctask->unsol_count -= ctask->data_count;
+ debug_scsi("Need to send %d more as data-out PDUs\n",
+ ctask->unsol_count);
+ }
+
+iscsi_iser_ctask_xmit_unsol_data_exit:
+ return error;
+}
+
+static int
+iscsi_iser_ctask_xmit(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask)
+{
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ int error = 0;
+
+ debug_scsi("ctask deq [cid %d itt 0x%x]\n",
+ conn->id, ctask->itt);
+
+ /*
+ * serialize with TMF AbortTask
+ */
+ if (ctask->mtask)
+ return error;
+
+ /* Send the cmd PDU */
+ if (!iser_ctask->command_sent) {
+ error = iser_send_command(conn, ctask);
+ if (error)
+ goto iscsi_iser_ctask_xmit_exit;
+ iser_ctask->command_sent = 1;
+ }
+
+ /* Send unsolicited data-out PDU(s) if necessary */
+ if (ctask->unsol_count)
+ error = iscsi_iser_ctask_xmit_unsol_data(conn, ctask);
+
+ iscsi_iser_ctask_xmit_exit:
+ if (error && error != -EAGAIN)
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ return error;
+}
+
+static void
+iscsi_iser_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+{
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+
+ if (iser_ctask->status == ISER_TASK_STATUS_STARTED) {
+ iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
+ iser_ctask_rdma_finalize(iser_ctask);
+ }
+}
+
+static struct iser_conn *
+iscsi_iser_ib_conn_lookup(__u64 ep_handle)
+{
+ struct iser_conn *ib_conn;
+ struct iser_conn *uib_conn = (struct iser_conn *)(unsigned long)ep_handle;
+
+ mutex_lock(&ig.connlist_mutex);
+ list_for_each_entry(ib_conn, &ig.connlist, conn_list) {
+ if (ib_conn == uib_conn) {
+ mutex_unlock(&ig.connlist_mutex);
+ return ib_conn;
+ }
+ }
+ mutex_unlock(&ig.connlist_mutex);
+ iser_err("no conn exists for eph %llx\n",(unsigned long long)ep_handle);
+ return NULL;
+}
+
+static struct iscsi_cls_conn *
+iscsi_iser_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
+{
+ struct iscsi_conn *conn;
+ struct iscsi_cls_conn *cls_conn;
+ struct iscsi_iser_conn *iser_conn;
+
+ cls_conn = iscsi_conn_setup(cls_session, conn_idx);
+ if (!cls_conn)
+ return NULL;
+ conn = cls_conn->dd_data;
+
+ /*
+ * due to issues with the login code re iser sematics
+ * this not set in iscsi_conn_setup - FIXME
+ */
+ conn->max_recv_dlength = 128;
+
+ iser_conn = kzalloc(sizeof(*iser_conn), GFP_KERNEL);
+ if (!iser_conn)
+ goto conn_alloc_fail;
+
+ /* currently this is the only field which need to be initiated */
+ rwlock_init(&iser_conn->lock);
+
+ conn->dd_data = iser_conn;
+ iser_conn->iscsi_conn = conn;
+
+ return cls_conn;
+
+conn_alloc_fail:
+ iscsi_conn_teardown(cls_conn);
+ return NULL;
+}
+
+static void
+iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+ iscsi_conn_teardown(cls_conn);
+ if (iser_conn->ib_conn)
+ iser_conn->ib_conn->iser_conn = NULL;
+ kfree(iser_conn);
+}
+
+static int
+iscsi_iser_conn_bind(struct iscsi_cls_session *cls_session,
+ struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
+ int is_leading)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_iser_conn *iser_conn;
+ struct iser_conn *ib_conn;
+ int error;
+
+ error = iscsi_conn_bind(cls_session, cls_conn, is_leading);
+ if (error)
+ return error;
+
+ /* the transport ep handle comes from user space so it must be
+ * verified against the global ib connections list */
+ ib_conn = iscsi_iser_ib_conn_lookup(transport_eph);
+ if (!ib_conn) {
+ iser_err("can't bind eph %llx\n",
+ (unsigned long long)transport_eph);
+ return -EINVAL;
+ }
+ /* binds the iSER connection retrieved from the previously
+ * connected ep_handle to the iSCSI layer connection. exchanges
+ * connection pointers */
+ iser_err("binding iscsi conn %p to iser_conn %p\n",conn,ib_conn);
+ iser_conn = conn->dd_data;
+ ib_conn->iser_conn = iser_conn;
+ iser_conn->ib_conn = ib_conn;
+
+ conn->recv_lock = &iser_conn->lock;
+
+ return 0;
+}
+
+static int
+iscsi_iser_conn_start(struct iscsi_cls_conn *cls_conn)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ int err;
+
+ err = iscsi_conn_start(cls_conn);
+ if (err)
+ return err;
+
+ return iser_conn_set_full_featured_mode(conn);
+}
+
+static struct iscsi_transport iscsi_iser_transport;
+
+static struct iscsi_cls_session *
+iscsi_iser_session_create(struct iscsi_transport *iscsit,
+ struct scsi_transport_template *scsit,
+ uint32_t initial_cmdsn, uint32_t *hostno)
+{
+ struct iscsi_cls_session *cls_session;
+ struct iscsi_session *session;
+ int i;
+ uint32_t hn;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_mgmt_task *mtask;
+ struct iscsi_iser_cmd_task *iser_ctask;
+ struct iser_desc *desc;
+
+ cls_session = iscsi_session_setup(iscsit, scsit,
+ sizeof(struct iscsi_iser_cmd_task),
+ sizeof(struct iser_desc),
+ initial_cmdsn, &hn);
+ if (!cls_session)
+ return NULL;
+
+ *hostno = hn;
+ session = class_to_transport_session(cls_session);
+
+ /* libiscsi setup itts, data and pool so just set desc fields */
+ for (i = 0; i < session->cmds_max; i++) {
+ ctask = session->cmds[i];
+ iser_ctask = ctask->dd_data;
+ ctask->hdr = (struct iscsi_cmd *)&iser_ctask->desc.iscsi_header;
+ }
+
+ for (i = 0; i < session->mgmtpool_max; i++) {
+ mtask = session->mgmt_cmds[i];
+ desc = mtask->dd_data;
+ mtask->hdr = &desc->iscsi_header;
+ desc->data = mtask->data;
+ }
+
+ return cls_session;
+}
+
+static int
+iscsi_iser_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen)
+{
+ int value;
+
+ switch (param) {
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ /* TBD */
+ break;
+ case ISCSI_PARAM_HDRDGST_EN:
+ sscanf(buf, "%d", &value);
+ if (value) {
+ printk(KERN_ERR "DataDigest wasn't negotiated to None");
+ return -EPROTO;
+ }
+ break;
+ case ISCSI_PARAM_DATADGST_EN:
+ sscanf(buf, "%d", &value);
+ if (value) {
+ printk(KERN_ERR "DataDigest wasn't negotiated to None");
+ return -EPROTO;
+ }
+ break;
+ case ISCSI_PARAM_IFMARKER_EN:
+ sscanf(buf, "%d", &value);
+ if (value) {
+ printk(KERN_ERR "IFMarker wasn't negotiated to No");
+ return -EPROTO;
+ }
+ break;
+ case ISCSI_PARAM_OFMARKER_EN:
+ sscanf(buf, "%d", &value);
+ if (value) {
+ printk(KERN_ERR "OFMarker wasn't negotiated to No");
+ return -EPROTO;
+ }
+ break;
+ default:
+ return iscsi_set_param(cls_conn, param, buf, buflen);
+ }
+
+ return 0;
+}
+
+static void
+iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *stats)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+
+ stats->txdata_octets = conn->txdata_octets;
+ stats->rxdata_octets = conn->rxdata_octets;
+ stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
+ stats->dataout_pdus = conn->dataout_pdus_cnt;
+ stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
+ stats->datain_pdus = conn->datain_pdus_cnt; /* always 0 */
+ stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */
+ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
+ stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
+ stats->custom_length = 3;
+ strcpy(stats->custom[0].desc, "qp_tx_queue_full");
+ stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */
+ strcpy(stats->custom[1].desc, "fmr_map_not_avail");
+ stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */;
+ strcpy(stats->custom[2].desc, "eh_abort_cnt");
+ stats->custom[2].value = conn->eh_abort_cnt;
+}
+
+static int
+iscsi_iser_ep_connect(struct sockaddr *dst_addr, int non_blocking,
+ __u64 *ep_handle)
+{
+ int err;
+ struct iser_conn *ib_conn;
+
+ err = iser_conn_init(&ib_conn);
+ if (err)
+ goto out;
+
+ err = iser_connect(ib_conn, NULL, (struct sockaddr_in *)dst_addr, non_blocking);
+ if (!err)
+ *ep_handle = (__u64)(unsigned long)ib_conn;
+
+out:
+ return err;
+}
+
+static int
+iscsi_iser_ep_poll(__u64 ep_handle, int timeout_ms)
+{
+ struct iser_conn *ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
+ int rc;
+
+ if (!ib_conn)
+ return -EINVAL;
+
+ rc = wait_event_interruptible_timeout(ib_conn->wait,
+ ib_conn->state == ISER_CONN_UP,
+ msecs_to_jiffies(timeout_ms));
+
+ /* if conn establishment failed, return error code to iscsi */
+ if (!rc &&
+ (ib_conn->state == ISER_CONN_TERMINATING ||
+ ib_conn->state == ISER_CONN_DOWN))
+ rc = -1;
+
+ iser_err("ib conn %p rc = %d\n", ib_conn, rc);
+
+ if (rc > 0)
+ return 1; /* success, this is the equivalent of POLLOUT */
+ else if (!rc)
+ return 0; /* timeout */
+ else
+ return rc; /* signal */
+}
+
+static void
+iscsi_iser_ep_disconnect(__u64 ep_handle)
+{
+ struct iser_conn *ib_conn;
+
+ ib_conn = iscsi_iser_ib_conn_lookup(ep_handle);
+ if (!ib_conn)
+ return;
+
+ iser_err("ib conn %p state %d\n",ib_conn, ib_conn->state);
+ iser_conn_terminate(ib_conn);
+}
+
+static struct scsi_host_template iscsi_iser_sht = {
+ .name = "iSCSI Initiator over iSER, v." DRV_VER,
+ .queuecommand = iscsi_queuecommand,
+ .can_queue = ISCSI_XMIT_CMDS_MAX - 1,
+ .sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
+ .max_sectors = 1024,
+ .cmd_per_lun = ISCSI_MAX_CMD_PER_LUN,
+ .eh_abort_handler = iscsi_eh_abort,
+ .eh_host_reset_handler = iscsi_eh_host_reset,
+ .use_clustering = DISABLE_CLUSTERING,
+ .proc_name = "iscsi_iser",
+ .this_id = -1,
+};
+
+static struct iscsi_transport iscsi_iser_transport = {
+ .owner = THIS_MODULE,
+ .name = "iser",
+ .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T,
+ .param_mask = ISCSI_MAX_RECV_DLENGTH |
+ ISCSI_MAX_XMIT_DLENGTH |
+ ISCSI_HDRDGST_EN |
+ ISCSI_DATADGST_EN |
+ ISCSI_INITIAL_R2T_EN |
+ ISCSI_MAX_R2T |
+ ISCSI_IMM_DATA_EN |
+ ISCSI_FIRST_BURST |
+ ISCSI_MAX_BURST |
+ ISCSI_PDU_INORDER_EN |
+ ISCSI_DATASEQ_INORDER_EN |
+ ISCSI_EXP_STATSN |
+ ISCSI_PERSISTENT_PORT |
+ ISCSI_PERSISTENT_ADDRESS |
+ ISCSI_TARGET_NAME |
+ ISCSI_TPGT,
+ .host_template = &iscsi_iser_sht,
+ .conndata_size = sizeof(struct iscsi_conn),
+ .max_lun = ISCSI_ISER_MAX_LUN,
+ .max_cmd_len = ISCSI_ISER_MAX_CMD_LEN,
+ /* session management */
+ .create_session = iscsi_iser_session_create,
+ .destroy_session = iscsi_session_teardown,
+ /* connection management */
+ .create_conn = iscsi_iser_conn_create,
+ .bind_conn = iscsi_iser_conn_bind,
+ .destroy_conn = iscsi_iser_conn_destroy,
+ .set_param = iscsi_iser_set_param,
+ .get_conn_param = iscsi_conn_get_param,
+ .get_session_param = iscsi_session_get_param,
+ .start_conn = iscsi_iser_conn_start,
+ .stop_conn = iscsi_conn_stop,
+ /* IO */
+ .send_pdu = iscsi_conn_send_pdu,
+ .get_stats = iscsi_iser_conn_get_stats,
+ .init_cmd_task = iscsi_iser_cmd_init,
+ .xmit_cmd_task = iscsi_iser_ctask_xmit,
+ .xmit_mgmt_task = iscsi_iser_mtask_xmit,
+ .cleanup_cmd_task = iscsi_iser_cleanup_ctask,
+ /* recovery */
+ .session_recovery_timedout = iscsi_session_recovery_timedout,
+
+ .ep_connect = iscsi_iser_ep_connect,
+ .ep_poll = iscsi_iser_ep_poll,
+ .ep_disconnect = iscsi_iser_ep_disconnect
+};
+
+static int __init iser_init(void)
+{
+ int err;
+
+ iser_dbg("Starting iSER datamover...\n");
+
+ if (iscsi_max_lun < 1) {
+ printk(KERN_ERR "Invalid max_lun value of %u\n", iscsi_max_lun);
+ return -EINVAL;
+ }
+
+ iscsi_iser_transport.max_lun = iscsi_max_lun;
+
+ memset(&ig, 0, sizeof(struct iser_global));
+
+ ig.desc_cache = kmem_cache_create("iser_descriptors",
+ sizeof (struct iser_desc),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (ig.desc_cache == NULL)
+ return -ENOMEM;
+
+ /* device init is called only after the first addr resolution */
+ mutex_init(&ig.device_list_mutex);
+ INIT_LIST_HEAD(&ig.device_list);
+ mutex_init(&ig.connlist_mutex);
+ INIT_LIST_HEAD(&ig.connlist);
+
+ if (!iscsi_register_transport(&iscsi_iser_transport)) {
+ iser_err("iscsi_register_transport failed\n");
+ err = -EINVAL;
+ goto register_transport_failure;
+ }
+
+ return 0;
+
+register_transport_failure:
+ kmem_cache_destroy(ig.desc_cache);
+
+ return err;
+}
+
+static void __exit iser_exit(void)
+{
+ iser_dbg("Removing iSER datamover...\n");
+ iscsi_unregister_transport(&iscsi_iser_transport);
+ kmem_cache_destroy(ig.desc_cache);
+}
+
+module_init(iser_init);
+module_exit(iser_exit);
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
new file mode 100644
index 00000000000..9c53916f28c
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -0,0 +1,365 @@
+/*
+ * iSER transport for the Open iSCSI Initiator & iSER transport internals
+ *
+ * Copyright (C) 2004 Dmitry Yusupov
+ * Copyright (C) 2004 Alex Aizman
+ * Copyright (C) 2005 Mike Christie
+ * based on code maintained by open-iscsi@googlegroups.com
+ *
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iscsi_iser.h 7051 2006-05-10 12:29:11Z ogerlitz $
+ */
+#ifndef __ISCSI_ISER_H__
+#define __ISCSI_ISER_H__
+
+#include <linux/types.h>
+#include <linux/net.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/mutex.h>
+#include <linux/mempool.h>
+#include <linux/uio.h>
+
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#include <rdma/ib_verbs.h>
+#include <rdma/ib_fmr_pool.h>
+#include <rdma/rdma_cm.h>
+
+#define DRV_NAME "iser"
+#define PFX DRV_NAME ": "
+#define DRV_VER "0.1"
+#define DRV_DATE "May 7th, 2006"
+
+#define iser_dbg(fmt, arg...) \
+ do { \
+ if (iser_debug_level > 0) \
+ printk(KERN_DEBUG PFX "%s:" fmt,\
+ __func__ , ## arg); \
+ } while (0)
+
+#define iser_err(fmt, arg...) \
+ do { \
+ printk(KERN_ERR PFX "%s:" fmt, \
+ __func__ , ## arg); \
+ } while (0)
+
+#define SHIFT_4K 12
+#define SIZE_4K (1UL << SHIFT_4K)
+#define MASK_4K (~(SIZE_4K-1))
+
+ /* support upto 512KB in one RDMA */
+#define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K)
+#define ISCSI_ISER_MAX_LUN 256
+#define ISCSI_ISER_MAX_CMD_LEN 16
+
+/* QP settings */
+/* Maximal bounds on received asynchronous PDUs */
+#define ISER_MAX_RX_MISC_PDUS 4 /* NOOP_IN(2) , ASYNC_EVENT(2) */
+
+#define ISER_MAX_TX_MISC_PDUS 6 /* NOOP_OUT(2), TEXT(1), *
+ * SCSI_TMFUNC(2), LOGOUT(1) */
+
+#define ISER_QP_MAX_RECV_DTOS (ISCSI_XMIT_CMDS_MAX + \
+ ISER_MAX_RX_MISC_PDUS + \
+ ISER_MAX_TX_MISC_PDUS)
+
+/* the max TX (send) WR supported by the iSER QP is defined by *
+ * max_send_wr = T * (1 + D) + C ; D is how many inflight dataouts we expect *
+ * to have at max for SCSI command. The tx posting & completion handling code *
+ * supports -EAGAIN scheme where tx is suspended till the QP has room for more *
+ * send WR. D=8 comes from 64K/8K */
+
+#define ISER_INFLIGHT_DATAOUTS 8
+
+#define ISER_QP_MAX_REQ_DTOS (ISCSI_XMIT_CMDS_MAX * \
+ (1 + ISER_INFLIGHT_DATAOUTS) + \
+ ISER_MAX_TX_MISC_PDUS + \
+ ISER_MAX_RX_MISC_PDUS)
+
+#define ISER_VER 0x10
+#define ISER_WSV 0x08
+#define ISER_RSV 0x04
+
+struct iser_hdr {
+ u8 flags;
+ u8 rsvd[3];
+ __be32 write_stag; /* write rkey */
+ __be64 write_va;
+ __be32 read_stag; /* read rkey */
+ __be64 read_va;
+} __attribute__((packed));
+
+
+/* Length of an object name string */
+#define ISER_OBJECT_NAME_SIZE 64
+
+enum iser_ib_conn_state {
+ ISER_CONN_INIT, /* descriptor allocd, no conn */
+ ISER_CONN_PENDING, /* in the process of being established */
+ ISER_CONN_UP, /* up and running */
+ ISER_CONN_TERMINATING, /* in the process of being terminated */
+ ISER_CONN_DOWN, /* shut down */
+ ISER_CONN_STATES_NUM
+};
+
+enum iser_task_status {
+ ISER_TASK_STATUS_INIT = 0,
+ ISER_TASK_STATUS_STARTED,
+ ISER_TASK_STATUS_COMPLETED
+};
+
+enum iser_data_dir {
+ ISER_DIR_IN = 0, /* to initiator */
+ ISER_DIR_OUT, /* from initiator */
+ ISER_DIRS_NUM
+};
+
+struct iser_data_buf {
+ void *buf; /* pointer to the sg list */
+ unsigned int size; /* num entries of this sg */
+ unsigned long data_len; /* total data len */
+ unsigned int dma_nents; /* returned by dma_map_sg */
+ char *copy_buf; /* allocated copy buf for SGs unaligned *
+ * for rdma which are copied */
+ struct scatterlist sg_single; /* SG-ified clone of a non SG SC or *
+ * unaligned SG */
+ };
+
+/* fwd declarations */
+struct iser_device;
+struct iscsi_iser_conn;
+struct iscsi_iser_cmd_task;
+
+struct iser_mem_reg {
+ u32 lkey;
+ u32 rkey;
+ u64 va;
+ u64 len;
+ void *mem_h;
+ int is_fmr;
+};
+
+struct iser_regd_buf {
+ struct iser_mem_reg reg; /* memory registration info */
+ void *virt_addr;
+ struct iser_device *device; /* device->device for dma_unmap */
+ dma_addr_t dma_addr; /* if non zero, addr for dma_unmap */
+ enum dma_data_direction direction; /* direction for dma_unmap */
+ unsigned int data_size;
+ atomic_t ref_count; /* refcount, freed when dec to 0 */
+};
+
+#define MAX_REGD_BUF_VECTOR_LEN 2
+
+struct iser_dto {
+ struct iscsi_iser_cmd_task *ctask;
+ struct iser_conn *ib_conn;
+ int notify_enable;
+
+ /* vector of registered buffers */
+ unsigned int regd_vector_len;
+ struct iser_regd_buf *regd[MAX_REGD_BUF_VECTOR_LEN];
+
+ /* offset into the registered buffer may be specified */
+ unsigned int offset[MAX_REGD_BUF_VECTOR_LEN];
+
+ /* a smaller size may be specified, if 0, then full size is used */
+ unsigned int used_sz[MAX_REGD_BUF_VECTOR_LEN];
+};
+
+enum iser_desc_type {
+ ISCSI_RX,
+ ISCSI_TX_CONTROL ,
+ ISCSI_TX_SCSI_COMMAND,
+ ISCSI_TX_DATAOUT
+};
+
+struct iser_desc {
+ struct iser_hdr iser_header;
+ struct iscsi_hdr iscsi_header;
+ struct iser_regd_buf hdr_regd_buf;
+ void *data; /* used by RX & TX_CONTROL */
+ struct iser_regd_buf data_regd_buf; /* used by RX & TX_CONTROL */
+ enum iser_desc_type type;
+ struct iser_dto dto;
+};
+
+struct iser_device {
+ struct ib_device *ib_device;
+ struct ib_pd *pd;
+ struct ib_cq *cq;
+ struct ib_mr *mr;
+ struct tasklet_struct cq_tasklet;
+ struct list_head ig_list; /* entry in ig devices list */
+ int refcount;
+};
+
+struct iser_conn {
+ struct iscsi_iser_conn *iser_conn; /* iser conn for upcalls */
+ enum iser_ib_conn_state state; /* rdma connection state */
+ spinlock_t lock; /* used for state changes */
+ struct iser_device *device; /* device context */
+ struct rdma_cm_id *cma_id; /* CMA ID */
+ struct ib_qp *qp; /* QP */
+ struct ib_fmr_pool *fmr_pool; /* pool of IB FMRs */
+ int disc_evt_flag; /* disconn event delivered */
+ wait_queue_head_t wait; /* waitq for conn/disconn */
+ atomic_t post_recv_buf_count; /* posted rx count */
+ atomic_t post_send_buf_count; /* posted tx count */
+ struct work_struct comperror_work; /* conn term sleepable ctx*/
+ char name[ISER_OBJECT_NAME_SIZE];
+ struct iser_page_vec *page_vec; /* represents SG to fmr maps*
+ * maps serialized as tx is*/
+ struct list_head conn_list; /* entry in ig conn list */
+};
+
+struct iscsi_iser_conn {
+ struct iscsi_conn *iscsi_conn;/* ptr to iscsi conn */
+ struct iser_conn *ib_conn; /* iSER IB conn */
+
+ rwlock_t lock;
+};
+
+struct iscsi_iser_cmd_task {
+ struct iser_desc desc;
+ struct iscsi_iser_conn *iser_conn;
+ enum iser_task_status status;
+ int command_sent; /* set if command sent */
+ int dir[ISER_DIRS_NUM]; /* set if dir use*/
+ struct iser_regd_buf rdma_regd[ISER_DIRS_NUM];/* regd rdma buf */
+ struct iser_data_buf data[ISER_DIRS_NUM]; /* orig. data des*/
+ struct iser_data_buf data_copy[ISER_DIRS_NUM];/* contig. copy */
+};
+
+struct iser_page_vec {
+ u64 *pages;
+ int length;
+ int offset;
+ int data_size;
+};
+
+struct iser_global {
+ struct mutex device_list_mutex;/* */
+ struct list_head device_list; /* all iSER devices */
+ struct mutex connlist_mutex;
+ struct list_head connlist; /* all iSER IB connections */
+
+ kmem_cache_t *desc_cache;
+};
+
+extern struct iser_global ig;
+extern int iser_debug_level;
+
+/* allocate connection resources needed for rdma functionality */
+int iser_conn_set_full_featured_mode(struct iscsi_conn *conn);
+
+int iser_send_control(struct iscsi_conn *conn,
+ struct iscsi_mgmt_task *mtask);
+
+int iser_send_command(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask);
+
+int iser_send_data_out(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask,
+ struct iscsi_data *hdr);
+
+void iscsi_iser_recv(struct iscsi_conn *conn,
+ struct iscsi_hdr *hdr,
+ char *rx_data,
+ int rx_data_len);
+
+int iser_conn_init(struct iser_conn **ib_conn);
+
+void iser_conn_terminate(struct iser_conn *ib_conn);
+
+void iser_conn_release(struct iser_conn *ib_conn);
+
+void iser_rcv_completion(struct iser_desc *desc,
+ unsigned long dto_xfer_len);
+
+void iser_snd_completion(struct iser_desc *desc);
+
+void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *ctask);
+
+void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *ctask);
+
+void iser_dto_buffs_release(struct iser_dto *dto);
+
+int iser_regd_buff_release(struct iser_regd_buf *regd_buf);
+
+void iser_reg_single(struct iser_device *device,
+ struct iser_regd_buf *regd_buf,
+ enum dma_data_direction direction);
+
+int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
+ enum iser_data_dir cmd_dir);
+
+void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *ctask,
+ enum iser_data_dir cmd_dir);
+
+int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *ctask,
+ enum iser_data_dir cmd_dir);
+
+int iser_connect(struct iser_conn *ib_conn,
+ struct sockaddr_in *src_addr,
+ struct sockaddr_in *dst_addr,
+ int non_blocking);
+
+int iser_reg_page_vec(struct iser_conn *ib_conn,
+ struct iser_page_vec *page_vec,
+ struct iser_mem_reg *mem_reg);
+
+void iser_unreg_mem(struct iser_mem_reg *mem_reg);
+
+int iser_post_recv(struct iser_desc *rx_desc);
+int iser_post_send(struct iser_desc *tx_desc);
+
+int iser_conn_state_comp(struct iser_conn *ib_conn,
+ enum iser_ib_conn_state comp);
+
+int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+ struct iser_data_buf *data,
+ enum iser_data_dir iser_dir,
+ enum dma_data_direction dma_dir);
+
+void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask);
+#endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
new file mode 100644
index 00000000000..9b3d79c796c
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iser_initiator.c 6964 2006-05-07 11:11:43Z ogerlitz $
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+#include <linux/kfifo.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+
+#include "iscsi_iser.h"
+
+/* Constant PDU lengths calculations */
+#define ISER_TOTAL_HEADERS_LEN (sizeof (struct iser_hdr) + \
+ sizeof (struct iscsi_hdr))
+
+/* iser_dto_add_regd_buff - increments the reference count for *
+ * the registered buffer & adds it to the DTO object */
+static void iser_dto_add_regd_buff(struct iser_dto *dto,
+ struct iser_regd_buf *regd_buf,
+ unsigned long use_offset,
+ unsigned long use_size)
+{
+ int add_idx;
+
+ atomic_inc(&regd_buf->ref_count);
+
+ add_idx = dto->regd_vector_len;
+ dto->regd[add_idx] = regd_buf;
+ dto->used_sz[add_idx] = use_size;
+ dto->offset[add_idx] = use_offset;
+
+ dto->regd_vector_len++;
+}
+
+/* Register user buffer memory and initialize passive rdma
+ * dto descriptor. Total data size is stored in
+ * iser_ctask->data[ISER_DIR_IN].data_len
+ */
+static int iser_prepare_read_cmd(struct iscsi_cmd_task *ctask,
+ unsigned int edtl)
+
+{
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iser_regd_buf *regd_buf;
+ int err;
+ struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
+ struct iser_data_buf *buf_in = &iser_ctask->data[ISER_DIR_IN];
+
+ err = iser_dma_map_task_data(iser_ctask,
+ buf_in,
+ ISER_DIR_IN,
+ DMA_FROM_DEVICE);
+ if (err)
+ return err;
+
+ if (edtl > iser_ctask->data[ISER_DIR_IN].data_len) {
+ iser_err("Total data length: %ld, less than EDTL: "
+ "%d, in READ cmd BHS itt: %d, conn: 0x%p\n",
+ iser_ctask->data[ISER_DIR_IN].data_len, edtl,
+ ctask->itt, iser_ctask->iser_conn);
+ return -EINVAL;
+ }
+
+ err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_IN);
+ if (err) {
+ iser_err("Failed to set up Data-IN RDMA\n");
+ return err;
+ }
+ regd_buf = &iser_ctask->rdma_regd[ISER_DIR_IN];
+
+ hdr->flags |= ISER_RSV;
+ hdr->read_stag = cpu_to_be32(regd_buf->reg.rkey);
+ hdr->read_va = cpu_to_be64(regd_buf->reg.va);
+
+ iser_dbg("Cmd itt:%d READ tags RKEY:%#.4X VA:%#llX\n",
+ ctask->itt, regd_buf->reg.rkey,
+ (unsigned long long)regd_buf->reg.va);
+
+ return 0;
+}
+
+/* Register user buffer memory and initialize passive rdma
+ * dto descriptor. Total data size is stored in
+ * ctask->data[ISER_DIR_OUT].data_len
+ */
+static int
+iser_prepare_write_cmd(struct iscsi_cmd_task *ctask,
+ unsigned int imm_sz,
+ unsigned int unsol_sz,
+ unsigned int edtl)
+{
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iser_regd_buf *regd_buf;
+ int err;
+ struct iser_dto *send_dto = &iser_ctask->desc.dto;
+ struct iser_hdr *hdr = &iser_ctask->desc.iser_header;
+ struct iser_data_buf *buf_out = &iser_ctask->data[ISER_DIR_OUT];
+
+ err = iser_dma_map_task_data(iser_ctask,
+ buf_out,
+ ISER_DIR_OUT,
+ DMA_TO_DEVICE);
+ if (err)
+ return err;
+
+ if (edtl > iser_ctask->data[ISER_DIR_OUT].data_len) {
+ iser_err("Total data length: %ld, less than EDTL: %d, "
+ "in WRITE cmd BHS itt: %d, conn: 0x%p\n",
+ iser_ctask->data[ISER_DIR_OUT].data_len,
+ edtl, ctask->itt, ctask->conn);
+ return -EINVAL;
+ }
+
+ err = iser_reg_rdma_mem(iser_ctask,ISER_DIR_OUT);
+ if (err != 0) {
+ iser_err("Failed to register write cmd RDMA mem\n");
+ return err;
+ }
+
+ regd_buf = &iser_ctask->rdma_regd[ISER_DIR_OUT];
+
+ if (unsol_sz < edtl) {
+ hdr->flags |= ISER_WSV;
+ hdr->write_stag = cpu_to_be32(regd_buf->reg.rkey);
+ hdr->write_va = cpu_to_be64(regd_buf->reg.va + unsol_sz);
+
+ iser_dbg("Cmd itt:%d, WRITE tags, RKEY:%#.4X "
+ "VA:%#llX + unsol:%d\n",
+ ctask->itt, regd_buf->reg.rkey,
+ (unsigned long long)regd_buf->reg.va, unsol_sz);
+ }
+
+ if (imm_sz > 0) {
+ iser_dbg("Cmd itt:%d, WRITE, adding imm.data sz: %d\n",
+ ctask->itt, imm_sz);
+ iser_dto_add_regd_buff(send_dto,
+ regd_buf,
+ 0,
+ imm_sz);
+ }
+
+ return 0;
+}
+
+/**
+ * iser_post_receive_control - allocates, initializes and posts receive DTO.
+ */
+static int iser_post_receive_control(struct iscsi_conn *conn)
+{
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_desc *rx_desc;
+ struct iser_regd_buf *regd_hdr;
+ struct iser_regd_buf *regd_data;
+ struct iser_dto *recv_dto = NULL;
+ struct iser_device *device = iser_conn->ib_conn->device;
+ int rx_data_size, err = 0;
+
+ rx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
+ if (rx_desc == NULL) {
+ iser_err("Failed to alloc desc for post recv\n");
+ return -ENOMEM;
+ }
+ rx_desc->type = ISCSI_RX;
+
+ /* for the login sequence we must support rx of upto 8K; login is done
+ * after conn create/bind (connect) and conn stop/bind (reconnect),
+ * what's common for both schemes is that the connection is not started
+ */
+ if (conn->c_stage != ISCSI_CONN_STARTED)
+ rx_data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
+ else /* FIXME till user space sets conn->max_recv_dlength correctly */
+ rx_data_size = 128;
+
+ rx_desc->data = kmalloc(rx_data_size, GFP_NOIO);
+ if (rx_desc->data == NULL) {
+ iser_err("Failed to alloc data buf for post recv\n");
+ err = -ENOMEM;
+ goto post_rx_kmalloc_failure;
+ }
+
+ recv_dto = &rx_desc->dto;
+ recv_dto->ib_conn = iser_conn->ib_conn;
+ recv_dto->regd_vector_len = 0;
+
+ regd_hdr = &rx_desc->hdr_regd_buf;
+ memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
+ regd_hdr->device = device;
+ regd_hdr->virt_addr = rx_desc; /* == &rx_desc->iser_header */
+ regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
+
+ iser_reg_single(device, regd_hdr, DMA_FROM_DEVICE);
+
+ iser_dto_add_regd_buff(recv_dto, regd_hdr, 0, 0);
+
+ regd_data = &rx_desc->data_regd_buf;
+ memset(regd_data, 0, sizeof(struct iser_regd_buf));
+ regd_data->device = device;
+ regd_data->virt_addr = rx_desc->data;
+ regd_data->data_size = rx_data_size;
+
+ iser_reg_single(device, regd_data, DMA_FROM_DEVICE);
+
+ iser_dto_add_regd_buff(recv_dto, regd_data, 0, 0);
+
+ err = iser_post_recv(rx_desc);
+ if (!err)
+ return 0;
+
+ /* iser_post_recv failed */
+ iser_dto_buffs_release(recv_dto);
+ kfree(rx_desc->data);
+post_rx_kmalloc_failure:
+ kmem_cache_free(ig.desc_cache, rx_desc);
+ return err;
+}
+
+/* creates a new tx descriptor and adds header regd buffer */
+static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn,
+ struct iser_desc *tx_desc)
+{
+ struct iser_regd_buf *regd_hdr = &tx_desc->hdr_regd_buf;
+ struct iser_dto *send_dto = &tx_desc->dto;
+
+ memset(regd_hdr, 0, sizeof(struct iser_regd_buf));
+ regd_hdr->device = iser_conn->ib_conn->device;
+ regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */
+ regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
+
+ send_dto->ib_conn = iser_conn->ib_conn;
+ send_dto->notify_enable = 1;
+ send_dto->regd_vector_len = 0;
+
+ memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr));
+ tx_desc->iser_header.flags = ISER_VER;
+
+ iser_dto_add_regd_buff(send_dto, regd_hdr, 0, 0);
+}
+
+/**
+ * iser_conn_set_full_featured_mode - (iSER API)
+ */
+int iser_conn_set_full_featured_mode(struct iscsi_conn *conn)
+{
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+ int i;
+ /* no need to keep it in a var, we are after login so if this should
+ * be negotiated, by now the result should be available here */
+ int initial_post_recv_bufs_num = ISER_MAX_RX_MISC_PDUS;
+
+ iser_dbg("Initially post: %d\n", initial_post_recv_bufs_num);
+
+ /* Check that there is no posted recv or send buffers left - */
+ /* they must be consumed during the login phase */
+ BUG_ON(atomic_read(&iser_conn->ib_conn->post_recv_buf_count) != 0);
+ BUG_ON(atomic_read(&iser_conn->ib_conn->post_send_buf_count) != 0);
+
+ /* Initial post receive buffers */
+ for (i = 0; i < initial_post_recv_bufs_num; i++) {
+ if (iser_post_receive_control(conn) != 0) {
+ iser_err("Failed to post recv bufs at:%d conn:0x%p\n",
+ i, conn);
+ return -ENOMEM;
+ }
+ }
+ iser_dbg("Posted %d post recv bufs, conn:0x%p\n", i, conn);
+ return 0;
+}
+
+static int
+iser_check_xmit(struct iscsi_conn *conn, void *task)
+{
+ int rc = 0;
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+
+ write_lock_bh(conn->recv_lock);
+ if (atomic_read(&iser_conn->ib_conn->post_send_buf_count) ==
+ ISER_QP_MAX_REQ_DTOS) {
+ iser_dbg("%ld can't xmit task %p, suspending tx\n",jiffies,task);
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ rc = -EAGAIN;
+ }
+ write_unlock_bh(conn->recv_lock);
+ return rc;
+}
+
+
+/**
+ * iser_send_command - send command PDU
+ */
+int iser_send_command(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask)
+{
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iser_dto *send_dto = NULL;
+ unsigned long edtl;
+ int err = 0;
+ struct iser_data_buf *data_buf;
+
+ struct iscsi_cmd *hdr = ctask->hdr;
+ struct scsi_cmnd *sc = ctask->sc;
+
+ if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
+ iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
+ return -EPERM;
+ }
+ if (iser_check_xmit(conn, ctask))
+ return -EAGAIN;
+
+ edtl = ntohl(hdr->data_length);
+
+ /* build the tx desc regd header and add it to the tx desc dto */
+ iser_ctask->desc.type = ISCSI_TX_SCSI_COMMAND;
+ send_dto = &iser_ctask->desc.dto;
+ send_dto->ctask = iser_ctask;
+ iser_create_send_desc(iser_conn, &iser_ctask->desc);
+
+ if (hdr->flags & ISCSI_FLAG_CMD_READ)
+ data_buf = &iser_ctask->data[ISER_DIR_IN];
+ else
+ data_buf = &iser_ctask->data[ISER_DIR_OUT];
+
+ if (sc->use_sg) { /* using a scatter list */
+ data_buf->buf = sc->request_buffer;
+ data_buf->size = sc->use_sg;
+ } else if (sc->request_bufflen) {
+ /* using a single buffer - convert it into one entry SG */
+ sg_init_one(&data_buf->sg_single,
+ sc->request_buffer, sc->request_bufflen);
+ data_buf->buf = &data_buf->sg_single;
+ data_buf->size = 1;
+ }
+
+ data_buf->data_len = sc->request_bufflen;
+
+ if (hdr->flags & ISCSI_FLAG_CMD_READ) {
+ err = iser_prepare_read_cmd(ctask, edtl);
+ if (err)
+ goto send_command_error;
+ }
+ if (hdr->flags & ISCSI_FLAG_CMD_WRITE) {
+ err = iser_prepare_write_cmd(ctask,
+ ctask->imm_count,
+ ctask->imm_count +
+ ctask->unsol_count,
+ edtl);
+ if (err)
+ goto send_command_error;
+ }
+
+ iser_reg_single(iser_conn->ib_conn->device,
+ send_dto->regd[0], DMA_TO_DEVICE);
+
+ if (iser_post_receive_control(conn) != 0) {
+ iser_err("post_recv failed!\n");
+ err = -ENOMEM;
+ goto send_command_error;
+ }
+
+ iser_ctask->status = ISER_TASK_STATUS_STARTED;
+
+ err = iser_post_send(&iser_ctask->desc);
+ if (!err)
+ return 0;
+
+send_command_error:
+ iser_dto_buffs_release(send_dto);
+ iser_err("conn %p failed ctask->itt %d err %d\n",conn, ctask->itt, err);
+ return err;
+}
+
+/**
+ * iser_send_data_out - send data out PDU
+ */
+int iser_send_data_out(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask,
+ struct iscsi_data *hdr)
+{
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iscsi_iser_cmd_task *iser_ctask = ctask->dd_data;
+ struct iser_desc *tx_desc = NULL;
+ struct iser_dto *send_dto = NULL;
+ unsigned long buf_offset;
+ unsigned long data_seg_len;
+ unsigned int itt;
+ int err = 0;
+
+ if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
+ iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
+ return -EPERM;
+ }
+
+ if (iser_check_xmit(conn, ctask))
+ return -EAGAIN;
+
+ itt = ntohl(hdr->itt);
+ data_seg_len = ntoh24(hdr->dlength);
+ buf_offset = ntohl(hdr->offset);
+
+ iser_dbg("%s itt %d dseg_len %d offset %d\n",
+ __func__,(int)itt,(int)data_seg_len,(int)buf_offset);
+
+ tx_desc = kmem_cache_alloc(ig.desc_cache, GFP_NOIO);
+ if (tx_desc == NULL) {
+ iser_err("Failed to alloc desc for post dataout\n");
+ return -ENOMEM;
+ }
+
+ tx_desc->type = ISCSI_TX_DATAOUT;
+ memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr));
+
+ /* build the tx desc regd header and add it to the tx desc dto */
+ send_dto = &tx_desc->dto;
+ send_dto->ctask = iser_ctask;
+ iser_create_send_desc(iser_conn, tx_desc);
+
+ iser_reg_single(iser_conn->ib_conn->device,
+ send_dto->regd[0], DMA_TO_DEVICE);
+
+ /* all data was registered for RDMA, we can use the lkey */
+ iser_dto_add_regd_buff(send_dto,
+ &iser_ctask->rdma_regd[ISER_DIR_OUT],
+ buf_offset,
+ data_seg_len);
+
+ if (buf_offset + data_seg_len > iser_ctask->data[ISER_DIR_OUT].data_len) {
+ iser_err("Offset:%ld & DSL:%ld in Data-Out "
+ "inconsistent with total len:%ld, itt:%d\n",
+ buf_offset, data_seg_len,
+ iser_ctask->data[ISER_DIR_OUT].data_len, itt);
+ err = -EINVAL;
+ goto send_data_out_error;
+ }
+ iser_dbg("data-out itt: %d, offset: %ld, sz: %ld\n",
+ itt, buf_offset, data_seg_len);
+
+
+ err = iser_post_send(tx_desc);
+ if (!err)
+ return 0;
+
+send_data_out_error:
+ iser_dto_buffs_release(send_dto);
+ kmem_cache_free(ig.desc_cache, tx_desc);
+ iser_err("conn %p failed err %d\n",conn, err);
+ return err;
+}
+
+int iser_send_control(struct iscsi_conn *conn,
+ struct iscsi_mgmt_task *mtask)
+{
+ struct iscsi_iser_conn *iser_conn = conn->dd_data;
+ struct iser_desc *mdesc = mtask->dd_data;
+ struct iser_dto *send_dto = NULL;
+ unsigned int itt;
+ unsigned long data_seg_len;
+ int err = 0;
+ unsigned char opcode;
+ struct iser_regd_buf *regd_buf;
+ struct iser_device *device;
+
+ if (!iser_conn_state_comp(iser_conn->ib_conn, ISER_CONN_UP)) {
+ iser_err("Failed to send, conn: 0x%p is not up\n", iser_conn->ib_conn);
+ return -EPERM;
+ }
+
+ if (iser_check_xmit(conn,mtask))
+ return -EAGAIN;
+
+ /* build the tx desc regd header and add it to the tx desc dto */
+ mdesc->type = ISCSI_TX_CONTROL;
+ send_dto = &mdesc->dto;
+ send_dto->ctask = NULL;
+ iser_create_send_desc(iser_conn, mdesc);
+
+ device = iser_conn->ib_conn->device;
+
+ iser_reg_single(device, send_dto->regd[0], DMA_TO_DEVICE);
+
+ itt = ntohl(mtask->hdr->itt);
+ opcode = mtask->hdr->opcode & ISCSI_OPCODE_MASK;
+ data_seg_len = ntoh24(mtask->hdr->dlength);
+
+ if (data_seg_len > 0) {
+ regd_buf = &mdesc->data_regd_buf;
+ memset(regd_buf, 0, sizeof(struct iser_regd_buf));
+ regd_buf->device = device;
+ regd_buf->virt_addr = mtask->data;
+ regd_buf->data_size = mtask->data_count;
+ iser_reg_single(device, regd_buf,
+ DMA_TO_DEVICE);
+ iser_dto_add_regd_buff(send_dto, regd_buf,
+ 0,
+ data_seg_len);
+ }
+
+ if (iser_post_receive_control(conn) != 0) {
+ iser_err("post_rcv_buff failed!\n");
+ err = -ENOMEM;
+ goto send_control_error;
+ }
+
+ err = iser_post_send(mdesc);
+ if (!err)
+ return 0;
+
+send_control_error:
+ iser_dto_buffs_release(send_dto);
+ iser_err("conn %p failed err %d\n",conn, err);
+ return err;
+}
+
+/**
+ * iser_rcv_dto_completion - recv DTO completion
+ */
+void iser_rcv_completion(struct iser_desc *rx_desc,
+ unsigned long dto_xfer_len)
+{
+ struct iser_dto *dto = &rx_desc->dto;
+ struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
+ struct iscsi_session *session = conn->iscsi_conn->session;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_iser_cmd_task *iser_ctask;
+ struct iscsi_hdr *hdr;
+ char *rx_data = NULL;
+ int rx_data_len = 0;
+ unsigned int itt;
+ unsigned char opcode;
+
+ hdr = &rx_desc->iscsi_header;
+
+ iser_dbg("op 0x%x itt 0x%x\n", hdr->opcode,hdr->itt);
+
+ if (dto_xfer_len > ISER_TOTAL_HEADERS_LEN) { /* we have data */
+ rx_data_len = dto_xfer_len - ISER_TOTAL_HEADERS_LEN;
+ rx_data = dto->regd[1]->virt_addr;
+ rx_data += dto->offset[1];
+ }
+
+ opcode = hdr->opcode & ISCSI_OPCODE_MASK;
+
+ if (opcode == ISCSI_OP_SCSI_CMD_RSP) {
+ itt = hdr->itt & ISCSI_ITT_MASK; /* mask out cid and age bits */
+ if (!(itt < session->cmds_max))
+ iser_err("itt can't be matched to task!!!"
+ "conn %p opcode %d cmds_max %d itt %d\n",
+ conn->iscsi_conn,opcode,session->cmds_max,itt);
+ /* use the mapping given with the cmds array indexed by itt */
+ ctask = (struct iscsi_cmd_task *)session->cmds[itt];
+ iser_ctask = ctask->dd_data;
+ iser_dbg("itt %d ctask %p\n",itt,ctask);
+ iser_ctask->status = ISER_TASK_STATUS_COMPLETED;
+ iser_ctask_rdma_finalize(iser_ctask);
+ }
+
+ iser_dto_buffs_release(dto);
+
+ iscsi_iser_recv(conn->iscsi_conn, hdr, rx_data, rx_data_len);
+
+ kfree(rx_desc->data);
+ kmem_cache_free(ig.desc_cache, rx_desc);
+
+ /* decrementing conn->post_recv_buf_count only --after-- freeing the *
+ * task eliminates the need to worry on tasks which are completed in *
+ * parallel to the execution of iser_conn_term. So the code that waits *
+ * for the posted rx bufs refcount to become zero handles everything */
+ atomic_dec(&conn->ib_conn->post_recv_buf_count);
+}
+
+void iser_snd_completion(struct iser_desc *tx_desc)
+{
+ struct iser_dto *dto = &tx_desc->dto;
+ struct iser_conn *ib_conn = dto->ib_conn;
+ struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
+ struct iscsi_conn *conn = iser_conn->iscsi_conn;
+ struct iscsi_mgmt_task *mtask;
+
+ iser_dbg("Initiator, Data sent dto=0x%p\n", dto);
+
+ iser_dto_buffs_release(dto);
+
+ if (tx_desc->type == ISCSI_TX_DATAOUT)
+ kmem_cache_free(ig.desc_cache, tx_desc);
+
+ atomic_dec(&ib_conn->post_send_buf_count);
+
+ write_lock(conn->recv_lock);
+ if (conn->suspend_tx) {
+ iser_dbg("%ld resuming tx\n",jiffies);
+ clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
+ scsi_queue_work(conn->session->host, &conn->xmitwork);
+ }
+ write_unlock(conn->recv_lock);
+
+ if (tx_desc->type == ISCSI_TX_CONTROL) {
+ /* this arithmetic is legal by libiscsi dd_data allocation */
+ mtask = (void *) ((long)(void *)tx_desc -
+ sizeof(struct iscsi_mgmt_task));
+ if (mtask->hdr->itt == cpu_to_be32(ISCSI_RESERVED_TAG)) {
+ struct iscsi_session *session = conn->session;
+
+ spin_lock(&conn->session->lock);
+ list_del(&mtask->running);
+ __kfifo_put(session->mgmtpool.queue, (void*)&mtask,
+ sizeof(void*));
+ spin_unlock(&session->lock);
+ }
+ }
+}
+
+void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *iser_ctask)
+
+{
+ iser_ctask->status = ISER_TASK_STATUS_INIT;
+
+ iser_ctask->dir[ISER_DIR_IN] = 0;
+ iser_ctask->dir[ISER_DIR_OUT] = 0;
+
+ iser_ctask->data[ISER_DIR_IN].data_len = 0;
+ iser_ctask->data[ISER_DIR_OUT].data_len = 0;
+
+ memset(&iser_ctask->rdma_regd[ISER_DIR_IN], 0,
+ sizeof(struct iser_regd_buf));
+ memset(&iser_ctask->rdma_regd[ISER_DIR_OUT], 0,
+ sizeof(struct iser_regd_buf));
+}
+
+void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
+{
+ int deferred;
+ int is_rdma_aligned = 1;
+
+ /* if we were reading, copy back to unaligned sglist,
+ * anyway dma_unmap and free the copy
+ */
+ if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL) {
+ is_rdma_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN);
+ }
+ if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
+ is_rdma_aligned = 0;
+ iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT);
+ }
+
+ if (iser_ctask->dir[ISER_DIR_IN]) {
+ deferred = iser_regd_buff_release
+ (&iser_ctask->rdma_regd[ISER_DIR_IN]);
+ if (deferred) {
+ iser_err("References remain for BUF-IN rdma reg\n");
+ BUG();
+ }
+ }
+
+ if (iser_ctask->dir[ISER_DIR_OUT]) {
+ deferred = iser_regd_buff_release
+ (&iser_ctask->rdma_regd[ISER_DIR_OUT]);
+ if (deferred) {
+ iser_err("References remain for BUF-OUT rdma reg\n");
+ BUG();
+ }
+ }
+
+ /* if the data was unaligned, it was already unmapped and then copied */
+ if (is_rdma_aligned)
+ iser_dma_unmap_task_data(iser_ctask);
+}
+
+void iser_dto_buffs_release(struct iser_dto *dto)
+{
+ int i;
+
+ for (i = 0; i < dto->regd_vector_len; i++)
+ iser_regd_buff_release(dto->regd[i]);
+}
+
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
new file mode 100644
index 00000000000..0606744c3f8
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iser_memory.c 6964 2006-05-07 11:11:43Z ogerlitz $
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <asm/io.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+#include "iscsi_iser.h"
+
+#define ISER_KMALLOC_THRESHOLD 0x20000 /* 128K - kmalloc limit */
+
+/**
+ * Decrements the reference count for the
+ * registered buffer & releases it
+ *
+ * returns 0 if released, 1 if deferred
+ */
+int iser_regd_buff_release(struct iser_regd_buf *regd_buf)
+{
+ struct device *dma_device;
+
+ if ((atomic_read(&regd_buf->ref_count) == 0) ||
+ atomic_dec_and_test(&regd_buf->ref_count)) {
+ /* if we used the dma mr, unreg is just NOP */
+ if (regd_buf->reg.is_fmr)
+ iser_unreg_mem(&regd_buf->reg);
+
+ if (regd_buf->dma_addr) {
+ dma_device = regd_buf->device->ib_device->dma_device;
+ dma_unmap_single(dma_device,
+ regd_buf->dma_addr,
+ regd_buf->data_size,
+ regd_buf->direction);
+ }
+ /* else this regd buf is associated with task which we */
+ /* dma_unmap_single/sg later */
+ return 0;
+ } else {
+ iser_dbg("Release deferred, regd.buff: 0x%p\n", regd_buf);
+ return 1;
+ }
+}
+
+/**
+ * iser_reg_single - fills registered buffer descriptor with
+ * registration information
+ */
+void iser_reg_single(struct iser_device *device,
+ struct iser_regd_buf *regd_buf,
+ enum dma_data_direction direction)
+{
+ dma_addr_t dma_addr;
+
+ dma_addr = dma_map_single(device->ib_device->dma_device,
+ regd_buf->virt_addr,
+ regd_buf->data_size, direction);
+ BUG_ON(dma_mapping_error(dma_addr));
+
+ regd_buf->reg.lkey = device->mr->lkey;
+ regd_buf->reg.len = regd_buf->data_size;
+ regd_buf->reg.va = dma_addr;
+ regd_buf->reg.is_fmr = 0;
+
+ regd_buf->dma_addr = dma_addr;
+ regd_buf->direction = direction;
+}
+
+/**
+ * iser_start_rdma_unaligned_sg
+ */
+int iser_start_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ enum iser_data_dir cmd_dir)
+{
+ int dma_nents;
+ struct device *dma_device;
+ char *mem = NULL;
+ struct iser_data_buf *data = &iser_ctask->data[cmd_dir];
+ unsigned long cmd_data_len = data->data_len;
+
+ if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
+ mem = (void *)__get_free_pages(GFP_NOIO,
+ long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+ else
+ mem = kmalloc(cmd_data_len, GFP_NOIO);
+
+ if (mem == NULL) {
+ iser_err("Failed to allocate mem size %d %d for copying sglist\n",
+ data->size,(int)cmd_data_len);
+ return -ENOMEM;
+ }
+
+ if (cmd_dir == ISER_DIR_OUT) {
+ /* copy the unaligned sg the buffer which is used for RDMA */
+ struct scatterlist *sg = (struct scatterlist *)data->buf;
+ int i;
+ char *p, *from;
+
+ for (p = mem, i = 0; i < data->size; i++) {
+ from = kmap_atomic(sg[i].page, KM_USER0);
+ memcpy(p,
+ from + sg[i].offset,
+ sg[i].length);
+ kunmap_atomic(from, KM_USER0);
+ p += sg[i].length;
+ }
+ }
+
+ sg_init_one(&iser_ctask->data_copy[cmd_dir].sg_single, mem, cmd_data_len);
+ iser_ctask->data_copy[cmd_dir].buf =
+ &iser_ctask->data_copy[cmd_dir].sg_single;
+ iser_ctask->data_copy[cmd_dir].size = 1;
+
+ iser_ctask->data_copy[cmd_dir].copy_buf = mem;
+
+ dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+ if (cmd_dir == ISER_DIR_OUT)
+ dma_nents = dma_map_sg(dma_device,
+ &iser_ctask->data_copy[cmd_dir].sg_single,
+ 1, DMA_TO_DEVICE);
+ else
+ dma_nents = dma_map_sg(dma_device,
+ &iser_ctask->data_copy[cmd_dir].sg_single,
+ 1, DMA_FROM_DEVICE);
+
+ BUG_ON(dma_nents == 0);
+
+ iser_ctask->data_copy[cmd_dir].dma_nents = dma_nents;
+ return 0;
+}
+
+/**
+ * iser_finalize_rdma_unaligned_sg
+ */
+void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_cmd_task *iser_ctask,
+ enum iser_data_dir cmd_dir)
+{
+ struct device *dma_device;
+ struct iser_data_buf *mem_copy;
+ unsigned long cmd_data_len;
+
+ dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+ mem_copy = &iser_ctask->data_copy[cmd_dir];
+
+ if (cmd_dir == ISER_DIR_OUT)
+ dma_unmap_sg(dma_device, &mem_copy->sg_single, 1,
+ DMA_TO_DEVICE);
+ else
+ dma_unmap_sg(dma_device, &mem_copy->sg_single, 1,
+ DMA_FROM_DEVICE);
+
+ if (cmd_dir == ISER_DIR_IN) {
+ char *mem;
+ struct scatterlist *sg;
+ unsigned char *p, *to;
+ unsigned int sg_size;
+ int i;
+
+ /* copy back read RDMA to unaligned sg */
+ mem = mem_copy->copy_buf;
+
+ sg = (struct scatterlist *)iser_ctask->data[ISER_DIR_IN].buf;
+ sg_size = iser_ctask->data[ISER_DIR_IN].size;
+
+ for (p = mem, i = 0; i < sg_size; i++){
+ to = kmap_atomic(sg[i].page, KM_SOFTIRQ0);
+ memcpy(to + sg[i].offset,
+ p,
+ sg[i].length);
+ kunmap_atomic(to, KM_SOFTIRQ0);
+ p += sg[i].length;
+ }
+ }
+
+ cmd_data_len = iser_ctask->data[cmd_dir].data_len;
+
+ if (cmd_data_len > ISER_KMALLOC_THRESHOLD)
+ free_pages((unsigned long)mem_copy->copy_buf,
+ long_log2(roundup_pow_of_two(cmd_data_len)) - PAGE_SHIFT);
+ else
+ kfree(mem_copy->copy_buf);
+
+ mem_copy->copy_buf = NULL;
+}
+
+/**
+ * iser_sg_to_page_vec - Translates scatterlist entries to physical addresses
+ * and returns the length of resulting physical address array (may be less than
+ * the original due to possible compaction).
+ *
+ * we build a "page vec" under the assumption that the SG meets the RDMA
+ * alignment requirements. Other then the first and last SG elements, all
+ * the "internal" elements can be compacted into a list whose elements are
+ * dma addresses of physical pages. The code supports also the weird case
+ * where --few fragments of the same page-- are present in the SG as
+ * consecutive elements. Also, it handles one entry SG.
+ */
+static int iser_sg_to_page_vec(struct iser_data_buf *data,
+ struct iser_page_vec *page_vec)
+{
+ struct scatterlist *sg = (struct scatterlist *)data->buf;
+ dma_addr_t first_addr, last_addr, page;
+ int start_aligned, end_aligned;
+ unsigned int cur_page = 0;
+ unsigned long total_sz = 0;
+ int i;
+
+ /* compute the offset of first element */
+ page_vec->offset = (u64) sg[0].offset & ~MASK_4K;
+
+ for (i = 0; i < data->dma_nents; i++) {
+ total_sz += sg_dma_len(&sg[i]);
+
+ first_addr = sg_dma_address(&sg[i]);
+ last_addr = first_addr + sg_dma_len(&sg[i]);
+
+ start_aligned = !(first_addr & ~MASK_4K);
+ end_aligned = !(last_addr & ~MASK_4K);
+
+ /* continue to collect page fragments till aligned or SG ends */
+ while (!end_aligned && (i + 1 < data->dma_nents)) {
+ i++;
+ total_sz += sg_dma_len(&sg[i]);
+ last_addr = sg_dma_address(&sg[i]) + sg_dma_len(&sg[i]);
+ end_aligned = !(last_addr & ~MASK_4K);
+ }
+
+ /* handle the 1st page in the 1st DMA element */
+ if (cur_page == 0) {
+ page = first_addr & MASK_4K;
+ page_vec->pages[cur_page] = page;
+ cur_page++;
+ page += SIZE_4K;
+ } else
+ page = first_addr;
+
+ for (; page < last_addr; page += SIZE_4K) {
+ page_vec->pages[cur_page] = page;
+ cur_page++;
+ }
+
+ }
+ page_vec->data_size = total_sz;
+ iser_dbg("page_vec->data_size:%d cur_page %d\n", page_vec->data_size,cur_page);
+ return cur_page;
+}
+
+#define IS_4K_ALIGNED(addr) ((((unsigned long)addr) & ~MASK_4K) == 0)
+
+/**
+ * iser_data_buf_aligned_len - Tries to determine the maximal correctly aligned
+ * for RDMA sub-list of a scatter-gather list of memory buffers, and returns
+ * the number of entries which are aligned correctly. Supports the case where
+ * consecutive SG elements are actually fragments of the same physcial page.
+ */
+static unsigned int iser_data_buf_aligned_len(struct iser_data_buf *data)
+{
+ struct scatterlist *sg;
+ dma_addr_t end_addr, next_addr;
+ int i, cnt;
+ unsigned int ret_len = 0;
+
+ sg = (struct scatterlist *)data->buf;
+
+ for (cnt = 0, i = 0; i < data->dma_nents; i++, cnt++) {
+ /* iser_dbg("Checking sg iobuf [%d]: phys=0x%08lX "
+ "offset: %ld sz: %ld\n", i,
+ (unsigned long)page_to_phys(sg[i].page),
+ (unsigned long)sg[i].offset,
+ (unsigned long)sg[i].length); */
+ end_addr = sg_dma_address(&sg[i]) +
+ sg_dma_len(&sg[i]);
+ /* iser_dbg("Checking sg iobuf end address "
+ "0x%08lX\n", end_addr); */
+ if (i + 1 < data->dma_nents) {
+ next_addr = sg_dma_address(&sg[i+1]);
+ /* are i, i+1 fragments of the same page? */
+ if (end_addr == next_addr)
+ continue;
+ else if (!IS_4K_ALIGNED(end_addr)) {
+ ret_len = cnt + 1;
+ break;
+ }
+ }
+ }
+ if (i == data->dma_nents)
+ ret_len = cnt; /* loop ended */
+ iser_dbg("Found %d aligned entries out of %d in sg:0x%p\n",
+ ret_len, data->dma_nents, data);
+ return ret_len;
+}
+
+static void iser_data_buf_dump(struct iser_data_buf *data)
+{
+ struct scatterlist *sg = (struct scatterlist *)data->buf;
+ int i;
+
+ for (i = 0; i < data->dma_nents; i++)
+ iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
+ "off:0x%x sz:0x%x dma_len:0x%x\n",
+ i, (unsigned long)sg_dma_address(&sg[i]),
+ sg[i].page, sg[i].offset,
+ sg[i].length,sg_dma_len(&sg[i]));
+}
+
+static void iser_dump_page_vec(struct iser_page_vec *page_vec)
+{
+ int i;
+
+ iser_err("page vec length %d data size %d\n",
+ page_vec->length, page_vec->data_size);
+ for (i = 0; i < page_vec->length; i++)
+ iser_err("%d %lx\n",i,(unsigned long)page_vec->pages[i]);
+}
+
+static void iser_page_vec_build(struct iser_data_buf *data,
+ struct iser_page_vec *page_vec)
+{
+ int page_vec_len = 0;
+
+ page_vec->length = 0;
+ page_vec->offset = 0;
+
+ iser_dbg("Translating sg sz: %d\n", data->dma_nents);
+ page_vec_len = iser_sg_to_page_vec(data,page_vec);
+ iser_dbg("sg len %d page_vec_len %d\n", data->dma_nents,page_vec_len);
+
+ page_vec->length = page_vec_len;
+
+ if (page_vec_len * SIZE_4K < page_vec->data_size) {
+ iser_err("page_vec too short to hold this SG\n");
+ iser_data_buf_dump(data);
+ iser_dump_page_vec(page_vec);
+ BUG();
+ }
+}
+
+int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+ struct iser_data_buf *data,
+ enum iser_data_dir iser_dir,
+ enum dma_data_direction dma_dir)
+{
+ struct device *dma_device;
+
+ iser_ctask->dir[iser_dir] = 1;
+ dma_device =
+ iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+ data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
+ if (data->dma_nents == 0) {
+ iser_err("dma_map_sg failed!!!\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+{
+ struct device *dma_device;
+ struct iser_data_buf *data;
+
+ dma_device =
+ iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+ if (iser_ctask->dir[ISER_DIR_IN]) {
+ data = &iser_ctask->data[ISER_DIR_IN];
+ dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
+ }
+
+ if (iser_ctask->dir[ISER_DIR_OUT]) {
+ data = &iser_ctask->data[ISER_DIR_OUT];
+ dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
+ }
+}
+
+/**
+ * iser_reg_rdma_mem - Registers memory intended for RDMA,
+ * obtaining rkey and va
+ *
+ * returns 0 on success, errno code on failure
+ */
+int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
+ enum iser_data_dir cmd_dir)
+{
+ struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn;
+ struct iser_device *device = ib_conn->device;
+ struct iser_data_buf *mem = &iser_ctask->data[cmd_dir];
+ struct iser_regd_buf *regd_buf;
+ int aligned_len;
+ int err;
+ int i;
+ struct scatterlist *sg;
+
+ regd_buf = &iser_ctask->rdma_regd[cmd_dir];
+
+ aligned_len = iser_data_buf_aligned_len(mem);
+ if (aligned_len != mem->dma_nents) {
+ iser_err("rdma alignment violation %d/%d aligned\n",
+ aligned_len, mem->size);
+ iser_data_buf_dump(mem);
+
+ /* unmap the command data before accessing it */
+ iser_dma_unmap_task_data(iser_ctask);
+
+ /* allocate copy buf, if we are writing, copy the */
+ /* unaligned scatterlist, dma map the copy */
+ if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
+ return -ENOMEM;
+ mem = &iser_ctask->data_copy[cmd_dir];
+ }
+
+ /* if there a single dma entry, FMR is not needed */
+ if (mem->dma_nents == 1) {
+ sg = (struct scatterlist *)mem->buf;
+
+ regd_buf->reg.lkey = device->mr->lkey;
+ regd_buf->reg.rkey = device->mr->rkey;
+ regd_buf->reg.len = sg_dma_len(&sg[0]);
+ regd_buf->reg.va = sg_dma_address(&sg[0]);
+ regd_buf->reg.is_fmr = 0;
+
+ iser_dbg("PHYSICAL Mem.register: lkey: 0x%08X rkey: 0x%08X "
+ "va: 0x%08lX sz: %ld]\n",
+ (unsigned int)regd_buf->reg.lkey,
+ (unsigned int)regd_buf->reg.rkey,
+ (unsigned long)regd_buf->reg.va,
+ (unsigned long)regd_buf->reg.len);
+ } else { /* use FMR for multiple dma entries */
+ iser_page_vec_build(mem, ib_conn->page_vec);
+ err = iser_reg_page_vec(ib_conn, ib_conn->page_vec, &regd_buf->reg);
+ if (err) {
+ iser_data_buf_dump(mem);
+ iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents,
+ ntoh24(iser_ctask->desc.iscsi_header.dlength));
+ iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n",
+ ib_conn->page_vec->data_size, ib_conn->page_vec->length,
+ ib_conn->page_vec->offset);
+ for (i=0 ; i<ib_conn->page_vec->length ; i++)
+ iser_err("page_vec[%d] = 0x%llx\n", i,
+ (unsigned long long) ib_conn->page_vec->pages[i]);
+ return err;
+ }
+ }
+
+ /* take a reference on this regd buf such that it will not be released *
+ * (eg in send dto completion) before we get the scsi response */
+ atomic_inc(&regd_buf->ref_count);
+ return 0;
+}
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
new file mode 100644
index 00000000000..18a00003499
--- /dev/null
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id: iser_verbs.c 7051 2006-05-10 12:29:11Z ogerlitz $
+ */
+#include <asm/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+#include "iscsi_iser.h"
+
+#define ISCSI_ISER_MAX_CONN 8
+#define ISER_MAX_CQ_LEN ((ISER_QP_MAX_RECV_DTOS + \
+ ISER_QP_MAX_REQ_DTOS) * \
+ ISCSI_ISER_MAX_CONN)
+
+static void iser_cq_tasklet_fn(unsigned long data);
+static void iser_cq_callback(struct ib_cq *cq, void *cq_context);
+static void iser_comp_error_worker(void *data);
+
+static void iser_cq_event_callback(struct ib_event *cause, void *context)
+{
+ iser_err("got cq event %d \n", cause->event);
+}
+
+static void iser_qp_event_callback(struct ib_event *cause, void *context)
+{
+ iser_err("got qp event %d\n",cause->event);
+}
+
+/**
+ * iser_create_device_ib_res - creates Protection Domain (PD), Completion
+ * Queue (CQ), DMA Memory Region (DMA MR) with the device associated with
+ * the adapator.
+ *
+ * returns 0 on success, -1 on failure
+ */
+static int iser_create_device_ib_res(struct iser_device *device)
+{
+ device->pd = ib_alloc_pd(device->ib_device);
+ if (IS_ERR(device->pd))
+ goto pd_err;
+
+ device->cq = ib_create_cq(device->ib_device,
+ iser_cq_callback,
+ iser_cq_event_callback,
+ (void *)device,
+ ISER_MAX_CQ_LEN);
+ if (IS_ERR(device->cq))
+ goto cq_err;
+
+ if (ib_req_notify_cq(device->cq, IB_CQ_NEXT_COMP))
+ goto cq_arm_err;
+
+ tasklet_init(&device->cq_tasklet,
+ iser_cq_tasklet_fn,
+ (unsigned long)device);
+
+ device->mr = ib_get_dma_mr(device->pd, IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE |
+ IB_ACCESS_REMOTE_READ);
+ if (IS_ERR(device->mr))
+ goto dma_mr_err;
+
+ return 0;
+
+dma_mr_err:
+ tasklet_kill(&device->cq_tasklet);
+cq_arm_err:
+ ib_destroy_cq(device->cq);
+cq_err:
+ ib_dealloc_pd(device->pd);
+pd_err:
+ iser_err("failed to allocate an IB resource\n");
+ return -1;
+}
+
+/**
+ * iser_free_device_ib_res - destory/dealloc/dereg the DMA MR,
+ * CQ and PD created with the device associated with the adapator.
+ */
+static void iser_free_device_ib_res(struct iser_device *device)
+{
+ BUG_ON(device->mr == NULL);
+
+ tasklet_kill(&device->cq_tasklet);
+
+ (void)ib_dereg_mr(device->mr);
+ (void)ib_destroy_cq(device->cq);
+ (void)ib_dealloc_pd(device->pd);
+
+ device->mr = NULL;
+ device->cq = NULL;
+ device->pd = NULL;
+}
+
+/**
+ * iser_create_ib_conn_res - Creates FMR pool and Queue-Pair (QP)
+ *
+ * returns 0 on success, -1 on failure
+ */
+static int iser_create_ib_conn_res(struct iser_conn *ib_conn)
+{
+ struct iser_device *device;
+ struct ib_qp_init_attr init_attr;
+ int ret;
+ struct ib_fmr_pool_param params;
+
+ BUG_ON(ib_conn->device == NULL);
+
+ device = ib_conn->device;
+
+ ib_conn->page_vec = kmalloc(sizeof(struct iser_page_vec) +
+ (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE +1)),
+ GFP_KERNEL);
+ if (!ib_conn->page_vec) {
+ ret = -ENOMEM;
+ goto alloc_err;
+ }
+ ib_conn->page_vec->pages = (u64 *) (ib_conn->page_vec + 1);
+
+ params.page_shift = SHIFT_4K;
+ /* when the first/last SG element are not start/end *
+ * page aligned, the map whould be of N+1 pages */
+ params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1;
+ /* make the pool size twice the max number of SCSI commands *
+ * the ML is expected to queue, watermark for unmap at 50% */
+ params.pool_size = ISCSI_XMIT_CMDS_MAX * 2;
+ params.dirty_watermark = ISCSI_XMIT_CMDS_MAX;
+ params.cache = 0;
+ params.flush_function = NULL;
+ params.access = (IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE |
+ IB_ACCESS_REMOTE_READ);
+
+ ib_conn->fmr_pool = ib_create_fmr_pool(device->pd, &params);
+ if (IS_ERR(ib_conn->fmr_pool)) {
+ ret = PTR_ERR(ib_conn->fmr_pool);
+ goto fmr_pool_err;
+ }
+
+ memset(&init_attr, 0, sizeof init_attr);
+
+ init_attr.event_handler = iser_qp_event_callback;
+ init_attr.qp_context = (void *)ib_conn;
+ init_attr.send_cq = device->cq;
+ init_attr.recv_cq = device->cq;
+ init_attr.cap.max_send_wr = ISER_QP_MAX_REQ_DTOS;
+ init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS;
+ init_attr.cap.max_send_sge = MAX_REGD_BUF_VECTOR_LEN;
+ init_attr.cap.max_recv_sge = 2;
+ init_attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+ init_attr.qp_type = IB_QPT_RC;
+
+ ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr);
+ if (ret)
+ goto qp_err;
+
+ ib_conn->qp = ib_conn->cma_id->qp;
+ iser_err("setting conn %p cma_id %p: fmr_pool %p qp %p\n",
+ ib_conn, ib_conn->cma_id,
+ ib_conn->fmr_pool, ib_conn->cma_id->qp);
+ return ret;
+
+qp_err:
+ (void)ib_destroy_fmr_pool(ib_conn->fmr_pool);
+fmr_pool_err:
+ kfree(ib_conn->page_vec);
+alloc_err:
+ iser_err("unable to alloc mem or create resource, err %d\n", ret);
+ return ret;
+}
+
+/**
+ * releases the FMR pool, QP and CMA ID objects, returns 0 on success,
+ * -1 on failure
+ */
+static int iser_free_ib_conn_res(struct iser_conn *ib_conn)
+{
+ BUG_ON(ib_conn == NULL);
+
+ iser_err("freeing conn %p cma_id %p fmr pool %p qp %p\n",
+ ib_conn, ib_conn->cma_id,
+ ib_conn->fmr_pool, ib_conn->qp);
+
+ /* qp is created only once both addr & route are resolved */
+ if (ib_conn->fmr_pool != NULL)
+ ib_destroy_fmr_pool(ib_conn->fmr_pool);
+
+ if (ib_conn->qp != NULL)
+ rdma_destroy_qp(ib_conn->cma_id);
+
+ if (ib_conn->cma_id != NULL)
+ rdma_destroy_id(ib_conn->cma_id);
+
+ ib_conn->fmr_pool = NULL;
+ ib_conn->qp = NULL;
+ ib_conn->cma_id = NULL;
+ kfree(ib_conn->page_vec);
+
+ return 0;
+}
+
+/**
+ * based on the resolved device node GUID see if there already allocated
+ * device for this device. If there's no such, create one.
+ */
+static
+struct iser_device *iser_device_find_by_ib_device(struct rdma_cm_id *cma_id)
+{
+ struct list_head *p_list;
+ struct iser_device *device = NULL;
+
+ mutex_lock(&ig.device_list_mutex);
+
+ p_list = ig.device_list.next;
+ while (p_list != &ig.device_list) {
+ device = list_entry(p_list, struct iser_device, ig_list);
+ /* find if there's a match using the node GUID */
+ if (device->ib_device->node_guid == cma_id->device->node_guid)
+ break;
+ }
+
+ if (device == NULL) {
+ device = kzalloc(sizeof *device, GFP_KERNEL);
+ if (device == NULL)
+ goto out;
+ /* assign this device to the device */
+ device->ib_device = cma_id->device;
+ /* init the device and link it into ig device list */
+ if (iser_create_device_ib_res(device)) {
+ kfree(device);
+ device = NULL;
+ goto out;
+ }
+ list_add(&device->ig_list, &ig.device_list);
+ }
+out:
+ BUG_ON(device == NULL);
+ device->refcount++;
+ mutex_unlock(&ig.device_list_mutex);
+ return device;
+}
+
+/* if there's no demand for this device, release it */
+static void iser_device_try_release(struct iser_device *device)
+{
+ mutex_lock(&ig.device_list_mutex);
+ device->refcount--;
+ iser_err("device %p refcount %d\n",device,device->refcount);
+ if (!device->refcount) {
+ iser_free_device_ib_res(device);
+ list_del(&device->ig_list);
+ kfree(device);
+ }
+ mutex_unlock(&ig.device_list_mutex);
+}
+
+int iser_conn_state_comp(struct iser_conn *ib_conn,
+ enum iser_ib_conn_state comp)
+{
+ int ret;
+
+ spin_lock_bh(&ib_conn->lock);
+ ret = (ib_conn->state == comp);
+ spin_unlock_bh(&ib_conn->lock);
+ return ret;
+}
+
+static int iser_conn_state_comp_exch(struct iser_conn *ib_conn,
+ enum iser_ib_conn_state comp,
+ enum iser_ib_conn_state exch)
+{
+ int ret;
+
+ spin_lock_bh(&ib_conn->lock);
+ if ((ret = (ib_conn->state == comp)))
+ ib_conn->state = exch;
+ spin_unlock_bh(&ib_conn->lock);
+ return ret;
+}
+
+/**
+ * triggers start of the disconnect procedures and wait for them to be done
+ */
+void iser_conn_terminate(struct iser_conn *ib_conn)
+{
+ int err = 0;
+
+ /* change the ib conn state only if the conn is UP, however always call
+ * rdma_disconnect since this is the only way to cause the CMA to change
+ * the QP state to ERROR
+ */
+
+ iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP, ISER_CONN_TERMINATING);
+ err = rdma_disconnect(ib_conn->cma_id);
+ if (err)
+ iser_err("Failed to disconnect, conn: 0x%p err %d\n",
+ ib_conn,err);
+
+ wait_event_interruptible(ib_conn->wait,
+ ib_conn->state == ISER_CONN_DOWN);
+
+ iser_conn_release(ib_conn);
+}
+
+static void iser_connect_error(struct rdma_cm_id *cma_id)
+{
+ struct iser_conn *ib_conn;
+ ib_conn = (struct iser_conn *)cma_id->context;
+
+ ib_conn->state = ISER_CONN_DOWN;
+ wake_up_interruptible(&ib_conn->wait);
+}
+
+static void iser_addr_handler(struct rdma_cm_id *cma_id)
+{
+ struct iser_device *device;
+ struct iser_conn *ib_conn;
+ int ret;
+
+ device = iser_device_find_by_ib_device(cma_id);
+ ib_conn = (struct iser_conn *)cma_id->context;
+ ib_conn->device = device;
+
+ ret = rdma_resolve_route(cma_id, 1000);
+ if (ret) {
+ iser_err("resolve route failed: %d\n", ret);
+ iser_connect_error(cma_id);
+ }
+ return;
+}
+
+static void iser_route_handler(struct rdma_cm_id *cma_id)
+{
+ struct rdma_conn_param conn_param;
+ int ret;
+
+ ret = iser_create_ib_conn_res((struct iser_conn *)cma_id->context);
+ if (ret)
+ goto failure;
+
+ iser_dbg("path.mtu is %d setting it to %d\n",
+ cma_id->route.path_rec->mtu, IB_MTU_1024);
+
+ /* we must set the MTU to 1024 as this is what the target is assuming */
+ if (cma_id->route.path_rec->mtu > IB_MTU_1024)
+ cma_id->route.path_rec->mtu = IB_MTU_1024;
+
+ memset(&conn_param, 0, sizeof conn_param);
+ conn_param.responder_resources = 4;
+ conn_param.initiator_depth = 1;
+ conn_param.retry_count = 7;
+ conn_param.rnr_retry_count = 6;
+
+ ret = rdma_connect(cma_id, &conn_param);
+ if (ret) {
+ iser_err("failure connecting: %d\n", ret);
+ goto failure;
+ }
+
+ return;
+failure:
+ iser_connect_error(cma_id);
+}
+
+static void iser_connected_handler(struct rdma_cm_id *cma_id)
+{
+ struct iser_conn *ib_conn;
+
+ ib_conn = (struct iser_conn *)cma_id->context;
+ ib_conn->state = ISER_CONN_UP;
+ wake_up_interruptible(&ib_conn->wait);
+}
+
+static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
+{
+ struct iser_conn *ib_conn;
+
+ ib_conn = (struct iser_conn *)cma_id->context;
+ ib_conn->disc_evt_flag = 1;
+
+ /* getting here when the state is UP means that the conn is being *
+ * terminated asynchronously from the iSCSI layer's perspective. */
+ if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
+ ISER_CONN_TERMINATING))
+ iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
+ ISCSI_ERR_CONN_FAILED);
+
+ /* Complete the termination process if no posts are pending */
+ if ((atomic_read(&ib_conn->post_recv_buf_count) == 0) &&
+ (atomic_read(&ib_conn->post_send_buf_count) == 0)) {
+ ib_conn->state = ISER_CONN_DOWN;
+ wake_up_interruptible(&ib_conn->wait);
+ }
+}
+
+static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
+{
+ int ret = 0;
+
+ iser_err("event %d conn %p id %p\n",event->event,cma_id->context,cma_id);
+
+ switch (event->event) {
+ case RDMA_CM_EVENT_ADDR_RESOLVED:
+ iser_addr_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_ROUTE_RESOLVED:
+ iser_route_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_ESTABLISHED:
+ iser_connected_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_ADDR_ERROR:
+ case RDMA_CM_EVENT_ROUTE_ERROR:
+ case RDMA_CM_EVENT_CONNECT_ERROR:
+ case RDMA_CM_EVENT_UNREACHABLE:
+ case RDMA_CM_EVENT_REJECTED:
+ iser_err("event: %d, error: %d\n", event->event, event->status);
+ iser_connect_error(cma_id);
+ break;
+ case RDMA_CM_EVENT_DISCONNECTED:
+ iser_disconnected_handler(cma_id);
+ break;
+ case RDMA_CM_EVENT_DEVICE_REMOVAL:
+ BUG();
+ break;
+ case RDMA_CM_EVENT_CONNECT_RESPONSE:
+ BUG();
+ break;
+ case RDMA_CM_EVENT_CONNECT_REQUEST:
+ default:
+ break;
+ }
+ return ret;
+}
+
+int iser_conn_init(struct iser_conn **ibconn)
+{
+ struct iser_conn *ib_conn;
+
+ ib_conn = kzalloc(sizeof *ib_conn, GFP_KERNEL);
+ if (!ib_conn) {
+ iser_err("can't alloc memory for struct iser_conn\n");
+ return -ENOMEM;
+ }
+ ib_conn->state = ISER_CONN_INIT;
+ init_waitqueue_head(&ib_conn->wait);
+ atomic_set(&ib_conn->post_recv_buf_count, 0);
+ atomic_set(&ib_conn->post_send_buf_count, 0);
+ INIT_WORK(&ib_conn->comperror_work, iser_comp_error_worker,
+ ib_conn);
+ INIT_LIST_HEAD(&ib_conn->conn_list);
+ spin_lock_init(&ib_conn->lock);
+
+ *ibconn = ib_conn;
+ return 0;
+}
+
+ /**
+ * starts the process of connecting to the target
+ * sleeps untill the connection is established or rejected
+ */
+int iser_connect(struct iser_conn *ib_conn,
+ struct sockaddr_in *src_addr,
+ struct sockaddr_in *dst_addr,
+ int non_blocking)
+{
+ struct sockaddr *src, *dst;
+ int err = 0;
+
+ sprintf(ib_conn->name,"%d.%d.%d.%d:%d",
+ NIPQUAD(dst_addr->sin_addr.s_addr), dst_addr->sin_port);
+
+ /* the device is known only --after-- address resolution */
+ ib_conn->device = NULL;
+
+ iser_err("connecting to: %d.%d.%d.%d, port 0x%x\n",
+ NIPQUAD(dst_addr->sin_addr), dst_addr->sin_port);
+
+ ib_conn->state = ISER_CONN_PENDING;
+
+ ib_conn->cma_id = rdma_create_id(iser_cma_handler,
+ (void *)ib_conn,
+ RDMA_PS_TCP);
+ if (IS_ERR(ib_conn->cma_id)) {
+ err = PTR_ERR(ib_conn->cma_id);
+ iser_err("rdma_create_id failed: %d\n", err);
+ goto id_failure;
+ }
+
+ src = (struct sockaddr *)src_addr;
+ dst = (struct sockaddr *)dst_addr;
+ err = rdma_resolve_addr(ib_conn->cma_id, src, dst, 1000);
+ if (err) {
+ iser_err("rdma_resolve_addr failed: %d\n", err);
+ goto addr_failure;
+ }
+
+ if (!non_blocking) {
+ wait_event_interruptible(ib_conn->wait,
+ (ib_conn->state != ISER_CONN_PENDING));
+
+ if (ib_conn->state != ISER_CONN_UP) {
+ err = -EIO;
+ goto connect_failure;
+ }
+ }
+
+ mutex_lock(&ig.connlist_mutex);
+ list_add(&ib_conn->conn_list, &ig.connlist);
+ mutex_unlock(&ig.connlist_mutex);
+ return 0;
+
+id_failure:
+ ib_conn->cma_id = NULL;
+addr_failure:
+ ib_conn->state = ISER_CONN_DOWN;
+connect_failure:
+ iser_conn_release(ib_conn);
+ return err;
+}
+
+/**
+ * Frees all conn objects and deallocs conn descriptor
+ */
+void iser_conn_release(struct iser_conn *ib_conn)
+{
+ struct iser_device *device = ib_conn->device;
+
+ BUG_ON(ib_conn->state != ISER_CONN_DOWN);
+
+ mutex_lock(&ig.connlist_mutex);
+ list_del(&ib_conn->conn_list);
+ mutex_unlock(&ig.connlist_mutex);
+
+ iser_free_ib_conn_res(ib_conn);
+ ib_conn->device = NULL;
+ /* on EVENT_ADDR_ERROR there's no device yet for this conn */
+ if (device != NULL)
+ iser_device_try_release(device);
+ if (ib_conn->iser_conn)
+ ib_conn->iser_conn->ib_conn = NULL;
+ kfree(ib_conn);
+}
+
+
+/**
+ * iser_reg_page_vec - Register physical memory
+ *
+ * returns: 0 on success, errno code on failure
+ */
+int iser_reg_page_vec(struct iser_conn *ib_conn,
+ struct iser_page_vec *page_vec,
+ struct iser_mem_reg *mem_reg)
+{
+ struct ib_pool_fmr *mem;
+ u64 io_addr;
+ u64 *page_list;
+ int status;
+
+ page_list = page_vec->pages;
+ io_addr = page_list[0];
+
+ mem = ib_fmr_pool_map_phys(ib_conn->fmr_pool,
+ page_list,
+ page_vec->length,
+ io_addr);
+
+ if (IS_ERR(mem)) {
+ status = (int)PTR_ERR(mem);
+ iser_err("ib_fmr_pool_map_phys failed: %d\n", status);
+ return status;
+ }
+
+ mem_reg->lkey = mem->fmr->lkey;
+ mem_reg->rkey = mem->fmr->rkey;
+ mem_reg->len = page_vec->length * SIZE_4K;
+ mem_reg->va = io_addr;
+ mem_reg->is_fmr = 1;
+ mem_reg->mem_h = (void *)mem;
+
+ mem_reg->va += page_vec->offset;
+ mem_reg->len = page_vec->data_size;
+
+ iser_dbg("PHYSICAL Mem.register, [PHYS p_array: 0x%p, sz: %d, "
+ "entry[0]: (0x%08lx,%ld)] -> "
+ "[lkey: 0x%08X mem_h: 0x%p va: 0x%08lX sz: %ld]\n",
+ page_vec, page_vec->length,
+ (unsigned long)page_vec->pages[0],
+ (unsigned long)page_vec->data_size,
+ (unsigned int)mem_reg->lkey, mem_reg->mem_h,
+ (unsigned long)mem_reg->va, (unsigned long)mem_reg->len);
+ return 0;
+}
+
+/**
+ * Unregister (previosuly registered) memory.
+ */
+void iser_unreg_mem(struct iser_mem_reg *reg)
+{
+ int ret;
+
+ iser_dbg("PHYSICAL Mem.Unregister mem_h %p\n",reg->mem_h);
+
+ ret = ib_fmr_pool_unmap((struct ib_pool_fmr *)reg->mem_h);
+ if (ret)
+ iser_err("ib_fmr_pool_unmap failed %d\n", ret);
+
+ reg->mem_h = NULL;
+}
+
+/**
+ * iser_dto_to_iov - builds IOV from a dto descriptor
+ */
+static void iser_dto_to_iov(struct iser_dto *dto, struct ib_sge *iov, int iov_len)
+{
+ int i;
+ struct ib_sge *sge;
+ struct iser_regd_buf *regd_buf;
+
+ if (dto->regd_vector_len > iov_len) {
+ iser_err("iov size %d too small for posting dto of len %d\n",
+ iov_len, dto->regd_vector_len);
+ BUG();
+ }
+
+ for (i = 0; i < dto->regd_vector_len; i++) {
+ sge = &iov[i];
+ regd_buf = dto->regd[i];
+
+ sge->addr = regd_buf->reg.va;
+ sge->length = regd_buf->reg.len;
+ sge->lkey = regd_buf->reg.lkey;
+
+ if (dto->used_sz[i] > 0) /* Adjust size */
+ sge->length = dto->used_sz[i];
+
+ /* offset and length should not exceed the regd buf length */
+ if (sge->length + dto->offset[i] > regd_buf->reg.len) {
+ iser_err("Used len:%ld + offset:%d, exceed reg.buf.len:"
+ "%ld in dto:0x%p [%d], va:0x%08lX\n",
+ (unsigned long)sge->length, dto->offset[i],
+ (unsigned long)regd_buf->reg.len, dto, i,
+ (unsigned long)sge->addr);
+ BUG();
+ }
+
+ sge->addr += dto->offset[i]; /* Adjust offset */
+ }
+}
+
+/**
+ * iser_post_recv - Posts a receive buffer.
+ *
+ * returns 0 on success, -1 on failure
+ */
+int iser_post_recv(struct iser_desc *rx_desc)
+{
+ int ib_ret, ret_val = 0;
+ struct ib_recv_wr recv_wr, *recv_wr_failed;
+ struct ib_sge iov[2];
+ struct iser_conn *ib_conn;
+ struct iser_dto *recv_dto = &rx_desc->dto;
+
+ /* Retrieve conn */
+ ib_conn = recv_dto->ib_conn;
+
+ iser_dto_to_iov(recv_dto, iov, 2);
+
+ recv_wr.next = NULL;
+ recv_wr.sg_list = iov;
+ recv_wr.num_sge = recv_dto->regd_vector_len;
+ recv_wr.wr_id = (unsigned long)rx_desc;
+
+ atomic_inc(&ib_conn->post_recv_buf_count);
+ ib_ret = ib_post_recv(ib_conn->qp, &recv_wr, &recv_wr_failed);
+ if (ib_ret) {
+ iser_err("ib_post_recv failed ret=%d\n", ib_ret);
+ atomic_dec(&ib_conn->post_recv_buf_count);
+ ret_val = -1;
+ }
+
+ return ret_val;
+}
+
+/**
+ * iser_start_send - Initiate a Send DTO operation
+ *
+ * returns 0 on success, -1 on failure
+ */
+int iser_post_send(struct iser_desc *tx_desc)
+{
+ int ib_ret, ret_val = 0;
+ struct ib_send_wr send_wr, *send_wr_failed;
+ struct ib_sge iov[MAX_REGD_BUF_VECTOR_LEN];
+ struct iser_conn *ib_conn;
+ struct iser_dto *dto = &tx_desc->dto;
+
+ ib_conn = dto->ib_conn;
+
+ iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN);
+
+ send_wr.next = NULL;
+ send_wr.wr_id = (unsigned long)tx_desc;
+ send_wr.sg_list = iov;
+ send_wr.num_sge = dto->regd_vector_len;
+ send_wr.opcode = IB_WR_SEND;
+ send_wr.send_flags = dto->notify_enable ? IB_SEND_SIGNALED : 0;
+
+ atomic_inc(&ib_conn->post_send_buf_count);
+
+ ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed);
+ if (ib_ret) {
+ iser_err("Failed to start SEND DTO, dto: 0x%p, IOV len: %d\n",
+ dto, dto->regd_vector_len);
+ iser_err("ib_post_send failed, ret:%d\n", ib_ret);
+ atomic_dec(&ib_conn->post_send_buf_count);
+ ret_val = -1;
+ }
+
+ return ret_val;
+}
+
+static void iser_comp_error_worker(void *data)
+{
+ struct iser_conn *ib_conn = data;
+
+ /* getting here when the state is UP means that the conn is being *
+ * terminated asynchronously from the iSCSI layer's perspective. */
+ if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP,
+ ISER_CONN_TERMINATING))
+ iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn,
+ ISCSI_ERR_CONN_FAILED);
+
+ /* complete the termination process if disconnect event was delivered *
+ * note there are no more non completed posts to the QP */
+ if (ib_conn->disc_evt_flag) {
+ ib_conn->state = ISER_CONN_DOWN;
+ wake_up_interruptible(&ib_conn->wait);
+ }
+}
+
+static void iser_handle_comp_error(struct iser_desc *desc)
+{
+ struct iser_dto *dto = &desc->dto;
+ struct iser_conn *ib_conn = dto->ib_conn;
+
+ iser_dto_buffs_release(dto);
+
+ if (desc->type == ISCSI_RX) {
+ kfree(desc->data);
+ kmem_cache_free(ig.desc_cache, desc);
+ atomic_dec(&ib_conn->post_recv_buf_count);
+ } else { /* type is TX control/command/dataout */
+ if (desc->type == ISCSI_TX_DATAOUT)
+ kmem_cache_free(ig.desc_cache, desc);
+ atomic_dec(&ib_conn->post_send_buf_count);
+ }
+
+ if (atomic_read(&ib_conn->post_recv_buf_count) == 0 &&
+ atomic_read(&ib_conn->post_send_buf_count) == 0)
+ schedule_work(&ib_conn->comperror_work);
+}
+
+static void iser_cq_tasklet_fn(unsigned long data)
+{
+ struct iser_device *device = (struct iser_device *)data;
+ struct ib_cq *cq = device->cq;
+ struct ib_wc wc;
+ struct iser_desc *desc;
+ unsigned long xfer_len;
+
+ while (ib_poll_cq(cq, 1, &wc) == 1) {
+ desc = (struct iser_desc *) (unsigned long) wc.wr_id;
+ BUG_ON(desc == NULL);
+
+ if (wc.status == IB_WC_SUCCESS) {
+ if (desc->type == ISCSI_RX) {
+ xfer_len = (unsigned long)wc.byte_len;
+ iser_rcv_completion(desc, xfer_len);
+ } else /* type == ISCSI_TX_CONTROL/SCSI_CMD/DOUT */
+ iser_snd_completion(desc);
+ } else {
+ iser_err("comp w. error op %d status %d\n",desc->type,wc.status);
+ iser_handle_comp_error(desc);
+ }
+ }
+ /* #warning "it is assumed here that arming CQ only once its empty" *
+ * " would not cause interrupts to be missed" */
+ ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+}
+
+static void iser_cq_callback(struct ib_cq *cq, void *cq_context)
+{
+ struct iser_device *device = (struct iser_device *)cq_context;
+
+ tasklet_schedule(&device->cq_tasklet);
+}
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 4e22afef720..44b9e5be668 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -77,6 +77,14 @@ MODULE_PARM_DESC(topspin_workarounds,
static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
+static int mellanox_workarounds = 1;
+
+module_param(mellanox_workarounds, int, 0444);
+MODULE_PARM_DESC(mellanox_workarounds,
+ "Enable workarounds for Mellanox SRP target bugs if != 0");
+
+static const u8 mellanox_oui[3] = { 0x00, 0x02, 0xc9 };
+
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
static void srp_completion(struct ib_cq *cq, void *target_ptr);
@@ -88,6 +96,8 @@ static struct ib_client srp_client = {
.remove = srp_remove_one
};
+static struct ib_sa_client srp_sa_client;
+
static inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
{
return (struct srp_target_port *) host->hostdata;
@@ -259,7 +269,8 @@ static int srp_lookup_path(struct srp_target_port *target)
init_completion(&target->done);
- target->path_query_id = ib_sa_path_rec_get(target->srp_host->dev->dev,
+ target->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
+ target->srp_host->dev->dev,
target->srp_host->port,
&target->path,
IB_SA_PATH_REC_DGID |
@@ -322,7 +333,7 @@ static int srp_send_req(struct srp_target_port *target)
req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
SRP_BUF_FORMAT_INDIRECT);
/*
- * In the published SRP specification (draft rev. 16a), the
+ * In the published SRP specification (draft rev. 16a), the
* port identifier format is 8 bytes of ID extension followed
* by 8 bytes of GUID. Older drafts put the two halves in the
* opposite order, so that the GUID comes first.
@@ -526,8 +537,10 @@ static int srp_reconnect_target(struct srp_target_port *target)
while (ib_poll_cq(target->cq, 1, &wc) > 0)
; /* nothing */
+ spin_lock_irq(target->scsi_host->host_lock);
list_for_each_entry_safe(req, tmp, &target->req_queue, list)
srp_reset_req(target, req);
+ spin_unlock_irq(target->scsi_host->host_lock);
target->rx_head = 0;
target->tx_head = 0;
@@ -567,7 +580,7 @@ err:
return ret;
}
-static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
+static int srp_map_fmr(struct srp_target_port *target, struct scatterlist *scat,
int sg_cnt, struct srp_request *req,
struct srp_direct_buf *buf)
{
@@ -577,10 +590,15 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
int page_cnt;
int i, j;
int ret;
+ struct srp_device *dev = target->srp_host->dev;
if (!dev->fmr_pool)
return -ENODEV;
+ if ((sg_dma_address(&scat[0]) & ~dev->fmr_page_mask) &&
+ mellanox_workarounds && !memcmp(&target->ioc_guid, mellanox_oui, 3))
+ return -EINVAL;
+
len = page_cnt = 0;
for (i = 0; i < sg_cnt; ++i) {
if (sg_dma_address(&scat[i]) & ~dev->fmr_page_mask) {
@@ -615,9 +633,10 @@ static int srp_map_fmr(struct srp_device *dev, struct scatterlist *scat,
(sg_dma_address(&scat[i]) & dev->fmr_page_mask) + j;
req->fmr = ib_fmr_pool_map_phys(dev->fmr_pool,
- dma_pages, page_cnt, &io_addr);
+ dma_pages, page_cnt, io_addr);
if (IS_ERR(req->fmr)) {
ret = PTR_ERR(req->fmr);
+ req->fmr = NULL;
goto out;
}
@@ -682,7 +701,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
buf->va = cpu_to_be64(sg_dma_address(scat));
buf->key = cpu_to_be32(target->srp_host->dev->mr->rkey);
buf->len = cpu_to_be32(sg_dma_len(scat));
- } else if (srp_map_fmr(target->srp_host->dev, scat, count, req,
+ } else if (srp_map_fmr(target, scat, count, req,
(void *) cmd->add_data)) {
/*
* FMR mapping failed, and the scatterlist has more
@@ -783,13 +802,6 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
}
-static void srp_reconnect_work(void *target_ptr)
-{
- struct srp_target_port *target = target_ptr;
-
- srp_reconnect_target(target);
-}
-
static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
{
struct srp_iu *iu;
@@ -842,7 +854,6 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
{
struct srp_target_port *target = target_ptr;
struct ib_wc wc;
- unsigned long flags;
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
while (ib_poll_cq(cq, 1, &wc) > 0) {
@@ -850,10 +861,6 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
printk(KERN_ERR PFX "failed %s status %d\n",
wc.wr_id & SRP_OP_RECV ? "receive" : "send",
wc.status);
- spin_lock_irqsave(target->scsi_host->host_lock, flags);
- if (target->state == SRP_TARGET_LIVE)
- schedule_work(&target->work);
- spin_unlock_irqrestore(target->scsi_host->host_lock, flags);
break;
}
@@ -1445,12 +1452,28 @@ static ssize_t show_zero_req_lim(struct class_device *cdev, char *buf)
return sprintf(buf, "%d\n", target->zero_req_lim);
}
-static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
-static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
-static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
-static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
-static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
+static ssize_t show_local_ib_port(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ return sprintf(buf, "%d\n", target->srp_host->port);
+}
+
+static ssize_t show_local_ib_device(struct class_device *cdev, char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(cdev));
+
+ return sprintf(buf, "%s\n", target->srp_host->dev->dev->name);
+}
+
+static CLASS_DEVICE_ATTR(id_ext, S_IRUGO, show_id_ext, NULL);
+static CLASS_DEVICE_ATTR(ioc_guid, S_IRUGO, show_ioc_guid, NULL);
+static CLASS_DEVICE_ATTR(service_id, S_IRUGO, show_service_id, NULL);
+static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static CLASS_DEVICE_ATTR(dgid, S_IRUGO, show_dgid, NULL);
+static CLASS_DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
+static CLASS_DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
+static CLASS_DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
static struct class_device_attribute *srp_host_attrs[] = {
&class_device_attr_id_ext,
@@ -1459,6 +1482,8 @@ static struct class_device_attribute *srp_host_attrs[] = {
&class_device_attr_pkey,
&class_device_attr_dgid,
&class_device_attr_zero_req_lim,
+ &class_device_attr_local_ib_port,
+ &class_device_attr_local_ib_device,
NULL
};
@@ -1689,8 +1714,6 @@ static ssize_t srp_create_target(struct class_device *class_dev,
target->scsi_host = target_host;
target->srp_host = host;
- INIT_WORK(&target->work, srp_reconnect_work, target);
-
INIT_LIST_HEAD(&target->free_reqs);
INIT_LIST_HEAD(&target->req_queue);
for (i = 0; i < SRP_SQ_SIZE; ++i) {
@@ -1879,7 +1902,7 @@ static void srp_add_one(struct ib_device *device)
if (IS_ERR(srp_dev->fmr_pool))
srp_dev->fmr_pool = NULL;
- if (device->node_type == IB_NODE_SWITCH) {
+ if (device->node_type == RDMA_NODE_IB_SWITCH) {
s = 0;
e = 0;
} else {
@@ -1978,9 +2001,12 @@ static int __init srp_init_module(void)
return ret;
}
+ ib_sa_register_client(&srp_sa_client);
+
ret = ib_register_client(&srp_client);
if (ret) {
printk(KERN_ERR PFX "couldn't register IB client\n");
+ ib_sa_unregister_client(&srp_sa_client);
class_unregister(&srp_class);
return ret;
}
@@ -1991,6 +2017,7 @@ static int __init srp_init_module(void)
static void __exit srp_cleanup_module(void)
{
ib_unregister_client(&srp_client);
+ ib_sa_unregister_client(&srp_sa_client);
class_unregister(&srp_class);
}
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 5f561fce32d..4bf48188cc9 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -78,14 +78,19 @@ static int evdev_fasync(int fd, struct file *file, int on)
{
int retval;
struct evdev_list *list = file->private_data;
+
retval = fasync_helper(fd, file, on, &list->fasync);
+
return retval < 0 ? retval : 0;
}
-static int evdev_flush(struct file * file, fl_owner_t id)
+static int evdev_flush(struct file *file, fl_owner_t id)
{
struct evdev_list *list = file->private_data;
- if (!list->evdev->exist) return -ENODEV;
+
+ if (!list->evdev->exist)
+ return -ENODEV;
+
return input_flush_device(&list->evdev->handle, file);
}
@@ -122,14 +127,10 @@ static int evdev_open(struct inode * inode, struct file * file)
{
struct evdev_list *list;
int i = iminor(inode) - EVDEV_MINOR_BASE;
- int accept_err;
if (i >= EVDEV_MINORS || !evdev_table[i] || !evdev_table[i]->exist)
return -ENODEV;
- if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file)))
- return accept_err;
-
if (!(list = kzalloc(sizeof(struct evdev_list), GFP_KERNEL)))
return -ENOMEM;
@@ -255,7 +256,7 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
if (evdev_event_from_user(buffer + retval, &event))
return -EFAULT;
- input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+ input_inject_event(&list->evdev->handle, event.type, event.code, event.value);
retval += evdev_event_size();
}
@@ -300,6 +301,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
static unsigned int evdev_poll(struct file *file, poll_table *wait)
{
struct evdev_list *list = file->private_data;
+
poll_wait(file, &list->evdev->wait, wait);
return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
@@ -422,8 +424,8 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
if (get_user(v, ip + 1))
return -EFAULT;
- input_event(dev, EV_REP, REP_DELAY, u);
- input_event(dev, EV_REP, REP_PERIOD, v);
+ input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u);
+ input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v);
return 0;
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index 462f8d300aa..9793ac36d17 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/ioport.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/slab.h>
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 47e93daa0fa..90de5afe03c 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -106,10 +106,10 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
gp->gameport = port;
gp->res_port = request_region(port->io, 0x10, "FM801 GP");
if (!gp->res_port) {
- kfree(gp);
- gameport_free_port(port);
printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
port->io, port->io + 0x0f);
+ gameport_free_port(port);
+ kfree(gp);
return -EBUSY;
}
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 36644bff379..3f47ae55c6f 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -53,6 +53,7 @@ static LIST_HEAD(gameport_list);
static struct bus_type gameport_bus;
+static void gameport_add_driver(struct gameport_driver *drv);
static void gameport_add_port(struct gameport *gameport);
static void gameport_destroy_port(struct gameport *gameport);
static void gameport_reconnect_port(struct gameport *gameport);
@@ -211,8 +212,14 @@ static void gameport_release_driver(struct gameport *gameport)
static void gameport_find_driver(struct gameport *gameport)
{
+ int error;
+
down_write(&gameport_bus.subsys.rwsem);
- device_attach(&gameport->dev);
+ error = device_attach(&gameport->dev);
+ if (error < 0)
+ printk(KERN_WARNING
+ "gameport: device_attach() failed for %s (%s), error: %d\n",
+ gameport->phys, gameport->name, error);
up_write(&gameport_bus.subsys.rwsem);
}
@@ -316,7 +323,6 @@ static void gameport_remove_duplicate_events(struct gameport_event *event)
spin_unlock_irqrestore(&gameport_event_lock, flags);
}
-
static struct gameport_event *gameport_get_event(void)
{
struct gameport_event *event;
@@ -342,7 +348,6 @@ static struct gameport_event *gameport_get_event(void)
static void gameport_handle_event(void)
{
struct gameport_event *event;
- struct gameport_driver *gameport_drv;
mutex_lock(&gameport_mutex);
@@ -369,8 +374,7 @@ static void gameport_handle_event(void)
break;
case GAMEPORT_REGISTER_DRIVER:
- gameport_drv = event->object;
- driver_register(&gameport_drv->driver);
+ gameport_add_driver(event->object);
break;
default:
@@ -532,6 +536,7 @@ static void gameport_init_port(struct gameport *gameport)
if (gameport->parent)
gameport->dev.parent = &gameport->parent->dev;
+ INIT_LIST_HEAD(&gameport->node);
spin_lock_init(&gameport->timer_lock);
init_timer(&gameport->poll_timer);
gameport->poll_timer.function = gameport_run_poll_handler;
@@ -544,6 +549,8 @@ static void gameport_init_port(struct gameport *gameport)
*/
static void gameport_add_port(struct gameport *gameport)
{
+ int error;
+
if (gameport->parent)
gameport->parent->child = gameport;
@@ -558,8 +565,13 @@ static void gameport_add_port(struct gameport *gameport)
printk(KERN_INFO "gameport: %s is %s, speed %dkHz\n",
gameport->name, gameport->phys, gameport->speed);
- device_add(&gameport->dev);
- gameport->registered = 1;
+ error = device_add(&gameport->dev);
+ if (error)
+ printk(KERN_ERR
+ "gameport: device_add() failed for %s (%s), error: %d\n",
+ gameport->phys, gameport->name, error);
+ else
+ gameport->registered = 1;
}
/*
@@ -583,10 +595,11 @@ static void gameport_destroy_port(struct gameport *gameport)
if (gameport->registered) {
device_del(&gameport->dev);
- list_del_init(&gameport->node);
gameport->registered = 0;
}
+ list_del_init(&gameport->node);
+
gameport_remove_pending_events(gameport);
put_device(&gameport->dev);
}
@@ -704,11 +717,22 @@ static int gameport_driver_remove(struct device *dev)
}
static struct bus_type gameport_bus = {
- .name = "gameport",
- .probe = gameport_driver_probe,
- .remove = gameport_driver_remove,
+ .name = "gameport",
+ .probe = gameport_driver_probe,
+ .remove = gameport_driver_remove,
};
+static void gameport_add_driver(struct gameport_driver *drv)
+{
+ int error;
+
+ error = driver_register(&drv->driver);
+ if (error)
+ printk(KERN_ERR
+ "gameport: driver_register() failed for %s, error: %d\n",
+ drv->driver.name, error);
+}
+
void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
{
drv->driver.bus = &gameport_bus;
@@ -778,16 +802,24 @@ void gameport_close(struct gameport *gameport)
static int __init gameport_init(void)
{
- gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
- if (IS_ERR(gameport_task)) {
- printk(KERN_ERR "gameport: Failed to start kgameportd\n");
- return PTR_ERR(gameport_task);
- }
+ int error;
gameport_bus.dev_attrs = gameport_device_attrs;
gameport_bus.drv_attrs = gameport_driver_attrs;
gameport_bus.match = gameport_bus_match;
- bus_register(&gameport_bus);
+ error = bus_register(&gameport_bus);
+ if (error) {
+ printk(KERN_ERR "gameport: failed to register gameport bus, error: %d\n", error);
+ return error;
+ }
+
+ gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+ if (IS_ERR(gameport_task)) {
+ bus_unregister(&gameport_bus);
+ error = PTR_ERR(gameport_task);
+ printk(KERN_ERR "gameport: Failed to start kgameportd, error: %d\n", error);
+ return error;
+ }
return 0;
}
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 3e2d28f263e..f68dbe6f7f0 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/ioport.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/gameport.h>
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 3038c268917..9cb4b9a54f0 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -28,20 +28,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("Input core");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(input_allocate_device);
-EXPORT_SYMBOL(input_register_device);
-EXPORT_SYMBOL(input_unregister_device);
-EXPORT_SYMBOL(input_register_handler);
-EXPORT_SYMBOL(input_unregister_handler);
-EXPORT_SYMBOL(input_grab_device);
-EXPORT_SYMBOL(input_release_device);
-EXPORT_SYMBOL(input_open_device);
-EXPORT_SYMBOL(input_close_device);
-EXPORT_SYMBOL(input_accept_process);
-EXPORT_SYMBOL(input_flush_device);
-EXPORT_SYMBOL(input_event);
-EXPORT_SYMBOL_GPL(input_class);
-
#define INPUT_DEVICES 256
static LIST_HEAD(input_dev_list);
@@ -49,6 +35,16 @@ static LIST_HEAD(input_handler_list);
static struct input_handler *input_table[8];
+/**
+ * input_event() - report new input event
+ * @handle: device that generated the event
+ * @type: type of the event
+ * @code: event code
+ * @value: value of the event
+ *
+ * This function should be used by drivers implementing various input devices
+ * See also input_inject_event()
+ */
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
@@ -63,11 +59,13 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
case EV_SYN:
switch (code) {
case SYN_CONFIG:
- if (dev->event) dev->event(dev, type, code, value);
+ if (dev->event)
+ dev->event(dev, type, code, value);
break;
case SYN_REPORT:
- if (dev->sync) return;
+ if (dev->sync)
+ return;
dev->sync = 1;
break;
}
@@ -136,7 +134,8 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (code > MSC_MAX || !test_bit(code, dev->mscbit))
return;
- if (dev->event) dev->event(dev, type, code, value);
+ if (dev->event)
+ dev->event(dev, type, code, value);
break;
@@ -146,7 +145,9 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
return;
change_bit(code, dev->led);
- if (dev->event) dev->event(dev, type, code, value);
+
+ if (dev->event)
+ dev->event(dev, type, code, value);
break;
@@ -158,21 +159,25 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (!!test_bit(code, dev->snd) != !!value)
change_bit(code, dev->snd);
- if (dev->event) dev->event(dev, type, code, value);
+ if (dev->event)
+ dev->event(dev, type, code, value);
break;
case EV_REP:
- if (code > REP_MAX || value < 0 || dev->rep[code] == value) return;
+ if (code > REP_MAX || value < 0 || dev->rep[code] == value)
+ return;
dev->rep[code] = value;
- if (dev->event) dev->event(dev, type, code, value);
+ if (dev->event)
+ dev->event(dev, type, code, value);
break;
case EV_FF:
- if (dev->event) dev->event(dev, type, code, value);
+ if (dev->event)
+ dev->event(dev, type, code, value);
break;
}
@@ -186,6 +191,24 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
if (handle->open)
handle->handler->event(handle, type, code, value);
}
+EXPORT_SYMBOL(input_event);
+
+/**
+ * input_inject_event() - send input event from input handler
+ * @handle: input handle to send event through
+ * @type: type of the event
+ * @code: event code
+ * @value: value of the event
+ *
+ * Similar to input_event() but will ignore event if device is "grabbed" and handle
+ * injecting event is not the one that owns the device.
+ */
+void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
+{
+ if (!handle->dev->grab || handle->dev->grab == handle)
+ input_event(handle->dev, type, code, value);
+}
+EXPORT_SYMBOL(input_inject_event);
static void input_repeat_key(unsigned long data)
{
@@ -201,14 +224,6 @@ static void input_repeat_key(unsigned long data)
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
-int input_accept_process(struct input_handle *handle, struct file *file)
-{
- if (handle->dev->accept)
- return handle->dev->accept(handle->dev, file);
-
- return 0;
-}
-
int input_grab_device(struct input_handle *handle)
{
if (handle->dev->grab)
@@ -217,12 +232,21 @@ int input_grab_device(struct input_handle *handle)
handle->dev->grab = handle;
return 0;
}
+EXPORT_SYMBOL(input_grab_device);
void input_release_device(struct input_handle *handle)
{
- if (handle->dev->grab == handle)
- handle->dev->grab = NULL;
+ struct input_dev *dev = handle->dev;
+
+ if (dev->grab == handle) {
+ dev->grab = NULL;
+
+ list_for_each_entry(handle, &dev->h_list, d_node)
+ if (handle->handler->start)
+ handle->handler->start(handle);
+ }
}
+EXPORT_SYMBOL(input_release_device);
int input_open_device(struct input_handle *handle)
{
@@ -245,6 +269,7 @@ int input_open_device(struct input_handle *handle)
return err;
}
+EXPORT_SYMBOL(input_open_device);
int input_flush_device(struct input_handle* handle, struct file* file)
{
@@ -253,6 +278,7 @@ int input_flush_device(struct input_handle* handle, struct file* file)
return 0;
}
+EXPORT_SYMBOL(input_flush_device);
void input_close_device(struct input_handle *handle)
{
@@ -268,6 +294,7 @@ void input_close_device(struct input_handle *handle)
mutex_unlock(&dev->mutex);
}
+EXPORT_SYMBOL(input_close_device);
static void input_link_handle(struct input_handle *handle)
{
@@ -335,9 +362,11 @@ static inline void input_wakeup_procfs_readers(void)
static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait)
{
int state = input_devices_state;
+
poll_wait(file, &input_devices_poll_wait, wait);
if (state != input_devices_state)
return POLLIN | POLLRDNORM;
+
return 0;
}
@@ -629,7 +658,7 @@ static ssize_t input_dev_show_modalias(struct class_device *dev, char *buf)
len = input_print_modalias(buf, PAGE_SIZE, id, 1);
- return max_t(int, len, PAGE_SIZE);
+ return min_t(int, len, PAGE_SIZE);
}
static CLASS_DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL);
@@ -862,6 +891,7 @@ struct class input_class = {
.release = input_dev_release,
.uevent = input_dev_uevent,
};
+EXPORT_SYMBOL_GPL(input_class);
struct input_dev *input_allocate_device(void)
{
@@ -872,12 +902,27 @@ struct input_dev *input_allocate_device(void)
dev->dynalloc = 1;
dev->cdev.class = &input_class;
class_device_initialize(&dev->cdev);
+ mutex_init(&dev->mutex);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
}
return dev;
}
+EXPORT_SYMBOL(input_allocate_device);
+
+void input_free_device(struct input_dev *dev)
+{
+ if (dev) {
+
+ mutex_lock(&dev->mutex);
+ dev->name = dev->phys = dev->uniq = NULL;
+ mutex_unlock(&dev->mutex);
+
+ input_put_device(dev);
+ }
+}
+EXPORT_SYMBOL(input_free_device);
int input_register_device(struct input_dev *dev)
{
@@ -895,7 +940,6 @@ int input_register_device(struct input_dev *dev)
return -EINVAL;
}
- mutex_init(&dev->mutex);
set_bit(EV_SYN, dev->evbit);
/*
@@ -944,8 +988,11 @@ int input_register_device(struct input_dev *dev)
list_for_each_entry(handler, &input_handler_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
if ((id = input_match_device(handler->id_table, dev)))
- if ((handle = handler->connect(handler, dev, id)))
+ if ((handle = handler->connect(handler, dev, id))) {
input_link_handle(handle);
+ if (handler->start)
+ handler->start(handle);
+ }
input_wakeup_procfs_readers();
@@ -956,12 +1003,14 @@ int input_register_device(struct input_dev *dev)
fail1: class_device_del(&dev->cdev);
return error;
}
+EXPORT_SYMBOL(input_register_device);
void input_unregister_device(struct input_dev *dev)
{
- struct list_head * node, * next;
+ struct list_head *node, *next;
- if (!dev) return;
+ if (!dev)
+ return;
del_timer_sync(&dev->timer);
@@ -977,10 +1026,16 @@ void input_unregister_device(struct input_dev *dev)
sysfs_remove_group(&dev->cdev.kobj, &input_dev_caps_attr_group);
sysfs_remove_group(&dev->cdev.kobj, &input_dev_id_attr_group);
sysfs_remove_group(&dev->cdev.kobj, &input_dev_attr_group);
+
+ mutex_lock(&dev->mutex);
+ dev->name = dev->phys = dev->uniq = NULL;
+ mutex_unlock(&dev->mutex);
+
class_device_unregister(&dev->cdev);
input_wakeup_procfs_readers();
}
+EXPORT_SYMBOL(input_unregister_device);
void input_register_handler(struct input_handler *handler)
{
@@ -988,7 +1043,8 @@ void input_register_handler(struct input_handler *handler)
struct input_handle *handle;
struct input_device_id *id;
- if (!handler) return;
+ if (!handler)
+ return;
INIT_LIST_HEAD(&handler->h_list);
@@ -1000,15 +1056,19 @@ void input_register_handler(struct input_handler *handler)
list_for_each_entry(dev, &input_dev_list, node)
if (!handler->blacklist || !input_match_device(handler->blacklist, dev))
if ((id = input_match_device(handler->id_table, dev)))
- if ((handle = handler->connect(handler, dev, id)))
+ if ((handle = handler->connect(handler, dev, id))) {
input_link_handle(handle);
+ if (handler->start)
+ handler->start(handle);
+ }
input_wakeup_procfs_readers();
}
+EXPORT_SYMBOL(input_register_handler);
void input_unregister_handler(struct input_handler *handler)
{
- struct list_head * node, * next;
+ struct list_head *node, *next;
list_for_each_safe(node, next, &handler->h_list) {
struct input_handle * handle = to_handle_h(node);
@@ -1024,6 +1084,7 @@ void input_unregister_handler(struct input_handler *handler)
input_wakeup_procfs_readers();
}
+EXPORT_SYMBOL(input_unregister_handler);
static int input_open_file(struct inode *inode, struct file *file)
{
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 949bdcef8c2..d67157513bf 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -81,10 +81,7 @@ static int joydev_correct(int value, struct js_corr *corr)
return 0;
}
- if (value < -32767) return -32767;
- if (value > 32767) return 32767;
-
- return value;
+ return value < -32767 ? -32767 : (value > 32767 ? 32767 : value);
}
static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
@@ -96,7 +93,8 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
switch (type) {
case EV_KEY:
- if (code < BTN_MISC || value == 2) return;
+ if (code < BTN_MISC || value == 2)
+ return;
event.type = JS_EVENT_BUTTON;
event.number = joydev->keymap[code - BTN_MISC];
event.value = value;
@@ -106,7 +104,8 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne
event.type = JS_EVENT_AXIS;
event.number = joydev->absmap[code];
event.value = joydev_correct(value, joydev->corr + event.number);
- if (event.value == joydev->abs[event.number]) return;
+ if (event.value == joydev->abs[event.number])
+ return;
joydev->abs[event.number] = event.value;
break;
@@ -134,7 +133,9 @@ static int joydev_fasync(int fd, struct file *file, int on)
{
int retval;
struct joydev_list *list = file->private_data;
+
retval = fasync_helper(fd, file, on, &list->fasync);
+
return retval < 0 ? retval : 0;
}
@@ -222,12 +223,12 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
return sizeof(struct JS_DATA_TYPE);
}
- if (list->startup == joydev->nabs + joydev->nkey
- && list->head == list->tail && (file->f_flags & O_NONBLOCK))
- return -EAGAIN;
+ if (list->startup == joydev->nabs + joydev->nkey &&
+ list->head == list->tail && (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
retval = wait_event_interruptible(list->joydev->wait,
- !list->joydev->exist ||
+ !list->joydev->exist ||
list->startup < joydev->nabs + joydev->nkey ||
list->head != list->tail);
@@ -276,8 +277,9 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo
static unsigned int joydev_poll(struct file *file, poll_table *wait)
{
struct joydev_list *list = file->private_data;
+
poll_wait(file, &list->joydev->wait, wait);
- return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
+ return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ?
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
}
@@ -291,20 +293,26 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, argp,
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+
case JS_GET_CAL:
return copy_to_user(argp, &joydev->glue.JS_CORR,
sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
+
case JS_SET_TIMEOUT:
return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
+
case JS_GET_TIMEOUT:
return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JSIOCGVERSION:
return put_user(JS_VERSION, (__u32 __user *) argp);
+
case JSIOCGAXES:
return put_user(joydev->nabs, (__u8 __user *) argp);
+
case JSIOCGBUTTONS:
return put_user(joydev->nkey, (__u8 __user *) argp);
+
case JSIOCSCORR:
if (copy_from_user(joydev->corr, argp,
sizeof(joydev->corr[0]) * joydev->nabs))
@@ -314,38 +322,49 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u
joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i);
}
return 0;
+
case JSIOCGCORR:
return copy_to_user(argp, joydev->corr,
sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
+
case JSIOCSAXMAP:
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
- if (joydev->abspam[i] > ABS_MAX) return -EINVAL;
+ if (joydev->abspam[i] > ABS_MAX)
+ return -EINVAL;
joydev->absmap[joydev->abspam[i]] = i;
}
return 0;
+
case JSIOCGAXMAP:
return copy_to_user(argp, joydev->abspam,
sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0;
+
case JSIOCSBTNMAP:
if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)))
return -EFAULT;
for (i = 0; i < joydev->nkey; i++) {
- if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) return -EINVAL;
+ if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC)
+ return -EINVAL;
joydev->keymap[joydev->keypam[i] - BTN_MISC] = i;
}
return 0;
+
case JSIOCGBTNMAP:
return copy_to_user(argp, joydev->keypam,
sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0;
+
default:
if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
int len;
- if (!dev->name) return 0;
+ if (!dev->name)
+ return 0;
len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- if (copy_to_user(argp, dev->name, len)) return -EFAULT;
+ if (len > _IOC_SIZE(cmd))
+ len = _IOC_SIZE(cmd);
+ if (copy_to_user(argp, dev->name, len))
+ return -EFAULT;
return len;
}
}
@@ -362,7 +381,9 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
struct JS_DATA_SAVE_TYPE_32 ds32;
int err;
- if (!joydev->exist) return -ENODEV;
+ if (!joydev->exist)
+ return -ENODEV;
+
switch(cmd) {
case JS_SET_TIMELIMIT:
err = get_user(tmp32, (s32 __user *) arg);
@@ -395,8 +416,7 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo
ds32.JS_SAVE = joydev->glue.JS_SAVE;
ds32.JS_CORR = joydev->glue.JS_CORR;
- err = copy_to_user(argp, &ds32,
- sizeof(ds32)) ? -EFAULT : 0;
+ err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0;
break;
default:
@@ -412,7 +432,8 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct joydev *joydev = list->joydev;
void __user *argp = (void __user *)arg;
- if (!joydev->exist) return -ENODEV;
+ if (!joydev->exist)
+ return -ENODEV;
switch(cmd) {
case JS_SET_TIMELIMIT:
@@ -546,8 +567,8 @@ static struct input_device_id joydev_blacklist[] = {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
- }, /* Avoid itouchpads, touchscreens and tablets */
- { }, /* Terminating entry */
+ }, /* Avoid itouchpads, touchscreens and tablets */
+ { } /* Terminating entry */
};
static struct input_device_id joydev_ids[] = {
@@ -566,7 +587,7 @@ static struct input_device_id joydev_ids[] = {
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_THROTTLE) },
},
- { }, /* Terminating entry */
+ { } /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, joydev_ids);
@@ -579,7 +600,7 @@ static struct input_handler joydev_handler = {
.minor = JOYDEV_MINOR_BASE,
.name = "joydev",
.id_table = joydev_ids,
- .blacklist = joydev_blacklist,
+ .blacklist = joydev_blacklist,
};
static int __init joydev_init(void)
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index 4612d13ea75..b11a4bbc84c 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -306,7 +306,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
gameport_set_poll_handler(gameport, a3d_poll);
gameport_set_poll_interval(gameport, 20);
- sprintf(a3d->phys, "%s/input0", gameport->phys);
+ snprintf(a3d->phys, sizeof(a3d->phys), "%s/input0", gameport->phys);
input_dev->name = a3d_names[a3d->mode];
input_dev->phys = a3d->phys;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 3121961e3e7..e9a02db36ec 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -28,7 +28,6 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -408,21 +407,23 @@ static void analog_calibrate_timer(struct analog_port *port)
static void analog_name(struct analog *analog)
{
- sprintf(analog->name, "Analog %d-axis %d-button",
- hweight8(analog->mask & ANALOG_AXES_STD),
- hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
- hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
+ snprintf(analog->name, sizeof(analog->name), "Analog %d-axis %d-button",
+ hweight8(analog->mask & ANALOG_AXES_STD),
+ hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
+ hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
if (analog->mask & ANALOG_HATS_ALL)
- sprintf(analog->name, "%s %d-hat",
- analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
+ snprintf(analog->name, sizeof(analog->name), "%s %d-hat",
+ analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
if (analog->mask & ANALOG_HAT_FCS)
- strcat(analog->name, " FCS");
+ strlcat(analog->name, " FCS", sizeof(analog->name));
if (analog->mask & ANALOG_ANY_CHF)
- strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
+ strlcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF",
+ sizeof(analog->name));
- strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
+ strlcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick",
+ sizeof(analog->name));
}
/*
@@ -435,7 +436,8 @@ static int analog_init_device(struct analog_port *port, struct analog *analog, i
int i, j, t, v, w, x, y, z;
analog_name(analog);
- sprintf(analog->phys, "%s/input%d", port->gameport->phys, index);
+ snprintf(analog->phys, sizeof(analog->phys),
+ "%s/input%d", port->gameport->phys, index);
analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
analog->dev = input_dev = input_allocate_device();
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 1909f7ef340..d5e42eb88a2 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -202,7 +202,8 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail3;
}
- sprintf(cobra->phys[i], "%s/input%d", gameport->phys, i);
+ snprintf(cobra->phys[i], sizeof(cobra->phys[i]),
+ "%s/input%d", gameport->phys, i);
input_dev->name = "Creative Labs Blaster GamePad Cobra";
input_dev->phys = cobra->phys[i];
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index e61894685cb..5080e15c6d3 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -584,7 +584,7 @@ static struct db9 __init *db9_probe(int parport, int mode)
goto err_out;
}
- if (db9_mode[mode].bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
+ if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
err = -EINVAL;
goto err_put_pp;
@@ -620,7 +620,8 @@ static struct db9 __init *db9_probe(int parport, int mode)
goto err_unreg_devs;
}
- sprintf(db9->phys[i], "%s/input%d", db9->pd->port->name, i);
+ snprintf(db9->phys[i], sizeof(db9->phys[i]),
+ "%s/input%d", db9->pd->port->name, i);
input_dev->name = db9_mode->name;
input_dev->phys = db9->phys[i];
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index ecbdb6b9bbd..fe12aa37393 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -761,7 +761,8 @@ static struct gc __init *gc_probe(int parport, int *pads, int n_pads)
if (!pads[i])
continue;
- sprintf(gc->phys[i], "%s/input%d", gc->pd->port->name, i);
+ snprintf(gc->phys[i], sizeof(gc->phys[i]),
+ "%s/input%d", gc->pd->port->name, i);
err = gc_setup_pad(gc, i, pads[i]);
if (err)
goto err_unreg_devs;
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index 8a3ad455eb3..e4a699f6ec8 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -298,7 +298,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
gameport_set_poll_handler(gameport, gf2k_poll);
gameport_set_poll_interval(gameport, 20);
- sprintf(gf2k->phys, "%s/input0", gameport->phys);
+ snprintf(gf2k->phys, sizeof(gf2k->phys), "%s/input0", gameport->phys);
gf2k->length = gf2k_lens[gf2k->id];
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 20cb98ac2d7..17a90c436de 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -354,7 +354,8 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
goto fail3;
}
- sprintf(grip->phys[i], "%s/input%d", gameport->phys, i);
+ snprintf(grip->phys[i], sizeof(grip->phys[i]),
+ "%s/input%d", gameport->phys, i);
input_dev->name = grip_name[grip->mode[i]];
input_dev->phys = grip->phys[i];
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 6e2c721c26b..840ed9b512b 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -222,7 +222,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
gameport_set_poll_handler(gameport, guillemot_poll);
gameport_set_poll_interval(gameport, 20);
- sprintf(guillemot->phys, "%s/input0", gameport->phys);
+ snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys);
guillemot->type = guillemot_type + i;
input_dev->name = guillemot_type[i].name;
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 2b8e8456c9f..50c90765aee 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -47,7 +47,7 @@ static int make_magnitude_modifier(struct iforce* iforce,
iforce->device_memory.start, iforce->device_memory.end, 2L,
NULL, NULL)) {
mutex_unlock(&iforce->mem_mutex);
- return -ENOMEM;
+ return -ENOSPC;
}
mutex_unlock(&iforce->mem_mutex);
}
@@ -80,7 +80,7 @@ static int make_period_modifier(struct iforce* iforce,
iforce->device_memory.start, iforce->device_memory.end, 2L,
NULL, NULL)) {
mutex_unlock(&iforce->mem_mutex);
- return -ENOMEM;
+ return -ENOSPC;
}
mutex_unlock(&iforce->mem_mutex);
}
@@ -120,7 +120,7 @@ static int make_envelope_modifier(struct iforce* iforce,
iforce->device_memory.start, iforce->device_memory.end, 2L,
NULL, NULL)) {
mutex_unlock(&iforce->mem_mutex);
- return -ENOMEM;
+ return -ENOSPC;
}
mutex_unlock(&iforce->mem_mutex);
}
@@ -157,7 +157,7 @@ static int make_condition_modifier(struct iforce* iforce,
iforce->device_memory.start, iforce->device_memory.end, 2L,
NULL, NULL)) {
mutex_unlock(&iforce->mem_mutex);
- return -ENOMEM;
+ return -ENOSPC;
}
mutex_unlock(&iforce->mem_mutex);
}
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index ab0a26b924c..b4914e7231f 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -79,6 +79,7 @@ static struct iforce_device iforce_device[] = {
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
+ { 0x06d6, 0x29bc, "Trust Force Feedback Race Master", btn_wheel, abs_wheel, ff_iforce },
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
@@ -86,7 +87,7 @@ static struct iforce_device iforce_device[] = {
static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
- struct iforce* iforce = (struct iforce*)(dev->private);
+ struct iforce* iforce = dev->private;
unsigned char data[3];
if (type != EV_FF)
@@ -138,7 +139,7 @@ static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned
*/
static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
{
- struct iforce* iforce = (struct iforce*)(dev->private);
+ struct iforce* iforce = dev->private;
int id;
int ret;
int is_update;
@@ -218,26 +219,26 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
*/
static int iforce_erase_effect(struct input_dev *dev, int effect_id)
{
- struct iforce* iforce = (struct iforce*)(dev->private);
+ struct iforce* iforce = dev->private;
int err = 0;
struct iforce_core_effect* core_effect;
- /* Check who is trying to erase this effect */
- if (iforce->core_effects[effect_id].owner != current->pid) {
- printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner);
- return -EACCES;
- }
-
if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
return -EINVAL;
- core_effect = iforce->core_effects + effect_id;
+ core_effect = &iforce->core_effects[effect_id];
+
+ /* Check who is trying to erase this effect */
+ if (core_effect->owner != current->pid) {
+ printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner);
+ return -EACCES;
+ }
if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
- err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk));
+ err = release_resource(&core_effect->mod1_chunk);
if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
- err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk));
+ err = release_resource(&core_effect->mod2_chunk);
/*TODO: remember to change that if more FF_MOD* bits are added */
core_effect->flags[0] = 0;
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index 668f24535ba..e9924d6f01b 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -35,7 +35,6 @@
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/serio.h>
-#include <linux/config.h>
#include <linux/circ_buf.h>
#include <linux/mutex.h>
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index c4ed0175822..bbfeb9c59b8 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -251,7 +251,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
gameport_set_poll_handler(gameport, interact_poll);
gameport_set_poll_interval(gameport, 20);
- sprintf(interact->phys, "%s/input0", gameport->phys);
+ snprintf(interact->phys, sizeof(interact->phys), "%s/input0", gameport->phys);
interact->type = i;
interact->length = interact_type[i].length;
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index ca3cc2319d6..168b1061a03 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -162,7 +162,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
magellan->dev = input_dev;
- sprintf(magellan->phys, "%s/input0", serio->phys);
+ snprintf(magellan->phys, sizeof(magellan->phys), "%s/input0", serio->phys);
input_dev->name = "LogiCad3D Magellan / SpaceMouse";
input_dev->phys = magellan->phys;
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 95c0de7964a..e58b22c018e 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -541,7 +541,7 @@ static void sw_print_packet(char *name, int length, unsigned char *buf, char bit
* Unfortunately I don't know how to do this for the other SW types.
*/
-static void sw_3dp_id(unsigned char *buf, char *comment)
+static void sw_3dp_id(unsigned char *buf, char *comment, size_t size)
{
int i;
char pnp[8], rev[9];
@@ -554,7 +554,7 @@ static void sw_3dp_id(unsigned char *buf, char *comment)
pnp[7] = rev[8] = 0;
- sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+ snprintf(comment, size, " [PnP %d.%02d id %s rev %s]",
(int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */
sw_get_bits(buf, 16, 6, 1)) / 100,
(int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
@@ -695,7 +695,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
sw->type = SW_ID_FFP;
sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
} else
- sw->type = SW_ID_PP;
+ sw->type = SW_ID_PP;
break;
case 66:
sw->bits = 3;
@@ -703,7 +703,8 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
sw->length = 22;
case 64:
sw->type = SW_ID_3DP;
- if (j == 160) sw_3dp_id(idbuf, comment);
+ if (j == 160)
+ sw_3dp_id(idbuf, comment, sizeof(comment));
break;
}
}
@@ -733,8 +734,10 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
for (i = 0; i < sw->number; i++) {
int bits, code;
- sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
- sprintf(sw->phys[i], "%s/input%d", gameport->phys, i);
+ snprintf(sw->name, sizeof(sw->name),
+ "Microsoft SideWinder %s", sw_name[sw->type]);
+ snprintf(sw->phys[i], sizeof(sw->phys[i]),
+ "%s/input%d", gameport->phys, i);
sw->dev[i] = input_dev = input_allocate_device();
if (!input_dev) {
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index d6f8db8ec3f..7a19ee05297 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -50,7 +50,7 @@ MODULE_LICENSE("GPL");
*/
#define SPACEBALL_MAX_LENGTH 128
-#define SPACEBALL_MAX_ID 8
+#define SPACEBALL_MAX_ID 9
#define SPACEBALL_1003 1
#define SPACEBALL_2003B 3
@@ -220,7 +220,7 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
spaceball->dev = input_dev;
- sprintf(spaceball->phys, "%s/input0", serio->phys);
+ snprintf(spaceball->phys, sizeof(spaceball->phys), "%s/input0", serio->phys);
input_dev->name = spaceball_names[id];
input_dev->phys = spaceball->phys;
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 7c123a01c58..3e2782e7983 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -177,7 +177,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
spaceorb->dev = input_dev;
- sprintf(spaceorb->phys, "%s/input0", serio->phys);
+ snprintf(spaceorb->phys, sizeof(spaceorb->phys), "%s/input0", serio->phys);
input_dev->name = "SpaceTec SpaceOrb 360 / Avenger";
input_dev->phys = spaceorb->phys;
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index 0a9ed1d3063..011ec4858e1 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -148,7 +148,7 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
stinger->dev = input_dev;
- sprintf(stinger->phys, "%s/serio0", serio->phys);
+ snprintf(stinger->phys, sizeof(stinger->phys), "%s/serio0", serio->phys);
input_dev->name = "Gravis Stinger";
input_dev->phys = stinger->phys;
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 7f8b0093c5b..076f237d965 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -199,7 +199,7 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
twidjoy->dev = input_dev;
- sprintf(twidjoy->phys, "%s/input0", serio->phys);
+ snprintf(twidjoy->phys, sizeof(twidjoy->phys), "%s/input0", serio->phys);
input_dev->name = "Handykey Twiddler";
input_dev->phys = twidjoy->phys;
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index 1849b176cf1..f9c1a03214e 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -154,7 +154,7 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
warrior->dev = input_dev;
- sprintf(warrior->phys, "%s/input0", serio->phys);
+ snprintf(warrior->phys, sizeof(warrior->phys), "%s/input0", serio->phys);
input_dev->name = "Logitech WingMan Warrior";
input_dev->phys = warrior->phys;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a9dda56f62c..83eac3a66bc 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -183,4 +183,13 @@ config KEYBOARD_HIL
This driver implements support for HIL-keyboards attached
to your machine, so normally you should say Y here.
+config KEYBOARD_OMAP
+ tristate "TI OMAP keypad support"
+ depends on (ARCH_OMAP1 || ARCH_OMAP2)
+ help
+ Say Y here if you want to use the OMAP keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap-keypad.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 2708167ba17..b265391f1f1 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -15,4 +15,5 @@ obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
+obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index fad04b66d26..a86afd0a5ef 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -55,7 +55,7 @@ static int atkbd_softraw = 1;
module_param_named(softraw, atkbd_softraw, bool, 0);
MODULE_PARM_DESC(softraw, "Use software generated rawmode");
-static int atkbd_scroll = 0;
+static int atkbd_scroll;
module_param_named(scroll, atkbd_scroll, bool, 0);
MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards");
@@ -150,8 +150,8 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_RET_EMUL0 0xe0
#define ATKBD_RET_EMUL1 0xe1
#define ATKBD_RET_RELEASE 0xf0
-#define ATKBD_RET_HANGUEL 0xf1
-#define ATKBD_RET_HANJA 0xf2
+#define ATKBD_RET_HANJA 0xf1
+#define ATKBD_RET_HANGEUL 0xf2
#define ATKBD_RET_ERR 0xff
#define ATKBD_KEY_UNKNOWN 0
@@ -170,6 +170,13 @@ static unsigned char atkbd_unxlate_table[128] = {
#define ATKBD_LED_EVENT_BIT 0
#define ATKBD_REP_EVENT_BIT 1
+#define ATKBD_XL_ERR 0x01
+#define ATKBD_XL_BAT 0x02
+#define ATKBD_XL_ACK 0x04
+#define ATKBD_XL_NAK 0x08
+#define ATKBD_XL_HANGEUL 0x10
+#define ATKBD_XL_HANJA 0x20
+
static struct {
unsigned char keycode;
unsigned char set2;
@@ -211,8 +218,7 @@ struct atkbd {
unsigned char emul;
unsigned char resend;
unsigned char release;
- unsigned char bat_xl;
- unsigned char err_xl;
+ unsigned long xl_bit;
unsigned int last;
unsigned long time;
@@ -245,17 +251,65 @@ ATKBD_DEFINE_ATTR(set);
ATKBD_DEFINE_ATTR(softrepeat);
ATKBD_DEFINE_ATTR(softraw);
+static const unsigned int xl_table[] = {
+ ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
+ ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
+};
-static void atkbd_report_key(struct input_dev *dev, struct pt_regs *regs, int code, int value)
+/*
+ * Checks if we should mangle the scancode to extract 'release' bit
+ * in translated mode.
+ */
+static int atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
{
- input_regs(dev, regs);
- if (value == 3) {
- input_report_key(dev, code, 1);
- input_sync(dev);
- input_report_key(dev, code, 0);
- } else
- input_event(dev, EV_KEY, code, value);
- input_sync(dev);
+ int i;
+
+ if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(xl_table); i++)
+ if (code == xl_table[i])
+ return test_bit(i, &xl_bit);
+
+ return 1;
+}
+
+/*
+ * Calculates new value of xl_bit so the driver can distinguish
+ * between make/break pair of scancodes for select keys and PS/2
+ * protocol responses.
+ */
+static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(xl_table); i++) {
+ if (!((code ^ xl_table[i]) & 0x7f)) {
+ if (code & 0x80)
+ __clear_bit(i, &atkbd->xl_bit);
+ else
+ __set_bit(i, &atkbd->xl_bit);
+ break;
+ }
+ }
+}
+
+/*
+ * Encode the scancode, 0xe0 prefix, and high bit into a single integer,
+ * keeping kernel 2.4 compatibility for set 2
+ */
+static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code)
+{
+ if (atkbd->set == 3) {
+ if (atkbd->emul == 1)
+ code |= 0x100;
+ } else {
+ code = (code & 0x7f) | ((code & 0x80) << 1);
+ if (atkbd->emul == 1)
+ code |= 0x80;
+ }
+
+ return code;
}
/*
@@ -267,9 +321,11 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
+ struct input_dev *dev = atkbd->dev;
unsigned int code = data;
- int scroll = 0, hscroll = 0, click = -1;
+ int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
int value;
+ unsigned char keycode;
#ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Received %02x flags %02x\n", data, flags);
@@ -298,25 +354,17 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
if (!atkbd->enabled)
goto out;
- input_event(atkbd->dev, EV_MSC, MSC_RAW, code);
+ input_event(dev, EV_MSC, MSC_RAW, code);
if (atkbd->translated) {
- if (atkbd->emul ||
- (code != ATKBD_RET_EMUL0 && code != ATKBD_RET_EMUL1 &&
- code != ATKBD_RET_HANGUEL && code != ATKBD_RET_HANJA &&
- (code != ATKBD_RET_ERR || atkbd->err_xl) &&
- (code != ATKBD_RET_BAT || atkbd->bat_xl))) {
+ if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
atkbd->release = code >> 7;
code &= 0x7f;
}
- if (!atkbd->emul) {
- if ((code & 0x7f) == (ATKBD_RET_BAT & 0x7f))
- atkbd->bat_xl = !(data >> 7);
- if ((code & 0x7f) == (ATKBD_RET_ERR & 0x7f))
- atkbd->err_xl = !(data >> 7);
- }
+ if (!atkbd->emul)
+ atkbd_calculate_xl_bit(atkbd, data);
}
switch (code) {
@@ -333,47 +381,48 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
case ATKBD_RET_RELEASE:
atkbd->release = 1;
goto out;
- case ATKBD_RET_HANGUEL:
- atkbd_report_key(atkbd->dev, regs, KEY_HANGUEL, 3);
+ case ATKBD_RET_ACK:
+ case ATKBD_RET_NAK:
+ printk(KERN_WARNING "atkbd.c: Spurious %s on %s. "
+ "Some program might be trying access hardware directly.\n",
+ data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
goto out;
+ case ATKBD_RET_HANGEUL:
case ATKBD_RET_HANJA:
- atkbd_report_key(atkbd->dev, regs, KEY_HANJA, 3);
- goto out;
+ /*
+ * These keys do not report release and thus need to be
+ * flagged properly
+ */
+ add_release_event = 1;
+ break;
case ATKBD_RET_ERR:
printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
goto out;
}
- if (atkbd->set != 3)
- code = (code & 0x7f) | ((code & 0x80) << 1);
- if (atkbd->emul) {
- if (--atkbd->emul)
- goto out;
- code |= (atkbd->set != 3) ? 0x80 : 0x100;
- }
+ code = atkbd_compat_scancode(atkbd, code);
+
+ if (atkbd->emul && --atkbd->emul)
+ goto out;
+
+ keycode = atkbd->keycode[code];
- if (atkbd->keycode[code] != ATKBD_KEY_NULL)
- input_event(atkbd->dev, EV_MSC, MSC_SCAN, code);
+ if (keycode != ATKBD_KEY_NULL)
+ input_event(dev, EV_MSC, MSC_SCAN, code);
- switch (atkbd->keycode[code]) {
+ switch (keycode) {
case ATKBD_KEY_NULL:
break;
case ATKBD_KEY_UNKNOWN:
- if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) {
- printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, "
- "like XFree86, might be trying access hardware directly.\n",
- data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
- } else {
- printk(KERN_WARNING "atkbd.c: Unknown key %s "
- "(%s set %d, code %#x on %s).\n",
- atkbd->release ? "released" : "pressed",
- atkbd->translated ? "translated" : "raw",
- atkbd->set, code, serio->phys);
- printk(KERN_WARNING "atkbd.c: Use 'setkeycodes %s%02x <keycode>' "
- "to make it known.\n",
- code & 0x80 ? "e0" : "", code & 0x7f);
- }
- input_sync(atkbd->dev);
+ printk(KERN_WARNING
+ "atkbd.c: Unknown key %s (%s set %d, code %#x on %s).\n",
+ atkbd->release ? "released" : "pressed",
+ atkbd->translated ? "translated" : "raw",
+ atkbd->set, code, serio->phys);
+ printk(KERN_WARNING
+ "atkbd.c: Use 'setkeycodes %s%02x <keycode>' to make it known.\n",
+ code & 0x80 ? "e0" : "", code & 0x7f);
+ input_sync(dev);
break;
case ATKBD_SCR_1:
scroll = 1 - atkbd->release * 2;
@@ -397,33 +446,35 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
hscroll = 1;
break;
default:
- value = atkbd->release ? 0 :
- (1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev->key)));
-
- switch (value) { /* Workaround Toshiba laptop multiple keypress */
- case 0:
- atkbd->last = 0;
- break;
- case 1:
- atkbd->last = code;
- atkbd->time = jiffies + msecs_to_jiffies(atkbd->dev->rep[REP_DELAY]) / 2;
- break;
- case 2:
- if (!time_after(jiffies, atkbd->time) && atkbd->last == code)
- value = 1;
- break;
+ if (atkbd->release) {
+ value = 0;
+ atkbd->last = 0;
+ } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) {
+ /* Workaround Toshiba laptop multiple keypress */
+ value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2;
+ } else {
+ value = 1;
+ atkbd->last = code;
+ atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
}
- atkbd_report_key(atkbd->dev, regs, atkbd->keycode[code], value);
+ input_regs(dev, regs);
+ input_event(dev, EV_KEY, keycode, value);
+ input_sync(dev);
+
+ if (value && add_release_event) {
+ input_report_key(dev, keycode, 0);
+ input_sync(dev);
+ }
}
if (atkbd->scroll) {
- input_regs(atkbd->dev, regs);
+ input_regs(dev, regs);
if (click != -1)
- input_report_key(atkbd->dev, BTN_MIDDLE, click);
- input_report_rel(atkbd->dev, REL_WHEEL, scroll);
- input_report_rel(atkbd->dev, REL_HWHEEL, hscroll);
- input_sync(atkbd->dev);
+ input_report_key(dev, BTN_MIDDLE, click);
+ input_report_rel(dev, REL_WHEEL, scroll);
+ input_report_rel(dev, REL_HWHEEL, hscroll);
+ input_sync(dev);
}
atkbd->release = 0;
@@ -431,13 +482,7 @@ out:
return IRQ_HANDLED;
}
-/*
- * atkbd_event_work() is used to complete processing of events that
- * can not be processed by input_event() which is often called from
- * interrupt context.
- */
-
-static void atkbd_event_work(void *data)
+static int atkbd_set_repeat_rate(struct atkbd *atkbd)
{
const short period[32] =
{ 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
@@ -445,41 +490,64 @@ static void atkbd_event_work(void *data)
const short delay[4] =
{ 250, 500, 750, 1000 };
- struct atkbd *atkbd = data;
+ struct input_dev *dev = atkbd->dev;
+ unsigned char param;
+ int i = 0, j = 0;
+
+ while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
+ i++;
+ dev->rep[REP_PERIOD] = period[i];
+
+ while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY])
+ j++;
+ dev->rep[REP_DELAY] = delay[j];
+
+ param = i | (j << 5);
+ return ps2_command(&atkbd->ps2dev, &param, ATKBD_CMD_SETREP);
+}
+
+static int atkbd_set_leds(struct atkbd *atkbd)
+{
struct input_dev *dev = atkbd->dev;
unsigned char param[2];
- int i, j;
- mutex_lock(&atkbd->event_mutex);
+ param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
+ | (test_bit(LED_NUML, dev->led) ? 2 : 0)
+ | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
+ if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
+ return -1;
- if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) {
- param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
- | (test_bit(LED_NUML, dev->led) ? 2 : 0)
- | (test_bit(LED_CAPSL, dev->led) ? 4 : 0);
- ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS);
-
- if (atkbd->extra) {
- param[0] = 0;
- param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
- | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
- | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
- | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
- | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
- ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS);
- }
+ if (atkbd->extra) {
+ param[0] = 0;
+ param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0)
+ | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0)
+ | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0)
+ | (test_bit(LED_MISC, dev->led) ? 0x10 : 0)
+ | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0);
+ if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS))
+ return -1;
}
- if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) {
- i = j = 0;
- while (i < 31 && period[i] < dev->rep[REP_PERIOD])
- i++;
- while (j < 3 && delay[j] < dev->rep[REP_DELAY])
- j++;
- dev->rep[REP_PERIOD] = period[i];
- dev->rep[REP_DELAY] = delay[j];
- param[0] = i | (j << 5);
- ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETREP);
- }
+ return 0;
+}
+
+/*
+ * atkbd_event_work() is used to complete processing of events that
+ * can not be processed by input_event() which is often called from
+ * interrupt context.
+ */
+
+static void atkbd_event_work(void *data)
+{
+ struct atkbd *atkbd = data;
+
+ mutex_lock(&atkbd->event_mutex);
+
+ if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
+ atkbd_set_leds(atkbd);
+
+ if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
+ atkbd_set_repeat_rate(atkbd);
mutex_unlock(&atkbd->event_mutex);
}
@@ -764,6 +832,9 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
}
+
+ atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL;
+ atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA;
}
/*
@@ -776,12 +847,15 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
int i;
if (atkbd->extra)
- sprintf(atkbd->name, "AT Set 2 Extra keyboard");
+ snprintf(atkbd->name, sizeof(atkbd->name),
+ "AT Set 2 Extra keyboard");
else
- sprintf(atkbd->name, "AT %s Set %d keyboard",
- atkbd->translated ? "Translated" : "Raw", atkbd->set);
+ snprintf(atkbd->name, sizeof(atkbd->name),
+ "AT %s Set %d keyboard",
+ atkbd->translated ? "Translated" : "Raw", atkbd->set);
- sprintf(atkbd->phys, "%s/input0", atkbd->ps2dev.serio->phys);
+ snprintf(atkbd->phys, sizeof(atkbd->phys),
+ "%s/input0", atkbd->ps2dev.serio->phys);
input_dev->name = atkbd->name;
input_dev->phys = atkbd->phys;
@@ -918,7 +992,6 @@ static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
struct serio_driver *drv = serio->drv;
- unsigned char param[1];
if (!atkbd || !drv) {
printk(KERN_DEBUG "atkbd: reconnect request, but serio is disconnected, ignoring...\n");
@@ -928,10 +1001,6 @@ static int atkbd_reconnect(struct serio *serio)
atkbd_disable(atkbd);
if (atkbd->write) {
- param[0] = (test_bit(LED_SCROLLL, atkbd->dev->led) ? 1 : 0)
- | (test_bit(LED_NUML, atkbd->dev->led) ? 2 : 0)
- | (test_bit(LED_CAPSL, atkbd->dev->led) ? 4 : 0);
-
if (atkbd_probe(atkbd))
return -1;
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
@@ -939,8 +1008,13 @@ static int atkbd_reconnect(struct serio *serio)
atkbd_activate(atkbd);
- if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS))
- return -1;
+/*
+ * Restore repeat rate and LEDs (that were reset by atkbd_activate)
+ * to pre-resume state
+ */
+ if (!atkbd->softrepeat)
+ atkbd_set_repeat_rate(atkbd);
+ atkbd_set_leds(atkbd);
}
atkbd_enable(atkbd);
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 1f0e720267d..1e03153b9bc 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -352,7 +352,7 @@ static int __init corgikbd_probe(struct platform_device *pdev)
for (i = 0; i < CORGI_KEY_SENSE_NUM; i++) {
pxa_gpio_mode(CORGI_GPIO_KEY_SENSE(i) | GPIO_IN);
if (request_irq(CORGI_IRQ_GPIO_KEY_SENSE(i), corgikbd_interrupt,
- SA_INTERRUPT | SA_TRIGGER_RISING,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING,
"corgikbd", corgikbd))
printk(KERN_WARNING "corgikbd: Can't get IRQ: %d!\n", i);
}
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index 33edd030aa7..d22c7c62429 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -18,7 +18,6 @@
#include <linux/pci_ids.h>
#include <linux/ioport.h>
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/init.h>
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 77c4d9669ad..5174224cadb 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -384,18 +384,21 @@ lkkbd_detection_done (struct lkkbd *lk)
*/
switch (lk->id[4]) {
case 1:
- sprintf (lk->name, "DEC LK201 keyboard");
+ strlcpy (lk->name, "DEC LK201 keyboard",
+ sizeof (lk->name));
if (lk201_compose_is_alt)
lk->keycode[0xb1] = KEY_LEFTALT;
break;
case 2:
- sprintf (lk->name, "DEC LK401 keyboard");
+ strlcpy (lk->name, "DEC LK401 keyboard",
+ sizeof (lk->name));
break;
default:
- sprintf (lk->name, "Unknown DEC keyboard");
+ strlcpy (lk->name, "Unknown DEC keyboard",
+ sizeof (lk->name));
printk (KERN_ERR "lkkbd: keyboard on %s is unknown, "
"please report to Jan-Benedict Glaw "
"<jbglaw@lug-owl.de>\n", lk->phys);
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 2c510881874..83906f80ba2 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -25,7 +25,6 @@
*
*/
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index d10983c521e..40a3f551247 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -96,7 +96,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
nkbd->serio = serio;
nkbd->dev = input_dev;
- sprintf(nkbd->phys, "%s/input0", serio->phys);
+ snprintf(nkbd->phys, sizeof(nkbd->phys), "%s/input0", serio->phys);
memcpy(nkbd->keycode, nkbd_keycode, sizeof(nkbd->keycode));
input_dev->name = "Newton Keyboard";
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
new file mode 100644
index 00000000000..d436287d1d2
--- /dev/null
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -0,0 +1,492 @@
+/*
+ * linux/drivers/input/keyboard/omap-keypad.c
+ *
+ * OMAP Keypad Driver
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ * Written by Timo Teräs <ext-timo.teras@nokia.com>
+ *
+ * Added support for H2 & H3 Keypad
+ * Copyright (C) 2004 Texas Instruments
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/menelaus.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+
+#undef NEW_BOARD_LEARNING_MODE
+
+static void omap_kp_tasklet(unsigned long);
+static void omap_kp_timer(unsigned long);
+
+static unsigned char keypad_state[8];
+static DEFINE_MUTEX(kp_enable_mutex);
+static int kp_enable = 1;
+static int kp_cur_group = -1;
+
+struct omap_kp {
+ struct input_dev *input;
+ struct timer_list timer;
+ int irq;
+ unsigned int rows;
+ unsigned int cols;
+ unsigned long delay;
+ unsigned int debounce;
+};
+
+DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
+
+static int *keymap;
+static unsigned int *row_gpios;
+static unsigned int *col_gpios;
+
+#ifdef CONFIG_ARCH_OMAP2
+static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
+{
+ int col;
+ for (col = 0; col < omap_kp->cols; col++) {
+ if (value & (1 << col))
+ omap_set_gpio_dataout(col_gpios[col], 1);
+ else
+ omap_set_gpio_dataout(col_gpios[col], 0);
+ }
+}
+
+static u8 get_row_gpio_val(struct omap_kp *omap_kp)
+{
+ int row;
+ u8 value = 0;
+
+ for (row = 0; row < omap_kp->rows; row++) {
+ if (omap_get_gpio_datain(row_gpios[row]))
+ value |= (1 << row);
+ }
+ return value;
+}
+#else
+#define set_col_gpio_val(x, y) do {} while (0)
+#define get_row_gpio_val(x) 0
+#endif
+
+static irqreturn_t omap_kp_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct omap_kp *omap_kp = dev_id;
+
+ /* disable keyboard interrupt and schedule for handling */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->rows; i++)
+ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ tasklet_schedule(&kp_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+static void omap_kp_timer(unsigned long data)
+{
+ tasklet_schedule(&kp_tasklet);
+}
+
+static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
+{
+ int col = 0;
+
+ /* read the keypad status */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->rows; i++)
+ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+
+ /* read the keypad status */
+ for (col = 0; col < omap_kp->cols; col++) {
+ set_col_gpio_val(omap_kp, ~(1 << col));
+ state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f;
+ }
+ set_col_gpio_val(omap_kp, 0);
+
+ } else {
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ /* read the keypad status */
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+ for (col = 0; col < omap_kp->cols; col++) {
+ omap_writew(~(1 << col) & 0xff,
+ OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+
+ udelay(omap_kp->delay);
+
+ state[col] = ~omap_readw(OMAP_MPUIO_BASE +
+ OMAP_MPUIO_KBR_LATCH) & 0xff;
+ }
+ omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+ udelay(2);
+ }
+}
+
+static inline int omap_kp_find_key(int col, int row)
+{
+ int i, key;
+
+ key = KEY(col, row, 0);
+ for (i = 0; keymap[i] != 0; i++)
+ if ((keymap[i] & 0xff000000) == key)
+ return keymap[i] & 0x00ffffff;
+ return -1;
+}
+
+static void omap_kp_tasklet(unsigned long data)
+{
+ struct omap_kp *omap_kp_data = (struct omap_kp *) data;
+ unsigned char new_state[8], changed, key_down = 0;
+ int col, row;
+ int spurious = 0;
+
+ /* check for any changes */
+ omap_kp_scan_keypad(omap_kp_data, new_state);
+
+ /* check for changes and print those */
+ for (col = 0; col < omap_kp_data->cols; col++) {
+ changed = new_state[col] ^ keypad_state[col];
+ key_down |= new_state[col];
+ if (changed == 0)
+ continue;
+
+ for (row = 0; row < omap_kp_data->rows; row++) {
+ int key;
+ if (!(changed & (1 << row)))
+ continue;
+#ifdef NEW_BOARD_LEARNING_MODE
+ printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
+ row, (new_state[col] & (1 << row)) ?
+ "pressed" : "released");
+#else
+ key = omap_kp_find_key(col, row);
+ if (key < 0) {
+ printk(KERN_WARNING
+ "omap-keypad: Spurious key event %d-%d\n",
+ col, row);
+ /* We scan again after a couple of seconds */
+ spurious = 1;
+ continue;
+ }
+
+ if (!(kp_cur_group == (key & GROUP_MASK) ||
+ kp_cur_group == -1))
+ continue;
+
+ kp_cur_group = key & GROUP_MASK;
+ input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
+ new_state[col] & (1 << row));
+#endif
+ }
+ }
+ memcpy(keypad_state, new_state, sizeof(keypad_state));
+
+ if (key_down) {
+ int delay = HZ / 20;
+ /* some key is pressed - keep irq disabled and use timer
+ * to poll the keypad */
+ if (spurious)
+ delay = 2 * HZ;
+ mod_timer(&omap_kp_data->timer, jiffies + delay);
+ } else {
+ /* enable interrupts */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp_data->rows; i++)
+ enable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else {
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ kp_cur_group = -1;
+ }
+ }
+}
+
+static ssize_t omap_kp_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", kp_enable);
+}
+
+static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int state;
+
+ if (sscanf(buf, "%u", &state) != 1)
+ return -EINVAL;
+
+ if ((state != 1) && (state != 0))
+ return -EINVAL;
+
+ mutex_lock(&kp_enable_mutex);
+ if (state != kp_enable) {
+ if (state)
+ enable_irq(INT_KEYBOARD);
+ else
+ disable_irq(INT_KEYBOARD);
+ kp_enable = state;
+ }
+ mutex_unlock(&kp_enable_mutex);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
+
+#ifdef CONFIG_PM
+static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* Nothing yet */
+
+ return 0;
+}
+
+static int omap_kp_resume(struct platform_device *dev)
+{
+ /* Nothing yet */
+
+ return 0;
+}
+#else
+#define omap_kp_suspend NULL
+#define omap_kp_resume NULL
+#endif
+
+static int __init omap_kp_probe(struct platform_device *pdev)
+{
+ struct omap_kp *omap_kp;
+ struct input_dev *input_dev;
+ struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
+ int i, col_idx, row_idx, irq_idx, ret;
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ printk(KERN_ERR "No rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!omap_kp || !input_dev) {
+ kfree(omap_kp);
+ input_free_device(input_dev);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, omap_kp);
+
+ omap_kp->input = input_dev;
+
+ /* Disable the interrupt for the MPUIO keyboard */
+ if (!cpu_is_omap24xx())
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ keymap = pdata->keymap;
+
+ if (pdata->rep)
+ set_bit(EV_REP, input_dev->evbit);
+
+ if (pdata->delay)
+ omap_kp->delay = pdata->delay;
+
+ if (pdata->row_gpios && pdata->col_gpios) {
+ row_gpios = pdata->row_gpios;
+ col_gpios = pdata->col_gpios;
+ }
+
+ omap_kp->rows = pdata->rows;
+ omap_kp->cols = pdata->cols;
+
+ if (cpu_is_omap24xx()) {
+ /* Cols: outputs */
+ for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
+ if (omap_request_gpio(col_gpios[col_idx]) < 0) {
+ printk(KERN_ERR "Failed to request"
+ "GPIO%d for keypad\n",
+ col_gpios[col_idx]);
+ goto err1;
+ }
+ omap_set_gpio_direction(col_gpios[col_idx], 0);
+ }
+ /* Rows: inputs */
+ for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
+ if (omap_request_gpio(row_gpios[row_idx]) < 0) {
+ printk(KERN_ERR "Failed to request"
+ "GPIO%d for keypad\n",
+ row_gpios[row_idx]);
+ goto err2;
+ }
+ omap_set_gpio_direction(row_gpios[row_idx], 1);
+ }
+ }
+
+ setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
+
+ /* get the irq and init timer*/
+ tasklet_enable(&kp_tasklet);
+ kp_tasklet.data = (unsigned long) omap_kp;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_enable);
+ if (ret < 0)
+ goto err2;
+
+ /* setup input device */
+ set_bit(EV_KEY, input_dev->evbit);
+ for (i = 0; keymap[i] != 0; i++)
+ set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
+ input_dev->name = "omap-keypad";
+ input_dev->phys = "omap-keypad/input0";
+ input_dev->cdev.dev = &pdev->dev;
+ input_dev->private = omap_kp;
+
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+
+ input_dev->keycode = keymap;
+ input_dev->keycodesize = sizeof(unsigned int);
+ input_dev->keycodemax = pdata->keymapsize;
+
+ ret = input_register_device(omap_kp->input);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to register omap-keypad input device\n");
+ goto err3;
+ }
+
+ if (pdata->dbounce)
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
+
+ /* scan current status and enable interrupt */
+ omap_kp_scan_keypad(omap_kp, keypad_state);
+ if (!cpu_is_omap24xx()) {
+ omap_kp->irq = platform_get_irq(pdev, 0);
+ if (omap_kp->irq >= 0) {
+ if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
+ "omap-keypad", omap_kp) < 0)
+ goto err4;
+ }
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ } else {
+ for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
+ if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
+ omap_kp_interrupt,
+ IRQF_TRIGGER_FALLING,
+ "omap-keypad", omap_kp) < 0)
+ goto err5;
+ }
+ }
+ return 0;
+err5:
+ for (i = irq_idx-1; i >=0; i--)
+ free_irq(row_gpios[i], 0);
+err4:
+ input_unregister_device(omap_kp->input);
+ input_dev = NULL;
+err3:
+ device_remove_file(&pdev->dev, &dev_attr_enable);
+err2:
+ for (i = row_idx-1; i >=0; i--)
+ omap_free_gpio(row_gpios[i]);
+err1:
+ for (i = col_idx-1; i >=0; i--)
+ omap_free_gpio(col_gpios[i]);
+
+ kfree(omap_kp);
+ input_free_device(input_dev);
+
+ return -EINVAL;
+}
+
+static int omap_kp_remove(struct platform_device *pdev)
+{
+ struct omap_kp *omap_kp = platform_get_drvdata(pdev);
+
+ /* disable keypad interrupt handling */
+ tasklet_disable(&kp_tasklet);
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->cols; i++)
+ omap_free_gpio(col_gpios[i]);
+ for (i = 0; i < omap_kp->rows; i++) {
+ omap_free_gpio(row_gpios[i]);
+ free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
+ }
+ } else {
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ free_irq(omap_kp->irq, 0);
+ }
+
+ del_timer_sync(&omap_kp->timer);
+ tasklet_kill(&kp_tasklet);
+
+ /* unregister everything */
+ input_unregister_device(omap_kp->input);
+
+ kfree(omap_kp);
+
+ return 0;
+}
+
+static struct platform_driver omap_kp_driver = {
+ .probe = omap_kp_probe,
+ .remove = omap_kp_remove,
+ .suspend = omap_kp_suspend,
+ .resume = omap_kp_resume,
+ .driver = {
+ .name = "omap-keypad",
+ },
+};
+
+static int __devinit omap_kp_init(void)
+{
+ printk(KERN_INFO "OMAP Keypad Driver\n");
+ return platform_driver_register(&omap_kp_driver);
+}
+
+static void __exit omap_kp_exit(void)
+{
+ platform_driver_unregister(&omap_kp_driver);
+}
+
+module_init(omap_kp_init);
+module_exit(omap_kp_exit);
+
+MODULE_AUTHOR("Timo Teräs");
+MODULE_DESCRIPTION("OMAP Keypad Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index c5d03fb77bc..e385710233f 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -410,7 +410,7 @@ static int __init spitzkbd_probe(struct platform_device *dev)
for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) {
pxa_gpio_mode(spitz_senses[i] | GPIO_IN);
if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt,
- SA_INTERRUPT|SA_TRIGGER_RISING,
+ IRQF_DISABLED|IRQF_TRIGGER_RISING,
"Spitzkbd Sense", spitzkbd))
printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i);
}
@@ -425,19 +425,19 @@ static int __init spitzkbd_probe(struct platform_device *dev)
pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN);
request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt,
- SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd Sync", spitzkbd);
request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt,
- SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd PwrOn", spitzkbd);
request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr,
- SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd SWA", spitzkbd);
request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr,
- SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd SWB", spitzkbd);
request_irq(SPITZ_IRQ_GPIO_AK_INT, spitzkbd_hinge_isr,
- SA_INTERRUPT | SA_TRIGGER_RISING | SA_TRIGGER_FALLING,
+ IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"Spitzkbd HP", spitzkbd);
printk(KERN_INFO "input: Spitz Keyboard Registered\n");
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index b15b6d8d4f8..9dbd7b85686 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -263,7 +263,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
}
- sprintf(sunkbd->name, "Sun Type %d keyboard", sunkbd->type);
+ snprintf(sunkbd->name, sizeof(sunkbd->name), "Sun Type %d keyboard", sunkbd->type);
memcpy(sunkbd->keycode, sunkbd_keycode, sizeof(sunkbd->keycode));
input_dev->name = sunkbd->name;
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index 4135e3e16c5..0821d53cf0c 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -100,7 +100,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
xtkbd->serio = serio;
xtkbd->dev = input_dev;
- sprintf(xtkbd->phys, "%s/input0", serio->phys);
+ snprintf(xtkbd->phys, sizeof(xtkbd->phys), "%s/input0", serio->phys);
memcpy(xtkbd->keycode, xtkbd_keycode, sizeof(xtkbd->keycode));
input_dev->name = "XT Keyboard";
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 4bad588d0e5..a6dfc745573 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -26,7 +26,7 @@ config INPUT_PCSPKR
config INPUT_SPARCSPKR
tristate "SPARC Speaker support"
- depends on PCI && SPARC
+ depends on PCI && SPARC64
help
Say Y here if you want the standard Speaker on Sparc PCI systems
to be used for bells and whistles.
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 3a6ae85cd69..805b636e73d 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -113,7 +113,7 @@ static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
input_dev->event = ixp4xx_spkr_event;
err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
- SA_INTERRUPT | SA_TIMER, "ixp4xx-beeper", (void *) dev->id);
+ IRQF_DISABLED | IRQF_TIMER, "ixp4xx-beeper", (void *) dev->id);
if (err)
goto err_free_device;
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index f0fd2c4740f..106c94f33b9 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -2,9 +2,8 @@
* Driver for PC-speaker like devices found on various Sparc systems.
*
* Copyright (c) 2002 Vojtech Pavlik
- * Copyright (c) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (c) 2002, 2006 David S. Miller (davem@davemloft.net)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -13,21 +12,23 @@
#include <asm/io.h>
#include <asm/ebus.h>
-#ifdef CONFIG_SPARC64
#include <asm/isa.h>
-#endif
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
MODULE_DESCRIPTION("Sparc Speaker beeper driver");
MODULE_LICENSE("GPL");
-const char *beep_name;
-static unsigned long beep_iobase;
-static int (*beep_event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
-static DEFINE_SPINLOCK(beep_lock);
+struct sparcspkr_state {
+ const char *name;
+ unsigned long iobase;
+ int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+ spinlock_t lock;
+ struct input_dev *input_dev;
+};
static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
+ struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@@ -43,24 +44,24 @@ static int ebus_spkr_event(struct input_dev *dev, unsigned int type, unsigned in
if (value > 20 && value < 32767)
count = 1193182 / value;
- spin_lock_irqsave(&beep_lock, flags);
+ spin_lock_irqsave(&state->lock, flags);
/* EBUS speaker only has on/off state, the frequency does not
* appear to be programmable.
*/
- if (beep_iobase & 0x2UL)
- outb(!!count, beep_iobase);
+ if (state->iobase & 0x2UL)
+ outb(!!count, state->iobase);
else
- outl(!!count, beep_iobase);
+ outl(!!count, state->iobase);
- spin_unlock_irqrestore(&beep_lock, flags);
+ spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
-#ifdef CONFIG_SPARC64
static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
+ struct sparcspkr_state *state = dev_get_drvdata(dev->cdev.dev);
unsigned int count = 0;
unsigned long flags;
@@ -76,29 +77,29 @@ static int isa_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
if (value > 20 && value < 32767)
count = 1193182 / value;
- spin_lock_irqsave(&beep_lock, flags);
+ spin_lock_irqsave(&state->lock, flags);
if (count) {
/* enable counter 2 */
- outb(inb(beep_iobase + 0x61) | 3, beep_iobase + 0x61);
+ outb(inb(state->iobase + 0x61) | 3, state->iobase + 0x61);
/* set command for counter 2, 2 byte write */
- outb(0xB6, beep_iobase + 0x43);
+ outb(0xB6, state->iobase + 0x43);
/* select desired HZ */
- outb(count & 0xff, beep_iobase + 0x42);
- outb((count >> 8) & 0xff, beep_iobase + 0x42);
+ outb(count & 0xff, state->iobase + 0x42);
+ outb((count >> 8) & 0xff, state->iobase + 0x42);
} else {
/* disable counter 2 */
- outb(inb_p(beep_iobase + 0x61) & 0xFC, beep_iobase + 0x61);
+ outb(inb_p(state->iobase + 0x61) & 0xFC, state->iobase + 0x61);
}
- spin_unlock_irqrestore(&beep_lock, flags);
+ spin_unlock_irqrestore(&state->lock, flags);
return 0;
}
-#endif
-static int __devinit sparcspkr_probe(struct platform_device *dev)
+static int __devinit sparcspkr_probe(struct device *dev)
{
+ struct sparcspkr_state *state = dev_get_drvdata(dev);
struct input_dev *input_dev;
int error;
@@ -106,18 +107,18 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
if (!input_dev)
return -ENOMEM;
- input_dev->name = beep_name;
+ input_dev->name = state->name;
input_dev->phys = "sparc/input0";
input_dev->id.bustype = BUS_ISA;
input_dev->id.vendor = 0x001f;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
- input_dev->cdev.dev = &dev->dev;
+ input_dev->cdev.dev = dev;
input_dev->evbit[0] = BIT(EV_SND);
input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
- input_dev->event = beep_event;
+ input_dev->event = state->event;
error = input_register_device(input_dev);
if (error) {
@@ -125,111 +126,137 @@ static int __devinit sparcspkr_probe(struct platform_device *dev)
return error;
}
- platform_set_drvdata(dev, input_dev);
+ state->input_dev = input_dev;
return 0;
}
-static int __devexit sparcspkr_remove(struct platform_device *dev)
+static int __devexit sparcspkr_remove(struct of_device *dev)
{
- struct input_dev *input_dev = platform_get_drvdata(dev);
+ struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
+ struct input_dev *input_dev = state->input_dev;
- input_unregister_device(input_dev);
- platform_set_drvdata(dev, NULL);
/* turn off the speaker */
- beep_event(NULL, EV_SND, SND_BELL, 0);
+ state->event(input_dev, EV_SND, SND_BELL, 0);
+
+ input_unregister_device(input_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(state);
return 0;
}
-static void sparcspkr_shutdown(struct platform_device *dev)
+static int sparcspkr_shutdown(struct of_device *dev)
{
+ struct sparcspkr_state *state = dev_get_drvdata(&dev->dev);
+ struct input_dev *input_dev = state->input_dev;
+
/* turn off the speaker */
- beep_event(NULL, EV_SND, SND_BELL, 0);
+ state->event(input_dev, EV_SND, SND_BELL, 0);
+
+ return 0;
+}
+
+static int __devinit ebus_beep_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
+ struct sparcspkr_state *state;
+ int err;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ state->name = "Sparc EBUS Speaker";
+ state->iobase = edev->resource[0].start;
+ state->event = ebus_spkr_event;
+ spin_lock_init(&state->lock);
+
+ dev_set_drvdata(&dev->dev, state);
+
+ err = sparcspkr_probe(&dev->dev);
+ if (err) {
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(state);
+ }
+
+ return 0;
}
-static struct platform_driver sparcspkr_platform_driver = {
- .driver = {
- .name = "sparcspkr",
- .owner = THIS_MODULE,
+static struct of_device_id ebus_beep_match[] = {
+ {
+ .name = "beep",
},
- .probe = sparcspkr_probe,
- .remove = __devexit_p(sparcspkr_remove),
- .shutdown = sparcspkr_shutdown,
+ {},
};
-static struct platform_device *sparcspkr_platform_device;
+static struct of_platform_driver ebus_beep_driver = {
+ .name = "beep",
+ .match_table = ebus_beep_match,
+ .probe = ebus_beep_probe,
+ .remove = sparcspkr_remove,
+ .shutdown = sparcspkr_shutdown,
+};
-static int __init sparcspkr_drv_init(void)
+static int __devinit isa_beep_probe(struct of_device *dev, const struct of_device_id *match)
{
- int error;
+ struct sparc_isa_device *idev = to_isa_device(&dev->dev);
+ struct sparcspkr_state *state;
+ int err;
- error = platform_driver_register(&sparcspkr_platform_driver);
- if (error)
- return error;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
- sparcspkr_platform_device = platform_device_alloc("sparcspkr", -1);
- if (!sparcspkr_platform_device) {
- error = -ENOMEM;
- goto err_unregister_driver;
- }
+ state->name = "Sparc ISA Speaker";
+ state->iobase = idev->resource.start;
+ state->event = isa_spkr_event;
+ spin_lock_init(&state->lock);
+
+ dev_set_drvdata(&dev->dev, state);
- error = platform_device_add(sparcspkr_platform_device);
- if (error)
- goto err_free_device;
+ err = sparcspkr_probe(&dev->dev);
+ if (err) {
+ dev_set_drvdata(&dev->dev, NULL);
+ kfree(state);
+ }
return 0;
+}
- err_free_device:
- platform_device_put(sparcspkr_platform_device);
- err_unregister_driver:
- platform_driver_unregister(&sparcspkr_platform_driver);
+static struct of_device_id isa_beep_match[] = {
+ {
+ .name = "dma",
+ },
+ {},
+};
- return error;
-}
+static struct of_platform_driver isa_beep_driver = {
+ .name = "beep",
+ .match_table = isa_beep_match,
+ .probe = isa_beep_probe,
+ .remove = sparcspkr_remove,
+ .shutdown = sparcspkr_shutdown,
+};
static int __init sparcspkr_init(void)
{
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
-#ifdef CONFIG_SPARC64
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-#endif
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "beep")) {
- beep_name = "Sparc EBUS Speaker";
- beep_event = ebus_spkr_event;
- beep_iobase = edev->resource[0].start;
- return sparcspkr_drv_init();
- }
- }
- }
-#ifdef CONFIG_SPARC64
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- /* A hack, the beep device's base lives in
- * the DMA isa node.
- */
- if (!strcmp(isa_dev->prom_name, "dma")) {
- beep_name = "Sparc ISA Speaker";
- beep_event = isa_spkr_event,
- beep_iobase = isa_dev->resource.start;
- return sparcspkr_drv_init();
- }
- }
+ int err = of_register_driver(&ebus_beep_driver, &ebus_bus_type);
+
+ if (!err) {
+ err = of_register_driver(&isa_beep_driver, &isa_bus_type);
+ if (err)
+ of_unregister_driver(&ebus_beep_driver);
}
-#endif
- return -ENODEV;
+ return err;
}
static void __exit sparcspkr_exit(void)
{
- platform_device_unregister(sparcspkr_platform_device);
- platform_driver_unregister(&sparcspkr_platform_driver);
+ of_unregister_driver(&ebus_beep_driver);
+ of_unregister_driver(&isa_beep_driver);
}
module_init(sparcspkr_init);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index e4e5be111c9..de0f46dd969 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -94,7 +94,7 @@ static void call_bios(struct regs *regs)
static ssize_t __init locate_wistron_bios(void __iomem *base)
{
- static const unsigned char __initdata signature[] =
+ static unsigned char __initdata signature[] =
{ 0x42, 0x21, 0x55, 0x30 };
ssize_t offset;
@@ -285,6 +285,15 @@ static struct key_entry keymap_fujitsu_n3510[] = {
{ KE_END, 0 }
};
+static struct key_entry keymap_wistron_ms2111[] = {
+ { KE_KEY, 0x11, KEY_PROG1 },
+ { KE_KEY, 0x12, KEY_PROG2 },
+ { KE_KEY, 0x13, KEY_PROG3 },
+ { KE_KEY, 0x31, KEY_MAIL },
+ { KE_KEY, 0x36, KEY_WWW },
+ { KE_END, 0 }
+};
+
static struct key_entry keymap_wistron_ms2141[] = {
{ KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 },
@@ -326,6 +335,7 @@ static struct key_entry keymap_aopen_1559as[] = {
{ KE_WIFI, 0x30, 0 },
{ KE_KEY, 0x31, KEY_MAIL },
{ KE_KEY, 0x36, KEY_WWW },
+ { KE_END, 0 },
};
/*
@@ -333,7 +343,7 @@ static struct key_entry keymap_aopen_1559as[] = {
* a list of buttons and their key codes (reported when loading this module
* with force=1) and the output of dmidecode to $MODULE_AUTHOR.
*/
-static struct dmi_system_id dmi_ids[] = {
+static struct dmi_system_id dmi_ids[] __initdata = {
{
.callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo Pro V2000",
@@ -388,6 +398,15 @@ static struct dmi_system_id dmi_ids[] = {
},
.driver_data = keymap_aopen_1559as
},
+ {
+ .callback = dmi_matched,
+ .ident = "Medion MD 9783",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MEDIONNB"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MD 9783"),
+ },
+ .driver_data = keymap_wistron_ms2111
+ },
{ NULL, }
};
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index a0e2e797c6d..070d75330af 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -470,7 +470,7 @@ int alps_init(struct psmouse *psmouse)
dev1->keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
}
- sprintf(priv->phys, "%s/input1", psmouse->ps2dev.serio->phys);
+ snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
dev2->name = (priv->i->flags & ALPS_DUALPOINT) ? "DualPoint Stick" : "PS/2 Mouse";
dev2->id.bustype = BUS_I8042;
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index afc66f56df4..50f1fed10be 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -36,7 +36,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 2f0d2884081..54b696cfe1e 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -238,8 +238,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 100, PS2PP_KIND_MX, /* MX510 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
- { 111, PS2PP_KIND_MX, /* MX300 */
- PS2PP_WHEEL | PS2PP_EXTRA_BTN | PS2PP_TASK_BTN },
+ { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */
{ 112, PS2PP_KIND_MX, /* MX500 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 136321a2cfd..343afa38f4c 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -150,9 +150,20 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_reg
*/
if (psmouse->type == PSMOUSE_IMEX) {
- input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
- input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
- input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+ switch (packet[3] & 0xC0) {
+ case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */
+ input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+ break;
+ case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */
+ input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31));
+ break;
+ case 0x00:
+ case 0xC0:
+ input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7));
+ input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1);
+ input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1);
+ break;
+ }
}
/*
@@ -466,9 +477,18 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties)
if (param[0] != 4)
return -1;
+/* Magic to enable horizontal scrolling on IntelliMouse 4.0 */
+ param[0] = 200;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ param[0] = 80;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ param[0] = 40;
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+
if (set_properties) {
set_bit(BTN_MIDDLE, psmouse->dev->keybit);
set_bit(REL_WHEEL, psmouse->dev->relbit);
+ set_bit(REL_HWHEEL, psmouse->dev->relbit);
set_bit(BTN_SIDE, psmouse->dev->keybit);
set_bit(BTN_EXTRA, psmouse->dev->keybit);
@@ -1057,8 +1077,8 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_proto
if (psmouse->resync_time && psmouse->poll(psmouse))
psmouse->resync_time = 0;
- sprintf(psmouse->devname, "%s %s %s",
- psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+ snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s",
+ psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
input_dev->name = psmouse->devname;
input_dev->phys = psmouse->phys;
@@ -1099,7 +1119,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
ps2_init(&psmouse->ps2dev, serio);
INIT_WORK(&psmouse->resync_work, psmouse_resync, psmouse);
psmouse->dev = input_dev;
- sprintf(psmouse->phys, "%s/input0", serio->phys);
+ snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 09b6ffdb758..872b30bf7aa 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -85,7 +85,7 @@ static int __init rpcmouse_init(void)
rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
- if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", rpcmouse_dev)) {
+ if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, IRQF_SHARED, "rpcmouse", rpcmouse_dev)) {
printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
input_free_device(rpcmouse_dev);
return -EBUSY;
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 2f9a04ae725..0023501a5b6 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -33,7 +33,6 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
-#include <linux/config.h>
#include <linux/serio.h>
#include <linux/init.h>
@@ -254,7 +253,7 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
goto fail;
sermouse->dev = input_dev;
- sprintf(sermouse->phys, "%s/input0", serio->phys);
+ snprintf(sermouse->phys, sizeof(sermouse->phys), "%s/input0", serio->phys);
sermouse->type = serio->id.proto;
input_dev->name = sermouse_protocols[sermouse->type];
diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c
index 6d9ec9ab1b9..ae5871a0e06 100644
--- a/drivers/input/mouse/trackpoint.c
+++ b/drivers/input/mouse/trackpoint.c
@@ -183,21 +183,26 @@ static struct attribute_group trackpoint_attr_group = {
.attrs = trackpoint_attrs,
};
-static void trackpoint_disconnect(struct psmouse *psmouse)
+static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id)
{
- sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);
+ unsigned char param[2] = { 0 };
- kfree(psmouse->private);
- psmouse->private = NULL;
+ if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
+ return -1;
+
+ if (param[0] != TP_MAGIC_IDENT)
+ return -1;
+
+ if (firmware_id)
+ *firmware_id = param[1];
+
+ return 0;
}
static int trackpoint_sync(struct psmouse *psmouse)
{
- unsigned char toggle;
struct trackpoint_data *tp = psmouse->private;
-
- if (!tp)
- return -1;
+ unsigned char toggle;
/* Disable features that may make device unusable with this driver */
trackpoint_read(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, &toggle);
@@ -263,27 +268,38 @@ static void trackpoint_defaults(struct trackpoint_data *tp)
tp->ext_dev = TP_DEF_EXT_DEV;
}
+static void trackpoint_disconnect(struct psmouse *psmouse)
+{
+ sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group);
+
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int trackpoint_reconnect(struct psmouse *psmouse)
+{
+ if (trackpoint_start_protocol(psmouse, NULL))
+ return -1;
+
+ if (trackpoint_sync(psmouse))
+ return -1;
+
+ return 0;
+}
+
int trackpoint_detect(struct psmouse *psmouse, int set_properties)
{
struct trackpoint_data *priv;
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char firmware_id;
unsigned char button_info;
- unsigned char param[2];
-
- param[0] = param[1] = 0;
- if (ps2_command(ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
- return -1;
-
- if (param[0] != TP_MAGIC_IDENT)
+ if (trackpoint_start_protocol(psmouse, &firmware_id))
return -1;
if (!set_properties)
return 0;
- firmware_id = param[1];
-
if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) {
printk(KERN_WARNING "trackpoint.c: failed to get extended button data\n");
button_info = 0;
@@ -296,7 +312,7 @@ int trackpoint_detect(struct psmouse *psmouse, int set_properties)
psmouse->vendor = "IBM";
psmouse->name = "TrackPoint";
- psmouse->reconnect = trackpoint_sync;
+ psmouse->reconnect = trackpoint_reconnect;
psmouse->disconnect = trackpoint_disconnect;
trackpoint_defaults(priv);
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index 36e9442a16b..47edcfd022b 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -81,7 +81,6 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
-#include <linux/config.h>
#include <linux/serio.h>
#include <linux/init.h>
@@ -153,22 +152,25 @@ vsxxxaa_detection_done (struct vsxxxaa *mouse)
{
switch (mouse->type) {
case 0x02:
- sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse");
+ strlcpy (mouse->name, "DEC VSXXX-AA/-GA mouse",
+ sizeof (mouse->name));
break;
case 0x04:
- sprintf (mouse->name, "DEC VSXXX-AB digitizer");
+ strlcpy (mouse->name, "DEC VSXXX-AB digitizer",
+ sizeof (mouse->name));
break;
default:
- sprintf (mouse->name, "unknown DEC pointer device "
- "(type = 0x%02x)", mouse->type);
+ snprintf (mouse->name, sizeof (mouse->name),
+ "unknown DEC pointer device (type = 0x%02x)",
+ mouse->type);
break;
}
- printk (KERN_INFO "Found %s version 0x%02x from country 0x%02x "
- "on port %s\n", mouse->name, mouse->version,
- mouse->country, mouse->phys);
+ printk (KERN_INFO
+ "Found %s version 0x%02x from country 0x%02x on port %s\n",
+ mouse->name, mouse->version, mouse->country, mouse->phys);
}
/*
@@ -503,8 +505,9 @@ vsxxxaa_connect (struct serio *serio, struct serio_driver *drv)
mouse->dev = input_dev;
mouse->serio = serio;
- sprintf (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer");
- sprintf (mouse->phys, "%s/input0", serio->phys);
+ strlcat (mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
+ sizeof (mouse->name));
+ snprintf (mouse->phys, sizeof (mouse->phys), "%s/input0", serio->phys);
input_dev->name = mouse->name;
input_dev->phys = mouse->phys;
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index b685a507955..1f851acab30 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -19,7 +19,6 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/input.h>
-#include <linux/config.h>
#include <linux/smp_lock.h>
#include <linux/random.h>
#include <linux/major.h>
@@ -123,7 +122,9 @@ static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mous
if (mousedev->touch) {
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0) size = 256 * 2;
+ if (size == 0)
+ size = 256 * 2;
+
switch (code) {
case ABS_X:
fx(0) = value;
@@ -155,18 +156,24 @@ static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev,
switch (code) {
case ABS_X:
size = dev->absmax[ABS_X] - dev->absmin[ABS_X];
- if (size == 0) size = xres ? : 1;
- if (value > dev->absmax[ABS_X]) value = dev->absmax[ABS_X];
- if (value < dev->absmin[ABS_X]) value = dev->absmin[ABS_X];
+ if (size == 0)
+ size = xres ? : 1;
+ if (value > dev->absmax[ABS_X])
+ value = dev->absmax[ABS_X];
+ if (value < dev->absmin[ABS_X])
+ value = dev->absmin[ABS_X];
mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size;
mousedev->packet.abs_event = 1;
break;
case ABS_Y:
size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y];
- if (size == 0) size = yres ? : 1;
- if (value > dev->absmax[ABS_Y]) value = dev->absmax[ABS_Y];
- if (value < dev->absmin[ABS_Y]) value = dev->absmin[ABS_Y];
+ if (size == 0)
+ size = yres ? : 1;
+ if (value > dev->absmax[ABS_Y])
+ value = dev->absmax[ABS_Y];
+ if (value < dev->absmin[ABS_Y])
+ value = dev->absmin[ABS_Y];
mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size;
mousedev->packet.abs_event = 1;
break;
@@ -202,7 +209,7 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int
case BTN_SIDE: index = 3; break;
case BTN_4:
case BTN_EXTRA: index = 4; break;
- default: return;
+ default: return;
}
if (value) {
@@ -285,10 +292,9 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
mousedev->touch = mousedev->pkt_count = 0;
mousedev->frac_dx = 0;
mousedev->frac_dy = 0;
- }
- else
- if (!mousedev->touch)
- mousedev->touch = jiffies;
+
+ } else if (!mousedev->touch)
+ mousedev->touch = jiffies;
}
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
@@ -327,7 +333,7 @@ static void mousedev_event(struct input_handle *handle, unsigned int type, unsig
mousedev->pkt_count++;
/* Input system eats duplicate events, but we need all of them
* to do correct averaging so apply present one forward
- */
+ */
fx(0) = fx(1);
fy(0) = fy(1);
}
@@ -346,7 +352,9 @@ static int mousedev_fasync(int fd, struct file *file, int on)
{
int retval;
struct mousedev_list *list = file->private_data;
+
retval = fasync_helper(fd, file, on, &list->fasync);
+
return retval < 0 ? retval : 0;
}
@@ -507,14 +515,16 @@ static ssize_t mousedev_write(struct file * file, const char __user * buffer, si
list->imexseq = 0;
list->mode = MOUSEDEV_EMUL_EXPS;
}
- } else list->imexseq = 0;
+ } else
+ list->imexseq = 0;
if (c == mousedev_imps_seq[list->impsseq]) {
if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
list->impsseq = 0;
list->mode = MOUSEDEV_EMUL_IMPS;
}
- } else list->impsseq = 0;
+ } else
+ list->impsseq = 0;
list->ps2[0] = 0xfa;
@@ -598,6 +608,7 @@ static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t co
static unsigned int mousedev_poll(struct file *file, poll_table *wait)
{
struct mousedev_list *list = file->private_data;
+
poll_wait(file, &list->mousedev->wait, wait);
return ((list->ready || list->buffer) ? (POLLIN | POLLRDNORM) : 0) |
(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
diff --git a/drivers/input/power.c b/drivers/input/power.c
index 526e6070600..51a519e24b6 100644
--- a/drivers/input/power.c
+++ b/drivers/input/power.c
@@ -28,7 +28,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/init.h>
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index 096b6a0b5cc..bc6e87add09 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
@@ -189,7 +188,7 @@ static int __devinit ct82c710_probe(struct platform_device *dev)
strlcpy(ct82c710_port->name, "C&T 82c710 mouse port",
sizeof(ct82c710_port->name));
snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
- "isa%04lx/serio0", CT82C710_DATA);
+ "isa%16llx/serio0", (unsigned long long)CT82C710_DATA);
serio_register_port(ct82c710_port);
@@ -241,8 +240,8 @@ static int __init ct82c710_init(void)
serio_register_port(ct82c710_port);
- printk(KERN_INFO "serio: C&T 82c710 mouse port at %#lx irq %d\n",
- CT82C710_DATA, CT82C710_IRQ);
+ printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
+ (unsigned long long)CT82C710_DATA, CT82C710_IRQ);
return 0;
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index c0b1e4becad..cde036a9216 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -22,7 +22,6 @@
* was usable/enabled ?)
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/serio.h>
@@ -371,7 +370,7 @@ static int __init gscps2_probe(struct parisc_device *dev)
serio->dev.parent = &dev->dev;
ret = -EBUSY;
- if (request_irq(dev->irq, gscps2_interrupt, SA_SHIRQ, ps2port->port->name, ps2port))
+ if (request_irq(dev->irq, gscps2_interrupt, IRQF_SHARED, ps2port->port->name, ps2port))
goto fail_miserably;
if (ps2port->id != GSC_ID_KEYBOARD && ps2port->id != GSC_ID_MOUSE) {
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index ed9446f6d7e..54adba2d8ed 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -1,13 +1,10 @@
#ifndef _I8042_SPARCIO_H
#define _I8042_SPARCIO_H
-#include <linux/config.h>
#include <asm/io.h>
-
-#ifdef CONFIG_PCI
#include <asm/oplib.h>
-#include <asm/ebus.h>
-#endif
+#include <asm/prom.h>
+#include <asm/of_device.h>
static int i8042_kbd_irq = -1;
static int i8042_aux_irq = -1;
@@ -48,54 +45,83 @@ static inline void i8042_write_command(int val)
#define OBP_PS2MS_NAME1 "kdmouse"
#define OBP_PS2MS_NAME2 "mouse"
+static int __devinit sparc_i8042_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct device_node *dp = op->node;
+
+ dp = dp->child;
+ while (dp) {
+ if (!strcmp(dp->name, OBP_PS2KBD_NAME1) ||
+ !strcmp(dp->name, OBP_PS2KBD_NAME2)) {
+ struct of_device *kbd = of_find_device_by_node(dp);
+ unsigned int irq = kbd->irqs[0];
+ if (irq == 0xffffffff)
+ irq = op->irqs[0];
+ i8042_kbd_irq = irq;
+ kbd_iobase = of_ioremap(&kbd->resource[0],
+ 0, 8, "kbd");
+ } else if (!strcmp(dp->name, OBP_PS2MS_NAME1) ||
+ !strcmp(dp->name, OBP_PS2MS_NAME2)) {
+ struct of_device *ms = of_find_device_by_node(dp);
+ unsigned int irq = ms->irqs[0];
+ if (irq == 0xffffffff)
+ irq = op->irqs[0];
+ i8042_aux_irq = irq;
+ }
+
+ dp = dp->sibling;
+ }
+
+ return 0;
+}
+
+static int __devexit sparc_i8042_remove(struct of_device *op)
+{
+ of_iounmap(kbd_iobase, 8);
+
+ return 0;
+}
+
+static struct of_device_id sparc_i8042_match[] = {
+ {
+ .name = "8042",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sparc_i8042_match);
+
+static struct of_platform_driver sparc_i8042_driver = {
+ .name = "i8042",
+ .match_table = sparc_i8042_match,
+ .probe = sparc_i8042_probe,
+ .remove = __devexit_p(sparc_i8042_remove),
+};
+
static int __init i8042_platform_init(void)
{
#ifndef CONFIG_PCI
return -ENODEV;
#else
- char prop[128];
- int len;
+ struct device_node *root = of_find_node_by_path("/");
- len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
- if (len < 0) {
- printk("i8042: Cannot get name property of root OBP node.\n");
- return -ENODEV;
- }
- if (strncmp(prop, "SUNW,JavaStation-1", len) == 0) {
+ if (!strcmp(root->name, "SUNW,JavaStation-1")) {
/* Hardcoded values for MrCoffee. */
i8042_kbd_irq = i8042_aux_irq = 13 | 0x20;
kbd_iobase = ioremap(0x71300060, 8);
if (!kbd_iobase)
return -ENODEV;
} else {
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev;
- struct linux_ebus_child *child;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "8042"))
- goto edev_found;
- }
- }
- return -ENODEV;
-
- edev_found:
- for_each_edevchild(edev, child) {
- if (!strcmp(child->prom_name, OBP_PS2KBD_NAME1) ||
- !strcmp(child->prom_name, OBP_PS2KBD_NAME2)) {
- i8042_kbd_irq = child->irqs[0];
- kbd_iobase =
- ioremap(child->resource[0].start, 8);
- }
- if (!strcmp(child->prom_name, OBP_PS2MS_NAME1) ||
- !strcmp(child->prom_name, OBP_PS2MS_NAME2))
- i8042_aux_irq = child->irqs[0];
- }
+ int err = of_register_driver(&sparc_i8042_driver,
+ &of_bus_type);
+ if (err)
+ return err;
+
if (i8042_kbd_irq == -1 ||
i8042_aux_irq == -1) {
- printk("i8042: Error, 8042 device lacks both kbd and "
- "mouse nodes.\n");
+ if (kbd_iobase) {
+ of_iounmap(kbd_iobase, 8);
+ kbd_iobase = (void __iomem *) NULL;
+ }
return -ENODEV;
}
}
@@ -109,7 +135,10 @@ static int __init i8042_platform_init(void)
static inline void i8042_platform_exit(void)
{
#ifdef CONFIG_PCI
- iounmap(kbd_iobase);
+ struct device_node *root = of_find_node_by_path("/");
+
+ if (strcmp(root->name, "SUNW,JavaStation-1"))
+ of_unregister_driver(&sparc_i8042_driver);
#endif
}
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index a7d91d5356a..06a3f25657d 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -15,7 +15,6 @@
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/err.h>
@@ -329,7 +328,7 @@ static int i8042_open(struct serio *serio)
return 0;
if (request_irq(port->irq, i8042_interrupt,
- SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
+ IRQF_SHARED, "i8042", i8042_request_irq_cookie)) {
printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name);
goto irq_fail;
}
@@ -611,7 +610,7 @@ static int __devinit i8042_check_aux(void)
*/
if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,
- SA_SHIRQ, "i8042", &i8042_check_aux_cookie))
+ IRQF_SHARED, "i8042", &i8042_check_aux_cookie))
return -1;
free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index cbbf3842da5..af526ab9ec0 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -1,7 +1,6 @@
#ifndef _I8042_H
#define _I8042_H
-#include <linux/config.h>
/*
* Copyright (c) 1999-2002 Vojtech Pavlik
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 79c97f94bcb..ed202f2f251 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -177,7 +177,12 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
return -1;
}
- mutex_lock(&ps2dev->cmd_mutex);
+ if (send && !param) {
+ WARN_ON(1);
+ return -1;
+ }
+
+ mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING);
serio_pause_rx(ps2dev->serio);
ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index 1e139c5e59d..fb727c66525 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -107,7 +107,7 @@ static int pcips2_open(struct serio *io)
outb(PS2_CTRL_ENABLE, ps2if->base);
pcips2_flush_input(ps2if);
- ret = request_irq(ps2if->dev->irq, pcips2_interrupt, SA_SHIRQ,
+ ret = request_irq(ps2if->dev->irq, pcips2_interrupt, IRQF_SHARED,
"pcips2", ps2if);
if (ret == 0)
val = PS2_CTRL_ENABLE | PS2_CTRL_RXIRQ;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 6521034bc93..3e76ad71c9a 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -62,6 +62,7 @@ static LIST_HEAD(serio_list);
static struct bus_type serio_bus;
+static void serio_add_driver(struct serio_driver *drv);
static void serio_add_port(struct serio *serio);
static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
@@ -140,8 +141,14 @@ static void serio_release_driver(struct serio *serio)
static void serio_find_driver(struct serio *serio)
{
+ int error;
+
down_write(&serio_bus.subsys.rwsem);
- device_attach(&serio->dev);
+ error = device_attach(&serio->dev);
+ if (error < 0)
+ printk(KERN_WARNING
+ "serio: device_attach() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
up_write(&serio_bus.subsys.rwsem);
}
@@ -272,7 +279,6 @@ static struct serio_event *serio_get_event(void)
static void serio_handle_event(void)
{
struct serio_event *event;
- struct serio_driver *serio_drv;
mutex_lock(&serio_mutex);
@@ -304,8 +310,7 @@ static void serio_handle_event(void)
break;
case SERIO_REGISTER_DRIVER:
- serio_drv = event->object;
- driver_register(&serio_drv->driver);
+ serio_add_driver(event->object);
break;
default:
@@ -525,6 +530,7 @@ static void serio_init_port(struct serio *serio)
__module_get(THIS_MODULE);
+ INIT_LIST_HEAD(&serio->node);
spin_lock_init(&serio->lock);
mutex_init(&serio->drv_mutex);
device_initialize(&serio->dev);
@@ -542,6 +548,8 @@ static void serio_init_port(struct serio *serio)
*/
static void serio_add_port(struct serio *serio)
{
+ int error;
+
if (serio->parent) {
serio_pause_rx(serio->parent);
serio->parent->child = serio;
@@ -551,9 +559,19 @@ static void serio_add_port(struct serio *serio)
list_add_tail(&serio->node, &serio_list);
if (serio->start)
serio->start(serio);
- device_add(&serio->dev);
- sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
- serio->registered = 1;
+ error = device_add(&serio->dev);
+ if (error)
+ printk(KERN_ERR
+ "serio: device_add() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
+ else {
+ serio->registered = 1;
+ error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group);
+ if (error)
+ printk(KERN_ERR
+ "serio: sysfs_create_group() failed for %s (%s), error: %d\n",
+ serio->phys, serio->name, error);
+ }
}
/*
@@ -583,10 +601,10 @@ static void serio_destroy_port(struct serio *serio)
if (serio->registered) {
sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group);
device_del(&serio->dev);
- list_del_init(&serio->node);
serio->registered = 0;
}
+ list_del_init(&serio->node);
serio_remove_pending_events(serio);
put_device(&serio->dev);
}
@@ -756,6 +774,17 @@ static struct bus_type serio_bus = {
.remove = serio_driver_remove,
};
+static void serio_add_driver(struct serio_driver *drv)
+{
+ int error;
+
+ error = driver_register(&drv->driver);
+ if (error)
+ printk(KERN_ERR
+ "serio: driver_register() failed for %s, error: %d\n",
+ drv->driver.name, error);
+}
+
void __serio_register_driver(struct serio_driver *drv, struct module *owner)
{
drv->driver.bus = &serio_bus;
@@ -903,18 +932,26 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void)
{
- serio_task = kthread_run(serio_thread, NULL, "kseriod");
- if (IS_ERR(serio_task)) {
- printk(KERN_ERR "serio: Failed to start kseriod\n");
- return PTR_ERR(serio_task);
- }
+ int error;
serio_bus.dev_attrs = serio_device_attrs;
serio_bus.drv_attrs = serio_driver_attrs;
serio_bus.match = serio_bus_match;
serio_bus.uevent = serio_uevent;
serio_bus.resume = serio_resume;
- bus_register(&serio_bus);
+ error = bus_register(&serio_bus);
+ if (error) {
+ printk(KERN_ERR "serio: failed to register serio bus, error: %d\n", error);
+ return error;
+ }
+
+ serio_task = kthread_run(serio_thread, NULL, "kseriod");
+ if (IS_ERR(serio_task)) {
+ bus_unregister(&serio_bus);
+ error = PTR_ERR(serio_task);
+ printk(KERN_ERR "serio: Failed to start kseriod, error: %d\n", error);
+ return error;
+ }
return 0;
}
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 5a2703b536d..71a8eea816c 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/major.h>
#include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/miscdevice.h>
#include <linux/wait.h>
#include <linux/mutex.h>
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 161afddd0f4..66e411badf7 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -773,8 +773,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->last_msg = m;
- if (request_irq(spi->irq, ads7846_irq,
- SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
+ if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING,
spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 5013703db0e..9b66271d3ba 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -17,7 +17,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/slab.h>
-//#include <asm/irq.h>
+#include <linux/irq.h>
#include <asm/arch/sharpsl.h>
#include <asm/arch/hardware.h>
@@ -318,7 +318,7 @@ static int __init corgits_probe(struct platform_device *pdev)
corgi_ssp_ads7846_putget((5u << ADSCTRL_ADR_SH) | ADSCTRL_STS);
mdelay(5);
- if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) {
+ if (request_irq(corgi_ts->irq_gpio, ts_interrupt, IRQF_DISABLED, "ts", corgi_ts)) {
err = -EBUSY;
goto fail;
}
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 466da190cee..b769b21973b 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -129,7 +129,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
gunze->serio = serio;
gunze->dev = input_dev;
- sprintf(gunze->phys, "%s/input0", serio->phys);
+ snprintf(gunze->phys, sizeof(serio->phys), "%s/input0", serio->phys);
input_dev->private = gunze;
input_dev->name = "Gunze AHL-51S TouchScreen";
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index a18d56bdafd..e2b91001877 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -363,7 +363,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
ts->serio = serio;
ts->dev = input_dev;
- sprintf(ts->phys, "%s/input0", serio->phys);
+ snprintf(ts->phys, sizeof(ts->phys), "%s/input0", serio->phys);
input_dev->name = "H3600 TouchScreen";
input_dev->phys = ts->phys;
@@ -399,16 +399,14 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
- SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
- "h3600_action", &ts->dev)) {
+ IRQF_SHARED | IRQF_DISABLED, "h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
err = -EBUSY;
goto fail2;
}
if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
- SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
- "h3600_suspend", &ts->dev)) {
+ IRQF_SHARED | IRQF_DISABLED, "h3600_suspend", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Power Button IRQ!\n");
err = -EBUSY;
goto fail3;
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index 957dd5a1b15..ee6c2f40cdf 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -15,7 +15,6 @@
#define HP680_TS_ABS_Y_MIN 80
#define HP680_TS_ABS_Y_MAX 910
-#define SCPCR 0xa4000116
#define PHDR 0xa400012e
#define SCPDR 0xa4000136
@@ -77,19 +76,6 @@ static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
static int __init hp680_ts_init(void)
{
- u8 scpdr;
- u16 scpcr;
-
- scpdr = ctrl_inb(SCPDR);
- scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
- scpdr &= ~SCPDR_TS_SCAN_ENABLE;
- ctrl_outb(scpdr, SCPDR);
-
- scpcr = ctrl_inw(SCPCR);
- scpcr &= ~SCPCR_TS_MASK;
- scpcr |= SCPCR_TS_ENABLE;
- ctrl_outw(scpcr, SCPCR);
-
hp680_ts_dev = input_allocate_device();
if (!hp680_ts_dev)
return -ENOMEM;
@@ -109,7 +95,7 @@ static int __init hp680_ts_init(void)
input_register_device(hp680_ts_dev);
if (request_irq(HP680_TS_IRQ, hp680_ts_interrupt,
- SA_INTERRUPT, MODNAME, 0) < 0) {
+ IRQF_DISABLED, MODNAME, 0) < 0) {
printk(KERN_ERR "hp680_touchscreen.c: Can't allocate irq %d\n",
HP680_TS_IRQ);
input_unregister_device(hp680_ts_dev);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 1d0d37eeef6..8647a905df8 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -143,7 +143,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
mtouch->serio = serio;
mtouch->dev = input_dev;
- sprintf(mtouch->phys, "%s/input0", serio->phys);
+ snprintf(mtouch->phys, sizeof(mtouch->phys), "%s/input0", serio->phys);
input_dev->private = mtouch;
input_dev->name = "MicroTouch Serial TouchScreen";
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index d678d144bbf..00e3929c628 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -35,7 +35,7 @@
* e-mail - mail your message to <jsimmons@infradead.org>.
*/
-#define TSDEV_MINOR_BASE 128
+#define TSDEV_MINOR_BASE 128
#define TSDEV_MINORS 32
/* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */
#define TSDEV_MINOR_MASK 15
@@ -48,7 +48,6 @@
#include <linux/init.h>
#include <linux/input.h>
#include <linux/major.h>
-#include <linux/config.h>
#include <linux/smp_lock.h>
#include <linux/random.h>
#include <linux/time.h>
@@ -230,6 +229,7 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
static unsigned int tsdev_poll(struct file *file, poll_table * wait)
{
struct tsdev_list *list = file->private_data;
+
poll_wait(file, &list->tsdev->wait, wait);
return ((list->head == list->tail) ? 0 : (POLLIN | POLLRDNORM)) |
(list->tsdev->exist ? 0 : (POLLHUP | POLLERR));
@@ -248,11 +248,13 @@ static int tsdev_ioctl(struct inode *inode, struct file *file,
sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
+
case TS_SET_CAL:
if (copy_from_user (&tsdev->cal, (void __user *)arg,
sizeof (struct ts_calibration)))
retval = -EFAULT;
break;
+
default:
retval = -EINVAL;
break;
@@ -284,9 +286,11 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
case ABS_X:
tsdev->x = value;
break;
+
case ABS_Y:
tsdev->y = value;
break;
+
case ABS_PRESSURE:
if (value > handle->dev->absmax[ABS_PRESSURE])
value = handle->dev->absmax[ABS_PRESSURE];
@@ -307,6 +311,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
else if (tsdev->x > xres)
tsdev->x = xres;
break;
+
case REL_Y:
tsdev->y += value;
if (tsdev->y < 0)
@@ -323,6 +328,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
case 0:
tsdev->pressure = 0;
break;
+
case 1:
if (!tsdev->pressure)
tsdev->pressure = 1;
@@ -370,9 +376,8 @@ static struct input_handle *tsdev_connect(struct input_handler *handler,
struct class_device *cdev;
int minor, delta;
- for (minor = 0; minor < TSDEV_MINORS/2 && tsdev_table[minor];
- minor++);
- if (minor >= TSDEV_MINORS/2) {
+ for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++);
+ if (minor >= TSDEV_MINORS / 2) {
printk(KERN_ERR
"tsdev: You have way too many touchscreens\n");
return NULL;
@@ -444,22 +449,22 @@ static struct input_device_id tsdev_ids[] = {
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
.keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) },
.relbit = { BIT(REL_X) | BIT(REL_Y) },
- },/* A mouse like device, at least one button, two relative axes */
+ }, /* A mouse like device, at least one button, two relative axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) },
.keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) },
.absbit = { BIT(ABS_X) | BIT(ABS_Y) },
- },/* A tablet like device, at least touch detection, two absolute axes */
+ }, /* A tablet like device, at least touch detection, two absolute axes */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
.absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) },
- },/* A tablet like device with several gradations of pressure */
+ }, /* A tablet like device with several gradations of pressure */
- {},/* Terminating entry */
+ {} /* Terminating entry */
};
MODULE_DEVICE_TABLE(input, tsdev_ids);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 173c899a1fb..669f76393b5 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -39,7 +38,6 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/isdn/capiutil.h>
#include <linux/isdn/capicmd.h>
#if defined(CONFIG_ISDN_CAPI_CAPIFS) || defined(CONFIG_ISDN_CAPI_CAPIFS_MODULE)
@@ -87,6 +85,11 @@ struct capincci;
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
struct capiminor;
+struct datahandle_queue {
+ struct list_head list;
+ u16 datahandle;
+};
+
struct capiminor {
struct list_head list;
struct capincci *nccip;
@@ -109,12 +112,9 @@ struct capiminor {
int outbytes;
/* transmit path */
- struct datahandle_queue {
- struct datahandle_queue *next;
- u16 datahandle;
- } *ackqueue;
+ struct list_head ackqueue;
int nack;
-
+ spinlock_t ackqlock;
};
#endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -156,48 +156,54 @@ static LIST_HEAD(capiminor_list);
static int capincci_add_ack(struct capiminor *mp, u16 datahandle)
{
- struct datahandle_queue *n, **pp;
+ struct datahandle_queue *n;
+ unsigned long flags;
n = kmalloc(sizeof(*n), GFP_ATOMIC);
- if (!n) {
- printk(KERN_ERR "capi: alloc datahandle failed\n");
- return -1;
+ if (unlikely(!n)) {
+ printk(KERN_ERR "capi: alloc datahandle failed\n");
+ return -1;
}
- n->next = NULL;
n->datahandle = datahandle;
- for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) ;
- *pp = n;
+ INIT_LIST_HEAD(&n->list);
+ spin_lock_irqsave(&mp->ackqlock, flags);
+ list_add_tail(&n->list, &mp->ackqueue);
mp->nack++;
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
return 0;
}
static int capiminor_del_ack(struct capiminor *mp, u16 datahandle)
{
- struct datahandle_queue **pp, *p;
+ struct datahandle_queue *p, *tmp;
+ unsigned long flags;
- for (pp = &mp->ackqueue; *pp; pp = &(*pp)->next) {
- if ((*pp)->datahandle == datahandle) {
- p = *pp;
- *pp = (*pp)->next;
+ spin_lock_irqsave(&mp->ackqlock, flags);
+ list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+ if (p->datahandle == datahandle) {
+ list_del(&p->list);
kfree(p);
mp->nack--;
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
return 0;
}
}
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
return -1;
}
static void capiminor_del_all_ack(struct capiminor *mp)
{
- struct datahandle_queue **pp, *p;
+ struct datahandle_queue *p, *tmp;
+ unsigned long flags;
- pp = &mp->ackqueue;
- while (*pp) {
- p = *pp;
- *pp = (*pp)->next;
+ spin_lock_irqsave(&mp->ackqlock, flags);
+ list_for_each_entry_safe(p, tmp, &mp->ackqueue, list) {
+ list_del(&p->list);
kfree(p);
mp->nack--;
}
+ spin_unlock_irqrestore(&mp->ackqlock, flags);
}
@@ -220,6 +226,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
mp->ncci = ncci;
mp->msgid = 0;
atomic_set(&mp->ttyopencount,0);
+ INIT_LIST_HEAD(&mp->ackqueue);
+ spin_lock_init(&mp->ackqlock);
skb_queue_head_init(&mp->inqueue);
skb_queue_head_init(&mp->outqueue);
@@ -1327,7 +1335,6 @@ static int capinc_tty_init(void)
drv->owner = THIS_MODULE;
drv->driver_name = "capi_nc";
- drv->devfs_name = "capi/";
drv->name = "capi";
drv->major = capi_ttymajor;
drv->minor_start = 0;
@@ -1506,8 +1513,6 @@ static int __init capi_init(void)
}
class_device_create(capi_class, NULL, MKDEV(capi_major, 0), NULL, "capi");
- devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
- "isdn/capi20");
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
if (capinc_tty_init() < 0) {
@@ -1542,7 +1547,6 @@ static void __exit capi_exit(void)
class_device_destroy(capi_class, MKDEV(capi_major, 0));
class_destroy(capi_class);
unregister_chrdev(capi_major, "capi20");
- devfs_remove("isdn/capi20");
#ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
capinc_tty_exit();
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 9ea6bd0ddc3..2dd1b57b0ba 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -104,7 +104,6 @@ capifs_fill_super(struct super_block *s, void *data, int silent)
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
- inode->i_blksize = 1024;
inode->i_uid = inode->i_gid = 0;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &simple_dir_inode_operations;
@@ -149,7 +148,6 @@ void capifs_new_ncci(unsigned int number, dev_t device)
if (!inode)
return;
inode->i_ino = number+2;
- inode->i_blksize = 1024;
inode->i_uid = config.setuid ? config.uid : current->fsuid;
inode->i_gid = config.setgid ? config.gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
diff --git a/drivers/isdn/capi/capiutil.c b/drivers/isdn/capi/capiutil.c
index e7cf6bc286a..c1b21552fc0 100644
--- a/drivers/isdn/capi/capiutil.c
+++ b/drivers/isdn/capi/capiutil.c
@@ -17,7 +17,6 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/isdn/capiutil.h>
/* from CAPI2.0 DDK AVM Berlin GmbH */
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 1b37d86d5ee..399b316111f 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/smp_lock.h>
diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c
index f1a1f9a9b88..1f5ebe9ee72 100644
--- a/drivers/isdn/divert/isdn_divert.c
+++ b/drivers/isdn/divert/isdn_divert.c
@@ -592,7 +592,7 @@ static int put_address(char *st, u_char *p, int len)
} /* put_address */
/*************************************/
-/* report a succesfull interrogation */
+/* report a successful interrogation */
/*************************************/
static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
{ char *src = ic->parm.dss1_io.data;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index eb41aba3dde..5cfbe6a3801 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define GIGASET_MINORS 1
#define GIGASET_MINOR 16
#define GIGASET_MODULENAME "bas_gigaset"
-#define GIGASET_DEVFSNAME "gig/bas/"
#define GIGASET_DEVNAME "ttyGB"
/* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
@@ -65,23 +64,22 @@ static struct usb_device_id gigaset_table [] = {
MODULE_DEVICE_TABLE(usb, gigaset_table);
-/*======================= local function prototypes =============================*/
+/*======================= local function prototypes ==========================*/
-/* This function is called if a new device is connected to the USB port. It
- * checks whether this new device belongs to this driver.
- */
+/* function called if a new device belonging to this driver is connected */
static int gigaset_probe(struct usb_interface *interface,
const struct usb_device_id *id);
/* Function will be called if the device is unplugged */
static void gigaset_disconnect(struct usb_interface *interface);
-static void read_ctrl_callback(struct urb *, struct pt_regs *);
+static int atread_submit(struct cardstate *, int);
static void stopurbs(struct bas_bc_state *);
+static int req_submit(struct bc_state *, int, int, int);
static int atwrite_submit(struct cardstate *, unsigned char *, int);
static int start_cbsend(struct cardstate *);
-/*==============================================================================*/
+/*============================================================================*/
struct bas_cardstate {
struct usb_device *udev; /* USB device pointer */
@@ -91,6 +89,7 @@ struct bas_cardstate {
struct urb *urb_ctrl; /* control pipe default URB */
struct usb_ctrlrequest dr_ctrl;
struct timer_list timer_ctrl; /* control request timeout */
+ int retry_ctrl;
struct timer_list timer_atrdy; /* AT command ready timeout */
struct urb *urb_cmd_out; /* for sending AT commands */
@@ -193,7 +192,7 @@ static char *get_usb_statmsg(int status)
return "bit stuffing error, timeout, or unknown USB error";
case -EILSEQ:
return "CRC mismatch, timeout, or unknown USB error";
- case -ETIMEDOUT:
+ case -ETIME:
return "timed out";
case -EPIPE:
return "endpoint stalled";
@@ -307,6 +306,7 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
* hang up any existing connection because of an unrecoverable error
* This function may be called from any context and takes care of scheduling
* the necessary actions for execution outside of interrupt context.
+ * cs->lock must not be held.
* argument:
* B channel control structure
*/
@@ -325,14 +325,17 @@ static inline void error_hangup(struct bc_state *bcs)
/* error_reset
* reset Gigaset device because of an unrecoverable error
- * This function may be called from any context, and should take care of
+ * This function may be called from any context, and takes care of
* scheduling the necessary actions for execution outside of interrupt context.
- * Right now, it just generates a kernel message calling for help.
+ * cs->lock must not be held.
* argument:
* controller state structure
*/
static inline void error_reset(struct cardstate *cs)
{
+ /* close AT command channel to recover (ignore errors) */
+ req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
+
//FIXME try to recover without bothering the user
dev_err(cs->dev,
"unrecoverable error - please disconnect Gigaset base to reset\n");
@@ -403,14 +406,30 @@ static void cmd_in_timeout(unsigned long data)
{
struct cardstate *cs = (struct cardstate *) data;
struct bas_cardstate *ucs = cs->hw.bas;
+ int rc;
if (!ucs->rcvbuf_size) {
gig_dbg(DEBUG_USBREQ, "%s: no receive in progress", __func__);
return;
}
- dev_err(cs->dev, "timeout reading AT response\n");
- error_reset(cs); //FIXME retry?
+ if (ucs->retry_cmd_in++ < BAS_RETRY) {
+ dev_notice(cs->dev, "control read: timeout, retry %d\n",
+ ucs->retry_cmd_in);
+ rc = atread_submit(cs, BAS_TIMEOUT);
+ if (rc >= 0 || rc == -ENODEV)
+ /* resubmitted or disconnected */
+ /* - bypass regular exit block */
+ return;
+ } else {
+ dev_err(cs->dev,
+ "control read: timeout, giving up after %d tries\n",
+ ucs->retry_cmd_in);
+ }
+ kfree(ucs->rcvbuf);
+ ucs->rcvbuf = NULL;
+ ucs->rcvbuf_size = 0;
+ error_reset(cs);
}
/* set/clear bits in base connection state, return previous state
@@ -428,6 +447,96 @@ inline static int update_basstate(struct bas_cardstate *ucs,
return state;
}
+/* read_ctrl_callback
+ * USB completion handler for control pipe input
+ * called by the USB subsystem in interrupt context
+ * parameter:
+ * urb USB request block
+ * urb->context = inbuf structure for controller state
+ */
+static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct inbuf_t *inbuf = urb->context;
+ struct cardstate *cs = inbuf->cs;
+ struct bas_cardstate *ucs = cs->hw.bas;
+ int have_data = 0;
+ unsigned numbytes;
+ int rc;
+
+ update_basstate(ucs, 0, BS_ATRDPEND);
+
+ if (!ucs->rcvbuf_size) {
+ dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
+ return;
+ }
+
+ del_timer(&ucs->timer_cmd_in);
+
+ switch (urb->status) {
+ case 0: /* normal completion */
+ numbytes = urb->actual_length;
+ if (unlikely(numbytes != ucs->rcvbuf_size)) {
+ dev_warn(cs->dev,
+ "control read: received %d chars, expected %d\n",
+ numbytes, ucs->rcvbuf_size);
+ if (numbytes > ucs->rcvbuf_size)
+ numbytes = ucs->rcvbuf_size;
+ }
+
+ /* copy received bytes to inbuf */
+ have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
+
+ if (unlikely(numbytes < ucs->rcvbuf_size)) {
+ /* incomplete - resubmit for remaining bytes */
+ ucs->rcvbuf_size -= numbytes;
+ ucs->retry_cmd_in = 0;
+ rc = atread_submit(cs, BAS_TIMEOUT);
+ if (rc >= 0 || rc == -ENODEV)
+ /* resubmitted or disconnected */
+ /* - bypass regular exit block */
+ return;
+ error_reset(cs);
+ }
+ break;
+
+ case -ENOENT: /* cancelled */
+ case -ECONNRESET: /* cancelled (async) */
+ case -EINPROGRESS: /* pending */
+ case -ENODEV: /* device removed */
+ case -ESHUTDOWN: /* device shut down */
+ /* no action necessary */
+ gig_dbg(DEBUG_USBREQ, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
+ break;
+
+ default: /* severe trouble */
+ dev_warn(cs->dev, "control read: %s\n",
+ get_usb_statmsg(urb->status));
+ if (ucs->retry_cmd_in++ < BAS_RETRY) {
+ dev_notice(cs->dev, "control read: retry %d\n",
+ ucs->retry_cmd_in);
+ rc = atread_submit(cs, BAS_TIMEOUT);
+ if (rc >= 0 || rc == -ENODEV)
+ /* resubmitted or disconnected */
+ /* - bypass regular exit block */
+ return;
+ } else {
+ dev_err(cs->dev,
+ "control read: giving up after %d tries\n",
+ ucs->retry_cmd_in);
+ }
+ error_reset(cs);
+ }
+
+ kfree(ucs->rcvbuf);
+ ucs->rcvbuf = NULL;
+ ucs->rcvbuf_size = 0;
+ if (have_data) {
+ gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
+ gigaset_schedule_event(cs);
+ }
+}
+
/* atread_submit
* submit an HD_READ_ATMESSAGE command URB and optionally start a timeout
* parameters:
@@ -466,7 +575,7 @@ static int atread_submit(struct cardstate *cs, int timeout)
if ((ret = usb_submit_urb(ucs->urb_cmd_in, SLAB_ATOMIC)) != 0) {
update_basstate(ucs, 0, BS_ATRDPEND);
dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: %s\n",
- get_usb_statmsg(ret));
+ get_usb_rcmsg(ret));
return ret;
}
@@ -611,9 +720,12 @@ static void read_int_callback(struct urb *urb, struct pt_regs *regs)
kfree(ucs->rcvbuf);
ucs->rcvbuf = NULL;
ucs->rcvbuf_size = 0;
- if (rc != -ENODEV)
+ if (rc != -ENODEV) {
//FIXME corrective action?
+ spin_unlock_irqrestore(&cs->lock, flags);
error_reset(cs);
+ break;
+ }
}
spin_unlock_irqrestore(&cs->lock, flags);
break;
@@ -643,97 +755,6 @@ resubmit:
}
}
-/* read_ctrl_callback
- * USB completion handler for control pipe input
- * called by the USB subsystem in interrupt context
- * parameter:
- * urb USB request block
- * urb->context = inbuf structure for controller state
- */
-static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
-{
- struct inbuf_t *inbuf = urb->context;
- struct cardstate *cs = inbuf->cs;
- struct bas_cardstate *ucs = cs->hw.bas;
- int have_data = 0;
- unsigned numbytes;
- int rc;
-
- update_basstate(ucs, 0, BS_ATRDPEND);
-
- if (!ucs->rcvbuf_size) {
- dev_warn(cs->dev, "%s: no receive in progress\n", __func__);
- return;
- }
-
- del_timer(&ucs->timer_cmd_in);
-
- switch (urb->status) {
- case 0: /* normal completion */
- numbytes = urb->actual_length;
- if (unlikely(numbytes == 0)) {
- dev_warn(cs->dev,
- "control read: empty block received\n");
- goto retry;
- }
- if (unlikely(numbytes != ucs->rcvbuf_size)) {
- dev_warn(cs->dev,
- "control read: received %d chars, expected %d\n",
- numbytes, ucs->rcvbuf_size);
- if (numbytes > ucs->rcvbuf_size)
- numbytes = ucs->rcvbuf_size;
- }
-
- /* copy received bytes to inbuf */
- have_data = gigaset_fill_inbuf(inbuf, ucs->rcvbuf, numbytes);
-
- if (unlikely(numbytes < ucs->rcvbuf_size)) {
- /* incomplete - resubmit for remaining bytes */
- ucs->rcvbuf_size -= numbytes;
- ucs->retry_cmd_in = 0;
- goto retry;
- }
- break;
-
- case -ENOENT: /* cancelled */
- case -ECONNRESET: /* cancelled (async) */
- case -EINPROGRESS: /* pending */
- case -ENODEV: /* device removed */
- case -ESHUTDOWN: /* device shut down */
- /* no action necessary */
- gig_dbg(DEBUG_USBREQ, "%s: %s",
- __func__, get_usb_statmsg(urb->status));
- break;
-
- default: /* severe trouble */
- dev_warn(cs->dev, "control read: %s\n",
- get_usb_statmsg(urb->status));
- retry:
- if (ucs->retry_cmd_in++ < BAS_RETRY) {
- dev_notice(cs->dev, "control read: retry %d\n",
- ucs->retry_cmd_in);
- rc = atread_submit(cs, BAS_TIMEOUT);
- if (rc >= 0 || rc == -ENODEV)
- /* resubmitted or disconnected */
- /* - bypass regular exit block */
- return;
- } else {
- dev_err(cs->dev,
- "control read: giving up after %d tries\n",
- ucs->retry_cmd_in);
- }
- error_reset(cs);
- }
-
- kfree(ucs->rcvbuf);
- ucs->rcvbuf = NULL;
- ucs->rcvbuf_size = 0;
- if (have_data) {
- gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
- gigaset_schedule_event(cs);
- }
-}
-
/* read_iso_callback
* USB completion handler for B channel isochronous input
* called by the USB subsystem in interrupt context
@@ -1378,6 +1399,7 @@ static void req_timeout(unsigned long data)
case HD_CLOSE_B1CHANNEL:
dev_err(bcs->cs->dev, "timeout closing channel %d\n",
bcs->channel + 1);
+ error_reset(bcs->cs);
break;
default:
@@ -1396,22 +1418,61 @@ static void req_timeout(unsigned long data)
static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
{
struct bas_cardstate *ucs = urb->context;
+ int rc;
unsigned long flags;
- spin_lock_irqsave(&ucs->lock, flags);
- if (urb->status && ucs->pending) {
- dev_err(&ucs->interface->dev,
- "control request 0x%02x failed: %s\n",
- ucs->pending, get_usb_statmsg(urb->status));
- del_timer(&ucs->timer_ctrl);
- ucs->pending = 0;
- }
- /* individual handling of specific request types */
- switch (ucs->pending) {
- case HD_DEVICE_INIT_ACK: /* no reply expected */
- ucs->pending = 0;
+ /* check status */
+ switch (urb->status) {
+ case 0: /* normal completion */
+ spin_lock_irqsave(&ucs->lock, flags);
+ switch (ucs->pending) {
+ case HD_DEVICE_INIT_ACK: /* no reply expected */
+ del_timer(&ucs->timer_ctrl);
+ ucs->pending = 0;
+ break;
+ }
+ spin_unlock_irqrestore(&ucs->lock, flags);
+ return;
+
+ case -ENOENT: /* cancelled */
+ case -ECONNRESET: /* cancelled (async) */
+ case -EINPROGRESS: /* pending */
+ case -ENODEV: /* device removed */
+ case -ESHUTDOWN: /* device shut down */
+ /* ignore silently */
+ gig_dbg(DEBUG_USBREQ, "%s: %s",
+ __func__, get_usb_statmsg(urb->status));
break;
+
+ default: /* any failure */
+ if (++ucs->retry_ctrl > BAS_RETRY) {
+ dev_err(&ucs->interface->dev,
+ "control request 0x%02x failed: %s\n",
+ ucs->dr_ctrl.bRequest,
+ get_usb_statmsg(urb->status));
+ break; /* give up */
+ }
+ dev_notice(&ucs->interface->dev,
+ "control request 0x%02x: %s, retry %d\n",
+ ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status),
+ ucs->retry_ctrl);
+ /* urb->dev is clobbered by USB subsystem */
+ urb->dev = ucs->udev;
+ rc = usb_submit_urb(urb, SLAB_ATOMIC);
+ if (unlikely(rc)) {
+ dev_err(&ucs->interface->dev,
+ "could not resubmit request 0x%02x: %s\n",
+ ucs->dr_ctrl.bRequest, get_usb_rcmsg(rc));
+ break;
+ }
+ /* resubmitted */
+ return;
}
+
+ /* failed, clear pending request */
+ spin_lock_irqsave(&ucs->lock, flags);
+ del_timer(&ucs->timer_ctrl);
+ ucs->pending = 0;
spin_unlock_irqrestore(&ucs->lock, flags);
}
@@ -1455,9 +1516,11 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout)
usb_sndctrlpipe(ucs->udev, 0),
(unsigned char*) &ucs->dr_ctrl, NULL, 0,
write_ctrl_callback, ucs);
- if ((ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC)) != 0) {
+ ucs->retry_ctrl = 0;
+ ret = usb_submit_urb(ucs->urb_ctrl, SLAB_ATOMIC);
+ if (unlikely(ret)) {
dev_err(bcs->cs->dev, "could not submit request 0x%02x: %s\n",
- req, get_usb_statmsg(ret));
+ req, get_usb_rcmsg(ret));
spin_unlock_irqrestore(&ucs->lock, flags);
return ret;
}
@@ -2285,8 +2348,7 @@ static int __init bas_gigaset_init(void)
/* allocate memory for our driver state and intialize it */
if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
- GIGASET_DEVFSNAME, &gigops,
- THIS_MODULE)) == NULL)
+ &gigops, THIS_MODULE)) == NULL)
goto error;
/* allocate memory for our device state and intialize it */
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c
index acb7e265678..aca165d43aa 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -981,7 +981,7 @@ exit:
EXPORT_SYMBOL_GPL(gigaset_stop);
static LIST_HEAD(drivers);
-static spinlock_t driver_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(driver_lock);
struct cardstate *gigaset_get_cs_by_id(int id)
{
@@ -1092,14 +1092,12 @@ EXPORT_SYMBOL_GPL(gigaset_freedriver);
* minors Number of minors this driver can handle
* procname Name of the driver
* devname Name of the device files (prefix without minor number)
- * devfsname Devfs name of the device files without %d
* return value:
* Pointer to the gigaset_driver structure on success, NULL on failure.
*/
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
const char *procname,
const char *devname,
- const char *devfsname,
const struct gigaset_ops *ops,
struct module *owner)
{
@@ -1139,7 +1137,7 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
drv->cs[i].minor_index = i;
}
- gigaset_if_initdriver(drv, procname, devname, devfsname);
+ gigaset_if_initdriver(drv, procname, devname);
spin_lock_irqsave(&driver_lock, flags);
list_add(&drv->list, &drivers);
diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c
index 18e05c09b71..44f02dbd111 100644
--- a/drivers/isdn/gigaset/ev-layer.c
+++ b/drivers/isdn/gigaset/ev-layer.c
@@ -1262,7 +1262,8 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_HUPMODEM:
/* send "+++" (hangup in unimodem mode) */
- cs->ops->write_cmd(cs, "+++", 3, NULL);
+ if (cs->connected)
+ cs->ops->write_cmd(cs, "+++", 3, NULL);
break;
case ACT_RING:
/* get fresh AT state structure for new CID */
@@ -1294,7 +1295,6 @@ static void do_action(int action, struct cardstate *cs,
break;
case ACT_ICALL:
handle_icall(cs, bcs, p_at_state);
- at_state = *p_at_state;
break;
case ACT_FAILSDOWN:
dev_warn(cs->dev, "Could not shut down the device.\n");
@@ -1334,10 +1334,8 @@ static void do_action(int action, struct cardstate *cs,
*/
at_state->pending_commands |= PC_DLE0;
atomic_set(&cs->commands_pending, 1);
- } else {
+ } else
disconnect(p_at_state);
- at_state = *p_at_state;
- }
break;
case ACT_FAKEDLE0:
at_state->int_var[VAR_ZDLE] = 0;
@@ -1354,10 +1352,8 @@ static void do_action(int action, struct cardstate *cs,
at_state->cid = -1;
if (bcs && cs->onechannel)
at_state->pending_commands |= PC_DLE0;
- else {
+ else
disconnect(p_at_state);
- at_state = *p_at_state;
- }
schedule_init(cs, MS_RECOVER);
break;
case ACT_FAILDLE0:
@@ -1410,7 +1406,6 @@ static void do_action(int action, struct cardstate *cs,
case ACT_ABORTACCEPT: /* hangup/error/timeout during ICALL processing */
disconnect(p_at_state);
- at_state = *p_at_state;
break;
case ACT_ABORTDIAL: /* error/timeout during dial preparation */
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h
index 8d63d822104..884bd72c1bf 100644
--- a/drivers/isdn/gigaset/gigaset.h
+++ b/drivers/isdn/gigaset/gigaset.h
@@ -16,7 +16,6 @@
#ifndef GIGASET_H
#define GIGASET_H
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/compiler.h>
#include <linux/types.h>
@@ -769,7 +768,6 @@ void gigaset_block_channels(struct cardstate *cs);
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
const char *procname,
const char *devname,
- const char *devfsname,
const struct gigaset_ops *ops,
struct module *owner);
@@ -892,7 +890,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
/* initialize interface */
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
- const char *devname, const char *devfsname);
+ const char *devname);
/* release interface */
void gigaset_if_freedriver(struct gigaset_driver *drv);
/* add minor */
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index 74fd234956c..bd2e4267528 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -673,10 +673,9 @@ EXPORT_SYMBOL_GPL(gigaset_if_receive);
* drv Driver
* procname Name of the driver (e.g. for /proc/tty/drivers)
* devname Name of the device files (prefix without minor number)
- * devfsname Devfs name of the device files without %d
*/
void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
- const char *devname, const char *devfsname)
+ const char *devname)
{
unsigned minors = drv->minors;
int ret;
@@ -692,7 +691,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
tty->major = GIG_MAJOR,
tty->type = TTY_DRIVER_TYPE_SERIAL,
tty->subtype = SERIAL_TYPE_NORMAL,
- tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+ tty->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty->driver_name = procname;
tty->name = devname;
@@ -700,7 +699,6 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname,
tty->num = drv->minors;
tty->owner = THIS_MODULE;
- tty->devfs_name = devfsname;
tty->init_termios = tty_std_termios; //FIXME
tty->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; //FIXME
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index d86ab68114b..6e05d9d4a51 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -41,7 +41,6 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
#define GIGASET_MINORS 1
#define GIGASET_MINOR 8
#define GIGASET_MODULENAME "usb_gigaset"
-#define GIGASET_DEVFSNAME "gig/usb/"
#define GIGASET_DEVNAME "ttyGU"
#define IF_WRITEBUF 2000 //FIXME // WAKEUP_CHARS: 256
@@ -896,8 +895,7 @@ static int __init usb_gigaset_init(void)
/* allocate memory for our driver state and intialize it */
if ((driver = gigaset_initdriver(GIGASET_MINOR, GIGASET_MINORS,
GIGASET_MODULENAME, GIGASET_DEVNAME,
- GIGASET_DEVFSNAME, &ops,
- THIS_MODULE)) == NULL)
+ &ops, THIS_MODULE)) == NULL)
goto error;
/* allocate memory for our device state and intialize it */
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index 4d64e5cbcdb..a4beeb46c85 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
diff --git a/drivers/isdn/hardware/avm/b1pci.c b/drivers/isdn/hardware/avm/b1pci.c
index 5435a6cfb5e..90e2e6643d1 100644
--- a/drivers/isdn/hardware/avm/b1pci.c
+++ b/drivers/isdn/hardware/avm/b1pci.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -98,7 +97,7 @@ static int b1pci_probe(struct capicardparams *p, struct pci_dev *pdev)
b1_reset(card->port);
b1_getrevision(card);
- retval = request_irq(card->irq, b1_interrupt, SA_SHIRQ, card->name, card);
+ retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pci: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
@@ -235,7 +234,7 @@ static int b1pciv4_probe(struct capicardparams *p, struct pci_dev *pdev)
b1dma_reset(card);
b1_getrevision(card);
- retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
+ retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pci: unable to get IRQ %d.\n",
card->irq);
diff --git a/drivers/isdn/hardware/avm/b1pcmcia.c b/drivers/isdn/hardware/avm/b1pcmcia.c
index 9746cc5ffff..e479c0aef38 100644
--- a/drivers/isdn/hardware/avm/b1pcmcia.c
+++ b/drivers/isdn/hardware/avm/b1pcmcia.c
@@ -82,7 +82,7 @@ static int b1pcmcia_add_card(unsigned int port, unsigned irq,
card->irq = irq;
card->cardtype = cardtype;
- retval = request_irq(card->irq, b1_interrupt, 0, card->name, card);
+ retval = request_irq(card->irq, b1_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "b1pcmcia: unable to get IRQ %d.\n",
card->irq);
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index f7253b2136e..6c3d5f5f1f4 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -1173,7 +1172,7 @@ static int c4_add_card(struct capicardparams *p, struct pci_dev *dev,
}
c4_reset(card);
- retval = request_irq(card->irq, c4_interrupt, SA_SHIRQ, card->name, card);
+ retval = request_irq(card->irq, c4_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "c4: unable to get IRQ %d.\n",card->irq);
retval = -EBUSY;
diff --git a/drivers/isdn/hardware/avm/t1pci.c b/drivers/isdn/hardware/avm/t1pci.c
index 2ceec8e8419..d1e253c94db 100644
--- a/drivers/isdn/hardware/avm/t1pci.c
+++ b/drivers/isdn/hardware/avm/t1pci.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
@@ -104,7 +103,7 @@ static int t1pci_add_card(struct capicardparams *p, struct pci_dev *pdev)
}
b1dma_reset(card);
- retval = request_irq(card->irq, b1dma_interrupt, SA_SHIRQ, card->name, card);
+ retval = request_irq(card->irq, b1dma_interrupt, IRQF_SHARED, card->name, card);
if (retval) {
printk(KERN_ERR "t1pci: unable to get IRQ %d.\n", card->irq);
retval = -EBUSY;
diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c
index 8fe4f3f0935..7a74ed35b1b 100644
--- a/drivers/isdn/hardware/eicon/capimain.c
+++ b/drivers/isdn/hardware/eicon/capimain.c
@@ -10,7 +10,6 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/uaccess.h>
diff --git a/drivers/isdn/hardware/eicon/diva_didd.c b/drivers/isdn/hardware/eicon/diva_didd.c
index 27204f4b111..14298b8c835 100644
--- a/drivers/isdn/hardware/eicon/diva_didd.c
+++ b/drivers/isdn/hardware/eicon/diva_didd.c
@@ -11,7 +11,6 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
index 6146f7633be..77155d9f399 100644
--- a/drivers/isdn/hardware/eicon/divamnt.c
+++ b/drivers/isdn/hardware/eicon/divamnt.c
@@ -10,14 +10,12 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include "platform.h"
@@ -178,7 +176,6 @@ static struct file_operations divas_maint_fops = {
static void divas_maint_unregister_chrdev(void)
{
- devfs_remove(DEVNAME);
unregister_chrdev(major, DEVNAME);
}
@@ -190,7 +187,6 @@ static int DIVA_INIT_FUNCTION divas_maint_register_chrdev(void)
DRIVERLNAME);
return (0);
}
- devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
return (1);
}
diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
index df715b47e2b..fff0d89c806 100644
--- a/drivers/isdn/hardware/eicon/divasi.c
+++ b/drivers/isdn/hardware/eicon/divasi.c
@@ -10,7 +10,6 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -19,7 +18,6 @@
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/skbuff.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include "platform.h"
@@ -145,7 +143,6 @@ static struct file_operations divas_idi_fops = {
static void divas_idi_unregister_chrdev(void)
{
- devfs_remove(DEVNAME);
unregister_chrdev(major, DEVNAME);
}
@@ -157,7 +154,6 @@ static int DIVA_INIT_FUNCTION divas_idi_register_chrdev(void)
DRIVERLNAME);
return (0);
}
- devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
return (1);
}
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index c9b26e86d18..b7dadba13e8 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -9,12 +9,10 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/ioport.h>
@@ -488,7 +486,7 @@ void __inline__ outpp(void __iomem *addr, word p)
int diva_os_register_irq(void *context, byte irq, const char *name)
{
int result = request_irq(irq, diva_os_irq_wrapper,
- SA_INTERRUPT | SA_SHIRQ, name, context);
+ IRQF_DISABLED | IRQF_SHARED, name, context);
return (result);
}
@@ -678,7 +676,6 @@ static struct file_operations divas_fops = {
static void divas_unregister_chrdev(void)
{
- devfs_remove(DEVNAME);
unregister_chrdev(major, DEVNAME);
}
@@ -690,7 +687,6 @@ static int DIVA_INIT_FUNCTION divas_register_chrdev(void)
DRIVERLNAME);
return (0);
}
- devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DEVNAME);
return (1);
}
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
index c12efa6f842..6a4373a4f1e 100644
--- a/drivers/isdn/hardware/eicon/divasproc.c
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -10,7 +10,6 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/poll.h>
diff --git a/drivers/isdn/hardware/eicon/divasync.h b/drivers/isdn/hardware/eicon/divasync.h
index 0a5be7f969f..af3eb9e795b 100644
--- a/drivers/isdn/hardware/eicon/divasync.h
+++ b/drivers/isdn/hardware/eicon/divasync.h
@@ -256,7 +256,6 @@ typedef struct
#define NO_ORDER_CHECK_MASK 0x00000010
#define LOW_CHANNEL_MASK 0x00000020
#define NO_HSCX30_MASK 0x00000040
-#define MODE_MASK 0x00000080
#define SET_BOARD 0x00001000
#define SET_CRC4 0x00030000
#define SET_L1_TRISTATE 0x00040000
diff --git a/drivers/isdn/hardware/eicon/platform.h b/drivers/isdn/hardware/eicon/platform.h
index 12b8ff29e97..a66836cf756 100644
--- a/drivers/isdn/hardware/eicon/platform.h
+++ b/drivers/isdn/hardware/eicon/platform.h
@@ -18,7 +18,6 @@
#define DIVA_BUILD "local"
#endif
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index a98c5e38bbb..93ff941c48f 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -297,7 +297,7 @@ Asus_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id asus_ids[] __initdata = {
+static struct isapnp_device_id asus_ids[] __devinitdata = {
{ ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
ISAPNP_VENDOR('A', 'S', 'U'), ISAPNP_FUNCTION(0x1688),
(unsigned long) "Asus1688 PnP" },
@@ -313,11 +313,11 @@ static struct isapnp_device_id asus_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &asus_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &asus_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_asuscom(struct IsdnCard *card)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
index 9a8b02557ff..729e906bdc6 100644
--- a/drivers/isdn/hisax/avm_a1.c
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -178,7 +178,7 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_avm_a1(struct IsdnCard *card)
{
u_char val;
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
index d643bb32ad0..574e252dfa4 100644
--- a/drivers/isdn/hisax/avm_a1p.c
+++ b/drivers/isdn/hisax/avm_a1p.c
@@ -255,7 +255,7 @@ setup_avm_a1_pcmcia(struct IsdnCard *card)
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &AVM_card_msg;
- cs->irq_flags = SA_SHIRQ;
+ cs->irq_flags = IRQF_SHARED;
cs->irq_func = &avm_a1p_interrupt;
ISACVersion(cs, "AVM A1 PCMCIA:");
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 4abe5ff10e7..369afd3a3a4 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -640,7 +639,7 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs)
}
#endif /* 0 */
-static void __init
+static void
inithdlc(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hdlc;
@@ -728,13 +727,13 @@ AVM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef CONFIG_PCI
-static struct pci_dev *dev_avm __initdata = NULL;
+static struct pci_dev *dev_avm __devinitdata = NULL;
#endif
#ifdef __ISAPNP__
-static struct pnp_card *pnp_avm_c __initdata = NULL;
+static struct pnp_card *pnp_avm_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_avm_pcipnp(struct IsdnCard *card)
{
u_int val, ver;
@@ -809,7 +808,7 @@ setup_avm_pcipnp(struct IsdnCard *card)
printk(KERN_WARNING "FritzPCI: No PCI card found\n");
return(0);
}
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
#else
printk(KERN_WARNING "FritzPCI: NO_PCI_BIOS\n");
return (0);
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index dcb308aeb50..87a630128a6 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -11,7 +11,6 @@
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -256,9 +255,9 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
-static struct pci_dev *dev_a4t __initdata = NULL;
+static struct pci_dev *dev_a4t __devinitdata = NULL;
-int __init
+int __devinit
setup_bkm_a4t(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -336,7 +335,7 @@ setup_bkm_a4t(struct IsdnCard *card)
cs->BC_Send_Data = &jade_fill_fifo;
cs->cardmsg = &BKM_card_msg;
cs->irq_func = &bkm_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "Telekom A4T:");
/* Jade version */
JadeVersion(cs, "Telekom A4T:");
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 5f21b82c8c8..dae090a9a48 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -11,7 +11,6 @@
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -261,7 +260,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
-static int __init
+static int __devinit
sct_alloc_io(u_int adr, u_int len)
{
if (!request_region(adr, len, "scitel")) {
@@ -273,16 +272,16 @@ sct_alloc_io(u_int adr, u_int len)
return(0);
}
-static struct pci_dev *dev_a8 __initdata = NULL;
-static u16 sub_vendor_id __initdata = 0;
-static u16 sub_sys_id __initdata = 0;
-static u_char pci_bus __initdata = 0;
-static u_char pci_device_fn __initdata = 0;
-static u_char pci_irq __initdata = 0;
+static struct pci_dev *dev_a8 __devinitdata = NULL;
+static u16 sub_vendor_id __devinitdata = 0;
+static u16 sub_sys_id __devinitdata = 0;
+static u_char pci_bus __devinitdata = 0;
+static u_char pci_device_fn __devinitdata = 0;
+static u_char pci_irq __devinitdata = 0;
#endif /* CONFIG_PCI */
-int __init
+int __devinit
setup_sct_quadro(struct IsdnCard *card)
{
#ifdef CONFIG_PCI
@@ -375,7 +374,7 @@ setup_sct_quadro(struct IsdnCard *card)
pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
/* Take over */
cs->irq = pci_irq;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
/* pci_ioaddr1 is unique to all subdevices */
/* pci_ioaddr2 is for the fourth subdevice only */
/* pci_ioaddr3 is for the third subdevice only */
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 27332506f9f..e10350360f2 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -17,7 +17,6 @@
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/timer.h>
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include <linux/module.h>
@@ -1876,7 +1875,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
#ifdef CONFIG_PCI
#include <linux/pci.h>
-static struct pci_device_id hisax_pci_tbl[] __initdata = {
+static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
#ifdef CONFIG_HISAX_FRITZPCI
{PCI_VENDOR_ID_AVM, PCI_DEVICE_ID_AVM_A1, PCI_ANY_ID, PCI_ANY_ID},
#endif
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index b0ff1cc97d7..e294fa3918f 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -16,7 +16,6 @@
*/
#include <linux/init.h>
-#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
@@ -888,13 +887,13 @@ Diva_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_diva __initdata = NULL;
-static struct pci_dev *dev_diva_u __initdata = NULL;
-static struct pci_dev *dev_diva201 __initdata = NULL;
-static struct pci_dev *dev_diva202 __initdata = NULL;
+static struct pci_dev *dev_diva __devinitdata = NULL;
+static struct pci_dev *dev_diva_u __devinitdata = NULL;
+static struct pci_dev *dev_diva201 __devinitdata = NULL;
+static struct pci_dev *dev_diva202 __devinitdata = NULL;
#ifdef __ISAPNP__
-static struct isapnp_device_id diva_ids[] __initdata = {
+static struct isapnp_device_id diva_ids[] __devinitdata = {
{ ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
ISAPNP_VENDOR('G', 'D', 'I'), ISAPNP_FUNCTION(0x51),
(unsigned long) "Diva picola" },
@@ -916,12 +915,12 @@ static struct isapnp_device_id diva_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &diva_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &diva_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_diva(struct IsdnCard *card)
{
int bytecnt = 8;
@@ -1077,7 +1076,7 @@ setup_diva(struct IsdnCard *card)
printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
return(0);
}
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
#else
printk(KERN_WARNING "Diva: cfgreg 0 and NO_PCI_BIOS\n");
printk(KERN_WARNING "Diva: unable to config DIVA PCI\n");
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index f8ca4b32333..3b3e318f607 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -19,7 +19,6 @@
*/
#include <linux/init.h>
-#include <linux/config.h>
#include "hisax.h"
#include "arcofi.h"
#include "isac.h"
@@ -86,8 +85,8 @@ static const char *ITACVer[] =
*** ***/
/* Config-Register (Read) */
-#define ELSA_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
-#define ELSA_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
+#define ELIRQF_TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
+#define ELIRQF_TIMER_RUN_PCC8 0x01 /* Bit 0 des Config-Reg bei PCC */
#define ELSA_IRQ_IDX 0x38 /* Bit 3,4,5 des Config-Reg */
#define ELSA_IRQ_IDX_PCC8 0x30 /* Bit 4,5 des Config-Reg */
#define ELSA_IRQ_IDX_PC 0x0c /* Bit 2,3 des Config-Reg */
@@ -103,7 +102,7 @@ static const char *ITACVer[] =
#define ELSA_S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
/* Status Flags */
-#define ELSA_TIMER_AKTIV 1
+#define ELIRQF_TIMER_AKTIV 1
#define ELSA_BAD_PWR 2
#define ELSA_ASSIGN 4
@@ -260,10 +259,10 @@ TimerRun(struct IsdnCardState *cs)
v = bytein(cs->hw.elsa.cfg);
if ((cs->subtyp == ELSA_QS1000) || (cs->subtyp == ELSA_QS3000))
- return (0 == (v & ELSA_TIMER_RUN));
+ return (0 == (v & ELIRQF_TIMER_RUN));
else if (cs->subtyp == ELSA_PCC8)
- return (v & ELSA_TIMER_RUN_PCC8);
- return (v & ELSA_TIMER_RUN);
+ return (v & ELIRQF_TIMER_RUN_PCC8);
+ return (v & ELIRQF_TIMER_RUN);
}
/*
* fast interrupt HSCX stuff goes here
@@ -335,7 +334,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.elsa.ale, cs->hw.elsa.isac, ISAC_MASK, 0xFF);
- if (cs->hw.elsa.status & ELSA_TIMER_AKTIV) {
+ if (cs->hw.elsa.status & ELIRQF_TIMER_AKTIV) {
if (!TimerRun(cs)) {
/* Timer Restart */
byteout(cs->hw.elsa.timer, 0);
@@ -686,7 +685,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
spin_lock_irqsave(&cs->lock, flags);
cs->hw.elsa.counter = 0;
cs->hw.elsa.ctrl_reg |= ELSA_ENA_TIMER_INT;
- cs->hw.elsa.status |= ELSA_TIMER_AKTIV;
+ cs->hw.elsa.status |= ELIRQF_TIMER_AKTIV;
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
byteout(cs->hw.elsa.timer, 0);
spin_unlock_irqrestore(&cs->lock, flags);
@@ -694,7 +693,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg)
spin_lock_irqsave(&cs->lock, flags);
cs->hw.elsa.ctrl_reg &= ~ELSA_ENA_TIMER_INT;
byteout(cs->hw.elsa.ctrl, cs->hw.elsa.ctrl_reg);
- cs->hw.elsa.status &= ~ELSA_TIMER_AKTIV;
+ cs->hw.elsa.status &= ~ELIRQF_TIMER_AKTIV;
spin_unlock_irqrestore(&cs->lock, flags);
printk(KERN_INFO "Elsa: %d timer tics in 110 msek\n",
cs->hw.elsa.counter);
@@ -1013,7 +1012,7 @@ setup_elsa(struct IsdnCard *card)
cs->hw.elsa.timer = 0;
cs->hw.elsa.trig = 0;
cs->hw.elsa.ctrl = 0;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
printk(KERN_INFO
"Elsa: %s defined at %#lx IRQ %d\n",
Elsa_Types[cs->subtyp],
@@ -1062,7 +1061,7 @@ setup_elsa(struct IsdnCard *card)
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
cs->hw.elsa.timer = 0;
cs->hw.elsa.trig = 0;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
printk(KERN_INFO
"Elsa: %s defined at %#lx/0x%x IRQ %d\n",
Elsa_Types[cs->subtyp],
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 898ec091619..0279fb323cb 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -7,7 +7,6 @@
*
*/
-#include <linux/config.h>
#include <linux/serial.h>
#include <linux/serial_reg.h>
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index 3341cf15553..76c7d29d1b2 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -60,7 +60,6 @@
*/
-#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "isdnl1.h"
@@ -302,10 +301,10 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
-static struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __devinitdata = NULL;
/* called by config.c */
-int __init
+int __devinit
setup_enternow_pci(struct IsdnCard *card)
{
int bytecnt;
@@ -406,7 +405,7 @@ setup_enternow_pci(struct IsdnCard *card)
cs->BC_Send_Data = &netjet_fill_dma;
cs->cardmsg = &enpci_card_msg;
cs->irq_func = &enpci_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
return (1);
}
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 60b04c6d9e7..fe293726777 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -485,7 +484,7 @@ reserve_regions(struct IsdnCard *card, struct IsdnCardState *cs)
return 1;
}
-static int __init
+static int __devinit
setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
{
printk(KERN_INFO "Gazel: ISA PnP card automatic recognition\n");
@@ -533,9 +532,9 @@ setup_gazelisa(struct IsdnCard *card, struct IsdnCardState *cs)
return (0);
}
-static struct pci_dev *dev_tel __initdata = NULL;
+static struct pci_dev *dev_tel __devinitdata = NULL;
-static int __init
+static int __devinit
setup_gazelpci(struct IsdnCardState *cs)
{
u_int pci_ioaddr0 = 0, pci_ioaddr1 = 0;
@@ -593,7 +592,7 @@ setup_gazelpci(struct IsdnCardState *cs)
cs->hw.gazel.hscxfifo[0] = cs->hw.gazel.hscx[0];
cs->hw.gazel.hscxfifo[1] = cs->hw.gazel.hscx[1];
cs->irq = pci_irq;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
switch (seekcard) {
case PCI_DEVICE_ID_PLX_R685:
@@ -622,7 +621,7 @@ setup_gazelpci(struct IsdnCardState *cs)
return (0);
}
-int __init
+int __devinit
setup_gazel(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index e3866b0a97f..3a5ca8a68fc 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -22,7 +22,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -1553,7 +1552,7 @@ setup_instance(hfc4s8s_hw * hw)
INIT_WORK(&hw->tqueue, (void *) (void *) hfc4s8s_bh, hw);
if (request_irq
- (hw->irq, hfc4s8s_interrupt, SA_SHIRQ, hw->card_name, hw)) {
+ (hw->irq, hfc4s8s_interrupt, IRQF_SHARED, hw->card_name, hw)) {
printk(KERN_INFO
"HFC-4S/8S: unable to alloc irq %d, card ignored\n",
hw->irq);
@@ -1704,7 +1703,7 @@ hfc4s8s_module_init(void)
/* driver module exit : */
/* release the HFC-4s/8s hardware */
/*************************************/
-static void
+static void __exit
hfc4s8s_module_exit(void)
{
pci_unregister_driver(&hfc4s8s_driver);
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 637a261c931..6360e821472 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -1015,7 +1015,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
{
}
-static unsigned int __init
+static unsigned int
*init_send_hfcd(int cnt)
{
int i, *send;
@@ -1030,7 +1030,7 @@ static unsigned int __init
return(send);
}
-void __init
+void
init2bds0(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_hfcd;
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index c964539cc43..d0520ad3067 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -551,7 +551,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
return (0);
}
-static void __init
+static void
init_send(struct BCState *bcs)
{
int i;
@@ -565,7 +565,7 @@ init_send(struct BCState *bcs)
bcs->hw.hfc.send[i] = 0x1fff;
}
-void __init
+void
inithfc(struct IsdnCardState *cs)
{
init_send(&cs->bcs[0]);
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 91d25acb5ed..1df60ca9481 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -16,7 +16,6 @@
*/
#include <linux/init.h>
-#include <linux/config.h>
#include "hisax.h"
#include "hfc_pci.h"
#include "isdnl1.h"
@@ -1582,7 +1581,7 @@ hfcpci_bh(struct IsdnCardState *cs)
/********************************/
/* called for card init message */
/********************************/
-static void __init
+static void
inithfcpci(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_2b;
@@ -1639,11 +1638,11 @@ hfcpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
/* this variable is used as card index when more than one cards are present */
-static struct pci_dev *dev_hfcpci __initdata = NULL;
+static struct pci_dev *dev_hfcpci __devinitdata = NULL;
#endif /* CONFIG_PCI */
-int __init
+int __devinit
setup_hfcpci(struct IsdnCard *card)
{
u_long flags;
@@ -1688,7 +1687,7 @@ setup_hfcpci(struct IsdnCard *card)
printk(KERN_WARNING "HFC-PCI: No IRQ for PCI card found\n");
return (0);
}
- cs->hw.hfcpci.pci_io = (char *) dev_hfcpci->resource[ 1].start;
+ cs->hw.hfcpci.pci_io = (char *)(unsigned long)dev_hfcpci->resource[1].start;
printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n", id_list[i].vendor_name, id_list[i].card_name);
} else {
printk(KERN_WARNING "HFC-PCI: No PCI card found\n");
@@ -1733,7 +1732,7 @@ setup_hfcpci(struct IsdnCard *card)
cs->BC_Read_Reg = NULL;
cs->BC_Write_Reg = NULL;
cs->irq_func = &hfcpci_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
cs->hw.hfcpci.timer.function = (void *) hfcpci_Timer;
cs->hw.hfcpci.timer.data = (long) cs;
init_timer(&cs->hw.hfcpci.timer);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index 262c4412741..b5e571a5269 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -32,7 +32,6 @@
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/timer.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel_stat.h>
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
index ec52c1a7c22..6349367ed48 100644
--- a/drivers/isdn/hisax/hfc_usb.h
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -137,11 +137,11 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
{-ENXIO, "URB already queued"},
{-EFBIG, "Too much ISO frames requested"},
{-ENOSR, "Buffer error (overrun)"},
- {-EPIPE, "Specified endpoint is stalled (device not responding)"},
+ {-EPIPE, "Specified endpoint is stalled"},
{-EOVERFLOW, "Babble (bad cable?)"},
{-EPROTO, "Bit-stuff error (bad cable?)"},
- {-EILSEQ, "CRC/Timeout"},
- {-ETIMEDOUT, "NAK (device does not respond)"},
+ {-EILSEQ, "CRC or missing token"},
+ {-ETIME, "Device did not respond"},
{-ESHUTDOWN, "Device unplugged"},
{-1, NULL}
};
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 86ab1c13f6b..4e7f472877e 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -139,7 +139,7 @@ hfcs_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id hfc_ids[] __initdata = {
+static struct isapnp_device_id hfc_ids[] __devinitdata = {
{ ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
ISAPNP_VENDOR('A', 'N', 'X'), ISAPNP_FUNCTION(0x1114),
(unsigned long) "Acer P10" },
@@ -164,11 +164,11 @@ static struct isapnp_device_id hfc_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &hfc_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &hfc_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_hfcs(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 11fe537e2f6..75920aa0a3c 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -6,7 +6,6 @@
* of the GNU General Public License, incorporated herein by reference.
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
diff --git a/drivers/isdn/hisax/hisax_debug.h b/drivers/isdn/hisax/hisax_debug.h
index ba518a7a7fb..ceafecdb103 100644
--- a/drivers/isdn/hisax/hisax_debug.h
+++ b/drivers/isdn/hisax/hisax_debug.h
@@ -22,7 +22,6 @@
#ifndef __HISAX_DEBUG_H__
#define __HISAX_DEBUG_H__
-#include <linux/config.h>
#ifdef CONFIG_HISAX_DEBUG
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index dbcca287ee2..1d7cf3bd6aa 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -725,11 +725,11 @@ static int __devinit fcpcipnp_setup(struct fritz_adapter *adapter)
switch (adapter->type) {
case AVM_FRITZ_PCIV2:
- retval = request_irq(adapter->irq, fcpci2_irq, SA_SHIRQ,
+ retval = request_irq(adapter->irq, fcpci2_irq, IRQF_SHARED,
"fcpcipnp", adapter);
break;
case AVM_FRITZ_PCI:
- retval = request_irq(adapter->irq, fcpci_irq, SA_SHIRQ,
+ retval = request_irq(adapter->irq, fcpci_irq, IRQF_SHARED,
"fcpcipnp", adapter);
break;
case AVM_FRITZ_PNP:
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index c615752b96a..2cf7b665609 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -24,10 +24,10 @@
#define DBUSY_TIMER_VALUE 80
#define ARCOFI_USE 0
-static char *ICCVer[] __initdata =
+static char *ICCVer[] =
{"2070 A1/A3", "2070 B1", "2070 B2/B3", "2070 V2.4"};
-void __init
+void
ICCVersion(struct IsdnCardState *cs, char *s)
{
int val;
@@ -613,7 +613,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
}
}
-void __init
+void
initicc(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_icc;
@@ -646,7 +646,7 @@ initicc(struct IsdnCardState *cs)
ph_command(cs, ICC_CMD_DI);
}
-void __init
+void
clear_pending_icc_ints(struct IsdnCardState *cs)
{
int val, eval;
diff --git a/drivers/isdn/hisax/icc.h b/drivers/isdn/hisax/icc.h
index b3bb3d5de53..e7f593967e4 100644
--- a/drivers/isdn/hisax/icc.h
+++ b/drivers/isdn/hisax/icc.h
@@ -65,7 +65,7 @@
#define ICC_IND_AIL 0xE
#define ICC_IND_DC 0xF
-extern void __init ICCVersion(struct IsdnCardState *cs, char *s);
+extern void ICCVersion(struct IsdnCardState *cs, char *s);
extern void initicc(struct IsdnCardState *cs);
extern void icc_interrupt(struct IsdnCardState *cs, u_char val);
extern void clear_pending_icc_ints(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index 2e9afae1254..00afd553890 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -10,7 +10,6 @@
*
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax_if.h"
#include "hisax.h"
@@ -39,8 +38,8 @@ static void dbusy_timer_handler(struct IsdnCardState *cs);
static void dch_empty_fifo(struct IsdnCardState *cs, int count);
static void dch_fill_fifo(struct IsdnCardState *cs);
static inline void dch_int(struct IsdnCardState *cs);
-static void __devinit dch_setstack(struct PStack *st, struct IsdnCardState *cs);
-static void __devinit dch_init(struct IsdnCardState *cs);
+static void dch_setstack(struct PStack *st, struct IsdnCardState *cs);
+static void dch_init(struct IsdnCardState *cs);
static void bch_l2l1(struct PStack *st, int pr, void *arg);
static void bch_empty_fifo(struct BCState *bcs, int count);
static void bch_fill_fifo(struct BCState *bcs);
@@ -49,8 +48,8 @@ static void bch_mode(struct BCState *bcs, int mode, int bc);
static void bch_close_state(struct BCState *bcs);
static int bch_open_state(struct IsdnCardState *cs, struct BCState *bcs);
static int bch_setstack(struct PStack *st, struct BCState *bcs);
-static void __devinit bch_init(struct IsdnCardState *cs, int hscx);
-static void __init clear_pending_ints(struct IsdnCardState *cs);
+static void bch_init(struct IsdnCardState *cs, int hscx);
+static void clear_pending_ints(struct IsdnCardState *cs);
//----------------------------------------------------------
// Issue Layer 1 command to chip
@@ -409,7 +408,7 @@ dch_int(struct IsdnCardState *cs)
//----------------------------------------------------------
//----------------------------------------------------------
-static void __devinit
+static void
dch_setstack(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = dch_l2l1;
@@ -417,7 +416,7 @@ dch_setstack(struct PStack *st, struct IsdnCardState *cs)
//----------------------------------------------------------
//----------------------------------------------------------
-static void __devinit
+static void
dch_init(struct IsdnCardState *cs)
{
printk(KERN_INFO "HiSax: IPACX ISDN driver v0.1.0\n");
@@ -824,7 +823,7 @@ bch_setstack(struct PStack *st, struct BCState *bcs)
//----------------------------------------------------------
//----------------------------------------------------------
-static void __devinit
+static void
bch_init(struct IsdnCardState *cs, int hscx)
{
cs->bcs[hscx].BC_SetStack = bch_setstack;
@@ -862,7 +861,7 @@ interrupt_ipacx(struct IsdnCardState *cs)
//----------------------------------------------------------
// Clears chip interrupt status
//----------------------------------------------------------
-static void __init
+static void
clear_pending_ints(struct IsdnCardState *cs)
{
int ista;
@@ -884,7 +883,7 @@ clear_pending_ints(struct IsdnCardState *cs)
// Does chip configuration work
// Work to do depends on bit mask in part
//----------------------------------------------------------
-void __init
+void
init_ipacx(struct IsdnCardState *cs, int part)
{
if (part &1) { // initialise chip
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index c9917cd2132..281fa27d9f0 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#include "hisax.h"
#include "isdnl3.h"
-#include <linux/config.h>
const char *l3_revision = "$Revision: 2.22.2.3 $";
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index 33747afc984..715a1a8cd69 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -196,10 +196,10 @@ isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
}
#ifdef __ISAPNP__
-static struct pnp_card *pnp_c __initdata = NULL;
+static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_isurf(struct IsdnCard *card)
{
int ver;
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index 908a7e14442..39717506c67 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -210,7 +210,7 @@ ix1_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
#ifdef __ISAPNP__
-static struct isapnp_device_id itk_ids[] __initdata = {
+static struct isapnp_device_id itk_ids[] __devinitdata = {
{ ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
ISAPNP_VENDOR('I', 'T', 'K'), ISAPNP_FUNCTION(0x25),
(unsigned long) "ITK micro 2" },
@@ -220,12 +220,12 @@ static struct isapnp_device_id itk_ids[] __initdata = {
{ 0, }
};
-static struct isapnp_device_id *ipid __initdata = &itk_ids[0];
+static struct isapnp_device_id *ipid __devinitdata = &itk_ids[0];
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_ix1micro(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index 2659fecc267..43d61d1bc5b 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -19,7 +19,7 @@
#include <linux/interrupt.h>
-int __init
+int
JadeVersion(struct IsdnCardState *cs, char *s)
{
int ver,i;
@@ -253,7 +253,7 @@ setstack_jade(struct PStack *st, struct BCState *bcs)
return (0);
}
-void __init
+void
clear_pending_jade_ints(struct IsdnCardState *cs)
{
int val;
@@ -279,7 +279,7 @@ clear_pending_jade_ints(struct IsdnCardState *cs)
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
}
-void __init
+void
initjade(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_jade;
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index e96845cdd4f..99feae8b921 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -23,7 +23,6 @@
#include "isdnl3.h"
#include "l3dss1.h"
#include <linux/ctype.h>
-#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
static const char *dss1_revision = "$Revision: 2.32.2.3 $";
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
index fe11f226b28..8c82519593a 100644
--- a/drivers/isdn/hisax/mic.c
+++ b/drivers/isdn/hisax/mic.c
@@ -189,7 +189,7 @@ mic_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_mic(struct IsdnCard *card)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 47a47ef0968..38f648f9b0e 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -909,7 +909,7 @@ setstack_tiger(struct PStack *st, struct BCState *bcs)
}
-void __init
+void
inittiger(struct IsdnCardState *cs)
{
if (!(cs->bcs[0].hw.tiger.send = kmalloc(NETJET_DMA_TXSIZE * sizeof(unsigned int),
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 68a2159cbd1..489022bdef7 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -14,7 +14,6 @@
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -233,12 +232,12 @@ niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *niccy_dev __initdata = NULL;
+static struct pci_dev *niccy_dev __devinitdata = NULL;
#ifdef __ISAPNP__
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __init
+int __devinit
setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -337,7 +336,7 @@ setup_niccy(struct IsdnCard *card)
printk(KERN_WARNING "Niccy: No PCI card found\n");
return(0);
}
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
cs->hw.niccy.isac_ale = pci_ioaddr + ISAC_PCI_ADDR;
cs->hw.niccy.hscx = pci_ioaddr + HSCX_PCI_DATA;
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index a7d3cd3f36f..80025fd890f 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -149,9 +148,9 @@ NETjet_S_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __devinitdata = NULL;
-int __init
+int __devinit
setup_netjet_s(struct IsdnCard *card)
{
int bytecnt,cfg;
@@ -272,7 +271,7 @@ setup_netjet_s(struct IsdnCard *card)
setup_isac(cs);
cs->cardmsg = &NETjet_S_card_msg;
cs->irq_func = &netjet_s_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "NETjet-S:");
return (1);
}
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 1ae7cac98a8..37497162d53 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "icc.h"
@@ -129,9 +128,9 @@ NETjet_U_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_netjet __initdata = NULL;
+static struct pci_dev *dev_netjet __devinitdata = NULL;
-int __init
+int __devinit
setup_netjet_u(struct IsdnCard *card)
{
int bytecnt;
@@ -238,7 +237,7 @@ setup_netjet_u(struct IsdnCard *card)
cs->BC_Send_Data = &netjet_fill_dma;
cs->cardmsg = &NETjet_U_card_msg;
cs->irq_func = &netjet_u_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
ICCVersion(cs, "NETspider-U:");
return (1);
}
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index abecabf8c27..aacbf0d14b6 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1402,12 +1402,12 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
}
/* No, locate it in the table */
if (cset == 0) {
- for (i = 0; i < IESIZE; i++)
+ for (i = 0; i < IESIZE_NI1; i++)
if (*buf == ielist_ni1[i].nr)
break;
/* When not found, give appropriate msg */
- if (i != IESIZE) {
+ if (i != IESIZE_NI1) {
dp += sprintf(dp, " %s\n", ielist_ni1[i].descr);
dp += ielist_ni1[i].f(dp, buf);
} else
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
index 7b63085ea6e..e76042d323e 100644
--- a/drivers/isdn/hisax/s0box.c
+++ b/drivers/isdn/hisax/s0box.c
@@ -211,7 +211,7 @@ S0Box_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_s0box(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index 821776e1561..d943d365890 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -241,7 +241,7 @@ saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
-int __init
+int __devinit
setup_saphir(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 8c044a6a7fe..8d8e8a29989 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -39,7 +39,6 @@
*/
#include <linux/init.h>
-#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
@@ -633,7 +632,7 @@ setup_sedlbauer(struct IsdnCard *card)
printk(KERN_WARNING "Sedlbauer: No PCI card found\n");
return(0);
}
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
cs->hw.sedl.bus = SEDL_BUS_PCI;
sub_vendor_id = dev_sedl->subsystem_vendor;
sub_id = dev_sedl->subsystem_device;
@@ -810,7 +809,7 @@ ready:
cs->hw.sedl.hscx = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_HSCX;
cs->hw.sedl.reset_on = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
cs->hw.sedl.reset_off = cs->hw.sedl.cfg_reg + SEDL_HSCX_PCMCIA_RESET;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
} else {
cs->hw.sedl.adr = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ADR;
cs->hw.sedl.isac = cs->hw.sedl.cfg_reg + SEDL_HSCX_ISA_ISAC;
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 9bb18f3f782..f9c14a2970b 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -164,7 +164,7 @@ static int sedlbauer_probe(struct pcmcia_device *link)
link->priv = local;
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index cdf35dc564c..a49b694eb73 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -184,7 +184,7 @@ Sportster_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static int __init
+static int __devinit
get_io_range(struct IsdnCardState *cs)
{
int i, j, adr;
@@ -209,7 +209,7 @@ get_io_range(struct IsdnCardState *cs)
}
}
-int __init
+int __devinit
setup_sportster(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index 9ffaae7c657..04416bad611 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -13,7 +13,6 @@
#ifndef _ST5481_H_
#define _ST5481_H_
-#include <linux/config.h>
// USB IDs, the Product Id is in the range 0x4810-0x481F
diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c
index 99cb0f3d59a..2716aa5c60f 100644
--- a/drivers/isdn/hisax/st5481_init.c
+++ b/drivers/isdn/hisax/st5481_init.c
@@ -24,7 +24,6 @@
* clean up debug
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index a2b1816af37..e94dc6f5bd6 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -261,7 +261,7 @@ TeleInt_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_TeleInt(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 2b7df8f9823..f94af0930a1 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -265,7 +265,7 @@ Teles_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-int __init
+int __devinit
setup_teles0(struct IsdnCard *card)
{
u_char val;
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index a3eaf4d6570..5cb712437da 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -369,6 +369,7 @@ setup_teles3(struct IsdnCard *card)
cs->hw.teles3.hscx[1] + 96);
return (0);
}
+ cs->irq_flags |= IRQF_SHARED; /* cardbus can share */
} else {
if (cs->hw.teles3.cfg_reg) {
if (cs->typ == ISDN_CTYPE_COMPAQ_ISA) {
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index e2bb4fd8e25..dca446865f2 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -13,7 +13,6 @@
*/
#include <linux/init.h>
-#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
@@ -285,9 +284,9 @@ TelesPCI_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return(0);
}
-static struct pci_dev *dev_tel __initdata = NULL;
+static struct pci_dev *dev_tel __devinitdata = NULL;
-int __init
+int __devinit
setup_telespci(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -311,8 +310,9 @@ setup_telespci(struct IsdnCard *card)
}
cs->hw.teles0.membase = ioremap(pci_resource_start(dev_tel, 0),
PAGE_SIZE);
- printk(KERN_INFO "Found: Zoran, base-address: 0x%lx, irq: 0x%x\n",
- pci_resource_start(dev_tel, 0), dev_tel->irq);
+ printk(KERN_INFO "Found: Zoran, base-address: 0x%llx, irq: 0x%x\n",
+ (unsigned long long)pci_resource_start(dev_tel, 0),
+ dev_tel->irq);
} else {
printk(KERN_WARNING "TelesPCI: No PCI card found\n");
return(0);
@@ -347,7 +347,7 @@ setup_telespci(struct IsdnCard *card)
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &TelesPCI_card_msg;
cs->irq_func = &telespci_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
ISACVersion(cs, "TelesPCI:");
if (HscxVersion(cs, "TelesPCI:")) {
printk(KERN_WARNING
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 0352ee5f706..0595293b865 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include "hisax.h"
#include "w6692.h"
@@ -45,11 +44,11 @@ static const char *w6692_revision = "$Revision: 1.18.2.4 $";
#define DBUSY_TIMER_VALUE 80
-static char *W6692Ver[] __initdata =
+static char *W6692Ver[] =
{"W6692 V00", "W6692 V01", "W6692 V10",
"W6692 V11"};
-static void __init
+static void
W6692Version(struct IsdnCardState *cs, char *s)
{
int val;
@@ -898,7 +897,7 @@ static void resetW6692(struct IsdnCardState *cs)
}
}
-static void __init initW6692(struct IsdnCardState *cs, int part)
+static void initW6692(struct IsdnCardState *cs, int part)
{
if (part & 1) {
cs->setstack_d = setstack_W6692;
@@ -993,9 +992,9 @@ w6692_card_msg(struct IsdnCardState *cs, int mt, void *arg)
static int id_idx ;
-static struct pci_dev *dev_w6692 __initdata = NULL;
+static struct pci_dev *dev_w6692 __devinitdata = NULL;
-int __init
+int __devinit
setup_w6692(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
@@ -1081,7 +1080,7 @@ setup_w6692(struct IsdnCard *card)
cs->BC_Send_Data = &W6692B_fill_fifo;
cs->cardmsg = &w6692_card_msg;
cs->irq_func = &W6692_interrupt;
- cs->irq_flags |= SA_SHIRQ;
+ cs->irq_flags |= IRQF_SHARED;
W6692Version(cs, "W6692:");
printk(KERN_INFO "W6692 ISTA=0x%X\n", ReadW6692(cs, W_ISTA));
printk(KERN_INFO "W6692 IMASK=0x%X\n", ReadW6692(cs, W_IMASK));
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 48d134be990..73afebdf80b 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/kernel.h>
@@ -436,7 +435,7 @@ ergo_inithardware(hysdn_card * card)
}
ergo_stopcard(card); /* disable interrupts */
- if (request_irq(card->irq, ergo_interrupt, SA_SHIRQ, "HYSDN", card)) {
+ if (request_irq(card->irq, ergo_interrupt, IRQF_SHARED, "HYSDN", card)) {
ergo_releasehardware(card); /* return the acquired hardware */
return (-1);
}
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
index 3a9b29b38bc..461e831592d 100644
--- a/drivers/isdn/hysdn/hysdn_defs.h
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -14,7 +14,6 @@
#ifndef HYSDN_DEFS_H
#define HYSDN_DEFS_H
-#include <linux/config.h>
#include <linux/hysdn_if.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index b75ac5af236..b702ed27252 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/poll.h>
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
index 133032920ff..1c0d54ac12a 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/kernel.h>
diff --git a/drivers/isdn/i4l/Kconfig b/drivers/isdn/i4l/Kconfig
index a4f7288a1fc..3ef567b99c7 100644
--- a/drivers/isdn/i4l/Kconfig
+++ b/drivers/isdn/i4l/Kconfig
@@ -5,6 +5,7 @@
config ISDN_PPP
bool "Support synchronous PPP"
depends on INET
+ select SLHC
help
Over digital connections such as ISDN, there is no need to
synchronize sender and recipient's clocks with start and stop bits
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index 81accdf3516..c3d79eef9e3 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/poll.h>
@@ -340,6 +339,16 @@ isdn_command(isdn_ctrl *cmd)
printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
return(1);
}
+ if (!dev->drv[cmd->driver]) {
+ printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
+ cmd->command, cmd->driver);
+ return(1);
+ }
+ if (!dev->drv[cmd->driver]->interface) {
+ printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
+ cmd->command, cmd->driver);
+ return(1);
+ }
if (cmd->command == ISDN_CMD_SETL2) {
int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
unsigned long l2prot = (cmd->arg >> 8) & 255;
@@ -933,7 +942,7 @@ isdn_readbchan_tty(int di, int channel, struct tty_struct *tty, int cisco_hack)
count_put = count_pull;
if(count_put > 1)
tty_insert_flip_string(tty, skb->data, count_put - 1);
- last = skb->data[count_put] - 1;
+ last = skb->data[count_put - 1];
len -= count_put;
#ifdef CONFIG_ISDN_AUDIO
}
@@ -1050,7 +1059,7 @@ isdn_info_update(void)
static ssize_t
isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
{
- uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ uint minor = iminor(file->f_dentry->d_inode);
int len = 0;
int drvidx;
int chidx;
@@ -1154,7 +1163,7 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
static ssize_t
isdn_write(struct file *file, const char __user *buf, size_t count, loff_t * off)
{
- uint minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ uint minor = iminor(file->f_dentry->d_inode);
int drvidx;
int chidx;
int retval;
@@ -1216,7 +1225,7 @@ static unsigned int
isdn_poll(struct file *file, poll_table * wait)
{
unsigned int mask = 0;
- unsigned int minor = MINOR(file->f_dentry->d_inode->i_rdev);
+ unsigned int minor = iminor(file->f_dentry->d_inode);
int drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
lock_kernel();
@@ -1257,7 +1266,7 @@ isdn_poll(struct file *file, poll_table * wait)
static int
isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
{
- uint minor = MINOR(inode->i_rdev);
+ uint minor = iminor(inode);
isdn_ctrl c;
int drvidx;
int chidx;
@@ -1708,7 +1717,7 @@ isdn_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg)
static int
isdn_open(struct inode *ino, struct file *filep)
{
- uint minor = MINOR(ino->i_rdev);
+ uint minor = iminor(ino);
int drvidx;
int chidx;
int retval = -ENODEV;
@@ -1770,7 +1779,7 @@ isdn_open(struct inode *ino, struct file *filep)
static int
isdn_close(struct inode *ino, struct file *filep)
{
- uint minor = MINOR(ino->i_rdev);
+ uint minor = iminor(ino);
lock_kernel();
if (minor == ISDN_MINOR_STATUS) {
@@ -1903,6 +1912,11 @@ isdn_free_channel(int di, int ch, int usage)
{
int i;
+ if ((di < 0) || (ch < 0)) {
+ printk(KERN_WARNING "%s: called with invalid drv(%d) or channel(%d)\n",
+ __FUNCTION__, di, ch);
+ return;
+ }
for (i = 0; i < ISDN_MAX_CHANNELS; i++)
if (((!usage) || ((dev->usage[i] & ISDN_USAGE_MASK) == usage)) &&
(dev->drvmap[i] == di) &&
@@ -1918,7 +1932,8 @@ isdn_free_channel(int di, int ch, int usage)
dev->v110[i] = NULL;
// 20.10.99 JIM, try to reinitialize v110 !
isdn_info_update();
- skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
+ if (dev->drv[di])
+ skb_queue_purge(&dev->drv[di]->rpqueue[ch]);
}
}
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 96c115e1338..1f8d6ae66b4 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -22,7 +22,6 @@
* http://i4l.zabbadoz.net/i4l/cisco-hdlc.txt
*/
-#include <linux/config.h>
#include <linux/isdn.h>
#include <net/arp.h>
#include <net/dst.h>
@@ -1615,8 +1614,8 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
struct sk_buff *skb;
unsigned char *p;
struct in_device *in_dev = NULL;
- u32 addr = 0; /* local ipv4 address */
- u32 mask = 0; /* local netmask */
+ __be32 addr = 0; /* local ipv4 address */
+ __be32 mask = 0; /* local netmask */
if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c
index 918742271c7..119412d6bd1 100644
--- a/drivers/isdn/i4l/isdn_ppp.c
+++ b/drivers/isdn/i4l/isdn_ppp.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/isdn.h>
#include <linux/poll.h>
#include <linux/ppp-comp.h>
@@ -668,7 +667,7 @@ isdn_ppp_poll(struct file *file, poll_table * wait)
if (is->debug & 0x2)
printk(KERN_DEBUG "isdn_ppp_poll: minor: %d\n",
- MINOR(file->f_dentry->d_inode->i_rdev));
+ iminor(file->f_dentry->d_inode));
/* just registers wait_queue hook. This doesn't really wait. */
poll_wait(file, &is->wq, wait);
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 2ac90242d26..9ab66e8960d 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -11,7 +11,6 @@
*/
#undef ISDN_TTY_STAT_DEBUG
-#include <linux/config.h>
#include <linux/isdn.h>
#include <linux/delay.h>
#include "isdn_common.h"
@@ -82,7 +81,7 @@ isdn_tty_try_read(modem_info * info, struct sk_buff *skb)
int l = skb->len;
unsigned char *dp = skb->data;
while (--l) {
- if (*skb->data == DLE)
+ if (*dp == DLE)
tty_insert_flip_char(tty, DLE, 0);
tty_insert_flip_char(tty, *dp++, 0);
}
@@ -1890,14 +1889,13 @@ isdn_tty_modem_init(void)
if (!m->tty_modem)
return -ENOMEM;
m->tty_modem->name = "ttyI";
- m->tty_modem->devfs_name = "isdn/ttyI";
m->tty_modem->major = ISDN_TTY_MAJOR;
m->tty_modem->minor_start = 0;
m->tty_modem->type = TTY_DRIVER_TYPE_SERIAL;
m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
m->tty_modem->init_termios = tty_std_termios;
m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
m->tty_modem->driver_name = "isdn_tty";
tty_set_operations(m->tty_modem, &modem_ops);
retval = tty_register_driver(m->tty_modem);
diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
index 9f0fa9501f4..692c74d6b74 100644
--- a/drivers/isdn/i4l/isdn_tty.h
+++ b/drivers/isdn/i4l/isdn_tty.h
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#define DLE 0x10
#define ETX 0x03
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
index 743ac4077f3..8b3efc24316 100644
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ b/drivers/isdn/i4l/isdn_x25iface.c
@@ -208,7 +208,7 @@ static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb
*/
static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
{
- struct sk_buff * skb = dev_alloc_skb(1);
+ struct sk_buff * skb;
enum wan_states *state_p
= &( ( (ix25_pdata_t*) (cprot->proto_data) ) -> state);
IX25DEBUG( "isdn_x25iface_connect_ind %s \n"
@@ -220,6 +220,8 @@ static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
return -1;
}
*state_p = WAN_CONNECTED;
+
+ skb = dev_alloc_skb(1);
if( skb ){
*( skb_put(skb, 1) ) = 0x01;
skb->protocol = x25_type_trans(skb, cprot->net_dev);
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index a67d31af797..fabbd461603 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index 62b7acfad8a..a627e68023f 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -342,7 +342,7 @@ static int __init sc_init(void)
*/
sc_adapter[cinst]->interrupt = irq[b];
if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler,
- SA_INTERRUPT, interface->id, NULL))
+ IRQF_DISABLED, interface->id, NULL))
{
kfree(sc_adapter[cinst]->channel);
indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index f573d5af0b1..9c39b98d5a5 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -69,6 +69,13 @@ config LEDS_AMS_DELTA
help
This option enables support for the LEDs on Amstrad Delta (E3).
+config LEDS_NET48XX
+ tristate "LED Support for Soekris net48xx series Error LED"
+ depends on LEDS_CLASS && SCx200_GPIO
+ help
+ This option enables support for the Soekris net4801 and net4826 error
+ LED.
+
comment "LED Triggers"
config LEDS_TRIGGERS
@@ -93,5 +100,14 @@ config LEDS_TRIGGER_IDE_DISK
This allows LEDs to be controlled by IDE disk activity.
If unsure, say Y.
+config LEDS_TRIGGER_HEARTBEAT
+ tristate "LED Heartbeat Trigger"
+ depends LEDS_TRIGGERS
+ help
+ This allows LEDs to be controlled by a CPU load average.
+ The flash frequency is a hyperbolic function of the 1-minute
+ load average.
+ If unsure, say Y.
+
endmenu
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index dcea1001faa..6aa2aed7539 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -12,7 +12,9 @@ obj-$(CONFIG_LEDS_IXP4XX) += leds-ixp4xx-gpio.o
obj-$(CONFIG_LEDS_TOSA) += leds-tosa.o
obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
+obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
# LED Triggers
obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += ledtrig-ide-disk.o
+obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index c75d0ef1609..d424b445202 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index fe6541326c7..9b015f9af35 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -18,7 +18,7 @@
#include <linux/leds.h>
#include "leds.h"
-rwlock_t leds_list_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(leds_list_lock);
LIST_HEAD(leds_list);
EXPORT_SYMBOL_GPL(leds_list);
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 5e2cd8be119..47f0ff19632 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -26,7 +25,7 @@
/*
* Nests outside led_cdev->trigger_lock
*/
-static rwlock_t triggers_list_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(triggers_list_lock);
static LIST_HEAD(trigger_list);
ssize_t led_trigger_store(struct class_device *dev, const char *buf,
diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c
index bb7d84df012..cf1dcd719a2 100644
--- a/drivers/leds/leds-corgi.c
+++ b/drivers/leds/leds-corgi.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-ixp4xx-gpio.c b/drivers/leds/leds-ixp4xx-gpio.c
index 30ced150e4c..7dcf0b92c46 100644
--- a/drivers/leds/leds-ixp4xx-gpio.c
+++ b/drivers/leds/leds-ixp4xx-gpio.c
@@ -31,7 +31,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 8419e29b71f..3b87951aa55 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -8,7 +8,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
new file mode 100644
index 00000000000..45ba3d45bcb
--- /dev/null
+++ b/drivers/leds/leds-net48xx.c
@@ -0,0 +1,115 @@
+/*
+ * LEDs driver for Soekris net48xx
+ *
+ * Copyright (C) 2006 Chris Boot <bootc@bootc.net>
+ *
+ * Based on leds-ams-delta.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/nsc_gpio.h>
+#include <linux/scx200_gpio.h>
+
+#define DRVNAME "net48xx-led"
+#define NET48XX_ERROR_LED_GPIO 20
+
+static struct platform_device *pdev;
+
+static void net48xx_error_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ scx200_gpio_ops.gpio_set(NET48XX_ERROR_LED_GPIO, value ? 1 : 0);
+}
+
+static struct led_classdev net48xx_error_led = {
+ .name = "net48xx:error",
+ .brightness_set = net48xx_error_led_set,
+};
+
+#ifdef CONFIG_PM
+static int net48xx_led_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ led_classdev_suspend(&net48xx_error_led);
+ return 0;
+}
+
+static int net48xx_led_resume(struct platform_device *dev)
+{
+ led_classdev_resume(&net48xx_error_led);
+ return 0;
+}
+#else
+#define net48xx_led_suspend NULL
+#define net48xx_led_resume NULL
+#endif
+
+static int net48xx_led_probe(struct platform_device *pdev)
+{
+ return led_classdev_register(&pdev->dev, &net48xx_error_led);
+}
+
+static int net48xx_led_remove(struct platform_device *pdev)
+{
+ led_classdev_unregister(&net48xx_error_led);
+ return 0;
+}
+
+static struct platform_driver net48xx_led_driver = {
+ .probe = net48xx_led_probe,
+ .remove = net48xx_led_remove,
+ .suspend = net48xx_led_suspend,
+ .resume = net48xx_led_resume,
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init net48xx_led_init(void)
+{
+ int ret;
+
+ /* small hack, but scx200_gpio doesn't set .dev if the probe fails */
+ if (!scx200_gpio_ops.dev) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ ret = platform_driver_register(&net48xx_led_driver);
+ if (ret < 0)
+ goto out;
+
+ pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
+ if (IS_ERR(pdev)) {
+ ret = PTR_ERR(pdev);
+ platform_driver_unregister(&net48xx_led_driver);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+static void __exit net48xx_led_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&net48xx_led_driver);
+}
+
+module_init(net48xx_led_init);
+module_exit(net48xx_led_exit);
+
+MODULE_AUTHOR("Chris Boot <bootc@bootc.net>");
+MODULE_DESCRIPTION("Soekris net48xx LED driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c
index 650cf72dc67..fb1edc1c9ed 100644
--- a/drivers/leds/leds-s3c24xx.c
+++ b/drivers/leds/leds-s3c24xx.c
@@ -11,7 +11,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c
index 65bbef4a5e0..126d09cc96e 100644
--- a/drivers/leds/leds-spitz.c
+++ b/drivers/leds/leds-spitz.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c
index c9e8cc1ec48..fb2416a3830 100644
--- a/drivers/leds/leds-tosa.c
+++ b/drivers/leds/leds-tosa.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/ledtrig-heartbeat.c b/drivers/leds/ledtrig-heartbeat.c
new file mode 100644
index 00000000000..4bf8cec8b8c
--- /dev/null
+++ b/drivers/leds/ledtrig-heartbeat.c
@@ -0,0 +1,118 @@
+/*
+ * LED Heartbeat Trigger
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * Based on Richard Purdie's ledtrig-timer.c and some arch's
+ * CONFIG_HEARTBEAT code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/leds.h>
+#include "leds.h"
+
+struct heartbeat_trig_data {
+ unsigned int phase;
+ unsigned int period;
+ struct timer_list timer;
+};
+
+static void led_heartbeat_function(unsigned long data)
+{
+ struct led_classdev *led_cdev = (struct led_classdev *) data;
+ struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+ unsigned long brightness = LED_OFF;
+ unsigned long delay = 0;
+
+ /* acts like an actual heart beat -- ie thump-thump-pause... */
+ switch (heartbeat_data->phase) {
+ case 0:
+ /*
+ * The hyperbolic function below modifies the
+ * heartbeat period length in dependency of the
+ * current (1min) load. It goes through the points
+ * f(0)=1260, f(1)=860, f(5)=510, f(inf)->300.
+ */
+ heartbeat_data->period = 300 +
+ (6720 << FSHIFT) / (5 * avenrun[0] + (7 << FSHIFT));
+ heartbeat_data->period =
+ msecs_to_jiffies(heartbeat_data->period);
+ delay = msecs_to_jiffies(70);
+ heartbeat_data->phase++;
+ brightness = LED_FULL;
+ break;
+ case 1:
+ delay = heartbeat_data->period / 4 - msecs_to_jiffies(70);
+ heartbeat_data->phase++;
+ break;
+ case 2:
+ delay = msecs_to_jiffies(70);
+ heartbeat_data->phase++;
+ brightness = LED_FULL;
+ break;
+ default:
+ delay = heartbeat_data->period - heartbeat_data->period / 4 -
+ msecs_to_jiffies(70);
+ heartbeat_data->phase = 0;
+ break;
+ }
+
+ led_set_brightness(led_cdev, brightness);
+ mod_timer(&heartbeat_data->timer, jiffies + delay);
+}
+
+static void heartbeat_trig_activate(struct led_classdev *led_cdev)
+{
+ struct heartbeat_trig_data *heartbeat_data;
+
+ heartbeat_data = kzalloc(sizeof(*heartbeat_data), GFP_KERNEL);
+ if (!heartbeat_data)
+ return;
+
+ led_cdev->trigger_data = heartbeat_data;
+ setup_timer(&heartbeat_data->timer,
+ led_heartbeat_function, (unsigned long) led_cdev);
+ heartbeat_data->phase = 0;
+ led_heartbeat_function(heartbeat_data->timer.data);
+}
+
+static void heartbeat_trig_deactivate(struct led_classdev *led_cdev)
+{
+ struct heartbeat_trig_data *heartbeat_data = led_cdev->trigger_data;
+
+ if (heartbeat_data) {
+ del_timer_sync(&heartbeat_data->timer);
+ kfree(heartbeat_data);
+ }
+}
+
+static struct led_trigger heartbeat_led_trigger = {
+ .name = "heartbeat",
+ .activate = heartbeat_trig_activate,
+ .deactivate = heartbeat_trig_deactivate,
+};
+
+static int __init heartbeat_trig_init(void)
+{
+ return led_trigger_register(&heartbeat_led_trigger);
+}
+
+static void __exit heartbeat_trig_exit(void)
+{
+ led_trigger_unregister(&heartbeat_led_trigger);
+}
+
+module_init(heartbeat_trig_init);
+module_exit(heartbeat_trig_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Heartbeat LED trigger");
+MODULE_LICENSE("GPL");
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index fbf141ef46e..179c2876b54 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index ccf5df44cde..d5d649f5ccd 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -78,6 +78,27 @@ config ADB_PMU
this device; you should do so if your machine is one of those
mentioned above.
+config ADB_PMU_LED
+ bool "Support for the Power/iBook front LED"
+ depends on ADB_PMU
+ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ Support the front LED on Power/iBooks as a generic LED that can
+ be triggered by any of the supported triggers. To get the
+ behaviour of the old CONFIG_BLK_DEV_IDE_PMAC_BLINK, select this
+ and the ide-disk LED trigger and configure appropriately through
+ sysfs.
+
+config ADB_PMU_LED_IDE
+ bool "Use front LED as IDE LED by default"
+ depends on ADB_PMU_LED
+ select LEDS_TRIGGERS
+ select LEDS_TRIGGER_IDE_DISK
+ help
+ This option makes the front LED default to the IDE trigger
+ so that it blinks on IDE activity.
+
config PMAC_SMU
bool "Support for SMU based PowerMacs"
depends on PPC_PMAC64
@@ -88,7 +109,7 @@ config PMAC_SMU
config PMAC_APM_EMU
tristate "APM emulation"
- depends on PPC_PMAC && PPC32 && PM
+ depends on PPC_PMAC && PPC32 && PM && ADB_PMU
config PMAC_MEDIABAY
bool "Support PowerBook hotswap media bay"
@@ -99,17 +120,23 @@ config PMAC_MEDIABAY
devices are not fully supported in the bay as I never had one to
try with
-# made a separate option since backlight may end up beeing used
-# on non-powerbook machines (but only on PMU based ones AFAIK)
config PMAC_BACKLIGHT
bool "Backlight control for LCD screens"
- depends on ADB_PMU && (BROKEN || !PPC64)
+ depends on ADB_PMU && FB = y && (BROKEN || !PPC64)
+ select FB_BACKLIGHT
+ help
+ Say Y here to enable Macintosh specific extensions of the generic
+ backlight code. With this enabled, the brightness keys on older
+ PowerBooks will be enabled so you can change the screen brightness.
+ Newer models should use an userspace daemon like pbbuttonsd.
+
+config PMAC_BACKLIGHT_LEGACY
+ bool "Provide legacy ioctl's on /dev/pmu for the backlight"
+ depends on PMAC_BACKLIGHT && (BROKEN || !PPC64)
help
- Say Y here to build in code to manage the LCD backlight on a
- Macintosh PowerBook. With this code, the backlight will be turned
- on and off appropriately on power-management and lid-open/lid-closed
- events; also, the PowerBook button device will be enabled so you can
- change the screen brightness.
+ Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for
+ programs which use this old interface. New and updated programs
+ should use the backlight classes in sysfs.
config ADB_MACIO
bool "Include MacIO (CHRP) ADB driver"
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 6081acdea40..b53d45f87b0 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -11,7 +11,9 @@ obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o
obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
obj-$(CONFIG_ANSLCD) += ans-lcd.o
-obj-$(CONFIG_ADB_PMU) += via-pmu.o
+obj-$(CONFIG_ADB_PMU) += via-pmu.o via-pmu-event.o
+obj-$(CONFIG_ADB_PMU_LED) += via-pmu-led.o
+obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o
obj-$(CONFIG_ADB_CUDA) += via-cuda.o
obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o
obj-$(CONFIG_PMAC_SMU) += smu.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 259fd8973ce..360f93f6fcd 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -16,7 +16,6 @@
* - move bus probe to a kernel thread
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -36,7 +35,6 @@
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/device.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -904,8 +902,6 @@ adbdev_init(void)
return;
}
- devfs_mk_cdev(MKDEV(ADB_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "adb");
-
adb_dev_class = class_create(THIS_MODULE, "adb");
if (IS_ERR(adb_dev_class))
return;
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index 394334ec576..efd51e01c06 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -34,7 +34,6 @@
* Move to syfs
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -47,11 +46,8 @@
#include <asm/machdep.h>
#ifdef CONFIG_PPC_PMAC
-#include <asm/pmac_feature.h>
-#endif
-
-#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
+#include <asm/pmac_feature.h>
#endif
MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>");
@@ -179,7 +175,7 @@ u8 adb_to_linux_keycodes[128] = {
/* 0x65 */ KEY_F9, /* 67 */
/* 0x66 */ KEY_HANJA, /* 123 */
/* 0x67 */ KEY_F11, /* 87 */
- /* 0x68 */ KEY_HANGUEL, /* 122 */
+ /* 0x68 */ KEY_HANGEUL, /* 122 */
/* 0x69 */ KEY_SYSRQ, /* 99 */
/* 0x6a */ 0,
/* 0x6b */ KEY_SCROLLLOCK, /* 70 */
@@ -238,11 +234,6 @@ static struct adb_ids keyboard_ids;
static struct adb_ids mouse_ids;
static struct adb_ids buttons_ids;
-#ifdef CONFIG_PMAC_BACKLIGHT
-/* Exported to via-pmu.c */
-int disable_kernel_backlight = 0;
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
/* Kind of keyboard, see Apple technote 1152 */
#define ADB_KEYBOARD_UNKNOWN 0
#define ADB_KEYBOARD_ANSI 0x0100
@@ -503,9 +494,7 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0x1f: /* Powerbook button device */
{
int down = (data[1] == (data[1] & 0xf));
-#ifdef CONFIG_PMAC_BACKLIGHT
- int backlight = get_backlight_level();
-#endif
+
/*
* XXX: Where is the contrast control for the passive?
* -- Cort
@@ -530,29 +519,17 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
case 0xa: /* brightness decrease */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight) {
- if (down && backlight >= 0) {
- if (backlight > BACKLIGHT_OFF)
- set_backlight_level(backlight-1);
- else
- set_backlight_level(BACKLIGHT_OFF);
- }
- }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ if (down)
+ pmac_backlight_key_down();
+#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSDOWN, down);
break;
case 0x9: /* brightness increase */
#ifdef CONFIG_PMAC_BACKLIGHT
- if (!disable_kernel_backlight) {
- if (down && backlight >= 0) {
- if (backlight < BACKLIGHT_MAX)
- set_backlight_level(backlight+1);
- else
- set_backlight_level(BACKLIGHT_MAX);
- }
- }
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ if (down)
+ pmac_backlight_key_up();
+#endif
input_report_key(adbhid[id]->input, KEY_BRIGHTNESSUP, down);
break;
diff --git a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c
index e5a2bbf9939..1293876a2eb 100644
--- a/drivers/macintosh/apm_emu.c
+++ b/drivers/macintosh/apm_emu.c
@@ -18,7 +18,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/poll.h>
diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c
index a66636116f0..6b129eef798 100644
--- a/drivers/macintosh/mac_hid.c
+++ b/drivers/macintosh/mac_hid.c
@@ -8,7 +8,6 @@
* This file will soon be removed in favor of an uinput userspace tool.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/sysctl.h>
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 314fc0830d9..4b08852c35e 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -90,22 +90,12 @@ int macio_init(void)
{
struct device_node *adbs;
struct resource r;
+ unsigned int irq;
adbs = find_compatible_devices("adb", "chrp,adb0");
if (adbs == 0)
return -ENXIO;
-#if 0
- { int i = 0;
-
- printk("macio_adb_init: node = %p, addrs =", adbs->node);
- while(!of_address_to_resource(adbs, i, &r))
- printk(" %x(%x)", r.start, r.end - r.start);
- printk(", intrs =");
- for (i = 0; i < adbs->n_intrs; ++i)
- printk(" %x", adbs->intrs[i].line);
- printk("\n"); }
-#endif
if (of_address_to_resource(adbs, 0, &r))
return -ENXIO;
adb = ioremap(r.start, sizeof(struct adb_regs));
@@ -117,10 +107,9 @@ int macio_init(void)
out_8(&adb->active_lo.r, 0xff);
out_8(&adb->autopoll.r, APE);
- if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
- 0, "ADB", (void *)0)) {
- printk(KERN_ERR "ADB: can't get irq %d\n",
- adbs->intrs[0].line);
+ irq = irq_of_parse_and_map(adbs, 0);
+ if (request_irq(irq, macio_adb_interrupt, 0, "ADB", (void *)0)) {
+ printk(KERN_ERR "ADB: can't get irq %d\n", irq);
return -EAGAIN;
}
out_8(&adb->intr_enb.r, DFB | TAG);
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index 431bd37225a..d5621606754 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -17,7 +17,6 @@
* sub-devices.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -140,7 +139,9 @@ static int macio_uevent(struct device *dev, char **envp, int num_envp,
{
struct macio_dev * macio_dev;
struct of_device * of;
- char *scratch, *compat, *compat2;
+ char *scratch;
+ const char *compat, *compat2;
+
int i = 0;
int length, cplen, cplen2, seen = 0;
@@ -174,7 +175,7 @@ static int macio_uevent(struct device *dev, char **envp, int num_envp,
* it's not really legal to split it out with commas. We split it
* up using a number of environment variables instead. */
- compat = (char *) get_property(of->node, "compatible", &cplen);
+ compat = get_property(of->node, "compatible", &cplen);
compat2 = compat;
cplen2= cplen;
while (compat && cplen > 0) {
@@ -281,75 +282,128 @@ static void macio_release_dev(struct device *dev)
static int macio_resource_quirks(struct device_node *np, struct resource *res,
int index)
{
- if (res->flags & IORESOURCE_MEM) {
- /* Grand Central has too large resource 0 on some machines */
- if (index == 0 && !strcmp(np->name, "gc"))
- res->end = res->start + 0x1ffff;
+ /* Only quirks for memory resources for now */
+ if ((res->flags & IORESOURCE_MEM) == 0)
+ return 0;
- /* Airport has bogus resource 2 */
- if (index >= 2 && !strcmp(np->name, "radio"))
- return 1;
+ /* Grand Central has too large resource 0 on some machines */
+ if (index == 0 && !strcmp(np->name, "gc"))
+ res->end = res->start + 0x1ffff;
+
+ /* Airport has bogus resource 2 */
+ if (index >= 2 && !strcmp(np->name, "radio"))
+ return 1;
#ifndef CONFIG_PPC64
- /* DBDMAs may have bogus sizes */
- if ((res->start & 0x0001f000) == 0x00008000)
- res->end = res->start + 0xff;
+ /* DBDMAs may have bogus sizes */
+ if ((res->start & 0x0001f000) == 0x00008000)
+ res->end = res->start + 0xff;
#endif /* CONFIG_PPC64 */
- /* ESCC parent eats child resources. We could have added a
- * level of hierarchy, but I don't really feel the need
- * for it
- */
- if (!strcmp(np->name, "escc"))
- return 1;
-
- /* ESCC has bogus resources >= 3 */
- if (index >= 3 && !(strcmp(np->name, "ch-a") &&
- strcmp(np->name, "ch-b")))
- return 1;
-
- /* Media bay has too many resources, keep only first one */
- if (index > 0 && !strcmp(np->name, "media-bay"))
- return 1;
-
- /* Some older IDE resources have bogus sizes */
- if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
- strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
- if (index == 0 && (res->end - res->start) > 0xfff)
- res->end = res->start + 0xfff;
- if (index == 1 && (res->end - res->start) > 0xff)
- res->end = res->start + 0xff;
- }
+ /* ESCC parent eats child resources. We could have added a
+ * level of hierarchy, but I don't really feel the need
+ * for it
+ */
+ if (!strcmp(np->name, "escc"))
+ return 1;
+
+ /* ESCC has bogus resources >= 3 */
+ if (index >= 3 && !(strcmp(np->name, "ch-a") &&
+ strcmp(np->name, "ch-b")))
+ return 1;
+
+ /* Media bay has too many resources, keep only first one */
+ if (index > 0 && !strcmp(np->name, "media-bay"))
+ return 1;
+
+ /* Some older IDE resources have bogus sizes */
+ if (!(strcmp(np->name, "IDE") && strcmp(np->name, "ATA") &&
+ strcmp(np->type, "ide") && strcmp(np->type, "ata"))) {
+ if (index == 0 && (res->end - res->start) > 0xfff)
+ res->end = res->start + 0xfff;
+ if (index == 1 && (res->end - res->start) > 0xff)
+ res->end = res->start + 0xff;
}
return 0;
}
+static void macio_create_fixup_irq(struct macio_dev *dev, int index,
+ unsigned int line)
+{
+ unsigned int irq;
-static void macio_setup_interrupts(struct macio_dev *dev)
+ irq = irq_create_mapping(NULL, line);
+ if (irq != NO_IRQ) {
+ dev->interrupt[index].start = irq;
+ dev->interrupt[index].flags = IORESOURCE_IRQ;
+ dev->interrupt[index].name = dev->ofdev.dev.bus_id;
+ }
+ if (dev->n_interrupts <= index)
+ dev->n_interrupts = index + 1;
+}
+
+static void macio_add_missing_resources(struct macio_dev *dev)
{
struct device_node *np = dev->ofdev.node;
- int i,j;
+ unsigned int irq_base;
+
+ /* Gatwick has some missing interrupts on child nodes */
+ if (dev->bus->chip->type != macio_gatwick)
+ return;
- /* For now, we use pre-parsed entries in the device-tree for
- * interrupt routing and addresses, but we should change that
- * to dynamically parsed entries and so get rid of most of the
- * clutter in struct device_node
+ /* irq_base is always 64 on gatwick. I have no cleaner way to get
+ * that value from here at this point
*/
- for (i = j = 0; i < np->n_intrs; i++) {
+ irq_base = 64;
+
+ /* Fix SCC */
+ if (strcmp(np->name, "ch-a") == 0) {
+ macio_create_fixup_irq(dev, 0, 15 + irq_base);
+ macio_create_fixup_irq(dev, 1, 4 + irq_base);
+ macio_create_fixup_irq(dev, 2, 5 + irq_base);
+ printk(KERN_INFO "macio: fixed SCC irqs on gatwick\n");
+ }
+
+ /* Fix media-bay */
+ if (strcmp(np->name, "media-bay") == 0) {
+ macio_create_fixup_irq(dev, 0, 29 + irq_base);
+ printk(KERN_INFO "macio: fixed media-bay irq on gatwick\n");
+ }
+
+ /* Fix left media bay childs */
+ if (dev->media_bay != NULL && strcmp(np->name, "floppy") == 0) {
+ macio_create_fixup_irq(dev, 0, 19 + irq_base);
+ macio_create_fixup_irq(dev, 1, 1 + irq_base);
+ printk(KERN_INFO "macio: fixed left floppy irqs\n");
+ }
+ if (dev->media_bay != NULL && strcasecmp(np->name, "ata4") == 0) {
+ macio_create_fixup_irq(dev, 0, 14 + irq_base);
+ macio_create_fixup_irq(dev, 0, 3 + irq_base);
+ printk(KERN_INFO "macio: fixed left ide irqs\n");
+ }
+}
+
+static void macio_setup_interrupts(struct macio_dev *dev)
+{
+ struct device_node *np = dev->ofdev.node;
+ unsigned int irq;
+ int i = 0, j = 0;
+
+ for (;;) {
struct resource *res = &dev->interrupt[j];
if (j >= MACIO_DEV_COUNT_IRQS)
break;
- res->start = np->intrs[i].line;
- res->flags = IORESOURCE_IO;
- if (np->intrs[j].sense)
- res->flags |= IORESOURCE_IRQ_LOWLEVEL;
- else
- res->flags |= IORESOURCE_IRQ_HIGHEDGE;
+ irq = irq_of_parse_and_map(np, i++);
+ if (irq == NO_IRQ)
+ break;
+ res->start = irq;
+ res->flags = IORESOURCE_IRQ;
res->name = dev->ofdev.dev.bus_id;
- if (macio_resource_quirks(np, res, i))
+ if (macio_resource_quirks(np, res, i - 1)) {
memset(res, 0, sizeof(struct resource));
- else
+ continue;
+ } else
j++;
}
dev->n_interrupts = j;
@@ -402,7 +456,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
struct resource *parent_res)
{
struct macio_dev *dev;
- u32 *reg;
+ const u32 *reg;
if (np == NULL)
return NULL;
@@ -428,16 +482,16 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
/* MacIO itself has a different reg, we use it's PCI base */
if (np == chip->of_node) {
- sprintf(dev->ofdev.dev.bus_id, "%1d.%08lx:%.*s",
+ sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
chip->lbus.index,
#ifdef CONFIG_PCI
- pci_resource_start(chip->lbus.pdev, 0),
+ (unsigned int)pci_resource_start(chip->lbus.pdev, 0),
#else
0, /* NuBus may want to do something better here */
#endif
MAX_NODE_NAME_SIZE, np->name);
} else {
- reg = (u32 *)get_property(np, "reg", NULL);
+ reg = get_property(np, "reg", NULL);
sprintf(dev->ofdev.dev.bus_id, "%1d.%08x:%.*s",
chip->lbus.index,
reg ? *reg : 0, MAX_NODE_NAME_SIZE, np->name);
@@ -446,6 +500,7 @@ static struct macio_dev * macio_add_one_device(struct macio_chip *chip,
/* Setup interrupts & resources */
macio_setup_interrupts(dev);
macio_setup_resources(dev, parent_res);
+ macio_add_missing_resources(dev);
/* Register with core */
if (of_device_register(&dev->ofdev) != 0) {
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
index 7f7d4eaca87..8566bdfdd4b 100644
--- a/drivers/macintosh/macio_sysfs.c
+++ b/drivers/macintosh/macio_sysfs.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/stat.h>
#include <asm/macio.h>
@@ -17,12 +16,12 @@ static ssize_t
compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct of_device *of;
- char *compat;
+ const char *compat;
int cplen;
int length = 0;
of = &to_macio_device (dev)->ofdev;
- compat = (char *) get_property(of->node, "compatible", &cplen);
+ compat = get_property(of->node, "compatible", &cplen);
if (!compat) {
*buf = '\0';
return 0;
@@ -43,12 +42,12 @@ static ssize_t modalias_show (struct device *dev, struct device_attribute *attr,
char *buf)
{
struct of_device *of;
- char *compat;
+ const char *compat;
int cplen;
int length;
of = &to_macio_device (dev)->ofdev;
- compat = (char *) get_property (of->node, "compatible", &cplen);
+ compat = get_property(of->node, "compatible", &cplen);
if (!compat) compat = "", cplen = 1;
length = sprintf (buf, "of:N%sT%s", of->node->name, of->node->type);
buf += length;
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 53c1c790941..0acf2f7fd9d 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -10,7 +10,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index f4516ca7aa3..090e40fc501 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -19,7 +19,6 @@
* the userland interface
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/device.h>
@@ -76,9 +75,11 @@ struct smu_device {
struct of_device *of_dev;
int doorbell; /* doorbell gpio */
u32 __iomem *db_buf; /* doorbell buffer */
- int db_irq;
+ struct device_node *db_node;
+ unsigned int db_irq;
int msg;
- int msg_irq;
+ struct device_node *msg_node;
+ unsigned int msg_irq;
struct smu_cmd_buf *cmd_buf; /* command buffer virtual */
u32 cmd_buf_abs; /* command buffer absolute */
struct list_head cmd_list;
@@ -94,6 +95,7 @@ struct smu_device {
*/
static struct smu_device *smu;
static DEFINE_MUTEX(smu_part_access);
+static int smu_irq_inited;
static void smu_i2c_retry(unsigned long data);
@@ -258,6 +260,10 @@ int smu_queue_cmd(struct smu_cmd *cmd)
smu_start_cmd();
spin_unlock_irqrestore(&smu->lock, flags);
+ /* Workaround for early calls when irq isn't available */
+ if (!smu_irq_inited || smu->db_irq == NO_IRQ)
+ smu_spinwait_cmd(cmd);
+
return 0;
}
EXPORT_SYMBOL(smu_queue_cmd);
@@ -448,7 +454,7 @@ EXPORT_SYMBOL(smu_present);
int __init smu_init (void)
{
struct device_node *np;
- u32 *data;
+ const u32 *data;
np = of_find_node_by_type(NULL, "smu");
if (np == NULL)
@@ -479,14 +485,15 @@ int __init smu_init (void)
smu->cmd_buf_abs = (u32)smu_cmdbuf_abs;
smu->cmd_buf = (struct smu_cmd_buf *)abs_to_virt(smu_cmdbuf_abs);
- np = of_find_node_by_name(NULL, "smu-doorbell");
- if (np == NULL) {
+ smu->db_node = of_find_node_by_name(NULL, "smu-doorbell");
+ if (smu->db_node == NULL) {
printk(KERN_ERR "SMU: Can't find doorbell GPIO !\n");
goto fail;
}
- data = (u32 *)get_property(np, "reg", NULL);
+ data = get_property(smu->db_node, "reg", NULL);
if (data == NULL) {
- of_node_put(np);
+ of_node_put(smu->db_node);
+ smu->db_node = NULL;
printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n");
goto fail;
}
@@ -498,27 +505,21 @@ int __init smu_init (void)
smu->doorbell = *data;
if (smu->doorbell < 0x50)
smu->doorbell += 0x50;
- if (np->n_intrs > 0)
- smu->db_irq = np->intrs[0].line;
-
- of_node_put(np);
/* Now look for the smu-interrupt GPIO */
do {
- np = of_find_node_by_name(NULL, "smu-interrupt");
- if (np == NULL)
+ smu->msg_node = of_find_node_by_name(NULL, "smu-interrupt");
+ if (smu->msg_node == NULL)
break;
- data = (u32 *)get_property(np, "reg", NULL);
+ data = get_property(smu->msg_node, "reg", NULL);
if (data == NULL) {
- of_node_put(np);
+ of_node_put(smu->msg_node);
+ smu->msg_node = NULL;
break;
}
smu->msg = *data;
if (smu->msg < 0x50)
smu->msg += 0x50;
- if (np->n_intrs > 0)
- smu->msg_irq = np->intrs[0].line;
- of_node_put(np);
} while(0);
/* Doorbell buffer is currently hard-coded, I didn't find a proper
@@ -550,13 +551,26 @@ static int smu_late_init(void)
smu->i2c_timer.function = smu_i2c_retry;
smu->i2c_timer.data = (unsigned long)smu;
+ if (smu->db_node) {
+ smu->db_irq = irq_of_parse_and_map(smu->db_node, 0);
+ if (smu->db_irq == NO_IRQ)
+ printk(KERN_ERR "smu: failed to map irq for node %s\n",
+ smu->db_node->full_name);
+ }
+ if (smu->msg_node) {
+ smu->msg_irq = irq_of_parse_and_map(smu->msg_node, 0);
+ if (smu->msg_irq == NO_IRQ)
+ printk(KERN_ERR "smu: failed to map irq for node %s\n",
+ smu->msg_node->full_name);
+ }
+
/*
* Try to request the interrupts
*/
if (smu->db_irq != NO_IRQ) {
if (request_irq(smu->db_irq, smu_db_intr,
- SA_SHIRQ, "SMU doorbell", smu) < 0) {
+ IRQF_SHARED, "SMU doorbell", smu) < 0) {
printk(KERN_WARNING "SMU: can't "
"request interrupt %d\n",
smu->db_irq);
@@ -566,7 +580,7 @@ static int smu_late_init(void)
if (smu->msg_irq != NO_IRQ) {
if (request_irq(smu->msg_irq, smu_msg_intr,
- SA_SHIRQ, "SMU message", smu) < 0) {
+ IRQF_SHARED, "SMU message", smu) < 0) {
printk(KERN_WARNING "SMU: can't "
"request interrupt %d\n",
smu->msg_irq);
@@ -574,6 +588,7 @@ static int smu_late_init(void)
}
}
+ smu_irq_inited = 1;
return 0;
}
/* This has to be before arch_initcall as the low i2c stuff relies on the
@@ -745,6 +760,11 @@ static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc)
if (fail && --cmd->retries > 0) {
DPRINTK("SMU: i2c failure, starting timer...\n");
BUG_ON(cmd != smu->cmd_i2c_cur);
+ if (!smu_irq_inited) {
+ mdelay(5);
+ smu_i2c_retry(0);
+ return;
+ }
mod_timer(&smu->i2c_timer, jiffies + msecs_to_jiffies(5));
return;
}
@@ -962,11 +982,11 @@ static struct smu_sdbp_header *smu_create_sdb_partition(int id)
/* Note: Only allowed to return error code in pointers (using ERR_PTR)
* when interruptible is 1
*/
-struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
- int interruptible)
+const struct smu_sdbp_header *__smu_get_sdb_partition(int id,
+ unsigned int *size, int interruptible)
{
char pname[32];
- struct smu_sdbp_header *part;
+ const struct smu_sdbp_header *part;
if (!smu)
return NULL;
@@ -983,8 +1003,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
} else
mutex_lock(&smu_part_access);
- part = (struct smu_sdbp_header *)get_property(smu->of_node,
- pname, size);
+ part = get_property(smu->of_node, pname, size);
if (part == NULL) {
DPRINTK("trying to extract from SMU ...\n");
part = smu_create_sdb_partition(id);
@@ -995,7 +1014,7 @@ struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
return part;
}
-struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
+const struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
{
return __smu_get_sdb_partition(id, size, 0);
}
@@ -1074,7 +1093,7 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
pp->mode = smu_file_events;
return 0;
} else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
- struct smu_sdbp_header *part;
+ const struct smu_sdbp_header *part;
part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
if (part == NULL)
return -EINVAL;
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 5282fec1707..a0f30d0853e 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -48,7 +47,7 @@ static u8 FAN_SPD_SET[2] = {0x30, 0x31};
static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */
static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */
-static char *sensor_location[3] = {NULL, NULL, NULL};
+static const char *sensor_location[3] = {NULL, NULL, NULL};
static int limit_adjust = 0;
static int fan_speed = -1;
@@ -554,7 +553,7 @@ static int __init
thermostat_init(void)
{
struct device_node* np;
- u32 *prop;
+ const u32 *prop;
int i = 0, offset = 0;
np = of_find_node_by_name(NULL, "fan");
@@ -567,13 +566,13 @@ thermostat_init(void)
else
return -ENODEV;
- prop = (u32 *)get_property(np, "hwsensor-params-version", NULL);
+ prop = get_property(np, "hwsensor-params-version", NULL);
printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop,
(*prop == 1)?"":"un");
if (*prop != 1)
return -ENODEV;
- prop = (u32 *)get_property(np, "reg", NULL);
+ prop = get_property(np, "reg", NULL);
if (!prop)
return -ENODEV;
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index 231146f439d..d00c0c37a12 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -95,9 +95,19 @@
* - Use min/max macros here or there
* - Latest darwin updated U3H min fan speed to 20% PWM
*
+ * July. 06, 2006 : 1.3
+ * - Fix setting of RPM fans on Xserve G5 (they were going too fast)
+ * - Add missing slots fan control loop for Xserve G5
+ * - Lower fixed slots fan speed from 50% to 40% on desktop G5s. We
+ * still can't properly implement the control loop for these, so let's
+ * reduce the noise a little bit, it appears that 40% still gives us
+ * a pretty good air flow
+ * - Add code to "tickle" the FCU regulary so it doesn't think that
+ * we are gone while in fact, the machine just didn't need any fan
+ * speed change lately
+ *
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -122,7 +132,7 @@
#include "therm_pm72.h"
-#define VERSION "1.2b2"
+#define VERSION "1.3"
#undef DEBUG
@@ -147,6 +157,7 @@ static struct basckside_pid_params backside_params;
static struct backside_pid_state backside_state;
static struct drives_pid_state drives_state;
static struct dimm_pid_state dimms_state;
+static struct slots_pid_state slots_state;
static int state;
static int cpu_count;
static int cpu_pid_type;
@@ -155,7 +166,8 @@ static struct completion ctrl_complete;
static int critical_state;
static int rackmac;
static s32 dimm_output_clamp;
-
+static int fcu_rpm_shift;
+static int fcu_tickle_ticks;
static DECLARE_MUTEX(driver_lock);
/*
@@ -496,13 +508,20 @@ static int start_fcu(void)
rc = fan_write_reg(0x2e, &buf, 1);
if (rc < 0)
return -EIO;
+ rc = fan_read_reg(0, &buf, 1);
+ if (rc < 0)
+ return -EIO;
+ fcu_rpm_shift = (buf == 1) ? 2 : 3;
+ printk(KERN_DEBUG "FCU Initialized, RPM fan shift is %d\n",
+ fcu_rpm_shift);
+
return 0;
}
static int set_rpm_fan(int fan_index, int rpm)
{
unsigned char buf[2];
- int rc, id;
+ int rc, id, min, max;
if (fcu_fans[fan_index].type != FCU_FAN_RPM)
return -EINVAL;
@@ -510,12 +529,15 @@ static int set_rpm_fan(int fan_index, int rpm)
if (id == FCU_FAN_ABSENT_ID)
return -EINVAL;
- if (rpm < 300)
- rpm = 300;
- else if (rpm > 8191)
- rpm = 8191;
- buf[0] = rpm >> 5;
- buf[1] = rpm << 3;
+ min = 2400 >> fcu_rpm_shift;
+ max = 56000 >> fcu_rpm_shift;
+
+ if (rpm < min)
+ rpm = min;
+ else if (rpm > max)
+ rpm = max;
+ buf[0] = rpm >> (8 - fcu_rpm_shift);
+ buf[1] = rpm << fcu_rpm_shift;
rc = fan_write_reg(0x10 + (id * 2), buf, 2);
if (rc < 0)
return -EIO;
@@ -552,7 +574,7 @@ static int get_rpm_fan(int fan_index, int programmed)
if (rc != 2)
return -EIO;
- return (buf[0] << 5) | buf[1] >> 3;
+ return (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
}
static int set_pwm_fan(int fan_index, int pwm)
@@ -610,6 +632,26 @@ static int get_pwm_fan(int fan_index)
return (buf[0] * 1000) / 2559;
}
+static void tickle_fcu(void)
+{
+ int pwm;
+
+ pwm = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+
+ DBG("FCU Tickle, slots fan is: %d\n", pwm);
+ if (pwm < 0)
+ pwm = 100;
+
+ if (!rackmac) {
+ pwm = SLOTS_FAN_DEFAULT_PWM;
+ } else if (pwm < SLOTS_PID_OUTPUT_MIN)
+ pwm = SLOTS_PID_OUTPUT_MIN;
+
+ /* That is hopefully enough to make the FCU happy */
+ set_pwm_fan(SLOTS_FAN_PWM_INDEX, pwm);
+}
+
+
/*
* Utility routine to read the CPU calibration EEPROM data
* from the device-tree
@@ -618,7 +660,7 @@ static int read_eeprom(int cpu, struct mpu_data *out)
{
struct device_node *np;
char nodename[64];
- u8 *data;
+ const u8 *data;
int len;
/* prom.c routine for finding a node by path is a bit brain dead
@@ -631,7 +673,7 @@ static int read_eeprom(int cpu, struct mpu_data *out)
printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid node from device-tree\n");
return -ENODEV;
}
- data = (u8 *)get_property(np, "cpuid", &len);
+ data = get_property(np, "cpuid", &len);
if (data == NULL) {
printk(KERN_ERR "therm_pm72: Failed to retrieve cpuid property from device-tree\n");
of_node_put(np);
@@ -716,6 +758,9 @@ BUILD_SHOW_FUNC_INT(backside_fan_pwm, backside_state.pwm)
BUILD_SHOW_FUNC_FIX(drives_temperature, drives_state.last_temp)
BUILD_SHOW_FUNC_INT(drives_fan_rpm, drives_state.rpm)
+BUILD_SHOW_FUNC_FIX(slots_temperature, slots_state.last_temp)
+BUILD_SHOW_FUNC_INT(slots_fan_pwm, slots_state.pwm)
+
BUILD_SHOW_FUNC_FIX(dimms_temperature, dimms_state.last_temp)
static DEVICE_ATTR(cpu0_temperature,S_IRUGO,show_cpu0_temperature,NULL);
@@ -736,6 +781,9 @@ static DEVICE_ATTR(backside_fan_pwm,S_IRUGO,show_backside_fan_pwm,NULL);
static DEVICE_ATTR(drives_temperature,S_IRUGO,show_drives_temperature,NULL);
static DEVICE_ATTR(drives_fan_rpm,S_IRUGO,show_drives_fan_rpm,NULL);
+static DEVICE_ATTR(slots_temperature,S_IRUGO,show_slots_temperature,NULL);
+static DEVICE_ATTR(slots_fan_pwm,S_IRUGO,show_slots_fan_pwm,NULL);
+
static DEVICE_ATTR(dimms_temperature,S_IRUGO,show_dimms_temperature,NULL);
/*
@@ -1077,6 +1125,9 @@ static void do_monitor_cpu_rack(struct cpu_pid_state *state)
fan_min = dimm_output_clamp;
fan_min = max(fan_min, (int)state->mpu.rminn_intake_fan);
+ DBG(" CPU min mpu = %d, min dimm = %d\n",
+ state->mpu.rminn_intake_fan, dimm_output_clamp);
+
state->rpm = max(state->rpm, (int)fan_min);
state->rpm = min(state->rpm, (int)state->mpu.rmaxn_intake_fan);
state->intake_rpm = state->rpm;
@@ -1285,7 +1336,7 @@ static int init_backside_state(struct backside_pid_state *state)
*/
u3 = of_find_node_by_path("/u3@0,f8000000");
if (u3 != NULL) {
- u32 *vers = (u32 *)get_property(u3, "device-rev", NULL);
+ const u32 *vers = get_property(u3, "device-rev", NULL);
if (vers)
if (((*vers) & 0x3f) < 0x34)
u3h = 0;
@@ -1375,7 +1426,8 @@ static void do_monitor_drives(struct drives_pid_state *state)
DBG(" current rpm: %d\n", state->rpm);
/* Get some sensor readings */
- temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor, DS1775_TEMP)) << 8;
+ temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+ DS1775_TEMP)) << 8;
state->last_temp = temp;
DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
FIX32TOPRINT(DRIVES_PID_INPUT_TARGET));
@@ -1576,7 +1628,7 @@ static int init_dimms_state(struct dimm_pid_state *state)
}
/*
- * Dispose of the state data for the drives control loop
+ * Dispose of the state data for the DIMM control loop
*/
static void dispose_dimms_state(struct dimm_pid_state *state)
{
@@ -1589,6 +1641,127 @@ static void dispose_dimms_state(struct dimm_pid_state *state)
state->monitor = NULL;
}
+/*
+ * Slots fan control loop
+ */
+static void do_monitor_slots(struct slots_pid_state *state)
+{
+ s32 temp, integral, derivative;
+ s64 integ_p, deriv_p, prop_p, sum;
+ int i, rc;
+
+ if (--state->ticks != 0)
+ return;
+ state->ticks = SLOTS_PID_INTERVAL;
+
+ DBG("slots:\n");
+
+ /* Check fan status */
+ rc = get_pwm_fan(SLOTS_FAN_PWM_INDEX);
+ if (rc < 0) {
+ printk(KERN_WARNING "Error %d reading slots fan !\n", rc);
+ /* XXX What do we do now ? */
+ } else
+ state->pwm = rc;
+ DBG(" current pwm: %d\n", state->pwm);
+
+ /* Get some sensor readings */
+ temp = le16_to_cpu(i2c_smbus_read_word_data(state->monitor,
+ DS1775_TEMP)) << 8;
+ state->last_temp = temp;
+ DBG(" temp: %d.%03d, target: %d.%03d\n", FIX32TOPRINT(temp),
+ FIX32TOPRINT(SLOTS_PID_INPUT_TARGET));
+
+ /* Store temperature and error in history array */
+ state->cur_sample = (state->cur_sample + 1) % SLOTS_PID_HISTORY_SIZE;
+ state->sample_history[state->cur_sample] = temp;
+ state->error_history[state->cur_sample] = temp - SLOTS_PID_INPUT_TARGET;
+
+ /* If first loop, fill the history table */
+ if (state->first) {
+ for (i = 0; i < (SLOTS_PID_HISTORY_SIZE - 1); i++) {
+ state->cur_sample = (state->cur_sample + 1) %
+ SLOTS_PID_HISTORY_SIZE;
+ state->sample_history[state->cur_sample] = temp;
+ state->error_history[state->cur_sample] =
+ temp - SLOTS_PID_INPUT_TARGET;
+ }
+ state->first = 0;
+ }
+
+ /* Calculate the integral term */
+ sum = 0;
+ integral = 0;
+ for (i = 0; i < SLOTS_PID_HISTORY_SIZE; i++)
+ integral += state->error_history[i];
+ integral *= SLOTS_PID_INTERVAL;
+ DBG(" integral: %08x\n", integral);
+ integ_p = ((s64)SLOTS_PID_G_r) * (s64)integral;
+ DBG(" integ_p: %d\n", (int)(integ_p >> 36));
+ sum += integ_p;
+
+ /* Calculate the derivative term */
+ derivative = state->error_history[state->cur_sample] -
+ state->error_history[(state->cur_sample + SLOTS_PID_HISTORY_SIZE - 1)
+ % SLOTS_PID_HISTORY_SIZE];
+ derivative /= SLOTS_PID_INTERVAL;
+ deriv_p = ((s64)SLOTS_PID_G_d) * (s64)derivative;
+ DBG(" deriv_p: %d\n", (int)(deriv_p >> 36));
+ sum += deriv_p;
+
+ /* Calculate the proportional term */
+ prop_p = ((s64)SLOTS_PID_G_p) * (s64)(state->error_history[state->cur_sample]);
+ DBG(" prop_p: %d\n", (int)(prop_p >> 36));
+ sum += prop_p;
+
+ /* Scale sum */
+ sum >>= 36;
+
+ DBG(" sum: %d\n", (int)sum);
+ state->pwm = (s32)sum;
+
+ state->pwm = max(state->pwm, SLOTS_PID_OUTPUT_MIN);
+ state->pwm = min(state->pwm, SLOTS_PID_OUTPUT_MAX);
+
+ DBG("** DRIVES PWM: %d\n", (int)state->pwm);
+ set_pwm_fan(SLOTS_FAN_PWM_INDEX, state->pwm);
+}
+
+/*
+ * Initialize the state structure for the slots bay fan control loop
+ */
+static int init_slots_state(struct slots_pid_state *state)
+{
+ state->ticks = 1;
+ state->first = 1;
+ state->pwm = 50;
+
+ state->monitor = attach_i2c_chip(XSERVE_SLOTS_LM75, "slots_temp");
+ if (state->monitor == NULL)
+ return -ENODEV;
+
+ device_create_file(&of_dev->dev, &dev_attr_slots_temperature);
+ device_create_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+ return 0;
+}
+
+/*
+ * Dispose of the state data for the slots control loop
+ */
+static void dispose_slots_state(struct slots_pid_state *state)
+{
+ if (state->monitor == NULL)
+ return;
+
+ device_remove_file(&of_dev->dev, &dev_attr_slots_temperature);
+ device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm);
+
+ detach_i2c_chip(state->monitor);
+ state->monitor = NULL;
+}
+
+
static int call_critical_overtemp(void)
{
char *argv[] = { critical_overtemp_path, NULL };
@@ -1618,14 +1791,17 @@ static int main_control_loop(void *x)
goto out;
}
- /* Set the PCI fan once for now */
- set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
+ /* Set the PCI fan once for now on non-RackMac */
+ if (!rackmac)
+ set_pwm_fan(SLOTS_FAN_PWM_INDEX, SLOTS_FAN_DEFAULT_PWM);
/* Initialize ADCs */
initialize_adc(&cpu_state[0]);
if (cpu_state[1].monitor != NULL)
initialize_adc(&cpu_state[1]);
+ fcu_tickle_ticks = FCU_TICKLE_TICKS;
+
up(&driver_lock);
while (state == state_attached) {
@@ -1635,6 +1811,12 @@ static int main_control_loop(void *x)
down(&driver_lock);
+ /* Tickle the FCU just in case */
+ if (--fcu_tickle_ticks < 0) {
+ fcu_tickle_ticks = FCU_TICKLE_TICKS;
+ tickle_fcu();
+ }
+
/* First, we always calculate the new DIMMs state on an Xserve */
if (rackmac)
do_monitor_dimms(&dimms_state);
@@ -1655,7 +1837,9 @@ static int main_control_loop(void *x)
}
/* Then, the rest */
do_monitor_backside(&backside_state);
- if (!rackmac)
+ if (rackmac)
+ do_monitor_slots(&slots_state);
+ else
do_monitor_drives(&drives_state);
up(&driver_lock);
@@ -1697,6 +1881,7 @@ static void dispose_control_loops(void)
dispose_cpu_state(&cpu_state[1]);
dispose_backside_state(&backside_state);
dispose_drives_state(&drives_state);
+ dispose_slots_state(&slots_state);
dispose_dimms_state(&dimms_state);
}
@@ -1746,6 +1931,8 @@ static int create_control_loops(void)
goto fail;
if (rackmac && init_dimms_state(&dimms_state))
goto fail;
+ if (rackmac && init_slots_state(&slots_state))
+ goto fail;
if (!rackmac && init_drives_state(&drives_state))
goto fail;
@@ -1924,8 +2111,8 @@ static void fcu_lookup_fans(struct device_node *fcu_node)
while ((np = of_get_next_child(fcu_node, np)) != NULL) {
int type = -1;
- char *loc;
- u32 *reg;
+ const char *loc;
+ const u32 *reg;
DBG(" control: %s, type: %s\n", np->name, np->type);
@@ -1941,8 +2128,8 @@ static void fcu_lookup_fans(struct device_node *fcu_node)
continue;
/* Lookup for a matching location */
- loc = (char *)get_property(np, "location", NULL);
- reg = (u32 *)get_property(np, "reg", NULL);
+ loc = get_property(np, "location", NULL);
+ reg = get_property(np, "reg", NULL);
if (loc == NULL || reg == NULL)
continue;
DBG(" matching location: %s, reg: 0x%08x\n", loc, *reg);
diff --git a/drivers/macintosh/therm_pm72.h b/drivers/macintosh/therm_pm72.h
index c17e61f9c41..393cc9df94e 100644
--- a/drivers/macintosh/therm_pm72.h
+++ b/drivers/macintosh/therm_pm72.h
@@ -93,7 +93,7 @@ static char * critical_overtemp_path = "/sbin/critical_overtemp";
* 0. This appear to be safe enough for this first version
* of the driver, though I would accept any clean patch
* doing a better use of the device-tree without turning the
- * while i2c registration mecanism into a racy mess
+ * while i2c registration mechanism into a racy mess
*
* Note: Xserve changed this. We have some bits on the K2 bus,
* which I arbitrarily set to 0x200. Ultimately, we really want
@@ -105,6 +105,7 @@ static char * critical_overtemp_path = "/sbin/critical_overtemp";
#define DRIVES_DALLAS_ID 0x94
#define BACKSIDE_MAX_ID 0x98
#define XSERVE_DIMMS_LM87 0x25a
+#define XSERVE_SLOTS_LM75 0x290
/*
* Some MAX6690, DS1775, LM87 register definitions
@@ -198,7 +199,7 @@ struct drives_pid_state
#define SLOTS_FAN_PWM_DEFAULT_ID 2
#define SLOTS_FAN_PWM_INDEX 2
-#define SLOTS_FAN_DEFAULT_PWM 50 /* Do better here ! */
+#define SLOTS_FAN_DEFAULT_PWM 40 /* Do better here ! */
/*
@@ -206,7 +207,7 @@ struct drives_pid_state
*/
#define DIMM_PID_G_d 0
#define DIMM_PID_G_p 0
-#define DIMM_PID_G_r 0x6553600
+#define DIMM_PID_G_r 0x06553600
#define DIMM_PID_INPUT_TARGET 3276800
#define DIMM_PID_INTERVAL 1
#define DIMM_PID_OUTPUT_MAX 14000
@@ -226,6 +227,31 @@ struct dimm_pid_state
};
+/*
+ * PID factors for the Xserve Slots control loop
+ */
+#define SLOTS_PID_G_d 0
+#define SLOTS_PID_G_p 0
+#define SLOTS_PID_G_r 0x00100000
+#define SLOTS_PID_INPUT_TARGET 3200000
+#define SLOTS_PID_INTERVAL 1
+#define SLOTS_PID_OUTPUT_MAX 100
+#define SLOTS_PID_OUTPUT_MIN 20
+#define SLOTS_PID_HISTORY_SIZE 20
+
+struct slots_pid_state
+{
+ int ticks;
+ struct i2c_client * monitor;
+ s32 sample_history[SLOTS_PID_HISTORY_SIZE];
+ s32 error_history[SLOTS_PID_HISTORY_SIZE];
+ int cur_sample;
+ s32 last_temp;
+ int first;
+ int pwm;
+};
+
+
/* Desktops */
@@ -283,6 +309,9 @@ struct cpu_pid_state
s32 pump_max;
};
+/* Tickle FCU every 10 seconds */
+#define FCU_TICKLE_TICKS 10
+
/*
* Driver state
*/
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 3d9dd2e166a..738faab1b22 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -485,14 +484,14 @@ struct apple_thermal_info {
static int __init
g4fan_init( void )
{
- struct apple_thermal_info *info;
+ const struct apple_thermal_info *info;
struct device_node *np;
init_MUTEX( &x.lock );
if( !(np=of_find_node_by_name(NULL, "power-mgt")) )
return -ENODEV;
- info = (struct apple_thermal_info*)get_property(np, "thermal-info", NULL);
+ info = get_property(np, "thermal-info", NULL);
of_node_put(np);
if( !info || !machine_is_compatible("PowerMac3,6") )
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 2d9d7915040..7512d1c1520 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -9,7 +9,6 @@
* Copyright (C) 1996 Paul Mackerras.
*/
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -35,13 +34,6 @@
static volatile unsigned char __iomem *via;
static DEFINE_SPINLOCK(cuda_lock);
-#ifdef CONFIG_MAC
-#define CUDA_IRQ IRQ_MAC_ADB
-#define eieio()
-#else
-#define CUDA_IRQ vias->intrs[0].line
-#endif
-
/* VIA registers - spaced 0x200 bytes apart */
#define RS 0x200 /* skip between registers */
#define B 0 /* B-side data */
@@ -131,7 +123,7 @@ int __init find_via_cuda(void)
{
struct adb_request req;
phys_addr_t taddr;
- u32 *reg;
+ const u32 *reg;
int err;
if (vias != 0)
@@ -140,7 +132,7 @@ int __init find_via_cuda(void)
if (vias == 0)
return 0;
- reg = (u32 *)get_property(vias, "reg", NULL);
+ reg = get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-cuda: No \"reg\" property !\n");
goto fail;
@@ -190,11 +182,24 @@ int __init find_via_cuda(void)
static int __init via_cuda_start(void)
{
+ unsigned int irq;
+
if (via == NULL)
return -ENODEV;
- if (request_irq(CUDA_IRQ, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
- printk(KERN_ERR "cuda_init: can't get irq %d\n", CUDA_IRQ);
+#ifdef CONFIG_MAC
+ irq = IRQ_MAC_ADB;
+#else /* CONFIG_MAC */
+ irq = irq_of_parse_and_map(vias, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR "via-cuda: can't map interrupts for %s\n",
+ vias->full_name);
+ return -ENODEV;
+ }
+#endif /* CONFIG_MAP */
+
+ if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) {
+ printk(KERN_ERR "via-cuda: can't request irq %d\n", irq);
return -EAGAIN;
}
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
new file mode 100644
index 00000000000..6c29fe727c0
--- /dev/null
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -0,0 +1,187 @@
+/*
+ * Backlight code for via-pmu
+ *
+ * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
+ * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ */
+
+#include <asm/ptrace.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/backlight.h>
+#include <asm/prom.h>
+
+#define MAX_PMU_LEVEL 0xFF
+
+static struct backlight_properties pmu_backlight_data;
+static DEFINE_SPINLOCK(pmu_backlight_lock);
+static int sleeping;
+static u8 bl_curve[FB_BACKLIGHT_LEVELS];
+
+static void pmu_backlight_init_curve(u8 off, u8 min, u8 max)
+{
+ unsigned int i, flat, count, range = (max - min);
+
+ bl_curve[0] = off;
+
+ for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+ bl_curve[flat] = min;
+
+ count = FB_BACKLIGHT_LEVELS * 15 / 16;
+ for (i = 0; i < count; ++i)
+ bl_curve[flat + i] = min + (range * (i + 1) / count);
+}
+
+static int pmu_backlight_curve_lookup(int value)
+{
+ int level = (FB_BACKLIGHT_LEVELS - 1);
+ int i, max = 0;
+
+ /* Look for biggest value */
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++)
+ max = max((int)bl_curve[i], max);
+
+ /* Look for nearest value */
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) {
+ int diff = abs(bl_curve[i] - value);
+ if (diff < max) {
+ max = diff;
+ level = i;
+ }
+ }
+ return level;
+}
+
+static int pmu_backlight_get_level_brightness(int level)
+{
+ int pmulevel;
+
+ /* Get and convert the value */
+ pmulevel = bl_curve[level] * FB_BACKLIGHT_MAX / MAX_PMU_LEVEL;
+ if (pmulevel < 0)
+ pmulevel = 0;
+ else if (pmulevel > MAX_PMU_LEVEL)
+ pmulevel = MAX_PMU_LEVEL;
+
+ return pmulevel;
+}
+
+static int pmu_backlight_update_status(struct backlight_device *bd)
+{
+ struct adb_request req;
+ unsigned long flags;
+ int level = bd->props->brightness;
+
+ spin_lock_irqsave(&pmu_backlight_lock, flags);
+
+ /* Don't update brightness when sleeping */
+ if (sleeping)
+ goto out;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+
+ if (level > 0) {
+ int pmulevel = pmu_backlight_get_level_brightness(level);
+
+ pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT, pmulevel);
+ pmu_wait_complete(&req);
+
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | PMU_POW_ON);
+ pmu_wait_complete(&req);
+ } else {
+ pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
+ PMU_POW_BACKLIGHT | PMU_POW_OFF);
+ pmu_wait_complete(&req);
+ }
+
+out:
+ spin_unlock_irqrestore(&pmu_backlight_lock, flags);
+
+ return 0;
+}
+
+static int pmu_backlight_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties pmu_backlight_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = pmu_backlight_get_brightness,
+ .update_status = pmu_backlight_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+#ifdef CONFIG_PM
+void pmu_backlight_set_sleep(int sleep)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu_backlight_lock, flags);
+ sleeping = sleep;
+ spin_unlock_irqrestore(&pmu_backlight_lock, flags);
+}
+#endif /* CONFIG_PM */
+
+void __init pmu_backlight_init()
+{
+ struct backlight_device *bd;
+ char name[10];
+ int level, autosave;
+
+ /* Special case for the old PowerBook since I can't test on it */
+ autosave =
+ machine_is_compatible("AAPL,3400/2400") ||
+ machine_is_compatible("AAPL,3500");
+
+ if (!autosave &&
+ !pmac_has_backlight_type("pmu") &&
+ !machine_is_compatible("AAPL,PowerBook1998") &&
+ !machine_is_compatible("PowerBook1,1"))
+ return;
+
+ snprintf(name, sizeof(name), "pmubl");
+
+ bd = backlight_device_register(name, NULL, &pmu_backlight_data);
+ if (IS_ERR(bd)) {
+ printk("pmubl: Backlight registration failed\n");
+ goto error;
+ }
+ pmu_backlight_init_curve(0x7F, 0x46, 0x0E);
+
+ level = pmu_backlight_data.max_brightness;
+
+ if (autosave) {
+ /* read autosaved value if available */
+ struct adb_request req;
+ pmu_request(&req, NULL, 2, 0xd9, 0);
+ pmu_wait_complete(&req);
+
+ level = pmu_backlight_curve_lookup(
+ (req.reply[0] >> 4) *
+ pmu_backlight_data.max_brightness / 15);
+ }
+
+ down(&bd->sem);
+ bd->props->brightness = level;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ up(&bd->sem);
+
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+
+ printk("pmubl: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
diff --git a/drivers/macintosh/via-pmu-event.c b/drivers/macintosh/via-pmu-event.c
new file mode 100644
index 00000000000..25cd5654232
--- /dev/null
+++ b/drivers/macintosh/via-pmu-event.c
@@ -0,0 +1,80 @@
+/*
+ * via-pmu event device for reporting some events that come through the PMU
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/input.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include "via-pmu-event.h"
+
+static struct input_dev *pmu_input_dev;
+
+static int __init via_pmu_event_init(void)
+{
+ int err;
+
+ /* do other models report button/lid status? */
+ if (pmu_get_model() != PMU_KEYLARGO_BASED)
+ return -ENODEV;
+
+ pmu_input_dev = input_allocate_device();
+ if (!pmu_input_dev)
+ return -ENOMEM;
+
+ pmu_input_dev->name = "PMU";
+ pmu_input_dev->id.bustype = BUS_HOST;
+ pmu_input_dev->id.vendor = 0x0001;
+ pmu_input_dev->id.product = 0x0001;
+ pmu_input_dev->id.version = 0x0100;
+
+ set_bit(EV_KEY, pmu_input_dev->evbit);
+ set_bit(EV_SW, pmu_input_dev->evbit);
+ set_bit(KEY_POWER, pmu_input_dev->keybit);
+ set_bit(SW_LID, pmu_input_dev->swbit);
+
+ err = input_register_device(pmu_input_dev);
+ if (err)
+ input_free_device(pmu_input_dev);
+ return err;
+}
+
+void via_pmu_event(int key, int down)
+{
+
+ if (unlikely(!pmu_input_dev))
+ return;
+
+ switch (key) {
+ case PMU_EVT_POWER:
+ input_report_key(pmu_input_dev, KEY_POWER, down);
+ break;
+ case PMU_EVT_LID:
+ input_report_switch(pmu_input_dev, SW_LID, down);
+ break;
+ default:
+ /* no such key handled */
+ return;
+ }
+
+ input_sync(pmu_input_dev);
+}
+
+late_initcall(via_pmu_event_init);
diff --git a/drivers/macintosh/via-pmu-event.h b/drivers/macintosh/via-pmu-event.h
new file mode 100644
index 00000000000..72c54de408e
--- /dev/null
+++ b/drivers/macintosh/via-pmu-event.h
@@ -0,0 +1,8 @@
+#ifndef __VIA_PMU_EVENT_H
+#define __VIA_PMU_EVENT_H
+
+#define PMU_EVT_POWER 0
+#define PMU_EVT_LID 1
+extern void via_pmu_event(int key, int down);
+
+#endif /* __VIA_PMU_EVENT_H */
diff --git a/drivers/macintosh/via-pmu-led.c b/drivers/macintosh/via-pmu-led.c
new file mode 100644
index 00000000000..179af10105d
--- /dev/null
+++ b/drivers/macintosh/via-pmu-led.c
@@ -0,0 +1,144 @@
+/*
+ * via-pmu LED class device
+ *
+ * Copyright 2006 Johannes Berg <johannes@sipsolutions.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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/leds.h>
+#include <linux/adb.h>
+#include <linux/pmu.h>
+#include <asm/prom.h>
+
+static spinlock_t pmu_blink_lock;
+static struct adb_request pmu_blink_req;
+/* -1: no change, 0: request off, 1: request on */
+static int requested_change;
+static int sleeping;
+
+static void pmu_req_done(struct adb_request * req)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu_blink_lock, flags);
+ /* if someone requested a change in the meantime
+ * (we only see the last one which is fine)
+ * then apply it now */
+ if (requested_change != -1 && !sleeping)
+ pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
+ /* reset requested change */
+ requested_change = -1;
+ spin_unlock_irqrestore(&pmu_blink_lock, flags);
+}
+
+static void pmu_led_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu_blink_lock, flags);
+ switch (brightness) {
+ case LED_OFF:
+ requested_change = 0;
+ break;
+ case LED_FULL:
+ requested_change = 1;
+ break;
+ default:
+ goto out;
+ break;
+ }
+ /* if request isn't done, then don't do anything */
+ if (pmu_blink_req.complete && !sleeping)
+ pmu_request(&pmu_blink_req, NULL, 4, 0xee, 4, 0, requested_change);
+ out:
+ spin_unlock_irqrestore(&pmu_blink_lock, flags);
+}
+
+static struct led_classdev pmu_led = {
+ .name = "pmu-front-led",
+#ifdef CONFIG_ADB_PMU_LED_IDE
+ .default_trigger = "ide-disk",
+#endif
+ .brightness_set = pmu_led_set,
+};
+
+#ifdef CONFIG_PM
+static int pmu_led_sleep_call(struct pmu_sleep_notifier *self, int when)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pmu_blink_lock, flags);
+
+ switch (when) {
+ case PBOOK_SLEEP_REQUEST:
+ sleeping = 1;
+ break;
+ case PBOOK_WAKE:
+ sleeping = 0;
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+ spin_unlock_irqrestore(&pmu_blink_lock, flags);
+
+ return PBOOK_SLEEP_OK;
+}
+
+static struct pmu_sleep_notifier via_pmu_led_sleep_notif = {
+ .notifier_call = pmu_led_sleep_call,
+};
+#endif
+
+static int __init via_pmu_led_init(void)
+{
+ struct device_node *dt;
+ const char *model;
+
+ /* only do this on keylargo based models */
+ if (pmu_get_model() != PMU_KEYLARGO_BASED)
+ return -ENODEV;
+
+ dt = of_find_node_by_path("/");
+ if (dt == NULL)
+ return -ENODEV;
+ model = get_property(dt, "model", NULL);
+ if (model == NULL)
+ return -ENODEV;
+ if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
+ strncmp(model, "iBook", strlen("iBook")) != 0) {
+ of_node_put(dt);
+ /* ignore */
+ return -ENODEV;
+ }
+ of_node_put(dt);
+
+ spin_lock_init(&pmu_blink_lock);
+ /* no outstanding req */
+ pmu_blink_req.complete = 1;
+ pmu_blink_req.done = pmu_req_done;
+#ifdef CONFIG_PM
+ pmu_register_sleep_notifier(&via_pmu_led_sleep_notif);
+#endif
+ return led_classdev_register(NULL, &pmu_led);
+}
+
+late_initcall(via_pmu_led_init);
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index c63d4e7984b..dda03985dcf 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -16,12 +16,10 @@
* a sleep or a freq. switch
* - Move sleep code out of here to pmac_pm, merge into new
* common PM infrastructure
- * - Move backlight code out as well
* - Save/Restore PCI space properly
*
*/
#include <stdarg.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -61,13 +59,9 @@
#include <asm/mmu_context.h>
#include <asm/cputable.h>
#include <asm/time.h>
-#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
-#endif
-#ifdef CONFIG_PPC32
-#include <asm/open_pic.h>
-#endif
+#include "via-pmu-event.h"
/* Some compile options */
#undef SUSPEND_USES_PMU
@@ -144,14 +138,13 @@ static int data_index;
static int data_len;
static volatile int adb_int_pending;
static volatile int disable_poll;
-static struct adb_request bright_req_1, bright_req_2;
static struct device_node *vias;
static int pmu_kind = PMU_UNKNOWN;
static int pmu_fully_inited = 0;
static int pmu_has_adb;
static struct device_node *gpio_node;
static unsigned char __iomem *gpio_reg = NULL;
-static int gpio_irq = -1;
+static int gpio_irq = NO_IRQ;
static int gpio_irq_enabled = -1;
static volatile int pmu_suspended = 0;
static spinlock_t pmu_lock;
@@ -161,7 +154,7 @@ static int drop_interrupts;
#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
static int option_lid_wakeup = 1;
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT)
+#if (defined(CONFIG_PM)&&defined(CONFIG_PPC32))||defined(CONFIG_PMAC_BACKLIGHT_LEGACY)
static int sleep_in_progress;
#endif
static unsigned long async_req_locks;
@@ -181,10 +174,6 @@ static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
-extern int disable_kernel_backlight;
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
-
int __fake_sleep;
int asleep;
BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
@@ -208,10 +197,6 @@ static int proc_get_info(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int proc_get_irqstats(char *page, char **start, off_t off,
int count, int *eof, void *data);
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int pmu_set_backlight_level(int level, void* data);
-static int pmu_set_backlight_enable(int on, int level, void* data);
-#endif /* CONFIG_PMAC_BACKLIGHT */
static void pmu_pass_intr(unsigned char *data, int len);
static int proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data);
@@ -292,17 +277,10 @@ static char *pbook_type[] = {
"Core99"
};
-#ifdef CONFIG_PMAC_BACKLIGHT
-static struct backlight_controller pmu_backlight_controller = {
- pmu_set_backlight_enable,
- pmu_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
int __init find_via_pmu(void)
{
u64 taddr;
- u32 *reg;
+ const u32 *reg;
if (via != 0)
return 1;
@@ -310,7 +288,7 @@ int __init find_via_pmu(void)
if (vias == NULL)
return 0;
- reg = (u32 *)get_property(vias, "reg", NULL);
+ reg = get_property(vias, "reg", NULL);
if (reg == NULL) {
printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
goto fail;
@@ -352,7 +330,7 @@ int __init find_via_pmu(void)
gpiop = of_find_node_by_name(NULL, "gpio");
if (gpiop) {
- reg = (u32 *)get_property(gpiop, "reg", NULL);
+ reg = get_property(gpiop, "reg", NULL);
if (reg)
gaddr = of_translate_address(gpiop, reg);
if (gaddr != OF_BAD_ADDR)
@@ -414,24 +392,21 @@ static int __init pmu_init(void)
*/
static int __init via_pmu_start(void)
{
+ unsigned int irq;
+
if (vias == NULL)
return -ENODEV;
- bright_req_1.complete = 1;
- bright_req_2.complete = 1;
batt_req.complete = 1;
-#ifndef CONFIG_PPC_MERGE
- if (pmu_kind == PMU_KEYLARGO_BASED)
- openpic_set_irq_priority(vias->intrs[0].line,
- OPENPIC_PRIORITY_DEFAULT + 1);
-#endif
-
- if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
- (void *)0)) {
- printk(KERN_ERR "VIA-PMU: can't get irq %d\n",
- vias->intrs[0].line);
- return -EAGAIN;
+ irq = irq_of_parse_and_map(vias, 0);
+ if (irq == NO_IRQ) {
+ printk(KERN_ERR "via-pmu: can't map interruptn");
+ return -ENODEV;
+ }
+ if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) {
+ printk(KERN_ERR "via-pmu: can't request irq %d\n", irq);
+ return -ENODEV;
}
if (pmu_kind == PMU_KEYLARGO_BASED) {
@@ -439,10 +414,10 @@ static int __init via_pmu_start(void)
if (gpio_node == NULL)
gpio_node = of_find_node_by_name(NULL,
"pmu-interrupt");
- if (gpio_node && gpio_node->n_intrs > 0)
- gpio_irq = gpio_node->intrs[0].line;
+ if (gpio_node)
+ gpio_irq = irq_of_parse_and_map(gpio_node, 0);
- if (gpio_irq != -1) {
+ if (gpio_irq != NO_IRQ) {
if (request_irq(gpio_irq, gpio1_interrupt, 0,
"GPIO1 ADB", (void *)0))
printk(KERN_ERR "pmu: can't get irq %d"
@@ -483,9 +458,9 @@ static int __init via_pmu_dev_init(void)
return -ENODEV;
#ifdef CONFIG_PMAC_BACKLIGHT
- /* Enable backlight */
- register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ /* Initialize backlight */
+ pmu_backlight_init();
+#endif
#ifdef CONFIG_PPC32
if (machine_is_compatible("AAPL,3400/2400") ||
@@ -504,9 +479,9 @@ static int __init via_pmu_dev_init(void)
pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
} else {
struct device_node* prim = find_devices("power-mgt");
- u32 *prim_info = NULL;
+ const u32 *prim_info = NULL;
if (prim)
- prim_info = (u32 *)get_property(prim, "prim-info", NULL);
+ prim_info = get_property(prim, "prim-info", NULL);
if (prim_info) {
/* Other stuffs here yet unknown */
pmu_battery_count = (prim_info[6] >> 16) & 0xff;
@@ -1421,11 +1396,8 @@ next:
else if ((1 << pirq) & PMU_INT_SNDBRT) {
#ifdef CONFIG_PMAC_BACKLIGHT
if (len == 3)
-#ifdef CONFIG_INPUT_ADBHID
- if (!disable_kernel_backlight)
-#endif /* CONFIG_INPUT_ADBHID */
- set_backlight_level(data[1] >> 4);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4);
+#endif
}
/* Tick interrupt */
else if ((1 << pirq) & PMU_INT_TICK) {
@@ -1441,6 +1413,12 @@ next:
if (pmu_battery_count)
query_battery_state();
pmu_pass_intr(data, len);
+ /* len == 6 is probably a bad check. But how do I
+ * know what PMU versions send what events here? */
+ if (len == 6) {
+ via_pmu_event(PMU_EVT_POWER, !!(data[1]&8));
+ via_pmu_event(PMU_EVT_LID, data[1]&1);
+ }
} else {
pmu_pass_intr(data, len);
}
@@ -1674,61 +1652,6 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
return IRQ_NONE;
}
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_to_bright[] = {
- 0x7f, 0x46, 0x42, 0x3e, 0x3a, 0x36, 0x32, 0x2e,
- 0x2a, 0x26, 0x22, 0x1e, 0x1a, 0x16, 0x12, 0x0e
-};
-
-static int
-pmu_set_backlight_enable(int on, int level, void* data)
-{
- struct adb_request req;
-
- if (vias == NULL)
- return -ENODEV;
-
- if (on) {
- pmu_request(&req, NULL, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_to_bright[level]);
- pmu_wait_complete(&req);
- }
- pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (on ? PMU_POW_ON : PMU_POW_OFF));
- pmu_wait_complete(&req);
-
- return 0;
-}
-
-static void
-pmu_bright_complete(struct adb_request *req)
-{
- if (req == &bright_req_1)
- clear_bit(1, &async_req_locks);
- if (req == &bright_req_2)
- clear_bit(2, &async_req_locks);
-}
-
-static int
-pmu_set_backlight_level(int level, void* data)
-{
- if (vias == NULL)
- return -ENODEV;
-
- if (test_and_set_bit(1, &async_req_locks))
- return -EAGAIN;
- pmu_request(&bright_req_1, pmu_bright_complete, 2, PMU_BACKLIGHT_BRIGHT,
- backlight_to_bright[level]);
- if (test_and_set_bit(2, &async_req_locks))
- return -EAGAIN;
- pmu_request(&bright_req_2, pmu_bright_complete, 2, PMU_POWER_CTRL,
- PMU_POW_BACKLIGHT | (level > BACKLIGHT_OFF ?
- PMU_POW_ON : PMU_POW_OFF));
-
- return 0;
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
void
pmu_enable_irled(int on)
{
@@ -2072,6 +1995,8 @@ restore_via_state(void)
out_8(&via[IER], IER_SET | SR_INT | CB1_INT);
}
+extern void pmu_backlight_set_sleep(int sleep);
+
static int
pmac_suspend_devices(void)
{
@@ -2109,6 +2034,11 @@ pmac_suspend_devices(void)
return -EBUSY;
}
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code not to muck around with the chip anymore */
+ pmu_backlight_set_sleep(1);
+#endif
+
/* Call platform functions marked "on sleep" */
pmac_pfunc_i2c_suspend();
pmac_pfunc_base_suspend();
@@ -2145,9 +2075,8 @@ pmac_suspend_devices(void)
return -EBUSY;
}
- /* Wait for completion of async backlight requests */
- while (!bright_req_1.complete || !bright_req_2.complete ||
- !batt_req.complete)
+ /* Wait for completion of async requests */
+ while (!batt_req.complete)
pmu_poll();
/* Giveup the lazy FPU & vec so we don't have to back them
@@ -2168,6 +2097,11 @@ pmac_wakeup_devices(void)
{
mdelay(100);
+#ifdef CONFIG_PMAC_BACKLIGHT
+ /* Tell backlight code it can use the chip again */
+ pmu_backlight_set_sleep(0);
+#endif
+
/* Power back up system devices (including the PIC) */
device_power_up();
@@ -2482,7 +2416,7 @@ struct pmu_private {
spinlock_t lock;
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
int backlight_locker;
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+#endif
};
static LIST_HEAD(all_pmu_pvt);
@@ -2532,7 +2466,7 @@ pmu_open(struct inode *inode, struct file *file)
spin_lock_irqsave(&all_pvt_lock, flags);
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
pp->backlight_locker = 0;
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+#endif
list_add(&pp->list, &all_pmu_pvt);
spin_unlock_irqrestore(&all_pvt_lock, flags);
file->private_data = pp;
@@ -2627,13 +2561,12 @@ pmu_release(struct inode *inode, struct file *file)
spin_lock_irqsave(&all_pvt_lock, flags);
list_del(&pp->list);
spin_unlock_irqrestore(&all_pvt_lock, flags);
+
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
- if (pp->backlight_locker) {
- spin_lock_irqsave(&pmu_lock, flags);
- disable_kernel_backlight--;
- spin_unlock_irqrestore(&pmu_lock, flags);
- }
-#endif /* defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT) */
+ if (pp->backlight_locker)
+ pmac_backlight_enable();
+#endif
+
kfree(pp);
}
unlock_kernel();
@@ -2678,42 +2611,50 @@ pmu_ioctl(struct inode * inode, struct file *filp,
return put_user(1, argp);
#endif /* CONFIG_PM && CONFIG_PPC32 */
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Backlight should have its own device or go via
- * the fbdev
- */
+#ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
+ /* Compatibility ioctl's for backlight */
case PMU_IOC_GET_BACKLIGHT:
+ {
+ int brightness;
+
if (sleep_in_progress)
return -EBUSY;
- error = get_backlight_level();
- if (error < 0)
- return error;
- return put_user(error, argp);
+
+ brightness = pmac_backlight_get_legacy_brightness();
+ if (brightness < 0)
+ return brightness;
+ else
+ return put_user(brightness, argp);
+
+ }
case PMU_IOC_SET_BACKLIGHT:
{
- __u32 value;
+ int brightness;
+
if (sleep_in_progress)
return -EBUSY;
- error = get_user(value, argp);
- if (!error)
- error = set_backlight_level(value);
- break;
+
+ error = get_user(brightness, argp);
+ if (error)
+ return error;
+
+ return pmac_backlight_set_legacy_brightness(brightness);
}
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
struct pmu_private *pp = filp->private_data;
- unsigned long flags;
if (pp->backlight_locker)
return 0;
+
pp->backlight_locker = 1;
- spin_lock_irqsave(&pmu_lock, flags);
- disable_kernel_backlight++;
- spin_unlock_irqrestore(&pmu_lock, flags);
+ pmac_backlight_disable();
+
return 0;
}
#endif /* CONFIG_INPUT_ADBHID */
-#endif /* CONFIG_PMAC_BACKLIGHT */
+#endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
+
case PMU_IOC_GET_MODEL:
return put_user(pmu_kind, argp);
case PMU_IOC_HAS_ADB:
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
index 81337cd16e8..900aade0619 100644
--- a/drivers/macintosh/windfarm_cpufreq_clamp.c
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index f1df6efcbe6..2ff546e4c92 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -396,7 +396,7 @@ static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
static void wf_smu_create_cpu_fans(void)
{
struct wf_cpu_pid_param pid_param;
- struct smu_sdbp_header *hdr;
+ const struct smu_sdbp_header *hdr;
struct smu_sdbp_cpupiddata *piddata;
struct smu_sdbp_fvt *fvt;
s32 tmax, tdelta, maxpow, powadj;
@@ -702,7 +702,7 @@ static struct notifier_block wf_smu_events = {
static int wf_init_pm(void)
{
- struct smu_sdbp_header *hdr;
+ const struct smu_sdbp_header *hdr;
hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
if (hdr != 0) {
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 0d6372e96d3..59e9ffe37c3 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -144,7 +144,7 @@ static struct wf_smu_slots_fans_state *wf_smu_slots_fans;
static void wf_smu_create_cpu_fans(void)
{
struct wf_cpu_pid_param pid_param;
- struct smu_sdbp_header *hdr;
+ const struct smu_sdbp_header *hdr;
struct smu_sdbp_cpupiddata *piddata;
struct smu_sdbp_fvt *fvt;
s32 tmax, tdelta, maxpow, powadj;
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index a9e88edc0c7..bff1f372f18 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -159,14 +159,15 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
int pwm_fan)
{
struct smu_fan_control *fct;
- s32 *v; u32 *reg;
- char *l;
+ const s32 *v;
+ const u32 *reg;
+ const char *l;
fct = kmalloc(sizeof(struct smu_fan_control), GFP_KERNEL);
if (fct == NULL)
return NULL;
fct->ctrl.ops = &smu_fan_ops;
- l = (char *)get_property(node, "location", NULL);
+ l = get_property(node, "location", NULL);
if (l == NULL)
goto fail;
@@ -223,17 +224,17 @@ static struct smu_fan_control *smu_fan_create(struct device_node *node,
goto fail;
/* Get min & max values*/
- v = (s32 *)get_property(node, "min-value", NULL);
+ v = get_property(node, "min-value", NULL);
if (v == NULL)
goto fail;
fct->min = *v;
- v = (s32 *)get_property(node, "max-value", NULL);
+ v = get_property(node, "max-value", NULL);
if (v == NULL)
goto fail;
fct->max = *v;
/* Get "reg" value */
- reg = (u32 *)get_property(node, "reg", NULL);
+ reg = get_property(node, "reg", NULL);
if (reg == NULL)
goto fail;
fct->reg = *reg;
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index e295a07a1eb..83f79de7174 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -233,15 +233,15 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
{
struct wf_sat *sat;
struct wf_sat_sensor *sens;
- u32 *reg;
- char *loc, *type;
+ const u32 *reg;
+ const char *loc, *type;
u8 addr, chip, core;
struct device_node *child;
int shift, cpu, index;
char *name;
int vsens[2], isens[2];
- reg = (u32 *) get_property(dev, "reg", NULL);
+ reg = get_property(dev, "reg", NULL);
if (reg == NULL)
return;
addr = *reg;
@@ -268,7 +268,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev)
isens[0] = isens[1] = -1;
child = NULL;
while ((child = of_get_next_child(dev, child)) != NULL) {
- reg = (u32 *) get_property(child, "reg", NULL);
+ reg = get_property(child, "reg", NULL);
type = get_property(child, "device_type", NULL);
loc = get_property(child, "location", NULL);
if (reg == NULL || loc == NULL)
@@ -397,12 +397,7 @@ static int wf_sat_detach(struct i2c_client *client)
static int __init sat_sensors_init(void)
{
- int err;
-
- err = i2c_add_driver(&wf_sat_driver);
- if (err < 0)
- return err;
- return 0;
+ return i2c_add_driver(&wf_sat_driver);
}
static void __exit sat_sensors_exit(void)
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index bed25dcf8a1..defe9922ebd 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -198,14 +198,14 @@ static struct wf_sensor_ops smu_slotspow_ops = {
static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
{
struct smu_ad_sensor *ads;
- char *c, *l;
- u32 *v;
+ const char *c, *l;
+ const u32 *v;
ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
if (ads == NULL)
return NULL;
- c = (char *)get_property(node, "device_type", NULL);
- l = (char *)get_property(node, "location", NULL);
+ c = get_property(node, "device_type", NULL);
+ l = get_property(node, "location", NULL);
if (c == NULL || l == NULL)
goto fail;
@@ -255,7 +255,7 @@ static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
} else
goto fail;
- v = (u32 *)get_property(node, "reg", NULL);
+ v = get_property(node, "reg", NULL);
if (v == NULL)
goto fail;
ads->reg = *v;
@@ -382,7 +382,7 @@ smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps)
static void smu_fetch_param_partitions(void)
{
- struct smu_sdbp_header *hdr;
+ const struct smu_sdbp_header *hdr;
/* Get CPU voltage/current/power calibration data */
hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL);
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index ac25a48362a..bf869ed03ee 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -90,7 +90,7 @@ config MD_RAID10
depends on BLK_DEV_MD && EXPERIMENTAL
---help---
RAID-10 provides a combination of striping (RAID-0) and
- mirroring (RAID-1) with easier configuration and more flexable
+ mirroring (RAID-1) with easier configuration and more flexible
layout.
Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to
be the same size (or at least, only as much as the smallest device
@@ -104,8 +104,8 @@ config MD_RAID10
If unsure, say Y.
-config MD_RAID5
- tristate "RAID-4/RAID-5 mode"
+config MD_RAID456
+ tristate "RAID-4/RAID-5/RAID-6 mode"
depends on BLK_DEV_MD
---help---
A RAID-5 set of N drives with a capacity of C MB per drive provides
@@ -116,20 +116,28 @@ config MD_RAID5
while a RAID-5 set distributes the parity across the drives in one
of the available parity distribution methods.
+ A RAID-6 set of N drives with a capacity of C MB per drive
+ provides the capacity of C * (N - 2) MB, and protects
+ against a failure of any two drives. For a given sector
+ (row) number, (N - 2) drives contain data sectors, and two
+ drives contains two independent redundancy syndromes. Like
+ RAID-5, RAID-6 distributes the syndromes across the drives
+ in one of the available parity distribution methods.
+
Information about Software RAID on Linux is contained in the
Software-RAID mini-HOWTO, available from
<http://www.tldp.org/docs.html#howto>. There you will also
learn where to get the supporting user space utilities raidtools.
- If you want to use such a RAID-4/RAID-5 set, say Y. To
+ If you want to use such a RAID-4/RAID-5/RAID-6 set, say Y. To
compile this code as a module, choose M here: the module
- will be called raid5.
+ will be called raid456.
If unsure, say Y.
config MD_RAID5_RESHAPE
bool "Support adding drives to a raid-5 array (experimental)"
- depends on MD_RAID5 && EXPERIMENTAL
+ depends on MD_RAID456 && EXPERIMENTAL
---help---
A RAID-5 set can be expanded by adding extra drives. This
requires "restriping" the array which means (almost) every
@@ -139,7 +147,7 @@ config MD_RAID5_RESHAPE
is online. However it is still EXPERIMENTAL code. It should
work, but please be sure that you have backups.
- You will need mdadm verion 2.4.1 or later to use this
+ You will need mdadm version 2.4.1 or later to use this
feature safely. During the early stage of reshape there is
a critical section where live data is being over-written. A
crash during this time needs extra care for recovery. The
@@ -154,28 +162,6 @@ config MD_RAID5_RESHAPE
There should be enough spares already present to make the new
array workable.
-config MD_RAID6
- tristate "RAID-6 mode"
- depends on BLK_DEV_MD
- ---help---
- A RAID-6 set of N drives with a capacity of C MB per drive
- provides the capacity of C * (N - 2) MB, and protects
- against a failure of any two drives. For a given sector
- (row) number, (N - 2) drives contain data sectors, and two
- drives contains two independent redundancy syndromes. Like
- RAID-5, RAID-6 distributes the syndromes across the drives
- in one of the available parity distribution methods.
-
- RAID-6 requires mdadm-1.5.0 or later, available at:
-
- ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/
-
- If you want to use such a RAID-6 set, say Y. To compile
- this code as a module, choose M here: the module will be
- called raid6.
-
- If unsure, say Y.
-
config MD_MULTIPATH
tristate "Multipath I/O support"
depends on BLK_DEV_MD
@@ -235,7 +221,7 @@ config DM_SNAPSHOT
tristate "Snapshot target (EXPERIMENTAL)"
depends on BLK_DEV_DM && EXPERIMENTAL
---help---
- Allow volume managers to take writeable snapshots of a device.
+ Allow volume managers to take writable snapshots of a device.
config DM_MIRROR
tristate "Mirror target (EXPERIMENTAL)"
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index d3efedf6a6a..34957a68d92 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -8,7 +8,7 @@ dm-multipath-objs := dm-hw-handler.o dm-path-selector.o dm-mpath.o
dm-snapshot-objs := dm-snap.o dm-exception-store.o
dm-mirror-objs := dm-log.o dm-raid1.o
md-mod-objs := md.o bitmap.o
-raid6-objs := raid6main.o raid6algos.o raid6recov.o raid6tables.o \
+raid456-objs := raid5.o raid6algos.o raid6recov.o raid6tables.o \
raid6int1.o raid6int2.o raid6int4.o \
raid6int8.o raid6int16.o raid6int32.o \
raid6altivec1.o raid6altivec2.o raid6altivec4.o \
@@ -25,8 +25,7 @@ obj-$(CONFIG_MD_LINEAR) += linear.o
obj-$(CONFIG_MD_RAID0) += raid0.o
obj-$(CONFIG_MD_RAID1) += raid1.o
obj-$(CONFIG_MD_RAID10) += raid10.o
-obj-$(CONFIG_MD_RAID5) += raid5.o xor.o
-obj-$(CONFIG_MD_RAID6) += raid6.o xor.o
+obj-$(CONFIG_MD_RAID456) += raid456.o xor.o
obj-$(CONFIG_MD_MULTIPATH) += multipath.o
obj-$(CONFIG_MD_FAULTY) += faulty.o
obj-$(CONFIG_BLK_DEV_MD) += md-mod.o
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index f8ffaee20ff..ecc56765d94 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -7,7 +7,6 @@
* additions, Copyright (C) 2003-2004, Paul Clements, SteelEye Technology, Inc.:
* - added disk storage for bitmap
* - changes to allow various bitmap chunk sizes
- * - added bitmap daemon (to asynchronously clear bitmap bits from disk)
*/
/*
@@ -15,16 +14,12 @@
*
* flush after percent set rather than just time based. (maybe both).
* wait if count gets too high, wake when it drops to half.
- * allow bitmap to be mirrored with superblock (before or after...)
- * allow hot-add to re-instate a current device.
- * allow hot-add of bitmap after quiessing device
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/list.h>
@@ -73,24 +68,6 @@ static inline char * bmname(struct bitmap *bitmap)
/*
- * test if the bitmap is active
- */
-int bitmap_active(struct bitmap *bitmap)
-{
- unsigned long flags;
- int res = 0;
-
- if (!bitmap)
- return res;
- spin_lock_irqsave(&bitmap->lock, flags);
- res = bitmap->flags & BITMAP_ACTIVE;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- return res;
-}
-
-#define WRITE_POOL_SIZE 256
-
-/*
* just a placeholder - calls kmalloc for bitmap pages
*/
static unsigned char *bitmap_alloc_page(struct bitmap *bitmap)
@@ -269,6 +246,8 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde
if (sync_page_io(rdev->bdev, target, PAGE_SIZE, page, READ)) {
page->index = index;
+ attach_page_buffers(page, NULL); /* so that free_buffer will
+ * quietly no-op */
return page;
}
}
@@ -300,77 +279,132 @@ static int write_sb_page(mddev_t *mddev, long offset, struct page *page, int wai
*/
static int write_page(struct bitmap *bitmap, struct page *page, int wait)
{
- int ret = -ENOMEM;
+ struct buffer_head *bh;
if (bitmap->file == NULL)
return write_sb_page(bitmap->mddev, bitmap->offset, page, wait);
- flush_dcache_page(page); /* make sure visible to anyone reading the file */
+ bh = page_buffers(page);
- if (wait)
- lock_page(page);
- else {
- if (TestSetPageLocked(page))
- return -EAGAIN; /* already locked */
- if (PageWriteback(page)) {
- unlock_page(page);
- return -EAGAIN;
- }
+ while (bh && bh->b_blocknr) {
+ atomic_inc(&bitmap->pending_writes);
+ set_buffer_locked(bh);
+ set_buffer_mapped(bh);
+ submit_bh(WRITE, bh);
+ bh = bh->b_this_page;
}
- ret = page->mapping->a_ops->prepare_write(bitmap->file, page, 0, PAGE_SIZE);
- if (!ret)
- ret = page->mapping->a_ops->commit_write(bitmap->file, page, 0,
- PAGE_SIZE);
- if (ret) {
- unlock_page(page);
- return ret;
+ if (wait) {
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes)==0);
+ return (bitmap->flags & BITMAP_WRITE_ERROR) ? -EIO : 0;
}
+ return 0;
+}
- set_page_dirty(page); /* force it to be written out */
-
- if (!wait) {
- /* add to list to be waited for by daemon */
- struct page_list *item = mempool_alloc(bitmap->write_pool, GFP_NOIO);
- item->page = page;
- get_page(page);
- spin_lock(&bitmap->write_lock);
- list_add(&item->list, &bitmap->complete_pages);
- spin_unlock(&bitmap->write_lock);
- md_wakeup_thread(bitmap->writeback_daemon);
+static void end_bitmap_write(struct buffer_head *bh, int uptodate)
+{
+ struct bitmap *bitmap = bh->b_private;
+ unsigned long flags;
+
+ if (!uptodate) {
+ spin_lock_irqsave(&bitmap->lock, flags);
+ bitmap->flags |= BITMAP_WRITE_ERROR;
+ spin_unlock_irqrestore(&bitmap->lock, flags);
+ }
+ if (atomic_dec_and_test(&bitmap->pending_writes))
+ wake_up(&bitmap->write_wait);
+}
+
+/* copied from buffer.c */
+static void
+__clear_page_buffers(struct page *page)
+{
+ ClearPagePrivate(page);
+ set_page_private(page, 0);
+ page_cache_release(page);
+}
+static void free_buffers(struct page *page)
+{
+ struct buffer_head *bh = page_buffers(page);
+
+ while (bh) {
+ struct buffer_head *next = bh->b_this_page;
+ free_buffer_head(bh);
+ bh = next;
}
- return write_one_page(page, wait);
+ __clear_page_buffers(page);
+ put_page(page);
}
-/* read a page from a file, pinning it into cache, and return bytes_read */
+/* read a page from a file.
+ * We both read the page, and attach buffers to the page to record the
+ * address of each block (using bmap). These addresses will be used
+ * to write the block later, completely bypassing the filesystem.
+ * This usage is similar to how swap files are handled, and allows us
+ * to write to a file with no concerns of memory allocation failing.
+ */
static struct page *read_page(struct file *file, unsigned long index,
- unsigned long *bytes_read)
+ struct bitmap *bitmap,
+ unsigned long count)
{
- struct inode *inode = file->f_mapping->host;
struct page *page = NULL;
- loff_t isize = i_size_read(inode);
- unsigned long end_index = isize >> PAGE_SHIFT;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct buffer_head *bh;
+ sector_t block;
PRINTK("read bitmap file (%dB @ %Lu)\n", (int)PAGE_SIZE,
(unsigned long long)index << PAGE_SHIFT);
- page = read_cache_page(inode->i_mapping, index,
- (filler_t *)inode->i_mapping->a_ops->readpage, file);
+ page = alloc_page(GFP_KERNEL);
+ if (!page)
+ page = ERR_PTR(-ENOMEM);
if (IS_ERR(page))
goto out;
- wait_on_page_locked(page);
- if (!PageUptodate(page) || PageError(page)) {
+
+ bh = alloc_page_buffers(page, 1<<inode->i_blkbits, 0);
+ if (!bh) {
put_page(page);
- page = ERR_PTR(-EIO);
+ page = ERR_PTR(-ENOMEM);
goto out;
}
+ attach_page_buffers(page, bh);
+ block = index << (PAGE_SHIFT - inode->i_blkbits);
+ while (bh) {
+ if (count == 0)
+ bh->b_blocknr = 0;
+ else {
+ bh->b_blocknr = bmap(inode, block);
+ if (bh->b_blocknr == 0) {
+ /* Cannot use this file! */
+ free_buffers(page);
+ page = ERR_PTR(-EINVAL);
+ goto out;
+ }
+ bh->b_bdev = inode->i_sb->s_bdev;
+ if (count < (1<<inode->i_blkbits))
+ count = 0;
+ else
+ count -= (1<<inode->i_blkbits);
+
+ bh->b_end_io = end_bitmap_write;
+ bh->b_private = bitmap;
+ atomic_inc(&bitmap->pending_writes);
+ set_buffer_locked(bh);
+ set_buffer_mapped(bh);
+ submit_bh(READ, bh);
+ }
+ block++;
+ bh = bh->b_this_page;
+ }
+ page->index = index;
- if (index > end_index) /* we have read beyond EOF */
- *bytes_read = 0;
- else if (index == end_index) /* possible short read */
- *bytes_read = isize & ~PAGE_MASK;
- else
- *bytes_read = PAGE_SIZE; /* got a full page */
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes)==0);
+ if (bitmap->flags & BITMAP_WRITE_ERROR) {
+ free_buffers(page);
+ page = ERR_PTR(-EIO);
+ }
out:
if (IS_ERR(page))
printk(KERN_ALERT "md: bitmap read error: (%dB @ %Lu): %ld\n",
@@ -441,16 +475,14 @@ static int bitmap_read_sb(struct bitmap *bitmap)
char *reason = NULL;
bitmap_super_t *sb;
unsigned long chunksize, daemon_sleep, write_behind;
- unsigned long bytes_read;
unsigned long long events;
int err = -EINVAL;
/* page 0 is the superblock, read it... */
if (bitmap->file)
- bitmap->sb_page = read_page(bitmap->file, 0, &bytes_read);
+ bitmap->sb_page = read_page(bitmap->file, 0, bitmap, PAGE_SIZE);
else {
bitmap->sb_page = read_sb_page(bitmap->mddev, bitmap->offset, 0);
- bytes_read = PAGE_SIZE;
}
if (IS_ERR(bitmap->sb_page)) {
err = PTR_ERR(bitmap->sb_page);
@@ -460,13 +492,6 @@ static int bitmap_read_sb(struct bitmap *bitmap)
sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
- if (bytes_read < sizeof(*sb)) { /* short read */
- printk(KERN_INFO "%s: bitmap file superblock truncated\n",
- bmname(bitmap));
- err = -ENOSPC;
- goto out;
- }
-
chunksize = le32_to_cpu(sb->chunksize);
daemon_sleep = le32_to_cpu(sb->daemon_sleep);
write_behind = le32_to_cpu(sb->write_behind);
@@ -550,7 +575,6 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
spin_unlock_irqrestore(&bitmap->lock, flags);
return;
}
- get_page(bitmap->sb_page);
spin_unlock_irqrestore(&bitmap->lock, flags);
sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
switch (op) {
@@ -561,7 +585,6 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
default: BUG();
}
kunmap_atomic(sb, KM_USER0);
- put_page(bitmap->sb_page);
}
/*
@@ -614,48 +637,17 @@ static void bitmap_file_unmap(struct bitmap *bitmap)
while (pages--)
if (map[pages]->index != 0) /* 0 is sb_page, release it below */
- put_page(map[pages]);
+ free_buffers(map[pages]);
kfree(map);
kfree(attr);
- safe_put_page(sb_page);
-}
-
-static void bitmap_stop_daemon(struct bitmap *bitmap);
-
-/* dequeue the next item in a page list -- don't call from irq context */
-static struct page_list *dequeue_page(struct bitmap *bitmap)
-{
- struct page_list *item = NULL;
- struct list_head *head = &bitmap->complete_pages;
-
- spin_lock(&bitmap->write_lock);
- if (list_empty(head))
- goto out;
- item = list_entry(head->prev, struct page_list, list);
- list_del(head->prev);
-out:
- spin_unlock(&bitmap->write_lock);
- return item;
-}
-
-static void drain_write_queues(struct bitmap *bitmap)
-{
- struct page_list *item;
-
- while ((item = dequeue_page(bitmap))) {
- /* don't bother to wait */
- put_page(item->page);
- mempool_free(item, bitmap->write_pool);
- }
-
- wake_up(&bitmap->write_wait);
+ if (sb_page)
+ free_buffers(sb_page);
}
static void bitmap_file_put(struct bitmap *bitmap)
{
struct file *file;
- struct inode *inode;
unsigned long flags;
spin_lock_irqsave(&bitmap->lock, flags);
@@ -663,17 +655,14 @@ static void bitmap_file_put(struct bitmap *bitmap)
bitmap->file = NULL;
spin_unlock_irqrestore(&bitmap->lock, flags);
- bitmap_stop_daemon(bitmap);
-
- drain_write_queues(bitmap);
-
+ if (file)
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes)==0);
bitmap_file_unmap(bitmap);
if (file) {
- inode = file->f_mapping->host;
- spin_lock(&inode->i_lock);
- atomic_set(&inode->i_writecount, 1); /* allow writes again */
- spin_unlock(&inode->i_lock);
+ struct inode *inode = file->f_dentry->d_inode;
+ invalidate_inode_pages(inode->i_mapping);
fput(file);
}
}
@@ -708,26 +697,27 @@ static void bitmap_file_kick(struct bitmap *bitmap)
}
enum bitmap_page_attr {
- BITMAP_PAGE_DIRTY = 1, // there are set bits that need to be synced
- BITMAP_PAGE_CLEAN = 2, // there are bits that might need to be cleared
- BITMAP_PAGE_NEEDWRITE=4, // there are cleared bits that need to be synced
+ BITMAP_PAGE_DIRTY = 0, // there are set bits that need to be synced
+ BITMAP_PAGE_CLEAN = 1, // there are bits that might need to be cleared
+ BITMAP_PAGE_NEEDWRITE=2, // there are cleared bits that need to be synced
};
static inline void set_page_attr(struct bitmap *bitmap, struct page *page,
enum bitmap_page_attr attr)
{
- bitmap->filemap_attr[page->index] |= attr;
+ __set_bit((page->index<<2) + attr, bitmap->filemap_attr);
}
static inline void clear_page_attr(struct bitmap *bitmap, struct page *page,
enum bitmap_page_attr attr)
{
- bitmap->filemap_attr[page->index] &= ~attr;
+ __clear_bit((page->index<<2) + attr, bitmap->filemap_attr);
}
-static inline unsigned long get_page_attr(struct bitmap *bitmap, struct page *page)
+static inline unsigned long test_page_attr(struct bitmap *bitmap, struct page *page,
+ enum bitmap_page_attr attr)
{
- return bitmap->filemap_attr[page->index];
+ return test_bit((page->index<<2) + attr, bitmap->filemap_attr);
}
/*
@@ -751,11 +741,6 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
page = filemap_get_page(bitmap, chunk);
bit = file_page_offset(chunk);
-
- /* make sure the page stays cached until it gets written out */
- if (! (get_page_attr(bitmap, page) & BITMAP_PAGE_DIRTY))
- get_page(page);
-
/* set the bit */
kaddr = kmap_atomic(page, KM_USER0);
if (bitmap->flags & BITMAP_HOSTENDIAN)
@@ -775,7 +760,8 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
* sync the dirty pages of the bitmap file to disk */
int bitmap_unplug(struct bitmap *bitmap)
{
- unsigned long i, attr, flags;
+ unsigned long i, flags;
+ int dirty, need_write;
struct page *page;
int wait = 0;
int err;
@@ -792,35 +778,26 @@ int bitmap_unplug(struct bitmap *bitmap)
return 0;
}
page = bitmap->filemap[i];
- attr = get_page_attr(bitmap, page);
+ dirty = test_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
+ need_write = test_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
clear_page_attr(bitmap, page, BITMAP_PAGE_DIRTY);
clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
- if ((attr & BITMAP_PAGE_DIRTY))
+ if (dirty)
wait = 1;
spin_unlock_irqrestore(&bitmap->lock, flags);
- if (attr & (BITMAP_PAGE_DIRTY | BITMAP_PAGE_NEEDWRITE)) {
+ if (dirty | need_write)
err = write_page(bitmap, page, 0);
- if (err == -EAGAIN) {
- if (attr & BITMAP_PAGE_DIRTY)
- err = write_page(bitmap, page, 1);
- else
- err = 0;
- }
- if (err)
- return 1;
- }
}
if (wait) { /* if any writes were performed, we need to wait on them */
- if (bitmap->file) {
- spin_lock_irq(&bitmap->write_lock);
- wait_event_lock_irq(bitmap->write_wait,
- list_empty(&bitmap->complete_pages), bitmap->write_lock,
- wake_up_process(bitmap->writeback_daemon->tsk));
- spin_unlock_irq(&bitmap->write_lock);
- } else
+ if (bitmap->file)
+ wait_event(bitmap->write_wait,
+ atomic_read(&bitmap->pending_writes)==0);
+ else
md_super_wait(bitmap->mddev);
}
+ if (bitmap->flags & BITMAP_WRITE_ERROR)
+ bitmap_file_kick(bitmap);
return 0;
}
@@ -842,7 +819,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
struct page *page = NULL, *oldpage = NULL;
unsigned long num_pages, bit_cnt = 0;
struct file *file;
- unsigned long bytes, offset, dummy;
+ unsigned long bytes, offset;
int outofdate;
int ret = -ENOSPC;
void *paddr;
@@ -879,7 +856,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
if (!bitmap->filemap)
goto out;
- bitmap->filemap_attr = kzalloc(sizeof(long) * num_pages, GFP_KERNEL);
+ /* We need 4 bits per page, rounded up to a multiple of sizeof(unsigned long) */
+ bitmap->filemap_attr = kzalloc(
+ (((num_pages*4/8)+sizeof(unsigned long)-1)
+ /sizeof(unsigned long))
+ *sizeof(unsigned long),
+ GFP_KERNEL);
if (!bitmap->filemap_attr)
goto out;
@@ -890,7 +872,12 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
index = file_page_index(i);
bit = file_page_offset(i);
if (index != oldindex) { /* this is a new page, read it in */
+ int count;
/* unmap the old page, we're done with it */
+ if (index == num_pages-1)
+ count = bytes - index * PAGE_SIZE;
+ else
+ count = PAGE_SIZE;
if (index == 0) {
/*
* if we're here then the superblock page
@@ -900,7 +887,7 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start)
page = bitmap->sb_page;
offset = sizeof(bitmap_super_t);
} else if (file) {
- page = read_page(file, index, &dummy);
+ page = read_page(file, index, bitmap, count);
offset = 0;
} else {
page = read_sb_page(bitmap->mddev, bitmap->offset, index);
@@ -971,12 +958,11 @@ void bitmap_write_all(struct bitmap *bitmap)
/* We don't actually write all bitmap blocks here,
* just flag them as needing to be written
*/
+ int i;
- unsigned long chunks = bitmap->chunks;
- unsigned long bytes = (chunks+7)/8 + sizeof(bitmap_super_t);
- unsigned long num_pages = (bytes + PAGE_SIZE-1) / PAGE_SIZE;
- while (num_pages--)
- bitmap->filemap_attr[num_pages] |= BITMAP_PAGE_NEEDWRITE;
+ for (i=0; i < bitmap->file_pages; i++)
+ set_page_attr(bitmap, bitmap->filemap[i],
+ BITMAP_PAGE_NEEDWRITE);
}
@@ -1007,7 +993,6 @@ int bitmap_daemon_work(struct bitmap *bitmap)
struct page *page = NULL, *lastpage = NULL;
int err = 0;
int blocks;
- int attr;
void *paddr;
if (bitmap == NULL)
@@ -1029,43 +1014,34 @@ int bitmap_daemon_work(struct bitmap *bitmap)
if (page != lastpage) {
/* skip this page unless it's marked as needing cleaning */
- if (!((attr=get_page_attr(bitmap, page)) & BITMAP_PAGE_CLEAN)) {
- if (attr & BITMAP_PAGE_NEEDWRITE) {
- get_page(page);
+ if (!test_page_attr(bitmap, page, BITMAP_PAGE_CLEAN)) {
+ int need_write = test_page_attr(bitmap, page,
+ BITMAP_PAGE_NEEDWRITE);
+ if (need_write)
clear_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
- }
+
spin_unlock_irqrestore(&bitmap->lock, flags);
- if (attr & BITMAP_PAGE_NEEDWRITE) {
+ if (need_write) {
switch (write_page(bitmap, page, 0)) {
- case -EAGAIN:
- set_page_attr(bitmap, page, BITMAP_PAGE_NEEDWRITE);
- break;
case 0:
break;
default:
bitmap_file_kick(bitmap);
}
- put_page(page);
}
continue;
}
/* grab the new page, sync and release the old */
- get_page(page);
if (lastpage != NULL) {
- if (get_page_attr(bitmap, lastpage) & BITMAP_PAGE_NEEDWRITE) {
+ if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
err = write_page(bitmap, lastpage, 0);
- if (err == -EAGAIN) {
- err = 0;
- set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
- }
} else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
}
- put_page(lastpage);
if (err)
bitmap_file_kick(bitmap);
} else
@@ -1107,131 +1083,19 @@ int bitmap_daemon_work(struct bitmap *bitmap)
/* now sync the final page */
if (lastpage != NULL) {
spin_lock_irqsave(&bitmap->lock, flags);
- if (get_page_attr(bitmap, lastpage) &BITMAP_PAGE_NEEDWRITE) {
+ if (test_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE)) {
clear_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
err = write_page(bitmap, lastpage, 0);
- if (err == -EAGAIN) {
- set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
- err = 0;
- }
} else {
set_page_attr(bitmap, lastpage, BITMAP_PAGE_NEEDWRITE);
spin_unlock_irqrestore(&bitmap->lock, flags);
}
-
- put_page(lastpage);
}
return err;
}
-static void daemon_exit(struct bitmap *bitmap, mdk_thread_t **daemon)
-{
- mdk_thread_t *dmn;
- unsigned long flags;
-
- /* if no one is waiting on us, we'll free the md thread struct
- * and exit, otherwise we let the waiter clean things up */
- spin_lock_irqsave(&bitmap->lock, flags);
- if ((dmn = *daemon)) { /* no one is waiting, cleanup and exit */
- *daemon = NULL;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- kfree(dmn);
- complete_and_exit(NULL, 0); /* do_exit not exported */
- }
- spin_unlock_irqrestore(&bitmap->lock, flags);
-}
-
-static void bitmap_writeback_daemon(mddev_t *mddev)
-{
- struct bitmap *bitmap = mddev->bitmap;
- struct page *page;
- struct page_list *item;
- int err = 0;
-
- if (signal_pending(current)) {
- printk(KERN_INFO
- "%s: bitmap writeback daemon got signal, exiting...\n",
- bmname(bitmap));
- err = -EINTR;
- goto out;
- }
- if (bitmap == NULL)
- /* about to be stopped. */
- return;
-
- PRINTK("%s: bitmap writeback daemon woke up...\n", bmname(bitmap));
- /* wait on bitmap page writebacks */
- while ((item = dequeue_page(bitmap))) {
- page = item->page;
- mempool_free(item, bitmap->write_pool);
- PRINTK("wait on page writeback: %p\n", page);
- wait_on_page_writeback(page);
- PRINTK("finished page writeback: %p\n", page);
-
- err = PageError(page);
- put_page(page);
- if (err) {
- printk(KERN_WARNING "%s: bitmap file writeback "
- "failed (page %lu): %d\n",
- bmname(bitmap), page->index, err);
- bitmap_file_kick(bitmap);
- goto out;
- }
- }
- out:
- wake_up(&bitmap->write_wait);
- if (err) {
- printk(KERN_INFO "%s: bitmap writeback daemon exiting (%d)\n",
- bmname(bitmap), err);
- daemon_exit(bitmap, &bitmap->writeback_daemon);
- }
-}
-
-static mdk_thread_t *bitmap_start_daemon(struct bitmap *bitmap,
- void (*func)(mddev_t *), char *name)
-{
- mdk_thread_t *daemon;
- char namebuf[32];
-
-#ifdef INJECT_FATAL_FAULT_2
- daemon = NULL;
-#else
- sprintf(namebuf, "%%s_%s", name);
- daemon = md_register_thread(func, bitmap->mddev, namebuf);
-#endif
- if (!daemon) {
- printk(KERN_ERR "%s: failed to start bitmap daemon\n",
- bmname(bitmap));
- return ERR_PTR(-ECHILD);
- }
-
- md_wakeup_thread(daemon); /* start it running */
-
- PRINTK("%s: %s daemon (pid %d) started...\n",
- bmname(bitmap), name, daemon->tsk->pid);
-
- return daemon;
-}
-
-static void bitmap_stop_daemon(struct bitmap *bitmap)
-{
- /* the daemon can't stop itself... it'll just exit instead... */
- if (bitmap->writeback_daemon && ! IS_ERR(bitmap->writeback_daemon) &&
- current->pid != bitmap->writeback_daemon->tsk->pid) {
- mdk_thread_t *daemon;
- unsigned long flags;
-
- spin_lock_irqsave(&bitmap->lock, flags);
- daemon = bitmap->writeback_daemon;
- bitmap->writeback_daemon = NULL;
- spin_unlock_irqrestore(&bitmap->lock, flags);
- if (daemon && ! IS_ERR(daemon))
- md_unregister_thread(daemon); /* destroy the thread */
- }
-}
-
static bitmap_counter_t *bitmap_get_counter(struct bitmap *bitmap,
sector_t offset, int *blocks,
int create)
@@ -1500,8 +1364,6 @@ static void bitmap_free(struct bitmap *bitmap)
/* free all allocated memory */
- mempool_destroy(bitmap->write_pool);
-
if (bp) /* deallocate the page memory */
for (k = 0; k < pages; k++)
if (bp[k].map && !bp[k].hijacked)
@@ -1549,20 +1411,20 @@ int bitmap_create(mddev_t *mddev)
return -ENOMEM;
spin_lock_init(&bitmap->lock);
- bitmap->mddev = mddev;
-
- spin_lock_init(&bitmap->write_lock);
- INIT_LIST_HEAD(&bitmap->complete_pages);
+ atomic_set(&bitmap->pending_writes, 0);
init_waitqueue_head(&bitmap->write_wait);
- bitmap->write_pool = mempool_create_kmalloc_pool(WRITE_POOL_SIZE,
- sizeof(struct page_list));
- err = -ENOMEM;
- if (!bitmap->write_pool)
- goto error;
+
+ bitmap->mddev = mddev;
bitmap->file = file;
bitmap->offset = mddev->bitmap_offset;
- if (file) get_file(file);
+ if (file) {
+ get_file(file);
+ do_sync_file_range(file, 0, LLONG_MAX,
+ SYNC_FILE_RANGE_WAIT_BEFORE |
+ SYNC_FILE_RANGE_WRITE |
+ SYNC_FILE_RANGE_WAIT_AFTER);
+ }
/* read superblock from bitmap file (this sets bitmap->chunksize) */
err = bitmap_read_sb(bitmap);
if (err)
@@ -1594,8 +1456,6 @@ int bitmap_create(mddev_t *mddev)
if (!bitmap->bp)
goto error;
- bitmap->flags |= BITMAP_ACTIVE;
-
/* now that we have some pages available, initialize the in-memory
* bitmap from the on-disk bitmap */
start = 0;
@@ -1613,15 +1473,6 @@ int bitmap_create(mddev_t *mddev)
mddev->bitmap = bitmap;
- if (file)
- /* kick off the bitmap writeback daemon */
- bitmap->writeback_daemon =
- bitmap_start_daemon(bitmap,
- bitmap_writeback_daemon,
- "bitmap_wb");
-
- if (IS_ERR(bitmap->writeback_daemon))
- return PTR_ERR(bitmap->writeback_daemon);
mddev->thread->timeout = bitmap->daemon_sleep * HZ;
return bitmap_update_sb(bitmap);
@@ -1638,4 +1489,3 @@ EXPORT_SYMBOL(bitmap_start_sync);
EXPORT_SYMBOL(bitmap_end_sync);
EXPORT_SYMBOL(bitmap_unplug);
EXPORT_SYMBOL(bitmap_close_sync);
-EXPORT_SYMBOL(bitmap_daemon_work);
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 61a590bb624..bdbd34993a8 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -5,6 +5,7 @@
* This file is released under the GPL.
*/
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -20,7 +21,7 @@
#include "dm.h"
-#define PFX "crypt: "
+#define DM_MSG_PREFIX "crypt"
/*
* per bio private data
@@ -78,11 +79,13 @@ struct crypt_config {
*/
struct crypt_iv_operations *iv_gen_ops;
char *iv_mode;
- void *iv_gen_private;
+ struct crypto_cipher *iv_gen_private;
sector_t iv_offset;
unsigned int iv_size;
- struct crypto_tfm *tfm;
+ char cipher[CRYPTO_MAX_ALG_NAME];
+ char chainmode[CRYPTO_MAX_ALG_NAME];
+ struct crypto_blkcipher *tfm;
unsigned int key_size;
u8 key[0];
};
@@ -96,12 +99,12 @@ static kmem_cache_t *_crypt_io_pool;
/*
* Different IV generation algorithms:
*
- * plain: the initial vector is the 32-bit low-endian version of the sector
+ * plain: the initial vector is the 32-bit little-endian version of the sector
* number, padded with zeros if neccessary.
*
- * ess_iv: "encrypted sector|salt initial vector", the sector number is
- * encrypted with the bulk cipher using a salt as key. The salt
- * should be derived from the bulk cipher's key via hashing.
+ * essiv: "encrypted sector|salt initial vector", the sector number is
+ * encrypted with the bulk cipher using a salt as key. The salt
+ * should be derived from the bulk cipher's key via hashing.
*
* plumb: unimplemented, see:
* http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
@@ -118,88 +121,84 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti,
const char *opts)
{
- struct crypto_tfm *essiv_tfm;
- struct crypto_tfm *hash_tfm;
+ struct crypto_cipher *essiv_tfm;
+ struct crypto_hash *hash_tfm;
+ struct hash_desc desc;
struct scatterlist sg;
unsigned int saltsize;
u8 *salt;
+ int err;
if (opts == NULL) {
- ti->error = PFX "Digest algorithm missing for ESSIV mode";
+ ti->error = "Digest algorithm missing for ESSIV mode";
return -EINVAL;
}
/* Hash the cipher key with the given hash algorithm */
- hash_tfm = crypto_alloc_tfm(opts, CRYPTO_TFM_REQ_MAY_SLEEP);
- if (hash_tfm == NULL) {
- ti->error = PFX "Error initializing ESSIV hash";
- return -EINVAL;
+ hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(hash_tfm)) {
+ ti->error = "Error initializing ESSIV hash";
+ return PTR_ERR(hash_tfm);
}
- if (crypto_tfm_alg_type(hash_tfm) != CRYPTO_ALG_TYPE_DIGEST) {
- ti->error = PFX "Expected digest algorithm for ESSIV hash";
- crypto_free_tfm(hash_tfm);
- return -EINVAL;
- }
-
- saltsize = crypto_tfm_alg_digestsize(hash_tfm);
+ saltsize = crypto_hash_digestsize(hash_tfm);
salt = kmalloc(saltsize, GFP_KERNEL);
if (salt == NULL) {
- ti->error = PFX "Error kmallocing salt storage in ESSIV";
- crypto_free_tfm(hash_tfm);
+ ti->error = "Error kmallocing salt storage in ESSIV";
+ crypto_free_hash(hash_tfm);
return -ENOMEM;
}
sg_set_buf(&sg, cc->key, cc->key_size);
- crypto_digest_digest(hash_tfm, &sg, 1, salt);
- crypto_free_tfm(hash_tfm);
+ desc.tfm = hash_tfm;
+ desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+ err = crypto_hash_digest(&desc, &sg, cc->key_size, salt);
+ crypto_free_hash(hash_tfm);
+
+ if (err) {
+ ti->error = "Error calculating hash in ESSIV";
+ return err;
+ }
/* Setup the essiv_tfm with the given salt */
- essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm),
- CRYPTO_TFM_MODE_ECB |
- CRYPTO_TFM_REQ_MAY_SLEEP);
- if (essiv_tfm == NULL) {
- ti->error = PFX "Error allocating crypto tfm for ESSIV";
+ essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(essiv_tfm)) {
+ ti->error = "Error allocating crypto tfm for ESSIV";
kfree(salt);
- return -EINVAL;
+ return PTR_ERR(essiv_tfm);
}
- if (crypto_tfm_alg_blocksize(essiv_tfm)
- != crypto_tfm_alg_ivsize(cc->tfm)) {
- ti->error = PFX "Block size of ESSIV cipher does "
+ if (crypto_cipher_blocksize(essiv_tfm) !=
+ crypto_blkcipher_ivsize(cc->tfm)) {
+ ti->error = "Block size of ESSIV cipher does "
"not match IV size of block cipher";
- crypto_free_tfm(essiv_tfm);
+ crypto_free_cipher(essiv_tfm);
kfree(salt);
return -EINVAL;
}
- if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) {
- ti->error = PFX "Failed to set key for ESSIV cipher";
- crypto_free_tfm(essiv_tfm);
+ err = crypto_cipher_setkey(essiv_tfm, salt, saltsize);
+ if (err) {
+ ti->error = "Failed to set key for ESSIV cipher";
+ crypto_free_cipher(essiv_tfm);
kfree(salt);
- return -EINVAL;
+ return err;
}
kfree(salt);
- cc->iv_gen_private = (void *)essiv_tfm;
+ cc->iv_gen_private = essiv_tfm;
return 0;
}
static void crypt_iv_essiv_dtr(struct crypt_config *cc)
{
- crypto_free_tfm((struct crypto_tfm *)cc->iv_gen_private);
+ crypto_free_cipher(cc->iv_gen_private);
cc->iv_gen_private = NULL;
}
static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector)
{
- struct scatterlist sg;
-
memset(iv, 0, cc->iv_size);
*(u64 *)iv = cpu_to_le64(sector);
-
- sg_set_buf(&sg, iv, cc->iv_size);
- crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private,
- &sg, &sg, cc->iv_size);
-
+ crypto_cipher_encrypt_one(cc->iv_gen_private, iv, iv);
return 0;
}
@@ -220,6 +219,11 @@ crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
int write, sector_t sector)
{
u8 iv[cc->iv_size];
+ struct blkcipher_desc desc = {
+ .tfm = cc->tfm,
+ .info = iv,
+ .flags = CRYPTO_TFM_REQ_MAY_SLEEP,
+ };
int r;
if (cc->iv_gen_ops) {
@@ -228,14 +232,14 @@ crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
return r;
if (write)
- r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length, iv);
+ r = crypto_blkcipher_encrypt_iv(&desc, out, in, length);
else
- r = crypto_cipher_decrypt_iv(cc->tfm, out, in, length, iv);
+ r = crypto_blkcipher_decrypt_iv(&desc, out, in, length);
} else {
if (write)
- r = crypto_cipher_encrypt(cc->tfm, out, in, length);
+ r = crypto_blkcipher_encrypt(&desc, out, in, length);
else
- r = crypto_cipher_decrypt(cc->tfm, out, in, length);
+ r = crypto_blkcipher_decrypt(&desc, out, in, length);
}
return r;
@@ -510,18 +514,17 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct crypt_config *cc;
- struct crypto_tfm *tfm;
+ struct crypto_blkcipher *tfm;
char *tmp;
char *cipher;
char *chainmode;
char *ivmode;
char *ivopts;
- unsigned int crypto_flags;
unsigned int key_size;
unsigned long long tmpll;
if (argc != 5) {
- ti->error = PFX "Not enough arguments";
+ ti->error = "Not enough arguments";
return -EINVAL;
}
@@ -532,21 +535,21 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ivmode = strsep(&ivopts, ":");
if (tmp)
- DMWARN(PFX "Unexpected additional cipher options");
+ DMWARN("Unexpected additional cipher options");
key_size = strlen(argv[1]) >> 1;
cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
if (cc == NULL) {
ti->error =
- PFX "Cannot allocate transparent encryption context";
+ "Cannot allocate transparent encryption context";
return -ENOMEM;
}
cc->key_size = key_size;
if ((!key_size && strcmp(argv[1], "-") != 0) ||
(key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
- ti->error = PFX "Error decoding key";
+ ti->error = "Error decoding key";
goto bad1;
}
@@ -556,31 +559,25 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ivmode = "plain";
}
- /* Choose crypto_flags according to chainmode */
- if (strcmp(chainmode, "cbc") == 0)
- crypto_flags = CRYPTO_TFM_MODE_CBC;
- else if (strcmp(chainmode, "ecb") == 0)
- crypto_flags = CRYPTO_TFM_MODE_ECB;
- else {
- ti->error = PFX "Unknown chaining mode";
+ if (strcmp(chainmode, "ecb") && !ivmode) {
+ ti->error = "This chaining mode requires an IV mechanism";
goto bad1;
}
- if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) {
- ti->error = PFX "This chaining mode requires an IV mechanism";
+ if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", chainmode,
+ cipher) >= CRYPTO_MAX_ALG_NAME) {
+ ti->error = "Chain mode + cipher name is too long";
goto bad1;
}
- tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP);
- if (!tfm) {
- ti->error = PFX "Error allocating crypto tfm";
+ tfm = crypto_alloc_blkcipher(cc->cipher, 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(tfm)) {
+ ti->error = "Error allocating crypto tfm";
goto bad1;
}
- if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) {
- ti->error = PFX "Expected cipher algorithm";
- goto bad2;
- }
+ strcpy(cc->cipher, cipher);
+ strcpy(cc->chainmode, chainmode);
cc->tfm = tfm;
/*
@@ -595,7 +592,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
else if (strcmp(ivmode, "essiv") == 0)
cc->iv_gen_ops = &crypt_iv_essiv_ops;
else {
- ti->error = PFX "Invalid IV mode";
+ ti->error = "Invalid IV mode";
goto bad2;
}
@@ -603,14 +600,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0)
goto bad2;
- if (tfm->crt_cipher.cit_decrypt_iv && tfm->crt_cipher.cit_encrypt_iv)
+ cc->iv_size = crypto_blkcipher_ivsize(tfm);
+ if (cc->iv_size)
/* at least a 64 bit sector number should fit in our buffer */
- cc->iv_size = max(crypto_tfm_alg_ivsize(tfm),
+ cc->iv_size = max(cc->iv_size,
(unsigned int)(sizeof(u64) / sizeof(u8)));
else {
- cc->iv_size = 0;
if (cc->iv_gen_ops) {
- DMWARN(PFX "Selected cipher does not support IVs");
+ DMWARN("Selected cipher does not support IVs");
if (cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
cc->iv_gen_ops = NULL;
@@ -619,36 +616,36 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
if (!cc->io_pool) {
- ti->error = PFX "Cannot allocate crypt io mempool";
+ ti->error = "Cannot allocate crypt io mempool";
goto bad3;
}
cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
if (!cc->page_pool) {
- ti->error = PFX "Cannot allocate page mempool";
+ ti->error = "Cannot allocate page mempool";
goto bad4;
}
- if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
- ti->error = PFX "Error setting key";
+ if (crypto_blkcipher_setkey(tfm, cc->key, key_size) < 0) {
+ ti->error = "Error setting key";
goto bad5;
}
if (sscanf(argv[2], "%llu", &tmpll) != 1) {
- ti->error = PFX "Invalid iv_offset sector";
+ ti->error = "Invalid iv_offset sector";
goto bad5;
}
cc->iv_offset = tmpll;
if (sscanf(argv[4], "%llu", &tmpll) != 1) {
- ti->error = PFX "Invalid device sector";
+ ti->error = "Invalid device sector";
goto bad5;
}
cc->start = tmpll;
if (dm_get_device(ti, argv[3], cc->start, ti->len,
dm_table_get_mode(ti->table), &cc->dev)) {
- ti->error = PFX "Device lookup failed";
+ ti->error = "Device lookup failed";
goto bad5;
}
@@ -657,7 +654,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
*(ivopts - 1) = ':';
cc->iv_mode = kmalloc(strlen(ivmode) + 1, GFP_KERNEL);
if (!cc->iv_mode) {
- ti->error = PFX "Error kmallocing iv_mode string";
+ ti->error = "Error kmallocing iv_mode string";
goto bad5;
}
strcpy(cc->iv_mode, ivmode);
@@ -675,7 +672,7 @@ bad3:
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
bad2:
- crypto_free_tfm(tfm);
+ crypto_free_blkcipher(tfm);
bad1:
/* Must zero key material before freeing */
memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8));
@@ -693,7 +690,7 @@ static void crypt_dtr(struct dm_target *ti)
kfree(cc->iv_mode);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
- crypto_free_tfm(cc->tfm);
+ crypto_free_blkcipher(cc->tfm);
dm_put_device(ti, cc->dev);
/* Must zero key material before freeing */
@@ -858,18 +855,9 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
break;
case STATUSTYPE_TABLE:
- cipher = crypto_tfm_alg_name(cc->tfm);
+ cipher = crypto_blkcipher_name(cc->tfm);
- switch(cc->tfm->crt_cipher.cit_mode) {
- case CRYPTO_TFM_MODE_CBC:
- chainmode = "cbc";
- break;
- case CRYPTO_TFM_MODE_ECB:
- chainmode = "ecb";
- break;
- default:
- BUG();
- }
+ chainmode = cc->chainmode;
if (cc->iv_mode)
DMEMIT("%s-%s-%s ", cipher, chainmode, cc->iv_mode);
@@ -918,13 +906,13 @@ static int __init dm_crypt_init(void)
_kcryptd_workqueue = create_workqueue("kcryptd");
if (!_kcryptd_workqueue) {
r = -ENOMEM;
- DMERR(PFX "couldn't create kcryptd");
+ DMERR("couldn't create kcryptd");
goto bad1;
}
r = dm_register_target(&crypt_target);
if (r < 0) {
- DMERR(PFX "register failed %d", r);
+ DMERR("register failed %d", r);
goto bad2;
}
@@ -942,7 +930,7 @@ static void __exit dm_crypt_exit(void)
int r = dm_unregister_target(&crypt_target);
if (r < 0)
- DMERR(PFX "unregister failed %d", r);
+ DMERR("unregister failed %d", r);
destroy_workqueue(_kcryptd_workqueue);
kmem_cache_destroy(_crypt_io_pool);
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index c7067674dcb..2a374ccb30d 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -12,6 +12,8 @@
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
+#define DM_MSG_PREFIX "multipath emc"
+
struct emc_handler {
spinlock_t lock;
@@ -66,7 +68,7 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size)
bio = bio_alloc(GFP_ATOMIC, 1);
if (!bio) {
- DMERR("dm-emc: get_failover_bio: bio_alloc() failed.");
+ DMERR("get_failover_bio: bio_alloc() failed.");
return NULL;
}
@@ -78,13 +80,13 @@ static struct bio *get_failover_bio(struct path *path, unsigned data_size)
page = alloc_page(GFP_ATOMIC);
if (!page) {
- DMERR("dm-emc: get_failover_bio: alloc_page() failed.");
+ DMERR("get_failover_bio: alloc_page() failed.");
bio_put(bio);
return NULL;
}
if (bio_add_page(bio, page, data_size, 0) != data_size) {
- DMERR("dm-emc: get_failover_bio: alloc_page() failed.");
+ DMERR("get_failover_bio: alloc_page() failed.");
__free_page(page);
bio_put(bio);
return NULL;
@@ -103,7 +105,7 @@ static struct request *get_failover_req(struct emc_handler *h,
/* FIXME: Figure out why it fails with GFP_ATOMIC. */
rq = blk_get_request(q, WRITE, __GFP_WAIT);
if (!rq) {
- DMERR("dm-emc: get_failover_req: blk_get_request failed");
+ DMERR("get_failover_req: blk_get_request failed");
return NULL;
}
@@ -160,7 +162,7 @@ static struct request *emc_trespass_get(struct emc_handler *h,
bio = get_failover_bio(path, data_size);
if (!bio) {
- DMERR("dm-emc: emc_trespass_get: no bio");
+ DMERR("emc_trespass_get: no bio");
return NULL;
}
@@ -173,7 +175,7 @@ static struct request *emc_trespass_get(struct emc_handler *h,
/* get request for block layer packet command */
rq = get_failover_req(h, bio, path);
if (!rq) {
- DMERR("dm-emc: emc_trespass_get: no rq");
+ DMERR("emc_trespass_get: no rq");
free_bio(bio);
return NULL;
}
@@ -200,18 +202,18 @@ static void emc_pg_init(struct hw_handler *hwh, unsigned bypassed,
* initial state passed into us and then get an update here.
*/
if (!q) {
- DMINFO("dm-emc: emc_pg_init: no queue");
+ DMINFO("emc_pg_init: no queue");
goto fail_path;
}
/* FIXME: The request should be pre-allocated. */
rq = emc_trespass_get(hwh->context, path);
if (!rq) {
- DMERR("dm-emc: emc_pg_init: no rq");
+ DMERR("emc_pg_init: no rq");
goto fail_path;
}
- DMINFO("dm-emc: emc_pg_init: sending switch-over command");
+ DMINFO("emc_pg_init: sending switch-over command");
elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 1);
return;
@@ -241,18 +243,18 @@ static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv)
hr = 0;
short_trespass = 0;
} else if (argc != 2) {
- DMWARN("dm-emc hwhandler: incorrect number of arguments");
+ DMWARN("incorrect number of arguments");
return -EINVAL;
} else {
if ((sscanf(argv[0], "%u", &short_trespass) != 1)
|| (short_trespass > 1)) {
- DMWARN("dm-emc: invalid trespass mode selected");
+ DMWARN("invalid trespass mode selected");
return -EINVAL;
}
if ((sscanf(argv[1], "%u", &hr) != 1)
|| (hr > 1)) {
- DMWARN("dm-emc: invalid honor reservation flag selected");
+ DMWARN("invalid honor reservation flag selected");
return -EINVAL;
}
}
@@ -264,14 +266,14 @@ static int emc_create(struct hw_handler *hwh, unsigned argc, char **argv)
hwh->context = h;
if ((h->short_trespass = short_trespass))
- DMWARN("dm-emc: short trespass command will be send");
+ DMWARN("short trespass command will be send");
else
- DMWARN("dm-emc: long trespass command will be send");
+ DMWARN("long trespass command will be send");
if ((h->hr = hr))
- DMWARN("dm-emc: honor reservation bit will be set");
+ DMWARN("honor reservation bit will be set");
else
- DMWARN("dm-emc: honor reservation bit will not be set (default)");
+ DMWARN("honor reservation bit will not be set (default)");
return 0;
}
@@ -336,9 +338,9 @@ static int __init dm_emc_init(void)
int r = dm_register_hw_handler(&emc_hwh);
if (r < 0)
- DMERR("emc: register failed %d", r);
+ DMERR("register failed %d", r);
- DMINFO("dm-emc version 0.0.3 loaded");
+ DMINFO("version 0.0.3 loaded");
return r;
}
@@ -348,7 +350,7 @@ static void __exit dm_emc_exit(void)
int r = dm_unregister_hw_handler(&emc_hwh);
if (r < 0)
- DMERR("emc: unregister failed %d", r);
+ DMERR("unregister failed %d", r);
}
module_init(dm_emc_init);
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index cc07bbebbb1..d12379b5cdb 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -16,6 +16,8 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
+#define DM_MSG_PREFIX "snapshots"
+
/*-----------------------------------------------------------------
* Persistent snapshots, by persistent we mean that the snapshot
* will survive a reboot.
@@ -91,7 +93,6 @@ struct pstore {
struct dm_snapshot *snap; /* up pointer to my snapshot */
int version;
int valid;
- uint32_t chunk_size;
uint32_t exceptions_per_area;
/*
@@ -133,7 +134,7 @@ static int alloc_area(struct pstore *ps)
int r = -ENOMEM;
size_t len;
- len = ps->chunk_size << SECTOR_SHIFT;
+ len = ps->snap->chunk_size << SECTOR_SHIFT;
/*
* Allocate the chunk_size block of memory that will hold
@@ -160,8 +161,8 @@ static int chunk_io(struct pstore *ps, uint32_t chunk, int rw)
unsigned long bits;
where.bdev = ps->snap->cow->bdev;
- where.sector = ps->chunk_size * chunk;
- where.count = ps->chunk_size;
+ where.sector = ps->snap->chunk_size * chunk;
+ where.count = ps->snap->chunk_size;
return dm_io_sync_vm(1, &where, rw, ps->area, &bits);
}
@@ -188,7 +189,7 @@ static int area_io(struct pstore *ps, uint32_t area, int rw)
static int zero_area(struct pstore *ps, uint32_t area)
{
- memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+ memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
return area_io(ps, area, WRITE);
}
@@ -196,6 +197,7 @@ static int read_header(struct pstore *ps, int *new_snapshot)
{
int r;
struct disk_header *dh;
+ chunk_t chunk_size;
r = chunk_io(ps, 0, READ);
if (r)
@@ -210,8 +212,29 @@ static int read_header(struct pstore *ps, int *new_snapshot)
*new_snapshot = 0;
ps->valid = le32_to_cpu(dh->valid);
ps->version = le32_to_cpu(dh->version);
- ps->chunk_size = le32_to_cpu(dh->chunk_size);
-
+ chunk_size = le32_to_cpu(dh->chunk_size);
+ if (ps->snap->chunk_size != chunk_size) {
+ DMWARN("chunk size %llu in device metadata overrides "
+ "table chunk size of %llu.",
+ (unsigned long long)chunk_size,
+ (unsigned long long)ps->snap->chunk_size);
+
+ /* We had a bogus chunk_size. Fix stuff up. */
+ dm_io_put(sectors_to_pages(ps->snap->chunk_size));
+ free_area(ps);
+
+ ps->snap->chunk_size = chunk_size;
+ ps->snap->chunk_mask = chunk_size - 1;
+ ps->snap->chunk_shift = ffs(chunk_size) - 1;
+
+ r = alloc_area(ps);
+ if (r)
+ return r;
+
+ r = dm_io_get(sectors_to_pages(chunk_size));
+ if (r)
+ return r;
+ }
} else {
DMWARN("Invalid/corrupt snapshot");
r = -ENXIO;
@@ -224,13 +247,13 @@ static int write_header(struct pstore *ps)
{
struct disk_header *dh;
- memset(ps->area, 0, ps->chunk_size << SECTOR_SHIFT);
+ memset(ps->area, 0, ps->snap->chunk_size << SECTOR_SHIFT);
dh = (struct disk_header *) ps->area;
dh->magic = cpu_to_le32(SNAP_MAGIC);
dh->valid = cpu_to_le32(ps->valid);
dh->version = cpu_to_le32(ps->version);
- dh->chunk_size = cpu_to_le32(ps->chunk_size);
+ dh->chunk_size = cpu_to_le32(ps->snap->chunk_size);
return chunk_io(ps, 0, WRITE);
}
@@ -365,7 +388,7 @@ static void persistent_destroy(struct exception_store *store)
{
struct pstore *ps = get_info(store);
- dm_io_put(sectors_to_pages(ps->chunk_size));
+ dm_io_put(sectors_to_pages(ps->snap->chunk_size));
vfree(ps->callbacks);
free_area(ps);
kfree(ps);
@@ -384,6 +407,16 @@ static int persistent_read_metadata(struct exception_store *store)
return r;
/*
+ * Now we know correct chunk_size, complete the initialisation.
+ */
+ ps->exceptions_per_area = (ps->snap->chunk_size << SECTOR_SHIFT) /
+ sizeof(struct disk_exception);
+ ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
+ sizeof(*ps->callbacks));
+ if (!ps->callbacks)
+ return -ENOMEM;
+
+ /*
* Do we need to setup a new snapshot ?
*/
if (new_snapshot) {
@@ -533,9 +566,6 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
ps->snap = store->snap;
ps->valid = 1;
ps->version = SNAPSHOT_DISK_VERSION;
- ps->chunk_size = chunk_size;
- ps->exceptions_per_area = (chunk_size << SECTOR_SHIFT) /
- sizeof(struct disk_exception);
ps->next_free = 2; /* skipping the header and first area */
ps->current_committed = 0;
@@ -543,18 +573,9 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
if (r)
goto bad;
- /*
- * Allocate space for all the callbacks.
- */
ps->callback_count = 0;
atomic_set(&ps->pending_count, 0);
- ps->callbacks = dm_vcalloc(ps->exceptions_per_area,
- sizeof(*ps->callbacks));
-
- if (!ps->callbacks) {
- r = -ENOMEM;
- goto bad;
- }
+ ps->callbacks = NULL;
store->destroy = persistent_destroy;
store->read_metadata = persistent_read_metadata;
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 8edd6435414..d13bb15a8a0 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- * Copyright (C) 2004 - 2005 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004 - 2006 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
@@ -13,12 +13,12 @@
#include <linux/init.h>
#include <linux/wait.h>
#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/dm-ioctl.h>
#include <linux/hdreg.h>
#include <asm/uaccess.h>
+#define DM_MSG_PREFIX "ioctl"
#define DM_DRIVER_EMAIL "dm-devel@redhat.com"
/*-----------------------------------------------------------------
@@ -48,7 +48,7 @@ struct vers_iter {
static struct list_head _name_buckets[NUM_BUCKETS];
static struct list_head _uuid_buckets[NUM_BUCKETS];
-static void dm_hash_remove_all(void);
+static void dm_hash_remove_all(int keep_open_devices);
/*
* Guards access to both hash tables.
@@ -67,14 +67,12 @@ static int dm_hash_init(void)
{
init_buckets(_name_buckets);
init_buckets(_uuid_buckets);
- devfs_mk_dir(DM_DIR);
return 0;
}
static void dm_hash_exit(void)
{
- dm_hash_remove_all();
- devfs_remove(DM_DIR);
+ dm_hash_remove_all(0);
}
/*-----------------------------------------------------------------
@@ -102,8 +100,10 @@ static struct hash_cell *__get_name_cell(const char *str)
unsigned int h = hash_str(str);
list_for_each_entry (hc, _name_buckets + h, name_list)
- if (!strcmp(hc->name, str))
+ if (!strcmp(hc->name, str)) {
+ dm_get(hc->md);
return hc;
+ }
return NULL;
}
@@ -114,8 +114,10 @@ static struct hash_cell *__get_uuid_cell(const char *str)
unsigned int h = hash_str(str);
list_for_each_entry (hc, _uuid_buckets + h, uuid_list)
- if (!strcmp(hc->uuid, str))
+ if (!strcmp(hc->uuid, str)) {
+ dm_get(hc->md);
return hc;
+ }
return NULL;
}
@@ -167,31 +169,12 @@ static void free_cell(struct hash_cell *hc)
}
/*
- * devfs stuff.
- */
-static int register_with_devfs(struct hash_cell *hc)
-{
- struct gendisk *disk = dm_disk(hc->md);
-
- devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
- S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
- DM_DIR "/%s", hc->name);
- return 0;
-}
-
-static int unregister_with_devfs(struct hash_cell *hc)
-{
- devfs_remove(DM_DIR"/%s", hc->name);
- return 0;
-}
-
-/*
* The kdev_t and uuid of a device can never change once it is
* initially inserted.
*/
static int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
{
- struct hash_cell *cell;
+ struct hash_cell *cell, *hc;
/*
* Allocate the new cells.
@@ -204,19 +187,23 @@ static int dm_hash_insert(const char *name, const char *uuid, struct mapped_devi
* Insert the cell into both hash tables.
*/
down_write(&_hash_lock);
- if (__get_name_cell(name))
+ hc = __get_name_cell(name);
+ if (hc) {
+ dm_put(hc->md);
goto bad;
+ }
list_add(&cell->name_list, _name_buckets + hash_str(name));
if (uuid) {
- if (__get_uuid_cell(uuid)) {
+ hc = __get_uuid_cell(uuid);
+ if (hc) {
list_del(&cell->name_list);
+ dm_put(hc->md);
goto bad;
}
list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
}
- register_with_devfs(cell);
dm_get(md);
dm_set_mdptr(md, cell);
up_write(&_hash_lock);
@@ -236,7 +223,6 @@ static void __hash_remove(struct hash_cell *hc)
/* remove from the dev hash */
list_del(&hc->uuid_list);
list_del(&hc->name_list);
- unregister_with_devfs(hc);
dm_set_mdptr(hc->md, NULL);
table = dm_get_table(hc->md);
@@ -251,19 +237,41 @@ static void __hash_remove(struct hash_cell *hc)
free_cell(hc);
}
-static void dm_hash_remove_all(void)
+static void dm_hash_remove_all(int keep_open_devices)
{
- int i;
+ int i, dev_skipped, dev_removed;
struct hash_cell *hc;
struct list_head *tmp, *n;
down_write(&_hash_lock);
+
+retry:
+ dev_skipped = dev_removed = 0;
for (i = 0; i < NUM_BUCKETS; i++) {
list_for_each_safe (tmp, n, _name_buckets + i) {
hc = list_entry(tmp, struct hash_cell, name_list);
+
+ if (keep_open_devices &&
+ dm_lock_for_deletion(hc->md)) {
+ dev_skipped++;
+ continue;
+ }
__hash_remove(hc);
+ dev_removed = 1;
}
}
+
+ /*
+ * Some mapped devices may be using other mapped devices, so if any
+ * still exist, repeat until we make no further progress.
+ */
+ if (dev_skipped) {
+ if (dev_removed)
+ goto retry;
+
+ DMWARN("remove_all left %d open device(s)", dev_skipped);
+ }
+
up_write(&_hash_lock);
}
@@ -289,6 +297,7 @@ static int dm_hash_rename(const char *old, const char *new)
if (hc) {
DMWARN("asked to rename to an already existing name %s -> %s",
old, new);
+ dm_put(hc->md);
up_write(&_hash_lock);
kfree(new_name);
return -EBUSY;
@@ -309,16 +318,11 @@ static int dm_hash_rename(const char *old, const char *new)
/*
* rename and move the name cell.
*/
- unregister_with_devfs(hc);
-
list_del(&hc->name_list);
old_name = hc->name;
hc->name = new_name;
list_add(&hc->name_list, _name_buckets + hash_str(new_name));
- /* rename the device node in devfs */
- register_with_devfs(hc);
-
/*
* Wake up any dm event waiters.
*/
@@ -328,6 +332,7 @@ static int dm_hash_rename(const char *old, const char *new)
dm_table_put(table);
}
+ dm_put(hc->md);
up_write(&_hash_lock);
kfree(old_name);
return 0;
@@ -344,7 +349,7 @@ typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
static int remove_all(struct dm_ioctl *param, size_t param_size)
{
- dm_hash_remove_all();
+ dm_hash_remove_all(1);
param->data_size = 0;
return 0;
}
@@ -524,7 +529,6 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
{
struct gendisk *disk = dm_disk(md);
struct dm_table *table;
- struct block_device *bdev;
param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
DM_ACTIVE_PRESENT_FLAG);
@@ -534,20 +538,12 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
param->dev = huge_encode_dev(MKDEV(disk->major, disk->first_minor));
- if (!(param->flags & DM_SKIP_BDGET_FLAG)) {
- bdev = bdget_disk(disk, 0);
- if (!bdev)
- return -ENXIO;
-
- /*
- * Yes, this will be out of date by the time it gets back
- * to userland, but it is still very useful for
- * debugging.
- */
- param->open_count = bdev->bd_openers;
- bdput(bdev);
- } else
- param->open_count = -1;
+ /*
+ * Yes, this will be out of date by the time it gets back
+ * to userland, but it is still very useful for
+ * debugging.
+ */
+ param->open_count = dm_open_count(md);
if (disk->policy)
param->flags |= DM_READONLY_FLAG;
@@ -567,7 +563,7 @@ static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
static int dev_create(struct dm_ioctl *param, size_t param_size)
{
- int r;
+ int r, m = DM_ANY_MINOR;
struct mapped_device *md;
r = check_name(param->name);
@@ -575,10 +571,9 @@ static int dev_create(struct dm_ioctl *param, size_t param_size)
return r;
if (param->flags & DM_PERSISTENT_DEV_FLAG)
- r = dm_create_with_minor(MINOR(huge_decode_dev(param->dev)), &md);
- else
- r = dm_create(&md);
+ m = MINOR(huge_decode_dev(param->dev));
+ r = dm_create(m, &md);
if (r)
return r;
@@ -611,10 +606,8 @@ static struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
return __get_name_cell(param->name);
md = dm_get_md(huge_decode_dev(param->dev));
- if (md) {
+ if (md)
mdptr = dm_get_mdptr(md);
- dm_put(md);
- }
return mdptr;
}
@@ -628,7 +621,6 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
hc = __find_device_hash_cell(param);
if (hc) {
md = hc->md;
- dm_get(md);
/*
* Sneakily write in both the name and the uuid
@@ -653,6 +645,8 @@ static struct mapped_device *find_device(struct dm_ioctl *param)
static int dev_remove(struct dm_ioctl *param, size_t param_size)
{
struct hash_cell *hc;
+ struct mapped_device *md;
+ int r;
down_write(&_hash_lock);
hc = __find_device_hash_cell(param);
@@ -663,8 +657,22 @@ static int dev_remove(struct dm_ioctl *param, size_t param_size)
return -ENXIO;
}
+ md = hc->md;
+
+ /*
+ * Ensure the device is not open and nothing further can open it.
+ */
+ r = dm_lock_for_deletion(md);
+ if (r) {
+ DMWARN("unable to remove open device %s", hc->name);
+ up_write(&_hash_lock);
+ dm_put(md);
+ return r;
+ }
+
__hash_remove(hc);
up_write(&_hash_lock);
+ dm_put(md);
param->data_size = 0;
return 0;
}
@@ -790,7 +798,6 @@ static int do_resume(struct dm_ioctl *param)
}
md = hc->md;
- dm_get(md);
new_map = hc->new_map;
hc->new_map = NULL;
@@ -1078,6 +1085,7 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
{
int r;
struct hash_cell *hc;
+ struct mapped_device *md;
down_write(&_hash_lock);
@@ -1096,7 +1104,9 @@ static int table_clear(struct dm_ioctl *param, size_t param_size)
param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
r = __dev_status(hc->md, param);
+ md = hc->md;
up_write(&_hash_lock);
+ dm_put(md);
return r;
}
@@ -1462,7 +1472,6 @@ static struct file_operations _ctl_fops = {
static struct miscdevice _dm_misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DM_NAME,
- .devfs_name = "mapper/control",
.fops = &_ctl_fops
};
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index daf586c0898..47b3c62bbdb 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -12,6 +12,8 @@
#include <linux/bio.h>
#include <linux/slab.h>
+#define DM_MSG_PREFIX "linear"
+
/*
* Linear: maps a linear range of a device.
*/
@@ -29,7 +31,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned long long tmp;
if (argc != 2) {
- ti->error = "dm-linear: Invalid argument count";
+ ti->error = "Invalid argument count";
return -EINVAL;
}
@@ -111,7 +113,7 @@ int __init dm_linear_init(void)
int r = dm_register_target(&linear_target);
if (r < 0)
- DMERR("linear: register failed %d", r);
+ DMERR("register failed %d", r);
return r;
}
@@ -121,5 +123,5 @@ void dm_linear_exit(void)
int r = dm_unregister_target(&linear_target);
if (r < 0)
- DMERR("linear: unregister failed %d", r);
+ DMERR("unregister failed %d", r);
}
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index d73779a4241..64b764bd02c 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -12,6 +12,8 @@
#include "dm-log.h"
#include "dm-io.h"
+#define DM_MSG_PREFIX "mirror log"
+
static LIST_HEAD(_log_types);
static DEFINE_SPINLOCK(_lock);
@@ -155,8 +157,6 @@ struct log_c {
struct io_region header_location;
struct log_header *disk_header;
-
- struct io_region bits_location;
};
/*
@@ -241,43 +241,21 @@ static inline int write_header(struct log_c *log)
}
/*----------------------------------------------------------------
- * Bits IO
- *--------------------------------------------------------------*/
-static int read_bits(struct log_c *log)
-{
- int r;
- unsigned long ebits;
-
- r = dm_io_sync_vm(1, &log->bits_location, READ,
- log->clean_bits, &ebits);
- if (r)
- return r;
-
- return 0;
-}
-
-static int write_bits(struct log_c *log)
-{
- unsigned long ebits;
- return dm_io_sync_vm(1, &log->bits_location, WRITE,
- log->clean_bits, &ebits);
-}
-
-/*----------------------------------------------------------------
* core log constructor/destructor
*
* argv contains region_size followed optionally by [no]sync
*--------------------------------------------------------------*/
#define BYTE_SHIFT 3
-static int core_ctr(struct dirty_log *log, struct dm_target *ti,
- unsigned int argc, char **argv)
+static int create_log_context(struct dirty_log *log, struct dm_target *ti,
+ unsigned int argc, char **argv,
+ struct dm_dev *dev)
{
enum sync sync = DEFAULTSYNC;
struct log_c *lc;
uint32_t region_size;
unsigned int region_count;
- size_t bitset_size;
+ size_t bitset_size, buf_size;
if (argc < 1 || argc > 2) {
DMWARN("wrong number of arguments to mirror log");
@@ -319,22 +297,53 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti,
* Work out how many "unsigned long"s we need to hold the bitset.
*/
bitset_size = dm_round_up(region_count,
- sizeof(unsigned long) << BYTE_SHIFT);
+ sizeof(*lc->clean_bits) << BYTE_SHIFT);
bitset_size >>= BYTE_SHIFT;
- lc->bitset_uint32_count = bitset_size / 4;
- lc->clean_bits = vmalloc(bitset_size);
- if (!lc->clean_bits) {
- DMWARN("couldn't allocate clean bitset");
- kfree(lc);
- return -ENOMEM;
+ lc->bitset_uint32_count = bitset_size / sizeof(*lc->clean_bits);
+
+ /*
+ * Disk log?
+ */
+ if (!dev) {
+ lc->clean_bits = vmalloc(bitset_size);
+ if (!lc->clean_bits) {
+ DMWARN("couldn't allocate clean bitset");
+ kfree(lc);
+ return -ENOMEM;
+ }
+ lc->disk_header = NULL;
+ } else {
+ lc->log_dev = dev;
+ lc->header_location.bdev = lc->log_dev->bdev;
+ lc->header_location.sector = 0;
+
+ /*
+ * Buffer holds both header and bitset.
+ */
+ buf_size = dm_round_up((LOG_OFFSET << SECTOR_SHIFT) +
+ bitset_size, ti->limits.hardsect_size);
+ lc->header_location.count = buf_size >> SECTOR_SHIFT;
+
+ lc->disk_header = vmalloc(buf_size);
+ if (!lc->disk_header) {
+ DMWARN("couldn't allocate disk log buffer");
+ kfree(lc);
+ return -ENOMEM;
+ }
+
+ lc->clean_bits = (void *)lc->disk_header +
+ (LOG_OFFSET << SECTOR_SHIFT);
}
+
memset(lc->clean_bits, -1, bitset_size);
lc->sync_bits = vmalloc(bitset_size);
if (!lc->sync_bits) {
DMWARN("couldn't allocate sync bitset");
- vfree(lc->clean_bits);
+ if (!dev)
+ vfree(lc->clean_bits);
+ vfree(lc->disk_header);
kfree(lc);
return -ENOMEM;
}
@@ -345,25 +354,40 @@ static int core_ctr(struct dirty_log *log, struct dm_target *ti,
if (!lc->recovering_bits) {
DMWARN("couldn't allocate sync bitset");
vfree(lc->sync_bits);
- vfree(lc->clean_bits);
+ if (!dev)
+ vfree(lc->clean_bits);
+ vfree(lc->disk_header);
kfree(lc);
return -ENOMEM;
}
memset(lc->recovering_bits, 0, bitset_size);
lc->sync_search = 0;
log->context = lc;
+
return 0;
}
-static void core_dtr(struct dirty_log *log)
+static int core_ctr(struct dirty_log *log, struct dm_target *ti,
+ unsigned int argc, char **argv)
+{
+ return create_log_context(log, ti, argc, argv, NULL);
+}
+
+static void destroy_log_context(struct log_c *lc)
{
- struct log_c *lc = (struct log_c *) log->context;
- vfree(lc->clean_bits);
vfree(lc->sync_bits);
vfree(lc->recovering_bits);
kfree(lc);
}
+static void core_dtr(struct dirty_log *log)
+{
+ struct log_c *lc = (struct log_c *) log->context;
+
+ vfree(lc->clean_bits);
+ destroy_log_context(lc);
+}
+
/*----------------------------------------------------------------
* disk log constructor/destructor
*
@@ -373,8 +397,6 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
unsigned int argc, char **argv)
{
int r;
- size_t size;
- struct log_c *lc;
struct dm_dev *dev;
if (argc < 2 || argc > 3) {
@@ -387,49 +409,22 @@ static int disk_ctr(struct dirty_log *log, struct dm_target *ti,
if (r)
return r;
- r = core_ctr(log, ti, argc - 1, argv + 1);
+ r = create_log_context(log, ti, argc - 1, argv + 1, dev);
if (r) {
dm_put_device(ti, dev);
return r;
}
- lc = (struct log_c *) log->context;
- lc->log_dev = dev;
-
- /* setup the disk header fields */
- lc->header_location.bdev = lc->log_dev->bdev;
- lc->header_location.sector = 0;
- lc->header_location.count = 1;
-
- /*
- * We can't read less than this amount, even though we'll
- * not be using most of this space.
- */
- lc->disk_header = vmalloc(1 << SECTOR_SHIFT);
- if (!lc->disk_header)
- goto bad;
-
- /* setup the disk bitset fields */
- lc->bits_location.bdev = lc->log_dev->bdev;
- lc->bits_location.sector = LOG_OFFSET;
-
- size = dm_round_up(lc->bitset_uint32_count * sizeof(uint32_t),
- 1 << SECTOR_SHIFT);
- lc->bits_location.count = size >> SECTOR_SHIFT;
return 0;
-
- bad:
- dm_put_device(ti, lc->log_dev);
- core_dtr(log);
- return -ENOMEM;
}
static void disk_dtr(struct dirty_log *log)
{
struct log_c *lc = (struct log_c *) log->context;
+
dm_put_device(lc->ti, lc->log_dev);
vfree(lc->disk_header);
- core_dtr(log);
+ destroy_log_context(lc);
}
static int count_bits32(uint32_t *addr, unsigned size)
@@ -454,12 +449,7 @@ static int disk_resume(struct dirty_log *log)
if (r)
return r;
- /* read the bits */
- r = read_bits(lc);
- if (r)
- return r;
-
- /* set or clear any new bits */
+ /* set or clear any new bits -- device has grown */
if (lc->sync == NOSYNC)
for (i = lc->header.nr_regions; i < lc->region_count; i++)
/* FIXME: amazingly inefficient */
@@ -469,15 +459,14 @@ static int disk_resume(struct dirty_log *log)
/* FIXME: amazingly inefficient */
log_clear_bit(lc, lc->clean_bits, i);
+ /* clear any old bits -- device has shrunk */
+ for (i = lc->region_count; i % (sizeof(*lc->clean_bits) << BYTE_SHIFT); i++)
+ log_clear_bit(lc, lc->clean_bits, i);
+
/* copy clean across to sync */
memcpy(lc->sync_bits, lc->clean_bits, size);
lc->sync_count = count_bits32(lc->clean_bits, lc->bitset_uint32_count);
- /* write the bits */
- r = write_bits(lc);
- if (r)
- return r;
-
/* set the correct number of regions in the header */
lc->header.nr_regions = lc->region_count;
@@ -518,7 +507,7 @@ static int disk_flush(struct dirty_log *log)
if (!lc->touched)
return 0;
- r = write_bits(lc);
+ r = write_header(lc);
if (!r)
lc->touched = 0;
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 1816f30678e..93f701ea87b 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -21,6 +21,7 @@
#include <linux/workqueue.h>
#include <asm/atomic.h>
+#define DM_MSG_PREFIX "multipath"
#define MESG_STR(x) x, sizeof(x)
/* Path properties */
@@ -446,8 +447,6 @@ struct param {
char *error;
};
-#define ESTR(s) ("dm-multipath: " s)
-
static int read_param(struct param *param, char *str, unsigned *v, char **error)
{
if (!str ||
@@ -495,12 +494,12 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
unsigned ps_argc;
static struct param _params[] = {
- {0, 1024, ESTR("invalid number of path selector args")},
+ {0, 1024, "invalid number of path selector args"},
};
pst = dm_get_path_selector(shift(as));
if (!pst) {
- ti->error = ESTR("unknown path selector type");
+ ti->error = "unknown path selector type";
return -EINVAL;
}
@@ -511,7 +510,7 @@ static int parse_path_selector(struct arg_set *as, struct priority_group *pg,
r = pst->create(&pg->ps, ps_argc, as->argv);
if (r) {
dm_put_path_selector(pst);
- ti->error = ESTR("path selector constructor failed");
+ ti->error = "path selector constructor failed";
return r;
}
@@ -529,7 +528,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
/* we need at least a path arg */
if (as->argc < 1) {
- ti->error = ESTR("no device given");
+ ti->error = "no device given";
return NULL;
}
@@ -540,7 +539,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
r = dm_get_device(ti, shift(as), ti->begin, ti->len,
dm_table_get_mode(ti->table), &p->path.dev);
if (r) {
- ti->error = ESTR("error getting device");
+ ti->error = "error getting device";
goto bad;
}
@@ -562,8 +561,8 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
struct dm_target *ti)
{
static struct param _params[] = {
- {1, 1024, ESTR("invalid number of paths")},
- {0, 1024, ESTR("invalid number of selector args")}
+ {1, 1024, "invalid number of paths"},
+ {0, 1024, "invalid number of selector args"}
};
int r;
@@ -572,13 +571,13 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
if (as->argc < 2) {
as->argc = 0;
- ti->error = ESTR("not enough priority group aruments");
+ ti->error = "not enough priority group aruments";
return NULL;
}
pg = alloc_priority_group();
if (!pg) {
- ti->error = ESTR("couldn't allocate priority group");
+ ti->error = "couldn't allocate priority group";
return NULL;
}
pg->m = m;
@@ -633,7 +632,7 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m,
unsigned hw_argc;
static struct param _params[] = {
- {0, 1024, ESTR("invalid number of hardware handler args")},
+ {0, 1024, "invalid number of hardware handler args"},
};
r = read_param(_params, shift(as), &hw_argc, &ti->error);
@@ -645,14 +644,14 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m,
hwht = dm_get_hw_handler(shift(as));
if (!hwht) {
- ti->error = ESTR("unknown hardware handler type");
+ ti->error = "unknown hardware handler type";
return -EINVAL;
}
r = hwht->create(&m->hw_handler, hw_argc - 1, as->argv);
if (r) {
dm_put_hw_handler(hwht);
- ti->error = ESTR("hardware handler constructor failed");
+ ti->error = "hardware handler constructor failed";
return r;
}
@@ -669,7 +668,7 @@ static int parse_features(struct arg_set *as, struct multipath *m,
unsigned argc;
static struct param _params[] = {
- {0, 1, ESTR("invalid number of feature args")},
+ {0, 1, "invalid number of feature args"},
};
r = read_param(_params, shift(as), &argc, &ti->error);
@@ -692,8 +691,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
{
/* target parameters */
static struct param _params[] = {
- {1, 1024, ESTR("invalid number of priority groups")},
- {1, 1024, ESTR("invalid initial priority group number")},
+ {1, 1024, "invalid number of priority groups"},
+ {1, 1024, "invalid initial priority group number"},
};
int r;
@@ -707,10 +706,12 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
m = alloc_multipath();
if (!m) {
- ti->error = ESTR("can't allocate multipath");
+ ti->error = "can't allocate multipath";
return -EINVAL;
}
+ m->ti = ti;
+
r = parse_features(&as, m, ti);
if (r)
goto bad;
@@ -746,13 +747,12 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
}
if (pg_count != m->nr_priority_groups) {
- ti->error = ESTR("priority group count mismatch");
+ ti->error = "priority group count mismatch";
r = -EINVAL;
goto bad;
}
ti->private = m;
- m->ti = ti;
return 0;
@@ -807,7 +807,7 @@ static int fail_path(struct pgpath *pgpath)
if (!pgpath->path.is_active)
goto out;
- DMWARN("dm-multipath: Failing path %s.", pgpath->path.dev->name);
+ DMWARN("Failing path %s.", pgpath->path.dev->name);
pgpath->pg->ps.type->fail_path(&pgpath->pg->ps, &pgpath->path);
pgpath->path.is_active = 0;
@@ -1250,7 +1250,7 @@ static int multipath_message(struct dm_target *ti, unsigned argc, char **argv)
r = dm_get_device(ti, argv[1], ti->begin, ti->len,
dm_table_get_mode(ti->table), &dev);
if (r) {
- DMWARN("dm-multipath message: error getting device %s",
+ DMWARN("message: error getting device %s",
argv[1]);
return -EINVAL;
}
@@ -1309,7 +1309,7 @@ static int __init dm_multipath_init(void)
return -ENOMEM;
}
- DMINFO("dm-multipath version %u.%u.%u loaded",
+ DMINFO("version %u.%u.%u loaded",
multipath_target.version[0], multipath_target.version[1],
multipath_target.version[2]);
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index d12cf3e5e07..c54de989eb0 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -20,6 +20,8 @@
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
+#define DM_MSG_PREFIX "raid1"
+
static struct workqueue_struct *_kmirrord_wq;
static struct work_struct _kmirrord_work;
@@ -106,12 +108,42 @@ struct region {
struct bio_list delayed_bios;
};
+
+/*-----------------------------------------------------------------
+ * Mirror set structures.
+ *---------------------------------------------------------------*/
+struct mirror {
+ atomic_t error_count;
+ struct dm_dev *dev;
+ sector_t offset;
+};
+
+struct mirror_set {
+ struct dm_target *ti;
+ struct list_head list;
+ struct region_hash rh;
+ struct kcopyd_client *kcopyd_client;
+
+ spinlock_t lock; /* protects the next two lists */
+ struct bio_list reads;
+ struct bio_list writes;
+
+ /* recovery */
+ region_t nr_regions;
+ int in_sync;
+
+ struct mirror *default_mirror; /* Default mirror */
+
+ unsigned int nr_mirrors;
+ struct mirror mirror[0];
+};
+
/*
* Conversion fns
*/
static inline region_t bio_to_region(struct region_hash *rh, struct bio *bio)
{
- return bio->bi_sector >> rh->region_shift;
+ return (bio->bi_sector - rh->ms->ti->begin) >> rh->region_shift;
}
static inline sector_t region_to_sector(struct region_hash *rh, region_t region)
@@ -223,7 +255,9 @@ static struct region *__rh_alloc(struct region_hash *rh, region_t region)
struct region *reg, *nreg;
read_unlock(&rh->hash_lock);
- nreg = mempool_alloc(rh->region_pool, GFP_NOIO);
+ nreg = mempool_alloc(rh->region_pool, GFP_ATOMIC);
+ if (unlikely(!nreg))
+ nreg = kmalloc(sizeof(struct region), GFP_NOIO);
nreg->state = rh->log->type->in_sync(rh->log, region, 1) ?
RH_CLEAN : RH_NOSYNC;
nreg->rh = rh;
@@ -458,11 +492,9 @@ static int __rh_recovery_prepare(struct region_hash *rh)
/* Already quiesced ? */
if (atomic_read(&reg->pending))
list_del_init(&reg->list);
+ else
+ list_move(&reg->list, &rh->quiesced_regions);
- else {
- list_del_init(&reg->list);
- list_add(&reg->list, &rh->quiesced_regions);
- }
spin_unlock_irq(&rh->region_lock);
return 1;
@@ -541,35 +573,6 @@ static void rh_start_recovery(struct region_hash *rh)
wake();
}
-/*-----------------------------------------------------------------
- * Mirror set structures.
- *---------------------------------------------------------------*/
-struct mirror {
- atomic_t error_count;
- struct dm_dev *dev;
- sector_t offset;
-};
-
-struct mirror_set {
- struct dm_target *ti;
- struct list_head list;
- struct region_hash rh;
- struct kcopyd_client *kcopyd_client;
-
- spinlock_t lock; /* protects the next two lists */
- struct bio_list reads;
- struct bio_list writes;
-
- /* recovery */
- region_t nr_regions;
- int in_sync;
-
- struct mirror *default_mirror; /* Default mirror */
-
- unsigned int nr_mirrors;
- struct mirror mirror[0];
-};
-
/*
* Every mirror should look like this one.
*/
@@ -603,7 +606,7 @@ static void recovery_complete(int read_err, unsigned int write_err,
struct region *reg = (struct region *) context;
/* FIXME: better error handling */
- rh_recovery_end(reg, read_err || write_err);
+ rh_recovery_end(reg, !(read_err || write_err));
}
static int recover(struct mirror_set *ms, struct region *reg)
@@ -893,7 +896,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
ms = kmalloc(len, GFP_KERNEL);
if (!ms) {
- ti->error = "dm-mirror: Cannot allocate mirror context";
+ ti->error = "Cannot allocate mirror context";
return NULL;
}
@@ -907,7 +910,7 @@ static struct mirror_set *alloc_context(unsigned int nr_mirrors,
ms->default_mirror = &ms->mirror[DEFAULT_MIRROR];
if (rh_init(&ms->rh, ms, dl, region_size, ms->nr_regions)) {
- ti->error = "dm-mirror: Error creating dirty region hash";
+ ti->error = "Error creating dirty region hash";
kfree(ms);
return NULL;
}
@@ -937,14 +940,14 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti,
unsigned long long offset;
if (sscanf(argv[1], "%llu", &offset) != 1) {
- ti->error = "dm-mirror: Invalid offset";
+ ti->error = "Invalid offset";
return -EINVAL;
}
if (dm_get_device(ti, argv[0], offset, ti->len,
dm_table_get_mode(ti->table),
&ms->mirror[mirror].dev)) {
- ti->error = "dm-mirror: Device lookup failure";
+ ti->error = "Device lookup failure";
return -ENXIO;
}
@@ -981,30 +984,30 @@ static struct dirty_log *create_dirty_log(struct dm_target *ti,
struct dirty_log *dl;
if (argc < 2) {
- ti->error = "dm-mirror: Insufficient mirror log arguments";
+ ti->error = "Insufficient mirror log arguments";
return NULL;
}
if (sscanf(argv[1], "%u", &param_count) != 1) {
- ti->error = "dm-mirror: Invalid mirror log argument count";
+ ti->error = "Invalid mirror log argument count";
return NULL;
}
*args_used = 2 + param_count;
if (argc < *args_used) {
- ti->error = "dm-mirror: Insufficient mirror log arguments";
+ ti->error = "Insufficient mirror log arguments";
return NULL;
}
dl = dm_create_dirty_log(argv[0], ti, param_count, argv + 2);
if (!dl) {
- ti->error = "dm-mirror: Error creating mirror dirty log";
+ ti->error = "Error creating mirror dirty log";
return NULL;
}
if (!_check_region_size(ti, dl->type->get_region_size(dl))) {
- ti->error = "dm-mirror: Invalid region size";
+ ti->error = "Invalid region size";
dm_destroy_dirty_log(dl);
return NULL;
}
@@ -1038,7 +1041,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (!argc || sscanf(argv[0], "%u", &nr_mirrors) != 1 ||
nr_mirrors < 2 || nr_mirrors > KCOPYD_MAX_REGIONS + 1) {
- ti->error = "dm-mirror: Invalid number of mirrors";
+ ti->error = "Invalid number of mirrors";
dm_destroy_dirty_log(dl);
return -EINVAL;
}
@@ -1046,7 +1049,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
argv++, argc--;
if (argc != nr_mirrors * 2) {
- ti->error = "dm-mirror: Wrong number of mirror arguments";
+ ti->error = "Wrong number of mirror arguments";
dm_destroy_dirty_log(dl);
return -EINVAL;
}
@@ -1115,7 +1118,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio,
struct mirror *m;
struct mirror_set *ms = ti->private;
- map_context->ll = bio->bi_sector >> ms->rh.region_shift;
+ map_context->ll = bio_to_region(&ms->rh, bio);
if (rw == WRITE) {
queue_bio(ms, bio, rw);
@@ -1221,7 +1224,7 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
static struct target_type mirror_target = {
.name = "mirror",
- .version = {1, 0, 1},
+ .version = {1, 0, 2},
.module = THIS_MODULE,
.ctr = mirror_ctr,
.dtr = mirror_dtr,
diff --git a/drivers/md/dm-round-robin.c b/drivers/md/dm-round-robin.c
index d0024865a78..c5a16c55012 100644
--- a/drivers/md/dm-round-robin.c
+++ b/drivers/md/dm-round-robin.c
@@ -14,6 +14,8 @@
#include <linux/slab.h>
+#define DM_MSG_PREFIX "multipath round-robin"
+
/*-----------------------------------------------------------------
* Path-handling code, paths are held in lists
*---------------------------------------------------------------*/
@@ -191,9 +193,9 @@ static int __init dm_rr_init(void)
int r = dm_register_path_selector(&rr_ps);
if (r < 0)
- DMERR("round-robin: register failed %d", r);
+ DMERR("register failed %d", r);
- DMINFO("dm-round-robin version 1.0.0 loaded");
+ DMINFO("version 1.0.0 loaded");
return r;
}
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 08312b46463..1d0fafda0f7 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -7,7 +7,6 @@
*/
#include <linux/blkdev.h>
-#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/device-mapper.h>
#include <linux/fs.h>
@@ -23,6 +22,8 @@
#include "dm-bio-list.h"
#include "kcopyd.h"
+#define DM_MSG_PREFIX "snapshots"
+
/*
* The percentage increment we will wake up users at
*/
@@ -117,7 +118,7 @@ static int init_origin_hash(void)
_origins = kmalloc(ORIGIN_HASH_SIZE * sizeof(struct list_head),
GFP_KERNEL);
if (!_origins) {
- DMERR("Device mapper: Snapshot: unable to allocate memory");
+ DMERR("unable to allocate memory");
return -ENOMEM;
}
@@ -412,7 +413,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
int blocksize;
if (argc < 4) {
- ti->error = "dm-snapshot: requires exactly 4 arguments";
+ ti->error = "requires exactly 4 arguments";
r = -EINVAL;
goto bad1;
}
@@ -530,7 +531,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ti->private = s;
- ti->split_io = chunk_size;
+ ti->split_io = s->chunk_size;
return 0;
@@ -1127,7 +1128,7 @@ static int origin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
struct dm_dev *dev;
if (argc != 1) {
- ti->error = "dm-origin: incorrect number of arguments";
+ ti->error = "origin: incorrect number of arguments";
return -EINVAL;
}
@@ -1204,7 +1205,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result,
static struct target_type origin_target = {
.name = "snapshot-origin",
- .version = {1, 1, 0},
+ .version = {1, 4, 0},
.module = THIS_MODULE,
.ctr = origin_ctr,
.dtr = origin_dtr,
@@ -1215,7 +1216,7 @@ static struct target_type origin_target = {
static struct target_type snapshot_target = {
.name = "snapshot",
- .version = {1, 1, 0},
+ .version = {1, 4, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
@@ -1236,7 +1237,7 @@ static int __init dm_snapshot_init(void)
r = dm_register_target(&origin_target);
if (r < 0) {
- DMERR("Device mapper: Origin: register failed %d\n", r);
+ DMERR("Origin target register failed %d", r);
goto bad1;
}
diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c
index 08328a8f5a3..6c29fcecd89 100644
--- a/drivers/md/dm-stripe.c
+++ b/drivers/md/dm-stripe.c
@@ -12,6 +12,8 @@
#include <linux/bio.h>
#include <linux/slab.h>
+#define DM_MSG_PREFIX "striped"
+
struct stripe {
struct dm_dev *dev;
sector_t physical_start;
@@ -78,19 +80,19 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned int i;
if (argc < 2) {
- ti->error = "dm-stripe: Not enough arguments";
+ ti->error = "Not enough arguments";
return -EINVAL;
}
stripes = simple_strtoul(argv[0], &end, 10);
if (*end) {
- ti->error = "dm-stripe: Invalid stripe count";
+ ti->error = "Invalid stripe count";
return -EINVAL;
}
chunk_size = simple_strtoul(argv[1], &end, 10);
if (*end) {
- ti->error = "dm-stripe: Invalid chunk_size";
+ ti->error = "Invalid chunk_size";
return -EINVAL;
}
@@ -99,19 +101,19 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
*/
if (!chunk_size || (chunk_size & (chunk_size - 1)) ||
(chunk_size < (PAGE_SIZE >> SECTOR_SHIFT))) {
- ti->error = "dm-stripe: Invalid chunk size";
+ ti->error = "Invalid chunk size";
return -EINVAL;
}
if (ti->len & (chunk_size - 1)) {
- ti->error = "dm-stripe: Target length not divisible by "
+ ti->error = "Target length not divisible by "
"chunk size";
return -EINVAL;
}
width = ti->len;
if (sector_div(width, stripes)) {
- ti->error = "dm-stripe: Target length not divisible by "
+ ti->error = "Target length not divisible by "
"number of stripes";
return -EINVAL;
}
@@ -120,14 +122,14 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
* Do we have enough arguments for that many stripes ?
*/
if (argc != (2 + 2 * stripes)) {
- ti->error = "dm-stripe: Not enough destinations "
+ ti->error = "Not enough destinations "
"specified";
return -EINVAL;
}
sc = alloc_context(stripes);
if (!sc) {
- ti->error = "dm-stripe: Memory allocation for striped context "
+ ti->error = "Memory allocation for striped context "
"failed";
return -ENOMEM;
}
@@ -149,8 +151,7 @@ static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv)
r = get_stripe(ti, sc, i, argv);
if (r < 0) {
- ti->error = "dm-stripe: Couldn't parse stripe "
- "destination";
+ ti->error = "Couldn't parse stripe destination";
while (i--)
dm_put_device(ti, sc->stripe[i].dev);
kfree(sc);
@@ -227,7 +228,7 @@ int __init dm_stripe_init(void)
r = dm_register_target(&stripe_target);
if (r < 0)
- DMWARN("striped target registration failed");
+ DMWARN("target registration failed");
return r;
}
@@ -235,7 +236,7 @@ int __init dm_stripe_init(void)
void dm_stripe_exit(void)
{
if (dm_unregister_target(&stripe_target))
- DMWARN("striped target unregistration failed");
+ DMWARN("target unregistration failed");
return;
}
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 8f56a54cf0c..75fe9493e6a 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -17,6 +17,8 @@
#include <linux/mutex.h>
#include <asm/atomic.h>
+#define DM_MSG_PREFIX "table"
+
#define MAX_DEPTH 16
#define NODE_SIZE L1_CACHE_BYTES
#define KEYS_PER_NODE (NODE_SIZE / sizeof(sector_t))
@@ -237,6 +239,44 @@ int dm_table_create(struct dm_table **result, int mode,
return 0;
}
+int dm_create_error_table(struct dm_table **result, struct mapped_device *md)
+{
+ struct dm_table *t;
+ sector_t dev_size = 1;
+ int r;
+
+ /*
+ * Find current size of device.
+ * Default to 1 sector if inactive.
+ */
+ t = dm_get_table(md);
+ if (t) {
+ dev_size = dm_table_get_size(t);
+ dm_table_put(t);
+ }
+
+ r = dm_table_create(&t, FMODE_READ, 1, md);
+ if (r)
+ return r;
+
+ r = dm_table_add_target(t, "error", 0, dev_size, NULL);
+ if (r)
+ goto out;
+
+ r = dm_table_complete(t);
+ if (r)
+ goto out;
+
+ *result = t;
+
+out:
+ if (r)
+ dm_table_put(t);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(dm_create_error_table);
+
static void free_devices(struct list_head *devices)
{
struct list_head *tmp, *next;
@@ -590,6 +630,12 @@ int dm_split_args(int *argc, char ***argvp, char *input)
unsigned array_size = 0;
*argc = 0;
+
+ if (!input) {
+ *argvp = NULL;
+ return 0;
+ }
+
argv = realloc_argv(&array_size, argv);
if (!argv)
return -ENOMEM;
@@ -671,15 +717,14 @@ int dm_table_add_target(struct dm_table *t, const char *type,
memset(tgt, 0, sizeof(*tgt));
if (!len) {
- tgt->error = "zero-length target";
- DMERR("%s", tgt->error);
+ DMERR("%s: zero-length target", dm_device_name(t->md));
return -EINVAL;
}
tgt->type = dm_get_target_type(type);
if (!tgt->type) {
- tgt->error = "unknown target type";
- DMERR("%s", tgt->error);
+ DMERR("%s: %s: unknown target type", dm_device_name(t->md),
+ type);
return -EINVAL;
}
@@ -716,7 +761,7 @@ int dm_table_add_target(struct dm_table *t, const char *type,
return 0;
bad:
- DMERR("%s", tgt->error);
+ DMERR("%s: %s: %s", dm_device_name(t->md), type, tgt->error);
dm_put_target_type(tgt->type);
return r;
}
@@ -802,7 +847,7 @@ sector_t dm_table_get_size(struct dm_table *t)
struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index)
{
- if (index > t->num_targets)
+ if (index >= t->num_targets)
return NULL;
return t->targets + index;
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 64fd8e79ea4..477a041a41c 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -12,6 +12,8 @@
#include <linux/bio.h>
#include <linux/slab.h>
+#define DM_MSG_PREFIX "target"
+
struct tt_internal {
struct target_type tt;
diff --git a/drivers/md/dm-zero.c b/drivers/md/dm-zero.c
index 51c0639b248..ea569f7348d 100644
--- a/drivers/md/dm-zero.c
+++ b/drivers/md/dm-zero.c
@@ -10,13 +10,15 @@
#include <linux/init.h>
#include <linux/bio.h>
+#define DM_MSG_PREFIX "zero"
+
/*
* Construct a dummy mapping that only returns zeros
*/
static int zero_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
if (argc != 0) {
- ti->error = "dm-zero: No arguments required";
+ ti->error = "No arguments required";
return -EINVAL;
}
@@ -60,7 +62,7 @@ static int __init dm_zero_init(void)
int r = dm_register_target(&zero_target);
if (r < 0)
- DMERR("zero: register failed %d", r);
+ DMERR("register failed %d", r);
return r;
}
@@ -70,7 +72,7 @@ static void __exit dm_zero_exit(void)
int r = dm_unregister_target(&zero_target);
if (r < 0)
- DMERR("zero: unregister failed %d", r);
+ DMERR("unregister failed %d", r);
}
module_init(dm_zero_init)
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 4d710b7a133..c99bf9f0175 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
@@ -21,11 +21,14 @@
#include <linux/hdreg.h>
#include <linux/blktrace_api.h>
+#define DM_MSG_PREFIX "core"
+
static const char *_name = DM_NAME;
static unsigned int major = 0;
static unsigned int _major = 0;
+static DEFINE_SPINLOCK(_minor_lock);
/*
* One of these is allocated per bio.
*/
@@ -49,23 +52,28 @@ struct target_io {
union map_info *dm_get_mapinfo(struct bio *bio)
{
- if (bio && bio->bi_private)
- return &((struct target_io *)bio->bi_private)->info;
- return NULL;
+ if (bio && bio->bi_private)
+ return &((struct target_io *)bio->bi_private)->info;
+ return NULL;
}
+#define MINOR_ALLOCED ((void *)-1)
+
/*
* Bits for the md->flags field.
*/
#define DMF_BLOCK_IO 0
#define DMF_SUSPENDED 1
#define DMF_FROZEN 2
+#define DMF_FREEING 3
+#define DMF_DELETING 4
struct mapped_device {
struct rw_semaphore io_lock;
struct semaphore suspend_lock;
rwlock_t map_lock;
atomic_t holders;
+ atomic_t open_count;
unsigned long flags;
@@ -159,7 +167,7 @@ static void local_exit(void)
bioset_free(dm_set);
if (unregister_blkdev(_major, _name) < 0)
- DMERR("devfs_unregister_blkdev failed");
+ DMERR("unregister_blkdev failed");
_major = 0;
@@ -218,9 +226,25 @@ static int dm_blk_open(struct inode *inode, struct file *file)
{
struct mapped_device *md;
+ spin_lock(&_minor_lock);
+
md = inode->i_bdev->bd_disk->private_data;
+ if (!md)
+ goto out;
+
+ if (test_bit(DMF_FREEING, &md->flags) ||
+ test_bit(DMF_DELETING, &md->flags)) {
+ md = NULL;
+ goto out;
+ }
+
dm_get(md);
- return 0;
+ atomic_inc(&md->open_count);
+
+out:
+ spin_unlock(&_minor_lock);
+
+ return md ? 0 : -ENXIO;
}
static int dm_blk_close(struct inode *inode, struct file *file)
@@ -228,10 +252,35 @@ static int dm_blk_close(struct inode *inode, struct file *file)
struct mapped_device *md;
md = inode->i_bdev->bd_disk->private_data;
+ atomic_dec(&md->open_count);
dm_put(md);
return 0;
}
+int dm_open_count(struct mapped_device *md)
+{
+ return atomic_read(&md->open_count);
+}
+
+/*
+ * Guarantees nothing is using the device before it's deleted.
+ */
+int dm_lock_for_deletion(struct mapped_device *md)
+{
+ int r = 0;
+
+ spin_lock(&_minor_lock);
+
+ if (dm_open_count(md))
+ r = -EBUSY;
+ else
+ set_bit(DMF_DELETING, &md->flags);
+
+ spin_unlock(&_minor_lock);
+
+ return r;
+}
+
static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{
struct mapped_device *md = bdev->bd_disk->private_data;
@@ -456,8 +505,8 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
if (r > 0) {
/* the bio has been remapped so dispatch it */
- blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
- tio->io->bio->bi_bdev->bd_dev, sector,
+ blk_add_trace_remap(bdev_get_queue(clone->bi_bdev), clone,
+ tio->io->bio->bi_bdev->bd_dev, sector,
clone->bi_sector);
generic_make_request(clone);
@@ -744,43 +793,39 @@ static int dm_any_congested(void *congested_data, int bdi_bits)
/*-----------------------------------------------------------------
* An IDR is used to keep track of allocated minor numbers.
*---------------------------------------------------------------*/
-static DEFINE_MUTEX(_minor_lock);
static DEFINE_IDR(_minor_idr);
-static void free_minor(unsigned int minor)
+static void free_minor(int minor)
{
- mutex_lock(&_minor_lock);
+ spin_lock(&_minor_lock);
idr_remove(&_minor_idr, minor);
- mutex_unlock(&_minor_lock);
+ spin_unlock(&_minor_lock);
}
/*
* See if the device with a specific minor # is free.
*/
-static int specific_minor(struct mapped_device *md, unsigned int minor)
+static int specific_minor(struct mapped_device *md, int minor)
{
int r, m;
if (minor >= (1 << MINORBITS))
return -EINVAL;
- mutex_lock(&_minor_lock);
+ r = idr_pre_get(&_minor_idr, GFP_KERNEL);
+ if (!r)
+ return -ENOMEM;
+
+ spin_lock(&_minor_lock);
if (idr_find(&_minor_idr, minor)) {
r = -EBUSY;
goto out;
}
- r = idr_pre_get(&_minor_idr, GFP_KERNEL);
- if (!r) {
- r = -ENOMEM;
- goto out;
- }
-
- r = idr_get_new_above(&_minor_idr, md, minor, &m);
- if (r) {
+ r = idr_get_new_above(&_minor_idr, MINOR_ALLOCED, minor, &m);
+ if (r)
goto out;
- }
if (m != minor) {
idr_remove(&_minor_idr, m);
@@ -789,24 +834,21 @@ static int specific_minor(struct mapped_device *md, unsigned int minor)
}
out:
- mutex_unlock(&_minor_lock);
+ spin_unlock(&_minor_lock);
return r;
}
-static int next_free_minor(struct mapped_device *md, unsigned int *minor)
+static int next_free_minor(struct mapped_device *md, int *minor)
{
- int r;
- unsigned int m;
-
- mutex_lock(&_minor_lock);
+ int r, m;
r = idr_pre_get(&_minor_idr, GFP_KERNEL);
- if (!r) {
- r = -ENOMEM;
- goto out;
- }
+ if (!r)
+ return -ENOMEM;
+
+ spin_lock(&_minor_lock);
- r = idr_get_new(&_minor_idr, md, &m);
+ r = idr_get_new(&_minor_idr, MINOR_ALLOCED, &m);
if (r) {
goto out;
}
@@ -820,7 +862,7 @@ static int next_free_minor(struct mapped_device *md, unsigned int *minor)
*minor = m;
out:
- mutex_unlock(&_minor_lock);
+ spin_unlock(&_minor_lock);
return r;
}
@@ -829,18 +871,25 @@ static struct block_device_operations dm_blk_dops;
/*
* Allocate and initialise a blank device with a given minor.
*/
-static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
+static struct mapped_device *alloc_dev(int minor)
{
int r;
struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL);
+ void *old_md;
if (!md) {
DMWARN("unable to allocate device, out of memory.");
return NULL;
}
+ if (!try_module_get(THIS_MODULE))
+ goto bad0;
+
/* get a minor number for the dev */
- r = persistent ? specific_minor(md, minor) : next_free_minor(md, &minor);
+ if (minor == DM_ANY_MINOR)
+ r = next_free_minor(md, &minor);
+ else
+ r = specific_minor(md, minor);
if (r < 0)
goto bad1;
@@ -849,6 +898,7 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
init_MUTEX(&md->suspend_lock);
rwlock_init(&md->map_lock);
atomic_set(&md->holders, 1);
+ atomic_set(&md->open_count, 0);
atomic_set(&md->event_nr, 0);
md->queue = blk_alloc_queue(GFP_KERNEL);
@@ -875,6 +925,10 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
if (!md->disk)
goto bad4;
+ atomic_set(&md->pending, 0);
+ init_waitqueue_head(&md->wait);
+ init_waitqueue_head(&md->eventq);
+
md->disk->major = _major;
md->disk->first_minor = minor;
md->disk->fops = &dm_blk_dops;
@@ -884,9 +938,12 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
add_disk(md->disk);
format_dev_t(md->name, MKDEV(_major, minor));
- atomic_set(&md->pending, 0);
- init_waitqueue_head(&md->wait);
- init_waitqueue_head(&md->eventq);
+ /* Populate the mapping, nobody knows we exist yet */
+ spin_lock(&_minor_lock);
+ old_md = idr_replace(&_minor_idr, md, minor);
+ spin_unlock(&_minor_lock);
+
+ BUG_ON(old_md != MINOR_ALLOCED);
return md;
@@ -898,13 +955,15 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
blk_cleanup_queue(md->queue);
free_minor(minor);
bad1:
+ module_put(THIS_MODULE);
+ bad0:
kfree(md);
return NULL;
}
static void free_dev(struct mapped_device *md)
{
- unsigned int minor = md->disk->first_minor;
+ int minor = md->disk->first_minor;
if (md->suspended_bdev) {
thaw_bdev(md->suspended_bdev, NULL);
@@ -914,8 +973,14 @@ static void free_dev(struct mapped_device *md)
mempool_destroy(md->io_pool);
del_gendisk(md->disk);
free_minor(minor);
+
+ spin_lock(&_minor_lock);
+ md->disk->private_data = NULL;
+ spin_unlock(&_minor_lock);
+
put_disk(md->disk);
blk_cleanup_queue(md->queue);
+ module_put(THIS_MODULE);
kfree(md);
}
@@ -984,12 +1049,11 @@ static void __unbind(struct mapped_device *md)
/*
* Constructor for a new device.
*/
-static int create_aux(unsigned int minor, int persistent,
- struct mapped_device **result)
+int dm_create(int minor, struct mapped_device **result)
{
struct mapped_device *md;
- md = alloc_dev(minor, persistent);
+ md = alloc_dev(minor);
if (!md)
return -ENXIO;
@@ -997,16 +1061,6 @@ static int create_aux(unsigned int minor, int persistent,
return 0;
}
-int dm_create(struct mapped_device **result)
-{
- return create_aux(0, 0, result);
-}
-
-int dm_create_with_minor(unsigned int minor, struct mapped_device **result)
-{
- return create_aux(minor, 1, result);
-}
-
static struct mapped_device *dm_find_md(dev_t dev)
{
struct mapped_device *md;
@@ -1015,13 +1069,18 @@ static struct mapped_device *dm_find_md(dev_t dev)
if (MAJOR(dev) != _major || minor >= (1 << MINORBITS))
return NULL;
- mutex_lock(&_minor_lock);
+ spin_lock(&_minor_lock);
md = idr_find(&_minor_idr, minor);
- if (!md || (dm_disk(md)->first_minor != minor))
+ if (md && (md == MINOR_ALLOCED ||
+ (dm_disk(md)->first_minor != minor) ||
+ test_bit(DMF_FREEING, &md->flags))) {
md = NULL;
+ goto out;
+ }
- mutex_unlock(&_minor_lock);
+out:
+ spin_unlock(&_minor_lock);
return md;
}
@@ -1051,12 +1110,23 @@ void dm_get(struct mapped_device *md)
atomic_inc(&md->holders);
}
+const char *dm_device_name(struct mapped_device *md)
+{
+ return md->name;
+}
+EXPORT_SYMBOL_GPL(dm_device_name);
+
void dm_put(struct mapped_device *md)
{
struct dm_table *map;
- if (atomic_dec_and_test(&md->holders)) {
+ BUG_ON(test_bit(DMF_FREEING, &md->flags));
+
+ if (atomic_dec_and_lock(&md->holders, &_minor_lock)) {
map = dm_get_table(md);
+ idr_replace(&_minor_idr, MINOR_ALLOCED, dm_disk(md)->first_minor);
+ set_bit(DMF_FREEING, &md->flags);
+ spin_unlock(&_minor_lock);
if (!dm_suspended(md)) {
dm_table_presuspend_targets(map);
dm_table_postsuspend_targets(map);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index fd90bc8f9e4..3c03c0ecab7 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -2,7 +2,7 @@
* Internal header file for device mapper
*
* Copyright (C) 2001, 2002 Sistina Software
- * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
*
* This file is released under the LGPL.
*/
@@ -17,9 +17,10 @@
#include <linux/hdreg.h>
#define DM_NAME "device-mapper"
-#define DMWARN(f, x...) printk(KERN_WARNING DM_NAME ": " f "\n" , ## x)
-#define DMERR(f, x...) printk(KERN_ERR DM_NAME ": " f "\n" , ## x)
-#define DMINFO(f, x...) printk(KERN_INFO DM_NAME ": " f "\n" , ## x)
+
+#define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
0 : scnprintf(result + sz, maxlen - sz, x))
@@ -39,83 +40,16 @@ struct dm_dev {
};
struct dm_table;
-struct mapped_device;
-
-/*-----------------------------------------------------------------
- * Functions for manipulating a struct mapped_device.
- * Drop the reference with dm_put when you finish with the object.
- *---------------------------------------------------------------*/
-int dm_create(struct mapped_device **md);
-int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
-void dm_set_mdptr(struct mapped_device *md, void *ptr);
-void *dm_get_mdptr(struct mapped_device *md);
-struct mapped_device *dm_get_md(dev_t dev);
-
-/*
- * Reference counting for md.
- */
-void dm_get(struct mapped_device *md);
-void dm_put(struct mapped_device *md);
-
-/*
- * A device can still be used while suspended, but I/O is deferred.
- */
-int dm_suspend(struct mapped_device *md, int with_lockfs);
-int dm_resume(struct mapped_device *md);
-
-/*
- * The device must be suspended before calling this method.
- */
-int dm_swap_table(struct mapped_device *md, struct dm_table *t);
-
-/*
- * Drop a reference on the table when you've finished with the
- * result.
- */
-struct dm_table *dm_get_table(struct mapped_device *md);
-
-/*
- * Event functions.
- */
-uint32_t dm_get_event_nr(struct mapped_device *md);
-int dm_wait_event(struct mapped_device *md, int event_nr);
-
-/*
- * Info functions.
- */
-struct gendisk *dm_disk(struct mapped_device *md);
-int dm_suspended(struct mapped_device *md);
-
-/*
- * Geometry functions.
- */
-int dm_get_geometry(struct mapped_device *md, struct hd_geometry *geo);
-int dm_set_geometry(struct mapped_device *md, struct hd_geometry *geo);
/*-----------------------------------------------------------------
- * Functions for manipulating a table. Tables are also reference
- * counted.
+ * Internal table functions.
*---------------------------------------------------------------*/
-int dm_table_create(struct dm_table **result, int mode,
- unsigned num_targets, struct mapped_device *md);
-
-void dm_table_get(struct dm_table *t);
-void dm_table_put(struct dm_table *t);
-
-int dm_table_add_target(struct dm_table *t, const char *type,
- sector_t start, sector_t len, char *params);
-int dm_table_complete(struct dm_table *t);
void dm_table_event_callback(struct dm_table *t,
void (*fn)(void *), void *context);
-void dm_table_event(struct dm_table *t);
-sector_t dm_table_get_size(struct dm_table *t);
struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector);
void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
-unsigned int dm_table_get_num_targets(struct dm_table *t);
struct list_head *dm_table_get_devices(struct dm_table *t);
-int dm_table_get_mode(struct dm_table *t);
-struct mapped_device *dm_table_get_md(struct dm_table *t);
void dm_table_presuspend_targets(struct dm_table *t);
void dm_table_postsuspend_targets(struct dm_table *t);
void dm_table_resume_targets(struct dm_table *t);
@@ -133,7 +67,6 @@ void dm_put_target_type(struct target_type *t);
int dm_target_iterate(void (*iter_func)(struct target_type *tt,
void *param), void *param);
-
/*-----------------------------------------------------------------
* Useful inlines.
*---------------------------------------------------------------*/
@@ -191,5 +124,7 @@ void dm_stripe_exit(void);
void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size);
union map_info *dm_get_mapinfo(struct bio *bio);
+int dm_open_count(struct mapped_device *md);
+int dm_lock_for_deletion(struct mapped_device *md);
#endif
diff --git a/drivers/md/kcopyd.c b/drivers/md/kcopyd.c
index 72480a48d88..f1db6eff485 100644
--- a/drivers/md/kcopyd.c
+++ b/drivers/md/kcopyd.c
@@ -12,7 +12,6 @@
#include <asm/atomic.h>
#include <linux/blkdev.h>
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/list.h>
@@ -314,7 +313,7 @@ static void complete_io(unsigned long error, void *context)
if (error) {
if (job->rw == WRITE)
- job->write_err &= error;
+ job->write_err |= error;
else
job->read_err = 1;
@@ -460,7 +459,7 @@ static void segment_complete(int read_err,
job->read_err = 1;
if (write_err)
- job->write_err &= write_err;
+ job->write_err |= write_err;
/*
* Only dispatch more work if there hasn't been an error.
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 777585458c8..b99c19c7eb2 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -111,7 +111,7 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
-static int linear_run (mddev_t *mddev)
+static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
{
linear_conf_t *conf;
dev_info_t **table;
@@ -121,20 +121,21 @@ static int linear_run (mddev_t *mddev)
sector_t curr_offset;
struct list_head *tmp;
- conf = kzalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t),
+ conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t),
GFP_KERNEL);
if (!conf)
- goto out;
+ return NULL;
+
mddev->private = conf;
cnt = 0;
- mddev->array_size = 0;
+ conf->array_size = 0;
ITERATE_RDEV(mddev,rdev,tmp) {
int j = rdev->raid_disk;
dev_info_t *disk = conf->disks + j;
- if (j < 0 || j > mddev->raid_disks || disk->rdev) {
+ if (j < 0 || j > raid_disks || disk->rdev) {
printk("linear: disk numbering problem. Aborting!\n");
goto out;
}
@@ -152,16 +153,16 @@ static int linear_run (mddev_t *mddev)
blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
disk->size = rdev->size;
- mddev->array_size += rdev->size;
+ conf->array_size += rdev->size;
cnt++;
}
- if (cnt != mddev->raid_disks) {
+ if (cnt != raid_disks) {
printk("linear: not enough drives present. Aborting!\n");
goto out;
}
- min_spacing = mddev->array_size;
+ min_spacing = conf->array_size;
sector_div(min_spacing, PAGE_SIZE/sizeof(struct dev_info *));
/* min_spacing is the minimum spacing that will fit the hash
@@ -170,7 +171,7 @@ static int linear_run (mddev_t *mddev)
* that is larger than min_spacing as use the size of that as
* the actual spacing
*/
- conf->hash_spacing = mddev->array_size;
+ conf->hash_spacing = conf->array_size;
for (i=0; i < cnt-1 ; i++) {
sector_t sz = 0;
int j;
@@ -200,7 +201,7 @@ static int linear_run (mddev_t *mddev)
unsigned round;
unsigned long base;
- sz = mddev->array_size >> conf->preshift;
+ sz = conf->array_size >> conf->preshift;
sz += 1; /* force round-up */
base = conf->hash_spacing >> conf->preshift;
round = sector_div(sz, base);
@@ -227,7 +228,7 @@ static int linear_run (mddev_t *mddev)
curr_offset = 0;
i = 0;
for (curr_offset = 0;
- curr_offset < mddev->array_size;
+ curr_offset < conf->array_size;
curr_offset += conf->hash_spacing) {
while (i < mddev->raid_disks-1 &&
@@ -247,14 +248,56 @@ static int linear_run (mddev_t *mddev)
BUG_ON(table - conf->hash_table > nb_zone);
+ return conf;
+
+out:
+ kfree(conf);
+ return NULL;
+}
+
+static int linear_run (mddev_t *mddev)
+{
+ linear_conf_t *conf;
+
+ conf = linear_conf(mddev, mddev->raid_disks);
+
+ if (!conf)
+ return 1;
+ mddev->private = conf;
+ mddev->array_size = conf->array_size;
+
blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
mddev->queue->unplug_fn = linear_unplug;
mddev->queue->issue_flush_fn = linear_issue_flush;
return 0;
+}
-out:
- kfree(conf);
- return 1;
+static int linear_add(mddev_t *mddev, mdk_rdev_t *rdev)
+{
+ /* Adding a drive to a linear array allows the array to grow.
+ * It is permitted if the new drive has a matching superblock
+ * already on it, with raid_disk equal to raid_disks.
+ * It is achieved by creating a new linear_private_data structure
+ * and swapping it in in-place of the current one.
+ * The current one is never freed until the array is stopped.
+ * This avoids races.
+ */
+ linear_conf_t *newconf;
+
+ if (rdev->raid_disk != mddev->raid_disks)
+ return -EINVAL;
+
+ newconf = linear_conf(mddev,mddev->raid_disks+1);
+
+ if (!newconf)
+ return -ENOMEM;
+
+ newconf->prev = mddev_to_conf(mddev);
+ mddev->private = newconf;
+ mddev->raid_disks++;
+ mddev->array_size = newconf->array_size;
+ set_capacity(mddev->gendisk, mddev->array_size << 1);
+ return 0;
}
static int linear_stop (mddev_t *mddev)
@@ -262,8 +305,12 @@ static int linear_stop (mddev_t *mddev)
linear_conf_t *conf = mddev_to_conf(mddev);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
- kfree(conf->hash_table);
- kfree(conf);
+ do {
+ linear_conf_t *t = conf->prev;
+ kfree(conf->hash_table);
+ kfree(conf);
+ conf = t;
+ } while (conf);
return 0;
}
@@ -360,6 +407,7 @@ static struct mdk_personality linear_personality =
.run = linear_run,
.stop = linear_stop,
.status = linear_status,
+ .hot_add_disk = linear_add,
};
static int __init linear_init (void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index f19b874753a..8dbab2ef388 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -33,17 +33,16 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kthread.h>
#include <linux/linkage.h>
#include <linux/raid/md.h>
#include <linux/raid/bitmap.h>
#include <linux/sysctl.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/buffer_head.h> /* for invalidate_bdev */
#include <linux/suspend.h>
#include <linux/poll.h>
#include <linux/mutex.h>
+#include <linux/ctype.h>
#include <linux/init.h>
@@ -72,6 +71,10 @@ static void autostart_arrays (int part);
static LIST_HEAD(pers_list);
static DEFINE_SPINLOCK(pers_lock);
+static void md_print_devices(void);
+
+#define MD_BUG(x...) { printk("md: bug in file %s, line %d\n", __FILE__, __LINE__); md_print_devices(); }
+
/*
* Current RAID-1,4,5 parallel reconstruction 'guaranteed speed limit'
* is 1000 KB/sec, so the extra system load does not show up that much.
@@ -107,7 +110,7 @@ static ctl_table raid_table[] = {
.procname = "speed_limit_min",
.data = &sysctl_speed_limit_min,
.maxlen = sizeof(int),
- .mode = 0644,
+ .mode = S_IRUGO|S_IWUSR,
.proc_handler = &proc_dointvec,
},
{
@@ -115,7 +118,7 @@ static ctl_table raid_table[] = {
.procname = "speed_limit_max",
.data = &sysctl_speed_limit_max,
.maxlen = sizeof(int),
- .mode = 0644,
+ .mode = S_IRUGO|S_IWUSR,
.proc_handler = &proc_dointvec,
},
{ .ctl_name = 0 }
@@ -126,7 +129,7 @@ static ctl_table raid_dir_table[] = {
.ctl_name = DEV_RAID,
.procname = "raid",
.maxlen = 0,
- .mode = 0555,
+ .mode = S_IRUGO|S_IXUGO,
.child = raid_table,
},
{ .ctl_name = 0 }
@@ -170,7 +173,7 @@ EXPORT_SYMBOL_GPL(md_new_event);
/* Alternate version that can be called from interrupts
* when calling sysfs_notify isn't needed.
*/
-void md_new_event_inintr(mddev_t *mddev)
+static void md_new_event_inintr(mddev_t *mddev)
{
atomic_inc(&md_event_count);
wake_up(&md_event_waiters);
@@ -732,6 +735,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
{
mdp_disk_t *desc;
mdp_super_t *sb = (mdp_super_t *)page_address(rdev->sb_page);
+ __u64 ev1 = md_event(sb);
rdev->raid_disk = -1;
rdev->flags = 0;
@@ -748,7 +752,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->layout = sb->layout;
mddev->raid_disks = sb->raid_disks;
mddev->size = sb->size;
- mddev->events = md_event(sb);
+ mddev->events = ev1;
mddev->bitmap_offset = 0;
mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
@@ -797,7 +801,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
} else if (mddev->pers == NULL) {
/* Insist on good event counter while assembling */
- __u64 ev1 = md_event(sb);
++ev1;
if (ev1 < mddev->events)
return -EINVAL;
@@ -805,19 +808,21 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
/* if adding to array with a bitmap, then we can accept an
* older device ... but not too old.
*/
- __u64 ev1 = md_event(sb);
if (ev1 < mddev->bitmap->events_cleared)
return 0;
- } else /* just a hot-add of a new device, leave raid_disk at -1 */
- return 0;
+ } else {
+ if (ev1 < mddev->events)
+ /* just a hot-add of a new device, leave raid_disk at -1 */
+ return 0;
+ }
if (mddev->level != LEVEL_MULTIPATH) {
desc = sb->disks + rdev->desc_nr;
if (desc->state & (1<<MD_DISK_FAULTY))
set_bit(Faulty, &rdev->flags);
- else if (desc->state & (1<<MD_DISK_SYNC) &&
- desc->raid_disk < mddev->raid_disks) {
+ else if (desc->state & (1<<MD_DISK_SYNC) /* &&
+ desc->raid_disk < mddev->raid_disks */) {
set_bit(In_sync, &rdev->flags);
rdev->raid_disk = desc->raid_disk;
}
@@ -1057,6 +1062,11 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
if (rdev->sb_size & bmask)
rdev-> sb_size = (rdev->sb_size | bmask)+1;
+ if (sb->level == cpu_to_le32(LEVEL_MULTIPATH))
+ rdev->desc_nr = -1;
+ else
+ rdev->desc_nr = le32_to_cpu(sb->dev_number);
+
if (refdev == 0)
ret = 1;
else {
@@ -1100,6 +1110,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
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);
+ __u64 ev1 = le64_to_cpu(sb->events);
rdev->raid_disk = -1;
rdev->flags = 0;
@@ -1115,7 +1126,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->layout = le32_to_cpu(sb->layout);
mddev->raid_disks = le32_to_cpu(sb->raid_disks);
mddev->size = le64_to_cpu(sb->size)/2;
- mddev->events = le64_to_cpu(sb->events);
+ mddev->events = ev1;
mddev->bitmap_offset = 0;
mddev->default_bitmap_offset = 1024 >> 9;
@@ -1149,7 +1160,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
} else if (mddev->pers == NULL) {
/* Insist of good event counter while assembling */
- __u64 ev1 = le64_to_cpu(sb->events);
++ev1;
if (ev1 < mddev->events)
return -EINVAL;
@@ -1157,15 +1167,15 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
/* If adding to array with a bitmap, then we can accept an
* older device, but not too old.
*/
- __u64 ev1 = le64_to_cpu(sb->events);
if (ev1 < mddev->bitmap->events_cleared)
return 0;
- } else /* just a hot-add of a new device, leave raid_disk at -1 */
- return 0;
-
+ } else {
+ if (ev1 < mddev->events)
+ /* just a hot-add of a new device, leave raid_disk at -1 */
+ return 0;
+ }
if (mddev->level != LEVEL_MULTIPATH) {
int role;
- rdev->desc_nr = le32_to_cpu(sb->dev_number);
role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
switch(role) {
case 0xffff: /* spare */
@@ -1174,7 +1184,11 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
set_bit(Faulty, &rdev->flags);
break;
default:
- set_bit(In_sync, &rdev->flags);
+ if ((le32_to_cpu(sb->feature_map) &
+ MD_FEATURE_RECOVERY_OFFSET))
+ rdev->recovery_offset = le64_to_cpu(sb->recovery_offset);
+ else
+ set_bit(In_sync, &rdev->flags);
rdev->raid_disk = role;
break;
}
@@ -1198,6 +1212,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->feature_map = 0;
sb->pad0 = 0;
+ sb->recovery_offset = cpu_to_le64(0);
memset(sb->pad1, 0, sizeof(sb->pad1));
memset(sb->pad2, 0, sizeof(sb->pad2));
memset(sb->pad3, 0, sizeof(sb->pad3));
@@ -1218,6 +1233,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
}
+
+ if (rdev->raid_disk >= 0 &&
+ !test_bit(In_sync, &rdev->flags) &&
+ rdev->recovery_offset > 0) {
+ sb->feature_map |= cpu_to_le32(MD_FEATURE_RECOVERY_OFFSET);
+ sb->recovery_offset = cpu_to_le64(rdev->recovery_offset);
+ }
+
if (mddev->reshape_position != MaxSector) {
sb->feature_map |= cpu_to_le32(MD_FEATURE_RESHAPE_ACTIVE);
sb->reshape_position = cpu_to_le64(mddev->reshape_position);
@@ -1242,11 +1265,12 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->dev_roles[i] = cpu_to_le16(0xfffe);
else if (test_bit(In_sync, &rdev2->flags))
sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
+ else if (rdev2->raid_disk >= 0 && rdev2->recovery_offset > 0)
+ sb->dev_roles[i] = cpu_to_le16(rdev2->raid_disk);
else
sb->dev_roles[i] = cpu_to_le16(0xffff);
}
- sb->recovery_offset = cpu_to_le64(0); /* not supported yet */
sb->sb_csum = calc_sb_1_csum(sb);
}
@@ -1384,7 +1408,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
struct block_device *bdev;
char b[BDEVNAME_SIZE];
- bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
+ bdev = open_partition_by_devnum(dev, FMODE_READ|FMODE_WRITE);
if (IS_ERR(bdev)) {
printk(KERN_ERR "md: could not open %s.\n",
__bdevname(dev, b));
@@ -1394,7 +1418,7 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev)
if (err) {
printk(KERN_ERR "md: could not bd_claim %s.\n",
bdevname(bdev, b));
- blkdev_put(bdev);
+ blkdev_put_partition(bdev);
return err;
}
rdev->bdev = bdev;
@@ -1408,7 +1432,7 @@ static void unlock_rdev(mdk_rdev_t *rdev)
if (!bdev)
MD_BUG();
bd_release(bdev);
- blkdev_put(bdev);
+ blkdev_put_partition(bdev);
}
void md_autodetect_dev(dev_t dev);
@@ -1507,7 +1531,7 @@ static void print_rdev(mdk_rdev_t *rdev)
printk(KERN_INFO "md: no rdev superblock!\n");
}
-void md_print_devices(void)
+static void md_print_devices(void)
{
struct list_head *tmp, *tmp2;
mdk_rdev_t *rdev;
@@ -1536,15 +1560,30 @@ void md_print_devices(void)
}
-static void sync_sbs(mddev_t * mddev)
+static void sync_sbs(mddev_t * mddev, int nospares)
{
+ /* Update each superblock (in-memory image), but
+ * if we are allowed to, skip spares which already
+ * have the right event counter, or have one earlier
+ * (which would mean they aren't being marked as dirty
+ * with the rest of the array)
+ */
mdk_rdev_t *rdev;
struct list_head *tmp;
ITERATE_RDEV(mddev,rdev,tmp) {
- super_types[mddev->major_version].
- sync_super(mddev, rdev);
- rdev->sb_loaded = 1;
+ if (rdev->sb_events == mddev->events ||
+ (nospares &&
+ rdev->raid_disk < 0 &&
+ (rdev->sb_events&1)==0 &&
+ rdev->sb_events+1 == mddev->events)) {
+ /* Don't update this superblock */
+ rdev->sb_loaded = 2;
+ } else {
+ super_types[mddev->major_version].
+ sync_super(mddev, rdev);
+ rdev->sb_loaded = 1;
+ }
}
}
@@ -1554,12 +1593,55 @@ void md_update_sb(mddev_t * mddev)
struct list_head *tmp;
mdk_rdev_t *rdev;
int sync_req;
+ int nospares = 0;
repeat:
spin_lock_irq(&mddev->write_lock);
+
+ if (mddev->degraded && mddev->sb_dirty == 3)
+ /* If the array is degraded, then skipping spares is both
+ * dangerous and fairly pointless.
+ * Dangerous because a device that was removed from the array
+ * might have a event_count that still looks up-to-date,
+ * so it can be re-added without a resync.
+ * Pointless because if there are any spares to skip,
+ * then a recovery will happen and soon that array won't
+ * be degraded any more and the spare can go back to sleep then.
+ */
+ mddev->sb_dirty = 1;
+
sync_req = mddev->in_sync;
mddev->utime = get_seconds();
- mddev->events ++;
+ if (mddev->sb_dirty == 3)
+ /* just a clean<-> dirty transition, possibly leave spares alone,
+ * though if events isn't the right even/odd, we will have to do
+ * spares after all
+ */
+ nospares = 1;
+
+ /* If this is just a dirty<->clean transition, and the array is clean
+ * and 'events' is odd, we can roll back to the previous clean state */
+ if (mddev->sb_dirty == 3
+ && (mddev->in_sync && mddev->recovery_cp == MaxSector)
+ && (mddev->events & 1))
+ mddev->events--;
+ else {
+ /* otherwise we have to go forward and ... */
+ mddev->events ++;
+ if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */
+ /* .. if the array isn't clean, insist on an odd 'events' */
+ if ((mddev->events&1)==0) {
+ mddev->events++;
+ nospares = 0;
+ }
+ } else {
+ /* otherwise insist on an even 'events' (for clean states) */
+ if ((mddev->events&1)) {
+ mddev->events++;
+ nospares = 0;
+ }
+ }
+ }
if (!mddev->events) {
/*
@@ -1571,7 +1653,7 @@ repeat:
mddev->events --;
}
mddev->sb_dirty = 2;
- sync_sbs(mddev);
+ sync_sbs(mddev, nospares);
/*
* do not write anything to disk if using
@@ -1593,6 +1675,8 @@ repeat:
ITERATE_RDEV(mddev,rdev,tmp) {
char b[BDEVNAME_SIZE];
dprintk(KERN_INFO "md: ");
+ if (rdev->sb_loaded != 1)
+ continue; /* no noise on spare devices */
if (test_bit(Faulty, &rdev->flags))
dprintk("(skipping faulty ");
@@ -1604,6 +1688,7 @@ repeat:
dprintk(KERN_INFO "(write) %s's sb offset: %llu\n",
bdevname(rdev->bdev,b),
(unsigned long long)rdev->sb_offset);
+ rdev->sb_events = mddev->events;
} else
dprintk(")\n");
@@ -1667,6 +1752,10 @@ state_show(mdk_rdev_t *rdev, char *page)
len += sprintf(page+len, "%sin_sync",sep);
sep = ",";
}
+ if (test_bit(WriteMostly, &rdev->flags)) {
+ len += sprintf(page+len, "%swrite_mostly",sep);
+ sep = ",";
+ }
if (!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags)) {
len += sprintf(page+len, "%sspare", sep);
@@ -1675,8 +1764,40 @@ state_show(mdk_rdev_t *rdev, char *page)
return len+sprintf(page+len, "\n");
}
-static struct rdev_sysfs_entry
-rdev_state = __ATTR_RO(state);
+static ssize_t
+state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
+{
+ /* can write
+ * faulty - simulates and error
+ * remove - disconnects the device
+ * writemostly - sets write_mostly
+ * -writemostly - clears write_mostly
+ */
+ int err = -EINVAL;
+ if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
+ md_error(rdev->mddev, rdev);
+ err = 0;
+ } else if (cmd_match(buf, "remove")) {
+ if (rdev->raid_disk >= 0)
+ err = -EBUSY;
+ else {
+ mddev_t *mddev = rdev->mddev;
+ kick_rdev_from_array(rdev);
+ md_update_sb(mddev);
+ md_new_event(mddev);
+ err = 0;
+ }
+ } else if (cmd_match(buf, "writemostly")) {
+ set_bit(WriteMostly, &rdev->flags);
+ err = 0;
+ } else if (cmd_match(buf, "-writemostly")) {
+ clear_bit(WriteMostly, &rdev->flags);
+ err = 0;
+ }
+ return err ? err : len;
+}
+static struct rdev_sysfs_entry rdev_state =
+__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);
static ssize_t
super_show(mdk_rdev_t *rdev, char *page)
@@ -1707,7 +1828,7 @@ errors_store(mdk_rdev_t *rdev, const char *buf, size_t len)
return -EINVAL;
}
static struct rdev_sysfs_entry rdev_errors =
-__ATTR(errors, 0644, errors_show, errors_store);
+__ATTR(errors, S_IRUGO|S_IWUSR, errors_show, errors_store);
static ssize_t
slot_show(mdk_rdev_t *rdev, char *page)
@@ -1741,7 +1862,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len)
static struct rdev_sysfs_entry rdev_slot =
-__ATTR(slot, 0644, slot_show, slot_store);
+__ATTR(slot, S_IRUGO|S_IWUSR, slot_show, slot_store);
static ssize_t
offset_show(mdk_rdev_t *rdev, char *page)
@@ -1763,7 +1884,7 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len)
}
static struct rdev_sysfs_entry rdev_offset =
-__ATTR(offset, 0644, offset_show, offset_store);
+__ATTR(offset, S_IRUGO|S_IWUSR, offset_show, offset_store);
static ssize_t
rdev_size_show(mdk_rdev_t *rdev, char *page)
@@ -1787,7 +1908,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
}
static struct rdev_sysfs_entry rdev_size =
-__ATTR(size, 0644, rdev_size_show, rdev_size_store);
+__ATTR(size, S_IRUGO|S_IWUSR, rdev_size_show, rdev_size_store);
static struct attribute *rdev_default_attrs[] = {
&rdev_state.attr,
@@ -1818,6 +1939,8 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr,
if (!entry->store)
return -EIO;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
return entry->store(rdev, page, length);
}
@@ -1873,6 +1996,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
rdev->desc_nr = -1;
rdev->flags = 0;
rdev->data_offset = 0;
+ rdev->sb_events = 0;
atomic_set(&rdev->nr_pending, 0);
atomic_set(&rdev->read_errors, 0);
atomic_set(&rdev->corrected_errors, 0);
@@ -1978,6 +2102,54 @@ static void analyze_sbs(mddev_t * mddev)
}
static ssize_t
+safe_delay_show(mddev_t *mddev, char *page)
+{
+ int msec = (mddev->safemode_delay*1000)/HZ;
+ return sprintf(page, "%d.%03d\n", msec/1000, msec%1000);
+}
+static ssize_t
+safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len)
+{
+ int scale=1;
+ int dot=0;
+ int i;
+ unsigned long msec;
+ char buf[30];
+ char *e;
+ /* remove a period, and count digits after it */
+ if (len >= sizeof(buf))
+ return -EINVAL;
+ strlcpy(buf, cbuf, len);
+ buf[len] = 0;
+ for (i=0; i<len; i++) {
+ if (dot) {
+ if (isdigit(buf[i])) {
+ buf[i-1] = buf[i];
+ scale *= 10;
+ }
+ buf[i] = 0;
+ } else if (buf[i] == '.') {
+ dot=1;
+ buf[i] = 0;
+ }
+ }
+ msec = simple_strtoul(buf, &e, 10);
+ if (e == buf || (*e && *e != '\n'))
+ return -EINVAL;
+ msec = (msec * 1000) / scale;
+ if (msec == 0)
+ mddev->safemode_delay = 0;
+ else {
+ mddev->safemode_delay = (msec*HZ)/1000;
+ if (mddev->safemode_delay == 0)
+ mddev->safemode_delay = 1;
+ }
+ return len;
+}
+static struct md_sysfs_entry md_safe_delay =
+__ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store);
+
+static ssize_t
level_show(mddev_t *mddev, char *page)
{
struct mdk_personality *p = mddev->pers;
@@ -2010,7 +2182,33 @@ level_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_level =
-__ATTR(level, 0644, level_show, level_store);
+__ATTR(level, S_IRUGO|S_IWUSR, level_show, level_store);
+
+
+static ssize_t
+layout_show(mddev_t *mddev, char *page)
+{
+ /* just a number, not meaningful for all levels */
+ return sprintf(page, "%d\n", mddev->layout);
+}
+
+static ssize_t
+layout_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ char *e;
+ unsigned long n = simple_strtoul(buf, &e, 10);
+ if (mddev->pers)
+ return -EBUSY;
+
+ if (!*buf || (*e && *e != '\n'))
+ return -EINVAL;
+
+ mddev->layout = n;
+ return len;
+}
+static struct md_sysfs_entry md_layout =
+__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);
+
static ssize_t
raid_disks_show(mddev_t *mddev, char *page)
@@ -2040,7 +2238,7 @@ raid_disks_store(mddev_t *mddev, const char *buf, size_t len)
return rv ? rv : len;
}
static struct md_sysfs_entry md_raid_disks =
-__ATTR(raid_disks, 0644, raid_disks_show, raid_disks_store);
+__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
static ssize_t
chunk_size_show(mddev_t *mddev, char *page)
@@ -2064,7 +2262,202 @@ chunk_size_store(mddev_t *mddev, const char *buf, size_t len)
return len;
}
static struct md_sysfs_entry md_chunk_size =
-__ATTR(chunk_size, 0644, chunk_size_show, chunk_size_store);
+__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);
+
+static ssize_t
+resync_start_show(mddev_t *mddev, char *page)
+{
+ return sprintf(page, "%llu\n", (unsigned long long)mddev->recovery_cp);
+}
+
+static ssize_t
+resync_start_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ /* can only set chunk_size if array is not yet active */
+ char *e;
+ unsigned long long n = simple_strtoull(buf, &e, 10);
+
+ if (mddev->pers)
+ return -EBUSY;
+ if (!*buf || (*e && *e != '\n'))
+ return -EINVAL;
+
+ mddev->recovery_cp = n;
+ return len;
+}
+static struct md_sysfs_entry md_resync_start =
+__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
+
+/*
+ * The array state can be:
+ *
+ * clear
+ * No devices, no size, no level
+ * Equivalent to STOP_ARRAY ioctl
+ * inactive
+ * May have some settings, but array is not active
+ * all IO results in error
+ * When written, doesn't tear down array, but just stops it
+ * suspended (not supported yet)
+ * All IO requests will block. The array can be reconfigured.
+ * Writing this, if accepted, will block until array is quiessent
+ * readonly
+ * no resync can happen. no superblocks get written.
+ * write requests fail
+ * read-auto
+ * like readonly, but behaves like 'clean' on a write request.
+ *
+ * clean - no pending writes, but otherwise active.
+ * When written to inactive array, starts without resync
+ * If a write request arrives then
+ * if metadata is known, mark 'dirty' and switch to 'active'.
+ * if not known, block and switch to write-pending
+ * If written to an active array that has pending writes, then fails.
+ * active
+ * fully active: IO and resync can be happening.
+ * When written to inactive array, starts with resync
+ *
+ * write-pending
+ * clean, but writes are blocked waiting for 'active' to be written.
+ *
+ * active-idle
+ * like active, but no writes have been seen for a while (100msec).
+ *
+ */
+enum array_state { clear, inactive, suspended, readonly, read_auto, clean, active,
+ write_pending, active_idle, bad_word};
+static char *array_states[] = {
+ "clear", "inactive", "suspended", "readonly", "read-auto", "clean", "active",
+ "write-pending", "active-idle", NULL };
+
+static int match_word(const char *word, char **list)
+{
+ int n;
+ for (n=0; list[n]; n++)
+ if (cmd_match(word, list[n]))
+ break;
+ return n;
+}
+
+static ssize_t
+array_state_show(mddev_t *mddev, char *page)
+{
+ enum array_state st = inactive;
+
+ if (mddev->pers)
+ switch(mddev->ro) {
+ case 1:
+ st = readonly;
+ break;
+ case 2:
+ st = read_auto;
+ break;
+ case 0:
+ if (mddev->in_sync)
+ st = clean;
+ else if (mddev->safemode)
+ st = active_idle;
+ else
+ st = active;
+ }
+ else {
+ if (list_empty(&mddev->disks) &&
+ mddev->raid_disks == 0 &&
+ mddev->size == 0)
+ st = clear;
+ else
+ st = inactive;
+ }
+ return sprintf(page, "%s\n", array_states[st]);
+}
+
+static int do_md_stop(mddev_t * mddev, int ro);
+static int do_md_run(mddev_t * mddev);
+static int restart_array(mddev_t *mddev);
+
+static ssize_t
+array_state_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ int err = -EINVAL;
+ enum array_state st = match_word(buf, array_states);
+ switch(st) {
+ case bad_word:
+ break;
+ case clear:
+ /* stopping an active array */
+ if (mddev->pers) {
+ if (atomic_read(&mddev->active) > 1)
+ return -EBUSY;
+ err = do_md_stop(mddev, 0);
+ }
+ break;
+ case inactive:
+ /* stopping an active array */
+ if (mddev->pers) {
+ if (atomic_read(&mddev->active) > 1)
+ return -EBUSY;
+ err = do_md_stop(mddev, 2);
+ }
+ break;
+ case suspended:
+ break; /* not supported yet */
+ case readonly:
+ if (mddev->pers)
+ err = do_md_stop(mddev, 1);
+ else {
+ mddev->ro = 1;
+ err = do_md_run(mddev);
+ }
+ break;
+ case read_auto:
+ /* stopping an active array */
+ if (mddev->pers) {
+ err = do_md_stop(mddev, 1);
+ if (err == 0)
+ mddev->ro = 2; /* FIXME mark devices writable */
+ } else {
+ mddev->ro = 2;
+ err = do_md_run(mddev);
+ }
+ break;
+ case clean:
+ if (mddev->pers) {
+ restart_array(mddev);
+ spin_lock_irq(&mddev->write_lock);
+ if (atomic_read(&mddev->writes_pending) == 0) {
+ mddev->in_sync = 1;
+ mddev->sb_dirty = 1;
+ }
+ spin_unlock_irq(&mddev->write_lock);
+ } else {
+ mddev->ro = 0;
+ mddev->recovery_cp = MaxSector;
+ err = do_md_run(mddev);
+ }
+ break;
+ case active:
+ if (mddev->pers) {
+ restart_array(mddev);
+ mddev->sb_dirty = 0;
+ wake_up(&mddev->sb_wait);
+ err = 0;
+ } else {
+ mddev->ro = 0;
+ err = do_md_run(mddev);
+ }
+ break;
+ case write_pending:
+ case active_idle:
+ /* these cannot be set */
+ break;
+ }
+ if (err)
+ return err;
+ else
+ return len;
+}
+static struct md_sysfs_entry md_array_state =
+__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
static ssize_t
null_show(mddev_t *mddev, char *page)
@@ -2124,7 +2517,7 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_new_device =
-__ATTR(new_dev, 0200, null_show, new_dev_store);
+__ATTR(new_dev, S_IWUSR, null_show, new_dev_store);
static ssize_t
size_show(mddev_t *mddev, char *page)
@@ -2162,7 +2555,7 @@ size_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_size =
-__ATTR(component_size, 0644, size_show, size_store);
+__ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store);
/* Metdata version.
@@ -2210,7 +2603,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len)
}
static struct md_sysfs_entry md_metadata =
-__ATTR(metadata_version, 0644, metadata_show, metadata_store);
+__ATTR(metadata_version, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
static ssize_t
action_show(mddev_t *mddev, char *page)
@@ -2278,12 +2671,11 @@ mismatch_cnt_show(mddev_t *mddev, char *page)
(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_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 md_sysfs_entry md_mismatches = __ATTR_RO(mismatch_cnt);
static ssize_t
sync_min_show(mddev_t *mddev, char *page)
@@ -2342,15 +2734,14 @@ static ssize_t
sync_speed_show(mddev_t *mddev, char *page)
{
unsigned long resync, dt, db;
- resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active));
+ resync = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active));
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
db = resync - (mddev->resync_mark_cnt);
return sprintf(page, "%ld\n", db/dt/2); /* K/sec */
}
-static struct md_sysfs_entry
-md_sync_speed = __ATTR_RO(sync_speed);
+static struct md_sysfs_entry md_sync_speed = __ATTR_RO(sync_speed);
static ssize_t
sync_completed_show(mddev_t *mddev, char *page)
@@ -2366,8 +2757,7 @@ sync_completed_show(mddev_t *mddev, char *page)
return sprintf(page, "%lu / %lu\n", resync, max_blocks);
}
-static struct md_sysfs_entry
-md_sync_completed = __ATTR_RO(sync_completed);
+static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed);
static ssize_t
suspend_lo_show(mddev_t *mddev, char *page)
@@ -2428,11 +2818,15 @@ __ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
static struct attribute *md_default_attrs[] = {
&md_level.attr,
+ &md_layout.attr,
&md_raid_disks.attr,
&md_chunk_size.attr,
&md_size.attr,
+ &md_resync_start.attr,
&md_metadata.attr,
&md_new_device.attr,
+ &md_safe_delay.attr,
+ &md_array_state.attr,
NULL,
};
@@ -2480,6 +2874,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
if (!entry->store)
return -EIO;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
rv = mddev_lock(mddev);
if (!rv) {
rv = entry->store(mddev, page, length);
@@ -2532,13 +2928,10 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
}
disk->major = MAJOR(dev);
disk->first_minor = unit << shift;
- if (partitioned) {
+ if (partitioned)
sprintf(disk->disk_name, "md_d%d", unit);
- sprintf(disk->devfs_name, "md/d%d", unit);
- } else {
+ else
sprintf(disk->disk_name, "md%d", unit);
- sprintf(disk->devfs_name, "md/%d", unit);
- }
disk->fops = &md_fops;
disk->private_data = mddev;
disk->queue = mddev->queue;
@@ -2553,8 +2946,6 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
return NULL;
}
-void md_wakeup_thread(mdk_thread_t *thread);
-
static void md_safemode_timeout(unsigned long data)
{
mddev_t *mddev = (mddev_t *) data;
@@ -2708,7 +3099,7 @@ static int do_md_run(mddev_t * mddev)
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->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1;
ITERATE_RDEV(mddev,rdev,tmp)
@@ -2719,7 +3110,6 @@ static int do_md_run(mddev_t * mddev)
}
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- md_wakeup_thread(mddev->thread);
if (mddev->sb_dirty)
md_update_sb(mddev);
@@ -2736,6 +3126,37 @@ static int do_md_run(mddev_t * mddev)
mddev->queue->queuedata = mddev;
mddev->queue->make_request_fn = mddev->pers->make_request;
+ /* If there is a partially-recovered drive we need to
+ * start recovery here. If we leave it to md_check_recovery,
+ * it will remove the drives and not do the right thing
+ */
+ if (mddev->degraded && !mddev->sync_thread) {
+ struct list_head *rtmp;
+ int spares = 0;
+ ITERATE_RDEV(mddev,rdev,rtmp)
+ if (rdev->raid_disk >= 0 &&
+ !test_bit(In_sync, &rdev->flags) &&
+ !test_bit(Faulty, &rdev->flags))
+ /* complete an interrupted recovery */
+ spares++;
+ if (spares && mddev->pers->sync_request) {
+ mddev->recovery = 0;
+ set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ mddev->sync_thread = md_register_thread(md_do_sync,
+ mddev,
+ "%s_resync");
+ if (!mddev->sync_thread) {
+ printk(KERN_ERR "%s: could not start resync"
+ " thread...\n",
+ mdname(mddev));
+ /* leave the spares where they are, it shouldn't hurt */
+ mddev->recovery = 0;
+ }
+ }
+ }
+ md_wakeup_thread(mddev->thread);
+ md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
+
mddev->changed = 1;
md_new_event(mddev);
return 0;
@@ -2769,18 +3190,47 @@ static int restart_array(mddev_t *mddev)
*/
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
md_wakeup_thread(mddev->thread);
+ md_wakeup_thread(mddev->sync_thread);
err = 0;
- } else {
- printk(KERN_ERR "md: %s has no personality assigned.\n",
- mdname(mddev));
+ } else
err = -EINVAL;
- }
out:
return err;
}
-static int do_md_stop(mddev_t * mddev, int ro)
+/* similar to deny_write_access, but accounts for our holding a reference
+ * to the file ourselves */
+static int deny_bitmap_write_access(struct file * file)
+{
+ struct inode *inode = file->f_mapping->host;
+
+ spin_lock(&inode->i_lock);
+ if (atomic_read(&inode->i_writecount) > 1) {
+ spin_unlock(&inode->i_lock);
+ return -ETXTBSY;
+ }
+ atomic_set(&inode->i_writecount, -1);
+ spin_unlock(&inode->i_lock);
+
+ return 0;
+}
+
+static void restore_bitmap_write_access(struct file *file)
+{
+ struct inode *inode = file->f_mapping->host;
+
+ spin_lock(&inode->i_lock);
+ atomic_set(&inode->i_writecount, 1);
+ spin_unlock(&inode->i_lock);
+}
+
+/* mode:
+ * 0 - completely stop and dis-assemble array
+ * 1 - switch to readonly
+ * 2 - stop but do not disassemble array
+ */
+static int do_md_stop(mddev_t * mddev, int mode)
{
int err = 0;
struct gendisk *disk = mddev->gendisk;
@@ -2792,6 +3242,7 @@ static int do_md_stop(mddev_t * mddev, int ro)
}
if (mddev->sync_thread) {
+ set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
md_unregister_thread(mddev->sync_thread);
mddev->sync_thread = NULL;
@@ -2801,12 +3252,15 @@ static int do_md_stop(mddev_t * mddev, int ro)
invalidate_partition(disk, 0);
- if (ro) {
+ switch(mode) {
+ case 1: /* readonly */
err = -ENXIO;
if (mddev->ro==1)
goto out;
mddev->ro = 1;
- } else {
+ break;
+ case 0: /* disassemble */
+ case 2: /* stop */
bitmap_flush(mddev);
md_super_wait(mddev);
if (mddev->ro)
@@ -2821,19 +3275,20 @@ static int do_md_stop(mddev_t * mddev, int ro)
if (mddev->ro)
mddev->ro = 0;
}
- if (!mddev->in_sync) {
+ if (!mddev->in_sync || mddev->sb_dirty) {
/* mark array as shutdown cleanly */
mddev->in_sync = 1;
md_update_sb(mddev);
}
- if (ro)
+ if (mode == 1)
set_disk_ro(disk, 1);
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
}
/*
* Free resources if final stop
*/
- if (!ro) {
+ if (mode == 0) {
mdk_rdev_t *rdev;
struct list_head *tmp;
struct gendisk *disk;
@@ -2841,7 +3296,7 @@ static int do_md_stop(mddev_t * mddev, int ro)
bitmap_destroy(mddev);
if (mddev->bitmap_file) {
- atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
+ restore_bitmap_write_access(mddev->bitmap_file);
fput(mddev->bitmap_file);
mddev->bitmap_file = NULL;
}
@@ -2857,11 +3312,15 @@ static int do_md_stop(mddev_t * mddev, int ro)
export_array(mddev);
mddev->array_size = 0;
+ mddev->size = 0;
+ mddev->raid_disks = 0;
+ mddev->recovery_cp = 0;
+
disk = mddev->gendisk;
if (disk)
set_capacity(disk, 0);
mddev->changed = 1;
- } else
+ } else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
mdname(mddev));
err = 0;
@@ -3264,6 +3723,17 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
rdev->raid_disk = -1;
err = bind_rdev_to_array(rdev, mddev);
+ if (!err && !mddev->pers->hot_remove_disk) {
+ /* If there is hot_add_disk but no hot_remove_disk
+ * then added disks for geometry changes,
+ * and should be added immediately.
+ */
+ super_types[mddev->major_version].
+ validate_super(mddev, rdev);
+ err = mddev->pers->hot_add_disk(mddev, rdev);
+ if (err)
+ unbind_rdev_from_array(rdev);
+ }
if (err)
export_rdev(rdev);
@@ -3434,23 +3904,6 @@ abort_export:
return err;
}
-/* similar to deny_write_access, but accounts for our holding a reference
- * to the file ourselves */
-static int deny_bitmap_write_access(struct file * file)
-{
- struct inode *inode = file->f_mapping->host;
-
- spin_lock(&inode->i_lock);
- if (atomic_read(&inode->i_writecount) > 1) {
- spin_unlock(&inode->i_lock);
- return -ETXTBSY;
- }
- atomic_set(&inode->i_writecount, -1);
- spin_unlock(&inode->i_lock);
-
- return 0;
-}
-
static int set_bitmap_file(mddev_t *mddev, int fd)
{
int err;
@@ -3491,12 +3944,17 @@ static int set_bitmap_file(mddev_t *mddev, int fd)
mddev->pers->quiesce(mddev, 1);
if (fd >= 0)
err = bitmap_create(mddev);
- if (fd < 0 || err)
+ if (fd < 0 || err) {
bitmap_destroy(mddev);
+ fd = -1; /* make sure to put the file */
+ }
mddev->pers->quiesce(mddev, 0);
- } else if (fd < 0) {
- if (mddev->bitmap_file)
+ }
+ if (fd < 0) {
+ if (mddev->bitmap_file) {
+ restore_bitmap_write_access(mddev->bitmap_file);
fput(mddev->bitmap_file);
+ }
mddev->bitmap_file = NULL;
}
@@ -3977,11 +4435,6 @@ static int md_ioctl(struct inode *inode, struct file *file,
goto done_unlock;
default:
- if (_IOC_TYPE(cmd) == MD_MAJOR)
- printk(KERN_WARNING "md: %s(pid %d) used"
- " obsolete MD ioctl, upgrade your"
- " software to use new ictls.\n",
- current->comm, current->pid);
err = -EINVAL;
goto abort_unlock;
}
@@ -4152,6 +4605,8 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
__builtin_return_address(0),__builtin_return_address(1),
__builtin_return_address(2),__builtin_return_address(3));
*/
+ if (!mddev->pers)
+ return;
if (!mddev->pers->error_handler)
return;
mddev->pers->error_handler(mddev,rdev);
@@ -4249,12 +4704,13 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
*/
dt = ((jiffies - mddev->resync_mark) / HZ);
if (!dt) dt++;
- db = resync - (mddev->resync_mark_cnt/2);
- rt = (dt * ((unsigned long)(max_blocks-resync) / (db/100+1)))/100;
+ db = (mddev->curr_mark_cnt - atomic_read(&mddev->recovery_active))
+ - mddev->resync_mark_cnt;
+ rt = (dt * ((unsigned long)(max_blocks-resync) / (db/2/100+1)))/100;
seq_printf(seq, " finish=%lu.%lumin", rt / 60, (rt % 60)/6);
- seq_printf(seq, " speed=%ldK/sec", db/dt);
+ seq_printf(seq, " speed=%ldK/sec", db/2/dt);
}
static void *md_seq_start(struct seq_file *seq, loff_t *pos)
@@ -4586,7 +5042,7 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) {
mddev->in_sync = 0;
- mddev->sb_dirty = 1;
+ mddev->sb_dirty = 3;
md_wakeup_thread(mddev->thread);
}
spin_unlock_irq(&mddev->write_lock);
@@ -4599,7 +5055,7 @@ void md_write_end(mddev_t *mddev)
if (atomic_dec_and_test(&mddev->writes_pending)) {
if (mddev->safemode == 2)
md_wakeup_thread(mddev->thread);
- else
+ else if (mddev->safemode_delay)
mod_timer(&mddev->safemode_timer, jiffies + mddev->safemode_delay);
}
}
@@ -4620,10 +5076,14 @@ void md_do_sync(mddev_t *mddev)
struct list_head *tmp;
sector_t last_check;
int skipped = 0;
+ struct list_head *rtmp;
+ mdk_rdev_t *rdev;
/* just incase thread restarts... */
if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
return;
+ if (mddev->ro) /* never try to sync a read-only array */
+ return;
/* we overload curr_resync somewhat here.
* 0 == not engaged in resync at all
@@ -4682,17 +5142,30 @@ void md_do_sync(mddev_t *mddev)
}
} while (mddev->curr_resync < 2);
+ j = 0;
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;
mddev->resync_mismatches = 0;
+ /* we don't use the checkpoint if there's a bitmap */
+ if (!mddev->bitmap &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ j = mddev->recovery_cp;
} else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
max_sectors = mddev->size << 1;
- else
+ else {
/* recovery follows the physical size of devices */
max_sectors = mddev->size << 1;
+ j = MaxSector;
+ ITERATE_RDEV(mddev,rdev,rtmp)
+ if (rdev->raid_disk >= 0 &&
+ !test_bit(Faulty, &rdev->flags) &&
+ !test_bit(In_sync, &rdev->flags) &&
+ rdev->recovery_offset < j)
+ j = rdev->recovery_offset;
+ }
printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
@@ -4702,12 +5175,7 @@ void md_do_sync(mddev_t *mddev)
speed_max(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
- && ! test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
- j = mddev->recovery_cp;
- else
- j = 0;
+
io_sectors = 0;
for (m = 0; m < SYNC_MARKS; m++) {
mark[m] = jiffies;
@@ -4753,6 +5221,7 @@ void md_do_sync(mddev_t *mddev)
j += sectors;
if (j>1) mddev->curr_resync = j;
+ mddev->curr_mark_cnt = io_sectors;
if (last_check == 0)
/* this is the earliers that rebuilt will be
* visible in /proc/mdstat
@@ -4828,15 +5297,28 @@ void md_do_sync(mddev_t *mddev)
if (!test_bit(MD_RECOVERY_ERR, &mddev->recovery) &&
test_bit(MD_RECOVERY_SYNC, &mddev->recovery) &&
!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) &&
- mddev->curr_resync > 2 &&
- mddev->curr_resync >= mddev->recovery_cp) {
- if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
- printk(KERN_INFO
- "md: checkpointing recovery of %s.\n",
- mdname(mddev));
- mddev->recovery_cp = mddev->curr_resync;
- } else
- mddev->recovery_cp = MaxSector;
+ mddev->curr_resync > 2) {
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+ if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+ if (mddev->curr_resync >= mddev->recovery_cp) {
+ printk(KERN_INFO
+ "md: checkpointing recovery of %s.\n",
+ mdname(mddev));
+ mddev->recovery_cp = mddev->curr_resync;
+ }
+ } else
+ mddev->recovery_cp = MaxSector;
+ } else {
+ if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery))
+ mddev->curr_resync = MaxSector;
+ ITERATE_RDEV(mddev,rdev,rtmp)
+ if (rdev->raid_disk >= 0 &&
+ !test_bit(Faulty, &rdev->flags) &&
+ !test_bit(In_sync, &rdev->flags) &&
+ rdev->recovery_offset < mddev->curr_resync)
+ rdev->recovery_offset = mddev->curr_resync;
+ mddev->sb_dirty = 1;
+ }
}
skip:
@@ -4908,7 +5390,7 @@ void md_check_recovery(mddev_t *mddev)
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1;
- mddev->sb_dirty = 1;
+ mddev->sb_dirty = 3;
}
if (mddev->safemode == 1)
mddev->safemode = 0;
@@ -4957,6 +5439,8 @@ void md_check_recovery(mddev_t *mddev)
clear_bit(MD_RECOVERY_INTR, &mddev->recovery);
clear_bit(MD_RECOVERY_DONE, &mddev->recovery);
+ if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
+ goto unlock;
/* no recovery is running.
* remove any failed drives, then
* add spares if possible.
@@ -4979,6 +5463,7 @@ void md_check_recovery(mddev_t *mddev)
ITERATE_RDEV(mddev,rdev,rtmp)
if (rdev->raid_disk < 0
&& !test_bit(Faulty, &rdev->flags)) {
+ rdev->recovery_offset = 0;
if (mddev->pers->hot_add_disk(mddev,rdev)) {
char nm[20];
sprintf(nm, "rd%d", rdev->raid_disk);
@@ -5071,8 +5556,6 @@ static void md_geninit(void)
static int __init md_init(void)
{
- int minor;
-
printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d,"
" MD_SB_DISKS=%d\n",
MD_MAJOR_VERSION, MD_MINOR_VERSION,
@@ -5086,23 +5569,11 @@ static int __init md_init(void)
unregister_blkdev(MAJOR_NR, "md");
return -1;
}
- devfs_mk_dir("md");
blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE,
md_probe, NULL, NULL);
blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<<MdpMinorShift, THIS_MODULE,
md_probe, NULL, NULL);
- for (minor=0; minor < MAX_MD_DEVS; ++minor)
- devfs_mk_bdev(MKDEV(MAJOR_NR, minor),
- S_IFBLK|S_IRUSR|S_IWUSR,
- "md/%d", minor);
-
- for (minor=0; minor < MAX_MD_DEVS; ++minor)
- devfs_mk_bdev(MKDEV(mdp_major, minor<<MdpMinorShift),
- S_IFBLK|S_IRUSR|S_IWUSR,
- "md/mdp%d", minor);
-
-
register_reboot_notifier(&md_notifier);
raid_table_header = register_sysctl_table(raid_root_table, 1);
@@ -5158,15 +5629,9 @@ static __exit void md_exit(void)
{
mddev_t *mddev;
struct list_head *tmp;
- int i;
+
blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS);
blk_unregister_region(MKDEV(mdp_major,0), MAX_MD_DEVS << MdpMinorShift);
- for (i=0; i < MAX_MD_DEVS; i++)
- devfs_remove("md/%d", i);
- for (i=0; i < MAX_MD_DEVS; i++)
- devfs_remove("md/d%d", i);
-
- devfs_remove("md");
unregister_blkdev(MAJOR_NR,"md");
unregister_blkdev(mdp_major, "mdp");
@@ -5203,8 +5668,8 @@ static int set_ro(const char *val, struct kernel_param *kp)
return -EINVAL;
}
-module_param_call(start_ro, set_ro, get_ro, NULL, 0600);
-module_param(start_dirty_degraded, int, 0644);
+module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
+module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
EXPORT_SYMBOL(register_md_personality);
@@ -5216,7 +5681,6 @@ EXPORT_SYMBOL(md_write_end);
EXPORT_SYMBOL(md_register_thread);
EXPORT_SYMBOL(md_unregister_thread);
EXPORT_SYMBOL(md_wakeup_thread);
-EXPORT_SYMBOL(md_print_devices);
EXPORT_SYMBOL(md_check_recovery);
MODULE_LICENSE("GPL");
MODULE_ALIAS("md");
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 4070eff6f0f..3b4d69c0562 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -374,26 +374,26 @@ 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)) {
+ if (test_bit(R1BIO_BarrierRetry, &r1_bio->state))
reschedule_retry(r1_bio);
- goto out;
- }
- /* it really is the end of this request */
- if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
- /* free extra copy of the data pages */
- int i = bio->bi_vcnt;
- while (i--)
- safe_put_page(bio->bi_io_vec[i].bv_page);
+ else {
+ /* it really is the end of this request */
+ if (test_bit(R1BIO_BehindIO, &r1_bio->state)) {
+ /* free extra copy of the data pages */
+ int i = bio->bi_vcnt;
+ while (i--)
+ safe_put_page(bio->bi_io_vec[i].bv_page);
+ }
+ /* clear the bitmap if all writes complete successfully */
+ bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
+ r1_bio->sectors,
+ !test_bit(R1BIO_Degraded, &r1_bio->state),
+ behind);
+ md_write_end(r1_bio->mddev);
+ raid_end_bio_io(r1_bio);
}
- /* clear the bitmap if all writes complete successfully */
- bitmap_endwrite(r1_bio->mddev->bitmap, r1_bio->sector,
- r1_bio->sectors,
- !test_bit(R1BIO_Degraded, &r1_bio->state),
- behind);
- md_write_end(r1_bio->mddev);
- raid_end_bio_io(r1_bio);
}
- out:
+
if (to_put)
bio_put(to_put);
@@ -930,10 +930,13 @@ static void status(struct seq_file *seq, mddev_t *mddev)
seq_printf(seq, " [%d/%d] [", conf->raid_disks,
conf->working_disks);
- for (i = 0; i < conf->raid_disks; i++)
+ rcu_read_lock();
+ for (i = 0; i < conf->raid_disks; i++) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
seq_printf(seq, "%s",
- conf->mirrors[i].rdev &&
- test_bit(In_sync, &conf->mirrors[i].rdev->flags) ? "U" : "_");
+ rdev && test_bit(In_sync, &rdev->flags) ? "U" : "_");
+ }
+ rcu_read_unlock();
seq_printf(seq, "]");
}
@@ -975,7 +978,6 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
static void print_conf(conf_t *conf)
{
int i;
- mirror_info_t *tmp;
printk("RAID1 conf printout:\n");
if (!conf) {
@@ -985,14 +987,17 @@ static void print_conf(conf_t *conf)
printk(" --- wd:%d rd:%d\n", conf->working_disks,
conf->raid_disks);
+ rcu_read_lock();
for (i = 0; i < conf->raid_disks; i++) {
char b[BDEVNAME_SIZE];
- tmp = conf->mirrors + i;
- if (tmp->rdev)
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev)
printk(" disk %d, wo:%d, o:%d, dev:%s\n",
- i, !test_bit(In_sync, &tmp->rdev->flags), !test_bit(Faulty, &tmp->rdev->flags),
- bdevname(tmp->rdev->bdev,b));
+ i, !test_bit(In_sync, &rdev->flags),
+ !test_bit(Faulty, &rdev->flags),
+ bdevname(rdev->bdev,b));
}
+ rcu_read_unlock();
}
static void close_sync(conf_t *conf)
@@ -1008,20 +1013,20 @@ static int raid1_spare_active(mddev_t *mddev)
{
int i;
conf_t *conf = mddev->private;
- mirror_info_t *tmp;
/*
* Find all failed disks within the RAID1 configuration
- * and mark them readable
+ * and mark them readable.
+ * Called under mddev lock, so rcu protection not needed.
*/
for (i = 0; i < conf->raid_disks; i++) {
- tmp = conf->mirrors + i;
- if (tmp->rdev
- && !test_bit(Faulty, &tmp->rdev->flags)
- && !test_bit(In_sync, &tmp->rdev->flags)) {
+ mdk_rdev_t *rdev = conf->mirrors[i].rdev;
+ if (rdev
+ && !test_bit(Faulty, &rdev->flags)
+ && !test_bit(In_sync, &rdev->flags)) {
conf->working_disks++;
mddev->degraded--;
- set_bit(In_sync, &tmp->rdev->flags);
+ set_bit(In_sync, &rdev->flags);
}
}
@@ -1145,7 +1150,7 @@ static int end_sync_write(struct bio *bio, unsigned int bytes_done, int error)
long sectors_to_go = r1_bio->sectors;
/* make sure these bits doesn't get cleared. */
do {
- bitmap_end_sync(mddev->bitmap, r1_bio->sector,
+ bitmap_end_sync(mddev->bitmap, s,
&sync_blocks, 1);
s += sync_blocks;
sectors_to_go -= sync_blocks;
@@ -1237,7 +1242,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
/* ouch - failed to read all of that.
* Try some synchronous reads of other devices to get
* good data, much like with normal read errors. Only
- * read into the pages we already have so they we don't
+ * read into the pages we already have so we don't
* need to re-issue the read request.
* We don't need to freeze the array, because being in an
* active sync request, there is no normal IO, and
@@ -1257,6 +1262,10 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
s = PAGE_SIZE >> 9;
do {
if (r1_bio->bios[d]->bi_end_io == end_sync_read) {
+ /* No rcu protection needed here devices
+ * can only be removed when no resync is
+ * active, and resync is currently active
+ */
rdev = conf->mirrors[d].rdev;
if (sync_page_io(rdev->bdev,
sect + rdev->data_offset,
@@ -1463,6 +1472,11 @@ static void raid1d(mddev_t *mddev)
s = PAGE_SIZE >> 9;
do {
+ /* Note: no rcu protection needed here
+ * as this is synchronous in the raid1d thread
+ * which is the thread that might remove
+ * a device. If raid1d ever becomes multi-threaded....
+ */
rdev = conf->mirrors[d].rdev;
if (rdev &&
test_bit(In_sync, &rdev->flags) &&
@@ -1486,7 +1500,6 @@ static void raid1d(mddev_t *mddev)
d = conf->raid_disks;
d--;
rdev = conf->mirrors[d].rdev;
- atomic_add(s, &rdev->corrected_errors);
if (rdev &&
test_bit(In_sync, &rdev->flags)) {
if (sync_page_io(rdev->bdev,
@@ -1509,6 +1522,11 @@ static void raid1d(mddev_t *mddev)
s<<9, conf->tmppage, READ) == 0)
/* Well, this device is dead */
md_error(mddev, rdev);
+ else {
+ atomic_add(s, &rdev->corrected_errors);
+ printk(KERN_INFO "raid1:%s: read error corrected (%d sectors at %llu on %s)\n",
+ mdname(mddev), s, (unsigned long long)(sect + rdev->data_offset), bdevname(rdev->bdev, b));
+ }
}
}
} else {
@@ -1622,6 +1640,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
return 0;
}
+ if (mddev->bitmap == NULL &&
+ mddev->recovery_cp == MaxSector &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery) &&
+ conf->fullsync == 0) {
+ *skipped = 1;
+ return max_sector - sector_nr;
+ }
/* before building a request, check if we can skip these blocks..
* This call the bitmap_start_sync doesn't actually record anything
*/
@@ -1777,19 +1802,17 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
for (i=0; i<conf->raid_disks; i++) {
bio = r1_bio->bios[i];
if (bio->bi_end_io == end_sync_read) {
- md_sync_acct(conf->mirrors[i].rdev->bdev, nr_sectors);
+ md_sync_acct(bio->bi_bdev, nr_sectors);
generic_make_request(bio);
}
}
} else {
atomic_set(&r1_bio->remaining, 1);
bio = r1_bio->bios[r1_bio->read_disk];
- md_sync_acct(conf->mirrors[r1_bio->read_disk].rdev->bdev,
- nr_sectors);
+ md_sync_acct(bio->bi_bdev, nr_sectors);
generic_make_request(bio);
}
-
return nr_sectors;
}
@@ -1888,7 +1911,8 @@ static int run(mddev_t *mddev)
disk = conf->mirrors + i;
- if (!disk->rdev) {
+ if (!disk->rdev ||
+ !test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
mddev->degraded++;
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1440935414e..016ddb831c9 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -29,6 +29,7 @@
* raid_disks
* near_copies (stored in low byte of layout)
* far_copies (stored in second byte of layout)
+ * far_offset (stored in bit 16 of layout )
*
* The data to be stored is divided into chunks using chunksize.
* Each device is divided into far_copies sections.
@@ -36,10 +37,14 @@
* near_copies copies of each chunk is stored (each on a different drive).
* The starting device for each section is offset near_copies from the starting
* device of the previous section.
- * Thus there are (near_copies*far_copies) of each chunk, and each is on a different
+ * Thus they are (near_copies*far_copies) of each chunk, and each is on a different
* drive.
* near_copies and far_copies must be at least one, and their product is at most
* raid_disks.
+ *
+ * If far_offset is true, then the far_copies are handled a bit differently.
+ * The copies are still in different stripes, but instead of be very far apart
+ * on disk, there are adjacent stripes.
*/
/*
@@ -357,8 +362,7 @@ static int raid10_end_write_request(struct bio *bio, unsigned int bytes_done, in
* With this layout, and block is never stored twice on the one device.
*
* raid10_find_phys finds the sector offset of a given virtual sector
- * on each device that it is on. If a block isn't on a device,
- * that entry in the array is set to MaxSector.
+ * on each device that it is on.
*
* raid10_find_virt does the reverse mapping, from a device and a
* sector offset to a virtual address
@@ -381,6 +385,8 @@ static void raid10_find_phys(conf_t *conf, r10bio_t *r10bio)
chunk *= conf->near_copies;
stripe = chunk;
dev = sector_div(stripe, conf->raid_disks);
+ if (conf->far_offset)
+ stripe *= conf->far_copies;
sector += stripe << conf->chunk_shift;
@@ -414,16 +420,24 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev)
{
sector_t offset, chunk, vchunk;
- while (sector > conf->stride) {
- sector -= conf->stride;
- if (dev < conf->near_copies)
- dev += conf->raid_disks - conf->near_copies;
- else
- dev -= conf->near_copies;
- }
-
offset = sector & conf->chunk_mask;
- chunk = sector >> conf->chunk_shift;
+ if (conf->far_offset) {
+ int fc;
+ chunk = sector >> conf->chunk_shift;
+ fc = sector_div(chunk, conf->far_copies);
+ dev -= fc * conf->near_copies;
+ if (dev < 0)
+ dev += conf->raid_disks;
+ } else {
+ while (sector > conf->stride) {
+ sector -= conf->stride;
+ if (dev < conf->near_copies)
+ dev += conf->raid_disks - conf->near_copies;
+ else
+ dev -= conf->near_copies;
+ }
+ chunk = sector >> conf->chunk_shift;
+ }
vchunk = chunk * conf->raid_disks + dev;
sector_div(vchunk, conf->near_copies);
return (vchunk << conf->chunk_shift) + offset;
@@ -900,9 +914,12 @@ static void status(struct seq_file *seq, mddev_t *mddev)
seq_printf(seq, " %dK chunks", mddev->chunk_size/1024);
if (conf->near_copies > 1)
seq_printf(seq, " %d near-copies", conf->near_copies);
- if (conf->far_copies > 1)
- seq_printf(seq, " %d far-copies", conf->far_copies);
-
+ if (conf->far_copies > 1) {
+ if (conf->far_offset)
+ seq_printf(seq, " %d offset-copies", conf->far_copies);
+ else
+ seq_printf(seq, " %d far-copies", conf->far_copies);
+ }
seq_printf(seq, " [%d/%d] [", conf->raid_disks,
conf->working_disks);
for (i = 0; i < conf->raid_disks; i++)
@@ -1475,6 +1492,10 @@ static void raid10d(mddev_t *mddev)
s<<9, conf->tmppage, READ) == 0)
/* Well, this device is dead */
md_error(mddev, rdev);
+ else
+ printk(KERN_INFO "raid10:%s: read error corrected (%d sectors at %llu on %s)\n",
+ mdname(mddev), s, (unsigned long long)(sect+rdev->data_offset), bdevname(rdev->bdev, b));
+
rdev_dec_pending(rdev, mddev);
rcu_read_lock();
}
@@ -1915,7 +1936,7 @@ static int run(mddev_t *mddev)
mirror_info_t *disk;
mdk_rdev_t *rdev;
struct list_head *tmp;
- int nc, fc;
+ int nc, fc, fo;
sector_t stride, size;
if (mddev->chunk_size == 0) {
@@ -1925,8 +1946,9 @@ static int run(mddev_t *mddev)
nc = mddev->layout & 255;
fc = (mddev->layout >> 8) & 255;
+ fo = mddev->layout & (1<<16);
if ((nc*fc) <2 || (nc*fc) > mddev->raid_disks ||
- (mddev->layout >> 16)) {
+ (mddev->layout >> 17)) {
printk(KERN_ERR "raid10: %s: unsupported raid10 layout: 0x%8x\n",
mdname(mddev), mddev->layout);
goto out;
@@ -1958,12 +1980,16 @@ static int run(mddev_t *mddev)
conf->near_copies = nc;
conf->far_copies = fc;
conf->copies = nc*fc;
+ conf->far_offset = fo;
conf->chunk_mask = (sector_t)(mddev->chunk_size>>9)-1;
conf->chunk_shift = ffz(~mddev->chunk_size) - 9;
- stride = mddev->size >> (conf->chunk_shift-1);
- sector_div(stride, fc);
- conf->stride = stride << conf->chunk_shift;
-
+ if (fo)
+ conf->stride = 1 << conf->chunk_shift;
+ else {
+ stride = mddev->size >> (conf->chunk_shift-1);
+ sector_div(stride, fc);
+ conf->stride = stride << conf->chunk_shift;
+ }
conf->r10bio_pool = mempool_create(NR_RAID10_BIOS, r10bio_pool_alloc,
r10bio_pool_free, conf);
if (!conf->r10bio_pool) {
@@ -2015,7 +2041,8 @@ static int run(mddev_t *mddev)
disk = conf->mirrors + i;
- if (!disk->rdev) {
+ if (!disk->rdev ||
+ !test_bit(In_sync, &rdev->flags)) {
disk->head_position = 0;
mddev->degraded++;
}
@@ -2037,7 +2064,13 @@ static int run(mddev_t *mddev)
/*
* Ok, everything is just fine now
*/
- size = conf->stride * conf->raid_disks;
+ if (conf->far_offset) {
+ size = mddev->size >> (conf->chunk_shift-1);
+ size *= conf->raid_disks;
+ size <<= conf->chunk_shift;
+ sector_div(size, conf->far_copies);
+ } else
+ size = conf->stride * conf->raid_disks;
sector_div(size, conf->near_copies);
mddev->array_size = size/2;
mddev->resync_max_sectors = size;
@@ -2050,7 +2083,7 @@ static int run(mddev_t *mddev)
* maybe...
*/
{
- int stripe = conf->raid_disks * mddev->chunk_size / PAGE_SIZE;
+ int stripe = conf->raid_disks * (mddev->chunk_size / PAGE_SIZE);
stripe /= conf->near_copies;
if (mddev->queue->backing_dev_info.ra_pages < 2* stripe)
mddev->queue->backing_dev_info.ra_pages = 2* stripe;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 31843604049..45006600716 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2,8 +2,11 @@
* raid5.c : Multiple Devices driver for Linux
* Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman
* Copyright (C) 1999, 2000 Ingo Molnar
+ * Copyright (C) 2002, 2003 H. Peter Anvin
*
- * RAID-5 management functions.
+ * RAID-4/5/6 management functions.
+ * Thanks to Penguin Computing for making the RAID-6 development possible
+ * by donating a test server!
*
* 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
@@ -15,15 +18,38 @@
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+/*
+ * BITMAP UNPLUGGING:
+ *
+ * The sequencing for updating the bitmap reliably is a little
+ * subtle (and I got it wrong the first time) so it deserves some
+ * explanation.
+ *
+ * We group bitmap updates into batches. Each batch has a number.
+ * We may write out several batches at once, but that isn't very important.
+ * conf->bm_write is the number of the last batch successfully written.
+ * conf->bm_flush is the number of the last batch that was closed to
+ * new additions.
+ * When we discover that we will need to write to any block in a stripe
+ * (in add_stripe_bio) we update the in-memory bitmap and record in sh->bm_seq
+ * the number of the batch it will be in. This is bm_flush+1.
+ * When we are ready to do a write, if that batch hasn't been written yet,
+ * we plug the array and queue the stripe for later.
+ * When an unplug happens, we increment bm_flush, thus closing the current
+ * batch.
+ * When we notice that bm_flush > bm_write, we write out all pending updates
+ * to the bitmap, and advance bm_write to where bm_flush was.
+ * This may occasionally write a bit out twice, but is sure never to
+ * miss any bits.
+ */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/raid/raid5.h>
#include <linux/highmem.h>
#include <linux/bitops.h>
#include <linux/kthread.h>
#include <asm/atomic.h>
+#include "raid6.h"
#include <linux/raid/bitmap.h>
@@ -68,6 +94,16 @@
#define __inline__
#endif
+#if !RAID6_USE_EMPTY_ZERO_PAGE
+/* In .bss so it's zeroed */
+const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
+#endif
+
+static inline int raid6_next_disk(int disk, int raid_disks)
+{
+ disk++;
+ return (disk < raid_disks) ? disk : 0;
+}
static void print_raid5_conf (raid5_conf_t *conf);
static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
@@ -76,12 +112,14 @@ static void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
BUG_ON(!list_empty(&sh->lru));
BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) {
- if (test_bit(STRIPE_DELAYED, &sh->state))
+ if (test_bit(STRIPE_DELAYED, &sh->state)) {
list_add_tail(&sh->lru, &conf->delayed_list);
- else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
- conf->seq_write == sh->bm_seq)
+ blk_plug_device(conf->mddev->queue);
+ } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
+ sh->bm_seq - conf->seq_write > 0) {
list_add_tail(&sh->lru, &conf->bitmap_list);
- else {
+ blk_plug_device(conf->mddev->queue);
+ } else {
clear_bit(STRIPE_BIT_DELAY, &sh->state);
list_add_tail(&sh->lru, &conf->handle_list);
}
@@ -104,7 +142,7 @@ static void release_stripe(struct stripe_head *sh)
{
raid5_conf_t *conf = sh->raid_conf;
unsigned long flags;
-
+
spin_lock_irqsave(&conf->device_lock, flags);
__release_stripe(conf, sh);
spin_unlock_irqrestore(&conf->device_lock, flags);
@@ -117,7 +155,7 @@ static inline void remove_hash(struct stripe_head *sh)
hlist_del_init(&sh->hash);
}
-static void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
+static inline void insert_hash(raid5_conf_t *conf, struct stripe_head *sh)
{
struct hlist_head *hp = stripe_hash(conf, sh->sector);
@@ -190,7 +228,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx, int
(unsigned long long)sh->sector);
remove_hash(sh);
-
+
sh->sector = sector;
sh->pd_idx = pd_idx;
sh->state = 0;
@@ -258,7 +296,7 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
< (conf->max_nr_stripes *3/4)
|| !conf->inactive_blocked),
conf->device_lock,
- unplug_slaves(conf->mddev)
+ raid5_unplug_device(conf->mddev->queue)
);
conf->inactive_blocked = 0;
} else
@@ -269,8 +307,10 @@ static struct stripe_head *get_active_stripe(raid5_conf_t *conf, sector_t sector
} else {
if (!test_bit(STRIPE_HANDLE, &sh->state))
atomic_inc(&conf->active_stripes);
- if (!list_empty(&sh->lru))
- list_del_init(&sh->lru);
+ if (list_empty(&sh->lru) &&
+ !test_bit(STRIPE_EXPANDING, &sh->state))
+ BUG();
+ list_del_init(&sh->lru);
}
}
} while (sh == NULL);
@@ -321,10 +361,9 @@ static int grow_stripes(raid5_conf_t *conf, int num)
return 1;
conf->slab_cache = sc;
conf->pool_size = devs;
- while (num--) {
+ while (num--)
if (!grow_one_stripe(conf))
return 1;
- }
return 0;
}
@@ -484,6 +523,8 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks, i;
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
+ char b[BDEVNAME_SIZE];
+ mdk_rdev_t *rdev;
if (bi->bi_size)
return 1;
@@ -531,25 +572,39 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
set_bit(R5_UPTODATE, &sh->dev[i].flags);
#endif
if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
- printk(KERN_INFO "raid5: read error corrected!!\n");
+ rdev = conf->disks[i].rdev;
+ printk(KERN_INFO "raid5:%s: read error corrected (%lu sectors at %llu on %s)\n",
+ mdname(conf->mddev), STRIPE_SECTORS,
+ (unsigned long long)sh->sector + rdev->data_offset,
+ bdevname(rdev->bdev, b));
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 {
+ const char *bdn = bdevname(conf->disks[i].rdev->bdev, b);
int retry = 0;
+ rdev = conf->disks[i].rdev;
+
clear_bit(R5_UPTODATE, &sh->dev[i].flags);
- atomic_inc(&conf->disks[i].rdev->read_errors);
+ atomic_inc(&rdev->read_errors);
if (conf->mddev->degraded)
- printk(KERN_WARNING "raid5: read error not correctable.\n");
+ printk(KERN_WARNING "raid5:%s: read error not correctable (sector %llu on %s).\n",
+ mdname(conf->mddev),
+ (unsigned long long)sh->sector + rdev->data_offset,
+ bdn);
else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
/* Oh, no!!! */
- printk(KERN_WARNING "raid5: read error NOT corrected!!\n");
- else if (atomic_read(&conf->disks[i].rdev->read_errors)
+ printk(KERN_WARNING "raid5:%s: read error NOT corrected!! (sector %llu on %s).\n",
+ mdname(conf->mddev),
+ (unsigned long long)sh->sector + rdev->data_offset,
+ bdn);
+ else if (atomic_read(&rdev->read_errors)
> conf->max_nr_stripes)
printk(KERN_WARNING
- "raid5: Too many read errors, failing device.\n");
+ "raid5:%s: Too many read errors, failing device %s.\n",
+ mdname(conf->mddev), bdn);
else
retry = 1;
if (retry)
@@ -557,7 +612,7 @@ static int raid5_end_read_request(struct bio * bi, unsigned int bytes_done,
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);
+ md_error(conf->mddev, rdev);
}
}
rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
@@ -631,8 +686,7 @@ static void raid5_build_block (struct stripe_head *sh, int i)
dev->req.bi_private = sh;
dev->flags = 0;
- if (i != sh->pd_idx)
- dev->sector = compute_blocknr(sh, i);
+ dev->sector = compute_blocknr(sh, i);
}
static void error(mddev_t *mddev, mdk_rdev_t *rdev)
@@ -659,7 +713,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
" Operation continuing on %d devices\n",
bdevname(rdev->bdev,b), conf->working_disks);
}
-}
+}
/*
* Input: a 'big' sector number,
@@ -697,9 +751,12 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
/*
* Select the parity disk based on the user selected algorithm.
*/
- if (conf->level == 4)
+ switch(conf->level) {
+ case 4:
*pd_idx = data_disks;
- else switch (conf->algorithm) {
+ break;
+ case 5:
+ switch (conf->algorithm) {
case ALGORITHM_LEFT_ASYMMETRIC:
*pd_idx = data_disks - stripe % raid_disks;
if (*dd_idx >= *pd_idx)
@@ -721,6 +778,39 @@ static sector_t raid5_compute_sector(sector_t r_sector, unsigned int raid_disks,
default:
printk(KERN_ERR "raid5: unsupported algorithm %d\n",
conf->algorithm);
+ }
+ break;
+ case 6:
+
+ /**** FIX THIS ****/
+ switch (conf->algorithm) {
+ case ALGORITHM_LEFT_ASYMMETRIC:
+ *pd_idx = raid_disks - 1 - (stripe % raid_disks);
+ if (*pd_idx == raid_disks-1)
+ (*dd_idx)++; /* Q D D D P */
+ else if (*dd_idx >= *pd_idx)
+ (*dd_idx) += 2; /* D D P Q D */
+ break;
+ case ALGORITHM_RIGHT_ASYMMETRIC:
+ *pd_idx = stripe % raid_disks;
+ if (*pd_idx == raid_disks-1)
+ (*dd_idx)++; /* Q D D D P */
+ else if (*dd_idx >= *pd_idx)
+ (*dd_idx) += 2; /* D D P Q D */
+ break;
+ case ALGORITHM_LEFT_SYMMETRIC:
+ *pd_idx = raid_disks - 1 - (stripe % raid_disks);
+ *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
+ break;
+ case ALGORITHM_RIGHT_SYMMETRIC:
+ *pd_idx = stripe % raid_disks;
+ *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
+ break;
+ default:
+ printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
+ conf->algorithm);
+ }
+ break;
}
/*
@@ -742,12 +832,17 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
int chunk_number, dummy1, dummy2, dd_idx = i;
sector_t r_sector;
+
chunk_offset = sector_div(new_sector, sectors_per_chunk);
stripe = new_sector;
BUG_ON(new_sector != stripe);
-
- switch (conf->algorithm) {
+ if (i == sh->pd_idx)
+ return 0;
+ switch(conf->level) {
+ case 4: break;
+ case 5:
+ switch (conf->algorithm) {
case ALGORITHM_LEFT_ASYMMETRIC:
case ALGORITHM_RIGHT_ASYMMETRIC:
if (i > sh->pd_idx)
@@ -761,7 +856,37 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
break;
default:
printk(KERN_ERR "raid5: unsupported algorithm %d\n",
+ conf->algorithm);
+ }
+ break;
+ case 6:
+ data_disks = raid_disks - 2;
+ if (i == raid6_next_disk(sh->pd_idx, raid_disks))
+ return 0; /* It is the Q disk */
+ switch (conf->algorithm) {
+ case ALGORITHM_LEFT_ASYMMETRIC:
+ case ALGORITHM_RIGHT_ASYMMETRIC:
+ if (sh->pd_idx == raid_disks-1)
+ i--; /* Q D D D P */
+ else if (i > sh->pd_idx)
+ i -= 2; /* D D P Q D */
+ break;
+ case ALGORITHM_LEFT_SYMMETRIC:
+ case ALGORITHM_RIGHT_SYMMETRIC:
+ if (sh->pd_idx == raid_disks-1)
+ i--; /* Q D D D P */
+ else {
+ /* D D P Q D */
+ if (i < sh->pd_idx)
+ i += raid_disks;
+ i -= (sh->pd_idx + 2);
+ }
+ break;
+ default:
+ printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
conf->algorithm);
+ }
+ break;
}
chunk_number = stripe * data_disks + i;
@@ -778,10 +903,11 @@ static sector_t compute_blocknr(struct stripe_head *sh, int i)
/*
- * Copy data between a page in the stripe cache, and a bio.
- * There are no alignment or size guarantees between the page or the
- * bio except that there is some overlap.
- * All iovecs in the bio must be considered.
+ * Copy data between a page in the stripe cache, and one or more bion
+ * The page could align with the middle of the bio, or there could be
+ * several bion, each with several bio_vecs, which cover part of the page
+ * Multiple bion are linked together on bi_next. There may be extras
+ * at the end of this list. We ignore them.
*/
static void copy_data(int frombio, struct bio *bio,
struct page *page,
@@ -810,7 +936,7 @@ static void copy_data(int frombio, struct bio *bio,
if (len > 0 && page_offset + len > STRIPE_SIZE)
clen = STRIPE_SIZE - page_offset;
else clen = len;
-
+
if (clen > 0) {
char *ba = __bio_kmap_atomic(bio, i, KM_USER0);
if (frombio)
@@ -862,14 +988,14 @@ static void compute_block(struct stripe_head *sh, int dd_idx)
set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
}
-static void compute_parity(struct stripe_head *sh, int method)
+static void compute_parity5(struct stripe_head *sh, int method)
{
raid5_conf_t *conf = sh->raid_conf;
int i, pd_idx = sh->pd_idx, disks = sh->disks, count;
void *ptr[MAX_XOR_BLOCKS];
struct bio *chosen;
- PRINTK("compute_parity, stripe %llu, method %d\n",
+ PRINTK("compute_parity5, stripe %llu, method %d\n",
(unsigned long long)sh->sector, method);
count = 1;
@@ -956,9 +1082,195 @@ static void compute_parity(struct stripe_head *sh, int method)
clear_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
}
+static void compute_parity6(struct stripe_head *sh, int method)
+{
+ raid6_conf_t *conf = sh->raid_conf;
+ int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count;
+ struct bio *chosen;
+ /**** FIX THIS: This could be very bad if disks is close to 256 ****/
+ void *ptrs[disks];
+
+ qd_idx = raid6_next_disk(pd_idx, disks);
+ d0_idx = raid6_next_disk(qd_idx, disks);
+
+ PRINTK("compute_parity, stripe %llu, method %d\n",
+ (unsigned long long)sh->sector, method);
+
+ switch(method) {
+ case READ_MODIFY_WRITE:
+ BUG(); /* READ_MODIFY_WRITE N/A for RAID-6 */
+ case RECONSTRUCT_WRITE:
+ for (i= disks; i-- ;)
+ if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) {
+ chosen = sh->dev[i].towrite;
+ sh->dev[i].towrite = NULL;
+
+ if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+ wake_up(&conf->wait_for_overlap);
+
+ if (sh->dev[i].written) BUG();
+ sh->dev[i].written = chosen;
+ }
+ break;
+ case CHECK_PARITY:
+ BUG(); /* Not implemented yet */
+ }
+
+ for (i = disks; i--;)
+ if (sh->dev[i].written) {
+ sector_t sector = sh->dev[i].sector;
+ struct bio *wbi = sh->dev[i].written;
+ while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) {
+ copy_data(1, wbi, sh->dev[i].page, sector);
+ wbi = r5_next_bio(wbi, sector);
+ }
+
+ set_bit(R5_LOCKED, &sh->dev[i].flags);
+ set_bit(R5_UPTODATE, &sh->dev[i].flags);
+ }
+
+// switch(method) {
+// case RECONSTRUCT_WRITE:
+// case CHECK_PARITY:
+// case UPDATE_PARITY:
+ /* Note that unlike RAID-5, the ordering of the disks matters greatly. */
+ /* FIX: Is this ordering of drives even remotely optimal? */
+ count = 0;
+ i = d0_idx;
+ do {
+ ptrs[count++] = page_address(sh->dev[i].page);
+ if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags))
+ printk("block %d/%d not uptodate on parity calc\n", i,count);
+ i = raid6_next_disk(i, disks);
+ } while ( i != d0_idx );
+// break;
+// }
+
+ raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs);
+
+ switch(method) {
+ case RECONSTRUCT_WRITE:
+ set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
+ set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
+ set_bit(R5_LOCKED, &sh->dev[pd_idx].flags);
+ set_bit(R5_LOCKED, &sh->dev[qd_idx].flags);
+ break;
+ case UPDATE_PARITY:
+ set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
+ set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
+ break;
+ }
+}
+
+
+/* Compute one missing block */
+static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
+{
+ raid6_conf_t *conf = sh->raid_conf;
+ int i, count, disks = conf->raid_disks;
+ void *ptr[MAX_XOR_BLOCKS], *p;
+ int pd_idx = sh->pd_idx;
+ int qd_idx = raid6_next_disk(pd_idx, disks);
+
+ PRINTK("compute_block_1, stripe %llu, idx %d\n",
+ (unsigned long long)sh->sector, dd_idx);
+
+ if ( dd_idx == qd_idx ) {
+ /* We're actually computing the Q drive */
+ compute_parity6(sh, UPDATE_PARITY);
+ } else {
+ ptr[0] = page_address(sh->dev[dd_idx].page);
+ if (!nozero) memset(ptr[0], 0, STRIPE_SIZE);
+ count = 1;
+ for (i = disks ; i--; ) {
+ if (i == dd_idx || i == qd_idx)
+ continue;
+ p = page_address(sh->dev[i].page);
+ if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
+ ptr[count++] = p;
+ else
+ printk("compute_block() %d, stripe %llu, %d"
+ " not present\n", dd_idx,
+ (unsigned long long)sh->sector, i);
+
+ check_xor();
+ }
+ if (count != 1)
+ xor_block(count, STRIPE_SIZE, ptr);
+ if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
+ else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
+ }
+}
+
+/* Compute two missing blocks */
+static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
+{
+ raid6_conf_t *conf = sh->raid_conf;
+ int i, count, disks = conf->raid_disks;
+ int pd_idx = sh->pd_idx;
+ int qd_idx = raid6_next_disk(pd_idx, disks);
+ int d0_idx = raid6_next_disk(qd_idx, disks);
+ int faila, failb;
+
+ /* faila and failb are disk numbers relative to d0_idx */
+ /* pd_idx become disks-2 and qd_idx become disks-1 */
+ faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx;
+ failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx;
+
+ BUG_ON(faila == failb);
+ if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; }
+
+ PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
+ (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb);
+
+ if ( failb == disks-1 ) {
+ /* Q disk is one of the missing disks */
+ if ( faila == disks-2 ) {
+ /* Missing P+Q, just recompute */
+ compute_parity6(sh, UPDATE_PARITY);
+ return;
+ } else {
+ /* We're missing D+Q; recompute D from P */
+ compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0);
+ compute_parity6(sh, UPDATE_PARITY); /* Is this necessary? */
+ return;
+ }
+ }
+
+ /* We're missing D+P or D+D; build pointer table */
+ {
+ /**** FIX THIS: This could be very bad if disks is close to 256 ****/
+ void *ptrs[disks];
+
+ count = 0;
+ i = d0_idx;
+ do {
+ ptrs[count++] = page_address(sh->dev[i].page);
+ i = raid6_next_disk(i, disks);
+ if (i != dd_idx1 && i != dd_idx2 &&
+ !test_bit(R5_UPTODATE, &sh->dev[i].flags))
+ printk("compute_2 with missing block %d/%d\n", count, i);
+ } while ( i != d0_idx );
+
+ if ( failb == disks-2 ) {
+ /* We're missing D+P. */
+ raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs);
+ } else {
+ /* We're missing D+D. */
+ raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs);
+ }
+
+ /* Both the above update both missing blocks */
+ set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags);
+ set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags);
+ }
+}
+
+
+
/*
* Each stripe/dev can have one or more bion attached.
- * toread/towrite point to the first in a chain.
+ * toread/towrite point to the first in a chain.
* The bi_next chain must be in order.
*/
static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite)
@@ -1001,9 +1313,9 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
(unsigned long long)sh->sector, dd_idx);
if (conf->mddev->bitmap && firstwrite) {
- sh->bm_seq = conf->seq_write;
bitmap_startwrite(conf->mddev->bitmap, sh->sector,
STRIPE_SECTORS, 0);
+ sh->bm_seq = conf->seq_flush+1;
set_bit(STRIPE_BIT_DELAY, &sh->state);
}
@@ -1031,6 +1343,13 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
static void end_reshape(raid5_conf_t *conf);
+static int page_is_zero(struct page *p)
+{
+ char *a = page_address(p);
+ return ((*(u32*)a) == 0 &&
+ memcmp(a, a+4, STRIPE_SIZE-4)==0);
+}
+
static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
{
int sectors_per_chunk = conf->chunk_size >> 9;
@@ -1062,7 +1381,7 @@ static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
*
*/
-static void handle_stripe(struct stripe_head *sh)
+static void handle_stripe5(struct stripe_head *sh)
{
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks;
@@ -1394,7 +1713,7 @@ static void handle_stripe(struct stripe_head *sh)
if (locked == 0 && (rcw == 0 ||rmw == 0) &&
!test_bit(STRIPE_BIT_DELAY, &sh->state)) {
PRINTK("Computing parity...\n");
- compute_parity(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE);
+ compute_parity5(sh, rcw==0 ? RECONSTRUCT_WRITE : READ_MODIFY_WRITE);
/* now every locked buffer is ready to be written */
for (i=disks; i--;)
if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
@@ -1421,13 +1740,10 @@ static void handle_stripe(struct stripe_head *sh)
!test_bit(STRIPE_INSYNC, &sh->state)) {
set_bit(STRIPE_HANDLE, &sh->state);
if (failed == 0) {
- char *pagea;
BUG_ON(uptodate != disks);
- compute_parity(sh, CHECK_PARITY);
+ compute_parity5(sh, CHECK_PARITY);
uptodate--;
- pagea = page_address(sh->dev[sh->pd_idx].page);
- if ((*(u32*)pagea) == 0 &&
- !memcmp(pagea, pagea+4, STRIPE_SIZE-4)) {
+ if (page_is_zero(sh->dev[sh->pd_idx].page)) {
/* parity is correct (on disc, not in buffer any more) */
set_bit(STRIPE_INSYNC, &sh->state);
} else {
@@ -1487,7 +1803,7 @@ static void handle_stripe(struct stripe_head *sh)
/* Need to write out all blocks after computing parity */
sh->disks = conf->raid_disks;
sh->pd_idx = stripe_to_pdidx(sh->sector, conf, conf->raid_disks);
- compute_parity(sh, RECONSTRUCT_WRITE);
+ compute_parity5(sh, RECONSTRUCT_WRITE);
for (i= conf->raid_disks; i--;) {
set_bit(R5_LOCKED, &sh->dev[i].flags);
locked++;
@@ -1615,6 +1931,569 @@ static void handle_stripe(struct stripe_head *sh)
}
}
+static void handle_stripe6(struct stripe_head *sh, struct page *tmp_page)
+{
+ raid6_conf_t *conf = sh->raid_conf;
+ int disks = conf->raid_disks;
+ struct bio *return_bi= NULL;
+ struct bio *bi;
+ int i;
+ int syncing;
+ int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
+ int non_overwrite = 0;
+ int failed_num[2] = {0, 0};
+ struct r5dev *dev, *pdev, *qdev;
+ int pd_idx = sh->pd_idx;
+ int qd_idx = raid6_next_disk(pd_idx, disks);
+ int p_failed, q_failed;
+
+ PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n",
+ (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count),
+ pd_idx, qd_idx);
+
+ spin_lock(&sh->lock);
+ clear_bit(STRIPE_HANDLE, &sh->state);
+ clear_bit(STRIPE_DELAYED, &sh->state);
+
+ syncing = test_bit(STRIPE_SYNCING, &sh->state);
+ /* Now to look around and see what can be done */
+
+ rcu_read_lock();
+ for (i=disks; i--; ) {
+ mdk_rdev_t *rdev;
+ dev = &sh->dev[i];
+ clear_bit(R5_Insync, &dev->flags);
+
+ PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
+ i, dev->flags, dev->toread, dev->towrite, dev->written);
+ /* maybe we can reply to a read */
+ if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) {
+ struct bio *rbi, *rbi2;
+ PRINTK("Return read for disc %d\n", i);
+ spin_lock_irq(&conf->device_lock);
+ rbi = dev->toread;
+ dev->toread = NULL;
+ if (test_and_clear_bit(R5_Overlap, &dev->flags))
+ wake_up(&conf->wait_for_overlap);
+ spin_unlock_irq(&conf->device_lock);
+ while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) {
+ copy_data(0, rbi, dev->page, dev->sector);
+ rbi2 = r5_next_bio(rbi, dev->sector);
+ spin_lock_irq(&conf->device_lock);
+ if (--rbi->bi_phys_segments == 0) {
+ rbi->bi_next = return_bi;
+ return_bi = rbi;
+ }
+ spin_unlock_irq(&conf->device_lock);
+ rbi = rbi2;
+ }
+ }
+
+ /* now count some things */
+ if (test_bit(R5_LOCKED, &dev->flags)) locked++;
+ if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++;
+
+
+ if (dev->toread) to_read++;
+ if (dev->towrite) {
+ to_write++;
+ if (!test_bit(R5_OVERWRITE, &dev->flags))
+ non_overwrite++;
+ }
+ if (dev->written) written++;
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (!rdev || !test_bit(In_sync, &rdev->flags)) {
+ /* The ReadError flag will 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)) {
+ if ( failed < 2 )
+ failed_num[failed] = i;
+ failed++;
+ } else
+ set_bit(R5_Insync, &dev->flags);
+ }
+ rcu_read_unlock();
+ PRINTK("locked=%d uptodate=%d to_read=%d"
+ " to_write=%d failed=%d failed_num=%d,%d\n",
+ locked, uptodate, to_read, to_write, failed,
+ failed_num[0], failed_num[1]);
+ /* check if the array has lost >2 devices and, if so, some requests might
+ * need to be failed
+ */
+ if (failed > 2 && 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;
+ rcu_read_lock();
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && test_bit(In_sync, &rdev->flags))
+ /* multiple read failures in one stripe */
+ md_error(conf->mddev, rdev);
+ rcu_read_unlock();
+ }
+
+ spin_lock_irq(&conf->device_lock);
+ /* fail all writes first */
+ bi = sh->dev[i].towrite;
+ sh->dev[i].towrite = NULL;
+ if (bi) { to_write--; bitmap_end = 1; }
+
+ if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
+ wake_up(&conf->wait_for_overlap);
+
+ while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
+ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
+ clear_bit(BIO_UPTODATE, &bi->bi_flags);
+ if (--bi->bi_phys_segments == 0) {
+ md_write_end(conf->mddev);
+ bi->bi_next = return_bi;
+ return_bi = bi;
+ }
+ bi = nextbi;
+ }
+ /* and fail all 'written' */
+ bi = sh->dev[i].written;
+ sh->dev[i].written = NULL;
+ if (bi) bitmap_end = 1;
+ while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) {
+ struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
+ clear_bit(BIO_UPTODATE, &bi->bi_flags);
+ if (--bi->bi_phys_segments == 0) {
+ md_write_end(conf->mddev);
+ bi->bi_next = return_bi;
+ return_bi = bi;
+ }
+ bi = bi2;
+ }
+
+ /* fail any reads if this device is non-operational */
+ 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))
+ wake_up(&conf->wait_for_overlap);
+ if (bi) to_read--;
+ while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
+ struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
+ clear_bit(BIO_UPTODATE, &bi->bi_flags);
+ if (--bi->bi_phys_segments == 0) {
+ bi->bi_next = return_bi;
+ return_bi = bi;
+ }
+ bi = nextbi;
+ }
+ }
+ spin_unlock_irq(&conf->device_lock);
+ if (bitmap_end)
+ bitmap_endwrite(conf->mddev->bitmap, sh->sector,
+ STRIPE_SECTORS, 0, 0);
+ }
+ }
+ if (failed > 2 && syncing) {
+ md_done_sync(conf->mddev, STRIPE_SECTORS,0);
+ clear_bit(STRIPE_SYNCING, &sh->state);
+ syncing = 0;
+ }
+
+ /*
+ * might be able to return some write requests if the parity blocks
+ * are safe, or on a failed drive
+ */
+ pdev = &sh->dev[pd_idx];
+ p_failed = (failed >= 1 && failed_num[0] == pd_idx)
+ || (failed >= 2 && failed_num[1] == pd_idx);
+ qdev = &sh->dev[qd_idx];
+ q_failed = (failed >= 1 && failed_num[0] == qd_idx)
+ || (failed >= 2 && failed_num[1] == qd_idx);
+
+ if ( written &&
+ ( p_failed || ((test_bit(R5_Insync, &pdev->flags)
+ && !test_bit(R5_LOCKED, &pdev->flags)
+ && test_bit(R5_UPTODATE, &pdev->flags))) ) &&
+ ( q_failed || ((test_bit(R5_Insync, &qdev->flags)
+ && !test_bit(R5_LOCKED, &qdev->flags)
+ && test_bit(R5_UPTODATE, &qdev->flags))) ) ) {
+ /* any written block on an uptodate or failed drive can be
+ * returned. Note that if we 'wrote' to a failed drive,
+ * it will be UPTODATE, but never LOCKED, so we don't need
+ * to test 'failed' directly.
+ */
+ for (i=disks; i--; )
+ if (sh->dev[i].written) {
+ dev = &sh->dev[i];
+ if (!test_bit(R5_LOCKED, &dev->flags) &&
+ test_bit(R5_UPTODATE, &dev->flags) ) {
+ /* We can return any write requests */
+ int bitmap_end = 0;
+ struct bio *wbi, *wbi2;
+ PRINTK("Return write for stripe %llu disc %d\n",
+ (unsigned long long)sh->sector, i);
+ spin_lock_irq(&conf->device_lock);
+ wbi = dev->written;
+ dev->written = NULL;
+ while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {
+ wbi2 = r5_next_bio(wbi, dev->sector);
+ if (--wbi->bi_phys_segments == 0) {
+ md_write_end(conf->mddev);
+ wbi->bi_next = return_bi;
+ return_bi = wbi;
+ }
+ wbi = wbi2;
+ }
+ if (dev->towrite == NULL)
+ bitmap_end = 1;
+ spin_unlock_irq(&conf->device_lock);
+ if (bitmap_end)
+ bitmap_endwrite(conf->mddev->bitmap, sh->sector,
+ STRIPE_SECTORS,
+ !test_bit(STRIPE_DEGRADED, &sh->state), 0);
+ }
+ }
+ }
+
+ /* Now we might consider reading some blocks, either to check/generate
+ * parity, or to satisfy requests
+ * or to load a block that is being partially written.
+ */
+ if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) {
+ for (i=disks; i--;) {
+ dev = &sh->dev[i];
+ if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
+ (dev->toread ||
+ (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
+ syncing ||
+ (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
+ (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
+ )
+ ) {
+ /* we would like to get this block, possibly
+ * by computing it, but we might not be able to
+ */
+ if (uptodate == disks-1) {
+ PRINTK("Computing stripe %llu block %d\n",
+ (unsigned long long)sh->sector, i);
+ compute_block_1(sh, i, 0);
+ uptodate++;
+ } else if ( uptodate == disks-2 && failed >= 2 ) {
+ /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */
+ int other;
+ for (other=disks; other--;) {
+ if ( other == i )
+ continue;
+ if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) )
+ break;
+ }
+ BUG_ON(other < 0);
+ PRINTK("Computing stripe %llu blocks %d,%d\n",
+ (unsigned long long)sh->sector, i, other);
+ compute_block_2(sh, i, other);
+ uptodate += 2;
+ } else if (test_bit(R5_Insync, &dev->flags)) {
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+#if 0
+ /* if I am just reading this block and we don't have
+ a failed drive, or any pending writes then sidestep the cache */
+ if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
+ ! syncing && !failed && !to_write) {
+ sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page;
+ sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data;
+ }
+#endif
+ locked++;
+ PRINTK("Reading block %d (sync=%d)\n",
+ i, syncing);
+ }
+ }
+ }
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+
+ /* now to consider writing and what else, if anything should be read */
+ if (to_write) {
+ int rcw=0, must_compute=0;
+ for (i=disks ; i--;) {
+ dev = &sh->dev[i];
+ /* Would I have to read this buffer for reconstruct_write */
+ if (!test_bit(R5_OVERWRITE, &dev->flags)
+ && i != pd_idx && i != qd_idx
+ && (!test_bit(R5_LOCKED, &dev->flags)
+#if 0
+ || sh->bh_page[i] != bh->b_page
+#endif
+ ) &&
+ !test_bit(R5_UPTODATE, &dev->flags)) {
+ if (test_bit(R5_Insync, &dev->flags)) rcw++;
+ else {
+ PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags);
+ must_compute++;
+ }
+ }
+ }
+ PRINTK("for sector %llu, rcw=%d, must_compute=%d\n",
+ (unsigned long long)sh->sector, rcw, must_compute);
+ set_bit(STRIPE_HANDLE, &sh->state);
+
+ if (rcw > 0)
+ /* want reconstruct write, but need to get some data */
+ for (i=disks; i--;) {
+ dev = &sh->dev[i];
+ if (!test_bit(R5_OVERWRITE, &dev->flags)
+ && !(failed == 0 && (i == pd_idx || i == qd_idx))
+ && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
+ test_bit(R5_Insync, &dev->flags)) {
+ if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+ {
+ PRINTK("Read_old stripe %llu block %d for Reconstruct\n",
+ (unsigned long long)sh->sector, i);
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantread, &dev->flags);
+ locked++;
+ } else {
+ PRINTK("Request delayed stripe %llu block %d for Reconstruct\n",
+ (unsigned long long)sh->sector, i);
+ set_bit(STRIPE_DELAYED, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ }
+ }
+ /* now if nothing is locked, and if we have enough data, we can start a write request */
+ if (locked == 0 && rcw == 0 &&
+ !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
+ if ( must_compute > 0 ) {
+ /* We have failed blocks and need to compute them */
+ switch ( failed ) {
+ case 0: BUG();
+ case 1: compute_block_1(sh, failed_num[0], 0); break;
+ case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break;
+ default: BUG(); /* This request should have been failed? */
+ }
+ }
+
+ PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector);
+ compute_parity6(sh, RECONSTRUCT_WRITE);
+ /* now every locked buffer is ready to be written */
+ for (i=disks; i--;)
+ if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
+ PRINTK("Writing stripe %llu block %d\n",
+ (unsigned long long)sh->sector, i);
+ locked++;
+ set_bit(R5_Wantwrite, &sh->dev[i].flags);
+ }
+ /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
+ set_bit(STRIPE_INSYNC, &sh->state);
+
+ if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ atomic_dec(&conf->preread_active_stripes);
+ if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
+ md_wakeup_thread(conf->mddev->thread);
+ }
+ }
+ }
+
+ /* maybe we need to check and possibly fix the parity for this stripe
+ * Any reads will already have been scheduled, so we just see if enough data
+ * is available
+ */
+ if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) {
+ int update_p = 0, update_q = 0;
+ struct r5dev *dev;
+
+ set_bit(STRIPE_HANDLE, &sh->state);
+
+ BUG_ON(failed>2);
+ BUG_ON(uptodate < disks);
+ /* Want to check and possibly repair P and Q.
+ * However there could be one 'failed' device, in which
+ * case we can only check one of them, possibly using the
+ * other to generate missing data
+ */
+
+ /* If !tmp_page, we cannot do the calculations,
+ * but as we have set STRIPE_HANDLE, we will soon be called
+ * by stripe_handle with a tmp_page - just wait until then.
+ */
+ if (tmp_page) {
+ if (failed == q_failed) {
+ /* The only possible failed device holds 'Q', so it makes
+ * sense to check P (If anything else were failed, we would
+ * have used P to recreate it).
+ */
+ compute_block_1(sh, pd_idx, 1);
+ if (!page_is_zero(sh->dev[pd_idx].page)) {
+ compute_block_1(sh,pd_idx,0);
+ update_p = 1;
+ }
+ }
+ if (!q_failed && failed < 2) {
+ /* q is not failed, and we didn't use it to generate
+ * anything, so it makes sense to check it
+ */
+ memcpy(page_address(tmp_page),
+ page_address(sh->dev[qd_idx].page),
+ STRIPE_SIZE);
+ compute_parity6(sh, UPDATE_PARITY);
+ if (memcmp(page_address(tmp_page),
+ page_address(sh->dev[qd_idx].page),
+ STRIPE_SIZE)!= 0) {
+ clear_bit(STRIPE_INSYNC, &sh->state);
+ update_q = 1;
+ }
+ }
+ if (update_p || update_q) {
+ conf->mddev->resync_mismatches += STRIPE_SECTORS;
+ if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
+ /* don't try to repair!! */
+ update_p = update_q = 0;
+ }
+
+ /* now write out any block on a failed drive,
+ * or P or Q if they need it
+ */
+
+ if (failed == 2) {
+ dev = &sh->dev[failed_num[1]];
+ locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+ if (failed >= 1) {
+ dev = &sh->dev[failed_num[0]];
+ locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+
+ if (update_p) {
+ dev = &sh->dev[pd_idx];
+ locked ++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+ if (update_q) {
+ dev = &sh->dev[qd_idx];
+ locked++;
+ set_bit(R5_LOCKED, &dev->flags);
+ set_bit(R5_Wantwrite, &dev->flags);
+ }
+ clear_bit(STRIPE_DEGRADED, &sh->state);
+
+ set_bit(STRIPE_INSYNC, &sh->state);
+ }
+ }
+
+ if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
+ md_done_sync(conf->mddev, STRIPE_SECTORS,1);
+ clear_bit(STRIPE_SYNCING, &sh->state);
+ }
+
+ /* If the failed drives are just a ReadError, then we might need
+ * to progress the repair/check process
+ */
+ if (failed <= 2 && ! conf->mddev->ro)
+ for (i=0; i<failed;i++) {
+ dev = &sh->dev[failed_num[i]];
+ if (test_bit(R5_ReadError, &dev->flags)
+ && !test_bit(R5_LOCKED, &dev->flags)
+ && test_bit(R5_UPTODATE, &dev->flags)
+ ) {
+ 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)) {
+ int bytes = bi->bi_size;
+
+ return_bi = bi->bi_next;
+ bi->bi_next = NULL;
+ bi->bi_size = 0;
+ bi->bi_end_io(bi, bytes, 0);
+ }
+ for (i=disks; i-- ;) {
+ int rw;
+ struct bio *bi;
+ mdk_rdev_t *rdev;
+ if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
+ rw = 1;
+ else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
+ rw = 0;
+ else
+ continue;
+
+ bi = &sh->dev[i].req;
+
+ bi->bi_rw = rw;
+ if (rw)
+ bi->bi_end_io = raid5_end_write_request;
+ else
+ bi->bi_end_io = raid5_end_read_request;
+
+ rcu_read_lock();
+ rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && test_bit(Faulty, &rdev->flags))
+ rdev = NULL;
+ if (rdev)
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+
+ if (rdev) {
+ if (syncing)
+ md_sync_acct(rdev->bdev, STRIPE_SECTORS);
+
+ bi->bi_bdev = rdev->bdev;
+ PRINTK("for %llu schedule op %ld on disc %d\n",
+ (unsigned long long)sh->sector, bi->bi_rw, i);
+ atomic_inc(&sh->count);
+ bi->bi_sector = sh->sector + rdev->data_offset;
+ bi->bi_flags = 1 << BIO_UPTODATE;
+ bi->bi_vcnt = 1;
+ bi->bi_max_vecs = 1;
+ bi->bi_idx = 0;
+ bi->bi_io_vec = &sh->dev[i].vec;
+ bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
+ bi->bi_io_vec[0].bv_offset = 0;
+ bi->bi_size = STRIPE_SIZE;
+ bi->bi_next = NULL;
+ if (rw == WRITE &&
+ test_bit(R5_ReWrite, &sh->dev[i].flags))
+ atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
+ generic_make_request(bi);
+ } else {
+ if (rw == 1)
+ set_bit(STRIPE_DEGRADED, &sh->state);
+ PRINTK("skip op %ld on disc %d for sector %llu\n",
+ bi->bi_rw, i, (unsigned long long)sh->sector);
+ clear_bit(R5_LOCKED, &sh->dev[i].flags);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ }
+}
+
+static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
+{
+ if (sh->raid_conf->level == 6)
+ handle_stripe6(sh, tmp_page);
+ else
+ handle_stripe5(sh);
+}
+
+
+
static void raid5_activate_delayed(raid5_conf_t *conf)
{
if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
@@ -1718,13 +2597,6 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
-static inline void raid5_plug_device(raid5_conf_t *conf)
-{
- spin_lock_irq(&conf->device_lock);
- blk_plug_device(conf->mddev->queue);
- spin_unlock_irq(&conf->device_lock);
-}
-
static int make_request(request_queue_t *q, struct bio * bi)
{
mddev_t *mddev = q->queuedata;
@@ -1753,7 +2625,7 @@ static int make_request(request_queue_t *q, struct bio * bi)
for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
DEFINE_WAIT(w);
- int disks;
+ int disks, data_disks;
retry:
prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
@@ -1781,7 +2653,9 @@ static int make_request(request_queue_t *q, struct bio * bi)
}
spin_unlock_irq(&conf->device_lock);
}
- new_sector = raid5_compute_sector(logical_sector, disks, disks - 1,
+ data_disks = disks - conf->max_degraded;
+
+ new_sector = raid5_compute_sector(logical_sector, disks, data_disks,
&dd_idx, &pd_idx, conf);
PRINTK("raid5: make_request, sector %llu logical %llu\n",
(unsigned long long)new_sector,
@@ -1832,8 +2706,7 @@ static int make_request(request_queue_t *q, struct bio * bi)
goto retry;
}
finish_wait(&conf->wait_for_overlap, &w);
- raid5_plug_device(conf);
- handle_stripe(sh);
+ handle_stripe(sh, NULL);
release_stripe(sh);
} else {
/* cannot get stripe for read-ahead, just give-up */
@@ -1849,7 +2722,7 @@ static int make_request(request_queue_t *q, struct bio * bi)
if (remaining == 0) {
int bytes = bi->bi_size;
- if ( bio_data_dir(bi) == WRITE )
+ if ( rw == WRITE )
md_write_end(mddev);
bi->bi_size = 0;
bi->bi_end_io(bi, bytes, 0);
@@ -1857,17 +2730,141 @@ static int make_request(request_queue_t *q, struct bio * bi)
return 0;
}
-/* FIXME go_faster isn't used */
-static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
+static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped)
{
+ /* reshaping is quite different to recovery/resync so it is
+ * handled quite separately ... here.
+ *
+ * On each call to sync_request, we gather one chunk worth of
+ * destination stripes and flag them as expanding.
+ * Then we find all the source stripes and request reads.
+ * As the reads complete, handle_stripe will copy the data
+ * into the destination stripe and release that stripe.
+ */
raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
struct stripe_head *sh;
int pd_idx;
sector_t first_sector, last_sector;
+ int raid_disks;
+ int data_disks;
+ int i;
+ int dd_idx;
+ sector_t writepos, safepos, gap;
+
+ if (sector_nr == 0 &&
+ conf->expand_progress != 0) {
+ /* restarting in the middle, skip the initial sectors */
+ sector_nr = conf->expand_progress;
+ sector_div(sector_nr, conf->raid_disks-1);
+ *skipped = 1;
+ return sector_nr;
+ }
+
+ /* we update the metadata when there is more than 3Meg
+ * in the block range (that is rather arbitrary, should
+ * probably be time based) or when the data about to be
+ * copied would over-write the source of the data at
+ * the front of the range.
+ * i.e. one new_stripe forward from expand_progress new_maps
+ * to after where expand_lo old_maps to
+ */
+ writepos = conf->expand_progress +
+ conf->chunk_size/512*(conf->raid_disks-1);
+ sector_div(writepos, conf->raid_disks-1);
+ safepos = conf->expand_lo;
+ sector_div(safepos, conf->previous_raid_disks-1);
+ gap = conf->expand_progress - conf->expand_lo;
+
+ if (writepos >= safepos ||
+ gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) {
+ /* Cannot proceed until we've updated the superblock... */
+ wait_event(conf->wait_for_overlap,
+ atomic_read(&conf->reshape_stripes)==0);
+ mddev->reshape_position = conf->expand_progress;
+ mddev->sb_dirty = 1;
+ md_wakeup_thread(mddev->thread);
+ wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
+ kthread_should_stop());
+ spin_lock_irq(&conf->device_lock);
+ conf->expand_lo = mddev->reshape_position;
+ spin_unlock_irq(&conf->device_lock);
+ wake_up(&conf->wait_for_overlap);
+ }
+
+ for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
+ int j;
+ int skipped = 0;
+ pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks);
+ sh = get_active_stripe(conf, sector_nr+i,
+ conf->raid_disks, pd_idx, 0);
+ set_bit(STRIPE_EXPANDING, &sh->state);
+ atomic_inc(&conf->reshape_stripes);
+ /* If any of this stripe is beyond the end of the old
+ * array, then we need to zero those blocks
+ */
+ for (j=sh->disks; j--;) {
+ sector_t s;
+ if (j == sh->pd_idx)
+ continue;
+ s = compute_blocknr(sh, j);
+ if (s < (mddev->array_size<<1)) {
+ skipped = 1;
+ continue;
+ }
+ memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE);
+ set_bit(R5_Expanded, &sh->dev[j].flags);
+ set_bit(R5_UPTODATE, &sh->dev[j].flags);
+ }
+ if (!skipped) {
+ set_bit(STRIPE_EXPAND_READY, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ }
+ release_stripe(sh);
+ }
+ spin_lock_irq(&conf->device_lock);
+ conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1);
+ spin_unlock_irq(&conf->device_lock);
+ /* Ok, those stripe are ready. We can start scheduling
+ * reads on the source stripes.
+ * The source stripes are determined by mapping the first and last
+ * block on the destination stripes.
+ */
+ raid_disks = conf->previous_raid_disks;
+ data_disks = raid_disks - 1;
+ first_sector =
+ raid5_compute_sector(sector_nr*(conf->raid_disks-1),
+ raid_disks, data_disks,
+ &dd_idx, &pd_idx, conf);
+ last_sector =
+ raid5_compute_sector((sector_nr+conf->chunk_size/512)
+ *(conf->raid_disks-1) -1,
+ raid_disks, data_disks,
+ &dd_idx, &pd_idx, conf);
+ if (last_sector >= (mddev->size<<1))
+ last_sector = (mddev->size<<1)-1;
+ while (first_sector <= last_sector) {
+ pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks);
+ sh = get_active_stripe(conf, first_sector,
+ conf->previous_raid_disks, pd_idx, 0);
+ set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
+ set_bit(STRIPE_HANDLE, &sh->state);
+ release_stripe(sh);
+ first_sector += STRIPE_SECTORS;
+ }
+ return conf->chunk_size>>9;
+}
+
+/* FIXME go_faster isn't used */
+static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
+{
+ raid5_conf_t *conf = (raid5_conf_t *) mddev->private;
+ struct stripe_head *sh;
+ int pd_idx;
int raid_disks = conf->raid_disks;
- int data_disks = raid_disks-1;
sector_t max_sector = mddev->size << 1;
int sync_blocks;
+ int still_degraded = 0;
+ int i;
if (sector_nr >= max_sector) {
/* just being told to finish up .. nothing much to do */
@@ -1880,134 +2877,22 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
if (mddev->curr_resync < max_sector) /* aborted */
bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
&sync_blocks, 1);
- else /* compelted sync */
+ else /* completed sync */
conf->fullsync = 0;
bitmap_close_sync(mddev->bitmap);
return 0;
}
- if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) {
- /* reshaping is quite different to recovery/resync so it is
- * handled quite separately ... here.
- *
- * On each call to sync_request, we gather one chunk worth of
- * destination stripes and flag them as expanding.
- * Then we find all the source stripes and request reads.
- * As the reads complete, handle_stripe will copy the data
- * into the destination stripe and release that stripe.
- */
- int i;
- int dd_idx;
- sector_t writepos, safepos, gap;
-
- if (sector_nr == 0 &&
- conf->expand_progress != 0) {
- /* restarting in the middle, skip the initial sectors */
- sector_nr = conf->expand_progress;
- sector_div(sector_nr, conf->raid_disks-1);
- *skipped = 1;
- return sector_nr;
- }
-
- /* we update the metadata when there is more than 3Meg
- * in the block range (that is rather arbitrary, should
- * probably be time based) or when the data about to be
- * copied would over-write the source of the data at
- * the front of the range.
- * i.e. one new_stripe forward from expand_progress new_maps
- * to after where expand_lo old_maps to
- */
- writepos = conf->expand_progress +
- conf->chunk_size/512*(conf->raid_disks-1);
- sector_div(writepos, conf->raid_disks-1);
- safepos = conf->expand_lo;
- sector_div(safepos, conf->previous_raid_disks-1);
- gap = conf->expand_progress - conf->expand_lo;
-
- if (writepos >= safepos ||
- gap > (conf->raid_disks-1)*3000*2 /*3Meg*/) {
- /* Cannot proceed until we've updated the superblock... */
- wait_event(conf->wait_for_overlap,
- atomic_read(&conf->reshape_stripes)==0);
- mddev->reshape_position = conf->expand_progress;
- mddev->sb_dirty = 1;
- md_wakeup_thread(mddev->thread);
- wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
- kthread_should_stop());
- spin_lock_irq(&conf->device_lock);
- conf->expand_lo = mddev->reshape_position;
- spin_unlock_irq(&conf->device_lock);
- wake_up(&conf->wait_for_overlap);
- }
-
- for (i=0; i < conf->chunk_size/512; i+= STRIPE_SECTORS) {
- int j;
- int skipped = 0;
- pd_idx = stripe_to_pdidx(sector_nr+i, conf, conf->raid_disks);
- sh = get_active_stripe(conf, sector_nr+i,
- conf->raid_disks, pd_idx, 0);
- set_bit(STRIPE_EXPANDING, &sh->state);
- atomic_inc(&conf->reshape_stripes);
- /* If any of this stripe is beyond the end of the old
- * array, then we need to zero those blocks
- */
- for (j=sh->disks; j--;) {
- sector_t s;
- if (j == sh->pd_idx)
- continue;
- s = compute_blocknr(sh, j);
- if (s < (mddev->array_size<<1)) {
- skipped = 1;
- continue;
- }
- memset(page_address(sh->dev[j].page), 0, STRIPE_SIZE);
- set_bit(R5_Expanded, &sh->dev[j].flags);
- set_bit(R5_UPTODATE, &sh->dev[j].flags);
- }
- if (!skipped) {
- set_bit(STRIPE_EXPAND_READY, &sh->state);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- release_stripe(sh);
- }
- spin_lock_irq(&conf->device_lock);
- conf->expand_progress = (sector_nr + i)*(conf->raid_disks-1);
- spin_unlock_irq(&conf->device_lock);
- /* Ok, those stripe are ready. We can start scheduling
- * reads on the source stripes.
- * The source stripes are determined by mapping the first and last
- * block on the destination stripes.
- */
- raid_disks = conf->previous_raid_disks;
- data_disks = raid_disks - 1;
- first_sector =
- raid5_compute_sector(sector_nr*(conf->raid_disks-1),
- raid_disks, data_disks,
- &dd_idx, &pd_idx, conf);
- last_sector =
- raid5_compute_sector((sector_nr+conf->chunk_size/512)
- *(conf->raid_disks-1) -1,
- raid_disks, data_disks,
- &dd_idx, &pd_idx, conf);
- if (last_sector >= (mddev->size<<1))
- last_sector = (mddev->size<<1)-1;
- while (first_sector <= last_sector) {
- pd_idx = stripe_to_pdidx(first_sector, conf, conf->previous_raid_disks);
- sh = get_active_stripe(conf, first_sector,
- conf->previous_raid_disks, pd_idx, 0);
- set_bit(STRIPE_EXPAND_SOURCE, &sh->state);
- set_bit(STRIPE_HANDLE, &sh->state);
- release_stripe(sh);
- first_sector += STRIPE_SECTORS;
- }
- return conf->chunk_size>>9;
- }
- /* if there is 1 or more failed drives and we are trying
+ if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ return reshape_request(mddev, sector_nr, skipped);
+
+ /* if there is too many failed drives and we are trying
* to resync, then assert that we are finished, because there is
* nothing we can do.
*/
- if (mddev->degraded >= 1 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+ if (mddev->degraded >= conf->max_degraded &&
+ test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
sector_t rv = (mddev->size << 1) - sector_nr;
*skipped = 1;
return rv;
@@ -2026,17 +2911,26 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
if (sh == NULL) {
sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 0);
/* make sure we don't swamp the stripe cache if someone else
- * is trying to get access
+ * is trying to get access
*/
schedule_timeout_uninterruptible(1);
}
- bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, 0);
- spin_lock(&sh->lock);
+ /* Need to check if array will still be degraded after recovery/resync
+ * We don't need to check the 'failed' flag as when that gets set,
+ * recovery aborts.
+ */
+ for (i=0; i<mddev->raid_disks; i++)
+ if (conf->disks[i].rdev == NULL)
+ still_degraded = 1;
+
+ bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
+
+ spin_lock(&sh->lock);
set_bit(STRIPE_SYNCING, &sh->state);
clear_bit(STRIPE_INSYNC, &sh->state);
spin_unlock(&sh->lock);
- handle_stripe(sh);
+ handle_stripe(sh, NULL);
release_stripe(sh);
return STRIPE_SECTORS;
@@ -2064,7 +2958,7 @@ static void raid5d (mddev_t *mddev)
while (1) {
struct list_head *first;
- if (conf->seq_flush - conf->seq_write > 0) {
+ if (conf->seq_flush != conf->seq_write) {
int seq = conf->seq_flush;
spin_unlock_irq(&conf->device_lock);
bitmap_unplug(mddev->bitmap);
@@ -2091,7 +2985,7 @@ static void raid5d (mddev_t *mddev)
spin_unlock_irq(&conf->device_lock);
handled++;
- handle_stripe(sh);
+ handle_stripe(sh, conf->spare_page);
release_stripe(sh);
spin_lock_irq(&conf->device_lock);
@@ -2181,8 +3075,8 @@ static int run(mddev_t *mddev)
struct disk_info *disk;
struct list_head *tmp;
- if (mddev->level != 5 && mddev->level != 4) {
- printk(KERN_ERR "raid5: %s: raid level not set to 4/5 (%d)\n",
+ if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) {
+ printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n",
mdname(mddev), mddev->level);
return -EIO;
}
@@ -2251,6 +3145,11 @@ static int run(mddev_t *mddev)
if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
goto abort;
+ if (mddev->level == 6) {
+ conf->spare_page = alloc_page(GFP_KERNEL);
+ if (!conf->spare_page)
+ goto abort;
+ }
spin_lock_init(&conf->device_lock);
init_waitqueue_head(&conf->wait_for_stripe);
init_waitqueue_head(&conf->wait_for_overlap);
@@ -2282,12 +3181,16 @@ static int run(mddev_t *mddev)
}
/*
- * 0 for a fully functional array, 1 for a degraded array.
+ * 0 for a fully functional array, 1 or 2 for a degraded array.
*/
mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks;
conf->mddev = mddev;
conf->chunk_size = mddev->chunk_size;
conf->level = mddev->level;
+ if (conf->level == 6)
+ conf->max_degraded = 2;
+ else
+ conf->max_degraded = 1;
conf->algorithm = mddev->layout;
conf->max_nr_stripes = NR_STRIPES;
conf->expand_progress = mddev->reshape_position;
@@ -2296,6 +3199,11 @@ static int run(mddev_t *mddev)
mddev->size &= ~(mddev->chunk_size/1024 -1);
mddev->resync_max_sectors = mddev->size << 1;
+ if (conf->level == 6 && conf->raid_disks < 4) {
+ printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
+ mdname(mddev), conf->raid_disks);
+ goto abort;
+ }
if (!conf->chunk_size || conf->chunk_size % 4) {
printk(KERN_ERR "raid5: invalid chunk size %d for %s\n",
conf->chunk_size, mdname(mddev));
@@ -2307,14 +3215,14 @@ static int run(mddev_t *mddev)
conf->algorithm, mdname(mddev));
goto abort;
}
- if (mddev->degraded > 1) {
+ if (mddev->degraded > conf->max_degraded) {
printk(KERN_ERR "raid5: not enough operational devices for %s"
" (%d/%d failed)\n",
mdname(mddev), conf->failed_disks, conf->raid_disks);
goto abort;
}
- if (mddev->degraded == 1 &&
+ if (mddev->degraded > 0 &&
mddev->recovery_cp != MaxSector) {
if (mddev->ok_start_degraded)
printk(KERN_WARNING
@@ -2373,17 +3281,15 @@ static int run(mddev_t *mddev)
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
mddev->sync_thread = md_register_thread(md_do_sync, mddev,
"%s_reshape");
- /* FIXME if md_register_thread fails?? */
- md_wakeup_thread(mddev->sync_thread);
-
}
/* read-ahead size must cover two whole stripes, which is
- * 2 * (n-1) * chunksize where 'n' is the number of raid devices
+ * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
*/
{
- int stripe = (mddev->raid_disks-1) * mddev->chunk_size
- / PAGE_SIZE;
+ int data_disks = conf->previous_raid_disks - conf->max_degraded;
+ int stripe = data_disks *
+ (mddev->chunk_size / PAGE_SIZE);
if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
}
@@ -2393,12 +3299,14 @@ static int run(mddev_t *mddev)
mddev->queue->unplug_fn = raid5_unplug_device;
mddev->queue->issue_flush_fn = raid5_issue_flush;
- mddev->array_size = mddev->size * (conf->previous_raid_disks - 1);
+ mddev->array_size = mddev->size * (conf->previous_raid_disks -
+ conf->max_degraded);
return 0;
abort:
if (conf) {
print_raid5_conf(conf);
+ safe_put_page(conf->spare_page);
kfree(conf->disks);
kfree(conf->stripe_hashtbl);
kfree(conf);
@@ -2427,23 +3335,23 @@ static int stop(mddev_t *mddev)
}
#if RAID5_DEBUG
-static void print_sh (struct stripe_head *sh)
+static void print_sh (struct seq_file *seq, struct stripe_head *sh)
{
int i;
- printk("sh %llu, pd_idx %d, state %ld.\n",
- (unsigned long long)sh->sector, sh->pd_idx, sh->state);
- printk("sh %llu, count %d.\n",
- (unsigned long long)sh->sector, atomic_read(&sh->count));
- printk("sh %llu, ", (unsigned long long)sh->sector);
+ seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n",
+ (unsigned long long)sh->sector, sh->pd_idx, sh->state);
+ seq_printf(seq, "sh %llu, count %d.\n",
+ (unsigned long long)sh->sector, atomic_read(&sh->count));
+ seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector);
for (i = 0; i < sh->disks; i++) {
- printk("(cache%d: %p %ld) ",
- i, sh->dev[i].page, sh->dev[i].flags);
+ seq_printf(seq, "(cache%d: %p %ld) ",
+ i, sh->dev[i].page, sh->dev[i].flags);
}
- printk("\n");
+ seq_printf(seq, "\n");
}
-static void printall (raid5_conf_t *conf)
+static void printall (struct seq_file *seq, raid5_conf_t *conf)
{
struct stripe_head *sh;
struct hlist_node *hn;
@@ -2454,7 +3362,7 @@ static void printall (raid5_conf_t *conf)
hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) {
if (sh->raid_conf != conf)
continue;
- print_sh(sh);
+ print_sh(seq, sh);
}
}
spin_unlock_irq(&conf->device_lock);
@@ -2474,9 +3382,8 @@ static void status (struct seq_file *seq, mddev_t *mddev)
test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
seq_printf (seq, "]");
#if RAID5_DEBUG
-#define D(x) \
- seq_printf (seq, "<"#x":%d>", atomic_read(&conf->x))
- printall(conf);
+ seq_printf (seq, "\n");
+ printall(seq, conf);
#endif
}
@@ -2560,14 +3467,20 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
int disk;
struct disk_info *p;
- if (mddev->degraded > 1)
+ if (mddev->degraded > conf->max_degraded)
/* no point adding a device */
return 0;
/*
- * find the disk ...
+ * find the disk ... but prefer rdev->saved_raid_disk
+ * if possible.
*/
- for (disk=0; disk < conf->raid_disks; disk++)
+ if (rdev->saved_raid_disk >= 0 &&
+ conf->disks[rdev->saved_raid_disk].rdev == NULL)
+ disk = rdev->saved_raid_disk;
+ else
+ disk = 0;
+ for ( ; disk < conf->raid_disks; disk++)
if ((p=conf->disks + disk)->rdev == NULL) {
clear_bit(In_sync, &rdev->flags);
rdev->raid_disk = disk;
@@ -2590,8 +3503,10 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors)
* any io in the removed space completes, but it hardly seems
* worth it.
*/
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+
sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
- mddev->array_size = (sectors * (mddev->raid_disks-1))>>1;
+ mddev->array_size = (sectors * (mddev->raid_disks-conf->max_degraded))>>1;
set_capacity(mddev->gendisk, mddev->array_size << 1);
mddev->changed = 1;
if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
@@ -2680,6 +3595,7 @@ static int raid5_start_reshape(mddev_t *mddev)
set_bit(In_sync, &rdev->flags);
conf->working_disks++;
added_devices++;
+ rdev->recovery_offset = 0;
sprintf(nm, "rd%d", rdev->raid_disk);
sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
} else
@@ -2731,6 +3647,17 @@ static void end_reshape(raid5_conf_t *conf)
conf->expand_progress = MaxSector;
spin_unlock_irq(&conf->device_lock);
conf->mddev->reshape_position = MaxSector;
+
+ /* read-ahead size must cover two whole stripes, which is
+ * 2 * (datadisks) * chunksize where 'n' is the number of raid devices
+ */
+ {
+ int data_disks = conf->previous_raid_disks - conf->max_degraded;
+ int stripe = data_disks *
+ (conf->mddev->chunk_size / PAGE_SIZE);
+ if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
+ conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
+ }
}
}
@@ -2762,6 +3689,23 @@ static void raid5_quiesce(mddev_t *mddev, int state)
}
}
+static struct mdk_personality raid6_personality =
+{
+ .name = "raid6",
+ .level = 6,
+ .owner = THIS_MODULE,
+ .make_request = make_request,
+ .run = run,
+ .stop = stop,
+ .status = status,
+ .error_handler = error,
+ .hot_add_disk = raid5_add_disk,
+ .hot_remove_disk= raid5_remove_disk,
+ .spare_active = raid5_spare_active,
+ .sync_request = sync_request,
+ .resize = raid5_resize,
+ .quiesce = raid5_quiesce,
+};
static struct mdk_personality raid5_personality =
{
.name = "raid5",
@@ -2804,6 +3748,12 @@ static struct mdk_personality raid4_personality =
static int __init raid5_init(void)
{
+ int e;
+
+ e = raid6_select_algo();
+ if ( e )
+ return e;
+ register_md_personality(&raid6_personality);
register_md_personality(&raid5_personality);
register_md_personality(&raid4_personality);
return 0;
@@ -2811,6 +3761,7 @@ static int __init raid5_init(void)
static void raid5_exit(void)
{
+ unregister_md_personality(&raid6_personality);
unregister_md_personality(&raid5_personality);
unregister_md_personality(&raid4_personality);
}
@@ -2823,3 +3774,10 @@ MODULE_ALIAS("md-raid5");
MODULE_ALIAS("md-raid4");
MODULE_ALIAS("md-level-5");
MODULE_ALIAS("md-level-4");
+MODULE_ALIAS("md-personality-8"); /* RAID6 */
+MODULE_ALIAS("md-raid6");
+MODULE_ALIAS("md-level-6");
+
+/* This used to be two separate modules, they were: */
+MODULE_ALIAS("raid5");
+MODULE_ALIAS("raid6");
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
deleted file mode 100644
index bc69355e010..00000000000
--- a/drivers/md/raid6main.c
+++ /dev/null
@@ -1,2427 +0,0 @@
-/*
- * raid6main.c : Multiple Devices driver for Linux
- * Copyright (C) 1996, 1997 Ingo Molnar, Miguel de Icaza, Gadi Oxman
- * Copyright (C) 1999, 2000 Ingo Molnar
- * Copyright (C) 2002, 2003 H. Peter Anvin
- *
- * RAID-6 management functions. This code is derived from raid5.c.
- * Last merge from raid5.c bkcvs version 1.79 (kernel 2.6.1).
- *
- * Thanks to Penguin Computing for making the RAID-6 development possible
- * by donating a test server!
- *
- * 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, or (at your option)
- * any later version.
- *
- * You should have received a copy of the GNU General Public License
- * (for example /usr/src/linux/COPYING); if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/highmem.h>
-#include <linux/bitops.h>
-#include <asm/atomic.h>
-#include "raid6.h"
-
-#include <linux/raid/bitmap.h>
-
-/*
- * Stripe cache
- */
-
-#define NR_STRIPES 256
-#define STRIPE_SIZE PAGE_SIZE
-#define STRIPE_SHIFT (PAGE_SHIFT - 9)
-#define STRIPE_SECTORS (STRIPE_SIZE>>9)
-#define IO_THRESHOLD 1
-#define NR_HASH (PAGE_SIZE / sizeof(struct hlist_head))
-#define HASH_MASK (NR_HASH - 1)
-
-#define stripe_hash(conf, sect) (&((conf)->stripe_hashtbl[((sect) >> STRIPE_SHIFT) & HASH_MASK]))
-
-/* bio's attached to a stripe+device for I/O are linked together in bi_sector
- * order without overlap. There may be several bio's per stripe+device, and
- * a bio could span several devices.
- * When walking this list for a particular stripe+device, we must never proceed
- * beyond a bio that extends past this device, as the next bio might no longer
- * be valid.
- * This macro is used to determine the 'next' bio in the list, given the sector
- * of the current stripe+device
- */
-#define r5_next_bio(bio, sect) ( ( (bio)->bi_sector + ((bio)->bi_size>>9) < sect + STRIPE_SECTORS) ? (bio)->bi_next : NULL)
-/*
- * The following can be used to debug the driver
- */
-#define RAID6_DEBUG 0 /* Extremely verbose printk */
-#define RAID6_PARANOIA 1 /* Check spinlocks */
-#define RAID6_DUMPSTATE 0 /* Include stripe cache state in /proc/mdstat */
-#if RAID6_PARANOIA && defined(CONFIG_SMP)
-# define CHECK_DEVLOCK() assert_spin_locked(&conf->device_lock)
-#else
-# define CHECK_DEVLOCK()
-#endif
-
-#define PRINTK(x...) ((void)(RAID6_DEBUG && printk(KERN_DEBUG x)))
-#if RAID6_DEBUG
-#undef inline
-#undef __inline__
-#define inline
-#define __inline__
-#endif
-
-#if !RAID6_USE_EMPTY_ZERO_PAGE
-/* In .bss so it's zeroed */
-const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256)));
-#endif
-
-static inline int raid6_next_disk(int disk, int raid_disks)
-{
- disk++;
- return (disk < raid_disks) ? disk : 0;
-}
-
-static void print_raid6_conf (raid6_conf_t *conf);
-
-static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
-{
- if (atomic_dec_and_test(&sh->count)) {
- BUG_ON(!list_empty(&sh->lru));
- BUG_ON(atomic_read(&conf->active_stripes)==0);
- if (test_bit(STRIPE_HANDLE, &sh->state)) {
- if (test_bit(STRIPE_DELAYED, &sh->state))
- list_add_tail(&sh->lru, &conf->delayed_list);
- else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
- conf->seq_write == sh->bm_seq)
- list_add_tail(&sh->lru, &conf->bitmap_list);
- else {
- clear_bit(STRIPE_BIT_DELAY, &sh->state);
- list_add_tail(&sh->lru, &conf->handle_list);
- }
- md_wakeup_thread(conf->mddev->thread);
- } else {
- if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
- atomic_dec(&conf->preread_active_stripes);
- if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
- md_wakeup_thread(conf->mddev->thread);
- }
- list_add_tail(&sh->lru, &conf->inactive_list);
- atomic_dec(&conf->active_stripes);
- if (!conf->inactive_blocked ||
- atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
- wake_up(&conf->wait_for_stripe);
- }
- }
-}
-static void release_stripe(struct stripe_head *sh)
-{
- raid6_conf_t *conf = sh->raid_conf;
- unsigned long flags;
-
- spin_lock_irqsave(&conf->device_lock, flags);
- __release_stripe(conf, sh);
- spin_unlock_irqrestore(&conf->device_lock, flags);
-}
-
-static inline void remove_hash(struct stripe_head *sh)
-{
- PRINTK("remove_hash(), stripe %llu\n", (unsigned long long)sh->sector);
-
- hlist_del_init(&sh->hash);
-}
-
-static inline void insert_hash(raid6_conf_t *conf, struct stripe_head *sh)
-{
- struct hlist_head *hp = stripe_hash(conf, sh->sector);
-
- PRINTK("insert_hash(), stripe %llu\n", (unsigned long long)sh->sector);
-
- CHECK_DEVLOCK();
- hlist_add_head(&sh->hash, hp);
-}
-
-
-/* find an idle stripe, make sure it is unhashed, and return it. */
-static struct stripe_head *get_free_stripe(raid6_conf_t *conf)
-{
- struct stripe_head *sh = NULL;
- struct list_head *first;
-
- CHECK_DEVLOCK();
- if (list_empty(&conf->inactive_list))
- goto out;
- first = conf->inactive_list.next;
- sh = list_entry(first, struct stripe_head, lru);
- list_del_init(first);
- remove_hash(sh);
- atomic_inc(&conf->active_stripes);
-out:
- return sh;
-}
-
-static void shrink_buffers(struct stripe_head *sh, int num)
-{
- struct page *p;
- int i;
-
- for (i=0; i<num ; i++) {
- p = sh->dev[i].page;
- if (!p)
- continue;
- sh->dev[i].page = NULL;
- put_page(p);
- }
-}
-
-static int grow_buffers(struct stripe_head *sh, int num)
-{
- int i;
-
- for (i=0; i<num; i++) {
- struct page *page;
-
- if (!(page = alloc_page(GFP_KERNEL))) {
- return 1;
- }
- sh->dev[i].page = page;
- }
- return 0;
-}
-
-static void raid6_build_block (struct stripe_head *sh, int i);
-
-static void init_stripe(struct stripe_head *sh, sector_t sector, int pd_idx)
-{
- raid6_conf_t *conf = sh->raid_conf;
- int disks = conf->raid_disks, i;
-
- BUG_ON(atomic_read(&sh->count) != 0);
- BUG_ON(test_bit(STRIPE_HANDLE, &sh->state));
-
- CHECK_DEVLOCK();
- PRINTK("init_stripe called, stripe %llu\n",
- (unsigned long long)sh->sector);
-
- remove_hash(sh);
-
- sh->sector = sector;
- sh->pd_idx = pd_idx;
- sh->state = 0;
-
- for (i=disks; i--; ) {
- struct r5dev *dev = &sh->dev[i];
-
- if (dev->toread || dev->towrite || dev->written ||
- test_bit(R5_LOCKED, &dev->flags)) {
- PRINTK("sector=%llx i=%d %p %p %p %d\n",
- (unsigned long long)sh->sector, i, dev->toread,
- dev->towrite, dev->written,
- test_bit(R5_LOCKED, &dev->flags));
- BUG();
- }
- dev->flags = 0;
- raid6_build_block(sh, i);
- }
- insert_hash(conf, sh);
-}
-
-static struct stripe_head *__find_stripe(raid6_conf_t *conf, sector_t sector)
-{
- struct stripe_head *sh;
- struct hlist_node *hn;
-
- CHECK_DEVLOCK();
- PRINTK("__find_stripe, sector %llu\n", (unsigned long long)sector);
- hlist_for_each_entry (sh, hn, stripe_hash(conf, sector), hash)
- if (sh->sector == sector)
- return sh;
- PRINTK("__stripe %llu not in cache\n", (unsigned long long)sector);
- return NULL;
-}
-
-static void unplug_slaves(mddev_t *mddev);
-
-static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector,
- int pd_idx, int noblock)
-{
- struct stripe_head *sh;
-
- PRINTK("get_stripe, sector %llu\n", (unsigned long long)sector);
-
- spin_lock_irq(&conf->device_lock);
-
- do {
- wait_event_lock_irq(conf->wait_for_stripe,
- conf->quiesce == 0,
- conf->device_lock, /* nothing */);
- sh = __find_stripe(conf, sector);
- if (!sh) {
- if (!conf->inactive_blocked)
- sh = get_free_stripe(conf);
- if (noblock && sh == NULL)
- break;
- if (!sh) {
- conf->inactive_blocked = 1;
- wait_event_lock_irq(conf->wait_for_stripe,
- !list_empty(&conf->inactive_list) &&
- (atomic_read(&conf->active_stripes)
- < (conf->max_nr_stripes *3/4)
- || !conf->inactive_blocked),
- conf->device_lock,
- unplug_slaves(conf->mddev);
- );
- conf->inactive_blocked = 0;
- } else
- init_stripe(sh, sector, pd_idx);
- } else {
- if (atomic_read(&sh->count)) {
- BUG_ON(!list_empty(&sh->lru));
- } else {
- if (!test_bit(STRIPE_HANDLE, &sh->state))
- atomic_inc(&conf->active_stripes);
- BUG_ON(list_empty(&sh->lru));
- list_del_init(&sh->lru);
- }
- }
- } while (sh == NULL);
-
- if (sh)
- atomic_inc(&sh->count);
-
- spin_unlock_irq(&conf->device_lock);
- return sh;
-}
-
-static int grow_one_stripe(raid6_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(raid6_conf_t *conf, int num)
-{
- kmem_cache_t *sc;
- int devs = conf->raid_disks;
-
- sprintf(conf->cache_name[0], "raid6/%s", mdname(conf->mddev));
-
- sc = kmem_cache_create(conf->cache_name[0],
- sizeof(struct stripe_head)+(devs-1)*sizeof(struct r5dev),
- 0, 0, NULL, NULL);
- if (!sc)
- return 1;
- conf->slab_cache = sc;
- while (num--)
- if (!grow_one_stripe(conf))
- return 1;
- return 0;
-}
-
-static int drop_one_stripe(raid6_conf_t *conf)
-{
- struct stripe_head *sh;
- spin_lock_irq(&conf->device_lock);
- sh = get_free_stripe(conf);
- spin_unlock_irq(&conf->device_lock);
- if (!sh)
- return 0;
- BUG_ON(atomic_read(&sh->count));
- shrink_buffers(sh, conf->raid_disks);
- kmem_cache_free(conf->slab_cache, sh);
- atomic_dec(&conf->active_stripes);
- return 1;
-}
-
-static void shrink_stripes(raid6_conf_t *conf)
-{
- while (drop_one_stripe(conf))
- ;
-
- if (conf->slab_cache)
- kmem_cache_destroy(conf->slab_cache);
- conf->slab_cache = NULL;
-}
-
-static int raid6_end_read_request(struct bio * bi, unsigned int bytes_done,
- int error)
-{
- struct stripe_head *sh = bi->bi_private;
- raid6_conf_t *conf = sh->raid_conf;
- int disks = conf->raid_disks, i;
- int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
-
- if (bi->bi_size)
- return 1;
-
- for (i=0 ; i<disks; i++)
- if (bi == &sh->dev[i].req)
- break;
-
- PRINTK("end_read_request %llu/%d, count: %d, uptodate %d.\n",
- (unsigned long long)sh->sector, i, atomic_read(&sh->count),
- uptodate);
- if (i == disks) {
- BUG();
- return 0;
- }
-
- if (uptodate) {
-#if 0
- struct bio *bio;
- unsigned long flags;
- spin_lock_irqsave(&conf->device_lock, flags);
- /* we can return a buffer if we bypassed the cache or
- * if the top buffer is not in highmem. If there are
- * multiple buffers, leave the extra work to
- * handle_stripe
- */
- buffer = sh->bh_read[i];
- if (buffer &&
- (!PageHighMem(buffer->b_page)
- || buffer->b_page == bh->b_page )
- ) {
- sh->bh_read[i] = buffer->b_reqnext;
- buffer->b_reqnext = NULL;
- } else
- buffer = NULL;
- spin_unlock_irqrestore(&conf->device_lock, flags);
- if (sh->bh_page[i]==bh->b_page)
- set_buffer_uptodate(bh);
- if (buffer) {
- if (buffer->b_page != bh->b_page)
- memcpy(buffer->b_data, bh->b_data, bh->b_size);
- buffer->b_end_io(buffer, 1);
- }
-#else
- set_bit(R5_UPTODATE, &sh->dev[i].flags);
-#endif
- if (test_bit(R5_ReadError, &sh->dev[i].flags)) {
- printk(KERN_INFO "raid6: 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 {
- int retry = 0;
- clear_bit(R5_UPTODATE, &sh->dev[i].flags);
- atomic_inc(&conf->disks[i].rdev->read_errors);
- if (conf->mddev->degraded)
- printk(KERN_WARNING "raid6: read error not correctable.\n");
- else if (test_bit(R5_ReWrite, &sh->dev[i].flags))
- /* Oh, no!!! */
- printk(KERN_WARNING "raid6: read error NOT corrected!!\n");
- else if (atomic_read(&conf->disks[i].rdev->read_errors)
- > conf->max_nr_stripes)
- printk(KERN_WARNING
- "raid6: 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
- /* must restore b_page before unlocking buffer... */
- if (sh->bh_page[i] != bh->b_page) {
- bh->b_page = sh->bh_page[i];
- bh->b_data = page_address(bh->b_page);
- clear_buffer_uptodate(bh);
- }
-#endif
- clear_bit(R5_LOCKED, &sh->dev[i].flags);
- set_bit(STRIPE_HANDLE, &sh->state);
- release_stripe(sh);
- return 0;
-}
-
-static int raid6_end_write_request (struct bio *bi, unsigned int bytes_done,
- int error)
-{
- struct stripe_head *sh = bi->bi_private;
- raid6_conf_t *conf = sh->raid_conf;
- int disks = conf->raid_disks, i;
- unsigned long flags;
- int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
-
- if (bi->bi_size)
- return 1;
-
- for (i=0 ; i<disks; i++)
- if (bi == &sh->dev[i].req)
- break;
-
- PRINTK("end_write_request %llu/%d, count %d, uptodate: %d.\n",
- (unsigned long long)sh->sector, i, atomic_read(&sh->count),
- uptodate);
- if (i == disks) {
- BUG();
- return 0;
- }
-
- spin_lock_irqsave(&conf->device_lock, flags);
- if (!uptodate)
- md_error(conf->mddev, conf->disks[i].rdev);
-
- rdev_dec_pending(conf->disks[i].rdev, conf->mddev);
-
- clear_bit(R5_LOCKED, &sh->dev[i].flags);
- set_bit(STRIPE_HANDLE, &sh->state);
- __release_stripe(conf, sh);
- spin_unlock_irqrestore(&conf->device_lock, flags);
- return 0;
-}
-
-
-static sector_t compute_blocknr(struct stripe_head *sh, int i);
-
-static void raid6_build_block (struct stripe_head *sh, int i)
-{
- struct r5dev *dev = &sh->dev[i];
- int pd_idx = sh->pd_idx;
- int qd_idx = raid6_next_disk(pd_idx, sh->raid_conf->raid_disks);
-
- bio_init(&dev->req);
- dev->req.bi_io_vec = &dev->vec;
- dev->req.bi_vcnt++;
- dev->req.bi_max_vecs++;
- dev->vec.bv_page = dev->page;
- dev->vec.bv_len = STRIPE_SIZE;
- dev->vec.bv_offset = 0;
-
- dev->req.bi_sector = sh->sector;
- dev->req.bi_private = sh;
-
- dev->flags = 0;
- if (i != pd_idx && i != qd_idx)
- dev->sector = compute_blocknr(sh, i);
-}
-
-static void error(mddev_t *mddev, mdk_rdev_t *rdev)
-{
- char b[BDEVNAME_SIZE];
- raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
- PRINTK("raid6: error called\n");
-
- if (!test_bit(Faulty, &rdev->flags)) {
- mddev->sb_dirty = 1;
- if (test_bit(In_sync, &rdev->flags)) {
- conf->working_disks--;
- mddev->degraded++;
- conf->failed_disks++;
- clear_bit(In_sync, &rdev->flags);
- /*
- * if recovery was running, make sure it aborts.
- */
- set_bit(MD_RECOVERY_ERR, &mddev->recovery);
- }
- set_bit(Faulty, &rdev->flags);
- printk (KERN_ALERT
- "raid6: Disk failure on %s, disabling device."
- " Operation continuing on %d devices\n",
- bdevname(rdev->bdev,b), conf->working_disks);
- }
-}
-
-/*
- * Input: a 'big' sector number,
- * Output: index of the data and parity disk, and the sector # in them.
- */
-static sector_t raid6_compute_sector(sector_t r_sector, unsigned int raid_disks,
- unsigned int data_disks, unsigned int * dd_idx,
- unsigned int * pd_idx, raid6_conf_t *conf)
-{
- long stripe;
- unsigned long chunk_number;
- unsigned int chunk_offset;
- sector_t new_sector;
- int sectors_per_chunk = conf->chunk_size >> 9;
-
- /* First compute the information on this sector */
-
- /*
- * Compute the chunk number and the sector offset inside the chunk
- */
- chunk_offset = sector_div(r_sector, sectors_per_chunk);
- chunk_number = r_sector;
- if ( r_sector != chunk_number ) {
- printk(KERN_CRIT "raid6: ERROR: r_sector = %llu, chunk_number = %lu\n",
- (unsigned long long)r_sector, (unsigned long)chunk_number);
- BUG();
- }
-
- /*
- * Compute the stripe number
- */
- stripe = chunk_number / data_disks;
-
- /*
- * Compute the data disk and parity disk indexes inside the stripe
- */
- *dd_idx = chunk_number % data_disks;
-
- /*
- * Select the parity disk based on the user selected algorithm.
- */
-
- /**** FIX THIS ****/
- switch (conf->algorithm) {
- case ALGORITHM_LEFT_ASYMMETRIC:
- *pd_idx = raid_disks - 1 - (stripe % raid_disks);
- if (*pd_idx == raid_disks-1)
- (*dd_idx)++; /* Q D D D P */
- else if (*dd_idx >= *pd_idx)
- (*dd_idx) += 2; /* D D P Q D */
- break;
- case ALGORITHM_RIGHT_ASYMMETRIC:
- *pd_idx = stripe % raid_disks;
- if (*pd_idx == raid_disks-1)
- (*dd_idx)++; /* Q D D D P */
- else if (*dd_idx >= *pd_idx)
- (*dd_idx) += 2; /* D D P Q D */
- break;
- case ALGORITHM_LEFT_SYMMETRIC:
- *pd_idx = raid_disks - 1 - (stripe % raid_disks);
- *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
- break;
- case ALGORITHM_RIGHT_SYMMETRIC:
- *pd_idx = stripe % raid_disks;
- *dd_idx = (*pd_idx + 2 + *dd_idx) % raid_disks;
- break;
- default:
- printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
- conf->algorithm);
- }
-
- PRINTK("raid6: chunk_number = %lu, pd_idx = %u, dd_idx = %u\n",
- chunk_number, *pd_idx, *dd_idx);
-
- /*
- * Finally, compute the new sector number
- */
- new_sector = (sector_t) stripe * sectors_per_chunk + chunk_offset;
- return new_sector;
-}
-
-
-static sector_t compute_blocknr(struct stripe_head *sh, int i)
-{
- raid6_conf_t *conf = sh->raid_conf;
- int raid_disks = conf->raid_disks, data_disks = raid_disks - 2;
- sector_t new_sector = sh->sector, check;
- int sectors_per_chunk = conf->chunk_size >> 9;
- sector_t stripe;
- int chunk_offset;
- int chunk_number, dummy1, dummy2, dd_idx = i;
- sector_t r_sector;
- int i0 = i;
-
- chunk_offset = sector_div(new_sector, sectors_per_chunk);
- stripe = new_sector;
- if ( new_sector != stripe ) {
- printk(KERN_CRIT "raid6: ERROR: new_sector = %llu, stripe = %lu\n",
- (unsigned long long)new_sector, (unsigned long)stripe);
- BUG();
- }
-
- switch (conf->algorithm) {
- case ALGORITHM_LEFT_ASYMMETRIC:
- case ALGORITHM_RIGHT_ASYMMETRIC:
- if (sh->pd_idx == raid_disks-1)
- i--; /* Q D D D P */
- else if (i > sh->pd_idx)
- i -= 2; /* D D P Q D */
- break;
- case ALGORITHM_LEFT_SYMMETRIC:
- case ALGORITHM_RIGHT_SYMMETRIC:
- if (sh->pd_idx == raid_disks-1)
- i--; /* Q D D D P */
- else {
- /* D D P Q D */
- if (i < sh->pd_idx)
- i += raid_disks;
- i -= (sh->pd_idx + 2);
- }
- break;
- default:
- printk (KERN_CRIT "raid6: unsupported algorithm %d\n",
- conf->algorithm);
- }
-
- PRINTK("raid6: compute_blocknr: pd_idx = %u, i0 = %u, i = %u\n", sh->pd_idx, i0, i);
-
- chunk_number = stripe * data_disks + i;
- r_sector = (sector_t)chunk_number * sectors_per_chunk + chunk_offset;
-
- check = raid6_compute_sector (r_sector, raid_disks, data_disks, &dummy1, &dummy2, conf);
- if (check != sh->sector || dummy1 != dd_idx || dummy2 != sh->pd_idx) {
- printk(KERN_CRIT "raid6: compute_blocknr: map not correct\n");
- return 0;
- }
- return r_sector;
-}
-
-
-
-/*
- * Copy data between a page in the stripe cache, and one or more bion
- * The page could align with the middle of the bio, or there could be
- * several bion, each with several bio_vecs, which cover part of the page
- * Multiple bion are linked together on bi_next. There may be extras
- * at the end of this list. We ignore them.
- */
-static void copy_data(int frombio, struct bio *bio,
- struct page *page,
- sector_t sector)
-{
- char *pa = page_address(page);
- struct bio_vec *bvl;
- int i;
- int page_offset;
-
- if (bio->bi_sector >= sector)
- page_offset = (signed)(bio->bi_sector - sector) * 512;
- else
- page_offset = (signed)(sector - bio->bi_sector) * -512;
- bio_for_each_segment(bvl, bio, i) {
- int len = bio_iovec_idx(bio,i)->bv_len;
- int clen;
- int b_offset = 0;
-
- if (page_offset < 0) {
- b_offset = -page_offset;
- page_offset += b_offset;
- len -= b_offset;
- }
-
- if (len > 0 && page_offset + len > STRIPE_SIZE)
- clen = STRIPE_SIZE - page_offset;
- else clen = len;
-
- if (clen > 0) {
- char *ba = __bio_kmap_atomic(bio, i, KM_USER0);
- if (frombio)
- memcpy(pa+page_offset, ba+b_offset, clen);
- else
- memcpy(ba+b_offset, pa+page_offset, clen);
- __bio_kunmap_atomic(ba, KM_USER0);
- }
- if (clen < len) /* hit end of page */
- break;
- page_offset += len;
- }
-}
-
-#define check_xor() do { \
- if (count == MAX_XOR_BLOCKS) { \
- xor_block(count, STRIPE_SIZE, ptr); \
- count = 1; \
- } \
- } while(0)
-
-/* Compute P and Q syndromes */
-static void compute_parity(struct stripe_head *sh, int method)
-{
- raid6_conf_t *conf = sh->raid_conf;
- int i, pd_idx = sh->pd_idx, qd_idx, d0_idx, disks = conf->raid_disks, count;
- struct bio *chosen;
- /**** FIX THIS: This could be very bad if disks is close to 256 ****/
- void *ptrs[disks];
-
- qd_idx = raid6_next_disk(pd_idx, disks);
- d0_idx = raid6_next_disk(qd_idx, disks);
-
- PRINTK("compute_parity, stripe %llu, method %d\n",
- (unsigned long long)sh->sector, method);
-
- switch(method) {
- case READ_MODIFY_WRITE:
- BUG(); /* READ_MODIFY_WRITE N/A for RAID-6 */
- case RECONSTRUCT_WRITE:
- for (i= disks; i-- ;)
- if ( i != pd_idx && i != qd_idx && sh->dev[i].towrite ) {
- chosen = sh->dev[i].towrite;
- sh->dev[i].towrite = NULL;
-
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
-
- BUG_ON(sh->dev[i].written);
- sh->dev[i].written = chosen;
- }
- break;
- case CHECK_PARITY:
- BUG(); /* Not implemented yet */
- }
-
- for (i = disks; i--;)
- if (sh->dev[i].written) {
- sector_t sector = sh->dev[i].sector;
- struct bio *wbi = sh->dev[i].written;
- while (wbi && wbi->bi_sector < sector + STRIPE_SECTORS) {
- copy_data(1, wbi, sh->dev[i].page, sector);
- wbi = r5_next_bio(wbi, sector);
- }
-
- set_bit(R5_LOCKED, &sh->dev[i].flags);
- set_bit(R5_UPTODATE, &sh->dev[i].flags);
- }
-
-// switch(method) {
-// case RECONSTRUCT_WRITE:
-// case CHECK_PARITY:
-// case UPDATE_PARITY:
- /* Note that unlike RAID-5, the ordering of the disks matters greatly. */
- /* FIX: Is this ordering of drives even remotely optimal? */
- count = 0;
- i = d0_idx;
- do {
- ptrs[count++] = page_address(sh->dev[i].page);
- if (count <= disks-2 && !test_bit(R5_UPTODATE, &sh->dev[i].flags))
- printk("block %d/%d not uptodate on parity calc\n", i,count);
- i = raid6_next_disk(i, disks);
- } while ( i != d0_idx );
-// break;
-// }
-
- raid6_call.gen_syndrome(disks, STRIPE_SIZE, ptrs);
-
- switch(method) {
- case RECONSTRUCT_WRITE:
- set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
- set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
- set_bit(R5_LOCKED, &sh->dev[pd_idx].flags);
- set_bit(R5_LOCKED, &sh->dev[qd_idx].flags);
- break;
- case UPDATE_PARITY:
- set_bit(R5_UPTODATE, &sh->dev[pd_idx].flags);
- set_bit(R5_UPTODATE, &sh->dev[qd_idx].flags);
- break;
- }
-}
-
-/* Compute one missing block */
-static void compute_block_1(struct stripe_head *sh, int dd_idx, int nozero)
-{
- raid6_conf_t *conf = sh->raid_conf;
- int i, count, disks = conf->raid_disks;
- void *ptr[MAX_XOR_BLOCKS], *p;
- int pd_idx = sh->pd_idx;
- int qd_idx = raid6_next_disk(pd_idx, disks);
-
- PRINTK("compute_block_1, stripe %llu, idx %d\n",
- (unsigned long long)sh->sector, dd_idx);
-
- if ( dd_idx == qd_idx ) {
- /* We're actually computing the Q drive */
- compute_parity(sh, UPDATE_PARITY);
- } else {
- ptr[0] = page_address(sh->dev[dd_idx].page);
- if (!nozero) memset(ptr[0], 0, STRIPE_SIZE);
- count = 1;
- for (i = disks ; i--; ) {
- if (i == dd_idx || i == qd_idx)
- continue;
- p = page_address(sh->dev[i].page);
- if (test_bit(R5_UPTODATE, &sh->dev[i].flags))
- ptr[count++] = p;
- else
- printk("compute_block() %d, stripe %llu, %d"
- " not present\n", dd_idx,
- (unsigned long long)sh->sector, i);
-
- check_xor();
- }
- if (count != 1)
- xor_block(count, STRIPE_SIZE, ptr);
- if (!nozero) set_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
- else clear_bit(R5_UPTODATE, &sh->dev[dd_idx].flags);
- }
-}
-
-/* Compute two missing blocks */
-static void compute_block_2(struct stripe_head *sh, int dd_idx1, int dd_idx2)
-{
- raid6_conf_t *conf = sh->raid_conf;
- int i, count, disks = conf->raid_disks;
- int pd_idx = sh->pd_idx;
- int qd_idx = raid6_next_disk(pd_idx, disks);
- int d0_idx = raid6_next_disk(qd_idx, disks);
- int faila, failb;
-
- /* faila and failb are disk numbers relative to d0_idx */
- /* pd_idx become disks-2 and qd_idx become disks-1 */
- faila = (dd_idx1 < d0_idx) ? dd_idx1+(disks-d0_idx) : dd_idx1-d0_idx;
- failb = (dd_idx2 < d0_idx) ? dd_idx2+(disks-d0_idx) : dd_idx2-d0_idx;
-
- BUG_ON(faila == failb);
- if ( failb < faila ) { int tmp = faila; faila = failb; failb = tmp; }
-
- PRINTK("compute_block_2, stripe %llu, idx %d,%d (%d,%d)\n",
- (unsigned long long)sh->sector, dd_idx1, dd_idx2, faila, failb);
-
- if ( failb == disks-1 ) {
- /* Q disk is one of the missing disks */
- if ( faila == disks-2 ) {
- /* Missing P+Q, just recompute */
- compute_parity(sh, UPDATE_PARITY);
- return;
- } else {
- /* We're missing D+Q; recompute D from P */
- compute_block_1(sh, (dd_idx1 == qd_idx) ? dd_idx2 : dd_idx1, 0);
- compute_parity(sh, UPDATE_PARITY); /* Is this necessary? */
- return;
- }
- }
-
- /* We're missing D+P or D+D; build pointer table */
- {
- /**** FIX THIS: This could be very bad if disks is close to 256 ****/
- void *ptrs[disks];
-
- count = 0;
- i = d0_idx;
- do {
- ptrs[count++] = page_address(sh->dev[i].page);
- i = raid6_next_disk(i, disks);
- if (i != dd_idx1 && i != dd_idx2 &&
- !test_bit(R5_UPTODATE, &sh->dev[i].flags))
- printk("compute_2 with missing block %d/%d\n", count, i);
- } while ( i != d0_idx );
-
- if ( failb == disks-2 ) {
- /* We're missing D+P. */
- raid6_datap_recov(disks, STRIPE_SIZE, faila, ptrs);
- } else {
- /* We're missing D+D. */
- raid6_2data_recov(disks, STRIPE_SIZE, faila, failb, ptrs);
- }
-
- /* Both the above update both missing blocks */
- set_bit(R5_UPTODATE, &sh->dev[dd_idx1].flags);
- set_bit(R5_UPTODATE, &sh->dev[dd_idx2].flags);
- }
-}
-
-
-/*
- * Each stripe/dev can have one or more bion attached.
- * toread/towrite point to the first in a chain.
- * The bi_next chain must be in order.
- */
-static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, int forwrite)
-{
- struct bio **bip;
- raid6_conf_t *conf = sh->raid_conf;
- int firstwrite=0;
-
- PRINTK("adding bh b#%llu to stripe s#%llu\n",
- (unsigned long long)bi->bi_sector,
- (unsigned long long)sh->sector);
-
-
- spin_lock(&sh->lock);
- spin_lock_irq(&conf->device_lock);
- if (forwrite) {
- bip = &sh->dev[dd_idx].towrite;
- if (*bip == NULL && sh->dev[dd_idx].written == NULL)
- firstwrite = 1;
- } else
- bip = &sh->dev[dd_idx].toread;
- while (*bip && (*bip)->bi_sector < bi->bi_sector) {
- if ((*bip)->bi_sector + ((*bip)->bi_size >> 9) > bi->bi_sector)
- goto overlap;
- bip = &(*bip)->bi_next;
- }
- if (*bip && (*bip)->bi_sector < bi->bi_sector + ((bi->bi_size)>>9))
- goto overlap;
-
- BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next);
- if (*bip)
- bi->bi_next = *bip;
- *bip = bi;
- bi->bi_phys_segments ++;
- spin_unlock_irq(&conf->device_lock);
- spin_unlock(&sh->lock);
-
- PRINTK("added bi b#%llu to stripe s#%llu, disk %d.\n",
- (unsigned long long)bi->bi_sector,
- (unsigned long long)sh->sector, dd_idx);
-
- if (conf->mddev->bitmap && firstwrite) {
- sh->bm_seq = conf->seq_write;
- bitmap_startwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS, 0);
- set_bit(STRIPE_BIT_DELAY, &sh->state);
- }
-
- if (forwrite) {
- /* check if page is covered */
- sector_t sector = sh->dev[dd_idx].sector;
- for (bi=sh->dev[dd_idx].towrite;
- sector < sh->dev[dd_idx].sector + STRIPE_SECTORS &&
- bi && bi->bi_sector <= sector;
- bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) {
- if (bi->bi_sector + (bi->bi_size>>9) >= sector)
- sector = bi->bi_sector + (bi->bi_size>>9);
- }
- if (sector >= sh->dev[dd_idx].sector + STRIPE_SECTORS)
- set_bit(R5_OVERWRITE, &sh->dev[dd_idx].flags);
- }
- return 1;
-
- overlap:
- set_bit(R5_Overlap, &sh->dev[dd_idx].flags);
- spin_unlock_irq(&conf->device_lock);
- spin_unlock(&sh->lock);
- return 0;
-}
-
-
-static int page_is_zero(struct page *p)
-{
- char *a = page_address(p);
- return ((*(u32*)a) == 0 &&
- memcmp(a, a+4, STRIPE_SIZE-4)==0);
-}
-/*
- * handle_stripe - do things to a stripe.
- *
- * We lock the stripe and then examine the state of various bits
- * to see what needs to be done.
- * Possible results:
- * return some read request which now have data
- * return some write requests which are safely on disc
- * schedule a read on some buffers
- * schedule a write of some buffers
- * return confirmation of parity correctness
- *
- * Parity calculations are done inside the stripe lock
- * buffers are taken off read_list or write_list, and bh_cache buffers
- * get BH_Lock set before the stripe lock is released.
- *
- */
-
-static void handle_stripe(struct stripe_head *sh, struct page *tmp_page)
-{
- raid6_conf_t *conf = sh->raid_conf;
- int disks = conf->raid_disks;
- struct bio *return_bi= NULL;
- struct bio *bi;
- int i;
- int syncing;
- int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
- int non_overwrite = 0;
- int failed_num[2] = {0, 0};
- struct r5dev *dev, *pdev, *qdev;
- int pd_idx = sh->pd_idx;
- int qd_idx = raid6_next_disk(pd_idx, disks);
- int p_failed, q_failed;
-
- PRINTK("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d, qd_idx=%d\n",
- (unsigned long long)sh->sector, sh->state, atomic_read(&sh->count),
- pd_idx, qd_idx);
-
- spin_lock(&sh->lock);
- clear_bit(STRIPE_HANDLE, &sh->state);
- clear_bit(STRIPE_DELAYED, &sh->state);
-
- syncing = test_bit(STRIPE_SYNCING, &sh->state);
- /* Now to look around and see what can be done */
-
- rcu_read_lock();
- for (i=disks; i--; ) {
- mdk_rdev_t *rdev;
- dev = &sh->dev[i];
- clear_bit(R5_Insync, &dev->flags);
-
- PRINTK("check %d: state 0x%lx read %p write %p written %p\n",
- i, dev->flags, dev->toread, dev->towrite, dev->written);
- /* maybe we can reply to a read */
- if (test_bit(R5_UPTODATE, &dev->flags) && dev->toread) {
- struct bio *rbi, *rbi2;
- PRINTK("Return read for disc %d\n", i);
- spin_lock_irq(&conf->device_lock);
- rbi = dev->toread;
- dev->toread = NULL;
- if (test_and_clear_bit(R5_Overlap, &dev->flags))
- wake_up(&conf->wait_for_overlap);
- spin_unlock_irq(&conf->device_lock);
- while (rbi && rbi->bi_sector < dev->sector + STRIPE_SECTORS) {
- copy_data(0, rbi, dev->page, dev->sector);
- rbi2 = r5_next_bio(rbi, dev->sector);
- spin_lock_irq(&conf->device_lock);
- if (--rbi->bi_phys_segments == 0) {
- rbi->bi_next = return_bi;
- return_bi = rbi;
- }
- spin_unlock_irq(&conf->device_lock);
- rbi = rbi2;
- }
- }
-
- /* now count some things */
- if (test_bit(R5_LOCKED, &dev->flags)) locked++;
- if (test_bit(R5_UPTODATE, &dev->flags)) uptodate++;
-
-
- if (dev->toread) to_read++;
- if (dev->towrite) {
- to_write++;
- if (!test_bit(R5_OVERWRITE, &dev->flags))
- non_overwrite++;
- }
- if (dev->written) written++;
- rdev = rcu_dereference(conf->disks[i].rdev);
- if (!rdev || !test_bit(In_sync, &rdev->flags)) {
- /* The ReadError flag will 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)) {
- if ( failed < 2 )
- failed_num[failed] = i;
- failed++;
- } else
- set_bit(R5_Insync, &dev->flags);
- }
- rcu_read_unlock();
- PRINTK("locked=%d uptodate=%d to_read=%d"
- " to_write=%d failed=%d failed_num=%d,%d\n",
- locked, uptodate, to_read, to_write, failed,
- failed_num[0], failed_num[1]);
- /* check if the array has lost >2 devices and, if so, some requests might
- * need to be failed
- */
- if (failed > 2 && 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;
- rcu_read_lock();
- rdev = rcu_dereference(conf->disks[i].rdev);
- if (rdev && test_bit(In_sync, &rdev->flags))
- /* multiple read failures in one stripe */
- md_error(conf->mddev, rdev);
- rcu_read_unlock();
- }
-
- spin_lock_irq(&conf->device_lock);
- /* fail all writes first */
- bi = sh->dev[i].towrite;
- sh->dev[i].towrite = NULL;
- if (bi) { to_write--; bitmap_end = 1; }
-
- if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
- wake_up(&conf->wait_for_overlap);
-
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
- struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = nextbi;
- }
- /* and fail all 'written' */
- bi = sh->dev[i].written;
- sh->dev[i].written = NULL;
- if (bi) bitmap_end = 1;
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) {
- struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = bi2;
- }
-
- /* fail any reads if this device is non-operational */
- 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))
- wake_up(&conf->wait_for_overlap);
- if (bi) to_read--;
- while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS){
- struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- if (--bi->bi_phys_segments == 0) {
- bi->bi_next = return_bi;
- return_bi = bi;
- }
- bi = nextbi;
- }
- }
- spin_unlock_irq(&conf->device_lock);
- if (bitmap_end)
- bitmap_endwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS, 0, 0);
- }
- }
- if (failed > 2 && syncing) {
- md_done_sync(conf->mddev, STRIPE_SECTORS,0);
- clear_bit(STRIPE_SYNCING, &sh->state);
- syncing = 0;
- }
-
- /*
- * might be able to return some write requests if the parity blocks
- * are safe, or on a failed drive
- */
- pdev = &sh->dev[pd_idx];
- p_failed = (failed >= 1 && failed_num[0] == pd_idx)
- || (failed >= 2 && failed_num[1] == pd_idx);
- qdev = &sh->dev[qd_idx];
- q_failed = (failed >= 1 && failed_num[0] == qd_idx)
- || (failed >= 2 && failed_num[1] == qd_idx);
-
- if ( written &&
- ( p_failed || ((test_bit(R5_Insync, &pdev->flags)
- && !test_bit(R5_LOCKED, &pdev->flags)
- && test_bit(R5_UPTODATE, &pdev->flags))) ) &&
- ( q_failed || ((test_bit(R5_Insync, &qdev->flags)
- && !test_bit(R5_LOCKED, &qdev->flags)
- && test_bit(R5_UPTODATE, &qdev->flags))) ) ) {
- /* any written block on an uptodate or failed drive can be
- * returned. Note that if we 'wrote' to a failed drive,
- * it will be UPTODATE, but never LOCKED, so we don't need
- * to test 'failed' directly.
- */
- for (i=disks; i--; )
- if (sh->dev[i].written) {
- dev = &sh->dev[i];
- if (!test_bit(R5_LOCKED, &dev->flags) &&
- test_bit(R5_UPTODATE, &dev->flags) ) {
- /* We can return any write requests */
- int bitmap_end = 0;
- struct bio *wbi, *wbi2;
- PRINTK("Return write for stripe %llu disc %d\n",
- (unsigned long long)sh->sector, i);
- spin_lock_irq(&conf->device_lock);
- wbi = dev->written;
- dev->written = NULL;
- while (wbi && wbi->bi_sector < dev->sector + STRIPE_SECTORS) {
- wbi2 = r5_next_bio(wbi, dev->sector);
- if (--wbi->bi_phys_segments == 0) {
- md_write_end(conf->mddev);
- wbi->bi_next = return_bi;
- return_bi = wbi;
- }
- wbi = wbi2;
- }
- if (dev->towrite == NULL)
- bitmap_end = 1;
- spin_unlock_irq(&conf->device_lock);
- if (bitmap_end)
- bitmap_endwrite(conf->mddev->bitmap, sh->sector,
- STRIPE_SECTORS,
- !test_bit(STRIPE_DEGRADED, &sh->state), 0);
- }
- }
- }
-
- /* Now we might consider reading some blocks, either to check/generate
- * parity, or to satisfy requests
- * or to load a block that is being partially written.
- */
- if (to_read || non_overwrite || (to_write && failed) || (syncing && (uptodate < disks))) {
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- (dev->toread ||
- (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
- syncing ||
- (failed >= 1 && (sh->dev[failed_num[0]].toread || to_write)) ||
- (failed >= 2 && (sh->dev[failed_num[1]].toread || to_write))
- )
- ) {
- /* we would like to get this block, possibly
- * by computing it, but we might not be able to
- */
- if (uptodate == disks-1) {
- PRINTK("Computing stripe %llu block %d\n",
- (unsigned long long)sh->sector, i);
- compute_block_1(sh, i, 0);
- uptodate++;
- } else if ( uptodate == disks-2 && failed >= 2 ) {
- /* Computing 2-failure is *very* expensive; only do it if failed >= 2 */
- int other;
- for (other=disks; other--;) {
- if ( other == i )
- continue;
- if ( !test_bit(R5_UPTODATE, &sh->dev[other].flags) )
- break;
- }
- BUG_ON(other < 0);
- PRINTK("Computing stripe %llu blocks %d,%d\n",
- (unsigned long long)sh->sector, i, other);
- compute_block_2(sh, i, other);
- uptodate += 2;
- } else if (test_bit(R5_Insync, &dev->flags)) {
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
-#if 0
- /* if I am just reading this block and we don't have
- a failed drive, or any pending writes then sidestep the cache */
- if (sh->bh_read[i] && !sh->bh_read[i]->b_reqnext &&
- ! syncing && !failed && !to_write) {
- sh->bh_cache[i]->b_page = sh->bh_read[i]->b_page;
- sh->bh_cache[i]->b_data = sh->bh_read[i]->b_data;
- }
-#endif
- locked++;
- PRINTK("Reading block %d (sync=%d)\n",
- i, syncing);
- }
- }
- }
- set_bit(STRIPE_HANDLE, &sh->state);
- }
-
- /* now to consider writing and what else, if anything should be read */
- if (to_write) {
- int rcw=0, must_compute=0;
- for (i=disks ; i--;) {
- dev = &sh->dev[i];
- /* Would I have to read this buffer for reconstruct_write */
- if (!test_bit(R5_OVERWRITE, &dev->flags)
- && i != pd_idx && i != qd_idx
- && (!test_bit(R5_LOCKED, &dev->flags)
-#if 0
- || sh->bh_page[i] != bh->b_page
-#endif
- ) &&
- !test_bit(R5_UPTODATE, &dev->flags)) {
- if (test_bit(R5_Insync, &dev->flags)) rcw++;
- else {
- PRINTK("raid6: must_compute: disk %d flags=%#lx\n", i, dev->flags);
- must_compute++;
- }
- }
- }
- PRINTK("for sector %llu, rcw=%d, must_compute=%d\n",
- (unsigned long long)sh->sector, rcw, must_compute);
- set_bit(STRIPE_HANDLE, &sh->state);
-
- if (rcw > 0)
- /* want reconstruct write, but need to get some data */
- for (i=disks; i--;) {
- dev = &sh->dev[i];
- if (!test_bit(R5_OVERWRITE, &dev->flags)
- && !(failed == 0 && (i == pd_idx || i == qd_idx))
- && !test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
- test_bit(R5_Insync, &dev->flags)) {
- if (test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
- {
- PRINTK("Read_old stripe %llu block %d for Reconstruct\n",
- (unsigned long long)sh->sector, i);
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantread, &dev->flags);
- locked++;
- } else {
- PRINTK("Request delayed stripe %llu block %d for Reconstruct\n",
- (unsigned long long)sh->sector, i);
- set_bit(STRIPE_DELAYED, &sh->state);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- }
- }
- /* now if nothing is locked, and if we have enough data, we can start a write request */
- if (locked == 0 && rcw == 0 &&
- !test_bit(STRIPE_BIT_DELAY, &sh->state)) {
- if ( must_compute > 0 ) {
- /* We have failed blocks and need to compute them */
- switch ( failed ) {
- case 0: BUG();
- case 1: compute_block_1(sh, failed_num[0], 0); break;
- case 2: compute_block_2(sh, failed_num[0], failed_num[1]); break;
- default: BUG(); /* This request should have been failed? */
- }
- }
-
- PRINTK("Computing parity for stripe %llu\n", (unsigned long long)sh->sector);
- compute_parity(sh, RECONSTRUCT_WRITE);
- /* now every locked buffer is ready to be written */
- for (i=disks; i--;)
- if (test_bit(R5_LOCKED, &sh->dev[i].flags)) {
- PRINTK("Writing stripe %llu block %d\n",
- (unsigned long long)sh->sector, i);
- locked++;
- set_bit(R5_Wantwrite, &sh->dev[i].flags);
- }
- /* after a RECONSTRUCT_WRITE, the stripe MUST be in-sync */
- set_bit(STRIPE_INSYNC, &sh->state);
-
- if (test_and_clear_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
- atomic_dec(&conf->preread_active_stripes);
- if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD)
- md_wakeup_thread(conf->mddev->thread);
- }
- }
- }
-
- /* maybe we need to check and possibly fix the parity for this stripe
- * Any reads will already have been scheduled, so we just see if enough data
- * is available
- */
- if (syncing && locked == 0 && !test_bit(STRIPE_INSYNC, &sh->state)) {
- int update_p = 0, update_q = 0;
- struct r5dev *dev;
-
- set_bit(STRIPE_HANDLE, &sh->state);
-
- BUG_ON(failed>2);
- BUG_ON(uptodate < disks);
- /* Want to check and possibly repair P and Q.
- * However there could be one 'failed' device, in which
- * case we can only check one of them, possibly using the
- * other to generate missing data
- */
-
- /* If !tmp_page, we cannot do the calculations,
- * but as we have set STRIPE_HANDLE, we will soon be called
- * by stripe_handle with a tmp_page - just wait until then.
- */
- if (tmp_page) {
- if (failed == q_failed) {
- /* The only possible failed device holds 'Q', so it makes
- * sense to check P (If anything else were failed, we would
- * have used P to recreate it).
- */
- compute_block_1(sh, pd_idx, 1);
- if (!page_is_zero(sh->dev[pd_idx].page)) {
- compute_block_1(sh,pd_idx,0);
- update_p = 1;
- }
- }
- if (!q_failed && failed < 2) {
- /* q is not failed, and we didn't use it to generate
- * anything, so it makes sense to check it
- */
- memcpy(page_address(tmp_page),
- page_address(sh->dev[qd_idx].page),
- STRIPE_SIZE);
- compute_parity(sh, UPDATE_PARITY);
- if (memcmp(page_address(tmp_page),
- page_address(sh->dev[qd_idx].page),
- STRIPE_SIZE)!= 0) {
- clear_bit(STRIPE_INSYNC, &sh->state);
- update_q = 1;
- }
- }
- if (update_p || update_q) {
- conf->mddev->resync_mismatches += STRIPE_SECTORS;
- if (test_bit(MD_RECOVERY_CHECK, &conf->mddev->recovery))
- /* don't try to repair!! */
- update_p = update_q = 0;
- }
-
- /* now write out any block on a failed drive,
- * or P or Q if they need it
- */
-
- if (failed == 2) {
- dev = &sh->dev[failed_num[1]];
- locked++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
- if (failed >= 1) {
- dev = &sh->dev[failed_num[0]];
- locked++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
-
- if (update_p) {
- dev = &sh->dev[pd_idx];
- locked ++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
- if (update_q) {
- dev = &sh->dev[qd_idx];
- locked++;
- set_bit(R5_LOCKED, &dev->flags);
- set_bit(R5_Wantwrite, &dev->flags);
- }
- clear_bit(STRIPE_DEGRADED, &sh->state);
-
- set_bit(STRIPE_INSYNC, &sh->state);
- }
- }
-
- if (syncing && locked == 0 && test_bit(STRIPE_INSYNC, &sh->state)) {
- md_done_sync(conf->mddev, STRIPE_SECTORS,1);
- clear_bit(STRIPE_SYNCING, &sh->state);
- }
-
- /* If the failed drives are just a ReadError, then we might need
- * to progress the repair/check process
- */
- if (failed <= 2 && ! conf->mddev->ro)
- for (i=0; i<failed;i++) {
- dev = &sh->dev[failed_num[i]];
- if (test_bit(R5_ReadError, &dev->flags)
- && !test_bit(R5_LOCKED, &dev->flags)
- && test_bit(R5_UPTODATE, &dev->flags)
- ) {
- 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)) {
- int bytes = bi->bi_size;
-
- return_bi = bi->bi_next;
- bi->bi_next = NULL;
- bi->bi_size = 0;
- bi->bi_end_io(bi, bytes, 0);
- }
- for (i=disks; i-- ;) {
- int rw;
- struct bio *bi;
- mdk_rdev_t *rdev;
- if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
- rw = 1;
- else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
- rw = 0;
- else
- continue;
-
- bi = &sh->dev[i].req;
-
- bi->bi_rw = rw;
- if (rw)
- bi->bi_end_io = raid6_end_write_request;
- else
- bi->bi_end_io = raid6_end_read_request;
-
- rcu_read_lock();
- rdev = rcu_dereference(conf->disks[i].rdev);
- if (rdev && test_bit(Faulty, &rdev->flags))
- rdev = NULL;
- if (rdev)
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
-
- if (rdev) {
- if (syncing)
- md_sync_acct(rdev->bdev, STRIPE_SECTORS);
-
- bi->bi_bdev = rdev->bdev;
- PRINTK("for %llu schedule op %ld on disc %d\n",
- (unsigned long long)sh->sector, bi->bi_rw, i);
- atomic_inc(&sh->count);
- bi->bi_sector = sh->sector + rdev->data_offset;
- bi->bi_flags = 1 << BIO_UPTODATE;
- bi->bi_vcnt = 1;
- bi->bi_max_vecs = 1;
- bi->bi_idx = 0;
- bi->bi_io_vec = &sh->dev[i].vec;
- bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
- bi->bi_io_vec[0].bv_offset = 0;
- bi->bi_size = STRIPE_SIZE;
- bi->bi_next = NULL;
- if (rw == WRITE &&
- test_bit(R5_ReWrite, &sh->dev[i].flags))
- atomic_add(STRIPE_SECTORS, &rdev->corrected_errors);
- generic_make_request(bi);
- } else {
- if (rw == 1)
- set_bit(STRIPE_DEGRADED, &sh->state);
- PRINTK("skip op %ld on disc %d for sector %llu\n",
- bi->bi_rw, i, (unsigned long long)sh->sector);
- clear_bit(R5_LOCKED, &sh->dev[i].flags);
- set_bit(STRIPE_HANDLE, &sh->state);
- }
- }
-}
-
-static void raid6_activate_delayed(raid6_conf_t *conf)
-{
- if (atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD) {
- while (!list_empty(&conf->delayed_list)) {
- struct list_head *l = conf->delayed_list.next;
- struct stripe_head *sh;
- sh = list_entry(l, struct stripe_head, lru);
- list_del_init(l);
- clear_bit(STRIPE_DELAYED, &sh->state);
- if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
- atomic_inc(&conf->preread_active_stripes);
- list_add_tail(&sh->lru, &conf->handle_list);
- }
- }
-}
-
-static void activate_bit_delay(raid6_conf_t *conf)
-{
- /* device_lock is held */
- struct list_head head;
- list_add(&head, &conf->bitmap_list);
- list_del_init(&conf->bitmap_list);
- while (!list_empty(&head)) {
- struct stripe_head *sh = list_entry(head.next, struct stripe_head, lru);
- list_del_init(&sh->lru);
- atomic_inc(&sh->count);
- __release_stripe(conf, sh);
- }
-}
-
-static void unplug_slaves(mddev_t *mddev)
-{
- raid6_conf_t *conf = mddev_to_conf(mddev);
- int i;
-
- rcu_read_lock();
- for (i=0; i<mddev->raid_disks; i++) {
- 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);
- rcu_read_unlock();
-
- if (r_queue->unplug_fn)
- r_queue->unplug_fn(r_queue);
-
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- rcu_read_unlock();
-}
-
-static void raid6_unplug_device(request_queue_t *q)
-{
- mddev_t *mddev = q->queuedata;
- raid6_conf_t *conf = mddev_to_conf(mddev);
- unsigned long flags;
-
- spin_lock_irqsave(&conf->device_lock, flags);
-
- if (blk_remove_plug(q)) {
- conf->seq_flush++;
- raid6_activate_delayed(conf);
- }
- md_wakeup_thread(mddev->thread);
-
- spin_unlock_irqrestore(&conf->device_lock, flags);
-
- unplug_slaves(mddev);
-}
-
-static int raid6_issue_flush(request_queue_t *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- mddev_t *mddev = q->queuedata;
- raid6_conf_t *conf = mddev_to_conf(mddev);
- int i, ret = 0;
-
- rcu_read_lock();
- for (i=0; i<mddev->raid_disks && ret == 0; i++) {
- 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);
-
- if (!r_queue->issue_flush_fn)
- ret = -EOPNOTSUPP;
- else {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- ret = r_queue->issue_flush_fn(r_queue, bdev->bd_disk,
- error_sector);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- }
- rcu_read_unlock();
- return ret;
-}
-
-static inline void raid6_plug_device(raid6_conf_t *conf)
-{
- spin_lock_irq(&conf->device_lock);
- blk_plug_device(conf->mddev->queue);
- spin_unlock_irq(&conf->device_lock);
-}
-
-static int make_request (request_queue_t *q, struct bio * bi)
-{
- mddev_t *mddev = q->queuedata;
- raid6_conf_t *conf = mddev_to_conf(mddev);
- const unsigned int raid_disks = conf->raid_disks;
- const unsigned int data_disks = raid_disks - 2;
- unsigned int dd_idx, pd_idx;
- sector_t new_sector;
- sector_t logical_sector, last_sector;
- struct stripe_head *sh;
- const int rw = bio_data_dir(bi);
-
- if (unlikely(bio_barrier(bi))) {
- bio_endio(bi, bi->bi_size, -EOPNOTSUPP);
- return 0;
- }
-
- md_write_start(mddev, bi);
-
- disk_stat_inc(mddev->gendisk, ios[rw]);
- disk_stat_add(mddev->gendisk, sectors[rw], bio_sectors(bi));
-
- logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
- last_sector = bi->bi_sector + (bi->bi_size>>9);
-
- bi->bi_next = NULL;
- bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
-
- for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
- DEFINE_WAIT(w);
-
- new_sector = raid6_compute_sector(logical_sector,
- raid_disks, data_disks, &dd_idx, &pd_idx, conf);
-
- PRINTK("raid6: make_request, sector %llu logical %llu\n",
- (unsigned long long)new_sector,
- (unsigned long long)logical_sector);
-
- retry:
- prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
- sh = get_active_stripe(conf, new_sector, pd_idx, (bi->bi_rw&RWA_MASK));
- if (sh) {
- if (!add_stripe_bio(sh, bi, dd_idx, (bi->bi_rw&RW_MASK))) {
- /* Add failed due to overlap. Flush everything
- * and wait a while
- */
- raid6_unplug_device(mddev->queue);
- release_stripe(sh);
- schedule();
- goto retry;
- }
- finish_wait(&conf->wait_for_overlap, &w);
- raid6_plug_device(conf);
- handle_stripe(sh, NULL);
- release_stripe(sh);
- } else {
- /* cannot get stripe for read-ahead, just give-up */
- clear_bit(BIO_UPTODATE, &bi->bi_flags);
- finish_wait(&conf->wait_for_overlap, &w);
- break;
- }
-
- }
- spin_lock_irq(&conf->device_lock);
- if (--bi->bi_phys_segments == 0) {
- int bytes = bi->bi_size;
-
- if (rw == WRITE )
- md_write_end(mddev);
- bi->bi_size = 0;
- bi->bi_end_io(bi, bytes, 0);
- }
- spin_unlock_irq(&conf->device_lock);
- return 0;
-}
-
-/* FIXME go_faster isn't used */
-static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, int go_faster)
-{
- raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
- struct stripe_head *sh;
- int sectors_per_chunk = conf->chunk_size >> 9;
- sector_t x;
- unsigned long stripe;
- int chunk_offset;
- int dd_idx, pd_idx;
- sector_t first_sector;
- int raid_disks = conf->raid_disks;
- int data_disks = raid_disks - 2;
- sector_t max_sector = mddev->size << 1;
- int sync_blocks;
- int still_degraded = 0;
- int i;
-
- if (sector_nr >= max_sector) {
- /* just being told to finish up .. nothing much to do */
- unplug_slaves(mddev);
-
- if (mddev->curr_resync < max_sector) /* aborted */
- bitmap_end_sync(mddev->bitmap, mddev->curr_resync,
- &sync_blocks, 1);
- else /* completed sync */
- conf->fullsync = 0;
- bitmap_close_sync(mddev->bitmap);
-
- return 0;
- }
- /* if there are 2 or more failed drives and we are trying
- * to resync, then assert that we are finished, because there is
- * nothing we can do.
- */
- if (mddev->degraded >= 2 && test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- sector_t rv = (mddev->size << 1) - sector_nr;
- *skipped = 1;
- 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;
- *skipped = 1;
- return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */
- }
-
- x = sector_nr;
- chunk_offset = sector_div(x, sectors_per_chunk);
- stripe = x;
- BUG_ON(x != stripe);
-
- first_sector = raid6_compute_sector((sector_t)stripe*data_disks*sectors_per_chunk
- + chunk_offset, raid_disks, data_disks, &dd_idx, &pd_idx, conf);
- sh = get_active_stripe(conf, sector_nr, pd_idx, 1);
- if (sh == NULL) {
- sh = get_active_stripe(conf, sector_nr, pd_idx, 0);
- /* make sure we don't swamp the stripe cache if someone else
- * is trying to get access
- */
- schedule_timeout_uninterruptible(1);
- }
- /* Need to check if array will still be degraded after recovery/resync
- * We don't need to check the 'failed' flag as when that gets set,
- * recovery aborts.
- */
- for (i=0; i<mddev->raid_disks; i++)
- if (conf->disks[i].rdev == NULL)
- still_degraded = 1;
-
- bitmap_start_sync(mddev->bitmap, sector_nr, &sync_blocks, still_degraded);
-
- spin_lock(&sh->lock);
- set_bit(STRIPE_SYNCING, &sh->state);
- clear_bit(STRIPE_INSYNC, &sh->state);
- spin_unlock(&sh->lock);
-
- handle_stripe(sh, NULL);
- release_stripe(sh);
-
- return STRIPE_SECTORS;
-}
-
-/*
- * This is our raid6 kernel thread.
- *
- * We scan the hash table for stripes which can be handled now.
- * During the scan, completed stripes are saved for us by the interrupt
- * handler, so that they will not have to wait for our next wakeup.
- */
-static void raid6d (mddev_t *mddev)
-{
- struct stripe_head *sh;
- raid6_conf_t *conf = mddev_to_conf(mddev);
- int handled;
-
- PRINTK("+++ raid6d active\n");
-
- md_check_recovery(mddev);
-
- handled = 0;
- spin_lock_irq(&conf->device_lock);
- while (1) {
- struct list_head *first;
-
- if (conf->seq_flush - conf->seq_write > 0) {
- int seq = conf->seq_flush;
- spin_unlock_irq(&conf->device_lock);
- bitmap_unplug(mddev->bitmap);
- spin_lock_irq(&conf->device_lock);
- conf->seq_write = seq;
- activate_bit_delay(conf);
- }
-
- if (list_empty(&conf->handle_list) &&
- atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD &&
- !blk_queue_plugged(mddev->queue) &&
- !list_empty(&conf->delayed_list))
- raid6_activate_delayed(conf);
-
- if (list_empty(&conf->handle_list))
- break;
-
- first = conf->handle_list.next;
- sh = list_entry(first, struct stripe_head, lru);
-
- list_del_init(first);
- atomic_inc(&sh->count);
- BUG_ON(atomic_read(&sh->count)!= 1);
- spin_unlock_irq(&conf->device_lock);
-
- handled++;
- handle_stripe(sh, conf->spare_page);
- release_stripe(sh);
-
- spin_lock_irq(&conf->device_lock);
- }
- PRINTK("%d stripes handled\n", handled);
-
- spin_unlock_irq(&conf->device_lock);
-
- unplug_slaves(mddev);
-
- PRINTK("--- raid6d inactive\n");
-}
-
-static ssize_t
-raid6_show_stripe_cache_size(mddev_t *mddev, char *page)
-{
- raid6_conf_t *conf = mddev_to_conf(mddev);
- if (conf)
- return sprintf(page, "%d\n", conf->max_nr_stripes);
- else
- return 0;
-}
-
-static ssize_t
-raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
-{
- raid6_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
-raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
- raid6_show_stripe_cache_size,
- raid6_store_stripe_cache_size);
-
-static ssize_t
-stripe_cache_active_show(mddev_t *mddev, char *page)
-{
- raid6_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
-raid6_stripecache_active = __ATTR_RO(stripe_cache_active);
-
-static struct attribute *raid6_attrs[] = {
- &raid6_stripecache_size.attr,
- &raid6_stripecache_active.attr,
- NULL,
-};
-static struct attribute_group raid6_attrs_group = {
- .name = NULL,
- .attrs = raid6_attrs,
-};
-
-static int run(mddev_t *mddev)
-{
- raid6_conf_t *conf;
- int raid_disk, memory;
- mdk_rdev_t *rdev;
- struct disk_info *disk;
- struct list_head *tmp;
-
- if (mddev->level != 6) {
- PRINTK("raid6: %s: raid level not set to 6 (%d)\n", mdname(mddev), mddev->level);
- return -EIO;
- }
-
- mddev->private = kzalloc(sizeof (raid6_conf_t), GFP_KERNEL);
- if ((conf = mddev->private) == NULL)
- goto abort;
- conf->disks = kzalloc(mddev->raid_disks * sizeof(struct disk_info),
- GFP_KERNEL);
- if (!conf->disks)
- goto abort;
-
- conf->mddev = mddev;
-
- if ((conf->stripe_hashtbl = kzalloc(PAGE_SIZE, GFP_KERNEL)) == NULL)
- goto abort;
-
- conf->spare_page = alloc_page(GFP_KERNEL);
- if (!conf->spare_page)
- goto abort;
-
- spin_lock_init(&conf->device_lock);
- init_waitqueue_head(&conf->wait_for_stripe);
- init_waitqueue_head(&conf->wait_for_overlap);
- INIT_LIST_HEAD(&conf->handle_list);
- INIT_LIST_HEAD(&conf->delayed_list);
- INIT_LIST_HEAD(&conf->bitmap_list);
- INIT_LIST_HEAD(&conf->inactive_list);
- atomic_set(&conf->active_stripes, 0);
- atomic_set(&conf->preread_active_stripes, 0);
-
- PRINTK("raid6: run(%s) called.\n", mdname(mddev));
-
- ITERATE_RDEV(mddev,rdev,tmp) {
- raid_disk = rdev->raid_disk;
- if (raid_disk >= mddev->raid_disks
- || raid_disk < 0)
- continue;
- disk = conf->disks + raid_disk;
-
- disk->rdev = rdev;
-
- 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),
- raid_disk);
- conf->working_disks++;
- }
- }
-
- conf->raid_disks = mddev->raid_disks;
-
- /*
- * 0 for a fully functional array, 1 or 2 for a degraded array.
- */
- mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks;
- conf->mddev = mddev;
- conf->chunk_size = mddev->chunk_size;
- conf->level = mddev->level;
- conf->algorithm = mddev->layout;
- conf->max_nr_stripes = NR_STRIPES;
-
- /* device size must be a multiple of chunk size */
- mddev->size &= ~(mddev->chunk_size/1024 -1);
- mddev->resync_max_sectors = mddev->size << 1;
-
- if (conf->raid_disks < 4) {
- printk(KERN_ERR "raid6: not enough configured devices for %s (%d, minimum 4)\n",
- mdname(mddev), conf->raid_disks);
- goto abort;
- }
- if (!conf->chunk_size || conf->chunk_size % 4) {
- printk(KERN_ERR "raid6: invalid chunk size %d for %s\n",
- conf->chunk_size, mdname(mddev));
- goto abort;
- }
- if (conf->algorithm > ALGORITHM_RIGHT_SYMMETRIC) {
- printk(KERN_ERR
- "raid6: unsupported parity algorithm %d for %s\n",
- conf->algorithm, mdname(mddev));
- goto abort;
- }
- if (mddev->degraded > 2) {
- printk(KERN_ERR "raid6: not enough operational devices for %s"
- " (%d/%d failed)\n",
- mdname(mddev), conf->failed_disks, conf->raid_disks);
- goto abort;
- }
-
- if (mddev->degraded > 0 &&
- mddev->recovery_cp != MaxSector) {
- if (mddev->ok_start_degraded)
- printk(KERN_WARNING "raid6: starting dirty degraded array:%s"
- "- data corruption possible.\n",
- mdname(mddev));
- else {
- printk(KERN_ERR "raid6: cannot start dirty degraded array"
- " for %s\n", mdname(mddev));
- goto abort;
- }
- }
-
- {
- mddev->thread = md_register_thread(raid6d, mddev, "%s_raid6");
- if (!mddev->thread) {
- printk(KERN_ERR
- "raid6: couldn't allocate thread for %s\n",
- mdname(mddev));
- goto abort;
- }
- }
-
- memory = conf->max_nr_stripes * (sizeof(struct stripe_head) +
- conf->raid_disks * ((sizeof(struct bio) + PAGE_SIZE))) / 1024;
- if (grow_stripes(conf, conf->max_nr_stripes)) {
- printk(KERN_ERR
- "raid6: couldn't allocate %dkB for buffers\n", memory);
- shrink_stripes(conf);
- md_unregister_thread(mddev->thread);
- goto abort;
- } else
- printk(KERN_INFO "raid6: allocated %dkB for %s\n",
- memory, mdname(mddev));
-
- if (mddev->degraded == 0)
- printk(KERN_INFO "raid6: raid level %d set %s active with %d out of %d"
- " devices, algorithm %d\n", conf->level, mdname(mddev),
- mddev->raid_disks-mddev->degraded, mddev->raid_disks,
- conf->algorithm);
- else
- printk(KERN_ALERT "raid6: raid level %d set %s active with %d"
- " out of %d devices, algorithm %d\n", conf->level,
- mdname(mddev), mddev->raid_disks - mddev->degraded,
- mddev->raid_disks, conf->algorithm);
-
- print_raid6_conf(conf);
-
- /* read-ahead size must cover two whole stripes, which is
- * 2 * (n-2) * chunksize where 'n' is the number of raid devices
- */
- {
- int stripe = (mddev->raid_disks-2) * mddev->chunk_size
- / PAGE_SIZE;
- if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
- mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
- }
-
- /* Ok, everything is just fine now */
- sysfs_create_group(&mddev->kobj, &raid6_attrs_group);
-
- mddev->array_size = mddev->size * (mddev->raid_disks - 2);
-
- mddev->queue->unplug_fn = raid6_unplug_device;
- mddev->queue->issue_flush_fn = raid6_issue_flush;
- return 0;
-abort:
- if (conf) {
- print_raid6_conf(conf);
- safe_put_page(conf->spare_page);
- kfree(conf->stripe_hashtbl);
- kfree(conf->disks);
- kfree(conf);
- }
- mddev->private = NULL;
- printk(KERN_ALERT "raid6: failed to run raid set %s\n", mdname(mddev));
- return -EIO;
-}
-
-
-
-static int stop (mddev_t *mddev)
-{
- raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
-
- md_unregister_thread(mddev->thread);
- mddev->thread = NULL;
- shrink_stripes(conf);
- kfree(conf->stripe_hashtbl);
- blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
- sysfs_remove_group(&mddev->kobj, &raid6_attrs_group);
- kfree(conf);
- mddev->private = NULL;
- return 0;
-}
-
-#if RAID6_DUMPSTATE
-static void print_sh (struct seq_file *seq, struct stripe_head *sh)
-{
- int i;
-
- seq_printf(seq, "sh %llu, pd_idx %d, state %ld.\n",
- (unsigned long long)sh->sector, sh->pd_idx, sh->state);
- seq_printf(seq, "sh %llu, count %d.\n",
- (unsigned long long)sh->sector, atomic_read(&sh->count));
- seq_printf(seq, "sh %llu, ", (unsigned long long)sh->sector);
- for (i = 0; i < sh->raid_conf->raid_disks; i++) {
- seq_printf(seq, "(cache%d: %p %ld) ",
- i, sh->dev[i].page, sh->dev[i].flags);
- }
- seq_printf(seq, "\n");
-}
-
-static void printall (struct seq_file *seq, raid6_conf_t *conf)
-{
- struct stripe_head *sh;
- struct hlist_node *hn;
- int i;
-
- spin_lock_irq(&conf->device_lock);
- for (i = 0; i < NR_HASH; i++) {
- sh = conf->stripe_hashtbl[i];
- hlist_for_each_entry(sh, hn, &conf->stripe_hashtbl[i], hash) {
- if (sh->raid_conf != conf)
- continue;
- print_sh(seq, sh);
- }
- }
- spin_unlock_irq(&conf->device_lock);
-}
-#endif
-
-static void status (struct seq_file *seq, mddev_t *mddev)
-{
- raid6_conf_t *conf = (raid6_conf_t *) mddev->private;
- int i;
-
- seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
- seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks);
- for (i = 0; i < conf->raid_disks; i++)
- seq_printf (seq, "%s",
- conf->disks[i].rdev &&
- test_bit(In_sync, &conf->disks[i].rdev->flags) ? "U" : "_");
- seq_printf (seq, "]");
-#if RAID6_DUMPSTATE
- seq_printf (seq, "\n");
- printall(seq, conf);
-#endif
-}
-
-static void print_raid6_conf (raid6_conf_t *conf)
-{
- int i;
- struct disk_info *tmp;
-
- printk("RAID6 conf printout:\n");
- if (!conf) {
- printk("(conf==NULL)\n");
- return;
- }
- printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks,
- conf->working_disks, conf->failed_disks);
-
- for (i = 0; i < conf->raid_disks; i++) {
- char b[BDEVNAME_SIZE];
- tmp = conf->disks + i;
- if (tmp->rdev)
- printk(" disk %d, o:%d, dev:%s\n",
- i, !test_bit(Faulty, &tmp->rdev->flags),
- bdevname(tmp->rdev->bdev,b));
- }
-}
-
-static int raid6_spare_active(mddev_t *mddev)
-{
- int i;
- raid6_conf_t *conf = mddev->private;
- struct disk_info *tmp;
-
- for (i = 0; i < conf->raid_disks; i++) {
- tmp = conf->disks + i;
- if (tmp->rdev
- && !test_bit(Faulty, &tmp->rdev->flags)
- && !test_bit(In_sync, &tmp->rdev->flags)) {
- mddev->degraded--;
- conf->failed_disks--;
- conf->working_disks++;
- set_bit(In_sync, &tmp->rdev->flags);
- }
- }
- print_raid6_conf(conf);
- return 0;
-}
-
-static int raid6_remove_disk(mddev_t *mddev, int number)
-{
- raid6_conf_t *conf = mddev->private;
- int err = 0;
- mdk_rdev_t *rdev;
- struct disk_info *p = conf->disks + number;
-
- print_raid6_conf(conf);
- rdev = p->rdev;
- if (rdev) {
- if (test_bit(In_sync, &rdev->flags) ||
- atomic_read(&rdev->nr_pending)) {
- err = -EBUSY;
- goto abort;
- }
- p->rdev = NULL;
- synchronize_rcu();
- if (atomic_read(&rdev->nr_pending)) {
- /* lost the race, try later */
- err = -EBUSY;
- p->rdev = rdev;
- }
- }
-
-abort:
-
- print_raid6_conf(conf);
- return err;
-}
-
-static int raid6_add_disk(mddev_t *mddev, mdk_rdev_t *rdev)
-{
- raid6_conf_t *conf = mddev->private;
- int found = 0;
- int disk;
- struct disk_info *p;
-
- if (mddev->degraded > 2)
- /* no point adding a device */
- return 0;
- /*
- * find the disk ... but prefer rdev->saved_raid_disk
- * if possible.
- */
- if (rdev->saved_raid_disk >= 0 &&
- conf->disks[rdev->saved_raid_disk].rdev == NULL)
- disk = rdev->saved_raid_disk;
- else
- disk = 0;
- for ( ; disk < mddev->raid_disks; disk++)
- if ((p=conf->disks + disk)->rdev == NULL) {
- clear_bit(In_sync, &rdev->flags);
- rdev->raid_disk = disk;
- found = 1;
- if (rdev->saved_raid_disk != disk)
- conf->fullsync = 1;
- rcu_assign_pointer(p->rdev, rdev);
- break;
- }
- print_raid6_conf(conf);
- return found;
-}
-
-static int raid6_resize(mddev_t *mddev, sector_t sectors)
-{
- /* no resync is happening, and there is enough space
- * on all devices, so we can resize.
- * We need to make sure resync covers any new space.
- * If the array is shrinking we should possibly wait until
- * any io in the removed space completes, but it hardly seems
- * worth it.
- */
- sectors &= ~((sector_t)mddev->chunk_size/512 - 1);
- mddev->array_size = (sectors * (mddev->raid_disks-2))>>1;
- set_capacity(mddev->gendisk, mddev->array_size << 1);
- mddev->changed = 1;
- if (sectors/2 > mddev->size && mddev->recovery_cp == MaxSector) {
- mddev->recovery_cp = mddev->size << 1;
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- }
- mddev->size = sectors /2;
- mddev->resync_max_sectors = sectors;
- return 0;
-}
-
-static void raid6_quiesce(mddev_t *mddev, int state)
-{
- raid6_conf_t *conf = mddev_to_conf(mddev);
-
- switch(state) {
- case 1: /* stop all writes */
- spin_lock_irq(&conf->device_lock);
- conf->quiesce = 1;
- wait_event_lock_irq(conf->wait_for_stripe,
- atomic_read(&conf->active_stripes) == 0,
- conf->device_lock, /* nothing */);
- spin_unlock_irq(&conf->device_lock);
- break;
-
- case 0: /* re-enable writes */
- spin_lock_irq(&conf->device_lock);
- conf->quiesce = 0;
- wake_up(&conf->wait_for_stripe);
- spin_unlock_irq(&conf->device_lock);
- break;
- }
-}
-
-static struct mdk_personality raid6_personality =
-{
- .name = "raid6",
- .level = 6,
- .owner = THIS_MODULE,
- .make_request = make_request,
- .run = run,
- .stop = stop,
- .status = status,
- .error_handler = error,
- .hot_add_disk = raid6_add_disk,
- .hot_remove_disk= raid6_remove_disk,
- .spare_active = raid6_spare_active,
- .sync_request = sync_request,
- .resize = raid6_resize,
- .quiesce = raid6_quiesce,
-};
-
-static int __init raid6_init(void)
-{
- int e;
-
- e = raid6_select_algo();
- if ( e )
- return e;
-
- return register_md_personality(&raid6_personality);
-}
-
-static void raid6_exit (void)
-{
- unregister_md_personality(&raid6_personality);
-}
-
-module_init(raid6_init);
-module_exit(raid6_exit);
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("md-personality-8"); /* RAID6 */
-MODULE_ALIAS("md-raid6");
-MODULE_ALIAS("md-level-6");
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 344d83aae3e..ed4aa4e7912 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -25,7 +25,7 @@ config VIDEO_DEV
module will be called videodev.
config VIDEO_V4L1
- boolean "Enable Video For Linux API 1 (DEPRECATED)"
+ bool "Enable Video For Linux API 1 (DEPRECATED)"
depends on VIDEO_DEV
select VIDEO_V4L1_COMPAT
default y
@@ -36,7 +36,7 @@ config VIDEO_V4L1
If you are unsure as to whether this is required, answer Y.
config VIDEO_V4L1_COMPAT
- boolean "Enable Video For Linux API 1 compatible Layer"
+ bool "Enable Video For Linux API 1 compatible Layer"
depends on VIDEO_DEV
default y
---help---
@@ -53,7 +53,7 @@ config VIDEO_V4L1_COMPAT
If you are unsure as to whether this is required, answer Y.
config VIDEO_V4L2
- tristate
+ bool
default y
source "drivers/media/video/Kconfig"
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 61b89617a96..8e744823064 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,5 @@
saa7146-objs := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index 397cff8b345..8eaa88fd8b9 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -269,4 +269,3 @@ EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
* c-basic-offset: 8
* End:
*/
-
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index a294d5c2c73..ca98d947894 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -618,7 +618,7 @@ IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = {
EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x3a ] = KEY_0,
[ 0x31 ] = KEY_1,
[ 0x32 ] = KEY_2,
@@ -670,7 +670,7 @@ IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
[ 0x27 ] = KEY_RECORD,
};
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
[ 0x0f ] = KEY_0,
@@ -1263,34 +1263,51 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
[ 0x0f ] = KEY_9,
[ 0x00 ] = KEY_POWER,
- [ 0x02 ] = KEY_TUNER, /* TV/FM */
- [ 0x1e ] = KEY_VIDEO,
+ [ 0x1b ] = KEY_AUDIO, /* Audio Source */
+ [ 0x02 ] = KEY_TUNER, /* TV/FM, not on Y0400052 */
+ [ 0x1e ] = KEY_VIDEO, /* Video Source */
+ [ 0x16 ] = KEY_INFO, /* Display information */
[ 0x04 ] = KEY_VOLUMEUP,
[ 0x08 ] = KEY_VOLUMEDOWN,
[ 0x0c ] = KEY_CHANNELUP,
[ 0x10 ] = KEY_CHANNELDOWN,
[ 0x03 ] = KEY_ZOOM, /* fullscreen */
- [ 0x1f ] = KEY_SUBTITLE, /* closed caption/teletext */
+ [ 0x1f ] = KEY_TEXT, /* closed caption/teletext */
[ 0x20 ] = KEY_SLEEP,
+ [ 0x29 ] = KEY_CLEAR, /* boss key */
[ 0x14 ] = KEY_MUTE,
[ 0x2b ] = KEY_RED,
[ 0x2c ] = KEY_GREEN,
[ 0x2d ] = KEY_YELLOW,
[ 0x2e ] = KEY_BLUE,
- [ 0x18 ] = KEY_KPPLUS, /* fine tune + */
- [ 0x19 ] = KEY_KPMINUS, /* fine tune - */
+ [ 0x18 ] = KEY_KPPLUS, /* fine tune + , not on Y040052 */
+ [ 0x19 ] = KEY_KPMINUS, /* fine tune - , not on Y040052 */
+ [ 0x2a ] = KEY_MEDIA, /* PIP (Picture in picture */
[ 0x21 ] = KEY_DOT,
[ 0x13 ] = KEY_ENTER,
- [ 0x22 ] = KEY_BACK,
+ [ 0x11 ] = KEY_LAST, /* Recall (last channel */
+ [ 0x22 ] = KEY_PREVIOUS,
[ 0x23 ] = KEY_PLAYPAUSE,
[ 0x24 ] = KEY_NEXT,
+ [ 0x25 ] = KEY_ARCHIVE, /* Time Shifting */
[ 0x26 ] = KEY_STOP,
- [ 0x27 ] = KEY_RECORD
+ [ 0x27 ] = KEY_RECORD,
+ [ 0x28 ] = KEY_SAVE, /* Screenshot */
+ [ 0x2f ] = KEY_MENU,
+ [ 0x30 ] = KEY_CANCEL,
+ [ 0x31 ] = KEY_CHANNEL, /* Channel Surf */
+ [ 0x32 ] = KEY_SUBTITLE,
+ [ 0x33 ] = KEY_LANGUAGE,
+ [ 0x34 ] = KEY_REWIND,
+ [ 0x35 ] = KEY_FASTFORWARD,
+ [ 0x36 ] = KEY_TV,
+ [ 0x37 ] = KEY_RADIO, /* FM */
+ [ 0x38 ] = KEY_DVD
};
EXPORT_SYMBOL_GPL(ir_codes_winfast);
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
[ 0x59 ] = KEY_MUTE,
[ 0x4a ] = KEY_POWER,
@@ -1348,7 +1365,7 @@ IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
[ 0x0a ] = KEY_BACKSPACE,
};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
/* Hauppauge: the newer, gray remotes (seems there are multiple
* slightly different versions), shipped with cx88+ivtv cards.
@@ -1413,3 +1430,46 @@ IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
+IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
+ [ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+ [ 0x2a ] = KEY_FRONT,
+
+ [ 0x3e ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x06 ] = KEY_3,
+ [ 0x0a ] = KEY_4,
+ [ 0x0e ] = KEY_5,
+ [ 0x12 ] = KEY_6,
+ [ 0x16 ] = KEY_7,
+ [ 0x1a ] = KEY_8,
+ [ 0x1e ] = KEY_9,
+ [ 0x3a ] = KEY_0,
+ [ 0x22 ] = KEY_NUMLOCK, /* -/-- */
+ [ 0x20 ] = KEY_REFRESH,
+
+ [ 0x03 ] = KEY_BRIGHTNESSDOWN,
+ [ 0x28 ] = KEY_AUDIO,
+ [ 0x3c ] = KEY_UP,
+ [ 0x3f ] = KEY_LEFT,
+ [ 0x2e ] = KEY_MUTE,
+ [ 0x3b ] = KEY_RIGHT,
+ [ 0x00 ] = KEY_DOWN,
+ [ 0x07 ] = KEY_BRIGHTNESSUP,
+ [ 0x2c ] = KEY_TEXT,
+
+ [ 0x37 ] = KEY_RECORD,
+ [ 0x17 ] = KEY_PLAY,
+ [ 0x13 ] = KEY_PAUSE,
+ [ 0x26 ] = KEY_STOP,
+ [ 0x18 ] = KEY_FASTFORWARD,
+ [ 0x14 ] = KEY_REWIND,
+ [ 0x33 ] = KEY_ZOOM,
+ [ 0x32 ] = KEY_KEYBOARD,
+ [ 0x30 ] = KEY_GOTO, /* Pointing arrow */
+ [ 0x36 ] = KEY_MACRO, /* Maximize/Minimize (yellow) */
+ [ 0x0b ] = KEY_RADIO,
+ [ 0x10 ] = KEY_POWER,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_npgtech);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 8cdd4d265ff..b88451e33c0 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -363,7 +363,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
saa7146_write(dev, MC2, 0xf8000000);
/* request an interrupt for the saa7146 */
- err = request_irq(pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT,
+ err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,
dev->name, dev);
if (err < 0) {
ERR(("request_irq() failed.\n"));
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 523ab3851c7..0027acc5b8e 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -501,6 +501,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
int saa7146_vv_release(struct saa7146_dev* dev)
{
@@ -515,6 +516,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
char *name, int type)
@@ -553,6 +555,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
*vid = vfd;
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_register_device);
int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
{
@@ -571,6 +574,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
static int __init saa7146_vv_init_module(void)
{
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index 33bec8a6843..d2905720eb7 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -158,7 +158,7 @@ static int calculate_h_scale_registers(struct saa7146_dev *dev,
}
/* the horizontal scaling increment controls the UV filter
- to reduce the bandwith to improve the display quality,
+ to reduce the bandwidth to improve the display quality,
so set it ... */
if ( xsci == 0x400)
pfuv = 0x00;
@@ -641,6 +641,7 @@ void saa7146_set_hps_source_and_sync(struct saa7146_dev *dev, int source, int sy
vv->current_hps_source = source;
vv->current_hps_sync = sync;
}
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
int saa7146_enable_overlay(struct saa7146_fh *fh)
{
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index e7079d1bd53..7e0cedc557d 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -318,6 +318,7 @@ int saa7146_start_preview(struct saa7146_fh *fh)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
int saa7146_stop_preview(struct saa7146_fh *fh)
{
@@ -352,6 +353,7 @@ int saa7146_stop_preview(struct saa7146_fh *fh)
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
{
@@ -1188,6 +1190,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
}
return err;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
@@ -1216,6 +1219,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int
mutex_unlock(&q->lock);
return 0;
}
+#endif
default:
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
saa7146_video_do_ioctl);
diff --git a/drivers/media/common/saa7146_vv_ksyms.c b/drivers/media/common/saa7146_vv_ksyms.c
deleted file mode 100644
index 62226eb4753..00000000000
--- a/drivers/media/common/saa7146_vv_ksyms.c
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <linux/module.h>
-#include <media/saa7146_vv.h>
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index d7f1fd5b7b0..49a06fc54c5 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -1,6 +1,7 @@
config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
depends on DVB_CORE && I2C
+ select DVB_PLL
select DVB_STV0299
select DVB_MT352
select DVB_MT312
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index b3dd0603cd9..5a6c4fe249e 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -8,7 +8,6 @@
#ifndef __FLEXCOP_COMMON_H__
#define __FLEXCOP_COMMON_H__
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/mutex.h>
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 9c7f122826e..3be87c72e37 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -14,6 +14,7 @@
#include "stv0297.h"
#include "mt312.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
#include "dvb-pll.h"
/* lnb control */
@@ -166,11 +167,12 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate,
return 0;
}
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct flexcop_device *fc = fe->dvb->priv;
div = params->frequency / 125;
@@ -181,8 +183,11 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter
if (params->frequency < 1500000) buf[3] |= 0x10;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
return -EIO;
+ }
return 0;
}
@@ -241,7 +246,6 @@ static struct stv0299_config samsung_tbmu24112_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
- .pll_set = samsung_tbmu24112_pll_set,
};
/* dvb-t mt352 */
@@ -264,11 +268,14 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
+ if (buf_len < 5)
+ return -EINVAL;
+
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
@@ -276,19 +283,18 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front
if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
- pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+ pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = 0xcc;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = samsung_tdtc9251dh0_demod_init,
- .pll_set = samsung_tdtc9251dh0_pll_set,
};
static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
@@ -297,56 +303,21 @@ 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)
+static int lgdt3303_tuner_set_params(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;
+ return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
}
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 nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a,
- .pll_address = 0xc2,
- .pll_desc = &dvb_pll_samsung_tbmv,
};
static struct bcm3510_config air2pc_atsc_first_gen_config = {
@@ -354,7 +325,7 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = {
.request_firmware = flexcop_fe_request_firmware,
};
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
@@ -371,6 +342,8 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
if (params->frequency < 1550000)
buf[3] |= 0x02;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -379,9 +352,52 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d
static struct mt312_config skystar23_samsung_tbdu18132_config = {
.demod_address = 0x0e,
- .pll_set = skystar23_samsung_tbdu18132_pll_set,
};
+static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ u8 buf[4];
+ u16 div;
+ int ret;
+
+/* 62.5 kHz * 10 */
+#define REF_FREQ 625
+#define FREQ_OFFSET 36125
+
+ div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz
+
+ buf[0] = (u8)( div >> 8) & 0x7f;
+ buf[1] = (u8) div & 0xff;
+
+/* F(osc) = N * Reference Freq. (62.5 kHz)
+ * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
+ * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
+ * byte 4 : 1 * * AGD R3 R2 R1 R0
+ * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
+ buf[2] = 0x95;
+
+// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
+// 47 - 153 0 * 0 0 0 0 0 1 0x01
+// 153 - 430 0 * 0 0 0 0 1 0 0x02
+// 430 - 822 0 * 0 0 1 0 0 0 0x08
+// 822 - 862 1 * 0 0 1 0 0 0 0x88
+
+ if (fep->frequency <= 153000000) buf[3] = 0x01;
+ else if (fep->frequency <= 430000000) buf[3] = 0x02;
+ else if (fep->frequency <= 822000000) buf[3] = 0x08;
+ else buf[3] = 0x88;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
+ ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
+ deb_tuner("tuner write returned: %d\n",ret);
+
+ return 0;
+}
static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x01,
@@ -490,7 +506,9 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
ops->set_voltage = flexcop_set_voltage;
@@ -503,16 +521,19 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
fc->dev_type = FC_AIR_DVB;
+ fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
} else
/* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
+ dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
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;
+ fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
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 */
@@ -523,11 +544,14 @@ int flexcop_frontend_init(struct flexcop_device *fc)
/* try the cable dvb (stv0297) */
if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_CABLE;
+ fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
} else
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
@@ -547,7 +571,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else {
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
if (ops->release != NULL)
ops->release(fc->fe);
fc->fe = NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 9bc40bdcc28..eb2e6432c8c 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -242,19 +242,16 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
return ret;
- if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
- goto dma1_free;
+ if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+ flexcop_dma_free(&fc_pci->dma[0]);
+ return ret;
+ }
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
fc_pci->init_state |= FC_PCI_DMA_INIT;
- goto success;
-dma1_free:
- flexcop_dma_free(&fc_pci->dma[0]);
-
-success:
return ret;
}
@@ -297,13 +294,13 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
pci_set_drvdata(fc_pci->pdev, fc_pci);
if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
- SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
+ IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
goto err_pci_iounmap;
spin_lock_init(&fc_pci->irq_lock);
fc_pci->init_state |= FC_PCI_INIT;
- goto success;
+ return ret;
err_pci_iounmap:
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
@@ -312,8 +309,6 @@ err_pci_release_regions:
pci_release_regions(fc_pci->pdev);
err_pci_disable_device:
pci_disable_device(fc_pci->pdev);
-
-success:
return ret;
}
@@ -378,14 +373,14 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
- goto success;
+ return ret;
+
err_fc_exit:
flexcop_device_exit(fc);
err_pci_exit:
flexcop_pci_exit(fc_pci);
err_kfree:
flexcop_device_kfree(fc);
-success:
return ret;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 06ec9fff0ec..515954f96c9 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -433,11 +433,10 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
- ret = 0;
- goto success;
+ return 0;
+
urb_error:
flexcop_usb_transfer_exit(fc_usb);
-success:
return ret;
}
@@ -515,15 +514,14 @@ static int flexcop_usb_probe(struct usb_interface *intf,
goto err_fc_exit;
info("%s successfully initialized and connected.",DRIVER_NAME);
- ret = 0;
- goto success;
+ return 0;
+
err_fc_exit:
flexcop_device_exit(fc);
err_usb_exit:
flexcop_usb_exit(fc_usb);
err_kfree:
flexcop_device_kfree(fc);
-success:
return ret;
}
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 56ba5247067..29ec4183118 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -67,7 +67,7 @@ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
static int flexcop_dvb_init(struct flexcop_device *fc)
{
int ret;
- if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+ if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
err("error registering DVB adapter");
return ret;
}
@@ -116,7 +116,7 @@ static int flexcop_dvb_init(struct flexcop_device *fc)
dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
fc->init_state |= FC_STATE_DVB_INIT;
- goto success;
+ return 0;
err_connect_frontend:
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
@@ -129,9 +129,6 @@ err_dmx_dev:
err_dmx:
dvb_unregister_adapter(&fc->dvb_adapter);
return ret;
-
-success:
- return 0;
}
static void flexcop_dvb_exit(struct flexcop_device *fc)
@@ -279,11 +276,10 @@ int flexcop_device_initialize(struct flexcop_device *fc)
flexcop_device_name(fc,"initialization of","complete");
- ret = 0;
- goto success;
+ return 0;
+
error:
flexcop_device_exit(fc);
-success:
return ret;
}
EXPORT_SYMBOL(flexcop_device_initialize);
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index f394002118f..7d0ee1ab290 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -1,6 +1,7 @@
config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
+ select DVB_PLL
select DVB_MT352
select DVB_SP887X
select DVB_NXT6000
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 5500f8a0ffe..755822ee6e9 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -63,8 +63,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off).");
int bt878_num;
struct bt878 bt878[BT878_MAX];
-EXPORT_SYMBOL(bt878_debug);
-EXPORT_SYMBOL(bt878_verbose);
EXPORT_SYMBOL(bt878_num);
EXPORT_SYMBOL(bt878);
@@ -393,7 +391,9 @@ static struct cards card_list[] __devinitdata = {
{ 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" },
- { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
+ { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
+ { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
+
{ 0, -1, NULL }
};
@@ -417,6 +417,11 @@ static int __devinit bt878_probe(struct pci_dev *dev,
printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
bt878_num);
+ if (bt878_num >= BT878_MAX) {
+ printk(KERN_ERR "bt878: Too many devices inserted\n");
+ result = -ENOMEM;
+ goto fail0;
+ }
if (pci_enable_device(dev))
return -EIO;
@@ -483,7 +488,7 @@ static int __devinit bt878_probe(struct pci_dev *dev,
btwrite(0, BT848_INT_MASK);
result = request_irq(bt->irq, bt878_irq,
- SA_SHIRQ | SA_INTERRUPT, "bt878",
+ IRQF_SHARED | IRQF_DISABLED, "bt878",
(void *) bt);
if (result == -EINVAL) {
printk(KERN_ERR "bt878(%d): Bad irq number or handler\n",
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 1cfa5e5035d..06ac899a9a2 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -38,6 +38,10 @@ static unsigned int dst_addons;
module_param(dst_addons, int, 0644);
MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
#define HAS_LOCK 1
#define ATTEMPT_TUNE 2
#define HAS_POWER 4
@@ -47,20 +51,24 @@ MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
#define DST_INFO 2
#define DST_DEBUG 3
-#define dprintk(x, y, z, format, arg...) do { \
- if (z) { \
- if ((x > DST_ERROR) && (x > y)) \
- printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_NOTICE) && (x > y)) \
- printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_INFO) && (x > y)) \
- printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_DEBUG) && (x > y)) \
- printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \
- } else { \
- if (x > y) \
- printk(format, ##arg); \
- } \
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > DST_ERROR) && (x > y)) \
+ printk(KERN_ERR "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_INFO) && (x > y)) \
+ printk(KERN_INFO "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ##arg); \
+ } \
} while(0)
@@ -110,7 +118,7 @@ int dst_gpio_inb(struct dst_state *state, u8 *result)
*result = 0;
if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
- dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err);
+ dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
return -EREMOTEIO;
}
*result = (u8) rd_packet.rd.value;
@@ -363,6 +371,17 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
state->tx_tuna[2] = (freq >> 16) & 0xff;
state->tx_tuna[3] = (freq >> 8) & 0xff;
state->tx_tuna[4] = (u8) freq;
+ } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+ freq = freq / 1000;
+ if (freq < 51000 || freq > 858000)
+ return -EINVAL;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
+ state->tx_tuna[5] = 0x00; /* ATSC */
+ state->tx_tuna[6] = 0x00;
+ if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+ state->tx_tuna[7] = 0x00; /* Digital */
} else
return -EINVAL;
@@ -374,7 +393,7 @@ static int dst_set_bandwidth(struct dst_state *state, fe_bandwidth_t bandwidth)
state->bandwidth = bandwidth;
if (state->dst_type != DST_TYPE_IS_TERR)
- return 0;
+ return -EOPNOTSUPP;
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
@@ -443,37 +462,49 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate)
state->symbol_rate = srate;
if (state->dst_type == DST_TYPE_IS_TERR) {
- return 0;
+ return -EOPNOTSUPP;
}
dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
srate /= 1000;
- if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
- sval = srate;
- sval <<= 20;
- do_div(sval, 88000);
- symcalc = (u32) sval;
- dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
- state->tx_tuna[5] = (u8) (symcalc >> 12);
- state->tx_tuna[6] = (u8) (symcalc >> 4);
- state->tx_tuna[7] = (u8) (symcalc << 4);
- } else {
- state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
- state->tx_tuna[6] = (u8) (srate >> 8);
- state->tx_tuna[7] = (u8) srate;
- }
- state->tx_tuna[8] &= ~0x20;
- if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
- if (srate > 8000)
- state->tx_tuna[8] |= 0x20;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+ sval = srate;
+ sval <<= 20;
+ do_div(sval, 88000);
+ symcalc = (u32) sval;
+ dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+ state->tx_tuna[5] = (u8) (symcalc >> 12);
+ state->tx_tuna[6] = (u8) (symcalc >> 4);
+ state->tx_tuna[7] = (u8) (symcalc << 4);
+ } else {
+ state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+ state->tx_tuna[6] = (u8) (srate >> 8);
+ state->tx_tuna[7] = (u8) srate;
+ }
+ state->tx_tuna[8] &= ~0x20;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+ if (srate > 8000)
+ state->tx_tuna[8] |= 0x20;
+ }
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+ if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+ state->tx_tuna[5] = (u8) (srate >> 8);
+ state->tx_tuna[6] = (u8) srate;
+ state->tx_tuna[7] = 0x00;
+ } else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+ state->tx_tuna[5] = 0x00;
+ state->tx_tuna[6] = (u8) (srate >> 8);
+ state->tx_tuna[7] = (u8) srate;
+ }
}
return 0;
}
-
static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
{
if (state->dst_type != DST_TYPE_IS_CABLE)
- return 0;
+ return -EOPNOTSUPP;
state->modulation = modulation;
switch (modulation) {
@@ -490,7 +521,10 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio
state->tx_tuna[8] = 0x80;
break;
case QAM_256:
- state->tx_tuna[8] = 0x00;
+ if (!strncmp(state->fw_name, "DCTNEW", 6))
+ state->tx_tuna[8] = 0xff;
+ else if (!strncmp(state->fw_name, "DCT-CI", 6))
+ state->tx_tuna[8] = 0x00;
break;
case QPSK:
case QAM_AUTO:
@@ -523,13 +557,19 @@ u8 dst_check_sum(u8 *buf, u32 len)
}
EXPORT_SYMBOL(dst_check_sum);
-static void dst_type_flags_print(u32 type_flags)
+static void dst_type_flags_print(struct dst_state *state)
{
+ u32 type_flags = state->type_flags;
+
dprintk(verbose, DST_ERROR, 0, "DST type flags :");
- if (type_flags & DST_TYPE_HAS_NEWTUNE)
- dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+ if (type_flags & DST_TYPE_HAS_TS188)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+ if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
if (type_flags & DST_TYPE_HAS_TS204)
dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+ if (type_flags & DST_TYPE_HAS_VLF)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
if (type_flags & DST_TYPE_HAS_SYMDIV)
dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
if (type_flags & DST_TYPE_HAS_FW_1)
@@ -542,7 +582,7 @@ static void dst_type_flags_print(u32 type_flags)
}
-static int dst_type_print(u8 type)
+static int dst_type_print(struct dst_state *state, u8 type)
{
char *otype;
switch (type) {
@@ -558,6 +598,10 @@ static int dst_type_print(u8 type)
otype = "cable";
break;
+ case DST_TYPE_IS_ATSC:
+ otype = "atsc";
+ break;
+
default:
dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
return -EINVAL;
@@ -567,6 +611,127 @@ static int dst_type_print(u8 type)
return 0;
}
+struct tuner_types tuner_list[] = {
+ {
+ .tuner_type = TUNER_TYPE_L64724,
+ .tuner_name = "L 64724",
+ .board_name = "UNKNOWN",
+ .fw_name = "UNKNOWN"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1020",
+ .fw_name = "DST-MOT"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1020",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_MB86A15,
+ .tuner_name = "MB 86A15",
+ .board_name = "VP1022",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_MB86A15,
+ .tuner_name = "MB 86A15",
+ .board_name = "VP1025",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1030",
+ .fw_name = "DST-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1030",
+ .fw_name = "DSTMCI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2021",
+ .fw_name = "DCTNEW"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2030",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2031",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2040",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3020",
+ .fw_name = "DTTFTA"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3021",
+ .fw_name = "DTTFTA"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_TDA10046,
+ .tuner_name = "TDA10046",
+ .board_name = "VP3040",
+ .fw_name = "DTT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3051",
+ .fw_name = "DTTNXT"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_NXT200x,
+ .tuner_name = "NXT200x",
+ .board_name = "VP3220",
+ .fw_name = "ATSCDI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_NXT200x,
+ .tuner_name = "NXT200x",
+ .board_name = "VP3250",
+ .fw_name = "ATSCAD"
+ },
+};
+
/*
Known cards list
Satellite
@@ -608,7 +773,8 @@ static struct dst_types dst_tlist[] = {
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
@@ -616,15 +782,17 @@ static struct dst_types dst_tlist[] = {
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.device_id = "DST-030",
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
@@ -633,7 +801,8 @@ static struct dst_types dst_tlist[] = {
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
- | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+ | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+ .tuner_type = TUNER_TYPE_MULTI
},
{
@@ -641,57 +810,63 @@ static struct dst_types dst_tlist[] = {
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.device_id = "DST-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
}, /* An OEM board */
{
.device_id = "DSTMCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
- | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+ | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+ .tuner_type = TUNER_TYPE_MULTI
},
{
.device_id = "DSTFCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* unknown to vendor */
{
.device_id = "DCT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_CABLE,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
- | DST_TYPE_HAS_FW_2,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
},
{
.device_id = "DCTNEW",
.offset = 1,
.dst_type = DST_TYPE_IS_CABLE,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.device_id = "DTT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
- .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
+ .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
},
{
@@ -699,7 +874,8 @@ static struct dst_types dst_tlist[] = {
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
@@ -707,7 +883,8 @@ static struct dst_types dst_tlist[] = {
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = DST_TYPE_HAS_ANALOG
+ .dst_feature = DST_TYPE_HAS_ANALOG,
+ .tuner_type = 0
},
{
@@ -715,15 +892,17 @@ static struct dst_types dst_tlist[] = {
.offset = 1,
.dst_type = DST_TYPE_IS_ATSC,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.device_id = "ATSCAD",
.offset = 1,
.dst_type = DST_TYPE_IS_ATSC,
- .type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+ .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+ .tuner_type = 0
},
{ }
@@ -768,6 +947,9 @@ static int dst_fw_ver(struct dst_state *state)
static int dst_card_type(struct dst_state *state)
{
+ int j;
+ struct tuner_types *p_tuner_list = NULL;
+
u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
get_type[7] = dst_check_sum(get_type, 7);
if (dst_command(state, get_type, 8) < 0) {
@@ -775,9 +957,17 @@ static int dst_card_type(struct dst_state *state)
return -1;
}
memset(&state->card_info, '\0', 8);
- memcpy(&state->card_info, &state->rxbuffer, 8);
+ memcpy(&state->card_info, &state->rxbuffer, 7);
dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
+ for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+ if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+ state->tuner_type = p_tuner_list->tuner_type;
+ dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+ p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+ }
+ }
+
return 0;
}
@@ -790,12 +980,64 @@ static int dst_get_vendor(struct dst_state *state)
return -1;
}
memset(&state->vendor, '\0', 8);
- memcpy(&state->vendor, &state->rxbuffer, 8);
+ memcpy(&state->vendor, &state->rxbuffer, 7);
dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
return 0;
}
+static void debug_dst_buffer(struct dst_state *state)
+{
+ int i;
+
+ if (verbose > 2) {
+ printk("%s: [", __func__);
+ for (i = 0; i < 8; i++)
+ printk(" %02x", state->rxbuffer[i]);
+ printk("]\n");
+ }
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+ u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+ if (dst_command(state, check_stv0299, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+ return -1;
+ }
+ debug_dst_buffer(state);
+
+ if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+ dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+ state->tuner_type = TUNER_TYPE_STV0299;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+ u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+ if (dst_command(state, check_mb86a15, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+ return -1;
+ }
+ debug_dst_buffer(state);
+
+ if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+ state->tuner_type = TUNER_TYPE_MB86A15;
+ return 0;
+ }
+
+ return -1;
+}
+
static int dst_get_tuner_info(struct dst_state *state)
{
u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
@@ -803,60 +1045,59 @@ static int dst_get_tuner_info(struct dst_state *state)
get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+ dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
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;
+ if (dst_command(state, get_tuner_1, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+ goto force;
}
} else {
- if (dst_command(state, get_tuner_1, 8) < 0) {
- dprintk(verbose, DST_INFO, 1, "Unsupported Command");
- return -1;
+ if (dst_command(state, get_tuner_2, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+ goto force;
}
}
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]);
+ dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+ }
+ if (state->board_info[0] == 0xbc) {
+ if (state->type_flags != DST_TYPE_IS_ATSC)
+ state->type_flags |= DST_TYPE_HAS_TS188;
+ else
+ state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
+
+ if (state->board_info[1] == 0x01) {
+ state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+ dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
}
}
return 0;
+force:
+ if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+ state->type_flags |= DST_TYPE_HAS_TS204;
+ dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+ }
+
+ return -1;
}
static int dst_get_device_id(struct dst_state *state)
{
u8 reply;
- int i;
- struct dst_types *p_dst_type;
+ int i, j;
+ struct dst_types *p_dst_type = NULL;
+ struct tuner_types *p_tuner_list = NULL;
+
u8 use_dst_type = 0;
u32 use_type_flags = 0;
static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+ state->tuner_type = 0;
device_type[7] = dst_check_sum(device_type, 7);
if (write_dst(state, device_type, FIXED_COMM))
@@ -888,8 +1129,34 @@ static int dst_get_device_id(struct dst_state *state)
/* Card capabilities */
state->dst_hw_cap = p_dst_type->dst_feature;
- dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id);
-
+ dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+ strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+ /* Multiple tuners */
+ if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+ switch (use_dst_type) {
+ case DST_TYPE_IS_SAT:
+ /* STV0299 check */
+ if (dst_check_stv0299(state) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Unsupported");
+ state->tuner_type = TUNER_TYPE_MB86A15;
+ }
+ break;
+ default:
+ break;
+ }
+ if (dst_check_mb86a15(state) < 0)
+ dprintk(verbose, DST_ERROR, 1, "Unsupported");
+ /* Single tuner */
+ } else {
+ state->tuner_type = p_dst_type->tuner_type;
+ }
+ for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+ if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+ p_tuner_list->tuner_type == state->tuner_type) {
+ dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+ p_dst_type->device_id, p_tuner_list->tuner_name);
+ }
+ }
break;
}
}
@@ -900,10 +1167,10 @@ static int dst_get_device_id(struct dst_state *state)
use_dst_type = DST_TYPE_IS_SAT;
use_type_flags = DST_TYPE_HAS_SYMDIV;
}
- dst_type_print(use_dst_type);
+ dst_type_print(state, use_dst_type);
state->type_flags = use_type_flags;
state->dst_type = use_dst_type;
- dst_type_flags_print(state->type_flags);
+ dst_type_flags_print(state);
return 0;
}
@@ -911,15 +1178,15 @@ static int dst_get_device_id(struct dst_state *state)
static int dst_probe(struct dst_state *state)
{
mutex_init(&state->dst_mutex);
- if ((rdc_8820_reset(state)) < 0) {
- dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
- return -1;
- }
- if (dst_addons & DST_TYPE_HAS_CA)
+ if (dst_addons & DST_TYPE_HAS_CA) {
+ if ((rdc_8820_reset(state)) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+ return -1;
+ }
msleep(4000);
- else
+ } else {
msleep(100);
-
+ }
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
return -1;
@@ -931,7 +1198,6 @@ static int dst_probe(struct dst_state *state)
}
if (dst_get_mac(state) < 0) {
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)
@@ -968,7 +1234,7 @@ int dst_command(struct dst_state *state, u8 *data, u8 len)
goto error;
}
if (write_dst(state, data, len)) {
- dprintk(verbose, DST_INFO, 1, "Tring to recover.. ");
+ dprintk(verbose, DST_INFO, 1, "Trying to recover.. ");
if ((dst_error_recovery(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "Recovery Failed.");
goto error;
@@ -1048,6 +1314,10 @@ static int dst_get_signal(struct dst_state *state)
state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
state->decode_strength = state->rxbuffer[4] << 8;
state->decode_snr = state->rxbuffer[3] << 8;
+ } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+ state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+ state->decode_strength = state->rxbuffer[4] << 8;
+ state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
}
state->cur_jiff = jiffies;
}
@@ -1058,15 +1328,13 @@ static int dst_tone_power_cmd(struct dst_state *state)
{
u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 };
- if (state->dst_type == DST_TYPE_IS_TERR)
- return 0;
+ if (state->dst_type != DST_TYPE_IS_SAT)
+ return -EOPNOTSUPP;
paket[4] = state->tx_tuna[4];
paket[2] = state->tx_tuna[2];
paket[3] = state->tx_tuna[3];
paket[7] = dst_check_sum (paket, 7);
- dst_command(state, paket, 8);
-
- return 0;
+ return dst_command(state, paket, 8);
}
static int dst_get_tuna(struct dst_state *state)
@@ -1078,8 +1346,9 @@ static int dst_get_tuna(struct dst_state *state)
state->diseq_flags &= ~(HAS_LOCK);
if (!dst_wait_dst_ready(state, NO_DELAY))
return -EIO;
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- /* how to get variable length reply ???? */
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ !(state->dst_type == DST_TYPE_IS_ATSC))
+
retval = read_dst(state, state->rx_tuna, 10);
else
retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
@@ -1087,7 +1356,10 @@ static int dst_get_tuna(struct dst_state *state)
dprintk(verbose, DST_DEBUG, 1, "read not successful");
return retval;
}
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ !(state->dst_type == DST_TYPE_IS_CABLE) &&
+ !(state->dst_type == DST_TYPE_IS_ATSC)) {
+
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
return -EIO;
@@ -1133,7 +1405,10 @@ static int dst_write_tuna(struct dvb_frontend *fe)
dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
goto error;
}
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ (!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
retval = write_dst(state, &state->tx_tuna[0], 10);
} else {
@@ -1188,23 +1463,25 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd
u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
if (state->dst_type != DST_TYPE_IS_SAT)
- return 0;
- if (cmd->msg_len == 0 || cmd->msg_len > 4)
+ return -EOPNOTSUPP;
+ if (cmd->msg_len > 0 && cmd->msg_len < 5)
+ memcpy(&paket[3], cmd->msg, cmd->msg_len);
+ else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+ memcpy(&paket[2], cmd->msg, cmd->msg_len);
+ else
return -EINVAL;
- memcpy(&paket[3], cmd->msg, cmd->msg_len);
paket[7] = dst_check_sum(&paket[0], 7);
- dst_command(state, paket, 8);
- return 0;
+ return dst_command(state, paket, 8);
}
static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- int need_cmd;
+ int need_cmd, retval = 0;
struct dst_state *state = fe->demodulator_priv;
state->voltage = voltage;
if (state->dst_type != DST_TYPE_IS_SAT)
- return 0;
+ return -EOPNOTSUPP;
need_cmd = 0;
@@ -1226,9 +1503,9 @@ static int dst_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
}
if (need_cmd)
- dst_tone_power_cmd(state);
+ retval = dst_tone_power_cmd(state);
- return 0;
+ return retval;
}
static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
@@ -1237,7 +1514,7 @@ static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
state->tone = tone;
if (state->dst_type != DST_TYPE_IS_SAT)
- return 0;
+ return -EOPNOTSUPP;
switch (tone) {
case SEC_TONE_OFF:
@@ -1253,9 +1530,7 @@ static int dst_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
default:
return -EINVAL;
}
- dst_tone_power_cmd(state);
-
- return 0;
+ return dst_tone_power_cmd(state);
}
static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
@@ -1263,7 +1538,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
struct dst_state *state = fe->demodulator_priv;
if (state->dst_type != DST_TYPE_IS_SAT)
- return 0;
+ return -EOPNOTSUPP;
state->minicmd = minicmd;
switch (minicmd) {
case SEC_MINI_A:
@@ -1273,9 +1548,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
state->tx_tuna[3] = 0xff;
break;
}
- dst_tone_power_cmd(state);
-
- return 0;
+ return dst_tone_power_cmd(state);
}
@@ -1287,8 +1560,9 @@ static int dst_init(struct dvb_frontend *fe)
static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
- static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
state->inversion = INVERSION_OFF;
state->voltage = SEC_VOLTAGE_13;
@@ -1298,11 +1572,13 @@ static int dst_init(struct dvb_frontend *fe)
state->bandwidth = BANDWIDTH_7_MHZ;
state->cur_jiff = jiffies;
if (state->dst_type == DST_TYPE_IS_SAT)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
else if (state->dst_type == DST_TYPE_IS_TERR)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
else if (state->dst_type == DST_TYPE_IS_CABLE)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+ else if (state->dst_type == DST_TYPE_IS_ATSC)
+ memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
return 0;
}
@@ -1325,23 +1601,55 @@ static int dst_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct dst_state *state = fe->demodulator_priv;
- dst_get_signal(state);
+ int retval = dst_get_signal(state);
*strength = state->decode_strength;
- return 0;
+ return retval;
}
static int dst_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct dst_state *state = fe->demodulator_priv;
- dst_get_signal(state);
+ int retval = dst_get_signal(state);
*snr = state->decode_snr;
- return 0;
+ return retval;
}
-static int dst_set_frontend(struct dvb_frontend* fe,
+static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+ int retval = -EINVAL;
+ struct dst_state *state = fe->demodulator_priv;
+
+ if (p != NULL) {
+ retval = dst_set_freq(state, p->frequency);
+ if(retval != 0)
+ return retval;
+ dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ dst_set_inversion(state, p->inversion);
+ dst_set_fec(state, p->u.qpsk.fec_inner);
+ dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_polarization(state);
+ dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+ } else if (state->dst_type == DST_TYPE_IS_TERR)
+ dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+ else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dst_set_fec(state, p->u.qam.fec_inner);
+ dst_set_symbolrate(state, p->u.qam.symbol_rate);
+ dst_set_modulation(state, p->u.qam.modulation);
+ }
+ retval = dst_write_tuna(fe);
+ }
+
+ return retval;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
int *delay,
@@ -1378,6 +1686,11 @@ static int dst_set_frontend(struct dvb_frontend* fe,
return 0;
}
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+ return dst_algo;
+}
+
static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
{
struct dst_state *state = fe->demodulator_priv;
@@ -1408,6 +1721,7 @@ static void dst_release(struct dvb_frontend *fe)
static struct dvb_frontend_ops dst_dvbt_ops;
static struct dvb_frontend_ops dst_dvbs_ops;
static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
{
@@ -1417,24 +1731,25 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad
return NULL;
}
/* determine settings based on type */
+ /* create dvb_frontend */
switch (state->dst_type) {
case DST_TYPE_IS_TERR:
- memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_CABLE:
- memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_SAT:
- memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ break;
+ case DST_TYPE_IS_ATSC:
+ memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
break;
default:
dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
kfree(state);
return NULL;
}
-
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return state; /* Manu (DST is a card not a frontend) */
@@ -1455,8 +1770,10 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
@@ -1479,8 +1796,10 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
@@ -1506,13 +1825,38 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
+ .get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
+ .read_status = dst_read_status,
+ .read_signal_strength = dst_read_signal_strength,
+ .read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_atsc_ops = {
+ .info = {
+ .name = "DST ATSC",
+ .type = FE_ATSC,
+ .frequency_stepsize = 62500,
+ .frequency_min = 510000000,
+ .frequency_max = 858000000,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .release = dst_release,
+ .init = dst_init,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
};
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
MODULE_AUTHOR("Jamie Honan, Manu Abraham");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index f6b49a801eb..fa923b9b346 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -68,6 +68,13 @@ static int ca_set_pid(void)
return -EOPNOTSUPP;
}
+static void put_command_and_length(u8 *data, int command, int length)
+{
+ data[0] = (command >> 16) & 0xff;
+ data[1] = (command >> 8) & 0xff;
+ data[2] = command & 0xff;
+ data[3] = length;
+}
static void put_checksum(u8 *check_string, int length)
{
@@ -124,15 +131,18 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
u8 dst_ca_comm_err = 0;
while (dst_ca_comm_err < RETRIES) {
- dst_comm_init(state);
dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
if (dst_ci_command(state, data, ca_string, len, read)) { // If error
dst_error_recovery(state);
dst_ca_comm_err++; // work required here.
+ } else {
+ break;
}
- break;
}
+ if(dst_ca_comm_err == RETRIES)
+ return -1;
+
return 0;
}
@@ -140,6 +150,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string,
static int ca_get_app_info(struct dst_state *state)
{
+ int length, str_length;
static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
put_checksum(&command[0], command[0]);
@@ -154,6 +165,68 @@ static int ca_get_app_info(struct dst_state *state)
(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
+ // Transform dst message to correct application_info message
+ length = state->messages[5];
+ str_length = length - 6;
+ if (str_length < 0) {
+ str_length = 0;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+ }
+
+ // First, the command and length fields
+ put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+ // Copy application_type, application_manufacturer and manufacturer_code
+ memcpy(&state->messages[4], &state->messages[7], 5);
+
+ // Set string length and copy string
+ state->messages[9] = str_length;
+ memcpy(&state->messages[10], &state->messages[12], str_length);
+
+ return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+ int srcPtr, dstPtr, i, num_ids;
+ static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+ const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+ put_checksum(&slot_command[0], slot_command[0]);
+ if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+ // Print raw data
+ dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+ for (i = 0; i < state->messages[0] + 1; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+ // Set the command and length of the output
+ num_ids = state->messages[in_num_ids_pos];
+ if (num_ids >= 100) {
+ num_ids = 100;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+ }
+ put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+ dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+ srcPtr = in_system_id_pos;
+ dstPtr = out_system_id_pos;
+ for(i = 0; i < num_ids; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+ // Append to output
+ state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+ state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+ srcPtr += 2;
+ dstPtr += 2;
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
return 0;
}
@@ -174,7 +247,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps,
dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
- for (i = 0; i < 8; i++)
+ for (i = 0; i < slot_cap[0] + 1; i++)
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
dprintk(verbose, DST_CA_INFO, 0, "\n");
@@ -260,6 +333,11 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
return -EFAULT;
break;
+ case CA_INFO:
+ memcpy(p_ca_message->msg, state->messages, 128);
+ if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+ return -EFAULT;
+ break;
}
}
@@ -302,7 +380,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l
rdc_reset_state(state);
return -1;
}
- dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
+ dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
return 0;
}
@@ -340,6 +418,7 @@ static int debug_string(u8 *msg, u32 length, u32 offset)
return 0;
}
+
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
{
u32 length = 0;
@@ -455,6 +534,16 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
break;
+ case CA_INFO_ENQUIRY:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+ if ((ca_get_ca_info(state)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+ break;
}
}
free_mem_and_exit:
@@ -473,18 +562,15 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
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");
- return -ENOMEM;
- }
- if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
+ p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+ p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+ p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+ if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
- }
- if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
+ result = -ENOMEM;
+ goto free_mem_and_exit;
}
+
/* We have now only the standard ioctl's, the driver is upposed to handle internals. */
switch (cmd) {
case CA_SEND_MSG:
@@ -582,7 +668,7 @@ static int dst_ca_release(struct inode *inode, struct file *file)
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
- int bytes_read = 0;
+ ssize_t bytes_read = 0;
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 51d4e043716..0677b047b3a 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -42,7 +42,7 @@
#define DST_TYPE_IS_CABLE 2
#define DST_TYPE_IS_ATSC 3
-#define DST_TYPE_HAS_NEWTUNE 1
+#define DST_TYPE_HAS_TS188 1
#define DST_TYPE_HAS_TS204 2
#define DST_TYPE_HAS_SYMDIV 4
#define DST_TYPE_HAS_FW_1 8
@@ -52,6 +52,9 @@
#define DST_TYPE_HAS_OBS_REGS 128
#define DST_TYPE_HAS_INC_COUNT 256
#define DST_TYPE_HAS_MULTI_FE 512
+#define DST_TYPE_HAS_NEWTUNE_2 1024
+#define DST_TYPE_HAS_DBOARD 2048
+#define DST_TYPE_HAS_VLF 4096
/* Card capability list */
@@ -64,6 +67,20 @@
#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */
#define DST_TYPE_HAS_SESSION 128
+#define TUNER_TYPE_MULTI 1
+#define TUNER_TYPE_UNKNOWN 2
+/* DVB-S */
+#define TUNER_TYPE_L64724 4
+#define TUNER_TYPE_STV0299 8
+#define TUNER_TYPE_MB86A15 16
+
+/* DVB-T */
+#define TUNER_TYPE_TDA10046 32
+
+/* ATSC */
+#define TUNER_TYPE_NXT200x 64
+
+
#define RDC_8820_PIO_0_DISABLE 0
#define RDC_8820_PIO_0_ENABLE 1
#define RDC_8820_INT 2
@@ -84,8 +101,6 @@ struct dst_state {
struct bt878* bt;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct dst_config* config;
@@ -121,8 +136,17 @@ struct dst_state {
u8 card_info[8];
u8 vendor[8];
u8 board_info[8];
-
+ u32 tuner_type;
+ char *tuner_name;
struct mutex dst_mutex;
+ u8 fw_name[8];
+};
+
+struct tuner_types {
+ u32 tuner_type;
+ char *tuner_name;
+ char *board_name;
+ char *fw_name;
};
struct dst_types {
@@ -131,6 +155,7 @@ struct dst_types {
u8 dst_type;
u32 type_flags;
u32 dst_feature;
+ u32 tuner_type;
};
struct dst_config
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index ccc7b2eb4a2..b715b972d2f 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -147,12 +147,15 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
+ if (buf_len < 5)
+ return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 542000000)
@@ -169,22 +172,25 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
else
bs = 0x08;
- pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+ pllbuf[0] = 0x60;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config thomson_dtt7579_config = {
.demod_address = 0x0f,
.demod_init = thomson_dtt7579_demod_init,
- .pll_set = thomson_dtt7579_pll_set,
};
-static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+ .demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
u32 freq = params->frequency;
@@ -237,7 +243,7 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
return 0;
}
-static int pinnsat_pll_init(struct dvb_frontend* fe)
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
@@ -247,7 +253,7 @@ static int pinnsat_pll_init(struct dvb_frontend* fe)
return 0;
}
-static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
@@ -258,12 +264,9 @@ static int pinnsat_pll_sleep(struct dvb_frontend* fe)
static struct cx24110_config pctvsat_config = {
.demod_address = 0x55,
- .pll_init = pinnsat_pll_init,
- .pll_set = cx24108_pll_set,
- .pll_sleep = pinnsat_pll_sleep,
};
-static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 cfg, cpump, band_select;
@@ -297,6 +300,8 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return (div * 166666 - 36000000);
}
@@ -310,7 +315,6 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s
static struct sp887x_config microtune_mt7202dtf_config = {
.demod_address = 0x70,
- .pll_set = microtune_mt7202dtf_pll_set,
.request_firmware = microtune_mt7202dtf_request_firmware,
};
@@ -337,12 +341,14 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
+ if (buf_len < 5) return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 150000000)
@@ -383,19 +389,18 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct
else
bs = 0x08;
- pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+ pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
- .pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
};
static struct dst_config dst_config = {
@@ -455,7 +460,7 @@ static struct or51211_config or51211_config = {
.sleep = or51211_sleep,
};
-static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 buf[4];
@@ -478,6 +483,8 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
else
return -EINVAL;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return 0;
}
@@ -485,7 +492,6 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
static struct nxt6000_config vp3021_alps_tded4_config = {
.demod_address = 0x0a,
.clock_inversion = 1,
- .pll_set = vp3021_alps_tded4_pll_set,
};
static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
@@ -506,14 +512,17 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
struct dvb_ofdm_parameters *op = &params->u.ofdm;
+ if (buf_len < 5)
+ return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
- pllbuf[0] = 0xc2;
+ pllbuf[0] = 0x61;
pllbuf[1] = (div >> 8) & 0x7F;
pllbuf[2] = div & 0xFF;
pllbuf[3] = 0x85;
@@ -530,7 +539,7 @@ static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten
if (op->bandwidth == 8)
pllbuf[4] |= 0x04;
- return 0;
+ return 5;
}
static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
@@ -557,43 +566,18 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
static struct mt352_config digitv_alps_tded4_config = {
.demod_address = 0x0a,
.demod_init = digitv_alps_tded4_demod_init,
- .pll_set = digitv_alps_tded4_pll_set,
};
-static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int tdvs_tua6034_tuner_set_params(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;
+ return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
}
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)
@@ -617,17 +601,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
switch(type) {
case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+
+ if (card->fe == NULL)
+ card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+ card->i2c_adapter);
+
if (card->fe != NULL) {
- card->fe->ops->info.frequency_min = 174000000;
- card->fe->ops->info.frequency_max = 862000000;
+ card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+ card->fe->ops.info.frequency_max = 862000000;
}
break;
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card);
card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
- if (card->fe != NULL)
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
dprintk ("dvb_bt8xx: lgdt330x detected\n");
+ }
break;
case BTTV_BOARD_NEBULA_DIGITV:
@@ -640,6 +632,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
digitv_alps_tded4_reset(card);
card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
break;
}
@@ -648,19 +641,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
digitv_alps_tded4_reset(card);
card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
- if (card->fe != NULL)
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+ }
break;
case BTTV_BOARD_AVDVBT_761:
card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+ }
break;
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;
- card->fe->ops->info.frequency_max = 862000000;
+ card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+ card->fe->ops.info.frequency_max = 862000000;
}
break;
@@ -687,6 +686,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_PINNACLESAT:
card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+ card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+ card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+ }
break;
case BTTV_BOARD_PC_HDTV:
@@ -703,8 +707,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
else
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
printk("dvb-bt8xx: Frontend registration failed!\n");
- if (card->fe->ops->release)
- card->fe->ops->release(card->fe);
+ if (card->fe->ops.release)
+ card->fe->ops.release(card->fe);
card->fe = NULL;
}
}
@@ -713,7 +717,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
{
int result;
- if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
+ if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
return result;
}
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 00dd9fa54c8..4745a9017a1 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -37,6 +37,8 @@
#include "cx24110.h"
#include "or51211.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "zl10353.h"
struct dvb_bt8xx_card {
struct mutex lock;
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index 6018fcdba1e..b5cdd57ec6f 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -64,7 +64,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL
config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
bool "Register the onboard IR Remote Control Receiver as Input Device"
depends on DVB_CINERGYT2_TUNING
- default "yes"
+ default y
help
Enable this option if you want to use the onboard Infrared Remote
Control Receiver as Linux-Input device.
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 9325d039ea6..410fa6d620f 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -544,15 +543,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
+ unsigned int mask = 0;
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
+ if (cinergyt2->pending_fe_events != 0)
+ mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
mutex_unlock(&cinergyt2->sem);
- return (POLLIN | POLLRDNORM | POLLPRI);
+ return mask;
}
@@ -902,7 +905,7 @@ static int cinergyt2_probe (struct usb_interface *intf,
return -ENOMEM;
}
- if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+ if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
kfree(cinergyt2);
return err;
}
@@ -978,7 +981,7 @@ static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state)
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
- if (state.event > PM_EVENT_ON) {
+ if (1) {
struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf);
cinergyt2_suspend_rc(cinergyt2);
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
index 7adb50c1e8e..0b5182835cc 100644
--- a/drivers/media/dvb/dvb-core/Makefile
+++ b/drivers/media/dvb/dvb-core/Makefile
@@ -2,8 +2,8 @@
# Makefile for the kernel DVB device drivers.
#
-dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
- dvb_ca_en50221.o dvb_frontend.o \
- dvb_net.o dvb_ringbuffer.o
+dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
+ dvb_ca_en50221.o dvb_frontend.o \
+ dvb_net.o dvb_ringbuffer.o dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 04578df3f24..988499dfddf 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -872,9 +872,6 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
mutex_unlock(&dmxdevfilter->mutex);
break;
- case DMX_GET_EVENT:
- break;
-
case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) {
ret = -EINVAL;
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index 00347a75068..2a03bf53cb2 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -1060,8 +1060,18 @@ static int dvb_ca_en50221_thread(void *data)
break;
case DVB_CA_SLOTSTATE_VALIDATE:
- if (dvb_ca_en50221_parse_attributes(ca, slot)
- != 0) {
+ if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
@@ -1108,6 +1118,17 @@ static int dvb_ca_en50221_thread(void *data)
case DVB_CA_SLOTSTATE_LINKINIT:
if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 83ec5e06c48..fcff5eab21a 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -473,7 +473,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
- if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) {
+ if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
memcpy(tmppack, demux->tsbuf, 188);
if (tmppack[0] == 0xB8)
tmppack[0] = 0x47;
@@ -484,7 +484,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
}
while (p < count) {
- if ((buf[p] == 0x47) | (buf[p] == 0xB8)) {
+ if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
if (count - p >= 204) {
memcpy(tmppack, &buf[p], 188);
if (tmppack[0] == 0xB8)
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index a051790161b..57b34cda99f 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AU
module_param(dvb_override_tune_delay, int, 0644);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
#define dprintk if (dvb_frontend_debug) printk
@@ -72,6 +72,8 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola
#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW 1
/*
* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
@@ -151,8 +153,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
sizeof (struct dvb_frontend_parameters));
if (status & FE_HAS_LOCK)
- if (fe->ops->get_frontend)
- fe->ops->get_frontend(fe, &e->parameters);
+ if (fe->ops.get_frontend)
+ fe->ops.get_frontend(fe, &e->parameters);
events->eventw = wp;
@@ -211,10 +213,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe)
{
dprintk ("DVB: initialising frontend %i (%s)...\n",
fe->dvb->num,
- fe->ops->info.name);
-
- if (fe->ops->init)
- fe->ops->init(fe);
+ fe->ops.info.name);
+
+ if (fe->ops.init)
+ fe->ops.init(fe);
+ if (fe->ops.tuner_ops.init) {
+ fe->ops.tuner_ops.init(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
}
void dvb_frontend_reinitialise(struct dvb_frontend *fe)
@@ -259,7 +266,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
u32 original_frequency = fepriv->parameters.frequency;
/* are we using autoinversion? */
- autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO));
/* setup parameters correctly */
@@ -329,8 +336,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
fepriv->parameters.frequency += fepriv->lnb_drift;
if (autoinversion)
fepriv->parameters.inversion = fepriv->inversion;
- if (fe->ops->set_frontend)
- fe->ops->set_frontend(fe, &fepriv->parameters);
+ if (fe->ops.set_frontend)
+ fe->ops.set_frontend(fe, &fepriv->parameters);
fepriv->parameters.frequency = original_frequency;
fepriv->parameters.inversion = original_inversion;
@@ -354,8 +361,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* in SCAN mode, we just set the frontend when asked and leave it alone */
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
if (fepriv->state & FESTATE_RETUNE) {
- if (fe->ops->set_frontend)
- fe->ops->set_frontend(fe, &fepriv->parameters);
+ if (fe->ops.set_frontend)
+ fe->ops.set_frontend(fe, &fepriv->parameters);
fepriv->state = FESTATE_TUNED;
}
fepriv->delay = 3*HZ;
@@ -367,8 +374,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
- if (fe->ops->read_status)
- fe->ops->read_status(fe, &s);
+ if (fe->ops.read_status)
+ fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
@@ -381,7 +388,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
- if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
@@ -405,7 +412,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
- (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+ (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
@@ -519,7 +526,9 @@ static int dvb_frontend_thread(void *data)
fepriv->delay = 3*HZ;
fepriv->status = 0;
fepriv->wakeup = 0;
- fepriv->reinitialise = 1;
+ fepriv->reinitialise = 0;
+
+ dvb_frontend_init(fe);
while (1) {
up(&fepriv->sem); /* is locked when we enter the thread... */
@@ -540,39 +549,46 @@ static int dvb_frontend_thread(void *data)
if (fepriv->reinitialise) {
dvb_frontend_init(fe);
if (fepriv->tone != -1) {
- fe->ops->set_tone(fe, fepriv->tone);
+ fe->ops.set_tone(fe, fepriv->tone);
}
if (fepriv->voltage != -1) {
- fe->ops->set_voltage(fe, fepriv->voltage);
+ fe->ops.set_voltage(fe, fepriv->voltage);
}
fepriv->reinitialise = 0;
}
/* do an iteration of the tuning loop */
- if (fe->ops->tune) {
- /* have we been asked to retune? */
- params = NULL;
- if (fepriv->state & FESTATE_RETUNE) {
- params = &fepriv->parameters;
- fepriv->state = FESTATE_TUNED;
- }
+ if (fe->ops.get_frontend_algo) {
+ if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
+ /* have we been asked to retune? */
+ params = NULL;
+ if (fepriv->state & FESTATE_RETUNE) {
+ params = &fepriv->parameters;
+ fepriv->state = FESTATE_TUNED;
+ }
- fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
- if (s != fepriv->status) {
- dvb_frontend_add_event(fe, s);
- fepriv->status = s;
- }
- } else {
+ fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+ if (s != fepriv->status) {
+ dvb_frontend_add_event(fe, s);
+ fepriv->status = s;
+ }
+ } else
+ dvb_frontend_swzigzag(fe);
+ } else
dvb_frontend_swzigzag(fe);
- }
}
if (dvb_shutdown_timeout) {
if (dvb_powerdown_on_sleep)
- if (fe->ops->set_voltage)
- fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
- if (fe->ops->sleep)
- fe->ops->sleep(fe);
+ if (fe->ops.set_voltage)
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+ if (fe->ops.tuner_ops.sleep) {
+ fe->ops.tuner_ops.sleep(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.sleep)
+ fe->ops.sleep(fe);
}
fepriv->thread_pid = 0;
@@ -724,7 +740,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
- memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+ memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
@@ -744,58 +760,58 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
}
- if (fe->ops->read_status)
- err = fe->ops->read_status(fe, status);
+ if (fe->ops.read_status)
+ err = fe->ops.read_status(fe, status);
break;
}
case FE_READ_BER:
- if (fe->ops->read_ber)
- err = fe->ops->read_ber(fe, (__u32*) parg);
+ if (fe->ops.read_ber)
+ err = fe->ops.read_ber(fe, (__u32*) parg);
break;
case FE_READ_SIGNAL_STRENGTH:
- if (fe->ops->read_signal_strength)
- err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+ if (fe->ops.read_signal_strength)
+ err = fe->ops.read_signal_strength(fe, (__u16*) parg);
break;
case FE_READ_SNR:
- if (fe->ops->read_snr)
- err = fe->ops->read_snr(fe, (__u16*) parg);
+ if (fe->ops.read_snr)
+ err = fe->ops.read_snr(fe, (__u16*) parg);
break;
case FE_READ_UNCORRECTED_BLOCKS:
- if (fe->ops->read_ucblocks)
- err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+ if (fe->ops.read_ucblocks)
+ err = fe->ops.read_ucblocks(fe, (__u32*) parg);
break;
case FE_DISEQC_RESET_OVERLOAD:
- if (fe->ops->diseqc_reset_overload) {
- err = fe->ops->diseqc_reset_overload(fe);
+ if (fe->ops.diseqc_reset_overload) {
+ err = fe->ops.diseqc_reset_overload(fe);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_DISEQC_SEND_MASTER_CMD:
- if (fe->ops->diseqc_send_master_cmd) {
- err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+ if (fe->ops.diseqc_send_master_cmd) {
+ err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_DISEQC_SEND_BURST:
- if (fe->ops->diseqc_send_burst) {
- err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+ if (fe->ops.diseqc_send_burst) {
+ err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_SET_TONE:
- if (fe->ops->set_tone) {
- err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+ if (fe->ops.set_tone) {
+ err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->tone = (fe_sec_tone_mode_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
@@ -803,8 +819,8 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_SET_VOLTAGE:
- if (fe->ops->set_voltage) {
- err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+ if (fe->ops.set_voltage) {
+ err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
fepriv->voltage = (fe_sec_voltage_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
@@ -812,11 +828,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_DISHNETWORK_SEND_LEGACY_CMD:
- if (fe->ops->dishnetwork_send_legacy_command) {
- err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+ if (fe->ops.dishnetwork_send_legacy_command) {
+ err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
- } else if (fe->ops->set_voltage) {
+ } else if (fe->ops.set_voltage) {
/*
* NOTE: This is a fallback condition. Some frontends
* (stv0299 for instance) take longer than 8msec to
@@ -846,7 +862,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
/* before sending a command, initialize by sending
* a 32ms 18V to the switch
*/
- fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
dvb_frontend_sleep_until(&nexttime, 32000);
for (i = 0; i < 9; i++) {
@@ -854,7 +870,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
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);
+ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
cmd = cmd >> 1;
@@ -874,13 +890,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_DISEQC_RECV_SLAVE_REPLY:
- if (fe->ops->diseqc_recv_slave_reply)
- err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+ if (fe->ops.diseqc_recv_slave_reply)
+ err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
break;
case FE_ENABLE_HIGH_LNB_VOLTAGE:
- if (fe->ops->enable_high_lnb_voltage)
- err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
+ if (fe->ops.enable_high_lnb_voltage)
+ err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
break;
case FE_SET_FRONTEND: {
@@ -898,7 +914,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
fepriv->parameters.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
- if (fe->ops->info.type == FE_OFDM) {
+ if (fe->ops.info.type == FE_OFDM) {
/* without hierachical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
@@ -907,13 +923,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
}
/* get frontend-specific tuning settings */
- if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
+ if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
fepriv->max_drift = fetunesettings.max_drift;
fepriv->step_size = fetunesettings.step_size;
} else {
/* default values */
- switch(fe->ops->info.type) {
+ switch(fe->ops.info.type) {
case FE_QPSK:
fepriv->min_delay = HZ/20;
fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
@@ -928,11 +944,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
case FE_OFDM:
fepriv->min_delay = HZ/20;
- fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
- fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+ fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+ fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
break;
case FE_ATSC:
- printk("dvb-core: FE_ATSC not handled yet.\n");
+ fepriv->min_delay = HZ/20;
+ fepriv->step_size = 0;
+ fepriv->max_drift = 0;
break;
}
}
@@ -952,14 +970,15 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
case FE_GET_FRONTEND:
- if (fe->ops->get_frontend) {
+ if (fe->ops.get_frontend) {
memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
- err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+ err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
}
break;
case FE_SET_FRONTEND_TUNE_MODE:
fepriv->tune_mode_flags = (unsigned long) parg;
+ err = 0;
break;
};
@@ -996,17 +1015,18 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
return ret;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+
+ /* normal tune mode when opened R/W */
+ fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
+ fepriv->tone = -1;
+ fepriv->voltage = -1;
+
ret = dvb_frontend_start (fe);
if (ret)
dvb_generic_release (inode, file);
/* empty event queue */
fepriv->events.eventr = fepriv->events.eventw = 0;
-
- /* normal tune mode when opened R/W */
- fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
- fepriv->tone = -1;
- fepriv->voltage = -1;
}
return ret;
@@ -1067,7 +1087,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
- fe->ops->info.name);
+ fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
@@ -1085,10 +1105,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
- if (fe->ops->release)
- fe->ops->release(fe);
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.release)
+ fe->ops.release(fe);
else
- printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+ printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
/* fe is invalid now */
kfree(fepriv);
mutex_unlock(&frontend_mutex);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 5926a3b745c..2887e2b862a 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -49,6 +49,44 @@ struct dvb_frontend_tune_settings {
struct dvb_frontend;
+struct dvb_tuner_info {
+ char name[128];
+
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_step;
+
+ u32 bandwidth_min;
+ u32 bandwidth_max;
+ u32 bandwidth_step;
+};
+
+struct dvb_tuner_ops {
+
+ struct dvb_tuner_info info;
+
+ int (*release)(struct dvb_frontend *fe);
+ int (*init)(struct dvb_frontend *fe);
+ int (*sleep)(struct dvb_frontend *fe);
+
+ /** This is for simple PLLs - set all parameters in one go. */
+ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
+ /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+
+ int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+ int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+
+#define TUNER_STATUS_LOCKED 1
+ int (*get_status)(struct dvb_frontend *fe, u32 *status);
+
+ /** These are provided seperately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+ int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+};
+
struct dvb_frontend_ops {
struct dvb_frontend_info info;
@@ -64,6 +102,8 @@ struct dvb_frontend_ops {
unsigned int mode_flags,
int *delay,
fe_status_t *status);
+ /* get frontend tuning algorithm from the module */
+ int (*get_frontend_algo)(struct dvb_frontend *fe);
/* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
@@ -86,6 +126,8 @@ struct dvb_frontend_ops {
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+
+ struct dvb_tuner_ops tuner_ops;
};
#define MAX_EVENT 8
@@ -100,9 +142,10 @@ struct dvb_fe_events {
};
struct dvb_frontend {
- struct dvb_frontend_ops* ops;
+ struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
void* demodulator_priv;
+ void* tuner_priv;
void* frontend_priv;
void* misc_priv;
};
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c
new file mode 100644
index 00000000000..beb7c93aa6c
--- /dev/null
+++ b/drivers/media/dvb/dvb-core/dvb_math.c
@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+ 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+ 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+ 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+ 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+ 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+ 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+ 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+ 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+ 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+ 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+ 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+ 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+ 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+ 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+ 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+ 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+ 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+ 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+ 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+ 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+ 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+ 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+ 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+ 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+ 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+ 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+ 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+ 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+ 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+ 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+ 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+ 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+ /**
+ * returns: log2(value) * 2^24
+ * wrong result if value = 0 (log2(0) is undefined)
+ */
+ unsigned int msb;
+ unsigned int logentry;
+ unsigned int significand;
+ unsigned int interpolation;
+
+ if (unlikely(value == 0)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ /* first detect the msb (count begins at 0) */
+ msb = fls(value) - 1;
+
+ /**
+ * now we use a logtable after the following method:
+ *
+ * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+ * where x = msb and therefore 1 <= y < 2
+ * first y is determined by shifting the value left
+ * so that msb is bit 31
+ * 0x00231f56 -> 0x8C7D5800
+ * the result is y * 2^31 -> "significand"
+ * then the highest 9 bits are used for a table lookup
+ * the highest bit is discarded because it's always set
+ * the highest nine bits in our example are 100011000
+ * so we would use the entry 0x18
+ */
+ significand = value << (31 - msb);
+ logentry = (significand >> 23) & 0xff;
+
+ /**
+ * last step we do is interpolation because of the
+ * limitations of the log table the error is that part of
+ * the significand which isn't used for lookup then we
+ * compute the ratio between the error and the next table entry
+ * and interpolate it between the log table entry used and the
+ * next one the biggest error possible is 0x7fffff
+ * (in our example it's 0x7D5800)
+ * needed value for next table entry is 0x800000
+ * so the interpolation is
+ * (error / 0x800000) * (logtable_next - logtable_current)
+ * in the implementation the division is moved to the end for
+ * better accuracy there is also an overflow correction if
+ * logtable_next is 256
+ */
+ interpolation = ((significand & 0x7fffff) *
+ ((logtable[(logentry + 1) & 0xff] -
+ logtable[logentry]) & 0xffff)) >> 15;
+
+ /* now we return the result */
+ return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+ /**
+ * returns: log10(value) * 2^24
+ * wrong result if value = 0 (log10(0) is undefined)
+ */
+ u64 log;
+
+ if (unlikely(value == 0)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ log = intlog2(value);
+
+ /**
+ * we use the following method:
+ * log10(x) = log2(x) * log10(2)
+ */
+
+ return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h
new file mode 100644
index 00000000000..aecc867e940
--- /dev/null
+++ b/drivers/media/dvb/dvb-core/dvb_math.h
@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ * intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ * intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ * due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 9fd87521a16..8859ab74f0f 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -12,7 +12,7 @@
* Hilmar Linder <hlinder@cosy.sbg.ac.at>
* and Wolfram Stering <wstering@cosy.sbg.ac.at>
*
- * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
+ * ULE Decaps according to RFC 4326.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -42,6 +42,9 @@
* Bugfixes and robustness improvements.
* Filtering on dest MAC addresses, if present (D-Bit = 0)
* ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by
+ * Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ * Paris Lodron University of Salzburg.
*/
/*
@@ -49,9 +52,6 @@
*
* Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
*
- * TS_FEED callback is called once for every single TS cell although it is
- * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()).
- *
*/
#include <linux/module.h>
@@ -89,6 +89,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
#ifdef ULE_DEBUG
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
static void hexdump( const unsigned char *buf, unsigned short len )
@@ -214,6 +217,8 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb,
#define ULE_TEST 0
#define ULE_BRIDGED 1
+#define ULE_OPTEXTHDR_PADDING 0
+
static int ule_test_sndu( struct dvb_net_priv *p )
{
return -1;
@@ -221,14 +226,28 @@ static int ule_test_sndu( struct dvb_net_priv *p )
static int ule_bridged_sndu( struct dvb_net_priv *p )
{
- /* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
- * This has to be the last extension header, otherwise it won't work.
- * Blame the authors!
+ struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+ if(ntohs(hdr->h_proto) < 1536) {
+ int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+ /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+ if(framelen != ntohs(hdr->h_proto)) {
+ return -1;
+ }
+ }
+ /* Note:
+ * From RFC4326:
+ * "A bridged SNDU is a Mandatory Extension Header of Type 1.
+ * It must be the final (or only) extension header specified in the header chain of a SNDU."
+ * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
*/
p->ule_bridged = 1;
return 0;
}
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+ return 0;
+}
/** Handle ULE extension headers.
* Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
@@ -242,7 +261,8 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, };
/* Table of optional extension header handlers. The header type is the index. */
- static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };
+ static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+ { [0] = ule_exthdr_padding, [1] = NULL, };
int ext_len = 0;
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
@@ -253,25 +273,31 @@ static int handle_one_ule_extension( struct dvb_net_priv *p )
/* Mandatory extension header */
if (ule_mandatory_ext_handlers[htype]) {
ext_len = ule_mandatory_ext_handlers[htype]( p );
- p->ule_next_hdr += ext_len;
- if (! p->ule_bridged) {
- p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
- p->ule_next_hdr += 2;
- } else {
- p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );
- /* This assures the extension handling loop will terminate. */
+ if(ext_len >= 0) {
+ p->ule_next_hdr += ext_len;
+ if (!p->ule_bridged) {
+ p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+ p->ule_next_hdr += 2;
+ } else {
+ p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+ /* This assures the extension handling loop will terminate. */
+ }
}
+ // else: extension handler failed or SNDU should be discarded
} else
ext_len = -1; /* SNDU has to be discarded. */
} else {
/* Optional extension header. Calculate the length. */
- ext_len = hlen << 2;
+ ext_len = hlen << 1;
/* Process the optional extension header according to its type. */
if (ule_optional_ext_handlers[htype])
(void)ule_optional_ext_handlers[htype]( p );
p->ule_next_hdr += ext_len;
- p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
- p->ule_next_hdr += 2;
+ p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+ /*
+ * note: the length of the next header type is included in the
+ * length of THIS optional extension header
+ */
}
return ext_len;
@@ -284,8 +310,14 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
p->ule_next_hdr = p->ule_skb->data;
do {
l = handle_one_ule_extension( p );
- if (l == -1) return -1; /* Stop extension header processing and discard SNDU. */
+ if (l < 0)
+ return l; /* Stop extension header processing and discard SNDU. */
total_ext_len += l;
+#ifdef ULE_DEBUG
+ dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+ "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+ (int) p->ule_sndu_type, l, total_ext_len);
+#endif
} while (p->ule_sndu_type < 1536);
@@ -355,8 +387,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
priv->need_pusi = 1;
@@ -396,27 +428,25 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
}
- /* Check continuity counter. */
if (new_ts) {
+ /* Check continuity counter. */
if ((ts[3] & 0x0F) == priv->tscc)
priv->tscc = (priv->tscc + 1) & 0x0F;
else {
/* TS discontinuity handling: */
printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
- "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+ "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
// reset_ule(priv); moved to below.
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
/* skip to next PUSI. */
priv->need_pusi = 1;
- ts += TS_SZ;
- priv->ts_count++;
continue;
}
/* If we still have an incomplete payload, but PUSI is
@@ -425,7 +455,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
* cells (continuity counter wrap). */
if (ts[1] & TS_PUSI) {
if (! priv->need_pusi) {
- if (*from_where > 181) {
+ if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
/* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */
printk(KERN_WARNING "%lu: Invalid pointer "
"field: %u.\n", priv->ts_count, *from_where);
@@ -438,8 +468,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
}
reset_ule(priv);
priv->need_pusi = 1;
- ts += TS_SZ;
- priv->ts_count++;
continue;
}
/* Skip pointer field (we're processing a
@@ -452,8 +480,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (priv->ule_sndu_remain > 183) {
/* Current SNDU lacks more data than there could be available in the
* current TS cell. */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
"got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n",
priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
@@ -492,9 +520,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
} else
priv->ule_dbit = 0;
- if (priv->ule_sndu_len > 32763) {
+ if (priv->ule_sndu_len < 5) {
printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
"Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
priv->ule_sndu_len = 0;
priv->need_pusi = 1;
new_ts = 1;
@@ -608,58 +638,103 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
ule_dump = 1;
#endif
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_crc_errors++;
dev_kfree_skb(priv->ule_skb);
} else {
/* CRC32 verified OK. */
+ u8 dest_addr[ETH_ALEN];
+ static const u8 bc_addr[ETH_ALEN] =
+ { [ 0 ... ETH_ALEN-1] = 0xff };
+
+ /* CRC32 was OK. Remove it from skb. */
+ priv->ule_skb->tail -= 4;
+ priv->ule_skb->len -= 4;
+
+ if (!priv->ule_dbit) {
+ /*
+ * The destination MAC address is the
+ * next data in the skb. It comes
+ * before any extension headers.
+ *
+ * Check if the payload of this SNDU
+ * should be passed up the stack.
+ */
+ register int drop = 0;
+ if (priv->rx_mode != RX_MODE_PROMISC) {
+ if (priv->ule_skb->data[0] & 0x01) {
+ /* multicast or broadcast */
+ if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+ /* multicast */
+ if (priv->rx_mode == RX_MODE_MULTI) {
+ int i;
+ for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+ ;
+ if (i == priv->multi_num)
+ drop = 1;
+ } else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+ drop = 1; /* no broadcast; */
+ /* else: all multicast mode: accept all multicast packets */
+ }
+ /* else: broadcast */
+ }
+ else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+ drop = 1;
+ /* else: destination address matches the MAC address of our receiver device */
+ }
+ /* else: promiscious mode; pass everything up the stack */
+
+ if (drop) {
+#ifdef ULE_DEBUG
+ dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+ MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+ dev_kfree_skb(priv->ule_skb);
+ goto sndu_done;
+ }
+ else
+ {
+ memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN);
+ skb_pull(priv->ule_skb, ETH_ALEN);
+ }
+ }
+
/* Handle ULE Extension Headers. */
if (priv->ule_sndu_type < 1536) {
/* There is an extension header. Handle it accordingly. */
- int l = handle_ule_extensions( priv );
+ int l = handle_ule_extensions(priv);
if (l < 0) {
/* Mandatory extension header unknown or TEST SNDU. Drop it. */
// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
- dev_kfree_skb( priv->ule_skb );
+ dev_kfree_skb(priv->ule_skb);
goto sndu_done;
}
- skb_pull( priv->ule_skb, l );
+ skb_pull(priv->ule_skb, l);
}
- /* CRC32 was OK. Remove it from skb. */
- priv->ule_skb->tail -= 4;
- priv->ule_skb->len -= 4;
-
- /* Filter on receiver's destination MAC address, if present. */
- if (!priv->ule_dbit) {
- /* The destination MAC address is the next data in the skb. */
- if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) {
- /* MAC addresses don't match. Drop SNDU. */
- // printk( KERN_WARNING "Dropping SNDU, MAC address.\n" );
- dev_kfree_skb( priv->ule_skb );
- goto sndu_done;
- }
- if (! priv->ule_bridged) {
- skb_push( priv->ule_skb, ETH_ALEN + 2 );
- ethh = (struct ethhdr *)priv->ule_skb->data;
- memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN );
- memset( ethh->h_source, 0, ETH_ALEN );
- ethh->h_proto = htons( priv->ule_sndu_type );
- } else {
- /* Skip the Receiver destination MAC address. */
- skb_pull( priv->ule_skb, ETH_ALEN );
- }
- } else {
- if (! priv->ule_bridged) {
- skb_push( priv->ule_skb, ETH_HLEN );
- ethh = (struct ethhdr *)priv->ule_skb->data;
- memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN );
- memset( ethh->h_source, 0, ETH_ALEN );
- ethh->h_proto = htons( priv->ule_sndu_type );
- } else {
- /* skb is in correct state; nothing to do. */
+ /*
+ * Construct/assure correct ethernet header.
+ * Note: in bridged mode (priv->ule_bridged !=
+ * 0) we already have the (original) ethernet
+ * header at the start of the payload (after
+ * optional dest. address and any extension
+ * headers).
+ */
+
+ if (!priv->ule_bridged) {
+ skb_push(priv->ule_skb, ETH_HLEN);
+ ethh = (struct ethhdr *)priv->ule_skb->data;
+ if (!priv->ule_dbit) {
+ /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+ memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+ memset(ethh->h_source, 0, ETH_ALEN);
}
+ else /* zeroize source and dest */
+ memset( ethh, 0, ETH_ALEN*2 );
+
+ ethh->h_proto = htons(priv->ule_sndu_type);
}
+ /* else: skb is in correct state; nothing to do. */
priv->ule_bridged = 0;
/* Stuff into kernel's protocol stack. */
@@ -668,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
* receive the packet anyhow. */
/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
priv->ule_skb->pkt_type = PACKET_HOST; */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += priv->ule_skb->len;
netif_rx(priv->ule_skb);
}
sndu_done:
@@ -944,7 +1019,7 @@ static int dvb_net_feed_start(struct net_device *dev)
dprintk("%s: start filtering\n", __FUNCTION__);
priv->secfeed->start_filtering(priv->secfeed);
} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
- struct timespec timeout = { 0, 30000000 }; // 30 msec
+ struct timespec timeout = { 0, 10000000 }; // 10 msec
/* we have payloads encapsulated in TS */
dprintk("%s: alloc tsfeed\n", __FUNCTION__);
@@ -956,10 +1031,13 @@ static int dvb_net_feed_start(struct net_device *dev)
/* Set netdevice pointer for ts decaps callback. */
priv->tsfeed->priv = (void *)dev;
- ret = priv->tsfeed->set(priv->tsfeed, priv->pid,
- TS_PACKET, DMX_TS_PES_OTHER,
+ ret = priv->tsfeed->set(priv->tsfeed,
+ priv->pid, /* pid */
+ TS_PACKET, /* type */
+ DMX_TS_PES_OTHER, /* pes type */
32768, /* circular buffer size */
- timeout);
+ timeout /* timeout */
+ );
if (ret < 0) {
printk("%s: could not set ts feed\n", dev->name);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 3852430d026..40774feb895 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -231,12 +231,8 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
- devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "dvb/adapter%d/%s%d", adap->num, dnames[type], id);
-
class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+ adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
@@ -252,9 +248,6 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
if (!dvbdev)
return;
- devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
- dnames[dvbdev->type], dvbdev->id);
-
class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num,
dvbdev->type, dvbdev->id)));
@@ -285,7 +278,7 @@ skip:
}
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
{
int num;
@@ -302,10 +295,10 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu
printk ("DVB: registering new adapter (%s).\n", name);
- devfs_mk_dir("dvb/adapter%d", num);
adap->num = num;
adap->name = name;
adap->module = module;
+ adap->device = device;
list_add_tail (&adap->list_head, &dvb_adapter_list);
@@ -318,8 +311,6 @@ EXPORT_SYMBOL(dvb_register_adapter);
int dvb_unregister_adapter(struct dvb_adapter *adap)
{
- devfs_remove("dvb/adapter%d", adap->num);
-
if (mutex_lock_interruptible(&dvbdev_register_lock))
return -ERESTARTSYS;
list_del (&adap->list_head);
@@ -409,8 +400,6 @@ static int __init init_dvbdev(void)
goto error;
}
- devfs_mk_dir("dvb");
-
dvb_class = class_create(THIS_MODULE, "dvb");
if (IS_ERR(dvb_class)) {
retval = PTR_ERR(dvb_class);
@@ -427,7 +416,6 @@ error:
static void __exit exit_dvbdev(void)
{
- devfs_remove("dvb");
class_destroy(dvb_class);
cdev_del(&dvb_device_cdev);
unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 74ed5853f0f..7a7f75fd168 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -27,7 +27,6 @@
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/list.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/smp_lock.h>
#define DVB_MAJOR 212
@@ -51,6 +50,8 @@ struct dvb_adapter {
u8 proposed_mac [6];
void* priv;
+ struct device *device;
+
struct module *module;
};
@@ -76,7 +77,7 @@ struct dvb_device {
};
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
extern int dvb_register_device (struct dvb_adapter *adap,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index e388fb1567d..75824b77198 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -2,6 +2,7 @@ config DVB_USB
tristate "Support for various USB DVB devices"
depends on DVB_CORE && USB && I2C
select FW_LOADER
+ select DVB_PLL
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -88,6 +89,7 @@ config DVB_USB_CXUSB
select DVB_CX22702
select DVB_LGDT330X
select DVB_MT352
+ select DVB_ZL10353
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -130,6 +132,15 @@ config DVB_USB_VP702X
DVB-S USB2.0 receivers.
+config DVB_USB_GP8PSK
+ tristate "GENPIX 8PSK->USB module support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+ GENPIX 8psk module
+
+ DVB-S USB2.0 receivers.
+
config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 2dc9aad9681..9643f56c7fe 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -7,6 +7,9 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
+dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 1f0d3e995c8..ae23bdde42a 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -27,8 +27,10 @@
#include "cx22702.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
#include "mt352.h"
#include "mt352_priv.h"
+#include "zl10353.h"
/* debug */
int dvb_usb_cxusb_debug;
@@ -322,32 +324,37 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
return 0;
}
+static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+ return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+}
+
static struct cx22702_config cxusb_cx22702_config = {
.demod_address = 0x63,
.output_mode = CX22702_PARALLEL_OUTPUT,
-
- .pll_init = dvb_usb_pll_init_i2c,
- .pll_set = dvb_usb_pll_set_i2c,
};
static struct lgdt330x_config cxusb_lgdt3303_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
- .pll_set = dvb_usb_pll_set_i2c,
};
static struct mt352_config cxusb_dee1601_config = {
.demod_address = 0x0f,
.demod_init = cxusb_dee1601_demod_init,
- .pll_set = dvb_usb_pll_set,
};
-struct mt352_config cxusb_mt352_config = {
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+ .demod_address = 0x0f,
+};
+
+static struct mt352_config cxusb_mt352_config = {
/* used in both lgz201 and th7579 */
.demod_address = 0x0f,
.demod_init = cxusb_mt352_demod_init,
- .pll_set = dvb_usb_pll_set,
};
/* Callbacks for DVB USB */
@@ -357,17 +364,10 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
d->pll_addr = 0x61;
memcpy(d->pll_init, bpll, 4);
d->pll_desc = &dvb_pll_fmd1216me;
- return 0;
-}
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
-{
- u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
- /* bpll[2] : unset bit 3, set bits 4&5
- bpll[3] : 0x50 - digital, 0x20 - analog */
- d->pll_addr = 0x61;
- memcpy(d->pll_init, bpll, 4);
- d->pll_desc = &dvb_pll_tdvs_tua6034;
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
return 0;
}
@@ -375,6 +375,7 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_thomson_dtt7579;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
@@ -382,6 +383,7 @@ static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_lg_z201;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
@@ -389,6 +391,13 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d)
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_thomson_dtt7579;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+}
+
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+{
+ d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
return 0;
}
@@ -439,7 +448,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+ if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+ ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
return 0;
return -EIO;
@@ -555,7 +565,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
.streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_lgdt3303_frontend_attach,
- .tuner_attach = cxusb_lgh064f_tuner_attach,
+ .tuner_attach = cxusb_lgdt3303_tuner_attach,
.i2c_algo = &cxusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index 2d52b76671d..abd75b4a350 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -173,11 +173,10 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
struct dib3000_config demod_cfg;
struct dibusb_state *st = d->priv;
- demod_cfg.pll_set = dvb_usb_pll_set_i2c;
- demod_cfg.pll_init = dvb_usb_pll_init_i2c;
-
for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
return 0;
}
@@ -190,6 +189,10 @@ int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_env57h1xd5;
+
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
return 0;
}
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index dd5a1319588..f4c45f386eb 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -20,11 +20,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
struct dibusb_state *st = d->priv;
demod_cfg.demod_address = 0x8;
- demod_cfg.pll_set = dvb_usb_pll_set_i2c;
- demod_cfg.pll_init = dvb_usb_pll_init_i2c;
- if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+ if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
return -ENODEV;
+ }
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index 91136c00ce9..c14d9efb48f 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -112,27 +112,30 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe)
static struct mt352_config digitv_mt352_config = {
.demod_init = digitv_mt352_demod_init,
- .pll_set = dvb_usb_pll_set,
};
-static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
u8 b[5];
- dvb_usb_pll_set(fe,fep,b);
+ dvb_usb_tuner_calc_regs(fe,fep,b, 5);
return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
}
static struct nxt6000_config digitv_nxt6000_config = {
.clock_inversion = 1,
- .pll_set = digitv_nxt6000_pll_set,
};
static int digitv_frontend_attach(struct dvb_usb_device *d)
{
- if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL ||
- (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL)
+ if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
+ }
+ if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+ d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ return 0;
+ }
return -EIO;
}
diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index cd21ddbfd05..17413adec7a 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -18,7 +18,6 @@ struct dtt200u_fe_state {
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
};
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
@@ -163,16 +162,13 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
deb_info("attaching frontend dtt200u\n");
state->d = d;
- memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
- goto success;
+ return &state->frontend;
error:
return NULL;
-success:
- return &state->frontend;
}
static struct dvb_frontend_ops dtt200u_fe_ops = {
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index 6fa92100248..ec631708c39 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -82,7 +82,7 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
int ret;
if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
- d->owner)) < 0) {
+ d->owner, &d->udev->dev)) < 0) {
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
@@ -121,16 +121,15 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d)
dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
- goto success;
+ d->state |= DVB_USB_STATE_DVB;
+ return 0;
+
err_dmx_dev:
dvb_dmx_release(&d->demux);
err_dmx:
dvb_unregister_adapter(&d->dvb_adap);
err:
return ret;
-success:
- d->state |= DVB_USB_STATE_DVB;
- return 0;
}
int dvb_usb_dvb_exit(struct dvb_usb_device *d)
@@ -184,13 +183,13 @@ int dvb_usb_fe_init(struct dvb_usb_device* d)
/* re-assign sleep and wakeup functions */
if (d->fe != NULL) {
- d->fe_init = d->fe->ops->init; d->fe->ops->init = dvb_usb_fe_wakeup;
- d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+ d->fe_init = d->fe->ops.init; d->fe->ops.init = dvb_usb_fe_wakeup;
+ d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
err("Frontend registration failed.");
- if (d->fe->ops->release)
- d->fe->ops->release(d->fe);
+ if (d->fe->ops.release)
+ d->fe->ops.release(d->fe);
d->fe = NULL;
return -ENODEV;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 9b254532af4..6b611a72509 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -46,7 +46,7 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
return 0;
}
-int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
{
struct dvb_usb_device *d = fe->dvb->priv;
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
@@ -63,6 +63,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
d->pll_init[2],d->pll_init[3]);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_init.");
ret = -EREMOTEIO;
@@ -73,38 +75,42 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
d->tuner_pass_ctrl(fe,0,d->pll_addr);
return ret;
}
-EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
{
struct dvb_usb_device *d = fe->dvb->priv;
+ if (buf_len != 5)
+ return -EINVAL;
if (d->pll_desc == NULL)
return 0;
deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
- b[0] = d->pll_addr << 1;
+ b[0] = d->pll_addr;
dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
- return 0;
+ return 5;
}
-EXPORT_SYMBOL(dvb_usb_pll_set);
+EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
int ret = 0;
u8 b[5];
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
- dvb_usb_pll_set(fe,fep,b);
+ dvb_usb_tuner_calc_regs(fe,fep,b,5);
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,1,d->pll_addr);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_set.");
ret = -EREMOTEIO;
@@ -116,4 +122,4 @@ int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters
return ret;
}
-EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index cb239049b09..95698918bc1 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -31,6 +31,7 @@
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+#define USB_VID_GENPIX 0x09c0
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
@@ -104,5 +105,6 @@
#define USB_PID_KYE_DVB_T_WARM 0x701f
#define USB_PID_PCTV_200E 0x020e
#define USB_PID_PCTV_400E 0x020f
-
+#define USB_PID_GENPIX_8PSK_COLD 0x0200
+#define USB_PID_GENPIX_8PSK_WARM 0x0201
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 9002f35aa95..88b283731bb 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -80,7 +80,6 @@ static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
switch (urb->status) {
case 0: /* success */
- case -ETIMEDOUT: /* NAK */
break;
case -ECONNRESET: /* kill */
case -ENOENT:
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index fead958a57e..97f8ea96243 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -8,7 +8,6 @@
#ifndef __DVB_USB_H__
#define __DVB_USB_H__
-#include <linux/config.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/firmware.h>
@@ -330,9 +329,9 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
/* commonly used pll init and set functions */
-extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
-extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
+extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
/* commonly used firmware download types and function */
struct hexline {
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
new file mode 100644
index 00000000000..6ccbdc9cd77
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -0,0 +1,272 @@
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+struct gp8psk_fe_state {
+ struct dvb_frontend fe;
+
+ struct dvb_usb_device *d;
+
+ u16 snr;
+
+ unsigned long next_snr_check;
+};
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 lock;
+
+ if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
+ return -EINVAL;
+
+ if (lock)
+ *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ else
+ *status = 0;
+
+ return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+ (void) fe;
+ *ber = 0;
+ return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+ (void) fe;
+ *unc = 0;
+ return 0;
+}
+
+static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 buf[2];
+
+ if (time_after(jiffies,st->next_snr_check)) {
+ gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
+ *snr = (int)(buf[1]) << 8 | buf[0];
+ /* snr is reported in dBu*256 */
+ /* snr / 38.4 ~= 100% strength */
+ /* snr * 17 returns 100% strength as 65535 */
+ if (*snr <= 3855)
+ *snr = (*snr<<4) + *snr; // snr * 17
+ else
+ *snr = 65535;
+ st->next_snr_check = jiffies + (10*HZ)/1000;
+ } else {
+ *snr = st->snr;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+ return gp8psk_fe_read_snr(fe, strength);
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 800;
+ return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ u8 cmd[10];
+ u32 freq = fep->frequency * 1000;
+
+ cmd[4] = freq & 0xff;
+ cmd[5] = (freq >> 8) & 0xff;
+ cmd[6] = (freq >> 16) & 0xff;
+ cmd[7] = (freq >> 24) & 0xff;
+
+ switch(fe->ops.info.type) {
+ case FE_QPSK:
+ cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
+ cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
+ cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
+ cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
+ cmd[8] = ADV_MOD_DVB_QPSK;
+ cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+ break;
+ default:
+ // other modes are unsuported right now
+ cmd[0] = 0;
+ cmd[1] = 0;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ cmd[8] = 0;
+ cmd[9] = 0;
+ break;
+ }
+
+ gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+
+ state->next_snr_check = jiffies;
+
+ return 0;
+}
+
+static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ return 0;
+}
+
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+ deb_fe("%s\n",__FUNCTION__);
+
+ if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+ m->msg, m->msg_len)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+ fe_sec_mini_cmd_t burst)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 cmd;
+
+ deb_fe("%s\n",__FUNCTION__);
+
+ /* These commands are certainly wrong */
+ cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+ if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+ &cmd, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+ if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+ (tone == SEC_TONE_ON), 0, NULL, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+ if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+ voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+ u8 cmd = sw_cmd & 0x7f;
+
+ if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+ NULL, 0)) {
+ return -EINVAL;
+ }
+ if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+ 0, NULL, 0)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+ struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+ if (s == NULL)
+ goto error;
+
+ s->d = d;
+ memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+ s->fe.demodulator_priv = s;
+
+ goto success;
+error:
+ return NULL;
+success:
+ return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+ .info = {
+ .name = "Genpix 8psk-USB DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 100,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500, /* ppm */
+ .caps = FE_CAN_INVERSION_AUTO |
+ 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_QPSK
+ },
+
+ .release = gp8psk_fe_release,
+
+ .init = NULL,
+ .sleep = NULL,
+
+ .set_frontend = gp8psk_fe_set_frontend,
+ .get_frontend = gp8psk_fe_get_frontend,
+ .get_tune_settings = gp8psk_fe_get_tune_settings,
+
+ .read_status = gp8psk_fe_read_status,
+ .read_ber = gp8psk_fe_read_ber,
+ .read_signal_strength = gp8psk_fe_read_signal_strength,
+ .read_snr = gp8psk_fe_read_snr,
+ .read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+ .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+ .diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+ .set_tone = gp8psk_fe_set_tone,
+ .set_voltage = gp8psk_fe_set_voltage,
+ .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+};
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
new file mode 100644
index 00000000000..9a98f3fdae3
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -0,0 +1,256 @@
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+ int ret = 0,try = 0;
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ while (ret >= 0 && ret != blen && try < 3) {
+ ret = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value,index,b,blen,
+ 2000);
+ deb_info("reading number %d (ret: %d)\n",try,ret);
+ try++;
+ }
+
+ if (ret < 0 || ret != blen) {
+ warn("usb in operation failed.");
+ ret = -EIO;
+ } else
+ ret = 0;
+
+ deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ if (usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value,index,b,blen,
+ 2000) != blen) {
+ warn("usb out operation failed.");
+ ret = -EIO;
+ } else
+ ret = 0;
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+ int ret;
+ const struct firmware *fw = NULL;
+ u8 *ptr, *buf;
+ if ((ret = request_firmware(&fw, bcm4500_firmware,
+ &d->udev->dev)) != 0) {
+ err("did not find the bcm4500 firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+ bcm4500_firmware,ret);
+ return ret;
+ }
+
+ ret = -EINVAL;
+
+ if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
+ goto out_rel_fw;
+
+ info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+
+ ptr = fw->data;
+ buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+
+ while (ptr[0] != 0xff) {
+ u16 buflen = ptr[0] + 4;
+ if (ptr + buflen >= fw->data + fw->size) {
+ err("failed to load bcm4500 firmware.");
+ goto out_free;
+ }
+ memcpy(buf, ptr, buflen);
+ if (dvb_usb_generic_write(d, buf, buflen)) {
+ err("failed to load bcm4500 firmware.");
+ goto out_free;
+ }
+ ptr += buflen;
+ }
+
+ ret = 0;
+
+out_free:
+ kfree(buf);
+out_rel_fw:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 status, buf;
+ if (onoff) {
+ gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ if (! (status & 0x01)) /* started */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+ return -EINVAL;
+
+ if (! (status & 0x02)) /* BCM4500 firmware loaded */
+ if(gp8psk_load_bcm4500fw(d))
+ return EINVAL;
+
+ if (! (status & 0x04)) /* LNB Power */
+ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
+ &buf, 1))
+ return EINVAL;
+
+ /* Set DVB mode */
+ if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+ return -EINVAL;
+ gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ } else {
+ /* Turn off LNB power */
+ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+ return EINVAL;
+ /* Turn off 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+ return -EINVAL;
+
+ }
+ return 0;
+}
+
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+{
+ d->fe = gp8psk_fe_attach(d);
+
+ return 0;
+}
+
+static struct dvb_usb_properties gp8psk_properties;
+
+static int gp8psk_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id gp8psk_usb_table [] = {
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_properties gp8psk_properties = {
+ .caps = 0,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-gp8psk-01.fw",
+
+ .streaming_ctrl = gp8psk_streaming_ctrl,
+ .power_ctrl = gp8psk_power_ctrl,
+ .frontend_attach = gp8psk_frontend_attach,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+ .cold_ids = { &gp8psk_usb_table[0], NULL },
+ .warm_ids = { &gp8psk_usb_table[1], NULL },
+ },
+ { 0 },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+ .name = "dvb_usb_gp8psk",
+ .probe = gp8psk_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = gp8psk_usb_table,
+};
+
+/* module stuff */
+static int __init gp8psk_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&gp8psk_usb_driver))) {
+ err("usb_register failed. (%d)",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit gp8psk_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&gp8psk_usb_driver);
+}
+
+module_init(gp8psk_usb_module_init);
+module_exit(gp8psk_usb_module_exit);
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
new file mode 100644
index 00000000000..3eba7061011
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -0,0 +1,79 @@
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
+/* gp8psk commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN 0xC0
+#define TH_COMMAND_OUT 0xC1
+
+/* command bytes */
+#define GET_8PSK_CONFIG 0x80
+#define SET_8PSK_CONFIG 0x81
+#define ARM_TRANSFER 0x85
+#define TUNE_8PSK 0x86
+#define GET_SIGNAL_STRENGTH 0x87
+#define LOAD_BCM4500 0x88
+#define BOOT_8PSK 0x89
+#define START_INTERSIL 0x8A
+#define SET_LNB_VOLTAGE 0x8B
+#define SET_22KHZ_TONE 0x8C
+#define SEND_DISEQC_COMMAND 0x8D
+#define SET_DVB_MODE 0x8E
+#define SET_DN_SWITCH 0x8F
+#define GET_SIGNAL_LOCK 0x90
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */
+
+#define GET_USB_SPEED 0x07
+ #define USB_SPEED_LOW 0
+ #define USB_SPEED_FULL 1
+ #define USB_SPEED_HIGH 2
+
+#define RESET_FX2 0x13
+
+#define FW_VERSION_READ 0x0B
+#define VENDOR_STRING_READ 0x0C
+#define PRODUCT_STRING_READ 0x0D
+#define FW_BCD_VERSION_READ 0x14
+
+extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 14f1911c79b..97d74da0dad 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -57,7 +57,6 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
memset(&umt_config,0,sizeof(struct mt352_config));
umt_config.demod_init = umt_mt352_demod_init;
umt_config.demod_address = 0xf;
- umt_config.pll_set = dvb_usb_pll_set;
d->fe = mt352_attach(&umt_config, &d->i2c_adap);
@@ -68,6 +67,7 @@ static int umt_tuner_attach (struct dvb_usb_device *d)
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_tua6034;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index 2a89f8c5da9..d4da494132e 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -287,17 +287,16 @@ struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d)
goto error;
s->d = d;
- s->fe.ops = &vp702x_fe_ops;
+
+ memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
s->fe.demodulator_priv = s;
s->lnb_buf[1] = SET_LNB_POWER;
s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
- goto success;
+ return &s->fe;
error:
return NULL;
-success:
- return &s->fe;
}
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
index 9999336aeeb..8452eef9032 100644
--- a/drivers/media/dvb/dvb-usb/vp7045-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c
@@ -23,8 +23,6 @@
struct vp7045_fe_state {
struct dvb_frontend fe;
- struct dvb_frontend_ops ops;
-
struct dvb_usb_device *d;
};
@@ -151,15 +149,12 @@ struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
goto error;
s->d = d;
- memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
- s->fe.ops = &s->ops;
+ memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
s->fe.demodulator_priv = s;
- goto success;
+ return &s->fe;
error:
return NULL;
-success:
- return &s->fe;
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 37d5e0af168..db978555b1e 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -6,43 +6,43 @@ comment "DVB-S (satellite) frontends"
config DVB_STV0299
tristate "ST STV0299 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_CX24110
tristate "Conexant CX24110 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_CX24123
tristate "Conexant CX24123 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA8083
tristate "Philips TDA8083 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_MT312
tristate "Zarlink VP310/MT312 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_VES1X93
tristate "VLSI VES1893 or VES1993 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_S5H1420
tristate "Samsung S5H1420 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-S tuner module. Say Y when you want to support this frontend.
@@ -51,7 +51,7 @@ comment "DVB-T (terrestrial) frontends"
config DVB_SP8870
tristate "Spase sp8870 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -63,7 +63,7 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -75,25 +75,25 @@ config DVB_SP887X
config DVB_CX22700
tristate "Conexant CX22700 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_CX22702
tristate "Conexant cx22702 demodulator (OFDM)"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_L64781
tristate "LSI L64781"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -106,32 +106,32 @@ config DVB_TDA1004X
config DVB_NXT6000
tristate "NxtWave Communications NXT6000 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_MT352
tristate "Zarlink MT352 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_ZL10353
tristate "Zarlink ZL10353 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DIB3000MB
tristate "DiBcom 3000M-B"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
config DVB_DIB3000MC
tristate "DiBcom 3000P/M-C"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
@@ -141,28 +141,28 @@ comment "DVB-C (cable) frontends"
config DVB_VES1820
tristate "VLSI VES1820 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_TDA10021
tristate "Philips TDA10021 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_STV0297
tristate "ST STV0297 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
A DVB-C tuner module. Say Y when you want to support this frontend.
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
depends on DVB_CORE
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -176,7 +176,7 @@ config DVB_NXT200X
config DVB_OR51211
tristate "Oren OR51211 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -188,7 +188,7 @@ config DVB_OR51211
config DVB_OR51132
tristate "Oren OR51132 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -203,7 +203,7 @@ config DVB_OR51132
config DVB_BCM3510
tristate "Broadcom BCM3510"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
select FW_LOADER
help
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
@@ -211,9 +211,29 @@ config DVB_BCM3510
config DVB_LGDT330X
tristate "LG Electronics LGDT3302/LGDT3303 based"
- depends on DVB_CORE
+ depends on DVB_CORE && I2C
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+
+comment "Miscellaneous devices"
+ depends on DVB_CORE
+
+config DVB_PLL
+ tristate
+ depends on DVB_CORE && I2C
+
+config DVB_LNBP21
+ tristate "LNBP21 SEC controller"
+ depends on DVB_CORE && I2C
+ help
+ An SEC control chip.
+
+config DVB_ISL6421
+ tristate "ISL6421 SEC controller"
+ depends on DVB_CORE && I2C
+ help
+ An SEC control chip.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index d09b6071fba..0e4880b6db1 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -4,7 +4,7 @@
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/
-obj-$(CONFIG_DVB_CORE) += dvb-pll.o
+obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
@@ -31,3 +31,5 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
index 1708a1d4893..baeb311de89 100644
--- a/drivers/media/dvb/frontends/bcm3510.c
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -48,7 +48,6 @@
struct bcm3510_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct bcm3510_config* config;
struct dvb_frontend frontend;
@@ -791,10 +790,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
mutex_init(&state->hab_mutex);
diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h
index 78573b22ada..d8f65738e5d 100644
--- a/drivers/media/dvb/frontends/bsbe1.h
+++ b/drivers/media/dvb/frontends/bsbe1.h
@@ -89,12 +89,13 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, 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) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -105,6 +106,8 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c,
data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(i2c, &msg, 1);
return (ret != 1) ? -EIO : 0;
}
@@ -117,7 +120,6 @@ static struct stv0299_config alps_bsbe1_config = {
.skip_reinit = 0,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsbe1_set_symbol_rate,
- .pll_set = alps_bsbe1_pll_set,
};
#endif
diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h
index 2a5366ce79c..e231cd84b3a 100644
--- a/drivers/media/dvb/frontends/bsru6.h
+++ b/drivers/media/dvb/frontends/bsru6.h
@@ -101,11 +101,12 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra
return 0;
}
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -119,6 +120,8 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c,
if (params->frequency > 1530000)
buf[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
return 0;
@@ -134,7 +137,6 @@ static struct stv0299_config alps_bsru6_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
};
#endif
diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c
index 755f774f6b7..13ad1bfae66 100644
--- a/drivers/media/dvb/frontends/cx22700.c
+++ b/drivers/media/dvb/frontends/cx22700.c
@@ -34,8 +34,6 @@ struct cx22700_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx22700_config* config;
struct dvb_frontend frontend;
@@ -136,6 +134,7 @@ static int cx22700_set_tps (struct cx22700_state *state, struct dvb_ofdm_paramet
return -EINVAL;
if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8)
+ return -EINVAL;
if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5)
return -EINVAL;
@@ -247,12 +246,6 @@ static int cx22700_init (struct dvb_frontend* fe)
cx22700_writereg (state, 0x00, 0x01);
- if (state->config->pll_init) {
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_init(fe);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
- }
-
return 0;
}
@@ -333,9 +326,11 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
cx22700_writereg (state, 0x00, 0x00);
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_set(fe, p);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx22700_set_inversion (state, p->inversion);
cx22700_set_tps (state, &p->u.ofdm);
cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
@@ -353,6 +348,17 @@ static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return cx22700_get_tps (state, &p->u.ofdm);
}
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct cx22700_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return cx22700_writereg(state, 0x0a, 0x00);
+ } else {
+ return cx22700_writereg(state, 0x0a, 0x01);
+ }
+}
+
static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 150;
@@ -381,13 +387,12 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (cx22700_readreg(state, 0x07) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -413,6 +418,7 @@ static struct dvb_frontend_ops cx22700_ops = {
.release = cx22700_release,
.init = cx22700_init,
+ .i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
.set_frontend = cx22700_set_frontend,
.get_frontend = cx22700_get_frontend,
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index c9145b45874..dcd8979c1a1 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -29,10 +29,6 @@ struct cx22700_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 0fc899f81c5..4106d46c957 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -40,8 +40,6 @@ struct cx22702_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct cx22702_config* config;
@@ -211,22 +209,10 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
u8 val;
struct cx22702_state* state = fe->demodulator_priv;
- /* set PLL */
- cx22702_i2c_gate_ctrl(fe, 1);
- if (state->config->pll_set) {
- state->config->pll_set(fe, p);
- } else if (state->config->pll_desc) {
- u8 pllbuf[4];
- struct i2c_msg msg = { .addr = state->config->pll_address,
- .buf = pllbuf, .len = 4 };
- dvb_pll_configure(state->config->pll_desc, pllbuf,
- p->frequency,
- p->u.ofdm.bandwidth);
- i2c_transfer(state->i2c, &msg, 1);
- } else {
- BUG();
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- cx22702_i2c_gate_ctrl(fe, 0);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
@@ -358,10 +344,6 @@ static int cx22702_init (struct dvb_frontend* fe)
cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
- /* init PLL */
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
cx22702_i2c_gate_ctrl(fe, 0);
return 0;
@@ -495,7 +477,6 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->prevUCBlocks = 0;
/* check if the demod is there */
@@ -503,7 +484,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -530,6 +511,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.release = cx22702_release,
.init = cx22702_init,
+ .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
.set_frontend = cx22702_set_tps,
.get_frontend = cx22702_get_frontend,
@@ -540,7 +522,6 @@ static struct dvb_frontend_ops cx22702_ops = {
.read_signal_strength = cx22702_read_signal_strength,
.read_snr = cx22702_read_snr,
.read_ucblocks = cx22702_read_ucblocks,
- .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
};
module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 5633976a58f..7f2f241e5d4 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -39,13 +39,6 @@ struct cx22702_config
#define CX22702_PARALLEL_OUTPUT 0
#define CX22702_SERIAL_OUTPUT 1
u8 output_mode;
-
- /* PLL maintenance */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index f3edf8b517d..ce3c7398bac 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -36,8 +36,6 @@ struct cx24110_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx24110_config* config;
struct dvb_frontend frontend;
@@ -250,7 +248,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
int i;
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
if (srate>90999000UL/2)
srate=90999000UL/2;
if (srate<500000)
@@ -366,17 +364,6 @@ static int cx24110_initfe(struct dvb_frontend* fe)
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
};
- if (state->config->pll_init) state->config->pll_init(fe);
-
- return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
- struct cx24110_state *state = fe->demodulator_priv;
-
- if (state->config->pll_sleep)
- return state->config->pll_sleep(fe);
return 0;
}
@@ -548,7 +535,12 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct cx24110_state *state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx24110_set_inversion (state, p->inversion);
cx24110_set_fec (state, p->u.qpsk.fec_inner);
cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -612,7 +604,6 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->lastbler = 0;
state->lastesn0 = 0;
@@ -622,7 +613,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
if ((ret != 0x5a) && (ret != 0x69)) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -651,7 +642,6 @@ static struct dvb_frontend_ops cx24110_ops = {
.release = cx24110_release,
.init = cx24110_initfe,
- .sleep = cx24110_sleep,
.set_frontend = cx24110_set_frontend,
.get_frontend = cx24110_get_frontend,
.read_status = cx24110_read_status,
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index 609ac642b40..b354a64e0e7 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -31,11 +31,6 @@ struct cx24110_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
- int (*pll_sleep)(struct dvb_frontend* fe);
};
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 691dc840dcc..274a87b7a5d 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -41,14 +41,12 @@ static int debug;
struct cx24123_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct cx24123_config* config;
struct dvb_frontend frontend;
u32 lastber;
u16 snr;
- u8 lnbreg;
/* Some PLL specifics for tuning */
u32 VCAarg;
@@ -249,29 +247,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
return 0;
}
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
- u8 buf[] = { reg, data };
- /* fixme: put the intersil addr int the config */
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
- int err;
-
- if (debug>1)
- printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
- __FUNCTION__,reg, data);
-
- if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
- printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
- return -EREMOTEIO;
- }
-
- /* cache the write, no way to read back */
- state->lnbreg = data;
-
- return 0;
-}
-
static int cx24123_readreg(struct cx24123_state* state, u8 reg)
{
int ret;
@@ -295,11 +270,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg)
return b1[0];
}
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
- return state->lnbreg;
-}
-
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -458,8 +428,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
u8 pll_mult;
/* check if symbol rate is within limits */
- if ((srate > state->ops.info.symbol_rate_max) ||
- (srate < state->ops.info.symbol_rate_min))
+ if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+ (srate < state->frontend.ops.info.symbol_rate_min))
return -EOPNOTSUPP;;
/* choose the sampling rate high enough for the required operation,
@@ -687,13 +657,6 @@ static int cx24123_initfe(struct dvb_frontend* fe)
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
- /* Configure the LNB for 14V */
- if (state->config->use_isl6421)
- cx24123_writelnbreg(state, 0x0, 0x2a);
-
return 0;
}
@@ -702,50 +665,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
-
- case 1:
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
- case SEC_VOLTAGE_18:
- dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
- case SEC_VOLTAGE_OFF:
- dprintk("%s: isl5421 voltage off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x30);
- default:
- return -EINVAL;
- };
-
- case 0:
-
- val = cx24123_readreg(state, 0x29);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: setting voltage 13V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val | 0x80);
- case SEC_VOLTAGE_18:
- dprintk("%s: setting voltage 18V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val & 0x7f);
- case SEC_VOLTAGE_OFF:
- dprintk("%s: setting voltage off\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 0);
- return 0;
- default:
- return -EINVAL;
- };
- }
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0x7f);
+ case SEC_VOLTAGE_18:
+ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x80);
+ default:
+ return -EINVAL;
+ };
return 0;
}
@@ -766,27 +697,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
{
struct cx24123_state *state = fe->demodulator_priv;
- int i, val;
+ int i, val, tone;
dprintk("%s:\n",__FUNCTION__);
- /* check if continuous tone has been stopped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
/* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
for (i = 0; i < cmd->msg_len; i++)
cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
@@ -797,36 +721,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
/* wait for diseqc message to finish sending */
cx24123_wait_for_diseqc(state);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
+
return 0;
}
static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{
struct cx24123_state *state = fe->demodulator_priv;
- int val;
+ int val, tone;
dprintk("%s:\n", __FUNCTION__);
- /* check if continuous tone has been stoped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
+ /* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- val = cx24123_readreg(state, 0x2a) & 0xf8;
- cx24123_writereg(state, 0x2a, val | 0x04);
-
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+ msleep(30);
val = cx24123_readreg(state, 0x29);
-
if (burst == SEC_MINI_A)
cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
else if (burst == SEC_MINI_B)
@@ -835,7 +756,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
return -EINVAL;
cx24123_wait_for_diseqc(state);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
return 0;
}
@@ -976,38 +902,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
- case 1:
-
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: isl6421 sec tone on\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: isl6421 sec tone off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x2f);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
-
- case 0:
+ /* wait for diseqc queue ready */
+ cx24123_wait_for_diseqc(state);
- val = cx24123_readreg(state, 0x29);
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: setting tone on\n", __FUNCTION__);
- return cx24123_writereg(state, 0x29, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: setting tone off\n",__FUNCTION__);
- return cx24123_writereg(state, 0x29, val & 0xef);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
+ switch (tone) {
+ case SEC_TONE_ON:
+ dprintk("%s: setting tone on\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x10);
+ case SEC_TONE_OFF:
+ dprintk("%s: setting tone off\n",__FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0xef);
+ default:
+ printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ return -EINVAL;
}
return 0;
@@ -1040,10 +949,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->snr = 0;
- state->lnbreg = 0;
state->VCAarg = 0;
state->VGAarg = 0;
state->bandselectarg = 0;
@@ -1059,7 +966,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 0c922b5e926..9606f825935 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -28,21 +28,8 @@ struct cx24123_config
/* the demodulator's i2c address */
u8 demod_address;
- /*
- cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
- for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
- from register 0x29 of the CX24123 demodulator
- */
- int use_isl6421;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
- void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
};
extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
index c31d6df1547..be1c0d3e138 100644
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ b/drivers/media/dvb/frontends/dib3000-common.h
@@ -38,8 +38,6 @@
struct dib3000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
struct dib3000_config config;
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index 2d5475b5c06..ec927628d27 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -30,10 +30,6 @@ struct dib3000_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance and the i2c address of the PLL */
- int (*pll_init)(struct dvb_frontend *fe);
- int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
};
struct dib_fe_xfer_ops
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ae589adb1c0..5302e11883a 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -21,7 +21,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -60,8 +59,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
- if (tuner && state->config.pll_set) {
- state->config.pll_set(fe, fep);
+ if (tuner && fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
@@ -386,9 +386,6 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
return 0;
}
@@ -707,7 +704,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -717,7 +713,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 3b303dbb615..98673474a14 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -20,7 +20,6 @@
* see Documentation/dvb/README.dibusb for more information
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -462,8 +461,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
int search_state,auto_val;
u16 val;
- if (tuner && state->config.pll_set) { /* initial call from dvb */
- state->config.pll_set(fe,fep);
+ if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
state->last_tuned_freq = fep->frequency;
// if (!scanboost) {
@@ -642,9 +642,6 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
deb_info("init end\n");
return 0;
}
@@ -839,7 +836,6 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
@@ -859,7 +855,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
@@ -876,6 +872,7 @@ error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(dib3000mc_attach);
static struct dvb_frontend_ops dib3000mc_ops = {
@@ -914,5 +911,3 @@ static struct dvb_frontend_ops dib3000mc_ops = {
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 791706ec1da..2be33f27c69 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -194,11 +194,11 @@ struct dvb_pll_desc dvb_pll_tda665x = {
{ 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
{ 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
{ 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
- { 444000000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
- { 583834000, 36249333, 166667, 0xca, 0x63 /* 011 0 0 0 11 */ },
- { 793834000, 36249333, 166667, 0xca, 0xa3 /* 101 0 0 0 11 */ },
- { 444834000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
- { 861000000, 36249333, 166667, 0xca, 0xe3 /* 111 0 0 0 11 */ },
+ { 444000000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
+ { 583834000, 36249333, 166667, 0xca, 0x64 /* 011 0 0 1 00 */ },
+ { 793834000, 36249333, 166667, 0xca, 0xa4 /* 101 0 0 1 00 */ },
+ { 444834000, 36249333, 166667, 0xca, 0xc4 /* 110 0 0 1 00 */ },
+ { 861000000, 36249333, 166667, 0xca, 0xe4 /* 111 0 0 1 00 */ },
}
};
EXPORT_SYMBOL(dvb_pll_tda665x);
@@ -227,10 +227,10 @@ struct dvb_pll_desc dvb_pll_tua6034 = {
EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
- .name = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+ .name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
.count = 3,
@@ -240,7 +240,7 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
{ 999999999, 44000000, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
@@ -419,6 +419,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
};
EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+struct dvb_pll_priv {
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
/* ----------------------------------------------------------- */
/* code */
@@ -443,7 +456,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
if (debug)
printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
desc->name, freq, bandwidth, i, desc->count);
- BUG_ON(i == desc->count);
+ if (i == desc->count)
+ return -EINVAL;
div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
buf[0] = div >> 8;
@@ -462,6 +476,177 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
}
EXPORT_SYMBOL(dvb_pll_configure);
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+ if (fe->tuner_priv)
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int i;
+ int result;
+
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (priv->pll_desc->entries[i].limit == 0)
+ break;
+ }
+ if (i == priv->pll_desc->count)
+ return 0;
+
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = priv->pll_desc->entries[i].config;
+ buf[3] = priv->pll_desc->entries[i].cb;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+ return result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (buf_len < 5)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+ return result;
+ buf[0] = priv->pll_i2c_address;
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+ .release = dvb_pll_release,
+ .sleep = dvb_pll_sleep,
+ .set_params = dvb_pll_set_params,
+ .calc_regs = dvb_pll_calc_regs,
+ .get_frequency = dvb_pll_get_frequency,
+ .get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 };
+ struct dvb_pll_priv *priv = NULL;
+ int ret;
+
+ if (i2c != NULL) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = i2c_transfer (i2c, &msg, 1);
+ if (ret != 1)
+ return -1;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->pll_i2c_address = pll_addr;
+ priv->i2c = i2c;
+ priv->pll_desc = desc;
+
+ memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+ strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+ fe->ops.tuner_ops.info.frequency_min = desc->min;
+ fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+ fe->tuner_priv = priv;
+ return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
MODULE_DESCRIPTION("dvb pll library");
MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 2b846178498..66361cd1880 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -5,6 +5,9 @@
#ifndef __DVB_PLL_H__
#define __DVB_PLL_H__
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
struct dvb_pll_desc {
char *name;
u32 min;
@@ -31,7 +34,7 @@ extern struct dvb_pll_desc dvb_pll_unknown_1;
extern struct dvb_pll_desc dvb_pll_tua6010xs;
extern struct dvb_pll_desc dvb_pll_env57h1xd5;
extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
extern struct dvb_pll_desc dvb_pll_tda665x;
extern struct dvb_pll_desc dvb_pll_fmd1216me;
extern struct dvb_pll_desc dvb_pll_tded4;
@@ -44,7 +47,18 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316;
extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
#endif
diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c
index 645946a992d..6271b1e7f6a 100644
--- a/drivers/media/dvb/frontends/dvb_dummy_fe.c
+++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c
@@ -30,7 +30,6 @@
struct dvb_dummy_fe_state {
- struct dvb_frontend_ops ops;
struct dvb_frontend frontend;
};
@@ -77,6 +76,11 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten
static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
+ if (fe->ops->tuner_ops->set_params) {
+ fe->ops->tuner_ops->set_params(fe, p);
+ if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+ }
+
return 0;
}
@@ -116,11 +120,8 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void)
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -139,11 +140,8 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach()
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -162,11 +160,8 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach()
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
new file mode 100644
index 00000000000..58c34db3107
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -0,0 +1,149 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ u8 i2c_addr;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ isl6421->config |= ISL6421_EN1;
+ break;
+ case SEC_VOLTAGE_18:
+ isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ if (arg)
+ isl6421->config |= ISL6421_LLC1;
+ else
+ isl6421->config &= ~ISL6421_LLC1;
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+ /* power off */
+ isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = isl6421->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+{
+ struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+ if (!isl6421)
+ return -ENOMEM;
+
+ /* default configuration */
+ isl6421->config = ISL6421_ISEL1;
+ isl6421->i2c = i2c;
+ isl6421->i2c_addr = i2c_addr;
+ fe->misc_priv = isl6421;
+
+ /* bits which should be forced to '1' */
+ isl6421->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ isl6421->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(isl6421);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ isl6421->release_chain = fe->ops.release;
+ fe->ops.release = isl6421_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = isl6421_set_voltage;
+ fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
new file mode 100644
index 00000000000..675f80a19b9
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -0,0 +1,46 @@
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1 0x01
+#define ISL6421_EN1 0x02
+#define ISL6421_VSEL1 0x04
+#define ISL6421_LLC1 0x08
+#define ISL6421_ENT1 0x10
+#define ISL6421_ISEL1 0x20
+#define ISL6421_DCL 0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear);
+
+#endif
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 1c7c9122447..f3bc82e44a2 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -32,7 +32,6 @@
struct l64781_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct l64781_config* config;
struct dvb_frontend frontend;
@@ -141,7 +140,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa
u8 val0x06;
int bw = p->bandwidth - BANDWIDTH_8_MHZ;
- state->config->pll_set(fe, param);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
if (param->inversion != INVERSION_ON &&
param->inversion != INVERSION_OFF)
@@ -463,8 +465,6 @@ static int l64781_init(struct dvb_frontend* fe)
/* Everything is two's complement, soft bit and CSI_OUT too */
l64781_writereg (state, 0x1e, 0x09);
- if (state->config->pll_init) state->config->pll_init(fe);
-
/* delay a bit after first init attempt */
if (state->first) {
state->first = 0;
@@ -508,7 +508,6 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->first = 1;
/**
@@ -554,7 +553,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 947f65f8746..83b8bc21027 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -29,10 +29,6 @@ struct l64781_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h
new file mode 100644
index 00000000000..754d51d1112
--- /dev/null
+++ b/drivers/media/dvb/frontends/lg_h06xf.h
@@ -0,0 +1,64 @@
+/*
+ * lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ * 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 _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+ struct dvb_frontend_parameters* params)
+{
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+ int err;
+
+ dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %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[0] = buf[2];
+ buf[0] &= ~0x20;
+ buf[0] |= 0x18;
+ buf[1] = 0x50;
+ msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index 4691ac54bc1..9a354708bd2 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -29,6 +29,7 @@
* DViCO FusionHDTV 5 Lite
* DViCO FusionHDTV 5 USB Gold
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ * pcHDTV HD5500
*
* TODO:
* signal strength always returns 0.
@@ -59,7 +60,6 @@ if (debug) printk(KERN_DEBUG "lgdt330x: " args); \
struct lgdt330x_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct lgdt330x_config* config;
@@ -216,7 +216,7 @@ static int lgdt330x_init(struct dvb_frontend* fe)
AGC_DELAY0, 0x07,
AGC_DELAY2, 0xfe,
/* Change the value of IAGCBW[15:8]
- of inner AGC loop filter bandwith */
+ of inner AGC loop filter bandwidth */
AGC_LOOP_BANDWIDTH0, 0x08,
AGC_LOOP_BANDWIDTH1, 0x9a
};
@@ -399,8 +399,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe,
}
/* Tune to the specified frequency */
- if (state->config->pll_set)
- state->config->pll_set(fe, param);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* Keep track of the new frequency */
/* FIXME this is the wrong way to do this... */
@@ -672,6 +674,7 @@ static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr)
if (state->current_modulation == VSB_8) {
+ i2c_read_demod_bytes(state, 0x6e, buf, 5);
/* Phase Tracker Mean-Square Error Register for VSB */
noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
} else {
@@ -721,16 +724,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
+
+ /* Create dvb_frontend */
switch (config->demod_chip) {
case LGDT3302:
- memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
break;
case LGDT3303:
- memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
break;
default:
goto error;
}
+ state->frontend.demodulator_priv = state;
/* Verify communication with demod chip */
if (i2c_read_demod_bytes(state, 2, buf, 1))
@@ -739,9 +745,6 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
state->current_frequency = -1;
state->current_modulation = -1;
- /* Create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index 2a6529cccf1..bad903c6f0f 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -43,7 +43,6 @@ struct lgdt330x_config
/* PLL interface */
int (*pll_rf_set) (struct dvb_frontend* fe, int index);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
new file mode 100644
index 00000000000..e933edc8dd2
--- /dev/null
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -0,0 +1,145 @@
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * 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.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+
+struct lnbp21 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ lnbp21->config |= LNBP21_EN;
+ break;
+ case SEC_VOLTAGE_18:
+ lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ if (arg)
+ lnbp21->config |= LNBP21_LLC;
+ else
+ lnbp21->config &= ~LNBP21_LLC;
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+ /* LNBP power off */
+ lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = lnbp21->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+ if (!lnbp21)
+ return -ENOMEM;
+
+ /* default configuration */
+ lnbp21->config = LNBP21_ISEL;
+ lnbp21->i2c = i2c;
+ fe->misc_priv = lnbp21;
+
+ /* bits which should be forced to '1' */
+ lnbp21->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ lnbp21->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(lnbp21);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ lnbp21->release_chain = fe->ops.release;
+ fe->ops.release = lnbp21_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = lnbp21_set_voltage;
+ fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 0dcbe61b61b..047a4ab68c0 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -27,7 +27,7 @@
#ifndef _LNBP21_H
#define _LNBP21_H
-/* system register */
+/* system register bits */
#define LNBP21_OLF 0x01
#define LNBP21_OTF 0x02
#define LNBP21_EN 0x04
@@ -37,103 +37,9 @@
#define LNBP21_ISEL 0x40
#define LNBP21_PCL 0x80
-struct lnbp21 {
- u8 config;
- u8 override_or;
- u8 override_and;
- struct i2c_adapter *i2c;
- void (*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- break;
- case SEC_VOLTAGE_13:
- lnbp21->config |= LNBP21_EN;
- break;
- case SEC_VOLTAGE_18:
- lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
- break;
- default:
- return -EINVAL;
- };
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- if (arg)
- lnbp21->config |= LNBP21_LLC;
- else
- lnbp21->config &= ~LNBP21_LLC;
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
- /* LNBP power off */
- lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
- /* free data & call next release routine */
- fe->ops->release = lnbp21->release_chain;
- kfree(fe->misc_priv);
- fe->misc_priv = NULL;
- if (fe->ops->release)
- fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
- struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
- if (!lnbp21)
- return -ENOMEM;
-
- /* default configuration */
- lnbp21->config = LNBP21_ISEL;
-
- /* bits which should be forced to '1' */
- lnbp21->override_or = override_set;
-
- /* bits which should be forced to '0' */
- lnbp21->override_and = ~override_clear;
-
- /* install release callback */
- lnbp21->release_chain = fe->ops->release;
- fe->ops->release = lnbp21_exit;
-
- /* override frontend ops */
- fe->ops->set_voltage = lnbp21_set_voltage;
- fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
- lnbp21->i2c = i2c;
- fe->misc_priv = lnbp21;
-
- return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
#endif
diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c
index d3aea83cf21..1ef82182564 100644
--- a/drivers/media/dvb/frontends/mt312.c
+++ b/drivers/media/dvb/frontends/mt312.c
@@ -39,7 +39,6 @@
struct mt312_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct mt312_config* config;
struct dvb_frontend frontend;
@@ -277,12 +276,6 @@ static int mt312_initfe(struct dvb_frontend* fe)
if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
return ret;
- if (state->config->pll_init) {
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_init(fe);
- mt312_writereg(state, GPP_CTRL, 0x00);
- }
-
return 0;
}
@@ -477,16 +470,16 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
- if ((p->frequency < fe->ops->info.frequency_min)
- || (p->frequency > fe->ops->info.frequency_max))
+ if ((p->frequency < fe->ops.info.frequency_min)
+ || (p->frequency > fe->ops.info.frequency_max))
return -EINVAL;
if ((p->inversion < INVERSION_OFF)
|| (p->inversion > INVERSION_ON))
return -EINVAL;
- if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
- || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+ if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+ || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
return -EINVAL;
if ((p->u.qpsk.fec_inner < FEC_NONE)
@@ -529,9 +522,10 @@ static int mt312_set_frontend(struct dvb_frontend* fe,
return -EINVAL;
}
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_set(fe, p);
- mt312_writereg(state, GPP_CTRL, 0x00);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* sr = (u16)(sr * 256.0 / 1000000.0) */
sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
@@ -578,6 +572,17 @@ static int mt312_get_frontend(struct dvb_frontend* fe,
return 0;
}
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct mt312_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return mt312_writereg(state, GPP_CTRL, 0x40);
+ } else {
+ return mt312_writereg(state, GPP_CTRL, 0x00);
+ }
+}
+
static int mt312_sleep(struct dvb_frontend* fe)
{
struct mt312_state *state = fe->demodulator_priv;
@@ -633,6 +638,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
.init = mt312_initfe,
.sleep = mt312_sleep,
+ .i2c_gate_ctrl = mt312_i2c_gate_ctrl,
.set_frontend = mt312_set_frontend,
.get_frontend = mt312_get_frontend,
@@ -663,19 +669,22 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt312_readreg(state, ID, &state->id) < 0)
goto error;
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
switch (state->id) {
case ID_VP310:
- strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
state->frequency = 90;
break;
case ID_MT312:
- strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
state->frequency = 60;
break;
default:
@@ -683,9 +692,6 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
goto error;
}
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 074d844f013..666a1bd1c24 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -32,10 +32,6 @@ struct mt312_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index aaaec909ddf..5de7376c94c 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -45,7 +45,6 @@
struct mt352_state {
struct i2c_adapter* i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
/* configuration settings */
struct mt352_config config;
@@ -286,16 +285,25 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
mt352_calc_input_freq(state, buf+6);
- state->config.pll_set(fe, param, buf+8);
- mt352_write(fe, buf, sizeof(buf));
if (state->config.no_tuner) {
- /* start decoding */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ mt352_write(fe, buf, 8);
mt352_write(fe, fsm_go, 2);
} else {
- /* start tuning */
- mt352_write(fe, tuner_go, 2);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+ buf[8] <<= 1;
+ mt352_write(fe, buf, sizeof(buf));
+ mt352_write(fe, tuner_go, 2);
+ }
}
+
return 0;
}
@@ -541,13 +549,12 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct mt352_config));
- memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 03040cd595b..9e7ff4b8fe5 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -49,12 +49,6 @@ struct mt352_config
/* Initialise the demodulator and PLL. Cannot be NULL */
int (*demod_init)(struct dvb_frontend* fe);
-
- /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
- * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
- * byte1-4: PLL configuration.
- */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
};
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c
index 9e353539450..87c286ee6a0 100644
--- a/drivers/media/dvb/frontends/nxt200x.c
+++ b/drivers/media/dvb/frontends/nxt200x.c
@@ -55,7 +55,6 @@
struct nxt200x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct nxt200x_config* config;
struct dvb_frontend frontend;
@@ -333,17 +332,17 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
dprintk("%s\n", __FUNCTION__);
- dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+ dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
/* 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))
+ if (i2c_writebytes(state, data[0], data+1, 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);
+ i2c_readbytes(state, data[0], &buf, 1);
if (buf & 0x40)
return 0;
msleep(100);
@@ -361,10 +360,10 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
nxt200x_writebytes(state, 0x34, &buf, 1);
/* write actual tuner bytes */
- nxt200x_writebytes(state, 0x36, data, 4);
+ nxt200x_writebytes(state, 0x36, data+1, 4);
/* set tuner i2c address */
- buf = state->config->pll_address;
+ buf = data[0] << 1;
nxt200x_writebytes(state, 0x35, &buf, 1);
/* write UC Opmode to begin transfer */
@@ -534,7 +533,7 @@ 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];
+ u8 buf[5];
/* stop the micro first */
nxt200x_microcontroller_stop(state);
@@ -548,7 +547,9 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe,
}
/* get tuning information */
- dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+ }
/* set additional params */
switch (p->u.vsb.modulation) {
@@ -895,9 +896,9 @@ static int nxt2002_init(struct dvb_frontend* fe)
}
ret = nxt2002_load_firmware(fe, fw);
+ release_firmware(fw);
if (ret) {
printk("nxt2002: Writing firmware to device failed\n");
- release_firmware(fw);
return ret;
}
printk("nxt2002: Firmware upload complete\n");
@@ -959,9 +960,9 @@ static int nxt2004_init(struct dvb_frontend* fe)
}
ret = nxt2004_load_firmware(fe, fw);
+ release_firmware(fw);
if (ret) {
printk("nxt2004: Writing firmware to device failed\n");
- release_firmware(fw);
return ret;
}
printk("nxt2004: Firmware upload complete\n");
@@ -1159,7 +1160,6 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
/* 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 */
@@ -1198,7 +1198,7 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 1d9d70bc37e..34d61735845 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -38,10 +38,6 @@ 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);
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index a16eeba0020..d313d7dcf38 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -33,7 +33,6 @@
struct nxt6000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct nxt6000_config* config;
struct dvb_frontend frontend;
@@ -207,12 +206,6 @@ static void nxt6000_setup(struct dvb_frontend* fe)
nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
nxt6000_writereg(state, TS_FORMAT, 0);
-
- if (state->config->pll_init) {
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_init(fe);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
- }
}
static void nxt6000_dump_status(struct nxt6000_state *state)
@@ -469,9 +462,10 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
struct nxt6000_state* state = fe->demodulator_priv;
int result;
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_set(fe, param);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
return result;
@@ -532,6 +526,17 @@ static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron
return 0;
}
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct nxt6000_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+ } else {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+ }
+}
+
static struct dvb_frontend_ops nxt6000_ops;
struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
@@ -546,13 +551,12 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -584,6 +588,7 @@ static struct dvb_frontend_ops nxt6000_ops = {
.release = nxt6000_release,
.init = nxt6000_init,
+ .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
.get_tune_settings = nxt6000_fe_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index b7d9bead300..117031d1170 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -31,10 +31,6 @@ struct nxt6000_config
/* should clock inversion be used? */
u8 clock_inversion:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c
index 80e0f28127b..d20ab30c1e8 100644
--- a/drivers/media/dvb/frontends/or51132.c
+++ b/drivers/media/dvb/frontends/or51132.c
@@ -54,7 +54,6 @@ static int debug;
struct or51132_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51132_config* config;
@@ -106,9 +105,8 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
{
struct or51132_state* state = fe->demodulator_priv;
static u8 run_buf[] = {0x7F,0x01};
- static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
- u8 rec_buf[14];
- u8 cmd_buf[14];
+ u8 rec_buf[8];
+ u8 cmd_buf[3];
u32 firmwareAsize, firmwareBsize;
int i,ret;
@@ -157,7 +155,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x10;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
@@ -167,8 +164,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x04;
cmd_buf[1] = 0x17;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
@@ -178,8 +173,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x00;
cmd_buf[1] = 0x00;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
@@ -189,7 +182,11 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
for(i=0;i<4;i++) {
msleep(20); /* 20ms */
- get_ver_buf[4] = i+1;
+ /* Once upon a time, this command might have had something
+ to do with getting the firmware version, but it's
+ not used anymore:
+ {0x04,0x00,0x30,0x00,i+1} */
+ /* Read 8 bytes, two bytes at a time */
if ((ret = i2c_readbytes(state,state->config->demod_address,
&rec_buf[i*2],2))) {
printk(KERN_WARNING
@@ -208,7 +205,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x00;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
@@ -243,7 +239,7 @@ static int or51132_sleep(struct dvb_frontend* fe)
static int or51132_setmode(struct dvb_frontend* fe)
{
struct or51132_state* state = fe->demodulator_priv;
- unsigned char cmd_buf[4];
+ unsigned char cmd_buf[3];
dprintk("setmode %d\n",(int)state->current_modulation);
/* set operation mode in Receiver 1 register; */
@@ -263,7 +259,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
default:
printk("setmode:Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
printk(KERN_WARNING "or51132: set_mode error 1\n");
@@ -301,7 +296,6 @@ static int or51132_setmode(struct dvb_frontend* fe)
default:
printk("setmode: Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
@@ -313,52 +307,65 @@ static int or51132_setmode(struct dvb_frontend* fe)
return 0;
}
+/* Some modulations use the same firmware. This classifies modulations
+ by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN 0
+#define MOD_FWCLASS_VSB 1
+#define MOD_FWCLASS_QAM 2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+ switch(modulation) {
+ case VSB_8:
+ return MOD_FWCLASS_VSB;
+ case QAM_AUTO:
+ case QAM_64:
+ case QAM_256:
+ return MOD_FWCLASS_QAM;
+ default:
+ return MOD_FWCLASS_UNKNOWN;
+ }
+}
+
static int or51132_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
int ret;
- u8 buf[4];
struct or51132_state* state = fe->demodulator_priv;
const struct firmware *fw;
-
- /* Change only if we are actually changing the modulation */
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
- case VSB_8:
+ const char *fwname;
+ int clock_mode;
+
+ /* Upload new firmware only if we need a different one */
+ if (modulation_fw_class(state->current_modulation) !=
+ modulation_fw_class(param->u.vsb.modulation)) {
+ switch(modulation_fw_class(param->u.vsb.modulation)) {
+ case MOD_FWCLASS_VSB:
dprintk("set_parameters VSB MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_VSB_FIRMWARE);
- ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_VSB_FIRMWARE;
+
/* Set non-punctured clock for VSB */
- state->config->set_ts_params(fe, 0);
+ clock_mode = 0;
break;
- case QAM_AUTO:
- case QAM_64:
- case QAM_256:
+ case MOD_FWCLASS_QAM:
dprintk("set_parameters QAM MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_QAM_FIRMWARE);
- ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_QAM_FIRMWARE;
+
/* Set punctured clock for QAM */
- state->config->set_ts_params(fe, 1);
+ clock_mode = 1;
break;
default:
- printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+ printk("or51132: Modulation type(%d) UNSUPPORTED\n",
param->u.vsb.modulation);
return -1;
- };
+ }
+ printk("or51132: Waiting for firmware upload(%s)...\n",
+ fwname);
+ ret = request_firmware(&fw, fwname, &state->i2c->dev);
+ if (ret) {
+ printk(KERN_WARNING "or51132: No firmware up"
+ "loaded(timeout or file not found?)\n");
+ return ret;
+ }
ret = or51132_load_firmware(fe, fw);
release_firmware(fw);
if (ret) {
@@ -367,18 +374,18 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
return ret;
}
printk("or51132: Firmware upload complete.\n");
-
+ state->config->set_ts_params(fe, clock_mode);
+ }
+ /* Change only if we are actually changing the modulation */
+ if (state->current_modulation != param->u.vsb.modulation) {
state->current_modulation = param->u.vsb.modulation;
or51132_setmode(fe);
}
- dvb_pll_configure(state->config->pll_desc, buf,
- param->frequency, 0);
- dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
- "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
- if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
- printk(KERN_WARNING "or51132: set_parameters error "
- "writing to tuner\n");
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* Set to current mode */
or51132_setmode(fe);
@@ -388,6 +395,44 @@ static int or51132_set_parameters(struct dvb_frontend* fe,
return 0;
}
+static int or51132_get_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct or51132_state* state = fe->demodulator_priv;
+ u8 buf[2];
+
+ /* Receiver Status */
+ buf[0]=0x04;
+ buf[1]=0x00;
+ msleep(30); /* 30ms */
+ if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters write error\n");
+ return -EREMOTEIO;
+ }
+ msleep(30); /* 30ms */
+ if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters read error\n");
+ return -EREMOTEIO;
+ }
+ switch(buf[0]) {
+ case 0x06: param->u.vsb.modulation = VSB_8; break;
+ case 0x43: param->u.vsb.modulation = QAM_64; break;
+ case 0x45: param->u.vsb.modulation = QAM_256; break;
+ default:
+ printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+ buf[0]);
+ return -EREMOTEIO;
+ }
+
+ /* FIXME: Read frequency from frontend, take AFC into account */
+ param->frequency = state->current_frequency;
+
+ /* FIXME: How to read inversion setting? Receiver 6 register? */
+ param->inversion = INVERSION_AUTO;
+
+ return 0;
+}
+
static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct or51132_state* state = fe->demodulator_priv;
@@ -572,12 +617,11 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->current_frequency = -1;
state->current_modulation = -1;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -590,7 +634,7 @@ static struct dvb_frontend_ops or51132_ops = {
.info = {
.name = "Oren OR51132 VSB/QAM Frontend",
- .type = FE_ATSC,
+ .type = FE_ATSC,
.frequency_min = 44000000,
.frequency_max = 958000000,
.frequency_stepsize = 166666,
@@ -606,6 +650,7 @@ static struct dvb_frontend_ops or51132_ops = {
.sleep = or51132_sleep,
.set_frontend = or51132_set_parameters,
+ .get_frontend = or51132_get_parameters,
.get_tune_settings = or51132_get_tune_settings,
.read_status = or51132_read_status,
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index 622cdd18381..89658883abf 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -29,8 +29,6 @@ struct or51132_config
{
/* The demodulator's i2c address */
u8 demod_address;
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c
index 7c3aed1f546..2bf124b5368 100644
--- a/drivers/media/dvb/frontends/or51211.c
+++ b/drivers/media/dvb/frontends/or51211.c
@@ -54,7 +54,6 @@ static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC
struct or51211_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51211_config* config;
@@ -438,10 +437,10 @@ static int or51211_init(struct dvb_frontend* fe)
}
ret = or51211_load_firmware(fe, fw);
+ release_firmware(fw);
if (ret) {
printk(KERN_WARNING "or51211: Writing firmware to "
"device failed!\n");
- release_firmware(fw);
return ret;
}
printk(KERN_INFO "or51211: Firmware upload complete.\n");
@@ -585,12 +584,11 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config,
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->initialized = 0;
state->current_frequency = 0;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index d6947759692..2c2c344c4c6 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -38,7 +38,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
struct s5h1420_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct s5h1420_config* config;
struct dvb_frontend frontend;
@@ -584,7 +583,6 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
- u32 tmp;
/* check if we should do a fast-tune */
memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
@@ -596,10 +594,17 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
(state->fec_inner == p->u.qpsk.fec_inner) &&
(state->symbol_rate == p->u.qpsk.symbol_rate)) {
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ u32 tmp;
+ fe->ops.tuner_ops.get_frequency(fe, &tmp);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, p->frequency - tmp);
+ } else {
+ s5h1420_setfreqoffset(state, 0);
}
return 0;
}
@@ -646,9 +651,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
/* set tuner PLL */
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, 0);
}
@@ -708,6 +713,17 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
return 0;
}
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ } else {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+}
+
static int s5h1420_init (struct dvb_frontend* fe)
{
struct s5h1420_state* state = fe->demodulator_priv;
@@ -717,13 +733,6 @@ static int s5h1420_init (struct dvb_frontend* fe)
msleep(10);
s5h1420_reset(state);
- /* init PLL */
- if (state->config->pll_init) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_init(fe);
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
- }
-
return 0;
}
@@ -756,7 +765,6 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->postlocked = 0;
state->fclk = 88000000;
state->tunedfreq = 0;
@@ -769,7 +777,7 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -800,6 +808,7 @@ static struct dvb_frontend_ops s5h1420_ops = {
.init = s5h1420_init,
.sleep = s5h1420_sleep,
+ .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
.set_frontend = s5h1420_set_frontend,
.get_frontend = s5h1420_get_frontend,
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 73296f13c32..4e39015fa67 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -32,10 +32,6 @@ struct s5h1420_config
/* does the inversion require inversion? */
u8 invert:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
};
extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index 73829e647e5..d98fd5c2e13 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -44,8 +44,6 @@ struct sp8870_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct sp8870_config* config;
struct dvb_frontend frontend;
@@ -262,9 +260,10 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe,
sp8870_microcontroller_stop(state);
// set tuner parameters
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_set(fe, p);
- sp8870_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
// sample rate correction bit [23..17]
sp8870_writereg(state, 0x0319, 0x000A);
@@ -319,7 +318,6 @@ static int sp8870_init (struct dvb_frontend* fe)
printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
printk("sp8870: no firmware upload (timeout or file not found?)\n");
- release_firmware(fw);
return -EIO;
}
@@ -328,6 +326,7 @@ static int sp8870_init (struct dvb_frontend* fe)
release_firmware(fw);
return -EIO;
}
+ release_firmware(fw);
printk("sp8870: firmware upload complete\n");
/* enable TS output and interface pins */
@@ -349,13 +348,6 @@ static int sp8870_init (struct dvb_frontend* fe)
sp8870_writereg(state, 0x0D00, 0x010);
sp8870_writereg(state, 0x0D01, 0x000);
- /* setup PLL */
- if (state->config->pll_init) {
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp8870_writereg(state, 0x206, 0x000);
- }
-
return 0;
}
@@ -541,6 +533,17 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend
return 0;
}
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp8870_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp8870_writereg(state, 0x206, 0x001);
+ } else {
+ return sp8870_writereg(state, 0x206, 0x000);
+ }
+}
+
static void sp8870_release(struct dvb_frontend* fe)
{
struct sp8870_state* state = fe->demodulator_priv;
@@ -561,14 +564,13 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp8870_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -597,6 +599,7 @@ static struct dvb_frontend_ops sp8870_ops = {
.init = sp8870_init,
.sleep = sp8870_sleep,
+ .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
.set_frontend = sp8870_set_frontend,
.get_tune_settings = sp8870_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index f3b555dbc96..93afbb969d6 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -31,10 +31,6 @@ struct sp8870_config
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c
index eb8a602198c..5c2f8f4e0ae 100644
--- a/drivers/media/dvb/frontends/sp887x.c
+++ b/drivers/media/dvb/frontends/sp887x.c
@@ -24,7 +24,6 @@
struct sp887x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct sp887x_config* config;
struct dvb_frontend frontend;
@@ -208,15 +207,6 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware
/* bit 0x010: enable data valid signal */
sp887x_writereg(state, 0xd00, 0x010);
sp887x_writereg(state, 0x0d1, 0x000);
-
- /* setup the PLL */
- if (state->config->pll_init) {
- sp887x_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp887x_writereg(state, 0x206, 0x000);
- }
-
- printk ("done.\n");
return 0;
};
@@ -362,9 +352,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe,
sp887x_microcontroller_stop(state);
/* setup the PLL */
- sp887x_writereg(state, 0x206, 0x001);
- actual_freq = state->config->pll_set(fe, p);
- sp887x_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ } else {
+ actual_freq = p->frequency;
+ }
/* read status reg in order to clear <pending irqs */
sp887x_readreg(state, 0x200);
@@ -486,6 +483,17 @@ static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
return 0;
}
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp887x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp887x_writereg(state, 0x206, 0x001);
+ } else {
+ return sp887x_writereg(state, 0x206, 0x000);
+ }
+}
+
static int sp887x_sleep(struct dvb_frontend* fe)
{
struct sp887x_state* state = fe->demodulator_priv;
@@ -512,9 +520,9 @@ static int sp887x_init(struct dvb_frontend* fe)
}
ret = sp887x_initial_setup(fe, fw);
+ release_firmware(fw);
if (ret) {
printk("sp887x: writing firmware to device failed\n");
- release_firmware(fw);
return ret;
}
printk("sp887x: firmware upload complete\n");
@@ -555,14 +563,13 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp887x_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -589,6 +596,7 @@ static struct dvb_frontend_ops sp887x_ops = {
.init = sp887x_init,
.sleep = sp887x_sleep,
+ .i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
.set_frontend = sp887x_setup_frontend_parameters,
.get_tune_settings = sp887x_get_tune_settings,
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index 6a05d8f8e8c..c44b0ebdf1e 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -13,12 +13,6 @@ struct sp887x_config
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
-
- /* this should return the actual frequency tuned to */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index eb15676d374..1ca64249010 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -32,7 +32,6 @@
struct stv0297_state {
struct i2c_adapter *i2c;
- struct dvb_frontend_ops ops;
const struct stv0297_config *config;
struct dvb_frontend frontend;
@@ -68,19 +67,25 @@ static int stv0297_readreg(struct stv0297_state *state, u8 reg)
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
- struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
- 1},
- {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
- };
+ struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+ {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ };
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
}
return b1[0];
@@ -107,13 +112,20 @@ static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len
};
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
}
return 0;
@@ -276,12 +288,14 @@ static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_invers
return 0;
}
-int stv0297_enable_plli2c(struct dvb_frontend *fe)
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct stv0297_state *state = fe->demodulator_priv;
- stv0297_writereg(state, 0x87, 0x78);
- stv0297_writereg(state, 0x86, 0xc8);
+ if (enable) {
+ stv0297_writereg(state, 0x87, 0x78);
+ stv0297_writereg(state, 0x86, 0xc8);
+ }
return 0;
}
@@ -296,9 +310,6 @@ static int stv0297_init(struct dvb_frontend *fe)
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
msleep(200);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
@@ -389,7 +400,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
case QAM_32:
case QAM_64:
delay = 100;
- sweeprate = 1500;
+ sweeprate = 1000;
break;
case QAM_128:
@@ -421,7 +432,10 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
stv0297_init(fe);
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* clear software interrupts */
stv0297_writereg(state, 0x82, 0x0);
@@ -634,7 +648,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->base_freq = 0;
/* check if the demod is there */
@@ -642,7 +655,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -668,6 +681,7 @@ static struct dvb_frontend_ops stv0297_ops = {
.init = stv0297_init,
.sleep = stv0297_sleep,
+ .i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
.set_frontend = stv0297_set_frontend,
.get_frontend = stv0297_get_frontend,
@@ -684,4 +698,3 @@ MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(stv0297_attach);
-EXPORT_SYMBOL(stv0297_enable_plli2c);
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 9e53f019db7..1da5384fb98 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -38,13 +38,11 @@ struct stv0297_config
/* does the "inversion" need inverted? */
u8 invert:1;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ /* set to 1 if the device requires an i2c STOP during reading */
+ u8 stop_during_read:1;
};
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
-extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
#endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 5bcd00f792e..96648a75440 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -56,7 +56,6 @@
struct stv0299_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct stv0299_config* config;
struct dvb_frontend frontend;
@@ -131,13 +130,6 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len
return ret == 2 ? 0 : ret;
}
-int stv0299_enable_plli2c (struct dvb_frontend* fe)
-{
- struct stv0299_state* state = fe->demodulator_priv;
-
- return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
-}
-
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
@@ -457,12 +449,6 @@ static int stv0299_init (struct dvb_frontend* fe)
for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
- if (state->config->pll_init) {
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_init(fe, state->i2c);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
- }
-
return 0;
}
@@ -560,9 +546,10 @@ 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);
- 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 */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
stv0299_set_FEC (state, p->u.qpsk.fec_inner);
stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
@@ -611,6 +598,19 @@ static int stv0299_sleep(struct dvb_frontend* fe)
return 0;
}
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ stv0299_writeregI(state, 0x05, 0xb5);
+ } else {
+ stv0299_writeregI(state, 0x05, 0x35);
+ }
+ udelay(1);
+ return 0;
+}
+
static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
struct stv0299_state* state = fe->demodulator_priv;
@@ -647,7 +647,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
state->tuner_frequency = 0;
state->symbol_rate = 0;
@@ -664,7 +663,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
if (id != 0xa1 && id != 0x80) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -695,6 +694,7 @@ static struct dvb_frontend_ops stv0299_ops = {
.init = stv0299_init,
.sleep = stv0299_sleep,
+ .i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
.set_frontend = stv0299_set_frontend,
.get_frontend = stv0299_get_frontend,
@@ -721,9 +721,8 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
- "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
+ "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(stv0299_enable_plli2c);
EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 32c87b4c2f1..1504828e423 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -87,14 +87,9 @@ struct stv0299_config
/* Set the symbol rate */
int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c);
- int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params);
};
extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c);
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 21255cac979..9cbd164aa28 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -21,7 +21,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -36,7 +35,6 @@
struct tda10021_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda10021_config* config;
struct dvb_frontend frontend;
@@ -90,6 +88,14 @@ static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
+int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ return tda10021_writereg(state, reg, data);
+}
+EXPORT_SYMBOL(tda10021_write_byte);
+
static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
{
u8 b0 [] = { reg };
@@ -225,13 +231,6 @@ static int tda10021_init (struct dvb_frontend *fe)
//Activate PLL
tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-
- if (state->config->pll_init) {
- lock_tuner(state);
- state->config->pll_init(fe);
- unlock_tuner(state);
- }
-
return 0;
}
@@ -259,9 +258,10 @@ static int tda10021_set_parameters (struct dvb_frontend *fe,
//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
- lock_tuner(state);
- state->config->pll_set(fe, p);
- unlock_tuner(state);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
tda10021_writereg (state, 0x34, state->pwm);
@@ -376,6 +376,18 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa
return 0;
}
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ lock_tuner(state);
+ } else {
+ unlock_tuner(state);
+ }
+ return 0;
+}
+
static int tda10021_sleep(struct dvb_frontend* fe)
{
struct tda10021_state* state = fe->demodulator_priv;
@@ -407,7 +419,6 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
state->reg0 = tda10021_inittab[0];
@@ -415,7 +426,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -448,6 +459,7 @@ static struct dvb_frontend_ops tda10021_ops = {
.init = tda10021_init,
.sleep = tda10021_sleep,
+ .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
.set_frontend = tda10021_set_parameters,
.get_frontend = tda10021_get_frontend,
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
index 53be939e8c5..b1df4259bee 100644
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -30,13 +30,11 @@ struct tda10021_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
struct i2c_adapter* i2c, u8 pwm);
+extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+
#endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index b83dafa4e12..59a2ed614fc 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -47,7 +47,6 @@ enum tda1004x_demod {
struct tda1004x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct tda1004x_config* config;
struct dvb_frontend frontend;
@@ -600,13 +599,6 @@ static int tda10045_init(struct dvb_frontend* fe)
tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
- // Init the PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_init(fe);
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
@@ -635,16 +627,6 @@ static int tda10046_init(struct dvb_frontend* fe)
return -EIO;
}
- // Init the tuner PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_init(fe)) {
- printk(KERN_ERR "tda1004x: pll init failed\n");
- return -EIO;
- }
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
@@ -712,12 +694,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
}
// set frequency
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_set(fe, fe_params)) {
- printk(KERN_ERR "tda1004x: pll set failed\n");
- return -EIO;
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fe_params);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- tda1004x_disable_tuner_i2c(state);
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
@@ -1183,16 +1163,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
break;
case TDA1004X_DEMOD_TDA10046:
- if (state->config->pll_sleep != NULL) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_sleep(fe);
- 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);
- }
- }
/* set outputs to tristate */
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
@@ -1202,6 +1172,17 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
return 0;
}
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda1004x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return tda1004x_enable_tuner_i2c(state);
+ } else {
+ return tda1004x_disable_tuner_i2c(state);
+ }
+}
+
static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 800;
@@ -1235,6 +1216,7 @@ static struct dvb_frontend_ops tda10045_ops = {
.init = tda10045_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
@@ -1260,7 +1242,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10045;
/* check if the demod is there */
@@ -1270,7 +1251,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
@@ -1293,6 +1274,7 @@ static struct dvb_frontend_ops tda10046_ops = {
.init = tda10046_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
@@ -1318,7 +1300,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10046;
/* check if the demod is there */
@@ -1328,7 +1309,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index cc0c4af6406..b877b23ed73 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -66,11 +66,6 @@ struct tda1004x_config
/* AGC configuration */
enum tda10046_agc agc_config;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- void (*pll_sleep)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
/* set this to NULL if the card has a firmware EEPROM */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c
index 91baa9cedd7..3aa45ebbac3 100644
--- a/drivers/media/dvb/frontends/tda8083.c
+++ b/drivers/media/dvb/frontends/tda8083.c
@@ -37,7 +37,6 @@
struct tda8083_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda8083_config* config;
struct dvb_frontend frontend;
@@ -293,7 +292,11 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct tda8083_state* state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
tda8083_set_inversion (state, p->inversion);
tda8083_set_fec (state, p->u.qpsk.fec_inner);
tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -334,8 +337,6 @@ static int tda8083_init(struct dvb_frontend* fe)
for (i=0; i<44; i++)
tda8083_writereg (state, i, tda8083_init_tab[i]);
- if (state->config->pll_init) state->config->pll_init(fe);
-
tda8083_writereg (state, 0x00, 0x3c);
tda8083_writereg (state, 0x00, 0x04);
@@ -395,13 +396,12 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index 466663307bf..e7a48f61ea2 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -33,10 +33,6 @@ struct tda8083_config
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c
index ad8647a3c85..9b57576bfeb 100644
--- a/drivers/media/dvb/frontends/ves1820.c
+++ b/drivers/media/dvb/frontends/ves1820.c
@@ -18,7 +18,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -35,7 +34,6 @@
struct ves1820_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1820_config* config;
struct dvb_frontend frontend;
@@ -204,9 +202,6 @@ static int ves1820_init(struct dvb_frontend* fe)
ves1820_writereg(state, 0x34, state->pwm);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
@@ -223,7 +218,11 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
ves1820_writereg(state, 0x34, state->pwm);
@@ -380,7 +379,6 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
goto error;
/* setup the state */
- memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
state->reg0 = ves1820_inittab[0];
state->config = config;
state->i2c = i2c;
@@ -393,12 +391,12 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
if (verbose)
printk("ves1820: pwm=0x%02x\n", state->pwm);
- state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
- state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
+ state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
state->frontend.demodulator_priv = state;
+
return &state->frontend;
error:
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index 355f130b1be..520f09522fb 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -39,10 +39,6 @@ struct ves1820_config
/* SELAGC control */
u8 selagc:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 821df8e839d..54d7b07571b 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -36,7 +36,6 @@
struct ves1x93_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1x93_config* config;
struct dvb_frontend frontend;
@@ -278,12 +277,6 @@ static int ves1x93_init (struct dvb_frontend* fe)
}
}
- if (state->config->pll_init) {
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_init(fe);
- ves1x93_writereg(state, 0x00, 0x01);
- }
-
return 0;
}
@@ -395,9 +388,10 @@ static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct ves1x93_state* state = fe->demodulator_priv;
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_set(fe, p);
- ves1x93_writereg(state, 0x00, 0x01);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
ves1x93_set_inversion (state, p->inversion);
ves1x93_set_fec (state, p->u.qpsk.fec_inner);
ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
@@ -442,6 +436,17 @@ static void ves1x93_release(struct dvb_frontend* fe)
kfree(state);
}
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct ves1x93_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return ves1x93_writereg(state, 0x00, 0x11);
+ } else {
+ return ves1x93_writereg(state, 0x00, 0x01);
+ }
+}
+
static struct dvb_frontend_ops ves1x93_ops;
struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
@@ -457,7 +462,6 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->inversion = INVERSION_OFF;
/* check if the demod is there + identify it */
@@ -492,7 +496,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -523,6 +527,7 @@ static struct dvb_frontend_ops ves1x93_ops = {
.init = ves1x93_init,
.sleep = ves1x93_sleep,
+ .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
.set_frontend = ves1x93_set_frontend,
.get_frontend = ves1x93_get_frontend,
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index 1627e37c57a..ba88ae0855c 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -38,10 +38,6 @@ struct ves1x93_config
/* should PWM be inverted? */
u8 invert_pwm:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index d7d9f59d76d..2b95e8b6cd3 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -34,7 +34,6 @@
struct zl10353_state {
struct i2c_adapter *i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
struct zl10353_config config;
};
@@ -126,6 +125,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
struct zl10353_state *state = fe->demodulator_priv;
+
u8 pllbuf[6] = { 0x67 };
/* These settings set "auto-everything" and start the FSM. */
@@ -142,7 +142,30 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, 0x66, 0xE9);
zl10353_single_write(fe, 0x62, 0x0A);
- state->config.pll_set(fe, param, pllbuf + 1);
+ // if there is no attached secondary tuner, we call set_params to program
+ // a potential tuner attached somewhere else
+ if (state->config.no_tuner) {
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ }
+
+ // if pllbuf is defined, retrieve the settings
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+ pllbuf[1] <<= 1;
+ } else {
+ // fake pllbuf settings
+ pllbuf[1] = 0x61 << 1;
+ pllbuf[2] = 0;
+ pllbuf[3] = 0;
+ pllbuf[3] = 0;
+ pllbuf[4] = 0;
+ }
+
+ // there is no call to _just_ start decoding, so we send the pllbuf anyway
+ // even if there isn't a PLL attached to the secondary bus
zl10353_write(fe, pllbuf, sizeof(pllbuf));
zl10353_single_write(fe, 0x70, 0x01);
@@ -254,14 +277,13 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config,
/* setup the state */
state->i2c = i2c;
memcpy(&state->config, config, sizeof(struct zl10353_config));
- memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 5cc4ae718d8..9770cb840cf 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -29,10 +29,8 @@ struct zl10353_config
/* demodulator's I2C address */
u8 demod_address;
- /* function which configures the PLL buffer (for secondary I2C
- * connected tuner) or tunes the PLL (for direct connected tuner) */
- int (*pll_set)(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params, u8 *pllbuf);
+ /* set if no pll is connected to the secondary i2c bus */
+ int no_tuner;
};
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
index 7d8e6e87bdb..9b84b1bdc31 100644
--- a/drivers/media/dvb/pluto2/Kconfig
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -2,6 +2,7 @@ config DVB_PLUTO2
tristate "Pluto2 cards"
depends on DVB_CORE && PCI && I2C
select I2C_ALGOBIT
+ select DVB_PLL
select DVB_TDA1004X
help
Support for PCI cards based on the Pluto2 FPGA like the Satelco
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 1c5316e209e..2310b2bfed4 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -424,8 +424,8 @@ static inline u32 divide(u32 numerator, u32 denominator)
}
/* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct pluto *pluto = frontend_to_pluto(fe);
struct i2c_msg msg;
@@ -473,6 +473,8 @@ static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
msg.buf = buf;
msg.len = sizeof(buf);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
if (ret < 0)
return ret;
@@ -497,8 +499,6 @@ static struct tda1004x_config pluto2_fe_config __devinitdata = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_set = lg_tdtpe001p_pll_set,
- .pll_sleep = NULL,
.request_firmware = pluto2_request_firmware,
};
@@ -511,11 +511,12 @@ static int __devinit frontend_init(struct pluto *pluto)
dev_err(&pluto->pdev->dev, "could not attach frontend\n");
return -ENODEV;
}
+ pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
if (ret < 0) {
- if (pluto->fe->ops->release)
- pluto->fe->ops->release(pluto->fe);
+ if (pluto->fe->ops.release)
+ pluto->fe->ops.release(pluto->fe);
return ret;
}
@@ -615,7 +616,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, pluto);
- ret = request_irq(pdev->irq, pluto_irq, SA_SHIRQ, DRIVER_NAME, pluto);
+ ret = request_irq(pdev->irq, pluto_irq, IRQF_SHARED, DRIVER_NAME, pluto);
if (ret < 0)
goto err_pci_iounmap;
@@ -647,7 +648,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
goto err_pluto_hw_exit;
/* dvb */
- ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+ ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
if (ret < 0)
goto err_i2c_bit_del_bus;
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index b5ac7dfde52..5fb097595cf 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -3,6 +3,7 @@ config DVB_AV7110
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select FW_LOADER
select VIDEO_SAA7146_VV
+ select DVB_PLL
select DVB_VES1820
select DVB_VES1X93
select DVB_STV0299
@@ -10,6 +11,7 @@ config DVB_AV7110
select DVB_SP8870
select DVB_STV0297
select DVB_L64781
+ select DVB_LNBP21
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -60,6 +62,7 @@ config DVB_BUDGET
tristate "Budget cards"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146
+ select DVB_PLL
select DVB_STV0299
select DVB_VES1X93
select DVB_VES1820
@@ -67,6 +70,7 @@ config DVB_BUDGET
select DVB_TDA8083
select DVB_TDA10021
select DVB_S5H1420
+ select DVB_LNBP21
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -81,9 +85,11 @@ config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146
+ select DVB_PLL
select DVB_STV0297
select DVB_STV0299
select DVB_TDA1004X
+ select DVB_LNBP21
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -101,6 +107,7 @@ config DVB_BUDGET_AV
tristate "Budget cards with analog video inputs"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146_VV
+ select DVB_PLL
select DVB_STV0299
select DVB_TDA1004X
select DVB_TDA10021
@@ -119,6 +126,7 @@ config DVB_BUDGET_PATCH
tristate "AV7110 cards with Budget Patch"
depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
select DVB_AV7110
+ select DVB_PLL
select DVB_STV0299
select DVB_VES1X93
select DVB_TDA8083
diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile
index a690730ac39..aa85ecdc6c8 100644
--- a/drivers/media/dvb/ttpci/Makefile
+++ b/drivers/media/dvb/ttpci/Makefile
@@ -15,9 +15,9 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
hostprogs-y := fdump
-ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
+ifeq ($(CONFIG_DVB_AV7110_FIRMWARE),y)
+$(obj)/av7110.o: $(obj)/av7110_firm.h
-$(obj)/av7110_firm.h:
+$(obj)/av7110_firm.h: $(obj)/fdump
$(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
endif
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index d028245c8ee..4506165c5de 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -30,7 +30,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/delay.h>
@@ -152,13 +151,9 @@ static void init_av7110_av(struct av7110 *av7110)
/* remaining inits according to card and frontend type */
av7110->analog_tuner_flags = 0;
av7110->current_input = 0;
- if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) {
- printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n",
- av7110->dvb_adapter.num);
- av7110->adac_type = DVB_ADAC_MSP34x5;
+ if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a)
av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
- }
- else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
+ if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_CRYSTAL;
@@ -1552,7 +1547,7 @@ static int get_firmware(struct av7110* av7110)
#endif
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
u8 pwr = 0;
@@ -1575,6 +1570,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1584,10 +1581,9 @@ static struct ves1x93_config alps_bsrv2_config = {
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1601,6 +1597,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1611,14 +1609,12 @@ static struct ves1820_config alps_tdbe2_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1631,6 +1627,8 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
data[2] = 0x8e;
data[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1638,13 +1636,11 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
-static int philips_cd1516_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1659,6 +1655,8 @@ static int philips_cd1516_pll_set(struct dvb_frontend* fe,
data[2] = 0x8e;
data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1669,12 +1667,11 @@ static struct ves1820_config philips_cd1516_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = philips_cd1516_pll_set,
};
-static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div, pwr;
@@ -1693,6 +1690,8 @@ static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85;
data[3] = pwr << 6;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1708,7 +1707,6 @@ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct fir
static struct sp8870_config alps_tdlb7_config = {
.demod_address = 0x71,
- .pll_set = alps_tdlb7_pll_set,
.request_firmware = alps_tdlb7_request_firmware,
};
@@ -1806,7 +1804,7 @@ static u8 nexusca_stv0297_inittab[] = {
0xff, 0xff,
};
-static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
@@ -1832,7 +1830,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
else
return -EINVAL;
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
printk("nexusca: pll transfer failed!\n");
return -EIO;
@@ -1840,8 +1839,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_
// wait for PLL lock
for(i = 0; i < 20; i++) {
-
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
if (data[0] & 0x40) break;
msleep(10);
@@ -1855,12 +1854,12 @@ static struct stv0297_config nexusca_stv0297_config = {
.demod_address = 0x1C,
.inittab = nexusca_stv0297_inittab,
.invert = 1,
- .pll_set = nexusca_stv0297_pll_set,
+ .stop_during_read = 1,
};
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
u32 div;
@@ -1887,13 +1886,14 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
- .pll_set = grundig_29504_401_pll_set,
};
@@ -2079,6 +2079,9 @@ static int frontend_init(struct av7110 *av7110)
case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
av7110->fe = ves1820_attach(&philips_cd1516_config,
&av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+ }
break;
}
@@ -2091,9 +2094,10 @@ static int frontend_init(struct av7110 *av7110)
// try the ALPS BSRV2 first of all
av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
@@ -2101,9 +2105,12 @@ static int frontend_init(struct av7110 *av7110)
// try the ALPS BSRU6 now
av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
@@ -2111,9 +2118,10 @@ static int frontend_init(struct av7110 *av7110)
// Try the grundig 29504-451
av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
@@ -2124,11 +2132,17 @@ static int frontend_init(struct av7110 *av7110)
/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+ }
break;
case 0x0003:
/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
break;
}
break;
@@ -2137,20 +2151,27 @@ static int frontend_init(struct av7110 *av7110)
// ALPS TDLB7
av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+ }
break;
case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
break;
case 0x0004: // Galaxis DVB-S rev1.3
/* ALPS BSRV2 */
av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
@@ -2159,9 +2180,10 @@ static int frontend_init(struct av7110 *av7110)
/* Grundig 29504-451 */
av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
@@ -2169,15 +2191,20 @@ static int frontend_init(struct av7110 *av7110)
case 0x0008: // Hauppauge/TT DVB-T
av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ }
break;
case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
/* set TDA9819 into DVB mode */
- saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
- saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+ saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
/* tuner on this needs a slower i2c bus speed */
av7110->dev->i2c_bitrate = SAA7146_I2C_BUS_BIT_RATE_240;
@@ -2189,13 +2216,16 @@ static int frontend_init(struct av7110 *av7110)
/* ALPS BSBE1 */
av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
if (av7110->fe) {
- if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+ if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
printk("dvb-ttpci: LNBP21 not found!\n");
- if (av7110->fe->ops->release)
- av7110->fe->ops->release(av7110->fe);
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
} else {
- av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+ av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
av7110->recover = dvb_s_recover;
}
}
@@ -2212,21 +2242,21 @@ static int frontend_init(struct av7110 *av7110)
av7110->dev->pci->subsystem_vendor,
av7110->dev->pci->subsystem_device);
} else {
- FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
- FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
- FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
if (ret < 0) {
printk("av7110: Frontend registration failed!\n");
- if (av7110->fe->ops->release)
- av7110->fe->ops->release(av7110->fe);
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
}
}
@@ -2413,7 +2443,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
goto err_kfree_0;
ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
- THIS_MODULE);
+ THIS_MODULE, &dev->pci->dev);
if (ret < 0)
goto err_put_firmware_1;
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 3e2e12124ba..9c79696da08 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -6,10 +6,6 @@
#include <linux/netdevice.h>
#include <linux/i2c.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
-#endif
-
#include <linux/dvb/video.h>
#include <linux/dvb/audio.h>
#include <linux/dvb/dmx.h>
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 2eff09f638d..0f3a044aeb1 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -318,7 +318,17 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
return 0;
+
+ case DVB_ADAC_MSP34x5:
+ vol = (volleft > volright) ? volleft : volright;
+ val = (vol * 0x73 / 255) << 8;
+ if (vol > 0)
+ balance = ((volright - volleft) * 127) / vol;
+ msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
+ msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
+ return 0;
}
+
return 0;
}
@@ -1267,23 +1277,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
switch(av7110->audiostate.channel_select) {
case AUDIO_STEREO:
ret = audcom(av7110, AUDIO_CMD_STEREO);
- if (!ret)
+ if (!ret) {
if (av7110->adac_type == DVB_ADAC_CRYSTAL)
i2c_writereg(av7110, 0x20, 0x02, 0x49);
+ else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+ msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
+ }
break;
case AUDIO_MONO_LEFT:
ret = audcom(av7110, AUDIO_CMD_MONO_L);
- if (!ret)
+ if (!ret) {
if (av7110->adac_type == DVB_ADAC_CRYSTAL)
i2c_writereg(av7110, 0x20, 0x02, 0x4a);
+ else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+ msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
+ }
break;
case AUDIO_MONO_RIGHT:
ret = audcom(av7110, AUDIO_CMD_MONO_R);
- if (!ret)
+ if (!ret) {
if (av7110->adac_type == DVB_ADAC_CRYSTAL)
i2c_writereg(av7110, 0x20, 0x02, 0x45);
+ else if (av7110->adac_type == DVB_ADAC_MSP34x5)
+ msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
+ }
break;
default:
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 603a22e4bfe..6ffe53fdcf5 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -42,7 +42,18 @@
int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
{
u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
- struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg };
+ struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
+
+ switch (av7110->adac_type) {
+ case DVB_ADAC_MSP34x0:
+ msgs.addr = 0x40;
+ break;
+ case DVB_ADAC_MSP34x5:
+ msgs.addr = 0x42;
+ break;
+ default:
+ return 0;
+ }
if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
@@ -57,10 +68,23 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
u8 msg2[2];
struct i2c_msg msgs[2] = {
- { .flags = 0, .addr = 0x40, .len = 3, .buf = msg1 },
- { .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 }
+ { .flags = 0 , .len = 3, .buf = msg1 },
+ { .flags = I2C_M_RD, .len = 2, .buf = msg2 }
};
+ switch (av7110->adac_type) {
+ case DVB_ADAC_MSP34x0:
+ msgs[0].addr = 0x40;
+ msgs[1].addr = 0x40;
+ break;
+ case DVB_ADAC_MSP34x5:
+ msgs[0].addr = 0x42;
+ msgs[1].addr = 0x42;
+ break;
+ default:
+ return 0;
+ }
+
if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
av7110->dvb_adapter.num, reg);
@@ -248,8 +272,8 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
if (ves1820_writereg(dev, 0x09, 0x0f, 0x60))
dprintk(1, "setting band in demodulator failed.\n");
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9198 pin9(STD)
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9198 pin30(VIF)
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // TDA9819 pin9(STD)
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); // TDA9819 pin30(VIF)
}
if (i2c_writereg(av7110, 0x48, 0x02, 0xd0) != 1)
dprintk(1, "saa7113 write failed @ card %d", av7110->dvb_adapter.num);
@@ -284,8 +308,8 @@ static int av7110_dvb_c_switch(struct saa7146_fh *fh)
if (ves1820_writereg(dev, 0x09, 0x0f, 0x20))
dprintk(1, "setting band in demodulator failed.\n");
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
- saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+ saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+ saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
}
}
@@ -678,17 +702,23 @@ int av7110_init_analog_module(struct av7110 *av7110)
{
u16 version1, version2;
- if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1
- || i2c_writereg(av7110, 0x80, 0x0, 0) != 1)
+ if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 &&
+ i2c_writereg(av7110, 0x80, 0x0, 0) == 1) {
+ printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
+ av7110->dvb_adapter.num);
+ av7110->adac_type = DVB_ADAC_MSP34x0;
+ } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 &&
+ i2c_writereg(av7110, 0x84, 0x0, 0) == 1) {
+ printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n",
+ av7110->dvb_adapter.num);
+ av7110->adac_type = DVB_ADAC_MSP34x5;
+ } else
return -ENODEV;
- printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n",
- av7110->dvb_adapter.num);
- av7110->adac_type = DVB_ADAC_MSP34x0;
msleep(100); // the probing above resets the msp...
msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
- dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n",
+ dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
av7110->dvb_adapter.num, version1, version2);
msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
@@ -697,7 +727,7 @@ int av7110_init_analog_module(struct av7110 *av7110)
msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume
msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
- msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART
+ msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
INFO(("saa7113 not accessible.\n"));
@@ -720,8 +750,8 @@ int av7110_init_analog_module(struct av7110 *av7110)
if (ves1820_writereg(av7110->dev, 0x09, 0x0f, 0x20))
dprintk(1, "setting band in demodulator failed.\n");
} else if (av7110->analog_tuner_flags & ANALOG_TUNER_STV0297) {
- saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
- saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
+ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9819 pin9(STD)
+ saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9819 pin30(VIF)
}
/* init the saa7113 */
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 8a7cd7d505c..2d21fec23b4 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -50,6 +50,12 @@
#define DEBICICAM 0x02420000
+#define SLOTSTATUS_NONE 1
+#define SLOTSTATUS_PRESENT 2
+#define SLOTSTATUS_RESET 4
+#define SLOTSTATUS_READY 8
+#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
struct budget_av {
struct budget budget;
struct video_device *vd;
@@ -58,8 +64,15 @@ struct budget_av {
struct tasklet_struct ciintf_irq_tasklet;
int slot_status;
struct dvb_ca_en50221 ca;
+ u8 reinitialise_demod:1;
+ u8 tda10021_poclkp:1;
+ u8 tda10021_ts_enabled;
+ int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
};
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+
+
/* GPIO Connections:
* 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
* 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
@@ -129,9 +142,10 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad
udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 1\n");
+ }
return result;
}
@@ -147,9 +161,10 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a
udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 2\n");
+ }
return result;
}
@@ -165,9 +180,11 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre
udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 3\n");
+ return -ETIMEDOUT;
+ }
return result;
}
@@ -183,9 +200,10 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr
udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 5\n");
+ }
return result;
}
@@ -193,12 +211,12 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int timeout = 50; // 5 seconds (4.4.6 Ready)
if (slot != 0)
return -EINVAL;
dprintk(1, "ciintf_slot_reset\n");
+ budget_av->slot_status = SLOTSTATUS_RESET;
saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
@@ -208,20 +226,17 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
msleep(20); /* 20 ms Vcc settling time */
saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+ ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+ msleep(20);
- /* This should have been based on pin 16 READY of the pcmcia port,
- * but AFAICS it is not routed to the saa7146 */
- while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
- msleep(100);
-
- /* reinitialise the frontend */
- dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
+ /* reinitialise the frontend if necessary */
+ if (budget_av->reinitialise_demod)
+ dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
- if (timeout <= 0)
- {
- printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
- saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
- return -ETIMEDOUT;
+ /* set tda10021 back to original clock configuration on reset */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
}
return 0;
@@ -238,7 +253,13 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
dprintk(1, "ciintf_slot_shutdown\n");
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
- budget_av->slot_status = 0;
+ budget_av->slot_status = SLOTSTATUS_NONE;
+
+ /* set tda10021 back to original clock configuration when cam removed */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
+ }
return 0;
}
@@ -253,6 +274,13 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+
+ /* tda10021 seems to need a different TS clock config when data is routed to the CAM */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ budget_av->tda10021_ts_enabled = 1;
+ }
+
return 0;
}
@@ -260,50 +288,61 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int cam_present = 0;
+ int result;
if (slot != 0)
return -EINVAL;
- if (!budget_av->slot_status)
- {
- // first of all test the card detect line
+ /* test the card detect line - needs to be done carefully
+ * since it never goes high for some CAMs on this interface (e.g. topuptv) */
+ if (budget_av->slot_status == SLOTSTATUS_NONE) {
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
udelay(1);
- if (saa7146_read(saa, PSR) & MASK_06)
- {
- cam_present = 1;
+ if (saa7146_read(saa, PSR) & MASK_06) {
+ if (budget_av->slot_status == SLOTSTATUS_NONE) {
+ budget_av->slot_status = SLOTSTATUS_PRESENT;
+ printk(KERN_INFO "budget-av: cam inserted A\n");
+ }
}
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+ }
- // that is unreliable however, so try and read from IO memory
- if (!cam_present)
- {
- saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
- if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
- {
- cam_present = 1;
+ /* We also try and read from IO memory to work round the above detection bug. If
+ * there is no CAM, we will get a timeout. Only done if there is no cam
+ * present, since this test actually breaks some cams :(
+ *
+ * if the CI interface is not open, we also do the above test since we
+ * don't care if the cam has problems - we'll be resetting it on open() anyway */
+ if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
+ saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+ result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
+ if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
+ budget_av->slot_status = SLOTSTATUS_PRESENT;
+ printk(KERN_INFO "budget-av: cam inserted B\n");
+ } else if (result < 0) {
+ if (budget_av->slot_status != SLOTSTATUS_NONE) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 5\n");
+ return 0;
}
}
+ }
- // did we find something?
- if (cam_present) {
- printk(KERN_INFO "budget-av: cam inserted\n");
- budget_av->slot_status = 1;
- }
- } else if (!open) {
- saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
- if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
- {
- printk(KERN_INFO "budget-av: cam ejected\n");
- saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
- budget_av->slot_status = 0;
+ /* read from attribute memory in reset/ready state to know when the CAM is ready */
+ if (budget_av->slot_status == SLOTSTATUS_RESET) {
+ result = ciintf_read_attribute_mem(ca, slot, 0);
+ if (result == 0x1d) {
+ budget_av->slot_status = SLOTSTATUS_READY;
}
}
- if (budget_av->slot_status == 1)
- return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-
+ /* work out correct return code */
+ if (budget_av->slot_status != SLOTSTATUS_NONE) {
+ if (budget_av->slot_status & SLOTSTATUS_READY) {
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ }
+ return DVB_CA_EN50221_POLL_CAM_PRESENT;
+ }
return 0;
}
@@ -333,6 +372,8 @@ static int ciintf_init(struct budget_av *budget_av)
budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
budget_av->ca.data = budget_av;
+ budget_av->budget.ci_present = 1;
+ budget_av->slot_status = SLOTSTATUS_NONE;
if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
&budget_av->ca, 0, 1)) != 0) {
@@ -341,7 +382,6 @@ static int ciintf_init(struct budget_av *budget_av)
}
printk(KERN_INFO "budget-av: ci interface initialised.\n");
- budget_av->budget.ci_present = 1;
return 0;
error:
@@ -472,12 +512,12 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra
return 0;
}
-static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u32 div;
u8 buf[4];
+ struct budget *budget = (struct budget *) fe->dvb->priv;
struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
if ((params->frequency < 950000) || (params->frequency > 2150000))
@@ -501,7 +541,9 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
else if (params->frequency < 2150000)
buf[3] |= 0xC0;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
@@ -509,9 +551,8 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
#define MIN2(a,b) ((a) < (b) ? (a) : (b))
#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 reg0 [2] = { 0x00, 0x00 };
u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
@@ -521,6 +562,7 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
int R, A, N, P, M;
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
int freq = params->frequency;
+ struct budget *budget = (struct budget *) fe->dvb->priv;
first_ZF = (freq) / 1000;
@@ -620,21 +662,25 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
reg0[1] |= 0x03;
/* already enabled - do not reenable i2c repeater or TX fails */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg0;
msg.len = sizeof(reg0);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
- stv0299_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg1;
msg.len = sizeof(reg1);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
- stv0299_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg2;
msg.len = sizeof(reg2);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -692,7 +738,6 @@ static struct stv0299_config typhoon_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278_ty_ci_pll_set,
};
@@ -706,7 +751,6 @@ static struct stv0299_config cinergy_1200s_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278_ty_ci_pll_set,
};
static struct stv0299_config cinergy_1200s_1894_0010_config = {
@@ -719,10 +763,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278sh2_tua6100_pll_set,
};
-static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 buf[4];
@@ -738,6 +781,8 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
buf[3] = (params->frequency < 150000000 ? 0x01 :
params->frequency < 445000000 ? 0x02 : 0x04);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -745,19 +790,20 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
static struct tda10021_config philips_cu1216_config = {
.demod_address = 0x0c,
- .pll_set = philips_cu1216_pll_set,
};
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
{
struct budget *budget = (struct budget *) 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 (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -765,7 +811,7 @@ static int philips_tu1216_pll_init(struct dvb_frontend *fe)
return 0;
}
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 tuner_buf[4];
@@ -839,6 +885,8 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -862,9 +910,6 @@ static struct tda1004x_config philips_tu1216_config = {
.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_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
@@ -911,13 +956,13 @@ static u8 philips_sd1878_inittab[] = {
0xff, 0xff
};
-static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 buf[4];
int rc;
struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
+ struct budget *budget = (struct budget *) fe->dvb->priv;
if((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
@@ -926,7 +971,9 @@ static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
params->frequency, 0);
if(rc < 0) return rc;
- if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
return 0;
@@ -969,7 +1016,7 @@ static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe,
static struct stv0299_config philips_sd1878_config = {
.demod_address = 0x68,
- .inittab = philips_sd1878_inittab,
+ .inittab = philips_sd1878_inittab,
.mclk = 88000000UL,
.invert = 0,
.skip_reinit = 0,
@@ -977,7 +1024,6 @@ static struct stv0299_config philips_sd1878_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
- .pll_set = philips_sd1878_tda8261_pll_set,
};
static u8 read_pwm(struct budget_av *budget_av)
@@ -1003,6 +1049,7 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
+#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_KNC1 0x0020
#define SUBID_DVBC_KNC1_PLUS 0x0021
@@ -1012,17 +1059,36 @@ static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBT_KNC1 0x0030
#define SUBID_DVBT_CINERGY1200 0x1157
+
+static int tda10021_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct budget_av* budget_av = fe->dvb->priv;
+ int result;
+
+ result = budget_av->tda10021_set_frontend(fe, p);
+ if (budget_av->tda10021_ts_enabled) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ } else {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ }
+
+ return result;
+}
+
static void frontend_init(struct budget_av *budget_av)
{
struct saa7146_dev * saa = budget_av->budget.dev;
struct dvb_frontend * fe = NULL;
+ /* Enable / PowerON Frontend */
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+
+ /* additional setup necessary for the PLUS cards */
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBT_KNC1_PLUS:
- // Enable / PowerON Frontend
- saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
break;
}
@@ -1030,12 +1096,19 @@ static void frontend_init(struct budget_av *budget_av)
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1:
+ case SUBID_DVBS_EASYWATCH_1:
if (saa->pci->subsystem_vendor == 0x1894) {
fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+ }
} else {
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
}
break;
@@ -1045,41 +1118,62 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBS_EASYWATCH:
fe = stv0299_attach(&philips_sd1878_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ }
break;
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_TYPHOON:
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
break;
case SUBID_DVBS_CINERGY1200:
fe = stv0299_attach(&cinergy_1200s_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
break;
case SUBID_DVBC_KNC1:
- case SUBID_DVBC_KNC1_PLUS:
+ budget_av->reinitialise_demod = 1;
fe = tda10021_attach(&philips_cu1216_config,
&budget_av->budget.i2c_adap,
read_pwm(budget_av));
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+ }
break;
- case SUBID_DVBT_KNC1:
- case SUBID_DVBT_KNC1_PLUS:
- fe = tda10046_attach(&philips_tu1216_config,
- &budget_av->budget.i2c_adap);
- break;
-
+ case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBC_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
fe = tda10021_attach(&philips_cu1216_config,
&budget_av->budget.i2c_adap,
read_pwm(budget_av));
+ if (fe) {
+ budget_av->tda10021_poclkp = 1;
+ budget_av->tda10021_set_frontend = fe->ops.set_frontend;
+ fe->ops.set_frontend = tda10021_set_frontend;
+ fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+ }
break;
+ case SUBID_DVBT_KNC1:
+ case SUBID_DVBT_KNC1_PLUS:
case SUBID_DVBT_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
fe = tda10046_attach(&philips_tu1216_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+ fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
+ }
break;
}
@@ -1098,8 +1192,8 @@ static void frontend_init(struct budget_av *budget_av)
if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
budget_av->budget.dvb_frontend)) {
printk(KERN_ERR "budget-av: Frontend registration failed!\n");
- if (budget_av->budget.dvb_frontend->ops->release)
- budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+ if (budget_av->budget.dvb_frontend->ops.release)
+ budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
budget_av->budget.dvb_frontend = NULL;
}
}
@@ -1208,10 +1302,9 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
budget_av->budget.dvb_adapter.priv = budget_av;
frontend_init(budget_av);
+ ciintf_init(budget_av);
- if (!budget_av->has_saa7113) {
- ciintf_init(budget_av);
- }
+ ttpci_budget_init_hooks(&budget_av->budget);
return 0;
}
@@ -1293,6 +1386,7 @@ MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C);
MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
@@ -1309,6 +1403,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+ MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index e64a609cf4f..ffbbb3e34be 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -620,10 +620,10 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate,
return 0;
}
-static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
+ struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u32 div;
u8 buf[4];
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
@@ -649,7 +649,9 @@ static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
else if (params->frequency < 2150000)
buf[3] |= 0xC0;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
@@ -665,12 +667,11 @@ static struct stv0299_config philips_su1278_tt_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 50,
.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
- .pll_set = philips_su1278_tt_pll_set,
};
-static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -679,6 +680,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
sizeof(td1316_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -687,14 +690,18 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
}
return 0;
}
-static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[4];
@@ -770,6 +777,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -793,13 +802,10 @@ static struct tda1004x_config philips_tdm1316l_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tdm1316l_pll_init,
- .pll_set = philips_tdm1316l_pll_set,
- .pll_sleep = NULL,
.request_firmware = philips_tdm1316l_request_firmware,
};
-static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[5];
@@ -857,13 +863,15 @@ static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_fro
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
tuner_buf[4] = 0x80;
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(50);
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -969,7 +977,7 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = {
.demod_address = 0x1c,
.inittab = dvbc_philips_tdm1316l_inittab,
.invert = 0,
- .pll_set = dvbc_philips_tdm1316l_pll_set,
+ .stop_during_read = 1,
};
@@ -982,6 +990,8 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
break;
}
break;
@@ -990,6 +1000,7 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
break;
}
break;
@@ -999,6 +1010,7 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
}
break;
@@ -1008,6 +1020,8 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
}
break;
@@ -1017,6 +1031,8 @@ static void frontend_init(struct budget_ci *budget_ci)
budget_ci->budget.dvb_frontend =
tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
}
break;
@@ -1024,11 +1040,14 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1017: // TT S-1500 PCI
budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
- budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
- if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+ budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+ if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
- if (budget_ci->budget.dvb_frontend->ops->release)
- budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ if (budget_ci->budget.dvb_frontend->ops.release)
+ budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
@@ -1046,8 +1065,8 @@ static void frontend_init(struct budget_ci *budget_ci)
if (dvb_register_frontend
(&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
printk("budget-ci: Frontend registration failed!\n");
- if (budget_ci->budget.dvb_frontend->ops->release)
- budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ if (budget_ci->budget.dvb_frontend->ops.release)
+ budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
@@ -1082,6 +1101,8 @@ static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
budget_ci->budget.dvb_adapter.priv = budget_ci;
frontend_init(budget_ci);
+ ttpci_budget_init_hooks(&budget_ci->budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index ea2066d461f..e15562f8166 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -63,9 +63,6 @@ static int stop_ts_capture(struct budget *budget)
{
dprintk(2, "budget: %p\n", budget);
- if (--budget->feeding)
- return budget->feeding;
-
saa7146_write(budget->dev, MC1, MASK_20); // DMA3 off
SAA7146_IER_DISABLE(budget->dev, MASK_10);
return 0;
@@ -77,8 +74,8 @@ static int start_ts_capture(struct budget *budget)
dprintk(2, "budget: %p\n", budget);
- if (budget->feeding)
- return ++budget->feeding;
+ if (!budget->feeding || !budget->fe_synced)
+ return 0;
saa7146_write(dev, MC1, MASK_20); // DMA3 off
@@ -139,7 +136,33 @@ static int start_ts_capture(struct budget *budget)
SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
saa7146_write(dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */
- return ++budget->feeding;
+ return 0;
+}
+
+static int budget_read_fe_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct budget *budget = (struct budget *) fe->dvb->priv;
+ int synced;
+ int ret;
+
+ if (budget->read_fe_status)
+ ret = budget->read_fe_status(fe, status);
+ else
+ ret = -EINVAL;
+
+ if (!ret) {
+ synced = (*status & FE_HAS_LOCK);
+ if (synced != budget->fe_synced) {
+ budget->fe_synced = synced;
+ spin_lock(&budget->feedlock);
+ if (synced)
+ start_ts_capture(budget);
+ else
+ stop_ts_capture(budget);
+ spin_unlock(&budget->feedlock);
+ }
+ }
+ return ret;
}
static void vpeirq(unsigned long data)
@@ -267,7 +290,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct budget *budget = (struct budget *) demux->priv;
- int status;
+ int status = 0;
dprintk(2, "budget: %p\n", budget);
@@ -276,7 +299,8 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
spin_lock(&budget->feedlock);
feed->pusi_seen = 0; /* have a clean section start */
- status = start_ts_capture(budget);
+ if (budget->feeding++ == 0)
+ status = start_ts_capture(budget);
spin_unlock(&budget->feedlock);
return status;
}
@@ -285,12 +309,13 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct budget *budget = (struct budget *) demux->priv;
- int status;
+ int status = 0;
dprintk(2, "budget: %p\n", budget);
spin_lock(&budget->feedlock);
- status = stop_ts_capture(budget);
+ if (--budget->feeding == 0)
+ status = stop_ts_capture(budget);
spin_unlock(&budget->feedlock);
return status;
}
@@ -400,7 +425,9 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
budget->dev->name, budget->buffer_width, budget->buffer_height);
printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
- dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
+ if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
+ return ret;
+ }
/* set dd1 stream a & b */
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
@@ -468,6 +495,14 @@ err:
return ret;
}
+void ttpci_budget_init_hooks(struct budget *budget)
+{
+ if (budget->dvb_frontend && !budget->read_fe_status) {
+ budget->read_fe_status = budget->dvb_frontend->ops.read_status;
+ budget->dvb_frontend->ops.read_status = budget_read_fe_status;
+ }
+}
+
int ttpci_budget_deinit(struct budget *budget)
{
struct saa7146_dev *dev = budget->dev;
@@ -506,11 +541,8 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
spin_lock(&budget->feedlock);
budget->video_port = video_port;
if (budget->feeding) {
- int oldfeeding = budget->feeding;
- budget->feeding = 1;
stop_ts_capture(budget);
start_ts_capture(budget);
- budget->feeding = oldfeeding;
}
spin_unlock(&budget->feedlock);
}
@@ -518,6 +550,7 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
EXPORT_SYMBOL_GPL(ttpci_budget_debiread);
EXPORT_SYMBOL_GPL(ttpci_budget_debiwrite);
EXPORT_SYMBOL_GPL(ttpci_budget_init);
+EXPORT_SYMBOL_GPL(ttpci_budget_init_hooks);
EXPORT_SYMBOL_GPL(ttpci_budget_deinit);
EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 1b3aaac5e76..57227441891 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -258,7 +258,7 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c
return 0;
}
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u8 pwr = 0;
@@ -281,7 +281,10 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
@@ -289,10 +292,9 @@ static struct ves1x93_config alps_bsrv2_config = {
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u32 div;
@@ -305,13 +307,15 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = 0x8e;
data[3] = 0x00;
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
static void frontend_init(struct budget_patch* budget)
@@ -323,27 +327,32 @@ static void frontend_init(struct budget_patch* budget)
// try the ALPS BSRV2 first of all
budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
break;
}
// try the ALPS BSRU6 now
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
// Try the grundig 29504-451
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
break;
@@ -358,8 +367,8 @@ static void frontend_init(struct budget_patch* budget)
} else {
if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
printk("budget-av: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ if (budget->dvb_frontend->ops.release)
+ budget->dvb_frontend->ops.release(budget->dvb_frontend);
budget->dvb_frontend = NULL;
}
}
@@ -608,6 +617,8 @@ static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_exte
budget->dvb_adapter.priv = budget;
frontend_init(budget);
+ ttpci_budget_init_hooks(budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index c23c02d9564..863dffb4ed8 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -186,7 +186,7 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
return 0;
}
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u8 pwr = 0;
@@ -209,6 +209,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
@@ -218,10 +220,9 @@ static struct ves1x93_config alps_bsrv2_config =
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -235,6 +236,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
@@ -244,10 +247,9 @@ static struct ves1820_config alps_tdbe2_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -274,16 +276,17 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
- .pll_set = grundig_29504_401_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -296,16 +299,17 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten
data[2] = 0x8e;
data[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
-static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
@@ -326,16 +330,16 @@ static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete
else
data[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- *freqout = div * 1000;
return 0;
}
static struct s5h1420_config s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
- .pll_set = s5h1420_pll_set,
};
static u8 read_pwm(struct budget* budget)
@@ -359,18 +363,18 @@ static void frontend_init(struct budget *budget)
// try the ALPS BSRV2 first of all
budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
// try the ALPS BSRU6 now
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
break;
}
break;
@@ -378,35 +382,45 @@ static void frontend_init(struct budget *budget)
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
- if (budget->dvb_frontend) break;
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
break;
case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
- if (budget->dvb_frontend) break;
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ break;
+ }
break;
case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
}
break;
case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
}
break;
case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+ if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out;
}
@@ -428,8 +442,8 @@ static void frontend_init(struct budget *budget)
error_out:
printk("budget: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ if (budget->dvb_frontend->ops.release)
+ budget->dvb_frontend->ops.release(budget->dvb_frontend);
budget->dvb_frontend = NULL;
return;
}
@@ -457,6 +471,8 @@ static int budget_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_
budget->dvb_adapter.priv = budget;
frontend_init(budget);
+ ttpci_budget_init_hooks(budget);
+
return 0;
}
diff --git a/drivers/media/dvb/ttpci/budget.h b/drivers/media/dvb/ttpci/budget.h
index ecea3a13030..e8a5c79178e 100644
--- a/drivers/media/dvb/ttpci/budget.h
+++ b/drivers/media/dvb/ttpci/budget.h
@@ -52,9 +52,6 @@ struct budget {
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
- int fe_synced;
- struct mutex pid_mutex;
-
int ci_present;
int video_port;
@@ -74,6 +71,9 @@ struct budget {
struct dvb_adapter dvb_adapter;
struct dvb_frontend *dvb_frontend;
+ int (*read_fe_status)(struct dvb_frontend *fe, fe_status_t *status);
+ int fe_synced;
+
void *priv;
};
@@ -106,6 +106,7 @@ static struct saa7146_pci_extension_data x_var = { \
extern int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
struct saa7146_pci_extension_data *info,
struct module *owner);
+extern void ttpci_budget_init_hooks(struct budget *budget);
extern int ttpci_budget_deinit(struct budget *budget);
extern void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 * isr);
extern void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port);
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 914587d52b5..46a6a60d2ab 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -1,11 +1,14 @@
config DVB_TTUSB_BUDGET
tristate "Technotrend/Hauppauge Nova-USB devices"
- depends on DVB_CORE && USB
+ depends on DVB_CORE && USB && I2C
+ select DVB_PLL
select DVB_CX22700
select DVB_TDA1004X
select DVB_VES1820
select DVB_TDA8083
select DVB_STV0299
+ select DVB_STV0297
+ select DVB_LNBP21
help
Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'Nova-USB'.
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 6ceae38125c..04cef302345 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -30,6 +30,8 @@
#include "tda1004x.h"
#include "stv0299.h"
#include "tda8083.h"
+#include "stv0297.h"
+#include "lnbp21.h"
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
@@ -41,7 +43,7 @@
is a bit braindead (no matching channel masks or no matching filter mask),
we won't support this - yet. it doesn't event support negative filters,
so the best way is maybe to keep TTUSB_HWSECTIONS undef'd and just
- parse TS data. USB bandwith will be a problem when having large
+ parse TS data. USB bandwidth will be a problem when having large
datastreams, especially for dvb-net, but hey, that's not my problem.
TTUSB_DISEQC, TTUSB_TONE:
@@ -124,10 +126,6 @@ struct ttusb {
int revision;
-#if 0
- devfs_handle_t stc_devfs_handle;
-#endif
-
struct dvb_frontend* fe;
};
@@ -486,31 +484,6 @@ static int ttusb_send_diseqc(struct dvb_frontend* fe,
}
#endif
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
- struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
- int ret;
- u8 data[1];
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- data[0] = 0x00;
- break;
- case SEC_VOLTAGE_13:
- data[0] = 0x44;
- break;
- case SEC_VOLTAGE_18:
- data[0] = 0x4c;
- break;
- default:
- return -EINVAL;
- };
-
- ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
static int ttusb_update_lnb(struct ttusb *ttusb)
{
u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
@@ -1048,7 +1021,7 @@ static u32 functionality(struct i2c_adapter *adapter)
-static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 data[4];
@@ -1062,20 +1035,21 @@ static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = ((div >> 10) & 0x60) | 0x85;
data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct cx22700_config alps_tdmb7_config = {
.demod_address = 0x43,
- .pll_set = alps_tdmb7_pll_set,
};
-static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
@@ -1083,6 +1057,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
msleep(1);
@@ -1090,6 +1066,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
}
@@ -1097,7 +1075,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
return 0;
}
-static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 tuner_buf[4];
@@ -1157,6 +1135,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -1176,8 +1156,6 @@ static struct tda1004x_config philips_tdm1316l_config = {
.demod_address = 0x8,
.invert = 1,
.invert_oclk = 0,
- .pll_init = philips_tdm1316l_pll_init,
- .pll_set = philips_tdm1316l_pll_set,
.request_firmware = philips_tdm1316l_request_firmware,
};
@@ -1299,7 +1277,7 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32
return 0;
}
-static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
@@ -1322,7 +1300,9 @@ static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *
if (ttusb->revision == TTUSB_REV_2_2)
buf[3] |= 0x20;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
@@ -1338,10 +1318,9 @@ static struct stv0299_config alps_stv0299_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_stv0299_set_symbol_rate,
- .pll_set = philips_tsa5059_pll_set,
};
-static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
@@ -1355,6 +1334,8 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct
buf[2] = 0x8e;
buf[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -1364,10 +1345,9 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct
static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
.demod_address = 0x68,
- .pll_set = ttusb_novas_grundig_29504_491_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = fe->dvb->priv;
u32 div;
@@ -1381,6 +1361,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -1393,7 +1375,6 @@ static struct ves1820_config alps_tdbe2_config = {
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
static u8 read_pwm(struct ttusb* ttusb)
@@ -1410,6 +1391,174 @@ static u8 read_pwm(struct ttusb* ttusb)
}
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
+ u8 tuner_buf[5];
+ struct i2c_msg tuner_msg = {.addr = 0x60,
+ .flags = 0,
+ .buf = tuner_buf,
+ .len = sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency;
+ if (tuner_frequency < 87000000) {return -EINVAL;}
+ else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
+ else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
+ else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
+ else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
+ else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
+ else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
+ else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
+ else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
+ else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
+ else {return -EINVAL;}
+
+ // assume PLL filter should always be 8MHz for the moment.
+ filter = 1;
+
+ // calculate divisor
+ // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
+ tuner_frequency = ((params->frequency + 36125000) / 62500);
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xc8;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ tuner_buf[4] = 0x80;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
+ return -EIO;
+ }
+
+ msleep(50);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
+ return -EIO;
+ }
+
+ msleep(1);
+
+ return 0;
+}
+
+static u8 dvbc_philips_tdm1316l_inittab[] = {
+ 0x80, 0x21,
+ 0x80, 0x20,
+ 0x81, 0x01,
+ 0x81, 0x00,
+ 0x00, 0x09,
+ 0x01, 0x69,
+ 0x03, 0x00,
+ 0x04, 0x00,
+ 0x07, 0x00,
+ 0x08, 0x00,
+ 0x20, 0x00,
+ 0x21, 0x40,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x24, 0x40,
+ 0x25, 0x88,
+ 0x30, 0xff,
+ 0x31, 0x00,
+ 0x32, 0xff,
+ 0x33, 0x00,
+ 0x34, 0x50,
+ 0x35, 0x7f,
+ 0x36, 0x00,
+ 0x37, 0x20,
+ 0x38, 0x00,
+ 0x40, 0x1c,
+ 0x41, 0xff,
+ 0x42, 0x29,
+ 0x43, 0x20,
+ 0x44, 0xff,
+ 0x45, 0x00,
+ 0x46, 0x00,
+ 0x49, 0x04,
+ 0x4a, 0xff,
+ 0x4b, 0x7f,
+ 0x52, 0x30,
+ 0x55, 0xae,
+ 0x56, 0x47,
+ 0x57, 0xe1,
+ 0x58, 0x3a,
+ 0x5a, 0x1e,
+ 0x5b, 0x34,
+ 0x60, 0x00,
+ 0x63, 0x00,
+ 0x64, 0x00,
+ 0x65, 0x00,
+ 0x66, 0x00,
+ 0x67, 0x00,
+ 0x68, 0x00,
+ 0x69, 0x00,
+ 0x6a, 0x02,
+ 0x6b, 0x00,
+ 0x70, 0xff,
+ 0x71, 0x00,
+ 0x72, 0x00,
+ 0x73, 0x00,
+ 0x74, 0x0c,
+ 0x80, 0x00,
+ 0x81, 0x00,
+ 0x82, 0x00,
+ 0x83, 0x00,
+ 0x84, 0x04,
+ 0x85, 0x80,
+ 0x86, 0x24,
+ 0x87, 0x78,
+ 0x88, 0x00,
+ 0x89, 0x00,
+ 0x90, 0x01,
+ 0x91, 0x01,
+ 0xa0, 0x00,
+ 0xa1, 0x00,
+ 0xa2, 0x00,
+ 0xb0, 0x91,
+ 0xb1, 0x0b,
+ 0xc0, 0x4b,
+ 0xc1, 0x00,
+ 0xc2, 0x00,
+ 0xd0, 0x00,
+ 0xd1, 0x00,
+ 0xd2, 0x00,
+ 0xd3, 0x00,
+ 0xd4, 0x00,
+ 0xd5, 0x00,
+ 0xde, 0x00,
+ 0xdf, 0x00,
+ 0x61, 0x38,
+ 0x62, 0x0a,
+ 0x53, 0x13,
+ 0x59, 0x08,
+ 0x55, 0x00,
+ 0x56, 0x40,
+ 0x57, 0x08,
+ 0x58, 0x3d,
+ 0x88, 0x10,
+ 0xa0, 0x00,
+ 0xa0, 0x00,
+ 0xa0, 0x00,
+ 0xa0, 0x04,
+ 0xff, 0xff,
+};
+
+static struct stv0297_config dvbc_philips_tdm1316l_config = {
+ .demod_address = 0x1c,
+ .inittab = dvbc_philips_tdm1316l_inittab,
+ .invert = 0,
+};
+
static void frontend_init(struct ttusb* ttusb)
{
switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
@@ -1417,11 +1566,13 @@ static void frontend_init(struct ttusb* ttusb)
// try the stv0299 based first
ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
+
if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
alps_stv0299_config.inittab = alps_bsbe1_inittab;
- ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+ lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
} else { // ALPS BSRU6
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
}
break;
}
@@ -1429,28 +1580,41 @@ static void frontend_init(struct ttusb* ttusb)
// Grundig 29504-491
ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
break;
}
-
break;
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
+
+ ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
+ }
break;
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
break;
+ }
// Philips td1316
ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
+ }
break;
}
@@ -1461,8 +1625,8 @@ static void frontend_init(struct ttusb* ttusb)
} else {
if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
printk("dvb-ttusb-budget: Frontend registration failed!\n");
- if (ttusb->fe->ops->release)
- ttusb->fe->ops->release(ttusb->fe);
+ if (ttusb->fe->ops.release)
+ ttusb->fe->ops.release(ttusb->fe);
ttusb->fe = NULL;
}
}
@@ -1507,7 +1671,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
mutex_unlock(&ttusb->semi2c);
- if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) {
+ if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) {
ttusb_free_iso_urbs(ttusb);
kfree(ttusb);
return result;
@@ -1578,13 +1742,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
return -ENODEV;
}
-#if 0
- ttusb->stc_devfs_handle =
- devfs_register(ttusb->adapter->devfs_handle, TTUSB_BUDGET_NAME,
- DEVFS_FL_DEFAULT, 0, 192,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
- | S_IROTH | S_IWOTH, &stc_fops, ttusb);
-#endif
usb_set_intfdata(intf, (void *) ttusb);
frontend_init(ttusb);
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 44dea321184..c9d663549df 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -215,7 +215,7 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is dead, cleanup */
dprintk("%s:urb shutting down with status: %d\n",
__FUNCTION__, urb->status);
@@ -1432,7 +1432,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec)
dprintk("%s\n", __FUNCTION__);
if ((result = dvb_register_adapter(&dec->adapter,
- dec->model_name, THIS_MODULE)) < 0) {
+ dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
printk("%s: dvb_register_adapter failed: error %d\n",
__FUNCTION__, result);
@@ -1657,8 +1657,8 @@ static int ttusb_dec_probe(struct usb_interface *intf,
} else {
if (dvb_register_frontend(&dec->adapter, dec->fe)) {
printk("budget-ci: Frontend registration failed!\n");
- if (dec->fe->ops->release)
- dec->fe->ops->release(dec->fe);
+ if (dec->fe->ops.release)
+ dec->fe->ops.release(dec->fe);
dec->fe = NULL;
}
}
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index a5a46175fa0..42f39a89bc4 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -28,8 +28,6 @@
struct ttusbdecfe_state {
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct ttusbdecfe_config* config;
@@ -203,10 +201,9 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
/* setup the state */
state->config = config;
- memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
@@ -226,10 +223,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
state->config = config;
state->voltage = 0;
state->hi_band = 0;
- memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 3fff7576369..220076b1b95 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -136,7 +136,7 @@ config RADIO_GEMTEK_PCI
Choose Y here if you have this PCI FM radio card.
In order to control your radio card, you will need to use programs
- that are compatible with the Video for Linux API. Information on
+ that are compatible with the Video for Linux API. Information on
this API and pointers to "v4l" programs may be found at
<file:Documentation/video4linux/API.html>.
@@ -350,5 +350,15 @@ config RADIO_ZOLTRIX_PORT
help
Enter the I/O port of your Zoltrix radio card.
-endmenu
+config USB_DSBR
+ tristate "D-Link USB FM radio support (EXPERIMENTAL)"
+ depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+ ---help---
+ Say Y here if you want to connect this type of radio to your
+ computer's USB port. Note that the audio is not digital, and
+ you must connect the line out connector to a sound card or a
+ set of speakers.
+ To compile this driver as a module, choose M here: the
+ module will be called dsbr100.
+endmenu
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index 8b351945d06..cf55a18e3dd 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -20,3 +20,6 @@ obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+obj-$(CONFIG_USB_DSBR) += dsbr100.o
+
+EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/video/dsbr100.c b/drivers/media/radio/dsbr100.c
index 3b4e9985c3d..f7e33f9ee8e 100644
--- a/drivers/media/video/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -72,6 +72,7 @@
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index dc292da2605..c4312fa0e2f 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -16,13 +16,14 @@
/* What ever you think about the ACI, version 0x07 is not very well!
* I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions... Robert
+ * conditions... Robert
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/videodev.h>
-#include "../../../sound/oss/aci.h"
+#include <media/v4l2-common.h>
+#include "oss/aci.h"
#include "miropcm20-rds-core.h"
static int radio_nr = -1;
@@ -123,7 +124,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
struct video_device *dev = video_devdata(file);
struct pcm20_device *pcm20 = dev->priv;
int i;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -139,7 +140,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=87*16000;
v->rangehigh=108*16000;
@@ -172,7 +173,7 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
return i;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags=VIDEO_AUDIO_MUTABLE;
@@ -183,12 +184,12 @@ static int pcm20_do_ioctl(struct inode *inode, struct file *file,
v->mode|=VIDEO_SOUND_MONO;
/* v->step=2048; */
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
@@ -237,7 +238,7 @@ static int __init pcm20_init(void)
{
if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
goto video_register_device;
-
+
if(attach_aci_rds()<0)
goto attach_aci_rds;
diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c
index b602c73e230..9428d8b2642 100644
--- a/drivers/media/radio/miropcm20-rds-core.c
+++ b/drivers/media/radio/miropcm20-rds-core.c
@@ -21,7 +21,7 @@
#include <linux/mutex.h>
#include <asm/io.h>
-#include "../../../sound/oss/aci.h"
+#include "oss/aci.h"
#include "miropcm20-rds-core.h"
#define DEBUG 0
@@ -33,24 +33,24 @@ static struct mutex aci_rds_mutex;
#define RDS_BUSYMASK 0x10 /* Bit 4 */
#define RDS_CLOCKMASK 0x08 /* Bit 3 */
-#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
+#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
#if DEBUG
static void print_matrix(char array[], unsigned int length)
{
- int i, j;
-
- for (i=0; i<length; i++) {
- printk(KERN_DEBUG "aci-rds: ");
- for (j=7; j>=0; j--) {
- printk("%d", (array[i] >> j) & 0x1);
- }
- if (i%8 == 0)
- printk(" byte-border\n");
- else
- printk("\n");
- }
+ int i, j;
+
+ for (i=0; i<length; i++) {
+ printk(KERN_DEBUG "aci-rds: ");
+ for (j=7; j>=0; j--) {
+ printk("%d", (array[i] >> j) & 0x1);
+ }
+ if (i%8 == 0)
+ printk(" byte-border\n");
+ else
+ printk("\n");
+ }
}
#endif /* DEBUG */
@@ -114,7 +114,7 @@ static int rds_write(unsigned char cmd)
{
unsigned char sendbuffer[8];
int i;
-
+
if (byte2trans(cmd, sendbuffer, 8) != 0){
return -1;
} else {
@@ -151,7 +151,7 @@ static int rds_read(unsigned char databuffer[], int datasize)
I have to waitread() here */
if (rds_waitread() < 0)
return -1;
-
+
memset(databuffer, 0, datasize);
for (i=0; i< READSIZE; i++)
@@ -194,7 +194,7 @@ int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize)
ret = 0;
mutex_unlock(&aci_rds_mutex);
-
+
return ret;
}
EXPORT_SYMBOL(aci_rds_cmd);
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
index e09214082e0..c1b1db65e66 100644
--- a/drivers/media/radio/miropcm20-rds.c
+++ b/drivers/media/radio/miropcm20-rds.c
@@ -48,7 +48,7 @@ static int rds_f_release(struct inode *in, struct file *fi)
static void print_matrix(char *ch, char out[])
{
- int j;
+ int j;
for (j=7; j>=0; j--) {
out[7-j] = ((*ch >> j) & 0x1) + '0';
@@ -115,7 +115,6 @@ static struct file_operations rds_fops = {
static struct miscdevice rds_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "radiotext",
- .devfs_name = "v4l/rds/radiotext",
.fops = &rds_fops,
};
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 557fb5c4af3..df22a582e7a 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -24,7 +24,7 @@
* out(port, start_increasing_volume);
* wait(a_wee_while);
* out(port, stop_changing_the_volume);
- *
+ *
*/
#include <linux/module.h> /* Modules */
@@ -34,6 +34,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_RTRACK_PORT */
#include <asm/semaphore.h> /* Lock for the I/O */
@@ -41,7 +42,7 @@
#define CONFIG_RADIO_RTRACK_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK_PORT;
+static int io = CONFIG_RADIO_RTRACK_PORT;
static int radio_nr = -1;
static struct mutex lock;
@@ -93,12 +94,12 @@ static int rt_setvol(struct rt_device *dev, int vol)
int i;
mutex_lock(&lock);
-
+
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
outb (0xd8, io); /* enable card */
- }
+ }
mutex_unlock(&lock);
return 0;
}
@@ -114,10 +115,10 @@ static int rt_setvol(struct rt_device *dev, int vol)
dev->muted = 0;
if(vol > dev->curvol)
- for(i = dev->curvol; i < vol; i++)
+ for(i = dev->curvol; i < vol; i++)
rt_incvol();
else
- for(i = dev->curvol; i > vol; i--)
+ for(i = dev->curvol; i > vol; i--)
rt_decvol();
dev->curvol = vol;
@@ -125,7 +126,7 @@ static int rt_setvol(struct rt_device *dev, int vol)
return 0;
}
-/* the 128+64 on these outb's is to keep the volume stable while tuning
+/* the 128+64 on these outb's is to keep the volume stable while tuning
* without them, the volume _will_ creep up with each frequency change
* and bit 4 (+16) is to keep the signal strength meter enabled
*/
@@ -140,7 +141,7 @@ static void send_0_byte(int port, struct rt_device *dev)
outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */
outb_p(128+64+16+8+2+1, port); /* clock */
}
- sleep_delay(1000);
+ sleep_delay(1000);
}
static void send_1_byte(int port, struct rt_device *dev)
@@ -148,13 +149,13 @@ static void send_1_byte(int port, struct rt_device *dev)
if ((dev->curvol == 0) || (dev->muted)) {
outb_p(128+64+16+4 +1, port); /* wr-enable+data high */
outb_p(128+64+16+4+2+1, port); /* clock */
- }
+ }
else {
outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */
outb_p(128+64+16+8+4+2+1, port); /* clock */
}
- sleep_delay(1000);
+ sleep_delay(1000);
}
static int rt_setfreq(struct rt_device *dev, unsigned long freq)
@@ -167,9 +168,9 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
-
+
mutex_lock(&lock); /* Stop other ops interfering */
-
+
send_0_byte (io, dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
@@ -195,7 +196,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
outb (0xd0, io); /* volume steady + sigstr */
else
outb (0xd8, io); /* volume steady + sigstr + on */
-
+
mutex_unlock(&lock);
return 0;
@@ -213,7 +214,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct rt_device *rt=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -229,7 +230,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
@@ -261,21 +262,21 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=rt->curvol * 6554;
v->step=6554;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
rt_mute(rt);
else
rt_setvol(rt,v->volume/6554);
@@ -298,7 +299,7 @@ static struct file_operations rtrack_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = rt_ioctl,
+ .ioctl = rt_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -320,14 +321,14 @@ static int __init rtrack_init(void)
return -EINVAL;
}
- if (!request_region(io, 2, "rtrack"))
+ if (!request_region(io, 2, "rtrack"))
{
printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
return -EBUSY;
}
rtrack_radio.priv=&rtrack_unit;
-
+
if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 2);
@@ -336,10 +337,10 @@ static int __init rtrack_init(void)
printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
/* Set up the I/O locking */
-
+
mutex_init(&lock);
-
- /* mute card - prevents noisy bootups */
+
+ /* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
outb(0x48, io); /* volume down but still "on" */
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 83bdae23417..95e6322133e 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,11 +1,11 @@
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2
+/* radio-aztech.c - Aztech radio card driver for Linux 2.2
*
- * Adapted to support the Video for Linux API by
+ * Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
@@ -31,6 +31,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_AZTECH_PORT */
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -39,7 +40,7 @@
#define CONFIG_RADIO_AZTECH_PORT -1
#endif
-static int io = CONFIG_RADIO_AZTECH_PORT;
+static int io = CONFIG_RADIO_AZTECH_PORT;
static int radio_nr = -1;
static int radio_wait_time = 1000;
static struct mutex lock;
@@ -53,15 +54,15 @@ struct az_device
static int volconvert(int level)
{
- level>>=14; /* Map 16bits down to 2 bit */
- level&=3;
-
+ level>>=14; /* Map 16bits down to 2 bit */
+ level&=3;
+
/* convert to card-friendly values */
- switch (level)
+ switch (level)
{
- case 0:
+ case 0:
return 0;
- case 1:
+ case 1:
return 1;
case 2:
return 4;
@@ -121,9 +122,9 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
frequency += 171200; /* Add 10.7 MHz IF */
frequency /= 800; /* Convert to 50 kHz units */
-
+
mutex_lock(&lock);
-
+
send_0_byte (dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
@@ -151,7 +152,7 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
udelay (radio_wait_time);
outb_p(128+64+volconvert(dev->curvol), io);
-
+
mutex_unlock(&lock);
return 0;
@@ -162,7 +163,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct az_device *az = dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -178,7 +179,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
@@ -211,7 +212,7 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
@@ -222,17 +223,17 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
v->volume=az->curvol;
v->step=16384;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
az->curvol=v->volume;
az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
az_setvol(az,0);
else
az_setvol(az,az->curvol);
@@ -277,7 +278,7 @@ static int __init aztech_init(void)
return -EINVAL;
}
- if (!request_region(io, 2, "aztech"))
+ if (!request_region(io, 2, "aztech"))
{
printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
return -EBUSY;
@@ -285,13 +286,13 @@ static int __init aztech_init(void)
mutex_init(&lock);
aztech_radio.priv=&aztech_unit;
-
+
if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io,2);
return -EINVAL;
}
-
+
printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
/* mute card - prevents noisy bootups */
outb (0, io);
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index f1b5ac81e9d..8641aec7baf 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -8,7 +8,7 @@
* Russell Kroll (rkroll@exploits.org)
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
@@ -34,6 +34,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/param.h>
#include <linux/pnp.h>
@@ -55,29 +56,29 @@ static int cadet_probe(void);
/*
* Signal Strength Threshold Values
- * The V4L API spec does not define any particular unit for the signal
+ * The V4L API spec does not define any particular unit for the signal
* strength value. These values are in microvolts of RF at the tuner's input.
*/
static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
static int cadet_getrds(void)
{
- int rdsstat=0;
+ int rdsstat=0;
spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
+ outb(3,io); /* Select Decoder Control/Status */
outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
spin_unlock(&cadet_io_lock);
-
+
msleep(100);
- spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
+ spin_lock(&cadet_io_lock);
+ outb(3,io); /* Select Decoder Control/Status */
if((inb(io+1)&0x80)!=0) {
- rdsstat|=VIDEO_TUNER_RDS_ON;
+ rdsstat|=VIDEO_TUNER_RDS_ON;
}
if((inb(io+1)&0x10)!=0) {
- rdsstat|=VIDEO_TUNER_MBS_ON;
+ rdsstat|=VIDEO_TUNER_MBS_ON;
}
spin_unlock(&cadet_io_lock);
return rdsstat;
@@ -86,49 +87,49 @@ static int cadet_getrds(void)
static int cadet_getstereo(void)
{
int ret = 0;
- if(curtuner != 0) /* Only FM has stereo capability! */
- return 0;
+ if(curtuner != 0) /* Only FM has stereo capability! */
+ return 0;
spin_lock(&cadet_io_lock);
- outb(7,io); /* Select tuner control */
+ outb(7,io); /* Select tuner control */
if( (inb(io+1) & 0x40) == 0)
- ret = 1;
- spin_unlock(&cadet_io_lock);
- return ret;
+ ret = 1;
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static unsigned cadet_gettune(void)
{
- int curvol,i;
+ int curvol,i;
unsigned fifo=0;
- /*
- * Prepare for read
- */
+ /*
+ * Prepare for read
+ */
spin_lock(&cadet_io_lock);
-
- outb(7,io); /* Select tuner control */
- curvol=inb(io+1); /* Save current volume/mute setting */
- outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
+
+ outb(7,io); /* Select tuner control */
+ curvol=inb(io+1); /* Save current volume/mute setting */
+ outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
tunestat=0xffff;
- /*
- * Read the shift register
- */
- for(i=0;i<25;i++) {
- fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
- if(i<24) {
- outb(0x01,io+1);
+ /*
+ * Read the shift register
+ */
+ for(i=0;i<25;i++) {
+ fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
+ if(i<24) {
+ outb(0x01,io+1);
tunestat&=inb(io+1);
- outb(0x00,io+1);
- }
- }
-
- /*
- * Restore volume/mute setting
- */
- outb(curvol,io+1);
+ outb(0x00,io+1);
+ }
+ }
+
+ /*
+ * Restore volume/mute setting
+ */
+ outb(curvol,io+1);
spin_unlock(&cadet_io_lock);
return fifo;
@@ -136,43 +137,43 @@ static unsigned cadet_gettune(void)
static unsigned cadet_getfreq(void)
{
- int i;
- unsigned freq=0,test,fifo=0;
+ int i;
+ unsigned freq=0,test,fifo=0;
/*
* Read current tuning
*/
fifo=cadet_gettune();
- /*
- * Convert to actual frequency
- */
+ /*
+ * Convert to actual frequency
+ */
if(curtuner==0) { /* FM */
- test=12500;
- for(i=0;i<14;i++) {
- if((fifo&0x01)!=0) {
- freq+=test;
- }
- test=test<<1;
- fifo=fifo>>1;
- }
- freq-=10700000; /* IF frequency is 10.7 MHz */
- freq=(freq*16)/1000000; /* Make it 1/16 MHz */
+ test=12500;
+ for(i=0;i<14;i++) {
+ if((fifo&0x01)!=0) {
+ freq+=test;
+ }
+ test=test<<1;
+ fifo=fifo>>1;
+ }
+ freq-=10700000; /* IF frequency is 10.7 MHz */
+ freq=(freq*16)/1000000; /* Make it 1/16 MHz */
}
if(curtuner==1) { /* AM */
- freq=((fifo&0x7fff)-2010)*16;
+ freq=((fifo&0x7fff)-2010)*16;
}
- return freq;
+ return freq;
}
static void cadet_settune(unsigned fifo)
{
- int i;
- unsigned test;
+ int i;
+ unsigned test;
spin_lock(&cadet_io_lock);
-
+
outb(7,io); /* Select tuner control */
/*
* Write the shift register
@@ -183,7 +184,7 @@ static void cadet_settune(unsigned fifo)
outb(7,io); /* Select tuner control */
outb(test,io+1); /* Initialize for write */
for(i=0;i<25;i++) {
- test|=0x01; /* Toggle SCK High */
+ test|=0x01; /* Toggle SCK High */
outb(test,io+1);
test&=0xfe; /* Toggle SCK Low */
outb(test,io+1);
@@ -196,57 +197,57 @@ static void cadet_settune(unsigned fifo)
static void cadet_setfreq(unsigned freq)
{
- unsigned fifo;
- int i,j,test;
- int curvol;
+ unsigned fifo;
+ int i,j,test;
+ int curvol;
- /*
- * Formulate a fifo command
- */
+ /*
+ * Formulate a fifo command
+ */
fifo=0;
if(curtuner==0) { /* FM */
- test=102400;
- freq=(freq*1000)/16; /* Make it kHz */
- freq+=10700; /* IF is 10700 kHz */
- for(i=0;i<14;i++) {
- fifo=fifo<<1;
- if(freq>=test) {
- fifo|=0x01;
- freq-=test;
- }
- test=test>>1;
- }
+ test=102400;
+ freq=(freq*1000)/16; /* Make it kHz */
+ freq+=10700; /* IF is 10700 kHz */
+ for(i=0;i<14;i++) {
+ fifo=fifo<<1;
+ if(freq>=test) {
+ fifo|=0x01;
+ freq-=test;
+ }
+ test=test>>1;
+ }
}
if(curtuner==1) { /* AM */
- fifo=(freq/16)+2010; /* Make it kHz */
+ fifo=(freq/16)+2010; /* Make it kHz */
fifo|=0x100000; /* Select AM Band */
}
- /*
- * Save current volume/mute setting
- */
+ /*
+ * Save current volume/mute setting
+ */
spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
- curvol=inb(io+1);
- spin_unlock(&cadet_io_lock);
+ curvol=inb(io+1);
+ spin_unlock(&cadet_io_lock);
/*
* Tune the card
*/
for(j=3;j>-1;j--) {
- cadet_settune(fifo|(j<<16));
-
- spin_lock(&cadet_io_lock);
+ cadet_settune(fifo|(j<<16));
+
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
outb(curvol,io+1);
spin_unlock(&cadet_io_lock);
-
+
msleep(100);
cadet_gettune();
if((tunestat & 0x40) == 0) { /* Tuned */
- sigstrength=sigtable[curtuner][j];
+ sigstrength=sigtable[curtuner][j];
return;
}
}
@@ -257,28 +258,28 @@ static void cadet_setfreq(unsigned freq)
static int cadet_getvol(void)
{
int ret = 0;
-
+
spin_lock(&cadet_io_lock);
-
- outb(7,io); /* Select tuner control */
- if((inb(io + 1) & 0x20) != 0)
- ret = 0xffff;
-
- spin_unlock(&cadet_io_lock);
- return ret;
+
+ outb(7,io); /* Select tuner control */
+ if((inb(io + 1) & 0x20) != 0)
+ ret = 0xffff;
+
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static void cadet_setvol(int vol)
{
spin_lock(&cadet_io_lock);
- outb(7,io); /* Select tuner control */
- if(vol>0)
- outb(0x20,io+1);
- else
- outb(0x00,io+1);
+ outb(7,io); /* Select tuner control */
+ if(vol>0)
+ outb(0x20,io+1);
+ else
+ outb(0x00,io+1);
spin_unlock(&cadet_io_lock);
-}
+}
static void cadet_handler(unsigned long data)
{
@@ -288,15 +289,15 @@ static void cadet_handler(unsigned long data)
if(spin_trylock(&cadet_io_lock))
{
- outb(0x3,io); /* Select RDS Decoder Control */
+ outb(0x3,io); /* Select RDS Decoder Control */
if((inb(io+1)&0x20)!=0) {
- printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+ printk(KERN_CRIT "cadet: RDS fifo overflow\n");
}
outb(0x80,io); /* Select RDS fifo */
while((inb(io)&0x80)!=0) {
- rdsbuf[rdsin]=inb(io+1);
+ rdsbuf[rdsin]=inb(io+1);
if(rdsin==rdsout)
- printk(KERN_WARNING "cadet: RDS buffer overflow\n");
+ printk(KERN_WARNING "cadet: RDS buffer overflow\n");
else
rdsin++;
}
@@ -307,9 +308,9 @@ static void cadet_handler(unsigned long data)
* Service pending read
*/
if( rdsin!=rdsout)
- wake_up_interruptible(&read_queue);
+ wake_up_interruptible(&read_queue);
- /*
+ /*
* Clean up and exit
*/
init_timer(&readtimer);
@@ -324,12 +325,12 @@ static void cadet_handler(unsigned long data)
static ssize_t cadet_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
- int i=0;
+ int i=0;
unsigned char readbuf[RDS_BUFFER];
- if(rdsstat==0) {
+ if(rdsstat==0) {
spin_lock(&cadet_io_lock);
- rdsstat=1;
+ rdsstat=1;
outb(0x80,io); /* Select RDS fifo */
spin_unlock(&cadet_io_lock);
init_timer(&readtimer);
@@ -339,15 +340,15 @@ static ssize_t cadet_read(struct file *file, char __user *data,
add_timer(&readtimer);
}
if(rdsin==rdsout) {
- if (file->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
- interruptible_sleep_on(&read_queue);
- }
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&read_queue);
+ }
while( i<count && rdsin!=rdsout)
- readbuf[i++]=rdsbuf[rdsout++];
+ readbuf[i++]=rdsbuf[rdsout++];
if (copy_to_user(data,readbuf,i))
- return -EFAULT;
+ return -EFAULT;
return i;
}
@@ -375,29 +376,29 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
}
switch(v->tuner) {
- case 0:
- strcpy(v->name,"FM");
- v->rangelow=1400; /* 87.5 MHz */
- v->rangehigh=1728; /* 108.0 MHz */
- v->flags=0;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- if(cadet_getstereo()==1) {
- v->flags|=VIDEO_TUNER_STEREO_ON;
- }
+ case 0:
+ strcpy(v->name,"FM");
+ v->rangelow=1400; /* 87.5 MHz */
+ v->rangehigh=1728; /* 108.0 MHz */
+ v->flags=0;
+ v->mode=0;
+ v->mode|=VIDEO_MODE_AUTO;
+ v->signal=sigstrength;
+ if(cadet_getstereo()==1) {
+ v->flags|=VIDEO_TUNER_STEREO_ON;
+ }
v->flags|=cadet_getrds();
- break;
- case 1:
- strcpy(v->name,"AM");
- v->rangelow=8320; /* 520 kHz */
- v->rangehigh=26400; /* 1650 kHz */
- v->flags=0;
- v->flags|=VIDEO_TUNER_LOW;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- break;
+ break;
+ case 1:
+ strcpy(v->name,"AM");
+ v->rangelow=8320; /* 520 kHz */
+ v->rangehigh=26400; /* 1650 kHz */
+ v->flags=0;
+ v->flags|=VIDEO_TUNER_LOW;
+ v->mode=0;
+ v->mode|=VIDEO_MODE_AUTO;
+ v->signal=sigstrength;
+ break;
}
return 0;
}
@@ -407,49 +408,49 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
if((v->tuner<0)||(v->tuner>1)) {
return -EINVAL;
}
- curtuner=v->tuner;
+ curtuner=v->tuner;
return 0;
}
case VIDIOCGFREQ:
{
- unsigned long *freq = arg;
+ unsigned long *freq = arg;
*freq = cadet_getfreq();
return 0;
}
case VIDIOCSFREQ:
{
- unsigned long *freq = arg;
+ unsigned long *freq = arg;
if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
- return -EINVAL;
+ return -EINVAL;
}
if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
- return -EINVAL;
+ return -EINVAL;
}
cadet_setfreq(*freq);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
if(cadet_getstereo()==0) {
- v->mode=VIDEO_SOUND_MONO;
+ v->mode=VIDEO_SOUND_MONO;
} else {
v->mode=VIDEO_SOUND_STEREO;
}
v->volume=cadet_getvol();
v->step=0xffff;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
cadet_setvol(v->volume);
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
cadet_setvol(0);
else
cadet_setvol(0xffff);
@@ -539,16 +540,16 @@ static struct pnp_driver cadet_pnp_driver = {
static int cadet_probe(void)
{
- static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
+ static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
int i;
for(i=0;i<8;i++) {
- io=iovals[i];
+ io=iovals[i];
if (request_region(io, 2, "cadet-probe")) {
- cadet_setfreq(1410);
+ cadet_setfreq(1410);
if(cadet_getfreq()==1410) {
release_region(io, 2);
- return io;
+ return io;
}
release_region(io, 2);
}
@@ -556,7 +557,7 @@ static int cadet_probe(void)
return -1;
}
-/*
+/*
* io should only be set if the user has used something like
* isapnp (the userspace program) to initialize this card for us
*/
@@ -564,7 +565,7 @@ static int cadet_probe(void)
static int __init cadet_init(void)
{
spin_lock_init(&cadet_io_lock);
-
+
/*
* If a probe was requested then probe ISAPnP first (safest)
*/
@@ -579,12 +580,12 @@ static int __init cadet_init(void)
/*
* Else we bail out
*/
-
- if(io < 0) {
-#ifdef MODULE
+
+ if(io < 0) {
+#ifdef MODULE
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
#endif
- goto fail;
+ goto fail;
}
if (!request_region(io,2,"cadet"))
goto fail;
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 8e499b8f64c..4c82956390c 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -1,6 +1,6 @@
/*
***************************************************************************
- *
+ *
* radio-gemtek-pci.c - Gemtek PCI Radio driver
* (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
*
@@ -31,19 +31,19 @@
* radio device driver.
*
* Please, let me know if this piece of code was useful :)
- *
+ *
* TODO: multiple device support and portability were not tested
*
***************************************************************************
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/errno.h>
#include <asm/io.h>
@@ -69,18 +69,18 @@
#define TRUE (1)
#endif
-#ifndef FALSE
+#ifndef FALSE
#define FALSE (0)
#endif
struct gemtek_pci_card {
struct video_device *videodev;
-
+
u32 iobase;
u32 length;
u8 chiprev;
u16 model;
-
+
u32 current_frequency;
u8 mute;
};
@@ -96,7 +96,7 @@ static inline u8 gemtek_pci_out( u16 value, u32 port )
return (u8)value;
}
-#define _b0( v ) *((u8 *)&v)
+#define _b0( v ) *((u8 *)&v)
static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
{
register u8 byte = *last_byte;
@@ -104,7 +104,7 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
if ( !value ) {
if ( !keep )
value = (u16)port;
- byte &= 0xfd;
+ byte &= 0xfd;
} else
byte |= 2;
@@ -116,7 +116,7 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
byte &= 0xfe;
_b0( value ) = byte;
outw( value, port );
-
+
*last_byte = byte;
}
@@ -193,13 +193,13 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
c->audios = 1;
strcpy( c->name, "Gemtek PCI Radio" );
return 0;
- }
+ }
case VIDIOCGTUNER:
{
struct video_tuner *t = arg;
- if ( t->tuner )
+ if ( t->tuner )
return -EINVAL;
t->rangelow = GEMTEK_PCI_RANGE_LOW;
@@ -228,7 +228,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCSFREQ:
{
unsigned long *freq = arg;
-
+
if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
(*freq > GEMTEK_PCI_RANGE_HIGH) )
return -EINVAL;
@@ -239,9 +239,9 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
-
+
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *a = arg;
memset( a, 0, sizeof( *a ) );
@@ -249,17 +249,17 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
a->volume = 1;
a->step = 65535;
strcpy( a->name, "Radio" );
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *a = arg;
- if ( a->audio )
+ if ( a->audio )
return -EINVAL;
- if ( a->flags & VIDEO_AUDIO_MUTE )
+ if ( a->flags & VIDEO_AUDIO_MUTE )
gemtek_pci_mute( card );
else
gemtek_pci_unmute( card );
@@ -323,9 +323,9 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
return -ENOMEM;
}
- if ( pci_enable_device( pci_dev ) )
+ if ( pci_enable_device( pci_dev ) )
goto err_pci;
-
+
card->iobase = pci_resource_start( pci_dev, 0 );
card->length = pci_resource_len( pci_dev, 0 );
@@ -338,7 +338,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
pci_set_drvdata( pci_dev, card );
-
+
if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
printk( KERN_ERR "gemtek_pci: out of memory\n" );
goto err_video;
@@ -354,7 +354,7 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci
devradio->priv = card;
gemtek_pci_mute( card );
- printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
+ printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
card->chiprev, card->iobase, card->iobase + card->length - 1 );
return 0;
@@ -364,7 +364,7 @@ err_video:
err_pci:
kfree( card );
- return -ENODEV;
+ return -ENODEV;
}
static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
@@ -375,12 +375,12 @@ static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
kfree( card->videodev );
release_region( card->iobase, card->length );
-
+
if ( mx )
gemtek_pci_mute( card );
kfree( card );
-
+
pci_set_drvdata( pci_dev, NULL );
}
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 47173be97b9..162f37d8bf9 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -6,7 +6,7 @@
* Besides the protocol changes, this is mostly a copy of:
*
* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- *
+ *
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -22,6 +22,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
#include <linux/spinlock.h>
@@ -29,7 +30,7 @@
#define CONFIG_RADIO_GEMTEK_PORT -1
#endif
-static int io = CONFIG_RADIO_GEMTEK_PORT;
+static int io = CONFIG_RADIO_GEMTEK_PORT;
static int radio_nr = -1;
static spinlock_t lock;
@@ -48,7 +49,7 @@ struct gemtek_device
*/
static void gemtek_mute(struct gemtek_device *dev)
{
- if(dev->muted)
+ if(dev->muted)
return;
spin_lock(&lock);
outb(0x10, io);
@@ -94,20 +95,20 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
freq /= 100000;
spin_lock(&lock);
-
+
/* 2 start bits */
outb_p(0x03, io);
udelay(5);
outb_p(0x07, io);
udelay(5);
- /* 28 frequency bits (lsb first) */
+ /* 28 frequency bits (lsb first) */
for (i = 0; i < 14; i++)
if (freq & (1 << i))
one();
else
zero();
- /* 36 unknown bits */
+ /* 36 unknown bits */
for (i = 0; i < 11; i++)
zero();
one();
@@ -123,7 +124,7 @@ static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
udelay(5);
spin_unlock(&lock);
-
+
return 0;
}
@@ -159,7 +160,7 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=87*16000;
v->rangehigh=108*16000;
@@ -193,25 +194,25 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE;
v->volume=1;
v->step=65535;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
gemtek_mute(rt);
else
- gemtek_unmute(rt);
+ gemtek_unmute(rt);
return 0;
}
@@ -254,14 +255,14 @@ static int __init gemtek_init(void)
return -EINVAL;
}
- if (!request_region(io, 4, "gemtek"))
+ if (!request_region(io, 4, "gemtek"))
{
printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
return -EBUSY;
}
gemtek_radio.priv=&gemtek_unit;
-
+
if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 4);
@@ -274,7 +275,7 @@ static int __init gemtek_init(void)
/* this is _maybe_ unnecessary */
outb(0x01, io);
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
gemtek_unit.muted = 0;
gemtek_mute(&gemtek_unit);
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 39c1d911863..fcfa6c9fe22 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -2,7 +2,7 @@
* (c) 2000 A. Tlalka, atlka@pg.gda.pl
* Notes on the hardware
*
- * + Frequency control is done digitally
+ * + Frequency control is done digitally
* + No volume control - only mute/unmute - you have to use Aux line volume
* control on Maestro card to set the volume
* + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
@@ -26,7 +26,7 @@
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
#define DRIVER_VERSION "0.05"
@@ -103,7 +103,7 @@ static struct video_device maestro_radio = {
struct radio_device {
u16 io, /* base of Maestro card radio io (GPIO_DATA)*/
muted, /* VIDEO_AUDIO_MUTE */
- stereo, /* VIDEO_TUNER_STEREO_ON */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
struct mutex lock;
};
@@ -122,14 +122,14 @@ static u32 radio_bits_get(struct radio_device *dev)
for (l=24;l--;) {
outw(STR_CLK, io); /* HI state */
udelay(2);
- if(!l)
+ if(!l)
dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
outw(0, io); /* LO state */
udelay(2);
data <<= 1; /* shift data */
rdata = inw(io);
if(!l)
- dev->stereo = rdata & STR_MOST ?
+ dev->stereo = rdata & STR_MOST ?
0 : VIDEO_TUNER_STEREO_ON;
else
if(rdata & STR_DATA)
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f0bf47bcb64..f93d7afe730 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -1,15 +1,15 @@
-/*
- * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
+/*
+ * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
* (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
*
* Based in the radio Maestro PCI driver. Actually it uses the same chip
* for radio but different pci controller.
*
* I didn't have any specs I reversed engineered the protocol from
- * the windows driver (radio.dll).
+ * the windows driver (radio.dll).
*
* The card uses the TEA5757 chip that includes a search function but it
- * is useless as I haven't found any way to read back the frequency. If
+ * is useless as I haven't found any way to read back the frequency. If
* anybody does please mail me.
*
* For the pdf file see:
@@ -24,7 +24,7 @@
* - tiding up
* - removed support for multiple devices as it didn't work anyway
*
- * BUGS:
+ * BUGS:
* - card unmutes if you change frequency
*
*/
@@ -41,6 +41,7 @@
#include <linux/pci.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
/* version 0.75 Sun Feb 4 22:51:27 EET 2001 */
#define DRIVER_VERSION "0.75"
@@ -80,7 +81,7 @@ static struct file_operations maxiradio_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = radio_ioctl,
+ .ioctl = radio_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -97,11 +98,11 @@ static struct radio_device
{
__u16 io, /* base of radio io */
muted, /* VIDEO_AUDIO_MUTE */
- stereo, /* VIDEO_TUNER_STEREO_ON */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
-
+
unsigned long freq;
-
+
struct mutex lock;
} radio_unit = {0, 0, 0, 0, };
@@ -114,7 +115,7 @@ static void outbit(unsigned long bit, __u16 io)
outb( power|wren|data|clk ,io); udelay(4);
outb( power|wren|data ,io); udelay(4);
}
- else
+ else
{
outb( power|wren ,io); udelay(4);
outb( power|wren|clk ,io); udelay(4);
@@ -132,12 +133,12 @@ static void set_freq(__u16 io, __u32 data)
{
unsigned long int si;
int bl;
-
+
/* TEA5757 shift register bits (see pdf) */
- outbit(0,io); // 24 search
+ outbit(0,io); // 24 search
outbit(1,io); // 23 search up/down
-
+
outbit(0,io); // 22 stereo/mono
outbit(0,io); // 21 band
@@ -145,24 +146,24 @@ static void set_freq(__u16 io, __u32 data)
outbit(0,io); // 19 port ?
outbit(0,io); // 18 port ?
-
+
outbit(0,io); // 17 search level
outbit(0,io); // 16 search level
-
+
si = 0x8000;
for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
-
+
outb(power,io);
}
static int get_stereo(__u16 io)
-{
+{
outb(power,io); udelay(4);
return !(inb(io) & mo_st);
}
static int get_tune(__u16 io)
-{
+{
outb(power+clk,io); udelay(4);
return !(inb(io) & mo_st);
}
@@ -177,7 +178,7 @@ static inline int radio_function(struct inode *inode, struct file *file,
switch(cmd) {
case VIDIOCGCAP: {
struct video_capability *v = arg;
-
+
memset(v,0,sizeof(*v));
strcpy(v->name, "Maxi Radio FM2000 radio");
v->type=VID_TYPE_TUNER;
@@ -186,22 +187,22 @@ static inline int radio_function(struct inode *inode, struct file *file,
}
case VIDIOCGTUNER: {
struct video_tuner *v = arg;
-
+
if(v->tuner)
return -EINVAL;
-
+
card->stereo = 0xffff * get_stereo(card->io);
card->tuned = 0xffff * get_tune(card->io);
-
+
v->flags = VIDEO_TUNER_LOW | card->stereo;
v->signal = card->tuned;
-
+
strcpy(v->name, "FM");
-
+
v->rangelow = FREQ_LO;
v->rangehigh = FREQ_HI;
v->mode = VIDEO_MODE_AUTO;
-
+
return 0;
}
case VIDIOCSTUNER: {
@@ -212,13 +213,13 @@ static inline int radio_function(struct inode *inode, struct file *file,
}
case VIDIOCGFREQ: {
unsigned long *freq = arg;
-
+
*freq = card->freq;
return 0;
}
case VIDIOCSFREQ: {
unsigned long *freq = arg;
-
+
if (*freq < FREQ_LO || *freq > FREQ_HI)
return -EINVAL;
card->freq = *freq;
@@ -226,18 +227,18 @@ static inline int radio_function(struct inode *inode, struct file *file,
msleep(125);
return 0;
}
- case VIDIOCGAUDIO: {
+ case VIDIOCGAUDIO: {
struct video_audio *v = arg;
memset(v,0,sizeof(*v));
strcpy(v->name, "Radio");
v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
v->mode=VIDEO_SOUND_STEREO;
- return 0;
+ return 0;
}
-
+
case VIDIOCSAUDIO: {
struct video_audio *v = arg;
-
+
if(v->audio)
return -EINVAL;
card->muted = v->flags & VIDEO_AUDIO_MUTE;
@@ -249,13 +250,13 @@ static inline int radio_function(struct inode *inode, struct file *file,
}
case VIDIOCGUNIT: {
struct video_unit *v = arg;
-
+
v->video=VIDEO_NO_UNIT;
v->vbi=VIDEO_NO_UNIT;
v->radio=dev->minor;
v->audio=0;
v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return 0;
}
default: return -ENOIOCTLCMD;
}
@@ -267,7 +268,7 @@ static int radio_ioctl(struct inode *inode, struct file *file,
struct video_device *dev = video_devdata(file);
struct radio_device *card=dev->priv;
int ret;
-
+
mutex_lock(&card->lock);
ret = video_usercopy(inode, file, cmd, arg, radio_function);
mutex_unlock(&card->lock);
@@ -282,21 +283,21 @@ MODULE_LICENSE("GPL");
static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
if(!request_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
- printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
- goto err_out;
+ pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+ printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+ goto err_out;
}
if (pci_enable_device(pdev))
- goto err_out_free_region;
+ goto err_out_free_region;
radio_unit.io = pci_resource_start(pdev, 0);
mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
- printk("radio-maxiradio: can't register device!");
- goto err_out_free_region;
+ printk("radio-maxiradio: can't register device!");
+ goto err_out_free_region;
}
printk(KERN_INFO "radio-maxiradio: version "
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 28a47c9e7a8..5b68ac4c732 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -1,5 +1,5 @@
/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- *
+ *
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
@@ -15,6 +15,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_RTRACK2_PORT */
#include <linux/spinlock.h>
@@ -22,7 +23,7 @@
#define CONFIG_RADIO_RTRACK2_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK2_PORT;
+static int io = CONFIG_RADIO_RTRACK2_PORT;
static int radio_nr = -1;
static spinlock_t lock;
@@ -38,7 +39,7 @@ struct rt_device
static void rt_mute(struct rt_device *dev)
{
- if(dev->muted)
+ if(dev->muted)
return;
spin_lock(&lock);
outb(1, io);
@@ -58,14 +59,14 @@ static void rt_unmute(struct rt_device *dev)
static void zero(void)
{
- outb_p(1, io);
+ outb_p(1, io);
outb_p(3, io);
outb_p(1, io);
}
static void one(void)
{
- outb_p(5, io);
+ outb_p(5, io);
outb_p(7, io);
outb_p(5, io);
}
@@ -75,7 +76,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
int i;
freq = freq / 200 + 856;
-
+
spin_lock(&lock);
outb_p(0xc8, io);
@@ -94,7 +95,7 @@ static int rt_setfreq(struct rt_device *dev, unsigned long freq)
outb_p(0xc8, io);
if (!dev->muted)
outb_p(0, io);
-
+
spin_unlock(&lock);
return 0;
}
@@ -127,7 +128,7 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=88*16000;
v->rangehigh=108*16000;
@@ -159,25 +160,25 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE;
v->volume=1;
v->step=65535;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
rt_mute(rt);
else
- rt_unmute(rt);
+ rt_unmute(rt);
return 0;
}
@@ -219,7 +220,7 @@ static int __init rtrack2_init(void)
printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
return -EINVAL;
}
- if (!request_region(io, 4, "rtrack2"))
+ if (!request_region(io, 4, "rtrack2"))
{
printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
return -EBUSY;
@@ -227,16 +228,16 @@ static int __init rtrack2_init(void)
rtrack2_radio.priv=&rtrack2_unit;
- spin_lock_init(&lock);
+ spin_lock_init(&lock);
if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 4);
return -EINVAL;
}
-
+
printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
outb(1, io);
rtrack2_unit.muted = 1;
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 53073b42410..efee6e339d1 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -12,7 +12,7 @@
* Frequency control is done digitally -- ie out(port,encodefreq(95.8));
* No volume control - only mute/unmute - you have to use line volume
* control on SB-part of SF16FMI
- *
+ *
*/
#include <linux/kernel.h> /* __setup */
@@ -21,6 +21,7 @@
#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/isapnp.h>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
@@ -29,19 +30,19 @@
struct fmi_device
{
int port;
- int curvol; /* 1 or 0 */
- unsigned long curfreq; /* freq in kHz */
- __u32 flags;
+ int curvol; /* 1 or 0 */
+ unsigned long curfreq; /* freq in kHz */
+ __u32 flags;
};
-static int io = -1;
+static int io = -1;
static int radio_nr = -1;
static struct pnp_dev *dev = NULL;
static struct mutex lock;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
* 92.7400017 -> 92.75
*/
#define RSF16_ENCODE(x) ((x)/800+214)
@@ -51,7 +52,7 @@ static struct mutex lock;
static void outbits(int bits, unsigned int data, int port)
{
while(bits--) {
- if(data & 1) {
+ if(data & 1) {
outb(5, port);
udelay(6);
outb(7, port);
@@ -101,7 +102,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
int res;
int myport = dev->port;
-
+
mutex_lock(&lock);
val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
outb(val, myport);
@@ -109,7 +110,7 @@ static inline int fmi_getsigstr(struct fmi_device *dev)
msleep(143); /* was schedule_timeout(HZ/7) */
res = (int)inb(myport+1);
outb(val, myport);
-
+
mutex_unlock(&lock);
return (res & 2) ? 0 : 0xFFFF;
}
@@ -119,7 +120,7 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct fmi_device *fmi=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -174,18 +175,18 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
/*rounding in steps of 800 to match th freq
that will be used */
- fmi->curfreq = (*freq/800)*800;
+ fmi->curfreq = (*freq/800)*800;
fmi_setfreq(fmi);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0,sizeof(*v));
v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
strcpy(v->name, "Radio");
v->mode=VIDEO_SOUND_STEREO;
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
@@ -193,19 +194,19 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
if(v->audio)
return -EINVAL;
fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
- fmi->curvol ?
+ fmi->curvol ?
fmi_unmute(fmi->port) : fmi_mute(fmi->port);
return 0;
}
- case VIDIOCGUNIT:
+ case VIDIOCGUNIT:
{
- struct video_unit *v = arg;
+ struct video_unit *v = arg;
v->video=VIDEO_NO_UNIT;
v->vbi=VIDEO_NO_UNIT;
v->radio=dev->minor;
v->audio=0; /* How do we find out this??? */
v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return 0;
}
default:
return -ENOIOCTLCMD;
@@ -295,14 +296,14 @@ static int __init fmi_init(void)
fmi_unit.curfreq = 0;
fmi_unit.flags = VIDEO_TUNER_LOW;
fmi_radio.priv = &fmi_unit;
-
+
mutex_init(&lock);
-
+
if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
release_region(io, 2);
return -EINVAL;
}
-
+
printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
/* mute card - prevents noisy bootups */
fmi_mute(io);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index bcebd8cb19a..3483b2c7bc9 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -19,6 +19,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
static struct mutex lock;
@@ -202,7 +203,7 @@ static int fmr2_setvolume(struct fmr2_device *dev)
}
static int fmr2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct fmr2_device *fmr2 = dev->priv;
@@ -344,7 +345,7 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
}
static int fmr2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
}
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index fcfde2e4f19..dfba4ae596c 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -2,11 +2,11 @@
* (c) 1999 R. Offermanns (rolf@offermanns.de)
* based on the aimslab radio driver from M. Kirkwood
* many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
- *
+ *
*
* History:
* 1999-05-21 First preview release
- *
+ *
* Notes on the hardware:
* There are two "main" chips on the card:
* - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
@@ -20,7 +20,7 @@
* (as soon i have understand how to get started :)
* If you can help me out with that, please contact me!!
*
- *
+ *
*/
#include <linux/module.h> /* Modules */
@@ -30,6 +30,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TERRATEC_PORT */
#include <linux/spinlock.h>
@@ -49,7 +50,7 @@
#define WRT_EN 0x10
/*******************************************************************/
-static int io = CONFIG_RADIO_TERRATEC_PORT;
+static int io = CONFIG_RADIO_TERRATEC_PORT;
static int radio_nr = -1;
static spinlock_t lock;
@@ -88,15 +89,15 @@ static void tt_mute(struct tt_device *dev)
static int tt_setvol(struct tt_device *dev, int vol)
{
-
+
// printk(KERN_ERR "setvol called, vol = %d\n", vol);
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
cardWriteVol(vol); /* enable card */
- }
-
+ }
+
return 0;
}
@@ -107,9 +108,9 @@ static int tt_setvol(struct tt_device *dev, int vol)
}
dev->muted = 0;
-
+
cardWriteVol(vol);
-
+
dev->curvol = vol;
return 0;
@@ -121,13 +122,13 @@ static int tt_setvol(struct tt_device *dev, int vol)
/* many more or less strange things are going on here, but hey, it works :) */
static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
-{
+{
int freq;
int i;
int p;
int temp;
long rest;
-
+
unsigned char buffer[25]; /* we have to bit shift 25 registers */
freq = freq1/160; /* convert the freq. to a nice to handle value */
for(i=24;i>-1;i--)
@@ -142,9 +143,9 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
{
if (rest%temp == rest)
buffer[i] = 0;
- else
+ else
{
- buffer[i] = 1;
+ buffer[i] = 1;
rest = rest-temp;
}
i--;
@@ -153,10 +154,10 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
}
spin_lock(&lock);
-
+
for (i=24;i>-1;i--) /* bit shift the values to the radiocard */
{
- if (buffer[i]==1)
+ if (buffer[i]==1)
{
outb(WRT_EN|DATA, BASEPORT);
outb(WRT_EN|DATA|CLK_ON , BASEPORT);
@@ -168,11 +169,11 @@ static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
outb(WRT_EN|0x00|CLK_ON , BASEPORT);
}
}
- outb(0x00, BASEPORT);
-
+ outb(0x00, BASEPORT);
+
spin_unlock(&lock);
-
- return 0;
+
+ return 0;
}
static int tt_getsigstr(struct tt_device *dev) /* TODO */
@@ -190,7 +191,7 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
{
struct video_device *dev = video_devdata(file);
struct tt_device *tt=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
@@ -206,7 +207,7 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
@@ -238,21 +239,21 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=tt->curvol * 6554;
v->step=6554;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
tt_mute(tt);
else
tt_setvol(tt,v->volume/6554);
@@ -296,25 +297,25 @@ static int __init terratec_init(void)
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if (!request_region(io, 2, "terratec"))
+ if (!request_region(io, 2, "terratec"))
{
printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
return -EBUSY;
}
terratec_radio.priv=&terratec_unit;
-
+
spin_lock_init(&lock);
-
+
if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io,2);
return -EINVAL;
}
-
+
printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
cardWriteVol(0);
@@ -334,7 +335,7 @@ static void __exit terratec_cleanup_module(void)
{
video_unregister_device(&terratec_radio);
release_region(io,2);
- printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+ printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
}
module_init(terratec_init);
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 5a099a50d4d..8da4badc22b 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -1,14 +1,14 @@
-/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
+/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
* by Eric Lammerts <eric@scintilla.utwente.nl>
*
* Based on radio-aztech.c. Original notes:
*
- * Adapted to support the Video for Linux API by
+ * Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
@@ -22,6 +22,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -30,7 +31,7 @@
#define CONFIG_RADIO_TRUST_PORT -1
#endif
-static int io = CONFIG_RADIO_TRUST_PORT;
+static int io = CONFIG_RADIO_TRUST_PORT;
static int radio_nr = -1;
static int ioval = 0xf;
static __u16 curvol;
@@ -135,7 +136,7 @@ static void tr_setmute(int mute)
static int tr_getsigstr(void)
{
int i, v;
-
+
for(i = 0, v = 0; i < 100; i++) v |= inb(io);
return (v & 1)? 0 : 0xffff;
}
@@ -175,7 +176,7 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow = 87500 * 16;
@@ -211,28 +212,28 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+ VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
v->volume = curvol * 2048;
v->step = 2048;
v->bass = curbass * 4370;
v->treble = curtreble * 4370;
-
+
strcpy(v->name, "Trust FM Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- tr_setvol(v->volume);
+ tr_setvol(v->volume);
tr_setbass(v->bass);
tr_settreble(v->treble);
tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
@@ -292,7 +293,7 @@ static int __init trust_init(void)
write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
- tr_setvol(0x8000);
+ tr_setvol(0x8000);
tr_setbass(0x8000);
tr_settreble(0x8000);
tr_setstereo(1);
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index e50955836d6..edd01228866 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -36,6 +36,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TYPHOON_* */
#define BANNER "Typhoon Radio Card driver v0.1\n"
@@ -361,8 +362,8 @@ static int __init typhoon_init(void)
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
- typhoon_get_info))
- printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+ typhoon_get_info))
+ printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
#endif
return 0;
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 7bf1a426489..59b86a6b4b0 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -1,7 +1,7 @@
/* zoltrix radio plus driver for Linux radio support
* (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
*
- * BUGS
+ * BUGS
* Due to the inconsistency in reading from the signal flags
* it is difficult to get an accurate tuned signal.
*
@@ -14,7 +14,7 @@
*
* 1999-05-06 - (C. van Schaik)
* - Make signal strength and stereo scans
- * kinder to cpu while in delay
+ * kinder to cpu while in delay
* 1999-01-05 - (C. van Schaik)
* - Changed tuning to 1/160Mhz accuracy
* - Added stereo support
@@ -33,6 +33,7 @@
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_ZOLTRIX_PORT */
#ifndef CONFIG_RADIO_ZOLTRIX_PORT
@@ -105,7 +106,7 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
i = 45;
mutex_lock(&dev->lock);
-
+
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
@@ -139,8 +140,8 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
udelay(1000);
inb(io+2);
- udelay(1000);
-
+ udelay(1000);
+
if (dev->muted)
{
outb(0, io);
@@ -148,12 +149,12 @@ static int zol_setfreq(struct zol_device *dev, unsigned long freq)
inb(io + 3);
udelay(1000);
}
-
+
mutex_unlock(&dev->lock);
-
+
if(!dev->muted)
{
- zol_setvol(dev, dev->curvol);
+ zol_setvol(dev, dev->curvol);
}
return 0;
}
@@ -174,14 +175,14 @@ static int zol_getsigstr(struct zol_device *dev)
b = inb(io);
mutex_unlock(&dev->lock);
-
+
if (a != b)
return (0);
- if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
+ if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
|| (a == 0xef)) /* with a binary scanner on the card io */
return (1);
- return (0);
+ return (0);
}
static int zol_is_stereo (struct zol_device *dev)
@@ -189,7 +190,7 @@ static int zol_is_stereo (struct zol_device *dev)
int x1, x2;
mutex_lock(&dev->lock);
-
+
outb(0x00, io);
outb(dev->curvol, io);
msleep(20);
@@ -199,7 +200,7 @@ static int zol_is_stereo (struct zol_device *dev)
x2 = inb(io);
mutex_unlock(&dev->lock);
-
+
if ((x1 == x2) && (x1 == 0xcf))
return 1;
return 0;
@@ -226,7 +227,7 @@ static int zol_do_ioctl(struct inode *inode, struct file *file,
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if (v->tuner)
+ if (v->tuner)
return -EINVAL;
strcpy(v->name, "FM");
v->rangelow = (int) (88.0 * 16000);
@@ -351,7 +352,7 @@ static int __init zoltrix_init(void)
printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
mutex_init(&zoltrix_unit.lock);
-
+
/* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6b419701856..94d078b77ba 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -145,7 +145,7 @@ config VIDEO_SAA5246A
config VIDEO_SAA5249
tristate "SAA5249 Teletext processor"
- depends on VIDEO_DEV && I2C
+ depends on VIDEO_DEV && I2C && VIDEO_V4L1
help
Support for I2C bus based teletext using the SAA5249 chip. At the
moment this is only useful on some European WinTV cards.
@@ -155,7 +155,7 @@ config VIDEO_SAA5249
config TUNER_3036
tristate "SAB3036 tuner"
- depends on VIDEO_DEV && I2C
+ depends on VIDEO_DEV && I2C && VIDEO_V4L1
help
Say Y here to include support for Philips SAB3036 compatible tuners.
If in doubt, say N.
@@ -224,6 +224,12 @@ config VIDEO_ZORAN_LML33R10
support for the Linux Media Labs LML33R10 MJPEG capture/playback
card.
+config VIDEO_ZORAN_AVS6EYES
+ tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+ depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+ help
+ Support for the AverMedia 6 Eyes video surveillance card.
+
config VIDEO_ZR36120
tristate "Zoran ZR36120/36125 Video For Linux"
depends on PCI && I2C && VIDEO_V4L1 && BROKEN
@@ -254,7 +260,7 @@ source "drivers/media/video/saa7134/Kconfig"
config VIDEO_MXB
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
- depends on PCI && VIDEO_V4L1
+ depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
select VIDEO_TUNER
---help---
@@ -266,7 +272,7 @@ config VIDEO_MXB
config VIDEO_DPC
tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
- depends on PCI && VIDEO_V4L1
+ depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
select VIDEO_V4L2
---help---
@@ -281,7 +287,7 @@ config VIDEO_DPC
config VIDEO_HEXIUM_ORION
tristate "Hexium HV-PCI6 and Orion frame grabber"
- depends on PCI && VIDEO_V4L1
+ depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
select VIDEO_V4L2
---help---
@@ -293,7 +299,7 @@ config VIDEO_HEXIUM_ORION
config VIDEO_HEXIUM_GEMINI
tristate "Hexium Gemini frame grabber"
- depends on PCI && VIDEO_V4L1
+ depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
select VIDEO_V4L2
---help---
@@ -306,17 +312,6 @@ config VIDEO_HEXIUM_GEMINI
source "drivers/media/video/cx88/Kconfig"
-config VIDEO_OVCAMCHIP
- tristate "OmniVision Camera Chip support"
- depends on I2C && VIDEO_V4L1
- ---help---
- Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
- This driver is intended to be used with the ov511 and w9968cf USB
- camera drivers.
-
- To compile this driver as a module, choose M here: the
- module will be called ovcamchip.
-
config VIDEO_M32R_AR
tristate "AR devices"
depends on M32R && VIDEO_V4L1
@@ -357,6 +352,15 @@ config VIDEO_CS53L32A
To compile this driver as a module, choose M here: the
module will be called cs53l32a.
+config VIDEO_TLV320AIC23B
+ tristate "Texas Instruments TLV320AIC23B audio codec"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Texas Instruments TLV320AIC23B audio codec.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tlv320aic23b.
+
config VIDEO_WM8775
tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
depends on VIDEO_DEV && I2C && EXPERIMENTAL
@@ -377,13 +381,25 @@ config VIDEO_WM8739
To compile this driver as a module, choose M here: the
module will be called wm8739.
+config VIDEO_CX2341X
+ tristate "Conexant CX2341x MPEG encoders"
+ depends on VIDEO_V4L2 && EXPERIMENTAL
+ ---help---
+ Support for the Conexant CX23416 MPEG encoders
+ and CX23415 MPEG encoder/decoders.
+
+ This module currently supports the encoding functions only.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx2341x.
+
source "drivers/media/video/cx25840/Kconfig"
config VIDEO_SAA711X
- tristate "Philips SAA7113/4/5 video decoders (OBSOLETED)"
- depends on VIDEO_V4L1 && I2C && EXPERIMENTAL
+ tristate "Philips SAA7113/4/5 video decoders"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
---help---
- Old support for the Philips SAA7113/4 video decoders.
+ Support for the Philips SAA7113/4/5 video decoders.
To compile this driver as a module, choose M here: the
module will be called saa7115.
@@ -429,23 +445,42 @@ endmenu # encoder / decoder chips
menu "V4L USB devices"
depends on USB && VIDEO_DEV
+source "drivers/media/video/pvrusb2/Kconfig"
+
source "drivers/media/video/em28xx/Kconfig"
-config USB_DSBR
- tristate "D-Link USB FM radio support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+source "drivers/media/video/usbvideo/Kconfig"
+
+source "drivers/media/video/et61x251/Kconfig"
+
+config VIDEO_OVCAMCHIP
+ tristate "OmniVision Camera Chip support"
+ depends on I2C && VIDEO_V4L1
---help---
- Say Y here if you want to connect this type of radio to your
- computer's USB port. Note that the audio is not digital, and
- you must connect the line out connector to a sound card or a
- set of speakers.
+ Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
+ This driver is intended to be used with the ov511 and w9968cf USB
+ camera drivers.
To compile this driver as a module, choose M here: the
- module will be called dsbr100.
+ module will be called ovcamchip.
-source "drivers/media/video/usbvideo/Kconfig"
+config USB_W9968CF
+ tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+ depends on USB && VIDEO_V4L1 && I2C
+ select VIDEO_OVCAMCHIP
+ ---help---
+ Say Y here if you want support for cameras based on OV681 or
+ Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-source "drivers/media/video/et61x251/Kconfig"
+ This driver has an optional plugin, which is distributed as a
+ separate module only (released under GPL). It allows to use higher
+ resolutions and framerates, but cannot be included in the official
+ Linux kernel for performance purposes.
+
+ See <file:Documentation/video4linux/w9968cf.txt> for more info.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w9968cf.
config USB_OV511
tristate "USB OV511 Camera support"
@@ -483,24 +518,6 @@ config USB_STV680
To compile this driver as a module, choose M here: the
module will be called stv680.
-config USB_W9968CF
- tristate "USB W996[87]CF JPEG Dual Mode Camera support"
- depends on USB && VIDEO_V4L1 && I2C
- select VIDEO_OVCAMCHIP
- ---help---
- Say Y here if you want support for cameras based on OV681 or
- Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
- This driver has an optional plugin, which is distributed as a
- separate module only (released under GPL). It allows to use higher
- resolutions and framerates, but cannot be included in the official
- Linux kernel for performance purposes.
-
- See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called w9968cf.
-
source "drivers/media/video/zc0301/Kconfig"
source "drivers/media/video/pwc/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e5bf2687b76..e82e511f2a7 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -6,7 +6,7 @@ zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
- mt20xx.o tda8290.o tea5767.o
+ mt20xx.o tda8290.o tea5767.o tda9887.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
@@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
zr36016.o
obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
@@ -46,8 +47,10 @@ obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
@@ -58,7 +61,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_BUF) += video-buf.o
obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
@@ -71,9 +74,9 @@ obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
-obj-$(CONFIG_USB_DSBR) += dsbr100.o
obj-$(CONFIG_USB_OV511) += ov511.o
obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_STV680) += stv680.o
@@ -87,6 +90,7 @@ obj-$(CONFIG_USB_ZC0301) += zc0301/
obj-$(CONFIG_USB_IBMCAM) += usbvideo/
obj-$(CONFIG_USB_KONICAWC) += usbvideo/
obj-$(CONFIG_USB_VICAM) += usbvideo/
+obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index dbe02517059..5c5e682a300 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -18,9 +18,7 @@
* 2003-09-01: Support w3cam by Takeo Takahashi
*/
-#include <linux/config.h>
#include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -31,6 +29,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -212,7 +211,7 @@ void init_iic(void)
ar_outl(0x0300, PLDI2CMOD); /* I2CMOD ACK/8b-data/7b-addr/auto */
ar_outl(0x1, PLDI2CACK); /* I2CACK ACK */
- /* I2C CLK */
+ /* I2C CLK */
/* 50MH-100k */
if (freq == 75) {
ar_outl(369, PLDI2CFREQ); /* BCLK = 75MHz */
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
new file mode 100644
index 00000000000..05e42bbcfc3
--- /dev/null
+++ b/drivers/media/video/bt866.c
@@ -0,0 +1,377 @@
+/*
+ bt866 - BT866 Digital Video Encoder (Rockwell Part)
+
+ Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+ Modifications for LML33/DC10plus unified driver
+ Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+ This code was modify/ported from the saa7111 driver written
+ by Dave Perks.
+
+ This code was adapted for the bt866 by Christer Weinigel and ported
+ to 2.6 by Martin Samuelsson.
+
+ 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 <linux/types.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+
+#include <linux/video_encoder.h>
+
+MODULE_LICENSE("GPL");
+
+#define BT866_DEVNAME "bt866"
+#define I2C_BT866 0x88
+
+MODULE_LICENSE("GPL");
+
+#define DEBUG(x) /* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt866 {
+ struct i2c_client *i2c;
+ int addr;
+ unsigned char reg[128];
+
+ int norm;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+static int bt866_write(struct bt866 *dev,
+ unsigned char subaddr, unsigned char data);
+
+static int bt866_do_command(struct bt866 *encoder,
+ unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case ENCODER_GET_CAPABILITIES:
+ {
+ struct video_encoder_capability *cap = arg;
+
+ DEBUG(printk
+ (KERN_INFO "%s: get capabilities\n",
+ encoder->i2c->name));
+
+ cap->flags
+ = VIDEO_ENCODER_PAL
+ | VIDEO_ENCODER_NTSC
+ | VIDEO_ENCODER_CCIR;
+ cap->inputs = 2;
+ cap->outputs = 1;
+ }
+ break;
+
+ case ENCODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ DEBUG(printk(KERN_INFO "%s: set norm %d\n",
+ encoder->i2c->name, *iarg));
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ break;
+
+ case VIDEO_MODE_PAL:
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ encoder->norm = *iarg;
+ }
+ break;
+
+ case ENCODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ static const __u8 init[] = {
+ 0xc8, 0xcc, /* CRSCALE */
+ 0xca, 0x91, /* CBSCALE */
+ 0xcc, 0x24, /* YC16 | OSDNUM */
+ 0xda, 0x00, /* */
+ 0xdc, 0x24, /* SETMODE | PAL */
+ 0xde, 0x02, /* EACTIVE */
+
+ /* overlay colors */
+ 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+ 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+ 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+ 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+ 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+ 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+ 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+ 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+ 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+ 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+ 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+ 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+ 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+ 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+ 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+ 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+ };
+ int i;
+ u8 val;
+
+ for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+ bt866_write(encoder, init[i], init[i+1]);
+
+ val = encoder->reg[0xdc];
+
+ if (*iarg == 0)
+ val |= 0x40; /* CBSWAP */
+ else
+ val &= ~0x40; /* !CBSWAP */
+
+ bt866_write(encoder, 0xdc, val);
+
+ val = encoder->reg[0xcc];
+ if (*iarg == 2)
+ val |= 0x01; /* OSDBAR */
+ else
+ val &= ~0x01; /* !OSDBAR */
+ bt866_write(encoder, 0xcc, val);
+
+ DEBUG(printk(KERN_INFO "%s: set input %d\n",
+ encoder->i2c->name, *iarg));
+
+ switch (*iarg) {
+ case 0:
+ break;
+ case 1:
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ }
+ break;
+
+ case ENCODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ DEBUG(printk(KERN_INFO "%s: set output %d\n",
+ encoder->i2c->name, *iarg));
+
+ /* not much choice of outputs */
+ if (*iarg != 0)
+ return -EINVAL;
+ }
+ break;
+
+ case ENCODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+ encoder->enable = !!*iarg;
+
+ DEBUG(printk
+ (KERN_INFO "%s: enable output %d\n",
+ encoder->i2c->name, encoder->enable));
+ }
+ break;
+
+ case 4711:
+ {
+ int *iarg = arg;
+ __u8 val;
+
+ printk("bt866: square = %d\n", *iarg);
+
+ val = encoder->reg[0xdc];
+ if (*iarg)
+ val |= 1; /* SQUARE */
+ else
+ val &= ~1; /* !SQUARE */
+ bt866_write(encoder, 0xdc, val);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bt866_write(struct bt866 *encoder,
+ unsigned char subaddr, unsigned char data)
+{
+ unsigned char buffer[2];
+ int err;
+
+ buffer[0] = subaddr;
+ buffer[1] = data;
+
+ encoder->reg[subaddr] = data;
+
+ DEBUG(printk
+ ("%s: write 0x%02X = 0x%02X\n",
+ encoder->i2c->name, subaddr, data));
+
+ for (err = 0; err < 3;) {
+ if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
+ break;
+ err++;
+ printk(KERN_WARNING "%s: I/O error #%d "
+ "(write 0x%02x/0x%02x)\n",
+ encoder->i2c->name, err, encoder->addr, subaddr);
+ schedule_timeout_interruptible(HZ/10);
+ }
+ if (err == 3) {
+ printk(KERN_WARNING "%s: giving up\n",
+ encoder->i2c->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter);
+static int bt866_detach(struct i2c_client *client);
+static int bt866_command(struct i2c_client *client,
+ unsigned int cmd, void *arg);
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_BT866>>1, I2C_CLIENT_END};
+static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+
+static struct i2c_client_address_data addr_data = {
+ normal_i2c,
+ probe,
+ ignore,
+};
+
+static struct i2c_driver i2c_driver_bt866 = {
+ .driver.name = BT866_DEVNAME,
+ .id = I2C_DRIVERID_BT866,
+ .attach_adapter = bt866_attach,
+ .detach_client = bt866_detach,
+ .command = bt866_command
+};
+
+
+static struct i2c_client bt866_client_tmpl =
+{
+ .name = "(nil)",
+ .addr = 0,
+ .adapter = NULL,
+ .driver = &i2c_driver_bt866,
+ .usage_count = 0
+};
+
+static int bt866_found_proc(struct i2c_adapter *adapter,
+ int addr, int kind)
+{
+ struct bt866 *encoder;
+ struct i2c_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &bt866_client_tmpl, sizeof(*client));
+
+ encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+ if (encoder == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, encoder);
+ client->adapter = adapter;
+ client->addr = addr;
+ sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
+
+ encoder->i2c = client;
+ encoder->addr = addr;
+ //encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
+
+ /* initialize */
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter)
+{
+ if (adapter->id == I2C_HW_B_ZR36067)
+ return i2c_probe(adapter, &addr_data, bt866_found_proc);
+ return 0;
+}
+
+static int bt866_detach(struct i2c_client *client)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(encoder);
+ kfree(client);
+
+ return 0;
+}
+
+static int bt866_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+ return bt866_do_command(encoder, cmd, arg);
+}
+
+static int __devinit bt866_init(void)
+{
+ i2c_add_driver(&i2c_driver_bt866);
+ return 0;
+}
+
+static void __devexit bt866_exit(void)
+{
+ i2c_del_driver(&i2c_driver_bt866);
+}
+
+module_init(bt866_init);
+module_exit(bt866_exit);
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 153f6a4a96c..cdcf5565071 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
+ depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L1
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 2b64aa835b4..de14818d5cc 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -25,7 +25,6 @@
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -269,7 +268,7 @@ static struct CARD {
{ 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" },
+ { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
{ 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" },
@@ -309,6 +308,7 @@ static struct CARD {
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
+ { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
{ 0, -1, NULL }
};
@@ -1903,7 +1903,7 @@ struct tvcard bttv_tvcards[] = {
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2x0] = {
- .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
+ .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
@@ -2745,7 +2745,7 @@ struct tvcard bttv_tvcards[] = {
/* Michael Krufky <mkrufky@m1k.net> */
.name = "DViCO FusionHDTV 5 Lite",
.tuner = 0,
- .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.video_inputs = 3,
@@ -2762,7 +2762,7 @@ struct tvcard bttv_tvcards[] = {
},
/* ---- card 0x88---------------------------------- */
[BTTV_BOARD_ACORP_Y878F] = {
- /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+ /* Mauro Carvalho Chehab <mchehab@infradead.org> */
.name = "Acorp Y878F",
.video_inputs = 3,
.audio_inputs = 1,
@@ -3547,11 +3547,6 @@ void __devinit bttv_init_card2(struct bttv *btv)
/* 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) ||
- tda9887)
- request_module("tda9887");
if (btv->tuner_type != UNSET)
request_module("tuner");
}
@@ -3790,6 +3785,7 @@ static void __devinit osprey_eeprom(struct bttv *btv)
break;
case 0x0060:
case 0x0070:
+ case 0x00A0:
btv->c.type = BTTV_BOARD_OSPREY2x0;
/* enable output on select control lines */
gpio_inout(0xffffff,0x000303);
@@ -4846,7 +4842,7 @@ static void picolo_tetra_muxsel (struct bttv* btv, unsigned int input)
*
* The IVC120G security card has 4 i2c controlled TDA8540 matrix
* swichers to provide 16 channels to MUX0. The TDA8540's have
- * 4 indepedant outputs and as such the IVC120G also has the
+ * 4 independent outputs and as such the IVC120G also has the
* optional "Monitor Out" bus. This allows the card to be looking
* at one input while the monitor is looking at another.
*
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 423e954948b..20dff7c316e 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -3923,7 +3923,12 @@ static int __devinit bttv_register_video(struct bttv *btv)
goto err;
printk(KERN_INFO "bttv%d: registered device video%d\n",
btv->c.nr,btv->video_dev->minor & 0x1f);
- video_device_create_file(btv->video_dev, &class_device_attr_card);
+ if (class_device_create_file(&btv->video_dev->class_dev,
+ &class_device_attr_card)<0) {
+ printk(KERN_ERR "bttv%d: class_device_create_file 'card' "
+ "failed\n", btv->c.nr);
+ goto err;
+ }
/* vbi */
btv->vbi_dev = vdev_init(btv, &bttv_vbi_template, "vbi");
@@ -4019,8 +4024,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
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",
- btv->c.nr, pci_resource_start(dev,0));
+ printk(KERN_WARNING "bttv%d: can't request iomem (0x%llx).\n",
+ btv->c.nr,
+ (unsigned long long)pci_resource_start(dev,0));
return -EBUSY;
}
pci_set_master(dev);
@@ -4031,8 +4037,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
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));
+ printk("irq: %d, latency: %d, mmio: 0x%llx\n",
+ btv->c.pci->irq, lat,
+ (unsigned long long)pci_resource_start(dev,0));
schedule();
btv->bt848_mmio=ioremap(pci_resource_start(dev,0), 0x1000);
@@ -4048,7 +4055,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
/* 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);
+ IRQF_SHARED | IRQF_DISABLED,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);
@@ -4285,6 +4292,8 @@ static struct pci_driver bttv_pci_driver = {
static int bttv_init_module(void)
{
+ int ret;
+
bttv_num = 0;
printk(KERN_INFO "bttv: driver version %d.%d.%d loaded\n",
@@ -4306,7 +4315,11 @@ static int bttv_init_module(void)
bttv_check_chipset();
- bus_register(&bttv_sub_bus_type);
+ ret = bus_register(&bttv_sub_bus_type);
+ if (ret < 0) {
+ printk(KERN_WARNING "bttv: bus_register error: %d\n", ret);
+ return ret;
+ }
return pci_register_driver(&bttv_pci_driver);
}
diff --git a/drivers/media/video/bt8xx/bttv-gpio.c b/drivers/media/video/bt8xx/bttv-gpio.c
index c4d5e2b70c2..ba081f6f8c8 100644
--- a/drivers/media/video/bt8xx/bttv-gpio.c
+++ b/drivers/media/video/bt8xx/bttv-gpio.c
@@ -118,20 +118,6 @@ int bttv_sub_del_devices(struct bttv_core *core)
return 0;
}
-void bttv_gpio_irq(struct bttv_core *core)
-{
- struct bttv_sub_driver *drv;
- struct bttv_sub_device *dev;
- struct list_head *item;
-
- list_for_each(item,&core->subs) {
- dev = list_entry(item,struct bttv_sub_device,list);
- drv = to_bttv_sub_drv(dev->dev.driver);
- if (drv && drv->gpio_irq)
- drv->gpio_irq(dev);
- }
-}
-
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 4b562b386fc..0dfbcc85ebb 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -100,7 +100,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
.getsda = bttv_bit_getsda,
.getscl = bttv_bit_getscl,
.udelay = 16,
- .mdelay = 10,
.timeout = 200,
};
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index 69efa0e5174..933d6db09ac 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -303,6 +303,7 @@ int bttv_input_init(struct bttv *btv)
ir->mask_keyup = 0x010000;
ir->polling = 50; // ms
break;
+ case BTTV_BOARD_PV_M4900:
case BTTV_BOARD_PV_BT878P_9B:
case BTTV_BOARD_PV_BT878P_PLUS:
ir_codes = ir_codes_pixelview;
@@ -355,7 +356,7 @@ int bttv_input_init(struct bttv *btv)
if (ir->rc5_gpio) {
u32 gpio;
- /* enable remote irq */
+ /* enable remote irq */
bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 8c9f0f7cf46..63676e7bd63 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -31,11 +31,16 @@
#include <asm/io.h>
#include "bttvp.h"
-/* Offset from line sync pulse leading edge (0H) in 1 / sampling_rate:
- bt8x8 /HRESET pulse starts at 0H and has length 64 / fCLKx1 (E|O_VTC
- HSFMT = 0). VBI_HDELAY (always 0) is an offset from the trailing edge
- of /HRESET in 1 / fCLKx1, and the sampling_rate tvnorm->Fsc is fCLKx2. */
-#define VBI_OFFSET ((64 + 0) * 2)
+/* Offset from line sync pulse leading edge (0H) to start of VBI capture,
+ in fCLKx2 pixels. According to the datasheet, VBI capture starts
+ VBI_HDELAY fCLKx1 pixels from the tailing edgeof /HRESET, and /HRESET
+ is 64 fCLKx1 pixels wide. VBI_HDELAY is set to 0, so this should be
+ (64 + 0) * 2 = 128 fCLKx2 pixels. But it's not! The datasheet is
+ Just Plain Wrong. The real value appears to be different for
+ different revisions of the bt8x8 chips, and to be affected by the
+ horizontal scaling factor. Experimentally, the value is measured
+ to be about 244. */
+#define VBI_OFFSET 244
#define VBI_DEFLINES 16
#define VBI_MAXLINES 32
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 3a23265c153..f9c9e3c4d11 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -350,7 +350,6 @@ struct bttv_sub_driver {
char wanted[BUS_ID_SIZE];
int (*probe)(struct bttv_sub_device *sub);
void (*remove)(struct bttv_sub_device *sub);
- void (*gpio_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index ee989d2e15d..311c4c541e0 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -33,6 +33,7 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
@@ -214,7 +215,6 @@ extern struct videobuf_queue_ops bttv_vbi_qops;
extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
-void bttv_gpio_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
@@ -360,7 +360,7 @@ struct bttv {
int mbox_csel;
/* risc memory management data
- - must aquire s_lock before changing these
+ - must acquire s_lock before changing these
- only the irq handler is supported to touch top + bottom + vcurr */
struct btcx_riscmem main;
struct bttv_buffer *screen; /* overlay */
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index cf61c590f4a..7d0b6e59c6e 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -73,6 +73,7 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -759,7 +760,7 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
{
struct video_picture *p = arg;
if(p->palette!=VIDEO_PALETTE_GREY)
- return -EINVAL;
+ return -EINVAL;
if(p->depth!=4 && p->depth!=6)
return -EINVAL;
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 22a7386bbea..a3989bd2f81 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -34,6 +34,7 @@
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index 840fe017712..b69ee119481 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -12,7 +12,6 @@
* ioctls.
*/
-#include <linux/config.h>
#include <linux/compat.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
@@ -22,7 +21,7 @@
#ifdef CONFIG_COMPAT
-
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
struct video_tuner32 {
compat_int_t tuner;
char name[32];
@@ -108,6 +107,7 @@ struct video_window32 {
compat_caddr_t clips;
compat_int_t clipcount;
};
+#endif
static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
@@ -125,6 +125,7 @@ static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* You get back everything except the clips... */
static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
@@ -139,6 +140,7 @@ static int put_video_window32(struct video_window *kp, struct video_window32 __u
return -EFAULT;
return 0;
}
+#endif
struct v4l2_clip32
{
@@ -491,6 +493,24 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user
return 0;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+struct video_code32
+{
+ char loadwhat[16]; /* name or tag of file being passed */
+ compat_int_t datasize;
+ unsigned char *data;
+};
+
+static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
+{
+ if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
+ copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) ||
+ get_user(kp->datasize, &up->datasize) ||
+ copy_from_user(kp->data, up->data, up->datasize))
+ return -EFAULT;
+ return 0;
+}
+
#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32)
#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32)
#define VIDIOCGWIN32 _IOR('v',9, struct video_window32)
@@ -499,6 +519,9 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user
#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32)
#define VIDIOCGFREQ32 _IOR('v',14, u32)
#define VIDIOCSFREQ32 _IOW('v',15, u32)
+#define VIDIOCSMICROCODE32 _IOW('v',27, struct video_code32)
+
+#endif
/* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
#define VIDIOC_ENUMINPUT32 VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4)
@@ -520,6 +543,7 @@ static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user
#define VIDIOC_S_INPUT32 _IOWR ('V', 39, compat_int_t)
#define VIDIOC_TRY_FMT32 _IOWR ('V', 64, struct v4l2_format32)
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
enum {
MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
};
@@ -584,13 +608,17 @@ static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
}
+#endif
static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
union {
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
struct video_tuner vt;
struct video_buffer vb;
struct video_window vw;
+ struct video_code vc;
+#endif
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
@@ -606,6 +634,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
/* First, convert the command. */
switch(cmd) {
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
@@ -613,6 +642,8 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
+ case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
+#endif
case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
@@ -632,6 +663,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
};
switch(cmd) {
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCSTUNER:
case VIDIOCGTUNER:
err = get_video_tuner32(&karg.vt, up);
@@ -645,6 +677,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
break;
case VIDIOCSFREQ:
+#endif
case VIDIOC_S_INPUT:
case VIDIOC_OVERLAY:
case VIDIOC_STREAMON:
@@ -698,14 +731,21 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
compatible_arg = 0;
break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGWIN:
case VIDIOCGFBUF:
case VIDIOCGFREQ:
+#endif
case VIDIOC_G_FBUF:
case VIDIOC_G_INPUT:
compatible_arg = 0;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ case VIDIOCSMICROCODE:
+ err = microcode32(&karg.vc, up);
+ compatible_arg = 0;
+ break;
+#endif
};
-
if(err)
goto out;
@@ -720,6 +760,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
}
if(err == 0) {
switch(cmd) {
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGTUNER:
err = put_video_tuner32(&karg.vt, up);
break;
@@ -731,7 +772,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOCGFBUF:
err = put_video_buffer32(&karg.vb, up);
break;
-
+#endif
case VIDIOC_G_FBUF:
err = put_v4l2_framebuffer32(&karg.v2fb, up);
break;
@@ -769,7 +810,9 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
err = put_v4l2_input32(&karg.v2i, up);
break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGFREQ:
+#endif
case VIDIOC_G_INPUT:
err = put_user(((u32)karg.vx), (u32 __user *)up);
break;
@@ -787,6 +830,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
return ret;
switch (cmd) {
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCSWIN32:
ret = do_set_window(file, cmd, arg);
break;
@@ -797,6 +841,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOCSFBUF32:
case VIDIOCGFREQ32:
case VIDIOCSFREQ32:
+#endif
case VIDIOC_QUERYCAP:
case VIDIOC_ENUM_FMT:
case VIDIOC_G_FMT32:
@@ -828,6 +873,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
ret = do_video_ioctl(file, cmd, arg);
break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* Little v, the video4linux ioctls (conflict?) */
case VIDIOCGCAP:
case VIDIOCGCHAN:
@@ -856,6 +902,7 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
break;
+#endif
default:
v4l_print_ioctl("compat_ioctl32", cmd);
}
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 85d84e89d8f..3b31a0dd2f0 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -26,7 +26,6 @@
/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
/* #define _CPIA_DEBUG_ 1 */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -47,13 +46,6 @@
#include "cpia.h"
-#ifdef CONFIG_VIDEO_CPIA_PP
-extern int cpia_pp_init(void);
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-extern int cpia_usb_init(void);
-#endif
-
static int video_nr = -1;
#ifdef MODULE
@@ -67,10 +59,10 @@ MODULE_SUPPORTED_DEVICE("video");
static unsigned short colorspace_conv;
module_param(colorspace_conv, ushort, 0444);
MODULE_PARM_DESC(colorspace_conv,
- " Colorspace conversion:"
- "\n 0 = disable, 1 = enable"
- "\n Default value is 0"
- );
+ " Colorspace conversion:"
+ "\n 0 = disable, 1 = enable"
+ "\n Default value is 0"
+ );
#define ABOUT "V4L-Driver for Vision CPiA based cameras"
@@ -4047,13 +4039,6 @@ static int __init cpia_init(void)
proc_cpia_create();
#endif
-#ifdef CONFIG_VIDEO_CPIA_PP
- cpia_pp_init();
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
- cpia_usb_init();
-#endif
-
return 0;
}
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
index dde27a6a4a0..6eaa692021c 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -45,6 +45,7 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
@@ -247,7 +248,7 @@ enum v4l_camstates {
struct cam_data {
struct list_head cam_data_list;
- struct mutex busy_lock; /* guard against SMP multithreading */
+ struct mutex busy_lock; /* guard against SMP multithreading */
struct cpia_camera_ops *ops; /* lowlevel driver operations */
void *lowlevel_data; /* private data for lowlevel driver */
u8 *raw_image; /* buffer for raw image data */
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
index 513cc092738..e39a9615200 100644
--- a/drivers/media/video/cpia2/Kconfig
+++ b/drivers/media/video/cpia2/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_CPIA2
tristate "CPiA2 Video For Linux"
- depends on VIDEO_DEV && USB
+ depends on VIDEO_DEV && USB && VIDEO_V4L1
---help---
This is the video4linux driver for cameras based on Vision's CPiA2
(Colour Processor Interface ASIC), such as the Digital Blue QX5
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index 1764991b0ac..c5ecb2be5f9 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -33,6 +33,7 @@
#include <linux/version.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/poll.h>
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 481e178ef56..d09f49950f2 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -31,7 +31,6 @@
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/time.h>
@@ -343,7 +342,9 @@ static int cpia2_close(struct inode *inode, struct file *file)
cpia2_free_buffers(cam);
if (!cam->present) {
video_unregister_device(dev);
+ mutex_unlock(&cam->busy_lock);
kfree(cam);
+ return 0;
}
}
@@ -1167,9 +1168,9 @@ static int ioctl_g_ctrl(void *arg,struct camera_data *cam)
} else {
if(cam->params.flicker_control.cam_register &
CPIA2_VP_FLICKER_MODES_50HZ) {
- mode = FLICKER_50;
+ mode = FLICKER_50;
} else {
- mode = FLICKER_60;
+ mode = FLICKER_60;
}
}
for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
index 0b00e6027df..41f4b8d1755 100644
--- a/drivers/media/video/cpia_pp.c
+++ b/drivers/media/video/cpia_pp.c
@@ -25,7 +25,6 @@
/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
/* #define _CPIA_DEBUG_ 1 */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -803,7 +802,7 @@ static struct parport_driver cpia_pp_driver = {
.detach = cpia_pp_detach,
};
-int cpia_pp_init(void)
+static int cpia_pp_init(void)
{
printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
@@ -860,6 +859,8 @@ void cleanup_module(void)
static int __init cpia_pp_setup(char *str)
{
+ int err;
+
if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str + 7, NULL, 10);
if (parport_ptr < PARPORT_MAX) {
@@ -873,6 +874,10 @@ static int __init cpia_pp_setup(char *str)
parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
}
+ err=cpia_pp_init();
+ if (err)
+ return err;
+
return 1;
}
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 9c49a4b0011..2ee34a3b928 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -474,12 +474,6 @@ static int cpia_usb_close(void *privdata)
return 0;
}
-int cpia_usb_init(void)
-{
- /* return -ENODEV; */
- return 0;
-}
-
/* Probing and initializing */
static int cpia_probe(struct usb_interface *intf,
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
new file mode 100644
index 00000000000..65f00fc08fa
--- /dev/null
+++ b/drivers/media/video/cx2341x.c
@@ -0,0 +1,932 @@
+/*
+ * cx2341x - generic code for cx23415/6 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+const u32 cx2341x_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_STREAM_VBI_FMT,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_CID_MPEG_AUDIO_MODE,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ V4L2_CID_MPEG_VIDEO_PULLDOWN,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ 0
+};
+
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ ctrl->value = params->audio_sampling_freq;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ ctrl->value = params->audio_encoding;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ ctrl->value = params->audio_l2_bitrate;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ ctrl->value = params->audio_mode;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ ctrl->value = params->audio_mode_extension;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ ctrl->value = params->audio_emphasis;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ ctrl->value = params->audio_crc;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ ctrl->value = params->video_encoding;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ ctrl->value = params->video_aspect;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ ctrl->value = params->video_b_frames;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = params->video_gop_size;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ ctrl->value = params->video_gop_closure;
+ break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ ctrl->value = params->video_pulldown;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ ctrl->value = params->video_bitrate_mode;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = params->video_bitrate;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ ctrl->value = params->video_bitrate_peak;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ ctrl->value = params->video_temporal_decimation;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = params->stream_type;
+ break;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ ctrl->value = params->stream_vbi_fmt;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ ctrl->value = params->video_spatial_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ ctrl->value = params->video_spatial_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_luma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_chroma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ ctrl->value = params->video_temporal_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ ctrl->value = params->video_temporal_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ ctrl->value = params->video_median_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_luma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_luma_median_filter_bottom;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_chroma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_chroma_median_filter_bottom;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ params->audio_sampling_freq = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ params->audio_encoding = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ params->audio_l2_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ params->audio_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ params->audio_mode_extension = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ params->audio_emphasis = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ params->audio_crc = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ params->video_aspect = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+ int b = ctrl->value + 1;
+ int gop = params->video_gop_size;
+ params->video_b_frames = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+ int b = params->video_b_frames + 1;
+ int gop = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ ctrl->value = params->video_gop_size;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ params->video_gop_closure = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ params->video_pulldown = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ /* MPEG-1 only allows CBR */
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
+ ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ return -EINVAL;
+ params->video_bitrate_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ params->video_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ params->video_bitrate_peak = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ params->video_temporal_decimation = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ params->stream_type = ctrl->value;
+ params->video_encoding =
+ (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+ params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ /* MPEG-1 implies CBR */
+ params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
+ break;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ params->stream_vbi_fmt = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ params->video_spatial_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ params->video_spatial_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ params->video_luma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ params->video_chroma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ params->video_temporal_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ params->video_temporal_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ params->video_median_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ params->video_luma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ params->video_luma_median_filter_bottom = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ params->video_chroma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ params->video_chroma_median_filter_bottom = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ qctrl->flags = 0;
+ switch (qctrl->id) {
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ name = "Spatial Filter Mode";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ name = "Spatial Filter";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ name = "Spatial Luma Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ name = "Spatial Chroma Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ name = "Temporal Filter Mode";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ name = "Temporal Filter";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ name = "Median Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ name = "Median Luma Filter Maximum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ name = "Median Luma Filter Minimum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ name = "Median Chroma Filter Maximum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ name = "Median Chroma Filter Minimum";
+ break;
+
+ default:
+ return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ min = 0;
+ step = 1;
+ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ snprintf(qctrl->name, sizeof(qctrl->name), name);
+ return 0;
+}
+
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+{
+ int err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return -EINVAL;
+
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ /* this setting is read-only for the cx2341x since the
+ V4L2_CID_MPEG_STREAM_TYPE really determines the
+ MPEG-1/2 setting */
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0)
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ if (params->capabilities & CX2341X_CAP_HAS_SLICED_VBI)
+ return v4l2_ctrl_query_fill_std(qctrl);
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE, 1,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE);
+
+ /* CX23415/6 specific */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ default:
+ return v4l2_ctrl_query_fill_std(qctrl);
+
+ }
+}
+
+const char **cx2341x_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ "1D Vertical",
+ "2D H/V Separable",
+ "2D Symmetric non-separable",
+ NULL
+ };
+
+ static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ NULL
+ };
+
+ static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_median_filter_type_menu[] = {
+ "Off",
+ "Horizontal",
+ "Vertical",
+ "Horizontal/Vertical",
+ "Diagonal",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return NULL;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_video_spatial_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_luma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_chroma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_video_temporal_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_video_median_filter_type_menu;
+ default:
+ return v4l2_ctrl_get_menu(id);
+ }
+}
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+ params->audio_properties = (params->audio_sampling_freq << 0) |
+ ((3 - params->audio_encoding) << 2) |
+ ((1 + params->audio_l2_bitrate) << 4) |
+ (params->audio_mode << 8) |
+ (params->audio_mode_extension << 10) |
+ (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
+ 3 :
+ params->audio_emphasis) << 12) |
+ (params->audio_crc << 14);
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_controls *ctrls, unsigned int cmd)
+{
+ int err = 0;
+ int i;
+
+ if (cmd == VIDIOC_G_EXT_CTRLS) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = cx2341x_get_ctrl(params, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+ struct v4l2_queryctrl qctrl;
+ const char **menu_items = NULL;
+
+ qctrl.id = ctrl->id;
+ err = cx2341x_ctrl_query(params, &qctrl);
+ if (err)
+ break;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+ err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+ if (err)
+ break;
+ err = cx2341x_set_ctrl(params, ctrl);
+ if (err)
+ break;
+ }
+ if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ params->video_bitrate_peak < params->video_bitrate) {
+ err = -ERANGE;
+ ctrls->error_idx = ctrls->count;
+ }
+ if (err) {
+ ctrls->error_idx = i;
+ }
+ else {
+ cx2341x_calc_audio_properties(params);
+ }
+ return err;
+}
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+ static struct cx2341x_mpeg_params default_params = {
+ /* misc */
+ .capabilities = 0,
+ .port = CX2341X_PORT_MEMORY,
+ .width = 720,
+ .height = 480,
+ .is_50hz = 0,
+
+ /* stream */
+ .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ .stream_vbi_fmt = V4L2_MPEG_STREAM_VBI_FMT_NONE,
+
+ /* audio */
+ .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+ .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+ .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+
+ /* video */
+ .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+ .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .video_b_frames = 2,
+ .video_gop_size = 12,
+ .video_gop_closure = 1,
+ .video_pulldown = 0,
+ .video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ .video_bitrate = 6000000,
+ .video_bitrate_peak = 8000000,
+ .video_temporal_decimation = 0,
+
+ /* encoding filters */
+ .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ .video_spatial_filter = 0,
+ .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ .video_temporal_filter = 0,
+ .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ .video_luma_median_filter_top = 255,
+ .video_luma_median_filter_bottom = 0,
+ .video_chroma_median_filter_top = 255,
+ .video_chroma_median_filter_bottom = 0,
+ };
+
+ *p = default_params;
+ cx2341x_calc_audio_properties(p);
+}
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i;
+
+ va_start(vargs, args);
+
+ for (i = 0; i < args; i++) {
+ data[i] = va_arg(vargs, int);
+ }
+ va_end(vargs);
+ return func(priv, cmd, args, 0, data);
+}
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+{
+ static int mpeg_stream_type[] = {
+ 0, /* MPEG-2 PS */
+ 1, /* MPEG-2 TS */
+ 2, /* MPEG-1 SS */
+ 14, /* DVD */
+ 11, /* VCD */
+ 12, /* SVCD */
+ };
+
+ int err = 0;
+
+ cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+ if (old == NULL || old->is_50hz != new->is_50hz) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+ if (err) return err;
+ }
+
+ if (old == NULL || old->width != new->width || old->height != new->height ||
+ old->video_encoding != new->video_encoding) {
+ u16 w = new->width;
+ u16 h = new->height;
+
+ if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ w /= 2;
+ h /= 2;
+ }
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+ if (err) return err;
+ }
+
+ if (old == NULL || old->stream_type != new->stream_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_aspect != new->video_aspect) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_b_frames != new->video_b_frames ||
+ old->video_gop_size != new->video_gop_size) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ new->video_gop_size, new->video_b_frames + 1);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_pulldown != new->video_pulldown) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
+ if (err) return err;
+ }
+ if (old == NULL || old->audio_properties != new->audio_properties) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
+ old->video_bitrate != new->video_bitrate ||
+ old->video_bitrate_peak != new->video_bitrate_peak) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+ new->video_bitrate_mode, new->video_bitrate,
+ new->video_bitrate_peak / 400, 0, 0);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
+ old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
+ old->video_median_filter_type != new->video_median_filter_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+ new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+ new->video_median_filter_type);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
+ old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
+ old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
+ old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ new->video_luma_median_filter_bottom,
+ new->video_luma_median_filter_top,
+ new->video_chroma_median_filter_bottom,
+ new->video_chroma_median_filter_top);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
+ old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+ new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_spatial_filter != new->video_spatial_filter ||
+ old->video_temporal_filter != new->video_temporal_filter) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+ new->video_spatial_filter, new->video_temporal_filter);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
+ new->video_temporal_decimation);
+ if (err) return err;
+ }
+ return 0;
+}
+
+static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+{
+ const char **menu = cx2341x_ctrl_get_menu(id);
+ struct v4l2_ext_control ctrl;
+
+ if (menu == NULL)
+ goto invalid;
+ ctrl.id = id;
+ if (cx2341x_get_ctrl(p, &ctrl))
+ goto invalid;
+ while (ctrl.value-- && *menu) menu++;
+ if (*menu == NULL)
+ goto invalid;
+ return *menu;
+
+invalid:
+ return "<invalid>";
+}
+
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
+{
+ int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+ /* Stream */
+ printk(KERN_INFO "%s: Stream: %s\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+
+ /* Video */
+ printk(KERN_INFO "%s: Video: %dx%d, %d fps\n",
+ prefix,
+ p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+ p->is_50hz ? 25 : 30);
+ printk(KERN_INFO "%s: Video: %s, %s, %s, %d",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+ p->video_bitrate);
+ if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+ printk(", Peak %d", p->video_bitrate_peak);
+ }
+ printk("\n");
+ printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+ prefix,
+ p->video_gop_size, p->video_b_frames,
+ p->video_gop_closure ? "" : "No ",
+ p->video_pulldown ? "" : "No ");
+ if (p->video_temporal_decimation) {
+ printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
+ prefix, p->video_temporal_decimation);
+ }
+
+ /* Audio */
+ printk(KERN_INFO "%s: Audio: %s, %s, %s, %s",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+ if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
+ printk(", %s",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+ }
+ printk(", %s, %s\n",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+ /* Encoding filters */
+ printk(KERN_INFO "%s: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+ p->video_spatial_filter);
+ printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+ p->video_temporal_filter);
+ printk(KERN_INFO "%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+ p->video_luma_median_filter_bottom,
+ p->video_luma_median_filter_top,
+ p->video_chroma_median_filter_bottom,
+ p->video_chroma_median_filter_top);
+}
+
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+EXPORT_SYMBOL(cx2341x_update);
+EXPORT_SYMBOL(cx2341x_log_status);
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 9a4b813152e..f897c1ebd5f 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -30,9 +30,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
- /* assert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
/* common for all inputs and rates */
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx25840_write(client, 0x127, 0x50);
@@ -46,6 +43,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xee39bb01);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x0801f77f */
cx25840_write4(client, 0x900, 0x7ff70108);
cx25840_write4(client, 0x904, 0x7ff70108);
@@ -59,6 +59,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xd66bec00);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x08016d59 */
cx25840_write4(client, 0x900, 0x596d0108);
cx25840_write4(client, 0x904, 0x596d0108);
@@ -72,6 +75,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xe5d69800);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x08014faa */
cx25840_write4(client, 0x900, 0xaa4f0108);
cx25840_write4(client, 0x904, 0xaa4f0108);
@@ -87,6 +93,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0x69082a01);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0x00000108);
@@ -106,6 +115,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xd66bec00);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0xcd600108);
@@ -122,6 +134,9 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xe5d69800);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0x00800108);
@@ -133,9 +148,6 @@ static int set_audclk_freq(struct i2c_client *client, u32 freq)
}
}
- /* deassert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
state->audclk_freq = freq;
return 0;
@@ -148,6 +160,10 @@ void cx25840_audio_set_path(struct i2c_client *client)
/* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0);
+ /* assert soft reset */
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
/* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f);
@@ -161,13 +177,19 @@ void cx25840_audio_set_path(struct i2c_client *client)
} else {
/* Set Path1 to Analog Demod Main Channel */
cx25840_write4(client, 0x8d0, 0x7038061f);
+ }
+ set_audclk_freq(client, state->audclk_freq);
+
+ /* deassert soft reset */
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
-
- set_audclk_freq(client, state->audclk_freq);
}
static int get_volume(struct i2c_client *client)
@@ -291,11 +313,25 @@ static void set_mute(struct i2c_client *client, int mute)
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_control *ctrl = arg;
+ int retval;
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return set_audclk_freq(client, *(u32 *)arg);
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ cx25840_and_or(client, 0x803, ~0x10, 0);
+ cx25840_write(client, 0x8d3, 0x1f);
+ }
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 1);
+ retval = set_audclk_freq(client, *(u32 *)arg);
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0);
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+ return retval;
case VIDIOC_G_CTRL:
switch (ctrl->id) {
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index a961bb2ab0f..7bb7589a07c 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -10,6 +10,9 @@
*
* VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
*
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
* 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
@@ -43,7 +46,7 @@ MODULE_LICENSE("GPL");
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-static int cx25840_debug;
+int cx25840_debug;
module_param_named(debug,cx25840_debug, int, 0644);
@@ -101,11 +104,11 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr)
if (i2c_master_recv(client, buffer, 4) < 4)
return 0;
- return (buffer[0] << 24) | (buffer[1] << 16) |
- (buffer[2] << 8) | buffer[3];
+ return (buffer[3] << 24) | (buffer[2] << 16) |
+ (buffer[1] << 8) | buffer[0];
}
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
u8 or_value)
{
return cx25840_write(client, addr,
@@ -117,7 +120,8 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
enum cx25840_audio_input aud_input);
-static void log_status(struct i2c_client *client);
+static void log_audio_status(struct i2c_client *client);
+static void log_video_status(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
@@ -147,6 +151,33 @@ static void init_dll2(struct i2c_client *client)
cx25840_write(client, 0x15d, 0xe1);
}
+static void cx25836_initialize(struct i2c_client *client)
+{
+ /* reset configuration is described on page 3-77 of the CX25836 datasheet */
+ /* 2. */
+ cx25840_and_or(client, 0x000, ~0x01, 0x01);
+ cx25840_and_or(client, 0x000, ~0x01, 0x00);
+ /* 3a. */
+ cx25840_and_or(client, 0x15a, ~0x70, 0x00);
+ /* 3b. */
+ cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
+ /* 3c. */
+ cx25840_and_or(client, 0x159, ~0x02, 0x02);
+ /* 3d. */
+ /* There should be a 10-us delay here, but since the
+ i2c bus already has a 10-us delay we don't need to do
+ anything */
+ /* 3e. */
+ cx25840_and_or(client, 0x159, ~0x02, 0x00);
+ /* 3f. */
+ cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
+ /* 3g. */
+ cx25840_and_or(client, 0x159, ~0x01, 0x00);
+ cx25840_and_or(client, 0x159, ~0x01, 0x01);
+ /* 3h. */
+ cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
+}
+
static void cx25840_initialize(struct i2c_client *client, int loadfw)
{
struct cx25840_state *state = i2c_get_clientdata(client);
@@ -220,17 +251,7 @@ static void input_change(struct i2c_client *client)
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
- /* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC
- instead of V4L2_STD_PAL. Someone needs to test this. */
- if (std & V4L2_STD_PAL) {
- /* Follow tuner change procedure for PAL */
- cx25840_write(client, 0x808, 0xff);
- cx25840_write(client, 0x80b, 0x10);
- } else if (std & V4L2_STD_SECAM) {
- /* Select autodetect for SECAM */
- cx25840_write(client, 0x808, 0xff);
- cx25840_write(client, 0x80b, 0x10);
- } else if (std & V4L2_STD_NTSC) {
+ if (std & V4L2_STD_525_60) {
/* Certain Hauppauge PVR150 models have a hardware bug
that causes audio to drop out. For these models the
audio standard must be set explicitly.
@@ -249,6 +270,14 @@ static void input_change(struct i2c_client *client)
cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
}
cx25840_write(client, 0x80b, 0x00);
+ } else if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
}
if (cx25840_read(client, 0x803) & 0x10) {
@@ -319,8 +348,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
state->vid_input = vid_input;
state->aud_input = aud_input;
- cx25840_audio_set_path(client);
- input_change(client);
+ if (!state->is_cx25836) {
+ cx25840_audio_set_path(client);
+ input_change(client);
+ }
return 0;
}
@@ -354,6 +385,8 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
}
}
+ v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+
/* Follow step 9 of section 3.16 in the cx25840 datasheet.
Without this PAL may display a vertical ghosting effect.
This happens for example with the Yuan MPC622. */
@@ -370,6 +403,7 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
/* check VID_FMT_SEL first */
u8 fmt = cx25840_read(client, 0x400) & 0xf;
@@ -383,7 +417,7 @@ v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
{
/* if the audio std is A2-M, then this is the South Korean
NTSC standard */
- if (cx25840_read(client, 0x805) == 2)
+ if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
return V4L2_STD_NTSC_M_KR;
return V4L2_STD_NTSC_M;
}
@@ -456,6 +490,8 @@ static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
default:
@@ -490,6 +526,8 @@ static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
default:
return -EINVAL;
@@ -579,91 +617,6 @@ static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
/* ----------------------------------------------------------------------- */
-static struct v4l2_queryctrl cx25840_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .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_AUDIO_BASS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- }, {
- .id = V4L2_CID_AUDIO_TREBLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- },
-};
-
-/* ----------------------------------------------------------------------- */
-
static int cx25840_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
@@ -706,8 +659,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
case VIDIOC_STREAMON:
v4l_dbg(1, cx25840_debug, client, "enable output\n");
- cx25840_write(client, 0x115, 0x8c);
- cx25840_write(client, 0x116, 0x07);
+ cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
+ cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
break;
case VIDIOC_STREAMOFF:
@@ -717,7 +670,9 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
break;
case VIDIOC_LOG_STATUS:
- log_status(client);
+ log_video_status(client);
+ if (!state->is_cx25836)
+ log_audio_status(client);
break;
case VIDIOC_G_CTRL:
@@ -729,13 +684,29 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
- if (qc->id && qc->id == cx25840_qctrl[i].id) {
- memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
- return 0;
- }
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+ if (state->is_cx25836)
+ return -EINVAL;
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
return -EINVAL;
}
@@ -760,31 +731,41 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
return set_input(client, route->input, state->aud_input);
case VIDIOC_INT_G_AUDIO_ROUTING:
+ if (state->is_cx25836)
+ return -EINVAL;
route->input = state->aud_input;
route->output = 0;
break;
case VIDIOC_INT_S_AUDIO_ROUTING:
+ if (state->is_cx25836)
+ return -EINVAL;
return set_input(client, state->vid_input, route->input);
case VIDIOC_S_FREQUENCY:
- input_change(client);
+ if (!state->is_cx25836) {
+ input_change(client);
+ }
break;
case VIDIOC_G_TUNER:
{
- u8 mode = cx25840_read(client, 0x804);
- u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+ u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+ u8 mode;
int val = 0;
if (state->radio)
break;
+ vt->signal = vpres ? 0xffff : 0x0;
+ if (state->is_cx25836)
+ break;
+
vt->capability |=
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
- vt->signal = vpres ? 0xffff : 0x0;
+ mode = cx25840_read(client, 0x804);
/* get rxsubchans and audmode */
if ((mode & 0xf) == 1)
@@ -804,7 +785,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
}
case VIDIOC_S_TUNER:
- if (state->radio)
+ if (state->radio || state->is_cx25836)
break;
switch (vt->audmode) {
@@ -846,12 +827,14 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
return set_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_RESET:
- cx25840_initialize(client, 0);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client, 0);
break;
case VIDIOC_INT_G_CHIP_IDENT:
- *(enum v4l2_chip_ident *)arg =
- V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+ *(enum v4l2_chip_ident *)arg = state->id;
break;
default:
@@ -870,6 +853,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
{
struct i2c_client *client;
struct cx25840_state *state;
+ enum v4l2_chip_ident id;
u16 device_id;
/* Check if the adapter supports the needed features
@@ -878,10 +862,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return 0;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == 0)
return -ENOMEM;
+ client = &state->c;
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver_cx25840;
@@ -893,10 +878,18 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
device_id |= cx25840_read(client, 0x100);
/* The high byte of the device ID should be
- * 0x84 if chip is present */
- if ((device_id & 0xff00) != 0x8400) {
+ * 0x83 for the cx2583x and 0x84 for the cx2584x */
+ if ((device_id & 0xff00) == 0x8300) {
+ id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+ state->is_cx25836 = 1;
+ }
+ else if ((device_id & 0xff00) == 0x8400) {
+ id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+ state->is_cx25836 = 0;
+ }
+ else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
- kfree(client);
+ kfree(state);
return 0;
}
@@ -905,21 +898,19 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
address << 1, adapter->name);
- state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- if (state == NULL) {
- kfree(client);
- return -ENOMEM;
- }
-
i2c_set_clientdata(client, state);
- memset(state, 0, sizeof(struct cx25840_state));
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
+ state->vbi_line_offset = 8;
+ state->id = id;
- cx25840_initialize(client, 1);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client, 1);
i2c_attach_client(client);
@@ -944,7 +935,6 @@ static int cx25840_detach_client(struct i2c_client *client)
}
kfree(state);
- kfree(client);
return 0;
}
@@ -977,7 +967,7 @@ module_exit(m__exit);
/* ----------------------------------------------------------------------- */
-static void log_status(struct i2c_client *client)
+static void log_video_status(struct i2c_client *client)
{
static const char *const fmt_strs[] = {
"0x0",
@@ -989,9 +979,36 @@ static void log_status(struct i2c_client *client)
};
struct cx25840_state *state = i2c_get_clientdata(client);
- u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
u8 gen_stat1 = cx25840_read(client, 0x40d);
+ u8 gen_stat2 = cx25840_read(client, 0x40e);
+ int vid_input = state->vid_input;
+
+ v4l_info(client, "Video signal: %spresent\n",
+ (gen_stat2 & 0x20) ? "" : "not ");
+ v4l_info(client, "Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ v4l_info(client, "Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ if (vid_input >= CX25840_COMPOSITE1 &&
+ vid_input <= CX25840_COMPOSITE8) {
+ v4l_info(client, "Specified video input: Composite %d\n",
+ vid_input - CX25840_COMPOSITE1 + 1);
+ } else {
+ v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ }
+
+ v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
u8 download_ctl = cx25840_read(client, 0x803);
u8 mod_det_stat0 = cx25840_read(client, 0x804);
u8 mod_det_stat1 = cx25840_read(client, 0x805);
@@ -999,15 +1016,9 @@ static void log_status(struct i2c_client *client)
u8 pref_mode = cx25840_read(client, 0x809);
u8 afc0 = cx25840_read(client, 0x80b);
u8 mute_ctl = cx25840_read(client, 0x8d3);
- int vid_input = state->vid_input;
int aud_input = state->aud_input;
char *p;
- v4l_info(client, "Video signal: %spresent\n",
- (microctrl_vidfmt & 0x10) ? "" : "not ");
- v4l_info(client, "Detected format: %s\n",
- fmt_strs[gen_stat1 & 0xf]);
-
switch (mod_det_stat0) {
case 0x00: p = "mono"; break;
case 0x01: p = "stereo"; break;
@@ -1107,25 +1118,12 @@ static void log_status(struct i2c_client *client)
v4l_info(client, "Configured audio system: %s\n", p);
}
- v4l_info(client, "Specified standard: %s\n",
- vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
- if (vid_input >= CX25840_COMPOSITE1 &&
- vid_input <= CX25840_COMPOSITE8) {
- v4l_info(client, "Specified video input: Composite %d\n",
- vid_input - CX25840_COMPOSITE1 + 1);
- } else {
- v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
- (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
- }
if (aud_input) {
v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input);
} else {
v4l_info(client, "Specified audio input: External\n");
}
- v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-
switch (pref_mode & 0xf) {
case 0: p = "mono/language A"; break;
case 1: p = "language B"; break;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 1736929fc20..28049064dd7 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -24,6 +24,8 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
+extern int cx25840_debug;
+
/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
@@ -33,12 +35,16 @@
#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
struct cx25840_state {
+ struct i2c_client c;
int pvr150_workaround;
int radio;
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
+ int vbi_line_offset;
+ enum v4l2_chip_ident id;
+ int is_cx25836;
};
/* ----------------------------------------------------------------------- */
@@ -47,7 +53,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
u8 cx25840_read(struct i2c_client *client, u16 addr);
u32 cx25840_read4(struct i2c_client *client, u16 addr);
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 57feca288d2..6cc8bf215e8 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -84,67 +84,140 @@ static int decode_vps(u8 * dst, u8 * p)
void cx25840_vbi_setup(struct i2c_client *client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
v4l2_std_id std = cx25840_get_v4lstd(client);
+ int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
+ int luma_lpf,uv_lpf, comb;
+ u32 pll_int,pll_frac,pll_post;
+ /* datasheet startup, step 8d */
if (std & ~V4L2_STD_NTSC) {
- /* datasheet startup, step 8d */
cx25840_write(client, 0x49f, 0x11);
+ } else {
+ cx25840_write(client, 0x49f, 0x14);
+ }
- cx25840_write(client, 0x470, 0x84);
- cx25840_write(client, 0x471, 0x00);
- cx25840_write(client, 0x472, 0x2d);
- cx25840_write(client, 0x473, 0x5d);
-
- cx25840_write(client, 0x474, 0x24);
- cx25840_write(client, 0x475, 0x40);
- cx25840_write(client, 0x476, 0x24);
- cx25840_write(client, 0x477, 0x28);
-
- cx25840_write(client, 0x478, 0x1f);
- cx25840_write(client, 0x479, 0x02);
+ if (std & V4L2_STD_625_50) {
+ hblank=0x084;
+ hactive=0x2d0;
+ burst=0x5d;
+ vblank=0x024;
+ vactive=0x244;
+ vblank656=0x28;
+ src_decimation=0x21f;
+ luma_lpf=2;
if (std & V4L2_STD_SECAM) {
- cx25840_write(client, 0x47a, 0x80);
- cx25840_write(client, 0x47b, 0x00);
- cx25840_write(client, 0x47c, 0x5f);
- cx25840_write(client, 0x47d, 0x42);
+ uv_lpf=0;
+ comb=0;
+ sc=0x0a425f;
} else {
- cx25840_write(client, 0x47a, 0x90);
- cx25840_write(client, 0x47b, 0x20);
- cx25840_write(client, 0x47c, 0x63);
- cx25840_write(client, 0x47d, 0x82);
+ uv_lpf=1;
+ comb=0x20;
+ sc=0x0a8263;
}
-
- cx25840_write(client, 0x47e, 0x0a);
- cx25840_write(client, 0x47f, 0x01);
} else {
- /* datasheet startup, step 8d */
- cx25840_write(client, 0x49f, 0x14);
+ hactive=720;
+ hblank=122;
+ vactive=487;
+ luma_lpf=1;
+ uv_lpf=1;
+
+ src_decimation=0x21f;
+ if (std == V4L2_STD_PAL_M) {
+ vblank=20;
+ vblank656=24;
+ burst=0x61;
+ comb=0x20;
+
+ sc=555452;
+ } else {
+ vblank=26;
+ vblank656=26;
+ burst=0x5b;
+ comb=0x66;
+ sc=556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int=cx25840_read(client, 0x108);
+ pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff;
+ pll_post=cx25840_read(client, 0x109);
+ v4l_dbg(1, cx25840_debug, client,
+ "PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int,pll_frac,pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L;
+
+ pll/=pll_post;
+ v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+ pll/1000000, pll%1000000);
+ v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+ pll/8000000, (pll/8)%1000000);
+
+ fin=((u64)src_decimation*pll)>>12;
+ v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = "
+ "%d.%06d MHz\n",
+ fin/1000000,fin%1000000);
+
+ fsc= (((u64)sc)*pll) >> 24L;
+ v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = "
+ "%d.%06d MHz\n",
+ fsc/1000000,fsc%1000000);
+
+ v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx25840_write(client, 0x470, hblank);
+ cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4)));
+ cx25840_write(client, 0x472, hactive>>4);
+
+ /* Sets burst gate delay */
+ cx25840_write(client, 0x473, burst);
- cx25840_write(client, 0x470, 0x7a);
- cx25840_write(client, 0x471, 0x00);
- cx25840_write(client, 0x472, 0x2d);
- cx25840_write(client, 0x473, 0x5b);
+ /* Sets vertical blanking delay and active duration */
+ cx25840_write(client, 0x474, vblank);
+ cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4)));
+ cx25840_write(client, 0x476, vactive>>4);
+ cx25840_write(client, 0x477, vblank656);
- cx25840_write(client, 0x474, 0x1a);
- cx25840_write(client, 0x475, 0x70);
- cx25840_write(client, 0x476, 0x1e);
- cx25840_write(client, 0x477, 0x1e);
+ /* Sets src decimation rate */
+ cx25840_write(client, 0x478, 0xff&src_decimation);
+ cx25840_write(client, 0x479, 0xff&(src_decimation>>8));
- cx25840_write(client, 0x478, 0x1f);
- cx25840_write(client, 0x479, 0x02);
- cx25840_write(client, 0x47a, 0x50);
- cx25840_write(client, 0x47b, 0x66);
+ /* Sets Luma and UV Low pass filters */
+ cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30));
- cx25840_write(client, 0x47c, 0x1f);
- cx25840_write(client, 0x47d, 0x7c);
- cx25840_write(client, 0x47e, 0x08);
+ /* Enables comb filters */
+ cx25840_write(client, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx25840_write(client, 0x47c, sc);
+ cx25840_write(client, 0x47d, 0xff&sc>>8);
+ cx25840_write(client, 0x47e, 0xff&sc>>16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx25840_write(client, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
cx25840_write(client, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
}
}
int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_format *fmt;
struct v4l2_sliced_vbi_format *svbi;
@@ -182,7 +255,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_FMT:
{
- int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
int vbi_offset = is_pal ? 1 : 0;
int i, x;
u8 lcr[24];
@@ -211,7 +284,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
cx25840_vbi_setup(client);
/* Sliced VBI */
- cx25840_write(client, 0x404, 0x36); /* Ancillery data */
+ cx25840_write(client, 0x404, 0x32); /* Ancillary data */
cx25840_write(client, 0x406, 0x13);
cx25840_write(client, 0x47f, vbi_offset);
@@ -248,8 +321,18 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
}
}
- for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
- cx25840_write(client, i, lcr[6 + x]);
+ if (is_pal) {
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+ cx25840_write(client, i, lcr[6 + x]);
+ }
+ }
+ else {
+ for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+ cx25840_write(client, i, lcr[9 + x]);
+ }
+ for (i = 0x431; i <= 0x434; i++) {
+ cx25840_write(client, i, 0);
+ }
}
cx25840_write(client, 0x43c, 0x16);
@@ -257,7 +340,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
if (is_pal) {
cx25840_write(client, 0x474, 0x2a);
} else {
- cx25840_write(client, 0x474, 0x1a + 6);
+ cx25840_write(client, 0x474, 0x22);
}
break;
}
@@ -278,7 +361,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
id1 = p[-1];
id2 = p[0] & 0xf;
l = p[2] & 0x3f;
- l += 5;
+ l += state->vbi_line_offset;
p += 4;
switch (id2) {
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 630273992a4..7a94e6a1192 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -35,13 +35,26 @@ config VIDEO_CX88_ALSA
To compile this driver as a module, choose M here: the
module will be called cx88-alsa.
+config VIDEO_CX88_BLACKBIRD
+ tristate "Blackbird MPEG encoder support (cx2388x + cx23416)"
+ depends on VIDEO_CX88
+ select VIDEO_CX2341X
+ ---help---
+ This adds support for MPEG encoder cards based on the
+ Blackbird reference design, using the Conexant 2388x
+ and 23416 chips.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx88-blackbird.
+
config VIDEO_CX88_DVB
tristate "DVB/ATSC Support for cx2388x based TV cards"
depends on VIDEO_CX88 && DVB_CORE
select VIDEO_BUF_DVB
+ select DVB_PLL
---help---
This adds support for DVB/ATSC cards based on the
- Connexant 2388x chip.
+ Conexant 2388x chip.
To compile this driver as a module, choose M here: the
module will be called cx88-dvb.
@@ -61,6 +74,7 @@ config VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_LGDT330X
select DVB_NXT200X
select DVB_CX24123
+ select DVB_ISL6421
---help---
This builds cx88-dvb with all currently supported frontend
demodulators. If you wish to tweak your configuration, and
@@ -139,6 +153,7 @@ config VIDEO_CX88_DVB_CX24123
default y
depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_CX24123
+ select DVB_ISL6421
---help---
This adds DVB-S support for cards based on the
Connexant 2388x chip and the CX24123 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 0dcd09b9b72..352b919f30c 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -3,9 +3,10 @@ cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \
cx8800-objs := cx88-video.o cx88-vbi.o
cx8802-objs := cx88-mpeg.o
-obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o cx88-blackbird.o
-obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
+obj-$(CONFIG_VIDEO_CX88) += cx88xx.o cx8800.o cx8802.o
obj-$(CONFIG_VIDEO_CX88_ALSA) += cx88-alsa.o
+obj-$(CONFIG_VIDEO_CX88_BLACKBIRD) += cx88-blackbird.o
+obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 320b3d9384b..f0340662e07 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -4,7 +4,7 @@
* PCI function #1 of the cx2388x.
*
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
- * (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ * (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
* Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
*
@@ -111,7 +111,7 @@ MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");
MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
MODULE_AUTHOR("Ricardo Cerqueira");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
"{{Conexant,23882},"
@@ -696,12 +696,11 @@ static int __devinit snd_cx88_create(struct snd_card *card,
chip->irq = -1;
spin_lock_init(&chip->reg_lock);
- cx88_reset(core);
chip->core = core;
/* get irq */
err = request_irq(chip->pci->irq, cx8801_irq,
- SA_SHIRQ | SA_INTERRUPT, chip->core->name, chip);
+ IRQF_SHARED | IRQF_DISABLED, chip->core->name, chip);
if (err < 0) {
dprintk(0, "%s: can't get IRQ %d\n",
chip->core->name, chip->pci->irq);
@@ -713,9 +712,9 @@ static int __devinit snd_cx88_create(struct snd_card *card,
pci_read_config_byte(pci, PCI_LATENCY_TIMER, &chip->pci_lat);
dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, "
- "latency: %d, mmio: 0x%lx\n", core->name, devno,
+ "latency: %d, mmio: 0x%llx\n", core->name, devno,
pci_name(pci), chip->pci_rev, pci->irq,
- chip->pci_lat,pci_resource_start(pci,0));
+ chip->pci_lat,(unsigned long long)pci_resource_start(pci,0));
chip->irq = pci->irq;
synchronize_irq(chip->irq);
@@ -767,8 +766,8 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
strcpy (card->driver, "CX88x");
sprintf(card->shortname, "Conexant CX%x", pci->device);
- sprintf(card->longname, "%s at %#lx",
- card->shortname, pci_resource_start(pci, 0));
+ sprintf(card->longname, "%s at %#llx",
+ card->shortname,(unsigned long long)pci_resource_start(pci, 0));
strcpy (card->mixername, "CX88");
dprintk (0, "%s/%i: ALSA support for cx2388x boards\n",
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e100d8ef369..b60177f173c 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -30,9 +30,10 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
#include "cx88.h"
-#include <media/v4l2-common.h>
MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -53,7 +54,6 @@ static LIST_HEAD(cx8802_devlist);
/* ------------------------------------------------------------------ */
-#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
/* defines below are from ivtv-driver.h */
@@ -63,8 +63,6 @@ static LIST_HEAD(cx8802_devlist);
/* Firmware API commands */
#define IVTV_API_STD_TIMEOUT 500
-#define BLACKBIRD_API_PING 0x80
-#define BLACKBIRD_API_BEGIN_CAPTURE 0x81
enum blackbird_capture_type {
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_CAPTURE,
@@ -78,205 +76,29 @@ enum blackbird_capture_bits {
BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10
};
-#define BLACKBIRD_API_END_CAPTURE 0x82
enum blackbird_capture_end {
BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
BLACKBIRD_END_NOW, /* stop immediately, no irq */
};
-#define BLACKBIRD_API_SET_AUDIO_ID 0x89
-#define BLACKBIRD_API_SET_VIDEO_ID 0x8B
-#define BLACKBIRD_API_SET_PCR_ID 0x8D
-#define BLACKBIRD_API_SET_FRAMERATE 0x8F
enum blackbird_framerate {
BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */
};
-#define BLACKBIRD_API_SET_RESOLUTION 0x91
-#define BLACKBIRD_API_SET_VIDEO_BITRATE 0x95
-enum blackbird_video_bitrate_type {
- BLACKBIRD_VIDEO_VBR,
- BLACKBIRD_VIDEO_CBR
-};
-#define BLACKBIRD_PEAK_RATE_DIVISOR 400
-enum blackbird_mux_rate {
- BLACKBIRD_MUX_RATE_DEFAULT,
- /* dvd mux rate: multiply by 400 to get the actual rate */
- BLACKBIRD_MUX_RATE_DVD = 25200
-};
-#define BLACKBIRD_API_SET_GOP_STRUCTURE 0x97
-#define BLACKBIRD_API_SET_ASPECT_RATIO 0x99
-enum blackbird_aspect_ratio {
- BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
- BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
- BLACKBIRD_ASPECT_RATIO_4_3,
- BLACKBIRD_ASPECT_RATIO_16_9,
- BLACKBIRD_ASPECT_RATIO_221_100,
- BLACKBIRD_ASPECT_RATIO_RESERVED
-};
-#define BLACKBIRD_API_SET_DNR_MODE 0x9B
-enum blackbird_dnr_bits {
- BLACKBIRD_DNR_BITS_MANUAL,
- BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
- BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
- BLACKBIRD_DNR_BITS_AUTO
-};
-enum blackbird_median_filter {
- BLACKBIRD_MEDIAN_FILTER_DISABLED,
- BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
- BLACKBIRD_MEDIAN_FILTER_VERTICAL,
- BLACKBIRD_MEDIAN_FILTER_HV,
- BLACKBIRD_MEDIAN_FILTER_DIAGONAL
-};
-#define BLACKBIRD_API_SET_MANUAL_DNR 0x9D
-#define BLACKBIRD_API_SET_DNR_MEDIAN 0x9F
-#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
-enum blackbird_spatial_filter_luma {
- BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
- BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
- BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
-};
-enum blackbird_spatial_filter_chroma {
- BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
-};
-#define BLACKBIRD_API_SET_3_2_PULLDOWN 0xB1
-enum blackbird_pulldown {
- BLACKBIRD_3_2_PULLDOWN_DISABLED,
- BLACKBIRD_3_2_PULLDOWN_ENABLED
-};
-#define BLACKBIRD_API_SET_VBI_LINE_NO 0xB7
-enum blackbird_vbi_line_bits {
- BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
- BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
- BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
-};
-enum blackbird_vbi_line {
- BLACKBIRD_VBI_LINE_DISABLED,
- BLACKBIRD_VBI_LINE_ENABLED
-};
-enum blackbird_vbi_slicing {
- BLACKBIRD_VBI_SLICING_NONE,
- BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
-};
-#define BLACKBIRD_API_SET_STREAM_TYPE 0xB9
-enum blackbird_stream_type {
- BLACKBIRD_STREAM_PROGRAM,
- BLACKBIRD_STREAM_TRANSPORT,
- BLACKBIRD_STREAM_MPEG1,
- BLACKBIRD_STREAM_PES_AV,
- BLACKBIRD_STREAM_UNKNOWN4,
- BLACKBIRD_STREAM_PES_VIDEO,
- BLACKBIRD_STREAM_UNKNOWN6,
- BLACKBIRD_STREAM_PES_AUDIO,
- BLACKBIRD_STREAM_UNKNOWN8,
- BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
- BLACKBIRD_STREAM_DVD,
- BLACKBIRD_STREAM_VCD,
- BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
-};
-#define BLACKBIRD_API_SET_OUTPUT_PORT 0xBB
enum blackbird_stream_port {
BLACKBIRD_OUTPUT_PORT_MEMORY,
BLACKBIRD_OUTPUT_PORT_STREAMING,
BLACKBIRD_OUTPUT_PORT_SERIAL
};
-#define BLACKBIRD_API_SET_AUDIO_PARAMS 0xBD
-enum blackbird_audio_bits_sample_rate {
- BLACKBIRD_AUDIO_BITS_44100HZ,
- BLACKBIRD_AUDIO_BITS_48000HZ,
- BLACKBIRD_AUDIO_BITS_32000HZ,
- BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
-};
-enum blackbird_audio_bits_encoding {
- BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
- BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
-};
-enum blackbird_audio_bits_bitrate_layer_1 {
- BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
- BLACKBIRD_AUDIO_BITS_LAYER_1_32 = 0x01 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_64 = 0x02 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_96 = 0x03 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
-};
-enum blackbird_audio_bits_bitrate_layer_2 {
- BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
- BLACKBIRD_AUDIO_BITS_LAYER_2_32 = 0x01 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_48 = 0x02 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_56 = 0x03 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_64 = 0x04 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_80 = 0x05 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_96 = 0x06 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
-};
-enum blackbird_audio_bits_mode {
- BLACKBIRD_AUDIO_BITS_STEREO,
- BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
- BLACKBIRD_AUDIO_BITS_DUAL = 0x2 << 8,
- BLACKBIRD_AUDIO_BITS_MONO = 0x3 << 8,
-};
-enum blackbird_audio_bits_mode_extension {
- BLACKBIRD_AUDIO_BITS_BOUND_4,
- BLACKBIRD_AUDIO_BITS_BOUND_8 = 0x1 << 10,
- BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
- BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
-};
-enum blackbird_audio_bits_emphasis {
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15 = 0x1 << 12,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED = 0x2 << 12,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
-};
-enum blackbird_audio_bits_crc {
- BLACKBIRD_AUDIO_BITS_CRC_OFF,
- BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
-};
-enum blackbird_audio_bits_copyright {
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
-};
-enum blackbird_audio_bits_original {
- BLACKBIRD_AUDIO_BITS_COPY,
- BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
-};
-#define BLACKBIRD_API_HALT 0xC3
-#define BLACKBIRD_API_GET_VERSION 0xC4
-#define BLACKBIRD_API_SET_GOP_CLOSURE 0xC5
-enum blackbird_gop_closure {
- BLACKBIRD_GOP_CLOSURE_OFF,
- BLACKBIRD_GOP_CLOSURE_ON,
-};
-#define BLACKBIRD_API_DATA_XFER_STATUS 0xC6
enum blackbird_data_xfer_status {
BLACKBIRD_MORE_BUFFERS_FOLLOW,
BLACKBIRD_LAST_BUFFER,
};
-#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
enum blackbird_picture_mask {
BLACKBIRD_PICTURE_MASK_NONE,
BLACKBIRD_PICTURE_MASK_I_FRAMES,
BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
};
-#define BLACKBIRD_API_SET_VBI_PARAMS 0xC8
enum blackbird_vbi_mode_bits {
BLACKBIRD_VBI_BITS_SLICED,
BLACKBIRD_VBI_BITS_RAW,
@@ -288,33 +110,23 @@ enum blackbird_vbi_insertion_bits {
BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
};
-#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
enum blackbird_dma_unit {
BLACKBIRD_DMA_BYTES,
BLACKBIRD_DMA_FRAMES,
};
-#define BLACKBIRD_API_DMA_TRANSFER_INFO 0xCA
-#define BLACKBIRD_API_DMA_TRANSFER_STAT 0xCB
enum blackbird_dma_transfer_status_bits {
BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
};
-#define BLACKBIRD_API_SET_DMA2HOST_ADDR 0xCC
-#define BLACKBIRD_API_INIT_VIDEO_INPUT 0xCD
-#define BLACKBIRD_API_SET_FRAMESKIP 0xD0
-#define BLACKBIRD_API_PAUSE 0xD2
enum blackbird_pause {
BLACKBIRD_PAUSE_ENCODING,
BLACKBIRD_RESUME_ENCODING,
};
-#define BLACKBIRD_API_REFRESH_INPUT 0xD3
-#define BLACKBIRD_API_SET_COPYRIGHT 0xD4
enum blackbird_copyright {
BLACKBIRD_COPYRIGHT_OFF,
BLACKBIRD_COPYRIGHT_ON,
};
-#define BLACKBIRD_API_SET_NOTIFICATION 0xD5
enum blackbird_notification_type {
BLACKBIRD_NOTIFICATION_REFRESH,
};
@@ -325,7 +137,6 @@ enum blackbird_notification_status {
enum blackbird_notification_mailbox {
BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
};
-#define BLACKBIRD_API_SET_CAPTURE_LINES 0xD6
enum blackbird_field1_lines {
BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
@@ -336,12 +147,10 @@ enum blackbird_field2_lines {
BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
};
-#define BLACKBIRD_API_SET_CUSTOM_DATA 0xD7
enum blackbird_custom_data_type {
BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
BLACKBIRD_CUSTOM_PRIVATE_PACKET,
};
-#define BLACKBIRD_API_MUTE_VIDEO 0xD9
enum blackbird_mute {
BLACKBIRD_UNMUTE,
BLACKBIRD_MUTE,
@@ -356,7 +165,6 @@ enum blackbird_mute_video_shift {
BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
};
-#define BLACKBIRD_API_MUTE_AUDIO 0xDA
/* Registers */
#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
@@ -498,15 +306,12 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value)
/* ------------------------------------------------------------------ */
-/* We don't need to call the API often, so using just one mailbox will probably suffice */
-static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
- u32 inputcnt, u32 outputcnt, ...)
+static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
{
+ struct cx8802_dev *dev = priv;
unsigned long timeout;
u32 value, flag, retval;
int i;
- va_list args;
- va_start(args, outputcnt);
dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
@@ -530,12 +335,11 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
/* write command + args + fill remaining with zeros */
memory_write(dev->core, dev->mailbox + 1, command); /* command code */
memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
- for (i = 0; i < inputcnt ; i++) {
- value = va_arg(args, int);
- memory_write(dev->core, dev->mailbox + 4 + i, value);
- dprintk(1, "API Input %d = %d\n", i, value);
+ for (i = 0; i < in; i++) {
+ memory_write(dev->core, dev->mailbox + 4 + i, data[i]);
+ dprintk(1, "API Input %d = %d\n", i, data[i]);
}
- for (; i < 16 ; i++)
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
memory_write(dev->core, dev->mailbox + 4 + i, 0);
flag |= 3; /* tell 'em we're done writing */
@@ -555,12 +359,10 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
}
/* read output values */
- for (i = 0; i < outputcnt ; i++) {
- int *vptr = va_arg(args, int *);
- memory_read(dev->core, dev->mailbox + 4 + i, vptr);
- dprintk(1, "API Output %d = %d\n", i, *vptr);
+ for (i = 0; i < out; i++) {
+ memory_read(dev->core, dev->mailbox + 4 + i, data + i);
+ dprintk(1, "API Output %d = %d\n", i, data[i]);
}
- va_end(args);
memory_read(dev->core, dev->mailbox + 2, &retval);
dprintk(1, "API result = %d\n",retval);
@@ -569,7 +371,29 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
memory_write(dev->core, dev->mailbox, flag);
return retval;
}
+/* ------------------------------------------------------------------ */
+
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+ u32 inputcnt, u32 outputcnt, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+ va_start(vargs, outputcnt);
+
+ for (i = 0; i < inputcnt; i++) {
+ data[i] = va_arg(vargs, int);
+ }
+ err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+ return err;
+}
static int blackbird_find_mailbox(struct cx8802_dev *dev)
{
@@ -614,13 +438,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
if (retval < 0)
dprintk(0, "Error with register_write\n");
- retval = request_firmware(&firmware, BLACKBIRD_FIRM_ENC_FILENAME,
+ retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
&dev->pci->dev);
if (retval != 0) {
dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
- BLACKBIRD_FIRM_ENC_FILENAME);
+ CX2341X_FIRM_ENC_FILENAME);
dprintk(0, "Please fix your hotplug setup, the board will "
"not work without firmware loaded!\n");
return -1;
@@ -629,11 +453,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
return -1;
}
if (0 != memcmp(firmware->data, magic, 8)) {
dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
return -1;
}
@@ -654,6 +480,7 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
}
if (checksum) {
dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n");
+ release_firmware(firmware);
return -1;
}
release_firmware(firmware);
@@ -686,12 +513,19 @@ DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | M
*DB: "DirectBurn"
*/
-static struct blackbird_dnr default_dnr_params = {
- .mode = BLACKBIRD_DNR_BITS_MANUAL,
- .type = BLACKBIRD_MEDIAN_FILTER_DISABLED,
- .spatial = 0,
- .temporal = 0
-};
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+ /* assign frame size */
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->height, dev->width);
+
+ dev->params.width = dev->width;
+ dev->params.height = dev->height;
+ dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+
+ cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
+}
+
static struct v4l2_mpeg_compression default_mpeg_params = {
.st_type = V4L2_MPEG_PS_2,
.st_bitrate = {
@@ -712,7 +546,7 @@ static struct v4l2_mpeg_compression default_mpeg_params = {
.target = 224,
.max = 224
},
- .au_sample_rate = 44100,
+ .au_sample_rate = 48000,
.au_pesid = 0,
.vi_type = V4L2_MPEG_VI_2,
.vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
@@ -723,524 +557,13 @@ static struct v4l2_mpeg_compression default_mpeg_params = {
.max = 6000
},
.vi_frame_rate = 25,
- .vi_frames_per_gop = 15,
+ .vi_frames_per_gop = 12,
.vi_bframes_count = 2,
.vi_pesid = 0,
- .closed_gops = 0,
+ .closed_gops = 1,
.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)
-{
- struct v4l2_mpeg_compression *params = &dev->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;
- 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;
- 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 */
- 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, 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, 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;
- }
- 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 */
- 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,
- dev->dnr_params.mode,
- dev->dnr_params.type
- );
-
- /* assign dnr filter props*/
- 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
- );
-
- /* 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)
{
struct cx88_core *core = dev->core;
@@ -1248,7 +571,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
int retval;
dprintk(1,"Initialize codec\n");
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
/* ping was not successful, reset and upload firmware */
cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
@@ -1263,13 +586,13 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
if (dev->mailbox < 0)
return -1;
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");
return -1;
}
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version);
if (retval < 0) {
dprintk(0, "ERROR: Firmware get encoder version failed!\n");
return -1;
@@ -1289,35 +612,35 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
BLACKBIRD_FIELD1_SAA7115,
- BLACKBIRD_FIELD1_SAA7115
+ BLACKBIRD_FIELD2_SAA7115
);
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* initialize the video input */
- blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0);
+ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
msleep(1);
- blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
+ blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
- blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
+ blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
/* start capturing to the host interface */
- /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */
- blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+ /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
+ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE
);
msleep(10);
- blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
+ blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
return 0;
}
@@ -1366,6 +689,39 @@ static struct videobuf_queue_ops blackbird_qops = {
/* ------------------------------------------------------------------ */
+static const u32 *ctrl_classes[] = {
+ cx88_user_ctrls,
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ /* Standard V4L2 controls */
+ if (cx8800_ctrl_query(qctrl) == 0)
+ return 0;
+
+ /* MPEG V4L2 controls */
+ if (cx2341x_ctrl_query(&dev->params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+}
+
+static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ blackbird_queryctrl(dev, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+/* ------------------------------------------------------------------ */
+
static int mpeg_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
@@ -1485,27 +841,84 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_mpeg_compression *f = arg;
- memcpy(f,&dev->params,sizeof(*f));
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
+ memcpy(f,&default_mpeg_params,sizeof(*f));
return 0;
}
case VIDIOC_S_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
+ return 0;
+ case VIDIOC_G_EXT_CTRLS:
{
- struct v4l2_mpeg_compression *f = arg;
+ struct v4l2_ext_controls *f = arg;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->params, f, cmd);
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *f = arg;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->params;
+ err = cx2341x_ext_ctrls(&p, f, cmd);
+ if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+ err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
+ dev->params = p;
+ }
+ return err;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ BLACKBIRD_END_NOW,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE);
- blackbird_set_params(dev, f);
+ cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+
+ blackbird_initialize_codec(dev);
+ cx88_set_scale(dev->core, dev->width, dev->height,
+ fh->mpegq.field);
+ return 0;
+ }
+ case VIDIOC_LOG_STATUS:
+ {
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", core->name);
+ printk("%s/2: ============ START LOG STATUS ============\n",
+ core->name);
+ cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, 0);
+ cx2341x_log_status(&dev->params, name);
+ printk("%s/2: ============= END LOG STATUS =============\n",
+ core->name);
return 0;
}
+ case VIDIOC_QUERYMENU:
+ return blackbird_querymenu(dev, arg);
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *c = arg;
+
+ if (blackbird_queryctrl(dev, c) == 0)
+ return 0;
+ return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
+ }
default:
- return cx88_do_ioctl( inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook );
+ return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
}
return 0;
}
-int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
-
static unsigned int mpeg_translate_ioctl(unsigned int cmd)
{
return cmd;
@@ -1514,8 +927,8 @@ static unsigned int mpeg_translate_ioctl(unsigned int cmd)
static int mpeg_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- cmd = cx88_ioctl_translator( cmd );
- return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
+ cmd = mpeg_translate_ioctl( cmd );
+ return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
}
static int mpeg_open(struct inode *inode, struct file *file)
@@ -1562,13 +975,14 @@ static int mpeg_release(struct inode *inode, struct file *file)
{
struct cx8802_fh *fh = file->private_data;
- /* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
- blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+ /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
BLACKBIRD_END_NOW,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE
);
+ cx8802_cancel_buffers(fh->dev);
/* stop mpeg capture */
if (fh->mpegq.streaming)
videobuf_streamoff(&fh->mpegq);
@@ -1683,19 +1097,13 @@ 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));
-
- if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
-
- if (core->tuner_formats & V4L2_STD_525_60) {
- dev->height = 480;
- dev->params.vi_frame_rate = 30;
- } else {
- dev->height = 576;
- dev->params.vi_frame_rate = 25;
- }
+ cx2341x_fill_defaults(&dev->params);
+ dev->params.port = CX2341X_PORT_STREAMING;
+ if (core->tvnorm->id & V4L2_STD_525_60) {
+ dev->height = 480;
+ } else {
+ dev->height = 576;
}
err = cx8802_init_common(dev);
@@ -1766,8 +1174,6 @@ static int blackbird_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- cx88_ioctl_hook = mpeg_do_ioctl;
- cx88_ioctl_translator = mpeg_translate_ioctl;
return pci_register_driver(&blackbird_pci_driver);
}
@@ -1779,11 +1185,6 @@ static void blackbird_fini(void)
module_init(blackbird_init);
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);
-
/* ----------------------------------------------------------- */
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index f80154b87d2..14bd4863d15 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -114,7 +114,7 @@ struct cx88_board cx88_boards[] = {
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xff10,
- },
+ },
},
[CX88_BOARD_ATI_WONDER_PRO] = {
.name = "ATI TV Wonder Pro",
@@ -267,7 +267,7 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x00007004,
.gpio2 = 0x0035d700,
.gpio3 = 0x02000000,
- },
+ },
},
[CX88_BOARD_LEADTEK_PVR2000] = {
// gpio values for PAL version from regspy by DScaler
@@ -413,7 +413,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
@@ -536,7 +536,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
@@ -759,7 +759,7 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
.name = "DViCO FusionHDTV 5 Gold",
- .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1050,11 +1050,7 @@ struct cx88_board cx88_boards[] = {
.dvb = 1,
},
[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
- /* FIXME: Standard video using the cx88 broadcast decoder is
- * working, but blackbird isn't working yet, audio is only
- * working correctly for television mode. S-Video and Composite
- * are working for video-only, so I have them disabled for now.
- */
+ /* FIXME: Audio not working for s-video / composite inputs. */
.name = "KWorld HardwareMpegTV XPert",
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
@@ -1065,12 +1061,21 @@ struct cx88_board cx88_boards[] = {
.vmux = 0,
.gpio0 = 0x3de2,
.gpio2 = 0x00ff,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x3de6,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x3de6,
}},
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x3de6,
.gpio2 = 0x00ff,
},
+ .blackbird = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
.name = "DViCO FusionHDTV DVB-T Hybrid",
@@ -1093,7 +1098,117 @@ struct cx88_board cx88_boards[] = {
}},
.dvb = 1,
},
-
+ [CX88_BOARD_PCHDTV_HD5500] = {
+ .name = "pcHDTV HD5500 HDTV",
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .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,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+ /* FIXME: tested TV input only, disabled composite,
+ svideo and radio until they can be tested also. */
+ .name = "Kworld MCE 200 Deluxe",
+ .tuner_type = TUNER_TENA_9533_DI,
+ .radio_type = UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0000BDE6
+ }},
+ .blackbird = 1,
+ },
+ [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+ /* FIXME: SVideo, Composite and FM inputs are untested */
+ .name = "PixelView PlayTV P7000",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+ TDA9887_PORT2_ACTIVE,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x5da6,
+ }},
+ .blackbird = 1,
+ },
+ [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+ .name = "NPG Tech Real TV FM Top 10",
+ .tuner_type = TUNER_TNF_5335MF, /* Actually a TNF9535 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0788,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x078b,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x078b,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x074a,
+ },
+ },
+ [CX88_BOARD_WINFAST_DTV2000H] = {
+ /* video inputs and radio still in testing */
+ .name = "WinFast DTV2000 H",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00017304,
+ .gpio1 = 0x00008203,
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_GENIATECH_DVBS] = {
+ .name = "Geniatech DVB-S",
+ .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_COMPOSITE1,
+ .vmux = 1,
+ }},
+ .dvb = 1,
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1311,6 +1426,38 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x18ac,
.subdevice = 0xdb44,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+ },{
+ .subvendor = 0x7063,
+ .subdevice = 0x5500,
+ .card = CX88_BOARD_PCHDTV_HD5500,
+ },{
+ .subvendor = 0x17de,
+ .subdevice = 0x0841,
+ .card = CX88_BOARD_KWORLD_MCE200_DELUXE,
+ },{
+ .subvendor = 0x1822,
+ .subdevice = 0x0019,
+ .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+ },{
+ .subvendor = 0x1554,
+ .subdevice = 0x4813,
+ .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
+ },{
+ .subvendor = 0x14f1,
+ .subdevice = 0x0842,
+ .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x665e,
+ .card = CX88_BOARD_WINFAST_DTV2000H,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
+ },{
+ .subvendor = 0x14f1,
+ .subdevice = 0x0084,
+ .card = CX88_BOARD_GENIATECH_DVBS,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1572,11 +1719,6 @@ void cx88_card_setup(struct cx88_core *core)
/* ------------------------------------------------------------------ */
EXPORT_SYMBOL(cx88_boards);
-EXPORT_SYMBOL(cx88_bcount);
-EXPORT_SYMBOL(cx88_subids);
-EXPORT_SYMBOL(cx88_idcount);
-EXPORT_SYMBOL(cx88_card_list);
-EXPORT_SYMBOL(cx88_card_setup);
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index e1092d5d462..973d3f39b2d 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -677,7 +677,7 @@ static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
{
- return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+ return (norm->id & V4L2_STD_625_50) ? 511 : 400;
}
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
@@ -932,9 +932,9 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
htotal, cx_read(MO_HTOTAL), (u32)tmp64);
cx_write(MO_HTOTAL, htotal);
- // vbi stuff
- cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
- norm_vbipack(norm)));
+ // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+ // the effective vbi offset ~244 samples, the same as the Bt8x8
+ cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
// this is needed as well to set all tvnorm parameter
cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
@@ -1031,8 +1031,8 @@ static int get_ressources(struct cx88_core *core, struct pci_dev *pci)
pci_resource_len(pci,0),
core->name))
return 0;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
- core->name,pci_resource_start(pci,0));
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ core->name,(unsigned long long)pci_resource_start(pci,0));
return -EBUSY;
}
@@ -1181,8 +1181,6 @@ EXPORT_SYMBOL(cx88_set_scale);
EXPORT_SYMBOL(cx88_vdev_init);
EXPORT_SYMBOL(cx88_core_get);
EXPORT_SYMBOL(cx88_core_put);
-EXPORT_SYMBOL(cx88_start_audio_dma);
-EXPORT_SYMBOL(cx88_stop_audio_dma);
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 3619a449aef..afde3789d70 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -51,6 +51,7 @@
#endif
#ifdef HAVE_LGDT330X
# include "lgdt330x.h"
+# include "lg_h06xf.h"
#endif
#ifdef HAVE_NXT200X
# include "nxt200x.h"
@@ -58,6 +59,7 @@
#ifdef HAVE_CX24123
# include "cx24123.h"
#endif
+#include "isl6421.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -113,21 +115,6 @@ static struct videobuf_queue_ops dvb_qops = {
/* ------------------------------------------------------------------ */
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
-static int zarlink_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *pllbuf)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
-
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 0;
-}
-#endif
-
#ifdef HAVE_MT352
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
@@ -196,19 +183,16 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
static struct mt352_config dvico_fusionhdtv = {
.demod_address = 0x0F,
.demod_init = dvico_fusionhdtv_demod_init,
- .pll_set = zarlink_pll_set,
};
static struct mt352_config dntv_live_dvbt_config = {
.demod_address = 0x0f,
.demod_init = dntv_live_dvbt_demod_init,
- .pll_set = zarlink_pll_set,
};
static struct mt352_config dvico_fusionhdtv_dual = {
.demod_address = 0x0F,
.demod_init = dvico_dual_demod_init,
- .pll_set = zarlink_pll_set,
};
#ifdef HAVE_VP3054_I2C
@@ -246,6 +230,8 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
.buf = fmd1216_init, .len = sizeof(fmd1216_init) };
int err;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
if (err < 0)
return err;
@@ -256,14 +242,14 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
return 0;
}
-static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
+static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
struct cx8802_dev *dev= fe->dvb->priv;
+ u8 buf[4];
struct i2c_msg msg =
{ .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf+1, .len = 4 };
+ .buf = buf, .len = 4 };
int err;
/* Switch PLL to DVB mode */
@@ -272,14 +258,16 @@ static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
return err;
/* Tune PLL */
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+ dvb_pll_configure(dev->core->pll_desc, buf,
params->frequency,
params->u.ofdm.bandwidth);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ __FUNCTION__, dev->core->pll_addr, buf[0], err);
if (err < 0)
return err;
else
@@ -293,27 +281,27 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
.demod_address = 0x0f,
.no_tuner = 1,
.demod_init = dntv_live_dvbt_pro_demod_init,
- .pll_set = dntv_live_dvbt_pro_pll_set,
};
#endif
#endif
#ifdef HAVE_ZL10353
-static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *pllbuf)
+static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
+ u8 pllbuf[4];
struct cx8802_dev *dev= fe->dvb->priv;
struct i2c_msg msg =
{ .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf + 1, .len = 4 };
+ .buf = pllbuf, .len = 4 };
int err;
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+ dvb_pll_configure(dev->core->pll_desc, pllbuf,
params->frequency,
params->u.ofdm.bandwidth);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
@@ -329,12 +317,11 @@ static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
static struct zl10353_config dvico_fusionhdtv_hybrid = {
.demod_address = 0x0F,
- .pll_set = dvico_hybrid_tune_pll,
+ .no_tuner = 1,
};
static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
.demod_address = 0x0F,
- .pll_set = zarlink_pll_set,
};
#endif
@@ -342,21 +329,15 @@ static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
static struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x60,
- .pll_desc = &dvb_pll_thomson_dtt7579,
};
static struct cx22702_config hauppauge_novat_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt759x,
};
static struct cx22702_config hauppauge_hvr1100_config = {
.demod_address = 0x63,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_fmd1216me,
};
#endif
@@ -371,15 +352,13 @@ static int or51132_set_ts_param(struct dvb_frontend* fe,
static struct or51132_config pchdtv_hd3000 = {
.demod_address = 0x15,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt761x,
.set_ts_params = or51132_set_ts_param,
};
#endif
#ifdef HAVE_LGDT330X
-static int lgdt330x_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
/* FIXME make this routine use the tuner-simple code.
* It could probably be shared with a number of ATSC
@@ -392,12 +371,12 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
{ .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
int err;
- /* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
dvb_pll_configure(core->pll_desc, 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 (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
@@ -407,16 +386,21 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe,
else
return -EREMOTEIO;
}
- if (core->tuner_type == TUNER_LG_TDVS_H062F) {
- /* Set the Auxiliary Byte. */
- buf[2] &= ~0x20;
- buf[2] |= 0x18;
- buf[3] = 0x50;
- i2c_transfer(&core->i2c_adap, &msg, 1);
- }
return 0;
}
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ /* Put the analog decoder in standby to keep it quiet */
+ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
+ return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
+}
+
static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
{
struct cx8802_dev *dev= fe->dvb->priv;
@@ -444,7 +428,6 @@ static struct lgdt330x_config fusionhdtv_3_gold = {
.demod_address = 0x0e,
.demod_chip = LGDT3302,
.serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
- .pll_set = lgdt330x_pll_set,
.set_ts_params = lgdt330x_set_ts_param,
};
@@ -452,7 +435,13 @@ static struct lgdt330x_config fusionhdtv_5_gold = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .pll_set = lgdt330x_pll_set,
+ .set_ts_params = lgdt330x_set_ts_param,
+};
+
+static struct lgdt330x_config pchdtv_hd5500 = {
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
.set_ts_params = lgdt330x_set_ts_param,
};
#endif
@@ -477,8 +466,6 @@ static int nxt200x_set_pll_input(u8* buf, int input)
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,
};
@@ -493,28 +480,50 @@ static int cx24123_set_ts_param(struct dvb_frontend* fe,
return 0;
}
-static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
- if (on)
- cx_write(MO_GP0_IO, 0x000006f9);
- else
+ if (voltage == SEC_VOLTAGE_OFF) {
cx_write(MO_GP0_IO, 0x000006fB);
+ } else {
+ cx_write(MO_GP0_IO, 0x000006f9);
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
}
+static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ if (voltage == SEC_VOLTAGE_OFF) {
+ dprintk(1,"LNB Voltage OFF\n");
+ cx_write(MO_GP0_IO, 0x0000efff);
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+}
+
+static struct cx24123_config geniatech_dvbs_config = {
+ .demod_address = 0x55,
+ .set_ts_params = cx24123_set_ts_param,
+};
+
static struct cx24123_config hauppauge_novas_config = {
.demod_address = 0x55,
- .use_isl6421 = 1,
.set_ts_params = cx24123_set_ts_param,
};
static struct cx24123_config kworld_dvbs_100_config = {
.demod_address = 0x15,
- .use_isl6421 = 0,
.set_ts_params = cx24123_set_ts_param,
- .enable_lnb_voltage = cx24123_enable_lnb_voltage,
};
#endif
@@ -530,6 +539,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt759x);
+ }
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
@@ -537,44 +551,92 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
break;
+ case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_fmd1216me);
+ }
break;
#endif
#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- dev->core->pll_addr = 0x60;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
#ifdef HAVE_MT352
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
- if (dev->dvb.frontend != NULL)
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
break;
+ }
#endif
#ifdef HAVE_ZL10353
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
+#endif
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+#ifdef HAVE_MT352
+ /* The tin box says DEE1601, but it seems to be DTT7579
+ * compatible, with a slightly different MT352 AGC gain. */
+ dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ break;
+ }
+#endif
+#ifdef HAVE_ZL10353
+ /* ZL10353 replaces MT352 on later cards */
+ dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
#endif
break;
#endif /* HAVE_MT352 || HAVE_ZL10353 */
#ifdef HAVE_MT352
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_lg_z201;
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_lg_z201);
+ }
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_ADSTECH_DVB_T_PCI:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_unknown_1;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_unknown_1);
+ }
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#ifdef HAVE_VP3054_I2C
@@ -582,18 +644,13 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_fmd1216me;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+ }
#else
printk("%s: built without vp3054 support\n", dev->core->name);
#endif
break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
- /* The tin box says DEE1601, but it seems to be DTT7579
- * compatible, with a slightly different MT352 AGC gain. */
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
- &dev->core->i2c_adap);
- break;
#endif
#ifdef HAVE_ZL10353
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
@@ -601,12 +658,20 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_thomson_fe6600;
dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+ }
break;
#endif
#ifdef HAVE_OR51132
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt761x);
+ }
break;
#endif
#ifdef HAVE_LGDT330X
@@ -627,6 +692,9 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_microtune_4042;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
@@ -643,6 +711,9 @@ static int dvb_register(struct cx8802_dev *dev)
dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
@@ -655,10 +726,28 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_tdvs_tua6034;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
+ }
+ break;
+ case CX88_BOARD_PCHDTV_HD5500:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+ dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
}
break;
#endif
@@ -666,6 +755,11 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_ATI_HDTVWONDER:
dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_tuv1236d);
+ }
break;
#endif
#ifdef HAVE_CX24123
@@ -673,10 +767,26 @@ static int dvb_register(struct cx8802_dev *dev)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
+ 0x08, 0x00, 0x00);
+ }
break;
case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+ }
+ break;
+ case CX88_BOARD_GENIATECH_DVBS:
+ dev->dvb.frontend = cx24123_attach(&geniatech_dvbs_config,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
+ }
break;
#endif
default:
@@ -690,15 +800,15 @@ static int dvb_register(struct cx8802_dev *dev)
}
if (dev->core->pll_desc) {
- dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
- dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+ dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
+ dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
}
/* 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);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
}
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index f720901e963..7bea3471486 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -138,13 +138,13 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
return;
if (core->dvbdev) {
- if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
i2c_clients_command(&core->i2c_adap, cmd, arg);
- if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
} else
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
@@ -155,7 +155,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
.getsda = cx8800_bit_getsda,
.getscl = cx8800_bit_getscl,
.udelay = 16,
- .mdelay = 10,
.timeout = 200,
};
@@ -234,7 +233,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
/* ----------------------------------------------------------------------- */
EXPORT_SYMBOL(cx88_call_i2c_clients);
-EXPORT_SYMBOL(cx88_i2c_init);
/*
* Local variables:
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index 78a63b7dd38..c2556464899 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -70,14 +70,33 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
static void cx88_ir_handle_key(struct cx88_IR *ir)
{
struct cx88_core *core = ir->core;
- u32 gpio, data;
+ u32 gpio, data, auxgpio;
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
+ if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+ /* This board apparently uses a combination of 2 GPIO
+ to represent the keys. Additionally, the second GPIO
+ can be used for parity.
+
+ Example:
+
+ for key "5"
+ gpio = 0x758, auxgpio = 0xe5 or 0xf5
+ for key "Power"
+ gpio = 0x758, auxgpio = 0xed or 0xfd
+ */
+
+ auxgpio = cx_read(MO_GP1_IO);
+ /* Take out the parity part */
+ gpio=(gpio & 0x7fd) + (auxgpio & 0xef);
+ } else
+ auxgpio = gpio;
+
if (ir->polling) {
- if (ir->last_gpio == gpio)
+ if (ir->last_gpio == auxgpio)
return;
- ir->last_gpio = gpio;
+ ir->last_gpio = auxgpio;
}
/* extract data */
@@ -172,12 +191,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
+ case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_WINFAST2000XP_EXPERT:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
ir->mask_keyup = 0x100;
- ir->polling = 1; /* ms */
+ ir->polling = 50; /* ms */
break;
case CX88_BOARD_IODATA_GVBCTV7E:
ir_codes = ir_codes_iodata_bctv7e;
@@ -228,6 +248,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_type = IR_TYPE_PD;
ir->sampling = 0xff00; /* address */
break;
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+ ir_codes = ir_codes_npgtech;
+ ir->gpio_addr = MO_GP0_IO;
+ ir->mask_keycode = 0xfa;
+ ir->polling = 50; /* ms */
+ break;
}
if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 7d16888b4a8..138a4f69250 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 w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+ dprintk(1, "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],
@@ -76,6 +76,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+ case CX88_BOARD_PCHDTV_HD5500:
cx_write(TS_SOP_STAT, 1<<13);
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -109,7 +110,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
q->count = 1;
/* enable irqs */
- dprintk( 0, "setting the interrupt mask\n" );
+ dprintk( 1, "setting the interrupt mask\n" );
cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
cx_set(MO_TS_INTMSK, 0x1f0011);
@@ -122,7 +123,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
static int cx8802_stop_dma(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
- dprintk( 0, "cx8802_stop_dma\n" );
+ dprintk( 1, "cx8802_stop_dma\n" );
/* stop dma */
cx_clear(MO_TS_DMACNTRL, 0x11);
@@ -142,10 +143,43 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
struct cx88_buffer *buf;
struct list_head *item;
- dprintk( 0, "cx8802_restart_queue\n" );
+ dprintk( 1, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
{
- dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
+ struct cx88_buffer *prev;
+ prev = NULL;
+
+ dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ 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);
+ cx8802_start_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(1,"[%p/%d] restart_queue - first active\n",
+ buf,buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(1,"[%p/%d] restart_queue - move to active\n",
+ buf,buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
return 0;
}
@@ -204,13 +238,13 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
if (list_empty(&cx88q->active)) {
- dprintk( 0, "queue is empty - first active\n" );
+ dprintk( 1, "queue is empty - first active\n" );
list_add_tail(&buf->vb.queue,&cx88q->active);
cx8802_start_dma(dev, cx88q, buf);
buf->vb.state = STATE_ACTIVE;
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(0,"[%p/%d] %s - first active\n",
+ dprintk(1,"[%p/%d] %s - first active\n",
buf, buf->vb.i, __FUNCTION__);
} else {
@@ -244,7 +278,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
}
if (restart)
{
- dprintk(0, "restarting queue\n" );
+ dprintk(1, "restarting queue\n" );
cx8802_restart_queue(dev,q);
}
spin_unlock_irqrestore(&dev->slock,flags);
@@ -386,9 +420,9 @@ 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, "
- "latency: %d, mmio: 0x%lx\n", dev->core->name,
+ "latency: %d, mmio: 0x%llx\n", dev->core->name,
pci_name(dev->pci), dev->pci_rev, dev->pci->irq,
- dev->pci_lat,pci_resource_start(dev->pci,0));
+ dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0));
/* initialize driver struct */
spin_lock_init(&dev->slock);
@@ -404,7 +438,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
/* get irq */
err = request_irq(dev->pci->irq, cx8802_irq,
- SA_SHIRQ | SA_INTERRUPT, dev->core->name, dev);
+ IRQF_SHARED | IRQF_DISABLED, dev->core->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
dev->core->name, dev->pci->irq);
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 641a0c5a649..5785c348157 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -52,6 +52,7 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
+#include <linux/config.h>
#include <linux/kthread.h>
#include "cx88.h"
@@ -137,21 +138,28 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
{
u32 volume;
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
/* restart dma; This avoids buzz in NICAM and is good in others */
cx88_stop_audio_dma(core);
#endif
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
cx88_start_audio_dma(core);
#endif
if (cx88_boards[core->board].blackbird) {
/* sets sound input from external adc */
- if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_ROSLYN:
+ case CX88_BOARD_KWORLD_MCE200_DELUXE:
+ case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
+ case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
+ case CX88_BOARD_ASUS_PVR_416:
cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
- else
+ break;
+ default:
cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+ }
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
@@ -718,7 +726,7 @@ static void set_audio_standard_FM(struct cx88_core *core,
/* ----------------------------------------------------------- */
-int cx88_detect_nicam(struct cx88_core *core)
+static int cx88_detect_nicam(struct cx88_core *core)
{
int i, j = 0;
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 846faadc9f1..aa2a6977009 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -34,8 +34,8 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
if (dev->core->tvnorm->id & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
- f->fmt.vbi.start[0] = 10 -1;
- f->fmt.vbi.start[1] = 273 -1;
+ f->fmt.vbi.start[0] = 10;
+ f->fmt.vbi.start[1] = 273;
} else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
/* pal */
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 694d1d80ff3..94c92bacc34 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -327,6 +327,51 @@ static struct cx88_ctrl cx8800_ctls[] = {
};
static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
+const u32 cx88_user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+ V4L2_CID_AUDIO_BALANCE,
+ V4L2_CID_AUDIO_MUTE,
+ 0
+};
+EXPORT_SYMBOL(cx88_user_ctrls);
+
+static const u32 *ctrl_classes[] = {
+ cx88_user_ctrls,
+ NULL
+};
+
+int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
+{
+ int i;
+
+ if (qctrl->id < V4L2_CID_BASE ||
+ qctrl->id >= V4L2_CID_LASTP1)
+ return -EINVAL;
+ for (i = 0; i < CX8800_CTLS; i++)
+ if (cx8800_ctls[i].v.id == qctrl->id)
+ break;
+ if (i == CX8800_CTLS) {
+ *qctrl = no_ctl;
+ return 0;
+ }
+ *qctrl = cx8800_ctls[i].v;
+ return 0;
+}
+EXPORT_SYMBOL(cx8800_ctrl_query);
+
+static int cx88_queryctrl(struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+ return cx8800_ctrl_query(qctrl);
+}
+
/* ------------------------------------------------------------------- */
/* resource management */
@@ -494,8 +539,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
return 0;
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);
+ list_move_tail(&buf->vb.queue, &q->active);
start_video_dma(dev, q, buf);
buf->vb.state = STATE_ACTIVE;
buf->count = q->count++;
@@ -506,8 +550,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
} else if (prev->vb.width == buf->vb.width &&
prev->vb.height == buf->vb.height &&
prev->fmt == buf->fmt) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue,&q->active);
+ list_move_tail(&buf->vb.queue, &q->active);
buf->vb.state = STATE_ACTIVE;
buf->count = q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
@@ -1137,7 +1180,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
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;
@@ -1183,7 +1225,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
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
/* --- streaming capture ------------------------------------- */
case VIDIOCGMBUF:
{
@@ -1364,20 +1406,8 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *c = arg;
- int i;
- if (c->id < V4L2_CID_BASE ||
- c->id >= V4L2_CID_LASTP1)
- return -EINVAL;
- for (i = 0; i < CX8800_CTLS; i++)
- if (cx8800_ctls[i].v.id == c->id)
- break;
- if (i == CX8800_CTLS) {
- *c = no_ctl;
- return 0;
- }
- *c = cx8800_ctls[i].v;
- return 0;
+ return cx88_queryctrl(c);
}
case VIDIOC_G_CTRL:
return get_control(core,arg);
@@ -1554,7 +1584,7 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
*id = 0;
return 0;
}
-#ifdef HAVE_V4L1
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCSTUNER:
{
struct video_tuner *v = arg;
@@ -1849,9 +1879,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
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, "
- "latency: %d, mmio: 0x%lx\n", core->name,
+ "latency: %d, mmio: 0x%llx\n", core->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
- dev->pci_lat,pci_resource_start(pci_dev,0));
+ dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
pci_set_master(pci_dev);
if (!pci_dma_supported(pci_dev,0xffffffff)) {
@@ -1884,7 +1914,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* get irq */
err = request_irq(pci_dev->irq, cx8800_irq,
- SA_SHIRQ | SA_INTERRUPT, core->name, dev);
+ IRQF_SHARED | IRQF_DISABLED, core->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
core->name,pci_dev->irq);
@@ -1895,8 +1925,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
/* load and configure helper modules */
if (TUNER_ABSENT != core->tuner_type)
request_module("tuner");
- if (core->tda9887_conf)
- request_module("tda9887");
/* register v4l devices */
dev->video_dev = cx88_vdev_init(core,dev->pci,
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 751a754a45e..2b4f1970c7d 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -100,7 +100,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
.getsda = vp3054_bit_getsda,
.getscl = vp3054_bit_getscl,
.udelay = 16,
- .mdelay = 10,
.timeout = 200,
};
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 326a25f147f..e7810955dd4 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -25,9 +25,11 @@
#include <linux/videodev2.h>
#include <linux/kdev_t.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/video-buf.h>
+#include <media/cx2341x.h>
#include <media/video-buf-dvb.h>
#include "btcx-risc.h"
@@ -35,7 +37,7 @@
#include <linux/version.h>
#include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
+#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
#ifndef TRUE
# define TRUE (1==1)
@@ -189,6 +191,12 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500 47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE 48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
+#define CX88_BOARD_WINFAST_DTV2000H 51
+#define CX88_BOARD_GENIATECH_DVBS 52
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -296,6 +304,7 @@ struct cx88_core {
/* config info -- dvb */
struct dvb_pll_desc *pll_desc;
unsigned int pll_addr;
+ int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
/* state info */
struct task_struct *kthread;
@@ -391,14 +400,6 @@ 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;
@@ -432,8 +433,7 @@ struct cx8802_dev {
unsigned char ts_gen_cntrl;
/* mpeg params */
- struct v4l2_mpeg_compression params;
- struct blackbird_dnr dnr_params;
+ struct cx2341x_mpeg_params params;
};
/* ----------------------------------------------------------- */
@@ -564,7 +564,6 @@ 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 */
@@ -592,16 +591,8 @@ int cx8802_resume_common(struct pci_dev *pci_dev);
extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
struct cx88_core *core, unsigned int cmd,
void *arg, v4l2_kioctl driver_ioctl);
-
-/* ----------------------------------------------------------- */
-/* cx88-blackbird.c */
-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);
+extern const u32 cx88_user_ctrls[];
+extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
/*
* Local variables:
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3ba3439db58..ed882ebc7b9 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,8 @@
#include <linux/usb.h>
#include <media/tuner.h>
#include <media/msp3400.h>
+#include <media/saa7115.h>
+#include <media/tvp5150.h>
#include <media/tveeprom.h>
#include <media/audiochip.h>
#include <media/v4l2-common.h>
@@ -46,11 +48,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -64,11 +66,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -82,11 +84,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -100,15 +102,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 1,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -122,15 +124,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -146,11 +148,11 @@ struct em28xx_board em28xx_boards[] = {
/*FIXME: S-Video not tested */
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 0,
+ .vmux = TVP5150_COMPOSITE0,
.amux = MSP_INPUT_DEFAULT,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 2,
+ .vmux = TVP5150_SVIDEO,
.amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
}},
@@ -165,15 +167,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7114,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 4,
+ .vmux = SAA7115_COMPOSITE4,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -188,15 +190,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -211,15 +213,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -234,15 +236,15 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -254,11 +256,11 @@ struct em28xx_board em28xx_boards[] = {
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
@@ -324,8 +326,4 @@ void em28xx_card_setup(struct em28xx *dev)
}
}
-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
index e5ee8bceb21..4350cc75b02 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -317,8 +317,8 @@ int em28xx_outfmt_set_yuv422(struct em28xx *dev)
return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
}
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
- u8 ymax)
+static 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);
@@ -328,7 +328,7 @@ int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
}
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u16 width, u16 height)
{
u8 cwidth = width;
@@ -345,7 +345,7 @@ int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
}
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
@@ -534,7 +534,7 @@ static inline void em28xx_isoc_video_copy(struct em28xx *dev,
* em28xx_isoIrq()
* handles the incoming isoc urbs and fills the frames from our inqueue
*/
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
{
struct em28xx *dev = urb->context;
int i, status;
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index 5b6cece37ae..d829d8f8c1f 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -399,17 +399,6 @@ 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)
{
@@ -436,9 +425,19 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x86:
+ case 0x43:
+ case 0x4b:
+ {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
break;
+ }
case 0x42:
dprintk1(1,"attach_inform: saa7114 detected.\n");
break;
@@ -464,6 +463,7 @@ static int attach_inform(struct i2c_client *client)
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;
@@ -480,12 +480,7 @@ static struct i2c_algorithm em28xx_algo = {
};
static struct i2c_adapter em28xx_adap_template = {
-#ifdef I2C_PEC
.owner = THIS_MODULE,
-#else
- .inc_use = inc_use,
- .dec_use = dec_use,
-#endif
.class = I2C_CLASS_TV_ANALOG,
.name = "em28xx",
.id = I2C_HW_B_EM28XX,
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 31e89e4f18b..3ffb5684f12 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
@@ -105,7 +105,7 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
@@ -148,8 +148,8 @@ void em28xx_set_ir(struct em28xx * dev,struct IR_i2c *ir)
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
break;
case (EM2820_BOARD_PINNACLE_USB_2):
- ir->ir_codes = ir_codes_em_pinnacle_usb;
- ir->get_key = get_key_pinnacle_usb;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ ir->get_key = get_key_pinnacle_usb_grey;
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
break;
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index cf7cdf9ef61..2a461dde480 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -3,7 +3,7 @@
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
Some parts based on SN9C10x PC Camera Controllers GPL driver made
@@ -42,7 +42,7 @@
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
"Markus Rechberger <mrechberger@gmail.com>, " \
- "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
"Sascha Sommer <saschasommer@freenet.de>"
#define DRIVER_NAME "em28xx"
@@ -170,8 +170,12 @@ static int em28xx_config(struct em28xx *dev)
static void em28xx_config_i2c(struct em28xx *dev)
{
struct v4l2_frequency f;
+ struct v4l2_routing route;
+
+ route.input = INPUT(dev->ctl_input)->vmux;
+ route.output = 0;
em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
- em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
/* configure tuner */
@@ -206,19 +210,19 @@ static void em28xx_empty_framequeues(struct em28xx *dev)
static void video_mux(struct em28xx *dev, int index)
{
- int input, ainput;
+ int ainput;
+ struct v4l2_routing route;
- input = INPUT(index)->vmux;
+ route.input = INPUT(index)->vmux;
+ route.output = 0;
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
- em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+ em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
if (dev->has_msp34xx) {
- struct v4l2_routing route;
-
if (dev->i2s_speed)
em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
route.input = dev->ctl_ainput;
@@ -1570,8 +1574,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
request_module("tvp5150");
if (dev->has_tuner)
request_module("tuner");
- if (dev->tda9887_conf)
- request_module("tda9887");
#endif
errCode = em28xx_config(dev);
if (errCode) {
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index e1ddc2f27a2..d8fcc9e17ac 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -3,7 +3,7 @@
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
@@ -319,13 +319,7 @@ 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);
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index dfc9dd732c9..8992b6e62b9 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2341,11 +2341,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_CTRL:
return et61x251_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return et61x251_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return et61x251_vidioc_cropcap(cam, arg);
@@ -2392,7 +2390,6 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_PARM:
return et61x251_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return et61x251_vidioc_s_parm(cam, arg);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 7e66d83fe0c..fba30a40e9c 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -150,12 +150,11 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-/* The new pinnacle PCTV remote (with the colored buttons)
+/* Common (grey or coloured) pinnacle PCTV remote handling
*
- * Ricardo Cerqueira <v4l@cerqueira.org>
*/
-
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int parity_offset, int marker, int code_modulo)
{
unsigned char b[4];
unsigned int start = 0,parity = 0,code = 0;
@@ -167,9 +166,9 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
}
for (start = 0; start<4; start++) {
- if (b[start] == 0x80) {
- code=b[(start+3)%4];
- parity=b[(start+2)%4];
+ if (b[start] == marker) {
+ code=b[(start+parity_offset+1)%4];
+ parity=b[(start+parity_offset)%4];
}
}
@@ -181,16 +180,14 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
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
- */
+ /* drop special codes when a key is held down a long time for the grey controller
+ In this case, the second bit of the code is asserted */
+ if (marker == 0xfe && (code & 0x40))
+ return 0;
- code %= 0x88;
+ code %= code_modulo;
*ir_raw = code;
*ir_key = code;
@@ -200,7 +197,40 @@ int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-EXPORT_SYMBOL_GPL(get_key_pinnacle);
+/* The grey pinnacle PCTV remote
+ *
+ * There are one issue with this remote:
+ * - I2c packet does not change when the same key is pressed quickly. The workaround
+ * is to hold down each key for about half a second, so that another code is generated
+ * in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
new file mode 100644
index 00000000000..3bf7ac4f528
--- /dev/null
+++ b/drivers/media/video/ks0127.c
@@ -0,0 +1,846 @@
+/*
+ * Video Capture Driver (Video for Linux 1/2)
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *****************************************************************************
+ *
+ * Modified and extended by
+ * Mike Bernson <mike@mlb.org>
+ * Gerard v.d. Horst
+ * Leon van Stuivenberg <l.vanstuivenberg@chello.nl>
+ * Gernot Ziegler <gz@lysator.liu.se>
+ *
+ * Version History:
+ * V1.0 Ryan Drake Initial version by Ryan Drake
+ * V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "ks0127.h"
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define dprintk if (debug) printk
+
+/* i2c identification */
+#define I2C_KS0127_ADDON 0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
+#define KS_TYPE_UNKNOWN 0
+#define KS_TYPE_0122S 1
+#define KS_TYPE_0127 2
+#define KS_TYPE_0127B 3
+
+/* ks0127 control registers */
+#define KS_STAT 0x00
+#define KS_CMDA 0x01
+#define KS_CMDB 0x02
+#define KS_CMDC 0x03
+#define KS_CMDD 0x04
+#define KS_HAVB 0x05
+#define KS_HAVE 0x06
+#define KS_HS1B 0x07
+#define KS_HS1E 0x08
+#define KS_HS2B 0x09
+#define KS_HS2E 0x0a
+#define KS_AGC 0x0b
+#define KS_HXTRA 0x0c
+#define KS_CDEM 0x0d
+#define KS_PORTAB 0x0e
+#define KS_LUMA 0x0f
+#define KS_CON 0x10
+#define KS_BRT 0x11
+#define KS_CHROMA 0x12
+#define KS_CHROMB 0x13
+#define KS_DEMOD 0x14
+#define KS_SAT 0x15
+#define KS_HUE 0x16
+#define KS_VERTIA 0x17
+#define KS_VERTIB 0x18
+#define KS_VERTIC 0x19
+#define KS_HSCLL 0x1a
+#define KS_HSCLH 0x1b
+#define KS_VSCLL 0x1c
+#define KS_VSCLH 0x1d
+#define KS_OFMTA 0x1e
+#define KS_OFMTB 0x1f
+#define KS_VBICTL 0x20
+#define KS_CCDAT2 0x21
+#define KS_CCDAT1 0x22
+#define KS_VBIL30 0x23
+#define KS_VBIL74 0x24
+#define KS_VBIL118 0x25
+#define KS_VBIL1512 0x26
+#define KS_TTFRAM 0x27
+#define KS_TESTA 0x28
+#define KS_UVOFFH 0x29
+#define KS_UVOFFL 0x2a
+#define KS_UGAIN 0x2b
+#define KS_VGAIN 0x2c
+#define KS_VAVB 0x2d
+#define KS_VAVE 0x2e
+#define KS_CTRACK 0x2f
+#define KS_POLCTL 0x30
+#define KS_REFCOD 0x31
+#define KS_INVALY 0x32
+#define KS_INVALU 0x33
+#define KS_INVALV 0x34
+#define KS_UNUSEY 0x35
+#define KS_UNUSEU 0x36
+#define KS_UNUSEV 0x37
+#define KS_USRSAV 0x38
+#define KS_USREAV 0x39
+#define KS_SHS1A 0x3a
+#define KS_SHS1B 0x3b
+#define KS_SHS1C 0x3c
+#define KS_CMDE 0x3d
+#define KS_VSDEL 0x3e
+#define KS_CMDF 0x3f
+#define KS_GAMMA0 0x40
+#define KS_GAMMA1 0x41
+#define KS_GAMMA2 0x42
+#define KS_GAMMA3 0x43
+#define KS_GAMMA4 0x44
+#define KS_GAMMA5 0x45
+#define KS_GAMMA6 0x46
+#define KS_GAMMA7 0x47
+#define KS_GAMMA8 0x48
+#define KS_GAMMA9 0x49
+#define KS_GAMMA10 0x4a
+#define KS_GAMMA11 0x4b
+#define KS_GAMMA12 0x4c
+#define KS_GAMMA13 0x4d
+#define KS_GAMMA14 0x4e
+#define KS_GAMMA15 0x4f
+#define KS_GAMMA16 0x50
+#define KS_GAMMA17 0x51
+#define KS_GAMMA18 0x52
+#define KS_GAMMA19 0x53
+#define KS_GAMMA20 0x54
+#define KS_GAMMA21 0x55
+#define KS_GAMMA22 0x56
+#define KS_GAMMA23 0x57
+#define KS_GAMMA24 0x58
+#define KS_GAMMA25 0x59
+#define KS_GAMMA26 0x5a
+#define KS_GAMMA27 0x5b
+#define KS_GAMMA28 0x5c
+#define KS_GAMMA29 0x5d
+#define KS_GAMMA30 0x5e
+#define KS_GAMMA31 0x5f
+#define KS_GAMMAD0 0x60
+#define KS_GAMMAD1 0x61
+#define KS_GAMMAD2 0x62
+#define KS_GAMMAD3 0x63
+#define KS_GAMMAD4 0x64
+#define KS_GAMMAD5 0x65
+#define KS_GAMMAD6 0x66
+#define KS_GAMMAD7 0x67
+#define KS_GAMMAD8 0x68
+#define KS_GAMMAD9 0x69
+#define KS_GAMMAD10 0x6a
+#define KS_GAMMAD11 0x6b
+#define KS_GAMMAD12 0x6c
+#define KS_GAMMAD13 0x6d
+#define KS_GAMMAD14 0x6e
+#define KS_GAMMAD15 0x6f
+#define KS_GAMMAD16 0x70
+#define KS_GAMMAD17 0x71
+#define KS_GAMMAD18 0x72
+#define KS_GAMMAD19 0x73
+#define KS_GAMMAD20 0x74
+#define KS_GAMMAD21 0x75
+#define KS_GAMMAD22 0x76
+#define KS_GAMMAD23 0x77
+#define KS_GAMMAD24 0x78
+#define KS_GAMMAD25 0x79
+#define KS_GAMMAD26 0x7a
+#define KS_GAMMAD27 0x7b
+#define KS_GAMMAD28 0x7c
+#define KS_GAMMAD29 0x7d
+#define KS_GAMMAD30 0x7e
+#define KS_GAMMAD31 0x7f
+
+
+/****************************************************************************
+* mga_dev : represents one ks0127 chip.
+****************************************************************************/
+
+struct adjust {
+ int contrast;
+ int bright;
+ int hue;
+ int ugain;
+ int vgain;
+};
+
+struct ks0127 {
+ struct i2c_client *client;
+ unsigned char addr;
+ int format_width;
+ int format_height;
+ int cap_width;
+ int cap_height;
+ int norm;
+ int ks_type;
+ u8 regs[256];
+};
+
+
+static int debug; /* insmod parameter */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug output");
+MODULE_LICENSE("GPL");
+
+static u8 reg_defaults[64];
+
+
+
+static void init_reg_defaults(void)
+{
+ u8 *table = reg_defaults;
+
+ table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */
+ table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */
+ table[KS_CMDC] = 0x00; /* Test options */
+ /* clock & input select, write 1 to PORTA */
+ table[KS_CMDD] = 0x01;
+ table[KS_HAVB] = 0x00; /* HAV Start Control */
+ table[KS_HAVE] = 0x00; /* HAV End Control */
+ table[KS_HS1B] = 0x10; /* HS1 Start Control */
+ table[KS_HS1E] = 0x00; /* HS1 End Control */
+ table[KS_HS2B] = 0x00; /* HS2 Start Control */
+ table[KS_HS2E] = 0x00; /* HS2 End Control */
+ table[KS_AGC] = 0x53; /* Manual setting for AGC */
+ table[KS_HXTRA] = 0x00; /* Extra Bits for HAV and HS1/2 */
+ table[KS_CDEM] = 0x00; /* Chroma Demodulation Control */
+ table[KS_PORTAB] = 0x0f; /* port B is input, port A output GPPORT */
+ table[KS_LUMA] = 0x01; /* Luma control */
+ table[KS_CON] = 0x00; /* Contrast Control */
+ table[KS_BRT] = 0x00; /* Brightness Control */
+ table[KS_CHROMA] = 0x2a; /* Chroma control A */
+ table[KS_CHROMB] = 0x90; /* Chroma control B */
+ table[KS_DEMOD] = 0x00; /* Chroma Demodulation Control & Status */
+ table[KS_SAT] = 0x00; /* Color Saturation Control*/
+ table[KS_HUE] = 0x00; /* Hue Control */
+ table[KS_VERTIA] = 0x00; /* Vertical Processing Control A */
+ /* Vertical Processing Control B, luma 1 line delayed */
+ table[KS_VERTIB] = 0x12;
+ table[KS_VERTIC] = 0x0b; /* Vertical Processing Control C */
+ table[KS_HSCLL] = 0x00; /* Horizontal Scaling Ratio Low */
+ table[KS_HSCLH] = 0x00; /* Horizontal Scaling Ratio High */
+ table[KS_VSCLL] = 0x00; /* Vertical Scaling Ratio Low */
+ table[KS_VSCLH] = 0x00; /* Vertical Scaling Ratio High */
+ /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */
+ table[KS_OFMTA] = 0x30;
+ table[KS_OFMTB] = 0x00; /* Output Control B */
+ /* VBI Decoder Control; 4bit fmt: avoid Y overflow */
+ table[KS_VBICTL] = 0x5d;
+ table[KS_CCDAT2] = 0x00; /* Read Only register */
+ table[KS_CCDAT1] = 0x00; /* Read Only register */
+ table[KS_VBIL30] = 0xa8; /* VBI data decoding options */
+ table[KS_VBIL74] = 0xaa; /* VBI data decoding options */
+ table[KS_VBIL118] = 0x2a; /* VBI data decoding options */
+ table[KS_VBIL1512] = 0x00; /* VBI data decoding options */
+ table[KS_TTFRAM] = 0x00; /* Teletext frame alignment pattern */
+ table[KS_TESTA] = 0x00; /* test register, shouldn't be written */
+ table[KS_UVOFFH] = 0x00; /* UV Offset Adjustment High */
+ table[KS_UVOFFL] = 0x00; /* UV Offset Adjustment Low */
+ table[KS_UGAIN] = 0x00; /* U Component Gain Adjustment */
+ table[KS_VGAIN] = 0x00; /* V Component Gain Adjustment */
+ table[KS_VAVB] = 0x07; /* VAV Begin */
+ table[KS_VAVE] = 0x00; /* VAV End */
+ table[KS_CTRACK] = 0x00; /* Chroma Tracking Control */
+ table[KS_POLCTL] = 0x41; /* Timing Signal Polarity Control */
+ table[KS_REFCOD] = 0x80; /* Reference Code Insertion Control */
+ table[KS_INVALY] = 0x10; /* Invalid Y Code */
+ table[KS_INVALU] = 0x80; /* Invalid U Code */
+ table[KS_INVALV] = 0x80; /* Invalid V Code */
+ table[KS_UNUSEY] = 0x10; /* Unused Y Code */
+ table[KS_UNUSEU] = 0x80; /* Unused U Code */
+ table[KS_UNUSEV] = 0x80; /* Unused V Code */
+ table[KS_USRSAV] = 0x00; /* reserved */
+ table[KS_USREAV] = 0x00; /* reserved */
+ table[KS_SHS1A] = 0x00; /* User Defined SHS1 A */
+ /* User Defined SHS1 B, ALT656=1 on 0127B */
+ table[KS_SHS1B] = 0x80;
+ table[KS_SHS1C] = 0x00; /* User Defined SHS1 C */
+ table[KS_CMDE] = 0x00; /* Command Register E */
+ table[KS_VSDEL] = 0x00; /* VS Delay Control */
+ /* Command Register F, update -immediately- */
+ /* (there might come no vsync)*/
+ table[KS_CMDF] = 0x02;
+}
+
+
+/* We need to manually read because of a bug in the KS0127 chip.
+ *
+ * An explanation from kayork@mail.utexas.edu:
+ *
+ * During I2C reads, the KS0127 only samples for a stop condition
+ * during the place where the acknoledge bit should be. Any standard
+ * I2C implementation (correctly) throws in another clock transition
+ * at the 9th bit, and the KS0127 will not recognize the stop condition
+ * and will continue to clock out data.
+ *
+ * So we have to do the read ourself. Big deal.
+ workaround in i2c-algo-bit
+ */
+
+
+static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+{
+ struct i2c_client *c = ks->client;
+ char val = 0;
+ struct i2c_msg msgs[] = {
+ {c->addr, 0, sizeof(reg), &reg},
+ {c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+ int ret;
+
+ ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ dprintk("ks0127_write error\n");
+
+ return val;
+}
+
+
+static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+{
+ char msg[] = {reg, val};
+
+ if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
+ dprintk("ks0127_write error\n");
+
+ ks->regs[reg] = val;
+}
+
+
+/* generic bit-twiddling */
+static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+{
+ u8 val = ks->regs[reg];
+ val = (val & and_v) | or_v;
+ ks0127_write(ks, reg, val);
+}
+
+
+
+/****************************************************************************
+* ks0127 private api
+****************************************************************************/
+static void ks0127_reset(struct ks0127* ks)
+{
+ int i;
+ u8 *table = reg_defaults;
+
+ ks->ks_type = KS_TYPE_UNKNOWN;
+
+ dprintk("ks0127: reset\n");
+ msleep(1);
+
+ /* initialize all registers to known values */
+ /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+ for(i = 1; i < 33; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 35; i < 40; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 41; i < 56; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 58; i < 64; i++)
+ ks0127_write(ks, i, table[i]);
+
+
+ if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+ ks->ks_type = KS_TYPE_0122S;
+ dprintk("ks0127: ks0122s Found\n");
+ return;
+ }
+
+ switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
+
+ case 0:
+ ks->ks_type = KS_TYPE_0127;
+ dprintk("ks0127: ks0127 found\n");
+ break;
+
+ case 9:
+ ks->ks_type = KS_TYPE_0127B;
+ dprintk("ks0127: ks0127B Revision A found\n");
+ break;
+
+ default:
+ dprintk("ks0127: unknown revision\n");
+ break;
+ }
+}
+
+static int ks0127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
+ int *iarg = (int*)arg;
+
+ int status;
+
+ if (!ks)
+ return -ENODEV;
+
+ switch (cmd) {
+
+ case DECODER_INIT:
+ dprintk("ks0127: command DECODER_INIT\n");
+ ks0127_reset(ks);
+ break;
+
+ case DECODER_SET_INPUT:
+ switch(*iarg) {
+ case KS_INPUT_COMPOSITE_1:
+ case KS_INPUT_COMPOSITE_2:
+ case KS_INPUT_COMPOSITE_3:
+ case KS_INPUT_COMPOSITE_4:
+ case KS_INPUT_COMPOSITE_5:
+ case KS_INPUT_COMPOSITE_6:
+ dprintk("ks0127: command DECODER_SET_INPUT %d: "
+ "Composite\n", *iarg);
+ /* autodetect 50/60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ /* VSE=0 */
+ ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ /* set input line */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ /* non-freerunning mode */
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ /* analog input */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ /* enable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ /* chroma trap, HYBWR=1 */
+ ks0127_and_or(ks, KS_LUMA, 0x00,
+ (reg_defaults[KS_LUMA])|0x0c);
+ /* scaler fullbw, luma comb off */
+ ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+ /* manual chroma comb .25 .5 .25 */
+ ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+
+ /* chroma path delay */
+ ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+
+ ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+ case KS_INPUT_SVIDEO_1:
+ case KS_INPUT_SVIDEO_2:
+ case KS_INPUT_SVIDEO_3:
+ dprintk("ks0127: command DECODER_SET_INPUT %d: "
+ "S-Video\n", *iarg);
+ /* autodetect 50/60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ /* VSE=0 */
+ ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ /* set input line */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ /* non-freerunning mode */
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ /* analog input */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ /* enable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ ks0127_and_or(ks, KS_LUMA, 0x00,
+ reg_defaults[KS_LUMA]);
+ /* disable luma comb */
+ ks0127_and_or(ks, KS_VERTIA, 0x08,
+ (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+ ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ reg_defaults[KS_VERTIC]&0xf0);
+
+ ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ reg_defaults[KS_CHROMB]&0xf0);
+
+ ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+ case KS_INPUT_YUV656:
+ dprintk("ks0127: command DECODER_SET_INPUT 15: "
+ "YUV656\n");
+ if (ks->norm == VIDEO_MODE_NTSC ||
+ ks->norm == KS_STD_PAL_M)
+ /* force 60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x03);
+ else
+ /* force 50 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x02);
+
+ ks0127_and_or(ks, KS_CMDA, 0xff, 0x40); /* VSE=1 */
+ /* set input line and VALIGN */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, (*iarg | 0x40));
+ /* freerunning mode, */
+ /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x87);
+ /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x08);
+ /* disable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+ /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+ ks0127_and_or(ks, KS_LUMA, 0x00, 0x71);
+ ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ reg_defaults[KS_VERTIC]&0xf0);
+
+ /* scaler fullbw, luma comb off */
+ ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+
+ ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ reg_defaults[KS_CHROMB]&0xf0);
+
+ ks0127_and_or(ks, KS_CON, 0x00, 0x00);
+ ks0127_and_or(ks, KS_BRT, 0x00, 32); /* spec: 34 */
+ /* spec: 229 (e5) */
+ ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
+ ks0127_and_or(ks, KS_HUE, 0x00, 0);
+
+ ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
+ ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+
+ /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+ ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
+ ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+ break;
+
+ default:
+ dprintk("ks0127: command DECODER_SET_INPUT: "
+ "Unknown input %d\n", *iarg);
+ break;
+ }
+
+ /* hack: CDMLPF sometimes spontaneously switches on; */
+ /* force back off */
+ ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+ break;
+
+ case DECODER_SET_OUTPUT:
+ switch(*iarg) {
+ case KS_OUTPUT_YUV656E:
+ dprintk("ks0127: command DECODER_SET_OUTPUT: "
+ "OUTPUT_YUV656E (Missing)\n");
+ return -EINVAL;
+ break;
+
+ case KS_OUTPUT_EXV:
+ dprintk("ks0127: command DECODER_SET_OUTPUT: "
+ "OUTPUT_EXV\n");
+ ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+ break;
+ }
+ break;
+
+ case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+ /* Set to automatic SECAM/Fsc mode */
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+
+ ks->norm = *iarg;
+ switch(*iarg)
+ {
+ /* this is untested !! */
+ /* It just detects PAL_N/NTSC_M (no special frequencies) */
+ /* And you have to set the standard a second time afterwards */
+ case VIDEO_MODE_AUTO:
+ dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+
+ /* The chip determines the format */
+ /* based on the current field rate */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ /* This is wrong for PAL ! As I said, */
+ /* you need to set the standard once again !! */
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_NTSC:
+ dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case KS_STD_NTSC_N:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "NTSC_N (fixme)\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_PAL:
+ dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks->format_height = 290;
+ ks->format_width = 704;
+ break;
+
+ case KS_STD_PAL_M:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "PAL_M (fixme)\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ ks->format_height = 290;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_SECAM:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "SECAM\n");
+ ks->format_height = 290;
+ ks->format_width = 704;
+
+ /* set to secam autodetection */
+ ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+ schedule_timeout_interruptible(HZ/10+1);
+
+ /* did it autodetect? */
+ if (ks0127_read(ks, KS_DEMOD) & 0x40)
+ break;
+
+ /* force to secam mode */
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+ break;
+
+ default:
+ dprintk("ks0127: command DECODER_SET_NORM: "
+ "Unknown norm %d\n", *iarg);
+ break;
+ }
+ break;
+
+ case DECODER_SET_PICTURE:
+ dprintk("ks0127: command DECODER_SET_PICTURE "
+ "not yet supported (fixme)\n");
+ return -EINVAL;
+
+ //sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
+ //sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_AGC_MODE:
+ //sam todo: KS0127_SET_AGC:
+ //sam todo: KS0127_SET_CHROMA_MODE:
+ //sam todo: KS0127_SET_PIXCLK_MODE:
+ //sam todo: KS0127_SET_GAMMA_MODE:
+ //sam todo: KS0127_SET_UGAIN:
+ //sam todo: KS0127_SET_VGAIN:
+ //sam todo: KS0127_SET_INVALY:
+ //sam todo: KS0127_SET_INVALU:
+ //sam todo: KS0127_SET_INVALV:
+ //sam todo: KS0127_SET_UNUSEY:
+ //sam todo: KS0127_SET_UNUSEU:
+ //sam todo: KS0127_SET_UNUSEV:
+ //sam todo: KS0127_SET_VSALIGN_MODE:
+
+ case DECODER_ENABLE_OUTPUT:
+ {
+
+ int *iarg = arg;
+ int enable = (*iarg != 0);
+ if (enable) {
+ dprintk("ks0127: command "
+ "DECODER_ENABLE_OUTPUT on "
+ "(%d)\n", enable);
+ /* All output pins on */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+ /* Obey the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+ } else {
+ dprintk("ks0127: command "
+ "DECODER_ENABLE_OUTPUT off "
+ "(%d)\n", enable);
+ /* Video output pins off */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+ /* Ignore the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+ }
+ }
+ break;
+
+ //sam todo: KS0127_SET_OUTPUT_MODE:
+ //sam todo: KS0127_SET_WIDTH:
+ //sam todo: KS0127_SET_HEIGHT:
+ //sam todo: KS0127_SET_HSCALE:
+
+ case DECODER_GET_STATUS:
+ dprintk("ks0127: command DECODER_GET_STATUS\n");
+ *iarg = 0;
+ status = ks0127_read(ks, KS_STAT);
+ if (!(status & 0x20)) /* NOVID not set */
+ *iarg = (*iarg & DECODER_STATUS_GOOD);
+ if ((status & 0x01)) /* CLOCK set */
+ *iarg = (*iarg & DECODER_STATUS_COLOR);
+ if ((status & 0x08)) /* PALDET set */
+ *iarg = (*iarg & DECODER_STATUS_PAL);
+ else
+ *iarg = (*iarg & DECODER_STATUS_NTSC);
+ break;
+
+ //Catch any unknown command
+ default:
+ dprintk("ks0127: command unknown: %04X\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+
+
+static int ks0127_probe(struct i2c_adapter *adapter);
+static int ks0127_detach(struct i2c_client *client);
+static int ks0127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg);
+
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
+ I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
+static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static struct i2c_client_address_data addr_data = {
+ normal_i2c,
+ probe,
+ ignore,
+};
+
+static struct i2c_driver i2c_driver_ks0127 = {
+ .driver.name = "ks0127",
+ .id = I2C_DRIVERID_KS0127,
+ .attach_adapter = ks0127_probe,
+ .detach_client = ks0127_detach,
+ .command = ks0127_command
+};
+
+static struct i2c_client ks0127_client_tmpl =
+{
+ .name = "(ks0127 unset)",
+ .addr = 0,
+ .adapter = NULL,
+ .driver = &i2c_driver_ks0127,
+ .usage_count = 0
+};
+
+static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct ks0127 *ks;
+ struct i2c_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+
+ ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+ if (ks == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, ks);
+ client->adapter = adapter;
+ client->addr = addr;
+ sprintf(client->name, "ks0127-%02x", adapter->id);
+
+ ks->client = client;
+ ks->addr = addr;
+ ks->ks_type = KS_TYPE_UNKNOWN;
+
+ /* power up */
+ ks0127_write(ks, KS_CMDA, 0x2c);
+ mdelay(10);
+
+ /* reset the device */
+ ks0127_reset(ks);
+ printk(KERN_INFO "ks0127: attach: %s video decoder\n",
+ ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+
+static int ks0127_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->id == I2C_HW_B_ZR36067)
+ return i2c_probe(adapter, &addr_data, ks0127_found_proc);
+ return 0;
+}
+
+static int ks0127_detach(struct i2c_client *client)
+{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
+ ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
+ ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+
+ i2c_detach_client(client);
+ kfree(ks);
+ kfree(client);
+
+ dprintk("ks0127: detach\n");
+ return 0;
+}
+
+
+static int __devinit ks0127_init_module(void)
+{
+ init_reg_defaults();
+ i2c_add_driver(&i2c_driver_ks0127);
+ return 0;
+}
+
+static void __devexit ks0127_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_ks0127);
+}
+
+
+module_init(ks0127_init_module);
+module_exit(ks0127_cleanup_module);
diff --git a/drivers/media/video/ks0127.h b/drivers/media/video/ks0127.h
new file mode 100644
index 00000000000..1ec578833ae
--- /dev/null
+++ b/drivers/media/video/ks0127.h
@@ -0,0 +1,53 @@
+/*
+ * Video Capture Driver ( Video for Linux 1/2 )
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KS0127_H
+#define KS0127_H
+
+#include <linux/videodev.h>
+
+/* input channels */
+#define KS_INPUT_COMPOSITE_1 0
+#define KS_INPUT_COMPOSITE_2 1
+#define KS_INPUT_COMPOSITE_3 2
+#define KS_INPUT_COMPOSITE_4 4
+#define KS_INPUT_COMPOSITE_5 5
+#define KS_INPUT_COMPOSITE_6 6
+
+#define KS_INPUT_SVIDEO_1 8
+#define KS_INPUT_SVIDEO_2 9
+#define KS_INPUT_SVIDEO_3 10
+
+#define KS_INPUT_YUV656 15
+#define KS_INPUT_COUNT 10
+
+/* output channels */
+#define KS_OUTPUT_YUV656E 0
+#define KS_OUTPUT_EXV 1
+
+/* video standards */
+#define KS_STD_NTSC_N 112 /* 50 Hz NTSC */
+#define KS_STD_PAL_M 113 /* 60 Hz PAL */
+
+#endif /* KS0127_H */
+
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 850bee97090..e278753f8f2 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -26,12 +26,12 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
@@ -1682,13 +1682,13 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
static void meye_vm_open(struct vm_area_struct *vma)
{
- int idx = (int)vma->vm_private_data;
+ long idx = (long)vma->vm_private_data;
meye.vma_use_count[idx]++;
}
static void meye_vm_close(struct vm_area_struct *vma)
{
- int idx = (int)vma->vm_private_data;
+ long idx = (long)vma->vm_private_data;
meye.vma_use_count[idx]--;
}
@@ -1881,7 +1881,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
meye.mchip_irq = pcidev->irq;
if (request_irq(meye.mchip_irq, meye_irq,
- SA_INTERRUPT | SA_SHIRQ, "meye", meye_irq)) {
+ IRQF_DISABLED | IRQF_SHARED, "meye", meye_irq)) {
printk(KERN_ERR "meye: request_irq failed\n");
goto outreqirq;
}
diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h
index 0d09a0e3803..ea107cb5c84 100644
--- a/drivers/media/video/meye.h
+++ b/drivers/media/video/meye.h
@@ -36,7 +36,6 @@
#define MEYE_DRIVER_VERSION __stringify(MEYE_DRIVER_MAJORVERSION) "." \
__stringify(MEYE_DRIVER_MINORVERSION)
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/kfifo.h>
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index b806999d6e0..56246b8578f 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -362,7 +362,7 @@ int msp_sleep(struct msp_state *state, int timeout)
}
/* ------------------------------------------------------------------------ */
-
+#ifdef CONFIG_VIDEO_V4L1
static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
{
if (rxsubchans == V4L2_TUNER_SUB_MONO)
@@ -384,67 +384,7 @@ static int msp_mode_v4l1_to_v4l2(int mode)
return V4L2_TUNER_MODE_LANG1;
return V4L2_TUNER_MODE_MONO;
}
-
-static struct v4l2_queryctrl msp_qctrl_std[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-
-static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
- {
- .id = V4L2_CID_AUDIO_BALANCE,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BASS,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_TREBLE,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_LOUDNESS,
- .name = "Loudness",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-
+#endif
static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
@@ -570,6 +510,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
+#ifdef CONFIG_VIDEO_V4L1
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
@@ -638,6 +579,12 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
case VIDIOCSFREQ:
+ {
+ /* new channel -- kick audio carrier scan */
+ msp_wake_thread(client);
+ break;
+ }
+#endif
case VIDIOC_S_FREQUENCY:
{
/* new channel -- kick audio carrier scan */
@@ -674,22 +621,31 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
int sc1_out = rt->output & 0xf;
int sc2_out = (rt->output >> 4) & 0xf;
u16 val, reg;
+ int i;
+ int extern_input = 1;
if (state->routing.input == rt->input &&
state->routing.output == rt->output)
break;
state->routing = *rt;
+ /* check if the tuner input is used */
+ for (i = 0; i < 5; i++) {
+ if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+ extern_input = 0;
+ }
+ if (extern_input)
+ state->mode = MSP_MODE_EXTERN;
+ else
+ state->mode = MSP_MODE_AM_DETECT;
msp_set_scart(client, sc_in, 0);
msp_set_scart(client, sc1_out, 1);
msp_set_scart(client, sc2_out, 2);
msp_set_audmode(client);
reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
val = msp_read_dem(client, reg);
- if (tuner != ((val >> 8) & 1)) {
- msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
- /* wake thread when a new tuner input is chosen */
- msp_wake_thread(client);
- }
+ msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+ /* wake thread when a new input is chosen */
+ msp_wake_thread(client);
break;
}
@@ -744,21 +700,25 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
- if (qc->id && qc->id == msp_qctrl_std[i].id) {
- memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
- return 0;
- }
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
if (!state->has_sound_processing)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
- if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
- memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
}
case VIDIOC_G_CTRL:
@@ -794,7 +754,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
case MSP_MODE_EXTERN: p = "External input"; break;
default: p = "unknown"; break;
}
- if (state->opmode == OPMODE_MANUAL) {
+ if (state->mode == MSP_MODE_EXTERN) {
+ v4l_info(client, "Mode: %s\n", p);
+ } else if (state->opmode == OPMODE_MANUAL) {
v4l_info(client, "Mode: %s (%s%s)\n", p,
(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
index 4e451049013..545e4ac094f 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/video/msp3400-driver.h
@@ -90,8 +90,8 @@ struct msp_state {
/* thread */
struct task_struct *kthread;
wait_queue_head_t wq;
- int restart:1;
- int watch_stereo:1;
+ unsigned int restart:1;
+ unsigned int watch_stereo:1;
};
/* msp3400-driver.c */
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 633a1021378..ed02ff81138 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -244,19 +244,21 @@ static void msp3400c_set_audmode(struct i2c_client *client)
the hardware does not support SAP. So the rxsubchans combination
of STEREO | LANG2 does not occur. */
- /* switch to mono if only mono is available */
- if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
- audmode = V4L2_TUNER_MODE_MONO;
- /* if bilingual */
- else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
- /* and mono or stereo, then fallback to lang1 */
- if (audmode == V4L2_TUNER_MODE_MONO ||
- audmode == V4L2_TUNER_MODE_STEREO)
- audmode = V4L2_TUNER_MODE_LANG1;
+ if (state->mode != MSP_MODE_EXTERN) {
+ /* switch to mono if only mono is available */
+ if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
+ audmode = V4L2_TUNER_MODE_MONO;
+ /* if bilingual */
+ else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
+ /* and mono or stereo, then fallback to lang1 */
+ if (audmode == V4L2_TUNER_MODE_MONO ||
+ audmode == V4L2_TUNER_MODE_STEREO)
+ audmode = V4L2_TUNER_MODE_LANG1;
+ }
+ /* if stereo, and audmode is not mono, then switch to stereo */
+ else if (audmode != V4L2_TUNER_MODE_MONO)
+ audmode = V4L2_TUNER_MODE_STEREO;
}
- /* if stereo, and audmode is not mono, then switch to stereo */
- else if (audmode != V4L2_TUNER_MODE_MONO)
- audmode = V4L2_TUNER_MODE_STEREO;
/* switch demodulator */
switch (state->mode) {
@@ -481,6 +483,7 @@ int msp3400c_thread(void *data)
/* no carrier scan, just unmute */
v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
state->scan_in_progress = 0;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp_set_audio(client);
continue;
}
@@ -947,13 +950,21 @@ int msp34xxg_thread(void *data)
if (kthread_should_stop())
break;
+ if (state->mode == MSP_MODE_EXTERN) {
+ /* no carrier scan needed, just unmute */
+ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+ state->scan_in_progress = 0;
+ msp_set_audio(client);
+ continue;
+ }
+
/* setup the chip*/
msp34xxg_reset(client);
state->std = state->radio ? 0x40 : msp_standard;
- if (state->std != 1)
- goto unmute;
/* start autodetect */
msp_write_dem(client, 0x20, state->std);
+ if (state->std != 1)
+ goto unmute;
/* watch autodetect */
v4l_dbg(1, msp_debug, client, "started autodetect, waiting for result\n");
@@ -978,6 +989,11 @@ int msp34xxg_thread(void *data)
v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
msp_standard_std_name(state->std), state->std);
+ if (state->std == 9) {
+ /* AM NICAM mode */
+ msp_write_dsp(client, 0x0e, 0x7c00);
+ }
+
/* unmute: dispatch sound to scart output, set scart volume */
msp_set_audio(client);
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index fdc8e3f1393..5d8cd283fcd 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -35,7 +35,6 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
@@ -302,10 +301,11 @@ static struct symbolic_list senlist[] = {
static struct symbolic_list urb_errlist[] = {
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Stalled (device not responding)" },
- { -EOVERFLOW, "Babble (bad cable?)" },
+ { -EOVERFLOW, "Babble (device sends too much data)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
- { -EILSEQ, "CRC/Timeout" },
- { -ETIMEDOUT, "NAK (device does not respond)" },
+ { -EILSEQ, "CRC/Timeout (bad cable?)" },
+ { -ETIME, "Device does not respond to token" },
+ { -ETIMEDOUT, "Device does not respond to command" },
{ -1, NULL }
};
@@ -3239,7 +3239,7 @@ ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
- int nextf;
+ int nextf;
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
@@ -3405,7 +3405,7 @@ eof:
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
- int nextf;
+ int nextf;
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 12b3d51e1c3..68b082bcee1 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -3,6 +3,7 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index d9e3cada52f..3484e36b680 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -40,6 +40,7 @@
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 09835ca098b..5d681fa8bcb 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -30,6 +30,7 @@
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
@@ -804,7 +805,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file,
struct video_picture *p = arg;
if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
- return -EINVAL;
+ return -EINVAL;
pd->picture= *p;
/*
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
new file mode 100644
index 00000000000..7e727fe14b3
--- /dev/null
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -0,0 +1,62 @@
+config VIDEO_PVRUSB2
+ tristate "Hauppauge WinTV-PVR USB2 support"
+ depends on VIDEO_V4L2 && USB && I2C && EXPERIMENTAL
+ select FW_LOADER
+ select VIDEO_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+ select VIDEO_SAA711X
+ select VIDEO_MSP3400
+ ---help---
+ This is a video4linux driver for Conexant 23416 based
+ usb2 personal video recorder devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called pvrusb2
+
+config VIDEO_PVRUSB2_24XXX
+ bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
+ depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+ select VIDEO_CX25840
+ select VIDEO_WM8775
+ ---help---
+ This option enables inclusion of additional logic to operate
+ newer WinTV-PVR USB2 devices whose model number is of the
+ form "24xxx" (leading prefix of "24" followed by 3 digits).
+ To see if you may need this option, examine the white
+ sticker on the underside of your device. Enabling this
+ option will not harm support for older devices, however it
+ is a separate option because of the experimental nature of
+ this new feature.
+
+ If you are in doubt, say N.
+
+ Note: This feature is _very_ experimental. You have been
+ warned.
+
+config VIDEO_PVRUSB2_SYSFS
+ bool "pvrusb2 sysfs support (EXPERIMENTAL)"
+ default y
+ depends on VIDEO_PVRUSB2 && SYSFS && EXPERIMENTAL
+ ---help---
+ This option enables the operation of a sysfs based
+ interface for query and control of the pvrusb2 driver.
+
+ This is not generally needed for v4l applications,
+ although certain applications are optimized to take
+ advantage of this feature.
+
+ If you are in doubt, say Y.
+
+ Note: This feature is experimental and subject to change.
+
+config VIDEO_PVRUSB2_DEBUGIFC
+ bool "pvrusb2 debug interface"
+ depends on VIDEO_PVRUSB2_SYSFS
+ ---help---
+ This option enables the inclusion of a debug interface
+ in the pvrusb2 driver, hosted through sysfs.
+
+ You do not need to select this option unless you plan
+ on debugging the driver or performing a manual firmware
+ extraction.
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
new file mode 100644
index 00000000000..02e414210da
--- /dev/null
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -0,0 +1,18 @@
+obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
+obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+
+obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
+ pvrusb2-cx2584x-v4l.o \
+ pvrusb2-wm8775.o
+
+pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
+ pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
+ pvrusb2-encoder.o pvrusb2-video-v4l.o \
+ pvrusb2-eeprom.o pvrusb2-tuner.o \
+ pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
+ pvrusb2-ctrl.o pvrusb2-std.o \
+ pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
+ $(obj-pvrusb2-24xxx-y) \
+ $(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
+
+obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.c b/drivers/media/video/pvrusb2/pvrusb2-audio.c
new file mode 100644
index 00000000000..9846c464ec8
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.c
@@ -0,0 +1,204 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "pvrusb2-audio.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/msp3400.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_msp3400_handler {
+ struct pvr2_hdw *hdw;
+ struct pvr2_i2c_client *client;
+ struct pvr2_i2c_handler i2c_handler;
+ struct pvr2_audio_stat astat;
+ unsigned long stale_mask;
+};
+
+
+/* This function selects the correct audio input source */
+static void set_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ struct v4l2_routing route;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
+
+ if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+ struct v4l2_tuner vt;
+ memset(&vt,0,sizeof(vt));
+ vt.audmode = hdw->audiomode_val;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
+ }
+
+ route.input = MSP_INPUT_DEFAULT;
+ route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
+ switch (hdw->input_val) {
+ case PVR2_CVAL_INPUT_TV:
+ break;
+ case PVR2_CVAL_INPUT_RADIO:
+ /* Assume that msp34xx also handle FM decoding, in which case
+ we're still using the tuner. */
+ /* HV: actually it is more likely to be the SCART2 input if
+ the ivtv experience is any indication. */
+ route.input = MSP_INPUT(MSP_IN_SCART2, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+ break;
+ case PVR2_CVAL_INPUT_SVIDEO:
+ case PVR2_CVAL_INPUT_COMPOSITE:
+ /* SCART 1 input */
+ route.input = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
+ MSP_DSP_IN_SCART, MSP_DSP_IN_SCART);
+ break;
+ }
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_stereo(struct pvr2_msp3400_handler *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return (hdw->input_dirty ||
+ hdw->audiomode_dirty);
+}
+
+
+struct pvr2_msp3400_ops {
+ void (*update)(struct pvr2_msp3400_handler *);
+ int (*check)(struct pvr2_msp3400_handler *);
+};
+
+
+static const struct pvr2_msp3400_ops msp3400_ops[] = {
+ { .update = set_stereo, .check = check_stereo},
+};
+
+
+static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (msp3400_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
+}
+
+
+static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ msp3400_ops[idx].update(ctxt);
+ }
+}
+
+
+/* This reads back the current signal type */
+static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
+{
+ struct v4l2_tuner vt;
+ int stat;
+
+ memset(&vt,0,sizeof(vt));
+ stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+ if (stat < 0) return stat;
+
+ ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
+ ctxt->hdw->flag_bilingual =
+ (vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
+ return 0;
+}
+
+
+static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
+{
+ ctxt->client->handler = NULL;
+ ctxt->hdw->audio_stat = NULL;
+ kfree(ctxt);
+}
+
+
+static unsigned int pvr2_msp3400_describe(struct pvr2_msp3400_handler *ctxt,
+ char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-audio v4l2");
+}
+
+
+const static struct pvr2_i2c_handler_functions msp3400_funcs = {
+ .detach = (void (*)(void *))pvr2_msp3400_detach,
+ .check = (int (*)(void *))msp3400_check,
+ .update = (void (*)(void *))msp3400_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_msp3400_describe,
+};
+
+
+int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+ struct pvr2_msp3400_handler *ctxt;
+ if (hdw->audio_stat) return 0;
+ if (cp->handler) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->i2c_handler.func_data = ctxt;
+ ctxt->i2c_handler.func_table = &msp3400_funcs;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ ctxt->astat.ctxt = ctxt;
+ ctxt->astat.status = (int (*)(void *))get_audio_status;
+ ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
+ ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
+ sizeof(msp3400_ops[0]))) - 1;
+ cp->handler = &ctxt->i2c_handler;
+ hdw->audio_stat = &ctxt->astat;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-audio.h b/drivers/media/video/pvrusb2/pvrusb2-audio.h
new file mode 100644
index 00000000000..536339b6884
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-audio.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_AUDIO_H
+#define __PVRUSB2_AUDIO_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_msp3400_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_AUDIO_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
new file mode 100644
index 00000000000..f129f316d20
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -0,0 +1,230 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-context.h"
+#include "pvrusb2-io.h"
+#include "pvrusb2-ioread.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+
+
+static void pvr2_context_destroy(struct pvr2_context *mp)
+{
+ if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+ pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
+ flush_workqueue(mp->workqueue);
+ destroy_workqueue(mp->workqueue);
+ kfree(mp);
+}
+
+
+static void pvr2_context_trigger_poll(struct pvr2_context *mp)
+{
+ queue_work(mp->workqueue,&mp->workpoll);
+}
+
+
+static void pvr2_context_poll(struct pvr2_context *mp)
+{
+ pvr2_context_enter(mp); do {
+ pvr2_hdw_poll(mp->hdw);
+ } while (0); pvr2_context_exit(mp);
+}
+
+
+static void pvr2_context_setup(struct pvr2_context *mp)
+{
+ pvr2_context_enter(mp); do {
+ if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+ pvr2_hdw_setup(mp->hdw);
+ pvr2_hdw_setup_poll_trigger(
+ mp->hdw,
+ (void (*)(void *))pvr2_context_trigger_poll,
+ mp);
+ if (!pvr2_hdw_dev_ok(mp->hdw)) break;
+ if (!pvr2_hdw_init_ok(mp->hdw)) break;
+ mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
+ if (mp->setup_func) {
+ mp->setup_func(mp);
+ }
+ } while (0); pvr2_context_exit(mp);
+}
+
+
+struct pvr2_context *pvr2_context_create(
+ struct usb_interface *intf,
+ const struct usb_device_id *devid,
+ void (*setup_func)(struct pvr2_context *))
+{
+ struct pvr2_context *mp = NULL;
+ mp = kmalloc(sizeof(*mp),GFP_KERNEL);
+ if (!mp) goto done;
+ memset(mp,0,sizeof(*mp));
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
+ mp->setup_func = setup_func;
+ mutex_init(&mp->mutex);
+ mp->hdw = pvr2_hdw_create(intf,devid);
+ if (!mp->hdw) {
+ pvr2_context_destroy(mp);
+ mp = NULL;
+ goto done;
+ }
+
+ mp->workqueue = create_singlethread_workqueue("pvrusb2");
+ INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp);
+ INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp);
+ queue_work(mp->workqueue,&mp->workinit);
+ done:
+ return mp;
+}
+
+
+void pvr2_context_enter(struct pvr2_context *mp)
+{
+ mutex_lock(&mp->mutex);
+ pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp);
+}
+
+
+void pvr2_context_exit(struct pvr2_context *mp)
+{
+ int destroy_flag = 0;
+ if (!(mp->mc_first || !mp->disconnect_flag)) {
+ destroy_flag = !0;
+ }
+ pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp);
+ mutex_unlock(&mp->mutex);
+ if (destroy_flag) pvr2_context_destroy(mp);
+}
+
+
+static void pvr2_context_run_checks(struct pvr2_context *mp)
+{
+ struct pvr2_channel *ch1,*ch2;
+ for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+ ch2 = ch1->mc_next;
+ if (ch1->check_func) {
+ ch1->check_func(ch1);
+ }
+ }
+}
+
+
+void pvr2_context_disconnect(struct pvr2_context *mp)
+{
+ pvr2_context_enter(mp); do {
+ pvr2_hdw_disconnect(mp->hdw);
+ mp->disconnect_flag = !0;
+ pvr2_context_run_checks(mp);
+ } while (0); pvr2_context_exit(mp);
+}
+
+
+void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
+{
+ cp->hdw = mp->hdw;
+ cp->mc_head = mp;
+ cp->mc_next = NULL;
+ cp->mc_prev = mp->mc_last;
+ if (mp->mc_last) {
+ mp->mc_last->mc_next = cp;
+ } else {
+ mp->mc_first = cp;
+ }
+ mp->mc_last = cp;
+}
+
+
+static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
+{
+ if (!cp->stream) return;
+ pvr2_stream_kill(cp->stream->stream);
+ cp->stream->user = NULL;
+ cp->stream = NULL;
+}
+
+
+void pvr2_channel_done(struct pvr2_channel *cp)
+{
+ struct pvr2_context *mp = cp->mc_head;
+ pvr2_channel_disclaim_stream(cp);
+ if (cp->mc_next) {
+ cp->mc_next->mc_prev = cp->mc_prev;
+ } else {
+ mp->mc_last = cp->mc_prev;
+ }
+ if (cp->mc_prev) {
+ cp->mc_prev->mc_next = cp->mc_next;
+ } else {
+ mp->mc_first = cp->mc_next;
+ }
+ cp->hdw = NULL;
+}
+
+
+int pvr2_channel_claim_stream(struct pvr2_channel *cp,
+ struct pvr2_context_stream *sp)
+{
+ int code = 0;
+ pvr2_context_enter(cp->mc_head); do {
+ if (sp == cp->stream) break;
+ if (sp->user) {
+ code = -EBUSY;
+ break;
+ }
+ pvr2_channel_disclaim_stream(cp);
+ if (!sp) break;
+ sp->user = cp;
+ cp->stream = sp;
+ } while (0); pvr2_context_exit(cp->mc_head);
+ return code;
+}
+
+
+// This is the marker for the real beginning of a legitimate mpeg2 stream.
+static char stream_sync_key[] = {
+ 0x00, 0x00, 0x01, 0xba,
+};
+
+struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
+ struct pvr2_context_stream *sp)
+{
+ struct pvr2_ioread *cp;
+ cp = pvr2_ioread_create();
+ if (!cp) return NULL;
+ pvr2_ioread_setup(cp,sp->stream);
+ pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
+ return cp;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
new file mode 100644
index 00000000000..6327fa1f7e4
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -0,0 +1,92 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_BASE_H
+#define __PVRUSB2_BASE_H
+
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+
+struct pvr2_hdw; /* hardware interface - defined elsewhere */
+struct pvr2_stream; /* stream interface - defined elsewhere */
+
+struct pvr2_context; /* All central state */
+struct pvr2_channel; /* One I/O pathway to a user */
+struct pvr2_context_stream; /* Wrapper for a stream */
+struct pvr2_crit_reg; /* Critical region pointer */
+struct pvr2_ioread; /* Low level stream structure */
+
+struct pvr2_context_stream {
+ struct pvr2_channel *user;
+ struct pvr2_stream *stream;
+};
+
+struct pvr2_context {
+ struct pvr2_channel *mc_first;
+ struct pvr2_channel *mc_last;
+ struct pvr2_hdw *hdw;
+ struct pvr2_context_stream video_stream;
+ struct mutex mutex;
+ int disconnect_flag;
+
+ /* Called after pvr2_context initialization is complete */
+ void (*setup_func)(struct pvr2_context *);
+
+ /* Work queue overhead for out-of-line processing */
+ struct workqueue_struct *workqueue;
+ struct work_struct workinit;
+ struct work_struct workpoll;
+};
+
+struct pvr2_channel {
+ struct pvr2_context *mc_head;
+ struct pvr2_channel *mc_next;
+ struct pvr2_channel *mc_prev;
+ struct pvr2_context_stream *stream;
+ struct pvr2_hdw *hdw;
+ void (*check_func)(struct pvr2_channel *);
+};
+
+void pvr2_context_enter(struct pvr2_context *);
+void pvr2_context_exit(struct pvr2_context *);
+
+struct pvr2_context *pvr2_context_create(struct usb_interface *intf,
+ const struct usb_device_id *devid,
+ void (*setup_func)(struct pvr2_context *));
+void pvr2_context_disconnect(struct pvr2_context *);
+
+void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
+void pvr2_channel_done(struct pvr2_channel *);
+int pvr2_channel_claim_stream(struct pvr2_channel *,
+ struct pvr2_context_stream *);
+struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
+ struct pvr2_context_stream *);
+
+
+#endif /* __PVRUSB2_CONTEXT_H */
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
new file mode 100644
index 00000000000..fb6198f1df9
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -0,0 +1,593 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-ctrl.h"
+#include "pvrusb2-hdw-internal.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
+{
+ return pvr2_ctrl_set_mask_value(cptr,~0,val);
+}
+
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
+{
+ int ret = 0;
+ if (!cptr) return -EINVAL;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->set_value != 0) {
+ if (cptr->info->type == pvr2_ctl_bitmask) {
+ mask &= cptr->info->def.type_bitmask.valid_bits;
+ } else if (cptr->info->type == pvr2_ctl_int) {
+ if (val < cptr->info->def.type_int.min_value) {
+ break;
+ }
+ if (val > cptr->info->def.type_int.max_value) {
+ break;
+ }
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ if (val >= cptr->info->def.type_enum.count) {
+ break;
+ }
+ } else if (cptr->info->type != pvr2_ctl_bool) {
+ break;
+ }
+ ret = cptr->info->set_value(cptr,mask,val);
+ } else {
+ ret = -EPERM;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *cptr,int *valptr)
+{
+ int ret = 0;
+ if (!cptr) return -EINVAL;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ ret = cptr->info->get_value(cptr,valptr);
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return pvr2_ctl_int;
+ return cptr->info->type;
+}
+
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.max_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->def.type_int.min_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = cptr->info->default_value;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_enum) {
+ ret = cptr->info->def.type_enum.count;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *cptr)
+{
+ int ret = 0;
+ if (!cptr) return 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_bitmask) {
+ ret = cptr->info->def.type_bitmask.valid_bits;
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return NULL;
+ return cptr->info->name;
+}
+
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return NULL;
+ return cptr->info->desc;
+}
+
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
+ char *bptr,unsigned int bmax,
+ unsigned int *blen)
+{
+ int ret = -EINVAL;
+ if (!cptr) return 0;
+ *blen = 0;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_enum) {
+ const char **names;
+ names = cptr->info->def.type_enum.value_names;
+ if ((val >= 0) &&
+ (val < cptr->info->def.type_enum.count)) {
+ if (names[val]) {
+ *blen = scnprintf(
+ bptr,bmax,"%s",
+ names[val]);
+ } else {
+ *blen = 0;
+ }
+ ret = 0;
+ }
+ } else if (cptr->info->type == pvr2_ctl_bitmask) {
+ const char **names;
+ unsigned int idx;
+ int msk;
+ names = cptr->info->def.type_bitmask.bit_names;
+ val &= cptr->info->def.type_bitmask.valid_bits;
+ for (idx = 0, msk = 1; val; idx++, msk <<= 1) {
+ if (val & msk) {
+ *blen = scnprintf(bptr,bmax,"%s",
+ names[idx]);
+ ret = 0;
+ break;
+ }
+ }
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ return cptr->info->v4l_id;
+}
+
+
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
+{
+ unsigned int flags = 0;
+
+ if (cptr->info->get_v4lflags) {
+ flags = cptr->info->get_v4lflags(cptr);
+ }
+
+ if (cptr->info->set_value) {
+ flags &= ~V4L2_CTRL_FLAG_READ_ONLY;
+ } else {
+ flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ }
+
+ return flags;
+}
+
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ return cptr->info->set_value != 0;
+}
+
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *cptr)
+{
+ if (!cptr) return 0;
+ if (!cptr->info->val_to_sym) return 0;
+ if (!cptr->info->sym_to_val) return 0;
+ return !0;
+}
+
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *cptr,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len)
+{
+ if (!cptr) return -EINVAL;
+ if (!cptr->info->val_to_sym) return -EINVAL;
+ return cptr->info->val_to_sym(cptr,mask,val,buf,maxlen,len);
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *cptr,
+ const char *buf,unsigned int len,
+ int *maskptr,int *valptr)
+{
+ if (!cptr) return -EINVAL;
+ if (!cptr->info->sym_to_val) return -EINVAL;
+ return cptr->info->sym_to_val(cptr,buf,len,maskptr,valptr);
+}
+
+
+static unsigned int gen_bitmask_string(int msk,int val,int msk_only,
+ const char **names,
+ char *ptr,unsigned int len)
+{
+ unsigned int idx;
+ long sm,um;
+ int spcFl;
+ unsigned int uc,cnt;
+ const char *idStr;
+
+ spcFl = 0;
+ uc = 0;
+ um = 0;
+ for (idx = 0, sm = 1; msk; idx++, sm <<= 1) {
+ if (sm & msk) {
+ msk &= ~sm;
+ idStr = names[idx];
+ if (idStr) {
+ cnt = scnprintf(ptr,len,"%s%s%s",
+ (spcFl ? " " : ""),
+ (msk_only ? "" :
+ ((val & sm) ? "+" : "-")),
+ idStr);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ } else {
+ um |= sm;
+ }
+ }
+ }
+ if (um) {
+ if (msk_only) {
+ cnt = scnprintf(ptr,len,"%s0x%lx",
+ (spcFl ? " " : ""),
+ um);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ } else if (um & val) {
+ cnt = scnprintf(ptr,len,"%s+0x%lx",
+ (spcFl ? " " : ""),
+ um & val);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ } else if (um & ~val) {
+ cnt = scnprintf(ptr,len,"%s+0x%lx",
+ (spcFl ? " " : ""),
+ um & ~val);
+ ptr += cnt; len -= cnt; uc += cnt;
+ spcFl = !0;
+ }
+ }
+ return uc;
+}
+
+
+static const char *boolNames[] = {
+ "false",
+ "true",
+ "no",
+ "yes",
+};
+
+
+static int parse_token(const char *ptr,unsigned int len,
+ int *valptr,
+ const char **names,unsigned int namecnt)
+{
+ char buf[33];
+ unsigned int slen;
+ unsigned int idx;
+ int negfl;
+ char *p2;
+ *valptr = 0;
+ if (!names) namecnt = 0;
+ for (idx = 0; idx < namecnt; idx++) {
+ if (!names[idx]) continue;
+ slen = strlen(names[idx]);
+ if (slen != len) continue;
+ if (memcmp(names[idx],ptr,slen)) continue;
+ *valptr = idx;
+ return 0;
+ }
+ negfl = 0;
+ if ((*ptr == '-') || (*ptr == '+')) {
+ negfl = (*ptr == '-');
+ ptr++; len--;
+ }
+ if (len >= sizeof(buf)) return -EINVAL;
+ memcpy(buf,ptr,len);
+ buf[len] = 0;
+ *valptr = simple_strtol(buf,&p2,0);
+ if (negfl) *valptr = -(*valptr);
+ if (*p2) return -EINVAL;
+ return 1;
+}
+
+
+static int parse_mtoken(const char *ptr,unsigned int len,
+ int *valptr,
+ const char **names,int valid_bits)
+{
+ char buf[33];
+ unsigned int slen;
+ unsigned int idx;
+ char *p2;
+ int msk;
+ *valptr = 0;
+ for (idx = 0, msk = 1; valid_bits; idx++, msk <<= 1) {
+ if (!msk & valid_bits) continue;
+ valid_bits &= ~msk;
+ if (!names[idx]) continue;
+ slen = strlen(names[idx]);
+ if (slen != len) continue;
+ if (memcmp(names[idx],ptr,slen)) continue;
+ *valptr = msk;
+ return 0;
+ }
+ if (len >= sizeof(buf)) return -EINVAL;
+ memcpy(buf,ptr,len);
+ buf[len] = 0;
+ *valptr = simple_strtol(buf,&p2,0);
+ if (*p2) return -EINVAL;
+ return 0;
+}
+
+
+static int parse_tlist(const char *ptr,unsigned int len,
+ int *maskptr,int *valptr,
+ const char **names,int valid_bits)
+{
+ unsigned int cnt;
+ int mask,val,kv,mode,ret;
+ mask = 0;
+ val = 0;
+ ret = 0;
+ while (len) {
+ cnt = 0;
+ while ((cnt < len) &&
+ ((ptr[cnt] <= 32) ||
+ (ptr[cnt] >= 127))) cnt++;
+ ptr += cnt;
+ len -= cnt;
+ mode = 0;
+ if ((*ptr == '-') || (*ptr == '+')) {
+ mode = (*ptr == '-') ? -1 : 1;
+ ptr++;
+ len--;
+ }
+ cnt = 0;
+ while (cnt < len) {
+ if (ptr[cnt] <= 32) break;
+ if (ptr[cnt] >= 127) break;
+ cnt++;
+ }
+ if (!cnt) break;
+ if (parse_mtoken(ptr,cnt,&kv,names,valid_bits)) {
+ ret = -EINVAL;
+ break;
+ }
+ ptr += cnt;
+ len -= cnt;
+ switch (mode) {
+ case 0:
+ mask = valid_bits;
+ val |= kv;
+ break;
+ case -1:
+ mask |= kv;
+ val &= ~kv;
+ break;
+ case 1:
+ mask |= kv;
+ val |= kv;
+ break;
+ default:
+ break;
+ }
+ }
+ *maskptr = mask;
+ *valptr = val;
+ return ret;
+}
+
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
+ const char *ptr,unsigned int len,
+ int *maskptr,int *valptr)
+{
+ int ret = -EINVAL;
+ unsigned int cnt;
+
+ *maskptr = 0;
+ *valptr = 0;
+
+ cnt = 0;
+ while ((cnt < len) && ((ptr[cnt] <= 32) || (ptr[cnt] >= 127))) cnt++;
+ len -= cnt; ptr += cnt;
+ cnt = 0;
+ while ((cnt < len) && ((ptr[len-(cnt+1)] <= 32) ||
+ (ptr[len-(cnt+1)] >= 127))) cnt++;
+ len -= cnt;
+
+ if (!len) return -EINVAL;
+
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ if (cptr->info->type == pvr2_ctl_int) {
+ ret = parse_token(ptr,len,valptr,NULL,0);
+ if ((ret >= 0) &&
+ ((*valptr < cptr->info->def.type_int.min_value) ||
+ (*valptr > cptr->info->def.type_int.max_value))) {
+ ret = -ERANGE;
+ }
+ if (maskptr) *maskptr = ~0;
+ } else if (cptr->info->type == pvr2_ctl_bool) {
+ ret = parse_token(
+ ptr,len,valptr,boolNames,
+ sizeof(boolNames)/sizeof(boolNames[0]));
+ if (ret == 1) {
+ *valptr = *valptr ? !0 : 0;
+ } else if (ret == 0) {
+ *valptr = (*valptr & 1) ? !0 : 0;
+ }
+ if (maskptr) *maskptr = 1;
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ ret = parse_token(
+ ptr,len,valptr,
+ cptr->info->def.type_enum.value_names,
+ cptr->info->def.type_enum.count);
+ if ((ret >= 0) &&
+ ((*valptr < 0) ||
+ (*valptr >= cptr->info->def.type_enum.count))) {
+ ret = -ERANGE;
+ }
+ if (maskptr) *maskptr = ~0;
+ } else if (cptr->info->type == pvr2_ctl_bitmask) {
+ ret = parse_tlist(
+ ptr,len,maskptr,valptr,
+ cptr->info->def.type_bitmask.bit_names,
+ cptr->info->def.type_bitmask.valid_bits);
+ }
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len)
+{
+ int ret = -EINVAL;
+
+ *len = 0;
+ if (cptr->info->type == pvr2_ctl_int) {
+ *len = scnprintf(buf,maxlen,"%d",val);
+ ret = 0;
+ } else if (cptr->info->type == pvr2_ctl_bool) {
+ *len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
+ ret = 0;
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ const char **names;
+ names = cptr->info->def.type_enum.value_names;
+ if ((val >= 0) &&
+ (val < cptr->info->def.type_enum.count)) {
+ if (names[val]) {
+ *len = scnprintf(
+ buf,maxlen,"%s",
+ names[val]);
+ } else {
+ *len = 0;
+ }
+ ret = 0;
+ }
+ } else if (cptr->info->type == pvr2_ctl_bitmask) {
+ *len = gen_bitmask_string(
+ val & mask & cptr->info->def.type_bitmask.valid_bits,
+ ~0,!0,
+ cptr->info->def.type_bitmask.bit_names,
+ buf,maxlen);
+ }
+ return ret;
+}
+
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len)
+{
+ int ret;
+ LOCK_TAKE(cptr->hdw->big_lock); do {
+ ret = pvr2_ctrl_value_to_sym_internal(cptr,mask,val,
+ buf,maxlen,len);
+ } while(0); LOCK_GIVE(cptr->hdw->big_lock);
+ return ret;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
new file mode 100644
index 00000000000..c1680053cd6
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.h
@@ -0,0 +1,123 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_CTRL_H
+#define __PVRUSB2_CTRL_H
+
+struct pvr2_ctrl;
+
+enum pvr2_ctl_type {
+ pvr2_ctl_int = 0,
+ pvr2_ctl_enum = 1,
+ pvr2_ctl_bitmask = 2,
+ pvr2_ctl_bool = 3,
+};
+
+
+/* Set the given control. */
+int pvr2_ctrl_set_value(struct pvr2_ctrl *,int val);
+
+/* Set/clear specific bits of the given control. */
+int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *,int mask,int val);
+
+/* Get the current value of the given control. */
+int pvr2_ctrl_get_value(struct pvr2_ctrl *,int *valptr);
+
+/* Retrieve control's type */
+enum pvr2_ctl_type pvr2_ctrl_get_type(struct pvr2_ctrl *);
+
+/* Retrieve control's maximum value (int type) */
+int pvr2_ctrl_get_max(struct pvr2_ctrl *);
+
+/* Retrieve control's minimum value (int type) */
+int pvr2_ctrl_get_min(struct pvr2_ctrl *);
+
+/* Retrieve control's default value (any type) */
+int pvr2_ctrl_get_def(struct pvr2_ctrl *);
+
+/* Retrieve control's enumeration count (enum only) */
+int pvr2_ctrl_get_cnt(struct pvr2_ctrl *);
+
+/* Retrieve control's valid mask bits (bit mask only) */
+int pvr2_ctrl_get_mask(struct pvr2_ctrl *);
+
+/* Retrieve the control's name */
+const char *pvr2_ctrl_get_name(struct pvr2_ctrl *);
+
+/* Retrieve the control's desc */
+const char *pvr2_ctrl_get_desc(struct pvr2_ctrl *);
+
+/* Retrieve a control enumeration or bit mask value */
+int pvr2_ctrl_get_valname(struct pvr2_ctrl *,int,char *,unsigned int,
+ unsigned int *);
+
+/* Return true if control is writable */
+int pvr2_ctrl_is_writable(struct pvr2_ctrl *);
+
+/* Return V4L flags value for control (or zero if there is no v4l control
+ actually under this control) */
+unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *);
+
+/* Return V4L ID for this control or zero if none */
+int pvr2_ctrl_get_v4lid(struct pvr2_ctrl *);
+
+/* Return true if control has custom symbolic representation */
+int pvr2_ctrl_has_custom_symbols(struct pvr2_ctrl *);
+
+/* Convert a given mask/val to a custom symbolic value */
+int pvr2_ctrl_custom_value_to_sym(struct pvr2_ctrl *,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_custom_sym_to_value(struct pvr2_ctrl *,
+ const char *buf,unsigned int len,
+ int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value */
+int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len);
+
+/* Convert a symbolic value to a mask/value pair */
+int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *,
+ const char *buf,unsigned int len,
+ int *maskptr,int *valptr);
+
+/* Convert a given mask/val to a symbolic value - must already be
+ inside of critical region. */
+int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *,
+ int mask,int val,
+ char *buf,unsigned int maxlen,
+ unsigned int *len);
+
+#endif /* __PVRUSB2_CTRL_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
new file mode 100644
index 00000000000..c80c26be6e4
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -0,0 +1,279 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+
+ This source file is specifically designed to interface with the
+ cx2584x, in kernels 2.6.16 or newer.
+
+*/
+
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <media/cx25840.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_cx2584x {
+ struct pvr2_i2c_handler handler;
+ struct pvr2_decoder_ctrl ctrl;
+ struct pvr2_i2c_client *client;
+ struct pvr2_hdw *hdw;
+ unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ struct v4l2_routing route;
+ enum cx25840_video_input vid_input;
+ enum cx25840_audio_input aud_input;
+
+ memset(&route,0,sizeof(route));
+
+ switch(hdw->input_val) {
+ case PVR2_CVAL_INPUT_TV:
+ vid_input = CX25840_COMPOSITE7;
+ aud_input = CX25840_AUDIO8;
+ break;
+ case PVR2_CVAL_INPUT_COMPOSITE:
+ vid_input = CX25840_COMPOSITE3;
+ aud_input = CX25840_AUDIO_SERIAL;
+ break;
+ case PVR2_CVAL_INPUT_SVIDEO:
+ vid_input = CX25840_SVIDEO1;
+ aud_input = CX25840_AUDIO_SERIAL;
+ break;
+ case PVR2_CVAL_INPUT_RADIO:
+ default:
+ // Just set it to be composite input for now...
+ vid_input = CX25840_COMPOSITE3;
+ aud_input = CX25840_AUDIO_SERIAL;
+ break;
+ }
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_input vid=0x%x aud=0x%x",
+ vid_input,aud_input);
+ route.input = (u32)vid_input;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+ route.input = (u32)aud_input;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+ u32 val;
+ struct pvr2_hdw *hdw = ctxt->hdw;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx2584x set_audio %d",
+ hdw->srate_val);
+ switch (hdw->srate_val) {
+ default:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+ val = 48000;
+ break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+ val = 44100;
+ break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+ val = 32000;
+ break;
+ }
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_cx2584x_ops {
+ void (*update)(struct pvr2_v4l_cx2584x *);
+ int (*check)(struct pvr2_v4l_cx2584x *);
+};
+
+
+static const struct pvr2_v4l_cx2584x_ops decoder_ops[] = {
+ { .update = set_input, .check = check_input},
+ { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_cx2584x *ctxt)
+{
+ ctxt->client->handler = NULL;
+ ctxt->hdw->decoder_ctrl = NULL;
+ kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (decoder_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ decoder_ops[idx].update(ctxt);
+ }
+}
+
+
+static void decoder_enable(struct pvr2_v4l_cx2584x *ctxt,int fl)
+{
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_enable(%d)",fl);
+ pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+ int ret;
+ /* Attempt to query the decoder - let's see if it will answer */
+ struct v4l2_queryctrl qc;
+
+ memset(&qc,0,sizeof(qc));
+
+ qc.id = V4L2_CID_BRIGHTNESS;
+
+ ret = pvr2_i2c_client_cmd(cp,VIDIOC_QUERYCTRL,&qc);
+ return ret == 0; /* Return true if it answered */
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
+{
+ struct v4l2_tuner vt;
+ int ret;
+
+ memset(&vt,0,sizeof(vt));
+ ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+ if (ret < 0) return -EINVAL;
+ return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
+ char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-cx2584x-v4l");
+}
+
+
+static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
+{
+ int ret;
+ ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL);
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+ .detach = (void (*)(void *))decoder_detach,
+ .check = (int (*)(void *))decoder_check,
+ .update = (void (*)(void *))decoder_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
+ struct pvr2_i2c_client *cp)
+{
+ struct pvr2_v4l_cx2584x *ctxt;
+
+ if (hdw->decoder_ctrl) return 0;
+ if (cp->handler) return 0;
+ if (!decoder_detect(cp)) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->handler.func_data = ctxt;
+ ctxt->handler.func_table = &hfuncs;
+ ctxt->ctrl.ctxt = ctxt;
+ ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+ ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+ ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+ ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+ sizeof(decoder_ops[0]))) - 1;
+ hdw->decoder_ctrl = &ctxt->ctrl;
+ cp->handler = &ctxt->handler;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x cx2584x V4L2 handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
new file mode 100644
index 00000000000..54b2844e7a7
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_CX2584X_V4L_H
+#define __PVRUSB2_CX2584X_V4L_H
+
+/*
+
+ This module connects the pvrusb2 driver to the I2C chip level
+ driver which handles combined device audio & video processing.
+ This interface is used internally by the driver; higher level code
+ should only interact through the interface provided by
+ pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_CX2584X_V4L_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
new file mode 100644
index 00000000000..d95a8588e4f
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -0,0 +1,67 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_DEBUG_H
+#define __PVRUSB2_DEBUG_H
+
+extern int pvrusb2_debug;
+
+#define pvr2_trace(msk, fmt, arg...) do {if(msk & pvrusb2_debug) printk(KERN_INFO "pvrusb2: " fmt "\n", ##arg); } while (0)
+
+/* These are listed in *rough* order of decreasing usefulness and
+ increasing noise level. */
+#define PVR2_TRACE_INFO (1 << 0) // Normal messages
+#define PVR2_TRACE_ERROR_LEGS (1 << 1) // error messages
+#define PVR2_TRACE_TOLERANCE (1 << 2) // track tolerance-affected errors
+#define PVR2_TRACE_TRAP (1 << 3) // Trap & report misbehavior from app
+#define PVR2_TRACE_INIT (1 << 4) // misc initialization steps
+#define PVR2_TRACE_START_STOP (1 << 5) // Streaming start / stop
+#define PVR2_TRACE_CTL (1 << 6) // commit of control changes
+#define PVR2_TRACE_DEBUG (1 << 7) // Temporary debug code
+#define PVR2_TRACE_EEPROM (1 << 8) // eeprom parsing / report
+#define PVR2_TRACE_STRUCT (1 << 9) // internal struct creation
+#define PVR2_TRACE_OPEN_CLOSE (1 << 10) // application open / close
+#define PVR2_TRACE_CREG (1 << 11) // Main critical region entry / exit
+#define PVR2_TRACE_SYSFS (1 << 12) // Sysfs driven I/O
+#define PVR2_TRACE_FIRMWARE (1 << 13) // firmware upload actions
+#define PVR2_TRACE_CHIPS (1 << 14) // chip broadcast operation
+#define PVR2_TRACE_I2C (1 << 15) // I2C related stuff
+#define PVR2_TRACE_I2C_CMD (1 << 16) // Software commands to I2C modules
+#define PVR2_TRACE_I2C_CORE (1 << 17) // I2C core debugging
+#define PVR2_TRACE_I2C_TRAF (1 << 18) // I2C traffic through the adapter
+#define PVR2_TRACE_V4LIOCTL (1 << 19) // v4l ioctl details
+#define PVR2_TRACE_ENCODER (1 << 20) // mpeg2 encoder operation
+#define PVR2_TRACE_BUF_POOL (1 << 21) // Track buffer pool management
+#define PVR2_TRACE_BUF_FLOW (1 << 22) // Track buffer flow in system
+#define PVR2_TRACE_DATA_FLOW (1 << 23) // Track data flow
+#define PVR2_TRACE_DEBUGIFC (1 << 24) // Debug interface actions
+#define PVR2_TRACE_GPIO (1 << 25) // GPIO state bit changes
+
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
new file mode 100644
index 00000000000..f985f00d885
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -0,0 +1,478 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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/string.h>
+#include <linux/slab.h>
+#include "pvrusb2-debugifc.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-i2c-core.h"
+
+struct debugifc_mask_item {
+ const char *name;
+ unsigned long msk;
+};
+
+static struct debugifc_mask_item mask_items[] = {
+ {"ENC_FIRMWARE",(1<<PVR2_SUBSYS_B_ENC_FIRMWARE)},
+ {"ENC_CFG",(1<<PVR2_SUBSYS_B_ENC_CFG)},
+ {"DIG_RUN",(1<<PVR2_SUBSYS_B_DIGITIZER_RUN)},
+ {"USB_RUN",(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)},
+ {"ENC_RUN",(1<<PVR2_SUBSYS_B_ENC_RUN)},
+};
+
+
+static unsigned int debugifc_count_whitespace(const char *buf,
+ unsigned int count)
+{
+ unsigned int scnt;
+ char ch;
+
+ for (scnt = 0; scnt < count; scnt++) {
+ ch = buf[scnt];
+ if (ch == ' ') continue;
+ if (ch == '\t') continue;
+ if (ch == '\n') continue;
+ break;
+ }
+ return scnt;
+}
+
+
+static unsigned int debugifc_count_nonwhitespace(const char *buf,
+ unsigned int count)
+{
+ unsigned int scnt;
+ char ch;
+
+ for (scnt = 0; scnt < count; scnt++) {
+ ch = buf[scnt];
+ if (ch == ' ') break;
+ if (ch == '\t') break;
+ if (ch == '\n') break;
+ }
+ return scnt;
+}
+
+
+static unsigned int debugifc_isolate_word(const char *buf,unsigned int count,
+ const char **wstrPtr,
+ unsigned int *wlenPtr)
+{
+ const char *wptr;
+ unsigned int consume_cnt = 0;
+ unsigned int wlen;
+ unsigned int scnt;
+
+ wptr = NULL;
+ wlen = 0;
+ scnt = debugifc_count_whitespace(buf,count);
+ consume_cnt += scnt; count -= scnt; buf += scnt;
+ if (!count) goto done;
+
+ scnt = debugifc_count_nonwhitespace(buf,count);
+ if (!scnt) goto done;
+ wptr = buf;
+ wlen = scnt;
+ consume_cnt += scnt; count -= scnt; buf += scnt;
+
+ done:
+ *wstrPtr = wptr;
+ *wlenPtr = wlen;
+ return consume_cnt;
+}
+
+
+static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
+ u32 *num_ptr)
+{
+ u32 result = 0;
+ u32 val;
+ int ch;
+ int radix = 10;
+ if ((count >= 2) && (buf[0] == '0') &&
+ ((buf[1] == 'x') || (buf[1] == 'X'))) {
+ radix = 16;
+ count -= 2;
+ buf += 2;
+ } else if ((count >= 1) && (buf[0] == '0')) {
+ radix = 8;
+ }
+
+ while (count--) {
+ ch = *buf++;
+ if ((ch >= '0') && (ch <= '9')) {
+ val = ch - '0';
+ } else if ((ch >= 'a') && (ch <= 'f')) {
+ val = ch - 'a' + 10;
+ } else if ((ch >= 'A') && (ch <= 'F')) {
+ val = ch - 'A' + 10;
+ } else {
+ return -EINVAL;
+ }
+ if (val >= radix) return -EINVAL;
+ result *= radix;
+ result += val;
+ }
+ *num_ptr = result;
+ return 0;
+}
+
+
+static int debugifc_match_keyword(const char *buf,unsigned int count,
+ const char *keyword)
+{
+ unsigned int kl;
+ if (!keyword) return 0;
+ kl = strlen(keyword);
+ if (kl != count) return 0;
+ return !memcmp(buf,keyword,kl);
+}
+
+
+static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
+{
+ struct debugifc_mask_item *mip;
+ unsigned int idx;
+ for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ mip = mask_items + idx;
+ if (debugifc_match_keyword(buf,count,mip->name)) {
+ return mip->msk;
+ }
+ }
+ return 0;
+}
+
+
+static int debugifc_print_mask(char *buf,unsigned int sz,
+ unsigned long msk,unsigned long val)
+{
+ struct debugifc_mask_item *mip;
+ unsigned int idx;
+ int bcnt = 0;
+ int ccnt;
+ for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
+ mip = mask_items + idx;
+ if (!(mip->msk & msk)) continue;
+ ccnt = scnprintf(buf,sz,"%s%c%s",
+ (bcnt ? " " : ""),
+ ((mip->msk & val) ? '+' : '-'),
+ mip->name);
+ sz -= ccnt;
+ buf += ccnt;
+ bcnt += ccnt;
+ }
+ return bcnt;
+}
+
+static unsigned int debugifc_parse_subsys_mask(const char *buf,
+ unsigned int count,
+ unsigned long *mskPtr,
+ unsigned long *valPtr)
+{
+ const char *wptr;
+ unsigned int consume_cnt = 0;
+ unsigned int scnt;
+ unsigned int wlen;
+ int mode;
+ unsigned long m1,msk,val;
+
+ msk = 0;
+ val = 0;
+
+ while (count) {
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (!scnt) break;
+ consume_cnt += scnt; count -= scnt; buf += scnt;
+ if (!wptr) break;
+
+ mode = 0;
+ if (wlen) switch (wptr[0]) {
+ case '+':
+ wptr++;
+ wlen--;
+ break;
+ case '-':
+ mode = 1;
+ wptr++;
+ wlen--;
+ break;
+ }
+ if (!wlen) continue;
+ m1 = debugifc_find_mask(wptr,wlen);
+ if (!m1) break;
+ msk |= m1;
+ if (!mode) val |= m1;
+ }
+ *mskPtr = msk;
+ *valPtr = val;
+ return consume_cnt;
+}
+
+
+int pvr2_debugifc_print_info(struct pvr2_hdw *hdw,char *buf,unsigned int acnt)
+{
+ int bcnt = 0;
+ int ccnt;
+ struct pvr2_hdw_debug_info dbg;
+
+ pvr2_hdw_get_debug_info(hdw,&dbg);
+
+ ccnt = scnprintf(buf,acnt,"big lock %s; ctl lock %s",
+ (dbg.big_lock_held ? "held" : "free"),
+ (dbg.ctl_lock_held ? "held" : "free"));
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ if (dbg.ctl_lock_held) {
+ ccnt = scnprintf(buf,acnt,"; cmd_state=%d cmd_code=%d"
+ " cmd_wlen=%d cmd_rlen=%d"
+ " wpend=%d rpend=%d tmout=%d rstatus=%d"
+ " wstatus=%d",
+ dbg.cmd_debug_state,dbg.cmd_code,
+ dbg.cmd_debug_write_len,
+ dbg.cmd_debug_read_len,
+ dbg.cmd_debug_write_pend,
+ dbg.cmd_debug_read_pend,
+ dbg.cmd_debug_timeout,
+ dbg.cmd_debug_rstatus,
+ dbg.cmd_debug_wstatus);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ }
+ ccnt = scnprintf(buf,acnt,"\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(
+ buf,acnt,"driver flags: %s %s %s\n",
+ (dbg.flag_init_ok ? "initialized" : "uninitialized"),
+ (dbg.flag_ok ? "ok" : "fail"),
+ (dbg.flag_disconnected ? "disconnected" : "connected"));
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = debugifc_print_mask(buf,acnt,dbg.subsys_flags,dbg.subsys_flags);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = debugifc_print_mask(buf,acnt,~dbg.subsys_flags,dbg.subsys_flags);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ ccnt = scnprintf(buf,acnt,"Attached I2C modules:\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = pvr2_i2c_report(hdw,buf,acnt);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ return bcnt;
+}
+
+
+int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
+ char *buf,unsigned int acnt)
+{
+ int bcnt = 0;
+ int ccnt;
+ unsigned long msk;
+ int ret;
+ u32 gpio_dir,gpio_in,gpio_out;
+
+ ret = pvr2_hdw_is_hsm(hdw);
+ ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
+ (ret < 0 ? "FAIL" : (ret ? "high" : "full")));
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ gpio_dir = 0; gpio_in = 0; gpio_out = 0;
+ pvr2_hdw_gpio_get_dir(hdw,&gpio_dir);
+ pvr2_hdw_gpio_get_out(hdw,&gpio_out);
+ pvr2_hdw_gpio_get_in(hdw,&gpio_in);
+ ccnt = scnprintf(buf,acnt,"GPIO state: dir=0x%x in=0x%x out=0x%x\n",
+ gpio_dir,gpio_in,gpio_out);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ ccnt = scnprintf(buf,acnt,"Streaming is %s\n",
+ pvr2_hdw_get_streaming(hdw) ? "on" : "off");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ msk = pvr2_hdw_subsys_get(hdw);
+ ccnt = scnprintf(buf,acnt,"Subsystems enabled / configured: ");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"Subsystems disabled / unconfigured: ");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = debugifc_print_mask(buf,acnt,~msk,msk);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ msk = pvr2_hdw_subsys_stream_get(hdw);
+ ccnt = scnprintf(buf,acnt,"Subsystems stopped on stream shutdown: ");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = debugifc_print_mask(buf,acnt,msk,msk);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ ccnt = scnprintf(buf,acnt,"\n");
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ return bcnt;
+}
+
+
+static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
+ unsigned int count)
+{
+ const char *wptr;
+ unsigned int wlen;
+ unsigned int scnt;
+
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (!scnt) return 0;
+ count -= scnt; buf += scnt;
+ if (!wptr) return 0;
+
+ pvr2_trace(PVR2_TRACE_DEBUGIFC,"debugifc cmd: \"%.*s\"",wlen,wptr);
+ if (debugifc_match_keyword(wptr,wlen,"reset")) {
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (!scnt) return -EINVAL;
+ count -= scnt; buf += scnt;
+ if (!wptr) return -EINVAL;
+ if (debugifc_match_keyword(wptr,wlen,"cpu")) {
+ pvr2_hdw_cpureset_assert(hdw,!0);
+ pvr2_hdw_cpureset_assert(hdw,0);
+ return 0;
+ } else if (debugifc_match_keyword(wptr,wlen,"bus")) {
+ pvr2_hdw_device_reset(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"soft")) {
+ return pvr2_hdw_cmd_powerup(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"deep")) {
+ return pvr2_hdw_cmd_deep_reset(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"firmware")) {
+ return pvr2_upload_firmware2(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"decoder")) {
+ return pvr2_hdw_cmd_decoder_reset(hdw);
+ }
+ return -EINVAL;
+ } else if (debugifc_match_keyword(wptr,wlen,"subsys_flags")) {
+ unsigned long msk = 0;
+ unsigned long val = 0;
+ if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+ pvr2_trace(PVR2_TRACE_DEBUGIFC,
+ "debugifc parse error on subsys mask");
+ return -EINVAL;
+ }
+ pvr2_hdw_subsys_bit_chg(hdw,msk,val);
+ return 0;
+ } else if (debugifc_match_keyword(wptr,wlen,"stream_flags")) {
+ unsigned long msk = 0;
+ unsigned long val = 0;
+ if (debugifc_parse_subsys_mask(buf,count,&msk,&val) != count) {
+ pvr2_trace(PVR2_TRACE_DEBUGIFC,
+ "debugifc parse error on stream mask");
+ return -EINVAL;
+ }
+ pvr2_hdw_subsys_stream_bit_chg(hdw,msk,val);
+ return 0;
+ } else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (!scnt) return -EINVAL;
+ count -= scnt; buf += scnt;
+ if (!wptr) return -EINVAL;
+ if (debugifc_match_keyword(wptr,wlen,"fetch")) {
+ pvr2_hdw_cpufw_set_enabled(hdw,!0);
+ return 0;
+ } else if (debugifc_match_keyword(wptr,wlen,"done")) {
+ pvr2_hdw_cpufw_set_enabled(hdw,0);
+ return 0;
+ } else {
+ return -EINVAL;
+ }
+ } else if (debugifc_match_keyword(wptr,wlen,"gpio")) {
+ int dir_fl = 0;
+ int ret;
+ u32 msk,val;
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (!scnt) return -EINVAL;
+ count -= scnt; buf += scnt;
+ if (!wptr) return -EINVAL;
+ if (debugifc_match_keyword(wptr,wlen,"dir")) {
+ dir_fl = !0;
+ } else if (!debugifc_match_keyword(wptr,wlen,"out")) {
+ return -EINVAL;
+ }
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (!scnt) return -EINVAL;
+ count -= scnt; buf += scnt;
+ if (!wptr) return -EINVAL;
+ ret = debugifc_parse_unsigned_number(wptr,wlen,&msk);
+ if (ret) return ret;
+ scnt = debugifc_isolate_word(buf,count,&wptr,&wlen);
+ if (wptr) {
+ ret = debugifc_parse_unsigned_number(wptr,wlen,&val);
+ if (ret) return ret;
+ } else {
+ val = msk;
+ msk = 0xffffffff;
+ }
+ if (dir_fl) {
+ ret = pvr2_hdw_gpio_chg_dir(hdw,msk,val);
+ } else {
+ ret = pvr2_hdw_gpio_chg_out(hdw,msk,val);
+ }
+ return ret;
+ }
+ pvr2_trace(PVR2_TRACE_DEBUGIFC,
+ "debugifc failed to recognize cmd: \"%.*s\"",wlen,wptr);
+ return -EINVAL;
+}
+
+
+int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
+ unsigned int count)
+{
+ unsigned int bcnt = 0;
+ int ret;
+
+ while (count) {
+ for (bcnt = 0; bcnt < count; bcnt++) {
+ if (buf[bcnt] == '\n') break;
+ }
+
+ ret = pvr2_debugifc_do1cmd(hdw,buf,bcnt);
+ if (ret < 0) return ret;
+ if (bcnt < count) bcnt++;
+ buf += bcnt;
+ count -= bcnt;
+ }
+
+ return 0;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.h b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
new file mode 100644
index 00000000000..990b02d35d3
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_DEBUGIFC_H
+#define __PVRUSB2_DEBUGIFC_H
+
+struct pvr2_hdw;
+
+/* Non-intrusively print some useful debugging info from inside the
+ driver. This should work even if the driver appears to be
+ wedged. */
+int pvr2_debugifc_print_info(struct pvr2_hdw *,
+ char *buf_ptr,unsigned int buf_size);
+
+/* Print general status of driver. This will also trigger a probe of
+ the USB link. Unlike print_info(), this one synchronizes with the
+ driver so the information should be self-consistent (but it will
+ hang if the driver is wedged). */
+int pvr2_debugifc_print_status(struct pvr2_hdw *,
+ char *buf_ptr,unsigned int buf_size);
+
+/* Parse a string command into a driver action. */
+int pvr2_debugifc_docmd(struct pvr2_hdw *,
+ const char *buf_ptr,unsigned int buf_size);
+
+#endif /* __PVRUSB2_DEBUGIFC_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.c b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
new file mode 100644
index 00000000000..6cff8e75f42
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.c
@@ -0,0 +1,164 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "pvrusb2-eeprom.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+#define trace_eeprom(...) pvr2_trace(PVR2_TRACE_EEPROM,__VA_ARGS__)
+
+
+
+/*
+
+ Read and analyze data in the eeprom. Use tveeprom to figure out
+ the packet structure, since this is another Hauppauge device and
+ internally it has a family resemblence to ivtv-type devices
+
+*/
+
+#include <media/tveeprom.h>
+
+/* We seem to only be interested in the last 128 bytes of the EEPROM */
+#define EEPROM_SIZE 128
+
+/* Grab EEPROM contents, needed for direct method. */
+static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
+{
+ struct i2c_msg msg[2];
+ u8 *eeprom;
+ u8 iadd[2];
+ u8 addr;
+ u16 eepromSize;
+ unsigned int offs;
+ int ret;
+ int mode16 = 0;
+ unsigned pcnt,tcnt;
+ eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL);
+ if (!eeprom) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to allocate memory"
+ " required to read eeprom");
+ return NULL;
+ }
+
+ trace_eeprom("Value for eeprom addr from controller was 0x%x",
+ hdw->eeprom_addr);
+ addr = hdw->eeprom_addr;
+ /* Seems that if the high bit is set, then the *real* eeprom
+ address is shifted right now bit position (noticed this in
+ newer PVR USB2 hardware) */
+ if (addr & 0x80) addr >>= 1;
+
+ /* FX2 documentation states that a 16bit-addressed eeprom is
+ expected if the I2C address is an odd number (yeah, this is
+ strange but it's what they do) */
+ mode16 = (addr & 1);
+ eepromSize = (mode16 ? 4096 : 256);
+ trace_eeprom("Examining %d byte eeprom at location 0x%x"
+ " using %d bit addressing",eepromSize,addr,
+ mode16 ? 16 : 8);
+
+ msg[0].addr = addr;
+ msg[0].flags = 0;
+ msg[0].len = mode16 ? 2 : 1;
+ msg[0].buf = iadd;
+ msg[1].addr = addr;
+ msg[1].flags = I2C_M_RD;
+
+ /* We have to do the actual eeprom data fetch ourselves, because
+ (1) we're only fetching part of the eeprom, and (2) if we were
+ getting the whole thing our I2C driver can't grab it in one
+ pass - which is what tveeprom is otherwise going to attempt */
+ memset(eeprom,0,EEPROM_SIZE);
+ for (tcnt = 0; tcnt < EEPROM_SIZE; tcnt += pcnt) {
+ pcnt = 16;
+ if (pcnt + tcnt > EEPROM_SIZE) pcnt = EEPROM_SIZE-tcnt;
+ offs = tcnt + (eepromSize - EEPROM_SIZE);
+ if (mode16) {
+ iadd[0] = offs >> 8;
+ iadd[1] = offs;
+ } else {
+ iadd[0] = offs;
+ }
+ msg[1].len = pcnt;
+ msg[1].buf = eeprom+tcnt;
+ if ((ret = i2c_transfer(
+ &hdw->i2c_adap,
+ msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "eeprom fetch set offs err=%d",ret);
+ kfree(eeprom);
+ return NULL;
+ }
+ }
+ return eeprom;
+}
+
+
+/* Directly call eeprom analysis function within tveeprom. */
+int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
+{
+ u8 *eeprom;
+ struct tveeprom tvdata;
+
+ memset(&tvdata,0,sizeof(tvdata));
+
+ eeprom = pvr2_eeprom_fetch(hdw);
+ if (!eeprom) return -EINVAL;
+
+ {
+ struct i2c_client fake_client;
+ /* Newer version expects a useless client interface */
+ fake_client.addr = hdw->eeprom_addr;
+ fake_client.adapter = &hdw->i2c_adap;
+ tveeprom_hauppauge_analog(&fake_client,&tvdata,eeprom);
+ }
+
+ trace_eeprom("eeprom assumed v4l tveeprom module");
+ trace_eeprom("eeprom direct call results:");
+ trace_eeprom("has_radio=%d",tvdata.has_radio);
+ trace_eeprom("tuner_type=%d",tvdata.tuner_type);
+ trace_eeprom("tuner_formats=0x%x",tvdata.tuner_formats);
+ trace_eeprom("audio_processor=%d",tvdata.audio_processor);
+ trace_eeprom("model=%d",tvdata.model);
+ trace_eeprom("revision=%d",tvdata.revision);
+ trace_eeprom("serial_number=%d",tvdata.serial_number);
+ trace_eeprom("rev_str=%s",tvdata.rev_str);
+ hdw->tuner_type = tvdata.tuner_type;
+ hdw->serial_number = tvdata.serial_number;
+ hdw->std_mask_eeprom = tvdata.tuner_formats;
+
+ kfree(eeprom);
+
+ return 0;
+}
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-eeprom.h b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
new file mode 100644
index 00000000000..84242975dea
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-eeprom.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_EEPROM_H
+#define __PVRUSB2_EEPROM_H
+
+struct pvr2_hdw;
+
+int pvr2_eeprom_analyze(struct pvr2_hdw *);
+
+#endif /* __PVRUSB2_EEPROM_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
new file mode 100644
index 00000000000..18a7073501c
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -0,0 +1,418 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/device.h> // for linux/firmware.h
+#include <linux/firmware.h>
+#include "pvrusb2-util.h"
+#include "pvrusb2-encoder.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+
+
+/* Firmware mailbox flags - definitions found from ivtv */
+#define IVTV_MBOX_FIRMWARE_DONE 0x00000004
+#define IVTV_MBOX_DRIVER_DONE 0x00000002
+#define IVTV_MBOX_DRIVER_BUSY 0x00000001
+
+
+static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
+ const u32 *data, unsigned int dlen)
+{
+ unsigned int idx;
+ int ret;
+ unsigned int offs = 0;
+ unsigned int chunkCnt;
+
+ /*
+
+ Format: First byte must be 0x01. Remaining 32 bit words are
+ spread out into chunks of 7 bytes each, little-endian ordered,
+ offset at zero within each 2 blank bytes following and a
+ single byte that is 0x44 plus the offset of the word. Repeat
+ request for additional words, with offset adjusted
+ accordingly.
+
+ */
+ while (dlen) {
+ chunkCnt = 8;
+ if (chunkCnt > dlen) chunkCnt = dlen;
+ memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
+ hdw->cmd_buffer[0] = 0x01;
+ for (idx = 0; idx < chunkCnt; idx++) {
+ hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
+ PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
+ data[idx]);
+ }
+ ret = pvr2_send_request(hdw,
+ hdw->cmd_buffer,1+(chunkCnt*7),
+ NULL,0);
+ if (ret) return ret;
+ data += chunkCnt;
+ dlen -= chunkCnt;
+ offs += chunkCnt;
+ }
+
+ return 0;
+}
+
+
+static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
+ u32 *data, unsigned int dlen)
+{
+ unsigned int idx;
+ int ret;
+ unsigned int offs = 0;
+ unsigned int chunkCnt;
+
+ /*
+
+ Format: First byte must be 0x02 (status check) or 0x28 (read
+ back block of 32 bit words). Next 6 bytes must be zero,
+ followed by a single byte of 0x44+offset for portion to be
+ read. Returned data is packed set of 32 bits words that were
+ read.
+
+ */
+
+ while (dlen) {
+ chunkCnt = 16;
+ if (chunkCnt > dlen) chunkCnt = dlen;
+ memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
+ hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
+ hdw->cmd_buffer[7] = 0x44 + offs;
+ ret = pvr2_send_request(hdw,
+ hdw->cmd_buffer,8,
+ hdw->cmd_buffer,chunkCnt * 4);
+ if (ret) return ret;
+
+ for (idx = 0; idx < chunkCnt; idx++) {
+ data[idx] = PVR2_COMPOSE_LE(hdw->cmd_buffer,idx*4);
+ }
+ data += chunkCnt;
+ dlen -= chunkCnt;
+ offs += chunkCnt;
+ }
+
+ return 0;
+}
+
+
+/* This prototype is set up to be compatible with the
+ cx2341x_mbox_func prototype in cx2341x.h, which should be in
+ kernels 2.6.18 or later. We do this so that we can enable
+ cx2341x.ko to write to our encoder (by handing it a pointer to this
+ function). For earlier kernels this doesn't really matter. */
+static int pvr2_encoder_cmd(void *ctxt,
+ int cmd,
+ int arg_cnt_send,
+ int arg_cnt_recv,
+ u32 *argp)
+{
+ unsigned int poll_count;
+ int ret = 0;
+ unsigned int idx;
+ /* These sizes look to be limited by the FX2 firmware implementation */
+ u32 wrData[16];
+ u32 rdData[16];
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)ctxt;
+
+
+ /*
+
+ The encoder seems to speak entirely using blocks 32 bit words.
+ In ivtv driver terms, this is a mailbox which we populate with
+ data and watch what the hardware does with it. The first word
+ is a set of flags used to control the transaction, the second
+ word is the command to execute, the third byte is zero (ivtv
+ driver suggests that this is some kind of return value), and
+ the fourth byte is a specified timeout (windows driver always
+ uses 0x00060000 except for one case when it is zero). All
+ successive words are the argument words for the command.
+
+ First, write out the entire set of words, with the first word
+ being zero.
+
+ Next, write out just the first word again, but set it to
+ IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
+ probably means "go").
+
+ Next, read back 16 words as status. Check the first word,
+ which should have IVTV_MBOX_FIRMWARE_DONE set. If however
+ that bit is not set, then the command isn't done so repeat the
+ read.
+
+ Next, read back 32 words and compare with the original
+ arugments. Hopefully they will match.
+
+ Finally, write out just the first word again, but set it to
+ 0x0 this time (which probably means "idle").
+
+ */
+
+ if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Failed to write cx23416 command"
+ " - too many input arguments"
+ " (was given %u limit %u)",
+ arg_cnt_send,
+ (unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
+ return -EINVAL;
+ }
+
+ if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Failed to write cx23416 command"
+ " - too many return arguments"
+ " (was given %u limit %u)",
+ arg_cnt_recv,
+ (unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
+ return -EINVAL;
+ }
+
+
+ LOCK_TAKE(hdw->ctl_lock); do {
+
+ wrData[0] = 0;
+ wrData[1] = cmd;
+ wrData[2] = 0;
+ wrData[3] = 0x00060000;
+ for (idx = 0; idx < arg_cnt_send; idx++) {
+ wrData[idx+4] = argp[idx];
+ }
+ for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
+ wrData[idx+4] = 0;
+ }
+
+ ret = pvr2_encoder_write_words(hdw,wrData,idx);
+ if (ret) break;
+ wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
+ ret = pvr2_encoder_write_words(hdw,wrData,1);
+ if (ret) break;
+ poll_count = 0;
+ while (1) {
+ if (poll_count < 10000000) poll_count++;
+ ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
+ if (ret) break;
+ if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
+ break;
+ }
+ if (poll_count == 100) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "***WARNING*** device's encoder"
+ " appears to be stuck"
+ " (status=0%08x)",rdData[0]);
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Encoder command: 0x%02x",cmd);
+ for (idx = 4; idx < arg_cnt_send; idx++) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Encoder arg%d: 0x%08x",
+ idx-3,wrData[idx]);
+ }
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Giving up waiting."
+ " It is likely that"
+ " this is a bad idea...");
+ ret = -EBUSY;
+ break;
+ }
+ }
+ if (ret) break;
+ wrData[0] = 0x7;
+ ret = pvr2_encoder_read_words(
+ hdw,0,rdData,
+ sizeof(rdData)/sizeof(rdData[0]));
+ if (ret) break;
+ for (idx = 0; idx < arg_cnt_recv; idx++) {
+ argp[idx] = rdData[idx+4];
+ }
+
+ wrData[0] = 0x0;
+ ret = pvr2_encoder_write_words(hdw,wrData,1);
+ if (ret) break;
+
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+
+static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
+ int args, ...)
+{
+ va_list vl;
+ unsigned int idx;
+ u32 data[12];
+
+ if (args > sizeof(data)/sizeof(data[0])) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Failed to write cx23416 command"
+ " - too many arguments"
+ " (was given %u limit %u)",
+ args,(unsigned int)(sizeof(data)/sizeof(data[0])));
+ return -EINVAL;
+ }
+
+ va_start(vl, args);
+ for (idx = 0; idx < args; idx++) {
+ data[idx] = va_arg(vl, u32);
+ }
+ va_end(vl);
+
+ return pvr2_encoder_cmd(hdw,cmd,args,0,data);
+}
+
+int pvr2_encoder_configure(struct pvr2_hdw *hdw)
+{
+ int ret;
+ pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure"
+ " (cx2341x module)");
+ hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING;
+ hdw->enc_ctl_state.width = hdw->res_hor_val;
+ hdw->enc_ctl_state.height = hdw->res_ver_val;
+ hdw->enc_ctl_state.is_50hz = ((hdw->std_mask_cur &
+ (V4L2_STD_NTSC|V4L2_STD_PAL_M)) ?
+ 0 : 1);
+
+ ret = 0;
+
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
+ 0xf0, 0xf0);
+
+ /* setup firmware to notify us about some events (don't know why...) */
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw,CX2341X_ENC_SET_EVENT_NOTIFICATION, 4,
+ 0, 0, 0x10000000, 0xffffffff);
+
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw,CX2341X_ENC_SET_VBI_LINE, 5,
+ 0xffffffff,0,0,0,0);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to configure cx32416");
+ return ret;
+ }
+
+ ret = cx2341x_update(hdw,pvr2_encoder_cmd,
+ (hdw->enc_cur_valid ? &hdw->enc_cur_state : NULL),
+ &hdw->enc_ctl_state);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Error from cx2341x module code=%d",ret);
+ return ret;
+ }
+
+ ret = 0;
+
+ if (!ret) ret = pvr2_encoder_vcmd(
+ hdw, CX2341X_ENC_INITIALIZE_INPUT, 0);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to initialize cx32416 video input");
+ return ret;
+ }
+
+ hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+ memcpy(&hdw->enc_cur_state,&hdw->enc_ctl_state,
+ sizeof(struct cx2341x_mpeg_params));
+ hdw->enc_cur_valid = !0;
+ return 0;
+}
+
+
+int pvr2_encoder_start(struct pvr2_hdw *hdw)
+{
+ int status;
+
+ /* unmask some interrupts */
+ pvr2_write_register(hdw, 0x0048, 0xbfffffff);
+
+ /* change some GPIO data */
+ pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
+ pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+
+ if (hdw->config == pvr2_config_vbi) {
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 0x01,0x14);
+ } else if (hdw->config == pvr2_config_mpeg) {
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 0,0x13);
+ } else {
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
+ 0,0x13);
+ }
+ if (!status) {
+ hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
+ }
+ return status;
+}
+
+int pvr2_encoder_stop(struct pvr2_hdw *hdw)
+{
+ int status;
+
+ /* mask all interrupts */
+ pvr2_write_register(hdw, 0x0048, 0xffffffff);
+
+ if (hdw->config == pvr2_config_vbi) {
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 0x01,0x01,0x14);
+ } else if (hdw->config == pvr2_config_mpeg) {
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 0x01,0,0x13);
+ } else {
+ status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
+ 0x01,0,0x13);
+ }
+
+ /* change some GPIO data */
+ /* Note: Bit d7 of dir appears to control the LED. So we shut it
+ off here. */
+ pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
+ pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
+
+ if (!status) {
+ hdw->subsys_enabled_mask &= ~(1<<PVR2_SUBSYS_B_ENC_RUN);
+ }
+ return status;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.h b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
new file mode 100644
index 00000000000..01b5a0b89c0
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.h
@@ -0,0 +1,42 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_ENCODER_H
+#define __PVRUSB2_ENCODER_H
+
+struct pvr2_hdw;
+
+int pvr2_encoder_configure(struct pvr2_hdw *);
+int pvr2_encoder_start(struct pvr2_hdw *);
+int pvr2_encoder_stop(struct pvr2_hdw *);
+
+#endif /* __PVRUSB2_ENCODER_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
new file mode 100644
index 00000000000..0d6dc33ca32
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -0,0 +1,367 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_HDW_INTERNAL_H
+#define __PVRUSB2_HDW_INTERNAL_H
+
+/*
+
+ This header sets up all the internal structures and definitions needed to
+ track and coordinate the driver's interaction with the hardware. ONLY
+ source files which actually implement part of that whole circus should be
+ including this header. Higher levels, like the external layers to the
+ various public APIs (V4L, sysfs, etc) should NOT ever include this
+ private, internal header. This means that pvrusb2-hdw, pvrusb2-encoder,
+ etc will include this, but pvrusb2-v4l should not.
+
+*/
+
+#include <linux/config.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-io.h"
+#include <media/cx2341x.h>
+
+/* Legal values for the SRATE state variable */
+#define PVR2_CVAL_SRATE_48 0
+#define PVR2_CVAL_SRATE_44_1 1
+
+/* Legal values for the AUDIOBITRATE state variable */
+#define PVR2_CVAL_AUDIOBITRATE_384 0
+#define PVR2_CVAL_AUDIOBITRATE_320 1
+#define PVR2_CVAL_AUDIOBITRATE_256 2
+#define PVR2_CVAL_AUDIOBITRATE_224 3
+#define PVR2_CVAL_AUDIOBITRATE_192 4
+#define PVR2_CVAL_AUDIOBITRATE_160 5
+#define PVR2_CVAL_AUDIOBITRATE_128 6
+#define PVR2_CVAL_AUDIOBITRATE_112 7
+#define PVR2_CVAL_AUDIOBITRATE_96 8
+#define PVR2_CVAL_AUDIOBITRATE_80 9
+#define PVR2_CVAL_AUDIOBITRATE_64 10
+#define PVR2_CVAL_AUDIOBITRATE_56 11
+#define PVR2_CVAL_AUDIOBITRATE_48 12
+#define PVR2_CVAL_AUDIOBITRATE_32 13
+#define PVR2_CVAL_AUDIOBITRATE_VBR 14
+
+/* Legal values for the AUDIOEMPHASIS state variable */
+#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
+#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
+#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
+
+/* Legal values for PVR2_CID_HSM */
+#define PVR2_CVAL_HSM_FAIL 0
+#define PVR2_CVAL_HSM_FULL 1
+#define PVR2_CVAL_HSM_HIGH 2
+
+#define PVR2_VID_ENDPOINT 0x84
+#define PVR2_UNK_ENDPOINT 0x86 /* maybe raw yuv ? */
+#define PVR2_VBI_ENDPOINT 0x88
+
+#define PVR2_CTL_BUFFSIZE 64
+
+#define FREQTABLE_SIZE 500
+
+#define LOCK_TAKE(x) do { mutex_lock(&x##_mutex); x##_held = !0; } while (0)
+#define LOCK_GIVE(x) do { x##_held = 0; mutex_unlock(&x##_mutex); } while (0)
+
+struct pvr2_decoder;
+
+typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
+typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
+typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
+typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
+typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
+ char *,unsigned int,unsigned int *);
+typedef int (*pvr2_ctlf_sym_to_val)(struct pvr2_ctrl *,
+ const char *,unsigned int,
+ int *mskp,int *valp);
+typedef unsigned int (*pvr2_ctlf_get_v4lflags)(struct pvr2_ctrl *);
+
+/* This structure describes a specific control. A table of these is set up
+ in pvrusb2-hdw.c. */
+struct pvr2_ctl_info {
+ /* Control's name suitable for use as an identifier */
+ const char *name;
+
+ /* Short description of control */
+ const char *desc;
+
+ /* Control's implementation */
+ pvr2_ctlf_get_value get_value; /* Get its value */
+ pvr2_ctlf_set_value set_value; /* Set its value */
+ pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
+ pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
+ pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */
+ pvr2_ctlf_clear_dirty clear_dirty; /* Clear dirty state */
+ pvr2_ctlf_get_v4lflags get_v4lflags;/* Retrieve v4l flags */
+
+ /* Control's type (int, enum, bitmask) */
+ enum pvr2_ctl_type type;
+
+ /* Associated V4L control ID, if any */
+ int v4l_id;
+
+ /* Associated driver internal ID, if any */
+ int internal_id;
+
+ /* Don't implicitly initialize this control's value */
+ int skip_init;
+
+ /* Starting value for this control */
+ int default_value;
+
+ /* Type-specific control information */
+ union {
+ struct { /* Integer control */
+ long min_value; /* lower limit */
+ long max_value; /* upper limit */
+ } type_int;
+ struct { /* enumerated control */
+ unsigned int count; /* enum value count */
+ const char **value_names; /* symbol names */
+ } type_enum;
+ struct { /* bitmask control */
+ unsigned int valid_bits; /* bits in use */
+ const char **bit_names; /* symbol name/bit */
+ } type_bitmask;
+ } def;
+};
+
+
+/* Same as pvr2_ctl_info, but includes storage for the control description */
+#define PVR2_CTLD_INFO_DESC_SIZE 32
+struct pvr2_ctld_info {
+ struct pvr2_ctl_info info;
+ char desc[PVR2_CTLD_INFO_DESC_SIZE];
+};
+
+struct pvr2_ctrl {
+ const struct pvr2_ctl_info *info;
+ struct pvr2_hdw *hdw;
+};
+
+
+struct pvr2_audio_stat {
+ void *ctxt;
+ void (*detach)(void *);
+ int (*status)(void *);
+};
+
+struct pvr2_decoder_ctrl {
+ void *ctxt;
+ void (*detach)(void *);
+ void (*enable)(void *,int);
+ int (*tuned)(void *);
+ void (*force_reset)(void *);
+};
+
+#define PVR2_I2C_PEND_DETECT 0x01 /* Need to detect a client type */
+#define PVR2_I2C_PEND_CLIENT 0x02 /* Client needs a specific update */
+#define PVR2_I2C_PEND_REFRESH 0x04 /* Client has specific pending bits */
+#define PVR2_I2C_PEND_STALE 0x08 /* Broadcast pending bits */
+
+#define PVR2_I2C_PEND_ALL (PVR2_I2C_PEND_DETECT |\
+ PVR2_I2C_PEND_CLIENT |\
+ PVR2_I2C_PEND_REFRESH |\
+ PVR2_I2C_PEND_STALE)
+
+/* Disposition of firmware1 loading situation */
+#define FW1_STATE_UNKNOWN 0
+#define FW1_STATE_MISSING 1
+#define FW1_STATE_FAILED 2
+#define FW1_STATE_RELOAD 3
+#define FW1_STATE_OK 4
+
+/* Known major hardware variants, keyed from device ID */
+#define PVR2_HDW_TYPE_29XXX 0
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#define PVR2_HDW_TYPE_24XXX 1
+#endif
+
+typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
+#define PVR2_I2C_FUNC_CNT 128
+
+/* This structure contains all state data directly needed to
+ manipulate the hardware (as opposed to complying with a kernel
+ interface) */
+struct pvr2_hdw {
+ /* Underlying USB device handle */
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_intf;
+
+ /* Device type, one of PVR2_HDW_TYPE_xxxxx */
+ unsigned int hdw_type;
+
+ /* Video spigot */
+ struct pvr2_stream *vid_stream;
+
+ /* Mutex for all hardware state control */
+ struct mutex big_lock_mutex;
+ int big_lock_held; /* For debugging */
+
+ void (*poll_trigger_func)(void *);
+ void *poll_trigger_data;
+
+ char name[32];
+
+ /* I2C stuff */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algorithm i2c_algo;
+ pvr2_i2c_func i2c_func[PVR2_I2C_FUNC_CNT];
+ int i2c_cx25840_hack_state;
+ int i2c_linked;
+ unsigned int i2c_pend_types; /* Which types of update are needed */
+ unsigned long i2c_pend_mask; /* Change bits we need to scan */
+ unsigned long i2c_stale_mask; /* Pending broadcast change bits */
+ unsigned long i2c_active_mask; /* All change bits currently in use */
+ struct list_head i2c_clients;
+ struct mutex i2c_list_lock;
+
+ /* Frequency table */
+ unsigned int freqTable[FREQTABLE_SIZE];
+ unsigned int freqProgSlot;
+ unsigned int freqSlot;
+
+ /* Stuff for handling low level control interaction with device */
+ struct mutex ctl_lock_mutex;
+ int ctl_lock_held; /* For debugging */
+ struct urb *ctl_write_urb;
+ struct urb *ctl_read_urb;
+ unsigned char *ctl_write_buffer;
+ unsigned char *ctl_read_buffer;
+ volatile int ctl_write_pend_flag;
+ volatile int ctl_read_pend_flag;
+ volatile int ctl_timeout_flag;
+ struct completion ctl_done;
+ unsigned char cmd_buffer[PVR2_CTL_BUFFSIZE];
+ int cmd_debug_state; // Low level command debugging info
+ unsigned char cmd_debug_code; //
+ unsigned int cmd_debug_write_len; //
+ unsigned int cmd_debug_read_len; //
+
+ int flag_ok; // device in known good state
+ int flag_disconnected; // flag_ok == 0 due to disconnect
+ int flag_init_ok; // true if structure is fully initialized
+ int flag_streaming_enabled; // true if streaming should be on
+ int fw1_state; // current situation with fw1
+
+ int flag_decoder_is_tuned;
+
+ struct pvr2_decoder_ctrl *decoder_ctrl;
+
+ // CPU firmware info (used to help find / save firmware data)
+ char *fw_buffer;
+ unsigned int fw_size;
+
+ // Which subsystem pieces have been enabled / configured
+ unsigned long subsys_enabled_mask;
+
+ // Which subsystems are manipulated to enable streaming
+ unsigned long subsys_stream_mask;
+
+ // True if there is a request to trigger logging of state in each
+ // module.
+ int log_requested;
+
+ /* Tuner / frequency control stuff */
+ unsigned int tuner_type;
+ int tuner_updated;
+ unsigned int freqVal;
+ int freqDirty;
+
+ /* Video standard handling */
+ v4l2_std_id std_mask_eeprom; // Hardware supported selections
+ v4l2_std_id std_mask_avail; // Which standards we may select from
+ v4l2_std_id std_mask_cur; // Currently selected standard(s)
+ unsigned int std_enum_cnt; // # of enumerated standards
+ int std_enum_cur; // selected standard enumeration value
+ int std_dirty; // True if std_mask_cur has changed
+ struct pvr2_ctl_info std_info_enum;
+ struct pvr2_ctl_info std_info_avail;
+ struct pvr2_ctl_info std_info_cur;
+ struct v4l2_standard *std_defs;
+ const char **std_enum_names;
+
+ // Generated string names, one per actual V4L2 standard
+ const char *std_mask_ptrs[32];
+ char std_mask_names[32][10];
+
+ int unit_number; /* ID for driver instance */
+ unsigned long serial_number; /* ID for hardware itself */
+
+ /* Minor number used by v4l logic (yes, this is a hack, as there should
+ be no v4l junk here). Probably a better way to do this. */
+ int v4l_minor_number;
+
+ /* Location of eeprom or a negative number if none */
+ int eeprom_addr;
+
+ enum pvr2_config config;
+
+ /* Information about what audio signal we're hearing */
+ int flag_stereo;
+ int flag_bilingual;
+ struct pvr2_audio_stat *audio_stat;
+
+ /* Control state needed for cx2341x module */
+ struct cx2341x_mpeg_params enc_cur_state;
+ struct cx2341x_mpeg_params enc_ctl_state;
+ /* True if an encoder attribute has changed */
+ int enc_stale;
+ /* True if enc_cur_state is valid */
+ int enc_cur_valid;
+
+ /* Control state */
+#define VCREATE_DATA(lab) int lab##_val; int lab##_dirty
+ VCREATE_DATA(brightness);
+ VCREATE_DATA(contrast);
+ VCREATE_DATA(saturation);
+ VCREATE_DATA(hue);
+ VCREATE_DATA(volume);
+ VCREATE_DATA(balance);
+ VCREATE_DATA(bass);
+ VCREATE_DATA(treble);
+ VCREATE_DATA(mute);
+ VCREATE_DATA(input);
+ VCREATE_DATA(audiomode);
+ VCREATE_DATA(res_hor);
+ VCREATE_DATA(res_ver);
+ VCREATE_DATA(srate);
+#undef VCREATE_DATA
+
+ struct pvr2_ctld_info *mpeg_ctrl_info;
+
+ struct pvr2_ctrl *controls;
+ unsigned int control_cnt;
+};
+
+#endif /* __PVRUSB2_HDW_INTERNAL_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
new file mode 100644
index 00000000000..be1e5cc7808
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -0,0 +1,3098 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/firmware.h>
+#include <linux/videodev2.h>
+#include <asm/semaphore.h>
+#include "pvrusb2.h"
+#include "pvrusb2-std.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-i2c-core.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-eeprom.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-encoder.h"
+#include "pvrusb2-debug.h"
+
+struct usb_device_id pvr2_device_table[] = {
+ [PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
+#endif
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, pvr2_device_table);
+
+static const char *pvr2_device_names[] = {
+ [PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
+#endif
+};
+
+struct pvr2_string_table {
+ const char **lst;
+ unsigned int cnt;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+// Names of other client modules to request for 24xxx model hardware
+static const char *pvr2_client_24xxx[] = {
+ "cx25840",
+ "tuner",
+ "wm8775",
+};
+#endif
+
+// Names of other client modules to request for 29xxx model hardware
+static const char *pvr2_client_29xxx[] = {
+ "msp3400",
+ "saa7115",
+ "tuner",
+};
+
+static struct pvr2_string_table pvr2_client_lists[] = {
+ [PVR2_HDW_TYPE_29XXX] = {
+ pvr2_client_29xxx,
+ sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
+ },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = {
+ pvr2_client_24xxx,
+ sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
+ },
+#endif
+};
+
+static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
+static DECLARE_MUTEX(pvr2_unit_sem);
+
+static int ctlchg = 0;
+static int initusbreset = 1;
+static int procreload = 0;
+static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
+static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
+static int init_pause_msec = 0;
+
+module_param(ctlchg, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
+module_param(init_pause_msec, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(init_pause_msec, "hardware initialization settling delay");
+module_param(initusbreset, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(initusbreset, "Do USB reset device on probe");
+module_param(procreload, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(procreload,
+ "Attempt init failure recovery with firmware reload");
+module_param_array(tuner, int, NULL, 0444);
+MODULE_PARM_DESC(tuner,"specify installed tuner type");
+module_param_array(video_std, int, NULL, 0444);
+MODULE_PARM_DESC(video_std,"specify initial video standard");
+module_param_array(tolerance, int, NULL, 0444);
+MODULE_PARM_DESC(tolerance,"specify stream error tolerance");
+
+#define PVR2_CTL_WRITE_ENDPOINT 0x01
+#define PVR2_CTL_READ_ENDPOINT 0x81
+
+#define PVR2_GPIO_IN 0x9008
+#define PVR2_GPIO_OUT 0x900c
+#define PVR2_GPIO_DIR 0x9020
+
+#define trace_firmware(...) pvr2_trace(PVR2_TRACE_FIRMWARE,__VA_ARGS__)
+
+#define PVR2_FIRMWARE_ENDPOINT 0x02
+
+/* size of a firmware chunk */
+#define FIRMWARE_CHUNK_SIZE 0x2000
+
+/* Define the list of additional controls we'll dynamically construct based
+ on query of the cx2341x module. */
+struct pvr2_mpeg_ids {
+ const char *strid;
+ int id;
+};
+static const struct pvr2_mpeg_ids mpeg_ids[] = {
+ {
+ .strid = "audio_layer",
+ .id = V4L2_CID_MPEG_AUDIO_ENCODING,
+ },{
+ .strid = "audio_bitrate",
+ .id = V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ },{
+ /* Already using audio_mode elsewhere :-( */
+ .strid = "mpeg_audio_mode",
+ .id = V4L2_CID_MPEG_AUDIO_MODE,
+ },{
+ .strid = "mpeg_audio_mode_extension",
+ .id = V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ },{
+ .strid = "audio_emphasis",
+ .id = V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ },{
+ .strid = "audio_crc",
+ .id = V4L2_CID_MPEG_AUDIO_CRC,
+ },{
+ .strid = "video_aspect",
+ .id = V4L2_CID_MPEG_VIDEO_ASPECT,
+ },{
+ .strid = "video_b_frames",
+ .id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ },{
+ .strid = "video_gop_size",
+ .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ },{
+ .strid = "video_gop_closure",
+ .id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
+ },{
+ .strid = "video_pulldown",
+ .id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
+ },{
+ .strid = "video_bitrate_mode",
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ },{
+ .strid = "video_bitrate",
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE,
+ },{
+ .strid = "video_bitrate_peak",
+ .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ },{
+ .strid = "video_temporal_decimation",
+ .id = V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ },{
+ .strid = "stream_type",
+ .id = V4L2_CID_MPEG_STREAM_TYPE,
+ },{
+ .strid = "video_spatial_filter_mode",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ },{
+ .strid = "video_spatial_filter",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ },{
+ .strid = "video_luma_spatial_filter_type",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ },{
+ .strid = "video_chroma_spatial_filter_type",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ },{
+ .strid = "video_temporal_filter_mode",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ },{
+ .strid = "video_temporal_filter",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ },{
+ .strid = "video_median_filter_type",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ },{
+ .strid = "video_luma_median_filter_top",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ },{
+ .strid = "video_luma_median_filter_bottom",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ },{
+ .strid = "video_chroma_median_filter_top",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ },{
+ .strid = "video_chroma_median_filter_bottom",
+ .id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ }
+};
+#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+
+static const char *control_values_srate[] = {
+ [PVR2_CVAL_SRATE_48] = "48KHz",
+ [PVR2_CVAL_SRATE_44_1] = "44.1KHz",
+};
+
+
+
+
+static const char *control_values_input[] = {
+ [PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
+ [PVR2_CVAL_INPUT_RADIO] = "radio",
+ [PVR2_CVAL_INPUT_SVIDEO] = "s-video",
+ [PVR2_CVAL_INPUT_COMPOSITE] = "composite",
+};
+
+
+static const char *control_values_audiomode[] = {
+ [V4L2_TUNER_MODE_MONO] = "Mono",
+ [V4L2_TUNER_MODE_STEREO] = "Stereo",
+ [V4L2_TUNER_MODE_LANG1] = "Lang1",
+ [V4L2_TUNER_MODE_LANG2] = "Lang2",
+ [V4L2_TUNER_MODE_LANG1_LANG2] = "Lang1+Lang2",
+};
+
+
+static const char *control_values_hsm[] = {
+ [PVR2_CVAL_HSM_FAIL] = "Fail",
+ [PVR2_CVAL_HSM_HIGH] = "High",
+ [PVR2_CVAL_HSM_FULL] = "Full",
+};
+
+
+static const char *control_values_subsystem[] = {
+ [PVR2_SUBSYS_B_ENC_FIRMWARE] = "enc_firmware",
+ [PVR2_SUBSYS_B_ENC_CFG] = "enc_config",
+ [PVR2_SUBSYS_B_DIGITIZER_RUN] = "digitizer_run",
+ [PVR2_SUBSYS_B_USBSTREAM_RUN] = "usbstream_run",
+ [PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
+};
+
+static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
+static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
+static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
+static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
+static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
+static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
+static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
+static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+ unsigned long msk,
+ unsigned long val);
+static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+ unsigned long msk,
+ unsigned long val);
+static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
+ unsigned int timeout,int probe_fl,
+ void *write_data,unsigned int write_len,
+ void *read_data,unsigned int read_len);
+static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res);
+static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res);
+
+static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+ *vp = hdw->freqTable[hdw->freqProgSlot-1];
+ } else {
+ *vp = 0;
+ }
+ return 0;
+}
+
+static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
+ hdw->freqTable[hdw->freqProgSlot-1] = v;
+ }
+ return 0;
+}
+
+static int ctrl_channelprog_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->freqProgSlot;
+ return 0;
+}
+
+static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if ((v >= 0) && (v <= FREQTABLE_SIZE)) {
+ hdw->freqProgSlot = v;
+ }
+ return 0;
+}
+
+static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->freqSlot;
+ return 0;
+}
+
+static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ unsigned freq = 0;
+ struct pvr2_hdw *hdw = cptr->hdw;
+ hdw->freqSlot = v;
+ if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
+ freq = hdw->freqTable[hdw->freqSlot-1];
+ }
+ if (freq && (freq != hdw->freqVal)) {
+ hdw->freqVal = freq;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->freqVal;
+ return 0;
+}
+
+static int ctrl_freq_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->freqDirty != 0;
+}
+
+static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->freqDirty = 0;
+}
+
+static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ hdw->freqVal = v;
+ hdw->freqDirty = !0;
+ hdw->freqSlot = 0;
+ return 0;
+}
+
+static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->enc_stale != 0;
+}
+
+static void ctrl_cx2341x_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->enc_stale = 0;
+}
+
+static int ctrl_cx2341x_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int ret;
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs,0,sizeof(cs));
+ memset(&c1,0,sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = cptr->info->v4l_id;
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ VIDIOC_G_EXT_CTRLS);
+ if (ret) return ret;
+ *vp = c1.value;
+ return 0;
+}
+
+static int ctrl_cx2341x_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ int ret;
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs,0,sizeof(cs));
+ memset(&c1,0,sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = cptr->info->v4l_id;
+ c1.value = v;
+ ret = cx2341x_ext_ctrls(&cptr->hdw->enc_ctl_state,&cs,
+ VIDIOC_S_EXT_CTRLS);
+ if (ret) return ret;
+ cptr->hdw->enc_stale = !0;
+ return 0;
+}
+
+static unsigned int ctrl_cx2341x_getv4lflags(struct pvr2_ctrl *cptr)
+{
+ struct v4l2_queryctrl qctrl;
+ struct pvr2_ctl_info *info;
+ qctrl.id = cptr->info->v4l_id;
+ cx2341x_ctrl_query(&cptr->hdw->enc_ctl_state,&qctrl);
+ /* Strip out the const so we can adjust a function pointer. It's
+ OK to do this here because we know this is a dynamically created
+ control, so the underlying storage for the info pointer is (a)
+ private to us, and (b) not in read-only storage. Either we do
+ this or we significantly complicate the underlying control
+ implementation. */
+ info = (struct pvr2_ctl_info *)(cptr->info);
+ if (qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY) {
+ if (info->set_value) {
+ info->set_value = NULL;
+ }
+ } else {
+ if (!(info->set_value)) {
+ info->set_value = ctrl_cx2341x_set;
+ }
+ }
+ return qctrl.flags;
+}
+
+static int ctrl_streamingenabled_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->flag_streaming_enabled;
+ return 0;
+}
+
+static int ctrl_hsm_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ int result = pvr2_hdw_is_hsm(cptr->hdw);
+ *vp = PVR2_CVAL_HSM_FULL;
+ if (result < 0) *vp = PVR2_CVAL_HSM_FAIL;
+ if (result) *vp = PVR2_CVAL_HSM_HIGH;
+ return 0;
+}
+
+static int ctrl_stdavail_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->std_mask_avail;
+ return 0;
+}
+
+static int ctrl_stdavail_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ v4l2_std_id ns;
+ ns = hdw->std_mask_avail;
+ ns = (ns & ~m) | (v & m);
+ if (ns == hdw->std_mask_avail) return 0;
+ hdw->std_mask_avail = ns;
+ pvr2_hdw_internal_set_std_avail(hdw);
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return 0;
+}
+
+static int ctrl_std_val_to_sym(struct pvr2_ctrl *cptr,int msk,int val,
+ char *bufPtr,unsigned int bufSize,
+ unsigned int *len)
+{
+ *len = pvr2_std_id_to_str(bufPtr,bufSize,msk & val);
+ return 0;
+}
+
+static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr,
+ const char *bufPtr,unsigned int bufSize,
+ int *mskp,int *valp)
+{
+ int ret;
+ v4l2_std_id id;
+ ret = pvr2_std_str_to_id(&id,bufPtr,bufSize);
+ if (ret < 0) return ret;
+ if (mskp) *mskp = id;
+ if (valp) *valp = id;
+ return 0;
+}
+
+static int ctrl_stdcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->std_mask_cur;
+ return 0;
+}
+
+static int ctrl_stdcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ v4l2_std_id ns;
+ ns = hdw->std_mask_cur;
+ ns = (ns & ~m) | (v & m);
+ if (ns == hdw->std_mask_cur) return 0;
+ hdw->std_mask_cur = ns;
+ hdw->std_dirty = !0;
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return 0;
+}
+
+static int ctrl_stdcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->std_dirty != 0;
+}
+
+static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->std_dirty = 0;
+}
+
+static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
+ PVR2_SIGNAL_OK) ? 1 : 0);
+ return 0;
+}
+
+static int ctrl_subsys_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->subsys_enabled_mask;
+ return 0;
+}
+
+static int ctrl_subsys_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ pvr2_hdw_subsys_bit_chg_no_lock(cptr->hdw,m,v);
+ return 0;
+}
+
+static int ctrl_subsys_stream_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->subsys_stream_mask;
+ return 0;
+}
+
+static int ctrl_subsys_stream_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ pvr2_hdw_subsys_stream_bit_chg_no_lock(cptr->hdw,m,v);
+ return 0;
+}
+
+static int ctrl_stdenumcur_set(struct pvr2_ctrl *cptr,int m,int v)
+{
+ struct pvr2_hdw *hdw = cptr->hdw;
+ if (v < 0) return -EINVAL;
+ if (v > hdw->std_enum_cnt) return -EINVAL;
+ hdw->std_enum_cur = v;
+ if (!v) return 0;
+ v--;
+ if (hdw->std_mask_cur == hdw->std_defs[v].id) return 0;
+ hdw->std_mask_cur = hdw->std_defs[v].id;
+ hdw->std_dirty = !0;
+ return 0;
+}
+
+
+static int ctrl_stdenumcur_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ *vp = cptr->hdw->std_enum_cur;
+ return 0;
+}
+
+
+static int ctrl_stdenumcur_is_dirty(struct pvr2_ctrl *cptr)
+{
+ return cptr->hdw->std_dirty != 0;
+}
+
+
+static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
+{
+ cptr->hdw->std_dirty = 0;
+}
+
+
+#define DEFINT(vmin,vmax) \
+ .type = pvr2_ctl_int, \
+ .def.type_int.min_value = vmin, \
+ .def.type_int.max_value = vmax
+
+#define DEFENUM(tab) \
+ .type = pvr2_ctl_enum, \
+ .def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
+ .def.type_enum.value_names = tab
+
+#define DEFBOOL \
+ .type = pvr2_ctl_bool
+
+#define DEFMASK(msk,tab) \
+ .type = pvr2_ctl_bitmask, \
+ .def.type_bitmask.valid_bits = msk, \
+ .def.type_bitmask.bit_names = tab
+
+#define DEFREF(vname) \
+ .set_value = ctrl_set_##vname, \
+ .get_value = ctrl_get_##vname, \
+ .is_dirty = ctrl_isdirty_##vname, \
+ .clear_dirty = ctrl_cleardirty_##vname
+
+
+#define VCREATE_FUNCS(vname) \
+static int ctrl_get_##vname(struct pvr2_ctrl *cptr,int *vp) \
+{*vp = cptr->hdw->vname##_val; return 0;} \
+static int ctrl_set_##vname(struct pvr2_ctrl *cptr,int m,int v) \
+{cptr->hdw->vname##_val = v; cptr->hdw->vname##_dirty = !0; return 0;} \
+static int ctrl_isdirty_##vname(struct pvr2_ctrl *cptr) \
+{return cptr->hdw->vname##_dirty != 0;} \
+static void ctrl_cleardirty_##vname(struct pvr2_ctrl *cptr) \
+{cptr->hdw->vname##_dirty = 0;}
+
+VCREATE_FUNCS(brightness)
+VCREATE_FUNCS(contrast)
+VCREATE_FUNCS(saturation)
+VCREATE_FUNCS(hue)
+VCREATE_FUNCS(volume)
+VCREATE_FUNCS(balance)
+VCREATE_FUNCS(bass)
+VCREATE_FUNCS(treble)
+VCREATE_FUNCS(mute)
+VCREATE_FUNCS(input)
+VCREATE_FUNCS(audiomode)
+VCREATE_FUNCS(res_hor)
+VCREATE_FUNCS(res_ver)
+VCREATE_FUNCS(srate)
+
+#define MIN_FREQ 55250000L
+#define MAX_FREQ 850000000L
+
+/* Table definition of all controls which can be manipulated */
+static const struct pvr2_ctl_info control_defs[] = {
+ {
+ .v4l_id = V4L2_CID_BRIGHTNESS,
+ .desc = "Brightness",
+ .name = "brightness",
+ .default_value = 128,
+ DEFREF(brightness),
+ DEFINT(0,255),
+ },{
+ .v4l_id = V4L2_CID_CONTRAST,
+ .desc = "Contrast",
+ .name = "contrast",
+ .default_value = 68,
+ DEFREF(contrast),
+ DEFINT(0,127),
+ },{
+ .v4l_id = V4L2_CID_SATURATION,
+ .desc = "Saturation",
+ .name = "saturation",
+ .default_value = 64,
+ DEFREF(saturation),
+ DEFINT(0,127),
+ },{
+ .v4l_id = V4L2_CID_HUE,
+ .desc = "Hue",
+ .name = "hue",
+ .default_value = 0,
+ DEFREF(hue),
+ DEFINT(-128,127),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_VOLUME,
+ .desc = "Volume",
+ .name = "volume",
+ .default_value = 65535,
+ DEFREF(volume),
+ DEFINT(0,65535),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_BALANCE,
+ .desc = "Balance",
+ .name = "balance",
+ .default_value = 0,
+ DEFREF(balance),
+ DEFINT(-32768,32767),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_BASS,
+ .desc = "Bass",
+ .name = "bass",
+ .default_value = 0,
+ DEFREF(bass),
+ DEFINT(-32768,32767),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_TREBLE,
+ .desc = "Treble",
+ .name = "treble",
+ .default_value = 0,
+ DEFREF(treble),
+ DEFINT(-32768,32767),
+ },{
+ .v4l_id = V4L2_CID_AUDIO_MUTE,
+ .desc = "Mute",
+ .name = "mute",
+ .default_value = 0,
+ DEFREF(mute),
+ DEFBOOL,
+ },{
+ .desc = "Video Source",
+ .name = "input",
+ .internal_id = PVR2_CID_INPUT,
+ .default_value = PVR2_CVAL_INPUT_TV,
+ DEFREF(input),
+ DEFENUM(control_values_input),
+ },{
+ .desc = "Audio Mode",
+ .name = "audio_mode",
+ .internal_id = PVR2_CID_AUDIOMODE,
+ .default_value = V4L2_TUNER_MODE_STEREO,
+ DEFREF(audiomode),
+ DEFENUM(control_values_audiomode),
+ },{
+ .desc = "Horizontal capture resolution",
+ .name = "resolution_hor",
+ .internal_id = PVR2_CID_HRES,
+ .default_value = 720,
+ DEFREF(res_hor),
+ DEFINT(320,720),
+ },{
+ .desc = "Vertical capture resolution",
+ .name = "resolution_ver",
+ .internal_id = PVR2_CID_VRES,
+ .default_value = 480,
+ DEFREF(res_ver),
+ DEFINT(200,625),
+ },{
+ .v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ .desc = "Sample rate",
+ .name = "srate",
+ .default_value = PVR2_CVAL_SRATE_48,
+ DEFREF(srate),
+ DEFENUM(control_values_srate),
+ },{
+ .desc = "Tuner Frequency (Hz)",
+ .name = "frequency",
+ .internal_id = PVR2_CID_FREQUENCY,
+ .default_value = 175250000L,
+ .set_value = ctrl_freq_set,
+ .get_value = ctrl_freq_get,
+ .is_dirty = ctrl_freq_is_dirty,
+ .clear_dirty = ctrl_freq_clear_dirty,
+ DEFINT(MIN_FREQ,MAX_FREQ),
+ },{
+ .desc = "Channel",
+ .name = "channel",
+ .set_value = ctrl_channel_set,
+ .get_value = ctrl_channel_get,
+ DEFINT(0,FREQTABLE_SIZE),
+ },{
+ .desc = "Channel Program Frequency",
+ .name = "freq_table_value",
+ .set_value = ctrl_channelfreq_set,
+ .get_value = ctrl_channelfreq_get,
+ DEFINT(MIN_FREQ,MAX_FREQ),
+ },{
+ .desc = "Channel Program ID",
+ .name = "freq_table_channel",
+ .set_value = ctrl_channelprog_set,
+ .get_value = ctrl_channelprog_get,
+ DEFINT(0,FREQTABLE_SIZE),
+ },{
+ .desc = "Streaming Enabled",
+ .name = "streaming_enabled",
+ .get_value = ctrl_streamingenabled_get,
+ DEFBOOL,
+ },{
+ .desc = "USB Speed",
+ .name = "usb_speed",
+ .get_value = ctrl_hsm_get,
+ DEFENUM(control_values_hsm),
+ },{
+ .desc = "Signal Present",
+ .name = "signal_present",
+ .get_value = ctrl_signal_get,
+ DEFBOOL,
+ },{
+ .desc = "Video Standards Available Mask",
+ .name = "video_standard_mask_available",
+ .internal_id = PVR2_CID_STDAVAIL,
+ .skip_init = !0,
+ .get_value = ctrl_stdavail_get,
+ .set_value = ctrl_stdavail_set,
+ .val_to_sym = ctrl_std_val_to_sym,
+ .sym_to_val = ctrl_std_sym_to_val,
+ .type = pvr2_ctl_bitmask,
+ },{
+ .desc = "Video Standards In Use Mask",
+ .name = "video_standard_mask_active",
+ .internal_id = PVR2_CID_STDCUR,
+ .skip_init = !0,
+ .get_value = ctrl_stdcur_get,
+ .set_value = ctrl_stdcur_set,
+ .is_dirty = ctrl_stdcur_is_dirty,
+ .clear_dirty = ctrl_stdcur_clear_dirty,
+ .val_to_sym = ctrl_std_val_to_sym,
+ .sym_to_val = ctrl_std_sym_to_val,
+ .type = pvr2_ctl_bitmask,
+ },{
+ .desc = "Subsystem enabled mask",
+ .name = "debug_subsys_mask",
+ .skip_init = !0,
+ .get_value = ctrl_subsys_get,
+ .set_value = ctrl_subsys_set,
+ DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+ },{
+ .desc = "Subsystem stream mask",
+ .name = "debug_subsys_stream_mask",
+ .skip_init = !0,
+ .get_value = ctrl_subsys_stream_get,
+ .set_value = ctrl_subsys_stream_set,
+ DEFMASK(PVR2_SUBSYS_ALL,control_values_subsystem),
+ },{
+ .desc = "Video Standard Name",
+ .name = "video_standard",
+ .internal_id = PVR2_CID_STDENUM,
+ .skip_init = !0,
+ .get_value = ctrl_stdenumcur_get,
+ .set_value = ctrl_stdenumcur_set,
+ .is_dirty = ctrl_stdenumcur_is_dirty,
+ .clear_dirty = ctrl_stdenumcur_clear_dirty,
+ .type = pvr2_ctl_enum,
+ }
+};
+
+#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
+
+
+const char *pvr2_config_get_name(enum pvr2_config cfg)
+{
+ switch (cfg) {
+ case pvr2_config_empty: return "empty";
+ case pvr2_config_mpeg: return "mpeg";
+ case pvr2_config_vbi: return "vbi";
+ case pvr2_config_radio: return "radio";
+ }
+ return "<unknown>";
+}
+
+
+struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *hdw)
+{
+ return hdw->usb_dev;
+}
+
+
+unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
+{
+ return hdw->serial_number;
+}
+
+int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
+{
+ return hdw->unit_number;
+}
+
+
+/* Attempt to locate one of the given set of files. Messages are logged
+ appropriate to what has been found. The return value will be 0 or
+ greater on success (it will be the index of the file name found) and
+ fw_entry will be filled in. Otherwise a negative error is returned on
+ failure. If the return value is -ENOENT then no viable firmware file
+ could be located. */
+static int pvr2_locate_firmware(struct pvr2_hdw *hdw,
+ const struct firmware **fw_entry,
+ const char *fwtypename,
+ unsigned int fwcount,
+ const char *fwnames[])
+{
+ unsigned int idx;
+ int ret = -EINVAL;
+ for (idx = 0; idx < fwcount; idx++) {
+ ret = request_firmware(fw_entry,
+ fwnames[idx],
+ &hdw->usb_dev->dev);
+ if (!ret) {
+ trace_firmware("Located %s firmware: %s;"
+ " uploading...",
+ fwtypename,
+ fwnames[idx]);
+ return idx;
+ }
+ if (ret == -ENOENT) continue;
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "request_firmware fatal error with code=%d",ret);
+ return ret;
+ }
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "***WARNING***"
+ " Device %s firmware"
+ " seems to be missing.",
+ fwtypename);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Did you install the pvrusb2 firmware files"
+ " in their proper location?");
+ if (fwcount == 1) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "request_firmware unable to locate %s file %s",
+ fwtypename,fwnames[0]);
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "request_firmware unable to locate"
+ " one of the following %s files:",
+ fwtypename);
+ for (idx = 0; idx < fwcount; idx++) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "request_firmware: Failed to find %s",
+ fwnames[idx]);
+ }
+ }
+ return ret;
+}
+
+
+/*
+ * pvr2_upload_firmware1().
+ *
+ * Send the 8051 firmware to the device. After the upload, arrange for
+ * device to re-enumerate.
+ *
+ * NOTE : the pointer to the firmware data given by request_firmware()
+ * is not suitable for an usb transaction.
+ *
+ */
+static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
+{
+ const struct firmware *fw_entry = NULL;
+ void *fw_ptr;
+ unsigned int pipe;
+ int ret;
+ u16 address;
+ static const char *fw_files_29xxx[] = {
+ "v4l-pvrusb2-29xxx-01.fw",
+ };
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ static const char *fw_files_24xxx[] = {
+ "v4l-pvrusb2-24xxx-01.fw",
+ };
+#endif
+ static const struct pvr2_string_table fw_file_defs[] = {
+ [PVR2_HDW_TYPE_29XXX] = {
+ fw_files_29xxx,
+ sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
+ },
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ [PVR2_HDW_TYPE_24XXX] = {
+ fw_files_24xxx,
+ sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
+ },
+#endif
+ };
+ hdw->fw1_state = FW1_STATE_FAILED; // default result
+
+ trace_firmware("pvr2_upload_firmware1");
+
+ ret = pvr2_locate_firmware(hdw,&fw_entry,"fx2 controller",
+ fw_file_defs[hdw->hdw_type].cnt,
+ fw_file_defs[hdw->hdw_type].lst);
+ if (ret < 0) {
+ if (ret == -ENOENT) hdw->fw1_state = FW1_STATE_MISSING;
+ return ret;
+ }
+
+ usb_settoggle(hdw->usb_dev, 0 & 0xf, !(0 & USB_DIR_IN), 0);
+ usb_clear_halt(hdw->usb_dev, usb_sndbulkpipe(hdw->usb_dev, 0 & 0x7f));
+
+ pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+
+ if (fw_entry->size != 0x2000){
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,"wrong fx2 firmware size");
+ release_firmware(fw_entry);
+ return -ENOMEM;
+ }
+
+ fw_ptr = kmalloc(0x800, GFP_KERNEL);
+ if (fw_ptr == NULL){
+ release_firmware(fw_entry);
+ return -ENOMEM;
+ }
+
+ /* We have to hold the CPU during firmware upload. */
+ pvr2_hdw_cpureset_assert(hdw,1);
+
+ /* upload the firmware to address 0000-1fff in 2048 (=0x800) bytes
+ chunk. */
+
+ ret = 0;
+ for(address = 0; address < fw_entry->size; address += 0x800) {
+ memcpy(fw_ptr, fw_entry->data + address, 0x800);
+ ret += usb_control_msg(hdw->usb_dev, pipe, 0xa0, 0x40, address,
+ 0, fw_ptr, 0x800, HZ);
+ }
+
+ trace_firmware("Upload done, releasing device's CPU");
+
+ /* Now release the CPU. It will disconnect and reconnect later. */
+ pvr2_hdw_cpureset_assert(hdw,0);
+
+ kfree(fw_ptr);
+ release_firmware(fw_entry);
+
+ trace_firmware("Upload done (%d bytes sent)",ret);
+
+ /* We should have written 8192 bytes */
+ if (ret == 8192) {
+ hdw->fw1_state = FW1_STATE_RELOAD;
+ return 0;
+ }
+
+ return -EIO;
+}
+
+
+/*
+ * pvr2_upload_firmware2()
+ *
+ * This uploads encoder firmware on endpoint 2.
+ *
+ */
+
+int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
+{
+ const struct firmware *fw_entry = NULL;
+ void *fw_ptr;
+ unsigned int pipe, fw_len, fw_done;
+ int actual_length;
+ int ret = 0;
+ int fwidx;
+ static const char *fw_files[] = {
+ CX2341X_FIRM_ENC_FILENAME,
+ };
+
+ trace_firmware("pvr2_upload_firmware2");
+
+ ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
+ sizeof(fw_files)/sizeof(fw_files[0]),
+ fw_files);
+ if (ret < 0) return ret;
+ fwidx = ret;
+ ret = 0;
+ /* Since we're about to completely reinitialize the encoder,
+ invalidate our cached copy of its configuration state. Next
+ time we configure the encoder, then we'll fully configure it. */
+ hdw->enc_cur_valid = 0;
+
+ /* First prepare firmware loading */
+ ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
+ ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
+ ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
+ ret |= pvr2_hdw_cmd_deep_reset(hdw);
+ ret |= pvr2_write_register(hdw, 0xa064, 0x00000000); /*APU command*/
+ ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000408); /*gpio dir*/
+ ret |= pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000008); /*gpio output state*/
+ ret |= pvr2_write_register(hdw, 0x9058, 0xffffffed); /*VPU ctrl*/
+ ret |= pvr2_write_register(hdw, 0x9054, 0xfffffffd); /*reset hw blocks*/
+ ret |= pvr2_write_register(hdw, 0x07f8, 0x80000800); /*encoder SDRAM refresh*/
+ ret |= pvr2_write_register(hdw, 0x07fc, 0x0000001a); /*encoder SDRAM pre-charge*/
+ ret |= pvr2_write_register(hdw, 0x0700, 0x00000000); /*I2C clock*/
+ ret |= pvr2_write_register(hdw, 0xaa00, 0x00000000); /*unknown*/
+ ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
+ ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
+ ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
+ ret |= pvr2_write_u8(hdw, 0x52, 0);
+ ret |= pvr2_write_u16(hdw, 0x0600, 0);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "firmware2 upload prep failed, ret=%d",ret);
+ release_firmware(fw_entry);
+ return ret;
+ }
+
+ /* Now send firmware */
+
+ fw_len = fw_entry->size;
+
+ if (fw_len % FIRMWARE_CHUNK_SIZE) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "size of %s firmware"
+ " must be a multiple of 8192B",
+ fw_files[fwidx]);
+ release_firmware(fw_entry);
+ return -1;
+ }
+
+ fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
+ if (fw_ptr == NULL){
+ release_firmware(fw_entry);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "failed to allocate memory for firmware2 upload");
+ return -ENOMEM;
+ }
+
+ pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
+
+ for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
+ fw_done += FIRMWARE_CHUNK_SIZE ) {
+ int i;
+ memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
+ /* Usbsnoop log shows that we must swap bytes... */
+ for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
+ ((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
+
+ ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
+ FIRMWARE_CHUNK_SIZE,
+ &actual_length, HZ);
+ ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
+ }
+
+ trace_firmware("upload of %s : %i / %i ",
+ fw_files[fwidx],fw_done,fw_len);
+
+ kfree(fw_ptr);
+ release_firmware(fw_entry);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "firmware2 upload transfer failure");
+ return ret;
+ }
+
+ /* Finish upload */
+
+ ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
+ ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
+ ret |= pvr2_write_u16(hdw, 0x0600, 0);
+
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "firmware2 upload post-proc failure");
+ } else {
+ hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_FIRMWARE);
+ }
+ return ret;
+}
+
+
+#define FIRMWARE_RECOVERY_BITS \
+ ((1<<PVR2_SUBSYS_B_ENC_CFG) | \
+ (1<<PVR2_SUBSYS_B_ENC_RUN) | \
+ (1<<PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+ (1<<PVR2_SUBSYS_B_USBSTREAM_RUN))
+
+/*
+
+ This single function is key to pretty much everything. The pvrusb2
+ device can logically be viewed as a series of subsystems which can be
+ stopped / started or unconfigured / configured. To get things streaming,
+ one must configure everything and start everything, but there may be
+ various reasons over time to deconfigure something or stop something.
+ This function handles all of this activity. Everything EVERYWHERE that
+ must affect a subsystem eventually comes here to do the work.
+
+ The current state of all subsystems is represented by a single bit mask,
+ known as subsys_enabled_mask. The bit positions are defined by the
+ PVR2_SUBSYS_xxxx macros, with one subsystem per bit position. At any
+ time the set of configured or active subsystems can be queried just by
+ looking at that mask. To change bits in that mask, this function here
+ must be called. The "msk" argument indicates which bit positions to
+ change, and the "val" argument defines the new values for the positions
+ defined by "msk".
+
+ There is a priority ordering of starting / stopping things, and for
+ multiple requested changes, this function implements that ordering.
+ (Thus we will act on a request to load encoder firmware before we
+ configure the encoder.) In addition to priority ordering, there is a
+ recovery strategy implemented here. If a particular step fails and we
+ detect that failure, this function will clear the affected subsystem bits
+ and restart. Thus we have a means for recovering from a dead encoder:
+ Clear all bits that correspond to subsystems that we need to restart /
+ reconfigure and start over.
+
+*/
+static void pvr2_hdw_subsys_bit_chg_no_lock(struct pvr2_hdw *hdw,
+ unsigned long msk,
+ unsigned long val)
+{
+ unsigned long nmsk;
+ unsigned long vmsk;
+ int ret;
+ unsigned int tryCount = 0;
+
+ if (!hdw->flag_ok) return;
+
+ msk &= PVR2_SUBSYS_ALL;
+ nmsk = (hdw->subsys_enabled_mask & ~msk) | (val & msk);
+ nmsk &= PVR2_SUBSYS_ALL;
+
+ for (;;) {
+ tryCount++;
+ if (!((nmsk ^ hdw->subsys_enabled_mask) &
+ PVR2_SUBSYS_ALL)) break;
+ if (tryCount > 4) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Too many retries when configuring device;"
+ " giving up");
+ pvr2_hdw_render_useless(hdw);
+ break;
+ }
+ if (tryCount > 1) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Retrying device reconfiguration");
+ }
+ pvr2_trace(PVR2_TRACE_INIT,
+ "subsys mask changing 0x%lx:0x%lx"
+ " from 0x%lx to 0x%lx",
+ msk,val,hdw->subsys_enabled_mask,nmsk);
+
+ vmsk = (nmsk ^ hdw->subsys_enabled_mask) &
+ hdw->subsys_enabled_mask;
+ if (vmsk) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " pvr2_encoder_stop");
+ ret = pvr2_encoder_stop(hdw);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Error recovery initiated");
+ hdw->subsys_enabled_mask &=
+ ~FIRMWARE_RECOVERY_BITS;
+ continue;
+ }
+ }
+ if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " pvr2_hdw_cmd_usbstream(0)");
+ pvr2_hdw_cmd_usbstream(hdw,0);
+ }
+ if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " decoder disable");
+ if (hdw->decoder_ctrl) {
+ hdw->decoder_ctrl->enable(
+ hdw->decoder_ctrl->ctxt,0);
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING:"
+ " No decoder present");
+ }
+ hdw->subsys_enabled_mask &=
+ ~(1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+ }
+ if (vmsk & PVR2_SUBSYS_CFG_ALL) {
+ hdw->subsys_enabled_mask &=
+ ~(vmsk & PVR2_SUBSYS_CFG_ALL);
+ }
+ }
+ vmsk = (nmsk ^ hdw->subsys_enabled_mask) & nmsk;
+ if (vmsk) {
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_FIRMWARE)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " pvr2_upload_firmware2");
+ ret = pvr2_upload_firmware2(hdw);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failure uploading encoder"
+ " firmware");
+ pvr2_hdw_render_useless(hdw);
+ break;
+ }
+ }
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_CFG)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " pvr2_encoder_configure");
+ ret = pvr2_encoder_configure(hdw);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Error recovery initiated");
+ hdw->subsys_enabled_mask &=
+ ~FIRMWARE_RECOVERY_BITS;
+ continue;
+ }
+ }
+ if (vmsk & (1<<PVR2_SUBSYS_B_DIGITIZER_RUN)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " decoder enable");
+ if (hdw->decoder_ctrl) {
+ hdw->decoder_ctrl->enable(
+ hdw->decoder_ctrl->ctxt,!0);
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING:"
+ " No decoder present");
+ }
+ hdw->subsys_enabled_mask |=
+ (1<<PVR2_SUBSYS_B_DIGITIZER_RUN);
+ }
+ if (vmsk & (1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " pvr2_hdw_cmd_usbstream(1)");
+ pvr2_hdw_cmd_usbstream(hdw,!0);
+ }
+ if (vmsk & (1<<PVR2_SUBSYS_B_ENC_RUN)) {
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*---TRACE_CTL----*/"
+ " pvr2_encoder_start");
+ ret = pvr2_encoder_start(hdw);
+ if (ret) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Error recovery initiated");
+ hdw->subsys_enabled_mask &=
+ ~FIRMWARE_RECOVERY_BITS;
+ continue;
+ }
+ }
+ }
+ }
+}
+
+
+void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+ unsigned long msk,unsigned long val)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,msk,val);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *hdw)
+{
+ return hdw->subsys_enabled_mask;
+}
+
+
+unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *hdw)
+{
+ return hdw->subsys_stream_mask;
+}
+
+
+static void pvr2_hdw_subsys_stream_bit_chg_no_lock(struct pvr2_hdw *hdw,
+ unsigned long msk,
+ unsigned long val)
+{
+ unsigned long val2;
+ msk &= PVR2_SUBSYS_ALL;
+ val2 = ((hdw->subsys_stream_mask & ~msk) | (val & msk));
+ pvr2_trace(PVR2_TRACE_INIT,
+ "stream mask changing 0x%lx:0x%lx from 0x%lx to 0x%lx",
+ msk,val,hdw->subsys_stream_mask,val2);
+ hdw->subsys_stream_mask = val2;
+}
+
+
+void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+ unsigned long msk,
+ unsigned long val)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_hdw_subsys_stream_bit_chg_no_lock(hdw,msk,val);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+static int pvr2_hdw_set_streaming_no_lock(struct pvr2_hdw *hdw,int enableFl)
+{
+ if ((!enableFl) == !(hdw->flag_streaming_enabled)) return 0;
+ if (enableFl) {
+ pvr2_trace(PVR2_TRACE_START_STOP,
+ "/*--TRACE_STREAM--*/ enable");
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,~0);
+ } else {
+ pvr2_trace(PVR2_TRACE_START_STOP,
+ "/*--TRACE_STREAM--*/ disable");
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+ }
+ if (!hdw->flag_ok) return -EIO;
+ hdw->flag_streaming_enabled = enableFl != 0;
+ return 0;
+}
+
+
+int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
+{
+ return hdw->flag_streaming_enabled != 0;
+}
+
+
+int pvr2_hdw_set_streaming(struct pvr2_hdw *hdw,int enable_flag)
+{
+ int ret;
+ LOCK_TAKE(hdw->big_lock); do {
+ ret = pvr2_hdw_set_streaming_no_lock(hdw,enable_flag);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return ret;
+}
+
+
+static int pvr2_hdw_set_stream_type_no_lock(struct pvr2_hdw *hdw,
+ enum pvr2_config config)
+{
+ unsigned long sm = hdw->subsys_enabled_mask;
+ if (!hdw->flag_ok) return -EIO;
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,hdw->subsys_stream_mask,0);
+ hdw->config = config;
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,sm);
+ return 0;
+}
+
+
+int pvr2_hdw_set_stream_type(struct pvr2_hdw *hdw,enum pvr2_config config)
+{
+ int ret;
+ if (!hdw->flag_ok) return -EIO;
+ LOCK_TAKE(hdw->big_lock);
+ ret = pvr2_hdw_set_stream_type_no_lock(hdw,config);
+ LOCK_GIVE(hdw->big_lock);
+ return ret;
+}
+
+
+static int get_default_tuner_type(struct pvr2_hdw *hdw)
+{
+ int unit_number = hdw->unit_number;
+ int tp = -1;
+ if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ tp = tuner[unit_number];
+ }
+ if (tp < 0) return -EINVAL;
+ hdw->tuner_type = tp;
+ return 0;
+}
+
+
+static v4l2_std_id get_default_standard(struct pvr2_hdw *hdw)
+{
+ int unit_number = hdw->unit_number;
+ int tp = 0;
+ if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ tp = video_std[unit_number];
+ }
+ return tp;
+}
+
+
+static unsigned int get_default_error_tolerance(struct pvr2_hdw *hdw)
+{
+ int unit_number = hdw->unit_number;
+ int tp = 0;
+ if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ tp = tolerance[unit_number];
+ }
+ return tp;
+}
+
+
+static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
+{
+ /* Try a harmless request to fetch the eeprom's address over
+ endpoint 1. See what happens. Only the full FX2 image can
+ respond to this. If this probe fails then likely the FX2
+ firmware needs be loaded. */
+ int result;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = 0xeb;
+ result = pvr2_send_request_ex(hdw,HZ*1,!0,
+ hdw->cmd_buffer,1,
+ hdw->cmd_buffer,1);
+ if (result < 0) break;
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+ if (result) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Probe of device endpoint 1 result status %d",
+ result);
+ } else {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Probe of device endpoint 1 succeeded");
+ }
+ return result == 0;
+}
+
+static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw)
+{
+ char buf[40];
+ unsigned int bcnt;
+ v4l2_std_id std1,std2;
+
+ std1 = get_default_standard(hdw);
+
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Supported video standard(s) reported by eeprom: %.*s",
+ bcnt,buf);
+
+ hdw->std_mask_avail = hdw->std_mask_eeprom;
+
+ std2 = std1 & ~hdw->std_mask_avail;
+ if (std2) {
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Expanding supported video standards"
+ " to include: %.*s",
+ bcnt,buf);
+ hdw->std_mask_avail |= std2;
+ }
+
+ pvr2_hdw_internal_set_std_avail(hdw);
+
+ if (std1) {
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std1);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Initial video standard forced to %.*s",
+ bcnt,buf);
+ hdw->std_mask_cur = std1;
+ hdw->std_dirty = !0;
+ pvr2_hdw_internal_find_stdenum(hdw);
+ return;
+ }
+
+ if (hdw->std_enum_cnt > 1) {
+ // Autoselect the first listed standard
+ hdw->std_enum_cur = 1;
+ hdw->std_mask_cur = hdw->std_defs[hdw->std_enum_cur-1].id;
+ hdw->std_dirty = !0;
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Initial video standard auto-selected to %s",
+ hdw->std_defs[hdw->std_enum_cur-1].name);
+ return;
+ }
+
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Unable to select a viable initial video standard");
+}
+
+
+static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
+{
+ int ret;
+ unsigned int idx;
+ struct pvr2_ctrl *cptr;
+ int reloadFl = 0;
+ if (!reloadFl) {
+ reloadFl = (hdw->usb_intf->cur_altsetting->desc.bNumEndpoints
+ == 0);
+ if (reloadFl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "USB endpoint config looks strange"
+ "; possibly firmware needs to be loaded");
+ }
+ }
+ if (!reloadFl) {
+ reloadFl = !pvr2_hdw_check_firmware(hdw);
+ if (reloadFl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Check for FX2 firmware failed"
+ "; possibly firmware needs to be loaded");
+ }
+ }
+ if (reloadFl) {
+ if (pvr2_upload_firmware1(hdw) != 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failure uploading firmware1");
+ }
+ return;
+ }
+ hdw->fw1_state = FW1_STATE_OK;
+
+ if (initusbreset) {
+ pvr2_hdw_device_reset(hdw);
+ }
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ for (idx = 0; idx < pvr2_client_lists[hdw->hdw_type].cnt; idx++) {
+ request_module(pvr2_client_lists[hdw->hdw_type].lst[idx]);
+ }
+
+ pvr2_hdw_cmd_powerup(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ if (pvr2_upload_firmware2(hdw)){
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,"device unstable!!");
+ pvr2_hdw_render_useless(hdw);
+ return;
+ }
+
+ // This step MUST happen after the earlier powerup step.
+ pvr2_i2c_core_init(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ if (cptr->info->skip_init) continue;
+ if (!cptr->info->set_value) continue;
+ cptr->info->set_value(cptr,~0,cptr->info->default_value);
+ }
+
+ // Do not use pvr2_reset_ctl_endpoints() here. It is not
+ // thread-safe against the normal pvr2_send_request() mechanism.
+ // (We should make it thread safe).
+
+ ret = pvr2_hdw_get_eeprom_addr(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+ if (ret < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Unable to determine location of eeprom, skipping");
+ } else {
+ hdw->eeprom_addr = ret;
+ pvr2_eeprom_analyze(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+ }
+
+ pvr2_hdw_setup_std(hdw);
+
+ if (!get_default_tuner_type(hdw)) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "pvr2_hdw_setup: Tuner type overridden to %d",
+ hdw->tuner_type);
+ }
+
+ hdw->tuner_updated = !0;
+ pvr2_i2c_core_check_stale(hdw);
+ hdw->tuner_updated = 0;
+
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ pvr2_hdw_commit_ctl_internal(hdw);
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ hdw->vid_stream = pvr2_stream_create();
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+ pvr2_trace(PVR2_TRACE_INIT,
+ "pvr2_hdw_setup: video stream is %p",hdw->vid_stream);
+ if (hdw->vid_stream) {
+ idx = get_default_error_tolerance(hdw);
+ if (idx) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "pvr2_hdw_setup: video stream %p"
+ " setting tolerance %u",
+ hdw->vid_stream,idx);
+ }
+ pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev,
+ PVR2_VID_ENDPOINT,idx);
+ }
+
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ /* Make sure everything is up to date */
+ pvr2_i2c_core_sync(hdw);
+
+ if (!pvr2_hdw_dev_ok(hdw)) return;
+
+ hdw->flag_init_ok = !0;
+}
+
+
+int pvr2_hdw_setup(struct pvr2_hdw *hdw)
+{
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) begin",hdw);
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_hdw_setup_low(hdw);
+ pvr2_trace(PVR2_TRACE_INIT,
+ "pvr2_hdw_setup(hdw=%p) done, ok=%d init_ok=%d",
+ hdw,hdw->flag_ok,hdw->flag_init_ok);
+ if (pvr2_hdw_dev_ok(hdw)) {
+ if (pvr2_hdw_init_ok(hdw)) {
+ pvr2_trace(
+ PVR2_TRACE_INFO,
+ "Device initialization"
+ " completed successfully.");
+ break;
+ }
+ if (hdw->fw1_state == FW1_STATE_RELOAD) {
+ pvr2_trace(
+ PVR2_TRACE_INFO,
+ "Device microcontroller firmware"
+ " (re)loaded; it should now reset"
+ " and reconnect.");
+ break;
+ }
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Device initialization was not successful.");
+ if (hdw->fw1_state == FW1_STATE_MISSING) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Giving up since device"
+ " microcontroller firmware"
+ " appears to be missing.");
+ break;
+ }
+ }
+ if (procreload) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Attempting pvrusb2 recovery by reloading"
+ " primary firmware.");
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "If this works, device should disconnect"
+ " and reconnect in a sane state.");
+ hdw->fw1_state = FW1_STATE_UNKNOWN;
+ pvr2_upload_firmware1(hdw);
+ } else {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "***WARNING*** pvrusb2 device hardware"
+ " appears to be jammed"
+ " and I can't clear it.");
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "You might need to power cycle"
+ " the pvrusb2 device"
+ " in order to recover.");
+ }
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw);
+ return hdw->flag_init_ok;
+}
+
+
+/* Create and return a structure for interacting with the underlying
+ hardware */
+struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ const struct usb_device_id *devid)
+{
+ unsigned int idx,cnt1,cnt2;
+ struct pvr2_hdw *hdw;
+ unsigned int hdw_type;
+ int valid_std_mask;
+ struct pvr2_ctrl *cptr;
+ __u8 ifnum;
+ struct v4l2_queryctrl qctrl;
+ struct pvr2_ctl_info *ciptr;
+
+ hdw_type = devid - pvr2_device_table;
+ if (hdw_type >=
+ sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Bogus device type of %u reported",hdw_type);
+ return NULL;
+ }
+
+ hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
+ hdw,pvr2_device_names[hdw_type]);
+ if (!hdw) goto fail;
+ memset(hdw,0,sizeof(*hdw));
+ cx2341x_fill_defaults(&hdw->enc_ctl_state);
+
+ hdw->control_cnt = CTRLDEF_COUNT;
+ hdw->control_cnt += MPEGDEF_COUNT;
+ hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
+ GFP_KERNEL);
+ if (!hdw->controls) goto fail;
+ memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
+ hdw->hdw_type = hdw_type;
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ cptr->hdw = hdw;
+ }
+ for (idx = 0; idx < 32; idx++) {
+ hdw->std_mask_ptrs[idx] = hdw->std_mask_names[idx];
+ }
+ for (idx = 0; idx < CTRLDEF_COUNT; idx++) {
+ cptr = hdw->controls + idx;
+ cptr->info = control_defs+idx;
+ }
+ /* Define and configure additional controls from cx2341x module. */
+ hdw->mpeg_ctrl_info = kmalloc(
+ sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
+ if (!hdw->mpeg_ctrl_info) goto fail;
+ memset(hdw->mpeg_ctrl_info,0,
+ sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
+ for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
+ cptr = hdw->controls + idx + CTRLDEF_COUNT;
+ ciptr = &(hdw->mpeg_ctrl_info[idx].info);
+ ciptr->desc = hdw->mpeg_ctrl_info[idx].desc;
+ ciptr->name = mpeg_ids[idx].strid;
+ ciptr->v4l_id = mpeg_ids[idx].id;
+ ciptr->skip_init = !0;
+ ciptr->get_value = ctrl_cx2341x_get;
+ ciptr->get_v4lflags = ctrl_cx2341x_getv4lflags;
+ ciptr->is_dirty = ctrl_cx2341x_is_dirty;
+ if (!idx) ciptr->clear_dirty = ctrl_cx2341x_clear_dirty;
+ qctrl.id = ciptr->v4l_id;
+ cx2341x_ctrl_query(&hdw->enc_ctl_state,&qctrl);
+ if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) {
+ ciptr->set_value = ctrl_cx2341x_set;
+ }
+ strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name,
+ PVR2_CTLD_INFO_DESC_SIZE);
+ hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0;
+ ciptr->default_value = qctrl.default_value;
+ switch (qctrl.type) {
+ default:
+ case V4L2_CTRL_TYPE_INTEGER:
+ ciptr->type = pvr2_ctl_int;
+ ciptr->def.type_int.min_value = qctrl.minimum;
+ ciptr->def.type_int.max_value = qctrl.maximum;
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ ciptr->type = pvr2_ctl_bool;
+ break;
+ case V4L2_CTRL_TYPE_MENU:
+ ciptr->type = pvr2_ctl_enum;
+ ciptr->def.type_enum.value_names =
+ cx2341x_ctrl_get_menu(ciptr->v4l_id);
+ for (cnt1 = 0;
+ ciptr->def.type_enum.value_names[cnt1] != NULL;
+ cnt1++) { }
+ ciptr->def.type_enum.count = cnt1;
+ break;
+ }
+ cptr->info = ciptr;
+ }
+
+ // Initialize video standard enum dynamic control
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDENUM);
+ if (cptr) {
+ memcpy(&hdw->std_info_enum,cptr->info,
+ sizeof(hdw->std_info_enum));
+ cptr->info = &hdw->std_info_enum;
+
+ }
+ // Initialize control data regarding video standard masks
+ valid_std_mask = pvr2_std_get_usable();
+ for (idx = 0; idx < 32; idx++) {
+ if (!(valid_std_mask & (1 << idx))) continue;
+ cnt1 = pvr2_std_id_to_str(
+ hdw->std_mask_names[idx],
+ sizeof(hdw->std_mask_names[idx])-1,
+ 1 << idx);
+ hdw->std_mask_names[idx][cnt1] = 0;
+ }
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDAVAIL);
+ if (cptr) {
+ memcpy(&hdw->std_info_avail,cptr->info,
+ sizeof(hdw->std_info_avail));
+ cptr->info = &hdw->std_info_avail;
+ hdw->std_info_avail.def.type_bitmask.bit_names =
+ hdw->std_mask_ptrs;
+ hdw->std_info_avail.def.type_bitmask.valid_bits =
+ valid_std_mask;
+ }
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR);
+ if (cptr) {
+ memcpy(&hdw->std_info_cur,cptr->info,
+ sizeof(hdw->std_info_cur));
+ cptr->info = &hdw->std_info_cur;
+ hdw->std_info_cur.def.type_bitmask.bit_names =
+ hdw->std_mask_ptrs;
+ hdw->std_info_avail.def.type_bitmask.valid_bits =
+ valid_std_mask;
+ }
+
+ hdw->eeprom_addr = -1;
+ hdw->unit_number = -1;
+ hdw->v4l_minor_number = -1;
+ hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
+ if (!hdw->ctl_write_buffer) goto fail;
+ hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
+ if (!hdw->ctl_read_buffer) goto fail;
+ hdw->ctl_write_urb = usb_alloc_urb(0,GFP_KERNEL);
+ if (!hdw->ctl_write_urb) goto fail;
+ hdw->ctl_read_urb = usb_alloc_urb(0,GFP_KERNEL);
+ if (!hdw->ctl_read_urb) goto fail;
+
+ down(&pvr2_unit_sem); do {
+ for (idx = 0; idx < PVR_NUM; idx++) {
+ if (unit_pointers[idx]) continue;
+ hdw->unit_number = idx;
+ unit_pointers[idx] = hdw;
+ break;
+ }
+ } while (0); up(&pvr2_unit_sem);
+
+ cnt1 = 0;
+ cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"pvrusb2");
+ cnt1 += cnt2;
+ if (hdw->unit_number >= 0) {
+ cnt2 = scnprintf(hdw->name+cnt1,sizeof(hdw->name)-cnt1,"_%c",
+ ('a' + hdw->unit_number));
+ cnt1 += cnt2;
+ }
+ if (cnt1 >= sizeof(hdw->name)) cnt1 = sizeof(hdw->name)-1;
+ hdw->name[cnt1] = 0;
+
+ pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
+ hdw->unit_number,hdw->name);
+
+ hdw->tuner_type = -1;
+ hdw->flag_ok = !0;
+ /* Initialize the mask of subsystems that we will shut down when we
+ stop streaming. */
+ hdw->subsys_stream_mask = PVR2_SUBSYS_RUN_ALL;
+ hdw->subsys_stream_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+
+ pvr2_trace(PVR2_TRACE_INIT,"subsys_stream_mask: 0x%lx",
+ hdw->subsys_stream_mask);
+
+ hdw->usb_intf = intf;
+ hdw->usb_dev = interface_to_usbdev(intf);
+
+ ifnum = hdw->usb_intf->cur_altsetting->desc.bInterfaceNumber;
+ usb_set_interface(hdw->usb_dev,ifnum,0);
+
+ mutex_init(&hdw->ctl_lock_mutex);
+ mutex_init(&hdw->big_lock_mutex);
+
+ return hdw;
+ fail:
+ if (hdw) {
+ if (hdw->ctl_read_urb) usb_free_urb(hdw->ctl_read_urb);
+ if (hdw->ctl_write_urb) usb_free_urb(hdw->ctl_write_urb);
+ if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
+ if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
+ if (hdw->controls) kfree(hdw->controls);
+ if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+ kfree(hdw);
+ }
+ return NULL;
+}
+
+
+/* Remove _all_ associations between this driver and the underlying USB
+ layer. */
+static void pvr2_hdw_remove_usb_stuff(struct pvr2_hdw *hdw)
+{
+ if (hdw->flag_disconnected) return;
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_remove_usb_stuff: hdw=%p",hdw);
+ if (hdw->ctl_read_urb) {
+ usb_kill_urb(hdw->ctl_read_urb);
+ usb_free_urb(hdw->ctl_read_urb);
+ hdw->ctl_read_urb = NULL;
+ }
+ if (hdw->ctl_write_urb) {
+ usb_kill_urb(hdw->ctl_write_urb);
+ usb_free_urb(hdw->ctl_write_urb);
+ hdw->ctl_write_urb = NULL;
+ }
+ if (hdw->ctl_read_buffer) {
+ kfree(hdw->ctl_read_buffer);
+ hdw->ctl_read_buffer = NULL;
+ }
+ if (hdw->ctl_write_buffer) {
+ kfree(hdw->ctl_write_buffer);
+ hdw->ctl_write_buffer = NULL;
+ }
+ pvr2_hdw_render_useless_unlocked(hdw);
+ hdw->flag_disconnected = !0;
+ hdw->usb_dev = NULL;
+ hdw->usb_intf = NULL;
+}
+
+
+/* Destroy hardware interaction structure */
+void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
+{
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
+ if (hdw->fw_buffer) {
+ kfree(hdw->fw_buffer);
+ hdw->fw_buffer = NULL;
+ }
+ if (hdw->vid_stream) {
+ pvr2_stream_destroy(hdw->vid_stream);
+ hdw->vid_stream = NULL;
+ }
+ if (hdw->audio_stat) {
+ hdw->audio_stat->detach(hdw->audio_stat->ctxt);
+ }
+ if (hdw->decoder_ctrl) {
+ hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
+ }
+ pvr2_i2c_core_done(hdw);
+ pvr2_hdw_remove_usb_stuff(hdw);
+ down(&pvr2_unit_sem); do {
+ if ((hdw->unit_number >= 0) &&
+ (hdw->unit_number < PVR_NUM) &&
+ (unit_pointers[hdw->unit_number] == hdw)) {
+ unit_pointers[hdw->unit_number] = NULL;
+ }
+ } while (0); up(&pvr2_unit_sem);
+ if (hdw->controls) kfree(hdw->controls);
+ if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
+ if (hdw->std_defs) kfree(hdw->std_defs);
+ if (hdw->std_enum_names) kfree(hdw->std_enum_names);
+ kfree(hdw);
+}
+
+
+int pvr2_hdw_init_ok(struct pvr2_hdw *hdw)
+{
+ return hdw->flag_init_ok;
+}
+
+
+int pvr2_hdw_dev_ok(struct pvr2_hdw *hdw)
+{
+ return (hdw && hdw->flag_ok);
+}
+
+
+/* Called when hardware has been unplugged */
+void pvr2_hdw_disconnect(struct pvr2_hdw *hdw)
+{
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_disconnect(hdw=%p)",hdw);
+ LOCK_TAKE(hdw->big_lock);
+ LOCK_TAKE(hdw->ctl_lock);
+ pvr2_hdw_remove_usb_stuff(hdw);
+ LOCK_GIVE(hdw->ctl_lock);
+ LOCK_GIVE(hdw->big_lock);
+}
+
+
+// Attempt to autoselect an appropriate value for std_enum_cur given
+// whatever is currently in std_mask_cur
+static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw)
+{
+ unsigned int idx;
+ for (idx = 1; idx < hdw->std_enum_cnt; idx++) {
+ if (hdw->std_defs[idx-1].id == hdw->std_mask_cur) {
+ hdw->std_enum_cur = idx;
+ return;
+ }
+ }
+ hdw->std_enum_cur = 0;
+}
+
+
+// Calculate correct set of enumerated standards based on currently known
+// set of available standards bits.
+static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw)
+{
+ struct v4l2_standard *newstd;
+ unsigned int std_cnt;
+ unsigned int idx;
+
+ newstd = pvr2_std_create_enum(&std_cnt,hdw->std_mask_avail);
+
+ if (hdw->std_defs) {
+ kfree(hdw->std_defs);
+ hdw->std_defs = NULL;
+ }
+ hdw->std_enum_cnt = 0;
+ if (hdw->std_enum_names) {
+ kfree(hdw->std_enum_names);
+ hdw->std_enum_names = NULL;
+ }
+
+ if (!std_cnt) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Failed to identify any viable standards");
+ }
+ hdw->std_enum_names = kmalloc(sizeof(char *)*(std_cnt+1),GFP_KERNEL);
+ hdw->std_enum_names[0] = "none";
+ for (idx = 0; idx < std_cnt; idx++) {
+ hdw->std_enum_names[idx+1] =
+ newstd[idx].name;
+ }
+ // Set up the dynamic control for this standard
+ hdw->std_info_enum.def.type_enum.value_names = hdw->std_enum_names;
+ hdw->std_info_enum.def.type_enum.count = std_cnt+1;
+ hdw->std_defs = newstd;
+ hdw->std_enum_cnt = std_cnt+1;
+ hdw->std_enum_cur = 0;
+ hdw->std_info_cur.def.type_bitmask.valid_bits = hdw->std_mask_avail;
+}
+
+
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,
+ struct v4l2_standard *std,
+ unsigned int idx)
+{
+ int ret = -EINVAL;
+ if (!idx) return ret;
+ LOCK_TAKE(hdw->big_lock); do {
+ if (idx >= hdw->std_enum_cnt) break;
+ idx--;
+ memcpy(std,hdw->std_defs+idx,sizeof(*std));
+ ret = 0;
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return ret;
+}
+
+
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *hdw)
+{
+ return hdw->control_cnt;
+}
+
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *hdw,
+ unsigned int idx)
+{
+ if (idx >= hdw->control_cnt) return NULL;
+ return hdw->controls + idx;
+}
+
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *hdw,
+ unsigned int ctl_id)
+{
+ struct pvr2_ctrl *cptr;
+ unsigned int idx;
+ int i;
+
+ /* This could be made a lot more efficient, but for now... */
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ i = cptr->info->internal_id;
+ if (i && (i == ctl_id)) return cptr;
+ }
+ return NULL;
+}
+
+
+/* Given a V4L ID, retrieve the control structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *hdw,unsigned int ctl_id)
+{
+ struct pvr2_ctrl *cptr;
+ unsigned int idx;
+ int i;
+
+ /* This could be made a lot more efficient, but for now... */
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ i = cptr->info->v4l_id;
+ if (i && (i == ctl_id)) return cptr;
+ }
+ return NULL;
+}
+
+
+/* Given a V4L ID for its immediate predecessor, retrieve the control
+ structure associated with it. */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *hdw,
+ unsigned int ctl_id)
+{
+ struct pvr2_ctrl *cptr,*cp2;
+ unsigned int idx;
+ int i;
+
+ /* This could be made a lot more efficient, but for now... */
+ cp2 = NULL;
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ i = cptr->info->v4l_id;
+ if (!i) continue;
+ if (i <= ctl_id) continue;
+ if (cp2 && (cp2->info->v4l_id < i)) continue;
+ cp2 = cptr;
+ }
+ return cp2;
+ return NULL;
+}
+
+
+static const char *get_ctrl_typename(enum pvr2_ctl_type tp)
+{
+ switch (tp) {
+ case pvr2_ctl_int: return "integer";
+ case pvr2_ctl_enum: return "enum";
+ case pvr2_ctl_bool: return "boolean";
+ case pvr2_ctl_bitmask: return "bitmask";
+ }
+ return "";
+}
+
+
+/* Commit all control changes made up to this point. Subsystems can be
+ indirectly affected by these changes. For a given set of things being
+ committed, we'll clear the affected subsystem bits and then once we're
+ done committing everything we'll make a request to restore the subsystem
+ state(s) back to their previous value before this function was called.
+ Thus we can automatically reconfigure affected pieces of the driver as
+ controls are changed. */
+static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
+{
+ unsigned long saved_subsys_mask = hdw->subsys_enabled_mask;
+ unsigned long stale_subsys_mask = 0;
+ unsigned int idx;
+ struct pvr2_ctrl *cptr;
+ int value;
+ int commit_flag = 0;
+ char buf[100];
+ unsigned int bcnt,ccnt;
+
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ if (cptr->info->is_dirty == 0) continue;
+ if (!cptr->info->is_dirty(cptr)) continue;
+ if (!commit_flag) {
+ commit_flag = !0;
+ }
+
+ bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
+ cptr->info->name);
+ value = 0;
+ cptr->info->get_value(cptr,&value);
+ pvr2_ctrl_value_to_sym_internal(cptr,~0,value,
+ buf+bcnt,
+ sizeof(buf)-bcnt,&ccnt);
+ bcnt += ccnt;
+ bcnt += scnprintf(buf+bcnt,sizeof(buf)-bcnt," <%s>",
+ get_ctrl_typename(cptr->info->type));
+ pvr2_trace(PVR2_TRACE_CTL,
+ "/*--TRACE_COMMIT--*/ %.*s",
+ bcnt,buf);
+ }
+
+ if (!commit_flag) {
+ /* Nothing has changed */
+ return 0;
+ }
+
+ /* When video standard changes, reset the hres and vres values -
+ but if the user has pending changes there, then let the changes
+ take priority. */
+ if (hdw->std_dirty) {
+ /* Rewrite the vertical resolution to be appropriate to the
+ video standard that has been selected. */
+ int nvres;
+ if (hdw->std_mask_cur & V4L2_STD_525_60) {
+ nvres = 480;
+ } else {
+ nvres = 576;
+ }
+ if (nvres != hdw->res_ver_val) {
+ hdw->res_ver_val = nvres;
+ hdw->res_ver_dirty = !0;
+ }
+ }
+
+ if (hdw->std_dirty ||
+ 0) {
+ /* If any of this changes, then the encoder needs to be
+ reconfigured, and we need to reset the stream. */
+ stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
+ stale_subsys_mask |= hdw->subsys_stream_mask;
+ }
+
+ if (hdw->srate_dirty) {
+ /* Write new sample rate into control structure since
+ * the master copy is stale. We must track srate
+ * separate from the mpeg control structure because
+ * other logic also uses this value. */
+ struct v4l2_ext_controls cs;
+ struct v4l2_ext_control c1;
+ memset(&cs,0,sizeof(cs));
+ memset(&c1,0,sizeof(c1));
+ cs.controls = &c1;
+ cs.count = 1;
+ c1.id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ;
+ c1.value = hdw->srate_val;
+ cx2341x_ext_ctrls(&hdw->enc_ctl_state,&cs,VIDIOC_S_EXT_CTRLS);
+ }
+
+ /* Scan i2c core at this point - before we clear all the dirty
+ bits. Various parts of the i2c core will notice dirty bits as
+ appropriate and arrange to broadcast or directly send updates to
+ the client drivers in order to keep everything in sync */
+ pvr2_i2c_core_check_stale(hdw);
+
+ for (idx = 0; idx < hdw->control_cnt; idx++) {
+ cptr = hdw->controls + idx;
+ if (!cptr->info->clear_dirty) continue;
+ cptr->info->clear_dirty(cptr);
+ }
+
+ /* Now execute i2c core update */
+ pvr2_i2c_core_sync(hdw);
+
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,stale_subsys_mask,0);
+ pvr2_hdw_subsys_bit_chg_no_lock(hdw,~0,saved_subsys_mask);
+
+ return 0;
+}
+
+
+int pvr2_hdw_commit_ctl(struct pvr2_hdw *hdw)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_hdw_commit_ctl_internal(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return 0;
+}
+
+
+void pvr2_hdw_poll(struct pvr2_hdw *hdw)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ pvr2_i2c_core_sync(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *hdw,
+ void (*func)(void *),
+ void *data)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ hdw->poll_trigger_func = func;
+ hdw->poll_trigger_data = data;
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *hdw)
+{
+ if (hdw->poll_trigger_func) {
+ hdw->poll_trigger_func(hdw->poll_trigger_data);
+ }
+}
+
+/* Return name for this driver instance */
+const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
+{
+ return hdw->name;
+}
+
+
+/* Return bit mask indicating signal status */
+static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
+{
+ unsigned int msk = 0;
+ switch (hdw->input_val) {
+ case PVR2_CVAL_INPUT_TV:
+ case PVR2_CVAL_INPUT_RADIO:
+ if (hdw->decoder_ctrl &&
+ hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
+ msk |= PVR2_SIGNAL_OK;
+ if (hdw->audio_stat &&
+ hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
+ if (hdw->flag_stereo) {
+ msk |= PVR2_SIGNAL_STEREO;
+ }
+ if (hdw->flag_bilingual) {
+ msk |= PVR2_SIGNAL_SAP;
+ }
+ }
+ }
+ break;
+ default:
+ msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
+ }
+ return msk;
+}
+
+
+int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
+{
+ int result;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = 0x0b;
+ result = pvr2_send_request(hdw,
+ hdw->cmd_buffer,1,
+ hdw->cmd_buffer,1);
+ if (result < 0) break;
+ result = (hdw->cmd_buffer[0] != 0);
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+ return result;
+}
+
+
+/* Return bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
+{
+ unsigned int msk = 0;
+ LOCK_TAKE(hdw->big_lock); do {
+ msk = pvr2_hdw_get_signal_status_internal(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ return msk;
+}
+
+
+/* Get handle to video output stream */
+struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *hp)
+{
+ return hp->vid_stream;
+}
+
+
+void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw)
+{
+ int nr = pvr2_hdw_get_unit_number(hdw);
+ LOCK_TAKE(hdw->big_lock); do {
+ hdw->log_requested = !0;
+ printk(KERN_INFO "pvrusb2: ================= START STATUS CARD #%d =================\n", nr);
+ pvr2_i2c_core_check_stale(hdw);
+ hdw->log_requested = 0;
+ pvr2_i2c_core_sync(hdw);
+ pvr2_trace(PVR2_TRACE_INFO,"cx2341x config:");
+ cx2341x_log_status(&hdw->enc_ctl_state, "pvrusb2");
+ printk(KERN_INFO "pvrusb2: ================== END STATUS CARD #%d ==================\n", nr);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
+{
+ int ret;
+ u16 address;
+ unsigned int pipe;
+ LOCK_TAKE(hdw->big_lock); do {
+ if ((hdw->fw_buffer == 0) == !enable_flag) break;
+
+ if (!enable_flag) {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Cleaning up after CPU firmware fetch");
+ kfree(hdw->fw_buffer);
+ hdw->fw_buffer = NULL;
+ hdw->fw_size = 0;
+ /* Now release the CPU. It will disconnect and
+ reconnect later. */
+ pvr2_hdw_cpureset_assert(hdw,0);
+ break;
+ }
+
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Preparing to suck out CPU firmware");
+ hdw->fw_size = 0x2000;
+ hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
+ if (!hdw->fw_buffer) {
+ hdw->fw_size = 0;
+ break;
+ }
+
+ memset(hdw->fw_buffer,0,hdw->fw_size);
+
+ /* We have to hold the CPU during firmware upload. */
+ pvr2_hdw_cpureset_assert(hdw,1);
+
+ /* download the firmware from address 0000-1fff in 2048
+ (=0x800) bytes chunk. */
+
+ pvr2_trace(PVR2_TRACE_FIRMWARE,"Grabbing CPU firmware");
+ pipe = usb_rcvctrlpipe(hdw->usb_dev, 0);
+ for(address = 0; address < hdw->fw_size; address += 0x800) {
+ ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0xc0,
+ address,0,
+ hdw->fw_buffer+address,0x800,HZ);
+ if (ret < 0) break;
+ }
+
+ pvr2_trace(PVR2_TRACE_FIRMWARE,"Done grabbing CPU firmware");
+
+ } while (0); LOCK_GIVE(hdw->big_lock);
+}
+
+
+/* Return true if we're in a mode for retrieval CPU firmware */
+int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw)
+{
+ return hdw->fw_buffer != 0;
+}
+
+
+int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
+ char *buf,unsigned int cnt)
+{
+ int ret = -EINVAL;
+ LOCK_TAKE(hdw->big_lock); do {
+ if (!buf) break;
+ if (!cnt) break;
+
+ if (!hdw->fw_buffer) {
+ ret = -EIO;
+ break;
+ }
+
+ if (offs >= hdw->fw_size) {
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Read firmware data offs=%d EOF",
+ offs);
+ ret = 0;
+ break;
+ }
+
+ if (offs + cnt > hdw->fw_size) cnt = hdw->fw_size - offs;
+
+ memcpy(buf,hdw->fw_buffer+offs,cnt);
+
+ pvr2_trace(PVR2_TRACE_FIRMWARE,
+ "Read firmware data offs=%d cnt=%d",
+ offs,cnt);
+ ret = cnt;
+ } while (0); LOCK_GIVE(hdw->big_lock);
+
+ return ret;
+}
+
+
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
+{
+ return hdw->v4l_minor_number;
+}
+
+
+/* Store the v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
+{
+ hdw->v4l_minor_number = v;
+}
+
+
+static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct pvr2_hdw *hdw = urb->context;
+ hdw->ctl_write_pend_flag = 0;
+ if (hdw->ctl_read_pend_flag) return;
+ complete(&hdw->ctl_done);
+}
+
+
+static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct pvr2_hdw *hdw = urb->context;
+ hdw->ctl_read_pend_flag = 0;
+ if (hdw->ctl_write_pend_flag) return;
+ complete(&hdw->ctl_done);
+}
+
+
+static void pvr2_ctl_timeout(unsigned long data)
+{
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+ if (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
+ hdw->ctl_timeout_flag = !0;
+ if (hdw->ctl_write_pend_flag && hdw->ctl_write_urb) {
+ usb_unlink_urb(hdw->ctl_write_urb);
+ }
+ if (hdw->ctl_read_pend_flag && hdw->ctl_read_urb) {
+ usb_unlink_urb(hdw->ctl_read_urb);
+ }
+ }
+}
+
+
+/* Issue a command and get a response from the device. This extended
+ version includes a probe flag (which if set means that device errors
+ should not be logged or treated as fatal) and a timeout in jiffies.
+ This can be used to non-lethally probe the health of endpoint 1. */
+static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
+ unsigned int timeout,int probe_fl,
+ void *write_data,unsigned int write_len,
+ void *read_data,unsigned int read_len)
+{
+ unsigned int idx;
+ int status = 0;
+ struct timer_list timer;
+ if (!hdw->ctl_lock_held) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Attempted to execute control transfer"
+ " without lock!!");
+ return -EDEADLK;
+ }
+ if ((!hdw->flag_ok) && !probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Attempted to execute control transfer"
+ " when device not ok");
+ return -EIO;
+ }
+ if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) {
+ if (!probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Attempted to execute control transfer"
+ " when USB is disconnected");
+ }
+ return -ENOTTY;
+ }
+
+ /* Ensure that we have sane parameters */
+ if (!write_data) write_len = 0;
+ if (!read_data) read_len = 0;
+ if (write_len > PVR2_CTL_BUFFSIZE) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Attempted to execute %d byte"
+ " control-write transfer (limit=%d)",
+ write_len,PVR2_CTL_BUFFSIZE);
+ return -EINVAL;
+ }
+ if (read_len > PVR2_CTL_BUFFSIZE) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Attempted to execute %d byte"
+ " control-read transfer (limit=%d)",
+ write_len,PVR2_CTL_BUFFSIZE);
+ return -EINVAL;
+ }
+ if ((!write_len) && (!read_len)) {
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "Attempted to execute null control transfer?");
+ return -EINVAL;
+ }
+
+
+ hdw->cmd_debug_state = 1;
+ if (write_len) {
+ hdw->cmd_debug_code = ((unsigned char *)write_data)[0];
+ } else {
+ hdw->cmd_debug_code = 0;
+ }
+ hdw->cmd_debug_write_len = write_len;
+ hdw->cmd_debug_read_len = read_len;
+
+ /* Initialize common stuff */
+ init_completion(&hdw->ctl_done);
+ hdw->ctl_timeout_flag = 0;
+ hdw->ctl_write_pend_flag = 0;
+ hdw->ctl_read_pend_flag = 0;
+ init_timer(&timer);
+ timer.expires = jiffies + timeout;
+ timer.data = (unsigned long)hdw;
+ timer.function = pvr2_ctl_timeout;
+
+ if (write_len) {
+ hdw->cmd_debug_state = 2;
+ /* Transfer write data to internal buffer */
+ for (idx = 0; idx < write_len; idx++) {
+ hdw->ctl_write_buffer[idx] =
+ ((unsigned char *)write_data)[idx];
+ }
+ /* Initiate a write request */
+ usb_fill_bulk_urb(hdw->ctl_write_urb,
+ hdw->usb_dev,
+ usb_sndbulkpipe(hdw->usb_dev,
+ PVR2_CTL_WRITE_ENDPOINT),
+ hdw->ctl_write_buffer,
+ write_len,
+ pvr2_ctl_write_complete,
+ hdw);
+ hdw->ctl_write_urb->actual_length = 0;
+ hdw->ctl_write_pend_flag = !0;
+ status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL);
+ if (status < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to submit write-control"
+ " URB status=%d",status);
+ hdw->ctl_write_pend_flag = 0;
+ goto done;
+ }
+ }
+
+ if (read_len) {
+ hdw->cmd_debug_state = 3;
+ memset(hdw->ctl_read_buffer,0x43,read_len);
+ /* Initiate a read request */
+ usb_fill_bulk_urb(hdw->ctl_read_urb,
+ hdw->usb_dev,
+ usb_rcvbulkpipe(hdw->usb_dev,
+ PVR2_CTL_READ_ENDPOINT),
+ hdw->ctl_read_buffer,
+ read_len,
+ pvr2_ctl_read_complete,
+ hdw);
+ hdw->ctl_read_urb->actual_length = 0;
+ hdw->ctl_read_pend_flag = !0;
+ status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL);
+ if (status < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to submit read-control"
+ " URB status=%d",status);
+ hdw->ctl_read_pend_flag = 0;
+ goto done;
+ }
+ }
+
+ /* Start timer */
+ add_timer(&timer);
+
+ /* Now wait for all I/O to complete */
+ hdw->cmd_debug_state = 4;
+ while (hdw->ctl_write_pend_flag || hdw->ctl_read_pend_flag) {
+ wait_for_completion(&hdw->ctl_done);
+ }
+ hdw->cmd_debug_state = 5;
+
+ /* Stop timer */
+ del_timer_sync(&timer);
+
+ hdw->cmd_debug_state = 6;
+ status = 0;
+
+ if (hdw->ctl_timeout_flag) {
+ status = -ETIMEDOUT;
+ if (!probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Timed out control-write");
+ }
+ goto done;
+ }
+
+ if (write_len) {
+ /* Validate results of write request */
+ if ((hdw->ctl_write_urb->status != 0) &&
+ (hdw->ctl_write_urb->status != -ENOENT) &&
+ (hdw->ctl_write_urb->status != -ESHUTDOWN) &&
+ (hdw->ctl_write_urb->status != -ECONNRESET)) {
+ /* USB subsystem is reporting some kind of failure
+ on the write */
+ status = hdw->ctl_write_urb->status;
+ if (!probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "control-write URB failure,"
+ " status=%d",
+ status);
+ }
+ goto done;
+ }
+ if (hdw->ctl_write_urb->actual_length < write_len) {
+ /* Failed to write enough data */
+ status = -EIO;
+ if (!probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "control-write URB short,"
+ " expected=%d got=%d",
+ write_len,
+ hdw->ctl_write_urb->actual_length);
+ }
+ goto done;
+ }
+ }
+ if (read_len) {
+ /* Validate results of read request */
+ if ((hdw->ctl_read_urb->status != 0) &&
+ (hdw->ctl_read_urb->status != -ENOENT) &&
+ (hdw->ctl_read_urb->status != -ESHUTDOWN) &&
+ (hdw->ctl_read_urb->status != -ECONNRESET)) {
+ /* USB subsystem is reporting some kind of failure
+ on the read */
+ status = hdw->ctl_read_urb->status;
+ if (!probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "control-read URB failure,"
+ " status=%d",
+ status);
+ }
+ goto done;
+ }
+ if (hdw->ctl_read_urb->actual_length < read_len) {
+ /* Failed to read enough data */
+ status = -EIO;
+ if (!probe_fl) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "control-read URB short,"
+ " expected=%d got=%d",
+ read_len,
+ hdw->ctl_read_urb->actual_length);
+ }
+ goto done;
+ }
+ /* Transfer retrieved data out from internal buffer */
+ for (idx = 0; idx < read_len; idx++) {
+ ((unsigned char *)read_data)[idx] =
+ hdw->ctl_read_buffer[idx];
+ }
+ }
+
+ done:
+
+ hdw->cmd_debug_state = 0;
+ if ((status < 0) && (!probe_fl)) {
+ pvr2_hdw_render_useless_unlocked(hdw);
+ }
+ return status;
+}
+
+
+int pvr2_send_request(struct pvr2_hdw *hdw,
+ void *write_data,unsigned int write_len,
+ void *read_data,unsigned int read_len)
+{
+ return pvr2_send_request_ex(hdw,HZ*4,0,
+ write_data,write_len,
+ read_data,read_len);
+}
+
+int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
+{
+ int ret;
+
+ LOCK_TAKE(hdw->ctl_lock);
+
+ hdw->cmd_buffer[0] = 0x04; /* write register prefix */
+ PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
+ hdw->cmd_buffer[5] = 0;
+ hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
+ hdw->cmd_buffer[7] = reg & 0xff;
+
+
+ ret = pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 0);
+
+ LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+
+static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
+{
+ int ret = 0;
+
+ LOCK_TAKE(hdw->ctl_lock);
+
+ hdw->cmd_buffer[0] = 0x05; /* read register prefix */
+ hdw->cmd_buffer[1] = 0;
+ hdw->cmd_buffer[2] = 0;
+ hdw->cmd_buffer[3] = 0;
+ hdw->cmd_buffer[4] = 0;
+ hdw->cmd_buffer[5] = 0;
+ hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
+ hdw->cmd_buffer[7] = reg & 0xff;
+
+ ret |= pvr2_send_request(hdw, hdw->cmd_buffer, 8, hdw->cmd_buffer, 4);
+ *data = PVR2_COMPOSE_LE(hdw->cmd_buffer,0);
+
+ LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+
+static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
+{
+ int ret;
+
+ LOCK_TAKE(hdw->ctl_lock);
+
+ hdw->cmd_buffer[0] = (data >> 8) & 0xff;
+ hdw->cmd_buffer[1] = data & 0xff;
+
+ ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
+
+ LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+
+static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
+{
+ int ret;
+
+ LOCK_TAKE(hdw->ctl_lock);
+
+ hdw->cmd_buffer[0] = data;
+
+ ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
+
+ LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+
+static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
+{
+ if (!hdw->flag_ok) return;
+ pvr2_trace(PVR2_TRACE_INIT,"render_useless");
+ hdw->flag_ok = 0;
+ if (hdw->vid_stream) {
+ pvr2_stream_setup(hdw->vid_stream,NULL,0,0);
+ }
+ hdw->flag_streaming_enabled = 0;
+ hdw->subsys_enabled_mask = 0;
+}
+
+
+void pvr2_hdw_render_useless(struct pvr2_hdw *hdw)
+{
+ LOCK_TAKE(hdw->ctl_lock);
+ pvr2_hdw_render_useless_unlocked(hdw);
+ LOCK_GIVE(hdw->ctl_lock);
+}
+
+
+void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
+{
+ int ret;
+ pvr2_trace(PVR2_TRACE_INIT,"Performing a device reset...");
+ ret = usb_lock_device_for_reset(hdw->usb_dev,NULL);
+ if (ret == 1) {
+ ret = usb_reset_device(hdw->usb_dev);
+ usb_unlock_device(hdw->usb_dev);
+ } else {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to lock USB device ret=%d",ret);
+ }
+ if (init_pause_msec) {
+ pvr2_trace(PVR2_TRACE_INFO,
+ "Waiting %u msec for hardware to settle",
+ init_pause_msec);
+ msleep(init_pause_msec);
+ }
+
+}
+
+
+void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
+{
+ char da[1];
+ unsigned int pipe;
+ int ret;
+
+ if (!hdw->usb_dev) return;
+
+ pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val);
+
+ da[0] = val ? 0x01 : 0x00;
+
+ /* Write the CPUCS register on the 8051. The lsb of the register
+ is the reset bit; a 1 asserts reset while a 0 clears it. */
+ pipe = usb_sndctrlpipe(hdw->usb_dev, 0);
+ ret = usb_control_msg(hdw->usb_dev,pipe,0xa0,0x40,0xe600,0,da,1,HZ);
+ if (ret < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "cpureset_assert(%d) error=%d",val,ret);
+ pvr2_hdw_render_useless(hdw);
+ }
+}
+
+
+int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
+{
+ int status;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
+ hdw->flag_ok = !0;
+ hdw->cmd_buffer[0] = 0xdd;
+ status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+ return status;
+}
+
+
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
+{
+ int status;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
+ hdw->cmd_buffer[0] = 0xde;
+ status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+ return status;
+}
+
+
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
+{
+ if (!hdw->decoder_ctrl) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Unable to reset decoder: nothing attached");
+ return -ENOTTY;
+ }
+
+ if (!hdw->decoder_ctrl->force_reset) {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Unable to reset decoder: not implemented");
+ return -ENOTTY;
+ }
+
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Requesting decoder reset");
+ hdw->decoder_ctrl->force_reset(hdw->decoder_ctrl->ctxt);
+ return 0;
+}
+
+
+/* Stop / start video stream transport */
+static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
+{
+ int status;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
+ status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+ if (!status) {
+ hdw->subsys_enabled_mask =
+ ((hdw->subsys_enabled_mask &
+ ~(1<<PVR2_SUBSYS_B_USBSTREAM_RUN)) |
+ (runFl ? (1<<PVR2_SUBSYS_B_USBSTREAM_RUN) : 0));
+ }
+ return status;
+}
+
+
+void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+ struct pvr2_hdw_debug_info *ptr)
+{
+ ptr->big_lock_held = hdw->big_lock_held;
+ ptr->ctl_lock_held = hdw->ctl_lock_held;
+ ptr->flag_ok = hdw->flag_ok;
+ ptr->flag_disconnected = hdw->flag_disconnected;
+ ptr->flag_init_ok = hdw->flag_init_ok;
+ ptr->flag_streaming_enabled = hdw->flag_streaming_enabled;
+ ptr->subsys_flags = hdw->subsys_enabled_mask;
+ ptr->cmd_debug_state = hdw->cmd_debug_state;
+ ptr->cmd_code = hdw->cmd_debug_code;
+ ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
+ ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
+ ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
+ ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
+ ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
+ ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
+ ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
+}
+
+
+int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
+{
+ return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
+}
+
+
+int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *dp)
+{
+ return pvr2_read_register(hdw,PVR2_GPIO_OUT,dp);
+}
+
+
+int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *dp)
+{
+ return pvr2_read_register(hdw,PVR2_GPIO_IN,dp);
+}
+
+
+int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val)
+{
+ u32 cval,nval;
+ int ret;
+ if (~msk) {
+ ret = pvr2_read_register(hdw,PVR2_GPIO_DIR,&cval);
+ if (ret) return ret;
+ nval = (cval & ~msk) | (val & msk);
+ pvr2_trace(PVR2_TRACE_GPIO,
+ "GPIO direction changing 0x%x:0x%x"
+ " from 0x%x to 0x%x",
+ msk,val,cval,nval);
+ } else {
+ nval = val;
+ pvr2_trace(PVR2_TRACE_GPIO,
+ "GPIO direction changing to 0x%x",nval);
+ }
+ return pvr2_write_register(hdw,PVR2_GPIO_DIR,nval);
+}
+
+
+int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
+{
+ u32 cval,nval;
+ int ret;
+ if (~msk) {
+ ret = pvr2_read_register(hdw,PVR2_GPIO_OUT,&cval);
+ if (ret) return ret;
+ nval = (cval & ~msk) | (val & msk);
+ pvr2_trace(PVR2_TRACE_GPIO,
+ "GPIO output changing 0x%x:0x%x from 0x%x to 0x%x",
+ msk,val,cval,nval);
+ } else {
+ nval = val;
+ pvr2_trace(PVR2_TRACE_GPIO,
+ "GPIO output changing to 0x%x",nval);
+ }
+ return pvr2_write_register(hdw,PVR2_GPIO_OUT,nval);
+}
+
+
+/* Find I2C address of eeprom */
+static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
+{
+ int result;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = 0xeb;
+ result = pvr2_send_request(hdw,
+ hdw->cmd_buffer,1,
+ hdw->cmd_buffer,1);
+ if (result < 0) break;
+ result = hdw->cmd_buffer[0];
+ } while(0); LOCK_GIVE(hdw->ctl_lock);
+ return result;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
new file mode 100644
index 00000000000..fd931b5da49
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -0,0 +1,303 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_HDW_H
+#define __PVRUSB2_HDW_H
+
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+#include "pvrusb2-io.h"
+#include "pvrusb2-ctrl.h"
+
+
+/* Private internal control ids, look these up with
+ pvr2_hdw_get_ctrl_by_id() - these are NOT visible in V4L */
+#define PVR2_CID_STDENUM 1
+#define PVR2_CID_STDCUR 2
+#define PVR2_CID_STDAVAIL 3
+#define PVR2_CID_INPUT 4
+#define PVR2_CID_AUDIOMODE 5
+#define PVR2_CID_FREQUENCY 6
+#define PVR2_CID_HRES 7
+#define PVR2_CID_VRES 8
+
+/* Legal values for the INPUT state variable */
+#define PVR2_CVAL_INPUT_TV 0
+#define PVR2_CVAL_INPUT_SVIDEO 1
+#define PVR2_CVAL_INPUT_COMPOSITE 2
+#define PVR2_CVAL_INPUT_RADIO 3
+
+/* Values that pvr2_hdw_get_signal_status() returns */
+#define PVR2_SIGNAL_OK 0x0001
+#define PVR2_SIGNAL_STEREO 0x0002
+#define PVR2_SIGNAL_SAP 0x0004
+
+
+/* Subsystem definitions - these are various pieces that can be
+ independently stopped / started. Usually you don't want to mess with
+ this directly (let the driver handle things itself), but it is useful
+ for debugging. */
+#define PVR2_SUBSYS_B_ENC_FIRMWARE 0
+#define PVR2_SUBSYS_B_ENC_CFG 1
+#define PVR2_SUBSYS_B_DIGITIZER_RUN 2
+#define PVR2_SUBSYS_B_USBSTREAM_RUN 3
+#define PVR2_SUBSYS_B_ENC_RUN 4
+
+#define PVR2_SUBSYS_CFG_ALL ( \
+ (1 << PVR2_SUBSYS_B_ENC_FIRMWARE) | \
+ (1 << PVR2_SUBSYS_B_ENC_CFG) )
+#define PVR2_SUBSYS_RUN_ALL ( \
+ (1 << PVR2_SUBSYS_B_DIGITIZER_RUN) | \
+ (1 << PVR2_SUBSYS_B_USBSTREAM_RUN) | \
+ (1 << PVR2_SUBSYS_B_ENC_RUN) )
+#define PVR2_SUBSYS_ALL ( \
+ PVR2_SUBSYS_CFG_ALL | \
+ PVR2_SUBSYS_RUN_ALL )
+
+enum pvr2_config {
+ pvr2_config_empty,
+ pvr2_config_mpeg,
+ pvr2_config_vbi,
+ pvr2_config_radio,
+};
+
+const char *pvr2_config_get_name(enum pvr2_config);
+
+struct pvr2_hdw;
+
+/* Create and return a structure for interacting with the underlying
+ hardware */
+struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
+ const struct usb_device_id *devid);
+
+/* Poll for background activity (if any) */
+void pvr2_hdw_poll(struct pvr2_hdw *);
+
+/* Trigger a poll to take place later at a convenient time */
+void pvr2_hdw_poll_trigger_unlocked(struct pvr2_hdw *);
+
+/* Register a callback used to trigger a future poll */
+void pvr2_hdw_setup_poll_trigger(struct pvr2_hdw *,
+ void (*func)(void *),
+ void *data);
+
+/* Destroy hardware interaction structure */
+void pvr2_hdw_destroy(struct pvr2_hdw *);
+
+/* Set up the structure and attempt to put the device into a usable state.
+ This can be a time-consuming operation, which is why it is not done
+ internally as part of the create() step. Return value is exactly the
+ same as pvr2_hdw_init_ok(). */
+int pvr2_hdw_setup(struct pvr2_hdw *);
+
+/* Initialization succeeded */
+int pvr2_hdw_init_ok(struct pvr2_hdw *);
+
+/* Return true if in the ready (normal) state */
+int pvr2_hdw_dev_ok(struct pvr2_hdw *);
+
+/* Return small integer number [1..N] for logical instance number of this
+ device. This is useful for indexing array-valued module parameters. */
+int pvr2_hdw_get_unit_number(struct pvr2_hdw *);
+
+/* Get pointer to underlying USB device */
+struct usb_device *pvr2_hdw_get_dev(struct pvr2_hdw *);
+
+/* Retrieve serial number of device */
+unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *);
+
+/* Called when hardware has been unplugged */
+void pvr2_hdw_disconnect(struct pvr2_hdw *);
+
+/* Get the number of defined controls */
+unsigned int pvr2_hdw_get_ctrl_count(struct pvr2_hdw *);
+
+/* Retrieve a control handle given its index (0..count-1) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_index(struct pvr2_hdw *,unsigned int);
+
+/* Retrieve a control handle given its internal ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_by_id(struct pvr2_hdw *,unsigned int);
+
+/* Retrieve a control handle given its V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_v4l(struct pvr2_hdw *,unsigned int ctl_id);
+
+/* Retrieve a control handle given its immediate predecessor V4L ID (if any) */
+struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *,
+ unsigned int ctl_id);
+
+/* Commit all control changes made up to this point */
+int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
+
+/* Return name for this driver instance */
+const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
+
+/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
+unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
+
+/* Query device and see if it thinks it is on a high-speed USB link */
+int pvr2_hdw_is_hsm(struct pvr2_hdw *);
+
+/* Turn streaming on/off */
+int pvr2_hdw_set_streaming(struct pvr2_hdw *,int);
+
+/* Find out if streaming is on */
+int pvr2_hdw_get_streaming(struct pvr2_hdw *);
+
+/* Configure the type of stream to generate */
+int pvr2_hdw_set_stream_type(struct pvr2_hdw *, enum pvr2_config);
+
+/* Get handle to video output stream */
+struct pvr2_stream *pvr2_hdw_get_video_stream(struct pvr2_hdw *);
+
+/* Emit a video standard struct */
+int pvr2_hdw_get_stdenum_value(struct pvr2_hdw *hdw,struct v4l2_standard *std,
+ unsigned int idx);
+
+/* Enable / disable various pieces of hardware. Items to change are
+ identified by bit positions within msk, and new state for each item is
+ identified by corresponding bit positions within val. */
+void pvr2_hdw_subsys_bit_chg(struct pvr2_hdw *hdw,
+ unsigned long msk,unsigned long val);
+
+/* Retrieve mask indicating which pieces of hardware are currently enabled
+ / configured. */
+unsigned long pvr2_hdw_subsys_get(struct pvr2_hdw *);
+
+/* Adjust mask of what get shut down when streaming is stopped. This is a
+ debugging aid. */
+void pvr2_hdw_subsys_stream_bit_chg(struct pvr2_hdw *hdw,
+ unsigned long msk,unsigned long val);
+
+/* Retrieve mask indicating which pieces of hardware are disabled when
+ streaming is turned off. */
+unsigned long pvr2_hdw_subsys_stream_get(struct pvr2_hdw *);
+
+
+/* Enable / disable retrieval of CPU firmware. This must be enabled before
+ pvr2_hdw_cpufw_get() will function. Note that doing this may prevent
+ the device from running (and leaving this mode may imply a device
+ reset). */
+void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *, int enable_flag);
+
+/* Return true if we're in a mode for retrieval CPU firmware */
+int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
+
+/* Retrieve a piece of the CPU's firmware at the given offset. Return
+ value is the number of bytes retrieved or zero if we're past the end or
+ an error otherwise (e.g. if firmware retrieval is not enabled). */
+int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
+ char *buf,unsigned int cnt);
+
+/* Retrieve previously stored v4l minor device number */
+int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
+
+/* Store the v4l minor device number */
+void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+
+
+/* The following entry points are all lower level things you normally don't
+ want to worry about. */
+
+/* Issue a command and get a response from the device. LOTS of higher
+ level stuff is built on this. */
+int pvr2_send_request(struct pvr2_hdw *,
+ void *write_ptr,unsigned int write_len,
+ void *read_ptr,unsigned int read_len);
+
+/* Slightly higher level device communication functions. */
+int pvr2_write_register(struct pvr2_hdw *, u16, u32);
+
+/* Call if for any reason we can't talk to the hardware anymore - this will
+ cause the driver to stop flailing on the device. */
+void pvr2_hdw_render_useless(struct pvr2_hdw *);
+
+/* Set / clear 8051's reset bit */
+void pvr2_hdw_cpureset_assert(struct pvr2_hdw *,int);
+
+/* Execute a USB-commanded device reset */
+void pvr2_hdw_device_reset(struct pvr2_hdw *);
+
+/* Execute hard reset command (after this point it's likely that the
+ encoder will have to be reconfigured). This also clears the "useless"
+ state. */
+int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *);
+
+/* Execute simple reset command */
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
+
+/* Order decoder to reset */
+int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
+
+/* Direct manipulation of GPIO bits */
+int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_get_out(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_get_in(struct pvr2_hdw *hdw,u32 *);
+int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val);
+int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val);
+
+/* This data structure is specifically for the next function... */
+struct pvr2_hdw_debug_info {
+ int big_lock_held;
+ int ctl_lock_held;
+ int flag_ok;
+ int flag_disconnected;
+ int flag_init_ok;
+ int flag_streaming_enabled;
+ unsigned long subsys_flags;
+ int cmd_debug_state;
+ int cmd_debug_write_len;
+ int cmd_debug_read_len;
+ int cmd_debug_write_pend;
+ int cmd_debug_read_pend;
+ int cmd_debug_timeout;
+ int cmd_debug_rstatus;
+ int cmd_debug_wstatus;
+ unsigned char cmd_code;
+};
+
+/* Non-intrusively retrieve internal state info - this is useful for
+ diagnosing lockups. Note that this operation is completed without any
+ kind of locking and so it is not atomic and may yield inconsistent
+ results. This is *purely* a debugging aid. */
+void pvr2_hdw_get_debug_info(const struct pvr2_hdw *hdw,
+ struct pvr2_hdw_debug_info *);
+
+/* Cause modules to log their state once */
+void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
+
+/* Cause encoder firmware to be uploaded into the device. This is normally
+ done autonomously, but the interface is exported here because it is also
+ a debugging aid. */
+int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
+
+/* List of device types that we can match */
+extern struct usb_device_id pvr2_device_table[];
+
+#endif /* __PVRUSB2_HDW_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
new file mode 100644
index 00000000000..fbe6039aeb6
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+#include "pvrusb2-audio.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-video-v4l.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+#include "pvrusb2-cx2584x-v4l.h"
+#include "pvrusb2-wm8775.h"
+#endif
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+#define OP_STANDARD 0
+#define OP_BCSH 1
+#define OP_VOLUME 2
+#define OP_FREQ 3
+#define OP_AUDIORATE 4
+#define OP_SIZE 5
+#define OP_LOG 6
+
+static const struct pvr2_i2c_op * const ops[] = {
+ [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard,
+ [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh,
+ [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume,
+ [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency,
+ [OP_SIZE] = &pvr2_i2c_op_v4l2_size,
+ [OP_LOG] = &pvr2_i2c_op_v4l2_log,
+};
+
+void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+ int id;
+ id = cp->client->driver->id;
+ cp->ctl_mask = ((1 << OP_STANDARD) |
+ (1 << OP_BCSH) |
+ (1 << OP_VOLUME) |
+ (1 << OP_FREQ) |
+ (1 << OP_SIZE) |
+ (1 << OP_LOG));
+
+ if (id == I2C_DRIVERID_MSP3400) {
+ if (pvr2_i2c_msp3400_setup(hdw,cp)) {
+ return;
+ }
+ }
+ if (id == I2C_DRIVERID_TUNER) {
+ if (pvr2_i2c_tuner_setup(hdw,cp)) {
+ return;
+ }
+ }
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ if (id == I2C_DRIVERID_CX25840) {
+ if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
+ return;
+ }
+ }
+ if (id == I2C_DRIVERID_WM8775) {
+ if (pvr2_i2c_wm8775_setup(hdw,cp)) {
+ return;
+ }
+ }
+#endif
+ if (id == I2C_DRIVERID_SAA711X) {
+ if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
+ return;
+ }
+ }
+}
+
+
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
+{
+ if (idx >= sizeof(ops)/sizeof(ops[0])) return 0;
+ return ops[idx];
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
new file mode 100644
index 00000000000..8a9933dec91
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -0,0 +1,232 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "pvrusb2-i2c-cmd-v4l2.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+
+
+static void set_standard(struct pvr2_hdw *hdw)
+{
+ v4l2_std_id vs;
+ vs = hdw->std_mask_cur;
+ pvr2_trace(PVR2_TRACE_CHIPS,
+ "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
+
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
+}
+
+
+static int check_standard(struct pvr2_hdw *hdw)
+{
+ return hdw->std_dirty != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard = {
+ .check = check_standard,
+ .update = set_standard,
+ .name = "v4l2_standard",
+};
+
+
+static void set_bcsh(struct pvr2_hdw *hdw)
+{
+ struct v4l2_control ctrl;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_bcsh"
+ " b=%d c=%d s=%d h=%d",
+ hdw->brightness_val,hdw->contrast_val,
+ hdw->saturation_val,hdw->hue_val);
+ memset(&ctrl,0,sizeof(ctrl));
+ ctrl.id = V4L2_CID_BRIGHTNESS;
+ ctrl.value = hdw->brightness_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_CONTRAST;
+ ctrl.value = hdw->contrast_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_SATURATION;
+ ctrl.value = hdw->saturation_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_HUE;
+ ctrl.value = hdw->hue_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+}
+
+
+static int check_bcsh(struct pvr2_hdw *hdw)
+{
+ return (hdw->brightness_dirty ||
+ hdw->contrast_dirty ||
+ hdw->saturation_dirty ||
+ hdw->hue_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh = {
+ .check = check_bcsh,
+ .update = set_bcsh,
+ .name = "v4l2_bcsh",
+};
+
+
+static void set_volume(struct pvr2_hdw *hdw)
+{
+ struct v4l2_control ctrl;
+ pvr2_trace(PVR2_TRACE_CHIPS,
+ "i2c v4l2 set_volume"
+ "(vol=%d bal=%d bas=%d treb=%d mute=%d)",
+ hdw->volume_val,
+ hdw->balance_val,
+ hdw->bass_val,
+ hdw->treble_val,
+ hdw->mute_val);
+ memset(&ctrl,0,sizeof(ctrl));
+ ctrl.id = V4L2_CID_AUDIO_MUTE;
+ ctrl.value = hdw->mute_val ? 1 : 0;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_AUDIO_VOLUME;
+ ctrl.value = hdw->volume_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_AUDIO_BALANCE;
+ ctrl.value = hdw->balance_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_AUDIO_BASS;
+ ctrl.value = hdw->bass_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+ ctrl.id = V4L2_CID_AUDIO_TREBLE;
+ ctrl.value = hdw->treble_val;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_CTRL,&ctrl);
+}
+
+
+static int check_volume(struct pvr2_hdw *hdw)
+{
+ return (hdw->volume_dirty ||
+ hdw->balance_dirty ||
+ hdw->bass_dirty ||
+ hdw->treble_dirty ||
+ hdw->mute_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume = {
+ .check = check_volume,
+ .update = set_volume,
+ .name = "v4l2_volume",
+};
+
+
+static void set_frequency(struct pvr2_hdw *hdw)
+{
+ unsigned long fv;
+ struct v4l2_frequency freq;
+ fv = hdw->freqVal;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_freq(%lu)",fv);
+ memset(&freq,0,sizeof(freq));
+ freq.frequency = fv / 62500;
+ freq.tuner = 0;
+ freq.type = V4L2_TUNER_ANALOG_TV;
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_FREQUENCY,&freq);
+}
+
+
+static int check_frequency(struct pvr2_hdw *hdw)
+{
+ return hdw->freqDirty != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency = {
+ .check = check_frequency,
+ .update = set_frequency,
+ .name = "v4l2_freq",
+};
+
+
+static void set_size(struct pvr2_hdw *hdw)
+{
+ struct v4l2_format fmt;
+
+ memset(&fmt,0,sizeof(fmt));
+
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = hdw->res_hor_val;
+ fmt.fmt.pix.height = hdw->res_ver_val;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_size(%dx%d)",
+ fmt.fmt.pix.width,fmt.fmt.pix.height);
+
+ pvr2_i2c_core_cmd(hdw,VIDIOC_S_FMT,&fmt);
+}
+
+
+static int check_size(struct pvr2_hdw *hdw)
+{
+ return (hdw->res_hor_dirty || hdw->res_ver_dirty);
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = {
+ .check = check_size,
+ .update = set_size,
+ .name = "v4l2_size",
+};
+
+
+static void do_log(struct pvr2_hdw *hdw)
+{
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()");
+ pvr2_i2c_core_cmd(hdw,VIDIOC_LOG_STATUS,NULL);
+
+}
+
+
+static int check_log(struct pvr2_hdw *hdw)
+{
+ return hdw->log_requested != 0;
+}
+
+
+const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log = {
+ .check = check_log,
+ .update = do_log,
+ .name = "v4l2_log",
+};
+
+
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl)
+{
+ pvr2_i2c_client_cmd(cp,
+ (fl ? VIDIOC_STREAMON : VIDIOC_STREAMOFF),NULL);
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
new file mode 100644
index 00000000000..ecabddba1ec
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_CMD_V4L2_H
+#define __PVRUSB2_CMD_V4L2_H
+
+#include "pvrusb2-i2c-core.h"
+
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_standard;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size;
+extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log;
+
+void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *,int);
+
+#endif /* __PVRUSB2_CMD_V4L2_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
new file mode 100644
index 00000000000..7fca4798227
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -0,0 +1,941 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-i2c-core.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+
+#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
+
+/*
+
+ This module attempts to implement a compliant I2C adapter for the pvrusb2
+ device. By doing this we can then make use of existing functionality in
+ V4L (e.g. tuner.c) rather than rolling our own.
+
+*/
+
+static unsigned int i2c_scan = 0;
+module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+
+static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+ unsigned int detail,
+ char *buf,unsigned int maxlen);
+
+static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
+ u8 i2c_addr, /* I2C address we're talking to */
+ u8 *data, /* Data to write */
+ u16 length) /* Size of data to write */
+{
+ /* Return value - default 0 means success */
+ int ret;
+
+
+ if (!data) length = 0;
+ if (length > (sizeof(hdw->cmd_buffer) - 3)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Killing an I2C write to %u that is too large"
+ " (desired=%u limit=%u)",
+ i2c_addr,
+ length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
+ return -ENOTSUPP;
+ }
+
+ LOCK_TAKE(hdw->ctl_lock);
+
+ /* Clear the command buffer (likely to be paranoia) */
+ memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
+
+ /* Set up command buffer for an I2C write */
+ hdw->cmd_buffer[0] = 0x08; /* write prefix */
+ hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
+ hdw->cmd_buffer[2] = length; /* length of what follows */
+ if (length) memcpy(hdw->cmd_buffer + 3, data, length);
+
+ /* Do the operation */
+ ret = pvr2_send_request(hdw,
+ hdw->cmd_buffer,
+ length + 3,
+ hdw->cmd_buffer,
+ 1);
+ if (!ret) {
+ if (hdw->cmd_buffer[0] != 8) {
+ ret = -EIO;
+ if (hdw->cmd_buffer[0] != 7) {
+ trace_i2c("unexpected status"
+ " from i2_write[%d]: %d",
+ i2c_addr,hdw->cmd_buffer[0]);
+ }
+ }
+ }
+
+ LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
+ u8 i2c_addr, /* I2C address we're talking to */
+ u8 *data, /* Data to write */
+ u16 dlen, /* Size of data to write */
+ u8 *res, /* Where to put data we read */
+ u16 rlen) /* Amount of data to read */
+{
+ /* Return value - default 0 means success */
+ int ret;
+
+
+ if (!data) dlen = 0;
+ if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Killing an I2C read to %u that has wlen too large"
+ " (desired=%u limit=%u)",
+ i2c_addr,
+ dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
+ return -ENOTSUPP;
+ }
+ if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Killing an I2C read to %u that has rlen too large"
+ " (desired=%u limit=%u)",
+ i2c_addr,
+ rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
+ return -ENOTSUPP;
+ }
+
+ LOCK_TAKE(hdw->ctl_lock);
+
+ /* Clear the command buffer (likely to be paranoia) */
+ memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
+
+ /* Set up command buffer for an I2C write followed by a read */
+ hdw->cmd_buffer[0] = 0x09; /* read prefix */
+ hdw->cmd_buffer[1] = dlen; /* arg length */
+ hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
+ more byte (status). */
+ hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */
+ if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
+
+ /* Do the operation */
+ ret = pvr2_send_request(hdw,
+ hdw->cmd_buffer,
+ 4 + dlen,
+ hdw->cmd_buffer,
+ rlen + 1);
+ if (!ret) {
+ if (hdw->cmd_buffer[0] != 8) {
+ ret = -EIO;
+ if (hdw->cmd_buffer[0] != 7) {
+ trace_i2c("unexpected status"
+ " from i2_read[%d]: %d",
+ i2c_addr,hdw->cmd_buffer[0]);
+ }
+ }
+ }
+
+ /* Copy back the result */
+ if (res && rlen) {
+ if (ret) {
+ /* Error, just blank out the return buffer */
+ memset(res, 0, rlen);
+ } else {
+ memcpy(res, hdw->cmd_buffer + 1, rlen);
+ }
+ }
+
+ LOCK_GIVE(hdw->ctl_lock);
+
+ return ret;
+}
+
+/* This is the common low level entry point for doing I2C operations to the
+ hardware. */
+static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
+ u8 i2c_addr,
+ u8 *wdata,
+ u16 wlen,
+ u8 *rdata,
+ u16 rlen)
+{
+ if (!rdata) rlen = 0;
+ if (!wdata) wlen = 0;
+ if (rlen || !wlen) {
+ return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+ } else {
+ return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
+ }
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+
+/* This is a special entry point that is entered if an I2C operation is
+ attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
+ part doesn't work, but we know it is really there. So let's look for
+ the autodetect attempt and just return success if we see that. */
+static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
+ u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+ if (!(rlen || wlen)) {
+ // This is a probe attempt. Just let it succeed.
+ return 0;
+ }
+ return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+}
+
+/* This is a special entry point that is entered if an I2C operation is
+ attempted to a cx25840 chip on model 24xxx hardware. This chip can
+ sometimes wedge itself. Worse still, when this happens msp3400 can
+ falsely detect this part and then the system gets hosed up after msp3400
+ gets confused and dies. What we want to do here is try to keep msp3400
+ away and also try to notice if the chip is wedged and send a warning to
+ the system log. */
+static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
+ u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
+{
+ int ret;
+ unsigned int subaddr;
+ u8 wbuf[2];
+ int state = hdw->i2c_cx25840_hack_state;
+
+ if (!(rlen || wlen)) {
+ // Probe attempt - always just succeed and don't bother the
+ // hardware (this helps to make the state machine further
+ // down somewhat easier).
+ return 0;
+ }
+
+ if (state == 3) {
+ return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
+ }
+
+ /* We're looking for the exact pattern where the revision register
+ is being read. The cx25840 module will always look at the
+ revision register first. Any other pattern of access therefore
+ has to be a probe attempt from somebody else so we'll reject it.
+ Normally we could just let each client just probe the part
+ anyway, but when the cx25840 is wedged, msp3400 will get a false
+ positive and that just screws things up... */
+
+ if (wlen == 0) {
+ switch (state) {
+ case 1: subaddr = 0x0100; break;
+ case 2: subaddr = 0x0101; break;
+ default: goto fail;
+ }
+ } else if (wlen == 2) {
+ subaddr = (wdata[0] << 8) | wdata[1];
+ switch (subaddr) {
+ case 0x0100: state = 1; break;
+ case 0x0101: state = 2; break;
+ default: goto fail;
+ }
+ } else {
+ goto fail;
+ }
+ if (!rlen) goto success;
+ state = 0;
+ if (rlen != 1) goto fail;
+
+ /* If we get to here then we have a legitimate read for one of the
+ two revision bytes, so pass it through. */
+ wbuf[0] = subaddr >> 8;
+ wbuf[1] = subaddr;
+ ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
+
+ if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Detected a wedged cx25840 chip;"
+ " the device will not work.");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Try power cycling the pvrusb2 device.");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "WARNING: Disabling further access to the device"
+ " to prevent other foul-ups.");
+ // This blocks all further communication with the part.
+ hdw->i2c_func[0x44] = NULL;
+ pvr2_hdw_render_useless(hdw);
+ goto fail;
+ }
+
+ /* Success! */
+ pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
+ state = 3;
+
+ success:
+ hdw->i2c_cx25840_hack_state = state;
+ return 0;
+
+ fail:
+ hdw->i2c_cx25840_hack_state = state;
+ return -EIO;
+}
+
+#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
+
+/* This is a very, very limited I2C adapter implementation. We can only
+ support what we actually know will work on the device... */
+static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ int ret = -ENOTSUPP;
+ pvr2_i2c_func funcp = NULL;
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
+
+ if (!num) {
+ ret = -EINVAL;
+ goto done;
+ }
+ if ((msgs[0].flags & I2C_M_NOSTART)) {
+ trace_i2c("i2c refusing I2C_M_NOSTART");
+ goto done;
+ }
+ if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
+ funcp = hdw->i2c_func[msgs[0].addr];
+ }
+ if (!funcp) {
+ ret = -EIO;
+ goto done;
+ }
+
+ if (num == 1) {
+ if (msgs[0].flags & I2C_M_RD) {
+ /* Simple read */
+ u16 tcnt,bcnt,offs;
+ if (!msgs[0].len) {
+ /* Length == 0 read. This is a probe. */
+ if (funcp(hdw,msgs[0].addr,NULL,0,NULL,0)) {
+ ret = -EIO;
+ goto done;
+ }
+ ret = 1;
+ goto done;
+ }
+ /* If the read is short enough we'll do the whole
+ thing atomically. Otherwise we have no choice
+ but to break apart the reads. */
+ tcnt = msgs[0].len;
+ offs = 0;
+ while (tcnt) {
+ bcnt = tcnt;
+ if (bcnt > sizeof(hdw->cmd_buffer)-1) {
+ bcnt = sizeof(hdw->cmd_buffer)-1;
+ }
+ if (funcp(hdw,msgs[0].addr,NULL,0,
+ msgs[0].buf+offs,bcnt)) {
+ ret = -EIO;
+ goto done;
+ }
+ offs += bcnt;
+ tcnt -= bcnt;
+ }
+ ret = 1;
+ goto done;
+ } else {
+ /* Simple write */
+ ret = 1;
+ if (funcp(hdw,msgs[0].addr,
+ msgs[0].buf,msgs[0].len,NULL,0)) {
+ ret = -EIO;
+ }
+ goto done;
+ }
+ } else if (num == 2) {
+ if (msgs[0].addr != msgs[1].addr) {
+ trace_i2c("i2c refusing 2 phase transfer with"
+ " conflicting target addresses");
+ ret = -ENOTSUPP;
+ goto done;
+ }
+ if ((!((msgs[0].flags & I2C_M_RD))) &&
+ (msgs[1].flags & I2C_M_RD)) {
+ u16 tcnt,bcnt,wcnt,offs;
+ /* Write followed by atomic read. If the read
+ portion is short enough we'll do the whole thing
+ atomically. Otherwise we have no choice but to
+ break apart the reads. */
+ tcnt = msgs[1].len;
+ wcnt = msgs[0].len;
+ offs = 0;
+ while (tcnt || wcnt) {
+ bcnt = tcnt;
+ if (bcnt > sizeof(hdw->cmd_buffer)-1) {
+ bcnt = sizeof(hdw->cmd_buffer)-1;
+ }
+ if (funcp(hdw,msgs[0].addr,
+ msgs[0].buf,wcnt,
+ msgs[1].buf+offs,bcnt)) {
+ ret = -EIO;
+ goto done;
+ }
+ offs += bcnt;
+ tcnt -= bcnt;
+ wcnt = 0;
+ }
+ ret = 2;
+ goto done;
+ } else {
+ trace_i2c("i2c refusing complex transfer"
+ " read0=%d read1=%d",
+ (msgs[0].flags & I2C_M_RD),
+ (msgs[1].flags & I2C_M_RD));
+ }
+ } else {
+ trace_i2c("i2c refusing %d phase transfer",num);
+ }
+
+ done:
+ if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
+ unsigned int idx,offs,cnt;
+ for (idx = 0; idx < num; idx++) {
+ cnt = msgs[idx].len;
+ printk(KERN_INFO
+ "pvrusb2 i2c xfer %u/%u:"
+ " addr=0x%x len=%d %s%s",
+ idx+1,num,
+ msgs[idx].addr,
+ cnt,
+ (msgs[idx].flags & I2C_M_RD ?
+ "read" : "write"),
+ (msgs[idx].flags & I2C_M_NOSTART ?
+ " nostart" : ""));
+ if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
+ if (cnt > 8) cnt = 8;
+ printk(" [");
+ for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
+ if (offs) printk(" ");
+ printk("%02x",msgs[idx].buf[offs]);
+ }
+ if (offs < cnt) printk(" ...");
+ printk("]");
+ }
+ if (idx+1 == num) {
+ printk(" result=%d",ret);
+ }
+ printk("\n");
+ }
+ if (!num) {
+ printk(KERN_INFO
+ "pvrusb2 i2c xfer null transfer result=%d\n",
+ ret);
+ }
+ }
+ return ret;
+}
+
+static int pvr2_i2c_control(struct i2c_adapter *adapter,
+ unsigned int cmd, unsigned long arg)
+{
+ return 0;
+}
+
+static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA;
+}
+
+static int pvr2_i2c_core_singleton(struct i2c_client *cp,
+ unsigned int cmd,void *arg)
+{
+ int stat;
+ if (!cp) return -EINVAL;
+ if (!(cp->driver)) return -EINVAL;
+ if (!(cp->driver->command)) return -EINVAL;
+ if (!try_module_get(cp->driver->driver.owner)) return -EAGAIN;
+ stat = cp->driver->command(cp,cmd,arg);
+ module_put(cp->driver->driver.owner);
+ return stat;
+}
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *cp,unsigned int cmd,void *arg)
+{
+ int stat;
+ if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+ char buf[100];
+ unsigned int cnt;
+ cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+ buf,sizeof(buf));
+ pvr2_trace(PVR2_TRACE_I2C_CMD,
+ "i2c COMMAND (code=%u 0x%x) to %.*s",
+ cmd,cmd,cnt,buf);
+ }
+ stat = pvr2_i2c_core_singleton(cp->client,cmd,arg);
+ if (pvrusb2_debug & PVR2_TRACE_I2C_CMD) {
+ char buf[100];
+ unsigned int cnt;
+ cnt = pvr2_i2c_client_describe(cp,PVR2_I2C_DETAIL_DEBUG,
+ buf,sizeof(buf));
+ pvr2_trace(PVR2_TRACE_I2C_CMD,
+ "i2c COMMAND to %.*s (ret=%d)",cnt,buf,stat);
+ }
+ return stat;
+}
+
+int pvr2_i2c_core_cmd(struct pvr2_hdw *hdw,unsigned int cmd,void *arg)
+{
+ struct list_head *item,*nc;
+ struct pvr2_i2c_client *cp;
+ int stat = -EINVAL;
+
+ if (!hdw) return stat;
+
+ mutex_lock(&hdw->i2c_list_lock);
+ list_for_each_safe(item,nc,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (!cp->recv_enable) continue;
+ mutex_unlock(&hdw->i2c_list_lock);
+ stat = pvr2_i2c_client_cmd(cp,cmd,arg);
+ mutex_lock(&hdw->i2c_list_lock);
+ }
+ mutex_unlock(&hdw->i2c_list_lock);
+ return stat;
+}
+
+
+static int handler_check(struct pvr2_i2c_client *cp)
+{
+ struct pvr2_i2c_handler *hp = cp->handler;
+ if (!hp) return 0;
+ if (!hp->func_table->check) return 0;
+ return hp->func_table->check(hp->func_data) != 0;
+}
+
+#define BUFSIZE 500
+
+void pvr2_i2c_core_sync(struct pvr2_hdw *hdw)
+{
+ unsigned long msk;
+ unsigned int idx;
+ struct list_head *item,*nc;
+ struct pvr2_i2c_client *cp;
+
+ if (!hdw->i2c_linked) return;
+ if (!(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL)) {
+ return;
+ }
+ mutex_lock(&hdw->i2c_list_lock); do {
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync BEGIN");
+ if (hdw->i2c_pend_types & PVR2_I2C_PEND_DETECT) {
+ /* One or more I2C clients have attached since we
+ last synced. So scan the list and identify the
+ new clients. */
+ char *buf;
+ unsigned int cnt;
+ unsigned long amask = 0;
+ buf = kmalloc(BUFSIZE,GFP_KERNEL);
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_DETECT");
+ hdw->i2c_pend_types &= ~PVR2_I2C_PEND_DETECT;
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,
+ list);
+ if (!cp->detected_flag) {
+ cp->ctl_mask = 0;
+ pvr2_i2c_probe(hdw,cp);
+ cp->detected_flag = !0;
+ msk = cp->ctl_mask;
+ cnt = 0;
+ if (buf) {
+ cnt = pvr2_i2c_client_describe(
+ cp,
+ PVR2_I2C_DETAIL_ALL,
+ buf,BUFSIZE);
+ }
+ trace_i2c("Probed: %.*s",cnt,buf);
+ if (handler_check(cp)) {
+ hdw->i2c_pend_types |=
+ PVR2_I2C_PEND_CLIENT;
+ }
+ cp->pend_mask = msk;
+ hdw->i2c_pend_mask |= msk;
+ hdw->i2c_pend_types |=
+ PVR2_I2C_PEND_REFRESH;
+ }
+ amask |= cp->ctl_mask;
+ }
+ hdw->i2c_active_mask = amask;
+ if (buf) kfree(buf);
+ }
+ if (hdw->i2c_pend_types & PVR2_I2C_PEND_STALE) {
+ /* Need to do one or more global updates. Arrange
+ for this to happen. */
+ unsigned long m2;
+ pvr2_trace(PVR2_TRACE_I2C_CORE,
+ "i2c: PEND_STALE (0x%lx)",
+ hdw->i2c_stale_mask);
+ hdw->i2c_pend_types &= ~PVR2_I2C_PEND_STALE;
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,
+ list);
+ m2 = hdw->i2c_stale_mask;
+ m2 &= cp->ctl_mask;
+ m2 &= ~cp->pend_mask;
+ if (m2) {
+ pvr2_trace(PVR2_TRACE_I2C_CORE,
+ "i2c: cp=%p setting 0x%lx",
+ cp,m2);
+ cp->pend_mask |= m2;
+ }
+ }
+ hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+ hdw->i2c_stale_mask = 0;
+ hdw->i2c_pend_types |= PVR2_I2C_PEND_REFRESH;
+ }
+ if (hdw->i2c_pend_types & PVR2_I2C_PEND_CLIENT) {
+ /* One or more client handlers are asking for an
+ update. Run through the list of known clients
+ and update each one. */
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_CLIENT");
+ hdw->i2c_pend_types &= ~PVR2_I2C_PEND_CLIENT;
+ list_for_each_safe(item,nc,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,
+ list);
+ if (!cp->handler) continue;
+ if (!cp->handler->func_table->update) continue;
+ pvr2_trace(PVR2_TRACE_I2C_CORE,
+ "i2c: cp=%p update",cp);
+ mutex_unlock(&hdw->i2c_list_lock);
+ cp->handler->func_table->update(
+ cp->handler->func_data);
+ mutex_lock(&hdw->i2c_list_lock);
+ /* If client's update function set some
+ additional pending bits, account for that
+ here. */
+ if (cp->pend_mask & ~hdw->i2c_pend_mask) {
+ hdw->i2c_pend_mask |= cp->pend_mask;
+ hdw->i2c_pend_types |=
+ PVR2_I2C_PEND_REFRESH;
+ }
+ }
+ }
+ if (hdw->i2c_pend_types & PVR2_I2C_PEND_REFRESH) {
+ const struct pvr2_i2c_op *opf;
+ unsigned long pm;
+ /* Some actual updates are pending. Walk through
+ each update type and perform it. */
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: PEND_REFRESH"
+ " (0x%lx)",hdw->i2c_pend_mask);
+ hdw->i2c_pend_types &= ~PVR2_I2C_PEND_REFRESH;
+ pm = hdw->i2c_pend_mask;
+ hdw->i2c_pend_mask = 0;
+ for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+ if (!(pm & msk)) continue;
+ pm &= ~msk;
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,
+ struct pvr2_i2c_client,
+ list);
+ if (cp->pend_mask & msk) {
+ cp->pend_mask &= ~msk;
+ cp->recv_enable = !0;
+ } else {
+ cp->recv_enable = 0;
+ }
+ }
+ opf = pvr2_i2c_get_op(idx);
+ if (!opf) continue;
+ mutex_unlock(&hdw->i2c_list_lock);
+ opf->update(hdw);
+ mutex_lock(&hdw->i2c_list_lock);
+ }
+ }
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"i2c: core_sync END");
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+}
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *hdw)
+{
+ unsigned long msk,sm,pm;
+ unsigned int idx;
+ const struct pvr2_i2c_op *opf;
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ unsigned int pt = 0;
+
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale BEGIN");
+
+ pm = hdw->i2c_active_mask;
+ sm = 0;
+ for (idx = 0, msk = 1; pm; idx++, msk <<= 1) {
+ if (!(msk & pm)) continue;
+ pm &= ~msk;
+ opf = pvr2_i2c_get_op(idx);
+ if (!opf) continue;
+ if (opf->check(hdw)) {
+ sm |= msk;
+ }
+ }
+ if (sm) pt |= PVR2_I2C_PEND_STALE;
+
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (!handler_check(cp)) continue;
+ pt |= PVR2_I2C_PEND_CLIENT;
+ }
+
+ if (pt) {
+ mutex_lock(&hdw->i2c_list_lock); do {
+ hdw->i2c_pend_types |= pt;
+ hdw->i2c_stale_mask |= sm;
+ hdw->i2c_pend_mask |= hdw->i2c_stale_mask;
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ }
+
+ pvr2_trace(PVR2_TRACE_I2C_CORE,
+ "i2c: types=0x%x stale=0x%lx pend=0x%lx",
+ hdw->i2c_pend_types,
+ hdw->i2c_stale_mask,
+ hdw->i2c_pend_mask);
+ pvr2_trace(PVR2_TRACE_I2C_CORE,"pvr2_i2c_core_check_stale END");
+
+ return (hdw->i2c_pend_types & PVR2_I2C_PEND_ALL) != 0;
+}
+
+static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp,
+ unsigned int detail,
+ char *buf,unsigned int maxlen)
+{
+ unsigned int ccnt,bcnt;
+ int spcfl = 0;
+ const struct pvr2_i2c_op *opf;
+
+ ccnt = 0;
+ if (detail & PVR2_I2C_DETAIL_DEBUG) {
+ bcnt = scnprintf(buf,maxlen,
+ "ctxt=%p ctl_mask=0x%lx",
+ cp,cp->ctl_mask);
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ spcfl = !0;
+ }
+ bcnt = scnprintf(buf,maxlen,
+ "%s%s @ 0x%x",
+ (spcfl ? " " : ""),
+ cp->client->name,
+ cp->client->addr);
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ if ((detail & PVR2_I2C_DETAIL_HANDLER) &&
+ cp->handler && cp->handler->func_table->describe) {
+ bcnt = scnprintf(buf,maxlen," (");
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ bcnt = cp->handler->func_table->describe(
+ cp->handler->func_data,buf,maxlen);
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ bcnt = scnprintf(buf,maxlen,")");
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ }
+ if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) {
+ unsigned int idx;
+ unsigned long msk,sm;
+ int spcfl;
+ bcnt = scnprintf(buf,maxlen," [");
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ sm = 0;
+ spcfl = 0;
+ for (idx = 0, msk = 1; msk; idx++, msk <<= 1) {
+ if (!(cp->ctl_mask & msk)) continue;
+ opf = pvr2_i2c_get_op(idx);
+ if (opf) {
+ bcnt = scnprintf(buf,maxlen,"%s%s",
+ spcfl ? " " : "",
+ opf->name);
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ spcfl = !0;
+ } else {
+ sm |= msk;
+ }
+ }
+ if (sm) {
+ bcnt = scnprintf(buf,maxlen,"%s%lx",
+ idx != 0 ? " " : "",sm);
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ }
+ bcnt = scnprintf(buf,maxlen,"]");
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ }
+ return ccnt;
+}
+
+unsigned int pvr2_i2c_report(struct pvr2_hdw *hdw,
+ char *buf,unsigned int maxlen)
+{
+ unsigned int ccnt,bcnt;
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ ccnt = 0;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ bcnt = pvr2_i2c_client_describe(
+ cp,
+ (PVR2_I2C_DETAIL_HANDLER|
+ PVR2_I2C_DETAIL_CTLMASK),
+ buf,maxlen);
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ bcnt = scnprintf(buf,maxlen,"\n");
+ ccnt += bcnt; buf += bcnt; maxlen -= bcnt;
+ }
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ return ccnt;
+}
+
+static int pvr2_i2c_attach_inform(struct i2c_client *client)
+{
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+ struct pvr2_i2c_client *cp;
+ int fl = !(hdw->i2c_pend_types & PVR2_I2C_PEND_ALL);
+ cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ trace_i2c("i2c_attach [client=%s @ 0x%x ctxt=%p]",
+ client->name,
+ client->addr,cp);
+ if (!cp) return -ENOMEM;
+ memset(cp,0,sizeof(*cp));
+ INIT_LIST_HEAD(&cp->list);
+ cp->client = client;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ list_add_tail(&cp->list,&hdw->i2c_clients);
+ hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT;
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ if (fl) pvr2_hdw_poll_trigger_unlocked(hdw);
+ return 0;
+}
+
+static int pvr2_i2c_detach_inform(struct i2c_client *client)
+{
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)(client->adapter->algo_data);
+ struct pvr2_i2c_client *cp;
+ struct list_head *item,*nc;
+ unsigned long amask = 0;
+ int foundfl = 0;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ list_for_each_safe(item,nc,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (cp->client == client) {
+ trace_i2c("pvr2_i2c_detach"
+ " [client=%s @ 0x%x ctxt=%p]",
+ client->name,
+ client->addr,cp);
+ if (cp->handler &&
+ cp->handler->func_table->detach) {
+ cp->handler->func_table->detach(
+ cp->handler->func_data);
+ }
+ list_del(&cp->list);
+ kfree(cp);
+ foundfl = !0;
+ continue;
+ }
+ amask |= cp->ctl_mask;
+ }
+ hdw->i2c_active_mask = amask;
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ if (!foundfl) {
+ trace_i2c("pvr2_i2c_detach [client=%s @ 0x%x ctxt=<unknown>]",
+ client->name,
+ client->addr);
+ }
+ return 0;
+}
+
+static struct i2c_algorithm pvr2_i2c_algo_template = {
+ .master_xfer = pvr2_i2c_xfer,
+ .algo_control = pvr2_i2c_control,
+ .functionality = pvr2_i2c_functionality,
+};
+
+static struct i2c_adapter pvr2_i2c_adap_template = {
+ .owner = THIS_MODULE,
+ .class = I2C_CLASS_TV_ANALOG,
+ .id = I2C_HW_B_BT848,
+ .client_register = pvr2_i2c_attach_inform,
+ .client_unregister = pvr2_i2c_detach_inform,
+};
+
+static void do_i2c_scan(struct pvr2_hdw *hdw)
+{
+ struct i2c_msg msg[1];
+ int i,rc;
+ msg[0].addr = 0;
+ msg[0].flags = I2C_M_RD;
+ msg[0].len = 0;
+ msg[0].buf = NULL;
+ printk("%s: i2c scan beginning\n",hdw->name);
+ for (i = 0; i < 128; i++) {
+ msg[0].addr = i;
+ rc = i2c_transfer(&hdw->i2c_adap,msg,
+ sizeof(msg)/sizeof(msg[0]));
+ if (rc != 1) continue;
+ printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i);
+ }
+ printk("%s: i2c scan done.\n",hdw->name);
+}
+
+void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
+{
+ unsigned int idx;
+
+ // The default action for all possible I2C addresses is just to do
+ // the transfer normally.
+ for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
+ hdw->i2c_func[idx] = pvr2_i2c_basic_op;
+ }
+
+#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
+ // If however we're dealing with new hardware, insert some hacks in
+ // the I2C transfer stack to let things work better.
+ if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+ hdw->i2c_func[0x1b] = i2c_hack_wm8775;
+ hdw->i2c_func[0x44] = i2c_hack_cx25840;
+ }
+#endif
+
+ // Configure the adapter and set up everything else related to it.
+ memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
+ memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
+ strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
+ hdw->i2c_adap.algo = &hdw->i2c_algo;
+ hdw->i2c_adap.algo_data = hdw;
+ hdw->i2c_pend_mask = 0;
+ hdw->i2c_stale_mask = 0;
+ hdw->i2c_active_mask = 0;
+ INIT_LIST_HEAD(&hdw->i2c_clients);
+ mutex_init(&hdw->i2c_list_lock);
+ hdw->i2c_linked = !0;
+ i2c_add_adapter(&hdw->i2c_adap);
+ if (i2c_scan) do_i2c_scan(hdw);
+}
+
+void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
+{
+ if (hdw->i2c_linked) {
+ i2c_del_adapter(&hdw->i2c_adap);
+ hdw->i2c_linked = 0;
+ }
+}
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
new file mode 100644
index 00000000000..6d7e2524757
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.h
@@ -0,0 +1,93 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_I2C_CORE_H
+#define __PVRUSB2_I2C_CORE_H
+
+#include <linux/list.h>
+#include <linux/i2c.h>
+
+struct pvr2_hdw;
+struct pvr2_i2c_client;
+struct pvr2_i2c_handler;
+struct pvr2_i2c_handler_functions;
+struct pvr2_i2c_op;
+struct pvr2_i2c_op_functions;
+
+struct pvr2_i2c_client {
+ struct i2c_client *client;
+ struct pvr2_i2c_handler *handler;
+ struct list_head list;
+ int detected_flag;
+ int recv_enable;
+ unsigned long pend_mask;
+ unsigned long ctl_mask;
+};
+
+struct pvr2_i2c_handler {
+ void *func_data;
+ const struct pvr2_i2c_handler_functions *func_table;
+};
+
+struct pvr2_i2c_handler_functions {
+ void (*detach)(void *);
+ int (*check)(void *);
+ void (*update)(void *);
+ unsigned int (*describe)(void *,char *,unsigned int);
+};
+
+struct pvr2_i2c_op {
+ int (*check)(struct pvr2_hdw *);
+ void (*update)(struct pvr2_hdw *);
+ const char *name;
+};
+
+void pvr2_i2c_core_init(struct pvr2_hdw *);
+void pvr2_i2c_core_done(struct pvr2_hdw *);
+
+int pvr2_i2c_client_cmd(struct pvr2_i2c_client *,unsigned int cmd,void *arg);
+int pvr2_i2c_core_cmd(struct pvr2_hdw *,unsigned int cmd,void *arg);
+
+int pvr2_i2c_core_check_stale(struct pvr2_hdw *);
+void pvr2_i2c_core_sync(struct pvr2_hdw *);
+unsigned int pvr2_i2c_report(struct pvr2_hdw *,char *buf,unsigned int maxlen);
+#define PVR2_I2C_DETAIL_DEBUG 0x0001
+#define PVR2_I2C_DETAIL_HANDLER 0x0002
+#define PVR2_I2C_DETAIL_CTLMASK 0x0004
+#define PVR2_I2C_DETAIL_ALL (\
+ PVR2_I2C_DETAIL_DEBUG |\
+ PVR2_I2C_DETAIL_HANDLER |\
+ PVR2_I2C_DETAIL_CTLMASK)
+
+void pvr2_i2c_probe(struct pvr2_hdw *,struct pvr2_i2c_client *);
+const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx);
+
+#endif /* __PVRUSB2_I2C_CORE_H */
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
new file mode 100644
index 00000000000..1e393762546
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -0,0 +1,667 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-io.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+
+static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state);
+
+#define BUFFER_SIG 0x47653271
+
+// #define SANITY_CHECK_BUFFERS
+
+
+#ifdef SANITY_CHECK_BUFFERS
+#define BUFFER_CHECK(bp) do { \
+ if ((bp)->signature != BUFFER_SIG) { \
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, \
+ "Buffer %p is bad at %s:%d", \
+ (bp),__FILE__,__LINE__); \
+ pvr2_buffer_describe(bp,"BadSig"); \
+ BUG(); \
+ } \
+} while (0)
+#else
+#define BUFFER_CHECK(bp) do {} while(0)
+#endif
+
+struct pvr2_stream {
+ /* Buffers queued for reading */
+ struct list_head queued_list;
+ unsigned int q_count;
+ unsigned int q_bcount;
+ /* Buffers with retrieved data */
+ struct list_head ready_list;
+ unsigned int r_count;
+ unsigned int r_bcount;
+ /* Buffers available for use */
+ struct list_head idle_list;
+ unsigned int i_count;
+ unsigned int i_bcount;
+ /* Pointers to all buffers */
+ struct pvr2_buffer **buffers;
+ /* Array size of buffers */
+ unsigned int buffer_slot_count;
+ /* Total buffers actually in circulation */
+ unsigned int buffer_total_count;
+ /* Designed number of buffers to be in circulation */
+ unsigned int buffer_target_count;
+ /* Executed when ready list become non-empty */
+ pvr2_stream_callback callback_func;
+ void *callback_data;
+ /* Context for transfer endpoint */
+ struct usb_device *dev;
+ int endpoint;
+ /* Overhead for mutex enforcement */
+ spinlock_t list_lock;
+ struct mutex mutex;
+ /* Tracking state for tolerating errors */
+ unsigned int fail_count;
+ unsigned int fail_tolerance;
+};
+
+struct pvr2_buffer {
+ int id;
+ int signature;
+ enum pvr2_buffer_state state;
+ void *ptr; /* Pointer to storage area */
+ unsigned int max_count; /* Size of storage area */
+ unsigned int used_count; /* Amount of valid data in storage area */
+ int status; /* Transfer result status */
+ struct pvr2_stream *stream;
+ struct list_head list_overhead;
+ struct urb *purb;
+};
+
+static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st)
+{
+ switch (st) {
+ case pvr2_buffer_state_none: return "none";
+ case pvr2_buffer_state_idle: return "idle";
+ case pvr2_buffer_state_queued: return "queued";
+ case pvr2_buffer_state_ready: return "ready";
+ }
+ return "unknown";
+}
+
+#ifdef SANITY_CHECK_BUFFERS
+static void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg)
+{
+ pvr2_trace(PVR2_TRACE_INFO,
+ "buffer%s%s %p state=%s id=%d status=%d"
+ " stream=%p purb=%p sig=0x%x",
+ (msg ? " " : ""),
+ (msg ? msg : ""),
+ bp,
+ (bp ? pvr2_buffer_state_decode(bp->state) : "(invalid)"),
+ (bp ? bp->id : 0),
+ (bp ? bp->status : 0),
+ (bp ? bp->stream : NULL),
+ (bp ? bp->purb : NULL),
+ (bp ? bp->signature : 0));
+}
+#endif /* SANITY_CHECK_BUFFERS */
+
+static void pvr2_buffer_remove(struct pvr2_buffer *bp)
+{
+ unsigned int *cnt;
+ unsigned int *bcnt;
+ unsigned int ccnt;
+ struct pvr2_stream *sp = bp->stream;
+ switch (bp->state) {
+ case pvr2_buffer_state_idle:
+ cnt = &sp->i_count;
+ bcnt = &sp->i_bcount;
+ ccnt = bp->max_count;
+ break;
+ case pvr2_buffer_state_queued:
+ cnt = &sp->q_count;
+ bcnt = &sp->q_bcount;
+ ccnt = bp->max_count;
+ break;
+ case pvr2_buffer_state_ready:
+ cnt = &sp->r_count;
+ bcnt = &sp->r_bcount;
+ ccnt = bp->used_count;
+ break;
+ default:
+ return;
+ }
+ list_del_init(&bp->list_overhead);
+ (*cnt)--;
+ (*bcnt) -= ccnt;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/"
+ " bufferPool %8s dec cap=%07d cnt=%02d",
+ pvr2_buffer_state_decode(bp->state),*bcnt,*cnt);
+ bp->state = pvr2_buffer_state_none;
+}
+
+static void pvr2_buffer_set_none(struct pvr2_buffer *bp)
+{
+ unsigned long irq_flags;
+ struct pvr2_stream *sp;
+ BUFFER_CHECK(bp);
+ sp = bp->stream;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s",
+ bp,
+ pvr2_buffer_state_decode(bp->state),
+ pvr2_buffer_state_decode(pvr2_buffer_state_none));
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ pvr2_buffer_remove(bp);
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static int pvr2_buffer_set_ready(struct pvr2_buffer *bp)
+{
+ int fl;
+ unsigned long irq_flags;
+ struct pvr2_stream *sp;
+ BUFFER_CHECK(bp);
+ sp = bp->stream;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s",
+ bp,
+ pvr2_buffer_state_decode(bp->state),
+ pvr2_buffer_state_decode(pvr2_buffer_state_ready));
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ fl = (sp->r_count == 0);
+ pvr2_buffer_remove(bp);
+ list_add_tail(&bp->list_overhead,&sp->ready_list);
+ bp->state = pvr2_buffer_state_ready;
+ (sp->r_count)++;
+ sp->r_bcount += bp->used_count;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/"
+ " bufferPool %8s inc cap=%07d cnt=%02d",
+ pvr2_buffer_state_decode(bp->state),
+ sp->r_bcount,sp->r_count);
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+ return fl;
+}
+
+static void pvr2_buffer_set_idle(struct pvr2_buffer *bp)
+{
+ unsigned long irq_flags;
+ struct pvr2_stream *sp;
+ BUFFER_CHECK(bp);
+ sp = bp->stream;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s",
+ bp,
+ pvr2_buffer_state_decode(bp->state),
+ pvr2_buffer_state_decode(pvr2_buffer_state_idle));
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ pvr2_buffer_remove(bp);
+ list_add_tail(&bp->list_overhead,&sp->idle_list);
+ bp->state = pvr2_buffer_state_idle;
+ (sp->i_count)++;
+ sp->i_bcount += bp->max_count;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/"
+ " bufferPool %8s inc cap=%07d cnt=%02d",
+ pvr2_buffer_state_decode(bp->state),
+ sp->i_bcount,sp->i_count);
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static void pvr2_buffer_set_queued(struct pvr2_buffer *bp)
+{
+ unsigned long irq_flags;
+ struct pvr2_stream *sp;
+ BUFFER_CHECK(bp);
+ sp = bp->stream;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/ bufferState %p %6s --> %6s",
+ bp,
+ pvr2_buffer_state_decode(bp->state),
+ pvr2_buffer_state_decode(pvr2_buffer_state_queued));
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ pvr2_buffer_remove(bp);
+ list_add_tail(&bp->list_overhead,&sp->queued_list);
+ bp->state = pvr2_buffer_state_queued;
+ (sp->q_count)++;
+ sp->q_bcount += bp->max_count;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/"
+ " bufferPool %8s inc cap=%07d cnt=%02d",
+ pvr2_buffer_state_decode(bp->state),
+ sp->q_bcount,sp->q_count);
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
+static void pvr2_buffer_wipe(struct pvr2_buffer *bp)
+{
+ if (bp->state == pvr2_buffer_state_queued) {
+ usb_kill_urb(bp->purb);
+ }
+}
+
+static int pvr2_buffer_init(struct pvr2_buffer *bp,
+ struct pvr2_stream *sp,
+ unsigned int id)
+{
+ memset(bp,0,sizeof(*bp));
+ bp->signature = BUFFER_SIG;
+ bp->id = id;
+ pvr2_trace(PVR2_TRACE_BUF_POOL,
+ "/*---TRACE_FLOW---*/ bufferInit %p stream=%p",bp,sp);
+ bp->stream = sp;
+ bp->state = pvr2_buffer_state_none;
+ INIT_LIST_HEAD(&bp->list_overhead);
+ bp->purb = usb_alloc_urb(0,GFP_KERNEL);
+ if (! bp->purb) return -ENOMEM;
+#ifdef SANITY_CHECK_BUFFERS
+ pvr2_buffer_describe(bp,"create");
+#endif
+ return 0;
+}
+
+static void pvr2_buffer_done(struct pvr2_buffer *bp)
+{
+#ifdef SANITY_CHECK_BUFFERS
+ pvr2_buffer_describe(bp,"delete");
+#endif
+ pvr2_buffer_wipe(bp);
+ pvr2_buffer_set_none(bp);
+ bp->signature = 0;
+ bp->stream = NULL;
+ if (bp->purb) usb_free_urb(bp->purb);
+ pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/"
+ " bufferDone %p",bp);
+}
+
+static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+{
+ int ret;
+ unsigned int scnt;
+
+ /* Allocate buffers pointer array in multiples of 32 entries */
+ if (cnt == sp->buffer_total_count) return 0;
+
+ pvr2_trace(PVR2_TRACE_BUF_POOL,
+ "/*---TRACE_FLOW---*/ poolResize "
+ " stream=%p cur=%d adj=%+d",
+ sp,
+ sp->buffer_total_count,
+ cnt-sp->buffer_total_count);
+
+ scnt = cnt & ~0x1f;
+ if (cnt > scnt) scnt += 0x20;
+
+ if (cnt > sp->buffer_total_count) {
+ if (scnt > sp->buffer_slot_count) {
+ struct pvr2_buffer **nb;
+ nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+ if (!nb) return -ENOMEM;
+ if (sp->buffer_slot_count) {
+ memcpy(nb,sp->buffers,
+ sp->buffer_slot_count * sizeof(*nb));
+ kfree(sp->buffers);
+ }
+ sp->buffers = nb;
+ sp->buffer_slot_count = scnt;
+ }
+ while (sp->buffer_total_count < cnt) {
+ struct pvr2_buffer *bp;
+ bp = kmalloc(sizeof(*bp),GFP_KERNEL);
+ if (!bp) return -ENOMEM;
+ ret = pvr2_buffer_init(bp,sp,sp->buffer_total_count);
+ if (ret) {
+ kfree(bp);
+ return -ENOMEM;
+ }
+ sp->buffers[sp->buffer_total_count] = bp;
+ (sp->buffer_total_count)++;
+ pvr2_buffer_set_idle(bp);
+ }
+ } else {
+ while (sp->buffer_total_count > cnt) {
+ struct pvr2_buffer *bp;
+ bp = sp->buffers[sp->buffer_total_count - 1];
+ /* Paranoia */
+ sp->buffers[sp->buffer_total_count - 1] = NULL;
+ (sp->buffer_total_count)--;
+ pvr2_buffer_done(bp);
+ kfree(bp);
+ }
+ if (scnt < sp->buffer_slot_count) {
+ struct pvr2_buffer **nb = NULL;
+ if (scnt) {
+ nb = kmalloc(scnt * sizeof(*nb),GFP_KERNEL);
+ if (!nb) return -ENOMEM;
+ memcpy(nb,sp->buffers,scnt * sizeof(*nb));
+ }
+ kfree(sp->buffers);
+ sp->buffers = nb;
+ sp->buffer_slot_count = scnt;
+ }
+ }
+ return 0;
+}
+
+static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp)
+{
+ struct pvr2_buffer *bp;
+ unsigned int cnt;
+
+ if (sp->buffer_total_count == sp->buffer_target_count) return 0;
+
+ pvr2_trace(PVR2_TRACE_BUF_POOL,
+ "/*---TRACE_FLOW---*/"
+ " poolCheck stream=%p cur=%d tgt=%d",
+ sp,sp->buffer_total_count,sp->buffer_target_count);
+
+ if (sp->buffer_total_count < sp->buffer_target_count) {
+ return pvr2_stream_buffer_count(sp,sp->buffer_target_count);
+ }
+
+ cnt = 0;
+ while ((sp->buffer_total_count - cnt) > sp->buffer_target_count) {
+ bp = sp->buffers[sp->buffer_total_count - (cnt + 1)];
+ if (bp->state != pvr2_buffer_state_idle) break;
+ cnt++;
+ }
+ if (cnt) {
+ pvr2_stream_buffer_count(sp,sp->buffer_total_count - cnt);
+ }
+
+ return 0;
+}
+
+static void pvr2_stream_internal_flush(struct pvr2_stream *sp)
+{
+ struct list_head *lp;
+ struct pvr2_buffer *bp1;
+ while ((lp = sp->queued_list.next) != &sp->queued_list) {
+ bp1 = list_entry(lp,struct pvr2_buffer,list_overhead);
+ pvr2_buffer_wipe(bp1);
+ /* At this point, we should be guaranteed that no
+ completion callback may happen on this buffer. But it's
+ possible that it might have completed after we noticed
+ it but before we wiped it. So double check its status
+ here first. */
+ if (bp1->state != pvr2_buffer_state_queued) continue;
+ pvr2_buffer_set_idle(bp1);
+ }
+ if (sp->buffer_total_count != sp->buffer_target_count) {
+ pvr2_stream_achieve_buffer_count(sp);
+ }
+}
+
+static void pvr2_stream_init(struct pvr2_stream *sp)
+{
+ spin_lock_init(&sp->list_lock);
+ mutex_init(&sp->mutex);
+ INIT_LIST_HEAD(&sp->queued_list);
+ INIT_LIST_HEAD(&sp->ready_list);
+ INIT_LIST_HEAD(&sp->idle_list);
+}
+
+static void pvr2_stream_done(struct pvr2_stream *sp)
+{
+ mutex_lock(&sp->mutex); do {
+ pvr2_stream_internal_flush(sp);
+ pvr2_stream_buffer_count(sp,0);
+ } while (0); mutex_unlock(&sp->mutex);
+}
+
+static void buffer_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct pvr2_buffer *bp = urb->context;
+ struct pvr2_stream *sp;
+ unsigned long irq_flags;
+ BUFFER_CHECK(bp);
+ sp = bp->stream;
+ bp->used_count = 0;
+ bp->status = 0;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/ bufferComplete %p stat=%d cnt=%d",
+ bp,urb->status,urb->actual_length);
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ if ((!(urb->status)) ||
+ (urb->status == -ENOENT) ||
+ (urb->status == -ECONNRESET) ||
+ (urb->status == -ESHUTDOWN)) {
+ bp->used_count = urb->actual_length;
+ if (sp->fail_count) {
+ pvr2_trace(PVR2_TRACE_TOLERANCE,
+ "stream %p transfer ok"
+ " - fail count reset",sp);
+ sp->fail_count = 0;
+ }
+ } else if (sp->fail_count < sp->fail_tolerance) {
+ // We can tolerate this error, because we're below the
+ // threshold...
+ (sp->fail_count)++;
+ pvr2_trace(PVR2_TRACE_TOLERANCE,
+ "stream %p ignoring error %d"
+ " - fail count increased to %u",
+ sp,urb->status,sp->fail_count);
+ } else {
+ bp->status = urb->status;
+ }
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+ pvr2_buffer_set_ready(bp);
+ if (sp && sp->callback_func) {
+ sp->callback_func(sp->callback_data);
+ }
+}
+
+struct pvr2_stream *pvr2_stream_create(void)
+{
+ struct pvr2_stream *sp;
+ sp = kmalloc(sizeof(*sp),GFP_KERNEL);
+ if (!sp) return sp;
+ memset(sp,0,sizeof(*sp));
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_create: sp=%p",sp);
+ pvr2_stream_init(sp);
+ return sp;
+}
+
+void pvr2_stream_destroy(struct pvr2_stream *sp)
+{
+ if (!sp) return;
+ pvr2_trace(PVR2_TRACE_INIT,"pvr2_stream_destroy: sp=%p",sp);
+ pvr2_stream_done(sp);
+ kfree(sp);
+}
+
+void pvr2_stream_setup(struct pvr2_stream *sp,
+ struct usb_device *dev,
+ int endpoint,
+ unsigned int tolerance)
+{
+ mutex_lock(&sp->mutex); do {
+ pvr2_stream_internal_flush(sp);
+ sp->dev = dev;
+ sp->endpoint = endpoint;
+ sp->fail_tolerance = tolerance;
+ } while(0); mutex_unlock(&sp->mutex);
+}
+
+void pvr2_stream_set_callback(struct pvr2_stream *sp,
+ pvr2_stream_callback func,
+ void *data)
+{
+ unsigned long irq_flags;
+ mutex_lock(&sp->mutex); do {
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ sp->callback_data = data;
+ sp->callback_func = func;
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+ } while(0); mutex_unlock(&sp->mutex);
+}
+
+/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
+{
+ return sp->buffer_target_count;
+}
+
+int pvr2_stream_set_buffer_count(struct pvr2_stream *sp,unsigned int cnt)
+{
+ int ret;
+ if (sp->buffer_target_count == cnt) return 0;
+ mutex_lock(&sp->mutex); do {
+ sp->buffer_target_count = cnt;
+ ret = pvr2_stream_achieve_buffer_count(sp);
+ } while(0); mutex_unlock(&sp->mutex);
+ return ret;
+}
+
+struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *sp)
+{
+ struct list_head *lp = sp->idle_list.next;
+ if (lp == &sp->idle_list) return NULL;
+ return list_entry(lp,struct pvr2_buffer,list_overhead);
+}
+
+struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *sp)
+{
+ struct list_head *lp = sp->ready_list.next;
+ if (lp == &sp->ready_list) return NULL;
+ return list_entry(lp,struct pvr2_buffer,list_overhead);
+}
+
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id)
+{
+ if (id < 0) return NULL;
+ if (id >= sp->buffer_total_count) return NULL;
+ return sp->buffers[id];
+}
+
+int pvr2_stream_get_ready_count(struct pvr2_stream *sp)
+{
+ return sp->r_count;
+}
+
+void pvr2_stream_kill(struct pvr2_stream *sp)
+{
+ struct pvr2_buffer *bp;
+ mutex_lock(&sp->mutex); do {
+ pvr2_stream_internal_flush(sp);
+ while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) {
+ pvr2_buffer_set_idle(bp);
+ }
+ if (sp->buffer_total_count != sp->buffer_target_count) {
+ pvr2_stream_achieve_buffer_count(sp);
+ }
+ } while(0); mutex_unlock(&sp->mutex);
+}
+
+int pvr2_buffer_queue(struct pvr2_buffer *bp)
+{
+#undef SEED_BUFFER
+#ifdef SEED_BUFFER
+ unsigned int idx;
+ unsigned int val;
+#endif
+ int ret = 0;
+ struct pvr2_stream *sp;
+ if (!bp) return -EINVAL;
+ sp = bp->stream;
+ mutex_lock(&sp->mutex); do {
+ pvr2_buffer_wipe(bp);
+ if (!sp->dev) {
+ ret = -EIO;
+ break;
+ }
+ pvr2_buffer_set_queued(bp);
+#ifdef SEED_BUFFER
+ for (idx = 0; idx < (bp->max_count) / 4; idx++) {
+ val = bp->id << 24;
+ val |= idx;
+ ((unsigned int *)(bp->ptr))[idx] = val;
+ }
+#endif
+ bp->status = -EINPROGRESS;
+ usb_fill_bulk_urb(bp->purb, // struct urb *urb
+ sp->dev, // struct usb_device *dev
+ // endpoint (below)
+ usb_rcvbulkpipe(sp->dev,sp->endpoint),
+ bp->ptr, // void *transfer_buffer
+ bp->max_count, // int buffer_length
+ buffer_complete,
+ bp);
+ usb_submit_urb(bp->purb,GFP_KERNEL);
+ } while(0); mutex_unlock(&sp->mutex);
+ return ret;
+}
+
+int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt)
+{
+ int ret = 0;
+ unsigned long irq_flags;
+ struct pvr2_stream *sp;
+ if (!bp) return -EINVAL;
+ sp = bp->stream;
+ mutex_lock(&sp->mutex); do {
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ if (bp->state != pvr2_buffer_state_idle) {
+ ret = -EPERM;
+ } else {
+ bp->ptr = ptr;
+ bp->stream->i_bcount -= bp->max_count;
+ bp->max_count = cnt;
+ bp->stream->i_bcount += bp->max_count;
+ pvr2_trace(PVR2_TRACE_BUF_FLOW,
+ "/*---TRACE_FLOW---*/ bufferPool "
+ " %8s cap cap=%07d cnt=%02d",
+ pvr2_buffer_state_decode(
+ pvr2_buffer_state_idle),
+ bp->stream->i_bcount,bp->stream->i_count);
+ }
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+ } while(0); mutex_unlock(&sp->mutex);
+ return ret;
+}
+
+unsigned int pvr2_buffer_get_count(struct pvr2_buffer *bp)
+{
+ return bp->used_count;
+}
+
+int pvr2_buffer_get_status(struct pvr2_buffer *bp)
+{
+ return bp->status;
+}
+
+int pvr2_buffer_get_id(struct pvr2_buffer *bp)
+{
+ return bp->id;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
new file mode 100644
index 00000000000..93279cc2a35
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.h
@@ -0,0 +1,91 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_IO_H
+#define __PVRUSB2_IO_H
+
+#include <linux/usb.h>
+#include <linux/list.h>
+
+typedef void (*pvr2_stream_callback)(void *);
+
+enum pvr2_buffer_state {
+ pvr2_buffer_state_none = 0, // Not on any list
+ pvr2_buffer_state_idle = 1, // Buffer is ready to be used again
+ pvr2_buffer_state_queued = 2, // Buffer has been queued for filling
+ pvr2_buffer_state_ready = 3, // Buffer has data available
+};
+
+struct pvr2_stream;
+struct pvr2_buffer;
+
+/* Initialize / tear down stream structure */
+struct pvr2_stream *pvr2_stream_create(void);
+void pvr2_stream_destroy(struct pvr2_stream *);
+void pvr2_stream_setup(struct pvr2_stream *,
+ struct usb_device *dev,int endpoint,
+ unsigned int tolerance);
+void pvr2_stream_set_callback(struct pvr2_stream *,
+ pvr2_stream_callback func,
+ void *data);
+
+/* Query / set the nominal buffer count */
+int pvr2_stream_get_buffer_count(struct pvr2_stream *);
+int pvr2_stream_set_buffer_count(struct pvr2_stream *,unsigned int);
+
+/* Get a pointer to a buffer that is either idle, ready, or is specified
+ named. */
+struct pvr2_buffer *pvr2_stream_get_idle_buffer(struct pvr2_stream *);
+struct pvr2_buffer *pvr2_stream_get_ready_buffer(struct pvr2_stream *);
+struct pvr2_buffer *pvr2_stream_get_buffer(struct pvr2_stream *sp,int id);
+
+/* Find out how many buffers are idle or ready */
+int pvr2_stream_get_ready_count(struct pvr2_stream *);
+
+
+/* Kill all pending buffers and throw away any ready buffers as well */
+void pvr2_stream_kill(struct pvr2_stream *);
+
+/* Set up the actual storage for a buffer */
+int pvr2_buffer_set_buffer(struct pvr2_buffer *,void *ptr,unsigned int cnt);
+
+/* Find out size of data in the given ready buffer */
+unsigned int pvr2_buffer_get_count(struct pvr2_buffer *);
+
+/* Retrieve completion code for given ready buffer */
+int pvr2_buffer_get_status(struct pvr2_buffer *);
+
+/* Retrieve ID of given buffer */
+int pvr2_buffer_get_id(struct pvr2_buffer *);
+
+/* Start reading into given buffer (kill it if needed) */
+int pvr2_buffer_queue(struct pvr2_buffer *);
+
+#endif /* __PVRUSB2_IO_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
new file mode 100644
index 00000000000..b71f9a961f8
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -0,0 +1,510 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-ioread.h"
+#include "pvrusb2-debug.h"
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <asm/uaccess.h>
+
+#define BUFFER_COUNT 32
+#define BUFFER_SIZE PAGE_ALIGN(0x4000)
+
+struct pvr2_ioread {
+ struct pvr2_stream *stream;
+ char *buffer_storage[BUFFER_COUNT];
+ char *sync_key_ptr;
+ unsigned int sync_key_len;
+ unsigned int sync_buf_offs;
+ unsigned int sync_state;
+ unsigned int sync_trashed_count;
+ int enabled; // Streaming is on
+ int spigot_open; // OK to pass data to client
+ int stream_running; // Passing data to client now
+
+ /* State relevant to current buffer being read */
+ struct pvr2_buffer *c_buf;
+ char *c_data_ptr;
+ unsigned int c_data_len;
+ unsigned int c_data_offs;
+ struct mutex mutex;
+};
+
+static int pvr2_ioread_init(struct pvr2_ioread *cp)
+{
+ unsigned int idx;
+
+ cp->stream = NULL;
+ mutex_init(&cp->mutex);
+
+ for (idx = 0; idx < BUFFER_COUNT; idx++) {
+ cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
+ if (!(cp->buffer_storage[idx])) break;
+ }
+
+ if (idx < BUFFER_COUNT) {
+ // An allocation appears to have failed
+ for (idx = 0; idx < BUFFER_COUNT; idx++) {
+ if (!(cp->buffer_storage[idx])) continue;
+ kfree(cp->buffer_storage[idx]);
+ }
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void pvr2_ioread_done(struct pvr2_ioread *cp)
+{
+ unsigned int idx;
+
+ pvr2_ioread_setup(cp,NULL);
+ for (idx = 0; idx < BUFFER_COUNT; idx++) {
+ if (!(cp->buffer_storage[idx])) continue;
+ kfree(cp->buffer_storage[idx]);
+ }
+}
+
+struct pvr2_ioread *pvr2_ioread_create(void)
+{
+ struct pvr2_ioread *cp;
+ cp = kmalloc(sizeof(*cp),GFP_KERNEL);
+ if (!cp) return NULL;
+ pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
+ memset(cp,0,sizeof(*cp));
+ if (pvr2_ioread_init(cp) < 0) {
+ kfree(cp);
+ return NULL;
+ }
+ return cp;
+}
+
+void pvr2_ioread_destroy(struct pvr2_ioread *cp)
+{
+ if (!cp) return;
+ pvr2_ioread_done(cp);
+ pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
+ if (cp->sync_key_ptr) {
+ kfree(cp->sync_key_ptr);
+ cp->sync_key_ptr = NULL;
+ }
+ kfree(cp);
+}
+
+void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
+ const char *sync_key_ptr,
+ unsigned int sync_key_len)
+{
+ if (!cp) return;
+
+ if (!sync_key_ptr) sync_key_len = 0;
+ if ((sync_key_len == cp->sync_key_len) &&
+ ((!sync_key_len) ||
+ (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
+
+ if (sync_key_len != cp->sync_key_len) {
+ if (cp->sync_key_ptr) {
+ kfree(cp->sync_key_ptr);
+ cp->sync_key_ptr = NULL;
+ }
+ cp->sync_key_len = 0;
+ if (sync_key_len) {
+ cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
+ if (cp->sync_key_ptr) {
+ cp->sync_key_len = sync_key_len;
+ }
+ }
+ }
+ if (!cp->sync_key_len) return;
+ memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
+}
+
+static void pvr2_ioread_stop(struct pvr2_ioread *cp)
+{
+ if (!(cp->enabled)) return;
+ pvr2_trace(PVR2_TRACE_START_STOP,
+ "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
+ pvr2_stream_kill(cp->stream);
+ cp->c_buf = NULL;
+ cp->c_data_ptr = NULL;
+ cp->c_data_len = 0;
+ cp->c_data_offs = 0;
+ cp->enabled = 0;
+ cp->stream_running = 0;
+ cp->spigot_open = 0;
+ if (cp->sync_state) {
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/ sync_state <== 0");
+ cp->sync_state = 0;
+ }
+}
+
+static int pvr2_ioread_start(struct pvr2_ioread *cp)
+{
+ int stat;
+ struct pvr2_buffer *bp;
+ if (cp->enabled) return 0;
+ if (!(cp->stream)) return 0;
+ pvr2_trace(PVR2_TRACE_START_STOP,
+ "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
+ while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) {
+ stat = pvr2_buffer_queue(bp);
+ if (stat < 0) {
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/"
+ " pvr2_ioread_start id=%p"
+ " error=%d",
+ cp,stat);
+ pvr2_ioread_stop(cp);
+ return stat;
+ }
+ }
+ cp->enabled = !0;
+ cp->c_buf = NULL;
+ cp->c_data_ptr = NULL;
+ cp->c_data_len = 0;
+ cp->c_data_offs = 0;
+ cp->stream_running = 0;
+ if (cp->sync_key_len) {
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/ sync_state <== 1");
+ cp->sync_state = 1;
+ cp->sync_trashed_count = 0;
+ cp->sync_buf_offs = 0;
+ }
+ cp->spigot_open = 0;
+ return 0;
+}
+
+struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
+{
+ return cp->stream;
+}
+
+int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
+{
+ int ret;
+ unsigned int idx;
+ struct pvr2_buffer *bp;
+
+ mutex_lock(&cp->mutex); do {
+ if (cp->stream) {
+ pvr2_trace(PVR2_TRACE_START_STOP,
+ "/*---TRACE_READ---*/"
+ " pvr2_ioread_setup (tear-down) id=%p",cp);
+ pvr2_ioread_stop(cp);
+ pvr2_stream_kill(cp->stream);
+ if (pvr2_stream_get_buffer_count(cp->stream)) {
+ pvr2_stream_set_buffer_count(cp->stream,0);
+ }
+ cp->stream = NULL;
+ }
+ if (sp) {
+ pvr2_trace(PVR2_TRACE_START_STOP,
+ "/*---TRACE_READ---*/"
+ " pvr2_ioread_setup (setup) id=%p",cp);
+ pvr2_stream_kill(sp);
+ ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
+ if (ret < 0) return ret;
+ for (idx = 0; idx < BUFFER_COUNT; idx++) {
+ bp = pvr2_stream_get_buffer(sp,idx);
+ pvr2_buffer_set_buffer(bp,
+ cp->buffer_storage[idx],
+ BUFFER_SIZE);
+ }
+ cp->stream = sp;
+ }
+ } while (0); mutex_unlock(&cp->mutex);
+
+ return 0;
+}
+
+int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
+{
+ int ret = 0;
+ if ((!fl) == (!(cp->enabled))) return ret;
+
+ mutex_lock(&cp->mutex); do {
+ if (fl) {
+ ret = pvr2_ioread_start(cp);
+ } else {
+ pvr2_ioread_stop(cp);
+ }
+ } while (0); mutex_unlock(&cp->mutex);
+ return ret;
+}
+
+static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
+{
+ int stat;
+
+ while (cp->c_data_len <= cp->c_data_offs) {
+ if (cp->c_buf) {
+ // Flush out current buffer first.
+ stat = pvr2_buffer_queue(cp->c_buf);
+ if (stat < 0) {
+ // Streaming error...
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/"
+ " pvr2_ioread_read id=%p"
+ " queue_error=%d",
+ cp,stat);
+ pvr2_ioread_stop(cp);
+ return 0;
+ }
+ cp->c_buf = NULL;
+ cp->c_data_ptr = NULL;
+ cp->c_data_len = 0;
+ cp->c_data_offs = 0;
+ }
+ // Now get a freshly filled buffer.
+ cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
+ if (!cp->c_buf) break; // Nothing ready; done.
+ cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
+ if (!cp->c_data_len) {
+ // Nothing transferred. Was there an error?
+ stat = pvr2_buffer_get_status(cp->c_buf);
+ if (stat < 0) {
+ // Streaming error...
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/"
+ " pvr2_ioread_read id=%p"
+ " buffer_error=%d",
+ cp,stat);
+ pvr2_ioread_stop(cp);
+ // Give up.
+ return 0;
+ }
+ // Start over...
+ continue;
+ }
+ cp->c_data_offs = 0;
+ cp->c_data_ptr = cp->buffer_storage[
+ pvr2_buffer_get_id(cp->c_buf)];
+ }
+ return !0;
+}
+
+static void pvr2_ioread_filter(struct pvr2_ioread *cp)
+{
+ unsigned int idx;
+ if (!cp->enabled) return;
+ if (cp->sync_state != 1) return;
+
+ // Search the stream for our synchronization key. This is made
+ // complicated by the fact that in order to be honest with
+ // ourselves here we must search across buffer boundaries...
+ mutex_lock(&cp->mutex); while (1) {
+ // Ensure we have a buffer
+ if (!pvr2_ioread_get_buffer(cp)) break;
+ if (!cp->c_data_len) break;
+
+ // Now walk the buffer contents until we match the key or
+ // run out of buffer data.
+ for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
+ if (cp->sync_buf_offs >= cp->sync_key_len) break;
+ if (cp->c_data_ptr[idx] ==
+ cp->sync_key_ptr[cp->sync_buf_offs]) {
+ // Found the next key byte
+ (cp->sync_buf_offs)++;
+ } else {
+ // Whoops, mismatched. Start key over...
+ cp->sync_buf_offs = 0;
+ }
+ }
+
+ // Consume what we've walked through
+ cp->c_data_offs += idx;
+ cp->sync_trashed_count += idx;
+
+ // If we've found the key, then update state and get out.
+ if (cp->sync_buf_offs >= cp->sync_key_len) {
+ cp->sync_trashed_count -= cp->sync_key_len;
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/"
+ " sync_state <== 2 (skipped %u bytes)",
+ cp->sync_trashed_count);
+ cp->sync_state = 2;
+ cp->sync_buf_offs = 0;
+ break;
+ }
+
+ if (cp->c_data_offs < cp->c_data_len) {
+ // Sanity check - should NEVER get here
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "ERROR: pvr2_ioread filter sync problem"
+ " len=%u offs=%u",
+ cp->c_data_len,cp->c_data_offs);
+ // Get out so we don't get stuck in an infinite
+ // loop.
+ break;
+ }
+
+ continue; // (for clarity)
+ } mutex_unlock(&cp->mutex);
+}
+
+int pvr2_ioread_avail(struct pvr2_ioread *cp)
+{
+ int ret;
+ if (!(cp->enabled)) {
+ // Stream is not enabled; so this is an I/O error
+ return -EIO;
+ }
+
+ if (cp->sync_state == 1) {
+ pvr2_ioread_filter(cp);
+ if (cp->sync_state == 1) return -EAGAIN;
+ }
+
+ ret = 0;
+ if (cp->stream_running) {
+ if (!pvr2_stream_get_ready_count(cp->stream)) {
+ // No data available at all right now.
+ ret = -EAGAIN;
+ }
+ } else {
+ if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
+ // Haven't buffered up enough yet; try again later
+ ret = -EAGAIN;
+ }
+ }
+
+ if ((!(cp->spigot_open)) != (!(ret == 0))) {
+ cp->spigot_open = (ret == 0);
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/ data is %s",
+ cp->spigot_open ? "available" : "pending");
+ }
+
+ return ret;
+}
+
+int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
+{
+ unsigned int copied_cnt;
+ unsigned int bcnt;
+ const char *src;
+ int stat;
+ int ret = 0;
+ unsigned int req_cnt = cnt;
+
+ if (!cnt) {
+ pvr2_trace(PVR2_TRACE_TRAP,
+ "/*---TRACE_READ---*/ pvr2_ioread_read id=%p"
+ " ZERO Request? Returning zero.",cp);
+ return 0;
+ }
+
+ stat = pvr2_ioread_avail(cp);
+ if (stat < 0) return stat;
+
+ cp->stream_running = !0;
+
+ mutex_lock(&cp->mutex); do {
+
+ // Suck data out of the buffers and copy to the user
+ copied_cnt = 0;
+ if (!buf) cnt = 0;
+ while (1) {
+ if (!pvr2_ioread_get_buffer(cp)) {
+ ret = -EIO;
+ break;
+ }
+
+ if (!cnt) break;
+
+ if (cp->sync_state == 2) {
+ // We're repeating the sync key data into
+ // the stream.
+ src = cp->sync_key_ptr + cp->sync_buf_offs;
+ bcnt = cp->sync_key_len - cp->sync_buf_offs;
+ } else {
+ // Normal buffer copy
+ src = cp->c_data_ptr + cp->c_data_offs;
+ bcnt = cp->c_data_len - cp->c_data_offs;
+ }
+
+ if (!bcnt) break;
+
+ // Don't run past user's buffer
+ if (bcnt > cnt) bcnt = cnt;
+
+ if (copy_to_user(buf,src,bcnt)) {
+ // User supplied a bad pointer?
+ // Give up - this *will* cause data
+ // to be lost.
+ ret = -EFAULT;
+ break;
+ }
+ cnt -= bcnt;
+ buf += bcnt;
+ copied_cnt += bcnt;
+
+ if (cp->sync_state == 2) {
+ // Update offset inside sync key that we're
+ // repeating back out.
+ cp->sync_buf_offs += bcnt;
+ if (cp->sync_buf_offs >= cp->sync_key_len) {
+ // Consumed entire key; switch mode
+ // to normal.
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/"
+ " sync_state <== 0");
+ cp->sync_state = 0;
+ }
+ } else {
+ // Update buffer offset.
+ cp->c_data_offs += bcnt;
+ }
+ }
+
+ } while (0); mutex_unlock(&cp->mutex);
+
+ if (!ret) {
+ if (copied_cnt) {
+ // If anything was copied, return that count
+ ret = copied_cnt;
+ } else {
+ // Nothing copied; suggest to caller that another
+ // attempt should be tried again later
+ ret = -EAGAIN;
+ }
+ }
+
+ pvr2_trace(PVR2_TRACE_DATA_FLOW,
+ "/*---TRACE_READ---*/ pvr2_ioread_read"
+ " id=%p request=%d result=%d",
+ cp,req_cnt,ret);
+ return ret;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.h b/drivers/media/video/pvrusb2/pvrusb2-ioread.h
new file mode 100644
index 00000000000..1d362f83358
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_IOREAD_H
+#define __PVRUSB2_IOREAD_H
+
+#include "pvrusb2-io.h"
+
+struct pvr2_ioread;
+
+struct pvr2_ioread *pvr2_ioread_create(void);
+void pvr2_ioread_destroy(struct pvr2_ioread *);
+int pvr2_ioread_setup(struct pvr2_ioread *,struct pvr2_stream *);
+struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *);
+void pvr2_ioread_set_sync_key(struct pvr2_ioread *,
+ const char *sync_key_ptr,
+ unsigned int sync_key_len);
+int pvr2_ioread_set_enabled(struct pvr2_ioread *,int fl);
+int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt);
+int pvr2_ioread_avail(struct pvr2_ioread *);
+
+#endif /* __PVRUSB2_IOREAD_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
new file mode 100644
index 00000000000..8f1a5afdd34
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -0,0 +1,172 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/smp_lock.h>
+#include <linux/usb.h>
+#include <linux/videodev2.h>
+
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-context.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-v4l2.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+#include "pvrusb2-sysfs.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+#define DRIVER_AUTHOR "Mike Isely <isely@pobox.com>"
+#define DRIVER_DESC "Hauppauge WinTV-PVR-USB2 MPEG2 Encoder/Tuner"
+#define DRIVER_VERSION "V4L in-tree version"
+
+#define DEFAULT_DEBUG_MASK (PVR2_TRACE_ERROR_LEGS| \
+ PVR2_TRACE_INFO| \
+ PVR2_TRACE_TOLERANCE| \
+ PVR2_TRACE_TRAP| \
+ 0)
+
+int pvrusb2_debug = DEFAULT_DEBUG_MASK;
+
+module_param_named(debug,pvrusb2_debug,int,S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug trace mask");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+static struct pvr2_sysfs_class *class_ptr = NULL;
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+static void pvr_setup_attach(struct pvr2_context *pvr)
+{
+ /* Create association with v4l layer */
+ pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+ pvr2_sysfs_create(pvr,class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+}
+
+static int pvr_probe(struct usb_interface *intf,
+ const struct usb_device_id *devid)
+{
+ struct pvr2_context *pvr;
+
+ /* Create underlying hardware interface */
+ pvr = pvr2_context_create(intf,devid,pvr_setup_attach);
+ if (!pvr) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Failed to create hdw handler");
+ return -ENOMEM;
+ }
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_probe(pvr=%p)",pvr);
+
+ usb_set_intfdata(intf, pvr);
+
+ return 0;
+}
+
+/*
+ * pvr_disconnect()
+ *
+ */
+static void pvr_disconnect(struct usb_interface *intf)
+{
+ struct pvr2_context *pvr = usb_get_intfdata(intf);
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) BEGIN",pvr);
+
+ usb_set_intfdata (intf, NULL);
+ pvr2_context_disconnect(pvr);
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_disconnect(pvr=%p) DONE",pvr);
+
+}
+
+static struct usb_driver pvr_driver = {
+ .name = "pvrusb2",
+ .id_table = pvr2_device_table,
+ .probe = pvr_probe,
+ .disconnect = pvr_disconnect
+};
+
+/*
+ * pvr_init() / pvr_exit()
+ *
+ * This code is run to initialize/exit the driver.
+ *
+ */
+static int __init pvr_init(void)
+{
+ int ret;
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+ class_ptr = pvr2_sysfs_class_create();
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+ ret = usb_register(&pvr_driver);
+
+ if (ret == 0)
+ info(DRIVER_DESC " : " DRIVER_VERSION);
+ if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
+ pvrusb2_debug,pvrusb2_debug);
+
+ return ret;
+}
+
+static void __exit pvr_exit(void)
+{
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_exit");
+
+#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
+ pvr2_sysfs_class_destroy(class_ptr);
+#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+ usb_deregister(&pvr_driver);
+}
+
+module_init(pvr_init);
+module_exit(pvr_exit);
+
+/* Mike Isely <mcisely@pobox.com> 11-Mar-2006: See pvrusb2-hdw.c for
+ MODULE_DEVICE_TABLE(). We have to declare that attribute there
+ because that's where the device table actually is now and it seems
+ that certain gcc configurations get angry if MODULE_DEVICE_TABLE()
+ is used on what ends up being an external symbol. */
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
new file mode 100644
index 00000000000..f95c598ff62
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -0,0 +1,408 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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 "pvrusb2-std.h"
+#include "pvrusb2-debug.h"
+#include <asm/string.h>
+#include <linux/slab.h>
+
+struct std_name {
+ const char *name;
+ v4l2_std_id id;
+};
+
+
+#define CSTD_PAL \
+ (V4L2_STD_PAL_B| \
+ V4L2_STD_PAL_B1| \
+ V4L2_STD_PAL_G| \
+ V4L2_STD_PAL_H| \
+ V4L2_STD_PAL_I| \
+ V4L2_STD_PAL_D| \
+ V4L2_STD_PAL_D1| \
+ V4L2_STD_PAL_K| \
+ V4L2_STD_PAL_M| \
+ V4L2_STD_PAL_N| \
+ V4L2_STD_PAL_Nc| \
+ V4L2_STD_PAL_60)
+
+#define CSTD_NTSC \
+ (V4L2_STD_NTSC_M| \
+ V4L2_STD_NTSC_M_JP| \
+ V4L2_STD_NTSC_M_KR| \
+ V4L2_STD_NTSC_443)
+
+#define CSTD_SECAM \
+ (V4L2_STD_SECAM_B| \
+ V4L2_STD_SECAM_D| \
+ V4L2_STD_SECAM_G| \
+ V4L2_STD_SECAM_H| \
+ V4L2_STD_SECAM_K| \
+ V4L2_STD_SECAM_K1| \
+ V4L2_STD_SECAM_L| \
+ V4L2_STD_SECAM_LC)
+
+#define TSTD_B (V4L2_STD_PAL_B|V4L2_STD_SECAM_B)
+#define TSTD_B1 (V4L2_STD_PAL_B1)
+#define TSTD_D (V4L2_STD_PAL_D|V4L2_STD_SECAM_D)
+#define TSTD_D1 (V4L2_STD_PAL_D1)
+#define TSTD_G (V4L2_STD_PAL_G|V4L2_STD_SECAM_G)
+#define TSTD_H (V4L2_STD_PAL_H|V4L2_STD_SECAM_H)
+#define TSTD_I (V4L2_STD_PAL_I)
+#define TSTD_K (V4L2_STD_PAL_K|V4L2_STD_SECAM_K)
+#define TSTD_K1 (V4L2_STD_SECAM_K1)
+#define TSTD_L (V4L2_STD_SECAM_L)
+#define TSTD_M (V4L2_STD_PAL_M|V4L2_STD_NTSC_M)
+#define TSTD_N (V4L2_STD_PAL_N)
+#define TSTD_Nc (V4L2_STD_PAL_Nc)
+#define TSTD_60 (V4L2_STD_PAL_60)
+
+#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
+
+/* Mapping of standard bits to color system */
+const static struct std_name std_groups[] = {
+ {"PAL",CSTD_PAL},
+ {"NTSC",CSTD_NTSC},
+ {"SECAM",CSTD_SECAM},
+};
+
+/* Mapping of standard bits to modulation system */
+const static struct std_name std_items[] = {
+ {"B",TSTD_B},
+ {"B1",TSTD_B1},
+ {"D",TSTD_D},
+ {"D1",TSTD_D1},
+ {"G",TSTD_G},
+ {"H",TSTD_H},
+ {"I",TSTD_I},
+ {"K",TSTD_K},
+ {"K1",TSTD_K1},
+ {"L",TSTD_L},
+ {"LC",V4L2_STD_SECAM_LC},
+ {"M",TSTD_M},
+ {"Mj",V4L2_STD_NTSC_M_JP},
+ {"443",V4L2_STD_NTSC_443},
+ {"Mk",V4L2_STD_NTSC_M_KR},
+ {"N",TSTD_N},
+ {"Nc",TSTD_Nc},
+ {"60",TSTD_60},
+};
+
+
+// Search an array of std_name structures and return a pointer to the
+// element with the matching name.
+static const struct std_name *find_std_name(const struct std_name *arrPtr,
+ unsigned int arrSize,
+ const char *bufPtr,
+ unsigned int bufSize)
+{
+ unsigned int idx;
+ const struct std_name *p;
+ for (idx = 0; idx < arrSize; idx++) {
+ p = arrPtr + idx;
+ if (strlen(p->name) != bufSize) continue;
+ if (!memcmp(bufPtr,p->name,bufSize)) return p;
+ }
+ return NULL;
+}
+
+
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+ unsigned int bufSize)
+{
+ v4l2_std_id id = 0;
+ v4l2_std_id cmsk = 0;
+ v4l2_std_id t;
+ int mMode = 0;
+ unsigned int cnt;
+ char ch;
+ const struct std_name *sp;
+
+ while (bufSize) {
+ if (!mMode) {
+ cnt = 0;
+ while ((cnt < bufSize) && (bufPtr[cnt] != '-')) cnt++;
+ if (cnt >= bufSize) return 0; // No more characters
+ sp = find_std_name(
+ std_groups,
+ sizeof(std_groups)/sizeof(std_groups[0]),
+ bufPtr,cnt);
+ if (!sp) return 0; // Illegal color system name
+ cnt++;
+ bufPtr += cnt;
+ bufSize -= cnt;
+ mMode = !0;
+ cmsk = sp->id;
+ continue;
+ }
+ cnt = 0;
+ while (cnt < bufSize) {
+ ch = bufPtr[cnt];
+ if (ch == ';') {
+ mMode = 0;
+ break;
+ }
+ if (ch == '/') break;
+ cnt++;
+ }
+ sp = find_std_name(std_items,
+ sizeof(std_items)/sizeof(std_items[0]),
+ bufPtr,cnt);
+ if (!sp) return 0; // Illegal modulation system ID
+ t = sp->id & cmsk;
+ if (!t) return 0; // Specific color + modulation system illegal
+ id |= t;
+ if (cnt < bufSize) cnt++;
+ bufPtr += cnt;
+ bufSize -= cnt;
+ }
+
+ if (idPtr) *idPtr = id;
+ return !0;
+}
+
+
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+ v4l2_std_id id)
+{
+ unsigned int idx1,idx2;
+ const struct std_name *ip,*gp;
+ int gfl,cfl;
+ unsigned int c1,c2;
+ cfl = 0;
+ c1 = 0;
+ for (idx1 = 0;
+ idx1 < sizeof(std_groups)/sizeof(std_groups[0]);
+ idx1++) {
+ gp = std_groups + idx1;
+ gfl = 0;
+ for (idx2 = 0;
+ idx2 < sizeof(std_items)/sizeof(std_items[0]);
+ idx2++) {
+ ip = std_items + idx2;
+ if (!(gp->id & ip->id & id)) continue;
+ if (!gfl) {
+ if (cfl) {
+ c2 = scnprintf(bufPtr,bufSize,";");
+ c1 += c2;
+ bufSize -= c2;
+ bufPtr += c2;
+ }
+ cfl = !0;
+ c2 = scnprintf(bufPtr,bufSize,
+ "%s-",gp->name);
+ gfl = !0;
+ } else {
+ c2 = scnprintf(bufPtr,bufSize,"/");
+ }
+ c1 += c2;
+ bufSize -= c2;
+ bufPtr += c2;
+ c2 = scnprintf(bufPtr,bufSize,
+ ip->name);
+ c1 += c2;
+ bufSize -= c2;
+ bufPtr += c2;
+ }
+ }
+ return c1;
+}
+
+
+// Template data for possible enumerated video standards. Here we group
+// standards which share common frame rates and resolution.
+static struct v4l2_standard generic_standards[] = {
+ {
+ .id = (TSTD_B|TSTD_B1|
+ TSTD_D|TSTD_D1|
+ TSTD_G|
+ TSTD_H|
+ TSTD_I|
+ TSTD_K|TSTD_K1|
+ TSTD_L|
+ V4L2_STD_SECAM_LC |
+ TSTD_N|TSTD_Nc),
+ .frameperiod =
+ {
+ .numerator = 1,
+ .denominator= 25
+ },
+ .framelines = 625,
+ .reserved = {0,0,0,0}
+ }, {
+ .id = (TSTD_M|
+ V4L2_STD_NTSC_M_JP|
+ V4L2_STD_NTSC_M_KR),
+ .frameperiod =
+ {
+ .numerator = 1001,
+ .denominator= 30000
+ },
+ .framelines = 525,
+ .reserved = {0,0,0,0}
+ }, { // This is a total wild guess
+ .id = (TSTD_60),
+ .frameperiod =
+ {
+ .numerator = 1001,
+ .denominator= 30000
+ },
+ .framelines = 525,
+ .reserved = {0,0,0,0}
+ }, { // This is total wild guess
+ .id = V4L2_STD_NTSC_443,
+ .frameperiod =
+ {
+ .numerator = 1001,
+ .denominator= 30000
+ },
+ .framelines = 525,
+ .reserved = {0,0,0,0}
+ }
+};
+
+#define generic_standards_cnt (sizeof(generic_standards)/sizeof(generic_standards[0]))
+
+static struct v4l2_standard *match_std(v4l2_std_id id)
+{
+ unsigned int idx;
+ for (idx = 0; idx < generic_standards_cnt; idx++) {
+ if (generic_standards[idx].id & id) {
+ return generic_standards + idx;
+ }
+ }
+ return NULL;
+}
+
+static int pvr2_std_fill(struct v4l2_standard *std,v4l2_std_id id)
+{
+ struct v4l2_standard *template;
+ int idx;
+ unsigned int bcnt;
+ template = match_std(id);
+ if (!template) return 0;
+ idx = std->index;
+ memcpy(std,template,sizeof(*template));
+ std->index = idx;
+ std->id = id;
+ bcnt = pvr2_std_id_to_str(std->name,sizeof(std->name)-1,id);
+ std->name[bcnt] = 0;
+ pvr2_trace(PVR2_TRACE_INIT,"Set up standard idx=%u name=%s",
+ std->index,std->name);
+ return !0;
+}
+
+/* These are special cases of combined standards that we should enumerate
+ separately if the component pieces are present. */
+static v4l2_std_id std_mixes[] = {
+ V4L2_STD_PAL_B | V4L2_STD_PAL_G,
+ V4L2_STD_PAL_D | V4L2_STD_PAL_K,
+ V4L2_STD_SECAM_B | V4L2_STD_SECAM_G,
+ V4L2_STD_SECAM_D | V4L2_STD_SECAM_K,
+};
+
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+ v4l2_std_id id)
+{
+ unsigned int std_cnt = 0;
+ unsigned int idx,bcnt,idx2;
+ v4l2_std_id idmsk,cmsk,fmsk;
+ struct v4l2_standard *stddefs;
+
+ if (pvrusb2_debug & PVR2_TRACE_INIT) {
+ char buf[50];
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
+ pvr2_trace(
+ PVR2_TRACE_INIT,"Mapping standards mask=0x%x (%.*s)",
+ (int)id,bcnt,buf);
+ }
+
+ *countptr = 0;
+ std_cnt = 0;
+ fmsk = 0;
+ for (idmsk = 1, cmsk = id; cmsk; idmsk <<= 1) {
+ if (!(idmsk & cmsk)) continue;
+ cmsk &= ~idmsk;
+ if (match_std(idmsk)) {
+ std_cnt++;
+ continue;
+ }
+ fmsk |= idmsk;
+ }
+
+ for (idx2 = 0; idx2 < sizeof(std_mixes)/sizeof(std_mixes[0]); idx2++) {
+ if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
+ }
+
+ if (fmsk) {
+ char buf[50];
+ bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
+ pvr2_trace(
+ PVR2_TRACE_ERROR_LEGS,
+ "WARNING:"
+ " Failed to classify the following standard(s): %.*s",
+ bcnt,buf);
+ }
+
+ pvr2_trace(PVR2_TRACE_INIT,"Setting up %u unique standard(s)",
+ std_cnt);
+ if (!std_cnt) return NULL; // paranoia
+
+ stddefs = kmalloc(sizeof(struct v4l2_standard) * std_cnt,
+ GFP_KERNEL);
+ memset(stddefs,0,sizeof(struct v4l2_standard) * std_cnt);
+ for (idx = 0; idx < std_cnt; idx++) stddefs[idx].index = idx;
+
+ idx = 0;
+
+ /* Enumerate potential special cases */
+ for (idx2 = 0; ((idx2 < sizeof(std_mixes)/sizeof(std_mixes[0])) &&
+ (idx < std_cnt)); idx2++) {
+ if (!(id & std_mixes[idx2])) continue;
+ if (pvr2_std_fill(stddefs+idx,std_mixes[idx2])) idx++;
+ }
+ /* Now enumerate individual pieces */
+ for (idmsk = 1, cmsk = id; cmsk && (idx < std_cnt); idmsk <<= 1) {
+ if (!(idmsk & cmsk)) continue;
+ cmsk &= ~idmsk;
+ if (!pvr2_std_fill(stddefs+idx,idmsk)) continue;
+ idx++;
+ }
+
+ *countptr = std_cnt;
+ return stddefs;
+}
+
+v4l2_std_id pvr2_std_get_usable(void)
+{
+ return CSTD_ALL;
+}
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.h b/drivers/media/video/pvrusb2/pvrusb2-std.h
new file mode 100644
index 00000000000..07c39937534
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.h
@@ -0,0 +1,60 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_STD_H
+#define __PVRUSB2_STD_H
+
+#include <linux/videodev2.h>
+
+// Convert string describing one or more video standards into a mask of V4L
+// standard bits. Return true if conversion succeeds otherwise return
+// false. String is expected to be of the form: C1-x/y;C2-a/b where C1 and
+// C2 are color system names (e.g. "PAL", "NTSC") and x, y, a, and b are
+// modulation schemes (e.g. "M", "B", "G", etc).
+int pvr2_std_str_to_id(v4l2_std_id *idPtr,const char *bufPtr,
+ unsigned int bufSize);
+
+// Convert any arbitrary set of video standard bits into an unambiguous
+// readable string. Return value is the number of bytes consumed in the
+// buffer. The formatted string is of a form that can be parsed by our
+// sibling std_std_to_id() function.
+unsigned int pvr2_std_id_to_str(char *bufPtr, unsigned int bufSize,
+ v4l2_std_id id);
+
+// Create an array of suitable v4l2_standard structures given a bit mask of
+// video standards to support. The array is allocated from the heap, and
+// the number of elements is returned in the first argument.
+struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
+ v4l2_std_id id);
+
+// Return mask of which video standard bits are valid
+v4l2_std_id pvr2_std_get_usable(void);
+
+#endif /* __PVRUSB2_STD_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
new file mode 100644
index 00000000000..d1dda5caf40
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -0,0 +1,926 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * 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/config.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <asm/semaphore.h>
+#include "pvrusb2-sysfs.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-debug.h"
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+#include "pvrusb2-debugifc.h"
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+#define pvr2_sysfs_trace(...) pvr2_trace(PVR2_TRACE_SYSFS,__VA_ARGS__)
+
+struct pvr2_sysfs {
+ struct pvr2_channel channel;
+ struct class_device *class_dev;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+ struct pvr2_sysfs_debugifc *debugifc;
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+ struct pvr2_sysfs_ctl_item *item_first;
+ struct pvr2_sysfs_ctl_item *item_last;
+ struct sysfs_ops kops;
+ struct kobj_type ktype;
+ struct class_device_attribute attr_v4l_minor_number;
+ struct class_device_attribute attr_unit_number;
+ int v4l_minor_number_created_ok;
+ int unit_number_created_ok;
+};
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+struct pvr2_sysfs_debugifc {
+ struct class_device_attribute attr_debugcmd;
+ struct class_device_attribute attr_debuginfo;
+ int debugcmd_created_ok;
+ int debuginfo_created_ok;
+};
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+struct pvr2_sysfs_ctl_item {
+ struct class_device_attribute attr_name;
+ struct class_device_attribute attr_type;
+ struct class_device_attribute attr_min;
+ struct class_device_attribute attr_max;
+ struct class_device_attribute attr_enum;
+ struct class_device_attribute attr_bits;
+ struct class_device_attribute attr_val;
+ struct class_device_attribute attr_custom;
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *chptr;
+ struct pvr2_sysfs_ctl_item *item_next;
+ struct attribute *attr_gen[7];
+ struct attribute_group grp;
+ int created_ok;
+ char name[80];
+};
+
+struct pvr2_sysfs_class {
+ struct class class;
+};
+
+static ssize_t show_name(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ const char *name;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+
+ name = pvr2_ctrl_get_desc(cptr);
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_name(cid=%d) is %s",sfp,id,name);
+
+ if (!name) return -EINVAL;
+
+ return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
+static ssize_t show_type(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ const char *name;
+ enum pvr2_ctl_type tp;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+
+ tp = pvr2_ctrl_get_type(cptr);
+ switch (tp) {
+ case pvr2_ctl_int: name = "integer"; break;
+ case pvr2_ctl_enum: name = "enum"; break;
+ case pvr2_ctl_bitmask: name = "bitmask"; break;
+ case pvr2_ctl_bool: name = "boolean"; break;
+ default: name = "?"; break;
+ }
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s",sfp,id,name);
+
+ if (!name) return -EINVAL;
+
+ return scnprintf(buf,PAGE_SIZE,"%s\n",name);
+}
+
+static ssize_t show_min(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ long val;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ val = pvr2_ctrl_get_min(cptr);
+
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_min(cid=%d) is %ld",sfp,id,val);
+
+ return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+}
+
+static ssize_t show_max(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ long val;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ val = pvr2_ctrl_get_max(cptr);
+
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_max(cid=%d) is %ld",sfp,id,val);
+
+ return scnprintf(buf,PAGE_SIZE,"%ld\n",val);
+}
+
+static ssize_t show_val_norm(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ int val,ret;
+ unsigned int cnt = 0;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+
+ ret = pvr2_ctrl_get_value(cptr,&val);
+ if (ret < 0) return ret;
+
+ ret = pvr2_ctrl_value_to_sym(cptr,~0,val,
+ buf,PAGE_SIZE-1,&cnt);
+
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_norm(cid=%d) is %.*s (%d)",
+ sfp,id,cnt,buf,val);
+ buf[cnt] = '\n';
+ return cnt+1;
+}
+
+static ssize_t show_val_custom(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ int val,ret;
+ unsigned int cnt = 0;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+
+ ret = pvr2_ctrl_get_value(cptr,&val);
+ if (ret < 0) return ret;
+
+ ret = pvr2_ctrl_custom_value_to_sym(cptr,~0,val,
+ buf,PAGE_SIZE-1,&cnt);
+
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_val_custom(cid=%d) is %.*s (%d)",
+ sfp,id,cnt,buf,val);
+ buf[cnt] = '\n';
+ return cnt+1;
+}
+
+static ssize_t show_enum(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ long val;
+ unsigned int bcnt,ccnt,ecnt;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ ecnt = pvr2_ctrl_get_cnt(cptr);
+ bcnt = 0;
+ for (val = 0; val < ecnt; val++) {
+ pvr2_ctrl_get_valname(cptr,val,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ if (!ccnt) continue;
+ bcnt += ccnt;
+ if (bcnt >= PAGE_SIZE) break;
+ buf[bcnt] = '\n';
+ bcnt++;
+ }
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_enum(cid=%d)",sfp,id);
+ return bcnt;
+}
+
+static ssize_t show_bits(int id,struct class_device *class_dev,char *buf)
+{
+ struct pvr2_ctrl *cptr;
+ struct pvr2_sysfs *sfp;
+ int valid_bits,msk;
+ unsigned int bcnt,ccnt;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (!cptr) return -EINVAL;
+ valid_bits = pvr2_ctrl_get_mask(cptr);
+ bcnt = 0;
+ for (msk = 1; valid_bits; msk <<= 1) {
+ if (!(msk & valid_bits)) continue;
+ valid_bits &= ~msk;
+ pvr2_ctrl_get_valname(cptr,msk,buf+bcnt,PAGE_SIZE-bcnt,&ccnt);
+ bcnt += ccnt;
+ if (bcnt >= PAGE_SIZE) break;
+ buf[bcnt] = '\n';
+ bcnt++;
+ }
+ pvr2_sysfs_trace("pvr2_sysfs(%p) show_bits(cid=%d)",sfp,id);
+ return bcnt;
+}
+
+static int store_val_any(int id,int customfl,struct pvr2_sysfs *sfp,
+ const char *buf,unsigned int count)
+{
+ struct pvr2_ctrl *cptr;
+ int ret;
+ int mask,val;
+
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,id);
+ if (customfl) {
+ ret = pvr2_ctrl_custom_sym_to_value(cptr,buf,count,&mask,&val);
+ } else {
+ ret = pvr2_ctrl_sym_to_value(cptr,buf,count,&mask,&val);
+ }
+ if (ret < 0) return ret;
+ ret = pvr2_ctrl_set_mask_value(cptr,mask,val);
+ pvr2_hdw_commit_ctl(sfp->channel.hdw);
+ return ret;
+}
+
+static ssize_t store_val_norm(int id,struct class_device *class_dev,
+ const char *buf,size_t count)
+{
+ struct pvr2_sysfs *sfp;
+ int ret;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ ret = store_val_any(id,0,sfp,buf,count);
+ if (!ret) ret = count;
+ return ret;
+}
+
+static ssize_t store_val_custom(int id,struct class_device *class_dev,
+ const char *buf,size_t count)
+{
+ struct pvr2_sysfs *sfp;
+ int ret;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ ret = store_val_any(id,1,sfp,buf,count);
+ if (!ret) ret = count;
+ return ret;
+}
+
+/*
+ Mike Isely <isely@pobox.com> 30-April-2005
+
+ This next batch of horrible preprocessor hackery is needed because the
+ kernel's class_device_attribute mechanism fails to pass the actual
+ attribute through to the show / store functions, which means we have no
+ way to package up any attribute-specific parameters, like for example the
+ control id. So we work around this brain-damage by encoding the control
+ id into the show / store functions themselves and pick the function based
+ on the control id we're setting up. These macros try to ease the pain.
+ Yuck.
+*/
+
+#define CREATE_SHOW_INSTANCE(sf_name,ctl_id) \
+static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,char *buf) \
+{ return sf_name(ctl_id,class_dev,buf); }
+
+#define CREATE_STORE_INSTANCE(sf_name,ctl_id) \
+static ssize_t sf_name##_##ctl_id(struct class_device *class_dev,const char *buf,size_t count) \
+{ return sf_name(ctl_id,class_dev,buf,count); }
+
+#define CREATE_BATCH(ctl_id) \
+CREATE_SHOW_INSTANCE(show_name,ctl_id) \
+CREATE_SHOW_INSTANCE(show_type,ctl_id) \
+CREATE_SHOW_INSTANCE(show_min,ctl_id) \
+CREATE_SHOW_INSTANCE(show_max,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_norm,ctl_id) \
+CREATE_SHOW_INSTANCE(show_val_custom,ctl_id) \
+CREATE_SHOW_INSTANCE(show_enum,ctl_id) \
+CREATE_SHOW_INSTANCE(show_bits,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_norm,ctl_id) \
+CREATE_STORE_INSTANCE(store_val_custom,ctl_id) \
+
+CREATE_BATCH(0)
+CREATE_BATCH(1)
+CREATE_BATCH(2)
+CREATE_BATCH(3)
+CREATE_BATCH(4)
+CREATE_BATCH(5)
+CREATE_BATCH(6)
+CREATE_BATCH(7)
+CREATE_BATCH(8)
+CREATE_BATCH(9)
+CREATE_BATCH(10)
+CREATE_BATCH(11)
+CREATE_BATCH(12)
+CREATE_BATCH(13)
+CREATE_BATCH(14)
+CREATE_BATCH(15)
+CREATE_BATCH(16)
+CREATE_BATCH(17)
+CREATE_BATCH(18)
+CREATE_BATCH(19)
+CREATE_BATCH(20)
+CREATE_BATCH(21)
+CREATE_BATCH(22)
+CREATE_BATCH(23)
+CREATE_BATCH(24)
+CREATE_BATCH(25)
+CREATE_BATCH(26)
+CREATE_BATCH(27)
+CREATE_BATCH(28)
+CREATE_BATCH(29)
+CREATE_BATCH(30)
+CREATE_BATCH(31)
+CREATE_BATCH(32)
+CREATE_BATCH(33)
+CREATE_BATCH(34)
+CREATE_BATCH(35)
+CREATE_BATCH(36)
+CREATE_BATCH(37)
+CREATE_BATCH(38)
+CREATE_BATCH(39)
+CREATE_BATCH(40)
+CREATE_BATCH(41)
+CREATE_BATCH(42)
+CREATE_BATCH(43)
+CREATE_BATCH(44)
+CREATE_BATCH(45)
+CREATE_BATCH(46)
+CREATE_BATCH(47)
+CREATE_BATCH(48)
+CREATE_BATCH(49)
+CREATE_BATCH(50)
+CREATE_BATCH(51)
+CREATE_BATCH(52)
+CREATE_BATCH(53)
+CREATE_BATCH(54)
+CREATE_BATCH(55)
+CREATE_BATCH(56)
+CREATE_BATCH(57)
+CREATE_BATCH(58)
+CREATE_BATCH(59)
+
+struct pvr2_sysfs_func_set {
+ ssize_t (*show_name)(struct class_device *,char *);
+ ssize_t (*show_type)(struct class_device *,char *);
+ ssize_t (*show_min)(struct class_device *,char *);
+ ssize_t (*show_max)(struct class_device *,char *);
+ ssize_t (*show_enum)(struct class_device *,char *);
+ ssize_t (*show_bits)(struct class_device *,char *);
+ ssize_t (*show_val_norm)(struct class_device *,char *);
+ ssize_t (*store_val_norm)(struct class_device *,
+ const char *,size_t);
+ ssize_t (*show_val_custom)(struct class_device *,char *);
+ ssize_t (*store_val_custom)(struct class_device *,
+ const char *,size_t);
+};
+
+#define INIT_BATCH(ctl_id) \
+[ctl_id] = { \
+ .show_name = show_name_##ctl_id, \
+ .show_type = show_type_##ctl_id, \
+ .show_min = show_min_##ctl_id, \
+ .show_max = show_max_##ctl_id, \
+ .show_enum = show_enum_##ctl_id, \
+ .show_bits = show_bits_##ctl_id, \
+ .show_val_norm = show_val_norm_##ctl_id, \
+ .store_val_norm = store_val_norm_##ctl_id, \
+ .show_val_custom = show_val_custom_##ctl_id, \
+ .store_val_custom = store_val_custom_##ctl_id, \
+} \
+
+static struct pvr2_sysfs_func_set funcs[] = {
+ INIT_BATCH(0),
+ INIT_BATCH(1),
+ INIT_BATCH(2),
+ INIT_BATCH(3),
+ INIT_BATCH(4),
+ INIT_BATCH(5),
+ INIT_BATCH(6),
+ INIT_BATCH(7),
+ INIT_BATCH(8),
+ INIT_BATCH(9),
+ INIT_BATCH(10),
+ INIT_BATCH(11),
+ INIT_BATCH(12),
+ INIT_BATCH(13),
+ INIT_BATCH(14),
+ INIT_BATCH(15),
+ INIT_BATCH(16),
+ INIT_BATCH(17),
+ INIT_BATCH(18),
+ INIT_BATCH(19),
+ INIT_BATCH(20),
+ INIT_BATCH(21),
+ INIT_BATCH(22),
+ INIT_BATCH(23),
+ INIT_BATCH(24),
+ INIT_BATCH(25),
+ INIT_BATCH(26),
+ INIT_BATCH(27),
+ INIT_BATCH(28),
+ INIT_BATCH(29),
+ INIT_BATCH(30),
+ INIT_BATCH(31),
+ INIT_BATCH(32),
+ INIT_BATCH(33),
+ INIT_BATCH(34),
+ INIT_BATCH(35),
+ INIT_BATCH(36),
+ INIT_BATCH(37),
+ INIT_BATCH(38),
+ INIT_BATCH(39),
+ INIT_BATCH(40),
+ INIT_BATCH(41),
+ INIT_BATCH(42),
+ INIT_BATCH(43),
+ INIT_BATCH(44),
+ INIT_BATCH(45),
+ INIT_BATCH(46),
+ INIT_BATCH(47),
+ INIT_BATCH(48),
+ INIT_BATCH(49),
+ INIT_BATCH(50),
+ INIT_BATCH(51),
+ INIT_BATCH(52),
+ INIT_BATCH(53),
+ INIT_BATCH(54),
+ INIT_BATCH(55),
+ INIT_BATCH(56),
+ INIT_BATCH(57),
+ INIT_BATCH(58),
+ INIT_BATCH(59),
+};
+
+
+static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
+{
+ struct pvr2_sysfs_ctl_item *cip;
+ struct pvr2_sysfs_func_set *fp;
+ struct pvr2_ctrl *cptr;
+ unsigned int cnt,acnt;
+ int ret;
+
+ if ((ctl_id < 0) || (ctl_id >= (sizeof(funcs)/sizeof(funcs[0])))) {
+ return;
+ }
+
+ fp = funcs + ctl_id;
+ cptr = pvr2_hdw_get_ctrl_by_index(sfp->channel.hdw,ctl_id);
+ if (!cptr) return;
+
+ cip = kmalloc(sizeof(*cip),GFP_KERNEL);
+ if (!cip) return;
+ memset(cip,0,sizeof(*cip));
+ pvr2_sysfs_trace("Creating pvr2_sysfs_ctl_item id=%p",cip);
+
+ cip->cptr = cptr;
+
+ cip->chptr = sfp;
+ cip->item_next = NULL;
+ if (sfp->item_last) {
+ sfp->item_last->item_next = cip;
+ } else {
+ sfp->item_first = cip;
+ }
+ sfp->item_last = cip;
+
+ cip->attr_name.attr.owner = THIS_MODULE;
+ cip->attr_name.attr.name = "name";
+ cip->attr_name.attr.mode = S_IRUGO;
+ cip->attr_name.show = fp->show_name;
+
+ cip->attr_type.attr.owner = THIS_MODULE;
+ cip->attr_type.attr.name = "type";
+ cip->attr_type.attr.mode = S_IRUGO;
+ cip->attr_type.show = fp->show_type;
+
+ cip->attr_min.attr.owner = THIS_MODULE;
+ cip->attr_min.attr.name = "min_val";
+ cip->attr_min.attr.mode = S_IRUGO;
+ cip->attr_min.show = fp->show_min;
+
+ cip->attr_max.attr.owner = THIS_MODULE;
+ cip->attr_max.attr.name = "max_val";
+ cip->attr_max.attr.mode = S_IRUGO;
+ cip->attr_max.show = fp->show_max;
+
+ cip->attr_val.attr.owner = THIS_MODULE;
+ cip->attr_val.attr.name = "cur_val";
+ cip->attr_val.attr.mode = S_IRUGO;
+
+ cip->attr_custom.attr.owner = THIS_MODULE;
+ cip->attr_custom.attr.name = "custom_val";
+ cip->attr_custom.attr.mode = S_IRUGO;
+
+ cip->attr_enum.attr.owner = THIS_MODULE;
+ cip->attr_enum.attr.name = "enum_val";
+ cip->attr_enum.attr.mode = S_IRUGO;
+ cip->attr_enum.show = fp->show_enum;
+
+ cip->attr_bits.attr.owner = THIS_MODULE;
+ cip->attr_bits.attr.name = "bit_val";
+ cip->attr_bits.attr.mode = S_IRUGO;
+ cip->attr_bits.show = fp->show_bits;
+
+ if (pvr2_ctrl_is_writable(cptr)) {
+ cip->attr_val.attr.mode |= S_IWUSR|S_IWGRP;
+ cip->attr_custom.attr.mode |= S_IWUSR|S_IWGRP;
+ }
+
+ acnt = 0;
+ cip->attr_gen[acnt++] = &cip->attr_name.attr;
+ cip->attr_gen[acnt++] = &cip->attr_type.attr;
+ cip->attr_gen[acnt++] = &cip->attr_val.attr;
+ cip->attr_val.show = fp->show_val_norm;
+ cip->attr_val.store = fp->store_val_norm;
+ if (pvr2_ctrl_has_custom_symbols(cptr)) {
+ cip->attr_gen[acnt++] = &cip->attr_custom.attr;
+ cip->attr_custom.show = fp->show_val_custom;
+ cip->attr_custom.store = fp->store_val_custom;
+ }
+ switch (pvr2_ctrl_get_type(cptr)) {
+ case pvr2_ctl_enum:
+ // Control is an enumeration
+ cip->attr_gen[acnt++] = &cip->attr_enum.attr;
+ break;
+ case pvr2_ctl_int:
+ // Control is an integer
+ cip->attr_gen[acnt++] = &cip->attr_min.attr;
+ cip->attr_gen[acnt++] = &cip->attr_max.attr;
+ break;
+ case pvr2_ctl_bitmask:
+ // Control is an bitmask
+ cip->attr_gen[acnt++] = &cip->attr_bits.attr;
+ break;
+ default: break;
+ }
+
+ cnt = scnprintf(cip->name,sizeof(cip->name)-1,"ctl_%s",
+ pvr2_ctrl_get_name(cptr));
+ cip->name[cnt] = 0;
+ cip->grp.name = cip->name;
+ cip->grp.attrs = cip->attr_gen;
+
+ ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
+ if (ret) {
+ printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
+ __FUNCTION__, ret);
+ return;
+ }
+ cip->created_ok = !0;
+}
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+static ssize_t debuginfo_show(struct class_device *,char *);
+static ssize_t debugcmd_show(struct class_device *,char *);
+static ssize_t debugcmd_store(struct class_device *,const char *,size_t count);
+
+static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
+{
+ struct pvr2_sysfs_debugifc *dip;
+ int ret;
+
+ dip = kmalloc(sizeof(*dip),GFP_KERNEL);
+ if (!dip) return;
+ memset(dip,0,sizeof(*dip));
+ dip->attr_debugcmd.attr.owner = THIS_MODULE;
+ dip->attr_debugcmd.attr.name = "debugcmd";
+ dip->attr_debugcmd.attr.mode = S_IRUGO|S_IWUSR|S_IWGRP;
+ dip->attr_debugcmd.show = debugcmd_show;
+ dip->attr_debugcmd.store = debugcmd_store;
+ dip->attr_debuginfo.attr.owner = THIS_MODULE;
+ dip->attr_debuginfo.attr.name = "debuginfo";
+ dip->attr_debuginfo.attr.mode = S_IRUGO;
+ dip->attr_debuginfo.show = debuginfo_show;
+ sfp->debugifc = dip;
+ ret = class_device_create_file(sfp->class_dev,&dip->attr_debugcmd);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ dip->debugcmd_created_ok = !0;
+ }
+ ret = class_device_create_file(sfp->class_dev,&dip->attr_debuginfo);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ dip->debuginfo_created_ok = !0;
+ }
+}
+
+
+static void pvr2_sysfs_tear_down_debugifc(struct pvr2_sysfs *sfp)
+{
+ if (!sfp->debugifc) return;
+ if (sfp->debugifc->debuginfo_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->debugifc->attr_debuginfo);
+ }
+ if (sfp->debugifc->debugcmd_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->debugifc->attr_debugcmd);
+ }
+ kfree(sfp->debugifc);
+ sfp->debugifc = NULL;
+}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+
+static void pvr2_sysfs_add_controls(struct pvr2_sysfs *sfp)
+{
+ unsigned int idx,cnt;
+ cnt = pvr2_hdw_get_ctrl_count(sfp->channel.hdw);
+ for (idx = 0; idx < cnt; idx++) {
+ pvr2_sysfs_add_control(sfp,idx);
+ }
+}
+
+
+static void pvr2_sysfs_tear_down_controls(struct pvr2_sysfs *sfp)
+{
+ struct pvr2_sysfs_ctl_item *cip1,*cip2;
+ for (cip1 = sfp->item_first; cip1; cip1 = cip2) {
+ cip2 = cip1->item_next;
+ if (cip1->created_ok) {
+ sysfs_remove_group(&sfp->class_dev->kobj,&cip1->grp);
+ }
+ pvr2_sysfs_trace("Destroying pvr2_sysfs_ctl_item id=%p",cip1);
+ kfree(cip1);
+ }
+}
+
+
+static void pvr2_sysfs_class_release(struct class *class)
+{
+ struct pvr2_sysfs_class *clp;
+ clp = container_of(class,struct pvr2_sysfs_class,class);
+ pvr2_sysfs_trace("Destroying pvr2_sysfs_class id=%p",clp);
+ kfree(clp);
+}
+
+
+static void pvr2_sysfs_release(struct class_device *class_dev)
+{
+ pvr2_sysfs_trace("Releasing class_dev id=%p",class_dev);
+ kfree(class_dev);
+}
+
+
+static void class_dev_destroy(struct pvr2_sysfs *sfp)
+{
+ if (!sfp->class_dev) return;
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+ pvr2_sysfs_tear_down_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+ pvr2_sysfs_tear_down_controls(sfp);
+ if (sfp->v4l_minor_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_v4l_minor_number);
+ }
+ if (sfp->unit_number_created_ok) {
+ class_device_remove_file(sfp->class_dev,
+ &sfp->attr_unit_number);
+ }
+ pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
+ sfp->class_dev->class_data = NULL;
+ class_device_unregister(sfp->class_dev);
+ sfp->class_dev = NULL;
+}
+
+
+static ssize_t v4l_minor_number_show(struct class_device *class_dev,char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return scnprintf(buf,PAGE_SIZE,"%d\n",
+ pvr2_hdw_v4l_get_minor_number(sfp->channel.hdw));
+}
+
+
+static ssize_t unit_number_show(struct class_device *class_dev,char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return scnprintf(buf,PAGE_SIZE,"%d\n",
+ pvr2_hdw_get_unit_number(sfp->channel.hdw));
+}
+
+
+static void class_dev_create(struct pvr2_sysfs *sfp,
+ struct pvr2_sysfs_class *class_ptr)
+{
+ struct usb_device *usb_dev;
+ struct class_device *class_dev;
+ int ret;
+
+ usb_dev = pvr2_hdw_get_dev(sfp->channel.hdw);
+ if (!usb_dev) return;
+ class_dev = kmalloc(sizeof(*class_dev),GFP_KERNEL);
+ if (!class_dev) return;
+ memset(class_dev,0,sizeof(*class_dev));
+
+ pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
+
+ class_dev->class = &class_ptr->class;
+ if (pvr2_hdw_get_sn(sfp->channel.hdw)) {
+ snprintf(class_dev->class_id,BUS_ID_SIZE,"sn-%lu",
+ pvr2_hdw_get_sn(sfp->channel.hdw));
+ } else if (pvr2_hdw_get_unit_number(sfp->channel.hdw) >= 0) {
+ snprintf(class_dev->class_id,BUS_ID_SIZE,"unit-%c",
+ pvr2_hdw_get_unit_number(sfp->channel.hdw) + 'a');
+ } else {
+ kfree(class_dev);
+ return;
+ }
+
+ class_dev->dev = &usb_dev->dev;
+
+ sfp->class_dev = class_dev;
+ class_dev->class_data = sfp;
+ ret = class_device_register(class_dev);
+ if (ret) {
+ printk(KERN_ERR "%s: class_device_register failed\n",
+ __FUNCTION__);
+ kfree(class_dev);
+ return;
+ }
+
+ sfp->attr_v4l_minor_number.attr.owner = THIS_MODULE;
+ sfp->attr_v4l_minor_number.attr.name = "v4l_minor_number";
+ sfp->attr_v4l_minor_number.attr.mode = S_IRUGO;
+ sfp->attr_v4l_minor_number.show = v4l_minor_number_show;
+ sfp->attr_v4l_minor_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,
+ &sfp->attr_v4l_minor_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->v4l_minor_number_created_ok = !0;
+ }
+
+ sfp->attr_unit_number.attr.owner = THIS_MODULE;
+ sfp->attr_unit_number.attr.name = "unit_number";
+ sfp->attr_unit_number.attr.mode = S_IRUGO;
+ sfp->attr_unit_number.show = unit_number_show;
+ sfp->attr_unit_number.store = NULL;
+ ret = class_device_create_file(sfp->class_dev,&sfp->attr_unit_number);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s: class_device_create_file error: %d\n",
+ __FUNCTION__, ret);
+ } else {
+ sfp->unit_number_created_ok = !0;
+ }
+
+ pvr2_sysfs_add_controls(sfp);
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+ pvr2_sysfs_add_debugifc(sfp);
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+}
+
+
+static void pvr2_sysfs_internal_check(struct pvr2_channel *chp)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = container_of(chp,struct pvr2_sysfs,channel);
+ if (!sfp->channel.mc_head->disconnect_flag) return;
+ pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_sysfs id=%p",sfp);
+ class_dev_destroy(sfp);
+ pvr2_channel_done(&sfp->channel);
+ kfree(sfp);
+}
+
+
+struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *mp,
+ struct pvr2_sysfs_class *class_ptr)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = kmalloc(sizeof(*sfp),GFP_KERNEL);
+ if (!sfp) return sfp;
+ memset(sfp,0,sizeof(*sfp));
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_sysfs id=%p",sfp);
+ pvr2_channel_init(&sfp->channel,mp);
+ sfp->channel.check_func = pvr2_sysfs_internal_check;
+
+ class_dev_create(sfp,class_ptr);
+ return sfp;
+}
+
+
+static int pvr2_sysfs_hotplug(struct class_device *cd,char **envp,
+ int numenvp,char *buf,int size)
+{
+ /* Even though we don't do anything here, we still need this function
+ because sysfs will still try to call it. */
+ return 0;
+}
+
+struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
+{
+ struct pvr2_sysfs_class *clp;
+ clp = kmalloc(sizeof(*clp),GFP_KERNEL);
+ if (!clp) return clp;
+ memset(clp,0,sizeof(*clp));
+ pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
+ clp->class.name = "pvrusb2";
+ clp->class.class_release = pvr2_sysfs_class_release;
+ clp->class.release = pvr2_sysfs_release;
+ clp->class.uevent = pvr2_sysfs_hotplug;
+ if (class_register(&clp->class)) {
+ pvr2_sysfs_trace(
+ "Registration failed for pvr2_sysfs_class id=%p",clp);
+ kfree(clp);
+ clp = NULL;
+ }
+ return clp;
+}
+
+
+void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
+{
+ class_unregister(&clp->class);
+}
+
+
+#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
+static ssize_t debuginfo_show(struct class_device *class_dev,char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ pvr2_hdw_trigger_module_log(sfp->channel.hdw);
+ return pvr2_debugifc_print_info(sfp->channel.hdw,buf,PAGE_SIZE);
+}
+
+
+static ssize_t debugcmd_show(struct class_device *class_dev,char *buf)
+{
+ struct pvr2_sysfs *sfp;
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+ return pvr2_debugifc_print_status(sfp->channel.hdw,buf,PAGE_SIZE);
+}
+
+
+static ssize_t debugcmd_store(struct class_device *class_dev,
+ const char *buf,size_t count)
+{
+ struct pvr2_sysfs *sfp;
+ int ret;
+
+ sfp = (struct pvr2_sysfs *)class_dev->class_data;
+ if (!sfp) return -EINVAL;
+
+ ret = pvr2_debugifc_docmd(sfp->channel.hdw,buf,count);
+ if (ret < 0) return ret;
+ return count;
+}
+#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.h b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
new file mode 100644
index 00000000000..ff9373b47f8
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.h
@@ -0,0 +1,47 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_SYSFS_H
+#define __PVRUSB2_SYSFS_H
+
+#include <linux/list.h>
+#include <linux/sysfs.h>
+#include "pvrusb2-context.h"
+
+struct pvr2_sysfs;
+struct pvr2_sysfs_class;
+
+struct pvr2_sysfs_class *pvr2_sysfs_class_create(void);
+void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *);
+
+struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *,
+ struct pvr2_sysfs_class *);
+
+#endif /* __PVRUSB2_SYSFS_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.c b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
new file mode 100644
index 00000000000..af9f246f8d3
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.c
@@ -0,0 +1,122 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include "pvrusb2.h"
+#include "pvrusb2-util.h"
+#include "pvrusb2-tuner.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/tuner.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_tuner_handler {
+ struct pvr2_hdw *hdw;
+ struct pvr2_i2c_client *client;
+ struct pvr2_i2c_handler i2c_handler;
+ int type_update_fl;
+};
+
+
+static void set_type(struct pvr2_tuner_handler *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ struct tuner_setup setup;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c tuner set_type(%d)",hdw->tuner_type);
+ if (((int)(hdw->tuner_type)) < 0) return;
+
+ setup.addr = ADDR_UNSET;
+ setup.type = hdw->tuner_type;
+ setup.mode_mask = T_RADIO | T_ANALOG_TV;
+ /* We may really want mode_mask to be T_ANALOG_TV for now */
+ pvr2_i2c_client_cmd(ctxt->client,TUNER_SET_TYPE_ADDR,&setup);
+ ctxt->type_update_fl = 0;
+}
+
+
+static int tuner_check(struct pvr2_tuner_handler *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ if (hdw->tuner_updated) ctxt->type_update_fl = !0;
+ return ctxt->type_update_fl != 0;
+}
+
+
+static void tuner_update(struct pvr2_tuner_handler *ctxt)
+{
+ if (ctxt->type_update_fl) set_type(ctxt);
+}
+
+
+static void pvr2_tuner_detach(struct pvr2_tuner_handler *ctxt)
+{
+ ctxt->client->handler = NULL;
+ kfree(ctxt);
+}
+
+
+static unsigned int pvr2_tuner_describe(struct pvr2_tuner_handler *ctxt,char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-tuner");
+}
+
+
+const static struct pvr2_i2c_handler_functions tuner_funcs = {
+ .detach = (void (*)(void *))pvr2_tuner_detach,
+ .check = (int (*)(void *))tuner_check,
+ .update = (void (*)(void *))tuner_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))pvr2_tuner_describe,
+};
+
+
+int pvr2_i2c_tuner_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+ struct pvr2_tuner_handler *ctxt;
+ if (cp->handler) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->i2c_handler.func_data = ctxt;
+ ctxt->i2c_handler.func_table = &tuner_funcs;
+ ctxt->type_update_fl = !0;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ cp->handler = &ctxt->i2c_handler;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x tuner handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-tuner.h b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
new file mode 100644
index 00000000000..556f12aa916
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-tuner.h
@@ -0,0 +1,38 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_TUNER_H
+#define __PVRUSB2_TUNER_H
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_tuner_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+#endif /* __PVRUSB2_TUNER_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-util.h b/drivers/media/video/pvrusb2/pvrusb2-util.h
new file mode 100644
index 00000000000..e53aee416f5
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-util.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_UTIL_H
+#define __PVRUSB2_UTIL_H
+
+#define PVR2_DECOMPOSE_LE(t,i,d) \
+ do { \
+ (t)[i] = (d) & 0xff;\
+ (t)[i+1] = ((d) >> 8) & 0xff;\
+ (t)[i+2] = ((d) >> 16) & 0xff;\
+ (t)[i+3] = ((d) >> 24) & 0xff;\
+ } while(0)
+
+#define PVR2_DECOMPOSE_BE(t,i,d) \
+ do { \
+ (t)[i+3] = (d) & 0xff;\
+ (t)[i+2] = ((d) >> 8) & 0xff;\
+ (t)[i+1] = ((d) >> 16) & 0xff;\
+ (t)[i] = ((d) >> 24) & 0xff;\
+ } while(0)
+
+#define PVR2_COMPOSE_LE(t,i) \
+ ((((u32)((t)[i+3])) << 24) | \
+ (((u32)((t)[i+2])) << 16) | \
+ (((u32)((t)[i+1])) << 8) | \
+ ((u32)((t)[i])))
+
+#define PVR2_COMPOSE_BE(t,i) \
+ ((((u32)((t)[i])) << 24) | \
+ (((u32)((t)[i+1])) << 16) | \
+ (((u32)((t)[i+2])) << 8) | \
+ ((u32)((t)[i+3])))
+
+
+#endif /* __PVRUSB2_UTIL_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
new file mode 100644
index 00000000000..0caf70b8c0d
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -0,0 +1,1124 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include "pvrusb2-context.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2.h"
+#include "pvrusb2-debug.h"
+#include "pvrusb2-v4l2.h"
+#include "pvrusb2-ioread.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+
+struct pvr2_v4l2_dev;
+struct pvr2_v4l2_fh;
+struct pvr2_v4l2;
+
+/* V4L no longer provide the ability to set / get a private context pointer
+ (i.e. video_get_drvdata / video_set_drvdata), which means we have to
+ concoct our own context locating mechanism. Supposedly this is intended
+ to simplify driver implementation. It's not clear to me how that can
+ possibly be true. Our solution here is to maintain a lookup table of
+ our context instances, indexed by the minor device number of the V4L
+ device. See pvr2_v4l2_open() for some implications of this approach. */
+static struct pvr2_v4l2_dev *devices[256];
+static DEFINE_MUTEX(device_lock);
+
+struct pvr2_v4l2_dev {
+ struct pvr2_v4l2 *v4lp;
+ struct video_device *vdev;
+ struct pvr2_context_stream *stream;
+ int ctxt_idx;
+ enum pvr2_config config;
+};
+
+struct pvr2_v4l2_fh {
+ struct pvr2_channel channel;
+ struct pvr2_v4l2_dev *dev_info;
+ enum v4l2_priority prio;
+ struct pvr2_ioread *rhp;
+ struct file *file;
+ struct pvr2_v4l2 *vhead;
+ struct pvr2_v4l2_fh *vnext;
+ struct pvr2_v4l2_fh *vprev;
+ wait_queue_head_t wait_data;
+ int fw_mode_flag;
+};
+
+struct pvr2_v4l2 {
+ struct pvr2_channel channel;
+ struct pvr2_v4l2_fh *vfirst;
+ struct pvr2_v4l2_fh *vlast;
+
+ struct v4l2_prio_state prio;
+
+ /* streams */
+ struct pvr2_v4l2_dev video_dev;
+};
+
+static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
+module_param_array(video_nr, int, NULL, 0444);
+MODULE_PARM_DESC(video_nr, "Offset for device's minor");
+
+static struct v4l2_capability pvr_capability ={
+ .driver = "pvrusb2",
+ .card = "Hauppauge WinTV pvr-usb2",
+ .bus_info = "usb",
+ .version = KERNEL_VERSION(0,8,0),
+ .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+ V4L2_CAP_READWRITE),
+ .reserved = {0,0,0,0}
+};
+
+static struct v4l2_tuner pvr_v4l2_tuners[]= {
+ {
+ .index = 0,
+ .name = "TV Tuner",
+ .type = V4L2_TUNER_ANALOG_TV,
+ .capability = (V4L2_TUNER_CAP_NORM |
+ V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2),
+ .rangelow = 0,
+ .rangehigh = 0,
+ .rxsubchans = V4L2_TUNER_SUB_STEREO,
+ .audmode = V4L2_TUNER_MODE_STEREO,
+ .signal = 0,
+ .afc = 0,
+ .reserved = {0,0,0,0}
+ }
+};
+
+static struct v4l2_fmtdesc pvr_fmtdesc [] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .flags = V4L2_FMT_FLAG_COMPRESSED,
+ .description = "MPEG1/2",
+ // This should really be V4L2_PIX_FMT_MPEG, but xawtv
+ // breaks when I do that.
+ .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
+ .reserved = { 0, 0, 0, 0 }
+ }
+};
+
+#define PVR_FORMAT_PIX 0
+#define PVR_FORMAT_VBI 1
+
+static struct v4l2_format pvr_format [] = {
+ [PVR_FORMAT_PIX] = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .fmt = {
+ .pix = {
+ .width = 720,
+ .height = 576,
+ // This should really be V4L2_PIX_FMT_MPEG,
+ // but xawtv breaks when I do that.
+ .pixelformat = 0, // V4L2_PIX_FMT_MPEG,
+ .field = V4L2_FIELD_INTERLACED,
+ .bytesperline = 0, // doesn't make sense
+ // here
+ //FIXME : Don't know what to put here...
+ .sizeimage = (32*1024),
+ .colorspace = 0, // doesn't make sense here
+ .priv = 0
+ }
+ }
+ },
+ [PVR_FORMAT_VBI] = {
+ .type = V4L2_BUF_TYPE_VBI_CAPTURE,
+ .fmt = {
+ .vbi = {
+ .sampling_rate = 27000000,
+ .offset = 248,
+ .samples_per_line = 1443,
+ .sample_format = V4L2_PIX_FMT_GREY,
+ .start = { 0, 0 },
+ .count = { 0, 0 },
+ .flags = 0,
+ .reserved = { 0, 0 }
+ }
+ }
+ }
+};
+
+/*
+ * pvr_ioctl()
+ *
+ * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
+ *
+ */
+static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ struct pvr2_v4l2 *vp = fh->vhead;
+ struct pvr2_v4l2_dev *dev_info = fh->dev_info;
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ int ret = -EINVAL;
+
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+ v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),cmd);
+ }
+
+ if (!pvr2_hdw_dev_ok(hdw)) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "ioctl failed - bad or no context");
+ return -EFAULT;
+ }
+
+ /* check priority */
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_S_FREQUENCY:
+ ret = v4l2_prio_check(&vp->prio, &fh->prio);
+ if (ret)
+ return ret;
+ }
+
+ switch (cmd) {
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+
+ ret = 0;
+ break;
+ }
+
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+
+ *p = v4l2_prio_max(&vp->prio);
+ ret = 0;
+ break;
+ }
+
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *prio = arg;
+
+ ret = v4l2_prio_change(&vp->prio, &fh->prio, *prio);
+ break;
+ }
+
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *vs = (struct v4l2_standard *)arg;
+ int idx = vs->index;
+ ret = pvr2_hdw_get_stdenum_value(hdw,vs,idx+1);
+ break;
+ }
+
+ case VIDIOC_G_STD:
+ {
+ int val = 0;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),&val);
+ *(v4l2_std_id *)arg = val;
+ break;
+ }
+
+ case VIDIOC_S_STD:
+ {
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_STDCUR),
+ *(v4l2_std_id *)arg);
+ break;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct pvr2_ctrl *cptr;
+ struct v4l2_input *vi = (struct v4l2_input *)arg;
+ struct v4l2_input tmp;
+ unsigned int cnt;
+
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+
+ memset(&tmp,0,sizeof(tmp));
+ tmp.index = vi->index;
+ ret = 0;
+ switch (vi->index) {
+ case PVR2_CVAL_INPUT_TV:
+ case PVR2_CVAL_INPUT_RADIO:
+ tmp.type = V4L2_INPUT_TYPE_TUNER;
+ break;
+ case PVR2_CVAL_INPUT_SVIDEO:
+ case PVR2_CVAL_INPUT_COMPOSITE:
+ tmp.type = V4L2_INPUT_TYPE_CAMERA;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret < 0) break;
+
+ cnt = 0;
+ pvr2_ctrl_get_valname(cptr,vi->index,
+ tmp.name,sizeof(tmp.name)-1,&cnt);
+ tmp.name[cnt] = 0;
+
+ /* Don't bother with audioset, since this driver currently
+ always switches the audio whenever the video is
+ switched. */
+
+ /* Handling std is a tougher problem. It doesn't make
+ sense in cases where a device might be multi-standard.
+ We could just copy out the current value for the
+ standard, but it can change over time. For now just
+ leave it zero. */
+
+ memcpy(vi, &tmp, sizeof(tmp));
+
+ ret = 0;
+ break;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ struct pvr2_ctrl *cptr;
+ struct v4l2_input *vi = (struct v4l2_input *)arg;
+ int val;
+ cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ val = 0;
+ ret = pvr2_ctrl_get_value(cptr,&val);
+ vi->index = val;
+ break;
+ }
+
+ case VIDIOC_S_INPUT:
+ {
+ struct v4l2_input *vi = (struct v4l2_input *)arg;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ vi->index);
+ break;
+ }
+
+ case VIDIOC_ENUMAUDIO:
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ case VIDIOC_G_AUDIO:
+ {
+ ret = -EINVAL;
+ break;
+ }
+
+ case VIDIOC_S_AUDIO:
+ {
+ ret = -EINVAL;
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+ unsigned int status_mask;
+ int val;
+ if (vt->index !=0) break;
+
+ status_mask = pvr2_hdw_get_signal_status(hdw);
+
+ memcpy(vt, &pvr_v4l2_tuners[vt->index],
+ sizeof(struct v4l2_tuner));
+
+ vt->signal = 0;
+ if (status_mask & PVR2_SIGNAL_OK) {
+ if (status_mask & PVR2_SIGNAL_STEREO) {
+ vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
+ if (status_mask & PVR2_SIGNAL_SAP) {
+ vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 |
+ V4L2_TUNER_SUB_LANG2);
+ }
+ vt->signal = 65535;
+ }
+
+ val = 0;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+ &val);
+ vt->audmode = val;
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *vt=(struct v4l2_tuner *)arg;
+
+ if (vt->index != 0)
+ break;
+
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE),
+ vt->audmode);
+ }
+
+ case VIDIOC_S_FREQUENCY:
+ {
+ const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+ vf->frequency * 62500);
+ break;
+ }
+
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *vf = (struct v4l2_frequency *)arg;
+ int val = 0;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),
+ &val);
+ val /= 62500;
+ vf->frequency = val;
+ break;
+ }
+
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *fd = (struct v4l2_fmtdesc *)arg;
+
+ /* Only one format is supported : mpeg.*/
+ if (fd->index != 0)
+ break;
+
+ memcpy(fd, pvr_fmtdesc, sizeof(struct v4l2_fmtdesc));
+ ret = 0;
+ break;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *vf = (struct v4l2_format *)arg;
+ int val;
+ switch(vf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+ sizeof(struct v4l2_format));
+ val = 0;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES),
+ &val);
+ vf->fmt.pix.width = val;
+ val = 0;
+ pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES),
+ &val);
+ vf->fmt.pix.height = val;
+ ret = 0;
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ // ????? Still need to figure out to do VBI correctly
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *vf = (struct v4l2_format *)arg;
+
+ ret = 0;
+ switch(vf->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ int h = vf->fmt.pix.height;
+ int w = vf->fmt.pix.width;
+
+ if (h < 200) {
+ h = 200;
+ } else if (h > 625) {
+ h = 625;
+ }
+ if (w < 320) {
+ w = 320;
+ } else if (w > 720) {
+ w = 720;
+ }
+
+ memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
+ sizeof(struct v4l2_format));
+ vf->fmt.pix.width = w;
+ vf->fmt.pix.height = h;
+
+ if (cmd == VIDIOC_S_FMT) {
+ pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,
+ PVR2_CID_HRES),
+ vf->fmt.pix.width);
+ pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,
+ PVR2_CID_VRES),
+ vf->fmt.pix.height);
+ }
+ } break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ // ????? Still need to figure out to do VBI correctly
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+
+ case VIDIOC_STREAMON:
+ {
+ ret = pvr2_hdw_set_stream_type(hdw,dev_info->config);
+ if (ret < 0) return ret;
+ ret = pvr2_hdw_set_streaming(hdw,!0);
+ break;
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ ret = pvr2_hdw_set_streaming(hdw,0);
+ break;
+ }
+
+ case VIDIOC_QUERYCTRL:
+ {
+ struct pvr2_ctrl *cptr;
+ struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg;
+ ret = 0;
+ if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) {
+ cptr = pvr2_hdw_get_ctrl_nextv4l(
+ hdw,(vc->id & ~V4L2_CTRL_FLAG_NEXT_CTRL));
+ if (cptr) vc->id = pvr2_ctrl_get_v4lid(cptr);
+ } else {
+ cptr = pvr2_hdw_get_ctrl_v4l(hdw,vc->id);
+ }
+ if (!cptr) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x not implemented here",
+ vc->id);
+ ret = -EINVAL;
+ break;
+ }
+
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x mapping name=%s (%s)",
+ vc->id,pvr2_ctrl_get_name(cptr),
+ pvr2_ctrl_get_desc(cptr));
+ strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name));
+ vc->flags = pvr2_ctrl_get_v4lflags(cptr);
+ vc->default_value = pvr2_ctrl_get_def(cptr);
+ switch (pvr2_ctrl_get_type(cptr)) {
+ case pvr2_ctl_enum:
+ vc->type = V4L2_CTRL_TYPE_MENU;
+ vc->minimum = 0;
+ vc->maximum = pvr2_ctrl_get_cnt(cptr) - 1;
+ vc->step = 1;
+ break;
+ case pvr2_ctl_bool:
+ vc->type = V4L2_CTRL_TYPE_BOOLEAN;
+ vc->minimum = 0;
+ vc->maximum = 1;
+ vc->step = 1;
+ break;
+ case pvr2_ctl_int:
+ vc->type = V4L2_CTRL_TYPE_INTEGER;
+ vc->minimum = pvr2_ctrl_get_min(cptr);
+ vc->maximum = pvr2_ctrl_get_max(cptr);
+ vc->step = 1;
+ break;
+ default:
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "QUERYCTRL id=0x%x name=%s not mappable",
+ vc->id,pvr2_ctrl_get_name(cptr));
+ ret = -EINVAL;
+ break;
+ }
+ break;
+ }
+
+ case VIDIOC_QUERYMENU:
+ {
+ struct v4l2_querymenu *vm = (struct v4l2_querymenu *)arg;
+ unsigned int cnt = 0;
+ ret = pvr2_ctrl_get_valname(pvr2_hdw_get_ctrl_v4l(hdw,vm->id),
+ vm->index,
+ vm->name,sizeof(vm->name)-1,
+ &cnt);
+ vm->name[cnt] = 0;
+ break;
+ }
+
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *vc = (struct v4l2_control *)arg;
+ int val = 0;
+ ret = pvr2_ctrl_get_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+ &val);
+ vc->value = val;
+ break;
+ }
+
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *vc = (struct v4l2_control *)arg;
+ ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_v4l(hdw,vc->id),
+ vc->value);
+ break;
+ }
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctls =
+ (struct v4l2_ext_controls *)arg;
+ struct v4l2_ext_control *ctrl;
+ unsigned int idx;
+ int val;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ ret = pvr2_ctrl_get_value(
+ pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),&val);
+ if (ret) {
+ ctls->error_idx = idx;
+ break;
+ }
+ /* Ensure that if read as a 64 bit value, the user
+ will still get a hopefully sane value */
+ ctrl->value64 = 0;
+ ctrl->value = val;
+ }
+ break;
+ }
+
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctls =
+ (struct v4l2_ext_controls *)arg;
+ struct v4l2_ext_control *ctrl;
+ unsigned int idx;
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id),
+ ctrl->value);
+ if (ret) {
+ ctls->error_idx = idx;
+ break;
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *ctls =
+ (struct v4l2_ext_controls *)arg;
+ struct v4l2_ext_control *ctrl;
+ struct pvr2_ctrl *pctl;
+ unsigned int idx;
+ /* For the moment just validate that the requested control
+ actually exists. */
+ for (idx = 0; idx < ctls->count; idx++) {
+ ctrl = ctls->controls + idx;
+ pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id);
+ if (!pctl) {
+ ret = -EINVAL;
+ ctls->error_idx = idx;
+ break;
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ {
+ pvr2_hdw_trigger_module_log(hdw);
+ ret = 0;
+ break;
+ }
+
+ default :
+ ret = v4l_compat_translate_ioctl(inode,file,cmd,
+ arg,pvr2_v4l2_do_ioctl);
+ }
+
+ pvr2_hdw_commit_ctl(hdw);
+
+ if (ret < 0) {
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "pvr2_v4l2_do_ioctl failure, ret=%d",ret);
+ } else {
+ if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "pvr2_v4l2_do_ioctl failure, ret=%d"
+ " command was:",ret);
+ v4l_print_ioctl(pvr2_hdw_get_driver_name(hdw),
+ cmd);
+ }
+ }
+ } else {
+ pvr2_trace(PVR2_TRACE_V4LIOCTL,
+ "pvr2_v4l2_do_ioctl complete, ret=%d (0x%x)",
+ ret,ret);
+ }
+ return ret;
+}
+
+
+static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
+{
+ printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
+ dip->vdev->minor,pvr2_config_get_name(dip->config));
+ if (dip->ctxt_idx >= 0) {
+ mutex_lock(&device_lock);
+ devices[dip->ctxt_idx] = NULL;
+ dip->ctxt_idx = -1;
+ mutex_unlock(&device_lock);
+ }
+ video_unregister_device(dip->vdev);
+}
+
+
+static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
+{
+ pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
+ pvr2_v4l2_dev_destroy(&vp->video_dev);
+
+ pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
+ pvr2_channel_done(&vp->channel);
+ kfree(vp);
+}
+
+
+static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
+{
+ struct pvr2_v4l2 *vp;
+ vp = container_of(chp,struct pvr2_v4l2,channel);
+ if (!vp->channel.mc_head->disconnect_flag) return;
+ if (vp->vfirst) return;
+ pvr2_v4l2_destroy_no_lock(vp);
+}
+
+
+static int pvr2_v4l2_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+
+/* Temporary hack : use ivtv api until a v4l2 one is available. */
+#define IVTV_IOC_G_CODEC 0xFFEE7703
+#define IVTV_IOC_S_CODEC 0xFFEE7704
+ if (cmd == IVTV_IOC_G_CODEC || cmd == IVTV_IOC_S_CODEC) return 0;
+ return video_usercopy(inode, file, cmd, arg, pvr2_v4l2_do_ioctl);
+}
+
+
+static int pvr2_v4l2_release(struct inode *inode, struct file *file)
+{
+ struct pvr2_v4l2_fh *fhp = file->private_data;
+ struct pvr2_v4l2 *vp = fhp->vhead;
+ struct pvr2_context *mp = fhp->vhead->channel.mc_head;
+
+ pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
+
+ if (fhp->rhp) {
+ struct pvr2_stream *sp;
+ struct pvr2_hdw *hdw;
+ hdw = fhp->channel.mc_head->hdw;
+ pvr2_hdw_set_streaming(hdw,0);
+ sp = pvr2_ioread_get_stream(fhp->rhp);
+ if (sp) pvr2_stream_set_callback(sp,NULL,NULL);
+ pvr2_ioread_destroy(fhp->rhp);
+ fhp->rhp = NULL;
+ }
+ v4l2_prio_close(&vp->prio, &fhp->prio);
+ file->private_data = NULL;
+
+ pvr2_context_enter(mp); do {
+ if (fhp->vnext) {
+ fhp->vnext->vprev = fhp->vprev;
+ } else {
+ vp->vlast = fhp->vprev;
+ }
+ if (fhp->vprev) {
+ fhp->vprev->vnext = fhp->vnext;
+ } else {
+ vp->vfirst = fhp->vnext;
+ }
+ fhp->vnext = NULL;
+ fhp->vprev = NULL;
+ fhp->vhead = NULL;
+ pvr2_channel_done(&fhp->channel);
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "Destroying pvr_v4l2_fh id=%p",fhp);
+ kfree(fhp);
+ if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+ pvr2_v4l2_destroy_no_lock(vp);
+ }
+ } while (0); pvr2_context_exit(mp);
+ return 0;
+}
+
+
+static int pvr2_v4l2_open(struct inode *inode, struct file *file)
+{
+ struct pvr2_v4l2_dev *dip = NULL; /* Our own context pointer */
+ struct pvr2_v4l2_fh *fhp;
+ struct pvr2_v4l2 *vp;
+ struct pvr2_hdw *hdw;
+
+ mutex_lock(&device_lock);
+ /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
+ atomic read of the device mapping array here, we still need the
+ mutex. The problem is that there is a tiny race possible when
+ we register the device. We can't update the device mapping
+ array until after the device has been registered, owing to the
+ fact that we can't know the minor device number until after the
+ registration succeeds. And if another thread tries to open the
+ device in the window of time after registration but before the
+ map is updated, then it will get back an erroneous null pointer
+ and the open will result in a spurious failure. The only way to
+ prevent that is to (a) be inside the mutex here before we access
+ the array, and (b) cover the entire registration process later
+ on with this same mutex. Thus if we get inside the mutex here,
+ then we can be assured that the registration process actually
+ completed correctly. This is an unhappy complication from the
+ use of global data in a driver that lives in a preemptible
+ environment. It sure would be nice if the video device itself
+ had a means for storing and retrieving a local context pointer.
+ Oh wait. It did. But now it's gone. Silly me. */
+ {
+ unsigned int midx = iminor(file->f_dentry->d_inode);
+ if (midx < sizeof(devices)/sizeof(devices[0])) {
+ dip = devices[midx];
+ }
+ }
+ mutex_unlock(&device_lock);
+
+ if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
+
+ vp = dip->v4lp;
+ hdw = vp->channel.hdw;
+
+ pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_open");
+
+ if (!pvr2_hdw_dev_ok(hdw)) {
+ pvr2_trace(PVR2_TRACE_OPEN_CLOSE,
+ "pvr2_v4l2_open: hardware not ready");
+ return -EIO;
+ }
+
+ fhp = kmalloc(sizeof(*fhp),GFP_KERNEL);
+ if (!fhp) {
+ return -ENOMEM;
+ }
+ memset(fhp,0,sizeof(*fhp));
+
+ init_waitqueue_head(&fhp->wait_data);
+ fhp->dev_info = dip;
+
+ pvr2_context_enter(vp->channel.mc_head); do {
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
+ pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+ fhp->vnext = NULL;
+ fhp->vprev = vp->vlast;
+ if (vp->vlast) {
+ vp->vlast->vnext = fhp;
+ } else {
+ vp->vfirst = fhp;
+ }
+ vp->vlast = fhp;
+ fhp->vhead = vp;
+ } while (0); pvr2_context_exit(vp->channel.mc_head);
+
+ fhp->file = file;
+ file->private_data = fhp;
+ v4l2_prio_open(&vp->prio,&fhp->prio);
+
+ fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw);
+
+ return 0;
+}
+
+
+static void pvr2_v4l2_notify(struct pvr2_v4l2_fh *fhp)
+{
+ wake_up(&fhp->wait_data);
+}
+
+static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh)
+{
+ int ret;
+ struct pvr2_stream *sp;
+ struct pvr2_hdw *hdw;
+ if (fh->rhp) return 0;
+
+ /* First read() attempt. Try to claim the stream and start
+ it... */
+ if ((ret = pvr2_channel_claim_stream(&fh->channel,
+ fh->dev_info->stream)) != 0) {
+ /* Someone else must already have it */
+ return ret;
+ }
+
+ fh->rhp = pvr2_channel_create_mpeg_stream(fh->dev_info->stream);
+ if (!fh->rhp) {
+ pvr2_channel_claim_stream(&fh->channel,NULL);
+ return -ENOMEM;
+ }
+
+ hdw = fh->channel.mc_head->hdw;
+ sp = fh->dev_info->stream->stream;
+ pvr2_stream_set_callback(sp,(pvr2_stream_callback)pvr2_v4l2_notify,fh);
+ pvr2_hdw_set_stream_type(hdw,fh->dev_info->config);
+ pvr2_hdw_set_streaming(hdw,!0);
+ ret = pvr2_ioread_set_enabled(fh->rhp,!0);
+
+ return ret;
+}
+
+
+static ssize_t pvr2_v4l2_read(struct file *file,
+ char __user *buff, size_t count, loff_t *ppos)
+{
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ int ret;
+
+ if (fh->fw_mode_flag) {
+ struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
+ char *tbuf;
+ int c1,c2;
+ int tcnt = 0;
+ unsigned int offs = *ppos;
+
+ tbuf = kmalloc(PAGE_SIZE,GFP_KERNEL);
+ if (!tbuf) return -ENOMEM;
+
+ while (count) {
+ c1 = count;
+ if (c1 > PAGE_SIZE) c1 = PAGE_SIZE;
+ c2 = pvr2_hdw_cpufw_get(hdw,offs,tbuf,c1);
+ if (c2 < 0) {
+ tcnt = c2;
+ break;
+ }
+ if (!c2) break;
+ if (copy_to_user(buff,tbuf,c2)) {
+ tcnt = -EFAULT;
+ break;
+ }
+ offs += c2;
+ tcnt += c2;
+ buff += c2;
+ count -= c2;
+ *ppos += c2;
+ }
+ kfree(tbuf);
+ return tcnt;
+ }
+
+ if (!fh->rhp) {
+ ret = pvr2_v4l2_iosetup(fh);
+ if (ret) {
+ return ret;
+ }
+ }
+
+ for (;;) {
+ ret = pvr2_ioread_read(fh->rhp,buff,count);
+ if (ret >= 0) break;
+ if (ret != -EAGAIN) break;
+ if (file->f_flags & O_NONBLOCK) break;
+ /* Doing blocking I/O. Wait here. */
+ ret = wait_event_interruptible(
+ fh->wait_data,
+ pvr2_ioread_avail(fh->rhp) >= 0);
+ if (ret < 0) break;
+ }
+
+ return ret;
+}
+
+
+static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
+{
+ unsigned int mask = 0;
+ struct pvr2_v4l2_fh *fh = file->private_data;
+ int ret;
+
+ if (fh->fw_mode_flag) {
+ mask |= POLLIN | POLLRDNORM;
+ return mask;
+ }
+
+ if (!fh->rhp) {
+ ret = pvr2_v4l2_iosetup(fh);
+ if (ret) return POLLERR;
+ }
+
+ poll_wait(file,&fh->wait_data,wait);
+
+ if (pvr2_ioread_avail(fh->rhp) >= 0) {
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ return mask;
+}
+
+
+static struct file_operations vdev_fops = {
+ .owner = THIS_MODULE,
+ .open = pvr2_v4l2_open,
+ .release = pvr2_v4l2_release,
+ .read = pvr2_v4l2_read,
+ .ioctl = pvr2_v4l2_ioctl,
+ .llseek = no_llseek,
+ .poll = pvr2_v4l2_poll,
+};
+
+
+#define VID_HARDWARE_PVRUSB2 38 /* FIXME : need a good value */
+
+static struct video_device vdev_template = {
+ .owner = THIS_MODULE,
+ .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER,
+ .type2 = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE
+ | V4L2_CAP_TUNER | V4L2_CAP_AUDIO
+ | V4L2_CAP_READWRITE),
+ .hardware = VID_HARDWARE_PVRUSB2,
+ .fops = &vdev_fops,
+};
+
+
+static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
+ struct pvr2_v4l2 *vp,
+ enum pvr2_config cfg)
+{
+ int mindevnum;
+ int unit_number;
+ int v4l_type;
+ dip->v4lp = vp;
+ dip->config = cfg;
+
+
+ switch (cfg) {
+ case pvr2_config_mpeg:
+ v4l_type = VFL_TYPE_GRABBER;
+ dip->stream = &vp->channel.mc_head->video_stream;
+ break;
+ case pvr2_config_vbi:
+ v4l_type = VFL_TYPE_VBI;
+ break;
+ case pvr2_config_radio:
+ v4l_type = VFL_TYPE_RADIO;
+ break;
+ default:
+ /* Bail out (this should be impossible) */
+ err("Failed to set up pvrusb2 v4l dev"
+ " due to unrecognized config");
+ return;
+ }
+
+ if (!dip->stream) {
+ err("Failed to set up pvrusb2 v4l dev"
+ " due to missing stream instance");
+ return;
+ }
+
+ dip->vdev = video_device_alloc();
+ if (!dip->vdev) {
+ err("Alloc of pvrusb2 v4l video device failed");
+ return;
+ }
+
+ memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
+ dip->vdev->release = video_device_release;
+ mutex_lock(&device_lock);
+
+ mindevnum = -1;
+ unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
+ if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
+ mindevnum = video_nr[unit_number];
+ }
+ if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) &&
+ (video_register_device(dip->vdev, v4l_type, -1) < 0)) {
+ err("Failed to register pvrusb2 v4l video device");
+ } else {
+ printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
+ dip->vdev->minor,pvr2_config_get_name(dip->config));
+ }
+
+ if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
+ (devices[dip->vdev->minor] == NULL)) {
+ dip->ctxt_idx = dip->vdev->minor;
+ devices[dip->ctxt_idx] = dip;
+ }
+ mutex_unlock(&device_lock);
+
+ pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
+ dip->vdev->minor);
+}
+
+
+struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
+{
+ struct pvr2_v4l2 *vp;
+
+ vp = kmalloc(sizeof(*vp),GFP_KERNEL);
+ if (!vp) return vp;
+ memset(vp,0,sizeof(*vp));
+ vp->video_dev.ctxt_idx = -1;
+ pvr2_channel_init(&vp->channel,mnp);
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
+
+ vp->channel.check_func = pvr2_v4l2_internal_check;
+
+ /* register streams */
+ pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg);
+
+
+ return vp;
+}
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.h b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
new file mode 100644
index 00000000000..9a995e2d225
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.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
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#ifndef __PVRUSB2_V4L2_H
+#define __PVRUSB2_V4L2_H
+
+#include "pvrusb2-context.h"
+
+struct pvr2_v4l2;
+
+struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *);
+
+#endif /* __PVRUSB2_V4L2_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 75 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
new file mode 100644
index 00000000000..05f2cddeb47
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.c
@@ -0,0 +1,253 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+
+ This source file is specifically designed to interface with the
+ saa711x support that is available in the v4l available starting
+ with linux 2.6.15.
+
+*/
+
+#include "pvrusb2-video-v4l.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/saa7115.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_decoder {
+ struct pvr2_i2c_handler handler;
+ struct pvr2_decoder_ctrl ctrl;
+ struct pvr2_i2c_client *client;
+ struct pvr2_hdw *hdw;
+ unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_decoder *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ struct v4l2_routing route;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_input(%d)",hdw->input_val);
+ switch(hdw->input_val) {
+ case PVR2_CVAL_INPUT_TV:
+ route.input = SAA7115_COMPOSITE4;
+ break;
+ case PVR2_CVAL_INPUT_COMPOSITE:
+ route.input = SAA7115_COMPOSITE5;
+ break;
+ case PVR2_CVAL_INPUT_SVIDEO:
+ route.input = SAA7115_SVIDEO2;
+ break;
+ case PVR2_CVAL_INPUT_RADIO:
+ // ????? No idea yet what to do here
+ default:
+ return;
+ }
+ route.output = 0;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_VIDEO_ROUTING,&route);
+}
+
+
+static int check_input(struct pvr2_v4l_decoder *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->input_dirty != 0;
+}
+
+
+static void set_audio(struct pvr2_v4l_decoder *ctxt)
+{
+ u32 val;
+ struct pvr2_hdw *hdw = ctxt->hdw;
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 set_audio %d",
+ hdw->srate_val);
+ switch (hdw->srate_val) {
+ default:
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000:
+ val = 48000;
+ break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100:
+ val = 44100;
+ break;
+ case V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000:
+ val = 32000;
+ break;
+ }
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_AUDIO_CLOCK_FREQ,&val);
+}
+
+
+static int check_audio(struct pvr2_v4l_decoder *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->srate_dirty != 0;
+}
+
+
+struct pvr2_v4l_decoder_ops {
+ void (*update)(struct pvr2_v4l_decoder *);
+ int (*check)(struct pvr2_v4l_decoder *);
+};
+
+
+static const struct pvr2_v4l_decoder_ops decoder_ops[] = {
+ { .update = set_input, .check = check_input},
+ { .update = set_audio, .check = check_audio},
+};
+
+
+static void decoder_detach(struct pvr2_v4l_decoder *ctxt)
+{
+ ctxt->client->handler = NULL;
+ ctxt->hdw->decoder_ctrl = NULL;
+ kfree(ctxt);
+}
+
+
+static int decoder_check(struct pvr2_v4l_decoder *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (decoder_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
+}
+
+
+static void decoder_update(struct pvr2_v4l_decoder *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ decoder_ops[idx].update(ctxt);
+ }
+}
+
+
+static int decoder_detect(struct pvr2_i2c_client *cp)
+{
+ /* Attempt to query the decoder - let's see if it will answer */
+ struct v4l2_tuner vt;
+ int ret;
+
+ memset(&vt,0,sizeof(vt));
+ ret = pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&vt);
+ return ret == 0; /* Return true if it answered */
+}
+
+
+static void decoder_enable(struct pvr2_v4l_decoder *ctxt,int fl)
+{
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 decoder_enable(%d)",fl);
+ pvr2_v4l2_cmd_stream(ctxt->client,fl);
+}
+
+
+static int decoder_is_tuned(struct pvr2_v4l_decoder *ctxt)
+{
+ struct v4l2_tuner vt;
+ int ret;
+
+ memset(&vt,0,sizeof(vt));
+ ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
+ if (ret < 0) return -EINVAL;
+ return vt.signal ? 1 : 0;
+}
+
+
+static unsigned int decoder_describe(struct pvr2_v4l_decoder *ctxt,char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-video-v4l");
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+ .detach = (void (*)(void *))decoder_detach,
+ .check = (int (*)(void *))decoder_check,
+ .update = (void (*)(void *))decoder_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))decoder_describe,
+};
+
+
+int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *hdw,
+ struct pvr2_i2c_client *cp)
+{
+ struct pvr2_v4l_decoder *ctxt;
+
+ if (hdw->decoder_ctrl) return 0;
+ if (cp->handler) return 0;
+ if (!decoder_detect(cp)) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->handler.func_data = ctxt;
+ ctxt->handler.func_table = &hfuncs;
+ ctxt->ctrl.ctxt = ctxt;
+ ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
+ ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
+ ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
+ sizeof(decoder_ops[0]))) - 1;
+ hdw->decoder_ctrl = &ctxt->ctrl;
+ cp->handler = &ctxt->handler;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x saa711x V4L2 handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
new file mode 100644
index 00000000000..2b917fda02e
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-video-v4l.h
@@ -0,0 +1,52 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_VIDEO_V4L_H
+#define __PVRUSB2_VIDEO_V4L_H
+
+/*
+
+ This module connects the pvrusb2 driver to the I2C chip level
+ driver which handles device video processing. This interface is
+ used internally by the driver; higher level code should only
+ interact through the interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_decoder_v4l_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_VIDEO_V4L_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.c b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
new file mode 100644
index 00000000000..2413e5198e1
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.c
@@ -0,0 +1,170 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/*
+
+ This source file is specifically designed to interface with the
+ wm8775.
+
+*/
+
+#include "pvrusb2-wm8775.h"
+#include "pvrusb2-i2c-cmd-v4l2.h"
+
+
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-debug.h"
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+struct pvr2_v4l_wm8775 {
+ struct pvr2_i2c_handler handler;
+ struct pvr2_i2c_client *client;
+ struct pvr2_hdw *hdw;
+ unsigned long stale_mask;
+};
+
+
+static void set_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+ struct v4l2_routing route;
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ int msk = 0;
+
+ memset(&route,0,sizeof(route));
+
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c wm8775 set_input(val=%d msk=0x%x)",
+ hdw->input_val,msk);
+
+ // Always point to input #1 no matter what
+ route.input = 2;
+ pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_S_AUDIO_ROUTING,&route);
+}
+
+static int check_input(struct pvr2_v4l_wm8775 *ctxt)
+{
+ struct pvr2_hdw *hdw = ctxt->hdw;
+ return hdw->input_dirty != 0;
+}
+
+
+struct pvr2_v4l_wm8775_ops {
+ void (*update)(struct pvr2_v4l_wm8775 *);
+ int (*check)(struct pvr2_v4l_wm8775 *);
+};
+
+
+static const struct pvr2_v4l_wm8775_ops wm8775_ops[] = {
+ { .update = set_input, .check = check_input},
+};
+
+
+static unsigned int wm8775_describe(struct pvr2_v4l_wm8775 *ctxt,
+ char *buf,unsigned int cnt)
+{
+ return scnprintf(buf,cnt,"handler: pvrusb2-wm8775");
+}
+
+
+static void wm8775_detach(struct pvr2_v4l_wm8775 *ctxt)
+{
+ ctxt->client->handler = NULL;
+ kfree(ctxt);
+}
+
+
+static int wm8775_check(struct pvr2_v4l_wm8775 *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (ctxt->stale_mask & msk) continue;
+ if (wm8775_ops[idx].check(ctxt)) {
+ ctxt->stale_mask |= msk;
+ }
+ }
+ return ctxt->stale_mask != 0;
+}
+
+
+static void wm8775_update(struct pvr2_v4l_wm8775 *ctxt)
+{
+ unsigned long msk;
+ unsigned int idx;
+
+ for (idx = 0; idx < sizeof(wm8775_ops)/sizeof(wm8775_ops[0]);
+ idx++) {
+ msk = 1 << idx;
+ if (!(ctxt->stale_mask & msk)) continue;
+ ctxt->stale_mask &= ~msk;
+ wm8775_ops[idx].update(ctxt);
+ }
+}
+
+
+const static struct pvr2_i2c_handler_functions hfuncs = {
+ .detach = (void (*)(void *))wm8775_detach,
+ .check = (int (*)(void *))wm8775_check,
+ .update = (void (*)(void *))wm8775_update,
+ .describe = (unsigned int (*)(void *,char *,unsigned int))wm8775_describe,
+};
+
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
+{
+ struct pvr2_v4l_wm8775 *ctxt;
+
+ if (cp->handler) return 0;
+
+ ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
+ if (!ctxt) return 0;
+ memset(ctxt,0,sizeof(*ctxt));
+
+ ctxt->handler.func_data = ctxt;
+ ctxt->handler.func_table = &hfuncs;
+ ctxt->client = cp;
+ ctxt->hdw = hdw;
+ ctxt->stale_mask = (1 << (sizeof(wm8775_ops)/
+ sizeof(wm8775_ops[0]))) - 1;
+ cp->handler = &ctxt->handler;
+ pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x wm8775 V4L2 handler set up",
+ cp->client->addr);
+ return !0;
+}
+
+
+
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-wm8775.h b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
new file mode 100644
index 00000000000..8aaeff4e1e2
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-wm8775.h
@@ -0,0 +1,53 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_WM8775_H
+#define __PVRUSB2_WM8775_H
+
+/*
+
+ This module connects the pvrusb2 driver to the I2C chip level
+ driver which performs analog -> digital audio conversion for
+ external audio inputs. This interface is used internally by the
+ driver; higher level code should only interact through the
+ interface provided by pvrusb2-hdw.h.
+
+*/
+
+
+
+#include "pvrusb2-i2c-core.h"
+
+int pvr2_i2c_wm8775_setup(struct pvr2_hdw *,struct pvr2_i2c_client *);
+
+
+#endif /* __PVRUSB2_WM8775_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2.h b/drivers/media/video/pvrusb2/pvrusb2.h
new file mode 100644
index 00000000000..074533e9c21
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * $Id$
+ *
+ * Copyright (C) 2005 Mike Isely <isely@pobox.com>
+ * Copyright (C) 2004 Aurelien Alleaume <slts@free.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef __PVRUSB2_H
+#define __PVRUSB2_H
+
+/* Maximum number of pvrusb2 instances we can track at once. You
+ might want to increase this - however the driver operation will not
+ be impaired if it is too small. Instead additional units just
+ won't have an ID assigned and it might not be possible to specify
+ module paramters for those extra units. */
+#define PVR_NUM 20
+
+#endif /* __PVRUSB2_H */
+
+/*
+ Stuff for Emacs to see, in order to encourage consistent editing style:
+ *** Local Variables: ***
+ *** mode: c ***
+ *** fill-column: 70 ***
+ *** tab-width: 8 ***
+ *** c-basic-offset: 8 ***
+ *** End: ***
+ */
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 53cbc950f95..8fdf7101d3b 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -7,6 +7,7 @@ config USB_PWC
* Philips PCA645, PCA646
* Philips PCVC675, PCVC680, PCVC690
* Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+ * Philips SPC900NC
* Askey VC010
* Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
and 'Orbit'/'Sphere'
@@ -19,10 +20,18 @@ config USB_PWC
and never will be, but the 665 and 720/20 are supported by other
drivers.
- See <file:Documentation/usb/philips.txt> for more information and
- installation instructions.
+ Some newer logitech webcams are not handled by this driver but by the
+ Usb Video Class driver (linux-uvc).
The built-in microphone is enabled by selecting USB Audio support.
To compile this driver as a module, choose M here: the
module will be called pwc.
+
+config USB_PWC_DEBUG
+ bool "USB Philips Cameras verbose debug"
+ depends on USB_PWC
+ help
+ Say Y here in order to have the pwc driver generate verbose debugging
+ messages.
+ A special module options 'trace' is used to control the verbosity.
diff --git a/drivers/media/video/pwc/Makefile b/drivers/media/video/pwc/Makefile
index 33d60126c02..9db2260d10c 100644
--- a/drivers/media/video/pwc/Makefile
+++ b/drivers/media/video/pwc/Makefile
@@ -1,3 +1,12 @@
-pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
obj-$(CONFIG_USB_PWC) += pwc.o
+
+ifeq ($(CONFIG_USB_PWC_DEBUG),y)
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
+else
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
+endif
+
+
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index 4ba549bfa0e..0bd115588f3 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -2,7 +2,7 @@
Functions that send various control messages to the webcam, including
video modes.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -41,12 +41,14 @@
#include <asm/uaccess.h>
#endif
#include <asm/errno.h>
+#include <linux/version.h>
#include "pwc.h"
-#include "pwc-ioctl.h"
#include "pwc-uncompress.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
/* Request types: video */
#define SET_LUM_CTL 0x01
@@ -57,6 +59,10 @@
#define GET_STATUS_CTL 0x06
#define SET_EP_STREAM_CTL 0x07
#define GET_EP_STREAM_CTL 0x08
+#define GET_XX_CTL 0x09
+#define SET_XX_CTL 0x0A
+#define GET_XY_CTL 0x0B
+#define SET_XY_CTL 0x0C
#define SET_MPT_CTL 0x0D
#define GET_MPT_CTL 0x0E
@@ -93,12 +99,20 @@
#define READ_SHUTTER_FORMATTER 0x0600
#define READ_RED_GAIN_FORMATTER 0x0700
#define READ_BLUE_GAIN_FORMATTER 0x0800
+#define GET_STATUS_B00 0x0B00
#define SENSOR_TYPE_FORMATTER1 0x0C00
+#define GET_STATUS_3000 0x3000
#define READ_RAW_Y_MEAN_FORMATTER 0x3100
#define SET_POWER_SAVE_MODE_FORMATTER 0x3200
#define MIRROR_IMAGE_FORMATTER 0x3300
#define LED_FORMATTER 0x3400
+#define LOWLIGHT 0x3500
+#define GET_STATUS_3600 0x3600
#define SENSOR_TYPE_FORMATTER2 0x3700
+#define GET_STATUS_3800 0x3800
+#define GET_STATUS_4000 0x4000
+#define GET_STATUS_4100 0x4100 /* Get */
+#define CTL_STATUS_4200 0x4200 /* [GS] 1 */
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
@@ -138,6 +152,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
#include "pwc-nala.h"
};
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
/****************************************************************************/
@@ -159,31 +174,7 @@ static struct Nala_table_entry Nala_table[PSZ_MAX][8] =
&buf, buflen, 500)
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
- int i;
- unsigned char *s;
- char buf[100], *d;
-
- s = (unsigned char *)p;
- d = buf;
- *d = '\0';
- Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
- for (i = 0; i < len; i++) {
- d += sprintf(d, "%02X ", *s++);
- if ((i & 0xF) == 0xF) {
- Debug("%s\n", buf);
- d = buf;
- *d = '\0';
- }
- }
- if ((i & 0xF) != 0)
- Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
{
return usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
@@ -196,7 +187,7 @@ static inline int send_video_command(struct usb_device *udev, int index, void *b
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
{
unsigned char buf[3];
int ret, fps;
@@ -229,34 +220,14 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
if (pEntry->alternate == 0)
return -EINVAL;
- if (pEntry->compressed)
- return -ENOENT; /* Not supported. */
-
memcpy(buf, pEntry->mode, 3);
ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
if (ret < 0) {
- Debug("Failed to send video command... %d\n", ret);
+ PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
return ret;
}
if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
- {
- switch(pdev->type) {
- case 645:
- case 646:
-/* pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
- break;
-
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-/* pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
- break;
- }
- }
+ pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
pdev->cmd_len = 3;
memcpy(pdev->cmd_buf, buf, 3);
@@ -283,7 +254,7 @@ static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int fra
}
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
{
unsigned char buf[13];
const struct Timon_table_entry *pChoose;
@@ -315,8 +286,8 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
if (ret < 0)
return ret;
-/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
- pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+ if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 13;
memcpy(pdev->cmd_buf, buf, 13);
@@ -336,7 +307,7 @@ static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int fr
}
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
{
const struct Kiara_table_entry *pChoose = NULL;
int fps, ret;
@@ -350,21 +321,14 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
fps = (frames / 5) - 1;
/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
- if (size == PSZ_VGA && frames == 5 && snapshot)
+ if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
{
/* Only available in case the raw palette is selected or
we have the decompressor available. This mode is
only available in compressed form
*/
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
- {
- Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
- pChoose = &RawEntry;
- }
- else
- {
- Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
- }
+ PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
+ pChoose = &RawEntry;
}
else
{
@@ -372,6 +336,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
if the preferred ratio is not available.
Skip this step when using RAW modes.
*/
+ snapshot = 0;
while (compression <= 3) {
pChoose = &Kiara_table[size][fps][compression];
if (pChoose->alternate != 0)
@@ -382,7 +347,7 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
if (pChoose == NULL || pChoose->alternate == 0)
return -ENOENT; /* Not supported. */
- Debug("Using alternate setting %d.\n", pChoose->alternate);
+ PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
/* usb_control_msg won't take staticly allocated arrays as argument?? */
memcpy(buf, pChoose->mode, 12);
@@ -394,8 +359,8 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
if (ret < 0)
return ret;
-/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
- pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+ if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 12;
memcpy(pdev->cmd_buf, buf, 12);
@@ -410,49 +375,13 @@ static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int fr
pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
else
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+ PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
+ pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
return 0;
}
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
- int i, factor = 0, filler = 0;
-
- /* for PALETTE_YUV420P */
- switch(pdev->vpalette)
- {
- case VIDEO_PALETTE_YUV420P:
- factor = 6;
- filler = 128;
- break;
- case VIDEO_PALETTE_RAW:
- factor = 6; /* can be uncompressed YUV420P */
- filler = 0;
- break;
- }
-
- /* Set sizes in bytes */
- pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
- pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
-
- /* Align offset, or you'll get some very weird results in
- YUV420 mode... x must be multiple of 4 (to get the Y's in
- place), and y even (or you'll mixup U & V). This is less of a
- problem for YUV420P.
- */
- pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
- pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
- /* Fill buffers with gray or black */
- for (i = 0; i < MAX_IMAGES; i++) {
- if (pdev->image_ptr[i] != NULL)
- memset(pdev->image_ptr[i], filler, pdev->view.size);
- }
-}
-
-
-
/**
@pdev: device structure
@width: viewport width
@@ -465,50 +394,78 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
{
int ret, size;
- Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+ PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
size = pwc_decode_size(pdev, width, height);
if (size < 0) {
- Debug("Could not find suitable size.\n");
+ PWC_DEBUG_MODULE("Could not find suitable size.\n");
return -ERANGE;
}
- Debug("decode_size = %d.\n", size);
+ PWC_TRACE("decode_size = %d.\n", size);
- ret = -EINVAL;
- switch(pdev->type) {
- case 645:
- case 646:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
ret = set_video_mode_Nala(pdev, size, frames);
- break;
- case 675:
- case 680:
- case 690:
- ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
- break;
-
- case 720:
- case 730:
- case 740:
- case 750:
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
- break;
+
+ } else {
+ ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
}
if (ret < 0) {
- if (ret == -ENOENT)
- Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
- else {
- Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
- }
+ PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
return ret;
}
pdev->view.x = width;
pdev->view.y = height;
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
pwc_set_image_buffer_size(pdev);
- Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+ PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
return 0;
}
+#define BLACK_Y 0
+#define BLACK_U 128
+#define BLACK_V 128
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+ int i, factor = 0;
+
+ /* for PALETTE_YUV420P */
+ switch(pdev->vpalette)
+ {
+ case VIDEO_PALETTE_YUV420P:
+ factor = 6;
+ break;
+ case VIDEO_PALETTE_RAW:
+ factor = 6; /* can be uncompressed YUV420P */
+ break;
+ }
+
+ /* Set sizes in bytes */
+ pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+ pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
+
+ /* Align offset, or you'll get some very weird results in
+ YUV420 mode... x must be multiple of 4 (to get the Y's in
+ place), and y even (or you'll mixup U & V). This is less of a
+ problem for YUV420P.
+ */
+ pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+ pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+ /* Fill buffers with black colors */
+ for (i = 0; i < pwc_mbufs; i++) {
+ unsigned char *p = pdev->image_data + pdev->images[i].offset;
+ memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
+ p += pdev->view.x * pdev->view.y;
+ memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
+ p += pdev->view.x * pdev->view.y/4;
+ memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
+ }
+}
+
+
/* BRIGHTNESS */
@@ -520,7 +477,7 @@ int pwc_get_brightness(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 9;
+ return buf;
}
int pwc_set_brightness(struct pwc_device *pdev, int value)
@@ -545,7 +502,7 @@ int pwc_get_contrast(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 10;
+ return buf;
}
int pwc_set_contrast(struct pwc_device *pdev, int value)
@@ -570,7 +527,7 @@ int pwc_get_gamma(struct pwc_device *pdev)
ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 11;
+ return buf;
}
int pwc_set_gamma(struct pwc_device *pdev, int value)
@@ -588,37 +545,47 @@ int pwc_set_gamma(struct pwc_device *pdev, int value)
/* SATURATION */
-int pwc_get_saturation(struct pwc_device *pdev)
+/* return a value between [-100 , 100] */
+int pwc_get_saturation(struct pwc_device *pdev, int *value)
{
char buf;
- int ret;
+ int ret, saturation_register;
if (pdev->type < 675)
- return -1;
- ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+ return -EINVAL;
+ if (pdev->type < 730)
+ saturation_register = SATURATION_MODE_FORMATTER2;
+ else
+ saturation_register = SATURATION_MODE_FORMATTER1;
+ ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1);
if (ret < 0)
return ret;
- return 32768 + buf * 327;
+ *value = (signed)buf;
+ return 0;
}
+/* @param value saturation color between [-100 , 100] */
int pwc_set_saturation(struct pwc_device *pdev, int value)
{
char buf;
+ int saturation_register;
if (pdev->type < 675)
return -EINVAL;
- if (value < 0)
- value = 0;
- if (value > 0xffff)
- value = 0xffff;
- /* saturation ranges from -100 to +100 */
- buf = (value - 32768) / 327;
- return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+ if (value < -100)
+ value = -100;
+ if (value > 100)
+ value = 100;
+ if (pdev->type < 730)
+ saturation_register = SATURATION_MODE_FORMATTER2;
+ else
+ saturation_register = SATURATION_MODE_FORMATTER1;
+ return SendControlMsg(SET_CHROM_CTL, saturation_register, 1);
}
/* AGC */
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
{
char buf;
int ret;
@@ -643,7 +610,7 @@ static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
return 0;
}
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_get_agc(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -673,7 +640,7 @@ static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
return 0;
}
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
{
char buf[2];
int speed, ret;
@@ -691,23 +658,16 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
value = 0;
if (value > 0xffff)
value = 0xffff;
- switch(pdev->type) {
- case 675:
- case 680:
- case 690:
+
+ if (DEVICE_USE_CODEC2(pdev->type)) {
/* speed ranges from 0x0 to 0x290 (656) */
speed = (value / 100);
buf[1] = speed >> 8;
buf[0] = speed & 0xff;
- break;
- case 720:
- case 730:
- case 740:
- case 750:
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
/* speed seems to range from 0x0 to 0xff */
buf[1] = 0;
buf[0] = value >> 8;
- break;
}
ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
@@ -715,6 +675,25 @@ static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int v
return ret;
}
+/* This function is not exported to v4l1, so output values between 0 -> 256 */
+int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+{
+ unsigned char buf[2];
+ int ret;
+
+ ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2);
+ if (ret < 0)
+ return ret;
+ *value = buf[0] + (buf[1] << 8);
+ if (DEVICE_USE_CODEC2(pdev->type)) {
+ /* speed ranges from 0x0 to 0x290 (656) */
+ *value *= 256/656;
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
+ /* speed seems to range from 0x0 to 0xff */
+ }
+ return 0;
+}
+
/* POWER */
@@ -736,19 +715,19 @@ int pwc_camera_power(struct pwc_device *pdev, int power)
/* private calls */
-static inline int pwc_restore_user(struct pwc_device *pdev)
+int pwc_restore_user(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
}
-static inline int pwc_save_user(struct pwc_device *pdev)
+int pwc_save_user(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
}
-static inline int pwc_restore_factory(struct pwc_device *pdev)
+int pwc_restore_factory(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
@@ -766,7 +745,7 @@ static inline int pwc_restore_factory(struct pwc_device *pdev)
* 03: manual
* 04: auto
*/
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+int pwc_set_awb(struct pwc_device *pdev, int mode)
{
char buf;
int ret;
@@ -786,7 +765,7 @@ static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
return 0;
}
-static inline int pwc_get_awb(struct pwc_device *pdev)
+int pwc_get_awb(struct pwc_device *pdev)
{
unsigned char buf;
int ret;
@@ -798,7 +777,7 @@ static inline int pwc_get_awb(struct pwc_device *pdev)
return buf;
}
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+int pwc_set_red_gain(struct pwc_device *pdev, int value)
{
unsigned char buf;
@@ -811,7 +790,7 @@ static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
}
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+int pwc_get_red_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -824,7 +803,7 @@ static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
}
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+int pwc_set_blue_gain(struct pwc_device *pdev, int value)
{
unsigned char buf;
@@ -837,7 +816,7 @@ static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
}
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -854,7 +833,7 @@ static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
internal red/blue gains, which may be different from the manual
gains set or read above.
*/
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -866,7 +845,7 @@ static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
return 0;
}
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -879,7 +858,7 @@ static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
}
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
{
unsigned char buf;
@@ -888,7 +867,7 @@ static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
}
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -901,7 +880,7 @@ static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
}
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
{
unsigned char buf;
@@ -910,7 +889,7 @@ static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
}
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
@@ -965,7 +944,7 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
return 0;
}
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+int pwc_set_contour(struct pwc_device *pdev, int contour)
{
unsigned char buf;
int ret;
@@ -990,7 +969,7 @@ static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
return 0;
}
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+int pwc_get_contour(struct pwc_device *pdev, int *contour)
{
unsigned char buf;
int ret;
@@ -1012,7 +991,7 @@ static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
}
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+int pwc_set_backlight(struct pwc_device *pdev, int backlight)
{
unsigned char buf;
@@ -1023,7 +1002,7 @@ static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
}
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
{
int ret;
unsigned char buf;
@@ -1031,12 +1010,35 @@ static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
if (ret < 0)
return ret;
- *backlight = buf;
+ *backlight = !!buf;
return 0;
}
+int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
+{
+ unsigned char buf;
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+ if (colour)
+ buf = 0xff;
+ else
+ buf = 0x0;
+ return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+}
+
+int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
+{
+ int ret;
+ unsigned char buf;
+
+ ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+ if (ret < 0)
+ return ret;
+ *colour = !!buf;
+ return 0;
+}
+
+
+int pwc_set_flicker(struct pwc_device *pdev, int flicker)
{
unsigned char buf;
@@ -1047,7 +1049,7 @@ static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
}
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
{
int ret;
unsigned char buf;
@@ -1055,12 +1057,11 @@ static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
if (ret < 0)
return ret;
- *flicker = buf;
+ *flicker = !!buf;
return 0;
}
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
{
unsigned char buf;
@@ -1072,7 +1073,7 @@ static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
}
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
{
int ret;
unsigned char buf;
@@ -1084,7 +1085,7 @@ static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
return 0;
}
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
{
unsigned char buf;
@@ -1092,7 +1093,18 @@ static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
}
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+ int ret;
+ ret = _pwc_mpt_reset(pdev, flags);
+ if (ret >= 0) {
+ pdev->pan_angle = 0;
+ pdev->tilt_angle = 0;
+ }
+ return ret;
+}
+
+static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
{
unsigned char buf[4];
@@ -1110,7 +1122,35 @@ static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
}
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+ int ret;
+
+ /* check absolute ranges */
+ if (pan < pdev->angle_range.pan_min ||
+ pan > pdev->angle_range.pan_max ||
+ tilt < pdev->angle_range.tilt_min ||
+ tilt > pdev->angle_range.tilt_max)
+ return -ERANGE;
+
+ /* go to relative range, check again */
+ pan -= pdev->pan_angle;
+ tilt -= pdev->tilt_angle;
+ /* angles are specified in degrees * 100, thus the limit = 36000 */
+ if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
+ return -ERANGE;
+
+ ret = _pwc_mpt_set_angle(pdev, pan, tilt);
+ if (ret >= 0) {
+ pdev->pan_angle += pan;
+ pdev->tilt_angle += tilt;
+ }
+ if (ret == -EPIPE) /* stall -> out of range */
+ ret = -ERANGE;
+ return ret;
+}
+
+static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
{
int ret;
unsigned char buf[5];
@@ -1151,6 +1191,26 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
/* End of Add-Ons */
/* ************************************************* */
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+ ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+ and copy_to_user() calls. With these macros we circumvent this,
+ and let me maintain only one source file. The functionality is
+ exactly the same otherwise.
+ */
+
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+ ARG_type *ARG_name = arg;
+/* copy arg to local variable */
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
@@ -1180,206 +1240,243 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCSCQUAL:
{
- int *qual = arg;
+ ARG_DEF(int, qual)
- if (*qual < 0 || *qual > 3)
+ ARG_IN(qual)
+ if (ARGR(qual) < 0 || ARGR(qual) > 3)
ret = -EINVAL;
else
- ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+ ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
if (ret >= 0)
- pdev->vcompression = *qual;
+ pdev->vcompression = ARGR(qual);
break;
}
case VIDIOCPWCGCQUAL:
{
- int *qual = arg;
- *qual = pdev->vcompression;
+ ARG_DEF(int, qual)
+
+ ARGR(qual) = pdev->vcompression;
+ ARG_OUT(qual)
break;
}
case VIDIOCPWCPROBE:
{
- struct pwc_probe *probe = arg;
- strcpy(probe->name, pdev->vdev->name);
- probe->type = pdev->type;
+ ARG_DEF(struct pwc_probe, probe)
+
+ strcpy(ARGR(probe).name, pdev->vdev->name);
+ ARGR(probe).type = pdev->type;
+ ARG_OUT(probe)
break;
}
case VIDIOCPWCGSERIAL:
{
- struct pwc_serial *serial = arg;
- strcpy(serial->serial, pdev->serial);
+ ARG_DEF(struct pwc_serial, serial)
+
+ strcpy(ARGR(serial).serial, pdev->serial);
+ ARG_OUT(serial)
break;
}
case VIDIOCPWCSAGC:
{
- int *agc = arg;
- if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+ ARG_DEF(int, agc)
+
+ ARG_IN(agc)
+ if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
ret = -EINVAL;
break;
}
case VIDIOCPWCGAGC:
{
- int *agc = arg;
+ ARG_DEF(int, agc)
- if (pwc_get_agc(pdev, agc))
+ if (pwc_get_agc(pdev, ARGA(agc)))
ret = -EINVAL;
+ ARG_OUT(agc)
break;
}
case VIDIOCPWCSSHUTTER:
{
- int *shutter_speed = arg;
- ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+ ARG_DEF(int, shutter_speed)
+
+ ARG_IN(shutter_speed)
+ ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
break;
}
case VIDIOCPWCSAWB:
{
- struct pwc_whitebalance *wb = arg;
+ ARG_DEF(struct pwc_whitebalance, wb)
- ret = pwc_set_awb(pdev, wb->mode);
- if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
- pwc_set_red_gain(pdev, wb->manual_red);
- pwc_set_blue_gain(pdev, wb->manual_blue);
+ ARG_IN(wb)
+ ret = pwc_set_awb(pdev, ARGR(wb).mode);
+ if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+ pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+ pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
}
break;
}
case VIDIOCPWCGAWB:
{
- struct pwc_whitebalance *wb = arg;
+ ARG_DEF(struct pwc_whitebalance, wb)
- memset(wb, 0, sizeof(struct pwc_whitebalance));
- wb->mode = pwc_get_awb(pdev);
- if (wb->mode < 0)
+ memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+ ARGR(wb).mode = pwc_get_awb(pdev);
+ if (ARGR(wb).mode < 0)
ret = -EINVAL;
else {
- if (wb->mode == PWC_WB_MANUAL) {
- ret = pwc_get_red_gain(pdev, &wb->manual_red);
+ if (ARGR(wb).mode == PWC_WB_MANUAL) {
+ ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
if (ret < 0)
break;
- ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+ ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
if (ret < 0)
break;
}
- if (wb->mode == PWC_WB_AUTO) {
- ret = pwc_read_red_gain(pdev, &wb->read_red);
+ if (ARGR(wb).mode == PWC_WB_AUTO) {
+ ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
if (ret < 0)
break;
- ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+ ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
if (ret < 0)
break;
}
}
+ ARG_OUT(wb)
break;
}
case VIDIOCPWCSAWBSPEED:
{
- struct pwc_wb_speed *wbs = arg;
+ ARG_DEF(struct pwc_wb_speed, wbs)
- if (wbs->control_speed > 0) {
- ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+ if (ARGR(wbs).control_speed > 0) {
+ ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
}
- if (wbs->control_delay > 0) {
- ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+ if (ARGR(wbs).control_delay > 0) {
+ ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
}
break;
}
case VIDIOCPWCGAWBSPEED:
{
- struct pwc_wb_speed *wbs = arg;
+ ARG_DEF(struct pwc_wb_speed, wbs)
- ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+ ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
if (ret < 0)
break;
- ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+ ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
if (ret < 0)
break;
+ ARG_OUT(wbs)
break;
}
case VIDIOCPWCSLED:
{
- struct pwc_leds *leds = arg;
- ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
- break;
+ ARG_DEF(struct pwc_leds, leds)
+
+ ARG_IN(leds)
+ ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+ break;
}
case VIDIOCPWCGLED:
{
- struct pwc_leds *leds = arg;
- ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+ ARG_DEF(struct pwc_leds, leds)
+
+ ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+ ARG_OUT(leds)
break;
}
case VIDIOCPWCSCONTOUR:
{
- int *contour = arg;
- ret = pwc_set_contour(pdev, *contour);
+ ARG_DEF(int, contour)
+
+ ARG_IN(contour)
+ ret = pwc_set_contour(pdev, ARGR(contour));
break;
}
case VIDIOCPWCGCONTOUR:
{
- int *contour = arg;
- ret = pwc_get_contour(pdev, contour);
+ ARG_DEF(int, contour)
+
+ ret = pwc_get_contour(pdev, ARGA(contour));
+ ARG_OUT(contour)
break;
}
case VIDIOCPWCSBACKLIGHT:
{
- int *backlight = arg;
- ret = pwc_set_backlight(pdev, *backlight);
+ ARG_DEF(int, backlight)
+
+ ARG_IN(backlight)
+ ret = pwc_set_backlight(pdev, ARGR(backlight));
break;
}
case VIDIOCPWCGBACKLIGHT:
{
- int *backlight = arg;
- ret = pwc_get_backlight(pdev, backlight);
+ ARG_DEF(int, backlight)
+
+ ret = pwc_get_backlight(pdev, ARGA(backlight));
+ ARG_OUT(backlight)
break;
}
case VIDIOCPWCSFLICKER:
{
- int *flicker = arg;
- ret = pwc_set_flicker(pdev, *flicker);
+ ARG_DEF(int, flicker)
+
+ ARG_IN(flicker)
+ ret = pwc_set_flicker(pdev, ARGR(flicker));
break;
}
case VIDIOCPWCGFLICKER:
{
- int *flicker = arg;
- ret = pwc_get_flicker(pdev, flicker);
+ ARG_DEF(int, flicker)
+
+ ret = pwc_get_flicker(pdev, ARGA(flicker));
+ ARG_OUT(flicker)
break;
}
case VIDIOCPWCSDYNNOISE:
{
- int *dynnoise = arg;
- ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+ ARG_DEF(int, dynnoise)
+
+ ARG_IN(dynnoise)
+ ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
break;
}
case VIDIOCPWCGDYNNOISE:
{
- int *dynnoise = arg;
- ret = pwc_get_dynamic_noise(pdev, dynnoise);
+ ARG_DEF(int, dynnoise)
+
+ ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+ ARG_OUT(dynnoise);
break;
}
case VIDIOCPWCGREALSIZE:
{
- struct pwc_imagesize *size = arg;
- size->width = pdev->image.x;
- size->height = pdev->image.y;
+ ARG_DEF(struct pwc_imagesize, size)
+
+ ARGR(size).width = pdev->image.x;
+ ARGR(size).height = pdev->image.y;
+ ARG_OUT(size)
break;
}
@@ -1387,14 +1484,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- int *flags = arg;
+ ARG_DEF(int, flags)
- ret = pwc_mpt_reset(pdev, *flags);
- if (ret >= 0)
- {
- pdev->pan_angle = 0;
- pdev->tilt_angle = 0;
- }
+ ARG_IN(flags)
+ ret = pwc_mpt_reset(pdev, ARGR(flags));
}
else
{
@@ -1407,8 +1500,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_range *range = arg;
- *range = pdev->angle_range;
+ ARG_DEF(struct pwc_mpt_range, range)
+
+ ARGR(range) = pdev->angle_range;
+ ARG_OUT(range)
}
else
{
@@ -1423,48 +1518,23 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_angles *angles = arg;
+ ARG_DEF(struct pwc_mpt_angles, angles)
+
+ ARG_IN(angles)
/* The camera can only set relative angles, so
do some calculations when getting an absolute angle .
*/
- if (angles->absolute)
+ if (ARGR(angles).absolute)
{
- new_pan = angles->pan;
- new_tilt = angles->tilt;
+ new_pan = ARGR(angles).pan;
+ new_tilt = ARGR(angles).tilt;
}
else
{
- new_pan = pdev->pan_angle + angles->pan;
- new_tilt = pdev->tilt_angle + angles->tilt;
- }
- /* check absolute ranges */
- if (new_pan < pdev->angle_range.pan_min ||
- new_pan > pdev->angle_range.pan_max ||
- new_tilt < pdev->angle_range.tilt_min ||
- new_tilt > pdev->angle_range.tilt_max)
- {
- ret = -ERANGE;
- }
- else
- {
- /* go to relative range, check again */
- new_pan -= pdev->pan_angle;
- new_tilt -= pdev->tilt_angle;
- /* angles are specified in degrees * 100, thus the limit = 36000 */
- if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
- ret = -ERANGE;
- }
- if (ret == 0) /* no errors so far */
- {
- ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
- if (ret >= 0)
- {
- pdev->pan_angle += new_pan;
- pdev->tilt_angle += new_tilt;
- }
- if (ret == -EPIPE) /* stall -> out of range */
- ret = -ERANGE;
+ new_pan = pdev->pan_angle + ARGR(angles).pan;
+ new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
}
+ ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
}
else
{
@@ -1478,11 +1548,12 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_angles *angles = arg;
+ ARG_DEF(struct pwc_mpt_angles, angles)
- angles->absolute = 1;
- angles->pan = pdev->pan_angle;
- angles->tilt = pdev->tilt_angle;
+ ARGR(angles).absolute = 1;
+ ARGR(angles).pan = pdev->pan_angle;
+ ARGR(angles).tilt = pdev->tilt_angle;
+ ARG_OUT(angles)
}
else
{
@@ -1495,8 +1566,10 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_status *status = arg;
- ret = pwc_mpt_get_status(pdev, status);
+ ARG_DEF(struct pwc_mpt_status, status)
+
+ ret = pwc_mpt_get_status(pdev, ARGA(status));
+ ARG_OUT(status)
}
else
{
@@ -1507,22 +1580,24 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
case VIDIOCPWCGVIDCMD:
{
- struct pwc_video_command *cmd = arg;
-
- cmd->type = pdev->type;
- cmd->release = pdev->release;
- cmd->command_len = pdev->cmd_len;
- memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
- cmd->bandlength = pdev->vbandlength;
- cmd->frame_size = pdev->frame_size;
+ ARG_DEF(struct pwc_video_command, cmd);
+
+ ARGR(cmd).type = pdev->type;
+ ARGR(cmd).release = pdev->release;
+ ARGR(cmd).command_len = pdev->cmd_len;
+ memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+ ARGR(cmd).bandlength = pdev->vbandlength;
+ ARGR(cmd).frame_size = pdev->frame_size;
+ ARG_OUT(cmd)
break;
}
/*
case VIDIOCPWCGVIDTABLE:
{
- struct pwc_table_init_buffer *table = arg;
- table->len = pdev->cmd_len;
- memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ ARG_DEF(struct pwc_table_init_buffer, table);
+ ARGR(table).len = pdev->cmd_len;
+ memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ ARG_OUT(table)
break;
}
*/
@@ -1538,4 +1613,4 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
}
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c
new file mode 100644
index 00000000000..c29593f589e
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec1.c
@@ -0,0 +1,50 @@
+/* Linux driver for Philips webcam
+ Decompression for chipset version 1
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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 "pwc-dec1.h"
+
+
+void pwc_dec1_init(int type, int release, void *buffer, void *table)
+{
+
+}
+
+void pwc_dec1_exit(void)
+{
+
+
+
+}
+
+int pwc_dec1_alloc(struct pwc_device *pwc)
+{
+ pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+ if (pwc->decompress_data == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h
new file mode 100644
index 00000000000..8b62ddcc5c7
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec1.h
@@ -0,0 +1,43 @@
+/* Linux driver for Philips webcam
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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
+*/
+
+
+
+#ifndef PWC_DEC1_H
+#define PWC_DEC1_H
+
+#include "pwc.h"
+
+struct pwc_dec1_private
+{
+ int version;
+
+};
+
+int pwc_dec1_alloc(struct pwc_device *pwc);
+void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
+void pwc_dec1_exit(void);
+
+#endif
+
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c
new file mode 100644
index 00000000000..9e2d91f26bf
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec23.c
@@ -0,0 +1,941 @@
+/* Linux driver for Philips webcam
+ Decompression for chipset version 2 et 3
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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 "pwc-timon.h"
+#include "pwc-kiara.h"
+#include "pwc-dec23.h"
+#include <media/pwc-ioctl.h>
+
+#include <linux/string.h>
+
+/*
+ * USE_LOOKUP_TABLE_TO_CLAMP
+ * 0: use a C version of this tests: { a<0?0:(a>255?255:a) }
+ * 1: use a faster lookup table for cpu with a big cache (intel)
+ */
+#define USE_LOOKUP_TABLE_TO_CLAMP 1
+/*
+ * UNROLL_LOOP_FOR_COPYING_BLOCK
+ * 0: use a loop for a smaller code (but little slower)
+ * 1: when unrolling the loop, gcc produces some faster code (perhaps only
+ * valid for intel processor class). Activating this option, automaticaly
+ * activate USE_LOOKUP_TABLE_TO_CLAMP
+ */
+#define UNROLL_LOOP_FOR_COPY 1
+#if UNROLL_LOOP_FOR_COPY
+# undef USE_LOOKUP_TABLE_TO_CLAMP
+# define USE_LOOKUP_TABLE_TO_CLAMP 1
+#endif
+
+/*
+ * ENABLE_BAYER_DECODER
+ * 0: bayer decoder is not build (save some space)
+ * 1: bayer decoder is build and can be used
+ */
+#define ENABLE_BAYER_DECODER 0
+
+static void build_subblock_pattern(struct pwc_dec23_private *pdec)
+{
+ static const unsigned int initial_values[12] = {
+ -0x526500, -0x221200, 0x221200, 0x526500,
+ -0x3de200, 0x3de200,
+ -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
+ -0x12c200, 0x12c200
+
+ };
+ static const unsigned int values_derivated[12] = {
+ 0xa4ca, 0x4424, -0x4424, -0xa4ca,
+ 0x7bc4, -0x7bc4,
+ 0xdb69, 0x5aba, -0x5aba, -0xdb69,
+ 0x2584, -0x2584
+ };
+ unsigned int temp_values[12];
+ int i, j;
+
+ memcpy(temp_values, initial_values, sizeof(initial_values));
+ for (i = 0; i < 256; i++) {
+ for (j = 0; j < 12; j++) {
+ pdec->table_subblock[i][j] = temp_values[j];
+ temp_values[j] += values_derivated[j];
+ }
+ }
+}
+
+static void build_bit_powermask_table(struct pwc_dec23_private *pdec)
+{
+ unsigned char *p;
+ unsigned int bit, byte, mask, val;
+ unsigned int bitpower = 1;
+
+ for (bit = 0; bit < 8; bit++) {
+ mask = bitpower - 1;
+ p = pdec->table_bitpowermask[bit];
+ for (byte = 0; byte < 256; byte++) {
+ val = (byte & mask);
+ if (byte & bitpower)
+ val = -val;
+ *p++ = val;
+ }
+ bitpower<<=1;
+ }
+}
+
+
+static void build_table_color(const unsigned int romtable[16][8],
+ unsigned char p0004[16][1024],
+ unsigned char p8004[16][256])
+{
+ int compression_mode, j, k, bit, pw;
+ unsigned char *p0, *p8;
+ const unsigned int *r;
+
+ /* We have 16 compressions tables */
+ for (compression_mode = 0; compression_mode < 16; compression_mode++) {
+ p0 = p0004[compression_mode];
+ p8 = p8004[compression_mode];
+ r = romtable[compression_mode];
+
+ for (j = 0; j < 8; j++, r++, p0 += 128) {
+
+ for (k = 0; k < 16; k++) {
+ if (k == 0)
+ bit = 1;
+ else if (k >= 1 && k < 3)
+ bit = (r[0] >> 15) & 7;
+ else if (k >= 3 && k < 6)
+ bit = (r[0] >> 12) & 7;
+ else if (k >= 6 && k < 10)
+ bit = (r[0] >> 9) & 7;
+ else if (k >= 10 && k < 13)
+ bit = (r[0] >> 6) & 7;
+ else if (k >= 13 && k < 15)
+ bit = (r[0] >> 3) & 7;
+ else
+ bit = (r[0]) & 7;
+ if (k == 0)
+ *p8++ = 8;
+ else
+ *p8++ = j - bit;
+ *p8++ = bit;
+
+ pw = 1 << bit;
+ p0[k + 0x00] = (1 * pw) + 0x80;
+ p0[k + 0x10] = (2 * pw) + 0x80;
+ p0[k + 0x20] = (3 * pw) + 0x80;
+ p0[k + 0x30] = (4 * pw) + 0x80;
+ p0[k + 0x40] = (-1 * pw) + 0x80;
+ p0[k + 0x50] = (-2 * pw) + 0x80;
+ p0[k + 0x60] = (-3 * pw) + 0x80;
+ p0[k + 0x70] = (-4 * pw) + 0x80;
+ } /* end of for (k=0; k<16; k++, p8++) */
+ } /* end of for (j=0; j<8; j++ , table++) */
+ } /* end of foreach compression_mode */
+}
+
+/*
+ *
+ */
+static void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
+{
+#define SCALEBITS 15
+#define ONE_HALF (1UL << (SCALEBITS - 1))
+ int i;
+ unsigned int offset1 = ONE_HALF;
+ unsigned int offset2 = 0x0000;
+
+ for (i=0; i<256; i++) {
+ pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
+ pdec->table_d800[i] = offset2;
+
+ offset1 += 0x7bc4;
+ offset2 += 0x7bc4;
+ }
+}
+
+/*
+ * To decode the stream:
+ * if look_bits(2) == 0: # op == 2 in the lookup table
+ * skip_bits(2)
+ * end of the stream
+ * elif look_bits(3) == 7: # op == 1 in the lookup table
+ * skip_bits(3)
+ * yyyy = get_bits(4)
+ * xxxx = get_bits(8)
+ * else: # op == 0 in the lookup table
+ * skip_bits(x)
+ *
+ * For speedup processing, we build a lookup table and we takes the first 6 bits.
+ *
+ * struct {
+ * unsigned char op; // operation to execute
+ * unsigned char bits; // bits use to perform operation
+ * unsigned char offset1; // offset to add to access in the table_0004 % 16
+ * unsigned char offset2; // offset to add to access in the table_0004
+ * }
+ *
+ * How to build this table ?
+ * op == 2 when (i%4)==0
+ * op == 1 when (i%8)==7
+ * op == 0 otherwise
+ *
+ */
+static const unsigned char hash_table_ops[64*4] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x01, 0x30,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x20,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x02, 0x10,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x60,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x40,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x40,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x01, 0x70,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x20,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x02, 0x50,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x60,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x40,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x40,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+/*
+ *
+ */
+static const unsigned int MulIdx[16][16] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+ {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
+ {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
+ {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
+ {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
+ {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
+ {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
+ {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
+ {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
+ {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
+ {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
+ {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
+ {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
+ {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
+ {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
+ {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
+};
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+#define MAX_OUTER_CROP_VALUE (512)
+static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
+#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
+#else
+#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
+#endif
+
+
+/* If the type or the command change, we rebuild the lookup table */
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+{
+ int flags, version, shift, i;
+ struct pwc_dec23_private *pdec;
+
+ if (pwc->decompress_data == NULL) {
+ pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+ if (pdec == NULL)
+ return -ENOMEM;
+ pwc->decompress_data = pdec;
+ }
+ pdec = pwc->decompress_data;
+
+ if (DEVICE_USE_CODEC3(type)) {
+ flags = cmd[2] & 0x18;
+ if (flags == 8)
+ pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */
+ else if (flags == 0x10)
+ pdec->nbits = 8;
+ else
+ pdec->nbits = 6;
+
+ version = cmd[2] >> 5;
+ build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+ build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+
+ } else {
+
+ flags = cmd[2] & 6;
+ if (flags == 2)
+ pdec->nbits = 7;
+ else if (flags == 4)
+ pdec->nbits = 8;
+ else
+ pdec->nbits = 6;
+
+ version = cmd[2] >> 3;
+ build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+ build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+ }
+
+ /* Informations can be coded on a variable number of bits but never less than 8 */
+ shift = 8 - pdec->nbits;
+ pdec->scalebits = SCALEBITS - shift;
+ pdec->nbitsmask = 0xFF >> shift;
+
+ fill_table_dc00_d800(pdec);
+ build_subblock_pattern(pdec);
+ build_bit_powermask_table(pdec);
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+ /* Build the static table to clamp value [0-255] */
+ for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
+ pwc_crop_table[i] = 0;
+ for (i=0; i<256; i++)
+ pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
+ for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
+ pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
+#endif
+
+ return 0;
+}
+
+/*
+ * Copy the 4x4 image block to Y plane buffer
+ */
+static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ const int *c = src;
+ unsigned char *d = dst;
+
+ *d++ = cm[c[0] >> scalebits];
+ *d++ = cm[c[1] >> scalebits];
+ *d++ = cm[c[2] >> scalebits];
+ *d++ = cm[c[3] >> scalebits];
+
+ d = dst + bytes_per_line;
+ *d++ = cm[c[4] >> scalebits];
+ *d++ = cm[c[5] >> scalebits];
+ *d++ = cm[c[6] >> scalebits];
+ *d++ = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line*2;
+ *d++ = cm[c[8] >> scalebits];
+ *d++ = cm[c[9] >> scalebits];
+ *d++ = cm[c[10] >> scalebits];
+ *d++ = cm[c[11] >> scalebits];
+
+ d = dst + bytes_per_line*3;
+ *d++ = cm[c[12] >> scalebits];
+ *d++ = cm[c[13] >> scalebits];
+ *d++ = cm[c[14] >> scalebits];
+ *d++ = cm[c[15] >> scalebits];
+#else
+ int i;
+ const int *c = src;
+ unsigned char *d = dst;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*2;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*3;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+#endif
+}
+
+/*
+ * Copy the 4x4 image block to a CrCb plane buffer
+ *
+ */
+static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ const int *c = src;
+ unsigned char *d = dst;
+
+ *d++ = cm[c[0] >> scalebits];
+ *d++ = cm[c[4] >> scalebits];
+ *d++ = cm[c[1] >> scalebits];
+ *d++ = cm[c[5] >> scalebits];
+ *d++ = cm[c[2] >> scalebits];
+ *d++ = cm[c[6] >> scalebits];
+ *d++ = cm[c[3] >> scalebits];
+ *d++ = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line;
+ *d++ = cm[c[12] >> scalebits];
+ *d++ = cm[c[8] >> scalebits];
+ *d++ = cm[c[13] >> scalebits];
+ *d++ = cm[c[9] >> scalebits];
+ *d++ = cm[c[14] >> scalebits];
+ *d++ = cm[c[10] >> scalebits];
+ *d++ = cm[c[15] >> scalebits];
+ *d++ = cm[c[11] >> scalebits];
+#else
+ int i;
+ const int *c1 = src;
+ const int *c2 = src + 4;
+ unsigned char *d = dst;
+
+ for (i = 0; i < 4; i++, c1++, c2++) {
+ *d++ = CLAMP((*c1) >> scalebits);
+ *d++ = CLAMP((*c2) >> scalebits);
+ }
+ c1 = src + 12;
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c1++, c2++) {
+ *d++ = CLAMP((*c1) >> scalebits);
+ *d++ = CLAMP((*c2) >> scalebits);
+ }
+#endif
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 8x2 pixels
+ * . G . G . G . G . G . G . G
+ * . . . . . . . . . . . . . .
+ * . G . G . G . G . G . G . G
+ * . . . . . . . . . . . . . .
+ * or
+ * . . . . . . . . . . . . . .
+ * G . G . G . G . G . G . G .
+ * . . . . . . . . . . . . . .
+ * G . G . G . G . G . G . G .
+*/
+static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ unsigned char *d = dst;
+ const int *c = src;
+
+ d[0] = cm[c[0] >> scalebits];
+ d[2] = cm[c[1] >> scalebits];
+ d[4] = cm[c[2] >> scalebits];
+ d[6] = cm[c[3] >> scalebits];
+ d[8] = cm[c[4] >> scalebits];
+ d[10] = cm[c[5] >> scalebits];
+ d[12] = cm[c[6] >> scalebits];
+ d[14] = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line;
+ d[0] = cm[c[8] >> scalebits];
+ d[2] = cm[c[9] >> scalebits];
+ d[4] = cm[c[10] >> scalebits];
+ d[6] = cm[c[11] >> scalebits];
+ d[8] = cm[c[12] >> scalebits];
+ d[10] = cm[c[13] >> scalebits];
+ d[12] = cm[c[14] >> scalebits];
+ d[14] = cm[c[15] >> scalebits];
+#else
+ int i;
+ unsigned char *d;
+ const int *c = src;
+
+ d = dst;
+ for (i = 0; i < 8; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 8; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 4x4 pixels
+ * R . R . R . R
+ * . B . B . B .
+ * R . R . R . R
+ * . B . B . B .
+ */
+static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ unsigned char *d = dst;
+ const int *c = src;
+
+ d[0] = cm[c[0] >> scalebits];
+ d[2] = cm[c[1] >> scalebits];
+ d[4] = cm[c[2] >> scalebits];
+ d[6] = cm[c[3] >> scalebits];
+
+ d = dst + bytes_per_line;
+ d[1] = cm[c[4] >> scalebits];
+ d[3] = cm[c[5] >> scalebits];
+ d[5] = cm[c[6] >> scalebits];
+ d[7] = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line*2;
+ d[0] = cm[c[8] >> scalebits];
+ d[2] = cm[c[9] >> scalebits];
+ d[4] = cm[c[10] >> scalebits];
+ d[6] = cm[c[11] >> scalebits];
+
+ d = dst + bytes_per_line*3;
+ d[1] = cm[c[12] >> scalebits];
+ d[3] = cm[c[13] >> scalebits];
+ d[5] = cm[c[14] >> scalebits];
+ d[7] = cm[c[15] >> scalebits];
+#else
+ int i;
+ unsigned char *d;
+ const int *c = src;
+
+ d = dst;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2+1] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*2;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*3;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2+1] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+/*
+ * To manage the stream, we keep bits in a 32 bits register.
+ * fill_nbits(n): fill the reservoir with at least n bits
+ * skip_bits(n): discard n bits from the reservoir
+ * get_bits(n): fill the reservoir, returns the first n bits and discard the
+ * bits from the reservoir.
+ * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
+ * contains at least n bits. bits returned is discarded.
+ */
+#define fill_nbits(pdec, nbits_wanted) do { \
+ while (pdec->nbits_in_reservoir<(nbits_wanted)) \
+ { \
+ pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
+ pdec->nbits_in_reservoir += 8; \
+ } \
+} while(0);
+
+#define skip_nbits(pdec, nbits_to_skip) do { \
+ pdec->reservoir >>= (nbits_to_skip); \
+ pdec->nbits_in_reservoir -= (nbits_to_skip); \
+} while(0);
+
+#define get_nbits(pdec, nbits_wanted, result) do { \
+ fill_nbits(pdec, nbits_wanted); \
+ result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+ skip_nbits(pdec, nbits_wanted); \
+} while(0);
+
+#define __get_nbits(pdec, nbits_wanted, result) do { \
+ result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+ skip_nbits(pdec, nbits_wanted); \
+} while(0);
+
+#define look_nbits(pdec, nbits_wanted) \
+ ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
+
+/*
+ * Decode a 4x4 pixel block
+ */
+static void decode_block(struct pwc_dec23_private *pdec,
+ const unsigned char *ptable0004,
+ const unsigned char *ptable8004)
+{
+ unsigned int primary_color;
+ unsigned int channel_v, offset1, op;
+ int i;
+
+ fill_nbits(pdec, 16);
+ __get_nbits(pdec, pdec->nbits, primary_color);
+
+ if (look_nbits(pdec,2) == 0) {
+ skip_nbits(pdec, 2);
+ /* Very simple, the color is the same for all pixels of the square */
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] = pdec->table_dc00[primary_color];
+
+ return;
+ }
+
+ /* This block is encoded with small pattern */
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] = pdec->table_d800[primary_color];
+
+ __get_nbits(pdec, 3, channel_v);
+ channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
+
+ ptable0004 += (channel_v * 128);
+ ptable8004 += (channel_v * 32);
+
+ offset1 = 0;
+ do
+ {
+ unsigned int htable_idx, rows = 0;
+ const unsigned int *block;
+
+ /* [ zzzz y x x ]
+ * xx == 00 :=> end of the block def, remove the two bits from the stream
+ * yxx == 111
+ * yxx == any other value
+ *
+ */
+ fill_nbits(pdec, 16);
+ htable_idx = look_nbits(pdec, 6);
+ op = hash_table_ops[htable_idx * 4];
+
+ if (op == 2) {
+ skip_nbits(pdec, 2);
+
+ } else if (op == 1) {
+ /* 15bits [ xxxx xxxx yyyy 111 ]
+ * yyy => offset in the table8004
+ * xxx => offset in the tabled004 (tree)
+ */
+ unsigned int mask, shift;
+ unsigned int nbits, col1;
+ unsigned int yyyy;
+
+ skip_nbits(pdec, 3);
+ /* offset1 += yyyy */
+ __get_nbits(pdec, 4, yyyy);
+ offset1 += 1 + yyyy;
+ offset1 &= 0x0F;
+ nbits = ptable8004[offset1 * 2];
+
+ /* col1 = xxxx xxxx */
+ __get_nbits(pdec, nbits+1, col1);
+
+ /* Bit mask table */
+ mask = pdec->table_bitpowermask[nbits][col1];
+ shift = ptable8004[offset1 * 2 + 1];
+ rows = ((mask << shift) + 0x80) & 0xFF;
+
+ block = pdec->table_subblock[rows];
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+ } else {
+ /* op == 0
+ * offset1 is coded on 3 bits
+ */
+ unsigned int shift;
+
+ offset1 += hash_table_ops [htable_idx * 4 + 2];
+ offset1 &= 0x0F;
+
+ rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
+ block = pdec->table_subblock[rows];
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+ shift = hash_table_ops[htable_idx * 4 + 1];
+ skip_nbits(pdec, shift);
+ }
+
+ } while (op != 2);
+
+}
+
+static void DecompressBand23(struct pwc_dec23_private *pdec,
+ const unsigned char *rawyuv,
+ unsigned char *planar_y,
+ unsigned char *planar_u,
+ unsigned char *planar_v,
+ unsigned int compressed_image_width,
+ unsigned int real_image_width)
+{
+ int compression_index, nblocks;
+ const unsigned char *ptable0004;
+ const unsigned char *ptable8004;
+
+ pdec->reservoir = 0;
+ pdec->nbits_in_reservoir = 0;
+ pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
+
+ get_nbits(pdec, 4, compression_index);
+
+ /* pass 1: uncompress Y component */
+ nblocks = compressed_image_width / 4;
+
+ ptable0004 = pdec->table_0004_pass1[compression_index];
+ ptable8004 = pdec->table_8004_pass1[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
+ planar_y += 4;
+ nblocks--;
+ }
+
+ /* pass 2: uncompress UV component */
+ nblocks = compressed_image_width / 8;
+
+ ptable0004 = pdec->table_0004_pass2[compression_index];
+ ptable8004 = pdec->table_8004_pass2[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
+
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
+
+ planar_v += 8;
+ planar_u += 8;
+ nblocks -= 2;
+ }
+
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Size need to be a multiple of 8 in width
+ *
+ * Return a block of four line encoded like this:
+ *
+ * G R G R G R G R G R G R G R G R
+ * B G B G B G B G B G B G B G B G
+ * G R G R G R G R G R G R G R G R
+ * B G B G B G B G B G B G B G B G
+ *
+ */
+static void DecompressBandBayer(struct pwc_dec23_private *pdec,
+ const unsigned char *rawyuv,
+ unsigned char *rgbbayer,
+ unsigned int compressed_image_width,
+ unsigned int real_image_width)
+{
+ int compression_index, nblocks;
+ const unsigned char *ptable0004;
+ const unsigned char *ptable8004;
+ unsigned char *dest;
+
+ pdec->reservoir = 0;
+ pdec->nbits_in_reservoir = 0;
+ pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
+
+ get_nbits(pdec, 4, compression_index);
+
+ /* pass 1: uncompress RB component */
+ nblocks = compressed_image_width / 4;
+
+ ptable0004 = pdec->table_0004_pass1[compression_index];
+ ptable8004 = pdec->table_8004_pass1[compression_index];
+ dest = rgbbayer;
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
+ dest += 8;
+ nblocks--;
+ }
+
+ /* pass 2: uncompress G component */
+ nblocks = compressed_image_width / 8;
+
+ ptable0004 = pdec->table_0004_pass2[compression_index];
+ ptable8004 = pdec->table_8004_pass2[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
+
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
+
+ rgbbayer += 16;
+ nblocks -= 2;
+ }
+}
+#endif
+
+
+/**
+ *
+ * Uncompress a pwc23 buffer.
+ *
+ * pwc.view: size of the image wanted
+ * pwc.image: size of the image returned by the camera
+ * pwc.offset: (x,y) to displayer image in the view
+ *
+ * src: raw data
+ * dst: image output
+ * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
+ */
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+ const void *src,
+ void *dst,
+ int flags)
+{
+ int bandlines_left, stride, bytes_per_block;
+
+ bandlines_left = pwc->image.y / 4;
+ bytes_per_block = pwc->view.x * 4;
+
+ if (flags & PWCX_FLAG_BAYER) {
+#if ENABLE_BAYER_DECODER
+ /* RGB Bayer format */
+ unsigned char *rgbout;
+
+ stride = pwc->view.x * pwc->offset.y;
+ rgbout = dst + stride + pwc->offset.x;
+
+
+ while (bandlines_left--) {
+
+ DecompressBandBayer(pwc->decompress_data,
+ src,
+ rgbout,
+ pwc->image.x, pwc->view.x);
+
+ src += pwc->vbandlength;
+ rgbout += bytes_per_block;
+
+ }
+#else
+ memset(dst, 0, pwc->view.x * pwc->view.y);
+#endif
+
+ } else {
+ /* YUV420P image format */
+ unsigned char *pout_planar_y;
+ unsigned char *pout_planar_u;
+ unsigned char *pout_planar_v;
+ unsigned int plane_size;
+
+ plane_size = pwc->view.x * pwc->view.y;
+
+ /* offset in Y plane */
+ stride = pwc->view.x * pwc->offset.y;
+ pout_planar_y = dst + stride + pwc->offset.x;
+
+ /* offsets in U/V planes */
+ stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
+ pout_planar_u = dst + plane_size + stride;
+ pout_planar_v = dst + plane_size + plane_size / 4 + stride;
+
+ while (bandlines_left--) {
+
+ DecompressBand23(pwc->decompress_data,
+ src,
+ pout_planar_y, pout_planar_u, pout_planar_v,
+ pwc->image.x, pwc->view.x);
+ src += pwc->vbandlength;
+ pout_planar_y += bytes_per_block;
+ pout_planar_u += pwc->view.x;
+ pout_planar_v += pwc->view.x;
+
+ }
+
+ }
+
+}
+
+void pwc_dec23_exit(void)
+{
+ /* Do nothing */
+
+}
+
+/**
+ * Allocate a private structure used by lookup table.
+ * You must call kfree() to free the memory allocated.
+ */
+int pwc_dec23_alloc(struct pwc_device *pwc)
+{
+ pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+ if (pwc->decompress_data == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h
new file mode 100644
index 00000000000..1c55298ad15
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-dec23.h
@@ -0,0 +1,67 @@
+/* Linux driver for Philips webcam
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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
+*/
+
+#ifndef PWC_DEC23_H
+#define PWC_DEC23_H
+
+#include "pwc.h"
+
+struct pwc_dec23_private
+{
+ unsigned int scalebits;
+ unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
+
+ unsigned int reservoir;
+ unsigned int nbits_in_reservoir;
+ const unsigned char *stream;
+ int temp_colors[16];
+
+ unsigned char table_0004_pass1[16][1024];
+ unsigned char table_0004_pass2[16][1024];
+ unsigned char table_8004_pass1[16][256];
+ unsigned char table_8004_pass2[16][256];
+ unsigned int table_subblock[256][12];
+
+ unsigned char table_bitpowermask[8][256];
+ unsigned int table_d800[256];
+ unsigned int table_dc00[256];
+
+};
+
+
+int pwc_dec23_alloc(struct pwc_device *pwc);
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
+void pwc_dec23_exit(void);
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+ const void *src,
+ void *dst,
+ int flags);
+
+
+
+#endif
+
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index 41418294a32..53c4b5790d5 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -1,7 +1,7 @@
/* Linux driver for Philips webcam
USB and Video4Linux interface part.
(C) 1999-2004 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -62,18 +62,21 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/version.h>
#include <asm/io.h>
+#include <linux/moduleparam.h>
#include "pwc.h"
-#include "pwc-ioctl.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
+#include "pwc-dec23.h"
+#include "pwc-dec1.h"
#include "pwc-uncompress.h"
/* Function prototypes and driver templates */
/* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
+static const struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
{ USB_DEVICE(0x0471, 0x0303) },
{ USB_DEVICE(0x0471, 0x0304) },
@@ -81,9 +84,10 @@ static struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0308) },
{ USB_DEVICE(0x0471, 0x030C) },
{ USB_DEVICE(0x0471, 0x0310) },
- { USB_DEVICE(0x0471, 0x0311) },
+ { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
{ USB_DEVICE(0x0471, 0x0312) },
{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+ { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
@@ -94,8 +98,9 @@ static struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
- { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
- { USB_DEVICE(0x055D, 0x9001) },
+ { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
+ { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
+ { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
@@ -122,11 +127,13 @@ static struct usb_driver pwc_driver = {
static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
-static int default_mbufs = 2; /* Default number of mmap() buffers */
- int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+ int pwc_mbufs = 2; /* Default number of mmap() buffers */
+#if CONFIG_PWC_DEBUG
+ int pwc_trace = PWC_DEBUG_LEVEL;
+#endif
static int power_save = 0;
static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
static struct {
int type;
char serial_number[30];
@@ -138,7 +145,7 @@ static struct {
static int pwc_video_open(struct inode *inode, struct file *file);
static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static int pwc_video_ioctl(struct inode *inode, struct file *file,
@@ -203,52 +210,44 @@ static struct video_device pwc_template = {
/* Here we want the physical address of the memory.
* This is used when initializing the contents of the area.
*/
-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); /* restore the offset */
- ret = __pa(kva);
- return ret;
-}
-static void * rvmalloc(unsigned long size)
+
+static void *pwc_rvmalloc(unsigned long size)
{
void * mem;
unsigned long adr;
- size=PAGE_ALIGN(size);
mem=vmalloc_32(size);
- if (mem)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- }
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ 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, unsigned long size)
+static void pwc_rvfree(void * mem, unsigned long size)
{
unsigned long adr;
- if (mem)
- {
- adr=(unsigned long) mem;
- while ((long) size > 0)
- {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- vfree(mem);
- }
+ if (!mem)
+ return;
+
+ adr=(unsigned long) mem;
+ while ((long) size > 0)
+ {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
}
@@ -256,100 +255,83 @@ static void rvfree(void * mem, unsigned long size)
static int pwc_allocate_buffers(struct pwc_device *pdev)
{
- int i;
+ int i, err;
void *kbuf;
- Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+ PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
if (pdev == NULL)
return -ENXIO;
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("allocate_buffers(): magic failed.\n");
- return -ENXIO;
- }
-#endif
- /* Allocate Isochronous pipe buffers */
+ /* Allocate Isochronuous pipe buffers */
for (i = 0; i < MAX_ISO_BUFS; i++) {
if (pdev->sbuf[i].data == NULL) {
- kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+ kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
if (kbuf == NULL) {
- Err("Failed to allocate iso buffer %d.\n", i);
+ PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
pdev->sbuf[i].data = kbuf;
- memset(kbuf, 0, ISO_BUFFER_SIZE);
}
}
/* Allocate frame buffer structure */
if (pdev->fbuf == NULL) {
- kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+ kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
if (kbuf == NULL) {
- Err("Failed to allocate frame buffer structure.\n");
+ PWC_ERROR("Failed to allocate frame buffer structure.\n");
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
pdev->fbuf = kbuf;
- memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
}
+
/* create frame buffers, and make circular ring */
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data == NULL) {
kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
if (kbuf == NULL) {
- Err("Failed to allocate frame buffer %d.\n", i);
+ PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+ PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
pdev->fbuf[i].data = kbuf;
- memset(kbuf, 128, PWC_FRAME_SIZE);
+ memset(kbuf, 0, PWC_FRAME_SIZE);
}
}
/* Allocate decompressor table space */
- kbuf = NULL;
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-#if 0
- Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
- kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */
- break;
- case 645:
- case 646:
- /* TODO & FIXME */
- kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
- break;
-#endif
- ;
- }
- pdev->decompress_data = kbuf;
+ if (DEVICE_USE_CODEC1(pdev->type))
+ err = pwc_dec1_alloc(pdev);
+ else
+ err = pwc_dec23_alloc(pdev);
+
+ if (err) {
+ PWC_ERROR("Failed to allocate decompress table.\n");
+ return err;
+ }
/* Allocate image buffer; double buffer for mmap() */
- kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+ kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
if (kbuf == NULL) {
- Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+ PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
+ pwc_mbufs * pdev->len_per_image);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
pdev->image_data = kbuf;
- for (i = 0; i < default_mbufs; i++)
- pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
- for (; i < MAX_IMAGES; i++)
- pdev->image_ptr[i] = NULL;
+ for (i = 0; i < pwc_mbufs; i++) {
+ pdev->images[i].offset = i * pdev->len_per_image;
+ pdev->images[i].vma_use_count = 0;
+ }
+ for (; i < MAX_IMAGES; i++) {
+ pdev->images[i].offset = 0;
+ }
kbuf = NULL;
- Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+ PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
return 0;
}
@@ -357,21 +339,14 @@ static void pwc_free_buffers(struct pwc_device *pdev)
{
int i;
- Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+ PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
if (pdev == NULL)
return;
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("free_buffers(): magic failed.\n");
- return;
- }
-#endif
-
/* Release Iso-pipe buffers */
for (i = 0; i < MAX_ISO_BUFS; i++)
if (pdev->sbuf[i].data != NULL) {
- Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+ PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
kfree(pdev->sbuf[i].data);
pdev->sbuf[i].data = NULL;
}
@@ -380,7 +355,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
if (pdev->fbuf != NULL) {
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data != NULL) {
- Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+ PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
vfree(pdev->fbuf[i].data);
pdev->fbuf[i].data = NULL;
}
@@ -391,20 +366,19 @@ static void pwc_free_buffers(struct pwc_device *pdev)
/* Intermediate decompression buffer & tables */
if (pdev->decompress_data != NULL) {
- Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+ PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
kfree(pdev->decompress_data);
pdev->decompress_data = NULL;
}
- pdev->decompressor = NULL;
/* Release image buffers */
if (pdev->image_data != NULL) {
- Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
- rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+ PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
+ pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
}
pdev->image_data = NULL;
- Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+ PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
}
/* The frame & image buffer mess.
@@ -464,7 +438,7 @@ static void pwc_free_buffers(struct pwc_device *pdev)
/**
\brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
*/
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+static int pwc_next_fill_frame(struct pwc_device *pdev)
{
int ret;
unsigned long flags;
@@ -489,23 +463,17 @@ static inline int pwc_next_fill_frame(struct pwc_device *pdev)
}
else {
/* Hmm. Take it from the full list */
-#if PWC_DEBUG
/* sanity check */
if (pdev->full_frames == NULL) {
- Err("Neither empty or full frames available!\n");
+ PWC_ERROR("Neither empty or full frames available!\n");
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return -EINVAL;
}
-#endif
pdev->fill_frame = pdev->full_frames;
pdev->full_frames = pdev->full_frames->next;
ret = 1;
}
pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
- Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
- pdev->fill_frame->sequence = pdev->sequence++;
-#endif
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return ret;
}
@@ -521,6 +489,8 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
int i;
unsigned long flags;
+ PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+
spin_lock_irqsave(&pdev->ptrlock, flags);
pdev->full_frames = NULL;
pdev->full_frames_tail = NULL;
@@ -540,13 +510,15 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
pdev->image_read_pos = 0;
pdev->fill_image = 0;
spin_unlock_irqrestore(&pdev->ptrlock, flags);
+
+ PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
}
/**
\brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
*/
-static int pwc_handle_frame(struct pwc_device *pdev)
+int pwc_handle_frame(struct pwc_device *pdev)
{
int ret = 0;
unsigned long flags;
@@ -556,41 +528,40 @@ static int pwc_handle_frame(struct pwc_device *pdev)
we can release the lock after this without problems */
if (pdev->read_frame != NULL) {
/* This can't theoretically happen */
- Err("Huh? Read frame still in use?\n");
+ PWC_ERROR("Huh? Read frame still in use?\n");
+ spin_unlock_irqrestore(&pdev->ptrlock, flags);
+ return ret;
+ }
+
+
+ if (pdev->full_frames == NULL) {
+ PWC_ERROR("Woops. No frames ready.\n");
}
else {
- if (pdev->full_frames == NULL) {
- Err("Woops. No frames ready.\n");
+ pdev->read_frame = pdev->full_frames;
+ pdev->full_frames = pdev->full_frames->next;
+ pdev->read_frame->next = NULL;
+ }
+
+ if (pdev->read_frame != NULL) {
+ /* Decompression is a lenghty process, so it's outside of the lock.
+ This gives the isoc_handler the opportunity to fill more frames
+ in the mean time.
+ */
+ spin_unlock_irqrestore(&pdev->ptrlock, flags);
+ ret = pwc_decompress(pdev);
+ spin_lock_irqsave(&pdev->ptrlock, flags);
+
+ /* We're done with read_buffer, tack it to the end of the empty buffer list */
+ if (pdev->empty_frames == NULL) {
+ pdev->empty_frames = pdev->read_frame;
+ pdev->empty_frames_tail = pdev->empty_frames;
}
else {
- pdev->read_frame = pdev->full_frames;
- pdev->full_frames = pdev->full_frames->next;
- pdev->read_frame->next = NULL;
- }
-
- if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
- Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
- /* Decompression is a lenghty process, so it's outside of the lock.
- This gives the isoc_handler the opportunity to fill more frames
- in the mean time.
- */
- spin_unlock_irqrestore(&pdev->ptrlock, flags);
- ret = pwc_decompress(pdev);
- spin_lock_irqsave(&pdev->ptrlock, flags);
-
- /* We're done with read_buffer, tack it to the end of the empty buffer list */
- if (pdev->empty_frames == NULL) {
- pdev->empty_frames = pdev->read_frame;
- pdev->empty_frames_tail = pdev->empty_frames;
- }
- else {
- pdev->empty_frames_tail->next = pdev->read_frame;
- pdev->empty_frames_tail = pdev->read_frame;
- }
- pdev->read_frame = NULL;
+ pdev->empty_frames_tail->next = pdev->read_frame;
+ pdev->empty_frames_tail = pdev->read_frame;
}
+ pdev->read_frame = NULL;
}
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return ret;
@@ -599,12 +570,114 @@ static int pwc_handle_frame(struct pwc_device *pdev)
/**
\brief Advance pointers of image buffer (after each user request)
*/
-static inline void pwc_next_image(struct pwc_device *pdev)
+void pwc_next_image(struct pwc_device *pdev)
{
pdev->image_used[pdev->fill_image] = 0;
- pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+ pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
}
+/**
+ * Print debug information when a frame is discarded because all of our buffer
+ * is full
+ */
+static void pwc_frame_dumped(struct pwc_device *pdev)
+{
+ pdev->vframes_dumped++;
+ if (pdev->vframe_count < FRAME_LOWMARK)
+ return;
+
+ if (pdev->vframes_dumped < 20)
+ PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
+ else if (pdev->vframes_dumped == 20)
+ PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
+ pdev->vframe_count);
+}
+
+static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+{
+ int awake = 0;
+
+ /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+ frames on the USB wire after an exposure change. This conditition is
+ however detected in the cam and a bit is set in the header.
+ */
+ if (pdev->type == 730) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+
+ if (ptr[1] == 1 && ptr[0] & 0x10) {
+ PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
+ pdev->drop_frames += 2;
+ pdev->vframes_error++;
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01) {
+ pdev->snapshot_button_status = 1;
+ PWC_TRACE("Snapshot button pressed.\n");
+ }
+ else {
+ PWC_TRACE("Snapshot button released.\n");
+ }
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+ if (ptr[0] & 0x02)
+ PWC_TRACE("Image is mirrored.\n");
+ else
+ PWC_TRACE("Image is normal.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+ after a short frame; this condition is filtered out specifically. A 4 byte
+ frame doesn't make sense anyway.
+ So we get either this sequence:
+ drop_bit set -> 4 byte frame -> short frame -> good frame
+ Or this one:
+ drop_bit set -> short frame -> good frame
+ So we drop either 3 or 2 frames in all!
+ */
+ if (fbuf->filled == 4)
+ pdev->drop_frames++;
+ }
+ else if (pdev->type == 740 || pdev->type == 720) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01) {
+ pdev->snapshot_button_status = 1;
+ PWC_TRACE("Snapshot button pressed.\n");
+ }
+ else
+ PWC_TRACE("Snapshot button released.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ }
+
+ /* In case we were instructed to drop the frame, do so silently.
+ The buffer pointers are not updated either (but the counters are reset below).
+ */
+ if (pdev->drop_frames > 0)
+ pdev->drop_frames--;
+ else {
+ /* Check for underflow first */
+ if (fbuf->filled < pdev->frame_total_size) {
+ PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
+ " discarded.\n", fbuf->filled);
+ pdev->vframes_error++;
+ }
+ else {
+ /* Send only once per EOF */
+ awake = 1; /* delay wake_ups */
+
+ /* Find our next frame to fill. This will always succeed, since we
+ * nick a frame from either empty or full list, but if we had to
+ * take it from the full list, it means a frame got dropped.
+ */
+ if (pwc_next_fill_frame(pdev))
+ pwc_frame_dumped(pdev);
+
+ }
+ } /* !drop_frames */
+ pdev->vframe_count++;
+ return awake;
+}
/* This gets called for the Isochronous pipe (video). This is done in
* interrupt time, so it has to be fast, not crash, and not stall. Neat.
@@ -620,17 +693,12 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
awake = 0;
pdev = (struct pwc_device *)urb->context;
if (pdev == NULL) {
- Err("isoc_handler() called with NULL device?!\n");
- return;
- }
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("isoc_handler() called with bad magic!\n");
+ PWC_ERROR("isoc_handler() called with NULL device?!\n");
return;
}
-#endif
+
if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
- Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+ PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
return;
}
if (urb->status != -EINPROGRESS && urb->status != 0) {
@@ -643,15 +711,15 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
- case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
+ case -ETIME: errmsg = "Device does not respond"; break;
}
- Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+ PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
/* Give up after a number of contiguous errors on the USB bus.
Appearantly something is wrong so we simulate an unplug event.
*/
if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
{
- Info("Too many ISOC errors, bailing out.\n");
+ PWC_INFO("Too many ISOC errors, bailing out.\n");
pdev->error_status = EIO;
awake = 1;
wake_up_interruptible(&pdev->frameq);
@@ -661,7 +729,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
fbuf = pdev->fill_frame;
if (fbuf == NULL) {
- Err("pwc_isoc_handler without valid fill frame.\n");
+ PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
awake = 1;
goto handler_end;
}
@@ -688,7 +756,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
/* ...copy data to frame buffer, if possible */
if (flen + fbuf->filled > pdev->frame_total_size) {
- Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+ PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
pdev->vframes_error++;
}
@@ -704,96 +772,28 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
/* Shorter packet... We probably have the end of an image-frame;
wake up read() process and let select()/poll() do something.
Decompression is done in user time over there.
- */
+ */
if (pdev->vsync == 2) {
- /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
- frames on the USB wire after an exposure change. This conditition is
- however detected in the cam and a bit is set in the header.
- */
- if (pdev->type == 730) {
- unsigned char *ptr = (unsigned char *)fbuf->data;
-
- if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
- Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
- pdev->drop_frames += 2;
- pdev->vframes_error++;
- }
- if ((ptr[0] ^ pdev->vmirror) & 0x01) {
- if (ptr[0] & 0x01)
- Info("Snapshot button pressed.\n");
- else
- Info("Snapshot button released.\n");
- }
- if ((ptr[0] ^ pdev->vmirror) & 0x02) {
- if (ptr[0] & 0x02)
- Info("Image is mirrored.\n");
- else
- Info("Image is normal.\n");
- }
- pdev->vmirror = ptr[0] & 0x03;
- /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
- after a short frame; this condition is filtered out specifically. A 4 byte
- frame doesn't make sense anyway.
- So we get either this sequence:
- drop_bit set -> 4 byte frame -> short frame -> good frame
- Or this one:
- drop_bit set -> short frame -> good frame
- So we drop either 3 or 2 frames in all!
- */
- if (fbuf->filled == 4)
- pdev->drop_frames++;
+ if (pwc_rcv_short_packet(pdev, fbuf)) {
+ awake = 1;
+ fbuf = pdev->fill_frame;
}
-
- /* In case we were instructed to drop the frame, do so silently.
- The buffer pointers are not updated either (but the counters are reset below).
- */
- if (pdev->drop_frames > 0)
- pdev->drop_frames--;
- else {
- /* Check for underflow first */
- if (fbuf->filled < pdev->frame_total_size) {
- Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
- pdev->vframes_error++;
- }
- else {
- /* Send only once per EOF */
- awake = 1; /* delay wake_ups */
-
- /* Find our next frame to fill. This will always succeed, since we
- * nick a frame from either empty or full list, but if we had to
- * take it from the full list, it means a frame got dropped.
- */
- if (pwc_next_fill_frame(pdev)) {
- pdev->vframes_dumped++;
- if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
- if (pdev->vframes_dumped < 20)
- Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
- if (pdev->vframes_dumped == 20)
- Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
- }
- }
- fbuf = pdev->fill_frame;
- }
- } /* !drop_frames */
- pdev->vframe_count++;
}
fbuf->filled = 0;
fillptr = fbuf->data;
pdev->vsync = 1;
- } /* .. flen < last_packet_size */
+ }
+
pdev->vlast_packet_size = flen;
} /* ..status == 0 */
-#if PWC_DEBUG
- /* This is normally not interesting to the user, unless you are really debugging something */
else {
+ /* This is normally not interesting to the user, unless
+ * you are really debugging something */
static int iso_error = 0;
iso_error++;
if (iso_error < 20)
- Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+ PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
}
-#endif
}
handler_end:
@@ -803,11 +803,11 @@ handler_end:
urb->dev = pdev->udev;
i = usb_submit_urb(urb, GFP_ATOMIC);
if (i != 0)
- Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+ PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
-static int pwc_isoc_init(struct pwc_device *pdev)
+int pwc_isoc_init(struct pwc_device *pdev)
{
struct usb_device *udev;
struct urb *urb;
@@ -826,7 +826,6 @@ static int pwc_isoc_init(struct pwc_device *pdev)
/* Get the current alternate interface, adjust packet size */
if (!udev->actconfig)
return -EFAULT;
-
intf = usb_ifnum_to_if(udev, 0);
if (intf)
idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
@@ -836,20 +835,21 @@ static int pwc_isoc_init(struct pwc_device *pdev)
/* Search video endpoint */
pdev->vmax_packet_size = -1;
- for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+ for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
break;
}
+ }
if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
- Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+ PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
return -ENFILE; /* Odd error, that should be noticeable */
}
/* Set alternate interface */
ret = 0;
- Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+ PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
if (ret < 0)
return ret;
@@ -857,12 +857,12 @@ static int pwc_isoc_init(struct pwc_device *pdev)
for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL) {
- Err("Failed to allocate urb %d\n", i);
+ PWC_ERROR("Failed to allocate urb %d\n", i);
ret = -ENOMEM;
break;
}
pdev->sbuf[i].urb = urb;
- Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+ PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
}
if (ret) {
/* De-allocate in reverse order */
@@ -899,24 +899,26 @@ static int pwc_isoc_init(struct pwc_device *pdev)
for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
if (ret)
- Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+ PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
else
- Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+ PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
}
/* All is done... */
pdev->iso_init = 1;
- Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+ PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
return 0;
}
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
+void pwc_isoc_cleanup(struct pwc_device *pdev)
{
int i;
- Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+ PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
if (pdev == NULL)
return;
+ if (pdev->iso_init == 0)
+ return;
/* Unlinking ISOC buffers one by one */
for (i = 0; i < MAX_ISO_BUFS; i++) {
@@ -925,10 +927,10 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
urb = pdev->sbuf[i].urb;
if (urb != 0) {
if (pdev->iso_init) {
- Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+ PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
usb_kill_urb(urb);
}
- Trace(TRACE_MEMORY, "Freeing URB\n");
+ PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
}
@@ -938,12 +940,12 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
is signalled by EPIPE)
*/
if (pdev->error_status && pdev->error_status != EPIPE) {
- Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+ PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
usb_set_interface(pdev->udev, 0, 0);
}
pdev->iso_init = 0;
- Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+ PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
@@ -957,18 +959,18 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
/* Try to set video mode... */
start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
if (ret) {
- Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+ PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
/* That failed... restore old mode (we know that worked) */
start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
if (start) {
- Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+ PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
}
}
if (start == 0)
{
if (pwc_isoc_init(pdev) < 0)
{
- Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+ PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
ret = -EAGAIN; /* let's try again, who knows if it works a second time */
}
}
@@ -976,54 +978,129 @@ int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_f
return ret; /* Return original error code */
}
+/*********
+ * sysfs
+ *********/
+static struct pwc_device *cd_to_pwc(struct class_device *cd)
+{
+ struct video_device *vdev = to_video_device(cd);
+ return video_get_drvdata(vdev);
+}
+
+static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
+}
+
+static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
+ size_t count)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ int pan, tilt;
+ int ret = -EINVAL;
+
+ if (strncmp(buf, "reset", 5) == 0)
+ ret = pwc_mpt_reset(pdev, 0x3);
+
+ else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
+ ret = pwc_mpt_set_angle(pdev, pan, tilt);
+
+ if (ret < 0)
+ return ret;
+ return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+ store_pan_tilt);
+
+static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ int status = pdev->snapshot_button_status;
+ pdev->snapshot_button_status = 0;
+ return sprintf(buf, "%d\n", status);
+}
+
+static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+ NULL);
+
+static void pwc_create_sysfs_files(struct video_device *vdev)
+{
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ video_device_create_file(vdev, &class_device_attr_pan_tilt);
+ video_device_create_file(vdev, &class_device_attr_button);
+}
+
+static void pwc_remove_sysfs_files(struct video_device *vdev)
+{
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ video_device_remove_file(vdev, &class_device_attr_pan_tilt);
+ video_device_remove_file(vdev, &class_device_attr_button);
+}
+
+#if CONFIG_PWC_DEBUG
+static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
+{
+ switch(sensor_type) {
+ case 0x00:
+ return "Hyundai CMOS sensor";
+ case 0x20:
+ return "Sony CCD sensor + TDA8787";
+ case 0x2E:
+ return "Sony CCD sensor + Exas 98L59";
+ case 0x2F:
+ return "Sony CCD sensor + ADI 9804";
+ case 0x30:
+ return "Sharp CCD sensor + TDA8787";
+ case 0x3E:
+ return "Sharp CCD sensor + Exas 98L59";
+ case 0x3F:
+ return "Sharp CCD sensor + ADI 9804";
+ case 0x40:
+ return "UPA 1021 sensor";
+ case 0x100:
+ return "VGA sensor";
+ case 0x101:
+ return "PAL MR sensor";
+ default:
+ return "unknown type of sensor";
+ }
+}
+#endif
/***************************************************************************/
/* Video4Linux functions */
static int pwc_video_open(struct inode *inode, struct file *file)
{
- int i;
+ int i, ret;
struct video_device *vdev = video_devdata(file);
struct pwc_device *pdev;
- Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+ PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev == NULL)
BUG();
- if (pdev->vopen)
+ if (pdev->vopen) {
+ PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
return -EBUSY;
+ }
down(&pdev->modlock);
if (!pdev->usb_init) {
- Trace(TRACE_OPEN, "Doing first time initialization.\n");
+ PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
- if (pwc_trace & TRACE_OPEN)
+ /* Query sensor type */
+ ret = pwc_get_cmos_sensor(pdev, &i);
+ if (ret >= 0)
{
- /* Query sensor type */
- const char *sensor_type = NULL;
- int ret;
-
- ret = pwc_get_cmos_sensor(pdev, &i);
- if (ret >= 0)
- {
- switch(i) {
- case 0x00: sensor_type = "Hyundai CMOS sensor"; break;
- case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break;
- case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break;
- case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break;
- case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break;
- case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
- case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break;
- case 0x40: sensor_type = "UPA 1021 sensor"; break;
- case 0x100: sensor_type = "VGA sensor"; break;
- case 0x101: sensor_type = "PAL MR sensor"; break;
- default: sensor_type = "unknown type of sensor"; break;
- }
- }
- if (sensor_type != NULL)
- Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+ PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+ pdev->vdev->name,
+ pwc_sensor_type_to_string(i), i);
}
}
@@ -1031,34 +1108,32 @@ static int pwc_video_open(struct inode *inode, struct file *file)
if (power_save) {
i = pwc_camera_power(pdev, 1);
if (i < 0)
- Info("Failed to restore power to the camera! (%d)\n", i);
+ PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
}
/* Set LED on/off time */
if (pwc_set_leds(pdev, led_on, led_off) < 0)
- Info("Failed to set LED on/off time.\n");
+ PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
pwc_construct(pdev); /* set min/max sizes correct */
/* So far, so good. Allocate memory. */
i = pwc_allocate_buffers(pdev);
if (i < 0) {
- Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+ PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
/* Reset buffers & parameters */
pwc_reset_buffers(pdev);
- for (i = 0; i < default_mbufs; i++)
+ for (i = 0; i < pwc_mbufs; i++)
pdev->image_used[i] = 0;
pdev->vframe_count = 0;
pdev->vframes_dumped = 0;
pdev->vframes_error = 0;
pdev->visoc_errors = 0;
pdev->error_status = 0;
-#if PWC_DEBUG
- pdev->sequence = 0;
-#endif
pwc_construct(pdev); /* set min/max sizes correct */
/* Set some defaults */
@@ -1070,29 +1145,44 @@ static int pwc_video_open(struct inode *inode, struct file *file)
*/
i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
if (i) {
- Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
- if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
- i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+ unsigned int default_resolution;
+ PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
+ if (pdev->type>= 730)
+ default_resolution = PSZ_QSIF;
else
- i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+ default_resolution = PSZ_QCIF;
+
+ i = pwc_set_video_mode(pdev,
+ pwc_image_sizes[default_resolution].x,
+ pwc_image_sizes[default_resolution].y,
+ 10,
+ pdev->vcompression,
+ 0);
}
if (i) {
- Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+ PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
i = pwc_isoc_init(pdev);
if (i) {
- Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+ PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
+ pwc_isoc_cleanup(pdev);
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
+ /* Initialize the webcam to sane value */
+ pwc_set_brightness(pdev, 0x7fff);
+ pwc_set_agc(pdev, 1, 0);
+
pdev->vopen++;
file->private_data = vdev;
up(&pdev->modlock);
- Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+ PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
return 0;
}
@@ -1103,35 +1193,23 @@ static int pwc_video_close(struct inode *inode, struct file *file)
struct pwc_device *pdev;
int i;
- Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+ PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0)
- Info("video_close() called on closed device?\n");
+ PWC_DEBUG_MODULE("video_close() called on closed device?\n");
/* Dump statistics, but only if a reasonable amount of frames were
processed (to prevent endless log-entries in case of snap-shot
programs)
*/
if (pdev->vframe_count > 20)
- Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+ PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-/* pwc_dec23_exit(); *//* Timon & Kiara */
- break;
- case 645:
- case 646:
-/* pwc_dec1_exit(); */
- break;
- }
+ if (DEVICE_USE_CODEC1(pdev->type))
+ pwc_dec1_exit();
+ else
+ pwc_dec23_exit();
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
@@ -1140,15 +1218,15 @@ static int pwc_video_close(struct inode *inode, struct file *file)
if (pdev->error_status != EPIPE) {
/* Turn LEDs off */
if (pwc_set_leds(pdev, 0, 0) < 0)
- Info("Failed to set LED on/off time.\n");
+ PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
if (power_save) {
i = pwc_camera_power(pdev, 0);
if (i < 0)
- Err("Failed to power down camera (%d)\n", i);
+ PWC_ERROR("Failed to power down camera (%d)\n", i);
}
}
- pdev->vopen = 0;
- Trace(TRACE_OPEN, "<< video_close()\n");
+ pdev->vopen--;
+ PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
return 0;
}
@@ -1164,7 +1242,7 @@ static int pwc_video_close(struct inode *inode, struct file *file)
device is tricky anyhow.
*/
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *vdev = file->private_data;
@@ -1172,8 +1250,10 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
int noblock = file->f_flags & O_NONBLOCK;
DECLARE_WAITQUEUE(wait, current);
int bytes_to_read;
+ void *image_buffer_addr;
- Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+ PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
+ vdev, buf, count);
if (vdev == NULL)
return -EFAULT;
pdev = vdev->priv;
@@ -1214,16 +1294,19 @@ static ssize_t pwc_video_read(struct file *file, char __user * buf,
return -EFAULT;
}
- Trace(TRACE_READ, "Copying data to user space.\n");
+ PWC_DEBUG_READ("Copying data to user space.\n");
if (pdev->vpalette == VIDEO_PALETTE_RAW)
- bytes_to_read = pdev->frame_size;
+ bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
else
bytes_to_read = pdev->view.size;
/* copy bytes to user space; we allow for partial reads */
if (count + pdev->image_read_pos > bytes_to_read)
count = bytes_to_read - pdev->image_read_pos;
- if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+ image_buffer_addr = pdev->image_data;
+ image_buffer_addr += pdev->images[pdev->fill_image].offset;
+ image_buffer_addr += pdev->image_read_pos;
+ if (copy_to_user(buf, image_buffer_addr, count))
return -EFAULT;
pdev->image_read_pos += count;
if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
@@ -1253,370 +1336,56 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
return 0;
}
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev;
- DECLARE_WAITQUEUE(wait, current);
-
- if (vdev == NULL)
- return -EFAULT;
- pdev = vdev->priv;
- if (pdev == NULL)
- return -EFAULT;
-
- switch (cmd) {
- /* Query cabapilities */
- case VIDIOCGCAP:
- {
- struct video_capability *caps = arg;
-
- strcpy(caps->name, vdev->name);
- caps->type = VID_TYPE_CAPTURE;
- caps->channels = 1;
- caps->audios = 1;
- caps->minwidth = pdev->view_min.x;
- caps->minheight = pdev->view_min.y;
- caps->maxwidth = pdev->view_max.x;
- caps->maxheight = pdev->view_max.y;
- break;
- }
-
- /* Channel functions (simulate 1 channel) */
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Webcam");
- return 0;
- }
-
- case VIDIOCSCHAN:
- {
- /* The spec says the argument is an integer, but
- the bttv driver uses a video_channel arg, which
- makes sense becasue it also has the norm flag.
- */
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
-
-
- /* Picture functions; contrast etc. */
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
- int val;
-
- val = pwc_get_brightness(pdev);
- if (val >= 0)
- p->brightness = val;
- else
- p->brightness = 0xffff;
- val = pwc_get_contrast(pdev);
- if (val >= 0)
- p->contrast = val;
- else
- p->contrast = 0xffff;
- /* Gamma, Whiteness, what's the difference? :) */
- val = pwc_get_gamma(pdev);
- if (val >= 0)
- p->whiteness = val;
- else
- p->whiteness = 0xffff;
- val = pwc_get_saturation(pdev);
- if (val >= 0)
- p->colour = val;
- else
- p->colour = 0xffff;
- p->depth = 24;
- p->palette = pdev->vpalette;
- p->hue = 0xFFFF; /* N/A */
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- /*
- * FIXME: Suppose we are mid read
- ANSWER: No problem: the firmware of the camera
- can handle brightness/contrast/etc
- changes at _any_ time, and the palette
- is used exactly once in the uncompress
- routine.
- */
- pwc_set_brightness(pdev, p->brightness);
- pwc_set_contrast(pdev, p->contrast);
- pwc_set_gamma(pdev, p->whiteness);
- pwc_set_saturation(pdev, p->colour);
- if (p->palette && p->palette != pdev->vpalette) {
- switch (p->palette) {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- pdev->vpalette = p->palette;
- return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- break;
- default:
- return -EINVAL;
- break;
- }
- }
- break;
- }
-
- /* Window/size parameters */
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- vw->x = 0;
- vw->y = 0;
- vw->width = pdev->view.x;
- vw->height = pdev->view.y;
- vw->chromakey = 0;
- vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
- (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
- break;
- }
-
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- int fps, snapshot, ret;
-
- fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
- snapshot = vw->flags & PWC_FPS_SNAPSHOT;
- if (fps == 0)
- fps = pdev->vframes;
- if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
- return 0;
- ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
- if (ret)
- return ret;
- break;
- }
-
- /* We don't have overlay support (yet) */
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- memset(vb,0,sizeof(*vb));
- break;
- }
-
- /* mmap() functions */
- case VIDIOCGMBUF:
- {
- /* Tell the user program how much memory is needed for a mmap() */
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = default_mbufs * pdev->len_per_image;
- vm->frames = default_mbufs; /* double buffering should be enough for most applications */
- for (i = 0; i < default_mbufs; i++)
- vm->offsets[i] = i * pdev->len_per_image;
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
- struct video_mmap *vm = arg;
-
- Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
- if (vm->frame < 0 || vm->frame >= default_mbufs)
- return -EINVAL;
-
- /* xawtv is nasty. It probes the available palettes
- by setting a very small image size and trying
- various palettes... The driver doesn't support
- such small images, so I'm working around it.
- */
- if (vm->format)
- {
- switch (vm->format)
- {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- break;
- default:
- return -EINVAL;
- break;
- }
- }
-
- if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
- (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
- int ret;
-
- Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
- ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- if (ret)
- return ret;
- } /* ... size mismatch */
-
- /* FIXME: should we lock here? */
- if (pdev->image_used[vm->frame])
- return -EBUSY; /* buffer wasn't available. Bummer */
- pdev->image_used[vm->frame] = 1;
-
- /* Okay, we're done here. In the SYNC call we wait until a
- frame comes available, then expand image into the given
- buffer.
- In contrast to the CPiA cam the Philips cams deliver a
- constant stream, almost like a grabber card. Also,
- we have separate buffers for the rawdata and the image,
- meaning we can nearly always expand into the requested buffer.
- */
- Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
- break;
- }
-
- case VIDIOCSYNC:
- {
- /* The doc says: "Whenever a buffer is used it should
- call VIDIOCSYNC to free this frame up and continue."
-
- The only odd thing about this whole procedure is
- that MCAPTURE flags the buffer as "in use", and
- SYNC immediately unmarks it, while it isn't
- after SYNC that you know that the buffer actually
- got filled! So you better not start a CAPTURE in
- the same frame immediately (use double buffering).
- This is not a problem for this cam, since it has
- extra intermediate buffers, but a hardware
- grabber card will then overwrite the buffer
- you're working on.
- */
- int *mbuf = arg;
- int ret;
-
- Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
- /* bounds check */
- if (*mbuf < 0 || *mbuf >= default_mbufs)
- return -EINVAL;
- /* check if this buffer was requested anyway */
- if (pdev->image_used[*mbuf] == 0)
- return -EINVAL;
-
- /* Add ourselves to the frame wait-queue.
-
- FIXME: needs auditing for safety.
- QUESTION: In what respect? I think that using the
- frameq is safe now.
- */
- add_wait_queue(&pdev->frameq, &wait);
- while (pdev->full_frames == NULL) {
- if (pdev->error_status) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -pdev->error_status;
- }
-
- if (signal_pending(current)) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -ERESTARTSYS;
- }
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
-
- /* The frame is ready. Expand in the image buffer
- requested by the user. I don't care if you
- mmap() 5 buffers and request data in this order:
- buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
- Grabber hardware may not be so forgiving.
- */
- Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
- pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
- /* Decompress, etc */
- ret = pwc_handle_frame(pdev);
- pdev->image_used[*mbuf] = 0;
- if (ret)
- return -EFAULT;
- break;
- }
-
- case VIDIOCGAUDIO:
- {
- struct video_audio *v = arg;
-
- strcpy(v->name, "Microphone");
- v->audio = -1; /* unknown audio minor */
- v->flags = 0;
- v->mode = VIDEO_SOUND_MONO;
- v->volume = 0;
- v->bass = 0;
- v->treble = 0;
- v->balance = 0x8000;
- v->step = 1;
- break;
- }
-
- case VIDIOCSAUDIO:
- {
- /* Dummy: nothing can be set */
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- vu->video = pdev->vdev->minor & 0x3F;
- vu->audio = -1; /* not known yet */
- vu->vbi = -1;
- vu->radio = -1;
- vu->teletext = -1;
- break;
- }
- default:
- return pwc_ioctl(pdev, cmd, arg);
- } /* ..switch */
- return 0;
-}
-
static int pwc_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
}
-
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
+ unsigned long start;
+ unsigned long size;
+ unsigned long page, pos = 0;
+ int index;
- Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+ PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
pdev = vdev->priv;
+ size = vma->vm_end - vma->vm_start;
+ start = vma->vm_start;
- vma->vm_flags |= VM_IO;
+ /* Find the idx buffer for this mapping */
+ for (index = 0; index < pwc_mbufs; index++) {
+ pos = pdev->images[index].offset;
+ if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+ if (index == MAX_IMAGES)
+ return -EINVAL;
+ if (index == 0) {
+ /*
+ * Special case for v4l1. In v4l1, we map only one big buffer,
+ * but in v4l2 each buffer is mapped
+ */
+ unsigned long total_size;
+ total_size = pwc_mbufs * pdev->len_per_image;
+ if (size != pdev->len_per_image && size != total_size) {
+ PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
+ size, pdev->len_per_image, total_size);
+ return -EINVAL;
+ }
+ } else if (size > pdev->len_per_image)
+ return -EINVAL;
- pos = (unsigned long)pdev->image_data;
+ vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
+
+ pos += (unsigned long)pdev->image_data;
while (size > 0) {
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
-
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
@@ -1624,7 +1393,6 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
else
size = 0;
}
-
return 0;
}
@@ -1645,10 +1413,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
+ vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+ product_id = le16_to_cpu(udev->descriptor.idProduct);
+
/* Check if we can handle this device */
- Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct),
+ PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
+ vendor_id, product_id,
intf->altsetting->desc.bInterfaceNumber);
/* the interfaces are probed one by one. We are only interested in the
@@ -1658,61 +1428,63 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
if (intf->altsetting->desc.bInterfaceNumber > 0)
return -ENODEV;
- vendor_id = le16_to_cpu(udev->descriptor.idVendor);
- product_id = le16_to_cpu(udev->descriptor.idProduct);
-
if (vendor_id == 0x0471) {
switch (product_id) {
case 0x0302:
- Info("Philips PCA645VC USB webcam detected.\n");
+ PWC_INFO("Philips PCA645VC USB webcam detected.\n");
name = "Philips 645 webcam";
type_id = 645;
break;
case 0x0303:
- Info("Philips PCA646VC USB webcam detected.\n");
+ PWC_INFO("Philips PCA646VC USB webcam detected.\n");
name = "Philips 646 webcam";
type_id = 646;
break;
case 0x0304:
- Info("Askey VC010 type 2 USB webcam detected.\n");
+ PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 646;
break;
case 0x0307:
- Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
name = "Philips 675 webcam";
type_id = 675;
break;
case 0x0308:
- Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
name = "Philips 680 webcam";
type_id = 680;
break;
case 0x030C:
- Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
name = "Philips 690 webcam";
type_id = 690;
break;
case 0x0310:
- Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
name = "Philips 730 webcam";
type_id = 730;
break;
case 0x0311:
- Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
name = "Philips 740 webcam";
type_id = 740;
break;
case 0x0312:
- Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
name = "Philips 750 webcam";
type_id = 750;
break;
case 0x0313:
- Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
name = "Philips 720K/40 webcam";
type_id = 720;
break;
+ case 0x0329:
+ PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
+ name = "Philips SPC 900NC webcam";
+ type_id = 720;
+ break;
default:
return -ENODEV;
break;
@@ -1721,7 +1493,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x069A) {
switch(product_id) {
case 0x0001:
- Info("Askey VC010 type 1 USB webcam detected.\n");
+ PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 645;
break;
@@ -1733,32 +1505,33 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x046d) {
switch(product_id) {
case 0x08b0:
- Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
name = "Logitech QuickCam Pro 3000";
type_id = 740; /* CCD sensor */
break;
case 0x08b1:
- Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
name = "Logitech QuickCam Notebook Pro";
type_id = 740; /* CCD sensor */
break;
case 0x08b2:
- Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
name = "Logitech QuickCam Pro 4000";
type_id = 740; /* CCD sensor */
break;
case 0x08b3:
- Info("Logitech QuickCam Zoom USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
break;
case 0x08B4:
- Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
+ power_save = 1;
break;
case 0x08b5:
- Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
name = "Logitech QuickCam Orbit";
type_id = 740; /* CCD sensor */
features |= FEATURE_MOTOR_PANTILT;
@@ -1766,7 +1539,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
case 0x08b6:
case 0x08b7:
case 0x08b8:
- Info("Logitech QuickCam detected (reserved ID).\n");
+ PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
name = "Logitech QuickCam (res.)";
type_id = 730; /* Assuming CMOS */
break;
@@ -1782,15 +1555,20 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
*/
switch(product_id) {
case 0x9000:
- Info("Samsung MPC-C10 USB webcam detected.\n");
+ PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
name = "Samsung MPC-C10";
type_id = 675;
break;
case 0x9001:
- Info("Samsung MPC-C30 USB webcam detected.\n");
+ PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
name = "Samsung MPC-C30";
type_id = 675;
break;
+ case 0x9002:
+ PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
+ name = "Samsung MPC-C30";
+ type_id = 740;
+ break;
default:
return -ENODEV;
break;
@@ -1799,12 +1577,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x041e) {
switch(product_id) {
case 0x400c:
- Info("Creative Labs Webcam 5 detected.\n");
+ PWC_INFO("Creative Labs Webcam 5 detected.\n");
name = "Creative Labs Webcam 5";
type_id = 730;
break;
case 0x4011:
- Info("Creative Labs Webcam Pro Ex detected.\n");
+ PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
name = "Creative Labs Webcam Pro Ex";
type_id = 740;
break;
@@ -1816,7 +1594,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x04cc) {
switch(product_id) {
case 0x8116:
- Info("Sotec Afina Eye USB webcam detected.\n");
+ PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
name = "Sotec Afina Eye";
type_id = 730;
break;
@@ -1829,7 +1607,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
switch(product_id) {
case 0x8116:
/* This is essentially the same cam as the Sotec Afina Eye */
- Info("AME Co. Afina Eye USB webcam detected.\n");
+ PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
name = "AME Co. Afina Eye";
type_id = 750;
break;
@@ -1842,12 +1620,12 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
else if (vendor_id == 0x0d81) {
switch(product_id) {
case 0x1900:
- Info("Visionite VCS-UC300 USB webcam detected.\n");
+ PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
name = "Visionite VCS-UC300";
type_id = 740; /* CCD sensor */
break;
case 0x1910:
- Info("Visionite VCS-UM100 USB webcam detected.\n");
+ PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
name = "Visionite VCS-UM100";
type_id = 730; /* CMOS sensor */
break;
@@ -1861,15 +1639,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
memset(serial_number, 0, 30);
usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
- Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+ PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
if (udev->descriptor.bNumConfigurations > 1)
- Info("Warning: more than 1 configuration available.\n");
+ PWC_WARNING("Warning: more than 1 configuration available.\n");
/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
if (pdev == NULL) {
- Err("Oops, could not allocate memory for pwc_device.\n");
+ PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
return -ENOMEM;
}
pdev->type = type_id;
@@ -1900,17 +1678,18 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev = video_device_alloc();
if (pdev->vdev == 0)
{
- Err("Err, cannot allocate video_device struture. Failing probe.");
+ PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
kfree(pdev);
return -ENOMEM;
}
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+ pdev->vdev->dev = &(udev->dev);
strcpy(pdev->vdev->name, name);
pdev->vdev->owner = THIS_MODULE;
video_set_drvdata(pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
- Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+ PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
/* Now search device_hint[] table for a match, so we can hint a node number. */
for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
@@ -1918,10 +1697,10 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
(device_hint[hint].pdev == NULL)) {
/* so far, so good... try serial number */
if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
- /* match! */
- video_nr = device_hint[hint].device_node;
- Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
- break;
+ /* match! */
+ video_nr = device_hint[hint].device_node;
+ PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
+ break;
}
}
}
@@ -1929,21 +1708,27 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev->release = video_device_release;
i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
if (i < 0) {
- Err("Failed to register as video device (%d).\n", i);
+ PWC_ERROR("Failed to register as video device (%d).\n", i);
video_device_release(pdev->vdev); /* Drip... drip... drip... */
kfree(pdev); /* Oops, no memory leaks please */
return -EIO;
}
else {
- Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
}
/* occupy slot */
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev;
- Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+ PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
usb_set_intfdata (intf, pdev);
+ pwc_create_sysfs_files(pdev->vdev);
+
+ /* Set the leds off */
+ pwc_set_leds(pdev, 0, 0);
+ pwc_camera_power(pdev, 0);
+
return 0;
}
@@ -1957,27 +1742,21 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
pdev = usb_get_intfdata (intf);
usb_set_intfdata (intf, NULL);
if (pdev == NULL) {
- Err("pwc_disconnect() Called without private pointer.\n");
+ PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
goto disconnect_out;
}
if (pdev->udev == NULL) {
- Err("pwc_disconnect() already called for %p\n", pdev);
+ PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
goto disconnect_out;
}
if (pdev->udev != interface_to_usbdev(intf)) {
- Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
- goto disconnect_out;
- }
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+ PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
goto disconnect_out;
}
-#endif
/* We got unplugged; this is signalled by an EPIPE error code */
if (pdev->vopen) {
- Info("Disconnected while webcam is in use!\n");
+ PWC_INFO("Disconnected while webcam is in use!\n");
pdev->error_status = EPIPE;
}
@@ -1987,7 +1766,8 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
while (pdev->vopen)
schedule();
/* Device is now closed, so we can safely unregister it */
- Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+ pwc_remove_sysfs_files(pdev->vdev);
video_unregister_device(pdev->vdev);
/* Free memory (don't set pdev to 0 just yet) */
@@ -2021,58 +1801,64 @@ static int pwc_atoi(const char *s)
* Initialization code & module stuff
*/
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
+static char *size;
+static int fps;
+static int fbufs;
+static int mbufs;
static int compression = -1;
static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
+static int leds_nargs;
+static char *dev_hint[MAX_DEV_HINTS];
+static int dev_hint_nargs;
+
+module_param(size, charp, 0444);
+module_param(fps, int, 0444);
+module_param(fbufs, int, 0444);
+module_param(mbufs, int, 0444);
+#if CONFIG_PWC_DEBUG
+module_param_named(trace, pwc_trace, int, 0644);
+#endif
+module_param(power_save, int, 0444);
+module_param(compression, int, 0444);
+module_param_array(leds, int, &leds_nargs, 0444);
+module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
-module_param_string(size, size, sizeof(size), 0);
MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
MODULE_PARM_DESC(dev_hint, "Device node hints");
MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("pwcx");
+MODULE_VERSION( PWC_VERSION );
static int __init usb_pwc_init(void)
{
int i, sz;
char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
- Info("Philips webcam module version " PWC_VERSION " loaded.\n");
- Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
- Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
- Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+ PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
+ PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+ PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+ PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
if (fps) {
if (fps < 4 || fps > 30) {
- Err("Framerate out of bounds (4-30).\n");
+ PWC_ERROR("Framerate out of bounds (4-30).\n");
return -EINVAL;
}
default_fps = fps;
- Info("Default framerate set to %d.\n", default_fps);
+ PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
}
- if (size[0]) {
+ if (size) {
/* string; try matching with array */
for (sz = 0; sz < PSZ_MAX; sz++) {
if (!strcmp(sizenames[sz], size)) { /* Found! */
@@ -2081,41 +1867,42 @@ static int __init usb_pwc_init(void)
}
}
if (sz == PSZ_MAX) {
- Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+ PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
return -EINVAL;
}
- Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+ PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
}
if (mbufs) {
if (mbufs < 1 || mbufs > MAX_IMAGES) {
- Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+ PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
return -EINVAL;
}
- default_mbufs = mbufs;
- Info("Number of image buffers set to %d.\n", default_mbufs);
+ pwc_mbufs = mbufs;
+ PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
}
if (fbufs) {
if (fbufs < 2 || fbufs > MAX_FRAMES) {
- Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+ PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
return -EINVAL;
}
default_fbufs = fbufs;
- Info("Number of frame buffers set to %d.\n", default_fbufs);
+ PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
}
- if (trace >= 0) {
- Info("Trace options: 0x%04x\n", trace);
- pwc_trace = trace;
+#if CONFIG_PWC_DEBUG
+ if (pwc_trace >= 0) {
+ PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
}
+#endif
if (compression >= 0) {
if (compression > 3) {
- Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+ PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
return -EINVAL;
}
pwc_preferred_compression = compression;
- Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+ PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
}
if (power_save)
- Info("Enabling power save on open/close.\n");
+ PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
if (leds[0] >= 0)
led_on = leds[0];
if (leds[1] >= 0)
@@ -2146,14 +1933,14 @@ static int __init usb_pwc_init(void)
dot++;
/* Few sanity checks */
if (*dot != '\0' && dot > colon) {
- Err("Malformed camera hint: the colon must be after the dot.\n");
+ PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
return -EINVAL;
}
if (*colon == '\0') {
/* No colon */
if (*dot != '\0') {
- Err("Malformed camera hint: no colon + device node given.\n");
+ PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
return -EINVAL;
}
else {
@@ -2178,28 +1965,27 @@ static int __init usb_pwc_init(void)
device_hint[i].serial_number[k] = '\0';
}
}
-#if PWC_DEBUG
- Debug("device_hint[%d]:\n", i);
- Debug(" type : %d\n", device_hint[i].type);
- Debug(" serial# : %s\n", device_hint[i].serial_number);
- Debug(" node : %d\n", device_hint[i].device_node);
-#endif
+ PWC_TRACE("device_hint[%d]:\n", i);
+ PWC_TRACE(" type : %d\n", device_hint[i].type);
+ PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
+ PWC_TRACE(" node : %d\n", device_hint[i].device_node);
}
else
device_hint[i].type = 0; /* not filled */
} /* ..for MAX_DEV_HINTS */
- Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+ PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
return usb_register(&pwc_driver);
}
static void __exit usb_pwc_exit(void)
{
- Trace(TRACE_MODULE, "Deregistering driver.\n");
+ PWC_DEBUG_MODULE("Deregistering driver.\n");
usb_deregister(&pwc_driver);
- Info("Philips webcam module removed.\n");
+ PWC_INFO("Philips webcam module removed.\n");
}
module_init(usb_pwc_init);
module_exit(usb_pwc_exit);
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c
index 4c96037f7be..fec39cc5a9f 100644
--- a/drivers/media/video/pwc/pwc-kiara.c
+++ b/drivers/media/video/pwc/pwc-kiara.c
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -316,3 +316,576 @@ const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] =
},
};
+
+/*
+ * Rom table for kiara chips
+ *
+ * 32 roms tables (one for each resolution ?)
+ * 2 tables per roms (one for each passes) (Y, and U&V)
+ * 128 bytes per passes
+ */
+
+const unsigned int KiaraRomTable [8][2][16][8] =
+{
+ { /* version 0 */
+ { /* version 0, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009292,0x00009292,0x00009493,0x000124db},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x0000a493,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x000124db,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 0, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000001,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009292,
+ 0x00009492,0x00009493,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000126dc,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 1 */
+ { /* version 1, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 1, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000049,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 2 */
+ { /* version 2, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x0000a49b},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 2, passes 1 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x0000a49b,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 3 */
+ { /* version 3, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 3, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 4 */
+ { /* version 4, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 4, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 5 */
+ { /* version 5, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 5, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x00009252,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 6 */
+ { /* version 6, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 6, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 7 */
+ { /* version 7, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 7, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ }
+};
+
diff --git a/drivers/media/video/pwc/pwc-kiara.h b/drivers/media/video/pwc/pwc-kiara.h
index 12929abbb1f..0bdb22547d8 100644
--- a/drivers/media/video/pwc/pwc-kiara.h
+++ b/drivers/media/video/pwc/pwc-kiara.h
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -27,7 +27,7 @@
#ifndef PWC_KIARA_H
#define PWC_KIARA_H
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
struct Kiara_table_entry
{
@@ -37,8 +37,8 @@ struct Kiara_table_entry
unsigned char mode[12]; /* precomputed mode settings for cam */
};
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const unsigned int KiaraRomTable[8][2][16][8];
#endif
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
index 58fe7974799..589c687439d 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/video/pwc/pwc-misc.c
@@ -1,7 +1,7 @@
/* Linux driver for Philips webcam
Various miscellaneous functions and tables.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -24,18 +24,17 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/slab.h>
#include "pwc.h"
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
{
- { 128, 96, 0 },
- { 160, 120, 0 },
- { 176, 144, 0 },
- { 320, 240, 0 },
- { 352, 288, 0 },
- { 640, 480, 0 },
+ { 128, 96, 0 }, /* sqcif */
+ { 160, 120, 0 }, /* qsif */
+ { 176, 144, 0 }, /* qcif */
+ { 320, 240, 0 }, /* sif */
+ { 352, 288, 0 }, /* cif */
+ { 640, 480, 0 }, /* vga */
};
/* x,y -> PSZ_ */
@@ -52,7 +51,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
{
if (width > pdev->abs_max.x || height > pdev->abs_max.y)
{
- Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+ PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
return -1;
}
}
@@ -60,7 +59,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
{
if (width > pdev->view_max.x || height > pdev->view_max.y)
{
- Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+ PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
return -1;
}
}
@@ -81,9 +80,8 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
/* initialize variables depending on type and decompressor*/
void pwc_construct(struct pwc_device *pdev)
{
- switch(pdev->type) {
- case 645:
- case 646:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+
pdev->view_min.x = 128;
pdev->view_min.y = 96;
pdev->view_max.x = 352;
@@ -95,10 +93,23 @@ void pwc_construct(struct pwc_device *pdev)
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
- break;
- case 675:
- case 680:
- case 690:
+
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
+
+ pdev->view_min.x = 160;
+ pdev->view_min.y = 120;
+ pdev->view_max.x = 640;
+ pdev->view_max.y = 480;
+ pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+ pdev->abs_max.x = 640;
+ pdev->abs_max.y = 480;
+ pdev->vcinterface = 3;
+ pdev->vendpoint = 5;
+ pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+ pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+
+ } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
+
pdev->view_min.x = 128;
pdev->view_min.y = 96;
/* Anthill bug #38: PWC always reports max size, even without PWCX */
@@ -111,30 +122,12 @@ void pwc_construct(struct pwc_device *pdev)
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
- break;
- case 720:
- case 730:
- case 740:
- case 750:
- pdev->view_min.x = 160;
- pdev->view_min.y = 120;
- pdev->view_max.x = 640;
- pdev->view_max.y = 480;
- pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
- pdev->abs_max.x = 640;
- pdev->abs_max.y = 480;
- pdev->vcinterface = 3;
- pdev->vendpoint = 5;
- pdev->frame_header_size = TOUCAM_HEADER_SIZE;
- pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
- break;
}
- Debug("type = %d\n",pdev->type);
pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
/* length of image, in YUV format; always allocate enough memory. */
- pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+ pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
}
diff --git a/drivers/media/video/pwc/pwc-timon.c b/drivers/media/video/pwc/pwc-timon.c
index 175250d089c..be65bdcd195 100644
--- a/drivers/media/video/pwc/pwc-timon.c
+++ b/drivers/media/video/pwc/pwc-timon.c
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -314,3 +314,1133 @@ const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] =
},
};
+/*
+ * 16 versions:
+ * 2 tables (one for Y, and one for U&V)
+ * 16 levels of details per tables
+ * 8 blocs
+ */
+
+const unsigned int TimonRomTable [16][2][16][8] =
+{
+ { /* version 0 */
+ { /* version 0, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000001,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000001,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 0, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000001,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000001,
+ 0x00000001,0x00000009,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000009,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000009,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 1 */
+ { /* version 1, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 1, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000001,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000049,0x00000249,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 2 */
+ { /* version 2, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 2, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000049,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 3 */
+ { /* version 3, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 3, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00000049,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009292,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 4 */
+ { /* version 4, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x0000a49b},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 4, passes 1 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x0000a49b,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 5 */
+ { /* version 5, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 5, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x000124db,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009493,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 6 */
+ { /* version 6, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 6, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 7 */
+ { /* version 7, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x0002496e},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 7, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001b724,0x0001b925,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 8 */
+ { /* version 8, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x00024b76,0x00024b77},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x00024b76,0x00025bbf},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 8, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0002496d,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 9 */
+ { /* version 9, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 9, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 10 */
+ { /* version 10, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 10, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x00009493,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009493,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 11 */
+ { /* version 11, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 11, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x00009252,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 12 */
+ { /* version 12, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 12, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 13 */
+ { /* version 13, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 13, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 14 */
+ { /* version 14, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0002496d,0x00024b76,0x00024b77},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 14, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000136e4,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 15 */
+ { /* version 15, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0002496d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 15, passes 1 */
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009292,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000124db,0x0001b724,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x0001b724,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001c924,0x0001b724,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001c924,0x0001b724,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002496d,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ }
+};
diff --git a/drivers/media/video/pwc/pwc-timon.h b/drivers/media/video/pwc/pwc-timon.h
index a86b3782a08..eef9e2cd432 100644
--- a/drivers/media/video/pwc/pwc-timon.h
+++ b/drivers/media/video/pwc/pwc-timon.h
@@ -1,5 +1,5 @@
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -42,7 +42,7 @@
#ifndef PWC_TIMON_H
#define PWC_TIMON_H
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
struct Timon_table_entry
{
@@ -52,8 +52,8 @@ struct Timon_table_entry
unsigned char mode[13]; /* precomputed mode settings for cam */
};
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const unsigned int TimonRomTable [16][2][16][8];
#endif
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
index b37a89a163f..5d82028ef94 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/video/pwc/pwc-uncompress.c
@@ -1,7 +1,7 @@
/* Linux driver for Philips webcam
Decompression frontend.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -22,6 +22,8 @@
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
+
+ vim: set ts=8:
*/
#include <asm/current.h>
@@ -29,6 +31,8 @@
#include "pwc.h"
#include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
int pwc_decompress(struct pwc_device *pdev)
{
@@ -40,107 +44,95 @@ int pwc_decompress(struct pwc_device *pdev)
if (pdev == NULL)
return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
- if (pdev->magic != PWC_MAGIC) {
- Err("pwc_decompress(): magic failed.\n");
- return -EFAULT;
- }
-#endif
fbuf = pdev->read_frame;
if (fbuf == NULL)
return -EFAULT;
- image = pdev->image_ptr[pdev->fill_image];
- if (!image)
- return -EFAULT;
+ image = pdev->image_data;
+ image += pdev->images[pdev->fill_image].offset;
yuv = fbuf->data + pdev->frame_header_size; /* Skip header */
/* Raw format; that's easy... */
if (pdev->vpalette == VIDEO_PALETTE_RAW)
{
- memcpy(image, yuv, pdev->frame_size);
+ struct pwc_raw_frame *raw_frame = image;
+ raw_frame->type = cpu_to_le16(pdev->type);
+ raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength);
+ /* cmd_buf is always 4 bytes, but sometimes, only the
+ * first 3 bytes is filled (Nala case). We can
+ * determine this using the type of the webcam */
+ memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
+ memcpy(raw_frame+1, yuv, pdev->frame_size);
return 0;
}
if (pdev->vbandlength == 0) {
- /* Uncompressed mode. We copy the data into the output buffer,
- using the viewport size (which may be larger than the image
- size). Unfortunately we have to do a bit of byte stuffing
- to get the desired output format/size.
+ /* Uncompressed mode.
+ * We copy the data into the output buffer, using the viewport
+ * size (which may be larger than the image size).
+ * Unfortunately we have to do a bit of byte stuffing to get
+ * the desired output format/size.
+ *
+ * We do some byte shuffling here to go from the
+ * native format to YUV420P.
*/
- /*
- * We do some byte shuffling here to go from the
- * native format to YUV420P.
- */
- src = (u16 *)yuv;
- n = pdev->view.x * pdev->view.y;
-
- /* offset in Y plane */
- stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
- dsty = (u16 *)(image + stride);
-
- /* offsets in U/V planes */
- stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
- dstu = (u16 *)(image + n + stride);
- dstv = (u16 *)(image + n + n / 4 + stride);
-
- /* increment after each line */
- stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
- for (line = 0; line < pdev->image.y; line++) {
- for (col = 0; col < pdev->image.x; col += 4) {
- *dsty++ = *src++;
- *dsty++ = *src++;
- if (line & 1)
- *dstv++ = *src++;
- else
- *dstu++ = *src++;
- }
- dsty += stride;
+ src = (u16 *)yuv;
+ n = pdev->view.x * pdev->view.y;
+
+ /* offset in Y plane */
+ stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+ dsty = (u16 *)(image + stride);
+
+ /* offsets in U/V planes */
+ stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+ dstu = (u16 *)(image + n + stride);
+ dstv = (u16 *)(image + n + n / 4 + stride);
+
+ /* increment after each line */
+ stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+ for (line = 0; line < pdev->image.y; line++) {
+ for (col = 0; col < pdev->image.x; col += 4) {
+ *dsty++ = *src++;
+ *dsty++ = *src++;
if (line & 1)
- dstv += (stride >> 1);
+ *dstv++ = *src++;
else
- dstu += (stride >> 1);
+ *dstu++ = *src++;
}
+ dsty += stride;
+ if (line & 1)
+ dstv += (stride >> 1);
+ else
+ dstu += (stride >> 1);
+ }
+
+ return 0;
}
- else {
- /* Compressed; the decompressor routines will write the data
- in planar format immediately.
- */
- int flags;
-
- flags = PWCX_FLAG_PLANAR;
- if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
- {
- printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
- flags |= PWCX_FLAG_BAYER;
- return -ENXIO; /* No such device or address: missing decompressor */
- }
-
-#if 0
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
- pwc_dec23_decompress(&pdev->image, &pdev->view,
- &pdev->offset, yuv, image, flags,
- pdev->decompress_data, pdev->vbandlength);
- break;
- case 645:
- case 646:
- /* TODO & FIXME */
- return -ENXIO; /* Missing decompressor */
- break;
- }
-#endif
+
+ /*
+ * Compressed;
+ * the decompressor routines will write the data in planar format
+ * immediately.
+ */
+ if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
+ PWC_ERROR("Mode Bayer is not supported for now\n");
+ /* flags |= PWCX_FLAG_BAYER; */
+ return -ENXIO; /* No such device or address: missing decompressor */
+ }
+
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+
+ /* TODO & FIXME */
+ PWC_ERROR("This chipset is not supported for now\n");
+ return -ENXIO; /* No such device or address: missing decompressor */
+
+ } else {
+ pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
}
return 0;
}
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h
index f75e1b6cbe1..43028e74e9e 100644
--- a/drivers/media/video/pwc/pwc-uncompress.h
+++ b/drivers/media/video/pwc/pwc-uncompress.h
@@ -1,5 +1,5 @@
/* (C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -30,9 +30,8 @@
#ifndef PWC_UNCOMPRESS_H
#define PWC_UNCOMPRESS_H
-#include <linux/config.h>
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
/* from pwc-dec.h */
#define PWCX_FLAG_PLANAR 0x0001
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
new file mode 100644
index 00000000000..b7eb3ce3b96
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -0,0 +1,1202 @@
+/* Linux driver for Philips webcam
+ USB and Video4Linux interface part.
+ (C) 1999-2004 Nemosoft Unv.
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ 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/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+
+static struct v4l2_queryctrl pwc_controls[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 128,
+ .step = 1,
+ .default_value = 64,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 64,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = -100,
+ .maximum = 100,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0,
+ .maximum = 32,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Gain",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Gain",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Speed (Exposure)",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 200,
+ },
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain Enabled",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain Level",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_SAVE_USER,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Save User Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_RESTORE_USER,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Restore User Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Restore Factory Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_COLOUR_MODE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Colour mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto contour",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_CONTOUR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contour",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_BACKLIGHT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Backlight compensation",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_FLICKERLESS,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flickerless",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Noise reduction",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+
+static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+{
+ memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+ f->fmt.pix.width = pdev->view.x;
+ f->fmt.pix.height = pdev->view.y;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ } else {
+ /* vbandlength contains 4 lines ... */
+ f->fmt.pix.bytesperline = pdev->vbandlength/4;
+ f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ if (DEVICE_USE_CODEC1(pdev->type))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
+ else
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
+ }
+ PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
+ "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ f->fmt.pix.bytesperline,
+ f->fmt.pix.sizeimage,
+ (f->fmt.pix.pixelformat)&255,
+ (f->fmt.pix.pixelformat>>8)&255,
+ (f->fmt.pix.pixelformat>>16)&255,
+ (f->fmt.pix.pixelformat>>24)&255);
+}
+
+/* ioctl(VIDIOC_TRY_FMT) */
+static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ return -EINVAL;
+ }
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ break;
+ case V4L2_PIX_FMT_PWC1:
+ if (DEVICE_USE_CODEC23(pdev->type)) {
+ PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_PIX_FMT_PWC2:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+ PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ PWC_DEBUG_IOCTL("Unsupported pixel format\n");
+ return -EINVAL;
+
+ }
+
+ if (f->fmt.pix.width > pdev->view_max.x)
+ f->fmt.pix.width = pdev->view_max.x;
+ else if (f->fmt.pix.width < pdev->view_min.x)
+ f->fmt.pix.width = pdev->view_min.x;
+
+ if (f->fmt.pix.height > pdev->view_max.y)
+ f->fmt.pix.height = pdev->view_max.y;
+ else if (f->fmt.pix.height < pdev->view_min.y)
+ f->fmt.pix.height = pdev->view_min.y;
+
+ return 0;
+}
+
+/* ioctl(VIDIOC_SET_FMT) */
+static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+ int ret, fps, snapshot, compression, pixelformat;
+
+ ret = pwc_vidioc_try_fmt(pdev, f);
+ if (ret<0)
+ return ret;
+
+ pixelformat = f->fmt.pix.pixelformat;
+ compression = pdev->vcompression;
+ snapshot = 0;
+ fps = pdev->vframes;
+ if (f->fmt.pix.priv) {
+ compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
+ snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
+ fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+ if (fps == 0)
+ fps = pdev->vframes;
+ }
+
+ if (pixelformat == V4L2_PIX_FMT_YUV420)
+ pdev->vpalette = VIDEO_PALETTE_YUV420P;
+ else
+ pdev->vpalette = VIDEO_PALETTE_RAW;
+
+ PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+ "compression=%d snapshot=%d format=%c%c%c%c\n",
+ f->fmt.pix.width, f->fmt.pix.height, fps,
+ compression, snapshot,
+ (pixelformat)&255,
+ (pixelformat>>8)&255,
+ (pixelformat>>16)&255,
+ (pixelformat>>24)&255);
+
+ ret = pwc_try_video_mode(pdev,
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ fps,
+ compression,
+ snapshot);
+
+ PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+
+ if (ret)
+ return ret;
+
+ pwc_vidioc_fill_fmt(pdev, f);
+
+ return 0;
+
+}
+
+int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct pwc_device *pdev;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (vdev == NULL)
+ return -EFAULT;
+ pdev = vdev->priv;
+ if (pdev == NULL)
+ return -EFAULT;
+
+#if CONFIG_PWC_DEBUG
+ if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+ v4l_printk_ioctl(cmd);
+#endif
+
+
+ switch (cmd) {
+ /* Query cabapilities */
+ case VIDIOCGCAP:
+ {
+ struct video_capability *caps = arg;
+
+ strcpy(caps->name, vdev->name);
+ caps->type = VID_TYPE_CAPTURE;
+ caps->channels = 1;
+ caps->audios = 1;
+ caps->minwidth = pdev->view_min.x;
+ caps->minheight = pdev->view_min.y;
+ caps->maxwidth = pdev->view_max.x;
+ caps->maxheight = pdev->view_max.y;
+ break;
+ }
+
+ /* Channel functions (simulate 1 channel) */
+ case VIDIOCGCHAN:
+ {
+ struct video_channel *v = arg;
+
+ if (v->channel != 0)
+ return -EINVAL;
+ v->flags = 0;
+ v->tuners = 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ strcpy(v->name, "Webcam");
+ return 0;
+ }
+
+ case VIDIOCSCHAN:
+ {
+ /* The spec says the argument is an integer, but
+ the bttv driver uses a video_channel arg, which
+ makes sense becasue it also has the norm flag.
+ */
+ struct video_channel *v = arg;
+ if (v->channel != 0)
+ return -EINVAL;
+ return 0;
+ }
+
+
+ /* Picture functions; contrast etc. */
+ case VIDIOCGPICT:
+ {
+ struct video_picture *p = arg;
+ int val;
+
+ val = pwc_get_brightness(pdev);
+ if (val >= 0)
+ p->brightness = (val<<9);
+ else
+ p->brightness = 0xffff;
+ val = pwc_get_contrast(pdev);
+ if (val >= 0)
+ p->contrast = (val<<10);
+ else
+ p->contrast = 0xffff;
+ /* Gamma, Whiteness, what's the difference? :) */
+ val = pwc_get_gamma(pdev);
+ if (val >= 0)
+ p->whiteness = (val<<11);
+ else
+ p->whiteness = 0xffff;
+ if (pwc_get_saturation(pdev, &val)<0)
+ p->colour = 0xffff;
+ else
+ p->colour = 32768 + val * 327;
+ p->depth = 24;
+ p->palette = pdev->vpalette;
+ p->hue = 0xFFFF; /* N/A */
+ break;
+ }
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture *p = arg;
+ /*
+ * FIXME: Suppose we are mid read
+ ANSWER: No problem: the firmware of the camera
+ can handle brightness/contrast/etc
+ changes at _any_ time, and the palette
+ is used exactly once in the uncompress
+ routine.
+ */
+ pwc_set_brightness(pdev, p->brightness);
+ pwc_set_contrast(pdev, p->contrast);
+ pwc_set_gamma(pdev, p->whiteness);
+ pwc_set_saturation(pdev, (p->colour-32768)/327);
+ if (p->palette && p->palette != pdev->vpalette) {
+ switch (p->palette) {
+ case VIDEO_PALETTE_YUV420P:
+ case VIDEO_PALETTE_RAW:
+ pdev->vpalette = p->palette;
+ return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+ break;
+ }
+
+ /* Window/size parameters */
+ case VIDIOCGWIN:
+ {
+ struct video_window *vw = arg;
+
+ vw->x = 0;
+ vw->y = 0;
+ vw->width = pdev->view.x;
+ vw->height = pdev->view.y;
+ vw->chromakey = 0;
+ vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+ (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+ break;
+ }
+
+ case VIDIOCSWIN:
+ {
+ struct video_window *vw = arg;
+ int fps, snapshot, ret;
+
+ fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+ snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+ if (fps == 0)
+ fps = pdev->vframes;
+ if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+ return 0;
+ ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ /* We don't have overlay support (yet) */
+ case VIDIOCGFBUF:
+ {
+ struct video_buffer *vb = arg;
+
+ memset(vb,0,sizeof(*vb));
+ break;
+ }
+
+ /* mmap() functions */
+ case VIDIOCGMBUF:
+ {
+ /* Tell the user program how much memory is needed for a mmap() */
+ struct video_mbuf *vm = arg;
+ int i;
+
+ memset(vm, 0, sizeof(*vm));
+ vm->size = pwc_mbufs * pdev->len_per_image;
+ vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
+ for (i = 0; i < pwc_mbufs; i++)
+ vm->offsets[i] = i * pdev->len_per_image;
+ break;
+ }
+
+ case VIDIOCMCAPTURE:
+ {
+ /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+ struct video_mmap *vm = arg;
+
+ PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+ if (vm->frame < 0 || vm->frame >= pwc_mbufs)
+ return -EINVAL;
+
+ /* xawtv is nasty. It probes the available palettes
+ by setting a very small image size and trying
+ various palettes... The driver doesn't support
+ such small images, so I'm working around it.
+ */
+ if (vm->format)
+ {
+ switch (vm->format)
+ {
+ case VIDEO_PALETTE_YUV420P:
+ case VIDEO_PALETTE_RAW:
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+
+ if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+ (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+ int ret;
+
+ PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+ ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+ if (ret)
+ return ret;
+ } /* ... size mismatch */
+
+ /* FIXME: should we lock here? */
+ if (pdev->image_used[vm->frame])
+ return -EBUSY; /* buffer wasn't available. Bummer */
+ pdev->image_used[vm->frame] = 1;
+
+ /* Okay, we're done here. In the SYNC call we wait until a
+ frame comes available, then expand image into the given
+ buffer.
+ In contrast to the CPiA cam the Philips cams deliver a
+ constant stream, almost like a grabber card. Also,
+ we have separate buffers for the rawdata and the image,
+ meaning we can nearly always expand into the requested buffer.
+ */
+ PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
+ break;
+ }
+
+ case VIDIOCSYNC:
+ {
+ /* The doc says: "Whenever a buffer is used it should
+ call VIDIOCSYNC to free this frame up and continue."
+
+ The only odd thing about this whole procedure is
+ that MCAPTURE flags the buffer as "in use", and
+ SYNC immediately unmarks it, while it isn't
+ after SYNC that you know that the buffer actually
+ got filled! So you better not start a CAPTURE in
+ the same frame immediately (use double buffering).
+ This is not a problem for this cam, since it has
+ extra intermediate buffers, but a hardware
+ grabber card will then overwrite the buffer
+ you're working on.
+ */
+ int *mbuf = arg;
+ int ret;
+
+ PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
+
+ /* bounds check */
+ if (*mbuf < 0 || *mbuf >= pwc_mbufs)
+ return -EINVAL;
+ /* check if this buffer was requested anyway */
+ if (pdev->image_used[*mbuf] == 0)
+ return -EINVAL;
+
+ /* Add ourselves to the frame wait-queue.
+
+ FIXME: needs auditing for safety.
+ QUESTION: In what respect? I think that using the
+ frameq is safe now.
+ */
+ add_wait_queue(&pdev->frameq, &wait);
+ while (pdev->full_frames == NULL) {
+ /* Check for unplugged/etc. here */
+ if (pdev->error_status) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -pdev->error_status;
+ }
+
+ if (signal_pending(current)) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -ERESTARTSYS;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ /* The frame is ready. Expand in the image buffer
+ requested by the user. I don't care if you
+ mmap() 5 buffers and request data in this order:
+ buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+ Grabber hardware may not be so forgiving.
+ */
+ PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
+ pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+ /* Decompress, etc */
+ ret = pwc_handle_frame(pdev);
+ pdev->image_used[*mbuf] = 0;
+ if (ret)
+ return -EFAULT;
+ break;
+ }
+
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *v = arg;
+
+ strcpy(v->name, "Microphone");
+ v->audio = -1; /* unknown audio minor */
+ v->flags = 0;
+ v->mode = VIDEO_SOUND_MONO;
+ v->volume = 0;
+ v->bass = 0;
+ v->treble = 0;
+ v->balance = 0x8000;
+ v->step = 1;
+ break;
+ }
+
+ case VIDIOCSAUDIO:
+ {
+ /* Dummy: nothing can be set */
+ break;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit *vu = arg;
+
+ vu->video = pdev->vdev->minor & 0x3F;
+ vu->audio = -1; /* not known yet */
+ vu->vbi = -1;
+ vu->radio = -1;
+ vu->teletext = -1;
+ break;
+ }
+
+ /* V4L2 Layer */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
+ "try to use the v4l2 layer\n");
+ strcpy(cap->driver,PWC_NAME);
+ strlcpy(cap->card, vdev->name, sizeof(cap->card));
+ usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
+ cap->version = PWC_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ return 0;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+
+ if ( i->index ) /* Only one INPUT is supported */
+ return -EINVAL;
+
+ memset(i, 0, sizeof(struct v4l2_input));
+ strcpy(i->name, "usb");
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ int *i = arg;
+ *i = 0; /* Only one INPUT is supported */
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int *i = arg;
+
+ if ( *i ) { /* Only one INPUT is supported */
+ PWC_DEBUG_IOCTL("Only one input source is"\
+ " supported with this webcam.\n");
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ /* TODO: */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *c = arg;
+ int i;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
+ for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
+ if (pwc_controls[i].id == c->id) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+ memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
+ return 0;
+ }
+ }
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *c = arg;
+ int ret;
+
+ switch (c->id)
+ {
+ case V4L2_CID_BRIGHTNESS:
+ c->value = pwc_get_brightness(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_CONTRAST:
+ c->value = pwc_get_contrast(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_SATURATION:
+ ret = pwc_get_saturation(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAMMA:
+ c->value = pwc_get_gamma(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ ret = pwc_get_red_gain(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = pwc_get_blue_gain(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = pwc_get_awb(pdev);
+ if (ret<0)
+ return -EINVAL;
+ c->value = (ret == PWC_WB_MANUAL)?0:1;
+ return 0;
+ case V4L2_CID_GAIN:
+ ret = pwc_get_agc(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ ret = pwc_get_agc(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value = (c->value < 0)?1:0;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ ret = pwc_get_shutter_speed(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
+ ret = pwc_get_colour_mode(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
+ ret = pwc_get_contour(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value=(c->value == -1?1:0);
+ return 0;
+ case V4L2_CID_PRIVATE_CONTOUR:
+ ret = pwc_get_contour(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value >>= 10;
+ return 0;
+ case V4L2_CID_PRIVATE_BACKLIGHT:
+ ret = pwc_get_backlight(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_FLICKERLESS:
+ ret = pwc_get_flicker(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value=(c->value?1:0);
+ return 0;
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+ ret = pwc_get_dynamic_noise(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CID_PRIVATE_SAVE_USER:
+ case V4L2_CID_PRIVATE_RESTORE_USER:
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+ return -EINVAL;
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *c = arg;
+ int ret;
+
+ switch (c->id)
+ {
+ case V4L2_CID_BRIGHTNESS:
+ c->value <<= 9;
+ ret = pwc_set_brightness(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_CONTRAST:
+ c->value <<= 10;
+ ret = pwc_set_contrast(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_SATURATION:
+ ret = pwc_set_saturation(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAMMA:
+ c->value <<= 11;
+ ret = pwc_set_gamma(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ c->value <<= 8;
+ ret = pwc_set_red_gain(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ c->value <<= 8;
+ ret = pwc_set_blue_gain(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
+ ret = pwc_set_awb(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ c->value <<= 8;
+ ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ /* autogain off means nothing without a gain */
+ if (c->value == 0)
+ return 0;
+ ret = pwc_set_agc(pdev, c->value, 0);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAIN:
+ c->value <<= 8;
+ ret = pwc_set_agc(pdev, 0, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_SAVE_USER:
+ if (pwc_save_user(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_RESTORE_USER:
+ if (pwc_restore_user(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+ if (pwc_restore_factory(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
+ ret = pwc_set_colour_mode(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
+ c->value=(c->value == 1)?-1:0;
+ ret = pwc_set_contour(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_CONTOUR:
+ c->value <<= 10;
+ ret = pwc_set_contour(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_BACKLIGHT:
+ ret = pwc_set_backlight(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_FLICKERLESS:
+ ret = pwc_set_flicker(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+ ret = pwc_set_dynamic_noise(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ int index;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* We only support two format: the raw format, and YUV */
+ index = f->index;
+ memset(f,0,sizeof(struct v4l2_fmtdesc));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->index = index;
+ switch(index)
+ {
+ case 0:
+ /* RAW format */
+ f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
+ break;
+ case 1:
+ f->pixelformat = V4L2_PIX_FMT_YUV420;
+ strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ pwc_vidioc_fill_fmt(pdev, f);
+
+ return 0;
+ }
+
+ case VIDIOC_TRY_FMT:
+ return pwc_vidioc_try_fmt(pdev, arg);
+
+ case VIDIOC_S_FMT:
+ return pwc_vidioc_set_fmt(pdev, arg);
+
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *std = arg;
+ *std = V4L2_STD_UNKNOWN;
+ return 0;
+ }
+
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *std = arg;
+ if (*std != V4L2_STD_UNKNOWN)
+ return -EINVAL;
+ return 0;
+ }
+
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *std = arg;
+ if (std->index != 0)
+ return -EINVAL;
+ std->id = V4L2_STD_UNKNOWN;
+ strncpy(std->name, "webcam", sizeof(std->name));
+ return 0;
+ }
+
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ int nbuffers;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ nbuffers = rb->count;
+ if (nbuffers < 2)
+ nbuffers = 2;
+ else if (nbuffers > pwc_mbufs)
+ nbuffers = pwc_mbufs;
+ /* Force to use our # of buffers */
+ rb->count = pwc_mbufs;
+ return 0;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ int index;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+ return -EINVAL;
+ }
+ if (buf->memory != V4L2_MEMORY_MMAP) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
+ return -EINVAL;
+ }
+ index = buf->index;
+ if (index < 0 || index >= pwc_mbufs) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+ return -EINVAL;
+ }
+
+ memset(buf, 0, sizeof(struct v4l2_buffer));
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->index = index;
+ buf->m.offset = index * pdev->len_per_image;
+ if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ else
+ buf->bytesused = pdev->view.size;
+ buf->field = V4L2_FIELD_NONE;
+ buf->memory = V4L2_MEMORY_MMAP;
+ //buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->length = pdev->len_per_image;
+
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+
+ return 0;
+ }
+
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ if (buf->index < 0 || buf->index >= pwc_mbufs)
+ return -EINVAL;
+
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ return 0;
+ }
+
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ int ret;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* Add ourselves to the frame wait-queue.
+
+ FIXME: needs auditing for safety.
+ QUESTION: In what respect? I think that using the
+ frameq is safe now.
+ */
+ add_wait_queue(&pdev->frameq, &wait);
+ while (pdev->full_frames == NULL) {
+ if (pdev->error_status) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -pdev->error_status;
+ }
+
+ if (signal_pending(current)) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -ERESTARTSYS;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+ /* Decompress data in pdev->images[pdev->fill_image] */
+ ret = pwc_handle_frame(pdev);
+ if (ret)
+ return -EFAULT;
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+ buf->index = pdev->fill_image;
+ if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ else
+ buf->bytesused = pdev->view.size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->field = V4L2_FIELD_NONE;
+ do_gettimeofday(&buf->timestamp);
+ buf->sequence = 0;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = pdev->fill_image * pdev->len_per_image;
+ buf->length = buf->bytesused;
+ pwc_next_image(pdev);
+
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+ return 0;
+
+ }
+
+ case VIDIOC_STREAMON:
+ {
+ /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
+ pwc_isoc_init(pdev);
+ return 0;
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ pwc_isoc_cleanup(pdev);
+ return 0;
+ }
+
+ default:
+ return pwc_ioctl(pdev, cmd, arg);
+ } /* ..switch */
+ return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index 1b0ee0ced0e..7e9c4237d1e 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -1,5 +1,5 @@
/* (C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
@@ -25,55 +25,90 @@
#ifndef PWC_H
#define PWC_H
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spinlock.h>
-#include <linux/videodev.h>
#include <linux/wait.h>
#include <linux/smp_lock.h>
+#include <linux/version.h>
#include <asm/semaphore.h>
#include <asm/errno.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
+#include <media/pwc-ioctl.h>
/* Turn some debugging options on/off */
-#define PWC_DEBUG 0
+#ifndef CONFIG_PWC_DEBUG
+#define CONFIG_PWC_DEBUG 1
+#endif
+
+/* Version block */
+#define PWC_MAJOR 10
+#define PWC_MINOR 0
+#define PWC_EXTRAMINOR 12
+#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
+#define PWC_VERSION "10.0.12"
+#define PWC_NAME "pwc"
+#define PFX PWC_NAME ": "
+
/* Trace certain actions in the driver */
-#define TRACE_MODULE 0x0001
-#define TRACE_PROBE 0x0002
-#define TRACE_OPEN 0x0004
-#define TRACE_READ 0x0008
-#define TRACE_MEMORY 0x0010
-#define TRACE_FLOW 0x0020
-#define TRACE_SIZE 0x0040
-#define TRACE_PWCX 0x0080
-#define TRACE_SEQUENCE 0x1000
-
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...) printk(KERN_INFO PWC_NAME " " A)
-#define Err(A...) printk(KERN_ERR PWC_NAME " " A)
+#define PWC_DEBUG_LEVEL_MODULE (1<<0)
+#define PWC_DEBUG_LEVEL_PROBE (1<<1)
+#define PWC_DEBUG_LEVEL_OPEN (1<<2)
+#define PWC_DEBUG_LEVEL_READ (1<<3)
+#define PWC_DEBUG_LEVEL_MEMORY (1<<4)
+#define PWC_DEBUG_LEVEL_FLOW (1<<5)
+#define PWC_DEBUG_LEVEL_SIZE (1<<6)
+#define PWC_DEBUG_LEVEL_IOCTL (1<<7)
+#define PWC_DEBUG_LEVEL_TRACE (1<<8)
+
+#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
+#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
+#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args)
+#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args)
+#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args)
+#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args)
+#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args)
+#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args)
+#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+
+#if CONFIG_PWC_DEBUG
+
+#define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE)
+
+#define PWC_DEBUG(level, fmt, args...) do {\
+ if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+ printk(KERN_DEBUG PFX fmt, ##args); \
+ } while(0)
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+#else /* if ! CONFIG_PWC_DEBUG */
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) do { } while(0)
+#define PWC_DEBUG(level, fmt, args...) do { } while(0)
+
+#define pwc_trace 0
+#endif
/* Defines for ToUCam cameras */
#define TOUCAM_HEADER_SIZE 8
#define TOUCAM_TRAILER_SIZE 4
#define FEATURE_MOTOR_PANTILT 0x0001
-
-/* Version block */
-#define PWC_MAJOR 9
-#define PWC_MINOR 0
-#define PWC_VERSION "9.0.2-unofficial"
-#define PWC_NAME "pwc"
+#define FEATURE_CODEC1 0x0002
+#define FEATURE_CODEC2 0x0004
/* Turn certain features on/off */
#define PWC_INT_PIPE 0
@@ -95,6 +130,18 @@
/* Absolute maximum number of buffers available for mmap() */
#define MAX_IMAGES 10
+/* Some macros to quickly find the type of a webcam */
+#define DEVICE_USE_CODEC1(x) ((x)<675)
+#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700)
+#define DEVICE_USE_CODEC3(x) ((x)>=700)
+#define DEVICE_USE_CODEC23(x) ((x)>=675)
+
+
+#ifndef V4L2_PIX_FMT_PWC1
+#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1')
+#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2')
+#endif
+
/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct pwc_iso_buf
{
@@ -110,17 +157,19 @@ struct pwc_frame_buf
void *data;
volatile int filled; /* number of bytes filled */
struct pwc_frame_buf *next; /* list */
-#if PWC_DEBUG
- int sequence; /* Sequence number */
-#endif
+};
+
+/* additionnal informations used when dealing image between kernel and userland */
+struct pwc_imgbuf
+{
+ unsigned long offset; /* offset of this buffer in the big array of image_data */
+ int vma_use_count; /* count the number of time this memory is mapped */
};
struct pwc_device
{
struct video_device *vdev;
-#ifdef PWC_MAGIC
- int magic;
-#endif
+
/* Pointer to our usb_device */
struct usb_device *udev;
@@ -177,12 +226,8 @@ struct pwc_device
int frame_size;
int frame_total_size; /* including header & trailer */
int drop_frames;
-#if PWC_DEBUG
- int sequence; /* Debugging aid */
-#endif
/* 3: decompression */
- struct pwc_decompressor *decompressor; /* function block with decompression routines */
void *decompress_data; /* private data for decompression engine */
/* 4: image */
@@ -198,7 +243,7 @@ struct pwc_device
struct pwc_coord offset; /* offset within the viewport */
void *image_data; /* total buffer, which is subdivided into ... */
- void *image_ptr[MAX_IMAGES]; /* ...several images... */
+ struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */
int fill_image; /* ...which are rotated. */
int len_per_image; /* length per image */
int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */
@@ -211,6 +256,7 @@ struct pwc_device
struct pwc_mpt_range angle_range;
int pan_angle; /* in degrees * 100 */
int tilt_angle; /* absolute angle; 0,0 is home position */
+ int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */
/*** Misc. data ***/
wait_queue_head_t frameq; /* When waiting for a frame to finish... */
@@ -219,20 +265,26 @@ struct pwc_device
#endif
};
-
#ifdef __cplusplus
extern "C" {
#endif
-/* Global variable */
+/* Global variables */
+#if CONFIG_PWC_DEBUG
extern int pwc_trace;
+#endif
+extern int pwc_mbufs;
/** functions in pwc-if.c */
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+int pwc_handle_frame(struct pwc_device *pdev);
+void pwc_next_image(struct pwc_device *pdev);
+int pwc_isoc_init(struct pwc_device *pdev);
+void pwc_isoc_cleanup(struct pwc_device *pdev);
/** Functions in pwc-misc.c */
/* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
int pwc_decode_size(struct pwc_device *pdev, int width, int height);
void pwc_construct(struct pwc_device *pdev);
@@ -240,6 +292,9 @@ void pwc_construct(struct pwc_device *pdev);
/** Functions in pwc-ctrl.c */
/* Request a certain video mode. Returns < 0 if not possible */
extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+/* Calculate the number of bytes per image (not frame) */
+extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
+extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
extern int pwc_get_brightness(struct pwc_device *pdev);
@@ -248,10 +303,36 @@ extern int pwc_get_contrast(struct pwc_device *pdev);
extern int pwc_set_contrast(struct pwc_device *pdev, int value);
extern int pwc_get_gamma(struct pwc_device *pdev);
extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
extern int pwc_set_saturation(struct pwc_device *pdev, int value);
extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+extern int pwc_restore_user(struct pwc_device *pdev);
+extern int pwc_save_user(struct pwc_device *pdev);
+extern int pwc_restore_factory(struct pwc_device *pdev);
+
+/* exported for use by v4l2 controls */
+extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_awb(struct pwc_device *pdev);
+extern int pwc_set_awb(struct pwc_device *pdev, int mode);
+extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_agc(struct pwc_device *pdev, int *value);
+extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
+
+extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
+extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
+extern int pwc_set_contour(struct pwc_device *pdev, int contour);
+extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
+extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
+extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
+extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
+extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
+extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
+extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
/* Power down or up the camera; not supported by all models */
extern int pwc_camera_power(struct pwc_device *pdev, int power);
@@ -259,6 +340,9 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power);
/* Private ioctl()s; see pwc-ioctl.h */
extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+/** Functions in pwc-v4l.c */
+extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
/** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
@@ -270,3 +354,4 @@ extern int pwc_decompress(struct pwc_device *pdev);
#endif
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index dd830e0e5e9..59a187272c8 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -46,6 +46,7 @@
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include "saa5246a.h"
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 531e9461cb6..19a8d65699f 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -56,6 +56,7 @@
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 41d951db6ec..676b9970eb2 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -43,6 +43,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
static int debug = 0;
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index dceebc0b125..b59c1171727 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -72,6 +72,10 @@ struct saa7115_state {
int sat;
enum v4l2_chip_ident ident;
u32 audclk_freq;
+ u32 crystal_freq;
+ u8 ucgc;
+ u8 cgcdiv;
+ u8 apll;
};
/* ----------------------------------------------------------------------- */
@@ -375,10 +379,6 @@ static const unsigned char saa7113_init_auto_input[] = {
};
static const unsigned char saa7115_init_misc[] = {
- 0x38, 0x03, /* audio stuff */
- 0x39, 0x10,
- 0x3a, 0x08,
-
0x81, 0x01, /* reg 0x15,0x16 define blanking window */
0x82, 0x00,
0x83, 0x01, /* I port settings */
@@ -584,6 +584,7 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
u32 acni;
u32 hz;
u64 f;
+ u8 acc = 0; /* reg 0x3a, audio clock control */
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
@@ -591,18 +592,34 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
if (freq < 32000 || freq > 48000)
return -EINVAL;
+ /* The saa7113 has no audio clock */
+ if (state->ident == V4L2_IDENT_SAA7113)
+ return 0;
+
/* hz is the refresh rate times 100 */
hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
acpf = (25600 * freq) / hz;
/* acni = (256 * freq * 2^23) / crystal_frequency =
(freq * 2^(8+23)) / crystal_frequency =
- (freq << 31) / 32.11 MHz */
+ (freq << 31) / crystal_frequency */
f = freq;
f = f << 31;
- do_div(f, 32110000);
+ do_div(f, state->crystal_freq);
acni = f;
+ if (state->ucgc) {
+ acpf = acpf * state->cgcdiv / 16;
+ acni = acni * state->cgcdiv / 16;
+ acc = 0x80;
+ if (state->cgcdiv == 3)
+ acc |= 0x40;
+ }
+ if (state->apll)
+ acc |= 0x08;
+ saa7115_write(client, 0x38, 0x03);
+ saa7115_write(client, 0x39, 0x10);
+ saa7115_write(client, 0x3a, acc);
saa7115_write(client, 0x30, acpf & 0xff);
saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
@@ -1073,48 +1090,6 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
/* ============ SAA7115 AUDIO settings (end) ============= */
-static struct v4l2_queryctrl saa7115_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
-};
-
-/* ----------------------------------------------------------------------- */
-
static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa7115_state *state = i2c_get_clientdata(client);
@@ -1158,14 +1133,16 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
- if (qc->id && qc->id == saa7115_qctrl[i].id) {
- memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
}
case VIDIOC_G_STD:
@@ -1221,34 +1198,6 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
break;
}
- case VIDIOC_G_INPUT:
- *(int *)arg = state->input;
- break;
-
- case VIDIOC_S_INPUT:
- v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg);
- /* inputs from 0-9 are available */
- if (*iarg < 0 || *iarg > 9) {
- return -EINVAL;
- }
-
- if (state->input == *iarg)
- break;
- v4l_dbg(1, debug, client, "now setting %s input\n",
- *iarg >= 6 ? "S-Video" : "Composite");
- state->input = *iarg;
-
- /* select mode */
- saa7115_write(client, 0x02,
- (saa7115_read(client, 0x02) & 0xf0) |
- state->input);
-
- /* bypass chrominance trap for modes 6..9 */
- saa7115_write(client, 0x09,
- (saa7115_read(client, 0x09) & 0x7f) |
- (state->input < 6 ? 0x0 : 0x80));
- break;
-
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
v4l_dbg(1, debug, client, "%s output\n",
@@ -1260,6 +1209,21 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
}
break;
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *freq = arg;
+
+ if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+ freq->freq != SAA7115_FREQ_24_576_MHZ)
+ return -EINVAL;
+ state->crystal_freq = freq->freq;
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
+ break;
+ }
+
case VIDIOC_INT_DECODE_VBI_LINE:
saa7115_decode_vbi_line(client, arg);
break;
@@ -1401,10 +1365,13 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
v4l_dbg(1, debug, client, "writing init values\n");
/* init to 60hz/48khz */
- if (state->ident == V4L2_IDENT_SAA7113)
+ if (state->ident == V4L2_IDENT_SAA7113) {
+ state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
saa7115_writeregs(client, saa7113_init_auto_input);
- else
+ } else {
+ state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
saa7115_writeregs(client, saa7115_init_auto_input);
+ }
saa7115_writeregs(client, saa7115_init_misc);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index c271e2e1410..ad401bdefea 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -270,7 +270,7 @@ static const char * const wss_strs[] = {
"letterbox 16:9 top",
"invalid",
"invalid",
- "16:9 full format anamorphic"
+ "16:9 full format anamorphic",
"4:3 full format",
"invalid",
"invalid",
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index e1c1805df1f..f5543166d19 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -40,6 +40,7 @@ config VIDEO_SAA7134_DVB
depends on VIDEO_SAA7134 && DVB_CORE
select VIDEO_BUF_DVB
select FW_LOADER
+ select DVB_PLL
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 0e0ba50946e..afc8f352b8e 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -39,6 +39,23 @@ enum saa6752hs_videoformat {
SAA6752HS_VF_UNKNOWN,
};
+struct saa6752hs_mpeg_params {
+ /* transport streams */
+ __u16 ts_pid_pmt;
+ __u16 ts_pid_audio;
+ __u16 ts_pid_video;
+ __u16 ts_pid_pcr;
+
+ /* audio */
+ enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+
+ /* video */
+ enum v4l2_mpeg_video_aspect vi_aspect;
+ enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
+ __u32 vi_bitrate;
+ __u32 vi_bitrate_peak;
+};
+
static const struct v4l2_format v4l2_format_table[] =
{
[SAA6752HS_VF_D1] =
@@ -55,18 +72,19 @@ static const struct v4l2_format v4l2_format_table[] =
struct saa6752hs_state {
struct i2c_client client;
- struct v4l2_mpeg_compression params;
+ struct v4l2_mpeg_compression old_params;
+ struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format;
v4l2_std_id standard;
};
enum saa6752hs_command {
SAA6752HS_COMMAND_RESET = 0,
- SAA6752HS_COMMAND_STOP = 1,
- SAA6752HS_COMMAND_START = 2,
- SAA6752HS_COMMAND_PAUSE = 3,
- SAA6752HS_COMMAND_RECONFIGURE = 4,
- SAA6752HS_COMMAND_SLEEP = 5,
+ SAA6752HS_COMMAND_STOP = 1,
+ SAA6752HS_COMMAND_START = 2,
+ SAA6752HS_COMMAND_PAUSE = 3,
+ SAA6752HS_COMMAND_RECONFIGURE = 4,
+ SAA6752HS_COMMAND_SLEEP = 5,
SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
SAA6752HS_COMMAND_MAX
@@ -129,7 +147,22 @@ static u8 PMT[] = {
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
-static struct v4l2_mpeg_compression param_defaults =
+static struct saa6752hs_mpeg_params param_defaults =
+{
+ .ts_pid_pmt = 16,
+ .ts_pid_video = 260,
+ .ts_pid_audio = 256,
+ .ts_pid_pcr = 259,
+
+ .vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .vi_bitrate = 4000,
+ .vi_bitrate_peak = 6000,
+ .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+
+ .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+};
+
+static struct v4l2_mpeg_compression old_param_defaults =
{
.st_type = V4L2_MPEG_TS_2,
.st_bitrate = {
@@ -228,45 +261,57 @@ static int saa6752hs_chip_command(struct i2c_client* client,
static int saa6752hs_set_bitrate(struct i2c_client* client,
- struct v4l2_mpeg_compression* params)
+ struct saa6752hs_mpeg_params* params)
{
u8 buf[3];
+ int tot_bitrate;
/* set the bitrate mode */
buf[0] = 0x71;
- buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
+ buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
i2c_master_send(client, buf, 2);
/* set the video bitrate */
- if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
+ if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
/* set the target bitrate */
buf[0] = 0x80;
- buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[1] = params->vi_bitrate >> 8;
+ buf[2] = params->vi_bitrate & 0xff;
i2c_master_send(client, buf, 3);
/* set the max bitrate */
buf[0] = 0x81;
- buf[1] = params->vi_bitrate.max >> 8;
- buf[2] = params->vi_bitrate.max & 0xff;
+ buf[1] = params->vi_bitrate_peak >> 8;
+ buf[2] = params->vi_bitrate_peak & 0xff;
i2c_master_send(client, buf, 3);
+ tot_bitrate = params->vi_bitrate_peak;
} else {
/* 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[1] = params->vi_bitrate >> 8;
+ buf[2] = params->vi_bitrate & 0xff;
i2c_master_send(client, buf, 3);
+ tot_bitrate = params->vi_bitrate;
}
/* set the audio bitrate */
buf[0] = 0x94;
- buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
+ buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
i2c_master_send(client, buf, 2);
+ tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+
+ /* Note: the total max bitrate is determined by adding the video and audio
+ bitrates together and also adding an extra 768kbit/s to stay on the
+ safe side. If more control should be required, then an extra MPEG control
+ should be added. */
+ tot_bitrate += 768;
+ if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
+ tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
/* set the total bitrate */
buf[0] = 0xb1;
- buf[1] = params->st_bitrate.target >> 8;
- buf[2] = params->st_bitrate.target & 0xff;
+ buf[1] = tot_bitrate >> 8;
+ buf[2] = tot_bitrate & 0xff;
i2c_master_send(client, buf, 3);
return 0;
@@ -318,50 +363,188 @@ static void saa6752hs_set_subsampling(struct i2c_client* client,
}
-static void saa6752hs_set_params(struct i2c_client* client,
+static void saa6752hs_old_set_params(struct i2c_client* client,
struct v4l2_mpeg_compression* params)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
/* check PIDs */
- if (params->ts_pid_pmt <= MPEG_PID_MAX)
+ if (params->ts_pid_pmt <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_pmt = params->ts_pid_pmt;
h->params.ts_pid_pmt = params->ts_pid_pmt;
- if (params->ts_pid_pcr <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_pcr <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_pcr = params->ts_pid_pcr;
h->params.ts_pid_pcr = params->ts_pid_pcr;
- if (params->ts_pid_video <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_video <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_video = params->ts_pid_video;
h->params.ts_pid_video = params->ts_pid_video;
- if (params->ts_pid_audio <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_audio <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_audio = params->ts_pid_audio;
h->params.ts_pid_audio = params->ts_pid_audio;
+ }
/* check bitrate parameters */
if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
- (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
- h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+ (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
+ h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
+ h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.st_bitrate.target = params->st_bitrate.target;
+ h->old_params.st_bitrate.target = params->st_bitrate.target;
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.vi_bitrate.target = params->vi_bitrate.target;
+ h->old_params.vi_bitrate.target = params->vi_bitrate.target;
if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
- h->params.vi_bitrate.max = params->vi_bitrate.max;
+ h->old_params.vi_bitrate.max = params->vi_bitrate.max;
if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.au_bitrate.target = params->au_bitrate.target;
+ h->old_params.au_bitrate.target = params->au_bitrate.target;
/* aspect ratio */
if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
- params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
- h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+ params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
+ h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
+ if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
+ h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ else
+ h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
+ }
/* range checks */
- if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
- h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
- if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
- h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
- if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
- h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
- if (h->params.au_bitrate.target <= 256)
- h->params.au_bitrate.target = 256;
+ if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+ h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+ if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+ h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+ if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+ h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+ h->params.vi_bitrate = params->vi_bitrate.target;
+ h->params.vi_bitrate_peak = params->vi_bitrate.max;
+ if (h->old_params.au_bitrate.target <= 256) {
+ h->old_params.au_bitrate.target = 256;
+ h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+ }
+ else {
+ h->old_params.au_bitrate.target = 384;
+ h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+ }
+}
+
+static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+ struct v4l2_ext_control *ctrl, unsigned int cmd)
+{
+ int old = 0, new;
+ int set = (cmd == VIDIOC_S_EXT_CTRLS);
+
+ new = ctrl->value;
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ old = params->ts_pid_pmt;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_pmt = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ old = params->ts_pid_audio;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_audio = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ old = params->ts_pid_video;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_video = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ old = params->ts_pid_pcr;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_pcr = new;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ old = params->au_l2_bitrate;
+ if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+ new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+ return -ERANGE;
+ if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+ new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+ else
+ new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+ params->au_l2_bitrate = new;
+ break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ old = params->vi_aspect;
+ if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+ new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+ return -ERANGE;
+ if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+ new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ params->vi_aspect = new;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ old = params->vi_bitrate * 1000;
+ new = 1000 * (new / 1000);
+ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ return -ERANGE;
+ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+ params->vi_bitrate = new / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ old = params->vi_bitrate_peak * 1000;
+ new = 1000 * (new / 1000);
+ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ return -ERANGE;
+ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+ params->vi_bitrate_peak = new / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ old = params->vi_bitrate_mode;
+ params->vi_bitrate_mode = new;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (cmd == VIDIOC_G_EXT_CTRLS)
+ ctrl->value = old;
else
- h->params.au_bitrate.target = 384;
+ ctrl->value = new;
+ return 0;
}
static int saa6752hs_init(struct i2c_client* client)
@@ -395,22 +578,22 @@ static int saa6752hs_init(struct i2c_client* client)
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);
@@ -441,7 +624,7 @@ 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;
@@ -489,11 +672,11 @@ static int saa6752hs_init(struct i2c_client* client)
buf[3] = 0x82;
buf[4] = 0xB0;
buf[5] = buf2[0];
- switch(h->params.vi_aspect_ratio) {
- case V4L2_MPEG_ASPECT_16_9:
+ switch(h->params.vi_aspect) {
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
buf[6] = buf2[1] | 0x40;
break;
- case V4L2_MPEG_ASPECT_4_3:
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
default:
buf[6] = buf2[1] & 0xBF;
break;
@@ -515,6 +698,7 @@ static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind)
return -ENOMEM;
h->client = client_template;
h->params = param_defaults;
+ h->old_params = old_param_defaults;
h->client.adapter = adap;
h->client.addr = addr;
@@ -550,20 +734,45 @@ static int
saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
- struct v4l2_mpeg_compression *params = arg;
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_mpeg_compression *old_params = arg;
+ struct saa6752hs_mpeg_params params;
int err = 0;
+ int i;
switch (cmd) {
case VIDIOC_S_MPEGCOMP:
- if (NULL == params) {
+ if (NULL == old_params) {
/* apply settings and start encoder */
saa6752hs_init(client);
break;
}
- saa6752hs_set_params(client, params);
+ saa6752hs_old_set_params(client, old_params);
/* fall through */
case VIDIOC_G_MPEGCOMP:
- *params = h->params;
+ *old_params = h->old_params;
+ break;
+ case VIDIOC_S_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ if (ctrls->count == 0) {
+ /* apply settings and start encoder */
+ saa6752hs_init(client);
+ break;
+ }
+ /* fall through */
+ case VIDIOC_TRY_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ params = h->params;
+ for (i = 0; i < ctrls->count; i++) {
+ if ((err = handle_ctrl(&params, ctrls->controls + i, cmd))) {
+ ctrls->error_idx = i;
+ return err;
+ }
+ }
+ h->params = params;
break;
case VIDIOC_G_FMT:
{
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index bb3e0ba946d..d73cff1970a 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -818,7 +818,7 @@ static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol,
break;
}
- /* output xbar always main channel */
+ /* 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
@@ -929,7 +929,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
err = request_irq(dev->pci->irq, saa7134_alsa_irq,
- SA_SHIRQ | SA_INTERRUPT, dev->name,
+ IRQF_SHARED | IRQF_DISABLED, dev->name,
(void*) &dev->dmasound);
if (err < 0) {
@@ -997,9 +997,9 @@ static int saa7134_alsa_init(void)
struct saa7134_dev *dev = NULL;
struct list_head *list;
- if (!dmasound_init && !dmasound_exit) {
- dmasound_init = alsa_device_init;
- dmasound_exit = alsa_device_exit;
+ if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
+ saa7134_dmasound_init = alsa_device_init;
+ saa7134_dmasound_exit = alsa_device_exit;
} else {
printk(KERN_WARNING "saa7134 ALSA: can't load, DMA sound handler already assigned (probably to OSS)\n");
return -EBUSY;
@@ -1036,8 +1036,8 @@ static void saa7134_alsa_exit(void)
snd_card_free(snd_saa7134_cards[idx]);
}
- dmasound_init = NULL;
- dmasound_exit = NULL;
+ saa7134_dmasound_init = NULL;
+ saa7134_dmasound_exit = NULL;
printk(KERN_INFO "saa7134 ALSA driver for DMA sound unloaded\n");
return;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 86eae352833..927413aded1 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -2160,7 +2160,7 @@ struct saa7134_board saa7134_boards[] = {
.radio = {
.name = name_radio,
.amux = LINE2,
- },
+ },
},
[SAA7134_BOARD_GOTVIEW_7135] = {
/* Mike Baikov <mike@baikov.com> */
@@ -2842,6 +2842,55 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
},
+ [SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+ /* "Zac Bowling" <zac@zacbowling.com> */
+ .name = "LifeView FlyVIDEO3000 (NTSC)",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -2901,6 +2950,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5169,
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x5168,
.subdevice = 0x0138,
.driver_data = SAA7134_BOARD_FLYVIDEO3000,
@@ -3459,6 +3514,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
+ case SAA7134_BOARD_FLYVIDEO3000_NTSC:
dev->has_remote = SAA7134_REMOTE_GPIO;
board_flyvideo(dev);
break;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index f0c2111f14a..be3a81fc90a 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -20,7 +20,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -96,8 +95,8 @@ LIST_HEAD(saa7134_devlist);
static LIST_HEAD(mops_list);
static unsigned int saa7134_devcount;
-int (*dmasound_init)(struct saa7134_dev *dev);
-int (*dmasound_exit)(struct saa7134_dev *dev);
+int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
#define dprintk(fmt, arg...) if (core_debug) \
printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg)
@@ -871,9 +870,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
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, "
- "latency: %d, mmio: 0x%lx\n", dev->name,
+ "latency: %d, mmio: 0x%llx\n", dev->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
- dev->pci_lat,pci_resource_start(pci_dev,0));
+ dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
pci_set_master(pci_dev);
if (!pci_dma_supported(pci_dev, DMA_32BIT_MASK)) {
printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name);
@@ -905,8 +904,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
pci_resource_len(pci_dev,0),
dev->name)) {
err = -EBUSY;
- printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n",
- dev->name,pci_resource_start(pci_dev,0));
+ printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n",
+ dev->name,(unsigned long long)pci_resource_start(pci_dev,0));
goto fail1;
}
dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000);
@@ -924,7 +923,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* get irq */
err = request_irq(pci_dev->irq, saa7134_irq,
- SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
dev->name,pci_dev->irq);
@@ -942,8 +941,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* load i2c helpers */
if (TUNER_ABSENT != dev->tuner_type)
request_module("tuner");
- if (dev->tda9887_conf)
- request_module("tda9887");
if (card_is_empress(dev)) {
request_module("saa6752hs");
request_module_depend("saa7134-empress",&need_empress);
@@ -1011,8 +1008,8 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
/* check for signal */
saa7134_irq_video_intl(dev);
- if (dmasound_init && !dev->dmasound.priv_data) {
- dmasound_init(dev);
+ if (saa7134_dmasound_init && !dev->dmasound.priv_data) {
+ saa7134_dmasound_init(dev);
}
return 0;
@@ -1039,8 +1036,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
struct saa7134_mpeg_ops *mops;
/* Release DMA sound modules if present */
- if (dmasound_exit && dev->dmasound.priv_data) {
- dmasound_exit(dev);
+ if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
+ saa7134_dmasound_exit(dev);
}
/* debugging ... */
@@ -1172,8 +1169,8 @@ EXPORT_SYMBOL(saa7134_boards);
/* ----------------- for the DMA sound modules --------------- */
-EXPORT_SYMBOL(dmasound_init);
-EXPORT_SYMBOL(dmasound_exit);
+EXPORT_SYMBOL(saa7134_dmasound_init);
+EXPORT_SYMBOL(saa7134_dmasound_exit);
EXPORT_SYMBOL(saa7134_pgtable_free);
EXPORT_SYMBOL(saa7134_pgtable_build);
EXPORT_SYMBOL(saa7134_pgtable_alloc);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 222a36c3891..279828b8f29 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -132,9 +132,8 @@ static int mt352_aver777_init(struct dvb_frontend* fe)
return 0;
}
-static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
u8 off[] = { 0x00, 0xf1};
u8 on[] = { 0x00, 0x71};
@@ -147,30 +146,31 @@ static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
f.tuner = 0;
f.type = V4L2_TUNER_DIGITAL_TV;
f.frequency = params->frequency / 1000 * 16 / 1000;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
msg.buf = on;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
pinnacle_antenna_pwr(dev, antenna_pwr);
/* mt352 setup */
- mt352_pinnacle_init(fe);
- pllbuf[0] = 0xc2;
- pllbuf[1] = 0x00;
- pllbuf[2] = 0x00;
- pllbuf[3] = 0x80;
- pllbuf[4] = 0x00;
- return 0;
+ return mt352_pinnacle_init(fe);
}
-static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
- pllbuf[0] = 0xc2;
+ if (buf_len < 5)
+ return -EINVAL;
+
+ pllbuf[0] = 0x61;
dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
params->frequency,
params->u.ofdm.bandwidth);
- return 0;
+ return 5;
}
static struct mt352_config pinnacle_300i = {
@@ -179,13 +179,11 @@ static struct mt352_config pinnacle_300i = {
.if2 = 36150,
.no_tuner = 1,
.demod_init = mt352_pinnacle_init,
- .pll_set = mt352_pinnacle_pll_set,
};
static struct mt352_config avermedia_777 = {
.demod_address = 0xf,
.demod_init = mt352_aver777_init,
- .pll_set = mt352_aver777_pll_set,
};
#endif
@@ -268,6 +266,8 @@ static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -281,6 +281,8 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
/* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -290,12 +292,12 @@ static int philips_tda6651_pll_init(u8 addr, struct dvb_frontend *fe)
/* ------------------------------------------------------------------ */
-static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_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)
+static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x60, fe, params);
}
@@ -315,20 +317,17 @@ static struct tda1004x_config philips_tu1216_60_config = {
.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)
+static int philips_tu1216_tuner_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)
+static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x61, fe, params);
}
@@ -341,21 +340,20 @@ static struct tda1004x_config philips_tu1216_61_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .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)
+static int philips_europa_tuner_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 (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -365,18 +363,20 @@ static int philips_europa_pll_init(struct dvb_frontend *fe)
init_msg.len = 0x02;
msg[0] = 0x00;
msg[1] = 0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
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)
+static int philips_td1316_tuner_set_params(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)
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message actually turns the tuner back to analog mode */
@@ -391,7 +391,20 @@ static void philips_europa_analog(struct dvb_frontend *fe)
analog_msg.len = 0x02;
msg[0] = 0x00;
msg[1] = 0x14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ if (dev->original_demod_sleep)
+ dev->original_demod_sleep(fe);
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ return 0;
}
static struct tda1004x_config philips_europa_config = {
@@ -402,21 +415,20 @@ static struct tda1004x_config philips_europa_config = {
.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)
+static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message is to set up ATC and ALC */
static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
@@ -424,22 +436,27 @@ static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
return 0;
}
-static void philips_fmd1216_analog(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message actually turns the tuner back to analog mode */
static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
msleep(1);
fmd1216_init[2] = 0x86;
fmd1216_init[3] = 0x54;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
msleep(1);
+ return 0;
}
-static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[4];
@@ -516,6 +533,8 @@ static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
tuner_buf[3] = 0x40 | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
return 0;
@@ -528,9 +547,6 @@ static struct tda1004x_config medion_cardbus = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_IFO_AUTO_NEG,
.if_freq = TDA10046_FREQ_3613,
- .pll_init = philips_fmd1216_pll_init,
- .pll_set = philips_fmd1216_pll_set,
- .pll_sleep = philips_fmd1216_analog,
.request_firmware = NULL,
};
@@ -578,12 +594,12 @@ static struct tda827x_data tda827x_dvbt[] = {
{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
};
-static int philips_tda827x_pll_init(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
{
return 0;
}
-static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[14];
@@ -630,6 +646,8 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
tuner_buf[13] = 0x40;
tuner_msg.len = 14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
@@ -638,18 +656,23 @@ static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_
tuner_buf[0] = 0x30;
tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
tuner_msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
return 0;
}
-static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_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) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+ return 0;
}
static struct tda1004x_config tda827x_lifeview_config = {
@@ -659,9 +682,6 @@ static struct tda1004x_config tda827x_lifeview_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = philips_tda827x_pll_init,
- .pll_set = philips_tda827x_pll_set,
- .pll_sleep = philips_tda827x_pll_sleep,
.request_firmware = NULL,
};
@@ -753,6 +773,8 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
tuner_buf[12] = 0x00;
tuner_buf[13] = 0x39; // lpsel
msg.len = 14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -760,10 +782,14 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
msg.len = 2;
reg2[0] = 0x60;
reg2[1] = 0x3c;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
reg2[0] = 0xa0;
reg2[1] = 0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
msleep(2);
@@ -771,36 +797,43 @@ static int philips_tda827xa_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb
reg2[0] = 0x30;
reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
msleep(550);
reg2[0] = 0x50;
reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
return 0;
}
-static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827xa_tuner_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) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
+ return 0;
}
/* ------------------------------------------------------------------ */
-static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tiger_tuner_set_params(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);
@@ -816,7 +849,7 @@ static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
return ret;
}
-static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 data[] = { 0x3c, 0x33, 0x6a};
@@ -827,14 +860,15 @@ static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
return 0;
}
-static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_sleep(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);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
}
static struct tda1004x_config philips_tiger_config = {
@@ -844,15 +878,12 @@ static struct tda1004x_config philips_tiger_config = {
.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,
};
/* ------------------------------------------------------------------ */
-static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
@@ -860,16 +891,12 @@ static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa
return ret;
}
-static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
{
+ philips_tda827xa_tuner_sleep(0x60, fe);
return 0;
}
-static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
-{
- philips_tda827xa_pll_sleep(0x60, fe);
-}
-
static struct tda1004x_config lifeview_trio_config = {
.demod_address = 0x09,
.invert = 1,
@@ -877,15 +904,12 @@ static struct tda1004x_config lifeview_trio_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X_GPL,
.if_freq = TDA10046_FREQ_045,
- .pll_init = lifeview_trio_dvb_mode,
- .pll_set = lifeview_trio_pll_set,
- .pll_sleep = lifeview_trio_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
@@ -893,7 +917,7 @@ static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_paramete
return ret;
}
-static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* route TDA8275a AGC input to the channel decoder */
@@ -901,12 +925,13 @@ static int ads_duo_dvb_mode(struct dvb_frontend *fe)
return 0;
}
-static void ads_duo_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* route TDA8275a AGC input to the analog IF chip*/
saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
- philips_tda827xa_pll_sleep( 0x61, fe);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
}
static struct tda1004x_config ads_tech_duo_config = {
@@ -916,31 +941,24 @@ static struct tda1004x_config ads_tech_duo_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X_GPL,
.if_freq = TDA10046_FREQ_045,
- .pll_init = ads_duo_dvb_mode,
- .pll_set = ads_duo_pll_set,
- .pll_sleep = ads_duo_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
ret = philips_tda827xa_pll_set(0x60, fe, params);
return ret;
}
-static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
{
+ philips_tda827xa_tuner_sleep( 0x61, fe);
return 0;
}
-static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
-{
- philips_tda827xa_pll_sleep( 0x61, fe);
-}
-
static struct tda1004x_config tevion_dvbt220rf_config = {
.demod_address = 0x08,
.invert = 1,
@@ -948,9 +966,6 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = tevion_dvb220rf_pll_init,
- .pll_set = tevion_dvb220rf_pll_set,
- .pll_sleep = tevion_dvb220rf_pll_sleep,
.request_firmware = NULL,
};
@@ -961,8 +976,6 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
#ifdef HAVE_NXT200X
static struct nxt200x_config avertvhda180 = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tdhu2,
};
static int nxt200x_set_pll_input(u8 *buf, int input)
@@ -976,8 +989,6 @@ static int nxt200x_set_pll_input(u8 *buf, int input)
static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tuv1236d,
.set_pll_input = nxt200x_set_pll_input,
};
#endif
@@ -1003,78 +1014,158 @@ static int dvb_init(struct saa7134_dev *dev)
printk("%s: pinnacle 300i dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&pinnacle_300i,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ }
break;
case SAA7134_BOARD_AVERMEDIA_777:
printk("%s: avertv 777 dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&avermedia_777,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ }
break;
#endif
#ifdef HAVE_TDA1004X
case SAA7134_BOARD_MD7134:
dev->dvb.frontend = tda10046_attach(&medion_cardbus,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBTDUO:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
dev->dvb.frontend = tda10046_attach(&philips_europa_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
dev->dvb.frontend = tda10046_attach(&philips_europa_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_TIGER:
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_LR301:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVB_TRIO:
dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+ }
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
break;
#endif
#ifdef HAVE_NXT200X
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+ }
break;
case SAA7134_BOARD_KWORLD_ATSC110:
dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+ }
break;
#endif
default:
@@ -1088,7 +1179,7 @@ static int dvb_init(struct saa7134_dev *dev)
}
/* register everything else */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
}
static int dvb_fini(struct saa7134_dev *dev)
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 1d972edb3be..65d044086ce 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -64,8 +64,10 @@ static void ts_reset_encoder(struct saa7134_dev* dev)
static int ts_init_encoder(struct saa7134_dev* dev)
{
+ struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+
ts_reset_encoder(dev);
- saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+ saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
dev->empress_started = 1;
return 0;
}
@@ -162,6 +164,7 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_ext_controls *ctrls = arg;
if (debug > 1)
v4l_print_ioctl(dev->name,cmd);
@@ -278,12 +281,31 @@ static int ts_do_ioctl(struct inode *inode, struct file *file,
return saa7134_common_ioctl(dev, cmd, arg);
case VIDIOC_S_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
ts_init_encoder(dev);
return 0;
case VIDIOC_G_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
return 0;
+ case VIDIOC_S_EXT_CTRLS:
+ /* count == 0 is abused in saa6752hs.c, so that special
+ case is handled here explicitly. */
+ if (ctrls->count == 0)
+ return 0;
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
+ ts_init_encoder(dev);
+ return 0;
+ case VIDIOC_G_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+ return 0;
default:
return -ENOIOCTLCMD;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 1426e4c8602..7c595492c56 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -37,6 +37,10 @@ static unsigned int ir_debug = 0;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+static int pinnacle_remote = 0;
+module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
@@ -316,8 +320,13 @@ void saa7134_set_i2c_ir(struct saa7134_dev *dev, struct IR_i2c *ir)
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;
+ if (pinnacle_remote == 0) {
+ ir->get_key = get_key_pinnacle_color;
+ ir->ir_codes = ir_codes_pinnacle_color;
+ } else {
+ ir->get_key = get_key_pinnacle_grey;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ }
break;
case SAA7134_BOARD_UPMOST_PURPLE_TV:
snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 7aa02b34e01..2e3ba5f3145 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -845,7 +845,7 @@ int saa7134_oss_init1(struct saa7134_dev *dev)
{
if ((request_irq(dev->pci->irq, saa7134_oss_irq,
- SA_SHIRQ | SA_INTERRUPT, dev->name,
+ IRQF_SHARED | IRQF_DISABLED, dev->name,
(void*) &dev->dmasound)) < 0)
return -1;
@@ -993,9 +993,9 @@ static int saa7134_oss_init(void)
struct saa7134_dev *dev = NULL;
struct list_head *list;
- if (!dmasound_init && !dmasound_exit) {
- dmasound_init = oss_device_init;
- dmasound_exit = oss_device_exit;
+ if (!saa7134_dmasound_init && !saa7134_dmasound_exit) {
+ saa7134_dmasound_init = oss_device_init;
+ saa7134_dmasound_exit = oss_device_exit;
} else {
printk(KERN_WARNING "saa7134 OSS: can't load, DMA sound handler already assigned (probably to ALSA)\n");
return -EBUSY;
@@ -1037,8 +1037,8 @@ static void saa7134_oss_exit(void)
}
- dmasound_init = NULL;
- dmasound_exit = NULL;
+ saa7134_dmasound_init = NULL;
+ saa7134_dmasound_exit = NULL;
printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n");
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index e4156ec9c6d..2c171af9a9f 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -40,7 +40,7 @@
static unsigned int video_debug = 0;
static unsigned int gbuffers = 8;
-static unsigned int noninterlaced = 0;
+static unsigned int noninterlaced = 1;
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
module_param(video_debug, int, 0644);
@@ -48,7 +48,7 @@ MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
module_param(gbuffers, int, 0444);
MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
module_param(noninterlaced, int, 0644);
-MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced");
+MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
#define dprintk(fmt, arg...) if (video_debug) \
printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
@@ -2087,7 +2087,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
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGMBUF:
{
struct video_mbuf *mbuf = arg;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 353af3a8b76..c04ce6152fd 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -33,6 +33,7 @@
#include <asm/io.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
@@ -221,6 +222,7 @@ struct saa7134_format {
#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
#define SAA7134_BOARD_MD7134_BRIDGE_2 93
#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -531,6 +533,7 @@ struct saa7134_dev {
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
+ int (*original_demod_sleep)(struct dvb_frontend* fe);
};
/* ----------------------------------------------------------- */
@@ -583,8 +586,8 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
int saa7134_set_dmabits(struct saa7134_dev *dev);
-extern int (*dmasound_init)(struct saa7134_dev *dev);
-extern int (*dmasound_exit)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_init)(struct saa7134_dev *dev);
+extern int (*saa7134_dmasound_exit)(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index a846ebc78cd..67987baee77 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -27,7 +27,6 @@
static const char version[] = "0.24";
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
index a7a216bd441..c0891b3e001 100644
--- a/drivers/media/video/se401.h
+++ b/drivers/media/video/se401.h
@@ -4,6 +4,7 @@
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index ea4394dc941..48d138a7c72 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -2608,11 +2608,9 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_CTRL:
return sn9c102_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return sn9c102_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return sn9c102_vidioc_cropcap(cam, arg);
@@ -2659,7 +2657,6 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_PARM:
return sn9c102_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return sn9c102_vidioc_s_parm(cam, arg);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 07476c71174..5686547ba76 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -42,6 +42,7 @@
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "saa7146.h"
#include "saa7146reg.h"
@@ -1982,7 +1983,7 @@ static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
saawrite(0, SAA7146_IER); /* turn off all interrupts */
- retval = request_irq(saa->irq, saa7146_irq, SA_SHIRQ | SA_INTERRUPT,
+ retval = request_irq(saa->irq, saa7146_irq, IRQF_SHARED | IRQF_DISABLED,
"stradis", saa);
if (retval == -EINVAL)
dev_err(&pdev->dev, "%d: Bad irq number or handler\n", num);
@@ -2180,7 +2181,6 @@ static struct pci_device_id stradis_pci_tbl[] = {
{ 0 }
};
-MODULE_DEVICE_TABLE(pci, stradis_pci_tbl);
static struct pci_driver stradis_driver = {
.name = "stradis",
@@ -2189,7 +2189,7 @@ static struct pci_driver stradis_driver = {
.remove = __devexit_p(stradis_remove)
};
-int __init stradis_init(void)
+static int __init stradis_init(void)
{
int retval;
@@ -2202,7 +2202,7 @@ int __init stradis_init(void)
return retval;
}
-void __exit stradis_exit(void)
+static void __exit stradis_exit(void)
{
pci_unregister_driver(&stradis_driver);
printk(KERN_INFO "stradis: module cleanup complete\n");
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index b38bda83a7c..2ba2991a214 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -58,7 +58,6 @@
* Fixed proc entry removal bug.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
@@ -66,6 +65,7 @@
#include <linux/pagemap.h>
#include <linux/errno.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 103ccb91929..827633b3bb4 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -26,6 +26,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
@@ -163,7 +164,7 @@ static void do_tda9875_init(struct i2c_client *client)
struct tda9875 *t = i2c_get_clientdata(client);
dprintk("In tda9875_init\n");
tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
- tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
+ tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/
tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/
tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 0d54f6c1982..8dab481d384 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -18,49 +18,21 @@
TDA9886 (PAL, SECAM, NTSC)
TDA9887 (PAL, SECAM, NTSC, FM Radio)
- found on:
- - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
- TDA9887 (world), TDA9885 (USA)
- Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
- - KNC One TV-Station RDS (saa7134)
- - Hauppauge PVR-150/500 (possibly more)
+ Used as part of several tuners
*/
+#define tda9887_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+ if (tuner_debug) \
+ printk(KERN_INFO "%s %d-%04x: " fmt, t->i2c.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
- 0x84 >>1,
- 0x86 >>1,
- 0x96 >>1,
- I2C_CLIENT_END,
-};
-I2C_CLIENT_INSMOD;
-
-/* insmod options */
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
#define UNSET (-1U)
-#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;
- v4l2_std_id std;
- enum tuner_mode mode;
- unsigned int config;
- unsigned int using_v4l2;
- unsigned int radio_mode;
- unsigned char data[4];
-};
struct tvnorm {
v4l2_std_id std;
@@ -70,9 +42,6 @@ struct tvnorm {
unsigned char e;
};
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
/* ---------------------------------------------------------------------- */
//
@@ -115,8 +84,7 @@ static struct i2c_client client_template;
#define cAudioGain6 0x80 // bit c7
#define cTopMask 0x1f // bit c0:4
-#define cTopPalSecamDefault 0x14 // bit c0:4
-#define cTopNtscRadioDefault 0x10 // bit c0:4
+#define cTopDefault 0x10 // bit c0:4
//// third reg (e)
#define cAudioIF_4_5 0x00 // bit e0:1
@@ -154,7 +122,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis50 |
- cTopPalSecamDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_5_5 |
cVideoIF_38_90 ),
@@ -165,7 +133,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis50 |
- cTopPalSecamDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_6_0 |
cVideoIF_38_90 ),
@@ -176,7 +144,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis50 |
- cTopPalSecamDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_6_5 |
cVideoIF_38_90 ),
@@ -187,7 +155,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis75 |
- cTopNtscRadioDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_4_5 |
cVideoIF_45_75 ),
@@ -196,7 +164,7 @@ static struct tvnorm tvnorms[] = {
.name = "SECAM-BGH",
.b = ( cPositiveAmTV |
cQSS ),
- .c = ( cTopPalSecamDefault),
+ .c = ( cTopDefault),
.e = ( cGating_36 |
cAudioIF_5_5 |
cVideoIF_38_90 ),
@@ -205,7 +173,7 @@ static struct tvnorm tvnorms[] = {
.name = "SECAM-L",
.b = ( cPositiveAmTV |
cQSS ),
- .c = ( cTopPalSecamDefault),
+ .c = ( cTopDefault),
.e = ( cGating_36 |
cAudioIF_6_5 |
cVideoIF_38_90 ),
@@ -215,7 +183,7 @@ static struct tvnorm tvnorms[] = {
.b = ( cOutputPort2Inactive |
cPositiveAmTV |
cQSS ),
- .c = ( cTopPalSecamDefault),
+ .c = ( cTopDefault),
.e = ( cGating_36 |
cAudioIF_6_5 |
cVideoIF_33_90 ),
@@ -226,7 +194,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis50 |
- cTopPalSecamDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_6_5 |
cVideoIF_38_90 ),
@@ -237,7 +205,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis75 |
- cTopNtscRadioDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_4_5 |
cVideoIF_45_75 ),
@@ -248,7 +216,7 @@ static struct tvnorm tvnorms[] = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis50 |
- cTopNtscRadioDefault),
+ cTopDefault),
.e = ( cGating_36 |
cAudioIF_4_5 |
cVideoIF_58_75 ),
@@ -261,7 +229,7 @@ static struct tvnorm radio_stereo = {
cQSS ),
.c = ( cDeemphasisOFF |
cAudioGain6 |
- cTopNtscRadioDefault),
+ cTopDefault),
.e = ( cTunerGainLow |
cAudioIF_5_5 |
cRadioIF_38_90 ),
@@ -273,7 +241,7 @@ static struct tvnorm radio_mono = {
cQSS ),
.c = ( cDeemphasisON |
cDeemphasis75 |
- cTopNtscRadioDefault),
+ cTopDefault),
.e = ( cTunerGainLow |
cAudioIF_5_5 |
cRadioIF_38_90 ),
@@ -281,7 +249,7 @@ static struct tvnorm radio_mono = {
/* ---------------------------------------------------------------------- */
-static void dump_read_message(struct tda9887 *t, unsigned char *buf)
+static void dump_read_message(struct tuner *t, unsigned char *buf)
{
static char *afc[16] = {
"- 12.5 kHz",
@@ -309,7 +277,7 @@ static void dump_read_message(struct tda9887 *t, unsigned char *buf)
tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
}
-static void dump_write_message(struct tda9887 *t, unsigned char *buf)
+static void dump_write_message(struct tuner *t, unsigned char *buf)
{
static char *sound[4] = {
"AM/TV",
@@ -405,13 +373,13 @@ static void dump_write_message(struct tda9887 *t, unsigned char *buf)
/* ---------------------------------------------------------------------- */
-static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
+static int tda9887_set_tvnorm(struct tuner *t, char *buf)
{
struct tvnorm *norm = NULL;
int i;
- if (t->mode == T_RADIO) {
- if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+ if (t->mode == V4L2_TUNER_RADIO) {
+ if (t->audmode == V4L2_TUNER_MODE_MONO)
norm = &radio_mono;
else
norm = &radio_stereo;
@@ -445,7 +413,7 @@ module_param(port2, int, 0644);
module_param(qss, int, 0644);
module_param(adjust, int, 0644);
-static int tda9887_set_insmod(struct tda9887 *t, char *buf)
+static int tda9887_set_insmod(struct tuner *t, char *buf)
{
if (UNSET != port1) {
if (port1)
@@ -474,27 +442,27 @@ static int tda9887_set_insmod(struct tda9887 *t, char *buf)
return 0;
}
-static int tda9887_set_config(struct tda9887 *t, char *buf)
+static int tda9887_set_config(struct tuner *t, char *buf)
{
- if (t->config & TDA9887_PORT1_ACTIVE)
+ if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
buf[1] &= ~cOutputPort1Inactive;
- if (t->config & TDA9887_PORT1_INACTIVE)
+ if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
buf[1] |= cOutputPort1Inactive;
- if (t->config & TDA9887_PORT2_ACTIVE)
+ if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
buf[1] &= ~cOutputPort2Inactive;
- if (t->config & TDA9887_PORT2_INACTIVE)
+ if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
buf[1] |= cOutputPort2Inactive;
- if (t->config & TDA9887_QSS)
+ if (t->tda9887_config & TDA9887_QSS)
buf[1] |= cQSS;
- if (t->config & TDA9887_INTERCARRIER)
+ if (t->tda9887_config & TDA9887_INTERCARRIER)
buf[1] &= ~cQSS;
- if (t->config & TDA9887_AUTOMUTE)
+ if (t->tda9887_config & TDA9887_AUTOMUTE)
buf[1] |= cAutoMuteFmActive;
- if (t->config & TDA9887_DEEMPHASIS_MASK) {
+ if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
buf[2] &= ~0x60;
- switch (t->config & TDA9887_DEEMPHASIS_MASK) {
+ switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
case TDA9887_DEEMPHASIS_NONE:
buf[2] |= cDeemphasisOFF;
break;
@@ -506,153 +474,36 @@ static int tda9887_set_config(struct tda9887 *t, char *buf)
break;
}
}
- if (t->config & TDA9887_TOP_SET) {
+ if (t->tda9887_config & TDA9887_TOP_SET) {
buf[2] &= ~cTopMask;
- buf[2] |= (t->config >> 8) & cTopMask;
+ buf[2] |= (t->tda9887_config >> 8) & cTopMask;
}
- if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+ if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
buf[1] &= ~cQSS;
return 0;
}
/* ---------------------------------------------------------------------- */
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-module_param_string(pal, pal, sizeof(pal), 0644);
-module_param_string(secam, secam, sizeof(secam), 0644);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-
-static int tda9887_fixup_std(struct tda9887 *t)
-{
- /* get more precise norm info from insmod option */
- if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
- switch (pal[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- case 'n':
- case 'N':
- if (pal[1] == 'c' || pal[1] == 'C') {
- tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
- t->std = V4L2_STD_PAL_Nc;
- } else {
- tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
- t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
- }
- break;
- case 'i':
- case 'I':
- tda9887_dbg("insmod fixup: PAL => PAL-I\n");
- t->std = V4L2_STD_PAL_I;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
- t->std = V4L2_STD_PAL_DK;
- break;
- case 'm':
- case 'M':
- tda9887_dbg("insmod fixup: PAL => PAL-M\n");
- t->std = V4L2_STD_PAL_M;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("pal= argument not recognised\n");
- break;
- }
- }
- if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
- switch (secam[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
- t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
- t->std = V4L2_STD_SECAM_DK;
- break;
- case 'l':
- case 'L':
- if (secam[1] == 'c' || secam[1] == 'C') {
- tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
- t->std = V4L2_STD_SECAM_LC;
- } else {
- tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
- }
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("secam= argument not recognised\n");
- break;
- }
- }
- if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
- switch (ntsc[0]) {
- case 'm':
- case 'M':
- tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
- t->std = V4L2_STD_NTSC_M;
- break;
- case 'j':
- case 'J':
- tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
- t->std = V4L2_STD_NTSC_M_JP;
- break;
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
- t->std = V4L2_STD_NTSC_M_KR;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("ntsc= argument not recognised\n");
- break;
- }
- }
- return 0;
-}
-
-static int tda9887_status(struct tda9887 *t)
+static int tda9887_status(struct tuner *t)
{
unsigned char buf[1];
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+ if (1 != (rc = i2c_master_recv(&t->i2c,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)
+static void tda9887_configure(struct i2c_client *client)
{
+ struct tuner *t = i2c_get_clientdata(client);
int rc;
- memset(t->data,0,sizeof(t->data));
- tda9887_set_tvnorm(t,t->data);
+ memset(t->tda9887_data,0,sizeof(t->tda9887_data));
+ tda9887_set_tvnorm(t,t->tda9887_data);
/* A note on the port settings:
These settings tend to depend on the specifics of the board.
@@ -667,249 +518,84 @@ static int tda9887_configure(struct tda9887 *t)
the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration.
*/
- t->data[1] |= cOutputPort1Inactive;
- t->data[1] |= cOutputPort2Inactive;
+ t->tda9887_data[1] |= cOutputPort1Inactive;
+ t->tda9887_data[1] |= cOutputPort2Inactive;
- tda9887_set_config(t,t->data);
- tda9887_set_insmod(t,t->data);
+ tda9887_set_config(t,t->tda9887_data);
+ tda9887_set_insmod(t,t->tda9887_data);
if (t->mode == T_STANDBY) {
- t->data[1] |= cForcedMuteAudioON;
+ t->tda9887_data[1] |= cForcedMuteAudioON;
}
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(t, t->data);
+ t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+ if (tuner_debug > 1)
+ dump_write_message(t, t->tda9887_data);
- if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+ if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
- if (debug > 2) {
+ if (tuner_debug > 2) {
msleep_interruptible(1000);
tda9887_status(t);
}
- return 0;
}
/* ---------------------------------------------------------------------- */
-static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
+static void tda9887_tuner_status(struct i2c_client *client)
{
- struct tda9887 *t;
-
- client_template.adapter = adap;
- client_template.addr = addr;
-
- if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
-
- t->client = client_template;
- t->std = 0;
- 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);
-
- return 0;
+ struct tuner *t = i2c_get_clientdata(client);
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
}
-static int tda9887_probe(struct i2c_adapter *adap)
+static int tda9887_get_afc(struct i2c_client *client)
{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, tda9887_attach);
- return 0;
-}
+ struct tuner *t = i2c_get_clientdata(client);
+ static int AFC_BITS_2_kHz[] = {
+ -12500, -37500, -62500, -97500,
+ -112500, -137500, -162500, -187500,
+ 187500, 162500, 137500, 112500,
+ 97500 , 62500, 37500 , 12500
+ };
+ int afc=0;
+ __u8 reg = 0;
-static int tda9887_detach(struct i2c_client *client)
-{
- struct tda9887 *t = i2c_get_clientdata(client);
+ if (1 == i2c_master_recv(&t->i2c,&reg,1))
+ afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
- i2c_detach_client(client);
- kfree(t);
- return 0;
+ return afc;
}
-#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \
- tda9887_info("switching to v4l2\n"); \
- t->using_v4l2 = 1;
-#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \
- tda9887_info("ignore v4l1 call\n"); \
- return 0; }
-
-static int
-tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static void tda9887_standby(struct i2c_client *client)
{
- struct tda9887 *t = i2c_get_clientdata(client);
-
- switch (cmd) {
-
- /* --- configuration --- */
- case AUDC_SET_RADIO:
- {
- t->mode = T_RADIO;
- tda9887_configure(t);
- break;
- }
- case TUNER_SET_STANDBY:
- {
- t->mode = T_STANDBY;
- tda9887_configure(t);
- break;
- }
- case TDA9887_SET_CONFIG:
- {
- int *i = arg;
-
- t->config = *i;
- tda9887_configure(t);
- break;
- }
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCSCHAN:
- {
- static const v4l2_std_id map[] = {
- [ VIDEO_MODE_PAL ] = V4L2_STD_PAL,
- [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M,
- [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
- [ 4 /* bttv */ ] = V4L2_STD_PAL_M,
- [ 5 /* bttv */ ] = V4L2_STD_PAL_N,
- [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
- };
- struct video_channel *vc = arg;
-
- CHECK_V4L2;
- t->mode = T_ANALOG_TV;
- if (vc->norm < ARRAY_SIZE(map))
- t->std = map[vc->norm];
- tda9887_fixup_std(t);
- tda9887_configure(t);
- break;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
-
- SWITCH_V4L2;
- t->mode = T_ANALOG_TV;
- t->std = *id;
- tda9887_fixup_std(t);
- tda9887_configure(t);
- break;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- SWITCH_V4L2;
- if (V4L2_TUNER_ANALOG_TV == f->type) {
- if (t->mode == T_ANALOG_TV)
- return 0;
- t->mode = T_ANALOG_TV;
- }
- if (V4L2_TUNER_RADIO == f->type) {
- if (t->mode == T_RADIO)
- return 0;
- t->mode = T_RADIO;
- }
- tda9887_configure(t);
- break;
- }
- case VIDIOC_G_TUNER:
- {
- static int AFC_BITS_2_kHz[] = {
- -12500, -37500, -62500, -97500,
- -112500, -137500, -162500, -187500,
- 187500, 162500, 137500, 112500,
- 97500 , 62500, 37500 , 12500
- };
- struct v4l2_tuner* tuner = arg;
-
- if (t->mode == T_RADIO) {
- __u8 reg = 0;
- tuner->afc=0;
- if (1 == i2c_master_recv(&t->client,&reg,1))
- tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
- }
- break;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner* tuner = arg;
-
- if (t->mode == T_RADIO) {
- t->radio_mode = tuner->audmode;
- tda9887_configure (t);
- }
- break;
- }
- case VIDIOC_LOG_STATUS:
- {
- tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
- break;
- }
- default:
- /* nothing */
- break;
- }
- return 0;
+ tda9887_configure(client);
}
-static int tda9887_suspend(struct device * dev, pm_message_t state)
+static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tda9887 *t = i2c_get_clientdata(c);
-
- tda9887_dbg("suspend\n");
- return 0;
+ tda9887_configure(client);
}
-static int tda9887_resume(struct device * dev)
+int tda9887_tuner_init(struct i2c_client *c)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tda9887 *t = i2c_get_clientdata(c);
+ struct tuner *t = i2c_get_clientdata(c);
- tda9887_dbg("resume\n");
- tda9887_configure(t);
- return 0;
-}
+ strlcpy(c->name, "tda9887", sizeof(c->name));
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
- .id = I2C_DRIVERID_TDA9887,
- .attach_adapter = tda9887_probe,
- .detach_client = tda9887_detach,
- .command = tda9887_command,
- .driver = {
- .name = "tda9887",
- .suspend = tda9887_suspend,
- .resume = tda9887_resume,
- },
-};
-static struct i2c_client client_template =
-{
- .name = "tda9887",
- .driver = &driver,
-};
+ tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
+ t->i2c.driver->driver.name);
-static int __init tda9887_init_module(void)
-{
- return i2c_add_driver(&driver);
-}
+ t->set_tv_freq = tda9887_set_freq;
+ t->set_radio_freq = tda9887_set_freq;
+ t->standby = tda9887_standby;
+ t->tuner_status = tda9887_tuner_status;
+ t->get_afc = tda9887_get_afc;
-static void __exit tda9887_cleanup_module(void)
-{
- i2c_del_driver(&driver);
+ return 0;
}
-module_init(tda9887_init_module);
-module_exit(tda9887_cleanup_module);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index c2b98f81c19..d1c41781ccc 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -3,7 +3,7 @@
* I2C address is allways 0xC0.
*
*
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License
*
* tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
new file mode 100644
index 00000000000..76b2e96429d
--- /dev/null
+++ b/drivers/media/video/tlv320aic23b.c
@@ -0,0 +1,217 @@
+/*
+ * tlv320aic23b - driver version 0.0.1
+ *
+ * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
+ *
+ * Based on wm8775 driver
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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/v4l2-common.h>
+
+MODULE_DESCRIPTION("tlv320aic23b driver");
+MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct tlv320aic23b_state {
+ u8 muted;
+};
+
+static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+{
+ int i;
+
+ if ((reg < 0 || reg > 9) && (reg != 15)) {
+ v4l_err(client, "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;
+ }
+ }
+ v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ return -1;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct tlv320aic23b_state *state = i2c_get_clientdata(client);
+ struct v4l2_control *ctrl = arg;
+ u32* freq = arg;
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ switch (*freq) {
+ case 32000: /* set sample rate to 32 kHz */
+ tlv320aic23b_write(client, 8, 0x018);
+ break;
+ case 44100: /* set sample rate to 44.1 kHz */
+ tlv320aic23b_write(client, 8, 0x022);
+ break;
+ case 48000: /* set sample rate to 48 kHz */
+ tlv320aic23b_write(client, 8, 0x000);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_G_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ ctrl->value = state->muted;
+ break;
+
+ case VIDIOC_S_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ state->muted = ctrl->value;
+ tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
+ /* set gain on both channels to +3.0 dB */
+ if (!state->muted)
+ tlv320aic23b_write(client, 0, 0x119);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ v4l_info(client, "Input: %s\n",
+ state->muted ? "muted" : "active");
+ 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 tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct tlv320aic23b_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->muted = 0;
+ i2c_set_clientdata(client, state);
+
+ /* initialize tlv320aic23b */
+ tlv320aic23b_write(client, 15, 0x000); /* RESET */
+ tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */
+ tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */
+ tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */
+ tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */
+ tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+ return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
+ return 0;
+}
+
+static int tlv320aic23b_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 = {
+ .driver = {
+ .name = "tlv320aic23b",
+ },
+ .id = I2C_DRIVERID_TLV320AIC23B,
+ .attach_adapter = tlv320aic23b_probe,
+ .detach_client = tlv320aic23b_detach,
+ .command = tlv320aic23b_command,
+};
+
+
+static int __init tlv320aic23b_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit tlv320aic23b_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(tlv320aic23b_init_module);
+module_exit(tlv320aic23b_cleanup_module);
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
index 74ab48c09c6..bdf506e6ae2 100644
--- a/drivers/media/video/tuner-3036.c
+++ b/drivers/media/video/tuner-3036.c
@@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 1013b4de89a..40590bae5ff 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -40,7 +40,6 @@ static unsigned int no_autodetect = 0;
static unsigned int show_i2c = 0;
/* insmod options used at runtime => read/write */
-static unsigned int tuner_debug_old = 0;
int tuner_debug = 0;
static unsigned int tv_range[2] = { 44, 958 };
@@ -54,8 +53,6 @@ static char ntsc[] = "-";
module_param(addr, int, 0444);
module_param(no_autodetect, int, 0444);
module_param(show_i2c, int, 0444);
-/* Note: tuner_debug is deprecated and will be removed in 2.6.17 */
-module_param_named(tuner_debug,tuner_debug_old, int, 0444);
module_param_named(debug,tuner_debug, int, 0644);
module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
@@ -199,14 +196,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c, buffer, 4);
default_tuner_init(c);
break;
- case TUNER_LG_TDVS_H062F:
- /* Set the Auxiliary Byte. */
- buffer[2] &= ~0x20;
- buffer[2] |= 0x18;
- buffer[3] = 0x20;
- i2c_master_send(c, buffer, 4);
- default_tuner_init(c);
- break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
buffer[1] = 0xdc;
@@ -215,6 +204,9 @@ static void set_type(struct i2c_client *c, unsigned int type,
i2c_master_send(c,buffer,4);
default_tuner_init(c);
break;
+ case TUNER_TDA9887:
+ tda9887_tuner_init(c);
+ break;
default:
default_tuner_init(c);
break;
@@ -241,6 +233,8 @@ static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
{
struct tuner *t = i2c_get_clientdata(c);
+ tuner_dbg("set addr for type %i\n", t->type);
+
if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
(t->mode_mask & tun_setup->mode_mask)) ||
tun_setup->addr == c->addr)) {
@@ -414,7 +408,7 @@ static void tuner_status(struct i2c_client *client)
/* ---------------------------------------------------------------------- */
-/* static var Used only in tuner_attach and tuner_probe */
+/* static vars: used only in tuner_attach and tuner_probe */
static unsigned default_mode_mask;
/* During client attach, set_type is called by adapter's attach_inform callback.
@@ -436,11 +430,7 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
- if (tuner_debug_old) {
- tuner_debug = tuner_debug_old;
- printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
- printk(KERN_ERR "tuner: use the debug option instead.\n");
- }
+ t->tuner_status = tuner_status;
if (show_i2c) {
unsigned char buffer[16];
@@ -462,10 +452,14 @@ static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
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;
+ if (tda8290_probe(&t->i2c) == 0) {
+ tuner_dbg("chip at addr %x is a tda8290\n", addr);
+ } else {
+ /* Default is being tda9887 */
+ t->type = TUNER_TDA9887;
+ t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ t->mode = T_STANDBY;
+ goto register_client;
}
break;
case 0x60:
@@ -592,9 +586,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
case TUNER_SET_STANDBY:
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
+ t->mode = T_STANDBY;
if (t->standby)
t->standby (client);
break;
+#ifdef CONFIG_VIDEO_V4L1
case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
return 0;
@@ -604,9 +600,6 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break;
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
case VIDIOCSCHAN:
{
static const v4l2_std_id map[] = {
@@ -690,7 +683,18 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
return 0;
}
+#endif
+ case TDA9887_SET_CONFIG:
+ if (t->type == TUNER_TDA9887) {
+ int *i = arg;
+ t->tda9887_config = *i;
+ set_freq(client, t->tv_freq);
+ }
+ break;
+ /* --- v4l ioctls --- */
+ /* take care: bttv does userspace copying, we'll get a
+ kernel pointer here... */
case VIDIOC_S_STD:
{
v4l2_std_id *id = arg;
@@ -711,14 +715,10 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct v4l2_frequency *f = arg;
+ if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+ == EINVAL)
+ return 0;
switch_v4l2();
- if ((V4L2_TUNER_RADIO == f->type && V4L2_TUNER_RADIO != t->mode)
- || (V4L2_TUNER_DIGITAL_TV == f->type
- && V4L2_TUNER_DIGITAL_TV != t->mode)) {
- if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
- == EINVAL)
- return 0;
- }
set_freq(client,f->frequency);
break;
@@ -744,6 +744,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch_v4l2();
tuner->type = t->mode;
+ if (t->get_afc)
+ tuner->afc=t->get_afc(client);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
@@ -787,7 +789,8 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
break;
}
case VIDIOC_LOG_STATUS:
- tuner_status(client);
+ if (t->tuner_status)
+ t->tuner_status(client);
break;
}
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 5d7abed7167..abe37cf632c 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -7,6 +7,7 @@
#include <linux/i2c.h>
#include <linux/videodev.h>
#include <media/tuner.h>
+#include <media/v4l2-common.h>
static int offset = 0;
module_param(offset, int, 0666);
@@ -105,7 +106,7 @@ static int tuner_stereo(struct i2c_client *c)
switch (t->type) {
case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
break;
@@ -128,6 +129,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
u8 buffer[4];
int rc, IFPCoff, i, j;
enum param_type desired_type;
+ struct tuner_params *params;
tun = &tuners[t->type];
@@ -169,19 +171,20 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
IFPCoff,t->type);
j = 0;
}
+ params = &tun->params[j];
- for (i = 0; i < tun->params[j].count; i++) {
- if (freq > tun->params[j].ranges[i].limit)
+ for (i = 0; i < params->count; i++) {
+ if (freq > params->ranges[i].limit)
continue;
break;
}
- if (i == tun->params[j].count) {
+ if (i == params->count) {
tuner_dbg("TV frequency out of range (%d > %d)",
- freq, tun->params[j].ranges[i - 1].limit);
- freq = tun->params[j].ranges[--i].limit;
+ freq, params->ranges[i - 1].limit);
+ freq = params->ranges[--i].limit;
}
- config = tun->params[j].ranges[i].config;
- cb = tun->params[j].ranges[i].cb;
+ config = params->ranges[i].config;
+ cb = params->ranges[i].cb;
/* i == 0 -> VHF_LO
* i == 1 -> VHF_HI
* i == 2 -> UHF */
@@ -281,7 +284,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
break;
}
- if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
+ if (params->cb_first_if_lower_freq && div < t->last_div) {
buffer[0] = config;
buffer[1] = cb;
buffer[2] = (div>>8) & 0x7f;
@@ -293,13 +296,63 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[3] = cb;
}
t->last_div = div;
+ if (params->has_tda9887) {
+ int config = 0;
+ int is_secam_l = (t->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
+ !(t->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+
+ if (t->std == V4L2_STD_SECAM_LC) {
+ if (params->port1_active ^ params->port1_invert_for_secam_lc)
+ config |= TDA9887_PORT1_ACTIVE;
+ if (params->port2_active ^ params->port2_invert_for_secam_lc)
+ config |= TDA9887_PORT2_ACTIVE;
+ }
+ else {
+ if (params->port1_active)
+ config |= TDA9887_PORT1_ACTIVE;
+ if (params->port2_active)
+ config |= TDA9887_PORT2_ACTIVE;
+ }
+ if (params->intercarrier_mode)
+ config |= TDA9887_INTERCARRIER;
+ if (is_secam_l) {
+ if (i == 0 && params->default_top_secam_low)
+ config |= TDA9887_TOP(params->default_top_secam_low);
+ else if (i == 1 && params->default_top_secam_mid)
+ config |= TDA9887_TOP(params->default_top_secam_mid);
+ else if (params->default_top_secam_high)
+ config |= TDA9887_TOP(params->default_top_secam_high);
+ }
+ else {
+ if (i == 0 && params->default_top_low)
+ config |= TDA9887_TOP(params->default_top_low);
+ else if (i == 1 && params->default_top_mid)
+ config |= TDA9887_TOP(params->default_top_mid);
+ else if (params->default_top_high)
+ config |= TDA9887_TOP(params->default_top_high);
+ }
+ i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ }
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)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
- if (t->type == TUNER_MICROTUNE_4042FI5) {
+ switch (t->type) {
+ case TUNER_LG_TDVS_H06XF:
+ /* Set the Auxiliary Byte. */
+ buffer[0] = buffer[2];
+ buffer[0] &= ~0x20;
+ buffer[0] |= 0x18;
+ buffer[1] = 0x20;
+ tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
+
+ if (2 != (rc = i2c_master_send(c,buffer,2)))
+ tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ break;
+ case TUNER_MICROTUNE_4042FI5:
+ {
// FIXME - this may also work for other tuners
unsigned long timeout = jiffies + msecs_to_jiffies(1);
u8 status_byte = 0;
@@ -324,10 +377,12 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
buffer[2] = config;
buffer[3] = cb;
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0],buffer[1],buffer[2],buffer[3]);
+ buffer[0],buffer[1],buffer[2],buffer[3]);
if (4 != (rc = i2c_master_send(c,buffer,4)))
tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+ break;
+ }
}
}
@@ -339,6 +394,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
u16 div;
int rc, j;
enum param_type desired_type = TUNER_PARAM_TYPE_RADIO;
+ struct tuner_params *params;
tun = &tuners[t->type];
@@ -352,7 +408,8 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
j = 0;
div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
- buffer[2] = (tun->params[j].ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
+ params = &tun->params[j];
+ buffer[2] = (params->ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
switch (t->type) {
case TUNER_TENA_9533_DI:
@@ -384,7 +441,7 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
}
buffer[0] = (div>>8) & 0x7f;
buffer[1] = div & 0xff;
- if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) {
+ if (params->cb_first_if_lower_freq && div < t->last_div) {
buffer[0] = buffer[2];
buffer[1] = buffer[3];
buffer[2] = (div>>8) & 0x7f;
@@ -398,6 +455,18 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
buffer[0],buffer[1],buffer[2],buffer[3]);
t->last_div = div;
+ if (params->has_tda9887) {
+ int config = 0;
+ if (params->port1_active && !params->port1_fm_high_sensitivity)
+ config |= TDA9887_PORT1_ACTIVE;
+ if (params->port2_active && !params->port2_fm_high_sensitivity)
+ config |= TDA9887_PORT2_ACTIVE;
+ if (params->intercarrier_mode)
+ config |= TDA9887_INTERCARRIER;
+/* if (params->port1_set_for_fm_mono)
+ config &= ~TDA9887_PORT1_ACTIVE;*/
+ i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
+ }
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/tuner-types.c b/drivers/media/video/tuner-types.c
index a1ae036b44e..8b542599ed4 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -380,6 +380,10 @@ static struct tuner_params tuner_philips_fq1216me_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_lg_pal_ranges,
.count = ARRAY_SIZE(tuner_lg_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_invert_for_secam_lc = 1,
},
};
@@ -542,6 +546,14 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = {
.ranges = tuner_fm1216me_mk3_pal_ranges,
.count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges),
.cb_first_if_lower_freq = 1,
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_invert_for_secam_lc = 1,
+ .port1_fm_high_sensitivity = 1,
+ .default_top_mid = -2,
+ .default_top_secam_mid = -2,
+ .default_top_secam_high = -2,
},
};
@@ -612,6 +624,10 @@ static struct tuner_params tuner_fm1236_mk3_params[] = {
.ranges = tuner_fm1236_mk3_ntsc_ranges,
.count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
.cb_first_if_lower_freq = 1,
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port1_fm_high_sensitivity = 1,
},
};
@@ -632,6 +648,8 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_temic_4009f_5_pal_ranges,
.count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_invert_for_secam_lc = 1,
},
};
@@ -648,6 +666,8 @@ static struct tuner_params tuner_panasonic_vp27_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_panasonic_vp27_ntsc_ranges,
.count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges),
+ .has_tda9887 = 1,
+ .intercarrier_mode = 1,
},
};
@@ -782,6 +802,13 @@ static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_fq12_6a___mk4_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_invert_for_secam_lc = 1,
+ .default_top_mid = -2,
+ .default_top_secam_low = -2,
+ .default_top_secam_mid = -2,
+ .default_top_secam_high = -2,
},
};
@@ -870,11 +897,17 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_fmd1216me_mk3_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_fm_high_sensitivity = 1,
+ .port2_invert_for_secam_lc = 1,
+ .port1_set_for_fm_mono = 1,
},
};
-/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
+/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
{ 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
@@ -883,7 +916,7 @@ static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
};
-static struct tuner_params tuner_tua6034_params[] = {
+static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tua6034_ntsc_ranges,
@@ -893,11 +926,17 @@ static struct tuner_params tuner_tua6034_params[] = {
/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
+static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = {
+ { 16 * 160.25 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 464.25 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
+};
+
static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_tena_9533_di_pal_ranges,
- .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges),
+ .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges,
+ .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges),
},
};
@@ -994,10 +1033,11 @@ static struct tuner_params tuner_tnf_5335mf_params[] = {
/* 70-79 */
/* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */
+/* '+ 4' turns on the Low Noise Amplifier */
static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = {
- { 16 * 130.00 /*MHz*/, 0xce, 0x01, },
- { 16 * 364.50 /*MHz*/, 0xce, 0x02, },
- { 16 * 999.99 , 0xce, 0x08, },
+ { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, },
+ { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, },
+ { 16 * 999.99 , 0xce, 0x08 + 4, },
};
static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
@@ -1005,6 +1045,7 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
.count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
+ .has_tda9887 = 1,
},
};
@@ -1024,6 +1065,27 @@ static struct tuner_params tuner_thomson_fe6600_params[] = {
},
};
+/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
+
+/* '+ 4' turns on the Low Noise Amplifier */
+static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
+ { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, },
+ { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, },
+ { 16 * 999.99 , 0xce, 0x08 + 4, },
+};
+
+static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
+ .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
+ .has_tda9887 = 1,
+ .port1_active = 1,
+ .port2_active = 1,
+ .port2_invert_for_secam_lc = 1,
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1354,10 +1416,10 @@ struct tunertype tuners[] = {
.params = tuner_philips_fmd1216me_mk3_params,
.count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
},
- [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
- .name = "LG TDVS-H062F/TUA6034",
- .params = tuner_tua6034_params,
- .count = ARRAY_SIZE(tuner_tua6034_params),
+ [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
+ .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */
+ .params = tuner_lg_tdvs_h06xf_params,
+ .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
},
[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
.name = "Ymec TVF66T5-B/DFF",
@@ -1400,6 +1462,16 @@ struct tunertype tuners[] = {
.params = tuner_thomson_fe6600_params,
.count = ARRAY_SIZE(tuner_thomson_fe6600_params),
},
+ [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
+ .name = "Samsung TCPG 6121P30A",
+ .params = tuner_samsung_tcpg_6121p30a_params,
+ .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
+ },
+ [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
+ This chip is part of some modern tuners */
+ .name = "Philips TDA988[5,6,7] IF PLL Demodulator",
+ /* see tda9887.c for details */
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index c2b75610754..936e3f746fb 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index b463e996961..d95529e8e51 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -73,14 +73,14 @@ static struct HAUPPAUGE_TUNER_FMT
}
hauppauge_tuner_fmt[] =
{
- { V4L2_STD_UNKNOWN," UNKNOWN" },
- { V4L2_STD_UNKNOWN," FM" },
- { V4L2_STD_PAL_BG, " PAL(B/G)" },
- { V4L2_STD_NTSC_M, " NTSC(M)" },
- { V4L2_STD_PAL_I, " PAL(I)" },
- { V4L2_STD_SECAM_L," SECAM(L/L')" },
- { V4L2_STD_PAL_DK, " PAL(D/D1/K)" },
- { V4L2_STD_ATSC, " ATSC/DVB Digital" },
+ { V4L2_STD_UNKNOWN, " UNKNOWN" },
+ { V4L2_STD_UNKNOWN, " FM" },
+ { V4L2_STD_B|V4L2_STD_GH, " PAL(B/G)" },
+ { V4L2_STD_MN, " NTSC(M)" },
+ { V4L2_STD_PAL_I, " PAL(I)" },
+ { V4L2_STD_SECAM_L|V4L2_STD_SECAM_LC, " SECAM(L/L')" },
+ { V4L2_STD_DK, " PAL(D/D1/K)" },
+ { V4L2_STD_ATSC, " ATSC/DVB Digital" },
};
/* This is the full list of possible tuners. Many thanks to Hauppauge for
@@ -200,7 +200,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Philips FQ1286A MK4"},
{ TUNER_ABSENT, "Philips FQ1216ME MK5"},
{ TUNER_ABSENT, "Philips FQ1236 MK5"},
- { TUNER_ABSENT, "Samsung TCPG_6121P30A"},
+ { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
{ TUNER_TCL_2002MB, "TCL 2002MB_3H"},
{ TUNER_ABSENT, "TCL 2002MI_3H"},
{ TUNER_TCL_2002N, "TCL 2002N 5H"},
@@ -219,7 +219,7 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Thompson DTT75105"},
{ TUNER_ABSENT, "Conexant_CX24109"},
{ TUNER_TCL_2002N, "TCL M2523_5N_E"},
- { TUNER_ABSENT, "TCL M2523_3DB_E"},
+ { TUNER_TCL_2002MB, "TCL M2523_3DB_E"},
{ TUNER_ABSENT, "Philips 8275A"},
{ TUNER_ABSENT, "Microtune MT2060"},
{ TUNER_ABSENT, "Philips FM1236 MK5"},
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index 9e86caeb96a..1654576de10 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -198,10 +198,6 @@ static int tvmixer_open(struct inode *inode, struct file *file)
/* lock bttv in memory while the mixer is in use */
file->private_data = mix;
-#ifndef I2C_PEC
- if (client->adapter->inc_use)
- client->adapter->inc_use(client->adapter);
-#endif
if (client->adapter->owner)
try_module_get(client->adapter->owner);
return 0;
@@ -217,10 +213,6 @@ static int tvmixer_release(struct inode *inode, struct file *file)
return -ENODEV;
}
-#ifndef I2C_PEC
- if (client->adapter->dec_use)
- client->adapter->dec_use(client->adapter);
-#endif
if (client->adapter->owner)
module_put(client->adapter->owner);
return 0;
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index dab4973bcf8..b167ffab252 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/video_decoder.h>
#include <media/v4l2-common.h>
+#include <media/tvp5150.h>
#include "tvp5150_reg.h"
@@ -89,7 +90,7 @@ struct tvp5150 {
struct i2c_client *client;
v4l2_std_id norm; /* Current set standard */
- int input;
+ struct v4l2_routing route;
int enable;
int bright;
int contrast;
@@ -283,29 +284,26 @@ static void dump_reg(struct i2c_client *c)
/****************************************************************************
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)
+static inline void tvp5150_selmux(struct i2c_client *c)
{
int opmode=0;
-
struct tvp5150 *decoder = i2c_get_clientdata(c);
+ int input = 0;
- if (!decoder->enable)
- input |= TVP5150_BLACK_SCREEN;
+ if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+ input = 8;
switch (input) {
- case TVP5150_ANALOG_CH0:
- case TVP5150_ANALOG_CH1:
+ case TVP5150_COMPOSITE1:
+ input |= 2;
+ /* fall through */
+ case TVP5150_COMPOSITE0:
opmode=0x30; /* TV Mode */
break;
+ case TVP5150_SVIDEO:
default:
+ input |= 1;
opmode=0; /* Auto Mode */
break;
}
@@ -790,7 +788,7 @@ static inline void tvp5150_reset(struct i2c_client *c)
tvp5150_vdp_init(c, vbi_ram_default);
/* Selects decoder input */
- tvp5150_selmux(c, decoder->input);
+ tvp5150_selmux(c);
/* Initializes TVP5150 to stream enabled values */
tvp5150_write_inittab(c, tvp5150_init_enable);
@@ -860,6 +858,21 @@ static int tvp5150_command(struct i2c_client *c,
case VIDIOC_INT_RESET:
tvp5150_reset(c);
break;
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *route = arg;
+
+ *route = decoder->route;
+ break;
+ }
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *route = arg;
+
+ decoder->route = *route;
+ tvp5150_selmux(c);
+ break;
+ }
case VIDIOC_S_STD:
if (decoder->norm == *(v4l2_std_id *)arg)
break;
@@ -1063,7 +1076,7 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
rv = i2c_attach_client(c);
core->norm = V4L2_STD_ALL; /* Default is autodetect */
- core->input = 2;
+ core->route.input = TVP5150_COMPOSITE1;
core->enable = 1;
core->bright = 32768;
core->contrast = 32768;
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
index 39269a2c563..a0fd82b924f 100644
--- a/drivers/media/video/usbvideo/Kconfig
+++ b/drivers/media/video/usbvideo/Kconfig
@@ -3,7 +3,7 @@ config VIDEO_USBVIDEO
config USB_VICAM
tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+ depends on USB && VIDEO_DEV && VIDEO_V4L1 && EXPERIMENTAL
select VIDEO_USBVIDEO
---help---
Say Y here if you have 3com homeconnect camera (vicam).
@@ -13,7 +13,7 @@ config USB_VICAM
config USB_IBMCAM
tristate "USB IBM (Xirlink) C-it Camera support"
- depends on USB && VIDEO_V4L1
+ depends on USB && VIDEO_DEV && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y here if you want to connect a IBM "C-It" camera, also known as
@@ -28,7 +28,7 @@ config USB_IBMCAM
config USB_KONICAWC
tristate "USB Konica Webcam support"
- depends on USB && VIDEO_V4L1
+ depends on USB && VIDEO_DEV && VIDEO_V4L1
select VIDEO_USBVIDEO
---help---
Say Y here if you want support for webcams based on a Konica
@@ -36,3 +36,15 @@ config USB_KONICAWC
To compile this driver as a module, choose M here: the
module will be called konicawc.
+
+config USB_QUICKCAM_MESSENGER
+ tristate "USB Logitech Quickcam Messenger"
+ depends on USB && VIDEO_DEV && VIDEO_V4L1
+ select VIDEO_USBVIDEO
+ ---help---
+ Say Y or M here to enable support for the USB Logitech Quickcam
+ Messenger webcam.
+
+ To compile this driver as a module, choose M here: the
+ module will be called quickcam_messenger.
+
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
index bb52eb8dc2f..4a1b144bee4 100644
--- a/drivers/media/video/usbvideo/Makefile
+++ b/drivers/media/video/usbvideo/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
obj-$(CONFIG_USB_KONICAWC) += konicawc.o
obj-$(CONFIG_USB_VICAM) += vicam.o
+obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
new file mode 100644
index 00000000000..56e01b62241
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -0,0 +1,1120 @@
+/*
+ * Driver for Logitech Quickcam Messenger usb video camera
+ * Copyright (C) Jaya Kumar
+ *
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ * History:
+ * 05/08/2006 - Jaya Kumar
+ * I wrote this based on the konicawc by Simon Evans.
+ * -
+ * Full credit for reverse engineering and creating an initial
+ * working linux driver for the VV6422 goes to the qce-ga project by
+ * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
+ * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
+ * others.
+ * ---
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb/input.h>
+
+#include "usbvideo.h"
+#include "quickcam_messenger.h"
+
+/*
+ * Version Information
+ */
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+ if (n <= debug) { \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ }
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define DRIVER_VERSION "v0.01"
+#define DRIVER_DESC "Logitech Quickcam Messenger USB"
+
+#define USB_LOGITECH_VENDOR_ID 0x046D
+#define USB_QCM_PRODUCT_ID 0x08F0
+
+#define MAX_CAMERAS 1
+
+#define MAX_COLOUR 32768
+#define MAX_HUE 32768
+#define MAX_BRIGHTNESS 32768
+#define MAX_CONTRAST 32768
+#define MAX_WHITENESS 32768
+
+static int size = SIZE_320X240;
+static int colour = MAX_COLOUR;
+static int hue = MAX_HUE;
+static int brightness = MAX_BRIGHTNESS;
+static int contrast = MAX_CONTRAST;
+static int whiteness = MAX_WHITENESS;
+
+static struct usbvideo *cams;
+
+static struct usb_device_id qcm_table [] = {
+ { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, qcm_table);
+
+#ifdef CONFIG_INPUT
+static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
+{
+ struct input_dev *input_dev;
+
+ usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+ strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+
+ cam->input = input_dev = input_allocate_device();
+ if (!input_dev) {
+ warn("insufficient mem for cam input device");
+ return;
+ }
+
+ input_dev->name = "QCM button";
+ input_dev->phys = cam->input_physname;
+ usb_to_input_id(dev, &input_dev->id);
+ input_dev->cdev.dev = &dev->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY);
+ input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+ input_dev->private = cam;
+
+ input_register_device(cam->input);
+}
+
+static void qcm_unregister_input(struct qcm *cam)
+{
+ if (cam->input) {
+ input_unregister_device(cam->input);
+ cam->input = NULL;
+ }
+}
+
+static void qcm_report_buttonstat(struct qcm *cam)
+{
+ if (cam->input) {
+ input_report_key(cam->input, BTN_0, cam->button_sts);
+ input_sync(cam->input);
+ }
+}
+
+static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
+{
+ int ret;
+ struct uvd *uvd = urb->context;
+ struct qcm *cam;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return;
+
+ if (!uvd->streaming)
+ return;
+
+ uvd->stats.urb_count++;
+
+ if (urb->status < 0)
+ uvd->stats.iso_err_count++;
+ else {
+ if (urb->actual_length > 0 ) {
+ cam = (struct qcm *) uvd->user_data;
+ if (cam->button_sts_buf == 0x88)
+ cam->button_sts = 0x0;
+ else if (cam->button_sts_buf == 0x80)
+ cam->button_sts = 0x1;
+ qcm_report_buttonstat(cam);
+ }
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ err("usb_submit_urb error (%d)", ret);
+}
+
+static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
+{
+ int errflag;
+ usb_fill_int_urb(cam->button_urb, uvd->dev,
+ usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
+ &cam->button_sts_buf,
+ 1,
+ qcm_int_irq,
+ uvd, 16);
+
+ errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
+ if (errflag)
+ err ("usb_submit_int ret %d", errflag);
+ return errflag;
+}
+
+static void qcm_stop_int_data(struct qcm *cam)
+{
+ usb_kill_urb(cam->button_urb);
+}
+
+static int qcm_alloc_int_urb(struct qcm *cam)
+{
+ cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!cam->button_urb)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void qcm_free_int(struct qcm *cam)
+{
+ if (cam->button_urb)
+ usb_free_urb(cam->button_urb);
+}
+#endif /* CONFIG_INPUT */
+
+static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ reg, 0, &val, 1, 3*HZ);
+ return ret;
+}
+
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ reg, 0, &val, 2, 3*HZ);
+ return ret;
+}
+
+static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
+ __le16 *val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+ reg, 0, val, 2, 3*HZ);
+ return ret;
+}
+
+static int qcm_camera_on(struct uvd *uvd)
+{
+ int ret;
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
+ return 0;
+}
+
+static int qcm_camera_off(struct uvd *uvd)
+{
+ int ret;
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+ return 0;
+}
+
+static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
+{
+ unsigned int segment, valsat;
+ signed int h = (signed int) hue;
+ unsigned int s = (sat - 32768) * 2; /* rescale */
+ unsigned int v = val;
+ unsigned int p;
+
+ /*
+ the registers controling gain are 8 bit of which
+ we affect only the last 4 bits with our gain.
+ we know that if saturation is 0, (unsaturated) then
+ we're grayscale (center axis of the colour cone) so
+ we set rgb=value. we use a formula obtained from
+ wikipedia to map the cone to the RGB plane. it's
+ as follows for the human value case of h=0..360,
+ s=0..1, v=0..1
+ h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
+ q = v(1 - f*s) , t = v(1 - (1-f)s)
+ h_i==0 => r=v , g=t, b=p
+ h_i==1 => r=q , g=v, b=p
+ h_i==2 => r=p , g=v, b=t
+ h_i==3 => r=p , g=q, b=v
+ h_i==4 => r=t , g=p, b=v
+ h_i==5 => r=v , g=p, b=q
+ the bottom side (the point) and the stuff just up
+ of that is black so we simplify those two cases.
+ */
+ if (sat < 32768) {
+ /* anything less than this is unsaturated */
+ *r = val;
+ *g = val;
+ *b = val;
+ return;
+ }
+ if (val <= (0xFFFF/8)) {
+ /* anything less than this is black */
+ *r = 0;
+ *g = 0;
+ *b = 0;
+ return;
+ }
+
+ /* the rest of this code is copying tukkat's
+ implementation of the hsv2rgb conversion as taken
+ from qc-usb-messenger code. the 10923 is 0xFFFF/6
+ to divide the cone into 6 sectors. */
+
+ segment = (h + 10923) & 0xFFFF;
+ segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */
+ hue -= segment * 21845; /* -10923..10923 */
+ h = hue;
+ h *= 3;
+ valsat = v*s >> 16; /* 0..65534 */
+ p = v - valsat;
+ if (h >= 0) {
+ unsigned int t = v - (valsat * (32769 - h) >> 15);
+ switch (segment) {
+ case 0: /* R-> */
+ *r = v;
+ *g = t;
+ *b = p;
+ break;
+ case 1: /* G-> */
+ *r = p;
+ *g = v;
+ *b = t;
+ break;
+ case 2: /* B-> */
+ *r = t;
+ *g = p;
+ *b = v;
+ break;
+ }
+ } else {
+ unsigned int q = v - (valsat * (32769 + h) >> 15);
+ switch (segment) {
+ case 0: /* ->R */
+ *r = v;
+ *g = p;
+ *b = q;
+ break;
+ case 1: /* ->G */
+ *r = q;
+ *g = v;
+ *b = p;
+ break;
+ case 2: /* ->B */
+ *r = p;
+ *g = q;
+ *b = v;
+ break;
+ }
+ }
+}
+
+static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
+ u16 saturation, u16 value)
+{
+ int ret;
+ u16 r=0,g=0,b=0;
+
+ /* this code is based on qc-usb-messenger */
+ qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
+
+ r >>= 12;
+ g >>= 12;
+ b >>= 12;
+
+ /* min val is 8 */
+ r = max((u16) 8, r);
+ g = max((u16) 8, g);
+ b = max((u16) 8, b);
+
+ r |= 0x30;
+ g |= 0x30;
+ b |= 0x30;
+
+ /* set the r,g,b gain registers */
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
+
+ /* doing as qc-usb did */
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+ return 0;
+}
+
+static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
+{
+ int ret;
+ int formedval;
+
+ /* calculation was from qc-usb-messenger driver */
+ formedval = ( exposure >> 12 );
+
+ /* max value for formedval is 14 */
+ formedval = min(formedval, 14);
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+ 0x143A, 0xF0 | formedval));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+ return 0;
+}
+
+static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
+ int hue, int colour)
+{
+ int ret;
+ /* brightness is exposure, contrast is gain, colour is saturation */
+ CHECK_RET(ret,
+ qcm_sensor_set_exposure(uvd, brightness));
+ CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
+
+ return 0;
+}
+
+static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
+{
+ int ret;
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
+ return 0;
+}
+
+static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
+{
+ int ret;
+ /* some rescaling as done by the qc-usb-messenger code */
+ if (whiteness > 0xC000)
+ whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
+ (whiteness >> 8) & 0xFF));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
+ (whiteness >> 16) & 0x03));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+ return 0;
+}
+
+static int qcm_sensor_init(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int ret;
+ int i;
+
+ for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+ regval_table[i].reg,
+ regval_table[i].val));
+ }
+
+ CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
+ cpu_to_le16(ISOC_PACKET_SIZE)));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
+ CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+ CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
+ uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
+
+ CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+ return 0;
+}
+
+static int qcm_set_camera_size(struct uvd *uvd)
+{
+ int ret;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+ cam->width = camera_sizes[cam->size].width;
+ cam->height = camera_sizes[cam->size].height;
+ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+ return 0;
+}
+
+static int qcm_setup_on_open(struct uvd *uvd)
+{
+ int ret;
+
+ CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
+ uvd->vpic.colour, uvd->vpic.contrast));
+ CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
+ CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+ CHECK_RET(ret, qcm_set_camera_size(uvd));
+ CHECK_RET(ret, qcm_camera_on(uvd));
+ return 0;
+}
+
+static void qcm_adjust_picture(struct uvd *uvd)
+{
+ int ret;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ ret = qcm_camera_off(uvd);
+ if (ret) {
+ err("can't turn camera off. abandoning pic adjustment");
+ return;
+ }
+
+ /* if there's been a change in contrast, hue, or
+ colour then we need to recalculate hsv in order
+ to update gains */
+ if ((cam->contrast != uvd->vpic.contrast) ||
+ (cam->hue != uvd->vpic.hue) ||
+ (cam->colour != uvd->vpic.colour)) {
+ cam->contrast = uvd->vpic.contrast;
+ cam->hue = uvd->vpic.hue;
+ cam->colour = uvd->vpic.colour;
+ ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
+ cam->contrast);
+ if (ret) {
+ err("can't set gains. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ if (cam->brightness != uvd->vpic.brightness) {
+ cam->brightness = uvd->vpic.brightness;
+ ret = qcm_sensor_set_exposure(uvd, cam->brightness);
+ if (ret) {
+ err("can't set exposure. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ if (cam->whiteness != uvd->vpic.whiteness) {
+ cam->whiteness = uvd->vpic.whiteness;
+ qcm_sensor_set_shutter(uvd, cam->whiteness);
+ if (ret) {
+ err("can't set shutter. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ ret = qcm_camera_on(uvd);
+ if (ret) {
+ err("can't reenable camera. pic adjustment failed");
+ return;
+ }
+}
+
+static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
+{
+ int datalen;
+ int totaldata;
+ struct framehdr {
+ __be16 id;
+ __be16 len;
+ };
+ struct framehdr *fhdr;
+
+ totaldata = 0;
+ while (framelen) {
+ fhdr = (struct framehdr *) cdata;
+ datalen = be16_to_cpu(fhdr->len);
+ framelen -= 4;
+ cdata += 4;
+
+ if ((fhdr->id) == cpu_to_be16(0x8001)) {
+ RingQueue_Enqueue(&uvd->dp, marker, 4);
+ totaldata += 4;
+ continue;
+ }
+ if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
+ RingQueue_Enqueue(&uvd->dp, cdata, datalen);
+ totaldata += datalen;
+ }
+ framelen -= datalen;
+ cdata += datalen;
+ }
+ return totaldata;
+}
+
+static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
+{
+ int totlen;
+ int i;
+ unsigned char *cdata;
+
+ totlen=0;
+ for (i = 0; i < dataurb->number_of_packets; i++) {
+ int n = dataurb->iso_frame_desc[i].actual_length;
+ int st = dataurb->iso_frame_desc[i].status;
+
+ cdata = dataurb->transfer_buffer +
+ dataurb->iso_frame_desc[i].offset;
+
+ if (st < 0) {
+ warn("Data error: packet=%d. len=%d. status=%d.",
+ i, n, st);
+ uvd->stats.iso_err_count++;
+ continue;
+ }
+ if (!n)
+ continue;
+
+ totlen += qcm_process_frame(uvd, cdata, n);
+ }
+ return totlen;
+}
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+ int ret;
+
+ urb->dev = uvd->dev;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ err("usb_submit_urb error (%d)", ret);
+}
+
+static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+ int len;
+ struct uvd *uvd = urb->context;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return;
+
+ if (!uvd->streaming)
+ return;
+
+ uvd->stats.urb_count++;
+
+ if (!urb->actual_length) {
+ resubmit_urb(uvd, urb);
+ return;
+ }
+
+ len = qcm_compress_iso(uvd, urb);
+ resubmit_urb(uvd, urb);
+ uvd->stats.urb_length = len;
+ uvd->stats.data_count += len;
+ if (len)
+ RingQueue_WakeUpInterruptible(&uvd->dp);
+}
+
+static int qcm_start_data(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int i;
+ int errflag;
+ int pktsz;
+ int err;
+
+ pktsz = uvd->iso_packet_len;
+ if (!CAMERA_IS_OPERATIONAL(uvd)) {
+ err("Camera is not operational");
+ return -EFAULT;
+ }
+
+ err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
+ if (err < 0) {
+ err("usb_set_interface error");
+ uvd->last_error = err;
+ return -EBUSY;
+ }
+
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ int j, k;
+ struct urb *urb = uvd->sbuf[i].urb;
+ urb->dev = uvd->dev;
+ urb->context = uvd;
+ urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
+ urb->interval = 1;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = uvd->sbuf[i].data;
+ urb->complete = qcm_isoc_irq;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+ for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = pktsz;
+ }
+ }
+
+ uvd->streaming = 1;
+ uvd->curframe = -1;
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+ if (errflag)
+ err ("usb_submit_isoc(%d) ret %d", i, errflag);
+ }
+
+ CHECK_RET(err, qcm_setup_input_int(cam, uvd));
+ CHECK_RET(err, qcm_camera_on(uvd));
+ return 0;
+}
+
+static void qcm_stop_data(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int i, j;
+ int ret;
+
+ if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+ return;
+
+ ret = qcm_camera_off(uvd);
+ if (ret)
+ warn("couldn't turn the cam off.");
+
+ uvd->streaming = 0;
+
+ /* Unschedule all of the iso td's */
+ for (i=0; i < USBVIDEO_NUMSBUF; i++)
+ usb_kill_urb(uvd->sbuf[i].urb);
+
+ qcm_stop_int_data(cam);
+
+ if (!uvd->remove_pending) {
+ /* Set packet size to 0 */
+ j = usb_set_interface(uvd->dev, uvd->iface,
+ uvd->ifaceAltInactive);
+ if (j < 0) {
+ err("usb_set_interface() error %d.", j);
+ uvd->last_error = j;
+ }
+ }
+}
+
+static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int x;
+ struct rgb *rgbL0;
+ struct rgb *rgbL1;
+ struct bayL0 *bayL0;
+ struct bayL1 *bayL1;
+ int hor,ver,hordel,verdel;
+ assert(frame != NULL);
+
+ switch (cam->size) {
+ case SIZE_160X120:
+ hor = 162; ver = 124; hordel = 1; verdel = 2;
+ break;
+ case SIZE_320X240:
+ default:
+ hor = 324; ver = 248; hordel = 2; verdel = 4;
+ break;
+ }
+
+ if (frame->scanstate == ScanState_Scanning) {
+ while (RingQueue_GetLength(&uvd->dp) >=
+ 4 + (hor*verdel + hordel)) {
+ if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
+ frame->curline = 0;
+ frame->scanstate = ScanState_Lines;
+ frame->frameState = FrameState_Grabbing;
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+ /*
+ * if we're starting, we need to discard the first
+ * 4 lines of y bayer data
+ * and the first 2 gr elements of x bayer data
+ */
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
+ (hor*verdel + hordel));
+ break;
+ }
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+ }
+ }
+
+ if (frame->scanstate == ScanState_Scanning)
+ return;
+
+ /* now we can start processing bayer data so long as we have at least
+ * 2 lines worth of data. this is the simplest demosaicing method that
+ * I could think of. I use each 2x2 bayer element without interpolation
+ * to generate 4 rgb pixels.
+ */
+ while ( frame->curline < cam->height &&
+ (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
+ /* get 2 lines of bayer for demosaicing
+ * into 2 lines of RGB */
+ RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
+ bayL0 = (struct bayL0 *) cam->scratch;
+ bayL1 = (struct bayL1 *) (cam->scratch + hor);
+ /* frame->curline is the rgb y line */
+ rgbL0 = (struct rgb *)
+ ( frame->data + (cam->width*3*frame->curline));
+ /* w/2 because we're already doing 2 pixels */
+ rgbL1 = rgbL0 + (cam->width/2);
+
+ for (x=0; x < cam->width; x+=2) {
+ rgbL0->r = bayL0->r;
+ rgbL0->g = bayL0->g;
+ rgbL0->b = bayL1->b;
+
+ rgbL0->r2 = bayL0->r;
+ rgbL0->g2 = bayL1->g;
+ rgbL0->b2 = bayL1->b;
+
+ rgbL1->r = bayL0->r;
+ rgbL1->g = bayL1->g;
+ rgbL1->b = bayL1->b;
+
+ rgbL1->r2 = bayL0->r;
+ rgbL1->g2 = bayL1->g;
+ rgbL1->b2 = bayL1->b;
+
+ rgbL0++;
+ rgbL1++;
+
+ bayL0++;
+ bayL1++;
+ }
+
+ frame->seqRead_Length += cam->width*3*2;
+ frame->curline += 2;
+ }
+ /* See if we filled the frame */
+ if (frame->curline == cam->height) {
+ frame->frameState = FrameState_Done_Hold;
+ frame->curline = 0;
+ uvd->curframe = -1;
+ uvd->stats.frame_num++;
+ }
+}
+
+/* taken from konicawc */
+static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+ int ret;
+ int newsize;
+ int oldsize;
+ int x = vw->width;
+ int y = vw->height;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ if (x > 0 && y > 0) {
+ DEBUG(2, "trying to find size %d,%d", x, y);
+ for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+ if ((camera_sizes[newsize].width == x) &&
+ (camera_sizes[newsize].height == y))
+ break;
+ }
+ } else
+ newsize = cam->size;
+
+ if (newsize > MAX_FRAME_SIZE) {
+ DEBUG(1, "couldn't find size %d,%d", x, y);
+ return -EINVAL;
+ }
+
+ if (newsize == cam->size) {
+ DEBUG(1, "Nothing to do");
+ return 0;
+ }
+
+ qcm_stop_data(uvd);
+
+ if (cam->size != newsize) {
+ oldsize = cam->size;
+ cam->size = newsize;
+ ret = qcm_set_camera_size(uvd);
+ if (ret) {
+ err("Couldn't set camera size, err=%d",ret);
+ /* restore the original size */
+ cam->size = oldsize;
+ return ret;
+ }
+ }
+
+ /* Flush the input queue and clear any current frame in progress */
+
+ RingQueue_Flush(&uvd->dp);
+ if (uvd->curframe != -1) {
+ uvd->frame[uvd->curframe].curline = 0;
+ uvd->frame[uvd->curframe].seqRead_Length = 0;
+ uvd->frame[uvd->curframe].seqRead_Index = 0;
+ }
+
+ CHECK_RET(ret, qcm_start_data(uvd));
+ return 0;
+}
+
+static int qcm_configure_video(struct uvd *uvd)
+{
+ int ret;
+ memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+ memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+ uvd->vpic.colour = colour;
+ uvd->vpic.hue = hue;
+ uvd->vpic.brightness = brightness;
+ uvd->vpic.contrast = contrast;
+ uvd->vpic.whiteness = whiteness;
+ uvd->vpic.depth = 24;
+ uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+ memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+ strcpy(uvd->vcap.name, "QCM USB Camera");
+ uvd->vcap.type = VID_TYPE_CAPTURE;
+ uvd->vcap.channels = 1;
+ uvd->vcap.audios = 0;
+
+ uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+ uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+ uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+ uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+ memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+ uvd->vchan.flags = 0 ;
+ uvd->vchan.tuners = 0;
+ uvd->vchan.channel = 0;
+ uvd->vchan.type = VIDEO_TYPE_CAMERA;
+ strcpy(uvd->vchan.name, "Camera");
+
+ CHECK_RET(ret, qcm_sensor_init(uvd));
+ return 0;
+}
+
+static int qcm_probe(struct usb_interface *intf,
+ const struct usb_device_id *devid)
+{
+ int err;
+ struct uvd *uvd;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct qcm *cam;
+ size_t buffer_size;
+ unsigned char video_ep;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ int i,j;
+ unsigned int ifacenum, ifacenum_inact=0;
+ __le16 sensor_id;
+
+ /* we don't support multiconfig cams */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+
+ /* first check for the video interface and not
+ * the audio interface */
+ interface = &intf->cur_altsetting[0];
+ if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+ || (interface->desc.bInterfaceSubClass !=
+ USB_CLASS_VENDOR_SPEC))
+ return -ENODEV;
+
+ /*
+ walk through each endpoint in each setting in the interface
+ stop when we find the one that's an isochronous IN endpoint.
+ */
+ for (i=0; i < intf->num_altsetting; i++) {
+ interface = &intf->cur_altsetting[i];
+ ifacenum = interface->desc.bAlternateSetting;
+ /* walk the end points */
+ for (j=0; j < interface->desc.bNumEndpoints; j++) {
+ endpoint = &interface->endpoint[j].desc;
+
+ if ((endpoint->bEndpointAddress &
+ USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+ continue; /* not input then not good */
+
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (!buffer_size) {
+ ifacenum_inact = ifacenum;
+ continue; /* 0 pkt size is not what we want */
+ }
+
+ if ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_ISOC) {
+ video_ep = endpoint->bEndpointAddress;
+ /* break out of the search */
+ goto good_videoep;
+ }
+ }
+ }
+ /* failed out since nothing useful was found */
+ err("No suitable endpoint was found\n");
+ return -ENODEV;
+
+good_videoep:
+ /* disable isochronous stream before doing anything else */
+ err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
+ if (err < 0) {
+ err("Failed to disable sensor stream");
+ return -EIO;
+ }
+
+ /*
+ Check that this is the same unknown sensor that is known to work. This
+ sensor is suspected to be the ST VV6422C001. I'll check the same value
+ that the qc-usb driver checks. This value is probably not even the
+ sensor ID since it matches the USB dev ID. Oh well. If it doesn't
+ match, it's probably a diff sensor so exit and apologize.
+ */
+ err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
+ if (err < 0) {
+ err("Couldn't read sensor values. Err %d\n",err);
+ return err;
+ }
+ if (sensor_id != cpu_to_le16(0x08F0)) {
+ err("Sensor ID %x != %x. Unsupported. Sorry\n",
+ le16_to_cpu(sensor_id), (0x08F0));
+ return -ENODEV;
+ }
+
+ uvd = usbvideo_AllocateDevice(cams);
+ if (!uvd)
+ return -ENOMEM;
+
+ cam = (struct qcm *) uvd->user_data;
+
+ /* buf for doing demosaicing */
+ cam->scratch = kmalloc(324*2, GFP_KERNEL);
+ if (!cam->scratch) /* uvd freed in dereg */
+ return -ENOMEM;
+
+ /* yes, if we fail after here, cam->scratch gets freed
+ by qcm_free_uvd */
+
+ err = qcm_alloc_int_urb(cam);
+ if (err < 0)
+ return err;
+
+ /* yes, if we fail after here, int urb gets freed
+ by qcm_free_uvd */
+
+ RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+ cam->width = camera_sizes[size].width;
+ cam->height = camera_sizes[size].height;
+ cam->size = size;
+
+ uvd->debug = debug;
+ uvd->flags = 0;
+ uvd->dev = dev;
+ uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+ uvd->ifaceAltActive = ifacenum;
+ uvd->ifaceAltInactive = ifacenum_inact;
+ uvd->video_endp = video_ep;
+ uvd->iso_packet_len = buffer_size;
+ uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+ uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+ uvd->canvas = VIDEOSIZE(320, 240);
+ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+ err = qcm_configure_video(uvd);
+ if (err) {
+ err("failed to configure video settings");
+ return err;
+ }
+
+ err = usbvideo_RegisterVideoDevice(uvd);
+ if (err) { /* the uvd gets freed in Deregister */
+ err("usbvideo_RegisterVideoDevice() failed.");
+ return err;
+ }
+
+ uvd->max_frame_size = (320 * 240 * 3);
+ qcm_register_input(cam, dev);
+ usb_set_intfdata(intf, uvd);
+ return 0;
+}
+
+static void qcm_free_uvd(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ kfree(cam->scratch);
+ qcm_unregister_input(cam);
+ qcm_free_int(cam);
+}
+
+static struct usbvideo_cb qcm_driver = {
+ .probe = qcm_probe,
+ .setupOnOpen = qcm_setup_on_open,
+ .processData = qcm_process_isoc,
+ .setVideoMode = qcm_set_video_mode,
+ .startDataPump = qcm_start_data,
+ .stopDataPump = qcm_stop_data,
+ .adjustPicture = qcm_adjust_picture,
+ .userFree = qcm_free_uvd
+};
+
+static int __init qcm_init(void)
+{
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ return usbvideo_register(
+ &cams,
+ MAX_CAMERAS,
+ sizeof(struct qcm),
+ "QCM",
+ &qcm_driver,
+ THIS_MODULE,
+ qcm_table);
+}
+
+static void __exit qcm_exit(void)
+{
+ usbvideo_Deregister(&cams);
+}
+
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
+module_param(colour, int, 0);
+MODULE_PARM_DESC(colour, "Initial colour");
+module_param(hue, int, 0);
+MODULE_PARM_DESC(hue, "Initial hue");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast");
+module_param(whiteness, int, 0);
+MODULE_PARM_DESC(whiteness, "Initial whiteness");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(qcm_init);
+module_exit(qcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_DESCRIPTION("QCM USB Camera");
+MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
new file mode 100644
index 00000000000..baab9c081b5
--- /dev/null
+++ b/drivers/media/video/usbvideo/quickcam_messenger.h
@@ -0,0 +1,126 @@
+#ifndef quickcam_messenger_h
+#define quickcam_messenger_h
+
+#ifndef CONFIG_INPUT
+/* if we're not using input we dummy out these functions */
+#define qcm_register_input(...)
+#define qcm_unregister_input(...)
+#define qcm_report_buttonstat(...)
+#define qcm_setup_input_int(...) 0
+#define qcm_stop_int_data(...)
+#define qcm_alloc_int_urb(...) 0
+#define qcm_free_int(...)
+#endif
+
+
+#define CHECK_RET(ret, expr) \
+ if ((ret = expr) < 0) return ret
+
+/* Control Registers for the STVV6422 ASIC
+ * - this define is taken from the qc-usb-messenger code
+ */
+#define STV_ISO_ENABLE 0x1440
+#define ISOC_PACKET_SIZE 1023
+
+/* Chip identification number including revision indicator */
+#define CMOS_SENSOR_IDREV 0xE00A
+
+struct rgb {
+ u8 b;
+ u8 g;
+ u8 r;
+ u8 b2;
+ u8 g2;
+ u8 r2;
+};
+
+struct bayL0 {
+#ifdef __BIG_ENDIAN
+ u8 r;
+ u8 g;
+#elif __LITTLE_ENDIAN
+ u8 g;
+ u8 r;
+#else
+#error not byte order defined
+#endif
+};
+
+struct bayL1 {
+#ifdef __BIG_ENDIAN
+ u8 g;
+ u8 b;
+#elif __LITTLE_ENDIAN
+ u8 b;
+ u8 g;
+#else
+#error not byte order defined
+#endif
+};
+
+struct cam_size {
+ u16 width;
+ u16 height;
+ u8 cmd;
+};
+
+static const struct cam_size camera_sizes[] = {
+ { 160, 120, 0xf },
+ { 320, 240, 0x2 },
+};
+
+enum frame_sizes {
+ SIZE_160X120 = 0,
+ SIZE_320X240 = 1,
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+struct qcm {
+ u16 colour;
+ u16 hue;
+ u16 brightness;
+ u16 contrast;
+ u16 whiteness;
+
+ u8 size;
+ int height;
+ int width;
+ u8 *scratch;
+ struct urb *button_urb;
+ u8 button_sts;
+ u8 button_sts_buf;
+
+#ifdef CONFIG_INPUT
+ struct input_dev *input;
+ char input_physname[64];
+#endif
+};
+
+struct regval {
+ u16 reg;
+ u8 val;
+};
+/* this table is derived from the
+qc-usb-messenger code */
+static const struct regval regval_table[] = {
+ { STV_ISO_ENABLE, 0x00 },
+ { 0x1436, 0x00 }, { 0x1432, 0x03 },
+ { 0x143a, 0xF9 }, { 0x0509, 0x38 },
+ { 0x050a, 0x38 }, { 0x050b, 0x38 },
+ { 0x050c, 0x2A }, { 0x050d, 0x01 },
+ { 0x1431, 0x00 }, { 0x1433, 0x34 },
+ { 0x1438, 0x18 }, { 0x1439, 0x00 },
+ { 0x143b, 0x05 }, { 0x143c, 0x00 },
+ { 0x143e, 0x01 }, { 0x143d, 0x00 },
+ { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
+ { 0x1500, 0xd0 }, { 0x1500, 0x50 },
+ { 0x1501, 0xaf }, { 0x1502, 0xc2 },
+ { 0x1503, 0x45 }, { 0x1505, 0x02 },
+ { 0x150e, 0x8e }, { 0x150f, 0x37 },
+ { 0x15c0, 0x00 },
+};
+
+static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
+
+#endif /* quickcam_messenger_h */
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h
index 3cbf4fc499a..051775d4c72 100644
--- a/drivers/media/video/usbvideo/usbvideo.h
+++ b/drivers/media/video/usbvideo/usbvideo.h
@@ -16,8 +16,8 @@
#ifndef usbvideo_h
#define usbvideo_h
-#include <linux/config.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 474a29bc176..d7c3fcbc80f 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -16,7 +16,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -32,6 +31,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -599,6 +599,10 @@ v4l_compat_translate_ioctl(struct inode *inode,
dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err);
break;
}
+
+ pict->depth = ((fmt2->fmt.pix.bytesperline<<3)
+ + (fmt2->fmt.pix.width-1) )
+ /fmt2->fmt.pix.width;
pict->palette = pixelformat_to_palette(
fmt2->fmt.pix.pixelformat);
break;
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index d330fa985bc..8d972ffdaf9 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -44,7 +44,6 @@
* Added Gerd Knorrs v4l1 enhancements (Justin Schoeman)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -59,6 +58,7 @@
#include <asm/io.h>
#include <asm/div64.h>
#include <linux/video_decoder.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#ifdef CONFIG_KMOD
@@ -202,7 +202,7 @@ static char *v4l2_memory_names[] = {
/* ------------------------------------------------------------------ */
/* debug help functions */
-#ifdef HAVE_V4L1
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
static const char *v4l1_ioctls[] = {
[_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
[_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
@@ -293,12 +293,15 @@ static const char *v4l2_ioctls[] = {
#if 1
[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
#endif
- [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS"
+ [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
+ [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS"
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
static const char *v4l2_int_ioctls[] = {
-#ifdef HAVE_VIDEO_DECODER
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
[_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES",
[_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS",
[_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM",
@@ -331,7 +334,8 @@ static const char *v4l2_int_ioctls[] = {
[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
- [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING"
+ [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ"
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
@@ -363,7 +367,7 @@ void v4l_printk_ioctl(unsigned int cmd)
(_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
break;
-#ifdef HAVE_V4L1
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case 'v':
printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
(_IOC_NR(cmd) < V4L1_IOCTLS) ?
@@ -410,6 +414,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: tuner type=%d\n", s, *p);
break;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case DECODER_SET_VBI_BYPASS:
case DECODER_ENABLE_OUTPUT:
case DECODER_GET_STATUS:
@@ -420,10 +425,13 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOCCAPTURE:
case VIDIOCSYNC:
case VIDIOCSWRITEMODE:
+#endif
case TUNER_SET_TYPE_ADDR:
case TUNER_SET_STANDBY:
case TDA9887_SET_CONFIG:
+#ifdef __OLD_VIDIOC_
case VIDIOC_OVERLAY_OLD:
+#endif
case VIDIOC_STREAMOFF:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
@@ -439,7 +447,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOC_G_AUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_ENUMAUDIO:
+#ifdef __OLD_VIDIOC_
case VIDIOC_G_AUDIO_OLD:
+#endif
{
struct v4l2_audio *p=arg;
@@ -450,7 +460,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOC_G_AUDOUT:
case VIDIOC_S_AUDOUT:
case VIDIOC_ENUMAUDOUT:
+#ifdef __OLD_VIDIOC_
case VIDIOC_G_AUDOUT_OLD:
+#endif
{
struct v4l2_audioout *p=arg;
printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
@@ -478,9 +490,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
prt_names(p->memory,v4l2_memory_names),
p->m.userptr);
printk ("%s: timecode= %02d:%02d:%02d type=%d, "
- "flags=0x%08x, frames=%d, userbits=0x%p\n",
+ "flags=0x%08x, frames=%d, userbits=0x%08x\n",
s,tc->hours,tc->minutes,tc->seconds,
- tc->type, tc->flags, tc->frames, tc->userbits);
+ tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
break;
}
case VIDIOC_QUERYCAP:
@@ -495,12 +507,31 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
}
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
+#ifdef __OLD_VIDIOC_
case VIDIOC_S_CTRL_OLD:
+#endif
{
struct v4l2_control *p=arg;
printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
break;
}
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+ int i;
+
+ printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
+ for (i = 0; i < p->count; i++) {
+ struct v4l2_ext_control *c = &p->controls[i];
+ if (cmd == VIDIOC_G_EXT_CTRLS)
+ printk("%s: id=%d\n", s, c->id);
+ else
+ printk("%s: id=%d, value=%d\n", s, c->id, c->value);
+ }
+ break;
+ }
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
{
@@ -510,7 +541,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
break;
}
case VIDIOC_CROPCAP:
+#ifdef __OLD_VIDIOC_
case VIDIOC_CROPCAP_OLD:
+#endif
{
struct v4l2_cropcap *p=arg;
/*FIXME: Should also show rect structs */
@@ -667,6 +700,12 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
break;
}
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *p=arg;
+ printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
+ break;
+ }
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *p=arg;
@@ -696,7 +735,9 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
}
case VIDIOC_G_PARM:
case VIDIOC_S_PARM:
+#ifdef __OLD_VIDIOC_
case VIDIOC_S_PARM_OLD:
+#endif
{
struct v4l2_streamparm *p=arg;
printk ("%s: type=%d\n", s, p->type);
@@ -716,6 +757,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
p->afc);
break;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGVBIFMT:
case VIDIOCSVBIFMT:
{
@@ -885,6 +927,14 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
p->clipcount);
break;
}
+ case VIDIOCGFREQ:
+ case VIDIOCSFREQ:
+ {
+ unsigned long *p=arg;
+ printk ("%s: value=%lu\n", s, *p);
+ break;
+ }
+#endif
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
case VIDIOC_INT_I2S_CLOCK_FREQ:
case VIDIOC_INT_S_STANDBY:
@@ -894,13 +944,6 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
printk ("%s: value=%d\n", s, *p);
break;
}
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- {
- unsigned long *p=arg;
- printk ("%s: value=%lu\n", s, *p);
- break;
- }
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_QUERYSTD:
@@ -915,6 +958,498 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
/* ----------------------------------------------------------------- */
+/* Helper functions for control handling */
+
+/* Check for correctness of the ctrl's value based on the data from
+ struct v4l2_queryctrl and the available menu items. Note that
+ menu_items may be NULL, in that case it is ignored. */
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char **menu_items)
+{
+ if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+ if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+ qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return 0;
+ if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+ return -ERANGE;
+ if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+ if (menu_items[ctrl->value] == NULL ||
+ menu_items[ctrl->value][0] == '\0')
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Returns NULL or a character pointer array containing the menu for
+ the given control ID. The pointer array ends with a NULL pointer.
+ An empty string signifies a menu entry that is invalid. This allows
+ drivers to disable certain options if it is not supported. */
+const char **v4l2_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_audio_sampling_freq[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz",
+ NULL
+ };
+ static const char *mpeg_audio_encoding[] = {
+ "Layer I",
+ "Layer II",
+ "Layer III",
+ NULL
+ };
+ static const char *mpeg_audio_l1_bitrate[] = {
+ "32 kbps",
+ "64 kbps",
+ "96 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "288 kbps",
+ "320 kbps",
+ "352 kbps",
+ "384 kbps",
+ "416 kbps",
+ "448 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l2_bitrate[] = {
+ "32 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_mode[] = {
+ "Stereo",
+ "Joint Stereo",
+ "Dual",
+ "Mono",
+ NULL
+ };
+ static const char *mpeg_audio_mode_extension[] = {
+ "Bound 4",
+ "Bound 8",
+ "Bound 12",
+ "Bound 16",
+ NULL
+ };
+ static const char *mpeg_audio_emphasis[] = {
+ "No Emphasis",
+ "50/15 us",
+ "CCITT J17",
+ NULL
+ };
+ static const char *mpeg_audio_crc[] = {
+ "No CRC",
+ "16-bit CRC",
+ NULL
+ };
+ static const char *mpeg_video_encoding[] = {
+ "MPEG-1",
+ "MPEG-2",
+ NULL
+ };
+ static const char *mpeg_video_aspect[] = {
+ "1x1",
+ "4x3",
+ "16x9",
+ "2.21x1",
+ NULL
+ };
+ static const char *mpeg_video_bitrate_mode[] = {
+ "Variable Bitrate",
+ "Constant Bitrate",
+ NULL
+ };
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+ static const char *mpeg_stream_vbi_fmt[] = {
+ "No VBI",
+ "Private packet, IVTV format",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return mpeg_audio_sampling_freq;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return mpeg_audio_encoding;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return mpeg_audio_l1_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return mpeg_audio_l2_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return mpeg_audio_mode;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return mpeg_audio_mode_extension;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return mpeg_audio_emphasis;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return mpeg_audio_crc;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return mpeg_video_encoding;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return mpeg_video_aspect;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return mpeg_video_bitrate_mode;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ return mpeg_stream_vbi_fmt;
+ default:
+ return NULL;
+ }
+}
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ qctrl->flags = 0;
+ switch (qctrl->id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS: name = "User Controls"; break;
+ case V4L2_CID_AUDIO_VOLUME: name = "Volume"; break;
+ case V4L2_CID_AUDIO_MUTE: name = "Mute"; break;
+ case V4L2_CID_AUDIO_BALANCE: name = "Balance"; break;
+ case V4L2_CID_AUDIO_BASS: name = "Bass"; break;
+ case V4L2_CID_AUDIO_TREBLE: name = "Treble"; break;
+ case V4L2_CID_AUDIO_LOUDNESS: name = "Loudness"; break;
+ case V4L2_CID_BRIGHTNESS: name = "Brightness"; break;
+ case V4L2_CID_CONTRAST: name = "Contrast"; break;
+ case V4L2_CID_SATURATION: name = "Saturation"; break;
+ case V4L2_CID_HUE: name = "Hue"; break;
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CLASS: name = "MPEG Encoder Controls"; break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING: name = "Audio Encoding Layer"; break;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: name = "Audio Layer I Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: name = "Audio Layer II Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: name = "Audio Layer III Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_MODE: name = "Audio Stereo Mode"; break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break;
+ case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: name = "Video GOP Size"; break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: name = "Video GOP Closure"; break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: name = "Video Pulldown"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: name = "Video Bitrate Mode"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
+ case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break;
+ case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: name = "Stream Video Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
+ case V4L2_CID_MPEG_STREAM_VBI_FMT: name = "Stream VBI Format"; break;
+
+ default:
+ return -EINVAL;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ min = 0;
+ max = step = 1;
+ break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ step = 1;
+ break;
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ min = max = step = def = 0;
+ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ snprintf(qctrl->name, sizeof(qctrl->name), name);
+ return 0;
+}
+
+/* Fill in a struct v4l2_queryctrl with standard values based on
+ the control ID. */
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
+{
+ switch (qctrl->id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L1_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
+ V4L2_MPEG_AUDIO_L1_BITRATE_256K);
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L3_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
+ V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_STEREO,
+ V4L2_MPEG_AUDIO_MODE_MONO, 1,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_CRC_NONE,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE,
+ V4L2_MPEG_STREAM_VBI_FMT_IVTV, 1,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+ the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
+ const char **menu_items)
+{
+ int i;
+
+ if (menu_items == NULL ||
+ (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
+ return -EINVAL;
+ for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+ if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+ return -EINVAL;
+ snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
+ qmenu->reserved = 0;
+ return 0;
+}
+
+/* ctrl_classes points to an array of u32 pointers, the last element is
+ a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+ Each array must be sorted low to high and belong to the same control
+ class. The array of u32 pointer must also be sorted, from low class IDs
+ to high class IDs.
+
+ This function returns the first ID that follows after the given ID.
+ When no more controls are available 0 is returned. */
+u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
+{
+ u32 ctrl_class;
+ const u32 *pctrl;
+
+ /* if no query is desired, then just return the control ID */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
+ return id;
+ if (ctrl_classes == NULL)
+ return 0;
+ id &= V4L2_CTRL_ID_MASK;
+ ctrl_class = V4L2_CTRL_ID2CLASS(id);
+ id++; /* select next control */
+ /* find first class that matches (or is greater than) the class of
+ the ID */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
+ ctrl_classes++;
+ /* no more classes */
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find first ctrl within the class that is >= ID */
+ while (*pctrl && *pctrl < id) pctrl++;
+ if (*pctrl)
+ return *pctrl;
+ /* we are at the end of the controls of the current class. */
+ /* continue with next class if available */
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ return **ctrl_classes;
+}
+
+/* ----------------------------------------------------------------- */
+
EXPORT_SYMBOL(v4l2_video_std_construct);
EXPORT_SYMBOL(v4l2_prio_init);
@@ -929,6 +1464,13 @@ EXPORT_SYMBOL(v4l2_type_names);
EXPORT_SYMBOL(v4l_printk_ioctl);
EXPORT_SYMBOL(v4l_printk_ioctl_arg);
+EXPORT_SYMBOL(v4l2_ctrl_next);
+EXPORT_SYMBOL(v4l2_ctrl_check);
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index caf3e7e2f21..7ee8a53cd33 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -135,14 +135,15 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
- void *adapter_priv)
+ void *adapter_priv,
+ struct device *device)
{
int result;
mutex_init(&dvb->lock);
/* register adapter */
- result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
+ result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
dvb->name, result);
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index 8f271de57fd..2ae3fb25063 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -36,7 +36,6 @@
#include <linux/slab.h>
// kernel config is here (procfs flag)
-#include <linux/config.h>
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
diff --git a/drivers/media/video/videocodec.h b/drivers/media/video/videocodec.h
index 8c233720b6a..97a3bbeda50 100644
--- a/drivers/media/video/videocodec.h
+++ b/drivers/media/video/videocodec.h
@@ -222,14 +222,14 @@ M zr36055[1] 0001 0000c001 00000000 (zr36050[1])
/* ========================= */
struct vfe_polarity {
- int vsync_pol:1;
- int hsync_pol:1;
- int field_pol:1;
- int blank_pol:1;
- int subimg_pol:1;
- int poe_pol:1;
- int pvalid_pol:1;
- int vclk_pol:1;
+ unsigned int vsync_pol:1;
+ unsigned int hsync_pol:1;
+ unsigned int field_pol:1;
+ unsigned int blank_pol:1;
+ unsigned int subimg_pol:1;
+ unsigned int poe_pol:1;
+ unsigned int pvalid_pol:1;
+ unsigned int vclk_pol:1;
};
struct vfe_settings {
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 5f87dd5f1d0..edd7b83c346 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -1,20 +1,31 @@
/*
- * Video capture interface for Linux
+ * Video capture interface for Linux version 2
*
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
*
- * 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 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.
*
- * Author: Alan Cox, <alan@redhat.com>
+ * Authors: Alan Cox, <alan@redhat.com> (version 1)
+ * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
*
* Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
* - Added procfs support
*/
+#define dbgarg(cmd, fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk (KERN_DEBUG "%s: ", vfd->name); \
+ v4l_printk_ioctl(cmd); \
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
+#define dbgarg2(fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -26,11 +37,16 @@
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
+#include <linux/videodev2.h>
+
+#ifdef CONFIG_VIDEO_V4L1
#include <linux/videodev.h>
+#endif
+#include <media/v4l2-common.h>
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
@@ -41,7 +57,8 @@
static ssize_t show_name(struct class_device *cd, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
}
@@ -62,7 +79,8 @@ void video_device_release(struct video_device *vfd)
static void video_release(struct class_device *cd)
{
- struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
#if 1
/* needed until all drivers are fixed */
@@ -90,7 +108,7 @@ struct video_device* video_devdata(struct file *file)
}
/*
- * Open a video device.
+ * Open a video device - FIXME: Obsoleted
*/
static int video_open(struct inode *inode, struct file *file)
{
@@ -130,6 +148,7 @@ static int video_open(struct inode *inode, struct file *file)
* helper function -- handles userspace copying for ioctl arguments
*/
+#ifdef __OLD_VIDIOC_
static unsigned int
video_fix_command(unsigned int cmd)
{
@@ -155,7 +174,11 @@ video_fix_command(unsigned int cmd)
}
return cmd;
}
+#endif
+/*
+ * Obsolete usercopy function - Should be removed soon
+ */
int
video_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
@@ -166,8 +189,15 @@ video_usercopy(struct inode *inode, struct file *file,
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+#ifdef __OLD_VIDIOC_
cmd = video_fix_command(cmd);
+#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
@@ -193,14 +223,43 @@ video_usercopy(struct inode *inode, struct file *file,
goto out;
break;
}
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ /* In case of an error, tell the caller that it wasn't
+ a specific control that caused it. */
+ p->error_idx = p->count;
+ user_ptr = (void __user *)p->controls;
+ if (p->count) {
+ ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+ /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+ mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_ext_ctrl;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, ctrls_size))
+ goto out_ext_ctrl;
+ p->controls = mbuf;
+ }
+ }
/* call driver */
err = func(inode, file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ p->controls = (void *)user_ptr;
+ if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ err = -EFAULT;
+ goto out_ext_ctrl;
+ }
if (err < 0)
goto out;
+out_ext_ctrl:
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
@@ -218,6 +277,7 @@ out:
/*
* open/release helper functions -- handle exclusive opens
+ * Should be removed soon
*/
int video_exclusive_open(struct inode *inode, struct file *file)
{
@@ -242,6 +302,1184 @@ int video_exclusive_release(struct inode *inode, struct file *file)
return 0;
}
+static char *v4l2_memory_names[] = {
+ [V4L2_MEMORY_MMAP] = "mmap",
+ [V4L2_MEMORY_USERPTR] = "userptr",
+ [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+
+/* FIXME: Those stuff are replicated also on v4l2-common.c */
+static char *v4l2_type_names_FIXME[] = {
+ [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
+ [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
+ [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
+ [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
+ [V4L2_BUF_TYPE_PRIVATE] = "private",
+};
+
+static char *v4l2_field_names_FIXME[] = {
+ [V4L2_FIELD_ANY] = "any",
+ [V4L2_FIELD_NONE] = "none",
+ [V4L2_FIELD_TOP] = "top",
+ [V4L2_FIELD_BOTTOM] = "bottom",
+ [V4L2_FIELD_INTERLACED] = "interlaced",
+ [V4L2_FIELD_SEQ_TB] = "seq-tb",
+ [V4L2_FIELD_SEQ_BT] = "seq-bt",
+ [V4L2_FIELD_ALTERNATE] = "alternate",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
+static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+ struct v4l2_buffer *p)
+{
+ struct v4l2_timecode *tc=&p->timecode;
+
+ dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+ "bytesused=%d, flags=0x%08d, "
+ "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+ (p->timestamp.tv_sec/3600),
+ (int)(p->timestamp.tv_sec/60)%60,
+ (int)(p->timestamp.tv_sec%60),
+ p->timestamp.tv_usec,
+ p->index,
+ prt_names(p->type,v4l2_type_names_FIXME),
+ p->bytesused,p->flags,
+ p->field,p->sequence,
+ prt_names(p->memory,v4l2_memory_names),
+ p->m.userptr);
+ dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+ "flags=0x%08d, frames=%d, userbits=0x%08x\n",
+ tc->hours,tc->minutes,tc->seconds,
+ tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
+}
+
+static inline void dbgrect(struct video_device *vfd, char *s,
+ struct v4l2_rect *r)
+{
+ dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+ r->width, r->height);
+};
+
+static inline void v4l_print_pix_fmt (struct video_device *vfd,
+ struct v4l2_pix_format *fmt)
+{
+ dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+ "bytesperline=%d sizeimage=%d, colorspace=%d\n",
+ fmt->width,fmt->height,fmt->pixelformat,
+ prt_names(fmt->field,v4l2_field_names_FIXME),
+ fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
+
+static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_try_fmt_cap)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_try_fmt_overlay)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_capture)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_video_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_try_fmt_type_private)
+ return (0);
+ break;
+ }
+ return (-EINVAL);
+}
+
+static int __video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vfd = video_devdata(file);
+ void *fh = file->private_data;
+ int ret = -EINVAL;
+
+ if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
+ !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) {
+ v4l_print_ioctl(vfd->name, cmd);
+ }
+
+ switch(cmd) {
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+ memset(cap, 0, sizeof(*cap));
+
+ if (!vfd->vidioc_querycap)
+ break;
+
+ ret=vfd->vidioc_querycap(file, fh, cap);
+ if (!ret)
+ dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
+ "version=0x%08x, "
+ "capabilities=0x%08x\n",
+ cap->driver,cap->card,cap->bus_info,
+ cap->version,
+ cap->capabilities);
+ break;
+ }
+
+ /* --- priority ------------------------------------------ */
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+
+ if (!vfd->vidioc_g_priority)
+ break;
+ ret=vfd->vidioc_g_priority(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "priority is %d\n", *p);
+ break;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+
+ if (!vfd->vidioc_s_priority)
+ break;
+ dbgarg(cmd, "setting priority to %d\n", *p);
+ ret=vfd->vidioc_s_priority(file, fh, *p);
+ break;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ enum v4l2_buf_type type;
+ unsigned int index;
+
+ index = f->index;
+ type = f->type;
+ memset(f,0,sizeof(*f));
+ f->index = index;
+ f->type = type;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_enum_fmt_cap)
+ ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_enum_fmt_overlay)
+ ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_enum_fmt_vbi)
+ ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_enum_fmt_vbi_output)
+ ret=vfd->vidioc_enum_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_enum_fmt_vbi_capture)
+ ret=vfd->vidioc_enum_fmt_vbi_capture(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_enum_fmt_video_output)
+ ret=vfd->vidioc_enum_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_enum_fmt_vbi_output)
+ ret=vfd->vidioc_enum_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_enum_fmt_type_private)
+ ret=vfd->vidioc_enum_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+ if (!ret)
+ dbgarg (cmd, "index=%d, type=%d, flags=%d, "
+ "description=%s,"
+ " pixelformat=0x%8x\n",
+ f->index, f->type, f->flags,
+ f->description,
+ f->pixelformat);
+
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+ enum v4l2_buf_type type=f->type;
+
+ memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+ f->type=type;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(type,
+ v4l2_type_names_FIXME));
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_g_fmt_cap)
+ ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_g_fmt_overlay)
+ ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi)
+ ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_vbi_output)
+ ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi_capture)
+ ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_g_fmt_video_output)
+ ret=vfd->vidioc_g_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_vbi_output)
+ ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_g_fmt_type_private)
+ ret=vfd->vidioc_g_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(f->type,
+ v4l2_type_names_FIXME));
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ if (vfd->vidioc_s_fmt_cap)
+ ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_s_fmt_overlay)
+ ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi)
+ ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_vbi_output)
+ ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi_capture)
+ ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_s_fmt_video_output)
+ ret=vfd->vidioc_s_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_vbi_output)
+ ret=vfd->vidioc_s_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_s_fmt_type_private)
+ ret=vfd->vidioc_s_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(f->type,
+ v4l2_type_names_FIXME));
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_try_fmt_cap)
+ ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_try_fmt_overlay)
+ ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi)
+ ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ ret=vfd->vidioc_try_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_capture)
+ ret=vfd->vidioc_try_fmt_vbi_capture(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_video_output)
+ ret=vfd->vidioc_try_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ ret=vfd->vidioc_try_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_try_fmt_type_private)
+ ret=vfd->vidioc_try_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+
+ break;
+ }
+ /* FIXME: Those buf reqs could be handled here,
+ with some changes on videobuf to allow its header to be included at
+ videodev2.h or being merged at videodev2.
+ */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *p=arg;
+
+ if (!vfd->vidioc_reqbufs)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_reqbufs(file, fh, p);
+ dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
+ p->count,
+ prt_names(p->type,v4l2_type_names_FIXME),
+ prt_names(p->memory,v4l2_memory_names));
+ break;
+ }
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *p=arg;
+
+ if (!vfd->vidioc_querybuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_querybuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *p=arg;
+
+ if (!vfd->vidioc_qbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_qbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *p=arg;
+ if (!vfd->vidioc_qbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_qbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_OVERLAY:
+ {
+ int *i = arg;
+
+ if (!vfd->vidioc_overlay)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_overlay(file, fh, *i);
+ break;
+ }
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf *p=arg;
+
+ memset(p,0,sizeof(p));
+
+ if (!vfd->vidiocgmbuf)
+ break;
+ ret=vfd->vidiocgmbuf(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
+ p->size, p->frames,
+ (unsigned long)p->offsets);
+ break;
+ }
+#endif
+ case VIDIOC_G_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ if (!vfd->vidioc_g_fbuf)
+ break;
+ ret=vfd->vidioc_g_fbuf(file, fh, arg);
+ if (!ret) {
+ dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+ p->capability,p->flags,
+ (unsigned long)p->base);
+ v4l_print_pix_fmt (vfd, &p->fmt);
+ }
+ break;
+ }
+ case VIDIOC_S_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ if (!vfd->vidioc_s_fbuf)
+ break;
+
+ dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+ p->capability,p->flags,(unsigned long)p->base);
+ v4l_print_pix_fmt (vfd, &p->fmt);
+ ret=vfd->vidioc_s_fbuf(file, fh, arg);
+
+ break;
+ }
+ case VIDIOC_STREAMON:
+ {
+ enum v4l2_buf_type i = *(int *)arg;
+ if (!vfd->vidioc_streamon)
+ break;
+ dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ ret=vfd->vidioc_streamon(file, fh,i);
+ break;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ enum v4l2_buf_type i = *(int *)arg;
+
+ if (!vfd->vidioc_streamoff)
+ break;
+ dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ ret=vfd->vidioc_streamoff(file, fh, i);
+ break;
+ }
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *p = arg;
+ unsigned int index = p->index;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ if (index < 0 || index >= vfd->tvnormsize) {
+ ret=-EINVAL;
+ break;
+ }
+ v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
+ vfd->tvnorms[p->index].name);
+ p->index = index;
+
+ dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+ "framelines=%d\n", p->index,
+ (unsigned long long)p->id, p->name,
+ p->frameperiod.numerator,
+ p->frameperiod.denominator,
+ p->framelines);
+
+ ret=0;
+ break;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = vfd->current_norm;
+
+ dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+ ret=0;
+ break;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+ /* First search for exact match */
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (*id == vfd->tvnorms[i].id)
+ break;
+ /* Then for a generic video std that contains desired std */
+ if (i == vfd->tvnormsize)
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (*id & vfd->tvnorms[i].id)
+ break;
+ if (i == vfd->tvnormsize) {
+ break;
+ }
+
+ /* Calls the specific handler */
+ if (vfd->vidioc_s_std)
+ ret=vfd->vidioc_s_std(file, fh, i);
+ else
+ ret=-EINVAL;
+
+ /* Updates standard information */
+ if (!ret)
+ vfd->current_norm=*id;
+
+ break;
+ }
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *p=arg;
+
+ if (!vfd->vidioc_querystd)
+ break;
+ ret=vfd->vidioc_querystd(file, fh, arg);
+ if (!ret)
+ dbgarg (cmd, "detected std=%Lu\n",
+ (unsigned long long)*p);
+ break;
+ }
+ /* ------ input switching ---------- */
+ /* FIXME: Inputs can be handled inside videodev2 */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *p=arg;
+ int i=p->index;
+
+ if (!vfd->vidioc_enum_input)
+ break;
+ memset(p, 0, sizeof(*p));
+ p->index=i;
+
+ ret=vfd->vidioc_enum_input(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "audioset=%d, "
+ "tuner=%d, std=%Ld, status=%d\n",
+ p->index,p->name,p->type,p->audioset,
+ p->tuner,
+ (unsigned long long)p->std,
+ p->status);
+ break;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_g_input)
+ break;
+ ret=vfd->vidioc_g_input(file, fh, i);
+ if (!ret)
+ dbgarg (cmd, "value=%d\n",*i);
+ break;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_s_input)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_s_input(file, fh, *i);
+ break;
+ }
+
+ /* ------ output switching ---------- */
+ case VIDIOC_G_OUTPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_g_output)
+ break;
+ ret=vfd->vidioc_g_output(file, fh, i);
+ if (!ret)
+ dbgarg (cmd, "value=%d\n",*i);
+ break;
+ }
+ case VIDIOC_S_OUTPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_s_output)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_s_output(file, fh, *i);
+ break;
+ }
+
+ /* --- controls ---------------------------------------------- */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *p=arg;
+
+ if (!vfd->vidioc_queryctrl)
+ break;
+ ret=vfd->vidioc_queryctrl(file, fh, p);
+
+ if (!ret)
+ dbgarg (cmd, "id=%d, type=%d, name=%s, "
+ "min/max=%d/%d,"
+ " step=%d, default=%d, flags=0x%08x\n",
+ p->id,p->type,p->name,p->minimum,
+ p->maximum,p->step,p->default_value,
+ p->flags);
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *p = arg;
+
+ if (!vfd->vidioc_g_ctrl)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->id);
+
+ ret=vfd->vidioc_g_ctrl(file, fh, p);
+ if (!ret)
+ dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *p = arg;
+
+ if (!vfd->vidioc_s_ctrl)
+ break;
+ dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
+
+ ret=vfd->vidioc_s_ctrl(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_g_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_s_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_try_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_QUERYMENU:
+ {
+ struct v4l2_querymenu *p=arg;
+ if (!vfd->vidioc_querymenu)
+ break;
+ ret=vfd->vidioc_querymenu(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "id=%d, index=%d, name=%s\n",
+ p->id,p->index,p->name);
+ break;
+ }
+ /* --- audio ---------------------------------------------- */
+ case VIDIOC_ENUMAUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_enumaudio)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_enumaudio(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n",p->index,p->name,
+ p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_g_audio)
+ break;
+ dbgarg(cmd, "Get for index=%d\n", p->index);
+ ret=vfd->vidioc_g_audio(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n",p->index,
+ p->name,p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_s_audio)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability, p->mode);
+ ret=vfd->vidioc_s_audio(file, fh, p);
+ break;
+ }
+ case VIDIOC_ENUMAUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_enumaudout)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_enumaudout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_g_audout)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_g_audout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_S_AUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_s_audout)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+
+ ret=vfd->vidioc_s_audout(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ if (!vfd->vidioc_g_modulator)
+ break;
+ ret=vfd->vidioc_g_modulator(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "index=%d, name=%s, "
+ "capability=%d, rangelow=%d,"
+ " rangehigh=%d, txsubchans=%d\n",
+ p->index, p->name,p->capability,
+ p->rangelow, p->rangehigh,
+ p->txsubchans);
+ break;
+ }
+ case VIDIOC_S_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ if (!vfd->vidioc_s_modulator)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
+ p->index, p->name,p->capability,p->rangelow,
+ p->rangehigh,p->txsubchans);
+ ret=vfd->vidioc_s_modulator(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ if (!vfd->vidioc_g_crop)
+ break;
+ ret=vfd->vidioc_g_crop(file, fh, p);
+ if (!ret) {
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "", &p->c);
+ }
+ break;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ if (!vfd->vidioc_s_crop)
+ break;
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "", &p->c);
+ ret=vfd->vidioc_s_crop(file, fh, p);
+ break;
+ }
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *p=arg;
+ /*FIXME: Should also show v4l2_fract pixelaspect */
+ if (!vfd->vidioc_cropcap)
+ break;
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "bounds ", &p->bounds);
+ dbgrect(vfd, "defrect ", &p->defrect);
+ ret=vfd->vidioc_cropcap(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+
+ /*FIXME: Several fields not shown */
+ if (!vfd->vidioc_g_mpegcomp)
+ break;
+ ret=vfd->vidioc_g_mpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
+ " ts_pid_video=%d, ts_pid_pcr=%d, "
+ "ps_size=%d, au_sample_rate=%d, "
+ "au_pesid=%c, vi_frame_rate=%d, "
+ "vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n",
+ p->ts_pid_pmt,p->ts_pid_audio,
+ p->ts_pid_video,p->ts_pid_pcr,
+ p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop,
+ p->vi_bframes_count, p->vi_pesid);
+ break;
+ }
+ case VIDIOC_S_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+ /*FIXME: Several fields not shown */
+ if (!vfd->vidioc_s_mpegcomp)
+ break;
+ dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
+ "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
+ "au_sample_rate=%d, au_pesid=%c, "
+ "vi_frame_rate=%d, vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n",
+ p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+ p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop, p->vi_bframes_count,
+ p->vi_pesid);
+ ret=vfd->vidioc_s_mpegcomp(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ if (!vfd->vidioc_g_jpegcomp)
+ break;
+ ret=vfd->vidioc_g_jpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "quality=%d, APPn=%d, "
+ "APP_len=%d, COM_len=%d, "
+ "jpeg_markers=%d\n",
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ break;
+ }
+ case VIDIOC_S_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ if (!vfd->vidioc_g_jpegcomp)
+ break;
+ dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
+ "COM_len=%d, jpeg_markers=%d\n",
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ ret=vfd->vidioc_s_jpegcomp(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+ if (!vfd->vidioc_g_parm)
+ break;
+ ret=vfd->vidioc_g_parm(file, fh, p);
+ dbgarg (cmd, "type=%d\n", p->type);
+ break;
+ }
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+ if (!vfd->vidioc_s_parm)
+ break;
+ dbgarg (cmd, "type=%d\n", p->type);
+ ret=vfd->vidioc_s_parm(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ if (!vfd->vidioc_g_tuner)
+ break;
+ ret=vfd->vidioc_g_tuner(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "capability=%d, rangelow=%d, "
+ "rangehigh=%d, signal=%d, afc=%d, "
+ "rxsubchans=%d, audmode=%d\n",
+ p->index, p->name, p->type,
+ p->capability, p->rangelow,
+ p->rangehigh, p->rxsubchans,
+ p->audmode, p->signal, p->afc);
+ break;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ if (!vfd->vidioc_s_tuner)
+ break;
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "capability=%d, rangelow=%d, rangehigh=%d, "
+ "signal=%d, afc=%d, rxsubchans=%d, "
+ "audmode=%d\n",p->index, p->name, p->type,
+ p->capability, p->rangelow,p->rangehigh,
+ p->rxsubchans, p->audmode, p->signal,
+ p->afc);
+ ret=vfd->vidioc_s_tuner(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ if (!vfd->vidioc_g_frequency)
+ break;
+ ret=vfd->vidioc_g_frequency(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner,p->type,p->frequency);
+ break;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ if (!vfd->vidioc_s_frequency)
+ break;
+ dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner,p->type,p->frequency);
+ ret=vfd->vidioc_s_frequency(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *p=arg;
+ if (!vfd->vidioc_g_sliced_vbi_cap)
+ break;
+ ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "service_set=%d\n", p->service_set);
+ break;
+ }
+ case VIDIOC_LOG_STATUS:
+ {
+ if (!vfd->vidioc_log_status)
+ break;
+ ret=vfd->vidioc_log_status(file, fh);
+ break;
+ }
+
+ /* --- Others --------------------------------------------- */
+
+ default:
+ ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
+ }
+
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
+ if (ret<0) {
+ printk ("%s: err:\n", vfd->name);
+ v4l_print_ioctl(vfd->name, cmd);
+ }
+ }
+
+ return ret;
+}
+
+int video_ioctl2 (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+
+#ifdef __OLD_VIDIOC_
+ cmd = video_fix_command(cmd);
+#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ parg = NULL;
+ break;
+ case _IOC_READ:
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ /* In case of an error, tell the caller that it wasn't
+ a specific control that caused it. */
+ p->error_idx = p->count;
+ user_ptr = (void __user *)p->controls;
+ if (p->count) {
+ ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+ /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+ mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_ext_ctrl;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, ctrls_size))
+ goto out_ext_ctrl;
+ p->controls = mbuf;
+ }
+ }
+
+ /* Handles IOCTL */
+ err = __video_do_ioctl(inode, file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
+ err = -EINVAL;
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ p->controls = (void *)user_ptr;
+ if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ err = -EFAULT;
+ goto out_ext_ctrl;
+ }
+ if (err < 0)
+ goto out;
+
+out_ext_ctrl:
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+
static struct file_operations video_fops;
/**
@@ -274,6 +1512,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
int i=0;
int base;
int end;
+ int ret;
char *name_base;
switch(type)
@@ -299,6 +1538,8 @@ int video_register_device(struct video_device *vfd, int type, int nr)
name_base = "radio";
break;
default:
+ printk(KERN_ERR "%s called with unknown type: %d\n",
+ __FUNCTION__, type);
return -1;
}
@@ -324,10 +1565,6 @@ int video_register_device(struct video_device *vfd, int type, int nr)
video_device[i]=vfd;
vfd->minor=i;
mutex_unlock(&videodev_lock);
-
- sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
- devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
- S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
mutex_init(&vfd->lock);
/* sysfs class */
@@ -336,10 +1573,19 @@ int video_register_device(struct video_device *vfd, int type, int nr)
vfd->class_dev.dev = vfd->dev;
vfd->class_dev.class = &video_class;
vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor);
- strlcpy(vfd->class_dev.class_id, vfd->devfs_name + 4, BUS_ID_SIZE);
- class_device_register(&vfd->class_dev);
- class_device_create_file(&vfd->class_dev,
- &class_device_attr_name);
+ sprintf(vfd->class_dev.class_id, "%s%d", name_base, i - base);
+ ret = class_device_register(&vfd->class_dev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: class_device_register failed\n",
+ __FUNCTION__);
+ goto fail_minor;
+ }
+ ret = class_device_create_file(&vfd->class_dev, &class_device_attr_name);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: class_device_create_file 'name' failed\n",
+ __FUNCTION__);
+ goto fail_classdev;
+ }
#if 1
/* needed until all drivers are fixed */
@@ -349,6 +1595,15 @@ int video_register_device(struct video_device *vfd, int type, int nr)
"http://lwn.net/Articles/36850/\n", vfd->name);
#endif
return 0;
+
+fail_classdev:
+ class_device_unregister(&vfd->class_dev);
+fail_minor:
+ mutex_lock(&videodev_lock);
+ video_device[vfd->minor] = NULL;
+ vfd->minor = -1;
+ mutex_unlock(&videodev_lock);
+ return ret;
}
/**
@@ -365,13 +1620,14 @@ void video_unregister_device(struct video_device *vfd)
if(video_device[vfd->minor]!=vfd)
panic("videodev: bad unregister");
- devfs_remove(vfd->devfs_name);
video_device[vfd->minor]=NULL;
class_device_unregister(&vfd->class_dev);
mutex_unlock(&videodev_lock);
}
-
+/*
+ * Video fs operations
+ */
static struct file_operations video_fops=
{
.owner = THIS_MODULE,
@@ -387,7 +1643,7 @@ static int __init videodev_init(void)
{
int ret;
- printk(KERN_INFO "Linux video capture interface: v1.00\n");
+ printk(KERN_INFO "Linux video capture interface: v2.00\n");
if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
return -EIO;
@@ -418,11 +1674,12 @@ EXPORT_SYMBOL(video_devdata);
EXPORT_SYMBOL(video_usercopy);
EXPORT_SYMBOL(video_exclusive_open);
EXPORT_SYMBOL(video_exclusive_release);
+EXPORT_SYMBOL(video_ioctl2);
EXPORT_SYMBOL(video_device_alloc);
EXPORT_SYMBOL(video_device_release);
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index a8c101494cf..268e69fdefc 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -40,7 +40,7 @@
#include <linux/i2c-algo-sgi.h>
#include <linux/videodev.h>
-#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
#include <linux/mutex.h>
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 779db26771c..841884af0cc 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -48,34 +48,15 @@
#include "font.h"
-#ifndef kzalloc
-#define kzalloc(size, flags) \
-({ \
- void *__ret = kmalloc(size, flags); \
- if (__ret) \
- memset(__ret, 0, size); \
- __ret; \
-})
-#endif
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
#define VIVI_MAJOR_VERSION 0
#define VIVI_MINOR_VERSION 4
#define VIVI_RELEASE 0
#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-
-static int debug = 0;
-module_param(debug, int, 0);
-
-static unsigned int vid_limit = 16;
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+static struct video_device vivi; /* Video device */
+static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
/* supported controls */
static struct v4l2_queryctrl vivi_qctrl[] = {
@@ -129,10 +110,10 @@ static struct v4l2_queryctrl vivi_qctrl[] = {
static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
-#define dprintk(level,fmt, arg...) \
- do { \
- if (debug >= (level)) \
- printk(KERN_DEBUG "vivi: " fmt , ## arg); \
+#define dprintk(level,fmt, arg...) \
+ do { \
+ if (vivi.debug >= (level)) \
+ printk(KERN_DEBUG "vivi: " fmt , ## arg); \
} while (0)
/* ------------------------------------------------------------------
@@ -190,7 +171,7 @@ struct vivi_dev {
/* various device info */
unsigned int resources;
- struct video_device video_dev;
+ struct video_device vfd;
struct vivi_dmaqueue vidq;
@@ -248,7 +229,8 @@ static u8 bars[8][3] = {
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
+static void prep_to_addr(struct sg_to_addr to_addr[],
+ struct videobuf_buffer *vb)
{
int i, pos=0;
@@ -259,7 +241,7 @@ void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
}
}
-inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
+static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
{
int p1=0,p2=pages-1,p3=pages/2;
@@ -280,8 +262,8 @@ inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
return (p1);
}
-void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
+static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
+ int hmax, int line, char *timestr)
{
int w,i,j,pos=inipos,pgpos,oldpg,y;
char *p,*s,*basep;
@@ -491,7 +473,7 @@ static void vivi_thread_tick(struct vivi_dmaqueue *dma_q)
dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
}
-void vivi_sleep(struct vivi_dmaqueue *dma_q)
+static void vivi_sleep(struct vivi_dmaqueue *dma_q)
{
int timeout;
DECLARE_WAITQUEUE(wait, current);
@@ -526,7 +508,7 @@ void vivi_sleep(struct vivi_dmaqueue *dma_q)
try_to_freeze();
}
-int vivi_thread(void *data)
+static int vivi_thread(void *data)
{
struct vivi_dmaqueue *dma_q=data;
@@ -542,7 +524,7 @@ int vivi_thread(void *data)
return 0;
}
-int vivi_start_thread(struct vivi_dmaqueue *dma_q)
+static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
{
dma_q->frame=0;
dma_q->ini_jiffies=jiffies;
@@ -560,7 +542,7 @@ int vivi_start_thread(struct vivi_dmaqueue *dma_q)
return 0;
}
-void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
+static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
{
dprintk(1,"%s\n",__FUNCTION__);
/* shutdown control thread */
@@ -666,8 +648,7 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
return 0;
}
-void
-free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
{
dprintk(1,"%s\n",__FUNCTION__);
@@ -791,8 +772,8 @@ static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb
free_buffer(vq,buf);
}
-int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
- int direction)
+static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
+ int direction)
{
int i;
@@ -808,15 +789,15 @@ int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
return nents;
}
-int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
+static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
+ int direction)
{
dprintk(1,"%s\n",__FUNCTION__);
return 0;
}
-int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
+static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
+ int direction)
{
// dprintk(1,"%s\n",__FUNCTION__);
@@ -840,7 +821,80 @@ static struct videobuf_queue_ops vivi_video_qops = {
IOCTL handling
------------------------------------------------------------------*/
-static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+
+static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+ /* is it free? */
+ down(&dev->lock);
+ if (dev->resources) {
+ /* no, someone else uses it */
+ up(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ dev->resources =1;
+ dprintk(1,"res: get\n");
+ up(&dev->lock);
+ return 1;
+}
+
+static int res_locked(struct vivi_dev *dev)
+{
+ return (dev->resources);
+}
+
+static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+ down(&dev->lock);
+ dev->resources = 0;
+ dprintk(1,"res: put\n");
+ up(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "vivi");
+ strcpy(cap->card, "vivi");
+ cap->version = VIVI_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index > 0)
+ return -EINVAL;
+
+ strlcpy(f->description,format.name,sizeof(f->description));
+ f->pixelformat = format.fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_fh *fh=priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return (0);
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fmt *fmt;
@@ -848,7 +902,8 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
unsigned int maxw, maxh;
if (format.fourcc != f->fmt.pix.pixelformat) {
- dprintk(1,"Fourcc format invalid.\n");
+ dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+ "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
return -EINVAL;
}
fmt=&format;
@@ -884,356 +939,196 @@ static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
return 0;
}
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- /* is it free? */
- down(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- up(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(1,"res: get\n");
- up(&dev->lock);
- return 1;
+ struct vivi_fh *fh=priv;
+ int ret = vidioc_try_fmt_cap(file,fh,f);
+ if (ret < 0)
+ return (ret);
+
+ fh->fmt = &format;
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+
+ return (0);
}
-static inline int res_locked(struct vivi_dev *dev)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
- return (dev->resources);
-}
+ struct vivi_fh *fh=priv;
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- down(&dev->lock);
- dev->resources = 0;
- dprintk(1,"res: put\n");
- up(&dev->lock);
+ return (videobuf_reqbufs(&fh->vb_vidq, p));
}
-static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_dev *dev = fh->dev;
- int ret=0;
+ struct vivi_fh *fh=priv;
- if (debug) {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- v4l_printk_ioctl_arg("vivi(w)",cmd, arg);
- else if (!_IOC_DIR(cmd) & _IOC_READ) {
- v4l_print_ioctl("vivi", cmd);
- }
- }
+ return (videobuf_querybuf(&fh->vb_vidq, p));
+}
- switch(cmd) {
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = (struct v4l2_capability*)arg;
-
- memset(cap, 0, sizeof(*cap));
-
- strcpy(cap->driver, "vivi");
- strcpy(cap->card, "vivi");
- cap->version = VIVI_VERSION;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- break;
- }
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vivi_fh *fh=priv;
- index = f->index;
- type = f->type;
+ return (videobuf_qbuf(&fh->vb_vidq, p));
+}
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vivi_fh *fh=priv;
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index > 0){
- ret=-EINVAL;
- break;
- }
- memset(f,0,sizeof(*f));
+ return (videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK));
+}
- f->index = index;
- f->type = type;
- strlcpy(f->description,format.name,sizeof(f->description));
- f->pixelformat = format.fourcc;
- break;
- default:
- ret=-EINVAL;
- }
- break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct vivi_fh *fh=priv;
+ struct videobuf_queue *q=&fh->vb_vidq;
+ struct v4l2_requestbuffers req;
+ unsigned int i, ret;
+
+ req.type = q->type;
+ req.count = 8;
+ req.memory = V4L2_MEMORY_MMAP;
+ ret = videobuf_reqbufs(q,&req);
+ if (ret < 0)
+ return (ret);
+
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = (struct v4l2_format *)arg;
+ return (0);
+}
+#endif
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vivi_fh *fh=priv;
+ struct vivi_dev *dev = fh->dev;
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- break;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dprintk(1,"Only capture supported.\n");
- ret=-EINVAL;
- break;
- }
+ if (!res_get(dev,fh))
+ return -EBUSY;
+ return (videobuf_streamon(&fh->vb_vidq));
+}
- ret = vivi_try_fmt(dev,fh,f);
- if (ret < 0)
- break;
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vivi_fh *fh=priv;
+ struct vivi_dev *dev = fh->dev;
- fh->fmt = &format;
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- break;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(dev,fh);
- ret=vivi_try_fmt(dev,fh,f);
- break;
- }
- case VIDIOC_REQBUFS:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_reqbufs(&fh->vb_vidq, arg);
- break;
- case VIDIOC_QUERYBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_querybuf(&fh->vb_vidq, arg);
- break;
- case VIDIOC_QBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_qbuf(&fh->vb_vidq, arg);
- break;
- case VIDIOC_DQBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_dqbuf(&fh->vb_vidq, arg,
- file->f_flags & O_NONBLOCK);
- break;
-#ifdef HAVE_V4L1
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q=&fh->vb_vidq;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- ret = videobuf_reqbufs(q,&req);
- if (ret < 0)
- break;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- break;
- }
-#endif
- case VIDIOC_STREAMON:
- {
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (!res_get(dev,fh))
- return -EBUSY;
- ret=videobuf_streamon(&fh->vb_vidq);
- break;
- }
- case VIDIOC_STREAMOFF:
+ return (0);
+}
+
+static struct v4l2_tvnorm tvnorms[] = {
{
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret = videobuf_streamoff(&fh->vb_vidq);
- if (ret < 0)
- break;
- res_free(dev,fh);
- break;
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
}
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
+};
- if (e->index>0) {
- ret=-EINVAL;
- break;
- }
- ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M");
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+{
- /* Allows vivi to use different fps from video std */
- e->frameperiod.numerator = WAKE_NUMERATOR;
- e->frameperiod.denominator = WAKE_DENOMINATOR;
+ return 0;
+}
- break;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+/* only one input in this sample driver */
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
- *id = V4L2_STD_NTSC_M;
- break;
- }
- case VIDIOC_S_STD:
- {
- break;
- }
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- { /* only one input in this sample driver */
- struct v4l2_input *inp = arg;
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_NTSC_M;
+ strcpy(inp->name,"Camera");
- if (inp->index != 0) {
- ret=-EINVAL;
- break;
- }
- memset(inp, 0, sizeof(*inp));
+ return (0);
+}
- inp->index = 0;
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = V4L2_STD_NTSC_M;
- strcpy(inp->name,"Camera");
- break;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
- *i = 0;
- break;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
+ return (0);
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
- if (*i > 0)
- ret=-EINVAL;
- break;
- }
+ return (0);
+}
/* --- controls ---------------------------------------------- */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (qc->id && qc->id == vivi_qctrl[i].id) {
- memcpy(qc, &(vivi_qctrl[i]),
- sizeof(*qc));
- break;
- }
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
- ret=-EINVAL;
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int i;
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (qc->id && qc->id == vivi_qctrl[i].id) {
+ memcpy(qc, &(vivi_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (ctrl->id == vivi_qctrl[i].id) {
- ctrl->value=qctl_regs[i];
- break;
- }
+ return -EINVAL;
+}
- ret=-EINVAL;
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (ctrl->id == vivi_qctrl[i].id) {
- if (ctrl->value <
- vivi_qctrl[i].minimum
- || ctrl->value >
- vivi_qctrl[i].maximum) {
- ret=-ERANGE;
- break;
- }
- qctl_regs[i]=ctrl->value;
- break;
- }
- ret=-EINVAL;
- break;
- }
- default:
- ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl);
- }
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
- if (debug) {
- if (ret<0) {
- v4l_print_ioctl("vivi(err)", cmd);
- dprintk(1,"errcode=%d\n",ret);
- } else if (_IOC_DIR(cmd) & _IOC_READ)
- v4l_printk_ioctl_arg("vivi(r)",cmd, arg);
- }
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+ ctrl->value=qctl_regs[i];
+ return (0);
+ }
- return ret;
+ return -EINVAL;
}
-
-static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
{
- return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+ if (ctrl->value <
+ vivi_qctrl[i].minimum
+ || ctrl->value >
+ vivi_qctrl[i].maximum) {
+ return (-ERANGE);
+ }
+ qctl_regs[i]=ctrl->value;
+ return (0);
+ }
+ return -EINVAL;
}
/* ------------------------------------------------------------------
@@ -1255,7 +1150,7 @@ static int vivi_open(struct inode *inode, struct file *file)
list_for_each(list,&vivi_devlist) {
h = list_entry(list, struct vivi_dev, vivi_devlist);
- if (h->video_dev.minor == minor) {
+ if (h->vfd.minor == minor) {
dev = h;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
}
@@ -1264,6 +1159,7 @@ static int vivi_open(struct inode *inode, struct file *file)
return -ENODEV;
+
/* If more than one user, mutex should be added */
dev->users++;
@@ -1279,6 +1175,7 @@ static int vivi_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
+
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->fmt = &format;
fh->width = 640;
@@ -1314,7 +1211,7 @@ static int vivi_open(struct inode *inode, struct file *file)
static ssize_t
vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
- struct vivi_fh *fh = file->private_data;
+ struct vivi_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (res_locked(fh->dev))
@@ -1328,8 +1225,8 @@ vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_buffer *buf;
+ struct vivi_fh *fh = file->private_data;
+ struct vivi_buffer *buf;
dprintk(1,"%s\n",__FUNCTION__);
@@ -1358,8 +1255,8 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
static int vivi_release(struct inode *inode, struct file *file)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_dev *dev = fh->dev;
+ struct vivi_fh *fh = file->private_data;
+ struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq;
int minor = iminor(inode);
@@ -1379,7 +1276,7 @@ static int vivi_release(struct inode *inode, struct file *file)
static int
vivi_mmap(struct file *file, struct vm_area_struct * vma)
{
- struct vivi_fh *fh = file->private_data;
+ struct vivi_fh *fh = file->private_data;
int ret;
dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
@@ -1400,20 +1297,44 @@ static struct file_operations vivi_fops = {
.release = vivi_release,
.read = vivi_read,
.poll = vivi_poll,
- .ioctl = vivi_ioctl,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = vivi_mmap,
.llseek = no_llseek,
};
static struct video_device vivi = {
- .name = "VTM Virtual Video Capture Board",
+ .name = "vivi",
.type = VID_TYPE_CAPTURE,
.hardware = 0,
.fops = &vivi_fops,
.minor = -1,
// .release = video_device_release,
+
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+ .tvnorms = tvnorms,
+ .tvnormsize = ARRAY_SIZE(tvnorms),
};
-/* ------------------------------------------------------------------
+/* -----------------------------------------------------------------
Initialization and module stuff
------------------------------------------------------------------*/
@@ -1457,3 +1378,16 @@ static void __exit vivi_exit(void)
module_init(vivi_init);
module_exit(vivi_exit);
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_param(video_nr, int, 0);
+
+module_param_named(debug,vivi.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 40b205b9148..1eca7e65d23 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -34,6 +34,7 @@
#define I2C_NAME(x) (x)->name
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
#define I2C_VPX3220 0x86
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 80ef8a1b8f6..4bdc886abc4 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -58,6 +58,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/parport.h>
//#define DEBUG // Undef me for production
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 20f211b55ad..2912326a5ae 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -586,15 +586,14 @@ static struct w9968cf_symbolic_list urb_errlist[] = {
{ -EFBIG, "Too much ISO frames requested" },
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Specified endpoint is stalled (device not responding)"},
- { -EOVERFLOW, "Babble (bad cable?)" },
+ { -EOVERFLOW, "Babble (too much data)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
{ -EILSEQ, "CRC/Timeout" },
- { -ETIMEDOUT, "NAK (device does not respond)" },
+ { -ETIME, "Device does not respond to token" },
+ { -ETIMEDOUT, "Device does not respond to command" },
{ -1, NULL }
};
-
-
/****************************************************************************
* Memory management functions *
****************************************************************************/
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
index 2836b45ec20..ec7696e8f1f 100644
--- a/drivers/media/video/w9968cf.h
+++ b/drivers/media/video/w9968cf.h
@@ -28,7 +28,6 @@
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/wait.h>
-#include <linux/config.h>
#include <linux/param.h>
#include <linux/types.h>
#include <linux/rwsem.h>
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
index 115833e4f4d..a859a692018 100644
--- a/drivers/media/video/zc0301/Kconfig
+++ b/drivers/media/video/zc0301/Kconfig
@@ -1,9 +1,9 @@
config USB_ZC0301
- tristate "USB ZC0301 Image Processor and Control Chip support"
+ tristate "USB ZC0301[P] Image Processor and Control Chip support"
depends on USB && VIDEO_V4L1
---help---
- Say Y here if you want support for cameras based on the ZC0301
- Image Processor and Control Chip.
+ Say Y here if you want support for cameras based on the ZC0301 or
+ ZC0301P Image Processors and Control Chips.
See <file:Documentation/video4linux/zc0301.txt> for more info.
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
index d749199d8f0..d9e6d97fade 100644
--- a/drivers/media/video/zc0301/Makefile
+++ b/drivers/media/video/zc0301/Makefile
@@ -1,3 +1,3 @@
-zc0301-objs := zc0301_core.o zc0301_pas202bcb.o
+zc0301-objs := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
obj-$(CONFIG_USB_ZC0301) += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 0fad39754f7..1b2be2d2a3e 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip *
+ * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
@@ -47,13 +47,13 @@
/*****************************************************************************/
-#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \
+#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
"Image Processor and Control Chip"
#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.03"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3)
+#define ZC0301_MODULE_VERSION "1:1.05"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 5)
/*****************************************************************************/
@@ -427,10 +427,11 @@ resubmit_urb:
static int zc0301_start_transfer(struct zc0301_device* cam)
{
struct usb_device *udev = cam->usbdev;
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ ZC0301_ALTERNATE_SETTING);
+ const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
struct urb* urb;
- const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
- 512, 768, 1023};
- const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
s8 i, j;
int err = 0;
@@ -1772,11 +1773,9 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_CTRL:
return zc0301_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return zc0301_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return zc0301_vidioc_cropcap(cam, arg);
@@ -1823,7 +1822,6 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp,
case VIDIOC_G_PARM:
return zc0301_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return zc0301_vidioc_s_parm(cam, arg);
@@ -1914,7 +1912,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
mutex_init(&cam->dev_mutex);
- DBG(2, "ZC0301 Image Processor and Control Chip detected "
+ DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
"(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
for (i = 0; zc0301_sensor_table[i]; i++) {
@@ -1936,7 +1934,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
cam->state |= DEV_MISCONFIGURED;
}
- strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+ strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->v4ldev->hardware = 0;
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
index eaadf025204..ecfd39a56df 100644
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ b/drivers/media/video/zc0301/zc0301_pas202bcb.c
@@ -1,10 +1,10 @@
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image *
* Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
- * Initialization values of the ZC0301 have been taken from the SPCA5XX *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
* *
* This program is free software; you can redistribute it and/or modify *
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
new file mode 100644
index 00000000000..ed8542e6c50
--- /dev/null
+++ b/drivers/media/video/zc0301/zc0301_pb0330.c
@@ -0,0 +1,187 @@
+/***************************************************************************
+ * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image *
+ * Processor and Control Chip *
+ * *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr> *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ ***************************************************************************/
+
+#include <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pb0330;
+
+
+static int pb0330_init(struct zc0301_device* cam)
+{
+ int err = 0;
+
+ err += zc0301_write_reg(cam, 0x0000, 0x01);
+ err += zc0301_write_reg(cam, 0x0008, 0x03);
+ err += zc0301_write_reg(cam, 0x0010, 0x0A);
+ err += zc0301_write_reg(cam, 0x0002, 0x00);
+ err += zc0301_write_reg(cam, 0x0003, 0x02);
+ err += zc0301_write_reg(cam, 0x0004, 0x80);
+ err += zc0301_write_reg(cam, 0x0005, 0x01);
+ err += zc0301_write_reg(cam, 0x0006, 0xE0);
+ err += zc0301_write_reg(cam, 0x0001, 0x01);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+ err += zc0301_write_reg(cam, 0x0012, 0x07);
+ err += zc0301_write_reg(cam, 0x0098, 0x00);
+ err += zc0301_write_reg(cam, 0x009A, 0x00);
+ err += zc0301_write_reg(cam, 0x011A, 0x00);
+ err += zc0301_write_reg(cam, 0x011C, 0x00);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+
+ err += zc0301_i2c_write(cam, 0x01, 0x0006);
+ err += zc0301_i2c_write(cam, 0x02, 0x0011);
+ err += zc0301_i2c_write(cam, 0x03, 0x01E7);
+ err += zc0301_i2c_write(cam, 0x04, 0x0287);
+ err += zc0301_i2c_write(cam, 0x06, 0x0003);
+ err += zc0301_i2c_write(cam, 0x07, 0x3002);
+ err += zc0301_i2c_write(cam, 0x20, 0x1100);
+ err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
+ err += zc0301_i2c_write(cam, 0x30, 0x0005);
+ err += zc0301_i2c_write(cam, 0x31, 0x0000);
+ err += zc0301_i2c_write(cam, 0x34, 0x0100);
+ err += zc0301_i2c_write(cam, 0x35, 0x0060);
+ err += zc0301_i2c_write(cam, 0x3D, 0x068F);
+ err += zc0301_i2c_write(cam, 0x40, 0x01E0);
+ err += zc0301_i2c_write(cam, 0x58, 0x0078);
+ err += zc0301_i2c_write(cam, 0x62, 0x0411);
+
+ err += zc0301_write_reg(cam, 0x0087, 0x10);
+ err += zc0301_write_reg(cam, 0x0101, 0x37);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+ err += zc0301_write_reg(cam, 0x0100, 0x0D);
+ err += zc0301_write_reg(cam, 0x0189, 0x06);
+ err += zc0301_write_reg(cam, 0x01AD, 0x00);
+ err += zc0301_write_reg(cam, 0x01C5, 0x03);
+ err += zc0301_write_reg(cam, 0x01CB, 0x13);
+ err += zc0301_write_reg(cam, 0x0250, 0x08);
+ err += zc0301_write_reg(cam, 0x0301, 0x08);
+ err += zc0301_write_reg(cam, 0x01A8, 0x60);
+ err += zc0301_write_reg(cam, 0x018D, 0x6C);
+ err += zc0301_write_reg(cam, 0x01AD, 0x09);
+ err += zc0301_write_reg(cam, 0x01AE, 0x15);
+ err += zc0301_write_reg(cam, 0x010A, 0x50);
+ err += zc0301_write_reg(cam, 0x010B, 0xF8);
+ err += zc0301_write_reg(cam, 0x010C, 0xF8);
+ err += zc0301_write_reg(cam, 0x010D, 0xF8);
+ err += zc0301_write_reg(cam, 0x010E, 0x50);
+ err += zc0301_write_reg(cam, 0x010F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0110, 0xF8);
+ err += zc0301_write_reg(cam, 0x0111, 0xF8);
+ err += zc0301_write_reg(cam, 0x0112, 0x50);
+ err += zc0301_write_reg(cam, 0x0008, 0x03);
+ err += zc0301_write_reg(cam, 0x01C6, 0x08);
+ err += zc0301_write_reg(cam, 0x01CB, 0x0F);
+ err += zc0301_write_reg(cam, 0x010A, 0x50);
+ err += zc0301_write_reg(cam, 0x010B, 0xF8);
+ err += zc0301_write_reg(cam, 0x010C, 0xF8);
+ err += zc0301_write_reg(cam, 0x010D, 0xF8);
+ err += zc0301_write_reg(cam, 0x010E, 0x50);
+ err += zc0301_write_reg(cam, 0x010F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0110, 0xF8);
+ err += zc0301_write_reg(cam, 0x0111, 0xF8);
+ err += zc0301_write_reg(cam, 0x0112, 0x50);
+ err += zc0301_write_reg(cam, 0x0180, 0x00);
+ err += zc0301_write_reg(cam, 0x0019, 0x00);
+
+ err += zc0301_i2c_write(cam, 0x05, 0x0066);
+ err += zc0301_i2c_write(cam, 0x09, 0x02B2);
+ err += zc0301_i2c_write(cam, 0x10, 0x0002);
+
+ err += zc0301_write_reg(cam, 0x011D, 0x60);
+ err += zc0301_write_reg(cam, 0x0190, 0x00);
+ err += zc0301_write_reg(cam, 0x0191, 0x07);
+ err += zc0301_write_reg(cam, 0x0192, 0x8C);
+ err += zc0301_write_reg(cam, 0x0195, 0x00);
+ err += zc0301_write_reg(cam, 0x0196, 0x00);
+ err += zc0301_write_reg(cam, 0x0197, 0x8A);
+ err += zc0301_write_reg(cam, 0x018C, 0x10);
+ err += zc0301_write_reg(cam, 0x018F, 0x20);
+ err += zc0301_write_reg(cam, 0x01A9, 0x14);
+ err += zc0301_write_reg(cam, 0x01AA, 0x24);
+ err += zc0301_write_reg(cam, 0x001D, 0xD7);
+ err += zc0301_write_reg(cam, 0x001E, 0xF0);
+ err += zc0301_write_reg(cam, 0x001F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0020, 0xFF);
+ err += zc0301_write_reg(cam, 0x01AD, 0x09);
+ err += zc0301_write_reg(cam, 0x01AE, 0x15);
+ err += zc0301_write_reg(cam, 0x0180, 0x40);
+ err += zc0301_write_reg(cam, 0x0180, 0x42);
+
+ msleep(100);
+
+ return err;
+}
+
+
+static struct zc0301_sensor pb0330 = {
+ .name = "PB-0330",
+ .init = &pb0330_init,
+ .cropcap = {
+ .bounds = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .defrect = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ },
+ .pix_format = {
+ .width = 640,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .priv = 8,
+ },
+};
+
+
+int zc0301_probe_pb0330(struct zc0301_device* cam)
+{
+ int r0, err = 0;
+
+ err += zc0301_write_reg(cam, 0x0000, 0x01);
+ err += zc0301_write_reg(cam, 0x0010, 0x0a);
+ err += zc0301_write_reg(cam, 0x0001, 0x01);
+ err += zc0301_write_reg(cam, 0x0012, 0x03);
+ err += zc0301_write_reg(cam, 0x0012, 0x01);
+
+ msleep(10);
+
+ r0 = zc0301_i2c_read(cam, 0x00, 2);
+
+ if (r0 < 0 || err)
+ return -EIO;
+
+ if (r0 != 0x8243)
+ return -ENODEV;
+
+ zc0301_attach_sensor(cam, &pb0330);
+
+ return 0;
+}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 1f95c28b101..4363a915b1f 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -1,5 +1,5 @@
/***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and *
+ * API for image sensors connected to the ZC0301 Image Processor and *
* Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
@@ -35,11 +35,13 @@ struct zc0301_sensor;
/*****************************************************************************/
extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+extern int zc0301_probe_pb0330(struct zc0301_device* cam);
#define ZC0301_SENSOR_TABLE \
/* Weak detections must go at the end of the list */ \
static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \
&zc0301_probe_pas202bcb, \
+ &zc0301_probe_pb0330, \
NULL, \
};
@@ -58,14 +60,28 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
#define ZC0301_ID_TABLE \
static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \
+ { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), }, \
{ ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
+ { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
- { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */ \
{ } \
};
diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h
index 0166f555a5c..8fb4a3414e0 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -159,7 +159,7 @@ Private IOCTL to set up for displaying MJPEG
#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */
#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */
-#define BUZ_MAX_INPUT 8
+#define BUZ_MAX_INPUT 16
#if VIDEO_MAX_FRAME <= 32
# define V4L_MAX_FRAME 32
@@ -191,6 +191,9 @@ enum card_type {
/* Iomega */
BUZ,
+ /* AverMedia */
+ AVS6EYES,
+
/* total number of cards */
NUM_CARDS
};
@@ -264,7 +267,7 @@ struct zoran_v4l_settings {
};
/* whoops, this one is undeclared if !v4l2 */
-#ifndef HAVE_V4L2
+#ifndef CONFIG_VIDEO_V4L2
struct v4l2_jpegcompression {
int quality;
int APPn;
@@ -379,6 +382,9 @@ struct card_info {
/* is the /GWS line conected? */
u8 gws_not_connected;
+ /* avs6eyes mux setting */
+ u8 input_mux;
+
void (*init) (struct zoran * zr);
};
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 0a85c9e7fb4..29f59c36f00 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -27,7 +27,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
+#include <linux/delay.h>
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -38,6 +39,7 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/spinlock.h>
#include <linux/sem.h>
#include <linux/kmod.h>
@@ -93,6 +95,11 @@ module_param(default_input, int, 0);
MODULE_PARM_DESC(default_input,
"Default input (0=Composite, 1=S-Video, 2=Internal)");
+static int default_mux = 1; /* 6 Eyes input selection */
+module_param(default_mux, int, 0);
+MODULE_PARM_DESC(default_mux,
+ "Default 6 Eyes mux setting (Input selection)");
+
static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */
module_param(default_norm, int, 0);
MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
@@ -301,6 +308,30 @@ lml33_init (struct zoran *zr)
GPIO(zr, 2, 1); // Set Composite input/output
}
+static void
+avs6eyes_init (struct zoran *zr)
+{
+ // AverMedia 6-Eyes original driver by Christer Weinigel
+
+ // Lifted straight from Christer's old driver and
+ // modified slightly by Martin Samuelsson.
+
+ int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+ GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+ udelay(2);
+
+ GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+ GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+ GPIO(zr, 2, mux & 1); /* MUX S0 */
+ GPIO(zr, 3, 0); /* /FRAME on */
+ GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+ GPIO(zr, 5, mux & 2); /* MUX S1 */
+ GPIO(zr, 6, 0); /* ? */
+ GPIO(zr, 7, mux & 4); /* MUX S2 */
+
+}
+
static char *
i2cid_to_modulename (u16 i2c_id)
{
@@ -391,6 +422,14 @@ static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 };
static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
{
.type = DC10_old,
@@ -419,6 +458,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = DC10_new,
@@ -445,6 +485,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 1},
.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10plus_init,
}, {
.type = DC10plus,
@@ -474,6 +515,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 1 },
.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10plus_init,
}, {
.type = DC30,
@@ -502,6 +544,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = DC30plus,
@@ -532,6 +575,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = LML33,
@@ -558,6 +602,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &lml33_init,
}, {
.type = LML33R10,
@@ -586,6 +631,7 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &lml33_init,
}, {
.type = BUZ,
@@ -614,8 +660,49 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &buz_init,
+ }, {
+ .type = AVS6EYES,
+ .name = "6-Eyes",
+ /* AverMedia chose not to brand the 6-Eyes. Thus it
+ can't be autodetected, and requires card=x. */
+ .vendor_id = -1,
+ .device_id = -1,
+ .i2c_decoder = I2C_DRIVERID_KS0127,
+ .i2c_encoder = I2C_DRIVERID_BT866,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 10,
+ .input = {
+ { 0, "Composite 1" },
+ { 1, "Composite 2" },
+ { 2, "Composite 3" },
+ { 4, "Composite 4" },
+ { 5, "Composite 5" },
+ { 6, "Composite 6" },
+ { 8, "S-Video 1" },
+ { 9, "S-Video 2" },
+ {10, "S-Video 3" },
+ {15, "YCbCr" }
+ },
+ .norms = 2,
+ .tvn = {
+ &f50ccir601_avs6eyes,
+ &f60ccir601_avs6eyes,
+ NULL
+ },
+ .jpeg_int = ZR36057_ISR_GIRQ1,
+ .vsync_int = ZR36057_ISR_GIRQ0,
+ .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+ .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+ .gpcs = { 3, 1 }, // Validity unknown /Sam
+ .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 }, // Validity unknown /Sam
+ .gws_not_connected = 1,
+ .input_mux = 1,
+ .init = &avs6eyes_init,
}
+
};
/*
@@ -733,7 +820,6 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
.getsda = zoran_i2c_getsda,
.getscl = zoran_i2c_getscl,
.udelay = 10,
- .mdelay = 0,
.timeout = 100,
};
@@ -1293,7 +1379,7 @@ find_zr36057 (void)
result = request_irq(zr->pci_dev->irq,
zoran_irq,
- SA_SHIRQ | SA_INTERRUPT,
+ IRQF_SHARED | IRQF_DISABLED,
ZR_DEVNAME(zr),
(void *) zr);
if (result < 0) {
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index c690b2ee880..3cbac2e8aed 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -27,7 +27,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -536,7 +535,7 @@ zr36057_overlay (struct zoran *zr,
* All error messages are internal driver checking only! */
/* video display top and bottom registers */
- reg = (u32) zr->buffer.base +
+ reg = (long) zr->buffer.base +
zr->overlay_settings.x *
((zr->overlay_settings.format->depth + 7) / 8) +
zr->overlay_settings.y *
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index b5a576a37fd..5f90db27892 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -44,7 +44,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -73,6 +72,7 @@
)
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "videocodec.h"
#include <asm/io.h>
@@ -86,7 +86,7 @@
#include "zoran_device.h"
#include "zoran_card.h"
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
/* we declare some card type definitions here, they mean
* the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
#define ZORAN_V4L2_VID_FLAGS ( \
@@ -103,7 +103,7 @@ const struct zoran_format zoran_formats[] = {
{
.name = "15-bit RGB",
.palette = VIDEO_PALETTE_RGB555,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
#ifdef __LITTLE_ENDIAN
.fourcc = V4L2_PIX_FMT_RGB555,
#else
@@ -117,7 +117,7 @@ const struct zoran_format zoran_formats[] = {
}, {
.name = "16-bit RGB",
.palette = VIDEO_PALETTE_RGB565,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
#ifdef __LITTLE_ENDIAN
.fourcc = V4L2_PIX_FMT_RGB565,
#else
@@ -131,7 +131,7 @@ const struct zoran_format zoran_formats[] = {
}, {
.name = "24-bit RGB",
.palette = VIDEO_PALETTE_RGB24,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
#ifdef __LITTLE_ENDIAN
.fourcc = V4L2_PIX_FMT_BGR24,
#else
@@ -145,7 +145,7 @@ const struct zoran_format zoran_formats[] = {
}, {
.name = "32-bit RGB",
.palette = VIDEO_PALETTE_RGB32,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
#ifdef __LITTLE_ENDIAN
.fourcc = V4L2_PIX_FMT_BGR32,
#else
@@ -159,7 +159,7 @@ const struct zoran_format zoran_formats[] = {
}, {
.name = "4:2:2, packed, YUYV",
.palette = VIDEO_PALETTE_YUV422,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
.fourcc = V4L2_PIX_FMT_YUYV,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
#endif
@@ -169,7 +169,7 @@ const struct zoran_format zoran_formats[] = {
}, {
.name = "Hardware-encoded Motion-JPEG",
.palette = -1,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
.fourcc = V4L2_PIX_FMT_MJPEG,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
#endif
@@ -210,7 +210,7 @@ static int lock_norm = 0; /* 1=Don't change TV standard (norm) */
module_param(lock_norm, int, 0);
MODULE_PARM_DESC(lock_norm, "Users can't change norm");
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
/* small helper function for calculating buffersizes for v4l2
* we calculate the nearest higher power-of-two, which
* will be the recommended buffersize */
@@ -1761,7 +1761,7 @@ setup_overlay (struct file *file,
return wait_grab_pending(zr);
}
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
/* get the status of a buffer in the clients buffer queue */
static int
zoran_v4l2_buffer_status (struct file *file,
@@ -2047,7 +2047,7 @@ zoran_do_ioctl (struct inode *inode,
dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
memset(vcap, 0, sizeof(struct video_capability));
- strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name));
+ strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
vcap->type = ZORAN_VID_TYPE;
vcap->channels = zr->card.inputs;
@@ -2676,7 +2676,7 @@ zoran_do_ioctl (struct inode *inode,
}
break;
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
/* The new video4linux2 capture interface - much nicer than video4linux1, since
* it allows for integrating the JPEG capturing calls inside standard v4l2
@@ -2689,8 +2689,8 @@ zoran_do_ioctl (struct inode *inode,
dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
memset(cap, 0, sizeof(*cap));
- strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
- strncpy(cap->driver, "zoran", sizeof(cap->driver));
+ strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+ strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(zr->pci_dev));
cap->version =
@@ -2742,7 +2742,7 @@ zoran_do_ioctl (struct inode *inode,
memset(fmt, 0, sizeof(*fmt));
fmt->index = index;
fmt->type = type;
- strncpy(fmt->description, zoran_formats[i].name, 31);
+ strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
fmt->pixelformat = zoran_formats[i].fourcc;
if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
@@ -3566,16 +3566,16 @@ zoran_do_ioctl (struct inode *inode,
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- strncpy(ctrl->name, "Brightness", 31);
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
break;
case V4L2_CID_CONTRAST:
- strncpy(ctrl->name, "Contrast", 31);
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
break;
case V4L2_CID_SATURATION:
- strncpy(ctrl->name, "Saturation", 31);
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
break;
case V4L2_CID_HUE:
- strncpy(ctrl->name, "Hue", 31);
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
break;
}
@@ -3693,7 +3693,7 @@ zoran_do_ioctl (struct inode *inode,
&caps);
if (caps.flags & VIDEO_DECODER_AUTO) {
std->id = V4L2_STD_ALL;
- strncpy(std->name, "Autodetect", 31);
+ strncpy(std->name, "Autodetect", sizeof(std->name)-1);
return 0;
} else
return -EINVAL;
@@ -3701,21 +3701,21 @@ zoran_do_ioctl (struct inode *inode,
switch (std->index) {
case 0:
std->id = V4L2_STD_PAL;
- strncpy(std->name, "PAL", 31);
+ strncpy(std->name, "PAL", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[0]->Ht;
break;
case 1:
std->id = V4L2_STD_NTSC;
- strncpy(std->name, "NTSC", 31);
+ strncpy(std->name, "NTSC", sizeof(std->name)-1);
std->frameperiod.numerator = 1001;
std->frameperiod.denominator = 30000;
std->framelines = zr->card.tvn[1]->Ht;
break;
case 2:
std->id = V4L2_STD_SECAM;
- strncpy(std->name, "SECAM", 31);
+ strncpy(std->name, "SECAM", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[2]->Ht;
@@ -3871,7 +3871,7 @@ zoran_do_ioctl (struct inode *inode,
memset(outp, 0, sizeof(*outp));
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
- strncpy(outp->name, "Autodetect", 31);
+ strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
return 0;
}
@@ -4689,7 +4689,7 @@ static struct file_operations zoran_fops = {
struct video_device zoran_template __devinitdata = {
.name = ZORAN_NAME,
.type = ZORAN_VID_TYPE,
-#ifdef HAVE_V4L2
+#ifdef CONFIG_VIDEO_V4L2
.type2 = ZORAN_V4L2_VID_FLAGS,
#endif
.hardware = ZORAN_HARDWARE,
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index a00fae90229..c7f6f648836 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -27,7 +27,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -43,6 +42,7 @@
#include <linux/seq_file.h>
#include <linux/ctype.h>
+#include <linux/poll.h>
#include <asm/io.h>
#include "videocodec.h"
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index 6ac3b674008..50437383ed6 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -1858,7 +1858,7 @@ int __init find_zoran(void)
DEBUG(printk(KERN_DEBUG "zoran: mapped-memory at 0x%p\n",ztv->zoran_mem));
result = request_irq(dev->irq, zoran_irq,
- SA_SHIRQ|SA_INTERRUPT,"zoran", ztv);
+ IRQF_SHARED|IRQF_DISABLED,"zoran", ztv);
if (result==-EINVAL)
{
iounmap(ztv->zoran_mem);
diff --git a/drivers/media/video/zr36120_mem.c b/drivers/media/video/zr36120_mem.c
index c87113d6cc6..416eaa93b8a 100644
--- a/drivers/media/video/zr36120_mem.c
+++ b/drivers/media/video/zr36120_mem.c
@@ -18,7 +18,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/slab.h>
diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig
index bbc22985288..ea31d847051 100644
--- a/drivers/message/fusion/Kconfig
+++ b/drivers/message/fusion/Kconfig
@@ -48,10 +48,8 @@ config FUSION_SAS
List of supported controllers:
LSISAS1064
- LSISAS1066
LSISAS1068
LSISAS1064E
- LSISAS1066E
LSISAS1068E
config FUSION_MAX_SGE
diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile
index 51740b34622..341691390e8 100644
--- a/drivers/message/fusion/Makefile
+++ b/drivers/message/fusion/Makefile
@@ -9,7 +9,6 @@
#EXTRA_CFLAGS += -DMPT_DEBUG_EXIT
#EXTRA_CFLAGS += -DMPT_DEBUG_FAIL
-
#
# driver/module specifics...
#
@@ -33,6 +32,11 @@
# For mptfc:
#CFLAGS_mptfc.o += -DMPT_DEBUG_FC
+# For mptsas:
+#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS
+#CFLAGS_mptsas.o += -DMPT_DEBUG_SAS_WIDE
+
+
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-} LSI_LOGIC
obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o
diff --git a/drivers/message/fusion/lsi/fc_log.h b/drivers/message/fusion/lsi/fc_log.h
deleted file mode 100644
index dc98d46f907..00000000000
--- a/drivers/message/fusion/lsi/fc_log.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (c) 2000-2001 LSI Logic Corporation. All rights reserved.
- *
- * NAME: fc_log.h
- * SUMMARY: MPI IocLogInfo definitions for the SYMFC9xx chips
- * DESCRIPTION: Contains the enumerated list of values that may be returned
- * in the IOCLogInfo field of a MPI Default Reply Message.
- *
- * CREATION DATE: 6/02/2000
- * ID: $Id: fc_log.h,v 4.6 2001/07/26 14:41:33 sschremm Exp $
- */
-
-
-/*
- * MpiIocLogInfo_t enum
- *
- * These 32 bit values are used in the IOCLogInfo field of the MPI reply
- * messages.
- * The value is 0xabcccccc where
- * a = The type of log info as per the MPI spec. Since these codes are
- * all for Fibre Channel this value will always be 2.
- * b = Specifies a subclass of the firmware where
- * 0 = FCP Initiator
- * 1 = FCP Target
- * 2 = LAN
- * 3 = MPI Message Layer
- * 4 = FC Link
- * 5 = Context Manager
- * 6 = Invalid Field Offset
- * 7 = State Change Info
- * all others are reserved for future use
- * c = A specific value within the subclass.
- *
- * NOTE: Any new values should be added to the end of each subclass so that the
- * codes remain consistent across firmware releases.
- */
-typedef enum _MpiIocLogInfoFc
-{
- MPI_IOCLOGINFO_FC_INIT_BASE = 0x20000000,
- MPI_IOCLOGINFO_FC_INIT_ERROR_OUT_OF_ORDER_FRAME = 0x20000001, /* received an out of order frame - unsupported */
- MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_START_OF_FRAME = 0x20000002, /* Bad Rx Frame, bad start of frame primative */
- MPI_IOCLOGINFO_FC_INIT_ERROR_BAD_END_OF_FRAME = 0x20000003, /* Bad Rx Frame, bad end of frame primative */
- MPI_IOCLOGINFO_FC_INIT_ERROR_OVER_RUN = 0x20000004, /* Bad Rx Frame, overrun */
- MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OTHER = 0x20000005, /* Other errors caught by IOC which require retries */
- MPI_IOCLOGINFO_FC_INIT_ERROR_SUBPROC_DEAD = 0x20000006, /* Main processor could not initialize sub-processor */
- MPI_IOCLOGINFO_FC_INIT_ERROR_RX_OVERRUN = 0x20000007, /* Scatter Gather overrun */
- MPI_IOCLOGINFO_FC_INIT_ERROR_RX_BAD_STATUS = 0x20000008, /* Receiver detected context mismatch via invalid header */
- MPI_IOCLOGINFO_FC_INIT_ERROR_RX_UNEXPECTED_FRAME= 0x20000009, /* CtxMgr detected unsupported frame type */
- MPI_IOCLOGINFO_FC_INIT_ERROR_LINK_FAILURE = 0x2000000A, /* Link failure occurred */
- MPI_IOCLOGINFO_FC_INIT_ERROR_TX_TIMEOUT = 0x2000000B, /* Transmitter timeout error */
-
- MPI_IOCLOGINFO_FC_TARGET_BASE = 0x21000000,
- MPI_IOCLOGINFO_FC_TARGET_NO_PDISC = 0x21000001, /* not sent because we are waiting for a PDISC from the initiator */
- MPI_IOCLOGINFO_FC_TARGET_NO_LOGIN = 0x21000002, /* not sent because we are not logged in to the remote node */
- MPI_IOCLOGINFO_FC_TARGET_DOAR_KILLED_BY_LIP = 0x21000003, /* Data Out, Auto Response, not sent due to a LIP */
- MPI_IOCLOGINFO_FC_TARGET_DIAR_KILLED_BY_LIP = 0x21000004, /* Data In, Auto Response, not sent due to a LIP */
- MPI_IOCLOGINFO_FC_TARGET_DIAR_MISSING_DATA = 0x21000005, /* Data In, Auto Response, missing data frames */
- MPI_IOCLOGINFO_FC_TARGET_DONR_KILLED_BY_LIP = 0x21000006, /* Data Out, No Response, not sent due to a LIP */
- MPI_IOCLOGINFO_FC_TARGET_WRSP_KILLED_BY_LIP = 0x21000007, /* Auto-response after a write not sent due to a LIP */
- MPI_IOCLOGINFO_FC_TARGET_DINR_KILLED_BY_LIP = 0x21000008, /* Data In, No Response, not completed due to a LIP */
- MPI_IOCLOGINFO_FC_TARGET_DINR_MISSING_DATA = 0x21000009, /* Data In, No Response, missing data frames */
- MPI_IOCLOGINFO_FC_TARGET_MRSP_KILLED_BY_LIP = 0x2100000a, /* Manual Response not sent due to a LIP */
- MPI_IOCLOGINFO_FC_TARGET_NO_CLASS_3 = 0x2100000b, /* not sent because remote node does not support Class 3 */
- MPI_IOCLOGINFO_FC_TARGET_LOGIN_NOT_VALID = 0x2100000c, /* not sent because login to remote node not validated */
- MPI_IOCLOGINFO_FC_TARGET_FROM_OUTBOUND = 0x2100000e, /* cleared from the outbound queue after a logout */
- MPI_IOCLOGINFO_FC_TARGET_WAITING_FOR_DATA_IN = 0x2100000f, /* cleared waiting for data after a logout */
-
- MPI_IOCLOGINFO_FC_LAN_BASE = 0x22000000,
- MPI_IOCLOGINFO_FC_LAN_TRANS_SGL_MISSING = 0x22000001, /* Transaction Context Sgl Missing */
- MPI_IOCLOGINFO_FC_LAN_TRANS_WRONG_PLACE = 0x22000002, /* Transaction Context found before an EOB */
- MPI_IOCLOGINFO_FC_LAN_TRANS_RES_BITS_SET = 0x22000003, /* Transaction Context value has reserved bits set */
- MPI_IOCLOGINFO_FC_LAN_WRONG_SGL_FLAG = 0x22000004, /* Invalid SGL Flags */
-
- MPI_IOCLOGINFO_FC_MSG_BASE = 0x23000000,
-
- MPI_IOCLOGINFO_FC_LINK_BASE = 0x24000000,
- MPI_IOCLOGINFO_FC_LINK_LOOP_INIT_TIMEOUT = 0x24000001, /* Loop initialization timed out */
- MPI_IOCLOGINFO_FC_LINK_ALREADY_INITIALIZED = 0x24000002, /* Another system controller already initialized the loop */
- MPI_IOCLOGINFO_FC_LINK_LINK_NOT_ESTABLISHED = 0x24000003, /* Not synchronized to signal or still negotiating (possible cable problem) */
- MPI_IOCLOGINFO_FC_LINK_CRC_ERROR = 0x24000004, /* CRC check detected error on received frame */
-
- MPI_IOCLOGINFO_FC_CTX_BASE = 0x25000000,
-
- MPI_IOCLOGINFO_FC_INVALID_FIELD_BYTE_OFFSET = 0x26000000, /* The lower 24 bits give the byte offset of the field in the request message that is invalid */
- MPI_IOCLOGINFO_FC_INVALID_FIELD_MAX_OFFSET = 0x26ffffff,
-
- MPI_IOCLOGINFO_FC_STATE_CHANGE = 0x27000000 /* The lower 24 bits give additional information concerning state change */
-
-} MpiIocLogInfoFc_t;
diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h
index 02cdc840a06..81ad77622da 100644
--- a/drivers/message/fusion/lsi/mpi.h
+++ b/drivers/message/fusion/lsi/mpi.h
@@ -6,7 +6,7 @@
* Title: MPI Message independent structures and definitions
* Creation Date: July 27, 2000
*
- * mpi.h Version: 01.05.10
+ * mpi.h Version: 01.05.11
*
* Version History
* ---------------
@@ -76,6 +76,7 @@
* Added EEDP IOCStatus codes.
* 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT.
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
+ * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -106,7 +107,7 @@
/* Note: The major versions of 0xe0 through 0xff are reserved */
/* versioning for this MPI header set */
-#define MPI_HEADER_VERSION_UNIT (0x0C)
+#define MPI_HEADER_VERSION_UNIT (0x0D)
#define MPI_HEADER_VERSION_DEV (0x00)
#define MPI_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h
index b1becec27e1..47e13e360c1 100644
--- a/drivers/message/fusion/lsi/mpi_cnfg.h
+++ b/drivers/message/fusion/lsi/mpi_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Config message, structures, and Pages
* Creation Date: July 27, 2000
*
- * mpi_cnfg.h Version: 01.05.11
+ * mpi_cnfg.h Version: 01.05.12
*
* Version History
* ---------------
@@ -266,6 +266,16 @@
* Added postpone SATA Init bit to SAS IO Unit Page 1
* ControlFlags.
* Changed LogEntry format for Log Page 0.
+ * 03-27-06 01.05.12 Added two new Flags defines for Manufacturing Page 4.
+ * Added Manufacturing Page 7.
+ * Added MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING.
+ * Added IOC Page 6.
+ * Added PrevBootDeviceForm field to CONFIG_PAGE_BIOS_2.
+ * Added MaxLBAHigh field to RAID Volume Page 0.
+ * Added Nvdata version fields to SAS IO Unit Page 0.
+ * Added AdditionalControlFlags, MaxTargetPortConnectTime,
+ * ReportDeviceMissingDelay, and IODeviceMissingDelay
+ * fields to SAS IO Unit Page 1.
* --------------------------------------------------------------------------
*/
@@ -631,9 +641,11 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_4
} CONFIG_PAGE_MANUFACTURING_4, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_4,
ManufacturingPage4_t, MPI_POINTER pManufacturingPage4_t;
-#define MPI_MANUFACTURING4_PAGEVERSION (0x03)
+#define MPI_MANUFACTURING4_PAGEVERSION (0x04)
/* defines for the Flags field */
+#define MPI_MANPAGE4_FORCE_BAD_BLOCK_TABLE (0x80)
+#define MPI_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x40)
#define MPI_MANPAGE4_IME_DISABLE (0x20)
#define MPI_MANPAGE4_IM_DISABLE (0x10)
#define MPI_MANPAGE4_IS_DISABLE (0x08)
@@ -668,6 +680,66 @@ typedef struct _CONFIG_PAGE_MANUFACTURING_6
#define MPI_MANUFACTURING6_PAGEVERSION (0x00)
+typedef struct _MPI_MANPAGE7_CONNECTOR_INFO
+{
+ U32 Pinout; /* 00h */
+ U8 Connector[16]; /* 04h */
+ U8 Location; /* 14h */
+ U8 Reserved1; /* 15h */
+ U16 Slot; /* 16h */
+ U32 Reserved2; /* 18h */
+} MPI_MANPAGE7_CONNECTOR_INFO, MPI_POINTER PTR_MPI_MANPAGE7_CONNECTOR_INFO,
+ MpiManPage7ConnectorInfo_t, MPI_POINTER pMpiManPage7ConnectorInfo_t;
+
+/* defines for the Pinout field */
+#define MPI_MANPAGE7_PINOUT_SFF_8484_L4 (0x00080000)
+#define MPI_MANPAGE7_PINOUT_SFF_8484_L3 (0x00040000)
+#define MPI_MANPAGE7_PINOUT_SFF_8484_L2 (0x00020000)
+#define MPI_MANPAGE7_PINOUT_SFF_8484_L1 (0x00010000)
+#define MPI_MANPAGE7_PINOUT_SFF_8470_L4 (0x00000800)
+#define MPI_MANPAGE7_PINOUT_SFF_8470_L3 (0x00000400)
+#define MPI_MANPAGE7_PINOUT_SFF_8470_L2 (0x00000200)
+#define MPI_MANPAGE7_PINOUT_SFF_8470_L1 (0x00000100)
+#define MPI_MANPAGE7_PINOUT_SFF_8482 (0x00000002)
+#define MPI_MANPAGE7_PINOUT_CONNECTION_UNKNOWN (0x00000001)
+
+/* defines for the Location field */
+#define MPI_MANPAGE7_LOCATION_UNKNOWN (0x01)
+#define MPI_MANPAGE7_LOCATION_INTERNAL (0x02)
+#define MPI_MANPAGE7_LOCATION_EXTERNAL (0x04)
+#define MPI_MANPAGE7_LOCATION_SWITCHABLE (0x08)
+#define MPI_MANPAGE7_LOCATION_AUTO (0x10)
+#define MPI_MANPAGE7_LOCATION_NOT_PRESENT (0x20)
+#define MPI_MANPAGE7_LOCATION_NOT_CONNECTED (0x80)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check NumPhys at runtime.
+ */
+#ifndef MPI_MANPAGE7_CONNECTOR_INFO_MAX
+#define MPI_MANPAGE7_CONNECTOR_INFO_MAX (1)
+#endif
+
+typedef struct _CONFIG_PAGE_MANUFACTURING_7
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ U32 Reserved1; /* 04h */
+ U32 Reserved2; /* 08h */
+ U32 Flags; /* 0Ch */
+ U8 EnclosureName[16]; /* 10h */
+ U8 NumPhys; /* 20h */
+ U8 Reserved3; /* 21h */
+ U16 Reserved4; /* 22h */
+ MPI_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI_MANPAGE7_CONNECTOR_INFO_MAX]; /* 24h */
+} CONFIG_PAGE_MANUFACTURING_7, MPI_POINTER PTR_CONFIG_PAGE_MANUFACTURING_7,
+ ManufacturingPage7_t, MPI_POINTER pManufacturingPage7_t;
+
+#define MPI_MANUFACTURING7_PAGEVERSION (0x00)
+
+/* defines for the Flags field */
+#define MPI_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
+
+
/****************************************************************************
* IO Unit Config Pages
****************************************************************************/
@@ -867,7 +939,7 @@ typedef struct _CONFIG_PAGE_IOC_2
} CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2,
IOCPage2_t, MPI_POINTER pIOCPage2_t;
-#define MPI_IOCPAGE2_PAGEVERSION (0x03)
+#define MPI_IOCPAGE2_PAGEVERSION (0x04)
/* IOC Page 2 Capabilities flags */
@@ -878,6 +950,7 @@ typedef struct _CONFIG_PAGE_IOC_2
#define MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT (0x00000010)
#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000020)
#define MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT (0x00000040)
+#define MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING (0x10000000)
#define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000)
#define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000)
#define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000)
@@ -975,6 +1048,44 @@ typedef struct _CONFIG_PAGE_IOC_5
#define MPI_IOCPAGE5_PAGEVERSION (0x00)
+typedef struct _CONFIG_PAGE_IOC_6
+{
+ CONFIG_PAGE_HEADER Header; /* 00h */
+ U32 CapabilitiesFlags; /* 04h */
+ U8 MaxDrivesIS; /* 08h */
+ U8 MaxDrivesIM; /* 09h */
+ U8 MaxDrivesIME; /* 0Ah */
+ U8 Reserved1; /* 0Bh */
+ U8 MinDrivesIS; /* 0Ch */
+ U8 MinDrivesIM; /* 0Dh */
+ U8 MinDrivesIME; /* 0Eh */
+ U8 Reserved2; /* 0Fh */
+ U8 MaxGlobalHotSpares; /* 10h */
+ U8 Reserved3; /* 11h */
+ U16 Reserved4; /* 12h */
+ U32 Reserved5; /* 14h */
+ U32 SupportedStripeSizeMapIS; /* 18h */
+ U32 SupportedStripeSizeMapIME; /* 1Ch */
+ U32 Reserved6; /* 20h */
+ U8 MetadataSize; /* 24h */
+ U8 Reserved7; /* 25h */
+ U16 Reserved8; /* 26h */
+ U16 MaxBadBlockTableEntries; /* 28h */
+ U16 Reserved9; /* 2Ah */
+ U16 IRNvsramUsage; /* 2Ch */
+ U16 Reserved10; /* 2Eh */
+ U32 IRNvsramVersion; /* 30h */
+ U32 Reserved11; /* 34h */
+ U32 Reserved12; /* 38h */
+} CONFIG_PAGE_IOC_6, MPI_POINTER PTR_CONFIG_PAGE_IOC_6,
+ IOCPage6_t, MPI_POINTER pIOCPage6_t;
+
+#define MPI_IOCPAGE6_PAGEVERSION (0x00)
+
+/* IOC Page 6 Capabilities Flags */
+
+#define MPI_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001)
+
/****************************************************************************
* BIOS Config Pages
@@ -1218,13 +1329,13 @@ typedef struct _CONFIG_PAGE_BIOS_2
U32 Reserved5; /* 14h */
U32 Reserved6; /* 18h */
U8 BootDeviceForm; /* 1Ch */
- U8 Reserved7; /* 1Dh */
+ U8 PrevBootDeviceForm; /* 1Ch */
U16 Reserved8; /* 1Eh */
MPI_BIOSPAGE2_BOOT_DEVICE BootDevice; /* 20h */
} CONFIG_PAGE_BIOS_2, MPI_POINTER PTR_CONFIG_PAGE_BIOS_2,
BIOSPage2_t, MPI_POINTER pBIOSPage2_t;
-#define MPI_BIOSPAGE2_PAGEVERSION (0x01)
+#define MPI_BIOSPAGE2_PAGEVERSION (0x02)
#define MPI_BIOSPAGE2_FORM_MASK (0x0F)
#define MPI_BIOSPAGE2_FORM_ADAPTER_ORDER (0x00)
@@ -2080,7 +2191,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0
RAID_VOL0_STATUS VolumeStatus; /* 08h */
RAID_VOL0_SETTINGS VolumeSettings; /* 0Ch */
U32 MaxLBA; /* 10h */
- U32 Reserved1; /* 14h */
+ U32 MaxLBAHigh; /* 14h */
U32 StripeSize; /* 18h */
U32 Reserved2; /* 1Ch */
U32 Reserved3; /* 20h */
@@ -2092,7 +2203,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0
} CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0,
RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t;
-#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x05)
+#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x06)
/* values for RAID Volume Page 0 InactiveStatus field */
#define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00)
@@ -2324,7 +2435,8 @@ typedef struct _MPI_SAS_IO_UNIT0_PHY_DATA
typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0
{
CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */
- U32 Reserved1; /* 08h */
+ U16 NvdataVersionDefault; /* 08h */
+ U16 NvdataVersionPersistent; /* 0Ah */
U8 NumPhys; /* 0Ch */
U8 Reserved2; /* 0Dh */
U16 Reserved3; /* 0Eh */
@@ -2332,7 +2444,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0
} CONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0,
SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t;
-#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x03)
+#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x04)
/* values for SAS IO Unit Page 0 PortFlags */
#define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08)
@@ -2373,12 +2485,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0
typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA
{
- U8 Port; /* 00h */
- U8 PortFlags; /* 01h */
- U8 PhyFlags; /* 02h */
- U8 MaxMinLinkRate; /* 03h */
- U32 ControllerPhyDeviceInfo;/* 04h */
- U32 Reserved1; /* 08h */
+ U8 Port; /* 00h */
+ U8 PortFlags; /* 01h */
+ U8 PhyFlags; /* 02h */
+ U8 MaxMinLinkRate; /* 03h */
+ U32 ControllerPhyDeviceInfo; /* 04h */
+ U16 MaxTargetPortConnectTime; /* 08h */
+ U16 Reserved1; /* 0Ah */
} MPI_SAS_IO_UNIT1_PHY_DATA, MPI_POINTER PTR_MPI_SAS_IO_UNIT1_PHY_DATA,
SasIOUnit1PhyData, MPI_POINTER pSasIOUnit1PhyData;
@@ -2395,15 +2508,17 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */
U16 ControlFlags; /* 08h */
U16 MaxNumSATATargets; /* 0Ah */
- U32 Reserved1; /* 0Ch */
+ U16 AdditionalControlFlags; /* 0Ch */
+ U16 Reserved1; /* 0Eh */
U8 NumPhys; /* 10h */
U8 SATAMaxQDepth; /* 11h */
- U16 Reserved2; /* 12h */
+ U8 ReportDeviceMissingDelay; /* 12h */
+ U8 IODeviceMissingDelay; /* 13h */
MPI_SAS_IO_UNIT1_PHY_DATA PhyData[MPI_SAS_IOUNIT1_PHY_MAX]; /* 14h */
} CONFIG_PAGE_SAS_IO_UNIT_1, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_1,
SasIOUnitPage1_t, MPI_POINTER pSasIOUnitPage1_t;
-#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x05)
+#define MPI_SASIOUNITPAGE1_PAGEVERSION (0x06)
/* values for SAS IO Unit Page 1 ControlFlags */
#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000)
@@ -2428,6 +2543,13 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1
#define MPI_SAS_IOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002)
#define MPI_SAS_IOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
+/* values for SAS IO Unit Page 1 AdditionalControlFlags */
+#define MPI_SAS_IOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001)
+
+/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */
+#define MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F)
+#define MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16 (0x80)
+
/* values for SAS IO Unit Page 1 PortFlags */
#define MPI_SAS_IOUNIT1_PORT_FLAGS_0_TARGET_IOC_NUM (0x00)
#define MPI_SAS_IOUNIT1_PORT_FLAGS_1_TARGET_IOC_NUM (0x04)
diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt
index 4a5f8dd1d76..582cfe7c2aa 100644
--- a/drivers/message/fusion/lsi/mpi_history.txt
+++ b/drivers/message/fusion/lsi/mpi_history.txt
@@ -6,25 +6,25 @@
Copyright (c) 2000-2005 LSI Logic Corporation.
---------------------------------------
- Header Set Release Version: 01.05.12
- Header Set Release Date: 08-30-05
+ Header Set Release Version: 01.05.13
+ Header Set Release Date: 03-27-06
---------------------------------------
Filename Current version Prior version
---------- --------------- -------------
- mpi.h 01.05.10 01.05.09
- mpi_ioc.h 01.05.10 01.05.09
- mpi_cnfg.h 01.05.11 01.05.10
- mpi_init.h 01.05.06 01.05.06
- mpi_targ.h 01.05.05 01.05.05
+ mpi.h 01.05.11 01.05.10
+ mpi_ioc.h 01.05.11 01.05.10
+ mpi_cnfg.h 01.05.12 01.05.11
+ mpi_init.h 01.05.07 01.05.06
+ mpi_targ.h 01.05.06 01.05.05
mpi_fc.h 01.05.01 01.05.01
mpi_lan.h 01.05.01 01.05.01
mpi_raid.h 01.05.02 01.05.02
mpi_tool.h 01.05.03 01.05.03
mpi_inb.h 01.05.01 01.05.01
- mpi_sas.h 01.05.02 01.05.01
- mpi_type.h 01.05.02 01.05.01
- mpi_history.txt 01.05.12 01.05.11
+ mpi_sas.h 01.05.03 01.05.02
+ mpi_type.h 01.05.02 01.05.02
+ mpi_history.txt 01.05.13 01.05.12
* Date Version Description
@@ -93,6 +93,7 @@ mpi.h
* Added EEDP IOCStatus codes.
* 08-03-05 01.05.09 Bumped MPI_HEADER_VERSION_UNIT.
* 08-30-05 01.05.10 Added 2 new IOCStatus codes for Target.
+ * 03-27-06 01.05.11 Bumped MPI_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
mpi_ioc.h
@@ -170,6 +171,17 @@ mpi_ioc.h
* Added new ReasonCode value for SAS Device Status Change
* event.
* Added new family code for FC949E.
+ * 03-27-06 01.05.11 Added MPI_IOCFACTS_CAPABILITY_TLR.
+ * Added additional Reason Codes and more event data fields
+ * to EVENT_DATA_SAS_DEVICE_STATUS_CHANGE.
+ * Added EVENT_DATA_SAS_BROADCAST_PRIMITIVE structure and
+ * new event.
+ * Added MPI_EVENT_SAS_SMP_ERROR and event data structure.
+ * Added MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE and event
+ * data structure.
+ * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event
+ * data structure.
+ * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION.
* --------------------------------------------------------------------------
mpi_cnfg.h
@@ -425,6 +437,16 @@ mpi_cnfg.h
* Added postpone SATA Init bit to SAS IO Unit Page 1
* ControlFlags.
* Changed LogEntry format for Log Page 0.
+ * 03-27-06 01.05.12 Added two new Flags defines for Manufacturing Page 4.
+ * Added Manufacturing Page 7.
+ * Added MPI_IOCPAGE2_CAP_FLAGS_RAID_64_BIT_ADDRESSING.
+ * Added IOC Page 6.
+ * Added PrevBootDeviceForm field to CONFIG_PAGE_BIOS_2.
+ * Added MaxLBAHigh field to RAID Volume Page 0.
+ * Added Nvdata version fields to SAS IO Unit Page 0.
+ * Added AdditionalControlFlags, MaxTargetPortConnectTime,
+ * ReportDeviceMissingDelay, and IODeviceMissingDelay
+ * fields to SAS IO Unit Page 1.
* --------------------------------------------------------------------------
mpi_init.h
@@ -467,6 +489,7 @@ mpi_init.h
* Added four new defines for SEP SlotStatus.
* 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
* unique in the first 32 characters.
+ * 03-27-06 01.05.07 Added Task Management type of Clear ACA.
* --------------------------------------------------------------------------
mpi_targ.h
@@ -511,6 +534,7 @@ mpi_targ.h
* 02-22-05 01.05.03 Changed a comment.
* 03-11-05 01.05.04 Removed TargetAssistExtended Request.
* 06-24-05 01.05.05 Added TargetAssistExtended structures and defines.
+ * 03-27-06 01.05.06 Added a comment.
* --------------------------------------------------------------------------
mpi_fc.h
@@ -610,6 +634,10 @@ mpi_sas.h
* 08-30-05 01.05.02 Added DeviceInfo bit for SEP.
* Added PrimFlags and Primitive field to SAS IO Unit
* Control request, and added a new operation code.
+ * 03-27-06 01.05.03 Added Force Full Discovery, Transmit Port Select Signal,
+ * and Remove Device operations to SAS IO Unit Control.
+ * Added DevHandle field to SAS IO Unit Control request and
+ * reply.
* --------------------------------------------------------------------------
mpi_type.h
@@ -625,20 +653,20 @@ mpi_type.h
mpi_history.txt Parts list history
-Filename 01.05.12 01.05.11 01.05.10 01.05.09
----------- -------- -------- -------- --------
-mpi.h 01.05.10 01.05.09 01.05.08 01.05.07
-mpi_ioc.h 01.05.10 01.05.09 01.05.09 01.05.08
-mpi_cnfg.h 01.05.11 01.05.10 01.05.09 01.05.08
-mpi_init.h 01.05.06 01.05.06 01.05.05 01.05.04
-mpi_targ.h 01.05.05 01.05.05 01.05.05 01.05.04
-mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01
-mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01
-mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02
-mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03
-mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01
-mpi_sas.h 01.05.02 01.05.01 01.05.01 01.05.01
-mpi_type.h 01.05.02 01.05.01 01.05.01 01.05.01
+Filename 01.05.13 01.05.12 01.05.11 01.05.10 01.05.09
+---------- -------- -------- -------- -------- --------
+mpi.h 01.05.11 01.05.10 01.05.09 01.05.08 01.05.07
+mpi_ioc.h 01.05.11 01.05.10 01.05.09 01.05.09 01.05.08
+mpi_cnfg.h 01.05.12 01.05.11 01.05.10 01.05.09 01.05.08
+mpi_init.h 01.05.07 01.05.06 01.05.06 01.05.05 01.05.04
+mpi_targ.h 01.05.06 01.05.05 01.05.05 01.05.05 01.05.04
+mpi_fc.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_lan.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_raid.h 01.05.02 01.05.02 01.05.02 01.05.02 01.05.02
+mpi_tool.h 01.05.03 01.05.03 01.05.03 01.05.03 01.05.03
+mpi_inb.h 01.05.01 01.05.01 01.05.01 01.05.01 01.05.01
+mpi_sas.h 01.05.03 01.05.02 01.05.01 01.05.01 01.05.01
+mpi_type.h 01.05.02 01.05.02 01.05.01 01.05.01 01.05.01
Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03
---------- -------- -------- -------- -------- -------- --------
diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h
index 68941f459ca..c1c678989a2 100644
--- a/drivers/message/fusion/lsi/mpi_init.h
+++ b/drivers/message/fusion/lsi/mpi_init.h
@@ -6,7 +6,7 @@
* Title: MPI initiator mode messages and structures
* Creation Date: June 8, 2000
*
- * mpi_init.h Version: 01.05.06
+ * mpi_init.h Version: 01.05.07
*
* Version History
* ---------------
@@ -52,6 +52,7 @@
* Added four new defines for SEP SlotStatus.
* 08-03-05 01.05.06 Fixed some MPI_SCSIIO32_MSGFLGS_ defines to make them
* unique in the first 32 characters.
+ * 03-27-06 01.05.07 Added Task Management type of Clear ACA.
* --------------------------------------------------------------------------
*/
@@ -427,6 +428,7 @@ typedef struct _MSG_SCSI_TASK_MGMT
#define MPI_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
#define MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
+#define MPI_SCSITASKMGMT_TASKTYPE_CLEAR_ACA (0x08)
/* MsgFlags bits */
#define MPI_SCSITASKMGMT_MSGFLAGS_TARGET_RESET_OPTION (0x00)
diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h
index 2c5f43fa7c7..18ba407fd39 100644
--- a/drivers/message/fusion/lsi/mpi_ioc.h
+++ b/drivers/message/fusion/lsi/mpi_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: August 11, 2000
*
- * mpi_ioc.h Version: 01.05.10
+ * mpi_ioc.h Version: 01.05.11
*
* Version History
* ---------------
@@ -87,6 +87,17 @@
* Added new ReasonCode value for SAS Device Status Change
* event.
* Added new family code for FC949E.
+ * 03-27-06 01.05.11 Added MPI_IOCFACTS_CAPABILITY_TLR.
+ * Added additional Reason Codes and more event data fields
+ * to EVENT_DATA_SAS_DEVICE_STATUS_CHANGE.
+ * Added EVENT_DATA_SAS_BROADCAST_PRIMITIVE structure and
+ * new event.
+ * Added MPI_EVENT_SAS_SMP_ERROR and event data structure.
+ * Added MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE and event
+ * data structure.
+ * Added MPI_EVENT_SAS_INIT_TABLE_OVERFLOW and event
+ * data structure.
+ * Added MPI_EXT_IMAGE_TYPE_INITIALIZATION.
* --------------------------------------------------------------------------
*/
@@ -272,6 +283,7 @@ typedef struct _MSG_IOC_FACTS_REPLY
#define MPI_IOCFACTS_CAPABILITY_MULTICAST (0x00000100)
#define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (0x00000200)
#define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (0x00000400)
+#define MPI_IOCFACTS_CAPABILITY_TLR (0x00000800)
/*****************************************************************************
@@ -448,30 +460,34 @@ typedef struct _MSG_EVENT_ACK_REPLY
/* Event */
-#define MPI_EVENT_NONE (0x00000000)
-#define MPI_EVENT_LOG_DATA (0x00000001)
-#define MPI_EVENT_STATE_CHANGE (0x00000002)
-#define MPI_EVENT_UNIT_ATTENTION (0x00000003)
-#define MPI_EVENT_IOC_BUS_RESET (0x00000004)
-#define MPI_EVENT_EXT_BUS_RESET (0x00000005)
-#define MPI_EVENT_RESCAN (0x00000006)
-#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007)
-#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008)
-#define MPI_EVENT_LOGOUT (0x00000009)
-#define MPI_EVENT_EVENT_CHANGE (0x0000000A)
-#define MPI_EVENT_INTEGRATED_RAID (0x0000000B)
-#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C)
-#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D)
-#define MPI_EVENT_QUEUE_FULL (0x0000000E)
-#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F)
-#define MPI_EVENT_SAS_SES (0x00000010)
-#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011)
-#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012)
-#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013)
-#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014)
-#define MPI_EVENT_IR2 (0x00000015)
-#define MPI_EVENT_SAS_DISCOVERY (0x00000016)
-#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021)
+#define MPI_EVENT_NONE (0x00000000)
+#define MPI_EVENT_LOG_DATA (0x00000001)
+#define MPI_EVENT_STATE_CHANGE (0x00000002)
+#define MPI_EVENT_UNIT_ATTENTION (0x00000003)
+#define MPI_EVENT_IOC_BUS_RESET (0x00000004)
+#define MPI_EVENT_EXT_BUS_RESET (0x00000005)
+#define MPI_EVENT_RESCAN (0x00000006)
+#define MPI_EVENT_LINK_STATUS_CHANGE (0x00000007)
+#define MPI_EVENT_LOOP_STATE_CHANGE (0x00000008)
+#define MPI_EVENT_LOGOUT (0x00000009)
+#define MPI_EVENT_EVENT_CHANGE (0x0000000A)
+#define MPI_EVENT_INTEGRATED_RAID (0x0000000B)
+#define MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE (0x0000000C)
+#define MPI_EVENT_ON_BUS_TIMER_EXPIRED (0x0000000D)
+#define MPI_EVENT_QUEUE_FULL (0x0000000E)
+#define MPI_EVENT_SAS_DEVICE_STATUS_CHANGE (0x0000000F)
+#define MPI_EVENT_SAS_SES (0x00000010)
+#define MPI_EVENT_PERSISTENT_TABLE_FULL (0x00000011)
+#define MPI_EVENT_SAS_PHY_LINK_STATUS (0x00000012)
+#define MPI_EVENT_SAS_DISCOVERY_ERROR (0x00000013)
+#define MPI_EVENT_IR_RESYNC_UPDATE (0x00000014)
+#define MPI_EVENT_IR2 (0x00000015)
+#define MPI_EVENT_SAS_DISCOVERY (0x00000016)
+#define MPI_EVENT_SAS_BROADCAST_PRIMITIVE (0x00000017)
+#define MPI_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x00000018)
+#define MPI_EVENT_SAS_INIT_TABLE_OVERFLOW (0x00000019)
+#define MPI_EVENT_SAS_SMP_ERROR (0x0000001A)
+#define MPI_EVENT_LOG_ENTRY_ADDED (0x00000021)
/* AckRequired field values */
@@ -558,18 +574,25 @@ typedef struct _EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
U8 PhyNum; /* 0Eh */
U8 Reserved1; /* 0Fh */
U64 SASAddress; /* 10h */
+ U8 LUN[8]; /* 18h */
+ U16 TaskTag; /* 20h */
+ U16 Reserved2; /* 22h */
} EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
MPI_POINTER PTR_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
MpiEventDataSasDeviceStatusChange_t,
MPI_POINTER pMpiEventDataSasDeviceStatusChange_t;
/* MPI SAS Device Status Change Event data ReasonCode values */
-#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03)
-#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04)
-#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
-#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06)
-#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
-#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
+#define MPI_EVENT_SAS_DEV_STAT_RC_ADDED (0x03)
+#define MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING (0x04)
+#define MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
+#define MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED (0x06)
+#define MPI_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
+#define MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
+#define MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
+#define MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
+#define MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
+#define MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
/* SCSI Event data for Queue Full event */
@@ -742,6 +765,27 @@ typedef struct _EVENT_DATA_SAS_SES
} EVENT_DATA_SAS_SES, MPI_POINTER PTR_EVENT_DATA_SAS_SES,
MpiEventDataSasSes_t, MPI_POINTER pMpiEventDataSasSes_t;
+/* SAS Broadcast Primitive Event data */
+
+typedef struct _EVENT_DATA_SAS_BROADCAST_PRIMITIVE
+{
+ U8 PhyNum; /* 00h */
+ U8 Port; /* 01h */
+ U8 PortWidth; /* 02h */
+ U8 Primitive; /* 04h */
+} EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
+ MPI_POINTER PTR_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
+ MpiEventDataSasBroadcastPrimitive_t,
+ MPI_POINTER pMpiEventDataSasBroadcastPrimitive_t;
+
+#define MPI_EVENT_PRIMITIVE_CHANGE (0x01)
+#define MPI_EVENT_PRIMITIVE_EXPANDER (0x03)
+#define MPI_EVENT_PRIMITIVE_RESERVED2 (0x04)
+#define MPI_EVENT_PRIMITIVE_RESERVED3 (0x05)
+#define MPI_EVENT_PRIMITIVE_RESERVED4 (0x06)
+#define MPI_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07)
+#define MPI_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08)
+
/* SAS Phy Link Status Event data */
typedef struct _EVENT_DATA_SAS_PHY_LINK_STATUS
@@ -804,6 +848,53 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR
#define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800)
#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000)
+/* SAS SMP Error Event data */
+
+typedef struct _EVENT_DATA_SAS_SMP_ERROR
+{
+ U8 Status; /* 00h */
+ U8 Port; /* 01h */
+ U8 SMPFunctionResult; /* 02h */
+ U8 Reserved1; /* 03h */
+ U64 SASAddress; /* 04h */
+} EVENT_DATA_SAS_SMP_ERROR, MPI_POINTER PTR_EVENT_DATA_SAS_SMP_ERROR,
+ MpiEventDataSasSmpError_t, MPI_POINTER pMpiEventDataSasSmpError_t;
+
+/* defines for the Status field of the SAS SMP Error event */
+#define MPI_EVENT_SAS_SMP_FUNCTION_RESULT_VALID (0x00)
+#define MPI_EVENT_SAS_SMP_CRC_ERROR (0x01)
+#define MPI_EVENT_SAS_SMP_TIMEOUT (0x02)
+#define MPI_EVENT_SAS_SMP_NO_DESTINATION (0x03)
+#define MPI_EVENT_SAS_SMP_BAD_DESTINATION (0x04)
+
+/* SAS Initiator Device Status Change Event data */
+
+typedef struct _EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
+{
+ U8 ReasonCode; /* 00h */
+ U8 Port; /* 01h */
+ U16 DevHandle; /* 02h */
+ U64 SASAddress; /* 04h */
+} EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
+ MPI_POINTER PTR_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
+ MpiEventDataSasInitDevStatusChange_t,
+ MPI_POINTER pMpiEventDataSasInitDevStatusChange_t;
+
+/* defines for the ReasonCode field of the SAS Initiator Device Status Change event */
+#define MPI_EVENT_SAS_INIT_RC_ADDED (0x01)
+
+/* SAS Initiator Device Table Overflow Event data */
+
+typedef struct _EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
+{
+ U8 MaxInit; /* 00h */
+ U8 CurrentInit; /* 01h */
+ U16 Reserved1; /* 02h */
+} EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+ MPI_POINTER PTR_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
+ MpiEventDataSasInitTableOverflow_t,
+ MPI_POINTER pMpiEventDataSasInitTableOverflow_t;
+
/*****************************************************************************
*
@@ -1013,5 +1104,6 @@ typedef struct _MPI_EXT_IMAGE_HEADER
#define MPI_EXT_IMAGE_TYPE_FW (0x01)
#define MPI_EXT_IMAGE_TYPE_NVDATA (0x03)
#define MPI_EXT_IMAGE_TYPE_BOOTLOADER (0x04)
+#define MPI_EXT_IMAGE_TYPE_INITIALIZATION (0x05)
#endif
diff --git a/drivers/message/fusion/lsi/mpi_log_sas.h b/drivers/message/fusion/lsi/mpi_log_sas.h
index a9c14ad132c..871ebc08b70 100644
--- a/drivers/message/fusion/lsi/mpi_log_sas.h
+++ b/drivers/message/fusion/lsi/mpi_log_sas.h
@@ -13,6 +13,8 @@
#ifndef IOPI_IOCLOGINFO_H_INCLUDED
#define IOPI_IOCLOGINFO_H_INCLUDED
+#define SAS_LOGINFO_NEXUS_LOSS 0x31170000
+#define SAS_LOGINFO_MASK 0xFFFF0000
/****************************************************************************/
/* IOC LOGINFO defines, 0x00000000 - 0x0FFFFFFF */
@@ -51,6 +53,9 @@
#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DNM (0x00030500) /* Device Not Mapped */
#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_PERSIST (0x00030600) /* Persistent Page not found */
#define IOP_LOGINFO_CODE_CONFIG_INVALID_PAGE_DEFAULT (0x00030700) /* Default Page not found */
+
+#define IOP_LOGINFO_CODE_DIAG_MSG_ERROR (0x00040000) /* Error handling diag msg - or'd with diag status */
+
#define IOP_LOGINFO_CODE_TASK_TERMINATED (0x00050000)
#define IOP_LOGINFO_CODE_ENCL_MGMT_READ_ACTION_ERR0R (0x00060001) /* Read Action not supported for SEP msg */
@@ -103,6 +108,7 @@
#define PL_LOGINFO_CODE_IO_EXECUTED (0x00140000)
#define PL_LOGINFO_CODE_PERS_RESV_OUT_NOT_AFFIL_OWNER (0x00150000)
#define PL_LOGINFO_CODE_OPEN_TXDMA_ABORT (0x00160000)
+#define PL_LOGINFO_CODE_IO_DEVICE_MISSING_DELAY_RETRY (0x00170000)
#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE (0x00000100)
#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_NO_DEST_TIMEOUT (0x00000101)
#define PL_LOGINFO_SUB_CODE_OPEN_FAILURE_ORR_TIMEOUT (0x0000011A) /* Open Reject (Retry) Timeout */
@@ -165,11 +171,81 @@
/****************************************************************************/
/* IR LOGINFO_CODE defines, valid if IOC_LOGINFO_ORIGINATOR = IR */
/****************************************************************************/
-#define IR_LOGINFO_CODE_UNUSED1 (0x00010000)
-#define IR_LOGINFO_CODE_UNUSED2 (0x00020000)
+#define IR_LOGINFO_RAID_ACTION_ERROR (0x00010000)
+#define IR_LOGINFO_CODE_UNUSED2 (0x00020000)
+
+/* Amount of information passed down for Create Volume is too large */
+#define IR_LOGINFO_VOLUME_CREATE_INVALID_LENGTH (0x00010001)
+/* Creation of duplicate volume attempted (Bus/Target ID checked) */
+#define IR_LOGINFO_VOLUME_CREATE_DUPLICATE (0x00010002)
+/* Creation failed due to maximum number of supported volumes exceeded */
+#define IR_LOGINFO_VOLUME_CREATE_NO_SLOTS (0x00010003)
+/* Creation failed due to DMA error in trying to read from host */
+#define IR_LOGINFO_VOLUME_CREATE_DMA_ERROR (0x00010004)
+/* Creation failed due to invalid volume type passed down */
+#define IR_LOGINFO_VOLUME_CREATE_INVALID_VOLUME_TYPE (0x00010005)
+/* Creation failed due to error reading MFG Page 4 */
+#define IR_LOGINFO_VOLUME_MFG_PAGE4_ERROR (0x00010006)
+/* Creation failed when trying to create internal structures */
+#define IR_LOGINFO_VOLUME_INTERNAL_CONFIG_STRUCTURE_ERROR (0x00010007)
+
+/* Activation failed due to trying to activate an already active volume */
+#define IR_LOGINFO_VOLUME_ACTIVATING_AN_ACTIVE_VOLUME (0x00010010)
+/* Activation failed due to trying to active unsupported volume type */
+#define IR_LOGINFO_VOLUME_ACTIVATING_INVALID_VOLUME_TYPE (0x00010011)
+/* Activation failed due to trying to active too many volumes */
+#define IR_LOGINFO_VOLUME_ACTIVATING_TOO_MANY_VOLUMES (0x00010012)
+/* Activation failed due to Volume ID in use already */
+#define IR_LOGINFO_VOLUME_ACTIVATING_VOLUME_ID_IN_USE (0x00010013)
+/* Activation failed call to activateVolume returned failure */
+#define IR_LOGINFO_VOLUME_ACTIVATE_VOLUME_FAILED (0x00010014)
+/* Activation failed trying to import the volume */
+#define IR_LOGINFO_VOLUME_ACTIVATING_IMPORT_VOLUME_FAILED (0x00010015)
+
+/* Phys Disk failed, too many phys disks */
+#define IR_LOGINFO_PHYSDISK_CREATE_TOO_MANY_DISKS (0x00010020)
+/* Amount of information passed down for Create Pnysdisk is too large */
+#define IR_LOGINFO_PHYSDISK_CREATE_INVALID_LENGTH (0x00010021)
+/* Creation failed due to DMA error in trying to read from host */
+#define IR_LOGINFO_PHYSDISK_CREATE_DMA_ERROR (0x00010022)
+/* Creation failed due to invalid Bus TargetID passed down */
+#define IR_LOGINFO_PHYSDISK_CREATE_BUS_TID_INVALID (0x00010023)
+/* Creation failed due to error in creating RAID Phys Disk Config Page */
+#define IR_LOGINFO_PHYSDISK_CREATE_CONFIG_PAGE_ERROR (0x00010024)
+
+
+/* Compatibility Error : IR Disabled */
+#define IR_LOGINFO_COMPAT_ERROR_RAID_DISABLED (0x00010030)
+/* Compatibility Error : Inquiry Comand failed */
+#define IR_LOGINFO_COMPAT_ERROR_INQUIRY_FAILED (0x00010031)
+/* Compatibility Error : Device not direct access device */
+#define IR_LOGINFO_COMPAT_ERROR_NOT_DIRECT_ACCESS (0x00010032)
+/* Compatibility Error : Removable device found */
+#define IR_LOGINFO_COMPAT_ERROR_REMOVABLE_FOUND (0x00010033)
+/* Compatibility Error : Device SCSI Version not 2 or higher */
+#define IR_LOGINFO_COMPAT_ERROR_NEED_SCSI_2_OR_HIGHER (0x00010034)
+/* Compatibility Error : SATA device, 48 BIT LBA not supported */
+#define IR_LOGINFO_COMPAT_ERROR_SATA_48BIT_LBA_NOT_SUPPORTED (0x00010035)
+/* Compatibility Error : Device does not have 512 byte block sizes */
+#define IR_LOGINFO_COMPAT_ERROR_DEVICE_NOT_512_BYTE_BLOCK (0x00010036)
+/* Compatibility Error : Volume Type check failed */
+#define IR_LOGINFO_COMPAT_ERROR_VOLUME_TYPE_CHECK_FAILED (0x00010037)
+/* Compatibility Error : Volume Type is unsupported by FW */
+#define IR_LOGINFO_COMPAT_ERROR_UNSUPPORTED_VOLUME_TYPE (0x00010038)
+/* Compatibility Error : Disk drive too small for use in volume */
+#define IR_LOGINFO_COMPAT_ERROR_DISK_TOO_SMALL (0x00010039)
+/* Compatibility Error : Phys disk for Create Volume not found */
+#define IR_LOGINFO_COMPAT_ERROR_PHYS_DISK_NOT_FOUND (0x0001003A)
+/* Compatibility Error : membership count error, too many or too few disks for volume type */
+#define IR_LOGINFO_COMPAT_ERROR_MEMBERSHIP_COUNT (0x0001003B)
+/* Compatibility Error : Disk stripe sizes must be 64KB */
+#define IR_LOGINFO_COMPAT_ERROR_NON_64K_STRIPE_SIZE (0x0001003C)
+/* Compatibility Error : IME size limited to < 2TB */
+#define IR_LOGINFO_COMPAT_ERROR_IME_VOL_NOT_CURRENTLY_SUPPORTED (0x0001003D)
+
/****************************************************************************/
-/* Defines for convienence */
+/* Defines for convenience */
/****************************************************************************/
#define IOC_LOGINFO_PREFIX_IOP ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_IOP)
#define IOC_LOGINFO_PREFIX_PL ((MPI_IOCLOGINFO_TYPE_SAS << MPI_IOCLOGINFO_TYPE_SHIFT) | IOC_LOGINFO_ORIGINATOR_PL)
diff --git a/drivers/message/fusion/lsi/mpi_sas.h b/drivers/message/fusion/lsi/mpi_sas.h
index 70514867bdd..50b8f0a8f45 100644
--- a/drivers/message/fusion/lsi/mpi_sas.h
+++ b/drivers/message/fusion/lsi/mpi_sas.h
@@ -6,7 +6,7 @@
* Title: MPI Serial Attached SCSI structures and definitions
* Creation Date: August 19, 2004
*
- * mpi_sas.h Version: 01.05.02
+ * mpi_sas.h Version: 01.05.03
*
* Version History
* ---------------
@@ -17,6 +17,10 @@
* 08-30-05 01.05.02 Added DeviceInfo bit for SEP.
* Added PrimFlags and Primitive field to SAS IO Unit
* Control request, and added a new operation code.
+ * 03-27-06 01.05.03 Added Force Full Discovery, Transmit Port Select Signal,
+ * and Remove Device operations to SAS IO Unit Control.
+ * Added DevHandle field to SAS IO Unit Control request and
+ * reply.
* --------------------------------------------------------------------------
*/
@@ -209,7 +213,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
U8 Reserved1; /* 01h */
U8 ChainOffset; /* 02h */
U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
+ U16 DevHandle; /* 04h */
U8 Reserved3; /* 06h */
U8 MsgFlags; /* 07h */
U32 MsgContext; /* 08h */
@@ -231,6 +235,9 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REQUEST
#define MPI_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08)
#define MPI_SAS_OP_MAP_CURRENT (0x09)
#define MPI_SAS_OP_SEND_PRIMITIVE (0x0A)
+#define MPI_SAS_OP_FORCE_FULL_DISCOVERY (0x0B)
+#define MPI_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
+#define MPI_SAS_OP_TRANSMIT_REMOVE_DEVICE (0x0D)
/* values for the PrimFlags field */
#define MPI_SAS_PRIMFLAGS_SINGLE (0x08)
@@ -245,7 +252,7 @@ typedef struct _MSG_SAS_IOUNIT_CONTROL_REPLY
U8 Reserved1; /* 01h */
U8 MsgLength; /* 02h */
U8 Function; /* 03h */
- U16 Reserved2; /* 04h */
+ U16 DevHandle; /* 04h */
U8 Reserved3; /* 06h */
U8 MsgFlags; /* 07h */
U32 MsgContext; /* 08h */
diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h
index 3f462859cee..20b66731577 100644
--- a/drivers/message/fusion/lsi/mpi_targ.h
+++ b/drivers/message/fusion/lsi/mpi_targ.h
@@ -6,7 +6,7 @@
* Title: MPI Target mode messages and structures
* Creation Date: June 22, 2000
*
- * mpi_targ.h Version: 01.05.05
+ * mpi_targ.h Version: 01.05.06
*
* Version History
* ---------------
@@ -54,6 +54,7 @@
* 02-22-05 01.05.03 Changed a comment.
* 03-11-05 01.05.04 Removed TargetAssistExtended Request.
* 06-24-05 01.05.05 Added TargetAssistExtended structures and defines.
+ * 03-27-06 01.05.06 Added a comment.
* --------------------------------------------------------------------------
*/
@@ -351,7 +352,7 @@ typedef struct _MSG_TARGET_ASSIST_REQUEST
#define TARGET_ASSIST_FLAGS_CONFIRMED (0x08)
#define TARGET_ASSIST_FLAGS_REPOST_CMD_BUFFER (0x80)
-
+/* Standard Target Mode Reply message */
typedef struct _MSG_TARGET_ERROR_REPLY
{
U16 Reserved; /* 00h */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 12dd8d493ee..29d0635cce1 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -46,7 +46,6 @@
*/
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -369,20 +368,21 @@ static irqreturn_t
mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
{
MPT_ADAPTER *ioc = bus_id;
- u32 pa;
+ u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
+
+ if (pa == 0xFFFFFFFF)
+ return IRQ_NONE;
/*
* Drain the reply FIFO!
*/
- while (1) {
- pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
- if (pa == 0xFFFFFFFF)
- return IRQ_HANDLED;
- else if (pa & MPI_ADDRESS_REPLY_A_BIT)
+ do {
+ if (pa & MPI_ADDRESS_REPLY_A_BIT)
mpt_reply(ioc, pa);
else
mpt_turbo_reply(ioc, pa);
- }
+ pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
+ } while (pa != 0xFFFFFFFF);
return IRQ_HANDLED;
}
@@ -436,8 +436,6 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply)
*/
if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) {
freereq = 0;
- devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n",
- ioc->name, pEvReply));
} else {
devtverboseprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n",
ioc->name, pEvReply));
@@ -678,19 +676,19 @@ int
mpt_device_driver_register(struct mpt_pci_driver * dd_cbfunc, int cb_idx)
{
MPT_ADAPTER *ioc;
+ const struct pci_device_id *id;
- if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS) {
+ if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS)
return -EINVAL;
- }
MptDeviceDriverHandlers[cb_idx] = dd_cbfunc;
/* call per pci device probe entry point */
list_for_each_entry(ioc, &ioc_list, list) {
- if(dd_cbfunc->probe) {
- dd_cbfunc->probe(ioc->pcidev,
- ioc->pcidev->driver->id_table);
- }
+ id = ioc->pcidev->driver ?
+ ioc->pcidev->driver->id_table : NULL;
+ if (dd_cbfunc->probe)
+ dd_cbfunc->probe(ioc->pcidev, id);
}
return 0;
@@ -1056,9 +1054,8 @@ mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init)
dinitprintk((MYIOC_s_INFO_FMT
"host_page_buffer @ %p, dma @ %x, sz=%d bytes\n",
- ioc->name,
- ioc->HostPageBuffer,
- ioc->HostPageBuffer_dma,
+ ioc->name, ioc->HostPageBuffer,
+ (u32)ioc->HostPageBuffer_dma,
host_page_buffer_sz));
ioc->alloc_total += host_page_buffer_sz;
ioc->HostPageBuffer_sz = host_page_buffer_sz;
@@ -1220,31 +1217,25 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
port = psize = 0;
for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) {
if (pci_resource_flags(pdev, ii) & PCI_BASE_ADDRESS_SPACE_IO) {
+ if (psize)
+ continue;
/* Get I/O space! */
port = pci_resource_start(pdev, ii);
psize = pci_resource_len(pdev,ii);
} else {
+ if (msize)
+ continue;
/* Get memmap */
mem_phys = pci_resource_start(pdev, ii);
msize = pci_resource_len(pdev,ii);
- break;
}
}
ioc->mem_size = msize;
- if (ii == DEVICE_COUNT_RESOURCE) {
- printk(KERN_ERR MYNAM ": ERROR - MPT adapter has no memory regions defined!\n");
- kfree(ioc);
- return -EINVAL;
- }
-
- dinitprintk((KERN_INFO MYNAM ": MPT adapter @ %lx, msize=%dd bytes\n", mem_phys, msize));
- dinitprintk((KERN_INFO MYNAM ": (port i/o @ %lx, psize=%dd bytes)\n", port, psize));
-
mem = NULL;
/* Get logical ptr for PciMem0 space */
/*mem = ioremap(mem_phys, msize);*/
- mem = ioremap(mem_phys, 0x100);
+ mem = ioremap(mem_phys, msize);
if (mem == NULL) {
printk(KERN_ERR MYNAM ": ERROR - Unable to map adapter memory!\n");
kfree(ioc);
@@ -1344,11 +1335,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->bus_type = SAS;
ioc->errata_flag_1064 = 1;
}
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) {
- ioc->prod_name = "LSISAS1066";
- ioc->bus_type = SAS;
- ioc->errata_flag_1064 = 1;
- }
else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) {
ioc->prod_name = "LSISAS1068";
ioc->bus_type = SAS;
@@ -1358,14 +1344,14 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->prod_name = "LSISAS1064E";
ioc->bus_type = SAS;
}
- else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) {
- ioc->prod_name = "LSISAS1066E";
- ioc->bus_type = SAS;
- }
else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) {
ioc->prod_name = "LSISAS1068E";
ioc->bus_type = SAS;
}
+ else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
+ ioc->prod_name = "LSISAS1078";
+ ioc->bus_type = SAS;
+ }
if (ioc->errata_flag_1064)
pci_disable_io_access(pdev);
@@ -1391,6 +1377,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id)
printk(KERN_WARNING MYNAM
": WARNING - %s did not initialize properly! (%d)\n",
ioc->name, r);
+
list_del(&ioc->list);
if (ioc->alt_ioc)
ioc->alt_ioc->alt_ioc = NULL;
@@ -1706,7 +1693,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
printk(MYIOC_s_INFO_FMT "PCI-MSI enabled\n",
ioc->name);
rc = request_irq(ioc->pcidev->irq, mpt_interrupt,
- SA_SHIRQ, ioc->name, ioc);
+ IRQF_SHARED, ioc->name, ioc);
if (rc < 0) {
printk(MYIOC_s_ERR_FMT "Unable to allocate "
"interrupt %d!\n", ioc->name,
@@ -1773,9 +1760,9 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
* chips (mpt_adapter_disable,
* mpt_diag_reset)
*/
- ioc->cached_fw = NULL;
ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n",
ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw));
+ ioc->alt_ioc->cached_fw = NULL;
}
} else {
printk(KERN_WARNING MYNAM ": firmware upload failure!\n");
@@ -1896,7 +1883,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag)
/* FIXME? Examine results here? */
}
-out:
+ out:
if ((ret != 0) && irq_allocated) {
free_irq(ioc->pci_irq, ioc);
if (mpt_msi_enable)
@@ -2681,6 +2668,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag)
dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n",
ioc->name, count));
+ ioc->aen_event_read_flag=0;
return r;
}
@@ -2748,6 +2736,8 @@ mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size)
if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) {
ioc->cached_fw = ioc->alt_ioc->cached_fw; /* use alt_ioc's memory */
ioc->cached_fw_dma = ioc->alt_ioc->cached_fw_dma;
+ ioc->alloc_total += size;
+ ioc->alt_ioc->alloc_total -= size;
} else {
if ( (ioc->cached_fw = pci_alloc_consistent(ioc->pcidev, size, &ioc->cached_fw_dma) ) )
ioc->alloc_total += size;
@@ -3177,6 +3167,7 @@ KickStart(MPT_ADAPTER *ioc, int force, int sleepFlag)
static int
mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
{
+ MPT_ADAPTER *iocp=NULL;
u32 diag0val;
u32 doorbell;
int hard_reset_done = 0;
@@ -3185,6 +3176,37 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
u32 diag1val = 0;
#endif
+ if (ioc->pcidev->device == MPI_MANUFACTPAGE_DEVID_SAS1078) {
+ drsprintk((MYIOC_s_WARN_FMT "%s: Doorbell=%p; 1078 reset "
+ "address=%p\n", ioc->name, __FUNCTION__,
+ &ioc->chip->Doorbell, &ioc->chip->Reset_1078));
+ CHIPREG_WRITE32(&ioc->chip->Reset_1078, 0x07);
+ if (sleepFlag == CAN_SLEEP)
+ msleep(1);
+ else
+ mdelay(1);
+
+ for (count = 0; count < 60; count ++) {
+ doorbell = CHIPREG_READ32(&ioc->chip->Doorbell);
+ doorbell &= MPI_IOC_STATE_MASK;
+
+ drsprintk((MYIOC_s_INFO_FMT
+ "looking for READY STATE: doorbell=%x"
+ " count=%d\n",
+ ioc->name, doorbell, count));
+ if (doorbell == MPI_IOC_STATE_READY) {
+ return 0;
+ }
+
+ /* wait 1 sec */
+ if (sleepFlag == CAN_SLEEP)
+ msleep(1000);
+ else
+ mdelay(1000);
+ }
+ return -1;
+ }
+
/* Clear any existing interrupts */
CHIPREG_WRITE32(&ioc->chip->IntStatus, 0);
@@ -3281,17 +3303,23 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
/* FIXME? Examine results here? */
}
- if (ioc->cached_fw) {
+ if (ioc->cached_fw)
+ iocp = ioc;
+ else if (ioc->alt_ioc && ioc->alt_ioc->cached_fw)
+ iocp = ioc->alt_ioc;
+ if (iocp) {
/* If the DownloadBoot operation fails, the
* IOC will be left unusable. This is a fatal error
* case. _diag_reset will return < 0
*/
for (count = 0; count < 30; count ++) {
- diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic);
+ diag0val = CHIPREG_READ32(&iocp->chip->Diagnostic);
if (!(diag0val & MPI_DIAG_RESET_ADAPTER)) {
break;
}
+ dprintk((MYIOC_s_INFO_FMT "cached_fw: diag0val=%x count=%d\n",
+ iocp->name, diag0val, count));
/* wait 1 sec */
if (sleepFlag == CAN_SLEEP) {
msleep (1000);
@@ -3300,7 +3328,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag)
}
}
if ((count = mpt_downloadboot(ioc,
- (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) {
+ (MpiFwHeader_t *)iocp->cached_fw, sleepFlag)) < 0) {
printk(KERN_WARNING MYNAM
": firmware downloadboot failure (%d)!\n", count);
}
@@ -3887,18 +3915,18 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag)
if (sleepFlag == CAN_SLEEP) {
while (--cntdn) {
+ msleep (1);
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
break;
- msleep (1);
count++;
}
} else {
while (--cntdn) {
+ mdelay (1);
intstat = CHIPREG_READ32(&ioc->chip->IntStatus);
if (! (intstat & MPI_HIS_IOP_DOORBELL_STATUS))
break;
- mdelay (1);
count++;
}
}
@@ -4863,6 +4891,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
pIoc4 = pci_alloc_consistent(ioc->pcidev, iocpage4sz, &ioc4_dma);
if (!pIoc4)
return;
+ ioc->alloc_total += iocpage4sz;
} else {
ioc4_dma = ioc->spi_data.IocPg4_dma;
iocpage4sz = ioc->spi_data.IocPg4Sz;
@@ -4879,6 +4908,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc)
} else {
pci_free_consistent(ioc->pcidev, iocpage4sz, pIoc4, ioc4_dma);
ioc->spi_data.pIocPg4 = NULL;
+ ioc->alloc_total -= iocpage4sz;
}
}
@@ -5010,19 +5040,18 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp)
EventAck_t *pAck;
if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) {
- printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK "
- "request frame for Event=%x EventContext=%x EventData=%x!\n",
- ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext),
- le32_to_cpu(evnp->Data[0]));
+ dfailprintk((MYIOC_s_WARN_FMT "%s, no msg frames!!\n",
+ ioc->name,__FUNCTION__));
return -1;
}
- memset(pAck, 0, sizeof(*pAck));
- dprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
+ devtverboseprintk((MYIOC_s_INFO_FMT "Sending EventAck\n", ioc->name));
pAck->Function = MPI_FUNCTION_EVENT_ACK;
pAck->ChainOffset = 0;
+ pAck->Reserved[0] = pAck->Reserved[1] = 0;
pAck->MsgFlags = 0;
+ pAck->Reserved1[0] = pAck->Reserved1[1] = pAck->Reserved1[2] = 0;
pAck->Event = evnp->Event;
pAck->EventContext = evnp->EventContext;
@@ -5592,7 +5621,7 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag)
/* The SCSI driver needs to adjust timeouts on all current
* commands prior to the diagnostic reset being issued.
- * Prevents timeouts occuring during a diagnostic reset...very bad.
+ * Prevents timeouts occurring during a diagnostic reset...very bad.
* For all other protocol drivers, this is a no-op.
*/
{
@@ -5684,9 +5713,9 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_EVENT_CHANGE:
if (evData0)
- ds = "Events(ON) Change";
+ ds = "Events ON";
else
- ds = "Events(OFF) Change";
+ ds = "Events OFF";
break;
case MPI_EVENT_INTEGRATED_RAID:
{
@@ -5757,8 +5786,27 @@ EventDescriptionStr(u8 event, u32 evData0, char *evStr)
break;
case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
snprintf(evStr, EVENT_DESCR_STR_SZ,
- "SAS Device Status Change: No Persistancy "
- "Added: id=%d", id);
+ "SAS Device Status Change: No Persistancy: id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Device Reset : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Task Abort : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Abort Task Set : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Clear Task Set : id=%d", id);
+ break;
+ case MPI_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
+ snprintf(evStr, EVENT_DESCR_STR_SZ,
+ "SAS Device Status Change: Internal Query Task : id=%d", id);
break;
default:
snprintf(evStr, EVENT_DESCR_STR_SZ,
@@ -6014,7 +6062,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply
* @ioc: Pointer to MPT_ADAPTER structure
* @log_info: U32 LogInfo reply word from the IOC
*
- * Refer to lsi/fc_log.h.
+ * Refer to lsi/mpi_log_fc.h.
*/
static void
mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info)
@@ -6111,8 +6159,10 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
"Invalid SAS Address", /* 01h */
NULL, /* 02h */
"Invalid Page", /* 03h */
- NULL, /* 04h */
- "Task Terminated" /* 05h */
+ "Diag Message Error", /* 04h */
+ "Task Terminated", /* 05h */
+ "Enclosure Management", /* 06h */
+ "Target Mode" /* 07h */
};
static char *pl_code_str[] = {
NULL, /* 00h */
@@ -6138,7 +6188,7 @@ mpt_spi_log_info(MPT_ADAPTER *ioc, u32 log_info)
"IO Executed", /* 14h */
"Persistant Reservation Out Not Affiliation Owner", /* 15h */
"Open Transmit DMA Abort", /* 16h */
- NULL, /* 17h */
+ "IO Device Missing Delay Retry", /* 17h */
NULL, /* 18h */
NULL, /* 19h */
NULL, /* 1Ah */
@@ -6218,7 +6268,7 @@ static void
mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
{
u32 status = ioc_status & MPI_IOCSTATUS_MASK;
- char *desc = "";
+ char *desc = NULL;
switch (status) {
case MPI_IOCSTATUS_INVALID_FUNCTION: /* 0x0001 */
@@ -6328,7 +6378,7 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf)
desc = "Others";
break;
}
- if (desc != "")
+ if (desc != NULL)
printk(MYIOC_s_INFO_FMT "IOCStatus(0x%04x): %s\n", ioc->name, status, desc);
}
@@ -6366,7 +6416,6 @@ EXPORT_SYMBOL(mpt_alloc_fw_memory);
EXPORT_SYMBOL(mpt_free_fw_memory);
EXPORT_SYMBOL(mptbase_sas_persist_operation);
-
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* fusion_init - Fusion MPT base driver initialization routine.
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h
index 4720f9ae86a..c537d71c18e 100644
--- a/drivers/message/fusion/mptbase.h
+++ b/drivers/message/fusion/mptbase.h
@@ -49,7 +49,6 @@
#define MPTBASE_H_INCLUDED
/*{-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -76,8 +75,8 @@
#define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR
#endif
-#define MPT_LINUX_VERSION_COMMON "3.03.10"
-#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.10"
+#define MPT_LINUX_VERSION_COMMON "3.04.01"
+#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.04.01"
#define WHAT_MAGIC_STRING "@" "(" "#" ")"
#define show_mptmod_ver(s,ver) \
@@ -308,7 +307,8 @@ typedef struct _SYSIF_REGS
u32 HostIndex; /* 50 Host Index register */
u32 Reserved4[15]; /* 54-8F */
u32 Fubar; /* 90 For Fubar usage */
- u32 Reserved5[27]; /* 94-FF */
+ u32 Reserved5[1050];/* 94-10F8 */
+ u32 Reset_1078; /* 10FC Reset 1078 */
} SYSIF_REGS;
/*
@@ -342,6 +342,7 @@ typedef struct _VirtTarget {
u8 negoFlags; /* bit field, see above */
u8 raidVolume; /* set, if RAID Volume */
u8 type; /* byte 0 of Inquiry data */
+ u8 deleted; /* target in process of being removed */
u32 num_luns;
u32 luns[8]; /* Max LUNs is 256 */
} VirtTarget;
@@ -362,6 +363,7 @@ typedef struct _VirtDevice {
#define MPT_TARGET_FLAGS_VALID_56 0x10
#define MPT_TARGET_FLAGS_SAF_TE_ISSUED 0x20
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x40
+#define MPT_TARGET_FLAGS_LED_ON 0x80
/*
* /proc/mpt interface
@@ -630,15 +632,14 @@ typedef struct _MPT_ADAPTER
struct mutex sas_discovery_mutex;
u8 sas_discovery_runtime;
u8 sas_discovery_ignore_events;
+ u16 handle;
int sas_index; /* index refrencing */
MPT_SAS_MGMT sas_mgmt;
- int num_ports;
- struct work_struct mptscsih_persistTask;
+ struct work_struct sas_persist_task;
struct work_struct fc_setup_reset_work;
struct list_head fc_rports;
spinlock_t fc_rescan_work_lock;
- int fc_rescan_work_count;
struct work_struct fc_rescan_work;
char fc_rescan_work_q_name[KOBJ_NAME_LEN];
struct workqueue_struct *fc_rescan_work_q;
@@ -893,6 +894,13 @@ typedef struct _mpt_sge {
#define DBG_DUMP_REQUEST_FRAME_HDR(mfp)
#endif
+// debug sas wide ports
+#ifdef MPT_DEBUG_SAS_WIDE
+#define dsaswideprintk(x) printk x
+#else
+#define dsaswideprintk(x)
+#endif
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
@@ -972,7 +980,7 @@ typedef struct _MPT_SCSI_HOST {
wait_queue_head_t scandv_waitq;
int scandv_wait_done;
long last_queue_full;
- u8 mpt_pq_filter;
+ u16 tm_iocstatus;
} MPT_SCSI_HOST;
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index b4967bb8a7d..30975ccd994 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -2332,7 +2332,7 @@ done_free_mem:
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Prototype Routine for the HP HOST INFO command.
+/* Prototype Routine for the HOST INFO command.
*
* Outputs: None.
* Return: 0 if successful
@@ -2568,7 +2568,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size)
}
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/* Prototype Routine for the HP TARGET INFO command.
+/* Prototype Routine for the TARGET INFO command.
*
* Outputs: None.
* Return: 0 if successful
diff --git a/drivers/message/fusion/mptctl.h b/drivers/message/fusion/mptctl.h
index a2f8a97992e..043941882c6 100644
--- a/drivers/message/fusion/mptctl.h
+++ b/drivers/message/fusion/mptctl.h
@@ -354,9 +354,6 @@ struct mpt_ioctl_command32 {
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
-/*
- * HP Specific IOCTL Defines and Structures
- */
#define CPQFCTS_IOC_MAGIC 'Z'
#define HP_IOC_MAGIC 'Z'
@@ -364,8 +361,6 @@ struct mpt_ioctl_command32 {
#define HP_GETHOSTINFO1 _IOR(HP_IOC_MAGIC, 20, hp_host_info_rev0_t)
#define HP_GETTARGETINFO _IOR(HP_IOC_MAGIC, 21, hp_target_info_t)
-/* All HP IOCTLs must include this header
- */
typedef struct _hp_header {
unsigned int iocnum;
unsigned int host;
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index 74714e5bcf0..e57bb035a02 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -77,10 +77,6 @@ MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
/* Command line args */
-static int mpt_pq_filter = 0;
-module_param(mpt_pq_filter, int, 0);
-MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
-
#define MPTFC_DEV_LOSS_TMO (60)
static int mptfc_dev_loss_tmo = MPTFC_DEV_LOSS_TMO; /* reasonable default */
module_param(mptfc_dev_loss_tmo, int, 0);
@@ -132,21 +128,21 @@ static struct scsi_host_template mptfc_driver_template = {
*/
static struct pci_device_id mptfc_pci_table[] = {
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC909,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC909,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC919X,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC919X,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC929X,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC929X,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC939X,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC939X,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949X,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949X,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FC949ES,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVICEID_FC949E,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
@@ -166,7 +162,13 @@ static struct fc_function_template mptfc_transport_functions = {
.show_starget_port_id = 1,
.set_rport_dev_loss_tmo = mptfc_set_rport_loss_tmo,
.show_rport_dev_loss_tmo = 1,
-
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+ .show_host_speed = 1,
+ .show_host_fabric_name = 1,
+ .show_host_port_type = 1,
+ .show_host_port_state = 1,
+ .show_host_symbolic_name = 1,
};
static void
@@ -305,10 +307,8 @@ mptfc_GetFcDevPage0(MPT_ADAPTER *ioc, int ioc_port,
}
out:
- if (pp0_array)
- kfree(pp0_array);
- if (p0_array)
- kfree(p0_array);
+ kfree(pp0_array);
+ kfree(p0_array);
return rc;
}
@@ -515,8 +515,7 @@ mptfc_slave_alloc(struct scsi_device *sdev)
if (vtarget->num_luns == 0) {
vtarget->ioc_id = hd->ioc->id;
- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES |
- MPT_TARGET_FLAGS_VALID_INQUIRY;
+ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
hd->Targets[sdev->id] = vtarget;
}
@@ -676,7 +675,10 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum)
* if still doing discovery,
* hang loose a while until finished
*/
- if (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) {
+ if ((pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_UNKNOWN) ||
+ (pp0dest->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE &&
+ (pp0dest->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_TYPE_MASK)
+ == MPI_FCPORTPAGE0_FLAGS_ATTACH_NO_INIT)) {
if (count-- > 0) {
msleep(100);
goto try_again;
@@ -843,33 +845,95 @@ mptfc_SetFcPortPage1_defaults(MPT_ADAPTER *ioc)
static void
mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum)
{
- unsigned class = 0, cos = 0;
+ unsigned class = 0;
+ unsigned cos = 0;
+ unsigned speed;
+ unsigned port_type;
+ unsigned port_state;
+ FCPortPage0_t *pp0;
+ struct Scsi_Host *sh;
+ char *sn;
/* don't know what to do as only one scsi (fc) host was allocated */
if (portnum != 0)
return;
- class = ioc->fc_port_page0[portnum].SupportedServiceClass;
+ pp0 = &ioc->fc_port_page0[portnum];
+ sh = ioc->sh;
+
+ sn = fc_host_symbolic_name(sh);
+ snprintf(sn, FC_SYMBOLIC_NAME_SIZE, "%s %s%08xh",
+ ioc->prod_name,
+ MPT_FW_REV_MAGIC_ID_STRING,
+ ioc->facts.FWVersion.Word);
+
+ fc_host_tgtid_bind_type(sh) = FC_TGTID_BIND_BY_WWPN;
+
+ fc_host_maxframe_size(sh) = pp0->MaxFrameSize;
+
+ fc_host_node_name(sh) =
+ (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
+
+ fc_host_port_name(sh) =
+ (u64)pp0->WWPN.High << 32 | (u64)pp0->WWPN.Low;
+
+ fc_host_port_id(sh) = pp0->PortIdentifier;
+
+ class = pp0->SupportedServiceClass;
if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_1)
cos |= FC_COS_CLASS1;
if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_2)
cos |= FC_COS_CLASS2;
if (class & MPI_FCPORTPAGE0_SUPPORT_CLASS_3)
cos |= FC_COS_CLASS3;
+ fc_host_supported_classes(sh) = cos;
+
+ if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT)
+ speed = FC_PORTSPEED_1GBIT;
+ else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT)
+ speed = FC_PORTSPEED_2GBIT;
+ else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT)
+ speed = FC_PORTSPEED_4GBIT;
+ else if (pp0->CurrentSpeed == MPI_FCPORTPAGE0_CURRENT_SPEED_10GBIT)
+ speed = FC_PORTSPEED_10GBIT;
+ else
+ speed = FC_PORTSPEED_UNKNOWN;
+ fc_host_speed(sh) = speed;
+
+ speed = 0;
+ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_1GBIT_SPEED)
+ speed |= FC_PORTSPEED_1GBIT;
+ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_2GBIT_SPEED)
+ speed |= FC_PORTSPEED_2GBIT;
+ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_4GBIT_SPEED)
+ speed |= FC_PORTSPEED_4GBIT;
+ if (pp0->SupportedSpeeds & MPI_FCPORTPAGE0_SUPPORT_10GBIT_SPEED)
+ speed |= FC_PORTSPEED_10GBIT;
+ fc_host_supported_speeds(sh) = speed;
+
+ port_state = FC_PORTSTATE_UNKNOWN;
+ if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_ONLINE)
+ port_state = FC_PORTSTATE_ONLINE;
+ else if (pp0->PortState == MPI_FCPORTPAGE0_PORTSTATE_OFFLINE)
+ port_state = FC_PORTSTATE_LINKDOWN;
+ fc_host_port_state(sh) = port_state;
+
+ port_type = FC_PORTTYPE_UNKNOWN;
+ if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_POINT_TO_POINT)
+ port_type = FC_PORTTYPE_PTP;
+ else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PRIVATE_LOOP)
+ port_type = FC_PORTTYPE_LPORT;
+ else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_PUBLIC_LOOP)
+ port_type = FC_PORTTYPE_NLPORT;
+ else if (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_ATTACH_FABRIC_DIRECT)
+ port_type = FC_PORTTYPE_NPORT;
+ fc_host_port_type(sh) = port_type;
+
+ fc_host_fabric_name(sh) =
+ (pp0->Flags & MPI_FCPORTPAGE0_FLAGS_FABRIC_WWN_VALID) ?
+ (u64) pp0->FabricWWNN.High << 32 | (u64) pp0->FabricWWPN.Low :
+ (u64)pp0->WWNN.High << 32 | (u64)pp0->WWNN.Low;
- fc_host_node_name(ioc->sh) =
- (u64)ioc->fc_port_page0[portnum].WWNN.High << 32
- | (u64)ioc->fc_port_page0[portnum].WWNN.Low;
-
- fc_host_port_name(ioc->sh) =
- (u64)ioc->fc_port_page0[portnum].WWPN.High << 32
- | (u64)ioc->fc_port_page0[portnum].WWPN.Low;
-
- fc_host_port_id(ioc->sh) = ioc->fc_port_page0[portnum].PortIdentifier;
-
- fc_host_supported_classes(ioc->sh) = cos;
-
- fc_host_tgtid_bind_type(ioc->sh) = FC_TGTID_BIND_BY_WWPN;
}
static void
@@ -902,59 +966,45 @@ mptfc_rescan_devices(void *arg)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
int ii;
- int work_to_do;
u64 pn;
- unsigned long flags;
struct mptfc_rport_info *ri;
- do {
- /* start by tagging all ports as missing */
- list_for_each_entry(ri, &ioc->fc_rports, list) {
- if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
- ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
- }
+ /* start by tagging all ports as missing */
+ list_for_each_entry(ri, &ioc->fc_rports, list) {
+ if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) {
+ ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING;
}
+ }
- /*
- * now rescan devices known to adapter,
- * will reregister existing rports
- */
- for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
- (void) mptfc_GetFcPortPage0(ioc, ii);
- mptfc_init_host_attr(ioc,ii); /* refresh */
- mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev);
- }
+ /*
+ * now rescan devices known to adapter,
+ * will reregister existing rports
+ */
+ for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) {
+ (void) mptfc_GetFcPortPage0(ioc, ii);
+ mptfc_init_host_attr(ioc, ii); /* refresh */
+ mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev);
+ }
- /* delete devices still missing */
- list_for_each_entry(ri, &ioc->fc_rports, list) {
- /* if newly missing, delete it */
- if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
+ /* delete devices still missing */
+ list_for_each_entry(ri, &ioc->fc_rports, list) {
+ /* if newly missing, delete it */
+ if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) {
- ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
- MPT_RPORT_INFO_FLAGS_MISSING);
- fc_remote_port_delete(ri->rport); /* won't sleep */
- ri->rport = NULL;
+ ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED|
+ MPT_RPORT_INFO_FLAGS_MISSING);
+ fc_remote_port_delete(ri->rport); /* won't sleep */
+ ri->rport = NULL;
- pn = (u64)ri->pg0.WWPN.High << 32 |
- (u64)ri->pg0.WWPN.Low;
- dfcprintk ((MYIOC_s_INFO_FMT
- "mptfc_rescan.%d: %llx deleted\n",
- ioc->name,
- ioc->sh->host_no,
- (unsigned long long)pn));
- }
+ pn = (u64)ri->pg0.WWPN.High << 32 |
+ (u64)ri->pg0.WWPN.Low;
+ dfcprintk ((MYIOC_s_INFO_FMT
+ "mptfc_rescan.%d: %llx deleted\n",
+ ioc->name,
+ ioc->sh->host_no,
+ (unsigned long long)pn));
}
-
- /*
- * allow multiple passes as target state
- * might have changed during scan
- */
- spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
- if (ioc->fc_rescan_work_count > 2) /* only need one more */
- ioc->fc_rescan_work_count = 2;
- work_to_do = --ioc->fc_rescan_work_count;
- spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
- } while (work_to_do);
+ }
}
static int
@@ -1131,13 +1181,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
- hd->mpt_pq_filter = mpt_pq_filter;
-
- ddvprintk((MYIOC_s_INFO_FMT
- "mpt_pq_filter %x\n",
- ioc->name,
- mpt_pq_filter));
-
init_waitqueue_head(&hd->scandv_waitq);
hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
@@ -1173,7 +1216,6 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
* by doing it via the workqueue, some locking is eliminated
*/
- ioc->fc_rescan_work_count = 1;
queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work);
flush_workqueue(ioc->fc_rescan_work_q);
@@ -1216,10 +1258,8 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply)
case MPI_EVENT_RESCAN:
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
if (ioc->fc_rescan_work_q) {
- if (ioc->fc_rescan_work_count++ == 0) {
- queue_work(ioc->fc_rescan_work_q,
- &ioc->fc_rescan_work);
- }
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_rescan_work);
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
break;
@@ -1262,10 +1302,8 @@ mptfc_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
mptfc_SetFcPortPage1_defaults(ioc);
spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags);
if (ioc->fc_rescan_work_q) {
- if (ioc->fc_rescan_work_count++ == 0) {
- queue_work(ioc->fc_rescan_work_q,
- &ioc->fc_rescan_work);
- }
+ queue_work(ioc->fc_rescan_work_q,
+ &ioc->fc_rescan_work);
}
spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags);
}
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index af6ec553ff7..b752a479f6d 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -50,11 +50,14 @@
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/workqueue.h>
+#include <linux/delay.h> /* for mdelay */
+#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport_sas.h>
+#include <scsi/scsi_dbg.h>
#include "mptbase.h"
#include "mptscsih.h"
@@ -64,20 +67,19 @@
#define my_VERSION MPT_LINUX_VERSION_COMMON
#define MYNAM "mptsas"
+/*
+ * Reserved channel for integrated raid
+ */
+#define MPTSAS_RAID_CHANNEL 1
+
MODULE_AUTHOR(MODULEAUTHOR);
MODULE_DESCRIPTION(my_NAME);
MODULE_LICENSE("GPL");
-static int mpt_pq_filter;
-module_param(mpt_pq_filter, int, 0);
-MODULE_PARM_DESC(mpt_pq_filter,
- "Enable peripheral qualifier filter: enable=1 "
- "(default=0)");
-
static int mpt_pt_clear;
module_param(mpt_pt_clear, int, 0);
MODULE_PARM_DESC(mpt_pt_clear,
- "Clear persistency table: enable=1 "
+ " Clear persistency table: enable=1 "
"(default=MPTSCSIH_PT_CLEAR=0)");
static int mptsasDoneCtx = -1;
@@ -137,23 +139,36 @@ struct mptsas_devinfo {
u32 device_info; /* bitfield detailed info about this device */
};
+/*
+ * Specific details on ports, wide/narrow
+ */
+struct mptsas_portinfo_details{
+ u16 num_phys; /* number of phys belong to this port */
+ u64 phy_bitmask; /* TODO, extend support for 255 phys */
+ struct sas_rphy *rphy; /* transport layer rphy object */
+ struct sas_port *port; /* transport layer port object */
+ struct scsi_target *starget;
+ struct mptsas_portinfo *port_info;
+};
+
struct mptsas_phyinfo {
u8 phy_id; /* phy index */
- u8 port_id; /* port number this phy is part of */
+ u8 port_id; /* firmware port identifier */
u8 negotiated_link_rate; /* nego'd link rate for this phy */
u8 hw_link_rate; /* hardware max/min phys link rate */
u8 programmed_link_rate; /* programmed max/min phy link rate */
+ u8 sas_port_add_phy; /* flag to request sas_port_add_phy*/
struct mptsas_devinfo identify; /* point to phy device info */
struct mptsas_devinfo attached; /* point to attached device info */
- struct sas_phy *phy;
- struct sas_rphy *rphy;
- struct scsi_target *starget;
+ struct sas_phy *phy; /* transport layer phy object */
+ struct mptsas_portinfo *portinfo;
+ struct mptsas_portinfo_details * port_details;
};
struct mptsas_portinfo {
struct list_head list;
u16 handle; /* unique id to address this */
- u8 num_phys; /* number of phys */
+ u16 num_phys; /* number of phys */
struct mptsas_phyinfo *phy_info;
};
@@ -169,7 +184,7 @@ struct mptsas_enclosure {
u8 sep_channel; /* SEP channel logical channel id */
};
-#ifdef SASDEBUG
+#ifdef MPT_DEBUG_SAS
static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
{
printk("---- IO UNIT PAGE 0 ------------\n");
@@ -305,7 +320,7 @@ mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
static inline int
mptsas_is_end_device(struct mptsas_devinfo * attached)
{
- if ((attached->handle) &&
+ if ((attached->sas_address) &&
(attached->device_info &
MPI_SAS_DEVICE_INFO_END_DEVICE) &&
((attached->device_info &
@@ -319,6 +334,247 @@ mptsas_is_end_device(struct mptsas_devinfo * attached)
return 0;
}
+/* no mutex */
+static void
+mptsas_port_delete(struct mptsas_portinfo_details * port_details)
+{
+ struct mptsas_portinfo *port_info;
+ struct mptsas_phyinfo *phy_info;
+ u8 i;
+
+ if (!port_details)
+ return;
+
+ port_info = port_details->port_info;
+ phy_info = port_info->phy_info;
+
+ dsaswideprintk((KERN_DEBUG "%s: [%p]: num_phys=%02d "
+ "bitmask=0x%016llX\n",
+ __FUNCTION__, port_details, port_details->num_phys,
+ port_details->phy_bitmask));
+
+ for (i = 0; i < port_info->num_phys; i++, phy_info++) {
+ if(phy_info->port_details != port_details)
+ continue;
+ memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+ phy_info->port_details = NULL;
+ }
+ kfree(port_details);
+}
+
+static inline struct sas_rphy *
+mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
+{
+ if (phy_info->port_details)
+ return phy_info->port_details->rphy;
+ else
+ return NULL;
+}
+
+static inline void
+mptsas_set_rphy(struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
+{
+ if (phy_info->port_details) {
+ phy_info->port_details->rphy = rphy;
+ dsaswideprintk((KERN_DEBUG "sas_rphy_add: rphy=%p\n", rphy));
+ }
+
+#ifdef MPT_DEBUG_SAS_WIDE
+ if (rphy) {
+ dev_printk(KERN_DEBUG, &rphy->dev, "add:");
+ printk("rphy=%p release=%p\n",
+ rphy, rphy->dev.release);
+ }
+#endif
+}
+
+static inline struct sas_port *
+mptsas_get_port(struct mptsas_phyinfo *phy_info)
+{
+ if (phy_info->port_details)
+ return phy_info->port_details->port;
+ else
+ return NULL;
+}
+
+static inline void
+mptsas_set_port(struct mptsas_phyinfo *phy_info, struct sas_port *port)
+{
+ if (phy_info->port_details)
+ phy_info->port_details->port = port;
+
+#ifdef MPT_DEBUG_SAS_WIDE
+ if (port) {
+ dev_printk(KERN_DEBUG, &port->dev, "add: ");
+ printk("port=%p release=%p\n",
+ port, port->dev.release);
+ }
+#endif
+}
+
+static inline struct scsi_target *
+mptsas_get_starget(struct mptsas_phyinfo *phy_info)
+{
+ if (phy_info->port_details)
+ return phy_info->port_details->starget;
+ else
+ return NULL;
+}
+
+static inline void
+mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
+starget)
+{
+ if (phy_info->port_details)
+ phy_info->port_details->starget = starget;
+}
+
+
+/*
+ * mptsas_setup_wide_ports
+ *
+ * Updates for new and existing narrow/wide port configuration
+ * in the sas_topology
+ */
+static void
+mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
+{
+ struct mptsas_portinfo_details * port_details;
+ struct mptsas_phyinfo *phy_info, *phy_info_cmp;
+ u64 sas_address;
+ int i, j;
+
+ mutex_lock(&ioc->sas_topology_mutex);
+
+ phy_info = port_info->phy_info;
+ for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
+ if (phy_info->attached.handle)
+ continue;
+ port_details = phy_info->port_details;
+ if (!port_details)
+ continue;
+ if (port_details->num_phys < 2)
+ continue;
+ /*
+ * Removing a phy from a port, letting the last
+ * phy be removed by firmware events.
+ */
+ dsaswideprintk((KERN_DEBUG
+ "%s: [%p]: deleting phy = %d\n",
+ __FUNCTION__, port_details, i));
+ port_details->num_phys--;
+ port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
+ memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
+ sas_port_delete_phy(port_details->port, phy_info->phy);
+ phy_info->port_details = NULL;
+ }
+
+ /*
+ * Populate and refresh the tree
+ */
+ phy_info = port_info->phy_info;
+ for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
+ sas_address = phy_info->attached.sas_address;
+ dsaswideprintk((KERN_DEBUG "phy_id=%d sas_address=0x%018llX\n",
+ i, sas_address));
+ if (!sas_address)
+ continue;
+ port_details = phy_info->port_details;
+ /*
+ * Forming a port
+ */
+ if (!port_details) {
+ port_details = kzalloc(sizeof(*port_details),
+ GFP_KERNEL);
+ if (!port_details)
+ goto out;
+ port_details->num_phys = 1;
+ port_details->port_info = port_info;
+ if (phy_info->phy_id < 64 )
+ port_details->phy_bitmask |=
+ (1 << phy_info->phy_id);
+ phy_info->sas_port_add_phy=1;
+ dsaswideprintk((KERN_DEBUG "\t\tForming port\n\t\t"
+ "phy_id=%d sas_address=0x%018llX\n",
+ i, sas_address));
+ phy_info->port_details = port_details;
+ }
+
+ if (i == port_info->num_phys - 1)
+ continue;
+ phy_info_cmp = &port_info->phy_info[i + 1];
+ for (j = i + 1 ; j < port_info->num_phys ; j++,
+ phy_info_cmp++) {
+ if (!phy_info_cmp->attached.sas_address)
+ continue;
+ if (sas_address != phy_info_cmp->attached.sas_address)
+ continue;
+ if (phy_info_cmp->port_details == port_details )
+ continue;
+ dsaswideprintk((KERN_DEBUG
+ "\t\tphy_id=%d sas_address=0x%018llX\n",
+ j, phy_info_cmp->attached.sas_address));
+ if (phy_info_cmp->port_details) {
+ port_details->rphy =
+ mptsas_get_rphy(phy_info_cmp);
+ port_details->port =
+ mptsas_get_port(phy_info_cmp);
+ port_details->starget =
+ mptsas_get_starget(phy_info_cmp);
+ port_details->num_phys =
+ phy_info_cmp->port_details->num_phys;
+ if (!phy_info_cmp->port_details->num_phys)
+ kfree(phy_info_cmp->port_details);
+ } else
+ phy_info_cmp->sas_port_add_phy=1;
+ /*
+ * Adding a phy to a port
+ */
+ phy_info_cmp->port_details = port_details;
+ if (phy_info_cmp->phy_id < 64 )
+ port_details->phy_bitmask |=
+ (1 << phy_info_cmp->phy_id);
+ port_details->num_phys++;
+ }
+ }
+
+ out:
+
+#ifdef MPT_DEBUG_SAS_WIDE
+ for (i = 0; i < port_info->num_phys; i++) {
+ port_details = port_info->phy_info[i].port_details;
+ if (!port_details)
+ continue;
+ dsaswideprintk((KERN_DEBUG
+ "%s: [%p]: phy_id=%02d num_phys=%02d "
+ "bitmask=0x%016llX\n",
+ __FUNCTION__,
+ port_details, i, port_details->num_phys,
+ port_details->phy_bitmask));
+ dsaswideprintk((KERN_DEBUG"\t\tport = %p rphy=%p\n",
+ port_details->port, port_details->rphy));
+ }
+ dsaswideprintk((KERN_DEBUG"\n"));
+#endif
+ mutex_unlock(&ioc->sas_topology_mutex);
+}
+
+static void
+mptsas_target_reset(MPT_ADAPTER *ioc, VirtTarget * vtarget)
+{
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata;
+
+ if (mptscsih_TMHandler(hd,
+ MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
+ vtarget->bus_id, vtarget->target_id, 0, 0, 5) < 0) {
+ hd->tmPending = 0;
+ hd->tmState = TM_STATE_NONE;
+ printk(MYIOC_s_WARN_FMT
+ "Error processing TaskMgmt id=%d TARGET_RESET\n",
+ ioc->name, vtarget->target_id);
+ }
+}
+
static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
u32 form, u32 form_specific)
@@ -387,24 +643,112 @@ mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
static int
mptsas_slave_configure(struct scsi_device *sdev)
{
- struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
- /*
- * RAID volumes placed beyond the last expected port.
- * Ignore sending sas mode pages in that case..
- */
- if (sdev->channel < hd->ioc->num_ports)
- sas_read_port_mode_page(sdev);
+ if (sdev->channel == MPTSAS_RAID_CHANNEL)
+ goto out;
+ sas_read_port_mode_page(sdev);
+
+ out:
return mptscsih_slave_configure(sdev);
}
-/*
- * This is pretty ugly. We will be able to seriously clean it up
- * once the DV code in mptscsih goes away and we can properly
- * implement ->target_alloc.
- */
+static int
+mptsas_target_alloc(struct scsi_target *starget)
+{
+ struct Scsi_Host *host = dev_to_shost(&starget->dev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ VirtTarget *vtarget;
+ u32 target_id;
+ u32 channel;
+ struct sas_rphy *rphy;
+ struct mptsas_portinfo *p;
+ int i;
+
+ vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
+ if (!vtarget)
+ return -ENOMEM;
+
+ vtarget->starget = starget;
+ vtarget->ioc_id = hd->ioc->id;
+ vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
+
+ target_id = starget->id;
+ channel = 0;
+
+ hd->Targets[target_id] = vtarget;
+
+ if (starget->channel == MPTSAS_RAID_CHANNEL)
+ goto out;
+
+ rphy = dev_to_rphy(starget->dev.parent);
+ mutex_lock(&hd->ioc->sas_topology_mutex);
+ list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ for (i = 0; i < p->num_phys; i++) {
+ if (p->phy_info[i].attached.sas_address !=
+ rphy->identify.sas_address)
+ continue;
+ target_id = p->phy_info[i].attached.id;
+ channel = p->phy_info[i].attached.channel;
+ mptsas_set_starget(&p->phy_info[i], starget);
+
+ /*
+ * Exposing hidden raid components
+ */
+ if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
+ target_id = mptscsih_raid_id_to_num(hd,
+ target_id);
+ vtarget->tflags |=
+ MPT_TARGET_FLAGS_RAID_COMPONENT;
+ }
+ mutex_unlock(&hd->ioc->sas_topology_mutex);
+ goto out;
+ }
+ }
+ mutex_unlock(&hd->ioc->sas_topology_mutex);
+
+ kfree(vtarget);
+ return -ENXIO;
+
+ out:
+ vtarget->target_id = target_id;
+ vtarget->bus_id = channel;
+ starget->hostdata = vtarget;
+ return 0;
+}
+
+static void
+mptsas_target_destroy(struct scsi_target *starget)
+{
+ struct Scsi_Host *host = dev_to_shost(&starget->dev);
+ MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
+ struct sas_rphy *rphy;
+ struct mptsas_portinfo *p;
+ int i;
+
+ if (!starget->hostdata)
+ return;
+
+ if (starget->channel == MPTSAS_RAID_CHANNEL)
+ goto out;
+
+ rphy = dev_to_rphy(starget->dev.parent);
+ list_for_each_entry(p, &hd->ioc->sas_topology, list) {
+ for (i = 0; i < p->num_phys; i++) {
+ if (p->phy_info[i].attached.sas_address !=
+ rphy->identify.sas_address)
+ continue;
+ mptsas_set_starget(&p->phy_info[i], NULL);
+ goto out;
+ }
+ }
+
+ out:
+ kfree(starget->hostdata);
+ starget->hostdata = NULL;
+}
+
+
static int
mptsas_slave_alloc(struct scsi_device *sdev)
{
@@ -412,61 +756,38 @@ mptsas_slave_alloc(struct scsi_device *sdev)
MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
struct sas_rphy *rphy;
struct mptsas_portinfo *p;
- VirtTarget *vtarget;
VirtDevice *vdev;
struct scsi_target *starget;
- u32 target_id;
- int i;
+ int i;
vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
if (!vdev) {
- printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+ printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
hd->ioc->name, sizeof(VirtDevice));
return -ENOMEM;
}
- sdev->hostdata = vdev;
starget = scsi_target(sdev);
- vtarget = starget->hostdata;
- vtarget->ioc_id = hd->ioc->id;
- vdev->vtarget = vtarget;
- if (vtarget->num_luns == 0) {
- vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY;
- hd->Targets[sdev->id] = vtarget;
- }
+ vdev->vtarget = starget->hostdata;
- /*
- RAID volumes placed beyond the last expected port.
- */
- if (sdev->channel == hd->ioc->num_ports) {
- target_id = sdev->id;
- vtarget->bus_id = 0;
- vdev->lun = 0;
+ if (sdev->channel == MPTSAS_RAID_CHANNEL)
goto out;
- }
rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
mutex_lock(&hd->ioc->sas_topology_mutex);
list_for_each_entry(p, &hd->ioc->sas_topology, list) {
for (i = 0; i < p->num_phys; i++) {
- if (p->phy_info[i].attached.sas_address ==
- rphy->identify.sas_address) {
- target_id = p->phy_info[i].attached.id;
- vtarget->bus_id = p->phy_info[i].attached.channel;
- vdev->lun = sdev->lun;
- p->phy_info[i].starget = sdev->sdev_target;
- /*
- * Exposing hidden disk (RAID)
- */
- if (mptscsih_is_phys_disk(hd->ioc, target_id)) {
- target_id = mptscsih_raid_id_to_num(hd,
- target_id);
- vdev->vtarget->tflags |=
- MPT_TARGET_FLAGS_RAID_COMPONENT;
- sdev->no_uld_attach = 1;
- }
- mutex_unlock(&hd->ioc->sas_topology_mutex);
- goto out;
- }
+ if (p->phy_info[i].attached.sas_address !=
+ rphy->identify.sas_address)
+ continue;
+ vdev->lun = sdev->lun;
+ /*
+ * Exposing hidden raid components
+ */
+ if (mptscsih_is_phys_disk(hd->ioc,
+ p->phy_info[i].attached.id))
+ sdev->no_uld_attach = 1;
+ mutex_unlock(&hd->ioc->sas_topology_mutex);
+ goto out;
}
}
mutex_unlock(&hd->ioc->sas_topology_mutex);
@@ -475,57 +796,39 @@ mptsas_slave_alloc(struct scsi_device *sdev)
return -ENXIO;
out:
- vtarget->target_id = target_id;
- vtarget->num_luns++;
+ vdev->vtarget->num_luns++;
+ sdev->hostdata = vdev;
return 0;
}
-static void
-mptsas_slave_destroy(struct scsi_device *sdev)
+static int
+mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
{
- struct Scsi_Host *host = sdev->host;
- MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata;
- VirtDevice *vdev;
+ VirtDevice *vdev = SCpnt->device->hostdata;
- /*
- * Issue target reset to flush firmware outstanding commands.
- */
- vdev = sdev->hostdata;
- if (vdev->configured_lun){
- if (mptscsih_TMHandler(hd,
- MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET,
- vdev->vtarget->bus_id,
- vdev->vtarget->target_id,
- 0, 0, 5 /* 5 second timeout */)
- < 0){
-
- /* The TM request failed!
- * Fatal error case.
- */
- printk(MYIOC_s_WARN_FMT
- "Error processing TaskMgmt id=%d TARGET_RESET\n",
- hd->ioc->name,
- vdev->vtarget->target_id);
-
- hd->tmPending = 0;
- hd->tmState = TM_STATE_NONE;
- }
+// scsi_print_command(SCpnt);
+ if (vdev->vtarget->deleted) {
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
}
- mptscsih_slave_destroy(sdev);
+
+ return mptscsih_qcmd(SCpnt,done);
}
+
static struct scsi_host_template mptsas_driver_template = {
.module = THIS_MODULE,
.proc_name = "mptsas",
.proc_info = mptscsih_proc_info,
.name = "MPT SPI Host",
.info = mptscsih_info,
- .queuecommand = mptscsih_qcmd,
- .target_alloc = mptscsih_target_alloc,
+ .queuecommand = mptsas_qcmd,
+ .target_alloc = mptsas_target_alloc,
.slave_alloc = mptsas_slave_alloc,
.slave_configure = mptsas_slave_configure,
- .target_destroy = mptscsih_target_destroy,
- .slave_destroy = mptsas_slave_destroy,
+ .target_destroy = mptsas_target_destroy,
+ .slave_destroy = mptscsih_slave_destroy,
.change_queue_depth = mptscsih_change_queue_depth,
.eh_abort_handler = mptscsih_abort,
.eh_device_reset_handler = mptscsih_dev_reset,
@@ -549,6 +852,10 @@ static int mptsas_get_linkerrors(struct sas_phy *phy)
dma_addr_t dma_handle;
int error;
+ /* FIXME: only have link errors on local phys */
+ if (!scsi_is_sas_phy_local(phy))
+ return -EINVAL;
+
hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
hdr.ExtPageLength = 0;
hdr.PageNumber = 1 /* page number 1*/;
@@ -621,6 +928,10 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
unsigned long timeleft;
int error = -ERESTARTSYS;
+ /* FIXME: fusion doesn't allow non-local phy reset */
+ if (!scsi_is_sas_phy_local(phy))
+ return -EINVAL;
+
/* not implemented for expanders */
if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
return -ENXIO;
@@ -795,7 +1106,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
port_info->num_phys = buffer->NumPhys;
port_info->phy_info = kcalloc(port_info->num_phys,
- sizeof(struct mptsas_phyinfo),GFP_KERNEL);
+ sizeof(*port_info->phy_info),GFP_KERNEL);
if (!port_info->phy_info) {
error = -ENOMEM;
goto out_free_consistent;
@@ -811,6 +1122,7 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
buffer->PhyData[i].Port;
port_info->phy_info[i].negotiated_link_rate =
buffer->PhyData[i].NegotiatedLinkRate;
+ port_info->phy_info[i].portinfo = port_info;
}
out_free_consistent:
@@ -968,7 +1280,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
CONFIGPARMS cfg;
SasExpanderPage0_t *buffer;
dma_addr_t dma_handle;
- int error;
+ int i, error;
hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
hdr.ExtPageLength = 0;
@@ -1013,12 +1325,15 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
port_info->num_phys = buffer->NumPhys;
port_info->handle = le16_to_cpu(buffer->DevHandle);
port_info->phy_info = kcalloc(port_info->num_phys,
- sizeof(struct mptsas_phyinfo),GFP_KERNEL);
+ sizeof(*port_info->phy_info),GFP_KERNEL);
if (!port_info->phy_info) {
error = -ENOMEM;
goto out_free_consistent;
}
+ for (i = 0; i < port_info->num_phys; i++)
+ port_info->phy_info[i].portinfo = port_info;
+
out_free_consistent:
pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
buffer, dma_handle);
@@ -1161,19 +1476,23 @@ static int mptsas_probe_one_phy(struct device *dev,
{
MPT_ADAPTER *ioc;
struct sas_phy *phy;
- int error;
+ struct sas_port *port;
+ int error = 0;
- if (!dev)
- return -ENODEV;
+ if (!dev) {
+ error = -ENODEV;
+ goto out;
+ }
if (!phy_info->phy) {
phy = sas_phy_alloc(dev, index);
- if (!phy)
- return -ENOMEM;
+ if (!phy) {
+ error = -ENOMEM;
+ goto out;
+ }
} else
phy = phy_info->phy;
- phy->port_identifier = phy_info->port_id;
mptsas_parse_device_info(&phy->identify, &phy_info->identify);
/*
@@ -1259,25 +1578,54 @@ static int mptsas_probe_one_phy(struct device *dev,
if (!phy_info->phy) {
- if (local)
- phy->local_attached = 1;
-
error = sas_phy_add(phy);
if (error) {
sas_phy_free(phy);
- return error;
+ goto out;
}
phy_info->phy = phy;
}
- if ((phy_info->attached.handle) &&
- (!phy_info->rphy)) {
+ if (!phy_info->attached.handle ||
+ !phy_info->port_details)
+ goto out;
+
+ port = mptsas_get_port(phy_info);
+ ioc = phy_to_ioc(phy_info->phy);
+
+ if (phy_info->sas_port_add_phy) {
+
+ if (!port) {
+ port = sas_port_alloc_num(dev);
+ if (!port) {
+ error = -ENOMEM;
+ goto out;
+ }
+ error = sas_port_add(port);
+ if (error) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ goto out;
+ }
+ mptsas_set_port(phy_info, port);
+ dsaswideprintk((KERN_DEBUG
+ "sas_port_alloc: port=%p dev=%p port_id=%d\n",
+ port, dev, port->port_identifier));
+ }
+ dsaswideprintk((KERN_DEBUG "sas_port_add_phy: phy_id=%d\n",
+ phy_info->phy_id));
+ sas_port_add_phy(port, phy_info->phy);
+ phy_info->sas_port_add_phy = 0;
+ }
+
+ if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
struct sas_rphy *rphy;
+ struct device *parent;
struct sas_identify identify;
- ioc = phy_to_ioc(phy_info->phy);
-
+ parent = dev->parent->parent;
/*
* Let the hotplug_work thread handle processing
* the adding/removing of devices that occur
@@ -1285,36 +1633,67 @@ static int mptsas_probe_one_phy(struct device *dev,
*/
if (ioc->sas_discovery_runtime &&
mptsas_is_end_device(&phy_info->attached))
- return 0;
+ goto out;
mptsas_parse_device_info(&identify, &phy_info->attached);
+ if (scsi_is_host_device(parent)) {
+ struct mptsas_portinfo *port_info;
+ int i;
+
+ mutex_lock(&ioc->sas_topology_mutex);
+ port_info = mptsas_find_portinfo_by_handle(ioc,
+ ioc->handle);
+ mutex_unlock(&ioc->sas_topology_mutex);
+
+ for (i = 0; i < port_info->num_phys; i++)
+ if (port_info->phy_info[i].identify.sas_address ==
+ identify.sas_address) {
+ sas_port_mark_backlink(port);
+ goto out;
+ }
+
+ } else if (scsi_is_sas_rphy(parent)) {
+ struct sas_rphy *parent_rphy = dev_to_rphy(parent);
+ if (identify.sas_address ==
+ parent_rphy->identify.sas_address) {
+ sas_port_mark_backlink(port);
+ goto out;
+ }
+ }
+
switch (identify.device_type) {
case SAS_END_DEVICE:
- rphy = sas_end_device_alloc(phy);
+ rphy = sas_end_device_alloc(port);
break;
case SAS_EDGE_EXPANDER_DEVICE:
case SAS_FANOUT_EXPANDER_DEVICE:
- rphy = sas_expander_alloc(phy, identify.device_type);
+ rphy = sas_expander_alloc(port, identify.device_type);
break;
default:
rphy = NULL;
break;
}
- if (!rphy)
- return 0; /* non-fatal: an rphy can be added later */
+ if (!rphy) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ goto out;
+ }
rphy->identify = identify;
-
error = sas_rphy_add(rphy);
if (error) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
sas_rphy_free(rphy);
- return error;
+ goto out;
}
-
- phy_info->rphy = rphy;
+ mptsas_set_rphy(phy_info, rphy);
}
- return 0;
+ out:
+ return error;
}
static int
@@ -1333,6 +1712,7 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
goto out_free_port_info;
mutex_lock(&ioc->sas_topology_mutex);
+ ioc->handle = hba->handle;
port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle);
if (!port_info) {
port_info = hba;
@@ -1342,13 +1722,11 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
for (i = 0; i < hba->num_phys; i++)
port_info->phy_info[i].negotiated_link_rate =
hba->phy_info[i].negotiated_link_rate;
- if (hba->phy_info)
- kfree(hba->phy_info);
+ kfree(hba->phy_info);
kfree(hba);
hba = NULL;
}
mutex_unlock(&ioc->sas_topology_mutex);
- ioc->num_ports = port_info->num_phys;
for (i = 0; i < port_info->num_phys; i++) {
mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
@@ -1362,24 +1740,24 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
port_info->phy_info[i].phy_id;
handle = port_info->phy_info[i].identify.handle;
- if (port_info->phy_info[i].attached.handle) {
+ if (port_info->phy_info[i].attached.handle)
mptsas_sas_device_pg0(ioc,
&port_info->phy_info[i].attached,
(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
port_info->phy_info[i].attached.handle);
- }
+ }
+ mptsas_setup_wide_ports(ioc, port_info);
+
+ for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
mptsas_probe_one_phy(&ioc->sh->shost_gendev,
&port_info->phy_info[i], ioc->sas_index, 1);
- ioc->sas_index++;
- }
return 0;
out_free_port_info:
- if (hba)
- kfree(hba);
+ kfree(hba);
out:
return error;
}
@@ -1388,6 +1766,8 @@ static int
mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
{
struct mptsas_portinfo *port_info, *p, *ex;
+ struct device *parent;
+ struct sas_rphy *rphy;
int error = -ENOMEM, i, j;
ex = kzalloc(sizeof(*port_info), GFP_KERNEL);
@@ -1409,16 +1789,13 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
list_add_tail(&port_info->list, &ioc->sas_topology);
} else {
port_info->handle = ex->handle;
- if (ex->phy_info)
- kfree(ex->phy_info);
+ kfree(ex->phy_info);
kfree(ex);
ex = NULL;
}
mutex_unlock(&ioc->sas_topology_mutex);
for (i = 0; i < port_info->num_phys; i++) {
- struct device *parent;
-
mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
(MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle);
@@ -1442,34 +1819,34 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle)
port_info->phy_info[i].attached.phy_id =
port_info->phy_info[i].phy_id;
}
+ }
- /*
- * If we find a parent port handle this expander is
- * attached to another expander, else it hangs of the
- * HBA phys.
- */
- parent = &ioc->sh->shost_gendev;
+ parent = &ioc->sh->shost_gendev;
+ for (i = 0; i < port_info->num_phys; i++) {
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(p, &ioc->sas_topology, list) {
for (j = 0; j < p->num_phys; j++) {
- if (port_info->phy_info[i].identify.handle ==
+ if (port_info->phy_info[i].identify.handle !=
p->phy_info[j].attached.handle)
- parent = &p->phy_info[j].rphy->dev;
+ continue;
+ rphy = mptsas_get_rphy(&p->phy_info[j]);
+ parent = &rphy->dev;
}
}
mutex_unlock(&ioc->sas_topology_mutex);
+ }
+
+ mptsas_setup_wide_ports(ioc, port_info);
+ for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
mptsas_probe_one_phy(parent, &port_info->phy_info[i],
ioc->sas_index, 0);
- ioc->sas_index++;
- }
return 0;
out_free_port_info:
if (ex) {
- if (ex->phy_info)
- kfree(ex->phy_info);
+ kfree(ex->phy_info);
kfree(ex);
}
out:
@@ -1488,7 +1865,12 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
{
struct mptsas_portinfo buffer;
struct mptsas_portinfo *port_info, *n, *parent;
+ struct mptsas_phyinfo *phy_info;
+ struct scsi_target * starget;
+ VirtTarget * vtarget;
+ struct sas_port * port;
int i;
+ u64 expander_sas_address;
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) {
@@ -1503,6 +1885,25 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) {
/*
+ * Issue target reset to all child end devices
+ * then mark them deleted to prevent further
+ * IO going to them.
+ */
+ phy_info = port_info->phy_info;
+ for (i = 0; i < port_info->num_phys; i++, phy_info++) {
+ starget = mptsas_get_starget(phy_info);
+ if (!starget)
+ continue;
+ vtarget = starget->hostdata;
+ if(vtarget->deleted)
+ continue;
+ vtarget->deleted = 1;
+ mptsas_target_reset(ioc, vtarget);
+ sas_port_delete(mptsas_get_port(phy_info));
+ mptsas_port_delete(phy_info->port_details);
+ }
+
+ /*
* Obtain the port_info instance to the parent port
*/
parent = mptsas_find_portinfo_by_handle(ioc,
@@ -1511,34 +1912,44 @@ mptsas_delete_expander_phys(MPT_ADAPTER *ioc)
if (!parent)
goto next_port;
+ expander_sas_address =
+ port_info->phy_info[0].identify.sas_address;
+
/*
* Delete rphys in the parent that point
* to this expander. The transport layer will
* cleanup all the children.
*/
- for (i = 0; i < parent->num_phys; i++) {
- if ((!parent->phy_info[i].rphy) ||
- (parent->phy_info[i].attached.sas_address !=
- port_info->phy_info[i].identify.sas_address))
+ phy_info = parent->phy_info;
+ for (i = 0; i < parent->num_phys; i++, phy_info++) {
+ port = mptsas_get_port(phy_info);
+ if (!port)
+ continue;
+ if (phy_info->attached.sas_address !=
+ expander_sas_address)
continue;
- sas_rphy_delete(parent->phy_info[i].rphy);
- memset(&parent->phy_info[i].attached, 0,
- sizeof(struct mptsas_devinfo));
- parent->phy_info[i].rphy = NULL;
- parent->phy_info[i].starget = NULL;
+#ifdef MPT_DEBUG_SAS_WIDE
+ dev_printk(KERN_DEBUG, &port->dev,
+ "delete port (%d)\n", port->port_identifier);
+#endif
+ sas_port_delete(port);
+ mptsas_port_delete(phy_info->port_details);
}
next_port:
+
+ phy_info = port_info->phy_info;
+ for (i = 0; i < port_info->num_phys; i++, phy_info++)
+ mptsas_port_delete(phy_info->port_details);
+
list_del(&port_info->list);
- if (port_info->phy_info)
- kfree(port_info->phy_info);
+ kfree(port_info->phy_info);
kfree(port_info);
}
/*
* Free this memory allocated from inside
* mptsas_sas_expander_pg0
*/
- if (buffer.phy_info)
- kfree(buffer.phy_info);
+ kfree(buffer.phy_info);
}
mutex_unlock(&ioc->sas_topology_mutex);
}
@@ -1564,7 +1975,7 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
goto out;
for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
- scsi_add_device(ioc->sh, ioc->num_ports,
+ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
}
out:
@@ -1574,60 +1985,59 @@ mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
/*
* Work queue thread to handle Runtime discovery
* Mere purpose is the hot add/delete of expanders
+ *(Mutex UNLOCKED)
*/
static void
-mptscsih_discovery_work(void * arg)
+__mptsas_discovery_work(MPT_ADAPTER *ioc)
{
- struct mptsas_discovery_event *ev = arg;
- MPT_ADAPTER *ioc = ev->ioc;
u32 handle = 0xFFFF;
- mutex_lock(&ioc->sas_discovery_mutex);
ioc->sas_discovery_runtime=1;
mptsas_delete_expander_phys(ioc);
mptsas_probe_hba_phys(ioc);
while (!mptsas_probe_expander_phys(ioc, &handle))
;
- kfree(ev);
ioc->sas_discovery_runtime=0;
+}
+
+/*
+ * Work queue thread to handle Runtime discovery
+ * Mere purpose is the hot add/delete of expanders
+ *(Mutex LOCKED)
+ */
+static void
+mptsas_discovery_work(void * arg)
+{
+ struct mptsas_discovery_event *ev = arg;
+ MPT_ADAPTER *ioc = ev->ioc;
+
+ mutex_lock(&ioc->sas_discovery_mutex);
+ __mptsas_discovery_work(ioc);
mutex_unlock(&ioc->sas_discovery_mutex);
+ kfree(ev);
}
static struct mptsas_phyinfo *
-mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id)
+mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
{
struct mptsas_portinfo *port_info;
- struct mptsas_devinfo device_info;
struct mptsas_phyinfo *phy_info = NULL;
- int i, error;
-
- /*
- * Retrieve the parent sas_address
- */
- error = mptsas_sas_device_pg0(ioc, &device_info,
- (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
- MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
- parent_handle);
- if (error)
- return NULL;
+ int i;
- /*
- * The phy_info structures are never deallocated during lifetime of
- * a host, so the code below is safe without additional refcounting.
- */
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) {
for (i = 0; i < port_info->num_phys; i++) {
- if (port_info->phy_info[i].identify.sas_address ==
- device_info.sas_address &&
- port_info->phy_info[i].phy_id == phy_id) {
- phy_info = &port_info->phy_info[i];
- break;
- }
+ if (port_info->phy_info[i].attached.sas_address
+ != sas_address)
+ continue;
+ if (!mptsas_is_end_device(
+ &port_info->phy_info[i].attached))
+ continue;
+ phy_info = &port_info->phy_info[i];
+ break;
}
}
mutex_unlock(&ioc->sas_topology_mutex);
-
return phy_info;
}
@@ -1638,21 +2048,19 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
struct mptsas_phyinfo *phy_info = NULL;
int i;
- /*
- * The phy_info structures are never deallocated during lifetime of
- * a host, so the code below is safe without additional refcounting.
- */
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry(port_info, &ioc->sas_topology, list) {
- for (i = 0; i < port_info->num_phys; i++)
- if (mptsas_is_end_device(&port_info->phy_info[i].attached))
- if (port_info->phy_info[i].attached.id == id) {
- phy_info = &port_info->phy_info[i];
- break;
- }
+ for (i = 0; i < port_info->num_phys; i++) {
+ if (port_info->phy_info[i].attached.id != id)
+ continue;
+ if (!mptsas_is_end_device(
+ &port_info->phy_info[i].attached))
+ continue;
+ phy_info = &port_info->phy_info[i];
+ break;
+ }
}
mutex_unlock(&ioc->sas_topology_mutex);
-
return phy_info;
}
@@ -1660,7 +2068,7 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id)
* Work queue thread to clear the persitency table
*/
static void
-mptscsih_sas_persist_clear_table(void * arg)
+mptsas_persist_clear_table(void * arg)
{
MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg;
@@ -1681,7 +2089,6 @@ mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
mptsas_reprobe_lun);
}
-
/*
* Work queue thread to handle SAS hotplug events
*/
@@ -1692,14 +2099,17 @@ mptsas_hotplug_work(void *arg)
MPT_ADAPTER *ioc = ev->ioc;
struct mptsas_phyinfo *phy_info;
struct sas_rphy *rphy;
+ struct sas_port *port;
struct scsi_device *sdev;
+ struct scsi_target * starget;
struct sas_identify identify;
char *ds = NULL;
struct mptsas_devinfo sas_device;
VirtTarget *vtarget;
+ VirtDevice *vdevice;
- mutex_lock(&ioc->sas_discovery_mutex);
+ mutex_lock(&ioc->sas_discovery_mutex);
switch (ev->event_type) {
case MPTSAS_DEL_DEVICE:
@@ -1708,24 +2118,50 @@ mptsas_hotplug_work(void *arg)
/*
* Sanity checks, for non-existing phys and remote rphys.
*/
- if (!phy_info)
+ if (!phy_info || !phy_info->port_details) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
- if (!phy_info->rphy)
+ }
+ rphy = mptsas_get_rphy(phy_info);
+ if (!rphy) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ break;
+ }
+ port = mptsas_get_port(phy_info);
+ if (!port) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
- if (phy_info->starget) {
- vtarget = phy_info->starget->hostdata;
+ }
+
+ starget = mptsas_get_starget(phy_info);
+ if (starget) {
+ vtarget = starget->hostdata;
- if (!vtarget)
+ if (!vtarget) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
+ }
+
/*
* Handling RAID components
*/
if (ev->phys_disk_num_valid) {
vtarget->target_id = ev->phys_disk_num;
vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
- mptsas_reprobe_target(vtarget->starget, 1);
+ mptsas_reprobe_target(starget, 1);
break;
}
+
+ vtarget->deleted = 1;
+ mptsas_target_reset(ioc, vtarget);
}
if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET)
@@ -1739,10 +2175,12 @@ mptsas_hotplug_work(void *arg)
"removing %s device, channel %d, id %d, phy %d\n",
ioc->name, ds, ev->channel, ev->id, phy_info->phy_id);
- sas_rphy_delete(phy_info->rphy);
- memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
- phy_info->rphy = NULL;
- phy_info->starget = NULL;
+#ifdef MPT_DEBUG_SAS_WIDE
+ dev_printk(KERN_DEBUG, &port->dev,
+ "delete port (%d)\n", port->port_identifier);
+#endif
+ sas_port_delete(port);
+ mptsas_port_delete(phy_info->port_details);
break;
case MPTSAS_ADD_DEVICE:
@@ -1754,59 +2192,60 @@ mptsas_hotplug_work(void *arg)
*/
if (mptsas_sas_device_pg0(ioc, &sas_device,
(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
- MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id))
+ MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
+ }
- phy_info = mptsas_find_phyinfo_by_parent(ioc,
- sas_device.handle_parent, sas_device.phy_id);
+ ssleep(2);
+ __mptsas_discovery_work(ioc);
- if (!phy_info) {
- u32 handle = 0xFFFF;
+ phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
+ sas_device.sas_address);
- /*
- * Its possible when an expander has been hot added
- * containing attached devices, the sas firmware
- * may send a RC_ADDED event prior to the
- * DISCOVERY STOP event. If that occurs, our
- * view of the topology in the driver in respect to this
- * expander might of not been setup, and we hit this
- * condition.
- * Therefore, this code kicks off discovery to
- * refresh the data.
- * Then again, we check whether the parent phy has
- * been created.
- */
- ioc->sas_discovery_runtime=1;
- mptsas_delete_expander_phys(ioc);
- mptsas_probe_hba_phys(ioc);
- while (!mptsas_probe_expander_phys(ioc, &handle))
- ;
- ioc->sas_discovery_runtime=0;
-
- phy_info = mptsas_find_phyinfo_by_parent(ioc,
- sas_device.handle_parent, sas_device.phy_id);
- if (!phy_info)
- break;
+ if (!phy_info || !phy_info->port_details) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ break;
}
- if (phy_info->starget) {
- vtarget = phy_info->starget->hostdata;
+ starget = mptsas_get_starget(phy_info);
+ if (starget) {
+ vtarget = starget->hostdata;
- if (!vtarget)
+ if (!vtarget) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
+ }
/*
* Handling RAID components
*/
if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
vtarget->target_id = ev->id;
- mptsas_reprobe_target(phy_info->starget, 0);
+ mptsas_reprobe_target(starget, 0);
}
break;
}
- if (phy_info->rphy)
+ if (mptsas_get_rphy(phy_info)) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break;
+ }
+ port = mptsas_get_port(phy_info);
+ if (!port) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
+ break;
+ }
memcpy(&phy_info->attached, &sas_device,
sizeof(struct mptsas_devinfo));
@@ -1823,59 +2262,48 @@ mptsas_hotplug_work(void *arg)
ioc->name, ds, ev->channel, ev->id, ev->phy_id);
mptsas_parse_device_info(&identify, &phy_info->attached);
- switch (identify.device_type) {
- case SAS_END_DEVICE:
- rphy = sas_end_device_alloc(phy_info->phy);
- break;
- case SAS_EDGE_EXPANDER_DEVICE:
- case SAS_FANOUT_EXPANDER_DEVICE:
- rphy = sas_expander_alloc(phy_info->phy, identify.device_type);
- break;
- default:
- rphy = NULL;
- break;
- }
- if (!rphy)
+ rphy = sas_end_device_alloc(port);
+ if (!rphy) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
break; /* non-fatal: an rphy can be added later */
+ }
rphy->identify = identify;
if (sas_rphy_add(rphy)) {
+ dfailprintk((MYIOC_s_ERR_FMT
+ "%s: exit at line=%d\n", ioc->name,
+ __FUNCTION__, __LINE__));
sas_rphy_free(rphy);
break;
}
-
- phy_info->rphy = rphy;
+ mptsas_set_rphy(phy_info, rphy);
break;
case MPTSAS_ADD_RAID:
- sdev = scsi_device_lookup(
- ioc->sh,
- ioc->num_ports,
- ev->id,
- 0);
+ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+ ev->id, 0);
if (sdev) {
scsi_device_put(sdev);
break;
}
printk(MYIOC_s_INFO_FMT
"attaching raid volume, channel %d, id %d\n",
- ioc->name, ioc->num_ports, ev->id);
- scsi_add_device(ioc->sh,
- ioc->num_ports,
- ev->id,
- 0);
+ ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+ scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL, ev->id, 0);
mpt_findImVolumes(ioc);
break;
case MPTSAS_DEL_RAID:
- sdev = scsi_device_lookup(
- ioc->sh,
- ioc->num_ports,
- ev->id,
- 0);
+ sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
+ ev->id, 0);
if (!sdev)
break;
printk(MYIOC_s_INFO_FMT
"removing raid volume, channel %d, id %d\n",
- ioc->name, ioc->num_ports, ev->id);
+ ioc->name, MPTSAS_RAID_CHANNEL, ev->id);
+ vdevice = sdev->hostdata;
+ vdevice->vtarget->deleted = 1;
+ mptsas_target_reset(ioc, vdevice->vtarget);
scsi_remove_device(sdev);
scsi_device_put(sdev);
mpt_findImVolumes(ioc);
@@ -1885,12 +2313,13 @@ mptsas_hotplug_work(void *arg)
break;
}
- kfree(ev);
mutex_unlock(&ioc->sas_discovery_mutex);
+ kfree(ev);
+
}
static void
-mptscsih_send_sas_event(MPT_ADAPTER *ioc,
+mptsas_send_sas_event(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
{
struct mptsas_hotplug_event *ev;
@@ -1906,7 +2335,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,
switch (sas_event_data->ReasonCode) {
case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
- ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
printk(KERN_WARNING "mptsas: lost hotplug event\n");
break;
@@ -1936,10 +2365,9 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,
/*
* Persistent table is full.
*/
- INIT_WORK(&ioc->mptscsih_persistTask,
- mptscsih_sas_persist_clear_table,
- (void *)ioc);
- schedule_work(&ioc->mptscsih_persistTask);
+ INIT_WORK(&ioc->sas_persist_task,
+ mptsas_persist_clear_table, (void *)ioc);
+ schedule_work(&ioc->sas_persist_task);
break;
case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
/* TODO */
@@ -1951,7 +2379,7 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc,
}
static void
-mptscsih_send_raid_event(MPT_ADAPTER *ioc,
+mptsas_send_raid_event(MPT_ADAPTER *ioc,
EVENT_DATA_RAID *raid_event_data)
{
struct mptsas_hotplug_event *ev;
@@ -1961,13 +2389,12 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
if (ioc->bus_type != SAS)
return;
- ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev) {
printk(KERN_WARNING "mptsas: lost hotplug event\n");
return;
}
- memset(ev,0,sizeof(struct mptsas_hotplug_event));
INIT_WORK(&ev->work, mptsas_hotplug_work, ev);
ev->ioc = ioc;
ev->id = raid_event_data->VolumeID;
@@ -2029,7 +2456,7 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc,
}
static void
-mptscsih_send_discovery(MPT_ADAPTER *ioc,
+mptsas_send_discovery_event(MPT_ADAPTER *ioc,
EVENT_DATA_SAS_DISCOVERY *discovery_data)
{
struct mptsas_discovery_event *ev;
@@ -2044,11 +2471,10 @@ mptscsih_send_discovery(MPT_ADAPTER *ioc,
if (discovery_data->DiscoveryStatus)
return;
- ev = kmalloc(sizeof(*ev), GFP_ATOMIC);
+ ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
if (!ev)
return;
- memset(ev,0,sizeof(struct mptsas_discovery_event));
- INIT_WORK(&ev->work, mptscsih_discovery_work, ev);
+ INIT_WORK(&ev->work, mptsas_discovery_work, ev);
ev->ioc = ioc;
schedule_work(&ev->work);
};
@@ -2076,21 +2502,21 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
switch (event) {
case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
- mptscsih_send_sas_event(ioc,
+ mptsas_send_sas_event(ioc,
(EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data);
break;
case MPI_EVENT_INTEGRATED_RAID:
- mptscsih_send_raid_event(ioc,
+ mptsas_send_raid_event(ioc,
(EVENT_DATA_RAID *)reply->Data);
break;
case MPI_EVENT_PERSISTENT_TABLE_FULL:
- INIT_WORK(&ioc->mptscsih_persistTask,
- mptscsih_sas_persist_clear_table,
+ INIT_WORK(&ioc->sas_persist_task,
+ mptsas_persist_clear_table,
(void *)ioc);
- schedule_work(&ioc->mptscsih_persistTask);
+ schedule_work(&ioc->sas_persist_task);
break;
case MPI_EVENT_SAS_DISCOVERY:
- mptscsih_send_discovery(ioc,
+ mptsas_send_discovery_event(ioc,
(EVENT_DATA_SAS_DISCOVERY *)reply->Data);
break;
default:
@@ -2280,7 +2706,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->timer.data = (unsigned long) hd;
hd->timer.function = mptscsih_timer_expired;
- hd->mpt_pq_filter = mpt_pq_filter;
ioc->sas_data.ptClear = mpt_pt_clear;
if (ioc->sas_data.ptClear==1) {
@@ -2288,12 +2713,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
}
- ddvprintk((MYIOC_s_INFO_FMT
- "mpt_pq_filter %x mpt_pq_filter %x\n",
- ioc->name,
- mpt_pq_filter,
- mpt_pq_filter));
-
init_waitqueue_head(&hd->scandv_waitq);
hd->scandv_wait_done = 0;
hd->last_queue_full = 0;
@@ -2309,7 +2728,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
-out_mptsas_probe:
+ out_mptsas_probe:
mptscsih_remove(pdev);
return error;
@@ -2319,6 +2738,7 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
{
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
struct mptsas_portinfo *p, *n;
+ int i;
ioc->sas_discovery_ignore_events=1;
sas_remove_host(ioc->sh);
@@ -2326,8 +2746,9 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
mutex_lock(&ioc->sas_topology_mutex);
list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
list_del(&p->list);
- if (p->phy_info)
- kfree(p->phy_info);
+ for (i = 0 ; i < p->num_phys ; i++)
+ mptsas_port_delete(p->phy_info[i].port_details);
+ kfree(p->phy_info);
kfree(p);
}
mutex_unlock(&ioc->sas_topology_mutex);
@@ -2336,17 +2757,15 @@ static void __devexit mptsas_remove(struct pci_dev *pdev)
}
static struct pci_device_id mptsas_pci_table[] = {
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index 8242b16e316..30524dc54b1 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -66,6 +66,7 @@
#include "mptbase.h"
#include "mptscsih.h"
+#include "lsi/mpi_log_sas.h"
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#define my_NAME "Fusion MPT SCSI Host driver"
@@ -127,7 +128,7 @@ static void mptscsih_freeChainBuffers(MPT_ADAPTER *ioc, int req_idx);
static void mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR *mf, SCSIIOReply_t *pScsiReply);
static int mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd);
static int mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout );
-static u32 SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
+static int SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc);
static int mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, int ctx2abort, ulong timeout);
@@ -497,6 +498,34 @@ nextSGEset:
return SUCCESS;
} /* mptscsih_AddSGE() */
+static void
+mptscsih_issue_sep_command(MPT_ADAPTER *ioc, VirtTarget *vtarget,
+ U32 SlotStatus)
+{
+ MPT_FRAME_HDR *mf;
+ SEPRequest_t *SEPMsg;
+
+ if (ioc->bus_type == FC)
+ return;
+
+ if ((mf = mpt_get_msg_frame(ioc->InternalCtx, ioc)) == NULL) {
+ dfailprintk((MYIOC_s_WARN_FMT "%s: no msg frames!!\n",
+ ioc->name,__FUNCTION__));
+ return;
+ }
+
+ SEPMsg = (SEPRequest_t *)mf;
+ SEPMsg->Function = MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
+ SEPMsg->Bus = vtarget->bus_id;
+ SEPMsg->TargetID = vtarget->target_id;
+ SEPMsg->Action = MPI_SEP_REQ_ACTION_WRITE_STATUS;
+ SEPMsg->SlotStatus = SlotStatus;
+ devtverboseprintk((MYIOC_s_WARN_FMT
+ "Sending SEP cmd=%x id=%d bus=%d\n",
+ ioc->name, SlotStatus, SEPMsg->TargetID, SEPMsg->Bus));
+ mpt_put_msg_frame(ioc->DoneCtx, ioc, mf);
+}
+
/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
/*
* mptscsih_io_done - Main SCSI IO callback routine registered to
@@ -520,6 +549,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
SCSIIORequest_t *pScsiReq;
SCSIIOReply_t *pScsiReply;
u16 req_idx, req_idx_MR;
+ VirtDevice *vdev;
+ VirtTarget *vtarget;
hd = (MPT_SCSI_HOST *) ioc->sh->hostdata;
@@ -538,6 +569,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
}
sc = hd->ScsiLookup[req_idx];
+ hd->ScsiLookup[req_idx] = NULL;
if (sc == NULL) {
MPIHeader_t *hdr = (MPIHeader_t *)mf;
@@ -553,6 +585,12 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
return 1;
}
+ if ((unsigned char *)mf != sc->host_scribble) {
+ mptscsih_freeChainBuffers(ioc, req_idx);
+ return 1;
+ }
+
+ sc->host_scribble = NULL;
sc->result = DID_OK << 16; /* Set default reply as OK */
pScsiReq = (SCSIIORequest_t *) mf;
pScsiReply = (SCSIIOReply_t *) mr;
@@ -640,10 +678,36 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF)
hd->sel_timeout[pScsiReq->TargetID]++;
+
+ vdev = sc->device->hostdata;
+ if (!vdev)
+ break;
+ vtarget = vdev->vtarget;
+ if (vtarget->tflags & MPT_TARGET_FLAGS_LED_ON) {
+ mptscsih_issue_sep_command(ioc, vtarget,
+ MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED);
+ vtarget->tflags &= ~MPT_TARGET_FLAGS_LED_ON;
+ }
break;
- case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
case MPI_IOCSTATUS_SCSI_IOC_TERMINATED: /* 0x004B */
+ if ( ioc->bus_type == SAS ) {
+ u16 ioc_status = le16_to_cpu(pScsiReply->IOCStatus);
+ if (ioc_status & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
+ u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo);
+ log_info &=SAS_LOGINFO_MASK;
+ if (log_info == SAS_LOGINFO_NEXUS_LOSS) {
+ sc->result = (DID_BUS_BUSY << 16);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Allow non-SAS & non-NEXUS_LOSS to drop into below code
+ */
+
+ case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */
case MPI_IOCSTATUS_SCSI_EXT_TERMINATED: /* 0x004C */
/* Linux handles an unsolicited DID_RESET better
* than an unsolicited DID_ABORT.
@@ -658,7 +722,7 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->result=DID_SOFT_ERROR << 16;
else /* Sufficient data transfer occurred */
sc->result = (DID_OK << 16) | scsi_status;
- dreplyprintk((KERN_NOTICE
+ dreplyprintk((KERN_NOTICE
"RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id));
break;
@@ -784,8 +848,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
sc->request_bufflen, sc->sc_data_direction);
}
- hd->ScsiLookup[req_idx] = NULL;
-
sc->scsi_done(sc); /* Issue the command callback */
/* Free Chain buffers */
@@ -827,9 +889,17 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
dmfprintk(( "flush: ScsiDone (mf=%p,sc=%p)\n",
mf, SCpnt));
+ /* Free Chain buffers */
+ mptscsih_freeChainBuffers(ioc, ii);
+
+ /* Free Message frames */
+ mpt_free_msg_frame(ioc, mf);
+
+ if ((unsigned char *)mf != SCpnt->host_scribble)
+ continue;
+
/* Set status, free OS resources (SG DMA buffers)
* Do OS callback
- * Free driver resources (chain, msg buffers)
*/
if (SCpnt->use_sg) {
pci_unmap_sg(ioc->pcidev,
@@ -845,12 +915,6 @@ mptscsih_flush_running_cmds(MPT_SCSI_HOST *hd)
SCpnt->result = DID_RESET << 16;
SCpnt->host_scribble = NULL;
- /* Free Chain buffers */
- mptscsih_freeChainBuffers(ioc, ii);
-
- /* Free Message frames */
- mpt_free_msg_frame(ioc, mf);
-
SCpnt->scsi_done(SCpnt); /* Issue the command callback */
}
}
@@ -887,10 +951,10 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
if ((sc = hd->ScsiLookup[ii]) != NULL) {
mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii);
-
+ if (mf == NULL)
+ continue;
dsprintk(( "search_running: found (sc=%p, mf = %p) target %d, lun %d \n",
hd->ScsiLookup[ii], mf, mf->TargetID, mf->LUN[1]));
-
if ((mf->TargetID != ((u8)vdevice->vtarget->target_id)) || (mf->LUN[1] != ((u8) vdevice->lun)))
continue;
@@ -899,6 +963,8 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, VirtDevice *vdevice)
hd->ScsiLookup[ii] = NULL;
mptscsih_freeChainBuffers(hd->ioc, ii);
mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf);
+ if ((unsigned char *)mf != sc->host_scribble)
+ continue;
if (sc->use_sg) {
pci_unmap_sg(hd->ioc->pcidev,
(struct scatterlist *) sc->request_buffer,
@@ -1341,8 +1407,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
goto fail;
}
+ SCpnt->host_scribble = (unsigned char *)mf;
hd->ScsiLookup[my_idx] = SCpnt;
- SCpnt->host_scribble = NULL;
mpt_put_msg_frame(hd->ioc->DoneCtx, hd->ioc, mf);
dmfprintk((MYIOC_s_INFO_FMT "Issued SCSI cmd (%p) mf=%p idx=%d\n",
@@ -1529,6 +1595,12 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in
rc = mpt_HardResetHandler(hd->ioc, CAN_SLEEP);
}
+ /*
+ * Check IOCStatus from TM reply message
+ */
+ if (hd->tm_iocstatus != MPI_IOCSTATUS_SUCCESS)
+ rc = FAILED;
+
dtmprintk((MYIOC_s_INFO_FMT "TMHandler rc = %d!\n", hd->ioc->name, rc));
return rc;
@@ -1654,6 +1726,7 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
int scpnt_idx;
int retval;
VirtDevice *vdev;
+ ulong sn = SCpnt->serial_number;
/* If we can't locate our host adapter structure, return FAILED status.
*/
@@ -1707,6 +1780,11 @@ mptscsih_abort(struct scsi_cmnd * SCpnt)
vdev->vtarget->bus_id, vdev->vtarget->target_id, vdev->lun,
ctx2abort, mptscsih_get_tm_timeout(hd->ioc));
+ if (SCPNT_TO_LOOKUP_IDX(SCpnt) == scpnt_idx &&
+ SCpnt->serial_number == sn) {
+ retval = FAILED;
+ }
+
printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n",
hd->ioc->name,
((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt);
@@ -2023,6 +2101,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m
DBG_DUMP_TM_REPLY_FRAME((u32 *)pScsiTmReply);
iocstatus = le16_to_cpu(pScsiTmReply->IOCStatus) & MPI_IOCSTATUS_MASK;
+ hd->tm_iocstatus = iocstatus;
dtmprintk((MYIOC_s_WARN_FMT " SCSI TaskMgmt (%d) IOCStatus=%04x IOCLogInfo=%08x\n",
ioc->name, tmType, iocstatus, le32_to_cpu(pScsiTmReply->IOCLogInfo)));
/* Error? (anything non-zero?) */
@@ -2401,6 +2480,13 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
ioc->events[idx].data[1] = (sense_data[13] << 8) || sense_data[12];
ioc->eventContext++;
+ if (hd->ioc->pcidev->vendor ==
+ PCI_VENDOR_ID_IBM) {
+ mptscsih_issue_sep_command(hd->ioc,
+ vdev->vtarget, MPI_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
+ vdev->vtarget->tflags |=
+ MPT_TARGET_FLAGS_LED_ON;
+ }
}
}
} else {
@@ -2409,7 +2495,7 @@ mptscsih_copy_sense_data(struct scsi_cmnd *sc, MPT_SCSI_HOST *hd, MPT_FRAME_HDR
}
}
-static u32
+static int
SCPNT_TO_LOOKUP_IDX(struct scsi_cmnd *sc)
{
MPT_SCSI_HOST *hd;
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 3201de05394..e4cc3dd5fc9 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -83,10 +83,6 @@ static int mpt_saf_te = MPTSCSIH_SAF_TE;
module_param(mpt_saf_te, int, 0);
MODULE_PARM_DESC(mpt_saf_te, " Force enabling SEP Processor: enable=1 (default=MPTSCSIH_SAF_TE=0)");
-static int mpt_pq_filter = 0;
-module_param(mpt_pq_filter, int, 0);
-MODULE_PARM_DESC(mpt_pq_filter, " Enable peripheral qualifier filter: enable=1 (default=0)");
-
static void mptspi_write_offset(struct scsi_target *, int);
static void mptspi_write_width(struct scsi_target *, int);
static int mptspi_write_spi_device_pg1(struct scsi_target *,
@@ -775,9 +771,9 @@ static struct spi_function_template mptspi_transport_functions = {
*/
static struct pci_device_id mptspi_pci_table[] = {
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1030,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1030,
PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_1030_53C1035,
+ { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_53C1035,
PCI_ANY_ID, PCI_ANY_ID },
{0} /* Terminating entry */
};
@@ -1047,14 +1043,12 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
hd->timer.function = mptscsih_timer_expired;
ioc->spi_data.Saf_Te = mpt_saf_te;
- hd->mpt_pq_filter = mpt_pq_filter;
hd->negoNvram = MPT_SCSICFG_USE_NVRAM;
ddvprintk((MYIOC_s_INFO_FMT
- "saf_te %x mpt_pq_filter %x\n",
+ "saf_te %x\n",
ioc->name,
- mpt_saf_te,
- mpt_pq_filter));
+ mpt_saf_te));
ioc->spi_data.noQas = 0;
init_waitqueue_head(&hd->scandv_waitq);
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
index 184974cc734..dc388a3ff5e 100644
--- a/drivers/message/i2o/core.h
+++ b/drivers/message/i2o/core.h
@@ -38,6 +38,9 @@ extern struct device_attribute i2o_device_attrs[];
extern void i2o_device_remove(struct i2o_device *);
extern int i2o_device_parse_lct(struct i2o_controller *);
+int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
+ int oplen, void *reslist, int reslen);
+
/* IOP */
extern struct i2o_controller *i2o_iop_alloc(void);
diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c
index 5a6cca8e8c4..8abe45e49ad 100644
--- a/drivers/message/i2o/debug.c
+++ b/drivers/message/i2o/debug.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 7d4c5497785..1ddc2fb429d 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -1089,7 +1089,6 @@ static int i2o_block_probe(struct device *dev)
gd = i2o_blk_dev->gd;
gd->first_minor = unit << 4;
sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit);
- sprintf(gd->devfs_name, "i2o/hd%c", 'a' + unit);
gd->driverfs_dev = &i2o_dev->device;
/* setup request queue */
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 89daf67b764..7d23e082bf2 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -36,9 +36,9 @@
#include <asm/uaccess.h>
-#define SG_TABLESIZE 30
+#include "core.h"
-extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+#define SG_TABLESIZE 30
static int i2o_cfg_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index febbdd4e060..3305c12372a 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -683,9 +683,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
c->mem_alloc = 1;
sb->current_mem_size = 1 + res->end - res->start;
sb->current_mem_base = res->start;
- osm_info("%s: allocated %ld bytes of PCI memory at "
- "0x%08lX.\n", c->name,
- 1 + res->end - res->start, res->start);
+ osm_info("%s: allocated %llu bytes of PCI memory at "
+ "0x%016llX.\n", c->name,
+ (unsigned long long)(1 + res->end - res->start),
+ (unsigned long long)res->start);
}
}
@@ -704,9 +705,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
c->io_alloc = 1;
sb->current_io_size = 1 + res->end - res->start;
sb->current_mem_base = res->start;
- osm_info("%s: allocated %ld bytes of PCI I/O at 0x%08lX"
- ".\n", c->name, 1 + res->end - res->start,
- res->start);
+ osm_info("%s: allocated %llu bytes of PCI I/O at "
+ "0x%016llX.\n", c->name,
+ (unsigned long long)(1 + res->end - res->start),
+ (unsigned long long)res->start);
}
}
@@ -1239,7 +1241,6 @@ EXPORT_SYMBOL(i2o_cntxt_list_remove);
EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
#endif
EXPORT_SYMBOL(i2o_msg_get_wait);
-EXPORT_SYMBOL(i2o_msg_nop);
EXPORT_SYMBOL(i2o_find_iop);
EXPORT_SYMBOL(i2o_iop_find_device);
EXPORT_SYMBOL(i2o_event_register);
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index 4f1515cae5d..1b58444d5aa 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -274,7 +274,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
writel(0xffffffff, c->irq_mask);
if (pdev->irq) {
- rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ,
+ rc = request_irq(pdev->irq, i2o_pci_interrupt, IRQF_SHARED,
c->name, c);
if (rc < 0) {
printk(KERN_ERR "%s: unable to allocate interrupt %d."
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index aff83f96680..2bf32721eb5 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -16,7 +16,6 @@
* Note that all locks are private to this file. Nothing else may
* touch them.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -420,8 +419,10 @@ static int ucb1x00_detect_irq(struct ucb1x00 *ucb)
unsigned long mask;
mask = probe_irq_on();
- if (!mask)
+ if (!mask) {
+ probe_irq_off(mask);
return NO_IRQ;
+ }
/*
* Enable the ADC interrupt.
@@ -478,7 +479,7 @@ static int ucb1x00_probe(struct mcp *mcp)
mcp_enable(mcp);
id = mcp_reg_read(mcp, UCB_ID);
- if (id != UCB_ID_1200 && id != UCB_ID_1300) {
+ if (id != UCB_ID_1200 && id != UCB_ID_1300 && id != UCB_ID_TC35143) {
printk(KERN_WARNING "UCB1x00 ID not found: %04x\n", id);
goto err_disable;
}
@@ -507,7 +508,7 @@ static int ucb1x00_probe(struct mcp *mcp)
goto err_free;
}
- ret = request_irq(ucb->irq, ucb1x00_irq, SA_TRIGGER_RISING,
+ ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
"UCB1x00", ucb);
if (ret) {
printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 79fd062ccb3..82938ad6ddb 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -17,7 +17,6 @@
* pin should provide pulses even when the LCD is blanked, otherwise
* a pen touch needed to unblank the LCD will never be read.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -59,6 +58,7 @@ static int adcsync;
static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
{
struct input_dev *idev = ts->idev;
+
input_report_abs(idev, ABS_X, x);
input_report_abs(idev, ABS_Y, y);
input_report_abs(idev, ABS_PRESSURE, pressure);
@@ -68,6 +68,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x
static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
{
struct input_dev *idev = ts->idev;
+
input_report_abs(idev, ABS_PRESSURE, 0);
input_sync(idev);
}
@@ -190,6 +191,7 @@ static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
{
unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
+
if (machine_is_collie())
return (!(val & (UCB_TS_CR_TSPX_LOW)));
else
@@ -292,6 +294,7 @@ static int ucb1x00_thread(void *_ts)
static void ucb1x00_ts_irq(int idx, void *id)
{
struct ucb1x00_ts *ts = id;
+
ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
wake_up(&ts->irq_wait);
}
@@ -373,36 +376,43 @@ static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
{
struct ucb1x00_ts *ts;
+ struct input_dev *idev;
+ int err;
ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- ts->idev = input_allocate_device();
- if (!ts->idev) {
- kfree(ts);
- return -ENOMEM;
+ idev = input_allocate_device();
+ if (!ts || !idev) {
+ err = -ENOMEM;
+ goto fail;
}
ts->ucb = dev->ucb;
+ ts->idev = idev;
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
- ts->idev->private = ts;
- ts->idev->name = "Touchscreen panel";
- ts->idev->id.product = ts->ucb->id;
- ts->idev->open = ucb1x00_ts_open;
- ts->idev->close = ucb1x00_ts_close;
+ idev->private = ts;
+ idev->name = "Touchscreen panel";
+ idev->id.product = ts->ucb->id;
+ idev->open = ucb1x00_ts_open;
+ idev->close = ucb1x00_ts_close;
- __set_bit(EV_ABS, ts->idev->evbit);
- __set_bit(ABS_X, ts->idev->absbit);
- __set_bit(ABS_Y, ts->idev->absbit);
- __set_bit(ABS_PRESSURE, ts->idev->absbit);
+ __set_bit(EV_ABS, idev->evbit);
+ __set_bit(ABS_X, idev->absbit);
+ __set_bit(ABS_Y, idev->absbit);
+ __set_bit(ABS_PRESSURE, idev->absbit);
- input_register_device(ts->idev);
+ err = input_register_device(idev);
+ if (err)
+ goto fail;
dev->priv = ts;
return 0;
+
+ fail:
+ input_free_device(idev);
+ kfree(ts);
+ return err;
}
static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
index 9c9a647d8b7..ca8df8072d4 100644
--- a/drivers/mfd/ucb1x00.h
+++ b/drivers/mfd/ucb1x00.h
@@ -94,6 +94,7 @@
#define UCB_ID 0x0c
#define UCB_ID_1200 0x1004
#define UCB_ID_1300 0x1005
+#define UCB_ID_TC35143 0x9712
#define UCB_MODE 0x0d
#define UCB_MODE_DYN_VFLAG_ENA (1 << 12)
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index 6aba4195444..634d538ccd1 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -29,7 +29,6 @@
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 4a35caff5d0..b99dc507de2 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -147,7 +147,6 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_mode = mode;
ret->i_uid = ret->i_gid = 0;
- ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
@@ -175,7 +174,7 @@ static struct dentry *ibmasmfs_create_file (struct super_block *sb,
}
inode->i_fop = fops;
- inode->u.generic_ip = data;
+ inode->i_private = data;
d_add(dentry, inode);
return dentry;
@@ -244,7 +243,7 @@ static int command_file_open(struct inode *inode, struct file *file)
{
struct ibmasmfs_command_data *command_data;
- if (!inode->u.generic_ip)
+ if (!inode->i_private)
return -ENODEV;
command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
@@ -252,7 +251,7 @@ static int command_file_open(struct inode *inode, struct file *file)
return -ENOMEM;
command_data->command = NULL;
- command_data->sp = inode->u.generic_ip;
+ command_data->sp = inode->i_private;
file->private_data = command_data;
return 0;
}
@@ -351,10 +350,10 @@ static int event_file_open(struct inode *inode, struct file *file)
struct ibmasmfs_event_data *event_data;
struct service_processor *sp;
- if (!inode->u.generic_ip)
+ if (!inode->i_private)
return -ENODEV;
- sp = inode->u.generic_ip;
+ sp = inode->i_private;
event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
if (!event_data)
@@ -439,14 +438,14 @@ static int r_heartbeat_file_open(struct inode *inode, struct file *file)
{
struct ibmasmfs_heartbeat_data *rhbeat;
- if (!inode->u.generic_ip)
+ if (!inode->i_private)
return -ENODEV;
rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
if (!rhbeat)
return -ENOMEM;
- rhbeat->sp = (struct service_processor *)inode->u.generic_ip;
+ rhbeat->sp = inode->i_private;
rhbeat->active = 0;
ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
file->private_data = rhbeat;
@@ -508,7 +507,7 @@ static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf,
static int remote_settings_file_open(struct inode *inode, struct file *file)
{
- file->private_data = inode->u.generic_ip;
+ file->private_data = inode->i_private;
return 0;
}
diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c
index 1fdf03fd2da..2f3bddfab93 100644
--- a/drivers/misc/ibmasm/module.c
+++ b/drivers/misc/ibmasm/module.c
@@ -85,7 +85,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
}
memset(sp, 0, sizeof(struct service_processor));
- sp->lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&sp->lock);
INIT_LIST_HEAD(&sp->command_queue);
pci_set_drvdata(pdev, (void *)sp);
@@ -113,7 +113,7 @@ static int __devinit ibmasm_init_one(struct pci_dev *pdev, const struct pci_devi
goto error_ioremap;
}
- result = request_irq(sp->irq, ibmasm_interrupt_handler, SA_SHIRQ, sp->devname, (void*)sp);
+ result = request_irq(sp->irq, ibmasm_interrupt_handler, IRQF_SHARED, sp->devname, (void*)sp);
if (result) {
dev_err(sp->dev, "Failed to register interrupt handler\n");
goto error_request_irq;
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index 3228516b7d1..cb142a66098 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -53,7 +53,6 @@
Gets the status of the write protect pin, if available.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -823,6 +822,7 @@ static int at91_mci_probe(struct platform_device *pdev)
mmc->f_min = 375000;
mmc->f_max = 25000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_BYTEBLOCK;
host = mmc_priv(mmc);
host->mmc = mmc;
@@ -851,7 +851,7 @@ static int at91_mci_probe(struct platform_device *pdev)
/*
* Allocate the MCI interrupt
*/
- ret = request_irq(AT91_ID_MCI, at91_mci_irq, SA_SHIRQ, DRIVER_NAME, host);
+ ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
if (ret) {
printk(KERN_ERR "Failed to request MCI interrupt\n");
clk_disable(mci_clk);
@@ -907,7 +907,7 @@ static int at91_mci_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
at91_mci_disable();
- free_irq(AT91_ID_MCI, host);
+ free_irq(AT91RM9200_ID_MCI, host);
mmc_free_host(mmc);
clk_disable(mci_clk); /* Disable the peripheral clock */
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 5dc4bee7abe..61268da1395 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -34,7 +34,6 @@
* So we use the timer to check the status manually.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
@@ -732,7 +731,7 @@ static void au1xmmc_set_ios(struct mmc_host* mmc, struct mmc_ios* ios)
}
}
-static void au1xmmc_dma_callback(int irq, void *dev_id, struct pt_regs *regs)
+static void au1xmmc_dma_callback(int irq, void *dev_id)
{
struct au1xmmc_host *host = (struct au1xmmc_host *) dev_id;
@@ -887,7 +886,7 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
int i, ret = 0;
/* THe interrupt is shared among all controllers */
- ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, SA_INTERRUPT, "MMC", 0);
+ ret = request_irq(AU1100_SD_IRQ, au1xmmc_irq, IRQF_DISABLED, "MMC", 0);
if (ret) {
printk(DRIVER_NAME "ERROR: Couldn't get int %d: %d\n",
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index 5c62f4e6ad0..1b79dd271aa 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -25,7 +25,6 @@
* deficiencies
*
*/
-#include <linux/config.h>
#ifdef CONFIG_MMC_DEBUG
#define DEBUG
@@ -92,6 +91,8 @@ struct imxmci_host {
int dma_allocated;
unsigned char actual_bus_width;
+
+ int prev_cmd_code;
};
#define IMXMCI_PEND_IRQ_b 0
@@ -249,16 +250,14 @@ static void imxmci_setup_data(struct imxmci_host *host, struct mmc_data *data)
* partial FIFO fills and reads. The length has to be rounded up to burst size multiple.
* This is required for SCR read at least.
*/
- if (datasz < 64) {
+ if (datasz < 512) {
host->dma_size = datasz;
if (data->flags & MMC_DATA_READ) {
host->dma_dir = DMA_FROM_DEVICE;
/* Hack to enable read SCR */
- if(datasz < 16) {
- MMC_NOB = 1;
- MMC_BLK_LEN = 16;
- }
+ MMC_NOB = 1;
+ MMC_BLK_LEN = 512;
} else {
host->dma_dir = DMA_TO_DEVICE;
}
@@ -410,6 +409,9 @@ static void imxmci_finish_request(struct imxmci_host *host, struct mmc_request *
spin_unlock_irqrestore(&host->lock, flags);
+ if(req && req->cmd)
+ host->prev_cmd_code = req->cmd->opcode;
+
host->req = NULL;
host->cmd = NULL;
host->data = NULL;
@@ -554,7 +556,6 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
{
int i;
int burst_len;
- int flush_len;
int trans_done = 0;
unsigned int stat = *pstat;
@@ -567,44 +568,43 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data running STATUS = 0x%x\n",
stat);
+ udelay(20); /* required for clocks < 8MHz*/
+
if(host->dma_dir == DMA_FROM_DEVICE) {
imxmci_busy_wait_for_status(host, &stat,
STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE,
- 20, "imxmci_cpu_driven_data read");
+ 50, "imxmci_cpu_driven_data read");
while((stat & (STATUS_APPL_BUFF_FF | STATUS_DATA_TRANS_DONE)) &&
- (host->data_cnt < host->dma_size)) {
- if(burst_len >= host->dma_size - host->data_cnt) {
- flush_len = burst_len;
- burst_len = host->dma_size - host->data_cnt;
- flush_len -= burst_len;
- host->data_cnt = host->dma_size;
- trans_done = 1;
- } else {
- flush_len = 0;
- host->data_cnt += burst_len;
- }
+ (host->data_cnt < 512)) {
+
+ udelay(20); /* required for clocks < 8MHz*/
for(i = burst_len; i>=2 ; i-=2) {
- *(host->data_ptr++) = MMC_BUFFER_ACCESS;
- udelay(20); /* required for clocks < 8MHz*/
+ u16 data;
+ data = MMC_BUFFER_ACCESS;
+ udelay(10); /* required for clocks < 8MHz*/
+ if(host->data_cnt+2 <= host->dma_size) {
+ *(host->data_ptr++) = data;
+ } else {
+ if(host->data_cnt < host->dma_size)
+ *(u8*)(host->data_ptr) = data;
+ }
+ host->data_cnt += 2;
}
- if(i == 1)
- *(u8*)(host->data_ptr) = MMC_BUFFER_ACCESS;
-
stat = MMC_STATUS;
- /* Flush extra bytes from FIFO */
- while(flush_len && !(stat & STATUS_DATA_TRANS_DONE)){
- i = MMC_BUFFER_ACCESS;
- stat = MMC_STATUS;
- stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */
- }
-
- dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read burst %d STATUS = 0x%x\n",
- burst_len, stat);
+ dev_dbg(mmc_dev(host->mmc), "imxmci_cpu_driven_data read %d burst %d STATUS = 0x%x\n",
+ host->data_cnt, burst_len, stat);
}
+
+ if((stat & STATUS_DATA_TRANS_DONE) && (host->data_cnt >= 512))
+ trans_done = 1;
+
+ if(host->dma_size & 0x1ff)
+ stat &= ~STATUS_CRC_READ_ERR;
+
} else {
imxmci_busy_wait_for_status(host, &stat,
STATUS_APPL_BUFF_FE,
@@ -693,8 +693,8 @@ static void imxmci_tasklet_fnc(unsigned long data)
what, stat, MMC_INT_MASK);
dev_err(mmc_dev(host->mmc), "CMD_DAT_CONT = 0x%04x, MMC_BLK_LEN = 0x%04x, MMC_NOB = 0x%04x, DMA_CCR = 0x%08x\n",
MMC_CMD_DAT_CONT, MMC_BLK_LEN, MMC_NOB, CCR(host->dma));
- dev_err(mmc_dev(host->mmc), "CMD%d, bus %d-bit, dma_size = 0x%x\n",
- host->cmd?host->cmd->opcode:0, 1<<host->actual_bus_width, host->dma_size);
+ dev_err(mmc_dev(host->mmc), "CMD%d, prevCMD%d, bus %d-bit, dma_size = 0x%x\n",
+ host->cmd?host->cmd->opcode:0, host->prev_cmd_code, 1<<host->actual_bus_width, host->dma_size);
}
if(!host->present || timeout)
@@ -956,7 +956,7 @@ static int imxmci_probe(struct platform_device *pdev)
mmc->f_min = 150000;
mmc->f_max = CLK_RATE/2;
mmc->ocr_avail = MMC_VDD_32_33;
- mmc->caps |= MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 6201f3086a0..5b9caa7978d 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -9,7 +9,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -129,7 +128,7 @@ static void mmc_wait_done(struct mmc_request *mrq)
int mmc_wait_for_req(struct mmc_host *host, struct mmc_request *mrq)
{
- DECLARE_COMPLETION(complete);
+ DECLARE_COMPLETION_ONSTACK(complete);
mrq->done_data = &complete;
mrq->done = mmc_wait_done;
@@ -248,6 +247,55 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
EXPORT_SYMBOL(mmc_wait_for_app_cmd);
+/**
+ * mmc_set_data_timeout - set the timeout for a data command
+ * @data: data phase for command
+ * @card: the MMC card associated with the data transfer
+ * @write: flag to differentiate reads from writes
+ */
+void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
+ int write)
+{
+ unsigned int mult;
+
+ /*
+ * SD cards use a 100 multiplier rather than 10
+ */
+ mult = mmc_card_sd(card) ? 100 : 10;
+
+ /*
+ * Scale up the multiplier (and therefore the timeout) by
+ * the r2w factor for writes.
+ */
+ if (write)
+ mult <<= card->csd.r2w_factor;
+
+ data->timeout_ns = card->csd.tacc_ns * mult;
+ data->timeout_clks = card->csd.tacc_clks * mult;
+
+ /*
+ * SD cards also have an upper limit on the timeout.
+ */
+ if (mmc_card_sd(card)) {
+ unsigned int timeout_us, limit_us;
+
+ timeout_us = data->timeout_ns / 1000;
+ timeout_us += data->timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (write)
+ limit_us = 250000;
+ else
+ limit_us = 100000;
+
+ if (timeout_us > limit_us) {
+ data->timeout_ns = limit_us * 1000;
+ data->timeout_clks = 0;
+ }
+ }
+}
+EXPORT_SYMBOL(mmc_set_data_timeout);
+
static int mmc_select_card(struct mmc_host *host, struct mmc_card *card);
/**
@@ -909,11 +957,9 @@ static void mmc_read_scrs(struct mmc_host *host)
{
int err;
struct mmc_card *card;
-
struct mmc_request mrq;
struct mmc_command cmd;
struct mmc_data data;
-
struct scatterlist sg;
list_for_each_entry(card, &host->cards, node) {
@@ -948,9 +994,8 @@ static void mmc_read_scrs(struct mmc_host *host)
memset(&data, 0, sizeof(struct mmc_data));
- data.timeout_ns = card->csd.tacc_ns * 10;
- data.timeout_clks = card->csd.tacc_clks * 10;
- data.blksz_bits = 3;
+ mmc_set_data_timeout(&data, card, 0);
+
data.blksz = 1 << 3;
data.blocks = 1;
data.flags = MMC_DATA_READ;
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 587458b370b..db0e8ad439a 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -27,11 +27,12 @@
#include <linux/hdreg.h>
#include <linux/kdev_t.h>
#include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/mutex.h>
#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -165,6 +166,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
do {
struct mmc_blk_request brq;
struct mmc_command cmd;
+ u32 readcmd, writecmd;
memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd;
@@ -172,35 +174,39 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.cmd.arg = req->sector << 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- brq.data.timeout_ns = card->csd.tacc_ns * 10;
- brq.data.timeout_clks = card->csd.tacc_clks * 10;
- brq.data.blksz_bits = md->block_bits;
brq.data.blksz = 1 << md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
- if (rq_data_dir(req) == READ) {
- brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
- brq.data.flags |= MMC_DATA_READ;
- } else {
- brq.cmd.opcode = MMC_WRITE_BLOCK;
- brq.data.flags |= MMC_DATA_WRITE;
- brq.data.blocks = 1;
+ mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
- /*
- * Scale up the timeout by the r2w factor
- */
- brq.data.timeout_ns <<= card->csd.r2w_factor;
- brq.data.timeout_clks <<= card->csd.r2w_factor;
- }
+ /*
+ * If the host doesn't support multiple block writes, force
+ * block writes to single block.
+ */
+ if (rq_data_dir(req) != READ &&
+ !(card->host->caps & MMC_CAP_MULTIWRITE))
+ brq.data.blocks = 1;
if (brq.data.blocks > 1) {
brq.data.flags |= MMC_DATA_MULTI;
brq.mrq.stop = &brq.stop;
+ readcmd = MMC_READ_MULTIPLE_BLOCK;
+ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else {
brq.mrq.stop = NULL;
+ readcmd = MMC_READ_SINGLE_BLOCK;
+ writecmd = MMC_WRITE_BLOCK;
+ }
+
+ if (rq_data_dir(req) == READ) {
+ brq.cmd.opcode = readcmd;
+ brq.data.flags |= MMC_DATA_READ;
+ } else {
+ brq.cmd.opcode = writecmd;
+ brq.data.flags |= MMC_DATA_WRITE;
}
brq.data.sg = mq->sg;
@@ -225,27 +231,29 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
goto cmd_err;
}
- do {
- int err;
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
- if (err) {
- printk(KERN_ERR "%s: error %d requesting status\n",
- req->rq_disk->disk_name, err);
- goto cmd_err;
- }
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+ if (rq_data_dir(req) != READ) {
+ do {
+ int err;
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(card->host, &cmd, 5);
+ if (err) {
+ printk(KERN_ERR "%s: error %d requesting status\n",
+ req->rq_disk->disk_name, err);
+ goto cmd_err;
+ }
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
#if 0
- if (cmd.resp[0] & ~0x00000900)
- printk(KERN_ERR "%s: status = %08x\n",
- req->rq_disk->disk_name, cmd.resp[0]);
- if (mmc_decode_status(cmd.resp))
- goto cmd_err;
+ if (cmd.resp[0] & ~0x00000900)
+ printk(KERN_ERR "%s: status = %08x\n",
+ req->rq_disk->disk_name, cmd.resp[0]);
+ if (mmc_decode_status(cmd.resp))
+ goto cmd_err;
#endif
+ }
/*
* A block was successfully transferred.
@@ -325,52 +333,11 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
md->read_only = mmc_blk_readonly(card);
/*
- * Figure out a workable block size. MMC cards have:
- * - two block sizes, one for read and one for write.
- * - may support partial reads and/or writes
- * (allows block sizes smaller than specified)
- */
- md->block_bits = card->csd.read_blkbits;
- if (card->csd.write_blkbits != card->csd.read_blkbits) {
- if (card->csd.write_blkbits < card->csd.read_blkbits &&
- card->csd.read_partial) {
- /*
- * write block size is smaller than read block
- * size, but we support partial reads, so choose
- * the smaller write block size.
- */
- md->block_bits = card->csd.write_blkbits;
- } else if (card->csd.write_blkbits > card->csd.read_blkbits &&
- card->csd.write_partial) {
- /*
- * read block size is smaller than write block
- * size, but we support partial writes. Use read
- * block size.
- */
- } else {
- /*
- * We don't support this configuration for writes.
- */
- printk(KERN_ERR "%s: unable to select block size for "
- "writing (rb%u wb%u rp%u wp%u)\n",
- mmc_card_id(card),
- 1 << card->csd.read_blkbits,
- 1 << card->csd.write_blkbits,
- card->csd.read_partial,
- card->csd.write_partial);
- md->read_only = 1;
- }
- }
-
- /*
- * Refuse to allow block sizes smaller than 512 bytes.
+ * Both SD and MMC specifications state (although a bit
+ * unclearly in the MMC case) that a block size of 512
+ * bytes must always be supported by the card.
*/
- if (md->block_bits < 9) {
- printk(KERN_ERR "%s: unable to support block size %u\n",
- mmc_card_id(card), 1 << md->block_bits);
- ret = -EINVAL;
- goto err_kfree;
- }
+ md->block_bits = 9;
md->disk = alloc_disk(1 << MMC_SHIFT);
if (md->disk == NULL) {
@@ -409,7 +376,6 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
*/
sprintf(md->disk->disk_name, "mmcblk%d", devidx);
- sprintf(md->disk->devfs_name, "mmc/blk%d", devidx);
blk_queue_hardsect_size(md->queue.queue, 1 << md->block_bits);
@@ -555,7 +521,6 @@ static int __init mmc_blk_init(void)
if (major == 0)
major = res;
- devfs_mk_dir("mmc");
return mmc_register_driver(&mmc_driver);
out:
@@ -565,7 +530,6 @@ static int __init mmc_blk_init(void)
static void __exit mmc_blk_exit(void)
{
mmc_unregister_driver(&mmc_driver);
- devfs_remove("mmc");
unregister_blkdev(major, "mmc");
}
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index 0b9682e9a35..74f8cdeeff0 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -79,7 +79,8 @@ static int mmc_queue_thread(void *d)
spin_lock_irq(q->queue_lock);
set_current_state(TASK_INTERRUPTIBLE);
if (!blk_queue_plugged(q))
- mq->req = req = elv_next_request(q);
+ req = elv_next_request(q);
+ mq->req = req;
spin_unlock_irq(q->queue_lock);
if (!req) {
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index da8e4d7339c..2b5a0cc9ea5 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -7,7 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -70,12 +69,13 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
unsigned int datactrl, timeout, irqmask;
unsigned long long clks;
void __iomem *base;
+ int blksz_bits;
DBG(host, "blksz %04x blks %04x flags %08x\n",
- 1 << data->blksz_bits, data->blocks, data->flags);
+ data->blksz, data->blocks, data->flags);
host->data = data;
- host->size = data->blocks << data->blksz_bits;
+ host->size = data->blksz;
host->data_xfered = 0;
mmci_init_sg(host, data);
@@ -89,7 +89,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
writel(timeout, base + MMCIDATATIMER);
writel(host->size, base + MMCIDATALENGTH);
- datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
+ blksz_bits = ffs(data->blksz) - 1;
+ BUG_ON(1 << blksz_bits != data->blksz);
+
+ datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
if (data->flags & MMC_DATA_READ) {
datactrl |= MCI_DPSM_DIRECTION;
irqmask = MCI_RXFIFOHALFFULLMASK;
@@ -146,7 +149,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
if (status & MCI_DATABLOCKEND) {
- host->data_xfered += 1 << data->blksz_bits;
+ host->data_xfered += data->blksz;
}
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
if (status & MCI_DATACRCFAIL)
@@ -506,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk, fmax);
mmc->ocr_avail = plat->ocr_mask;
+ mmc->caps = MMC_CAP_MULTIWRITE;
/*
* We can do SGIO
@@ -532,11 +536,11 @@ static int mmci_probe(struct amba_device *dev, void *id)
writel(0, host->base + MMCIMASK1);
writel(0xfff, host->base + MMCICLEAR);
- ret = request_irq(dev->irq[0], mmci_irq, SA_SHIRQ, DRIVER_NAME " (cmd)", host);
+ ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
if (ret)
goto unmap;
- ret = request_irq(dev->irq[1], mmci_pio_irq, SA_SHIRQ, DRIVER_NAME " (pio)", host);
+ ret = request_irq(dev->irq[1], mmci_pio_irq, IRQF_SHARED, DRIVER_NAME " (pio)", host);
if (ret)
goto irq0_free;
@@ -546,9 +550,9 @@ static int mmci_probe(struct amba_device *dev, void *id)
mmc_add_host(mmc);
- printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%08lx irq %d,%d\n",
+ printk(KERN_INFO "%s: MMCI rev %x cfg %02x at 0x%016llx irq %d,%d\n",
mmc_hostname(mmc), amba_rev(dev), amba_config(dev),
- dev->res.start, dev->irq[0], dev->irq[1]);
+ (unsigned long long)dev->res.start, dev->irq[0], dev->irq[1]);
init_timer(&host->timer);
host->timer.data = (unsigned long)host;
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index c25244b3657..52c9e52e6b7 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -11,7 +11,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -61,6 +60,7 @@ struct mmc_omap_host {
unsigned char id; /* 16xx chips have 2 MMC blocks */
struct clk * iclk;
struct clk * fclk;
+ struct resource *res;
void __iomem *base;
int irq;
unsigned char bus_mode;
@@ -340,8 +340,6 @@ static void
mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
{
int n;
- void __iomem *reg;
- u16 *p;
if (host->buffer_bytes_left == 0) {
host->sg_idx++;
@@ -658,12 +656,12 @@ static void mmc_omap_dma_cb(int lch, u16 ch_status, void *data)
struct mmc_data *mmcdat = host->data;
if (unlikely(host->dma_ch < 0)) {
- dev_err(mmc_dev(host->mmc), "DMA callback while DMA not
- enabled\n");
+ dev_err(mmc_dev(host->mmc),
+ "DMA callback while DMA not enabled\n");
return;
}
/* FIXME: We really should do something to _handle_ the errors */
- if (ch_status & OMAP_DMA_TOUT_IRQ) {
+ if (ch_status & OMAP1_DMA_TOUT_IRQ) {
dev_err(mmc_dev(host->mmc),"DMA timeout\n");
return;
}
@@ -973,20 +971,20 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
struct omap_mmc_conf *minfo = pdev->dev.platform_data;
struct mmc_host *mmc;
struct mmc_omap_host *host = NULL;
+ struct resource *r;
int ret = 0;
+ int irq;
- if (platform_get_resource(pdev, IORESOURCE_MEM, 0) ||
- platform_get_irq(pdev, IORESOURCE_IRQ, 0)) {
- dev_err(&pdev->dev, "mmc_omap_probe: invalid resource type\n");
- return -ENODEV;
- }
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!r || irq < 0)
+ return -ENXIO;
- if (!request_mem_region(pdev->resource[0].start,
+ r = request_mem_region(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1,
- pdev->name)) {
- dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ pdev->name);
+ if (!r)
return -EBUSY;
- }
mmc = mmc_alloc_host(sizeof(struct mmc_omap_host), &pdev->dev);
if (!mmc) {
@@ -1003,6 +1001,8 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
host->dma_timer.data = (unsigned long) host;
host->id = pdev->id;
+ host->res = r;
+ host->irq = irq;
if (cpu_is_omap24xx()) {
host->iclk = clk_get(&pdev->dev, "mmc_ick");
@@ -1032,19 +1032,16 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
host->dma_ch = -1;
host->irq = pdev->resource[1].start;
- host->base = ioremap(pdev->res.start, SZ_4K);
- if (!host->base) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (minfo->wire4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
+ host->base = (void __iomem*)IO_ADDRESS(r->start);
mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_BYTEBLOCK;
+
+ if (minfo->wire4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
/* Use scatterlist DMA to reduce per-transfer costs.
* NOTE max_seg_size assumption that small blocks aren't
@@ -1057,8 +1054,8 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
if (host->power_pin >= 0) {
if ((ret = omap_request_gpio(host->power_pin)) != 0) {
- dev_err(mmc_dev(host->mmc), "Unable to get GPIO
- pin for MMC power\n");
+ dev_err(mmc_dev(host->mmc),
+ "Unable to get GPIO pin for MMC power\n");
goto out;
}
omap_set_gpio_direction(host->power_pin, 0);
@@ -1086,7 +1083,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
omap_set_gpio_direction(host->switch_pin, 1);
ret = request_irq(OMAP_GPIO_IRQ(host->switch_pin),
- mmc_omap_switch_irq, SA_TRIGGER_RISING, DRIVER_NAME, host);
+ mmc_omap_switch_irq, IRQF_TRIGGER_RISING, DRIVER_NAME, host);
if (ret) {
dev_warn(mmc_dev(host->mmc), "Unable to get IRQ for MMC cover switch\n");
omap_free_gpio(host->switch_pin);
@@ -1100,7 +1097,7 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
device_remove_file(&pdev->dev, &dev_attr_cover_switch);
}
if (ret) {
- dev_wan(mmc_dev(host->mmc), "Unable to create sysfs attributes\n");
+ dev_warn(mmc_dev(host->mmc), "Unable to create sysfs attributes\n");
free_irq(OMAP_GPIO_IRQ(host->switch_pin), host);
omap_free_gpio(host->switch_pin);
host->switch_pin = -1;
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index b49368fd96b..ef350908478 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -16,7 +16,6 @@
* 1 and 3 byte data transfers not supported
* max block length up to 1023
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 8e9100bd57e..fdfc3838dd7 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -8,12 +8,6 @@
* published by the Free Software Foundation.
*/
- /*
- * Note that PIO transfer is rather crappy atm. The buffer full/empty
- * interrupts aren't reliable so we currently transfer the entire buffer
- * directly. Patches to solve the problem are welcome.
- */
-
#include <linux/delay.h>
#include <linux/highmem.h>
#include <linux/pci.h>
@@ -27,16 +21,50 @@
#include "sdhci.h"
#define DRIVER_NAME "sdhci"
-#define DRIVER_VERSION "0.11"
+#define DRIVER_VERSION "0.12"
#define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
#define DBG(f, x...) \
pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
+static unsigned int debug_nodma = 0;
+static unsigned int debug_forcedma = 0;
+static unsigned int debug_quirks = 0;
+
+#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
+#define SDHCI_QUIRK_FORCE_DMA (1<<1)
+
static const struct pci_device_id pci_ids[] __devinitdata = {
- /* handle any SD host controller */
- {PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)},
+ {
+ .vendor = PCI_VENDOR_ID_RICOH,
+ .device = PCI_DEVICE_ID_RICOH_R5C822,
+ .subvendor = PCI_VENDOR_ID_IBM,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_CLOCK_BEFORE_RESET |
+ SDHCI_QUIRK_FORCE_DMA,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_RICOH,
+ .device = PCI_DEVICE_ID_RICOH_R5C822,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_FORCE_DMA,
+ },
+
+ {
+ .vendor = PCI_VENDOR_ID_TI,
+ .device = PCI_DEVICE_ID_TI_XX21_XX11_SD,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = SDHCI_QUIRK_FORCE_DMA,
+ },
+
+ { /* Generic SD host controller */
+ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
+ },
+
{ /* end: all zeroes */ },
};
@@ -94,12 +122,27 @@ static void sdhci_dumpregs(struct sdhci_host *host)
static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
+ unsigned long timeout;
+
writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
- if (mask & SDHCI_RESET_ALL) {
+ if (mask & SDHCI_RESET_ALL)
host->clock = 0;
- mdelay(50);
+ /* Wait max 100 ms */
+ timeout = 100;
+
+ /* hw clears the bit when it's done */
+ while (readb(host->ioaddr + SDHCI_SOFTWARE_RESET) & mask) {
+ if (timeout == 0) {
+ printk(KERN_ERR "%s: Reset 0x%x never completed. "
+ "Please report this to " BUGMAIL ".\n",
+ mmc_hostname(host->mmc), (int)mask);
+ sdhci_dumpregs(host);
+ return;
+ }
+ timeout--;
+ mdelay(1);
}
}
@@ -109,13 +152,15 @@ static void sdhci_init(struct sdhci_host *host)
sdhci_reset(host, SDHCI_RESET_ALL);
- intmask = ~(SDHCI_INT_CARD_INT | SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL);
+ intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+ SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
+ SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
+ SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
+ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
+ SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-
- /* This is unknown magic. */
- writeb(0xE, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
}
static void sdhci_activate_led(struct sdhci_host *host)
@@ -172,79 +217,96 @@ static inline int sdhci_next_sg(struct sdhci_host* host)
return host->num_sg;
}
-static void sdhci_transfer_pio(struct sdhci_host *host)
+static void sdhci_read_block_pio(struct sdhci_host *host)
{
+ int blksize, chunk_remain;
+ u32 data;
char *buffer;
- u32 mask;
- int bytes, size;
- unsigned long max_jiffies;
+ int size;
- BUG_ON(!host->data);
+ DBG("PIO reading\n");
- if (host->num_sg == 0)
- return;
-
- bytes = 0;
- if (host->data->flags & MMC_DATA_READ)
- mask = SDHCI_DATA_AVAILABLE;
- else
- mask = SDHCI_SPACE_AVAILABLE;
+ blksize = host->data->blksz;
+ chunk_remain = 0;
+ data = 0;
buffer = sdhci_kmap_sg(host) + host->offset;
- /* Transfer shouldn't take more than 5 s */
- max_jiffies = jiffies + HZ * 5;
+ while (blksize) {
+ if (chunk_remain == 0) {
+ data = readl(host->ioaddr + SDHCI_BUFFER);
+ chunk_remain = min(blksize, 4);
+ }
- while (host->size > 0) {
- if (time_after(jiffies, max_jiffies)) {
- printk(KERN_ERR "%s: PIO transfer stalled. "
- "Please report this to "
- BUGMAIL ".\n", mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
+ size = min(host->size, host->remain);
+ size = min(size, chunk_remain);
- sdhci_kunmap_sg(host);
+ chunk_remain -= size;
+ blksize -= size;
+ host->offset += size;
+ host->remain -= size;
+ host->size -= size;
+ while (size) {
+ *buffer = data & 0xFF;
+ buffer++;
+ data >>= 8;
+ size--;
+ }
- host->data->error = MMC_ERR_FAILED;
- sdhci_finish_data(host);
- return;
+ if (host->remain == 0) {
+ sdhci_kunmap_sg(host);
+ if (sdhci_next_sg(host) == 0) {
+ BUG_ON(blksize != 0);
+ return;
+ }
+ buffer = sdhci_kmap_sg(host);
}
+ }
- if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask))
- continue;
+ sdhci_kunmap_sg(host);
+}
- size = min(host->size, host->remain);
+static void sdhci_write_block_pio(struct sdhci_host *host)
+{
+ int blksize, chunk_remain;
+ u32 data;
+ char *buffer;
+ int bytes, size;
- if (size >= 4) {
- if (host->data->flags & MMC_DATA_READ)
- *(u32*)buffer = readl(host->ioaddr + SDHCI_BUFFER);
- else
- writel(*(u32*)buffer, host->ioaddr + SDHCI_BUFFER);
- size = 4;
- } else if (size >= 2) {
- if (host->data->flags & MMC_DATA_READ)
- *(u16*)buffer = readw(host->ioaddr + SDHCI_BUFFER);
- else
- writew(*(u16*)buffer, host->ioaddr + SDHCI_BUFFER);
- size = 2;
- } else {
- if (host->data->flags & MMC_DATA_READ)
- *(u8*)buffer = readb(host->ioaddr + SDHCI_BUFFER);
- else
- writeb(*(u8*)buffer, host->ioaddr + SDHCI_BUFFER);
- size = 1;
- }
+ DBG("PIO writing\n");
- buffer += size;
+ blksize = host->data->blksz;
+ chunk_remain = 4;
+ data = 0;
+
+ bytes = 0;
+ buffer = sdhci_kmap_sg(host) + host->offset;
+
+ while (blksize) {
+ size = min(host->size, host->remain);
+ size = min(size, chunk_remain);
+
+ chunk_remain -= size;
+ blksize -= size;
host->offset += size;
host->remain -= size;
-
- bytes += size;
host->size -= size;
+ while (size) {
+ data >>= 8;
+ data |= (u32)*buffer << 24;
+ buffer++;
+ size--;
+ }
+
+ if (chunk_remain == 0) {
+ writel(data, host->ioaddr + SDHCI_BUFFER);
+ chunk_remain = min(blksize, 4);
+ }
if (host->remain == 0) {
sdhci_kunmap_sg(host);
if (sdhci_next_sg(host) == 0) {
- DBG("PIO transfer: %d bytes\n", bytes);
+ BUG_ON(blksize != 0);
return;
}
buffer = sdhci_kmap_sg(host);
@@ -252,38 +314,87 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
}
sdhci_kunmap_sg(host);
+}
+
+static void sdhci_transfer_pio(struct sdhci_host *host)
+{
+ u32 mask;
+
+ BUG_ON(!host->data);
+
+ if (host->size == 0)
+ return;
+
+ if (host->data->flags & MMC_DATA_READ)
+ mask = SDHCI_DATA_AVAILABLE;
+ else
+ mask = SDHCI_SPACE_AVAILABLE;
+
+ while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+ if (host->data->flags & MMC_DATA_READ)
+ sdhci_read_block_pio(host);
+ else
+ sdhci_write_block_pio(host);
- DBG("PIO transfer: %d bytes\n", bytes);
+ if (host->size == 0)
+ break;
+
+ BUG_ON(host->num_sg == 0);
+ }
+
+ DBG("PIO transfer complete.\n");
}
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
{
- u16 mode;
+ u8 count;
+ unsigned target_timeout, current_timeout;
WARN_ON(host->data);
- if (data == NULL) {
- writew(0, host->ioaddr + SDHCI_TRANSFER_MODE);
+ if (data == NULL)
return;
- }
DBG("blksz %04x blks %04x flags %08x\n",
data->blksz, data->blocks, data->flags);
DBG("tsac %d ms nsac %d clk\n",
data->timeout_ns / 1000000, data->timeout_clks);
- mode = SDHCI_TRNS_BLK_CNT_EN;
- if (data->blocks > 1)
- mode |= SDHCI_TRNS_MULTI;
- if (data->flags & MMC_DATA_READ)
- mode |= SDHCI_TRNS_READ;
- if (host->flags & SDHCI_USE_DMA)
- mode |= SDHCI_TRNS_DMA;
+ /* Sanity checks */
+ BUG_ON(data->blksz * data->blocks > 524288);
+ BUG_ON(data->blksz > host->max_block);
+ BUG_ON(data->blocks > 65535);
- writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
+ /* timeout in us */
+ target_timeout = data->timeout_ns / 1000 +
+ data->timeout_clks / host->clock;
- writew(data->blksz, host->ioaddr + SDHCI_BLOCK_SIZE);
- writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
+ /*
+ * Figure out needed cycles.
+ * We do this in steps in order to fit inside a 32 bit int.
+ * The first step is the minimum timeout, which will have a
+ * minimum resolution of 6 bits:
+ * (1) 2^13*1000 > 2^22,
+ * (2) host->timeout_clk < 2^16
+ * =>
+ * (1) / (2) > 2^6
+ */
+ count = 0;
+ current_timeout = (1 << 13) * 1000 / host->timeout_clk;
+ while (current_timeout < target_timeout) {
+ count++;
+ current_timeout <<= 1;
+ if (count >= 0xF)
+ break;
+ }
+
+ if (count >= 0xF) {
+ printk(KERN_WARNING "%s: Too large timeout requested!\n",
+ mmc_hostname(host->mmc));
+ count = 0xE;
+ }
+
+ writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
if (host->flags & SDHCI_USE_DMA) {
int count;
@@ -302,12 +413,37 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
host->offset = 0;
host->remain = host->cur_sg->length;
}
+
+ /* We do not handle DMA boundaries, so set it to max (512 KiB) */
+ writew(SDHCI_MAKE_BLKSZ(7, data->blksz),
+ host->ioaddr + SDHCI_BLOCK_SIZE);
+ writew(data->blocks, host->ioaddr + SDHCI_BLOCK_COUNT);
+}
+
+static void sdhci_set_transfer_mode(struct sdhci_host *host,
+ struct mmc_data *data)
+{
+ u16 mode;
+
+ WARN_ON(host->data);
+
+ if (data == NULL)
+ return;
+
+ mode = SDHCI_TRNS_BLK_CNT_EN;
+ if (data->blocks > 1)
+ mode |= SDHCI_TRNS_MULTI;
+ if (data->flags & MMC_DATA_READ)
+ mode |= SDHCI_TRNS_READ;
+ if (host->flags & SDHCI_USE_DMA)
+ mode |= SDHCI_TRNS_DMA;
+
+ writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE);
}
static void sdhci_finish_data(struct sdhci_host *host)
{
struct mmc_data *data;
- u32 intmask;
u16 blocks;
BUG_ON(!host->data);
@@ -318,14 +454,6 @@ static void sdhci_finish_data(struct sdhci_host *host)
if (host->flags & SDHCI_USE_DMA) {
pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len,
(data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE);
- } else {
- intmask = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
- intmask &= ~(SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL);
- writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-
- intmask = readl(host->ioaddr + SDHCI_INT_ENABLE);
- intmask &= ~(SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL);
- writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
}
/*
@@ -342,9 +470,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
"though there were blocks left. Please report this "
"to " BUGMAIL ".\n", mmc_hostname(host->mmc));
data->error = MMC_ERR_FAILED;
- }
-
- if (host->size != 0) {
+ } else if (host->size != 0) {
printk(KERN_ERR "%s: %d bytes were left untransferred. "
"Please report this to " BUGMAIL ".\n",
mmc_hostname(host->mmc), host->size);
@@ -371,27 +497,38 @@ static void sdhci_finish_data(struct sdhci_host *host)
static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{
int flags;
- u32 present;
- unsigned long max_jiffies;
+ u32 mask;
+ unsigned long timeout;
WARN_ON(host->cmd);
DBG("Sending cmd (%x)\n", cmd->opcode);
/* Wait max 10 ms */
- max_jiffies = jiffies + (HZ + 99)/100;
- do {
- if (time_after(jiffies, max_jiffies)) {
+ timeout = 10;
+
+ mask = SDHCI_CMD_INHIBIT;
+ if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+ mask |= SDHCI_DATA_INHIBIT;
+
+ /* We shouldn't wait for data inihibit for stop commands, even
+ though they might use busy signaling */
+ if (host->mrq->data && (cmd == host->mrq->data->stop))
+ mask &= ~SDHCI_DATA_INHIBIT;
+
+ while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
+ if (timeout == 0) {
printk(KERN_ERR "%s: Controller never released "
- "inhibit bits. Please report this to "
+ "inhibit bit(s). Please report this to "
BUGMAIL ".\n", mmc_hostname(host->mmc));
sdhci_dumpregs(host);
cmd->error = MMC_ERR_FAILED;
tasklet_schedule(&host->finish_tasklet);
return;
}
- present = readl(host->ioaddr + SDHCI_PRESENT_STATE);
- } while (present & (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT));
+ timeout--;
+ mdelay(1);
+ }
mod_timer(&host->timer, jiffies + 10 * HZ);
@@ -401,6 +538,8 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
writel(cmd->arg, host->ioaddr + SDHCI_ARGUMENT);
+ sdhci_set_transfer_mode(host, cmd->data);
+
if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
printk(KERN_ERR "%s: Unsupported response type! "
"Please report this to " BUGMAIL ".\n",
@@ -426,7 +565,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
if (cmd->data)
flags |= SDHCI_CMD_DATA;
- writel(SDHCI_MAKE_CMD(cmd->opcode, flags),
+ writew(SDHCI_MAKE_CMD(cmd->opcode, flags),
host->ioaddr + SDHCI_COMMAND);
}
@@ -456,31 +595,9 @@ static void sdhci_finish_command(struct sdhci_host *host)
DBG("Ending cmd (%x)\n", host->cmd->opcode);
- if (host->cmd->data) {
- u32 intmask;
-
+ if (host->cmd->data)
host->data = host->cmd->data;
-
- if (!(host->flags & SDHCI_USE_DMA)) {
- /*
- * Don't enable the interrupts until now to make sure we
- * get stable handling of the FIFO.
- */
- intmask = readl(host->ioaddr + SDHCI_INT_ENABLE);
- intmask |= SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL;
- writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
-
- intmask = readl(host->ioaddr + SDHCI_SIGNAL_ENABLE);
- intmask |= SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL;
- writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
-
- /*
- * The buffer interrupts are to unreliable so we
- * start the transfer immediatly.
- */
- sdhci_transfer_pio(host);
- }
- } else
+ else
tasklet_schedule(&host->finish_tasklet);
host->cmd = NULL;
@@ -490,7 +607,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
{
int div;
u16 clk;
- unsigned long max_jiffies;
+ unsigned long timeout;
if (clock == host->clock)
return;
@@ -511,17 +628,19 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
/* Wait max 10 ms */
- max_jiffies = jiffies + (HZ + 99)/100;
- do {
- if (time_after(jiffies, max_jiffies)) {
+ timeout = 10;
+ while (!((clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL))
+ & SDHCI_CLOCK_INT_STABLE)) {
+ if (timeout == 0) {
printk(KERN_ERR "%s: Internal clock never stabilised. "
"Please report this to " BUGMAIL ".\n",
mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
- clk = readw(host->ioaddr + SDHCI_CLOCK_CONTROL);
- } while (!(clk & SDHCI_CLOCK_INT_STABLE));
+ timeout--;
+ mdelay(1);
+ }
clk |= SDHCI_CLOCK_CARD_EN;
writew(clk, host->ioaddr + SDHCI_CLOCK_CONTROL);
@@ -530,6 +649,46 @@ out:
host->clock = clock;
}
+static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
+{
+ u8 pwr;
+
+ if (host->power == power)
+ return;
+
+ writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+
+ if (power == (unsigned short)-1)
+ goto out;
+
+ pwr = SDHCI_POWER_ON;
+
+ switch (power) {
+ case MMC_VDD_170:
+ case MMC_VDD_180:
+ case MMC_VDD_190:
+ pwr |= SDHCI_POWER_180;
+ break;
+ case MMC_VDD_290:
+ case MMC_VDD_300:
+ case MMC_VDD_310:
+ pwr |= SDHCI_POWER_300;
+ break;
+ case MMC_VDD_320:
+ case MMC_VDD_330:
+ case MMC_VDD_340:
+ pwr |= SDHCI_POWER_330;
+ break;
+ default:
+ BUG();
+ }
+
+ writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
+
+out:
+ host->power = power;
+}
+
/*****************************************************************************\
* *
* MMC callbacks *
@@ -576,17 +735,15 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/
if (ios->power_mode == MMC_POWER_OFF) {
writel(0, host->ioaddr + SDHCI_SIGNAL_ENABLE);
- spin_unlock_irqrestore(&host->lock, flags);
sdhci_init(host);
- spin_lock_irqsave(&host->lock, flags);
}
sdhci_set_clock(host, ios->clock);
if (ios->power_mode == MMC_POWER_OFF)
- writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
+ sdhci_set_power(host, -1);
else
- writeb(0xFF, host->ioaddr + SDHCI_POWER_CONTROL);
+ sdhci_set_power(host, ios->vdd);
ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
if (ios->bus_width == MMC_BUS_WIDTH_4)
@@ -679,6 +836,19 @@ static void sdhci_tasklet_finish(unsigned long param)
if ((mrq->cmd->error != MMC_ERR_NONE) ||
(mrq->data && ((mrq->data->error != MMC_ERR_NONE) ||
(mrq->data->stop && (mrq->data->stop->error != MMC_ERR_NONE))))) {
+
+ /* Some controllers need this kick or reset won't work here */
+ if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) {
+ unsigned int clock;
+
+ /* This is to force an update */
+ clock = host->clock;
+ host->clock = 0;
+ sdhci_set_clock(host, clock);
+ }
+
+ /* Spec says we should do both at the same time, but Ricoh
+ controllers do not like that. */
sdhci_reset(host, SDHCI_RESET_CMD);
sdhci_reset(host, SDHCI_RESET_DATA);
}
@@ -793,7 +963,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
if (host->data->error != MMC_ERR_NONE)
sdhci_finish_data(host);
else {
- if (intmask & (SDHCI_INT_BUF_FULL | SDHCI_INT_BUF_EMPTY))
+ if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
sdhci_transfer_pio(host);
if (intmask & SDHCI_INT_DATA_END)
@@ -818,50 +988,44 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
DBG("*** %s got interrupt: 0x%08x\n", host->slot_descr, intmask);
- if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE))
+ if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+ writel(intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE),
+ host->ioaddr + SDHCI_INT_STATUS);
tasklet_schedule(&host->card_tasklet);
+ }
- if (intmask & SDHCI_INT_CMD_MASK) {
- sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
+ intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
+ if (intmask & SDHCI_INT_CMD_MASK) {
writel(intmask & SDHCI_INT_CMD_MASK,
host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
}
if (intmask & SDHCI_INT_DATA_MASK) {
- sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-
writel(intmask & SDHCI_INT_DATA_MASK,
host->ioaddr + SDHCI_INT_STATUS);
+ sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
}
intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
- if (intmask & SDHCI_INT_CARD_INT) {
- printk(KERN_ERR "%s: Unexpected card interrupt. Please "
- "report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
- }
-
if (intmask & SDHCI_INT_BUS_POWER) {
- printk(KERN_ERR "%s: Unexpected bus power interrupt. Please "
- "report this to " BUGMAIL ".\n",
+ printk(KERN_ERR "%s: Card is consuming too much power!\n",
mmc_hostname(host->mmc));
- sdhci_dumpregs(host);
+ writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
}
- if (intmask & SDHCI_INT_ACMD12ERR) {
- printk(KERN_ERR "%s: Unexpected auto CMD12 error. Please "
+ intmask &= SDHCI_INT_BUS_POWER;
+
+ if (intmask) {
+ printk(KERN_ERR "%s: Unexpected interrupt 0x%08x. Please "
"report this to " BUGMAIL ".\n",
- mmc_hostname(host->mmc));
+ mmc_hostname(host->mmc), intmask);
sdhci_dumpregs(host);
- writew(~0, host->ioaddr + SDHCI_ACMD12_ERR);
- }
-
- if (intmask)
writel(intmask, host->ioaddr + SDHCI_INT_STATUS);
+ }
result = IRQ_HANDLED;
@@ -954,6 +1118,7 @@ static int sdhci_resume (struct pci_dev *pdev)
static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
{
int ret;
+ unsigned int version;
struct sdhci_chip *chip;
struct mmc_host *mmc;
struct sdhci_host *host;
@@ -985,6 +1150,16 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
return -ENODEV;
}
+ if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+ printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
+ return -ENODEV;
+ }
+
+ if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
+ printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
+ return -ENODEV;
+ }
+
mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
if (!mmc)
return -ENOMEM;
@@ -1012,9 +1187,30 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
goto release;
}
+ sdhci_reset(host, SDHCI_RESET_ALL);
+
+ version = readw(host->ioaddr + SDHCI_HOST_VERSION);
+ version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+ if (version != 0) {
+ printk(KERN_ERR "%s: Unknown controller version (%d). "
+ "You may experience problems.\n", host->slot_descr,
+ version);
+ }
+
caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
- if ((caps & SDHCI_CAN_DO_DMA) && ((pdev->class & 0x0000FF) == 0x01))
+ if (debug_nodma)
+ DBG("DMA forced off\n");
+ else if (debug_forcedma) {
+ DBG("DMA forced on\n");
+ host->flags |= SDHCI_USE_DMA;
+ } else if (chip->quirks & SDHCI_QUIRK_FORCE_DMA)
+ host->flags |= SDHCI_USE_DMA;
+ else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
+ DBG("Controller doesn't have DMA interface\n");
+ else if (!(caps & SDHCI_CAN_DO_DMA))
+ DBG("Controller doesn't have DMA capability\n");
+ else
host->flags |= SDHCI_USE_DMA;
if (host->flags & SDHCI_USE_DMA) {
@@ -1030,17 +1226,58 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
else /* XXX: Hack to get MMC layer to avoid highmem */
pdev->dma_mask = 0;
- host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+ host->max_clk =
+ (caps & SDHCI_CLOCK_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT;
+ if (host->max_clk == 0) {
+ printk(KERN_ERR "%s: Hardware doesn't specify base clock "
+ "frequency.\n", host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
host->max_clk *= 1000000;
+ host->timeout_clk =
+ (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
+ if (host->timeout_clk == 0) {
+ printk(KERN_ERR "%s: Hardware doesn't specify timeout clock "
+ "frequency.\n", host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
+ if (caps & SDHCI_TIMEOUT_CLK_UNIT)
+ host->timeout_clk *= 1000;
+
+ host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+ if (host->max_block >= 3) {
+ printk(KERN_ERR "%s: Invalid maximum block size.\n",
+ host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
+ host->max_block = 512 << host->max_block;
+
/*
* Set host parameters.
*/
mmc->ops = &sdhci_ops;
mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
- mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
+
+ mmc->ocr_avail = 0;
+ if (caps & SDHCI_CAN_VDD_330)
+ mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
+ else if (caps & SDHCI_CAN_VDD_300)
+ mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
+ else if (caps & SDHCI_CAN_VDD_180)
+ mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
+
+ if (mmc->ocr_avail == 0) {
+ printk(KERN_ERR "%s: Hardware doesn't report any "
+ "support voltages.\n", host->slot_descr);
+ ret = -ENODEV;
+ goto unmap;
+ }
spin_lock_init(&host->lock);
@@ -1054,10 +1291,10 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->max_phys_segs = 16;
/*
- * Maximum number of sectors in one transfer. Limited by sector
- * count register.
+ * Maximum number of sectors in one transfer. Limited by DMA boundary
+ * size (512KiB), which means (512 KiB/512=) 1024 entries.
*/
- mmc->max_sectors = 0x3FFF;
+ mmc->max_sectors = 1024;
/*
* Maximum segment size. Could be one segment with the maximum number
@@ -1075,10 +1312,10 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
- ret = request_irq(host->irq, sdhci_irq, SA_SHIRQ,
+ ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
host->slot_descr, host);
if (ret)
- goto unmap;
+ goto untasklet;
sdhci_init(host);
@@ -1097,10 +1334,10 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
return 0;
-unmap:
+untasklet:
tasklet_kill(&host->card_tasklet);
tasklet_kill(&host->finish_tasklet);
-
+unmap:
iounmap(host->ioaddr);
release:
pci_release_region(pdev, host->bar);
@@ -1144,13 +1381,18 @@ static int __devinit sdhci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int ret, i;
- u8 slots;
+ u8 slots, rev;
struct sdhci_chip *chip;
BUG_ON(pdev == NULL);
BUG_ON(ent == NULL);
- DBG("found at %s\n", pci_name(pdev));
+ pci_read_config_byte(pdev, PCI_CLASS_REVISION, &rev);
+
+ printk(KERN_INFO DRIVER_NAME
+ ": SDHCI controller found at %s [%04x:%04x] (rev %x)\n",
+ pci_name(pdev), (int)pdev->vendor, (int)pdev->device,
+ (int)rev);
ret = pci_read_config_byte(pdev, PCI_SLOT_INFO, &slots);
if (ret)
@@ -1173,6 +1415,10 @@ static int __devinit sdhci_probe(struct pci_dev *pdev,
}
chip->pdev = pdev;
+ chip->quirks = ent->driver_data;
+
+ if (debug_quirks)
+ chip->quirks = debug_quirks;
chip->num_slots = slots;
pci_set_drvdata(pdev, chip);
@@ -1251,7 +1497,15 @@ static void __exit sdhci_drv_exit(void)
module_init(sdhci_drv_init);
module_exit(sdhci_drv_exit);
+module_param(debug_nodma, uint, 0444);
+module_param(debug_forcedma, uint, 0444);
+module_param(debug_quirks, uint, 0444);
+
MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
+
+MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index 3b270ef486b..f2453343f78 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -12,6 +12,10 @@
* PCI registers
*/
+#define PCI_SDHCI_IFPIO 0x00
+#define PCI_SDHCI_IFDMA 0x01
+#define PCI_SDHCI_IFVENDOR 0x02
+
#define PCI_SLOT_INFO 0x40 /* 8 bits */
#define PCI_SLOT_INFO_SLOTS(x) ((x >> 4) & 7)
#define PCI_SLOT_INFO_FIRST_BAR_MASK 0x07
@@ -23,6 +27,7 @@
#define SDHCI_DMA_ADDRESS 0x00
#define SDHCI_BLOCK_SIZE 0x04
+#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
#define SDHCI_BLOCK_COUNT 0x06
@@ -67,6 +72,10 @@
#define SDHCI_CTRL_4BITBUS 0x02
#define SDHCI_POWER_CONTROL 0x29
+#define SDHCI_POWER_ON 0x01
+#define SDHCI_POWER_180 0x0A
+#define SDHCI_POWER_300 0x0C
+#define SDHCI_POWER_330 0x0E
#define SDHCI_BLOCK_GAP_CONTROL 0x2A
@@ -91,8 +100,8 @@
#define SDHCI_INT_RESPONSE 0x00000001
#define SDHCI_INT_DATA_END 0x00000002
#define SDHCI_INT_DMA_END 0x00000008
-#define SDHCI_INT_BUF_EMPTY 0x00000010
-#define SDHCI_INT_BUF_FULL 0x00000020
+#define SDHCI_INT_SPACE_AVAIL 0x00000010
+#define SDHCI_INT_DATA_AVAIL 0x00000020
#define SDHCI_INT_CARD_INSERT 0x00000040
#define SDHCI_INT_CARD_REMOVE 0x00000080
#define SDHCI_INT_CARD_INT 0x00000100
@@ -112,7 +121,7 @@
#define SDHCI_INT_CMD_MASK (SDHCI_INT_RESPONSE | SDHCI_INT_TIMEOUT | \
SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)
#define SDHCI_INT_DATA_MASK (SDHCI_INT_DATA_END | SDHCI_INT_DMA_END | \
- SDHCI_INT_BUF_EMPTY | SDHCI_INT_BUF_FULL | \
+ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \
SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \
SDHCI_INT_DATA_END_BIT)
@@ -121,9 +130,17 @@
/* 3E-3F reserved */
#define SDHCI_CAPABILITIES 0x40
-#define SDHCI_CAN_DO_DMA 0x00400000
+#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
+#define SDHCI_TIMEOUT_CLK_SHIFT 0
+#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
#define SDHCI_CLOCK_BASE_MASK 0x00003F00
#define SDHCI_CLOCK_BASE_SHIFT 8
+#define SDHCI_MAX_BLOCK_MASK 0x00030000
+#define SDHCI_MAX_BLOCK_SHIFT 16
+#define SDHCI_CAN_DO_DMA 0x00400000
+#define SDHCI_CAN_VDD_330 0x01000000
+#define SDHCI_CAN_VDD_300 0x02000000
+#define SDHCI_CAN_VDD_180 0x04000000
/* 44-47 reserved for more caps */
@@ -136,6 +153,10 @@
#define SDHCI_SLOT_INT_STATUS 0xFC
#define SDHCI_HOST_VERSION 0xFE
+#define SDHCI_VENDOR_VER_MASK 0xFF00
+#define SDHCI_VENDOR_VER_SHIFT 8
+#define SDHCI_SPEC_VER_MASK 0x00FF
+#define SDHCI_SPEC_VER_SHIFT 0
struct sdhci_chip;
@@ -149,8 +170,11 @@ struct sdhci_host {
#define SDHCI_USE_DMA (1<<0)
unsigned int max_clk; /* Max possible freq (MHz) */
+ unsigned int timeout_clk; /* Timeout freq (KHz) */
+ unsigned int max_block; /* Max block size (bytes) */
unsigned int clock; /* Current clock (MHz) */
+ unsigned short power; /* Current voltage */
struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */
@@ -180,6 +204,8 @@ struct sdhci_host {
struct sdhci_chip {
struct pci_dev *pdev;
+ unsigned long quirks;
+
int num_slots; /* Slots on controller */
struct sdhci_host *hosts[0]; /* Pointers to hosts */
};
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index 8167332d401..6435a6822ad 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -21,7 +21,6 @@
* - On APIC systems the FIFO empty interrupt is sometimes lost.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -42,7 +41,7 @@
#include "wbsd.h"
#define DRIVER_NAME "wbsd"
-#define DRIVER_VERSION "1.5"
+#define DRIVER_VERSION "1.6"
#define DBG(x...) \
pr_debug(DRIVER_NAME ": " x)
@@ -1324,7 +1323,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
spin_lock_init(&host->lock);
@@ -1440,13 +1439,13 @@ static int __devinit wbsd_scan(struct wbsd_host *host)
static int __devinit wbsd_request_region(struct wbsd_host *host, int base)
{
- if (io & 0x7)
+ if (base & 0x7)
return -EINVAL;
if (!request_region(base, 8, DRIVER_NAME))
return -EIO;
- host->base = io;
+ host->base = base;
return 0;
}
@@ -1554,7 +1553,7 @@ static int __devinit wbsd_request_irq(struct wbsd_host *host, int irq)
* Allocate interrupt.
*/
- ret = request_irq(irq, wbsd_irq, SA_SHIRQ, DRIVER_NAME, host);
+ ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
if (ret)
return ret;
@@ -1774,7 +1773,7 @@ static int __devinit wbsd_init(struct device *dev, int base, int irq, int dma,
/*
* Request resources.
*/
- ret = wbsd_request_resources(host, io, irq, dma);
+ ret = wbsd_request_resources(host, base, irq, dma);
if (ret) {
wbsd_release_resources(host);
wbsd_free_mmc(dev);
@@ -1862,6 +1861,7 @@ static void __devexit wbsd_shutdown(struct device *dev, int pnp)
static int __devinit wbsd_probe(struct platform_device *dev)
{
+ /* Use the module parameters for resources */
return wbsd_init(&dev->dev, io, irq, dma, 0);
}
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 5ac265dde42..a03e862851d 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -86,14 +86,14 @@ config MTD_REDBOOT_DIRECTORY_BLOCK
block and "-2" means the penultimate block.
config MTD_REDBOOT_PARTS_UNALLOCATED
- bool " Include unallocated flash regions"
+ bool "Include unallocated flash regions"
depends on MTD_REDBOOT_PARTS
help
If you need to register each unallocated flash region as a MTD
'partition', enable this option.
config MTD_REDBOOT_PARTS_READONLY
- bool " Force read-only for RedBoot system images"
+ bool "Force read-only for RedBoot system images"
depends on MTD_REDBOOT_PARTS
help
If you need to force read-only for 'RedBoot', 'RedBoot Config' and
@@ -101,7 +101,7 @@ config MTD_REDBOOT_PARTS_READONLY
config MTD_CMDLINE_PARTS
bool "Command line partition table parsing"
- depends on MTD_PARTITIONS = "y"
+ depends on MTD_PARTITIONS = "y" && MTD = "y"
---help---
Allow generic configuration of the MTD partition tables via the kernel
command line. Multiple flash resources are supported for hardware where
@@ -263,6 +263,14 @@ config RFD_FTL
http://www.gensw.com/pages/prod/bios/rfd.htm
+config SSFDC
+ tristate "NAND SSFDC (SmartMedia) read only translation layer"
+ depends on MTD
+ default n
+ help
+ This enables read only access to SmartMedia formatted NAND
+ flash. You can mount it with FAT file system.
+
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index fc9374407c2..1e36b9aed98 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o
+obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 0d435814aaa..7ea49a0d5ec 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -357,6 +357,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
mtd->resume = cfi_intelext_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
+ mtd->writesize = 1;
mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
@@ -907,7 +908,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
static int __xipram xip_wait_for_operation(
struct map_info *map, struct flchip *chip,
- unsigned long adr, int *chip_op_time )
+ unsigned long adr, unsigned int chip_op_time )
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
@@ -916,7 +917,7 @@ static int __xipram xip_wait_for_operation(
flstate_t oldstate, newstate;
start = xip_currtime();
- usec = *chip_op_time * 8;
+ usec = chip_op_time * 8;
if (usec == 0)
usec = 500000;
done = 0;
@@ -1026,8 +1027,8 @@ static int __xipram xip_wait_for_operation(
#define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
-#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, p_usec) \
- xip_wait_for_operation(map, chip, cmd_adr, p_usec)
+#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
+ xip_wait_for_operation(map, chip, cmd_adr, usec)
#else
@@ -1039,64 +1040,64 @@ static int __xipram xip_wait_for_operation(
static int inval_cache_and_wait_for_operation(
struct map_info *map, struct flchip *chip,
unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
- int *chip_op_time )
+ unsigned int chip_op_time)
{
struct cfi_private *cfi = map->fldrv_priv;
map_word status, status_OK = CMD(0x80);
- int z, chip_state = chip->state;
- unsigned long timeo;
+ int chip_state = chip->state;
+ unsigned int timeo, sleep_time;
spin_unlock(chip->mutex);
if (inval_len)
INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
- if (*chip_op_time)
- cfi_udelay(*chip_op_time);
spin_lock(chip->mutex);
- timeo = *chip_op_time * 8 * HZ / 1000000;
- if (timeo < HZ/2)
- timeo = HZ/2;
- timeo += jiffies;
+ /* set our timeout to 8 times the expected delay */
+ timeo = chip_op_time * 8;
+ if (!timeo)
+ timeo = 500000;
+ sleep_time = chip_op_time / 2;
- z = 0;
for (;;) {
- if (chip->state != chip_state) {
- /* Someone's suspended the operation: sleep */
- DECLARE_WAITQUEUE(wait, current);
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
- timeo = jiffies + (HZ / 2); /* FIXME */
- spin_lock(chip->mutex);
- continue;
- }
-
status = map_read(map, cmd_adr);
if (map_word_andequal(map, status, status_OK, status_OK))
break;
- /* OK Still waiting */
- if (time_after(jiffies, timeo)) {
+ if (!timeo) {
map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
return -ETIME;
}
- /* Latency issues. Drop the lock, wait a while and retry */
- z++;
+ /* OK Still waiting. Drop the lock, wait a while and retry. */
spin_unlock(chip->mutex);
- cfi_udelay(1);
+ if (sleep_time >= 1000000/HZ) {
+ /*
+ * Half of the normal delay still remaining
+ * can be performed with a sleeping delay instead
+ * of busy waiting.
+ */
+ msleep(sleep_time/1000);
+ timeo -= sleep_time;
+ sleep_time = 1000000/HZ;
+ } else {
+ udelay(1);
+ cond_resched();
+ timeo--;
+ }
spin_lock(chip->mutex);
- }
- if (!z) {
- if (!--(*chip_op_time))
- *chip_op_time = 1;
- } else if (z > 1)
- ++(*chip_op_time);
+ if (chip->state != chip_state) {
+ /* Someone's suspended the operation: sleep */
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ spin_lock(chip->mutex);
+ }
+ }
/* Done and happy. */
chip->state = FL_STATUS;
@@ -1106,8 +1107,7 @@ static int inval_cache_and_wait_for_operation(
#endif
#define WAIT_TIMEOUT(map, chip, adr, udelay) \
- ({ int __udelay = (udelay); \
- INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, &__udelay); })
+ INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1331,7 +1331,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, map_bankwidth(map),
- &chip->word_write_time);
+ chip->word_write_time);
if (ret) {
xip_enable(map, chip, adr);
printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
@@ -1568,7 +1568,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
adr, len,
- &chip->buffer_write_time);
+ chip->buffer_write_time);
if (ret) {
map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS;
@@ -1703,7 +1703,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, len,
- &chip->erase_time);
+ chip->erase_time);
if (ret) {
map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index 1e01ad38b26..702ae4cd869 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -21,7 +21,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -46,9 +45,11 @@
#define MAX_WORD_RETRIES 3
#define MANUFACTURER_AMD 0x0001
+#define MANUFACTURER_ATMEL 0x001F
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
#define SST49LF008A 0x005a
+#define AT49BV6416 0x00d6
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -69,6 +70,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr);
#include "fwh_lock.h"
+static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
+static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+
static struct mtd_chip_driver cfi_amdstd_chipdrv = {
.probe = NULL, /* Not usable directly */
.destroy = cfi_amdstd_destroy,
@@ -162,6 +166,26 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
}
}
+/* Atmel chips don't use the same PRI format as AMD chips */
+static void fixup_convert_atmel_pri(struct mtd_info *mtd, void *param)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+ struct cfi_pri_atmel atmel_pri;
+
+ memcpy(&atmel_pri, extp, sizeof(atmel_pri));
+ memset((char *)extp + 5, 0, sizeof(*extp) - 5);
+
+ if (atmel_pri.Features & 0x02)
+ extp->EraseSuspend = 2;
+
+ if (atmel_pri.BottomBoot)
+ extp->TopBottom = 2;
+ else
+ extp->TopBottom = 3;
+}
+
static void fixup_use_secsi(struct mtd_info *mtd, void *param)
{
/* Setup for chips with a secsi area */
@@ -180,6 +204,17 @@ static void fixup_use_erase_chip(struct mtd_info *mtd, void *param)
}
+/*
+ * Some Atmel chips (e.g. the AT49BV6416) power-up with all sectors
+ * locked by default.
+ */
+static void fixup_use_atmel_lock(struct mtd_info *mtd, void *param)
+{
+ mtd->lock = cfi_atmel_lock;
+ mtd->unlock = cfi_atmel_unlock;
+ mtd->flags |= MTD_STUPID_LOCK;
+}
+
static struct cfi_fixup cfi_fixup_table[] = {
#ifdef AMD_BOOTLOC_BUG
{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock, NULL },
@@ -193,6 +228,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
#if !FORCE_WORD_WRITE
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers, NULL, },
#endif
+ { CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri, NULL },
{ 0, 0, NULL, NULL }
};
static struct cfi_fixup jedec_fixup_table[] = {
@@ -208,6 +244,7 @@ static struct cfi_fixup fixup_table[] = {
* we know that is the case.
*/
{ CFI_MFR_ANY, CFI_ID_ANY, fixup_use_erase_chip, NULL },
+ { CFI_MFR_ATMEL, AT49BV6416, fixup_use_atmel_lock, NULL },
{ 0, 0, NULL, NULL }
};
@@ -1608,6 +1645,80 @@ static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr)
return 0;
}
+static int do_atmel_lock(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int len, void *thunk)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ret;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr + chip->start, FL_LOCKING);
+ if (ret)
+ goto out_unlock;
+ chip->state = FL_LOCKING;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n",
+ __func__, adr, len);
+
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ map_write(map, CMD(0x40), chip->start + adr);
+
+ chip->state = FL_READY;
+ put_chip(map, chip, adr + chip->start);
+ ret = 0;
+
+out_unlock:
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+static int do_atmel_unlock(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int len, void *thunk)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ret;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, adr + chip->start, FL_UNLOCKING);
+ if (ret)
+ goto out_unlock;
+ chip->state = FL_UNLOCKING;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n",
+ __func__, adr, len);
+
+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi,
+ cfi->device_type, NULL);
+ map_write(map, CMD(0x70), adr);
+
+ chip->state = FL_READY;
+ put_chip(map, chip, adr + chip->start);
+ ret = 0;
+
+out_unlock:
+ spin_unlock(chip->mutex);
+ return ret;
+}
+
+static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL);
+}
+
+static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL);
+}
+
static void cfi_amdstd_sync (struct mtd_info *mtd)
{
diff --git a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c
index 4bf9f8cac0d..60e11a0ada9 100644
--- a/drivers/mtd/chips/cfi_probe.c
+++ b/drivers/mtd/chips/cfi_probe.c
@@ -4,7 +4,6 @@
$Id: cfi_probe.c,v 1.86 2005/11/29 14:48:31 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c
index c2127840a18..2174c97549f 100644
--- a/drivers/mtd/chips/chipreg.c
+++ b/drivers/mtd/chips/chipreg.c
@@ -6,7 +6,6 @@
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/spinlock.h>
diff --git a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c
index c40b48dabed..2c3f019197c 100644
--- a/drivers/mtd/chips/jedec.c
+++ b/drivers/mtd/chips/jedec.c
@@ -256,6 +256,7 @@ static struct mtd_info *jedec_probe(struct map_info *map)
MTD->name = map->name;
MTD->type = MTD_NORFLASH;
MTD->flags = MTD_CAP_NORFLASH;
+ MTD->writesize = 1;
MTD->erasesize = SectorSize*(map->buswidth);
// printk("MTD->erasesize is %x\n",(unsigned int)MTD->erasesize);
MTD->size = priv->size;
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 517ea33e726..1154dac715a 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -8,7 +8,6 @@
Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -112,6 +111,7 @@
#define MX29LV040C 0x004F
#define MX29LV160T 0x22C4
#define MX29LV160B 0x2249
+#define MX29F040 0x00A4
#define MX29F016 0x00AD
#define MX29F002T 0x00B0
#define MX29F004T 0x0045
@@ -1173,6 +1173,19 @@ static const struct amd_flash_info jedec_table[] = {
}
}, {
.mfr_id = MANUFACTURER_MACRONIX,
+ .dev_id = MX29F040,
+ .name = "Macronix MX29F040",
+ .uaddr = {
+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */
+ },
+ .DevSize = SIZE_512KiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 1,
+ .regions = {
+ ERASEINFO(0x10000,8),
+ }
+ }, {
+ .mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29F016,
.name = "Macronix MX29F016",
.uaddr = {
diff --git a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c
index a611de9b151..ac01a949b68 100644
--- a/drivers/mtd/chips/map_absent.c
+++ b/drivers/mtd/chips/map_absent.c
@@ -64,7 +64,8 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
mtd->write = map_absent_write;
mtd->sync = map_absent_sync;
mtd->flags = 0;
- mtd->erasesize = PAGE_SIZE;
+ mtd->erasesize = PAGE_SIZE;
+ mtd->writesize = 1;
__module_get(THIS_MODULE);
return mtd;
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 763925747db..3a66680abfd 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -71,6 +71,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->write = mapram_write;
mtd->sync = mapram_nop;
mtd->flags = MTD_CAP_RAM;
+ mtd->writesize = 1;
mtd->erasesize = PAGE_SIZE;
while(mtd->size & (mtd->erasesize - 1))
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index bc6ee9ef8a3..1b328b1378f 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -47,6 +47,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->sync = maprom_nop;
mtd->flags = MTD_CAP_ROM;
mtd->erasesize = map->size;
+ mtd->writesize = 1;
__module_get(THIS_MODULE);
return mtd;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index 0d98c223c5f..401c6a294ba 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -8,7 +8,6 @@
*
* Licence: GPL
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
@@ -19,6 +18,7 @@
#include <linux/mtd/mtd.h>
#include <linux/buffer_head.h>
#include <linux/mutex.h>
+#include <linux/mount.h>
#define VERSION "$Revision: 1.30 $"
@@ -237,6 +237,8 @@ static int _block2mtd_write(struct block2mtd_dev *dev, const u_char *buf,
}
return 0;
}
+
+
static int block2mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -300,6 +302,19 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
/* Get a handle on the device */
bdev = open_bdev_excl(devname, O_RDWR, NULL);
+#ifndef MODULE
+ if (IS_ERR(bdev)) {
+
+ /* We might not have rootfs mounted at this point. Try
+ to resolve the device name by other means. */
+
+ dev_t dev = name_to_dev_t(devname);
+ if (dev != 0) {
+ bdev = open_by_devnum(dev, FMODE_WRITE | FMODE_READ);
+ }
+ }
+#endif
+
if (IS_ERR(bdev)) {
ERROR("error: cannot open device %s", devname);
goto devinit_err;
@@ -324,6 +339,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
dev->mtd.erasesize = erase_size;
+ dev->mtd.writesize = 1;
dev->mtd.type = MTD_RAM;
dev->mtd.flags = MTD_CAP_RAM;
dev->mtd.erase = block2mtd_erase;
@@ -393,26 +409,6 @@ static int parse_num(size_t *num, const char *token)
}
-static int parse_name(char **pname, const char *token, size_t limit)
-{
- size_t len;
- char *name;
-
- len = strlen(token) + 1;
- if (len > limit)
- return -ENOSPC;
-
- name = kmalloc(len, GFP_KERNEL);
- if (!name)
- return -ENOMEM;
-
- strcpy(name, token);
-
- *pname = name;
- return 0;
-}
-
-
static inline void kill_final_newline(char *str)
{
char *newline = strrchr(str, '\n');
@@ -426,9 +422,15 @@ static inline void kill_final_newline(char *str)
return 0; \
} while (0)
-static int block2mtd_setup(const char *val, struct kernel_param *kp)
+#ifndef MODULE
+static int block2mtd_init_called = 0;
+static __initdata char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
+#endif
+
+
+static int block2mtd_setup2(const char *val)
{
- char buf[80+12]; /* 80 for device, 12 for erase size */
+ char buf[80 + 12]; /* 80 for device, 12 for erase size */
char *str = buf;
char *token[2];
char *name;
@@ -450,13 +452,9 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
if (!token[0])
parse_err("no argument");
- ret = parse_name(&name, token[0], 80);
- if (ret == -ENOMEM)
- parse_err("out of memory");
- if (ret == -ENOSPC)
- parse_err("name too long");
- if (ret)
- return 0;
+ name = token[0];
+ if (strlen(name) + 1 > 80)
+ parse_err("device name too long");
if (token[1]) {
ret = parse_num(&erase_size, token[1]);
@@ -472,13 +470,48 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
}
+static int block2mtd_setup(const char *val, struct kernel_param *kp)
+{
+#ifdef MODULE
+ return block2mtd_setup2(val);
+#else
+ /* If more parameters are later passed in via
+ /sys/module/block2mtd/parameters/block2mtd
+ and block2mtd_init() has already been called,
+ we can parse the argument now. */
+
+ if (block2mtd_init_called)
+ return block2mtd_setup2(val);
+
+ /* During early boot stage, we only save the parameters
+ here. We must parse them later: if the param passed
+ from kernel boot command line, block2mtd_setup() is
+ called so early that it is not possible to resolve
+ the device (even kmalloc() fails). Deter that work to
+ block2mtd_setup2(). */
+
+ strlcpy(block2mtd_paramline, val, sizeof(block2mtd_paramline));
+
+ return 0;
+#endif
+}
+
+
module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
static int __init block2mtd_init(void)
{
+ int ret = 0;
INFO("version " VERSION);
- return 0;
+
+#ifndef MODULE
+ if (strlen(block2mtd_paramline))
+ ret = block2mtd_setup2(block2mtd_paramline);
+ block2mtd_init_called = 1;
+#endif
+
+ return ret;
}
diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c
index c54e40464d8..603a7951ac9 100644
--- a/drivers/mtd/devices/doc2000.c
+++ b/drivers/mtd/devices/doc2000.c
@@ -55,10 +55,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@@ -615,17 +611,10 @@ EXPORT_SYMBOL_GPL(DoC2k_init);
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf)
{
- /* Just a special case of doc_read_ecc */
- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel)
-{
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip;
- unsigned char syndrome[6];
+ unsigned char syndrome[6], eccbuf[6];
volatile char dummy;
int i, len256 = 0, ret=0;
size_t left = len;
@@ -673,15 +662,9 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP,
CDSN_CTRL_ECC_IO);
- if (eccbuf) {
- /* Prime the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_EN, docptr, ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
- }
+ /* Prime the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_EN, docptr, ECCConf);
/* treat crossing 256-byte sector for 2M x 8bits devices */
if (this->page256 && from + len > (from | 0xff) + 1) {
@@ -698,58 +681,59 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
/* Let the caller know we completed it */
*retlen += len;
- if (eccbuf) {
- /* Read the ECC data through the DiskOnChip ECC logic */
- /* Note: this will work even with 2M x 8bit devices as */
- /* they have 8 bytes of OOB per 256 page. mf. */
- DoC_ReadBuf(this, eccbuf, 6);
-
- /* Flush the pipeline */
- if (DoC_is_Millennium(this)) {
- dummy = ReadDOC(docptr, ECCConf);
- dummy = ReadDOC(docptr, ECCConf);
- i = ReadDOC(docptr, ECCConf);
- } else {
- dummy = ReadDOC(docptr, 2k_ECCStatus);
- dummy = ReadDOC(docptr, 2k_ECCStatus);
- i = ReadDOC(docptr, 2k_ECCStatus);
- }
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ /* Note: this will work even with 2M x 8bit devices as */
+ /* they have 8 bytes of OOB per 256 page. mf. */
+ DoC_ReadBuf(this, eccbuf, 6);
- /* Check the ECC Status */
- if (i & 0x80) {
- int nb_errors;
- /* There was an ECC error */
+ /* Flush the pipeline */
+ if (DoC_is_Millennium(this)) {
+ dummy = ReadDOC(docptr, ECCConf);
+ dummy = ReadDOC(docptr, ECCConf);
+ i = ReadDOC(docptr, ECCConf);
+ } else {
+ dummy = ReadDOC(docptr, 2k_ECCStatus);
+ dummy = ReadDOC(docptr, 2k_ECCStatus);
+ i = ReadDOC(docptr, 2k_ECCStatus);
+ }
+
+ /* Check the ECC Status */
+ if (i & 0x80) {
+ int nb_errors;
+ /* There was an ECC error */
#ifdef ECC_DEBUG
- printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
+ printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif
- /* Read the ECC syndrom through the DiskOnChip ECC logic.
- These syndrome will be all ZERO when there is no error */
- for (i = 0; i < 6; i++) {
- syndrome[i] =
- ReadDOC(docptr, ECCSyndrome0 + i);
- }
- nb_errors = doc_decode_ecc(buf, syndrome);
+ /* Read the ECC syndrom through the DiskOnChip ECC
+ logic. These syndrome will be all ZERO when there
+ is no error */
+ for (i = 0; i < 6; i++) {
+ syndrome[i] =
+ ReadDOC(docptr, ECCSyndrome0 + i);
+ }
+ nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
- printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
+ printk(KERN_ERR "Errors corrected: %x\n", nb_errors);
#endif
- if (nb_errors < 0) {
- /* We return error, but have actually done the read. Not that
- this can be told to user-space, via sys_read(), but at least
- MTD-aware stuff can know about it by checking *retlen */
- ret = -EIO;
- }
+ if (nb_errors < 0) {
+ /* We return error, but have actually done the
+ read. Not that this can be told to
+ user-space, via sys_read(), but at least
+ MTD-aware stuff can know about it by
+ checking *retlen */
+ ret = -EIO;
}
+ }
#ifdef PSYCHO_DEBUG
- printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
- eccbuf[3], eccbuf[4], eccbuf[5]);
+ printk(KERN_DEBUG "ECC DATA at %lxB: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2],
+ eccbuf[3], eccbuf[4], eccbuf[5]);
#endif
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
- }
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
/* according to 11.4.1, we need to wait for the busy line
* drop if we read to the end of the page. */
@@ -771,17 +755,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t * retlen, const u_char * buf)
{
- char eccbuf[6];
- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t * retlen, const u_char * buf,
- u_char * eccbuf, struct nand_oobinfo *oobsel)
-{
struct DiskOnChip *this = mtd->priv;
int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */
void __iomem *docptr = this->virtadr;
+ unsigned char eccbuf[6];
volatile char dummy;
int len256 = 0;
struct Nand *mychip;
@@ -835,15 +812,9 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
DoC_Command(this, NAND_CMD_SEQIN, 0);
DoC_Address(this, ADDR_COLUMN_PAGE, to, 0, CDSN_CTRL_ECC_IO);
- if (eccbuf) {
- /* Prime the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
- }
+ /* Prime the ECC engine */
+ WriteDOC(DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
/* treat crossing 256-byte sector for 2M x 8bits devices */
if (this->page256 && to + len > (to | 0xff) + 1) {
@@ -873,39 +844,35 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
DoC_WriteBuf(this, &buf[len256], len - len256);
- if (eccbuf) {
- WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr,
- CDSNControl);
-
- if (DoC_is_Millennium(this)) {
- WriteDOC(0, docptr, NOP);
- WriteDOC(0, docptr, NOP);
- WriteDOC(0, docptr, NOP);
- } else {
- WriteDOC_(0, docptr, this->ioreg);
- WriteDOC_(0, docptr, this->ioreg);
- WriteDOC_(0, docptr, this->ioreg);
- }
+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_CE, docptr, CDSNControl);
- WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
- CDSNControl);
+ if (DoC_is_Millennium(this)) {
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ } else {
+ WriteDOC_(0, docptr, this->ioreg);
+ WriteDOC_(0, docptr, this->ioreg);
+ WriteDOC_(0, docptr, this->ioreg);
+ }
- /* Read the ECC data through the DiskOnChip ECC logic */
- for (di = 0; di < 6; di++) {
- eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
- }
+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr,
+ CDSNControl);
- /* Reset the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (di = 0; di < 6; di++) {
+ eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di);
+ }
+
+ /* Reset the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr, ECCConf);
#ifdef PSYCHO_DEBUG
- printk
- ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
+ printk
+ ("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
#endif
- }
-
DoC_Command(this, NAND_CMD_PAGEPROG, 0);
DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP);
diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c
index 0cf022a69e6..0e2a9326f71 100644
--- a/drivers/mtd/devices/doc2001.c
+++ b/drivers/mtd/devices/doc2001.c
@@ -37,12 +37,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@@ -397,17 +391,9 @@ EXPORT_SYMBOL_GPL(DoCMil_init);
static int doc_read (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- /* Just a special case of doc_read_ecc */
- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel)
-{
int i, ret;
volatile char dummy;
- unsigned char syndrome[6];
+ unsigned char syndrome[6], eccbuf[6];
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -437,15 +423,9 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
DoC_Address(docptr, 3, from, CDSN_CTRL_WP, 0x00);
DoC_WaitReady(docptr);
- if (eccbuf) {
- /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
- WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC (DOC_ECC_EN, docptr, ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
- }
+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+ WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC (DOC_ECC_EN, docptr, ECCConf);
/* Read the data via the internal pipeline through CDSN IO register,
see Pipelined Read Operations 11.3 */
@@ -465,58 +445,56 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
*retlen = len;
ret = 0;
- if (eccbuf) {
- /* Read the ECC data from Spare Data Area,
- see Reed-Solomon EDC/ECC 11.1 */
- dummy = ReadDOC(docptr, ReadPipeInit);
+ /* Read the ECC data from Spare Data Area,
+ see Reed-Solomon EDC/ECC 11.1 */
+ dummy = ReadDOC(docptr, ReadPipeInit);
#ifndef USE_MEMCPY
- for (i = 0; i < 5; i++) {
- /* N.B. you have to increase the source address in this way or the
- ECC logic will not work properly */
- eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
- }
+ for (i = 0; i < 5; i++) {
+ /* N.B. you have to increase the source address in this way or the
+ ECC logic will not work properly */
+ eccbuf[i] = ReadDOC(docptr, Mil_CDSN_IO + i);
+ }
#else
- memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
+ memcpy_fromio(eccbuf, docptr + DoC_Mil_CDSN_IO, 5);
#endif
- eccbuf[5] = ReadDOC(docptr, LastDataRead);
+ eccbuf[5] = ReadDOC(docptr, LastDataRead);
- /* Flush the pipeline */
- dummy = ReadDOC(docptr, ECCConf);
- dummy = ReadDOC(docptr, ECCConf);
+ /* Flush the pipeline */
+ dummy = ReadDOC(docptr, ECCConf);
+ dummy = ReadDOC(docptr, ECCConf);
- /* Check the ECC Status */
- if (ReadDOC(docptr, ECCConf) & 0x80) {
- int nb_errors;
- /* There was an ECC error */
+ /* Check the ECC Status */
+ if (ReadDOC(docptr, ECCConf) & 0x80) {
+ int nb_errors;
+ /* There was an ECC error */
#ifdef ECC_DEBUG
- printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif
- /* Read the ECC syndrom through the DiskOnChip ECC logic.
- These syndrome will be all ZERO when there is no error */
- for (i = 0; i < 6; i++) {
- syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
- }
- nb_errors = doc_decode_ecc(buf, syndrome);
+ /* Read the ECC syndrom through the DiskOnChip ECC logic.
+ These syndrome will be all ZERO when there is no error */
+ for (i = 0; i < 6; i++) {
+ syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i);
+ }
+ nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
- printk("ECC Errors corrected: %x\n", nb_errors);
+ printk("ECC Errors corrected: %x\n", nb_errors);
#endif
- if (nb_errors < 0) {
- /* We return error, but have actually done the read. Not that
- this can be told to user-space, via sys_read(), but at least
- MTD-aware stuff can know about it by checking *retlen */
- ret = -EIO;
- }
+ if (nb_errors < 0) {
+ /* We return error, but have actually done the read. Not that
+ this can be told to user-space, via sys_read(), but at least
+ MTD-aware stuff can know about it by checking *retlen */
+ ret = -EIO;
}
+ }
#ifdef PSYCHO_DEBUG
- printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
+ printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
#endif
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
- }
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
return ret;
}
@@ -524,15 +502,8 @@ static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- char eccbuf[6];
- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel)
-{
int i,ret = 0;
+ char eccbuf[6];
volatile char dummy;
struct DiskOnChip *this = mtd->priv;
void __iomem *docptr = this->virtadr;
@@ -573,15 +544,9 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
DoC_Address(docptr, 3, to, 0x00, 0x00);
DoC_WaitReady(docptr);
- if (eccbuf) {
- /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
- WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
- WriteDOC (DOC_ECC_DIS, docptr, ECCConf);
- }
+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+ WriteDOC (DOC_ECC_RESET, docptr, ECCConf);
+ WriteDOC (DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf);
/* Write the data via the internal pipeline through CDSN IO register,
see Pipelined Write Operations 11.2 */
@@ -596,46 +561,44 @@ static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
#endif
WriteDOC(0x00, docptr, WritePipeTerm);
- if (eccbuf) {
- /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
- see Reed-Solomon EDC/ECC 11.1 */
- WriteDOC(0, docptr, NOP);
- WriteDOC(0, docptr, NOP);
- WriteDOC(0, docptr, NOP);
+ /* Write ECC data to flash, the ECC info is generated by the DiskOnChip ECC logic
+ see Reed-Solomon EDC/ECC 11.1 */
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
+ WriteDOC(0, docptr, NOP);
- /* Read the ECC data through the DiskOnChip ECC logic */
- for (i = 0; i < 6; i++) {
- eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
- }
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (i = 0; i < 6; i++) {
+ eccbuf[i] = ReadDOC(docptr, ECCSyndrome0 + i);
+ }
- /* ignore the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
+ /* ignore the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr , ECCConf);
#ifndef USE_MEMCPY
- /* Write the ECC data to flash */
- for (i = 0; i < 6; i++) {
- /* N.B. you have to increase the source address in this way or the
- ECC logic will not work properly */
- WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
- }
+ /* Write the ECC data to flash */
+ for (i = 0; i < 6; i++) {
+ /* N.B. you have to increase the source address in this way or the
+ ECC logic will not work properly */
+ WriteDOC(eccbuf[i], docptr, Mil_CDSN_IO + i);
+ }
#else
- memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
+ memcpy_toio(docptr + DoC_Mil_CDSN_IO, eccbuf, 6);
#endif
- /* write the block status BLOCK_USED (0x5555) at the end of ECC data
- FIXME: this is only a hack for programming the IPL area for LinuxBIOS
- and should be replace with proper codes in user space utilities */
- WriteDOC(0x55, docptr, Mil_CDSN_IO);
- WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
+ /* write the block status BLOCK_USED (0x5555) at the end of ECC data
+ FIXME: this is only a hack for programming the IPL area for LinuxBIOS
+ and should be replace with proper codes in user space utilities */
+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
+ WriteDOC(0x55, docptr, Mil_CDSN_IO + 1);
- WriteDOC(0x00, docptr, WritePipeTerm);
+ WriteDOC(0x00, docptr, WritePipeTerm);
#ifdef PSYCHO_DEBUG
- printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
#endif
- }
/* Commit the Page Program command and wait for ready
see Software Requirement 11.4 item 1.*/
diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c
index 66cb1e50469..92dbb47f2ac 100644
--- a/drivers/mtd/devices/doc2001plus.c
+++ b/drivers/mtd/devices/doc2001plus.c
@@ -41,12 +41,6 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf);
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf);
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel);
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel);
static int doc_read_oob(struct mtd_info *mtd, loff_t ofs,
struct mtd_oob_ops *ops);
static int doc_write_oob(struct mtd_info *mtd, loff_t ofs,
@@ -595,18 +589,10 @@ static int doc_dumpblk(struct mtd_info *mtd, loff_t from)
static int doc_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
- /* Just a special case of doc_read_ecc */
- return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
-}
-
-static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel)
-{
int ret, i;
volatile char dummy;
loff_t fofs;
- unsigned char syndrome[6];
+ unsigned char syndrome[6], eccbuf[6];
struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[from >> (this->chipshift)];
@@ -644,56 +630,51 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
WriteDOC(0, docptr, Mplus_FlashControl);
DoC_WaitReady(docptr);
- if (eccbuf) {
- /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
- WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
- WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
- } else {
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
- }
+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
+ WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf);
/* Let the caller know we completed it */
*retlen = len;
- ret = 0;
+ ret = 0;
ReadDOC(docptr, Mplus_ReadPipeInit);
ReadDOC(docptr, Mplus_ReadPipeInit);
- if (eccbuf) {
- /* Read the data via the internal pipeline through CDSN IO
- register, see Pipelined Read Operations 11.3 */
- MemReadDOC(docptr, buf, len);
+ /* Read the data via the internal pipeline through CDSN IO
+ register, see Pipelined Read Operations 11.3 */
+ MemReadDOC(docptr, buf, len);
- /* Read the ECC data following raw data */
- MemReadDOC(docptr, eccbuf, 4);
- eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
- eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
+ /* Read the ECC data following raw data */
+ MemReadDOC(docptr, eccbuf, 4);
+ eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead);
+ eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead);
- /* Flush the pipeline */
- dummy = ReadDOC(docptr, Mplus_ECCConf);
- dummy = ReadDOC(docptr, Mplus_ECCConf);
+ /* Flush the pipeline */
+ dummy = ReadDOC(docptr, Mplus_ECCConf);
+ dummy = ReadDOC(docptr, Mplus_ECCConf);
- /* Check the ECC Status */
- if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
- int nb_errors;
- /* There was an ECC error */
+ /* Check the ECC Status */
+ if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) {
+ int nb_errors;
+ /* There was an ECC error */
#ifdef ECC_DEBUG
- printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from);
#endif
- /* Read the ECC syndrom through the DiskOnChip ECC logic.
- These syndrome will be all ZERO when there is no error */
- for (i = 0; i < 6; i++)
- syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+ /* Read the ECC syndrom through the DiskOnChip ECC logic.
+ These syndrome will be all ZERO when there is no error */
+ for (i = 0; i < 6; i++)
+ syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
- nb_errors = doc_decode_ecc(buf, syndrome);
+ nb_errors = doc_decode_ecc(buf, syndrome);
#ifdef ECC_DEBUG
- printk("ECC Errors corrected: %x\n", nb_errors);
+ printk("ECC Errors corrected: %x\n", nb_errors);
#endif
- if (nb_errors < 0) {
- /* We return error, but have actually done the read. Not that
- this can be told to user-space, via sys_read(), but at least
- MTD-aware stuff can know about it by checking *retlen */
+ if (nb_errors < 0) {
+ /* We return error, but have actually done the
+ read. Not that this can be told to user-space, via
+ sys_read(), but at least MTD-aware stuff can know
+ about it by checking *retlen */
#ifdef ECC_DEBUG
printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n",
__FILE__, __LINE__, (int)from);
@@ -707,24 +688,16 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
eccbuf[3], eccbuf[4], eccbuf[5]);
#endif
ret = -EIO;
- }
}
+ }
#ifdef PSYCHO_DEBUG
- printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
+ printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
#endif
-
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
- } else {
- /* Read the data via the internal pipeline through CDSN IO
- register, see Pipelined Read Operations 11.3 */
- MemReadDOC(docptr, buf, len-2);
- buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead);
- buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead);
- }
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf);
/* Disable flash internally */
WriteDOC(0, docptr, Mplus_FlashSelect);
@@ -735,17 +708,10 @@ static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int doc_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
- char eccbuf[6];
- return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL);
-}
-
-static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf, u_char *eccbuf,
- struct nand_oobinfo *oobsel)
-{
int i, before, ret = 0;
loff_t fto;
volatile char dummy;
+ char eccbuf[6];
struct DiskOnChip *this = mtd->priv;
void __iomem * docptr = this->virtadr;
struct Nand *mychip = &this->chips[to >> (this->chipshift)];
@@ -795,46 +761,42 @@ static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
/* Disable the ECC engine */
WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf);
- if (eccbuf) {
- if (before) {
- /* Write the block status BLOCK_USED (0x5555) */
- WriteDOC(0x55, docptr, Mil_CDSN_IO);
- WriteDOC(0x55, docptr, Mil_CDSN_IO);
- }
-
- /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
- WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+ if (before) {
+ /* Write the block status BLOCK_USED (0x5555) */
+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
+ WriteDOC(0x55, docptr, Mil_CDSN_IO);
}
+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/
+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf);
+
MemWriteDOC(docptr, (unsigned char *) buf, len);
- if (eccbuf) {
- /* Write ECC data to flash, the ECC info is generated by
- the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
- DoC_Delay(docptr, 3);
+ /* Write ECC data to flash, the ECC info is generated by
+ the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */
+ DoC_Delay(docptr, 3);
- /* Read the ECC data through the DiskOnChip ECC logic */
- for (i = 0; i < 6; i++)
- eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
+ /* Read the ECC data through the DiskOnChip ECC logic */
+ for (i = 0; i < 6; i++)
+ eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i);
- /* disable the ECC engine */
- WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
+ /* disable the ECC engine */
+ WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf);
- /* Write the ECC data to flash */
- MemWriteDOC(docptr, eccbuf, 6);
+ /* Write the ECC data to flash */
+ MemWriteDOC(docptr, eccbuf, 6);
- if (!before) {
- /* Write the block status BLOCK_USED (0x5555) */
- WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
- WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
- }
+ if (!before) {
+ /* Write the block status BLOCK_USED (0x5555) */
+ WriteDOC(0x55, docptr, Mil_CDSN_IO+6);
+ WriteDOC(0x55, docptr, Mil_CDSN_IO+7);
+ }
#ifdef PSYCHO_DEBUG
- printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
- (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
- eccbuf[4], eccbuf[5]);
+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n",
+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3],
+ eccbuf[4], eccbuf[5]);
#endif
- }
WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
WriteDOC(0x00, docptr, Mplus_WritePipeTerm);
diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c
index 593bb033a3f..78872c3f376 100644
--- a/drivers/mtd/devices/docprobe.c
+++ b/drivers/mtd/devices/docprobe.c
@@ -40,7 +40,6 @@
*/
#define DOC_SINGLE_DRIVER
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index a8466141e91..ef4a731ca5c 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -406,13 +406,13 @@ struct flash_info {
static struct flash_info __devinitdata m25p_data [] = {
/* REVISIT: fill in JEDEC ids, for parts that have them */
- { "m25p05", 0x05, 0x0000, 32 * 1024, 2 },
- { "m25p10", 0x10, 0x0000, 32 * 1024, 4 },
- { "m25p20", 0x11, 0x0000, 64 * 1024, 4 },
- { "m25p40", 0x12, 0x0000, 64 * 1024, 8 },
+ { "m25p05", 0x05, 0x2010, 32 * 1024, 2 },
+ { "m25p10", 0x10, 0x2011, 32 * 1024, 4 },
+ { "m25p20", 0x11, 0x2012, 64 * 1024, 4 },
+ { "m25p40", 0x12, 0x2013, 64 * 1024, 8 },
{ "m25p80", 0x13, 0x0000, 64 * 1024, 16 },
- { "m25p16", 0x14, 0x0000, 64 * 1024, 32 },
- { "m25p32", 0x15, 0x0000, 64 * 1024, 64 },
+ { "m25p16", 0x14, 0x2015, 64 * 1024, 32 },
+ { "m25p32", 0x15, 0x2016, 64 * 1024, 64 },
{ "m25p64", 0x16, 0x2017, 64 * 1024, 128 },
};
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 4ab7670770e..08dfb899b27 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -225,6 +225,7 @@ static int __init ms02nv_init_one(ulong addr)
mtd->owner = THIS_MODULE;
mtd->read = ms02nv_read;
mtd->write = ms02nv_write;
+ mtd->writesize = 1;
ret = -EIO;
if (add_mtd_device(mtd)) {
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index a19480d0788..5db71604592 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -9,7 +9,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -478,6 +477,7 @@ add_dataflash(struct spi_device *spi, char *name,
device->name = (pdata && pdata->name) ? pdata->name : priv->name;
device->size = nr_pages * pagesize;
device->erasesize = pagesize;
+ device->writesize = pagesize;
device->owner = THIS_MODULE;
device->type = MTD_DATAFLASH;
device->flags = MTD_CAP_NORFLASH;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index b4438eacfd8..e427c82d5f4 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -10,7 +10,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index e09e416667d..6c7337f9ebb 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -151,6 +151,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
new->mtd.owner = THIS_MODULE;
new->mtd.type = MTD_RAM;
new->mtd.erasesize = PAGE_SIZE;
+ new->mtd.writesize = 1;
ret = -EAGAIN;
if (add_mtd_device(&new->mtd)) {
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 666cce1bf60..354e1657cc2 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -4,85 +4,84 @@
* PMC551 PCI Mezzanine Ram Device
*
* Author:
- * Mark Ferrell <mferrell@mvista.com>
- * Copyright 1999,2000 Nortel Networks
+ * Mark Ferrell <mferrell@mvista.com>
+ * Copyright 1999,2000 Nortel Networks
*
* License:
- * As part of this driver was derived from the slram.c driver it
- * falls under the same license, which is GNU General Public
- * License v2
+ * As part of this driver was derived from the slram.c driver it
+ * falls under the same license, which is GNU General Public
+ * License v2
*
* Description:
- * This driver is intended to support the PMC551 PCI Ram device
- * from Ramix Inc. The PMC551 is a PMC Mezzanine module for
- * cPCI embedded systems. The device contains a single SROM
- * that initially programs the V370PDC chipset onboard the
- * device, and various banks of DRAM/SDRAM onboard. This driver
- * implements this PCI Ram device as an MTD (Memory Technology
- * Device) so that it can be used to hold a file system, or for
- * added swap space in embedded systems. Since the memory on
- * this board isn't as fast as main memory we do not try to hook
- * it into main memory as that would simply reduce performance
- * on the system. Using it as a block device allows us to use
- * it as high speed swap or for a high speed disk device of some
- * sort. Which becomes very useful on diskless systems in the
- * embedded market I might add.
+ * This driver is intended to support the PMC551 PCI Ram device
+ * from Ramix Inc. The PMC551 is a PMC Mezzanine module for
+ * cPCI embedded systems. The device contains a single SROM
+ * that initially programs the V370PDC chipset onboard the
+ * device, and various banks of DRAM/SDRAM onboard. This driver
+ * implements this PCI Ram device as an MTD (Memory Technology
+ * Device) so that it can be used to hold a file system, or for
+ * added swap space in embedded systems. Since the memory on
+ * this board isn't as fast as main memory we do not try to hook
+ * it into main memory as that would simply reduce performance
+ * on the system. Using it as a block device allows us to use
+ * it as high speed swap or for a high speed disk device of some
+ * sort. Which becomes very useful on diskless systems in the
+ * embedded market I might add.
*
* Notes:
- * Due to what I assume is more buggy SROM, the 64M PMC551 I
- * have available claims that all 4 of it's DRAM banks have 64M
- * of ram configured (making a grand total of 256M onboard).
- * This is slightly annoying since the BAR0 size reflects the
- * aperture size, not the dram size, and the V370PDC supplies no
- * other method for memory size discovery. This problem is
- * mostly only relevant when compiled as a module, as the
- * unloading of the module with an aperture size smaller then
- * the ram will cause the driver to detect the onboard memory
- * size to be equal to the aperture size when the module is
- * reloaded. Soooo, to help, the module supports an msize
- * option to allow the specification of the onboard memory, and
- * an asize option, to allow the specification of the aperture
- * size. The aperture must be equal to or less then the memory
- * size, the driver will correct this if you screw it up. This
- * problem is not relevant for compiled in drivers as compiled
- * in drivers only init once.
+ * Due to what I assume is more buggy SROM, the 64M PMC551 I
+ * have available claims that all 4 of it's DRAM banks have 64M
+ * of ram configured (making a grand total of 256M onboard).
+ * This is slightly annoying since the BAR0 size reflects the
+ * aperture size, not the dram size, and the V370PDC supplies no
+ * other method for memory size discovery. This problem is
+ * mostly only relevant when compiled as a module, as the
+ * unloading of the module with an aperture size smaller then
+ * the ram will cause the driver to detect the onboard memory
+ * size to be equal to the aperture size when the module is
+ * reloaded. Soooo, to help, the module supports an msize
+ * option to allow the specification of the onboard memory, and
+ * an asize option, to allow the specification of the aperture
+ * size. The aperture must be equal to or less then the memory
+ * size, the driver will correct this if you screw it up. This
+ * problem is not relevant for compiled in drivers as compiled
+ * in drivers only init once.
*
* Credits:
- * Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
- * initial example code of how to initialize this device and for
- * help with questions I had concerning operation of the device.
+ * Saeed Karamooz <saeed@ramix.com> of Ramix INC. for the
+ * initial example code of how to initialize this device and for
+ * help with questions I had concerning operation of the device.
*
- * Most of the MTD code for this driver was originally written
- * for the slram.o module in the MTD drivers package which
- * allows the mapping of system memory into an MTD device.
- * Since the PMC551 memory module is accessed in the same
- * fashion as system memory, the slram.c code became a very nice
- * fit to the needs of this driver. All we added was PCI
- * detection/initialization to the driver and automatically figure
- * out the size via the PCI detection.o, later changes by Corey
- * Minyard set up the card to utilize a 1M sliding apature.
+ * Most of the MTD code for this driver was originally written
+ * for the slram.o module in the MTD drivers package which
+ * allows the mapping of system memory into an MTD device.
+ * Since the PMC551 memory module is accessed in the same
+ * fashion as system memory, the slram.c code became a very nice
+ * fit to the needs of this driver. All we added was PCI
+ * detection/initialization to the driver and automatically figure
+ * out the size via the PCI detection.o, later changes by Corey
+ * Minyard set up the card to utilize a 1M sliding apature.
*
- * Corey Minyard <minyard@nortelnetworks.com>
- * * Modified driver to utilize a sliding aperture instead of
- * mapping all memory into kernel space which turned out to
- * be very wasteful.
- * * Located a bug in the SROM's initialization sequence that
- * made the memory unusable, added a fix to code to touch up
- * the DRAM some.
+ * Corey Minyard <minyard@nortelnetworks.com>
+ * * Modified driver to utilize a sliding aperture instead of
+ * mapping all memory into kernel space which turned out to
+ * be very wasteful.
+ * * Located a bug in the SROM's initialization sequence that
+ * made the memory unusable, added a fix to code to touch up
+ * the DRAM some.
*
* Bugs/FIXME's:
- * * MUST fix the init function to not spin on a register
- * waiting for it to set .. this does not safely handle busted
- * devices that never reset the register correctly which will
- * cause the system to hang w/ a reboot being the only chance at
- * recover. [sort of fixed, could be better]
- * * Add I2C handling of the SROM so we can read the SROM's information
- * about the aperture size. This should always accurately reflect the
- * onboard memory size.
- * * Comb the init routine. It's still a bit cludgy on a few things.
+ * * MUST fix the init function to not spin on a register
+ * waiting for it to set .. this does not safely handle busted
+ * devices that never reset the register correctly which will
+ * cause the system to hang w/ a reboot being the only chance at
+ * recover. [sort of fixed, could be better]
+ * * Add I2C handling of the SROM so we can read the SROM's information
+ * about the aperture size. This should always accurately reflect the
+ * onboard memory size.
+ * * Comb the init routine. It's still a bit cludgy on a few things.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
@@ -100,84 +99,83 @@
#include <asm/system.h>
#include <linux/pci.h>
-#ifndef CONFIG_PCI
-#error Enable PCI in your kernel config
-#endif
-
#include <linux/mtd/mtd.h>
#include <linux/mtd/pmc551.h>
#include <linux/mtd/compatmac.h>
static struct mtd_info *pmc551list;
-static int pmc551_erase (struct mtd_info *mtd, struct erase_info *instr)
+static int pmc551_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- struct mypriv *priv = mtd->priv;
- u32 soff_hi, soff_lo; /* start address offset hi/lo */
- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
- unsigned long end;
+ struct mypriv *priv = mtd->priv;
+ u32 soff_hi, soff_lo; /* start address offset hi/lo */
+ u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
+ unsigned long end;
u_char *ptr;
size_t retlen;
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
+ printk(KERN_DEBUG "pmc551_erase(pos:%ld, len:%ld)\n", (long)instr->addr,
+ (long)instr->len);
#endif
- end = instr->addr + instr->len - 1;
+ end = instr->addr + instr->len - 1;
- /* Is it past the end? */
- if ( end > mtd->size ) {
+ /* Is it past the end? */
+ if (end > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n", (long)end, (long)mtd->size);
+ printk(KERN_DEBUG "pmc551_erase() out of bounds (%ld > %ld)\n",
+ (long)end, (long)mtd->size);
#endif
- return -EINVAL;
- }
-
- eoff_hi = end & ~(priv->asize - 1);
- soff_hi = instr->addr & ~(priv->asize - 1);
- eoff_lo = end & (priv->asize - 1);
- soff_lo = instr->addr & (priv->asize - 1);
-
- pmc551_point (mtd, instr->addr, instr->len, &retlen, &ptr);
-
- if ( soff_hi == eoff_hi || mtd->size == priv->asize) {
- /* The whole thing fits within one access, so just one shot
- will do it. */
- memset(ptr, 0xff, instr->len);
- } else {
- /* We have to do multiple writes to get all the data
- written. */
- while (soff_hi != eoff_hi) {
+ return -EINVAL;
+ }
+
+ eoff_hi = end & ~(priv->asize - 1);
+ soff_hi = instr->addr & ~(priv->asize - 1);
+ eoff_lo = end & (priv->asize - 1);
+ soff_lo = instr->addr & (priv->asize - 1);
+
+ pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
+
+ if (soff_hi == eoff_hi || mtd->size == priv->asize) {
+ /* The whole thing fits within one access, so just one shot
+ will do it. */
+ memset(ptr, 0xff, instr->len);
+ } else {
+ /* We have to do multiple writes to get all the data
+ written. */
+ while (soff_hi != eoff_hi) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk( KERN_DEBUG "pmc551_erase() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
+ printk(KERN_DEBUG "pmc551_erase() soff_hi: %ld, "
+ "eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
#endif
- memset(ptr, 0xff, priv->asize);
- if (soff_hi + priv->asize >= mtd->size) {
- goto out;
- }
- soff_hi += priv->asize;
- pmc551_point (mtd,(priv->base_map0|soff_hi),
- priv->asize, &retlen, &ptr);
- }
- memset (ptr, 0xff, eoff_lo);
- }
-
-out:
+ memset(ptr, 0xff, priv->asize);
+ if (soff_hi + priv->asize >= mtd->size) {
+ goto out;
+ }
+ soff_hi += priv->asize;
+ pmc551_point(mtd, (priv->base_map0 | soff_hi),
+ priv->asize, &retlen, &ptr);
+ }
+ memset(ptr, 0xff, eoff_lo);
+ }
+
+ out:
instr->state = MTD_ERASE_DONE;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_erase() done\n");
#endif
- mtd_erase_callback(instr);
- return 0;
+ mtd_erase_callback(instr);
+ return 0;
}
-
-static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char ** mtdbuf)
{
- struct mypriv *priv = mtd->priv;
- u32 soff_hi;
- u32 soff_lo;
+ struct mypriv *priv = mtd->priv;
+ u32 soff_hi;
+ u32 soff_lo;
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_point(%ld, %ld)\n", (long)from, (long)len);
@@ -185,18 +183,19 @@ static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *
if (from + len > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n", (long)from+len, (long)mtd->size);
+ printk(KERN_DEBUG "pmc551_point() out of bounds (%ld > %ld)\n",
+ (long)from + len, (long)mtd->size);
#endif
return -EINVAL;
}
- soff_hi = from & ~(priv->asize - 1);
- soff_lo = from & (priv->asize - 1);
+ soff_hi = from & ~(priv->asize - 1);
+ soff_lo = from & (priv->asize - 1);
/* Cheap hack optimization */
- if( priv->curr_map0 != from ) {
- pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
- (priv->base_map0 | soff_hi) );
+ if (priv->curr_map0 != from) {
+ pci_write_config_dword(priv->dev, PMC551_PCI_MEM_MAP0,
+ (priv->base_map0 | soff_hi));
priv->curr_map0 = soff_hi;
}
@@ -205,137 +204,144 @@ static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *
return 0;
}
-
-static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
+ size_t len)
{
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n");
#endif
}
-
-static int pmc551_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+static int pmc551_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf)
{
- struct mypriv *priv = mtd->priv;
- u32 soff_hi, soff_lo; /* start address offset hi/lo */
- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
- unsigned long end;
+ struct mypriv *priv = mtd->priv;
+ u32 soff_hi, soff_lo; /* start address offset hi/lo */
+ u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
+ unsigned long end;
u_char *ptr;
- u_char *copyto = buf;
+ u_char *copyto = buf;
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n", (long)from, (long)len, (long)priv->asize);
+ printk(KERN_DEBUG "pmc551_read(pos:%ld, len:%ld) asize: %ld\n",
+ (long)from, (long)len, (long)priv->asize);
#endif
- end = from + len - 1;
+ end = from + len - 1;
- /* Is it past the end? */
- if (end > mtd->size) {
+ /* Is it past the end? */
+ if (end > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n", (long) end, (long)mtd->size);
+ printk(KERN_DEBUG "pmc551_read() out of bounds (%ld > %ld)\n",
+ (long)end, (long)mtd->size);
#endif
- return -EINVAL;
- }
-
- soff_hi = from & ~(priv->asize - 1);
- eoff_hi = end & ~(priv->asize - 1);
- soff_lo = from & (priv->asize - 1);
- eoff_lo = end & (priv->asize - 1);
-
- pmc551_point (mtd, from, len, retlen, &ptr);
-
- if (soff_hi == eoff_hi) {
- /* The whole thing fits within one access, so just one shot
- will do it. */
- memcpy(copyto, ptr, len);
- copyto += len;
- } else {
- /* We have to do multiple writes to get all the data
- written. */
- while (soff_hi != eoff_hi) {
+ return -EINVAL;
+ }
+
+ soff_hi = from & ~(priv->asize - 1);
+ eoff_hi = end & ~(priv->asize - 1);
+ soff_lo = from & (priv->asize - 1);
+ eoff_lo = end & (priv->asize - 1);
+
+ pmc551_point(mtd, from, len, retlen, &ptr);
+
+ if (soff_hi == eoff_hi) {
+ /* The whole thing fits within one access, so just one shot
+ will do it. */
+ memcpy(copyto, ptr, len);
+ copyto += len;
+ } else {
+ /* We have to do multiple writes to get all the data
+ written. */
+ while (soff_hi != eoff_hi) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk( KERN_DEBUG "pmc551_read() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
+ printk(KERN_DEBUG "pmc551_read() soff_hi: %ld, "
+ "eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
#endif
- memcpy(copyto, ptr, priv->asize);
- copyto += priv->asize;
- if (soff_hi + priv->asize >= mtd->size) {
- goto out;
- }
- soff_hi += priv->asize;
- pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
- }
- memcpy(copyto, ptr, eoff_lo);
- copyto += eoff_lo;
- }
-
-out:
+ memcpy(copyto, ptr, priv->asize);
+ copyto += priv->asize;
+ if (soff_hi + priv->asize >= mtd->size) {
+ goto out;
+ }
+ soff_hi += priv->asize;
+ pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ }
+ memcpy(copyto, ptr, eoff_lo);
+ copyto += eoff_lo;
+ }
+
+ out:
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_read() done\n");
#endif
- *retlen = copyto - buf;
- return 0;
+ *retlen = copyto - buf;
+ return 0;
}
-static int pmc551_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+static int pmc551_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t * retlen, const u_char * buf)
{
- struct mypriv *priv = mtd->priv;
- u32 soff_hi, soff_lo; /* start address offset hi/lo */
- u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
- unsigned long end;
+ struct mypriv *priv = mtd->priv;
+ u32 soff_hi, soff_lo; /* start address offset hi/lo */
+ u32 eoff_hi, eoff_lo; /* end address offset hi/lo */
+ unsigned long end;
u_char *ptr;
- const u_char *copyfrom = buf;
-
+ const u_char *copyfrom = buf;
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n", (long)to, (long)len, (long)priv->asize);
+ printk(KERN_DEBUG "pmc551_write(pos:%ld, len:%ld) asize:%ld\n",
+ (long)to, (long)len, (long)priv->asize);
#endif
- end = to + len - 1;
- /* Is it past the end? or did the u32 wrap? */
- if (end > mtd->size ) {
+ end = to + len - 1;
+ /* Is it past the end? or did the u32 wrap? */
+ if (end > mtd->size) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, size: %ld, to: %ld)\n", (long) end, (long)mtd->size, (long)to);
+ printk(KERN_DEBUG "pmc551_write() out of bounds (end: %ld, "
+ "size: %ld, to: %ld)\n", (long)end, (long)mtd->size,
+ (long)to);
#endif
- return -EINVAL;
- }
-
- soff_hi = to & ~(priv->asize - 1);
- eoff_hi = end & ~(priv->asize - 1);
- soff_lo = to & (priv->asize - 1);
- eoff_lo = end & (priv->asize - 1);
-
- pmc551_point (mtd, to, len, retlen, &ptr);
-
- if (soff_hi == eoff_hi) {
- /* The whole thing fits within one access, so just one shot
- will do it. */
- memcpy(ptr, copyfrom, len);
- copyfrom += len;
- } else {
- /* We have to do multiple writes to get all the data
- written. */
- while (soff_hi != eoff_hi) {
+ return -EINVAL;
+ }
+
+ soff_hi = to & ~(priv->asize - 1);
+ eoff_hi = end & ~(priv->asize - 1);
+ soff_lo = to & (priv->asize - 1);
+ eoff_lo = end & (priv->asize - 1);
+
+ pmc551_point(mtd, to, len, retlen, &ptr);
+
+ if (soff_hi == eoff_hi) {
+ /* The whole thing fits within one access, so just one shot
+ will do it. */
+ memcpy(ptr, copyfrom, len);
+ copyfrom += len;
+ } else {
+ /* We have to do multiple writes to get all the data
+ written. */
+ while (soff_hi != eoff_hi) {
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk( KERN_DEBUG "pmc551_write() soff_hi: %ld, eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
+ printk(KERN_DEBUG "pmc551_write() soff_hi: %ld, "
+ "eoff_hi: %ld\n", (long)soff_hi, (long)eoff_hi);
#endif
- memcpy(ptr, copyfrom, priv->asize);
- copyfrom += priv->asize;
- if (soff_hi >= mtd->size) {
- goto out;
- }
- soff_hi += priv->asize;
- pmc551_point (mtd, soff_hi, priv->asize, retlen, &ptr);
- }
- memcpy(ptr, copyfrom, eoff_lo);
- copyfrom += eoff_lo;
- }
-
-out:
+ memcpy(ptr, copyfrom, priv->asize);
+ copyfrom += priv->asize;
+ if (soff_hi >= mtd->size) {
+ goto out;
+ }
+ soff_hi += priv->asize;
+ pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ }
+ memcpy(ptr, copyfrom, eoff_lo);
+ copyfrom += eoff_lo;
+ }
+
+ out:
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_write() done\n");
#endif
- *retlen = copyfrom - buf;
- return 0;
+ *retlen = copyfrom - buf;
+ return 0;
}
/*
@@ -350,58 +356,58 @@ out:
* mechanism
* returns the size of the memory region found.
*/
-static u32 fixup_pmc551 (struct pci_dev *dev)
+static u32 fixup_pmc551(struct pci_dev *dev)
{
#ifdef CONFIG_MTD_PMC551_BUGFIX
- u32 dram_data;
+ u32 dram_data;
#endif
- u32 size, dcmd, cfg, dtmp;
- u16 cmd, tmp, i;
+ u32 size, dcmd, cfg, dtmp;
+ u16 cmd, tmp, i;
u8 bcmd, counter;
- /* Sanity Check */
- if(!dev) {
- return -ENODEV;
- }
+ /* Sanity Check */
+ if (!dev) {
+ return -ENODEV;
+ }
/*
* Attempt to reset the card
* FIXME: Stop Spinning registers
*/
- counter=0;
+ counter = 0;
/* unlock registers */
- pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5 );
+ pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, 0xA5);
/* read in old data */
- pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
+ pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
/* bang the reset line up and down for a few */
- for(i=0;i<10;i++) {
- counter=0;
+ for (i = 0; i < 10; i++) {
+ counter = 0;
bcmd &= ~0x80;
- while(counter++ < 100) {
+ while (counter++ < 100) {
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
}
- counter=0;
+ counter = 0;
bcmd |= 0x80;
- while(counter++ < 100) {
+ while (counter++ < 100) {
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
}
}
- bcmd |= (0x40|0x20);
+ bcmd |= (0x40 | 0x20);
pci_write_config_byte(dev, PMC551_SYS_CTRL_REG, bcmd);
- /*
+ /*
* Take care and turn off the memory on the device while we
* tweak the configurations
*/
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- tmp = cmd & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY);
- pci_write_config_word(dev, PCI_COMMAND, tmp);
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+ pci_write_config_word(dev, PCI_COMMAND, tmp);
/*
* Disable existing aperture before probing memory size
*/
pci_read_config_dword(dev, PMC551_PCI_MEM_MAP0, &dcmd);
- dtmp=(dcmd|PMC551_PCI_MEM_MAP_ENABLE|PMC551_PCI_MEM_MAP_REG_EN);
+ dtmp = (dcmd | PMC551_PCI_MEM_MAP_ENABLE | PMC551_PCI_MEM_MAP_REG_EN);
pci_write_config_dword(dev, PMC551_PCI_MEM_MAP0, dtmp);
/*
* Grab old BAR0 config so that we can figure out memory size
@@ -412,220 +418,230 @@ static u32 fixup_pmc551 (struct pci_dev *dev)
* then write all 1's to the memory space, read back the result into
* "size", and then write back all the old config.
*/
- pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &cfg );
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &cfg);
#ifndef CONFIG_MTD_PMC551_BUGFIX
- pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, ~0 );
- pci_read_config_dword( dev, PCI_BASE_ADDRESS_0, &size );
- size = (size&PCI_BASE_ADDRESS_MEM_MASK);
- size &= ~(size-1);
- pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, ~0);
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &size);
+ size = (size & PCI_BASE_ADDRESS_MEM_MASK);
+ size &= ~(size - 1);
+ pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, cfg);
#else
- /*
- * Get the size of the memory by reading all the DRAM size values
- * and adding them up.
- *
- * KLUDGE ALERT: the boards we are using have invalid column and
- * row mux values. We fix them here, but this will break other
- * memory configurations.
- */
- pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
- size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
- pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
-
- pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
- size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
- pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
-
- pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
- size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
- pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
-
- pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
- size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
- dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
- dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
- pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
-
- /*
- * Oops .. something went wrong
- */
- if( (size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
- return -ENODEV;
- }
-#endif /* CONFIG_MTD_PMC551_BUGFIX */
-
- if ((cfg&PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
- return -ENODEV;
+ /*
+ * Get the size of the memory by reading all the DRAM size values
+ * and adding them up.
+ *
+ * KLUDGE ALERT: the boards we are using have invalid column and
+ * row mux values. We fix them here, but this will break other
+ * memory configurations.
+ */
+ pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dram_data);
+ size = PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK0, dram_data);
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dram_data);
+ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK1, dram_data);
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dram_data);
+ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK2, dram_data);
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dram_data);
+ size += PMC551_DRAM_BLK_GET_SIZE(dram_data);
+ dram_data = PMC551_DRAM_BLK_SET_COL_MUX(dram_data, 0x5);
+ dram_data = PMC551_DRAM_BLK_SET_ROW_MUX(dram_data, 0x9);
+ pci_write_config_dword(dev, PMC551_DRAM_BLK3, dram_data);
+
+ /*
+ * Oops .. something went wrong
+ */
+ if ((size &= PCI_BASE_ADDRESS_MEM_MASK) == 0) {
+ return -ENODEV;
+ }
+#endif /* CONFIG_MTD_PMC551_BUGFIX */
+
+ if ((cfg & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
+ return -ENODEV;
}
- /*
- * Precharge Dram
- */
- pci_write_config_word( dev, PMC551_SDRAM_MA, 0x0400 );
- pci_write_config_word( dev, PMC551_SDRAM_CMD, 0x00bf );
-
- /*
- * Wait until command has gone through
- * FIXME: register spinning issue
- */
- do { pci_read_config_word( dev, PMC551_SDRAM_CMD, &cmd );
- if(counter++ > 100)break;
- } while ( (PCI_COMMAND_IO) & cmd );
-
- /*
+ /*
+ * Precharge Dram
+ */
+ pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0400);
+ pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x00bf);
+
+ /*
+ * Wait until command has gone through
+ * FIXME: register spinning issue
+ */
+ do {
+ pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
+ if (counter++ > 100)
+ break;
+ } while ((PCI_COMMAND_IO) & cmd);
+
+ /*
* Turn on auto refresh
* The loop is taken directly from Ramix's example code. I assume that
* this must be held high for some duration of time, but I can find no
* documentation refrencing the reasons why.
- */
- for ( i = 1; i<=8 ; i++) {
- pci_write_config_word (dev, PMC551_SDRAM_CMD, 0x0df);
-
- /*
- * Make certain command has gone through
- * FIXME: register spinning issue
- */
- counter=0;
- do { pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
- if(counter++ > 100)break;
- } while ( (PCI_COMMAND_IO) & cmd );
- }
-
- pci_write_config_word ( dev, PMC551_SDRAM_MA, 0x0020);
- pci_write_config_word ( dev, PMC551_SDRAM_CMD, 0x0ff);
-
- /*
- * Wait until command completes
- * FIXME: register spinning issue
- */
- counter=0;
- do { pci_read_config_word ( dev, PMC551_SDRAM_CMD, &cmd);
- if(counter++ > 100)break;
- } while ( (PCI_COMMAND_IO) & cmd );
-
- pci_read_config_dword ( dev, PMC551_DRAM_CFG, &dcmd);
- dcmd |= 0x02000000;
- pci_write_config_dword ( dev, PMC551_DRAM_CFG, dcmd);
-
- /*
- * Check to make certain fast back-to-back, if not
- * then set it so
- */
- pci_read_config_word( dev, PCI_STATUS, &cmd);
- if((cmd&PCI_COMMAND_FAST_BACK) == 0) {
- cmd |= PCI_COMMAND_FAST_BACK;
- pci_write_config_word( dev, PCI_STATUS, cmd);
- }
-
- /*
- * Check to make certain the DEVSEL is set correctly, this device
- * has a tendancy to assert DEVSEL and TRDY when a write is performed
- * to the memory when memory is read-only
- */
- if((cmd&PCI_STATUS_DEVSEL_MASK) != 0x0) {
- cmd &= ~PCI_STATUS_DEVSEL_MASK;
- pci_write_config_word( dev, PCI_STATUS, cmd );
- }
- /*
- * Set to be prefetchable and put everything back based on old cfg.
+ */
+ for (i = 1; i <= 8; i++) {
+ pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0df);
+
+ /*
+ * Make certain command has gone through
+ * FIXME: register spinning issue
+ */
+ counter = 0;
+ do {
+ pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
+ if (counter++ > 100)
+ break;
+ } while ((PCI_COMMAND_IO) & cmd);
+ }
+
+ pci_write_config_word(dev, PMC551_SDRAM_MA, 0x0020);
+ pci_write_config_word(dev, PMC551_SDRAM_CMD, 0x0ff);
+
+ /*
+ * Wait until command completes
+ * FIXME: register spinning issue
+ */
+ counter = 0;
+ do {
+ pci_read_config_word(dev, PMC551_SDRAM_CMD, &cmd);
+ if (counter++ > 100)
+ break;
+ } while ((PCI_COMMAND_IO) & cmd);
+
+ pci_read_config_dword(dev, PMC551_DRAM_CFG, &dcmd);
+ dcmd |= 0x02000000;
+ pci_write_config_dword(dev, PMC551_DRAM_CFG, dcmd);
+
+ /*
+ * Check to make certain fast back-to-back, if not
+ * then set it so
+ */
+ pci_read_config_word(dev, PCI_STATUS, &cmd);
+ if ((cmd & PCI_COMMAND_FAST_BACK) == 0) {
+ cmd |= PCI_COMMAND_FAST_BACK;
+ pci_write_config_word(dev, PCI_STATUS, cmd);
+ }
+
+ /*
+ * Check to make certain the DEVSEL is set correctly, this device
+ * has a tendancy to assert DEVSEL and TRDY when a write is performed
+ * to the memory when memory is read-only
+ */
+ if ((cmd & PCI_STATUS_DEVSEL_MASK) != 0x0) {
+ cmd &= ~PCI_STATUS_DEVSEL_MASK;
+ pci_write_config_word(dev, PCI_STATUS, cmd);
+ }
+ /*
+ * Set to be prefetchable and put everything back based on old cfg.
* it's possible that the reset of the V370PDC nuked the original
* setup
- */
+ */
+ /*
+ cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
+ pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
+ */
+
/*
- cfg |= PCI_BASE_ADDRESS_MEM_PREFETCH;
- pci_write_config_dword( dev, PCI_BASE_ADDRESS_0, cfg );
- */
-
- /*
- * Turn PCI memory and I/O bus access back on
- */
- pci_write_config_word( dev, PCI_COMMAND,
- PCI_COMMAND_MEMORY | PCI_COMMAND_IO );
+ * Turn PCI memory and I/O bus access back on
+ */
+ pci_write_config_word(dev, PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_IO);
#ifdef CONFIG_MTD_PMC551_DEBUG
- /*
- * Some screen fun
- */
- printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at 0x%lx\n",
- (size<1024)?size:(size<1048576)?size>>10:size>>20,
- (size<1024)?'B':(size<1048576)?'K':'M',
- size, ((dcmd&(0x1<<3)) == 0)?"non-":"",
- (dev->resource[0].start)&PCI_BASE_ADDRESS_MEM_MASK );
-
- /*
- * Check to see the state of the memory
- */
- pci_read_config_dword( dev, PMC551_DRAM_BLK0, &dcmd );
- printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
- "pmc551: DRAM_BLK0 Size: %d at %d\n"
- "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
- (((0x1<<0)&dcmd) == 0)?"Off":"On",
- PMC551_DRAM_BLK_GET_SIZE(dcmd),
- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
- pci_read_config_dword( dev, PMC551_DRAM_BLK1, &dcmd );
- printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
- "pmc551: DRAM_BLK1 Size: %d at %d\n"
- "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
- (((0x1<<0)&dcmd) == 0)?"Off":"On",
- PMC551_DRAM_BLK_GET_SIZE(dcmd),
- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
- pci_read_config_dword( dev, PMC551_DRAM_BLK2, &dcmd );
- printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
- "pmc551: DRAM_BLK2 Size: %d at %d\n"
- "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
- (((0x1<<0)&dcmd) == 0)?"Off":"On",
- PMC551_DRAM_BLK_GET_SIZE(dcmd),
- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
- pci_read_config_dword( dev, PMC551_DRAM_BLK3, &dcmd );
- printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
- "pmc551: DRAM_BLK3 Size: %d at %d\n"
- "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
- (((0x1<<1)&dcmd) == 0)?"RW":"RO",
- (((0x1<<0)&dcmd) == 0)?"Off":"On",
- PMC551_DRAM_BLK_GET_SIZE(dcmd),
- ((dcmd>>20)&0x7FF), ((dcmd>>13)&0x7), ((dcmd>>9)&0xF) );
-
- pci_read_config_word( dev, PCI_COMMAND, &cmd );
- printk( KERN_DEBUG "pmc551: Memory Access %s\n",
- (((0x1<<1)&cmd) == 0)?"off":"on" );
- printk( KERN_DEBUG "pmc551: I/O Access %s\n",
- (((0x1<<0)&cmd) == 0)?"off":"on" );
-
- pci_read_config_word( dev, PCI_STATUS, &cmd );
- printk( KERN_DEBUG "pmc551: Devsel %s\n",
- ((PCI_STATUS_DEVSEL_MASK&cmd)==0x000)?"Fast":
- ((PCI_STATUS_DEVSEL_MASK&cmd)==0x200)?"Medium":
- ((PCI_STATUS_DEVSEL_MASK&cmd)==0x400)?"Slow":"Invalid" );
-
- printk( KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
- ((PCI_COMMAND_FAST_BACK&cmd) == 0)?"Not ":"" );
-
- pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd );
- printk( KERN_DEBUG "pmc551: EEPROM is under %s control\n"
- "pmc551: System Control Register is %slocked to PCI access\n"
- "pmc551: System Control Register is %slocked to EEPROM access\n",
- (bcmd&0x1)?"software":"hardware",
- (bcmd&0x20)?"":"un", (bcmd&0x40)?"":"un");
+ /*
+ * Some screen fun
+ */
+ printk(KERN_DEBUG "pmc551: %d%c (0x%x) of %sprefetchable memory at "
+ "0x%llx\n", (size < 1024) ? size : (size < 1048576) ?
+ size >> 10 : size >> 20,
+ (size < 1024) ? 'B' : (size < 1048576) ? 'K' : 'M', size,
+ ((dcmd & (0x1 << 3)) == 0) ? "non-" : "",
+ (unsigned long long)pci_resource_start(dev, 0));
+
+ /*
+ * Check to see the state of the memory
+ */
+ pci_read_config_dword(dev, PMC551_DRAM_BLK0, &dcmd);
+ printk(KERN_DEBUG "pmc551: DRAM_BLK0 Flags: %s,%s\n"
+ "pmc551: DRAM_BLK0 Size: %d at %d\n"
+ "pmc551: DRAM_BLK0 Row MUX: %d, Col MUX: %d\n",
+ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
+ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
+ PMC551_DRAM_BLK_GET_SIZE(dcmd),
+ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
+ ((dcmd >> 9) & 0xF));
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK1, &dcmd);
+ printk(KERN_DEBUG "pmc551: DRAM_BLK1 Flags: %s,%s\n"
+ "pmc551: DRAM_BLK1 Size: %d at %d\n"
+ "pmc551: DRAM_BLK1 Row MUX: %d, Col MUX: %d\n",
+ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
+ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
+ PMC551_DRAM_BLK_GET_SIZE(dcmd),
+ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
+ ((dcmd >> 9) & 0xF));
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK2, &dcmd);
+ printk(KERN_DEBUG "pmc551: DRAM_BLK2 Flags: %s,%s\n"
+ "pmc551: DRAM_BLK2 Size: %d at %d\n"
+ "pmc551: DRAM_BLK2 Row MUX: %d, Col MUX: %d\n",
+ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
+ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
+ PMC551_DRAM_BLK_GET_SIZE(dcmd),
+ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
+ ((dcmd >> 9) & 0xF));
+
+ pci_read_config_dword(dev, PMC551_DRAM_BLK3, &dcmd);
+ printk(KERN_DEBUG "pmc551: DRAM_BLK3 Flags: %s,%s\n"
+ "pmc551: DRAM_BLK3 Size: %d at %d\n"
+ "pmc551: DRAM_BLK3 Row MUX: %d, Col MUX: %d\n",
+ (((0x1 << 1) & dcmd) == 0) ? "RW" : "RO",
+ (((0x1 << 0) & dcmd) == 0) ? "Off" : "On",
+ PMC551_DRAM_BLK_GET_SIZE(dcmd),
+ ((dcmd >> 20) & 0x7FF), ((dcmd >> 13) & 0x7),
+ ((dcmd >> 9) & 0xF));
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ printk(KERN_DEBUG "pmc551: Memory Access %s\n",
+ (((0x1 << 1) & cmd) == 0) ? "off" : "on");
+ printk(KERN_DEBUG "pmc551: I/O Access %s\n",
+ (((0x1 << 0) & cmd) == 0) ? "off" : "on");
+
+ pci_read_config_word(dev, PCI_STATUS, &cmd);
+ printk(KERN_DEBUG "pmc551: Devsel %s\n",
+ ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x000) ? "Fast" :
+ ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x200) ? "Medium" :
+ ((PCI_STATUS_DEVSEL_MASK & cmd) == 0x400) ? "Slow" : "Invalid");
+
+ printk(KERN_DEBUG "pmc551: %sFast Back-to-Back\n",
+ ((PCI_COMMAND_FAST_BACK & cmd) == 0) ? "Not " : "");
+
+ pci_read_config_byte(dev, PMC551_SYS_CTRL_REG, &bcmd);
+ printk(KERN_DEBUG "pmc551: EEPROM is under %s control\n"
+ "pmc551: System Control Register is %slocked to PCI access\n"
+ "pmc551: System Control Register is %slocked to EEPROM access\n",
+ (bcmd & 0x1) ? "software" : "hardware",
+ (bcmd & 0x20) ? "" : "un", (bcmd & 0x40) ? "" : "un");
#endif
- return size;
+ return size;
}
/*
* Kernel version specific module stuffages
*/
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mark Ferrell <mferrell@mvista.com>");
MODULE_DESCRIPTION(PMC551_VERSION);
@@ -633,11 +649,11 @@ MODULE_DESCRIPTION(PMC551_VERSION);
/*
* Stuff these outside the ifdef so as to not bust compiled in driver support
*/
-static int msize=0;
+static int msize = 0;
#if defined(CONFIG_MTD_PMC551_APERTURE_SIZE)
-static int asize=CONFIG_MTD_PMC551_APERTURE_SIZE
+static int asize = CONFIG_MTD_PMC551_APERTURE_SIZE
#else
-static int asize=0;
+static int asize = 0;
#endif
module_param(msize, int, 0);
@@ -650,163 +666,174 @@ MODULE_PARM_DESC(asize, "aperture size, must be <= memsize [1-1024]");
*/
static int __init init_pmc551(void)
{
- struct pci_dev *PCI_Device = NULL;
- struct mypriv *priv;
- int count, found=0;
- struct mtd_info *mtd;
- u32 length = 0;
-
- if(msize) {
- msize = (1 << (ffs(msize) - 1))<<20;
- if (msize > (1<<30)) {
- printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n", msize);
+ struct pci_dev *PCI_Device = NULL;
+ struct mypriv *priv;
+ int count, found = 0;
+ struct mtd_info *mtd;
+ u32 length = 0;
+
+ if (msize) {
+ msize = (1 << (ffs(msize) - 1)) << 20;
+ if (msize > (1 << 30)) {
+ printk(KERN_NOTICE "pmc551: Invalid memory size [%d]\n",
+ msize);
return -EINVAL;
}
}
- if(asize) {
- asize = (1 << (ffs(asize) - 1))<<20;
- if (asize > (1<<30) ) {
- printk(KERN_NOTICE "pmc551: Invalid aperture size [%d]\n", asize);
+ if (asize) {
+ asize = (1 << (ffs(asize) - 1)) << 20;
+ if (asize > (1 << 30)) {
+ printk(KERN_NOTICE "pmc551: Invalid aperture size "
+ "[%d]\n", asize);
return -EINVAL;
}
}
- printk(KERN_INFO PMC551_VERSION);
-
- /*
- * PCU-bus chipset probe.
- */
- for( count = 0; count < MAX_MTD_DEVICES; count++ ) {
-
- if ((PCI_Device = pci_find_device(PCI_VENDOR_ID_V3_SEMI,
- PCI_DEVICE_ID_V3_SEMI_V370PDC,
- PCI_Device ) ) == NULL) {
- break;
- }
-
- printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%lX\n",
- PCI_Device->resource[0].start);
-
- /*
- * The PMC551 device acts VERY weird if you don't init it
- * first. i.e. it will not correctly report devsel. If for
- * some reason the sdram is in a wrote-protected state the
- * device will DEVSEL when it is written to causing problems
- * with the oldproc.c driver in
- * some kernels (2.2.*)
- */
- if((length = fixup_pmc551(PCI_Device)) <= 0) {
- printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
- break;
- }
+ printk(KERN_INFO PMC551_VERSION);
+
+ /*
+ * PCU-bus chipset probe.
+ */
+ for (count = 0; count < MAX_MTD_DEVICES; count++) {
+
+ if ((PCI_Device = pci_get_device(PCI_VENDOR_ID_V3_SEMI,
+ PCI_DEVICE_ID_V3_SEMI_V370PDC,
+ PCI_Device)) == NULL) {
+ break;
+ }
+
+ printk(KERN_NOTICE "pmc551: Found PCI V370PDC at 0x%llx\n",
+ (unsigned long long)pci_resource_start(PCI_Device, 0));
+
+ /*
+ * The PMC551 device acts VERY weird if you don't init it
+ * first. i.e. it will not correctly report devsel. If for
+ * some reason the sdram is in a wrote-protected state the
+ * device will DEVSEL when it is written to causing problems
+ * with the oldproc.c driver in
+ * some kernels (2.2.*)
+ */
+ if ((length = fixup_pmc551(PCI_Device)) <= 0) {
+ printk(KERN_NOTICE "pmc551: Cannot init SDRAM\n");
+ break;
+ }
/*
* This is needed until the driver is capable of reading the
* onboard I2C SROM to discover the "real" memory size.
*/
- if(msize) {
+ if (msize) {
length = msize;
- printk(KERN_NOTICE "pmc551: Using specified memory size 0x%x\n", length);
+ printk(KERN_NOTICE "pmc551: Using specified memory "
+ "size 0x%x\n", length);
} else {
msize = length;
}
- mtd = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd) {
- printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
- break;
- }
-
- memset(mtd, 0, sizeof(struct mtd_info));
-
- priv = kmalloc (sizeof(struct mypriv), GFP_KERNEL);
- if (!priv) {
- printk(KERN_NOTICE "pmc551: Cannot allocate new MTD device.\n");
- kfree(mtd);
- break;
- }
- memset(priv, 0, sizeof(*priv));
- mtd->priv = priv;
- priv->dev = PCI_Device;
-
- if(asize > length) {
- printk(KERN_NOTICE "pmc551: reducing aperture size to fit %dM\n",length>>20);
+ mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (!mtd) {
+ printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
+ "device.\n");
+ break;
+ }
+
+ priv = kzalloc(sizeof(struct mypriv), GFP_KERNEL);
+ if (!priv) {
+ printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
+ "device.\n");
+ kfree(mtd);
+ break;
+ }
+ mtd->priv = priv;
+ priv->dev = PCI_Device;
+
+ if (asize > length) {
+ printk(KERN_NOTICE "pmc551: reducing aperture size to "
+ "fit %dM\n", length >> 20);
priv->asize = asize = length;
} else if (asize == 0 || asize == length) {
- printk(KERN_NOTICE "pmc551: Using existing aperture size %dM\n", length>>20);
+ printk(KERN_NOTICE "pmc551: Using existing aperture "
+ "size %dM\n", length >> 20);
priv->asize = asize = length;
} else {
- printk(KERN_NOTICE "pmc551: Using specified aperture size %dM\n", asize>>20);
+ printk(KERN_NOTICE "pmc551: Using specified aperture "
+ "size %dM\n", asize >> 20);
priv->asize = asize;
}
- priv->start = ioremap(((PCI_Device->resource[0].start)
- & PCI_BASE_ADDRESS_MEM_MASK),
- priv->asize);
+ priv->start = pci_iomap(PCI_Device, 0, priv->asize);
if (!priv->start) {
printk(KERN_NOTICE "pmc551: Unable to map IO space\n");
- kfree(mtd->priv);
- kfree(mtd);
+ kfree(mtd->priv);
+ kfree(mtd);
break;
}
-
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk( KERN_DEBUG "pmc551: setting aperture to %d\n",
- ffs(priv->asize>>20)-1);
+ printk(KERN_DEBUG "pmc551: setting aperture to %d\n",
+ ffs(priv->asize >> 20) - 1);
#endif
- priv->base_map0 = ( PMC551_PCI_MEM_MAP_REG_EN
- | PMC551_PCI_MEM_MAP_ENABLE
- | (ffs(priv->asize>>20)-1)<<4 );
- priv->curr_map0 = priv->base_map0;
- pci_write_config_dword ( priv->dev, PMC551_PCI_MEM_MAP0,
- priv->curr_map0 );
+ priv->base_map0 = (PMC551_PCI_MEM_MAP_REG_EN
+ | PMC551_PCI_MEM_MAP_ENABLE
+ | (ffs(priv->asize >> 20) - 1) << 4);
+ priv->curr_map0 = priv->base_map0;
+ pci_write_config_dword(priv->dev, PMC551_PCI_MEM_MAP0,
+ priv->curr_map0);
#ifdef CONFIG_MTD_PMC551_DEBUG
- printk( KERN_DEBUG "pmc551: aperture set to %d\n",
- (priv->base_map0 & 0xF0)>>4 );
+ printk(KERN_DEBUG "pmc551: aperture set to %d\n",
+ (priv->base_map0 & 0xF0) >> 4);
#endif
- mtd->size = msize;
- mtd->flags = MTD_CAP_RAM;
- mtd->erase = pmc551_erase;
- mtd->read = pmc551_read;
- mtd->write = pmc551_write;
- mtd->point = pmc551_point;
- mtd->unpoint = pmc551_unpoint;
- mtd->type = MTD_RAM;
- mtd->name = "PMC551 RAM board";
- mtd->erasesize = 0x10000;
+ mtd->size = msize;
+ mtd->flags = MTD_CAP_RAM;
+ mtd->erase = pmc551_erase;
+ mtd->read = pmc551_read;
+ mtd->write = pmc551_write;
+ mtd->point = pmc551_point;
+ mtd->unpoint = pmc551_unpoint;
+ mtd->type = MTD_RAM;
+ mtd->name = "PMC551 RAM board";
+ mtd->erasesize = 0x10000;
+ mtd->writesize = 1;
mtd->owner = THIS_MODULE;
- if (add_mtd_device(mtd)) {
- printk(KERN_NOTICE "pmc551: Failed to register new device\n");
- iounmap(priv->start);
- kfree(mtd->priv);
- kfree(mtd);
- break;
- }
- printk(KERN_NOTICE "Registered pmc551 memory device.\n");
- printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
- priv->asize>>20,
- priv->start,
- priv->start + priv->asize);
- printk(KERN_NOTICE "Total memory is %d%c\n",
- (length<1024)?length:
- (length<1048576)?length>>10:length>>20,
- (length<1024)?'B':(length<1048576)?'K':'M');
+ if (add_mtd_device(mtd)) {
+ printk(KERN_NOTICE "pmc551: Failed to register new "
+ "device\n");
+ pci_iounmap(PCI_Device, priv->start);
+ kfree(mtd->priv);
+ kfree(mtd);
+ break;
+ }
+
+ /* Keep a reference as the add_mtd_device worked */
+ pci_dev_get(PCI_Device);
+
+ printk(KERN_NOTICE "Registered pmc551 memory device.\n");
+ printk(KERN_NOTICE "Mapped %dM of memory from 0x%p to 0x%p\n",
+ priv->asize >> 20,
+ priv->start, priv->start + priv->asize);
+ printk(KERN_NOTICE "Total memory is %d%c\n",
+ (length < 1024) ? length :
+ (length < 1048576) ? length >> 10 : length >> 20,
+ (length < 1024) ? 'B' : (length < 1048576) ? 'K' : 'M');
priv->nextpmc551 = pmc551list;
pmc551list = mtd;
found++;
- }
+ }
+
+ /* Exited early, reference left over */
+ if (PCI_Device)
+ pci_dev_put(PCI_Device);
- if( !pmc551list ) {
- printk(KERN_NOTICE "pmc551: not detected\n");
- return -ENODEV;
- } else {
+ if (!pmc551list) {
+ printk(KERN_NOTICE "pmc551: not detected\n");
+ return -ENODEV;
+ } else {
printk(KERN_NOTICE "pmc551: %d pmc551 devices loaded\n", found);
- return 0;
+ return 0;
}
}
@@ -815,23 +842,24 @@ static int __init init_pmc551(void)
*/
static void __exit cleanup_pmc551(void)
{
- int found=0;
- struct mtd_info *mtd;
+ int found = 0;
+ struct mtd_info *mtd;
struct mypriv *priv;
- while((mtd=pmc551list)) {
+ while ((mtd = pmc551list)) {
priv = mtd->priv;
pmc551list = priv->nextpmc551;
- if(priv->start) {
- printk (KERN_DEBUG "pmc551: unmapping %dM starting at 0x%p\n",
- priv->asize>>20, priv->start);
- iounmap (priv->start);
+ if (priv->start) {
+ printk(KERN_DEBUG "pmc551: unmapping %dM starting at "
+ "0x%p\n", priv->asize >> 20, priv->start);
+ pci_iounmap(priv->dev, priv->start);
}
+ pci_dev_put(priv->dev);
- kfree (mtd->priv);
- del_mtd_device (mtd);
- kfree (mtd);
+ kfree(mtd->priv);
+ del_mtd_device(mtd);
+ kfree(mtd);
found++;
}
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index b3f665e3c38..542a0c00900 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -209,6 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->owner = THIS_MODULE;
(*curmtd)->mtdinfo->type = MTD_RAM;
(*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
+ (*curmtd)->mtdinfo->writesize = 1;
if (add_mtd_device((*curmtd)->mtdinfo)) {
E("slram: Failed to register new device\n");
diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c
index 1e21a2c3dd2..4116535805f 100644
--- a/drivers/mtd/inftlcore.c
+++ b/drivers/mtd/inftlcore.c
@@ -24,7 +24,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 6bdaacc6d6f..24747bdc3e1 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -13,13 +13,13 @@ config MTD_COMPLEX_MAPPINGS
config MTD_PHYSMAP
tristate "CFI Flash device in physical memory map"
- depends on MTD_CFI
+ depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM
help
- This provides a 'mapping' driver which allows the CFI probe and
- command set driver code to communicate with flash chips which
- are mapped physically into the CPU's memory. You will need to
- configure the physical address and size of the flash chips on
- your particular board as well as the bus width, either statically
+ This provides a 'mapping' driver which allows the NOR Flash and
+ ROM driver code to communicate with chips which are mapped
+ physically into the CPU's memory. You will need to configure
+ the physical address and size of the flash chips on your
+ particular board as well as the bus width, either statically
with config options or at run-time.
config MTD_PHYSMAP_START
@@ -212,7 +212,7 @@ config MTD_NETtel
Support for flash chips on NETtel/SecureEdge/SnapGear boards.
config MTD_ALCHEMY
- tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support'
+ tristate "AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support"
depends on SOC_AU1X00
help
Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
@@ -447,14 +447,6 @@ config MTD_DC21285
21285 bridge used with Intel's StrongARM processors. More info at
<http://www.intel.com/design/bridge/docs/21285_documentation.htm>.
-config MTD_IQ80310
- tristate "CFI Flash device mapped on the XScale IQ80310 board"
- depends on MTD_CFI && ARCH_IQ80310
- help
- This enables access routines for the flash chips on the Intel XScale
- IQ80310 evaluation board. If you have one of these boards and would
- like to use the flash chips on it, say 'Y'.
-
config MTD_IXP4XX
tristate "CFI Flash device mapped on Intel IXP4xx based systems"
depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index ab71f172eb7..191c1928bbe 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
-obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
index b933a2a27b1..7fc8097e41d 100644
--- a/drivers/mtd/maps/alchemy-flash.c
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -7,7 +7,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index c350878d459..797caffb20b 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -14,7 +14,6 @@
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/flashchip.h>
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/list.h>
@@ -58,6 +57,7 @@ static void amd76xrom_cleanup(struct amd76xrom_window *window)
/* Disable writes through the rom window */
pci_read_config_byte(window->pdev, 0x40, &byte);
pci_write_config_byte(window->pdev, 0x40, byte & ~1);
+ pci_dev_put(window->pdev);
}
/* Free all of the mtd devices */
@@ -92,7 +92,7 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
struct amd76xrom_map_info *map = NULL;
unsigned long map_top;
- /* Remember the pci dev I find the window in */
+ /* Remember the pci dev I find the window in - already have a ref */
window->pdev = pdev;
/* Assume the rom window is properly setup, and find it's size */
@@ -123,9 +123,10 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
window->rsrc.parent = NULL;
printk(KERN_ERR MOD_NAME
" %s(): Unable to register resource"
- " 0x%.08lx-0x%.08lx - kernel bug?\n",
+ " 0x%.16llx-0x%.16llx - kernel bug?\n",
__func__,
- window->rsrc.start, window->rsrc.end);
+ (unsigned long long)window->rsrc.start,
+ (unsigned long long)window->rsrc.end);
}
#if 0
@@ -302,7 +303,7 @@ static int __init init_amd76xrom(void)
struct pci_device_id *id;
pdev = NULL;
for(id = amd76xrom_pci_tbl; id->vendor; id++) {
- pdev = pci_find_device(id->vendor, id->device, NULL);
+ pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
break;
}
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
index d95ae582fbe..642d96bc891 100644
--- a/drivers/mtd/maps/arctic-mtd.c
+++ b/drivers/mtd/maps/arctic-mtd.c
@@ -96,6 +96,8 @@ static struct mtd_partition arctic_partitions[PARTITIONS] = {
static int __init
init_arctic_mtd(void)
{
+ int err = 0;
+
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
arctic_mtd_map.virt = ioremap(PADDR, SIZE);
@@ -109,12 +111,20 @@ init_arctic_mtd(void)
printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
- if (!arctic_mtd)
+ if (!arctic_mtd) {
+ iounmap((void *) arctic_mtd_map.virt);
return -ENXIO;
+ }
arctic_mtd->owner = THIS_MODULE;
- return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
+ err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
+ if (err) {
+ printk("%s: add_mtd_partitions failed\n", NAME);
+ iounmap((void *) arctic_mtd_map.virt);
+ }
+
+ return err;
}
static void __exit
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
index 5df7361d140..a64b1a5ab31 100644
--- a/drivers/mtd/maps/beech-mtd.c
+++ b/drivers/mtd/maps/beech-mtd.c
@@ -72,6 +72,8 @@ static struct mtd_partition beech_partitions[2] = {
static int __init
init_beech_mtd(void)
{
+ int err = 0;
+
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
beech_mtd_map.virt = ioremap(PADDR, SIZE);
@@ -86,12 +88,20 @@ init_beech_mtd(void)
printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8);
beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
- if (!beech_mtd)
+ if (!beech_mtd) {
+ iounmap((void *) beech_mtd_map.virt);
return -ENXIO;
+ }
beech_mtd->owner = THIS_MODULE;
- return add_mtd_partitions(beech_mtd, beech_partitions, 2);
+ err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
+ if (err) {
+ printk("%s: add_mtd_partitions failed\n", NAME);
+ iounmap((void *) beech_mtd_map.virt);
+ }
+
+ return err;
}
static void __exit
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
index 5a95ab370a9..0402c21e291 100644
--- a/drivers/mtd/maps/ceiva.c
+++ b/drivers/mtd/maps/ceiva.c
@@ -14,7 +14,6 @@
* $Id: ceiva.c,v 1.11 2004/09/16 23:27:12 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/ioport.h>
diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c
index a370953c151..d6bef100d69 100644
--- a/drivers/mtd/maps/cstm_mips_ixx.c
+++ b/drivers/mtd/maps/cstm_mips_ixx.c
@@ -38,7 +38,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <linux/delay.h>
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
@@ -172,7 +171,14 @@ int __init init_cstm_mips_ixx(void)
cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
if (!cstm_mips_ixx_map[i].virt) {
+ int j = 0;
printk(KERN_WARNING "Failed to ioremap\n");
+ for (j = 0; j < i; j++) {
+ if (cstm_mips_ixx_map[j].virt) {
+ iounmap((void *)cstm_mips_ixx_map[j].virt);
+ cstm_mips_ixx_map[j].virt = 0;
+ }
+ }
return -EIO;
}
cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
@@ -205,8 +211,15 @@ int __init init_cstm_mips_ixx(void)
cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
}
- else
- return -ENXIO;
+ else {
+ for (i = 0; i < PHYSMAP_NUMBER; i++) {
+ if (cstm_mips_ixx_map[i].virt) {
+ iounmap((void *)cstm_mips_ixx_map[i].virt);
+ cstm_mips_ixx_map[i].virt = 0;
+ }
+ }
+ return -ENXIO;
+ }
}
return 0;
}
diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c
index 85c2a9e22b1..92a9c7fac99 100644
--- a/drivers/mtd/maps/dbox2-flash.c
+++ b/drivers/mtd/maps/dbox2-flash.c
@@ -12,7 +12,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <linux/errno.h>
/* partition_info gives details on the logical partitions that the split the
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
index 8b3784e2de8..b32bb9347d7 100644
--- a/drivers/mtd/maps/dc21285.c
+++ b/drivers/mtd/maps/dc21285.c
@@ -7,7 +7,6 @@
*
* $Id: dc21285.c,v 1.24 2005/11/07 11:14:26 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c
index c299d10b33e..b1104fe1f20 100644
--- a/drivers/mtd/maps/dilnetpc.c
+++ b/drivers/mtd/maps/dilnetpc.c
@@ -25,7 +25,6 @@
* and http://www.ssv-embedded.de/ssv/pc104/p170.htm
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c
index 2bb3c0f0f97..a43c49905ca 100644
--- a/drivers/mtd/maps/dmv182.c
+++ b/drivers/mtd/maps/dmv182.c
@@ -16,7 +16,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
diff --git a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c
index 60a6e51d662..1488bb92f26 100644
--- a/drivers/mtd/maps/ebony.c
+++ b/drivers/mtd/maps/ebony.c
@@ -20,7 +20,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <asm/io.h>
#include <asm/ibm44x.h>
#include <platforms/4xx/ebony.h>
@@ -109,6 +108,7 @@ int __init init_ebony(void)
ARRAY_SIZE(ebony_small_partitions));
} else {
printk("map probe failed for flash\n");
+ iounmap(ebony_small_map.virt);
return -ENXIO;
}
@@ -118,6 +118,7 @@ int __init init_ebony(void)
if (!ebony_large_map.virt) {
printk("Failed to ioremap flash\n");
+ iounmap(ebony_small_map.virt);
return -EIO;
}
@@ -130,6 +131,8 @@ int __init init_ebony(void)
ARRAY_SIZE(ebony_large_partitions));
} else {
printk("map probe failed for flash\n");
+ iounmap(ebony_small_map.virt);
+ iounmap(ebony_large_map.virt);
return -ENXIO;
}
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
index b48a3473ffc..1c5b97c8968 100644
--- a/drivers/mtd/maps/edb7312.c
+++ b/drivers/mtd/maps/edb7312.c
@@ -17,7 +17,6 @@
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#include <linux/config.h>
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
index c6bf4e1219e..7c50c271651 100644
--- a/drivers/mtd/maps/fortunet.c
+++ b/drivers/mtd/maps/fortunet.c
@@ -218,8 +218,11 @@ int __init init_fortunet(void)
map_regions[ix].map_info.size);
if(!map_regions[ix].map_info.virt)
{
+ int j = 0;
printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
map_regions[ix].map_info.name);
+ for (j = 0 ; j < ix; j++)
+ iounmap(map_regions[j].map_info.virt);
return -ENXIO;
}
simple_map_init(&map_regions[ix].map_info);
diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c
index 0667101ccbe..6dde3182d64 100644
--- a/drivers/mtd/maps/h720x-flash.c
+++ b/drivers/mtd/maps/h720x-flash.c
@@ -8,7 +8,6 @@
* 2003 Thomas Gleixner <tglx@linutronix.de>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index ea5073781b3..2bb3e63606e 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -14,7 +14,6 @@
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/flashchip.h>
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/list.h>
@@ -62,6 +61,7 @@ static void ichxrom_cleanup(struct ichxrom_window *window)
/* Disable writes through the rom window */
pci_read_config_word(window->pdev, BIOS_CNTL, &word);
pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1);
+ pci_dev_put(window->pdev);
/* Free all of the mtd devices */
list_for_each_entry_safe(map, scratch, &window->maps, list) {
@@ -177,9 +177,10 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev,
window->rsrc.parent = NULL;
printk(KERN_DEBUG MOD_NAME
": %s(): Unable to register resource"
- " 0x%.08lx-0x%.08lx - kernel bug?\n",
+ " 0x%.16llx-0x%.16llx - kernel bug?\n",
__func__,
- window->rsrc.start, window->rsrc.end);
+ (unsigned long long)window->rsrc.start,
+ (unsigned long long)window->rsrc.end);
}
/* Map the firmware hub into my address space. */
@@ -355,7 +356,7 @@ static int __init init_ichxrom(void)
pdev = NULL;
for (id = ichxrom_pci_tbl; id->vendor; id++) {
- pdev = pci_find_device(id->vendor, id->device, NULL);
+ pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
break;
}
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
index ba7f40311a7..a0b4dc7155d 100644
--- a/drivers/mtd/maps/impa7.c
+++ b/drivers/mtd/maps/impa7.c
@@ -17,7 +17,6 @@
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#include <linux/config.h>
#ifdef CONFIG_MTD_PARTITIONS
#include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c
index a3ba52fbd86..c8db01b3e45 100644
--- a/drivers/mtd/maps/integrator-flash.c
+++ b/drivers/mtd/maps/integrator-flash.c
@@ -26,7 +26,6 @@
======================================================================*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c
index b8ccb0a9578..f27c132794c 100644
--- a/drivers/mtd/maps/ipaq-flash.c
+++ b/drivers/mtd/maps/ipaq-flash.c
@@ -8,7 +8,6 @@
* $Id: ipaq-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c
deleted file mode 100644
index 62d9e87d84e..00000000000
--- a/drivers/mtd/maps/iq80310.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * $Id: iq80310.c,v 1.21 2005/11/07 11:14:27 gleixner Exp $
- *
- * Mapping for the Intel XScale IQ80310 evaluation board
- *
- * Author: Nicolas Pitre
- * Copyright: (C) 2001 MontaVista Software Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-
-#define WINDOW_ADDR 0
-#define WINDOW_SIZE 8*1024*1024
-#define BUSWIDTH 1
-
-static struct mtd_info *mymtd;
-
-static struct map_info iq80310_map = {
- .name = "IQ80310 flash",
- .size = WINDOW_SIZE,
- .bankwidth = BUSWIDTH,
- .phys = WINDOW_ADDR
-};
-
-static struct mtd_partition iq80310_partitions[4] = {
- {
- .name = "Firmware",
- .size = 0x00080000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },{
- .name = "Kernel",
- .size = 0x000a0000,
- .offset = 0x00080000,
- },{
- .name = "Filesystem",
- .size = 0x00600000,
- .offset = 0x00120000
- },{
- .name = "RedBoot",
- .size = 0x000e0000,
- .offset = 0x00720000,
- .mask_flags = MTD_WRITEABLE
- }
-};
-
-static struct mtd_info *mymtd;
-static struct mtd_partition *parsed_parts;
-static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
-
-static int __init init_iq80310(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
- int parsed_nr_parts = 0;
- int ret;
-
- iq80310_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
- if (!iq80310_map.virt) {
- printk("Failed to ioremap\n");
- return -EIO;
- }
- simple_map_init(&iq80310_map);
-
- mymtd = do_map_probe("cfi_probe", &iq80310_map);
- if (!mymtd) {
- iounmap((void *)iq80310_map.virt);
- return -ENXIO;
- }
- mymtd->owner = THIS_MODULE;
-
- ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0);
-
- if (ret > 0)
- parsed_nr_parts = ret;
-
- if (parsed_nr_parts > 0) {
- parts = parsed_parts;
- nb_parts = parsed_nr_parts;
- } else {
- parts = iq80310_partitions;
- nb_parts = ARRAY_SIZE(iq80310_partitions);
- }
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit cleanup_iq80310(void)
-{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- kfree(parsed_parts);
- }
- if (iq80310_map.virt)
- iounmap((void *)iq80310_map.virt);
-}
-
-module_init(init_iq80310);
-module_exit(cleanup_iq80310);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
-MODULE_DESCRIPTION("MTD map driver for Intel XScale IQ80310 evaluation board");
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index 2c9cc7f37e9..c26488a1793 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -42,7 +42,6 @@ struct ixp2000_flash_info {
struct map_info map;
struct mtd_partition *partitions;
struct resource *res;
- int nr_banks;
};
static inline unsigned long flash_bank_setup(struct map_info *map, unsigned long ofs)
@@ -183,7 +182,6 @@ static int ixp2000_flash_probe(struct platform_device *dev)
*/
info->map.phys = NO_XIP;
- info->nr_banks = ixp_data->nr_banks;
info->map.size = ixp_data->nr_banks * window_size;
info->map.bankwidth = 1;
diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c
index 986c5862839..7a828e3e644 100644
--- a/drivers/mtd/maps/ixp4xx.c
+++ b/drivers/mtd/maps/ixp4xx.c
@@ -253,7 +253,7 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
/* Use the fast version */
info->map.write = ixp4xx_write16,
- err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0);
+ err = parse_mtd_partitions(info->mtd, probes, &info->partitions, dev->resource->start);
if (err > 0) {
err = add_mtd_partitions(info->mtd, info->partitions, err);
if(err)
diff --git a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c
index 851bf957605..67620adf481 100644
--- a/drivers/mtd/maps/l440gx.c
+++ b/drivers/mtd/maps/l440gx.c
@@ -13,7 +13,6 @@
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#include <linux/config.h>
#define PIIXE_IOBASE_RESOURCE 11
@@ -62,14 +61,17 @@ static int __init init_l440gx(void)
struct resource *pm_iobase;
__u16 word;
- dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0, NULL);
- pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+ pm_dev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ pci_dev_put(dev);
+
if (!dev || !pm_dev) {
printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n");
+ pci_dev_put(pm_dev);
return -ENODEV;
}
@@ -77,6 +79,7 @@ static int __init init_l440gx(void)
if (!l440gx_map.virt) {
printk(KERN_WARNING "Failed to ioremap L440GX flash region\n");
+ pci_dev_put(pm_dev);
return -ENOMEM;
}
simple_map_init(&l440gx_map);
@@ -100,8 +103,12 @@ static int __init init_l440gx(void)
pm_iobase->start += iobase & ~1;
pm_iobase->end += iobase & ~1;
+ pci_dev_put(pm_dev);
+
/* Allocate the resource region */
if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) {
+ pci_dev_put(dev);
+ pci_dev_put(pm_dev);
printk(KERN_WARNING "Could not allocate pm iobase resource\n");
iounmap(l440gx_map.virt);
return -ENXIO;
diff --git a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c
index c658d4045ef..e3437632105 100644
--- a/drivers/mtd/maps/lasat.c
+++ b/drivers/mtd/maps/lasat.c
@@ -19,7 +19,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <asm/lasat/lasat.h>
static struct mtd_info *lasat_mtd;
@@ -80,6 +79,7 @@ static int __init init_lasat(void)
return 0;
}
+ iounmap(lasat_map.virt);
return -ENXIO;
}
@@ -90,6 +90,7 @@ static void __exit cleanup_lasat(void)
map_destroy(lasat_mtd);
}
if (lasat_map.virt) {
+ iounmap(lasat_map.virt);
lasat_map.virt = 0;
}
}
diff --git a/drivers/mtd/maps/mpc1211.c b/drivers/mtd/maps/mpc1211.c
index 4685e8e1346..45a00fac88a 100644
--- a/drivers/mtd/maps/mpc1211.c
+++ b/drivers/mtd/maps/mpc1211.c
@@ -15,7 +15,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
static struct mtd_info *flash_mtd;
static struct mtd_partition *parsed_parts;
diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c
index 5c25d4e552c..d884f2be28f 100644
--- a/drivers/mtd/maps/mtx-1_flash.c
+++ b/drivers/mtd/maps/mtx-1_flash.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 0994b5b2e33..198e840ff6d 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -277,6 +277,7 @@ int __init nettel_init(void)
nettel_amd_map.virt = ioremap_nocache(amdaddr, maxsize);
if (!nettel_amd_map.virt) {
printk("SNAPGEAR: failed to ioremap() BOOTCS\n");
+ iounmap(nettel_mmcrp);
return(-EIO);
}
simple_map_init(&nettel_amd_map);
@@ -337,7 +338,8 @@ int __init nettel_init(void)
nettel_amd_map.virt = NULL;
#else
/* Only AMD flash supported */
- return(-ENXIO);
+ rc = -ENXIO;
+ goto out_unmap2;
#endif
}
@@ -361,14 +363,15 @@ int __init nettel_init(void)
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1\n");
- return(-EIO);
+ rc = -EIO;
+ goto out_unmap2;
}
simple_map_init(&nettel_intel_map);
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (!intel_mtd) {
- iounmap(nettel_intel_map.virt);
- return(-ENXIO);
+ rc = -ENXIO;
+ goto out_unmap1;
}
/* Set PAR to the detected size */
@@ -394,13 +397,14 @@ int __init nettel_init(void)
nettel_intel_map.virt = ioremap_nocache(intel0addr, maxsize);
if (!nettel_intel_map.virt) {
printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n");
- return(-EIO);
+ rc = -EIO;
+ goto out_unmap2;
}
intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map);
if (! intel_mtd) {
- iounmap((void *) nettel_intel_map.virt);
- return(-ENXIO);
+ rc = -ENXIO;
+ goto out_unmap1;
}
intel1size = intel_mtd->size - intel0size;
@@ -456,6 +460,18 @@ int __init nettel_init(void)
#endif
return(rc);
+
+#ifdef CONFIG_MTD_CFI_INTELEXT
+out_unmap1:
+ iounmap((void *) nettel_intel_map.virt);
+#endif
+
+out_unmap2:
+ iounmap(nettel_mmcrp);
+ iounmap(nettel_amd_map.virt);
+
+ return(rc);
+
}
/****************************************************************************/
@@ -469,6 +485,10 @@ void __exit nettel_cleanup(void)
del_mtd_partitions(amd_mtd);
map_destroy(amd_mtd);
}
+ if (nettel_mmcrp) {
+ iounmap(nettel_mmcrp);
+ nettel_mmcrp = NULL;
+ }
if (nettel_amd_map.virt) {
iounmap(nettel_amd_map.virt);
nettel_amd_map.virt = NULL;
diff --git a/drivers/mtd/maps/ocotea.c b/drivers/mtd/maps/ocotea.c
index a21fcd195ab..5522eac8c98 100644
--- a/drivers/mtd/maps/ocotea.c
+++ b/drivers/mtd/maps/ocotea.c
@@ -18,7 +18,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <asm/io.h>
#include <asm/ibm44x.h>
#include <platforms/4xx/ocotea.h>
@@ -98,6 +97,7 @@ int __init init_ocotea(void)
ARRAY_SIZE(ocotea_small_partitions));
} else {
printk("map probe failed for flash\n");
+ iounmap(ocotea_small_map.virt);
return -ENXIO;
}
@@ -107,6 +107,7 @@ int __init init_ocotea(void)
if (!ocotea_large_map.virt) {
printk("Failed to ioremap flash\n");
+ iounmap(ocotea_small_map.virt);
return -EIO;
}
@@ -119,6 +120,8 @@ int __init init_ocotea(void)
ARRAY_SIZE(ocotea_large_partitions));
} else {
printk("map probe failed for flash\n");
+ iounmap(ocotea_small_map.virt);
+ iounmap(ocotea_large_map.virt);
return -ENXIO;
}
diff --git a/drivers/mtd/maps/omap-toto-flash.c b/drivers/mtd/maps/omap-toto-flash.c
index dc376527005..e6e391efbeb 100644
--- a/drivers/mtd/maps/omap-toto-flash.c
+++ b/drivers/mtd/maps/omap-toto-flash.c
@@ -8,7 +8,6 @@
* $Id: omap-toto-flash.c,v 1.5 2005/11/07 11:14:27 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index c861134cbc4..995347b1beb 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -602,6 +602,10 @@ static int pcmciamtd_config(struct pcmcia_device *link)
ret = pcmcia_request_configuration(link, &link->conf);
if(ret != CS_SUCCESS) {
cs_error(link, RequestConfiguration, ret);
+ if (dev->win_base) {
+ iounmap(dev->win_base);
+ dev->win_base = NULL;
+ }
return -ENODEV;
}
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index 433c3cac3ca..bc7cc71788b 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -18,7 +18,6 @@
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#include <linux/config.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <asm/io.h>
@@ -159,9 +158,42 @@ err_out:
return err;
}
+#ifdef CONFIG_PM
+static int physmap_flash_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct physmap_flash_info *info = platform_get_drvdata(dev);
+ int ret = 0;
+
+ if (info)
+ ret = info->mtd->suspend(info->mtd);
+
+ return ret;
+}
+
+static int physmap_flash_resume(struct platform_device *dev)
+{
+ struct physmap_flash_info *info = platform_get_drvdata(dev);
+ if (info)
+ info->mtd->resume(info->mtd);
+ return 0;
+}
+
+static void physmap_flash_shutdown(struct platform_device *dev)
+{
+ struct physmap_flash_info *info = platform_get_drvdata(dev);
+ if (info && info->mtd->suspend(info->mtd) == 0)
+ info->mtd->resume(info->mtd);
+}
+#endif
+
static struct platform_driver physmap_flash_driver = {
.probe = physmap_flash_probe,
.remove = physmap_flash_remove,
+#ifdef CONFIG_PM
+ .suspend = physmap_flash_suspend,
+ .resume = physmap_flash_resume,
+ .shutdown = physmap_flash_shutdown,
+#endif
.driver = {
.name = "physmap-flash",
},
@@ -182,7 +214,7 @@ static struct physmap_flash_data physmap_flash_data = {
static struct resource physmap_flash_resource = {
.start = CONFIG_MTD_PHYSMAP_START,
- .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN,
+ .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
.flags = IORESOURCE_MEM,
};
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
index 50b14033613..2257d2b500c 100644
--- a/drivers/mtd/maps/redwood.c
+++ b/drivers/mtd/maps/redwood.c
@@ -13,7 +13,6 @@
* or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -127,6 +126,8 @@ static struct mtd_info *redwood_mtd;
int __init init_redwood_flash(void)
{
+ int err = 0;
+
printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
WINDOW_SIZE, WINDOW_ADDR);
@@ -142,11 +143,18 @@ int __init init_redwood_flash(void)
if (redwood_mtd) {
redwood_mtd->owner = THIS_MODULE;
- return add_mtd_partitions(redwood_mtd,
+ err = add_mtd_partitions(redwood_mtd,
redwood_flash_partitions,
NUM_REDWOOD_FLASH_PARTITIONS);
+ if (err) {
+ printk("init_redwood_flash: add_mtd_partitions failed\n");
+ iounmap(redwood_flash_map.virt);
+ }
+ return err;
+
}
+ iounmap(redwood_flash_map.virt);
return -ENXIO;
}
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index 5cefb015633..950bf1c5784 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -5,7 +5,6 @@
*
* $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/ioport.h>
diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c
index 350286dc1d2..b8c1331b7a0 100644
--- a/drivers/mtd/maps/sbc8240.c
+++ b/drivers/mtd/maps/sbc8240.c
@@ -18,7 +18,6 @@
* Both parts are JEDEC compatible.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -157,7 +156,7 @@ int __init init_sbc8240_mtd (void)
};
int devicesfound = 0;
- int i;
+ int i,j;
for (i = 0; i < NUM_FLASH_BANKS; i++) {
printk (KERN_NOTICE MSG_PREFIX
@@ -167,6 +166,10 @@ int __init init_sbc8240_mtd (void)
(unsigned long) ioremap (pt[i].addr, pt[i].size);
if (!sbc8240_map[i].map_priv_1) {
printk (MSG_PREFIX "failed to ioremap\n");
+ for (j = 0; j < i; j++) {
+ iounmap((void *) sbc8240_map[j].map_priv_1);
+ sbc8240_map[j].map_priv_1 = 0;
+ }
return -EIO;
}
simple_map_init(&sbc8240_mtd[i]);
@@ -176,6 +179,11 @@ int __init init_sbc8240_mtd (void)
if (sbc8240_mtd[i]) {
sbc8240_mtd[i]->module = THIS_MODULE;
devicesfound++;
+ } else {
+ if (sbc8240_map[i].map_priv_1) {
+ iounmap((void *) sbc8240_map[i].map_priv_1);
+ sbc8240_map[i].map_priv_1 = 0;
+ }
}
}
diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c
index e8c130e1efd..9b50cfc355b 100644
--- a/drivers/mtd/maps/sc520cdp.c
+++ b/drivers/mtd/maps/sc520cdp.c
@@ -25,7 +25,6 @@
* For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
index 97a8dfd6925..dcfb85840d1 100644
--- a/drivers/mtd/maps/scb2_flash.c
+++ b/drivers/mtd/maps/scb2_flash.c
@@ -53,7 +53,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
diff --git a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c
index 28b8a571a91..5e2bce22f37 100644
--- a/drivers/mtd/maps/scx200_docflash.c
+++ b/drivers/mtd/maps/scx200_docflash.c
@@ -8,7 +8,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -88,19 +87,23 @@ static int __init init_scx200_docflash(void)
printk(KERN_DEBUG NAME ": NatSemi SCx200 DOCCS Flash Driver\n");
- if ((bridge = pci_find_device(PCI_VENDOR_ID_NS,
+ if ((bridge = pci_get_device(PCI_VENDOR_ID_NS,
PCI_DEVICE_ID_NS_SCx200_BRIDGE,
NULL)) == NULL)
return -ENODEV;
/* check that we have found the configuration block */
- if (!scx200_cb_present())
+ if (!scx200_cb_present()) {
+ pci_dev_put(bridge);
return -ENODEV;
+ }
if (probe) {
/* Try to use the present flash mapping if any */
pci_read_config_dword(bridge, SCx200_DOCCS_BASE, &base);
pci_read_config_dword(bridge, SCx200_DOCCS_CTRL, &ctrl);
+ pci_dev_put(bridge);
+
pmr = inl(scx200_cb_base + SCx200_PMR);
if (base == 0
@@ -128,6 +131,7 @@ static int __init init_scx200_docflash(void)
return -ENOMEM;
}
} else {
+ pci_dev_put(bridge);
for (u = size; u > 1; u >>= 1)
;
if (u != 1) {
@@ -164,8 +168,9 @@ static int __init init_scx200_docflash(void)
outl(pmr, scx200_cb_base + SCx200_PMR);
}
- printk(KERN_INFO NAME ": DOCCS mapped at 0x%lx-0x%lx, width %d\n",
- docmem.start, docmem.end, width);
+ printk(KERN_INFO NAME ": DOCCS mapped at 0x%llx-0x%llx, width %d\n",
+ (unsigned long long)docmem.start,
+ (unsigned long long)docmem.end, width);
scx200_docflash_map.size = size;
if (width == 8)
diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c
index c53c2c369c9..d76ceef453c 100644
--- a/drivers/mtd/maps/solutionengine.c
+++ b/drivers/mtd/maps/solutionengine.c
@@ -16,7 +16,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <linux/errno.h>
static struct mtd_info *flash_mtd;
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c
index 0758cb1d010..4db2055cee3 100644
--- a/drivers/mtd/maps/sun_uflash.c
+++ b/drivers/mtd/maps/sun_uflash.c
@@ -18,6 +18,7 @@
#include <linux/ioport.h>
#include <asm/ebus.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -30,146 +31,141 @@
#define UFLASH_WINDOW_SIZE 0x200000
#define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */
-MODULE_AUTHOR
- ("Eric Brower <ebrower@usa.net>");
-MODULE_DESCRIPTION
- ("User-programmable flash device on Sun Microsystems boardsets");
-MODULE_SUPPORTED_DEVICE
- ("userflash");
-MODULE_LICENSE
- ("GPL");
+MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
+MODULE_DESCRIPTION("User-programmable flash device on Sun Microsystems boardsets");
+MODULE_SUPPORTED_DEVICE("userflash");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0");
static LIST_HEAD(device_list);
struct uflash_dev {
- char * name; /* device name */
+ char *name; /* device name */
struct map_info map; /* mtd map info */
- struct mtd_info * mtd; /* mtd info */
- struct list_head list;
+ struct mtd_info *mtd; /* mtd info */
};
struct map_info uflash_map_templ = {
- .name = "SUNW,???-????",
- .size = UFLASH_WINDOW_SIZE,
- .bankwidth = UFLASH_BUSWIDTH,
+ .name = "SUNW,???-????",
+ .size = UFLASH_WINDOW_SIZE,
+ .bankwidth = UFLASH_BUSWIDTH,
};
-int uflash_devinit(struct linux_ebus_device* edev)
+int uflash_devinit(struct linux_ebus_device *edev, struct device_node *dp)
{
- int iTmp, nregs;
- struct linux_prom_registers regs[2];
- struct uflash_dev *pdev;
-
- iTmp = prom_getproperty(
- edev->prom_node, "reg", (void *)regs, sizeof(regs));
- if ((iTmp % sizeof(regs[0])) != 0) {
- printk("%s: Strange reg property size %d\n",
- UFLASH_DEVNAME, iTmp);
- return -ENODEV;
- }
+ struct uflash_dev *up;
+ struct resource *res;
- nregs = iTmp / sizeof(regs[0]);
+ res = &edev->resource[0];
- if (nregs != 1) {
+ if (edev->num_addrs != 1) {
/* Non-CFI userflash device-- once I find one we
* can work on supporting it.
*/
- printk("%s: unsupported device at 0x%lx (%d regs): " \
+ printk("%s: unsupported device at 0x%llx (%d regs): " \
"email ebrower@usa.net\n",
- UFLASH_DEVNAME, edev->resource[0].start, nregs);
+ dp->full_name, (unsigned long long)res->start,
+ edev->num_addrs);
+
return -ENODEV;
}
- if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) {
- printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
- return(-ENOMEM);
- }
+ up = kzalloc(sizeof(struct uflash_dev), GFP_KERNEL);
+ if (!up)
+ return -ENOMEM;
/* copy defaults and tweak parameters */
- memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
- pdev->map.size = regs[0].reg_size;
-
- iTmp = prom_getproplen(edev->prom_node, "model");
- pdev->name = kmalloc(iTmp, GFP_KERNEL);
- prom_getstring(edev->prom_node, "model", pdev->name, iTmp);
- if(0 != pdev->name && 0 < strlen(pdev->name)) {
- pdev->map.name = pdev->name;
- }
- pdev->map.phys = edev->resource[0].start;
- pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size);
- if(0 == pdev->map.virt) {
- printk("%s: failed to map device\n", __FUNCTION__);
- kfree(pdev->name);
- kfree(pdev);
- return(-1);
+ memcpy(&up->map, &uflash_map_templ, sizeof(uflash_map_templ));
+ up->map.size = (res->end - res->start) + 1UL;
+
+ up->name = of_get_property(dp, "model", NULL);
+ if (up->name && 0 < strlen(up->name))
+ up->map.name = up->name;
+
+ up->map.phys = res->start;
+
+ up->map.virt = ioremap_nocache(res->start, up->map.size);
+ if (!up->map.virt) {
+ printk("%s: Failed to map device.\n", dp->full_name);
+ kfree(up);
+
+ return -EINVAL;
}
- simple_map_init(&pdev->map);
+ simple_map_init(&up->map);
/* MTD registration */
- pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
- if(0 == pdev->mtd) {
- iounmap(pdev->map.virt);
- kfree(pdev->name);
- kfree(pdev);
- return(-ENXIO);
+ up->mtd = do_map_probe("cfi_probe", &up->map);
+ if (!up->mtd) {
+ iounmap(up->map.virt);
+ kfree(up);
+
+ return -ENXIO;
}
- list_add(&pdev->list, &device_list);
+ up->mtd->owner = THIS_MODULE;
- pdev->mtd->owner = THIS_MODULE;
+ add_mtd_device(up->mtd);
- add_mtd_device(pdev->mtd);
- return(0);
+ dev_set_drvdata(&edev->ofdev.dev, up);
+
+ return 0;
}
-static int __init uflash_init(void)
+static int __devinit uflash_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct linux_ebus *ebus = NULL;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) {
- if(0 > prom_getproplen(edev->prom_node, "user")) {
- DEBUG(2, "%s: ignoring device at 0x%lx\n",
- UFLASH_DEVNAME, edev->resource[0].start);
- } else {
- uflash_devinit(edev);
- }
- }
- }
- }
+ struct linux_ebus_device *edev = to_ebus_device(&dev->dev);
+ struct device_node *dp = dev->node;
- if(list_empty(&device_list)) {
- printk("%s: unable to locate device\n", UFLASH_DEVNAME);
+ if (of_find_property(dp, "user", NULL))
return -ENODEV;
- }
- return(0);
+
+ return uflash_devinit(edev, dp);
}
-static void __exit uflash_cleanup(void)
+static int __devexit uflash_remove(struct of_device *dev)
{
- struct list_head *udevlist;
- struct uflash_dev *udev;
-
- list_for_each(udevlist, &device_list) {
- udev = list_entry(udevlist, struct uflash_dev, list);
- DEBUG(2, "%s: removing device %s\n",
- UFLASH_DEVNAME, udev->name);
-
- if(0 != udev->mtd) {
- del_mtd_device(udev->mtd);
- map_destroy(udev->mtd);
- }
- if(0 != udev->map.virt) {
- iounmap(udev->map.virt);
- udev->map.virt = NULL;
- }
- kfree(udev->name);
- kfree(udev);
+ struct uflash_dev *up = dev_get_drvdata(&dev->dev);
+
+ if (up->mtd) {
+ del_mtd_device(up->mtd);
+ map_destroy(up->mtd);
}
+ if (up->map.virt) {
+ iounmap(up->map.virt);
+ up->map.virt = NULL;
+ }
+
+ kfree(up);
+
+ return 0;
+}
+
+static struct of_device_id uflash_match[] = {
+ {
+ .name = UFLASH_OBPNAME,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, uflash_match);
+
+static struct of_platform_driver uflash_driver = {
+ .name = UFLASH_DEVNAME,
+ .match_table = uflash_match,
+ .probe = uflash_probe,
+ .remove = __devexit_p(uflash_remove),
+};
+
+static int __init uflash_init(void)
+{
+ return of_register_driver(&uflash_driver, &ebus_bus_type);
+}
+
+static void __exit uflash_exit(void)
+{
+ of_unregister_driver(&uflash_driver);
}
module_init(uflash_init);
-module_exit(uflash_cleanup);
+module_exit(uflash_exit);
diff --git a/drivers/mtd/maps/tqm834x.c b/drivers/mtd/maps/tqm834x.c
index c7ae9a515c1..58e5912bd38 100644
--- a/drivers/mtd/maps/tqm834x.c
+++ b/drivers/mtd/maps/tqm834x.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c
index a43517053e7..19578ba84ee 100644
--- a/drivers/mtd/maps/tqm8xxl.c
+++ b/drivers/mtd/maps/tqm8xxl.c
@@ -22,7 +22,6 @@
* Thus, we choose CONFIG_MTD_CFI_I2 & CONFIG_MTD_CFI_B4 at
* kernel configuration.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c
index a7422c20056..b47270e850b 100644
--- a/drivers/mtd/maps/ts5500_flash.c
+++ b/drivers/mtd/maps/ts5500_flash.c
@@ -26,7 +26,6 @@
* $Id: ts5500_flash.c,v 1.5 2005/11/07 11:14:28 gleixner Exp $
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index f7264dc2ac9..389fea28b9a 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -10,7 +10,6 @@
/****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
diff --git a/drivers/mtd/maps/walnut.c b/drivers/mtd/maps/walnut.c
index f46bec66150..ca932122fb6 100644
--- a/drivers/mtd/maps/walnut.c
+++ b/drivers/mtd/maps/walnut.c
@@ -20,7 +20,6 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
-#include <linux/config.h>
#include <asm/io.h>
#include <asm/ibm4xx.h>
#include <platforms/4xx/walnut.h>
@@ -69,6 +68,7 @@ int __init init_walnut(void)
if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
printk("The on-board flash is disabled (U79 sw 5)!");
+ iounmap(fpga_status_adr);
return -EIO;
}
if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
@@ -82,6 +82,7 @@ int __init init_walnut(void)
if (!walnut_map.virt) {
printk("Failed to ioremap flash.\n");
+ iounmap(fpga_status_adr);
return -EIO;
}
@@ -94,9 +95,11 @@ int __init init_walnut(void)
ARRAY_SIZE(walnut_partitions));
} else {
printk("map probe failed for flash\n");
+ iounmap(fpga_status_adr);
return -ENXIO;
}
+ iounmap(fpga_status_adr);
return 0;
}
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
index 60c197ec455..ac5b8105b6e 100644
--- a/drivers/mtd/maps/wr_sbc82xx_flash.c
+++ b/drivers/mtd/maps/wr_sbc82xx_flash.c
@@ -17,7 +17,6 @@
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
-#include <linux/config.h>
#include <linux/mtd/partitions.h>
#include <asm/immap_cpm2.h>
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index e5c78463ebf..04ed34694b1 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -7,7 +7,6 @@
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index aa18d45b264..5b6acfcb2b8 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
@@ -63,22 +62,19 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
struct mtd_info *mtd = mfi->mtd;
switch (orig) {
- case 0:
- /* SEEK_SET */
+ case SEEK_SET:
break;
- case 1:
- /* SEEK_CUR */
+ case SEEK_CUR:
offset += file->f_pos;
break;
- case 2:
- /* SEEK_END */
+ case SEEK_END:
offset += mtd->size;
break;
default:
return -EINVAL;
}
- if (offset >= 0 && offset < mtd->size)
+ if (offset >= 0 && offset <= mtd->size)
return file->f_pos = offset;
return -EINVAL;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 16a952dd486..c4d26de7434 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -6,7 +6,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -58,6 +57,16 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->index = i;
mtd->usecount = 0;
+ /* Some chips always power up locked. Unlock them now */
+ if ((mtd->flags & MTD_WRITEABLE)
+ && (mtd->flags & MTD_STUPID_LOCK) && mtd->unlock) {
+ if (mtd->unlock(mtd, 0, mtd->size))
+ printk(KERN_WARNING
+ "%s: unlock failed, "
+ "writes may not work\n",
+ mtd->name);
+ }
+
DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
/* No need to get a refcount on the module containing
the notifier, since we hold the mtd_table_mutex */
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 77a7123a5c5..06a930372b7 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>
-#include <linux/config.h>
#include <linux/kmod.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 3db77eec0ed..c99302ed382 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -11,7 +11,7 @@ config MTD_NAND
help
This enables support for accessing all type of NAND flash
devices. For further information see
- <http://www.linux-mtd.infradead.org/tech/nand.html>.
+ <http://www.linux-mtd.infradead.org/doc/nand.html>.
config MTD_NAND_VERIFY_WRITE
bool "Verify NAND page writes"
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index d7897dc6b3c..a0ba07c36ee 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -130,11 +130,13 @@ static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
if (ctrl & NAND_CTRL_CHANGE) {
unsigned long bits;
- bits = (~ctrl & NAND_NCE) << 2;
- bits |= (ctrl & NAND_CLE) << 7;
- bits |= (ctrl & NAND_ALE) << 6;
+ bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0;
+ bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0;
+ bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0;
- ams_delta_latch2_write(0xC2, bits);
+ ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE |
+ AMS_DELTA_LATCH2_NAND_ALE |
+ AMS_DELTA_LATCH2_NAND_NCE, bits);
}
if (cmd != NAND_CMD_NONE)
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c
index 31228334da1..09e421a9689 100644
--- a/drivers/mtd/nand/au1550nd.c
+++ b/drivers/mtd/nand/au1550nd.c
@@ -21,18 +21,7 @@
#include <linux/version.h>
#include <asm/io.h>
-/* fixme: this is ugly */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)
#include <asm/mach-au1x00/au1xxx.h>
-#else
-#include <asm/au1000.h>
-#ifdef CONFIG_MIPS_PB1550
-#include <asm/pb1550.h>
-#endif
-#ifdef CONFIG_MIPS_DB1550
-#include <asm/db1x00.h>
-#endif
-#endif
/*
* MTD structure for NAND controller
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
index 516c0e5e564..12017f3c6bd 100644
--- a/drivers/mtd/nand/edb7312.c
+++ b/drivers/mtd/nand/edb7312.c
@@ -198,6 +198,9 @@ static void __exit ep7312_cleanup(void)
/* Release resources, unregister device */
nand_release(ap7312_mtd);
+ /* Release io resource */
+ iounmap((void *)this->IO_ADDR_R);
+
/* Free the MTD device structure */
kfree(ep7312_mtd);
}
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 27083ed0a01..975b2ef6112 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -155,7 +155,7 @@ static u16 nand_read_word(struct mtd_info *mtd)
/**
* nand_select_chip - [DEFAULT] control CE line
* @mtd: MTD device structure
- * @chip: chipnumber to select, -1 for deselect
+ * @chipnr: chipnumber to select, -1 for deselect
*
* Default select function for 1 chip devices.
*/
@@ -542,7 +542,6 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
* Send command to NAND device. This is the version for the new large page
* devices We dont have the separate regions as we have in the small page
* devices. We must emulate NAND_CMD_READOOB to keep the code compatible.
- *
*/
static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
int column, int page_addr)
@@ -656,7 +655,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
/**
* nand_get_device - [GENERIC] Get chip for selected access
- * @this: the nand chip descriptor
+ * @chip: the nand chip descriptor
* @mtd: MTD device structure
* @new_state: the state which is requested
*
@@ -696,13 +695,12 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
/**
* nand_wait - [DEFAULT] wait until the command is done
* @mtd: MTD device structure
- * @this: NAND chip structure
+ * @chip: NAND chip structure
*
* Wait for command done. This applies to erase and program only
* Erase can take up to 400ms and program up to 20ms according to
* general NAND and SmartMedia specs
- *
-*/
+ */
static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip)
{
@@ -896,6 +894,7 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_transfer_oob - [Internal] Transfer oob to client buffer
* @chip: nand chip structure
+ * @oob: oob destination address
* @ops: oob ops structure
*/
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
@@ -946,6 +945,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
*
* @mtd: MTD device structure
* @from: offset to read from
+ * @ops: oob ops structure
*
* Internal function. Called with chip held.
*/
@@ -1093,9 +1093,10 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
ret = nand_do_read_ops(mtd, from, &chip->ops);
+ *retlen = chip->ops.retlen;
+
nand_release_device(mtd);
- *retlen = chip->ops.retlen;
return ret;
}
@@ -1176,7 +1177,7 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
status = chip->waitfunc(mtd, chip);
- return status;
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
}
/**
@@ -1203,7 +1204,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
pos = steps * (eccsize + chunk);
steps = 0;
} else
- pos = eccsize + chunk;
+ pos = eccsize;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
for (i = 0; i < steps; i++) {
@@ -1271,10 +1272,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
buf = nand_transfer_oob(chip, buf, ops);
- readlen -= ops->ooblen;
- if (!readlen)
- break;
-
if (!(chip->options & NAND_NO_READRDY)) {
/*
* Apply delay or wait for ready/busy pin. Do this
@@ -1288,6 +1285,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
nand_wait_ready(mtd);
}
+ readlen -= ops->ooblen;
+ if (!readlen)
+ break;
+
/* Increment page address */
realpage++;
@@ -1566,7 +1567,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
bytes = min_t(size_t, len, free->length);
boffs = free->offset;
}
- memcpy(chip->oob_poi + woffs, oob, bytes);
+ memcpy(chip->oob_poi + boffs, oob, bytes);
oob += bytes;
}
return oob;
@@ -1610,13 +1611,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (!writelen)
return 0;
+ chipnr = (int)(to >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
+
/* Check, if it is write protected */
if (nand_check_wp(mtd))
return -EIO;
- chipnr = (int)(to >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
-
realpage = (int)(to >> chip->page_shift);
page = realpage & chip->pagemask;
blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
@@ -1691,9 +1692,10 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
ret = nand_do_write_ops(mtd, to, &chip->ops);
+ *retlen = chip->ops.retlen;
+
nand_release_device(mtd);
- *retlen = chip->ops.retlen;
return ret;
}
@@ -1760,7 +1762,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
/**
* nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
* @mtd: MTD device structure
- * @from: offset to read from
+ * @to: offset to write to
* @ops: oob operation description structure
*/
static int nand_write_oob(struct mtd_info *mtd, loff_t to,
@@ -2055,7 +2057,7 @@ static void nand_sync(struct mtd_info *mtd)
/**
* nand_block_isbad - [MTD Interface] Check if block at offset is bad
* @mtd: MTD device structure
- * @ofs: offset relative to mtd start
+ * @offs: offset relative to mtd start
*/
static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
@@ -2222,7 +2224,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
}
/* Try to identify manufacturer */
- for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_id++) {
+ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) {
if (nand_manuf_ids[maf_idx].id == *maf_id)
break;
}
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
index 2a163e4084d..dd438ca47d9 100644
--- a/drivers/mtd/nand/nand_ecc.c
+++ b/drivers/mtd/nand/nand_ecc.c
@@ -65,8 +65,7 @@ static const u_char nand_ecc_precalc_table[] = {
};
/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3 byte ECC code
- * for 256 byte block
+ * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block
* @mtd: MTD block structure
* @dat: raw data
* @ecc_code: buffer for ECC
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index ebd64abc8be..545ff252d81 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -25,7 +25,6 @@
* $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/module.h>
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c
index fe8d38514ba..039c759cfbf 100644
--- a/drivers/mtd/nand/ndfc.c
+++ b/drivers/mtd/nand/ndfc.c
@@ -61,15 +61,15 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
- struct nand_chip *chip = mtd->priv;
+ struct ndfc_controller *ndfc = &ndfc_ctrl;
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
- writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_CMD);
+ writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_CMD);
else
- writel(cmd & 0xFF, chip->IO_ADDR_W + NDFC_ALE);
+ writel(cmd & 0xFF, ndfc->ndfcbase + NDFC_ALE);
}
static int ndfc_ready(struct mtd_info *mtd)
@@ -168,7 +168,7 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd)
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 256;
chip->ecc.bytes = 3;
- chip->ecclayout = mtd->pl_chip->ecclayout;
+ chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout;
mtd->mtd.priv = chip;
mtd->mtd.owner = THIS_MODULE;
}
diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c
index 22fa65c12ab..eb7d4d443de 100644
--- a/drivers/mtd/nand/ppchameleonevb.c
+++ b/drivers/mtd/nand/ppchameleonevb.c
@@ -276,6 +276,7 @@ static int __init ppchameleonevb_init(void)
/* Scan to find existence of the device (it could not be mounted) */
if (nand_scan(ppchameleon_mtd, 1)) {
iounmap((void *)ppchameleon_fio_base);
+ ppchameleon_fio_base = NULL;
kfree(ppchameleon_mtd);
goto nand_evb_init;
}
@@ -314,6 +315,8 @@ static int __init ppchameleonevb_init(void)
ppchameleonevb_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
if (!ppchameleonevb_mtd) {
printk("Unable to allocate PPChameleonEVB NAND MTD device structure.\n");
+ if (ppchameleon_fio_base)
+ iounmap(ppchameleon_fio_base);
return -ENOMEM;
}
@@ -322,6 +325,8 @@ static int __init ppchameleonevb_init(void)
if (!ppchameleonevb_fio_base) {
printk("ioremap PPChameleonEVB NAND flash failed\n");
kfree(ppchameleonevb_mtd);
+ if (ppchameleon_fio_base)
+ iounmap(ppchameleon_fio_base);
return -EIO;
}
@@ -378,6 +383,8 @@ static int __init ppchameleonevb_init(void)
if (nand_scan(ppchameleonevb_mtd, 1)) {
iounmap((void *)ppchameleonevb_fio_base);
kfree(ppchameleonevb_mtd);
+ if (ppchameleon_fio_base)
+ iounmap(ppchameleon_fio_base);
return -ENXIO;
}
#ifdef CONFIG_MTD_PARTITIONS
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index 2c262fe03d8..ff5cef24d5b 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -63,8 +63,6 @@
#include <asm/arch/regs-nand.h>
#include <asm/arch/nand.h>
-#define PFX "s3c2410-nand: "
-
#ifdef CONFIG_MTD_NAND_S3C2410_HWECC
static int hardware_ecc = 1;
#else
@@ -99,6 +97,12 @@ struct s3c2410_nand_mtd {
int scan_res;
};
+enum s3c_cpu_type {
+ TYPE_S3C2410,
+ TYPE_S3C2412,
+ TYPE_S3C2440,
+};
+
/* overview of the s3c2410 nand state */
struct s3c2410_nand_info {
@@ -112,9 +116,11 @@ struct s3c2410_nand_info {
struct resource *area;
struct clk *clk;
void __iomem *regs;
+ void __iomem *sel_reg;
+ int sel_bit;
int mtd_count;
- unsigned char is_s3c2440;
+ enum s3c_cpu_type cpu_type;
};
/* conversion functions */
@@ -148,7 +154,7 @@ static inline int allow_clk_stop(struct s3c2410_nand_info *info)
#define NS_IN_KHZ 1000000
-static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
+static int s3c_nand_calc_rate(int wanted, unsigned long clk, int max)
{
int result;
@@ -172,53 +178,58 @@ static int s3c2410_nand_calc_rate(int wanted, unsigned long clk, int max)
/* controller setup */
-static int s3c2410_nand_inithw(struct s3c2410_nand_info *info, struct platform_device *pdev)
+static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
+ struct platform_device *pdev)
{
struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
unsigned long clkrate = clk_get_rate(info->clk);
+ int tacls_max = (info->cpu_type == TYPE_S3C2412) ? 8 : 4;
int tacls, twrph0, twrph1;
- unsigned long cfg;
+ unsigned long cfg = 0;
/* calculate the timing information for the controller */
clkrate /= 1000; /* turn clock into kHz for ease of use */
if (plat != NULL) {
- tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
- twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
- twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
+ tacls = s3c_nand_calc_rate(plat->tacls, clkrate, tacls_max);
+ twrph0 = s3c_nand_calc_rate(plat->twrph0, clkrate, 8);
+ twrph1 = s3c_nand_calc_rate(plat->twrph1, clkrate, 8);
} else {
/* default timings */
- tacls = 4;
+ tacls = tacls_max;
twrph0 = 8;
twrph1 = 8;
}
if (tacls < 0 || twrph0 < 0 || twrph1 < 0) {
- printk(KERN_ERR PFX "cannot get timings suitable for board\n");
+ dev_err(info->device, "cannot get suitable timings\n");
return -EINVAL;
}
- printk(KERN_INFO PFX "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
+ dev_info(info->device, "Tacls=%d, %dns Twrph0=%d %dns, Twrph1=%d %dns\n",
tacls, to_ns(tacls, clkrate), twrph0, to_ns(twrph0, clkrate), twrph1, to_ns(twrph1, clkrate));
- if (!info->is_s3c2440) {
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
cfg = S3C2410_NFCONF_EN;
cfg |= S3C2410_NFCONF_TACLS(tacls - 1);
cfg |= S3C2410_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2410_NFCONF_TWRPH1(twrph1 - 1);
- } else {
+ break;
+
+ case TYPE_S3C2440:
+ case TYPE_S3C2412:
cfg = S3C2440_NFCONF_TACLS(tacls - 1);
cfg |= S3C2440_NFCONF_TWRPH0(twrph0 - 1);
cfg |= S3C2440_NFCONF_TWRPH1(twrph1 - 1);
/* enable the controller and de-assert nFCE */
- writel(S3C2440_NFCONT_ENABLE | S3C2440_NFCONT_ENABLE,
- info->regs + S3C2440_NFCONT);
+ writel(S3C2440_NFCONT_ENABLE, info->regs + S3C2440_NFCONT);
}
- pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
+ dev_dbg(info->device, "NF_CONF is 0x%lx\n", cfg);
writel(cfg, info->regs + S3C2410_NFCONF);
return 0;
@@ -231,26 +242,21 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
struct nand_chip *this = mtd->priv;
- void __iomem *reg;
unsigned long cur;
- unsigned long bit;
nmtd = this->priv;
info = nmtd->info;
- bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
- reg = info->regs + ((info->is_s3c2440) ? S3C2440_NFCONT : S3C2410_NFCONF);
-
if (chip != -1 && allow_clk_stop(info))
clk_enable(info->clk);
- cur = readl(reg);
+ cur = readl(info->sel_reg);
if (chip == -1) {
- cur |= bit;
+ cur |= info->sel_bit;
} else {
if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
- printk(KERN_ERR PFX "chip %d out of range\n", chip);
+ dev_err(info->device, "invalid chip %d\n", chip);
return;
}
@@ -259,10 +265,10 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
(info->platform->select_chip) (nmtd->set, chip);
}
- cur &= ~bit;
+ cur &= ~info->sel_bit;
}
- writel(cur, reg);
+ writel(cur, info->sel_reg);
if (chip == -1 && allow_clk_stop(info))
clk_disable(info->clk);
@@ -311,15 +317,25 @@ static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd,
static int s3c2410_nand_devready(struct mtd_info *mtd)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
-
- if (info->is_s3c2440)
- return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
}
+static int s3c2440_nand_devready(struct mtd_info *mtd)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
+}
+
+static int s3c2412_nand_devready(struct mtd_info *mtd)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ return readb(info->regs + S3C2412_NFSTAT) & S3C2412_NFSTAT_READY;
+}
+
/* ECC handling functions */
-static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
+ u_char *read_ecc, u_char *calc_ecc)
{
pr_debug("s3c2410_nand_correct_data(%p,%p,%p,%p)\n", mtd, dat, read_ecc, calc_ecc);
@@ -487,11 +503,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
struct s3c2410_nand_set *set)
{
struct nand_chip *chip = &nmtd->chip;
+ void __iomem *regs = info->regs;
- chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
- chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
- chip->cmd_ctrl = s3c2410_nand_hwcontrol;
- chip->dev_ready = s3c2410_nand_devready;
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
@@ -500,11 +513,37 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->options = 0;
chip->controller = &info->controller;
- if (info->is_s3c2440) {
- chip->IO_ADDR_R = info->regs + S3C2440_NFDATA;
- chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
- chip->cmd_ctrl = s3c2440_nand_hwcontrol;
- }
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
+ chip->IO_ADDR_W = regs + S3C2410_NFDATA;
+ info->sel_reg = regs + S3C2410_NFCONF;
+ info->sel_bit = S3C2410_NFCONF_nFCE;
+ chip->cmd_ctrl = s3c2410_nand_hwcontrol;
+ chip->dev_ready = s3c2410_nand_devready;
+ break;
+
+ case TYPE_S3C2440:
+ chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+ info->sel_reg = regs + S3C2440_NFCONT;
+ info->sel_bit = S3C2440_NFCONT_nFCE;
+ chip->cmd_ctrl = s3c2440_nand_hwcontrol;
+ chip->dev_ready = s3c2440_nand_devready;
+ break;
+
+ case TYPE_S3C2412:
+ chip->IO_ADDR_W = regs + S3C2440_NFDATA;
+ info->sel_reg = regs + S3C2440_NFCONT;
+ info->sel_bit = S3C2412_NFCONT_nFCE0;
+ chip->cmd_ctrl = s3c2440_nand_hwcontrol;
+ chip->dev_ready = s3c2412_nand_devready;
+
+ if (readl(regs + S3C2410_NFCONF) & S3C2412_NFCONF_NANDBOOT)
+ dev_info(info->device, "System booted from NAND\n");
+
+ break;
+ }
+
+ chip->IO_ADDR_R = chip->IO_ADDR_W;
nmtd->info = info;
nmtd->mtd.priv = chip;
@@ -512,17 +551,25 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
nmtd->set = set;
if (hardware_ecc) {
- chip->ecc.correct = s3c2410_nand_correct_data;
- chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ chip->ecc.correct = s3c2410_nand_correct_data;
chip->ecc.mode = NAND_ECC_HW;
chip->ecc.size = 512;
chip->ecc.bytes = 3;
chip->ecc.layout = &nand_hw_eccoob;
- if (info->is_s3c2440) {
- chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
- chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+ switch (info->cpu_type) {
+ case TYPE_S3C2410:
+ chip->ecc.hwctl = s3c2410_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2410_nand_calculate_ecc;
+ break;
+
+ case TYPE_S3C2412:
+ case TYPE_S3C2440:
+ chip->ecc.hwctl = s3c2440_nand_enable_hwecc;
+ chip->ecc.calculate = s3c2440_nand_calculate_ecc;
+ break;
+
}
} else {
chip->ecc.mode = NAND_ECC_SOFT;
@@ -537,7 +584,8 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
* nand layer to look for devices
*/
-static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
+static int s3c24xx_nand_probe(struct platform_device *pdev,
+ enum s3c_cpu_type cpu_type)
{
struct s3c2410_platform_nand *plat = to_nand_plat(pdev);
struct s3c2410_nand_info *info;
@@ -592,7 +640,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev, int is_s3c2440)
info->device = &pdev->dev;
info->platform = plat;
info->regs = ioremap(res->start, size);
- info->is_s3c2440 = is_s3c2440;
+ info->cpu_type = cpu_type;
if (info->regs == NULL) {
dev_err(&pdev->dev, "cannot reserve register region\n");
@@ -699,12 +747,17 @@ static int s3c24xx_nand_resume(struct platform_device *dev)
static int s3c2410_nand_probe(struct platform_device *dev)
{
- return s3c24xx_nand_probe(dev, 0);
+ return s3c24xx_nand_probe(dev, TYPE_S3C2410);
}
static int s3c2440_nand_probe(struct platform_device *dev)
{
- return s3c24xx_nand_probe(dev, 1);
+ return s3c24xx_nand_probe(dev, TYPE_S3C2440);
+}
+
+static int s3c2412_nand_probe(struct platform_device *dev)
+{
+ return s3c24xx_nand_probe(dev, TYPE_S3C2412);
}
static struct platform_driver s3c2410_nand_driver = {
@@ -729,16 +782,29 @@ static struct platform_driver s3c2440_nand_driver = {
},
};
+static struct platform_driver s3c2412_nand_driver = {
+ .probe = s3c2412_nand_probe,
+ .remove = s3c2410_nand_remove,
+ .suspend = s3c24xx_nand_suspend,
+ .resume = s3c24xx_nand_resume,
+ .driver = {
+ .name = "s3c2412-nand",
+ .owner = THIS_MODULE,
+ },
+};
+
static int __init s3c2410_nand_init(void)
{
printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
+ platform_driver_register(&s3c2412_nand_driver);
platform_driver_register(&s3c2440_nand_driver);
return platform_driver_register(&s3c2410_nand_driver);
}
static void __exit s3c2410_nand_exit(void)
{
+ platform_driver_unregister(&s3c2412_nand_driver);
platform_driver_unregister(&s3c2440_nand_driver);
platform_driver_unregister(&s3c2410_nand_driver);
}
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 21743658d15..51c7288ab49 100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -78,7 +78,7 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = {
/*
* hardware specific access to control-lines
* ctrl:
- * NAND_CNE: bit 0 -> bit 0 & 4
+ * NAND_CNE: bit 0 -> ! bit 0 & 4
* NAND_CLE: bit 1 -> bit 1
* NAND_ALE: bit 2 -> bit 2
*
@@ -92,7 +92,10 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned char bits = ctrl & 0x07;
bits |= (ctrl & 0x01) << 4;
- writeb((readb(FLASHCTL) & 0x17) | bits, FLASHCTL);
+
+ bits ^= 0x11;
+
+ writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL);
}
if (cmd != NAND_CMD_NONE)
@@ -237,11 +240,6 @@ static int __init sharpsl_nand_init(void)
}
}
- if (machine_is_husky() || machine_is_borzoi() || machine_is_akita()) {
- /* Need to use small eraseblock size for backward compatibility */
- sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS;
- }
-
add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
/* Return happy */
@@ -255,8 +253,6 @@ module_init(sharpsl_nand_init);
*/
static void __exit sharpsl_nand_cleanup(void)
{
- struct nand_chip *this = (struct nand_chip *)&sharpsl_mtd[1];
-
/* Release resources, unregister device */
nand_release(sharpsl_mtd);
diff --git a/drivers/mtd/nand/ts7250.c b/drivers/mtd/nand/ts7250.c
index a0b4b1edcb0..f40081069ab 100644
--- a/drivers/mtd/nand/ts7250.c
+++ b/drivers/mtd/nand/ts7250.c
@@ -97,7 +97,7 @@ static void ts7250_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
unsigned long addr = TS72XX_NAND_CONTROL_VIRT_BASE;
unsigned char bits;
- bits = (ctrl & NAND_CNE) << 2;
+ bits = (ctrl & NAND_NCE) << 2;
bits |= ctrl & NAND_CLE;
bits |= (ctrl & NAND_ALE) >> 2;
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index dc7573501d8..dd5cea8b4a7 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -11,7 +11,6 @@
#define PRERELEASE
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/errno.h>
diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c
new file mode 100644
index 00000000000..79d3bb659bf
--- /dev/null
+++ b/drivers/mtd/ssfdc.c
@@ -0,0 +1,474 @@
+/*
+ * Linux driver for SSFDC Flash Translation Layer (Read only)
+ * (c) 2005 Eptar srl
+ * Author: Claudio Lanconelli <lanconelli.claudio@eptar.com>
+ *
+ * Based on NTFL and MTDBLOCK_RO drivers
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/hdreg.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/blktrans.h>
+
+struct ssfdcr_record {
+ struct mtd_blktrans_dev mbd;
+ int usecount;
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ int cis_block; /* block n. containing CIS/IDI */
+ int erase_size; /* phys_block_size */
+ unsigned short *logic_block_map; /* all zones (max 8192 phys blocks on
+ the 128MiB) */
+ int map_len; /* n. phys_blocks on the card */
+};
+
+#define SSFDCR_MAJOR 257
+#define SSFDCR_PARTN_BITS 3
+
+#define SECTOR_SIZE 512
+#define SECTOR_SHIFT 9
+#define OOB_SIZE 16
+
+#define MAX_LOGIC_BLK_PER_ZONE 1000
+#define MAX_PHYS_BLK_PER_ZONE 1024
+
+#define KiB(x) ( (x) * 1024L )
+#define MiB(x) ( KiB(x) * 1024L )
+
+/** CHS Table
+ 1MiB 2MiB 4MiB 8MiB 16MiB 32MiB 64MiB 128MiB
+NCylinder 125 125 250 250 500 500 500 500
+NHead 4 4 4 4 4 8 8 16
+NSector 4 8 8 16 16 16 32 32
+SumSector 2,000 4,000 8,000 16,000 32,000 64,000 128,000 256,000
+SectorSize 512 512 512 512 512 512 512 512
+**/
+
+typedef struct {
+ unsigned long size;
+ unsigned short cyl;
+ unsigned char head;
+ unsigned char sec;
+} chs_entry_t;
+
+/* Must be ordered by size */
+static const chs_entry_t chs_table[] = {
+ { MiB( 1), 125, 4, 4 },
+ { MiB( 2), 125, 4, 8 },
+ { MiB( 4), 250, 4, 8 },
+ { MiB( 8), 250, 4, 16 },
+ { MiB( 16), 500, 4, 16 },
+ { MiB( 32), 500, 8, 16 },
+ { MiB( 64), 500, 8, 32 },
+ { MiB(128), 500, 16, 32 },
+ { 0 },
+};
+
+static int get_chs(unsigned long size, unsigned short *cyl, unsigned char *head,
+ unsigned char *sec)
+{
+ int k;
+ int found = 0;
+
+ k = 0;
+ while (chs_table[k].size > 0 && size > chs_table[k].size)
+ k++;
+
+ if (chs_table[k].size > 0) {
+ if (cyl)
+ *cyl = chs_table[k].cyl;
+ if (head)
+ *head = chs_table[k].head;
+ if (sec)
+ *sec = chs_table[k].sec;
+ found = 1;
+ }
+
+ return found;
+}
+
+/* These bytes are the signature for the CIS/IDI sector */
+static const uint8_t cis_numbers[] = {
+ 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
+};
+
+/* Read and check for a valid CIS sector */
+static int get_valid_cis_sector(struct mtd_info *mtd)
+{
+ int ret, k, cis_sector;
+ size_t retlen;
+ loff_t offset;
+ uint8_t *sect_buf;
+
+ cis_sector = -1;
+
+ sect_buf = kmalloc(SECTOR_SIZE, GFP_KERNEL);
+ if (!sect_buf)
+ goto out;
+
+ /*
+ * Look for CIS/IDI sector on the first GOOD block (give up after 4 bad
+ * blocks). If the first good block doesn't contain CIS number the flash
+ * is not SSFDC formatted
+ */
+ for (k = 0, offset = 0; k < 4; k++, offset += mtd->erasesize) {
+ if (!mtd->block_isbad(mtd, offset)) {
+ ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen,
+ sect_buf);
+
+ /* CIS pattern match on the sector buffer */
+ if (ret < 0 || retlen != SECTOR_SIZE) {
+ printk(KERN_WARNING
+ "SSFDC_RO:can't read CIS/IDI sector\n");
+ } else if (!memcmp(sect_buf, cis_numbers,
+ sizeof(cis_numbers))) {
+ /* Found */
+ cis_sector = (int)(offset >> SECTOR_SHIFT);
+ } else {
+ DEBUG(MTD_DEBUG_LEVEL1,
+ "SSFDC_RO: CIS/IDI sector not found"
+ " on %s (mtd%d)\n", mtd->name,
+ mtd->index);
+ }
+ break;
+ }
+ }
+
+ kfree(sect_buf);
+ out:
+ return cis_sector;
+}
+
+/* Read physical sector (wrapper to MTD_READ) */
+static int read_physical_sector(struct mtd_info *mtd, uint8_t *sect_buf,
+ int sect_no)
+{
+ int ret;
+ size_t retlen;
+ loff_t offset = (loff_t)sect_no << SECTOR_SHIFT;
+
+ ret = mtd->read(mtd, offset, SECTOR_SIZE, &retlen, sect_buf);
+ if (ret < 0 || retlen != SECTOR_SIZE)
+ return -1;
+
+ return 0;
+}
+
+/* Read redundancy area (wrapper to MTD_READ_OOB */
+static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)
+{
+ struct mtd_oob_ops ops;
+ int ret;
+
+ ops.mode = MTD_OOB_RAW;
+ ops.ooboffs = 0;
+ ops.ooblen = mtd->oobsize;
+ ops.len = OOB_SIZE;
+ ops.oobbuf = buf;
+ ops.datbuf = NULL;
+
+ ret = mtd->read_oob(mtd, offs, &ops);
+ if (ret < 0 || ops.retlen != OOB_SIZE)
+ return -1;
+
+ return 0;
+}
+
+/* Parity calculator on a word of n bit size */
+static int get_parity(int number, int size)
+{
+ int k;
+ int parity;
+
+ parity = 1;
+ for (k = 0; k < size; k++) {
+ parity += (number >> k);
+ parity &= 1;
+ }
+ return parity;
+}
+
+/* Read and validate the logical block address field stored in the OOB */
+static int get_logical_address(uint8_t *oob_buf)
+{
+ int block_address, parity;
+ int offset[2] = {6, 11}; /* offset of the 2 address fields within OOB */
+ int j;
+ int ok = 0;
+
+ /*
+ * Look for the first valid logical address
+ * Valid address has fixed pattern on most significant bits and
+ * parity check
+ */
+ for (j = 0; j < ARRAY_SIZE(offset); j++) {
+ block_address = ((int)oob_buf[offset[j]] << 8) |
+ oob_buf[offset[j]+1];
+
+ /* Check for the signature bits in the address field (MSBits) */
+ if ((block_address & ~0x7FF) == 0x1000) {
+ parity = block_address & 0x01;
+ block_address &= 0x7FF;
+ block_address >>= 1;
+
+ if (get_parity(block_address, 10) != parity) {
+ DEBUG(MTD_DEBUG_LEVEL0,
+ "SSFDC_RO: logical address field%d"
+ "parity error(0x%04X)\n", j+1,
+ block_address);
+ } else {
+ ok = 1;
+ break;
+ }
+ }
+ }
+
+ if (!ok)
+ block_address = -2;
+
+ DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n",
+ block_address);
+
+ return block_address;
+}
+
+/* Build the logic block map */
+static int build_logical_block_map(struct ssfdcr_record *ssfdc)
+{
+ unsigned long offset;
+ uint8_t oob_buf[OOB_SIZE];
+ int ret, block_address, phys_block;
+ struct mtd_info *mtd = ssfdc->mbd.mtd;
+
+ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n",
+ ssfdc->map_len,
+ (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024);
+
+ /* Scan every physical block, skip CIS block */
+ for (phys_block = ssfdc->cis_block + 1; phys_block < ssfdc->map_len;
+ phys_block++) {
+ offset = (unsigned long)phys_block * ssfdc->erase_size;
+ if (mtd->block_isbad(mtd, offset))
+ continue; /* skip bad blocks */
+
+ ret = read_raw_oob(mtd, offset, oob_buf);
+ if (ret < 0) {
+ DEBUG(MTD_DEBUG_LEVEL0,
+ "SSFDC_RO: mtd read_oob() failed at %lu\n",
+ offset);
+ return -1;
+ }
+ block_address = get_logical_address(oob_buf);
+
+ /* Skip invalid addresses */
+ if (block_address >= 0 &&
+ block_address < MAX_LOGIC_BLK_PER_ZONE) {
+ int zone_index;
+
+ zone_index = phys_block / MAX_PHYS_BLK_PER_ZONE;
+ block_address += zone_index * MAX_LOGIC_BLK_PER_ZONE;
+ ssfdc->logic_block_map[block_address] =
+ (unsigned short)phys_block;
+
+ DEBUG(MTD_DEBUG_LEVEL2,
+ "SSFDC_RO: build_block_map() phys_block=%d,"
+ "logic_block_addr=%d, zone=%d\n",
+ phys_block, block_address, zone_index);
+ }
+ }
+ return 0;
+}
+
+static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
+{
+ struct ssfdcr_record *ssfdc;
+ int cis_sector;
+
+ /* Check for small page NAND flash */
+ if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE)
+ return;
+
+ /* Check for SSDFC format by reading CIS/IDI sector */
+ cis_sector = get_valid_cis_sector(mtd);
+ if (cis_sector == -1)
+ return;
+
+ ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL);
+ if (!ssfdc) {
+ printk(KERN_WARNING
+ "SSFDC_RO: out of memory for data structures\n");
+ return;
+ }
+
+ ssfdc->mbd.mtd = mtd;
+ ssfdc->mbd.devnum = -1;
+ ssfdc->mbd.blksize = SECTOR_SIZE;
+ ssfdc->mbd.tr = tr;
+ ssfdc->mbd.readonly = 1;
+
+ ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT);
+ ssfdc->erase_size = mtd->erasesize;
+ ssfdc->map_len = mtd->size / mtd->erasesize;
+
+ DEBUG(MTD_DEBUG_LEVEL1,
+ "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n",
+ ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len,
+ (ssfdc->map_len + MAX_PHYS_BLK_PER_ZONE - 1) /
+ MAX_PHYS_BLK_PER_ZONE);
+
+ /* Set geometry */
+ ssfdc->heads = 16;
+ ssfdc->sectors = 32;
+ get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors);
+ ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) /
+ ((long)ssfdc->sectors * (long)ssfdc->heads));
+
+ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n",
+ ssfdc->cylinders, ssfdc->heads , ssfdc->sectors,
+ (long)ssfdc->cylinders * (long)ssfdc->heads *
+ (long)ssfdc->sectors);
+
+ ssfdc->mbd.size = (long)ssfdc->heads * (long)ssfdc->cylinders *
+ (long)ssfdc->sectors;
+
+ /* Allocate logical block map */
+ ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) *
+ ssfdc->map_len, GFP_KERNEL);
+ if (!ssfdc->logic_block_map) {
+ printk(KERN_WARNING
+ "SSFDC_RO: out of memory for data structures\n");
+ goto out_err;
+ }
+ memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) *
+ ssfdc->map_len);
+
+ /* Build logical block map */
+ if (build_logical_block_map(ssfdc) < 0)
+ goto out_err;
+
+ /* Register device + partitions */
+ if (add_mtd_blktrans_dev(&ssfdc->mbd))
+ goto out_err;
+
+ printk(KERN_INFO "SSFDC_RO: Found ssfdc%c on mtd%d (%s)\n",
+ ssfdc->mbd.devnum + 'a', mtd->index, mtd->name);
+ return;
+
+out_err:
+ kfree(ssfdc->logic_block_map);
+ kfree(ssfdc);
+}
+
+static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev)
+{
+ struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
+
+ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum);
+
+ del_mtd_blktrans_dev(dev);
+ kfree(ssfdc->logic_block_map);
+ kfree(ssfdc);
+}
+
+static int ssfdcr_readsect(struct mtd_blktrans_dev *dev,
+ unsigned long logic_sect_no, char *buf)
+{
+ struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
+ int sectors_per_block, offset, block_address;
+
+ sectors_per_block = ssfdc->erase_size >> SECTOR_SHIFT;
+ offset = (int)(logic_sect_no % sectors_per_block);
+ block_address = (int)(logic_sect_no / sectors_per_block);
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d,"
+ " block_addr=%d\n", logic_sect_no, sectors_per_block, offset,
+ block_address);
+
+ if (block_address >= ssfdc->map_len)
+ BUG();
+
+ block_address = ssfdc->logic_block_map[block_address];
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n",
+ block_address);
+
+ if (block_address < 0xffff) {
+ unsigned long sect_no;
+
+ sect_no = (unsigned long)block_address * sectors_per_block +
+ offset;
+
+ DEBUG(MTD_DEBUG_LEVEL3,
+ "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n",
+ sect_no);
+
+ if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0)
+ return -EIO;
+ } else {
+ memset(buf, 0xff, SECTOR_SIZE);
+ }
+
+ return 0;
+}
+
+static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
+{
+ struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev;
+
+ DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n",
+ ssfdc->cylinders, ssfdc->heads, ssfdc->sectors);
+
+ geo->heads = ssfdc->heads;
+ geo->sectors = ssfdc->sectors;
+ geo->cylinders = ssfdc->cylinders;
+
+ return 0;
+}
+
+/****************************************************************************
+ *
+ * Module stuff
+ *
+ ****************************************************************************/
+
+static struct mtd_blktrans_ops ssfdcr_tr = {
+ .name = "ssfdc",
+ .major = SSFDCR_MAJOR,
+ .part_bits = SSFDCR_PARTN_BITS,
+ .getgeo = ssfdcr_getgeo,
+ .readsect = ssfdcr_readsect,
+ .add_mtd = ssfdcr_add_mtd,
+ .remove_dev = ssfdcr_remove_dev,
+ .owner = THIS_MODULE,
+};
+
+static int __init init_ssfdcr(void)
+{
+ printk(KERN_INFO "SSFDC read-only Flash Translation layer\n");
+
+ return register_mtd_blktrans(&ssfdcr_tr);
+}
+
+static void __exit cleanup_ssfdcr(void)
+{
+ deregister_mtd_blktrans(&ssfdcr_tr);
+}
+
+module_init(init_ssfdcr);
+module_exit(cleanup_ssfdcr);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Claudio Lanconelli <lanconelli.claudio@eptar.com>");
+MODULE_DESCRIPTION("Flash Translation Layer for read-only SSFDC SmartMedia card");
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index bb44509fd40..1b82bccd8c7 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -30,17 +30,17 @@
with a TX-TX optimisation to see if we can touch 180-200K/second as seems
theoretically maximum.
19950402 Alan Cox <Alan.Cox@linux.org>
-
- Cleaned up for 2.3.x because we broke SMP now.
+
+ Cleaned up for 2.3.x because we broke SMP now.
20000208 Alan Cox <alan@redhat.com>
Check up pass for 2.5. Nothing significant changed
20021009 Alan Cox <alan@redhat.com>
- Fixed zero fill corner case
+ Fixed zero fill corner case
20030104 Alan Cox <alan@redhat.com>
-
-
+
+
For the avoidance of doubt the "preferred form" of this code is one which
is in an open non patent encumbered format. Where cryptographic key signing
forms part of the process of creating an executable the information
@@ -58,7 +58,7 @@
* Some documentation is available from 3Com. Due to the boards age
* standard responses when you ask for this will range from 'be serious'
* to 'give it to a museum'. The documentation is incomplete and mostly
- * of historical interest anyway.
+ * of historical interest anyway.
*
* The basic system is a single buffer which can be used to receive or
* transmit a packet. A third command mode exists when you are setting
@@ -80,7 +80,7 @@
* out with those too).
*
* DOC: Problems
- *
+ *
* There are a wide variety of undocumented error returns from the card
* and you basically have to kick the board and pray if they turn up. Most
* only occur under extreme load or if you do something the board doesn't
@@ -120,7 +120,6 @@ static const char version[] =
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/config.h> /* for CONFIG_IP_MULTICAST */
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/delay.h>
@@ -146,7 +145,7 @@ static int mem_start;
/**
* el1_probe: - probe for a 3c501
- * @dev: The device structure passed in to probe.
+ * @dev: The device structure passed in to probe.
*
* This can be called from two places. The network layer will probe using
* a device structure passed in with the probe information completed. For a
@@ -156,7 +155,7 @@ static int mem_start;
* Returns 0 on success. ENXIO if asked not to probe and ENODEV if asked to
* probe and failing to find anything.
*/
-
+
struct net_device * __init el1_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
@@ -201,7 +200,7 @@ out:
}
/**
- * el1_probe1:
+ * el1_probe1:
* @dev: The device structure to use
* @ioaddr: An I/O address to probe at.
*
@@ -308,7 +307,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
memset(dev->priv, 0, sizeof(struct net_local));
lp = netdev_priv(dev);
spin_lock_init(&lp->lock);
-
+
/*
* The EL1-specific entries in the device structure.
*/
@@ -329,7 +328,7 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr)
* @dev: device that is being opened
*
* When an ifconfig is issued which changes the device flags to include
- * IFF_UP this function is called. It is only called when the change
+ * IFF_UP this function is called. It is only called when the change
* occurs, not when the interface remains up. #el1_close will be called
* when it goes down.
*
@@ -368,12 +367,12 @@ static int el_open(struct net_device *dev)
* violence and prayer
*
*/
-
+
static void el_timeout(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
-
+
if (el_debug)
printk (KERN_DEBUG "%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
@@ -386,7 +385,7 @@ static void el_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
-
+
/**
* el_start_xmit:
* @skb: The packet that is queued to be sent
@@ -422,7 +421,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
spin_lock_irqsave(&lp->lock, flags);
-
+
/*
* Avoid timer-based retransmission conflicts.
*/
@@ -435,10 +434,10 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
int pad = 0;
int gp_start;
unsigned char *buf = skb->data;
-
+
if (len < ETH_ZLEN)
pad = ETH_ZLEN - len;
-
+
gp_start = 0x800 - ( len + pad );
lp->tx_pkt_start = gp_start;
@@ -464,7 +463,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
spin_unlock_irqrestore(&lp->lock, flags);
-
+
outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */
outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */
outsb(DATAPORT,buf,len); /* load buffer (usual thing each byte increments the pointer) */
@@ -473,7 +472,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
outb(0, DATAPORT);
}
outw(gp_start, GP_LOW); /* the board reuses the same register */
-
+
if(lp->loading != 2)
{
outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */
@@ -499,7 +498,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
* @dev_id: The 3c501 that burped
* @regs: Register data (surplus to our requirements)
*
- * Handle the ether interface interrupts. The 3c501 needs a lot more
+ * Handle the ether interface interrupts. The 3c501 needs a lot more
* hand holding than most cards. In particular we get a transmit interrupt
* with a collision error because the board firmware isnt capable of rewinding
* its own transmit buffer pointers. It can however count to 16 for us.
@@ -508,11 +507,11 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
* speak of. We simply pull the packet out of its PIO buffer (which is slow)
* and queue it for the kernel. Then we reset the card for the next packet.
*
- * We sometimes get suprise interrupts late both because the SMP IRQ delivery
+ * We sometimes get surprise interrupts late both because the SMP IRQ delivery
* is message passing and because the card sometimes seems to deliver late. I
* think if it is part way through a receive and the mode is changed it carries
* on receiving and sends us an interrupt. We have to band aid all these cases
- * to get a sensible 150kbytes/second performance. Even then you want a small
+ * to get a sensible 150kBytes/second performance. Even then you want a small
* TCP window.
*/
@@ -527,7 +526,7 @@ static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp = netdev_priv(dev);
spin_lock(&lp->lock);
-
+
/*
* What happened ?
*/
@@ -795,7 +794,7 @@ static void el_reset(struct net_device *dev)
* of the rest will be cleaned up by #el1_open. Always returns 0 indicating
* a success.
*/
-
+
static int el1_close(struct net_device *dev)
{
int ioaddr = dev->base_addr;
@@ -804,7 +803,7 @@ static int el1_close(struct net_device *dev)
printk(KERN_INFO "%s: Shutting down Ethernet card at %#x.\n", dev->name, ioaddr);
netif_stop_queue(dev);
-
+
/*
* Free and disable the IRQ.
*/
@@ -825,7 +824,7 @@ static int el1_close(struct net_device *dev)
*
* Returns the statistics for the card from the card private data
*/
-
+
static struct net_device_stats *el1_get_stats(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
@@ -836,7 +835,7 @@ static struct net_device_stats *el1_get_stats(struct net_device *dev)
* set_multicast_list:
* @dev: The device to adjust
*
- * Set or clear the multicast filter for this adaptor to use the best-effort
+ * Set or clear the multicast filter for this adaptor to use the best-effort
* filtering supported. The 3c501 supports only three modes of filtering.
* It always receives broadcasts and packets for itself. You can choose to
* optionally receive all packets, or all multicast packets on top of this.
@@ -882,7 +881,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
debug = level;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
@@ -908,7 +907,7 @@ MODULE_PARM_DESC(irq, "EtherLink IRQ number");
* Returns 0 for success or -EIO if a card is not found. Returning an error
* here also causes the module to be unloaded
*/
-
+
int __init init_module(void)
{
dev_3c501 = el1_probe(-1);
@@ -919,11 +918,11 @@ int __init init_module(void)
/**
* cleanup_module:
- *
+ *
* The module is being unloaded. We unhook our network device from the system
* and then free up the resources we took when the card was found.
*/
-
+
void cleanup_module(void)
{
struct net_device *dev = dev_3c501;
diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
index adb0588a4d7..39d33247475 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/3c501.h
@@ -13,7 +13,7 @@ static void el_reset(struct net_device *dev);
static int el1_close(struct net_device *dev);
static struct net_device_stats *el1_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
#define EL1_IO_EXTENT 16
@@ -37,7 +37,7 @@ struct net_local
spinlock_t lock; /* Serializing lock */
};
-
+
#define RX_STATUS (ioaddr + 0x06)
#define RX_CMD RX_STATUS
#define TX_STATUS (ioaddr + 0x07)
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index cb5ef75450d..a34b2206132 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -79,9 +79,9 @@ static void el2_block_input(struct net_device *dev, int count, struct sk_buff *s
int ring_offset);
static void el2_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
+
-
/* This routine probes for a memory-mapped 3c503 board by looking for
the "location register" at the end of the jumpered boot PROM space.
This works even if a PROM isn't there.
@@ -96,7 +96,7 @@ static int __init do_el2_probe(struct net_device *dev)
int irq = dev->irq;
SET_MODULE_OWNER(dev);
-
+
if (base_addr > 0x1ff) /* Check a single specified location. */
return el2_probe1(dev, base_addr);
else if (base_addr != 0) /* Don't probe at all. */
@@ -127,7 +127,7 @@ static int __init do_el2_probe(struct net_device *dev)
/* Try all of the locations that aren't obviously empty. This touches
a lot of locations, and is much riskier than the code above. */
-static int __init
+static int __init
el2_pio_probe(struct net_device *dev)
{
int i;
@@ -173,7 +173,7 @@ out:
/* Probe for the Etherlink II card at I/O port base IOADDR,
returning non-zero on success. If found, set the station
address and memory parameters in DEVICE. */
-static int __init
+static int __init
el2_probe1(struct net_device *dev, int ioaddr)
{
int i, iobase_reg, membase_reg, saved_406, wordlength, retval;
@@ -367,7 +367,7 @@ out:
release_region(ioaddr, EL2_IO_EXTENT);
return retval;
}
-
+
static int
el2_open(struct net_device *dev)
{
@@ -385,7 +385,7 @@ el2_open(struct net_device *dev)
outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR);
if (*irqp == probe_irq_off(cookie) /* It's a good IRQ line! */
- && ((retval = request_irq(dev->irq = *irqp,
+ && ((retval = request_irq(dev->irq = *irqp,
ei_interrupt, 0, dev->name, dev)) == 0))
break;
}
@@ -666,7 +666,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
sprintf(info->bus_info, "ISA 0x%lx", dev->base_addr);
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
diff --git a/drivers/net/3c503.h b/drivers/net/3c503.h
index b9f8a46f89b..e2367b82a2e 100644
--- a/drivers/net/3c503.h
+++ b/drivers/net/3c503.h
@@ -14,7 +14,7 @@
/* Shared memory management parameters. NB: The 8 bit cards have only
one bank (MB1) which serves both Tx and Rx packet space. The 16bit
- cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
+ cards have 2 banks, MB0 for Tx packets, and MB1 for Rx packets.
You choose which bank appears in the sh. mem window with EGACFR_MBSn */
#define EL2_MB0_START_PG (0x00) /* EL2/16 Tx packets go in bank 0 */
@@ -82,7 +82,7 @@
0 1 0 0x4000 -- bank 2, not used
0 1 1 0x6000 -- bank 3, not used
-There was going to be a 32k card that used bank 2 and 3, but it
+There was going to be a 32k card that used bank 2 and 3, but it
never got produced.
*/
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 19c0b856c48..ab8230a68be 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -315,11 +315,11 @@ static inline void check_3c505_dma(struct net_device *dev)
spin_lock_irqsave(&adapter->lock, flags);
adapter->dmaing = 0;
adapter->busy = 0;
-
+
f=claim_dma_lock();
disable_dma(dev->dma);
release_dma_lock(f);
-
+
if (adapter->rx_active)
adapter->rx_active--;
outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
@@ -660,7 +660,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
dev = dev_id;
adapter = (elp_device *) dev->priv;
-
+
spin_lock(&adapter->lock);
do {
@@ -712,7 +712,7 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
timeout = jiffies + 3*HZ/100;
while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
if (receive_pcb(dev, &adapter->irx_pcb)) {
- switch (adapter->irx_pcb.command)
+ switch (adapter->irx_pcb.command)
{
case 0:
break;
@@ -889,7 +889,7 @@ static int elp_open(struct net_device *dev)
adapter->send_pcb_semaphore = 0;
adapter->rx_backlog.in = 0;
adapter->rx_backlog.out = 0;
-
+
spin_lock_init(&adapter->lock);
/*
@@ -1003,7 +1003,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
}
adapter->stats.tx_bytes += nlen;
-
+
/*
* send the adapter a transmit packet command. Ignore segment and offset
* and make sure the length is even
@@ -1044,7 +1044,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
outb_control(adapter->hcr_val | DMAE | TCEN, dev);
enable_dma(dev->dma);
release_dma_lock(flags);
-
+
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: DMA transfer started\n", dev->name);
@@ -1054,7 +1054,7 @@ static int send_packet(struct net_device *dev, struct sk_buff *skb)
/*
* The upper layer thinks we timed out
*/
-
+
static void elp_timeout(struct net_device *dev)
{
elp_device *adapter = dev->priv;
@@ -1080,7 +1080,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
elp_device *adapter = dev->priv;
-
+
spin_lock_irqsave(&adapter->lock, flags);
check_3c505_dma(dev);
@@ -1088,7 +1088,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: request to send packet of length %d\n", dev->name, (int) skb->len);
netif_stop_queue(dev);
-
+
/*
* send the packet at skb->data for skb->len
*/
@@ -1169,7 +1169,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
debug = level;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
@@ -1235,7 +1235,7 @@ static void elp_set_mc_list(struct net_device *dev)
printk(KERN_DEBUG "%s: request to set multicast list\n", dev->name);
spin_lock_irqsave(&adapter->lock, flags);
-
+
if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
/* send a "load multicast list" command to the board, max 10 addrs/cmd */
/* if num_addrs==0 the list will be cleared */
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
index 77dfeedff81..1910cb1dc78 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/3c505.h
@@ -72,7 +72,7 @@
/*****************************************************************
*
* timeout value
- * this is a rough value used for loops to stop them from
+ * this is a rough value used for loops to stop them from
* locking up the whole machine in the case of failure or
* error conditions
*
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 6039049259e..8205a535c5b 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -294,14 +294,14 @@ static void el16_tx_timeout (struct net_device *dev);
static void hardware_send_packet(struct net_device *dev, void *buf, short length, short pad);
static void init_82586_mem(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void init_rx_bufs(struct net_device *);
static int io = 0x300;
static int irq;
static int mem_start;
-
+
/* Check for a network adaptor of this type, and return '0' iff one exists.
If dev->base_addr == 0, probe all likely locations.
If dev->base_addr == 1, always return failure.
@@ -379,7 +379,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr)
if (!request_region(ioaddr, EL16_IO_EXTENT, DRV_NAME))
return -ENODEV;
- if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
+ if ((inb(ioaddr) != '*') || (inb(ioaddr + 1) != '3') ||
(inb(ioaddr + 2) != 'C') || (inb(ioaddr + 3) != 'O')) {
retval = -ENODEV;
goto out;
@@ -575,7 +575,7 @@ static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while (lp->tx_pkts_in_ring) {
unsigned short tx_status = readw(shmem+lp->tx_reap);
if (!(tx_status & 0x8000)) {
- if (net_debug > 5)
+ if (net_debug > 5)
printk("Tx command incomplete (%#x).\n", lp->tx_reap);
break;
}
@@ -825,7 +825,7 @@ static void hardware_send_packet(struct net_device *dev, void *buf, short length
}
/* Grimly block further packets if there has been insufficient reaping. */
- if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
+ if (++lp->tx_pkts_in_ring < NUM_TX_BUFS)
netif_wake_queue(dev);
}
@@ -919,7 +919,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
debug = level;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
@@ -953,7 +953,7 @@ cleanup_module(void)
#endif /* MODULE */
MODULE_LICENSE("GPL");
-
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c"
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index dc845f36fe4..b936373ab2a 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -28,7 +28,7 @@
FIXES:
Alan Cox: Removed the 'Unexpected interrupt' bug.
Michael Meskes: Upgraded to Donald Becker's version 1.07.
- Alan Cox: Increased the eeprom delay. Regardless of
+ Alan Cox: Increased the eeprom delay. Regardless of
what the docs say some people definitely
get problems with lower (but in card spec)
delays
@@ -68,7 +68,6 @@
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
static int max_interrupt_work = 10;
-#include <linux/config.h>
#include <linux/module.h>
#ifdef CONFIG_MCA
#include <linux/mca.h>
@@ -163,7 +162,7 @@ enum RxFilter {
#define WN4_MEDIA 0x0A /* Window 4: Various transcvr/media bits. */
#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */
#define WN4_NETDIAG 0x06 /* Window 4: Net diagnostic */
-#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */
+#define FD_ENABLE 0x8000 /* Enable full-duplex ("external loopback") */
/*
* Must be a power of two (we use a binary and in the
@@ -201,7 +200,7 @@ static void set_multicast_list(struct net_device *dev);
static void el3_tx_timeout (struct net_device *dev);
static void el3_down(struct net_device *dev);
static void el3_up(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
#ifdef EL3_SUSPEND
static int el3_suspend(struct device *, pm_message_t);
static int el3_resume(struct device *);
@@ -226,6 +225,7 @@ static struct eisa_device_id el3_eisa_ids[] = {
{ "TCM5095" },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, el3_eisa_ids);
static int el3_eisa_probe (struct device *device);
@@ -351,7 +351,7 @@ static int __init el3_common_init(struct net_device *dev)
{
const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"};
printk("%s: 3c5x9 found at %#3.3lx, %s port, address ",
- dev->name, dev->base_addr,
+ dev->name, dev->base_addr,
if_names[(dev->if_port & 0x03)]);
}
@@ -529,7 +529,7 @@ no_pnp:
SET_MODULE_OWNER(dev);
netdev_boot_setup_check(dev);
-
+
/* Set passed-in IRQ or I/O Addr. */
if (dev->irq > 1 && dev->irq < 16)
irq = dev->irq;
@@ -631,7 +631,7 @@ static int __init el3_mca_probe(struct device *device)
if_port = pos4 & 0x03;
irq = mca_device_transform_irq(mdev, irq);
- ioaddr = mca_device_transform_ioport(mdev, ioaddr);
+ ioaddr = mca_device_transform_ioport(mdev, ioaddr);
if (el3_debug > 2) {
printk("3c529: irq %d ioaddr 0x%x ifport %d\n", irq, ioaddr, if_port);
}
@@ -668,7 +668,7 @@ static int __init el3_mca_probe(struct device *device)
el3_cards++;
return 0;
}
-
+
#endif /* CONFIG_MCA */
#ifdef CONFIG_EISA
@@ -685,7 +685,7 @@ static int __init el3_eisa_probe (struct device *device)
/* Yeepee, The driver framework is calling us ! */
edev = to_eisa_device (device);
ioaddr = edev->base_addr;
-
+
if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509"))
return -EBUSY;
@@ -752,7 +752,7 @@ static int __devexit el3_device_remove (struct device *device)
static ushort read_eeprom(int ioaddr, int index)
{
outw(EEPROM_READ + index, ioaddr + 10);
- /* Pause for at least 162 us. for the read to take place.
+ /* Pause for at least 162 us. for the read to take place.
Some chips seem to require much longer */
mdelay(2);
return inw(ioaddr + 12);
@@ -770,7 +770,7 @@ static ushort __init id_read_eeprom(int index)
/* Pause for at least 162 us. for the read to take place. */
/* Some chips seem to require much longer */
mdelay(4);
-
+
for (bit = 15; bit >= 0; bit--)
word = (word << 1) + (inb(id_port) & 0x01);
@@ -839,7 +839,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue (dev);
lp->stats.tx_bytes += skb->len;
-
+
if (el3_debug > 4) {
printk("%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
dev->name, skb->len, inw(ioaddr + EL3_STATUS));
@@ -880,11 +880,7 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
outw(skb->len, ioaddr + TX_FIFO);
outw(0x00, ioaddr + TX_FIFO);
/* ... and the packet rounded to a doubleword. */
-#ifdef __powerpc__
- outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-#else
outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
-#endif
dev->trans_start = jiffies;
if (inw(ioaddr + TX_FREE) > 1536)
@@ -1025,7 +1021,7 @@ el3_get_stats(struct net_device *dev)
* This is fast enough not to bother with disable IRQ
* stuff.
*/
-
+
spin_lock_irqsave(&lp->lock, flags);
update_stats(dev);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -1104,13 +1100,8 @@ el3_rx(struct net_device *dev)
skb_reserve(skb, 2); /* Align IP on 16 byte */
/* 'skb->data' points to the start of sk_buff data area. */
-#ifdef __powerpc__
- insl_ns(ioaddr+RX_FIFO, skb_put(skb,pkt_len),
- (pkt_len + 3) >> 2);
-#else
insl(ioaddr + RX_FIFO, skb_put(skb,pkt_len),
(pkt_len + 3) >> 2);
-#endif
outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
skb->protocol = eth_type_trans(skb,dev);
@@ -1169,7 +1160,7 @@ el3_close(struct net_device *dev)
{
int ioaddr = dev->base_addr;
struct el3_private *lp = netdev_priv(dev);
-
+
if (el3_debug > 2)
printk("%s: Shutting down ethercard.\n", dev->name);
@@ -1188,7 +1179,7 @@ el3_close(struct net_device *dev)
return 0;
}
-static int
+static int
el3_link_ok(struct net_device *dev)
{
int ioaddr = dev->base_addr;
@@ -1205,9 +1196,9 @@ el3_netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
{
u16 tmp;
int ioaddr = dev->base_addr;
-
+
EL3WINDOW(0);
- /* obtain current transceiver via WN4_MEDIA? */
+ /* obtain current transceiver via WN4_MEDIA? */
tmp = inw(ioaddr + WN0_ADDR_CONF);
ecmd->transceiver = XCVR_INTERNAL;
switch (tmp >> 14) {
@@ -1350,7 +1341,7 @@ static void el3_set_msglevel(struct net_device *dev, u32 v)
el3_debug = v;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = el3_get_drvinfo,
.get_settings = el3_get_settings,
.set_settings = el3_set_settings,
@@ -1392,7 +1383,7 @@ el3_up(struct net_device *dev)
{
int i, sw_info, net_diag;
int ioaddr = dev->base_addr;
-
+
/* Activating the board required and does no harm otherwise */
outw(0x0001, ioaddr + 4);
@@ -1412,7 +1403,7 @@ el3_up(struct net_device *dev)
/* Combine secondary sw_info word (the adapter level) and primary
sw_info word (duplex setting plus other useless bits) */
EL3WINDOW(0);
- sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |
+ sw_info = (read_eeprom(ioaddr, 0x14) & 0x400f) |
(read_eeprom(ioaddr, 0x0d) & 0xBff0);
EL3WINDOW(4);
@@ -1484,7 +1475,7 @@ el3_suspend(struct device *pdev, pm_message_t state)
struct net_device *dev;
struct el3_private *lp;
int ioaddr;
-
+
dev = pdev->driver_data;
lp = netdev_priv(dev);
ioaddr = dev->base_addr;
@@ -1508,7 +1499,7 @@ el3_resume(struct device *pdev)
struct net_device *dev;
struct el3_private *lp;
int ioaddr;
-
+
dev = pdev->driver_data;
lp = netdev_priv(dev);
ioaddr = dev->base_addr;
@@ -1520,7 +1511,7 @@ el3_resume(struct device *pdev)
if (netif_running(dev))
netif_device_attach(dev);
-
+
spin_unlock_irqrestore(&lp->lock, flags);
return 0;
}
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 91d1c4c24d9..91f2232e605 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -12,12 +12,12 @@
Annapolis MD 21403
- 2000/2/2- Added support for kernel-level ISAPnP
+ 2000/2/2- Added support for kernel-level ISAPnP
by Stephen Frost <sfrost@snowman.net> and Alessandro Zummo
Cleaned up for 2.3.x/softnet by Jeff Garzik and Alan Cox.
-
+
2001/11/17 - Added ethtool support (jgarzik)
-
+
2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
*/
@@ -57,7 +57,6 @@ static int max_interrupt_work = 20;
#define RX_RING_SIZE 16
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/isapnp.h>
#include <linux/kernel.h>
@@ -188,9 +187,9 @@ enum corkscrew_cmd {
TotalReset = 0 << 11, SelectWindow = 1 << 11, StartCoax = 2 << 11,
RxDisable = 3 << 11, RxEnable = 4 << 11, RxReset = 5 << 11,
UpStall = 6 << 11, UpUnstall = (6 << 11) + 1, DownStall = (6 << 11) + 2,
- DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
- TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
- AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
+ DownUnstall = (6 << 11) + 3, RxDiscard = 8 << 11, TxEnable = 9 << 11,
+ TxDisable = 10 << 11, TxReset = 11 << 11, FakeIntr = 12 << 11,
+ AckIntr = 13 << 11, SetIntrEnb = 14 << 11, SetStatusEnb = 15 << 11,
SetRxFilter = 16 << 11, SetRxThreshold = 17 << 11,
SetTxThreshold = 18 << 11, SetTxStart = 19 << 11, StartDMAUp = 20 << 11,
StartDMADown = (20 << 11) + 1, StatsEnable = 21 << 11,
@@ -339,15 +338,15 @@ static struct media_table {
mask:8, /* The transceiver-present bit in Wn3_Config. */
next:8; /* The media type to try next. */
short wait; /* Time before we check media status. */
-} media_tbl[] = {
- { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
- { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
- { "undefined", 0, 0x80, XCVR_10baseT, 10000},
- { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
- { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
- { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
- { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
- { "undefined", 0, 0x01, XCVR_10baseT, 10000},
+} media_tbl[] = {
+ { "10baseT", Media_10TP, 0x08, XCVR_10base2, (14 * HZ) / 10 },
+ { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1 * HZ) / 10},
+ { "undefined", 0, 0x80, XCVR_10baseT, 10000},
+ { "10base2", 0, 0x10, XCVR_AUI, (1 * HZ) / 10},
+ { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14 * HZ) / 10},
+ { "100baseFX", Media_Lnk, 0x04, XCVR_MII, (14 * HZ) / 10},
+ { "MII", 0, 0x40, XCVR_10baseT, 3 * HZ},
+ { "undefined", 0, 0x01, XCVR_10baseT, 10000},
{ "Default", 0, 0xFF, XCVR_10baseT, 10000},
};
@@ -380,10 +379,10 @@ static int corkscrew_close(struct net_device *dev);
static void update_stats(int addr, struct net_device *dev);
static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
-
+static const struct ethtool_ops netdev_ethtool_ops;
-/*
+
+/*
Unfortunately maximizing the shared code between the integrated and
module version of the driver results in a complicated set of initialization
procedures.
@@ -613,7 +612,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
printk(KERN_INFO "%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr);
spin_lock_init(&vp->lock);
-
+
/* Read the station address from the EEPROM. */
EL3WINDOW(0);
for (i = 0; i < 0x18; i++) {
@@ -692,7 +691,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr,
return register_netdev(dev);
}
-
+
static int corkscrew_open(struct net_device *dev)
{
@@ -716,7 +715,7 @@ static int corkscrew_open(struct net_device *dev)
} else if (vp->autoselect) {
/* Find first available media type, starting with 100baseTx. */
dev->if_port = 4;
- while (!(vp->available_media & media_tbl[dev->if_port].mask))
+ while (!(vp->available_media & media_tbl[dev->if_port].mask))
dev->if_port = media_tbl[dev->if_port].next;
if (corkscrew_debug > 1)
@@ -761,7 +760,7 @@ static int corkscrew_open(struct net_device *dev)
vp->product_name, dev)) return -EAGAIN;
enable_dma(dev->dma);
set_dma_mode(dev->dma, DMA_MODE_CASCADE);
- } else if (request_irq(dev->irq, &corkscrew_interrupt, SA_SHIRQ,
+ } else if (request_irq(dev->irq, &corkscrew_interrupt, IRQF_SHARED,
vp->product_name, dev)) {
return -EAGAIN;
}
@@ -872,7 +871,7 @@ static void corkscrew_timer(unsigned long data)
dev->name, media_tbl[dev->if_port].name);
spin_lock_irqsave(&vp->lock, flags);
-
+
{
int old_window = inw(ioaddr + EL3_CMD) >> 13;
int media_status;
@@ -912,7 +911,7 @@ static void corkscrew_timer(unsigned long data)
media_tbl[dev->if_port].next;
}
while (!(vp->available_media & media_tbl[dev->if_port].mask));
-
+
if (dev->if_port == 8) { /* Go back to default. */
dev->if_port = vp->default_media;
if (corkscrew_debug > 1)
@@ -941,7 +940,7 @@ static void corkscrew_timer(unsigned long data)
}
EL3WINDOW(old_window);
}
-
+
spin_unlock_irqrestore(&vp->lock, flags);
if (corkscrew_debug > 1)
printk("%s: Media selection timer finished, %s.\n",
@@ -1004,7 +1003,8 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
/* Calculate the next Tx descriptor entry. */
int entry = vp->cur_tx % TX_RING_SIZE;
struct boom_tx_desc *prev_entry;
- unsigned long flags, i;
+ unsigned long flags;
+ int i;
if (vp->tx_full) /* No room to transmit with */
return 1;
@@ -1026,7 +1026,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
outw(DownStall, ioaddr + EL3_CMD);
/* Wait for the stall to complete. */
for (i = 20; i >= 0; i--)
- if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
+ if ((inw(ioaddr + EL3_STATUS) & CmdInProgress) == 0)
break;
if (prev_entry)
prev_entry->next = isa_virt_to_bus(&vp->tx_ring[entry]);
@@ -1102,7 +1102,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
int j;
outw(TxReset, ioaddr + EL3_CMD);
for (j = 20; j >= 0; j--)
- if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
}
outw(TxEnable, ioaddr + EL3_CMD);
@@ -1130,7 +1130,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
latency = inb(ioaddr + Timer);
spin_lock(&lp->lock);
-
+
status = inw(ioaddr + EL3_STATUS);
if (corkscrew_debug > 4)
@@ -1249,7 +1249,7 @@ static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
-
+
spin_unlock(&lp->lock);
if (corkscrew_debug > 4)
@@ -1308,7 +1308,7 @@ static int corkscrew_rx(struct net_device *dev)
vp->stats.rx_bytes += pkt_len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
- if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+ if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
break;
continue;
} else if (corkscrew_debug)
@@ -1561,13 +1561,13 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
corkscrew_debug = level;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
};
-
+
#ifdef MODULE
void cleanup_module(void)
{
@@ -1584,7 +1584,7 @@ void cleanup_module(void)
}
}
#endif /* MODULE */
-
+
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c"
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 4bf8510655c..cf8a0bc3bf3 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -83,7 +83,7 @@
Stuart Adamson <stuart.adamson@compsoc.net>
Nov 2001
added support for ethtool (jgarzik)
-
+
$Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
*/
@@ -189,7 +189,7 @@ static void elmc_timeout(struct net_device *dev);
#ifdef ELMC_MULTICAST
static void set_multicast_list(struct net_device *dev);
#endif
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
/* helper-functions */
static int init586(struct net_device *dev);
@@ -289,7 +289,7 @@ static int elmc_open(struct net_device *dev)
elmc_id_attn586(); /* disable interrupts */
- ret = request_irq(dev->irq, &elmc_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM,
+ ret = request_irq(dev->irq, &elmc_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM,
dev->name, dev);
if (ret) {
printk(KERN_ERR "%s: couldn't get irq %d\n", dev->name, dev->irq);
@@ -434,14 +434,14 @@ static int __init do_elmc_probe(struct net_device *dev)
dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
-
+
/*
If we're trying to match a specified irq or IO address,
we'll reject a match unless it's what we're looking for.
Also reject it if the card is already in use.
*/
- if ((irq && irq != dev->irq) ||
+ if ((irq && irq != dev->irq) ||
(base_addr && base_addr != dev->base_addr)) {
slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
continue;
@@ -540,7 +540,7 @@ static int __init do_elmc_probe(struct net_device *dev)
/* dump all the assorted information */
printk(KERN_INFO "%s: IRQ %d, %sternal xcvr, memory %#lx-%#lx.\n", dev->name,
- dev->irq, dev->if_port ? "ex" : "in",
+ dev->irq, dev->if_port ? "ex" : "in",
dev->mem_start, dev->mem_end - 1);
/* The hardware address for the 3c523 is stored in the first six
@@ -564,7 +564,7 @@ static int __init do_elmc_probe(struct net_device *dev)
dev->set_multicast_list = NULL;
#endif
dev->ethtool_ops = &netdev_ethtool_ops;
-
+
/* note that we haven't actually requested the IRQ from the kernel.
That gets done in elmc_open(). I'm not sure that's such a good idea,
but it works, so I'll go with it. */
@@ -583,7 +583,7 @@ err_out:
release_region(dev->base_addr, ELMC_IO_EXTENT);
return retval;
}
-
+
static void cleanup_card(struct net_device *dev)
{
mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL);
@@ -926,7 +926,7 @@ elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
p = (struct priv *) dev->priv;
- while ((stat = p->scb->status & STAT_MASK))
+ while ((stat = p->scb->status & STAT_MASK))
{
p->scb->cmd = stat;
elmc_attn586(); /* ack inter. */
@@ -1102,7 +1102,7 @@ static void startrecv586(struct net_device *dev)
/******************************************************
* timeout
*/
-
+
static void elmc_timeout(struct net_device *dev)
{
struct priv *p = (struct priv *) dev->priv;
@@ -1129,7 +1129,7 @@ static void elmc_timeout(struct net_device *dev)
elmc_open(dev);
}
}
-
+
/******************************************************
* send frame
*/
@@ -1146,7 +1146,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-
+
if (len != skb->len)
memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN);
memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);
@@ -1177,7 +1177,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev)
#else
next_nop = (p->nop_point + 1) & 0x1;
p->xmit_buffs[0]->size = TBD_LAST | len;
-
+
p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link
= make16((p->nop_cmds[next_nop]));
p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0;
@@ -1259,7 +1259,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
@@ -1281,7 +1281,7 @@ int __init init_module(void)
{
int this_dev,found = 0;
- /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
+ /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */
for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
struct net_device *dev = alloc_etherdev(sizeof(struct priv));
if (!dev)
diff --git a/drivers/net/3c523.h b/drivers/net/3c523.h
index 7292f88b48e..6956441687b 100644
--- a/drivers/net/3c523.h
+++ b/drivers/net/3c523.h
@@ -130,7 +130,7 @@ struct rfd_struct
/*
* Receive Buffer Descriptor (RBD)
*/
-struct rbd_struct
+struct rbd_struct
{
unsigned short status; /* status word,number of used bytes in buff */
unsigned short next; /* pointeroffset to next RBD */
@@ -182,7 +182,7 @@ struct nop_cmd_struct
/*
* IA Setup command
*/
-struct iasetup_cmd_struct
+struct iasetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
@@ -191,7 +191,7 @@ struct iasetup_cmd_struct
};
/*
- * Configure command
+ * Configure command
*/
struct configure_cmd_struct
{
@@ -213,9 +213,9 @@ struct configure_cmd_struct
};
/*
- * Multicast Setup command
+ * Multicast Setup command
*/
-struct mcsetup_cmd_struct
+struct mcsetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
@@ -225,9 +225,9 @@ struct mcsetup_cmd_struct
};
/*
- * transmit command
+ * transmit command
*/
-struct transmit_cmd_struct
+struct transmit_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 157eda57392..625e57dc3b4 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -1,7 +1,7 @@
/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.4 and 2.6.
*
* (c) Copyright 1998 Red Hat Software Inc
- * Written by Alan Cox.
+ * Written by Alan Cox.
* Further debugging by Carl Drougge.
* Initial SMP support by Felipe W Damasio <felipewd@terra.com.br>
* Heavily modified by Richard Procter <rnp@paradise.net.nz>
@@ -30,12 +30,12 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.
* The diagram (Figure 1-1) and the POS summary disagree with the
* "Interrupt Level" section in the manual.
*
- * The manual contradicts itself when describing the minimum number
- * buffers in the 'configure lists' command.
- * My card accepts a buffer config of 4/4.
+ * The manual contradicts itself when describing the minimum number
+ * buffers in the 'configure lists' command.
+ * My card accepts a buffer config of 4/4.
*
* Setting the SAV BP bit does not save bad packets, but
- * only enables RX on-card stats collection.
+ * only enables RX on-card stats collection.
*
* The documentation in places seems to miss things. In actual fact
* I've always eventually found everything is documented, it just
@@ -64,16 +64,16 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Richard Procter <rnp@paradise.net.
* received frames exceeding a configurable length are passed
* directly to the higher networking layers without incuring a copy,
* in what amounts to a time/space trade-off.
- *
+ *
* The card also keeps a large amount of statistical information
* on-board. In a perfect world, these could be used safely at no
* cost. However, lacking information to the contrary, processing
* them without races would involve so much extra complexity as to
* make it unworthwhile to do so. In the end, a hybrid SW/HW
- * implementation was made necessary --- see mc32_update_stats().
+ * implementation was made necessary --- see mc32_update_stats().
*
* DOC: Notes
- *
+ *
* It should be possible to use two or more cards, but at this stage
* only by loading two copies of the same module.
*
@@ -132,28 +132,28 @@ static unsigned int mc32_debug = NET_DEBUG;
/* The number of low I/O ports used by the ethercard. */
#define MC32_IO_EXTENT 8
-/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
+/* As implemented, values must be a power-of-2 -- 4/8/16/32 */
#define TX_RING_LEN 32 /* Typically the card supports 37 */
#define RX_RING_LEN 8 /* " " " */
-/* Copy break point, see above for details.
- * Setting to > 1512 effectively disables this feature. */
+/* Copy break point, see above for details.
+ * Setting to > 1512 effectively disables this feature. */
#define RX_COPYBREAK 200 /* Value from 3c59x.c */
/* Issue the 82586 workaround command - this is for "busy lans", but
- * basically means for all lans now days - has a performance (latency)
- * cost, but best set. */
+ * basically means for all lans now days - has a performance (latency)
+ * cost, but best set. */
static const int WORKAROUND_82586=1;
/* Pointers to buffers and their on-card records */
-struct mc32_ring_desc
+struct mc32_ring_desc
{
- volatile struct skb_header *p;
- struct sk_buff *skb;
+ volatile struct skb_header *p;
+ struct sk_buff *skb;
};
/* Information that needs to be kept for each board. */
-struct mc32_local
+struct mc32_local
{
int slot;
@@ -165,7 +165,7 @@ struct mc32_local
volatile struct mc32_stats *stats; /* Start of on-card statistics */
u16 tx_chain; /* Transmit list start offset */
u16 rx_chain; /* Receive list start offset */
- u16 tx_len; /* Transmit list count */
+ u16 tx_len; /* Transmit list count */
u16 rx_len; /* Receive list count */
u16 xceiver_desired_state; /* HALTED or RUNNING */
@@ -180,7 +180,7 @@ struct mc32_local
atomic_t tx_ring_head; /* index to tx en-queue end */
u16 tx_ring_tail; /* index to tx de-queue end */
- u16 rx_ring_tail; /* index to rx de-queue end */
+ u16 rx_ring_tail; /* index to rx de-queue end */
struct semaphore cmd_mutex; /* Serialises issuing of execute commands */
struct completion execution_cmd; /* Card has completed an execute command */
@@ -204,7 +204,7 @@ static const struct mca_adapters_t mc32_adapters[] = {
};
-/* Macros for ring index manipulations */
+/* Macros for ring index manipulations */
static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
@@ -222,7 +222,7 @@ static int mc32_close(struct net_device *dev);
static struct net_device_stats *mc32_get_stats(struct net_device *dev);
static void mc32_set_multicast_list(struct net_device *dev);
static void mc32_reset_multicast_list(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void cleanup_card(struct net_device *dev)
{
@@ -259,21 +259,21 @@ struct net_device *__init mc32_probe(int unit)
SET_MODULE_OWNER(dev);
- /* Do not check any supplied i/o locations.
+ /* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
- /* MCA cards have POS registers.
- Autodetecting MCA cards is extremely simple.
+ /* MCA cards have POS registers.
+ Autodetecting MCA cards is extremely simple.
Just search for the card. */
for(i = 0; (mc32_adapters[i].name != NULL); i++) {
- current_mca_slot =
+ current_mca_slot =
mca_find_unused_adapter(mc32_adapters[i].id, 0);
if(current_mca_slot != MCA_NOTFOUND) {
if(!mc32_probe1(dev, current_mca_slot))
{
- mca_set_adapter_name(current_mca_slot,
+ mca_set_adapter_name(current_mca_slot,
mc32_adapters[i].name);
mca_mark_as_used(current_mca_slot);
err = register_netdev(dev);
@@ -284,7 +284,7 @@ struct net_device *__init mc32_probe(int unit)
}
return dev;
}
-
+
}
}
free_netdev(dev);
@@ -298,7 +298,7 @@ struct net_device *__init mc32_probe(int unit)
*
* Decode the slot data and configure the card structures. Having done this we
* can reset the card and configure it. The card does a full self test cycle
- * in firmware so we have to wait for it to return and post us either a
+ * in firmware so we have to wait for it to return and post us either a
* failure case or some addresses we use to find the board internals.
*/
@@ -347,7 +347,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
printk(KERN_INFO "%s: %s found in slot %d:", dev->name, cardname, slot);
POS = mca_read_stored_pos(slot, 2);
-
+
if(!(POS&1))
{
printk(" disabled.\n");
@@ -357,7 +357,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
/* Fill in the 'dev' fields. */
dev->base_addr = mca_io_bases[(POS>>1)&7];
dev->mem_start = mca_mem_bases[(POS>>4)&7];
-
+
POS = mca_read_stored_pos(slot, 4);
if(!(POS&1))
{
@@ -366,21 +366,21 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
}
POS = mca_read_stored_pos(slot, 5);
-
+
i=(POS>>4)&3;
if(i==3)
{
printk("invalid memory window.\n");
return -ENODEV;
}
-
+
i*=16384;
i+=16384;
-
+
dev->mem_end=dev->mem_start + i;
-
+
dev->irq = ((POS>>2)&3)+9;
-
+
if(!request_region(dev->base_addr, MC32_IO_EXTENT, cardname))
{
printk("io 0x%3lX, which is busy.\n", dev->base_addr);
@@ -389,23 +389,23 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
printk("io 0x%3lX irq %d mem 0x%lX (%dK)\n",
dev->base_addr, dev->irq, dev->mem_start, i/1024);
-
-
+
+
/* We ought to set the cache line size here.. */
-
-
+
+
/*
* Go PROM browsing
*/
-
+
printk("%s: Address ", dev->name);
-
+
/* Retrieve and print the ethernet address. */
for (i = 0; i < 6; i++)
{
mca_write_pos(slot, 6, i+12);
mca_write_pos(slot, 7, 0);
-
+
printk(" %2.2x", dev->dev_addr[i] = mca_read_pos(slot,3));
}
@@ -413,12 +413,12 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
mca_write_pos(slot, 7, 0);
POS = mca_read_stored_pos(slot, 4);
-
+
if(POS&2)
printk(" : BNC port selected.\n");
- else
+ else
printk(" : AUI port selected.\n");
-
+
POS=inb(dev->base_addr+HOST_CTRL);
POS|=HOST_CTRL_ATTN|HOST_CTRL_RESET;
POS&=~HOST_CTRL_INTE;
@@ -428,14 +428,14 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
/* Reset off */
POS&=~(HOST_CTRL_ATTN|HOST_CTRL_RESET);
outb(POS, dev->base_addr+HOST_CTRL);
-
+
udelay(300);
-
+
/*
* Grab the IRQ
*/
- err = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ | SA_SAMPLE_RANDOM, DRV_NAME, dev);
+ err = request_irq(dev->irq, &mc32_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, DRV_NAME, dev);
if (err) {
release_region(dev->base_addr, MC32_IO_EXTENT);
printk(KERN_ERR "%s: unable to get IRQ %d.\n", DRV_NAME, dev->irq);
@@ -448,14 +448,14 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
i=0;
base = inb(dev->base_addr);
-
+
while(base == 0xFF)
{
i++;
if(i == 1000)
{
printk(KERN_ERR "%s: failed to boot adapter.\n", dev->name);
- err = -ENODEV;
+ err = -ENODEV;
goto err_exit_irq;
}
udelay(1000);
@@ -470,15 +470,15 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
base<0x0A?" test failure":"");
else
printk(KERN_ERR "%s: unknown failure %d.\n", dev->name, base);
- err = -ENODEV;
+ err = -ENODEV;
goto err_exit_irq;
}
-
+
base=0;
for(i=0;i<4;i++)
{
int n=0;
-
+
while(!(inb(dev->base_addr+2)&(1<<5)))
{
n++;
@@ -493,31 +493,31 @@ static int __init mc32_probe1(struct net_device *dev, int slot)
base|=(inb(dev->base_addr)<<(8*i));
}
-
+
lp->exec_box=isa_bus_to_virt(dev->mem_start+base);
-
- base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
-
+
+ base=lp->exec_box->data[1]<<16|lp->exec_box->data[0];
+
lp->base = dev->mem_start+base;
-
- lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
+
+ lp->rx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[2]);
lp->tx_box=isa_bus_to_virt(lp->base + lp->exec_box->data[3]);
-
+
lp->stats = isa_bus_to_virt(lp->base + lp->exec_box->data[5]);
/*
* Descriptor chains (card relative)
*/
-
+
lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
- lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
+ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
init_MUTEX_LOCKED(&lp->cmd_mutex);
init_completion(&lp->execution_cmd);
init_completion(&lp->xceiver_cmd);
-
+
printk("%s: Firmware Rev %d. %d RX buffers, %d TX buffers. Base of 0x%08X.\n",
dev->name, lp->exec_box->data[12], lp->rx_len, lp->tx_len, lp->base);
@@ -543,12 +543,12 @@ err_exit_ports:
/**
* mc32_ready_poll - wait until we can feed it a command
* @dev: The device to wait for
- *
+ *
* Wait until the card becomes ready to accept a command via the
* command register. This tells us nothing about the completion
* status of any pending commands and takes very little time at all.
*/
-
+
static inline void mc32_ready_poll(struct net_device *dev)
{
int ioaddr = dev->base_addr;
@@ -608,22 +608,22 @@ static int mc32_command_nowait(struct net_device *dev, u16 cmd, void *data, int
*
* Sends exec commands in a user context. This permits us to wait around
* for the replies and also to wait for the command buffer to complete
- * from a previous command before we execute our command. After our
+ * from a previous command before we execute our command. After our
* command completes we will attempt any pending multicast reload
* we blocked off by hogging the exec buffer.
*
- * You feed the card a command, you wait, it interrupts you get a
+ * You feed the card a command, you wait, it interrupts you get a
* reply. All well and good. The complication arises because you use
* commands for filter list changes which come in at bh level from things
* like IPV6 group stuff.
*/
-
+
static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
{
struct mc32_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int ret = 0;
-
+
down(&lp->cmd_mutex);
/*
@@ -640,7 +640,7 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
outb(1<<6, ioaddr+HOST_CMD);
wait_for_completion(&lp->execution_cmd);
-
+
if(lp->exec_box->mbox&(1<<13))
ret = -1;
@@ -664,8 +664,8 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int len)
* @dev: The 3c527 card to issue the command to
*
* This may be called from the interrupt state, where it is used
- * to restart the rx ring if the card runs out of rx buffers.
- *
+ * to restart the rx ring if the card runs out of rx buffers.
+ *
* We must first check if it's ok to (re)start the transceiver. See
* mc32_close for details.
*/
@@ -675,21 +675,21 @@ static void mc32_start_transceiver(struct net_device *dev) {
struct mc32_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
- /* Ignore RX overflow on device closure */
+ /* Ignore RX overflow on device closure */
if (lp->xceiver_desired_state==HALTED)
- return;
+ return;
/* Give the card the offset to the post-EOL-bit RX descriptor */
- mc32_ready_poll(dev);
+ mc32_ready_poll(dev);
lp->rx_box->mbox=0;
- lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
- outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
+ lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next;
+ outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);
- mc32_ready_poll(dev);
+ mc32_ready_poll(dev);
lp->tx_box->mbox=0;
- outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
-
- /* We are not interrupted on start completion */
+ outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD); /* card ignores this on RX restart */
+
+ /* We are not interrupted on start completion */
}
@@ -703,21 +703,21 @@ static void mc32_start_transceiver(struct net_device *dev) {
*
* We then sleep until the card has notified us that both rx and
* tx have been suspended.
- */
+ */
-static void mc32_halt_transceiver(struct net_device *dev)
+static void mc32_halt_transceiver(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
- mc32_ready_poll(dev);
+ mc32_ready_poll(dev);
lp->rx_box->mbox=0;
- outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
+ outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);
wait_for_completion(&lp->xceiver_cmd);
- mc32_ready_poll(dev);
+ mc32_ready_poll(dev);
lp->tx_box->mbox=0;
- outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
+ outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);
wait_for_completion(&lp->xceiver_cmd);
}
@@ -741,14 +741,14 @@ static void mc32_halt_transceiver(struct net_device *dev)
* We then set the end-of-list bit for the last entry so that the
* card will know when it has run out of buffers.
*/
-
+
static int mc32_load_rx_ring(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
int i;
u16 rx_base;
volatile struct skb_header *p;
-
+
rx_base=lp->rx_chain;
for(i=0; i<RX_RING_LEN; i++) {
@@ -761,14 +761,14 @@ static int mc32_load_rx_ring(struct net_device *dev)
skb_reserve(lp->rx_ring[i].skb, 18);
p=isa_bus_to_virt(lp->base+rx_base);
-
+
p->control=0;
p->data=isa_virt_to_bus(lp->rx_ring[i].skb->data);
p->status=0;
p->length=1532;
-
- lp->rx_ring[i].p=p;
- rx_base=p->next;
+
+ lp->rx_ring[i].p=p;
+ rx_base=p->next;
}
lp->rx_ring[i-1].p->control |= CONTROL_EOL;
@@ -776,14 +776,14 @@ static int mc32_load_rx_ring(struct net_device *dev)
lp->rx_ring_tail=0;
return 0;
-}
+}
/**
* mc32_flush_rx_ring - free the ring of receive buffers
* @lp: Local data of 3c527 to flush the rx ring of
*
- * Free the buffer for each ring slot. This may be called
+ * Free the buffer for each ring slot. This may be called
* before mc32_load_rx_ring(), eg. on error in mc32_open().
* Requires rx skb pointers to point to a valid skb, or NULL.
*/
@@ -791,16 +791,16 @@ static int mc32_load_rx_ring(struct net_device *dev)
static void mc32_flush_rx_ring(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
- int i;
+ int i;
- for(i=0; i < RX_RING_LEN; i++)
- {
+ for(i=0; i < RX_RING_LEN; i++)
+ {
if (lp->rx_ring[i].skb) {
dev_kfree_skb(lp->rx_ring[i].skb);
lp->rx_ring[i].skb = NULL;
}
- lp->rx_ring[i].p=NULL;
- }
+ lp->rx_ring[i].p=NULL;
+ }
}
@@ -808,31 +808,31 @@ static void mc32_flush_rx_ring(struct net_device *dev)
* mc32_load_tx_ring - load transmit ring
* @dev: The 3c527 card to issue the command to
*
- * This sets up the host transmit data-structures.
+ * This sets up the host transmit data-structures.
*
* First, we obtain from the card it's current postion in the tx
* ring, so that we will know where to begin transmitting
* packets.
- *
+ *
* Then, we read the 'next' pointers from the on-card tx ring into
* our tx_ring array to reduce slow shared-mem reads. Finally, we
* intitalise the tx house keeping variables.
- *
- */
+ *
+ */
static void mc32_load_tx_ring(struct net_device *dev)
-{
+{
struct mc32_local *lp = netdev_priv(dev);
volatile struct skb_header *p;
- int i;
+ int i;
u16 tx_base;
- tx_base=lp->tx_box->data[0];
+ tx_base=lp->tx_box->data[0];
for(i=0 ; i<TX_RING_LEN ; i++)
{
p=isa_bus_to_virt(lp->base+tx_base);
- lp->tx_ring[i].p=p;
+ lp->tx_ring[i].p=p;
lp->tx_ring[i].skb=NULL;
tx_base=p->next;
@@ -841,10 +841,10 @@ static void mc32_load_tx_ring(struct net_device *dev)
/* -1 so that tx_ring_head cannot "lap" tx_ring_tail */
/* see mc32_tx_ring */
- atomic_set(&lp->tx_count, TX_RING_LEN-1);
- atomic_set(&lp->tx_ring_head, 0);
- lp->tx_ring_tail=0;
-}
+ atomic_set(&lp->tx_count, TX_RING_LEN-1);
+ atomic_set(&lp->tx_ring_head, 0);
+ lp->tx_ring_tail=0;
+}
/**
@@ -871,11 +871,11 @@ static void mc32_flush_tx_ring(struct net_device *dev)
}
}
- atomic_set(&lp->tx_count, 0);
- atomic_set(&lp->tx_ring_head, 0);
+ atomic_set(&lp->tx_count, 0);
+ atomic_set(&lp->tx_ring_head, 0);
lp->tx_ring_tail=0;
}
-
+
/**
* mc32_open - handle 'up' of card
@@ -909,7 +909,7 @@ static int mc32_open(struct net_device *dev)
regs=inb(ioaddr+HOST_CTRL);
regs|=HOST_CTRL_INTE;
outb(regs, ioaddr+HOST_CTRL);
-
+
/*
* Allow ourselves to issue commands
*/
@@ -924,52 +924,52 @@ static int mc32_open(struct net_device *dev)
mc32_command(dev, 4, &one, 2);
/*
- * Poke it to make sure it's really dead.
+ * Poke it to make sure it's really dead.
*/
- mc32_halt_transceiver(dev);
- mc32_flush_tx_ring(dev);
+ mc32_halt_transceiver(dev);
+ mc32_flush_tx_ring(dev);
- /*
- * Ask card to set up on-card descriptors to our spec
- */
+ /*
+ * Ask card to set up on-card descriptors to our spec
+ */
- if(mc32_command(dev, 8, descnumbuffs, 4)) {
+ if(mc32_command(dev, 8, descnumbuffs, 4)) {
printk("%s: %s rejected our buffer configuration!\n",
dev->name, cardname);
- mc32_close(dev);
- return -ENOBUFS;
+ mc32_close(dev);
+ return -ENOBUFS;
}
-
- /* Report new configuration */
- mc32_command(dev, 6, NULL, 0);
+
+ /* Report new configuration */
+ mc32_command(dev, 6, NULL, 0);
lp->tx_chain = lp->exec_box->data[8]; /* Transmit list start offset */
lp->rx_chain = lp->exec_box->data[10]; /* Receive list start offset */
- lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
+ lp->tx_len = lp->exec_box->data[9]; /* Transmit list count */
lp->rx_len = lp->exec_box->data[11]; /* Receive list count */
-
+
/* Set Network Address */
mc32_command(dev, 1, dev->dev_addr, 6);
-
+
/* Set the filters */
mc32_set_multicast_list(dev);
-
- if (WORKAROUND_82586) {
+
+ if (WORKAROUND_82586) {
u16 zero_word=0;
mc32_command(dev, 0x0D, &zero_word, 2); /* 82586 bug workaround on */
}
mc32_load_tx_ring(dev);
-
- if(mc32_load_rx_ring(dev))
+
+ if(mc32_load_rx_ring(dev))
{
mc32_close(dev);
return -ENOBUFS;
}
lp->xceiver_desired_state = RUNNING;
-
+
/* And finally, set the ball rolling... */
mc32_start_transceiver(dev);
@@ -1015,14 +1015,14 @@ static void mc32_timeout(struct net_device *dev)
* after we've established a valid packet on the tx ring (and
* before we let the card "see" it, to prevent it racing with the
* irq handler).
- *
+ *
*/
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
u32 head = atomic_read(&lp->tx_ring_head);
-
+
volatile struct skb_header *p, *np;
netif_stop_queue(dev);
@@ -1036,31 +1036,31 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0;
}
- atomic_dec(&lp->tx_count);
+ atomic_dec(&lp->tx_count);
/* P is the last sending/sent buffer as a pointer */
p=lp->tx_ring[head].p;
-
+
head = next_tx(head);
/* NP is the buffer we will be loading */
- np=lp->tx_ring[head].p;
-
+ np=lp->tx_ring[head].p;
+
/* We will need this to flush the buffer out */
lp->tx_ring[head].skb=skb;
- np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ np->length = unlikely(skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
np->data = isa_virt_to_bus(skb->data);
np->status = 0;
- np->control = CONTROL_EOP | CONTROL_EOL;
+ np->control = CONTROL_EOP | CONTROL_EOL;
wmb();
-
+
/*
* The new frame has been setup; we can now
* let the interrupt handler and card "see" it
*/
- atomic_set(&lp->tx_ring_head, head);
+ atomic_set(&lp->tx_ring_head, head);
p->control &= ~CONTROL_EOL;
netif_wake_queue(dev);
@@ -1072,13 +1072,13 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
* mc32_update_stats - pull off the on board statistics
* @dev: 3c527 to service
*
- *
+ *
* Query and reset the on-card stats. There's the small possibility
* of a race here, which would result in an underestimation of
* actual errors. As such, we'd prefer to keep all our stats
* collection in software. As a rule, we do. However it can't be
* used for rx errors and collisions as, by default, the card discards
- * bad rx packets.
+ * bad rx packets.
*
* Setting the SAV BP in the rx filter command supposedly
* stops this behaviour. However, testing shows that it only seems to
@@ -1090,30 +1090,30 @@ static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev)
static void mc32_update_stats(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
- volatile struct mc32_stats *st = lp->stats;
+ volatile struct mc32_stats *st = lp->stats;
- u32 rx_errors=0;
-
- rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors;
+ u32 rx_errors=0;
+
+ rx_errors+=lp->net_stats.rx_crc_errors +=st->rx_crc_errors;
st->rx_crc_errors=0;
- rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors;
- st->rx_overrun_errors=0;
- rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
+ rx_errors+=lp->net_stats.rx_fifo_errors +=st->rx_overrun_errors;
+ st->rx_overrun_errors=0;
+ rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors;
st->rx_alignment_errors=0;
- rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors;
+ rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors;
st->rx_tooshort_errors=0;
rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
- st->rx_outofresource_errors=0;
- lp->net_stats.rx_errors=rx_errors;
-
+ st->rx_outofresource_errors=0;
+ lp->net_stats.rx_errors=rx_errors;
+
/* Number of packets which saw one collision */
lp->net_stats.collisions+=st->dataC[10];
- st->dataC[10]=0;
+ st->dataC[10]=0;
- /* Number of packets which saw 2--15 collisions */
- lp->net_stats.collisions+=st->dataC[11];
- st->dataC[11]=0;
-}
+ /* Number of packets which saw 2--15 collisions */
+ lp->net_stats.collisions+=st->dataC[11];
+ st->dataC[11]=0;
+}
/**
@@ -1130,7 +1130,7 @@ static void mc32_update_stats(struct net_device *dev)
* For each completed packet, we will either copy it and pass it up
* the stack or, if the packet is near MTU sized, we allocate
* another buffer and flip the old one up the stack.
- *
+ *
* We must succeed in keeping a buffer on the ring. If necessary we
* will toss a received packet rather than lose a ring entry. Once
* the first uncompleted descriptor is found, we move the
@@ -1147,72 +1147,72 @@ static void mc32_rx_ring(struct net_device *dev)
int x=0;
rx_old_tail = rx_ring_tail = lp->rx_ring_tail;
-
+
do
- {
- p=lp->rx_ring[rx_ring_tail].p;
+ {
+ p=lp->rx_ring[rx_ring_tail].p;
- if(!(p->status & (1<<7))) { /* Not COMPLETED */
+ if(!(p->status & (1<<7))) { /* Not COMPLETED */
break;
- }
+ }
if(p->status & (1<<6)) /* COMPLETED_OK */
- {
+ {
u16 length=p->length;
- struct sk_buff *skb;
- struct sk_buff *newskb;
+ struct sk_buff *skb;
+ struct sk_buff *newskb;
/* Try to save time by avoiding a copy on big frames */
- if ((length > RX_COPYBREAK)
- && ((newskb=dev_alloc_skb(1532)) != NULL))
- {
+ if ((length > RX_COPYBREAK)
+ && ((newskb=dev_alloc_skb(1532)) != NULL))
+ {
skb=lp->rx_ring[rx_ring_tail].skb;
skb_put(skb, length);
-
- skb_reserve(newskb,18);
- lp->rx_ring[rx_ring_tail].skb=newskb;
- p->data=isa_virt_to_bus(newskb->data);
- }
- else
+
+ skb_reserve(newskb,18);
+ lp->rx_ring[rx_ring_tail].skb=newskb;
+ p->data=isa_virt_to_bus(newskb->data);
+ }
+ else
{
- skb=dev_alloc_skb(length+2);
+ skb=dev_alloc_skb(length+2);
if(skb==NULL) {
- lp->net_stats.rx_dropped++;
- goto dropped;
+ lp->net_stats.rx_dropped++;
+ goto dropped;
}
skb_reserve(skb,2);
memcpy(skb_put(skb, length),
lp->rx_ring[rx_ring_tail].skb->data, length);
}
-
- skb->protocol=eth_type_trans(skb,dev);
- skb->dev=dev;
+
+ skb->protocol=eth_type_trans(skb,dev);
+ skb->dev=dev;
dev->last_rx = jiffies;
- lp->net_stats.rx_packets++;
- lp->net_stats.rx_bytes += length;
+ lp->net_stats.rx_packets++;
+ lp->net_stats.rx_bytes += length;
netif_rx(skb);
}
dropped:
- p->length = 1532;
+ p->length = 1532;
p->status = 0;
-
- rx_ring_tail=next_rx(rx_ring_tail);
+
+ rx_ring_tail=next_rx(rx_ring_tail);
}
- while(x++<48);
+ while(x++<48);
- /* If there was actually a frame to be processed, place the EOL bit */
- /* at the descriptor prior to the one to be filled next */
+ /* If there was actually a frame to be processed, place the EOL bit */
+ /* at the descriptor prior to the one to be filled next */
- if (rx_ring_tail != rx_old_tail)
- {
- lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
- lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
+ if (rx_ring_tail != rx_old_tail)
+ {
+ lp->rx_ring[prev_rx(rx_ring_tail)].p->control |= CONTROL_EOL;
+ lp->rx_ring[prev_rx(rx_old_tail)].p->control &= ~CONTROL_EOL;
- lp->rx_ring_tail=rx_ring_tail;
+ lp->rx_ring_tail=rx_ring_tail;
}
}
@@ -1228,10 +1228,10 @@ static void mc32_rx_ring(struct net_device *dev)
* any errors. This continues until the transmit ring is emptied
* or we reach a descriptor that hasn't yet been processed by the
* card.
- *
+ *
*/
-static void mc32_tx_ring(struct net_device *dev)
+static void mc32_tx_ring(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
volatile struct skb_header *np;
@@ -1243,28 +1243,28 @@ static void mc32_tx_ring(struct net_device *dev)
* condition with 'queue full'
*/
- while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
- {
- u16 t;
+ while (lp->tx_ring_tail != atomic_read(&lp->tx_ring_head))
+ {
+ u16 t;
- t=next_tx(lp->tx_ring_tail);
- np=lp->tx_ring[t].p;
+ t=next_tx(lp->tx_ring_tail);
+ np=lp->tx_ring[t].p;
- if(!(np->status & (1<<7)))
+ if(!(np->status & (1<<7)))
{
- /* Not COMPLETED */
- break;
- }
+ /* Not COMPLETED */
+ break;
+ }
lp->net_stats.tx_packets++;
if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
{
- lp->net_stats.tx_errors++;
+ lp->net_stats.tx_errors++;
switch(np->status&0x0F)
{
case 1:
lp->net_stats.tx_aborted_errors++;
- break; /* Max collisions */
+ break; /* Max collisions */
case 2:
lp->net_stats.tx_fifo_errors++;
break;
@@ -1273,10 +1273,10 @@ static void mc32_tx_ring(struct net_device *dev)
break;
case 4:
lp->net_stats.tx_window_errors++;
- break; /* CTS Lost */
+ break; /* CTS Lost */
case 5:
lp->net_stats.tx_aborted_errors++;
- break; /* Transmit timeout */
+ break; /* Transmit timeout */
}
}
/* Packets are sent in order - this is
@@ -1288,10 +1288,10 @@ static void mc32_tx_ring(struct net_device *dev)
atomic_inc(&lp->tx_count);
netif_wake_queue(dev);
- lp->tx_ring_tail=t;
+ lp->tx_ring_tail=t;
}
-}
+}
/**
@@ -1322,13 +1322,13 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct mc32_local *lp;
int ioaddr, status, boguscount = 0;
int rx_event = 0;
- int tx_event = 0;
-
+ int tx_event = 0;
+
if (dev == NULL) {
printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
return IRQ_NONE;
}
-
+
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
@@ -1338,19 +1338,19 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
status=inb(ioaddr+HOST_CMD);
-#ifdef DEBUG_IRQ
+#ifdef DEBUG_IRQ
printk("Status TX%d RX%d EX%d OV%d BC%d\n",
(status&7), (status>>3)&7, (status>>6)&1,
(status>>7)&1, boguscount);
#endif
-
+
switch(status&7)
{
case 0:
break;
case 6: /* TX fail */
case 2: /* TX ok */
- tx_event = 1;
+ tx_event = 1;
break;
case 3: /* Halt */
case 4: /* Abort */
@@ -1365,7 +1365,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
case 0:
break;
case 2: /* RX */
- rx_event=1;
+ rx_event=1;
break;
case 3: /* Halt */
case 4: /* Abort */
@@ -1375,12 +1375,12 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* Out of RX buffers stat */
/* Must restart rx */
lp->net_stats.rx_dropped++;
- mc32_rx_ring(dev);
- mc32_start_transceiver(dev);
+ mc32_rx_ring(dev);
+ mc32_start_transceiver(dev);
break;
default:
- printk("%s: strange rx ack %d\n",
- dev->name, status&7);
+ printk("%s: strange rx ack %d\n",
+ dev->name, status&7);
}
status>>=3;
if(status&1)
@@ -1389,10 +1389,10 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* No thread is waiting: we need to tidy
* up ourself.
*/
-
+
if (lp->cmd_nonblocking) {
up(&lp->cmd_mutex);
- if (lp->mc_reload_wait)
+ if (lp->mc_reload_wait)
mc32_reset_multicast_list(dev);
}
else complete(&lp->execution_cmd);
@@ -1401,22 +1401,22 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
/*
* We get interrupted once per
- * counter that is about to overflow.
+ * counter that is about to overflow.
*/
- mc32_update_stats(dev);
+ mc32_update_stats(dev);
}
}
/*
- * Process the transmit and receive rings
+ * Process the transmit and receive rings
*/
- if(tx_event)
+ if(tx_event)
mc32_tx_ring(dev);
-
- if(rx_event)
+
+ if(rx_event)
mc32_rx_ring(dev);
return IRQ_HANDLED;
@@ -1435,7 +1435,7 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* driver. Otherwise, it is possible that the card may run out
* of receive buffers and restart the transceiver while we're
* trying to close it.
- *
+ *
* We abort any receive and transmits going on and then wait until
* any pending exec commands have completed in other code threads.
* In theory we can't get here while that is true, in practice I am
@@ -1452,7 +1452,7 @@ static int mc32_close(struct net_device *dev)
u8 regs;
u16 one=1;
-
+
lp->xceiver_desired_state = HALTED;
netif_stop_queue(dev);
@@ -1464,22 +1464,22 @@ static int mc32_close(struct net_device *dev)
/* Shut down the transceiver */
- mc32_halt_transceiver(dev);
-
+ mc32_halt_transceiver(dev);
+
/* Ensure we issue no more commands beyond this point */
down(&lp->cmd_mutex);
-
- /* Ok the card is now stopping */
-
+
+ /* Ok the card is now stopping */
+
regs=inb(ioaddr+HOST_CTRL);
regs&=~HOST_CTRL_INTE;
outb(regs, ioaddr+HOST_CTRL);
mc32_flush_rx_ring(dev);
mc32_flush_tx_ring(dev);
-
- mc32_update_stats(dev);
+
+ mc32_update_stats(dev);
return 0;
}
@@ -1490,15 +1490,15 @@ static int mc32_close(struct net_device *dev)
* @dev: The 3c527 card to handle
*
* We've collected all the stats we can in software already. Now
- * it's time to update those kept on-card and return the lot.
- *
+ * it's time to update those kept on-card and return the lot.
+ *
*/
static struct net_device_stats *mc32_get_stats(struct net_device *dev)
{
struct mc32_local *lp = netdev_priv(dev);
-
- mc32_update_stats(dev);
+
+ mc32_update_stats(dev);
return &lp->net_stats;
}
@@ -1506,7 +1506,7 @@ static struct net_device_stats *mc32_get_stats(struct net_device *dev)
/**
* do_mc32_set_multicast_list - attempt to update multicasts
* @dev: 3c527 device to load the list on
- * @retry: indicates this is not the first call.
+ * @retry: indicates this is not the first call.
*
*
* Actually set or clear the multicast filter for this adaptor. The
@@ -1514,22 +1514,22 @@ static struct net_device_stats *mc32_get_stats(struct net_device *dev)
* state as it may take multiple calls to get the command sequence
* completed. We just keep trying to schedule the loads until we
* manage to process them all.
- *
+ *
* num_addrs == -1 Promiscuous mode, receive all packets
- *
+ *
* num_addrs == 0 Normal mode, clear multicast list
- *
- * num_addrs > 0 Multicast mode, receive normal and MC packets,
- * and do best-effort filtering.
*
- * See mc32_update_stats() regards setting the SAV BP bit.
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * and do best-effort filtering.
+ *
+ * See mc32_update_stats() regards setting the SAV BP bit.
*
*/
static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
{
struct mc32_local *lp = netdev_priv(dev);
- u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
+ u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */
if (dev->flags&IFF_PROMISC)
/* Enable promiscuous mode */
@@ -1544,9 +1544,9 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
unsigned char block[62];
unsigned char *bp;
struct dev_mc_list *dmc=dev->mc_list;
-
+
int i;
-
+
if(retry==0)
lp->mc_list_valid = 0;
if(!lp->mc_list_valid)
@@ -1554,7 +1554,7 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
block[1]=0;
block[0]=dev->mc_count;
bp=block+2;
-
+
for(i=0;i<dev->mc_count;i++)
{
memcpy(bp, dmc->dmi_addr, 6);
@@ -1569,12 +1569,12 @@ static void do_mc32_set_multicast_list(struct net_device *dev, int retry)
lp->mc_list_valid=1;
}
}
-
- if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+
+ if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
{
lp->mc_reload_wait = 1;
- }
- else {
+ }
+ else {
lp->mc_reload_wait = 0;
}
}
@@ -1627,7 +1627,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
mc32_debug = level;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_msglevel = netdev_get_msglevel,
.set_msglevel = netdev_set_msglevel,
diff --git a/drivers/net/3c527.h b/drivers/net/3c527.h
index 53b5b071df0..75e28fef797 100644
--- a/drivers/net/3c527.h
+++ b/drivers/net/3c527.h
@@ -5,7 +5,7 @@
/*
* Registers
*/
-
+
#define HOST_CMD 0
#define HOST_CMD_START_RX (1<<3)
#define HOST_CMD_SUSPND_RX (3<<3)
@@ -63,7 +63,7 @@ struct mc32_stats
u32 tx_underrun_errors;
u32 tx_cts_errors;
u32 tx_timeout_errors;
-
+
/* various cruft */
u32 dataA[6];
u16 dataB[5];
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index e27778926eb..df42e28cc80 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -17,172 +17,6 @@
410 Severn Ave., Suite 210
Annapolis MD 21403
- Linux Kernel Additions:
-
- 0.99H+lk0.9 - David S. Miller - softnet, PCI DMA updates
- 0.99H+lk1.0 - Jeff Garzik <jgarzik@pobox.com>
- Remove compatibility defines for kernel versions < 2.2.x.
- Update for new 2.3.x module interface
- LK1.1.2 (March 19, 2000)
- * New PCI interface (jgarzik)
-
- LK1.1.3 25 April 2000, Andrew Morton <andrewm@uow.edu.au>
- - Merged with 3c575_cb.c
- - Don't set RxComplete in boomerang interrupt enable reg
- - spinlock in vortex_timer to protect mdio functions
- - disable local interrupts around call to vortex_interrupt in
- vortex_tx_timeout() (So vortex_interrupt can use spin_lock())
- - Select window 3 in vortex_timer()'s write to Wn3_MAC_Ctrl
- - In vortex_start_xmit(), move the lock to _after_ we've altered
- vp->cur_tx and vp->tx_full. This defeats the race between
- vortex_start_xmit() and vortex_interrupt which was identified
- by Bogdan Costescu.
- - Merged back support for six new cards from various sources
- - Set vortex_have_pci if pci_module_init returns zero (fixes cardbus
- insertion oops)
- - Tell it that 3c905C has NWAY for 100bT autoneg
- - Fix handling of SetStatusEnd in 'Too much work..' code, as
- per 2.3.99's 3c575_cb (Dave Hinds).
- - Split ISR into two for vortex & boomerang
- - Fix MOD_INC/DEC races
- - Handle resource allocation failures.
- - Fix 3CCFE575CT LED polarity
- - Make tx_interrupt_mitigation the default
-
- LK1.1.4 25 April 2000, Andrew Morton <andrewm@uow.edu.au>
- - Add extra TxReset to vortex_up() to fix 575_cb hotplug initialisation probs.
- - Put vortex_info_tbl into __devinitdata
- - In the vortex_error StatsFull HACK, disable stats in vp->intr_enable as well
- as in the hardware.
- - Increased the loop counter in issue_and_wait from 2,000 to 4,000.
-
- LK1.1.5 28 April 2000, andrewm
- - Added powerpc defines (John Daniel <jdaniel@etresoft.com> said these work...)
- - Some extra diagnostics
- - In vortex_error(), reset the Tx on maxCollisions. Otherwise most
- chips usually get a Tx timeout.
- - Added extra_reset module parm
- - Replaced some inline timer manip with mod_timer
- (Franois romieu <Francois.Romieu@nic.fr>)
- - In vortex_up(), don't make Wn3_config initialisation dependent upon has_nway
- (this came across from 3c575_cb).
-
- LK1.1.6 06 Jun 2000, andrewm
- - Backed out the PPC defines.
- - Use del_timer_sync(), mod_timer().
- - Fix wrapped ulong comparison in boomerang_rx()
- - Add IS_TORNADO, use it to suppress 3c905C checksum error msg
- (Donald Becker, I Lee Hetherington <ilh@sls.lcs.mit.edu>)
- - Replace union wn3_config with BFINS/BFEXT manipulation for
- sparc64 (Pete Zaitcev, Peter Jones)
- - In vortex_error, do_tx_reset and vortex_tx_timeout(Vortex):
- do a netif_wake_queue() to better recover from errors. (Anders Pedersen,
- Donald Becker)
- - Print a warning on out-of-memory (rate limited to 1 per 10 secs)
- - Added two more Cardbus 575 NICs: 5b57 and 6564 (Paul Wagland)
-
- LK1.1.7 2 Jul 2000 andrewm
- - Better handling of shared IRQs
- - Reset the transmitter on a Tx reclaim error
- - Fixed crash under OOM during vortex_open() (Mark Hemment)
- - Fix Rx cessation problem during OOM (help from Mark Hemment)
- - The spinlocks around the mdio access were blocking interrupts for 300uS.
- Fix all this to use spin_lock_bh() within mdio_read/write
- - Only write to TxFreeThreshold if it's a boomerang - other NICs don't
- have one.
- - Added 802.3x MAC-layer flow control support
-
- LK1.1.8 13 Aug 2000 andrewm
- - Ignore request_region() return value - already reserved if Cardbus.
- - Merged some additional Cardbus flags from Don's 0.99Qk
- - Some fixes for 3c556 (Fred Maciel)
- - Fix for EISA initialisation (Jan Rekorajski)
- - Renamed MII_XCVR_PWR and EEPROM_230 to align with 3c575_cb and D. Becker's drivers
- - Fixed MII_XCVR_PWR for 3CCFE575CT
- - Added INVERT_LED_PWR, used it.
- - Backed out the extra_reset stuff
-
- LK1.1.9 12 Sep 2000 andrewm
- - Backed out the tx_reset_resume flags. It was a no-op.
- - In vortex_error, don't reset the Tx on txReclaim errors
- - In vortex_error, don't reset the Tx on maxCollisions errors.
- Hence backed out all the DownListPtr logic here.
- - In vortex_error, give Tornado cards a partial TxReset on
- maxCollisions (David Hinds). Defined MAX_COLLISION_RESET for this.
- - Redid some driver flags and device names based on pcmcia_cs-3.1.20.
- - Fixed a bug where, if vp->tx_full is set when the interface
- is downed, it remains set when the interface is upped. Bad
- things happen.
-
- LK1.1.10 17 Sep 2000 andrewm
- - Added EEPROM_8BIT for 3c555 (Fred Maciel)
- - Added experimental support for the 3c556B Laptop Hurricane (Louis Gerbarg)
- - Add HAS_NWAY to "3c900 Cyclone 10Mbps TPO"
-
- LK1.1.11 13 Nov 2000 andrewm
- - Dump MOD_INC/DEC_USE_COUNT, use SET_MODULE_OWNER
-
- LK1.1.12 1 Jan 2001 andrewm (2.4.0-pre1)
- - Call pci_enable_device before we request our IRQ (Tobias Ringstrom)
- - Add 3c590 PCI latency timer hack to vortex_probe1 (from 0.99Ra)
- - Added extended issue_and_wait for the 3c905CX.
- - Look for an MII on PHY index 24 first (3c905CX oddity).
- - Add HAS_NWAY to 3cSOHO100-TX (Brett Frankenberger)
- - Don't free skbs we don't own on oom path in vortex_open().
-
- LK1.1.13 27 Jan 2001
- - Added explicit `medialock' flag so we can truly
- lock the media type down with `options'.
- - "check ioremap return and some tidbits" (Arnaldo Carvalho de Melo <acme@conectiva.com.br>)
- - Added and used EEPROM_NORESET for 3c556B PM resumes.
- - Fixed leakage of vp->rx_ring.
- - Break out separate HAS_HWCKSM device capability flag.
- - Kill vp->tx_full (ANK)
- - Merge zerocopy fragment handling (ANK?)
-
- LK1.1.14 15 Feb 2001
- - Enable WOL. Can be turned on with `enable_wol' module option.
- - EISA and PCI initialisation fixes (jgarzik, Manfred Spraul)
- - If a device's internalconfig register reports it has NWAY,
- use it, even if autoselect is enabled.
-
- LK1.1.15 6 June 2001 akpm
- - Prevent double counting of received bytes (Lars Christensen)
- - Add ethtool support (jgarzik)
- - Add module parm descriptions (Andrzej M. Krzysztofowicz)
- - Implemented alloc_etherdev() API
- - Special-case the 'Tx error 82' message.
-
- LK1.1.16 18 July 2001 akpm
- - Make NETIF_F_SG dependent upon nr_free_highpages(), not on CONFIG_HIGHMEM
- - Lessen verbosity of bootup messages
- - Fix WOL - use new PM API functions.
- - Use netif_running() instead of vp->open in suspend/resume.
- - Don't reset the interface logic on open/close/rmmod. It upsets
- autonegotiation, and hence DHCP (from 0.99T).
- - Back out EEPROM_NORESET flag because of the above (we do it for all
- NICs).
- - Correct 3c982 identification string
- - Rename wait_for_completion() to issue_and_wait() to avoid completion.h
- clash.
-
- LK1.1.17 18Dec01 akpm
- - PCI ID 9805 is a Python-T, not a dual-port Cyclone. Apparently.
- And it has NWAY.
- - Mask our advertised modes (vp->advertising) with our capabilities
- (MII reg5) when deciding which duplex mode to use.
- - Add `global_options' as default for options[]. Ditto global_enable_wol,
- global_full_duplex.
-
- LK1.1.18 01Jul02 akpm
- - Fix for undocumented transceiver power-up bit on some 3c566B's
- (Donald Becker, Rahul Karnik)
-
- - See http://www.zip.com.au/~akpm/linux/#3c59x-2.3 for more details.
- - Also see Documentation/networking/vortex.txt
-
- LK1.1.19 10Nov02 Marc Zyngier <maz@wild-wind.fr.eu.org>
- - EISA sysfs integration.
*/
/*
@@ -236,7 +70,6 @@ static int vortex_debug = VORTEX_DEBUG;
static int vortex_debug = 1;
#endif
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -375,8 +208,7 @@ limit of 4K.
of the drivers, and will likely be provided by some future kernel.
*/
enum pci_flags_bit {
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+ PCI_USES_MASTER=4,
};
enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4, IS_TORNADO=8,
@@ -446,95 +278,95 @@ static struct vortex_chip_info {
int io_size;
} vortex_info_tbl[] __devinitdata = {
{"3c590 Vortex 10Mbps",
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c592 EISA 10Mbps Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c597 EISA Fast Demon/Vortex", /* AKPM: from Don's 3c59x_cb.c 0.49H */
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c595 Vortex 100baseTx",
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c595 Vortex 100baseT4",
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c595 Vortex 100base-MII",
- PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, },
+ PCI_USES_MASTER, IS_VORTEX, 32, },
{"3c900 Boomerang 10baseT",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
+ PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
{"3c900 Boomerang 10Mbps Combo",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
+ PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, },
{"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c900 Cyclone 10Mbps Combo",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c900 Cyclone 10Mbps TPC", /* AKPM: from Don's 0.99M */
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c900B-FL Cyclone 10base-FL",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c905 Boomerang 100baseTx",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
+ PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
{"3c905 Boomerang 100baseT4",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
+ PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, },
{"3c905B Cyclone 100baseTx",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
{"3c905B Cyclone 10/100/BNC",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
{"3c905B-FX Cyclone 100baseFx",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c905C Tornado",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
{"3c920B-EMB-WNM (ATI Radeon 9100 IGP)",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_MII|HAS_HWCKSM, 128, },
{"3c980 Cyclone",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, },
{"3c980C Python-T",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
{"3cSOHO100-TX Hurricane",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM, 128, },
{"3c555 Laptop Hurricane",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|EEPROM_8BIT|HAS_HWCKSM, 128, },
{"3c556 Laptop Tornado",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_8BIT|HAS_CB_FNS|INVERT_MII_PWR|
HAS_HWCKSM, 128, },
{"3c556B Laptop Hurricane",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|EEPROM_OFFSET|HAS_CB_FNS|INVERT_MII_PWR|
WNO_XCVR_PWR|HAS_HWCKSM, 128, },
{"3c575 [Megahertz] 10/100 LAN CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+ PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
{"3c575 Boomerang CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
+ PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_8BIT, 128, },
{"3CCFE575BT Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|
INVERT_LED_PWR|HAS_HWCKSM, 128, },
{"3CCFE575CT Tornado CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
{"3CCFE656 Cyclone CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
INVERT_LED_PWR|HAS_HWCKSM, 128, },
{"3CCFEM656B Cyclone+Winmodem CardBus",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
INVERT_LED_PWR|HAS_HWCKSM, 128, },
{"3CXFEM656C Tornado+Winmodem CardBus", /* From pcmcia-cs-3.1.5 */
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_CB_FNS|EEPROM_8BIT|INVERT_MII_PWR|
MAX_COLLISION_RESET|HAS_HWCKSM, 128, },
{"3c450 HomePNA Tornado", /* AKPM: from Don's 0.99Q */
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
{"3c920 Tornado",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
{"3c982 Hydra Dual Port A",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
{"3c982 Hydra Dual Port B",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
{"3c905B-T4",
- PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+ PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
{"3c920B-EMB-WNM Tornado",
- PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+ PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
{NULL,}, /* NULL terminated list. */
};
@@ -897,7 +729,7 @@ static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
#endif
static void vortex_tx_timeout(struct net_device *dev);
static void acpi_set_WOL(struct net_device *dev);
-static struct ethtool_ops vortex_ethtool_ops;
+static const struct ethtool_ops vortex_ethtool_ops;
static void set_8021q_mode(struct net_device *dev, int enable);
/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
@@ -964,7 +796,7 @@ static void poll_vortex(struct net_device *dev)
local_irq_disable();
(vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL);
local_irq_restore(flags);
-}
+}
#endif
#ifdef CONFIG_PM
@@ -998,7 +830,7 @@ static int vortex_resume(struct pci_dev *pdev)
pci_enable_device(pdev);
pci_set_master(pdev);
if (request_irq(dev->irq, vp->full_bus_master_rx ?
- &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
+ &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev)) {
printk(KERN_WARNING "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
pci_disable_device(pdev);
return -EBUSY;
@@ -1019,6 +851,7 @@ static struct eisa_device_id vortex_eisa_ids[] = {
{ "TCM5970", CH_3C597 },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
static int vortex_eisa_probe(struct device *device);
static int vortex_eisa_remove(struct device *device);
@@ -1072,7 +905,7 @@ static int vortex_eisa_remove(struct device *device)
vp = netdev_priv(dev);
ioaddr = vp->ioaddr;
-
+
unregister_netdev(dev);
iowrite16(TotalReset|0x14, ioaddr + EL3_CMD);
release_region(dev->base_addr, VORTEX_TOTAL_SIZE);
@@ -1103,7 +936,7 @@ static int __init vortex_eisa_init(void)
eisa_found = 1;
}
#endif
-
+
/* Special code to work-around the Compaq PCI BIOS32 problem. */
if (compaq_ioaddr) {
vortex_probe1(NULL, ioport_map(compaq_ioaddr, VORTEX_TOTAL_SIZE),
@@ -1121,7 +954,7 @@ static int __devinit vortex_init_one(struct pci_dev *pdev,
struct vortex_chip_info *vci;
void __iomem *ioaddr;
- /* wake up and enable device */
+ /* wake up and enable device */
rc = pci_enable_device(pdev);
if (rc < 0)
goto out;
@@ -1257,7 +1090,7 @@ static int __devinit vortex_probe1(struct device *gendev,
if (request_region(dev->base_addr, vci->io_size, print_name) != NULL)
vp->must_free_region = 1;
- /* enable bus-mastering if necessary */
+ /* enable bus-mastering if necessary */
if (vci->flags & PCI_USES_MASTER)
pci_set_master(pdev);
@@ -1299,7 +1132,7 @@ static int __devinit vortex_probe1(struct device *gendev,
vp->tx_ring_dma = vp->rx_ring_dma + sizeof(struct boom_rx_desc) * RX_RING_SIZE;
/* if we are a PCI driver, we store info in pdev->driver_data
- * instead of a module list */
+ * instead of a module list */
if (pdev)
pci_set_drvdata(pdev, dev);
if (edev)
@@ -1408,8 +1241,10 @@ static int __devinit vortex_probe1(struct device *gendev,
}
if (print_info) {
- printk(KERN_INFO "%s: CardBus functions mapped %8.8lx->%p\n",
- print_name, pci_resource_start(pdev, 2),
+ printk(KERN_INFO "%s: CardBus functions mapped "
+ "%16.16llx->%p\n",
+ print_name,
+ (unsigned long long)pci_resource_start(pdev, 2),
vp->cb_fn_base);
}
EL3WINDOW(2);
@@ -1559,7 +1394,7 @@ static int __devinit vortex_probe1(struct device *gendev,
dev->tx_timeout = vortex_tx_timeout;
dev->watchdog_timeo = (watchdog * HZ) / 1000;
#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = poll_vortex;
+ dev->poll_controller = poll_vortex;
#endif
if (pdev) {
vp->pm_state_valid = 1;
@@ -1833,7 +1668,7 @@ vortex_open(struct net_device *dev)
/* Use the now-standard shared IRQ implementation. */
if ((retval = request_irq(dev->irq, vp->full_bus_master_rx ?
- &boomerang_interrupt : &vortex_interrupt, SA_SHIRQ, dev->name, dev))) {
+ &boomerang_interrupt : &vortex_interrupt, IRQF_SHARED, dev->name, dev))) {
printk(KERN_ERR "%s: Could not reserve IRQ %d\n", dev->name, dev->irq);
goto out;
}
@@ -1897,7 +1732,7 @@ vortex_timer(unsigned long data)
printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo);
}
- disable_irq(dev->irq);
+ disable_irq_lockdep(dev->irq);
old_window = ioread16(ioaddr + EL3_CMD) >> 13;
EL3WINDOW(4);
media_status = ioread16(ioaddr + Wn4_Media);
@@ -1978,7 +1813,7 @@ leave_media_alone:
dev->name, media_tbl[dev->if_port].name);
EL3WINDOW(old_window);
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
mod_timer(&vp->timer, RUN_AT(next_tick));
if (vp->deferred)
iowrite16(FakeIntr, ioaddr + EL3_CMD);
@@ -2041,11 +1876,11 @@ static void vortex_tx_timeout(struct net_device *dev)
vp->stats.tx_dropped++;
netif_wake_queue(dev);
}
-
+
/* Issue Tx Enable */
iowrite16(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies;
-
+
/* Switch to register set 7 for normal use. */
EL3WINDOW(7);
}
@@ -2243,7 +2078,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
vp->tx_ring[entry].next = 0;
#if DO_ZEROCOPY
- if (skb->ip_summed != CHECKSUM_HW)
+ if (skb->ip_summed != CHECKSUM_PARTIAL)
vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
else
vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded | AddTCPChksum | AddUDPChksum);
@@ -2482,10 +2317,10 @@ boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((vp->tx_ring[entry].status & DN_COMPLETE) == 0)
break; /* It still hasn't been processed. */
#endif
-
+
if (vp->tx_skbuff[entry]) {
struct sk_buff *skb = vp->tx_skbuff[entry];
-#if DO_ZEROCOPY
+#if DO_ZEROCOPY
int i;
for (i=0; i<=skb_shinfo(skb)->nr_frags; i++)
pci_unmap_single(VORTEX_PCI(vp),
@@ -2799,7 +2634,7 @@ vortex_close(struct net_device *dev)
"not using them!\n", dev->name);
}
#endif
-
+
free_irq(dev->irq, dev);
if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
@@ -2841,7 +2676,7 @@ dump_tx_ring(struct net_device *dev)
if (vortex_debug > 0) {
struct vortex_private *vp = netdev_priv(dev);
void __iomem *ioaddr = vp->ioaddr;
-
+
if (vp->full_bus_master_tx) {
int i;
int stalled = ioread32(ioaddr + PktStatus) & 0x04; /* Possible racy. But it's only debug stuff */
@@ -3039,7 +2874,7 @@ static void vortex_get_drvinfo(struct net_device *dev,
}
}
-static struct ethtool_ops vortex_ethtool_ops = {
+static const struct ethtool_ops vortex_ethtool_ops = {
.get_drvinfo = vortex_get_drvinfo,
.get_strings = vortex_get_strings,
.get_msglevel = vortex_get_msglevel,
@@ -3094,7 +2929,7 @@ static void set_rx_mode(struct net_device *dev)
int new_mode;
if (dev->flags & IFF_PROMISC) {
- if (vortex_debug > 0)
+ if (vortex_debug > 3)
printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
} else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) {
@@ -3335,7 +3170,7 @@ static int __init vortex_init(void)
{
int pci_rc, eisa_rc;
- pci_rc = pci_module_init(&vortex_driver);
+ pci_rc = pci_register_driver(&vortex_driver);
eisa_rc = vortex_eisa_init();
if (pci_rc == 0)
@@ -3356,7 +3191,7 @@ static void __exit vortex_eisa_cleanup(void)
/* Take care of the EISA devices */
eisa_driver_unregister(&vortex_eisa_driver);
#endif
-
+
if (compaq_net_device) {
vp = compaq_net_device->priv;
ioaddr = ioport_map(compaq_net_device->base_addr,
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index 86633c5f1a4..db7b19a5cd5 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -1,7 +1,7 @@
-/*
- * 7990.c -- LANCE ethernet IC generic routines.
+/*
+ * 7990.c -- LANCE ethernet IC generic routines.
* This is an attempt to separate out the bits of various ethernet
- * drivers that are common because they all use the AMD 7990 LANCE
+ * drivers that are common because they all use the AMD 7990 LANCE
* (Local Area Network Controller for Ethernet) chip.
*
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
@@ -9,7 +9,7 @@
* Most of this stuff was obtained by looking at other LANCE drivers,
* in particular a2065.[ch]. The AMD C-LANCE datasheet was also helpful.
* NB: this was made easy by the fact that Jes Sorensen had cleaned up
- * most of a2025 and sunlance with the aim of merging them, so the
+ * most of a2025 and sunlance with the aim of merging them, so the
* common code was pretty obvious.
*/
#include <linux/crc32.h>
@@ -109,10 +109,10 @@ do { \
ib->btx_ring[t].length,\
ib->btx_ring[t].misc, ib->btx_ring[t].tmd1_bits);\
}\
-} while (0)
+} while (0)
#else
#define PRINT_RINGS()
-#endif
+#endif
/* Load the CSR registers. The LANCE has to be STOPped when we do this! */
static void load_csrs (struct lance_private *lp)
@@ -157,7 +157,7 @@ static void lance_init_ring (struct net_device *dev)
* a2065 and atarilance do the byteswap and lance.c (PC) doesn't.
* However, the datasheet says that the BSWAP bit doesn't affect
* the init block, so surely it should be low byte first for
- * everybody? Um.]
+ * everybody? Um.]
* We could define the ib->physaddr as three 16bit values and
* use (addr[1] << 8) | addr[0] & co, but this is more efficient.
*/
@@ -171,11 +171,11 @@ static void lance_init_ring (struct net_device *dev)
#else
for (i=0; i<6; i++)
ib->phys_addr[i] = dev->dev_addr[i];
-#endif
+#endif
if (DEBUG_IRING)
printk ("TX rings:\n");
-
+
lp->tx_full = 0;
/* Setup the Tx ring entries */
for (i = 0; i < (1<<lp->lance_log_tx_bufs); i++) {
@@ -185,7 +185,7 @@ static void lance_init_ring (struct net_device *dev)
ib->btx_ring [i].tmd1_bits = 0;
ib->btx_ring [i].length = 0xf000; /* The ones required by tmd2 */
ib->btx_ring [i].misc = 0;
- if (DEBUG_IRING)
+ if (DEBUG_IRING)
printk ("%d: 0x%8.8x\n", i, leptr);
}
@@ -206,14 +206,14 @@ static void lance_init_ring (struct net_device *dev)
}
/* Setup the initialization block */
-
+
/* Setup rx descriptor pointer */
leptr = LANCE_ADDR(&aib->brx_ring);
ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
ib->rx_ptr = leptr;
if (DEBUG_IRING)
printk ("RX ptr: %8.8x\n", leptr);
-
+
/* Setup tx descriptor pointer */
leptr = LANCE_ADDR(&aib->btx_ring);
ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
@@ -256,7 +256,7 @@ static int lance_reset (struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int status;
-
+
/* Stop the lance */
WRITERAP(lp, LE_CSR0);
WRITERDP(lp, LE_C0_STOP);
@@ -297,7 +297,7 @@ static int lance_rx (struct net_device *dev)
#endif
#ifdef CONFIG_HP300
blinken_leds(0x40, 0);
-#endif
+#endif
WRITERDP(lp, LE_C0_RINT | LE_C0_INEA); /* ack Rx int, reenable ints */
for (rd = &ib->brx_ring [lp->rx_new]; /* For each Rx ring we own... */
!((bits = rd->rmd1_bits) & LE_R1_OWN);
@@ -330,7 +330,7 @@ static int lance_rx (struct net_device *dev)
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
return 0;
}
-
+
skb->dev = dev;
skb_reserve (skb, 2); /* 16 byte align */
skb_put (skb, len); /* make room */
@@ -374,10 +374,10 @@ static int lance_tx (struct net_device *dev)
/* If we hit a packet not owned by us, stop */
if (td->tmd1_bits & LE_T1_OWN)
break;
-
+
if (td->tmd1_bits & LE_T1_ERR) {
status = td->misc;
-
+
lp->stats.tx_errors++;
if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
@@ -429,7 +429,7 @@ static int lance_tx (struct net_device *dev)
lp->stats.tx_packets++;
}
-
+
j = (j + 1) & lp->tx_ring_mod_mask;
}
lp->tx_old = j;
@@ -450,7 +450,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
csr0 = READRDP(lp);
PRINT_RINGS();
-
+
if (!(csr0 & LE_C0_INTR)) { /* Check if any interrupt has */
spin_unlock (&lp->devlock);
return IRQ_NONE; /* been generated by the Lance. */
@@ -476,7 +476,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
if (csr0 & LE_C0_MISS)
lp->stats.rx_errors++; /* Missed a Rx frame. */
if (csr0 & LE_C0_MERR) {
- printk("%s: Bus master arbitration failure, status %4.4x.\n",
+ printk("%s: Bus master arbitration failure, status %4.4x.\n",
dev->name, csr0);
/* Restart the chip. */
WRITERDP(lp, LE_C0_STRT);
@@ -486,7 +486,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
lp->tx_full = 0;
netif_wake_queue (dev);
}
-
+
WRITERAP(lp, LE_CSR0);
WRITERDP(lp, LE_C0_BABL|LE_C0_CERR|LE_C0_MISS|LE_C0_MERR|LE_C0_IDON|LE_C0_INEA);
@@ -498,7 +498,7 @@ int lance_open (struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int res;
-
+
/* Install the Interrupt handler. Or we could shunt this out to specific drivers? */
if (request_irq(lp->irq, lance_interrupt, 0, lp->name, dev))
return -EAGAIN;
@@ -513,7 +513,7 @@ int lance_open (struct net_device *dev)
int lance_close (struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
-
+
netif_stop_queue (dev);
/* Stop the LANCE */
@@ -553,7 +553,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
/* dump the packet */
{
int i;
-
+
for (i = 0; i < 64; i++) {
if ((i % 16) == 0)
printk ("\n");
@@ -565,11 +565,11 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
entry = lp->tx_new & lp->tx_ring_mod_mask;
ib->btx_ring [entry].length = (-len) | 0xf000;
ib->btx_ring [entry].misc = 0;
-
+
if (skb->len < ETH_ZLEN)
memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN);
memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
-
+
/* Now, give the packet to the lance */
ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
@@ -579,7 +579,7 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
WRITERDP(lp, LE_C0_INEA | LE_C0_TDMD);
dev->trans_start = jiffies;
dev_kfree_skb (skb);
-
+
spin_lock_irqsave (&lp->devlock, flags);
if (TX_BUFFS_AVAIL)
netif_start_queue (dev);
@@ -607,9 +607,9 @@ static void lance_load_multicast (struct net_device *dev)
char *addrs;
int i;
u32 crc;
-
+
/* set all multicast bits */
- if (dev->flags & IFF_ALLMULTI){
+ if (dev->flags & IFF_ALLMULTI){
ib->filter [0] = 0xffffffff;
ib->filter [1] = 0xffffffff;
return;
@@ -626,7 +626,7 @@ static void lance_load_multicast (struct net_device *dev)
/* multicast address? */
if (!(*addrs & 1))
continue;
-
+
crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
diff --git a/drivers/net/7990.h b/drivers/net/7990.h
index 31ae5099738..b1212b5ed92 100644
--- a/drivers/net/7990.h
+++ b/drivers/net/7990.h
@@ -1,9 +1,9 @@
-/*
+/*
* 7990.h -- LANCE ethernet IC generic routines.
* This is an attempt to separate out the bits of various ethernet
* drivers that are common because they all use the AMD 7990 LANCE
* (Local Area Network Controller for Ethernet) chip.
- *
+ *
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
*
* Most of this stuff was obtained by looking at other LANCE drivers,
@@ -55,7 +55,7 @@ struct lance_rx_desc {
*/
volatile unsigned short mblength; /* Actual number of bytes received */
};
-
+
/* Ditto for TMD: */
struct lance_tx_desc {
volatile unsigned short tmd0; /* low address of packet */
@@ -80,8 +80,8 @@ struct lance_init_block {
volatile unsigned short rx_len; /* receive len and high addr */
volatile unsigned short tx_ptr; /* transmit descriptor addr */
volatile unsigned short tx_len; /* transmit len and high addr */
-
- /* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
+
+ /* The Tx and Rx ring entries must be aligned on 8-byte boundaries.
* This will be true if this whole struct is 8-byte aligned.
*/
volatile struct lance_tx_desc btx_ring[TX_RING_SIZE];
@@ -104,21 +104,21 @@ struct lance_private
unsigned long base;
volatile struct lance_init_block *init_block; /* CPU address of RAM */
volatile struct lance_init_block *lance_init_block; /* LANCE address of RAM */
-
+
int rx_new, tx_new;
int rx_old, tx_old;
-
+
int lance_log_rx_bufs, lance_log_tx_bufs;
int rx_ring_mod_mask, tx_ring_mod_mask;
-
+
struct net_device_stats stats;
int tpe; /* TPE is selected */
int auto_select; /* cable-selection is by carrier */
unsigned short busmaster_regval;
unsigned int irq; /* IRQ to register */
-
- /* This is because the HP LANCE is disgusting and you have to check
+
+ /* This is because the HP LANCE is disgusting and you have to check
* a DIO-specific register every time you read/write the LANCE regs :-<
* [could we get away with making these some sort of macro?]
*/
@@ -148,7 +148,7 @@ struct lance_private
#define LE_C0_RINT 0x0400 /* Receive Interrupt */
#define LE_C0_TINT 0x0200 /* Transmit Interrupt */
#define LE_C0_IDON 0x0100 /* Initialization Done */
-#define LE_C0_INTR 0x0080 /* Interrupt Flag
+#define LE_C0_INTR 0x0080 /* Interrupt Flag
= BABL | MISS | MERR | RINT | TINT | IDON */
#define LE_C0_INEA 0x0040 /* Interrupt Enable */
#define LE_C0_RXON 0x0020 /* Receive On */
@@ -185,7 +185,7 @@ struct lance_private
#define LE_MO_PSEL1 0x0100 /* port selection bit1 */
#define LE_MO_PSEL0 0x0080 /* port selection bit0 */
/* and this one is from the C-LANCE data sheet... */
-#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
+#define LE_MO_EMBA 0x0080 /* Enable Modified Backoff Algorithm
(C-LANCE, not original LANCE) */
#define LE_MO_INTL 0x0040 /* Internal Loopback */
#define LE_MO_DRTY 0x0020 /* Disable Retry */
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 0cdc830449d..5a4990ae373 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -48,11 +48,10 @@
*/
#define DRV_NAME "8139cp"
-#define DRV_VERSION "1.2"
+#define DRV_VERSION "1.3"
#define DRV_RELDATE "Mar 22, 2004"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -315,12 +314,6 @@ struct cp_desc {
u64 addr;
};
-struct ring_info {
- struct sk_buff *skb;
- dma_addr_t mapping;
- u32 len;
-};
-
struct cp_dma_stats {
u64 tx_ok;
u64 rx_ok;
@@ -354,23 +347,23 @@ struct cp_private {
struct net_device_stats net_stats;
struct cp_extra_stats cp_stats;
- unsigned rx_tail ____cacheline_aligned;
+ unsigned rx_head ____cacheline_aligned;
+ unsigned rx_tail;
struct cp_desc *rx_ring;
- struct ring_info rx_skb[CP_RX_RING_SIZE];
- unsigned rx_buf_sz;
+ struct sk_buff *rx_skb[CP_RX_RING_SIZE];
unsigned tx_head ____cacheline_aligned;
unsigned tx_tail;
-
struct cp_desc *tx_ring;
- struct ring_info tx_skb[CP_TX_RING_SIZE];
- dma_addr_t ring_dma;
+ struct sk_buff *tx_skb[CP_TX_RING_SIZE];
+
+ unsigned rx_buf_sz;
+ unsigned wol_enabled : 1; /* Is Wake-on-LAN enabled? */
#if CP_VLAN_TAG_USED
struct vlan_group *vlgrp;
#endif
-
- unsigned int wol_enabled : 1; /* Is Wake-on-LAN enabled? */
+ dma_addr_t ring_dma;
struct mii_if_info mii_if;
};
@@ -408,10 +401,8 @@ static int cp_set_eeprom(struct net_device *dev,
struct ethtool_eeprom *eeprom, u8 *data);
static struct pci_device_id cp_pci_tbl[] = {
- { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
- { PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139), },
+ { PCI_DEVICE(PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322), },
{ },
};
MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
@@ -543,7 +534,7 @@ rx_status_loop:
struct cp_desc *desc;
unsigned buflen;
- skb = cp->rx_skb[rx_tail].skb;
+ skb = cp->rx_skb[rx_tail];
BUG_ON(!skb);
desc = &cp->rx_ring[rx_tail];
@@ -552,7 +543,7 @@ rx_status_loop:
break;
len = (status & 0x1fff) - 4;
- mapping = cp->rx_skb[rx_tail].mapping;
+ mapping = le64_to_cpu(desc->addr);
if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {
/* we don't support incoming fragmented frames.
@@ -573,7 +564,7 @@ rx_status_loop:
if (netif_msg_rx_status(cp))
printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
- cp->dev->name, rx_tail, status, len);
+ dev->name, rx_tail, status, len);
buflen = cp->rx_buf_sz + RX_OFFSET;
new_skb = dev_alloc_skb (buflen);
@@ -583,7 +574,7 @@ rx_status_loop:
}
skb_reserve(new_skb, RX_OFFSET);
- new_skb->dev = cp->dev;
+ new_skb->dev = dev;
pci_unmap_single(cp->pdev, mapping,
buflen, PCI_DMA_FROMDEVICE);
@@ -596,11 +587,9 @@ rx_status_loop:
skb_put(skb, len);
- mapping =
- cp->rx_skb[rx_tail].mapping =
- pci_map_single(cp->pdev, new_skb->data,
- buflen, PCI_DMA_FROMDEVICE);
- cp->rx_skb[rx_tail].skb = new_skb;
+ mapping = pci_map_single(cp->pdev, new_skb->data, buflen,
+ PCI_DMA_FROMDEVICE);
+ cp->rx_skb[rx_tail] = new_skb;
cp_rx_skb(cp, skb, desc);
rx++;
@@ -718,19 +707,21 @@ static void cp_tx (struct cp_private *cp)
unsigned tx_tail = cp->tx_tail;
while (tx_tail != tx_head) {
+ struct cp_desc *txd = cp->tx_ring + tx_tail;
struct sk_buff *skb;
u32 status;
rmb();
- status = le32_to_cpu(cp->tx_ring[tx_tail].opts1);
+ status = le32_to_cpu(txd->opts1);
if (status & DescOwn)
break;
- skb = cp->tx_skb[tx_tail].skb;
+ skb = cp->tx_skb[tx_tail];
BUG_ON(!skb);
- pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
- cp->tx_skb[tx_tail].len, PCI_DMA_TODEVICE);
+ pci_unmap_single(cp->pdev, le64_to_cpu(txd->addr),
+ le32_to_cpu(txd->opts1) & 0xffff,
+ PCI_DMA_TODEVICE);
if (status & LastFrag) {
if (status & (TxError | TxFIFOUnder)) {
@@ -757,7 +748,7 @@ static void cp_tx (struct cp_private *cp)
dev_kfree_skb_irq(skb);
}
- cp->tx_skb[tx_tail].skb = NULL;
+ cp->tx_skb[tx_tail] = NULL;
tx_tail = NEXT_TX(tx_tail);
}
@@ -814,7 +805,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (mss)
flags |= LargeSend | ((mss & MSSMask) << MSSShift);
- else if (skb->ip_summed == CHECKSUM_HW) {
+ else if (skb->ip_summed == CHECKSUM_PARTIAL) {
const struct iphdr *ip = skb->nh.iph;
if (ip->protocol == IPPROTO_TCP)
flags |= IPCS | TCPCS;
@@ -827,9 +818,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
txd->opts1 = cpu_to_le32(flags);
wmb();
- cp->tx_skb[entry].skb = skb;
- cp->tx_skb[entry].mapping = mapping;
- cp->tx_skb[entry].len = len;
+ cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
} else {
struct cp_desc *txd;
@@ -845,9 +834,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
first_len = skb_headlen(skb);
first_mapping = pci_map_single(cp->pdev, skb->data,
first_len, PCI_DMA_TODEVICE);
- cp->tx_skb[entry].skb = skb;
- cp->tx_skb[entry].mapping = first_mapping;
- cp->tx_skb[entry].len = first_len;
+ cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
@@ -868,7 +855,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
if (mss)
ctrl |= LargeSend |
((mss & MSSMask) << MSSShift);
- else if (skb->ip_summed == CHECKSUM_HW) {
+ else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (ip->protocol == IPPROTO_TCP)
ctrl |= IPCS | TCPCS;
else if (ip->protocol == IPPROTO_UDP)
@@ -888,9 +875,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
txd->opts1 = cpu_to_le32(ctrl);
wmb();
- cp->tx_skb[entry].skb = skb;
- cp->tx_skb[entry].mapping = mapping;
- cp->tx_skb[entry].len = len;
+ cp->tx_skb[entry] = skb;
entry = NEXT_TX(entry);
}
@@ -899,7 +884,7 @@ static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
txd->addr = cpu_to_le64(first_mapping);
wmb();
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (ip->protocol == IPPROTO_TCP)
txd->opts1 = cpu_to_le32(first_eor | first_len |
FirstFrag | DescOwn |
@@ -943,8 +928,6 @@ static void __cp_set_rx_mode (struct net_device *dev)
/* Note: do not reorder, GCC is clever about common statements. */
if (dev->flags & IFF_PROMISC) {
/* Unconditionally log net taps. */
- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
@@ -1092,6 +1075,7 @@ static int cp_refill_rx (struct cp_private *cp)
for (i = 0; i < CP_RX_RING_SIZE; i++) {
struct sk_buff *skb;
+ dma_addr_t mapping;
skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET);
if (!skb)
@@ -1100,12 +1084,12 @@ static int cp_refill_rx (struct cp_private *cp)
skb->dev = cp->dev;
skb_reserve(skb, RX_OFFSET);
- cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
- skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- cp->rx_skb[i].skb = skb;
+ mapping = pci_map_single(cp->pdev, skb->data, cp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ cp->rx_skb[i] = skb;
cp->rx_ring[i].opts2 = 0;
- cp->rx_ring[i].addr = cpu_to_le64(cp->rx_skb[i].mapping);
+ cp->rx_ring[i].addr = cpu_to_le64(mapping);
if (i == (CP_RX_RING_SIZE - 1))
cp->rx_ring[i].opts1 =
cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
@@ -1153,23 +1137,27 @@ static int cp_alloc_rings (struct cp_private *cp)
static void cp_clean_rings (struct cp_private *cp)
{
+ struct cp_desc *desc;
unsigned i;
for (i = 0; i < CP_RX_RING_SIZE; i++) {
- if (cp->rx_skb[i].skb) {
- pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping,
+ if (cp->rx_skb[i]) {
+ desc = cp->rx_ring + i;
+ pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(cp->rx_skb[i].skb);
+ dev_kfree_skb(cp->rx_skb[i]);
}
}
for (i = 0; i < CP_TX_RING_SIZE; i++) {
- if (cp->tx_skb[i].skb) {
- struct sk_buff *skb = cp->tx_skb[i].skb;
-
- pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping,
- cp->tx_skb[i].len, PCI_DMA_TODEVICE);
- if (le32_to_cpu(cp->tx_ring[i].opts1) & LastFrag)
+ if (cp->tx_skb[i]) {
+ struct sk_buff *skb = cp->tx_skb[i];
+
+ desc = cp->tx_ring + i;
+ pci_unmap_single(cp->pdev, le64_to_cpu(desc->addr),
+ le32_to_cpu(desc->opts1) & 0xffff,
+ PCI_DMA_TODEVICE);
+ if (le32_to_cpu(desc->opts1) & LastFrag)
dev_kfree_skb(skb);
cp->net_stats.tx_dropped++;
}
@@ -1178,8 +1166,8 @@ static void cp_clean_rings (struct cp_private *cp)
memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
- memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE);
- memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);
+ memset(cp->rx_skb, 0, sizeof(struct sk_buff *) * CP_RX_RING_SIZE);
+ memset(cp->tx_skb, 0, sizeof(struct sk_buff *) * CP_TX_RING_SIZE);
}
static void cp_free_rings (struct cp_private *cp)
@@ -1204,7 +1192,7 @@ static int cp_open (struct net_device *dev)
cp_init_hw(cp);
- rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
+ rc = request_irq(dev->irq, cp_interrupt, IRQF_SHARED, dev->name, dev);
if (rc)
goto err_out_hw;
@@ -1558,7 +1546,7 @@ static void cp_get_ethtool_stats (struct net_device *dev,
pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma);
}
-static struct ethtool_ops cp_ethtool_ops = {
+static const struct ethtool_ops cp_ethtool_ops = {
.get_drvinfo = cp_get_drvinfo,
.get_regs_len = cp_get_regs_len,
.get_stats_count = cp_get_stats_count,
@@ -1823,7 +1811,7 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
struct cp_private *cp;
int rc;
void __iomem *regs;
- long pciaddr;
+ resource_size_t pciaddr;
unsigned int addr_len, i, pci_using_dac;
u8 pci_rev;
@@ -1837,9 +1825,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
- printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
+ dev_err(&pdev->dev,
+ "This (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
+ pdev->vendor, pdev->device, pci_rev);
+ dev_err(&pdev->dev, "Try the \"8139too\" driver instead.\n");
return -ENODEV;
}
@@ -1877,14 +1866,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pciaddr = pci_resource_start(pdev, 1);
if (!pciaddr) {
rc = -EIO;
- printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "no MMIO resource\n");
goto err_out_res;
}
if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
rc = -EIO;
- printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
- pci_resource_len(pdev, 1), pci_name(pdev));
+ dev_err(&pdev->dev, "MMIO resource (%llx) too small\n",
+ (unsigned long long)pci_resource_len(pdev, 1));
goto err_out_res;
}
@@ -1898,14 +1886,15 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "No usable DMA configuration, aborting.\n");
goto err_out_res;
}
rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
- printk(KERN_ERR PFX "No usable consistent DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "No usable consistent DMA configuration, "
+ "aborting.\n");
goto err_out_res;
}
}
@@ -1916,8 +1905,9 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
regs = ioremap(pciaddr, CP_REGS_SIZE);
if (!regs) {
rc = -EIO;
- printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
- pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
+ dev_err(&pdev->dev, "Cannot map PCI MMIO (%Lx@%Lx)\n",
+ (unsigned long long)pci_resource_len(pdev, 1),
+ (unsigned long long)pciaddr);
goto err_out_res;
}
dev->base_addr = (unsigned long) regs;
@@ -1986,7 +1976,8 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* enable busmastering and memory-write-invalidate */
pci_set_master(pdev);
- if (cp->wol_enabled) cp_set_d3_state (cp);
+ if (cp->wol_enabled)
+ cp_set_d3_state (cp);
return 0;
@@ -2008,10 +1999,10 @@ static void cp_remove_one (struct pci_dev *pdev)
struct net_device *dev = pci_get_drvdata(pdev);
struct cp_private *cp = netdev_priv(dev);
- BUG_ON(!dev);
unregister_netdev(dev);
iounmap(cp->regs);
- if (cp->wol_enabled) pci_set_power_state (pdev, PCI_D0);
+ if (cp->wol_enabled)
+ pci_set_power_state (pdev, PCI_D0);
pci_release_regions(pdev);
pci_clear_mwi(pdev);
pci_disable_device(pdev);
@@ -2022,14 +2013,12 @@ static void cp_remove_one (struct pci_dev *pdev)
#ifdef CONFIG_PM
static int cp_suspend (struct pci_dev *pdev, pm_message_t state)
{
- struct net_device *dev;
- struct cp_private *cp;
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct cp_private *cp = netdev_priv(dev);
unsigned long flags;
- dev = pci_get_drvdata (pdev);
- cp = netdev_priv(dev);
-
- if (!dev || !netif_running (dev)) return 0;
+ if (!netif_running(dev))
+ return 0;
netif_device_detach (dev);
netif_stop_queue (dev);
@@ -2095,7 +2084,7 @@ static int __init cp_init (void)
#ifdef MODULE
printk("%s", version);
#endif
- return pci_module_init (&cp_driver);
+ return pci_register_driver(&cp_driver);
}
static void __exit cp_exit (void)
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index abd6261465f..dbc5c0b1b96 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -90,10 +90,9 @@
*/
#define DRV_NAME "8139too"
-#define DRV_VERSION "0.9.27"
+#define DRV_VERSION "0.9.28"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/compiler.h>
@@ -640,7 +639,7 @@ static void __set_rx_mode (struct net_device *dev);
static void rtl8139_hw_start (struct net_device *dev);
static void rtl8139_thread (void *_data);
static void rtl8139_tx_timeout_task(void *_data);
-static struct ethtool_ops rtl8139_ethtool_ops;
+static const struct ethtool_ops rtl8139_ethtool_ops;
/* write MMIO register, with flush */
/* Flush avoids rtl8139 bug w/ posted MMIO writes */
@@ -769,7 +768,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* dev and priv zeroed in alloc_etherdev */
dev = alloc_etherdev (sizeof (*tp));
if (dev == NULL) {
- printk (KERN_ERR PFX "%s: Unable to alloc new net device\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Unable to alloc new net device\n");
return -ENOMEM;
}
SET_MODULE_OWNER(dev);
@@ -801,31 +800,31 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
#ifdef USE_IO_OPS
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "%s: region #0 not a PIO resource, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
/* check for weird/broken PCI region reporting */
if (pio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI I/O region size(s), aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Invalid PCI I/O region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#else
/* make sure PCI base addr 1 is MMIO */
if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "%s: region #1 not an MMIO resource, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
if (mmio_len < RTL_MIN_IO_SIZE) {
- printk (KERN_ERR PFX "%s: Invalid PCI mem region size(s), aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "Invalid PCI mem region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
#endif
- rc = pci_request_regions (pdev, "8139too");
+ rc = pci_request_regions (pdev, DRV_NAME);
if (rc)
goto err_out;
disable_dev_on_err = 1;
@@ -836,7 +835,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
#ifdef USE_IO_OPS
ioaddr = ioport_map(pio_start, pio_len);
if (!ioaddr) {
- printk (KERN_ERR PFX "%s: cannot map PIO, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "cannot map PIO, aborting\n");
rc = -EIO;
goto err_out;
}
@@ -847,7 +846,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* ioremap MMIO region */
ioaddr = pci_iomap(pdev, 1, 0);
if (ioaddr == NULL) {
- printk (KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pdev));
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out;
}
@@ -861,8 +860,7 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
/* check for missing/broken hardware */
if (RTL_R32 (TxConfig) == 0xFFFFFFFF) {
- printk (KERN_ERR PFX "%s: Chip not responding, ignoring board\n",
- pci_name(pdev));
+ dev_err(&pdev->dev, "Chip not responding, ignoring board\n");
rc = -EIO;
goto err_out;
}
@@ -876,9 +874,10 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev,
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "%s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "%s: TxConfig = 0x%lx\n", pci_name(pdev), RTL_R32 (TxConfig));
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "TxConfig = 0x%lx\n", RTL_R32 (TxConfig));
tp->chipset = 0;
match:
@@ -955,9 +954,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
- printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
- pci_name(pdev), pdev->vendor, pdev->device, pci_rev);
- printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+ dev_info(&pdev->dev,
+ "This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+ pdev->vendor, pdev->device, pci_rev);
+ dev_info(&pdev->dev,
+ "Use the \"8139cp\" driver for improved performance and stability.\n");
}
i = rtl8139_init_board (pdev, &dev);
@@ -1311,7 +1312,7 @@ static int rtl8139_open (struct net_device *dev)
int retval;
void __iomem *ioaddr = tp->mmio_addr;
- retval = request_irq (dev->irq, rtl8139_interrupt, SA_SHIRQ, dev->name, dev);
+ retval = request_irq (dev->irq, rtl8139_interrupt, IRQF_SHARED, dev->name, dev);
if (retval)
return retval;
@@ -1341,9 +1342,9 @@ static int rtl8139_open (struct net_device *dev)
netif_start_queue (dev);
if (netif_msg_ifup(tp))
- printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#lx IRQ %d"
- " GP Pins %2.2x %s-duplex.\n",
- dev->name, pci_resource_start (tp->pci_dev, 1),
+ printk(KERN_DEBUG "%s: rtl8139_open() ioaddr %#llx IRQ %d"
+ " GP Pins %2.2x %s-duplex.\n", dev->name,
+ (unsigned long long)pci_resource_start (tp->pci_dev, 1),
dev->irq, RTL_R8 (MediaStatus),
tp->mii.full_duplex ? "full" : "half");
@@ -1708,6 +1709,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
void __iomem *ioaddr = tp->mmio_addr;
unsigned int entry;
unsigned int len = skb->len;
+ unsigned long flags;
/* Calculate the next Tx descriptor entry. */
entry = tp->cur_tx % NUM_TX_DESC;
@@ -1724,7 +1726,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
return 0;
}
- spin_lock_irq(&tp->lock);
+ spin_lock_irqsave(&tp->lock, flags);
RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
@@ -1735,7 +1737,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
netif_stop_queue (dev);
- spin_unlock_irq(&tp->lock);
+ spin_unlock_irqrestore(&tp->lock, flags);
if (netif_msg_tx_queued(tp))
printk (KERN_DEBUG "%s: Queued Tx packet size %u to slot %d.\n",
@@ -2444,7 +2446,7 @@ static void rtl8139_get_strings(struct net_device *dev, u32 stringset, u8 *data)
memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
}
-static struct ethtool_ops rtl8139_ethtool_ops = {
+static const struct ethtool_ops rtl8139_ethtool_ops = {
.get_drvinfo = rtl8139_get_drvinfo,
.get_settings = rtl8139_get_settings,
.set_settings = rtl8139_set_settings,
@@ -2510,9 +2512,6 @@ static void __set_rx_mode (struct net_device *dev)
/* Note: do not reorder, GCC is clever about common statements. */
if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
@@ -2627,7 +2626,7 @@ static int __init rtl8139_init_module (void)
printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
#endif
- return pci_module_init (&rtl8139_pci_driver);
+ return pci_register_driver(&rtl8139_pci_driver);
}
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 8a9f7d61b9b..c9e4dca9d41 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -40,7 +40,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -445,7 +444,7 @@ static inline int wait_cmd(struct net_device *dev, struct i596_private *lp, int
static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int delcnt, char *str)
{
volatile struct i596_cmd *c = cmd;
-
+
while (--delcnt && c->command)
udelay(10);
if (!delcnt) {
@@ -456,7 +455,7 @@ static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int del
return 0;
}
-
+
static void i596_display_data(struct net_device *dev)
{
struct i596_private *lp = dev->priv;
@@ -788,7 +787,7 @@ static inline int i596_rx(struct net_device *dev)
}
DEB(DEB_RXFRAME, printk(KERN_DEBUG " rfd %p, rfd.rbd %p, rfd.stat %04x\n",
rfd, rfd->rbd, rfd->stat));
-
+
if (rbd != I596_NULL && ((rfd->stat) & STAT_OK)) {
/* a good frame */
int pkt_len = rbd->count & 0x3fff;
@@ -900,7 +899,7 @@ memory_squeeze:
}
-static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
+static void i596_cleanup_cmd(struct net_device *dev, struct i596_private *lp)
{
struct i596_cmd *ptr;
@@ -933,7 +932,8 @@ static inline void i596_cleanup_cmd(struct net_device *dev, struct i596_private
lp->scb.cmd = I596_NULL;
}
-static inline void i596_reset(struct net_device *dev, struct i596_private *lp, int ioaddr)
+static void i596_reset(struct net_device *dev, struct i596_private *lp,
+ int ioaddr)
{
unsigned long flags;
@@ -1208,7 +1208,7 @@ struct net_device * __init i82596_probe(int unit)
Some other boards trip the checksum.. but then appear as
ether address 0. Trap these - AC */
- if ((checksum % 0x100) ||
+ if ((checksum % 0x100) ||
(memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {
err = -ENODEV;
goto out1;
@@ -1545,7 +1545,7 @@ static void set_multicast_list(struct net_device *dev)
printk(KERN_ERR "%s: Only %d multicast addresses supported",
dev->name, cnt);
}
-
+
if (dev->mc_count > 0) {
struct dev_mc_list *dmi;
unsigned char *cp;
@@ -1579,7 +1579,7 @@ static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "i82596 debug mask");
-int init_module(void)
+int __init init_module(void)
{
if (debug >= 0)
i596_debug = debug;
@@ -1589,7 +1589,7 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+void __exit cleanup_module(void)
{
unregister_netdev(dev_82596);
#ifdef __mc68000__
@@ -1609,7 +1609,7 @@ void cleanup_module(void)
}
#endif /* MODULE */
-
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c"
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 86be96af9c8..9d34056147a 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -1,7 +1,7 @@
/* 8390.c: A general NS8390 ethernet driver core for linux. */
/*
Written 1992-94 by Donald Becker.
-
+
Copyright 1993 United States Government as represented by the
Director, National Security Agency.
@@ -13,7 +13,7 @@
410 Severn Ave., Suite 210
Annapolis MD 21403
-
+
This is the chip-specific code for many 8390-based ethernet adaptors.
This is not a complete driver, it must be combined with board-specific
code such as ne.c, wd.c, 3c503.c, etc.
@@ -27,7 +27,7 @@
Changelog:
Paul Gortmaker : remove set_bit lock, other cleanups.
- Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
+ Paul Gortmaker : add ei_get_8390_hdr() so we can pass skb's to
ei_block_input() for eth_io_copy_and_sum().
Paul Gortmaker : exchange static int ei_pingpong for a #define,
also add better Tx error handling.
@@ -94,9 +94,9 @@ static const char version[] =
Read the 4 byte, page aligned 8390 header. *If* there is a
subsequent read, it will be of the rest of the packet.
void block_input(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
- Read COUNT bytes from the packet buffer into the skb data area. Start
+ Read COUNT bytes from the packet buffer into the skb data area. Start
reading from RING_OFFSET, the address as the 8390 sees it. This will always
- follow the read of the 8390 header.
+ follow the read of the 8390 header.
*/
#define ei_reset_8390 (ei_local->reset_8390)
#define ei_block_output (ei_local->block_output)
@@ -128,7 +128,7 @@ static void do_set_multicast_list(struct net_device *dev);
* a page register that controls bank and packet buffer access. We guard
* this with ei_local->page_lock. Nobody should assume or set the page other
* than zero when the lock is not held. Lock holders must restore page 0
- * before unlocking. Even pure readers must take the lock to protect in
+ * before unlocking. Even pure readers must take the lock to protect in
* page 0.
*
* To make life difficult the chip can also be very slow. We therefore can't
@@ -141,14 +141,14 @@ static void do_set_multicast_list(struct net_device *dev);
* a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
* enter lock, take the queued irq. So we waddle instead of flying.
*
- * Finally by special arrangement for the purpose of being generally
+ * Finally by special arrangement for the purpose of being generally
* annoying the transmit function is called bh atomic. That places
* restrictions on the user context callers as disable_irq won't save
* them.
*/
-
-
+
+
/**
* ei_open - Open/initialize the board.
* @dev: network device to initialize
@@ -168,12 +168,12 @@ int ei_open(struct net_device *dev)
dev->tx_timeout = ei_tx_timeout;
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = TX_TIMEOUT;
-
+
/*
* Grab the page lock so we own the register set, then call
* the init function.
*/
-
+
spin_lock_irqsave(&ei_local->page_lock, flags);
NS8390_init(dev, 1);
/* Set the flag before we drop the lock, That way the IRQ arrives
@@ -198,7 +198,7 @@ int ei_close(struct net_device *dev)
/*
* Hold the page lock during close
*/
-
+
spin_lock_irqsave(&ei_local->page_lock, flags);
NS8390_init(dev, 0);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
@@ -241,26 +241,26 @@ void ei_tx_timeout(struct net_device *dev)
dev->name, (txsr & ENTSR_ABT) ? "excess collisions." :
(isr) ? "lost interrupt?" : "cable problem?", txsr, isr, tickssofar);
- if (!isr && !ei_local->stat.tx_packets)
+ if (!isr && !ei_local->stat.tx_packets)
{
/* The 8390 probably hasn't gotten on the cable yet. */
ei_local->interface_num ^= 1; /* Try a different xcvr. */
}
/* Ugly but a reset can be slow, yet must be protected */
-
- disable_irq_nosync(dev->irq);
+
+ disable_irq_nosync_lockdep(dev->irq);
spin_lock(&ei_local->page_lock);
-
+
/* Try to restart the card. Perhaps the user has fixed something. */
ei_reset_8390(dev);
NS8390_init(dev, 1);
-
+
spin_unlock(&ei_local->page_lock);
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
netif_wake_queue(dev);
}
-
+
/**
* ei_start_xmit - begin packet transmission
* @skb: packet to be sent
@@ -268,7 +268,7 @@ void ei_tx_timeout(struct net_device *dev)
*
* Sends a packet to an 8390 network device.
*/
-
+
static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
long e8390_base = dev->base_addr;
@@ -285,24 +285,24 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
data = buf;
}
- /* Mask interrupts from the ethercard.
+ /* Mask interrupts from the ethercard.
SMP: We have to grab the lock here otherwise the IRQ handler
on another CPU can flip window and race the IRQ mask set. We end
up trashing the mcast filter not disabling irqs if we don't lock */
-
+
spin_lock_irqsave(&ei_local->page_lock, flags);
outb_p(0x00, e8390_base + EN0_IMR);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
-
+
+
/*
* Slow phase with lock held.
*/
-
- disable_irq_nosync(dev->irq);
-
+
+ disable_irq_nosync_lockdep_irqsave(dev->irq, &flags);
+
spin_lock(&ei_local->page_lock);
-
+
ei_local->irqlock = 1;
/*
@@ -313,7 +313,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* card, leaving a substantial gap between each transmitted packet.
*/
- if (ei_local->tx1 == 0)
+ if (ei_local->tx1 == 0)
{
output_page = ei_local->tx_start_page;
ei_local->tx1 = send_length;
@@ -321,7 +321,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_DEBUG "%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing);
}
- else if (ei_local->tx2 == 0)
+ else if (ei_local->tx2 == 0)
{
output_page = ei_local->tx_start_page + TX_PAGES/2;
ei_local->tx2 = send_length;
@@ -338,7 +338,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
- enable_irq(dev->irq);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
ei_local->stat.tx_errors++;
return 1;
}
@@ -348,20 +348,20 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* isn't already sending. If it is busy, the interrupt handler will
* trigger the send later, upon receiving a Tx done interrupt.
*/
-
+
ei_block_output(dev, send_length, data, output_page);
-
- if (! ei_local->txing)
+
+ if (! ei_local->txing)
{
ei_local->txing = 1;
NS8390_trigger_send(dev, send_length, output_page);
dev->trans_start = jiffies;
- if (output_page == ei_local->tx_start_page)
+ if (output_page == ei_local->tx_start_page)
{
ei_local->tx1 = -1;
ei_local->lasttx = -1;
}
- else
+ else
{
ei_local->tx2 = -1;
ei_local->lasttx = -2;
@@ -377,16 +377,16 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Turn 8390 interrupts back on. */
ei_local->irqlock = 0;
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
-
+
spin_unlock(&ei_local->page_lock);
- enable_irq(dev->irq);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
dev_kfree_skb (skb);
ei_local->stat.tx_bytes += send_length;
-
+
return 0;
}
-
+
/**
* ei_interrupt - handle the interrupts from an 8390
* @irq: interrupt number
@@ -406,23 +406,23 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
long e8390_base;
int interrupts, nr_serviced = 0;
struct ei_device *ei_local;
-
- if (dev == NULL)
+
+ if (dev == NULL)
{
printk ("net_interrupt(): irq %d for unknown device.\n", irq);
return IRQ_NONE;
}
-
+
e8390_base = dev->base_addr;
ei_local = (struct ei_device *) netdev_priv(dev);
/*
* Protect the irq test too.
*/
-
+
spin_lock(&ei_local->page_lock);
- if (ei_local->irqlock)
+ if (ei_local->irqlock)
{
#if 1 /* This might just be an interrupt for a PCI device sharing this line */
/* The "irqlock" check is only for testing. */
@@ -435,16 +435,16 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
spin_unlock(&ei_local->page_lock);
return IRQ_NONE;
}
-
+
/* Change to page 0 and read the intr status reg. */
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
if (ei_debug > 3)
printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
inb_p(e8390_base + EN0_ISR));
-
+
/* !!Assumption!! -- we stay in page 0. Don't break this. */
while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
- && ++nr_serviced < MAX_SERVICE)
+ && ++nr_serviced < MAX_SERVICE)
{
if (!netif_running(dev)) {
printk(KERN_WARNING "%s: interrupt from stopped card\n", dev->name);
@@ -453,9 +453,9 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
interrupts = 0;
break;
}
- if (interrupts & ENISR_OVER)
+ if (interrupts & ENISR_OVER)
ei_rx_overrun(dev);
- else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
+ else if (interrupts & (ENISR_RX+ENISR_RX_ERR))
{
/* Got a good (?) packet. */
ei_receive(dev);
@@ -466,27 +466,27 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
else if (interrupts & ENISR_TX_ERR)
ei_tx_err(dev);
- if (interrupts & ENISR_COUNTERS)
+ if (interrupts & ENISR_COUNTERS)
{
ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
}
-
+
/* Ignore any RDC interrupts that make it back to here. */
- if (interrupts & ENISR_RDC)
+ if (interrupts & ENISR_RDC)
{
outb_p(ENISR_RDC, e8390_base + EN0_ISR);
}
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
}
-
- if (interrupts && ei_debug)
+
+ if (interrupts && ei_debug)
{
outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
- if (nr_serviced >= MAX_SERVICE)
+ if (nr_serviced >= MAX_SERVICE)
{
/* 0xFF is valid for a card removal */
if(interrupts!=0xFF)
@@ -505,9 +505,9 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef CONFIG_NET_POLL_CONTROLLER
void ei_poll(struct net_device *dev)
{
- disable_irq(dev->irq);
+ disable_irq_lockdep(dev->irq);
ei_interrupt(dev->irq, dev, NULL);
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
}
#endif
@@ -551,7 +551,7 @@ static void ei_tx_err(struct net_device *dev)
if (tx_was_aborted)
ei_tx_intr(dev);
- else
+ else
{
ei_local->stat.tx_errors++;
if (txsr & ENTSR_CRS) ei_local->stat.tx_carrier_errors++;
@@ -573,7 +573,7 @@ static void ei_tx_intr(struct net_device *dev)
long e8390_base = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
int status = inb(e8390_base + EN0_TSR);
-
+
outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
/*
@@ -582,13 +582,13 @@ static void ei_tx_intr(struct net_device *dev)
*/
ei_local->txqueue--;
- if (ei_local->tx1 < 0)
+ if (ei_local->tx1 < 0)
{
if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
printk(KERN_ERR "%s: bogus last_tx_buffer %d, tx1=%d.\n",
ei_local->name, ei_local->lasttx, ei_local->tx1);
ei_local->tx1 = 0;
- if (ei_local->tx2 > 0)
+ if (ei_local->tx2 > 0)
{
ei_local->txing = 1;
NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
@@ -596,15 +596,15 @@ static void ei_tx_intr(struct net_device *dev)
ei_local->tx2 = -1,
ei_local->lasttx = 2;
}
- else ei_local->lasttx = 20, ei_local->txing = 0;
+ else ei_local->lasttx = 20, ei_local->txing = 0;
}
- else if (ei_local->tx2 < 0)
+ else if (ei_local->tx2 < 0)
{
if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
ei_local->name, ei_local->lasttx, ei_local->tx2);
ei_local->tx2 = 0;
- if (ei_local->tx1 > 0)
+ if (ei_local->tx1 > 0)
{
ei_local->txing = 1;
NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
@@ -623,17 +623,17 @@ static void ei_tx_intr(struct net_device *dev)
ei_local->stat.collisions++;
if (status & ENTSR_PTX)
ei_local->stat.tx_packets++;
- else
+ else
{
ei_local->stat.tx_errors++;
- if (status & ENTSR_ABT)
+ if (status & ENTSR_ABT)
{
ei_local->stat.tx_aborted_errors++;
ei_local->stat.collisions += 16;
}
- if (status & ENTSR_CRS)
+ if (status & ENTSR_CRS)
ei_local->stat.tx_carrier_errors++;
- if (status & ENTSR_FU)
+ if (status & ENTSR_FU)
ei_local->stat.tx_fifo_errors++;
if (status & ENTSR_CDH)
ei_local->stat.tx_heartbeat_errors++;
@@ -647,7 +647,7 @@ static void ei_tx_intr(struct net_device *dev)
* ei_receive - receive some packets
* @dev: network device with which receive will be run
*
- * We have a good packet(s), get it/them out of the buffers.
+ * We have a good packet(s), get it/them out of the buffers.
* Called with lock held.
*/
@@ -660,42 +660,42 @@ static void ei_receive(struct net_device *dev)
int rx_pkt_count = 0;
struct e8390_pkt_hdr rx_frame;
int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
-
- while (++rx_pkt_count < 10)
+
+ while (++rx_pkt_count < 10)
{
int pkt_len, pkt_stat;
-
+
/* Get the rx page (incoming packet pointer). */
outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
rxing_page = inb_p(e8390_base + EN1_CURPAG);
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
-
+
/* Remove one frame from the ring. Boundary is always a page behind. */
this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
if (this_frame >= ei_local->stop_page)
this_frame = ei_local->rx_start_page;
-
+
/* Someday we'll omit the previous, iff we never get this message.
- (There is at least one clone claimed to have a problem.)
-
+ (There is at least one clone claimed to have a problem.)
+
Keep quiet if it looks like a card removal. One problem here
is that some clones crash in roughly the same way.
*/
if (ei_debug > 0 && this_frame != ei_local->current_page && (this_frame!=0x0 || rxing_page!=0xFF))
printk(KERN_ERR "%s: mismatched read page pointers %2x vs %2x.\n",
dev->name, this_frame, ei_local->current_page);
-
+
if (this_frame == rxing_page) /* Read all the frames? */
break; /* Done for now */
-
+
current_offset = this_frame << 8;
ei_get_8390_hdr(dev, &rx_frame, this_frame);
-
+
pkt_len = rx_frame.count - sizeof(struct e8390_pkt_hdr);
pkt_stat = rx_frame.status;
-
+
next_frame = this_frame + 1 + ((pkt_len+4)>>8);
-
+
/* Check for bogosity warned by 3c503 book: the status byte is never
written. This happened a lot during testing! This code should be
cleaned up someday. */
@@ -709,7 +709,7 @@ static void ei_receive(struct net_device *dev)
continue;
}
- if (pkt_len < 60 || pkt_len > 1518)
+ if (pkt_len < 60 || pkt_len > 1518)
{
if (ei_debug)
printk(KERN_DEBUG "%s: bogus packet size: %d, status=%#2x nxpg=%#2x.\n",
@@ -718,12 +718,12 @@ static void ei_receive(struct net_device *dev)
ei_local->stat.rx_errors++;
ei_local->stat.rx_length_errors++;
}
- else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
+ else if ((pkt_stat & 0x0F) == ENRSR_RXOK)
{
struct sk_buff *skb;
-
+
skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL)
+ if (skb == NULL)
{
if (ei_debug > 1)
printk(KERN_DEBUG "%s: Couldn't allocate a sk_buff of size %d.\n",
@@ -745,8 +745,8 @@ static void ei_receive(struct net_device *dev)
if (pkt_stat & ENRSR_PHY)
ei_local->stat.multicast++;
}
- }
- else
+ }
+ else
{
if (ei_debug)
printk(KERN_DEBUG "%s: bogus packet: status=%#2x nxpg=%#2x size=%d\n",
@@ -758,7 +758,7 @@ static void ei_receive(struct net_device *dev)
ei_local->stat.rx_fifo_errors++;
}
next_frame = rx_frame.next;
-
+
/* This _should_ never happen: it's here for avoiding bad clones. */
if (next_frame >= ei_local->stop_page) {
printk("%s: next frame inconsistency, %#2x\n", dev->name,
@@ -785,7 +785,7 @@ static void ei_receive(struct net_device *dev)
* This includes causing "the NIC to defer indefinitely when it is stopped
* on a busy network." Ugh.
* Called with lock held. Don't call this with the interrupts off or your
- * computer will hate you - it takes 10ms or so.
+ * computer will hate you - it takes 10ms or so.
*/
static void ei_rx_overrun(struct net_device *dev)
@@ -793,19 +793,19 @@ static void ei_rx_overrun(struct net_device *dev)
long e8390_base = dev->base_addr;
unsigned char was_txing, must_resend = 0;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
-
+
/*
* Record whether a Tx was in progress and then issue the
* stop command.
*/
was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
+
if (ei_debug > 1)
printk(KERN_DEBUG "%s: Receiver overrun.\n", dev->name);
ei_local->stat.rx_over_errors++;
-
- /*
+
+ /*
* Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
* Early datasheets said to poll the reset bit, but now they say that
* it "is not a reliable indicator and subsequently should be ignored."
@@ -826,7 +826,7 @@ static void ei_rx_overrun(struct net_device *dev)
*/
if (was_txing)
- {
+ {
unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
if (!tx_completed)
must_resend = 1;
@@ -848,7 +848,7 @@ static void ei_rx_overrun(struct net_device *dev)
/*
* Leave loopback mode, and resend any packet that got stopped.
*/
- outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
+ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR);
if (must_resend)
outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
}
@@ -856,13 +856,13 @@ static void ei_rx_overrun(struct net_device *dev)
/*
* Collect the stats. This is called unlocked and from several contexts.
*/
-
+
static struct net_device_stats *get_stats(struct net_device *dev)
{
long ioaddr = dev->base_addr;
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
unsigned long flags;
-
+
/* If the card is stopped, just return the present stats. */
if (!netif_running(dev))
return &ei_local->stat;
@@ -873,7 +873,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
-
+
return &ei_local->stat;
}
@@ -881,21 +881,21 @@ static struct net_device_stats *get_stats(struct net_device *dev)
* Form the 64 bit 8390 multicast table from the linked list of addresses
* associated with this dev structure.
*/
-
+
static inline void make_mc_bits(u8 *bits, struct net_device *dev)
{
struct dev_mc_list *dmi;
- for (dmi=dev->mc_list; dmi; dmi=dmi->next)
+ for (dmi=dev->mc_list; dmi; dmi=dmi->next)
{
u32 crc;
- if (dmi->dmi_addrlen != ETH_ALEN)
+ if (dmi->dmi_addrlen != ETH_ALEN)
{
printk(KERN_INFO "%s: invalid multicast address length given.\n", dev->name);
continue;
}
crc = ether_crc(ETH_ALEN, dmi->dmi_addr);
- /*
+ /*
* The 8390 uses the 6 most significant bits of the
* CRC to index the multicast table.
*/
@@ -908,16 +908,16 @@ static inline void make_mc_bits(u8 *bits, struct net_device *dev)
* @dev: net device for which multicast filter is adjusted
*
* Set or clear the multicast filter for this adaptor. May be called
- * from a BH in 2.1.x. Must be called with lock held.
+ * from a BH in 2.1.x. Must be called with lock held.
*/
-
+
static void do_set_multicast_list(struct net_device *dev)
{
long e8390_base = dev->base_addr;
int i;
struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
- if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
+ if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI)))
{
memset(ei_local->mcfilter, 0, 8);
if (dev->mc_list)
@@ -926,23 +926,23 @@ static void do_set_multicast_list(struct net_device *dev)
else
memset(ei_local->mcfilter, 0xFF, 8); /* mcast set to accept-all */
- /*
+ /*
* DP8390 manuals don't specify any magic sequence for altering
* the multicast regs on an already running card. To be safe, we
* ensure multicast mode is off prior to loading up the new hash
* table. If this proves to be not enough, we can always resort
* to stopping the NIC, loading the table and then restarting.
*
- * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
+ * Bug Alert! The MC regs on the SMC 83C690 (SMC Elite and SMC
* Elite16) appear to be write-only. The NS 8390 data sheet lists
* them as r/w so this is a bug. The SMC 83C790 (SMC Ultra and
* Ultra32 EISA) appears to have this bug fixed.
*/
-
+
if (netif_running(dev))
outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
- for(i = 0; i < 8; i++)
+ for(i = 0; i < 8; i++)
{
outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
#ifndef BUG_83C690
@@ -965,16 +965,16 @@ static void do_set_multicast_list(struct net_device *dev)
* be parallel to just about everything else. Its also fairly quick and
* not called too often. Must protect against both bh and irq users
*/
-
+
static void set_multicast_list(struct net_device *dev)
{
unsigned long flags;
struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev);
-
+
spin_lock_irqsave(&ei_local->page_lock, flags);
do_set_multicast_list(dev);
spin_unlock_irqrestore(&ei_local->page_lock, flags);
-}
+}
/**
* ethdev_setup - init rest of 8390 device struct
@@ -989,7 +989,7 @@ static void ethdev_setup(struct net_device *dev)
struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
if (ei_debug > 1)
printk(version);
-
+
dev->hard_start_xmit = &ei_start_xmit;
dev->get_stats = get_stats;
dev->set_multicast_list = &set_multicast_list;
@@ -1011,7 +1011,7 @@ struct net_device *__alloc_ei_netdev(int size)
ethdev_setup);
}
-
+
/* This page of functions should be 8390 generic */
@@ -1033,9 +1033,9 @@ void NS8390_init(struct net_device *dev, int startp)
int endcfg = ei_local->word16
? (0x48 | ENDCFG_WTS | (ei_local->bigendian ? ENDCFG_BOS : 0))
: 0x48;
-
+
if(sizeof(struct e8390_pkt_hdr)!=4)
- panic("8390.c: header struct mispacked\n");
+ panic("8390.c: header struct mispacked\n");
/* Follow National Semi's recommendations for initing the DP83902. */
outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); /* 0x21 */
outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
@@ -1055,11 +1055,11 @@ void NS8390_init(struct net_device *dev, int startp)
/* Clear the pending interrupts and mask. */
outb_p(0xFF, e8390_base + EN0_ISR);
outb_p(0x00, e8390_base + EN0_IMR);
-
+
/* Copy the station address into the DS8390 registers. */
outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
- for(i = 0; i < 6; i++)
+ for(i = 0; i < 6; i++)
{
outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS_SHIFT(i));
if (ei_debug > 1 && inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i])
@@ -1073,7 +1073,7 @@ void NS8390_init(struct net_device *dev, int startp)
ei_local->tx1 = ei_local->tx2 = 0;
ei_local->txing = 0;
- if (startp)
+ if (startp)
{
outb_p(0xff, e8390_base + EN0_ISR);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -1085,18 +1085,18 @@ void NS8390_init(struct net_device *dev, int startp)
}
}
-/* Trigger a transmit start, assuming the length is valid.
+/* Trigger a transmit start, assuming the length is valid.
Always called with the page lock held */
-
+
static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
int start_page)
{
long e8390_base = dev->base_addr;
struct ei_device *ei_local __attribute((unused)) = (struct ei_device *) netdev_priv(dev);
-
+
outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
-
- if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
+
+ if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS)
{
printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n",
dev->name);
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index 51e39dcd060..ca4eb0ccf8c 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -7,7 +7,6 @@
#ifndef _8390_h
#define _8390_h
-#include <linux/config.h>
#include <linux/if_ether.h>
#include <linux/ioport.h>
#include <linux/skbuff.h>
@@ -107,7 +106,7 @@ struct ei_device {
* Only generate indirect loads given a machine that needs them.
* - removed AMIGA_PCMCIA from this list, handled as ISA io now
*/
-
+
#if defined(CONFIG_MAC) || \
defined(CONFIG_ZORRO8390) || defined(CONFIG_ZORRO8390_MODULE) || \
defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 39189903e35..ff8a8c0a26d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -24,6 +24,9 @@ config NETDEVICES
If unsure, say Y.
+# All the following symbols are dependent on NETDEVICES - do not repeat
+# that for each of the symbols.
+if NETDEVICES
config IFB
tristate "Intermediate Functional Block support"
@@ -438,12 +441,6 @@ config MIPS_JAZZ_SONIC
This is the driver for the onboard card of MIPS Magnum 4000,
Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
-config MIPS_GT96100ETH
- bool "MIPS GT96100 Ethernet support"
- depends on NET_ETHERNET && MIPS_GT96100
- help
- Say Y here to support the Ethernet subsystem on your GT96100 card.
-
config MIPS_AU1X00_ENET
bool "MIPS AU1000 Ethernet support"
depends on NET_ETHERNET && SOC_AU1X00
@@ -1300,6 +1297,23 @@ config PCNET32
<file:Documentation/networking/net-modules.txt>. The module
will be called pcnet32.
+config PCNET32_NAPI
+ bool "Use RX polling (NAPI) (EXPERIMENTAL)"
+ depends on PCNET32 && EXPERIMENTAL
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
+
config AMD8111_ETH
tristate "AMD 8111 (new PCI lance) support"
depends on NET_PCI && PCI
@@ -1411,6 +1425,22 @@ config FORCEDETH
<file:Documentation/networking/net-modules.txt>. The module will be
called forcedeth.
+config FORCEDETH_NAPI
+ bool "Use Rx and Tx Polling (NAPI) (EXPERIMENTAL)"
+ depends on FORCEDETH && EXPERIMENTAL
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card. It is
+ still somewhat experimental and thus not yet enabled by default.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
+ If in doubt, say N.
config CS89x0
tristate "CS89x0 support"
@@ -1724,6 +1754,20 @@ config VIA_RHINE_MMIO
If unsure, say Y.
+config VIA_RHINE_NAPI
+ bool "Use Rx Polling (NAPI)"
+ depends on VIA_RHINE
+ help
+ NAPI is a new driver API designed to reduce CPU and interrupt load
+ when the driver is receiving lots of packets from the card.
+
+ If your estimated Rx load is 10kpps or more, or if the card will be
+ deployed on potentially unfriendly networks (e.g. in a firewall),
+ then say Y here.
+
+ See <file:Documentation/networking/NAPI_HOWTO.txt> for more
+ information.
+
config LAN_SAA9730
bool "Philips SAA9730 Ethernet support (EXPERIMENTAL)"
depends on NET_PCI && EXPERIMENTAL && MIPS
@@ -2219,9 +2263,36 @@ config GFAR_NAPI
bool "NAPI Support"
depends on GIANFAR
+config UCC_GETH
+ tristate "Freescale QE UCC GETH"
+ depends on QUICC_ENGINE && UCC_FAST
+ help
+ This driver supports the Gigabit Ethernet mode of QE UCC.
+ QE can be found on MPC836x CPUs.
+
+config UGETH_NAPI
+ bool "NAPI Support"
+ depends on UCC_GETH
+
+config UGETH_MAGIC_PACKET
+ bool "Magic Packet detection support"
+ depends on UCC_GETH
+
+config UGETH_FILTERING
+ bool "Mac address filtering support"
+ depends on UCC_GETH
+
+config UGETH_TX_ON_DEMOND
+ bool "Transmit on Demond support"
+ depends on UCC_GETH
+
+config UGETH_HAS_GIGA
+ bool
+ depends on UCC_GETH && MPC836x
+
config MV643XX_ETH
tristate "MV-643XX Ethernet support"
- depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM
+ depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32)
select MII
help
This driver supports the gigabit Ethernet on the Marvell MV643XX
@@ -2249,6 +2320,15 @@ config MV643XX_ETH_2
This enables support for Port 2 of the Marvell MV643XX Gigabit
Ethernet.
+config QLA3XXX
+ tristate "QLogic QLA3XXX Network Driver Support"
+ depends on PCI
+ help
+ This driver supports QLogic ISP3XXX gigabit Ethernet cards.
+
+ To compile this driver as a module, choose M here: the module
+ will be called qla3xxx.
+
endmenu
#
@@ -2277,6 +2357,15 @@ config CHELSIO_T1
To compile this driver as a module, choose M here: the module
will be called cxgb.
+config EHEA
+ tristate "eHEA Ethernet support"
+ depends on IBMEBUS
+ ---help---
+ This driver supports the IBM pSeries eHEA ethernet adapter.
+
+ To compile the driver as a module, choose M here. The module
+ will be called ehea.
+
config IXGB
tristate "Intel(R) PRO/10GbE support"
depends on PCI
@@ -2352,7 +2441,7 @@ config MYRI10GE
you will need a newer firmware image.
You may get this image or more information, at:
- <http://www.myri.com/Myri-10G/>
+ <http://www.myri.com/scs/download-Myri10GE.html>
To compile this driver as a module, choose M here and read
<file:Documentation/networking/net-modules.txt>. The module
@@ -2509,6 +2598,7 @@ config PLIP
config PPP
tristate "PPP (point-to-point protocol) support"
+ select SLHC
---help---
PPP (Point to Point Protocol) is a newer and better SLIP. It serves
the same purpose: sending Internet traffic over telephone (and other
@@ -2689,6 +2779,7 @@ config SLIP
config SLIP_COMPRESSED
bool "CSLIP compressed headers"
depends on SLIP
+ select SLHC
---help---
This protocol is faster than SLIP because it uses compression on the
TCP/IP headers (not on the data itself), but it has to be supported
@@ -2701,6 +2792,12 @@ config SLIP_COMPRESSED
<http://www.tldp.org/docs.html#howto>, explains how to configure
CSLIP. This won't enlarge your kernel.
+config SLHC
+ tristate
+ help
+ This option enables Van Jacobsen serial line header compression
+ routines.
+
config SLIP_SMART
bool "Keepalive and linefill"
depends on SLIP
@@ -2758,6 +2855,8 @@ config NETCONSOLE
If you want to log kernel messages over the network, enable this.
See <file:Documentation/networking/netconsole.txt> for details.
+endif #NETDEVICES
+
config NETPOLL
def_bool NETCONSOLE
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index c91e95126f7..f270bc49e57 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,14 +2,11 @@
# Makefile for the Linux network (ethercard) device drivers.
#
-ifeq ($(CONFIG_ISDN_PPP),y)
- obj-$(CONFIG_ISDN) += slhc.o
-endif
-
obj-$(CONFIG_E1000) += e1000/
obj-$(CONFIG_IBM_EMAC) += ibm_emac/
obj-$(CONFIG_IXGB) += ixgb/
obj-$(CONFIG_CHELSIO_T1) += chelsio/
+obj-$(CONFIG_EHEA) += ehea/
obj-$(CONFIG_BONDING) += bonding/
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
@@ -18,6 +15,9 @@ gianfar_driver-objs := gianfar.o \
gianfar_mii.o \
gianfar_sysfs.o
+obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o
+ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o
+
#
# link order important here
#
@@ -110,8 +110,9 @@ obj-$(CONFIG_FORCEDETH) += forcedeth.o
obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
+obj-$(CONFIG_QLA3XXX) += qla3xxx.o
-obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
+obj-$(CONFIG_PPP) += ppp_generic.o
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
obj-$(CONFIG_PPP_SYNC_TTY) += ppp_synctty.o
obj-$(CONFIG_PPP_DEFLATE) += ppp_deflate.o
@@ -120,9 +121,7 @@ obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
obj-$(CONFIG_SLIP) += slip.o
-ifeq ($(CONFIG_SLIP_COMPRESSED),y)
- obj-$(CONFIG_SLIP) += slhc.o
-endif
+obj-$(CONFIG_SLHC) += slhc.o
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_IFB) += ifb.o
@@ -171,7 +170,6 @@ obj-$(CONFIG_HPLANCE) += hplance.o 7990.o
obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o
obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_MIPS_JAZZ_SONIC) += jazzsonic.o
-obj-$(CONFIG_MIPS_GT96100ETH) += gt96100eth.o
obj-$(CONFIG_MIPS_AU1X00_ENET) += au1000_eth.o
obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o
obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 60304f7e7e5..9953201c670 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -18,7 +18,7 @@
* - struct init cleanup, enable multiple ISA autoprobes.
* Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999
* - fix sbni: s/device/net_device/
- * Paul Gortmaker (06/98):
+ * Paul Gortmaker (06/98):
* - sort probes in a sane way, make sure all (safe) probes
* get run once & failed autoprobes don't autoprobe again.
*
@@ -27,7 +27,6 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/trdevice.h>
@@ -92,7 +91,7 @@ extern struct net_device *mac89x0_probe(int unit);
extern struct net_device *mc32_probe(int unit);
extern struct net_device *cops_probe(int unit);
extern struct net_device *ltpc_probe(void);
-
+
/* Detachable devices ("pocket adaptors") */
extern struct net_device *de620_probe(int unit);
@@ -130,10 +129,10 @@ static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe)
*/
static struct devprobe2 eisa_probes[] __initdata = {
-#ifdef CONFIG_ULTRA32
- {ultra32_probe, 0},
+#ifdef CONFIG_ULTRA32
+ {ultra32_probe, 0},
#endif
-#ifdef CONFIG_AC3200
+#ifdef CONFIG_AC3200
{ac3200_probe, 0},
#endif
#ifdef CONFIG_ES3210
@@ -168,14 +167,14 @@ static struct devprobe2 mca_probes[] __initdata = {
static struct devprobe2 isa_probes[] __initdata = {
#ifdef CONFIG_HP100 /* ISA, EISA & PCI */
{hp100_probe, 0},
-#endif
+#endif
#ifdef CONFIG_3C515
{tc515_probe, 0},
#endif
-#ifdef CONFIG_ULTRA
+#ifdef CONFIG_ULTRA
{ultra_probe, 0},
#endif
-#ifdef CONFIG_WD80x3
+#ifdef CONFIG_WD80x3
{wd_probe, 0},
#endif
#ifdef CONFIG_EL2 /* 3c503 */
@@ -200,7 +199,7 @@ static struct devprobe2 isa_probes[] __initdata = {
#ifdef CONFIG_SMC9194
{smc_init, 0},
#endif
-#ifdef CONFIG_SEEQ8005
+#ifdef CONFIG_SEEQ8005
{seeq8005_probe, 0},
#endif
#ifdef CONFIG_CS89x0
@@ -296,7 +295,7 @@ static struct devprobe2 m68k_probes[] __initdata = {
* Unified ethernet device probe, segmented per architecture and
* per bus interface. This drives the legacy devices only for now.
*/
-
+
static void __init ethif_probe2(int unit)
{
unsigned long base_addr = netdev_boot_base("eth", unit);
@@ -350,7 +349,7 @@ static void __init trif_probe2(int unit)
}
#endif
-
+
/*
* The loopback device is global so it can be directly referenced
* by the network code. Also, it must be first on device list.
@@ -366,7 +365,7 @@ static int __init net_olddevs_init(void)
printk(KERN_ERR "Network loopback device setup failed\n");
}
-
+
#ifdef CONFIG_SBNI
for (num = 0; num < 8; ++num)
sbni_probe(num);
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 71165ac0257..5f7258fea19 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -48,7 +48,6 @@
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/crc32.h>
#include <linux/zorro.h>
@@ -94,7 +93,7 @@ struct lance_init_block {
unsigned short rx_len; /* receive len and high addr */
unsigned short tx_ptr; /* transmit descriptor addr */
unsigned short tx_len; /* transmit len and high addr */
-
+
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
@@ -116,7 +115,7 @@ struct lance_private {
int rx_new, tx_new;
int rx_old, tx_old;
-
+
int lance_log_rx_bufs, lance_log_tx_bufs;
int rx_ring_mod_mask, tx_ring_mod_mask;
@@ -191,7 +190,7 @@ static void lance_init_ring (struct net_device *dev)
if (ZERO)
printk(KERN_DEBUG "TX rings:\n");
-
+
/* Setup the Tx ring entries */
for (i = 0; i <= (1<<lp->lance_log_tx_bufs); i++) {
leptr = LANCE_ADDR(&aib->tx_buf[i][0]);
@@ -220,14 +219,14 @@ static void lance_init_ring (struct net_device *dev)
}
/* Setup the initialization block */
-
+
/* Setup rx descriptor pointer */
leptr = LANCE_ADDR(&aib->brx_ring);
ib->rx_len = (lp->lance_log_rx_bufs << 13) | (leptr >> 16);
ib->rx_ptr = leptr;
if (ZERO)
printk(KERN_DEBUG "RX ptr: %8.8x\n", leptr);
-
+
/* Setup tx descriptor pointer */
leptr = LANCE_ADDR(&aib->btx_ring);
ib->tx_len = (lp->lance_log_tx_bufs << 13) | (leptr >> 16);
@@ -287,7 +286,7 @@ static int lance_rx (struct net_device *dev)
}
printk ("]\n");
#endif
-
+
ll->rdp = LE_C0_RINT|LE_C0_INEA;
for (rd = &ib->brx_ring [lp->rx_new];
!((bits = rd->rmd1_bits) & LE_R1_OWN);
@@ -320,7 +319,7 @@ static int lance_rx (struct net_device *dev)
lp->rx_new = (lp->rx_new + 1) & lp->rx_ring_mod_mask;
return 0;
}
-
+
skb->dev = dev;
skb_reserve (skb, 2); /* 16 byte align */
skb_put (skb, len); /* make room */
@@ -362,10 +361,10 @@ static int lance_tx (struct net_device *dev)
/* If we hit a packet not owned by us, stop */
if (td->tmd1_bits & LE_T1_OWN)
break;
-
+
if (td->tmd1_bits & LE_T1_ERR) {
status = td->misc;
-
+
lp->stats.tx_errors++;
if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
@@ -418,7 +417,7 @@ static int lance_tx (struct net_device *dev)
lp->stats.tx_packets++;
}
-
+
j = (j + 1) & lp->tx_ring_mod_mask;
}
lp->tx_old = j;
@@ -453,7 +452,7 @@ lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
/* Clear the error condition */
ll->rdp = LE_C0_BABL|LE_C0_ERR|LE_C0_MISS|LE_C0_INEA;
}
-
+
if (csr0 & LE_C0_RINT)
lance_rx (dev);
@@ -496,7 +495,7 @@ static int lance_open (struct net_device *dev)
ll->rdp = LE_C0_STOP;
/* Install the Interrupt handler */
- ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, SA_SHIRQ,
+ ret = request_irq(IRQ_AMIGA_PORTS, lance_interrupt, IRQF_SHARED,
dev->name, dev);
if (ret) return ret;
@@ -529,7 +528,7 @@ static inline int lance_reset (struct net_device *dev)
struct lance_private *lp = netdev_priv(dev);
volatile struct lance_regs *ll = lp->ll;
int status;
-
+
/* Stop the lance */
ll->rap = LE_CSR0;
ll->rdp = LE_C0_STOP;
@@ -570,7 +569,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
skblen = skb->len;
len = skblen;
-
+
if (len < ETH_ZLEN) {
len = ETH_ZLEN;
if (skb_padto(skb, ETH_ZLEN))
@@ -588,7 +587,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
/* dump the packet */
{
int i;
-
+
for (i = 0; i < 64; i++) {
if ((i % 16) == 0)
printk("\n" KERN_DEBUG);
@@ -600,13 +599,13 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
entry = lp->tx_new & lp->tx_ring_mod_mask;
ib->btx_ring [entry].length = (-len) | 0xf000;
ib->btx_ring [entry].misc = 0;
-
+
memcpy ((char *)&ib->tx_buf [entry][0], skb->data, skblen);
/* Clear the slack of the packet, do I need this? */
if (len != skblen)
memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen);
-
+
/* Now, give the packet to the lance */
ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
@@ -620,7 +619,7 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
ll->rdp = LE_C0_INEA | LE_C0_TDMD;
dev->trans_start = jiffies;
dev_kfree_skb (skb);
-
+
local_irq_restore(flags);
return status;
@@ -643,9 +642,9 @@ static void lance_load_multicast (struct net_device *dev)
char *addrs;
int i;
u32 crc;
-
+
/* set all multicast bits */
- if (dev->flags & IFF_ALLMULTI){
+ if (dev->flags & IFF_ALLMULTI){
ib->filter [0] = 0xffffffff;
ib->filter [1] = 0xffffffff;
return;
@@ -662,7 +661,7 @@ static void lance_load_multicast (struct net_device *dev)
/* multicast address? */
if (!(*addrs & 1))
continue;
-
+
crc = ether_crc_le(6, addrs);
crc = crc >> 26;
mcast_table [crc >> 4] |= 1 << (crc & 0xf);
diff --git a/drivers/net/a2065.h b/drivers/net/a2065.h
index 184ad573dbd..5117759d4e9 100644
--- a/drivers/net/a2065.h
+++ b/drivers/net/a2065.h
@@ -109,7 +109,7 @@ struct lance_rx_desc {
*/
unsigned short mblength; /* Aactual number of bytes received */
};
-
+
struct lance_tx_desc {
unsigned short tmd0; /* low address of packet */
unsigned char tmd1_bits; /* descriptor bits */
@@ -117,7 +117,7 @@ struct lance_tx_desc {
short length; /* Length is 2s complement (negative)! */
unsigned short misc;
};
-
+
/*
* Receive Flags
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 7952dc6d77e..0dca8bb9d2c 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -45,7 +45,7 @@ static const char version[] =
#define AC_NIC_BASE 0x00
#define AC_SA_PROM 0x16 /* The station address PROM. */
#define AC_ADDR0 0x00 /* Prefix station address values. */
-#define AC_ADDR1 0x40
+#define AC_ADDR1 0x40
#define AC_ADDR2 0x90
#define AC_ID_PORT 0xC80
#define AC_EISA_ID 0x0110d305
@@ -89,7 +89,7 @@ static void ac_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
static int ac_close_card(struct net_device *dev);
-
+
/* Probe for the AC3200.
@@ -217,7 +217,7 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
dev->if_port = inb(ioaddr + AC_CONFIG) >> 6;
dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG));
- printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
+ printk("%s: AC3200 at %#3x with %dkB memory at physical address %#lx.\n",
dev->name, ioaddr, AC_STOP_PG/4, dev->mem_start);
/*
@@ -370,8 +370,7 @@ MODULE_PARM_DESC(mem, "Memory base address(es)");
MODULE_DESCRIPTION("Ansel AC3200 EISA ethernet driver");
MODULE_LICENSE("GPL");
-int
-init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 23ff22ba5d3..71a4f60f732 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -50,7 +50,6 @@
* Grant Grundler <grundler@cup.hp.com>: PCI write posting fixes.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/version.h>
@@ -100,7 +99,7 @@
#endif
#ifndef PCI_VENDOR_ID_ALTEON
-#define PCI_VENDOR_ID_ALTEON 0x12ae
+#define PCI_VENDOR_ID_ALTEON 0x12ae
#endif
#ifndef PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE
#define PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE 0x0001
@@ -164,11 +163,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define SET_NETDEV_DEV(net, pdev) do{} while(0)
#endif
-#if LINUX_VERSION_CODE >= 0x2051c
#define ace_sync_irq(irq) synchronize_irq(irq)
-#else
-#define ace_sync_irq(irq) synchronize_irq()
-#endif
#ifndef offset_in_page
#define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK)
@@ -444,7 +439,7 @@ MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descript
MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
-static char version[] __devinitdata =
+static char version[] __devinitdata =
"acenic.c: v0.92 08/05/2002 Jes Sorensen, linux-acenic@SunSITE.dk\n"
" http://home.cern.ch/~jes/gige/acenic.html\n";
@@ -452,7 +447,7 @@ static int ace_get_settings(struct net_device *, struct ethtool_cmd *);
static int ace_set_settings(struct net_device *, struct ethtool_cmd *);
static void ace_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
-static struct ethtool_ops ace_ethtool_ops = {
+static const struct ethtool_ops ace_ethtool_ops = {
.get_settings = ace_get_settings,
.set_settings = ace_set_settings,
.get_drvinfo = ace_get_drvinfo,
@@ -517,7 +512,7 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev,
pci_read_config_word(pdev, PCI_COMMAND, &ap->pci_command);
- /* OpenFirmware on Mac's does not set this - DOH.. */
+ /* OpenFirmware on Mac's does not set this - DOH.. */
if (!(ap->pci_command & PCI_COMMAND_MEMORY)) {
printk(KERN_INFO "%s: Enabling PCI Memory Mapped "
"access - was not enabled by BIOS/Firmware\n",
@@ -637,7 +632,7 @@ static void __devexit acenic_remove_one(struct pci_dev *pdev)
writel(readl(&regs->CpuCtrl) | CPU_HALT, &regs->CpuCtrl);
if (ap->version >= 2)
writel(readl(&regs->CpuBCtrl) | CPU_HALT, &regs->CpuBCtrl);
-
+
/*
* This clears any pending interrupts
*/
@@ -726,7 +721,7 @@ static struct pci_driver acenic_pci_driver = {
static int __init acenic_init(void)
{
- return pci_module_init(&acenic_pci_driver);
+ return pci_register_driver(&acenic_pci_driver);
}
static void __exit acenic_exit(void)
@@ -1060,7 +1055,7 @@ static int __devinit ace_init(struct net_device *dev)
printk(KERN_INFO " PCI bus width: %i bits, speed: %iMHz, "
"latency: %i clks\n",
(pci_state & PCI_32BIT) ? 32 : 64,
- (pci_state & PCI_66MHZ) ? 66 : 33,
+ (pci_state & PCI_66MHZ) ? 66 : 33,
ap->pci_latency);
/*
@@ -1162,7 +1157,7 @@ static int __devinit ace_init(struct net_device *dev)
pci_write_config_word(pdev, PCI_COMMAND, ap->pci_command);
}
#endif
-
+
/*
* Configure DMA attributes.
*/
@@ -1195,7 +1190,7 @@ static int __devinit ace_init(struct net_device *dev)
goto init_error;
}
- ecode = request_irq(pdev->irq, ace_interrupt, SA_SHIRQ,
+ ecode = request_irq(pdev->irq, ace_interrupt, IRQF_SHARED,
DRV_NAME, dev);
if (ecode) {
printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
@@ -1285,7 +1280,7 @@ static int __devinit ace_init(struct net_device *dev)
(RX_STD_RING_ENTRIES +
RX_JUMBO_RING_ENTRIES))));
info->rx_mini_ctrl.max_len = ACE_MINI_SIZE;
- info->rx_mini_ctrl.flags =
+ info->rx_mini_ctrl.flags =
RCB_FLG_TCP_UDP_SUM|RCB_FLG_NO_PSEUDO_HDR|ACE_RCB_VLAN_FLAG;
for (i = 0; i < RX_MINI_RING_ENTRIES; i++)
@@ -1319,7 +1314,7 @@ static int __devinit ace_init(struct net_device *dev)
if (ACE_IS_TIGON_I(ap)) {
ap->tx_ring = (struct tx_desc *) regs->Window;
- for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
+ for (i = 0; i < (TIGON_I_TX_RING_ENTRIES
* sizeof(struct tx_desc)) / sizeof(u32); i++)
writel(0, (void __iomem *)ap->tx_ring + i * 4);
@@ -1671,7 +1666,7 @@ static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs)
{
struct ace_regs __iomem *regs = ap->regs;
short i, idx;
-
+
prefetchw(&ap->cur_rx_bufs);
@@ -1967,7 +1962,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
prefetchw(&ap->cur_rx_bufs);
prefetchw(&ap->cur_mini_bufs);
-
+
while (idx != rxretprd) {
struct ring_info *rip;
struct sk_buff *skb;
@@ -1978,7 +1973,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
/* make sure the rx descriptor isn't read before rxretprd */
- if (idx == rxretcsm)
+ if (idx == rxretcsm)
rmb();
retdesc = &ap->rx_return_ring[idx];
@@ -2010,7 +2005,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
rip = &ap->skb->rx_mini_skbuff[skbidx];
mapsize = ACE_MINI_BUFSIZE;
rxdesc = &ap->rx_mini_ring[skbidx];
- mini_count++;
+ mini_count++;
break;
default:
printk(KERN_INFO "%s: unknown frame type (0x%02x) "
@@ -2041,7 +2036,7 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
*/
if (bd_flags & BD_FLG_TCP_UDP_SUM) {
skb->csum = htons(csum);
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
} else {
skb->ip_summed = CHECKSUM_NONE;
}
@@ -2378,7 +2373,7 @@ static int ace_close(struct net_device *dev)
*/
netif_stop_queue(dev);
-
+
if (ap->promisc) {
cmd.evt = C_SET_PROMISC_MODE;
cmd.code = C_C_PROMISC_DISABLE;
@@ -2413,7 +2408,7 @@ static int ace_close(struct net_device *dev)
if (mapping) {
if (ACE_IS_TIGON_I(ap)) {
- struct tx_desc __iomem *tx
+ struct tx_desc __iomem *tx
= (struct tx_desc __iomem *) &ap->tx_ring[i];
writel(0, &tx->addr.addrhi);
writel(0, &tx->addr.addrlo);
@@ -2512,7 +2507,7 @@ restart:
mapping = ace_map_tx_skb(ap, skb, skb, idx);
flagsize = (skb->len << 16) | (BD_FLG_END);
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
flagsize |= BD_FLG_TCP_UDP_SUM;
#if ACENIC_DO_VLAN
if (vlan_tx_tag_present(skb)) {
@@ -2535,7 +2530,7 @@ restart:
mapping = ace_map_tx_skb(ap, skb, NULL, idx);
flagsize = (skb_headlen(skb) << 16);
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
flagsize |= BD_FLG_TCP_UDP_SUM;
#if ACENIC_DO_VLAN
if (vlan_tx_tag_present(skb)) {
@@ -2561,7 +2556,7 @@ restart:
PCI_DMA_TODEVICE);
flagsize = (frag->size << 16);
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
flagsize |= BD_FLG_TCP_UDP_SUM;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
@@ -2626,7 +2621,7 @@ overflow:
cpu_relax();
goto restart;
}
-
+
/* The ring is stuck full. */
printk(KERN_WARNING "%s: Transmit ring stuck full\n", dev->name);
return NETDEV_TX_BUSY;
@@ -2785,18 +2780,18 @@ static int ace_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
return 0;
}
-static void ace_get_drvinfo(struct net_device *dev,
+static void ace_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *info)
{
struct ace_private *ap = netdev_priv(dev);
strlcpy(info->driver, "acenic", sizeof(info->driver));
- snprintf(info->version, sizeof(info->version), "%i.%i.%i",
+ snprintf(info->version, sizeof(info->version), "%i.%i.%i",
tigonFwReleaseMajor, tigonFwReleaseMinor,
tigonFwReleaseFix);
if (ap->pdev)
- strlcpy(info->bus_info, pci_name(ap->pdev),
+ strlcpy(info->bus_info, pci_name(ap->pdev),
sizeof(info->bus_info));
}
@@ -2913,7 +2908,7 @@ static void __devinit ace_copy(struct ace_regs __iomem *regs, void *src,
while (size > 0) {
tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
min_t(u32, size, ACE_WINDOW_SIZE));
- tdest = (void __iomem *) &regs->Window +
+ tdest = (void __iomem *) &regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
/*
@@ -2944,7 +2939,7 @@ static void __devinit ace_clear(struct ace_regs __iomem *regs, u32 dest, int siz
while (size > 0) {
tsize = min_t(u32, ((~dest & (ACE_WINDOW_SIZE - 1)) + 1),
min_t(u32, size, ACE_WINDOW_SIZE));
- tdest = (void __iomem *) &regs->Window +
+ tdest = (void __iomem *) &regs->Window +
(dest & (ACE_WINDOW_SIZE - 1));
writel(dest & ~(ACE_WINDOW_SIZE - 1), &regs->WinBase);
@@ -3061,7 +3056,7 @@ static void __devinit eeprom_prep(struct ace_regs __iomem *regs, u8 magic)
for (i = 0; i < 8; i++, magic <<= 1) {
udelay(ACE_SHORT_DELAY);
- if (magic & 0x80)
+ if (magic & 0x80)
local |= EEPROM_DATA_OUT;
else
local &= ~EEPROM_DATA_OUT;
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index a9710702349..efb14b9f4d9 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -1,7 +1,6 @@
#ifndef _ACENIC_H_
#define _ACENIC_H_
-#include <linux/config.h>
/*
* Generate TX index update each time, when TX ring is closed.
@@ -174,7 +173,7 @@ typedef struct {
/*
* Host control register bits.
*/
-
+
#define IN_INT 0x01
#define CLR_INT 0x02
#define HW_RESET 0x08
@@ -450,7 +449,7 @@ struct cmd {
struct tx_desc{
aceaddr addr;
- u32 flagsize;
+ u32 flagsize;
#if 0
/*
* This is in PCI shared mem and must be accessed with readl/writel
@@ -755,7 +754,7 @@ static inline void ace_unmask_irq(struct net_device *dev)
{
struct ace_private *ap = netdev_priv(dev);
struct ace_regs __iomem *regs = ap->regs;
-
+
if (ACE_IS_TIGON_I(ap))
writel(0, &regs->MaskInt);
else
diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h
index d7882dd783c..fd41f7887e2 100644
--- a/drivers/net/acenic_firmware.h
+++ b/drivers/net/acenic_firmware.h
@@ -1,4 +1,3 @@
-#include <linux/config.h>
/*
* Declare these here even if Tigon I support is disabled to avoid
* the compiler complaining about undefined symbols.
@@ -24,4577 +23,4577 @@
#else
/* Generated by genfw.c */
static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
-0x10000003,
-0x0, 0xd, 0xd, 0x3c1d0001,
-0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000,
-0xc00100c, 0x0, 0xd, 0x27bdffd8,
-0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
-0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
-0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
-0x0, 0x3c040001, 0x248451a4, 0x24050001,
-0x2e03021, 0x3821, 0x3c100001, 0x26107e50,
-0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
-0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
-0x24050003, 0x3c040001, 0x248451b0, 0x2003021,
-0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
-0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
-0x370821, 0xa02083b0, 0x3c010001, 0x370821,
-0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3,
-0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8,
-0x418c0, 0x24840001, 0x771021, 0xac40727c,
-0x771021, 0xac407280, 0x2e31021, 0xa445727c,
-0x2c820020, 0x1440fff7, 0x418c0, 0x2021,
-0x3405c000, 0x418c0, 0x24840001, 0x771021,
-0xac40737c, 0x771021, 0xac407380, 0x2e31021,
-0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0,
-0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040,
-0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
-0x8f420218, 0x30420002, 0x10400009, 0x0,
-0x8f420220, 0x3c030002, 0x34630004, 0x431025,
-0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004,
-0x8f420220, 0x3c030002, 0x34630006, 0x431025,
-0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc,
-0x8f420218, 0x30420010, 0x1040000a, 0x0,
-0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220,
-0x3c03000a, 0x34630004, 0x431025, 0x800108a,
-0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006,
-0x431025, 0xaee204c0, 0x8f42021c, 0x34420006,
-0xaee204c8, 0x8f420218, 0x30420200, 0x10400003,
-0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248,
-0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
-0x8f820054, 0x8001099, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010,
-0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030,
-0xaee20028, 0x24020490, 0xaee20018, 0xaf840090,
-0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a,
-0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025,
-0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
-0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
-0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
-0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
-0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014,
-0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
-0x26e40030, 0xc002488, 0x24050400, 0x27440080,
-0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
-0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060,
-0x8f420260, 0x27450200, 0x24060008, 0xaee20068,
-0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a,
-0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
-0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
-0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
-0x641821, 0x90635c20, 0x2e41021, 0x24840001,
-0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
-0x8f820040, 0x2e41821, 0x24840001, 0x21702,
-0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
-0x96e2046a, 0x30420003, 0x14400009, 0x0,
-0x96e2047a, 0x30420003, 0x50400131, 0x3c030800,
-0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700,
-0x96e2047a, 0x30420003, 0x10400026, 0x3c020700,
-0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700,
-0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00,
-0xaee204c0, 0x8f420218, 0x30420100, 0x10400005,
-0x0, 0x3c020001, 0x2442e168, 0x800111d,
-0x21100, 0x3c020001, 0x2442d35c, 0x21100,
-0x21182, 0x3c030800, 0x431025, 0x3c010001,
-0xac221238, 0x3c020001, 0x2442f680, 0x21100,
-0x21182, 0x3c030800, 0x431025, 0x3c010001,
-0xac221278, 0x8ee20000, 0x34424000, 0x8001238,
-0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608,
-0x8f430228, 0x24420001, 0x304900ff, 0x512300e2,
-0xafa00010, 0x8ee20608, 0x210c0, 0x571021,
-0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610,
-0x8f870120, 0x27623800, 0x24e80020, 0x102102b,
-0x50400001, 0x27683000, 0x8f820128, 0x11020004,
-0x0, 0x8f820124, 0x15020007, 0x1021,
-0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
-0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0,
-0x801821, 0x8ee40430, 0x8ee50434, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xace40000,
-0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e,
-0x2402000d, 0xace20018, 0xace9001c, 0x318c0,
-0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4,
-0xace20010, 0xaf880120, 0x92e24e20, 0x14400037,
-0x24060001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
-0x0, 0x800118a, 0x0, 0x14a00005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80011a0, 0x0, 0x8ee24e30,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x24020007,
-0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
-0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f000, 0x8001223, 0x0,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
-0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c,
-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400037, 0x24060001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x80011f1, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8001207, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020012, 0xac820000,
-0x24020001, 0xac820004, 0x14c0001b, 0x0,
-0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
-0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
-0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
-0x248451e8, 0x3405f001, 0x24420001, 0xaee20160,
-0x8ee20160, 0x3021, 0x3821, 0xafa00010,
-0xc002403, 0xafa00014, 0x8001238, 0x0,
-0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
-0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
-0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
-0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
-0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec,
-0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
-0x2442a390, 0x451024, 0x21082, 0xaee304c8,
-0x3c030800, 0x431025, 0x3c010001, 0xac221220,
-0x3c020001, 0x2442add4, 0x451024, 0x21082,
-0x431025, 0x3c010001, 0xac221280, 0x96e6045a,
-0x3821, 0x24050011, 0xafa00010, 0xc002403,
-0xafa00014, 0x8001268, 0x0, 0x3c020001,
-0x2442a9d4, 0x21100, 0x21182, 0x3c030800,
-0x431025, 0x3c010001, 0xac221280, 0x96e2046a,
-0x30420010, 0x14400009, 0x0, 0x96e2047a,
-0x30420010, 0x10400112, 0x0, 0x96e2046a,
-0x30420010, 0x10400005, 0x3c020700, 0x96e2047a,
-0x30420010, 0x14400102, 0x3c020700, 0x34423000,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee30608,
-0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
-0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
-0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
-0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x80012d4,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x80012ea,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020007, 0xac820000, 0x24020001,
-0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
-0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
-0x800136d, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x800133b, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x8001351, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
-0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
-0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002,
-0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
-0x3821, 0xafa00010, 0xc002403, 0xafa00014,
-0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200,
-0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
-0xc004500, 0x0, 0xc002318, 0x0,
-0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
-0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8,
-0x34a5c358, 0x27623800, 0xaee27258, 0x27623800,
-0xaee27260, 0x27623800, 0xaee27264, 0x3661021,
-0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0,
-0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c,
-0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c,
-0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c,
-0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268,
-0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8,
-0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee30608,
-0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
-0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
-0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
-0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x800140c,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8001422,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020007, 0xac820000, 0x24020001,
-0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
-0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
-0x80014a5, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x3021,
-0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x8001473, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x8001489, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
-0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
-0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
-0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd,
-0x0, 0x8f820040, 0x30420001, 0x14400008,
-0x0, 0x8f430104, 0x24020001, 0x10620004,
-0x0, 0x8f420264, 0x10400006, 0x0,
-0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5,
-0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044,
-0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178,
-0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c,
-0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021,
-0xaee2726c, 0xc004064, 0x0, 0xc004440,
-0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008,
-0x27bd0028, 0x3e00008, 0x0, 0x3e00008,
-0x0, 0x0, 0x0, 0x2402002c,
-0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278,
-0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88,
-0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
-0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
-0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
-0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067,
-0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
-0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
-0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
-0x431025, 0xaee20000, 0x8f420218, 0x30420100,
-0x104000c6, 0x0, 0x8f8200b0, 0x30420004,
-0x104000c2, 0x0, 0x3c030001, 0x771821,
-0x8c6383d0, 0x8f820104, 0x146200b4, 0x0,
-0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4,
-0x146200ae, 0x0, 0x8f8200b0, 0x3c030080,
-0x431024, 0x1040000d, 0x0, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
-0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
-0x431024, 0x80015cc, 0xaf82011c, 0x3c030001,
-0x771821, 0x8c6383d0, 0x8f820104, 0x14620082,
-0x0, 0x3c030001, 0x771821, 0x8c6383d4,
-0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
-0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
-0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0,
-0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
-0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20006, 0x0, 0x8ee201a4,
-0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4,
-0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008,
-0x24020400, 0xa462000e, 0x2402000f, 0xac620018,
-0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
-0x0, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
-0x0, 0x800158a, 0x0, 0x14a00005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80015a0, 0x0, 0x8ee24e30,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x24020007,
-0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
-0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
-0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c,
-0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
-0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
-0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284,
-0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
-0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
-0x34a50900, 0x80015cc, 0x0, 0x8f820104,
-0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4,
-0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274,
-0x92e304f4, 0x24420067, 0x14600006, 0xaee27274,
-0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b,
-0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004,
-0x0, 0x92e204f4, 0x50400074, 0xa2e004f4,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
-0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x8001621, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8001637, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020012, 0xac820000,
-0x24020001, 0xac820004, 0x5600000b, 0x24100001,
-0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014,
-0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
-0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
-0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4,
-0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c,
-0x1040006d, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
-0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4,
-0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x8001697, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x80016ad, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020012, 0xac820000, 0x24020001, 0xac820004,
-0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
-0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c,
-0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
-0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
-0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
-0x0, 0xaee04e24, 0x8f820040, 0x30420001,
-0x14400008, 0x0, 0x8f430104, 0x24020001,
-0x10620004, 0x0, 0x8f420264, 0x10400006,
-0x0, 0x8ee2017c, 0x24420001, 0xaee2017c,
-0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004,
-0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178,
-0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278,
-0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238,
-0x104002aa, 0x0, 0x3c020001, 0x571021,
-0x904283e0, 0x144002a5, 0x0, 0x8f420080,
-0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084,
-0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088,
-0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090,
-0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098,
-0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0,
-0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8,
-0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0,
-0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8,
-0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c,
-0xaee0003c, 0x41080, 0x571021, 0x8ee3003c,
-0x8c420244, 0x24840001, 0x621821, 0x2c82000f,
-0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc,
-0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8001775,
-0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030,
-0xac620008, 0x24020400, 0xa462000e, 0x2402000f,
-0xac620018, 0xac60001c, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x800175f, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x8001775, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x12000212, 0x3c020400, 0xafa20018, 0x3c020001,
-0x571021, 0x904283b0, 0x1040010b, 0x0,
-0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
-0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
-0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
-0x1221023, 0x2c420033, 0x1040006a, 0x5821,
-0x24180008, 0x240f000d, 0x240d0007, 0x240c0040,
-0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
-0x11020004, 0x0, 0x8f820124, 0x15020007,
-0x1021, 0x8ee201a4, 0x8021, 0x24420001,
-0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608,
-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e,
-0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
-0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
-0xaf880120, 0x92e24e20, 0x14400033, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x80017e0,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x80017f3,
-0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
-0x0, 0x316300ff, 0x24020001, 0x14620077,
-0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x10400061,
-0x5821, 0x240d0008, 0x240c0011, 0x24080012,
-0x24070040, 0x240a0001, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
-0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400033, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x1448001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10470007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x800184c,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x800185f,
-0x0, 0x8ee24e30, 0x24420001, 0x50470003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac880000, 0xac8a0004, 0x56000006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
-0x0, 0x316300ff, 0x24020001, 0x14620003,
-0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
-0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
-0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
-0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120,
-0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
-0x800197c, 0x0, 0x3c040001, 0x248452bc,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
-0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120,
-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
-0x27683000, 0x8f820128, 0x11020004, 0x0,
-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x80018f7,
-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xace40000, 0xace50004,
-0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d,
-0xace20018, 0xace9001c, 0x318c0, 0x2463060c,
-0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010,
-0xaf880120, 0x92e24e20, 0x14400037, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020007, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee54e30, 0x24420001, 0x10430007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x80018e1, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x80018f7, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
-0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
-0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f000, 0x800197c, 0x0, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x800195e,
-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
-0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x8001948,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x800195e,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020012, 0xac820000, 0x24020001,
-0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
-0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
-0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
-0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
-0xc002403, 0x0, 0x8ee201ac, 0x8021,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
-0x24020001, 0x3c010001, 0x370821, 0xa02083b0,
-0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
-0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
-0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
-0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84,
-0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
-0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
-0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
-0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228,
-0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010,
-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x1040006a, 0x5821, 0x24180008, 0x240f000d,
-0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
-0x27683000, 0x8f820128, 0x11020004, 0x0,
-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8001a15,
-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xace40000, 0xace50004,
-0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
-0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
-0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8001a02, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x8001a15, 0x0, 0x8ee24e30,
-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
-0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
-0x24020001, 0x54620078, 0xafa00010, 0xaeea0608,
-0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
-0x2c420033, 0x10400061, 0x5821, 0x240d0008,
-0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c,
-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
-0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8001a6e, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x8001a81, 0x0, 0x8ee24e30,
-0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
-0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
-0x24020001, 0x10620022, 0x0, 0x3c040001,
-0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
-0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
-0x8001aad, 0x0, 0x3c040001, 0x248452b0,
-0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
-0xc002403, 0x34a5f010, 0x8001aad, 0x0,
-0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608,
-0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
-0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
-0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
-0x8ee204d4, 0x30420001, 0x10400055, 0x0,
-0x8f420218, 0x30420080, 0x10400029, 0x0,
-0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c,
-0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000,
-0x2407ffff, 0x2021, 0x461024, 0x1444000d,
-0x671824, 0x1465000b, 0x0, 0x8ee27b80,
-0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021,
-0x461024, 0x14440003, 0x671824, 0x1065000b,
-0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0,
-0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044,
-0x38420020, 0x8001b38, 0xaf820044, 0x8f820044,
-0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044,
-0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044,
-0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4,
-0x24060000, 0x2407ffff, 0x2021, 0x461024,
-0x1444000d, 0x671824, 0x1465000b, 0x0,
-0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4,
-0x2021, 0x461024, 0x14440003, 0x671824,
-0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4,
-0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80,
-0x8f820044, 0x38420040, 0x8001b38, 0xaf820044,
-0x8f820044, 0x34420040, 0x8001b38, 0xaf820044,
-0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c,
-0x24430001, 0x28420015, 0x14400028, 0xaee37b8c,
-0x8f820044, 0x38420020, 0xaf820044, 0x8001b38,
-0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011,
-0x0, 0x8f420218, 0x30420080, 0x10400009,
-0x0, 0x8f820044, 0x34420020, 0xaf820044,
-0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36,
-0xaf820044, 0x8f820044, 0x34420060, 0x8001b36,
-0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
-0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
-0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
-0xaee07b88, 0xc004603, 0x0, 0x8fbf0024,
-0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
-0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
-0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
-0x8f960064, 0x32c20004, 0x1040000c, 0x24020004,
-0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060,
-0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001,
-0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
-0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
-0x0, 0x32c20002, 0x1440000c, 0x3c050003,
-0x3c040001, 0x24845354, 0x34a50001, 0x2c03021,
-0x3821, 0xafa00010, 0xc002403, 0xafa00014,
-0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
-0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
-0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
-0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
-0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360,
-0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
-0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
-0x0, 0x80022ed, 0xaf960064, 0x93a20020,
-0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
-0x3c010001, 0x220821, 0x8c225418, 0x400008,
-0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
-0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
-0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
-0x8fa20020, 0x24030001, 0x3c010001, 0x370821,
-0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060,
-0x34420100, 0xaf820060, 0x8ee20144, 0x24420001,
-0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020,
-0x21200, 0x22502, 0x24020001, 0x10820005,
-0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9,
-0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074,
-0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4,
-0xaee40070, 0xaee40074, 0x621824, 0xaee304d4,
-0x8f840054, 0x41442, 0x41c82, 0x431021,
-0x41cc2, 0x431023, 0x41d02, 0x431021,
-0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
-0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020,
-0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
-0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
-0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
-0x920c0, 0x2e41021, 0x9442727c, 0x30424000,
-0x1040000a, 0x971021, 0x97430212, 0xa443727e,
-0x8f430214, 0x971021, 0xac437280, 0x2e41821,
-0x34028000, 0x8001c79, 0xa462727c, 0x9443727e,
-0x97420212, 0x14620006, 0x2e41021, 0x971021,
-0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021,
-0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff,
-0x2021, 0x410c0, 0x2e21021, 0x9442737c,
-0x30424000, 0x54400005, 0x803021, 0x24840001,
-0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
-0x618c0, 0x610c0, 0x571821, 0x8c63737c,
-0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
-0x24845378, 0xafa20014, 0x8f470214, 0x3c050003,
-0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
-0x97440212, 0x771021, 0xa444737e, 0x8f440214,
-0x771021, 0x2e31821, 0xac447380, 0x34028000,
-0xa462737c, 0x910c0, 0x2e21021, 0x8001c79,
-0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e,
-0x510c0, 0x9443737e, 0x97420212, 0x14620006,
-0x510c0, 0x971021, 0x8c437380, 0x8f420214,
-0x10620065, 0x510c0, 0x2e21021, 0x9445737c,
-0x510c0, 0x2e21021, 0x9442737c, 0x30428000,
-0x1040fff0, 0x971021, 0x520c0, 0x971021,
-0x9443737e, 0x97420212, 0x14620006, 0x2406ffff,
-0x971021, 0x8c437380, 0x8f420214, 0x10620053,
-0x3c020800, 0x2021, 0x410c0, 0x2e21021,
-0x9442737c, 0x30424000, 0x54400005, 0x803021,
-0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
-0x4c10023, 0x618c0, 0x910c0, 0x571821,
-0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
-0x3c040001, 0x24845384, 0xafa20014, 0x8f470214,
-0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
-0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
-0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
-0x571021, 0x8c4283b4, 0x24420001, 0x3c010001,
-0x370821, 0xac2283b4, 0x3c030001, 0x771821,
-0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c,
-0x97440212, 0x771021, 0xa444737e, 0x8f440214,
-0x771021, 0x2e31821, 0xac447380, 0x34028000,
-0xa462737c, 0x510c0, 0x2e21021, 0xa446737c,
-0x2021, 0x428c0, 0x2e51021, 0x9442777c,
-0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa,
-0x428c0, 0x92e204d8, 0x10400006, 0x24020001,
-0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f,
-0xaee304dc, 0x8f830228, 0x24020001, 0x1221004,
-0x621825, 0xaf830228, 0x3c020800, 0x34421000,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
-0x5821, 0x24100008, 0x240f000d, 0x240d0007,
-0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3821,
-0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee20608,
-0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
-0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
-0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144d001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8001cf5, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x8001d08, 0x0, 0x8ee24e30, 0x24420001,
-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
-0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x10400061, 0x5821, 0x240e0008, 0x240d0011,
-0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x3821, 0x24420001, 0xaee201a4, 0x8001d74,
-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
-0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
-0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144a001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x10480007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8001d61, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x8001d74, 0x0, 0x8ee24e30, 0x24420001,
-0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
-0x10620022, 0x0, 0x3c040001, 0x24845390,
-0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
-0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
-0x0, 0x3c040001, 0x2484539c, 0xafa00014,
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
-0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
-0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
-0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
-0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
-0x928c0, 0x2e51021, 0x9442727c, 0x30428000,
-0x1040002f, 0x2e51021, 0x9442727c, 0x30424000,
-0x1440001c, 0xb71021, 0x9443727e, 0x97420212,
-0x14620018, 0xb71021, 0x8c437280, 0x8f420214,
-0x54620016, 0xafa20010, 0x92e204d8, 0x10400007,
-0x24020001, 0x8ee304dc, 0x1221004, 0x21027,
-0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228,
-0x1221004, 0x21027, 0x621824, 0xaf830228,
-0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
-0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
-0x571021, 0x8c42727c, 0x3c040001, 0x248453b4,
-0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
-0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
-0xb71021, 0x9443727e, 0x97420212, 0x14620019,
-0x918c0, 0xb71021, 0x8c437280, 0x8f420214,
-0x14620014, 0x918c0, 0x2e51021, 0x9447727c,
-0x720c0, 0x971021, 0x9443737e, 0xb71021,
-0xa443727e, 0x971021, 0x8c437380, 0xb71021,
-0xac437280, 0x2e41021, 0x9443737c, 0x2e51021,
-0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e,
-0xa462737c, 0x2e31021, 0x9447727c, 0x3021,
-0x720c0, 0x2e41021, 0x9442737c, 0x4021,
-0x30428000, 0x14400025, 0xe02821, 0x605021,
-0x340bc000, 0x971021, 0x9443737e, 0x97420212,
-0x54620015, 0xe02821, 0x971021, 0x8c437380,
-0x8f420214, 0x54620010, 0xe02821, 0x11000006,
-0x2e41021, 0x9443737c, 0x510c0, 0x2e21021,
-0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021,
-0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c,
-0x8001e28, 0x24060001, 0x510c0, 0x2e21021,
-0x9447737c, 0x720c0, 0x2e41021, 0x9442737c,
-0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff,
-0x14400025, 0x2021, 0x720c0, 0x971021,
-0x9443737e, 0x97420212, 0x1462000f, 0x910c0,
-0x971021, 0x8c437380, 0x8f420214, 0x1462000a,
-0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
-0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
-0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
-0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010,
-0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
-0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
-0x3c020800, 0x2021, 0x428c0, 0xb71021,
-0x9443777e, 0x97420212, 0x5462002b, 0x24840001,
-0xb71021, 0x8c437780, 0x8f420214, 0x54620026,
-0x24840001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4,
-0x3c020001, 0x571021, 0x8c4283b4, 0x809021,
-0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784,
-0x2f02021, 0x2f12821, 0xc002490, 0x24060008,
-0x26310008, 0x3c020001, 0x571021, 0x8c4283b4,
-0x26520001, 0x242102b, 0x1440fff5, 0x26100008,
-0x3c040001, 0x972021, 0x8c8483b4, 0x24050008,
-0x420c0, 0x2484777c, 0xc002488, 0x2e42021,
-0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf,
-0x428c0, 0x3c020800, 0x34422000, 0xafa20018,
-0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
-0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
-0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
-0x1221023, 0x2c420033, 0x1040006a, 0x5821,
-0x24100008, 0x240f000d, 0x240d0007, 0x240c0040,
-0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
-0x11020004, 0x0, 0x8f820124, 0x15020007,
-0x1021, 0x8ee201a4, 0x3821, 0x24420001,
-0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608,
-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e,
-0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
-0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
-0xaf880120, 0x92e24e20, 0x14400033, 0x24070001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8001ee8,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x8001efb,
-0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
-0x0, 0x316300ff, 0x24020001, 0x54620078,
-0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x10400061,
-0x5821, 0x240e0008, 0x240d0011, 0x240a0012,
-0x24080040, 0x240c0001, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x3821,
-0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4,
-0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
-0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400033, 0x24070001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144a001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10480007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8001f54,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x8001f67,
-0x0, 0x8ee24e30, 0x24420001, 0x50480003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
-0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
-0x0, 0x316300ff, 0x24020001, 0x10620022,
-0x0, 0x3c040001, 0x24845390, 0xafa00010,
-0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
-0xc002403, 0x34a5f011, 0x8001f93, 0x0,
-0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120,
-0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
-0x8001f93, 0x0, 0x3c040001, 0x248453a8,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
-0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
-0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001,
-0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020,
-0x21200, 0x21d02, 0x24020001, 0x10620005,
-0x24020002, 0x1062000d, 0x0, 0x8001fb7,
-0xafa00010, 0x92e204d8, 0x14400006, 0x24020001,
-0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
-0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
-0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
-0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8,
-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
-0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
-0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
-0x22502, 0x24020001, 0x10820005, 0x24020002,
-0x1082000f, 0x0, 0x8001fe3, 0xafa00010,
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
-0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
-0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
-0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
-0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4,
-0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
-0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
-0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
-0x21d02, 0x24020001, 0x10620005, 0x24020002,
-0x1062000e, 0x0, 0x8002011, 0xafa00010,
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
-0x370821, 0x8002018, 0xa02283b3, 0x3c020001,
-0x571021, 0x904283b2, 0x3c010001, 0x370821,
-0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
-0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
-0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020,
-0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
-0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
-0x27840208, 0x27450200, 0xc00249a, 0x24060008,
-0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
-0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
-0x8ee20134, 0x8f460248, 0x2021, 0xc005108,
-0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
-0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
-0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
-0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070,
-0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0,
-0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070,
-0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
-0x27450200, 0x24060008, 0xaee20068, 0x24020006,
-0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00,
-0xaee2006c, 0x240203e8, 0x24040002, 0x24030001,
-0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
-0x30420008, 0x10400004, 0x0, 0xaee30108,
-0x8002061, 0x2021, 0xaee40108, 0x2021,
-0x3c030001, 0x641821, 0x90635c30, 0x2e41021,
-0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
-0x0, 0x8f820040, 0x2e41821, 0x24840001,
-0x21702, 0x24420030, 0xa062009c, 0x2e41021,
-0x80022e8, 0xa040009c, 0x24020001, 0x3c010001,
-0x370821, 0xa02283e0, 0x240b0400, 0x24080014,
-0x240a0040, 0x24090001, 0x8f830100, 0x27623000,
-0x24660020, 0xc2102b, 0x50400001, 0x27662800,
-0x8f820108, 0x10c20004, 0x0, 0x8f820104,
-0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821,
-0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8,
-0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e,
-0xac680018, 0xac60001c, 0xac640000, 0xac650004,
-0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec,
-0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001,
-0x504a0003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2,
-0x0, 0x80022e8, 0x0, 0x3c020900,
-0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244,
-0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1,
-0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
-0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
-0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
-0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
-0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
-0x5821, 0x24100008, 0x240f000d, 0x240d0007,
-0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
-0x24e80020, 0x102102b, 0x50400001, 0x27683000,
-0x8f820128, 0x11020004, 0x0, 0x8f820124,
-0x15020007, 0x1021, 0x8ee201a4, 0x3821,
-0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4,
-0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
-0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee20608,
-0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
-0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
-0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144d001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8002119, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x800212c, 0x0, 0x8ee24e30, 0x24420001,
-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
-0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x10400061, 0x5821, 0x240e0008, 0x240d0011,
-0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x3821, 0x24420001, 0xaee201a4, 0x8002198,
-0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
-0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
-0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x144a001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x10480007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8002185, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x8002198, 0x0, 0x8ee24e30, 0x24420001,
-0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
-0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
-0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
-0x10620022, 0x0, 0x3c040001, 0x24845390,
-0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
-0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
-0x0, 0x3c040001, 0x2484539c, 0xafa00014,
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
-0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
-0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
-0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
-0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168,
-0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
-0x27450200, 0x24060008, 0xc00249a, 0xaee20068,
-0x8f820220, 0x30420008, 0x14400002, 0x24020001,
-0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
-0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
-0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020,
-0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
-0x3c030700, 0x34631000, 0x431025, 0xafa20018,
-0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
-0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0,
-0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
-0xac440610, 0x8f870120, 0x27623800, 0x24e80020,
-0x102102b, 0x50400001, 0x27683000, 0x8f820128,
-0x11020004, 0x0, 0x8f820124, 0x15020007,
-0x1021, 0x8ee201a4, 0x3821, 0x24420001,
-0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608,
-0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xace40000, 0xace50004, 0x8ee30608, 0x24020008,
-0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c,
-0x318c0, 0x2463060c, 0x2e31021, 0xace20008,
-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
-0x14400037, 0x24070001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
-0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
-0x10430007, 0x0, 0x8ee24e34, 0x24420001,
-0x10a20005, 0x0, 0x8002247, 0x0,
-0x14a00005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x800225d, 0x0,
-0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4,
-0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
-0x0, 0x8f830120, 0x27623800, 0x24660020,
-0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
-0x10c20004, 0x0, 0x8f820124, 0x14c20007,
-0x0, 0x8ee201a4, 0x3821, 0x24420001,
-0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608,
-0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c,
-0xac620008, 0x24020008, 0xa462000e, 0x24020011,
-0xac620018, 0xac640000, 0xac650004, 0x8ee204c4,
-0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
-0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020012, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
-0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
-0x0, 0x80022ae, 0x0, 0x14a00005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80022c4, 0x0, 0x8ee24e30,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x24020012,
-0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
-0x0, 0x3c040001, 0x248453fc, 0xafa00010,
-0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
-0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
-0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
-0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228,
-0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
-0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
-0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
-0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c,
-0x8f42010c, 0x14620009, 0x24020002, 0xaf820064,
-0x8f820064, 0x14400005, 0x0, 0x8f43022c,
-0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044,
-0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034,
-0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
-0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014,
-0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
-0x24840001, 0x3021, 0x1071026, 0x30420001,
-0x10400002, 0x81842, 0x6a1826, 0x604021,
-0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
-0x25290001, 0x125102b, 0x1440fff0, 0x0,
-0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8,
-0x27642800, 0xafbf0010, 0xc002488, 0x24051000,
-0x24020021, 0xaf800100, 0xaf800104, 0xaf800108,
-0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120,
-0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134,
-0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30,
-0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040,
-0x10400004, 0x0, 0x8f82011c, 0x34420004,
-0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
-0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
-0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403,
-0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
-0x3c020400, 0x10620029, 0x43102b, 0x14400008,
-0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
-0x10620011, 0x0, 0x8002374, 0x0,
-0x10620008, 0x3c024000, 0x1462001c, 0x0,
-0x8ee20190, 0x24420001, 0xaee20190, 0x8002374,
-0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c,
-0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
-0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd,
-0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001,
-0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0,
-0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
-0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
-0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
-0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0,
-0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
-0x8021, 0x43102b, 0x14400008, 0x3c042000,
-0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
-0x0, 0x80023e0, 0x0, 0x10640003,
-0x3c024000, 0x14620045, 0x0, 0x8f8200a0,
-0x441024, 0x10400006, 0x0, 0x8ee20194,
-0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194,
-0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198,
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c,
-0x30420200, 0x1040001b, 0x0, 0x8f8300a0,
-0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001,
-0x3c020001, 0x3442f000, 0x621024, 0x50400001,
-0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0,
-0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124,
-0x8f820124, 0x27633000, 0x43102b, 0x10400005,
-0x276237e0, 0xaf820124, 0x80023ca, 0x0,
-0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024,
-0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
-0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd,
-0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001,
-0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
-0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
-0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
-0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012,
-0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021,
-0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
-0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250,
-0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
-0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010,
-0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94,
-0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
-0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004,
-0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
-0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
-0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0,
-0x62182b, 0x10600005, 0x0, 0x3c020001,
-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
-0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
-0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
-0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
-0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0,
-0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
-0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
-0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
-0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001,
-0x8c425c40, 0xc09021, 0xe09821, 0x10800006,
-0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
-0x800244e, 0x0, 0x24a40008, 0xc002488,
-0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001,
-0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94,
-0x45102b, 0x10400005, 0x0, 0x3c020001,
-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
-0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001,
-0x8c635d94, 0x8e020004, 0xac620004, 0xac710008,
-0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94,
-0x45102b, 0xac720010, 0xac730014, 0xac740018,
-0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
-0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
-0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
-0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
-0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
-0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd,
-0x24840004, 0x3e00008, 0x0, 0x10c00007,
-0x0, 0x8c820000, 0x24840004, 0x24c6fffc,
-0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008,
-0x0, 0x10c00007, 0x0, 0x8ca20000,
-0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb,
-0x24840004, 0x3e00008, 0x0, 0x3e00008,
-0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4,
-0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4,
-0x8ee304fc, 0x21100, 0x626021, 0x95870008,
-0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c,
-0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b,
-0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258,
-0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003,
-0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c,
-0x8ee3726c, 0x441021, 0x62182b, 0x10600006,
-0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8,
-0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200,
-0x1040014d, 0x4821, 0x96e2045a, 0x30420010,
-0x10400149, 0x0, 0x8f840100, 0x27623000,
-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
-0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001,
-0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000,
-0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e,
-0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c,
-0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec,
-0x14400036, 0x24090001, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f,
-0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
-0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
-0x0, 0x8002516, 0x0, 0x14a00005,
-0x0, 0x8f820108, 0x24420020, 0xaf820108,
-0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x800252c, 0x0, 0x8ee24e28,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
-0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
-0xac820000, 0x24020001, 0xac820004, 0x1520000a,
-0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
-0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
-0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
-0x3641821, 0x24420010, 0x43102b, 0x14400073,
-0x0, 0x8ee27264, 0x24480010, 0x3641021,
-0x102102b, 0x14400002, 0x3c02ffff, 0x1024021,
-0x8f850100, 0x27623000, 0x24a60020, 0xc2102b,
-0x50400001, 0x27662800, 0x8f820108, 0x10c20004,
-0x0, 0x8f820104, 0x14c20007, 0x2563000c,
-0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
-0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021,
-0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e,
-0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4,
-0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025,
-0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037,
-0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x8c830000, 0x24020005, 0x1462001f,
-0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
-0x24030040, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
-0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
-0x0, 0x800258a, 0x0, 0x14a00005,
-0x0, 0x8f820108, 0x24420020, 0xaf820108,
-0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
-0xac800000, 0x80025a0, 0x0, 0x8ee24e28,
-0x24030040, 0x24420001, 0x50430003, 0x1021,
-0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
-0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
-0xac820000, 0x24020001, 0xac820004, 0x1520000a,
-0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
-0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
-0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
-0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
-0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
-0x27662800, 0x8f820108, 0x10c20004, 0x0,
-0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8,
-0x4821, 0x24420001, 0xaee201a8, 0x800260d,
-0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000,
-0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e,
-0x24020006, 0xaca20018, 0x24630010, 0xaca30008,
-0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002,
-0x431025, 0xaca20010, 0xaf860100, 0x92e204ec,
-0x14400037, 0x24090001, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x8c830000, 0x24020005,
-0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c,
-0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001,
-0x10430007, 0x0, 0x8ee24e2c, 0x24420001,
-0x10a20005, 0x0, 0x80025f7, 0x0,
-0x14a00005, 0x0, 0x8f820108, 0x24420020,
-0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011,
-0x50400013, 0xac800000, 0x800260d, 0x0,
-0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x24020005, 0xac820000, 0x24020001, 0xac820004,
-0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
-0x3c040001, 0x24845730, 0x3c050004, 0xafa20014,
-0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
-0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
-0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
-0x14a20007, 0x24020006, 0x8ee201a8, 0x4821,
-0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8,
-0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e,
-0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c,
-0x8ee204c8, 0x3c030002, 0x431025, 0xac820010,
-0xaf850100, 0x92e204ec, 0x14400037, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c830000, 0x24020005, 0x1462001f, 0x0,
-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
-0x8002661, 0x0, 0x14a00005, 0x0,
-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8002677, 0x0, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
-0x24020001, 0xac820004, 0x15200009, 0x3c050004,
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
-0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
-0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
-0x431021, 0xac44000c, 0x8ee27258, 0xafa20018,
-0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
-0x10400004, 0x24620001, 0x2403fffe, 0x431024,
-0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800,
-0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007,
-0x451024, 0x24630007, 0xaee27258, 0x8ee2726c,
-0x8ee47258, 0x651824, 0x431023, 0xaee2726c,
-0x3661021, 0x82202b, 0x14800004, 0x3c03ffff,
-0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258,
-0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800,
-0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4,
-0x14e20007, 0x0, 0x8ee201b4, 0x4821,
-0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4,
-0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
-0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
-0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
-0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018,
-0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
-0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
-0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
-0x10620016, 0x28620003, 0x10400005, 0x24020001,
-0x10620008, 0x0, 0x8002703, 0x0,
-0x24020003, 0x10620017, 0x0, 0x8002703,
-0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
-0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
-0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0,
-0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703,
-0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
-0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0,
-0x8ee500e4, 0x401821, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaee400e0,
-0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff,
-0x104001c1, 0x31a20200, 0x1040014d, 0x4821,
-0x96e2045a, 0x30420010, 0x10400149, 0x0,
-0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
-0x50400001, 0x27652800, 0x8f820108, 0x10a20004,
-0x0, 0x8f820104, 0x14a20006, 0x2402000c,
-0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e,
-0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264,
-0x24060005, 0xa482000e, 0xac860018, 0xac830008,
-0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010,
-0xaf850100, 0x92e204ec, 0x14400036, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c820000, 0x1446001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x8002758,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x800276e,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
-0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
-0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
-0x43102b, 0x14400073, 0x0, 0x8ee27264,
-0x24480010, 0x3641021, 0x102102b, 0x14400002,
-0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000,
-0x24a60020, 0xc2102b, 0x50400001, 0x27662800,
-0x8f820108, 0x10c20004, 0x0, 0x8f820104,
-0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821,
-0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8,
-0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004,
-0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008,
-0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8,
-0x3c030002, 0x431025, 0xaca20010, 0xaf860100,
-0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28,
-0x210c0, 0x24424e38, 0x2e22021, 0x8c830000,
-0x24020005, 0x1462001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x80027cc,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x80027e2,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
-0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
-0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
-0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
-0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
-0xc2102b, 0x50400001, 0x27662800, 0x8f820108,
-0x10c20004, 0x0, 0x8f820104, 0x14c20007,
-0x2563000c, 0x8ee201a8, 0x4821, 0x24420001,
-0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c,
-0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264,
-0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018,
-0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c,
-0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010,
-0xaf860100, 0x92e204ec, 0x14400037, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c830000, 0x24020005, 0x1462001f, 0x0,
-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
-0x8002839, 0x0, 0x14a00005, 0x0,
-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x800284f, 0x0, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
-0x24020001, 0xac820004, 0x1520000a, 0x34028100,
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
-0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
-0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
-0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
-0x8f830100, 0x27623000, 0x24640020, 0x82102b,
-0x50400001, 0x27642800, 0x8f820108, 0x10820004,
-0x0, 0x8f820104, 0x14820007, 0x24050005,
-0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
-0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004,
-0x8ee27264, 0xa467000e, 0xac650018, 0xac620008,
-0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010,
-0xaf840100, 0x92e204ec, 0x14400036, 0x24090001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x80028a0,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x80028b6,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
-0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4,
-0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
-0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
-0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
-0x34a53800, 0x441021, 0xaee2725c, 0x3651021,
-0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264,
-0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458,
-0x24630001, 0x2442ffff, 0x621824, 0xaee304e4,
-0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0,
-0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0,
-0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189,
-0x0, 0x8ee204e8, 0x8ee304fc, 0x21100,
-0x621821, 0x94670008, 0x92e204ed, 0x8c680000,
-0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8,
-0x34460400, 0x31420200, 0x1040001f, 0x0,
-0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000,
-0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264,
-0x9464000e, 0x3c050001, 0x34a53800, 0x24420004,
-0xaee27264, 0x8ee37264, 0x42400, 0x3651021,
-0x3c010001, 0x370821, 0xac2483dc, 0x62182b,
-0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff,
-0x431021, 0xaee27264, 0x8ee27264, 0x8002917,
-0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff,
-0x44102a, 0x10400015, 0x0, 0x8f8200d8,
-0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c,
-0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001,
-0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a,
-0x10400006, 0x0, 0x8ee201b8, 0x24420001,
-0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001,
-0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc,
-0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001,
-0x571021, 0x8c4283d8, 0x1040002f, 0x5021,
-0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
-0x50400001, 0x27652800, 0x8f820108, 0x10a20032,
-0x0, 0x8f820104, 0x10a2002f, 0x24020015,
-0xac880000, 0xac890004, 0x8ee37264, 0xa487000e,
-0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001,
-0x771821, 0x8c6383dc, 0xac860010, 0x431025,
-0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066,
-0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e21821, 0x24020015, 0xac620000, 0x24020001,
-0x80029bf, 0xac620004, 0x8f840100, 0x27623000,
-0x24850020, 0xa2102b, 0x50400001, 0x27652800,
-0x8f820108, 0x10a20004, 0x0, 0x8f820104,
-0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001,
-0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000,
-0xac890004, 0x8ee37264, 0xa487000e, 0xac820018,
-0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c,
-0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c830000, 0x24020005, 0x1462001f, 0x0,
-0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
-0x8ee54e28, 0x24420001, 0x10430007, 0x0,
-0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
-0x80029a9, 0x0, 0x14a00005, 0x0,
-0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x80029bf, 0x0, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
-0x24020001, 0xac820004, 0x1540000a, 0x24020001,
-0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730,
-0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
-0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
-0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
-0x370821, 0xac2083d8, 0x3c010001, 0x370821,
-0xac2083dc, 0x21100, 0x431021, 0xac44000c,
-0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021,
-0x24420007, 0x451024, 0x24630007, 0xaee27258,
-0x8ee2726c, 0x8ee47258, 0x651824, 0x431023,
-0xaee2726c, 0x3661021, 0x82202b, 0x14800004,
-0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258,
-0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073,
-0x0, 0x8f830100, 0x27623000, 0x24640020,
-0x82102b, 0x14400002, 0x5021, 0x27642800,
-0x8f820108, 0x10820004, 0x0, 0x8f820104,
-0x14820006, 0x24050005, 0x8ee201a8, 0x24420001,
-0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000,
-0xac690004, 0x8ee27264, 0xa467000e, 0xac650018,
-0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c,
-0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
-0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
-0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
-0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
-0x24420001, 0x10a20005, 0x0, 0x8002a30,
-0x0, 0x14a00005, 0x0, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8002a46,
-0x0, 0x8ee24e28, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
-0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
-0x2e22021, 0x24020005, 0xac820000, 0x24020001,
-0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
-0x24845748, 0x3c050004, 0xafa90010, 0xafa00014,
-0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
-0x8002a72, 0x0, 0x8ee27264, 0x451021,
-0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
-0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c,
-0x3641021, 0x62182b, 0x14600004, 0x3c03ffff,
-0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8,
-0x96e20458, 0x24630001, 0x2442ffff, 0x621824,
-0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005,
-0x0, 0x8f820060, 0x2403fff7, 0x431024,
-0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100,
-0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040,
-0x24630001, 0x50620003, 0x1021, 0x8ee24e2c,
-0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c,
-0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28,
-0x8c870004, 0x14620007, 0xa03021, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2,
-0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e2c, 0x24420001,
-0x210c0, 0x24424e38, 0x2e22021, 0x8c820004,
-0x8f830108, 0x21140, 0x621821, 0xaf830108,
-0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
-0x104000c1, 0x31080, 0x3c010001, 0x220821,
-0x8c225770, 0x400008, 0x0, 0x8ee204f0,
-0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
-0x43102b, 0x144000be, 0x0, 0x8ee304e4,
-0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8002b12,
-0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
-0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
-0x24420001, 0x10430007, 0x0, 0x8ee24e34,
-0x24420001, 0x10a20005, 0x0, 0x8002afc,
-0x0, 0x14a00005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8002b12,
-0x0, 0x8ee24e30, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020012, 0xac820000, 0x24020001,
-0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
-0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
-0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
-0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0,
-0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274,
-0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184,
-0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee20504,
-0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018,
-0x21080, 0x571021, 0x8c440508, 0x24020003,
-0x1462000f, 0x0, 0x3c020001, 0x571021,
-0x904283b1, 0x10400014, 0x0, 0x8ee201d0,
-0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8,
-0x641821, 0x306300ff, 0x8002b59, 0xaee35240,
-0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc,
-0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10,
-0x441021, 0xaee201d8, 0x8ee20000, 0x34420040,
-0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
-0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
-0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
-0x3c040001, 0x24845760, 0xafa60014, 0xafa20010,
-0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
-0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048,
-0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104,
-0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
-0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
-0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
-0x31080, 0x3c010001, 0x220821, 0x8c2257c0,
-0x400008, 0x0, 0x9663000e, 0x8ee2725c,
-0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
-0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
-0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c,
-0x82202b, 0x148003b9, 0x0, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8021, 0x24420001, 0xaee201a4, 0x8002bfe,
-0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
-0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8002be8,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400013, 0xac800000, 0x8002bfe,
-0x0, 0x8ee24e30, 0x240c0040, 0x24420001,
-0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
-0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
-0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
-0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
-0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
-0x240c0001, 0x8002f19, 0x0, 0x966c001c,
-0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024,
-0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc,
-0x151900, 0x621021, 0x8c52000c, 0x92e27b98,
-0x641821, 0x9476000a, 0x14400003, 0x32c20002,
-0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021,
-0x96e2045a, 0x30420002, 0x10400047, 0x0,
-0x8e63001c, 0x8ee204fc, 0x32100, 0x821021,
-0x8c42000c, 0x37e1821, 0x24420022, 0x43102b,
-0x1440000a, 0x24050014, 0x8ee204fc, 0x821021,
-0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e,
-0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc,
-0x821021, 0x8c42000c, 0x9450000e, 0x94430010,
-0x94440012, 0x94450014, 0x2038021, 0x2048021,
-0x2058021, 0x94430016, 0x94440018, 0x9445001a,
-0x2038021, 0x2048021, 0x2058021, 0x9443001c,
-0x9444001e, 0x94420020, 0x2038021, 0x2048021,
-0x2028021, 0x101c02, 0x3202ffff, 0x628021,
-0x8e63001c, 0x8ee204fc, 0x102402, 0x32900,
-0xa21021, 0x8c43000c, 0x3202ffff, 0x828021,
-0x37e1021, 0x24630018, 0x62182b, 0x14600009,
-0x0, 0x8ee204fc, 0xa21021, 0x8c43000c,
-0x101027, 0x3c01ffff, 0x230821, 0x8002c6f,
-0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c,
-0x101027, 0xa4620018, 0x96e2045a, 0x8821,
-0x30420008, 0x14400063, 0xa021, 0x8e63001c,
-0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c,
-0x37e1821, 0x24420022, 0x43102b, 0x14400035,
-0x0, 0x8ee204fc, 0xc21021, 0x8c42000c,
-0x24470010, 0x37e1021, 0xe2102b, 0x50400001,
-0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021,
-0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b,
-0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc,
-0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a,
-0x37e1021, 0xe2102b, 0x14400002, 0x2838821,
-0xeb3821, 0x94e20000, 0x24e70002, 0x2228821,
-0x37e1021, 0xe2102b, 0x50400001, 0xeb3821,
-0x94e20000, 0x24e70002, 0x2228821, 0x37e1021,
-0xe2102b, 0x50400001, 0xeb3821, 0x94e20000,
-0x24e70002, 0x2228821, 0x37e1021, 0xe2102b,
-0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0,
-0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c,
-0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021,
-0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec,
-0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821,
-0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821,
-0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c,
-0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020,
-0x2238821, 0x2248821, 0x2228821, 0x111c02,
-0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
-0x628821, 0x32c20001, 0x104000b2, 0x0,
-0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080,
-0x10400008, 0x0, 0x92e27b98, 0x14400005,
-0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c,
-0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021,
-0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b,
-0x14400008, 0xe02021, 0x2405000e, 0xc002f75,
-0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09,
-0x2028021, 0x94e60000, 0x24e70002, 0x94e50000,
-0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000,
-0x24e70002, 0x94e40000, 0x24e70002, 0x2068021,
-0x2058021, 0x2038021, 0x2028021, 0x94e20000,
-0x94e30002, 0x2048021, 0x2028021, 0x2038021,
-0x101c02, 0x3202ffff, 0x628021, 0x101c02,
-0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004,
-0x3205ffff, 0x96620016, 0x8002d17, 0x512021,
-0x96620016, 0x542021, 0x41402, 0x3083ffff,
-0x432021, 0x852023, 0x41402, 0x822021,
-0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4,
-0x24430017, 0x37e1021, 0x62102b, 0x50400001,
-0x6b1821, 0x90630000, 0x24020011, 0x14620031,
-0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028,
-0x43102b, 0x14400018, 0x0, 0x8ee27b9c,
-0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff,
-0x220821, 0x94220028, 0x822021, 0x41c02,
-0x3082ffff, 0x622021, 0x32c20100, 0x14400004,
-0x41027, 0x92e27b98, 0x14400002, 0x41027,
-0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821,
-0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008,
-0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021,
-0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
-0x14400004, 0x41027, 0x92e27b98, 0x14400002,
-0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a,
-0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4,
-0x24420032, 0x43102b, 0x14400018, 0x0,
-0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4,
-0x3c01ffff, 0x220821, 0x94220032, 0x822021,
-0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
-0x14400004, 0x41027, 0x92e27b98, 0x14400002,
-0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff,
-0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c,
-0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032,
-0x822021, 0x41c02, 0x3082ffff, 0x622021,
-0x32c20100, 0x14400004, 0x41027, 0x92e27b98,
-0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4,
-0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821,
-0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b,
-0x1440001b, 0x34038100, 0x26430004, 0x37e1021,
-0x62102b, 0x14400003, 0x602021, 0x6b1821,
-0x602021, 0x8c620000, 0x24630004, 0xae420000,
-0x37e1021, 0x62102b, 0x50400001, 0x6b1821,
-0x8c620000, 0xac820000, 0x34028100, 0xa4620000,
-0x24630002, 0x37e1021, 0x62102b, 0x50400001,
-0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000,
-0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e,
-0xa64c000a, 0xae420000, 0xae440004, 0x9662000e,
-0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e,
-0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018,
-0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
-0x10400004, 0x24620001, 0x2403fffe, 0x431024,
-0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100,
-0x8ee27ba8, 0x24430001, 0x210c0, 0x571021,
-0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac,
-0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072,
-0x0, 0x8ee27ba8, 0x24430001, 0x210c0,
-0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c,
-0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063,
-0x4821, 0x5021, 0x8f8200f0, 0x24480008,
-0x27621800, 0x102102b, 0x50400001, 0x27681000,
-0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4,
-0x8021, 0x24420001, 0xaee201b4, 0x8002dfa,
-0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021,
-0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004,
-0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088,
-0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088,
-0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c,
-0x401821, 0x1021, 0xa32821, 0xa3382b,
-0x822021, 0x872021, 0x8ee204fc, 0xc93021,
-0x63100, 0xaee400e0, 0xaee500e4, 0xc23021,
-0x94c2000a, 0x240c0002, 0x21142, 0x30430003,
-0x106c0016, 0x28620003, 0x10400005, 0x240c0001,
-0x106c0008, 0x0, 0x8002e3f, 0x0,
-0x240c0003, 0x106c0017, 0x0, 0x8002e3f,
-0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
-0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
-0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0,
-0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
-0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f,
-0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
-0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001,
-0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98,
-0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008,
-0x27621800, 0xe2102b, 0x50400001, 0x27671000,
-0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4,
-0x8021, 0x24420001, 0xaee201b4, 0x8002e5d,
-0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018,
-0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0,
-0x16000007, 0x0, 0x8ee20088, 0x24420001,
-0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c,
-0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002,
-0x401821, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0x161142, 0x30430003,
-0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003,
-0x10400005, 0x240c0001, 0x106c0008, 0x0,
-0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019,
-0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8,
-0x8ee300ec, 0x24630001, 0x2c640001, 0x441021,
-0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec,
-0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4,
-0x24630001, 0x2c640001, 0x441021, 0xaee200f0,
-0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0,
-0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
-0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c,
-0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff,
-0x431024, 0x24840001, 0xaee204e4, 0xaee404f0,
-0x8f42023c, 0x82202b, 0x148000b0, 0x0,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
-0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8002ef1, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x8002f07, 0x0, 0x8ee24e30, 0x240c0040,
-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
-0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
-0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014,
-0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
-0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
-0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
-0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170,
-0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274,
-0xaee204f8, 0x8f42023c, 0x10400038, 0x0,
-0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c,
-0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001,
-0x504c0003, 0x1021, 0x8ee20504, 0x24420001,
-0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003,
-0x21080, 0x571021, 0x146c000f, 0x8c440508,
-0x3c020001, 0x571021, 0x904283b1, 0x10400014,
-0x0, 0x8ee201d0, 0x8ee35240, 0x441021,
-0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff,
-0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10,
-0x441021, 0xaee201cc, 0x8ee201d8, 0x641821,
-0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8,
-0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000,
-0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0,
-0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x8f820108,
-0x27633000, 0x43102b, 0x14400002, 0x27622800,
-0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e,
-0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058,
-0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048,
-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068,
-0x52843, 0x10a0000d, 0x3021, 0x3c030001,
-0x34633800, 0x3c07ffff, 0x3631021, 0x82102b,
-0x50400001, 0x872021, 0x94820000, 0x24840002,
-0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02,
-0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff,
-0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88,
-0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068,
-0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058,
-0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c,
-0x8ee204d4, 0x8021, 0x30420001, 0x1440002a,
-0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8,
-0xe22023, 0x2c821000, 0x50400001, 0x24841000,
-0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8,
-0x3c02000a, 0x3442efff, 0x1032023, 0x44102b,
-0x10400003, 0x3c02000a, 0x3442f000, 0x822021,
-0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4,
-0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021,
-0x904283c0, 0x1040000b, 0x0, 0x3c140001,
-0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821,
-0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193,
-0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007,
-0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
-0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
-0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
-0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0,
-0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
-0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
-0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
-0x2409821, 0x3c020080, 0x621024, 0x1040000a,
-0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c,
-0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc,
-0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001,
-0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080,
-0x3c080020, 0x34078000, 0x24420001, 0xaee20080,
-0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021,
-0xc3102b, 0x14400007, 0x0, 0x106b0011,
-0x0, 0x106a0015, 0x0, 0x8003049,
-0x42042, 0x10650023, 0xa3102b, 0x14400005,
-0x0, 0x10690019, 0x0, 0x8003049,
-0x42042, 0x10680021, 0x0, 0x8003049,
-0x42042, 0x8ee20034, 0x24420001, 0xaee20034,
-0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec,
-0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049,
-0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0,
-0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4,
-0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049,
-0x42042, 0x8ee20030, 0x24420001, 0xaee20030,
-0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8,
-0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042,
-0x1087047c, 0x0, 0x800300e, 0x0,
-0x3c020001, 0x571021, 0x904283b2, 0x14400084,
-0x24020001, 0x3c030001, 0x771821, 0x906383b3,
-0x1462007f, 0x3c020100, 0x8e430000, 0x621024,
-0x1040006f, 0x2402ffff, 0x14620005, 0x24100001,
-0x96430004, 0x3402ffff, 0x10620075, 0x0,
-0x92e204d8, 0x14400072, 0x0, 0x3c020001,
-0x571021, 0x8c4283b4, 0x28420005, 0x10400020,
-0x3821, 0x3c020001, 0x571021, 0x8c4283b4,
-0x18400016, 0x2821, 0x96660000, 0x520c0,
-0x971021, 0x9442777e, 0x14460009, 0x971021,
-0x94437780, 0x96620002, 0x14620005, 0x971021,
-0x94437782, 0x96620004, 0x50620008, 0x24070001,
-0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001,
-0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff,
-0x10400440, 0x0, 0x80030d5, 0x0,
-0x2402021, 0xc0022fe, 0x24050006, 0x3044001f,
-0x428c0, 0x2e51021, 0x9442727c, 0x30424000,
-0x14400434, 0xb71021, 0x9443727e, 0x96620000,
-0x1462000b, 0x418c0, 0xb71021, 0x94437280,
-0x96620002, 0x14620006, 0x418c0, 0xb71021,
-0x94437282, 0x96620004, 0x10620035, 0x418c0,
-0x2e31021, 0x9442727c, 0x30428000, 0x14400421,
-0x2e31021, 0x944b727c, 0x96670000, 0xb28c0,
-0xb71021, 0x9442737e, 0x80030b7, 0x3021,
-0x420c0, 0x2e41021, 0x9443737c, 0x2e41021,
-0x944b737c, 0x30638000, 0x14600010, 0xb28c0,
-0xb71021, 0x9442737e, 0x1447fff5, 0x1602021,
-0xb71021, 0x94437380, 0x96620002, 0x5462fff1,
-0x420c0, 0xb71021, 0x94437382, 0x96620004,
-0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff,
-0x10400400, 0x0, 0x80030d5, 0x0,
-0x97430202, 0x96420000, 0x146203fa, 0x0,
-0x97430204, 0x96420002, 0x146203f6, 0x0,
-0x97430206, 0x96420004, 0x146203f2, 0x0,
-0x92420000, 0x3a030001, 0x30420001, 0x431024,
-0x10400074, 0x2402ffff, 0x8e630000, 0x14620004,
-0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002,
-0x3c020001, 0x571021, 0x904283b2, 0x1440006a,
-0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c,
-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
-0x10400020, 0x3821, 0x3c020001, 0x571021,
-0x8c4283b4, 0x18400016, 0x2821, 0x96660000,
-0x520c0, 0x971021, 0x9442777e, 0x14460009,
-0x971021, 0x94437780, 0x96620002, 0x14620005,
-0x971021, 0x94437782, 0x96620004, 0x50620008,
-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
-0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6,
-0x0, 0x2402021, 0xc0022fe, 0x24050006,
-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
-0x30424000, 0x144003af, 0xb71021, 0x9443727e,
-0x96620000, 0x1462000b, 0x418c0, 0xb71021,
-0x94437280, 0x96620002, 0x14620006, 0x418c0,
-0xb71021, 0x94437282, 0x96620004, 0x10620027,
-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
-0x1440039c, 0x2e31021, 0x944b727c, 0x96670000,
-0xb28c0, 0xb71021, 0x9442737e, 0x800313c,
-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
-0x2e41021, 0x944b737c, 0x30638000, 0x14600010,
-0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5,
-0x1602021, 0xb71021, 0x94437380, 0x96620002,
-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
-0x96620004, 0x5462ffec, 0x420c0, 0x24060001,
-0x30c200ff, 0x1040037b, 0x0, 0x800314f,
-0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260,
-0x54102b, 0x1040003a, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
-0xc002403, 0x34a5f003, 0x80034cc, 0x0,
-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
-0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
-0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
-0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
-0x96e20468, 0x54102b, 0x10400003, 0x0,
-0x240f0001, 0xa3af0027, 0x12800301, 0x24160007,
-0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c,
-0x8f430280, 0x24420001, 0x304207ff, 0x106202d3,
-0x0, 0x93a20027, 0x10400014, 0x0,
-0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244,
-0x8ee65244, 0x8ee35244, 0x21140, 0x24425248,
-0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff,
-0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0,
-0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
-0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18,
-0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021,
-0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010,
-0x10400019, 0x0, 0x9642000c, 0x340f8100,
-0x144f0015, 0x0, 0x3c020001, 0x571021,
-0x904283c0, 0x14400010, 0x0, 0x9642000e,
-0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000,
-0x2694fffc, 0xae42000c, 0xae430008, 0xae440004,
-0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037,
-0x34420200, 0xa602000e, 0x8e020000, 0x8e030004,
-0x3c040001, 0x34843800, 0x306a0007, 0x26a9823,
-0x3641021, 0x262102b, 0x10400005, 0x28aa021,
-0x2641023, 0x3621823, 0x3c020020, 0x439823,
-0x26820007, 0x2404fff8, 0x9603000a, 0x446024,
-0x6a1821, 0x6c102b, 0x10400002, 0x1803821,
-0x603821, 0xae130018, 0x8f880120, 0x24e20007,
-0x443824, 0x27623800, 0x25090020, 0x122102b,
-0x50400001, 0x27693000, 0x8f820128, 0x11220004,
-0x0, 0x8f820124, 0x15220007, 0x1401821,
-0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
-0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004,
-0x1021, 0xad130008, 0xa507000e, 0xad160018,
-0xad06001c, 0xa3302b, 0xa32823, 0x822023,
-0x862023, 0xad040000, 0xad050004, 0x8ee204c0,
-0xad020010, 0xaf890120, 0x92e24e20, 0x14400033,
-0x24110001, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c820000, 0x1456001f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x10550007, 0x0,
-0x8ee24e34, 0x24420001, 0x10620005, 0x0,
-0x8003239, 0x0, 0x14600005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
-0x800324c, 0x0, 0x8ee24e30, 0x24420001,
-0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
-0x3c050006, 0x8e020018, 0x3c040001, 0x24845890,
-0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
-0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
-0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
-0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004,
-0xae440008, 0x96020016, 0x8003470, 0xa642000e,
-0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e,
-0x28a1023, 0xa602000a, 0x34620004, 0xa602000e,
-0x8f880120, 0x27623800, 0x25090020, 0x122102b,
-0x14400002, 0x306affff, 0x27693000, 0x8f820128,
-0x11220004, 0x0, 0x8f820124, 0x15220007,
-0x24040020, 0x8ee201a4, 0x8821, 0x24420001,
-0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c,
-0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004,
-0xad100008, 0xad040018, 0x52940, 0xa01821,
-0x1021, 0xe33821, 0xe3202b, 0xc23021,
-0xc43021, 0xad060000, 0xad070004, 0x8ee2724c,
-0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
-0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
-0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x0, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
-0x10550007, 0x0, 0x8ee24e34, 0x24420001,
-0x10620005, 0x0, 0x80032b7, 0x0,
-0x14600005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400010, 0xac800000, 0x80032ca, 0x0,
-0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0xac960000,
-0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
-0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
-0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
-0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
-0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
-0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
-0x24630001, 0x306307ff, 0x26e25244, 0x15a20006,
-0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
-0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
-0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073,
-0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
-0x8f430240, 0x43102b, 0x14400176, 0xa021,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
-0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
-0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400033, 0x24110001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x144e001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10550007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x800333c,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x800334f,
-0x0, 0x8ee24e30, 0x24420001, 0x50550003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
-0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014,
-0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
-0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
-0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
-0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120,
-0x27623800, 0x24660020, 0xc2102b, 0x50400001,
-0x27663000, 0x8f820128, 0x10c20004, 0x0,
-0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
-0x8821, 0x24420001, 0xaee201a4, 0x80033ba,
-0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8,
-0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008,
-0xa462000e, 0x24020011, 0xac620018, 0xac640000,
-0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
-0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34,
-0x1062001b, 0x0, 0x8c820004, 0x24420001,
-0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
-0x10550007, 0x0, 0x8ee24e34, 0x24420001,
-0x10620005, 0x0, 0x80033a7, 0x0,
-0x14600005, 0x0, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
-0x50400010, 0xac800000, 0x80033ba, 0x0,
-0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
-0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
-0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
-0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
-0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
-0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
-0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
-0xa021, 0x960c000a, 0x183102b, 0x54400001,
-0x1801821, 0xa603000a, 0x8f880120, 0x27623800,
-0x25090020, 0x122102b, 0x50400001, 0x27693000,
-0x8f820128, 0x11220004, 0x0, 0x8f820124,
-0x15220007, 0x24040020, 0x8ee201a4, 0x8821,
-0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4,
-0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e,
-0x24040004, 0xad100008, 0xad040018, 0x52940,
-0xa01821, 0x1021, 0xe33821, 0xe3202b,
-0xc23021, 0xc43021, 0xad060000, 0xad070004,
-0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010,
-0xaf890120, 0x92e24e20, 0x14400033, 0x24110001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x1456001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10550007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x800341c,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400010, 0xac800000, 0x800342f,
-0x0, 0x8ee24e30, 0x24420001, 0x50550003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0xac960000, 0xac9e0004, 0x1620001d, 0x0,
-0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
-0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
-0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
-0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
-0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
-0xae430004, 0xae440008, 0x96020016, 0xa642000e,
-0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e,
-0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
-0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821,
-0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a,
-0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821,
-0x93202b, 0x10800003, 0x3c02fff5, 0x34421000,
-0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001,
-0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004,
-0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
-0xa3a00027, 0x1680fd29, 0x0, 0x12800024,
-0x0, 0x3c010001, 0x370821, 0xac3483c4,
-0x3c010001, 0x370821, 0xac3383c8, 0x3c010001,
-0x370821, 0xac3283cc, 0x93a20037, 0x10400008,
-0x0, 0x3c020001, 0x571021, 0x8c4283cc,
-0x24420004, 0x3c010001, 0x370821, 0xac2283cc,
-0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff,
-0x14620006, 0x0, 0x8ee201c4, 0x24420001,
-0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc,
-0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc,
-0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
-0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xaee400c0, 0xaee500c4,
-0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003,
-0x14400017, 0x24020003, 0x15e20015, 0x0,
-0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
-0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
-0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
-0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
-0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc,
-0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
-0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
-0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
-0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070,
-0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060,
-0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050,
-0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044,
-0xa821, 0xafb00030, 0x8021, 0xafbf004c,
-0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038,
-0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001,
-0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4,
-0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
-0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
-0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
-0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
-0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
-0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
-0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001,
-0x571021, 0x904283c0, 0x1040000b, 0x0,
-0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001,
-0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021,
-0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
-0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
-0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
-0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
-0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014,
-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
-0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
-0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
-0x10400058, 0x2408821, 0x3c020080, 0x621024,
-0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
-0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
-0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004,
-0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
-0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
-0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
-0x10660021, 0xc3102b, 0x14400007, 0x0,
-0x106b0011, 0x0, 0x106a0015, 0x0,
-0x8003592, 0x42042, 0x10650023, 0xa3102b,
-0x14400005, 0x0, 0x10690019, 0x0,
-0x8003592, 0x42042, 0x10680021, 0x0,
-0x8003592, 0x42042, 0x8ee20034, 0x24420001,
-0xaee20034, 0x8ee20034, 0x8003592, 0x42042,
-0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
-0x8003592, 0x42042, 0x8ee201f0, 0x24420001,
-0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042,
-0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
-0x8003592, 0x42042, 0x8ee20030, 0x24420001,
-0xaee20030, 0x8ee20030, 0x8003592, 0x42042,
-0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
-0x42042, 0x108702b7, 0x0, 0x8003557,
-0x0, 0x3c020001, 0x571021, 0x904283b2,
-0x14400084, 0x24020001, 0x3c030001, 0x771821,
-0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
-0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
-0x24100001, 0x96430004, 0x3402ffff, 0x10620075,
-0x0, 0x92e204d8, 0x14400072, 0x0,
-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
-0x10400020, 0x3821, 0x3c020001, 0x571021,
-0x8c4283b4, 0x18400016, 0x2821, 0x96260000,
-0x520c0, 0x971021, 0x9442777e, 0x14460009,
-0x971021, 0x94437780, 0x96220002, 0x14620005,
-0x971021, 0x94437782, 0x96220004, 0x50620008,
-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
-0x30e200ff, 0x1040027b, 0x0, 0x800361e,
-0x0, 0x2402021, 0xc0022fe, 0x24050006,
-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
-0x30424000, 0x1440026f, 0xb71021, 0x9443727e,
-0x96220000, 0x1462000b, 0x418c0, 0xb71021,
-0x94437280, 0x96220002, 0x14620006, 0x418c0,
-0xb71021, 0x94437282, 0x96220004, 0x10620035,
-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
-0x1440025c, 0x2e31021, 0x9448727c, 0x96270000,
-0x828c0, 0xb71021, 0x9442737e, 0x8003600,
-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
-0x2e41021, 0x9448737c, 0x30638000, 0x14600010,
-0x828c0, 0xb71021, 0x9442737e, 0x1447fff5,
-0x1002021, 0xb71021, 0x94437380, 0x96220002,
-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
-0x96220004, 0x5462ffec, 0x420c0, 0x24060001,
-0x30c200ff, 0x1040023b, 0x0, 0x800361e,
-0x0, 0x97430202, 0x96420000, 0x14620235,
-0x0, 0x97430204, 0x96420002, 0x14620231,
-0x0, 0x97430206, 0x96420004, 0x1462022d,
-0x0, 0x92420000, 0x3a030001, 0x30420001,
-0x431024, 0x10400074, 0x2402ffff, 0x8e230000,
-0x14620004, 0x3402ffff, 0x96230004, 0x1062006f,
-0x24140002, 0x3c020001, 0x571021, 0x904283b2,
-0x1440006a, 0x24140003, 0x92e204d8, 0x14400067,
-0x0, 0x3c020001, 0x571021, 0x8c4283b4,
-0x28420005, 0x10400020, 0x3821, 0x3c020001,
-0x571021, 0x8c4283b4, 0x18400016, 0x2821,
-0x96260000, 0x520c0, 0x971021, 0x9442777e,
-0x14460009, 0x971021, 0x94437780, 0x96220002,
-0x14620005, 0x971021, 0x94437782, 0x96220004,
-0x50620008, 0x24070001, 0x3c020001, 0x571021,
-0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
-0x520c0, 0x30e200ff, 0x14400044, 0x24140003,
-0x800384a, 0x0, 0x2402021, 0xc0022fe,
-0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
-0x9442727c, 0x30424000, 0x144001ea, 0xb71021,
-0x9443727e, 0x96220000, 0x1462000b, 0x418c0,
-0xb71021, 0x94437280, 0x96220002, 0x14620006,
-0x418c0, 0xb71021, 0x94437282, 0x96220004,
-0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
-0x30428000, 0x144001d7, 0x2e31021, 0x9448727c,
-0x96270000, 0x828c0, 0xb71021, 0x9442737e,
-0x8003685, 0x3021, 0x420c0, 0x2e41021,
-0x9443737c, 0x2e41021, 0x9448737c, 0x30638000,
-0x14600010, 0x828c0, 0xb71021, 0x9442737e,
-0x1447fff5, 0x1002021, 0xb71021, 0x94437380,
-0x96220002, 0x5462fff1, 0x420c0, 0xb71021,
-0x94437382, 0x96220004, 0x5462ffec, 0x420c0,
-0x24060001, 0x30c200ff, 0x104001b6, 0x0,
-0x8003698, 0x24140003, 0x24140001, 0x8f420260,
-0x53102b, 0x10400049, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
-0xc002403, 0x34a5f003, 0x8003850, 0x0,
-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
-0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
-0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
-0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
-0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884,
-0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
-0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
-0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
-0x53102b, 0x54400001, 0x3c158000, 0x12600131,
-0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280,
-0x24420001, 0x304207ff, 0x10620108, 0x0,
-0x12a00014, 0x0, 0x8ee35240, 0x8ee25244,
-0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244,
-0x21140, 0x24425248, 0x2e28021, 0x24630001,
-0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0,
-0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0,
-0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb,
-0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18,
-0x21140, 0x24420e20, 0x2e28021, 0x24630001,
-0x306801ff, 0x96e2046a, 0x30420010, 0x10400017,
-0x34028100, 0x9643000c, 0x14620014, 0x0,
-0x3c020001, 0x571021, 0x904283c0, 0x1440000f,
-0x0, 0x9642000e, 0xa6020016, 0x8e420008,
-0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c,
-0xae430008, 0xae440004, 0x9602000e, 0x26310004,
-0x24160001, 0x34420200, 0xa602000e, 0x9603000a,
-0x2605021, 0x73102b, 0x10400002, 0x2606821,
-0x605021, 0x2d42003d, 0x1040002a, 0x3821,
-0x9623000c, 0x24020800, 0x54620027, 0xae110018,
-0x3c020001, 0x571021, 0x904283c0, 0x54400022,
-0xae110018, 0x26220017, 0x182102b, 0x10400013,
-0x0, 0x3c02fff5, 0x511021, 0x90421017,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x10600013, 0x26220010, 0x182102b,
-0x1040000e, 0x0, 0x3c07fff5, 0xf13821,
-0x94e71010, 0x800375e, 0x24e7000e, 0x92220017,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x50600004, 0xae110018, 0x96270010,
-0x24e7000e, 0xae110018, 0x3c020001, 0x571021,
-0x904283c0, 0x2102b, 0x14e00002, 0x24ec0,
-0x1403821, 0x8f830120, 0x27623800, 0x24660020,
-0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
-0x10c20004, 0x0, 0x8f820124, 0x14c20007,
-0x2402000b, 0x8ee201a4, 0x4821, 0x24420001,
-0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000,
-0x8e050004, 0xac620018, 0x1751025, 0x491025,
-0xac710008, 0xa467000e, 0xac62001c, 0xac640000,
-0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120,
-0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x14620020, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001c, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30,
-0x24020040, 0x24630001, 0x10620007, 0x0,
-0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
-0x80037a9, 0x0, 0x14a00005, 0x0,
-0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
-0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
-0x80037bf, 0x0, 0x8ee24e30, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
-0x24020001, 0xac820004, 0x15200018, 0x3c050006,
-0x8e020018, 0x3c040001, 0x24845890, 0xafa20010,
-0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
-0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
-0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
-0xa642000c, 0xae430000, 0xae440004, 0xae450008,
-0x96020016, 0x80037f8, 0xa642000e, 0x154d000a,
-0x0, 0x9602000e, 0xa613000a, 0x34420004,
-0xa602000e, 0x3c010001, 0x370821, 0xa02083c0,
-0x80037f6, 0x9821, 0x9604000a, 0x93102b,
-0x10400002, 0x2601821, 0x801821, 0x24020001,
-0xa603000a, 0x3c010001, 0x370821, 0xa02283c0,
-0x9604000a, 0x2248821, 0x191102b, 0x10400003,
-0x3c02fff5, 0x34421000, 0x2228821, 0x2649823,
-0xa821, 0x1660fef4, 0xadc80000, 0x12600021,
-0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4,
-0x3c010001, 0x370821, 0xac3183c8, 0x3c010001,
-0x370821, 0x10400008, 0xac3283cc, 0x3c020001,
-0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
-0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280,
-0x24420001, 0x14620006, 0x0, 0x8ee201c4,
-0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4,
-0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850,
-0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821,
-0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0x24020002,
-0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003,
-0x14400017, 0x24020003, 0x16820015, 0x0,
-0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
-0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
-0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
-0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
-0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc,
-0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
-0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
-0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
-0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c,
-0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021,
-0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058,
-0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
-0x8ee204d4, 0x8821, 0x24150001, 0x30420001,
-0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4,
-0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
-0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
-0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
-0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
-0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
-0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
-0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001,
-0x571021, 0x904283c0, 0x1040000b, 0x0,
-0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001,
-0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021,
-0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
-0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
-0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
-0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
-0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014,
-0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
-0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
-0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
-0x10400058, 0x2408021, 0x3c020080, 0x621024,
-0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
-0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
-0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004,
-0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
-0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
-0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
-0x10660021, 0xc3102b, 0x14400007, 0x0,
-0x106b0011, 0x0, 0x106a0015, 0x0,
-0x8003916, 0x42042, 0x10650023, 0xa3102b,
-0x14400005, 0x0, 0x10690019, 0x0,
-0x8003916, 0x42042, 0x10680021, 0x0,
-0x8003916, 0x42042, 0x8ee20034, 0x24420001,
-0xaee20034, 0x8ee20034, 0x8003916, 0x42042,
-0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
-0x8003916, 0x42042, 0x8ee201f0, 0x24420001,
-0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042,
-0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
-0x8003916, 0x42042, 0x8ee20030, 0x24420001,
-0xaee20030, 0x8ee20030, 0x8003916, 0x42042,
-0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
-0x42042, 0x1087033e, 0x0, 0x80038db,
-0x0, 0x3c020001, 0x571021, 0x904283b2,
-0x14400084, 0x24020001, 0x3c030001, 0x771821,
-0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
-0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
-0x24110001, 0x96430004, 0x3402ffff, 0x10620075,
-0x0, 0x92e204d8, 0x14400072, 0x0,
-0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
-0x10400020, 0x3821, 0x3c020001, 0x571021,
-0x8c4283b4, 0x18400016, 0x2821, 0x96060000,
-0x520c0, 0x971021, 0x9442777e, 0x14460009,
-0x971021, 0x94437780, 0x96020002, 0x14620005,
-0x971021, 0x94437782, 0x96020004, 0x50620008,
-0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
-0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
-0x30e200ff, 0x10400302, 0x0, 0x80039a2,
-0x0, 0x2402021, 0xc0022fe, 0x24050006,
-0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
-0x30424000, 0x144002f6, 0xb71021, 0x9443727e,
-0x96020000, 0x1462000b, 0x418c0, 0xb71021,
-0x94437280, 0x96020002, 0x14620006, 0x418c0,
-0xb71021, 0x94437282, 0x96020004, 0x10620035,
-0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
-0x144002e3, 0x2e31021, 0x944d727c, 0x96070000,
-0xd28c0, 0xb71021, 0x9442737e, 0x8003984,
-0x3021, 0x420c0, 0x2e41021, 0x9443737c,
-0x2e41021, 0x944d737c, 0x30638000, 0x14600010,
-0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5,
-0x1a02021, 0xb71021, 0x94437380, 0x96020002,
-0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
-0x96020004, 0x5462ffec, 0x420c0, 0x24060001,
-0x30c200ff, 0x104002c2, 0x0, 0x80039a2,
-0x0, 0x97430202, 0x96420000, 0x146202bc,
-0x0, 0x97430204, 0x96420002, 0x146202b8,
-0x0, 0x97430206, 0x96420004, 0x146202b4,
-0x0, 0x92420000, 0x3a230001, 0x30420001,
-0x431024, 0x10400074, 0x2402ffff, 0x8e030000,
-0x14620004, 0x3402ffff, 0x96030004, 0x1062006f,
-0x24150002, 0x3c020001, 0x571021, 0x904283b2,
-0x1440006a, 0x24150003, 0x92e204d8, 0x14400067,
-0x0, 0x3c020001, 0x571021, 0x8c4283b4,
-0x28420005, 0x10400020, 0x3821, 0x3c020001,
-0x571021, 0x8c4283b4, 0x18400016, 0x2821,
-0x96060000, 0x520c0, 0x971021, 0x9442777e,
-0x14460009, 0x971021, 0x94437780, 0x96020002,
-0x14620005, 0x971021, 0x94437782, 0x96020004,
-0x50620008, 0x24070001, 0x3c020001, 0x571021,
-0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
-0x520c0, 0x30e200ff, 0x14400044, 0x24150003,
-0x8003c55, 0x0, 0x2402021, 0xc0022fe,
-0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
-0x9442727c, 0x30424000, 0x14400271, 0xb71021,
-0x9443727e, 0x96020000, 0x1462000b, 0x418c0,
-0xb71021, 0x94437280, 0x96020002, 0x14620006,
-0x418c0, 0xb71021, 0x94437282, 0x96020004,
-0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
-0x30428000, 0x1440025e, 0x2e31021, 0x944d727c,
-0x96070000, 0xd28c0, 0xb71021, 0x9442737e,
-0x8003a09, 0x3021, 0x420c0, 0x2e41021,
-0x9443737c, 0x2e41021, 0x944d737c, 0x30638000,
-0x14600010, 0xd28c0, 0xb71021, 0x9442737e,
-0x1447fff5, 0x1a02021, 0xb71021, 0x94437380,
-0x96020002, 0x5462fff1, 0x420c0, 0xb71021,
-0x94437382, 0x96020004, 0x5462ffec, 0x420c0,
-0x24060001, 0x30c200ff, 0x1040023d, 0x0,
-0x8003a1c, 0x24150003, 0x24150001, 0x8f420260,
-0x53102b, 0x10400036, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
-0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
-0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
-0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0,
-0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
-0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
-0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
-0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
-0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
-0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
-0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
-0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5,
-0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280,
-0x24420001, 0x304207ff, 0x1062019e, 0x0,
-0x12c00012, 0x0, 0x8ee35240, 0x8ee25244,
-0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024,
-0x8ee35244, 0x21140, 0x24425248, 0x2e28821,
-0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0,
-0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
-0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18,
-0xb021, 0xafb80024, 0x8ee30e18, 0x21140,
-0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff,
-0x96e2046a, 0x30420010, 0x10400018, 0x34028100,
-0x9643000c, 0x14620015, 0x0, 0x3c020001,
-0x571021, 0x904283c0, 0x14400010, 0x0,
-0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004,
-0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008,
-0xae440004, 0x9622000e, 0x26100004, 0x24180001,
-0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000,
-0x8e230004, 0x3c040001, 0x34843800, 0x2003021,
-0x306a0007, 0x20a8023, 0x3641021, 0x202102b,
-0x10400005, 0x26a9821, 0x2041023, 0x3621823,
-0x3c020020, 0x438023, 0x26620007, 0x9623000a,
-0x2418fff8, 0x58c824, 0x6a1821, 0x79102b,
-0x10400002, 0x3206021, 0x606021, 0x1801821,
-0x24620007, 0x2418fff8, 0x586024, 0x26c102b,
-0x14400004, 0x1932823, 0x1832823, 0x8003ac3,
-0xc31021, 0xd31021, 0x4a2023, 0x1c4102b,
-0x54400001, 0x8f2021, 0x25420040, 0x4c102b,
-0x14400035, 0x5821, 0x94c3000c, 0x24020800,
-0x54620032, 0xae260018, 0x3c020001, 0x571021,
-0x904283c0, 0x5440002d, 0xae260018, 0x24c20017,
-0x1c2102b, 0x10400013, 0x0, 0x3c02fff5,
-0x461021, 0x90421017, 0x38430006, 0x2c630001,
-0x38420011, 0x2c420001, 0x621825, 0x10600014,
-0x24c20010, 0x1c2102b, 0x1040000e, 0x0,
-0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4,
-0x2562000e, 0x90c20017, 0x38430006, 0x2c630001,
-0x38420011, 0x2c420001, 0x621825, 0x10600005,
-0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821,
-0x1601821, 0x24620007, 0x2418fff8, 0x585824,
-0xc31021, 0x4a2023, 0x1c4102b, 0x10400002,
-0x1632823, 0x8f2021, 0xae260018, 0x3c020001,
-0x571021, 0x904283c0, 0x2102b, 0x216c0,
-0x15600002, 0xafa20044, 0x1805821, 0x30820001,
-0x10400007, 0x4021, 0x90880000, 0x24840001,
-0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021,
-0x50a00012, 0x81c02, 0x2ca20002, 0x54400009,
-0x24a5ffff, 0x94820000, 0x24840002, 0x1024021,
-0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21,
-0x8f2021, 0x90820000, 0x21200, 0x1024021,
-0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff,
-0x624021, 0x3108ffff, 0x1402821, 0x11400011,
-0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff,
-0x94820000, 0x24840002, 0x1024021, 0x1c4102b,
-0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021,
-0x90820000, 0x21200, 0x1024021, 0x14a0fff2,
-0x2ca20002, 0x81c02, 0x3102ffff, 0x624021,
-0x81c02, 0x3102ffff, 0x8f890120, 0x624021,
-0x27623800, 0x25230020, 0x62102b, 0x14400002,
-0x3108ffff, 0x27633000, 0x8f820128, 0x10620004,
-0x0, 0x8f820124, 0x14620007, 0x1402821,
-0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4,
-0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004,
-0x81400, 0x3448000b, 0xad300008, 0xa52b000e,
-0xad280018, 0x8fb80044, 0x2021, 0x2961025,
-0x581025, 0xad22001c, 0xe5102b, 0xe53823,
-0xc43023, 0xc23023, 0xad260000, 0xad270004,
-0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20,
-0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002,
-0x14400003, 0x24020011, 0x15020024, 0x0,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c830000, 0x24020012, 0x1462000f, 0x0,
-0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0,
-0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
-0x8ee34e30, 0x24420001, 0x105e002a, 0x0,
-0x8003ba8, 0x0, 0x8ee24e30, 0x24420001,
-0x505e0003, 0x1021, 0x8ee24e30, 0x24420001,
-0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30,
-0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
-0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x105e0007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8003bb4,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400012, 0xac800000, 0x8003bc9,
-0x0, 0x8ee24e30, 0x24420001, 0x505e0003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020007, 0xac820000, 0x24020001, 0xac820004,
-0x14e00019, 0x3c050006, 0x3c040001, 0x24845890,
-0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
-0x8e230004, 0x2203021, 0x1603821, 0xc002403,
-0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
-0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c,
-0xae430000, 0xae440004, 0xae450008, 0x96220016,
-0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823,
-0x9622000e, 0xa623000a, 0x34420004, 0xa622000e,
-0x3c010001, 0x370821, 0xa02083c0, 0x8003bff,
-0x9821, 0x9624000a, 0x83102b, 0x54400001,
-0x801821, 0x24020001, 0xa623000a, 0x3c010001,
-0x370821, 0xa02283c0, 0x9622000a, 0x4a1821,
-0x2038021, 0x1d0102b, 0x54400001, 0x20f8021,
-0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e,
-0xaf0d0000, 0x12600022, 0x0, 0x3c010001,
-0x370821, 0xac3383c4, 0x3c010001, 0x370821,
-0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc,
-0x93a2002f, 0x10400008, 0x0, 0x3c020001,
-0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
-0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c,
-0x14620006, 0x0, 0x8ee201c4, 0x24420001,
-0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc,
-0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc,
-0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
-0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0x24020002, 0xaee400c0,
-0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017,
-0x24020003, 0x16a20015, 0x0, 0x8ee200d0,
-0x8ee300d4, 0x24630001, 0x2c640001, 0x441021,
-0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55,
-0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001,
-0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc,
-0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8,
-0x8ee300cc, 0x24630001, 0x2c640001, 0x441021,
-0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc,
-0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008,
-0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064,
-0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054,
-0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
-0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14,
-0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c,
-0x8ee20e14, 0x622023, 0x4820001, 0x24840200,
-0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004,
-0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823,
-0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff,
-0x804821, 0x69102a, 0x54400001, 0x604821,
-0x8f870100, 0x27623000, 0x24e80020, 0x102102b,
-0x50400001, 0x27682800, 0x8f820108, 0x11020004,
-0x0, 0x8f820104, 0x15020007, 0x1021,
-0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8,
-0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140,
-0x801821, 0x8ee40460, 0x8ee50464, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xace40000,
-0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e,
-0x24020002, 0xace20018, 0x31940, 0x24630e20,
-0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c,
-0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec,
-0x14400011, 0x24040001, 0x8ee24e28, 0x24030040,
-0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
-0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
-0x24424e38, 0x2e21821, 0x24020002, 0xac620000,
-0x24020001, 0xac620004, 0x1480000e, 0x24030040,
-0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
-0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
-0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd,
-0x0, 0x8ee20500, 0x24420001, 0x50430003,
-0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
-0x8ee20500, 0x21080, 0x571021, 0xac490508,
-0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14,
-0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0,
-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
-0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074,
-0x0, 0x8ee35238, 0x8ee2523c, 0x622023,
-0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c,
-0x43102b, 0x14400004, 0x24020100, 0x8ee3523c,
-0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c,
-0x431023, 0x2443ffff, 0x804821, 0x69102a,
-0x54400001, 0x604821, 0x8f870100, 0x27623000,
-0x24e80020, 0x102102b, 0x50400001, 0x27682800,
-0x8f820108, 0x11020004, 0x0, 0x8f820104,
-0x15020007, 0x1021, 0x8ee201a8, 0x2021,
-0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8,
-0x8ee4523c, 0x42140, 0x801821, 0x8ee40470,
-0x8ee50474, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xace40000, 0xace50004, 0x8ee3523c,
-0x91140, 0xa4e2000e, 0x24020003, 0xace20018,
-0x31940, 0x24635248, 0x2e31021, 0xace20008,
-0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010,
-0xaf880100, 0x92e204ec, 0x14400011, 0x24040001,
-0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
-0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
-0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821,
-0x24020003, 0xac620000, 0x24020001, 0xac620004,
-0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
-0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
-0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403,
-0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
-0x24420001, 0x50430003, 0x1021, 0x8ee20500,
-0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
-0x571021, 0xac490508, 0x8ee2523c, 0x491021,
-0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238,
-0x14620005, 0x0, 0x8f820060, 0x2403feff,
-0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124,
-0x8f860128, 0x24020040, 0x24630001, 0x50620003,
-0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34,
-0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0,
-0x24425038, 0x14830007, 0x2e22821, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8003d92,
-0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001,
-0x50430003, 0x1021, 0x8ee24e34, 0x24420001,
-0x210c0, 0x24425038, 0x2e22821, 0x8ca20004,
-0x8f830128, 0x21140, 0x621821, 0xaf830128,
-0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
-0x10400008, 0x31080, 0x3c010001, 0x220821,
-0x8c2258f0, 0x400008, 0x0, 0x24020001,
-0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
-0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
-0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
-0x8f820124, 0x106202b0, 0x9821, 0x3c11001f,
-0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012,
-0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
-0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
-0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
-0x220821, 0x8c225948, 0x400008, 0x0,
-0x8f420218, 0x30420100, 0x10400007, 0x0,
-0x95830016, 0x95820018, 0x621823, 0x31402,
-0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
-0x3044ffff, 0x436824, 0x3c030800, 0x431824,
-0x11a00004, 0xad84001c, 0x41140, 0x8003dd8,
-0x24425248, 0x41140, 0x24420e20, 0x2e25821,
-0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e,
-0x95840016, 0x8003ec0, 0x0, 0x8d690018,
-0x4021, 0x952a0000, 0x25290002, 0x95270000,
-0x25290002, 0x95260000, 0x25290002, 0x95250000,
-0x25290002, 0x95240000, 0x25290002, 0x95230000,
-0x25290002, 0x95220000, 0x25290002, 0x1475021,
-0x1465021, 0x1455021, 0x1445021, 0x1435021,
-0x1425021, 0xa1c02, 0x3142ffff, 0x625021,
-0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a,
-0x314effff, 0x30420002, 0x10400044, 0x5021,
-0x25220014, 0x222102b, 0x10400014, 0x1201821,
-0x2405000a, 0x2021, 0x223102b, 0x54400001,
-0x721821, 0x94620000, 0x24630002, 0x24a5ffff,
-0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff,
-0x622021, 0x41402, 0x3083ffff, 0x431021,
-0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000,
-0x25290002, 0x95280000, 0x25290002, 0x95270000,
-0x25290002, 0x95260000, 0x25290002, 0x95250000,
-0x25290002, 0x95230000, 0x25290002, 0x95220000,
-0x25290002, 0x95240000, 0x25290002, 0x1485021,
-0x1475021, 0x1465021, 0x1455021, 0x1435021,
-0x1425021, 0x95220000, 0x95230002, 0x1445021,
-0x1425021, 0x1435021, 0xa1c02, 0x3142ffff,
-0x625021, 0xa1c02, 0x3142ffff, 0x625021,
-0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018,
-0x9443000c, 0x24020800, 0x54620005, 0xa5680010,
-0x9562000e, 0x34420002, 0xa562000e, 0xa5680010,
-0x96e2046a, 0x2821, 0x30420008, 0x14400056,
-0x3021, 0x8d630018, 0x24620024, 0x222102b,
-0x10400034, 0x24690010, 0x229102b, 0x54400001,
-0x1324821, 0x95250000, 0x24690014, 0x229102b,
-0x10400002, 0x24a5ffec, 0x1324821, 0x95220000,
-0x30420fff, 0x14400003, 0x25290002, 0x8003e60,
-0x24130001, 0x9821, 0xa03021, 0x229102b,
-0x54400001, 0x1324821, 0x91220001, 0x25290002,
-0xa22821, 0x229102b, 0x54400001, 0x1324821,
-0x25290002, 0x229102b, 0x54400001, 0x1324821,
-0x95220000, 0x25290002, 0xa22821, 0x229102b,
-0x54400001, 0x1324821, 0x95220000, 0x25290002,
-0xa22821, 0x229102b, 0x54400001, 0x1324821,
-0x95220000, 0x25290002, 0xa22821, 0x229102b,
-0x54400001, 0x1324821, 0x95220000, 0x8003e99,
-0xa22821, 0x94650010, 0x94620014, 0x24690016,
-0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c,
-0x24130001, 0x9821, 0xa03021, 0x91230001,
-0x25290004, 0x95220000, 0x25290002, 0x95240000,
-0x25290002, 0xa32821, 0xa22821, 0x95220000,
-0x95230002, 0xa42821, 0xa22821, 0xa32821,
-0x51c02, 0x30a2ffff, 0x622821, 0x51c02,
-0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001,
-0x1040001e, 0x2021, 0x95820016, 0x4e2023,
-0x41402, 0x822021, 0x326200ff, 0x50400002,
-0x862021, 0x852021, 0x41402, 0x822021,
-0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018,
-0x24430017, 0x223102b, 0x54400001, 0x721821,
-0x90620000, 0x38430011, 0x2c630001, 0x38420006,
-0x2c420001, 0x621825, 0x10600004, 0x0,
-0x9562000e, 0x34420001, 0xa562000e, 0x9562000e,
-0x240a0002, 0x30420004, 0x10400002, 0xa5640012,
-0x240a0004, 0x8f880120, 0x27623800, 0x25090020,
-0x122102b, 0x50400001, 0x27693000, 0x8f820128,
-0x11220004, 0x0, 0x8f820124, 0x15220007,
-0x24040020, 0x8ee201a4, 0x8021, 0x24420001,
-0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c,
-0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e,
-0xad0a0018, 0x52940, 0xa01821, 0x1021,
-0xe33821, 0xe3202b, 0xc23021, 0xc43021,
-0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025,
-0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
-0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee,
-0x2c630002, 0x39420011, 0x2c420001, 0x621825,
-0x10600024, 0x0, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1455000f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b,
-0x0, 0x8003f2e, 0x0, 0x8ee24e30,
-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020001, 0x8003f4e,
-0xac950000, 0x8ee24e30, 0x210c0, 0x24425038,
-0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8003f3a, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400012,
-0xac800000, 0x8003f4f, 0x0, 0x8ee24e30,
-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020007, 0xac820000,
-0x24020001, 0xac820004, 0x1600000d, 0x0,
-0x8f820120, 0x3c040001, 0x24845938, 0xafa00014,
-0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
-0xc002403, 0x34a50001, 0x8004057, 0x0,
-0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
-0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
-0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
-0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff,
-0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240,
-0x104000e5, 0x0, 0x8ee20e1c, 0x24420001,
-0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c,
-0x8f420240, 0x10400072, 0x0, 0x8ee20e1c,
-0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b,
-0x144000d5, 0x0, 0x8f830120, 0x27623800,
-0x24660020, 0xc2102b, 0x50400001, 0x27663000,
-0x8f820128, 0x10c20004, 0x0, 0x8f820124,
-0x14c20007, 0x0, 0x8ee201a4, 0x8021,
-0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4,
-0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
-0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
-0x24020011, 0xac620018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400034, 0x24100001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1455001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8003fc6, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400011,
-0xac800000, 0x8003fda, 0x0, 0x8ee24e30,
-0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x24020001, 0xac950000,
-0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
-0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
-0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
-0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
-0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
-0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
-0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
-0x24020008, 0xa462000e, 0x24020011, 0xac620018,
-0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
-0xaf860120, 0x92e24e20, 0x14400034, 0x24100001,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x8c820000, 0x1455001f, 0x0, 0x8ee34e30,
-0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
-0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
-0x24420001, 0x10540007, 0x0, 0x8ee24e34,
-0x24420001, 0x10620005, 0x0, 0x8004030,
-0x0, 0x14600005, 0x0, 0x8f820128,
-0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
-0x2c420011, 0x50400011, 0xac800000, 0x8004044,
-0x0, 0x8ee24e30, 0x24420001, 0x50540003,
-0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
-0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
-0x24020001, 0xac950000, 0xac820004, 0x1600000b,
-0x0, 0x8ee2724c, 0x3c040001, 0x248458a8,
-0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
-0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
-0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
-0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124,
-0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c,
-0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
-0x27840208, 0x27450200, 0x24060008, 0xafbf0014,
-0xc00249a, 0xafb00010, 0x2021, 0x24100001,
-0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
-0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
-0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8,
-0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0,
-0x3c010001, 0xac235cc8, 0xc005108, 0x24050004,
-0xc004822, 0x0, 0x8ee20000, 0x3c03feff,
-0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
-0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
-0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
-0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
-0x248459f0, 0xc002403, 0x3821, 0x8ee20280,
-0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
-0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
-0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214,
-0x3821, 0x24420001, 0xaee20214, 0x8ee20214,
-0x3c020300, 0x2021024, 0x10400027, 0x3c110400,
-0xc00429b, 0x0, 0x3c020100, 0x2021024,
-0x10400007, 0x0, 0x8ee20218, 0x24420001,
-0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
-0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
-0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
-0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008,
-0x2003021, 0x431024, 0xaee20000, 0x8f820220,
-0x3821, 0x3c030300, 0x481024, 0x431025,
-0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
-0x8004296, 0x0, 0x2111024, 0x1040001f,
-0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
-0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
-0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
-0x3463ffff, 0x2002021, 0x431024, 0xc004e54,
-0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
-0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x8004295, 0x511025, 0x2021024,
-0x10400142, 0x0, 0x8ee2022c, 0x24420001,
-0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff,
-0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
-0x8f830054, 0x8f820054, 0x800410e, 0x24630002,
-0x8f820054, 0x621023, 0x2c420003, 0x1440fffc,
-0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007,
-0x10400012, 0x0, 0x8f8300e4, 0x2402fff8,
-0xc21024, 0x1043000d, 0x0, 0x8f820054,
-0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054,
-0x821023, 0x2c420051, 0x10400004, 0x0,
-0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220,
-0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220,
-0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8,
-0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f,
-0x3442ffff, 0x24680008, 0x48102b, 0x10400003,
-0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8,
-0x8f850120, 0x8f840124, 0x8004145, 0x6021,
-0x27623800, 0x82102b, 0x50400001, 0x27643000,
-0x10a40010, 0x318200ff, 0x8c820018, 0x38430007,
-0x2c630001, 0x3842000b, 0x2c420001, 0x621825,
-0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001,
-0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008,
-0x318200ff, 0x14400065, 0x0, 0x3c020001,
-0x571021, 0x904283c0, 0x14400060, 0x0,
-0x8f8400e4, 0xc41023, 0x218c3, 0x4620001,
-0x24630200, 0x8f8900c4, 0x10600005, 0x24020001,
-0x10620009, 0x0, 0x8004187, 0x0,
-0x8ee20230, 0x1205821, 0x24420001, 0xaee20230,
-0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a,
-0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000,
-0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001,
-0x651821, 0x2c62233f, 0x14400040, 0x0,
-0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8,
-0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4,
-0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a,
-0x24420001, 0xaee20238, 0x8c840000, 0x3463f000,
-0x8ee20238, 0x883823, 0x67102b, 0x54400001,
-0xe33821, 0x3c020003, 0x34420d40, 0x47102b,
-0x10400003, 0x0, 0x80041bc, 0x805821,
-0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4,
-0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003,
-0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c,
-0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b,
-0x54400001, 0xe53821, 0x147102b, 0x54400007,
-0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4,
-0x8f8400e4, 0x1486ffef, 0x0, 0x14860005,
-0x0, 0x1205821, 0xaf8600e4, 0x80041bc,
-0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8,
-0x3c03000a, 0x3463f000, 0x483823, 0x67102b,
-0x54400001, 0xe33821, 0x3c020003, 0x34420d3f,
-0x47102b, 0x54400007, 0x6021, 0x1683823,
-0x67102b, 0x54400003, 0xe33821, 0x80041cf,
-0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b,
-0x14400016, 0x318200ff, 0x14400006, 0x0,
-0x3c020001, 0x571021, 0x904283c0, 0x1040000f,
-0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000,
-0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c,
-0x24020001, 0x641824, 0x3c010001, 0x370821,
-0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8,
-0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000,
-0x623823, 0x87102b, 0x54400001, 0xe43821,
-0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001,
-0x431025, 0x10400008, 0x0, 0x8f820220,
-0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000,
-0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
-0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
-0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
-0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0,
-0x431024, 0x1040001d, 0x0, 0x10c4001b,
-0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
-0x24850008, 0x27622800, 0x50a20001, 0x27651800,
-0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff,
-0x431021, 0x4d1024, 0x24430010, 0x6b102b,
-0x54400001, 0x6a1821, 0x12b102b, 0x54400001,
-0x12a4821, 0x10690002, 0x10c1025, 0xac820004,
-0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220,
-0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002,
-0xaf820220, 0x8f830054, 0x8f820054, 0x8004237,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff,
-0x3463fffb, 0x431024, 0xaf820220, 0x6010055,
-0x0, 0x8ee20228, 0x24420001, 0xaee20228,
-0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820220, 0x8f830054,
-0x8f820054, 0x8004251, 0x24630002, 0x8f820054,
-0x621023, 0x2c420003, 0x1440fffc, 0x0,
-0x8f8600e0, 0x30c20007, 0x10400012, 0x0,
-0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d,
-0x0, 0x8f820054, 0x8f8300e0, 0x14c30009,
-0x24440032, 0x8f820054, 0x821023, 0x2c420033,
-0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9,
-0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd,
-0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007,
-0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0,
-0x240301f5, 0x8f8200e8, 0x673823, 0x718c0,
-0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4,
-0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021,
-0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002,
-0x441024, 0x431025, 0xaf820220, 0x8f830054,
-0x8f820054, 0x800428d, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
-0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8,
-0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
-0x24845a14, 0x3c050008, 0x24020001, 0x3c010001,
-0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
-0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8,
-0x3c010001, 0xac225ccc, 0xc002403, 0x3821,
-0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
-0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
-0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
-0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4,
-0x8f820044, 0x3c030600, 0x34632000, 0x34420020,
-0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228,
-0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010,
-0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
-0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
-0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
-0x1040006a, 0x5821, 0x24180008, 0x240f000d,
-0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
-0x27623800, 0x24e80020, 0x102102b, 0x50400001,
-0x27683000, 0x8f820128, 0x11020004, 0x0,
-0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
-0x2821, 0x24420001, 0xaee201a4, 0x800433d,
-0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
-0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
-0x822021, 0x862021, 0xace40000, 0xace50004,
-0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
-0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
-0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
-0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x800432a, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x800433d, 0x0, 0x8ee24e30,
-0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
-0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
-0x24020001, 0x54620079, 0xafa00010, 0xaeea0608,
-0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
-0x2c420033, 0x10400061, 0x5821, 0x240d0008,
-0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
-0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
-0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
-0x0, 0x8f820124, 0x14c20007, 0x0,
-0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4,
-0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c,
-0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
-0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
-0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
-0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
-0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
-0x0, 0x8c820004, 0x24420001, 0xac820004,
-0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
-0x0, 0x8ee24e34, 0x24420001, 0x10620005,
-0x0, 0x8004396, 0x0, 0x14600005,
-0x0, 0x8f820128, 0x24420020, 0xaf820128,
-0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
-0xac800000, 0x80043a9, 0x0, 0x8ee24e30,
-0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
-0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
-0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
-0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
-0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
-0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
-0x0, 0x3c040001, 0x24845a20, 0xafa00014,
-0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
-0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
-0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124,
-0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
-0x0, 0x3c040001, 0x24845a38, 0xafa00014,
-0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
-0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
-0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
-0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
-0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d,
-0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
-0x24020001, 0x3c010001, 0xac225cd8, 0xc002403,
-0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
-0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
-0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
-0x34420008, 0xaf820220, 0x2021, 0xc0052a2,
-0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x3c120001,
-0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001,
-0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
-0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
-0x0, 0xd, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x80014d6,
-0x0, 0x80014d8, 0x3c0a0001, 0x80014d8,
-0x3c0a0002, 0x80014d8, 0x0, 0x80024a6,
-0x0, 0x80014d8, 0x3c0a0003, 0x80014d8,
-0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8,
-0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66,
-0x0, 0x80014d8, 0x3c0a0006, 0x80014d8,
-0x3c0a0007, 0x80014d8, 0x0, 0x80014d8,
-0x0, 0x80014d8, 0x0, 0x8002a75,
-0x0, 0x80014d8, 0x3c0a000b, 0x80014d8,
-0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a,
-0x0, 0x8002339, 0x0, 0x80014d8,
-0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4,
-0x0, 0x80014d8, 0x3c0a000f, 0x80040a7,
-0x0, 0x8004091, 0x0, 0x80014d8,
-0x3c0a0010, 0x80014ee, 0x0, 0x80014d8,
-0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8,
-0x3c0a0013, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x3c030001,
-0x34633800, 0x24050080, 0x2404001f, 0x2406ffff,
-0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
-0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4,
-0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0,
-0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8,
-0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4,
-0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0,
-0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8,
-0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004,
-0x8f830040, 0x3c02f000, 0x621824, 0x3c025000,
-0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
-0x3c024000, 0x10620008, 0x24020800, 0x8004539,
-0x0, 0x10620004, 0x24020800, 0x8004539,
-0x0, 0x24020700, 0x3c010001, 0xac225cdc,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001,
-0xac205cc4, 0x8004545, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0xc004d71, 0x0, 0x24040001, 0x2821,
-0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018,
-0x8f830054, 0x8f820054, 0x8004556, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x8004562, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x800456e, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c,
-0x24050002, 0x8f830054, 0x8f820054, 0x800457b,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
-0x26105da2, 0xc00494c, 0x2003021, 0x97a60018,
-0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0,
-0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
-0xc002403, 0xafa20010, 0x97a20018, 0x1040004c,
-0x24036040, 0x96020000, 0x3042fff0, 0x1443000a,
-0x24020020, 0x3c030001, 0x94635da0, 0x54620009,
-0x24027830, 0x24020003, 0x3c010001, 0xac225cc4,
-0x80045ac, 0x24020005, 0x3c030001, 0x94635da0,
-0x24027830, 0x1462000f, 0x24030010, 0x3c020001,
-0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003,
-0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001,
-0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6,
-0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001,
-0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4,
-0x24020015, 0x1462000f, 0x0, 0x3c020001,
-0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001,
-0x3842f430, 0x2c420001, 0x621825, 0x10600005,
-0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6,
-0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810,
-0x1462000b, 0x24020002, 0x3c020001, 0x94425da2,
-0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
-0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
-0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
-0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001,
-0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4,
-0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4,
-0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001,
-0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc,
-0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2,
-0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8,
-0x491021, 0x3c010001, 0xac225dac, 0xafa30010,
-0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020,
-0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001,
-0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014,
-0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000,
-0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc,
-0x8004617, 0x34844240, 0x3c040004, 0x3c030001,
-0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016,
-0x0, 0x3c04003d, 0x800462f, 0x34840900,
-0x3c020001, 0x8c427e38, 0x30428000, 0x10400005,
-0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a,
-0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc,
-0x34844240, 0x24020005, 0x14620003, 0x0,
-0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac,
-0x8f830054, 0x441021, 0x431023, 0x44102b,
-0x14400037, 0x0, 0x3c020001, 0x8c425cd0,
-0x14400033, 0x0, 0x3c010001, 0x10c00025,
-0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001,
-0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc,
-0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
-0xa91024, 0x10400010, 0x0, 0x14a70008,
-0x0, 0x8d020000, 0x441024, 0x1040000a,
-0x0, 0x3c010001, 0x800465b, 0xac255ce0,
-0x8d420000, 0x441024, 0x10400003, 0x0,
-0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0,
-0x6182b, 0x2c420001, 0x431024, 0x5440ffe5,
-0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0,
-0x3c010001, 0xac225dac, 0x1060002a, 0x24020001,
-0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc,
-0x3c020001, 0x8c425ce0, 0x10400022, 0x0,
-0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001,
-0x3c010001, 0xac205ccc, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001,
-0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac,
-0x24020008, 0x10620005, 0x24020001, 0xc004695,
-0x0, 0x8004692, 0x0, 0x3c030001,
-0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001,
-0x8c637dd0, 0x10620003, 0x0, 0xc004e54,
-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000,
-0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0,
-0x3442ffff, 0x621824, 0x14a40008, 0xaee30000,
-0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001,
-0x8c425cf4, 0x10620008, 0x0, 0x3c020001,
-0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0,
-0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8,
-0x24020002, 0x10620169, 0x2c620003, 0x10400005,
-0x24020001, 0x10620008, 0x0, 0x800481c,
-0x0, 0x24020004, 0x106200b1, 0x24020001,
-0x800481d, 0x0, 0x3c020001, 0x571021,
-0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a,
-0x31080, 0x3c010001, 0x220821, 0x8c225ac8,
-0x400008, 0x0, 0x3c030001, 0x8c635dbc,
-0x24020005, 0x14620014, 0x0, 0x3c020001,
-0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822,
-0x0, 0x24020002, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4,
-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
-0x800481f, 0xac205c60, 0xc004822, 0x0,
-0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60,
-0x104000dd, 0x24020002, 0x3c010001, 0x370821,
-0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4,
-0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003,
-0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf,
-0x0, 0x3c030001, 0x8c635d00, 0x800478e,
-0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001,
-0x8cc67e3c, 0xc005108, 0x2021, 0x24020005,
-0x3c010001, 0xac205cd4, 0x3c010001, 0x370821,
-0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc,
-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
-0xafa00010, 0xc002403, 0xafa00014, 0x800481f,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004,
-0x431024, 0x144000a9, 0x24020007, 0x8f830054,
-0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x144000f8, 0x24020001, 0x800481d,
-0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
-0x2021, 0xc005386, 0x2021, 0x3c030001,
-0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008,
-0x621024, 0x10400006, 0x0, 0x8f820214,
-0x3c03ffff, 0x431024, 0x8004741, 0x3442251f,
-0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
-0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
-0x24020008, 0x3c010001, 0x370821, 0xac2283ac,
-0x8f820220, 0x3c030004, 0x431024, 0x14400005,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005,
-0x1462000a, 0x0, 0x3c020001, 0x94425da2,
-0x24429fbc, 0x2c420004, 0x10400004, 0x24040018,
-0x24050002, 0xc004d93, 0x24060020, 0xc0043dd,
-0x0, 0x3c010001, 0x800481f, 0xac205d50,
-0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
-0x2c620008, 0x104000ac, 0x31080, 0x3c010001,
-0x220821, 0x8c225ae8, 0x400008, 0x0,
-0xc00429b, 0x0, 0x3c010001, 0xac205ccc,
-0xaf800204, 0x3c010001, 0xc004822, 0xac207e20,
-0x24020001, 0x3c010001, 0xac225ce4, 0x24020002,
-0x3c010001, 0x370821, 0x800481f, 0xac2283ac,
-0xc00489f, 0x0, 0x3c030001, 0x8c635ce4,
-0x24020009, 0x14620090, 0x24020003, 0x3c010001,
-0x370821, 0x800481f, 0xac2283ac, 0x3c020001,
-0x8c427e38, 0x30424000, 0x10400005, 0x0,
-0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff,
-0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
-0x8f830054, 0x80047b9, 0x24020004, 0x8f830054,
-0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x14400074, 0x24020005, 0x3c010001,
-0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
-0x3c010001, 0xac207e20, 0x8f830054, 0x24020006,
-0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
-0x800481f, 0xac235da4, 0x8f830054, 0x3c020001,
-0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a,
-0x14400059, 0x0, 0x24020007, 0x3c010001,
-0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
-0x3c04f700, 0x441025, 0xaf820220, 0x8f820220,
-0x3c030300, 0x431024, 0x14400005, 0x1821,
-0x8f820220, 0x24030001, 0x441025, 0xaf820220,
-0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff,
-0x3c040001, 0x8c845d98, 0x431024, 0x3442251f,
-0xaf820214, 0x24020008, 0x3c010001, 0x370821,
-0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74,
-0x14400007, 0x24020001, 0x3c010001, 0xac227dd0,
-0xc004e54, 0x8f840220, 0x800480c, 0x0,
-0x8f820220, 0x3c030008, 0x431024, 0x14400017,
-0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000,
-0x2021, 0x3c030200, 0x431025, 0xc005386,
-0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd,
-0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
-0x2021, 0x800481f, 0x0, 0x3c020001,
-0x8c425d74, 0x10400010, 0x0, 0x3c020001,
-0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70,
-0x14400009, 0x24020002, 0x3c010001, 0xac205d74,
-0x3c010001, 0x800481f, 0xac225d70, 0x24020001,
-0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
-0x34420004, 0xaf820220, 0x8f820200, 0x3c060001,
-0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002,
-0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001,
-0x10c20008, 0x0, 0x8004868, 0x0,
-0x24020004, 0x10c20013, 0x24020001, 0x8004868,
-0x0, 0x3c030001, 0x8c635cb8, 0x3c020001,
-0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001,
-0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022,
-0x441025, 0x451025, 0x34420002, 0x8004867,
-0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200,
-0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74,
-0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0,
-0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0,
-0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
-0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001,
-0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825,
-0x431025, 0x451025, 0xaf820220, 0x3e00008,
-0x0, 0x8f820220, 0x3c030001, 0x8c635cc8,
-0x34420004, 0xaf820220, 0x24020001, 0x1062000f,
-0x0, 0x8f830054, 0x8f820054, 0x24630002,
-0x621023, 0x2c420003, 0x10400011, 0x0,
-0x8f820054, 0x621023, 0x2c420003, 0x1040000c,
-0x0, 0x8004879, 0x0, 0x8f830054,
-0x8f820054, 0x8004885, 0x24630007, 0x8f820054,
-0x621023, 0x2c420008, 0x1440fffc, 0x0,
-0x8f8400e0, 0x30820007, 0x1040000d, 0x0,
-0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032,
-0x8f820054, 0xa21023, 0x2c420033, 0x10400004,
-0x0, 0x8f8200e0, 0x1082fff9, 0x0,
-0x8f820220, 0x2403fffd, 0x431024, 0xaf820220,
-0x3e00008, 0x0, 0x3c030001, 0x8c635ce4,
-0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff,
-0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009,
-0x1040009d, 0x31080, 0x3c010001, 0x220821,
-0x8c225b08, 0x400008, 0x0, 0x8f820044,
-0x34428080, 0xaf820044, 0x8f830054, 0x8004938,
-0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8,
-0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a,
-0x24020003, 0x8004945, 0x0, 0x8f820044,
-0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044,
-0x8f830054, 0x8004938, 0x24020004, 0x8f830054,
-0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023,
-0x2c42000a, 0x14400078, 0x24020005, 0x8004945,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0xaf820220, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
-0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200,
-0x2403fffd, 0x431024, 0xaf820200, 0x24040001,
-0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054,
-0x80048ec, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
-0x42040, 0xa4102b, 0x1040fff2, 0x0,
-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f,
-0xaf820214, 0x8f820220, 0x2403fffb, 0x431024,
-0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008,
-0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00,
-0x346300e2, 0x441025, 0xaf820220, 0xaf830200,
-0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008,
-0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000,
-0x34630040, 0x3c020001, 0x24425c70, 0xac820000,
-0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938,
-0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8,
-0x2463fff6, 0x431023, 0x2c42000a, 0x14400022,
-0x24020007, 0x8004945, 0x0, 0x8f8200e0,
-0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220,
-0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7,
-0x431024, 0xaf820220, 0x8f820044, 0x34428080,
-0xaf820044, 0x8f830054, 0x24020008, 0x3c010001,
-0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8,
-0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400003, 0x24020009,
-0x3c010001, 0xac225ce4, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x27bdffd8,
-0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
-0xafb10014, 0xc08821, 0xafb00010, 0x8021,
-0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d4b, 0x2021, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x24100010, 0x2501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fffa,
-0x2501024, 0x24100010, 0x2701024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x2701024, 0xc004d71, 0x34108000,
-0xc004d71, 0x0, 0xc004d2b, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c,
-0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
-0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
-0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
-0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x2301024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2501024, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96620000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8fbf0020,
-0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00,
-0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
-0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349,
-0x31080, 0x3c010001, 0x220821, 0x8c225b30,
-0x400008, 0x0, 0xc004d71, 0x8021,
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010,
-0x8021, 0xc004d4b, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d4b,
-0x2021, 0xc004d4b, 0x24040001, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004d4b, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004d71, 0x34108000,
-0xc004d71, 0x0, 0xc004d2b, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004d71, 0x0, 0x97a20010, 0x30428000,
-0x144002dc, 0x24020003, 0x8004d24, 0x0,
-0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0xc004d4b, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0xc004d4b, 0x24040001, 0xc004d4b,
-0x2021, 0x34108000, 0x96220000, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fff8, 0x0, 0xc004d71,
-0x0, 0x8f830054, 0x8004d16, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c,
-0x431023, 0x2c420064, 0x1440029e, 0x24020002,
-0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003,
-0x14400296, 0x24020011, 0x24020003, 0x10620005,
-0x24020004, 0x10620291, 0x2402000f, 0x8004d24,
-0x24020011, 0x8004d24, 0x24020005, 0x24020014,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020012, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8f830054,
-0x8004d16, 0x24020006, 0x8f830054, 0x3c020001,
-0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400250, 0x24020007, 0x8004d24, 0x0,
-0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020013, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020013,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x24020008, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440020f, 0x24020009, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x14400127, 0x24020012, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x24020013, 0x8f830054,
-0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
-0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
-0xc004d4b, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d71, 0x34108000, 0xc004d71, 0x0,
-0xc004d2b, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004d71, 0x8021,
-0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
-0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fff8, 0x0, 0xc004d71, 0x0,
-0x8f830054, 0x8004d16, 0x2402000e, 0x24020840,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x32020013, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8f830054,
-0x24020010, 0x3c010001, 0xac225d00, 0x3c010001,
-0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001,
-0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400004, 0x0, 0x24020011, 0x3c010001,
-0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
-0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
-0x8f840054, 0x8f820054, 0xa32824, 0x8004d37,
-0x24840001, 0x8f820054, 0x821023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004d45, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
-0x3442ffff, 0x42480, 0x621824, 0x3c020002,
-0x822025, 0x641825, 0xaf830044, 0x8f820044,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
-0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x3e00008, 0x0,
-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
-0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
-0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
-0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x12000075,
-0x0, 0x8004dc9, 0x0, 0x3274ffff,
-0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b,
-0x2021, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2901024, 0xc004d71,
-0x34108000, 0xc004d71, 0x0, 0xc004d2b,
-0x0, 0x50400005, 0x108042, 0x96220000,
-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
-0x0, 0xc004d71, 0x0, 0x32a5ffff,
-0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
-0x8004e14, 0x521025, 0x14a20006, 0x3271ffff,
-0x97a20010, 0x121827, 0x431024, 0xa7a20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d4b, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d4b,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
-0x24040001, 0xc004d4b, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
-0x0, 0xc004d71, 0x0, 0x8fbf0030,
-0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
-0x0, 0x0, 0x0, 0x27bdffe8,
-0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
-0x24020008, 0x1462022c, 0x803021, 0x3c020001,
-0x8c425d98, 0x14400033, 0x0, 0x8f850224,
-0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
-0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
-0x38a20400, 0x2c420001, 0x621825, 0x14600007,
-0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
-0x621825, 0x10600005, 0x0, 0xc00429b,
-0x0, 0x8004e8d, 0x2402000e, 0xc0043dd,
-0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
-0x2021, 0x3c030001, 0x8c635cc8, 0x24020004,
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4,
-0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4,
-0x431024, 0x3c010001, 0xac225cc4, 0x2402000e,
-0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087,
-0x0, 0x8f820220, 0x3c030400, 0x431024,
-0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
-0x8c427ddc, 0xa32024, 0x431024, 0x1482000c,
-0x0, 0x3c020001, 0x8c427de0, 0x24420001,
-0x3c010001, 0xac227de0, 0x2c420002, 0x14400008,
-0x24020001, 0x3c010001, 0x8004ead, 0xac227e00,
-0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00,
-0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040,
-0x10400004, 0x24020001, 0x3c010001, 0x8004eb8,
-0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001,
-0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10,
-0x24020001, 0x3c010001, 0xac227e10, 0x3c010001,
-0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001,
-0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001,
-0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003,
-0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024,
-0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
-0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700,
-0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
-0x220821, 0x8c225b80, 0x400008, 0x0,
-0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0,
-0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04,
-0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0,
-0xc00486a, 0xaf800224, 0x24020002, 0x3c010001,
-0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056,
-0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
-0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
-0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
-0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8,
-0x24040001, 0x3c010001, 0xac247e0c, 0x24420001,
-0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001,
-0xac237df4, 0x14400006, 0x24020003, 0x3c010001,
-0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8,
-0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054,
-0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
-0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026,
-0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
-0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c,
-0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001,
-0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10,
-0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
-0x431024, 0xaee20000, 0x8f820204, 0x30420030,
-0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c,
-0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001,
-0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10,
-0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c,
-0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002,
-0x14400131, 0x24020001, 0x3c010001, 0xac225d74,
-0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083,
-0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024,
-0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122,
-0x0, 0x3c020001, 0x8c427ddc, 0x1040011e,
-0x0, 0x3c010001, 0xac227e08, 0x24020003,
-0x3c010001, 0xac227de0, 0x8005024, 0x24020006,
-0x3c010001, 0xac207de8, 0x8f820204, 0x34420040,
-0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007,
-0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001,
-0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005,
-0x0, 0x3c020001, 0x8c427ddc, 0x104000f9,
-0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000,
-0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
-0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001,
-0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024,
-0x641824, 0x10430004, 0x24020001, 0x3c010001,
-0x8005083, 0xac227dd0, 0x24020003, 0xaca20000,
-0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001,
-0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001,
-0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28,
-0x14400005, 0x24020001, 0x3c020001, 0x8c427e24,
-0x10400006, 0x24020001, 0x3c010001, 0xac225ccc,
-0x3c010001, 0x8005083, 0xac207df8, 0x3c020001,
-0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001,
-0x210c0, 0x30630008, 0x3c010001, 0xac227df0,
-0x3c010001, 0xac237dec, 0x8f830054, 0x24020009,
-0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083,
-0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4,
-0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
-0x0, 0x3c020001, 0x8c427e00, 0x10400005,
-0x0, 0x3c020001, 0x8c427ddc, 0x104000a9,
-0x24020002, 0x3c030001, 0x24637de0, 0x8c620000,
-0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
-0x8c427e0c, 0x1040000e, 0x0, 0x3c020001,
-0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080,
-0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
-0x1440000c, 0x24020003, 0x8005011, 0x2402000c,
-0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005,
-0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
-0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
-0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000,
-0x3c030001, 0x8c637df0, 0x431025, 0xaf820204,
-0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b,
-0x3c010001, 0xac227dd0, 0x641825, 0x3c010001,
-0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000,
-0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
-0x8c427e10, 0x10400005, 0x0, 0x2402000c,
-0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001,
-0x8c427e00, 0x1040006c, 0x0, 0x3c040001,
-0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001,
-0x8c637dec, 0x10620064, 0x24020003, 0x3c010001,
-0xac247e08, 0xaca20000, 0x24020006, 0x3c010001,
-0x8005083, 0xac227dd0, 0x8f820200, 0x34420002,
-0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
-0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054,
-0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
-0x2c422710, 0x1440003a, 0x0, 0x3c020001,
-0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001,
-0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0,
-0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8,
-0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8,
-0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
-0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001,
-0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4,
-0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
-0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220,
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
-0x34420002, 0x8005083, 0xaf820220, 0x3c020001,
-0x8c427e00, 0x10400005, 0x0, 0x3c020001,
-0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001,
-0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002,
-0x3c020001, 0x8c427e00, 0x1040000f, 0x0,
-0x3c020001, 0x8c427ddc, 0x1440000b, 0x0,
-0x24020002, 0x3c010001, 0x8005083, 0xac227dd0,
-0x3c020001, 0x8c427e00, 0x10400003, 0x0,
-0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
-0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
-0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000,
-0x10400005, 0x34422000, 0x3c010001, 0xac227e1c,
-0x8005095, 0xac600000, 0x3c010001, 0xac247e1c,
-0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
-0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067,
-0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
-0x24020030, 0x30822000, 0x1040005d, 0x30838000,
-0x31a02, 0x30820001, 0x21200, 0x3c040001,
-0x8c845d9c, 0x621825, 0x331c2, 0x3c030001,
-0x24635d78, 0x30828000, 0x21202, 0x30840001,
-0x42200, 0x441025, 0x239c2, 0x61080,
-0x431021, 0x471021, 0x90430000, 0x24020001,
-0x10620025, 0x0, 0x10600007, 0x24020002,
-0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
-0x80050f9, 0x0, 0x8f820200, 0x2403feff,
-0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
-0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c,
-0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
-0x24020100, 0x3c010001, 0xac227e44, 0x3c010001,
-0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff,
-0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
-0x431025, 0xaf820220, 0x3c010001, 0xac207e44,
-0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200,
-0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
-0x431025, 0xaf820220, 0x24020100, 0x3c010001,
-0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c,
-0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010,
-0xc002403, 0xafa00014, 0x8005104, 0x0,
-0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018,
-0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
-0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
-0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0,
-0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001,
-0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
-0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
-0x24020002, 0x12620083, 0x2e620003, 0x10400005,
-0x24020001, 0x1262000a, 0x0, 0x800529b,
-0x0, 0x24020004, 0x126200fa, 0x24020008,
-0x126200f9, 0x3c02ffec, 0x800529b, 0x0,
-0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004,
-0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
-0x3c010001, 0x310821, 0xac307e3c, 0x3c024000,
-0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
-0x101382, 0x3042001c, 0x3c030001, 0x24635d08,
-0x431021, 0x823821, 0x3c020020, 0x2021024,
-0x10400006, 0x24020100, 0x3c010001, 0x310821,
-0xac227e40, 0x8005150, 0x3c020080, 0x3c010001,
-0x310821, 0xac207e40, 0x3c020080, 0x2021024,
-0x10400006, 0x121940, 0x3c020001, 0x3c010001,
-0x230821, 0x800515c, 0xac227e48, 0x121140,
-0x3c010001, 0x220821, 0xac207e48, 0x94e40000,
-0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010,
-0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
-0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
-0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002,
-0x24040001, 0x2821, 0xc00498e, 0x27a60018,
-0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001,
-0xac315cd4, 0x14530004, 0x32028000, 0xc00429b,
-0x0, 0x32028000, 0x1040011f, 0x0,
-0xc00429b, 0x0, 0x3c030001, 0x8c635dbc,
-0x24020005, 0x10620118, 0x24020002, 0x3c010001,
-0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8,
-0x24040001, 0x24050004, 0x27b0001a, 0xc00498e,
-0x2003021, 0x24040001, 0x2821, 0xc00498e,
-0x2003021, 0x3c020001, 0x511021, 0x8c427e34,
-0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff,
-0x3c010001, 0xac335cd4, 0x431024, 0x3c010001,
-0x310821, 0x109300fa, 0xac227e34, 0x800529b,
-0x0, 0x3c022000, 0x2021024, 0x10400005,
-0x24020001, 0x3c010001, 0xac225d98, 0x80051ad,
-0x128940, 0x3c010001, 0xac205d98, 0x128940,
-0x3c010001, 0x310821, 0xac307e38, 0x3c024000,
-0x2021024, 0x14400016, 0x0, 0x3c020001,
-0x8c425d98, 0x10400008, 0x24040004, 0x24050001,
-0xc004d93, 0x24062000, 0x24020001, 0x3c010001,
-0x370821, 0xac2283ac, 0x3c020001, 0x511021,
-0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024,
-0x3c010001, 0x310821, 0x8005299, 0xac227e30,
-0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0,
-0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
-0x8c425d9c, 0x24030100, 0x3c010001, 0x310821,
-0xac237e44, 0x3c030001, 0x3c010001, 0x310821,
-0xac237e4c, 0x80051f0, 0x34420400, 0x2021024,
-0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c,
-0x3c010001, 0x310821, 0xac237e44, 0x80051f0,
-0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
-0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001,
-0x310821, 0xac237e4c, 0x34420c00, 0x3c010001,
-0xac225d9c, 0x8005218, 0x24040001, 0x3c020020,
-0x2021024, 0x10400006, 0x24020100, 0x3c010001,
-0x310821, 0xac227e44, 0x8005201, 0x3c020080,
-0x3c010001, 0x310821, 0xac207e44, 0x3c020080,
-0x2021024, 0x10400007, 0x121940, 0x3c020001,
-0x3c010001, 0x230821, 0xac227e4c, 0x800520f,
-0x24040001, 0x121140, 0x3c010001, 0x220821,
-0xac207e4c, 0x24040001, 0x2821, 0x27b0001e,
-0xc00494c, 0x2003021, 0x24040001, 0x2821,
-0xc00494c, 0x2003021, 0x24040001, 0x24050001,
-0x27b0001c, 0xc00494c, 0x2003021, 0x24040001,
-0x24050001, 0xc00494c, 0x2003021, 0x8005299,
-0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
-0x3c020008, 0x2028025, 0x121140, 0x3c010001,
-0x220821, 0xac307e38, 0x3c022000, 0x2021024,
-0x10400009, 0x0, 0x3c020001, 0x8c425d74,
-0x14400005, 0x24020001, 0x3c010001, 0xac225d98,
-0x800523a, 0x3c024000, 0x3c010001, 0xac205d98,
-0x3c024000, 0x2021024, 0x1440001e, 0x0,
-0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0,
-0x10400007, 0x24022020, 0x3c010001, 0xac225d9c,
-0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
-0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
-0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff,
-0x441024, 0x3c010001, 0x230821, 0xac227e30,
-0x24020001, 0x10a20044, 0x0, 0x8005299,
-0x0, 0x3c020001, 0x8c425d98, 0x1040001c,
-0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0,
-0x2031024, 0x14430005, 0x121140, 0x3402a000,
-0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001,
-0x621821, 0x8c637e38, 0x3c020020, 0x621024,
-0x10400004, 0x24022001, 0x3c010001, 0x8005294,
-0xac225d9c, 0x3c020080, 0x621024, 0x1040001f,
-0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c,
-0x3c020020, 0x2021024, 0x10400007, 0x121940,
-0x24020100, 0x3c010001, 0x230821, 0xac227e44,
-0x8005288, 0x3c020080, 0x121140, 0x3c010001,
-0x220821, 0xac207e44, 0x3c020080, 0x2021024,
-0x10400006, 0x121940, 0x3c020001, 0x3c010001,
-0x230821, 0x8005294, 0xac227e4c, 0x121140,
-0x3c010001, 0x220821, 0xac207e4c, 0x3c030001,
-0x8c635cc8, 0x24020001, 0x10620003, 0x0,
-0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
-0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021,
-0xafb1001c, 0x8821, 0x24020002, 0xafbf0024,
-0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010,
-0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a,
-0x128140, 0x8005380, 0x2201021, 0x24020004,
-0x10a2007d, 0x24020008, 0x10a2007c, 0x122940,
-0x8005380, 0x2201021, 0x3c030001, 0x701821,
-0x8c637e3c, 0x3c024000, 0x621024, 0x14400009,
-0x24040001, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010001, 0x300821, 0xac317e34, 0x8005380,
-0x2201021, 0x24050001, 0xc00494c, 0x27a60010,
-0x24040001, 0x24050001, 0xc00494c, 0x27a60010,
-0x97a20010, 0x30420004, 0x10400034, 0x3c114000,
-0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006,
-0x10400034, 0x31080, 0x3c010001, 0x220821,
-0x8c225be0, 0x400008, 0x0, 0x24040001,
-0x24050011, 0x27b00012, 0xc00494c, 0x2003021,
-0x24040001, 0x24050011, 0xc00494c, 0x2003021,
-0x97a50012, 0x30a24000, 0x10400002, 0x3c040010,
-0x3c040008, 0x3c030001, 0x8005301, 0x30a28000,
-0x24040001, 0x24050014, 0x27b00012, 0xc00494c,
-0x2003021, 0x24040001, 0x24050014, 0xc00494c,
-0x2003021, 0x97a50012, 0x30a21000, 0x10400002,
-0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800,
-0x54400001, 0x3c030002, 0x3c028000, 0x2221025,
-0x641825, 0x800530e, 0x438825, 0x3c110001,
-0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff,
-0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d,
-0x121140, 0x3c020001, 0x8c425d98, 0x10400002,
-0x3c022000, 0x2228825, 0x121140, 0x3c010001,
-0x220821, 0x8c227e40, 0x10400003, 0x3c020020,
-0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff,
-0x2228824, 0x121140, 0x3c010001, 0x220821,
-0x8c227e48, 0x10400003, 0x3c020080, 0x800532d,
-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
-0x121140, 0x3c010001, 0x220821, 0xac317e34,
-0x8005380, 0x2201021, 0x122940, 0x3c030001,
-0x651821, 0x8c637e38, 0x3c024000, 0x621024,
-0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010001, 0x250821, 0xac317e30, 0x8005380,
-0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033,
-0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c,
-0x34842000, 0x3c030001, 0x8c635d98, 0x2102b,
-0x21023, 0x441024, 0x10600003, 0x518825,
-0x3c022000, 0x2228825, 0x3c020001, 0x451021,
-0x8c427e44, 0x10400003, 0x3c020020, 0x800535d,
-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x121140, 0x3c010001, 0x220821, 0x8c227e4c,
-0x10400003, 0x3c020080, 0x8005368, 0x2228825,
-0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
-0x8c425d60, 0x10400002, 0x3c020800, 0x2228825,
-0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400,
-0x2228825, 0x3c020001, 0x8c425d68, 0x10400006,
-0x3c020100, 0x800537b, 0x2228825, 0x3c027fff,
-0x3442ffff, 0x628824, 0x121140, 0x3c010001,
-0x220821, 0xac317e30, 0x2201021, 0x8fbf0024,
-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
-0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021,
-0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
-0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8,
-0x8f930220, 0x24020002, 0x10620063, 0x2c620003,
-0x10400005, 0x24020001, 0x1062000a, 0x141940,
-0x8005448, 0x0, 0x24020004, 0x1062005a,
-0x24020008, 0x10620059, 0x149140, 0x8005448,
-0x0, 0x3c040001, 0x832021, 0x8c847e3c,
-0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000,
-0x821024, 0x1040003e, 0x3c020008, 0x2221024,
-0x10400020, 0x36100002, 0x3c020001, 0x431021,
-0x8c427e40, 0x10400005, 0x36100020, 0x36100100,
-0x3c020020, 0x80053bd, 0x2228825, 0x2402feff,
-0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x141140, 0x3c010001, 0x220821, 0x8c227e48,
-0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
-0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff,
-0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc,
-0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
-0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
-0x2228824, 0x3c010001, 0x230821, 0xac207e40,
-0x3c010001, 0x230821, 0xac207e48, 0xc00486a,
-0x0, 0xaf900200, 0xaf930220, 0x8f820220,
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
-0x34420002, 0xaf820220, 0x80053f3, 0x141140,
-0x8f820200, 0x2403fffd, 0x431024, 0xc00486a,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
-0x2228824, 0x141140, 0x3c010001, 0x220821,
-0x8005448, 0xac317e34, 0x149140, 0x3c040001,
-0x922021, 0x8c847e38, 0x3c110001, 0x2328821,
-0x8e317e30, 0x3c024000, 0x821024, 0x14400011,
-0x0, 0x3c020001, 0x8c425d98, 0x14400006,
-0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a,
-0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
-0x2228824, 0x3c010001, 0x320821, 0x8005448,
-0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005,
-0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b,
-0x3c020020, 0x821024, 0x10400007, 0x36100020,
-0x24020100, 0x3c010001, 0x320821, 0xac227e44,
-0x8005428, 0x36100100, 0x3c010001, 0x320821,
-0xac207e44, 0x2402feff, 0x2028024, 0x3c020080,
-0x821024, 0x10400007, 0x141940, 0x3c020001,
-0x3c010001, 0x230821, 0xac227e4c, 0x8005439,
-0x2629825, 0x141140, 0x3c010001, 0x220821,
-0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824,
-0xc00486a, 0x0, 0xaf900200, 0xaf930220,
-0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
-0x8f820220, 0x34420002, 0xaf820220, 0x141140,
-0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024,
-0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x10000003,
+0x0, 0xd, 0xd, 0x3c1d0001,
+0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000,
+0xc00100c, 0x0, 0xd, 0x27bdffd8,
+0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021,
+0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8,
+0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8,
+0x0, 0x3c040001, 0x248451a4, 0x24050001,
+0x2e03021, 0x3821, 0x3c100001, 0x26107e50,
+0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f,
+0x3442ffff, 0x2021024, 0x362102b, 0x10400009,
+0x24050003, 0x3c040001, 0x248451b0, 0x2003021,
+0x3603821, 0x3c020010, 0xafa20010, 0xc002403,
+0xafa00014, 0x2021, 0x3405c000, 0x3c010001,
+0x370821, 0xa02083b0, 0x3c010001, 0x370821,
+0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3,
+0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8,
+0x418c0, 0x24840001, 0x771021, 0xac40727c,
+0x771021, 0xac407280, 0x2e31021, 0xa445727c,
+0x2c820020, 0x1440fff7, 0x418c0, 0x2021,
+0x3405c000, 0x418c0, 0x24840001, 0x771021,
+0xac40737c, 0x771021, 0xac407380, 0x2e31021,
+0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0,
+0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040,
+0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
+0x8f420218, 0x30420002, 0x10400009, 0x0,
+0x8f420220, 0x3c030002, 0x34630004, 0x431025,
+0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004,
+0x8f420220, 0x3c030002, 0x34630006, 0x431025,
+0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc,
+0x8f420218, 0x30420010, 0x1040000a, 0x0,
+0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220,
+0x3c03000a, 0x34630004, 0x431025, 0x800108a,
+0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006,
+0x431025, 0xaee204c0, 0x8f42021c, 0x34420006,
+0xaee204c8, 0x8f420218, 0x30420200, 0x10400003,
+0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248,
+0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054,
+0x8f820054, 0x8001099, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010,
+0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030,
+0xaee20028, 0x24020490, 0xaee20018, 0xaf840090,
+0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a,
+0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025,
+0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd,
+0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc,
+0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d,
+0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001,
+0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014,
+0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021,
+0x26e40030, 0xc002488, 0x24050400, 0x27440080,
+0xc002488, 0x24050080, 0x26e4777c, 0xc002488,
+0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060,
+0x8f420260, 0x27450200, 0x24060008, 0xaee20068,
+0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a,
+0x3442ca00, 0x2021, 0x24030002, 0xaee30074,
+0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104,
+0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001,
+0x641821, 0x90635c20, 0x2e41021, 0x24840001,
+0xa043009c, 0x2c82000f, 0x1440fff8, 0x0,
+0x8f820040, 0x2e41821, 0x24840001, 0x21702,
+0x24420030, 0xa062009c, 0x2e41021, 0xa040009c,
+0x96e2046a, 0x30420003, 0x14400009, 0x0,
+0x96e2047a, 0x30420003, 0x50400131, 0x3c030800,
+0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700,
+0x96e2047a, 0x30420003, 0x10400026, 0x3c020700,
+0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700,
+0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00,
+0xaee204c0, 0x8f420218, 0x30420100, 0x10400005,
+0x0, 0x3c020001, 0x2442e168, 0x800111d,
+0x21100, 0x3c020001, 0x2442d35c, 0x21100,
+0x21182, 0x3c030800, 0x431025, 0x3c010001,
+0xac221238, 0x3c020001, 0x2442f680, 0x21100,
+0x21182, 0x3c030800, 0x431025, 0x3c010001,
+0xac221278, 0x8ee20000, 0x34424000, 0x8001238,
+0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608,
+0x8f430228, 0x24420001, 0x304900ff, 0x512300e2,
+0xafa00010, 0x8ee20608, 0x210c0, 0x571021,
+0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610,
+0x8f870120, 0x27623800, 0x24e80020, 0x102102b,
+0x50400001, 0x27683000, 0x8f820128, 0x11020004,
+0x0, 0x8f820124, 0x15020007, 0x1021,
+0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
+0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0,
+0x801821, 0x8ee40430, 0x8ee50434, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xace40000,
+0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e,
+0x2402000d, 0xace20018, 0xace9001c, 0x318c0,
+0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4,
+0xace20010, 0xaf880120, 0x92e24e20, 0x14400037,
+0x24060001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+0x0, 0x800118a, 0x0, 0x14a00005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80011a0, 0x0, 0x8ee24e30,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x24020007,
+0xac820000, 0x24020001, 0xac820004, 0x54c0000c,
+0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f000, 0x8001223, 0x0,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4,
+0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400037, 0x24060001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x80011f1, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8001207, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020012, 0xac820000,
+0x24020001, 0xac820004, 0x14c0001b, 0x0,
+0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0,
+0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001,
+0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001,
+0x248451e8, 0x3405f001, 0x24420001, 0xaee20160,
+0x8ee20160, 0x3021, 0x3821, 0xafa00010,
+0xc002403, 0xafa00014, 0x8001238, 0x0,
+0x3c020001, 0x2442f5a8, 0x21100, 0x21182,
+0x431025, 0x3c010001, 0xac221278, 0x96e2045a,
+0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8,
+0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8,
+0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec,
+0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001,
+0x2442a390, 0x451024, 0x21082, 0xaee304c8,
+0x3c030800, 0x431025, 0x3c010001, 0xac221220,
+0x3c020001, 0x2442add4, 0x451024, 0x21082,
+0x431025, 0x3c010001, 0xac221280, 0x96e6045a,
+0x3821, 0x24050011, 0xafa00010, 0xc002403,
+0xafa00014, 0x8001268, 0x0, 0x3c020001,
+0x2442a9d4, 0x21100, 0x21182, 0x3c030800,
+0x431025, 0x3c010001, 0xac221280, 0x96e2046a,
+0x30420010, 0x14400009, 0x0, 0x96e2047a,
+0x30420010, 0x10400112, 0x0, 0x96e2046a,
+0x30420010, 0x10400005, 0x3c020700, 0x96e2047a,
+0x30420010, 0x14400102, 0x3c020700, 0x34423000,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee30608,
+0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
+0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
+0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
+0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x80012d4,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x80012ea,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020007, 0xac820000, 0x24020001,
+0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
+0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
+0x800136d, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x800133b, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x8001351, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020012, 0xac820000, 0x24020001, 0xac820004,
+0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
+0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
+0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0,
+0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
+0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002,
+0x24420001, 0xaee20160, 0x8ee20160, 0x3021,
+0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200,
+0x24050012, 0xafa00010, 0xc002403, 0xafa00014,
+0xc004500, 0x0, 0xc002318, 0x0,
+0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228,
+0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8,
+0x34a5c358, 0x27623800, 0xaee27258, 0x27623800,
+0xaee27260, 0x27623800, 0xaee27264, 0x3661021,
+0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0,
+0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c,
+0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c,
+0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c,
+0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268,
+0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8,
+0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee30608,
+0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018,
+0xace9001c, 0x318c0, 0x2463060c, 0x2e31021,
+0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120,
+0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x800140c,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8001422,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020007, 0xac820000, 0x24020001,
+0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001,
+0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000,
+0x80014a5, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x3021,
+0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24060001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x8001473, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x8001489, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020012, 0xac820000, 0x24020001, 0xac820004,
+0x14c0001b, 0x0, 0x3c040001, 0x248451d0,
+0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0,
+0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0,
+0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005,
+0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc,
+0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd,
+0x0, 0x8f820040, 0x30420001, 0x14400008,
+0x0, 0x8f430104, 0x24020001, 0x10620004,
+0x0, 0x8f420264, 0x10400006, 0x0,
+0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5,
+0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044,
+0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178,
+0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c,
+0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021,
+0xaee2726c, 0xc004064, 0x0, 0xc004440,
+0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x3e00008,
+0x0, 0x0, 0x0, 0x2402002c,
+0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278,
+0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88,
+0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821,
+0xac2083bc, 0x3c010001, 0x370821, 0x3e00008,
+0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020,
+0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067,
+0x1060000d, 0xaf820058, 0x3c020001, 0x571021,
+0x904283b8, 0x10400005, 0x3c030200, 0x3c010001,
+0x370821, 0x8001503, 0xa02083b8, 0x8ee20000,
+0x431025, 0xaee20000, 0x8f420218, 0x30420100,
+0x104000c6, 0x0, 0x8f8200b0, 0x30420004,
+0x104000c2, 0x0, 0x3c030001, 0x771821,
+0x8c6383d0, 0x8f820104, 0x146200b4, 0x0,
+0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4,
+0x146200ae, 0x0, 0x8f8200b0, 0x3c030080,
+0x431024, 0x1040000d, 0x0, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb,
+0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd,
+0x431024, 0x80015cc, 0xaf82011c, 0x3c030001,
+0x771821, 0x8c6383d0, 0x8f820104, 0x14620082,
+0x0, 0x3c030001, 0x771821, 0x8c6383d4,
+0x8f8200b4, 0x1462007c, 0x0, 0x3c070001,
+0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001,
+0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0,
+0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0,
+0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20006, 0x0, 0x8ee201a4,
+0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4,
+0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008,
+0x24020400, 0xa462000e, 0x2402000f, 0xac620018,
+0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
+0x0, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+0x0, 0x800158a, 0x0, 0x14a00005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80015a0, 0x0, 0x8ee24e30,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x24020007,
+0xac820000, 0x24020001, 0xac820004, 0x8f82011c,
+0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4,
+0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001,
+0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c,
+0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001,
+0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001,
+0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284,
+0x3c010001, 0x370821, 0xac2283d4, 0xafa00010,
+0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403,
+0x34a50900, 0x80015cc, 0x0, 0x8f820104,
+0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4,
+0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274,
+0x92e304f4, 0x24420067, 0x14600006, 0xaee27274,
+0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b,
+0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004,
+0x0, 0x92e204f4, 0x50400074, 0xa2e004f4,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
+0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x8001621, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8001637, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020012, 0xac820000,
+0x24020001, 0xac820004, 0x5600000b, 0x24100001,
+0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014,
+0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f006, 0x16000003, 0x24020001,
+0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001,
+0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4,
+0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c,
+0x1040006d, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4,
+0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020012,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x8001697, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x80016ad, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020012, 0xac820000, 0x24020001, 0xac820004,
+0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001,
+0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c,
+0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008,
+0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001,
+0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019,
+0x0, 0xaee04e24, 0x8f820040, 0x30420001,
+0x14400008, 0x0, 0x8f430104, 0x24020001,
+0x10620004, 0x0, 0x8f420264, 0x10400006,
+0x0, 0x8ee2017c, 0x24420001, 0xaee2017c,
+0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004,
+0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178,
+0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278,
+0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238,
+0x104002aa, 0x0, 0x3c020001, 0x571021,
+0x904283e0, 0x144002a5, 0x0, 0x8f420080,
+0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084,
+0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088,
+0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090,
+0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098,
+0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0,
+0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8,
+0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0,
+0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8,
+0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c,
+0xaee0003c, 0x41080, 0x571021, 0x8ee3003c,
+0x8c420244, 0x24840001, 0x621821, 0x2c82000f,
+0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc,
+0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8001775,
+0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030,
+0xac620008, 0x24020400, 0xa462000e, 0x2402000f,
+0xac620018, 0xac60001c, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400037, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x800175f, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x8001775, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020007, 0xac820000, 0x24020001, 0xac820004,
+0x12000212, 0x3c020400, 0xafa20018, 0x3c020001,
+0x571021, 0x904283b0, 0x1040010b, 0x0,
+0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
+0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
+0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
+0x1221023, 0x2c420033, 0x1040006a, 0x5821,
+0x24180008, 0x240f000d, 0x240d0007, 0x240c0040,
+0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
+0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+0x11020004, 0x0, 0x8f820124, 0x15020007,
+0x1021, 0x8ee201a4, 0x8021, 0x24420001,
+0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608,
+0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e,
+0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
+0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
+0xaf880120, 0x92e24e20, 0x14400033, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x80017e0,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x80017f3,
+0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
+0x0, 0x316300ff, 0x24020001, 0x14620077,
+0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x10400061,
+0x5821, 0x240d0008, 0x240c0011, 0x24080012,
+0x24070040, 0x240a0001, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400033, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x1448001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10470007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x800184c,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x800185f,
+0x0, 0x8ee24e30, 0x24420001, 0x50470003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac880000, 0xac8a0004, 0x56000006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
+0x0, 0x316300ff, 0x24020001, 0x14620003,
+0x3c050009, 0x800197c, 0x24100001, 0x3c040001,
+0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
+0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001,
+0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120,
+0x8f870124, 0x34a5f010, 0xc002403, 0x8021,
+0x800197c, 0x0, 0x3c040001, 0x248452bc,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228,
+0x24420001, 0x304900ff, 0x512300e2, 0xafa00010,
+0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120,
+0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+0x27683000, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x80018f7,
+0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xace40000, 0xace50004,
+0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d,
+0xace20018, 0xace9001c, 0x318c0, 0x2463060c,
+0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010,
+0xaf880120, 0x92e24e20, 0x14400037, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020007, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee54e30, 0x24420001, 0x10430007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x80018e1, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x80018f7, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+0x24020001, 0xac820004, 0x5600000c, 0xaee90608,
+0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f000, 0x800197c, 0x0, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x800195e,
+0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x8001948,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x800195e,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020012, 0xac820000, 0x24020001,
+0xac820004, 0x5600001d, 0x24100001, 0x3c040001,
+0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001,
+0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c,
+0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005,
+0xc002403, 0x0, 0x8ee201ac, 0x8021,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c,
+0x24020001, 0x3c010001, 0x370821, 0xa02083b0,
+0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158,
+0x8ee30158, 0x800198c, 0xaee27278, 0x24020001,
+0x3c010001, 0x370821, 0xa02283b0, 0x3c020001,
+0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84,
+0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84,
+0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84,
+0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002,
+0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228,
+0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010,
+0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x1040006a, 0x5821, 0x24180008, 0x240f000d,
+0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
+0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+0x27683000, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8001a15,
+0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xace40000, 0xace50004,
+0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
+0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
+0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8001a02, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x8001a15, 0x0, 0x8ee24e30,
+0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
+0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
+0x24020001, 0x54620078, 0xafa00010, 0xaeea0608,
+0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
+0x2c420033, 0x10400061, 0x5821, 0x240d0008,
+0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400033, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8001a6e, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x8001a81, 0x0, 0x8ee24e30,
+0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
+0x56000006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
+0x24020001, 0x10620022, 0x0, 0x3c040001,
+0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120,
+0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011,
+0x8001aad, 0x0, 0x3c040001, 0x248452b0,
+0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
+0xc002403, 0x34a5f010, 0x8001aad, 0x0,
+0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608,
+0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f,
+0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac,
+0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c,
+0x8ee204d4, 0x30420001, 0x10400055, 0x0,
+0x8f420218, 0x30420080, 0x10400029, 0x0,
+0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c,
+0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000,
+0x2407ffff, 0x2021, 0x461024, 0x1444000d,
+0x671824, 0x1465000b, 0x0, 0x8ee27b80,
+0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021,
+0x461024, 0x14440003, 0x671824, 0x1065000b,
+0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0,
+0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044,
+0x38420020, 0x8001b38, 0xaf820044, 0x8f820044,
+0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044,
+0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044,
+0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4,
+0x24060000, 0x2407ffff, 0x2021, 0x461024,
+0x1444000d, 0x671824, 0x1465000b, 0x0,
+0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4,
+0x2021, 0x461024, 0x14440003, 0x671824,
+0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80,
+0x8f820044, 0x38420040, 0x8001b38, 0xaf820044,
+0x8f820044, 0x34420040, 0x8001b38, 0xaf820044,
+0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c,
+0x24430001, 0x28420015, 0x14400028, 0xaee37b8c,
+0x8f820044, 0x38420020, 0xaf820044, 0x8001b38,
+0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011,
+0x0, 0x8f420218, 0x30420080, 0x10400009,
+0x0, 0x8f820044, 0x34420020, 0xaf820044,
+0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36,
+0xaf820044, 0x8f820044, 0x34420060, 0x8001b36,
+0xaf820044, 0x8f820044, 0x34420040, 0xaf820044,
+0x8ee27b88, 0x24430001, 0x28421389, 0x14400005,
+0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044,
+0xaee07b88, 0xc004603, 0x0, 0x8fbf0024,
+0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8,
+0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038,
+0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028,
+0x8f960064, 0x32c20004, 0x1040000c, 0x24020004,
+0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060,
+0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001,
+0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001,
+0x10400004, 0x24020001, 0xaf820064, 0x80022f4,
+0x0, 0x32c20002, 0x1440000c, 0x3c050003,
+0x3c040001, 0x24845354, 0x34a50001, 0x2c03021,
+0x3821, 0xafa00010, 0xc002403, 0xafa00014,
+0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c,
+0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c,
+0x21080, 0x5a1021, 0x8c420300, 0xafa20020,
+0x8f42022c, 0x24070001, 0x24420001, 0x3042003f,
+0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360,
+0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003,
+0xc002403, 0x34a5f01f, 0x3821, 0x14e00003,
+0x0, 0x80022ed, 0xaf960064, 0x93a20020,
+0x2443ffff, 0x2c620011, 0x10400658, 0x31080,
+0x3c010001, 0x220821, 0x8c225418, 0x400008,
+0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c,
+0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118,
+0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118,
+0x8fa20020, 0x24030001, 0x3c010001, 0x370821,
+0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060,
+0x34420100, 0xaf820060, 0x8ee20144, 0x24420001,
+0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020,
+0x21200, 0x22502, 0x24020001, 0x10820005,
+0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9,
+0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074,
+0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4,
+0xaee40070, 0xaee40074, 0x621824, 0xaee304d4,
+0x8f840054, 0x41442, 0x41c82, 0x431021,
+0x41cc2, 0x431023, 0x41d02, 0x431021,
+0x41d42, 0x431023, 0x8001bd0, 0xaee20078,
+0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020,
+0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110,
+0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110,
+0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
+0x920c0, 0x2e41021, 0x9442727c, 0x30424000,
+0x1040000a, 0x971021, 0x97430212, 0xa443727e,
+0x8f430214, 0x971021, 0xac437280, 0x2e41821,
+0x34028000, 0x8001c79, 0xa462727c, 0x9443727e,
+0x97420212, 0x14620006, 0x2e41021, 0x971021,
+0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021,
+0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff,
+0x2021, 0x410c0, 0x2e21021, 0x9442737c,
+0x30424000, 0x54400005, 0x803021, 0x24840001,
+0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010,
+0x618c0, 0x610c0, 0x571821, 0x8c63737c,
+0x571021, 0xafa30010, 0x8c427380, 0x3c040001,
+0x24845378, 0xafa20014, 0x8f470214, 0x3c050003,
+0xc002403, 0x34a50013, 0x8001c90, 0x3c020800,
+0x97440212, 0x771021, 0xa444737e, 0x8f440214,
+0x771021, 0x2e31821, 0xac447380, 0x34028000,
+0xa462737c, 0x910c0, 0x2e21021, 0x8001c79,
+0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e,
+0x510c0, 0x9443737e, 0x97420212, 0x14620006,
+0x510c0, 0x971021, 0x8c437380, 0x8f420214,
+0x10620065, 0x510c0, 0x2e21021, 0x9445737c,
+0x510c0, 0x2e21021, 0x9442737c, 0x30428000,
+0x1040fff0, 0x971021, 0x520c0, 0x971021,
+0x9443737e, 0x97420212, 0x14620006, 0x2406ffff,
+0x971021, 0x8c437380, 0x8f420214, 0x10620053,
+0x3c020800, 0x2021, 0x410c0, 0x2e21021,
+0x9442737c, 0x30424000, 0x54400005, 0x803021,
+0x24840001, 0x2c820080, 0x1440fff8, 0x410c0,
+0x4c10023, 0x618c0, 0x910c0, 0x571821,
+0x8c63727c, 0x571021, 0xafa30010, 0x8c427280,
+0x3c040001, 0x24845384, 0xafa20014, 0x8f470214,
+0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90,
+0x3c020800, 0x8f430210, 0xb71021, 0xac43777c,
+0x8f430214, 0xb71021, 0xac437780, 0x3c020001,
+0x571021, 0x8c4283b4, 0x24420001, 0x3c010001,
+0x370821, 0xac2283b4, 0x3c030001, 0x771821,
+0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c,
+0x97440212, 0x771021, 0xa444737e, 0x8f440214,
+0x771021, 0x2e31821, 0xac447380, 0x34028000,
+0xa462737c, 0x510c0, 0x2e21021, 0xa446737c,
+0x2021, 0x428c0, 0x2e51021, 0x9442777c,
+0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa,
+0x428c0, 0x92e204d8, 0x10400006, 0x24020001,
+0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f,
+0xaee304dc, 0x8f830228, 0x24020001, 0x1221004,
+0x621825, 0xaf830228, 0x3c020800, 0x34421000,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
+0x5821, 0x24100008, 0x240f000d, 0x240d0007,
+0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3821,
+0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee20608,
+0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
+0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
+0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144d001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8001cf5, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x8001d08, 0x0, 0x8ee24e30, 0x24420001,
+0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
+0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x10400061, 0x5821, 0x240e0008, 0x240d0011,
+0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x3821, 0x24420001, 0xaee201a4, 0x8001d74,
+0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
+0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144a001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x10480007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8001d61, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x8001d74, 0x0, 0x8ee24e30, 0x24420001,
+0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
+0x10620022, 0x0, 0x3c040001, 0x24845390,
+0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
+0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0,
+0x0, 0x3c040001, 0x2484539c, 0xafa00014,
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+0x34a5f010, 0x8001da0, 0x0, 0x3c040001,
+0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124,
+0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124,
+0x27440212, 0xc0022fe, 0x24050006, 0x3049001f,
+0x928c0, 0x2e51021, 0x9442727c, 0x30428000,
+0x1040002f, 0x2e51021, 0x9442727c, 0x30424000,
+0x1440001c, 0xb71021, 0x9443727e, 0x97420212,
+0x14620018, 0xb71021, 0x8c437280, 0x8f420214,
+0x54620016, 0xafa20010, 0x92e204d8, 0x10400007,
+0x24020001, 0x8ee304dc, 0x1221004, 0x21027,
+0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228,
+0x1221004, 0x21027, 0x621824, 0xaf830228,
+0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e,
+0xa462727c, 0x8f420214, 0xafa20010, 0x910c0,
+0x571021, 0x8c42727c, 0x3c040001, 0x248453b4,
+0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c,
+0xc002403, 0x1203021, 0x8001e83, 0x3c020800,
+0xb71021, 0x9443727e, 0x97420212, 0x14620019,
+0x918c0, 0xb71021, 0x8c437280, 0x8f420214,
+0x14620014, 0x918c0, 0x2e51021, 0x9447727c,
+0x720c0, 0x971021, 0x9443737e, 0xb71021,
+0xa443727e, 0x971021, 0x8c437380, 0xb71021,
+0xac437280, 0x2e41021, 0x9443737c, 0x2e51021,
+0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e,
+0xa462737c, 0x2e31021, 0x9447727c, 0x3021,
+0x720c0, 0x2e41021, 0x9442737c, 0x4021,
+0x30428000, 0x14400025, 0xe02821, 0x605021,
+0x340bc000, 0x971021, 0x9443737e, 0x97420212,
+0x54620015, 0xe02821, 0x971021, 0x8c437380,
+0x8f420214, 0x54620010, 0xe02821, 0x11000006,
+0x2e41021, 0x9443737c, 0x510c0, 0x2e21021,
+0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021,
+0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c,
+0x8001e28, 0x24060001, 0x510c0, 0x2e21021,
+0x9447737c, 0x720c0, 0x2e41021, 0x9442737c,
+0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff,
+0x14400025, 0x2021, 0x720c0, 0x971021,
+0x9443737e, 0x97420212, 0x1462000f, 0x910c0,
+0x971021, 0x8c437380, 0x8f420214, 0x1462000a,
+0x910c0, 0x2e41821, 0x3402c000, 0x15000015,
+0xa462737c, 0x910c0, 0x2e21821, 0x34028000,
+0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c,
+0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010,
+0x710c0, 0x571021, 0x8c42737c, 0x34a5001e,
+0x1203021, 0xc002403, 0xafa20014, 0x8001e83,
+0x3c020800, 0x2021, 0x428c0, 0xb71021,
+0x9443777e, 0x97420212, 0x5462002b, 0x24840001,
+0xb71021, 0x8c437780, 0x8f420214, 0x54620026,
+0x24840001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4,
+0x3c020001, 0x571021, 0x8c4283b4, 0x809021,
+0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784,
+0x2f02021, 0x2f12821, 0xc002490, 0x24060008,
+0x26310008, 0x3c020001, 0x571021, 0x8c4283b4,
+0x26520001, 0x242102b, 0x1440fff5, 0x26100008,
+0x3c040001, 0x972021, 0x8c8483b4, 0x24050008,
+0x420c0, 0x2484777c, 0xc002488, 0x2e42021,
+0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf,
+0x428c0, 0x3c020800, 0x34422000, 0xafa20018,
+0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff,
+0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0,
+0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+0xac440610, 0x8f830054, 0x8f820054, 0x24690032,
+0x1221023, 0x2c420033, 0x1040006a, 0x5821,
+0x24100008, 0x240f000d, 0x240d0007, 0x240c0040,
+0x240e0001, 0x8f870120, 0x27623800, 0x24e80020,
+0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+0x11020004, 0x0, 0x8f820124, 0x15020007,
+0x1021, 0x8ee201a4, 0x3821, 0x24420001,
+0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608,
+0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e,
+0xacef0018, 0xacea001c, 0x210c0, 0x2442060c,
+0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010,
+0xaf880120, 0x92e24e20, 0x14400033, 0x24070001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144d001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8001ee8,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x8001efb,
+0x0, 0x8ee24e30, 0x24420001, 0x504c0003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d,
+0x0, 0x316300ff, 0x24020001, 0x54620078,
+0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x10400061,
+0x5821, 0x240e0008, 0x240d0011, 0x240a0012,
+0x24080040, 0x240c0001, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x3821,
+0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4,
+0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4,
+0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400033, 0x24070001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144a001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10480007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8001f54,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x8001f67,
+0x0, 0x8ee24e30, 0x24420001, 0x50480003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001,
+0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6,
+0x0, 0x316300ff, 0x24020001, 0x10620022,
+0x0, 0x3c040001, 0x24845390, 0xafa00010,
+0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009,
+0xc002403, 0x34a5f011, 0x8001f93, 0x0,
+0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120,
+0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010,
+0x8001f93, 0x0, 0x3c040001, 0x248453a8,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001,
+0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001,
+0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001,
+0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020,
+0x21200, 0x21d02, 0x24020001, 0x10620005,
+0x24020002, 0x1062000d, 0x0, 0x8001fb7,
+0xafa00010, 0x92e204d8, 0x14400006, 0x24020001,
+0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228,
+0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8,
+0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228,
+0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8,
+0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
+0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c,
+0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200,
+0x22502, 0x24020001, 0x10820005, 0x24020002,
+0x1082000f, 0x0, 0x8001fe3, 0xafa00010,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
+0x370821, 0xa02283b2, 0x8001fea, 0xaee40108,
+0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024,
+0xaf820220, 0x3c010001, 0x370821, 0xa02083b2,
+0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4,
+0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403,
+0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c,
+0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200,
+0x21d02, 0x24020001, 0x10620005, 0x24020002,
+0x1062000e, 0x0, 0x8002011, 0xafa00010,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420008, 0xaf820220, 0x24020001, 0x3c010001,
+0x370821, 0x8002018, 0xa02283b3, 0x3c020001,
+0x571021, 0x904283b2, 0x3c010001, 0x370821,
+0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff,
+0x3463fff7, 0x431024, 0x8002018, 0xaf820220,
+0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020,
+0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114,
+0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114,
+0x27840208, 0x27450200, 0xc00249a, 0x24060008,
+0x26e40094, 0x27450200, 0xc00249a, 0x24060008,
+0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8,
+0x8ee20134, 0x8f460248, 0x2021, 0xc005108,
+0x24050004, 0x8ee20130, 0x24420001, 0xaee20130,
+0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0,
+0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001,
+0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070,
+0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0,
+0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070,
+0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
+0x27450200, 0x24060008, 0xaee20068, 0x24020006,
+0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00,
+0xaee2006c, 0x240203e8, 0x24040002, 0x24030001,
+0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220,
+0x30420008, 0x10400004, 0x0, 0xaee30108,
+0x8002061, 0x2021, 0xaee40108, 0x2021,
+0x3c030001, 0x641821, 0x90635c30, 0x2e41021,
+0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8,
+0x0, 0x8f820040, 0x2e41821, 0x24840001,
+0x21702, 0x24420030, 0xa062009c, 0x2e41021,
+0x80022e8, 0xa040009c, 0x24020001, 0x3c010001,
+0x370821, 0xa02283e0, 0x240b0400, 0x24080014,
+0x240a0040, 0x24090001, 0x8f830100, 0x27623000,
+0x24660020, 0xc2102b, 0x50400001, 0x27662800,
+0x8f820108, 0x10c20004, 0x0, 0x8f820104,
+0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821,
+0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8,
+0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e,
+0xac680018, 0xac60001c, 0xac640000, 0xac650004,
+0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec,
+0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001,
+0x504a0003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2,
+0x0, 0x80022e8, 0x0, 0x3c020900,
+0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244,
+0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1,
+0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001,
+0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608,
+0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c,
+0xac43060c, 0xac440610, 0x8f830054, 0x8f820054,
+0x24690032, 0x1221023, 0x2c420033, 0x1040006a,
+0x5821, 0x24100008, 0x240f000d, 0x240d0007,
+0x240c0040, 0x240e0001, 0x8f870120, 0x27623800,
+0x24e80020, 0x102102b, 0x50400001, 0x27683000,
+0x8f820128, 0x11020004, 0x0, 0x8f820124,
+0x15020007, 0x1021, 0x8ee201a4, 0x3821,
+0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4,
+0x8ee40608, 0x420c0, 0x801821, 0x8ee40430,
+0x8ee50434, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee20608,
+0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0,
+0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4,
+0xace20010, 0xaf880120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144d001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8002119, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x800212c, 0x0, 0x8ee24e30, 0x24420001,
+0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ff9d, 0x0, 0x316300ff, 0x24020001,
+0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x10400061, 0x5821, 0x240e0008, 0x240d0011,
+0x240a0012, 0x24080040, 0x240c0001, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x3821, 0x24420001, 0xaee201a4, 0x8002198,
+0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0,
+0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e,
+0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400033,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x144a001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x10480007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8002185, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x8002198, 0x0, 0x8ee24e30, 0x24420001,
+0x50480003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006,
+0x240b0001, 0x8f820054, 0x1221023, 0x2c420033,
+0x1440ffa6, 0x0, 0x316300ff, 0x24020001,
+0x10620022, 0x0, 0x3c040001, 0x24845390,
+0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124,
+0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4,
+0x0, 0x3c040001, 0x2484539c, 0xafa00014,
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+0x34a5f010, 0x80021c4, 0x0, 0x3c040001,
+0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120,
+0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168,
+0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168,
+0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260,
+0x27450200, 0x24060008, 0xc00249a, 0xaee20068,
+0x8f820220, 0x30420008, 0x14400002, 0x24020001,
+0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001,
+0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001,
+0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020,
+0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020,
+0x3c030700, 0x34631000, 0x431025, 0xafa20018,
+0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff,
+0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0,
+0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c,
+0xac440610, 0x8f870120, 0x27623800, 0x24e80020,
+0x102102b, 0x50400001, 0x27683000, 0x8f820128,
+0x11020004, 0x0, 0x8f820124, 0x15020007,
+0x1021, 0x8ee201a4, 0x3821, 0x24420001,
+0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608,
+0x420c0, 0x801821, 0x8ee40430, 0x8ee50434,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xace40000, 0xace50004, 0x8ee30608, 0x24020008,
+0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c,
+0x318c0, 0x2463060c, 0x2e31021, 0xace20008,
+0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+0x14400037, 0x24070001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c830000, 0x24020007,
+0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001,
+0x10430007, 0x0, 0x8ee24e34, 0x24420001,
+0x10a20005, 0x0, 0x8002247, 0x0,
+0x14a00005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x800225d, 0x0,
+0x8ee24e30, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020007, 0xac820000, 0x24020001, 0xac820004,
+0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4,
+0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0,
+0x0, 0x8f830120, 0x27623800, 0x24660020,
+0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
+0x10c20004, 0x0, 0x8f820124, 0x14c20007,
+0x0, 0x8ee201a4, 0x3821, 0x24420001,
+0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608,
+0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c,
+0xac620008, 0x24020008, 0xa462000e, 0x24020011,
+0xac620018, 0xac640000, 0xac650004, 0x8ee204c4,
+0xac620010, 0xaf860120, 0x92e24e20, 0x14400037,
+0x24070001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020012, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007,
+0x0, 0x8ee24e34, 0x24420001, 0x10a20005,
+0x0, 0x80022ae, 0x0, 0x14a00005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80022c4, 0x0, 0x8ee24e30,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x24020012,
+0xac820000, 0x24020001, 0xac820004, 0x14e0001b,
+0x0, 0x3c040001, 0x248453fc, 0xafa00010,
+0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009,
+0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001,
+0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001,
+0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228,
+0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac,
+0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150,
+0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160,
+0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c,
+0x8f42010c, 0x14620009, 0x24020002, 0xaf820064,
+0x8f820064, 0x14400005, 0x0, 0x8f43022c,
+0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044,
+0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034,
+0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008,
+0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014,
+0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000,
+0x24840001, 0x3021, 0x1071026, 0x30420001,
+0x10400002, 0x81842, 0x6a1826, 0x604021,
+0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842,
+0x25290001, 0x125102b, 0x1440fff0, 0x0,
+0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8,
+0x27642800, 0xafbf0010, 0xc002488, 0x24051000,
+0x24020021, 0xaf800100, 0xaf800104, 0xaf800108,
+0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120,
+0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134,
+0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30,
+0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040,
+0x10400004, 0x0, 0x8f82011c, 0x34420004,
+0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010,
+0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0,
+0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403,
+0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824,
+0x3c020400, 0x10620029, 0x43102b, 0x14400008,
+0x3c022000, 0x3c020100, 0x10620024, 0x3c020200,
+0x10620011, 0x0, 0x8002374, 0x0,
+0x10620008, 0x3c024000, 0x1462001c, 0x0,
+0x8ee20190, 0x24420001, 0xaee20190, 0x8002374,
+0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c,
+0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001,
+0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001,
+0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0,
+0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001,
+0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001,
+0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0,
+0x3c027f00, 0x621824, 0x3c020400, 0x10620053,
+0x8021, 0x43102b, 0x14400008, 0x3c042000,
+0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a,
+0x0, 0x80023e0, 0x0, 0x10640003,
+0x3c024000, 0x14620045, 0x0, 0x8f8200a0,
+0x441024, 0x10400006, 0x0, 0x8ee20194,
+0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194,
+0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c,
+0x30420200, 0x1040001b, 0x0, 0x8f8300a0,
+0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001,
+0x3c020001, 0x3442f000, 0x621024, 0x50400001,
+0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0,
+0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124,
+0x8f820124, 0x27633000, 0x43102b, 0x10400005,
+0x276237e0, 0xaf820124, 0x80023ca, 0x0,
+0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024,
+0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001,
+0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd,
+0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001,
+0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0,
+0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018,
+0x3e00008, 0x27bd0020, 0x0, 0x3c020001,
+0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012,
+0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021,
+0xc002488, 0x24052000, 0x26021fe0, 0x3c010001,
+0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250,
+0x24022000, 0xaf500254, 0xaf420258, 0x24020001,
+0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010,
+0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94,
+0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000,
+0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004,
+0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010,
+0xac470014, 0xac480018, 0xac49001c, 0x3c010001,
+0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0,
+0x62182b, 0x10600005, 0x0, 0x3c020001,
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
+0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
+0xac620004, 0x3e00008, 0xaf430250, 0x3c030001,
+0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0,
+0xafb40020, 0x8fb40040, 0xafb00010, 0x808021,
+0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014,
+0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018,
+0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001,
+0x8c425c40, 0xc09021, 0xe09821, 0x10800006,
+0xaca20004, 0x24a50008, 0xc002490, 0x24060018,
+0x800244e, 0x0, 0x24a40008, 0xc002488,
+0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001,
+0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94,
+0x45102b, 0x10400005, 0x0, 0x3c020001,
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001,
+0x8c635d94, 0x8e020004, 0xac620004, 0xac710008,
+0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94,
+0x45102b, 0xac720010, 0xac730014, 0xac740018,
+0xac75001c, 0x10400005, 0xac64000c, 0x3c020001,
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001,
+0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000,
+0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40,
+0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024,
+0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005,
+0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd,
+0x24840004, 0x3e00008, 0x0, 0x10c00007,
+0x0, 0x8c820000, 0x24840004, 0x24c6fffc,
+0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008,
+0x0, 0x10c00007, 0x0, 0x8ca20000,
+0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb,
+0x24840004, 0x3e00008, 0x0, 0x3e00008,
+0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4,
+0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4,
+0x8ee304fc, 0x21100, 0x626021, 0x95870008,
+0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c,
+0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b,
+0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258,
+0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003,
+0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c,
+0x8ee3726c, 0x441021, 0x62182b, 0x10600006,
+0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8,
+0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200,
+0x1040014d, 0x4821, 0x96e2045a, 0x30420010,
+0x10400149, 0x0, 0x8f840100, 0x27623000,
+0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001,
+0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000,
+0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e,
+0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c,
+0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec,
+0x14400036, 0x24090001, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f,
+0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
+0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
+0x0, 0x8002516, 0x0, 0x14a00005,
+0x0, 0x8f820108, 0x24420020, 0xaf820108,
+0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x800252c, 0x0, 0x8ee24e28,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
+0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
+0xac820000, 0x24020001, 0xac820004, 0x1520000a,
+0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001,
+0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
+0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800,
+0x3641821, 0x24420010, 0x43102b, 0x14400073,
+0x0, 0x8ee27264, 0x24480010, 0x3641021,
+0x102102b, 0x14400002, 0x3c02ffff, 0x1024021,
+0x8f850100, 0x27623000, 0x24a60020, 0xc2102b,
+0x50400001, 0x27662800, 0x8f820108, 0x10c20004,
+0x0, 0x8f820104, 0x14c20007, 0x2563000c,
+0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
+0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021,
+0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e,
+0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4,
+0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025,
+0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037,
+0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x8c830000, 0x24020005, 0x1462001f,
+0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b,
+0x24030040, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007,
+0x0, 0x8ee24e2c, 0x24420001, 0x10a20005,
+0x0, 0x800258a, 0x0, 0x14a00005,
+0x0, 0x8f820108, 0x24420020, 0xaf820108,
+0x8f820108, 0x8c820004, 0x2c420011, 0x50400013,
+0xac800000, 0x80025a0, 0x0, 0x8ee24e28,
+0x24030040, 0x24420001, 0x50430003, 0x1021,
+0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28,
+0x210c0, 0x24424e38, 0x2e22021, 0x24020005,
+0xac820000, 0x24020001, 0xac820004, 0x1520000a,
+0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001,
+0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4,
+0x80028be, 0x34a5f125, 0x34028100, 0xa5020000,
+0x9582000e, 0x800261d, 0xa5020002, 0x8f850100,
+0x27623000, 0x24a60020, 0xc2102b, 0x50400001,
+0x27662800, 0x8f820108, 0x10c20004, 0x0,
+0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8,
+0x4821, 0x24420001, 0xaee201a8, 0x800260d,
+0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000,
+0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e,
+0x24020006, 0xaca20018, 0x24630010, 0xaca30008,
+0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002,
+0x431025, 0xaca20010, 0xaf860100, 0x92e204ec,
+0x14400037, 0x24090001, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x8c830000, 0x24020005,
+0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c,
+0x1062001b, 0x24030040, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001,
+0x10430007, 0x0, 0x8ee24e2c, 0x24420001,
+0x10a20005, 0x0, 0x80025f7, 0x0,
+0x14a00005, 0x0, 0x8f820108, 0x24420020,
+0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011,
+0x50400013, 0xac800000, 0x800260d, 0x0,
+0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x24020005, 0xac820000, 0x24020001, 0xac820004,
+0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264,
+0x3c040001, 0x24845730, 0x3c050004, 0xafa20014,
+0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264,
+0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e,
+0x8002681, 0x24e70004, 0x8f840100, 0x27623000,
+0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+0x14a20007, 0x24020006, 0x8ee201a8, 0x4821,
+0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8,
+0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e,
+0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c,
+0x8ee204c8, 0x3c030002, 0x431025, 0xac820010,
+0xaf850100, 0x92e204ec, 0x14400037, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c830000, 0x24020005, 0x1462001f, 0x0,
+0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+0x8002661, 0x0, 0x14a00005, 0x0,
+0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8002677, 0x0, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+0x24020001, 0xac820004, 0x15200009, 0x3c050004,
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004,
+0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c,
+0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100,
+0x431021, 0xac44000c, 0x8ee27258, 0xafa20018,
+0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
+0x10400004, 0x24620001, 0x2403fffe, 0x431024,
+0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800,
+0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007,
+0x451024, 0x24630007, 0xaee27258, 0x8ee2726c,
+0x8ee47258, 0x651824, 0x431023, 0xaee2726c,
+0x3661021, 0x82202b, 0x14800004, 0x3c03ffff,
+0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258,
+0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800,
+0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4,
+0x14e20007, 0x0, 0x8ee201b4, 0x4821,
+0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4,
+0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c,
+0xac430000, 0xac440004, 0xaf8700f0, 0x15200012,
+0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4,
+0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018,
+0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005,
+0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088,
+0x80028d3, 0xaee0725c, 0x30430003, 0x24020002,
+0x10620016, 0x28620003, 0x10400005, 0x24020001,
+0x10620008, 0x0, 0x8002703, 0x0,
+0x24020003, 0x10620017, 0x0, 0x8002703,
+0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
+0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
+0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0,
+0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
+0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703,
+0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0,
+0x8ee500e4, 0x401821, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xaee400e0,
+0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff,
+0x104001c1, 0x31a20200, 0x1040014d, 0x4821,
+0x96e2045a, 0x30420010, 0x10400149, 0x0,
+0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
+0x50400001, 0x27652800, 0x8f820108, 0x10a20004,
+0x0, 0x8f820104, 0x14a20006, 0x2402000c,
+0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e,
+0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264,
+0x24060005, 0xa482000e, 0xac860018, 0xac830008,
+0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010,
+0xaf850100, 0x92e204ec, 0x14400036, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c820000, 0x1446001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x8002758,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x800276e,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1520000a, 0x3c040001, 0xafab0010,
+0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014,
+0x8ee27264, 0x34843800, 0x3641821, 0x24420010,
+0x43102b, 0x14400073, 0x0, 0x8ee27264,
+0x24480010, 0x3641021, 0x102102b, 0x14400002,
+0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000,
+0x24a60020, 0xc2102b, 0x50400001, 0x27662800,
+0x8f820108, 0x10c20004, 0x0, 0x8f820104,
+0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821,
+0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8,
+0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004,
+0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008,
+0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8,
+0x3c030002, 0x431025, 0xaca20010, 0xaf860100,
+0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28,
+0x210c0, 0x24424e38, 0x2e22021, 0x8c830000,
+0x24020005, 0x1462001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x80027cc,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x80027e2,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010,
+0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004,
+0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015,
+0x34028100, 0xa5020000, 0x9582000e, 0x800285f,
+0xa5020002, 0x8f850100, 0x27623000, 0x24a60020,
+0xc2102b, 0x50400001, 0x27662800, 0x8f820108,
+0x10c20004, 0x0, 0x8f820104, 0x14c20007,
+0x2563000c, 0x8ee201a8, 0x4821, 0x24420001,
+0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c,
+0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264,
+0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018,
+0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c,
+0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010,
+0xaf860100, 0x92e204ec, 0x14400037, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c830000, 0x24020005, 0x1462001f, 0x0,
+0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+0x8002839, 0x0, 0x14a00005, 0x0,
+0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x800284f, 0x0, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+0x24020001, 0xac820004, 0x1520000a, 0x34028100,
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730,
+0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be,
+0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264,
+0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004,
+0x8f830100, 0x27623000, 0x24640020, 0x82102b,
+0x50400001, 0x27642800, 0x8f820108, 0x10820004,
+0x0, 0x8f820104, 0x14820007, 0x24050005,
+0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8,
+0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004,
+0x8ee27264, 0xa467000e, 0xac650018, 0xac620008,
+0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010,
+0xaf840100, 0x92e204ec, 0x14400036, 0x24090001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x80028a0,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x80028b6,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1520000b, 0x3c050004, 0x3c040001,
+0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4,
+0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1,
+0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff,
+0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264,
+0x34a53800, 0x441021, 0xaee2725c, 0x3651021,
+0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264,
+0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458,
+0x24630001, 0x2442ffff, 0x621824, 0xaee304e4,
+0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0,
+0x8f820060, 0x2403fff7, 0x431024, 0xaf820060,
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0,
+0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189,
+0x0, 0x8ee204e8, 0x8ee304fc, 0x21100,
+0x621821, 0x94670008, 0x92e204ed, 0x8c680000,
+0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8,
+0x34460400, 0x31420200, 0x1040001f, 0x0,
+0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000,
+0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264,
+0x9464000e, 0x3c050001, 0x34a53800, 0x24420004,
+0xaee27264, 0x8ee37264, 0x42400, 0x3651021,
+0x3c010001, 0x370821, 0xac2483dc, 0x62182b,
+0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff,
+0x431021, 0xaee27264, 0x8ee27264, 0x8002917,
+0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff,
+0x44102a, 0x10400015, 0x0, 0x8f8200d8,
+0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c,
+0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001,
+0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a,
+0x10400006, 0x0, 0x8ee201b8, 0x24420001,
+0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001,
+0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc,
+0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001,
+0x571021, 0x8c4283d8, 0x1040002f, 0x5021,
+0x8f840100, 0x27623000, 0x24850020, 0xa2102b,
+0x50400001, 0x27652800, 0x8f820108, 0x10a20032,
+0x0, 0x8f820104, 0x10a2002f, 0x24020015,
+0xac880000, 0xac890004, 0x8ee37264, 0xa487000e,
+0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001,
+0x771821, 0x8c6383dc, 0xac860010, 0x431025,
+0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066,
+0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e21821, 0x24020015, 0xac620000, 0x24020001,
+0x80029bf, 0xac620004, 0x8f840100, 0x27623000,
+0x24850020, 0xa2102b, 0x50400001, 0x27652800,
+0x8f820108, 0x10a20004, 0x0, 0x8f820104,
+0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001,
+0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000,
+0xac890004, 0x8ee37264, 0xa487000e, 0xac820018,
+0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c,
+0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c830000, 0x24020005, 0x1462001f, 0x0,
+0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c,
+0x8ee54e28, 0x24420001, 0x10430007, 0x0,
+0x8ee24e2c, 0x24420001, 0x10a20005, 0x0,
+0x80029a9, 0x0, 0x14a00005, 0x0,
+0x8f820108, 0x24420020, 0xaf820108, 0x8f820108,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x80029bf, 0x0, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e22021, 0x24020005, 0xac820000,
+0x24020001, 0xac820004, 0x1540000a, 0x24020001,
+0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730,
+0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f,
+0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc,
+0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001,
+0x370821, 0xac2083d8, 0x3c010001, 0x370821,
+0xac2083dc, 0x21100, 0x431021, 0xac44000c,
+0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021,
+0x24420007, 0x451024, 0x24630007, 0xaee27258,
+0x8ee2726c, 0x8ee47258, 0x651824, 0x431023,
+0xaee2726c, 0x3661021, 0x82202b, 0x14800004,
+0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258,
+0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073,
+0x0, 0x8f830100, 0x27623000, 0x24640020,
+0x82102b, 0x14400002, 0x5021, 0x27642800,
+0x8f820108, 0x10820004, 0x0, 0x8f820104,
+0x14820006, 0x24050005, 0x8ee201a8, 0x24420001,
+0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000,
+0xac690004, 0x8ee27264, 0xa467000e, 0xac650018,
+0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c,
+0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021,
+0x8c820000, 0x1445001f, 0x0, 0x8ee34e28,
+0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28,
+0x24420001, 0x10430007, 0x0, 0x8ee24e2c,
+0x24420001, 0x10a20005, 0x0, 0x8002a30,
+0x0, 0x14a00005, 0x0, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8002a46,
+0x0, 0x8ee24e28, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e28, 0x24420001,
+0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38,
+0x2e22021, 0x24020005, 0xac820000, 0x24020001,
+0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001,
+0x24845748, 0x3c050004, 0xafa90010, 0xafa00014,
+0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff,
+0x8002a72, 0x0, 0x8ee27264, 0x451021,
+0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001,
+0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c,
+0x3641021, 0x62182b, 0x14600004, 0x3c03ffff,
+0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8,
+0x96e20458, 0x24630001, 0x2442ffff, 0x621824,
+0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005,
+0x0, 0x8f820060, 0x2403fff7, 0x431024,
+0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100,
+0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040,
+0x24630001, 0x50620003, 0x1021, 0x8ee24e2c,
+0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c,
+0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28,
+0x8c870004, 0x14620007, 0xa03021, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2,
+0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e2c, 0x24420001,
+0x210c0, 0x24424e38, 0x2e22021, 0x8c820004,
+0x8f830108, 0x21140, 0x621821, 0xaf830108,
+0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013,
+0x104000c1, 0x31080, 0x3c010001, 0x220821,
+0x8c225770, 0x400008, 0x0, 0x8ee204f0,
+0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c,
+0x43102b, 0x144000be, 0x0, 0x8ee304e4,
+0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8002b12,
+0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
+0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30,
+0x24420001, 0x10430007, 0x0, 0x8ee24e34,
+0x24420001, 0x10a20005, 0x0, 0x8002afc,
+0x0, 0x14a00005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8002b12,
+0x0, 0x8ee24e30, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020012, 0xac820000, 0x24020001,
+0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4,
+0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f006, 0x16000003, 0x24020001, 0x8002b71,
+0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170,
+0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0,
+0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274,
+0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184,
+0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee20504,
+0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018,
+0x21080, 0x571021, 0x8c440508, 0x24020003,
+0x1462000f, 0x0, 0x3c020001, 0x571021,
+0x904283b1, 0x10400014, 0x0, 0x8ee201d0,
+0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8,
+0x641821, 0x306300ff, 0x8002b59, 0xaee35240,
+0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc,
+0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10,
+0x441021, 0xaee201d8, 0x8ee20000, 0x34420040,
+0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001,
+0x370821, 0xa02083e0, 0x24420001, 0xaee2014c,
+0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c,
+0x3c040001, 0x24845760, 0xafa60014, 0xafa20010,
+0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058,
+0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048,
+0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104,
+0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001,
+0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018,
+0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf,
+0x31080, 0x3c010001, 0x220821, 0x8c2257c0,
+0x400008, 0x0, 0x9663000e, 0x8ee2725c,
+0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c,
+0x96e20458, 0x24840001, 0xaee404f0, 0x24630001,
+0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c,
+0x82202b, 0x148003b9, 0x0, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8021, 0x24420001, 0xaee201a4, 0x8002bfe,
+0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0,
+0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020012, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x104c0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8002be8,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400013, 0xac800000, 0x8002bfe,
+0x0, 0x8ee24e30, 0x240c0040, 0x24420001,
+0x504c0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x24020012, 0x240c0001, 0xac820000,
+0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4,
+0x3c040001, 0x24845754, 0xafa00014, 0xafa20010,
+0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006,
+0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a,
+0x240c0001, 0x8002f19, 0x0, 0x966c001c,
+0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024,
+0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc,
+0x151900, 0x621021, 0x8c52000c, 0x92e27b98,
+0x641821, 0x9476000a, 0x14400003, 0x32c20002,
+0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021,
+0x96e2045a, 0x30420002, 0x10400047, 0x0,
+0x8e63001c, 0x8ee204fc, 0x32100, 0x821021,
+0x8c42000c, 0x37e1821, 0x24420022, 0x43102b,
+0x1440000a, 0x24050014, 0x8ee204fc, 0x821021,
+0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e,
+0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc,
+0x821021, 0x8c42000c, 0x9450000e, 0x94430010,
+0x94440012, 0x94450014, 0x2038021, 0x2048021,
+0x2058021, 0x94430016, 0x94440018, 0x9445001a,
+0x2038021, 0x2048021, 0x2058021, 0x9443001c,
+0x9444001e, 0x94420020, 0x2038021, 0x2048021,
+0x2028021, 0x101c02, 0x3202ffff, 0x628021,
+0x8e63001c, 0x8ee204fc, 0x102402, 0x32900,
+0xa21021, 0x8c43000c, 0x3202ffff, 0x828021,
+0x37e1021, 0x24630018, 0x62182b, 0x14600009,
+0x0, 0x8ee204fc, 0xa21021, 0x8c43000c,
+0x101027, 0x3c01ffff, 0x230821, 0x8002c6f,
+0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c,
+0x101027, 0xa4620018, 0x96e2045a, 0x8821,
+0x30420008, 0x14400063, 0xa021, 0x8e63001c,
+0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c,
+0x37e1821, 0x24420022, 0x43102b, 0x14400035,
+0x0, 0x8ee204fc, 0xc21021, 0x8c42000c,
+0x24470010, 0x37e1021, 0xe2102b, 0x50400001,
+0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021,
+0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b,
+0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc,
+0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a,
+0x37e1021, 0xe2102b, 0x14400002, 0x2838821,
+0xeb3821, 0x94e20000, 0x24e70002, 0x2228821,
+0x37e1021, 0xe2102b, 0x50400001, 0xeb3821,
+0x94e20000, 0x24e70002, 0x2228821, 0x37e1021,
+0xe2102b, 0x50400001, 0xeb3821, 0x94e20000,
+0x24e70002, 0x2228821, 0x37e1021, 0xe2102b,
+0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0,
+0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c,
+0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021,
+0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec,
+0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821,
+0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821,
+0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c,
+0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020,
+0x2238821, 0x2248821, 0x2228821, 0x111c02,
+0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
+0x628821, 0x32c20001, 0x104000b2, 0x0,
+0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080,
+0x10400008, 0x0, 0x92e27b98, 0x14400005,
+0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c,
+0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021,
+0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b,
+0x14400008, 0xe02021, 0x2405000e, 0xc002f75,
+0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09,
+0x2028021, 0x94e60000, 0x24e70002, 0x94e50000,
+0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000,
+0x24e70002, 0x94e40000, 0x24e70002, 0x2068021,
+0x2058021, 0x2038021, 0x2028021, 0x94e20000,
+0x94e30002, 0x2048021, 0x2028021, 0x2038021,
+0x101c02, 0x3202ffff, 0x628021, 0x101c02,
+0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004,
+0x3205ffff, 0x96620016, 0x8002d17, 0x512021,
+0x96620016, 0x542021, 0x41402, 0x3083ffff,
+0x432021, 0x852023, 0x41402, 0x822021,
+0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4,
+0x24430017, 0x37e1021, 0x62102b, 0x50400001,
+0x6b1821, 0x90630000, 0x24020011, 0x14620031,
+0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028,
+0x43102b, 0x14400018, 0x0, 0x8ee27b9c,
+0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff,
+0x220821, 0x94220028, 0x822021, 0x41c02,
+0x3082ffff, 0x622021, 0x32c20100, 0x14400004,
+0x41027, 0x92e27b98, 0x14400002, 0x41027,
+0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821,
+0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008,
+0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021,
+0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
+0x14400004, 0x41027, 0x92e27b98, 0x14400002,
+0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a,
+0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4,
+0x24420032, 0x43102b, 0x14400018, 0x0,
+0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4,
+0x3c01ffff, 0x220821, 0x94220032, 0x822021,
+0x41c02, 0x3082ffff, 0x622021, 0x32c20100,
+0x14400004, 0x41027, 0x92e27b98, 0x14400002,
+0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff,
+0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c,
+0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032,
+0x822021, 0x41c02, 0x3082ffff, 0x622021,
+0x32c20100, 0x14400004, 0x41027, 0x92e27b98,
+0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4,
+0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821,
+0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b,
+0x1440001b, 0x34038100, 0x26430004, 0x37e1021,
+0x62102b, 0x14400003, 0x602021, 0x6b1821,
+0x602021, 0x8c620000, 0x24630004, 0xae420000,
+0x37e1021, 0x62102b, 0x50400001, 0x6b1821,
+0x8c620000, 0xac820000, 0x34028100, 0xa4620000,
+0x24630002, 0x37e1021, 0x62102b, 0x50400001,
+0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000,
+0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e,
+0xa64c000a, 0xae420000, 0xae440004, 0x9662000e,
+0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e,
+0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018,
+0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c,
+0x10400004, 0x24620001, 0x2403fffe, 0x431024,
+0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100,
+0x8ee27ba8, 0x24430001, 0x210c0, 0x571021,
+0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac,
+0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072,
+0x0, 0x8ee27ba8, 0x24430001, 0x210c0,
+0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c,
+0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063,
+0x4821, 0x5021, 0x8f8200f0, 0x24480008,
+0x27621800, 0x102102b, 0x50400001, 0x27681000,
+0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4,
+0x8021, 0x24420001, 0xaee201b4, 0x8002dfa,
+0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021,
+0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004,
+0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088,
+0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088,
+0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c,
+0x401821, 0x1021, 0xa32821, 0xa3382b,
+0x822021, 0x872021, 0x8ee204fc, 0xc93021,
+0x63100, 0xaee400e0, 0xaee500e4, 0xc23021,
+0x94c2000a, 0x240c0002, 0x21142, 0x30430003,
+0x106c0016, 0x28620003, 0x10400005, 0x240c0001,
+0x106c0008, 0x0, 0x8002e3f, 0x0,
+0x240c0003, 0x106c0017, 0x0, 0x8002e3f,
+0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001,
+0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec,
+0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0,
+0x8ee300f4, 0x24630001, 0x2c640001, 0x441021,
+0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f,
+0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001,
+0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98,
+0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008,
+0x27621800, 0xe2102b, 0x50400001, 0x27671000,
+0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4,
+0x8021, 0x24420001, 0xaee201b4, 0x8002e5d,
+0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018,
+0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0,
+0x16000007, 0x0, 0x8ee20088, 0x24420001,
+0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c,
+0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002,
+0x401821, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0x161142, 0x30430003,
+0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003,
+0x10400005, 0x240c0001, 0x106c0008, 0x0,
+0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019,
+0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8,
+0x8ee300ec, 0x24630001, 0x2c640001, 0x441021,
+0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec,
+0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4,
+0x24630001, 0x2c640001, 0x441021, 0xaee200f0,
+0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0,
+0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc,
+0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c,
+0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff,
+0x431024, 0x24840001, 0xaee204e4, 0xaee404f0,
+0x8f42023c, 0x82202b, 0x148000b0, 0x0,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c,
+0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400037, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x104c0007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8002ef1, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x8002f07, 0x0, 0x8ee24e30, 0x240c0040,
+0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020012, 0x240c0001,
+0xac820000, 0xac8c0004, 0x5600000d, 0x24100001,
+0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014,
+0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009,
+0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038,
+0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4,
+0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170,
+0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274,
+0xaee204f8, 0x8f42023c, 0x10400038, 0x0,
+0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c,
+0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001,
+0x504c0003, 0x1021, 0x8ee20504, 0x24420001,
+0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003,
+0x21080, 0x571021, 0x146c000f, 0x8c440508,
+0x3c020001, 0x571021, 0x904283b1, 0x10400014,
+0x0, 0x8ee201d0, 0x8ee35240, 0x441021,
+0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff,
+0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10,
+0x441021, 0xaee201cc, 0x8ee201d8, 0x641821,
+0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8,
+0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000,
+0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0,
+0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x8f820108,
+0x27633000, 0x43102b, 0x14400002, 0x27622800,
+0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e,
+0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058,
+0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048,
+0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068,
+0x52843, 0x10a0000d, 0x3021, 0x3c030001,
+0x34633800, 0x3c07ffff, 0x3631021, 0x82102b,
+0x50400001, 0x872021, 0x94820000, 0x24840002,
+0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02,
+0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff,
+0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88,
+0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068,
+0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058,
+0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c,
+0x8ee204d4, 0x8021, 0x30420001, 0x1440002a,
+0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8,
+0xe22023, 0x2c821000, 0x50400001, 0x24841000,
+0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8,
+0x3c02000a, 0x3442efff, 0x1032023, 0x44102b,
+0x10400003, 0x3c02000a, 0x3442f000, 0x822021,
+0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4,
+0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021,
+0x904283c0, 0x1040000b, 0x0, 0x3c140001,
+0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821,
+0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193,
+0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007,
+0x8821, 0x8f8200e4, 0x24110001, 0x8c430000,
+0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e,
+0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8,
+0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0,
+0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000,
+0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018,
+0x3074ffff, 0x2694fffc, 0x621024, 0x10400058,
+0x2409821, 0x3c020080, 0x621024, 0x1040000a,
+0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c,
+0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc,
+0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001,
+0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080,
+0x3c080020, 0x34078000, 0x24420001, 0xaee20080,
+0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021,
+0xc3102b, 0x14400007, 0x0, 0x106b0011,
+0x0, 0x106a0015, 0x0, 0x8003049,
+0x42042, 0x10650023, 0xa3102b, 0x14400005,
+0x0, 0x10690019, 0x0, 0x8003049,
+0x42042, 0x10680021, 0x0, 0x8003049,
+0x42042, 0x8ee20034, 0x24420001, 0xaee20034,
+0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec,
+0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049,
+0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0,
+0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4,
+0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049,
+0x42042, 0x8ee20030, 0x24420001, 0xaee20030,
+0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8,
+0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042,
+0x1087047c, 0x0, 0x800300e, 0x0,
+0x3c020001, 0x571021, 0x904283b2, 0x14400084,
+0x24020001, 0x3c030001, 0x771821, 0x906383b3,
+0x1462007f, 0x3c020100, 0x8e430000, 0x621024,
+0x1040006f, 0x2402ffff, 0x14620005, 0x24100001,
+0x96430004, 0x3402ffff, 0x10620075, 0x0,
+0x92e204d8, 0x14400072, 0x0, 0x3c020001,
+0x571021, 0x8c4283b4, 0x28420005, 0x10400020,
+0x3821, 0x3c020001, 0x571021, 0x8c4283b4,
+0x18400016, 0x2821, 0x96660000, 0x520c0,
+0x971021, 0x9442777e, 0x14460009, 0x971021,
+0x94437780, 0x96620002, 0x14620005, 0x971021,
+0x94437782, 0x96620004, 0x50620008, 0x24070001,
+0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001,
+0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff,
+0x10400440, 0x0, 0x80030d5, 0x0,
+0x2402021, 0xc0022fe, 0x24050006, 0x3044001f,
+0x428c0, 0x2e51021, 0x9442727c, 0x30424000,
+0x14400434, 0xb71021, 0x9443727e, 0x96620000,
+0x1462000b, 0x418c0, 0xb71021, 0x94437280,
+0x96620002, 0x14620006, 0x418c0, 0xb71021,
+0x94437282, 0x96620004, 0x10620035, 0x418c0,
+0x2e31021, 0x9442727c, 0x30428000, 0x14400421,
+0x2e31021, 0x944b727c, 0x96670000, 0xb28c0,
+0xb71021, 0x9442737e, 0x80030b7, 0x3021,
+0x420c0, 0x2e41021, 0x9443737c, 0x2e41021,
+0x944b737c, 0x30638000, 0x14600010, 0xb28c0,
+0xb71021, 0x9442737e, 0x1447fff5, 0x1602021,
+0xb71021, 0x94437380, 0x96620002, 0x5462fff1,
+0x420c0, 0xb71021, 0x94437382, 0x96620004,
+0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff,
+0x10400400, 0x0, 0x80030d5, 0x0,
+0x97430202, 0x96420000, 0x146203fa, 0x0,
+0x97430204, 0x96420002, 0x146203f6, 0x0,
+0x97430206, 0x96420004, 0x146203f2, 0x0,
+0x92420000, 0x3a030001, 0x30420001, 0x431024,
+0x10400074, 0x2402ffff, 0x8e630000, 0x14620004,
+0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002,
+0x3c020001, 0x571021, 0x904283b2, 0x1440006a,
+0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c,
+0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+0x10400020, 0x3821, 0x3c020001, 0x571021,
+0x8c4283b4, 0x18400016, 0x2821, 0x96660000,
+0x520c0, 0x971021, 0x9442777e, 0x14460009,
+0x971021, 0x94437780, 0x96620002, 0x14620005,
+0x971021, 0x94437782, 0x96620004, 0x50620008,
+0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6,
+0x0, 0x2402021, 0xc0022fe, 0x24050006,
+0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+0x30424000, 0x144003af, 0xb71021, 0x9443727e,
+0x96620000, 0x1462000b, 0x418c0, 0xb71021,
+0x94437280, 0x96620002, 0x14620006, 0x418c0,
+0xb71021, 0x94437282, 0x96620004, 0x10620027,
+0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+0x1440039c, 0x2e31021, 0x944b727c, 0x96670000,
+0xb28c0, 0xb71021, 0x9442737e, 0x800313c,
+0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+0x2e41021, 0x944b737c, 0x30638000, 0x14600010,
+0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5,
+0x1602021, 0xb71021, 0x94437380, 0x96620002,
+0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+0x96620004, 0x5462ffec, 0x420c0, 0x24060001,
+0x30c200ff, 0x1040037b, 0x0, 0x800314f,
+0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260,
+0x54102b, 0x1040003a, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
+0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+0xc002403, 0x34a5f003, 0x80034cc, 0x0,
+0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0,
+0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0,
+0x2403ffbf, 0x431024, 0x8003470, 0xaee20000,
+0x96e20468, 0x54102b, 0x10400003, 0x0,
+0x240f0001, 0xa3af0027, 0x12800301, 0x24160007,
+0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c,
+0x8f430280, 0x24420001, 0x304207ff, 0x106202d3,
+0x0, 0x93a20027, 0x10400014, 0x0,
+0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244,
+0x8ee65244, 0x8ee35244, 0x21140, 0x24425248,
+0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff,
+0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0,
+0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
+0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18,
+0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021,
+0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010,
+0x10400019, 0x0, 0x9642000c, 0x340f8100,
+0x144f0015, 0x0, 0x3c020001, 0x571021,
+0x904283c0, 0x14400010, 0x0, 0x9642000e,
+0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000,
+0x2694fffc, 0xae42000c, 0xae430008, 0xae440004,
+0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037,
+0x34420200, 0xa602000e, 0x8e020000, 0x8e030004,
+0x3c040001, 0x34843800, 0x306a0007, 0x26a9823,
+0x3641021, 0x262102b, 0x10400005, 0x28aa021,
+0x2641023, 0x3621823, 0x3c020020, 0x439823,
+0x26820007, 0x2404fff8, 0x9603000a, 0x446024,
+0x6a1821, 0x6c102b, 0x10400002, 0x1803821,
+0x603821, 0xae130018, 0x8f880120, 0x24e20007,
+0x443824, 0x27623800, 0x25090020, 0x122102b,
+0x50400001, 0x27693000, 0x8f820128, 0x11220004,
+0x0, 0x8f820124, 0x15220007, 0x1401821,
+0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
+0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004,
+0x1021, 0xad130008, 0xa507000e, 0xad160018,
+0xad06001c, 0xa3302b, 0xa32823, 0x822023,
+0x862023, 0xad040000, 0xad050004, 0x8ee204c0,
+0xad020010, 0xaf890120, 0x92e24e20, 0x14400033,
+0x24110001, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c820000, 0x1456001f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x10550007, 0x0,
+0x8ee24e34, 0x24420001, 0x10620005, 0x0,
+0x8003239, 0x0, 0x14600005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400010, 0xac800000,
+0x800324c, 0x0, 0x8ee24e30, 0x24420001,
+0x50550003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0xac960000, 0xac9e0004, 0x16200018,
+0x3c050006, 0x8e020018, 0x3c040001, 0x24845890,
+0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009,
+0x2003021, 0xc002403, 0xafa30014, 0x93a20037,
+0x10400216, 0x340f8100, 0x8e420004, 0x8e430008,
+0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004,
+0xae440008, 0x96020016, 0x8003470, 0xa642000e,
+0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e,
+0x28a1023, 0xa602000a, 0x34620004, 0xa602000e,
+0x8f880120, 0x27623800, 0x25090020, 0x122102b,
+0x14400002, 0x306affff, 0x27693000, 0x8f820128,
+0x11220004, 0x0, 0x8f820124, 0x15220007,
+0x24040020, 0x8ee201a4, 0x8821, 0x24420001,
+0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c,
+0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004,
+0xad100008, 0xad040018, 0x52940, 0xa01821,
+0x1021, 0xe33821, 0xe3202b, 0xc23021,
+0xc43021, 0xad060000, 0xad070004, 0x8ee2724c,
+0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
+0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
+0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x0, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
+0x10550007, 0x0, 0x8ee24e34, 0x24420001,
+0x10620005, 0x0, 0x80032b7, 0x0,
+0x14600005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400010, 0xac800000, 0x80032ca, 0x0,
+0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0xac960000,
+0xac9e0004, 0x1620000d, 0x0, 0xa60c000a,
+0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104,
+0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
+0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001,
+0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8,
+0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
+0x24630001, 0x306307ff, 0x26e25244, 0x15a20006,
+0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
+0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
+0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073,
+0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
+0x8f430240, 0x43102b, 0x14400176, 0xa021,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4,
+0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
+0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400033, 0x24110001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x144e001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10550007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x800333c,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x800334f,
+0x0, 0x8ee24e30, 0x24420001, 0x50550003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001,
+0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014,
+0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009,
+0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048,
+0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001,
+0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120,
+0x27623800, 0x24660020, 0xc2102b, 0x50400001,
+0x27663000, 0x8f820128, 0x10c20004, 0x0,
+0x8f820124, 0x14c20007, 0x0, 0x8ee201a4,
+0x8821, 0x24420001, 0xaee201a4, 0x80033ba,
+0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8,
+0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008,
+0xa462000e, 0x24020011, 0xac620018, 0xac640000,
+0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c820000,
+0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34,
+0x1062001b, 0x0, 0x8c820004, 0x24420001,
+0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001,
+0x10550007, 0x0, 0x8ee24e34, 0x24420001,
+0x10620005, 0x0, 0x80033a7, 0x0,
+0x14600005, 0x0, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011,
+0x50400010, 0xac800000, 0x80033ba, 0x0,
+0x8ee24e30, 0x24420001, 0x50550003, 0x1021,
+0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0xac8e0000,
+0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c,
+0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
+0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008,
+0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174,
+0x24420001, 0xaee20174, 0x8ee20174, 0x800346e,
+0xa021, 0x960c000a, 0x183102b, 0x54400001,
+0x1801821, 0xa603000a, 0x8f880120, 0x27623800,
+0x25090020, 0x122102b, 0x50400001, 0x27693000,
+0x8f820128, 0x11220004, 0x0, 0x8f820124,
+0x15220007, 0x24040020, 0x8ee201a4, 0x8821,
+0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4,
+0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e,
+0x24040004, 0xad100008, 0xad040018, 0x52940,
+0xa01821, 0x1021, 0xe33821, 0xe3202b,
+0xc23021, 0xc43021, 0xad060000, 0xad070004,
+0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010,
+0xaf890120, 0x92e24e20, 0x14400033, 0x24110001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x1456001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10550007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x800341c,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400010, 0xac800000, 0x800342f,
+0x0, 0x8ee24e30, 0x24420001, 0x50550003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0xac960000, 0xac9e0004, 0x1620001d, 0x0,
+0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104,
+0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014,
+0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821,
+0x93a20037, 0x10400031, 0x340f8100, 0x8e420004,
+0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000,
+0xae430004, 0xae440008, 0x96020016, 0xa642000e,
+0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e,
+0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8,
+0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821,
+0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a,
+0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821,
+0x93202b, 0x10800003, 0x3c02fff5, 0x34421000,
+0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001,
+0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004,
+0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c,
+0xa3a00027, 0x1680fd29, 0x0, 0x12800024,
+0x0, 0x3c010001, 0x370821, 0xac3483c4,
+0x3c010001, 0x370821, 0xac3383c8, 0x3c010001,
+0x370821, 0xac3283cc, 0x93a20037, 0x10400008,
+0x0, 0x3c020001, 0x571021, 0x8c4283cc,
+0x24420004, 0x3c010001, 0x370821, 0xac2283cc,
+0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff,
+0x14620006, 0x0, 0x8ee201c4, 0x24420001,
+0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc,
+0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc,
+0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
+0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaee400c0, 0xaee500c4,
+0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003,
+0x14400017, 0x24020003, 0x15e20015, 0x0,
+0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
+0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
+0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
+0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
+0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc,
+0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
+0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
+0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
+0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070,
+0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060,
+0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050,
+0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044,
+0xa821, 0xafb00030, 0x8021, 0xafbf004c,
+0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038,
+0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001,
+0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4,
+0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
+0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
+0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
+0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
+0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
+0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
+0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001,
+0x571021, 0x904283c0, 0x1040000b, 0x0,
+0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001,
+0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021,
+0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
+0x10430007, 0x4821, 0x8f8200e4, 0x24090001,
+0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
+0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
+0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014,
+0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
+0x34a5f000, 0x8003850, 0x0, 0x8fa3001c,
+0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
+0x10400058, 0x2408821, 0x3c020080, 0x621024,
+0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
+0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
+0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004,
+0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
+0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
+0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
+0x10660021, 0xc3102b, 0x14400007, 0x0,
+0x106b0011, 0x0, 0x106a0015, 0x0,
+0x8003592, 0x42042, 0x10650023, 0xa3102b,
+0x14400005, 0x0, 0x10690019, 0x0,
+0x8003592, 0x42042, 0x10680021, 0x0,
+0x8003592, 0x42042, 0x8ee20034, 0x24420001,
+0xaee20034, 0x8ee20034, 0x8003592, 0x42042,
+0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
+0x8003592, 0x42042, 0x8ee201f0, 0x24420001,
+0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042,
+0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
+0x8003592, 0x42042, 0x8ee20030, 0x24420001,
+0xaee20030, 0x8ee20030, 0x8003592, 0x42042,
+0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
+0x42042, 0x108702b7, 0x0, 0x8003557,
+0x0, 0x3c020001, 0x571021, 0x904283b2,
+0x14400084, 0x24020001, 0x3c030001, 0x771821,
+0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
+0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
+0x24100001, 0x96430004, 0x3402ffff, 0x10620075,
+0x0, 0x92e204d8, 0x14400072, 0x0,
+0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+0x10400020, 0x3821, 0x3c020001, 0x571021,
+0x8c4283b4, 0x18400016, 0x2821, 0x96260000,
+0x520c0, 0x971021, 0x9442777e, 0x14460009,
+0x971021, 0x94437780, 0x96220002, 0x14620005,
+0x971021, 0x94437782, 0x96220004, 0x50620008,
+0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+0x30e200ff, 0x1040027b, 0x0, 0x800361e,
+0x0, 0x2402021, 0xc0022fe, 0x24050006,
+0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+0x30424000, 0x1440026f, 0xb71021, 0x9443727e,
+0x96220000, 0x1462000b, 0x418c0, 0xb71021,
+0x94437280, 0x96220002, 0x14620006, 0x418c0,
+0xb71021, 0x94437282, 0x96220004, 0x10620035,
+0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+0x1440025c, 0x2e31021, 0x9448727c, 0x96270000,
+0x828c0, 0xb71021, 0x9442737e, 0x8003600,
+0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+0x2e41021, 0x9448737c, 0x30638000, 0x14600010,
+0x828c0, 0xb71021, 0x9442737e, 0x1447fff5,
+0x1002021, 0xb71021, 0x94437380, 0x96220002,
+0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+0x96220004, 0x5462ffec, 0x420c0, 0x24060001,
+0x30c200ff, 0x1040023b, 0x0, 0x800361e,
+0x0, 0x97430202, 0x96420000, 0x14620235,
+0x0, 0x97430204, 0x96420002, 0x14620231,
+0x0, 0x97430206, 0x96420004, 0x1462022d,
+0x0, 0x92420000, 0x3a030001, 0x30420001,
+0x431024, 0x10400074, 0x2402ffff, 0x8e230000,
+0x14620004, 0x3402ffff, 0x96230004, 0x1062006f,
+0x24140002, 0x3c020001, 0x571021, 0x904283b2,
+0x1440006a, 0x24140003, 0x92e204d8, 0x14400067,
+0x0, 0x3c020001, 0x571021, 0x8c4283b4,
+0x28420005, 0x10400020, 0x3821, 0x3c020001,
+0x571021, 0x8c4283b4, 0x18400016, 0x2821,
+0x96260000, 0x520c0, 0x971021, 0x9442777e,
+0x14460009, 0x971021, 0x94437780, 0x96220002,
+0x14620005, 0x971021, 0x94437782, 0x96220004,
+0x50620008, 0x24070001, 0x3c020001, 0x571021,
+0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
+0x520c0, 0x30e200ff, 0x14400044, 0x24140003,
+0x800384a, 0x0, 0x2402021, 0xc0022fe,
+0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
+0x9442727c, 0x30424000, 0x144001ea, 0xb71021,
+0x9443727e, 0x96220000, 0x1462000b, 0x418c0,
+0xb71021, 0x94437280, 0x96220002, 0x14620006,
+0x418c0, 0xb71021, 0x94437282, 0x96220004,
+0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
+0x30428000, 0x144001d7, 0x2e31021, 0x9448727c,
+0x96270000, 0x828c0, 0xb71021, 0x9442737e,
+0x8003685, 0x3021, 0x420c0, 0x2e41021,
+0x9443737c, 0x2e41021, 0x9448737c, 0x30638000,
+0x14600010, 0x828c0, 0xb71021, 0x9442737e,
+0x1447fff5, 0x1002021, 0xb71021, 0x94437380,
+0x96220002, 0x5462fff1, 0x420c0, 0xb71021,
+0x94437382, 0x96220004, 0x5462ffec, 0x420c0,
+0x24060001, 0x30c200ff, 0x104001b6, 0x0,
+0x8003698, 0x24140003, 0x24140001, 0x8f420260,
+0x53102b, 0x10400049, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878,
+0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+0xc002403, 0x34a5f003, 0x8003850, 0x0,
+0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
+0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf,
+0x431024, 0x80037f8, 0xaee20000, 0x8ee25240,
+0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884,
+0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006,
+0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001,
+0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468,
+0x53102b, 0x54400001, 0x3c158000, 0x12600131,
+0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280,
+0x24420001, 0x304207ff, 0x10620108, 0x0,
+0x12a00014, 0x0, 0x8ee35240, 0x8ee25244,
+0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244,
+0x21140, 0x24425248, 0x2e28021, 0x24630001,
+0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0,
+0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0,
+0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb,
+0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18,
+0x21140, 0x24420e20, 0x2e28021, 0x24630001,
+0x306801ff, 0x96e2046a, 0x30420010, 0x10400017,
+0x34028100, 0x9643000c, 0x14620014, 0x0,
+0x3c020001, 0x571021, 0x904283c0, 0x1440000f,
+0x0, 0x9642000e, 0xa6020016, 0x8e420008,
+0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c,
+0xae430008, 0xae440004, 0x9602000e, 0x26310004,
+0x24160001, 0x34420200, 0xa602000e, 0x9603000a,
+0x2605021, 0x73102b, 0x10400002, 0x2606821,
+0x605021, 0x2d42003d, 0x1040002a, 0x3821,
+0x9623000c, 0x24020800, 0x54620027, 0xae110018,
+0x3c020001, 0x571021, 0x904283c0, 0x54400022,
+0xae110018, 0x26220017, 0x182102b, 0x10400013,
+0x0, 0x3c02fff5, 0x511021, 0x90421017,
+0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+0x621825, 0x10600013, 0x26220010, 0x182102b,
+0x1040000e, 0x0, 0x3c07fff5, 0xf13821,
+0x94e71010, 0x800375e, 0x24e7000e, 0x92220017,
+0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+0x621825, 0x50600004, 0xae110018, 0x96270010,
+0x24e7000e, 0xae110018, 0x3c020001, 0x571021,
+0x904283c0, 0x2102b, 0x14e00002, 0x24ec0,
+0x1403821, 0x8f830120, 0x27623800, 0x24660020,
+0xc2102b, 0x50400001, 0x27663000, 0x8f820128,
+0x10c20004, 0x0, 0x8f820124, 0x14c20007,
+0x2402000b, 0x8ee201a4, 0x4821, 0x24420001,
+0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000,
+0x8e050004, 0xac620018, 0x1751025, 0x491025,
+0xac710008, 0xa467000e, 0xac62001c, 0xac640000,
+0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120,
+0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x14620020, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001c, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30,
+0x24020040, 0x24630001, 0x10620007, 0x0,
+0x8ee24e34, 0x24420001, 0x10a20005, 0x0,
+0x80037a9, 0x0, 0x14a00005, 0x0,
+0x8f820128, 0x24420020, 0xaf820128, 0x8f820128,
+0x8c820004, 0x2c420011, 0x50400013, 0xac800000,
+0x80037bf, 0x0, 0x8ee24e30, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+0x24020001, 0xac820004, 0x15200018, 0x3c050006,
+0x8e020018, 0x3c040001, 0x24845890, 0xafa20010,
+0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021,
+0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b,
+0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c,
+0xa642000c, 0xae430000, 0xae440004, 0xae450008,
+0x96020016, 0x80037f8, 0xa642000e, 0x154d000a,
+0x0, 0x9602000e, 0xa613000a, 0x34420004,
+0xa602000e, 0x3c010001, 0x370821, 0xa02083c0,
+0x80037f6, 0x9821, 0x9604000a, 0x93102b,
+0x10400002, 0x2601821, 0x801821, 0x24020001,
+0xa603000a, 0x3c010001, 0x370821, 0xa02283c0,
+0x9604000a, 0x2248821, 0x191102b, 0x10400003,
+0x3c02fff5, 0x34421000, 0x2228821, 0x2649823,
+0xa821, 0x1660fef4, 0xadc80000, 0x12600021,
+0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4,
+0x3c010001, 0x370821, 0xac3183c8, 0x3c010001,
+0x370821, 0x10400008, 0xac3283cc, 0x3c020001,
+0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
+0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280,
+0x24420001, 0x14620006, 0x0, 0x8ee201c4,
+0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4,
+0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850,
+0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821,
+0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0x24020002,
+0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003,
+0x14400017, 0x24020003, 0x16820015, 0x0,
+0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001,
+0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0,
+0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc,
+0x24630001, 0x2c640001, 0x441021, 0xaee200d8,
+0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc,
+0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001,
+0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8,
+0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003,
+0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c,
+0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021,
+0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058,
+0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048,
+0x8ee204d4, 0x8821, 0x24150001, 0x30420001,
+0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4,
+0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001,
+0x24841000, 0x420c2, 0x801821, 0x8ee400c8,
+0x8ee500cc, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xaee400c8, 0xaee500cc,
+0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023,
+0x44102b, 0x10400003, 0x3c02000a, 0x3442f000,
+0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8,
+0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001,
+0x571021, 0x904283c0, 0x1040000b, 0x0,
+0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001,
+0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021,
+0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4,
+0x10430007, 0x3821, 0x8f8200e4, 0x24070001,
+0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c,
+0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010,
+0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014,
+0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403,
+0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c,
+0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024,
+0x10400058, 0x2408021, 0x3c020080, 0x621024,
+0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001,
+0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001,
+0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004,
+0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008,
+0x8ee20080, 0x3c080020, 0x34078000, 0x24420001,
+0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824,
+0x10660021, 0xc3102b, 0x14400007, 0x0,
+0x106b0011, 0x0, 0x106a0015, 0x0,
+0x8003916, 0x42042, 0x10650023, 0xa3102b,
+0x14400005, 0x0, 0x10690019, 0x0,
+0x8003916, 0x42042, 0x10680021, 0x0,
+0x8003916, 0x42042, 0x8ee20034, 0x24420001,
+0xaee20034, 0x8ee20034, 0x8003916, 0x42042,
+0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec,
+0x8003916, 0x42042, 0x8ee201f0, 0x24420001,
+0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042,
+0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4,
+0x8003916, 0x42042, 0x8ee20030, 0x24420001,
+0xaee20030, 0x8ee20030, 0x8003916, 0x42042,
+0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8,
+0x42042, 0x1087033e, 0x0, 0x80038db,
+0x0, 0x3c020001, 0x571021, 0x904283b2,
+0x14400084, 0x24020001, 0x3c030001, 0x771821,
+0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000,
+0x621024, 0x1040006f, 0x2402ffff, 0x14620005,
+0x24110001, 0x96430004, 0x3402ffff, 0x10620075,
+0x0, 0x92e204d8, 0x14400072, 0x0,
+0x3c020001, 0x571021, 0x8c4283b4, 0x28420005,
+0x10400020, 0x3821, 0x3c020001, 0x571021,
+0x8c4283b4, 0x18400016, 0x2821, 0x96060000,
+0x520c0, 0x971021, 0x9442777e, 0x14460009,
+0x971021, 0x94437780, 0x96020002, 0x14620005,
+0x971021, 0x94437782, 0x96020004, 0x50620008,
+0x24070001, 0x3c020001, 0x571021, 0x8c4283b4,
+0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0,
+0x30e200ff, 0x10400302, 0x0, 0x80039a2,
+0x0, 0x2402021, 0xc0022fe, 0x24050006,
+0x3044001f, 0x428c0, 0x2e51021, 0x9442727c,
+0x30424000, 0x144002f6, 0xb71021, 0x9443727e,
+0x96020000, 0x1462000b, 0x418c0, 0xb71021,
+0x94437280, 0x96020002, 0x14620006, 0x418c0,
+0xb71021, 0x94437282, 0x96020004, 0x10620035,
+0x418c0, 0x2e31021, 0x9442727c, 0x30428000,
+0x144002e3, 0x2e31021, 0x944d727c, 0x96070000,
+0xd28c0, 0xb71021, 0x9442737e, 0x8003984,
+0x3021, 0x420c0, 0x2e41021, 0x9443737c,
+0x2e41021, 0x944d737c, 0x30638000, 0x14600010,
+0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5,
+0x1a02021, 0xb71021, 0x94437380, 0x96020002,
+0x5462fff1, 0x420c0, 0xb71021, 0x94437382,
+0x96020004, 0x5462ffec, 0x420c0, 0x24060001,
+0x30c200ff, 0x104002c2, 0x0, 0x80039a2,
+0x0, 0x97430202, 0x96420000, 0x146202bc,
+0x0, 0x97430204, 0x96420002, 0x146202b8,
+0x0, 0x97430206, 0x96420004, 0x146202b4,
+0x0, 0x92420000, 0x3a230001, 0x30420001,
+0x431024, 0x10400074, 0x2402ffff, 0x8e030000,
+0x14620004, 0x3402ffff, 0x96030004, 0x1062006f,
+0x24150002, 0x3c020001, 0x571021, 0x904283b2,
+0x1440006a, 0x24150003, 0x92e204d8, 0x14400067,
+0x0, 0x3c020001, 0x571021, 0x8c4283b4,
+0x28420005, 0x10400020, 0x3821, 0x3c020001,
+0x571021, 0x8c4283b4, 0x18400016, 0x2821,
+0x96060000, 0x520c0, 0x971021, 0x9442777e,
+0x14460009, 0x971021, 0x94437780, 0x96020002,
+0x14620005, 0x971021, 0x94437782, 0x96020004,
+0x50620008, 0x24070001, 0x3c020001, 0x571021,
+0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee,
+0x520c0, 0x30e200ff, 0x14400044, 0x24150003,
+0x8003c55, 0x0, 0x2402021, 0xc0022fe,
+0x24050006, 0x3044001f, 0x428c0, 0x2e51021,
+0x9442727c, 0x30424000, 0x14400271, 0xb71021,
+0x9443727e, 0x96020000, 0x1462000b, 0x418c0,
+0xb71021, 0x94437280, 0x96020002, 0x14620006,
+0x418c0, 0xb71021, 0x94437282, 0x96020004,
+0x10620027, 0x418c0, 0x2e31021, 0x9442727c,
+0x30428000, 0x1440025e, 0x2e31021, 0x944d727c,
+0x96070000, 0xd28c0, 0xb71021, 0x9442737e,
+0x8003a09, 0x3021, 0x420c0, 0x2e41021,
+0x9443737c, 0x2e41021, 0x944d737c, 0x30638000,
+0x14600010, 0xd28c0, 0xb71021, 0x9442737e,
+0x1447fff5, 0x1a02021, 0xb71021, 0x94437380,
+0x96020002, 0x5462fff1, 0x420c0, 0xb71021,
+0x94437382, 0x96020004, 0x5462ffec, 0x420c0,
+0x24060001, 0x30c200ff, 0x1040023d, 0x0,
+0x8003a1c, 0x24150003, 0x24150001, 0x8f420260,
+0x53102b, 0x10400036, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4,
+0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058,
+0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c,
+0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0,
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0,
+0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006,
+0xc002403, 0x34a5f203, 0x8003c5b, 0x0,
+0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001,
+0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18,
+0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0,
+0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0,
+0x96e20468, 0x53102b, 0x54400001, 0x3c168000,
+0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5,
+0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280,
+0x24420001, 0x304207ff, 0x1062019e, 0x0,
+0x12c00012, 0x0, 0x8ee35240, 0x8ee25244,
+0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024,
+0x8ee35244, 0x21140, 0x24425248, 0x2e28821,
+0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0,
+0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10,
+0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18,
+0xb021, 0xafb80024, 0x8ee30e18, 0x21140,
+0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff,
+0x96e2046a, 0x30420010, 0x10400018, 0x34028100,
+0x9643000c, 0x14620015, 0x0, 0x3c020001,
+0x571021, 0x904283c0, 0x14400010, 0x0,
+0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004,
+0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008,
+0xae440004, 0x9622000e, 0x26100004, 0x24180001,
+0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000,
+0x8e230004, 0x3c040001, 0x34843800, 0x2003021,
+0x306a0007, 0x20a8023, 0x3641021, 0x202102b,
+0x10400005, 0x26a9821, 0x2041023, 0x3621823,
+0x3c020020, 0x438023, 0x26620007, 0x9623000a,
+0x2418fff8, 0x58c824, 0x6a1821, 0x79102b,
+0x10400002, 0x3206021, 0x606021, 0x1801821,
+0x24620007, 0x2418fff8, 0x586024, 0x26c102b,
+0x14400004, 0x1932823, 0x1832823, 0x8003ac3,
+0xc31021, 0xd31021, 0x4a2023, 0x1c4102b,
+0x54400001, 0x8f2021, 0x25420040, 0x4c102b,
+0x14400035, 0x5821, 0x94c3000c, 0x24020800,
+0x54620032, 0xae260018, 0x3c020001, 0x571021,
+0x904283c0, 0x5440002d, 0xae260018, 0x24c20017,
+0x1c2102b, 0x10400013, 0x0, 0x3c02fff5,
+0x461021, 0x90421017, 0x38430006, 0x2c630001,
+0x38420011, 0x2c420001, 0x621825, 0x10600014,
+0x24c20010, 0x1c2102b, 0x1040000e, 0x0,
+0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4,
+0x2562000e, 0x90c20017, 0x38430006, 0x2c630001,
+0x38420011, 0x2c420001, 0x621825, 0x10600005,
+0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821,
+0x1601821, 0x24620007, 0x2418fff8, 0x585824,
+0xc31021, 0x4a2023, 0x1c4102b, 0x10400002,
+0x1632823, 0x8f2021, 0xae260018, 0x3c020001,
+0x571021, 0x904283c0, 0x2102b, 0x216c0,
+0x15600002, 0xafa20044, 0x1805821, 0x30820001,
+0x10400007, 0x4021, 0x90880000, 0x24840001,
+0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021,
+0x50a00012, 0x81c02, 0x2ca20002, 0x54400009,
+0x24a5ffff, 0x94820000, 0x24840002, 0x1024021,
+0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21,
+0x8f2021, 0x90820000, 0x21200, 0x1024021,
+0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff,
+0x624021, 0x3108ffff, 0x1402821, 0x11400011,
+0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff,
+0x94820000, 0x24840002, 0x1024021, 0x1c4102b,
+0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021,
+0x90820000, 0x21200, 0x1024021, 0x14a0fff2,
+0x2ca20002, 0x81c02, 0x3102ffff, 0x624021,
+0x81c02, 0x3102ffff, 0x8f890120, 0x624021,
+0x27623800, 0x25230020, 0x62102b, 0x14400002,
+0x3108ffff, 0x27633000, 0x8f820128, 0x10620004,
+0x0, 0x8f820124, 0x14620007, 0x1402821,
+0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4,
+0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004,
+0x81400, 0x3448000b, 0xad300008, 0xa52b000e,
+0xad280018, 0x8fb80044, 0x2021, 0x2961025,
+0x581025, 0xad22001c, 0xe5102b, 0xe53823,
+0xc43023, 0xc23023, 0xad260000, 0xad270004,
+0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20,
+0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002,
+0x14400003, 0x24020011, 0x15020024, 0x0,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c830000, 0x24020012, 0x1462000f, 0x0,
+0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0,
+0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34,
+0x8ee34e30, 0x24420001, 0x105e002a, 0x0,
+0x8003ba8, 0x0, 0x8ee24e30, 0x24420001,
+0x505e0003, 0x1021, 0x8ee24e30, 0x24420001,
+0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30,
+0x210c0, 0x24425038, 0x2e22021, 0x8c830000,
+0x24020007, 0x1462001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x105e0007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8003bb4,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400012, 0xac800000, 0x8003bc9,
+0x0, 0x8ee24e30, 0x24420001, 0x505e0003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020007, 0xac820000, 0x24020001, 0xac820004,
+0x14e00019, 0x3c050006, 0x3c040001, 0x24845890,
+0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000,
+0x8e230004, 0x2203021, 0x1603821, 0xc002403,
+0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100,
+0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c,
+0xae430000, 0xae440004, 0xae450008, 0x96220016,
+0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823,
+0x9622000e, 0xa623000a, 0x34420004, 0xa622000e,
+0x3c010001, 0x370821, 0xa02083c0, 0x8003bff,
+0x9821, 0x9624000a, 0x83102b, 0x54400001,
+0x801821, 0x24020001, 0xa623000a, 0x3c010001,
+0x370821, 0xa02283c0, 0x9622000a, 0x4a1821,
+0x2038021, 0x1d0102b, 0x54400001, 0x20f8021,
+0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e,
+0xaf0d0000, 0x12600022, 0x0, 0x3c010001,
+0x370821, 0xac3383c4, 0x3c010001, 0x370821,
+0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc,
+0x93a2002f, 0x10400008, 0x0, 0x3c020001,
+0x571021, 0x8c4283cc, 0x24420004, 0x3c010001,
+0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c,
+0x14620006, 0x0, 0x8ee201c4, 0x24420001,
+0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc,
+0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc,
+0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0,
+0x8ee500c4, 0x1021, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0x24020002, 0xaee400c0,
+0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017,
+0x24020003, 0x16a20015, 0x0, 0x8ee200d0,
+0x8ee300d4, 0x24630001, 0x2c640001, 0x441021,
+0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55,
+0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001,
+0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc,
+0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8,
+0x8ee300cc, 0x24630001, 0x2c640001, 0x441021,
+0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc,
+0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008,
+0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064,
+0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054,
+0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008,
+0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14,
+0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c,
+0x8ee20e14, 0x622023, 0x4820001, 0x24840200,
+0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004,
+0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823,
+0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff,
+0x804821, 0x69102a, 0x54400001, 0x604821,
+0x8f870100, 0x27623000, 0x24e80020, 0x102102b,
+0x50400001, 0x27682800, 0x8f820108, 0x11020004,
+0x0, 0x8f820104, 0x15020007, 0x1021,
+0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8,
+0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140,
+0x801821, 0x8ee40460, 0x8ee50464, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xace40000,
+0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e,
+0x24020002, 0xace20018, 0x31940, 0x24630e20,
+0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c,
+0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec,
+0x14400011, 0x24040001, 0x8ee24e28, 0x24030040,
+0x24420001, 0x50430003, 0x1021, 0x8ee24e28,
+0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0,
+0x24424e38, 0x2e21821, 0x24020002, 0xac620000,
+0x24020001, 0xac620004, 0x1480000e, 0x24030040,
+0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007,
+0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001,
+0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd,
+0x0, 0x8ee20500, 0x24420001, 0x50430003,
+0x1021, 0x8ee20500, 0x24420001, 0xaee20500,
+0x8ee20500, 0x21080, 0x571021, 0xac490508,
+0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14,
+0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0,
+0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
+0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074,
+0x0, 0x8ee35238, 0x8ee2523c, 0x622023,
+0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c,
+0x43102b, 0x14400004, 0x24020100, 0x8ee3523c,
+0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c,
+0x431023, 0x2443ffff, 0x804821, 0x69102a,
+0x54400001, 0x604821, 0x8f870100, 0x27623000,
+0x24e80020, 0x102102b, 0x50400001, 0x27682800,
+0x8f820108, 0x11020004, 0x0, 0x8f820104,
+0x15020007, 0x1021, 0x8ee201a8, 0x2021,
+0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8,
+0x8ee4523c, 0x42140, 0x801821, 0x8ee40470,
+0x8ee50474, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xace40000, 0xace50004, 0x8ee3523c,
+0x91140, 0xa4e2000e, 0x24020003, 0xace20018,
+0x31940, 0x24635248, 0x2e31021, 0xace20008,
+0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010,
+0xaf880100, 0x92e204ec, 0x14400011, 0x24040001,
+0x8ee24e28, 0x24030040, 0x24420001, 0x50430003,
+0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28,
+0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821,
+0x24020003, 0xac620000, 0x24020001, 0xac620004,
+0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010,
+0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238,
+0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403,
+0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500,
+0x24420001, 0x50430003, 0x1021, 0x8ee20500,
+0x24420001, 0xaee20500, 0x8ee20500, 0x21080,
+0x571021, 0xac490508, 0x8ee2523c, 0x491021,
+0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238,
+0x14620005, 0x0, 0x8f820060, 0x2403feff,
+0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124,
+0x8f860128, 0x24020040, 0x24630001, 0x50620003,
+0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34,
+0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0,
+0x24425038, 0x14830007, 0x2e22821, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8003d92,
+0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001,
+0x50430003, 0x1021, 0x8ee24e34, 0x24420001,
+0x210c0, 0x24425038, 0x2e22821, 0x8ca20004,
+0x8f830128, 0x21140, 0x621821, 0xaf830128,
+0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012,
+0x10400008, 0x31080, 0x3c010001, 0x220821,
+0x8c2258f0, 0x400008, 0x0, 0x24020001,
+0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8,
+0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024,
+0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128,
+0x8f820124, 0x106202b0, 0x9821, 0x3c11001f,
+0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012,
+0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020,
+0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe,
+0x2c620012, 0x1040029c, 0x31080, 0x3c010001,
+0x220821, 0x8c225948, 0x400008, 0x0,
+0x8f420218, 0x30420100, 0x10400007, 0x0,
+0x95830016, 0x95820018, 0x621823, 0x31402,
+0x431021, 0xa5820016, 0x8d82001c, 0x3c038000,
+0x3044ffff, 0x436824, 0x3c030800, 0x431824,
+0x11a00004, 0xad84001c, 0x41140, 0x8003dd8,
+0x24425248, 0x41140, 0x24420e20, 0x2e25821,
+0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e,
+0x95840016, 0x8003ec0, 0x0, 0x8d690018,
+0x4021, 0x952a0000, 0x25290002, 0x95270000,
+0x25290002, 0x95260000, 0x25290002, 0x95250000,
+0x25290002, 0x95240000, 0x25290002, 0x95230000,
+0x25290002, 0x95220000, 0x25290002, 0x1475021,
+0x1465021, 0x1455021, 0x1445021, 0x1435021,
+0x1425021, 0xa1c02, 0x3142ffff, 0x625021,
+0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a,
+0x314effff, 0x30420002, 0x10400044, 0x5021,
+0x25220014, 0x222102b, 0x10400014, 0x1201821,
+0x2405000a, 0x2021, 0x223102b, 0x54400001,
+0x721821, 0x94620000, 0x24630002, 0x24a5ffff,
+0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff,
+0x622021, 0x41402, 0x3083ffff, 0x431021,
+0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000,
+0x25290002, 0x95280000, 0x25290002, 0x95270000,
+0x25290002, 0x95260000, 0x25290002, 0x95250000,
+0x25290002, 0x95230000, 0x25290002, 0x95220000,
+0x25290002, 0x95240000, 0x25290002, 0x1485021,
+0x1475021, 0x1465021, 0x1455021, 0x1435021,
+0x1425021, 0x95220000, 0x95230002, 0x1445021,
+0x1425021, 0x1435021, 0xa1c02, 0x3142ffff,
+0x625021, 0xa1c02, 0x3142ffff, 0x625021,
+0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018,
+0x9443000c, 0x24020800, 0x54620005, 0xa5680010,
+0x9562000e, 0x34420002, 0xa562000e, 0xa5680010,
+0x96e2046a, 0x2821, 0x30420008, 0x14400056,
+0x3021, 0x8d630018, 0x24620024, 0x222102b,
+0x10400034, 0x24690010, 0x229102b, 0x54400001,
+0x1324821, 0x95250000, 0x24690014, 0x229102b,
+0x10400002, 0x24a5ffec, 0x1324821, 0x95220000,
+0x30420fff, 0x14400003, 0x25290002, 0x8003e60,
+0x24130001, 0x9821, 0xa03021, 0x229102b,
+0x54400001, 0x1324821, 0x91220001, 0x25290002,
+0xa22821, 0x229102b, 0x54400001, 0x1324821,
+0x25290002, 0x229102b, 0x54400001, 0x1324821,
+0x95220000, 0x25290002, 0xa22821, 0x229102b,
+0x54400001, 0x1324821, 0x95220000, 0x25290002,
+0xa22821, 0x229102b, 0x54400001, 0x1324821,
+0x95220000, 0x25290002, 0xa22821, 0x229102b,
+0x54400001, 0x1324821, 0x95220000, 0x8003e99,
+0xa22821, 0x94650010, 0x94620014, 0x24690016,
+0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c,
+0x24130001, 0x9821, 0xa03021, 0x91230001,
+0x25290004, 0x95220000, 0x25290002, 0x95240000,
+0x25290002, 0xa32821, 0xa22821, 0x95220000,
+0x95230002, 0xa42821, 0xa22821, 0xa32821,
+0x51c02, 0x30a2ffff, 0x622821, 0x51c02,
+0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001,
+0x1040001e, 0x2021, 0x95820016, 0x4e2023,
+0x41402, 0x822021, 0x326200ff, 0x50400002,
+0x862021, 0x852021, 0x41402, 0x822021,
+0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018,
+0x24430017, 0x223102b, 0x54400001, 0x721821,
+0x90620000, 0x38430011, 0x2c630001, 0x38420006,
+0x2c420001, 0x621825, 0x10600004, 0x0,
+0x9562000e, 0x34420001, 0xa562000e, 0x9562000e,
+0x240a0002, 0x30420004, 0x10400002, 0xa5640012,
+0x240a0004, 0x8f880120, 0x27623800, 0x25090020,
+0x122102b, 0x50400001, 0x27693000, 0x8f820128,
+0x11220004, 0x0, 0x8f820124, 0x15220007,
+0x24040020, 0x8ee201a4, 0x8021, 0x24420001,
+0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c,
+0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e,
+0xad0a0018, 0x52940, 0xa01821, 0x1021,
+0xe33821, 0xe3202b, 0xc23021, 0xc43021,
+0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025,
+0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120,
+0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee,
+0x2c630002, 0x39420011, 0x2c420001, 0x621825,
+0x10600024, 0x0, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1455000f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b,
+0x0, 0x8003f2e, 0x0, 0x8ee24e30,
+0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020001, 0x8003f4e,
+0xac950000, 0x8ee24e30, 0x210c0, 0x24425038,
+0x2e22021, 0x8c830000, 0x24020007, 0x1462001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8003f3a, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400012,
+0xac800000, 0x8003f4f, 0x0, 0x8ee24e30,
+0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020007, 0xac820000,
+0x24020001, 0xac820004, 0x1600000d, 0x0,
+0x8f820120, 0x3c040001, 0x24845938, 0xafa00014,
+0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008,
+0xc002403, 0x34a50001, 0x8004057, 0x0,
+0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006,
+0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0,
+0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff,
+0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff,
+0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240,
+0x104000e5, 0x0, 0x8ee20e1c, 0x24420001,
+0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c,
+0x8f420240, 0x10400072, 0x0, 0x8ee20e1c,
+0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b,
+0x144000d5, 0x0, 0x8f830120, 0x27623800,
+0x24660020, 0xc2102b, 0x50400001, 0x27663000,
+0x8f820128, 0x10c20004, 0x0, 0x8f820124,
+0x14c20007, 0x0, 0x8ee201a4, 0x8021,
+0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4,
+0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac,
+0x2462001c, 0xac620008, 0x24020008, 0xa462000e,
+0x24020011, 0xac620018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400034, 0x24100001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1455001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8003fc6, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400011,
+0xac800000, 0x8003fda, 0x0, 0x8ee24e30,
+0x24420001, 0x50540003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x24020001, 0xac950000,
+0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c,
+0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010,
+0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403,
+0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188,
+0x24420001, 0xaee20188, 0x8004050, 0x8ee20188,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4,
+0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c,
+0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008,
+0x24020008, 0xa462000e, 0x24020011, 0xac620018,
+0xac640000, 0xac650004, 0x8ee204c4, 0xac620010,
+0xaf860120, 0x92e24e20, 0x14400034, 0x24100001,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x8c820000, 0x1455001f, 0x0, 0x8ee34e30,
+0x8ee24e34, 0x1062001b, 0x0, 0x8c820004,
+0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30,
+0x24420001, 0x10540007, 0x0, 0x8ee24e34,
+0x24420001, 0x10620005, 0x0, 0x8004030,
+0x0, 0x14600005, 0x0, 0x8f820128,
+0x24420020, 0xaf820128, 0x8f820128, 0x8c820004,
+0x2c420011, 0x50400011, 0xac800000, 0x8004044,
+0x0, 0x8ee24e30, 0x24420001, 0x50540003,
+0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30,
+0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021,
+0x24020001, 0xac950000, 0xac820004, 0x1600000b,
+0x0, 0x8ee2724c, 0x3c040001, 0x248458a8,
+0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280,
+0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174,
+0x24420001, 0xaee20174, 0x8004057, 0x8ee20174,
+0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124,
+0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c,
+0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8,
+0x27840208, 0x27450200, 0x24060008, 0xafbf0014,
+0xc00249a, 0xafb00010, 0x2021, 0x24100001,
+0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204,
+0xaf820214, 0x8f460248, 0x24030004, 0x3c020040,
+0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8,
+0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0,
+0x3c010001, 0xac235cc8, 0xc005108, 0x24050004,
+0xc004822, 0x0, 0x8ee20000, 0x3c03feff,
+0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00,
+0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac,
+0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018,
+0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001,
+0x248459f0, 0xc002403, 0x3821, 0x8ee20280,
+0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200,
+0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400,
+0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214,
+0x3821, 0x24420001, 0xaee20214, 0x8ee20214,
+0x3c020300, 0x2021024, 0x10400027, 0x3c110400,
+0xc00429b, 0x0, 0x3c020100, 0x2021024,
+0x10400007, 0x0, 0x8ee20218, 0x24420001,
+0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff,
+0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c,
+0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff,
+0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008,
+0x2003021, 0x431024, 0xaee20000, 0x8f820220,
+0x3821, 0x3c030300, 0x481024, 0x431025,
+0xaf820220, 0xafa00010, 0xc002403, 0xafa00014,
+0x8004296, 0x0, 0x2111024, 0x1040001f,
+0x3c024000, 0x8f830224, 0x24021402, 0x1462000b,
+0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff,
+0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000,
+0x3463ffff, 0x2002021, 0x431024, 0xc004e54,
+0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220,
+0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x8004295, 0x511025, 0x2021024,
+0x10400142, 0x0, 0x8ee2022c, 0x24420001,
+0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff,
+0x3463ffff, 0x431024, 0x34420004, 0xaf820220,
+0x8f830054, 0x8f820054, 0x800410e, 0x24630002,
+0x8f820054, 0x621023, 0x2c420003, 0x1440fffc,
+0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007,
+0x10400012, 0x0, 0x8f8300e4, 0x2402fff8,
+0xc21024, 0x1043000d, 0x0, 0x8f820054,
+0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054,
+0x821023, 0x2c420051, 0x10400004, 0x0,
+0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220,
+0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220,
+0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8,
+0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f,
+0x3442ffff, 0x24680008, 0x48102b, 0x10400003,
+0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8,
+0x8f850120, 0x8f840124, 0x8004145, 0x6021,
+0x27623800, 0x82102b, 0x50400001, 0x27643000,
+0x10a40010, 0x318200ff, 0x8c820018, 0x38430007,
+0x2c630001, 0x3842000b, 0x2c420001, 0x621825,
+0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001,
+0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008,
+0x318200ff, 0x14400065, 0x0, 0x3c020001,
+0x571021, 0x904283c0, 0x14400060, 0x0,
+0x8f8400e4, 0xc41023, 0x218c3, 0x4620001,
+0x24630200, 0x8f8900c4, 0x10600005, 0x24020001,
+0x10620009, 0x0, 0x8004187, 0x0,
+0x8ee20230, 0x1205821, 0x24420001, 0xaee20230,
+0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a,
+0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000,
+0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001,
+0x651821, 0x2c62233f, 0x14400040, 0x0,
+0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8,
+0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4,
+0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a,
+0x24420001, 0xaee20238, 0x8c840000, 0x3463f000,
+0x8ee20238, 0x883823, 0x67102b, 0x54400001,
+0xe33821, 0x3c020003, 0x34420d40, 0x47102b,
+0x10400003, 0x0, 0x80041bc, 0x805821,
+0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4,
+0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003,
+0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c,
+0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b,
+0x54400001, 0xe53821, 0x147102b, 0x54400007,
+0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4,
+0x8f8400e4, 0x1486ffef, 0x0, 0x14860005,
+0x0, 0x1205821, 0xaf8600e4, 0x80041bc,
+0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8,
+0x3c03000a, 0x3463f000, 0x483823, 0x67102b,
+0x54400001, 0xe33821, 0x3c020003, 0x34420d3f,
+0x47102b, 0x54400007, 0x6021, 0x1683823,
+0x67102b, 0x54400003, 0xe33821, 0x80041cf,
+0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b,
+0x14400016, 0x318200ff, 0x14400006, 0x0,
+0x3c020001, 0x571021, 0x904283c0, 0x1040000f,
+0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000,
+0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c,
+0x24020001, 0x641824, 0x3c010001, 0x370821,
+0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8,
+0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000,
+0x623823, 0x87102b, 0x54400001, 0xe43821,
+0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001,
+0x431025, 0x10400008, 0x0, 0x8f820220,
+0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000,
+0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4,
+0x10c4002a, 0x0, 0x8ee2007c, 0x24420001,
+0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0,
+0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0,
+0x431024, 0x1040001d, 0x0, 0x10c4001b,
+0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080,
+0x24850008, 0x27622800, 0x50a20001, 0x27651800,
+0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff,
+0x431021, 0x4d1024, 0x24430010, 0x6b102b,
+0x54400001, 0x6a1821, 0x12b102b, 0x54400001,
+0x12a4821, 0x10690002, 0x10c1025, 0xac820004,
+0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220,
+0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002,
+0xaf820220, 0x8f830054, 0x8f820054, 0x8004237,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff,
+0x3463fffb, 0x431024, 0xaf820220, 0x6010055,
+0x0, 0x8ee20228, 0x24420001, 0xaee20228,
+0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420004, 0xaf820220, 0x8f830054,
+0x8f820054, 0x8004251, 0x24630002, 0x8f820054,
+0x621023, 0x2c420003, 0x1440fffc, 0x0,
+0x8f8600e0, 0x30c20007, 0x10400012, 0x0,
+0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d,
+0x0, 0x8f820054, 0x8f8300e0, 0x14c30009,
+0x24440032, 0x8f820054, 0x821023, 0x2c420033,
+0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9,
+0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd,
+0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007,
+0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0,
+0x240301f5, 0x8f8200e8, 0x673823, 0x718c0,
+0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4,
+0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021,
+0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002,
+0x441024, 0x431025, 0xaf820220, 0x8f830054,
+0x8f820054, 0x800428d, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024,
+0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8,
+0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001,
+0x24845a14, 0x3c050008, 0x24020001, 0x3c010001,
+0x370821, 0xac2283ac, 0xafa00010, 0xafa00014,
+0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8,
+0x3c010001, 0xac225ccc, 0xc002403, 0x3821,
+0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024,
+0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe,
+0x431024, 0x30840002, 0x1080011e, 0xaee204d0,
+0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4,
+0x8f820044, 0x3c030600, 0x34632000, 0x34420020,
+0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228,
+0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010,
+0x8ee20608, 0x210c0, 0x571021, 0x8fa30018,
+0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054,
+0x8f820054, 0x24690032, 0x1221023, 0x2c420033,
+0x1040006a, 0x5821, 0x24180008, 0x240f000d,
+0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120,
+0x27623800, 0x24e80020, 0x102102b, 0x50400001,
+0x27683000, 0x8f820128, 0x11020004, 0x0,
+0x8f820124, 0x15020007, 0x1021, 0x8ee201a4,
+0x2821, 0x24420001, 0xaee201a4, 0x800433d,
+0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821,
+0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b,
+0x822021, 0x862021, 0xace40000, 0xace50004,
+0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c,
+0x210c0, 0x2442060c, 0x2e21021, 0xace20008,
+0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20,
+0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x144d001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x800432a, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x800433d, 0x0, 0x8ee24e30,
+0x24420001, 0x504c0003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004,
+0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ff9d, 0x0, 0x316300ff,
+0x24020001, 0x54620079, 0xafa00010, 0xaeea0608,
+0x8f830054, 0x8f820054, 0x24690032, 0x1221023,
+0x2c420033, 0x10400061, 0x5821, 0x240d0008,
+0x240c0011, 0x24080012, 0x24070040, 0x240a0001,
+0x8f830120, 0x27623800, 0x24660020, 0xc2102b,
+0x50400001, 0x27663000, 0x8f820128, 0x10c20004,
+0x0, 0x8f820124, 0x14c20007, 0x0,
+0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4,
+0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c,
+0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008,
+0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004,
+0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20,
+0x14400033, 0x24050001, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0x8c820000, 0x1448001f,
+0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b,
+0x0, 0x8c820004, 0x24420001, 0xac820004,
+0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007,
+0x0, 0x8ee24e34, 0x24420001, 0x10620005,
+0x0, 0x8004396, 0x0, 0x14600005,
+0x0, 0x8f820128, 0x24420020, 0xaf820128,
+0x8f820128, 0x8c820004, 0x2c420011, 0x50400010,
+0xac800000, 0x80043a9, 0x0, 0x8ee24e30,
+0x24420001, 0x50470003, 0x1021, 0x8ee24e30,
+0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0,
+0x24425038, 0x2e22021, 0xac880000, 0xac8a0004,
+0x54a00006, 0x240b0001, 0x8f820054, 0x1221023,
+0x2c420033, 0x1440ffa6, 0x0, 0x316300ff,
+0x24020001, 0x54620003, 0xafa00010, 0x80043d6,
+0x0, 0x3c040001, 0x24845a20, 0xafa00014,
+0x8f860120, 0x8f870124, 0x3c050009, 0xc002403,
+0x34a5f011, 0x80043d6, 0x0, 0x3c040001,
+0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124,
+0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6,
+0x0, 0x3c040001, 0x24845a38, 0xafa00014,
+0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403,
+0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac,
+0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c,
+0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028,
+0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d,
+0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499,
+0x24020001, 0x3c010001, 0xac225cd8, 0xc002403,
+0x3821, 0x8ee204d0, 0x3c030001, 0x771821,
+0x946383b2, 0x34420001, 0x10600007, 0xaee204d0,
+0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024,
+0x34420008, 0xaf820220, 0x2021, 0xc0052a2,
+0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x3c120001,
+0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001,
+0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000,
+0x8eb30000, 0x26a400b, 0x248000a, 0x200f821,
+0x0, 0xd, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x80014d6,
+0x0, 0x80014d8, 0x3c0a0001, 0x80014d8,
+0x3c0a0002, 0x80014d8, 0x0, 0x80024a6,
+0x0, 0x80014d8, 0x3c0a0003, 0x80014d8,
+0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8,
+0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66,
+0x0, 0x80014d8, 0x3c0a0006, 0x80014d8,
+0x3c0a0007, 0x80014d8, 0x0, 0x80014d8,
+0x0, 0x80014d8, 0x0, 0x8002a75,
+0x0, 0x80014d8, 0x3c0a000b, 0x80014d8,
+0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a,
+0x0, 0x8002339, 0x0, 0x80014d8,
+0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4,
+0x0, 0x80014d8, 0x3c0a000f, 0x80040a7,
+0x0, 0x8004091, 0x0, 0x80014d8,
+0x3c0a0010, 0x80014ee, 0x0, 0x80014d8,
+0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8,
+0x3c0a0013, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x3c030001,
+0x34633800, 0x24050080, 0x2404001f, 0x2406ffff,
+0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
+0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4,
+0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0,
+0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8,
+0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4,
+0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0,
+0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8,
+0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004,
+0x8f830040, 0x3c02f000, 0x621824, 0x3c025000,
+0x1062000c, 0x43102b, 0x14400006, 0x3c026000,
+0x3c024000, 0x10620008, 0x24020800, 0x8004539,
+0x0, 0x10620004, 0x24020800, 0x8004539,
+0x0, 0x24020700, 0x3c010001, 0xac225cdc,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001,
+0xac205cc4, 0x8004545, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0xc004d71, 0x0, 0x24040001, 0x2821,
+0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018,
+0x8f830054, 0x8f820054, 0x8004556, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
+0x8f830054, 0x8f820054, 0x8004562, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc00494c, 0x27a60018,
+0x8f830054, 0x8f820054, 0x800456e, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c,
+0x24050002, 0x8f830054, 0x8f820054, 0x800457b,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
+0x26105da2, 0xc00494c, 0x2003021, 0x97a60018,
+0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0,
+0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
+0xc002403, 0xafa20010, 0x97a20018, 0x1040004c,
+0x24036040, 0x96020000, 0x3042fff0, 0x1443000a,
+0x24020020, 0x3c030001, 0x94635da0, 0x54620009,
+0x24027830, 0x24020003, 0x3c010001, 0xac225cc4,
+0x80045ac, 0x24020005, 0x3c030001, 0x94635da0,
+0x24027830, 0x1462000f, 0x24030010, 0x3c020001,
+0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003,
+0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001,
+0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6,
+0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001,
+0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4,
+0x24020015, 0x1462000f, 0x0, 0x3c020001,
+0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001,
+0x3842f430, 0x2c420001, 0x621825, 0x10600005,
+0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6,
+0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810,
+0x1462000b, 0x24020002, 0x3c020001, 0x94425da2,
+0x3042fff0, 0x14400006, 0x24020002, 0x24020004,
+0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
+0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0,
+0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001,
+0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4,
+0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4,
+0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001,
+0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc,
+0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2,
+0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8,
+0x491021, 0x3c010001, 0xac225dac, 0xafa30010,
+0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020,
+0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001,
+0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014,
+0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000,
+0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc,
+0x8004617, 0x34844240, 0x3c040004, 0x3c030001,
+0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016,
+0x0, 0x3c04003d, 0x800462f, 0x34840900,
+0x3c020001, 0x8c427e38, 0x30428000, 0x10400005,
+0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a,
+0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc,
+0x34844240, 0x24020005, 0x14620003, 0x0,
+0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac,
+0x8f830054, 0x441021, 0x431023, 0x44102b,
+0x14400037, 0x0, 0x3c020001, 0x8c425cd0,
+0x14400033, 0x0, 0x3c010001, 0x10c00025,
+0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001,
+0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc,
+0x52842, 0x14a00002, 0x24c6ffff, 0x24050008,
+0xa91024, 0x10400010, 0x0, 0x14a70008,
+0x0, 0x8d020000, 0x441024, 0x1040000a,
+0x0, 0x3c010001, 0x800465b, 0xac255ce0,
+0x8d420000, 0x441024, 0x10400003, 0x0,
+0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0,
+0x6182b, 0x2c420001, 0x431024, 0x5440ffe5,
+0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0,
+0x3c010001, 0xac225dac, 0x1060002a, 0x24020001,
+0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc,
+0x3c020001, 0x8c425ce0, 0x10400022, 0x0,
+0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001,
+0x3c010001, 0xac205ccc, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001,
+0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac,
+0x24020008, 0x10620005, 0x24020001, 0xc004695,
+0x0, 0x8004692, 0x0, 0x3c030001,
+0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001,
+0x8c637dd0, 0x10620003, 0x0, 0xc004e54,
+0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000,
+0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0,
+0x3442ffff, 0x621824, 0x14a40008, 0xaee30000,
+0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001,
+0x8c425cf4, 0x10620008, 0x0, 0x3c020001,
+0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0,
+0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8,
+0x24020002, 0x10620169, 0x2c620003, 0x10400005,
+0x24020001, 0x10620008, 0x0, 0x800481c,
+0x0, 0x24020004, 0x106200b1, 0x24020001,
+0x800481d, 0x0, 0x3c020001, 0x571021,
+0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a,
+0x31080, 0x3c010001, 0x220821, 0x8c225ac8,
+0x400008, 0x0, 0x3c030001, 0x8c635dbc,
+0x24020005, 0x14620014, 0x0, 0x3c020001,
+0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822,
+0x0, 0x24020002, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4,
+0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+0x800481f, 0xac205c60, 0xc004822, 0x0,
+0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60,
+0x104000dd, 0x24020002, 0x3c010001, 0x370821,
+0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4,
+0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003,
+0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf,
+0x0, 0x3c030001, 0x8c635d00, 0x800478e,
+0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001,
+0x8cc67e3c, 0xc005108, 0x2021, 0x24020005,
+0x3c010001, 0xac205cd4, 0x3c010001, 0x370821,
+0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc,
+0x3c05000f, 0x34a50100, 0x3021, 0x3821,
+0xafa00010, 0xc002403, 0xafa00014, 0x800481f,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004,
+0x431024, 0x144000a9, 0x24020007, 0x8f830054,
+0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x144000f8, 0x24020001, 0x800481d,
+0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+0x2021, 0xc005386, 0x2021, 0x3c030001,
+0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008,
+0x621024, 0x10400006, 0x0, 0x8f820214,
+0x3c03ffff, 0x431024, 0x8004741, 0x3442251f,
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f,
+0xaf820214, 0x8ee20000, 0x3c030200, 0x431025,
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+0x24020008, 0x3c010001, 0x370821, 0xac2283ac,
+0x8f820220, 0x3c030004, 0x431024, 0x14400005,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005,
+0x1462000a, 0x0, 0x3c020001, 0x94425da2,
+0x24429fbc, 0x2c420004, 0x10400004, 0x24040018,
+0x24050002, 0xc004d93, 0x24060020, 0xc0043dd,
+0x0, 0x3c010001, 0x800481f, 0xac205d50,
+0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff,
+0x2c620008, 0x104000ac, 0x31080, 0x3c010001,
+0x220821, 0x8c225ae8, 0x400008, 0x0,
+0xc00429b, 0x0, 0x3c010001, 0xac205ccc,
+0xaf800204, 0x3c010001, 0xc004822, 0xac207e20,
+0x24020001, 0x3c010001, 0xac225ce4, 0x24020002,
+0x3c010001, 0x370821, 0x800481f, 0xac2283ac,
+0xc00489f, 0x0, 0x3c030001, 0x8c635ce4,
+0x24020009, 0x14620090, 0x24020003, 0x3c010001,
+0x370821, 0x800481f, 0xac2283ac, 0x3c020001,
+0x8c427e38, 0x30424000, 0x10400005, 0x0,
+0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff,
+0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044,
+0x8f830054, 0x80047b9, 0x24020004, 0x8f830054,
+0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x14400074, 0x24020005, 0x3c010001,
+0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0xaf800204,
+0x3c010001, 0xac207e20, 0x8f830054, 0x24020006,
+0x3c010001, 0x370821, 0xac2283ac, 0x3c010001,
+0x800481f, 0xac235da4, 0x8f830054, 0x3c020001,
+0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a,
+0x14400059, 0x0, 0x24020007, 0x3c010001,
+0x370821, 0x800481f, 0xac2283ac, 0x8f820220,
+0x3c04f700, 0x441025, 0xaf820220, 0x8f820220,
+0x3c030300, 0x431024, 0x14400005, 0x1821,
+0x8f820220, 0x24030001, 0x441025, 0xaf820220,
+0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff,
+0x3c040001, 0x8c845d98, 0x431024, 0x3442251f,
+0xaf820214, 0x24020008, 0x3c010001, 0x370821,
+0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74,
+0x14400007, 0x24020001, 0x3c010001, 0xac227dd0,
+0xc004e54, 0x8f840220, 0x800480c, 0x0,
+0x8f820220, 0x3c030008, 0x431024, 0x14400017,
+0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000,
+0x2021, 0x3c030200, 0x431025, 0xc005386,
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd,
+0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+0x2021, 0x800481f, 0x0, 0x3c020001,
+0x8c425d74, 0x10400010, 0x0, 0x3c020001,
+0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70,
+0x14400009, 0x24020002, 0x3c010001, 0xac205d74,
+0x3c010001, 0x800481f, 0xac225d70, 0x24020001,
+0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820200, 0x3c060001,
+0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002,
+0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001,
+0x10c20008, 0x0, 0x8004868, 0x0,
+0x24020004, 0x10c20013, 0x24020001, 0x8004868,
+0x0, 0x3c030001, 0x8c635cb8, 0x3c020001,
+0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001,
+0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022,
+0x441025, 0x451025, 0x34420002, 0x8004867,
+0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200,
+0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74,
+0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0,
+0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0,
+0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
+0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001,
+0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825,
+0x431025, 0x451025, 0xaf820220, 0x3e00008,
+0x0, 0x8f820220, 0x3c030001, 0x8c635cc8,
+0x34420004, 0xaf820220, 0x24020001, 0x1062000f,
+0x0, 0x8f830054, 0x8f820054, 0x24630002,
+0x621023, 0x2c420003, 0x10400011, 0x0,
+0x8f820054, 0x621023, 0x2c420003, 0x1040000c,
+0x0, 0x8004879, 0x0, 0x8f830054,
+0x8f820054, 0x8004885, 0x24630007, 0x8f820054,
+0x621023, 0x2c420008, 0x1440fffc, 0x0,
+0x8f8400e0, 0x30820007, 0x1040000d, 0x0,
+0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032,
+0x8f820054, 0xa21023, 0x2c420033, 0x10400004,
+0x0, 0x8f8200e0, 0x1082fff9, 0x0,
+0x8f820220, 0x2403fffd, 0x431024, 0xaf820220,
+0x3e00008, 0x0, 0x3c030001, 0x8c635ce4,
+0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff,
+0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009,
+0x1040009d, 0x31080, 0x3c010001, 0x220821,
+0x8c225b08, 0x400008, 0x0, 0x8f820044,
+0x34428080, 0xaf820044, 0x8f830054, 0x8004938,
+0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8,
+0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a,
+0x24020003, 0x8004945, 0x0, 0x8f820044,
+0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044,
+0x8f830054, 0x8004938, 0x24020004, 0x8f830054,
+0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023,
+0x2c42000a, 0x14400078, 0x24020005, 0x8004945,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0xaf820220, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220,
+0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200,
+0x2403fffd, 0x431024, 0xaf820200, 0x24040001,
+0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054,
+0x80048ec, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
+0x42040, 0xa4102b, 0x1040fff2, 0x0,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f,
+0xaf820214, 0x8f820220, 0x2403fffb, 0x431024,
+0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008,
+0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00,
+0x346300e2, 0x441025, 0xaf820220, 0xaf830200,
+0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008,
+0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000,
+0x34630040, 0x3c020001, 0x24425c70, 0xac820000,
+0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938,
+0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8,
+0x2463fff6, 0x431023, 0x2c42000a, 0x14400022,
+0x24020007, 0x8004945, 0x0, 0x8f8200e0,
+0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7,
+0x431024, 0xaf820220, 0x8f820044, 0x34428080,
+0xaf820044, 0x8f830054, 0x24020008, 0x3c010001,
+0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8,
+0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400003, 0x24020009,
+0x3c010001, 0xac225ce4, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x27bdffd8,
+0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
+0xafb10014, 0xc08821, 0xafb00010, 0x8021,
+0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d4b, 0x2021, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x24100010, 0x2501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fffa,
+0x2501024, 0x24100010, 0x2701024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x2701024, 0xc004d71, 0x34108000,
+0xc004d71, 0x0, 0xc004d2b, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c,
+0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
+0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
+0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
+0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x2301024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2501024, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96620000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8fbf0020,
+0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00,
+0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001,
+0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349,
+0x31080, 0x3c010001, 0x220821, 0x8c225b30,
+0x400008, 0x0, 0xc004d71, 0x8021,
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010,
+0x8021, 0xc004d4b, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d4b,
+0x2021, 0xc004d4b, 0x24040001, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004d4b, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004d71, 0x34108000,
+0xc004d71, 0x0, 0xc004d2b, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004d71, 0x0, 0x97a20010, 0x30428000,
+0x144002dc, 0x24020003, 0x8004d24, 0x0,
+0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0xc004d4b, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc004d4b, 0x24040001, 0xc004d4b,
+0x2021, 0x34108000, 0x96220000, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fff8, 0x0, 0xc004d71,
+0x0, 0x8f830054, 0x8004d16, 0x24020004,
+0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c,
+0x431023, 0x2c420064, 0x1440029e, 0x24020002,
+0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003,
+0x14400296, 0x24020011, 0x24020003, 0x10620005,
+0x24020004, 0x10620291, 0x2402000f, 0x8004d24,
+0x24020011, 0x8004d24, 0x24020005, 0x24020014,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020012, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8f830054,
+0x8004d16, 0x24020006, 0x8f830054, 0x3c020001,
+0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400250, 0x24020007, 0x8004d24, 0x0,
+0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020013, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020013,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x24020008, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440020f, 0x24020009, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020017, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020017, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x14400127, 0x24020012, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020014, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020014, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x24020013, 0x8f830054,
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023,
+0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001,
+0xc004d4b, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d71, 0x34108000, 0xc004d71, 0x0,
+0xc004d2b, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004d71, 0x8021,
+0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fff8, 0x0, 0xc004d71, 0x0,
+0x8f830054, 0x8004d16, 0x2402000e, 0x24020840,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x32020013, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8f830054,
+0x24020010, 0x3c010001, 0xac225d00, 0x3c010001,
+0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001,
+0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400004, 0x0, 0x24020011, 0x3c010001,
+0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044,
+0x3c030001, 0x431025, 0x3c030008, 0xaf820044,
+0x8f840054, 0x8f820054, 0xa32824, 0x8004d37,
+0x24840001, 0x8f820054, 0x821023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+0x8f820054, 0x8004d45, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0,
+0x3442ffff, 0x42480, 0x621824, 0x3c020002,
+0x822025, 0x641825, 0xaf830044, 0x8f820044,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820044, 0x3c030001, 0x431025,
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x3e00008, 0x0,
+0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
+0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+0x809821, 0xafb5002c, 0xa0a821, 0xafb20020,
+0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028,
+0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x12000075,
+0x0, 0x8004dc9, 0x0, 0x3274ffff,
+0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2901024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2901024, 0xc004d71,
+0x34108000, 0xc004d71, 0x0, 0xc004d2b,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004d71, 0x0, 0x32a5ffff,
+0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
+0x8004e14, 0x521025, 0x14a20006, 0x3271ffff,
+0x97a20010, 0x121827, 0x431024, 0xa7a20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d4b, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d4b,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d4b,
+0x24040001, 0xc004d4b, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8,
+0x0, 0xc004d71, 0x0, 0x8fbf0030,
+0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
+0x0, 0x0, 0x0, 0x27bdffe8,
+0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac,
+0x24020008, 0x1462022c, 0x803021, 0x3c020001,
+0x8c425d98, 0x14400033, 0x0, 0x8f850224,
+0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001,
+0x621825, 0x1460000d, 0x38a30030, 0x2c630001,
+0x38a20400, 0x2c420001, 0x621825, 0x14600007,
+0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001,
+0x621825, 0x10600005, 0x0, 0xc00429b,
+0x0, 0x8004e8d, 0x2402000e, 0xc0043dd,
+0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2,
+0x2021, 0x3c030001, 0x8c635cc8, 0x24020004,
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4,
+0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4,
+0x431024, 0x3c010001, 0xac225cc4, 0x2402000e,
+0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087,
+0x0, 0x8f820220, 0x3c030400, 0x431024,
+0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001,
+0x8c427ddc, 0xa32024, 0x431024, 0x1482000c,
+0x0, 0x3c020001, 0x8c427de0, 0x24420001,
+0x3c010001, 0xac227de0, 0x2c420002, 0x14400008,
+0x24020001, 0x3c010001, 0x8004ead, 0xac227e00,
+0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00,
+0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040,
+0x10400004, 0x24020001, 0x3c010001, 0x8004eb8,
+0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001,
+0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10,
+0x24020001, 0x3c010001, 0xac227e10, 0x3c010001,
+0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001,
+0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001,
+0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003,
+0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024,
+0x10400007, 0x2463ffff, 0x8f820220, 0x24030001,
+0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700,
+0x2c62000e, 0x104001a8, 0x31080, 0x3c010001,
+0x220821, 0x8c225b80, 0x400008, 0x0,
+0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0,
+0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04,
+0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0,
+0xc00486a, 0xaf800224, 0x24020002, 0x3c010001,
+0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056,
+0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
+0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200,
+0x2403fffd, 0x431024, 0xaf820200, 0x3c010001,
+0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8,
+0x24040001, 0x3c010001, 0xac247e0c, 0x24420001,
+0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001,
+0xac237df4, 0x14400006, 0x24020003, 0x3c010001,
+0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8,
+0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054,
+0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x14400003, 0x24020004, 0x3c010001,
+0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026,
+0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024,
+0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c,
+0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001,
+0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10,
+0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff,
+0x431024, 0xaee20000, 0x8f820204, 0x30420030,
+0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c,
+0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001,
+0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10,
+0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c,
+0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002,
+0x14400131, 0x24020001, 0x3c010001, 0xac225d74,
+0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083,
+0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024,
+0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122,
+0x0, 0x3c020001, 0x8c427ddc, 0x1040011e,
+0x0, 0x3c010001, 0xac227e08, 0x24020003,
+0x3c010001, 0xac227de0, 0x8005024, 0x24020006,
+0x3c010001, 0xac207de8, 0x8f820204, 0x34420040,
+0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007,
+0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001,
+0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005,
+0x0, 0x3c020001, 0x8c427ddc, 0x104000f9,
+0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000,
+0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001,
+0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001,
+0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024,
+0x641824, 0x10430004, 0x24020001, 0x3c010001,
+0x8005083, 0xac227dd0, 0x24020003, 0xaca20000,
+0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001,
+0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001,
+0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28,
+0x14400005, 0x24020001, 0x3c020001, 0x8c427e24,
+0x10400006, 0x24020001, 0x3c010001, 0xac225ccc,
+0x3c010001, 0x8005083, 0xac207df8, 0x3c020001,
+0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001,
+0x210c0, 0x30630008, 0x3c010001, 0xac227df0,
+0x3c010001, 0xac237dec, 0x8f830054, 0x24020009,
+0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083,
+0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4,
+0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8,
+0x0, 0x3c020001, 0x8c427e00, 0x10400005,
+0x0, 0x3c020001, 0x8c427ddc, 0x104000a9,
+0x24020002, 0x3c030001, 0x24637de0, 0x8c620000,
+0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001,
+0x8c427e0c, 0x1040000e, 0x0, 0x3c020001,
+0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080,
+0x1040002f, 0x2402000c, 0x8f820204, 0x30420080,
+0x1440000c, 0x24020003, 0x8005011, 0x2402000c,
+0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005,
+0x24020003, 0x8f820204, 0x30420080, 0x1040001f,
+0x24020003, 0xac620000, 0x2402000a, 0x3c010001,
+0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000,
+0x3c030001, 0x8c637df0, 0x431025, 0xaf820204,
+0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b,
+0x3c010001, 0xac227dd0, 0x641825, 0x3c010001,
+0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000,
+0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001,
+0x8c427e10, 0x10400005, 0x0, 0x2402000c,
+0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001,
+0x8c427e00, 0x1040006c, 0x0, 0x3c040001,
+0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001,
+0x8c637dec, 0x10620064, 0x24020003, 0x3c010001,
+0xac247e08, 0xaca20000, 0x24020006, 0x3c010001,
+0x8005083, 0xac227dd0, 0x8f820200, 0x34420002,
+0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001,
+0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054,
+0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023,
+0x2c422710, 0x1440003a, 0x0, 0x3c020001,
+0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001,
+0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0,
+0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8,
+0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8,
+0x24020004, 0x14620005, 0x2403fffb, 0x3c020001,
+0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001,
+0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4,
+0x8ee20000, 0x3c030200, 0x431025, 0xaee20000,
+0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220,
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+0x34420002, 0x8005083, 0xaf820220, 0x3c020001,
+0x8c427e00, 0x10400005, 0x0, 0x3c020001,
+0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001,
+0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002,
+0x3c020001, 0x8c427e00, 0x1040000f, 0x0,
+0x3c020001, 0x8c427ddc, 0x1440000b, 0x0,
+0x24020002, 0x3c010001, 0x8005083, 0xac227dd0,
+0x3c020001, 0x8c427e00, 0x10400003, 0x0,
+0xc00429b, 0x0, 0x8f820220, 0x3c03f700,
+0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008,
+0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000,
+0x10400005, 0x34422000, 0x3c010001, 0xac227e1c,
+0x8005095, 0xac600000, 0x3c010001, 0xac247e1c,
+0x3e00008, 0x0, 0x27bdffe0, 0x30820030,
+0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067,
+0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061,
+0x24020030, 0x30822000, 0x1040005d, 0x30838000,
+0x31a02, 0x30820001, 0x21200, 0x3c040001,
+0x8c845d9c, 0x621825, 0x331c2, 0x3c030001,
+0x24635d78, 0x30828000, 0x21202, 0x30840001,
+0x42200, 0x441025, 0x239c2, 0x61080,
+0x431021, 0x471021, 0x90430000, 0x24020001,
+0x10620025, 0x0, 0x10600007, 0x24020002,
+0x10620013, 0x24020003, 0x1062002c, 0x3c05000f,
+0x80050f9, 0x0, 0x8f820200, 0x2403feff,
+0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820220, 0x3c010001,
+0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c,
+0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+0x24020100, 0x3c010001, 0xac227e44, 0x3c010001,
+0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff,
+0x431024, 0xaf820200, 0x8f820220, 0x3c030001,
+0x431025, 0xaf820220, 0x3c010001, 0xac207e44,
+0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200,
+0x34420100, 0xaf820200, 0x8f820220, 0x3c030001,
+0x431025, 0xaf820220, 0x24020100, 0x3c010001,
+0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c,
+0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010,
+0xc002403, 0xafa00014, 0x8005104, 0x0,
+0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018,
+0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8,
+0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0,
+0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001,
+0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010,
+0x24020002, 0x12620083, 0x2e620003, 0x10400005,
+0x24020001, 0x1262000a, 0x0, 0x800529b,
+0x0, 0x24020004, 0x126200fa, 0x24020008,
+0x126200f9, 0x3c02ffec, 0x800529b, 0x0,
+0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004,
+0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+0x3c010001, 0x310821, 0xac307e3c, 0x3c024000,
+0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
+0x101382, 0x3042001c, 0x3c030001, 0x24635d08,
+0x431021, 0x823821, 0x3c020020, 0x2021024,
+0x10400006, 0x24020100, 0x3c010001, 0x310821,
+0xac227e40, 0x8005150, 0x3c020080, 0x3c010001,
+0x310821, 0xac207e40, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+0x230821, 0x800515c, 0xac227e48, 0x121140,
+0x3c010001, 0x220821, 0xac207e48, 0x94e40000,
+0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010,
+0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
+0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002,
+0x24040001, 0x2821, 0xc00498e, 0x27a60018,
+0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001,
+0xac315cd4, 0x14530004, 0x32028000, 0xc00429b,
+0x0, 0x32028000, 0x1040011f, 0x0,
+0xc00429b, 0x0, 0x3c030001, 0x8c635dbc,
+0x24020005, 0x10620118, 0x24020002, 0x3c010001,
+0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8,
+0x24040001, 0x24050004, 0x27b0001a, 0xc00498e,
+0x2003021, 0x24040001, 0x2821, 0xc00498e,
+0x2003021, 0x3c020001, 0x511021, 0x8c427e34,
+0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff,
+0x3c010001, 0xac335cd4, 0x431024, 0x3c010001,
+0x310821, 0x109300fa, 0xac227e34, 0x800529b,
+0x0, 0x3c022000, 0x2021024, 0x10400005,
+0x24020001, 0x3c010001, 0xac225d98, 0x80051ad,
+0x128940, 0x3c010001, 0xac205d98, 0x128940,
+0x3c010001, 0x310821, 0xac307e38, 0x3c024000,
+0x2021024, 0x14400016, 0x0, 0x3c020001,
+0x8c425d98, 0x10400008, 0x24040004, 0x24050001,
+0xc004d93, 0x24062000, 0x24020001, 0x3c010001,
+0x370821, 0xac2283ac, 0x3c020001, 0x511021,
+0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024,
+0x3c010001, 0x310821, 0x8005299, 0xac227e30,
+0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0,
+0x2031024, 0x5443000d, 0x3c020020, 0x3c020001,
+0x8c425d9c, 0x24030100, 0x3c010001, 0x310821,
+0xac237e44, 0x3c030001, 0x3c010001, 0x310821,
+0xac237e4c, 0x80051f0, 0x34420400, 0x2021024,
+0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c,
+0x3c010001, 0x310821, 0xac237e44, 0x80051f0,
+0x34420800, 0x3c020080, 0x2021024, 0x1040002e,
+0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001,
+0x310821, 0xac237e4c, 0x34420c00, 0x3c010001,
+0xac225d9c, 0x8005218, 0x24040001, 0x3c020020,
+0x2021024, 0x10400006, 0x24020100, 0x3c010001,
+0x310821, 0xac227e44, 0x8005201, 0x3c020080,
+0x3c010001, 0x310821, 0xac207e44, 0x3c020080,
+0x2021024, 0x10400007, 0x121940, 0x3c020001,
+0x3c010001, 0x230821, 0xac227e4c, 0x800520f,
+0x24040001, 0x121140, 0x3c010001, 0x220821,
+0xac207e4c, 0x24040001, 0x2821, 0x27b0001e,
+0xc00494c, 0x2003021, 0x24040001, 0x2821,
+0xc00494c, 0x2003021, 0x24040001, 0x24050001,
+0x27b0001c, 0xc00494c, 0x2003021, 0x24040001,
+0x24050001, 0xc00494c, 0x2003021, 0x8005299,
+0x0, 0x3c02ffec, 0x3442ffff, 0x2028024,
+0x3c020008, 0x2028025, 0x121140, 0x3c010001,
+0x220821, 0xac307e38, 0x3c022000, 0x2021024,
+0x10400009, 0x0, 0x3c020001, 0x8c425d74,
+0x14400005, 0x24020001, 0x3c010001, 0xac225d98,
+0x800523a, 0x3c024000, 0x3c010001, 0xac205d98,
+0x3c024000, 0x2021024, 0x1440001e, 0x0,
+0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0,
+0x10400007, 0x24022020, 0x3c010001, 0xac225d9c,
+0x24020001, 0x3c010001, 0x370821, 0xac2283ac,
+0x3c04bfff, 0x121940, 0x3c020001, 0x431021,
+0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff,
+0x441024, 0x3c010001, 0x230821, 0xac227e30,
+0x24020001, 0x10a20044, 0x0, 0x8005299,
+0x0, 0x3c020001, 0x8c425d98, 0x1040001c,
+0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0,
+0x2031024, 0x14430005, 0x121140, 0x3402a000,
+0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001,
+0x621821, 0x8c637e38, 0x3c020020, 0x621024,
+0x10400004, 0x24022001, 0x3c010001, 0x8005294,
+0xac225d9c, 0x3c020080, 0x621024, 0x1040001f,
+0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c,
+0x3c020020, 0x2021024, 0x10400007, 0x121940,
+0x24020100, 0x3c010001, 0x230821, 0xac227e44,
+0x8005288, 0x3c020080, 0x121140, 0x3c010001,
+0x220821, 0xac207e44, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010001,
+0x230821, 0x8005294, 0xac227e4c, 0x121140,
+0x3c010001, 0x220821, 0xac207e4c, 0x3c030001,
+0x8c635cc8, 0x24020001, 0x10620003, 0x0,
+0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021,
+0xafb1001c, 0x8821, 0x24020002, 0xafbf0024,
+0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010,
+0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a,
+0x128140, 0x8005380, 0x2201021, 0x24020004,
+0x10a2007d, 0x24020008, 0x10a2007c, 0x122940,
+0x8005380, 0x2201021, 0x3c030001, 0x701821,
+0x8c637e3c, 0x3c024000, 0x621024, 0x14400009,
+0x24040001, 0x3c027fff, 0x3442ffff, 0x628824,
+0x3c010001, 0x300821, 0xac317e34, 0x8005380,
+0x2201021, 0x24050001, 0xc00494c, 0x27a60010,
+0x24040001, 0x24050001, 0xc00494c, 0x27a60010,
+0x97a20010, 0x30420004, 0x10400034, 0x3c114000,
+0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006,
+0x10400034, 0x31080, 0x3c010001, 0x220821,
+0x8c225be0, 0x400008, 0x0, 0x24040001,
+0x24050011, 0x27b00012, 0xc00494c, 0x2003021,
+0x24040001, 0x24050011, 0xc00494c, 0x2003021,
+0x97a50012, 0x30a24000, 0x10400002, 0x3c040010,
+0x3c040008, 0x3c030001, 0x8005301, 0x30a28000,
+0x24040001, 0x24050014, 0x27b00012, 0xc00494c,
+0x2003021, 0x24040001, 0x24050014, 0xc00494c,
+0x2003021, 0x97a50012, 0x30a21000, 0x10400002,
+0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800,
+0x54400001, 0x3c030002, 0x3c028000, 0x2221025,
+0x641825, 0x800530e, 0x438825, 0x3c110001,
+0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff,
+0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d,
+0x121140, 0x3c020001, 0x8c425d98, 0x10400002,
+0x3c022000, 0x2228825, 0x121140, 0x3c010001,
+0x220821, 0x8c227e40, 0x10400003, 0x3c020020,
+0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff,
+0x2228824, 0x121140, 0x3c010001, 0x220821,
+0x8c227e48, 0x10400003, 0x3c020080, 0x800532d,
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
+0x121140, 0x3c010001, 0x220821, 0xac317e34,
+0x8005380, 0x2201021, 0x122940, 0x3c030001,
+0x651821, 0x8c637e38, 0x3c024000, 0x621024,
+0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
+0x3c010001, 0x250821, 0xac317e30, 0x8005380,
+0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033,
+0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c,
+0x34842000, 0x3c030001, 0x8c635d98, 0x2102b,
+0x21023, 0x441024, 0x10600003, 0x518825,
+0x3c022000, 0x2228825, 0x3c020001, 0x451021,
+0x8c427e44, 0x10400003, 0x3c020020, 0x800535d,
+0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x121140, 0x3c010001, 0x220821, 0x8c227e4c,
+0x10400003, 0x3c020080, 0x8005368, 0x2228825,
+0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001,
+0x8c425d60, 0x10400002, 0x3c020800, 0x2228825,
+0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400,
+0x2228825, 0x3c020001, 0x8c425d68, 0x10400006,
+0x3c020100, 0x800537b, 0x2228825, 0x3c027fff,
+0x3442ffff, 0x628824, 0x121140, 0x3c010001,
+0x220821, 0xac317e30, 0x2201021, 0x8fbf0024,
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021,
+0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014,
+0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8,
+0x8f930220, 0x24020002, 0x10620063, 0x2c620003,
+0x10400005, 0x24020001, 0x1062000a, 0x141940,
+0x8005448, 0x0, 0x24020004, 0x1062005a,
+0x24020008, 0x10620059, 0x149140, 0x8005448,
+0x0, 0x3c040001, 0x832021, 0x8c847e3c,
+0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000,
+0x821024, 0x1040003e, 0x3c020008, 0x2221024,
+0x10400020, 0x36100002, 0x3c020001, 0x431021,
+0x8c427e40, 0x10400005, 0x36100020, 0x36100100,
+0x3c020020, 0x80053bd, 0x2228825, 0x2402feff,
+0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x141140, 0x3c010001, 0x220821, 0x8c227e48,
+0x10400005, 0x3c020001, 0x2629825, 0x3c020080,
+0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff,
+0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc,
+0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe,
+0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff,
+0x2228824, 0x3c010001, 0x230821, 0xac207e40,
+0x3c010001, 0x230821, 0xac207e48, 0xc00486a,
+0x0, 0xaf900200, 0xaf930220, 0x8f820220,
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220,
+0x34420002, 0xaf820220, 0x80053f3, 0x141140,
+0x8f820200, 0x2403fffd, 0x431024, 0xc00486a,
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+0x2228824, 0x141140, 0x3c010001, 0x220821,
+0x8005448, 0xac317e34, 0x149140, 0x3c040001,
+0x922021, 0x8c847e38, 0x3c110001, 0x2328821,
+0x8e317e30, 0x3c024000, 0x821024, 0x14400011,
+0x0, 0x3c020001, 0x8c425d98, 0x14400006,
+0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a,
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b,
+0x2228824, 0x3c010001, 0x320821, 0x8005448,
+0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005,
+0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b,
+0x3c020020, 0x821024, 0x10400007, 0x36100020,
+0x24020100, 0x3c010001, 0x320821, 0xac227e44,
+0x8005428, 0x36100100, 0x3c010001, 0x320821,
+0xac207e44, 0x2402feff, 0x2028024, 0x3c020080,
+0x821024, 0x10400007, 0x141940, 0x3c020001,
+0x3c010001, 0x230821, 0xac227e4c, 0x8005439,
+0x2629825, 0x141140, 0x3c010001, 0x220821,
+0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824,
+0xc00486a, 0x0, 0xaf900200, 0xaf930220,
+0x8f820220, 0x2403fffb, 0x431024, 0xaf820220,
+0x8f820220, 0x34420002, 0xaf820220, 0x141140,
+0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024,
+0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
-0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e,
-0x322e3131, 0x20313939, 0x382f3034, 0x2f323720,
-0x32323a31, 0x333a3432, 0x20736875, 0x616e6720,
-0x45787020, 0x24000000, 0x7468655f, 0x4441574e,
-0x0, 0x53544143, 0x4b5f3120, 0x0,
-0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71,
-0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
-0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43,
-0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375,
-0x6d000000, 0x52656376, 0x566c616e, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32,
-0x2e382031, 0x3939382f, 0x30372f33, 0x31203137,
-0x3a35383a, 0x34352073, 0x6875616e, 0x67204578,
-0x70202400, 0x542d446d, 0x61526431, 0x0,
-0x542d446d, 0x61424200, 0x542d446d, 0x61320000,
-0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51,
-0x64527845, 0x0, 0x656e714d, 0x45765046,
-0x61696c00, 0x656e714d, 0x45764661, 0x696c0000,
-0x6661696c, 0x456e454d, 0x0, 0x3f456e71,
-0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
-0x6576526e, 0x6746756c, 0x6c000000, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31,
-0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138,
-0x2031373a, 0x31313a31, 0x38207368, 0x75616e67,
-0x20457870, 0x20240000, 0x3f4d626f, 0x78457674,
-0x0, 0x4e4f636f, 0x6d616e64, 0x0,
-0x68737465, 0x5f455252, 0x0, 0x412d4572,
-0x72427563, 0x0, 0x4552524f, 0x522d4164,
-0x64000000, 0x656e714d, 0x45765046, 0x61696c00,
-0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
-0x456e454d, 0x0, 0x442d4572, 0x724c6173,
-0x74000000, 0x442d4572, 0x72320000, 0x6d437374,
-0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552,
-0x52000000, 0x46696c74, 0x4d644552, 0x52000000,
-0x636d645f, 0x45525200, 0x3f456e71, 0x45767400,
-0x3f6e6f51, 0x64457650, 0x0, 0x6576526e,
-0x6746756c, 0x6c000000, 0x0, 0x6ea0,
-0x7fbc, 0x6e38, 0x8734, 0x82b0,
-0x8780, 0x8780, 0x6f54, 0x7694,
-0x7f0c, 0x80a8, 0x8074, 0x8780,
-0x7e70, 0x80cc, 0x6e64, 0x81cc,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33,
-0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
-0x333a3431, 0x20736875, 0x616e6720, 0x45787020,
-0x24000000, 0x646d6172, 0x6441544e, 0x0,
-0x646d6177, 0x7241544e, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32,
-0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
-0x3a31333a, 0x35302073, 0x6875616e, 0x67204578,
-0x70202400, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e,
-0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
-0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
-0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
-0x23312046, 0x72692041, 0x70722037, 0x2031373a,
-0x35353a34, 0x38205044, 0x54203230, 0x30300000,
-0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
-0x2031373a, 0x35353a34, 0x38000000, 0x46575f43,
-0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
-0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
-0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
-0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
-0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f,
-0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a,
-0x20676363, 0x20766572, 0x73696f6e, 0x20322e37,
-0x2e320000, 0x0, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32,
-0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
-0x333a3434, 0x20736875, 0x616e6720, 0x45787020,
-0x24000000, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e,
-0x31312031, 0x3939382f, 0x31322f32, 0x32203137,
-0x3a31373a, 0x35352073, 0x6875616e, 0x67204578,
-0x70202400, 0x736e6464, 0x654e6f51, 0x20000000,
-0x6e6f454e, 0x515f5458, 0x0, 0x736e6464,
-0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845,
-0x0, 0x756e6b72, 0x64747970, 0x65000000,
-0x0, 0xaccc, 0xaccc, 0xad9c,
-0xaab0, 0xaab0, 0xad9c, 0xad9c,
-0xad9c, 0xad9c, 0xad9c, 0xad9c,
-0xad9c, 0xad9c, 0xad9c, 0xad9c,
-0xad9c, 0xad9c, 0xad9c, 0xad7c,
-0x0, 0xbca8, 0xbca8, 0xbd70,
-0xae4c, 0xb058, 0xbd70, 0xbd70,
-0xbd70, 0xbd70, 0xbd70, 0xbd70,
-0xbd70, 0xbd70, 0xbd70, 0xbd70,
-0xbd70, 0xbd70, 0xbd70, 0xbd54,
-0xb040, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e,
-0x31392031, 0x3939382f, 0x30372f32, 0x34203231,
-0x3a33303a, 0x30352073, 0x6875616e, 0x67204578,
-0x70202400, 0x706b5278, 0x45525200, 0x66726d32,
-0x4c617267, 0x65000000, 0x72784e6f, 0x52784264,
-0x0, 0x72785144, 0x6d614446, 0x0,
-0x72785144, 0x6d614246, 0x0, 0x3f6e6f51,
-0x64527845, 0x0, 0x706b5278, 0x45525273,
-0x0, 0x66726d32, 0x4c726753, 0x0,
-0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146,
-0x0, 0x3f724a42, 0x64446d46, 0x0,
-0x0, 0xf678, 0xf678, 0xf678,
-0xf678, 0xf678, 0xf678, 0xf678,
-0xf678, 0xf678, 0xf678, 0xf678,
-0xf678, 0xf678, 0xf678, 0xf678,
-0xf670, 0xf670, 0xf670, 0x572d444d,
-0x41456e46, 0x0, 0x0, 0xfdc0,
-0x1015c, 0xfddc, 0x1015c, 0x1015c,
-0x1015c, 0x1015c, 0x1015c, 0x1015c,
-0xf704, 0x1015c, 0x1015c, 0x1015c,
-0x1015c, 0x1015c, 0x10154, 0x10154,
-0x10154, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31,
-0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
-0x31333a34, 0x32207368, 0x75616e67, 0x20457870,
-0x20240000, 0x6d616374, 0x7841544e, 0x0,
-0x4e745379, 0x6e264c6b, 0x0, 0x72656d61,
-0x73737274, 0x0, 0x6c696e6b, 0x444f574e,
-0x0, 0x656e714d, 0x45765046, 0x61696c00,
-0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
-0x456e454d, 0x0, 0x6c696e6b, 0x55500000,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
-0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32,
-0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
-0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
-0x70202400, 0x50726f62, 0x65506879, 0x0,
-0x6c6e6b41, 0x53535254, 0x0, 0x11b2c,
-0x11bc4, 0x11bf8, 0x11c2c, 0x11c58,
-0x11c6c, 0x11ca8, 0x1207c, 0x11de4,
-0x11e24, 0x11e50, 0x11e90, 0x11ec0,
-0x11efc, 0x11f30, 0x1207c, 0x122c0,
-0x122d8, 0x12300, 0x12320, 0x12348,
-0x12478, 0x124a0, 0x124f4, 0x1251c,
-0x0, 0x1278c, 0x1285c, 0x12934,
-0x12a04, 0x12a60, 0x12b3c, 0x12b64,
-0x12c40, 0x12c68, 0x12e10, 0x12e38,
-0x12fe0, 0x131d8, 0x1346c, 0x13380,
-0x1346c, 0x13498, 0x13008, 0x131b0,
-0x0, 0x13b84, 0x13bc8, 0x13c60,
-0x13cac, 0x13d1c, 0x13db4, 0x13de8,
-0x13e70, 0x13f08, 0x13fd8, 0x14018,
-0x1409c, 0x140c0, 0x141f4, 0x646f4261,
-0x73655067, 0x0, 0x0, 0x0,
-0x0, 0x73746d61, 0x634c4e4b, 0x0,
-0x0, 0x14c38, 0x14c38, 0x14b80,
-0x14bc4, 0x14c38, 0x14c38, 0x0,
+0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e,
+0x322e3131, 0x20313939, 0x382f3034, 0x2f323720,
+0x32323a31, 0x333a3432, 0x20736875, 0x616e6720,
+0x45787020, 0x24000000, 0x7468655f, 0x4441574e,
+0x0, 0x53544143, 0x4b5f3120, 0x0,
+0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71,
+0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
+0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43,
+0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375,
+0x6d000000, 0x52656376, 0x566c616e, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32,
+0x2e382031, 0x3939382f, 0x30372f33, 0x31203137,
+0x3a35383a, 0x34352073, 0x6875616e, 0x67204578,
+0x70202400, 0x542d446d, 0x61526431, 0x0,
+0x542d446d, 0x61424200, 0x542d446d, 0x61320000,
+0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51,
+0x64527845, 0x0, 0x656e714d, 0x45765046,
+0x61696c00, 0x656e714d, 0x45764661, 0x696c0000,
+0x6661696c, 0x456e454d, 0x0, 0x3f456e71,
+0x45767400, 0x3f6e6f51, 0x64457650, 0x0,
+0x6576526e, 0x6746756c, 0x6c000000, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31,
+0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138,
+0x2031373a, 0x31313a31, 0x38207368, 0x75616e67,
+0x20457870, 0x20240000, 0x3f4d626f, 0x78457674,
+0x0, 0x4e4f636f, 0x6d616e64, 0x0,
+0x68737465, 0x5f455252, 0x0, 0x412d4572,
+0x72427563, 0x0, 0x4552524f, 0x522d4164,
+0x64000000, 0x656e714d, 0x45765046, 0x61696c00,
+0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
+0x456e454d, 0x0, 0x442d4572, 0x724c6173,
+0x74000000, 0x442d4572, 0x72320000, 0x6d437374,
+0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552,
+0x52000000, 0x46696c74, 0x4d644552, 0x52000000,
+0x636d645f, 0x45525200, 0x3f456e71, 0x45767400,
+0x3f6e6f51, 0x64457650, 0x0, 0x6576526e,
+0x6746756c, 0x6c000000, 0x0, 0x6ea0,
+0x7fbc, 0x6e38, 0x8734, 0x82b0,
+0x8780, 0x8780, 0x6f54, 0x7694,
+0x7f0c, 0x80a8, 0x8074, 0x8780,
+0x7e70, 0x80cc, 0x6e64, 0x81cc,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33,
+0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
+0x333a3431, 0x20736875, 0x616e6720, 0x45787020,
+0x24000000, 0x646d6172, 0x6441544e, 0x0,
+0x646d6177, 0x7241544e, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32,
+0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
+0x3a31333a, 0x35302073, 0x6875616e, 0x67204578,
+0x70202400, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e,
+0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
+0x31333a34, 0x30207368, 0x75616e67, 0x20457870,
+0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20,
+0x23312046, 0x72692041, 0x70722037, 0x2031373a,
+0x35353a34, 0x38205044, 0x54203230, 0x30300000,
+0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a,
+0x2031373a, 0x35353a34, 0x38000000, 0x46575f43,
+0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263,
+0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48,
+0x4f53543a, 0x20636f6d, 0x70757465, 0x0,
+0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149,
+0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f,
+0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a,
+0x20676363, 0x20766572, 0x73696f6e, 0x20322e37,
+0x2e320000, 0x0, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32,
+0x20313939, 0x382f3034, 0x2f323720, 0x32323a31,
+0x333a3434, 0x20736875, 0x616e6720, 0x45787020,
+0x24000000, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e,
+0x31312031, 0x3939382f, 0x31322f32, 0x32203137,
+0x3a31373a, 0x35352073, 0x6875616e, 0x67204578,
+0x70202400, 0x736e6464, 0x654e6f51, 0x20000000,
+0x6e6f454e, 0x515f5458, 0x0, 0x736e6464,
+0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845,
+0x0, 0x756e6b72, 0x64747970, 0x65000000,
+0x0, 0xaccc, 0xaccc, 0xad9c,
+0xaab0, 0xaab0, 0xad9c, 0xad9c,
+0xad9c, 0xad9c, 0xad9c, 0xad9c,
+0xad9c, 0xad9c, 0xad9c, 0xad9c,
+0xad9c, 0xad9c, 0xad9c, 0xad7c,
+0x0, 0xbca8, 0xbca8, 0xbd70,
+0xae4c, 0xb058, 0xbd70, 0xbd70,
+0xbd70, 0xbd70, 0xbd70, 0xbd70,
+0xbd70, 0xbd70, 0xbd70, 0xbd70,
+0xbd70, 0xbd70, 0xbd70, 0xbd54,
+0xb040, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e,
+0x31392031, 0x3939382f, 0x30372f32, 0x34203231,
+0x3a33303a, 0x30352073, 0x6875616e, 0x67204578,
+0x70202400, 0x706b5278, 0x45525200, 0x66726d32,
+0x4c617267, 0x65000000, 0x72784e6f, 0x52784264,
+0x0, 0x72785144, 0x6d614446, 0x0,
+0x72785144, 0x6d614246, 0x0, 0x3f6e6f51,
+0x64527845, 0x0, 0x706b5278, 0x45525273,
+0x0, 0x66726d32, 0x4c726753, 0x0,
+0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146,
+0x0, 0x3f724a42, 0x64446d46, 0x0,
+0x0, 0xf678, 0xf678, 0xf678,
+0xf678, 0xf678, 0xf678, 0xf678,
+0xf678, 0xf678, 0xf678, 0xf678,
+0xf678, 0xf678, 0xf678, 0xf678,
+0xf670, 0xf670, 0xf670, 0x572d444d,
+0x41456e46, 0x0, 0x0, 0xfdc0,
+0x1015c, 0xfddc, 0x1015c, 0x1015c,
+0x1015c, 0x1015c, 0x1015c, 0x1015c,
+0xf704, 0x1015c, 0x1015c, 0x1015c,
+0x1015c, 0x1015c, 0x10154, 0x10154,
+0x10154, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31,
+0x32203139, 0x39382f30, 0x342f3237, 0x2032323a,
+0x31333a34, 0x32207368, 0x75616e67, 0x20457870,
+0x20240000, 0x6d616374, 0x7841544e, 0x0,
+0x4e745379, 0x6e264c6b, 0x0, 0x72656d61,
+0x73737274, 0x0, 0x6c696e6b, 0x444f574e,
+0x0, 0x656e714d, 0x45765046, 0x61696c00,
+0x656e714d, 0x45764661, 0x696c0000, 0x6661696c,
+0x456e454d, 0x0, 0x6c696e6b, 0x55500000,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e,
+0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32,
+0x2e322031, 0x3939382f, 0x30342f32, 0x37203232,
+0x3a31333a, 0x33392073, 0x6875616e, 0x67204578,
+0x70202400, 0x50726f62, 0x65506879, 0x0,
+0x6c6e6b41, 0x53535254, 0x0, 0x11b2c,
+0x11bc4, 0x11bf8, 0x11c2c, 0x11c58,
+0x11c6c, 0x11ca8, 0x1207c, 0x11de4,
+0x11e24, 0x11e50, 0x11e90, 0x11ec0,
+0x11efc, 0x11f30, 0x1207c, 0x122c0,
+0x122d8, 0x12300, 0x12320, 0x12348,
+0x12478, 0x124a0, 0x124f4, 0x1251c,
+0x0, 0x1278c, 0x1285c, 0x12934,
+0x12a04, 0x12a60, 0x12b3c, 0x12b64,
+0x12c40, 0x12c68, 0x12e10, 0x12e38,
+0x12fe0, 0x131d8, 0x1346c, 0x13380,
+0x1346c, 0x13498, 0x13008, 0x131b0,
+0x0, 0x13b84, 0x13bc8, 0x13c60,
+0x13cac, 0x13d1c, 0x13db4, 0x13de8,
+0x13e70, 0x13f08, 0x13fd8, 0x14018,
+0x1409c, 0x140c0, 0x141f4, 0x646f4261,
+0x73655067, 0x0, 0x0, 0x0,
+0x0, 0x73746d61, 0x634c4e4b, 0x0,
+0x0, 0x14c38, 0x14c38, 0x14b80,
+0x14bc4, 0x14c38, 0x14c38, 0x0,
0x0, 0x0 };
static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
-0x416c7465,
-0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
-0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
-0x0, 0x0, 0x0, 0x135418,
-0x13e7fc, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x60cf00,
-0x60, 0xcf000000, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x3, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x1, 0x0,
-0x0, 0x0, 0x0, 0x1,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x1000000, 0x21000000,
-0x12000140, 0x0, 0x0, 0x20000000,
-0x120000a0, 0x0, 0x12000060, 0x12000180,
-0x120001e0, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x2,
-0x0, 0x0, 0x30001, 0x1,
+0x416c7465,
+0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465,
+0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
+0x0, 0x0, 0x0, 0x135418,
+0x13e7fc, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x60cf00,
+0x60, 0xcf000000, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x3, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x1, 0x0,
+0x0, 0x0, 0x0, 0x1,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x1000000, 0x21000000,
+0x12000140, 0x0, 0x0, 0x20000000,
+0x120000a0, 0x0, 0x12000060, 0x12000180,
+0x120001e0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x2,
+0x0, 0x0, 0x30001, 0x1,
0x30201, 0x0, 0x0, 0x0 };
#endif
/* Generated by genfw.c */
@@ -4613,4845 +4612,4845 @@ static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
#define tigon2FwBssAddr 0x00016f50
#define tigon2FwBssLen 0x20c0
static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = {
-0x0,
-0x10000003, 0x0, 0xd, 0xd,
-0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000,
-0x26104000, 0xc0010c0, 0x0, 0xd,
-0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000,
-0x26104000, 0xc0017e0, 0x0, 0xd,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x2000008,
-0x0, 0x800172f, 0x3c0a0001, 0x800172f,
-0x3c0a0002, 0x800172f, 0x0, 0x8002cac,
-0x0, 0x8002c4f, 0x0, 0x800172f,
-0x3c0a0004, 0x800328a, 0x0, 0x8001a52,
-0x0, 0x800394d, 0x0, 0x80038f4,
-0x0, 0x800172f, 0x3c0a0006, 0x80039bb,
-0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f,
-0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6,
-0x0, 0x800172f, 0x3c0a000b, 0x800172f,
-0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb,
-0x0, 0x8002890, 0x0, 0x800172f,
-0x3c0a000e, 0x800208c, 0x0, 0x8001964,
-0x0, 0x8001a04, 0x0, 0x8003ca6,
-0x0, 0x8003c94, 0x0, 0x800172f,
-0x0, 0x800191a, 0x0, 0x800172f,
-0x0, 0x800172f, 0x3c0a0013, 0x800172f,
-0x3c0a0014, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140,
-0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20,
-0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc,
-0x401821, 0x3c020010, 0x3c010001, 0xac236e9c,
-0x10620011, 0x43102b, 0x14400002, 0x3c020020,
-0x3c020008, 0x1062000c, 0x24050100, 0x3c060001,
-0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020,
-0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001,
-0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4,
-0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe,
-0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002,
-0x24639010, 0x3c040001, 0x8c846cc4, 0x431023,
-0x14800002, 0x458021, 0x2610fa38, 0x2402f000,
-0x2028024, 0xc001785, 0x2002021, 0x2022823,
-0x3c040020, 0x821823, 0x651823, 0x247bb000,
-0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf,
-0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf,
-0x3463e000, 0x852023, 0x3c010001, 0xac246ea8,
-0x822023, 0x3c010001, 0xac256e90, 0x52842,
-0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001,
-0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823,
-0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac,
-0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011,
-0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
-0xc001749, 0x0, 0x3c020001, 0x8c426cd0,
-0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200,
-0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004,
-0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021,
-0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38,
-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
-0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8,
-0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4,
-0x3c020001, 0x8c426cc8, 0x14400003, 0x0,
-0x3c010001, 0xac206cd0, 0xc001151, 0x0,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
-0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8,
-0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060,
-0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c,
-0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014,
-0x8f860040, 0x3c040001, 0x24845c80, 0x24050200,
-0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821,
-0x8f830040, 0x3c02f000, 0x621824, 0x3c026000,
-0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001,
-0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014,
-0x8f860040, 0x24050300, 0xc002b3b, 0x2003821,
-0x8f820240, 0x3c030001, 0x431025, 0xaf820240,
-0xaf800048, 0x8f820048, 0x14400005, 0x0,
-0xaf800048, 0x8f820048, 0x10400004, 0x0,
-0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c,
-0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8,
-0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001,
-0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001,
-0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001,
-0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001,
-0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001,
-0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c,
-0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138,
-0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150,
-0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140,
-0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014,
-0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014,
-0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0,
-0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014,
-0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac,
-0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c,
-0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff,
-0x1061824, 0xe81024, 0x43102b, 0x10400006,
-0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010,
-0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010,
-0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004,
-0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000,
-0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c,
-0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010,
-0xc002b3b, 0xafa30014, 0xaf800054, 0xaf80011c,
-0x8c020218, 0x30420002, 0x10400009, 0x0,
-0x8c020220, 0x3c030002, 0x34630004, 0x431025,
-0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004,
-0x8c020220, 0x3c030002, 0x34630006, 0x431025,
-0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014,
-0x8c020218, 0x30420010, 0x1040000a, 0x0,
-0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220,
-0x3c03000a, 0x34630004, 0x431025, 0x10000009,
-0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006,
-0x431025, 0xaf420008, 0x8c02021c, 0x34420006,
-0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0,
-0x8f830054, 0x8f820054, 0xaf8000d0, 0xaf8000c0,
-0x10000002, 0x24630064, 0x8f820054, 0x621023,
-0x2c420065, 0x1440fffc, 0x0, 0x8c040208,
-0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490,
-0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008,
-0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
-0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c,
-0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004,
-0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00,
-0x431024, 0x10400021, 0x0, 0x8f8200b4,
-0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001,
-0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c,
-0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001,
-0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014,
-0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b,
-0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
-0x3c030001, 0x431025, 0xaf820140, 0x96e20472,
-0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482,
-0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b,
-0xafa20014, 0x96f00452, 0x32020001, 0x10400002,
-0xb021, 0x24160001, 0x32020002, 0x54400001,
-0x36d60002, 0x32020008, 0x54400001, 0x36d60004,
-0x32020010, 0x54400001, 0x36d60008, 0x32020020,
-0x54400001, 0x36d60010, 0x32020040, 0x54400001,
-0x36d60020, 0x32020080, 0x54400001, 0x36d60040,
-0x96e60482, 0x30c20200, 0x54400001, 0x36d64000,
-0x96e30472, 0x30620200, 0x10400003, 0x30620100,
-0x10000003, 0x36d62000, 0x54400001, 0x36d61000,
-0x96f00462, 0x32c24000, 0x14400004, 0x3207009b,
-0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000,
-0x1440000d, 0x32020001, 0x3062009b, 0x10e20009,
-0x240e0001, 0x3c040001, 0x24845d20, 0x24051300,
-0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b,
-0xafa00014, 0x32020001, 0x54400001, 0x36d60080,
-0x32020002, 0x54400001, 0x36d60100, 0x32020008,
-0x54400001, 0x36d60200, 0x32020010, 0x54400001,
-0x36d60400, 0x32020080, 0x54400001, 0x36d60800,
-0x8c020218, 0x30420200, 0x10400002, 0x3c020008,
-0x2c2b025, 0x8c020218, 0x30420800, 0x10400002,
-0x3c020080, 0x2c2b025, 0x8c020218, 0x30420400,
-0x10400002, 0x3c020100, 0x2c2b025, 0x8c020218,
-0x30420100, 0x10400002, 0x3c020200, 0x2c2b025,
-0x8c020218, 0x30420080, 0x10400002, 0x3c020400,
-0x2c2b025, 0x8c020218, 0x30422000, 0x10400002,
-0x3c020010, 0x2c2b025, 0x8c020218, 0x30424000,
-0x10400002, 0x3c020020, 0x2c2b025, 0x8c020218,
-0x30421000, 0x10400002, 0x3c020040, 0x2c2b025,
-0x8ee20498, 0x8ee3049c, 0xaf420160, 0xaf430164,
-0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c,
-0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174,
-0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c,
-0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184,
-0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c,
-0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194,
-0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c,
-0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4,
-0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8,
-0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c,
-0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
-0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a,
-0x3484ca00, 0x3821, 0x24020006, 0x24030002,
-0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200,
-0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290,
-0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8,
-0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f,
-0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001,
-0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c,
-0x24051400, 0x21702, 0x24420030, 0xa062022c,
-0x3471021, 0xa040022c, 0x8c070218, 0x2c03021,
-0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014,
-0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80,
-0x24060010, 0x27b10030, 0x2203821, 0x27b30034,
-0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8,
-0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00,
-0x8fa20034, 0x246400ff, 0x852024, 0x831823,
-0x431023, 0xafa20034, 0xafa40030, 0x3c040001,
-0x24845d44, 0x3c050000, 0x24a54100, 0x24060108,
-0x2203821, 0xc0017a3, 0xafb30010, 0x409021,
-0x32c20003, 0x3c010001, 0xac326e80, 0x10400045,
-0x2203821, 0x8f820050, 0x3c030010, 0x431024,
-0x10400016, 0x0, 0x8c020218, 0x30420040,
-0x1040000f, 0x24020001, 0x8f820050, 0x8c030218,
-0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f,
-0xafa20010, 0xafa30014, 0x8f870040, 0x24051500,
-0xc002b3b, 0x2c03021, 0x10000004, 0x0,
-0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
-0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001,
-0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030,
-0x2603821, 0x27b10034, 0x34420a00, 0xaf420010,
-0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70,
-0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90,
-0xc53023, 0x2603821, 0xaf420108, 0xc0017a3,
-0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001,
-0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023,
-0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3,
-0xafb10010, 0x3c040001, 0x24845da4, 0x10000024,
-0x24051600, 0x3c040001, 0x24845dac, 0x3c050001,
-0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc,
-0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c,
-0xc53023, 0x2203821, 0xaf420108, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001,
-0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023,
-0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845de4, 0x24051650,
-0x2c03021, 0x3821, 0x3c010001, 0xac226ef8,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020,
-0x10400021, 0x27a70030, 0x3c040001, 0x24845df0,
-0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8,
-0xc53023, 0x24022000, 0xaf42001c, 0x27a20034,
-0xc0017a3, 0xafa20010, 0x21900, 0x31982,
-0x3c040800, 0x641825, 0xae430028, 0x24030010,
-0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040,
-0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010,
-0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0,
-0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c,
-0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001,
-0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10,
-0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c,
-0x24051700, 0xc002b3b, 0x3821, 0x3c020000,
-0x24425cbc, 0x21100, 0x21182, 0x3c030800,
-0x431025, 0xae420028, 0x24020008, 0xaf42003c,
-0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001,
-0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c,
-0x24051800, 0x32c60020, 0xc002b3b, 0x0,
-0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff,
-0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800,
-0x651824, 0x31882, 0x641825, 0x451024,
-0x21082, 0x441025, 0xacc20080, 0x32c20180,
-0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080,
-0x431024, 0x1040000d, 0x0, 0x8f820050,
-0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001,
-0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040,
-0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050,
-0x3c030010, 0x431024, 0x10400016, 0x0,
-0x8c020218, 0x30420040, 0x1040000f, 0x24020001,
-0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001,
-0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014,
-0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021,
-0x10000004, 0x0, 0x3c010001, 0x370821,
-0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001,
-0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023,
-0x8f420008, 0x27b30030, 0x2603821, 0x27b10034,
-0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010,
-0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4,
-0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821,
-0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001,
-0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001,
-0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001,
-0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001,
-0x24845e7c, 0x10000027, 0x24052100, 0x3c040001,
-0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001,
-0x24c6a104, 0xc53023, 0x27b10030, 0x2203821,
-0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001,
-0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001,
-0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4,
-0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4,
-0xc53023, 0x2203821, 0x3c010001, 0xac226f04,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8,
-0x24052150, 0x2c03021, 0x3821, 0x3c010001,
-0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014,
-0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff,
-0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800,
-0x711824, 0x31882, 0x6e1825, 0x511024,
-0x21082, 0x4e1025, 0xae630038, 0xae620078,
-0x8c020218, 0x30420040, 0x14400004, 0x24020001,
-0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
-0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001,
-0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821,
-0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001,
-0xac226efc, 0x511024, 0x21082, 0x3c0e0800,
-0x4e1025, 0xae620050, 0x32c22000, 0x10400006,
-0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024,
-0x1000000f, 0x21082, 0x3c040001, 0x24845ed8,
-0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4,
-0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001,
-0xac226f14, 0x511024, 0x21082, 0x3c0e0800,
-0x4e1025, 0xae620048, 0x32c24000, 0x10400005,
-0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e,
-0x21100, 0x3c040001, 0x24845ef0, 0x3c050001,
-0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023,
-0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001,
-0xac226f08, 0x21100, 0x21182, 0x3c030800,
-0x431025, 0xae420060, 0x3c040001, 0x24845f08,
-0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650,
-0xc53023, 0x27b10030, 0x2203821, 0x27b30034,
-0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff,
-0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468,
-0x3c060000, 0x24c66588, 0xc53023, 0x2203821,
-0x240f021, 0x3c010001, 0xac226edc, 0x4e1024,
-0x21082, 0x3c150800, 0x551025, 0xafae0044,
-0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001,
-0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000,
-0x24c66808, 0x8fae0044, 0xc53023, 0x2203821,
-0x3c010001, 0xac226ed0, 0x4e1024, 0x21082,
-0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010,
-0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810,
-0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023,
-0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024,
-0x21082, 0x551025, 0xafc200c0, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001,
-0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044,
-0xc53023, 0x2203821, 0x3c010001, 0xac226ed4,
-0x4e1024, 0x21082, 0x551025, 0xafc200c8,
-0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c,
-0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20,
-0xc53023, 0x2203821, 0xaf420110, 0xc0017a3,
-0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001,
-0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023,
-0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010,
-0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80,
-0x3c060001, 0x24c65aac, 0xc53023, 0x2203821,
-0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010,
-0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298,
-0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821,
-0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044,
-0x3c010001, 0xac226f18, 0x4e1024, 0x21082,
-0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40,
-0x0, 0xc0027a8, 0x0, 0xac000228,
-0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038,
-0x96e20460, 0xaf420080, 0x32c24000, 0x14400003,
-0x0, 0x96e20480, 0xaf420084, 0x96e70490,
-0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088,
-0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000,
-0x10400003, 0x24020400, 0x10e2000b, 0x0,
-0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f,
-0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138,
-0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098,
-0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084,
-0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200,
-0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58,
-0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0,
-0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c,
-0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff,
-0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010,
-0x3c010001, 0xac226eb8, 0x21100, 0x21182,
-0x511025, 0xc0018fc, 0xae420000, 0x8f820240,
-0x3c030001, 0x431025, 0xaf820240, 0x3c020000,
-0x24424034, 0xaf820244, 0xaf800240, 0x8f820060,
-0x511024, 0x14400005, 0x3c030800, 0x8f820060,
-0x431024, 0x1040fffd, 0x0, 0xc003c4d,
-0x8821, 0x3c020100, 0xafa20020, 0x8f530018,
-0x240200ff, 0x56620001, 0x26710001, 0x8c020228,
-0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
-0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
-0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x1440000b, 0x24070008,
-0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020,
-0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
-0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
-0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x14400010, 0x0,
-0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
-0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020,
-0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4,
-0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f,
-0x10400069, 0x3c020700, 0x34423000, 0xafa20028,
-0x8f530018, 0x240200ff, 0x12620002, 0x8821,
-0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f,
-0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
-0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009,
-0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200,
-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
-0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400010, 0x0, 0x8f420340, 0x24420001,
-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009,
-0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b,
-0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0,
-0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010,
-0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b,
-0x3821, 0x10000004, 0x0, 0x8c020264,
-0x10400005, 0x0, 0x8f8200a0, 0x30420004,
-0x1440fffa, 0x0, 0x8f820044, 0x34420004,
-0xaf820044, 0x8f420308, 0x24420001, 0xaf420308,
-0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023,
-0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
-0x10400006, 0x24020001, 0x8f420090, 0x8f430144,
-0x431021, 0xaf420090, 0x24020001, 0xaf42008c,
-0x32c20008, 0x10400006, 0x0, 0x8f820214,
-0x3c038100, 0x3042ffff, 0x431025, 0xaf820214,
-0x3c030001, 0x8c636d94, 0x30620002, 0x10400009,
-0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000,
-0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012,
-0xc53023, 0x10400009, 0x0, 0x3c040001,
-0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000,
-0x24c67678, 0x10000008, 0xc53023, 0x3c040001,
-0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000,
-0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034,
-0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc,
-0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100,
-0x21182, 0x431025, 0xae420040, 0x8f8200a0,
-0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c,
-0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001,
-0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001,
-0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001,
-0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b,
-0x24052400, 0x8f820200, 0xafa20010, 0x8f820220,
-0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001,
-0x24846008, 0xc002b3b, 0x24052500, 0x8f830060,
-0x74100b, 0x242000a, 0x200f821, 0x0,
-0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
-0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
-0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001,
-0x24846014, 0x24052600, 0x3021, 0x3821,
-0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
-0x0, 0x3e00008, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x3e00008, 0x0, 0x3e00008, 0x0,
-0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef,
-0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff,
-0xafa40018, 0xa22823, 0xa32824, 0x8ca20000,
-0x1044000a, 0x0, 0xafa50010, 0x8ca20000,
-0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001,
-0x2484601c, 0xc002b3b, 0x24052700, 0x8fbf0218,
-0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
-0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
-0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
-0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
-0xaca30000, 0x10460005, 0xae040000, 0xa08021,
-0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
-0x24846028, 0x24052800, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021,
-0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
-0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
-0x2821, 0x24030020, 0xe31024, 0x10400002,
-0x63042, 0xa62821, 0x31842, 0x1460fffb,
-0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
-0x45102b, 0x14400003, 0x3c020001, 0x10000008,
-0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
-0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
-0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
-0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
-0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
-0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
-0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
-0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
-0xc002b3b, 0x2403021, 0x8e230000, 0x702021,
-0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
-0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
-0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
-0x8e220000, 0x501021, 0x1000000b, 0xae220000,
-0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
-0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
-0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c,
-0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
-0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84,
-0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc,
-0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001,
-0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0,
-0xac201ffc, 0x431023, 0x441023, 0x245bb000,
-0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
-0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
-0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0,
-0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001,
-0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d,
-0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200,
-0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
-0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
-0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
-0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014,
-0xc001916, 0x0, 0x8f820240, 0x34420004,
-0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
-0x571021, 0x904240f4, 0x10400092, 0x2403fffc,
-0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c,
-0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
-0x24846040, 0x70102b, 0x1440001a, 0x27b30018,
-0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
-0xafa30014, 0xc002b3b, 0x2203821, 0x8fa30018,
-0x702021, 0x64102b, 0x10400007, 0x2403021,
-0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
-0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
-0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
-0xae620000, 0x2408821, 0x24053100, 0xafb00010,
-0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
-0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c,
-0x3c040001, 0x2484605c, 0x24120020, 0x3c010001,
-0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018,
-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50,
-0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
-0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020,
-0x65102b, 0x10400007, 0x0, 0x8c820000,
-0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
-0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
-0x8e220000, 0x521021, 0x1000000b, 0xae220000,
-0x3c100001, 0x26106f50, 0x24053100, 0xafa70010,
-0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
-0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001,
-0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001,
-0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018,
-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70,
-0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
-0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020,
-0x65102b, 0x10400007, 0x0, 0x8c820000,
-0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
-0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
-0x8e220000, 0x521021, 0x1000000b, 0xae220000,
-0x3c100001, 0x26106f70, 0x24053100, 0xafa70010,
-0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
-0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031,
-0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001,
-0x2652809c, 0x2121023, 0x438024, 0x8fa3001c,
-0x3c040001, 0x24846084, 0x70102b, 0x1440001a,
-0x27b30018, 0x8fb10018, 0x24053000, 0x2403021,
-0xafb00010, 0xafa30014, 0xc002b3b, 0x2203821,
-0x8fa30018, 0x702021, 0x64102b, 0x10400007,
-0x2403021, 0x8cc20000, 0xac620000, 0x24630004,
-0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c,
-0x501023, 0xafa2001c, 0x8e620000, 0x501021,
-0x1000000a, 0xae620000, 0x2408821, 0x24053100,
-0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021,
-0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001,
-0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400,
-0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c,
-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
-0x27bd0038, 0x0, 0x0, 0x8f820040,
-0x3c03f000, 0x431024, 0x3c036000, 0x14430006,
-0x0, 0x8f820050, 0x2403ff80, 0x431024,
-0x34420055, 0xaf820050, 0x8f820054, 0x244203e8,
-0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004,
-0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4,
-0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008,
-0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008,
-0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054,
-0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024,
-0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024,
-0x36940040, 0x3c020001, 0x8c426da8, 0x10400017,
-0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016,
-0x282a025, 0x3c020001, 0x8c426e44, 0x14400012,
-0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003,
-0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002,
-0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf,
-0x0, 0x10000004, 0x3c020200, 0xc004196,
-0x0, 0x3c020200, 0x2c21024, 0x10400003,
-0x0, 0xc001f4b, 0x0, 0x8f4200d8,
-0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b,
-0x14400003, 0x0, 0xaf4000d8, 0x36940080,
-0x8c030238, 0x1060000c, 0x0, 0x8f4201b0,
-0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006,
-0x0, 0x934205c5, 0x14400003, 0x0,
-0xc001da0, 0x0, 0x8fbf0010, 0x3e00008,
-0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8,
-0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059,
-0x0, 0x3c020001, 0x571021, 0x904240f0,
-0x10400026, 0x24070008, 0x8f440170, 0x8f450174,
-0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f0, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x24846128, 0xafa20014,
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
-0x34a50900, 0x1000005c, 0x0, 0x8f420300,
-0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c,
-0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170,
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
-0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
-0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120,
-0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036,
-0x0, 0x8f420300, 0x8f43002c, 0x24420001,
-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
-0xaf430038, 0x3c010001, 0x370821, 0xa02040f1,
-0x3c010001, 0x370821, 0xa02040f0, 0x10000026,
-0xaf400034, 0x934205c1, 0x1040001d, 0x0,
-0xa34005c1, 0x8f820040, 0x30420001, 0x14400008,
-0x2021, 0x8c030104, 0x24020001, 0x50620005,
-0x24040001, 0x8c020264, 0x10400003, 0x801021,
-0x24040001, 0x801021, 0x10400006, 0x0,
-0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008,
-0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
-0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
-0x3c010001, 0x370821, 0xa02040f0, 0x3c010001,
-0x370821, 0xa02040f1, 0x8f420000, 0x10400007,
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
-0x0, 0x10000005, 0x0, 0xaf800048,
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
-0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008,
-0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8,
-0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029,
-0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c,
-0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044,
-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300,
-0x1000000f, 0x0, 0x8f420304, 0x24420001,
-0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
-0x3c010001, 0x370821, 0xa02040f2, 0x10000004,
-0xaf400078, 0x3c010001, 0x370821, 0xa02040f2,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x3c03feff, 0x3463ffff,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
-0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8,
-0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
-0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5,
-0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b,
-0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002,
-0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001,
-0x8c636d98, 0x34420002, 0xaf420004, 0x24020001,
-0x14620003, 0x3c020600, 0x10000002, 0x34423000,
-0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034,
-0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff,
-0x11420002, 0x1821, 0x25430001, 0x8c020228,
-0x609821, 0x1662000e, 0x3c050009, 0x8f42033c,
-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
-0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014,
-0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500,
-0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020,
-0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
-0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
-0x1040001b, 0xa821, 0xe09021, 0x265e04c0,
-0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004,
-0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021,
-0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008,
-0xa32821, 0xa3482b, 0x822021, 0x100f809,
-0x892021, 0x54400006, 0x24150001, 0x8f820054,
-0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0,
-0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846118, 0xafa20014, 0x8d460000,
-0x3c050009, 0x10000035, 0x34a50600, 0x8f420308,
-0x24150001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054,
-0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016,
-0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c,
-0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010,
-0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c,
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
-0x0, 0x8f820054, 0x2221023, 0x2c4203e9,
-0x1440ffee, 0x0, 0x32a200ff, 0x14400011,
-0x3c050009, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
-0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec,
-0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029,
-0x36100040, 0x3c020400, 0x2c21024, 0x10400013,
-0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4,
-0x14640006, 0x36100040, 0x8f420270, 0x8f430274,
-0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250,
-0x8f430254, 0x8f440270, 0x8f450274, 0x10000012,
-0x3a100020, 0x1000002b, 0x2028024, 0x8f420250,
-0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024,
-0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021,
-0x36100040, 0x8f420250, 0x8f430254, 0x8f440270,
-0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019,
-0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011,
-0x28420033, 0x8f420004, 0x30420001, 0x10400009,
-0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf,
-0x2028024, 0x1000000b, 0x36100040, 0x10000009,
-0x36100060, 0x8f4200d4, 0x36100040, 0x24430001,
-0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4,
-0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024,
-0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
-0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
-0x27bd0058, 0x3e00008, 0x0, 0x3c020001,
-0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
-0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001,
-0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004,
-0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004,
-0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004,
-0x24020001, 0x14620003, 0x3c020600, 0x10000002,
-0x34423000, 0x34421000, 0xafa20020, 0x1821,
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
-0x8d460000, 0x10000035, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016,
-0x9821, 0x3c150020, 0x24110010, 0x8f42000c,
-0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
-0xafb20014, 0x551025, 0xafa20018, 0x8f42010c,
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
-0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
-0x1440ffee, 0x0, 0x326200ff, 0x14400011,
-0x0, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846120, 0x3c050009,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
-0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec,
-0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018,
-0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4,
-0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270,
-0x8f430274, 0x8f4401b8, 0x10640021, 0x0,
-0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0,
-0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4,
-0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0,
-0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001,
-0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001,
-0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001,
-0x8f420004, 0x30420001, 0x10400008, 0x0,
-0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1,
-0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4,
-0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5,
-0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1,
-0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1,
-0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c,
-0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001,
-0x5462001f, 0x2021, 0x3c020001, 0x90426cf0,
-0x1443001b, 0x24040005, 0x10000019, 0x24040006,
-0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b,
-0x24020001, 0x3c030001, 0x90636cf1, 0x54620010,
-0x2021, 0x3c020001, 0x90426cf0, 0x1443000c,
-0x24040003, 0x1000000a, 0x24040004, 0x3c030001,
-0x90636cf1, 0x14620006, 0x2021, 0x3c020001,
-0x90426cf0, 0x24040001, 0x50440001, 0x24040002,
-0xc00565a, 0x0, 0x2402ff7f, 0x282a024,
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x3e00008, 0x0, 0x3c020001,
-0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
-0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001,
-0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8,
-0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
-0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
-0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
-0x10000002, 0x34423000, 0x34421000, 0xafa20020,
-0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
-0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
-0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
-0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014,
-0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
-0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
-0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
-0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
-0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
-0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
-0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
-0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
-0x822021, 0x100f809, 0x892021, 0x54400006,
-0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
-0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
-0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846118, 0x3c050009,
-0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
-0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
-0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
-0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
-0x10400016, 0x9821, 0x3c150020, 0x24110010,
-0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
-0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
-0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
-0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
-0x14400011, 0x0, 0x8f420378, 0x24420001,
-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
-0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
-0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001,
-0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
-0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
-0x0, 0x934205c0, 0x8f440250, 0x8f450254,
-0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
-0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
-0x0, 0x8f420250, 0x8f430254, 0x934405c0,
-0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
-0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
-0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
-0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
-0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
-0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
-0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
-0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
-0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
-0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
-0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
-0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
-0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
-0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
-0x10400007, 0x0, 0x934205c0, 0x34420040,
-0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
-0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
-0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
-0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
-0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
-0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
-0x14620005, 0x0, 0x934405c0, 0x42102,
-0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
-0xc005640, 0x0, 0x2402ff7f, 0x282a024,
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
-0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
-0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
-0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
-0x8c820000, 0xac620000, 0x24630004, 0x65102b,
-0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
-0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
-0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
-0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
-0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
-0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
-0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
-0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
-0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
-0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
-0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
-0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
-0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
-0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
-0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
-0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
-0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
-0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
-0x24040001, 0x24050000, 0x651821, 0x65302b,
-0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
-0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
-0x24090000, 0x401821, 0x1021, 0x882024,
-0xa92824, 0x822025, 0xa32825, 0xaee400c0,
-0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
-0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
-0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
-0x65302b, 0x441021, 0x461021, 0xaee200d0,
-0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
-0x401821, 0x1021, 0x882024, 0xa92824,
-0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
-0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
-0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
-0x24040001, 0x24050000, 0x651821, 0x65302b,
-0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
-0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
-0x1021, 0x882024, 0xa92824, 0x822025,
-0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
-0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
-0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
-0x40f809, 0x24070400, 0x104000f0, 0x3c020400,
-0xafa20020, 0x934205c6, 0x10400089, 0x1821,
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
-0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
-0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24846120, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x1021,
-0x1440005b, 0x24020001, 0x10000065, 0x0,
-0x8f510018, 0x240200ff, 0x12220002, 0x8021,
-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x54400011, 0x24020001, 0x8f420340, 0x24420001,
-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846104, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
-0x2203821, 0x1021, 0x1040000d, 0x24020001,
-0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
-0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
-0xaee20150, 0x10000003, 0x8ee20150, 0x24020001,
-0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020,
-0x8f8200b0, 0x30420004, 0x10400068, 0x0,
-0x8f430128, 0x8f820104, 0x14620005, 0x0,
-0x8f430130, 0x8f8200b4, 0x10620006, 0x0,
-0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b,
-0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024,
-0x1040000d, 0x0, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024,
-0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024,
-0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104,
-0x14620005, 0x0, 0x8f430130, 0x8f8200b4,
-0x10620010, 0x0, 0x8f820104, 0xaf420128,
-0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010,
-0x8f420130, 0x3c040001, 0x24846144, 0xafa20014,
-0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031,
-0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130,
-0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c,
-0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000,
-0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104,
-0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008,
-0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c,
-0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c,
-0x26e60028, 0x40f809, 0x24070400, 0x8f82011c,
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128,
-0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c,
-0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
-0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0,
-0x30420004, 0x10400069, 0x0, 0x8f43012c,
-0x8f820124, 0x14620005, 0x0, 0x8f430134,
-0x8f8200a4, 0x10620006, 0x0, 0x8f820124,
-0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134,
-0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d,
-0x0, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0,
-0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b,
-0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005,
-0x0, 0x8f430134, 0x8f8200a4, 0x10620010,
-0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
-0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134,
-0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c,
-0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200,
-0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001,
-0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0,
-0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c,
-0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0,
-0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124,
-0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208,
-0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001,
-0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c,
-0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
-0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c,
-0xafa20010, 0x8f420134, 0x3c040001, 0x24846180,
-0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
-0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020,
-0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001,
-0x3c060080, 0x3c050100, 0x8f820070, 0x481024,
-0x1040fffd, 0x0, 0x8f820054, 0x24420005,
-0xaf820078, 0x8c040234, 0x10800016, 0x1821,
-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
-0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
-0x0, 0x3c030080, 0x3c010001, 0x370821,
-0xac2040e8, 0x3c010001, 0x370821, 0x1000000b,
-0xa02740f0, 0x3c020001, 0x571021, 0x904240f0,
-0x54400006, 0x661825, 0x3c020001, 0x571021,
-0x904240f1, 0x54400001, 0x661825, 0x8c040230,
-0x10800013, 0x0, 0x3c020001, 0x571021,
-0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
-0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
-0x44102b, 0x14400006, 0x0, 0x3c010001,
-0x370821, 0xac2040ec, 0x10000006, 0x651825,
-0x3c020001, 0x571021, 0x904240f2, 0x54400001,
-0x651825, 0x1060ffbc, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x1000ffa7, 0xaf80004c,
-0x1000ffa5, 0xaf800048, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025,
-0x24040004, 0x8c020114, 0xaf420020, 0xaf840064,
-0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc,
-0x8f820064, 0x30420004, 0x14400005, 0x0,
-0x8c030114, 0x8f420020, 0x1462fff2, 0x0,
-0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x431025, 0xaf820060,
-0x8f420000, 0x10400073, 0x0, 0x1000006f,
-0x0, 0x30c20008, 0x10400020, 0x24040008,
-0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
-0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
-0x30420008, 0x14400005, 0x0, 0x8c03011c,
-0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
-0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
-0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
-0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
-0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
-0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
-0x30c20010, 0x10400029, 0x24040010, 0x8c020124,
-0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
-0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
-0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
-0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x34420100, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x1000006c,
-0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001,
-0x10400004, 0x24020001, 0xaf820064, 0x10000064,
-0x0, 0x30c20002, 0x1440000b, 0x3c050003,
-0x3c040001, 0x24846244, 0x34a50500, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0,
-0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c,
-0x10a20048, 0x51080, 0x8c460300, 0x24a20001,
-0x3045003f, 0x24020003, 0xac05022c, 0x61e02,
-0x10620005, 0x24020010, 0x1062001d, 0x30c20fff,
-0x10000039, 0x0, 0x8f4302a8, 0x8f440000,
-0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8,
-0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
-0x1040001f, 0x0, 0x1000001b, 0x0,
-0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
-0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
-0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x34420100, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000006, 0xaf80004c,
-0x10000004, 0xaf800048, 0xc002196, 0xc02021,
-0x402821, 0x8c02010c, 0x14a20002, 0x24020002,
-0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
-0x0, 0x8c02010c, 0x14a2ffac, 0x0,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
-0x0, 0x27bdffa0, 0xafb00040, 0x808021,
-0x101602, 0x2442ffff, 0x304300ff, 0x2c620013,
-0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
-0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034,
-0x31080, 0x3c010001, 0x220821, 0x8c226288,
-0x400008, 0x0, 0x101302, 0x30440fff,
-0x24020001, 0x10820005, 0x24020002, 0x1082000c,
-0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004,
-0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204,
-0x3c040001, 0x8c846e80, 0x10000009, 0x34630001,
-0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001,
-0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28,
-0x21100, 0x21182, 0xaf430004, 0x3c030800,
-0x431025, 0xac820038, 0x8f840054, 0x41442,
-0x41c82, 0x431021, 0x41cc2, 0x431023,
-0x41d02, 0x431021, 0x41d42, 0x431023,
-0x10000009, 0xaf420208, 0x3c040001, 0x24846250,
-0x34a51000, 0x2003021, 0x3821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001,
-0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028,
-0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
-0xc002518, 0x2002021, 0x10000216, 0x0,
-0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
-0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
-0x21080, 0x8c430300, 0x25420001, 0x3042003f,
-0xafa20034, 0xac02022c, 0xafa50028, 0xc002518,
-0xafa3002c, 0x10000203, 0x0, 0x27b00028,
-0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
-0xc002657, 0x2002021, 0x100001fa, 0x0,
-0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
-0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
-0x21080, 0x8c430300, 0x25420001, 0x3042003f,
-0xafa20034, 0xac02022c, 0xafa50028, 0xc002657,
-0xafa3002c, 0x100001e7, 0x0, 0x101302,
-0x30430fff, 0x24020001, 0x10620005, 0x24020002,
-0x1062001e, 0x3c020002, 0x10000033, 0x3c050003,
-0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025,
-0x8f820228, 0x3c010001, 0x370821, 0xac2238d8,
-0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc,
-0x8f820230, 0x3c010001, 0x370821, 0xac2238e0,
-0x8f820234, 0x3c010001, 0x370821, 0xac2238e4,
-0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230,
-0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024,
-0x10400012, 0x3c02fffd, 0x3c020001, 0x571021,
-0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021,
-0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021,
-0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021,
-0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff,
-0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c,
-0x34a51100, 0x2003021, 0x3821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001,
-0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302,
-0x30450fff, 0x24020001, 0x10a20005, 0x24020002,
-0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003,
-0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004,
-0x2c4b025, 0x621824, 0x34630008, 0xaf830220,
-0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb,
-0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024,
-0xaf820220, 0x10000009, 0xaf450298, 0x3c040001,
-0x24846268, 0x34a51200, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc,
-0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc,
-0x27840208, 0x24050200, 0xc002bbf, 0x24060008,
-0x27440224, 0x24050200, 0xc002bbf, 0x24060008,
-0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169,
-0x8f4202c4, 0x101302, 0x30430fff, 0x24020001,
-0x10620011, 0x28620002, 0x50400005, 0x24020002,
-0x10600007, 0x0, 0x10000017, 0x0,
-0x1062000f, 0x0, 0x10000013, 0x0,
-0x8c060248, 0x2021, 0xc005104, 0x24050004,
-0x10000007, 0x0, 0x8c060248, 0x2021,
-0xc005104, 0x24050004, 0x10000010, 0x0,
-0x8c06024c, 0x2021, 0xc005104, 0x24050001,
-0x1000000a, 0x0, 0x3c040001, 0x24846274,
-0x3c050003, 0x34a51300, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0,
-0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0,
-0xc002426, 0x0, 0x10000136, 0x0,
-0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8,
-0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014,
-0xafa20018, 0x8f420108, 0x26e60028, 0x40f809,
-0x24070400, 0x1040fff5, 0x0, 0x10000125,
-0x0, 0x3c03ffff, 0x34637fff, 0x8f420368,
-0x8f440360, 0x2c3b024, 0x1821, 0xaf400058,
-0xaf40005c, 0xaf400060, 0xaf400064, 0x441023,
-0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020,
-0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
-0xafaa003c, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846218, 0x3c050009, 0xafa20014,
-0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24846220, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0,
-0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8,
-0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8,
-0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
-0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8,
-0x8f820220, 0x30420008, 0x14400002, 0x24020001,
-0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001,
-0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff,
-0x3442ffff, 0x2021824, 0x32c20180, 0x14400006,
-0x3402fffb, 0x43102b, 0x14400003, 0x0,
-0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280,
-0x3c050003, 0x34a51500, 0x2003021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700,
-0x34421000, 0x101e02, 0x621825, 0xafa30020,
-0x8f510018, 0x240200ff, 0x12220002, 0x8021,
-0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
-0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
-0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
-0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
-0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
-0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
-0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400010, 0x0, 0x8f420340, 0x24420001,
-0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846204, 0x3c050009,
-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
-0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0,
-0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0,
-0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054,
-0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044,
-0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8,
-0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8,
-0x354a8320, 0x90870000, 0x24840001, 0x3021,
-0x1071026, 0x30420001, 0x10400002, 0x81842,
-0x6a1826, 0x604021, 0x24c60001, 0x2cc20008,
-0x1440fff7, 0x73842, 0x25290001, 0x125102b,
-0x1440fff0, 0x0, 0x1001021, 0x3e00008,
-0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
-0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
-0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200,
-0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820220, 0x8f820200,
-0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004,
-0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360,
-0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c,
-0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0,
-0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8,
-0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360,
-0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368,
-0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c,
-0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
-0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf,
-0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc,
-0x240203e8, 0x24040002, 0x24030001, 0xaf420294,
-0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008,
-0x10400004, 0x0, 0xaf430298, 0x10000003,
-0x3021, 0xaf440298, 0x3021, 0x3c030001,
-0x661821, 0x90636d00, 0x3461021, 0x24c60001,
-0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821,
-0x24c60001, 0x8f820040, 0x24040080, 0x24050080,
-0x21702, 0x24420030, 0xa062022c, 0x3461021,
-0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004,
-0x14400006, 0x0, 0x8f820220, 0x3c0308ff,
-0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c,
-0x30e20004, 0x14400006, 0x0, 0x8f820200,
-0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
-0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
-0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
-0x27bd0050, 0x0, 0x0, 0xaf400104,
-0x24040001, 0x410c0, 0x2e21821, 0x24820001,
-0x3c010001, 0x230821, 0xa42234d0, 0x402021,
-0x2c820080, 0x1440fff8, 0x410c0, 0x24020001,
-0x3c010001, 0x370821, 0xa42038d0, 0xaf420100,
-0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234,
-0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014,
-0xafb00010, 0x8f420104, 0x28420005, 0x10400026,
-0x808021, 0x3c020001, 0x8f430104, 0x344230d0,
-0x2e22021, 0x318c0, 0x621821, 0x2e31821,
-0x83102b, 0x10400015, 0x1021, 0x96070000,
-0x24840006, 0x24660006, 0x9482fffc, 0x14470009,
-0x2821, 0x9483fffe, 0x96020002, 0x14620006,
-0xa01021, 0x94820000, 0x96030004, 0x431026,
-0x2c450001, 0xa01021, 0x14400009, 0x24840008,
-0x86102b, 0x1440fff0, 0x1021, 0x304200ff,
-0x14400030, 0x24020001, 0x1000002e, 0x1021,
-0x1000fffa, 0x24020001, 0x2002021, 0xc00240c,
-0x24050006, 0x3042007f, 0x218c0, 0x2e31021,
-0x3c010001, 0x220821, 0x942230d0, 0x1040fff2,
-0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0,
-0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000,
-0x610c0, 0x572021, 0x882021, 0x94820000,
-0x14470009, 0x2821, 0x94830002, 0x96020002,
-0x14620006, 0xa01021, 0x94820004, 0x96030004,
-0x431026, 0x2c450001, 0xa01021, 0x14400007,
-0x610c0, 0x2e21021, 0x3c060001, 0xc23021,
-0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2,
-0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008,
-0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0,
-0x801021, 0xafb00030, 0x24500002, 0x2002021,
-0x24050006, 0xafb10034, 0x408821, 0xafbf0048,
-0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c,
-0xafb20038, 0x3047007f, 0x710c0, 0x2e21021,
-0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c,
-0xa03021, 0x3c090001, 0x352934d2, 0x96280002,
-0x510c0, 0x572021, 0x892021, 0x94820000,
-0x14480009, 0x3021, 0x94830002, 0x96020002,
-0x14620006, 0xc01021, 0x94820004, 0x96030004,
-0x431026, 0x2c460001, 0xc01021, 0x14400007,
-0x510c0, 0x2e21021, 0x3c050001, 0xa22821,
-0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021,
-0x10c00014, 0x610c0, 0x571821, 0x3c010001,
-0x230821, 0x8c2334d0, 0x571021, 0xafa30010,
-0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001,
-0x24846394, 0xafa20014, 0x8e260000, 0x8e270004,
-0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063,
-0x3c020800, 0x8f450100, 0x10a00006, 0x510c0,
-0x2e21021, 0x3c010001, 0x220821, 0x942234d0,
-0xaf420100, 0xa03021, 0x14c00011, 0x628c0,
-0x710c0, 0x2e21021, 0xafa70010, 0x3c010001,
-0x220821, 0x942230d0, 0x3c040001, 0x248463a0,
-0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004,
-0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800,
-0xb71821, 0x3c020001, 0x96040000, 0x344234d2,
-0x621821, 0xa4640000, 0x8e020002, 0x720c0,
-0xac620002, 0x2e41021, 0x3c030001, 0x621821,
-0x946330d0, 0x2e51021, 0x3c010001, 0x220821,
-0xa42334d0, 0x2e41021, 0x3c010001, 0x220821,
-0xa42630d0, 0x8f420104, 0x24420001, 0x28420080,
-0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001,
-0x348430d2, 0x96030000, 0x210c0, 0x571021,
-0x441021, 0xa4430000, 0x8e030002, 0xac430002,
-0x8f420104, 0x24420001, 0xaf420104, 0x3c020002,
-0x2c21024, 0x10400011, 0x72142, 0x3c030001,
-0x346338d8, 0x24020003, 0x441023, 0x21080,
-0x572021, 0x832021, 0x571021, 0x431021,
-0x30e5001f, 0x8c430000, 0x24020001, 0xa21004,
-0x621825, 0x1000000c, 0xac830000, 0x24020003,
-0x441023, 0x21080, 0x5c2821, 0x5c1021,
-0x30e4001f, 0x8c430228, 0x24020001, 0x821004,
-0x621825, 0xaca30228, 0x3c020800, 0x34421000,
-0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020,
-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
-0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440178,
-0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846368,
-0x3c050009, 0xafa20014, 0x8d460000, 0x10000033,
-0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
-0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
-0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
-0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
-0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
-0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
-0x1440ffef, 0x0, 0x326200ff, 0x14400011,
-0x0, 0x8f420378, 0x24420001, 0xaf420378,
-0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
-0x8f820124, 0x3c040001, 0x24846370, 0x3c050009,
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
-0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4,
-0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4,
-0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021,
-0xafb00040, 0x24500002, 0x2002021, 0x24050006,
-0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054,
-0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048,
-0x3048007f, 0x810c0, 0x2e21021, 0x3c060001,
-0xc23021, 0x94c630d0, 0x10c0001c, 0x3821,
-0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0,
-0x572021, 0x8a2021, 0x94820000, 0x14490009,
-0x2821, 0x94830002, 0x96020002, 0x14620006,
-0xa01021, 0x94820004, 0x96030004, 0x431026,
-0x2c450001, 0xa01021, 0x14400008, 0x610c0,
-0xc03821, 0x2e21021, 0x3c060001, 0xc23021,
-0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011,
-0xafa70028, 0x810c0, 0x2e21021, 0xafa80010,
-0x3c010001, 0x220821, 0x942230d0, 0x3c040001,
-0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004,
-0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075,
-0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021,
-0x3c030001, 0x621821, 0x946334d0, 0x710c0,
-0x2e21021, 0x3c010001, 0x220821, 0xa42334d0,
-0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001,
-0x621821, 0x946334d0, 0x810c0, 0x2e21021,
-0x3c010001, 0x220821, 0xa42330d0, 0x3c040001,
-0x348430d0, 0x8f430100, 0x610c0, 0x2e21021,
-0x3c010001, 0x220821, 0xa42334d0, 0x8f420104,
-0x2e43821, 0x2821, 0x18400029, 0xaf460100,
-0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009,
-0x2021, 0x94c3fffe, 0x96020002, 0x14620006,
-0x801021, 0x94c20000, 0x96030004, 0x431026,
-0x2c440001, 0x801021, 0x50400014, 0x24a50001,
-0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b,
-0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe,
-0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff,
-0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104,
-0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104,
-0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008,
-0x810c0, 0x2e21021, 0x3c010001, 0x220821,
-0x942230d0, 0x14400023, 0x3c020800, 0x3c020002,
-0x2c21024, 0x10400012, 0x82142, 0x3c030001,
-0x346338d8, 0x24020003, 0x441023, 0x21080,
-0x572021, 0x832021, 0x571021, 0x431021,
-0x3105001f, 0x24030001, 0x8c420000, 0xa31804,
-0x31827, 0x431024, 0x1000000d, 0xac820000,
-0x24020003, 0x441023, 0x21080, 0x5c2821,
-0x5c1021, 0x3104001f, 0x24030001, 0x8c420228,
-0x831804, 0x31827, 0x431024, 0xaca20228,
-0x3c020800, 0x34422000, 0x1821, 0xafa20020,
-0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002,
-0xafab0034, 0x27c30001, 0x8c020228, 0x609021,
-0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
-0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
-0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010,
-0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
-0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
-0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
-0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c,
-0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
-0x24070008, 0xa32821, 0xa3482b, 0x822021,
-0x100f809, 0x892021, 0x54400006, 0x24130001,
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
-0x0, 0x326200ff, 0x54400017, 0xaf520018,
-0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
-0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124,
-0x3c040001, 0x24846368, 0x3c050009, 0xafa20014,
-0x8d660000, 0x10000033, 0x34a50600, 0x8f420308,
-0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
-0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
-0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
-0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001,
-0x24846370, 0x3c050009, 0xafa20014, 0x8d660000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8,
-0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4,
-0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058,
-0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
-0x0, 0x0, 0x0, 0x27bdffe0,
-0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000,
-0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8,
-0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100,
-0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114,
-0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128,
-0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec,
-0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4,
-0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021,
-0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c,
-0x3c040001, 0x24846470, 0x3c050001, 0x34420001,
-0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
-0x34a50100, 0xc002b3b, 0x3821, 0x8c020218,
-0x30420040, 0x10400014, 0x0, 0x8f82011c,
-0x3c040001, 0x2484647c, 0x3c050001, 0x34420004,
-0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
-0x10000007, 0x34a50200, 0x3c040001, 0x24846484,
-0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300,
-0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014,
-0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002,
-0x24680020, 0x27684800, 0x8f820128, 0x11020004,
-0x0, 0x8f820124, 0x15020007, 0x0,
-0x8f430334, 0x1021, 0x24630001, 0xaf430334,
-0x10000039, 0x8f430334, 0xac640000, 0xac650004,
-0xac660008, 0xa467000e, 0xac690018, 0xac6a001c,
-0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc,
-0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000,
-0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f,
-0x10400018, 0x3c020001, 0x8c830004, 0x2c620010,
-0x10400013, 0x3c020001, 0x24630001, 0xac830004,
-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
-0x14440015, 0x24020001, 0x8f820128, 0x24420020,
-0xaf820128, 0x8f820128, 0x1000000f, 0x24020001,
-0x3c020001, 0x344230c8, 0x2e21021, 0x54820004,
-0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021,
-0x402021, 0x24020001, 0xaf4400f4, 0xac890000,
-0xac820004, 0x24020001, 0x3e00008, 0x0,
-0x3e00008, 0x0, 0x8fa90010, 0x8f83010c,
-0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0,
-0x14620002, 0x24680020, 0x27684000, 0x8f820108,
-0x11020004, 0x0, 0x8f820104, 0x15020007,
-0x0, 0x8f430338, 0x1021, 0x24630001,
-0xaf430338, 0x10000035, 0x8f430338, 0xac640000,
-0xac650004, 0xac660008, 0xa467000e, 0xac690018,
-0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100,
-0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019,
-0x31220006, 0x10400018, 0x3c020001, 0x8c830004,
-0x2c620010, 0x10400013, 0x3c020001, 0x24630001,
-0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021,
-0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
-0x2e21021, 0x14440015, 0x24020001, 0x8f820108,
-0x24420020, 0xaf820108, 0x8f820108, 0x1000000f,
-0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021,
-0x54820004, 0x24820008, 0x3c020001, 0x34422cc0,
-0x2e21021, 0x402021, 0x24020001, 0xaf4400ec,
-0xac890000, 0xac820004, 0x24020001, 0x3e00008,
-0x0, 0x3e00008, 0x0, 0x27bdffd8,
-0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024,
-0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104,
-0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100,
-0x2403021, 0x2203821, 0xafa20010, 0xc002b3b,
-0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c,
-0x3c040001, 0x24846498, 0xafa20014, 0x8e060000,
-0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510,
-0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001,
-0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014,
-0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00,
-0x2221024, 0x3c030800, 0x54430016, 0x3c030200,
-0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200,
-0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030,
-0x3021, 0x3821, 0x36420002, 0xaf82011c,
-0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024,
-0x0, 0x2c31024, 0x1040000d, 0x2231024,
-0x1040000b, 0x36420002, 0xaf82011c, 0x36220001,
-0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330,
-0x24420001, 0xaf420330, 0x10000015, 0x8f420330,
-0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010,
-0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0,
-0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002,
-0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
-0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
-0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001,
-0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020,
-0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0,
-0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021,
-0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014,
-0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001,
-0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004,
-0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018,
-0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500,
-0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001,
-0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024,
-0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac,
-0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001,
-0x2484650c, 0x3c050001, 0x34a5f030, 0x3021,
-0x3821, 0x36420002, 0xaf82011c, 0x36220001,
-0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x10000024, 0x0,
-0x2c31024, 0x1040000d, 0x2231024, 0x1040000b,
-0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
-0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001,
-0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001,
-0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014,
-0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b,
-0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
-0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
-0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
-0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
-0x27bd0028, 0x6021, 0x5021, 0x3021,
-0x2821, 0x6821, 0x4821, 0x7821,
-0x7021, 0x8f880124, 0x8f870104, 0x1580002e,
-0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120,
-0x10460029, 0x0, 0x3c040001, 0x8c846ee4,
-0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004,
-0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e,
-0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014,
-0x10000012, 0x24c60020, 0x10400017, 0x0,
-0x3c040001, 0x8c846ee4, 0x8d020000, 0x8d030004,
-0xac820000, 0xac830004, 0x8d020008, 0xac820008,
-0x9502000e, 0xa482000e, 0x8d020010, 0x25060020,
-0xac820010, 0x8d020014, 0x240c0001, 0xc01821,
-0xac820014, 0x27624fe0, 0x43102b, 0x54400001,
-0x27634800, 0x603021, 0x1540002f, 0x31620100,
-0x11200014, 0x31628000, 0x8f820100, 0x1045002a,
-0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000,
-0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008,
-0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010,
-0x240a0001, 0xac820010, 0x8ca20014, 0x10000012,
-0x24a50020, 0x10400018, 0x31620100, 0x3c040001,
-0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000,
-0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e,
-0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010,
-0x8ce20014, 0x240a0001, 0xa01821, 0xac820014,
-0x276247e0, 0x43102b, 0x54400001, 0x27634000,
-0x602821, 0x31620100, 0x5440001d, 0x31621000,
-0x11a00009, 0x31a20800, 0x10400004, 0x25020020,
-0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124,
-0x8f880124, 0x6821, 0x11800011, 0x31621000,
-0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004,
-0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4,
-0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021,
-0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000,
-0x1440ff82, 0x0, 0x1120000f, 0x31220800,
-0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000,
-0x3c020002, 0x1221024, 0x10400004, 0x24e20020,
-0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104,
-0x8f870104, 0x4821, 0x1140ff70, 0x0,
-0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004,
-0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4,
-0x9482000e, 0xaf82009c, 0x8c820010, 0x5021,
-0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014,
-0x3e00008, 0x0, 0x6021, 0x5821,
-0x3021, 0x2821, 0x6821, 0x5021,
-0x7821, 0x7021, 0x8f880124, 0x8f870104,
-0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014,
-0x31220800, 0x8f820120, 0x10460029, 0x0,
-0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004,
-0xac820000, 0xac830004, 0x8cc20008, 0xac820008,
-0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001,
-0xac820010, 0x8cc20014, 0x10000012, 0x24c60020,
-0x10400017, 0x0, 0x3c040001, 0x8c846ee4,
-0x8d020000, 0x8d030004, 0xac820000, 0xac830004,
-0x8d020008, 0xac820008, 0x9502000e, 0xa482000e,
-0x8d020010, 0x25060020, 0xac820010, 0x8d020014,
-0x240c0001, 0xc01821, 0xac820014, 0x27624fe0,
-0x43102b, 0x54400001, 0x27634800, 0x603021,
-0x1560002f, 0x31220100, 0x11400014, 0x31228000,
-0x8f820100, 0x1045002a, 0x31220100, 0x3c040001,
-0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000,
-0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e,
-0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010,
-0x8ca20014, 0x10000012, 0x24a50020, 0x10400018,
-0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000,
-0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008,
-0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010,
-0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001,
-0xa01821, 0xac820014, 0x276247e0, 0x43102b,
-0x54400001, 0x27634000, 0x602821, 0x31220100,
-0x5440001d, 0x31221000, 0x11a00009, 0x31a20800,
-0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000,
-0x25020020, 0xaf820124, 0x8f880124, 0x6821,
-0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4,
-0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084,
-0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac,
-0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010,
-0x8c8f0014, 0x31221000, 0x14400022, 0x0,
-0x1140000f, 0x31420800, 0x10400004, 0x3c020002,
-0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024,
-0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4,
-0x24e20020, 0xaf820104, 0x8f870104, 0x5021,
-0x11600010, 0x0, 0x3c040001, 0x8c846ee0,
-0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
-0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c,
-0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010,
-0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024,
-0x1040ff5c, 0x0, 0x8f820054, 0x24420005,
-0xaf820078, 0x8c040234, 0x10800016, 0x1821,
-0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
-0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
-0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
-0x24020001, 0x3c030080, 0x3c010001, 0x370821,
-0xac2040e8, 0x3c010001, 0x370821, 0x1000000c,
-0xa02240f0, 0x3c020001, 0x571021, 0x904240f0,
-0x14400006, 0x3c020080, 0x3c020001, 0x571021,
-0x904240f1, 0x10400002, 0x3c020080, 0x621825,
-0x8c040230, 0x10800013, 0x0, 0x3c020001,
-0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
-0x370821, 0xac2240ec, 0x3c020001, 0x571021,
-0x8c4240ec, 0x44102b, 0x14400006, 0x0,
-0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
-0x781825, 0x3c020001, 0x571021, 0x904240f2,
-0x54400001, 0x781825, 0x1060ff1a, 0x0,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x431025, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x1000ff05,
-0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008,
-0x0, 0x0, 0x0, 0x3c020001,
-0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012,
-0xafb00010, 0x3c100001, 0x26106f90, 0x2002021,
-0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001,
-0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250,
-0x24022000, 0xac100254, 0xac020258, 0x24020001,
-0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010,
-0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec,
-0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
-0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
-0xad260010, 0xad270014, 0xad230018, 0xad28001c,
-0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90,
-0x122102b, 0x10400003, 0x0, 0x3c090001,
-0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000,
-0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec,
-0xad220004, 0xac090250, 0x3e00008, 0x0,
-0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec,
-0x3c020001, 0x8c426d10, 0xafb10014, 0x808821,
-0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
-0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
-0xae020000, 0x3c020001, 0x8c426d10, 0xc09821,
-0xe0a821, 0x10800006, 0xae020004, 0x26050008,
-0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0,
-0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0,
-0x3c030001, 0x24636f90, 0x203102b, 0x10400003,
-0x0, 0x3c100001, 0x8e106ee8, 0x8e220000,
-0xae020000, 0x8e220004, 0xae120008, 0xae020004,
-0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
-0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
-0x203102b, 0x10400003, 0x0, 0x3c100001,
-0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000,
-0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec,
-0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
-0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
-0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
-0x83102b, 0x10400006, 0x0, 0xac800000,
-0x24840004, 0x83102b, 0x5440fffd, 0xac800000,
-0x3e00008, 0x0, 0xa61821, 0xa3102b,
-0x10400007, 0x0, 0x8c820000, 0xaca20000,
-0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004,
-0x3e00008, 0x0, 0x861821, 0x83102b,
-0x10400007, 0x0, 0x8ca20000, 0xac820000,
-0x24840004, 0x83102b, 0x1440fffb, 0x24a50004,
-0x3e00008, 0x0, 0x63080, 0x861821,
-0x83102b, 0x10400006, 0x0, 0xac850000,
-0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
-0x3e00008, 0x0, 0x0, 0x26e50028,
-0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c,
-0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204,
-0x8f4c0200, 0x24640400, 0x64102b, 0x10400008,
-0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004,
-0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff,
-0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c,
-0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204,
-0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200,
-0x821024, 0x34420004, 0xc31824, 0x34630004,
-0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084,
-0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c,
-0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094,
-0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c,
-0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4,
-0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac,
-0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4,
-0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc,
-0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0,
-0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0,
-0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4,
-0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec,
-0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c,
-0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4,
-0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8,
-0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff,
-0x3463fffb, 0x431024, 0xaf820220, 0x30c20004,
-0x14400006, 0x0, 0x8f820200, 0x3c03c0ff,
-0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc,
-0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f430024, 0x8f420020, 0x10620038,
-0x0, 0x8f430020, 0x8f420024, 0x622023,
-0x4810003, 0x0, 0x8f420040, 0x822021,
-0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
-0x0, 0x8f430040, 0x8f420024, 0x10000005,
-0x621023, 0x8f420030, 0x8f430024, 0x431023,
-0x2442ffff, 0x406021, 0x8c102a, 0x54400001,
-0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024,
-0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c,
-0x24070001, 0xafa70010, 0x84100, 0x1001821,
-0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014,
-0x8f470014, 0x1021, 0x63100, 0xafa70018,
-0xa32821, 0xa3382b, 0x822021, 0x872021,
-0x8f420108, 0x1663021, 0x40f809, 0xc3900,
-0x54400001, 0xaf500024, 0x8f430024, 0x8f420020,
-0x14620018, 0x0, 0x8f420000, 0x10400007,
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
-0x0, 0x10000005, 0x0, 0xaf800048,
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
-0x2403ffef, 0x431024, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000002, 0xaf80004c,
-0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008,
-0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0,
-0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
-0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
-0x10000002, 0x0, 0x8f530020, 0x8f420030,
-0x105300eb, 0x21100, 0x8f43001c, 0x628021,
-0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
-0x9611000a, 0x3246ffff, 0x46102a, 0x10400017,
-0x0, 0x8f8200d8, 0x8f430098, 0x431023,
-0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf,
-0x10400005, 0x0, 0x8f420090, 0x8f430144,
-0x431021, 0xaf420090, 0x8f420090, 0x46102a,
-0x10400006, 0x0, 0x8f420348, 0x24420001,
-0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc,
-0x14400006, 0x0, 0x8f420344, 0x24420001,
-0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2,
-0x1040000b, 0x32c20008, 0x10400008, 0x32220200,
-0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
-0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac,
-0x32220004, 0x1040007f, 0x32220800, 0x10400003,
-0x3247ffff, 0x10000002, 0x24020020, 0x24020004,
-0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
-0x3c030002, 0x431025, 0xafa20018, 0x8f460098,
-0x8f420108, 0x40f809, 0x0, 0x104000b7,
-0x0, 0x8f42009c, 0x8f430094, 0x2421021,
-0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008,
-0x3c034000, 0x8f420094, 0x431025, 0xafa20020,
-0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025,
-0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024,
-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
-0x8f440270, 0x8f450274, 0x401821, 0x1021,
-0xa32821, 0xa3302b, 0x822021, 0x862021,
-0x32230060, 0x24020040, 0xaf440270, 0xaf450274,
-0x10620017, 0x2c620041, 0x10400005, 0x24020020,
-0x10620008, 0x24020001, 0x10000026, 0x0,
-0x24020060, 0x10620019, 0x24020001, 0x10000021,
-0x0, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x8f43027c, 0x10000016, 0x24020001,
-0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
-0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
-0x8f430284, 0x1000000b, 0x24020001, 0x8f420288,
-0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
-0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c,
-0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff,
-0x2406fff8, 0x8f45013c, 0x441021, 0x24420007,
-0x461024, 0x24840007, 0xaf420094, 0x8f420090,
-0x8f430094, 0x862024, 0x441023, 0x65182b,
-0x14600005, 0xaf420090, 0x8f420094, 0x8f430144,
-0x431023, 0xaf420094, 0x8f420094, 0x10000023,
-0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020,
-0x14400002, 0x24020010, 0x24020002, 0xafa20010,
-0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018,
-0x8f460098, 0x8f420108, 0x40f809, 0x0,
-0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090,
-0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c,
-0x8f440098, 0xa34005c2, 0x651823, 0xaf430090,
-0x451021, 0x86202b, 0x14800005, 0xaf42009c,
-0x8f420098, 0x8f430144, 0x431023, 0xaf420098,
-0x32c20020, 0x10400005, 0x0, 0x8f420358,
-0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030,
-0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
-0xaf420030, 0x8f420030, 0x14530018, 0x0,
-0x8f420000, 0x10400007, 0x0, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x2403fff7, 0x431024,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038,
-0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
-0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
-0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
-0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
-0x10000002, 0x0, 0x8f520020, 0x8f420030,
-0x105200b5, 0x21100, 0x8f43001c, 0x628021,
-0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
-0x9607000a, 0x3226ffff, 0x46102a, 0x10400017,
-0x0, 0x8f8200d8, 0x8f430098, 0x431023,
-0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47,
-0x10400005, 0x0, 0x8f420090, 0x8f430144,
-0x431021, 0xaf420090, 0x8f420090, 0x46102a,
-0x10400006, 0x0, 0x8f420348, 0x24420001,
-0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc,
-0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8,
-0x431024, 0x461023, 0x218c3, 0x58600001,
-0x24630100, 0x8f42008c, 0x43102b, 0x14400006,
-0x712c2, 0x8f420344, 0x24420001, 0xaf420344,
-0x10000098, 0x8f420344, 0x934305c2, 0x1060000f,
-0x30460001, 0x8f420010, 0x34480400, 0x32c20008,
-0x10400008, 0x30e20200, 0x10400006, 0x3c034000,
-0x9602000e, 0xaf4300ac, 0x21400, 0x10000004,
-0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010,
-0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac,
-0x11200005, 0x30c200ff, 0x14400006, 0x24020040,
-0x10000004, 0x24020008, 0x14400002, 0x24020020,
-0x24020004, 0xafa20010, 0x8f430030, 0x11200004,
-0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014,
-0x3c020002, 0x1021025, 0xafa20018, 0x8f460098,
-0x8f420108, 0x40f809, 0x0, 0x10400069,
-0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001,
-0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2,
-0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021,
-0x24420007, 0x461024, 0x24840007, 0xaf420094,
-0x8f420090, 0x8f430094, 0x862024, 0x441023,
-0x65182b, 0x14600005, 0xaf420090, 0x8f420094,
-0x8f430144, 0x431023, 0xaf420094, 0x8f430094,
-0x8f420140, 0x43102b, 0x10400009, 0x0,
-0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138,
-0x641823, 0x431023, 0xaf420090, 0xaf450094,
-0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d,
-0x30c200ff, 0x14400002, 0x24020010, 0x24020002,
-0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014,
-0x8f460098, 0x8f420108, 0x40f809, 0x0,
-0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c,
-0x451021, 0xaf420098, 0x8f420090, 0x8f430098,
-0xa34005c2, 0x451023, 0x64182b, 0x14600005,
-0xaf420090, 0x8f420098, 0x8f430144, 0x431023,
-0xaf420098, 0x8f420030, 0x8f430040, 0x24420001,
-0x2463ffff, 0x431024, 0xaf420030, 0x8f420030,
-0x14520018, 0x0, 0x8f420000, 0x10400007,
-0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
-0x0, 0x10000005, 0x0, 0xaf800048,
-0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
-0x2403fff7, 0x431024, 0xaf820060, 0x8f420000,
-0x10400003, 0x0, 0x10000002, 0xaf80004c,
-0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024,
-0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
-0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0,
-0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021,
-0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
-0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
-0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001,
-0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0,
-0x34422ec0, 0x2e21021, 0x54620004, 0x24620008,
-0x3c020001, 0x34422cc0, 0x2e21021, 0x401821,
-0x8c620004, 0x21140, 0x821021, 0xaf820108,
-0xac600000, 0x8c850018, 0x30a20036, 0x1040006c,
-0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034,
-0x24420001, 0x2463ffff, 0x431024, 0x862021,
-0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034,
-0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4,
-0x0, 0x32c20010, 0x10400028, 0x24070008,
-0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
-0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100,
-0x10000036, 0x0, 0x8f420300, 0x8f43002c,
-0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
-0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170,
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020020, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
-0x24020001, 0x3c010001, 0x370821, 0xa02240f0,
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
-0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120,
-0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f,
-0x0, 0x8f420300, 0x24420001, 0xaf420300,
-0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038,
-0x3c010001, 0x370821, 0xa02040f1, 0x3c010001,
-0x370821, 0xa02040f0, 0xaf400034, 0x8f420314,
-0x24420001, 0xaf420314, 0x10000059, 0x8f420314,
-0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028,
-0xa22023, 0x4810003, 0x0, 0x8f420040,
-0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
-0x441021, 0x10600007, 0xaf420358, 0xaf80004c,
-0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
-0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
-0x0, 0x8f820060, 0x34420008, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000038,
-0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f,
-0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c,
-0x8f420050, 0x622023, 0x4820001, 0x24840200,
-0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368,
-0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000,
-0x8c83001c, 0x8f420070, 0x622023, 0x4820001,
-0x24840400, 0x8f420364, 0x441021, 0xaf420364,
-0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e,
-0x3c020800, 0x8c83001c, 0x8f420060, 0x622023,
-0x4820001, 0x24840100, 0x8f420360, 0x441021,
-0xaf420360, 0x8f420368, 0xaf430060, 0x441021,
-0xaf420368, 0x3c020800, 0x2c21024, 0x50400008,
-0x36940040, 0x10000006, 0x0, 0x30a20100,
-0x10400003, 0x0, 0xc002bd8, 0x0,
-0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
-0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c,
-0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c,
-0xafb00038, 0x8f910108, 0x26220020, 0xaf820108,
-0x8e320018, 0xa821, 0x32420024, 0x104001ba,
-0xf021, 0x8e26001c, 0x8f43001c, 0x61100,
-0x621821, 0x8c70000c, 0x9604000c, 0x962d0016,
-0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001,
-0x621825, 0x10600015, 0x2821, 0x32c20040,
-0x10400015, 0x24020800, 0x96030014, 0x14620012,
-0x3402aaaa, 0x9603000e, 0x14620007, 0x2021,
-0x96030010, 0x24020300, 0x14620004, 0x801021,
-0x96020012, 0x2c440001, 0x801021, 0x54400006,
-0x24050016, 0x10000004, 0x0, 0x24020800,
-0x50820001, 0x2405000e, 0x934205c3, 0x14400008,
-0x5821, 0x240b0001, 0x32620180, 0xaf4500a8,
-0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3,
-0x10a00085, 0x2054021, 0x91020000, 0x3821,
-0x3042000f, 0x25080, 0x32c20002, 0x10400012,
-0x10a1821, 0x32620002, 0x10400010, 0x32c20001,
-0x1002021, 0x94820000, 0x24840002, 0xe23821,
-0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02,
-0x623821, 0x71c02, 0x30e2ffff, 0x623821,
-0x71027, 0xa502000a, 0x32c20001, 0x1040006a,
-0x32620001, 0x10400068, 0x0, 0x8f4200a8,
-0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8,
-0x431021, 0x904c0009, 0x318900ff, 0x39230006,
-0x3182b, 0x39220011, 0x2102b, 0x621824,
-0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001,
-0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600,
-0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e,
-0x0, 0x32c20004, 0x14400013, 0x2821,
-0x316200ff, 0x14400004, 0x0, 0x95020002,
-0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e,
-0x95030010, 0xa22821, 0xa32821, 0x95030012,
-0x91040009, 0x95020002, 0xa32821, 0xa42821,
-0x4a1023, 0xa22821, 0x2002021, 0x94820000,
-0x24840002, 0xe23821, 0x88102b, 0x1440fffb,
-0x71c02, 0x30e2ffff, 0x623821, 0x71c02,
-0x30e2ffff, 0x623821, 0x1a52821, 0x51c02,
-0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
-0x622821, 0xa72823, 0x51402, 0xa22821,
-0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff,
-0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8,
-0x624021, 0x91020000, 0x3042000f, 0x25080,
-0x318300ff, 0x24020006, 0x14620003, 0x10a1021,
-0x10000002, 0x24440010, 0x24440006, 0x316200ff,
-0x14400006, 0x0, 0x94820000, 0xa22821,
-0x51c02, 0x30a2ffff, 0x622821, 0x934205c3,
-0x10400003, 0x32620100, 0x50400003, 0xa4850000,
-0x52827, 0xa4850000, 0x9622000e, 0x8f43009c,
-0x621821, 0x32a200ff, 0x10400007, 0xaf43009c,
-0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c,
-0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c,
-0xafa20024, 0x32620080, 0x10400010, 0x32620100,
-0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
-0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
-0x220821, 0xac2338e8, 0x3c010001, 0x220821,
-0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064,
-0x0, 0x8f4200b4, 0x24430001, 0x210c0,
-0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024,
-0x3c010001, 0x220821, 0xac2338e8, 0x3c010001,
-0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051,
-0x3821, 0x3c090001, 0x352938e8, 0x3c08001f,
-0x3508ffff, 0x240bffff, 0x340affff, 0x710c0,
-0x571021, 0x491021, 0x8c430000, 0x8c440004,
-0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028,
-0x8fa4002c, 0xac430000, 0xac440004, 0x24420008,
-0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c,
-0x97a2002e, 0x8f440270, 0x8f450274, 0x401821,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaf440270, 0xaf450274, 0x8fa20028,
-0x481024, 0x90430000, 0x30630001, 0x1460000b,
-0x402021, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000,
-0x144b000e, 0x0, 0x94820004, 0x144a000b,
-0x0, 0x8f420288, 0x8f43028c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420288, 0xaf43028c,
-0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280,
-0x8f430284, 0x24630001, 0x2c640001, 0x441021,
-0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
-0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8,
-0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4,
-0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
-0x8f46008c, 0x8f440270, 0x8f450274, 0x401821,
-0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaf440270,
-0xaf450274, 0x92020000, 0x30420001, 0x1440000c,
-0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001,
-0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
-0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020,
-0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004,
-0x1462000c, 0x0, 0x8f420288, 0x8f43028c,
-0x24630001, 0x2c640001, 0x441021, 0xaf420288,
-0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b,
-0x32c20020, 0x8f420280, 0x8f430284, 0x24630001,
-0x2c640001, 0x441021, 0xaf420280, 0xaf430284,
-0x8f420280, 0x8f430284, 0x32c20020, 0x10400005,
-0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358,
-0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001,
-0x2463ffff, 0x431024, 0xaf42002c, 0x32420060,
-0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
-0xaf420034, 0x8c03023c, 0x43102b, 0x14400102,
-0x32c20010, 0x10400018, 0x24070008, 0x8f440170,
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047,
-0x24020001, 0x8f420300, 0x8f43002c, 0x24420001,
-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
-0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174,
-0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x10400057, 0x24020001,
-0x10000065, 0x0, 0x32420012, 0x10400075,
-0x32420001, 0x9622000e, 0x8f43009c, 0x621821,
-0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358,
-0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c,
-0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
-0xaf42002c, 0x32420010, 0x14400008, 0x32c20010,
-0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
-0x43102b, 0x144000bc, 0x32c20010, 0x10400028,
-0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
-0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
-0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
-0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
-0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
-0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014,
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
-0x34a51100, 0x10000036, 0x0, 0x8f420300,
-0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
-0x24020001, 0xa34205c1, 0x10000026, 0xaf430038,
-0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
-0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
-0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
-0x14400011, 0x24020001, 0x3c010001, 0x370821,
-0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
-0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c,
-0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900,
-0x1000000f, 0x0, 0x8f420300, 0x24420001,
-0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1,
-0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
-0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
-0x8f420314, 0x24420001, 0xaf420314, 0x10000062,
-0x8f420314, 0x10400022, 0x32427000, 0x8e25001c,
-0x8f420028, 0xa22023, 0x4810003, 0x0,
-0x8f420040, 0x822021, 0x8f420358, 0x8f430000,
-0xaf450028, 0x441021, 0x10600007, 0xaf420358,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x34420008,
-0xaf820060, 0x8f420000, 0x10400003, 0x0,
-0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048,
-0x1040002f, 0x32421000, 0x1040000c, 0x32424000,
-0x8e23001c, 0x8f420050, 0x622023, 0x4820001,
-0x24840200, 0x8f42035c, 0x441021, 0xaf42035c,
-0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c,
-0x32c28000, 0x8e23001c, 0x8f420070, 0x622023,
-0x4820001, 0x24840400, 0x8f420364, 0x441021,
-0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070,
-0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060,
-0x622023, 0x4820001, 0x24840100, 0x8f420360,
-0x441021, 0xaf420360, 0x8f420368, 0xaf430060,
-0x441021, 0xaf420368, 0x3c020800, 0x2c21024,
-0x50400011, 0x36940040, 0x1000000f, 0x0,
-0x32420048, 0x10400007, 0x24150001, 0x8e22001c,
-0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75,
-0xae22001c, 0x32420100, 0x10400003, 0x0,
-0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c,
-0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c,
-0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008,
-0x0, 0x0, 0x0, 0x8f8300e4,
-0x8f8200e0, 0x2404fff8, 0x441024, 0x621026,
-0x2102b, 0x21023, 0x3e00008, 0x621024,
-0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
-0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4,
-0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8,
-0x14a20002, 0x24a20008, 0x27623000, 0x408021,
-0x16030005, 0x30820004, 0x10400004, 0xc02021,
-0x10000022, 0x1021, 0x8e040000, 0x8f42011c,
-0x14a20003, 0x0, 0x8f420120, 0xaf420114,
-0x8ca30000, 0x8f420148, 0x831823, 0x43102b,
-0x10400003, 0x0, 0x8f420148, 0x621821,
-0x94a20006, 0x24420050, 0x62102b, 0x1440000f,
-0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000,
-0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894,
-0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
-0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c,
-0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
-0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8,
-0x2402fff8, 0x823824, 0xe32023, 0x2c821000,
-0x50400001, 0x24841000, 0x420c2, 0x801821,
-0x8f440258, 0x8f45025c, 0x1021, 0xa32821,
-0xa3302b, 0x822021, 0x862021, 0xaf440258,
-0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023,
-0x82102b, 0x14400004, 0x801821, 0x8f420148,
-0x822021, 0x801821, 0x8f440250, 0x8f450254,
-0x1021, 0xa32821, 0xa3302b, 0x822021,
-0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8,
-0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0,
-0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4,
-0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
-0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c,
-0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086,
-0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c,
-0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129,
-0xafaa007c, 0x8f420114, 0x40f809, 0x0,
-0x403021, 0x10c0034f, 0x0, 0x8cc20000,
-0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024,
-0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c,
-0x3c020006, 0x2c21024, 0xafab007c, 0x14400015,
-0xafaa0064, 0x91420000, 0x30420001, 0x10400011,
-0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff,
-0x95430004, 0x1062000b, 0x0, 0xc0024bb,
-0x8fa40064, 0x304200ff, 0x14400006, 0x0,
-0x8f420118, 0x40f809, 0x0, 0x1000032d,
-0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
-0x431024, 0x3c03ffff, 0x431824, 0x14600003,
-0xafa20024, 0x10000040, 0x1821, 0x3c020080,
-0x621024, 0x10400007, 0x0, 0x8f42038c,
-0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
-0x24030001, 0x8f420210, 0x24420001, 0xaf420210,
-0x8f420210, 0x3c020001, 0x621024, 0x10400006,
-0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
-0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
-0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
-0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
-0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
-0x8f420380, 0x3c020008, 0x621024, 0x10400006,
-0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
-0x8f420384, 0x3c020010, 0x621024, 0x10400006,
-0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
-0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
-0x24030001, 0x8f420388, 0x24420001, 0xaf420388,
-0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c,
-0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8,
-0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c,
-0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010,
-0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
-0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
-0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080,
-0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c,
-0x3c020080, 0x34420100, 0x1621024, 0x10400005,
-0x0, 0x8f42020c, 0x24420001, 0xaf42020c,
-0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400,
-0x10400015, 0x34028100, 0x8faa0064, 0x9543000c,
-0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e,
-0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
-0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c,
-0xa7a20086, 0xad63000c, 0xad640008, 0xad650004,
-0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024,
-0x10400004, 0x0, 0x8faa006c, 0x254a0004,
-0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074,
-0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074,
-0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc,
-0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b,
-0x10400056, 0x32c28000, 0x1040005e, 0x240a0003,
-0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058,
-0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024,
-0x24420001, 0xaf420350, 0x1000024f, 0x8f420350,
-0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
-0x3c040001, 0x248468d0, 0x26620001, 0xafa20014,
-0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
-0xc002b3b, 0x34a52250, 0x1000023f, 0x0,
-0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
-0x3c040001, 0x248468d0, 0x24020002, 0xafa20014,
-0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
-0xc002b3b, 0x34a52450, 0x1000022f, 0x0,
-0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8,
-0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800,
-0xc002b3b, 0x603021, 0x10000223, 0x0,
-0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0,
-0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120,
-0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216,
-0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124,
-0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010,
-0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b,
-0x34a53200, 0x10000208, 0x0, 0x8f420084,
-0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001,
-0x2c21024, 0x10400004, 0x0, 0x240b0002,
-0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020,
-0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c,
-0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002,
-0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054,
-0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001,
-0x304201ff, 0xafa20054, 0x1e1140, 0x431021,
-0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c,
-0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010,
-0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b,
-0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024,
-0x24630001, 0xaf430350, 0x100001d3, 0x8f420350,
-0x156a001d, 0x0, 0x8f430074, 0x8f420070,
-0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c,
-0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140,
-0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044,
-0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007,
-0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070,
-0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c,
-0x1000ffc3, 0x0, 0x8f430064, 0x8f420060,
-0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c,
-0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054,
-0x24020004, 0x1562000e, 0x1e1140, 0x1e1180,
-0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a,
-0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024,
-0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097,
-0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044,
-0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014,
-0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007,
-0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024,
-0x1440ff34, 0x0, 0x8f420370, 0x240a0001,
-0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90,
-0x8f420370, 0x27a30036, 0x131040, 0x621821,
-0x94620000, 0x441021, 0x10000020, 0xa4620000,
-0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072,
-0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4,
-0x25420020, 0xafa20028, 0x25420008, 0xafa20030,
-0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a,
-0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a,
-0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018,
-0x24630002, 0x822023, 0x1880ffde, 0x26730001,
-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
-0x26650001, 0xa2102a, 0x1440002b, 0x24030001,
-0x8f83012c, 0x10600023, 0x0, 0x8f820124,
-0x431023, 0x22143, 0x58800001, 0x24840040,
-0x8f820128, 0x431023, 0x21943, 0x58600001,
-0x24630040, 0x64102a, 0x54400001, 0x602021,
-0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011,
-0x24030001, 0x10000015, 0x306200ff, 0x8fab0064,
-0x96070018, 0xafab0010, 0x8e220008, 0x3c040001,
-0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400,
-0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b,
-0x0, 0x8f420334, 0x1821, 0x24420001,
-0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc,
-0x3c020800, 0x12600021, 0x9021, 0x8fb100a4,
-0x2208021, 0x8e220008, 0x96070018, 0x8fa60064,
-0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010,
-0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
-0x40f809, 0x0, 0x1040ffd8, 0x3c050007,
-0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821,
-0x14b102b, 0x10400004, 0xafab0064, 0x8f420148,
-0x1625823, 0xafab0064, 0x26100002, 0x26520001,
-0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c,
-0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002,
-0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
-0x10600013, 0x0, 0x8f820124, 0x431023,
-0x22143, 0x58800001, 0x24840040, 0x8f820128,
-0x431023, 0x21943, 0x58600001, 0x24630040,
-0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
-0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
-0x8f420334, 0x1821, 0x24420001, 0xaf420334,
-0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800,
-0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b,
-0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
-0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008,
-0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809,
-0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e,
-0x97aa008e, 0x11400007, 0x609021, 0x934205c4,
-0x14400004, 0x0, 0x97ab0086, 0x6a1825,
-0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024,
-0x10400003, 0xa1402, 0x34630400, 0xa6a20014,
-0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004,
-0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a,
-0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000,
-0xafa20010, 0x8f420044, 0x2a03021, 0x24070020,
-0xafa20014, 0x8f42000c, 0x31940, 0x604821,
-0xafa20018, 0x8f42010c, 0x4021, 0xa92821,
-0xa9182b, 0x882021, 0x40f809, 0x832021,
-0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c,
-0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c,
-0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002,
-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
-0x8f42035c, 0x156a0006, 0x0, 0x8f420364,
-0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364,
-0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360,
-0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044,
-0x8f440088, 0x8f430078, 0x24420001, 0x441024,
-0x24630001, 0xaf420044, 0xaf430078, 0x8c020240,
-0x62182b, 0x14600075, 0x24070008, 0x8f440168,
-0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120,
-0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
-0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2,
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
-0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120,
-0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b,
-0x0, 0x8f420304, 0x24420001, 0xaf420304,
-0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
-0x370821, 0xa02040f2, 0xaf400078, 0x8f420318,
-0x24420001, 0xaf420318, 0x10000048, 0x8f420318,
-0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
-0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
-0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
-0x604821, 0xafa20018, 0x8f42010c, 0x4021,
-0xa92821, 0xa9182b, 0x882021, 0x40f809,
-0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4,
-0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c,
-0x8fab009c, 0x1505021, 0x16a102b, 0x10400004,
-0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064,
-0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c,
-0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002,
-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
-0x8f42035c, 0x114b0006, 0x0, 0x8f420360,
-0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360,
-0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364,
-0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044,
-0x8f440088, 0x8f430078, 0x24420001, 0x441024,
-0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c,
-0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e,
-0x0, 0x934205c4, 0x10400009, 0x0,
-0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c,
-0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc,
-0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020,
-0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004,
-0x8c450008, 0xa44a000e, 0xac440000, 0xac450004,
-0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c,
-0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff,
-0x2484fffc, 0x801821, 0x8f440250, 0x8f450254,
-0x8f460118, 0x1021, 0xa32821, 0xa3382b,
-0x822021, 0x872021, 0xaf440250, 0xc0f809,
-0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
-0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
-0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
-0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc,
-0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac,
-0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c,
-0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e,
-0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4,
-0x10000130, 0xafab006c, 0x8f420114, 0x40f809,
-0x0, 0x403021, 0x10c002a1, 0x0,
-0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024,
-0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc,
-0xafa20064, 0x3c020006, 0x2c21024, 0x14400015,
-0xafac006c, 0x93c20000, 0x30420001, 0x10400011,
-0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff,
-0x97c30004, 0x1062000b, 0x0, 0xc0024bb,
-0x3c02021, 0x304200ff, 0x14400006, 0x0,
-0x8f420118, 0x40f809, 0x0, 0x10000280,
-0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
-0x431024, 0x3c03ffff, 0x431824, 0x14600003,
-0xafa20024, 0x10000040, 0x8021, 0x3c020080,
-0x621024, 0x10400007, 0x0, 0x8f42038c,
-0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
-0x24100001, 0x8f420210, 0x24420001, 0xaf420210,
-0x8f420210, 0x3c020001, 0x621024, 0x10400006,
-0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
-0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
-0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
-0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
-0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
-0x8f420380, 0x3c020008, 0x621024, 0x10400006,
-0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
-0x8f420384, 0x3c020010, 0x621024, 0x10400006,
-0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
-0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
-0x24100001, 0x8f420388, 0x24420001, 0xaf420388,
-0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064,
-0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8,
-0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c,
-0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010,
-0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
-0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
-0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010,
-0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400,
-0x8fab006c, 0x3c020080, 0x34420100, 0x1621024,
-0x10400005, 0x0, 0x8f42020c, 0x24420001,
-0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064,
-0x32c20400, 0x10400012, 0x34028100, 0x97c3000c,
-0x1462000f, 0x0, 0x240c0200, 0xa7ac0076,
-0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064,
-0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e,
-0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004,
-0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100,
-0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001,
-0x621825, 0x10600015, 0x2821, 0x32c20800,
-0x10400015, 0x24020800, 0x97c30014, 0x14620012,
-0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021,
-0x97c30010, 0x24020300, 0x14620004, 0x801021,
-0x97c20012, 0x2c440001, 0x801021, 0x54400006,
-0x24050016, 0x10000004, 0x0, 0x24020800,
-0x50820001, 0x2405000e, 0x10a00013, 0x3c52021,
-0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b,
-0x10400003, 0x0, 0x8f420148, 0x621823,
-0x90620000, 0x38430006, 0x2c630001, 0x38420011,
-0x2c420001, 0x621825, 0x10600004, 0x3c020100,
-0x94820002, 0x453821, 0x3c020100, 0x2c21024,
-0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008,
-0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064,
-0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014,
-0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080,
-0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000,
-0x10400034, 0x240b0003, 0x32c21000, 0x10400031,
-0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350,
-0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350,
-0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025,
-0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001,
-0x248468d0, 0x26620001, 0xafa20014, 0xafa30010,
-0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b,
-0x34a55300, 0x10000162, 0x0, 0x8ea20000,
-0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010,
-0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b,
-0x603021, 0x10000156, 0x0, 0x8f420084,
-0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001,
-0x2c21024, 0x10400004, 0x0, 0x240c0002,
-0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020,
-0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021,
-0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b,
-0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c,
-0x26220001, 0x304201ff, 0xafa20054, 0x111140,
-0x431021, 0x1000006b, 0x2e2a821, 0x8f420044,
-0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014,
-0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
-0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf,
-0x282a024, 0x24630001, 0xaf430350, 0x10000124,
-0x8f420350, 0x156c001d, 0x0, 0x8f430074,
-0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074,
-0xafab004c, 0x26220001, 0x304203ff, 0xafa20054,
-0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821,
-0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8,
-0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074,
-0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b,
-0xafab005c, 0x1000ffc3, 0x0, 0x8f430064,
-0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064,
-0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff,
-0xafa20054, 0x24020004, 0x1562000e, 0x111140,
-0x111180, 0x24420cc0, 0x2e21021, 0xafa20044,
-0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b,
-0x10400024, 0x25950020, 0x240c0001, 0x10000021,
-0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821,
-0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4,
-0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060,
-0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008,
-0x2c21024, 0x1440ff61, 0x0, 0x8f420370,
-0x240c0001, 0xafac005c, 0x24420001, 0xaf420370,
-0x1000ff90, 0x8f420370, 0x27a30036, 0x131040,
-0x621821, 0x94620000, 0x441021, 0x1000001f,
-0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084,
-0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c,
-0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
-0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
-0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
-0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
-0x24630002, 0x822023, 0x1880ffdf, 0x26730001,
-0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
-0x262102a, 0x14400030, 0x24030001, 0x8f83012c,
-0x10600028, 0x0, 0x8f820124, 0x431023,
-0x22143, 0x58800001, 0x24840040, 0x8f820128,
-0x431023, 0x21943, 0x58600001, 0x24630040,
-0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
-0x8f4200fc, 0x262102a, 0x10400016, 0x24030001,
-0x1000001a, 0x306200ff, 0x8fac008c, 0x101040,
-0x4c1021, 0x94470018, 0x101080, 0x4c1021,
-0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc,
-0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500,
-0x2003021, 0xc002b3b, 0xafa30014, 0x10000039,
-0x0, 0x8f420334, 0x1821, 0x24420001,
-0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06,
-0x8021, 0x8f430008, 0x2402fbff, 0x1260002d,
-0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c,
-0x2669ffff, 0x2209021, 0x8e420008, 0x96270018,
-0x8c440000, 0x8c450004, 0x56090004, 0x240b0001,
-0x240c0002, 0x10000002, 0xafac0010, 0xafab0010,
-0x16000004, 0xafa80014, 0x8f420008, 0x10000002,
-0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021,
-0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0,
-0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2,
-0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021,
-0x5e102b, 0x10400003, 0x26310002, 0x8f420148,
-0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda,
-0x26520004, 0x8fb00064, 0x1000001a, 0x0,
-0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001,
-0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c,
-0x240c0002, 0xafac0010, 0x934305c4, 0xb1700,
-0x10600003, 0x2223025, 0x3c020800, 0xc23025,
-0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c,
-0x3c03021, 0x40f809, 0x2003821, 0x1040fecb,
-0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e,
-0x934205c4, 0x14400004, 0x0, 0x97ab007e,
-0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff,
-0x1821024, 0x10400003, 0xc1402, 0x34630400,
-0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006,
-0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e,
-0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f,
-0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064,
-0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4,
-0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c,
-0xad8b0000, 0x8fac0064, 0x1580feba, 0x0,
-0x8fab0064, 0x1160001b, 0x0, 0x934205c4,
-0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0,
-0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076,
-0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c,
-0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008,
-0xa44c000e, 0xac440000, 0xac450004, 0xac460008,
-0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010,
-0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc,
-0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
-0x1021, 0xa32821, 0xa3382b, 0x822021,
-0x872021, 0xaf440250, 0xc0f809, 0xaf450254,
-0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4,
-0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008,
-0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8,
-0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048,
-0x10620034, 0x0, 0x8f430048, 0x8f42004c,
-0x622023, 0x4820001, 0x24840200, 0x8f430054,
-0x8f42004c, 0x43102b, 0x14400004, 0x24020200,
-0x8f43004c, 0x10000005, 0x431023, 0x8f420054,
-0x8f43004c, 0x431023, 0x2442ffff, 0x405021,
-0x8a102a, 0x54400001, 0x805021, 0x8f49004c,
-0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
-0x24071000, 0xafa70010, 0x84140, 0x1001821,
-0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014,
-0x1021, 0x63140, 0xafa70018, 0xa32821,
-0xa3382b, 0x822021, 0x872021, 0x3402ecc0,
-0xc23021, 0x8f420108, 0x2e63021, 0x40f809,
-0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c,
-0x8f420048, 0x14620018, 0x0, 0x8f420000,
-0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
-0x1040fffd, 0x0, 0x10000005, 0x0,
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
-0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
-0x8f420000, 0x10400003, 0x0, 0x10000002,
-0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
-0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
-0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c,
-0x8f420058, 0x10620049, 0x0, 0x8f430058,
-0x8f42005c, 0x622023, 0x4820001, 0x24840100,
-0x8f430064, 0x8f42005c, 0x43102b, 0x14400004,
-0x24020100, 0x8f43005c, 0x10000005, 0x431023,
-0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff,
-0x403821, 0x87102a, 0x54400001, 0x803821,
-0x8f42005c, 0x471021, 0x305000ff, 0x32c21000,
-0x10400015, 0x24082000, 0x8f49005c, 0x8f440190,
-0x8f450194, 0x8f46005c, 0x73980, 0xafa80010,
-0xafb00014, 0x8f480014, 0x94980, 0x1201821,
-0x1021, 0xa32821, 0xa3482b, 0x822021,
-0x892021, 0x63180, 0xafa80018, 0x8f420108,
-0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190,
-0x8f450194, 0x8f46005c, 0x73940, 0xafa80010,
-0xafb00014, 0x8f480014, 0x94940, 0x1201821,
-0x1021, 0xa32821, 0xa3482b, 0x822021,
-0x892021, 0x63140, 0xafa80018, 0x8f420108,
-0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001,
-0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018,
-0x0, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x2403feff,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
-0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033,
-0x0, 0x8f430068, 0x8f42006c, 0x622023,
-0x4820001, 0x24840400, 0x8f430074, 0x8f42006c,
-0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
-0x10000005, 0x431023, 0x8f420074, 0x8f43006c,
-0x431023, 0x2442ffff, 0x405021, 0x8a102a,
-0x54400001, 0x805021, 0x8f49006c, 0x8f48006c,
-0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000,
-0xafa70010, 0x84140, 0x1001821, 0x12a4821,
-0x313003ff, 0xafb00014, 0x8f470014, 0x1021,
-0x63140, 0x24c66cc0, 0xafa70018, 0xa32821,
-0xa3382b, 0x822021, 0x872021, 0x8f420108,
-0x2e63021, 0x40f809, 0xa3940, 0x54400001,
-0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018,
-0x0, 0x8f420000, 0x10400007, 0x0,
-0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
-0x10000005, 0x0, 0xaf800048, 0x8f820048,
-0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff,
-0x431024, 0xaf820060, 0x8f420000, 0x10400003,
-0x0, 0x10000002, 0xaf80004c, 0xaf800048,
-0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x8f4200fc, 0x3c030001,
-0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc,
-0x8f850128, 0x2e31021, 0x54820004, 0x24820008,
-0x3c020001, 0x34422ec8, 0x2e21021, 0x401821,
-0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004,
-0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128,
-0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
-0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
-0x401821, 0x8c620004, 0x21140, 0xa21021,
-0xaf820128, 0xac600000, 0x8ca30018, 0x30620070,
-0x1040002d, 0x30620020, 0x10400004, 0x3c020010,
-0x2c21024, 0x1040000d, 0x0, 0x30620040,
-0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
-0x0, 0x30620010, 0x1040001f, 0x3c020040,
-0x2c21024, 0x1440001c, 0x0, 0x8f820040,
-0x30420001, 0x14400008, 0x2021, 0x8c030104,
-0x24020001, 0x50620005, 0x24040001, 0x8c020264,
-0x10400003, 0x801021, 0x24040001, 0x801021,
-0x10400006, 0x0, 0x8f42030c, 0x24420001,
-0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044,
-0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
-0xaf420308, 0x8f420308, 0x3e00008, 0x0,
-0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
-0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
-0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001,
-0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128,
-0x8d030018, 0x30620070, 0x1040002e, 0x30620020,
-0x10400004, 0x3c020010, 0x2c21024, 0x1040000d,
-0x0, 0x30620040, 0x10400004, 0x3c020020,
-0x2c21024, 0x10400007, 0x0, 0x30620010,
-0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6,
-0x0, 0x8f820040, 0x30420001, 0x14400008,
-0x2021, 0x8c030104, 0x24020001, 0x50620005,
-0x24040001, 0x8c020264, 0x10400003, 0x801021,
-0x24040001, 0x801021, 0x10400006, 0x0,
-0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192,
-0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
-0x8f420308, 0x24420001, 0xaf420308, 0x1000018a,
-0x8f420308, 0x30620002, 0x1040014b, 0x3c020800,
-0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016,
-0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001,
-0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0,
-0x431021, 0x10000010, 0x2e2a821, 0x24020002,
-0x15420005, 0x24020003, 0x1e1140, 0x24426cc0,
-0x10000009, 0x2e2a821, 0x15420005, 0x1e1180,
-0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821,
-0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc,
-0x30420400, 0x10400003, 0xafaa002c, 0x100000e1,
-0x8821, 0x10800004, 0x8821, 0x97b10026,
-0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c,
-0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870,
-0x2c420001, 0x621825, 0x10600015, 0x2021,
-0x32c20800, 0x10400015, 0x24020800, 0x96630014,
-0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007,
-0x2821, 0x96630010, 0x24020300, 0x14620004,
-0xa01021, 0x96620012, 0x2c450001, 0xa01021,
-0x54400006, 0x24040016, 0x10000004, 0x0,
-0x24020800, 0x50a20001, 0x2404000e, 0x108000b9,
-0x2649021, 0x92420000, 0x3042000f, 0x28080,
-0x32c20100, 0x10400020, 0x2501821, 0x3c020020,
-0x43102b, 0x1440000e, 0x2402021, 0x2821,
-0x94820000, 0x24840002, 0xa22821, 0x83102b,
-0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821,
-0x51c02, 0x30a2ffff, 0x10000009, 0x622821,
-0x8f470148, 0x8f420110, 0x102842, 0x3c060020,
-0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040,
-0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002,
-0x10000002, 0xafaa002c, 0x2821, 0x32c20080,
-0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f,
-0x3442ffff, 0x43102b, 0x10400003, 0x0,
-0x8f420148, 0x621823, 0x90660000, 0x30c200ff,
-0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
-0x621825, 0x1060007f, 0x24020800, 0x8821,
-0x97a3003e, 0x1462000f, 0x2602021, 0x96710000,
-0x96620002, 0x96630004, 0x96640006, 0x2228821,
-0x2238821, 0x2248821, 0x96620008, 0x9663000a,
-0x9664000c, 0x2228821, 0x2238821, 0x10000007,
-0x2248821, 0x94820000, 0x24840002, 0x2228821,
-0x92102b, 0x1440fffb, 0x0, 0x111c02,
-0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
-0x628821, 0x32c20200, 0x10400003, 0x26440006,
-0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x30421fff, 0x10400004,
-0x2644000c, 0x96420002, 0x10000030, 0x508023,
-0x96420002, 0x26430014, 0x508023, 0x3c020020,
-0x43102b, 0x1440000a, 0xd08021, 0x9642000c,
-0x2028021, 0x9642000e, 0x96430010, 0x96440012,
-0x2028021, 0x2038021, 0x10000020, 0x2048021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x24840002, 0x2028021,
-0xa4102b, 0x10400003, 0x0, 0x8f420148,
-0x822023, 0x94820000, 0x2028021, 0x3c020100,
-0x2c21024, 0x1040000e, 0x0, 0x8faa002c,
-0x31420004, 0x1040000a, 0x0, 0x9504000e,
-0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff,
-0x2228821, 0x111c02, 0x3222ffff, 0x628821,
-0x8faa0024, 0x1518823, 0x111402, 0x2228821,
-0x2308821, 0x111402, 0x2228821, 0x3231ffff,
-0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001,
-0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e,
-0x8faa002c, 0x31420004, 0x10400002, 0x24091000,
-0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4,
-0xafa90010, 0x8f490044, 0x84140, 0x1001821,
-0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020,
-0xafa80018, 0x8f48010c, 0x1021, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x1440000b, 0x0, 0x8f820128, 0x3c040001,
-0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124,
-0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920,
-0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044,
-0x8f430088, 0x24420001, 0x431024, 0xaf420044,
-0x8faa0034, 0x8f440368, 0x24020001, 0x15420006,
-0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
-0x10000049, 0x8f42035c, 0x15420006, 0x0,
-0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042,
-0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
-0x1000003d, 0x8f420360, 0x30621000, 0x10400005,
-0x30628000, 0x8f420078, 0x24420001, 0x10000036,
-0xaf420078, 0x10400034, 0x0, 0x8f420078,
-0x24420001, 0xaf420078, 0x8c030240, 0x43102b,
-0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c,
-0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040,
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
-0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
-0x3c010001, 0x370821, 0xa02240f2, 0x8f820124,
-0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c,
-0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009,
-0xc002b3b, 0x34a51300, 0x1000000b, 0x0,
-0x8f420304, 0x24420001, 0xaf420304, 0x8f420304,
-0x8f420044, 0xaf42007c, 0x3c010001, 0x370821,
-0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001,
-0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c,
-0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c,
-0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008,
-0x0, 0x0, 0x0, 0x8f42013c,
-0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
-0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
-0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
-0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
-0xc002bbf, 0x24060008, 0x8c020204, 0xc004012,
-0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002,
-0x1040000e, 0x2021, 0x8c060248, 0x24020002,
-0x3c010001, 0xac226d98, 0xc005104, 0x24050002,
-0x2021, 0x8c060248, 0x24020001, 0x3c010001,
-0xac226d98, 0x10000011, 0x24050001, 0x8c060248,
-0x24020004, 0x3c010001, 0xac226d98, 0xc005104,
-0x24050004, 0x3c020001, 0x8c426d94, 0x30420001,
-0x10400008, 0x24020001, 0x3c010001, 0xac226d98,
-0x2021, 0x24050001, 0x3c06601b, 0xc005104,
-0x0, 0x3c040001, 0x248469d0, 0x8f420150,
-0x8f430154, 0x3c050008, 0x8f460158, 0x21640,
-0x31940, 0x34630403, 0x431025, 0x633c0,
-0x461025, 0xaf82021c, 0xafa00010, 0xafa00014,
-0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821,
-0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8,
-0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
-0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010,
-0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc,
-0xc002b3b, 0x3821, 0x8f420410, 0x24420001,
-0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c,
-0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4,
-0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010,
-0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8,
-0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821,
-0x3c044000, 0x2041024, 0x504000b4, 0x3c040100,
-0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc,
-0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823,
-0x43102b, 0x10400003, 0x0, 0x8f420148,
-0x621821, 0x10600005, 0x0, 0x8f42014c,
-0x43102b, 0x1040000b, 0x0, 0x8f8200e0,
-0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220,
-0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce,
-0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420004, 0xaf820220, 0x8f8200e0,
-0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8,
-0x8f840120, 0x8f830124, 0x10000005, 0x2821,
-0x14620002, 0x24620020, 0x27624800, 0x401821,
-0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003,
-0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001,
-0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008,
-0x30a200ff, 0x14400058, 0x0, 0x934205c4,
-0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0,
-0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023,
-0x218c3, 0x4620001, 0x24630200, 0x10600005,
-0x24020001, 0x10620009, 0x0, 0x1000001f,
-0x0, 0x8f4203c0, 0xe03021, 0x24420001,
-0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4,
-0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
-0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
-0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
-0x14400031, 0x0, 0x8f42020c, 0x24420001,
-0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
-0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8,
-0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000,
-0x8f420148, 0xa71823, 0x43102b, 0x10400003,
-0x0, 0x8f420148, 0x621821, 0x8f42014c,
-0x43102b, 0x5440000a, 0xa03021, 0x8f42020c,
-0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008,
-0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8,
-0x1488000d, 0x27623000, 0x14820002, 0x2482fff8,
-0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff,
-0xc33021, 0x46102b, 0x10400003, 0x0,
-0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4,
-0x8f420148, 0xc31823, 0x43102b, 0x10400003,
-0x0, 0x8f420148, 0x621821, 0x10600005,
-0x0, 0x8f42014c, 0x43102b, 0x50400008,
-0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb,
-0x431024, 0x3c034000, 0x1000003f, 0x431025,
-0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
-0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024,
-0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001,
-0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff,
-0x3463ffff, 0x431024, 0x441025, 0xc003daf,
-0xaf820220, 0x10000029, 0x0, 0x2111024,
-0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001,
-0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019,
-0x0, 0x2111024, 0x1040001c, 0x0,
-0x8f830224, 0x24021402, 0x14620009, 0x3c050008,
-0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014,
-0x8f860224, 0x34a50500, 0xc002b3b, 0x3821,
-0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0,
-0x8f820220, 0x2002021, 0x34420002, 0xc004e9c,
-0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x511025, 0xaf820220, 0x8fbf0020,
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
-0x3e00008, 0x0, 0x3c020001, 0x8c426da8,
-0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
-0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
-0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
-0x24020001, 0x3c010001, 0xac206da8, 0x3c010001,
-0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff,
-0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
-0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
-0x10400092, 0x284a024, 0x3c040600, 0x34842000,
-0x8f420004, 0x2821, 0x2403fffd, 0x431024,
-0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
-0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
-0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
-0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
-0x8c020228, 0x3c040001, 0x24846998, 0x3c050009,
-0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
-0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
-0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
-0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
-0x9821, 0xe08821, 0x263504c0, 0x8f440178,
-0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
-0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
-0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
-0xa3482b, 0x822021, 0x100f809, 0x892021,
-0x54400006, 0x24130001, 0x8f820054, 0x2021023,
-0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
-0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
-0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
-0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4,
-0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
-0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
-0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
-0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
-0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
-0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
-0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
-0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
-0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
-0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
-0x326200ff, 0x14400011, 0x0, 0x8f420378,
-0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
-0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
-0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000,
-0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec,
-0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
-0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
-0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
-0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d,
-0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008,
-0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
-0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b,
-0x3821, 0x3c020004, 0x2c21024, 0x10400007,
-0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
-0x431024, 0x34420008, 0xaf820220, 0x3c050001,
-0x8ca56d98, 0x24020001, 0x14a20007, 0x2021,
-0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c,
-0x10000006, 0x3c020007, 0xc00529b, 0x2021,
-0xac020268, 0x8c030268, 0x3c020007, 0x621824,
-0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
-0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
-0x3c020098, 0x1000000b, 0x0, 0x14620009,
-0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
-0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
-0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x0, 0x0, 0x0, 0x86102b,
-0x50400001, 0x872023, 0xc41023, 0x24843,
-0x125102b, 0x1040001b, 0x91040, 0x824021,
-0x88102b, 0x10400007, 0x1821, 0x94820000,
-0x24840002, 0x621821, 0x88102b, 0x1440fffb,
-0x0, 0x602021, 0xc73023, 0xa91023,
-0x21040, 0xc22821, 0xc5102b, 0x10400007,
-0x1821, 0x94c20000, 0x24c60002, 0x621821,
-0xc5102b, 0x1440fffb, 0x0, 0x1000000d,
-0x832021, 0x51040, 0x822821, 0x85102b,
-0x10400007, 0x1821, 0x94820000, 0x24840002,
-0x621821, 0x85102b, 0x1440fffb, 0x0,
-0x602021, 0x41c02, 0x3082ffff, 0x622021,
-0x41c02, 0x3082ffff, 0x622021, 0x3e00008,
-0x3082ffff, 0x3e00008, 0x0, 0x802821,
-0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff,
-0x24a20004, 0x62102b, 0x54400007, 0x65102b,
-0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002,
-0x1000002a, 0x441021, 0x10400003, 0x0,
-0x8f420148, 0xa22823, 0x90a40000, 0x24a50001,
-0x65102b, 0x10400003, 0x0, 0x8f420148,
-0xa22823, 0x90a20000, 0x24a50001, 0x21200,
-0x822021, 0x65102b, 0x10400003, 0x0,
-0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
-0x822021, 0x65102b, 0x10400003, 0x0,
-0x8f420148, 0xa22823, 0x90a20000, 0x1000002d,
-0x21200, 0x3463ffff, 0x24a20004, 0x62102b,
-0x5440000a, 0x65102b, 0x90a20000, 0x90a40002,
-0x90a30001, 0x90a50003, 0x441021, 0x21200,
-0x651821, 0x10000020, 0x432021, 0x10400003,
-0x0, 0x8f420148, 0xa22823, 0x90a20000,
-0x24a50001, 0x22200, 0x65102b, 0x10400003,
-0x0, 0x8f420148, 0xa22823, 0x90a20000,
-0x24a50001, 0x822021, 0x65102b, 0x10400003,
-0x0, 0x8f420148, 0xa22823, 0x90a20000,
-0x24a50001, 0x21200, 0x822021, 0x65102b,
-0x10400003, 0x0, 0x8f420148, 0xa22823,
-0x90a20000, 0x822021, 0x41c02, 0x3082ffff,
-0x622021, 0x41c02, 0x3082ffff, 0x622021,
-0x3e00008, 0x3082ffff, 0x0, 0x8f820220,
-0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8,
-0x30424000, 0x10400054, 0x24040001, 0x8f820200,
-0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
-0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820224, 0x1444004d, 0x42040, 0xc4102b,
-0x1040fff1, 0x0, 0x8f820200, 0x451025,
-0xaf820200, 0x8f820220, 0x34428000, 0xaf820220,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x8f820220, 0x3c030004, 0x431024,
-0x1440000f, 0x0, 0x8f820220, 0x3c03ffff,
-0x34637fff, 0x431024, 0xaf820220, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820220, 0x3c030004, 0x431024, 0x1440000d,
-0x0, 0x8f820220, 0x34428000, 0xaf820220,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x8f820220, 0x3c030004, 0x431024,
-0x1040001b, 0x1021, 0x8f830220, 0x24020001,
-0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700,
-0x441025, 0xaf820220, 0x8f820220, 0x2403fffd,
-0x431024, 0xaf820220, 0x8f820220, 0x3c030300,
-0x431024, 0x14400003, 0x0, 0x10000008,
-0x1021, 0x8f820220, 0x34420002, 0xaf820220,
-0x8f830220, 0x24020001, 0x641825, 0xaf830220,
-0x3e00008, 0x0, 0x2021, 0x3c050100,
-0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
-0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4,
-0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0,
-0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8,
-0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4,
-0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0,
-0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8,
-0x418c0, 0x24840001, 0x3631021, 0xac453004,
-0x3631021, 0xac403000, 0x28820200, 0x1440fff9,
-0x418c0, 0x2021, 0x418c0, 0x24840001,
-0x3631021, 0xac402804, 0x3631021, 0xac402800,
-0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c,
-0x24030080, 0x24040100, 0xac600000, 0x24630004,
-0x64102b, 0x5440fffd, 0xac600000, 0x8f830040,
-0x3c02f000, 0x621824, 0x3c025000, 0x1062000c,
-0x43102b, 0x14400006, 0x3c026000, 0x3c024000,
-0x10620008, 0x24020800, 0x10000008, 0x0,
-0x10620004, 0x24020800, 0x10000004, 0x0,
-0x24020700, 0x3c010001, 0xac226dac, 0x3e00008,
-0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0,
-0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020,
-0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e,
-0x0, 0x3c010001, 0xac206dbc, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0xc004db9, 0x0, 0x24040001, 0x2821,
-0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
-0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c,
-0x24050002, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630064, 0x8f820054, 0x621023, 0x2c420065,
-0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
-0x26106f26, 0xc00457c, 0x2003021, 0x97a60018,
-0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0,
-0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
-0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d,
-0x24036040, 0x96020000, 0x3042fff0, 0x1443000c,
-0x24020020, 0x3c030001, 0x94636f24, 0x1462000b,
-0x24027830, 0x24020003, 0x3c010001, 0xac226d94,
-0x24020005, 0x3c010001, 0x1000003f, 0xac226f34,
-0x3c030001, 0x94636f24, 0x24027830, 0x1462000c,
-0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0,
-0x14430007, 0x24020003, 0x3c010001, 0xac226d94,
-0x24020006, 0x3c010001, 0x1000002f, 0xac226f34,
-0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24,
-0x34420001, 0x3c010001, 0xac226d94, 0x24020015,
-0x1462000b, 0x0, 0x3c020001, 0x94426f26,
-0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430,
-0x2c420001, 0x621825, 0x1460001b, 0x24020003,
-0x3c030001, 0x94636f24, 0x24027810, 0x14620016,
-0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0,
-0x14400011, 0x24020002, 0x1000000f, 0x24020004,
-0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001,
-0xac226d94, 0x1000005e, 0x24020004, 0x3c020001,
-0x8c426d94, 0x34420004, 0x3c010001, 0x100000af,
-0xac226d94, 0x24020001, 0x3c010001, 0xac226f40,
-0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2,
-0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054,
-0x8f820054, 0x24030008, 0x3c010001, 0xac236d98,
-0x10000002, 0x248401f4, 0x8f820054, 0x821023,
-0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
-0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
-0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
-0x1440fffc, 0x8021, 0x24120001, 0x24110009,
-0xc004482, 0x0, 0x3c010001, 0xac326db4,
-0xc004547, 0x0, 0x3c020001, 0x8c426db4,
-0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
-0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
-0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
-0x0, 0x8f820220, 0x24040001, 0x34420002,
-0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
-0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x8f820224, 0x14440005, 0x34028000, 0x42040,
-0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0,
-0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
-0x3c010001, 0xac226d98, 0x8021, 0x24120009,
-0x3c11ffff, 0x36313f7f, 0xc004482, 0x0,
-0x24020001, 0x3c010001, 0xac226db4, 0xc004547,
-0x0, 0x3c020001, 0x8c426db4, 0x1452fffb,
-0x0, 0x8f820044, 0x511024, 0x34425080,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
-0x1440fffc, 0x0, 0x8f820044, 0x511024,
-0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
-0x10000002, 0x2463000a, 0x8f820054, 0x621023,
-0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
-0x621023, 0x2c420065, 0x1440fffc, 0x0,
-0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
-0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
-0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
-0x10000002, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
-0x14440005, 0x34028000, 0x42040, 0xa4102b,
-0x1040fff0, 0x34028000, 0x1082ff50, 0x26100001,
-0x2e020064, 0x1440ffb0, 0x0, 0x3c020001,
-0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0,
-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
-0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001,
-0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001,
-0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001,
-0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001,
-0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001,
-0xac206d98, 0x491021, 0x3c010001, 0xac226f30,
-0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c,
-0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
-0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98,
-0x24060004, 0x24020001, 0x14a20014, 0xafbf0010,
-0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005,
-0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005,
-0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40,
-0x348493e0, 0x24020005, 0x14620016, 0x0,
-0x3c04003d, 0x10000013, 0x34840900, 0x3c020002,
-0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e,
-0x3c030001, 0x8c636f40, 0x10000005, 0x34848480,
-0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240,
-0x24020005, 0x14620003, 0x0, 0x3c04007a,
-0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054,
-0x441021, 0x431023, 0x44102b, 0x1440004c,
-0x0, 0x3c020001, 0x8c426da0, 0x14400048,
-0x0, 0x3c010001, 0x10c00025, 0xac206db0,
-0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000,
-0x3c080002, 0x25088ffc, 0x250afffc, 0x52842,
-0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024,
-0x10400010, 0x0, 0x14a70008, 0x0,
-0x8d020000, 0x441024, 0x1040000a, 0x0,
-0x3c010001, 0x10000007, 0xac256db0, 0x8d420000,
-0x441024, 0x10400003, 0x0, 0x3c010001,
-0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b,
-0x2c420001, 0x431024, 0x5440ffe5, 0x52842,
-0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001,
-0xac226f30, 0x1060003b, 0x24020005, 0x3c030001,
-0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012,
-0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000,
-0x34635000, 0x431024, 0x14400006, 0x24020001,
-0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98,
-0x24020001, 0x3c010001, 0xac226e24, 0x3c010001,
-0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c,
-0x3c020001, 0x8c426db0, 0x1040001e, 0x0,
-0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001,
-0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001,
-0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8,
-0x24020008, 0x10620005, 0x24020001, 0xc004239,
-0x0, 0x1000000b, 0x0, 0x3c030001,
-0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002,
-0x8c638f90, 0x10620003, 0x0, 0xc004e9c,
-0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
-0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98,
-0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024,
-0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001,
-0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8,
-0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4,
-0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c,
-0x2c620003, 0x10400005, 0x24020001, 0x1062000a,
-0x0, 0x10000226, 0x0, 0x24020004,
-0x106200b6, 0x24020008, 0x1062010a, 0x24020001,
-0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff,
-0x2c620008, 0x1040021c, 0x31080, 0x3c010001,
-0x220821, 0x8c226af8, 0x400008, 0x0,
-0x3c030001, 0x8c636f40, 0x24020005, 0x14620010,
-0x0, 0x3c020001, 0x8c426da4, 0x10400008,
-0x24020003, 0xc004482, 0x0, 0x24020002,
-0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4,
-0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30,
-0xc004482, 0x0, 0x3c020001, 0x8c426da4,
-0x3c010001, 0xac206d30, 0x1440017a, 0x24020002,
-0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40,
-0x24020005, 0x14620003, 0x24020001, 0x3c010001,
-0xac226dd0, 0xc0045ff, 0x0, 0x3c030001,
-0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001,
-0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104,
-0x2021, 0x24020005, 0x3c010001, 0xac206da4,
-0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec,
-0x3c05000f, 0x34a50100, 0x3021, 0x3821,
-0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6,
-0x0, 0x8f820220, 0x3c030004, 0x431024,
-0x14400175, 0x24020007, 0x8f830054, 0x3c020001,
-0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400003, 0x24020001, 0x3c010001, 0xac226d9c,
-0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2,
-0x0, 0x8f820220, 0x30428000, 0x1040017d,
-0x0, 0x10000175, 0x0, 0x3c050001,
-0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b,
-0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0,
-0x24020001, 0x3c020008, 0x621024, 0x10400006,
-0x0, 0x8f820214, 0x3c03ffff, 0x431024,
-0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff,
-0x431024, 0x3442241f, 0xaf820214, 0x8f820220,
-0x3c030200, 0x34420002, 0xaf820220, 0x24020008,
-0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004,
-0x431024, 0x14400016, 0x0, 0x3c020002,
-0x8c428ffc, 0x30425000, 0x1040000d, 0x0,
-0x8f820220, 0x30428000, 0x10400006, 0x0,
-0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003,
-0x431024, 0x8f820220, 0x34428000, 0xaf820220,
-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a,
-0x0, 0x3c020001, 0x94426f26, 0x24429fbc,
-0x2c420004, 0x10400004, 0x24040018, 0x24050002,
-0xc004ddb, 0x24060020, 0xc003e6d, 0x0,
-0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8,
-0x2443ffff, 0x2c620008, 0x1040016b, 0x31080,
-0x3c010001, 0x220821, 0x8c226b18, 0x400008,
-0x0, 0xc004547, 0x0, 0x3c030001,
-0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002,
-0x8c428ff8, 0x30424000, 0x10400004, 0x0,
-0x8f820044, 0x10000006, 0x3442f080, 0x8f820044,
-0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080,
-0xaf820044, 0x8f830054, 0x100000ea, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400147, 0x24020005,
-0x100000d8, 0x0, 0x8f820220, 0x3c03f700,
-0x431025, 0xaf820220, 0xaf800204, 0x3c010002,
-0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001,
-0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a,
-0x14400135, 0x24020007, 0x100000d7, 0x0,
-0xc003f50, 0x0, 0x1040012d, 0x24020001,
-0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c,
-0x431024, 0x3442251f, 0xaf820214, 0x24020008,
-0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44,
-0x10400064, 0x24020001, 0x8f820220, 0x3c030008,
-0x431024, 0x1040006a, 0x3c020200, 0x10000078,
-0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007,
-0x10400115, 0x31080, 0x3c010001, 0x220821,
-0x8c226b38, 0x400008, 0x0, 0xc003daf,
-0x0, 0x3c010001, 0xac206d9c, 0xaf800204,
-0x3c010002, 0xc004482, 0xac208fe0, 0x24020001,
-0x3c010001, 0xac226db4, 0x24020002, 0x10000102,
-0xaee204b8, 0xc004547, 0x0, 0x3c030001,
-0x8c636db4, 0x10000084, 0x24020009, 0x3c020002,
-0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8,
-0x10000002, 0x344201f6, 0x344201fe, 0xaf820238,
-0x8f830054, 0x1000008b, 0x24020004, 0x8f830054,
-0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023,
-0x2c422710, 0x144000e8, 0x24020005, 0x10000079,
-0x0, 0x8f820220, 0x3c03f700, 0x431025,
-0xaf820220, 0xaf800204, 0x3c010002, 0x10000077,
-0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28,
-0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6,
-0x24020007, 0x10000078, 0x0, 0xc003f50,
-0x0, 0x104000ce, 0x24020001, 0x8f820214,
-0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024,
-0x3442251f, 0xaf820214, 0x24020008, 0x1080000f,
-0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b,
-0x0, 0x8f820220, 0x34420002, 0xaf820220,
-0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c,
-0x8f840220, 0x10000016, 0x0, 0x8f820220,
-0x3c030008, 0x431024, 0x14400011, 0x3c020200,
-0x282a025, 0x2402000e, 0x3c010002, 0xac228f90,
-0xc00551b, 0x2021, 0x8f820220, 0x34420002,
-0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98,
-0xc00529b, 0x2021, 0x100000a3, 0x0,
-0x3c020001, 0x8c426e44, 0x1040009f, 0x0,
-0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001,
-0xac226e40, 0x14400098, 0x24020002, 0x3c010001,
-0xac206e44, 0x3c010001, 0x10000093, 0xac226e40,
-0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e,
-0x31080, 0x3c010001, 0x220821, 0x8c226b58,
-0x400008, 0x0, 0x3c020001, 0x8c426da4,
-0x10400018, 0x24020005, 0xc004482, 0x0,
-0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e,
-0xac206da4, 0xc004963, 0x0, 0x3c030001,
-0x8c636dd4, 0x24020006, 0x14620077, 0x24020003,
-0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98,
-0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021,
-0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
-0x24020006, 0xaee204b8, 0x3c010001, 0x10000062,
-0xac236f28, 0x8f820220, 0x3c030004, 0x431024,
-0x10400003, 0x24020007, 0x1000005b, 0xaee204b8,
-0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400003, 0x24020001,
-0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8,
-0x30425000, 0x1040004c, 0x0, 0x8f820220,
-0x30428000, 0x10400007, 0x0, 0x8f820220,
-0x3c03ffff, 0x34637fff, 0x431024, 0x10000042,
-0xaf820220, 0x8f820220, 0x34428000, 0x1000003e,
-0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b,
-0x2021, 0xc00551b, 0x2021, 0x3c020002,
-0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214,
-0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
-0x24020008, 0xaee204b8, 0x8f820220, 0x34420002,
-0xaf820220, 0x8f820220, 0x3c030004, 0x431024,
-0x14400016, 0x0, 0x3c020002, 0x8c428ff8,
-0x30425000, 0x1040000d, 0x0, 0x8f820220,
-0x30428000, 0x10400006, 0x0, 0x8f820220,
-0x3c03ffff, 0x34637fff, 0x10000003, 0x431024,
-0x8f820220, 0x34428000, 0xaf820220, 0x8f820220,
-0x3c03f700, 0x431025, 0xaf820220, 0x3c020001,
-0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004,
-0x24040018, 0x24050002, 0xc004ddb, 0x24060020,
-0xc003e6d, 0x0, 0x10000003, 0x0,
-0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008,
-0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
-0x34420004, 0xaf820220, 0x8f820200, 0x3c050001,
-0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002,
-0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001,
-0x10a2000a, 0x0, 0x100000b1, 0x0,
-0x24020004, 0x10a20072, 0x24020008, 0x10a20085,
-0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050,
-0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40,
-0x621824, 0x3c020700, 0x621825, 0x24020e00,
-0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200,
-0xaf850220, 0x14800006, 0xaf820238, 0x8f820044,
-0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044,
-0x3c030001, 0x8c636f40, 0x24020005, 0x14620004,
-0x0, 0x8f820044, 0x34425000, 0xaf820044,
-0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40,
-0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c,
-0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001,
-0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000,
-0x621825, 0x641825, 0x1000000a, 0x34620002,
-0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac,
-0x3c040001, 0x8c846d8c, 0x431025, 0x441025,
-0x34420002, 0xaf820220, 0x1000002f, 0x24020001,
-0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff,
-0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824,
-0x3c020d00, 0x621825, 0x24020001, 0xaf830050,
-0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00,
-0x3c020001, 0x8c426d80, 0x10000004, 0x34630070,
-0x3c020001, 0x8c426d80, 0x34630072, 0x431025,
-0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700,
-0x621825, 0x3c020001, 0x8c426d90, 0x3c040001,
-0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025,
-0x441025, 0xaf820220, 0x24020005, 0x14a20006,
-0x24020001, 0x8f820044, 0x2403afff, 0x431024,
-0xaf820044, 0x24020001, 0x1000003d, 0xaf820238,
-0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001,
-0x8c846f1c, 0x621824, 0x3c020a00, 0x621825,
-0x24020001, 0xaf830050, 0xaf820200, 0x1080001e,
-0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a,
-0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a,
-0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c,
-0x3442ffff, 0x621824, 0x1080000f, 0xaf830050,
-0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00,
-0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001,
-0xaf820200, 0xaf820220, 0x641825, 0xaf830200,
-0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80,
-0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
-0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84,
-0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac,
-0x651825, 0x431025, 0x441025, 0xaf820220,
-0x3e00008, 0x0, 0x3c030001, 0x8c636db4,
-0x3c020001, 0x8c426db8, 0x10620003, 0x24020002,
-0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003,
-0x10400025, 0x24020001, 0x14620023, 0x24020004,
-0x3c030001, 0x8c636d98, 0x10620006, 0x24020008,
-0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009,
-0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044,
-0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080,
-0xaf820044, 0x8f830054, 0x24020002, 0x3c010001,
-0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c,
-0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0,
-0x431023, 0x2c422710, 0x14400003, 0x24020009,
-0x3c010001, 0xac226db4, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x27bdffd8,
-0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
-0xafb10014, 0xc08821, 0xafb00010, 0x8021,
-0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x2501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x2501024, 0x24100010, 0x2701024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x2701024, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c,
-0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
-0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
-0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
-0xafb00010, 0x8021, 0xafbf0020, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x2301024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2501024, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96620000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8fbf0020,
-0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
-0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0,
-0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020,
-0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001,
-0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005,
-0x14620005, 0x2483ffff, 0xc004963, 0x0,
-0x1000034c, 0x0, 0x2c620013, 0x10400349,
-0x31080, 0x3c010001, 0x220821, 0x8c226b80,
-0x400008, 0x0, 0xc004db9, 0x8021,
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010,
-0x8021, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x0, 0x97a20010, 0x30428000,
-0x144002dc, 0x24020003, 0x100002d8, 0x0,
-0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0xc004d78, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x34108000, 0x96220000, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fff8, 0x0, 0xc004db9,
-0x0, 0x8f830054, 0x10000296, 0x24020004,
-0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c,
-0x431023, 0x2c420064, 0x1440029e, 0x24020002,
-0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003,
-0x14400296, 0x24020011, 0x24020003, 0x10620005,
-0x24020004, 0x10620291, 0x2402000f, 0x1000028f,
-0x24020011, 0x1000028d, 0x24020005, 0x24020014,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020012, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8f830054,
-0x10000248, 0x24020006, 0x8f830054, 0x3c020001,
-0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400250, 0x24020007, 0x1000024c, 0x0,
-0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020013, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020013,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x10000207, 0x24020008, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440020f, 0x24020009, 0x1000020b,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x10000193, 0x2402000a, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x1440019b, 0x2402000b, 0x10000197,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020017, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x14400127, 0x24020012, 0x10000123,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020014, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x100000ab, 0x24020013, 0x8f830054,
-0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
-0x2c420064, 0x144000b3, 0x2402000d, 0x100000af,
-0x0, 0x27b10010, 0xa7a00010, 0x8021,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x96220000, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x8f830054, 0x10000037, 0x2402000e, 0x24020840,
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020013, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96220000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8f830054,
-0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001,
-0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001,
-0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
-0x14400004, 0x0, 0x24020011, 0x3c010001,
-0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98,
-0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030,
-0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002,
-0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc,
-0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c,
-0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c,
-0x2463ffff, 0x2c620006, 0x10400377, 0x31080,
-0x3c010001, 0x220821, 0x8c226bd8, 0x400008,
-0x0, 0x2021, 0x2821, 0xc004ddb,
-0x34068000, 0x24040010, 0x24050002, 0x24060002,
-0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002,
-0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018,
-0xa7a00018, 0x8021, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x32020001, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020001, 0x24100010, 0xc004d78, 0x2021,
-0x108042, 0x1600fffc, 0x0, 0xc004db9,
-0x34108000, 0xc004db9, 0x0, 0xc004d58,
-0x0, 0x50400005, 0x108042, 0x96220000,
-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
-0x0, 0xc004db9, 0x0, 0x97a20018,
-0x30428000, 0x14400004, 0x24020003, 0x3c010001,
-0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a,
-0xac226dd4, 0x24040010, 0x24050002, 0x24060002,
-0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001,
-0x8c636e20, 0x24020001, 0x146201e1, 0x8021,
-0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x32020001, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020001, 0x24100010, 0x32020018, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x96220000, 0x501025,
-0xa6220000, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0x27b10018, 0xa7a00018,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0x32020001,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x32020001, 0x24100010,
-0x32020018, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x96220000, 0x501025, 0xa6220000, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0x24040018, 0x2821, 0xc004ddb, 0x24060404,
-0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0x32020018, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020018, 0xc004db9, 0x34108000, 0xc004db9,
-0x0, 0xc004d58, 0x0, 0x50400005,
-0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
-0x108042, 0x1600fff7, 0x0, 0xc004db9,
-0x8021, 0xa7a0001a, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0x32020001, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x32020001, 0x24100010, 0x32020018, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x97a2001a, 0x501025,
-0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x24100010, 0xc004d78, 0x2021,
-0x108042, 0x1600fffc, 0x0, 0x24100010,
-0x3202001e, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x3202001e,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x97a2001c, 0x501025, 0xa7a2001c, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x8021,
-0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0xc004d78, 0x2021, 0x108042, 0x1600fffc,
-0x0, 0x24100010, 0x3202001e, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x97a2001c, 0x501025,
-0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0x24020002, 0xa7a2001e,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0x24100010, 0x3202001e, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x3202001e, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x34108000, 0x97a2001e, 0x501024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fff8, 0x0, 0xc004db9,
-0x8021, 0xa7a00020, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0x24100010, 0x3202001e,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x3202001e, 0xc004db9,
-0x34108000, 0xc004db9, 0x0, 0xc004d58,
-0x0, 0x50400005, 0x108042, 0x97a20020,
-0x501025, 0xa7a20020, 0x108042, 0x1600fff7,
-0x0, 0xc004db9, 0x8021, 0xa7a00020,
-0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
-0x1440fffb, 0x0, 0xc004d78, 0x2021,
-0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0x24100010, 0x3202001e, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
-0x3202001e, 0xc004db9, 0x34108000, 0xc004db9,
-0x0, 0xc004d58, 0x0, 0x50400005,
-0x108042, 0x97a20020, 0x501025, 0xa7a20020,
-0x108042, 0x1600fff7, 0x0, 0xc004db9,
-0x8021, 0xa7a00022, 0xc004d78, 0x24040001,
-0x26100001, 0x2e020020, 0x1440fffb, 0x0,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0xc004d78, 0x2021, 0xc004d78, 0x24040001,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004d78, 0x24040001, 0xc004d78, 0x2021,
-0x34108000, 0x97a20022, 0x501024, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fff8, 0x0, 0xc004db9, 0x0,
-0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
-0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d,
-0x0, 0x3c020001, 0x94426f26, 0x3c010001,
-0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c,
-0x24040009, 0x24050001, 0xc004ddb, 0x24060400,
-0x24040018, 0x24050001, 0xc004ddb, 0x24060020,
-0x24040018, 0x24050001, 0xc004ddb, 0x24062000,
-0x3c024000, 0x2421024, 0x10400123, 0x3c022000,
-0x2421024, 0x10400004, 0x0, 0x3c010001,
-0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c,
-0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9,
-0x0, 0x3c020001, 0x8c426f1c, 0x10400067,
-0x3c020004, 0x2421024, 0x10400011, 0xa7a00018,
-0x3c020008, 0x2421024, 0x10400002, 0x24020200,
-0xa7a20018, 0x3c020010, 0x2421024, 0x10400004,
-0x0, 0x97a20018, 0x34420100, 0xa7a20018,
-0x97a60018, 0x24040009, 0x10000004, 0x2821,
-0x24040009, 0x2821, 0x3021, 0xc004ddb,
-0x0, 0x24020001, 0xa7a2001a, 0x3c020008,
-0x2421024, 0x1040000c, 0x3c020002, 0x2421024,
-0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001,
-0x2421024, 0x10400005, 0x3c020010, 0x97a2001a,
-0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024,
-0x1040000e, 0x3c020002, 0x2421024, 0x10400005,
-0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a,
-0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0,
-0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0,
-0x2431024, 0x54430004, 0x3c020020, 0x97a2001a,
-0x1000000c, 0x34420400, 0x2421024, 0x50400004,
-0x3c020080, 0x97a2001a, 0x10000006, 0x34420800,
-0x2421024, 0x10400004, 0x0, 0x97a2001a,
-0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004,
-0xc004ddb, 0x2821, 0x3c020004, 0x2421024,
-0x10400004, 0xa7a0001c, 0x32425000, 0x14400004,
-0x0, 0x32424000, 0x10400005, 0x2021,
-0xc004cf9, 0x2402021, 0x10000096, 0x0,
-0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb,
-0xa7a6001c, 0x1000008f, 0x0, 0x2421024,
-0x10400004, 0xa7a00018, 0x32425000, 0x14400004,
-0x0, 0x32424000, 0x10400005, 0x3c020010,
-0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a,
-0x2421024, 0x10400004, 0x0, 0x97a20018,
-0x10000004, 0xa7a20018, 0x97a20018, 0x34420100,
-0xa7a20018, 0x3c020001, 0x2421024, 0x10400004,
-0x0, 0x97a20018, 0x10000004, 0xa7a20018,
-0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018,
-0x2021, 0xc004ddb, 0x2821, 0xa7a0001a,
-0x8021, 0xc004d78, 0x24040001, 0x26100001,
-0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
-0x2021, 0xc004d78, 0x24040001, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x24100010,
-0x32020001, 0x10400002, 0x2021, 0x24040001,
-0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
-0x24100010, 0xc004d78, 0x2021, 0x108042,
-0x1600fffc, 0x0, 0xc004db9, 0x34108000,
-0xc004db9, 0x0, 0xc004d58, 0x0,
-0x50400005, 0x108042, 0x97a2001a, 0x501025,
-0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
-0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
-0x2021, 0x108042, 0x1600fffc, 0x0,
-0xc004db9, 0x34108000, 0xc004db9, 0x0,
-0xc004d58, 0x0, 0x50400005, 0x108042,
-0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
-0x1600fff7, 0x0, 0xc004db9, 0x0,
-0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a,
-0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c,
-0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b,
-0xafa30014, 0x8f830054, 0x24020004, 0x3c010001,
-0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38,
-0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c,
-0x431023, 0x2c420064, 0x1440000f, 0x0,
-0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4,
-0x3c03f700, 0x431025, 0x10000007, 0xaf820220,
-0x24020006, 0x3c010001, 0xac226dd4, 0x24020011,
-0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030,
-0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038,
-0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c,
-0x8821, 0x32024000, 0x10400013, 0xafbf0020,
-0x3c020010, 0x2021024, 0x2c420001, 0x21023,
-0x30434100, 0x3c020001, 0x2021024, 0x14400006,
-0x34714000, 0x3c020002, 0x2021024, 0x14400002,
-0x34716000, 0x34714040, 0x2021, 0x2821,
-0x10000036, 0x2203021, 0x32021000, 0x10400035,
-0x2021, 0x2821, 0xc004ddb, 0x24060040,
-0x24040018, 0x2821, 0xc004ddb, 0x24060c00,
-0x24040017, 0x2821, 0xc004ddb, 0x24060400,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x24040017, 0x2821, 0xc004ddb, 0x24062500,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x24040017, 0x2821, 0xc004ddb, 0x24064600,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x24040017, 0x2821, 0xc004ddb, 0x24066700,
-0x24040016, 0x2821, 0xc004ddb, 0x24060006,
-0x2404001f, 0x2821, 0xc004ddb, 0x24060010,
-0x24040009, 0x2821, 0xc004ddb, 0x24061500,
-0x24040009, 0x2821, 0x24061d00, 0xc004ddb,
-0x0, 0x3c040001, 0x24846bf0, 0x3c05000e,
-0x34a50100, 0x2003021, 0x2203821, 0xafa00010,
-0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c,
-0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044,
-0x8f820044, 0x3c030001, 0x431025, 0x3c030008,
-0xaf820044, 0x8f840054, 0x8f820054, 0xa32824,
-0x10000002, 0x24840001, 0x8f820054, 0x821023,
-0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
-0x0, 0x3e00008, 0xa01021, 0x8f830044,
-0x3c02fff0, 0x3442ffff, 0x42480, 0x621824,
-0x3c020002, 0x822025, 0x641825, 0xaf830044,
-0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c030001,
-0x431025, 0xaf820044, 0x8f830054, 0x8f820054,
-0x10000002, 0x24630001, 0x8f820054, 0x621023,
-0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
-0x0, 0x8f820044, 0x2403ff7f, 0x431024,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x34420080,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x3e00008, 0x0,
-0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
-0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
-0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
-0x24630001, 0x8f820054, 0x621023, 0x2c420002,
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
-0x621023, 0x2c420002, 0x1440fffc, 0x0,
-0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
-0x809821, 0xafbe002c, 0xa0f021, 0xafb20020,
-0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028,
-0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x12000075,
-0x0, 0x1000fff6, 0x0, 0x3275ffff,
-0x27b10010, 0xa7a00010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
-0x2021, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2b01024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2b01024, 0xc004db9,
-0x34108000, 0xc004db9, 0x0, 0xc004d58,
-0x0, 0x50400005, 0x108042, 0x96220000,
-0x501025, 0xa6220000, 0x108042, 0x1600fff7,
-0x0, 0xc004db9, 0x0, 0x33c5ffff,
-0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
-0x10000006, 0x521025, 0x14a20006, 0x3271ffff,
-0x97a20010, 0x121827, 0x431024, 0xa7a20010,
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
-0x0, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0xc004d78,
-0x24040001, 0x24100010, 0x32020001, 0x10400002,
-0x2021, 0x24040001, 0xc004d78, 0x108042,
-0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
-0x10400002, 0x2021, 0x24040001, 0xc004d78,
-0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
-0x24040001, 0xc004d78, 0x2021, 0x34108000,
-0x96420000, 0x501024, 0x10400002, 0x2021,
-0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
-0x0, 0xc004db9, 0x0, 0x8fbf0030,
-0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020,
-0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
-0x0, 0x0, 0x0, 0x27bdffe8,
-0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0,
-0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
-0x0, 0xc003daf, 0x8f840224, 0x100001d8,
-0x0, 0x8f820220, 0x3c030008, 0x431024,
-0x10400026, 0x24020001, 0x8f840224, 0x8f820220,
-0x3c030400, 0x431024, 0x10400006, 0x0,
-0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b,
-0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000,
-0x24420001, 0xac620000, 0x2c420002, 0x14400003,
-0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002,
-0x8c428fc0, 0x10400006, 0x30820040, 0x10400004,
-0x24020001, 0x3c010002, 0x10000003, 0xac228fc4,
-0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c,
-0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002,
-0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002,
-0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002,
-0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002,
-0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002,
-0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194,
-0x31080, 0x3c010001, 0x220821, 0x8c226c00,
-0x400008, 0x0, 0x24020002, 0x3c010002,
-0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002,
-0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002,
-0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224,
-0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0,
-0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf,
-0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd,
-0x431024, 0xaf820200, 0x3c010002, 0xac208fe0,
-0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001,
-0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002,
-0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4,
-0x14400006, 0x24020003, 0x3c010001, 0xac246d9c,
-0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002,
-0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002,
-0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400003, 0x24020004, 0x3c010002, 0xac228f90,
-0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff,
-0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001,
-0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8,
-0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002,
-0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204,
-0x3463ffff, 0x30420030, 0x1440012f, 0x283a024,
-0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002,
-0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0,
-0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff,
-0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001,
-0xac226e3c, 0x2c420002, 0x14400125, 0x24020001,
-0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c,
-0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002,
-0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024,
-0x3c020002, 0x8c428f9c, 0x10400115, 0x0,
-0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002,
-0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002,
-0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204,
-0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002,
-0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0,
-0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
-0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002,
-0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
-0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4,
-0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c,
-0x3c030002, 0x8c638fc8, 0x441024, 0x641824,
-0x10430004, 0x24020001, 0x3c010002, 0x100000e4,
-0xac228f90, 0x24020003, 0xaca20000, 0x24020008,
-0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc,
-0x1040000c, 0x24020001, 0x3c040002, 0xc005091,
-0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005,
-0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006,
-0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002,
-0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0,
-0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0,
-0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002,
-0xac238fac, 0x8f830054, 0x24020009, 0x3c010002,
-0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4,
-0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0,
-0x431023, 0x2c422710, 0x1440009f, 0x0,
-0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
-0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002,
-0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21,
-0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc,
-0x1040000e, 0x0, 0x3c020002, 0x8c428f9c,
-0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f,
-0x2402000c, 0x8f820204, 0x30420080, 0x1440000c,
-0x24020003, 0x10000029, 0x2402000c, 0x3c020002,
-0x8c428f9c, 0x30420080, 0x14400005, 0x24020003,
-0x8f820204, 0x30420080, 0x1040001f, 0x24020003,
-0xac620000, 0x2402000a, 0x3c010002, 0xac228f90,
-0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002,
-0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000,
-0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002,
-0xac228f90, 0x641825, 0x3c010002, 0xac238fe0,
-0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
-0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0,
-0x10400005, 0x0, 0x2402000c, 0x3c010002,
-0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0,
-0x10400063, 0x0, 0x3c040002, 0x8c848f9c,
-0x10800055, 0x30820008, 0x3c030002, 0x8c638fac,
-0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8,
-0xaca20000, 0x24020006, 0x3c010002, 0x10000054,
-0xac228f90, 0x8f820200, 0x34420002, 0xaf820200,
-0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90,
-0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002,
-0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
-0x14400031, 0x0, 0x3c020002, 0x8c428fd0,
-0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4,
-0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d,
-0x0, 0x3c050001, 0x8ca56d98, 0xc00529b,
-0x2021, 0x3c030001, 0x8c636d98, 0x24020004,
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94,
-0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94,
-0x431024, 0x3c010001, 0xac226d94, 0x8f830224,
-0x3c020200, 0x3c010002, 0xac238fec, 0x10000020,
-0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005,
-0x0, 0x3c020002, 0x8c428f9c, 0x1040000f,
-0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21,
-0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0,
-0x1040000f, 0x0, 0x3c020002, 0x8c428f9c,
-0x1440000b, 0x0, 0x24020002, 0x3c010002,
-0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0,
-0x10400003, 0x0, 0xc003daf, 0x0,
-0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
-0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002,
-0x24638fe8, 0x8c620000, 0x10400005, 0x34422000,
-0x3c010002, 0xac228fdc, 0x10000003, 0xac600000,
-0x3c010002, 0xac248fdc, 0x3e00008, 0x0,
-0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002,
-0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e,
-0x821024, 0x14400061, 0x24020030, 0x30822000,
-0x1040005d, 0x30838000, 0x31a02, 0x30820001,
-0x21200, 0x3c040001, 0x8c846f20, 0x621825,
-0x331c2, 0x3c030001, 0x24636e48, 0x30828000,
-0x21202, 0x30840001, 0x42200, 0x441025,
-0x239c2, 0x61080, 0x431021, 0x471021,
-0x90430000, 0x24020001, 0x10620025, 0x0,
-0x10600007, 0x24020002, 0x10620013, 0x24020003,
-0x1062002c, 0x3c05000f, 0x10000037, 0x0,
-0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
-0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820220, 0x3c010002, 0xac209004, 0x3c010002,
-0x10000034, 0xac20900c, 0x8f820200, 0x34420100,
-0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
-0x431024, 0xaf820220, 0x24020100, 0x3c010002,
-0xac229004, 0x3c010002, 0x10000026, 0xac20900c,
-0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
-0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
-0x3c010002, 0xac209004, 0x3c010002, 0x10000019,
-0xac23900c, 0x8f820200, 0x34420100, 0xaf820200,
-0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
-0x24020100, 0x3c010002, 0xac229004, 0x3c010002,
-0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001,
-0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014,
-0x10000004, 0x0, 0x24020030, 0x3c010002,
-0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020,
-0x0, 0x0, 0x0, 0x27bdffc8,
-0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
-0xafb00020, 0xc08021, 0x3c040001, 0x24846c50,
-0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001,
-0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
-0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010,
-0x24020002, 0x12620083, 0x2e620003, 0x10400005,
-0x24020001, 0x1262000a, 0x0, 0x10000173,
-0x0, 0x24020004, 0x126200f8, 0x24020008,
-0x126200f7, 0x3c02ffec, 0x1000016c, 0x0,
-0x3c020001, 0x8c426d94, 0x30420002, 0x14400004,
-0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
-0x3c010002, 0x310821, 0xac308ffc, 0x3c024000,
-0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
-0x101382, 0x3042001c, 0x3c030001, 0x24636dd8,
-0x431021, 0x823821, 0x3c020020, 0x2021024,
-0x10400006, 0x24020100, 0x3c010002, 0x310821,
-0xac229000, 0x10000005, 0x3c020080, 0x3c010002,
-0x310821, 0xac209000, 0x3c020080, 0x2021024,
-0x10400006, 0x121940, 0x3c020001, 0x3c010002,
-0x230821, 0x10000005, 0xac229008, 0x121140,
-0x3c010002, 0x220821, 0xac209008, 0x94e40000,
-0x3c030001, 0x8c636f40, 0x24020005, 0x10620010,
-0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
-0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
-0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002,
-0x24040001, 0x2821, 0xc0045be, 0x27a60018,
-0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001,
-0xac316da4, 0x14530004, 0x32028000, 0xc003daf,
-0x0, 0x32028000, 0x1040011c, 0x0,
-0xc003daf, 0x0, 0x3c030001, 0x8c636f40,
-0x24020005, 0x10620115, 0x24020002, 0x3c010001,
-0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98,
-0x24040001, 0x24050004, 0x27b0001a, 0xc0045be,
-0x2003021, 0x24040001, 0x2821, 0xc0045be,
-0x2003021, 0x3c020002, 0x511021, 0x8c428ff4,
-0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff,
-0x3c010001, 0xac336da4, 0x431024, 0x3c010002,
-0x310821, 0x109300f7, 0xac228ff4, 0x100000f7,
-0x0, 0x3c022000, 0x2021024, 0x10400005,
-0x24020001, 0x3c010001, 0xac226f1c, 0x10000004,
-0x128940, 0x3c010001, 0xac206f1c, 0x128940,
-0x3c010002, 0x310821, 0xac308ff8, 0x3c024000,
-0x2021024, 0x14400014, 0x0, 0x3c020001,
-0x8c426f1c, 0x10400006, 0x24040004, 0x24050001,
-0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8,
-0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff,
-0x3463ffff, 0x431024, 0x3c010002, 0x310821,
-0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c,
-0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
-0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100,
-0x3c010002, 0x310821, 0xac239004, 0x3c030001,
-0x3c010002, 0x310821, 0xac23900c, 0x10000015,
-0x34420400, 0x2021024, 0x10400008, 0x24030100,
-0x3c020001, 0x8c426f20, 0x3c010002, 0x310821,
-0xac239004, 0x1000000b, 0x34420800, 0x3c020080,
-0x2021024, 0x1040002e, 0x3c030001, 0x3c020001,
-0x8c426f20, 0x3c010002, 0x310821, 0xac23900c,
-0x34420c00, 0x3c010001, 0xac226f20, 0x10000025,
-0x24040001, 0x3c020020, 0x2021024, 0x10400006,
-0x24020100, 0x3c010002, 0x310821, 0xac229004,
-0x10000005, 0x3c020080, 0x3c010002, 0x310821,
-0xac209004, 0x3c020080, 0x2021024, 0x10400007,
-0x121940, 0x3c020001, 0x3c010002, 0x230821,
-0xac22900c, 0x10000006, 0x24040001, 0x121140,
-0x3c010002, 0x220821, 0xac20900c, 0x24040001,
-0x2821, 0x27b0001e, 0xc00457c, 0x2003021,
-0x24040001, 0x2821, 0xc00457c, 0x2003021,
-0x24040001, 0x24050001, 0x27b0001c, 0xc00457c,
-0x2003021, 0x24040001, 0x24050001, 0xc00457c,
-0x2003021, 0x10000077, 0x0, 0x3c02ffec,
-0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
-0x121140, 0x3c010002, 0x220821, 0xac308ff8,
-0x3c022000, 0x2021024, 0x10400009, 0x0,
-0x3c020001, 0x8c426e44, 0x14400005, 0x24020001,
-0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000,
-0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024,
-0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c,
-0xaf820238, 0x3c010001, 0xac206db0, 0x10600005,
-0x24022020, 0x3c010001, 0xac226f20, 0x24020001,
-0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
-0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98,
-0x3484ffff, 0x441024, 0x3c010002, 0x230821,
-0xac228ff0, 0x24020001, 0x10a20044, 0x0,
-0x10000040, 0x0, 0x3c020001, 0x8c426f1c,
-0x1040001c, 0x24022000, 0x3c010001, 0xac226f20,
-0x3c0300a0, 0x2031024, 0x14430005, 0x121140,
-0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20,
-0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020,
-0x621024, 0x10400004, 0x24022001, 0x3c010001,
-0x10000023, 0xac226f20, 0x3c020080, 0x621024,
-0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c,
-0xac226f20, 0x3c020020, 0x2021024, 0x10400007,
-0x121940, 0x24020100, 0x3c010002, 0x230821,
-0xac229004, 0x10000006, 0x3c020080, 0x121140,
-0x3c010002, 0x220821, 0xac209004, 0x3c020080,
-0x2021024, 0x10400006, 0x121940, 0x3c020001,
-0x3c010002, 0x230821, 0x10000005, 0xac22900c,
-0x121140, 0x3c010002, 0x220821, 0xac20900c,
-0x3c030001, 0x8c636d98, 0x24020001, 0x10620003,
-0x0, 0xc003daf, 0x0, 0x8fbf0030,
-0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
-0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c,
-0x9821, 0xafb50040, 0xa821, 0xafb10034,
-0x8821, 0x24020002, 0xafbf0048, 0xafbe0044,
-0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a,
-0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022,
-0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005,
-0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d,
-0x2201021, 0x24020004, 0x10a2020a, 0x24020008,
-0x10a20208, 0x2201021, 0x10000256, 0x0,
-0x8fa8002c, 0x88140, 0x3c030002, 0x701821,
-0x8c638ffc, 0x621024, 0x14400009, 0x24040001,
-0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002,
-0x300821, 0xac318ff4, 0x10000246, 0x2201021,
-0x24050001, 0xc00457c, 0x27a60018, 0x24040001,
-0x24050001, 0xc00457c, 0x27a60018, 0x97a20018,
-0x30420004, 0x104000d9, 0x3c114000, 0x3c020001,
-0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9,
-0x31080, 0x3c010001, 0x220821, 0x8c226c68,
-0x400008, 0x0, 0x24040001, 0x24050011,
-0x27b0001a, 0xc00457c, 0x2003021, 0x24040001,
-0x24050011, 0xc00457c, 0x2003021, 0x97a3001a,
-0x30624000, 0x10400002, 0x3c150010, 0x3c150008,
-0x30628000, 0x104000aa, 0x3c130001, 0x100000a8,
-0x3c130002, 0x24040001, 0x24050014, 0x27b0001a,
-0xc00457c, 0x2003021, 0x24040001, 0x24050014,
-0xc00457c, 0x2003021, 0x97a3001a, 0x30621000,
-0x10400002, 0x3c150010, 0x3c150008, 0x30620800,
-0x10400097, 0x3c130001, 0x10000095, 0x3c130002,
-0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
-0x2003021, 0x24040001, 0x24050019, 0xc00457c,
-0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
-0x10620027, 0x28620401, 0x1040000e, 0x24020200,
-0x1062001f, 0x28620201, 0x10400005, 0x24020100,
-0x5062001e, 0x3c130001, 0x1000001e, 0x24040001,
-0x24020300, 0x50620019, 0x3c130002, 0x10000019,
-0x24040001, 0x24020600, 0x1062000d, 0x28620601,
-0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
-0x10000010, 0x24040001, 0x24020700, 0x1462000d,
-0x24040001, 0x3c130004, 0x1000000a, 0x3c150008,
-0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
-0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
-0x24040001, 0x24050018, 0x27b0001e, 0xc00457c,
-0x2003021, 0x24040001, 0x24050018, 0xc00457c,
-0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140,
-0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022,
-0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010,
-0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b,
-0xafa20014, 0x3c020004, 0x16620010, 0x3c020001,
-0x8f840054, 0x24030001, 0x24020002, 0x3c010001,
-0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001,
-0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001,
-0xac246f30, 0x1000004f, 0x2b38825, 0x16620039,
-0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e,
-0x24040018, 0x2021, 0x2821, 0xc004ddb,
-0x34068000, 0x8f830054, 0x8f820054, 0x2b38825,
-0x10000002, 0x24630032, 0x8f820054, 0x621023,
-0x2c420033, 0x1440fffc, 0x0, 0x8f830054,
-0x24020001, 0x3c010001, 0xac226e20, 0x3c010001,
-0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001,
-0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001,
-0x1000002c, 0xac236f30, 0x2821, 0xc004ddb,
-0x24060404, 0x2021, 0x2405001e, 0x27a60018,
-0x24020002, 0xc0045be, 0xa7a20018, 0x2021,
-0x2821, 0x27a60018, 0xc0045be, 0xa7a00018,
-0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
-0x3c028000, 0x2221025, 0x2b31825, 0x10000015,
-0x438825, 0x2221025, 0x2751825, 0x438825,
-0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98,
-0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b,
-0xafb10014, 0x10000007, 0x0, 0x3c110002,
-0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff,
-0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e,
-0x0, 0x3c020001, 0x8c426f1c, 0x10400002,
-0x3c022000, 0x2228825, 0x8fa8002c, 0x81140,
-0x3c010002, 0x220821, 0x8c229000, 0x10400003,
-0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf,
-0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
-0x3c010002, 0x220821, 0x8c229008, 0x10400003,
-0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f,
-0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
-0x3c010002, 0x220821, 0xac318ff4, 0x10000135,
-0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002,
-0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024,
-0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff,
-0x628824, 0x3c010002, 0x3e0821, 0xac318ff0,
-0x10000124, 0x2201021, 0x2821, 0xc00457c,
-0x27a60018, 0x24040001, 0x2821, 0xc00457c,
-0x27a60018, 0x24040001, 0x24050001, 0x27b20020,
-0xc00457c, 0x2403021, 0x24040001, 0x24050001,
-0xc00457c, 0x2403021, 0x24040001, 0x24050004,
-0x27b1001e, 0xc00457c, 0x2203021, 0x24040001,
-0x24050004, 0xc00457c, 0x2203021, 0x24040001,
-0x24050005, 0x27b00022, 0xc00457c, 0x2003021,
-0x24040001, 0x24050005, 0xc00457c, 0x2003021,
-0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
-0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
-0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
-0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
-0x24040001, 0x24050018, 0xc00457c, 0x2203021,
-0x24040001, 0x24050018, 0xc00457c, 0x2203021,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
-0x97a20018, 0x30420004, 0x10400066, 0x3c114000,
-0x3c030001, 0x8c636f34, 0x24020005, 0x14620067,
-0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
-0x2003021, 0x24040001, 0x24050019, 0xc00457c,
-0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
-0x10620027, 0x28620401, 0x1040000e, 0x24020200,
-0x1062001f, 0x28620201, 0x10400005, 0x24020100,
-0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004,
-0x24020300, 0x50620019, 0x3c130002, 0x10000019,
-0x3c020004, 0x24020600, 0x1062000d, 0x28620601,
-0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
-0x10000010, 0x3c020004, 0x24020700, 0x1462000d,
-0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008,
-0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
-0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
-0x3c020004, 0x12620017, 0x3c028000, 0x8f820054,
-0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001,
-0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001,
-0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001,
-0x16620022, 0x2758825, 0x2021, 0x2821,
-0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b,
-0xac306e20, 0x2221025, 0x2b31825, 0x438825,
-0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001,
-0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010,
-0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001,
-0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007,
-0x0, 0x3c110002, 0x23e8821, 0x8e318ff0,
-0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001,
-0x8c426da8, 0x10400069, 0x0, 0x3c020001,
-0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825,
-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
-0x8c229004, 0x10400003, 0x3c020020, 0x10000005,
-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
-0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f,
-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b,
-0x2228824, 0x8fa8002c, 0x82940, 0x3c030002,
-0x651821, 0x8c638ff8, 0x3c024000, 0x621024,
-0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
-0x3c010002, 0x250821, 0xac318ff0, 0x10000041,
-0x2201021, 0x3c020001, 0x8c426da8, 0x10400034,
-0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c,
-0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b,
-0x21023, 0x441024, 0x10600003, 0x518825,
-0x3c022000, 0x2228825, 0x3c020002, 0x451021,
-0x8c429004, 0x10400003, 0x3c020020, 0x10000004,
-0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
-0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
-0x8c22900c, 0x10400003, 0x3c020080, 0x10000004,
-0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
-0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800,
-0x2228825, 0x3c020001, 0x8c426e34, 0x10400002,
-0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38,
-0x10400006, 0x3c020100, 0x10000004, 0x2228825,
-0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c,
-0x81140, 0x3c010002, 0x220821, 0xac318ff0,
-0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
-0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
-0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028,
-0x809021, 0xafbf002c, 0xafb10024, 0xafb00020,
-0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220,
-0x24020002, 0x1202005c, 0x2e020003, 0x10400005,
-0x24020001, 0x1202000a, 0x121940, 0x1000010c,
-0x0, 0x24020004, 0x120200bf, 0x24020008,
-0x120200be, 0x128940, 0x10000105, 0x0,
-0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002,
-0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024,
-0x10400038, 0x3c020008, 0x2021024, 0x10400020,
-0x34840002, 0x3c020002, 0x431021, 0x8c429000,
-0x10400005, 0x34840020, 0x34840100, 0x3c020020,
-0x10000006, 0x2028025, 0x2402feff, 0x822024,
-0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140,
-0x3c010002, 0x220821, 0x8c229008, 0x10400005,
-0x3c020001, 0xc23025, 0x3c020080, 0x10000016,
-0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024,
-0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024,
-0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff,
-0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024,
-0x3c010002, 0x230821, 0xac209000, 0x3c010002,
-0x230821, 0xac209008, 0xaf840200, 0xaf860220,
-0x8f820220, 0x34420002, 0xaf820220, 0x1000000a,
-0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200,
-0x2028024, 0x2402fffd, 0x621824, 0xc003daf,
-0xaf830200, 0x121140, 0x3c010002, 0x220821,
-0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c,
-0x10400069, 0x24050004, 0x24040001, 0xc00457c,
-0x27a60018, 0x24040001, 0x24050005, 0xc00457c,
-0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001,
-0x24846e48, 0x30630c00, 0x31a82, 0x30420c00,
-0x21282, 0xa7a2001a, 0x21080, 0x441021,
-0x431021, 0xa7a30018, 0x90480000, 0x24020001,
-0x3103ffff, 0x10620029, 0x28620002, 0x10400005,
-0x0, 0x10600009, 0x0, 0x1000003d,
-0x0, 0x10700013, 0x24020003, 0x1062002c,
-0x0, 0x10000037, 0x0, 0x8f820200,
-0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
-0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
-0x3c010002, 0xac209004, 0x3c010002, 0x10000032,
-0xac20900c, 0x8f820200, 0x34420100, 0xaf820200,
-0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
-0xaf820220, 0x24020100, 0x3c010002, 0xac229004,
-0x3c010002, 0x10000024, 0xac20900c, 0x8f820200,
-0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
-0x3c030001, 0x431025, 0xaf820220, 0x3c010002,
-0xac209004, 0x3c010002, 0x10000017, 0xac23900c,
-0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
-0x3c030001, 0x431025, 0xaf820220, 0x24020100,
-0x3c010002, 0xac229004, 0x3c010002, 0x1000000a,
-0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a,
-0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010,
-0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002,
-0x1000004b, 0xaf820200, 0x128940, 0x3c050002,
-0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021,
-0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010,
-0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
-0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200,
-0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024,
-0x3c010002, 0x310821, 0x10000031, 0xac308ff0,
-0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020,
-0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020,
-0xa21024, 0x10400007, 0x34840020, 0x24020100,
-0x3c010002, 0x310821, 0xac229004, 0x10000006,
-0x34840100, 0x3c010002, 0x310821, 0xac209004,
-0x2402feff, 0x822024, 0x3c020080, 0xa21024,
-0x10400007, 0x121940, 0x3c020001, 0x3c010002,
-0x230821, 0xac22900c, 0x10000008, 0xc23025,
-0x121140, 0x3c010002, 0x220821, 0xac20900c,
-0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200,
-0xaf860220, 0x8f820220, 0x34420002, 0xaf820220,
-0x121140, 0x3c010002, 0x220821, 0xac308ff0,
-0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
-0x3e00008, 0x27bd0030, 0x0, 0x1821,
-0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007,
-0x30420001, 0x10400004, 0x0, 0x8f820044,
-0x10000003, 0x34420040, 0x8f820044, 0x461024,
-0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
-0x8f820044, 0x451024, 0xaf820044, 0x24630001,
-0x28620008, 0x5440ffee, 0x641007, 0x3e00008,
-0x0, 0x2c820008, 0x1040001b, 0x0,
-0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001,
-0x24426e60, 0x621821, 0x24640004, 0x90620000,
-0x10400004, 0x0, 0x8f820044, 0x10000003,
-0x34420040, 0x8f820044, 0x461024, 0xaf820044,
-0x8f820044, 0x34420020, 0xaf820044, 0x8f820044,
-0x451024, 0xaf820044, 0x24630001, 0x64102b,
-0x1440ffee, 0x0, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x8f8400c4,
-0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824,
-0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008,
-0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004,
-0x14400012, 0x805021, 0x8ce90000, 0x8f42013c,
-0x1494823, 0x49182b, 0x94eb0006, 0x10600002,
-0x25630050, 0x494821, 0x123182b, 0x50400003,
-0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8,
-0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008,
-0x1021, 0x3e00008, 0x0, 0x8f8300e4,
-0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8,
-0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8,
-0x3e00008, 0xaf8200e4, 0x3e00008, 0x0,
-0x0, 0x0, 0x0, 0x8f880120,
-0x27624fe0, 0x8f830128, 0x15020002, 0x25090020,
-0x27694800, 0x11230012, 0x8fa20010, 0xad040000,
-0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
-0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
-0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc,
-0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc,
-0x8f430324, 0x1021, 0x24630001, 0x3e00008,
-0xaf430324, 0x3e00008, 0x0, 0x8f880100,
-0x276247e0, 0x8f830108, 0x15020002, 0x25090020,
-0x27694000, 0x1123000f, 0x8fa20010, 0xad040000,
-0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
-0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
-0xad020010, 0xad030014, 0xaf890100, 0x3e00008,
-0x24020001, 0x8f430328, 0x1021, 0x24630001,
-0x3e00008, 0xaf430328, 0x3e00008, 0x0,
+0x0,
+0x10000003, 0x0, 0xd, 0xd,
+0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000,
+0x26104000, 0xc0010c0, 0x0, 0xd,
+0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000,
+0x26104000, 0xc0017e0, 0x0, 0xd,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x2000008,
+0x0, 0x800172f, 0x3c0a0001, 0x800172f,
+0x3c0a0002, 0x800172f, 0x0, 0x8002cac,
+0x0, 0x8002c4f, 0x0, 0x800172f,
+0x3c0a0004, 0x800328a, 0x0, 0x8001a52,
+0x0, 0x800394d, 0x0, 0x80038f4,
+0x0, 0x800172f, 0x3c0a0006, 0x80039bb,
+0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f,
+0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6,
+0x0, 0x800172f, 0x3c0a000b, 0x800172f,
+0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb,
+0x0, 0x8002890, 0x0, 0x800172f,
+0x3c0a000e, 0x800208c, 0x0, 0x8001964,
+0x0, 0x8001a04, 0x0, 0x8003ca6,
+0x0, 0x8003c94, 0x0, 0x800172f,
+0x0, 0x800191a, 0x0, 0x800172f,
+0x0, 0x800172f, 0x3c0a0013, 0x800172f,
+0x3c0a0014, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x27bdffe0,
+0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140,
+0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20,
+0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc,
+0x401821, 0x3c020010, 0x3c010001, 0xac236e9c,
+0x10620011, 0x43102b, 0x14400002, 0x3c020020,
+0x3c020008, 0x1062000c, 0x24050100, 0x3c060001,
+0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020,
+0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001,
+0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4,
+0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe,
+0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002,
+0x24639010, 0x3c040001, 0x8c846cc4, 0x431023,
+0x14800002, 0x458021, 0x2610fa38, 0x2402f000,
+0x2028024, 0xc001785, 0x2002021, 0x2022823,
+0x3c040020, 0x821823, 0x651823, 0x247bb000,
+0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf,
+0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf,
+0x3463e000, 0x852023, 0x3c010001, 0xac246ea8,
+0x822023, 0x3c010001, 0xac256e90, 0x52842,
+0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001,
+0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823,
+0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac,
+0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011,
+0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
+0xc001749, 0x0, 0x3c020001, 0x8c426cd0,
+0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200,
+0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004,
+0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021,
+0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38,
+0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
+0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8,
+0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4,
+0x3c020001, 0x8c426cc8, 0x14400003, 0x0,
+0x3c010001, 0xac206cd0, 0xc001151, 0x0,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
+0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8,
+0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060,
+0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c,
+0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014,
+0x8f860040, 0x3c040001, 0x24845c80, 0x24050200,
+0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821,
+0x8f830040, 0x3c02f000, 0x621824, 0x3c026000,
+0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001,
+0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014,
+0x8f860040, 0x24050300, 0xc002b3b, 0x2003821,
+0x8f820240, 0x3c030001, 0x431025, 0xaf820240,
+0xaf800048, 0x8f820048, 0x14400005, 0x0,
+0xaf800048, 0x8f820048, 0x10400004, 0x0,
+0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c,
+0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8,
+0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001,
+0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001,
+0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001,
+0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001,
+0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001,
+0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c,
+0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138,
+0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150,
+0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140,
+0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014,
+0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014,
+0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0,
+0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014,
+0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac,
+0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c,
+0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff,
+0x1061824, 0xe81024, 0x43102b, 0x10400006,
+0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010,
+0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010,
+0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004,
+0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000,
+0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c,
+0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010,
+0xc002b3b, 0xafa30014, 0xaf800054, 0xaf80011c,
+0x8c020218, 0x30420002, 0x10400009, 0x0,
+0x8c020220, 0x3c030002, 0x34630004, 0x431025,
+0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004,
+0x8c020220, 0x3c030002, 0x34630006, 0x431025,
+0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014,
+0x8c020218, 0x30420010, 0x1040000a, 0x0,
+0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220,
+0x3c03000a, 0x34630004, 0x431025, 0x10000009,
+0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006,
+0x431025, 0xaf420008, 0x8c02021c, 0x34420006,
+0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0,
+0x8f830054, 0x8f820054, 0xaf8000d0, 0xaf8000c0,
+0x10000002, 0x24630064, 0x8f820054, 0x621023,
+0x2c420065, 0x1440fffc, 0x0, 0x8c040208,
+0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490,
+0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008,
+0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
+0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c,
+0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004,
+0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00,
+0x431024, 0x10400021, 0x0, 0x8f8200b4,
+0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001,
+0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c,
+0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001,
+0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x96e20472,
+0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482,
+0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b,
+0xafa20014, 0x96f00452, 0x32020001, 0x10400002,
+0xb021, 0x24160001, 0x32020002, 0x54400001,
+0x36d60002, 0x32020008, 0x54400001, 0x36d60004,
+0x32020010, 0x54400001, 0x36d60008, 0x32020020,
+0x54400001, 0x36d60010, 0x32020040, 0x54400001,
+0x36d60020, 0x32020080, 0x54400001, 0x36d60040,
+0x96e60482, 0x30c20200, 0x54400001, 0x36d64000,
+0x96e30472, 0x30620200, 0x10400003, 0x30620100,
+0x10000003, 0x36d62000, 0x54400001, 0x36d61000,
+0x96f00462, 0x32c24000, 0x14400004, 0x3207009b,
+0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000,
+0x1440000d, 0x32020001, 0x3062009b, 0x10e20009,
+0x240e0001, 0x3c040001, 0x24845d20, 0x24051300,
+0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b,
+0xafa00014, 0x32020001, 0x54400001, 0x36d60080,
+0x32020002, 0x54400001, 0x36d60100, 0x32020008,
+0x54400001, 0x36d60200, 0x32020010, 0x54400001,
+0x36d60400, 0x32020080, 0x54400001, 0x36d60800,
+0x8c020218, 0x30420200, 0x10400002, 0x3c020008,
+0x2c2b025, 0x8c020218, 0x30420800, 0x10400002,
+0x3c020080, 0x2c2b025, 0x8c020218, 0x30420400,
+0x10400002, 0x3c020100, 0x2c2b025, 0x8c020218,
+0x30420100, 0x10400002, 0x3c020200, 0x2c2b025,
+0x8c020218, 0x30420080, 0x10400002, 0x3c020400,
+0x2c2b025, 0x8c020218, 0x30422000, 0x10400002,
+0x3c020010, 0x2c2b025, 0x8c020218, 0x30424000,
+0x10400002, 0x3c020020, 0x2c2b025, 0x8c020218,
+0x30421000, 0x10400002, 0x3c020040, 0x2c2b025,
+0x8ee20498, 0x8ee3049c, 0xaf420160, 0xaf430164,
+0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c,
+0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174,
+0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c,
+0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184,
+0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c,
+0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194,
+0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c,
+0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4,
+0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8,
+0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c,
+0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
+0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a,
+0x3484ca00, 0x3821, 0x24020006, 0x24030002,
+0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200,
+0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290,
+0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8,
+0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f,
+0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001,
+0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c,
+0x24051400, 0x21702, 0x24420030, 0xa062022c,
+0x3471021, 0xa040022c, 0x8c070218, 0x2c03021,
+0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014,
+0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80,
+0x24060010, 0x27b10030, 0x2203821, 0x27b30034,
+0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8,
+0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00,
+0x8fa20034, 0x246400ff, 0x852024, 0x831823,
+0x431023, 0xafa20034, 0xafa40030, 0x3c040001,
+0x24845d44, 0x3c050000, 0x24a54100, 0x24060108,
+0x2203821, 0xc0017a3, 0xafb30010, 0x409021,
+0x32c20003, 0x3c010001, 0xac326e80, 0x10400045,
+0x2203821, 0x8f820050, 0x3c030010, 0x431024,
+0x10400016, 0x0, 0x8c020218, 0x30420040,
+0x1040000f, 0x24020001, 0x8f820050, 0x8c030218,
+0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f,
+0xafa20010, 0xafa30014, 0x8f870040, 0x24051500,
+0xc002b3b, 0x2c03021, 0x10000004, 0x0,
+0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
+0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001,
+0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030,
+0x2603821, 0x27b10034, 0x34420a00, 0xaf420010,
+0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70,
+0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90,
+0xc53023, 0x2603821, 0xaf420108, 0xc0017a3,
+0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001,
+0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023,
+0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3,
+0xafb10010, 0x3c040001, 0x24845da4, 0x10000024,
+0x24051600, 0x3c040001, 0x24845dac, 0x3c050001,
+0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023,
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc,
+0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c,
+0xc53023, 0x2203821, 0xaf420108, 0xc0017a3,
+0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001,
+0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023,
+0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3,
+0xafb30010, 0x3c040001, 0x24845de4, 0x24051650,
+0x2c03021, 0x3821, 0x3c010001, 0xac226ef8,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020,
+0x10400021, 0x27a70030, 0x3c040001, 0x24845df0,
+0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8,
+0xc53023, 0x24022000, 0xaf42001c, 0x27a20034,
+0xc0017a3, 0xafa20010, 0x21900, 0x31982,
+0x3c040800, 0x641825, 0xae430028, 0x24030010,
+0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040,
+0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010,
+0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0,
+0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c,
+0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001,
+0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10,
+0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c,
+0x24051700, 0xc002b3b, 0x3821, 0x3c020000,
+0x24425cbc, 0x21100, 0x21182, 0x3c030800,
+0x431025, 0xae420028, 0x24020008, 0xaf42003c,
+0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001,
+0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c,
+0x24051800, 0x32c60020, 0xc002b3b, 0x0,
+0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff,
+0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800,
+0x651824, 0x31882, 0x641825, 0x451024,
+0x21082, 0x441025, 0xacc20080, 0x32c20180,
+0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080,
+0x431024, 0x1040000d, 0x0, 0x8f820050,
+0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001,
+0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040,
+0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050,
+0x3c030010, 0x431024, 0x10400016, 0x0,
+0x8c020218, 0x30420040, 0x1040000f, 0x24020001,
+0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001,
+0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014,
+0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021,
+0x10000004, 0x0, 0x3c010001, 0x370821,
+0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001,
+0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023,
+0x8f420008, 0x27b30030, 0x2603821, 0x27b10034,
+0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010,
+0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4,
+0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821,
+0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001,
+0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001,
+0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001,
+0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001,
+0x24845e7c, 0x10000027, 0x24052100, 0x3c040001,
+0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001,
+0x24c6a104, 0xc53023, 0x27b10030, 0x2203821,
+0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001,
+0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001,
+0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c,
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4,
+0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4,
+0xc53023, 0x2203821, 0x3c010001, 0xac226f04,
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8,
+0x24052150, 0x2c03021, 0x3821, 0x3c010001,
+0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014,
+0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff,
+0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800,
+0x711824, 0x31882, 0x6e1825, 0x511024,
+0x21082, 0x4e1025, 0xae630038, 0xae620078,
+0x8c020218, 0x30420040, 0x14400004, 0x24020001,
+0x3c010001, 0x370821, 0xa02240f4, 0x3c040001,
+0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001,
+0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821,
+0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001,
+0xac226efc, 0x511024, 0x21082, 0x3c0e0800,
+0x4e1025, 0xae620050, 0x32c22000, 0x10400006,
+0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024,
+0x1000000f, 0x21082, 0x3c040001, 0x24845ed8,
+0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4,
+0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001,
+0xac226f14, 0x511024, 0x21082, 0x3c0e0800,
+0x4e1025, 0xae620048, 0x32c24000, 0x10400005,
+0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e,
+0x21100, 0x3c040001, 0x24845ef0, 0x3c050001,
+0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023,
+0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001,
+0xac226f08, 0x21100, 0x21182, 0x3c030800,
+0x431025, 0xae420060, 0x3c040001, 0x24845f08,
+0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650,
+0xc53023, 0x27b10030, 0x2203821, 0x27b30034,
+0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff,
+0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468,
+0x3c060000, 0x24c66588, 0xc53023, 0x2203821,
+0x240f021, 0x3c010001, 0xac226edc, 0x4e1024,
+0x21082, 0x3c150800, 0x551025, 0xafae0044,
+0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001,
+0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000,
+0x24c66808, 0x8fae0044, 0xc53023, 0x2203821,
+0x3c010001, 0xac226ed0, 0x4e1024, 0x21082,
+0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010,
+0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810,
+0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023,
+0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024,
+0x21082, 0x551025, 0xafc200c0, 0xc0017a3,
+0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001,
+0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044,
+0xc53023, 0x2203821, 0x3c010001, 0xac226ed4,
+0x4e1024, 0x21082, 0x551025, 0xafc200c8,
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c,
+0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20,
+0xc53023, 0x2203821, 0xaf420110, 0xc0017a3,
+0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001,
+0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023,
+0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010,
+0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80,
+0x3c060001, 0x24c65aac, 0xc53023, 0x2203821,
+0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010,
+0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298,
+0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821,
+0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044,
+0x3c010001, 0xac226f18, 0x4e1024, 0x21082,
+0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40,
+0x0, 0xc0027a8, 0x0, 0xac000228,
+0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038,
+0x96e20460, 0xaf420080, 0x32c24000, 0x14400003,
+0x0, 0x96e20480, 0xaf420084, 0x96e70490,
+0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088,
+0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000,
+0x10400003, 0x24020400, 0x10e2000b, 0x0,
+0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f,
+0x96e60490, 0x24052170, 0x2c03821, 0xafa00010,
+0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138,
+0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098,
+0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084,
+0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200,
+0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58,
+0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0,
+0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c,
+0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff,
+0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010,
+0x3c010001, 0xac226eb8, 0x21100, 0x21182,
+0x511025, 0xc0018fc, 0xae420000, 0x8f820240,
+0x3c030001, 0x431025, 0xaf820240, 0x3c020000,
+0x24424034, 0xaf820244, 0xaf800240, 0x8f820060,
+0x511024, 0x14400005, 0x3c030800, 0x8f820060,
+0x431024, 0x1040fffd, 0x0, 0xc003c4d,
+0x8821, 0x3c020100, 0xafa20020, 0x8f530018,
+0x240200ff, 0x56620001, 0x26710001, 0x8c020228,
+0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0xc01821, 0x8f440178, 0x8f45017c, 0x1021,
+0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c,
+0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x1440000b, 0x24070008,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020,
+0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164,
+0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010,
+0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400010, 0x0,
+0x8f420340, 0x24420001, 0xaf420340, 0x8f420340,
+0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020,
+0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4,
+0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f,
+0x10400069, 0x3c020700, 0x34423000, 0xafa20028,
+0x8f530018, 0x240200ff, 0x12620002, 0x8821,
+0x26710001, 0x8c020228, 0x1622000e, 0x1330c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f,
+0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009,
+0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018,
+0x8f860120, 0x24020010, 0xafa20010, 0xafb10014,
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400010, 0x0, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009,
+0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b,
+0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0,
+0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010,
+0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b,
+0x3821, 0x10000004, 0x0, 0x8c020264,
+0x10400005, 0x0, 0x8f8200a0, 0x30420004,
+0x1440fffa, 0x0, 0x8f820044, 0x34420004,
+0xaf820044, 0x8f420308, 0x24420001, 0xaf420308,
+0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023,
+0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81,
+0x10400006, 0x24020001, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x24020001, 0xaf42008c,
+0x32c20008, 0x10400006, 0x0, 0x8f820214,
+0x3c038100, 0x3042ffff, 0x431025, 0xaf820214,
+0x3c030001, 0x8c636d94, 0x30620002, 0x10400009,
+0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000,
+0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012,
+0xc53023, 0x10400009, 0x0, 0x3c040001,
+0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000,
+0x24c67678, 0x10000008, 0xc53023, 0x3c040001,
+0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000,
+0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034,
+0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc,
+0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100,
+0x21182, 0x431025, 0xae420040, 0x8f8200a0,
+0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c,
+0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001,
+0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001,
+0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001,
+0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b,
+0x24052400, 0x8f820200, 0xafa20010, 0x8f820220,
+0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001,
+0x24846008, 0xc002b3b, 0x24052500, 0x8f830060,
+0x74100b, 0x242000a, 0x200f821, 0x0,
+0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058,
+0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048,
+0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001,
+0x24846014, 0x24052600, 0x3021, 0x3821,
+0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x3e00008, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x3e00008, 0x0, 0x3e00008, 0x0,
+0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef,
+0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff,
+0xafa40018, 0xa22823, 0xa32824, 0x8ca20000,
+0x1044000a, 0x0, 0xafa50010, 0x8ca20000,
+0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001,
+0x2484601c, 0xc002b3b, 0x24052700, 0x8fbf0218,
+0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba,
+0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f,
+0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000,
+0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000,
+0xaca30000, 0x10460005, 0xae040000, 0xa08021,
+0xf0102b, 0x1040fff5, 0x102840, 0x3c040001,
+0x24846028, 0x24052800, 0x2003021, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021,
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020,
+0x8c020224, 0x3047003f, 0x10e00010, 0x803021,
+0x2821, 0x24030020, 0xe31024, 0x10400002,
+0x63042, 0xa62821, 0x31842, 0x1460fffb,
+0xe31024, 0x2402f000, 0xa22824, 0x3402ffff,
+0x45102b, 0x14400003, 0x3c020001, 0x10000008,
+0x3c020001, 0x3442ffff, 0x851823, 0x43102b,
+0x14400003, 0xa01021, 0x3c02fffe, 0x821021,
+0x3e00008, 0x0, 0x27bdffd0, 0xafb50028,
+0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c,
+0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018,
+0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b,
+0x1440001b, 0xe08821, 0x8e330000, 0xafb00010,
+0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000,
+0xc002b3b, 0x2403021, 0x8e230000, 0x702021,
+0x64102b, 0x10400007, 0x2402821, 0x8ca20000,
+0xac620000, 0x24630004, 0x64102b, 0x1440fffb,
+0x24a50004, 0x8ea20000, 0x501023, 0xaea20000,
+0x8e220000, 0x501021, 0x1000000b, 0xae220000,
+0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000,
+0x2409821, 0xafa20014, 0x8e270000, 0x24053100,
+0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c,
+0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8,
+0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84,
+0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc,
+0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001,
+0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0,
+0xac201ffc, 0x431023, 0x441023, 0x245bb000,
+0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021,
+0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0,
+0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0,
+0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001,
+0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d,
+0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200,
+0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4,
+0x3021, 0x3603821, 0xafbf0030, 0xafb3002c,
+0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c,
+0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014,
+0xc001916, 0x0, 0x8f820240, 0x34420004,
+0xaf820240, 0x24020001, 0xaf420000, 0x3c020001,
+0x571021, 0x904240f4, 0x10400092, 0x2403fffc,
+0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c,
+0x2121023, 0x438024, 0x8fa3001c, 0x3c040001,
+0x24846040, 0x70102b, 0x1440001a, 0x27b30018,
+0x8fb10018, 0x24053000, 0x2403021, 0xafb00010,
+0xafa30014, 0xc002b3b, 0x2203821, 0x8fa30018,
+0x702021, 0x64102b, 0x10400007, 0x2403021,
+0x8cc20000, 0xac620000, 0x24630004, 0x64102b,
+0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023,
+0xafa2001c, 0x8e620000, 0x501021, 0x1000000a,
+0xae620000, 0x2408821, 0x24053100, 0xafb00010,
+0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d,
+0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c,
+0x3c040001, 0x2484605c, 0x24120020, 0x3c010001,
+0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018,
+0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50,
+0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
+0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020,
+0x65102b, 0x10400007, 0x0, 0x8c820000,
+0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+0x3c100001, 0x26106f50, 0x24053100, 0xafa70010,
+0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001,
+0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001,
+0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018,
+0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70,
+0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821,
+0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020,
+0x65102b, 0x10400007, 0x0, 0x8c820000,
+0xac620000, 0x24630004, 0x65102b, 0x1440fffb,
+0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c,
+0x8e220000, 0x521021, 0x1000000b, 0xae220000,
+0x3c100001, 0x26106f70, 0x24053100, 0xafa70010,
+0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d,
+0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031,
+0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001,
+0x2652809c, 0x2121023, 0x438024, 0x8fa3001c,
+0x3c040001, 0x24846084, 0x70102b, 0x1440001a,
+0x27b30018, 0x8fb10018, 0x24053000, 0x2403021,
+0xafb00010, 0xafa30014, 0xc002b3b, 0x2203821,
+0x8fa30018, 0x702021, 0x64102b, 0x10400007,
+0x2403021, 0x8cc20000, 0xac620000, 0x24630004,
+0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c,
+0x501023, 0xafa2001c, 0x8e620000, 0x501021,
+0x1000000a, 0xae620000, 0x2408821, 0x24053100,
+0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021,
+0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001,
+0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400,
+0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0038, 0x0, 0x0, 0x8f820040,
+0x3c03f000, 0x431024, 0x3c036000, 0x14430006,
+0x0, 0x8f820050, 0x2403ff80, 0x431024,
+0x34420055, 0xaf820050, 0x8f820054, 0x244203e8,
+0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004,
+0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4,
+0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008,
+0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008,
+0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054,
+0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024,
+0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024,
+0x36940040, 0x3c020001, 0x8c426da8, 0x10400017,
+0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016,
+0x282a025, 0x3c020001, 0x8c426e44, 0x14400012,
+0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003,
+0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002,
+0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf,
+0x0, 0x10000004, 0x3c020200, 0xc004196,
+0x0, 0x3c020200, 0x2c21024, 0x10400003,
+0x0, 0xc001f4b, 0x0, 0x8f4200d8,
+0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b,
+0x14400003, 0x0, 0xaf4000d8, 0x36940080,
+0x8c030238, 0x1060000c, 0x0, 0x8f4201b0,
+0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006,
+0x0, 0x934205c5, 0x14400003, 0x0,
+0xc001da0, 0x0, 0x8fbf0010, 0x3e00008,
+0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8,
+0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059,
+0x0, 0x3c020001, 0x571021, 0x904240f0,
+0x10400026, 0x24070008, 0x8f440170, 0x8f450174,
+0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010,
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
+0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
+0x370821, 0xa02240f0, 0x8f820124, 0xafa20010,
+0x8f820128, 0x3c040001, 0x24846128, 0xafa20014,
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
+0x34a50900, 0x1000005c, 0x0, 0x8f420300,
+0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c,
+0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f1,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120,
+0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036,
+0x0, 0x8f420300, 0x8f43002c, 0x24420001,
+0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+0xaf430038, 0x3c010001, 0x370821, 0xa02040f1,
+0x3c010001, 0x370821, 0xa02040f0, 0x10000026,
+0xaf400034, 0x934205c1, 0x1040001d, 0x0,
+0xa34005c1, 0x8f820040, 0x30420001, 0x14400008,
+0x2021, 0x8c030104, 0x24020001, 0x50620005,
+0x24040001, 0x8c020264, 0x10400003, 0x801021,
+0x24040001, 0x801021, 0x10400006, 0x0,
+0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008,
+0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
+0x8f420308, 0x24420001, 0xaf420308, 0x8f420308,
+0x3c010001, 0x370821, 0xa02040f0, 0x3c010001,
+0x370821, 0xa02040f1, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x10000002,
+0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8,
+0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029,
+0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c,
+0x8f860120, 0x24020040, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044,
+0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300,
+0x1000000f, 0x0, 0x8f420304, 0x24420001,
+0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c,
+0x3c010001, 0x370821, 0xa02040f2, 0x10000004,
+0xaf400078, 0x3c010001, 0x370821, 0xa02040f2,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x3c03feff, 0x3463ffff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
+0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8,
+0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044,
+0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5,
+0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b,
+0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002,
+0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001,
+0x8c636d98, 0x34420002, 0xaf420004, 0x24020001,
+0x14620003, 0x3c020600, 0x10000002, 0x34423000,
+0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034,
+0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff,
+0x11420002, 0x1821, 0x25430001, 0x8c020228,
+0x609821, 0x1662000e, 0x3c050009, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014,
+0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500,
+0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020,
+0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054,
+0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9,
+0x1040001b, 0xa821, 0xe09021, 0x265e04c0,
+0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004,
+0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021,
+0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008,
+0xa32821, 0xa3482b, 0x822021, 0x100f809,
+0x892021, 0x54400006, 0x24150001, 0x8f820054,
+0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0,
+0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24846118, 0xafa20014, 0x8d460000,
+0x3c050009, 0x10000035, 0x34a50600, 0x8f420308,
+0x24150001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054,
+0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016,
+0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c,
+0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010,
+0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c,
+0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
+0x0, 0x8f820054, 0x2221023, 0x2c4203e9,
+0x1440ffee, 0x0, 0x32a200ff, 0x14400011,
+0x3c050009, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
+0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec,
+0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029,
+0x36100040, 0x3c020400, 0x2c21024, 0x10400013,
+0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4,
+0x14640006, 0x36100040, 0x8f420270, 0x8f430274,
+0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250,
+0x8f430254, 0x8f440270, 0x8f450274, 0x10000012,
+0x3a100020, 0x1000002b, 0x2028024, 0x8f420250,
+0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024,
+0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021,
+0x36100040, 0x8f420250, 0x8f430254, 0x8f440270,
+0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019,
+0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011,
+0x28420033, 0x8f420004, 0x30420001, 0x10400009,
+0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf,
+0x2028024, 0x1000000b, 0x36100040, 0x10000009,
+0x36100060, 0x8f4200d4, 0x36100040, 0x24430001,
+0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4,
+0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024,
+0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044,
+0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008,
+0x27bd0058, 0x3e00008, 0x0, 0x3c020001,
+0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001,
+0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004,
+0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004,
+0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004,
+0x24020001, 0x14620003, 0x3c020600, 0x10000002,
+0x34423000, 0x34421000, 0xafa20020, 0x1821,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000035, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016,
+0x9821, 0x3c150020, 0x24110010, 0x8f42000c,
+0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010,
+0xafb20014, 0x551025, 0xafa20018, 0x8f42010c,
+0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3,
+0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffee, 0x0, 0x326200ff, 0x14400011,
+0x0, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846120, 0x3c050009,
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
+0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec,
+0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018,
+0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4,
+0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270,
+0x8f430274, 0x8f4401b8, 0x10640021, 0x0,
+0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0,
+0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4,
+0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0,
+0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001,
+0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001,
+0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001,
+0x8f420004, 0x30420001, 0x10400008, 0x0,
+0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1,
+0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4,
+0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5,
+0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1,
+0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1,
+0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c,
+0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001,
+0x5462001f, 0x2021, 0x3c020001, 0x90426cf0,
+0x1443001b, 0x24040005, 0x10000019, 0x24040006,
+0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b,
+0x24020001, 0x3c030001, 0x90636cf1, 0x54620010,
+0x2021, 0x3c020001, 0x90426cf0, 0x1443000c,
+0x24040003, 0x1000000a, 0x24040004, 0x3c030001,
+0x90636cf1, 0x14620006, 0x2021, 0x3c020001,
+0x90426cf0, 0x24040001, 0x50440001, 0x24040002,
+0xc00565a, 0x0, 0x2402ff7f, 0x282a024,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x3e00008, 0x0, 0x3c020001,
+0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001,
+0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8,
+0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002,
+0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002,
+0xaf420004, 0x24020001, 0x14820003, 0x3c020600,
+0x10000002, 0x34423000, 0x34421000, 0xafa20020,
+0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff,
+0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228,
+0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c,
+0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228,
+0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014,
+0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500,
+0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0,
+0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8,
+0x2021023, 0x2c4203e9, 0x1040001b, 0x9821,
+0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c,
+0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014,
+0x8f48000c, 0x1021, 0x2f53021, 0xafa80018,
+0x8f48010c, 0x24070008, 0xa32821, 0xa3482b,
+0x822021, 0x100f809, 0x892021, 0x54400006,
+0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffe9, 0x0, 0x326200ff, 0x54400017,
+0xaf520018, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846118, 0x3c050009,
+0xafa20014, 0x8d460000, 0x10000035, 0x34a50600,
+0x8f420308, 0x24130001, 0x24420001, 0xaf420308,
+0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054,
+0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9,
+0x10400016, 0x9821, 0x3c150020, 0x24110010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb10010, 0xafb20014, 0x551025, 0xafa20018,
+0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c,
+0x1440ffe3, 0x0, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff,
+0x14400011, 0x0, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846120,
+0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700,
+0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001,
+0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001,
+0x10400033, 0x3c020400, 0x2c21024, 0x10400017,
+0x0, 0x934205c0, 0x8f440250, 0x8f450254,
+0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0,
+0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008,
+0x0, 0x8f420250, 0x8f430254, 0x934405c0,
+0x8f460270, 0x8f470274, 0x10000016, 0x38840040,
+0x934205c0, 0x10000048, 0x304200bf, 0x934205c0,
+0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf,
+0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274,
+0x8f4401b8, 0x1064000b, 0x0, 0x8f420250,
+0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274,
+0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033,
+0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020,
+0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0,
+0x24620001, 0x10000023, 0x28630033, 0x8f4200e4,
+0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a,
+0x14400006, 0x24030001, 0x8f4200e8, 0x14430002,
+0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004,
+0x30420001, 0x1040000d, 0x3c020400, 0x2c21024,
+0x10400007, 0x0, 0x934205c0, 0x34420040,
+0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df,
+0x934205c0, 0x1000000c, 0x34420060, 0x934205c0,
+0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001,
+0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0,
+0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0,
+0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001,
+0x14620005, 0x0, 0x934405c0, 0x42102,
+0x10000003, 0x348400f0, 0x934405c0, 0x3484000f,
+0xc005640, 0x0, 0x2402ff7f, 0x282a024,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0,
+0x274401c0, 0x26e30028, 0x24650400, 0x65102b,
+0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c,
+0xafb20038, 0xafb10034, 0x10400007, 0xafb00030,
+0x8c820000, 0xac620000, 0x24630004, 0x65102b,
+0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044,
+0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030,
+0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240,
+0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248,
+0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250,
+0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258,
+0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260,
+0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268,
+0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270,
+0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034,
+0x41080, 0x571021, 0x8ee30034, 0x8c42023c,
+0x24840001, 0x621821, 0x2c82000f, 0xaee30034,
+0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048,
+0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8,
+0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200,
+0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208,
+0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b,
+0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4,
+0x24040001, 0x24050000, 0x651821, 0x65302b,
+0x441021, 0x461021, 0xaee200c0, 0xaee300c4,
+0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff,
+0x24090000, 0x401821, 0x1021, 0x882024,
+0xa92824, 0x822025, 0xa32825, 0xaee400c0,
+0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4,
+0x45102b, 0x1040000b, 0x0, 0x8ee200d0,
+0x8ee300d4, 0x24040001, 0x24050000, 0x651821,
+0x65302b, 0x441021, 0x461021, 0xaee200d0,
+0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4,
+0x401821, 0x1021, 0x882024, 0xa92824,
+0x822025, 0xa32825, 0xaee400d0, 0xaee500d4,
+0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b,
+0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc,
+0x24040001, 0x24050000, 0x651821, 0x65302b,
+0x441021, 0x461021, 0xaee200c8, 0xaee300cc,
+0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821,
+0x1021, 0x882024, 0xa92824, 0x822025,
+0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc,
+0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208,
+0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028,
+0x40f809, 0x24070400, 0x104000f0, 0x3c020400,
+0xafa20020, 0x934205c6, 0x10400089, 0x1821,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa002c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24846118, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+0x326200ff, 0x54400012, 0x24020001, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24846120, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002b3b, 0x3c03821, 0x1021,
+0x1440005b, 0x24020001, 0x10000065, 0x0,
+0x8f510018, 0x240200ff, 0x12220002, 0x8021,
+0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
+0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x54400011, 0x24020001, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846104, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
+0x2203821, 0x1021, 0x1040000d, 0x24020001,
+0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001,
+0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001,
+0xaee20150, 0x10000003, 0x8ee20150, 0x24020001,
+0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020,
+0x8f8200b0, 0x30420004, 0x10400068, 0x0,
+0x8f430128, 0x8f820104, 0x14620005, 0x0,
+0x8f430130, 0x8f8200b4, 0x10620006, 0x0,
+0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b,
+0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024,
+0x1040000d, 0x0, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024,
+0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024,
+0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104,
+0x14620005, 0x0, 0x8f430130, 0x8f8200b4,
+0x10620010, 0x0, 0x8f820104, 0xaf420128,
+0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010,
+0x8f420130, 0x3c040001, 0x24846144, 0xafa20014,
+0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031,
+0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130,
+0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c,
+0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000,
+0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104,
+0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008,
+0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c,
+0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c,
+0x26e60028, 0x40f809, 0x24070400, 0x8f82011c,
+0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
+0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128,
+0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c,
+0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005,
+0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0,
+0x30420004, 0x10400069, 0x0, 0x8f43012c,
+0x8f820124, 0x14620005, 0x0, 0x8f430134,
+0x8f8200a4, 0x10620006, 0x0, 0x8f820124,
+0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134,
+0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d,
+0x0, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0,
+0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b,
+0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005,
+0x0, 0x8f430134, 0x8f8200a4, 0x10620010,
+0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4,
+0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134,
+0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c,
+0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200,
+0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001,
+0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0,
+0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c,
+0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0,
+0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124,
+0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208,
+0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001,
+0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c,
+0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc,
+0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c,
+0xafa20010, 0x8f420134, 0x3c040001, 0x24846180,
+0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005,
+0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020,
+0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001,
+0x3c060080, 0x3c050100, 0x8f820070, 0x481024,
+0x1040fffd, 0x0, 0x8f820054, 0x24420005,
+0xaf820078, 0x8c040234, 0x10800016, 0x1821,
+0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
+0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
+0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
+0x0, 0x3c030080, 0x3c010001, 0x370821,
+0xac2040e8, 0x3c010001, 0x370821, 0x1000000b,
+0xa02740f0, 0x3c020001, 0x571021, 0x904240f0,
+0x54400006, 0x661825, 0x3c020001, 0x571021,
+0x904240f1, 0x54400001, 0x661825, 0x8c040230,
+0x10800013, 0x0, 0x3c020001, 0x571021,
+0x8c4240ec, 0x24420005, 0x3c010001, 0x370821,
+0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec,
+0x44102b, 0x14400006, 0x0, 0x3c010001,
+0x370821, 0xac2040ec, 0x10000006, 0x651825,
+0x3c020001, 0x571021, 0x904240f2, 0x54400001,
+0x651825, 0x1060ffbc, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x431025, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x1000ffa7, 0xaf80004c,
+0x1000ffa5, 0xaf800048, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x27bdffe0,
+0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025,
+0x24040004, 0x8c020114, 0xaf420020, 0xaf840064,
+0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc,
+0x8f820064, 0x30420004, 0x14400005, 0x0,
+0x8c030114, 0x8f420020, 0x1462fff2, 0x0,
+0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x431025, 0xaf820060,
+0x8f420000, 0x10400073, 0x0, 0x1000006f,
+0x0, 0x30c20008, 0x10400020, 0x24040008,
+0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8,
+0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064,
+0x30420008, 0x14400005, 0x0, 0x8c03011c,
+0x8f420048, 0x1462fff2, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020,
+0x10400023, 0x24040020, 0x8c02012c, 0xaf420068,
+0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8,
+0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005,
+0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2,
+0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x1000ffb4, 0x34420800,
+0x30c20010, 0x10400029, 0x24040010, 0x8c020124,
+0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001,
+0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010,
+0x14400005, 0x32c22000, 0x8c030124, 0x8f420058,
+0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x34420100, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x1000006c,
+0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001,
+0x10400004, 0x24020001, 0xaf820064, 0x10000064,
+0x0, 0x30c20002, 0x1440000b, 0x3c050003,
+0x3c040001, 0x24846244, 0x34a50500, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0,
+0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c,
+0x10a20048, 0x51080, 0x8c460300, 0x24a20001,
+0x3045003f, 0x24020003, 0xac05022c, 0x61e02,
+0x10620005, 0x24020010, 0x1062001d, 0x30c20fff,
+0x10000039, 0x0, 0x8f4302a8, 0x8f440000,
+0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8,
+0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420200, 0xaf820060, 0x8f420000,
+0x1040001f, 0x0, 0x1000001b, 0x0,
+0xaf420058, 0x32c22000, 0x50400001, 0x36d68000,
+0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4,
+0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x34420100, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000006, 0xaf80004c,
+0x10000004, 0xaf800048, 0xc002196, 0xc02021,
+0x402821, 0x8c02010c, 0x14a20002, 0x24020002,
+0xaf820064, 0x8f820064, 0x30420002, 0x14400004,
+0x0, 0x8c02010c, 0x14a2ffac, 0x0,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x27bdffa0, 0xafb00040, 0x808021,
+0x101602, 0x2442ffff, 0x304300ff, 0x2c620013,
+0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c,
+0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034,
+0x31080, 0x3c010001, 0x220821, 0x8c226288,
+0x400008, 0x0, 0x101302, 0x30440fff,
+0x24020001, 0x10820005, 0x24020002, 0x1082000c,
+0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004,
+0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204,
+0x3c040001, 0x8c846e80, 0x10000009, 0x34630001,
+0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001,
+0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28,
+0x21100, 0x21182, 0xaf430004, 0x3c030800,
+0x431025, 0xac820038, 0x8f840054, 0x41442,
+0x41c82, 0x431021, 0x41cc2, 0x431023,
+0x41d02, 0x431021, 0x41d42, 0x431023,
+0x10000009, 0xaf420208, 0x3c040001, 0x24846250,
+0x34a51000, 0x2003021, 0x3821, 0xafa00010,
+0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001,
+0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028,
+0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
+0xc002518, 0x2002021, 0x10000216, 0x0,
+0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
+0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
+0x21080, 0x8c430300, 0x25420001, 0x3042003f,
+0xafa20034, 0xac02022c, 0xafa50028, 0xc002518,
+0xafa3002c, 0x10000203, 0x0, 0x27b00028,
+0x2002021, 0x24050210, 0xc002bbf, 0x24060008,
+0xc002657, 0x2002021, 0x100001fa, 0x0,
+0x8faa0034, 0x27a40028, 0xa1880, 0x25420001,
+0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034,
+0x21080, 0x8c430300, 0x25420001, 0x3042003f,
+0xafa20034, 0xac02022c, 0xafa50028, 0xc002657,
+0xafa3002c, 0x100001e7, 0x0, 0x101302,
+0x30430fff, 0x24020001, 0x10620005, 0x24020002,
+0x1062001e, 0x3c020002, 0x10000033, 0x3c050003,
+0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025,
+0x8f820228, 0x3c010001, 0x370821, 0xac2238d8,
+0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc,
+0x8f820230, 0x3c010001, 0x370821, 0xac2238e0,
+0x8f820234, 0x3c010001, 0x370821, 0xac2238e4,
+0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230,
+0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024,
+0x10400012, 0x3c02fffd, 0x3c020001, 0x571021,
+0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021,
+0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021,
+0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021,
+0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff,
+0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c,
+0x34a51100, 0x2003021, 0x3821, 0xafa00010,
+0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001,
+0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302,
+0x30450fff, 0x24020001, 0x10a20005, 0x24020002,
+0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003,
+0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004,
+0x2c4b025, 0x621824, 0x34630008, 0xaf830220,
+0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb,
+0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024,
+0xaf820220, 0x10000009, 0xaf450298, 0x3c040001,
+0x24846268, 0x34a51200, 0x2003021, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc,
+0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc,
+0x27840208, 0x24050200, 0xc002bbf, 0x24060008,
+0x27440224, 0x24050200, 0xc002bbf, 0x24060008,
+0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169,
+0x8f4202c4, 0x101302, 0x30430fff, 0x24020001,
+0x10620011, 0x28620002, 0x50400005, 0x24020002,
+0x10600007, 0x0, 0x10000017, 0x0,
+0x1062000f, 0x0, 0x10000013, 0x0,
+0x8c060248, 0x2021, 0xc005104, 0x24050004,
+0x10000007, 0x0, 0x8c060248, 0x2021,
+0xc005104, 0x24050004, 0x10000010, 0x0,
+0x8c06024c, 0x2021, 0xc005104, 0x24050001,
+0x1000000a, 0x0, 0x3c040001, 0x24846274,
+0x3c050003, 0x34a51300, 0x2003021, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0,
+0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0,
+0xc002426, 0x0, 0x10000136, 0x0,
+0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8,
+0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014,
+0xafa20018, 0x8f420108, 0x26e60028, 0x40f809,
+0x24070400, 0x1040fff5, 0x0, 0x10000125,
+0x0, 0x3c03ffff, 0x34637fff, 0x8f420368,
+0x8f440360, 0x2c3b024, 0x1821, 0xaf400058,
+0xaf40005c, 0xaf400060, 0xaf400064, 0x441023,
+0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020,
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002,
+0xafaa003c, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24846218, 0x3c050009, 0xafa20014,
+0x8d460000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24846220, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0,
+0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8,
+0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8,
+0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260,
+0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8,
+0x8f820220, 0x30420008, 0x14400002, 0x24020001,
+0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001,
+0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff,
+0x3442ffff, 0x2021824, 0x32c20180, 0x14400006,
+0x3402fffb, 0x43102b, 0x14400003, 0x0,
+0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280,
+0x3c050003, 0x34a51500, 0x2003021, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700,
+0x34421000, 0x101e02, 0x621825, 0xafa30020,
+0x8f510018, 0x240200ff, 0x12220002, 0x8021,
+0x26300001, 0x8c020228, 0x1602000e, 0x1130c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f,
+0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178,
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010,
+0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200,
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018,
+0x8f860120, 0x24020010, 0xafa20010, 0xafb00014,
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400010, 0x0, 0x8f420340, 0x24420001,
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846204, 0x3c050009,
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b,
+0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0,
+0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0,
+0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054,
+0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044,
+0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8,
+0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8,
+0x354a8320, 0x90870000, 0x24840001, 0x3021,
+0x1071026, 0x30420001, 0x10400002, 0x81842,
+0x6a1826, 0x604021, 0x24c60001, 0x2cc20008,
+0x1440fff7, 0x73842, 0x25290001, 0x125102b,
+0x1440fff0, 0x0, 0x1001021, 0x3e00008,
+0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044,
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034,
+0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200,
+0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420004, 0xaf820220, 0x8f820200,
+0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004,
+0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360,
+0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c,
+0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0,
+0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8,
+0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360,
+0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368,
+0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c,
+0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200,
+0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf,
+0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc,
+0x240203e8, 0x24040002, 0x24030001, 0xaf420294,
+0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008,
+0x10400004, 0x0, 0xaf430298, 0x10000003,
+0x3021, 0xaf440298, 0x3021, 0x3c030001,
+0x661821, 0x90636d00, 0x3461021, 0x24c60001,
+0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821,
+0x24c60001, 0x8f820040, 0x24040080, 0x24050080,
+0x21702, 0x24420030, 0xa062022c, 0x3461021,
+0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004,
+0x14400006, 0x0, 0x8f820220, 0x3c0308ff,
+0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c,
+0x30e20004, 0x14400006, 0x0, 0x8f820200,
+0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200,
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c,
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008,
+0x27bd0050, 0x0, 0x0, 0xaf400104,
+0x24040001, 0x410c0, 0x2e21821, 0x24820001,
+0x3c010001, 0x230821, 0xa42234d0, 0x402021,
+0x2c820080, 0x1440fff8, 0x410c0, 0x24020001,
+0x3c010001, 0x370821, 0xa42038d0, 0xaf420100,
+0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234,
+0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014,
+0xafb00010, 0x8f420104, 0x28420005, 0x10400026,
+0x808021, 0x3c020001, 0x8f430104, 0x344230d0,
+0x2e22021, 0x318c0, 0x621821, 0x2e31821,
+0x83102b, 0x10400015, 0x1021, 0x96070000,
+0x24840006, 0x24660006, 0x9482fffc, 0x14470009,
+0x2821, 0x9483fffe, 0x96020002, 0x14620006,
+0xa01021, 0x94820000, 0x96030004, 0x431026,
+0x2c450001, 0xa01021, 0x14400009, 0x24840008,
+0x86102b, 0x1440fff0, 0x1021, 0x304200ff,
+0x14400030, 0x24020001, 0x1000002e, 0x1021,
+0x1000fffa, 0x24020001, 0x2002021, 0xc00240c,
+0x24050006, 0x3042007f, 0x218c0, 0x2e31021,
+0x3c010001, 0x220821, 0x942230d0, 0x1040fff2,
+0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0,
+0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000,
+0x610c0, 0x572021, 0x882021, 0x94820000,
+0x14470009, 0x2821, 0x94830002, 0x96020002,
+0x14620006, 0xa01021, 0x94820004, 0x96030004,
+0x431026, 0x2c450001, 0xa01021, 0x14400007,
+0x610c0, 0x2e21021, 0x3c060001, 0xc23021,
+0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2,
+0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008,
+0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0,
+0x801021, 0xafb00030, 0x24500002, 0x2002021,
+0x24050006, 0xafb10034, 0x408821, 0xafbf0048,
+0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c,
+0xafb20038, 0x3047007f, 0x710c0, 0x2e21021,
+0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c,
+0xa03021, 0x3c090001, 0x352934d2, 0x96280002,
+0x510c0, 0x572021, 0x892021, 0x94820000,
+0x14480009, 0x3021, 0x94830002, 0x96020002,
+0x14620006, 0xc01021, 0x94820004, 0x96030004,
+0x431026, 0x2c460001, 0xc01021, 0x14400007,
+0x510c0, 0x2e21021, 0x3c050001, 0xa22821,
+0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021,
+0x10c00014, 0x610c0, 0x571821, 0x3c010001,
+0x230821, 0x8c2334d0, 0x571021, 0xafa30010,
+0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001,
+0x24846394, 0xafa20014, 0x8e260000, 0x8e270004,
+0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063,
+0x3c020800, 0x8f450100, 0x10a00006, 0x510c0,
+0x2e21021, 0x3c010001, 0x220821, 0x942234d0,
+0xaf420100, 0xa03021, 0x14c00011, 0x628c0,
+0x710c0, 0x2e21021, 0xafa70010, 0x3c010001,
+0x220821, 0x942230d0, 0x3c040001, 0x248463a0,
+0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004,
+0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800,
+0xb71821, 0x3c020001, 0x96040000, 0x344234d2,
+0x621821, 0xa4640000, 0x8e020002, 0x720c0,
+0xac620002, 0x2e41021, 0x3c030001, 0x621821,
+0x946330d0, 0x2e51021, 0x3c010001, 0x220821,
+0xa42334d0, 0x2e41021, 0x3c010001, 0x220821,
+0xa42630d0, 0x8f420104, 0x24420001, 0x28420080,
+0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001,
+0x348430d2, 0x96030000, 0x210c0, 0x571021,
+0x441021, 0xa4430000, 0x8e030002, 0xac430002,
+0x8f420104, 0x24420001, 0xaf420104, 0x3c020002,
+0x2c21024, 0x10400011, 0x72142, 0x3c030001,
+0x346338d8, 0x24020003, 0x441023, 0x21080,
+0x572021, 0x832021, 0x571021, 0x431021,
+0x30e5001f, 0x8c430000, 0x24020001, 0xa21004,
+0x621825, 0x1000000c, 0xac830000, 0x24020003,
+0x441023, 0x21080, 0x5c2821, 0x5c1021,
+0x30e4001f, 0x8c430228, 0x24020001, 0x821004,
+0x621825, 0xaca30228, 0x3c020800, 0x34421000,
+0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020,
+0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001,
+0x8c020228, 0x609021, 0x1642000e, 0x1e38c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b,
+0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
+0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
+0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x54400006, 0x24130001, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
+0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846368,
+0x3c050009, 0xafa20014, 0x8d460000, 0x10000033,
+0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x10400014, 0x9821, 0x24110010,
+0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120,
+0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c,
+0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5,
+0x0, 0x8f820054, 0x2021023, 0x2c4203e9,
+0x1440ffef, 0x0, 0x326200ff, 0x14400011,
+0x0, 0x8f420378, 0x24420001, 0xaf420378,
+0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010,
+0x8f820124, 0x3c040001, 0x24846370, 0x3c050009,
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b,
+0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4,
+0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4,
+0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021,
+0xafb00040, 0x24500002, 0x2002021, 0x24050006,
+0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054,
+0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048,
+0x3048007f, 0x810c0, 0x2e21021, 0x3c060001,
+0xc23021, 0x94c630d0, 0x10c0001c, 0x3821,
+0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0,
+0x572021, 0x8a2021, 0x94820000, 0x14490009,
+0x2821, 0x94830002, 0x96020002, 0x14620006,
+0xa01021, 0x94820004, 0x96030004, 0x431026,
+0x2c450001, 0xa01021, 0x14400008, 0x610c0,
+0xc03821, 0x2e21021, 0x3c060001, 0xc23021,
+0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011,
+0xafa70028, 0x810c0, 0x2e21021, 0xafa80010,
+0x3c010001, 0x220821, 0x942230d0, 0x3c040001,
+0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004,
+0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075,
+0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021,
+0x3c030001, 0x621821, 0x946334d0, 0x710c0,
+0x2e21021, 0x3c010001, 0x220821, 0xa42334d0,
+0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001,
+0x621821, 0x946334d0, 0x810c0, 0x2e21021,
+0x3c010001, 0x220821, 0xa42330d0, 0x3c040001,
+0x348430d0, 0x8f430100, 0x610c0, 0x2e21021,
+0x3c010001, 0x220821, 0xa42334d0, 0x8f420104,
+0x2e43821, 0x2821, 0x18400029, 0xaf460100,
+0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009,
+0x2021, 0x94c3fffe, 0x96020002, 0x14620006,
+0x801021, 0x94c20000, 0x96030004, 0x431026,
+0x2c440001, 0x801021, 0x50400014, 0x24a50001,
+0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b,
+0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe,
+0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff,
+0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104,
+0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104,
+0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008,
+0x810c0, 0x2e21021, 0x3c010001, 0x220821,
+0x942230d0, 0x14400023, 0x3c020800, 0x3c020002,
+0x2c21024, 0x10400012, 0x82142, 0x3c030001,
+0x346338d8, 0x24020003, 0x441023, 0x21080,
+0x572021, 0x832021, 0x571021, 0x431021,
+0x3105001f, 0x24030001, 0x8c420000, 0xa31804,
+0x31827, 0x431024, 0x1000000d, 0xac820000,
+0x24020003, 0x441023, 0x21080, 0x5c2821,
+0x5c1021, 0x3104001f, 0x24030001, 0x8c420228,
+0x831804, 0x31827, 0x431024, 0xaca20228,
+0x3c020800, 0x34422000, 0x1821, 0xafa20020,
+0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002,
+0xafab0034, 0x27c30001, 0x8c020228, 0x609021,
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001,
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001,
+0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010,
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021,
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821,
+0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821,
+0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c,
+0x1021, 0x2f53021, 0xafa80018, 0x8f48010c,
+0x24070008, 0xa32821, 0xa3482b, 0x822021,
+0x100f809, 0x892021, 0x54400006, 0x24130001,
+0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9,
+0x0, 0x326200ff, 0x54400017, 0xaf520018,
+0x8f420378, 0x24420001, 0xaf420378, 0x8f420378,
+0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124,
+0x3c040001, 0x24846368, 0x3c050009, 0xafa20014,
+0x8d660000, 0x10000033, 0x34a50600, 0x8f420308,
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308,
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014,
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160,
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001,
+0x24846370, 0x3c050009, 0xafa20014, 0x8d660000,
+0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8,
+0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4,
+0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058,
+0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048,
+0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060,
+0x0, 0x0, 0x0, 0x27bdffe0,
+0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000,
+0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8,
+0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100,
+0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114,
+0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128,
+0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec,
+0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4,
+0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021,
+0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c,
+0x3c040001, 0x24846470, 0x3c050001, 0x34420001,
+0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
+0x34a50100, 0xc002b3b, 0x3821, 0x8c020218,
+0x30420040, 0x10400014, 0x0, 0x8f82011c,
+0x3c040001, 0x2484647c, 0x3c050001, 0x34420004,
+0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c,
+0x10000007, 0x34a50200, 0x3c040001, 0x24846484,
+0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300,
+0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014,
+0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002,
+0x24680020, 0x27684800, 0x8f820128, 0x11020004,
+0x0, 0x8f820124, 0x15020007, 0x0,
+0x8f430334, 0x1021, 0x24630001, 0xaf430334,
+0x10000039, 0x8f430334, 0xac640000, 0xac650004,
+0xac660008, 0xa467000e, 0xac690018, 0xac6a001c,
+0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc,
+0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000,
+0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f,
+0x10400018, 0x3c020001, 0x8c830004, 0x2c620010,
+0x10400013, 0x3c020001, 0x24630001, 0xac830004,
+0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+0x14440015, 0x24020001, 0x8f820128, 0x24420020,
+0xaf820128, 0x8f820128, 0x1000000f, 0x24020001,
+0x3c020001, 0x344230c8, 0x2e21021, 0x54820004,
+0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021,
+0x402021, 0x24020001, 0xaf4400f4, 0xac890000,
+0xac820004, 0x24020001, 0x3e00008, 0x0,
+0x3e00008, 0x0, 0x8fa90010, 0x8f83010c,
+0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0,
+0x14620002, 0x24680020, 0x27684000, 0x8f820108,
+0x11020004, 0x0, 0x8f820104, 0x15020007,
+0x0, 0x8f430338, 0x1021, 0x24630001,
+0xaf430338, 0x10000035, 0x8f430338, 0xac640000,
+0xac650004, 0xac660008, 0xa467000e, 0xac690018,
+0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100,
+0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019,
+0x31220006, 0x10400018, 0x3c020001, 0x8c830004,
+0x2c620010, 0x10400013, 0x3c020001, 0x24630001,
+0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021,
+0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
+0x2e21021, 0x14440015, 0x24020001, 0x8f820108,
+0x24420020, 0xaf820108, 0x8f820108, 0x1000000f,
+0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021,
+0x54820004, 0x24820008, 0x3c020001, 0x34422cc0,
+0x2e21021, 0x402021, 0x24020001, 0xaf4400ec,
+0xac890000, 0xac820004, 0x24020001, 0x3e00008,
+0x0, 0x3e00008, 0x0, 0x27bdffd8,
+0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024,
+0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104,
+0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100,
+0x2403021, 0x2203821, 0xafa20010, 0xc002b3b,
+0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c,
+0x3c040001, 0x24846498, 0xafa20014, 0x8e060000,
+0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510,
+0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001,
+0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014,
+0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00,
+0x2221024, 0x3c030800, 0x54430016, 0x3c030200,
+0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200,
+0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030,
+0x3021, 0x3821, 0x36420002, 0xaf82011c,
+0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024,
+0x0, 0x2c31024, 0x1040000d, 0x2231024,
+0x1040000b, 0x36420002, 0xaf82011c, 0x36220001,
+0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330,
+0x24420001, 0xaf420330, 0x10000015, 0x8f420330,
+0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010,
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0,
+0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002,
+0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220,
+0x8f820140, 0x3c030001, 0x431025, 0xaf820140,
+0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001,
+0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020,
+0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0,
+0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021,
+0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014,
+0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001,
+0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004,
+0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018,
+0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500,
+0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001,
+0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024,
+0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac,
+0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001,
+0x2484650c, 0x3c050001, 0x34a5f030, 0x3021,
+0x3821, 0x36420002, 0xaf82011c, 0x36220001,
+0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010,
+0xc002b3b, 0xafa00014, 0x10000024, 0x0,
+0x2c31024, 0x1040000d, 0x2231024, 0x1040000b,
+0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0,
+0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001,
+0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001,
+0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014,
+0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b,
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c,
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140,
+0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024,
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008,
+0x27bd0028, 0x6021, 0x5021, 0x3021,
+0x2821, 0x6821, 0x4821, 0x7821,
+0x7021, 0x8f880124, 0x8f870104, 0x1580002e,
+0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120,
+0x10460029, 0x0, 0x3c040001, 0x8c846ee4,
+0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004,
+0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e,
+0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014,
+0x10000012, 0x24c60020, 0x10400017, 0x0,
+0x3c040001, 0x8c846ee4, 0x8d020000, 0x8d030004,
+0xac820000, 0xac830004, 0x8d020008, 0xac820008,
+0x9502000e, 0xa482000e, 0x8d020010, 0x25060020,
+0xac820010, 0x8d020014, 0x240c0001, 0xc01821,
+0xac820014, 0x27624fe0, 0x43102b, 0x54400001,
+0x27634800, 0x603021, 0x1540002f, 0x31620100,
+0x11200014, 0x31628000, 0x8f820100, 0x1045002a,
+0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000,
+0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008,
+0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010,
+0x240a0001, 0xac820010, 0x8ca20014, 0x10000012,
+0x24a50020, 0x10400018, 0x31620100, 0x3c040001,
+0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000,
+0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e,
+0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010,
+0x8ce20014, 0x240a0001, 0xa01821, 0xac820014,
+0x276247e0, 0x43102b, 0x54400001, 0x27634000,
+0x602821, 0x31620100, 0x5440001d, 0x31621000,
+0x11a00009, 0x31a20800, 0x10400004, 0x25020020,
+0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124,
+0x8f880124, 0x6821, 0x11800011, 0x31621000,
+0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004,
+0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4,
+0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021,
+0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000,
+0x1440ff82, 0x0, 0x1120000f, 0x31220800,
+0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000,
+0x3c020002, 0x1221024, 0x10400004, 0x24e20020,
+0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104,
+0x8f870104, 0x4821, 0x1140ff70, 0x0,
+0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004,
+0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4,
+0x9482000e, 0xaf82009c, 0x8c820010, 0x5021,
+0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014,
+0x3e00008, 0x0, 0x6021, 0x5821,
+0x3021, 0x2821, 0x6821, 0x5021,
+0x7821, 0x7021, 0x8f880124, 0x8f870104,
+0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014,
+0x31220800, 0x8f820120, 0x10460029, 0x0,
+0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004,
+0xac820000, 0xac830004, 0x8cc20008, 0xac820008,
+0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001,
+0xac820010, 0x8cc20014, 0x10000012, 0x24c60020,
+0x10400017, 0x0, 0x3c040001, 0x8c846ee4,
+0x8d020000, 0x8d030004, 0xac820000, 0xac830004,
+0x8d020008, 0xac820008, 0x9502000e, 0xa482000e,
+0x8d020010, 0x25060020, 0xac820010, 0x8d020014,
+0x240c0001, 0xc01821, 0xac820014, 0x27624fe0,
+0x43102b, 0x54400001, 0x27634800, 0x603021,
+0x1560002f, 0x31220100, 0x11400014, 0x31228000,
+0x8f820100, 0x1045002a, 0x31220100, 0x3c040001,
+0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000,
+0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e,
+0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010,
+0x8ca20014, 0x10000012, 0x24a50020, 0x10400018,
+0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000,
+0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008,
+0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010,
+0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001,
+0xa01821, 0xac820014, 0x276247e0, 0x43102b,
+0x54400001, 0x27634000, 0x602821, 0x31220100,
+0x5440001d, 0x31221000, 0x11a00009, 0x31a20800,
+0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000,
+0x25020020, 0xaf820124, 0x8f880124, 0x6821,
+0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4,
+0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084,
+0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac,
+0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010,
+0x8c8f0014, 0x31221000, 0x14400022, 0x0,
+0x1140000f, 0x31420800, 0x10400004, 0x3c020002,
+0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024,
+0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4,
+0x24e20020, 0xaf820104, 0x8f870104, 0x5021,
+0x11600010, 0x0, 0x3c040001, 0x8c846ee0,
+0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094,
+0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c,
+0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010,
+0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024,
+0x1040ff5c, 0x0, 0x8f820054, 0x24420005,
+0xaf820078, 0x8c040234, 0x10800016, 0x1821,
+0x3c020001, 0x571021, 0x8c4240e8, 0x24420005,
+0x3c010001, 0x370821, 0xac2240e8, 0x3c020001,
+0x571021, 0x8c4240e8, 0x44102b, 0x14400009,
+0x24020001, 0x3c030080, 0x3c010001, 0x370821,
+0xac2040e8, 0x3c010001, 0x370821, 0x1000000c,
+0xa02240f0, 0x3c020001, 0x571021, 0x904240f0,
+0x14400006, 0x3c020080, 0x3c020001, 0x571021,
+0x904240f1, 0x10400002, 0x3c020080, 0x621825,
+0x8c040230, 0x10800013, 0x0, 0x3c020001,
+0x571021, 0x8c4240ec, 0x24420005, 0x3c010001,
+0x370821, 0xac2240ec, 0x3c020001, 0x571021,
+0x8c4240ec, 0x44102b, 0x14400006, 0x0,
+0x3c010001, 0x370821, 0xac2040ec, 0x10000006,
+0x781825, 0x3c020001, 0x571021, 0x904240f2,
+0x54400001, 0x781825, 0x1060ff1a, 0x0,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x431025, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x1000ff05,
+0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008,
+0x0, 0x0, 0x0, 0x3c020001,
+0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012,
+0xafb00010, 0x3c100001, 0x26106f90, 0x2002021,
+0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001,
+0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250,
+0x24022000, 0xac100254, 0xac020258, 0x24020001,
+0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010,
+0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec,
+0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000,
+0x8c820004, 0xad250008, 0xad220004, 0x8f820054,
+0xad260010, 0xad270014, 0xad230018, 0xad28001c,
+0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90,
+0x122102b, 0x10400003, 0x0, 0x3c090001,
+0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000,
+0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec,
+0xad220004, 0xac090250, 0x3e00008, 0x0,
+0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec,
+0x3c020001, 0x8c426d10, 0xafb10014, 0x808821,
+0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018,
+0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c,
+0xae020000, 0x3c020001, 0x8c426d10, 0xc09821,
+0xe0a821, 0x10800006, 0xae020004, 0x26050008,
+0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0,
+0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0,
+0x3c030001, 0x24636f90, 0x203102b, 0x10400003,
+0x0, 0x3c100001, 0x8e106ee8, 0x8e220000,
+0xae020000, 0x8e220004, 0xae120008, 0xae020004,
+0x8f820054, 0xae130010, 0xae150014, 0xae1e0018,
+0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0,
+0x203102b, 0x10400003, 0x0, 0x3c100001,
+0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000,
+0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec,
+0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024,
+0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014,
+0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821,
+0x83102b, 0x10400006, 0x0, 0xac800000,
+0x24840004, 0x83102b, 0x5440fffd, 0xac800000,
+0x3e00008, 0x0, 0xa61821, 0xa3102b,
+0x10400007, 0x0, 0x8c820000, 0xaca20000,
+0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004,
+0x3e00008, 0x0, 0x861821, 0x83102b,
+0x10400007, 0x0, 0x8ca20000, 0xac820000,
+0x24840004, 0x83102b, 0x1440fffb, 0x24a50004,
+0x3e00008, 0x0, 0x63080, 0x861821,
+0x83102b, 0x10400006, 0x0, 0xac850000,
+0x24840004, 0x83102b, 0x5440fffd, 0xac850000,
+0x3e00008, 0x0, 0x0, 0x26e50028,
+0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c,
+0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204,
+0x8f4c0200, 0x24640400, 0x64102b, 0x10400008,
+0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004,
+0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff,
+0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c,
+0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204,
+0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200,
+0x821024, 0x34420004, 0xc31824, 0x34630004,
+0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084,
+0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c,
+0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094,
+0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c,
+0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4,
+0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac,
+0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4,
+0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc,
+0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0,
+0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0,
+0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4,
+0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec,
+0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c,
+0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4,
+0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8,
+0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff,
+0x3463fffb, 0x431024, 0xaf820220, 0x30c20004,
+0x14400006, 0x0, 0x8f820200, 0x3c03c0ff,
+0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc,
+0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+0xafb00020, 0x8f430024, 0x8f420020, 0x10620038,
+0x0, 0x8f430020, 0x8f420024, 0x622023,
+0x4810003, 0x0, 0x8f420040, 0x822021,
+0x8f430030, 0x8f420024, 0x43102b, 0x14400005,
+0x0, 0x8f430040, 0x8f420024, 0x10000005,
+0x621023, 0x8f420030, 0x8f430024, 0x431023,
+0x2442ffff, 0x406021, 0x8c102a, 0x54400001,
+0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024,
+0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c,
+0x24070001, 0xafa70010, 0x84100, 0x1001821,
+0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014,
+0x8f470014, 0x1021, 0x63100, 0xafa70018,
+0xa32821, 0xa3382b, 0x822021, 0x872021,
+0x8f420108, 0x1663021, 0x40f809, 0xc3900,
+0x54400001, 0xaf500024, 0x8f430024, 0x8f420020,
+0x14620018, 0x0, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x2403ffef, 0x431024, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000002, 0xaf80004c,
+0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008,
+0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0,
+0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030,
+0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028,
+0x10000002, 0x0, 0x8f530020, 0x8f420030,
+0x105300eb, 0x21100, 0x8f43001c, 0x628021,
+0x8e040000, 0x8e050004, 0x96120008, 0x8f420090,
+0x9611000a, 0x3246ffff, 0x46102a, 0x10400017,
+0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf,
+0x10400005, 0x0, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+0x10400006, 0x0, 0x8f420348, 0x24420001,
+0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc,
+0x14400006, 0x0, 0x8f420344, 0x24420001,
+0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2,
+0x1040000b, 0x32c20008, 0x10400008, 0x32220200,
+0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac,
+0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac,
+0x32220004, 0x1040007f, 0x32220800, 0x10400003,
+0x3247ffff, 0x10000002, 0x24020020, 0x24020004,
+0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010,
+0x3c030002, 0x431025, 0xafa20018, 0x8f460098,
+0x8f420108, 0x40f809, 0x0, 0x104000b7,
+0x0, 0x8f42009c, 0x8f430094, 0x2421021,
+0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008,
+0x3c034000, 0x8f420094, 0x431025, 0xafa20020,
+0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025,
+0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024,
+0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
+0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
+0x8f440270, 0x8f450274, 0x401821, 0x1021,
+0xa32821, 0xa3302b, 0x822021, 0x862021,
+0x32230060, 0x24020040, 0xaf440270, 0xaf450274,
+0x10620017, 0x2c620041, 0x10400005, 0x24020020,
+0x10620008, 0x24020001, 0x10000026, 0x0,
+0x24020060, 0x10620019, 0x24020001, 0x10000021,
+0x0, 0x8f420278, 0x8f43027c, 0x24630001,
+0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+0x8f420278, 0x8f43027c, 0x10000016, 0x24020001,
+0x8f420280, 0x8f430284, 0x24630001, 0x2c640001,
+0x441021, 0xaf420280, 0xaf430284, 0x8f420280,
+0x8f430284, 0x1000000b, 0x24020001, 0x8f420288,
+0x8f43028c, 0x24630001, 0x2c640001, 0x441021,
+0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c,
+0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff,
+0x2406fff8, 0x8f45013c, 0x441021, 0x24420007,
+0x461024, 0x24840007, 0xaf420094, 0x8f420090,
+0x8f430094, 0x862024, 0x441023, 0x65182b,
+0x14600005, 0xaf420090, 0x8f420094, 0x8f430144,
+0x431023, 0xaf420094, 0x8f420094, 0x10000023,
+0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020,
+0x14400002, 0x24020010, 0x24020002, 0xafa20010,
+0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018,
+0x8f460098, 0x8f420108, 0x40f809, 0x0,
+0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090,
+0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c,
+0x8f440098, 0xa34005c2, 0x651823, 0xaf430090,
+0x451021, 0x86202b, 0x14800005, 0xaf42009c,
+0x8f420098, 0x8f430144, 0x431023, 0xaf420098,
+0x32c20020, 0x10400005, 0x0, 0x8f420358,
+0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030,
+0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+0xaf420030, 0x8f420030, 0x14530018, 0x0,
+0x8f420000, 0x10400007, 0x0, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x2403fff7, 0x431024,
+0xaf820060, 0x8f420000, 0x10400003, 0x0,
+0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038,
+0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028,
+0x3e00008, 0x27bd0040, 0x3e00008, 0x0,
+0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028,
+0xafb10024, 0x10400004, 0xafb00020, 0x8f520028,
+0x10000002, 0x0, 0x8f520020, 0x8f420030,
+0x105200b5, 0x21100, 0x8f43001c, 0x628021,
+0x8e040000, 0x8e050004, 0x96110008, 0x8f420090,
+0x9607000a, 0x3226ffff, 0x46102a, 0x10400017,
+0x0, 0x8f8200d8, 0x8f430098, 0x431023,
+0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47,
+0x10400005, 0x0, 0x8f420090, 0x8f430144,
+0x431021, 0xaf420090, 0x8f420090, 0x46102a,
+0x10400006, 0x0, 0x8f420348, 0x24420001,
+0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc,
+0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8,
+0x431024, 0x461023, 0x218c3, 0x58600001,
+0x24630100, 0x8f42008c, 0x43102b, 0x14400006,
+0x712c2, 0x8f420344, 0x24420001, 0xaf420344,
+0x10000098, 0x8f420344, 0x934305c2, 0x1060000f,
+0x30460001, 0x8f420010, 0x34480400, 0x32c20008,
+0x10400008, 0x30e20200, 0x10400006, 0x3c034000,
+0x9602000e, 0xaf4300ac, 0x21400, 0x10000004,
+0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010,
+0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac,
+0x11200005, 0x30c200ff, 0x14400006, 0x24020040,
+0x10000004, 0x24020008, 0x14400002, 0x24020020,
+0x24020004, 0xafa20010, 0x8f430030, 0x11200004,
+0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014,
+0x3c020002, 0x1021025, 0xafa20018, 0x8f460098,
+0x8f420108, 0x40f809, 0x0, 0x10400069,
+0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001,
+0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2,
+0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021,
+0x24420007, 0x461024, 0x24840007, 0xaf420094,
+0x8f420090, 0x8f430094, 0x862024, 0x441023,
+0x65182b, 0x14600005, 0xaf420090, 0x8f420094,
+0x8f430144, 0x431023, 0xaf420094, 0x8f430094,
+0x8f420140, 0x43102b, 0x10400009, 0x0,
+0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138,
+0x641823, 0x431023, 0xaf420090, 0xaf450094,
+0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d,
+0x30c200ff, 0x14400002, 0x24020010, 0x24020002,
+0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014,
+0x8f460098, 0x8f420108, 0x40f809, 0x0,
+0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c,
+0x451021, 0xaf420098, 0x8f420090, 0x8f430098,
+0xa34005c2, 0x451023, 0x64182b, 0x14600005,
+0xaf420090, 0x8f420098, 0x8f430144, 0x431023,
+0xaf420098, 0x8f420030, 0x8f430040, 0x24420001,
+0x2463ffff, 0x431024, 0xaf420030, 0x8f420030,
+0x14520018, 0x0, 0x8f420000, 0x10400007,
+0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd,
+0x0, 0x10000005, 0x0, 0xaf800048,
+0x8f820048, 0x1040fffd, 0x0, 0x8f820060,
+0x2403fff7, 0x431024, 0xaf820060, 0x8f420000,
+0x10400003, 0x0, 0x10000002, 0xaf80004c,
+0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024,
+0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008,
+0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0,
+0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021,
+0x54620004, 0x24620008, 0x3c020001, 0x34422cc0,
+0x2e21021, 0x401821, 0xaf4300f0, 0xac600000,
+0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001,
+0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0,
+0x34422ec0, 0x2e21021, 0x54620004, 0x24620008,
+0x3c020001, 0x34422cc0, 0x2e21021, 0x401821,
+0x8c620004, 0x21140, 0x821021, 0xaf820108,
+0xac600000, 0x8c850018, 0x30a20036, 0x1040006c,
+0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034,
+0x24420001, 0x2463ffff, 0x431024, 0x862021,
+0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034,
+0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4,
+0x0, 0x32c20010, 0x10400028, 0x24070008,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+0x8f860120, 0x24020080, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c,
+0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100,
+0x10000036, 0x0, 0x8f420300, 0x8f43002c,
+0x24420001, 0xaf420300, 0x8f420300, 0x24020001,
+0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020020, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x24020001, 0x3c010001, 0x370821, 0xa02240f0,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120,
+0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f,
+0x0, 0x8f420300, 0x24420001, 0xaf420300,
+0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038,
+0x3c010001, 0x370821, 0xa02040f1, 0x3c010001,
+0x370821, 0xa02040f0, 0xaf400034, 0x8f420314,
+0x24420001, 0xaf420314, 0x10000059, 0x8f420314,
+0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028,
+0xa22023, 0x4810003, 0x0, 0x8f420040,
+0x822021, 0x8f420358, 0x8f430000, 0xaf450028,
+0x441021, 0x10600007, 0xaf420358, 0xaf80004c,
+0x8f82004c, 0x1040fffd, 0x0, 0x10000005,
+0x0, 0xaf800048, 0x8f820048, 0x1040fffd,
+0x0, 0x8f820060, 0x34420008, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x10000038,
+0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f,
+0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c,
+0x8f420050, 0x622023, 0x4820001, 0x24840200,
+0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368,
+0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000,
+0x8c83001c, 0x8f420070, 0x622023, 0x4820001,
+0x24840400, 0x8f420364, 0x441021, 0xaf420364,
+0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e,
+0x3c020800, 0x8c83001c, 0x8f420060, 0x622023,
+0x4820001, 0x24840100, 0x8f420360, 0x441021,
+0xaf420360, 0x8f420368, 0xaf430060, 0x441021,
+0xaf420368, 0x3c020800, 0x2c21024, 0x50400008,
+0x36940040, 0x10000006, 0x0, 0x30a20100,
+0x10400003, 0x0, 0xc002bd8, 0x0,
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008,
+0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c,
+0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c,
+0xafb00038, 0x8f910108, 0x26220020, 0xaf820108,
+0x8e320018, 0xa821, 0x32420024, 0x104001ba,
+0xf021, 0x8e26001c, 0x8f43001c, 0x61100,
+0x621821, 0x8c70000c, 0x9604000c, 0x962d0016,
+0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001,
+0x621825, 0x10600015, 0x2821, 0x32c20040,
+0x10400015, 0x24020800, 0x96030014, 0x14620012,
+0x3402aaaa, 0x9603000e, 0x14620007, 0x2021,
+0x96030010, 0x24020300, 0x14620004, 0x801021,
+0x96020012, 0x2c440001, 0x801021, 0x54400006,
+0x24050016, 0x10000004, 0x0, 0x24020800,
+0x50820001, 0x2405000e, 0x934205c3, 0x14400008,
+0x5821, 0x240b0001, 0x32620180, 0xaf4500a8,
+0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3,
+0x10a00085, 0x2054021, 0x91020000, 0x3821,
+0x3042000f, 0x25080, 0x32c20002, 0x10400012,
+0x10a1821, 0x32620002, 0x10400010, 0x32c20001,
+0x1002021, 0x94820000, 0x24840002, 0xe23821,
+0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02,
+0x623821, 0x71c02, 0x30e2ffff, 0x623821,
+0x71027, 0xa502000a, 0x32c20001, 0x1040006a,
+0x32620001, 0x10400068, 0x0, 0x8f4200a8,
+0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8,
+0x431021, 0x904c0009, 0x318900ff, 0x39230006,
+0x3182b, 0x39220011, 0x2102b, 0x621824,
+0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001,
+0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600,
+0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e,
+0x0, 0x32c20004, 0x14400013, 0x2821,
+0x316200ff, 0x14400004, 0x0, 0x95020002,
+0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e,
+0x95030010, 0xa22821, 0xa32821, 0x95030012,
+0x91040009, 0x95020002, 0xa32821, 0xa42821,
+0x4a1023, 0xa22821, 0x2002021, 0x94820000,
+0x24840002, 0xe23821, 0x88102b, 0x1440fffb,
+0x71c02, 0x30e2ffff, 0x623821, 0x71c02,
+0x30e2ffff, 0x623821, 0x1a52821, 0x51c02,
+0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff,
+0x622821, 0xa72823, 0x51402, 0xa22821,
+0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff,
+0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8,
+0x624021, 0x91020000, 0x3042000f, 0x25080,
+0x318300ff, 0x24020006, 0x14620003, 0x10a1021,
+0x10000002, 0x24440010, 0x24440006, 0x316200ff,
+0x14400006, 0x0, 0x94820000, 0xa22821,
+0x51c02, 0x30a2ffff, 0x622821, 0x934205c3,
+0x10400003, 0x32620100, 0x50400003, 0xa4850000,
+0x52827, 0xa4850000, 0x9622000e, 0x8f43009c,
+0x621821, 0x32a200ff, 0x10400007, 0xaf43009c,
+0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c,
+0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c,
+0xafa20024, 0x32620080, 0x10400010, 0x32620100,
+0x8f4200b4, 0x24430001, 0x210c0, 0x571021,
+0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001,
+0x220821, 0xac2338e8, 0x3c010001, 0x220821,
+0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064,
+0x0, 0x8f4200b4, 0x24430001, 0x210c0,
+0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024,
+0x3c010001, 0x220821, 0xac2338e8, 0x3c010001,
+0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051,
+0x3821, 0x3c090001, 0x352938e8, 0x3c08001f,
+0x3508ffff, 0x240bffff, 0x340affff, 0x710c0,
+0x571021, 0x491021, 0x8c430000, 0x8c440004,
+0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028,
+0x8fa4002c, 0xac430000, 0xac440004, 0x24420008,
+0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c,
+0x97a2002e, 0x8f440270, 0x8f450274, 0x401821,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaf440270, 0xaf450274, 0x8fa20028,
+0x481024, 0x90430000, 0x30630001, 0x1460000b,
+0x402021, 0x8f420278, 0x8f43027c, 0x24630001,
+0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000,
+0x144b000e, 0x0, 0x94820004, 0x144a000b,
+0x0, 0x8f420288, 0x8f43028c, 0x24630001,
+0x2c640001, 0x441021, 0xaf420288, 0xaf43028c,
+0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280,
+0x8f430284, 0x24630001, 0x2c640001, 0x441021,
+0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284,
+0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8,
+0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4,
+0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000,
+0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c,
+0x8f46008c, 0x8f440270, 0x8f450274, 0x401821,
+0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xaf440270,
+0xaf450274, 0x92020000, 0x30420001, 0x1440000c,
+0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001,
+0x2c640001, 0x441021, 0xaf420278, 0xaf43027c,
+0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020,
+0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004,
+0x1462000c, 0x0, 0x8f420288, 0x8f43028c,
+0x24630001, 0x2c640001, 0x441021, 0xaf420288,
+0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b,
+0x32c20020, 0x8f420280, 0x8f430284, 0x24630001,
+0x2c640001, 0x441021, 0xaf420280, 0xaf430284,
+0x8f420280, 0x8f430284, 0x32c20020, 0x10400005,
+0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358,
+0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001,
+0x2463ffff, 0x431024, 0xaf42002c, 0x32420060,
+0x14400008, 0x32c20010, 0x8f420034, 0x24420001,
+0xaf420034, 0x8c03023c, 0x43102b, 0x14400102,
+0x32c20010, 0x10400018, 0x24070008, 0x8f440170,
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120,
+0x24020080, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047,
+0x24020001, 0x8f420300, 0x8f43002c, 0x24420001,
+0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1,
+0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174,
+0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020,
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x10400057, 0x24020001,
+0x10000065, 0x0, 0x32420012, 0x10400075,
+0x32420001, 0x9622000e, 0x8f43009c, 0x621821,
+0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358,
+0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c,
+0x8f430040, 0x24420001, 0x2463ffff, 0x431024,
+0xaf42002c, 0x32420010, 0x14400008, 0x32c20010,
+0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c,
+0x43102b, 0x144000bc, 0x32c20010, 0x10400028,
+0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c,
+0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010,
+0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809,
+0x24c6001c, 0x14400011, 0x24020001, 0x3c010001,
+0x370821, 0xa02240f1, 0x8f820124, 0xafa20010,
+0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014,
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b,
+0x34a51100, 0x10000036, 0x0, 0x8f420300,
+0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300,
+0x24020001, 0xa34205c1, 0x10000026, 0xaf430038,
+0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c,
+0x8f860120, 0x24020020, 0xafa20010, 0xafa30014,
+0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c,
+0x14400011, 0x24020001, 0x3c010001, 0x370821,
+0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128,
+0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c,
+0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900,
+0x1000000f, 0x0, 0x8f420300, 0x24420001,
+0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1,
+0xaf420038, 0x3c010001, 0x370821, 0xa02040f1,
+0x3c010001, 0x370821, 0xa02040f0, 0xaf400034,
+0x8f420314, 0x24420001, 0xaf420314, 0x10000062,
+0x8f420314, 0x10400022, 0x32427000, 0x8e25001c,
+0x8f420028, 0xa22023, 0x4810003, 0x0,
+0x8f420040, 0x822021, 0x8f420358, 0x8f430000,
+0xaf450028, 0x441021, 0x10600007, 0xaf420358,
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+0x10000005, 0x0, 0xaf800048, 0x8f820048,
+0x1040fffd, 0x0, 0x8f820060, 0x34420008,
+0xaf820060, 0x8f420000, 0x10400003, 0x0,
+0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048,
+0x1040002f, 0x32421000, 0x1040000c, 0x32424000,
+0x8e23001c, 0x8f420050, 0x622023, 0x4820001,
+0x24840200, 0x8f42035c, 0x441021, 0xaf42035c,
+0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c,
+0x32c28000, 0x8e23001c, 0x8f420070, 0x622023,
+0x4820001, 0x24840400, 0x8f420364, 0x441021,
+0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070,
+0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060,
+0x622023, 0x4820001, 0x24840100, 0x8f420360,
+0x441021, 0xaf420360, 0x8f420368, 0xaf430060,
+0x441021, 0xaf420368, 0x3c020800, 0x2c21024,
+0x50400011, 0x36940040, 0x1000000f, 0x0,
+0x32420048, 0x10400007, 0x24150001, 0x8e22001c,
+0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75,
+0xae22001c, 0x32420100, 0x10400003, 0x0,
+0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c,
+0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c,
+0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008,
+0x0, 0x0, 0x0, 0x8f8300e4,
+0x8f8200e0, 0x2404fff8, 0x441024, 0x621026,
+0x2102b, 0x21023, 0x3e00008, 0x621024,
+0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c,
+0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4,
+0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8,
+0x14a20002, 0x24a20008, 0x27623000, 0x408021,
+0x16030005, 0x30820004, 0x10400004, 0xc02021,
+0x10000022, 0x1021, 0x8e040000, 0x8f42011c,
+0x14a20003, 0x0, 0x8f420120, 0xaf420114,
+0x8ca30000, 0x8f420148, 0x831823, 0x43102b,
+0x10400003, 0x0, 0x8f420148, 0x621821,
+0x94a20006, 0x24420050, 0x62102b, 0x1440000f,
+0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000,
+0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894,
+0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c,
+0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c,
+0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008,
+0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8,
+0x2402fff8, 0x823824, 0xe32023, 0x2c821000,
+0x50400001, 0x24841000, 0x420c2, 0x801821,
+0x8f440258, 0x8f45025c, 0x1021, 0xa32821,
+0xa3302b, 0x822021, 0x862021, 0xaf440258,
+0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023,
+0x82102b, 0x14400004, 0x801821, 0x8f420148,
+0x822021, 0x801821, 0x8f440250, 0x8f450254,
+0x1021, 0xa32821, 0xa3302b, 0x822021,
+0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8,
+0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0,
+0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4,
+0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4,
+0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c,
+0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086,
+0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c,
+0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129,
+0xafaa007c, 0x8f420114, 0x40f809, 0x0,
+0x403021, 0x10c0034f, 0x0, 0x8cc20000,
+0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024,
+0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c,
+0x3c020006, 0x2c21024, 0xafab007c, 0x14400015,
+0xafaa0064, 0x91420000, 0x30420001, 0x10400011,
+0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff,
+0x95430004, 0x1062000b, 0x0, 0xc0024bb,
+0x8fa40064, 0x304200ff, 0x14400006, 0x0,
+0x8f420118, 0x40f809, 0x0, 0x1000032d,
+0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
+0x431024, 0x3c03ffff, 0x431824, 0x14600003,
+0xafa20024, 0x10000040, 0x1821, 0x3c020080,
+0x621024, 0x10400007, 0x0, 0x8f42038c,
+0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
+0x24030001, 0x8f420210, 0x24420001, 0xaf420210,
+0x8f420210, 0x3c020001, 0x621024, 0x10400006,
+0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
+0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
+0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
+0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
+0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
+0x8f420380, 0x3c020008, 0x621024, 0x10400006,
+0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
+0x8f420384, 0x3c020010, 0x621024, 0x10400006,
+0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
+0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
+0x24030001, 0x8f420388, 0x24420001, 0xaf420388,
+0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c,
+0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8,
+0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c,
+0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010,
+0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
+0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
+0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080,
+0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c,
+0x3c020080, 0x34420100, 0x1621024, 0x10400005,
+0x0, 0x8f42020c, 0x24420001, 0xaf42020c,
+0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400,
+0x10400015, 0x34028100, 0x8faa0064, 0x9543000c,
+0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e,
+0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000,
+0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c,
+0xa7a20086, 0xad63000c, 0xad640008, 0xad650004,
+0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024,
+0x10400004, 0x0, 0x8faa006c, 0x254a0004,
+0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074,
+0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074,
+0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc,
+0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b,
+0x10400056, 0x32c28000, 0x1040005e, 0x240a0003,
+0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058,
+0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024,
+0x24420001, 0xaf420350, 0x1000024f, 0x8f420350,
+0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
+0x3c040001, 0x248468d0, 0x26620001, 0xafa20014,
+0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
+0xc002b3b, 0x34a52250, 0x1000023f, 0x0,
+0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128,
+0x3c040001, 0x248468d0, 0x24020002, 0xafa20014,
+0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007,
+0xc002b3b, 0x34a52450, 0x1000022f, 0x0,
+0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8,
+0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800,
+0xc002b3b, 0x603021, 0x10000223, 0x0,
+0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0,
+0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120,
+0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216,
+0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124,
+0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010,
+0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b,
+0x34a53200, 0x10000208, 0x0, 0x8f420084,
+0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001,
+0x2c21024, 0x10400004, 0x0, 0x240b0002,
+0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020,
+0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c,
+0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002,
+0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054,
+0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001,
+0x304201ff, 0xafa20054, 0x1e1140, 0x431021,
+0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c,
+0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010,
+0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b,
+0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024,
+0x24630001, 0xaf430350, 0x100001d3, 0x8f420350,
+0x156a001d, 0x0, 0x8f430074, 0x8f420070,
+0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c,
+0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140,
+0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044,
+0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007,
+0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070,
+0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c,
+0x1000ffc3, 0x0, 0x8f430064, 0x8f420060,
+0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c,
+0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054,
+0x24020004, 0x1562000e, 0x1e1140, 0x1e1180,
+0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a,
+0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024,
+0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097,
+0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044,
+0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014,
+0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007,
+0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024,
+0x1440ff34, 0x0, 0x8f420370, 0x240a0001,
+0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90,
+0x8f420370, 0x27a30036, 0x131040, 0x621821,
+0x94620000, 0x441021, 0x10000020, 0xa4620000,
+0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072,
+0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4,
+0x25420020, 0xafa20028, 0x25420008, 0xafa20030,
+0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a,
+0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a,
+0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018,
+0x24630002, 0x822023, 0x1880ffde, 0x26730001,
+0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
+0x26650001, 0xa2102a, 0x1440002b, 0x24030001,
+0x8f83012c, 0x10600023, 0x0, 0x8f820124,
+0x431023, 0x22143, 0x58800001, 0x24840040,
+0x8f820128, 0x431023, 0x21943, 0x58600001,
+0x24630040, 0x64102a, 0x54400001, 0x602021,
+0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011,
+0x24030001, 0x10000015, 0x306200ff, 0x8fab0064,
+0x96070018, 0xafab0010, 0x8e220008, 0x3c040001,
+0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400,
+0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b,
+0x0, 0x8f420334, 0x1821, 0x24420001,
+0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc,
+0x3c020800, 0x12600021, 0x9021, 0x8fb100a4,
+0x2208021, 0x8e220008, 0x96070018, 0x8fa60064,
+0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010,
+0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c,
+0x40f809, 0x0, 0x1040ffd8, 0x3c050007,
+0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821,
+0x14b102b, 0x10400004, 0xafab0064, 0x8f420148,
+0x1625823, 0xafab0064, 0x26100002, 0x26520001,
+0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c,
+0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002,
+0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c,
+0x10600013, 0x0, 0x8f820124, 0x431023,
+0x22143, 0x58800001, 0x24840040, 0x8f820128,
+0x431023, 0x21943, 0x58600001, 0x24630040,
+0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001,
+0x8f420334, 0x1821, 0x24420001, 0xaf420334,
+0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800,
+0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b,
+0x54400001, 0x608021, 0x8ea40000, 0x8ea50004,
+0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008,
+0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809,
+0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e,
+0x97aa008e, 0x11400007, 0x609021, 0x934205c4,
+0x14400004, 0x0, 0x97ab0086, 0x6a1825,
+0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024,
+0x10400003, 0xa1402, 0x34630400, 0xa6a20014,
+0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004,
+0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a,
+0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000,
+0xafa20010, 0x8f420044, 0x2a03021, 0x24070020,
+0xafa20014, 0x8f42000c, 0x31940, 0x604821,
+0xafa20018, 0x8f42010c, 0x4021, 0xa92821,
+0xa9182b, 0x882021, 0x40f809, 0x832021,
+0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c,
+0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c,
+0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002,
+0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
+0x8f42035c, 0x156a0006, 0x0, 0x8f420364,
+0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364,
+0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360,
+0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044,
+0x8f440088, 0x8f430078, 0x24420001, 0x441024,
+0x24630001, 0xaf420044, 0xaf430078, 0x8c020240,
+0x62182b, 0x14600075, 0x24070008, 0x8f440168,
+0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120,
+0x24020040, 0xafa20010, 0xafa30014, 0xafa80018,
+0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011,
+0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2,
+0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001,
+0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120,
+0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b,
+0x0, 0x8f420304, 0x24420001, 0xaf420304,
+0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001,
+0x370821, 0xa02040f2, 0xaf400078, 0x8f420318,
+0x24420001, 0xaf420318, 0x10000048, 0x8f420318,
+0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4,
+0x34028000, 0xafa20010, 0x8f420044, 0x2a03021,
+0x24070020, 0xafa20014, 0x8f42000c, 0x31940,
+0x604821, 0xafa20018, 0x8f42010c, 0x4021,
+0xa92821, 0xa9182b, 0x882021, 0x40f809,
+0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4,
+0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c,
+0x8fab009c, 0x1505021, 0x16a102b, 0x10400004,
+0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064,
+0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c,
+0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002,
+0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c,
+0x8f42035c, 0x114b0006, 0x0, 0x8f420360,
+0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360,
+0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364,
+0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044,
+0x8f440088, 0x8f430078, 0x24420001, 0x441024,
+0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c,
+0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e,
+0x0, 0x934205c4, 0x10400009, 0x0,
+0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c,
+0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc,
+0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020,
+0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004,
+0x8c450008, 0xa44a000e, 0xac440000, 0xac450004,
+0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c,
+0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff,
+0x2484fffc, 0x801821, 0x8f440250, 0x8f450254,
+0x8f460118, 0x1021, 0xa32821, 0xa3382b,
+0x822021, 0x872021, 0xaf440250, 0xc0f809,
+0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0,
+0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0,
+0x3e00008, 0x27bd00d0, 0x3e00008, 0x0,
+0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc,
+0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac,
+0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c,
+0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e,
+0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4,
+0x10000130, 0xafab006c, 0x8f420114, 0x40f809,
+0x0, 0x403021, 0x10c002a1, 0x0,
+0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024,
+0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc,
+0xafa20064, 0x3c020006, 0x2c21024, 0x14400015,
+0xafac006c, 0x93c20000, 0x30420001, 0x10400011,
+0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff,
+0x97c30004, 0x1062000b, 0x0, 0xc0024bb,
+0x3c02021, 0x304200ff, 0x14400006, 0x0,
+0x8f420118, 0x40f809, 0x0, 0x10000280,
+0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff,
+0x431024, 0x3c03ffff, 0x431824, 0x14600003,
+0xafa20024, 0x10000040, 0x8021, 0x3c020080,
+0x621024, 0x10400007, 0x0, 0x8f42038c,
+0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036,
+0x24100001, 0x8f420210, 0x24420001, 0xaf420210,
+0x8f420210, 0x3c020001, 0x621024, 0x10400006,
+0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4,
+0x8f4201c4, 0x3c020002, 0x621024, 0x10400006,
+0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c,
+0x8f42037c, 0x3c020004, 0x621024, 0x10400006,
+0x3c020008, 0x8f420380, 0x24420001, 0xaf420380,
+0x8f420380, 0x3c020008, 0x621024, 0x10400006,
+0x3c020010, 0x8f420384, 0x24420001, 0xaf420384,
+0x8f420384, 0x3c020010, 0x621024, 0x10400006,
+0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0,
+0x8f4201c0, 0x3c020020, 0x621024, 0x10400006,
+0x24100001, 0x8f420388, 0x24420001, 0xaf420388,
+0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064,
+0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8,
+0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c,
+0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010,
+0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0,
+0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007,
+0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010,
+0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400,
+0x8fab006c, 0x3c020080, 0x34420100, 0x1621024,
+0x10400005, 0x0, 0x8f42020c, 0x24420001,
+0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064,
+0x32c20400, 0x10400012, 0x34028100, 0x97c3000c,
+0x1462000f, 0x0, 0x240c0200, 0xa7ac0076,
+0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064,
+0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e,
+0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004,
+0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100,
+0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001,
+0x621825, 0x10600015, 0x2821, 0x32c20800,
+0x10400015, 0x24020800, 0x97c30014, 0x14620012,
+0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021,
+0x97c30010, 0x24020300, 0x14620004, 0x801021,
+0x97c20012, 0x2c440001, 0x801021, 0x54400006,
+0x24050016, 0x10000004, 0x0, 0x24020800,
+0x50820001, 0x2405000e, 0x10a00013, 0x3c52021,
+0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b,
+0x10400003, 0x0, 0x8f420148, 0x621823,
+0x90620000, 0x38430006, 0x2c630001, 0x38420011,
+0x2c420001, 0x621825, 0x10600004, 0x3c020100,
+0x94820002, 0x453821, 0x3c020100, 0x2c21024,
+0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008,
+0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064,
+0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014,
+0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080,
+0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000,
+0x10400034, 0x240b0003, 0x32c21000, 0x10400031,
+0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350,
+0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350,
+0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025,
+0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001,
+0x248468d0, 0x26620001, 0xafa20014, 0xafa30010,
+0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b,
+0x34a55300, 0x10000162, 0x0, 0x8ea20000,
+0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010,
+0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b,
+0x603021, 0x10000156, 0x0, 0x8f420084,
+0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001,
+0x2c21024, 0x10400004, 0x0, 0x240c0002,
+0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020,
+0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021,
+0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b,
+0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c,
+0x26220001, 0x304201ff, 0xafa20054, 0x111140,
+0x431021, 0x1000006b, 0x2e2a821, 0x8f420044,
+0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014,
+0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007,
+0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf,
+0x282a024, 0x24630001, 0xaf430350, 0x10000124,
+0x8f420350, 0x156c001d, 0x0, 0x8f430074,
+0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074,
+0xafab004c, 0x26220001, 0x304203ff, 0xafa20054,
+0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821,
+0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8,
+0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074,
+0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b,
+0xafab005c, 0x1000ffc3, 0x0, 0x8f430064,
+0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064,
+0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff,
+0xafa20054, 0x24020004, 0x1562000e, 0x111140,
+0x111180, 0x24420cc0, 0x2e21021, 0xafa20044,
+0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b,
+0x10400024, 0x25950020, 0x240c0001, 0x10000021,
+0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821,
+0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4,
+0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060,
+0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008,
+0x2c21024, 0x1440ff61, 0x0, 0x8f420370,
+0x240c0001, 0xafac005c, 0x24420001, 0xaf420370,
+0x1000ff90, 0x8f420370, 0x27a30036, 0x131040,
+0x621821, 0x94620000, 0x441021, 0x1000001f,
+0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084,
+0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c,
+0x25620020, 0xafa20028, 0x25620008, 0xafa20030,
+0x25620010, 0xafab002c, 0xafa20034, 0x9562002a,
+0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a,
+0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018,
+0x24630002, 0x822023, 0x1880ffdf, 0x26730001,
+0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc,
+0x262102a, 0x14400030, 0x24030001, 0x8f83012c,
+0x10600028, 0x0, 0x8f820124, 0x431023,
+0x22143, 0x58800001, 0x24840040, 0x8f820128,
+0x431023, 0x21943, 0x58600001, 0x24630040,
+0x64102a, 0x54400001, 0x602021, 0xaf4400fc,
+0x8f4200fc, 0x262102a, 0x10400016, 0x24030001,
+0x1000001a, 0x306200ff, 0x8fac008c, 0x101040,
+0x4c1021, 0x94470018, 0x101080, 0x4c1021,
+0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc,
+0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500,
+0x2003021, 0xc002b3b, 0xafa30014, 0x10000039,
+0x0, 0x8f420334, 0x1821, 0x24420001,
+0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06,
+0x8021, 0x8f430008, 0x2402fbff, 0x1260002d,
+0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c,
+0x2669ffff, 0x2209021, 0x8e420008, 0x96270018,
+0x8c440000, 0x8c450004, 0x56090004, 0x240b0001,
+0x240c0002, 0x10000002, 0xafac0010, 0xafab0010,
+0x16000004, 0xafa80014, 0x8f420008, 0x10000002,
+0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021,
+0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0,
+0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2,
+0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021,
+0x5e102b, 0x10400003, 0x26310002, 0x8f420148,
+0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda,
+0x26520004, 0x8fb00064, 0x1000001a, 0x0,
+0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001,
+0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c,
+0x240c0002, 0xafac0010, 0x934305c4, 0xb1700,
+0x10600003, 0x2223025, 0x3c020800, 0xc23025,
+0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c,
+0x3c03021, 0x40f809, 0x2003821, 0x1040fecb,
+0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e,
+0x934205c4, 0x14400004, 0x0, 0x97ab007e,
+0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff,
+0x1821024, 0x10400003, 0xc1402, 0x34630400,
+0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006,
+0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e,
+0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f,
+0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064,
+0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4,
+0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c,
+0xad8b0000, 0x8fac0064, 0x1580feba, 0x0,
+0x8fab0064, 0x1160001b, 0x0, 0x934205c4,
+0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0,
+0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076,
+0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c,
+0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008,
+0xa44c000e, 0xac440000, 0xac450004, 0xac460008,
+0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010,
+0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc,
+0x801821, 0x8f440250, 0x8f450254, 0x8f460118,
+0x1021, 0xa32821, 0xa3382b, 0x822021,
+0x872021, 0xaf440250, 0xc0f809, 0xaf450254,
+0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4,
+0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008,
+0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8,
+0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048,
+0x10620034, 0x0, 0x8f430048, 0x8f42004c,
+0x622023, 0x4820001, 0x24840200, 0x8f430054,
+0x8f42004c, 0x43102b, 0x14400004, 0x24020200,
+0x8f43004c, 0x10000005, 0x431023, 0x8f420054,
+0x8f43004c, 0x431023, 0x2442ffff, 0x405021,
+0x8a102a, 0x54400001, 0x805021, 0x8f49004c,
+0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c,
+0x24071000, 0xafa70010, 0x84140, 0x1001821,
+0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014,
+0x1021, 0x63140, 0xafa70018, 0xa32821,
+0xa3382b, 0x822021, 0x872021, 0x3402ecc0,
+0xc23021, 0x8f420108, 0x2e63021, 0x40f809,
+0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c,
+0x8f420048, 0x14620018, 0x0, 0x8f420000,
+0x10400007, 0x0, 0xaf80004c, 0x8f82004c,
+0x1040fffd, 0x0, 0x10000005, 0x0,
+0xaf800048, 0x8f820048, 0x1040fffd, 0x0,
+0x8f820060, 0x2403fdff, 0x431024, 0xaf820060,
+0x8f420000, 0x10400003, 0x0, 0x10000002,
+0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020,
+0x3e00008, 0x27bd0028, 0x3e00008, 0x0,
+0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c,
+0x8f420058, 0x10620049, 0x0, 0x8f430058,
+0x8f42005c, 0x622023, 0x4820001, 0x24840100,
+0x8f430064, 0x8f42005c, 0x43102b, 0x14400004,
+0x24020100, 0x8f43005c, 0x10000005, 0x431023,
+0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff,
+0x403821, 0x87102a, 0x54400001, 0x803821,
+0x8f42005c, 0x471021, 0x305000ff, 0x32c21000,
+0x10400015, 0x24082000, 0x8f49005c, 0x8f440190,
+0x8f450194, 0x8f46005c, 0x73980, 0xafa80010,
+0xafb00014, 0x8f480014, 0x94980, 0x1201821,
+0x1021, 0xa32821, 0xa3482b, 0x822021,
+0x892021, 0x63180, 0xafa80018, 0x8f420108,
+0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190,
+0x8f450194, 0x8f46005c, 0x73940, 0xafa80010,
+0xafb00014, 0x8f480014, 0x94940, 0x1201821,
+0x1021, 0xa32821, 0xa3482b, 0x822021,
+0x892021, 0x63140, 0xafa80018, 0x8f420108,
+0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001,
+0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018,
+0x0, 0x8f420000, 0x10400007, 0x0,
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+0x10000005, 0x0, 0xaf800048, 0x8f820048,
+0x1040fffd, 0x0, 0x8f820060, 0x2403feff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024,
+0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033,
+0x0, 0x8f430068, 0x8f42006c, 0x622023,
+0x4820001, 0x24840400, 0x8f430074, 0x8f42006c,
+0x43102b, 0x14400004, 0x24020400, 0x8f43006c,
+0x10000005, 0x431023, 0x8f420074, 0x8f43006c,
+0x431023, 0x2442ffff, 0x405021, 0x8a102a,
+0x54400001, 0x805021, 0x8f49006c, 0x8f48006c,
+0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000,
+0xafa70010, 0x84140, 0x1001821, 0x12a4821,
+0x313003ff, 0xafb00014, 0x8f470014, 0x1021,
+0x63140, 0x24c66cc0, 0xafa70018, 0xa32821,
+0xa3382b, 0x822021, 0x872021, 0x8f420108,
+0x2e63021, 0x40f809, 0xa3940, 0x54400001,
+0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018,
+0x0, 0x8f420000, 0x10400007, 0x0,
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0,
+0x10000005, 0x0, 0xaf800048, 0x8f820048,
+0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff,
+0x431024, 0xaf820060, 0x8f420000, 0x10400003,
+0x0, 0x10000002, 0xaf80004c, 0xaf800048,
+0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x8f4200fc, 0x3c030001,
+0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc,
+0x8f850128, 0x2e31021, 0x54820004, 0x24820008,
+0x3c020001, 0x34422ec8, 0x2e21021, 0x401821,
+0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004,
+0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128,
+0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004,
+0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021,
+0x401821, 0x8c620004, 0x21140, 0xa21021,
+0xaf820128, 0xac600000, 0x8ca30018, 0x30620070,
+0x1040002d, 0x30620020, 0x10400004, 0x3c020010,
+0x2c21024, 0x1040000d, 0x0, 0x30620040,
+0x10400004, 0x3c020020, 0x2c21024, 0x10400007,
+0x0, 0x30620010, 0x1040001f, 0x3c020040,
+0x2c21024, 0x1440001c, 0x0, 0x8f820040,
+0x30420001, 0x14400008, 0x2021, 0x8c030104,
+0x24020001, 0x50620005, 0x24040001, 0x8c020264,
+0x10400003, 0x801021, 0x24040001, 0x801021,
+0x10400006, 0x0, 0x8f42030c, 0x24420001,
+0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044,
+0x34420004, 0xaf820044, 0x8f420308, 0x24420001,
+0xaf420308, 0x8f420308, 0x3e00008, 0x0,
+0x3e00008, 0x0, 0x27bdff98, 0xafbf0060,
+0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050,
+0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001,
+0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128,
+0x8d030018, 0x30620070, 0x1040002e, 0x30620020,
+0x10400004, 0x3c020010, 0x2c21024, 0x1040000d,
+0x0, 0x30620040, 0x10400004, 0x3c020020,
+0x2c21024, 0x10400007, 0x0, 0x30620010,
+0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6,
+0x0, 0x8f820040, 0x30420001, 0x14400008,
+0x2021, 0x8c030104, 0x24020001, 0x50620005,
+0x24040001, 0x8c020264, 0x10400003, 0x801021,
+0x24040001, 0x801021, 0x10400006, 0x0,
+0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192,
+0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044,
+0x8f420308, 0x24420001, 0xaf420308, 0x1000018a,
+0x8f420308, 0x30620002, 0x1040014b, 0x3c020800,
+0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016,
+0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001,
+0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0,
+0x431021, 0x10000010, 0x2e2a821, 0x24020002,
+0x15420005, 0x24020003, 0x1e1140, 0x24426cc0,
+0x10000009, 0x2e2a821, 0x15420005, 0x1e1180,
+0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821,
+0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc,
+0x30420400, 0x10400003, 0xafaa002c, 0x100000e1,
+0x8821, 0x10800004, 0x8821, 0x97b10026,
+0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c,
+0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870,
+0x2c420001, 0x621825, 0x10600015, 0x2021,
+0x32c20800, 0x10400015, 0x24020800, 0x96630014,
+0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007,
+0x2821, 0x96630010, 0x24020300, 0x14620004,
+0xa01021, 0x96620012, 0x2c450001, 0xa01021,
+0x54400006, 0x24040016, 0x10000004, 0x0,
+0x24020800, 0x50a20001, 0x2404000e, 0x108000b9,
+0x2649021, 0x92420000, 0x3042000f, 0x28080,
+0x32c20100, 0x10400020, 0x2501821, 0x3c020020,
+0x43102b, 0x1440000e, 0x2402021, 0x2821,
+0x94820000, 0x24840002, 0xa22821, 0x83102b,
+0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821,
+0x51c02, 0x30a2ffff, 0x10000009, 0x622821,
+0x8f470148, 0x8f420110, 0x102842, 0x3c060020,
+0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040,
+0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002,
+0x10000002, 0xafaa002c, 0x2821, 0x32c20080,
+0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f,
+0x3442ffff, 0x43102b, 0x10400003, 0x0,
+0x8f420148, 0x621823, 0x90660000, 0x30c200ff,
+0x38430006, 0x2c630001, 0x38420011, 0x2c420001,
+0x621825, 0x1060007f, 0x24020800, 0x8821,
+0x97a3003e, 0x1462000f, 0x2602021, 0x96710000,
+0x96620002, 0x96630004, 0x96640006, 0x2228821,
+0x2238821, 0x2248821, 0x96620008, 0x9663000a,
+0x9664000c, 0x2228821, 0x2238821, 0x10000007,
+0x2248821, 0x94820000, 0x24840002, 0x2228821,
+0x92102b, 0x1440fffb, 0x0, 0x111c02,
+0x3222ffff, 0x628821, 0x111c02, 0x3222ffff,
+0x628821, 0x32c20200, 0x10400003, 0x26440006,
+0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
+0x822023, 0x94820000, 0x30421fff, 0x10400004,
+0x2644000c, 0x96420002, 0x10000030, 0x508023,
+0x96420002, 0x26430014, 0x508023, 0x3c020020,
+0x43102b, 0x1440000a, 0xd08021, 0x9642000c,
+0x2028021, 0x9642000e, 0x96430010, 0x96440012,
+0x2028021, 0x2038021, 0x10000020, 0x2048021,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
+0x822023, 0x94820000, 0x24840002, 0x2028021,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
+0x822023, 0x94820000, 0x24840002, 0x2028021,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
+0x822023, 0x94820000, 0x24840002, 0x2028021,
+0xa4102b, 0x10400003, 0x0, 0x8f420148,
+0x822023, 0x94820000, 0x2028021, 0x3c020100,
+0x2c21024, 0x1040000e, 0x0, 0x8faa002c,
+0x31420004, 0x1040000a, 0x0, 0x9504000e,
+0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff,
+0x2228821, 0x111c02, 0x3222ffff, 0x628821,
+0x8faa0024, 0x1518823, 0x111402, 0x2228821,
+0x2308821, 0x111402, 0x2228821, 0x3231ffff,
+0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001,
+0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e,
+0x8faa002c, 0x31420004, 0x10400002, 0x24091000,
+0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4,
+0xafa90010, 0x8f490044, 0x84140, 0x1001821,
+0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020,
+0xafa80018, 0x8f48010c, 0x1021, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x1440000b, 0x0, 0x8f820128, 0x3c040001,
+0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124,
+0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920,
+0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044,
+0x8f430088, 0x24420001, 0x431024, 0xaf420044,
+0x8faa0034, 0x8f440368, 0x24020001, 0x15420006,
+0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c,
+0x10000049, 0x8f42035c, 0x15420006, 0x0,
+0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042,
+0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360,
+0x1000003d, 0x8f420360, 0x30621000, 0x10400005,
+0x30628000, 0x8f420078, 0x24420001, 0x10000036,
+0xaf420078, 0x10400034, 0x0, 0x8f420078,
+0x24420001, 0xaf420078, 0x8c030240, 0x43102b,
+0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c,
+0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040,
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c,
+0x40f809, 0x24c6001c, 0x14400011, 0x24020001,
+0x3c010001, 0x370821, 0xa02240f2, 0x8f820124,
+0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c,
+0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009,
+0xc002b3b, 0x34a51300, 0x1000000b, 0x0,
+0x8f420304, 0x24420001, 0xaf420304, 0x8f420304,
+0x8f420044, 0xaf42007c, 0x3c010001, 0x370821,
+0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001,
+0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c,
+0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c,
+0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008,
+0x0, 0x0, 0x0, 0x8f42013c,
+0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c,
+0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138,
+0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8,
+0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018,
+0xc002bbf, 0x24060008, 0x8c020204, 0xc004012,
+0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002,
+0x1040000e, 0x2021, 0x8c060248, 0x24020002,
+0x3c010001, 0xac226d98, 0xc005104, 0x24050002,
+0x2021, 0x8c060248, 0x24020001, 0x3c010001,
+0xac226d98, 0x10000011, 0x24050001, 0x8c060248,
+0x24020004, 0x3c010001, 0xac226d98, 0xc005104,
+0x24050004, 0x3c020001, 0x8c426d94, 0x30420001,
+0x10400008, 0x24020001, 0x3c010001, 0xac226d98,
+0x2021, 0x24050001, 0x3c06601b, 0xc005104,
+0x0, 0x3c040001, 0x248469d0, 0x8f420150,
+0x8f430154, 0x3c050008, 0x8f460158, 0x21640,
+0x31940, 0x34630403, 0x431025, 0x633c0,
+0x461025, 0xaf82021c, 0xafa00010, 0xafa00014,
+0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821,
+0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8,
+0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0,
+0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010,
+0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc,
+0xc002b3b, 0x3821, 0x8f420410, 0x24420001,
+0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c,
+0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4,
+0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010,
+0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8,
+0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821,
+0x3c044000, 0x2041024, 0x504000b4, 0x3c040100,
+0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc,
+0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823,
+0x43102b, 0x10400003, 0x0, 0x8f420148,
+0x621821, 0x10600005, 0x0, 0x8f42014c,
+0x43102b, 0x1040000b, 0x0, 0x8f8200e0,
+0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220,
+0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce,
+0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420004, 0xaf820220, 0x8f8200e0,
+0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8,
+0x8f840120, 0x8f830124, 0x10000005, 0x2821,
+0x14620002, 0x24620020, 0x27624800, 0x401821,
+0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003,
+0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001,
+0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008,
+0x30a200ff, 0x14400058, 0x0, 0x934205c4,
+0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0,
+0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023,
+0x218c3, 0x4620001, 0x24630200, 0x10600005,
+0x24020001, 0x10620009, 0x0, 0x1000001f,
+0x0, 0x8f4203c0, 0xe03021, 0x24420001,
+0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4,
+0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148,
+0x8f4303c4, 0xe61823, 0x43102b, 0x10400004,
+0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f,
+0x14400031, 0x0, 0x8f42020c, 0x24420001,
+0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008,
+0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8,
+0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000,
+0x8f420148, 0xa71823, 0x43102b, 0x10400003,
+0x0, 0x8f420148, 0x621821, 0x8f42014c,
+0x43102b, 0x5440000a, 0xa03021, 0x8f42020c,
+0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008,
+0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8,
+0x1488000d, 0x27623000, 0x14820002, 0x2482fff8,
+0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff,
+0xc33021, 0x46102b, 0x10400003, 0x0,
+0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4,
+0x8f420148, 0xc31823, 0x43102b, 0x10400003,
+0x0, 0x8f420148, 0x621821, 0x10600005,
+0x0, 0x8f42014c, 0x43102b, 0x50400008,
+0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb,
+0x431024, 0x3c034000, 0x1000003f, 0x431025,
+0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001,
+0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024,
+0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001,
+0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff,
+0x3463ffff, 0x431024, 0x441025, 0xc003daf,
+0xaf820220, 0x10000029, 0x0, 0x2111024,
+0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001,
+0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019,
+0x0, 0x2111024, 0x1040001c, 0x0,
+0x8f830224, 0x24021402, 0x14620009, 0x3c050008,
+0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014,
+0x8f860224, 0x34a50500, 0xc002b3b, 0x3821,
+0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0,
+0x8f820220, 0x2002021, 0x34420002, 0xc004e9c,
+0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x511025, 0xaf820220, 0x8fbf0020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028,
+0x3e00008, 0x0, 0x3c020001, 0x8c426da8,
+0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040,
+0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f,
+0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600,
+0x24020001, 0x3c010001, 0xac206da8, 0x3c010001,
+0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff,
+0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024,
+0xac020268, 0x8f420004, 0x3484ffff, 0x30420002,
+0x10400092, 0x284a024, 0x3c040600, 0x34842000,
+0x8f420004, 0x2821, 0x2403fffd, 0x431024,
+0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020,
+0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001,
+0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0,
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c,
+0x8c020228, 0x3c040001, 0x24846998, 0x3c050009,
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d,
+0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024,
+0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054,
+0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b,
+0x9821, 0xe08821, 0x263504c0, 0x8f440178,
+0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010,
+0xafb20014, 0x8f48000c, 0x1021, 0x2f53021,
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821,
+0xa3482b, 0x822021, 0x100f809, 0x892021,
+0x54400006, 0x24130001, 0x8f820054, 0x2021023,
+0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff,
+0x54400017, 0xaf520018, 0x8f420378, 0x24420001,
+0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c,
+0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4,
+0x3c050009, 0xafa20014, 0x8d460000, 0x10000035,
+0x34a50600, 0x8f420308, 0x24130001, 0x24420001,
+0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff,
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023,
+0x2c4203e9, 0x10400016, 0x9821, 0x3c150020,
+0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164,
+0x8f860120, 0xafb10010, 0xafb20014, 0x551025,
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809,
+0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054,
+0x2021023, 0x2c4203e9, 0x1440ffee, 0x0,
+0x326200ff, 0x14400011, 0x0, 0x8f420378,
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120,
+0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001,
+0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000,
+0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec,
+0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048,
+0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038,
+0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050,
+0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d,
+0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008,
+0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700,
+0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b,
+0x3821, 0x3c020004, 0x2c21024, 0x10400007,
+0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff,
+0x431024, 0x34420008, 0xaf820220, 0x3c050001,
+0x8ca56d98, 0x24020001, 0x14a20007, 0x2021,
+0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c,
+0x10000006, 0x3c020007, 0xc00529b, 0x2021,
+0xac020268, 0x8c030268, 0x3c020007, 0x621824,
+0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b,
+0x14400006, 0x3c020004, 0x3c020001, 0x10620009,
+0x3c020098, 0x1000000b, 0x0, 0x14620009,
+0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002,
+0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc,
+0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x0, 0x0, 0x0, 0x86102b,
+0x50400001, 0x872023, 0xc41023, 0x24843,
+0x125102b, 0x1040001b, 0x91040, 0x824021,
+0x88102b, 0x10400007, 0x1821, 0x94820000,
+0x24840002, 0x621821, 0x88102b, 0x1440fffb,
+0x0, 0x602021, 0xc73023, 0xa91023,
+0x21040, 0xc22821, 0xc5102b, 0x10400007,
+0x1821, 0x94c20000, 0x24c60002, 0x621821,
+0xc5102b, 0x1440fffb, 0x0, 0x1000000d,
+0x832021, 0x51040, 0x822821, 0x85102b,
+0x10400007, 0x1821, 0x94820000, 0x24840002,
+0x621821, 0x85102b, 0x1440fffb, 0x0,
+0x602021, 0x41c02, 0x3082ffff, 0x622021,
+0x41c02, 0x3082ffff, 0x622021, 0x3e00008,
+0x3082ffff, 0x3e00008, 0x0, 0x802821,
+0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff,
+0x24a20004, 0x62102b, 0x54400007, 0x65102b,
+0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002,
+0x1000002a, 0x441021, 0x10400003, 0x0,
+0x8f420148, 0xa22823, 0x90a40000, 0x24a50001,
+0x65102b, 0x10400003, 0x0, 0x8f420148,
+0xa22823, 0x90a20000, 0x24a50001, 0x21200,
+0x822021, 0x65102b, 0x10400003, 0x0,
+0x8f420148, 0xa22823, 0x90a20000, 0x24a50001,
+0x822021, 0x65102b, 0x10400003, 0x0,
+0x8f420148, 0xa22823, 0x90a20000, 0x1000002d,
+0x21200, 0x3463ffff, 0x24a20004, 0x62102b,
+0x5440000a, 0x65102b, 0x90a20000, 0x90a40002,
+0x90a30001, 0x90a50003, 0x441021, 0x21200,
+0x651821, 0x10000020, 0x432021, 0x10400003,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
+0x24a50001, 0x22200, 0x65102b, 0x10400003,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
+0x24a50001, 0x822021, 0x65102b, 0x10400003,
+0x0, 0x8f420148, 0xa22823, 0x90a20000,
+0x24a50001, 0x21200, 0x822021, 0x65102b,
+0x10400003, 0x0, 0x8f420148, 0xa22823,
+0x90a20000, 0x822021, 0x41c02, 0x3082ffff,
+0x622021, 0x41c02, 0x3082ffff, 0x622021,
+0x3e00008, 0x3082ffff, 0x0, 0x8f820220,
+0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8,
+0x30424000, 0x10400054, 0x24040001, 0x8f820200,
+0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd,
+0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820224, 0x1444004d, 0x42040, 0xc4102b,
+0x1040fff1, 0x0, 0x8f820200, 0x451025,
+0xaf820200, 0x8f820220, 0x34428000, 0xaf820220,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820220, 0x3c030004, 0x431024,
+0x1440000f, 0x0, 0x8f820220, 0x3c03ffff,
+0x34637fff, 0x431024, 0xaf820220, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820220, 0x3c030004, 0x431024, 0x1440000d,
+0x0, 0x8f820220, 0x34428000, 0xaf820220,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x8f820220, 0x3c030004, 0x431024,
+0x1040001b, 0x1021, 0x8f830220, 0x24020001,
+0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700,
+0x441025, 0xaf820220, 0x8f820220, 0x2403fffd,
+0x431024, 0xaf820220, 0x8f820220, 0x3c030300,
+0x431024, 0x14400003, 0x0, 0x10000008,
+0x1021, 0x8f820220, 0x34420002, 0xaf820220,
+0x8f830220, 0x24020001, 0x641825, 0xaf830220,
+0x3e00008, 0x0, 0x2021, 0x3c050100,
+0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220,
+0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4,
+0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0,
+0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8,
+0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4,
+0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0,
+0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8,
+0x418c0, 0x24840001, 0x3631021, 0xac453004,
+0x3631021, 0xac403000, 0x28820200, 0x1440fff9,
+0x418c0, 0x2021, 0x418c0, 0x24840001,
+0x3631021, 0xac402804, 0x3631021, 0xac402800,
+0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c,
+0x24030080, 0x24040100, 0xac600000, 0x24630004,
+0x64102b, 0x5440fffd, 0xac600000, 0x8f830040,
+0x3c02f000, 0x621824, 0x3c025000, 0x1062000c,
+0x43102b, 0x14400006, 0x3c026000, 0x3c024000,
+0x10620008, 0x24020800, 0x10000008, 0x0,
+0x10620004, 0x24020800, 0x10000004, 0x0,
+0x24020700, 0x3c010001, 0xac226dac, 0x3e00008,
+0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0,
+0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020,
+0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e,
+0x0, 0x3c010001, 0xac206dbc, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0xc004db9, 0x0, 0x24040001, 0x2821,
+0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630064,
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc,
+0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c,
+0x24050002, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630064, 0x8f820054, 0x621023, 0x2c420065,
+0x1440fffc, 0x24040001, 0x24050003, 0x3c100001,
+0x26106f26, 0xc00457c, 0x2003021, 0x97a60018,
+0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0,
+0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100,
+0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d,
+0x24036040, 0x96020000, 0x3042fff0, 0x1443000c,
+0x24020020, 0x3c030001, 0x94636f24, 0x1462000b,
+0x24027830, 0x24020003, 0x3c010001, 0xac226d94,
+0x24020005, 0x3c010001, 0x1000003f, 0xac226f34,
+0x3c030001, 0x94636f24, 0x24027830, 0x1462000c,
+0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0,
+0x14430007, 0x24020003, 0x3c010001, 0xac226d94,
+0x24020006, 0x3c010001, 0x1000002f, 0xac226f34,
+0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24,
+0x34420001, 0x3c010001, 0xac226d94, 0x24020015,
+0x1462000b, 0x0, 0x3c020001, 0x94426f26,
+0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430,
+0x2c420001, 0x621825, 0x1460001b, 0x24020003,
+0x3c030001, 0x94636f24, 0x24027810, 0x14620016,
+0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0,
+0x14400011, 0x24020002, 0x1000000f, 0x24020004,
+0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001,
+0xac226d94, 0x1000005e, 0x24020004, 0x3c020001,
+0x8c426d94, 0x34420004, 0x3c010001, 0x100000af,
+0xac226d94, 0x24020001, 0x3c010001, 0xac226f40,
+0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2,
+0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054,
+0x8f820054, 0x24030008, 0x3c010001, 0xac236d98,
+0x10000002, 0x248401f4, 0x8f820054, 0x821023,
+0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb,
+0xaf820238, 0x8f830054, 0x8f820054, 0x10000002,
+0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5,
+0x1440fffc, 0x8021, 0x24120001, 0x24110009,
+0xc004482, 0x0, 0x3c010001, 0xac326db4,
+0xc004547, 0x0, 0x3c020001, 0x8c426db4,
+0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238,
+0x8f830054, 0x8f820054, 0x10000002, 0x2463000a,
+0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc,
+0x0, 0x8f820220, 0x24040001, 0x34420002,
+0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd,
+0x621824, 0xaf830200, 0xaf840204, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x8f820224, 0x14440005, 0x34028000, 0x42040,
+0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0,
+0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004,
+0x3c010001, 0xac226d98, 0x8021, 0x24120009,
+0x3c11ffff, 0x36313f7f, 0xc004482, 0x0,
+0x24020001, 0x3c010001, 0xac226db4, 0xc004547,
+0x0, 0x3c020001, 0x8c426db4, 0x1452fffb,
+0x0, 0x8f820044, 0x511024, 0x34425080,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x2463000a, 0x8f820054, 0x621023, 0x2c42000b,
+0x1440fffc, 0x0, 0x8f820044, 0x511024,
+0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x2463000a, 0x8f820054, 0x621023,
+0x2c42000b, 0x1440fffc, 0x0, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630064, 0x8f820054,
+0x621023, 0x2c420065, 0x1440fffc, 0x0,
+0x8f820220, 0x24040001, 0x34420002, 0xaf820220,
+0x8f830200, 0x24057fff, 0x2402fffd, 0x621824,
+0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820224,
+0x14440005, 0x34028000, 0x42040, 0xa4102b,
+0x1040fff0, 0x34028000, 0x1082ff50, 0x26100001,
+0x2e020064, 0x1440ffb0, 0x0, 0x3c020001,
+0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0,
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024,
+0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001,
+0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001,
+0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001,
+0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001,
+0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001,
+0xac206d98, 0x491021, 0x3c010001, 0xac226f30,
+0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c,
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008,
+0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98,
+0x24060004, 0x24020001, 0x14a20014, 0xafbf0010,
+0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005,
+0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005,
+0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40,
+0x348493e0, 0x24020005, 0x14620016, 0x0,
+0x3c04003d, 0x10000013, 0x34840900, 0x3c020002,
+0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e,
+0x3c030001, 0x8c636f40, 0x10000005, 0x34848480,
+0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240,
+0x24020005, 0x14620003, 0x0, 0x3c04007a,
+0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054,
+0x441021, 0x431023, 0x44102b, 0x1440004c,
+0x0, 0x3c020001, 0x8c426da0, 0x14400048,
+0x0, 0x3c010001, 0x10c00025, 0xac206db0,
+0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000,
+0x3c080002, 0x25088ffc, 0x250afffc, 0x52842,
+0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024,
+0x10400010, 0x0, 0x14a70008, 0x0,
+0x8d020000, 0x441024, 0x1040000a, 0x0,
+0x3c010001, 0x10000007, 0xac256db0, 0x8d420000,
+0x441024, 0x10400003, 0x0, 0x3c010001,
+0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b,
+0x2c420001, 0x431024, 0x5440ffe5, 0x52842,
+0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001,
+0xac226f30, 0x1060003b, 0x24020005, 0x3c030001,
+0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012,
+0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000,
+0x34635000, 0x431024, 0x14400006, 0x24020001,
+0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98,
+0x24020001, 0x3c010001, 0xac226e24, 0x3c010001,
+0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c,
+0x3c020001, 0x8c426db0, 0x1040001e, 0x0,
+0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001,
+0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001,
+0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8,
+0x24020008, 0x10620005, 0x24020001, 0xc004239,
+0x0, 0x1000000b, 0x0, 0x3c030001,
+0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002,
+0x8c638f90, 0x10620003, 0x0, 0xc004e9c,
+0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018,
+0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98,
+0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024,
+0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001,
+0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8,
+0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4,
+0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c,
+0x2c620003, 0x10400005, 0x24020001, 0x1062000a,
+0x0, 0x10000226, 0x0, 0x24020004,
+0x106200b6, 0x24020008, 0x1062010a, 0x24020001,
+0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff,
+0x2c620008, 0x1040021c, 0x31080, 0x3c010001,
+0x220821, 0x8c226af8, 0x400008, 0x0,
+0x3c030001, 0x8c636f40, 0x24020005, 0x14620010,
+0x0, 0x3c020001, 0x8c426da4, 0x10400008,
+0x24020003, 0xc004482, 0x0, 0x24020002,
+0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4,
+0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30,
+0xc004482, 0x0, 0x3c020001, 0x8c426da4,
+0x3c010001, 0xac206d30, 0x1440017a, 0x24020002,
+0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40,
+0x24020005, 0x14620003, 0x24020001, 0x3c010001,
+0xac226dd0, 0xc0045ff, 0x0, 0x3c030001,
+0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001,
+0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104,
+0x2021, 0x24020005, 0x3c010001, 0xac206da4,
+0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec,
+0x3c05000f, 0x34a50100, 0x3021, 0x3821,
+0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6,
+0x0, 0x8f820220, 0x3c030004, 0x431024,
+0x14400175, 0x24020007, 0x8f830054, 0x3c020001,
+0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400003, 0x24020001, 0x3c010001, 0xac226d9c,
+0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2,
+0x0, 0x8f820220, 0x30428000, 0x1040017d,
+0x0, 0x10000175, 0x0, 0x3c050001,
+0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b,
+0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0,
+0x24020001, 0x3c020008, 0x621024, 0x10400006,
+0x0, 0x8f820214, 0x3c03ffff, 0x431024,
+0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff,
+0x431024, 0x3442241f, 0xaf820214, 0x8f820220,
+0x3c030200, 0x34420002, 0xaf820220, 0x24020008,
+0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004,
+0x431024, 0x14400016, 0x0, 0x3c020002,
+0x8c428ffc, 0x30425000, 0x1040000d, 0x0,
+0x8f820220, 0x30428000, 0x10400006, 0x0,
+0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003,
+0x431024, 0x8f820220, 0x34428000, 0xaf820220,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a,
+0x0, 0x3c020001, 0x94426f26, 0x24429fbc,
+0x2c420004, 0x10400004, 0x24040018, 0x24050002,
+0xc004ddb, 0x24060020, 0xc003e6d, 0x0,
+0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8,
+0x2443ffff, 0x2c620008, 0x1040016b, 0x31080,
+0x3c010001, 0x220821, 0x8c226b18, 0x400008,
+0x0, 0xc004547, 0x0, 0x3c030001,
+0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002,
+0x8c428ff8, 0x30424000, 0x10400004, 0x0,
+0x8f820044, 0x10000006, 0x3442f080, 0x8f820044,
+0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080,
+0xaf820044, 0x8f830054, 0x100000ea, 0x24020004,
+0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400147, 0x24020005,
+0x100000d8, 0x0, 0x8f820220, 0x3c03f700,
+0x431025, 0xaf820220, 0xaf800204, 0x3c010002,
+0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001,
+0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a,
+0x14400135, 0x24020007, 0x100000d7, 0x0,
+0xc003f50, 0x0, 0x1040012d, 0x24020001,
+0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c,
+0x431024, 0x3442251f, 0xaf820214, 0x24020008,
+0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44,
+0x10400064, 0x24020001, 0x8f820220, 0x3c030008,
+0x431024, 0x1040006a, 0x3c020200, 0x10000078,
+0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007,
+0x10400115, 0x31080, 0x3c010001, 0x220821,
+0x8c226b38, 0x400008, 0x0, 0xc003daf,
+0x0, 0x3c010001, 0xac206d9c, 0xaf800204,
+0x3c010002, 0xc004482, 0xac208fe0, 0x24020001,
+0x3c010001, 0xac226db4, 0x24020002, 0x10000102,
+0xaee204b8, 0xc004547, 0x0, 0x3c030001,
+0x8c636db4, 0x10000084, 0x24020009, 0x3c020002,
+0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8,
+0x10000002, 0x344201f6, 0x344201fe, 0xaf820238,
+0x8f830054, 0x1000008b, 0x24020004, 0x8f830054,
+0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023,
+0x2c422710, 0x144000e8, 0x24020005, 0x10000079,
+0x0, 0x8f820220, 0x3c03f700, 0x431025,
+0xaf820220, 0xaf800204, 0x3c010002, 0x10000077,
+0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28,
+0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6,
+0x24020007, 0x10000078, 0x0, 0xc003f50,
+0x0, 0x104000ce, 0x24020001, 0x8f820214,
+0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024,
+0x3442251f, 0xaf820214, 0x24020008, 0x1080000f,
+0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b,
+0x0, 0x8f820220, 0x34420002, 0xaf820220,
+0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c,
+0x8f840220, 0x10000016, 0x0, 0x8f820220,
+0x3c030008, 0x431024, 0x14400011, 0x3c020200,
+0x282a025, 0x2402000e, 0x3c010002, 0xac228f90,
+0xc00551b, 0x2021, 0x8f820220, 0x34420002,
+0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98,
+0xc00529b, 0x2021, 0x100000a3, 0x0,
+0x3c020001, 0x8c426e44, 0x1040009f, 0x0,
+0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001,
+0xac226e40, 0x14400098, 0x24020002, 0x3c010001,
+0xac206e44, 0x3c010001, 0x10000093, 0xac226e40,
+0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e,
+0x31080, 0x3c010001, 0x220821, 0x8c226b58,
+0x400008, 0x0, 0x3c020001, 0x8c426da4,
+0x10400018, 0x24020005, 0xc004482, 0x0,
+0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e,
+0xac206da4, 0xc004963, 0x0, 0x3c030001,
+0x8c636dd4, 0x24020006, 0x14620077, 0x24020003,
+0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98,
+0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021,
+0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0x8f830054,
+0x24020006, 0xaee204b8, 0x3c010001, 0x10000062,
+0xac236f28, 0x8f820220, 0x3c030004, 0x431024,
+0x10400003, 0x24020007, 0x1000005b, 0xaee204b8,
+0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400003, 0x24020001,
+0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8,
+0x30425000, 0x1040004c, 0x0, 0x8f820220,
+0x30428000, 0x10400007, 0x0, 0x8f820220,
+0x3c03ffff, 0x34637fff, 0x431024, 0x10000042,
+0xaf820220, 0x8f820220, 0x34428000, 0x1000003e,
+0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b,
+0x2021, 0xc00551b, 0x2021, 0x3c020002,
+0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214,
+0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214,
+0x24020008, 0xaee204b8, 0x8f820220, 0x34420002,
+0xaf820220, 0x8f820220, 0x3c030004, 0x431024,
+0x14400016, 0x0, 0x3c020002, 0x8c428ff8,
+0x30425000, 0x1040000d, 0x0, 0x8f820220,
+0x30428000, 0x10400006, 0x0, 0x8f820220,
+0x3c03ffff, 0x34637fff, 0x10000003, 0x431024,
+0x8f820220, 0x34428000, 0xaf820220, 0x8f820220,
+0x3c03f700, 0x431025, 0xaf820220, 0x3c020001,
+0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004,
+0x24040018, 0x24050002, 0xc004ddb, 0x24060020,
+0xc003e6d, 0x0, 0x10000003, 0x0,
+0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008,
+0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220,
+0x34420004, 0xaf820220, 0x8f820200, 0x3c050001,
+0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002,
+0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001,
+0x10a2000a, 0x0, 0x100000b1, 0x0,
+0x24020004, 0x10a20072, 0x24020008, 0x10a20085,
+0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050,
+0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40,
+0x621824, 0x3c020700, 0x621825, 0x24020e00,
+0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200,
+0xaf850220, 0x14800006, 0xaf820238, 0x8f820044,
+0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044,
+0x3c030001, 0x8c636f40, 0x24020005, 0x14620004,
+0x0, 0x8f820044, 0x34425000, 0xaf820044,
+0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40,
+0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c,
+0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001,
+0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000,
+0x621825, 0x641825, 0x1000000a, 0x34620002,
+0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac,
+0x3c040001, 0x8c846d8c, 0x431025, 0x441025,
+0x34420002, 0xaf820220, 0x1000002f, 0x24020001,
+0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff,
+0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824,
+0x3c020d00, 0x621825, 0x24020001, 0xaf830050,
+0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00,
+0x3c020001, 0x8c426d80, 0x10000004, 0x34630070,
+0x3c020001, 0x8c426d80, 0x34630072, 0x431025,
+0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700,
+0x621825, 0x3c020001, 0x8c426d90, 0x3c040001,
+0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025,
+0x441025, 0xaf820220, 0x24020005, 0x14a20006,
+0x24020001, 0x8f820044, 0x2403afff, 0x431024,
+0xaf820044, 0x24020001, 0x1000003d, 0xaf820238,
+0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001,
+0x8c846f1c, 0x621824, 0x3c020a00, 0x621825,
+0x24020001, 0xaf830050, 0xaf820200, 0x1080001e,
+0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a,
+0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a,
+0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c,
+0x3442ffff, 0x621824, 0x1080000f, 0xaf830050,
+0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00,
+0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001,
+0xaf820200, 0xaf820220, 0x641825, 0xaf830200,
+0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80,
+0x3c033f00, 0x346300e2, 0x431025, 0xaf820200,
+0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84,
+0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac,
+0x651825, 0x431025, 0x441025, 0xaf820220,
+0x3e00008, 0x0, 0x3c030001, 0x8c636db4,
+0x3c020001, 0x8c426db8, 0x10620003, 0x24020002,
+0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003,
+0x10400025, 0x24020001, 0x14620023, 0x24020004,
+0x3c030001, 0x8c636d98, 0x10620006, 0x24020008,
+0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009,
+0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044,
+0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080,
+0xaf820044, 0x8f830054, 0x24020002, 0x3c010001,
+0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c,
+0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0,
+0x431023, 0x2c422710, 0x14400003, 0x24020009,
+0x3c010001, 0xac226db4, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x27bdffd8,
+0xafb20018, 0x809021, 0xafb3001c, 0xa09821,
+0xafb10014, 0xc08821, 0xafb00010, 0x8021,
+0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x24100010, 0x2501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x2501024, 0x24100010, 0x2701024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x2701024, 0xc004db9, 0x34108000,
+0xc004db9, 0x0, 0xc004d58, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c,
+0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008,
+0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821,
+0xafb20018, 0xa09021, 0xafb3001c, 0xc09821,
+0xafb00010, 0x8021, 0xafbf0020, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0x24100010, 0x2301024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x2301024, 0x24100010, 0x2501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x2501024, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x34108000,
+0x96620000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+0x0, 0xc004db9, 0x0, 0x8fbf0020,
+0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010,
+0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0,
+0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020,
+0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001,
+0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005,
+0x14620005, 0x2483ffff, 0xc004963, 0x0,
+0x1000034c, 0x0, 0x2c620013, 0x10400349,
+0x31080, 0x3c010001, 0x220821, 0x8c226b80,
+0x400008, 0x0, 0xc004db9, 0x8021,
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010,
+0x8021, 0xc004d78, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004d78, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004db9, 0x34108000,
+0xc004db9, 0x0, 0xc004d58, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004db9, 0x0, 0x97a20010, 0x30428000,
+0x144002dc, 0x24020003, 0x100002d8, 0x0,
+0x24021200, 0xa7a20010, 0x27b10010, 0x8021,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0xc004d78, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0xc004d78, 0x24040001, 0xc004d78,
+0x2021, 0x34108000, 0x96220000, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fff8, 0x0, 0xc004db9,
+0x0, 0x8f830054, 0x10000296, 0x24020004,
+0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c,
+0x431023, 0x2c420064, 0x1440029e, 0x24020002,
+0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003,
+0x14400296, 0x24020011, 0x24020003, 0x10620005,
+0x24020004, 0x10620291, 0x2402000f, 0x1000028f,
+0x24020011, 0x1000028d, 0x24020005, 0x24020014,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020012,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020012, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+0x0, 0xc004db9, 0x0, 0x8f830054,
+0x10000248, 0x24020006, 0x8f830054, 0x3c020001,
+0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400250, 0x24020007, 0x1000024c, 0x0,
+0x24020006, 0xa7a20010, 0x27b10010, 0x8021,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020013, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020013,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x8f830054, 0x10000207, 0x24020008, 0x8f830054,
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440020f, 0x24020009, 0x1000020b,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x8021,
+0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x8f830054, 0x10000193, 0x2402000a, 0x8f830054,
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+0x2c420064, 0x1440019b, 0x2402000b, 0x10000197,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020017, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x8021,
+0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020017, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020017,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054,
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+0x2c420064, 0x14400127, 0x24020012, 0x10000123,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020014, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x8021,
+0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020014, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020014,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x8f830054, 0x100000ab, 0x24020013, 0x8f830054,
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023,
+0x2c420064, 0x144000b3, 0x2402000d, 0x100000af,
+0x0, 0x27b10010, 0xa7a00010, 0x8021,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x8021,
+0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x96220000, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x8f830054, 0x10000037, 0x2402000e, 0x24020840,
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x32020013,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020013, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x34108000,
+0x96220000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+0x0, 0xc004db9, 0x0, 0x8f830054,
+0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001,
+0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001,
+0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064,
+0x14400004, 0x0, 0x24020011, 0x3c010001,
+0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018,
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98,
+0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030,
+0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002,
+0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc,
+0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c,
+0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c,
+0x2463ffff, 0x2c620006, 0x10400377, 0x31080,
+0x3c010001, 0x220821, 0x8c226bd8, 0x400008,
+0x0, 0x2021, 0x2821, 0xc004ddb,
+0x34068000, 0x24040010, 0x24050002, 0x24060002,
+0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002,
+0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018,
+0xa7a00018, 0x8021, 0xc004d78, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0xc004d78, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0xc004db9,
+0x34108000, 0xc004db9, 0x0, 0xc004d58,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004db9, 0x0, 0x97a20018,
+0x30428000, 0x14400004, 0x24020003, 0x3c010001,
+0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a,
+0xac226dd4, 0x24040010, 0x24050002, 0x24060002,
+0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001,
+0x8c636e20, 0x24020001, 0x146201e1, 0x8021,
+0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
+0xc004db9, 0x0, 0xc004d58, 0x0,
+0x50400005, 0x108042, 0x96220000, 0x501025,
+0xa6220000, 0x108042, 0x1600fff7, 0x0,
+0xc004db9, 0x8021, 0x27b10018, 0xa7a00018,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0x24100010, 0x32020001,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x32020001, 0x24100010,
+0x32020018, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x96220000, 0x501025, 0xa6220000, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x8021,
+0x24040018, 0x2821, 0xc004ddb, 0x24060404,
+0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0x32020018, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x32020018, 0xc004db9, 0x34108000, 0xc004db9,
+0x0, 0xc004d58, 0x0, 0x50400005,
+0x108042, 0x97a2001a, 0x501025, 0xa7a2001a,
+0x108042, 0x1600fff7, 0x0, 0xc004db9,
+0x8021, 0xa7a0001a, 0xc004d78, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x24100010, 0x32020001, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x32020001, 0x24100010, 0x32020018, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020018, 0xc004db9, 0x34108000,
+0xc004db9, 0x0, 0xc004d58, 0x0,
+0x50400005, 0x108042, 0x97a2001a, 0x501025,
+0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
+0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
+0x2021, 0x24100010, 0xc004d78, 0x2021,
+0x108042, 0x1600fffc, 0x0, 0x24100010,
+0x3202001e, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x3202001e,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x97a2001c, 0x501025, 0xa7a2001c, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x8021,
+0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x24100010,
+0xc004d78, 0x2021, 0x108042, 0x1600fffc,
+0x0, 0x24100010, 0x3202001e, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000,
+0xc004db9, 0x0, 0xc004d58, 0x0,
+0x50400005, 0x108042, 0x97a2001c, 0x501025,
+0xa7a2001c, 0x108042, 0x1600fff7, 0x0,
+0xc004db9, 0x8021, 0x24020002, 0xa7a2001e,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0x24100010, 0xc004d78,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0x24100010, 0x3202001e, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x3202001e, 0xc004d78, 0x24040001, 0xc004d78,
+0x2021, 0x34108000, 0x97a2001e, 0x501024,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fff8, 0x0, 0xc004db9,
+0x8021, 0xa7a00020, 0xc004d78, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x24100010, 0xc004d78, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0x24100010, 0x3202001e,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x3202001e, 0xc004db9,
+0x34108000, 0xc004db9, 0x0, 0xc004d58,
+0x0, 0x50400005, 0x108042, 0x97a20020,
+0x501025, 0xa7a20020, 0x108042, 0x1600fff7,
+0x0, 0xc004db9, 0x8021, 0xa7a00020,
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020,
+0x1440fffb, 0x0, 0xc004d78, 0x2021,
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0x24100010, 0xc004d78,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0x24100010, 0x3202001e, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa,
+0x3202001e, 0xc004db9, 0x34108000, 0xc004db9,
+0x0, 0xc004d58, 0x0, 0x50400005,
+0x108042, 0x97a20020, 0x501025, 0xa7a20020,
+0x108042, 0x1600fff7, 0x0, 0xc004db9,
+0x8021, 0xa7a00022, 0xc004d78, 0x24040001,
+0x26100001, 0x2e020020, 0x1440fffb, 0x0,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0xc004d78, 0x2021, 0xc004d78, 0x24040001,
+0x24100010, 0xc004d78, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0x24100010, 0xc004d78,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc004d78, 0x24040001, 0xc004d78, 0x2021,
+0x34108000, 0x97a20022, 0x501024, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fff8, 0x0, 0xc004db9, 0x0,
+0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
+0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d,
+0x0, 0x3c020001, 0x94426f26, 0x3c010001,
+0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c,
+0x24040009, 0x24050001, 0xc004ddb, 0x24060400,
+0x24040018, 0x24050001, 0xc004ddb, 0x24060020,
+0x24040018, 0x24050001, 0xc004ddb, 0x24062000,
+0x3c024000, 0x2421024, 0x10400123, 0x3c022000,
+0x2421024, 0x10400004, 0x0, 0x3c010001,
+0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c,
+0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9,
+0x0, 0x3c020001, 0x8c426f1c, 0x10400067,
+0x3c020004, 0x2421024, 0x10400011, 0xa7a00018,
+0x3c020008, 0x2421024, 0x10400002, 0x24020200,
+0xa7a20018, 0x3c020010, 0x2421024, 0x10400004,
+0x0, 0x97a20018, 0x34420100, 0xa7a20018,
+0x97a60018, 0x24040009, 0x10000004, 0x2821,
+0x24040009, 0x2821, 0x3021, 0xc004ddb,
+0x0, 0x24020001, 0xa7a2001a, 0x3c020008,
+0x2421024, 0x1040000c, 0x3c020002, 0x2421024,
+0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001,
+0x2421024, 0x10400005, 0x3c020010, 0x97a2001a,
+0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024,
+0x1040000e, 0x3c020002, 0x2421024, 0x10400005,
+0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a,
+0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0,
+0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0,
+0x2431024, 0x54430004, 0x3c020020, 0x97a2001a,
+0x1000000c, 0x34420400, 0x2421024, 0x50400004,
+0x3c020080, 0x97a2001a, 0x10000006, 0x34420800,
+0x2421024, 0x10400004, 0x0, 0x97a2001a,
+0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004,
+0xc004ddb, 0x2821, 0x3c020004, 0x2421024,
+0x10400004, 0xa7a0001c, 0x32425000, 0x14400004,
+0x0, 0x32424000, 0x10400005, 0x2021,
+0xc004cf9, 0x2402021, 0x10000096, 0x0,
+0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb,
+0xa7a6001c, 0x1000008f, 0x0, 0x2421024,
+0x10400004, 0xa7a00018, 0x32425000, 0x14400004,
+0x0, 0x32424000, 0x10400005, 0x3c020010,
+0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a,
+0x2421024, 0x10400004, 0x0, 0x97a20018,
+0x10000004, 0xa7a20018, 0x97a20018, 0x34420100,
+0xa7a20018, 0x3c020001, 0x2421024, 0x10400004,
+0x0, 0x97a20018, 0x10000004, 0xa7a20018,
+0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018,
+0x2021, 0xc004ddb, 0x2821, 0xa7a0001a,
+0x8021, 0xc004d78, 0x24040001, 0x26100001,
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78,
+0x2021, 0xc004d78, 0x24040001, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x24100010,
+0x32020001, 0x10400002, 0x2021, 0x24040001,
+0xc004d78, 0x108042, 0x1600fffa, 0x32020001,
+0x24100010, 0xc004d78, 0x2021, 0x108042,
+0x1600fffc, 0x0, 0xc004db9, 0x34108000,
+0xc004db9, 0x0, 0xc004d58, 0x0,
+0x50400005, 0x108042, 0x97a2001a, 0x501025,
+0xa7a2001a, 0x108042, 0x1600fff7, 0x0,
+0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d78,
+0x2021, 0x108042, 0x1600fffc, 0x0,
+0xc004db9, 0x34108000, 0xc004db9, 0x0,
+0xc004d58, 0x0, 0x50400005, 0x108042,
+0x97a2001a, 0x501025, 0xa7a2001a, 0x108042,
+0x1600fff7, 0x0, 0xc004db9, 0x0,
+0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a,
+0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c,
+0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b,
+0xafa30014, 0x8f830054, 0x24020004, 0x3c010001,
+0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38,
+0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c,
+0x431023, 0x2c420064, 0x1440000f, 0x0,
+0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4,
+0x3c03f700, 0x431025, 0x10000007, 0xaf820220,
+0x24020006, 0x3c010001, 0xac226dd4, 0x24020011,
+0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030,
+0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038,
+0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c,
+0x8821, 0x32024000, 0x10400013, 0xafbf0020,
+0x3c020010, 0x2021024, 0x2c420001, 0x21023,
+0x30434100, 0x3c020001, 0x2021024, 0x14400006,
+0x34714000, 0x3c020002, 0x2021024, 0x14400002,
+0x34716000, 0x34714040, 0x2021, 0x2821,
+0x10000036, 0x2203021, 0x32021000, 0x10400035,
+0x2021, 0x2821, 0xc004ddb, 0x24060040,
+0x24040018, 0x2821, 0xc004ddb, 0x24060c00,
+0x24040017, 0x2821, 0xc004ddb, 0x24060400,
+0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+0x24040017, 0x2821, 0xc004ddb, 0x24062500,
+0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+0x24040017, 0x2821, 0xc004ddb, 0x24064600,
+0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+0x24040017, 0x2821, 0xc004ddb, 0x24066700,
+0x24040016, 0x2821, 0xc004ddb, 0x24060006,
+0x2404001f, 0x2821, 0xc004ddb, 0x24060010,
+0x24040009, 0x2821, 0xc004ddb, 0x24061500,
+0x24040009, 0x2821, 0x24061d00, 0xc004ddb,
+0x0, 0x3c040001, 0x24846bf0, 0x3c05000e,
+0x34a50100, 0x2003021, 0x2203821, 0xafa00010,
+0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c,
+0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044,
+0x8f820044, 0x3c030001, 0x431025, 0x3c030008,
+0xaf820044, 0x8f840054, 0x8f820054, 0xa32824,
+0x10000002, 0x24840001, 0x8f820054, 0x821023,
+0x2c420002, 0x1440fffc, 0x0, 0x8f820044,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044,
+0x8f830054, 0x8f820054, 0x10000002, 0x24630001,
+0x8f820054, 0x621023, 0x2c420002, 0x1440fffc,
+0x0, 0x3e00008, 0xa01021, 0x8f830044,
+0x3c02fff0, 0x3442ffff, 0x42480, 0x621824,
+0x3c020002, 0x822025, 0x641825, 0xaf830044,
+0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x3c030001,
+0x431025, 0xaf820044, 0x8f830054, 0x8f820054,
+0x10000002, 0x24630001, 0x8f820054, 0x621023,
+0x2c420002, 0x1440fffc, 0x0, 0x3e00008,
+0x0, 0x8f820044, 0x2403ff7f, 0x431024,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x34420080,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x3e00008, 0x0,
+0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024,
+0xaf820044, 0x8f820044, 0x3c030001, 0x431025,
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002,
+0x24630001, 0x8f820054, 0x621023, 0x2c420002,
+0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe,
+0x3463ffff, 0x431024, 0xaf820044, 0x8f830054,
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054,
+0x621023, 0x2c420002, 0x1440fffc, 0x0,
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024,
+0x809821, 0xafbe002c, 0xa0f021, 0xafb20020,
+0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028,
+0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x12000075,
+0x0, 0x1000fff6, 0x0, 0x3275ffff,
+0x27b10010, 0xa7a00010, 0x8021, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x24040001, 0xc004d78,
+0x2021, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2b01024,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x2b01024, 0xc004db9,
+0x34108000, 0xc004db9, 0x0, 0xc004d58,
+0x0, 0x50400005, 0x108042, 0x96220000,
+0x501025, 0xa6220000, 0x108042, 0x1600fff7,
+0x0, 0xc004db9, 0x0, 0x33c5ffff,
+0x24020001, 0x54a20004, 0x24020002, 0x97a20010,
+0x10000006, 0x521025, 0x14a20006, 0x3271ffff,
+0x97a20010, 0x121827, 0x431024, 0xa7a20010,
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d78,
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb,
+0x0, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0xc004d78,
+0x24040001, 0x24100010, 0x32020001, 0x10400002,
+0x2021, 0x24040001, 0xc004d78, 0x108042,
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024,
+0x10400002, 0x2021, 0x24040001, 0xc004d78,
+0x108042, 0x1600fffa, 0x2301024, 0xc004d78,
+0x24040001, 0xc004d78, 0x2021, 0x34108000,
+0x96420000, 0x501024, 0x10400002, 0x2021,
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8,
+0x0, 0xc004db9, 0x0, 0x8fbf0030,
+0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020,
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038,
+0x0, 0x0, 0x0, 0x27bdffe8,
+0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0,
+0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
+0x0, 0xc003daf, 0x8f840224, 0x100001d8,
+0x0, 0x8f820220, 0x3c030008, 0x431024,
+0x10400026, 0x24020001, 0x8f840224, 0x8f820220,
+0x3c030400, 0x431024, 0x10400006, 0x0,
+0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b,
+0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000,
+0x24420001, 0xac620000, 0x2c420002, 0x14400003,
+0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002,
+0x8c428fc0, 0x10400006, 0x30820040, 0x10400004,
+0x24020001, 0x3c010002, 0x10000003, 0xac228fc4,
+0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c,
+0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002,
+0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002,
+0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002,
+0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002,
+0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002,
+0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194,
+0x31080, 0x3c010001, 0x220821, 0x8c226c00,
+0x400008, 0x0, 0x24020002, 0x3c010002,
+0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002,
+0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002,
+0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224,
+0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0,
+0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf,
+0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd,
+0x431024, 0xaf820200, 0x3c010002, 0xac208fe0,
+0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001,
+0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002,
+0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4,
+0x14400006, 0x24020003, 0x3c010001, 0xac246d9c,
+0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002,
+0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002,
+0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400003, 0x24020004, 0x3c010002, 0xac228f90,
+0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff,
+0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001,
+0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8,
+0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002,
+0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204,
+0x3463ffff, 0x30420030, 0x1440012f, 0x283a024,
+0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002,
+0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0,
+0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff,
+0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001,
+0xac226e3c, 0x2c420002, 0x14400125, 0x24020001,
+0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c,
+0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002,
+0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024,
+0x3c020002, 0x8c428f9c, 0x10400115, 0x0,
+0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002,
+0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002,
+0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204,
+0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002,
+0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0,
+0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
+0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002,
+0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
+0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4,
+0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c,
+0x3c030002, 0x8c638fc8, 0x441024, 0x641824,
+0x10430004, 0x24020001, 0x3c010002, 0x100000e4,
+0xac228f90, 0x24020003, 0xaca20000, 0x24020008,
+0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc,
+0x1040000c, 0x24020001, 0x3c040002, 0xc005091,
+0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005,
+0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006,
+0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002,
+0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0,
+0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0,
+0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002,
+0xac238fac, 0x8f830054, 0x24020009, 0x3c010002,
+0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4,
+0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0,
+0x431023, 0x2c422710, 0x1440009f, 0x0,
+0x3c020002, 0x8c428fc0, 0x10400005, 0x0,
+0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002,
+0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21,
+0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc,
+0x1040000e, 0x0, 0x3c020002, 0x8c428f9c,
+0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f,
+0x2402000c, 0x8f820204, 0x30420080, 0x1440000c,
+0x24020003, 0x10000029, 0x2402000c, 0x3c020002,
+0x8c428f9c, 0x30420080, 0x14400005, 0x24020003,
+0x8f820204, 0x30420080, 0x1040001f, 0x24020003,
+0xac620000, 0x2402000a, 0x3c010002, 0xac228f90,
+0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002,
+0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000,
+0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002,
+0xac228f90, 0x641825, 0x3c010002, 0xac238fe0,
+0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21,
+0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0,
+0x10400005, 0x0, 0x2402000c, 0x3c010002,
+0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0,
+0x10400063, 0x0, 0x3c040002, 0x8c848f9c,
+0x10800055, 0x30820008, 0x3c030002, 0x8c638fac,
+0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8,
+0xaca20000, 0x24020006, 0x3c010002, 0x10000054,
+0xac228f90, 0x8f820200, 0x34420002, 0xaf820200,
+0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90,
+0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002,
+0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710,
+0x14400031, 0x0, 0x3c020002, 0x8c428fd0,
+0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4,
+0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d,
+0x0, 0x3c050001, 0x8ca56d98, 0xc00529b,
+0x2021, 0x3c030001, 0x8c636d98, 0x24020004,
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94,
+0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94,
+0x431024, 0x3c010001, 0xac226d94, 0x8f830224,
+0x3c020200, 0x3c010002, 0xac238fec, 0x10000020,
+0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005,
+0x0, 0x3c020002, 0x8c428f9c, 0x1040000f,
+0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21,
+0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0,
+0x1040000f, 0x0, 0x3c020002, 0x8c428f9c,
+0x1440000b, 0x0, 0x24020002, 0x3c010002,
+0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0,
+0x10400003, 0x0, 0xc003daf, 0x0,
+0x8f820220, 0x3c03f700, 0x431025, 0xaf820220,
+0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002,
+0x24638fe8, 0x8c620000, 0x10400005, 0x34422000,
+0x3c010002, 0xac228fdc, 0x10000003, 0xac600000,
+0x3c010002, 0xac248fdc, 0x3e00008, 0x0,
+0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002,
+0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e,
+0x821024, 0x14400061, 0x24020030, 0x30822000,
+0x1040005d, 0x30838000, 0x31a02, 0x30820001,
+0x21200, 0x3c040001, 0x8c846f20, 0x621825,
+0x331c2, 0x3c030001, 0x24636e48, 0x30828000,
+0x21202, 0x30840001, 0x42200, 0x441025,
+0x239c2, 0x61080, 0x431021, 0x471021,
+0x90430000, 0x24020001, 0x10620025, 0x0,
+0x10600007, 0x24020002, 0x10620013, 0x24020003,
+0x1062002c, 0x3c05000f, 0x10000037, 0x0,
+0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
+0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
+0xaf820220, 0x3c010002, 0xac209004, 0x3c010002,
+0x10000034, 0xac20900c, 0x8f820200, 0x34420100,
+0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff,
+0x431024, 0xaf820220, 0x24020100, 0x3c010002,
+0xac229004, 0x3c010002, 0x10000026, 0xac20900c,
+0x8f820200, 0x2403feff, 0x431024, 0xaf820200,
+0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
+0x3c010002, 0xac209004, 0x3c010002, 0x10000019,
+0xac23900c, 0x8f820200, 0x34420100, 0xaf820200,
+0x8f820220, 0x3c030001, 0x431025, 0xaf820220,
+0x24020100, 0x3c010002, 0xac229004, 0x3c010002,
+0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001,
+0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014,
+0x10000004, 0x0, 0x24020030, 0x3c010002,
+0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020,
+0x0, 0x0, 0x0, 0x27bdffc8,
+0xafb20028, 0x809021, 0xafb3002c, 0xa09821,
+0xafb00020, 0xc08021, 0x3c040001, 0x24846c50,
+0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001,
+0x2403021, 0x2603821, 0xafbf0030, 0xafb10024,
+0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010,
+0x24020002, 0x12620083, 0x2e620003, 0x10400005,
+0x24020001, 0x1262000a, 0x0, 0x10000173,
+0x0, 0x24020004, 0x126200f8, 0x24020008,
+0x126200f7, 0x3c02ffec, 0x1000016c, 0x0,
+0x3c020001, 0x8c426d94, 0x30420002, 0x14400004,
+0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024,
+0x3c010002, 0x310821, 0xac308ffc, 0x3c024000,
+0x2021024, 0x1040004e, 0x1023c2, 0x30840030,
+0x101382, 0x3042001c, 0x3c030001, 0x24636dd8,
+0x431021, 0x823821, 0x3c020020, 0x2021024,
+0x10400006, 0x24020100, 0x3c010002, 0x310821,
+0xac229000, 0x10000005, 0x3c020080, 0x3c010002,
+0x310821, 0xac209000, 0x3c020080, 0x2021024,
+0x10400006, 0x121940, 0x3c020001, 0x3c010002,
+0x230821, 0x10000005, 0xac229008, 0x121140,
+0x3c010002, 0x220821, 0xac209008, 0x94e40000,
+0x3c030001, 0x8c636f40, 0x24020005, 0x10620010,
+0xa7a40018, 0x32024000, 0x10400002, 0x34824000,
+0xa7a20018, 0x24040001, 0x94e20002, 0x24050004,
+0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002,
+0x24040001, 0x2821, 0xc0045be, 0x27a60018,
+0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001,
+0xac316da4, 0x14530004, 0x32028000, 0xc003daf,
+0x0, 0x32028000, 0x1040011c, 0x0,
+0xc003daf, 0x0, 0x3c030001, 0x8c636f40,
+0x24020005, 0x10620115, 0x24020002, 0x3c010001,
+0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98,
+0x24040001, 0x24050004, 0x27b0001a, 0xc0045be,
+0x2003021, 0x24040001, 0x2821, 0xc0045be,
+0x2003021, 0x3c020002, 0x511021, 0x8c428ff4,
+0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff,
+0x3c010001, 0xac336da4, 0x431024, 0x3c010002,
+0x310821, 0x109300f7, 0xac228ff4, 0x100000f7,
+0x0, 0x3c022000, 0x2021024, 0x10400005,
+0x24020001, 0x3c010001, 0xac226f1c, 0x10000004,
+0x128940, 0x3c010001, 0xac206f1c, 0x128940,
+0x3c010002, 0x310821, 0xac308ff8, 0x3c024000,
+0x2021024, 0x14400014, 0x0, 0x3c020001,
+0x8c426f1c, 0x10400006, 0x24040004, 0x24050001,
+0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8,
+0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff,
+0x3463ffff, 0x431024, 0x3c010002, 0x310821,
+0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c,
+0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d,
+0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100,
+0x3c010002, 0x310821, 0xac239004, 0x3c030001,
+0x3c010002, 0x310821, 0xac23900c, 0x10000015,
+0x34420400, 0x2021024, 0x10400008, 0x24030100,
+0x3c020001, 0x8c426f20, 0x3c010002, 0x310821,
+0xac239004, 0x1000000b, 0x34420800, 0x3c020080,
+0x2021024, 0x1040002e, 0x3c030001, 0x3c020001,
+0x8c426f20, 0x3c010002, 0x310821, 0xac23900c,
+0x34420c00, 0x3c010001, 0xac226f20, 0x10000025,
+0x24040001, 0x3c020020, 0x2021024, 0x10400006,
+0x24020100, 0x3c010002, 0x310821, 0xac229004,
+0x10000005, 0x3c020080, 0x3c010002, 0x310821,
+0xac209004, 0x3c020080, 0x2021024, 0x10400007,
+0x121940, 0x3c020001, 0x3c010002, 0x230821,
+0xac22900c, 0x10000006, 0x24040001, 0x121140,
+0x3c010002, 0x220821, 0xac20900c, 0x24040001,
+0x2821, 0x27b0001e, 0xc00457c, 0x2003021,
+0x24040001, 0x2821, 0xc00457c, 0x2003021,
+0x24040001, 0x24050001, 0x27b0001c, 0xc00457c,
+0x2003021, 0x24040001, 0x24050001, 0xc00457c,
+0x2003021, 0x10000077, 0x0, 0x3c02ffec,
+0x3442ffff, 0x2028024, 0x3c020008, 0x2028025,
+0x121140, 0x3c010002, 0x220821, 0xac308ff8,
+0x3c022000, 0x2021024, 0x10400009, 0x0,
+0x3c020001, 0x8c426e44, 0x14400005, 0x24020001,
+0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000,
+0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024,
+0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c,
+0xaf820238, 0x3c010001, 0xac206db0, 0x10600005,
+0x24022020, 0x3c010001, 0xac226f20, 0x24020001,
+0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002,
+0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98,
+0x3484ffff, 0x441024, 0x3c010002, 0x230821,
+0xac228ff0, 0x24020001, 0x10a20044, 0x0,
+0x10000040, 0x0, 0x3c020001, 0x8c426f1c,
+0x1040001c, 0x24022000, 0x3c010001, 0xac226f20,
+0x3c0300a0, 0x2031024, 0x14430005, 0x121140,
+0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20,
+0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020,
+0x621024, 0x10400004, 0x24022001, 0x3c010001,
+0x10000023, 0xac226f20, 0x3c020080, 0x621024,
+0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c,
+0xac226f20, 0x3c020020, 0x2021024, 0x10400007,
+0x121940, 0x24020100, 0x3c010002, 0x230821,
+0xac229004, 0x10000006, 0x3c020080, 0x121140,
+0x3c010002, 0x220821, 0xac209004, 0x3c020080,
+0x2021024, 0x10400006, 0x121940, 0x3c020001,
+0x3c010002, 0x230821, 0x10000005, 0xac22900c,
+0x121140, 0x3c010002, 0x220821, 0xac20900c,
+0x3c030001, 0x8c636d98, 0x24020001, 0x10620003,
+0x0, 0xc003daf, 0x0, 0x8fbf0030,
+0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c,
+0x9821, 0xafb50040, 0xa821, 0xafb10034,
+0x8821, 0x24020002, 0xafbf0048, 0xafbe0044,
+0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a,
+0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022,
+0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005,
+0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d,
+0x2201021, 0x24020004, 0x10a2020a, 0x24020008,
+0x10a20208, 0x2201021, 0x10000256, 0x0,
+0x8fa8002c, 0x88140, 0x3c030002, 0x701821,
+0x8c638ffc, 0x621024, 0x14400009, 0x24040001,
+0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002,
+0x300821, 0xac318ff4, 0x10000246, 0x2201021,
+0x24050001, 0xc00457c, 0x27a60018, 0x24040001,
+0x24050001, 0xc00457c, 0x27a60018, 0x97a20018,
+0x30420004, 0x104000d9, 0x3c114000, 0x3c020001,
+0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9,
+0x31080, 0x3c010001, 0x220821, 0x8c226c68,
+0x400008, 0x0, 0x24040001, 0x24050011,
+0x27b0001a, 0xc00457c, 0x2003021, 0x24040001,
+0x24050011, 0xc00457c, 0x2003021, 0x97a3001a,
+0x30624000, 0x10400002, 0x3c150010, 0x3c150008,
+0x30628000, 0x104000aa, 0x3c130001, 0x100000a8,
+0x3c130002, 0x24040001, 0x24050014, 0x27b0001a,
+0xc00457c, 0x2003021, 0x24040001, 0x24050014,
+0xc00457c, 0x2003021, 0x97a3001a, 0x30621000,
+0x10400002, 0x3c150010, 0x3c150008, 0x30620800,
+0x10400097, 0x3c130001, 0x10000095, 0x3c130002,
+0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
+0x2003021, 0x24040001, 0x24050019, 0xc00457c,
+0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
+0x10620027, 0x28620401, 0x1040000e, 0x24020200,
+0x1062001f, 0x28620201, 0x10400005, 0x24020100,
+0x5062001e, 0x3c130001, 0x1000001e, 0x24040001,
+0x24020300, 0x50620019, 0x3c130002, 0x10000019,
+0x24040001, 0x24020600, 0x1062000d, 0x28620601,
+0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
+0x10000010, 0x24040001, 0x24020700, 0x1462000d,
+0x24040001, 0x3c130004, 0x1000000a, 0x3c150008,
+0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
+0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
+0x24040001, 0x24050018, 0x27b0001e, 0xc00457c,
+0x2003021, 0x24040001, 0x24050018, 0xc00457c,
+0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140,
+0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022,
+0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010,
+0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b,
+0xafa20014, 0x3c020004, 0x16620010, 0x3c020001,
+0x8f840054, 0x24030001, 0x24020002, 0x3c010001,
+0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001,
+0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001,
+0xac246f30, 0x1000004f, 0x2b38825, 0x16620039,
+0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e,
+0x24040018, 0x2021, 0x2821, 0xc004ddb,
+0x34068000, 0x8f830054, 0x8f820054, 0x2b38825,
+0x10000002, 0x24630032, 0x8f820054, 0x621023,
+0x2c420033, 0x1440fffc, 0x0, 0x8f830054,
+0x24020001, 0x3c010001, 0xac226e20, 0x3c010001,
+0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001,
+0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001,
+0x1000002c, 0xac236f30, 0x2821, 0xc004ddb,
+0x24060404, 0x2021, 0x2405001e, 0x27a60018,
+0x24020002, 0xc0045be, 0xa7a20018, 0x2021,
+0x2821, 0x27a60018, 0xc0045be, 0xa7a00018,
+0x24040018, 0x24050002, 0xc004ddb, 0x24060004,
+0x3c028000, 0x2221025, 0x2b31825, 0x10000015,
+0x438825, 0x2221025, 0x2751825, 0x438825,
+0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98,
+0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b,
+0xafb10014, 0x10000007, 0x0, 0x3c110002,
+0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff,
+0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e,
+0x0, 0x3c020001, 0x8c426f1c, 0x10400002,
+0x3c022000, 0x2228825, 0x8fa8002c, 0x81140,
+0x3c010002, 0x220821, 0x8c229000, 0x10400003,
+0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf,
+0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
+0x3c010002, 0x220821, 0x8c229008, 0x10400003,
+0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f,
+0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140,
+0x3c010002, 0x220821, 0xac318ff4, 0x10000135,
+0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002,
+0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024,
+0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff,
+0x628824, 0x3c010002, 0x3e0821, 0xac318ff0,
+0x10000124, 0x2201021, 0x2821, 0xc00457c,
+0x27a60018, 0x24040001, 0x2821, 0xc00457c,
+0x27a60018, 0x24040001, 0x24050001, 0x27b20020,
+0xc00457c, 0x2403021, 0x24040001, 0x24050001,
+0xc00457c, 0x2403021, 0x24040001, 0x24050004,
+0x27b1001e, 0xc00457c, 0x2203021, 0x24040001,
+0x24050004, 0xc00457c, 0x2203021, 0x24040001,
+0x24050005, 0x27b00022, 0xc00457c, 0x2003021,
+0x24040001, 0x24050005, 0xc00457c, 0x2003021,
+0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
+0x24040001, 0x24050010, 0xc00457c, 0x27a60018,
+0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
+0x24040001, 0x2405000a, 0xc00457c, 0x2403021,
+0x24040001, 0x24050018, 0xc00457c, 0x2203021,
+0x24040001, 0x24050018, 0xc00457c, 0x2203021,
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018,
+0x97a20018, 0x30420004, 0x10400066, 0x3c114000,
+0x3c030001, 0x8c636f34, 0x24020005, 0x14620067,
+0x24040001, 0x24050019, 0x27b0001c, 0xc00457c,
+0x2003021, 0x24040001, 0x24050019, 0xc00457c,
+0x2003021, 0x97a2001c, 0x30430700, 0x24020400,
+0x10620027, 0x28620401, 0x1040000e, 0x24020200,
+0x1062001f, 0x28620201, 0x10400005, 0x24020100,
+0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004,
+0x24020300, 0x50620019, 0x3c130002, 0x10000019,
+0x3c020004, 0x24020600, 0x1062000d, 0x28620601,
+0x10400005, 0x24020500, 0x5062000b, 0x3c130002,
+0x10000010, 0x3c020004, 0x24020700, 0x1462000d,
+0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008,
+0x10000006, 0x3c130004, 0x10000005, 0x3c150008,
+0x3c130001, 0x10000002, 0x3c150008, 0x3c150010,
+0x3c020004, 0x12620017, 0x3c028000, 0x8f820054,
+0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001,
+0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001,
+0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001,
+0x16620022, 0x2758825, 0x2021, 0x2821,
+0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b,
+0xac306e20, 0x2221025, 0x2b31825, 0x438825,
+0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001,
+0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010,
+0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001,
+0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007,
+0x0, 0x3c110002, 0x23e8821, 0x8e318ff0,
+0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001,
+0x8c426da8, 0x10400069, 0x0, 0x3c020001,
+0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825,
+0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
+0x8c229004, 0x10400003, 0x3c020020, 0x10000005,
+0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
+0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f,
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b,
+0x2228824, 0x8fa8002c, 0x82940, 0x3c030002,
+0x651821, 0x8c638ff8, 0x3c024000, 0x621024,
+0x14400008, 0x3c027fff, 0x3442ffff, 0x628824,
+0x3c010002, 0x250821, 0xac318ff0, 0x10000041,
+0x2201021, 0x3c020001, 0x8c426da8, 0x10400034,
+0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c,
+0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b,
+0x21023, 0x441024, 0x10600003, 0x518825,
+0x3c022000, 0x2228825, 0x3c020002, 0x451021,
+0x8c429004, 0x10400003, 0x3c020020, 0x10000004,
+0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824,
+0x8fa8002c, 0x81140, 0x3c010002, 0x220821,
+0x8c22900c, 0x10400003, 0x3c020080, 0x10000004,
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824,
+0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800,
+0x2228825, 0x3c020001, 0x8c426e34, 0x10400002,
+0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38,
+0x10400006, 0x3c020100, 0x10000004, 0x2228825,
+0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c,
+0x81140, 0x3c010002, 0x220821, 0xac318ff0,
+0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040,
+0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030,
+0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028,
+0x809021, 0xafbf002c, 0xafb10024, 0xafb00020,
+0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220,
+0x24020002, 0x1202005c, 0x2e020003, 0x10400005,
+0x24020001, 0x1202000a, 0x121940, 0x1000010c,
+0x0, 0x24020004, 0x120200bf, 0x24020008,
+0x120200be, 0x128940, 0x10000105, 0x0,
+0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002,
+0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024,
+0x10400038, 0x3c020008, 0x2021024, 0x10400020,
+0x34840002, 0x3c020002, 0x431021, 0x8c429000,
+0x10400005, 0x34840020, 0x34840100, 0x3c020020,
+0x10000006, 0x2028025, 0x2402feff, 0x822024,
+0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140,
+0x3c010002, 0x220821, 0x8c229008, 0x10400005,
+0x3c020001, 0xc23025, 0x3c020080, 0x10000016,
+0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024,
+0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024,
+0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff,
+0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024,
+0x3c010002, 0x230821, 0xac209000, 0x3c010002,
+0x230821, 0xac209008, 0xaf840200, 0xaf860220,
+0x8f820220, 0x34420002, 0xaf820220, 0x1000000a,
+0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200,
+0x2028024, 0x2402fffd, 0x621824, 0xc003daf,
+0xaf830200, 0x121140, 0x3c010002, 0x220821,
+0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c,
+0x10400069, 0x24050004, 0x24040001, 0xc00457c,
+0x27a60018, 0x24040001, 0x24050005, 0xc00457c,
+0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001,
+0x24846e48, 0x30630c00, 0x31a82, 0x30420c00,
+0x21282, 0xa7a2001a, 0x21080, 0x441021,
+0x431021, 0xa7a30018, 0x90480000, 0x24020001,
+0x3103ffff, 0x10620029, 0x28620002, 0x10400005,
+0x0, 0x10600009, 0x0, 0x1000003d,
+0x0, 0x10700013, 0x24020003, 0x1062002c,
+0x0, 0x10000037, 0x0, 0x8f820200,
+0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220,
+0x3c010002, 0xac209004, 0x3c010002, 0x10000032,
+0xac20900c, 0x8f820200, 0x34420100, 0xaf820200,
+0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024,
+0xaf820220, 0x24020100, 0x3c010002, 0xac229004,
+0x3c010002, 0x10000024, 0xac20900c, 0x8f820200,
+0x2403feff, 0x431024, 0xaf820200, 0x8f820220,
+0x3c030001, 0x431025, 0xaf820220, 0x3c010002,
+0xac209004, 0x3c010002, 0x10000017, 0xac23900c,
+0x8f820200, 0x34420100, 0xaf820200, 0x8f820220,
+0x3c030001, 0x431025, 0xaf820220, 0x24020100,
+0x3c010002, 0xac229004, 0x3c010002, 0x1000000a,
+0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a,
+0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010,
+0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002,
+0x1000004b, 0xaf820200, 0x128940, 0x3c050002,
+0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021,
+0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010,
+0x0, 0x3c020001, 0x8c426f1c, 0x14400005,
+0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200,
+0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024,
+0x3c010002, 0x310821, 0x10000031, 0xac308ff0,
+0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020,
+0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020,
+0xa21024, 0x10400007, 0x34840020, 0x24020100,
+0x3c010002, 0x310821, 0xac229004, 0x10000006,
+0x34840100, 0x3c010002, 0x310821, 0xac209004,
+0x2402feff, 0x822024, 0x3c020080, 0xa21024,
+0x10400007, 0x121940, 0x3c020001, 0x3c010002,
+0x230821, 0xac22900c, 0x10000008, 0xc23025,
+0x121140, 0x3c010002, 0x220821, 0xac20900c,
+0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200,
+0xaf860220, 0x8f820220, 0x34420002, 0xaf820220,
+0x121140, 0x3c010002, 0x220821, 0xac308ff0,
+0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020,
+0x3e00008, 0x27bd0030, 0x0, 0x1821,
+0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007,
+0x30420001, 0x10400004, 0x0, 0x8f820044,
+0x10000003, 0x34420040, 0x8f820044, 0x461024,
+0xaf820044, 0x8f820044, 0x34420020, 0xaf820044,
+0x8f820044, 0x451024, 0xaf820044, 0x24630001,
+0x28620008, 0x5440ffee, 0x641007, 0x3e00008,
+0x0, 0x2c820008, 0x1040001b, 0x0,
+0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001,
+0x24426e60, 0x621821, 0x24640004, 0x90620000,
+0x10400004, 0x0, 0x8f820044, 0x10000003,
+0x34420040, 0x8f820044, 0x461024, 0xaf820044,
+0x8f820044, 0x34420020, 0xaf820044, 0x8f820044,
+0x451024, 0xaf820044, 0x24630001, 0x64102b,
+0x1440ffee, 0x0, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x8f8400c4,
+0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824,
+0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008,
+0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004,
+0x14400012, 0x805021, 0x8ce90000, 0x8f42013c,
+0x1494823, 0x49182b, 0x94eb0006, 0x10600002,
+0x25630050, 0x494821, 0x123182b, 0x50400003,
+0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8,
+0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008,
+0x1021, 0x3e00008, 0x0, 0x8f8300e4,
+0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8,
+0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8,
+0x3e00008, 0xaf8200e4, 0x3e00008, 0x0,
+0x0, 0x0, 0x0, 0x8f880120,
+0x27624fe0, 0x8f830128, 0x15020002, 0x25090020,
+0x27694800, 0x11230012, 0x8fa20010, 0xad040000,
+0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
+0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
+0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc,
+0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc,
+0x8f430324, 0x1021, 0x24630001, 0x3e00008,
+0xaf430324, 0x3e00008, 0x0, 0x8f880100,
+0x276247e0, 0x8f830108, 0x15020002, 0x25090020,
+0x27694000, 0x1123000f, 0x8fa20010, 0xad040000,
+0xad050004, 0xad060008, 0xa507000e, 0x8fa30014,
+0xad020018, 0x8fa20018, 0xad03001c, 0x25030016,
+0xad020010, 0xad030014, 0xaf890100, 0x3e00008,
+0x24020001, 0x8f430328, 0x1021, 0x24630001,
+0x3e00008, 0xaf430328, 0x3e00008, 0x0,
0x0, 0x0, 0x0, 0x0 };
static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = {
-0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31,
-0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234,
-0x2030303a, 0x31303a35, 0x35207368, 0x75616e67,
-0x20457870, 0x20240000, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x6261644d, 0x656d537a,
-0x0, 0x68775665, 0x72000000, 0x62616448,
-0x77566572, 0x0, 0x2a2a4441, 0x574e5f41,
-0x0, 0x74785278, 0x4266537a, 0x0,
-0x62664174, 0x6e4d726b, 0x0, 0x7265645a,
-0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600,
-0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c,
-0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e,
-0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e,
-0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677,
-0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773,
-0x0, 0x62616452, 0x78526362, 0x0,
-0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469,
-0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64,
-0x6c657200, 0x63616e74, 0x31446d61, 0x0,
-0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b,
-0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461,
-0x5f726561, 0x64795f63, 0x6b73756d, 0x0,
-0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374,
-0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00,
-0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000,
-0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561,
-0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173,
-0x73697374, 0x0, 0x74436b73, 0x6d4f6666,
-0x0, 0x2b685f73, 0x656e645f, 0x62645f72,
-0x65616479, 0x0, 0x68737453, 0x52696e67,
-0x0, 0x62616453, 0x52696e67, 0x0,
-0x6e696353, 0x52696e67, 0x0, 0x77446d61,
-0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74,
-0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0,
-0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63,
-0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77,
-0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000,
-0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74,
-0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72,
-0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77,
-0x725f6173, 0x73697374, 0x0, 0x72436b73,
-0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f,
-0x62645f72, 0x65616479, 0x0, 0x2b685f72,
-0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561,
-0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69,
-0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f,
-0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572,
-0x0, 0x2b685f64, 0x6f5f7570, 0x64617465,
-0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64,
-0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64,
-0x0, 0x2b636b73, 0x756d3136, 0x0,
-0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100,
-0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0,
-0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d,
-0x61635f72, 0x785f6174, 0x746e0000, 0x62616452,
-0x6574537a, 0x0, 0x72784264, 0x4266537a,
-0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65,
-0x72000000, 0x66774f70, 0x4661696c, 0x0,
-0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000,
-0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000,
-0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000,
-0x696e7453, 0x74617465, 0x0, 0x2a2a696e,
-0x69744370, 0x0, 0x23736372, 0x65616d00,
-0x69537461, 0x636b4572, 0x0, 0x70726f62,
-0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42,
-0x0, 0x2b73775f, 0x646d615f, 0x61737369,
-0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000,
-0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573,
-0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264,
-0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469,
-0x6d657200, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e,
-0x322e3335, 0x20313939, 0x392f3031, 0x2f323720,
-0x31393a30, 0x393a3530, 0x20686179, 0x65732045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x542d446d, 0x61526432,
-0x0, 0x542d446d, 0x61526431, 0x0,
-0x542d446d, 0x61526442, 0x0, 0x542d446d,
-0x61577232, 0x0, 0x542d446d, 0x61577231,
-0x0, 0x542d446d, 0x61577242, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e,
-0x312e322e, 0x32382031, 0x3939392f, 0x30312f32,
-0x30203139, 0x3a34393a, 0x34392073, 0x6875616e,
-0x67204578, 0x70202400, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278,
-0x0, 0x3f636d64, 0x48737453, 0x0,
-0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
-0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
-0x0, 0x3f636d64, 0x45727200, 0x86ac,
-0x8e5c, 0x8e5c, 0x8de4, 0x8b78,
-0x8e30, 0x8e5c, 0x8790, 0x8800,
-0x8990, 0x8a68, 0x8a34, 0x8e5c,
-0x8870, 0x8b24, 0x8e5c, 0x8b34,
-0x87b4, 0x8824, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e,
-0x322e3820, 0x31393938, 0x2f31322f, 0x30382030,
-0x323a3336, 0x3a333620, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x6164644d, 0x63447570,
-0x0, 0x6164644d, 0x6346756c, 0x0,
-0x64656c4d, 0x634e6f45, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e,
-0x32342031, 0x3939382f, 0x31322f32, 0x31203030,
-0x3a33333a, 0x30392073, 0x6875616e, 0x67204578,
-0x70202400, 0x65767452, 0x6e674600, 0x51657674,
-0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
-0x526e6746, 0x0, 0x4d516576, 0x74460000,
-0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
-0x0, 0x5173436f, 0x6e734600, 0x51725072,
-0x6f644600, 0x7377446d, 0x614f6666, 0x0,
-0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00,
-0x2372446d, 0x6141544e, 0x0, 0x72446d61,
-0x41544e30, 0x0, 0x72446d61, 0x41544e31,
-0x0, 0x72446d61, 0x34476200, 0x2a50414e,
-0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f,
-0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63,
-0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d,
-0x6141544e, 0x0, 0x77446d61, 0x41544e30,
-0x0, 0x77446d61, 0x41544e31, 0x0,
-0x77446d61, 0x34476200, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e,
-0x322e3520, 0x31393938, 0x2f30392f, 0x33302031,
-0x383a3530, 0x3a323820, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32,
-0x2e313220, 0x31393939, 0x2f30312f, 0x32302031,
-0x393a3439, 0x3a353120, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x46575f56, 0x45525349,
-0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037,
-0x2031373a, 0x35373a35, 0x32205044, 0x54203230,
-0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54,
-0x494d453a, 0x2031373a, 0x35373a35, 0x32000000,
-0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064,
-0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049,
-0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465,
-0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44,
-0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f,
-0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049,
-0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e,
-0x20322e37, 0x2e320000, 0x0, 0x12041100,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e,
-0x35203139, 0x39382f30, 0x392f3330, 0x2031383a,
-0x35303a30, 0x38207368, 0x75616e67, 0x20457870,
-0x20240000, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32,
-0x2e343420, 0x31393938, 0x2f31322f, 0x32312030,
-0x303a3333, 0x3a313820, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x69736e74, 0x54637055,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32,
-0x2e353320, 0x31393939, 0x2f30312f, 0x31362030,
-0x323a3535, 0x3a343320, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x724d6163, 0x43686b30,
-0x0, 0x72784672, 0x6d324c67, 0x0,
-0x72784e6f, 0x53744264, 0x0, 0x72784e6f,
-0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264,
-0x0, 0x7278436b, 0x446d6146, 0x0,
-0x72785144, 0x6d457846, 0x0, 0x72785144,
-0x6d614600, 0x72785144, 0x4c426446, 0x0,
-0x72785144, 0x6d426446, 0x0, 0x72784372,
-0x63506164, 0x0, 0x72536d51, 0x446d6146,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e,
-0x32322031, 0x3939382f, 0x31322f30, 0x38203032,
-0x3a33363a, 0x33302073, 0x6875616e, 0x67204578,
-0x70202400, 0x65767452, 0x6e674600, 0x51657674,
-0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
-0x526e6746, 0x0, 0x4d516576, 0x74460000,
-0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
-0x0, 0x5173436f, 0x6e734600, 0x51725072,
-0x6f644600, 0x6d616354, 0x68726573, 0x0,
-0x23744d61, 0x6341544e, 0x0, 0x23724d61,
-0x6341544e, 0x0, 0x72656d41, 0x73737274,
-0x0, 0x6c696e6b, 0x444f574e, 0x0,
-0x6c696e6b, 0x55500000, 0x0, 0x0,
-0x0, 0x24486561, 0x6465723a, 0x202f7072,
-0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
-0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
-0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e,
-0x322e3920, 0x31393939, 0x2f30312f, 0x31342030,
-0x303a3033, 0x3a343820, 0x73687561, 0x6e672045,
-0x78702024, 0x0, 0x65767452, 0x6e674600,
-0x51657674, 0x46000000, 0x51657674, 0x505f4600,
-0x4d657674, 0x526e6746, 0x0, 0x4d516576,
-0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
-0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
-0x51725072, 0x6f644600, 0x0, 0x0,
-0x0, 0x50726f62, 0x65506879, 0x0,
-0x6c6e6b41, 0x53535254, 0x0, 0x109a4,
-0x10a1c, 0x10a50, 0x10a7c, 0x11050,
-0x10aa8, 0x10b10, 0x111fc, 0x10dc0,
-0x10c68, 0x10c80, 0x10cc4, 0x10cec,
-0x10d0c, 0x10d34, 0x111fc, 0x10dc0,
-0x10df8, 0x10e10, 0x10e40, 0x10e68,
-0x10e88, 0x10eb0, 0x0, 0x10fdc,
-0x11008, 0x1102c, 0x111fc, 0x11050,
-0x11078, 0x11108, 0x0, 0x0,
-0x0, 0x1186c, 0x1193c, 0x11a14,
-0x11ae4, 0x11b40, 0x11c1c, 0x11c44,
-0x11d20, 0x11d48, 0x11ef0, 0x11f18,
-0x120c0, 0x122b8, 0x1254c, 0x12460,
-0x1254c, 0x12578, 0x120e8, 0x12290,
-0x7273745f, 0x676d6969, 0x0, 0x12608,
-0x12640, 0x12728, 0x13374, 0x133b4,
-0x133cc, 0x7365746c, 0x6f6f7000, 0x0,
-0x0, 0x13bbc, 0x13bfc, 0x13c8c,
-0x13cd0, 0x13d34, 0x13dc0, 0x13df4,
-0x13e7c, 0x13f14, 0x13fe4, 0x14024,
-0x140a8, 0x140cc, 0x141dc, 0x646f4261,
-0x73655067, 0x0, 0x0, 0x0,
-0x0, 0x73746d61, 0x634c4e4b, 0x0,
-0x6765746d, 0x636c6e6b, 0x0, 0x14ed8,
-0x14ed8, 0x14b8c, 0x14bd8, 0x14c24,
-0x14ed8, 0x7365746d, 0x61636163, 0x74000000,
+0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31,
+0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234,
+0x2030303a, 0x31303a35, 0x35207368, 0x75616e67,
+0x20457870, 0x20240000, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x6261644d, 0x656d537a,
+0x0, 0x68775665, 0x72000000, 0x62616448,
+0x77566572, 0x0, 0x2a2a4441, 0x574e5f41,
+0x0, 0x74785278, 0x4266537a, 0x0,
+0x62664174, 0x6e4d726b, 0x0, 0x7265645a,
+0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600,
+0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c,
+0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e,
+0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e,
+0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677,
+0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773,
+0x0, 0x62616452, 0x78526362, 0x0,
+0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469,
+0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64,
+0x6c657200, 0x63616e74, 0x31446d61, 0x0,
+0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b,
+0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461,
+0x5f726561, 0x64795f63, 0x6b73756d, 0x0,
+0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374,
+0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00,
+0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000,
+0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561,
+0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173,
+0x73697374, 0x0, 0x74436b73, 0x6d4f6666,
+0x0, 0x2b685f73, 0x656e645f, 0x62645f72,
+0x65616479, 0x0, 0x68737453, 0x52696e67,
+0x0, 0x62616453, 0x52696e67, 0x0,
+0x6e696353, 0x52696e67, 0x0, 0x77446d61,
+0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74,
+0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0,
+0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63,
+0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77,
+0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000,
+0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74,
+0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72,
+0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77,
+0x725f6173, 0x73697374, 0x0, 0x72436b73,
+0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f,
+0x62645f72, 0x65616479, 0x0, 0x2b685f72,
+0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561,
+0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69,
+0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f,
+0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572,
+0x0, 0x2b685f64, 0x6f5f7570, 0x64617465,
+0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64,
+0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64,
+0x0, 0x2b636b73, 0x756d3136, 0x0,
+0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100,
+0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0,
+0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d,
+0x61635f72, 0x785f6174, 0x746e0000, 0x62616452,
+0x6574537a, 0x0, 0x72784264, 0x4266537a,
+0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65,
+0x72000000, 0x66774f70, 0x4661696c, 0x0,
+0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000,
+0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000,
+0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000,
+0x696e7453, 0x74617465, 0x0, 0x2a2a696e,
+0x69744370, 0x0, 0x23736372, 0x65616d00,
+0x69537461, 0x636b4572, 0x0, 0x70726f62,
+0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42,
+0x0, 0x2b73775f, 0x646d615f, 0x61737369,
+0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000,
+0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573,
+0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264,
+0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469,
+0x6d657200, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e,
+0x322e3335, 0x20313939, 0x392f3031, 0x2f323720,
+0x31393a30, 0x393a3530, 0x20686179, 0x65732045,
+0x78702024, 0x0, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x542d446d, 0x61526432,
+0x0, 0x542d446d, 0x61526431, 0x0,
+0x542d446d, 0x61526442, 0x0, 0x542d446d,
+0x61577232, 0x0, 0x542d446d, 0x61577231,
+0x0, 0x542d446d, 0x61577242, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e,
+0x312e322e, 0x32382031, 0x3939392f, 0x30312f32,
+0x30203139, 0x3a34393a, 0x34392073, 0x6875616e,
+0x67204578, 0x70202400, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278,
+0x0, 0x3f636d64, 0x48737453, 0x0,
+0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64,
+0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b,
+0x0, 0x3f636d64, 0x45727200, 0x86ac,
+0x8e5c, 0x8e5c, 0x8de4, 0x8b78,
+0x8e30, 0x8e5c, 0x8790, 0x8800,
+0x8990, 0x8a68, 0x8a34, 0x8e5c,
+0x8870, 0x8b24, 0x8e5c, 0x8b34,
+0x87b4, 0x8824, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e,
+0x322e3820, 0x31393938, 0x2f31322f, 0x30382030,
+0x323a3336, 0x3a333620, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x6164644d, 0x63447570,
+0x0, 0x6164644d, 0x6346756c, 0x0,
+0x64656c4d, 0x634e6f45, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e,
+0x32342031, 0x3939382f, 0x31322f32, 0x31203030,
+0x3a33333a, 0x30392073, 0x6875616e, 0x67204578,
+0x70202400, 0x65767452, 0x6e674600, 0x51657674,
+0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
+0x526e6746, 0x0, 0x4d516576, 0x74460000,
+0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
+0x0, 0x5173436f, 0x6e734600, 0x51725072,
+0x6f644600, 0x7377446d, 0x614f6666, 0x0,
+0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00,
+0x2372446d, 0x6141544e, 0x0, 0x72446d61,
+0x41544e30, 0x0, 0x72446d61, 0x41544e31,
+0x0, 0x72446d61, 0x34476200, 0x2a50414e,
+0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f,
+0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63,
+0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d,
+0x6141544e, 0x0, 0x77446d61, 0x41544e30,
+0x0, 0x77446d61, 0x41544e31, 0x0,
+0x77446d61, 0x34476200, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e,
+0x322e3520, 0x31393938, 0x2f30392f, 0x33302031,
+0x383a3530, 0x3a323820, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32,
+0x2e313220, 0x31393939, 0x2f30312f, 0x32302031,
+0x393a3439, 0x3a353120, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x46575f56, 0x45525349,
+0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037,
+0x2031373a, 0x35373a35, 0x32205044, 0x54203230,
+0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54,
+0x494d453a, 0x2031373a, 0x35373a35, 0x32000000,
+0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064,
+0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049,
+0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465,
+0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44,
+0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f,
+0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049,
+0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e,
+0x20322e37, 0x2e320000, 0x0, 0x12041100,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e,
+0x35203139, 0x39382f30, 0x392f3330, 0x2031383a,
+0x35303a30, 0x38207368, 0x75616e67, 0x20457870,
+0x20240000, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32,
+0x2e343420, 0x31393938, 0x2f31322f, 0x32312030,
+0x303a3333, 0x3a313820, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x69736e74, 0x54637055,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32,
+0x2e353320, 0x31393939, 0x2f30312f, 0x31362030,
+0x323a3535, 0x3a343320, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x724d6163, 0x43686b30,
+0x0, 0x72784672, 0x6d324c67, 0x0,
+0x72784e6f, 0x53744264, 0x0, 0x72784e6f,
+0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264,
+0x0, 0x7278436b, 0x446d6146, 0x0,
+0x72785144, 0x6d457846, 0x0, 0x72785144,
+0x6d614600, 0x72785144, 0x4c426446, 0x0,
+0x72785144, 0x6d426446, 0x0, 0x72784372,
+0x63506164, 0x0, 0x72536d51, 0x446d6146,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e,
+0x32322031, 0x3939382f, 0x31322f30, 0x38203032,
+0x3a33363a, 0x33302073, 0x6875616e, 0x67204578,
+0x70202400, 0x65767452, 0x6e674600, 0x51657674,
+0x46000000, 0x51657674, 0x505f4600, 0x4d657674,
+0x526e6746, 0x0, 0x4d516576, 0x74460000,
+0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46,
+0x0, 0x5173436f, 0x6e734600, 0x51725072,
+0x6f644600, 0x6d616354, 0x68726573, 0x0,
+0x23744d61, 0x6341544e, 0x0, 0x23724d61,
+0x6341544e, 0x0, 0x72656d41, 0x73737274,
+0x0, 0x6c696e6b, 0x444f574e, 0x0,
+0x6c696e6b, 0x55500000, 0x0, 0x0,
+0x0, 0x24486561, 0x6465723a, 0x202f7072,
+0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765,
+0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f,
+0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e,
+0x322e3920, 0x31393939, 0x2f30312f, 0x31342030,
+0x303a3033, 0x3a343820, 0x73687561, 0x6e672045,
+0x78702024, 0x0, 0x65767452, 0x6e674600,
+0x51657674, 0x46000000, 0x51657674, 0x505f4600,
+0x4d657674, 0x526e6746, 0x0, 0x4d516576,
+0x74460000, 0x4d516576, 0x505f4600, 0x5173436f,
+0x6e495f46, 0x0, 0x5173436f, 0x6e734600,
+0x51725072, 0x6f644600, 0x0, 0x0,
+0x0, 0x50726f62, 0x65506879, 0x0,
+0x6c6e6b41, 0x53535254, 0x0, 0x109a4,
+0x10a1c, 0x10a50, 0x10a7c, 0x11050,
+0x10aa8, 0x10b10, 0x111fc, 0x10dc0,
+0x10c68, 0x10c80, 0x10cc4, 0x10cec,
+0x10d0c, 0x10d34, 0x111fc, 0x10dc0,
+0x10df8, 0x10e10, 0x10e40, 0x10e68,
+0x10e88, 0x10eb0, 0x0, 0x10fdc,
+0x11008, 0x1102c, 0x111fc, 0x11050,
+0x11078, 0x11108, 0x0, 0x0,
+0x0, 0x1186c, 0x1193c, 0x11a14,
+0x11ae4, 0x11b40, 0x11c1c, 0x11c44,
+0x11d20, 0x11d48, 0x11ef0, 0x11f18,
+0x120c0, 0x122b8, 0x1254c, 0x12460,
+0x1254c, 0x12578, 0x120e8, 0x12290,
+0x7273745f, 0x676d6969, 0x0, 0x12608,
+0x12640, 0x12728, 0x13374, 0x133b4,
+0x133cc, 0x7365746c, 0x6f6f7000, 0x0,
+0x0, 0x13bbc, 0x13bfc, 0x13c8c,
+0x13cd0, 0x13d34, 0x13dc0, 0x13df4,
+0x13e7c, 0x13f14, 0x13fe4, 0x14024,
+0x140a8, 0x140cc, 0x141dc, 0x646f4261,
+0x73655067, 0x0, 0x0, 0x0,
+0x0, 0x73746d61, 0x634c4e4b, 0x0,
+0x6765746d, 0x636c6e6b, 0x0, 0x14ed8,
+0x14ed8, 0x14b8c, 0x14bd8, 0x14c24,
+0x14ed8, 0x7365746d, 0x61636163, 0x74000000,
0x0, 0x0 };
static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = {
-0x1,
-0x1, 0x1, 0xc001fc, 0x3ffc,
-0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
-0x43205600, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x416c7465,
-0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
-0x0, 0x0, 0x0, 0x1ffffc,
-0x1fff7c, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x60cf00,
-0x60, 0xcf000000, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x3, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x1, 0x0,
-0x0, 0x0, 0x0, 0x1,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x1000000, 0x21000000,
-0x12000140, 0x0, 0x0, 0x20000000,
-0x120000a0, 0x0, 0x12000060, 0x12000180,
-0x120001e0, 0x0, 0x0, 0x0,
-0x1, 0x0, 0x0, 0x0,
-0x0, 0x0, 0x0, 0x2,
-0x0, 0x0, 0x30001, 0x1,
-0x30201, 0x0, 0x0, 0x1010101,
-0x1010100, 0x10100, 0x1010001, 0x10001,
+0x1,
+0x1, 0x1, 0xc001fc, 0x3ffc,
+0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49,
+0x43205600, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x416c7465,
+0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242,
+0x0, 0x0, 0x0, 0x1ffffc,
+0x1fff7c, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x60cf00,
+0x60, 0xcf000000, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x3, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x1, 0x0,
+0x0, 0x0, 0x0, 0x1,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x1000000, 0x21000000,
+0x12000140, 0x0, 0x0, 0x20000000,
+0x120000a0, 0x0, 0x12000060, 0x12000180,
+0x120001e0, 0x0, 0x0, 0x0,
+0x1, 0x0, 0x0, 0x0,
+0x0, 0x0, 0x0, 0x2,
+0x0, 0x0, 0x30001, 0x1,
+0x30201, 0x0, 0x0, 0x1010101,
+0x1010100, 0x10100, 0x1010001, 0x10001,
0x1000101, 0x101, 0x0, 0x0 };
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index d9ba8be72af..28855a01ed7 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1,8 +1,8 @@
-/* Advanced Micro Devices Inc. AMD8111E Linux Network Driver
- * Copyright (C) 2004 Advanced Micro Devices
+/* Advanced Micro Devices Inc. AMD8111E Linux Network Driver
+ * Copyright (C) 2004 Advanced Micro Devices
+ *
*
- *
* Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ]
* Copyright (C) 2001, 2002 David S. Miller (davem@redhat.com)[ tg3.c]
* Copyright 1996-1999 Thomas Bogendoerfer [ pcnet32.c ]
@@ -12,7 +12,7 @@
* Carsten Langgaard, carstenl@mips.com [ pcnet32.c ]
* Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved.
*
- *
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
@@ -25,16 +25,16 @@
*
* 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
-
+
Module Name:
amd8111e.c
Abstract:
-
- AMD8111 based 10/100 Ethernet Controller Driver.
+
+ AMD8111 based 10/100 Ethernet Controller Driver.
Environment:
@@ -58,18 +58,17 @@ Revision History:
3.0.4 12/09/2003
1. Added set_mac_address routine for bonding driver support.
2. Tested the driver for bonding support
- 3. Bug fix: Fixed mismach in actual receive buffer lenth and lenth
+ 3. Bug fix: Fixed mismach in actual receive buffer lenth and lenth
indicated to the h/w.
- 4. Modified amd8111e_rx() routine to receive all the received packets
+ 4. Modified amd8111e_rx() routine to receive all the received packets
in the first interrupt.
5. Bug fix: Corrected rx_errors reported in get_stats() function.
3.0.5 03/22/2004
- 1. Added NAPI support
+ 1. Added NAPI support
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -85,7 +84,7 @@ Revision History:
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
-#include <linux/ctype.h>
+#include <linux/ctype.h>
#include <linux/crc32.h>
#include <linux/dma-mapping.h>
@@ -102,9 +101,9 @@ Revision History:
#include "amd8111e.h"
#define MODULE_NAME "amd8111e"
-#define MODULE_VERS "3.0.5"
+#define MODULE_VERS "3.0.6"
MODULE_AUTHOR("Advanced Micro Devices, Inc.");
-MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.3");
+MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.6");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, amd8111e_pci_tbl);
module_param_array(speed_duplex, int, NULL, 0);
@@ -115,13 +114,13 @@ module_param_array(dynamic_ipg, bool, NULL, 0);
MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable");
static struct pci_device_id amd8111e_pci_tbl[] = {
-
+
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD8111E_7462,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ 0, }
};
-/*
+/*
This function will read the PHY registers.
*/
static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val)
@@ -142,17 +141,17 @@ static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32*
} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
if(reg_val & PHY_RD_ERR)
goto err_phy_read;
-
+
*val = reg_val & 0xffff;
return 0;
-err_phy_read:
+err_phy_read:
*val = 0;
return -EINVAL;
-
+
}
-/*
-This function will write into PHY registers.
+/*
+This function will write into PHY registers.
*/
static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val)
{
@@ -171,19 +170,19 @@ static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32
reg_val = readl(mmio + PHY_ACCESS);
udelay(30); /* It takes 30 us to read/write the data */
} while (--repeat && (reg_val & PHY_CMD_ACTIVE));
-
+
if(reg_val & PHY_RD_ERR)
goto err_phy_write;
-
+
return 0;
-err_phy_write:
+err_phy_write:
return -EINVAL;
-
+
}
-/*
+/*
This is the mii register read function provided to the mii interface.
-*/
+*/
static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num)
{
struct amd8111e_priv* lp = netdev_priv(dev);
@@ -191,12 +190,12 @@ static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num)
amd8111e_read_phy(lp,phy_id,reg_num,&reg_val);
return reg_val;
-
+
}
-/*
+/*
This is the mii register write function provided to the mii interface.
-*/
+*/
static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val)
{
struct amd8111e_priv* lp = netdev_priv(dev);
@@ -211,7 +210,7 @@ static void amd8111e_set_ext_phy(struct net_device *dev)
{
struct amd8111e_priv *lp = netdev_priv(dev);
u32 bmcr,advert,tmp;
-
+
/* Determine mii register values to set the speed */
advert = amd8111e_mdio_read(dev, lp->ext_phy_addr, MII_ADVERTISE);
tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
@@ -228,7 +227,7 @@ static void amd8111e_set_ext_phy(struct net_device *dev)
case SPEED10_FULL:
tmp |= ADVERTISE_10FULL;
break;
- case SPEED100_HALF:
+ case SPEED100_HALF:
tmp |= ADVERTISE_100HALF;
break;
case SPEED100_FULL:
@@ -245,8 +244,8 @@ static void amd8111e_set_ext_phy(struct net_device *dev)
}
-/*
-This function will unmap skb->data space and will free
+/*
+This function will unmap skb->data space and will free
all transmit and receive skbuffs.
*/
static int amd8111e_free_skbs(struct net_device *dev)
@@ -275,7 +274,7 @@ static int amd8111e_free_skbs(struct net_device *dev)
lp->rx_dma_addr[i] = 0;
}
}
-
+
return 0;
}
@@ -286,7 +285,7 @@ static inline void amd8111e_set_rx_buff_len(struct net_device* dev)
{
struct amd8111e_priv* lp = netdev_priv(dev);
unsigned int mtu = dev->mtu;
-
+
if (mtu > ETH_DATA_LEN){
/* MTU + ethernet header + FCS
+ optional VLAN tag + skb reserve space 2 */
@@ -299,7 +298,7 @@ static inline void amd8111e_set_rx_buff_len(struct net_device* dev)
}
}
-/*
+/*
This function will free all the previously allocated buffers, determine new receive buffer length and will allocate new receive buffers. This function also allocates and initializes both the transmitter and receive hardware descriptors.
*/
static int amd8111e_init_ring(struct net_device *dev)
@@ -310,24 +309,24 @@ static int amd8111e_init_ring(struct net_device *dev)
lp->rx_idx = lp->tx_idx = 0;
lp->tx_complete_idx = 0;
lp->tx_ring_idx = 0;
-
+
if(lp->opened)
/* Free previously allocated transmit and receive skbs */
- amd8111e_free_skbs(dev);
+ amd8111e_free_skbs(dev);
else{
/* allocate the tx and rx descriptors */
- if((lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
+ if((lp->tx_ring = pci_alloc_consistent(lp->pci_dev,
sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,
&lp->tx_ring_dma_addr)) == NULL)
-
+
goto err_no_mem;
-
- if((lp->rx_ring = pci_alloc_consistent(lp->pci_dev,
+
+ if((lp->rx_ring = pci_alloc_consistent(lp->pci_dev,
sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,
&lp->rx_ring_dma_addr)) == NULL)
-
+
goto err_free_tx_ring;
}
@@ -347,7 +346,7 @@ static int amd8111e_init_ring(struct net_device *dev)
}
/* Initilaizing receive descriptors */
for (i = 0; i < NUM_RX_BUFFERS; i++) {
- lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev,
+ lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev,
lp->rx_skbuff[i]->data,lp->rx_buff_len-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]);
@@ -366,15 +365,15 @@ static int amd8111e_init_ring(struct net_device *dev)
return 0;
err_free_rx_ring:
-
- pci_free_consistent(lp->pci_dev,
+
+ pci_free_consistent(lp->pci_dev,
sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,lp->rx_ring,
lp->rx_ring_dma_addr);
err_free_tx_ring:
-
+
pci_free_consistent(lp->pci_dev,
- sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,lp->tx_ring,
+ sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,lp->tx_ring,
lp->tx_ring_dma_addr);
err_no_mem:
@@ -396,11 +395,11 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
case RX_INTR_COAL :
timeout = coal_conf->rx_timeout;
event_count = coal_conf->rx_event_count;
- if( timeout > MAX_TIMEOUT ||
- event_count > MAX_EVENT_COUNT )
+ if( timeout > MAX_TIMEOUT ||
+ event_count > MAX_EVENT_COUNT )
return -EINVAL;
- timeout = timeout * DELAY_TIMER_CONV;
+ timeout = timeout * DELAY_TIMER_CONV;
writel(VAL0|STINTEN, mmio+INTEN0);
writel((u32)DLY_INT_A_R0|( event_count<< 16 )|timeout,
mmio+DLY_INT_A);
@@ -409,12 +408,12 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
case TX_INTR_COAL :
timeout = coal_conf->tx_timeout;
event_count = coal_conf->tx_event_count;
- if( timeout > MAX_TIMEOUT ||
- event_count > MAX_EVENT_COUNT )
+ if( timeout > MAX_TIMEOUT ||
+ event_count > MAX_EVENT_COUNT )
return -EINVAL;
-
- timeout = timeout * DELAY_TIMER_CONV;
+
+ timeout = timeout * DELAY_TIMER_CONV;
writel(VAL0|STINTEN,mmio+INTEN0);
writel((u32)DLY_INT_B_T0|( event_count<< 16 )|timeout,
mmio+DLY_INT_B);
@@ -426,7 +425,7 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
writel(0, mmio +DLY_INT_B);
writel(0, mmio+DLY_INT_A);
break;
- case ENABLE_COAL:
+ case ENABLE_COAL:
/* Start the timer */
writel((u32)SOFT_TIMER_FREQ, mmio+STVAL); /* 0.5 sec */
writel(VAL0|STINTEN, mmio+INTEN0);
@@ -439,8 +438,8 @@ static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod)
}
-/*
-This function initializes the device registers and starts the device.
+/*
+This function initializes the device registers and starts the device.
*/
static int amd8111e_restart(struct net_device *dev)
{
@@ -456,8 +455,8 @@ static int amd8111e_restart(struct net_device *dev)
/* enable the port manager and set auto negotiation always */
writel((u32) VAL1|EN_PMGR, mmio + CMD3 );
- writel((u32)XPHYANE|XPHYRST , mmio + CTRL2);
-
+ writel((u32)XPHYANE|XPHYRST , mmio + CTRL2);
+
amd8111e_set_ext_phy(dev);
/* set control registers */
@@ -466,7 +465,7 @@ static int amd8111e_restart(struct net_device *dev)
writel( reg_val| XMTSP_128 | CACHE_ALIGN, mmio + CTRL1 );
/* enable interrupt */
- writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN |
+ writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN |
APINT0EN | MIIPDTINTEN | MCCIINTEN | MCCINTEN | MREINTEN |
SPNDINTEN | MPINTEN | SINTEN | STINTEN, mmio + INTEN0);
@@ -478,10 +477,10 @@ static int amd8111e_restart(struct net_device *dev)
writew((u32)NUM_TX_RING_DR, mmio + XMT_RING_LEN0);
writew((u16)NUM_RX_RING_DR, mmio + RCV_RING_LEN0);
-
+
/* set default IPG to 96 */
writew((u32)DEFAULT_IPG,mmio+IPG);
- writew((u32)(DEFAULT_IPG-IFS1_DELTA), mmio + IFS1);
+ writew((u32)(DEFAULT_IPG-IFS1_DELTA), mmio + IFS1);
if(lp->options & OPTION_JUMBO_ENABLE){
writel((u32)VAL2|JUMBO, mmio + CMD3);
@@ -498,10 +497,10 @@ static int amd8111e_restart(struct net_device *dev)
writel((u32) VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3);
#endif
writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2 );
-
+
/* Setting the MAC address to the device */
for(i = 0; i < ETH_ADDR_LEN; i++)
- writeb( dev->dev_addr[i], mmio + PADR + i );
+ writeb( dev->dev_addr[i], mmio + PADR + i );
/* Enable interrupt coalesce */
if(lp->options & OPTION_INTR_COAL_ENABLE){
@@ -509,18 +508,18 @@ static int amd8111e_restart(struct net_device *dev)
dev->name);
amd8111e_set_coalesce(dev,ENABLE_COAL);
}
-
+
/* set RUN bit to start the chip */
writel(VAL2 | RDMD0, mmio + CMD0);
writel(VAL0 | INTREN | RUN, mmio + CMD0);
-
+
/* To avoid PCI posting bug */
readl(mmio+CMD0);
return 0;
}
-/*
-This function clears necessary the device registers.
-*/
+/*
+This function clears necessary the device registers.
+*/
static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
{
unsigned int reg_val;
@@ -545,7 +544,7 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
/* Clear CMD0 */
writel(CMD0_CLEAR,mmio + CMD0);
-
+
/* Clear CMD2 */
writel(CMD2_CLEAR, mmio +CMD2);
@@ -595,7 +594,7 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
/* SRAM_SIZE register */
reg_val = readl(mmio + SRAM_SIZE);
-
+
if(lp->options & OPTION_JUMBO_ENABLE)
writel( VAL2|JUMBO, mmio + CMD3);
#if AMD8111E_VLAN_TAG_USED
@@ -609,56 +608,56 @@ static void amd8111e_init_hw_default( struct amd8111e_priv* lp)
}
-/*
-This function disables the interrupt and clears all the pending
+/*
+This function disables the interrupt and clears all the pending
interrupts in INT0
*/
static void amd8111e_disable_interrupt(struct amd8111e_priv* lp)
-{
+{
u32 intr0;
/* Disable interrupt */
writel(INTREN, lp->mmio + CMD0);
-
+
/* Clear INT0 */
intr0 = readl(lp->mmio + INT0);
writel(intr0, lp->mmio + INT0);
-
+
/* To avoid PCI posting bug */
readl(lp->mmio + INT0);
}
/*
-This function stops the chip.
+This function stops the chip.
*/
static void amd8111e_stop_chip(struct amd8111e_priv* lp)
{
writel(RUN, lp->mmio + CMD0);
-
+
/* To avoid PCI posting bug */
readl(lp->mmio + CMD0);
}
-/*
+/*
This function frees the transmiter and receiver descriptor rings.
*/
static void amd8111e_free_ring(struct amd8111e_priv* lp)
-{
+{
/* Free transmit and receive skbs */
amd8111e_free_skbs(lp->amd8111e_net_dev);
/* Free transmit and receive descriptor rings */
if(lp->rx_ring){
- pci_free_consistent(lp->pci_dev,
+ pci_free_consistent(lp->pci_dev,
sizeof(struct amd8111e_rx_dr)*NUM_RX_RING_DR,
lp->rx_ring, lp->rx_ring_dma_addr);
lp->rx_ring = NULL;
}
-
+
if(lp->tx_ring){
- pci_free_consistent(lp->pci_dev,
+ pci_free_consistent(lp->pci_dev,
sizeof(struct amd8111e_tx_dr)*NUM_TX_RING_DR,
lp->tx_ring, lp->tx_ring_dma_addr);
@@ -666,10 +665,10 @@ static void amd8111e_free_ring(struct amd8111e_priv* lp)
}
}
-#if AMD8111E_VLAN_TAG_USED
-/*
+#if AMD8111E_VLAN_TAG_USED
+/*
This is the receive indication function for packets with vlan tag.
-*/
+*/
static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 vlan_tag)
{
#ifdef CONFIG_AMD8111E_NAPI
@@ -681,7 +680,7 @@ static int amd8111e_vlan_rx(struct amd8111e_priv *lp, struct sk_buff *skb, u16 v
#endif
/*
-This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb.
+This function will free all the transmit skbs that are actually transmitted by the device. It will check the ownership of the skb before freeing the skb.
*/
static int amd8111e_tx(struct net_device *dev)
{
@@ -710,7 +709,7 @@ static int amd8111e_tx(struct net_device *dev)
lp->tx_complete_idx++;
/*COAL update tx coalescing parameters */
lp->coal_conf.tx_packets++;
- lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
+ lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count;
if (netif_queue_stopped(dev) &&
lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){
@@ -735,13 +734,13 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
int num_rx_pkt = 0;
/*int max_rx_pkt = NUM_RX_BUFFERS;*/
short pkt_len;
-#if AMD8111E_VLAN_TAG_USED
+#if AMD8111E_VLAN_TAG_USED
short vtag;
#endif
int rx_pkt_limit = dev->quota;
unsigned long flags;
-
- do{
+
+ do{
/* process receive packets until we use the quota*/
/* If we own the next entry, it's a new packet. Send it up. */
while(1) {
@@ -749,11 +748,11 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
if (status & OWN_BIT)
break;
- /*
+ /*
* There is a tricky error noted by John Murphy,
* <murf@perftech.com> to Russ Nelson: Even with
- * full-sized * buffers it's possible for a
- * jabber packet to use two buffers, with only
+ * full-sized * buffers it's possible for a
+ * jabber packet to use two buffers, with only
* the last correctly noting the error.
*/
@@ -770,9 +769,9 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
}
pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
-#if AMD8111E_VLAN_TAG_USED
+#if AMD8111E_VLAN_TAG_USED
vtag = status & TT_MASK;
- /*MAC will strip vlan tag*/
+ /*MAC will strip vlan tag*/
if(lp->vlgrp != NULL && vtag !=0)
min_pkt_len =MIN_PKT_LEN - 4;
else
@@ -787,13 +786,13 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
if(--rx_pkt_limit < 0)
goto rx_not_empty;
if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
- /* if allocation fail,
+ /* if allocation fail,
ignore that pkt and go to next one */
lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
lp->drv_rx_errors++;
goto err_next_pkt;
}
-
+
skb_reserve(new_skb, 2);
skb = lp->rx_skbuff[rx_index];
pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
@@ -806,10 +805,10 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
new_skb->data,
lp->rx_buff_len-2,
PCI_DMA_FROMDEVICE);
-
+
skb->protocol = eth_type_trans(skb, dev);
-#if AMD8111E_VLAN_TAG_USED
+#if AMD8111E_VLAN_TAG_USED
if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
amd8111e_vlan_rx(lp, skb,
le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
@@ -818,20 +817,20 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
netif_receive_skb(skb);
/*COAL update rx coalescing parameters*/
lp->coal_conf.rx_packets++;
- lp->coal_conf.rx_bytes += pkt_len;
+ lp->coal_conf.rx_bytes += pkt_len;
num_rx_pkt++;
dev->last_rx = jiffies;
-
- err_next_pkt:
+
+ err_next_pkt:
lp->rx_ring[rx_index].buff_phy_addr
= cpu_to_le32(lp->rx_dma_addr[rx_index]);
- lp->rx_ring[rx_index].buff_count =
+ lp->rx_ring[rx_index].buff_count =
cpu_to_le16(lp->rx_buff_len-2);
wmb();
lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK;
}
- /* Check the interrupt status register for more packets in the
+ /* Check the interrupt status register for more packets in the
mean time. Process them since we have not used up our quota.*/
intr0 = readl(mmio + INT0);
@@ -853,13 +852,13 @@ static int amd8111e_rx_poll(struct net_device *dev, int * budget)
rx_not_empty:
/* Do not call a netif_rx_complete */
- dev->quota -= num_rx_pkt;
+ dev->quota -= num_rx_pkt;
*budget -= num_rx_pkt;
return 1;
}
#else
-/*
+/*
This function will check the ownership of receive buffers and descriptors. It will indicate to kernel up to half the number of maximum receive buffers in the descriptor ring, in a single receive interrupt. It will also replenish the descriptors with new skbs.
*/
static int amd8111e_rx(struct net_device *dev)
@@ -871,19 +870,19 @@ static int amd8111e_rx(struct net_device *dev)
int num_rx_pkt = 0;
int max_rx_pkt = NUM_RX_BUFFERS;
short pkt_len;
-#if AMD8111E_VLAN_TAG_USED
+#if AMD8111E_VLAN_TAG_USED
short vtag;
#endif
-
+
/* If we own the next entry, it's a new packet. Send it up. */
while(++num_rx_pkt <= max_rx_pkt){
status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags);
if(status & OWN_BIT)
return 0;
-
- /* check if err summary bit is set */
+
+ /* check if err summary bit is set */
if(status & ERR_BIT){
- /*
+ /*
* There is a tricky error noted by John Murphy,
* <murf@perftech.com> to Russ Nelson: Even with full-sized
* buffers it's possible for a jabber packet to use two
@@ -900,9 +899,9 @@ static int amd8111e_rx(struct net_device *dev)
}
pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4;
-#if AMD8111E_VLAN_TAG_USED
+#if AMD8111E_VLAN_TAG_USED
vtag = status & TT_MASK;
- /*MAC will strip vlan tag*/
+ /*MAC will strip vlan tag*/
if(lp->vlgrp != NULL && vtag !=0)
min_pkt_len =MIN_PKT_LEN - 4;
else
@@ -915,13 +914,13 @@ static int amd8111e_rx(struct net_device *dev)
goto err_next_pkt;
}
if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){
- /* if allocation fail,
+ /* if allocation fail,
ignore that pkt and go to next one */
lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS;
lp->drv_rx_errors++;
goto err_next_pkt;
}
-
+
skb_reserve(new_skb, 2);
skb = lp->rx_skbuff[rx_index];
pci_unmap_single(lp->pci_dev,lp->rx_dma_addr[rx_index],
@@ -932,27 +931,27 @@ static int amd8111e_rx(struct net_device *dev)
new_skb->dev = dev;
lp->rx_dma_addr[rx_index] = pci_map_single(lp->pci_dev,
new_skb->data, lp->rx_buff_len-2,PCI_DMA_FROMDEVICE);
-
+
skb->protocol = eth_type_trans(skb, dev);
-#if AMD8111E_VLAN_TAG_USED
+#if AMD8111E_VLAN_TAG_USED
if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){
amd8111e_vlan_rx(lp, skb,
le16_to_cpu(lp->rx_ring[rx_index].tag_ctrl_info));
} else
#endif
-
+
netif_rx (skb);
/*COAL update rx coalescing parameters*/
lp->coal_conf.rx_packets++;
- lp->coal_conf.rx_bytes += pkt_len;
+ lp->coal_conf.rx_bytes += pkt_len;
dev->last_rx = jiffies;
-
+
err_next_pkt:
lp->rx_ring[rx_index].buff_phy_addr
= cpu_to_le32(lp->rx_dma_addr[rx_index]);
- lp->rx_ring[rx_index].buff_count =
+ lp->rx_ring[rx_index].buff_count =
cpu_to_le16(lp->rx_buff_len-2);
wmb();
lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT);
@@ -962,26 +961,26 @@ err_next_pkt:
return 0;
}
#endif /* CONFIG_AMD8111E_NAPI */
-/*
+/*
This function will indicate the link status to the kernel.
*/
static int amd8111e_link_change(struct net_device* dev)
-{
+{
struct amd8111e_priv *lp = netdev_priv(dev);
int status0,speed;
/* read the link change */
status0 = readl(lp->mmio + STAT0);
-
+
if(status0 & LINK_STATS){
if(status0 & AUTONEG_COMPLETE)
lp->link_config.autoneg = AUTONEG_ENABLE;
- else
+ else
lp->link_config.autoneg = AUTONEG_DISABLE;
if(status0 & FULL_DPLX)
lp->link_config.duplex = DUPLEX_FULL;
- else
+ else
lp->link_config.duplex = DUPLEX_HALF;
speed = (status0 & SPEED_MASK) >> 7;
if(speed == PHY_SPEED_10)
@@ -990,22 +989,22 @@ static int amd8111e_link_change(struct net_device* dev)
lp->link_config.speed = SPEED_100;
printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n", dev->name,
- (lp->link_config.speed == SPEED_100) ? "100": "10",
- (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half");
+ (lp->link_config.speed == SPEED_100) ? "100": "10",
+ (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half");
netif_carrier_on(dev);
}
- else{
+ else{
lp->link_config.speed = SPEED_INVALID;
lp->link_config.duplex = DUPLEX_INVALID;
lp->link_config.autoneg = AUTONEG_INVALID;
printk(KERN_INFO "%s: Link is Down.\n",dev->name);
netif_carrier_off(dev);
}
-
+
return 0;
}
/*
-This function reads the mib counters.
+This function reads the mib counters.
*/
static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
{
@@ -1026,7 +1025,7 @@ static int amd8111e_read_mib(void __iomem *mmio, u8 MIB_COUNTER)
/*
This function reads the mib registers and returns the hardware statistics. It updates previous internal driver statistics with new values.
-*/
+*/
static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
{
struct amd8111e_priv *lp = netdev_priv(dev);
@@ -1034,9 +1033,9 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
unsigned long flags;
/* struct net_device_stats *prev_stats = &lp->prev_stats; */
struct net_device_stats* new_stats = &lp->stats;
-
+
if(!lp->opened)
- return &lp->stats;
+ return &lp->stats;
spin_lock_irqsave (&lp->lock, flags);
/* stats.rx_packets */
@@ -1079,7 +1078,7 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
new_stats->collisions = amd8111e_read_mib(mmio, xmt_collisions);
/* stats.rx_length_errors*/
- new_stats->rx_length_errors =
+ new_stats->rx_length_errors =
amd8111e_read_mib(mmio, rcv_undersize_pkts)+
amd8111e_read_mib(mmio, rcv_oversize_pkts);
@@ -1100,11 +1099,11 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
new_stats->rx_missed_errors = amd8111e_read_mib(mmio, rcv_miss_pkts);
/* stats.tx_aborted_errors*/
- new_stats->tx_aborted_errors =
+ new_stats->tx_aborted_errors =
amd8111e_read_mib(mmio, xmt_excessive_collision);
/* stats.tx_carrier_errors*/
- new_stats->tx_carrier_errors =
+ new_stats->tx_carrier_errors =
amd8111e_read_mib(mmio, xmt_loss_carrier);
/* stats.tx_fifo_errors*/
@@ -1116,12 +1115,12 @@ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev)
/* Reset the mibs for collecting new statistics */
/* writew(MIB_CLEAR, mmio + MIB_ADDR);*/
-
+
spin_unlock_irqrestore (&lp->lock, flags);
return new_stats;
}
-/* This function recalculate the interupt coalescing mode on every interrupt
+/* This function recalculate the interupt coalescing mode on every interrupt
according to the datarate and the packet rate.
*/
static int amd8111e_calc_coalesce(struct net_device *dev)
@@ -1137,19 +1136,19 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
tx_pkt_rate = coal_conf->tx_packets - coal_conf->tx_prev_packets;
coal_conf->tx_prev_packets = coal_conf->tx_packets;
-
+
tx_data_rate = coal_conf->tx_bytes - coal_conf->tx_prev_bytes;
coal_conf->tx_prev_bytes = coal_conf->tx_bytes;
-
+
rx_pkt_rate = coal_conf->rx_packets - coal_conf->rx_prev_packets;
coal_conf->rx_prev_packets = coal_conf->rx_packets;
-
+
rx_data_rate = coal_conf->rx_bytes - coal_conf->rx_prev_bytes;
coal_conf->rx_prev_bytes = coal_conf->rx_bytes;
-
+
if(rx_pkt_rate < 800){
if(coal_conf->rx_coal_type != NO_COALESCE){
-
+
coal_conf->rx_timeout = 0x0;
coal_conf->rx_event_count = 0;
amd8111e_set_coalesce(dev,RX_INTR_COAL);
@@ -1157,11 +1156,11 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
}
}
else{
-
+
rx_pkt_size = rx_data_rate/rx_pkt_rate;
if (rx_pkt_size < 128){
if(coal_conf->rx_coal_type != NO_COALESCE){
-
+
coal_conf->rx_timeout = 0;
coal_conf->rx_event_count = 0;
amd8111e_set_coalesce(dev,RX_INTR_COAL);
@@ -1170,7 +1169,7 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
}
else if ( (rx_pkt_size >= 128) && (rx_pkt_size < 512) ){
-
+
if(coal_conf->rx_coal_type != LOW_COALESCE){
coal_conf->rx_timeout = 1;
coal_conf->rx_event_count = 4;
@@ -1179,14 +1178,14 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
}
}
else if ((rx_pkt_size >= 512) && (rx_pkt_size < 1024)){
-
+
if(coal_conf->rx_coal_type != MEDIUM_COALESCE){
coal_conf->rx_timeout = 1;
coal_conf->rx_event_count = 4;
amd8111e_set_coalesce(dev,RX_INTR_COAL);
coal_conf->rx_coal_type = MEDIUM_COALESCE;
- }
-
+ }
+
}
else if(rx_pkt_size >= 1024){
if(coal_conf->rx_coal_type != HIGH_COALESCE){
@@ -1194,13 +1193,13 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
coal_conf->rx_event_count = 3;
amd8111e_set_coalesce(dev,RX_INTR_COAL);
coal_conf->rx_coal_type = HIGH_COALESCE;
- }
+ }
}
}
/* NOW FOR TX INTR COALESC */
if(tx_pkt_rate < 800){
if(coal_conf->tx_coal_type != NO_COALESCE){
-
+
coal_conf->tx_timeout = 0x0;
coal_conf->tx_event_count = 0;
amd8111e_set_coalesce(dev,TX_INTR_COAL);
@@ -1208,12 +1207,12 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
}
}
else{
-
+
tx_pkt_size = tx_data_rate/tx_pkt_rate;
if (tx_pkt_size < 128){
-
+
if(coal_conf->tx_coal_type != NO_COALESCE){
-
+
coal_conf->tx_timeout = 0;
coal_conf->tx_event_count = 0;
amd8111e_set_coalesce(dev,TX_INTR_COAL);
@@ -1222,7 +1221,7 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
}
else if ( (tx_pkt_size >= 128) && (tx_pkt_size < 512) ){
-
+
if(coal_conf->tx_coal_type != LOW_COALESCE){
coal_conf->tx_timeout = 1;
coal_conf->tx_event_count = 2;
@@ -1232,14 +1231,14 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
}
}
else if ((tx_pkt_size >= 512) && (tx_pkt_size < 1024)){
-
+
if(coal_conf->tx_coal_type != MEDIUM_COALESCE){
coal_conf->tx_timeout = 2;
coal_conf->tx_event_count = 5;
amd8111e_set_coalesce(dev,TX_INTR_COAL);
coal_conf->tx_coal_type = MEDIUM_COALESCE;
- }
-
+ }
+
}
else if(tx_pkt_size >= 1024){
if (tx_pkt_size >= 1024){
@@ -1248,7 +1247,7 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
coal_conf->tx_event_count = 8;
amd8111e_set_coalesce(dev,TX_INTR_COAL);
coal_conf->tx_coal_type = HIGH_COALESCE;
- }
+ }
}
}
}
@@ -1285,7 +1284,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg
handled = 0;
goto err_no_interrupt;
}
-
+
/* Current driver processes 4 interrupts : RINT,TINT,LCINT,STINT */
writel(intr0, mmio + INT0);
@@ -1314,7 +1313,7 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg
/* Check if Transmit Interrupt has occurred. */
if(intr0 & TINT0)
amd8111e_tx(dev);
-
+
/* Check if Link Change Interrupt has occurred. */
if (intr0 & LCINT)
amd8111e_link_change(dev);
@@ -1325,21 +1324,21 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *reg
err_no_interrupt:
writel( VAL0 | INTREN,mmio + CMD0);
-
+
spin_unlock(&lp->lock);
-
+
return IRQ_RETVAL(handled);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
static void amd8111e_poll(struct net_device *dev)
-{
+{
unsigned long flags;
- local_save_flags(flags);
+ local_save_flags(flags);
local_irq_disable();
amd8111e_interrupt(0, dev, NULL);
- local_irq_restore(flags);
-}
+ local_irq_restore(flags);
+}
#endif
@@ -1350,35 +1349,35 @@ static int amd8111e_close(struct net_device * dev)
{
struct amd8111e_priv *lp = netdev_priv(dev);
netif_stop_queue(dev);
-
+
spin_lock_irq(&lp->lock);
-
+
amd8111e_disable_interrupt(lp);
amd8111e_stop_chip(lp);
amd8111e_free_ring(lp);
-
+
netif_carrier_off(lp->amd8111e_net_dev);
/* Delete ipg timer */
- if(lp->options & OPTION_DYN_IPG_ENABLE)
+ if(lp->options & OPTION_DYN_IPG_ENABLE)
del_timer_sync(&lp->ipg_data.ipg_timer);
spin_unlock_irq(&lp->lock);
free_irq(dev->irq, dev);
-
+
/* Update the statistics before closing */
amd8111e_get_stats(dev);
lp->opened = 0;
return 0;
}
-/* This function opens new interface.It requests irq for the device, initializes the device,buffers and descriptors, and starts the device.
+/* This function opens new interface.It requests irq for the device, initializes the device,buffers and descriptors, and starts the device.
*/
static int amd8111e_open(struct net_device * dev )
{
struct amd8111e_priv *lp = netdev_priv(dev);
- if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, SA_SHIRQ,
- dev->name, dev))
+ if(dev->irq ==0 || request_irq(dev->irq, amd8111e_interrupt, IRQF_SHARED,
+ dev->name, dev))
return -EAGAIN;
spin_lock_irq(&lp->lock);
@@ -1392,7 +1391,7 @@ static int amd8111e_open(struct net_device * dev )
return -ENOMEM;
}
/* Start ipg timer */
- if(lp->options & OPTION_DYN_IPG_ENABLE){
+ if(lp->options & OPTION_DYN_IPG_ENABLE){
add_timer(&lp->ipg_data.ipg_timer);
printk(KERN_INFO "%s: Dynamic IPG Enabled.\n",dev->name);
}
@@ -1403,21 +1402,21 @@ static int amd8111e_open(struct net_device * dev )
netif_start_queue(dev);
- return 0;
+ return 0;
}
-/*
+/*
This function checks if there is any transmit descriptors available to queue more packet.
*/
static int amd8111e_tx_queue_avail(struct amd8111e_priv* lp )
-{
+{
int tx_index = lp->tx_idx & TX_BUFF_MOD_MASK;
if(lp->tx_skbuff[tx_index] != 0)
return -1;
else
return 0;
-
+
}
-/*
+/*
This function will queue the transmit packets to the descriptors and will trigger the send operation. It also initializes the transmit descriptors with buffer physical address, byte count, ownership to hardware etc.
*/
@@ -1438,9 +1437,9 @@ static int amd8111e_start_xmit(struct sk_buff *skb, struct net_device * dev)
#if AMD8111E_VLAN_TAG_USED
if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){
- lp->tx_ring[tx_index].tag_ctrl_cmd |=
- cpu_to_le16(TCC_VLAN_INSERT);
- lp->tx_ring[tx_index].tag_ctrl_info =
+ lp->tx_ring[tx_index].tag_ctrl_cmd |=
+ cpu_to_le16(TCC_VLAN_INSERT);
+ lp->tx_ring[tx_index].tag_ctrl_info =
cpu_to_le16(vlan_tx_tag_get(skb));
}
@@ -1511,14 +1510,14 @@ static int amd8111e_ether_crc(int len, char* mac_addr)
}
else
crc >>= 1;
-
+
octet >>= 1;
}
- }
- return crc;
+ }
+ return crc;
}
/*
-This function sets promiscuos mode, all-multi mode or the multicast address
+This function sets promiscuos mode, all-multi mode or the multicast address
list to the device.
*/
static void amd8111e_set_multicast_list(struct net_device *dev)
@@ -1528,7 +1527,6 @@ static void amd8111e_set_multicast_list(struct net_device *dev)
u32 mc_filter[2] ;
int i,bit_num;
if(dev->flags & IFF_PROMISC){
- printk(KERN_INFO "%s: Setting promiscuous mode.\n",dev->name);
writel( VAL2 | PROM, lp->mmio + CMD2);
return;
}
@@ -1560,7 +1558,7 @@ static void amd8111e_set_multicast_list(struct net_device *dev)
i++, mc_ptr = mc_ptr->next) {
bit_num = ( amd8111e_ether_crc(ETH_ALEN,mc_ptr->dmi_addr) >> 26 ) & 0x3f;
mc_filter[bit_num >> 5] |= 1 << (bit_num & 31);
- }
+ }
amd8111e_writeq(*(u64*)mc_filter,lp->mmio+ LADRF);
/* To eliminate PCI posting bug */
@@ -1636,18 +1634,18 @@ static int amd8111e_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol_
return -EINVAL;
spin_lock_irq(&lp->lock);
if (wol_info->wolopts & WAKE_MAGIC)
- lp->options |=
+ lp->options |=
(OPTION_WOL_ENABLE | OPTION_WAKE_MAGIC_ENABLE);
else if(wol_info->wolopts & WAKE_PHY)
- lp->options |=
+ lp->options |=
(OPTION_WOL_ENABLE | OPTION_WAKE_PHY_ENABLE);
else
- lp->options &= ~OPTION_WOL_ENABLE;
+ lp->options &= ~OPTION_WOL_ENABLE;
spin_unlock_irq(&lp->lock);
return 0;
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = amd8111e_get_drvinfo,
.get_regs_len = amd8111e_get_regs_len,
.get_regs = amd8111e_get_regs,
@@ -1660,9 +1658,9 @@ static struct ethtool_ops ops = {
};
/*
-This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application.
+This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application.
*/
-
+
static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *data = if_mii(ifr);
@@ -1678,7 +1676,7 @@ static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd)
data->phy_id = lp->ext_phy_addr;
/* fallthru */
- case SIOCGMIIREG:
+ case SIOCGMIIREG:
spin_lock_irq(&lp->lock);
err = amd8111e_read_phy(lp, data->phy_id,
@@ -1713,16 +1711,16 @@ static int amd8111e_set_mac_address(struct net_device *dev, void *p)
spin_lock_irq(&lp->lock);
/* Setting the MAC address to the device */
for(i = 0; i < ETH_ADDR_LEN; i++)
- writeb( dev->dev_addr[i], lp->mmio + PADR + i );
-
+ writeb( dev->dev_addr[i], lp->mmio + PADR + i );
+
spin_unlock_irq(&lp->lock);
return 0;
}
-/*
+/*
This function changes the mtu of the device. It restarts the device to initialize the descriptor with new receive buffers.
-*/
+*/
static int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
{
struct amd8111e_priv *lp = netdev_priv(dev);
@@ -1733,7 +1731,7 @@ static int amd8111e_change_mtu(struct net_device *dev, int new_mtu)
if (!netif_running(dev)) {
/* new_mtu will be used
- when device starts netxt time */
+ when device starts netxt time */
dev->mtu = new_mtu;
return 0;
}
@@ -1760,7 +1758,7 @@ static void amd8111e_vlan_rx_register(struct net_device *dev, struct vlan_group
lp->vlgrp = grp;
spin_unlock_irq(&lp->lock);
}
-
+
static void amd8111e_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct amd8111e_priv *lp = netdev_priv(dev);
@@ -1785,11 +1783,11 @@ static int amd8111e_enable_link_change(struct amd8111e_priv* lp)
/* Adapter is already stoped/suspended/interrupt-disabled */
writel(VAL0|LCMODE_SW,lp->mmio + CMD7);
-
+
/* To eliminate PCI posting bug */
readl(lp->mmio + CMD7);
return 0;
-}
+}
/* This function is called when a packet transmission fails to complete within a resonable period, on the assumption that an interrupts have been failed or the interface is locked up. This function will reinitialize the hardware */
static void amd8111e_tx_timeout(struct net_device *dev)
@@ -1806,10 +1804,10 @@ static void amd8111e_tx_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
static int amd8111e_suspend(struct pci_dev *pci_dev, pm_message_t state)
-{
+{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct amd8111e_priv *lp = netdev_priv(dev);
-
+
if (!netif_running(dev))
return 0;
@@ -1819,10 +1817,10 @@ static int amd8111e_suspend(struct pci_dev *pci_dev, pm_message_t state)
spin_unlock_irq(&lp->lock);
netif_device_detach(dev);
-
+
/* stop chip */
spin_lock_irq(&lp->lock);
- if(lp->options & OPTION_DYN_IPG_ENABLE)
+ if(lp->options & OPTION_DYN_IPG_ENABLE)
del_timer_sync(&lp->ipg_data.ipg_timer);
amd8111e_stop_chip(lp);
spin_unlock_irq(&lp->lock);
@@ -1830,19 +1828,19 @@ static int amd8111e_suspend(struct pci_dev *pci_dev, pm_message_t state)
if(lp->options & OPTION_WOL_ENABLE){
/* enable wol */
if(lp->options & OPTION_WAKE_MAGIC_ENABLE)
- amd8111e_enable_magicpkt(lp);
+ amd8111e_enable_magicpkt(lp);
if(lp->options & OPTION_WAKE_PHY_ENABLE)
- amd8111e_enable_link_change(lp);
-
+ amd8111e_enable_link_change(lp);
+
pci_enable_wake(pci_dev, PCI_D3hot, 1);
pci_enable_wake(pci_dev, PCI_D3cold, 1);
}
- else{
+ else{
pci_enable_wake(pci_dev, PCI_D3hot, 0);
pci_enable_wake(pci_dev, PCI_D3cold, 0);
}
-
+
pci_save_state(pci_dev);
pci_set_power_state(pci_dev, PCI_D3hot);
@@ -1852,7 +1850,7 @@ static int amd8111e_resume(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
struct amd8111e_priv *lp = netdev_priv(dev);
-
+
if (!netif_running(dev))
return 0;
@@ -1867,8 +1865,8 @@ static int amd8111e_resume(struct pci_dev *pci_dev)
spin_lock_irq(&lp->lock);
amd8111e_restart(dev);
/* Restart ipg timer */
- if(lp->options & OPTION_DYN_IPG_ENABLE)
- mod_timer(&lp->ipg_data.ipg_timer,
+ if(lp->options & OPTION_DYN_IPG_ENABLE)
+ mod_timer(&lp->ipg_data.ipg_timer,
jiffies + IPG_CONVERGE_JIFFIES);
spin_unlock_irq(&lp->lock);
@@ -1896,16 +1894,16 @@ static void amd8111e_config_ipg(struct net_device* dev)
unsigned int prev_col_cnt = ipg_data->col_cnt;
unsigned int total_col_cnt;
unsigned int tmp_ipg;
-
+
if(lp->link_config.duplex == DUPLEX_FULL){
ipg_data->ipg = DEFAULT_IPG;
return;
}
if(ipg_data->ipg_state == SSTATE){
-
+
if(ipg_data->timer_tick == IPG_STABLE_TIME){
-
+
ipg_data->timer_tick = 0;
ipg_data->ipg = MIN_IPG - IPG_STEP;
ipg_data->current_ipg = MIN_IPG;
@@ -1917,15 +1915,15 @@ static void amd8111e_config_ipg(struct net_device* dev)
}
if(ipg_data->ipg_state == CSTATE){
-
+
/* Get the current collision count */
- total_col_cnt = ipg_data->col_cnt =
+ total_col_cnt = ipg_data->col_cnt =
amd8111e_read_mib(mmio, xmt_collisions);
- if ((total_col_cnt - prev_col_cnt) <
+ if ((total_col_cnt - prev_col_cnt) <
(ipg_data->diff_col_cnt)){
-
+
ipg_data->diff_col_cnt =
total_col_cnt - prev_col_cnt ;
@@ -1940,8 +1938,8 @@ static void amd8111e_config_ipg(struct net_device* dev)
tmp_ipg = ipg_data->ipg;
ipg_data->ipg_state = SSTATE;
}
- writew((u32)tmp_ipg, mmio + IPG);
- writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1);
+ writew((u32)tmp_ipg, mmio + IPG);
+ writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1);
}
mod_timer(&lp->ipg_data.ipg_timer, jiffies + IPG_CONVERGE_JIFFIES);
return;
@@ -2012,7 +2010,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
"exiting.\n");
goto err_free_reg;
}
-
+
reg_addr = pci_resource_start(pdev, 0);
reg_len = pci_resource_len(pdev, 0);
@@ -2030,8 +2028,8 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
dev->vlan_rx_register =amd8111e_vlan_rx_register;
dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
-#endif
-
+#endif
+
lp = netdev_priv(dev);
lp->pci_dev = pdev;
lp->amd8111e_net_dev = dev;
@@ -2046,17 +2044,17 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
err = -ENOMEM;
goto err_free_dev;
}
-
+
/* Initializing MAC address */
for(i = 0; i < ETH_ADDR_LEN; i++)
dev->dev_addr[i] =readb(lp->mmio + PADR + i);
-
+
/* Setting user defined parametrs */
lp->ext_phy_option = speed_duplex[card_idx];
if(coalesce[card_idx])
- lp->options |= OPTION_INTR_COAL_ENABLE;
+ lp->options |= OPTION_INTR_COAL_ENABLE;
if(dynamic_ipg[card_idx++])
- lp->options |= OPTION_DYN_IPG_ENABLE;
+ lp->options |= OPTION_DYN_IPG_ENABLE;
/* Initialize driver entry points */
dev->open = amd8111e_open;
@@ -2069,21 +2067,21 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
dev->change_mtu = amd8111e_change_mtu;
SET_ETHTOOL_OPS(dev, &ops);
dev->irq =pdev->irq;
- dev->tx_timeout = amd8111e_tx_timeout;
- dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
+ dev->tx_timeout = amd8111e_tx_timeout;
+ dev->watchdog_timeo = AMD8111E_TX_TIMEOUT;
#ifdef CONFIG_AMD8111E_NAPI
dev->poll = amd8111e_rx_poll;
dev->weight = 32;
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = amd8111e_poll;
+ dev->poll_controller = amd8111e_poll;
#endif
#if AMD8111E_VLAN_TAG_USED
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
dev->vlan_rx_register =amd8111e_vlan_rx_register;
dev->vlan_rx_kill_vid = amd8111e_vlan_rx_kill_vid;
-#endif
+#endif
/* Probe the external PHY */
amd8111e_probe_ext_phy(dev);
@@ -2105,13 +2103,13 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
}
pci_set_drvdata(pdev, dev);
-
+
/* Initialize software ipg timer */
- if(lp->options & OPTION_DYN_IPG_ENABLE){
+ if(lp->options & OPTION_DYN_IPG_ENABLE){
init_timer(&lp->ipg_data.ipg_timer);
lp->ipg_data.ipg_timer.data = (unsigned long) dev;
lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg;
- lp->ipg_data.ipg_timer.expires = jiffies +
+ lp->ipg_data.ipg_timer.expires = jiffies +
IPG_CONVERGE_JIFFIES;
lp->ipg_data.ipg = DEFAULT_IPG;
lp->ipg_data.ipg_state = CSTATE;
@@ -2124,7 +2122,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version);
for (i = 0; i < 6; i++)
printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':');
- printk( "\n");
+ printk( "\n");
if (lp->ext_phy_id)
printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n",
dev->name, lp->ext_phy_id, lp->ext_phy_addr);
@@ -2159,7 +2157,7 @@ static struct pci_driver amd8111e_driver = {
static int __init amd8111e_init(void)
{
- return pci_module_init(&amd8111e_driver);
+ return pci_register_driver(&amd8111e_driver);
}
static void __exit amd8111e_cleanup(void)
diff --git a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h
index cfe3a429882..7727d328f65 100644
--- a/drivers/net/amd8111e.h
+++ b/drivers/net/amd8111e.h
@@ -1,6 +1,6 @@
/*
- * Advanced Micro Devices Inc. AMD8111E Linux Network Driver
- * Copyright (C) 2003 Advanced Micro Devices
+ * Advanced Micro Devices Inc. AMD8111E Linux Network Driver
+ * Copyright (C) 2003 Advanced Micro Devices
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -14,7 +14,7 @@
*
* 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
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
Module Name:
@@ -22,11 +22,11 @@ Module Name:
amd8111e.h
Abstract:
-
- AMD8111 based 10/100 Ethernet Controller driver definitions.
+
+ AMD8111 based 10/100 Ethernet Controller driver definitions.
Environment:
-
+
Kernel Mode
Revision History:
@@ -40,7 +40,7 @@ Revision History:
/* Command style register access
-Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register.
+Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register.
eg., if the value 10011010b is written into the least significant byte of a command style register, bits 1,3 and 4 of the register will be set to 1, and the other bits will not be altered. If the value 00011010b is written into the same byte, bits 1,3 and 4 will be cleared to 0 and the other bits will not be altered.
@@ -122,8 +122,8 @@ typedef enum {
ASF_INIT_DONE = (1 << 1),
ASF_INIT_PRESENT = (1 << 0),
-}STAT_ASF_BITS;
-
+}STAT_ASF_BITS;
+
typedef enum {
MIB_CMD_ACTIVE = (1 << 15 ),
@@ -135,7 +135,7 @@ typedef enum {
typedef enum {
-
+
PMAT_DET = (1 << 12),
MP_DET = (1 << 11),
LC_DET = (1 << 10),
@@ -157,7 +157,7 @@ typedef enum {
typedef enum {
INTR = (1 << 31),
- PCSINT = (1 << 28),
+ PCSINT = (1 << 28),
LCINT = (1 << 27),
APINT5 = (1 << 26),
APINT4 = (1 << 25),
@@ -221,7 +221,7 @@ typedef enum {
INTEN0_CLEAR = 0x1F7F7F1F, /* Command style register */
-}INTEN0_BITS;
+}INTEN0_BITS;
typedef enum {
/* VAL2 */
@@ -240,7 +240,7 @@ typedef enum {
INTREN = (1 << 1),
RUN = (1 << 0),
- CMD0_CLEAR = 0x000F0F7F, /* Command style register */
+ CMD0_CLEAR = 0x000F0F7F, /* Command style register */
}CMD0_BITS;
@@ -279,20 +279,20 @@ typedef enum {
ASF_INIT_DONE_ALIAS = (1 << 29),
/* VAL2 */
JUMBO = (1 << 21),
- VSIZE = (1 << 20),
+ VSIZE = (1 << 20),
VLONLY = (1 << 19),
- VL_TAG_DEL = (1 << 18),
+ VL_TAG_DEL = (1 << 18),
/* VAL1 */
- EN_PMGR = (1 << 14),
+ EN_PMGR = (1 << 14),
INTLEVEL = (1 << 13),
- FORCE_FULL_DUPLEX = (1 << 12),
- FORCE_LINK_STATUS = (1 << 11),
- APEP = (1 << 10),
- MPPLBA = (1 << 9),
+ FORCE_FULL_DUPLEX = (1 << 12),
+ FORCE_LINK_STATUS = (1 << 11),
+ APEP = (1 << 10),
+ MPPLBA = (1 << 9),
/* VAL0 */
- RESET_PHY_PULSE = (1 << 2),
- RESET_PHY = (1 << 1),
- PHY_RST_POL = (1 << 0),
+ RESET_PHY_PULSE = (1 << 2),
+ RESET_PHY = (1 << 1),
+ PHY_RST_POL = (1 << 0),
}CMD3_BITS;
@@ -314,7 +314,7 @@ typedef enum {
RESET_PHY_WIDTH = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */
XMTSP_MASK = (1 << 9) | (1 << 8), /* 9:8 */
- XMTSP_128 = (1 << 9), /* 9 */
+ XMTSP_128 = (1 << 9), /* 9 */
XMTSP_64 = (1 << 8),
CACHE_ALIGN = (1 << 4),
BURST_LIMIT_MASK = (0xF << 0 ),
@@ -445,7 +445,7 @@ typedef enum {
DLY_INT_B_T1 = (1 << 25),
DLY_INT_B_T0 = ( 1 << 24),
EVENT_COUNT_B = (0xF << 16) | (0x1 << 20),/* 20:16 */
- MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)|
+ MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)|
(1 << 9) | (1 << 10), /* 10:0 */
}DLY_INT_B_BITS;
@@ -569,20 +569,20 @@ typedef enum {
#define MAX_UNITS 8 /* Maximum number of devices possible */
#define NUM_TX_BUFFERS 32 /* Number of transmit buffers */
-#define NUM_RX_BUFFERS 32 /* Number of receive buffers */
+#define NUM_RX_BUFFERS 32 /* Number of receive buffers */
#define TX_BUFF_MOD_MASK 31 /* (NUM_TX_BUFFERS -1) */
#define RX_BUFF_MOD_MASK 31 /* (NUM_RX_BUFFERS -1) */
-#define NUM_TX_RING_DR 32
-#define NUM_RX_RING_DR 32
+#define NUM_TX_RING_DR 32
+#define NUM_RX_RING_DR 32
#define TX_RING_DR_MOD_MASK 31 /* (NUM_TX_RING_DR -1) */
#define RX_RING_DR_MOD_MASK 31 /* (NUM_RX_RING_DR -1) */
-#define MAX_FILTER_SIZE 64 /* Maximum multicast address */
-#define AMD8111E_MIN_MTU 60
-#define AMD8111E_MAX_MTU 9000
+#define MAX_FILTER_SIZE 64 /* Maximum multicast address */
+#define AMD8111E_MIN_MTU 60
+#define AMD8111E_MAX_MTU 9000
#define PKT_BUFF_SZ 1536
#define MIN_PKT_LEN 60
@@ -591,7 +591,7 @@ typedef enum {
#define AMD8111E_TX_TIMEOUT (3 * HZ)/* 3 sec */
#define SOFT_TIMER_FREQ 0xBEBC /* 0.5 sec */
#define DELAY_TIMER_CONV 50 /* msec to 10 usec conversion.
- Only 500 usec resolution */
+ Only 500 usec resolution */
#define OPTION_VLAN_ENABLE 0x0001
#define OPTION_JUMBO_ENABLE 0x0002
#define OPTION_MULTICAST_ENABLE 0x0004
@@ -611,12 +611,12 @@ typedef enum {
#define MIN_IPG 96
#define MAX_IPG 255
#define IPG_STEP 16
-#define CSTATE 1
-#define SSTATE 2
+#define CSTATE 1
+#define SSTATE 2
/* Assume contoller gets data 10 times the maximum processing time */
-#define REPEAT_CNT 10;
-
+#define REPEAT_CNT 10;
+
/* amd8111e decriptor flag definitions */
typedef enum {
@@ -649,7 +649,7 @@ typedef enum {
#define TCC_MASK 0x0003
/* driver ioctl parameters */
-#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32)
+#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32)
/* crc generator constants */
#define CRC32 0xedb88320
@@ -670,15 +670,15 @@ struct amd8111e_tx_dr{
u32 buff_phy_addr;
u32 reserved;
-};
+};
struct amd8111e_rx_dr{
-
+
u32 reserved;
u16 msg_count; /* Received message len */
- u16 tag_ctrl_info;
+ u16 tag_ctrl_info;
u16 buff_count; /* Len of the buffer pointed by descriptor. */
@@ -692,7 +692,7 @@ struct amd8111e_link_config{
#define SPEED_INVALID 0xffff
#define DUPLEX_INVALID 0xff
#define AUTONEG_INVALID 0xff
-
+
unsigned long orig_phy_option;
u16 speed;
u8 duplex;
@@ -709,7 +709,7 @@ enum coal_type{
};
-enum coal_mode{
+enum coal_mode{
RX_INTR_COAL,
TX_INTR_COAL,
DISABLE_COAL,
@@ -727,7 +727,7 @@ struct amd8111e_coalesce_conf{
unsigned long rx_bytes;
unsigned long rx_prev_bytes;
unsigned int rx_coal_type;
-
+
unsigned int tx_timeout;
unsigned int tx_event_count;
unsigned long tx_packets;
@@ -738,7 +738,7 @@ struct amd8111e_coalesce_conf{
};
struct ipg_info{
-
+
unsigned int ipg_state;
unsigned int ipg;
unsigned int current_ipg;
@@ -750,7 +750,7 @@ struct ipg_info{
};
struct amd8111e_priv{
-
+
struct amd8111e_tx_dr* tx_ring;
struct amd8111e_rx_dr* rx_ring;
dma_addr_t tx_ring_dma_addr; /* tx descriptor ring base address */
@@ -766,7 +766,7 @@ struct amd8111e_priv{
dma_addr_t rx_dma_addr[NUM_RX_BUFFERS];
/* Reg memory mapped address */
void __iomem *mmio;
-
+
spinlock_t lock; /* Guard lock */
unsigned long rx_idx, tx_idx; /* The next free ring entry */
unsigned long tx_complete_idx;
@@ -778,7 +778,7 @@ struct amd8111e_priv{
unsigned long ext_phy_option;
int ext_phy_addr;
u32 ext_phy_id;
-
+
struct amd8111e_link_config link_config;
int pm_cap;
@@ -787,22 +787,22 @@ struct amd8111e_priv{
struct mii_if_info mii_if;
#if AMD8111E_VLAN_TAG_USED
struct vlan_group *vlgrp;
-#endif
+#endif
char opened;
struct net_device_stats stats;
unsigned int drv_rx_errors;
struct dev_mc_list* mc_list;
struct amd8111e_coalesce_conf coal_conf;
- struct ipg_info ipg_data;
-
+ struct ipg_info ipg_data;
+
};
/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register.
BUG? */
#define amd8111e_writeq(_UlData,_memMap) \
writel(*(u32*)(&_UlData), _memMap); \
- writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)
+ writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4)
/* maps the external speed options to internal value */
typedef enum {
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index b9820b86cdc..643b08cc740 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -132,9 +132,9 @@ struct net_device * __init apne_probe(int unit)
if ( !(AMIGAHW_PRESENT(PCMCIA)) )
return ERR_PTR(-ENODEV);
-
+
printk("Looking for PCMCIA ethernet card : ");
-
+
/* check if a card is inserted */
if (!(PCMCIA_INSERTED)) {
printk("NO PCMCIA card inserted\n");
@@ -205,7 +205,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
int neX000, ctron;
#endif
static unsigned version_printed;
-
+
if (ei_debug && version_printed++ == 0)
printk(version);
@@ -261,13 +261,13 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
/* At this point, wordlength *only* tells us if the SA_prom is doubled
up or not because some broken PCI cards don't respect the byte-wide
- request in program_seq above, and hence don't have doubled up values.
+ request in program_seq above, and hence don't have doubled up values.
These broken cards would otherwise be detected as an ne1000. */
if (wordlength == 2)
for (i = 0; i < 16; i++)
SA_prom[i] = SA_prom[i+i];
-
+
if (wordlength == 2) {
/* We must set the 8390 for word mode. */
outb(0x49, ioaddr + NE_EN0_DCFG);
@@ -313,7 +313,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
dev->base_addr = ioaddr;
/* Install the Interrupt handler */
- i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, SA_SHIRQ, DRV_NAME, dev);
+ i = request_irq(IRQ_AMIGA_PORTS, apne_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
for(i = 0; i < ETHER_ADDR_LEN; i++) {
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
index b14e89004c3..0a0e0cd81a2 100644
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -29,7 +29,7 @@ config ATALK
even politically correct people are allowed to say Y here.
config DEV_APPLETALK
- bool "Appletalk interfaces support"
+ tristate "Appletalk interfaces support"
depends on ATALK
help
AppleTalk is the protocol that Apple computers can use to communicate
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index 9edaa183227..ae7f828344d 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -48,7 +48,6 @@ static const char *version =
* the driver figure it out.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -1031,7 +1030,7 @@ module_param(io, int, 0);
module_param(irq, int, 0);
module_param(board_type, int, 0);
-int init_module(void)
+int __init init_module(void)
{
if (io == 0)
printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
diff --git a/drivers/net/appletalk/cops_ffdrv.h b/drivers/net/appletalk/cops_ffdrv.h
index 31cf8c9c947..b02005087c1 100644
--- a/drivers/net/appletalk/cops_ffdrv.h
+++ b/drivers/net/appletalk/cops_ffdrv.h
@@ -24,7 +24,6 @@
* - Jay Schulist <jschlst@samba.org>
*/
-#include <linux/config.h>
#ifdef CONFIG_COPS_DAYNA
diff --git a/drivers/net/appletalk/cops_ltdrv.h b/drivers/net/appletalk/cops_ltdrv.h
index 4afb8e18ba6..c699b1ad31d 100644
--- a/drivers/net/appletalk/cops_ltdrv.h
+++ b/drivers/net/appletalk/cops_ltdrv.h
@@ -23,7 +23,6 @@
* - Jay Schulist <jschlst@samba.org>
*/
-#include <linux/config.h>
#ifdef CONFIG_COPS_TANGENT
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 1a44a79ed06..b98592a8bac 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -23,7 +23,6 @@
* of the GNU General Public License, incorporated herein by reference.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -146,9 +145,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
/* Create the Extended DDP header */
ddp = (struct ddpehdr *)skb->data;
- ddp->deh_len = skb->len;
- ddp->deh_hops = 1;
- ddp->deh_pad = 0;
+ ddp->deh_len_hops = htons(skb->len + (1<<10));
ddp->deh_sum = 0;
/*
@@ -171,7 +168,6 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
ddp->deh_sport = 72;
*((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
- *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index fabc0607b0f..5a95005253f 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -44,7 +44,6 @@
#define VERSION "arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al.\n"
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 96636ca8754..98d326b23c9 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -120,7 +120,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de
goto out_port;
}
- if ((err = com20020_found(dev, SA_SHIRQ)) != 0)
+ if ((err = com20020_found(dev, IRQF_SHARED)) != 0)
goto out_port;
return 0;
@@ -161,6 +161,7 @@ static struct pci_device_id com20020pci_id_table[] = {
{ 0x1571, 0xa204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x1571, 0xa206, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
+ { 0x10B5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{ 0x10B5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ARC_CAN_10MBIT },
{0,}
};
@@ -177,7 +178,7 @@ static struct pci_driver com20020pci_driver = {
static int __init com20020pci_init(void)
{
BUGLVL(D_NORMAL) printk(VERSION);
- return pci_module_init(&com20020pci_driver);
+ return pci_register_driver(&com20020pci_driver);
}
static void __exit com20020pci_cleanup(void)
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index a9bb7a4aff9..3aef3c10d56 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -320,7 +320,7 @@ static int ariadne_open(struct net_device *dev)
netif_start_queue(dev);
- i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, SA_SHIRQ,
+ i = request_irq(IRQ_AMIGA_PORTS, ariadne_interrupt, IRQF_SHARED,
dev->name, dev);
if (i) return i;
@@ -825,8 +825,6 @@ static void set_multicast_list(struct net_device *dev)
ariadne_init_ring(dev);
if (dev->flags & IFF_PROMISC) {
- /* Log any net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
lance->RAP = CSR15; /* Mode Register */
lance->RDP = PROM; /* Set promiscuous mode */
} else {
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index 77fe20dbea3..678e4f48d36 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -39,3 +39,10 @@ config ARM_AT91_ETHER
help
If you wish to compile a kernel for the AT91RM9200 and enable
ethernet support, then you should always answer Y to this.
+
+config EP93XX_ETH
+ tristate "EP93xx Ethernet support"
+ depends on NET_ETHERNET && ARM && ARCH_EP93XX
+ help
+ This is a driver for the ethernet hardware included in EP93xx CPUs.
+ Say Y if you are building a kernel for EP93xx based devices.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
index 42c95b79c26..a4c868278e1 100644
--- a/drivers/net/arm/Makefile
+++ b/drivers/net/arm/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_ARM_ETHERH) += etherh.o
obj-$(CONFIG_ARM_ETHER3) += ether3.o
obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
+obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 613005a0285..3ecf2cc53a7 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/mii.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -649,7 +648,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
}
-static struct ethtool_ops at91ether_ethtool_ops = {
+static const struct ethtool_ops at91ether_ethtool_ops = {
.get_settings = at91ether_get_settings,
.set_settings = at91ether_set_settings,
.get_drvinfo = at91ether_get_drvinfo,
@@ -948,7 +947,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
return -ENOMEM;
dev->base_addr = AT91_VA_BASE_EMAC;
- dev->irq = AT91_ID_EMAC;
+ dev->irq = AT91RM9200_ID_EMAC;
SET_MODULE_OWNER(dev);
/* Install the interrupt handler */
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
new file mode 100644
index 00000000000..cef00744a9d
--- /dev/null
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -0,0 +1,944 @@
+/*
+ * EP93xx ethernet network device driver
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Dedicated to Marija Kulikova.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <asm/arch/ep93xx-regs.h>
+#include <asm/arch/platform.h>
+#include <asm/io.h>
+
+#define DRV_MODULE_NAME "ep93xx-eth"
+#define DRV_MODULE_VERSION "0.1"
+
+#define RX_QUEUE_ENTRIES 64
+#define TX_QUEUE_ENTRIES 8
+
+#define MAX_PKT_SIZE 2044
+#define PKT_BUF_SIZE 2048
+
+#define REG_RXCTL 0x0000
+#define REG_RXCTL_DEFAULT 0x00073800
+#define REG_TXCTL 0x0004
+#define REG_TXCTL_ENABLE 0x00000001
+#define REG_MIICMD 0x0010
+#define REG_MIICMD_READ 0x00008000
+#define REG_MIICMD_WRITE 0x00004000
+#define REG_MIIDATA 0x0014
+#define REG_MIISTS 0x0018
+#define REG_MIISTS_BUSY 0x00000001
+#define REG_SELFCTL 0x0020
+#define REG_SELFCTL_RESET 0x00000001
+#define REG_INTEN 0x0024
+#define REG_INTEN_TX 0x00000008
+#define REG_INTEN_RX 0x00000007
+#define REG_INTSTSP 0x0028
+#define REG_INTSTS_TX 0x00000008
+#define REG_INTSTS_RX 0x00000004
+#define REG_INTSTSC 0x002c
+#define REG_AFP 0x004c
+#define REG_INDAD0 0x0050
+#define REG_INDAD1 0x0051
+#define REG_INDAD2 0x0052
+#define REG_INDAD3 0x0053
+#define REG_INDAD4 0x0054
+#define REG_INDAD5 0x0055
+#define REG_GIINTMSK 0x0064
+#define REG_GIINTMSK_ENABLE 0x00008000
+#define REG_BMCTL 0x0080
+#define REG_BMCTL_ENABLE_TX 0x00000100
+#define REG_BMCTL_ENABLE_RX 0x00000001
+#define REG_BMSTS 0x0084
+#define REG_BMSTS_RX_ACTIVE 0x00000008
+#define REG_RXDQBADD 0x0090
+#define REG_RXDQBLEN 0x0094
+#define REG_RXDCURADD 0x0098
+#define REG_RXDENQ 0x009c
+#define REG_RXSTSQBADD 0x00a0
+#define REG_RXSTSQBLEN 0x00a4
+#define REG_RXSTSQCURADD 0x00a8
+#define REG_RXSTSENQ 0x00ac
+#define REG_TXDQBADD 0x00b0
+#define REG_TXDQBLEN 0x00b4
+#define REG_TXDQCURADD 0x00b8
+#define REG_TXDENQ 0x00bc
+#define REG_TXSTSQBADD 0x00c0
+#define REG_TXSTSQBLEN 0x00c4
+#define REG_TXSTSQCURADD 0x00c8
+#define REG_MAXFRMLEN 0x00e8
+
+struct ep93xx_rdesc
+{
+ u32 buf_addr;
+ u32 rdesc1;
+};
+
+#define RDESC1_NSOF 0x80000000
+#define RDESC1_BUFFER_INDEX 0x7fff0000
+#define RDESC1_BUFFER_LENGTH 0x0000ffff
+
+struct ep93xx_rstat
+{
+ u32 rstat0;
+ u32 rstat1;
+};
+
+#define RSTAT0_RFP 0x80000000
+#define RSTAT0_RWE 0x40000000
+#define RSTAT0_EOF 0x20000000
+#define RSTAT0_EOB 0x10000000
+#define RSTAT0_AM 0x00c00000
+#define RSTAT0_RX_ERR 0x00200000
+#define RSTAT0_OE 0x00100000
+#define RSTAT0_FE 0x00080000
+#define RSTAT0_RUNT 0x00040000
+#define RSTAT0_EDATA 0x00020000
+#define RSTAT0_CRCE 0x00010000
+#define RSTAT0_CRCI 0x00008000
+#define RSTAT0_HTI 0x00003f00
+#define RSTAT1_RFP 0x80000000
+#define RSTAT1_BUFFER_INDEX 0x7fff0000
+#define RSTAT1_FRAME_LENGTH 0x0000ffff
+
+struct ep93xx_tdesc
+{
+ u32 buf_addr;
+ u32 tdesc1;
+};
+
+#define TDESC1_EOF 0x80000000
+#define TDESC1_BUFFER_INDEX 0x7fff0000
+#define TDESC1_BUFFER_ABORT 0x00008000
+#define TDESC1_BUFFER_LENGTH 0x00000fff
+
+struct ep93xx_tstat
+{
+ u32 tstat0;
+};
+
+#define TSTAT0_TXFP 0x80000000
+#define TSTAT0_TXWE 0x40000000
+#define TSTAT0_FA 0x20000000
+#define TSTAT0_LCRS 0x10000000
+#define TSTAT0_OW 0x04000000
+#define TSTAT0_TXU 0x02000000
+#define TSTAT0_ECOLL 0x01000000
+#define TSTAT0_NCOLL 0x001f0000
+#define TSTAT0_BUFFER_INDEX 0x00007fff
+
+struct ep93xx_descs
+{
+ struct ep93xx_rdesc rdesc[RX_QUEUE_ENTRIES];
+ struct ep93xx_tdesc tdesc[TX_QUEUE_ENTRIES];
+ struct ep93xx_rstat rstat[RX_QUEUE_ENTRIES];
+ struct ep93xx_tstat tstat[TX_QUEUE_ENTRIES];
+};
+
+struct ep93xx_priv
+{
+ struct resource *res;
+ void *base_addr;
+ int irq;
+
+ struct ep93xx_descs *descs;
+ dma_addr_t descs_dma_addr;
+
+ void *rx_buf[RX_QUEUE_ENTRIES];
+ void *tx_buf[TX_QUEUE_ENTRIES];
+
+ spinlock_t rx_lock;
+ unsigned int rx_pointer;
+ unsigned int tx_clean_pointer;
+ unsigned int tx_pointer;
+ spinlock_t tx_pending_lock;
+ unsigned int tx_pending;
+
+ struct net_device_stats stats;
+
+ struct mii_if_info mii;
+ u8 mdc_divisor;
+};
+
+#define rdb(ep, off) __raw_readb((ep)->base_addr + (off))
+#define rdw(ep, off) __raw_readw((ep)->base_addr + (off))
+#define rdl(ep, off) __raw_readl((ep)->base_addr + (off))
+#define wrb(ep, off, val) __raw_writeb((val), (ep)->base_addr + (off))
+#define wrw(ep, off, val) __raw_writew((val), (ep)->base_addr + (off))
+#define wrl(ep, off, val) __raw_writel((val), (ep)->base_addr + (off))
+
+static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg);
+
+static struct net_device_stats *ep93xx_get_stats(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ return &(ep->stats);
+}
+
+static int ep93xx_rx(struct net_device *dev, int *budget)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int tail_offset;
+ int rx_done;
+ int processed;
+
+ tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr;
+
+ rx_done = 0;
+ processed = 0;
+ while (*budget > 0) {
+ int entry;
+ struct ep93xx_rstat *rstat;
+ u32 rstat0;
+ u32 rstat1;
+ int length;
+ struct sk_buff *skb;
+
+ entry = ep->rx_pointer;
+ rstat = ep->descs->rstat + entry;
+ if ((void *)rstat - (void *)ep->descs == tail_offset) {
+ rx_done = 1;
+ break;
+ }
+
+ rstat0 = rstat->rstat0;
+ rstat1 = rstat->rstat1;
+ rstat->rstat0 = 0;
+ rstat->rstat1 = 0;
+
+ if (!(rstat0 & RSTAT0_RFP))
+ printk(KERN_CRIT "ep93xx_rx: buffer not done "
+ " %.8x %.8x\n", rstat0, rstat1);
+ if (!(rstat0 & RSTAT0_EOF))
+ printk(KERN_CRIT "ep93xx_rx: not end-of-frame "
+ " %.8x %.8x\n", rstat0, rstat1);
+ if (!(rstat0 & RSTAT0_EOB))
+ printk(KERN_CRIT "ep93xx_rx: not end-of-buffer "
+ " %.8x %.8x\n", rstat0, rstat1);
+ if (!(rstat1 & RSTAT1_RFP))
+ printk(KERN_CRIT "ep93xx_rx: buffer1 not done "
+ " %.8x %.8x\n", rstat0, rstat1);
+ if ((rstat1 & RSTAT1_BUFFER_INDEX) >> 16 != entry)
+ printk(KERN_CRIT "ep93xx_rx: entry mismatch "
+ " %.8x %.8x\n", rstat0, rstat1);
+
+ if (!(rstat0 & RSTAT0_RWE)) {
+ printk(KERN_NOTICE "ep93xx_rx: receive error "
+ " %.8x %.8x\n", rstat0, rstat1);
+
+ ep->stats.rx_errors++;
+ if (rstat0 & RSTAT0_OE)
+ ep->stats.rx_fifo_errors++;
+ if (rstat0 & RSTAT0_FE)
+ ep->stats.rx_frame_errors++;
+ if (rstat0 & (RSTAT0_RUNT | RSTAT0_EDATA))
+ ep->stats.rx_length_errors++;
+ if (rstat0 & RSTAT0_CRCE)
+ ep->stats.rx_crc_errors++;
+ goto err;
+ }
+
+ length = rstat1 & RSTAT1_FRAME_LENGTH;
+ if (length > MAX_PKT_SIZE) {
+ printk(KERN_NOTICE "ep93xx_rx: invalid length "
+ " %.8x %.8x\n", rstat0, rstat1);
+ goto err;
+ }
+
+ /* Strip FCS. */
+ if (rstat0 & RSTAT0_CRCI)
+ length -= 4;
+
+ skb = dev_alloc_skb(length + 2);
+ if (likely(skb != NULL)) {
+ skb->dev = dev;
+ skb_reserve(skb, 2);
+ dma_sync_single(NULL, ep->descs->rdesc[entry].buf_addr,
+ length, DMA_FROM_DEVICE);
+ eth_copy_and_sum(skb, ep->rx_buf[entry], length, 0);
+ skb_put(skb, length);
+ skb->protocol = eth_type_trans(skb, dev);
+
+ dev->last_rx = jiffies;
+
+ netif_receive_skb(skb);
+
+ ep->stats.rx_packets++;
+ ep->stats.rx_bytes += length;
+ } else {
+ ep->stats.rx_dropped++;
+ }
+
+err:
+ ep->rx_pointer = (entry + 1) & (RX_QUEUE_ENTRIES - 1);
+ processed++;
+ dev->quota--;
+ (*budget)--;
+ }
+
+ if (processed) {
+ wrw(ep, REG_RXDENQ, processed);
+ wrw(ep, REG_RXSTSENQ, processed);
+ }
+
+ return !rx_done;
+}
+
+static int ep93xx_have_more_rx(struct ep93xx_priv *ep)
+{
+ struct ep93xx_rstat *rstat;
+ int tail_offset;
+
+ rstat = ep->descs->rstat + ep->rx_pointer;
+ tail_offset = rdl(ep, REG_RXSTSQCURADD) - ep->descs_dma_addr;
+
+ return !((void *)rstat - (void *)ep->descs == tail_offset);
+}
+
+static int ep93xx_poll(struct net_device *dev, int *budget)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+
+ /*
+ * @@@ Have to stop polling if device is downed while we
+ * are polling.
+ */
+
+poll_some_more:
+ if (ep93xx_rx(dev, budget))
+ return 1;
+
+ netif_rx_complete(dev);
+
+ spin_lock_irq(&ep->rx_lock);
+ wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
+ if (ep93xx_have_more_rx(ep)) {
+ wrl(ep, REG_INTEN, REG_INTEN_TX);
+ wrl(ep, REG_INTSTSP, REG_INTSTS_RX);
+ spin_unlock_irq(&ep->rx_lock);
+
+ if (netif_rx_reschedule(dev, 0))
+ goto poll_some_more;
+
+ return 0;
+ }
+ spin_unlock_irq(&ep->rx_lock);
+
+ return 0;
+}
+
+static int ep93xx_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int entry;
+
+ if (unlikely(skb->len) > MAX_PKT_SIZE) {
+ ep->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ entry = ep->tx_pointer;
+ ep->tx_pointer = (ep->tx_pointer + 1) & (TX_QUEUE_ENTRIES - 1);
+
+ ep->descs->tdesc[entry].tdesc1 =
+ TDESC1_EOF | (entry << 16) | (skb->len & 0xfff);
+ skb_copy_and_csum_dev(skb, ep->tx_buf[entry]);
+ dma_sync_single(NULL, ep->descs->tdesc[entry].buf_addr,
+ skb->len, DMA_TO_DEVICE);
+ dev_kfree_skb(skb);
+
+ dev->trans_start = jiffies;
+
+ spin_lock_irq(&ep->tx_pending_lock);
+ ep->tx_pending++;
+ if (ep->tx_pending == TX_QUEUE_ENTRIES)
+ netif_stop_queue(dev);
+ spin_unlock_irq(&ep->tx_pending_lock);
+
+ wrl(ep, REG_TXDENQ, 1);
+
+ return NETDEV_TX_OK;
+}
+
+static void ep93xx_tx_complete(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int tail_offset;
+ int wake;
+
+ tail_offset = rdl(ep, REG_TXSTSQCURADD) - ep->descs_dma_addr;
+ wake = 0;
+
+ spin_lock(&ep->tx_pending_lock);
+ while (1) {
+ int entry;
+ struct ep93xx_tstat *tstat;
+ u32 tstat0;
+
+ entry = ep->tx_clean_pointer;
+ tstat = ep->descs->tstat + entry;
+ if ((void *)tstat - (void *)ep->descs == tail_offset)
+ break;
+
+ tstat0 = tstat->tstat0;
+ tstat->tstat0 = 0;
+
+ if (!(tstat0 & TSTAT0_TXFP))
+ printk(KERN_CRIT "ep93xx_tx_complete: buffer not done "
+ " %.8x\n", tstat0);
+ if (tstat0 & TSTAT0_FA)
+ printk(KERN_CRIT "ep93xx_tx_complete: frame aborted "
+ " %.8x\n", tstat0);
+ if ((tstat0 & TSTAT0_BUFFER_INDEX) != entry)
+ printk(KERN_CRIT "ep93xx_tx_complete: entry mismatch "
+ " %.8x\n", tstat0);
+
+ if (tstat0 & TSTAT0_TXWE) {
+ int length = ep->descs->tdesc[entry].tdesc1 & 0xfff;
+
+ ep->stats.tx_packets++;
+ ep->stats.tx_bytes += length;
+ } else {
+ ep->stats.tx_errors++;
+ }
+
+ if (tstat0 & TSTAT0_OW)
+ ep->stats.tx_window_errors++;
+ if (tstat0 & TSTAT0_TXU)
+ ep->stats.tx_fifo_errors++;
+ ep->stats.collisions += (tstat0 >> 16) & 0x1f;
+
+ ep->tx_clean_pointer = (entry + 1) & (TX_QUEUE_ENTRIES - 1);
+ if (ep->tx_pending == TX_QUEUE_ENTRIES)
+ wake = 1;
+ ep->tx_pending--;
+ }
+ spin_unlock(&ep->tx_pending_lock);
+
+ if (wake)
+ netif_wake_queue(dev);
+}
+
+static irqreturn_t ep93xx_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_id;
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ u32 status;
+
+ status = rdl(ep, REG_INTSTSC);
+ if (status == 0)
+ return IRQ_NONE;
+
+ if (status & REG_INTSTS_RX) {
+ spin_lock(&ep->rx_lock);
+ if (likely(__netif_rx_schedule_prep(dev))) {
+ wrl(ep, REG_INTEN, REG_INTEN_TX);
+ __netif_rx_schedule(dev);
+ }
+ spin_unlock(&ep->rx_lock);
+ }
+
+ if (status & REG_INTSTS_TX)
+ ep93xx_tx_complete(dev);
+
+ return IRQ_HANDLED;
+}
+
+static void ep93xx_free_buffers(struct ep93xx_priv *ep)
+{
+ int i;
+
+ for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+ dma_addr_t d;
+
+ d = ep->descs->rdesc[i].buf_addr;
+ if (d)
+ dma_unmap_single(NULL, d, PAGE_SIZE, DMA_FROM_DEVICE);
+
+ if (ep->rx_buf[i] != NULL)
+ free_page((unsigned long)ep->rx_buf[i]);
+ }
+
+ for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) {
+ dma_addr_t d;
+
+ d = ep->descs->tdesc[i].buf_addr;
+ if (d)
+ dma_unmap_single(NULL, d, PAGE_SIZE, DMA_TO_DEVICE);
+
+ if (ep->tx_buf[i] != NULL)
+ free_page((unsigned long)ep->tx_buf[i]);
+ }
+
+ dma_free_coherent(NULL, sizeof(struct ep93xx_descs), ep->descs,
+ ep->descs_dma_addr);
+}
+
+/*
+ * The hardware enforces a sub-2K maximum packet size, so we put
+ * two buffers on every hardware page.
+ */
+static int ep93xx_alloc_buffers(struct ep93xx_priv *ep)
+{
+ int i;
+
+ ep->descs = dma_alloc_coherent(NULL, sizeof(struct ep93xx_descs),
+ &ep->descs_dma_addr, GFP_KERNEL | GFP_DMA);
+ if (ep->descs == NULL)
+ return 1;
+
+ for (i = 0; i < RX_QUEUE_ENTRIES; i += 2) {
+ void *page;
+ dma_addr_t d;
+
+ page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ if (page == NULL)
+ goto err;
+
+ d = dma_map_single(NULL, page, PAGE_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(d)) {
+ free_page((unsigned long)page);
+ goto err;
+ }
+
+ ep->rx_buf[i] = page;
+ ep->descs->rdesc[i].buf_addr = d;
+ ep->descs->rdesc[i].rdesc1 = (i << 16) | PKT_BUF_SIZE;
+
+ ep->rx_buf[i + 1] = page + PKT_BUF_SIZE;
+ ep->descs->rdesc[i + 1].buf_addr = d + PKT_BUF_SIZE;
+ ep->descs->rdesc[i + 1].rdesc1 = ((i + 1) << 16) | PKT_BUF_SIZE;
+ }
+
+ for (i = 0; i < TX_QUEUE_ENTRIES; i += 2) {
+ void *page;
+ dma_addr_t d;
+
+ page = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+ if (page == NULL)
+ goto err;
+
+ d = dma_map_single(NULL, page, PAGE_SIZE, DMA_TO_DEVICE);
+ if (dma_mapping_error(d)) {
+ free_page((unsigned long)page);
+ goto err;
+ }
+
+ ep->tx_buf[i] = page;
+ ep->descs->tdesc[i].buf_addr = d;
+
+ ep->tx_buf[i + 1] = page + PKT_BUF_SIZE;
+ ep->descs->tdesc[i + 1].buf_addr = d + PKT_BUF_SIZE;
+ }
+
+ return 0;
+
+err:
+ ep93xx_free_buffers(ep);
+ return 1;
+}
+
+static int ep93xx_start_hw(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ unsigned long addr;
+ int i;
+
+ wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET);
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10) {
+ printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
+ return 1;
+ }
+
+ wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9));
+
+ /* Does the PHY support preamble suppress? */
+ if ((ep93xx_mdio_read(dev, ep->mii.phy_id, MII_BMSR) & 0x0040) != 0)
+ wrl(ep, REG_SELFCTL, ((ep->mdc_divisor - 1) << 9) | (1 << 8));
+
+ /* Receive descriptor ring. */
+ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rdesc);
+ wrl(ep, REG_RXDQBADD, addr);
+ wrl(ep, REG_RXDCURADD, addr);
+ wrw(ep, REG_RXDQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rdesc));
+
+ /* Receive status ring. */
+ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, rstat);
+ wrl(ep, REG_RXSTSQBADD, addr);
+ wrl(ep, REG_RXSTSQCURADD, addr);
+ wrw(ep, REG_RXSTSQBLEN, RX_QUEUE_ENTRIES * sizeof(struct ep93xx_rstat));
+
+ /* Transmit descriptor ring. */
+ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tdesc);
+ wrl(ep, REG_TXDQBADD, addr);
+ wrl(ep, REG_TXDQCURADD, addr);
+ wrw(ep, REG_TXDQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tdesc));
+
+ /* Transmit status ring. */
+ addr = ep->descs_dma_addr + offsetof(struct ep93xx_descs, tstat);
+ wrl(ep, REG_TXSTSQBADD, addr);
+ wrl(ep, REG_TXSTSQCURADD, addr);
+ wrw(ep, REG_TXSTSQBLEN, TX_QUEUE_ENTRIES * sizeof(struct ep93xx_tstat));
+
+ wrl(ep, REG_BMCTL, REG_BMCTL_ENABLE_TX | REG_BMCTL_ENABLE_RX);
+ wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX);
+ wrl(ep, REG_GIINTMSK, 0);
+
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_BMSTS) & REG_BMSTS_RX_ACTIVE) != 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10) {
+ printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to start\n");
+ return 1;
+ }
+
+ wrl(ep, REG_RXDENQ, RX_QUEUE_ENTRIES);
+ wrl(ep, REG_RXSTSENQ, RX_QUEUE_ENTRIES);
+
+ wrb(ep, REG_INDAD0, dev->dev_addr[0]);
+ wrb(ep, REG_INDAD1, dev->dev_addr[1]);
+ wrb(ep, REG_INDAD2, dev->dev_addr[2]);
+ wrb(ep, REG_INDAD3, dev->dev_addr[3]);
+ wrb(ep, REG_INDAD4, dev->dev_addr[4]);
+ wrb(ep, REG_INDAD5, dev->dev_addr[5]);
+ wrl(ep, REG_AFP, 0);
+
+ wrl(ep, REG_MAXFRMLEN, (MAX_PKT_SIZE << 16) | MAX_PKT_SIZE);
+
+ wrl(ep, REG_RXCTL, REG_RXCTL_DEFAULT);
+ wrl(ep, REG_TXCTL, REG_TXCTL_ENABLE);
+
+ return 0;
+}
+
+static void ep93xx_stop_hw(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int i;
+
+ wrl(ep, REG_SELFCTL, REG_SELFCTL_RESET);
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_SELFCTL) & REG_SELFCTL_RESET) == 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10)
+ printk(KERN_CRIT DRV_MODULE_NAME ": hw failed to reset\n");
+}
+
+static int ep93xx_open(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int err;
+
+ if (ep93xx_alloc_buffers(ep))
+ return -ENOMEM;
+
+ if (is_zero_ether_addr(dev->dev_addr)) {
+ random_ether_addr(dev->dev_addr);
+ printk(KERN_INFO "%s: generated random MAC address "
+ "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5]);
+ }
+
+ if (ep93xx_start_hw(dev)) {
+ ep93xx_free_buffers(ep);
+ return -EIO;
+ }
+
+ spin_lock_init(&ep->rx_lock);
+ ep->rx_pointer = 0;
+ ep->tx_clean_pointer = 0;
+ ep->tx_pointer = 0;
+ spin_lock_init(&ep->tx_pending_lock);
+ ep->tx_pending = 0;
+
+ err = request_irq(ep->irq, ep93xx_irq, IRQF_SHARED, dev->name, dev);
+ if (err) {
+ ep93xx_stop_hw(dev);
+ ep93xx_free_buffers(ep);
+ return err;
+ }
+
+ wrl(ep, REG_GIINTMSK, REG_GIINTMSK_ENABLE);
+
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int ep93xx_close(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+
+ wrl(ep, REG_GIINTMSK, 0);
+ free_irq(ep->irq, dev);
+ ep93xx_stop_hw(dev);
+ ep93xx_free_buffers(ep);
+
+ return 0;
+}
+
+static int ep93xx_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+
+ return generic_mii_ioctl(&ep->mii, data, cmd, NULL);
+}
+
+static int ep93xx_mdio_read(struct net_device *dev, int phy_id, int reg)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int data;
+ int i;
+
+ wrl(ep, REG_MIICMD, REG_MIICMD_READ | (phy_id << 5) | reg);
+
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10) {
+ printk(KERN_INFO DRV_MODULE_NAME ": mdio read timed out\n");
+ data = 0xffff;
+ } else {
+ data = rdl(ep, REG_MIIDATA);
+ }
+
+ return data;
+}
+
+static void ep93xx_mdio_write(struct net_device *dev, int phy_id, int reg, int data)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ int i;
+
+ wrl(ep, REG_MIIDATA, data);
+ wrl(ep, REG_MIICMD, REG_MIICMD_WRITE | (phy_id << 5) | reg);
+
+ for (i = 0; i < 10; i++) {
+ if ((rdl(ep, REG_MIISTS) & REG_MIISTS_BUSY) == 0)
+ break;
+ msleep(1);
+ }
+
+ if (i == 10)
+ printk(KERN_INFO DRV_MODULE_NAME ": mdio write timed out\n");
+}
+
+static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_MODULE_NAME);
+ strcpy(info->version, DRV_MODULE_VERSION);
+}
+
+static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ return mii_ethtool_gset(&ep->mii, cmd);
+}
+
+static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ return mii_ethtool_sset(&ep->mii, cmd);
+}
+
+static int ep93xx_nway_reset(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ return mii_nway_restart(&ep->mii);
+}
+
+static u32 ep93xx_get_link(struct net_device *dev)
+{
+ struct ep93xx_priv *ep = netdev_priv(dev);
+ return mii_link_ok(&ep->mii);
+}
+
+static struct ethtool_ops ep93xx_ethtool_ops = {
+ .get_drvinfo = ep93xx_get_drvinfo,
+ .get_settings = ep93xx_get_settings,
+ .set_settings = ep93xx_set_settings,
+ .nway_reset = ep93xx_nway_reset,
+ .get_link = ep93xx_get_link,
+};
+
+struct net_device *ep93xx_dev_alloc(struct ep93xx_eth_data *data)
+{
+ struct net_device *dev;
+ struct ep93xx_priv *ep;
+
+ dev = alloc_etherdev(sizeof(struct ep93xx_priv));
+ if (dev == NULL)
+ return NULL;
+ ep = netdev_priv(dev);
+
+ memcpy(dev->dev_addr, data->dev_addr, ETH_ALEN);
+
+ dev->get_stats = ep93xx_get_stats;
+ dev->ethtool_ops = &ep93xx_ethtool_ops;
+ dev->poll = ep93xx_poll;
+ dev->hard_start_xmit = ep93xx_xmit;
+ dev->open = ep93xx_open;
+ dev->stop = ep93xx_close;
+ dev->do_ioctl = ep93xx_ioctl;
+
+ dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
+ dev->weight = 64;
+
+ return dev;
+}
+
+
+static int ep93xx_eth_remove(struct platform_device *pdev)
+{
+ struct net_device *dev;
+ struct ep93xx_priv *ep;
+
+ dev = platform_get_drvdata(pdev);
+ if (dev == NULL)
+ return 0;
+ platform_set_drvdata(pdev, NULL);
+
+ ep = netdev_priv(dev);
+
+ /* @@@ Force down. */
+ unregister_netdev(dev);
+ ep93xx_free_buffers(ep);
+
+ if (ep->base_addr != NULL)
+ iounmap(ep->base_addr);
+
+ if (ep->res != NULL) {
+ release_resource(ep->res);
+ kfree(ep->res);
+ }
+
+ free_netdev(dev);
+
+ return 0;
+}
+
+static int ep93xx_eth_probe(struct platform_device *pdev)
+{
+ struct ep93xx_eth_data *data;
+ struct net_device *dev;
+ struct ep93xx_priv *ep;
+ int err;
+
+ data = pdev->dev.platform_data;
+ if (pdev == NULL)
+ return -ENODEV;
+
+ dev = ep93xx_dev_alloc(data);
+ if (dev == NULL) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ ep = netdev_priv(dev);
+
+ platform_set_drvdata(pdev, dev);
+
+ ep->res = request_mem_region(pdev->resource[0].start,
+ pdev->resource[0].end - pdev->resource[0].start + 1,
+ pdev->dev.bus_id);
+ if (ep->res == NULL) {
+ dev_err(&pdev->dev, "Could not reserve memory region\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+
+ ep->base_addr = ioremap(pdev->resource[0].start,
+ pdev->resource[0].end - pdev->resource[0].start);
+ if (ep->base_addr == NULL) {
+ dev_err(&pdev->dev, "Failed to ioremap ethernet registers\n");
+ err = -EIO;
+ goto err_out;
+ }
+ ep->irq = pdev->resource[1].start;
+
+ ep->mii.phy_id = data->phy_id;
+ ep->mii.phy_id_mask = 0x1f;
+ ep->mii.reg_num_mask = 0x1f;
+ ep->mii.dev = dev;
+ ep->mii.mdio_read = ep93xx_mdio_read;
+ ep->mii.mdio_write = ep93xx_mdio_write;
+ ep->mdc_divisor = 40; /* Max HCLK 100 MHz, min MDIO clk 2.5 MHz. */
+
+ err = register_netdev(dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to register netdev\n");
+ goto err_out;
+ }
+
+ printk(KERN_INFO "%s: ep93xx on-chip ethernet, IRQ %d, "
+ "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x.\n", dev->name,
+ ep->irq, data->dev_addr[0], data->dev_addr[1],
+ data->dev_addr[2], data->dev_addr[3],
+ data->dev_addr[4], data->dev_addr[5]);
+
+ return 0;
+
+err_out:
+ ep93xx_eth_remove(pdev);
+ return err;
+}
+
+
+static struct platform_driver ep93xx_eth_driver = {
+ .probe = ep93xx_eth_probe,
+ .remove = ep93xx_eth_remove,
+ .driver = {
+ .name = "ep93xx-eth",
+ },
+};
+
+static int __init ep93xx_eth_init_module(void)
+{
+ printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n");
+ return platform_driver_register(&ep93xx_eth_driver);
+}
+
+static void __exit ep93xx_eth_cleanup_module(void)
+{
+ platform_driver_unregister(&ep93xx_eth_driver);
+}
+
+module_init(ep93xx_eth_init_module);
+module_exit(ep93xx_eth_cleanup_module);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index d52deb8d207..4ae98970b28 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -626,7 +626,7 @@ static int etherh_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return 0;
}
-static struct ethtool_ops etherh_ethtool_ops = {
+static const struct ethtool_ops etherh_ethtool_ops = {
.get_settings = etherh_get_settings,
.set_settings = etherh_set_settings,
.get_drvinfo = etherh_get_drvinfo,
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index e613cc28974..4aeca11f3ee 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -18,7 +18,7 @@
straight-forward Fujitsu MB86965 implementations.
Modification for Fujitsu FMV-18X cards is done by Yutaka Tamiya
- (tamy@flab.fujitsu.co.jp).
+ (tamy@flab.fujitsu.co.jp).
Sources:
The Fujitsu MB86965 datasheet.
@@ -35,7 +35,6 @@
response to inb()s from other device probes!
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -59,7 +58,7 @@
#include <asm/dma.h>
static char version[] __initdata =
- "at1700.c:v1.15 4/7/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+ "at1700.c:v1.16 9/11/06 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
#define DRV_NAME "at1700"
@@ -169,7 +168,7 @@ static struct net_device_stats *net_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void net_tx_timeout (struct net_device *dev);
-
+
#ifdef CONFIG_MCA_LEGACY
struct at1720_mca_adapters_struct {
char* name;
@@ -202,7 +201,7 @@ static void cleanup_card(struct net_device *dev)
struct net_local *lp = netdev_priv(dev);
if (lp->mca_slot >= 0)
mca_mark_as_unused(lp->mca_slot);
-#endif
+#endif
free_irq(dev->irq, NULL);
release_region(dev->base_addr, AT1700_IO_EXTENT);
}
@@ -302,7 +301,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
for (j = 0; at1720_mca_adapters[j].name != NULL; j ++) {
slot = 0;
while (slot != MCA_NOTFOUND) {
-
+
slot = mca_find_unused_adapter( at1720_mca_adapters[j].id, slot );
if (slot == MCA_NOTFOUND) break;
@@ -316,7 +315,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
if (( pos3 & 0x07) == at1700_ioaddr_pattern[l_i])
break;
ioaddr = at1700_mca_probe_list[l_i];
-
+
for (irq = 0; irq < 0x10; irq++)
if (((((pos4>>4) & 0x0f) | (pos3 & 0xf0)) & 0xff) == at1700_irq_pattern[irq])
break;
@@ -329,7 +328,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
}
dev->irq = irq;
-
+
/* claim the slot */
mca_set_adapter_name( slot, at1720_mca_adapters[j].name );
mca_mark_as_used(slot);
@@ -354,7 +353,7 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr)
else {
goto err_out;
}
-
+
#ifdef CONFIG_MCA_LEGACY
found:
#endif
@@ -488,7 +487,7 @@ err_out:
return ret;
}
-
+
/* EEPROM_Ctrl bits. */
#define EE_SHIFT_CLK 0x40 /* EEPROM shift clock, in reg. 16. */
#define EE_CS 0x20 /* EEPROM chip select, in reg. 16. */
@@ -529,7 +528,7 @@ static int __init read_eeprom(long ioaddr, int location)
return retval;
}
-
+
static int net_open(struct net_device *dev)
{
@@ -646,7 +645,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
return 0;
}
-
+
/* The typical workload of the driver:
Handle the network interface interrupts. */
static irqreturn_t
@@ -664,9 +663,9 @@ net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
-
+
spin_lock (&lp->lock);
-
+
status = inw(ioaddr + TX_STATUS);
outw(status, ioaddr + TX_STATUS);
@@ -852,8 +851,6 @@ set_rx_mode(struct net_device *dev)
int i;
if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk("%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
} else if (dev->mc_count > MC_FILTERBREAK
@@ -902,7 +899,7 @@ MODULE_PARM_DESC(io, "AT1700/FMV18X I/O base address");
MODULE_PARM_DESC(irq, "AT1700/FMV18X IRQ number");
MODULE_PARM_DESC(net_debug, "AT1700/FMV18X debug level (0-6)");
-int init_module(void)
+int __init init_module(void)
{
if (io == 0)
printk("at1700: You should not use auto-probing with insmod!\n");
@@ -922,7 +919,7 @@ cleanup_module(void)
#endif /* MODULE */
MODULE_LICENSE("GPL");
-
+
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c"
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index 5e5f80b99b9..92b52138aca 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -460,7 +460,7 @@ bionet_send_packet(struct sk_buff *skb, struct net_device *dev) {
if (bionet_debug >1) {
u_char *data = nic_packet->buffer, *p;
int i;
-
+
printk( "%s: TX pkt type 0x%4x from ", dev->name,
((u_short *)data)[6]);
@@ -551,7 +551,7 @@ bionet_poll_rx(struct net_device *dev) {
/* 'skb->data' points to the start of sk_buff data area.
*/
memcpy(skb->data, nic_packet->buffer, pkt_len);
- skb->protocol = eth_type_trans( skb, dev );
+ skb->protocol = eth_type_trans( skb, dev );
netif_rx(skb);
dev->last_rx = jiffies;
lp->stats.rx_packets++;
@@ -565,17 +565,17 @@ bionet_poll_rx(struct net_device *dev) {
if (bionet_debug >1) {
u_char *data = nic_packet->buffer, *p;
int i;
-
+
printk( "%s: RX pkt type 0x%4x from ", dev->name,
((u_short *)data)[6]);
-
-
+
+
for( p = &data[6], i = 0; i < 6; i++ )
printk("%02x%s", *p++,i != 5 ? ":" : "" );
printk(" to ");
for( p = data, i = 0; i < 6; i++ )
printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" );
-
+
printk( "%s: ", dev->name );
printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x"
" %02x%02x%02x%02x len %d\n",
@@ -636,7 +636,7 @@ bionet_close(struct net_device *dev) {
/* Get the current statistics.
This may be called with the card open or closed.
*/
-static struct net_device_stats *net_get_stats(struct net_device *dev)
+static struct net_device_stats *net_get_stats(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
return &lp->stats;
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
index d6039e62d83..a1026251b93 100644
--- a/drivers/net/atari_pamsnet.c
+++ b/drivers/net/atari_pamsnet.c
@@ -857,7 +857,7 @@ pamsnet_close(struct net_device *dev) {
/* Get the current statistics.
This may be called with the card open or closed.
*/
-static struct net_device_stats *net_get_stats(struct net_device *dev)
+static struct net_device_stats *net_get_stats(struct net_device *dev)
{
struct net_local *lp = netdev_priv(dev);
return &lp->stats;
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index 91783a8008b..b6570ca6ada 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -356,7 +356,7 @@ static void lance_tx_timeout (struct net_device *dev);
-
+
static void *slow_memcpy( void *dst, const void *src, size_t len )
@@ -549,7 +549,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
memaddr == (unsigned short *)0xffe00000) {
/* PAMs card and Riebl on ST use level 5 autovector */
if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
- "PAM/Riebl-ST Ethernet", dev)) {
+ "PAM/Riebl-ST Ethernet", dev)) {
printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
return( 0 );
}
@@ -639,7 +639,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
/* XXX MSch */
dev->tx_timeout = lance_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-
+
#if 0
dev->start = 0;
@@ -650,7 +650,7 @@ static unsigned long __init lance_probe1( struct net_device *dev,
return( 1 );
}
-
+
static int lance_open( struct net_device *dev )
{ struct lance_private *lp = (struct lance_private *)dev->priv;
@@ -744,7 +744,7 @@ static void lance_tx_timeout (struct net_device *dev)
{
struct lance_private *lp = (struct lance_private *) dev->priv;
struct lance_ioreg *IO = lp->iobase;
-
+
AREG = CSR0;
DPRINTK( 1, ( "%s: transmit timed out, status %04x, resetting.\n",
dev->name, DREG ));
@@ -772,7 +772,7 @@ static void lance_tx_timeout (struct net_device *dev)
-MEM->tx_head[i].length,
MEM->tx_head[i].misc ));
}
-#endif
+#endif
/* XXX MSch: maybe purge/reinit ring here */
/* lance_restart, essentially */
lance_init_ring(dev);
@@ -802,12 +802,12 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* PAM-Card has a bug: Can only send packets with even number of bytes! */
else if (lp->cardtype == PAM_CARD && (len & 1))
++len;
-
+
if (len > skb->len) {
if (skb_padto(skb, len))
return 0;
}
-
+
netif_stop_queue (dev);
/* Fill in a Tx ring entry */
@@ -1121,7 +1121,7 @@ static void set_multicast_list( struct net_device *dev )
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
- DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+ DPRINTK( 2, ( "%s: Promiscuous mode enabled.\n", dev->name ));
REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
} else {
short multicast_table[4];
@@ -1175,7 +1175,7 @@ static int lance_set_mac_address( struct net_device *dev, void *addr )
return( 0 );
}
-
+
#ifdef MODULE
static struct net_device *atarilance_dev;
@@ -1195,7 +1195,7 @@ void cleanup_module(void)
}
#endif /* MODULE */
-
+
/*
* Local variables:
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index bfa674ed449..f2c8e0d5497 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -221,7 +221,7 @@ static struct net_device *root_atp_dev;
If dev->base_addr == 1, always return failure.
If dev->base_addr == 2, allocate space for the device and return success
(detachable devices only).
-
+
FIXME: we should use the parport layer for this
*/
static int __init atp_init(void)
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index 038d5fcb15e..ac33b1b9cf4 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -6,8 +6,8 @@
* Copyright 2002 TimeSys Corp.
* Added ethtool/mii-tool support,
* Copyright 2004 Matt Porter <mporter@kernel.crashing.org>
- * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de
- * or riemer@riemer-nt.de: fixed the link beat detection with
+ * Update: 2004 Bjoern Riemer, riemer@fokus.fraunhofer.de
+ * or riemer@riemer-nt.de: fixed the link beat detection with
* ioctls (SIOCGMIIPHY)
* Copyright 2006 Herbert Valerio Riedel <hvr@gnu.org>
* converted to use linux-2.6.x's PHY framework
@@ -32,10 +32,9 @@
*
* ########################################################################
*
- *
+ *
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -73,7 +72,7 @@ static int au1000_debug = 3;
#endif
#define DRV_NAME "au1000_eth"
-#define DRV_VERSION "1.5"
+#define DRV_VERSION "1.6"
#define DRV_AUTHOR "Pete Popov <ppopov@embeddedalley.com>"
#define DRV_DESC "Au1xxx on-chip Ethernet driver"
@@ -108,13 +107,13 @@ extern char * __init prom_getcmdline(void);
/*
* Theory of operation
*
- * The Au1000 MACs use a simple rx and tx descriptor ring scheme.
- * There are four receive and four transmit descriptors. These
- * descriptors are not in memory; rather, they are just a set of
+ * The Au1000 MACs use a simple rx and tx descriptor ring scheme.
+ * There are four receive and four transmit descriptors. These
+ * descriptors are not in memory; rather, they are just a set of
* hardware registers.
*
* Since the Au1000 has a coherent data cache, the receive and
- * transmit buffers are allocated from the KSEG0 segment. The
+ * transmit buffers are allocated from the KSEG0 segment. The
* hardware registers, however, are still mapped at KSEG1 to
* make sure there's no out-of-order writes, and that all writes
* complete immediately.
@@ -124,7 +123,7 @@ extern char * __init prom_getcmdline(void);
* the mac address is, and the mac address is not passed on the
* command line.
*/
-static unsigned char au1000_mac_addr[6] __devinitdata = {
+static unsigned char au1000_mac_addr[6] __devinitdata = {
0x00, 0x50, 0xc2, 0x0c, 0x30, 0x00
};
@@ -208,13 +207,13 @@ static int mdio_read(struct net_device *dev, int phy_addr, int reg)
while (*mii_control_reg & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
- printk(KERN_ERR "%s: read_MII busy timeout!!\n",
+ printk(KERN_ERR "%s: read_MII busy timeout!!\n",
dev->name);
return -1;
}
}
- mii_control = MAC_SET_MII_SELECT_REG(reg) |
+ mii_control = MAC_SET_MII_SELECT_REG(reg) |
MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_READ;
*mii_control_reg = mii_control;
@@ -223,7 +222,7 @@ static int mdio_read(struct net_device *dev, int phy_addr, int reg)
while (*mii_control_reg & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
- printk(KERN_ERR "%s: mdio_read busy timeout!!\n",
+ printk(KERN_ERR "%s: mdio_read busy timeout!!\n",
dev->name);
return -1;
}
@@ -242,13 +241,13 @@ static void mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value)
while (*mii_control_reg & MAC_MII_BUSY) {
mdelay(1);
if (--timedout == 0) {
- printk(KERN_ERR "%s: mdio_write busy timeout!!\n",
+ printk(KERN_ERR "%s: mdio_write busy timeout!!\n",
dev->name);
return;
}
}
- mii_control = MAC_SET_MII_SELECT_REG(reg) |
+ mii_control = MAC_SET_MII_SELECT_REG(reg) |
MAC_SET_MII_SELECT_PHY(phy_addr) | MAC_MII_WRITE;
*mii_data_reg = value;
@@ -395,7 +394,7 @@ static int mii_probe (struct net_device *dev)
/*
* Buffer allocation/deallocation routines. The buffer descriptor returned
- * has the virtual and dma address of a buffer suitable for
+ * has the virtual and dma address of a buffer suitable for
* both, receive and transmit operations.
*/
static db_dest_t *GetFreeDB(struct au1000_private *aup)
@@ -501,22 +500,22 @@ static void reset_mac(struct net_device *dev)
spin_unlock_irqrestore(&aup->lock, flags);
}
-/*
+/*
* Setup the receive and transmit "rings". These pointers are the addresses
* of the rx and tx MAC DMA registers so they are fixed by the hardware --
* these are not descriptors sitting in memory.
*/
-static void
+static void
setup_hw_rings(struct au1000_private *aup, u32 rx_base, u32 tx_base)
{
int i;
for (i = 0; i < NUM_RX_DMA; i++) {
- aup->rx_dma_ring[i] =
+ aup->rx_dma_ring[i] =
(volatile rx_dma_t *) (rx_base + sizeof(rx_dma_t)*i);
}
for (i = 0; i < NUM_TX_DMA; i++) {
- aup->tx_dma_ring[i] =
+ aup->tx_dma_ring[i] =
(volatile tx_dma_t *) (tx_base + sizeof(tx_dma_t)*i);
}
}
@@ -609,7 +608,7 @@ au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
info->regdump_len = 0;
}
-static struct ethtool_ops au1000_ethtool_ops = {
+static const struct ethtool_ops au1000_ethtool_ops = {
.get_settings = au1000_get_settings,
.set_settings = au1000_set_settings,
.get_drvinfo = au1000_get_drvinfo,
@@ -692,7 +691,7 @@ static struct net_device * au1000_probe(int port_num)
/* Use the hard coded MAC addresses */
else {
str2eaddr(ethaddr, pmac + strlen("ethaddr="));
- memcpy(au1000_mac_addr, ethaddr,
+ memcpy(au1000_mac_addr, ethaddr,
sizeof(au1000_mac_addr));
}
}
@@ -781,8 +780,8 @@ static struct net_device * au1000_probe(int port_num)
dev->tx_timeout = au1000_tx_timeout;
dev->watchdog_timeo = ETH_TX_TIMEOUT;
- /*
- * The boot code uses the ethernet controller, so reset it to start
+ /*
+ * The boot code uses the ethernet controller, so reset it to start
* fresh. au1000_init() expects that the device is in reset state.
*/
reset_mac(dev);
@@ -811,7 +810,7 @@ err_out:
return NULL;
}
-/*
+/*
* Initialize the interface.
*
* When the device powers up, the clocks are disabled and the
@@ -827,7 +826,7 @@ static int au1000_init(struct net_device *dev)
int i;
u32 control;
- if (au1000_debug > 4)
+ if (au1000_debug > 4)
printk("%s: au1000_init\n", dev->name);
/* bring the device out of reset */
@@ -1103,8 +1102,8 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
int i;
if (au1000_debug > 5)
- printk("%s: tx: aup %x len=%d, data=%p, head %d\n",
- dev->name, (unsigned)aup, skb->len,
+ printk("%s: tx: aup %x len=%d, data=%p, head %d\n",
+ dev->name, (unsigned)aup, skb->len,
skb->data, aup->tx_head);
ptxd = aup->tx_dma_ring[aup->tx_head];
@@ -1128,7 +1127,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev)
pDB = aup->tx_db_inuse[aup->tx_head];
memcpy((void *)pDB->vaddr, skb->data, skb->len);
if (skb->len < ETH_ZLEN) {
- for (i=skb->len; i<ETH_ZLEN; i++) {
+ for (i=skb->len; i<ETH_ZLEN; i++) {
((char *)pDB->vaddr)[i] = 0;
}
ptxd->len = ETH_ZLEN;
@@ -1167,7 +1166,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status)
if (status & RX_COLL)
ps->collisions++;
}
- else
+ else
ps->rx_bytes += status & RX_FRAME_LEN_MASK;
}
@@ -1216,13 +1215,13 @@ static int au1000_rx(struct net_device *dev)
}
else {
if (au1000_debug > 4) {
- if (status & RX_MISSED_FRAME)
+ if (status & RX_MISSED_FRAME)
printk("rx miss\n");
- if (status & RX_WDOG_TIMER)
+ if (status & RX_WDOG_TIMER)
printk("rx wdog\n");
- if (status & RX_RUNT)
+ if (status & RX_RUNT)
printk("rx runt\n");
- if (status & RX_OVERLEN)
+ if (status & RX_OVERLEN)
printk("rx overlen\n");
if (status & RX_COLL)
printk("rx coll\n");
@@ -1288,12 +1287,11 @@ static void set_rx_mode(struct net_device *dev)
{
struct au1000_private *aup = (struct au1000_private *) dev->priv;
- if (au1000_debug > 4)
+ if (au1000_debug > 4)
printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags);
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
aup->mac->control |= MAC_PROMISCUOUS;
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
} else if ((dev->flags & IFF_ALLMULTI) ||
dev->mc_count > MULTICAST_FILTER_LIMIT) {
aup->mac->control |= MAC_PASS_ALL_MULTI;
@@ -1307,7 +1305,7 @@ static void set_rx_mode(struct net_device *dev)
mc_filter[1] = mc_filter[0] = 0;
for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
i++, mclist = mclist->next) {
- set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,
+ set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26,
(long *)mc_filter);
}
aup->mac->multi_hash_high = mc_filter[1];
diff --git a/drivers/net/au1000_eth.h b/drivers/net/au1000_eth.h
index 41c2f848d2c..52fe00dd6d2 100644
--- a/drivers/net/au1000_eth.h
+++ b/drivers/net/au1000_eth.h
@@ -23,7 +23,7 @@
*
* ########################################################################
*
- *
+ *
*/
@@ -40,8 +40,8 @@
#define MULTICAST_FILTER_LIMIT 64
-/*
- * Data Buffer Descriptor. Data buffers must be aligned on 32 byte
+/*
+ * Data Buffer Descriptor. Data buffers must be aligned on 32 byte
* boundary for both, receive and transmit.
*/
typedef struct db_dest {
@@ -51,7 +51,7 @@ typedef struct db_dest {
} db_dest_t;
/*
- * The transmit and receive descriptors are memory
+ * The transmit and receive descriptors are memory
* mapped registers.
*/
typedef struct tx_dma {
@@ -107,9 +107,9 @@ struct au1000_private {
struct phy_device *phy_dev;
struct mii_bus mii_bus;
-
+
/* These variables are just for quick access to certain regs addresses. */
- volatile mac_reg_t *mac; /* mac registers */
+ volatile mac_reg_t *mac; /* mac registers */
volatile u32 *enable; /* address of MAC Enable Register */
u32 vaddr; /* virtual address of rx/tx buffers */
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index a7e4ba5a580..e891ea2ecc3 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1421,7 +1421,7 @@ static int b44_open(struct net_device *dev)
b44_check_phy(bp);
- err = request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev);
+ err = request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev);
if (unlikely(err < 0)) {
b44_chip_reset(bp);
b44_free_rings(bp);
@@ -2012,7 +2012,7 @@ static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
-static struct ethtool_ops b44_ethtool_ops = {
+static const struct ethtool_ops b44_ethtool_ops = {
.get_drvinfo = b44_get_drvinfo,
.get_settings = b44_get_settings,
.set_settings = b44_set_settings,
@@ -2120,13 +2120,14 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
+ dev_err(&pdev->dev, "Cannot enable PCI device, "
"aborting.\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
+ dev_err(&pdev->dev,
+ "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
@@ -2134,8 +2135,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, DRV_MODULE_NAME);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable_pdev;
}
@@ -2143,15 +2144,13 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = pci_set_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
err = pci_set_consistent_dma_mask(pdev, (u64) B44_DMA_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
- "aborting.\n");
+ dev_err(&pdev->dev, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
@@ -2160,7 +2159,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*bp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_free_res;
}
@@ -2181,8 +2180,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
bp->regs = ioremap(b44reg_base, b44reg_len);
if (bp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
err = -ENOMEM;
goto err_out_free_dev;
}
@@ -2212,8 +2210,8 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = b44_get_invariants(bp);
if (err) {
- printk(KERN_ERR PFX "Problem fetching invariants of chip, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Problem fetching invariants of chip, aborting.\n");
goto err_out_iounmap;
}
@@ -2233,8 +2231,7 @@ static int __devinit b44_init_one(struct pci_dev *pdev,
err = register_netdev(dev);
if (err) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_out_iounmap;
}
@@ -2322,7 +2319,7 @@ static int b44_resume(struct pci_dev *pdev)
if (!netif_running(dev))
return 0;
- if (request_irq(dev->irq, b44_interrupt, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, b44_interrupt, IRQF_SHARED, dev->name, dev))
printk(KERN_ERR PFX "%s: request_irq failed\n", dev->name);
spin_lock_irq(&bp->lock);
@@ -2357,7 +2354,7 @@ static int __init b44_init(void)
dma_desc_align_mask = ~(dma_desc_align_size - 1);
dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
- return pci_module_init(&b44_driver);
+ return pci_register_driver(&b44_driver);
}
static void __exit b44_cleanup(void)
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index bbca8ae8018..4adfe7b7703 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -7,7 +7,6 @@
* May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to
* dynamic procfs inode.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
@@ -334,7 +333,7 @@ bmac_init_registers(struct net_device *dev)
udelay(10000);
}
- bmwrite(dev, RSEED, (unsigned short)0x1968);
+ bmwrite(dev, RSEED, (unsigned short)0x1968);
regValue = bmread(dev, XIFC);
regValue |= TxOutputEnable;
@@ -374,7 +373,7 @@ bmac_init_registers(struct net_device *dev)
bmwrite(dev, BHASH2, bp->hash_table_mask[1]); /* bits 31 - 16 */
bmwrite(dev, BHASH1, bp->hash_table_mask[2]); /* bits 47 - 32 */
bmwrite(dev, BHASH0, bp->hash_table_mask[3]); /* bits 63 - 48 */
-
+
pWord16 = (unsigned short *)dev->dev_addr;
bmwrite(dev, MADD0, *pWord16++);
bmwrite(dev, MADD1, *pWord16++);
@@ -412,11 +411,11 @@ bmac_start_chip(struct net_device *dev)
/* enable rx dma channel */
dbdma_continue(rd);
- oldConfig = bmread(dev, TXCFG);
+ oldConfig = bmread(dev, TXCFG);
bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
/* turn on rx plus any other bits already on (promiscuous possibly) */
- oldConfig = bmread(dev, RXCFG);
+ oldConfig = bmread(dev, RXCFG);
bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
udelay(20000);
}
@@ -457,12 +456,12 @@ static void bmac_init_chip(struct net_device *dev)
#ifdef CONFIG_PM
static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
{
- struct net_device* dev = macio_get_drvdata(mdev);
+ struct net_device* dev = macio_get_drvdata(mdev);
struct bmac_data *bp = netdev_priv(dev);
unsigned long flags;
unsigned short config;
int i;
-
+
netif_device_detach(dev);
/* prolly should wait for dma to finish & turn off the chip */
spin_lock_irqsave(&bp->lock, flags);
@@ -478,7 +477,7 @@ static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
if (bp->opened) {
volatile struct dbdma_regs __iomem *rd = bp->rx_dma;
volatile struct dbdma_regs __iomem *td = bp->tx_dma;
-
+
config = bmread(dev, RXCFG);
bmwrite(dev, RXCFG, (config & ~RxMACEnable));
config = bmread(dev, TXCFG);
@@ -507,7 +506,7 @@ static int bmac_suspend(struct macio_dev *mdev, pm_message_t state)
static int bmac_resume(struct macio_dev *mdev)
{
- struct net_device* dev = macio_get_drvdata(mdev);
+ struct net_device* dev = macio_get_drvdata(mdev);
struct bmac_data *bp = netdev_priv(dev);
/* see if this is enough */
@@ -856,12 +855,12 @@ crc416(unsigned int curval, unsigned short nxtval)
else high_crc_set = 1;
cur = cur << 1;
-
+
if ((next & 0x0001) == 0) low_data_set = 0;
else low_data_set = 1;
next = next >> 1;
-
+
/* do the XOR */
if (high_crc_set ^ low_data_set) cur = cur ^ ENET_CRCPOLY;
}
@@ -870,7 +869,7 @@ crc416(unsigned int curval, unsigned short nxtval)
static unsigned int
bmac_crc(unsigned short *address)
-{
+{
unsigned int newcrc;
XXDEBUG(("bmac_crc: addr=%#04x, %#04x, %#04x\n", *address, address[1], address[2]));
@@ -888,7 +887,7 @@ bmac_crc(unsigned short *address)
static void
bmac_addhash(struct bmac_data *bp, unsigned char *addr)
-{
+{
unsigned int crc;
unsigned short mask;
@@ -903,7 +902,7 @@ bmac_addhash(struct bmac_data *bp, unsigned char *addr)
static void
bmac_removehash(struct bmac_data *bp, unsigned char *addr)
-{
+{
unsigned int crc;
unsigned char mask;
@@ -1055,13 +1054,13 @@ static void bmac_set_multicast(struct net_device *dev)
bmwrite(dev, RXCFG, rx_cfg);
} else {
u16 hash_table[4];
-
+
rx_cfg = bmread(dev, RXCFG);
rx_cfg &= ~RxPromiscEnable;
bmwrite(dev, RXCFG, rx_cfg);
for(i = 0; i < 4; i++) hash_table[i] = 0;
-
+
for(i = 0; i < dev->mc_count; i++) {
addrs = dmi->dmi_addr;
dmi = dmi->next;
@@ -1221,7 +1220,7 @@ bmac_get_station_address(struct net_device *dev, unsigned char *ea)
int i;
unsigned short data;
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
{
reset_and_select_srom(dev);
data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
@@ -1245,7 +1244,7 @@ static void bmac_reset_and_enable(struct net_device *dev)
bmac_start_chip(dev);
bmwrite(dev, INTDISABLE, EnableNormal);
bp->sleeping = 0;
-
+
/*
* It seems that the bmac can't receive until it's transmitted
* a packet. So we give it a dummy packet to transmit.
@@ -1265,7 +1264,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
{
int j, rev, ret;
struct bmac_data *bp;
- unsigned char *addr;
+ const unsigned char *prop_addr;
+ unsigned char addr[6];
struct net_device *dev;
int is_bmac_plus = ((int)match->data) != 0;
@@ -1273,21 +1273,23 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n");
return -ENODEV;
}
- addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
- if (addr == NULL) {
- addr = get_property(macio_get_of_node(mdev), "local-mac-address", NULL);
- if (addr == NULL) {
+ prop_addr = get_property(macio_get_of_node(mdev), "mac-address", NULL);
+ if (prop_addr == NULL) {
+ prop_addr = get_property(macio_get_of_node(mdev),
+ "local-mac-address", NULL);
+ if (prop_addr == NULL) {
printk(KERN_ERR "BMAC: Can't get mac-address\n");
return -ENODEV;
}
}
+ memcpy(addr, prop_addr, sizeof(addr));
dev = alloc_etherdev(PRIV_BYTES);
if (!dev) {
printk(KERN_ERR "BMAC: alloc_etherdev failed, out of memory\n");
return -ENOMEM;
}
-
+
bp = netdev_priv(dev);
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &mdev->ofdev.dev);
@@ -1380,7 +1382,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
printk("%c%.2x", (j? ':': ' '), dev->dev_addr[j]);
XXDEBUG((", base_addr=%#0lx", dev->base_addr));
printk("\n");
-
+
return 0;
err_out_irq2:
@@ -1472,7 +1474,7 @@ bmac_start(struct net_device *dev)
if (bp->sleeping)
return;
-
+
spin_lock_irqsave(&bp->lock, flags);
while (1) {
i = bp->tx_fill + 1;
@@ -1560,9 +1562,9 @@ static void bmac_tx_timeout(unsigned long data)
}
/* turn it back on */
- oldConfig = bmread(dev, RXCFG);
+ oldConfig = bmread(dev, RXCFG);
bmwrite(dev, RXCFG, oldConfig | RxMACEnable );
- oldConfig = bmread(dev, TXCFG);
+ oldConfig = bmread(dev, TXCFG);
bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
spin_unlock_irqrestore(&bp->lock, flags);
@@ -1572,10 +1574,10 @@ static void bmac_tx_timeout(unsigned long data)
static void dump_dbdma(volatile struct dbdma_cmd *cp,int count)
{
int i,*ip;
-
+
for (i=0;i< count;i++) {
ip = (int*)(cp+i);
-
+
printk("dbdma req 0x%x addr 0x%x baddr 0x%x xfer/res 0x%x\n",
ld_le32(ip+0),
ld_le32(ip+1),
@@ -1631,7 +1633,7 @@ static int __devexit bmac_remove(struct macio_dev *mdev)
unregister_netdev(dev);
free_irq(dev->irq, dev);
- free_irq(bp->tx_dma_intr, dev);
+ free_irq(bp->tx_dma_intr, dev);
free_irq(bp->rx_dma_intr, dev);
iounmap((void __iomem *)dev->base_addr);
@@ -1645,7 +1647,7 @@ static int __devexit bmac_remove(struct macio_dev *mdev)
return 0;
}
-static struct of_device_id bmac_match[] =
+static struct of_device_id bmac_match[] =
{
{
.name = "bmac",
@@ -1660,7 +1662,7 @@ static struct of_device_id bmac_match[] =
};
MODULE_DEVICE_TABLE (of, bmac_match);
-static struct macio_driver bmac_driver =
+static struct macio_driver bmac_driver =
{
.name = "bmac",
.match_table = bmac_match,
diff --git a/drivers/net/bmac.h b/drivers/net/bmac.h
index df3b93d1ac2..a1d19d867ba 100644
--- a/drivers/net/bmac.h
+++ b/drivers/net/bmac.h
@@ -14,7 +14,7 @@
* (HME) controller. See sunhme.h
*/
-
+
/* register offsets */
/* global status and control */
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 7635736cc79..6b4edb63c4c 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -9,7 +9,6 @@
* Written by: Michael Chan (mchan@broadcom.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -57,8 +56,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.4.42"
-#define DRV_MODULE_RELDATE "June 12, 2006"
+#define DRV_MODULE_VERSION "1.4.45"
+#define DRV_MODULE_RELDATE "September 29, 2006"
#define RUN_AT(x) (jiffies + (x))
@@ -149,7 +148,7 @@ static struct flash_spec flash_table[] =
SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
"Entry 0100"},
/* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
- {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
+ {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
"Entry 0101: ST M45PE10 (128kB non-bufferred)"},
@@ -210,8 +209,10 @@ MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
static inline u32 bnx2_tx_avail(struct bnx2 *bp)
{
- u32 diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
+ u32 diff;
+ smp_mb();
+ diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
if (diff > MAX_TX_DESC_CNT)
diff = (diff & MAX_TX_DESC_CNT) - 1;
return (bp->tx_ring_size - diff);
@@ -316,7 +317,7 @@ bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
-
+
for (i = 0; i < 50; i++) {
udelay(10);
@@ -584,7 +585,7 @@ bnx2_resolve_flow_ctrl(struct bnx2 *bp)
u32 local_adv, remote_adv;
bp->flow_ctrl = 0;
- if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
+ if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
(AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
if (bp->duplex == DUPLEX_FULL) {
@@ -1086,7 +1087,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp)
#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
-
+
#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
static int
@@ -1119,7 +1120,7 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
new_adv_reg |= ADVERTISE_100FULL;
if (bp->advertising & ADVERTISED_1000baseT_Full)
new_adv1000_reg |= ADVERTISE_1000FULL;
-
+
new_adv_reg |= ADVERTISE_CSMA;
new_adv_reg |= bnx2_phy_get_pause_adv(bp);
@@ -1156,7 +1157,7 @@ bnx2_setup_copper_phy(struct bnx2 *bp)
bnx2_read_phy(bp, MII_BMSR, &bmsr);
bnx2_read_phy(bp, MII_BMSR, &bmsr);
-
+
if (bmsr & BMSR_LSTATUS) {
/* Force link down */
bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
@@ -1546,7 +1547,7 @@ bnx2_alloc_bad_rbuf(struct bnx2 *bp)
}
static void
-bnx2_set_mac_addr(struct bnx2 *bp)
+bnx2_set_mac_addr(struct bnx2 *bp)
{
u32 val;
u8 *mac_addr = bp->dev->dev_addr;
@@ -1555,7 +1556,7 @@ bnx2_set_mac_addr(struct bnx2 *bp)
REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
- val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
+ val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
(mac_addr[4] << 8) | mac_addr[5];
REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
@@ -1570,7 +1571,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
unsigned long align;
- skb = dev_alloc_skb(bp->rx_buf_size);
+ skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
if (skb == NULL) {
return -ENOMEM;
}
@@ -1579,7 +1580,6 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
skb_reserve(skb, 8 - align);
}
- skb->dev = bp->dev;
mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
PCI_DMA_FROMDEVICE);
@@ -1638,9 +1638,9 @@ bnx2_tx_int(struct bnx2 *bp)
tx_buf = &bp->tx_buf_ring[sw_ring_cons];
skb = tx_buf->skb;
-#ifdef BCM_TSO
+#ifdef BCM_TSO
/* partial BD completions possible with TSO packets */
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
u16 last_idx, last_ring_idx;
last_idx = sw_cons +
@@ -1676,7 +1676,7 @@ bnx2_tx_int(struct bnx2 *bp)
tx_free_bd += last + 1;
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb(skb);
hw_cons = bp->hw_tx_cons =
sblk->status_tx_quick_consumer_index0;
@@ -1687,15 +1687,20 @@ bnx2_tx_int(struct bnx2 *bp)
}
bp->tx_cons = sw_cons;
+ /* Need to make the tx_cons update visible to bnx2_start_xmit()
+ * before checking for netif_queue_stopped(). Without the
+ * memory barrier, there is a small possibility that bnx2_start_xmit()
+ * will miss it and cause the queue to be stopped forever.
+ */
+ smp_mb();
- if (unlikely(netif_queue_stopped(bp->dev))) {
- spin_lock(&bp->tx_lock);
+ if (unlikely(netif_queue_stopped(bp->dev)) &&
+ (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) {
+ netif_tx_lock(bp->dev);
if ((netif_queue_stopped(bp->dev)) &&
- (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)) {
-
+ (bnx2_tx_avail(bp) > bp->tx_wake_thresh))
netif_wake_queue(bp->dev);
- }
- spin_unlock(&bp->tx_lock);
+ netif_tx_unlock(bp->dev);
}
}
@@ -1787,7 +1792,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
struct sk_buff *new_skb;
- new_skb = dev_alloc_skb(len + 2);
+ new_skb = netdev_alloc_skb(bp->dev, len + 2);
if (new_skb == NULL)
goto reuse_rx;
@@ -1798,7 +1803,6 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
skb_reserve(new_skb, 2);
skb_put(new_skb, len);
- new_skb->dev = bp->dev;
bnx2_reuse_rx_skb(bp, skb,
sw_ring_cons, sw_ring_prod);
@@ -1824,7 +1828,7 @@ reuse_rx:
if ((len > (bp->dev->mtu + ETH_HLEN)) &&
(ntohs(skb->protocol) != 0x8100)) {
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb(skb);
goto next_rx;
}
@@ -1980,12 +1984,12 @@ bnx2_poll(struct net_device *dev, int *budget)
if (orig_budget > dev->quota)
orig_budget = dev->quota;
-
+
work_done = bnx2_rx_int(bp, orig_budget);
*budget -= work_done;
dev->quota -= work_done;
}
-
+
bp->last_status_idx = bp->status_blk->status_idx;
rmb();
@@ -2318,7 +2322,7 @@ bnx2_init_cpus(struct bnx2 *bp)
cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
cpu_reg.spad_base = BNX2_RXP_SCRATCH;
cpu_reg.mips_view_base = 0x8000000;
-
+
fw.ver_major = bnx2_RXP_b06FwReleaseMajor;
fw.ver_minor = bnx2_RXP_b06FwReleaseMinor;
fw.ver_fix = bnx2_RXP_b06FwReleaseFix;
@@ -2370,7 +2374,7 @@ bnx2_init_cpus(struct bnx2 *bp)
cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
cpu_reg.spad_base = BNX2_TXP_SCRATCH;
cpu_reg.mips_view_base = 0x8000000;
-
+
fw.ver_major = bnx2_TXP_b06FwReleaseMajor;
fw.ver_minor = bnx2_TXP_b06FwReleaseMinor;
fw.ver_fix = bnx2_TXP_b06FwReleaseFix;
@@ -2422,7 +2426,7 @@ bnx2_init_cpus(struct bnx2 *bp)
cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
cpu_reg.mips_view_base = 0x8000000;
-
+
fw.ver_major = bnx2_TPAT_b06FwReleaseMajor;
fw.ver_minor = bnx2_TPAT_b06FwReleaseMinor;
fw.ver_fix = bnx2_TPAT_b06FwReleaseFix;
@@ -2474,7 +2478,7 @@ bnx2_init_cpus(struct bnx2 *bp)
cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
cpu_reg.spad_base = BNX2_COM_SCRATCH;
cpu_reg.mips_view_base = 0x8000000;
-
+
fw.ver_major = bnx2_COM_b06FwReleaseMajor;
fw.ver_minor = bnx2_COM_b06FwReleaseMinor;
fw.ver_fix = bnx2_COM_b06FwReleaseFix;
@@ -2737,7 +2741,7 @@ bnx2_enable_nvram_access(struct bnx2 *bp)
val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
/* Enable both bits, even on read. */
- REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
+ REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
}
@@ -2748,7 +2752,7 @@ bnx2_disable_nvram_access(struct bnx2 *bp)
val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
/* Disable both bits, even after read. */
- REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
+ REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
BNX2_NVM_ACCESS_ENABLE_WR_EN));
}
@@ -3139,7 +3143,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
/* Find the data_start addr */
data_start = (written == 0) ? offset32 : page_start;
/* Find the data_end addr */
- data_end = (page_end > offset32 + len32) ?
+ data_end = (page_end > offset32 + len32) ?
(offset32 + len32) : page_end;
/* Request access to the flash interface. */
@@ -3160,8 +3164,8 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
cmd_flags |= BNX2_NVM_COMMAND_LAST;
}
rc = bnx2_nvram_read_dword(bp,
- page_start + j,
- &flash_buffer[j],
+ page_start + j,
+ &flash_buffer[j],
cmd_flags);
if (rc)
@@ -3188,7 +3192,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
if (bp->flash_info->buffered == 0) {
for (addr = page_start; addr < data_start;
addr += 4, i += 4) {
-
+
rc = bnx2_nvram_write_dword(bp, addr,
&flash_buffer[i], cmd_flags);
@@ -3222,7 +3226,7 @@ bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
if (bp->flash_info->buffered == 0) {
for (addr = data_end; addr < page_end;
addr += 4, i += 4) {
-
+
if (addr == page_end-4) {
cmd_flags = BNX2_NVM_COMMAND_LAST;
}
@@ -3347,9 +3351,9 @@ bnx2_init_chip(struct bnx2 *bp)
val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
BNX2_DMA_CONFIG_DATA_WORD_SWAP |
#ifdef __BIG_ENDIAN
- BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
+ BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
#endif
- BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
+ BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
DMA_READ_CHANS << 12 |
DMA_WRITE_CHANS << 16;
@@ -3442,7 +3446,7 @@ bnx2_init_chip(struct bnx2 *bp)
REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
(u64) bp->stats_blk_mapping >> 32);
- REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
+ REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
(bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
@@ -3504,8 +3508,10 @@ bnx2_init_tx_ring(struct bnx2 *bp)
struct tx_bd *txbd;
u32 val;
+ bp->tx_wake_thresh = bp->tx_ring_size / 2;
+
txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
-
+
txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
@@ -3513,7 +3519,7 @@ bnx2_init_tx_ring(struct bnx2 *bp)
bp->tx_cons = 0;
bp->hw_tx_cons = 0;
bp->tx_prod_bseq = 0;
-
+
val = BNX2_L2CTX_TYPE_TYPE_L2;
val |= BNX2_L2CTX_TYPE_SIZE_L2;
CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TYPE, val);
@@ -3534,7 +3540,7 @@ bnx2_init_rx_ring(struct bnx2 *bp)
{
struct rx_bd *rxbd;
int i;
- u16 prod, ring_prod;
+ u16 prod, ring_prod;
u32 val;
/* 8 for CRC and VLAN */
@@ -3546,7 +3552,7 @@ bnx2_init_rx_ring(struct bnx2 *bp)
bp->rx_cons = 0;
bp->hw_rx_cons = 0;
bp->rx_prod_bseq = 0;
-
+
for (i = 0; i < bp->rx_max_ring; i++) {
int j;
@@ -3643,7 +3649,7 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
skb_shinfo(skb)->frags[j].size,
PCI_DMA_TODEVICE);
}
- dev_kfree_skb_any(skb);
+ dev_kfree_skb(skb);
i += j + 1;
}
@@ -3669,7 +3675,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp)
rx_buf->skb = NULL;
- dev_kfree_skb_any(skb);
+ dev_kfree_skb(skb);
}
}
@@ -3921,7 +3927,7 @@ bnx2_test_memory(struct bnx2 *bp)
return ret;
}
}
-
+
return ret;
}
@@ -3953,7 +3959,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
return -EINVAL;
pkt_size = 1514;
- skb = dev_alloc_skb(pkt_size);
+ skb = netdev_alloc_skb(bp->dev, pkt_size);
if (!skb)
return -ENOMEM;
packet = skb_put(skb, pkt_size);
@@ -3999,7 +4005,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
udelay(5);
pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb(skb);
if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
goto loopback_test_done;
@@ -4118,7 +4124,7 @@ bnx2_test_link(struct bnx2 *bp)
bnx2_read_phy(bp, MII_BMSR, &bmsr);
bnx2_read_phy(bp, MII_BMSR, &bmsr);
spin_unlock_bh(&bp->phy_lock);
-
+
if (bmsr & BMSR_LSTATUS) {
return 0;
}
@@ -4261,11 +4267,11 @@ bnx2_open(struct net_device *dev)
}
else {
rc = request_irq(bp->pdev->irq, bnx2_interrupt,
- SA_SHIRQ, dev->name, dev);
+ IRQF_SHARED, dev->name, dev);
}
}
else {
- rc = request_irq(bp->pdev->irq, bnx2_interrupt, SA_SHIRQ,
+ rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED,
dev->name, dev);
}
if (rc) {
@@ -4285,7 +4291,7 @@ bnx2_open(struct net_device *dev)
bnx2_free_mem(bp);
return rc;
}
-
+
mod_timer(&bp->timer, jiffies + bp->current_interval);
atomic_set(&bp->intr_sem, 0);
@@ -4312,7 +4318,7 @@ bnx2_open(struct net_device *dev)
if (!rc) {
rc = request_irq(bp->pdev->irq, bnx2_interrupt,
- SA_SHIRQ, dev->name, dev);
+ IRQF_SHARED, dev->name, dev);
}
if (rc) {
bnx2_free_skbs(bp);
@@ -4391,10 +4397,8 @@ bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
#endif
/* Called with netif_tx_lock.
- * hard_start_xmit is pseudo-lockless - a lock is only required when
- * the tx queue is full. This way, we get the benefit of lockless
- * operations most of the time without the complexities to handle
- * netif_stop_queue/wake_queue race conditions.
+ * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
+ * netif_wake_queue().
*/
static int
bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -4419,7 +4423,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
ring_prod = TX_RING_IDX(prod);
vlan_tag_flags = 0;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
}
@@ -4427,7 +4431,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |=
(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
}
-#ifdef BCM_TSO
+#ifdef BCM_TSO
if ((mss = skb_shinfo(skb)->gso_size) &&
(skb->len > (bp->dev->mtu + ETH_HLEN))) {
u32 tcp_opt_len, ip_tcp_len;
@@ -4466,7 +4470,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
-
+
tx_buf = &bp->tx_buf_ring[ring_prod];
tx_buf->skb = skb;
pci_unmap_addr_set(tx_buf, mapping, mapping);
@@ -4513,12 +4517,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
- spin_lock(&bp->tx_lock);
netif_stop_queue(dev);
-
- if (bnx2_tx_avail(bp) > MAX_SKB_FRAGS)
+ if (bnx2_tx_avail(bp) > bp->tx_wake_thresh)
netif_wake_queue(dev);
- spin_unlock(&bp->tx_lock);
}
return NETDEV_TX_OK;
@@ -4541,7 +4542,7 @@ bnx2_close(struct net_device *dev)
bnx2_netif_stop(bp);
del_timer_sync(&bp->timer);
if (bp->flags & NO_WOL_FLAG)
- reset_code = BNX2_DRV_MSG_CODE_UNLOAD;
+ reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
else if (bp->wol)
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
else
@@ -4599,23 +4600,23 @@ bnx2_get_stats(struct net_device *dev)
net_stats->tx_bytes =
GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
- net_stats->multicast =
+ net_stats->multicast =
GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
- net_stats->collisions =
+ net_stats->collisions =
(unsigned long) stats_blk->stat_EtherStatsCollisions;
- net_stats->rx_length_errors =
+ net_stats->rx_length_errors =
(unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
stats_blk->stat_EtherStatsOverrsizePkts);
- net_stats->rx_over_errors =
+ net_stats->rx_over_errors =
(unsigned long) stats_blk->stat_IfInMBUFDiscards;
- net_stats->rx_frame_errors =
+ net_stats->rx_frame_errors =
(unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
- net_stats->rx_crc_errors =
+ net_stats->rx_crc_errors =
(unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
net_stats->rx_errors = net_stats->rx_length_errors +
@@ -4636,7 +4637,7 @@ bnx2_get_stats(struct net_device *dev)
}
net_stats->tx_errors =
- (unsigned long)
+ (unsigned long)
stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
+
net_stats->tx_aborted_errors +
@@ -4697,7 +4698,7 @@ bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return 0;
}
-
+
static int
bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
@@ -4710,7 +4711,7 @@ bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (cmd->autoneg == AUTONEG_ENABLE) {
autoneg |= AUTONEG_SPEED;
- cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
+ cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
/* allow advertising 1 speed */
if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
@@ -4987,7 +4988,7 @@ bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
- bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
+ bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
@@ -5128,6 +5129,16 @@ bnx2_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
+static int
+bnx2_set_tso(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
+ else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
+ return 0;
+}
+
#define BNX2_NUM_STATS 46
static struct {
@@ -5195,46 +5206,46 @@ static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
- STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
- STATS_OFFSET32(stat_Dot3StatsFCSErrors),
- STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
- STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
- STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
- STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
- STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
- STATS_OFFSET32(stat_Dot3StatsLateCollisions),
- STATS_OFFSET32(stat_EtherStatsCollisions),
- STATS_OFFSET32(stat_EtherStatsFragments),
- STATS_OFFSET32(stat_EtherStatsJabbers),
- STATS_OFFSET32(stat_EtherStatsUndersizePkts),
- STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
- STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
- STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
- STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
- STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
- STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
- STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
- STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
- STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
- STATS_OFFSET32(stat_XonPauseFramesReceived),
- STATS_OFFSET32(stat_XoffPauseFramesReceived),
- STATS_OFFSET32(stat_OutXonSent),
- STATS_OFFSET32(stat_OutXoffSent),
- STATS_OFFSET32(stat_MacControlFramesReceived),
- STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
- STATS_OFFSET32(stat_IfInMBUFDiscards),
+ STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
+ STATS_OFFSET32(stat_Dot3StatsFCSErrors),
+ STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
+ STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
+ STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
+ STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
+ STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
+ STATS_OFFSET32(stat_Dot3StatsLateCollisions),
+ STATS_OFFSET32(stat_EtherStatsCollisions),
+ STATS_OFFSET32(stat_EtherStatsFragments),
+ STATS_OFFSET32(stat_EtherStatsJabbers),
+ STATS_OFFSET32(stat_EtherStatsUndersizePkts),
+ STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
+ STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
+ STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
+ STATS_OFFSET32(stat_XonPauseFramesReceived),
+ STATS_OFFSET32(stat_XoffPauseFramesReceived),
+ STATS_OFFSET32(stat_OutXonSent),
+ STATS_OFFSET32(stat_OutXoffSent),
+ STATS_OFFSET32(stat_MacControlFramesReceived),
+ STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
+ STATS_OFFSET32(stat_IfInMBUFDiscards),
STATS_OFFSET32(stat_FwRxDrop),
};
/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
* skipped because of errata.
- */
+ */
static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
8,0,8,8,8,8,8,8,8,8,
4,0,4,4,4,4,4,4,4,4,
@@ -5418,7 +5429,7 @@ bnx2_phys_id(struct net_device *dev, u32 data)
return 0;
}
-static struct ethtool_ops bnx2_ethtool_ops = {
+static const struct ethtool_ops bnx2_ethtool_ops = {
.get_settings = bnx2_get_settings,
.set_settings = bnx2_set_settings,
.get_drvinfo = bnx2_get_drvinfo,
@@ -5445,7 +5456,7 @@ static struct ethtool_ops bnx2_ethtool_ops = {
.set_sg = ethtool_op_set_sg,
#ifdef BCM_TSO
.get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .set_tso = bnx2_set_tso,
#endif
.self_test_count = bnx2_self_test_count,
.self_test = bnx2_self_test,
@@ -5566,20 +5577,20 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
/* enable device (incl. PCI PM wakeup), and bus-mastering */
rc = pci_enable_device(pdev);
if (rc) {
- printk(KERN_ERR PFX "Cannot enable PCI device, aborting.");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
goto err_out;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find PCI device base address, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot find PCI device base address, aborting.\n");
rc = -ENODEV;
goto err_out_disable;
}
rc = pci_request_regions(pdev, DRV_MODULE_NAME);
if (rc) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
goto err_out_disable;
}
@@ -5587,15 +5598,15 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (bp->pm_cap == 0) {
- printk(KERN_ERR PFX "Cannot find power management capability, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "Cannot find power management capability, aborting.\n");
rc = -EIO;
goto err_out_release;
}
bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
if (bp->pcix_cap == 0) {
- printk(KERN_ERR PFX "Cannot find PCIX capability, aborting.\n");
+ dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
rc = -EIO;
goto err_out_release;
}
@@ -5603,14 +5614,14 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
bp->flags |= USING_DAC_FLAG;
if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
- printk(KERN_ERR PFX "pci_set_consistent_dma_mask "
- "failed, aborting.\n");
+ dev_err(&pdev->dev,
+ "pci_set_consistent_dma_mask failed, aborting.\n");
rc = -EIO;
goto err_out_release;
}
}
else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
- printk(KERN_ERR PFX "System does not support DMA, aborting.\n");
+ dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
rc = -EIO;
goto err_out_release;
}
@@ -5619,7 +5630,6 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->pdev = pdev;
spin_lock_init(&bp->phy_lock);
- spin_lock_init(&bp->tx_lock);
INIT_WORK(&bp->reset_task, bnx2_reset_task, bp);
dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
@@ -5630,7 +5640,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->regview = ioremap_nocache(dev->base_addr, mem_len);
if (!bp->regview) {
- printk(KERN_ERR PFX "Cannot map register space, aborting.\n");
+ dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
rc = -ENOMEM;
goto err_out_release;
}
@@ -5655,7 +5665,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->flags |= PCIX_FLAG;
clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
-
+
clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
switch (clkreg) {
case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
@@ -5702,8 +5712,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
!(bp->flags & PCIX_FLAG)) {
- printk(KERN_ERR PFX "5706 A1 can only be used in a PCIX bus, "
- "aborting.\n");
+ dev_err(&pdev->dev,
+ "5706 A1 can only be used in a PCIX bus, aborting.\n");
goto err_out_unmap;
}
@@ -5724,7 +5734,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
BNX2_DEV_INFO_SIGNATURE_MAGIC) {
- printk(KERN_ERR PFX "Firmware not running, aborting.\n");
+ dev_err(&pdev->dev, "Firmware not running, aborting.\n");
rc = -ENODEV;
goto err_out_unmap;
}
@@ -5742,7 +5752,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->mac_addr[5] = (u8) reg;
bp->tx_ring_size = MAX_TX_DESC_CNT;
- bnx2_set_rx_ring_size(bp, 100);
+ bnx2_set_rx_ring_size(bp, 255);
bp->rx_csum = 1;
@@ -5752,7 +5762,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->tx_quick_cons_trip = 20;
bp->tx_ticks_int = 80;
bp->tx_ticks = 80;
-
+
bp->rx_quick_cons_trip_int = 6;
bp->rx_quick_cons_trip = 6;
bp->rx_ticks_int = 18;
@@ -5795,6 +5805,34 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->cmd_ticks_int = bp->cmd_ticks;
}
+ /* Disable MSI on 5706 if AMD 8132 bridge is found.
+ *
+ * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
+ * with byte enables disabled on the unused 32-bit word. This is legal
+ * but causes problems on the AMD 8132 which will eventually stop
+ * responding after a while.
+ *
+ * AMD believes this incompatibility is unique to the 5706, and
+ * prefers to locally disable MSI rather than globally disabling it
+ * using pci_msi_quirk.
+ */
+ if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
+ struct pci_dev *amd_8132 = NULL;
+
+ while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_8132_BRIDGE,
+ amd_8132))) {
+ u8 rev;
+
+ pci_read_config_byte(amd_8132, PCI_REVISION_ID, &rev);
+ if (rev >= 0x10 && rev <= 0x13) {
+ disable_msi = 1;
+ pci_dev_put(amd_8132);
+ break;
+ }
+ }
+ }
+
bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
bp->req_line_speed = 0;
if (bp->phy_flags & PHY_SERDES_FLAG) {
@@ -5886,7 +5924,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
if ((rc = register_netdev(dev))) {
- printk(KERN_ERR PFX "Cannot register net device\n");
+ dev_err(&pdev->dev, "Cannot register net device\n");
if (bp->regview)
iounmap(bp->regview);
pci_release_regions(pdev);
@@ -5926,7 +5964,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
#endif
#ifdef BCM_TSO
- dev->features |= NETIF_F_TSO;
+ dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
#endif
netif_carrier_off(bp->dev);
@@ -5968,7 +6006,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_detach(dev);
del_timer_sync(&bp->timer);
if (bp->flags & NO_WOL_FLAG)
- reset_code = BNX2_DRV_MSG_CODE_UNLOAD;
+ reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
else if (bp->wol)
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
else
@@ -6006,7 +6044,7 @@ static struct pci_driver bnx2_pci_driver = {
static int __init bnx2_init(void)
{
- return pci_module_init(&bnx2_pci_driver);
+ return pci_register_driver(&bnx2_pci_driver);
}
static void __exit bnx2_cleanup(void)
diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h
index 5845e334941..ca31904893e 100644
--- a/drivers/net/bnx2.h
+++ b/drivers/net/bnx2.h
@@ -22,9 +22,9 @@
*/
struct tx_bd {
u32 tx_bd_haddr_hi;
- u32 tx_bd_haddr_lo;
- u32 tx_bd_mss_nbytes;
- u32 tx_bd_vlan_tag_flags;
+ u32 tx_bd_haddr_lo;
+ u32 tx_bd_mss_nbytes;
+ u32 tx_bd_vlan_tag_flags;
#define TX_BD_FLAGS_CONN_FAULT (1<<0)
#define TX_BD_FLAGS_TCP_UDP_CKSUM (1<<1)
#define TX_BD_FLAGS_IP_CKSUM (1<<2)
@@ -3890,14 +3890,10 @@ struct bnx2 {
u32 tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES)));
u16 tx_prod;
- struct tx_bd *tx_desc_ring;
- struct sw_bd *tx_buf_ring;
- int tx_ring_size;
-
u16 tx_cons __attribute__((aligned(L1_CACHE_BYTES)));
u16 hw_tx_cons;
-#ifdef BCM_VLAN
+#ifdef BCM_VLAN
struct vlan_group *vlgrp;
#endif
@@ -3916,9 +3912,11 @@ struct bnx2 {
struct sw_bd *rx_buf_ring;
struct rx_bd *rx_desc_ring[MAX_RX_RINGS];
- /* Only used to synchronize netif_stop_queue/wake_queue when tx */
- /* ring is full */
- spinlock_t tx_lock;
+ /* TX constants */
+ struct tx_bd *tx_desc_ring;
+ struct sw_bd *tx_buf_ring;
+ int tx_ring_size;
+ u32 tx_wake_thresh;
/* End of fields used in the performance code paths. */
@@ -3952,7 +3950,7 @@ struct bnx2 {
#define CHIP_REV_Ax 0x00000000
#define CHIP_REV_Bx 0x00001000
#define CHIP_REV_Cx 0x00002000
-
+
#define CHIP_METAL(bp) (((bp)->chip_id) & 0x00000ff0)
#define CHIP_BONDING(bp) (((bp)->chip_id) & 0x0000000f)
@@ -3971,7 +3969,7 @@ struct bnx2 {
u32 phy_addr;
u32 phy_id;
-
+
u16 bus_speed_mhz;
u8 wol;
@@ -4027,7 +4025,7 @@ struct bnx2 {
u32 advertising;
- u8 req_flow_ctrl; /* flow ctrl advertisement */
+ u8 req_flow_ctrl; /* flow ctrl advertisement */
/* settings or forced */
/* settings */
u8 autoneg;
@@ -4174,13 +4172,14 @@ struct fw_info {
#define BNX2_DRV_MSG_CODE_PULSE 0x06000000
#define BNX2_DRV_MSG_CODE_DIAG 0x07000000
#define BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL 0x09000000
+#define BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN 0x0b000000
#define BNX2_DRV_MSG_DATA 0x00ff0000
#define BNX2_DRV_MSG_DATA_WAIT0 0x00010000
#define BNX2_DRV_MSG_DATA_WAIT1 0x00020000
#define BNX2_DRV_MSG_DATA_WAIT2 0x00030000
#define BNX2_DRV_MSG_DATA_WAIT3 0x00040000
-
+
#define BNX2_DRV_MSG_SEQ 0x0000ffff
#define BNX2_FW_MB 0x00000008
@@ -4190,38 +4189,38 @@ struct fw_info {
#define BNX2_FW_MSG_STATUS_FAILURE 0x00ff0000
#define BNX2_LINK_STATUS 0x0000000c
-#define BNX2_LINK_STATUS_INIT_VALUE 0xffffffff
-#define BNX2_LINK_STATUS_LINK_UP 0x1
-#define BNX2_LINK_STATUS_LINK_DOWN 0x0
+#define BNX2_LINK_STATUS_INIT_VALUE 0xffffffff
+#define BNX2_LINK_STATUS_LINK_UP 0x1
+#define BNX2_LINK_STATUS_LINK_DOWN 0x0
#define BNX2_LINK_STATUS_SPEED_MASK 0x1e
-#define BNX2_LINK_STATUS_AN_INCOMPLETE (0<<1)
-#define BNX2_LINK_STATUS_10HALF (1<<1)
-#define BNX2_LINK_STATUS_10FULL (2<<1)
-#define BNX2_LINK_STATUS_100HALF (3<<1)
-#define BNX2_LINK_STATUS_100BASE_T4 (4<<1)
-#define BNX2_LINK_STATUS_100FULL (5<<1)
-#define BNX2_LINK_STATUS_1000HALF (6<<1)
-#define BNX2_LINK_STATUS_1000FULL (7<<1)
-#define BNX2_LINK_STATUS_2500HALF (8<<1)
-#define BNX2_LINK_STATUS_2500FULL (9<<1)
-#define BNX2_LINK_STATUS_AN_ENABLED (1<<5)
-#define BNX2_LINK_STATUS_AN_COMPLETE (1<<6)
-#define BNX2_LINK_STATUS_PARALLEL_DET (1<<7)
-#define BNX2_LINK_STATUS_RESERVED (1<<8)
-#define BNX2_LINK_STATUS_PARTNER_AD_1000FULL (1<<9)
-#define BNX2_LINK_STATUS_PARTNER_AD_1000HALF (1<<10)
-#define BNX2_LINK_STATUS_PARTNER_AD_100BT4 (1<<11)
-#define BNX2_LINK_STATUS_PARTNER_AD_100FULL (1<<12)
-#define BNX2_LINK_STATUS_PARTNER_AD_100HALF (1<<13)
-#define BNX2_LINK_STATUS_PARTNER_AD_10FULL (1<<14)
-#define BNX2_LINK_STATUS_PARTNER_AD_10HALF (1<<15)
-#define BNX2_LINK_STATUS_TX_FC_ENABLED (1<<16)
-#define BNX2_LINK_STATUS_RX_FC_ENABLED (1<<17)
-#define BNX2_LINK_STATUS_PARTNER_SYM_PAUSE_CAP (1<<18)
-#define BNX2_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP (1<<19)
-#define BNX2_LINK_STATUS_SERDES_LINK (1<<20)
-#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL (1<<21)
-#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF (1<<22)
+#define BNX2_LINK_STATUS_AN_INCOMPLETE (0<<1)
+#define BNX2_LINK_STATUS_10HALF (1<<1)
+#define BNX2_LINK_STATUS_10FULL (2<<1)
+#define BNX2_LINK_STATUS_100HALF (3<<1)
+#define BNX2_LINK_STATUS_100BASE_T4 (4<<1)
+#define BNX2_LINK_STATUS_100FULL (5<<1)
+#define BNX2_LINK_STATUS_1000HALF (6<<1)
+#define BNX2_LINK_STATUS_1000FULL (7<<1)
+#define BNX2_LINK_STATUS_2500HALF (8<<1)
+#define BNX2_LINK_STATUS_2500FULL (9<<1)
+#define BNX2_LINK_STATUS_AN_ENABLED (1<<5)
+#define BNX2_LINK_STATUS_AN_COMPLETE (1<<6)
+#define BNX2_LINK_STATUS_PARALLEL_DET (1<<7)
+#define BNX2_LINK_STATUS_RESERVED (1<<8)
+#define BNX2_LINK_STATUS_PARTNER_AD_1000FULL (1<<9)
+#define BNX2_LINK_STATUS_PARTNER_AD_1000HALF (1<<10)
+#define BNX2_LINK_STATUS_PARTNER_AD_100BT4 (1<<11)
+#define BNX2_LINK_STATUS_PARTNER_AD_100FULL (1<<12)
+#define BNX2_LINK_STATUS_PARTNER_AD_100HALF (1<<13)
+#define BNX2_LINK_STATUS_PARTNER_AD_10FULL (1<<14)
+#define BNX2_LINK_STATUS_PARTNER_AD_10HALF (1<<15)
+#define BNX2_LINK_STATUS_TX_FC_ENABLED (1<<16)
+#define BNX2_LINK_STATUS_RX_FC_ENABLED (1<<17)
+#define BNX2_LINK_STATUS_PARTNER_SYM_PAUSE_CAP (1<<18)
+#define BNX2_LINK_STATUS_PARTNER_ASYM_PAUSE_CAP (1<<19)
+#define BNX2_LINK_STATUS_SERDES_LINK (1<<20)
+#define BNX2_LINK_STATUS_PARTNER_AD_2500FULL (1<<21)
+#define BNX2_LINK_STATUS_PARTNER_AD_2500HALF (1<<22)
#define BNX2_DRV_PULSE_MB 0x00000010
#define BNX2_DRV_PULSE_SEQ_MASK 0x00007fff
@@ -4401,7 +4400,7 @@ struct fw_info {
0x00020000)
#define BNX2_BC_STATE_RESET_TYPE_VAUX (BNX2_BC_STATE_RESET_TYPE_SIG | \
0x00030000)
-#define BNX2_BC_STATE_RESET_TYPE_DRV_MASK DRV_MSG_CODE
+#define BNX2_BC_STATE_RESET_TYPE_DRV_MASK DRV_MSG_CODE
#define BNX2_BC_STATE_RESET_TYPE_DRV_RESET (BNX2_BC_STATE_RESET_TYPE_SIG | \
DRV_MSG_CODE_RESET)
#define BNX2_BC_STATE_RESET_TYPE_DRV_UNLOAD (BNX2_BC_STATE_RESET_TYPE_SIG | \
@@ -4444,7 +4443,7 @@ struct fw_info {
#define BNX2_BC_STATE_ERR_DRV_DEAD (BNX2_BC_STATE_SIGN | 0x0500)
#define BNX2_BC_STATE_ERR_NO_RXP (BNX2_BC_STATE_SIGN | 0x0600)
#define BNX2_BC_STATE_ERR_TOO_MANY_RBUF (BNX2_BC_STATE_SIGN | 0x0700)
-
+
#define BNX2_BC_STATE_DEBUG_CMD 0x1dc
#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE 0x42440000
#define BNX2_BC_STATE_BC_DBG_CMD_SIGNATURE_MASK 0xffff0000
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 6a407070c2e..3fb354d9c51 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -85,6 +85,7 @@
#define AD_LINK_SPEED_BITMASK_10MBPS 0x2
#define AD_LINK_SPEED_BITMASK_100MBPS 0x4
#define AD_LINK_SPEED_BITMASK_1000MBPS 0x8
+#define AD_LINK_SPEED_BITMASK_10000MBPS 0x10
//endalloun
// compare MAC addresses
@@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port *port);
static u8 __get_duplex(struct port *port);
static inline void __initialize_port_locks(struct port *port);
//conversions
-static void __ntohs_lacpdu(struct lacpdu *lacpdu);
+static void __htons_lacpdu(struct lacpdu *lacpdu);
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
@@ -330,7 +331,8 @@ static inline void __release_rx_machine_lock(struct port *port)
* 0,
* %AD_LINK_SPEED_BITMASK_10MBPS,
* %AD_LINK_SPEED_BITMASK_100MBPS,
- * %AD_LINK_SPEED_BITMASK_1000MBPS
+ * %AD_LINK_SPEED_BITMASK_1000MBPS,
+ * %AD_LINK_SPEED_BITMASK_10000MBPS
*/
static u16 __get_link_speed(struct port *port)
{
@@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port *port)
speed = AD_LINK_SPEED_BITMASK_1000MBPS;
break;
+ case SPEED_10000:
+ speed = AD_LINK_SPEED_BITMASK_10000MBPS;
+ break;
+
default:
speed = 0; // unknown speed value from ethtool. shouldn't happen
break;
@@ -414,23 +420,23 @@ static inline void __initialize_port_locks(struct port *port)
//conversions
/**
- * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
+ * __htons_lacpdu - convert the contents of a LACPDU to network byte order
* @lacpdu: the speicifed lacpdu
*
* For each multi-byte field in the lacpdu, convert its content
*/
-static void __ntohs_lacpdu(struct lacpdu *lacpdu)
+static void __htons_lacpdu(struct lacpdu *lacpdu)
{
if (lacpdu) {
- lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority);
- lacpdu->actor_key = ntohs(lacpdu->actor_key);
- lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority);
- lacpdu->actor_port = ntohs(lacpdu->actor_port);
- lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
- lacpdu->partner_key = ntohs(lacpdu->partner_key);
- lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority);
- lacpdu->partner_port = ntohs(lacpdu->partner_port);
- lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay);
+ lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
+ lacpdu->actor_key = htons(lacpdu->actor_key);
+ lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
+ lacpdu->actor_port = htons(lacpdu->actor_port);
+ lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
+ lacpdu->partner_key = htons(lacpdu->partner_key);
+ lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
+ lacpdu->partner_port = htons(lacpdu->partner_port);
+ lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
}
}
@@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// record the new parameter values for the partner operational
- port->partner_oper_port_number = lacpdu->actor_port;
- port->partner_oper_port_priority = lacpdu->actor_port_priority;
+ port->partner_oper_port_number = ntohs(lacpdu->actor_port);
+ port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority);
port->partner_oper_system = lacpdu->actor_system;
- port->partner_oper_system_priority = lacpdu->actor_system_priority;
- port->partner_oper_key = lacpdu->actor_key;
+ port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority);
+ port->partner_oper_key = ntohs(lacpdu->actor_key);
// zero partener's lase states
port->partner_oper_port_state = 0;
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
@@ -561,11 +567,11 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// check if any parameter is different
- if ((lacpdu->actor_port != port->partner_oper_port_number) ||
- (lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
+ if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) ||
+ (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) ||
MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
- (lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
- (lacpdu->actor_key != port->partner_oper_key) ||
+ (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) ||
+ (ntohs(lacpdu->actor_key) != port->partner_oper_key) ||
((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
) {
// update the state machine Selected variable
@@ -628,11 +634,11 @@ static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// check if all parameters are alike
- if (((lacpdu->partner_port == port->actor_port_number) &&
- (lacpdu->partner_port_priority == port->actor_port_priority) &&
+ if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
+ (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
!MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
- (lacpdu->partner_system_priority == port->actor_system_priority) &&
- (lacpdu->partner_key == port->actor_oper_port_key) &&
+ (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
+ (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
// or this is individual link(aggregation == FALSE)
((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
@@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// check if any parameter is different
- if ((lacpdu->partner_port != port->actor_port_number) ||
- (lacpdu->partner_port_priority != port->actor_port_priority) ||
+ if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
+ (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
- (lacpdu->partner_system_priority != port->actor_system_priority) ||
- (lacpdu->partner_key != port->actor_oper_port_key) ||
+ (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
+ (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
@@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
case AD_LINK_SPEED_BITMASK_1000MBPS:
bandwidth = aggregator->num_of_ports * 1000;
break;
+ case AD_LINK_SPEED_BITMASK_10000MBPS:
+ bandwidth = aggregator->num_of_ports * 10000;
+ break;
default:
bandwidth=0; // to silent the compilor ....
}
@@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_port(struct port *port)
*/
/* Convert all non u8 parameters to Big Endian for transmit */
- __ntohs_lacpdu(lacpdu);
+ __htons_lacpdu(lacpdu);
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
switch (lacpdu->subtype) {
case AD_TYPE_LACPDU:
- __ntohs_lacpdu(lacpdu);
dprintk("Received LACPDU on port %d\n", port->actor_port_number);
ad_rx_machine(lacpdu, port);
break;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 8171cae0668..c0bbddae4ec 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -33,7 +33,6 @@
//#define BONDING_DEBUG 1
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -97,6 +96,7 @@ static char *lacp_rate = NULL;
static char *xmit_hash_policy = NULL;
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
+static char *arp_validate = NULL;
struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
@@ -128,6 +128,8 @@ module_param(arp_interval, int, 0);
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
module_param_array(arp_ip_target, charp, NULL, 0);
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
+module_param(arp_validate, charp, 0);
+MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
/*----------------------------- Global variables ----------------------------*/
@@ -171,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = {
{ NULL, -1},
};
+struct bond_parm_tbl arp_validate_tbl[] = {
+{ "none", BOND_ARP_VALIDATE_NONE},
+{ "active", BOND_ARP_VALIDATE_ACTIVE},
+{ "backup", BOND_ARP_VALIDATE_BACKUP},
+{ "all", BOND_ARP_VALIDATE_ALL},
+{ NULL, -1},
+};
+
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -639,6 +649,7 @@ verify:
case SPEED_10:
case SPEED_100:
case SPEED_1000:
+ case SPEED_10000:
break;
default:
return -1;
@@ -1211,10 +1222,14 @@ static int bond_compute_features(struct bonding *bond)
unsigned long features = BOND_INTERSECT_FEATURES;
struct slave *slave;
struct net_device *bond_dev = bond->dev;
+ unsigned short max_hard_header_len = ETH_HLEN;
int i;
- bond_for_each_slave(bond, slave, i)
+ bond_for_each_slave(bond, slave, i) {
features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
+ if (slave->dev->hard_header_len > max_hard_header_len)
+ max_hard_header_len = slave->dev->hard_header_len;
+ }
if ((features & NETIF_F_SG) &&
!(features & NETIF_F_ALL_CSUM))
@@ -1232,6 +1247,7 @@ static int bond_compute_features(struct bonding *bond)
features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
bond_dev->features = features;
+ bond_dev->hard_header_len = max_hard_header_len;
return 0;
}
@@ -1366,6 +1382,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
new_slave->dev = slave_dev;
+ slave_dev->priv_flags |= IFF_BONDING;
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
@@ -1418,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_compute_features(bond);
+ new_slave->last_arp_rx = jiffies;
+
if (bond->params.miimon && !bond->params.use_carrier) {
link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@@ -1494,29 +1513,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
switch (bond->params.mode) {
case BOND_MODE_ACTIVEBACKUP:
- /* if we're in active-backup mode, we need one and
- * only one active interface. The backup interfaces
- * will have their SLAVE_INACTIVE flag set because we
- * need them to be drop all packets. Thus, since we
- * guarantee that curr_active_slave always point to
- * the last usable interface, we just have to verify
- * this interface's flag.
- */
- if (((!bond->curr_active_slave) ||
- (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
- (new_slave->link != BOND_LINK_DOWN)) {
- /* first slave or no active slave yet, and this link
- is OK, so make this interface the active one */
- bond_change_active_slave(bond, new_slave);
- printk(KERN_INFO DRV_NAME
- ": %s: first active interface up!\n",
- bond->dev->name);
- netif_carrier_on(bond->dev);
-
- } else {
- dprintk("This is just a backup slave\n");
- bond_set_slave_inactive_flags(new_slave);
- }
+ bond_set_slave_inactive_flags(new_slave);
+ bond_select_active_slave(bond);
break;
case BOND_MODE_8023AD:
/* in 802.3ad mode, the internal mechanism
@@ -1779,7 +1777,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mac_address(slave_dev, &addr);
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
- IFF_SLAVE_INACTIVE);
+ IFF_SLAVE_INACTIVE | IFF_BONDING |
+ IFF_SLAVE_NEEDARP);
kfree(slave);
@@ -2253,7 +2252,7 @@ static u32 bond_glean_dev_ip(struct net_device *dev)
{
struct in_device *idev;
struct in_ifaddr *ifa;
- u32 addr = 0;
+ __be32 addr = 0;
if (!dev)
return 0;
@@ -2292,6 +2291,25 @@ static int bond_has_ip(struct bonding *bond)
return 0;
}
+static int bond_has_this_ip(struct bonding *bond, u32 ip)
+{
+ struct vlan_entry *vlan, *vlan_next;
+
+ if (ip == bond->master_ip)
+ return 1;
+
+ if (list_empty(&bond->vlan_list))
+ return 0;
+
+ list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+ vlan_list) {
+ if (ip == vlan->vlan_ip)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* We go to the (large) trouble of VLAN tagging ARP frames because
* switches in VLAN mode (especially if ports are configured as
@@ -2430,6 +2448,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
}
}
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
+{
+ int i;
+ u32 *targets = bond->params.arp_targets;
+
+ targets = bond->params.arp_targets;
+ for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
+ dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] "
+ "%u.%u.%u.%u bhti(tip) %d\n",
+ NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]),
+ bond_has_this_ip(bond, tip));
+ if (sip == targets[i]) {
+ if (bond_has_this_ip(bond, tip))
+ slave->last_arp_rx = jiffies;
+ return;
+ }
+ }
+}
+
+static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct arphdr *arp;
+ struct slave *slave;
+ struct bonding *bond;
+ unsigned char *arp_ptr;
+ u32 sip, tip;
+
+ if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
+ goto out;
+
+ bond = dev->priv;
+ read_lock(&bond->lock);
+
+ dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
+ bond->dev->name, skb->dev ? skb->dev->name : "NULL",
+ orig_dev ? orig_dev->name : "NULL");
+
+ slave = bond_get_slave_by_dev(bond, orig_dev);
+ if (!slave || !slave_do_arp_validate(bond, slave))
+ goto out_unlock;
+
+ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
+ if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+ (2 * dev->addr_len) +
+ (2 * sizeof(u32)))))
+ goto out_unlock;
+
+ arp = skb->nh.arph;
+ if (arp->ar_hln != dev->addr_len ||
+ skb->pkt_type == PACKET_OTHERHOST ||
+ skb->pkt_type == PACKET_LOOPBACK ||
+ arp->ar_hrd != htons(ARPHRD_ETHER) ||
+ arp->ar_pro != htons(ETH_P_IP) ||
+ arp->ar_pln != 4)
+ goto out_unlock;
+
+ arp_ptr = (unsigned char *)(arp + 1);
+ arp_ptr += dev->addr_len;
+ memcpy(&sip, arp_ptr, 4);
+ arp_ptr += 4 + dev->addr_len;
+ memcpy(&tip, arp_ptr, 4);
+
+ dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u"
+ " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name,
+ slave->state, bond->params.arp_validate,
+ slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip));
+
+ /*
+ * Backup slaves won't see the ARP reply, but do come through
+ * here for each ARP probe (so we swap the sip/tip to validate
+ * the probe). In a "redundant switch, common router" type of
+ * configuration, the ARP probe will (hopefully) travel from
+ * the active, through one switch, the router, then the other
+ * switch before reaching the backup.
+ */
+ if (slave->state == BOND_STATE_ACTIVE)
+ bond_validate_arp(bond, slave, sip, tip);
+ else
+ bond_validate_arp(bond, slave, tip, sip);
+
+out_unlock:
+ read_unlock(&bond->lock);
+out:
+ dev_kfree_skb(skb);
+ return NET_RX_SUCCESS;
+}
+
/*
* this function is called regularly to monitor each slave's link
* ensuring that traffic is being sent and received when arp monitoring
@@ -2594,7 +2699,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
*/
bond_for_each_slave(bond, slave, i) {
if (slave->link != BOND_LINK_UP) {
- if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) {
+ if ((jiffies - slave_last_rx(bond, slave)) <=
+ delta_in_ticks) {
slave->link = BOND_LINK_UP;
@@ -2639,7 +2745,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
if ((slave != bond->curr_active_slave) &&
(!bond->current_arp_slave) &&
- (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
+ (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) &&
bond_has_ip(bond))) {
/* a backup slave has gone down; three times
* the delta allows the current slave to be
@@ -2686,7 +2792,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
* if it is up and needs to take over as the curr_active_slave
*/
if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
- (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
+ (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) &&
bond_has_ip(bond))) &&
((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
@@ -2951,7 +3057,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave
seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
seq_printf(seq, "MII Status: %s\n",
(slave->link == BOND_LINK_UP) ? "up" : "down");
- seq_printf(seq, "Link Failure Count: %d\n",
+ seq_printf(seq, "Link Failure Count: %u\n",
slave->link_failure_count);
seq_printf(seq,
@@ -3211,6 +3317,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
(event_dev ? event_dev->name : "None"),
event);
+ if (!(event_dev->priv_flags & IFF_BONDING))
+ return NOTIFY_DONE;
+
if (event_dev->flags & IFF_MASTER) {
dprintk("IFF_MASTER\n");
return bond_master_netdev_event(event, event_dev);
@@ -3306,6 +3415,21 @@ static void bond_unregister_lacpdu(struct bonding *bond)
dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
}
+void bond_register_arp(struct bonding *bond)
+{
+ struct packet_type *pt = &bond->arp_mon_pt;
+
+ pt->type = htons(ETH_P_ARP);
+ pt->dev = NULL; /*bond->dev;XXX*/
+ pt->func = bond_arp_rcv;
+ dev_add_pack(pt);
+}
+
+void bond_unregister_arp(struct bonding *bond)
+{
+ dev_remove_pack(&bond->arp_mon_pt);
+}
+
/*---------------------------- Hashing Policies -----------------------------*/
/*
@@ -3392,6 +3516,9 @@ static int bond_open(struct net_device *bond_dev)
} else {
arp_timer->function = (void *)&bond_loadbalance_arp_mon;
}
+ if (bond->params.arp_validate)
+ bond_register_arp(bond);
+
add_timer(arp_timer);
}
@@ -3419,9 +3546,11 @@ static int bond_close(struct net_device *bond_dev)
bond_unregister_lacpdu(bond);
}
+ if (bond->params.arp_validate)
+ bond_unregister_arp(bond);
+
write_lock_bh(&bond->lock);
- bond_mc_list_destroy(bond);
/* signal timers not to re-arm */
bond->kill_timers = 1;
@@ -3452,8 +3581,6 @@ static int bond_close(struct net_device *bond_dev)
break;
}
- /* Release the bonded slaves */
- bond_release_all(bond_dev);
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
@@ -4131,7 +4258,7 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
snprintf(drvinfo->fw_version, 32, "%d", BOND_ABI_VERSION);
}
-static struct ethtool_ops bond_ethtool_ops = {
+static const struct ethtool_ops bond_ethtool_ops = {
.get_tx_csum = ethtool_op_get_tx_csum,
.get_tso = ethtool_op_get_tso,
.get_ufo = ethtool_op_get_ufo,
@@ -4180,6 +4307,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
/* Initialize the device options */
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
+ bond_dev->priv_flags |= IFF_BONDING;
/* At first, we block adding VLANs. That's the only way to
* prevent problems that occur when adding VLANs over an
@@ -4238,6 +4366,9 @@ static void bond_free_all(void)
list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
struct net_device *bond_dev = bond->dev;
+ bond_mc_list_destroy(bond);
+ /* Release the bonded slaves */
+ bond_release_all(bond_dev);
unregister_netdevice(bond_dev);
bond_deinit(bond_dev);
}
@@ -4271,6 +4402,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
static int bond_check_params(struct bond_params *params)
{
+ int arp_validate_value;
+
/*
* Convert string parameters.
*/
@@ -4474,6 +4607,29 @@ static int bond_check_params(struct bond_params *params)
arp_interval = 0;
}
+ if (arp_validate) {
+ if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
+ printk(KERN_ERR DRV_NAME
+ ": arp_validate only supported in active-backup mode\n");
+ return -EINVAL;
+ }
+ if (!arp_interval) {
+ printk(KERN_ERR DRV_NAME
+ ": arp_validate requires arp_interval\n");
+ return -EINVAL;
+ }
+
+ arp_validate_value = bond_parse_parm(arp_validate,
+ arp_validate_tbl);
+ if (arp_validate_value == -1) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: invalid arp_validate \"%s\"\n",
+ arp_validate == NULL ? "NULL" : arp_validate);
+ return -EINVAL;
+ }
+ } else
+ arp_validate_value = 0;
+
if (miimon) {
printk(KERN_INFO DRV_NAME
": MII link monitoring set to %d ms\n",
@@ -4482,8 +4638,10 @@ static int bond_check_params(struct bond_params *params)
int i;
printk(KERN_INFO DRV_NAME
- ": ARP monitoring set to %d ms with %d target(s):",
- arp_interval, arp_ip_count);
+ ": ARP monitoring set to %d ms, validate %s, with %d target(s):",
+ arp_interval,
+ arp_validate_tbl[arp_validate_value].modename,
+ arp_ip_count);
for (i = 0; i < arp_ip_count; i++)
printk (" %s", arp_ip_target[i]);
@@ -4517,6 +4675,7 @@ static int bond_check_params(struct bond_params *params)
params->xmit_policy = xmit_hashtype;
params->miimon = miimon;
params->arp_interval = arp_interval;
+ params->arp_validate = arp_validate_value;
params->updelay = updelay;
params->downdelay = downdelay;
params->use_carrier = use_carrier;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index 5a9bd95884b..ced9ed8f995 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -20,7 +20,6 @@
* file called LICENSE.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -52,6 +51,7 @@ extern struct bond_params bonding_defaults;
extern struct bond_parm_tbl bond_mode_tbl[];
extern struct bond_parm_tbl bond_lacp_tbl[];
extern struct bond_parm_tbl xmit_hashtype_tbl[];
+extern struct bond_parm_tbl arp_validate_tbl[];
static int expected_refcount = -1;
static struct class *netdev_class;
@@ -504,6 +504,53 @@ out:
static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
/*
+ * Show and set arp_validate.
+ */
+static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+{
+ struct bonding *bond = to_bond(cd);
+
+ return sprintf(buf, "%s %d\n",
+ arp_validate_tbl[bond->params.arp_validate].modename,
+ bond->params.arp_validate) + 1;
+}
+
+static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+{
+ int new_value;
+ struct bonding *bond = to_bond(cd);
+
+ new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
+ if (new_value < 0) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Ignoring invalid arp_validate value %s\n",
+ bond->dev->name, buf);
+ return -EINVAL;
+ }
+ if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: arp_validate only supported in active-backup mode.\n",
+ bond->dev->name);
+ return -EINVAL;
+ }
+ printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n",
+ bond->dev->name, arp_validate_tbl[new_value].modename,
+ new_value);
+
+ if (!bond->params.arp_validate && new_value) {
+ bond_register_arp(bond);
+ } else if (bond->params.arp_validate && !new_value) {
+ bond_unregister_arp(bond);
+ }
+
+ bond->params.arp_validate = new_value;
+
+ return count;
+}
+
+static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+
+/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
* MII monitoring. Second, if the ARP timer isn't running, we must
@@ -915,6 +962,11 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
"ARP monitoring. Disabling ARP monitoring...\n",
bond->dev->name);
bond->params.arp_interval = 0;
+ if (bond->params.arp_validate) {
+ bond_unregister_arp(bond);
+ bond->params.arp_validate =
+ BOND_ARP_VALIDATE_NONE;
+ }
/* Kill ARP timer, else it brings bond's link down */
if (bond->mii_timer.function) {
printk(KERN_INFO DRV_NAME
@@ -1094,7 +1146,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b
strlen(slave->dev->name)) == 0) {
old_active = bond->curr_active_slave;
new_active = slave;
- if (new_active && (new_active == old_active)) {
+ if (new_active == old_active) {
/* do nothing */
printk(KERN_INFO DRV_NAME
": %s: %s is already the current active slave.\n",
@@ -1274,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, N
static struct attribute *per_bond_attrs[] = {
&class_device_attr_slaves.attr,
&class_device_attr_mode.attr,
+ &class_device_attr_arp_validate.attr,
&class_device_attr_arp_interval.attr,
&class_device_attr_arp_ip_target.attr,
&class_device_attr_downdelay.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0bdfe2c7145..dc434fb6da8 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.0.3"
-#define DRV_RELDATE "March 23, 2006"
+#define DRV_VERSION "3.1.1"
+#define DRV_RELDATE "September 26, 2006"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -126,6 +126,7 @@ struct bond_params {
int xmit_policy;
int miimon;
int arp_interval;
+ int arp_validate;
int use_carrier;
int updelay;
int downdelay;
@@ -149,8 +150,9 @@ struct slave {
struct net_device *dev; /* first - useful for panic debug */
struct slave *next;
struct slave *prev;
- s16 delay;
+ int delay;
u32 jiffies;
+ u32 last_arp_rx;
s8 link; /* one of BOND_LINK_XXXX */
s8 state; /* one of BOND_STATE_XXXX */
u32 original_flags;
@@ -198,6 +200,7 @@ struct bonding {
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
+ struct packet_type arp_mon_pt;
};
/**
@@ -228,6 +231,25 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
return (struct bonding *)slave->dev->master->priv;
}
+#define BOND_ARP_VALIDATE_NONE 0
+#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
+#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
+#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
+ BOND_ARP_VALIDATE_BACKUP)
+
+extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
+{
+ return bond->params.arp_validate & (1 << slave->state);
+}
+
+extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave)
+{
+ if (slave_do_arp_validate(bond, slave))
+ return slave->last_arp_rx;
+
+ return slave->dev->last_rx;
+}
+
static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
struct bonding *bond = slave->dev->master->priv;
@@ -235,12 +257,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
bond->params.mode != BOND_MODE_ALB)
slave->state = BOND_STATE_BACKUP;
slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ if (slave_do_arp_validate(bond, slave))
+ slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
}
static inline void bond_set_slave_active_flags(struct slave *slave)
{
slave->state = BOND_STATE_ACTIVE;
- slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+ slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP);
}
static inline void bond_set_master_3ad_flags(struct bonding *bond)
@@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
const char *bond_mode_name(int mode);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
+void bond_register_arp(struct bonding *);
+void bond_unregister_arp(struct bonding *);
#endif /* _LINUX_BONDING_H */
diff --git a/drivers/net/bsd_comp.c b/drivers/net/bsd_comp.c
index fb4098ed469..bae1de1e780 100644
--- a/drivers/net/bsd_comp.c
+++ b/drivers/net/bsd_comp.c
@@ -1,5 +1,5 @@
/*
- * Update: The Berkeley copyright was changed, and the change
+ * Update: The Berkeley copyright was changed, and the change
* is retroactive to all "true" BSD software (ie everything
* from UCB as opposed to other peoples code that just carried
* the same license). The new copyright doesn't clash with the
@@ -256,9 +256,9 @@ static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */
db->in_count -= (db->in_count >> 2);
db->bytes_out -= (db->bytes_out >> 2);
}
-
+
db->checkpoint = db->in_count + CHECK_GAP;
-
+
if (db->max_ent >= db->maxmaxcode)
{
/* Reset the dictionary only if the ratio is worse,
@@ -274,7 +274,7 @@ static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */
{
new_ratio /= db->bytes_out;
}
-
+
if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE)
{
bsd_clear (db);
@@ -293,7 +293,7 @@ static int bsd_check (struct bsd_db *db) /* 1=output CLEAR */
static void bsd_comp_stats (void *state, struct compstat *stats)
{
struct bsd_db *db = (struct bsd_db *) state;
-
+
stats->unc_bytes = db->uncomp_bytes;
stats->unc_packets = db->uncomp_count;
stats->comp_bytes = db->comp_bytes;
@@ -325,7 +325,7 @@ static void bsd_reset (void *state)
static void bsd_free (void *state)
{
struct bsd_db *db = state;
-
+
if (!db)
return;
@@ -468,7 +468,7 @@ static int bsd_init (void *state, unsigned char *options,
{
struct bsd_db *db = state;
int indx;
-
+
if ((opt_len != 3) || (options[0] != CI_BSD_COMPRESS) || (options[1] != 3)
|| (BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
|| (BSD_NBITS(options[2]) != db->maxbits)
@@ -500,9 +500,9 @@ static int bsd_init (void *state, unsigned char *options,
if (debug)
#endif
db->debug = 1;
-
+
bsd_reset(db);
-
+
return 1;
}
@@ -660,7 +660,7 @@ static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf,
fcode = BSD_KEY (ent, c);
hval = BSD_HASH (ent, c, hshift);
dictp = dict_ptr (db, hval);
-
+
/* Validate and then check the entry. */
if (dictp->codem1 >= max_ent)
{
@@ -672,7 +672,7 @@ static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf,
ent = dictp->codem1 + 1;
continue; /* found (prefix,suffix) */
}
-
+
/* continue probing until a match or invalid entry */
disp = (hval == 0) ? 1 : hval;
@@ -693,10 +693,10 @@ static int bsd_compress (void *state, unsigned char *rptr, unsigned char *obuf,
ent = dictp->codem1 + 1; /* finally found (prefix,suffix) */
continue;
-
+
nomatch:
OUTPUT(ent); /* output the prefix */
-
+
/* code -> hashtable */
if (max_ent < db->maxmaxcode)
{
@@ -710,7 +710,7 @@ nomatch:
db->n_bits = ++n_bits;
mxcode = MAXCODE (n_bits);
}
-
+
/* Invalidate old hash table entry using
* this code, and then take it over.
*/
@@ -738,7 +738,7 @@ nomatch:
}
ent = c;
}
-
+
OUTPUT(ent); /* output the last code */
db->bytes_out += olen - PPP_HDRLEN - BSD_OVHD;
@@ -760,7 +760,7 @@ nomatch:
{
OUTPUT (CLEAR);
}
-
+
/*
* Pad dribble bits of last code with ones.
* Do not emit a completely useless byte of ones.
@@ -770,7 +770,7 @@ nomatch:
{
PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
}
-
+
/*
* Increase code size if we would have without the packet
* boundary because the decompressor will do so.
@@ -856,7 +856,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
bitno = 32; /* 1st valid bit in accm */
n_bits = db->n_bits;
tgtbitno = 32 - n_bits; /* bitno when we have a code */
-
+
/*
* Save the address/control from the PPP header
* and then get the sequence number.
@@ -869,7 +869,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
ibuf += (PPP_HDRLEN + 2);
ilen = isize - (PPP_HDRLEN + 2);
-
+
/*
* Check the sequence number and give up if it differs from
* the value we're expecting.
@@ -897,7 +897,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
*wptr++ = adrs;
*wptr++ = ctrl;
*wptr++ = 0;
-
+
oldcode = CLEAR;
explen = 3;
@@ -934,7 +934,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
/*
* The dictionary must only be cleared at the end of a packet.
*/
-
+
if (incode == CLEAR)
{
if (ilen > 0)
@@ -945,7 +945,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
}
return DECOMP_FATALERROR; /* probably a bug */
}
-
+
bsd_clear(db);
break;
}
@@ -962,7 +962,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
}
return DECOMP_FATALERROR; /* probably a bug */
}
-
+
/* Special case for KwKwK string. */
if (incode > max_ent)
{
@@ -974,7 +974,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
finchar = incode;
extra = 0;
}
-
+
codelen = *(lens_ptr (db, finchar));
explen += codelen + extra;
if (explen > osize)
@@ -989,7 +989,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
}
return DECOMP_FATALERROR;
}
-
+
/*
* Decode this code and install it in the decompressed buffer.
*/
@@ -999,7 +999,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
while (finchar > LAST)
{
struct bsd_dict *dictp2 = dict_ptr (db, finchar);
-
+
dictp = dict_ptr (db, dictp2->cptr);
#ifdef DEBUG
if (--codelen <= 0 || dictp->codem1 != finchar-1)
@@ -1029,7 +1029,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
finchar = dictp->f.hs.prefix;
}
*--p = finchar;
-
+
#ifdef DEBUG
if (--codelen != 0)
{
@@ -1037,12 +1037,12 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
db->unit, codelen, incode, max_ent);
}
#endif
-
+
if (extra) /* the KwKwK case again */
{
*wptr++ = finchar;
}
-
+
/*
* If not first code in a packet, and
* if not out of code space, then allocate a new code.
@@ -1057,11 +1057,11 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
unsigned short *lens1, *lens2;
unsigned long fcode;
int hval, disp, indx;
-
+
fcode = BSD_KEY(oldcode,finchar);
hval = BSD_HASH(oldcode,finchar,db->hshift);
dictp = dict_ptr (db, hval);
-
+
/* look for a free hash table entry */
if (dictp->codem1 < max_ent)
{
@@ -1077,7 +1077,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
}
while (dictp->codem1 < max_ent);
}
-
+
/*
* Invalidate previous hash table entry
* assigned this code, and then take it over
@@ -1101,7 +1101,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
lens1 = lens_ptr (db, max_ent);
lens2 = lens_ptr (db, oldcode);
*lens1 = *lens2 + 1;
-
+
/* Expand code size if needed. */
if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
{
@@ -1127,7 +1127,7 @@ static int bsd_decompress (void *state, unsigned char *ibuf, int isize,
}
return explen;
}
-
+
/*************************************************************
* Table of addresses for the BSD compression module
*************************************************************/
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 565a54f1d06..7694365092f 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -43,7 +43,7 @@
* -- on page reclamation, the driver swaps the page with a spare page.
* if that page is still in use, it frees its reference to that page,
* and allocates a new page for use. otherwise, it just recycles the
- * the page.
+ * the page.
*
* NOTE: cassini can parse the header. however, it's not worth it
* as long as the network stack requires a header copy.
@@ -60,13 +60,12 @@
* interrupts, but the INT# assignment needs to be set up properly by
* the BIOS and conveyed to the driver. PCI BIOSes don't know how to do
* that. also, the two descriptor rings are designed to distinguish between
- * encrypted and non-encrypted packets, but we use them for buffering
+ * encrypted and non-encrypted packets, but we use them for buffering
* instead.
*
- * by default, the selective clear mask is set up to process rx packets.
+ * by default, the selective clear mask is set up to process rx packets.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -113,7 +112,7 @@
#endif
/* select which firmware to use */
-#define USE_HP_WORKAROUND
+#define USE_HP_WORKAROUND
#define HP_WORKAROUND_DEFAULT /* select which firmware to use as default */
#define CAS_HP_ALT_FIRMWARE cas_prog_null /* alternate firmware */
@@ -169,7 +168,7 @@
#define STOP_TRIES_PHY 1000
#define STOP_TRIES 5000
-/* specify a minimum frame size to deal with some fifo issues
+/* specify a minimum frame size to deal with some fifo issues
* max mtu == 2 * page size - ethernet header - 64 - swivel =
* 2 * page_size - 0x50
*/
@@ -208,7 +207,7 @@ MODULE_PARM_DESC(link_mode, "default link mode");
* being confused and never showing a link status of "up."
*/
#define DEFAULT_LINKDOWN_TIMEOUT 5
-/*
+/*
* Value in seconds, for user input.
*/
static int linkdown_timeout = DEFAULT_LINKDOWN_TIMEOUT;
@@ -250,7 +249,7 @@ static inline void cas_lock_tx(struct cas *cp)
{
int i;
- for (i = 0; i < N_TX_RINGS; i++)
+ for (i = 0; i < N_TX_RINGS; i++)
spin_lock(&cp->tx_lock[i]);
}
@@ -279,8 +278,8 @@ static inline void cas_unlock_tx(struct cas *cp)
{
int i;
- for (i = N_TX_RINGS; i > 0; i--)
- spin_unlock(&cp->tx_lock[i - 1]);
+ for (i = N_TX_RINGS; i > 0; i--)
+ spin_unlock(&cp->tx_lock[i - 1]);
}
static inline void cas_unlock_all(struct cas *cp)
@@ -317,7 +316,7 @@ static void cas_disable_irq(struct cas *cp, const int ring)
#ifdef USE_PCI_INTD
case 3:
#endif
- writel(INTRN_MASK_CLEAR_ALL | INTRN_MASK_RX_EN,
+ writel(INTRN_MASK_CLEAR_ALL | INTRN_MASK_RX_EN,
cp->regs + REG_PLUS_INTRN_MASK(ring));
break;
#endif
@@ -416,7 +415,7 @@ static inline void cas_entropy_reset(struct cas *cp)
if ((cp->cas_flags & CAS_FLAG_ENTROPY_DEV) == 0)
return;
- writel(BIM_LOCAL_DEV_PAD | BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_EXT,
+ writel(BIM_LOCAL_DEV_PAD | BIM_LOCAL_DEV_PROM | BIM_LOCAL_DEV_EXT,
cp->regs + REG_BIM_LOCAL_DEV_EN);
writeb(ENTROPY_RESET_STC_MODE, cp->regs + REG_ENTROPY_RESET);
writeb(0x55, cp->regs + REG_ENTROPY_RAND_REG);
@@ -427,7 +426,7 @@ static inline void cas_entropy_reset(struct cas *cp)
#endif
}
-/* access to the phy. the following assumes that we've initialized the MIF to
+/* access to the phy. the following assumes that we've initialized the MIF to
* be in frame rather than bit-bang mode
*/
static u16 cas_phy_read(struct cas *cp, int reg)
@@ -440,7 +439,7 @@ static u16 cas_phy_read(struct cas *cp, int reg)
cmd |= CAS_BASE(MIF_FRAME_REG_ADDR, reg);
cmd |= MIF_FRAME_TURN_AROUND_MSB;
writel(cmd, cp->regs + REG_MIF_FRAME);
-
+
/* poll for completion */
while (limit-- > 0) {
udelay(10);
@@ -462,7 +461,7 @@ static int cas_phy_write(struct cas *cp, int reg, u16 val)
cmd |= MIF_FRAME_TURN_AROUND_MSB;
cmd |= val & MIF_FRAME_DATA_MASK;
writel(cmd, cp->regs + REG_MIF_FRAME);
-
+
/* poll for completion */
while (limit-- > 0) {
udelay(10);
@@ -475,7 +474,7 @@ static int cas_phy_write(struct cas *cp, int reg, u16 val)
static void cas_phy_powerup(struct cas *cp)
{
- u16 ctl = cas_phy_read(cp, MII_BMCR);
+ u16 ctl = cas_phy_read(cp, MII_BMCR);
if ((ctl & BMCR_PDOWN) == 0)
return;
@@ -485,7 +484,7 @@ static void cas_phy_powerup(struct cas *cp)
static void cas_phy_powerdown(struct cas *cp)
{
- u16 ctl = cas_phy_read(cp, MII_BMCR);
+ u16 ctl = cas_phy_read(cp, MII_BMCR);
if (ctl & BMCR_PDOWN)
return;
@@ -496,7 +495,7 @@ static void cas_phy_powerdown(struct cas *cp)
/* cp->lock held. note: the last put_page will free the buffer */
static int cas_page_free(struct cas *cp, cas_page_t *page)
{
- pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
+ pci_unmap_page(cp->pdev, page->dma_addr, cp->page_size,
PCI_DMA_FROMDEVICE);
cas_buffer_dec(page);
__free_pages(page->buffer, cp->page_order);
@@ -508,7 +507,7 @@ static int cas_page_free(struct cas *cp, cas_page_t *page)
#define RX_USED_ADD(x, y) ((x)->used += (y))
#define RX_USED_SET(x, y) ((x)->used = (y))
#else
-#define RX_USED_ADD(x, y)
+#define RX_USED_ADD(x, y)
#define RX_USED_SET(x, y)
#endif
@@ -603,7 +602,7 @@ static void cas_spare_recover(struct cas *cp, const gfp_t flags)
list_splice(&cp->rx_inuse_list, &list);
INIT_LIST_HEAD(&cp->rx_inuse_list);
spin_unlock(&cp->rx_inuse_lock);
-
+
list_for_each_safe(elem, tmp, &list) {
cas_page_t *page = list_entry(elem, cas_page_t, list);
@@ -628,7 +627,7 @@ static void cas_spare_recover(struct cas *cp, const gfp_t flags)
list_splice(&list, &cp->rx_inuse_list);
spin_unlock(&cp->rx_inuse_lock);
}
-
+
spin_lock(&cp->rx_spare_lock);
needed = cp->rx_spares_needed;
spin_unlock(&cp->rx_spare_lock);
@@ -640,7 +639,7 @@ static void cas_spare_recover(struct cas *cp, const gfp_t flags)
i = 0;
while (i < needed) {
cas_page_t *spare = cas_page_alloc(cp, flags);
- if (!spare)
+ if (!spare)
break;
list_add(&spare->list, &list);
i++;
@@ -696,12 +695,12 @@ static cas_page_t *cas_page_dequeue(struct cas *cp)
static void cas_mif_poll(struct cas *cp, const int enable)
{
u32 cfg;
-
- cfg = readl(cp->regs + REG_MIF_CFG);
+
+ cfg = readl(cp->regs + REG_MIF_CFG);
cfg &= (MIF_CFG_MDIO_0 | MIF_CFG_MDIO_1);
if (cp->phy_type & CAS_PHY_MII_MDIO1)
- cfg |= MIF_CFG_PHY_SELECT;
+ cfg |= MIF_CFG_PHY_SELECT;
/* poll and interrupt on link status change. */
if (enable) {
@@ -709,8 +708,8 @@ static void cas_mif_poll(struct cas *cp, const int enable)
cfg |= CAS_BASE(MIF_CFG_POLL_REG, MII_BMSR);
cfg |= CAS_BASE(MIF_CFG_POLL_PHY, cp->phy_addr);
}
- writel((enable) ? ~(BMSR_LSTATUS | BMSR_ANEGCOMPLETE) : 0xFFFF,
- cp->regs + REG_MIF_MASK);
+ writel((enable) ? ~(BMSR_LSTATUS | BMSR_ANEGCOMPLETE) : 0xFFFF,
+ cp->regs + REG_MIF_MASK);
writel(cfg, cp->regs + REG_MIF_CFG);
}
@@ -760,7 +759,7 @@ start_aneg:
/*
* WTZ: If the old state was link_up, we turn off the carrier
* to replicate everything we do elsewhere on a link-down
- * event when we were already in a link-up state..
+ * event when we were already in a link-up state..
*/
if (oldstate == link_up)
netif_carrier_off(cp->dev);
@@ -768,7 +767,7 @@ start_aneg:
/*
* WTZ: This branch will simply schedule a full reset after
* we explicitly changed link modes in an ioctl. See if this
- * fixes the link-problems we were having for forced mode.
+ * fixes the link-problems we were having for forced mode.
*/
atomic_inc(&cp->reset_task_pending);
atomic_inc(&cp->reset_task_pending_all);
@@ -796,7 +795,7 @@ start_aneg:
} else {
cas_mif_poll(cp, 0);
ctl = cas_phy_read(cp, MII_BMCR);
- ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
+ ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 |
CAS_BMCR_SPEED1000 | BMCR_ANENABLE);
ctl |= cp->link_cntl;
if (ctl & BMCR_ANENABLE) {
@@ -819,7 +818,7 @@ static int cas_reset_mii_phy(struct cas *cp)
{
int limit = STOP_TRIES_PHY;
u16 val;
-
+
cas_phy_write(cp, MII_BMCR, BMCR_RESET);
udelay(100);
while (limit--) {
@@ -902,17 +901,17 @@ static void cas_phy_init(struct cas *cp)
val = cas_phy_read(cp, BROADCOM_MII_REG4);
if (val & 0x0080) {
/* link workaround */
- cas_phy_write(cp, BROADCOM_MII_REG4,
+ cas_phy_write(cp, BROADCOM_MII_REG4,
val & ~0x0080);
}
-
+
} else if (cp->cas_flags & CAS_FLAG_SATURN) {
- writel((cp->phy_type & CAS_PHY_MII_MDIO0) ?
- SATURN_PCFG_FSI : 0x0,
+ writel((cp->phy_type & CAS_PHY_MII_MDIO0) ?
+ SATURN_PCFG_FSI : 0x0,
cp->regs + REG_SATURN_PCFG);
/* load firmware to address 10Mbps auto-negotiation
- * issue. NOTE: this will need to be changed if the
+ * issue. NOTE: this will need to be changed if the
* default firmware gets fixed.
*/
if (PHY_NS_DP83065 == cp->phy_id) {
@@ -931,9 +930,9 @@ static void cas_phy_init(struct cas *cp)
cas_phy_read(cp, MII_ADVERTISE) |
(ADVERTISE_10HALF | ADVERTISE_10FULL |
ADVERTISE_100HALF | ADVERTISE_100FULL |
- CAS_ADVERTISE_PAUSE |
+ CAS_ADVERTISE_PAUSE |
CAS_ADVERTISE_ASYM_PAUSE));
-
+
if (cp->cas_flags & CAS_FLAG_1000MB_CAP) {
/* make sure that we don't advertise half
* duplex to avoid a chip issue
@@ -964,7 +963,7 @@ static void cas_phy_init(struct cas *cp)
limit = STOP_TRIES;
while (limit-- > 0) {
udelay(10);
- if ((readl(cp->regs + REG_PCS_MII_CTRL) &
+ if ((readl(cp->regs + REG_PCS_MII_CTRL) &
PCS_MII_RESET) == 0)
break;
}
@@ -981,7 +980,7 @@ static void cas_phy_init(struct cas *cp)
/* Advertise all capabilities except half-duplex. */
val = readl(cp->regs + REG_PCS_MII_ADVERT);
val &= ~PCS_MII_ADVERT_HD;
- val |= (PCS_MII_ADVERT_FD | PCS_MII_ADVERT_SYM_PAUSE |
+ val |= (PCS_MII_ADVERT_FD | PCS_MII_ADVERT_SYM_PAUSE |
PCS_MII_ADVERT_ASYM_PAUSE);
writel(val, cp->regs + REG_PCS_MII_ADVERT);
@@ -1015,7 +1014,7 @@ static int cas_pcs_link_check(struct cas *cp)
PCS_MII_STATUS_REMOTE_FAULT)) ==
(PCS_MII_STATUS_AUTONEG_COMP | PCS_MII_STATUS_REMOTE_FAULT)) {
if (netif_msg_link(cp))
- printk(KERN_INFO "%s: PCS RemoteFault\n",
+ printk(KERN_INFO "%s: PCS RemoteFault\n",
cp->dev->name);
}
@@ -1034,7 +1033,7 @@ static int cas_pcs_link_check(struct cas *cp)
if (cp->opened) {
cp->lstate = link_up;
cp->link_transition = LINK_TRANSITION_LINK_UP;
-
+
cas_set_link_modes(cp);
netif_carrier_on(cp->dev);
}
@@ -1045,8 +1044,8 @@ static int cas_pcs_link_check(struct cas *cp)
cp->link_transition != LINK_TRANSITION_REQUESTED_RESET &&
!cp->link_transition_jiffies_valid) {
/*
- * force a reset, as a workaround for the
- * link-failure problem. May want to move this to a
+ * force a reset, as a workaround for the
+ * link-failure problem. May want to move this to a
* point a bit earlier in the sequence. If we had
* generated a reset a short time ago, we'll wait for
* the link timer to check the status until a
@@ -1104,17 +1103,17 @@ static int cas_pcs_link_check(struct cas *cp)
return retval;
}
-static int cas_pcs_interrupt(struct net_device *dev,
+static int cas_pcs_interrupt(struct net_device *dev,
struct cas *cp, u32 status)
{
u32 stat = readl(cp->regs + REG_PCS_INTR_STATUS);
- if ((stat & PCS_INTR_STATUS_LINK_CHANGE) == 0)
+ if ((stat & PCS_INTR_STATUS_LINK_CHANGE) == 0)
return 0;
return cas_pcs_link_check(cp);
}
-static int cas_txmac_interrupt(struct net_device *dev,
+static int cas_txmac_interrupt(struct net_device *dev,
struct cas *cp, u32 status)
{
u32 txmac_stat = readl(cp->regs + REG_MAC_TX_STATUS);
@@ -1169,7 +1168,7 @@ static int cas_txmac_interrupt(struct net_device *dev,
return 0;
}
-static void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
+static void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
{
cas_hp_inst_t *inst;
u32 val;
@@ -1204,12 +1203,12 @@ static void cas_load_firmware(struct cas *cp, cas_hp_inst_t *firmware)
static void cas_init_rx_dma(struct cas *cp)
{
- u64 desc_dma = cp->block_dvma;
+ u64 desc_dma = cp->block_dvma;
u32 val;
int i, size;
/* rx free descriptors */
- val = CAS_BASE(RX_CFG_SWIVEL, RX_SWIVEL_OFF_VAL);
+ val = CAS_BASE(RX_CFG_SWIVEL, RX_SWIVEL_OFF_VAL);
val |= CAS_BASE(RX_CFG_DESC_RING, RX_DESC_RINGN_INDEX(0));
val |= CAS_BASE(RX_CFG_COMP_RING, RX_COMP_RINGN_INDEX(0));
if ((N_RX_DESC_RINGS > 1) &&
@@ -1217,27 +1216,27 @@ static void cas_init_rx_dma(struct cas *cp)
val |= CAS_BASE(RX_CFG_DESC_RING1, RX_DESC_RINGN_INDEX(1));
writel(val, cp->regs + REG_RX_CFG);
- val = (unsigned long) cp->init_rxds[0] -
+ val = (unsigned long) cp->init_rxds[0] -
(unsigned long) cp->init_block;
writel((desc_dma + val) >> 32, cp->regs + REG_RX_DB_HI);
writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_DB_LOW);
writel(RX_DESC_RINGN_SIZE(0) - 4, cp->regs + REG_RX_KICK);
if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
- /* rx desc 2 is for IPSEC packets. however,
+ /* rx desc 2 is for IPSEC packets. however,
* we don't it that for that purpose.
*/
- val = (unsigned long) cp->init_rxds[1] -
+ val = (unsigned long) cp->init_rxds[1] -
(unsigned long) cp->init_block;
writel((desc_dma + val) >> 32, cp->regs + REG_PLUS_RX_DB1_HI);
- writel((desc_dma + val) & 0xffffffff, cp->regs +
+ writel((desc_dma + val) & 0xffffffff, cp->regs +
REG_PLUS_RX_DB1_LOW);
- writel(RX_DESC_RINGN_SIZE(1) - 4, cp->regs +
+ writel(RX_DESC_RINGN_SIZE(1) - 4, cp->regs +
REG_PLUS_RX_KICK1);
}
-
+
/* rx completion registers */
- val = (unsigned long) cp->init_rxcs[0] -
+ val = (unsigned long) cp->init_rxcs[0] -
(unsigned long) cp->init_block;
writel((desc_dma + val) >> 32, cp->regs + REG_RX_CB_HI);
writel((desc_dma + val) & 0xffffffff, cp->regs + REG_RX_CB_LOW);
@@ -1245,11 +1244,11 @@ static void cas_init_rx_dma(struct cas *cp)
if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
/* rx comp 2-4 */
for (i = 1; i < MAX_RX_COMP_RINGS; i++) {
- val = (unsigned long) cp->init_rxcs[i] -
+ val = (unsigned long) cp->init_rxcs[i] -
(unsigned long) cp->init_block;
- writel((desc_dma + val) >> 32, cp->regs +
+ writel((desc_dma + val) >> 32, cp->regs +
REG_PLUS_RX_CBN_HI(i));
- writel((desc_dma + val) & 0xffffffff, cp->regs +
+ writel((desc_dma + val) & 0xffffffff, cp->regs +
REG_PLUS_RX_CBN_LOW(i));
}
}
@@ -1266,21 +1265,21 @@ static void cas_init_rx_dma(struct cas *cp)
/* 2 is different from 3 and 4 */
if (N_RX_COMP_RINGS > 1)
- writel(INTR_RX_DONE_ALT | INTR_RX_BUF_UNAVAIL_1,
+ writel(INTR_RX_DONE_ALT | INTR_RX_BUF_UNAVAIL_1,
cp->regs + REG_PLUS_ALIASN_CLEAR(1));
- for (i = 2; i < N_RX_COMP_RINGS; i++)
- writel(INTR_RX_DONE_ALT,
+ for (i = 2; i < N_RX_COMP_RINGS; i++)
+ writel(INTR_RX_DONE_ALT,
cp->regs + REG_PLUS_ALIASN_CLEAR(i));
}
/* set up pause thresholds */
val = CAS_BASE(RX_PAUSE_THRESH_OFF,
cp->rx_pause_off / RX_PAUSE_THRESH_QUANTUM);
- val |= CAS_BASE(RX_PAUSE_THRESH_ON,
+ val |= CAS_BASE(RX_PAUSE_THRESH_ON,
cp->rx_pause_on / RX_PAUSE_THRESH_QUANTUM);
writel(val, cp->regs + REG_RX_PAUSE_THRESH);
-
+
/* zero out dma reassembly buffers */
for (i = 0; i < 64; i++) {
writel(i, cp->regs + REG_RX_TABLE_ADDR);
@@ -1319,7 +1318,7 @@ static void cas_init_rx_dma(struct cas *cp)
* this should be tunable.
*/
writel(0x0, cp->regs + REG_RX_RED);
-
+
/* receive page sizes. default == 2K (0x800) */
val = 0;
if (cp->page_size == 0x1000)
@@ -1328,7 +1327,7 @@ static void cas_init_rx_dma(struct cas *cp)
val = 0x2;
else if (cp->page_size == 0x4000)
val = 0x3;
-
+
/* round mtu + offset. constrain to page size. */
size = cp->dev->mtu + 64;
if (size > cp->page_size)
@@ -1345,11 +1344,11 @@ static void cas_init_rx_dma(struct cas *cp)
cp->mtu_stride = 1 << (i + 10);
val = CAS_BASE(RX_PAGE_SIZE, val);
- val |= CAS_BASE(RX_PAGE_SIZE_MTU_STRIDE, i);
+ val |= CAS_BASE(RX_PAGE_SIZE_MTU_STRIDE, i);
val |= CAS_BASE(RX_PAGE_SIZE_MTU_COUNT, cp->page_size >> (i + 10));
val |= CAS_BASE(RX_PAGE_SIZE_MTU_OFF, 0x1);
writel(val, cp->regs + REG_RX_PAGE_SIZE);
-
+
/* enable the header parser if desired */
if (CAS_HP_FIRMWARE == cas_prog_null)
return;
@@ -1363,7 +1362,7 @@ static void cas_init_rx_dma(struct cas *cp)
static inline void cas_rxc_init(struct cas_rx_comp *rxc)
{
memset(rxc, 0, sizeof(*rxc));
- rxc->word4 = cpu_to_le64(RX_COMP4_ZERO);
+ rxc->word4 = cpu_to_le64(RX_COMP4_ZERO);
}
/* NOTE: we use the ENC RX DESC ring for spares. the rx_page[0,1]
@@ -1386,9 +1385,9 @@ static inline cas_page_t *cas_page_spare(struct cas *cp, const int index)
}
return new;
}
-
+
/* this needs to be changed if we actually use the ENC RX DESC ring */
-static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
+static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
const int index)
{
cas_page_t **page0 = cp->rx_pages[0];
@@ -1401,7 +1400,7 @@ static cas_page_t *cas_page_swap(struct cas *cp, const int ring,
page1[index] = page0[index];
page0[index] = new;
}
- }
+ }
RX_USED_SET(page0[index], 0);
return page0[index];
}
@@ -1425,11 +1424,11 @@ static void cas_clean_rxds(struct cas *cp)
for (i = 0; i < size; i++) {
cas_page_t *page = cas_page_swap(cp, 0, i);
rxd[i].buffer = cpu_to_le64(page->dma_addr);
- rxd[i].index = cpu_to_le64(CAS_BASE(RX_INDEX_NUM, i) |
+ rxd[i].index = cpu_to_le64(CAS_BASE(RX_INDEX_NUM, i) |
CAS_BASE(RX_INDEX_RING, 0));
}
- cp->rx_old[0] = RX_DESC_RINGN_SIZE(0) - 4;
+ cp->rx_old[0] = RX_DESC_RINGN_SIZE(0) - 4;
cp->rx_last[0] = 0;
cp->cas_flags &= ~CAS_FLAG_RXD_POST(0);
}
@@ -1534,7 +1533,7 @@ static int cas_rxmac_interrupt(struct net_device *dev, struct cas *cp,
/* these are all rollovers */
spin_lock(&cp->stat_lock[0]);
- if (stat & MAC_RX_ALIGN_ERR)
+ if (stat & MAC_RX_ALIGN_ERR)
cp->net_stats[0].rx_frame_errors += 0x10000;
if (stat & MAC_RX_CRC_ERR)
@@ -1580,12 +1579,12 @@ static int cas_mac_interrupt(struct net_device *dev, struct cas *cp,
return 0;
}
-
+
/* Must be invoked under cp->lock. */
static inline int cas_mdio_link_not_up(struct cas *cp)
{
u16 val;
-
+
switch (cp->lstate) {
case link_force_ret:
if (netif_msg_link(cp))
@@ -1596,7 +1595,7 @@ static inline int cas_mdio_link_not_up(struct cas *cp)
cp->lstate = link_force_ok;
cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
break;
-
+
case link_aneg:
val = cas_phy_read(cp, MII_BMCR);
@@ -1605,7 +1604,7 @@ static inline int cas_mdio_link_not_up(struct cas *cp)
*/
val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
val |= BMCR_FULLDPLX;
- val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
+ val |= (cp->cas_flags & CAS_FLAG_1000MB_CAP) ?
CAS_BMCR_SPEED1000 : BMCR_SPEED100;
cas_phy_write(cp, MII_BMCR, val);
cp->timer_ticks = 5;
@@ -1647,11 +1646,11 @@ static int cas_mii_link_check(struct cas *cp, const u16 bmsr)
if (bmsr & BMSR_LSTATUS) {
/* Ok, here we got a link. If we had it due to a forced
- * fallback, and we were configured for autoneg, we
+ * fallback, and we were configured for autoneg, we
* retry a short autoneg pass. If you know your hub is
* broken, use ethtool ;)
*/
- if ((cp->lstate == link_force_try) &&
+ if ((cp->lstate == link_force_try) &&
(cp->link_cntl & BMCR_ANENABLE)) {
cp->lstate = link_force_ret;
cp->link_transition = LINK_TRANSITION_LINK_CONFIG;
@@ -1691,10 +1690,10 @@ static int cas_mii_link_check(struct cas *cp, const u16 bmsr)
printk(KERN_INFO "%s: Link down\n",
cp->dev->name);
restart = 1;
-
+
} else if (++cp->timer_ticks > 10)
cas_mdio_link_not_up(cp);
-
+
return restart;
}
@@ -1909,7 +1908,7 @@ static inline void cas_tx_ringN(struct cas *cp, int ring, int limit)
skbs[entry] = NULL;
cp->tx_tiny_use[ring][entry].nbufs = 0;
-
+
for (frag = 0; frag <= skb_shinfo(skb)->nr_frags; frag++) {
struct cas_tx_desc *txd = txds + entry;
@@ -1924,7 +1923,7 @@ static inline void cas_tx_ringN(struct cas *cp, int ring, int limit)
if (cp->tx_tiny_use[ring][entry].used) {
cp->tx_tiny_use[ring][entry].used = 0;
entry = TX_DESC_NEXT(ring, entry);
- }
+ }
}
spin_lock(&cp->stat_lock[ring]);
@@ -1965,14 +1964,14 @@ static void cas_tx(struct net_device *dev, struct cas *cp,
#else
limit = readl(cp->regs + REG_TX_COMPN(ring));
#endif
- if (cp->tx_old[ring] != limit)
+ if (cp->tx_old[ring] != limit)
cas_tx_ringN(cp, ring, limit);
}
}
-static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
- int entry, const u64 *words,
+static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
+ int entry, const u64 *words,
struct sk_buff **skbref)
{
int dlen, hlen, len, i, alloclen;
@@ -1980,19 +1979,19 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
struct cas_page *page;
struct sk_buff *skb;
void *addr, *crcaddr;
- char *p;
+ char *p;
hlen = CAS_VAL(RX_COMP2_HDR_SIZE, words[1]);
dlen = CAS_VAL(RX_COMP1_DATA_SIZE, words[0]);
len = hlen + dlen;
- if (RX_COPY_ALWAYS || (words[2] & RX_COMP3_SMALL_PKT))
+ if (RX_COPY_ALWAYS || (words[2] & RX_COMP3_SMALL_PKT))
alloclen = len;
- else
+ else
alloclen = max(hlen, RX_COPY_MIN);
skb = dev_alloc_skb(alloclen + swivel + cp->crc_size);
- if (skb == NULL)
+ if (skb == NULL)
return -1;
*skbref = skb;
@@ -2004,7 +2003,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
if (hlen) { /* always copy header pages */
i = CAS_VAL(RX_COMP2_HDR_INDEX, words[1]);
page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
- off = CAS_VAL(RX_COMP2_HDR_OFF, words[1]) * 0x100 +
+ off = CAS_VAL(RX_COMP2_HDR_OFF, words[1]) * 0x100 +
swivel;
i = hlen;
@@ -2020,7 +2019,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
RX_USED_ADD(page, 0x100);
p += hlen;
swivel = 0;
- }
+ }
if (alloclen < (hlen + dlen)) {
@@ -2071,7 +2070,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
frag->page = page->buffer;
frag->page_offset = off;
frag->size = hlen - swivel;
-
+
/* any more data? */
if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
hlen = dlen;
@@ -2079,8 +2078,8 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
- pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
- hlen + cp->crc_size,
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
+ hlen + cp->crc_size,
PCI_DMA_FROMDEVICE);
pci_dma_sync_single_for_device(cp->pdev, page->dma_addr,
hlen + cp->crc_size,
@@ -2088,7 +2087,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
skb_shinfo(skb)->nr_frags++;
skb->data_len += hlen;
- skb->len += hlen;
+ skb->len += hlen;
frag++;
get_page(page->buffer);
@@ -2135,14 +2134,14 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
RX_USED_ADD(page, cp->mtu_stride);
else
RX_USED_ADD(page, i);
-
+
/* any more data? */
if ((words[0] & RX_COMP1_SPLIT_PKT) && ((dlen -= hlen) > 0)) {
p += hlen;
i = CAS_VAL(RX_COMP2_NEXT_INDEX, words[1]);
page = cp->rx_pages[CAS_VAL(RX_INDEX_RING, i)][CAS_VAL(RX_INDEX_NUM, i)];
- pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
- dlen + cp->crc_size,
+ pci_dma_sync_single_for_cpu(cp->pdev, page->dma_addr,
+ dlen + cp->crc_size,
PCI_DMA_FROMDEVICE);
addr = cas_page_map(page->buffer);
memcpy(p, addr, dlen + cp->crc_size);
@@ -2150,7 +2149,7 @@ static int cas_rx_process_pkt(struct cas *cp, struct cas_rx_comp *rxc,
dlen + cp->crc_size,
PCI_DMA_FROMDEVICE);
cas_page_unmap(addr);
- RX_USED_ADD(page, dlen + cp->crc_size);
+ RX_USED_ADD(page, dlen + cp->crc_size);
}
end_copy_pkt:
if (cp->crc_size) {
@@ -2168,14 +2167,14 @@ end_copy_pkt:
cas_page_unmap(addr);
}
skb->csum = ntohs(i ^ 0xffff);
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
skb->protocol = eth_type_trans(skb, cp->dev);
return len;
}
/* we can handle up to 64 rx flows at a time. we do the same thing
- * as nonreassm except that we batch up the buffers.
+ * as nonreassm except that we batch up the buffers.
* NOTE: we currently just treat each flow as a bunch of packets that
* we pass up. a better way would be to coalesce the packets
* into a jumbo packet. to do that, we need to do the following:
@@ -2185,7 +2184,7 @@ end_copy_pkt:
* data length and merge the checksums.
* 3) on flow release, fix up the header.
* 4) make sure the higher layer doesn't care.
- * because packets get coalesced, we shouldn't run into fragment count
+ * because packets get coalesced, we shouldn't run into fragment count
* issues.
*/
static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words,
@@ -2193,8 +2192,8 @@ static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words,
{
int flowid = CAS_VAL(RX_COMP3_FLOWID, words[2]) & (N_RX_FLOWS - 1);
struct sk_buff_head *flow = &cp->rx_flows[flowid];
-
- /* this is protected at a higher layer, so no need to
+
+ /* this is protected at a higher layer, so no need to
* do any additional locking here. stick the buffer
* at the end.
*/
@@ -2219,19 +2218,19 @@ static void cas_post_page(struct cas *cp, const int ring, const int index)
new = cas_page_swap(cp, ring, index);
cp->init_rxds[ring][entry].buffer = cpu_to_le64(new->dma_addr);
cp->init_rxds[ring][entry].index =
- cpu_to_le64(CAS_BASE(RX_INDEX_NUM, index) |
+ cpu_to_le64(CAS_BASE(RX_INDEX_NUM, index) |
CAS_BASE(RX_INDEX_RING, ring));
entry = RX_DESC_ENTRY(ring, entry + 1);
cp->rx_old[ring] = entry;
-
+
if (entry % 4)
return;
if (ring == 0)
writel(entry, cp->regs + REG_RX_KICK);
else if ((N_RX_DESC_RINGS > 1) &&
- (cp->cas_flags & CAS_FLAG_REG_PLUS))
+ (cp->cas_flags & CAS_FLAG_REG_PLUS))
writel(entry, cp->regs + REG_PLUS_RX_KICK1);
}
@@ -2250,7 +2249,7 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
cp->dev->name, ring, entry);
cluster = -1;
- count = entry & 0x3;
+ count = entry & 0x3;
last = RX_DESC_ENTRY(ring, num ? entry + num - 4: entry - 4);
released = 0;
while (entry != last) {
@@ -2258,12 +2257,12 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
if (cas_buffer_count(page[entry]) > 1) {
cas_page_t *new = cas_page_dequeue(cp);
if (!new) {
- /* let the timer know that we need to
+ /* let the timer know that we need to
* do this again
*/
cp->cas_flags |= CAS_FLAG_RXD_POST(ring);
if (!timer_pending(&cp->link_timer))
- mod_timer(&cp->link_timer, jiffies +
+ mod_timer(&cp->link_timer, jiffies +
CAS_LINK_FAST_TIMEOUT);
cp->rx_old[ring] = entry;
cp->rx_last[ring] = num ? num - released : 0;
@@ -2272,10 +2271,10 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
spin_lock(&cp->rx_inuse_lock);
list_add(&page[entry]->list, &cp->rx_inuse_list);
spin_unlock(&cp->rx_inuse_lock);
- cp->init_rxds[ring][entry].buffer =
+ cp->init_rxds[ring][entry].buffer =
cpu_to_le64(new->dma_addr);
page[entry] = new;
-
+
}
if (++count == 4) {
@@ -2287,13 +2286,13 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
}
cp->rx_old[ring] = entry;
- if (cluster < 0)
+ if (cluster < 0)
return 0;
if (ring == 0)
writel(cluster, cp->regs + REG_RX_KICK);
else if ((N_RX_DESC_RINGS > 1) &&
- (cp->cas_flags & CAS_FLAG_REG_PLUS))
+ (cp->cas_flags & CAS_FLAG_REG_PLUS))
writel(cluster, cp->regs + REG_PLUS_RX_KICK1);
return 0;
}
@@ -2302,14 +2301,14 @@ static int cas_post_rxds_ringN(struct cas *cp, int ring, int num)
/* process a completion ring. packets are set up in three basic ways:
* small packets: should be copied header + data in single buffer.
* large packets: header and data in a single buffer.
- * split packets: header in a separate buffer from data.
+ * split packets: header in a separate buffer from data.
* data may be in multiple pages. data may be > 256
- * bytes but in a single page.
+ * bytes but in a single page.
*
* NOTE: RX page posting is done in this routine as well. while there's
* the capability of using multiple RX completion rings, it isn't
* really worthwhile due to the fact that the page posting will
- * force serialization on the single descriptor ring.
+ * force serialization on the single descriptor ring.
*/
static int cas_rx_ringN(struct cas *cp, int ring, int budget)
{
@@ -2320,7 +2319,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
if (netif_msg_intr(cp))
printk(KERN_DEBUG "%s: rx[%d] interrupt, done: %d/%d\n",
cp->dev->name, ring,
- readl(cp->regs + REG_RX_COMP_HEAD),
+ readl(cp->regs + REG_RX_COMP_HEAD),
cp->rx_new[ring]);
entry = cp->rx_new[ring];
@@ -2376,7 +2375,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
*/
if (RX_DONT_BATCH || (type == 0x2)) {
/* non-reassm: these always get released */
- cas_skb_release(skb);
+ cas_skb_release(skb);
} else {
cas_rx_flow_pkt(cp, words, skb);
}
@@ -2397,7 +2396,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
i = CAS_VAL(RX_INDEX_NUM, i);
cas_post_page(cp, dring, i);
}
-
+
if (words[0] & RX_COMP1_RELEASE_DATA) {
i = CAS_VAL(RX_COMP1_DATA_INDEX, words[0]);
dring = CAS_VAL(RX_INDEX_RING, i);
@@ -2413,7 +2412,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget)
}
/* skip to the next entry */
- entry = RX_COMP_ENTRY(ring, entry + 1 +
+ entry = RX_COMP_ENTRY(ring, entry + 1 +
CAS_VAL(RX_COMP1_SKIP, words[0]));
#ifdef USE_NAPI
if (budget && (npackets >= budget))
@@ -2437,12 +2436,12 @@ static void cas_post_rxcs_ringN(struct net_device *dev,
int last, entry;
last = cp->rx_cur[ring];
- entry = cp->rx_new[ring];
+ entry = cp->rx_new[ring];
if (netif_msg_intr(cp))
printk(KERN_DEBUG "%s: rxc[%d] interrupt, done: %d/%d\n",
dev->name, ring, readl(cp->regs + REG_RX_COMP_HEAD),
entry);
-
+
/* zero and re-mark descriptors */
while (last != entry) {
cas_rxc_init(rxc + last);
@@ -2452,21 +2451,21 @@ static void cas_post_rxcs_ringN(struct net_device *dev,
if (ring == 0)
writel(last, cp->regs + REG_RX_COMP_TAIL);
- else if (cp->cas_flags & CAS_FLAG_REG_PLUS)
+ else if (cp->cas_flags & CAS_FLAG_REG_PLUS)
writel(last, cp->regs + REG_PLUS_RX_COMPN_TAIL(ring));
}
-/* cassini can use all four PCI interrupts for the completion ring.
+/* cassini can use all four PCI interrupts for the completion ring.
* rings 3 and 4 are identical
*/
#if defined(USE_PCI_INTC) || defined(USE_PCI_INTD)
-static inline void cas_handle_irqN(struct net_device *dev,
+static inline void cas_handle_irqN(struct net_device *dev,
struct cas *cp, const u32 status,
const int ring)
{
- if (status & (INTR_RX_COMP_FULL_ALT | INTR_RX_COMP_AF_ALT))
+ if (status & (INTR_RX_COMP_FULL_ALT | INTR_RX_COMP_AF_ALT))
cas_post_rxcs_ringN(dev, cp, ring);
}
@@ -2506,7 +2505,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id, struct pt_regs *regs)
static inline void cas_handle_irq1(struct cas *cp, const u32 status)
{
if (status & INTR_RX_BUF_UNAVAIL_1) {
- /* Frame arrived, no free RX buffers available.
+ /* Frame arrived, no free RX buffers available.
* NOTE: we can get this on a link transition. */
cas_post_rxds_ringN(cp, 1, 0);
spin_lock(&cp->stat_lock[1]);
@@ -2514,8 +2513,8 @@ static inline void cas_handle_irq1(struct cas *cp, const u32 status)
spin_unlock(&cp->stat_lock[1]);
}
- if (status & INTR_RX_BUF_AE_1)
- cas_post_rxds_ringN(cp, 1, RX_DESC_RINGN_SIZE(1) -
+ if (status & INTR_RX_BUF_AE_1)
+ cas_post_rxds_ringN(cp, 1, RX_DESC_RINGN_SIZE(1) -
RX_AE_FREEN_VAL(1));
if (status & (INTR_RX_COMP_AF | INTR_RX_COMP_FULL))
@@ -2559,7 +2558,7 @@ static inline void cas_handle_irq(struct net_device *dev,
cas_abnormal_irq(dev, cp, status);
if (status & INTR_RX_BUF_UNAVAIL) {
- /* Frame arrived, no free RX buffers available.
+ /* Frame arrived, no free RX buffers available.
* NOTE: we can get this on a link transition.
*/
cas_post_rxds_ringN(cp, 0, 0);
@@ -2626,7 +2625,7 @@ static int cas_poll(struct net_device *dev, int *budget)
todo = min(*budget, dev->quota);
/* to make sure we're fair with the work we loop through each
- * ring N_RX_COMP_RING times with a request of
+ * ring N_RX_COMP_RING times with a request of
* todo / N_RX_COMP_RINGS
*/
enable_intr = 1;
@@ -2785,13 +2784,13 @@ static void cas_write_txd(struct cas *cp, int ring, int entry,
txd->buffer = cpu_to_le64(mapping);
}
-static inline void *tx_tiny_buf(struct cas *cp, const int ring,
+static inline void *tx_tiny_buf(struct cas *cp, const int ring,
const int entry)
{
return cp->tx_tiny_bufs[ring] + TX_TINY_BUF_LEN*entry;
}
-static inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
+static inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
const int entry, const int tentry)
{
cp->tx_tiny_use[ring][tentry].nbufs++;
@@ -2799,7 +2798,7 @@ static inline dma_addr_t tx_tiny_map(struct cas *cp, const int ring,
return cp->tx_tiny_dvma[ring] + TX_TINY_BUF_LEN*entry;
}
-static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
+static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
struct sk_buff *skb)
{
struct net_device *dev = cp->dev;
@@ -2812,7 +2811,7 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
spin_lock_irqsave(&cp->tx_lock[ring], flags);
/* This is a hard error, log it. */
- if (TX_BUFFS_AVAIL(cp, ring) <=
+ if (TX_BUFFS_AVAIL(cp, ring) <=
CAS_TABORT(cp)*(skb_shinfo(skb)->nr_frags + 1)) {
netif_stop_queue(dev);
spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
@@ -2822,13 +2821,13 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
}
ctrl = 0;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
u64 csum_start_off, csum_stuff_off;
csum_start_off = (u64) (skb->h.raw - skb->data);
csum_stuff_off = (u64) ((skb->h.raw + skb->csum) - skb->data);
- ctrl = TX_DESC_CSUM_EN |
+ ctrl = TX_DESC_CSUM_EN |
CAS_BASE(TX_DESC_CSUM_START, csum_start_off) |
CAS_BASE(TX_DESC_CSUM_STUFF, csum_stuff_off);
}
@@ -2846,17 +2845,17 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
tabort = cas_calc_tabort(cp, (unsigned long) skb->data, len);
if (unlikely(tabort)) {
/* NOTE: len is always > tabort */
- cas_write_txd(cp, ring, entry, mapping, len - tabort,
+ cas_write_txd(cp, ring, entry, mapping, len - tabort,
ctrl | TX_DESC_SOF, 0);
entry = TX_DESC_NEXT(ring, entry);
- memcpy(tx_tiny_buf(cp, ring, entry), skb->data +
+ memcpy(tx_tiny_buf(cp, ring, entry), skb->data +
len - tabort, tabort);
mapping = tx_tiny_map(cp, ring, entry, tentry);
cas_write_txd(cp, ring, entry, mapping, tabort, ctrl,
(nr_frags == 0));
} else {
- cas_write_txd(cp, ring, entry, mapping, len, ctrl |
+ cas_write_txd(cp, ring, entry, mapping, len, ctrl |
TX_DESC_SOF, (nr_frags == 0));
}
entry = TX_DESC_NEXT(ring, entry);
@@ -2877,10 +2876,10 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
cas_write_txd(cp, ring, entry, mapping, len - tabort,
ctrl, 0);
entry = TX_DESC_NEXT(ring, entry);
-
+
addr = cas_page_map(fragp->page);
memcpy(tx_tiny_buf(cp, ring, entry),
- addr + fragp->page_offset + len - tabort,
+ addr + fragp->page_offset + len - tabort,
tabort);
cas_page_unmap(addr);
mapping = tx_tiny_map(cp, ring, entry, tentry);
@@ -2899,12 +2898,12 @@ static inline int cas_xmit_tx_ringN(struct cas *cp, int ring,
if (netif_msg_tx_queued(cp))
printk(KERN_DEBUG "%s: tx[%d] queued, slot %d, skblen %d, "
"avail %d\n",
- dev->name, ring, entry, skb->len,
+ dev->name, ring, entry, skb->len,
TX_BUFFS_AVAIL(cp, ring));
writel(entry, cp->regs + REG_TX_KICKN(ring));
spin_unlock_irqrestore(&cp->tx_lock[ring], flags);
return 0;
-}
+}
static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -2913,7 +2912,7 @@ static int cas_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* this is only used as a load-balancing hint, so it doesn't
* need to be SMP safe
*/
- static int ring;
+ static int ring;
if (skb_padto(skb, cp->min_frame_size))
return 0;
@@ -2944,14 +2943,14 @@ static void cas_init_tx_dma(struct cas *cp)
/* enable completion writebacks, enable paced mode,
* disable read pipe, and disable pre-interrupt compwbs
*/
- val = TX_CFG_COMPWB_Q1 | TX_CFG_COMPWB_Q2 |
+ val = TX_CFG_COMPWB_Q1 | TX_CFG_COMPWB_Q2 |
TX_CFG_COMPWB_Q3 | TX_CFG_COMPWB_Q4 |
- TX_CFG_DMA_RDPIPE_DIS | TX_CFG_PACED_MODE |
+ TX_CFG_DMA_RDPIPE_DIS | TX_CFG_PACED_MODE |
TX_CFG_INTR_COMPWB_DIS;
/* write out tx ring info and tx desc bases */
for (i = 0; i < MAX_TX_RINGS; i++) {
- off = (unsigned long) cp->init_txds[i] -
+ off = (unsigned long) cp->init_txds[i] -
(unsigned long) cp->init_block;
val |= CAS_TX_RINGN_BASE(i);
@@ -2992,7 +2991,7 @@ static u32 cas_setup_multicast(struct cas *cp)
{
u32 rxcfg = 0;
int i;
-
+
if (cp->dev->flags & IFF_PROMISC) {
rxcfg |= MAC_RX_CFG_PROMISC_EN;
@@ -3017,16 +3016,16 @@ static u32 cas_setup_multicast(struct cas *cp)
writel(0x0, cp->regs + REG_MAC_ADDRN(i*3 + 2));
continue;
}
- writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
+ writel((dmi->dmi_addr[4] << 8) | dmi->dmi_addr[5],
cp->regs + REG_MAC_ADDRN(i*3 + 0));
- writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
+ writel((dmi->dmi_addr[2] << 8) | dmi->dmi_addr[3],
cp->regs + REG_MAC_ADDRN(i*3 + 1));
- writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
+ writel((dmi->dmi_addr[0] << 8) | dmi->dmi_addr[1],
cp->regs + REG_MAC_ADDRN(i*3 + 2));
dmi = dmi->next;
}
- /* use hw hash table for the next series of
+ /* use hw hash table for the next series of
* multicast addresses
*/
memset(hash_table, 0, sizeof(hash_table));
@@ -3037,7 +3036,7 @@ static u32 cas_setup_multicast(struct cas *cp)
dmi = dmi->next;
}
for (i=0; i < 16; i++)
- writel(hash_table[i], cp->regs +
+ writel(hash_table[i], cp->regs +
REG_MAC_HASH_TABLEN(i));
rxcfg |= MAC_RX_CFG_HASH_FILTER_EN;
}
@@ -3122,23 +3121,23 @@ static void cas_init_mac(struct cas *cp)
writel(0x00, cp->regs + REG_MAC_IPG0);
writel(0x08, cp->regs + REG_MAC_IPG1);
writel(0x04, cp->regs + REG_MAC_IPG2);
-
+
/* change later for 802.3z */
- writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
+ writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
/* min frame + FCS */
writel(ETH_ZLEN + 4, cp->regs + REG_MAC_FRAMESIZE_MIN);
/* Ethernet payload + header + FCS + optional VLAN tag. NOTE: we
- * specify the maximum frame size to prevent RX tag errors on
+ * specify the maximum frame size to prevent RX tag errors on
* oversized frames.
*/
writel(CAS_BASE(MAC_FRAMESIZE_MAX_BURST, 0x2000) |
- CAS_BASE(MAC_FRAMESIZE_MAX_FRAME,
- (CAS_MAX_MTU + ETH_HLEN + 4 + 4)),
+ CAS_BASE(MAC_FRAMESIZE_MAX_FRAME,
+ (CAS_MAX_MTU + ETH_HLEN + 4 + 4)),
cp->regs + REG_MAC_FRAMESIZE_MAX);
- /* NOTE: crc_size is used as a surrogate for half-duplex.
+ /* NOTE: crc_size is used as a surrogate for half-duplex.
* workaround saturn half-duplex issue by increasing preamble
* size to 65 bytes.
*/
@@ -3181,7 +3180,7 @@ static void cas_init_mac(struct cas *cp)
* spin_lock_irqsave, but we are called only in cas_init_hw and
* cas_init_hw is protected by cas_lock_all, which calls
* spin_lock_irq (so it doesn't need to save the flags, and
- * we should be OK for the writel, as that is the only
+ * we should be OK for the writel, as that is the only
* difference).
*/
cp->mac_rx_cfg = rxcfg = cas_setup_multicast(cp);
@@ -3230,7 +3229,7 @@ static int cas_vpd_match(const void __iomem *p, const char *str)
{
int len = strlen(str) + 1;
int i;
-
+
for (i = 0; i < len; i++) {
if (readb(p + i) != str[i])
return 0;
@@ -3247,7 +3246,7 @@ static int cas_vpd_match(const void __iomem *p, const char *str)
* number.
* 3) fiber cards don't have bridges, so their slot numbers don't
* mean anything.
- * 4) we don't actually know we have a fiber card until after
+ * 4) we don't actually know we have a fiber card until after
* the mac addresses are parsed.
*/
static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
@@ -3279,15 +3278,15 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
(readb(p + i + 1) == 0x43) &&
(readb(p + i + 2) == 0x49) &&
(readb(p + i + 3) == 0x52)) {
- base = p + (readb(p + i + 8) |
+ base = p + (readb(p + i + 8) |
(readb(p + i + 9) << 8));
break;
- }
+ }
}
if (!base || (readb(base) != 0x82))
goto use_random_mac_addr;
-
+
i = (readb(base + 1) | (readb(base + 2) << 8)) + 3;
while (i < EXPANSION_ROM_SIZE) {
if (readb(base + i) != 0x90) /* no vpd found */
@@ -3305,20 +3304,20 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
char type;
p += 3;
-
+
/* look for the following things:
* -- correct length == 29
- * 3 (type) + 2 (size) +
- * 18 (strlen("local-mac-address") + 1) +
- * 6 (mac addr)
+ * 3 (type) + 2 (size) +
+ * 18 (strlen("local-mac-address") + 1) +
+ * 6 (mac addr)
* -- VPD Instance 'I'
* -- VPD Type Bytes 'B'
* -- VPD data length == 6
* -- property string == local-mac-address
- *
+ *
* -- correct length == 24
- * 3 (type) + 2 (size) +
- * 12 (strlen("entropy-dev") + 1) +
+ * 3 (type) + 2 (size) +
+ * 12 (strlen("entropy-dev") + 1) +
* 7 (strlen("vms110") + 1)
* -- VPD Instance 'I'
* -- VPD Type String 'B'
@@ -3326,17 +3325,17 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
* -- property string == entropy-dev
*
* -- correct length == 18
- * 3 (type) + 2 (size) +
- * 9 (strlen("phy-type") + 1) +
+ * 3 (type) + 2 (size) +
+ * 9 (strlen("phy-type") + 1) +
* 4 (strlen("pcs") + 1)
* -- VPD Instance 'I'
* -- VPD Type String 'S'
* -- VPD data length == 4
* -- property string == phy-type
- *
+ *
* -- correct length == 23
- * 3 (type) + 2 (size) +
- * 14 (strlen("phy-interface") + 1) +
+ * 3 (type) + 2 (size) +
+ * 14 (strlen("phy-interface") + 1) +
* 4 (strlen("pcs") + 1)
* -- VPD Instance 'I'
* -- VPD Type String 'S'
@@ -3350,14 +3349,14 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
type = readb(p + 3);
if (type == 'B') {
if ((klen == 29) && readb(p + 4) == 6 &&
- cas_vpd_match(p + 5,
+ cas_vpd_match(p + 5,
"local-mac-address")) {
- if (mac_off++ > offset)
+ if (mac_off++ > offset)
goto next;
/* set mac address */
- for (j = 0; j < 6; j++)
- dev_addr[j] =
+ for (j = 0; j < 6; j++)
+ dev_addr[j] =
readb(p + 23 + j);
goto found_mac;
}
@@ -3367,7 +3366,7 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
goto next;
#ifdef USE_ENTROPY_DEV
- if ((klen == 24) &&
+ if ((klen == 24) &&
cas_vpd_match(p + 5, "entropy-dev") &&
cas_vpd_match(p + 17, "vms110")) {
cp->cas_flags |= CAS_FLAG_ENTROPY_DEV;
@@ -3385,7 +3384,7 @@ static int cas_get_vpd_info(struct cas *cp, unsigned char *dev_addr,
goto found_phy;
}
}
-
+
if ((klen == 23) && readb(p + 4) == 4 &&
cas_vpd_match(p + 5, "phy-interface")) {
if (cas_vpd_match(p + 19, "pcs")) {
@@ -3463,12 +3462,12 @@ static int cas_check_invariants(struct cas *cp)
int i;
/* get page size for rx buffers. */
- cp->page_order = 0;
+ cp->page_order = 0;
#ifdef USE_PAGE_ORDER
if (PAGE_SHIFT < CAS_JUMBO_PAGE_SHIFT) {
/* see if we can allocate larger pages */
- struct page *page = alloc_pages(GFP_ATOMIC,
- CAS_JUMBO_PAGE_SHIFT -
+ struct page *page = alloc_pages(GFP_ATOMIC,
+ CAS_JUMBO_PAGE_SHIFT -
PAGE_SHIFT);
if (page) {
__free_pages(page, CAS_JUMBO_PAGE_SHIFT - PAGE_SHIFT);
@@ -3484,15 +3483,15 @@ static int cas_check_invariants(struct cas *cp)
cp->tx_fifo_size = readl(cp->regs + REG_TX_FIFO_SIZE) * 64;
cp->rx_fifo_size = RX_FIFO_SIZE;
- /* finish phy determination. MDIO1 takes precedence over MDIO0 if
+ /* finish phy determination. MDIO1 takes precedence over MDIO0 if
* they're both connected.
*/
- cp->phy_type = cas_get_vpd_info(cp, cp->dev->dev_addr,
+ cp->phy_type = cas_get_vpd_info(cp, cp->dev->dev_addr,
PCI_SLOT(pdev->devfn));
if (cp->phy_type & CAS_PHY_SERDES) {
cp->cas_flags |= CAS_FLAG_1000MB_CAP;
return 0; /* no more checking needed */
- }
+ }
/* MII */
cfg = readl(cp->regs + REG_MIF_CFG);
@@ -3526,7 +3525,7 @@ static int cas_check_invariants(struct cas *cp)
done:
/* see if we can do gigabit */
cfg = cas_phy_read(cp, MII_BMSR);
- if ((cfg & CAS_BMSR_1000_EXTEND) &&
+ if ((cfg & CAS_BMSR_1000_EXTEND) &&
cas_phy_read(cp, CAS_MII_1000_EXTEND))
cp->cas_flags |= CAS_FLAG_1000MB_CAP;
return 0;
@@ -3538,7 +3537,7 @@ static inline void cas_start_dma(struct cas *cp)
int i;
u32 val;
int txfailed = 0;
-
+
/* enable dma */
val = readl(cp->regs + REG_TX_CFG) | TX_CFG_DMA_EN;
writel(val, cp->regs + REG_TX_CFG);
@@ -3564,8 +3563,8 @@ static inline void cas_start_dma(struct cas *cp)
val = readl(cp->regs + REG_MAC_RX_CFG);
if ((val & MAC_RX_CFG_EN)) {
if (txfailed) {
- printk(KERN_ERR
- "%s: enabling mac failed [tx:%08x:%08x].\n",
+ printk(KERN_ERR
+ "%s: enabling mac failed [tx:%08x:%08x].\n",
cp->dev->name,
readl(cp->regs + REG_MIF_STATE_MACHINE),
readl(cp->regs + REG_MAC_STATE_MACHINE));
@@ -3574,7 +3573,7 @@ static inline void cas_start_dma(struct cas *cp)
}
udelay(10);
}
- printk(KERN_ERR "%s: enabling mac failed [%s:%08x:%08x].\n",
+ printk(KERN_ERR "%s: enabling mac failed [%s:%08x:%08x].\n",
cp->dev->name,
(txfailed? "tx,rx":"rx"),
readl(cp->regs + REG_MIF_STATE_MACHINE),
@@ -3586,11 +3585,11 @@ enable_rx_done:
writel(0, cp->regs + REG_RX_COMP_TAIL);
if (cp->cas_flags & CAS_FLAG_REG_PLUS) {
- if (N_RX_DESC_RINGS > 1)
- writel(RX_DESC_RINGN_SIZE(1) - 4,
+ if (N_RX_DESC_RINGS > 1)
+ writel(RX_DESC_RINGN_SIZE(1) - 4,
cp->regs + REG_PLUS_RX_KICK1);
- for (i = 1; i < N_RX_COMP_RINGS; i++)
+ for (i = 1; i < N_RX_COMP_RINGS; i++)
writel(0, cp->regs + REG_PLUS_RX_COMPN_TAIL(i));
}
}
@@ -3616,7 +3615,7 @@ static void cas_read_mii_link_mode(struct cas *cp, int *fd, int *spd,
*fd = 0;
*spd = 10;
*pause = 0;
-
+
/* use GMII registers */
val = cas_phy_read(cp, MII_LPA);
if (val & CAS_LPA_PAUSE)
@@ -3657,7 +3656,7 @@ static void cas_set_link_modes(struct cas *cp)
cas_mif_poll(cp, 0);
val = cas_phy_read(cp, MII_BMCR);
if (val & BMCR_ANENABLE) {
- cas_read_mii_link_mode(cp, &full_duplex, &speed,
+ cas_read_mii_link_mode(cp, &full_duplex, &speed,
&pause);
} else {
if (val & BMCR_FULLDPLX)
@@ -3690,7 +3689,7 @@ static void cas_set_link_modes(struct cas *cp)
if (!full_duplex)
val |= MAC_XIF_DISABLE_ECHO;
}
- if (full_duplex)
+ if (full_duplex)
val |= MAC_XIF_FDPLX_LED;
if (speed == 1000)
val |= MAC_XIF_GMII_MODE;
@@ -3710,17 +3709,17 @@ static void cas_set_link_modes(struct cas *cp)
/* val now set up for REG_MAC_TX_CFG */
/* If gigabit and half-duplex, enable carrier extension
- * mode. increase slot time to 512 bytes as well.
+ * mode. increase slot time to 512 bytes as well.
* else, disable it and make sure slot time is 64 bytes.
* also activate checksum bug workaround
*/
if ((speed == 1000) && !full_duplex) {
- writel(val | MAC_TX_CFG_CARRIER_EXTEND,
+ writel(val | MAC_TX_CFG_CARRIER_EXTEND,
cp->regs + REG_MAC_TX_CFG);
val = readl(cp->regs + REG_MAC_RX_CFG);
val &= ~MAC_RX_CFG_STRIP_FCS; /* checksum workaround */
- writel(val | MAC_RX_CFG_CARRIER_EXTEND,
+ writel(val | MAC_RX_CFG_CARRIER_EXTEND,
cp->regs + REG_MAC_RX_CFG);
writel(0x200, cp->regs + REG_MAC_SLOT_TIME);
@@ -3732,7 +3731,7 @@ static void cas_set_link_modes(struct cas *cp)
} else {
writel(val, cp->regs + REG_MAC_TX_CFG);
- /* checksum bug workaround. don't strip FCS when in
+ /* checksum bug workaround. don't strip FCS when in
* half-duplex mode
*/
val = readl(cp->regs + REG_MAC_RX_CFG);
@@ -3745,7 +3744,7 @@ static void cas_set_link_modes(struct cas *cp)
cp->crc_size = 4;
cp->min_frame_size = CAS_MIN_FRAME;
}
- writel(val & ~MAC_RX_CFG_CARRIER_EXTEND,
+ writel(val & ~MAC_RX_CFG_CARRIER_EXTEND,
cp->regs + REG_MAC_RX_CFG);
writel(0x40, cp->regs + REG_MAC_SLOT_TIME);
}
@@ -3773,7 +3772,7 @@ static void cas_set_link_modes(struct cas *cp)
val |= MAC_CTRL_CFG_SEND_PAUSE_EN;
if (pause & 0x01) { /* symmetric pause */
val |= MAC_CTRL_CFG_RECV_PAUSE_EN;
- }
+ }
}
writel(val, cp->regs + REG_MAC_CTRL_CFG);
cas_start_dma(cp);
@@ -3805,7 +3804,7 @@ static void cas_init_hw(struct cas *cp, int restart_link)
*/
static void cas_hard_reset(struct cas *cp)
{
- writel(BIM_LOCAL_DEV_SOFT_0, cp->regs + REG_BIM_LOCAL_DEV_EN);
+ writel(BIM_LOCAL_DEV_SOFT_0, cp->regs + REG_BIM_LOCAL_DEV_EN);
udelay(20);
pci_restore_state(cp->pdev);
}
@@ -3823,7 +3822,7 @@ static void cas_global_reset(struct cas *cp, int blkflag)
* need some special handling if the chip is set into a
* loopback mode.
*/
- writel((SW_RESET_TX | SW_RESET_RX | SW_RESET_BLOCK_PCS_SLINK),
+ writel((SW_RESET_TX | SW_RESET_RX | SW_RESET_BLOCK_PCS_SLINK),
cp->regs + REG_SW_RESET);
} else {
writel(SW_RESET_TX | SW_RESET_RX, cp->regs + REG_SW_RESET);
@@ -3843,16 +3842,16 @@ static void cas_global_reset(struct cas *cp, int blkflag)
done:
/* enable various BIM interrupts */
- writel(BIM_CFG_DPAR_INTR_ENABLE | BIM_CFG_RMA_INTR_ENABLE |
+ writel(BIM_CFG_DPAR_INTR_ENABLE | BIM_CFG_RMA_INTR_ENABLE |
BIM_CFG_RTA_INTR_ENABLE, cp->regs + REG_BIM_CFG);
/* clear out pci error status mask for handled errors.
* we don't deal with DMA counter overflows as they happen
* all the time.
*/
- writel(0xFFFFFFFFU & ~(PCI_ERR_BADACK | PCI_ERR_DTRTO |
- PCI_ERR_OTHER | PCI_ERR_BIM_DMA_WRITE |
- PCI_ERR_BIM_DMA_READ), cp->regs +
+ writel(0xFFFFFFFFU & ~(PCI_ERR_BADACK | PCI_ERR_DTRTO |
+ PCI_ERR_OTHER | PCI_ERR_BIM_DMA_WRITE |
+ PCI_ERR_BIM_DMA_READ), cp->regs +
REG_PCI_ERR_STATUS_MASK);
/* set up for MII by default to address mac rx reset timeout
@@ -3913,7 +3912,7 @@ static void cas_shutdown(struct cas *cp)
#else
while (atomic_read(&cp->reset_task_pending))
schedule();
-#endif
+#endif
/* Actually stop the chip */
cas_lock_all_save(cp, flags);
cas_reset(cp, 0);
@@ -3943,7 +3942,7 @@ static int cas_change_mtu(struct net_device *dev, int new_mtu)
}
schedule_work(&cp->reset_task);
#else
- atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
+ atomic_set(&cp->reset_task_pending, (cp->phy_type & CAS_PHY_SERDES) ?
CAS_RESET_ALL : CAS_RESET_MTU);
printk(KERN_ERR "reset called in cas_change_mtu\n");
schedule_work(&cp->reset_task);
@@ -3977,7 +3976,7 @@ static void cas_clean_txd(struct cas *cp, int ring)
* needs to be unmapped.
*/
daddr = le64_to_cpu(txd[ent].buffer);
- dlen = CAS_VAL(TX_DESC_BUFLEN,
+ dlen = CAS_VAL(TX_DESC_BUFLEN,
le64_to_cpu(txd[ent].control));
pci_unmap_page(cp->pdev, daddr, dlen,
PCI_DMA_TODEVICE);
@@ -4048,7 +4047,7 @@ static inline int cas_alloc_rx_desc(struct cas *cp, int ring)
size = RX_DESC_RINGN_SIZE(ring);
for (i = 0; i < size; i++) {
- if ((page[i] = cas_page_alloc(cp, GFP_KERNEL)) == NULL)
+ if ((page[i] = cas_page_alloc(cp, GFP_KERNEL)) == NULL)
return -1;
}
return 0;
@@ -4115,7 +4114,7 @@ static void cas_reset_task(void *data)
* call to cas_init_hw will restart auto negotiation.
* Setting the second argument of cas_reset to
* !(pending == CAS_RESET_ALL) will set this argument
- * to 1 (avoiding reinitializing the PHY for the normal
+ * to 1 (avoiding reinitializing the PHY for the normal
* PCS case) when auto negotiation is not restarted.
*/
#if 1
@@ -4152,9 +4151,9 @@ static void cas_link_timer(unsigned long data)
if (link_transition_timeout != 0 &&
cp->link_transition_jiffies_valid &&
- ((jiffies - cp->link_transition_jiffies) >
+ ((jiffies - cp->link_transition_jiffies) >
(link_transition_timeout))) {
- /* One-second counter so link-down workaround doesn't
+ /* One-second counter so link-down workaround doesn't
* cause resets to occur so fast as to fool the switch
* into thinking the link is down.
*/
@@ -4174,10 +4173,10 @@ static void cas_link_timer(unsigned long data)
#if 1
if (atomic_read(&cp->reset_task_pending_all) ||
atomic_read(&cp->reset_task_pending_spare) ||
- atomic_read(&cp->reset_task_pending_mtu))
+ atomic_read(&cp->reset_task_pending_mtu))
goto done;
#else
- if (atomic_read(&cp->reset_task_pending))
+ if (atomic_read(&cp->reset_task_pending))
goto done;
#endif
@@ -4269,7 +4268,7 @@ done:
spin_unlock_irqrestore(&cp->lock, flags);
}
-/* tiny buffers are used to avoid target abort issues with
+/* tiny buffers are used to avoid target abort issues with
* older cassini's
*/
static void cas_tx_tiny_free(struct cas *cp)
@@ -4281,7 +4280,7 @@ static void cas_tx_tiny_free(struct cas *cp)
if (!cp->tx_tiny_bufs[i])
continue;
- pci_free_consistent(pdev, TX_TINY_BUF_BLOCK,
+ pci_free_consistent(pdev, TX_TINY_BUF_BLOCK,
cp->tx_tiny_bufs[i],
cp->tx_tiny_dvma[i]);
cp->tx_tiny_bufs[i] = NULL;
@@ -4294,7 +4293,7 @@ static int cas_tx_tiny_alloc(struct cas *cp)
int i;
for (i = 0; i < N_TX_RINGS; i++) {
- cp->tx_tiny_bufs[i] =
+ cp->tx_tiny_bufs[i] =
pci_alloc_consistent(pdev, TX_TINY_BUF_BLOCK,
&cp->tx_tiny_dvma[i]);
if (!cp->tx_tiny_bufs[i]) {
@@ -4323,7 +4322,7 @@ static int cas_open(struct net_device *dev)
/* Reset the chip */
cas_lock_all_save(cp, flags);
/* We set the second arg to cas_reset to zero
- * because cas_init_hw below will have its second
+ * because cas_init_hw below will have its second
* argument set to non-zero, which will force
* autonegotiation to start.
*/
@@ -4339,19 +4338,19 @@ static int cas_open(struct net_device *dev)
err = -ENOMEM;
if (cas_alloc_rxds(cp) < 0)
goto err_tx_tiny;
-
+
/* allocate spares */
cas_spare_init(cp);
cas_spare_recover(cp, GFP_KERNEL);
/* We can now request the interrupt as we know it's masked
* on the controller. cassini+ has up to 4 interrupts
- * that can be used, but you need to do explicit pci interrupt
+ * that can be used, but you need to do explicit pci interrupt
* mapping to expose them
*/
if (request_irq(cp->pdev->irq, cas_interrupt,
- SA_SHIRQ, dev->name, (void *) dev)) {
- printk(KERN_ERR "%s: failed to request irq !\n",
+ IRQF_SHARED, dev->name, (void *) dev)) {
+ printk(KERN_ERR "%s: failed to request irq !\n",
cp->dev->name);
err = -EAGAIN;
goto err_spare;
@@ -4389,9 +4388,9 @@ static int cas_close(struct net_device *dev)
/* Stop traffic, mark us closed */
cas_lock_all_save(cp, flags);
- cp->opened = 0;
+ cp->opened = 0;
cas_reset(cp, 0);
- cas_phy_init(cp);
+ cas_phy_init(cp);
cas_begin_auto_negotiation(cp, NULL);
cas_clean_rings(cp);
cas_unlock_all_restore(cp, flags);
@@ -4484,7 +4483,7 @@ static struct net_device_stats *cas_get_stats(struct net_device *dev)
/* we collate all of the stats into net_stats[N_TX_RING] */
if (!cp->hw_running)
return stats + N_TX_RINGS;
-
+
/* collect outstanding stats */
/* WTZ: the Cassini spec gives these as 16 bit counters but
* stored in 32-bit words. Added a mask of 0xffff to be safe,
@@ -4494,11 +4493,11 @@ static struct net_device_stats *cas_get_stats(struct net_device *dev)
* that consistent.
*/
spin_lock_irqsave(&cp->stat_lock[N_TX_RINGS], flags);
- stats[N_TX_RINGS].rx_crc_errors +=
+ stats[N_TX_RINGS].rx_crc_errors +=
readl(cp->regs + REG_MAC_FCS_ERR) & 0xffff;
- stats[N_TX_RINGS].rx_frame_errors +=
+ stats[N_TX_RINGS].rx_frame_errors +=
readl(cp->regs + REG_MAC_ALIGN_ERR) &0xffff;
- stats[N_TX_RINGS].rx_length_errors +=
+ stats[N_TX_RINGS].rx_length_errors +=
readl(cp->regs + REG_MAC_LEN_ERR) & 0xffff;
#if 1
tmp = (readl(cp->regs + REG_MAC_COLL_EXCESS) & 0xffff) +
@@ -4507,7 +4506,7 @@ static struct net_device_stats *cas_get_stats(struct net_device *dev)
stats[N_TX_RINGS].collisions +=
tmp + (readl(cp->regs + REG_MAC_COLL_NORMAL) & 0xffff);
#else
- stats[N_TX_RINGS].tx_aborted_errors +=
+ stats[N_TX_RINGS].tx_aborted_errors +=
readl(cp->regs + REG_MAC_COLL_EXCESS);
stats[N_TX_RINGS].collisions += readl(cp->regs + REG_MAC_COLL_EXCESS) +
readl(cp->regs + REG_MAC_COLL_LATE);
@@ -4526,7 +4525,7 @@ static struct net_device_stats *cas_get_stats(struct net_device *dev)
for (i = 0; i < N_TX_RINGS; i++) {
spin_lock(&cp->stat_lock[i]);
- stats[N_TX_RINGS].rx_length_errors +=
+ stats[N_TX_RINGS].rx_length_errors +=
stats[i].rx_length_errors;
stats[N_TX_RINGS].rx_crc_errors += stats[i].rx_crc_errors;
stats[N_TX_RINGS].rx_packets += stats[i].rx_packets;
@@ -4551,10 +4550,10 @@ static void cas_set_multicast(struct net_device *dev)
u32 rxcfg, rxcfg_new;
unsigned long flags;
int limit = STOP_TRIES;
-
+
if (!cp->hw_running)
return;
-
+
spin_lock_irqsave(&cp->lock, flags);
rxcfg = readl(cp->regs + REG_MAC_RX_CFG);
@@ -4620,22 +4619,22 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
XCVR_INTERNAL : XCVR_EXTERNAL;
cmd->phy_address = cp->phy_addr;
cmd->advertising |= ADVERTISED_TP | ADVERTISED_MII |
- ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
+ ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
ADVERTISED_100baseT_Full;
cmd->supported |=
- (SUPPORTED_10baseT_Half |
+ (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
- SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_TP | SUPPORTED_MII);
if (cp->hw_running) {
cas_mif_poll(cp, 0);
bmcr = cas_phy_read(cp, MII_BMCR);
- cas_read_mii_link_mode(cp, &full_duplex,
+ cas_read_mii_link_mode(cp, &full_duplex,
&speed, &pause);
cas_mif_poll(cp, 1);
}
@@ -4648,9 +4647,9 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->advertising |= ADVERTISED_FIBRE;
if (cp->hw_running) {
- /* pcs uses the same bits as mii */
+ /* pcs uses the same bits as mii */
bmcr = readl(cp->regs + REG_PCS_MII_CTRL);
- cas_read_pcs_link_mode(cp, &full_duplex,
+ cas_read_pcs_link_mode(cp, &full_duplex,
&speed, &pause);
}
}
@@ -4668,8 +4667,8 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->autoneg = AUTONEG_DISABLE;
cmd->speed =
(bmcr & CAS_BMCR_SPEED1000) ?
- SPEED_1000 :
- ((bmcr & BMCR_SPEED100) ? SPEED_100:
+ SPEED_1000 :
+ ((bmcr & BMCR_SPEED100) ? SPEED_100:
SPEED_10);
cmd->duplex =
(bmcr & BMCR_FULLDPLX) ?
@@ -4677,7 +4676,7 @@ static int cas_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
}
if (linkstate != link_up) {
/* Force these to "unknown" if the link is not up and
- * autonogotiation in enabled. We can set the link
+ * autonogotiation in enabled. We can set the link
* speed to 0, but not cmd->duplex,
* because its legal values are 0 and 1. Ethtool will
* print the value reported in parentheses after the
@@ -4784,7 +4783,7 @@ static int cas_get_stats_count(struct net_device *dev)
static void cas_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
- memcpy(data, &ethtool_cassini_statnames,
+ memcpy(data, &ethtool_cassini_statnames,
CAS_NUM_STAT_KEYS * ETH_GSTRING_LEN);
}
@@ -4813,7 +4812,7 @@ static void cas_get_ethtool_stats(struct net_device *dev,
BUG_ON(i != CAS_NUM_STAT_KEYS);
}
-static struct ethtool_ops cas_ethtool_ops = {
+static const struct ethtool_ops cas_ethtool_ops = {
.get_drvinfo = cas_get_drvinfo,
.get_settings = cas_get_settings,
.set_settings = cas_set_settings,
@@ -4834,7 +4833,7 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
struct mii_ioctl_data *data = if_mii(ifr);
unsigned long flags;
int rc = -EOPNOTSUPP;
-
+
/* Hold the PM mutex while doing ioctl's or we may collide
* with open/close and power management and oops.
*/
@@ -4888,13 +4887,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_enable_device(pdev);
if (err) {
- printk(KERN_ERR PFX "Cannot enable PCI device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot enable PCI device, aborting.\n");
return err;
}
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
- printk(KERN_ERR PFX "Cannot find proper PCI device "
+ dev_err(&pdev->dev, "Cannot find proper PCI device "
"base address, aborting.\n");
err = -ENODEV;
goto err_out_disable_pdev;
@@ -4902,7 +4900,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev = alloc_etherdev(sizeof(*cp));
if (!dev) {
- printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+ dev_err(&pdev->dev, "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out_disable_pdev;
}
@@ -4911,8 +4909,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_request_regions(pdev, dev->name);
if (err) {
- printk(KERN_ERR PFX "Cannot obtain PCI resources, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
goto err_out_free_netdev;
}
pci_set_master(pdev);
@@ -4936,13 +4933,13 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,
&orig_cacheline_size);
if (orig_cacheline_size < CAS_PREF_CACHELINE_SIZE) {
- cas_cacheline_size =
- (CAS_PREF_CACHELINE_SIZE < SMP_CACHE_BYTES) ?
+ cas_cacheline_size =
+ (CAS_PREF_CACHELINE_SIZE < SMP_CACHE_BYTES) ?
CAS_PREF_CACHELINE_SIZE : SMP_CACHE_BYTES;
- if (pci_write_config_byte(pdev,
- PCI_CACHE_LINE_SIZE,
+ if (pci_write_config_byte(pdev,
+ PCI_CACHE_LINE_SIZE,
cas_cacheline_size)) {
- printk(KERN_ERR PFX "Could not set PCI cache "
+ dev_err(&pdev->dev, "Could not set PCI cache "
"line size\n");
goto err_write_cacheline;
}
@@ -4956,7 +4953,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
err = pci_set_consistent_dma_mask(pdev,
DMA_64BIT_MASK);
if (err < 0) {
- printk(KERN_ERR PFX "Unable to obtain 64-bit DMA "
+ dev_err(&pdev->dev, "Unable to obtain 64-bit DMA "
"for consistent allocations\n");
goto err_out_free_res;
}
@@ -4964,7 +4961,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
} else {
err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
- printk(KERN_ERR PFX "No usable DMA configuration, "
+ dev_err(&pdev->dev, "No usable DMA configuration, "
"aborting.\n");
goto err_out_free_res;
}
@@ -4980,7 +4977,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
cp->orig_cacheline_size = cas_cacheline_size ? orig_cacheline_size: 0;
#endif
cp->dev = dev;
- cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
+ cp->msg_enable = (cassini_debug < 0) ? CAS_DEF_MSG_ENABLE :
cassini_debug;
cp->link_transition = LINK_TRANSITION_UNKNOWN;
@@ -5024,8 +5021,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
/* give us access to cassini registers */
cp->regs = pci_iomap(pdev, 0, casreg_len);
if (cp->regs == 0UL) {
- printk(KERN_ERR PFX "Cannot map device registers, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot map device registers, aborting.\n");
goto err_out_free_res;
}
cp->casreg_len = casreg_len;
@@ -5041,18 +5037,17 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
&cp->block_dvma);
if (!cp->init_block) {
- printk(KERN_ERR PFX "Cannot allocate init block, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot allocate init block, aborting.\n");
goto err_out_iounmap;
}
- for (i = 0; i < N_TX_RINGS; i++)
+ for (i = 0; i < N_TX_RINGS; i++)
cp->init_txds[i] = cp->init_block->txds[i];
- for (i = 0; i < N_RX_DESC_RINGS; i++)
+ for (i = 0; i < N_RX_DESC_RINGS; i++)
cp->init_rxds[i] = cp->init_block->rxds[i];
- for (i = 0; i < N_RX_COMP_RINGS; i++)
+ for (i = 0; i < N_RX_COMP_RINGS; i++)
cp->init_rxcs[i] = cp->init_block->rxcs[i];
for (i = 0; i < N_RX_FLOWS; i++)
@@ -5086,18 +5081,17 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
dev->features |= NETIF_F_HIGHDMA;
if (register_netdev(dev)) {
- printk(KERN_ERR PFX "Cannot register net device, "
- "aborting.\n");
+ dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
goto err_out_free_consistent;
}
i = readl(cp->regs + REG_BIM_CFG);
printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) "
- "Ethernet[%d] ", dev->name,
- (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
+ "Ethernet[%d] ", dev->name,
+ (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "",
(i & BIM_CFG_32BIT) ? "32" : "64",
(i & BIM_CFG_66MHZ) ? "66" : "33",
- (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
+ (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i],
@@ -5129,7 +5123,7 @@ err_out_free_res:
err_write_cacheline:
/* Try to restore it in case the error occured after we
- * set it.
+ * set it.
*/
pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, orig_cacheline_size);
@@ -5163,7 +5157,7 @@ static void __devexit cas_remove_one(struct pci_dev *pdev)
/* Restore the cache line size if we had modified
* it.
*/
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
cp->orig_cacheline_size);
}
#endif
@@ -5184,7 +5178,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state)
unsigned long flags;
mutex_lock(&cp->pm_mutex);
-
+
/* If the driver is opened, we stop the DMA */
if (cp->opened) {
netif_device_detach(dev);
@@ -5251,7 +5245,7 @@ static int __init cas_init(void)
else
link_transition_timeout = 0;
- return pci_module_init(&cas_driver);
+ return pci_register_driver(&cas_driver);
}
static void __exit cas_cleanup(void)
diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h
index ab55c7ee101..a970804487c 100644
--- a/drivers/net/cassini.h
+++ b/drivers/net/cassini.h
@@ -21,7 +21,7 @@
*
* vendor id: 0x108E (Sun Microsystems, Inc.)
* device id: 0xabba (Cassini)
- * revision ids: 0x01 = Cassini
+ * revision ids: 0x01 = Cassini
* 0x02 = Cassini rev 2
* 0x10 = Cassini+
* 0x11 = Cassini+ 0.2u
@@ -46,16 +46,16 @@
* appear in cassini+. REG_MINUS_ addresses only appear in cassini.
*/
#define CAS_ID_REV2 0x02
-#define CAS_ID_REVPLUS 0x10
-#define CAS_ID_REVPLUS02u 0x11
+#define CAS_ID_REVPLUS 0x10
+#define CAS_ID_REVPLUS02u 0x11
#define CAS_ID_REVSATURNB2 0x30
/** global resources **/
/* this register sets the weights for the weighted round robin arbiter. e.g.,
* if rx weight == 1 and tx weight == 0, rx == 2x tx transfer credit
- * for its next turn to access the pci bus.
- * map: 0x0 = x1, 0x1 = x2, 0x2 = x4, 0x3 = x8
+ * for its next turn to access the pci bus.
+ * map: 0x0 = x1, 0x1 = x2, 0x2 = x4, 0x3 = x8
* DEFAULT: 0x0, SIZE: 5 bits
*/
#define REG_CAWR 0x0004 /* core arbitration weight */
@@ -66,8 +66,8 @@
#define CAWR_RR_DIS 0x10 /* [4] */
/* if enabled, BIM can send bursts across PCI bus > cacheline size. burst
- * sizes determined by length of packet or descriptor transfer and the
- * max length allowed by the target.
+ * sizes determined by length of packet or descriptor transfer and the
+ * max length allowed by the target.
* DEFAULT: 0x0, SIZE: 1 bit
*/
#define REG_INF_BURST 0x0008 /* infinite burst enable reg */
@@ -75,21 +75,21 @@
/* top level interrupts [0-9] are auto-cleared to 0 when the status
* register is read. second level interrupts [13 - 18] are cleared at
- * the source. tx completion register 3 is replicated in [19 - 31]
+ * the source. tx completion register 3 is replicated in [19 - 31]
* DEFAULT: 0x00000000, SIZE: 29 bits
*/
#define REG_INTR_STATUS 0x000C /* interrupt status register */
-#define INTR_TX_INTME 0x00000001 /* frame w/ INT ME desc bit set
+#define INTR_TX_INTME 0x00000001 /* frame w/ INT ME desc bit set
xferred from host queue to
TX FIFO */
#define INTR_TX_ALL 0x00000002 /* all xmit frames xferred into
TX FIFO. i.e.,
- TX Kick == TX complete. if
+ TX Kick == TX complete. if
PACED_MODE set, then TX FIFO
also empty */
-#define INTR_TX_DONE 0x00000004 /* any frame xferred into tx
+#define INTR_TX_DONE 0x00000004 /* any frame xferred into tx
FIFO */
-#define INTR_TX_TAG_ERROR 0x00000008 /* TX FIFO tag framing
+#define INTR_TX_TAG_ERROR 0x00000008 /* TX FIFO tag framing
corrupted. FATAL ERROR */
#define INTR_RX_DONE 0x00000010 /* at least 1 frame xferred
from RX FIFO to host mem.
@@ -98,18 +98,18 @@
intr blanking. */
#define INTR_RX_BUF_UNAVAIL 0x00000020 /* no more receive buffers.
RX Kick == RX complete */
-#define INTR_RX_TAG_ERROR 0x00000040 /* RX FIFO tag framing
+#define INTR_RX_TAG_ERROR 0x00000040 /* RX FIFO tag framing
corrupted. FATAL ERROR */
#define INTR_RX_COMP_FULL 0x00000080 /* no more room in completion
ring to post descriptors.
RX complete head incr to
almost reach RX complete
tail */
-#define INTR_RX_BUF_AE 0x00000100 /* less than the
+#define INTR_RX_BUF_AE 0x00000100 /* less than the
programmable threshold #
of free descr avail for
hw use */
-#define INTR_RX_COMP_AF 0x00000200 /* less than the
+#define INTR_RX_COMP_AF 0x00000200 /* less than the
programmable threshold #
of descr spaces for hw
use in completion descr
@@ -119,17 +119,17 @@
from fifo during DMA or
header parser provides TCP
header and payload size >
- MAC packet size.
+ MAC packet size.
FATAL ERROR */
#define INTR_SUMMARY 0x00001000 /* summary interrupt bit. this
- bit will be set if an interrupt
+ bit will be set if an interrupt
generated on the pci bus. useful
- when driver is polling for
+ when driver is polling for
interrupts */
#define INTR_PCS_STATUS 0x00002000 /* PCS interrupt status register */
-#define INTR_TX_MAC_STATUS 0x00004000 /* TX MAC status register has at
+#define INTR_TX_MAC_STATUS 0x00004000 /* TX MAC status register has at
least 1 unmasked interrupt set */
-#define INTR_RX_MAC_STATUS 0x00008000 /* RX MAC status register has at
+#define INTR_RX_MAC_STATUS 0x00008000 /* RX MAC status register has at
least 1 unmasked interrupt set */
#define INTR_MAC_CTRL_STATUS 0x00010000 /* MAC control status register has
at least 1 unmasked interrupt
@@ -137,9 +137,9 @@
#define INTR_MIF_STATUS 0x00020000 /* MIF status register has at least
1 unmasked interrupt set */
#define INTR_PCI_ERROR_STATUS 0x00040000 /* PCI error status register in the
- BIF has at least 1 unmasked
+ BIF has at least 1 unmasked
interrupt set */
-#define INTR_TX_COMP_3_MASK 0xFFF80000 /* mask for TX completion
+#define INTR_TX_COMP_3_MASK 0xFFF80000 /* mask for TX completion
3 reg data */
#define INTR_TX_COMP_3_SHIFT 19
#define INTR_ERROR_MASK (INTR_MIF_STATUS | INTR_PCI_ERROR_STATUS | \
@@ -149,7 +149,7 @@
INTR_MAC_CTRL_STATUS)
/* determines which status events will cause an interrupt. layout same
- * as REG_INTR_STATUS.
+ * as REG_INTR_STATUS.
* DEFAULT: 0xFFFFFFFF, SIZE: 16 bits
*/
#define REG_INTR_MASK 0x0010 /* Interrupt mask */
@@ -158,18 +158,18 @@
* useful when driver is polling for interrupts. layout same as REG_INTR_MASK.
* DEFAULT: 0x00000000, SIZE: 12 bits
*/
-#define REG_ALIAS_CLEAR 0x0014 /* alias clear mask
+#define REG_ALIAS_CLEAR 0x0014 /* alias clear mask
(used w/ status alias) */
/* same as REG_INTR_STATUS except that only bits cleared are those selected by
- * REG_ALIAS_CLEAR
+ * REG_ALIAS_CLEAR
* DEFAULT: 0x00000000, SIZE: 29 bits
*/
-#define REG_INTR_STATUS_ALIAS 0x001C /* interrupt status alias
+#define REG_INTR_STATUS_ALIAS 0x001C /* interrupt status alias
(selective clear) */
/* DEFAULT: 0x0, SIZE: 3 bits */
#define REG_PCI_ERR_STATUS 0x1000 /* PCI error status */
-#define PCI_ERR_BADACK 0x01 /* reserved in Cassini+.
+#define PCI_ERR_BADACK 0x01 /* reserved in Cassini+.
set if no ACK64# during ABS64 cycle
in Cassini. */
#define PCI_ERR_DTRTO 0x02 /* delayed xaction timeout. set if
@@ -179,16 +179,16 @@
unused in Cassini. */
#define PCI_ERR_BIM_DMA_READ 0x10 /* BIM received 0 count DMA read req.
unused in Cassini. */
-#define PCI_ERR_BIM_DMA_TIMEOUT 0x20 /* BIM received 255 retries during
+#define PCI_ERR_BIM_DMA_TIMEOUT 0x20 /* BIM received 255 retries during
DMA. unused in cassini. */
/* mask for PCI status events that will set PCI_ERR_STATUS. if cleared, event
- * causes an interrupt to be generated.
+ * causes an interrupt to be generated.
* DEFAULT: 0x7, SIZE: 3 bits
*/
#define REG_PCI_ERR_STATUS_MASK 0x1004 /* PCI Error status mask */
-/* used to configure PCI related parameters that are not in PCI config space.
+/* used to configure PCI related parameters that are not in PCI config space.
* DEFAULT: 0bxx000, SIZE: 5 bits
*/
#define REG_BIM_CFG 0x1008 /* BIM Configuration */
@@ -201,7 +201,7 @@
#define BIM_CFG_RMA_INTR_ENABLE 0x040 /* master abort intr enable */
#define BIM_CFG_RTA_INTR_ENABLE 0x080 /* target abort intr enable */
#define BIM_CFG_RESERVED2 0x100 /* reserved */
-#define BIM_CFG_BIM_DISABLE 0x200 /* stop BIM DMA. use before global
+#define BIM_CFG_BIM_DISABLE 0x200 /* stop BIM DMA. use before global
reset. reserved in Cassini. */
#define BIM_CFG_BIM_STATUS 0x400 /* (ro) 1 = BIM DMA suspended.
reserved in Cassini. */
@@ -212,7 +212,7 @@
#define REG_BIM_DIAG 0x100C /* BIM Diagnostic */
#define BIM_DIAG_MSTR_SM_MASK 0x3FFFFF00 /* PCI master controller state
machine bits [21:0] */
-#define BIM_DIAG_BRST_SM_MASK 0x7F /* PCI burst controller state
+#define BIM_DIAG_BRST_SM_MASK 0x7F /* PCI burst controller state
machine bits [6:0] */
/* writing to SW_RESET_TX and SW_RESET_RX will issue a global
@@ -224,14 +224,14 @@
#define SW_RESET_RX 0x00000002 /* reset RX DMA engine. poll until
cleared to 0. */
#define SW_RESET_RSTOUT 0x00000004 /* force RSTOUT# pin active (low).
- resets PHY and anything else
+ resets PHY and anything else
connected to RSTOUT#. RSTOUT#
is also activated by local PCI
- reset when hot-swap is being
+ reset when hot-swap is being
done. */
-#define SW_RESET_BLOCK_PCS_SLINK 0x00000008 /* if a global reset is done with
- this bit set, PCS and SLINK
- modules won't be reset.
+#define SW_RESET_BLOCK_PCS_SLINK 0x00000008 /* if a global reset is done with
+ this bit set, PCS and SLINK
+ modules won't be reset.
i.e., link won't drop. */
#define SW_RESET_BREQ_SM_MASK 0x00007F00 /* breq state machine [6:0] */
#define SW_RESET_PCIARB_SM_MASK 0x00070000 /* pci arbitration state bits:
@@ -252,7 +252,7 @@
0b01: AD_ACK_RX
0b10: AD_ACK_TX
0b11: AD_IDL_TX */
-#define SW_RESET_WRPCI_SM_MASK 0x06000000 /* write pci state bits
+#define SW_RESET_WRPCI_SM_MASK 0x06000000 /* write pci state bits
0b00: WR_PCI_WAT
0b01: WR_PCI_RDY
0b11: WR_PCI_ACK */
@@ -268,7 +268,7 @@
* value written has both lower and upper 32-bit halves rotated to the right
* one bit position. e.g., FFFFFFFF FFFFFFFF -> 7FFFFFFF 7FFFFFFF
*/
-#define REG_MINUS_BIM_DATAPATH_TEST 0x1018 /* Cassini: BIM datapath test
+#define REG_MINUS_BIM_DATAPATH_TEST 0x1018 /* Cassini: BIM datapath test
Cassini+: reserved */
/* output enables are provided for each device's chip select and for the rest
@@ -276,12 +276,12 @@
* bits are connected to general purpus control/status bits.
* DEFAULT: 0x7
*/
-#define REG_BIM_LOCAL_DEV_EN 0x1020 /* BIM local device
+#define REG_BIM_LOCAL_DEV_EN 0x1020 /* BIM local device
output EN. default: 0x7 */
#define BIM_LOCAL_DEV_PAD 0x01 /* address bus, RW signal, and
OE signal output enable on the
local bus interface. these
- are shared between both local
+ are shared between both local
bus devices. tristate when 0. */
#define BIM_LOCAL_DEV_PROM 0x02 /* PROM chip select */
#define BIM_LOCAL_DEV_EXT 0x04 /* secondary local bus device chip
@@ -291,8 +291,8 @@
#define BIM_LOCAL_DEV_HW_RESET 0x20 /* internal hw reset. Cassini+ only. */
/* access 24 entry BIM read and write buffers. put address in REG_BIM_BUFFER_ADDR
- * and read/write from/to it REG_BIM_BUFFER_DATA_LOW and _DATA_HI.
- * _DATA_HI should be the last access of the sequence.
+ * and read/write from/to it REG_BIM_BUFFER_DATA_LOW and _DATA_HI.
+ * _DATA_HI should be the last access of the sequence.
* DEFAULT: undefined
*/
#define REG_BIM_BUFFER_ADDR 0x1024 /* BIM buffer address. for
@@ -304,10 +304,10 @@
#define REG_BIM_BUFFER_DATA_LOW 0x1028 /* BIM buffer data low */
#define REG_BIM_BUFFER_DATA_HI 0x102C /* BIM buffer data high */
-/* set BIM_RAM_BIST_START to start built-in self test for BIM read buffer.
+/* set BIM_RAM_BIST_START to start built-in self test for BIM read buffer.
* bit auto-clears when done with status read from _SUMMARY and _PASS bits.
*/
-#define REG_BIM_RAM_BIST 0x102C /* BIM RAM (read buffer) BIST
+#define REG_BIM_RAM_BIST 0x102C /* BIM RAM (read buffer) BIST
control/status */
#define BIM_RAM_BIST_RD_START 0x01 /* start BIST for BIM read buffer */
#define BIM_RAM_BIST_WR_START 0x02 /* start BIST for BIM write buffer.
@@ -321,7 +321,7 @@
#define BIM_RAM_BIST_RD_LOW_PASS 0x10 /* read low bank passes BIST */
#define BIM_RAM_BIST_RD_HI_PASS 0x20 /* read high bank passes BIST */
#define BIM_RAM_BIST_WR_LOW_PASS 0x40 /* write low bank passes BIST.
- Cassini only. reserved in
+ Cassini only. reserved in
Cassini+. */
#define BIM_RAM_BIST_WR_HI_PASS 0x80 /* write high bank passes BIST.
Cassini only. reserved in
@@ -333,7 +333,7 @@
#define REG_BIM_DIAG_MUX 0x1030 /* BIM diagnostic probe mux
select register */
-/* enable probe monitoring mode and select data appearing on the P_A* bus. bit
+/* enable probe monitoring mode and select data appearing on the P_A* bus. bit
* values for _SEL_HI_MASK and _SEL_LOW_MASK:
* 0x0: internal probe[7:0] (pci arb state, wtc empty w, wtc full w, wtc empty w,
* wtc empty r, post pci)
@@ -353,7 +353,7 @@
* 0xe: hp probe[7:0] 0xf: mac probe[7:0]
*/
#define REG_PLUS_PROBE_MUX_SELECT 0x1034 /* Cassini+: PROBE MUX SELECT */
-#define PROBE_MUX_EN 0x80000000 /* allow probe signals to be
+#define PROBE_MUX_EN 0x80000000 /* allow probe signals to be
driven on local bus P_A[15:0]
for debugging */
#define PROBE_MUX_SUB_MUX_MASK 0x0000FF00 /* select sub module probe signals:
@@ -362,28 +362,28 @@
0x30 = tx[1:0]
0xC0 = hp[1:0] */
#define PROBE_MUX_SEL_HI_MASK 0x000000F0 /* select which module to appear
- on P_A[15:8]. see above for
+ on P_A[15:8]. see above for
values. */
#define PROBE_MUX_SEL_LOW_MASK 0x0000000F /* select which module to appear
- on P_A[7:0]. see above for
+ on P_A[7:0]. see above for
values. */
-/* values mean the same thing as REG_INTR_MASK excep that it's for INTB.
+/* values mean the same thing as REG_INTR_MASK excep that it's for INTB.
DEFAULT: 0x1F */
#define REG_PLUS_INTR_MASK_1 0x1038 /* Cassini+: interrupt mask
register 2 for INTB */
#define REG_PLUS_INTRN_MASK(x) (REG_PLUS_INTR_MASK_1 + ((x) - 1)*16)
-/* bits correspond to both _MASK and _STATUS registers. _ALT corresponds to
- * all of the alternate (2-4) INTR registers while _1 corresponds to only
- * _MASK_1 and _STATUS_1 registers.
+/* bits correspond to both _MASK and _STATUS registers. _ALT corresponds to
+ * all of the alternate (2-4) INTR registers while _1 corresponds to only
+ * _MASK_1 and _STATUS_1 registers.
* DEFAULT: 0x7 for MASK registers, 0x0 for ALIAS_CLEAR registers
*/
-#define INTR_RX_DONE_ALT 0x01
+#define INTR_RX_DONE_ALT 0x01
#define INTR_RX_COMP_FULL_ALT 0x02
#define INTR_RX_COMP_AF_ALT 0x04
#define INTR_RX_BUF_UNAVAIL_1 0x08
#define INTR_RX_BUF_AE_1 0x10 /* almost empty */
-#define INTRN_MASK_RX_EN 0x80
+#define INTRN_MASK_RX_EN 0x80
#define INTRN_MASK_CLEAR_ALL (INTR_RX_DONE_ALT | \
INTR_RX_COMP_FULL_ALT | \
INTR_RX_COMP_AF_ALT | \
@@ -399,7 +399,7 @@
register 2 for INTB */
#define REG_PLUS_ALIASN_CLEAR(x) (REG_PLUS_ALIAS_CLEAR_1 + ((x) - 1)*16)
-#define REG_PLUS_INTR_STATUS_ALIAS_1 0x1044 /* Cassini+: interrupt status
+#define REG_PLUS_INTR_STATUS_ALIAS_1 0x1044 /* Cassini+: interrupt status
register alias 2 for INTB */
#define REG_PLUS_INTRN_STATUS_ALIAS(x) (REG_PLUS_INTR_STATUS_ALIAS_1 + ((x) - 1)*16)
@@ -411,18 +411,18 @@
#define SATURN_PCFG_CLA 0x00000004 /* 1 = phy link100led */
#define SATURN_PCFG_LLA 0x00000008 /* 1 = phy link1000led */
#define SATURN_PCFG_RLA 0x00000010 /* 1 = phy duplexled */
-#define SATURN_PCFG_PDS 0x00000020 /* phy debug mode.
+#define SATURN_PCFG_PDS 0x00000020 /* phy debug mode.
0 = normal */
-#define SATURN_PCFG_MTP 0x00000080 /* test point select */
-#define SATURN_PCFG_GMO 0x00000100 /* GMII observe. 1 =
+#define SATURN_PCFG_MTP 0x00000080 /* test point select */
+#define SATURN_PCFG_GMO 0x00000100 /* GMII observe. 1 =
GMII on SERDES pins for
monitoring. */
#define SATURN_PCFG_FSI 0x00000200 /* 1 = freeze serdes/gmii. all
pins configed as outputs.
for power saving when using
internal phy. */
-#define SATURN_PCFG_LAD 0x00000800 /* 0 = mac core led ctrl
- polarity from strapping
+#define SATURN_PCFG_LAD 0x00000800 /* 0 = mac core led ctrl
+ polarity from strapping
value.
1 = mac core led ctrl
polarity active low. */
@@ -433,26 +433,26 @@
#define MAX_TX_RINGS (1 << MAX_TX_RINGS_SHIFT)
#define MAX_TX_RINGS_MASK (MAX_TX_RINGS - 1)
-/* TX configuration.
- * descr ring sizes size = 32 * (1 << n), n < 9. e.g., 0x8 = 8k. default: 0x8
+/* TX configuration.
+ * descr ring sizes size = 32 * (1 << n), n < 9. e.g., 0x8 = 8k. default: 0x8
* DEFAULT: 0x3F000001
*/
#define REG_TX_CFG 0x2004 /* TX config */
#define TX_CFG_DMA_EN 0x00000001 /* enable TX DMA. if cleared, DMA
will stop after xfer of current
buffer has been completed. */
-#define TX_CFG_FIFO_PIO_SEL 0x00000002 /* TX DMA FIFO can be
- accessed w/ FIFO addr
- and data registers.
- TX DMA should be
+#define TX_CFG_FIFO_PIO_SEL 0x00000002 /* TX DMA FIFO can be
+ accessed w/ FIFO addr
+ and data registers.
+ TX DMA should be
disabled. */
#define TX_CFG_DESC_RING0_MASK 0x0000003C /* # desc entries in
ring 1. */
#define TX_CFG_DESC_RING0_SHIFT 2
#define TX_CFG_DESC_RINGN_MASK(a) (TX_CFG_DESC_RING0_MASK << (a)*4)
#define TX_CFG_DESC_RINGN_SHIFT(a) (TX_CFG_DESC_RING0_SHIFT + (a)*4)
-#define TX_CFG_PACED_MODE 0x00100000 /* TX_ALL only set after
- TX FIFO becomes empty.
+#define TX_CFG_PACED_MODE 0x00100000 /* TX_ALL only set after
+ TX FIFO becomes empty.
if 0, TX_ALL set
if descr queue empty. */
#define TX_CFG_DMA_RDPIPE_DIS 0x01000000 /* always set to 1 */
@@ -470,26 +470,26 @@
through Q4 */
#define TX_CFG_INTR_COMPWB_DIS 0x20000000 /* disable pre-interrupt completion
writeback */
-#define TX_CFG_CTX_SEL_MASK 0xC0000000 /* selects tx test port
+#define TX_CFG_CTX_SEL_MASK 0xC0000000 /* selects tx test port
connection
- 0b00: tx mac req,
+ 0b00: tx mac req,
tx mac retry req,
tx ack and tx tag.
- 0b01: txdma rd req,
+ 0b01: txdma rd req,
txdma rd ack,
txdma rd rdy,
txdma rd type0
- 0b11: txdma wr req,
+ 0b11: txdma wr req,
txdma wr ack,
txdma wr rdy,
txdma wr xfr done. */
#define TX_CFG_CTX_SEL_SHIFT 30
-
+
/* 11-bit counters that point to next location in FIFO to be loaded/retrieved.
* used for diagnostics only.
*/
#define REG_TX_FIFO_WRITE_PTR 0x2014 /* TX FIFO write pointer */
-#define REG_TX_FIFO_SHADOW_WRITE_PTR 0x2018 /* TX FIFO shadow write
+#define REG_TX_FIFO_SHADOW_WRITE_PTR 0x2018 /* TX FIFO shadow write
pointer. temp hold reg.
diagnostics only. */
#define REG_TX_FIFO_READ_PTR 0x201C /* TX FIFO read pointer */
@@ -509,7 +509,7 @@
#define TX_SM_1_CACHE_MASK 0x03C00000 /* desc. prefetch cache controller
state machine */
#define TX_SM_1_CBQ_ARB_MASK 0xF8000000 /* CBQ arbiter state machine */
-
+
#define REG_TX_SM_2 0x202C /* TX state machine reg #2 */
#define TX_SM_2_COMP_WB_MASK 0x07 /* completion writeback sm */
#define TX_SM_2_SUB_LOAD_MASK 0x38 /* sub load state machine */
@@ -521,9 +521,9 @@
#define REG_TX_DATA_PTR_LOW 0x2030 /* TX data pointer low */
#define REG_TX_DATA_PTR_HI 0x2034 /* TX data pointer high */
-/* 13 bit registers written by driver w/ descriptor value that follows
+/* 13 bit registers written by driver w/ descriptor value that follows
* last valid xmit descriptor. kick # and complete # values are used by
- * the xmit dma engine to control tx descr fetching. if > 1 valid
+ * the xmit dma engine to control tx descr fetching. if > 1 valid
* tx descr is available within the cache line being read, cassini will
* internally cache up to 4 of them. 0 on reset. _KICK = rw, _COMP = ro.
*/
@@ -532,12 +532,12 @@
#define REG_TX_COMP0 0x2048 /* TX completion reg #1 */
#define REG_TX_COMPN(x) (REG_TX_COMP0 + (x)*4)
-/* values of TX_COMPLETE_1-4 are written. each completion register
- * is 2bytes in size and contiguous. 8B allocation w/ 8B alignment.
+/* values of TX_COMPLETE_1-4 are written. each completion register
+ * is 2bytes in size and contiguous. 8B allocation w/ 8B alignment.
* NOTE: completion reg values are only written back prior to TX_INTME and
- * TX_ALL interrupts. at all other times, the most up-to-date index values
- * should be obtained from the REG_TX_COMPLETE_# registers.
- * here's the layout:
+ * TX_ALL interrupts. at all other times, the most up-to-date index values
+ * should be obtained from the REG_TX_COMPLETE_# registers.
+ * here's the layout:
* offset from base addr completion # byte
* 0 TX_COMPLETE_1_MSB
* 1 TX_COMPLETE_1_LSB
@@ -558,7 +558,7 @@
#define TX_COMPWB_LSB_MASK 0x000000000000FF00ULL
#define TX_COMPWB_LSB_SHIFT 8
#define TX_COMPWB_NEXT(x) ((x) >> 16)
-
+
/* 53 MSB used as base address. 11 LSB assumed to be 0. TX desc pointer must
* be 2KB-aligned. */
#define REG_TX_DB0_LOW 0x2060 /* TX descriptor base low #1 */
@@ -594,11 +594,11 @@
#define REG_TX_FIFO_DATA_HI_T0 0x2114 /* TX FIFO data high t0 */
#define REG_TX_FIFO_SIZE 0x2118 /* (ro) TX FIFO size = 0x090 = 9KB */
-/* 9-bit register controls BIST of TX FIFO. bit set indicates that the BIST
+/* 9-bit register controls BIST of TX FIFO. bit set indicates that the BIST
* passed for the specified memory
*/
#define REG_TX_RAMBIST 0x211C /* TX RAMBIST control/status */
-#define TX_RAMBIST_STATE 0x01C0 /* progress state of RAMBIST
+#define TX_RAMBIST_STATE 0x01C0 /* progress state of RAMBIST
controller state machine */
#define TX_RAMBIST_RAM33A_PASS 0x0020 /* RAM33A passed */
#define TX_RAMBIST_RAM32A_PASS 0x0010 /* RAM32A passed */
@@ -612,33 +612,33 @@
#define MAX_RX_DESC_RINGS 2
#define MAX_RX_COMP_RINGS 4
-/* receive DMA channel configuration. default: 0x80910
+/* receive DMA channel configuration. default: 0x80910
* free ring size = (1 << n)*32 -> [32 - 8k]
- * completion ring size = (1 << n)*128 -> [128 - 32k], n < 9
+ * completion ring size = (1 << n)*128 -> [128 - 32k], n < 9
* DEFAULT: 0x80910
*/
#define REG_RX_CFG 0x4000 /* RX config */
#define RX_CFG_DMA_EN 0x00000001 /* enable RX DMA. 0 stops
channel as soon as current
frame xfer has completed.
- driver should disable MAC
- for 200ms before disabling
+ driver should disable MAC
+ for 200ms before disabling
RX */
-#define RX_CFG_DESC_RING_MASK 0x0000001E /* # desc entries in RX
- free desc ring.
+#define RX_CFG_DESC_RING_MASK 0x0000001E /* # desc entries in RX
+ free desc ring.
def: 0x8 = 8k */
#define RX_CFG_DESC_RING_SHIFT 1
#define RX_CFG_COMP_RING_MASK 0x000001E0 /* # desc entries in RX complete
ring. def: 0x8 = 32k */
#define RX_CFG_COMP_RING_SHIFT 5
-#define RX_CFG_BATCH_DIS 0x00000200 /* disable receive desc
+#define RX_CFG_BATCH_DIS 0x00000200 /* disable receive desc
batching. def: 0x0 =
enabled */
-#define RX_CFG_SWIVEL_MASK 0x00001C00 /* byte offset of the 1st
- data byte of the packet
+#define RX_CFG_SWIVEL_MASK 0x00001C00 /* byte offset of the 1st
+ data byte of the packet
w/in 8 byte boundares.
- this swivels the data
- DMA'ed to header
+ this swivels the data
+ DMA'ed to header
buffers, jumbo buffers
when header split is not
requested and MTU sized
@@ -647,17 +647,17 @@
/* cassini+ only */
#define RX_CFG_DESC_RING1_MASK 0x000F0000 /* # of desc entries in
- RX free desc ring 2.
+ RX free desc ring 2.
def: 0x8 = 8k */
#define RX_CFG_DESC_RING1_SHIFT 16
-/* the page size register allows cassini chips to do the following with
+/* the page size register allows cassini chips to do the following with
* received data:
* [--------------------------------------------------------------] page
* [off][buf1][pad][off][buf2][pad][off][buf3][pad][off][buf4][pad]
* |--------------| = PAGE_SIZE_BUFFER_STRIDE
- * page = PAGE_SIZE
+ * page = PAGE_SIZE
* offset = PAGE_SIZE_MTU_OFF
* for the above example, MTU_BUFFER_COUNT = 4.
* NOTE: as is apparent, you need to ensure that the following holds:
@@ -667,20 +667,20 @@
#define REG_RX_PAGE_SIZE 0x4004 /* RX page size */
#define RX_PAGE_SIZE_MASK 0x00000003 /* size of pages pointed to
by receive descriptors.
- if jumbo buffers are
- supported the page size
+ if jumbo buffers are
+ supported the page size
should not be < 8k.
0b00 = 2k, 0b01 = 4k
0b10 = 8k, 0b11 = 16k
DEFAULT: 8k */
#define RX_PAGE_SIZE_SHIFT 0
#define RX_PAGE_SIZE_MTU_COUNT_MASK 0x00007800 /* # of MTU buffers the hw
- packs into a page.
+ packs into a page.
DEFAULT: 4 */
#define RX_PAGE_SIZE_MTU_COUNT_SHIFT 11
#define RX_PAGE_SIZE_MTU_STRIDE_MASK 0x18000000 /* # of bytes that separate
- each MTU buffer +
- offset from each
+ each MTU buffer +
+ offset from each
other.
0b00 = 1k, 0b01 = 2k
0b10 = 4k, 0b11 = 8k
@@ -688,24 +688,24 @@
#define RX_PAGE_SIZE_MTU_STRIDE_SHIFT 27
#define RX_PAGE_SIZE_MTU_OFF_MASK 0xC0000000 /* offset in each page that
hw writes the MTU buffer
- into.
- 0b00 = 0,
+ into.
+ 0b00 = 0,
0b01 = 64 bytes
0b10 = 96, 0b11 = 128
DEFAULT: 0x1 */
#define RX_PAGE_SIZE_MTU_OFF_SHIFT 30
-
-/* 11-bit counter points to next location in RX FIFO to be loaded/read.
+
+/* 11-bit counter points to next location in RX FIFO to be loaded/read.
* shadow write pointers enable retries in case of early receive aborts.
* DEFAULT: 0x0. generated on 64-bit boundaries.
*/
#define REG_RX_FIFO_WRITE_PTR 0x4008 /* RX FIFO write pointer */
#define REG_RX_FIFO_READ_PTR 0x400C /* RX FIFO read pointer */
-#define REG_RX_IPP_FIFO_SHADOW_WRITE_PTR 0x4010 /* RX IPP FIFO shadow write
+#define REG_RX_IPP_FIFO_SHADOW_WRITE_PTR 0x4010 /* RX IPP FIFO shadow write
pointer */
#define REG_RX_IPP_FIFO_SHADOW_READ_PTR 0x4014 /* RX IPP FIFO shadow read
pointer */
-#define REG_RX_IPP_FIFO_READ_PTR 0x400C /* RX IPP FIFO read
+#define REG_RX_IPP_FIFO_READ_PTR 0x400C /* RX IPP FIFO read
pointer. (8-bit counter) */
/* current state of RX DMA state engines + other info
@@ -738,7 +738,7 @@
0x2 = wait xon
0x3 = wait xon ack */
#define RX_DEBUG_DATA_STATE_MASK 0x000001E00 /* unload data state machine
- states:
+ states:
0x0 = idle data
0x1 = header begin
0x2 = xfer header
@@ -747,7 +747,7 @@
0x5 = xfer mtu
0x6 = xfer mtu ld
0x7 = jumbo begin
- 0x8 = xfer jumbo
+ 0x8 = xfer jumbo
0x9 = xfer jumbo ld
0xa = reas begin
0xb = xfer reas
@@ -776,15 +776,15 @@
* XOFF PAUSE uses pause time value pre-programmed in the Send PAUSE MAC reg
* XON PAUSE uses a pause time of 0. granularity of threshold is 64bytes.
* PAUSE thresholds defined in terms of FIFO occupancy and may be translated
- * into FIFO vacancy using RX_FIFO_SIZE. setting ON will trigger XON frames
+ * into FIFO vacancy using RX_FIFO_SIZE. setting ON will trigger XON frames
* when FIFO reaches 0. OFF threshold should not be > size of RX FIFO. max
- * value is is 0x6F.
+ * value is is 0x6F.
* DEFAULT: 0x00078
*/
#define REG_RX_PAUSE_THRESH 0x4020 /* RX pause thresholds */
#define RX_PAUSE_THRESH_QUANTUM 64
#define RX_PAUSE_THRESH_OFF_MASK 0x000001FF /* XOFF PAUSE emitted when
- RX FIFO occupancy >
+ RX FIFO occupancy >
value*64B */
#define RX_PAUSE_THRESH_OFF_SHIFT 0
#define RX_PAUSE_THRESH_ON_MASK 0x001FF000 /* XON PAUSE emitted after
@@ -797,9 +797,9 @@
#define RX_PAUSE_THRESH_ON_SHIFT 12
/* 13-bit register used to control RX desc fetching and intr generation. if 4+
- * valid RX descriptors are available, Cassini will read 4 at a time.
+ * valid RX descriptors are available, Cassini will read 4 at a time.
* writing N means that all desc up to *but* excluding N are available. N must
- * be a multiple of 4 (N % 4 = 0). first desc should be cache-line aligned.
+ * be a multiple of 4 (N % 4 = 0). first desc should be cache-line aligned.
* DEFAULT: 0 on reset
*/
#define REG_RX_KICK 0x4024 /* RX kick reg */
@@ -807,16 +807,16 @@
/* 8KB aligned 64-bit pointer to the base of the RX free/completion rings.
* lower 13 bits of the low register are hard-wired to 0.
*/
-#define REG_RX_DB_LOW 0x4028 /* RX descriptor ring
+#define REG_RX_DB_LOW 0x4028 /* RX descriptor ring
base low */
#define REG_RX_DB_HI 0x402C /* RX descriptor ring
base hi */
#define REG_RX_CB_LOW 0x4030 /* RX completion ring
base low */
-#define REG_RX_CB_HI 0x4034 /* RX completion ring
+#define REG_RX_CB_HI 0x4034 /* RX completion ring
base hi */
/* 13-bit register indicate desc used by cassini for receive frames. used
- * for diagnostic purposes.
+ * for diagnostic purposes.
* DEFAULT: 0 on reset
*/
#define REG_RX_COMP 0x4038 /* (ro) RX completion */
@@ -837,9 +837,9 @@
/* values used for receive interrupt blanking. loaded each time the ISR is read
* DEFAULT: 0x00000000
*/
-#define REG_RX_BLANK 0x4044 /* RX blanking register
+#define REG_RX_BLANK 0x4044 /* RX blanking register
for ISR read */
-#define RX_BLANK_INTR_PKT_MASK 0x000001FF /* RX_DONE intr asserted if
+#define RX_BLANK_INTR_PKT_MASK 0x000001FF /* RX_DONE intr asserted if
this many sets of completion
writebacks (up to 2 packets)
occur since the last time
@@ -849,33 +849,33 @@
#define RX_BLANK_INTR_TIME_MASK 0x3FFFF000 /* RX_DONE interrupt asserted
if that many clocks were
counted since last time the
- ISR was read.
+ ISR was read.
each count is 512 core
clocks (125MHz). 0 = no
time blanking */
#define RX_BLANK_INTR_TIME_SHIFT 12
-/* values used for interrupt generation based on threshold values of how
+/* values used for interrupt generation based on threshold values of how
* many free desc and completion entries are available for hw use.
* DEFAULT: 0x00000000
*/
-#define REG_RX_AE_THRESH 0x4048 /* RX almost empty
+#define REG_RX_AE_THRESH 0x4048 /* RX almost empty
thresholds */
-#define RX_AE_THRESH_FREE_MASK 0x00001FFF /* RX_BUF_AE will be
+#define RX_AE_THRESH_FREE_MASK 0x00001FFF /* RX_BUF_AE will be
generated if # desc
- avail for hw use <=
+ avail for hw use <=
# */
#define RX_AE_THRESH_FREE_SHIFT 0
#define RX_AE_THRESH_COMP_MASK 0x0FFFE000 /* RX_COMP_AE will be
- generated if # of
+ generated if # of
completion entries
- avail for hw use <=
+ avail for hw use <=
# */
#define RX_AE_THRESH_COMP_SHIFT 13
-/* probabilities for random early drop (RED) thresholds on a FIFO threshold
- * basis. probability should increase when the FIFO level increases. control
- * packets are never dropped and not counted in stats. probability programmed
+/* probabilities for random early drop (RED) thresholds on a FIFO threshold
+ * basis. probability should increase when the FIFO level increases. control
+ * packets are never dropped and not counted in stats. probability programmed
* on a 12.5% granularity. e.g., 0x1 = 1/8 packets dropped.
* DEFAULT: 0x00000000
*/
@@ -885,8 +885,8 @@
#define RX_RED_8K_10K_FIFO_MASK 0x00FF0000 /* 8KB < FIFO thresh < 10KB */
#define RX_RED_10K_12K_FIFO_MASK 0xFF000000 /* 10KB < FIFO thresh < 12KB */
-/* FIFO fullness levels for RX FIFO, RX control FIFO, and RX IPP FIFO.
- * RX control FIFO = # of packets in RX FIFO.
+/* FIFO fullness levels for RX FIFO, RX control FIFO, and RX IPP FIFO.
+ * RX control FIFO = # of packets in RX FIFO.
* DEFAULT: 0x0
*/
#define REG_RX_FIFO_FULLNESS 0x4050 /* (ro) RX FIFO fullness */
@@ -895,12 +895,12 @@
#define RX_FIFO_FULLNESS_RX_PKT_MASK 0x000000FF /* # packets in RX FIFO */
#define REG_RX_IPP_PACKET_COUNT 0x4054 /* RX IPP packet counter */
#define REG_RX_WORK_DMA_PTR_LOW 0x4058 /* RX working DMA ptr low */
-#define REG_RX_WORK_DMA_PTR_HI 0x405C /* RX working DMA ptr
+#define REG_RX_WORK_DMA_PTR_HI 0x405C /* RX working DMA ptr
high */
/* BIST testing ro RX FIFO, RX control FIFO, and RX IPP FIFO. only RX BIST
* START/COMPLETE is writeable. START will clear when the BIST has completed
- * checking all 17 RAMS.
+ * checking all 17 RAMS.
* DEFAULT: 0bxxxx xxxxx xxxx xxxx xxxx x000 0000 0000 00x0
*/
#define REG_RX_BIST 0x4060 /* (ro) RX BIST */
@@ -923,41 +923,41 @@
#define RX_BIST_REAS_27_PASS 0x00080000 /* RX Reas 27 passed */
#define RX_BIST_STATE_MASK 0x00078000 /* BIST state machine */
#define RX_BIST_SUMMARY 0x00000002 /* when BIST complete,
- summary pass bit
+ summary pass bit
contains AND of BIST
results of all 16
RAMS */
-#define RX_BIST_START 0x00000001 /* write 1 to start
+#define RX_BIST_START 0x00000001 /* write 1 to start
BIST. self clears
on completion. */
/* next location in RX CTRL FIFO that will be loaded w/ data from RX IPP/read
- * from to retrieve packet control info.
+ * from to retrieve packet control info.
* DEFAULT: 0
*/
-#define REG_RX_CTRL_FIFO_WRITE_PTR 0x4064 /* (ro) RX control FIFO
+#define REG_RX_CTRL_FIFO_WRITE_PTR 0x4064 /* (ro) RX control FIFO
write ptr */
#define REG_RX_CTRL_FIFO_READ_PTR 0x4068 /* (ro) RX control FIFO read
ptr */
/* receive interrupt blanking. loaded each time interrupt alias register is
- * read.
+ * read.
* DEFAULT: 0x0
*/
#define REG_RX_BLANK_ALIAS_READ 0x406C /* RX blanking register for
alias read */
-#define RX_BAR_INTR_PACKET_MASK 0x000001FF /* assert RX_DONE if #
- completion writebacks
- > # since last ISR
- read. 0 = no
- blanking. up to 2
- packets per
+#define RX_BAR_INTR_PACKET_MASK 0x000001FF /* assert RX_DONE if #
+ completion writebacks
+ > # since last ISR
+ read. 0 = no
+ blanking. up to 2
+ packets per
completion wb. */
#define RX_BAR_INTR_TIME_MASK 0x3FFFF000 /* assert RX_DONE if #
clocks > # since last
ISR read. each count
is 512 core clocks
- (125MHz). 0 = no
+ (125MHz). 0 = no
blanking. */
/* diagnostic access to RX FIFO. 32 LSB accessed via DATA_LOW. 32 MSB accessed
@@ -981,13 +981,13 @@
* should be last write access of the write sequence.
* DEFAULT: undefined
*/
-#define REG_RX_CTRL_FIFO_ADDR 0x4094 /* RX Control FIFO and
+#define REG_RX_CTRL_FIFO_ADDR 0x4094 /* RX Control FIFO and
Batching FIFO addr */
-#define REG_RX_CTRL_FIFO_DATA_LOW 0x4098 /* RX Control FIFO data
+#define REG_RX_CTRL_FIFO_DATA_LOW 0x4098 /* RX Control FIFO data
low */
-#define REG_RX_CTRL_FIFO_DATA_MID 0x409C /* RX Control FIFO data
+#define REG_RX_CTRL_FIFO_DATA_MID 0x409C /* RX Control FIFO data
mid */
-#define REG_RX_CTRL_FIFO_DATA_HI 0x4100 /* RX Control FIFO data
+#define REG_RX_CTRL_FIFO_DATA_HI 0x4100 /* RX Control FIFO data
hi and flow id */
#define RX_CTRL_FIFO_DATA_HI_CTRL 0x0001 /* upper bit of ctrl word */
#define RX_CTRL_FIFO_DATA_HI_FLOW_MASK 0x007E /* flow id */
@@ -1004,7 +1004,7 @@
T1 */
/* 64-bit pointer to receive data buffer in host memory used for headers and
- * small packets. MSB in high register. loaded by DMA state machine and
+ * small packets. MSB in high register. loaded by DMA state machine and
* increments as DMA writes receive data. only 50 LSB are incremented. top
* 13 bits taken from RX descriptor.
* DEFAULT: undefined
@@ -1013,17 +1013,17 @@
low */
#define REG_RX_HEADER_PAGE_PTR_HI 0x411C /* (ro) RX header page ptr
high */
-#define REG_RX_MTU_PAGE_PTR_LOW 0x4120 /* (ro) RX MTU page pointer
+#define REG_RX_MTU_PAGE_PTR_LOW 0x4120 /* (ro) RX MTU page pointer
low */
-#define REG_RX_MTU_PAGE_PTR_HI 0x4124 /* (ro) RX MTU page pointer
+#define REG_RX_MTU_PAGE_PTR_HI 0x4124 /* (ro) RX MTU page pointer
high */
/* PIO diagnostic access to RX reassembly DMA Table RAM. 6-bit register holds
* one of 64 79-bit locations in the RX Reassembly DMA table and the addr of
- * one of the 64 byte locations in the Batching table. LOW holds 32 LSB.
+ * one of the 64 byte locations in the Batching table. LOW holds 32 LSB.
* MID holds the next 32 LSB. HIGH holds the 15 MSB. RX_DMA_EN must be set
* to 0 for PIO access. DATA_HIGH should be last write of write sequence.
- * layout:
+ * layout:
* reassmbl ptr [78:15] | reassmbl index [14:1] | reassmbl entry valid [0]
* DEFAULT: undefined
*/
@@ -1033,7 +1033,7 @@
#define REG_RX_TABLE_DATA_LOW 0x412C /* RX reassembly DMA table
data low */
-#define REG_RX_TABLE_DATA_MID 0x4130 /* RX reassembly DMA table
+#define REG_RX_TABLE_DATA_MID 0x4130 /* RX reassembly DMA table
data mid */
#define REG_RX_TABLE_DATA_HI 0x4134 /* RX reassembly DMA table
data high */
@@ -1053,11 +1053,11 @@
#define REG_PLUS_RX_CBN_LOW(x) (REG_PLUS_RX_CB1_LOW + 8*((x) - 1))
#define REG_PLUS_RX_CBN_HI(x) (REG_PLUS_RX_CB1_HI + 8*((x) - 1))
#define REG_PLUS_RX_KICK1 0x4220 /* RX Kick 2 register */
-#define REG_PLUS_RX_COMP1 0x4224 /* (ro) RX completion 2
+#define REG_PLUS_RX_COMP1 0x4224 /* (ro) RX completion 2
reg */
-#define REG_PLUS_RX_COMP1_HEAD 0x4228 /* (ro) RX completion 2
+#define REG_PLUS_RX_COMP1_HEAD 0x4228 /* (ro) RX completion 2
head reg. 4 total. */
-#define REG_PLUS_RX_COMP1_TAIL 0x422C /* RX completion 2
+#define REG_PLUS_RX_COMP1_TAIL 0x422C /* RX completion 2
tail reg. 4 total. */
#define REG_PLUS_RX_COMPN_HEAD(x) (REG_PLUS_RX_COMP1_HEAD + 8*((x) - 1))
#define REG_PLUS_RX_COMPN_TAIL(x) (REG_PLUS_RX_COMP1_TAIL + 8*((x) - 1))
@@ -1068,13 +1068,13 @@
/** header parser registers **/
-/* RX parser configuration register.
+/* RX parser configuration register.
* DEFAULT: 0x1651004
*/
-#define REG_HP_CFG 0x4140 /* header parser
+#define REG_HP_CFG 0x4140 /* header parser
configuration reg */
#define HP_CFG_PARSE_EN 0x00000001 /* enab header parsing */
-#define HP_CFG_NUM_CPU_MASK 0x000000FC /* # processors
+#define HP_CFG_NUM_CPU_MASK 0x000000FC /* # processors
0 = 64. 0x3f = 63 */
#define HP_CFG_NUM_CPU_SHIFT 2
#define HP_CFG_SYN_INC_MASK 0x00000100 /* SYN bit won't increment
@@ -1088,7 +1088,7 @@
/* access to RX Instruction RAM. 5-bit register/counter holds addr
* of 39 bit entry to be read/written. 32 LSB in _DATA_LOW. 7 MSB in _DATA_HI.
* RX_DMA_EN must be 0 for RX instr PIO access. DATA_HI should be last access
- * of sequence.
+ * of sequence.
* DEFAULT: undefined
*/
#define REG_HP_INSTR_RAM_ADDR 0x4144 /* HP instruction RAM
@@ -1104,7 +1104,7 @@
#define HP_INSTR_RAM_LOW_OUTEN_SHIFT 20
#define HP_INSTR_RAM_LOW_OUTARG_MASK 0xFFC00000
#define HP_INSTR_RAM_LOW_OUTARG_SHIFT 22
-#define REG_HP_INSTR_RAM_DATA_MID 0x414C /* HP instruction RAM
+#define REG_HP_INSTR_RAM_DATA_MID 0x414C /* HP instruction RAM
data mid */
#define HP_INSTR_RAM_MID_OUTARG_MASK 0x00000003
#define HP_INSTR_RAM_MID_OUTARG_SHIFT 0
@@ -1131,7 +1131,7 @@
* 11-bit register. Data fills the LSB portion of bus if less than 32 bits.
* DATA_RAM: write RAM_FDB_DATA with index to access DATA_RAM.
* RAM bytes = 4*(x - 1) + [3:0]. e.g., 0 -> [3:0], 31 -> [123:120]
- * FLOWDB: write DATA_RAM_FDB register and then read/write FDB1-12 to access
+ * FLOWDB: write DATA_RAM_FDB register and then read/write FDB1-12 to access
* flow database.
* RX_DMA_EN must be 0 for RX parser RAM PIO access. RX Parser RAM data reg
* should be the last write access of the write sequence.
@@ -1139,17 +1139,17 @@
*/
#define REG_HP_DATA_RAM_FDB_ADDR 0x4154 /* HP data and FDB
RAM address */
-#define HP_DATA_RAM_FDB_DATA_MASK 0x001F /* select 1 of 86 byte
- locations in header
- parser data ram to
+#define HP_DATA_RAM_FDB_DATA_MASK 0x001F /* select 1 of 86 byte
+ locations in header
+ parser data ram to
read/write */
#define HP_DATA_RAM_FDB_FDB_MASK 0x3F00 /* 1 of 64 353-bit locations
in the flow database */
#define REG_HP_DATA_RAM_DATA 0x4158 /* HP data RAM data */
-/* HP flow database registers: 1 - 12, 0x415C - 0x4188, 4 8-bit bytes
+/* HP flow database registers: 1 - 12, 0x415C - 0x4188, 4 8-bit bytes
* FLOW_DB(1) = IP_SA[127:96], FLOW_DB(2) = IP_SA[95:64]
- * FLOW_DB(3) = IP_SA[63:32], FLOW_DB(4) = IP_SA[31:0]
+ * FLOW_DB(3) = IP_SA[63:32], FLOW_DB(4) = IP_SA[31:0]
* FLOW_DB(5) = IP_DA[127:96], FLOW_DB(6) = IP_DA[95:64]
* FLOW_DB(7) = IP_DA[63:32], FLOW_DB(8) = IP_DA[31:0]
* FLOW_DB(9) = {TCP_SP[15:0],TCP_DP[15:0]}
@@ -1159,7 +1159,7 @@
#define REG_HP_FLOW_DB0 0x415C /* HP flow database 1 reg */
#define REG_HP_FLOW_DBN(x) (REG_HP_FLOW_DB0 + (x)*4)
-/* diagnostics for RX Header Parser block.
+/* diagnostics for RX Header Parser block.
* ASUN: the header parser state machine register is used for diagnostics
* purposes. however, the spec doesn't have any details on it.
*/
@@ -1167,7 +1167,7 @@
#define REG_HP_STATUS0 0x4190 /* (ro) HP status 1 */
#define HP_STATUS0_SAP_MASK 0xFFFF0000 /* SAP */
#define HP_STATUS0_L3_OFF_MASK 0x0000FE00 /* L3 offset */
-#define HP_STATUS0_LB_CPUNUM_MASK 0x000001F8 /* load balancing CPU
+#define HP_STATUS0_LB_CPUNUM_MASK 0x000001F8 /* load balancing CPU
number */
#define HP_STATUS0_HRP_OPCODE_MASK 0x00000007 /* HRP opcode */
@@ -1179,11 +1179,11 @@
#define REG_HP_STATUS2 0x4198 /* (ro) HP status 3 */
#define HP_STATUS2_ACCUR2_MASK 0xF0000000 /* accu R2[3:0] */
-#define HP_STATUS2_CSUM_OFF_MASK 0x07F00000 /* checksum start
+#define HP_STATUS2_CSUM_OFF_MASK 0x07F00000 /* checksum start
start offset */
#define HP_STATUS2_ACCUR1_MASK 0x000FE000 /* accu R1 */
#define HP_STATUS2_FORCE_DROP 0x00001000 /* force drop */
-#define HP_STATUS2_BWO_REASSM 0x00000800 /* batching w/o
+#define HP_STATUS2_BWO_REASSM 0x00000800 /* batching w/o
reassembly */
#define HP_STATUS2_JH_SPLIT_EN 0x00000400 /* jumbo header split
enable */
@@ -1191,9 +1191,9 @@
check */
#define HP_STATUS2_DATA_MASK_ZERO 0x00000100 /* mask of data length
equal to zero */
-#define HP_STATUS2_FORCE_TCP_CHECK 0x00000080 /* force tcp payload
+#define HP_STATUS2_FORCE_TCP_CHECK 0x00000080 /* force tcp payload
chk */
-#define HP_STATUS2_MASK_TCP_THRESH 0x00000040 /* mask of payload
+#define HP_STATUS2_MASK_TCP_THRESH 0x00000040 /* mask of payload
threshold */
#define HP_STATUS2_NO_ASSIST 0x00000020 /* no assist */
#define HP_STATUS2_CTRL_PACKET_FLAG 0x00000010 /* control packet flag */
@@ -1214,7 +1214,7 @@
#define HP_RAM_BIST_HP_INSTR2_PASS 0x10000000 /* HP instr ram 2 */
#define HP_RAM_BIST_FDBM_AGE0_PASS 0x08000000 /* FDBM aging RAM0 */
#define HP_RAM_BIST_FDBM_AGE1_PASS 0x04000000 /* FDBM aging RAM1 */
-#define HP_RAM_BIST_FDBM_FLOWID00_PASS 0x02000000 /* FDBM flowid RAM0
+#define HP_RAM_BIST_FDBM_FLOWID00_PASS 0x02000000 /* FDBM flowid RAM0
bank 0 */
#define HP_RAM_BIST_FDBM_FLOWID10_PASS 0x01000000 /* FDBM flowid RAM1
bank 0 */
@@ -1247,25 +1247,25 @@
/* execute a pause flow control frame transmission
DEFAULT: 0x0XXXX */
#define REG_MAC_SEND_PAUSE 0x6008 /* send pause command reg */
-#define MAC_SEND_PAUSE_TIME_MASK 0x0000FFFF /* value of pause time
+#define MAC_SEND_PAUSE_TIME_MASK 0x0000FFFF /* value of pause time
to be sent on network
- in units of slot
+ in units of slot
times */
#define MAC_SEND_PAUSE_SEND 0x00010000 /* send pause flow ctrl
frame on network */
/* bit set indicates that event occurred. auto-cleared when status register
- * is read and have corresponding mask bits in mask register. events will
- * trigger an interrupt if the corresponding mask bit is 0.
+ * is read and have corresponding mask bits in mask register. events will
+ * trigger an interrupt if the corresponding mask bit is 0.
* status register default: 0x00000000
* mask register default = 0xFFFFFFFF on reset
*/
#define REG_MAC_TX_STATUS 0x6010 /* TX MAC status reg */
-#define MAC_TX_FRAME_XMIT 0x0001 /* successful frame
+#define MAC_TX_FRAME_XMIT 0x0001 /* successful frame
transmision */
-#define MAC_TX_UNDERRUN 0x0002 /* terminated frame
+#define MAC_TX_UNDERRUN 0x0002 /* terminated frame
transmission due to
- data starvation in the
+ data starvation in the
xmit data path */
#define MAC_TX_MAX_PACKET_ERR 0x0004 /* frame exceeds max allowed
length passed to TX MAC
@@ -1286,7 +1286,7 @@
#define REG_MAC_RX_STATUS 0x6014 /* RX MAC status reg */
#define MAC_RX_FRAME_RECV 0x0001 /* successful receipt of
a frame */
-#define MAC_RX_OVERFLOW 0x0002 /* dropped frame due to
+#define MAC_RX_OVERFLOW 0x0002 /* dropped frame due to
RX FIFO overflow */
#define MAC_RX_FRAME_COUNT 0x0004 /* rollover of receive frame
counter */
@@ -1294,27 +1294,27 @@
error counter */
#define MAC_RX_CRC_ERR 0x0010 /* rollover of crc error
counter */
-#define MAC_RX_LEN_ERR 0x0020 /* rollover of length
+#define MAC_RX_LEN_ERR 0x0020 /* rollover of length
error counter */
-#define MAC_RX_VIOL_ERR 0x0040 /* rollover of code
+#define MAC_RX_VIOL_ERR 0x0040 /* rollover of code
violation error */
/* DEFAULT: 0xXXXX0000 on reset */
#define REG_MAC_CTRL_STATUS 0x6018 /* MAC control status reg */
-#define MAC_CTRL_PAUSE_RECEIVED 0x00000001 /* successful
- reception of a
- pause control
+#define MAC_CTRL_PAUSE_RECEIVED 0x00000001 /* successful
+ reception of a
+ pause control
frame */
-#define MAC_CTRL_PAUSE_STATE 0x00000002 /* MAC has made a
- transition from
- "not paused" to
+#define MAC_CTRL_PAUSE_STATE 0x00000002 /* MAC has made a
+ transition from
+ "not paused" to
"paused" */
-#define MAC_CTRL_NOPAUSE_STATE 0x00000004 /* MAC has made a
- transition from
+#define MAC_CTRL_NOPAUSE_STATE 0x00000004 /* MAC has made a
+ transition from
"paused" to "not
paused" */
#define MAC_CTRL_PAUSE_TIME_MASK 0xFFFF0000 /* value of pause time
- operand that was
+ operand that was
received in the last
pause flow control
frame */
@@ -1326,13 +1326,13 @@
/* layout identical to CTRL MAC[2:0] */
#define REG_MAC_CTRL_MASK 0x6028 /* MAC control mask reg */
-/* to ensure proper operation, CFG_EN must be cleared to 0 and a delay
+/* to ensure proper operation, CFG_EN must be cleared to 0 and a delay
* imposed before writes to other bits in the TX_MAC_CFG register or any of
* the MAC parameters is performed. delay dependent upon time required to
* transmit a maximum size frame (= MAC_FRAMESIZE_MAX*8/Mbps). e.g.,
- * the delay for a 1518-byte frame on a 100Mbps network is 125us.
- * alternatively, just poll TX_CFG_EN until it reads back as 0.
- * NOTE: on half-duplex 1Gbps, TX_CFG_CARRIER_EXTEND and
+ * the delay for a 1518-byte frame on a 100Mbps network is 125us.
+ * alternatively, just poll TX_CFG_EN until it reads back as 0.
+ * NOTE: on half-duplex 1Gbps, TX_CFG_CARRIER_EXTEND and
* RX_CFG_CARRIER_EXTEND should be set and the SLOT_TIME register should
* be 0x200 (slot time of 512 bytes)
*/
@@ -1340,12 +1340,12 @@
#define MAC_TX_CFG_EN 0x0001 /* enable TX MAC. 0 will
force TXMAC state
machine to remain in
- idle state or to
+ idle state or to
transition to idle state
on completion of an
ongoing packet. */
#define MAC_TX_CFG_IGNORE_CARRIER 0x0002 /* disable CSMA/CD deferral
- process. set to 1 when
+ process. set to 1 when
full duplex and 0 when
half duplex */
#define MAC_TX_CFG_IGNORE_COLL 0x0004 /* disable CSMA/CD backoff
@@ -1353,32 +1353,32 @@
full duplex and 0 when
half duplex */
#define MAC_TX_CFG_IPG_EN 0x0008 /* enable extension of the
- Rx-to-TX IPG. after
- receiving a frame, TX
- MAC will reset its
- deferral process to
+ Rx-to-TX IPG. after
+ receiving a frame, TX
+ MAC will reset its
+ deferral process to
carrier sense for the
amount of time = IPG0 +
- IPG1 and commit to
+ IPG1 and commit to
transmission for time
specified in IPG2. when
0 or when xmitting frames
back-to-pack (Tx-to-Tx
- IPG), TX MAC ignores
+ IPG), TX MAC ignores
IPG0 and will only use
IPG1 for deferral time.
IPG2 still used. */
#define MAC_TX_CFG_NEVER_GIVE_UP_EN 0x0010 /* TX MAC will not easily
- give up on frame
- xmission. if backoff
+ give up on frame
+ xmission. if backoff
algorithm reaches the
ATTEMPT_LIMIT, it will
clear attempts counter
and continue trying to
- send the frame as
- specified by
+ send the frame as
+ specified by
GIVE_UP_LIM. when 0,
- TX MAC will execute
+ TX MAC will execute
standard CSMA/CD prot. */
#define MAC_TX_CFG_NEVER_GIVE_UP_LIM 0x0020 /* when set, TX MAC will
continue to try to xmit
@@ -1386,13 +1386,13 @@
0, TX MAC will continue
to try xmitting until
successful or backoff
- algorithm reaches
+ algorithm reaches
ATTEMPT_LIMIT*16 */
#define MAC_TX_CFG_NO_BACKOFF 0x0040 /* modify CSMA/CD to disable
backoff algorithm. TX
MAC will not back off
after a xmission attempt
- that resulted in a
+ that resulted in a
collision. */
#define MAC_TX_CFG_SLOW_DOWN 0x0080 /* modify CSMA/CD so that
deferral process is reset
@@ -1408,11 +1408,11 @@
packets. when clear, CRC
generation is dependent
upon NO_CRC bit in the
- xmit control word from
+ xmit control word from
TX DMA */
#define MAC_TX_CFG_CARRIER_EXTEND 0x0200 /* enables xmit part of the
- carrier extension
- feature. this allows for
+ carrier extension
+ feature. this allows for
longer collision domains
by extending the carrier
and collision window
@@ -1422,44 +1422,44 @@
for half-duplex at 1Gbps,
clear otherwise. */
-/* when CRC is not stripped, reassembly packets will not contain the CRC.
+/* when CRC is not stripped, reassembly packets will not contain the CRC.
* these will be stripped by HRP because it reassembles layer 4 data, and the
- * CRC is layer 2. however, non-reassembly packets will still contain the CRC
+ * CRC is layer 2. however, non-reassembly packets will still contain the CRC
* when passed to the host. to ensure proper operation, need to wait 3.2ms
* after clearing RX_CFG_EN before writing to any other RX MAC registers
* or other MAC parameters. alternatively, poll RX_CFG_EN until it clears
- * to 0. similary, HASH_FILTER_EN and ADDR_FILTER_EN have the same
+ * to 0. similary, HASH_FILTER_EN and ADDR_FILTER_EN have the same
* restrictions as CFG_EN.
*/
#define REG_MAC_RX_CFG 0x6034 /* RX MAC config reg */
#define MAC_RX_CFG_EN 0x0001 /* enable RX MAC */
#define MAC_RX_CFG_STRIP_PAD 0x0002 /* always program to 0.
feature not supported */
-#define MAC_RX_CFG_STRIP_FCS 0x0004 /* RX MAC will strip the
- last 4 bytes of a
+#define MAC_RX_CFG_STRIP_FCS 0x0004 /* RX MAC will strip the
+ last 4 bytes of a
received frame. */
#define MAC_RX_CFG_PROMISC_EN 0x0008 /* promiscuous mode */
-#define MAC_RX_CFG_PROMISC_GROUP_EN 0x0010 /* accept all valid
+#define MAC_RX_CFG_PROMISC_GROUP_EN 0x0010 /* accept all valid
multicast frames (group
bit in DA field set) */
#define MAC_RX_CFG_HASH_FILTER_EN 0x0020 /* use hash table to filter
multicast addresses */
-#define MAC_RX_CFG_ADDR_FILTER_EN 0x0040 /* cause RX MAC to use
- address filtering regs
+#define MAC_RX_CFG_ADDR_FILTER_EN 0x0040 /* cause RX MAC to use
+ address filtering regs
to filter both unicast
- and multicast
+ and multicast
addresses */
#define MAC_RX_CFG_DISABLE_DISCARD 0x0080 /* pass errored frames to
RX DMA by setting BAD
bit but not Abort bit
- in the status. CRC,
+ in the status. CRC,
framing, and length errs
- will not increment
+ will not increment
error counters. frames
which don't match dest
addr will be passed up
w/ BAD bit set. */
-#define MAC_RX_CFG_CARRIER_EXTEND 0x0100 /* enable reception of
+#define MAC_RX_CFG_CARRIER_EXTEND 0x0100 /* enable reception of
packet bursts generated
by carrier extension
with packet bursting
@@ -1468,18 +1468,18 @@
/* DEFAULT: 0x0 */
#define REG_MAC_CTRL_CFG 0x6038 /* MAC control config reg */
-#define MAC_CTRL_CFG_SEND_PAUSE_EN 0x0001 /* respond to requests for
- sending pause flow ctrl
+#define MAC_CTRL_CFG_SEND_PAUSE_EN 0x0001 /* respond to requests for
+ sending pause flow ctrl
frames */
-#define MAC_CTRL_CFG_RECV_PAUSE_EN 0x0002 /* respond to received
+#define MAC_CTRL_CFG_RECV_PAUSE_EN 0x0002 /* respond to received
pause flow ctrl frames */
#define MAC_CTRL_CFG_PASS_CTRL 0x0004 /* pass valid MAC ctrl
packets to RX DMA */
/* to ensure proper operation, a global initialization sequence should be
* performed when a loopback config is entered or exited. if programmed after
- * a hw or global sw reset, RX/TX MAC software reset and initialization
- * should be done to ensure stable clocking.
+ * a hw or global sw reset, RX/TX MAC software reset and initialization
+ * should be done to ensure stable clocking.
* DEFAULT: 0x0
*/
#define REG_MAC_XIF_CFG 0x603C /* XIF config reg */
@@ -1489,26 +1489,26 @@
path to GMII recv data
path. phy mode register
clock selection must be
- set to GMII mode and
+ set to GMII mode and
GMII_MODE should be set
to 1. in loopback mode,
REFCLK will drive the
entire mac core. 0 for
normal operation. */
#define MAC_XIF_DISABLE_ECHO 0x0004 /* disables receive data
- path during packet
+ path during packet
xmission. clear to 0
in any full duplex mode,
in any loopback mode,
or in half-duplex SERDES
or SLINK modes. set when
- in half-duplex when
+ in half-duplex when
using external phy. */
#define MAC_XIF_GMII_MODE 0x0008 /* MAC operates with GMII
clocks and datapath */
#define MAC_XIF_MII_BUFFER_OUTPUT_EN 0x0010 /* MII_BUF_EN pin. enable
external tristate buffer
- on the MII receive
+ on the MII receive
bus. */
#define MAC_XIF_LINK_LED 0x0020 /* LINKLED# active (low) */
#define MAC_XIF_FDPLX_LED 0x0040 /* FDPLXLED# active (low) */
@@ -1521,7 +1521,7 @@
recommended: 0x04 */
#define REG_MAC_SLOT_TIME 0x604C /* slot time reg
recommended: 0x40 */
-#define REG_MAC_FRAMESIZE_MIN 0x6050 /* min frame size reg
+#define REG_MAC_FRAMESIZE_MIN 0x6050 /* min frame size reg
recommended: 0x40 */
/* FRAMESIZE_MAX holds both the max frame size as well as the max burst size.
@@ -1536,39 +1536,39 @@
preamble bytes that the
TX MAC will xmit at the
beginning of each frame
- value should be 2 or
- greater. recommended
+ value should be 2 or
+ greater. recommended
value: 0x07 */
-#define REG_MAC_JAM_SIZE 0x605C /* jam size reg. duration
+#define REG_MAC_JAM_SIZE 0x605C /* jam size reg. duration
of jam in units of media
byte time. recommended
value: 0x04 */
#define REG_MAC_ATTEMPT_LIMIT 0x6060 /* attempt limit reg. #
of attempts TX MAC will
- make to xmit a frame
+ make to xmit a frame
before it resets its
attempts counter. after
- the limit has been
+ the limit has been
reached, TX MAC may or
may not drop the frame
dependent upon value
- in TX_MAC_CFG.
- recommended
+ in TX_MAC_CFG.
+ recommended
value: 0x10 */
#define REG_MAC_CTRL_TYPE 0x6064 /* MAC control type reg.
- type field of a MAC
+ type field of a MAC
ctrl frame. recommended
value: 0x8808 */
/* mac address registers: 0 - 44, 0x6080 - 0x6130, 4 8-bit bytes.
- * register contains comparison
+ * register contains comparison
* 0 16 MSB of primary MAC addr [47:32] of DA field
* 1 16 middle bits "" [31:16] of DA field
* 2 16 LSB "" [15:0] of DA field
* 3*x 16MSB of alt MAC addr 1-15 [47:32] of DA field
* 4*x 16 middle bits "" [31:16]
* 5*x 16 LSB "" [15:0]
- * 42 16 MSB of MAC CTRL addr [47:32] of DA.
+ * 42 16 MSB of MAC CTRL addr [47:32] of DA.
* 43 16 middle bits "" [31:16]
* 44 16 LSB "" [15:0]
* MAC CTRL addr must be the reserved multicast addr for MAC CTRL frames.
@@ -1586,39 +1586,39 @@
#define REG_MAC_ADDRN(x) (REG_MAC_ADDR0 + (x)*4)
#define REG_MAC_ADDR_FILTER0 0x614C /* address filter 0 reg
[47:32] */
-#define REG_MAC_ADDR_FILTER1 0x6150 /* address filter 1 reg
+#define REG_MAC_ADDR_FILTER1 0x6150 /* address filter 1 reg
[31:16] */
-#define REG_MAC_ADDR_FILTER2 0x6154 /* address filter 2 reg
+#define REG_MAC_ADDR_FILTER2 0x6154 /* address filter 2 reg
[15:0] */
#define REG_MAC_ADDR_FILTER2_1_MASK 0x6158 /* address filter 2 and 1
mask reg. 8-bit reg
contains nibble mask for
reg 2 and 1. */
-#define REG_MAC_ADDR_FILTER0_MASK 0x615C /* address filter 0 mask
+#define REG_MAC_ADDR_FILTER0_MASK 0x615C /* address filter 0 mask
reg */
-/* hash table registers: 0 - 15, 0x6160 - 0x619C, 4 8-bit bytes
+/* hash table registers: 0 - 15, 0x6160 - 0x619C, 4 8-bit bytes
* 16-bit registers contain bits of the hash table.
- * reg x -> [16*(15 - x) + 15 : 16*(15 - x)].
+ * reg x -> [16*(15 - x) + 15 : 16*(15 - x)].
* e.g., 15 -> [15:0], 0 -> [255:240]
*/
#define REG_MAC_HASH_TABLE0 0x6160 /* hash table 0 reg */
#define REG_MAC_HASH_TABLEN(x) (REG_MAC_HASH_TABLE0 + (x)*4)
-/* statistics registers. these registers generate an interrupt on
+/* statistics registers. these registers generate an interrupt on
* overflow. recommended initialization: 0x0000. most are 16-bits except
* for PEAK_ATTEMPTS register which is 8 bits.
*/
-#define REG_MAC_COLL_NORMAL 0x61A0 /* normal collision
+#define REG_MAC_COLL_NORMAL 0x61A0 /* normal collision
counter. */
#define REG_MAC_COLL_FIRST 0x61A4 /* first attempt
- successful collision
+ successful collision
counter */
-#define REG_MAC_COLL_EXCESS 0x61A8 /* excessive collision
+#define REG_MAC_COLL_EXCESS 0x61A8 /* excessive collision
counter */
#define REG_MAC_COLL_LATE 0x61AC /* late collision counter */
-#define REG_MAC_TIMER_DEFER 0x61B0 /* defer timer. time base
- is the media byte
+#define REG_MAC_TIMER_DEFER 0x61B0 /* defer timer. time base
+ is the media byte
clock/256 */
#define REG_MAC_ATTEMPTS_PEAK 0x61B4 /* peak attempts reg */
#define REG_MAC_RECV_FRAME 0x61B8 /* receive frame counter */
@@ -1633,13 +1633,13 @@
10-bit register used as a
seed for the random number
generator for the CSMA/CD
- backoff algorithm. only
+ backoff algorithm. only
programmed after power-on
- reset and should be a
- random value which has a
- high likelihood of being
- unique for each MAC
- attached to a network
+ reset and should be a
+ random value which has a
+ high likelihood of being
+ unique for each MAC
+ attached to a network
segment (e.g., 10 LSB of
MAC address) */
@@ -1649,7 +1649,7 @@
/* 27-bit register has the current state for key state machines in the MAC */
#define REG_MAC_STATE_MACHINE 0x61D0 /* (ro) state machine reg */
-#define MAC_SM_RLM_MASK 0x07800000
+#define MAC_SM_RLM_MASK 0x07800000
#define MAC_SM_RLM_SHIFT 23
#define MAC_SM_RX_FC_MASK 0x00700000
#define MAC_SM_RX_FC_SHIFT 20
@@ -1666,26 +1666,26 @@
#define MAC_SM_TX_FIFO_EMPTY_MASK 0x00000007
#define MAC_SM_TX_FIFO_EMPTY_SHIFT 0
-/** MIF registers. the MIF can be programmed in either bit-bang or
+/** MIF registers. the MIF can be programmed in either bit-bang or
* frame mode.
**/
#define REG_MIF_BIT_BANG_CLOCK 0x6200 /* MIF bit-bang clock.
- 1 -> 0 will generate a
+ 1 -> 0 will generate a
rising edge. 0 -> 1 will
generate a falling edge. */
#define REG_MIF_BIT_BANG_DATA 0x6204 /* MIF bit-bang data. 1-bit
register generates data */
-#define REG_MIF_BIT_BANG_OUTPUT_EN 0x6208 /* MIF bit-bang output
- enable. enable when
+#define REG_MIF_BIT_BANG_OUTPUT_EN 0x6208 /* MIF bit-bang output
+ enable. enable when
xmitting data from MIF to
transceiver. */
-/* 32-bit register serves as an instruction register when the MIF is
+/* 32-bit register serves as an instruction register when the MIF is
* programmed in frame mode. load this register w/ a valid instruction
* (as per IEEE 802.3u MII spec). poll this register to check for instruction
* execution completion. during a read operation, this register will also
- * contain the 16-bit data returned by the tranceiver. unless specified
- * otherwise, fields are considered "don't care" when polling for
+ * contain the 16-bit data returned by the tranceiver. unless specified
+ * otherwise, fields are considered "don't care" when polling for
* completion.
*/
#define REG_MIF_FRAME 0x620C /* MIF frame/output reg */
@@ -1693,14 +1693,14 @@
load w/ 01 when
issuing an instr */
#define MIF_FRAME_ST 0x40000000 /* STart of frame */
-#define MIF_FRAME_OPCODE_MASK 0x30000000 /* opcode. 01 for a
- write. 10 for a
+#define MIF_FRAME_OPCODE_MASK 0x30000000 /* opcode. 01 for a
+ write. 10 for a
read */
#define MIF_FRAME_OP_READ 0x20000000 /* read OPcode */
#define MIF_FRAME_OP_WRITE 0x10000000 /* write OPcode */
#define MIF_FRAME_PHY_ADDR_MASK 0x0F800000 /* phy address. when
issuing an instr,
- this field should be
+ this field should be
loaded w/ the XCVR
addr */
#define MIF_FRAME_PHY_ADDR_SHIFT 23
@@ -1724,12 +1724,12 @@
to be written in
transceiver reg for a
write. doesn't matter
- in a read. when
- polling for
+ in a read. when
+ polling for
completion, field is
"don't care" for write
- and 16-bit data
- returned by the
+ and 16-bit data
+ returned by the
transceiver for a
read (if valid bit
is set) */
@@ -1748,16 +1748,16 @@
#define MIF_CFG_POLL_REG_SHIFT 3
#define MIF_CFG_MDIO_0 0x0100 /* (ro) dual purpose.
when MDIO_0 is idle,
- 1 -> tranceiver is
+ 1 -> tranceiver is
connected to MDIO_0.
when MIF is communicating
- w/ MDIO_0 in bit-bang
+ w/ MDIO_0 in bit-bang
mode, this bit indicates
the incoming bit stream
during a read op */
#define MIF_CFG_MDIO_1 0x0200 /* (ro) dual purpose.
- when MDIO_1 is idle,
- 1 -> transceiver is
+ when MDIO_1 is idle,
+ 1 -> transceiver is
connected to MDIO_1.
when MIF is communicating
w/ MDIO_1 in bit-bang
@@ -1770,7 +1770,7 @@
/* 16-bit register used to determine which bits in the POLL_STATUS portion of
* the MIF_STATUS register will cause an interrupt. if a mask bit is 0,
- * corresponding bit of the POLL_STATUS will generate a MIF interrupt when
+ * corresponding bit of the POLL_STATUS will generate a MIF interrupt when
* set. DEFAULT: 0xFFFF
*/
#define REG_MIF_MASK 0x6214 /* MIF mask reg */
@@ -1779,7 +1779,7 @@
#define REG_MIF_STATUS 0x6218 /* MIF status reg */
#define MIF_STATUS_POLL_DATA_MASK 0xFFFF0000 /* poll data contains
the "latest image"
- update of the XCVR
+ update of the XCVR
reg being read */
#define MIF_STATUS_POLL_DATA_SHIFT 16
#define MIF_STATUS_POLL_STATUS_MASK 0x0000FFFF /* poll status indicates
@@ -1792,19 +1792,19 @@
/* 7-bit register has current state for all state machines in the MIF */
#define REG_MIF_STATE_MACHINE 0x621C /* MIF state machine reg */
-#define MIF_SM_CONTROL_MASK 0x07 /* control state machine
+#define MIF_SM_CONTROL_MASK 0x07 /* control state machine
state */
#define MIF_SM_EXECUTION_MASK 0x60 /* execution state machine
state */
/** PCS/Serialink. the following registers are equivalent to the standard
- * MII management registers except that they're directly mapped in
+ * MII management registers except that they're directly mapped in
* Cassini's register space.
**/
/* the auto-negotiation enable bit should be programmed the same at
* the link partner as in the local device to enable auto-negotiation to
- * complete. when that bit is reprogrammed, auto-neg/manual config is
+ * complete. when that bit is reprogrammed, auto-neg/manual config is
* restarted automatically.
* DEFAULT: 0x1040
*/
@@ -1815,10 +1815,10 @@
to MAC interface is
activated regardless
of activity */
-#define PCS_MII_CTRL_DUPLEX 0x0100 /* forced 0x0. PCS
+#define PCS_MII_CTRL_DUPLEX 0x0100 /* forced 0x0. PCS
behaviour same for
half and full dplx */
-#define PCS_MII_RESTART_AUTONEG 0x0200 /* self clearing.
+#define PCS_MII_RESTART_AUTONEG 0x0200 /* self clearing.
restart auto-
negotiation */
#define PCS_MII_ISOLATE 0x0400 /* read as 0. ignored
@@ -1829,10 +1829,10 @@
through automatic
link config before it
can be used. when 0,
- link can be used
+ link can be used
w/out any link config
phase */
-#define PCS_MII_10_100_SEL 0x2000 /* read as 0. ignored on
+#define PCS_MII_10_100_SEL 0x2000 /* read as 0. ignored on
writes */
#define PCS_MII_RESET 0x8000 /* reset PCS. self-clears
when done */
@@ -1841,7 +1841,7 @@
#define REG_PCS_MII_STATUS 0x9004 /* PCS MII status reg */
#define PCS_MII_STATUS_EXTEND_CAP 0x0001 /* reads 0 */
#define PCS_MII_STATUS_JABBER_DETECT 0x0002 /* reads 0 */
-#define PCS_MII_STATUS_LINK_STATUS 0x0004 /* 1 -> link up.
+#define PCS_MII_STATUS_LINK_STATUS 0x0004 /* 1 -> link up.
0 -> link down. 0 is
latched so that 0 is
kept until read. read
@@ -1853,7 +1853,7 @@
from received link code
word. only valid after
auto-neg completed */
-#define PCS_MII_STATUS_AUTONEG_COMP 0x0020 /* 1 -> auto-negotiation
+#define PCS_MII_STATUS_AUTONEG_COMP 0x0020 /* 1 -> auto-negotiation
completed
0 -> auto-negotiation not
completed */
@@ -1862,7 +1862,7 @@
a 1000 Base-X PHY. writes
to it are ignored */
-/* used during auto-negotiation.
+/* used during auto-negotiation.
* DEFAULT: 0x00E0
*/
#define REG_PCS_MII_ADVERT 0x9008 /* PCS MII advertisement
@@ -1873,7 +1873,7 @@
1000 Base-X */
#define PCS_MII_ADVERT_SYM_PAUSE 0x0080 /* advertise PAUSE
symmetric capability */
-#define PCS_MII_ADVERT_ASYM_PAUSE 0x0100 /* advertises PAUSE
+#define PCS_MII_ADVERT_ASYM_PAUSE 0x0100 /* advertises PAUSE
asymmetric capability */
#define PCS_MII_ADVERT_RF_MASK 0x3000 /* remote fault. write bit13
to optionally indicate to
@@ -1881,7 +1881,7 @@
going off-line. bit12 will
get set when signal
detect == FAIL and will
- remain set until
+ remain set until
successful negotiation */
#define PCS_MII_ADVERT_ACK 0x4000 /* (ro) */
#define PCS_MII_ADVERT_NEXT_PAGE 0x8000 /* (ro) forced 0x0 */
@@ -1905,7 +1905,7 @@
0 when modifying
PCS_MII_ADVERT */
#define PCS_CFG_SD_OVERRIDE 0x02 /* sets signal detect to
- OK. bit is
+ OK. bit is
non-resettable */
#define PCS_CFG_SD_ACTIVE_LOW 0x04 /* changes interpretation
of optical signal to make
@@ -1914,23 +1914,23 @@
#define PCS_CFG_JITTER_STUDY_MASK 0x18 /* used to make jitter
measurements. a single
code group is xmitted
- regularly.
+ regularly.
0x0 = normal operation
- 0x1 = high freq test
+ 0x1 = high freq test
pattern, D21.5
0x2 = low freq test
pattern, K28.7
0x3 = reserved */
#define PCS_CFG_10MS_TIMER_OVERRIDE 0x20 /* shortens 10-20ms auto-
- negotiation timer to
+ negotiation timer to
a few cycles for test
purposes */
/* used for diagnostic purposes. bits 20-22 autoclear on read */
-#define REG_PCS_STATE_MACHINE 0x9014 /* (ro) PCS state machine
+#define REG_PCS_STATE_MACHINE 0x9014 /* (ro) PCS state machine
and diagnostic reg */
-#define PCS_SM_TX_STATE_MASK 0x0000000F /* 0 and 1 indicate
- xmission of idle.
+#define PCS_SM_TX_STATE_MASK 0x0000000F /* 0 and 1 indicate
+ xmission of idle.
otherwise, xmission of
a packet */
#define PCS_SM_RX_STATE_MASK 0x000000F0 /* 0 indicates reception
@@ -1943,39 +1943,39 @@
Config codes. cycling
through 0-1 indicates
reception of idles */
-#define PCS_SM_LINK_STATE_MASK 0x0001E000
+#define PCS_SM_LINK_STATE_MASK 0x0001E000
#define SM_LINK_STATE_UP 0x00016000 /* link state is up */
#define PCS_SM_LOSS_LINK_C 0x00100000 /* loss of link due to
- recept of Config
+ recept of Config
codes */
#define PCS_SM_LOSS_LINK_SYNC 0x00200000 /* loss of link due to
loss of sync */
-#define PCS_SM_LOSS_SIGNAL_DETECT 0x00400000 /* signal detect goes
+#define PCS_SM_LOSS_SIGNAL_DETECT 0x00400000 /* signal detect goes
from OK to FAIL. bit29
- will also be set if
+ will also be set if
this is set */
#define PCS_SM_NO_LINK_BREAKLINK 0x01000000 /* link not up due to
receipt of breaklink
C codes from partner.
C codes w/ 0 content
received triggering
- start/restart of
- autonegotiation.
+ start/restart of
+ autonegotiation.
should be sent for
no longer than 20ms */
-#define PCS_SM_NO_LINK_SERDES 0x02000000 /* serdes being
+#define PCS_SM_NO_LINK_SERDES 0x02000000 /* serdes being
initialized. see serdes
state reg */
#define PCS_SM_NO_LINK_C 0x04000000 /* C codes not stable or
not received */
-#define PCS_SM_NO_LINK_SYNC 0x08000000 /* word sync not
+#define PCS_SM_NO_LINK_SYNC 0x08000000 /* word sync not
achieved */
-#define PCS_SM_NO_LINK_WAIT_C 0x10000000 /* waiting for C codes
+#define PCS_SM_NO_LINK_WAIT_C 0x10000000 /* waiting for C codes
w/ ack bit set */
#define PCS_SM_NO_LINK_NO_IDLE 0x20000000 /* link partner continues
- to send C codes
- instead of idle
+ to send C codes
+ instead of idle
symbols or pkt data */
/* this register indicates interrupt changes in specific PCS MII status bits.
@@ -1991,21 +1991,21 @@
* DEFAULT: none
*/
#define REG_PCS_DATAPATH_MODE 0x9050 /* datapath mode reg */
-#define PCS_DATAPATH_MODE_MII 0x00 /* PCS is not used and
- MII/GMII is selected.
+#define PCS_DATAPATH_MODE_MII 0x00 /* PCS is not used and
+ MII/GMII is selected.
selection between MII and
- GMII is controlled by
+ GMII is controlled by
XIF_CFG */
#define PCS_DATAPATH_MODE_SERDES 0x02 /* PCS is used via the
10-bit interface */
/* input to serdes chip or serialink block */
#define REG_PCS_SERDES_CTRL 0x9054 /* serdes control reg */
-#define PCS_SERDES_CTRL_LOOPBACK 0x01 /* enable loopback on
+#define PCS_SERDES_CTRL_LOOPBACK 0x01 /* enable loopback on
serdes interface */
#define PCS_SERDES_CTRL_SYNCD_EN 0x02 /* enable sync carrier
detection. should be
- 0x0 for normal
+ 0x0 for normal
operation */
#define PCS_SERDES_CTRL_LOCKREF 0x04 /* frequency-lock RBC[0:1]
to REFCLK when set.
@@ -2014,28 +2014,28 @@
serial data */
/* multiplex test outputs into the PROM address (PA_3 through PA_0) pins.
- * should be 0x0 for normal operations.
+ * should be 0x0 for normal operations.
* 0b000 normal operation, PROM address[3:0] selected
- * 0b001 rxdma req, rxdma ack, rxdma ready, rxdma read
- * 0b010 rxmac req, rx ack, rx tag, rx clk shared
- * 0b011 txmac req, tx ack, tx tag, tx retry req
- * 0b100 tx tp3, tx tp2, tx tp1, tx tp0
+ * 0b001 rxdma req, rxdma ack, rxdma ready, rxdma read
+ * 0b010 rxmac req, rx ack, rx tag, rx clk shared
+ * 0b011 txmac req, tx ack, tx tag, tx retry req
+ * 0b100 tx tp3, tx tp2, tx tp1, tx tp0
* 0b101 R period RX, R period TX, R period HP, R period BIM
* DEFAULT: 0x0
*/
#define REG_PCS_SHARED_OUTPUT_SEL 0x9058 /* shared output select */
#define PCS_SOS_PROM_ADDR_MASK 0x0007
-/* used for diagnostics. this register indicates progress of the SERDES
- * boot up.
+/* used for diagnostics. this register indicates progress of the SERDES
+ * boot up.
* 0b00 undergoing reset
* 0b01 waiting 500us while lockrefn is asserted
* 0b10 waiting for comma detect
- * 0b11 receive data is synchronized
+ * 0b11 receive data is synchronized
* DEFAULT: 0x0
*/
#define REG_PCS_SERDES_STATE 0x905C /* (ro) serdes state */
-#define PCS_SERDES_STATE_MASK 0x03
+#define PCS_SERDES_STATE_MASK 0x03
/* used for diagnostics. indicates number of packets transmitted or received.
* counters rollover w/out generating an interrupt.
@@ -2044,18 +2044,18 @@
#define REG_PCS_PACKET_COUNT 0x9060 /* (ro) PCS packet counter */
#define PCS_PACKET_COUNT_TX 0x000007FF /* pkts xmitted by PCS */
#define PCS_PACKET_COUNT_RX 0x07FF0000 /* pkts recvd by PCS
- whether they
+ whether they
encountered an error
or not */
-/** LocalBus Devices. the following provides run-time access to the
+/** LocalBus Devices. the following provides run-time access to the
* Cassini's PROM
***/
#define REG_EXPANSION_ROM_RUN_START 0x100000 /* expansion rom run time
access */
#define REG_EXPANSION_ROM_RUN_END 0x17FFFF
-#define REG_SECOND_LOCALBUS_START 0x180000 /* secondary local bus
+#define REG_SECOND_LOCALBUS_START 0x180000 /* secondary local bus
device */
#define REG_SECOND_LOCALBUS_END 0x1FFFFF
@@ -2103,7 +2103,7 @@
#define CAS_MII_1000_EXTEND 0x0F
#define CAS_BMSR_1000_EXTEND 0x0100 /* supports 1000Base-T extended status */
-/*
+/*
* if autoneg is disabled, here's the table:
* BMCR_SPEED100 = 100Mbps
* BMCR_SPEED1000 = 1000Mbps
@@ -2145,7 +2145,7 @@ typedef struct cas_hp_inst {
u8 outenab; /* output enable: 0 = not, 1 = if match
2 = if !match, 3 = always */
u8 outshift; /* barrel shift right, 4 bits */
- u16 outmask;
+ u16 outmask;
} cas_hp_inst_t;
/* comparison */
@@ -2232,9 +2232,9 @@ typedef struct cas_hp_inst {
#ifdef USE_HP_IP46TCP4
static cas_hp_inst_t cas_prog_ip46tcp4tab[] = {
- CAS_PROG_IP46TCP4_PREAMBLE,
- { "TCP seq", /* DADDR should point to dest port */
- 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
+ CAS_PROG_IP46TCP4_PREAMBLE,
+ { "TCP seq", /* DADDR should point to dest port */
+ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
{ "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
S1_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
@@ -2263,7 +2263,7 @@ static cas_hp_inst_t cas_prog_ip46tcp4tab[] = {
static cas_hp_inst_t cas_prog_ip46tcp4nohttptab[] = {
CAS_PROG_IP46TCP4_PREAMBLE,
{ "TCP seq", /* DADDR should point to dest port */
- 0xFFFF, 0x0080, OP_EQ, 0, S2_HTTP, 0, S1_TCPFG, LD_SEQ,
+ 0xFFFF, 0x0080, OP_EQ, 0, S2_HTTP, 0, S1_TCPFG, LD_SEQ,
0x081, 3, 0x0, 0xffff} , /* Load TCP seq # */
{ "TCP control flags", 0xFFFF, 0x8080, OP_EQ, 0, S2_HTTP, 0,
S1_TCPHL, ST_FLG, 0x145, 2, 0x0, 0x002f, }, /* Load TCP flags */
@@ -2328,7 +2328,7 @@ static cas_hp_inst_t cas_prog_ip4fragtab[] = {
{ "TCP seq", /* DADDR should point to dest port */
0x0000, 0x0000, OP_EQ, 0, S3_TCPFG, 4, S3_TCPFG, LD_SEQ,
0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
- { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHL, 0,
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHL, 0,
S3_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
{ "TCP length", 0x0000, 0x0000, OP_EQ, 0, S3_TCPHc, 0, S3_TCPHc,
LD_R1, 0x205, 3, 0xB, 0xf000},
@@ -2338,7 +2338,7 @@ static cas_hp_inst_t cas_prog_ip4fragtab[] = {
LD_FID, 0x103, 3, 0x0, 0xffff}, /* FID IP4 src+dst */
{ "IP4 frag offset", 0x0000, 0x0000, OP_EQ, 0, S3_FOFF, 0, S3_FOFF,
LD_SEQ, 0x040, 1, 0xD, 0xfff8},
- { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
+ { "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
IM_CTL, 0x001, 3, 0x0, 0x0001},
{ NULL },
};
@@ -2356,11 +2356,11 @@ static cas_hp_inst_t cas_prog_ip46tcp4batchtab[] = {
{ "TCP seq", /* DADDR should point to dest port */
0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 0, S1_TCPFG, LD_SEQ,
0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
- { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
+ { "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
S1_TCPHL, ST_FLG, 0x000, 3, 0x0, 0x0000}, /* Load TCP flags */
- { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0,
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0,
S1_TCPHc, LD_R1, 0x205, 3, 0xB, 0xf000},
- { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
+ { "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
S1_PCKT, IM_CTL, 0x040, 3, 0x0, 0xffff}, /* set batch bit */
{ "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
IM_CTL, 0x001, 3, 0x0, 0x0001},
@@ -2381,7 +2381,7 @@ static cas_hp_inst_t cas_prog_ip46tcp4batchtab[] = {
static cas_hp_inst_t cas_prog_workaroundtab[] = {
{ "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
S1_PCKT, CL_REG, 0x3ff, 1, 0x0, 0x0000} ,
- { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
+ { "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
IM_CTL, 0x04a, 3, 0x0, 0xffff},
{ "CFI?", 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
CL_REG, 0x000, 0, 0x0, 0x0000},
@@ -2395,7 +2395,7 @@ static cas_hp_inst_t cas_prog_workaroundtab[] = {
IM_SAP, 0x6AE, 3, 0x0, 0xffff},
{ "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
LD_SUM, 0x00a, 1, 0x0, 0x0000},
- { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
+ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
LD_LEN, 0x03e, 1, 0x0, 0xffff},
{ "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_CLNP,
LD_FID, 0x182, 3, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
@@ -2408,7 +2408,7 @@ static cas_hp_inst_t cas_prog_workaroundtab[] = {
{ "TCP64?", 0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_CLNP,
LD_LEN, 0x03f, 1, 0x0, 0xffff},
{ "TCP seq", /* DADDR should point to dest port */
- 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
+ 0x0000, 0x0000, OP_EQ, 0, S1_TCPFG, 4, S1_TCPFG, LD_SEQ,
0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
{ "TCP control flags", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHL, 0,
S1_TCPHL, ST_FLG, 0x045, 3, 0x0, 0x002f}, /* Load TCP flags */
@@ -2429,7 +2429,7 @@ static cas_hp_inst_t cas_prog_workaroundtab[] = {
#ifdef USE_HP_ENCRYPT
static cas_hp_inst_t cas_prog_encryptiontab[] = {
- { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
+ { "packet arrival?", 0xffff, 0x0000, OP_NP, 6, S1_VLAN, 0,
S1_PCKT, CL_REG, 0x3ff, 1, 0x0, 0x0000},
{ "VLAN?", 0xffff, 0x8100, OP_EQ, 1, S1_CFI, 0, S1_8023,
IM_CTL, 0x00a, 3, 0x0, 0xffff},
@@ -2439,19 +2439,19 @@ static cas_hp_inst_t cas_prog_encryptiontab[] = {
00,
#endif
{ "CFI?", /* FIND CFI and If FIND go to CleanUP1 (ignore and send to host) */
- 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
+ 0x1000, 0x1000, OP_EQ, 0, S1_CLNP, 1, S1_8023,
CL_REG, 0x000, 0, 0x0, 0x0000},
- { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
+ { "8023?", 0xffff, 0x0600, OP_LT, 1, S1_LLC, 0, S1_IPV4,
CL_REG, 0x000, 0, 0x0, 0x0000},
- { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP,
+ { "LLC?", 0xffff, 0xaaaa, OP_EQ, 1, S1_LLCc, 0, S1_CLNP,
CL_REG, 0x000, 0, 0x0, 0x0000},
{ "LLCc?", 0xff00, 0x0300, OP_EQ, 2, S1_IPV4, 0, S1_CLNP,
CL_REG, 0x000, 0, 0x0, 0x0000},
- { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
+ { "IPV4?", 0xffff, 0x0800, OP_EQ, 1, S1_IPV4c, 0, S1_IPV6,
LD_SAP, 0x100, 3, 0x0, 0xffff},
- { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
+ { "IPV4 cont?", 0xff00, 0x4500, OP_EQ, 3, S1_IPV4F, 0, S1_CLNP,
LD_SUM, 0x00a, 1, 0x0, 0x0000},
- { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
+ { "IPV4 frag?", 0x3fff, 0x0000, OP_EQ, 1, S1_TCP44, 0, S1_CLNP,
LD_LEN, 0x03e, 1, 0x0, 0xffff},
{ "TCP44?", 0x00ff, 0x0006, OP_EQ, 7, S1_TCPSQ, 0, S1_ESP4,
LD_FID, 0x182, 1, 0x0, 0xffff}, /* FID IP4&TCP src+dst */
@@ -2459,9 +2459,9 @@ static cas_hp_inst_t cas_prog_encryptiontab[] = {
LD_SUM, 0x015, 1, 0x0, 0x0000},
{ "IPV6 len", 0xf000, 0x6000, OP_EQ, 0, S1_IPV6c, 0, S1_CLNP,
IM_R1, 0x128, 1, 0x0, 0xffff},
- { "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP,
+ { "IPV6 cont?", 0x0000, 0x0000, OP_EQ, 3, S1_TCP64, 0, S1_CLNP,
LD_FID, 0x484, 1, 0x0, 0xffff}, /* FID IP6&TCP src+dst */
- { "TCP64?",
+ { "TCP64?",
#if 0
//@@@0xff00, 0x0600, OP_EQ, 18, S1_TCPSQ, 0, S1_ESP6, LD_LEN, 0x03f, 1, 0x0, 0xffff,
#endif
@@ -2472,10 +2472,10 @@ static cas_hp_inst_t cas_prog_encryptiontab[] = {
0x081, 3, 0x0, 0xffff}, /* Load TCP seq # */
{ "TCP control flags", 0xFFFF, 0x8080, OP_EQ, 0, S2_HTTP, 0,
S1_TCPHL, ST_FLG, 0x145, 2, 0x0, 0x002f}, /* Load TCP flags */
- { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
+ { "TCP length", 0x0000, 0x0000, OP_EQ, 0, S1_TCPHc, 0, S1_TCPHc,
LD_R1, 0x205, 3, 0xB, 0xf000} ,
{ "TCP length cont", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0,
- S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
+ S1_PCKT, LD_HDR, 0x0ff, 3, 0x0, 0xffff},
{ "Cleanup", 0x0000, 0x0000, OP_EQ, 0, S1_CLNP2, 0, S1_CLNP2,
IM_CTL, 0x001, 3, 0x0, 0x0001},
{ "Cleanup 2", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
@@ -2483,7 +2483,7 @@ static cas_hp_inst_t cas_prog_encryptiontab[] = {
{ "Drop packet", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
IM_CTL, 0x080, 3, 0x0, 0xffff},
{ "No HTTP", 0x0000, 0x0000, OP_EQ, 0, S1_PCKT, 0, S1_PCKT,
- IM_CTL, 0x044, 3, 0x0, 0xffff},
+ IM_CTL, 0x044, 3, 0x0, 0xffff},
{ "IPV4 ESP encrypted?", /* S1_ESP4 */
0x00ff, 0x0032, OP_EQ, 0, S1_CLNP2, 0, S1_AH4, IM_CTL,
0x021, 1, 0x0, 0xffff},
@@ -4044,7 +4044,7 @@ cas_saturn_patch_t cas_saturn_patch[] = {
* deal with that, i just allocate rings to create the desired
* alignment. here are the constraints:
* RX DESC and COMP rings must be 8KB aligned
- * TX DESC must be 2KB aligned.
+ * TX DESC must be 2KB aligned.
* if you change the numbers, be cognizant of how the alignment will change
* in INIT_BLOCK as well.
*/
@@ -4095,20 +4095,20 @@ cas_saturn_patch_t cas_saturn_patch[] = {
/* min is 2k, but we can't do jumbo frames unless it's at least 8k */
#define CAS_MIN_PAGE_SHIFT 11 /* 2048 */
#define CAS_JUMBO_PAGE_SHIFT 13 /* 8192 */
-#define CAS_MAX_PAGE_SHIFT 14 /* 16384 */
+#define CAS_MAX_PAGE_SHIFT 14 /* 16384 */
#define TX_DESC_BUFLEN_MASK 0x0000000000003FFFULL /* buffer length in
bytes. 0 - 9256 */
#define TX_DESC_BUFLEN_SHIFT 0
#define TX_DESC_CSUM_START_MASK 0x00000000001F8000ULL /* checksum start. #
- of bytes to be
+ of bytes to be
skipped before
csum calc begins.
value must be
even */
#define TX_DESC_CSUM_START_SHIFT 15
#define TX_DESC_CSUM_STUFF_MASK 0x000000001FE00000ULL /* checksum stuff.
- byte offset w/in
+ byte offset w/in
the pkt for the
1st csum byte.
must be > 8 */
@@ -4137,7 +4137,7 @@ struct cas_rx_desc {
/* received packets are put on the completion ring. */
/* word 1 */
-#define RX_COMP1_DATA_SIZE_MASK 0x0000000007FFE000ULL
+#define RX_COMP1_DATA_SIZE_MASK 0x0000000007FFE000ULL
#define RX_COMP1_DATA_SIZE_SHIFT 13
#define RX_COMP1_DATA_OFF_MASK 0x000001FFF8000000ULL
#define RX_COMP1_DATA_OFF_SHIFT 27
@@ -4147,8 +4147,8 @@ struct cas_rx_desc {
#define RX_COMP1_SKIP_SHIFT 55
#define RX_COMP1_RELEASE_NEXT 0x0200000000000000ULL
#define RX_COMP1_SPLIT_PKT 0x0400000000000000ULL
-#define RX_COMP1_RELEASE_FLOW 0x0800000000000000ULL
-#define RX_COMP1_RELEASE_DATA 0x1000000000000000ULL
+#define RX_COMP1_RELEASE_FLOW 0x0800000000000000ULL
+#define RX_COMP1_RELEASE_DATA 0x1000000000000000ULL
#define RX_COMP1_RELEASE_HDR 0x2000000000000000ULL
#define RX_COMP1_TYPE_MASK 0xC000000000000000ULL
#define RX_COMP1_TYPE_SHIFT 62
@@ -4201,7 +4201,7 @@ struct cas_rx_desc {
/* we encode the following: ring/index/release. only 14 bits
* are usable.
- * NOTE: the encoding is dependent upon RX_DESC_RING_SIZE and
+ * NOTE: the encoding is dependent upon RX_DESC_RING_SIZE and
* MAX_RX_DESC_RINGS. */
#define RX_INDEX_NUM_MASK 0x0000000000000FFFULL
#define RX_INDEX_NUM_SHIFT 0
@@ -4214,7 +4214,7 @@ struct cas_rx_comp {
u64 word2;
u64 word3;
u64 word4;
-};
+};
enum link_state {
link_down = 0, /* No link, will retry */
@@ -4235,9 +4235,9 @@ typedef struct cas_page {
/* some alignment constraints:
* TX DESC, RX DESC, and RX COMP must each be 8K aligned.
- * TX COMPWB must be 8-byte aligned.
+ * TX COMPWB must be 8-byte aligned.
* to accomplish this, here's what we do:
- *
+ *
* INIT_BLOCK_RX_COMP = 64k (already aligned)
* INIT_BLOCK_RX_DESC = 8k
* INIT_BLOCK_TX = 8k
@@ -4250,9 +4250,9 @@ typedef struct cas_page {
struct cas_init_block {
struct cas_rx_comp rxcs[N_RX_COMP_RINGS][INIT_BLOCK_RX_COMP];
- struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
+ struct cas_rx_desc rxds[N_RX_DESC_RINGS][INIT_BLOCK_RX_DESC];
struct cas_tx_desc txds[N_TX_RINGS][INIT_BLOCK_TX];
- u64 tx_compwb;
+ u64 tx_compwb;
};
/* tiny buffers to deal with target abort issue. we allocate a bit
@@ -4278,7 +4278,7 @@ struct cas {
int tx_new[N_TX_RINGS], tx_old[N_TX_RINGS];
int rx_old[N_RX_DESC_RINGS];
int rx_cur[N_RX_COMP_RINGS], rx_new[N_RX_COMP_RINGS];
- int rx_last[N_RX_DESC_RINGS];
+ int rx_last[N_RX_DESC_RINGS];
/* Set when chip is actually in operational state
* (ie. not power managed) */
@@ -4337,7 +4337,7 @@ struct cas {
int min_frame_size; /* for tx fifo workaround */
/* page size allocation */
- int page_size;
+ int page_size;
int page_order;
int mtu_stride;
@@ -4362,7 +4362,7 @@ struct cas {
#ifdef CONFIG_CASSINI_QGE_DEBUG
atomic_t interrupt_seen; /* 1 if any interrupts are getting through */
#endif
-
+
/* Link-down problem workaround */
#define LINK_TRANSITION_UNKNOWN 0
#define LINK_TRANSITION_ON_FAILURE 1
@@ -4383,7 +4383,7 @@ struct cas {
int casreg_len; /* reg-space size for dumping */
u64 pause_entered;
u16 pause_last_time_recvd;
-
+
dma_addr_t block_dvma, tx_tiny_dvma[N_TX_RINGS];
struct pci_dev *pdev;
struct net_device *dev;
@@ -4394,7 +4394,7 @@ struct cas {
#define RX_COMP_ENTRY(r, x) ((x) & (RX_COMP_RINGN_SIZE(r) - 1))
#define TX_BUFF_COUNT(r, x, y) ((x) <= (y) ? ((y) - (x)) : \
- (TX_DESC_RINGN_SIZE(r) - (x) + (y)))
+ (TX_DESC_RINGN_SIZE(r) - (x) + (y)))
#define TX_BUFFS_AVAIL(cp, i) ((cp)->tx_old[(i)] <= (cp)->tx_new[(i)] ? \
(cp)->tx_old[(i)] + (TX_DESC_RINGN_SIZE(i) - 1) - (cp)->tx_new[(i)] : \
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h
index bf3e7b6a7a1..5d9dd14427c 100644
--- a/drivers/net/chelsio/common.h
+++ b/drivers/net/chelsio/common.h
@@ -39,7 +39,6 @@
#ifndef _CXGB_COMMON_H_
#define _CXGB_COMMON_H_
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/types.h>
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 7fe2638ae06..5f1b0675346 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -37,7 +37,6 @@
****************************************************************************/
#include "common.h"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -219,7 +218,7 @@ static int cxgb_up(struct adapter *adapter)
t1_interrupts_clear(adapter);
if ((err = request_irq(adapter->pdev->irq,
- t1_select_intr_handler(adapter), SA_SHIRQ,
+ t1_select_intr_handler(adapter), IRQF_SHARED,
adapter->name, adapter))) {
goto out_err;
}
@@ -780,7 +779,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
return 0;
}
-static struct ethtool_ops t1_ethtool_ops = {
+static const struct ethtool_ops t1_ethtool_ops = {
.get_settings = get_settings,
.set_settings = set_settings,
.get_drvinfo = get_drvinfo,
@@ -1244,7 +1243,7 @@ static struct pci_driver driver = {
static int __init t1_init_module(void)
{
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit t1_cleanup_module(void)
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index 53efff6da78..ddd0bdb498f 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -39,7 +39,6 @@
#include "common.h"
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/pci.h>
@@ -1418,7 +1417,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct cpl_tx_pkt *cpl;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
int eth_type;
struct cpl_tx_pkt_lso *hdr;
@@ -1471,9 +1470,9 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (!(adapter->flags & UDP_CSUM_CAPABLE) &&
- skb->ip_summed == CHECKSUM_HW &&
+ skb->ip_summed == CHECKSUM_PARTIAL &&
skb->nh.iph->protocol == IPPROTO_UDP)
- if (unlikely(skb_checksum_help(skb, 0))) {
+ if (unlikely(skb_checksum_help(skb))) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
}
@@ -1496,11 +1495,11 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
cpl = (struct cpl_tx_pkt *)__skb_push(skb, sizeof(*cpl));
cpl->opcode = CPL_TX_PKT;
cpl->ip_csum_dis = 1; /* SW calculates IP csum */
- cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_HW ? 0 : 1;
+ cpl->l4_csum_dis = skb->ip_summed == CHECKSUM_PARTIAL ? 0 : 1;
/* the length field isn't used so don't bother setting it */
- st->tx_cso += (skb->ip_summed == CHECKSUM_HW);
- sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_HW);
+ st->tx_cso += (skb->ip_summed == CHECKSUM_PARTIAL);
+ sge->stats.tx_do_cksum += (skb->ip_summed == CHECKSUM_PARTIAL);
sge->stats.tx_reg_pkts++;
}
cpl->iff = dev->if_port;
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index 64105e4eaf3..f1501b6f247 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -218,7 +218,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
@@ -435,7 +434,7 @@ 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 const struct ethtool_ops e100_ethtool_ops;
static void broadcom_check_speed(struct net_device* dev);
static void broadcom_check_duplex(struct net_device* dev);
@@ -672,7 +671,7 @@ e100_open(struct net_device *dev)
/* allocate the irq corresponding to the receiving DMA */
if (request_irq(NETWORK_DMA_RX_IRQ_NBR, e100rxtx_interrupt,
- SA_SAMPLE_RANDOM, cardname, (void *)dev)) {
+ IRQF_SAMPLE_RANDOM, cardname, (void *)dev)) {
goto grace_exit0;
}
@@ -1553,7 +1552,7 @@ static int e100_nway_reset(struct net_device *dev)
return 0;
}
-static struct ethtool_ops e100_ethtool_ops = {
+static const struct ethtool_ops e100_ethtool_ops = {
.get_settings = e100_get_settings,
.set_settings = e100_set_settings,
.get_drvinfo = e100_get_drvinfo,
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index ef54ebeb29b..e4d50f0de93 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -15,13 +15,13 @@
Changelog:
Mike Cruse : mcruse@cti-ltd.com
- : Changes for Linux 2.0 compatibility.
+ : Changes for Linux 2.0 compatibility.
: Added dev_id parameter in net_interrupt(),
: request_irq() and free_irq(). Just NULL for now.
Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
: in net_open() and net_close() so kerneld would know
- : that the module is in use and wouldn't eject the
+ : that the module is in use and wouldn't eject the
: driver prematurely.
Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
@@ -31,7 +31,7 @@
Russ Nelson : Jul 13 1998. Added RxOnly DMA support.
- Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility.
+ Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility.
: email: ethernet@crystal.cirrus.com
Alan Cox : Removed 1.2 support, added 2.1 extra counters.
@@ -100,7 +100,6 @@
/* Always include 'config.h' first in case the user wants to turn on
or override something. */
-#include <linux/config.h>
#include <linux/module.h>
/*
@@ -164,12 +163,12 @@ static char version[] __initdata =
/* First, a few definitions that the brave might change.
A zero-terminated list of I/O addresses to be probed. Some special flags..
Addr & 1 = Read back the address port, look for signature and reset
- the page window before probing
- Addr & 3 = Reset the page window and probe
+ the page window before probing
+ Addr & 3 = Reset the page window and probe
The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space,
but it is possible that a Cirrus board could be plugged into the ISA
slots. */
-/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
+/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps
them to system IRQ numbers. This mapping is card specific and is set to
the configuration of the Cirrus Eval board for this chip. */
#ifdef CONFIG_ARCH_CLPS7500
@@ -300,7 +299,7 @@ static int __init media_fn(char *str)
__setup("cs89x0_media=", media_fn);
-
+
/* Check for a network adaptor of this type, and return '0' iff one exists.
If dev->base_addr == 0, probe all likely locations.
If dev->base_addr == 1, always return failure.
@@ -631,7 +630,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
dev->base_addr);
reset_chip(dev);
-
+
/* Here we read the current configuration of the chip. If there
is no Extended EEPROM then the idea is to not disturb the chip
configuration, it should have been correctly setup by automatic
@@ -655,7 +654,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
cnt = (*confd++ & 0x00ff) >> 1;
while (--cnt > 0) {
__u16 j = *confd++;
-
+
switch (j & 0x0fff) {
case PP_IA:
for (i = 0; i < ETH_ALEN/2; i++) {
@@ -671,7 +670,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
} else
#endif
- if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
+ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) ==
(EEPROM_OK|EEPROM_PRESENT)) {
/* Load the MAC. */
for (i=0; i < ETH_ALEN/2; i++) {
@@ -680,17 +679,17 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
dev->dev_addr[i*2] = Addr & 0xFF;
dev->dev_addr[i*2+1] = Addr >> 8;
}
-
- /* Load the Adapter Configuration.
- Note: Barring any more specific information from some
- other source (ie EEPROM+Schematics), we would not know
- how to operate a 10Base2 interface on the AUI port.
- However, since we do read the status of HCB1 and use
- settings that always result in calls to control_dc_dc(dev,0)
- a BNC interface should work if the enable pin
- (dc/dc converter) is on HCB1. It will be called AUI
+
+ /* Load the Adapter Configuration.
+ Note: Barring any more specific information from some
+ other source (ie EEPROM+Schematics), we would not know
+ how to operate a 10Base2 interface on the AUI port.
+ However, since we do read the status of HCB1 and use
+ settings that always result in calls to control_dc_dc(dev,0)
+ a BNC interface should work if the enable pin
+ (dc/dc converter) is on HCB1. It will be called AUI
however. */
-
+
lp->adapter_cnf = 0;
i = readreg(dev, PP_LineCTL);
/* Preserve the setting of the HCB1 pin. */
@@ -707,22 +706,22 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI;
/* Check if the card is in Auto mode. */
if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET)
- lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
+ lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T |
A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO;
-
+
if (net_debug > 1)
printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n",
dev->name, i, lp->adapter_cnf);
/* IRQ. Other chips already probe, see below. */
- if (lp->chip_type == CS8900)
+ if (lp->chip_type == CS8900)
lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK;
-
+
printk( "[Cirrus EEPROM] ");
}
printk("\n");
-
+
/* First check to see if an EEPROM is attached. */
#ifdef CONFIG_SH_HICOSH4 /* no EEPROM on HiCO, don't hazzle with it here */
if (1) {
@@ -737,13 +736,13 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
/* Check if the chip was able to read its own configuration starting
at 0 in the EEPROM*/
if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) !=
- (EEPROM_OK|EEPROM_PRESENT))
+ (EEPROM_OK|EEPROM_PRESENT))
printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n");
-
+
} else {
/* This reads an extended EEPROM that is not documented
in the CS8900 datasheet. */
-
+
/* get transmission control word but keep the autonegotiation bits */
if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2];
/* Store adapter configuration */
@@ -811,7 +810,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
printk("\ncs89x0: invalid ISA interrupt number %d\n", i);
else
i = cs8900_irq_map[i];
-
+
lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */
} else {
int irq_map_buff[IRQ_MAP_LEN/2];
@@ -876,7 +875,7 @@ out1:
return retval;
}
-
+
/*********************************
* This page contains DMA routines
**********************************/
@@ -1065,14 +1064,14 @@ void __init reset_chip(struct net_device *dev)
;
}
-
+
static void
control_dc_dc(struct net_device *dev, int on_not_off)
{
struct net_local *lp = netdev_priv(dev);
unsigned int selfcontrol;
int timenow = jiffies;
- /* control the DC to DC convertor in the SelfControl register.
+ /* control the DC to DC convertor in the SelfControl register.
Note: This is hooked up to a general purpose pin, might not
always be a DC to DC convertor. */
@@ -1241,7 +1240,7 @@ detect_bnc(struct net_device *dev)
return DETECTED_NONE;
}
-
+
static void
write_irq(struct net_device *dev, int chip_type, int irq)
{
@@ -1545,7 +1544,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
* Gasp! It hasn't. But that shouldn't happen since
* we're waiting for TxOk, so return 1 and requeue this packet.
*/
-
+
spin_unlock_irq(&lp->lock);
if (net_debug) printk("cs89x0: Tx buffer not free!\n");
return 1;
@@ -1570,10 +1569,10 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-
+
/* The typical workload of the driver:
Handle the network interface interrupts. */
-
+
static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
struct net_device *dev = dev_id;
@@ -1741,7 +1740,7 @@ net_close(struct net_device *dev)
#endif
netif_stop_queue(dev);
-
+
writereg(dev, PP_RxCFG, 0);
writereg(dev, PP_TxCFG, 0);
writereg(dev, PP_BufCFG, 0);
@@ -1792,7 +1791,7 @@ static void set_multicast_list(struct net_device *dev)
/* The multicast-accept list is initialized to accept-all, and we
rely on higher-level filtering for now. */
lp->rx_mode = RX_MULTCAST_ACCEPT;
- }
+ }
else
lp->rx_mode = 0;
@@ -1834,8 +1833,8 @@ static int set_mac_address(struct net_device *dev, void *p)
static struct net_device *dev_cs89x0;
/*
- * Support the 'debug' module parm even if we're compiled for non-debug to
- * avoid breaking someone's startup scripts
+ * Support the 'debug' module parm even if we're compiled for non-debug to
+ * avoid breaking someone's startup scripts
*/
static int io;
@@ -1906,8 +1905,7 @@ MODULE_LICENSE("GPL");
*/
-int
-init_module(void)
+int __init init_module(void)
{
struct net_device *dev = alloc_etherdev(sizeof(struct net_local));
struct net_local *lp;
@@ -1985,7 +1983,7 @@ cleanup_module(void)
free_netdev(dev_cs89x0);
}
#endif /* MODULE */
-
+
/*
* Local variables:
* version-control: t
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index bd954aaa636..204ed37fa9d 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -14,7 +14,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */
/* offset 2h -> Model/Product Number */
@@ -428,8 +427,8 @@
#define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */
#define CS8900 0x0000
-#define CS8920 0x4000
-#define CS8920M 0x6000
+#define CS8920 0x4000
+#define CS8920M 0x6000
#define REVISON_BITS 0x1F00
#define EEVER_NUMBER 0x12
#define CHKSUM_LEN 0x14
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index 56a100fb9e4..0b930da5d47 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -179,7 +179,7 @@ static inline void trigger_interrupt(struct net_device *dev)
* Copy a buffer to the adapter transmit page memory.
* Start sending.
*/
-
+
static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
unsigned long flags;
@@ -272,7 +272,7 @@ static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
spin_lock(&de600_lock);
-
+
select_nic();
irq_status = de600_read_status(dev);
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index 22fc5b869a6..a18d4d14b66 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -40,7 +40,7 @@
*****************************************************************************/
static const char version[] =
"de620.c: $Revision: 1.40 $, Bjorn Ekwall <bj0rn@blox.se>\n";
-
+
/***********************************************************************
*
* "Tuning" section.
@@ -115,7 +115,7 @@ static const char version[] =
#define COUNT_LOOPS
*/
#endif
-
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -250,7 +250,7 @@ static struct nic {
byte Media;
byte SCR;
} nic_data;
-
+
/**********************************************************
* *
* Convenience macros/functions for D-Link DE-620 adapter *
@@ -432,7 +432,7 @@ de620_get_register(struct net_device *dev, byte reg)
return value;
}
-
+
/*********************************************************************
*
* Open/initialize the board.
@@ -515,10 +515,10 @@ static void de620_set_multicast_list(struct net_device *dev)
}
/*******************************************************
- *
+ *
* Handle timeouts on transmit
*/
-
+
static void de620_timeout(struct net_device *dev)
{
printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, "network cable problem");
@@ -540,9 +540,9 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
byte using_txbuf;
using_txbuf = de620_tx_buffs(dev); /* Peek at the adapter */
-
+
netif_stop_queue(dev);
-
+
if ((len = skb->len) < RUNT)
len = RUNT;
@@ -584,7 +584,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb (skb);
return 0;
}
-
+
/*****************************************************
*
* Handle the network interface interrupts.
@@ -599,7 +599,7 @@ de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
int again = 0;
spin_lock(&de620_lock);
-
+
/* Read the status register (_not_ the status port) */
irq_status = de620_get_register(dev, R_STS);
@@ -615,7 +615,7 @@ de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
if(de620_tx_buffs(dev) != (TXBF0 | TXBF1))
netif_wake_queue(dev);
-
+
spin_unlock(&de620_lock);
return IRQ_HANDLED;
}
@@ -720,7 +720,7 @@ static int de620_rx_intr(struct net_device *dev)
return (next_rx_page != curr_page); /* That was slightly tricky... */
}
-
+
/*********************************************
*
* Reset the adapter to a known state
@@ -803,7 +803,7 @@ static int adapter_init(struct net_device *dev)
return 0; /* all ok */
}
-
+
/******************************************************************************
*
* Only start-up code below
@@ -827,7 +827,7 @@ struct net_device * __init de620_probe(int unit)
SET_MODULE_OWNER(dev);
spin_lock_init(&de620_lock);
-
+
/*
* This is where the base_addr and irq gets set.
* Tunable at compile-time and insmod-time
@@ -840,7 +840,7 @@ struct net_device * __init de620_probe(int unit)
sprintf(dev->name, "eth%d", unit);
netdev_boot_setup_check(dev);
}
-
+
if (de620_debug)
printk(version);
@@ -889,7 +889,7 @@ struct net_device * __init de620_probe(int unit)
dev->tx_timeout = de620_timeout;
dev->watchdog_timeo = HZ*2;
dev->set_multicast_list = de620_set_multicast_list;
-
+
/* base_addr and irq are already set, see above! */
/* dump eeprom */
@@ -917,7 +917,7 @@ out1:
out:
return ERR_PTR(err);
}
-
+
/**********************************
*
* Read info from on-board EEPROM
@@ -1003,7 +1003,7 @@ static int __init read_eeprom(struct net_device *dev)
return 0; /* no errors */
}
-
+
/******************************************************************************
*
* Loadable module skeleton
@@ -1029,7 +1029,7 @@ void cleanup_module(void)
#endif /* MODULE */
MODULE_LICENSE("GPL");
-
+
/*
* (add '-DMODULE' when compiling as loadable module)
*
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index d3d958e7ac5..bbccd741cdb 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -1,4 +1,4 @@
-/*
+/*
* Lance ethernet driver for the MIPS processor based
* DECstation family
*
@@ -42,7 +42,6 @@
* bits. macro
*/
-#include <linux/config.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -159,9 +158,9 @@ MODULE_LICENSE("GPL");
/* The DS2000/3000 have a linear 64 KB buffer.
- * The PMAD-AA has 128 kb buffer on-board.
+ * The PMAD-AA has 128 kb buffer on-board.
*
- * The IOASIC LANCE devices use a shared memory region. This region as seen
+ * The IOASIC LANCE devices use a shared memory region. This region as seen
* from the CPU is (max) 128 KB long and has to be on an 128 KB boundary.
* The LANCE sees this as a 64 KB long continuous memory region.
*
@@ -704,8 +703,8 @@ static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
return IRQ_HANDLED;
}
-static irqreturn_t
-lance_interrupt(const int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt(const int irq, void *dev_id,
+ struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct lance_private *lp = netdev_priv(dev);
@@ -883,7 +882,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
skblen = skb->len;
len = skblen;
-
+
if (len < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
return 0;
@@ -1254,7 +1253,7 @@ static int __init dec_lance_init(const int type, const int slot)
return 0;
err_out_free_dev:
- kfree(dev);
+ free_netdev(dev);
err_out:
return ret;
@@ -1300,6 +1299,7 @@ static void __exit dec_lance_cleanup(void)
while (root_lance_dev) {
struct net_device *dev = root_lance_dev;
struct lance_private *lp = netdev_priv(dev);
+
unregister_netdev(dev);
#ifdef CONFIG_TC
if (lp->slot >= 0)
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index 5acd35c312a..ae9680552b8 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -275,7 +275,7 @@ static void dfx_xmt_flush(DFX_board_t *bp);
static struct net_device *root_dfx_eisa_dev;
-
+
/*
* =======================
* = dfx_port_write_byte =
@@ -283,13 +283,13 @@ static struct net_device *root_dfx_eisa_dev;
* = dfx_port_write_long =
* = dfx_port_read_long =
* =======================
- *
+ *
* Overview:
* Routines for reading and writing values from/to adapter
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
* offset - register offset from base I/O address
@@ -301,7 +301,7 @@ static struct net_device *root_dfx_eisa_dev;
* Functional Description:
* These routines perform the correct operation to read or write
* the adapter register.
- *
+ *
* EISA port block base addresses are based on the slot number in which the
* controller is installed. For example, if the EISA controller is installed
* in slot 4, the port block base address is 0x4000. If the controller is
@@ -377,18 +377,18 @@ static inline void dfx_port_read_long(
*data = inl(port);
}
-
+
/*
* =============
* = dfx_init_one_pci_or_eisa =
* =============
- *
+ *
* Overview:
* Initializes a supported FDDI EISA or PCI controller
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* pdev - pointer to pci device information (NULL for EISA)
* ioaddr - pointer to port (NULL for PCI)
@@ -537,18 +537,18 @@ static int __init dfx_eisa_init(void)
}
return rc;
}
-
+
/*
* ================
* = dfx_bus_init =
* ================
- *
+ *
* Overview:
* Initializes EISA and PCI controller bus-specific logic.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* dev - pointer to device information
*
@@ -672,19 +672,19 @@ static void __devinit dfx_bus_init(struct net_device *dev)
}
}
-
+
/*
* ========================
* = dfx_bus_config_check =
* ========================
- *
+ *
* Overview:
* Checks the configuration (burst size, full-duplex, etc.) If any parameters
* are illegal, then this routine will set new defaults.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -766,19 +766,19 @@ static void __devinit dfx_bus_config_check(DFX_board_t *bp)
}
}
-
+
/*
* ===================
* = dfx_driver_init =
* ===================
- *
+ *
* Overview:
* Initializes remaining adapter board structure information
* and makes sure adapter is in a safe state prior to dfx_open().
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* dev - pointer to device information
* print_name - printable device name
@@ -984,18 +984,18 @@ static int __devinit dfx_driver_init(struct net_device *dev,
return(DFX_K_SUCCESS);
}
-
+
/*
* =================
* = dfx_adap_init =
* =================
- *
+ *
* Overview:
* Brings the adapter to the link avail/link unavailable state.
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* bp - pointer to board information
* get_buffers - non-zero if buffers to be allocated
@@ -1188,18 +1188,18 @@ static int dfx_adap_init(DFX_board_t *bp, int get_buffers)
return(DFX_K_SUCCESS);
}
-
+
/*
* ============
* = dfx_open =
* ============
- *
+ *
* Overview:
* Opens the adapter
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* dev - pointer to device information
*
@@ -1225,10 +1225,10 @@ static int dfx_open(struct net_device *dev)
DFX_board_t *bp = dev->priv;
DBG_printk("In dfx_open...\n");
-
+
/* Register IRQ - support shared interrupts by passing device ptr */
- ret = request_irq(dev->irq, dfx_interrupt, SA_SHIRQ, dev->name, dev);
+ ret = request_irq(dev->irq, dfx_interrupt, IRQF_SHARED, dev->name, dev);
if (ret) {
printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
return ret;
@@ -1276,18 +1276,18 @@ static int dfx_open(struct net_device *dev)
return(0);
}
-
+
/*
* =============
* = dfx_close =
* =============
- *
+ *
* Overview:
* Closes the device/module.
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* dev - pointer to device information
*
@@ -1360,26 +1360,26 @@ static int dfx_close(struct net_device *dev)
/* Clear device structure flags */
netif_stop_queue(dev);
-
+
/* Deregister (free) IRQ */
free_irq(dev->irq, dev);
-
+
return(0);
}
-
+
/*
* ======================
* = dfx_int_pr_halt_id =
* ======================
- *
+ *
* Overview:
* Displays halt id's in string form.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -1452,18 +1452,18 @@ static void dfx_int_pr_halt_id(DFX_board_t *bp)
}
}
-
+
/*
* ==========================
* = dfx_int_type_0_process =
* ==========================
- *
+ *
* Overview:
* Processes Type 0 interrupts.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -1569,7 +1569,7 @@ static void dfx_int_type_0_process(DFX_board_t *bp)
/* Check for adapter state change */
if (type_0_status & PI_TYPE_0_STAT_M_STATE_CHANGE)
- {
+ {
/* Get latest adapter state */
state = dfx_hw_adap_state_rd(bp); /* get adapter state */
@@ -1604,18 +1604,18 @@ static void dfx_int_type_0_process(DFX_board_t *bp)
}
}
-
+
/*
* ==================
* = dfx_int_common =
* ==================
- *
+ *
* Overview:
* Interrupt service routine (ISR)
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -1678,7 +1678,7 @@ static void dfx_int_common(struct net_device *dev)
dfx_int_type_0_process(bp); /* process Type 0 interrupts */
}
-
+
/*
* =================
* = dfx_interrupt =
@@ -1780,18 +1780,18 @@ static irqreturn_t dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-
+
/*
* =====================
* = dfx_ctl_get_stats =
* =====================
- *
+ *
* Overview:
* Get statistics for FDDI adapter
- *
+ *
* Returns:
* Pointer to FDDI statistics structure
- *
+ *
* Arguments:
* dev - pointer to device information
*
@@ -1967,19 +1967,19 @@ static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev)
return((struct net_device_stats *) &bp->stats);
}
-
+
/*
* ==============================
* = dfx_ctl_set_multicast_list =
* ==============================
- *
+ *
* Overview:
* Enable/Disable LLC frame promiscuous mode reception
* on the adapter and/or update multicast address table.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* dev - pointer to device information
*
@@ -2088,19 +2088,19 @@ static void dfx_ctl_set_multicast_list(struct net_device *dev)
}
}
-
+
/*
* ===========================
* = dfx_ctl_set_mac_address =
* ===========================
- *
+ *
* Overview:
* Add node address override (unicast address) to adapter
* CAM and update dev_addr field in device table.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* dev - pointer to device information
* addr - pointer to sockaddr structure containing unicast address to add
@@ -2178,7 +2178,7 @@ static int dfx_ctl_set_mac_address(struct net_device *dev, void *addr)
return(0); /* always return zero */
}
-
+
/*
* ======================
* = dfx_ctl_update_cam =
@@ -2263,7 +2263,7 @@ static int dfx_ctl_update_cam(DFX_board_t *bp)
return(DFX_K_SUCCESS);
}
-
+
/*
* ==========================
* = dfx_ctl_update_filters =
@@ -2272,10 +2272,10 @@ static int dfx_ctl_update_cam(DFX_board_t *bp)
* Overview:
* Procedure to update adapter filters with desired
* filter settings.
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -2329,18 +2329,18 @@ static int dfx_ctl_update_filters(DFX_board_t *bp)
return(DFX_K_SUCCESS);
}
-
+
/*
* ======================
* = dfx_hw_dma_cmd_req =
* ======================
- *
+ *
* Overview:
* Sends PDQ DMA command to adapter firmware
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -2374,9 +2374,9 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
{
int status; /* adapter status */
int timeout_cnt; /* used in for loops */
-
+
/* Make sure the adapter is in a state that we can issue the DMA command in */
-
+
status = dfx_hw_adap_state_rd(bp);
if ((status == PI_STATE_K_RESET) ||
(status == PI_STATE_K_HALTED) ||
@@ -2397,7 +2397,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
dfx_port_write_long(bp, PI_PDQ_K_REG_CMD_RSP_PROD, bp->cmd_rsp_reg.lword);
/* Put request buffer on the command request queue */
-
+
bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_0 = (u32) (PI_XMT_DESCR_M_SOP |
PI_XMT_DESCR_M_EOP | (PI_CMD_REQ_K_SIZE_MAX << PI_XMT_DESCR_V_SEG_LEN));
bp->descr_block_virt->cmd_req[bp->cmd_req_reg.index.prod].long_1 = bp->cmd_req_phys;
@@ -2419,7 +2419,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
break;
udelay(100); /* wait for 100 microseconds */
}
- if (timeout_cnt == 0)
+ if (timeout_cnt == 0)
return(DFX_K_HW_TIMEOUT);
/* Bump (and wrap) the completion index and write out to register */
@@ -2439,7 +2439,7 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
break;
udelay(100); /* wait for 100 microseconds */
}
- if (timeout_cnt == 0)
+ if (timeout_cnt == 0)
return(DFX_K_HW_TIMEOUT);
/* Bump (and wrap) the completion index and write out to register */
@@ -2450,18 +2450,18 @@ static int dfx_hw_dma_cmd_req(DFX_board_t *bp)
return(DFX_K_SUCCESS);
}
-
+
/*
* ========================
* = dfx_hw_port_ctrl_req =
* ========================
- *
+ *
* Overview:
* Sends PDQ port control command to adapter firmware
- *
+ *
* Returns:
* Host data register value in host_data if ptr is not NULL
- *
+ *
* Arguments:
* bp - pointer to board information
* command - port control command
@@ -2497,7 +2497,7 @@ static int dfx_hw_port_ctrl_req(
int timeout_cnt; /* used in for loops */
/* Set Command Error bit in command longword */
-
+
port_cmd = (PI_UINT32) (command | PI_PCTRL_M_CMD_ERROR);
/* Issue port command to the adapter */
@@ -2520,12 +2520,12 @@ static int dfx_hw_port_ctrl_req(
break;
udelay(100); /* wait for 100 microseconds */
}
- if (timeout_cnt == 0)
+ if (timeout_cnt == 0)
return(DFX_K_HW_TIMEOUT);
/*
- * If the address of host_data is non-zero, assume caller has supplied a
- * non NULL pointer, and return the contents of the HOST_DATA register in
+ * If the address of host_data is non-zero, assume caller has supplied a
+ * non NULL pointer, and return the contents of the HOST_DATA register in
* it.
*/
@@ -2534,18 +2534,18 @@ static int dfx_hw_port_ctrl_req(
return(DFX_K_SUCCESS);
}
-
+
/*
* =====================
* = dfx_hw_adap_reset =
* =====================
- *
+ *
* Overview:
* Resets adapter
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
* type - type of reset to perform
@@ -2588,18 +2588,18 @@ static void dfx_hw_adap_reset(
dfx_port_write_long(bp, PI_PDQ_K_REG_PORT_RESET, 0);
}
-
+
/*
* ========================
* = dfx_hw_adap_state_rd =
* ========================
- *
+ *
* Overview:
* Returns current adapter state
- *
+ *
* Returns:
* Adapter state per PDQ Port Specification
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -2624,18 +2624,18 @@ static int dfx_hw_adap_state_rd(DFX_board_t *bp)
return((port_status & PI_PSTATUS_M_STATE) >> PI_PSTATUS_V_STATE);
}
-
+
/*
* =====================
* = dfx_hw_dma_uninit =
* =====================
- *
+ *
* Overview:
* Brings adapter to DMA_UNAVAILABLE state
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* bp - pointer to board information
* type - type of reset to perform
@@ -2672,38 +2672,38 @@ static int dfx_hw_dma_uninit(DFX_board_t *bp, PI_UINT32 type)
break;
udelay(100); /* wait for 100 microseconds */
}
- if (timeout_cnt == 0)
+ if (timeout_cnt == 0)
return(DFX_K_HW_TIMEOUT);
return(DFX_K_SUCCESS);
}
-
+
/*
* Align an sk_buff to a boundary power of 2
*
*/
-
+
static void my_skb_align(struct sk_buff *skb, int n)
{
unsigned long x = (unsigned long)skb->data;
unsigned long v;
-
+
v = ALIGN(x, n); /* Where we want to be */
-
+
skb_reserve(skb, v - x);
}
-
+
/*
* ================
* = dfx_rcv_init =
* ================
- *
+ *
* Overview:
* Produces buffers to adapter LLC Host receive descriptor block
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
* get_buffers - non-zero if buffers to be allocated
@@ -2764,7 +2764,7 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
* align to 128 bytes for compatibility with
* the old EISA boards.
*/
-
+
my_skb_align(newskb, 128);
bp->descr_block_virt->rcv_data[i + j].long_1 =
(u32)pci_map_single(bp->pci_dev, newskb->data,
@@ -2795,18 +2795,18 @@ static int dfx_rcv_init(DFX_board_t *bp, int get_buffers)
return 0;
}
-
+
/*
* =========================
* = dfx_rcv_queue_process =
* =========================
- *
+ *
* Overview:
* Process received LLC frames.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -2880,7 +2880,7 @@ static void dfx_rcv_queue_process(
newskb = dev_alloc_skb(NEW_SKB_SIZE);
if (newskb){
rx_in_place = 1;
-
+
my_skb_align(newskb, 128);
skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
pci_unmap_single(bp->pci_dev,
@@ -2914,7 +2914,7 @@ static void dfx_rcv_queue_process(
memcpy(skb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
}
-
+
skb_reserve(skb,3); /* adjust data field so that it points to FC byte */
skb_put(skb, pkt_len); /* pass up packet length, NOT including CRC */
skb->dev = bp->dev; /* pass up device pointer */
@@ -2945,18 +2945,18 @@ static void dfx_rcv_queue_process(
}
}
-
+
/*
* =====================
* = dfx_xmt_queue_pkt =
* =====================
- *
+ *
* Overview:
* Queues packets for transmission
- *
+ *
* Returns:
* Condition code
- *
+ *
* Arguments:
* skb - pointer to sk_buff to queue for transmission
* dev - pointer to device information
@@ -3020,7 +3020,7 @@ static int dfx_xmt_queue_pkt(
unsigned long flags;
netif_stop_queue(dev);
-
+
/*
* Verify that incoming transmit request is OK
*
@@ -3032,7 +3032,7 @@ static int dfx_xmt_queue_pkt(
if (!IN_RANGE(skb->len, FDDI_K_LLC_ZLEN, FDDI_K_LLC_LEN))
{
- printk("%s: Invalid packet length - %u bytes\n",
+ printk("%s: Invalid packet length - %u bytes\n",
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
netif_wake_queue(dev);
@@ -3065,7 +3065,7 @@ static int dfx_xmt_queue_pkt(
}
spin_lock_irqsave(&bp->lock, flags);
-
+
/* Get the current producer and the next free xmt data descriptor */
prod = bp->rcv_xmt_reg.index.xmt_prod;
@@ -3167,18 +3167,18 @@ static int dfx_xmt_queue_pkt(
return(0); /* packet queued to adapter */
}
-
+
/*
* ================
* = dfx_xmt_done =
* ================
- *
+ *
* Overview:
* Processes all frames that have been transmitted.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -3246,18 +3246,18 @@ static int dfx_xmt_done(DFX_board_t *bp)
return freed;
}
-
+
/*
* =================
* = dfx_rcv_flush =
* =================
- *
+ *
* Overview:
* Remove all skb's in the receive ring.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -3299,14 +3299,14 @@ static inline void dfx_rcv_flush( DFX_board_t *bp )
* =================
* = dfx_xmt_flush =
* =================
- *
+ *
* Overview:
* Processes all frames whether they've been transmitted
* or not.
- *
+ *
* Returns:
* None
- *
+ *
* Arguments:
* bp - pointer to board information
*
@@ -3444,13 +3444,13 @@ static int __init dfx_init(void)
{
int rc_pci, rc_eisa;
- rc_pci = pci_module_init(&dfx_driver);
+ rc_pci = pci_register_driver(&dfx_driver);
if (rc_pci >= 0) dfx_have_pci = 1;
-
+
rc_eisa = dfx_eisa_init();
if (rc_eisa >= 0) dfx_have_eisa = 1;
- return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
+ return ((rc_eisa < 0) ? 0 : rc_eisa) + ((rc_pci < 0) ? 0 : rc_pci);
}
static void __exit dfx_cleanup(void)
@@ -3459,8 +3459,8 @@ static void __exit dfx_cleanup(void)
pci_unregister_driver(&dfx_driver);
if (dfx_have_eisa)
dfx_eisa_cleanup();
-
-}
+
+}
module_init(dfx_init);
module_exit(dfx_cleanup);
@@ -3469,7 +3469,7 @@ MODULE_DESCRIPTION("DEC FDDIcontroller EISA/PCI (DEFEA/DEFPA) driver "
DRV_VERSION " " DRV_RELDATE);
MODULE_LICENSE("GPL");
-
+
/*
* Local variables:
* kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c"
diff --git a/drivers/net/defxx.h b/drivers/net/defxx.h
index a480b80d2f9..8b1e9a11ca2 100644
--- a/drivers/net/defxx.h
+++ b/drivers/net/defxx.h
@@ -45,7 +45,7 @@ typedef struct /* 64-bit counter */
} PI_CNTR;
typedef struct /* LAN address */
- {
+ {
PI_UINT32 lwrd_0;
PI_UINT32 lwrd_1;
} PI_LAN_ADDR;
@@ -146,7 +146,7 @@ typedef struct /* Station ID address */
#define PI_STATE_K_LINK_UNAVAIL 5
#define PI_STATE_K_HALTED 6
#define PI_STATE_K_RING_MEMBER 7
-#define PI_STATE_K_NUMBER 8
+#define PI_STATE_K_NUMBER 8
/* Define codes for command type */
@@ -175,9 +175,9 @@ typedef struct /* Station ID address */
#define PI_ITEM_K_EOL 0x00 /* End-of-Item list */
#define PI_ITEM_K_T_REQ 0x01 /* DECnet T_REQ */
#define PI_ITEM_K_TVX 0x02 /* DECnet TVX */
-#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */
+#define PI_ITEM_K_RESTRICTED_TOKEN 0x03 /* DECnet Restricted Token */
#define PI_ITEM_K_LEM_THRESHOLD 0x04 /* DECnet LEM Threshold */
-#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */
+#define PI_ITEM_K_RING_PURGER 0x05 /* DECnet Ring Purger Enable */
#define PI_ITEM_K_CNTR_INTERVAL 0x06 /* Chars_Set */
#define PI_ITEM_K_IND_GROUP_PROM 0x07 /* Filters_Set */
#define PI_ITEM_K_GROUP_PROM 0x08 /* Filters_Set */
@@ -283,16 +283,16 @@ typedef struct
/* Start Response */
-typedef struct
+typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_START_RSP;
/* Filters_Set Request */
#define PI_CMD_FILTERS_SET_K_ITEMS_MAX 63 /* Fits in a 512 byte buffer */
-typedef struct
+typedef struct
{
PI_UINT32 cmd_type;
PI_ITEM_LIST item[PI_CMD_FILTERS_SET_K_ITEMS_MAX];
@@ -302,21 +302,21 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_FILTERS_SET_RSP;
/* Filters_Get Request */
typedef struct
{
- PI_UINT32 cmd_type;
+ PI_UINT32 cmd_type;
} PI_CMD_FILTERS_GET_REQ;
/* Filters_Get Response */
-typedef struct
+typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
PI_UINT32 ind_group_prom;
PI_UINT32 group_prom;
PI_UINT32 broadcast_all;
@@ -339,14 +339,14 @@ typedef struct
PI_UINT32 item_code;
PI_UINT32 value;
PI_UINT32 item_index;
- } item[PI_CMD_CHARS_SET_K_ITEMS_MAX];
+ } item[PI_CMD_CHARS_SET_K_ITEMS_MAX];
} PI_CMD_CHARS_SET_REQ;
/* Chars_Set Response */
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_CHARS_SET_RSP;
@@ -362,20 +362,20 @@ typedef struct
PI_UINT32 item_code;
PI_UINT32 value;
PI_UINT32 item_index;
- } item[PI_CMD_SNMP_SET_K_ITEMS_MAX];
+ } item[PI_CMD_SNMP_SET_K_ITEMS_MAX];
} PI_CMD_SNMP_SET_REQ;
/* SNMP_Set Response */
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_SNMP_SET_RSP;
/* SMT_MIB_Set Request */
-#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */
+#define PI_CMD_SMT_MIB_SET_K_ITEMS_MAX 42 /* Max number of items */
typedef struct
{
@@ -392,7 +392,7 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_SMT_MIB_SET_RSP;
/* SMT_MIB_Get Request */
@@ -407,8 +407,8 @@ typedef struct
typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */
{
PI_RSP_HEADER header;
-
- /* SMT GROUP */
+
+ /* SMT GROUP */
PI_STATION_ID smt_station_id;
PI_UINT32 smt_op_version_id;
@@ -485,7 +485,7 @@ typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */
PI_UINT32 port_connection_capabilities[PI_PHY_K_MAX];
PI_UINT32 port_bs_flag[PI_PHY_K_MAX];
PI_UINT32 port_ler_estimate[PI_PHY_K_MAX];
- PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
PI_UINT32 port_ler_alarm[PI_PHY_K_MAX];
PI_UINT32 port_connect_state[PI_PHY_K_MAX];
PI_UINT32 port_pcm_state[PI_PHY_K_MAX];
@@ -497,7 +497,7 @@ typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */
PI_CNTR path_ring_latency;
- } PI_CMD_SMT_MIB_GET_RSP;
+ } PI_CMD_SMT_MIB_GET_RSP;
/*
@@ -506,7 +506,7 @@ typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */
* certain host-sent SMT frames such as PMF Get and Set requests. The
* codes have been taken from the MIB summary section of ANSI SMT 7.3.
*/
-
+
#define PI_GRP_K_SMT_STATION_ID 0x100A
#define PI_ITEM_K_SMT_STATION_ID 0x100B
#define PI_ITEM_K_SMT_OP_VERS_ID 0x100D
@@ -536,7 +536,7 @@ typedef struct /* Refer to ANSI FDDI SMT Rev. 7.3 */
#define PI_ITEM_K_SMT_REM_DISC_FLAG 0x102C
#define PI_ITEM_K_SMT_STATION_STATUS 0x102D
#define PI_ITEM_K_SMT_PEER_WRAP_FLAG 0x102E
-
+
#define PI_GRP_K_SMT_MIB_OPERATION 0x1032
#define PI_ITEM_K_SMT_MSG_TIME_STAMP 0x1033
#define PI_ITEM_K_SMT_TRN_TIME_STAMP 0x1034
@@ -643,9 +643,9 @@ typedef struct
/* Addr_Filter_Set Response */
-typedef struct
+typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_ADDR_FILTER_SET_RSP;
/* Addr_Filter_Get Request */
@@ -659,7 +659,7 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
PI_LAN_ADDR entry[PI_CMD_ADDR_FILTER_K_SIZE];
} PI_CMD_ADDR_FILTER_GET_RSP;
@@ -674,7 +674,7 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
PI_STATION_ID station_id; /* Station */
PI_UINT32 station_type;
PI_UINT32 smt_ver_id;
@@ -728,66 +728,66 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
/* SMT GROUP */
- PI_STATION_ID smt_station_id;
+ PI_STATION_ID smt_station_id;
PI_UINT32 smt_op_version_id;
PI_UINT32 smt_hi_version_id;
PI_UINT32 smt_lo_version_id;
- PI_UINT32 smt_mac_ct;
- PI_UINT32 smt_non_master_ct;
- PI_UINT32 smt_master_ct;
- PI_UINT32 smt_paths_available;
- PI_UINT32 smt_config_capabilities;
- PI_UINT32 smt_config_policy;
- PI_UINT32 smt_connection_policy;
- PI_UINT32 smt_t_notify;
+ PI_UINT32 smt_mac_ct;
+ PI_UINT32 smt_non_master_ct;
+ PI_UINT32 smt_master_ct;
+ PI_UINT32 smt_paths_available;
+ PI_UINT32 smt_config_capabilities;
+ PI_UINT32 smt_config_policy;
+ PI_UINT32 smt_connection_policy;
+ PI_UINT32 smt_t_notify;
PI_UINT32 smt_status_reporting;
- PI_UINT32 smt_ecm_state;
- PI_UINT32 smt_cf_state;
- PI_UINT32 smt_hold_state;
+ PI_UINT32 smt_ecm_state;
+ PI_UINT32 smt_cf_state;
+ PI_UINT32 smt_hold_state;
PI_UINT32 smt_remote_disconnect_flag;
- PI_UINT32 smt_station_action;
+ PI_UINT32 smt_station_action;
/* MAC GROUP */
- PI_UINT32 mac_frame_status_capabilities;
+ PI_UINT32 mac_frame_status_capabilities;
PI_UINT32 mac_t_max_greatest_lower_bound;
PI_UINT32 mac_tvx_greatest_lower_bound;
PI_UINT32 mac_paths_available;
PI_UINT32 mac_current_path;
- PI_LAN_ADDR mac_upstream_nbr;
- PI_LAN_ADDR mac_old_upstream_nbr;
- PI_UINT32 mac_dup_addr_test;
+ PI_LAN_ADDR mac_upstream_nbr;
+ PI_LAN_ADDR mac_old_upstream_nbr;
+ PI_UINT32 mac_dup_addr_test;
PI_UINT32 mac_paths_requested;
PI_UINT32 mac_downstream_port_type;
- PI_LAN_ADDR mac_smt_address;
- PI_UINT32 mac_t_req;
+ PI_LAN_ADDR mac_smt_address;
+ PI_UINT32 mac_t_req;
PI_UINT32 mac_t_neg;
- PI_UINT32 mac_t_max;
- PI_UINT32 mac_tvx_value;
- PI_UINT32 mac_t_min;
+ PI_UINT32 mac_t_max;
+ PI_UINT32 mac_tvx_value;
+ PI_UINT32 mac_t_min;
PI_UINT32 mac_current_frame_status;
/* mac_frame_cts */
/* mac_error_cts */
/* mac_lost_cts */
- PI_UINT32 mac_frame_error_threshold;
- PI_UINT32 mac_frame_error_ratio;
+ PI_UINT32 mac_frame_error_threshold;
+ PI_UINT32 mac_frame_error_ratio;
PI_UINT32 mac_rmt_state;
PI_UINT32 mac_da_flag;
- PI_UINT32 mac_una_da_flag;
+ PI_UINT32 mac_una_da_flag;
PI_UINT32 mac_frame_condition;
- PI_UINT32 mac_chip_set;
- PI_UINT32 mac_action;
+ PI_UINT32 mac_chip_set;
+ PI_UINT32 mac_action;
/* PATH GROUP => Does not need to be implemented */
/* PORT GROUP */
- PI_UINT32 port_pc_type[PI_PHY_K_MAX];
- PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX];
+ PI_UINT32 port_pc_type[PI_PHY_K_MAX];
+ PI_UINT32 port_pc_neighbor[PI_PHY_K_MAX];
PI_UINT32 port_connection_policies[PI_PHY_K_MAX];
PI_UINT32 port_remote_mac_indicated[PI_PHY_K_MAX];
PI_UINT32 port_ce_state[PI_PHY_K_MAX];
@@ -798,17 +798,17 @@ typedef struct
PI_UINT32 port_tb_max[PI_PHY_K_MAX];
PI_UINT32 port_bs_flag[PI_PHY_K_MAX];
/* port_lct_fail_cts[PI_PHY_K_MAX]; */
- PI_UINT32 port_ler_estimate[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_estimate[PI_PHY_K_MAX];
/* port_lem_reject_cts[PI_PHY_K_MAX]; */
/* port_lem_cts[PI_PHY_K_MAX]; */
- PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
- PI_UINT32 port_ler_alarm[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_cutoff[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_alarm[PI_PHY_K_MAX];
PI_UINT32 port_connect_state[PI_PHY_K_MAX];
PI_UINT32 port_pcm_state[PI_PHY_K_MAX];
PI_UINT32 port_pc_withhold[PI_PHY_K_MAX];
- PI_UINT32 port_ler_condition[PI_PHY_K_MAX];
- PI_UINT32 port_chip_set[PI_PHY_K_MAX];
- PI_UINT32 port_action[PI_PHY_K_MAX];
+ PI_UINT32 port_ler_condition[PI_PHY_K_MAX];
+ PI_UINT32 port_chip_set[PI_PHY_K_MAX];
+ PI_UINT32 port_action[PI_PHY_K_MAX];
/* ATTACHMENT GROUP */
@@ -833,7 +833,7 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
/* SMT GROUP */
@@ -841,7 +841,7 @@ typedef struct
/* MAC GROUP */
- PI_UINT32 emac_link_state;
+ PI_UINT32 emac_link_state;
PI_UINT32 emac_ring_purger_state;
PI_UINT32 emac_ring_purger_enable;
PI_UINT32 emac_frame_strip_mode;
@@ -915,9 +915,9 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
- PI_CNTR time_since_reset;
- PI_CNTR_BLK cntrs;
+ PI_RSP_HEADER header;
+ PI_CNTR time_since_reset;
+ PI_CNTR_BLK cntrs;
} PI_CMD_CNTRS_GET_RSP;
/* Counters_Set Request */
@@ -925,14 +925,14 @@ typedef struct
typedef struct
{
PI_UINT32 cmd_type;
- PI_CNTR_BLK cntrs;
+ PI_CNTR_BLK cntrs;
} PI_CMD_CNTRS_SET_REQ;
/* Counters_Set Response */
-typedef struct
+typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_CNTRS_SET_RSP;
/* Error_Log_Clear Request */
@@ -946,7 +946,7 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
} PI_CMD_ERROR_LOG_CLEAR_RSP;
/* Error_Log_Get Request */
@@ -966,7 +966,7 @@ typedef struct
typedef struct
{
- struct
+ struct
{
PI_UINT32 fru_imp_mask;
PI_UINT32 test_id;
@@ -977,7 +977,7 @@ typedef struct
typedef struct
{
- PI_RSP_HEADER header;
+ PI_RSP_HEADER header;
PI_UINT32 event_status;
PI_UINT32 caller_id;
PI_UINT32 timestamp_l;
@@ -993,7 +993,7 @@ typedef struct
#define PI_LOG_EVENT_STATUS_K_VALID 0 /* Valid Event Status */
#define PI_LOG_EVENT_STATUS_K_INVALID 1 /* Invalid Event Status */
#define PI_LOG_CALLER_ID_K_NONE 0 /* No caller */
-#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */
+#define PI_LOG_CALLER_ID_K_SELFTEST 1 /* Normal power-up selftest */
#define PI_LOG_CALLER_ID_K_MFG 2 /* Mfg power-up selftest */
#define PI_LOG_CALLER_ID_K_ONLINE 3 /* On-line diagnostics */
#define PI_LOG_CALLER_ID_K_HW 4 /* Hardware */
@@ -1026,7 +1026,7 @@ typedef union
PI_CMD_DEC_EXT_MIB_GET_REQ dec_mib_get;
PI_CMD_SMT_MIB_SET_REQ smt_mib_set;
PI_CMD_SMT_MIB_GET_REQ smt_mib_get;
- char pad[PI_CMD_REQ_K_SIZE_MAX];
+ char pad[PI_CMD_REQ_K_SIZE_MAX];
} PI_DMA_CMD_REQ;
typedef union
@@ -1048,7 +1048,7 @@ typedef union
PI_CMD_DEC_EXT_MIB_GET_RSP dec_mib_get;
PI_CMD_SMT_MIB_SET_RSP smt_mib_set;
PI_CMD_SMT_MIB_GET_RSP smt_mib_get;
- char pad[PI_CMD_RSP_K_SIZE_MAX];
+ char pad[PI_CMD_RSP_K_SIZE_MAX];
} PI_DMA_CMD_RSP;
typedef union
@@ -1094,7 +1094,7 @@ typedef struct
#define PI_DESCR_BLK_K_SMT_HOST 0x1000
#define PI_DESCR_BLK_K_UNSOL 0x1200
#define PI_DESCR_BLK_K_CMD_RSP 0x1280
-#define PI_DESCR_BLK_K_CMD_REQ 0x1300
+#define PI_DESCR_BLK_K_CMD_REQ 0x1300
/* Define format of a rcv descr (Rcv Data, Cmd Rsp, Unsolicited, SMT Host) */
/* Note a field has been added for later versions of the PDQ to allow for */
@@ -1110,10 +1110,10 @@ typedef struct
} PI_RCV_DESCR;
#define PI_RCV_DESCR_M_SOP 0x80000000
-#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000
-#define PI_RCV_DESCR_M_MBZ 0x60000000
+#define PI_RCV_DESCR_M_SEG_LEN_LO 0x60000000
+#define PI_RCV_DESCR_M_MBZ 0x60000000
#define PI_RCV_DESCR_M_SEG_LEN 0x1F800000
-#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000
+#define PI_RCV_DESCR_M_SEG_LEN_HI 0x1FF00000
#define PI_RCV_DESCR_M_SEG_CNT 0x000F0000
#define PI_RCV_DESCR_M_BUFF_HI 0x0000FFFF
@@ -1121,7 +1121,7 @@ typedef struct
#define PI_RCV_DESCR_V_SEG_LEN_LO 29
#define PI_RCV_DESCR_V_MBZ 29
#define PI_RCV_DESCR_V_SEG_LEN 23
-#define PI_RCV_DESCR_V_SEG_LEN_HI 20
+#define PI_RCV_DESCR_V_SEG_LEN_HI 20
#define PI_RCV_DESCR_V_SEG_CNT 16
#define PI_RCV_DESCR_V_BUFF_HI 0
@@ -1135,7 +1135,7 @@ typedef struct
#define PI_XMT_DESCR_M_SOP 0x80000000
#define PI_XMT_DESCR_M_EOP 0x40000000
-#define PI_XMT_DESCR_M_MBZ 0x20000000
+#define PI_XMT_DESCR_M_MBZ 0x20000000
#define PI_XMT_DESCR_M_SEG_LEN 0x1FFF0000
#define PI_XMT_DESCR_M_BUFF_HI 0x0000FFFF
@@ -1195,7 +1195,7 @@ typedef struct
#define PI_PCTRL_M_CONS_BLOCK 0x0040
#define PI_PCTRL_M_UNINIT 0x0020
#define PI_PCTRL_M_RING_MEMBER 0x0010
-#define PI_PCTRL_M_MLA 0x0008
+#define PI_PCTRL_M_MLA 0x0008
#define PI_PCTRL_M_FW_REV_READ 0x0004
#define PI_PCTRL_M_DEV_SPECIFIC 0x0002
#define PI_PCTRL_M_SUB_CMD 0x0001
@@ -1230,12 +1230,12 @@ typedef struct
#define PI_PDATA_A_INIT_M_DESC_BLK_ADDR 0x0FFFFE000
#define PI_PDATA_A_INIT_M_RESERVED 0x000001FFC
-#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002
+#define PI_PDATA_A_INIT_M_BSWAP_DATA 0x000000002
#define PI_PDATA_A_INIT_M_BSWAP_LITERAL 0x000000001
#define PI_PDATA_A_INIT_V_DESC_BLK_ADDR 13
#define PI_PDATA_A_INIT_V_RESERVED 3
-#define PI_PDATA_A_INIT_V_BSWAP_DATA 1
+#define PI_PDATA_A_INIT_V_BSWAP_DATA 1
#define PI_PDATA_A_INIT_V_BSWAP_LITERAL 0
/* Port Reset Register */
@@ -1281,11 +1281,11 @@ typedef struct
#define PI_HALT_ID_K_IMAGE_CRC_ERROR 7 /* Image is bad, update it */
#define PI_HALT_ID_K_BUS_EXCEPTION 8 /* 68K bus exception */
-/* Host Interrupt Enable Register as seen by host */
+/* Host Interrupt Enable Register as seen by host */
#define PI_HOST_INT_M_XMT_DATA_ENB 0x80000000 /* Type 2 Enables */
-#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000
-#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */
+#define PI_HOST_INT_M_RCV_DATA_ENB 0x40000000
+#define PI_HOST_INT_M_SMT_HOST_ENB 0x10000000 /* Type 1 Enables */
#define PI_HOST_INT_M_UNSOL_ENB 0x20000000
#define PI_HOST_INT_M_CMD_RSP_ENB 0x08000000
#define PI_HOST_INT_M_CMD_REQ_ENB 0x04000000
@@ -1301,8 +1301,8 @@ typedef struct
#define PI_HOST_INT_M_BUS_PAR_ERR 0x00000001
#define PI_HOST_INT_V_XMT_DATA_ENB 31 /* Type 2 Enables */
-#define PI_HOST_INT_V_RCV_DATA_ENB 30
-#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */
+#define PI_HOST_INT_V_RCV_DATA_ENB 30
+#define PI_HOST_INT_V_SMT_HOST_ENB 29 /* Type 1 Enables */
#define PI_HOST_INT_V_UNSOL_ENB 28
#define PI_HOST_INT_V_CMD_RSP_ENB 27
#define PI_HOST_INT_V_CMD_REQ_ENB 26
@@ -1333,8 +1333,8 @@ typedef struct
#define PI_TYPE_0_STAT_M_PM_PAR_ERR 0x00000002
#define PI_TYPE_0_STAT_M_BUS_PAR_ERR 0x00000001
-#define PI_TYPE_0_STAT_V_1MS 7
-#define PI_TYPE_0_STAT_V_20MS 6
+#define PI_TYPE_0_STAT_V_1MS 7
+#define PI_TYPE_0_STAT_V_20MS 6
#define PI_TYPE_0_STAT_V_CSR_CMD_DONE 5
#define PI_TYPE_0_STAT_V_STATE_CHANGE 4
#define PI_TYPE_0_STAT_V_XMT_FLUSH 3
@@ -1692,7 +1692,7 @@ typedef struct DFX_board_tag
{
/* Keep virtual and physical pointers to locked, physically contiguous memory */
- char *kmalloced; /* pci_free_consistent this on unload */
+ char *kmalloced; /* pci_free_consistent this on unload */
dma_addr_t kmalloced_dma;
/* DMA handle for the above */
PI_DESCR_BLOCK *descr_block_virt; /* PDQ descriptor block virt address */
@@ -1739,9 +1739,9 @@ typedef struct DFX_board_tag
/* Store pointers to transmit buffers for transmit completion code */
XMT_DRIVER_DESCR xmt_drv_descr_blk[PI_XMT_DATA_K_NUM_ENTRIES];
-
+
/* Transmit spinlocks */
-
+
spinlock_t lock;
/* Store device, bus-specific, and parameter information for this adapter */
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index e946c43d3b1..af594664df5 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -4,9 +4,9 @@
Copyright 1994 David C. Davies
- and
+ and
United States Government
- (as represented by the Director, National Security Agency).
+ (as represented by the Director, National Security Agency).
Copyright 1995 Digital Equipment Corporation.
@@ -61,7 +61,7 @@
Digital Equipment Corporation, 1989
8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
-
+
Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
driver.
@@ -135,20 +135,20 @@
[Alan Cox: Changed the code to allow command line irq/io assignments]
[Dave Davies: Changed the code to allow command line mem/name
assignments]
- 6) run the net startup bits for your eth?? interface manually
- (usually /etc/rc.inet[12] at boot time).
+ 6) run the net startup bits for your eth?? interface manually
+ (usually /etc/rc.inet[12] at boot time).
7) enjoy!
Note that autoprobing is not allowed in loadable modules - the system is
already up and running and you're messing with interrupts.
- To unload a module, turn off the associated interface
+ To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod depca'.
To assign a base memory address for the shared memory when running as a
loadable module, see 5 above. To include the adapter name (if you have
no PROM but know the card name) also see 5 above. Note that this last
- option will not work with kernel built-in depca's.
+ option will not work with kernel built-in depca's.
The shared memory assignment for a loadable module makes sense to avoid
the 'memory autoprobe' picking the wrong shared memory (for the case of
@@ -157,7 +157,7 @@
************************************************************************
Support for MCA EtherWORKS cards added 11-3-98.
Verified to work with up to 2 DE212 cards in a system (although not
- fully stress-tested).
+ fully stress-tested).
Currently known bugs/limitations:
@@ -176,7 +176,7 @@
----------------
Version Date Description
-
+
0.1 25-jan-94 Initial writing.
0.2 27-jan-94 Added LANCE TX hardware buffer chaining.
0.3 1-feb-94 Added multiple DEPCA support.
@@ -190,7 +190,7 @@
0.351 30-apr-94 Added EISA support. Added DE422 recognition.
0.36 16-may-94 DE422 fix released.
0.37 22-jul-94 Added MODULE support
- 0.38 15-aug-94 Added DBR ROM switch in depca_close().
+ 0.38 15-aug-94 Added DBR ROM switch in depca_close().
Multi DEPCA bug fix.
0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0.
0.381 12-dec-94 Added DE101 recognition, fix multicast bug.
@@ -198,17 +198,17 @@
0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
<stromain@alf.dec.com>
0.384 17-mar-95 Fix a ring full bug reported by <bkm@star.rl.ac.uk>
- 0.385 3-apr-95 Fix a recognition bug reported by
+ 0.385 3-apr-95 Fix a recognition bug reported by
<ryan.niemi@lastfrontier.com>
0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
0.40 25-May-95 Rewrite for portability & updated.
ALPHA support from <jestabro@amt.tay1.dec.com>
0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
suggestion by <heiko@colossus.escape.de>
- 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
+ 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
modules.
Add 'adapter_name' for loadable modules when no PROM.
- Both above from a suggestion by
+ Both above from a suggestion by
<pchen@woodruffs121.residence.gatech.edu>.
Add new multicasting code.
0.421 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
@@ -218,7 +218,7 @@
0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
reported by <mmogilvi@elbert.uccs.edu>
0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
- by <tymm@computer.org>
+ by <tymm@computer.org>
0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
0.5 14-Nov-98 Re-spin for 2.1.x kernels.
0.51 27-Jun-99 Correct received packet length for CRC from
@@ -235,7 +235,6 @@
=========================================================================
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -412,7 +411,7 @@ static struct platform_driver depca_isa_driver = {
.name = depca_string,
},
};
-
+
/*
** Miscellaneous info...
*/
@@ -422,14 +421,14 @@ static struct platform_driver depca_isa_driver = {
** Memory Alignment. Each descriptor is 4 longwords long. To force a
** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
** DESC_ALIGN. DEPCA_ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
+** and hence the RX descriptor ring's first entry.
*/
#define DEPCA_ALIGN4 ((u_long)4 - 1) /* 1 longword align */
#define DEPCA_ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */
#define DEPCA_ALIGN DEPCA_ALIGN8 /* Keep the LANCE happy... */
/*
-** The DEPCA Rx and Tx ring descriptors.
+** The DEPCA Rx and Tx ring descriptors.
*/
struct depca_rx_desc {
volatile s32 base;
@@ -592,7 +591,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
*/
ioaddr = dev->base_addr;
-
+
STOP_DEPCA;
nicsr = inb(DEPCA_NICSR);
@@ -611,7 +610,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
printk ("%s: %s at 0x%04lx",
device->bus_id, depca_signature[lp->adapter], ioaddr);
-
+
switch (lp->depca_bus) {
#ifdef CONFIG_MCA
case DEPCA_BUS_MCA:
@@ -658,7 +657,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
if (lp->depca_bus != DEPCA_BUS_MCA)
mem_start += 0x8000;
}
-
+
if ((mem_len = (NUM_RX_DESC * (sizeof(struct depca_rx_desc) + RX_BUFF_SZ) + NUM_TX_DESC * (sizeof(struct depca_tx_desc) + TX_BUFF_SZ) + sizeof(struct depca_init)))
> (netRAM << 10)) {
printk(",\n requests %dkB RAM: only %dkB is available!\n", (mem_len >> 10), netRAM);
@@ -683,7 +682,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
goto out_priv;
}
-
+
status = -EIO;
lp->sh_mem = ioremap(mem_start, mem_len);
if (lp->sh_mem == NULL) {
@@ -812,7 +811,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device)
device->driver_data = dev;
SET_NETDEV_DEV (dev, device);
-
+
status = register_netdev(dev);
if (status == 0)
return 0;
@@ -823,7 +822,7 @@ out1:
out_priv:
return status;
}
-
+
static int depca_open(struct net_device *dev)
{
@@ -925,8 +924,8 @@ static void depca_tx_timeout(struct net_device *dev)
}
-/*
-** Writes a socket buffer to TX descriptor ring and starts transmission
+/*
+** Writes a socket buffer to TX descriptor ring and starts transmission
*/
static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -940,7 +939,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (skb_padto(skb, ETH_ZLEN))
goto out;
-
+
netif_stop_queue(dev);
if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
@@ -964,7 +963,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/*
-** The DEPCA interrupt handler.
+** The DEPCA interrupt handler.
*/
static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -1054,8 +1053,8 @@ static int depca_rx(struct net_device *dev)
memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
}
- /*
- ** Notify the upper protocol layers that there is another
+ /*
+ ** Notify the upper protocol layers that there is another
** packet to handle
*/
skb->protocol = eth_type_trans(skb, dev);
@@ -1168,9 +1167,9 @@ static int depca_close(struct net_device *dev)
printk("%s: Shutting down ethercard, status was %2.2x.\n", dev->name, inw(DEPCA_DATA));
}
- /*
+ /*
** We stop the DEPCA here -- it occasionally polls
- ** memory if we don't.
+ ** memory if we don't.
*/
outw(STOP, DEPCA_DATA);
@@ -1321,12 +1320,12 @@ static void SetMulticastFilter(struct net_device *dev)
static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
{
int status = 0;
-
+
if (!request_region (ioaddr, DEPCA_TOTAL_SIZE, depca_string)) {
status = -EBUSY;
goto out;
}
-
+
if (DevicePresent(ioaddr)) {
status = -ENODEV;
goto out_release;
@@ -1338,7 +1337,7 @@ static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
}
return 0;
-
+
out_release:
release_region (ioaddr, DEPCA_TOTAL_SIZE);
out:
@@ -1360,16 +1359,16 @@ static int __init depca_mca_probe(struct device *device)
struct depca_private *lp;
/*
- ** Search for the adapter. If an address has been given, search
+ ** Search for the adapter. If an address has been given, search
** specifically for the card at that address. Otherwise find the
** first card in the system.
*/
-
+
pos[0] = mca_device_read_stored_pos(mdev, 2);
pos[1] = mca_device_read_stored_pos(mdev, 3);
/*
- ** IO of card is handled by bits 1 and 2 of pos0.
+ ** IO of card is handled by bits 1 and 2 of pos0.
**
** bit2 bit1 IO
** 0 0 0x2c00
@@ -1382,12 +1381,12 @@ static int __init depca_mca_probe(struct device *device)
/*
** Found the adapter we were looking for. Now start setting it up.
- **
+ **
** First work on decoding the IRQ. It's stored in the lower 4 bits
** of pos1. Bits are as follows (from the ADF file):
**
- ** Bits
- ** 3 2 1 0 IRQ
+ ** Bits
+ ** 3 2 1 0 IRQ
** --------------------
** 0 0 1 0 5
** 0 0 0 1 9
@@ -1436,7 +1435,7 @@ static int __init depca_mca_probe(struct device *device)
strncpy(mdev->name, depca_mca_adapter_name[mdev->index],
sizeof(mdev->name));
mca_device_set_claim(mdev, 1);
-
+
/*
** Get everything allocated and initialized... (almost just
** like the ISA and EISA probes)
@@ -1453,10 +1452,10 @@ static int __init depca_mca_probe(struct device *device)
lp->depca_bus = DEPCA_BUS_MCA;
lp->adapter = depca_mca_adapter_type[mdev->index];
lp->mem_start = mem_start;
-
+
if ((err = depca_hw_init(dev, device)))
goto out_free;
-
+
return 0;
out_free:
@@ -1480,7 +1479,7 @@ static void __init depca_platform_probe (void)
for (i = 0; depca_io_ports[i].iobase; i++) {
depca_io_ports[i].device = NULL;
-
+
/* if an address has been specified on the command
* line, use it (if valid) */
if (io && io != depca_io_ports[i].iobase)
@@ -1504,7 +1503,7 @@ static void __init depca_platform_probe (void)
* no hardware at this address. Unregister it, as the
* release fuction will take care of freeing the
* allocated structure */
-
+
depca_io_ports[i].device = NULL;
pldev->dev.platform_data = NULL;
platform_device_unregister (pldev);
@@ -1542,7 +1541,7 @@ static int __init depca_isa_probe (struct platform_device *device)
goto out;
adapter = depca_shmem_probe (&mem_start);
-
+
if (adapter == unknown) {
status = -ENODEV;
goto out_free;
@@ -1555,10 +1554,10 @@ static int __init depca_isa_probe (struct platform_device *device)
lp->depca_bus = DEPCA_BUS_ISA;
lp->adapter = adapter;
lp->mem_start = mem_start;
-
+
if ((status = depca_hw_init(dev, &device->dev)))
goto out_free;
-
+
return 0;
out_free:
@@ -1592,7 +1591,7 @@ static int __init depca_eisa_probe (struct device *device)
* it's address with the ethernet prom)... As we don't parse
* the EISA configuration structures (yet... :-), just rely on
* the ISA probing to sort it out... */
-
+
depca_shmem_probe (&mem_start);
dev->base_addr = ioaddr;
@@ -1601,10 +1600,10 @@ static int __init depca_eisa_probe (struct device *device)
lp->depca_bus = DEPCA_BUS_EISA;
lp->adapter = edev->id.driver_data;
lp->mem_start = mem_start;
-
+
if ((status = depca_hw_init(dev, device)))
goto out_free;
-
+
return 0;
out_free:
@@ -1651,7 +1650,7 @@ static int __init DepcaSignature(char *name, u_long base_addr)
* used, at least on x86. Instead, reserve a memory region a
* board would certainly use. If it works, go ahead. If not,
* run like hell... */
-
+
if (!request_mem_region (mem_addr, 16, depca_string))
return unknown;
@@ -1700,7 +1699,7 @@ static int __init DepcaSignature(char *name, u_long base_addr)
** if the first address octet is a 0x08 - this minimises the chances of
** messing around with some other hardware, but it assumes that this DEPCA
** card initialized itself correctly.
-**
+**
** Search the Ethernet address ROM for the signature. Since the ROM address
** counter can start at an arbitrary point, the search must include the entire
** probe sequence length plus the (length_of_the_signature - 1).
@@ -1805,7 +1804,7 @@ static int load_packet(struct net_device *dev, struct sk_buff *skb)
entry = lp->tx_new; /* Ring around buffer number. */
end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
if (!(readl(&lp->tx_ring[end].base) & T_OWN)) { /* Enough room? */
- /*
+ /*
** Caution: the write order is important here... don't set up the
** ownership rights until all the other information is in place.
*/
@@ -2087,7 +2086,7 @@ static int __init depca_module_init (void)
#endif
err |= platform_driver_register (&depca_isa_driver);
depca_platform_probe ();
-
+
return err;
}
diff --git a/drivers/net/depca.h b/drivers/net/depca.h
index 11785275a66..ee42648dbde 100644
--- a/drivers/net/depca.h
+++ b/drivers/net/depca.h
@@ -20,17 +20,17 @@
#define DEPCA_RBSA ioaddr+0x0e /* RAM buffer starting address (2k buff.) */
/*
-** These are LANCE registers addressable through DEPCA_ADDR
+** These are LANCE registers addressable through DEPCA_ADDR
*/
#define CSR0 0
#define CSR1 1
#define CSR2 2
#define CSR3 3
-/*
-** NETWORK INTERFACE CSR (NI_CSR) bit definitions
+/*
+** NETWORK INTERFACE CSR (NI_CSR) bit definitions
*/
-
+
#define TO 0x0100 /* Time Out for remote boot */
#define SHE 0x0080 /* SHadow memory Enable */
#define BS 0x0040 /* Bank Select */
@@ -42,8 +42,8 @@
#define IEN 0x0002 /* Interrupt tristate ENable (1->enable) */
#define LED 0x0001 /* LED control */
-/*
-** Control and Status Register 0 (CSR0) bit definitions
+/*
+** Control and Status Register 0 (CSR0) bit definitions
*/
#define ERR 0x8000 /* Error summary */
@@ -74,7 +74,7 @@
#define BCON 0x0001 /* Byte CONtrol */
/*
-** Initialization Block Mode Register
+** Initialization Block Mode Register
*/
#define PROM 0x8000 /* Promiscuous Mode */
@@ -88,7 +88,7 @@
#define DRX 0x0001 /* Disable the Receiver */
/*
-** Receive Message Descriptor 1 (RMD1) bit definitions.
+** Receive Message Descriptor 1 (RMD1) bit definitions.
*/
#define R_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
@@ -101,7 +101,7 @@
#define R_ENP 0x0100 /* End of Packet */
/*
-** Transmit Message Descriptor 1 (TMD1) bit definitions.
+** Transmit Message Descriptor 1 (TMD1) bit definitions.
*/
#define T_OWN 0x80000000 /* Owner bit 0 = host, 1 = lance */
@@ -125,10 +125,10 @@
#define TMD3_LCAR 0x0800 /* Loss of CARrier */
#define TMD3_RTRY 0x0400 /* ReTRY error */
-/*
-** EISA configuration Register (CNFG) bit definitions
+/*
+** EISA configuration Register (CNFG) bit definitions
*/
-
+
#define TIMEOUT 0x0100 /* 0:2.5 mins, 1: 30 secs */
#define REMOTE 0x0080 /* Remote Boot Enable -> 1 */
#define IRQ11 0x0040 /* Enable -> 1 */
@@ -165,8 +165,8 @@ struct depca_ioctl {
unsigned char __user *data; /* Pointer to the data buffer */
};
-/*
-** Recognised commands for the driver
+/*
+** Recognised commands for the driver
*/
#define DEPCA_GET_HWADDR 0x01 /* Get the hardware address */
#define DEPCA_SET_HWADDR 0x02 /* Get the hardware address */
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index e175d487668..e9361cb5f4c 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -874,7 +874,7 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd)
privN->bcomm->bc_filter_port = ioc.port;
privN->bcomm->bc_filter_num = ioc.filter;
privN->bcomm->bc_filter_len = ioc.len;
-
+
if (ioc.len)
{
if(copy_from_user(S2HN(privN->bcomm->bc_filter_area),
@@ -986,7 +986,7 @@ ack_intr:
/*
* Download the board firmware
*/
-static int __init
+static int __init
dgrs_download(struct net_device *dev0)
{
DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
@@ -1150,7 +1150,7 @@ dgrs_download(struct net_device *dev0)
/*
* Probe (init) a board
*/
-static int __init
+static int __init
dgrs_probe1(struct net_device *dev)
{
DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
@@ -1190,8 +1190,8 @@ dgrs_probe1(struct net_device *dev)
*/
if (priv->plxreg)
OUTL(dev->base_addr + PLX_LCL2PCI_DOORBELL, 1);
-
- rc = request_irq(dev->irq, &dgrs_intr, SA_SHIRQ, "RightSwitch", dev);
+
+ rc = request_irq(dev->irq, &dgrs_intr, IRQF_SHARED, "RightSwitch", dev);
if (rc)
goto err_out;
@@ -1228,7 +1228,7 @@ err_out:
return rc;
}
-static int __init
+static int __init
dgrs_initclone(struct net_device *dev)
{
DGRS_PRIV *priv = (DGRS_PRIV *) dev->priv;
@@ -1243,7 +1243,7 @@ dgrs_initclone(struct net_device *dev)
return (0);
}
-static struct net_device * __init
+static struct net_device * __init
dgrs_found_device(
int io,
ulong mem,
@@ -1276,9 +1276,9 @@ dgrs_found_device(
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, pdev);
-
+
ret = dgrs_probe1(dev);
- if (ret)
+ if (ret)
goto err1;
ret = register_netdev(dev);
@@ -1301,7 +1301,7 @@ dgrs_found_device(
/* Allocate new dev and priv structures */
devN = alloc_etherdev(sizeof(DGRS_PRIV));
ret = -ENOMEM;
- if (!devN)
+ if (!devN)
goto fail;
/* Don't copy the network device structure! */
@@ -1335,7 +1335,7 @@ dgrs_found_device(
}
return dev;
- fail:
+ fail:
while (i >= 0) {
struct net_device *d = priv->devtbl[i--];
unregister_netdev(d);
@@ -1480,7 +1480,7 @@ static int __init dgrs_eisa_probe (struct device *gendev)
return -EBUSY;
}
- if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
+ if ( ! (inb(io+ES4H_EC) & ES4H_EC_ENABLE) )
goto err_out;
mem = (inb(io+ES4H_AS_31_24) << 24)
@@ -1504,11 +1504,11 @@ static int __init dgrs_eisa_probe (struct device *gendev)
static int __devexit dgrs_eisa_remove(struct device *gendev)
{
struct net_device *dev = gendev->driver_data;
-
+
dgrs_remove(dev);
release_region(dev->base_addr, 256);
-
+
free_netdev(dev);
return 0;
}
diff --git a/drivers/net/dgrs.h b/drivers/net/dgrs.h
index c347cd11740..6058d5301cb 100644
--- a/drivers/net/dgrs.h
+++ b/drivers/net/dgrs.h
@@ -31,8 +31,8 @@ typedef struct dgrs_ioctl {
unsigned short filter; /* filter number for command, if needed */
} DGRS_IOCTL;
-/*
- * Commands for the driver
+/*
+ * Commands for the driver
*/
#define DGRS_GETMEM 0x01 /* Get the dual port memory address */
#define DGRS_SETFILTER 0x02 /* Set a filter */
diff --git a/drivers/net/dgrs_asstruct.h b/drivers/net/dgrs_asstruct.h
index a8e5bb5ef53..f0e2121770f 100644
--- a/drivers/net/dgrs_asstruct.h
+++ b/drivers/net/dgrs_asstruct.h
@@ -19,7 +19,7 @@
# define S1(t,x) _Off=(_Off+0)&~0; x=_Off; _Off=_Off+1
# define S2(t,x) _Off=(_Off+1)&~1; x=_Off; _Off=_Off+2
# define S4(t,x) _Off=(_Off+3)&~3; x=_Off; _Off=_Off+4
-# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
+# define END_STRUCT(x) _Off=(_Off+3)&~3; x=_Off
#else /* C */
diff --git a/drivers/net/dgrs_bcomm.h b/drivers/net/dgrs_bcomm.h
index 6646608811c..5e9c2527398 100644
--- a/drivers/net/dgrs_bcomm.h
+++ b/drivers/net/dgrs_bcomm.h
@@ -27,7 +27,7 @@
* bc_nowait
* bc_hostarea_len
* bc_filter_len
- *
+ *
*/
BEGIN_STRUCT(bios_comm)
S4(ulong, bc_intflag) /* Count of all interrupts */
diff --git a/drivers/net/dgrs_ether.h b/drivers/net/dgrs_ether.h
index 51596ce6cf8..7539b596bff 100644
--- a/drivers/net/dgrs_ether.h
+++ b/drivers/net/dgrs_ether.h
@@ -49,7 +49,7 @@ typedef struct
int buf_cnt; /* Total RBD's allocated */
/* Rx Statistics */
- ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
+ ulong cnt_rx_cnt; /* Total packets rcvd, good and bad */
ulong cnt_rx_good; /* Total good packets rcvd */
ulong cnt_rx_bad; /* Total of all bad packets rcvd */
/* Subtotals can be gotten from SCB */
@@ -94,7 +94,7 @@ typedef struct
* Filter 0: input filter
* Filter 1: output filter
*/
-
+
ulong *filter_space[NFILTERS];
FILTER_FUNC *filter_func[NFILTERS];
ulong filter_cnt[NFILTERS];
diff --git a/drivers/net/dgrs_i82596.h b/drivers/net/dgrs_i82596.h
index c7a38c16a00..ac9217ad213 100644
--- a/drivers/net/dgrs_i82596.h
+++ b/drivers/net/dgrs_i82596.h
@@ -455,7 +455,7 @@ typedef volatile struct
/************************************************************************/
typedef volatile struct
{
- ulong sysbus;
+ ulong sysbus;
ulong dummy;
I596_ISCP *iscpp;
} I596_SCP;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 038447fb5c5..7e95cf1a487 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -9,54 +9,15 @@
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
-/*
- Rev Date Description
- ==========================================================================
- 0.01 2001/05/03 Created DL2000-based linux driver
- 0.02 2001/05/21 Added VLAN and hardware checksum support.
- 1.00 2001/06/26 Added jumbo frame support.
- 1.01 2001/08/21 Added two parameters, rx_coalesce and rx_timeout.
- 1.02 2001/10/08 Supported fiber media.
- Added flow control parameters.
- 1.03 2001/10/12 Changed the default media to 1000mbps_fd for
- the fiber devices.
- 1.04 2001/11/08 Fixed Tx stopped when tx very busy.
- 1.05 2001/11/22 Fixed Tx stopped when unidirectional tx busy.
- 1.06 2001/12/13 Fixed disconnect bug at 10Mbps mode.
- Fixed tx_full flag incorrect.
- Added tx_coalesce paramter.
- 1.07 2002/01/03 Fixed miscount of RX frame error.
- 1.08 2002/01/17 Fixed the multicast bug.
- 1.09 2002/03/07 Move rx-poll-now to re-fill loop.
- Added rio_timer() to watch rx buffers.
- 1.10 2002/04/16 Fixed miscount of carrier error.
- 1.11 2002/05/23 Added ISR schedule scheme
- Fixed miscount of rx frame error for DGE-550SX.
- Fixed VLAN bug.
- 1.12 2002/06/13 Lock tx_coalesce=1 on 10/100Mbps mode.
- 1.13 2002/08/13 1. Fix disconnection (many tx:carrier/rx:frame
- errs) with some mainboards.
- 2. Use definition "DRV_NAME" "DRV_VERSION"
- "DRV_RELDATE" for flexibility.
- 1.14 2002/08/14 Support ethtool.
- 1.15 2002/08/27 Changed the default media to Auto-Negotiation
- for the fiber devices.
- 1.16 2002/09/04 More power down time for fiber devices auto-
- negotiation.
- Fix disconnect bug after ifup and ifdown.
- 1.17 2002/10/03 Fix RMON statistics overflow.
- Always use I/O mapping to access eeprom,
- avoid system freezing with some chipsets.
-*/
#define DRV_NAME "D-Link DL2000-based linux driver"
-#define DRV_VERSION "v1.17b"
-#define DRV_RELDATE "2006/03/10"
+#define DRV_VERSION "v1.18"
+#define DRV_RELDATE "2006/06/27"
#include "dl2k.h"
#include <linux/dma-mapping.h>
static char version[] __devinitdata =
- KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
+ KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";
#define MAX_UNITS 8
static int mtu[MAX_UNITS];
static int vlan[MAX_UNITS];
@@ -122,7 +83,7 @@ static int mii_read (struct net_device *dev, int phy_addr, int reg_num);
static int mii_write (struct net_device *dev, int phy_addr, int reg_num,
u16 data);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
static int __devinit
rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -183,9 +144,9 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
if (media[card_idx] != NULL) {
np->an_enable = 0;
if (strcmp (media[card_idx], "auto") == 0 ||
- strcmp (media[card_idx], "autosense") == 0 ||
+ strcmp (media[card_idx], "autosense") == 0 ||
strcmp (media[card_idx], "0") == 0 ) {
- np->an_enable = 2;
+ np->an_enable = 2;
} else if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
strcmp (media[card_idx], "4") == 0) {
np->speed = 100;
@@ -271,7 +232,7 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
err = find_miiphy (dev);
if (err)
goto err_out_unmap_rx;
-
+
/* Fiber device? */
np->phy_media = (readw(ioaddr + ASICCtrl) & PhyMedia) ? 1 : 0;
np->link_status = 0;
@@ -302,11 +263,11 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5], irq);
if (tx_coalesce > 1)
- printk(KERN_INFO "tx_coalesce:\t%d packets\n",
+ printk(KERN_INFO "tx_coalesce:\t%d packets\n",
tx_coalesce);
if (np->coalesce)
printk(KERN_INFO "rx_coalesce:\t%d packets\n"
- KERN_INFO "rx_timeout: \t%d ns\n",
+ KERN_INFO "rx_timeout: \t%d ns\n",
np->rx_coalesce, np->rx_timeout*640);
if (np->vlan)
printk(KERN_INFO "vlan(id):\t%d\n", np->vlan);
@@ -378,7 +339,7 @@ parse_eeprom (struct net_device *dev)
}
#ifdef MEM_MAPPING
ioaddr = dev->base_addr;
-#endif
+#endif
/* Check CRC */
crc = ~ether_crc_le (256 - 4, sromdata);
if (psrom->crc != crc) {
@@ -390,7 +351,7 @@ parse_eeprom (struct net_device *dev)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = psrom->mac_addr[i];
- /* Parse Software Infomation Block */
+ /* Parse Software Information Block */
i = 0x30;
psib = (u8 *) sromdata;
do {
@@ -439,16 +400,16 @@ rio_open (struct net_device *dev)
long ioaddr = dev->base_addr;
int i;
u16 macctrl;
-
- i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
+
+ i = request_irq (dev->irq, &rio_interrupt, IRQF_SHARED, dev->name, dev);
if (i)
return i;
-
+
/* Reset all logic functions */
writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
ioaddr + ASICCtrl + 2);
mdelay(10);
-
+
/* DebugCtrl bit 4, 5, 9 must set */
writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
@@ -479,7 +440,7 @@ rio_open (struct net_device *dev)
/* VLAN supported */
if (np->vlan) {
/* priority field in RxDMAIntCtrl */
- writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
+ writel (readl(ioaddr + RxDMAIntCtrl) | 0x7 << 10,
ioaddr + RxDMAIntCtrl);
/* VLANId */
writew (np->vlan, ioaddr + VLANId);
@@ -498,9 +459,9 @@ rio_open (struct net_device *dev)
add_timer (&np->timer);
/* Start Tx/Rx */
- writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
+ writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable,
ioaddr + MACCtrl);
-
+
macctrl = 0;
macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
macctrl |= (np->full_duplex) ? DuplexSelect : 0;
@@ -509,13 +470,13 @@ rio_open (struct net_device *dev)
writew(macctrl, ioaddr + MACCtrl);
netif_start_queue (dev);
-
+
/* Enable default interrupts */
EnableInt ();
return 0;
}
-static void
+static void
rio_timer (unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
@@ -560,7 +521,7 @@ rio_timer (unsigned long data)
np->timer.expires = jiffies + next_tick;
add_timer(&np->timer);
}
-
+
static void
rio_tx_timeout (struct net_device *dev)
{
@@ -650,7 +611,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
txdesc = &np->tx_ring[entry];
#if 0
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
txdesc->status |=
cpu_to_le64 (TCPChecksumEnable | UDPChecksumEnable |
IPChecksumEnable);
@@ -671,12 +632,12 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
* Work around: Always use 1 descriptor in 10Mbps mode */
if (entry % np->tx_coalesce == 0 || np->speed == 10)
txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
- WordAlignDisable |
+ WordAlignDisable |
TxDMAIndicate |
(1 << FragCountShift));
else
txdesc->status = cpu_to_le64 (entry | tfc_vlan_tag |
- WordAlignDisable |
+ WordAlignDisable |
(1 << FragCountShift));
/* TxDMAPollNow */
@@ -697,7 +658,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
dev->base_addr + TFDListPtr0);
writel (0, dev->base_addr + TFDListPtr1);
}
-
+
/* NETDEV WATCHDOG timer */
dev->trans_start = jiffies;
return 0;
@@ -716,7 +677,7 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
ioaddr = dev->base_addr;
np = netdev_priv(dev);
while (1) {
- int_status = readw (ioaddr + IntStatus);
+ int_status = readw (ioaddr + IntStatus);
writew (int_status, ioaddr + IntStatus);
int_status &= DEFAULT_INTR;
if (int_status == 0 || --cnt < 0)
@@ -732,7 +693,7 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
if (tx_status & 0x01)
tx_error (dev, tx_status);
/* Free used tx skbuffs */
- rio_free_tx (dev, 1);
+ rio_free_tx (dev, 1);
}
/* Handle uncommon events */
@@ -745,19 +706,19 @@ rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
return IRQ_RETVAL(handled);
}
-static void
-rio_free_tx (struct net_device *dev, int irq)
+static void
+rio_free_tx (struct net_device *dev, int irq)
{
struct netdev_private *np = netdev_priv(dev);
int entry = np->old_tx % TX_RING_SIZE;
int tx_use = 0;
unsigned long flag = 0;
-
+
if (irq)
spin_lock(&np->tx_lock);
else
spin_lock_irqsave(&np->tx_lock, flag);
-
+
/* Free used tx skbuffs */
while (entry != np->cur_tx) {
struct sk_buff *skb;
@@ -783,11 +744,11 @@ rio_free_tx (struct net_device *dev, int irq)
spin_unlock_irqrestore(&np->tx_lock, flag);
np->old_tx = entry;
- /* If the ring is no longer full, clear tx_full and
+ /* If the ring is no longer full, clear tx_full and
call netif_wake_queue() */
if (netif_queue_stopped(dev) &&
- ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
+ ((np->cur_tx - np->old_tx + TX_RING_SIZE) % TX_RING_SIZE
< TX_QUEUE_LEN - 1 || np->speed == 10)) {
netif_wake_queue (dev);
}
@@ -844,11 +805,11 @@ tx_error (struct net_device *dev, int tx_status)
/* Let TxStartThresh stay default value */
}
/* Maximum Collisions */
-#ifdef ETHER_STATS
- if (tx_status & 0x08)
+#ifdef ETHER_STATS
+ if (tx_status & 0x08)
np->stats.collisions16++;
#else
- if (tx_status & 0x08)
+ if (tx_status & 0x08)
np->stats.collisions++;
#endif
/* Restart the Tx */
@@ -901,7 +862,7 @@ receive_packet (struct net_device *dev)
np->rx_skbuff[entry] = NULL;
} else if ((skb = dev_alloc_skb (pkt_len + 2)) != NULL) {
pci_dma_sync_single_for_cpu(np->pdev,
- desc->fraginfo &
+ desc->fraginfo &
DMA_48BIT_MASK,
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
@@ -919,12 +880,12 @@ receive_packet (struct net_device *dev)
PCI_DMA_FROMDEVICE);
}
skb->protocol = eth_type_trans (skb, dev);
-#if 0
+#if 0
/* Checksum done by hw, but csum value unavailable. */
- if (np->pci_rev_id >= 0x0c &&
+ if (np->pci_rev_id >= 0x0c &&
!(frame_status & (TCPError | UDPError | IPError))) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
- }
+ }
#endif
netif_rx (skb);
dev->last_rx = jiffies;
@@ -984,14 +945,14 @@ rio_error (struct net_device *dev, int int_status)
mii_get_media (dev);
if (np->speed == 1000)
np->tx_coalesce = tx_coalesce;
- else
+ else
np->tx_coalesce = 1;
macctrl = 0;
macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
macctrl |= (np->full_duplex) ? DuplexSelect : 0;
- macctrl |= (np->tx_flow) ?
+ macctrl |= (np->tx_flow) ?
TxFlowControlEnable : 0;
- macctrl |= (np->rx_flow) ?
+ macctrl |= (np->rx_flow) ?
RxFlowControlEnable : 0;
writew(macctrl, ioaddr + MACCtrl);
np->link_status = 1;
@@ -1008,7 +969,7 @@ rio_error (struct net_device *dev, int int_status)
get_stats (dev);
}
- /* PCI Error, a catastronphic error related to the bus interface
+ /* PCI Error, a catastronphic error related to the bus interface
occurs, set GlobalReset and HostReset to reset. */
if (int_status & HostError) {
printk (KERN_ERR "%s: HostError! IntStatus %4.4x.\n",
@@ -1030,16 +991,16 @@ get_stats (struct net_device *dev)
/* All statistics registers need to be acknowledged,
else statistic overflow could cause problems */
-
+
np->stats.rx_packets += readl (ioaddr + FramesRcvOk);
np->stats.tx_packets += readl (ioaddr + FramesXmtOk);
np->stats.rx_bytes += readl (ioaddr + OctetRcvOk);
np->stats.tx_bytes += readl (ioaddr + OctetXmtOk);
np->stats.multicast = readl (ioaddr + McstFramesRcvdOk);
- np->stats.collisions += readl (ioaddr + SingleColFrames)
- + readl (ioaddr + MultiColFrames);
-
+ np->stats.collisions += readl (ioaddr + SingleColFrames)
+ + readl (ioaddr + MultiColFrames);
+
/* detailed tx errors */
stat_reg = readw (ioaddr + FramesAbortXSColls);
np->stats.tx_aborted_errors += stat_reg;
@@ -1086,7 +1047,7 @@ clear_stats (struct net_device *dev)
long ioaddr = dev->base_addr;
#ifdef MEM_MAPPING
int i;
-#endif
+#endif
/* All statistics registers need to be acknowledged,
else statistic overflow could cause problems */
@@ -1099,7 +1060,7 @@ clear_stats (struct net_device *dev)
readl (ioaddr + SingleColFrames);
readl (ioaddr + MultiColFrames);
readl (ioaddr + LateCollisions);
- /* detailed rx errors */
+ /* detailed rx errors */
readw (ioaddr + FrameTooLongErrors);
readw (ioaddr + InRangeLengthErrors);
readw (ioaddr + FramesCheckSeqErrors);
@@ -1125,7 +1086,7 @@ clear_stats (struct net_device *dev)
#ifdef MEM_MAPPING
for (i = 0x100; i <= 0x150; i += 4)
readl (ioaddr + i);
-#endif
+#endif
readw (ioaddr + TxJumboFrames);
readw (ioaddr + RxJumboFrames);
readw (ioaddr + TCPCheckSumErrors);
@@ -1157,26 +1118,26 @@ set_multicast (struct net_device *dev)
u32 hash_table[2];
u16 rx_mode = 0;
struct netdev_private *np = netdev_priv(dev);
-
+
hash_table[0] = hash_table[1] = 0;
/* RxFlowcontrol DA: 01-80-C2-00-00-01. Hash index=0x39 */
hash_table[1] |= cpu_to_le32(0x02000000);
if (dev->flags & IFF_PROMISC) {
/* Receive all frames promiscuously. */
rx_mode = ReceiveAllFrames;
- } else if ((dev->flags & IFF_ALLMULTI) ||
+ } else if ((dev->flags & IFF_ALLMULTI) ||
(dev->mc_count > multicast_filter_limit)) {
/* Receive broadcast and multicast frames */
rx_mode = ReceiveBroadcast | ReceiveMulticast | ReceiveUnicast;
} else if (dev->mc_count > 0) {
int i;
struct dev_mc_list *mclist;
- /* Receive broadcast frames and multicast frames filtering
+ /* Receive broadcast frames and multicast frames filtering
by Hashtable */
rx_mode =
ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
- for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
- i++, mclist=mclist->next)
+ for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist=mclist->next)
{
int bit, index = 0;
int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
@@ -1206,7 +1167,7 @@ static void rio_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
strcpy(info->driver, "dl2k");
strcpy(info->version, DRV_VERSION);
strcpy(info->bus_info, pci_name(np->pdev));
-}
+}
static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
@@ -1216,10 +1177,10 @@ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported = SUPPORTED_Autoneg | SUPPORTED_FIBRE;
cmd->advertising= ADVERTISED_Autoneg | ADVERTISED_FIBRE;
cmd->port = PORT_FIBRE;
- cmd->transceiver = XCVR_INTERNAL;
+ cmd->transceiver = XCVR_INTERNAL;
} else {
/* copper device */
- cmd->supported = SUPPORTED_10baseT_Half |
+ cmd->supported = SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg | SUPPORTED_MII;
@@ -1230,7 +1191,7 @@ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->port = PORT_MII;
cmd->transceiver = XCVR_INTERNAL;
}
- if ( np->link_status ) {
+ if ( np->link_status ) {
cmd->speed = np->speed;
cmd->duplex = np->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
} else {
@@ -1241,9 +1202,9 @@ static int rio_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->autoneg = AUTONEG_ENABLE;
else
cmd->autoneg = AUTONEG_DISABLE;
-
+
cmd->phy_address = np->phy_addr;
- return 0;
+ return 0;
}
static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
@@ -1256,22 +1217,22 @@ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
else {
np->an_enable = 1;
mii_set_media(dev);
- return 0;
- }
+ return 0;
+ }
} else {
np->an_enable = 0;
if (np->speed == 1000) {
- cmd->speed = SPEED_100;
+ cmd->speed = SPEED_100;
cmd->duplex = DUPLEX_FULL;
printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manual 100Mbps, Full duplex.\n");
}
switch(cmd->speed + cmd->duplex) {
-
+
case SPEED_10 + DUPLEX_HALF:
np->speed = 10;
np->full_duplex = 0;
break;
-
+
case SPEED_10 + DUPLEX_FULL:
np->speed = 10;
np->full_duplex = 1;
@@ -1287,7 +1248,7 @@ static int rio_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
case SPEED_1000 + DUPLEX_HALF:/* not supported */
case SPEED_1000 + DUPLEX_FULL:/* not supported */
default:
- return -EINVAL;
+ return -EINVAL;
}
mii_set_media(dev);
}
@@ -1300,7 +1261,7 @@ static u32 rio_get_link(struct net_device *dev)
return np->link_status;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = rio_get_drvinfo,
.get_settings = rio_get_settings,
.set_settings = rio_set_settings,
@@ -1313,7 +1274,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
int phy_addr;
struct netdev_private *np = netdev_priv(dev);
struct mii_data *miidata = (struct mii_data *) &rq->ifr_ifru;
-
+
struct netdev_desc *desc;
int i;
@@ -1321,7 +1282,7 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
switch (cmd) {
case SIOCDEVPRIVATE:
break;
-
+
case SIOCDEVPRIVATE + 1:
miidata->out_value = mii_read (dev, phy_addr, miidata->reg_num);
break;
@@ -1506,7 +1467,7 @@ mii_get_media (struct net_device *dev)
/* Auto-Negotiation not completed */
return -1;
}
- negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
+ negotiate.image = mii_read (dev, phy_addr, MII_ANAR) &
mii_read (dev, phy_addr, MII_ANLPAR);
mscr.image = mii_read (dev, phy_addr, MII_MSCR);
mssr.image = mii_read (dev, phy_addr, MII_MSSR);
@@ -1558,9 +1519,9 @@ mii_get_media (struct net_device *dev)
printk ("Half duplex\n");
}
}
- if (np->tx_flow)
+ if (np->tx_flow)
printk(KERN_INFO "Enable Tx Flow Control\n");
- else
+ else
printk(KERN_INFO "Disable Tx Flow Control\n");
if (np->rx_flow)
printk(KERN_INFO "Enable Rx Flow Control\n");
@@ -1600,7 +1561,7 @@ mii_set_media (struct net_device *dev)
pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR);
pscr.bits.mdi_crossover_mode = 3; /* 11'b */
mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image);
-
+
/* Soft reset PHY */
mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET);
bmcr.image = 0;
@@ -1678,7 +1639,7 @@ mii_get_media_pcs (struct net_device *dev)
/* Auto-Negotiation not completed */
return -1;
}
- negotiate.image = mii_read (dev, phy_addr, PCS_ANAR) &
+ negotiate.image = mii_read (dev, phy_addr, PCS_ANAR) &
mii_read (dev, phy_addr, PCS_ANLPAR);
np->speed = 1000;
if (negotiate.bits.full_duplex) {
@@ -1705,9 +1666,9 @@ mii_get_media_pcs (struct net_device *dev)
printk ("Half duplex\n");
}
}
- if (np->tx_flow)
+ if (np->tx_flow)
printk(KERN_INFO "Enable Tx Flow Control\n");
- else
+ else
printk(KERN_INFO "Disable Tx Flow Control\n");
if (np->rx_flow)
printk(KERN_INFO "Enable Rx Flow Control\n");
@@ -1733,9 +1694,9 @@ mii_set_media_pcs (struct net_device *dev)
/* Advertise capabilities */
esr.image = mii_read (dev, phy_addr, PCS_ESR);
anar.image = mii_read (dev, phy_addr, MII_ANAR);
- anar.bits.half_duplex =
+ anar.bits.half_duplex =
esr.bits.media_1000BT_HD | esr.bits.media_1000BX_HD;
- anar.bits.full_duplex =
+ anar.bits.full_duplex =
esr.bits.media_1000BT_FD | esr.bits.media_1000BX_FD;
anar.bits.pause = 1;
anar.bits.asymmetric = 1;
@@ -1793,14 +1754,14 @@ rio_close (struct net_device *dev)
synchronize_irq (dev->irq);
free_irq (dev->irq, dev);
del_timer_sync (&np->timer);
-
+
/* Free all the skbuffs in the queue. */
for (i = 0; i < RX_RING_SIZE; i++) {
np->rx_ring[i].status = 0;
np->rx_ring[i].fraginfo = 0;
skb = np->rx_skbuff[i];
if (skb) {
- pci_unmap_single(np->pdev,
+ pci_unmap_single(np->pdev,
np->rx_ring[i].fraginfo & DMA_48BIT_MASK,
skb->len, PCI_DMA_FROMDEVICE);
dev_kfree_skb (skb);
@@ -1810,7 +1771,7 @@ rio_close (struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
skb = np->tx_skbuff[i];
if (skb) {
- pci_unmap_single(np->pdev,
+ pci_unmap_single(np->pdev,
np->tx_ring[i].fraginfo & DMA_48BIT_MASK,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb (skb);
@@ -1854,7 +1815,7 @@ static struct pci_driver rio_driver = {
static int __init
rio_init (void)
{
- return pci_module_init (&rio_driver);
+ return pci_register_driver(&rio_driver);
}
static void __exit
@@ -1867,9 +1828,9 @@ module_init (rio_init);
module_exit (rio_exit);
/*
-
-Compile command:
-
+
+Compile command:
+
gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -c dl2k.c
Read Documentation/networking/dl2k.txt for details.
diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h
index 6e75482d75f..814c449c359 100644
--- a/drivers/net/dl2k.h
+++ b/drivers/net/dl2k.h
@@ -1,5 +1,5 @@
/* D-Link DL2000-based Gigabit Ethernet Adapter Linux driver */
-/*
+/*
Copyright (c) 2001, 2002 by D-Link Corporation
Written by Edward Peng.<edward_peng@dlink.com.tw>
Created 03-May-2001, base on Linux' sundance.c.
@@ -216,7 +216,7 @@ enum MACCtrl_bits {
enum ASICCtrl_LoWord_bits {
PhyMedia = 0x0080,
};
-
+
enum ASICCtrl_HiWord_bits {
GlobalReset = 0x0001,
RxReset = 0x0002,
@@ -596,7 +596,7 @@ typedef union t_PCS_ANLPAR {
} ANLPAR_PCS_t, *PANLPAR_PCS_t;
enum _pcs_anlpar {
- PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
+ PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE,
PCS_ANLPAR_REMOTE_FAULT = PCS_ANAR_REMOTE_FAULT,
PCS_ANLPAR_ASYMMETRIC = PCS_ANAR_ASYMMETRIC,
PCS_ANLPAR_PAUSE = PCS_ANAR_PAUSE,
@@ -683,11 +683,6 @@ struct netdev_private {
};
/* The station address location in the EEPROM. */
-#ifdef MEM_MAPPING
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-#endif
/* The struct pci_device_id consist of:
vendor, device Vendor and device ID to match (or PCI_ANY_ID)
subvendor, subdevice Subsystem vendor and device ID to match (or PCI_ANY_ID)
@@ -695,9 +690,10 @@ struct netdev_private {
class_mask of the class are honored during the comparison.
driver_data Data private to the driver.
*/
-static struct pci_device_id rio_pci_tbl[] = {
- {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0,}
+
+static const struct pci_device_id rio_pci_tbl[] = {
+ {0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
+ { }
};
MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
#define TX_TIMEOUT (4*HZ)
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index 24996da4c1c..a860ebbbf81 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -339,6 +339,17 @@ static void dm9000_timeout(struct net_device *dev)
spin_unlock_irqrestore(&db->lock,flags);
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/*
+ *Used by netconsole
+ */
+static void dm9000_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ dm9000_interrupt(dev->irq,dev,NULL);
+ enable_irq(dev->irq);
+}
+#endif
/* dm9000_release_board
*
@@ -366,8 +377,8 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db)
kfree(db->data_req);
}
- if (db->addr_res != NULL) {
- release_resource(db->addr_res);
+ if (db->addr_req != NULL) {
+ release_resource(db->addr_req);
kfree(db->addr_req);
}
}
@@ -410,10 +421,7 @@ dm9000_probe(struct platform_device *pdev)
if (pdev->num_resources < 2) {
ret = -ENODEV;
goto out;
- }
-
- switch (pdev->num_resources) {
- case 2:
+ } else if (pdev->num_resources == 2) {
base = pdev->resource[0].start;
if (!request_mem_region(base, 4, ndev->name)) {
@@ -423,17 +431,16 @@ dm9000_probe(struct platform_device *pdev)
ndev->base_addr = base;
ndev->irq = pdev->resource[1].start;
- db->io_addr = (void *)base;
- db->io_data = (void *)(base + 4);
-
- break;
+ db->io_addr = (void __iomem *)base;
+ db->io_data = (void __iomem *)(base + 4);
- case 3:
+ } else {
db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (db->addr_res == NULL || db->data_res == NULL) {
+ if (db->addr_res == NULL || db->data_res == NULL ||
+ db->irq_res == NULL) {
printk(KERN_ERR PFX "insufficient resources\n");
ret = -ENOENT;
goto out;
@@ -482,7 +489,6 @@ dm9000_probe(struct platform_device *pdev)
/* ensure at least we have a default set of IO routines */
dm9000_set_io(db, iosize);
-
}
/* check to see if anything is being over-ridden */
@@ -543,6 +549,9 @@ dm9000_probe(struct platform_device *pdev)
ndev->stop = &dm9000_stop;
ndev->get_stats = &dm9000_get_stats;
ndev->set_multicast_list = &dm9000_hash_table;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ ndev->poll_controller = &dm9000_poll_controller;
+#endif
#ifdef DM9000_PROGRAM_EEPROM
program_eeprom(db);
@@ -564,6 +573,13 @@ dm9000_probe(struct platform_device *pdev)
for (i = 0; i < 6; i++)
ndev->dev_addr[i] = db->srom[i];
+ if (!is_valid_ether_addr(ndev->dev_addr)) {
+ /* try reading from mac */
+
+ for (i = 0; i < 6; i++)
+ ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
+ }
+
if (!is_valid_ether_addr(ndev->dev_addr))
printk("%s: Invalid ethernet MAC address. Please "
"set using ifconfig\n", ndev->name);
@@ -601,7 +617,7 @@ dm9000_open(struct net_device *dev)
PRINTK2("entering dm9000_open\n");
- if (request_irq(dev->irq, &dm9000_interrupt, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, &dm9000_interrupt, IRQF_SHARED, dev->name, dev))
return -EAGAIN;
/* Initialize DM9000 board */
@@ -663,7 +679,6 @@ dm9000_init_dm9000(struct net_device *dev)
db->tx_pkt_cnt = 0;
db->queue_pkt_len = 0;
dev->trans_start = 0;
- spin_lock_init(&db->lock);
}
/*
@@ -767,7 +782,7 @@ dm9000_stop(struct net_device *ndev)
* receive the packet to upper layer, free the transmitted packet
*/
-void
+static void
dm9000_tx_done(struct net_device *dev, board_info_t * db)
{
int tx_status = ior(db, DM9000_NSR); /* Got TX status */
@@ -1187,13 +1202,14 @@ dm9000_drv_remove(struct platform_device *pdev)
}
static struct platform_driver dm9000_driver = {
+ .driver = {
+ .name = "dm9000",
+ .owner = THIS_MODULE,
+ },
.probe = dm9000_probe,
.remove = dm9000_drv_remove,
.suspend = dm9000_drv_suspend,
.resume = dm9000_drv_resume,
- .driver = {
- .name = "dm9000",
- },
};
static int __init
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c
index dd8c15ac5c7..60673bc292c 100644
--- a/drivers/net/dummy.c
+++ b/drivers/net/dummy.c
@@ -11,7 +11,7 @@
One solution is to set up a dummy link using PPP/SLIP/PLIP,
but this seems (to me) too much overhead for too little gain.
This driver provides a small alternative. Thus you can do
-
+
[when not running slip]
ifconfig dummy slip.addr.ess.here up
[to go to slip]
@@ -28,7 +28,6 @@
Alan Cox, 30th May 1994
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
@@ -45,9 +44,9 @@ static int dummy_set_address(struct net_device *dev, void *p)
{
struct sockaddr *sa = p;
- if (!is_valid_ether_addr(sa->sa_data))
+ if (!is_valid_ether_addr(sa->sa_data))
return -EADDRNOTAVAIL;
-
+
memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
return 0;
}
@@ -112,7 +111,7 @@ static int __init dummy_init_one(int index)
free_netdev(dev_dummy);
dev_dummy = NULL;
} else {
- dummies[index] = dev_dummy;
+ dummies[index] = dev_dummy;
}
return err;
@@ -122,29 +121,30 @@ static void dummy_free_one(int index)
{
unregister_netdev(dummies[index]);
free_netdev(dummies[index]);
-}
+}
static int __init dummy_init_module(void)
-{
+{
int i, err = 0;
- dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL);
+ dummies = kmalloc(numdummies * sizeof(void *), GFP_KERNEL);
if (!dummies)
- return -ENOMEM;
+ return -ENOMEM;
for (i = 0; i < numdummies && !err; i++)
- err = dummy_init_one(i);
- if (err) {
+ err = dummy_init_one(i);
+ if (err) {
+ i--;
while (--i >= 0)
dummy_free_one(i);
}
return err;
-}
+}
static void __exit dummy_cleanup_module(void)
{
int i;
- for (i = 0; i < numdummies; i++)
- dummy_free_one(i);
- kfree(dummies);
+ for (i = 0; i < numdummies; i++)
+ dummy_free_one(i);
+ kfree(dummies);
}
module_init(dummy_init_module);
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index f37170cc1a3..dc5e38aefca 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1,7 +1,7 @@
/*******************************************************************************
- Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
@@ -138,7 +138,6 @@
* - Stratus87247: protect MDI control register manipulations
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -159,10 +158,10 @@
#define DRV_NAME "e100"
-#define DRV_EXT "-NAPI"
-#define DRV_VERSION "3.5.10-k2"DRV_EXT
+#define DRV_EXT "-NAPI"
+#define DRV_VERSION "3.5.16-k2"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
-#define DRV_COPYRIGHT "Copyright(c) 1999-2005 Intel Corporation"
+#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
#define PFX DRV_NAME ": "
#define E100_WATCHDOG_PERIOD (2 * HZ)
@@ -174,8 +173,11 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
static int debug = 3;
+static int eeprom_bad_csum_allow = 0;
module_param(debug, int, 0);
+module_param(eeprom_bad_csum_allow, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums");
#define DPRINTK(nlevel, klevel, fmt, args...) \
(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
@@ -757,7 +759,8 @@ static int e100_eeprom_load(struct nic *nic)
checksum = le16_to_cpu(0xBABA - checksum);
if(checksum != nic->eeprom[nic->eeprom_wc - 1]) {
DPRINTK(PROBE, ERR, "EEPROM corrupted\n");
- return -EAGAIN;
+ if (!eeprom_bad_csum_allow)
+ return -EAGAIN;
}
return 0;
@@ -1392,15 +1395,11 @@ static int e100_phy_init(struct nic *nic)
}
if((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
- (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
- /* enable/disable MDI/MDI-X auto-switching.
- MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
- if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
- (nic->mac == mac_82551_10) || (nic->mii.force_media) ||
- !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))
- mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
- else
- mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+ (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
+ !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
+ /* enable/disable MDI/MDI-X auto-switching. */
+ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG,
+ nic->mii.force_media ? 0 : NCONFIG_AUTO_SWITCH);
}
return 0;
@@ -1764,11 +1763,10 @@ static inline void e100_start_receiver(struct nic *nic, struct rx *rx)
#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)
static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx)
{
- if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))
+ if(!(rx->skb = netdev_alloc_skb(nic->netdev, RFD_BUF_LEN + NET_IP_ALIGN)))
return -ENOMEM;
/* Align, init, and map the RFD. */
- rx->skb->dev = nic->netdev;
skb_reserve(rx->skb, NET_IP_ALIGN);
memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));
rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,
@@ -2064,7 +2062,7 @@ static int e100_up(struct nic *nic)
e100_set_multicast_list(nic->netdev);
e100_start_receiver(nic, NULL);
mod_timer(&nic->watchdog, jiffies);
- if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
+ if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED,
nic->netdev->name, nic->netdev)))
goto err_no_irq;
netif_wake_queue(nic->netdev);
@@ -2144,7 +2142,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode)
e100_start_receiver(nic, NULL);
- if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {
+ if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) {
err = -ENOMEM;
goto err_loopback_none;
}
@@ -2479,7 +2477,7 @@ static void e100_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
}
}
-static struct ethtool_ops e100_ethtool_ops = {
+static const struct ethtool_ops e100_ethtool_ops = {
.get_settings = e100_get_settings,
.set_settings = e100_set_settings,
.get_drvinfo = e100_get_drvinfo,
@@ -2678,9 +2676,9 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_free;
}
- DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, "
+ DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, "
"MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n",
- pci_resource_start(pdev, 0), pdev->irq,
+ (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2],
netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]);
@@ -2796,6 +2794,7 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel
/* Detach; put netif into state similar to hotplug unplug. */
netif_poll_enable(netdev);
netif_device_detach(netdev);
+ pci_disable_device(pdev);
/* Request a slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
@@ -2874,7 +2873,7 @@ static int __init e100_init_module(void)
printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
}
- return pci_module_init(&e100_driver);
+ return pci_register_driver(&e100_driver);
}
static void __exit e100_cleanup_module(void)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 2bc34fbfa69..98afa9c2057 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -34,7 +34,6 @@
#define _E1000_H_
#include <linux/stddef.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -69,7 +68,6 @@
#ifdef NETIF_F_TSO
#include <net/checksum.h>
#endif
-#include <linux/workqueue.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
@@ -112,6 +110,9 @@ struct e1000_adapter;
#define E1000_MIN_RXD 80
#define E1000_MAX_82544_RXD 4096
+/* this is the size past which hardware will drop packets when setting LPE=0 */
+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
+
/* Supported Rx Buffer Sizes */
#define E1000_RXBUFFER_128 128 /* Used for packet split */
#define E1000_RXBUFFER_256 256 /* Used for packet split */
@@ -144,6 +145,7 @@ struct e1000_adapter;
#define AUTO_ALL_MODES 0
#define E1000_EEPROM_82544_APM 0x0004
+#define E1000_EEPROM_ICH8_APME 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
@@ -240,12 +242,10 @@ struct e1000_adapter {
struct timer_list watchdog_timer;
struct timer_list phy_info_timer;
struct vlan_group *vlgrp;
- uint16_t mng_vlan_id;
+ uint16_t mng_vlan_id;
uint32_t bd_number;
uint32_t rx_buffer_len;
- uint32_t part_num;
uint32_t wol;
- uint32_t ksp3_port_a;
uint32_t smartspeed;
uint32_t en_mng_pt;
uint16_t link_speed;
@@ -255,7 +255,6 @@ struct e1000_adapter {
spinlock_t tx_queue_lock;
#endif
atomic_t irq_sem;
- struct work_struct watchdog_task;
struct work_struct reset_task;
uint8_t fc_autoneg;
@@ -340,8 +339,16 @@ struct e1000_adapter {
#ifdef NETIF_F_TSO
boolean_t tso_force;
#endif
+ boolean_t smart_power_down; /* phy smart power down */
+ boolean_t quad_port_a;
+ unsigned long flags;
+ uint32_t eeprom_wol;
};
+enum e1000_state_t {
+ __E1000_DRIVER_TESTING,
+ __E1000_RESETTING,
+};
/* e1000_main.c */
extern char e1000_driver_name[];
@@ -349,6 +356,7 @@ extern char e1000_driver_version[];
int e1000_up(struct e1000_adapter *adapter);
void e1000_down(struct e1000_adapter *adapter);
void e1000_reset(struct e1000_adapter *adapter);
+void e1000_reinit_locked(struct e1000_adapter *adapter);
int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 6ed7f599eba..e39aa1fc4d1 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -109,7 +109,8 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
SUPPORTED_1000baseT_Full|
SUPPORTED_Autoneg |
SUPPORTED_TP);
-
+ if (hw->phy_type == e1000_phy_ife)
+ ecmd->supported &= ~SUPPORTED_1000baseT_Full;
ecmd->advertising = ADVERTISED_TP;
if (hw->autoneg == 1) {
@@ -182,6 +183,9 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
return -EINVAL;
}
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+
if (ecmd->autoneg == AUTONEG_ENABLE) {
hw->autoneg = 1;
if (hw->media_type == e1000_media_type_fiber)
@@ -198,18 +202,20 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ADVERTISED_TP;
ecmd->advertising = hw->autoneg_advertised;
} else
- if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
+ if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
+ clear_bit(__E1000_RESETTING, &adapter->flags);
return -EINVAL;
+ }
/* reset the link */
if (netif_running(adapter->netdev)) {
e1000_down(adapter);
- e1000_reset(adapter);
e1000_up(adapter);
} else
e1000_reset(adapter);
+ clear_bit(__E1000_RESETTING, &adapter->flags);
return 0;
}
@@ -239,9 +245,13 @@ e1000_set_pauseparam(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ int retval = 0;
adapter->fc_autoneg = pause->autoneg;
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+
if (pause->rx_pause && pause->tx_pause)
hw->fc = e1000_fc_full;
else if (pause->rx_pause && !pause->tx_pause)
@@ -260,10 +270,11 @@ e1000_set_pauseparam(struct net_device *netdev,
} else
e1000_reset(adapter);
} else
- return ((hw->media_type == e1000_media_type_fiber) ?
- e1000_setup_link(hw) : e1000_force_mac_fc(hw));
+ retval = ((hw->media_type == e1000_media_type_fiber) ?
+ e1000_setup_link(hw) : e1000_force_mac_fc(hw));
- return 0;
+ clear_bit(__E1000_RESETTING, &adapter->flags);
+ return retval;
}
static uint32_t
@@ -279,10 +290,9 @@ e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->rx_csum = data;
- if (netif_running(netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
return 0;
}
@@ -418,12 +428,12 @@ e1000_get_regs(struct net_device *netdev,
regs_buff[23] = regs_buff[18]; /* mdix mode */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
} else {
- e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
regs_buff[13] = (uint32_t)phy_data; /* cable length */
regs_buff[14] = 0; /* Dummy (to align w/ IGP phy reg dump) */
regs_buff[15] = 0; /* Dummy (to align w/ IGP phy reg dump) */
regs_buff[16] = 0; /* Dummy (to align w/ IGP phy reg dump) */
- e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
regs_buff[17] = (uint32_t)phy_data; /* extended 10bt distance */
regs_buff[18] = regs_buff[13]; /* cable polarity */
regs_buff[19] = 0; /* Dummy (to align w/ IGP phy reg dump) */
@@ -577,6 +587,7 @@ e1000_get_drvinfo(struct net_device *netdev,
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
+ case e1000_ich8lan:
sprintf(firmware_version, "%d.%d-%d",
(eeprom_data & 0xF000) >> 12,
(eeprom_data & 0x0FF0) >> 4,
@@ -631,6 +642,9 @@ e1000_set_ringparam(struct net_device *netdev,
tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues;
rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues;
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+
if (netif_running(adapter->netdev))
e1000_down(adapter);
@@ -691,9 +705,10 @@ e1000_set_ringparam(struct net_device *netdev,
adapter->rx_ring = rx_new;
adapter->tx_ring = tx_new;
if ((err = e1000_up(adapter)))
- return err;
+ goto err_setup;
}
+ clear_bit(__E1000_RESETTING, &adapter->flags);
return 0;
err_setup_tx:
e1000_free_all_rx_resources(adapter);
@@ -701,6 +716,8 @@ err_setup_rx:
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
e1000_up(adapter);
+err_setup:
+ clear_bit(__E1000_RESETTING, &adapter->flags);
return err;
}
@@ -754,6 +771,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
toggle = 0x7FFFF3FF;
break;
case e1000_82573:
+ case e1000_ich8lan:
toggle = 0x7FFFF033;
break;
default:
@@ -773,11 +791,12 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
}
/* restore previous status */
E1000_WRITE_REG(&adapter->hw, STATUS, before);
-
- REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
- REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
- REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
- REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+ if (adapter->hw.mac_type != e1000_ich8lan) {
+ REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF);
+ REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF);
+ }
REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF);
@@ -790,20 +809,22 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF);
REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000);
- REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB);
+ before = (adapter->hw.mac_type == e1000_ich8lan ?
+ 0x06C3B33E : 0x06DFB3FE);
+ REG_SET_AND_CHECK(RCTL, before, 0x003FFFFB);
REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000);
if (adapter->hw.mac_type >= e1000_82543) {
- REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF);
+ REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
- REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
+ if (adapter->hw.mac_type != e1000_ich8lan)
+ REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
-
- for (i = 0; i < E1000_RAR_ENTRIES; i++) {
- REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF,
- 0xFFFFFFFF);
+ value = (adapter->hw.mac_type == e1000_ich8lan ?
+ E1000_RAR_ENTRIES_ICH8LAN : E1000_RAR_ENTRIES);
+ for (i = 0; i < value; i++) {
REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF,
0xFFFFFFFF);
}
@@ -817,7 +838,9 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
}
- for (i = 0; i < E1000_MC_TBL_SIZE; i++)
+ value = (adapter->hw.mac_type == e1000_ich8lan ?
+ E1000_MC_TBL_SIZE_ICH8LAN : E1000_MC_TBL_SIZE);
+ for (i = 0; i < value; i++)
REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF);
*data = 0;
@@ -870,25 +893,28 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
*data = 0;
+ /* NOTE: we don't test MSI interrupts here, yet */
/* Hook up test interrupt handler just for this test */
- if (!request_irq(irq, &e1000_test_intr, SA_PROBEIRQ, netdev->name,
- netdev)) {
- shared_int = FALSE;
- } else if (request_irq(irq, &e1000_test_intr, SA_SHIRQ,
- netdev->name, netdev)){
+ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED,
+ netdev->name, netdev))
+ shared_int = FALSE;
+ else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
+ netdev->name, netdev)) {
*data = 1;
return -1;
}
- DPRINTK(PROBE,INFO, "testing %s interrupt\n",
+ DPRINTK(HW, INFO, "testing %s interrupt\n",
(shared_int ? "shared" : "unshared"));
/* Disable all the interrupts */
E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
- msec_delay(10);
+ msleep(10);
/* Test each interrupt */
for (; i < 10; i++) {
+ if (adapter->hw.mac_type == e1000_ich8lan && i == 8)
+ continue;
/* Interrupt to test */
mask = 1 << i;
@@ -902,7 +928,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
adapter->test_icr = 0;
E1000_WRITE_REG(&adapter->hw, IMC, mask);
E1000_WRITE_REG(&adapter->hw, ICS, mask);
- msec_delay(10);
+ msleep(10);
if (adapter->test_icr & mask) {
*data = 3;
@@ -919,7 +945,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
adapter->test_icr = 0;
E1000_WRITE_REG(&adapter->hw, IMS, mask);
E1000_WRITE_REG(&adapter->hw, ICS, mask);
- msec_delay(10);
+ msleep(10);
if (!(adapter->test_icr & mask)) {
*data = 4;
@@ -936,7 +962,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
adapter->test_icr = 0;
E1000_WRITE_REG(&adapter->hw, IMC, ~mask & 0x00007FFF);
E1000_WRITE_REG(&adapter->hw, ICS, ~mask & 0x00007FFF);
- msec_delay(10);
+ msleep(10);
if (adapter->test_icr) {
*data = 5;
@@ -947,7 +973,7 @@ e1000_intr_test(struct e1000_adapter *adapter, uint64_t *data)
/* Disable all the interrupts */
E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF);
- msec_delay(10);
+ msleep(10);
/* Unhook test interrupt handler */
free_irq(irq, netdev);
@@ -1243,26 +1269,40 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter)
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140);
/* autoneg off */
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140);
- } else if (adapter->hw.phy_type == e1000_phy_gg82563) {
+ } else if (adapter->hw.phy_type == e1000_phy_gg82563)
e1000_write_phy_reg(&adapter->hw,
GG82563_PHY_KMRN_MODE_CTRL,
- 0x1CE);
- }
- /* force 1000, set loopback */
- e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
+ 0x1CC);
- /* Now set up the MAC to the same speed/duplex as the PHY. */
ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
- ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
- ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
- E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
- E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
- E1000_CTRL_FD); /* Force Duplex to FULL */
+
+ if (adapter->hw.phy_type == e1000_phy_ife) {
+ /* force 100, set loopback */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x6100);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_100 |/* Force Speed to 100 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ } else {
+ /* force 1000, set loopback */
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140);
+
+ /* Now set up the MAC to the same speed/duplex as the PHY. */
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD | /* Set the Force Speed Bit */
+ E1000_CTRL_FRCDPX | /* Set the Force Duplex Bit */
+ E1000_CTRL_SPD_1000 |/* Force Speed to 1000 */
+ E1000_CTRL_FD); /* Force Duplex to FULL */
+ }
if (adapter->hw.media_type == e1000_media_type_copper &&
- adapter->hw.phy_type == e1000_phy_m88) {
+ adapter->hw.phy_type == e1000_phy_m88)
ctrl_reg |= E1000_CTRL_ILOS; /* Invert Loss of Signal */
- } else {
+ else {
/* Set the ILOS bit on the fiber Nic is half
* duplex link is detected. */
stat_reg = E1000_READ_REG(&adapter->hw, STATUS);
@@ -1317,6 +1357,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
+ case e1000_ich8lan:
return e1000_integrated_phy_loopback(adapter);
break;
@@ -1354,7 +1395,7 @@ e1000_setup_loopback_test(struct e1000_adapter *adapter)
#define E1000_SERDES_LB_ON 0x410
e1000_set_phy_loopback(adapter);
E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_ON);
- msec_delay(10);
+ msleep(10);
return 0;
break;
default:
@@ -1387,7 +1428,7 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter)
hw->media_type == e1000_media_type_internal_serdes) {
#define E1000_SERDES_LB_OFF 0x400
E1000_WRITE_REG(hw, SCTL, E1000_SERDES_LB_OFF);
- msec_delay(10);
+ msleep(10);
break;
}
/* Fall Through */
@@ -1397,11 +1438,10 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter)
case e1000_82546_rev_3:
default:
hw->autoneg = TRUE;
- if (hw->phy_type == e1000_phy_gg82563) {
+ if (hw->phy_type == e1000_phy_gg82563)
e1000_write_phy_reg(hw,
GG82563_PHY_KMRN_MODE_CTRL,
0x180);
- }
e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg);
if (phy_reg & MII_CR_LOOPBACK) {
phy_reg &= ~MII_CR_LOOPBACK;
@@ -1468,7 +1508,7 @@ e1000_run_loopback_test(struct e1000_adapter *adapter)
if (unlikely(++k == txdr->count)) k = 0;
}
E1000_WRITE_REG(&adapter->hw, TDT, k);
- msec_delay(200);
+ msleep(200);
time = jiffies; /* set the start time for the receive */
good_cnt = 0;
do { /* receive the sent packets */
@@ -1539,14 +1579,14 @@ e1000_link_test(struct e1000_adapter *adapter, uint64_t *data)
e1000_check_for_link(&adapter->hw);
if (adapter->hw.serdes_link_down == FALSE)
return *data;
- msec_delay(20);
+ msleep(20);
} while (i++ < 3750);
*data = 1;
} else {
e1000_check_for_link(&adapter->hw);
if (adapter->hw.autoneg) /* if auto_neg is set wait for it */
- msec_delay(4000);
+ msleep(4000);
if (!(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU)) {
*data = 1;
@@ -1561,6 +1601,8 @@ e1000_diag_test_count(struct net_device *netdev)
return E1000_TEST_LEN;
}
+extern void e1000_power_up_phy(struct e1000_adapter *);
+
static void
e1000_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, uint64_t *data)
@@ -1568,6 +1610,7 @@ e1000_diag_test(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
boolean_t if_running = netif_running(netdev);
+ set_bit(__E1000_DRIVER_TESTING, &adapter->flags);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
@@ -1576,13 +1619,16 @@ e1000_diag_test(struct net_device *netdev,
uint8_t forced_speed_duplex = adapter->hw.forced_speed_duplex;
uint8_t autoneg = adapter->hw.autoneg;
+ DPRINTK(HW, INFO, "offline testing starting\n");
+
/* Link test performed before hardware reset so autoneg doesn't
* interfere with test result */
if (e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
if (if_running)
- e1000_down(adapter);
+ /* indicate we're in test mode */
+ dev_close(netdev);
else
e1000_reset(adapter);
@@ -1598,6 +1644,8 @@ e1000_diag_test(struct net_device *netdev,
eth_test->flags |= ETH_TEST_FL_FAILED;
e1000_reset(adapter);
+ /* make sure the phy is powered up */
+ e1000_power_up_phy(adapter);
if (e1000_loopback_test(adapter, &data[3]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1607,9 +1655,11 @@ e1000_diag_test(struct net_device *netdev,
adapter->hw.autoneg = autoneg;
e1000_reset(adapter);
+ clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
if (if_running)
- e1000_up(adapter);
+ dev_open(netdev);
} else {
+ DPRINTK(HW, INFO, "online testing starting\n");
/* Online tests */
if (e1000_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
@@ -1619,18 +1669,18 @@ e1000_diag_test(struct net_device *netdev,
data[1] = 0;
data[2] = 0;
data[3] = 0;
+
+ clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
}
msleep_interruptible(4 * 1000);
}
-static void
-e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+static int e1000_wol_exclusion(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
{
- struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ int retval = 1; /* fail by default */
- switch (adapter->hw.device_id) {
- case E1000_DEV_ID_82542:
+ switch (hw->device_id) {
case E1000_DEV_ID_82543GC_FIBER:
case E1000_DEV_ID_82543GC_COPPER:
case E1000_DEV_ID_82544EI_FIBER:
@@ -1638,52 +1688,87 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
case E1000_DEV_ID_82545EM_FIBER:
case E1000_DEV_ID_82545EM_COPPER:
case E1000_DEV_ID_82546GB_QUAD_COPPER:
+ case E1000_DEV_ID_82546GB_PCIE:
+ /* these don't support WoL at all */
wol->supported = 0;
- wol->wolopts = 0;
- return;
-
- case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
- /* device id 10B5 port-A supports wol */
- if (!adapter->ksp3_port_a) {
- wol->supported = 0;
- return;
- }
- /* KSP3 does not suppport UCAST wake-ups for any interface */
- wol->supported = WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC;
-
- if (adapter->wol & E1000_WUFC_EX)
- DPRINTK(DRV, ERR, "Interface does not support "
- "directed (unicast) frame wake-up packets\n");
- wol->wolopts = 0;
- goto do_defaults;
-
+ break;
case E1000_DEV_ID_82546EB_FIBER:
case E1000_DEV_ID_82546GB_FIBER:
case E1000_DEV_ID_82571EB_FIBER:
- /* Wake events only supported on port A for dual fiber */
+ case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_COPPER:
+ /* Wake events not supported on port B */
if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) {
wol->supported = 0;
- wol->wolopts = 0;
- return;
+ break;
}
- /* Fall Through */
-
+ /* return success for non excluded adapter ports */
+ retval = 0;
+ break;
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+ /* quad port adapters only support WoL on port A */
+ if (!adapter->quad_port_a) {
+ wol->supported = 0;
+ break;
+ }
+ /* return success for non excluded adapter ports */
+ retval = 0;
+ break;
default:
- wol->supported = WAKE_UCAST | WAKE_MCAST |
- WAKE_BCAST | WAKE_MAGIC;
- wol->wolopts = 0;
+ /* dual port cards only support WoL on port A from now on
+ * unless it was enabled in the eeprom for port B
+ * so exclude FUNC_1 ports from having WoL enabled */
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1 &&
+ !adapter->eeprom_wol) {
+ wol->supported = 0;
+ break;
+ }
-do_defaults:
- if (adapter->wol & E1000_WUFC_EX)
- wol->wolopts |= WAKE_UCAST;
- if (adapter->wol & E1000_WUFC_MC)
- wol->wolopts |= WAKE_MCAST;
- if (adapter->wol & E1000_WUFC_BC)
- wol->wolopts |= WAKE_BCAST;
- if (adapter->wol & E1000_WUFC_MAG)
- wol->wolopts |= WAKE_MAGIC;
+ retval = 0;
+ }
+
+ return retval;
+}
+
+static void
+e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = WAKE_UCAST | WAKE_MCAST |
+ WAKE_BCAST | WAKE_MAGIC;
+ wol->wolopts = 0;
+
+ /* this function will set ->supported = 0 and return 1 if wol is not
+ * supported by this hardware */
+ if (e1000_wol_exclusion(adapter, wol))
return;
+
+ /* apply any specific unsupported masks here */
+ switch (adapter->hw.device_id) {
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+ /* KSP3 does not suppport UCAST wake-ups */
+ wol->supported &= ~WAKE_UCAST;
+
+ if (adapter->wol & E1000_WUFC_EX)
+ DPRINTK(DRV, ERR, "Interface does not support "
+ "directed (unicast) frame wake-up packets\n");
+ break;
+ default:
+ break;
}
+
+ if (adapter->wol & E1000_WUFC_EX)
+ wol->wolopts |= WAKE_UCAST;
+ if (adapter->wol & E1000_WUFC_MC)
+ wol->wolopts |= WAKE_MCAST;
+ if (adapter->wol & E1000_WUFC_BC)
+ wol->wolopts |= WAKE_BCAST;
+ if (adapter->wol & E1000_WUFC_MAG)
+ wol->wolopts |= WAKE_MAGIC;
+
+ return;
}
static int
@@ -1692,51 +1777,35 @@ e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- switch (adapter->hw.device_id) {
- case E1000_DEV_ID_82542:
- case E1000_DEV_ID_82543GC_FIBER:
- case E1000_DEV_ID_82543GC_COPPER:
- case E1000_DEV_ID_82544EI_FIBER:
- case E1000_DEV_ID_82546EB_QUAD_COPPER:
- case E1000_DEV_ID_82546GB_QUAD_COPPER:
- case E1000_DEV_ID_82545EM_FIBER:
- case E1000_DEV_ID_82545EM_COPPER:
+ if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+ return -EOPNOTSUPP;
+
+ if (e1000_wol_exclusion(adapter, wol))
return wol->wolopts ? -EOPNOTSUPP : 0;
+ switch (hw->device_id) {
case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
- /* device id 10B5 port-A supports wol */
- if (!adapter->ksp3_port_a)
- return wol->wolopts ? -EOPNOTSUPP : 0;
-
if (wol->wolopts & WAKE_UCAST) {
DPRINTK(DRV, ERR, "Interface does not support "
"directed (unicast) frame wake-up packets\n");
return -EOPNOTSUPP;
}
-
- case E1000_DEV_ID_82546EB_FIBER:
- case E1000_DEV_ID_82546GB_FIBER:
- case E1000_DEV_ID_82571EB_FIBER:
- /* Wake events only supported on port A for dual fiber */
- if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
- return wol->wolopts ? -EOPNOTSUPP : 0;
- /* Fall Through */
-
+ break;
default:
- if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
- return -EOPNOTSUPP;
+ break;
+ }
- adapter->wol = 0;
+ /* these settings will always override what we currently have */
+ adapter->wol = 0;
- if (wol->wolopts & WAKE_UCAST)
- adapter->wol |= E1000_WUFC_EX;
- if (wol->wolopts & WAKE_MCAST)
- adapter->wol |= E1000_WUFC_MC;
- if (wol->wolopts & WAKE_BCAST)
- adapter->wol |= E1000_WUFC_BC;
- if (wol->wolopts & WAKE_MAGIC)
- adapter->wol |= E1000_WUFC_MAG;
- }
+ if (wol->wolopts & WAKE_UCAST)
+ adapter->wol |= E1000_WUFC_EX;
+ if (wol->wolopts & WAKE_MCAST)
+ adapter->wol |= E1000_WUFC_MC;
+ if (wol->wolopts & WAKE_BCAST)
+ adapter->wol |= E1000_WUFC_BC;
+ if (wol->wolopts & WAKE_MAGIC)
+ adapter->wol |= E1000_WUFC_MAG;
return 0;
}
@@ -1778,21 +1847,18 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
mod_timer(&adapter->blink_timer, jiffies);
msleep_interruptible(data * 1000);
del_timer_sync(&adapter->blink_timer);
- } else if (adapter->hw.mac_type < e1000_82573) {
- E1000_WRITE_REG(&adapter->hw, LEDCTL,
- (E1000_LEDCTL_LED2_BLINK_RATE |
- E1000_LEDCTL_LED0_BLINK | E1000_LEDCTL_LED2_BLINK |
- (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED0_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED1_MODE_SHIFT)));
+ } else if (adapter->hw.phy_type == e1000_phy_ife) {
+ if (!adapter->blink_timer.function) {
+ init_timer(&adapter->blink_timer);
+ adapter->blink_timer.function = e1000_led_blink_callback;
+ adapter->blink_timer.data = (unsigned long) adapter;
+ }
+ mod_timer(&adapter->blink_timer, jiffies);
msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ e1000_write_phy_reg(&(adapter->hw), IFE_PHY_SPECIAL_CONTROL_LED, 0);
} else {
- E1000_WRITE_REG(&adapter->hw, LEDCTL,
- (E1000_LEDCTL_LED2_BLINK_RATE |
- E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |
- (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
- (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+ e1000_blink_led_start(&adapter->hw);
msleep_interruptible(data * 1000);
}
@@ -1807,10 +1873,8 @@ static int
e1000_nway_reset(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- if (netif_running(netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- }
+ if (netif_running(netdev))
+ e1000_reinit_locked(adapter);
return 0;
}
@@ -1858,7 +1922,7 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
}
}
-static struct ethtool_ops e1000_ethtool_ops = {
+static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings,
.set_settings = e1000_set_settings,
.get_drvinfo = e1000_get_drvinfo,
@@ -1866,8 +1930,8 @@ static struct ethtool_ops e1000_ethtool_ops = {
.get_regs = e1000_get_regs,
.get_wol = e1000_get_wol,
.set_wol = e1000_set_wol,
- .get_msglevel = e1000_get_msglevel,
- .set_msglevel = e1000_set_msglevel,
+ .get_msglevel = e1000_get_msglevel,
+ .set_msglevel = e1000_set_msglevel,
.nway_reset = e1000_nway_reset,
.get_link = ethtool_op_get_link,
.get_eeprom_len = e1000_get_eeprom_len,
@@ -1875,17 +1939,17 @@ static struct ethtool_ops e1000_ethtool_ops = {
.set_eeprom = e1000_set_eeprom,
.get_ringparam = e1000_get_ringparam,
.set_ringparam = e1000_set_ringparam,
- .get_pauseparam = e1000_get_pauseparam,
- .set_pauseparam = e1000_set_pauseparam,
- .get_rx_csum = e1000_get_rx_csum,
- .set_rx_csum = e1000_set_rx_csum,
- .get_tx_csum = e1000_get_tx_csum,
- .set_tx_csum = e1000_set_tx_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
+ .get_pauseparam = e1000_get_pauseparam,
+ .set_pauseparam = e1000_set_pauseparam,
+ .get_rx_csum = e1000_get_rx_csum,
+ .set_rx_csum = e1000_set_rx_csum,
+ .get_tx_csum = e1000_get_tx_csum,
+ .set_tx_csum = e1000_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
#ifdef NETIF_F_TSO
- .get_tso = ethtool_op_get_tso,
- .set_tso = e1000_set_tso,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = e1000_set_tso,
#endif
.self_test_count = e1000_diag_test_count,
.self_test = e1000_diag_test,
@@ -1893,7 +1957,7 @@ static struct ethtool_ops e1000_ethtool_ops = {
.phys_id = e1000_phys_id,
.get_stats_count = e1000_get_stats_count,
.get_ethtool_stats = e1000_get_ethtool_stats,
- .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_perm_addr = ethtool_op_get_perm_addr,
};
void e1000_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 3959039b16e..10b8c8c2532 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -31,6 +31,7 @@
* Shared functions for accessing and configuring the MAC
*/
+
#include "e1000_hw.h"
static int32_t e1000_set_phy_type(struct e1000_hw *hw);
@@ -101,9 +102,37 @@ static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
#define E1000_WRITE_REG_IO(a, reg, val) \
e1000_write_reg_io((a), E1000_##reg, val)
-static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw);
+static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw,
+ uint16_t duplex);
static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
+static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw,
+ uint32_t segment);
+static int32_t e1000_get_software_flag(struct e1000_hw *hw);
+static int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
+static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
+static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
+static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index,
+ uint8_t* data);
+static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index,
+ uint16_t *data);
+static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t *data);
+static void e1000_release_software_flag(struct e1000_hw *hw);
+static void e1000_release_software_semaphore(struct e1000_hw *hw);
+static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw,
+ uint32_t no_snoop);
+static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw,
+ uint32_t index, uint8_t byte);
+static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
+ uint8_t data);
+static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t data);
+
/* IGP cable length table */
static const
uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
@@ -138,10 +167,10 @@ e1000_set_phy_type(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_set_phy_type");
- if(hw->mac_type == e1000_undefined)
+ if (hw->mac_type == e1000_undefined)
return -E1000_ERR_PHY_TYPE;
- switch(hw->phy_id) {
+ switch (hw->phy_id) {
case M88E1000_E_PHY_ID:
case M88E1000_I_PHY_ID:
case M88E1011_I_PHY_ID:
@@ -149,13 +178,21 @@ e1000_set_phy_type(struct e1000_hw *hw)
hw->phy_type = e1000_phy_m88;
break;
case IGP01E1000_I_PHY_ID:
- if(hw->mac_type == e1000_82541 ||
- hw->mac_type == e1000_82541_rev_2 ||
- hw->mac_type == e1000_82547 ||
- hw->mac_type == e1000_82547_rev_2) {
+ if (hw->mac_type == e1000_82541 ||
+ hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547 ||
+ hw->mac_type == e1000_82547_rev_2) {
hw->phy_type = e1000_phy_igp;
break;
}
+ case IGP03E1000_E_PHY_ID:
+ hw->phy_type = e1000_phy_igp_3;
+ break;
+ case IFE_E_PHY_ID:
+ case IFE_PLUS_E_PHY_ID:
+ case IFE_C_E_PHY_ID:
+ hw->phy_type = e1000_phy_ife;
+ break;
case GG82563_E_PHY_ID:
if (hw->mac_type == e1000_80003es2lan) {
hw->phy_type = e1000_phy_gg82563;
@@ -171,6 +208,7 @@ e1000_set_phy_type(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+
/******************************************************************************
* IGP phy init script - initializes the GbE PHY
*
@@ -184,8 +222,8 @@ e1000_phy_init_script(struct e1000_hw *hw)
DEBUGFUNC("e1000_phy_init_script");
- if(hw->phy_init_script) {
- msec_delay(20);
+ if (hw->phy_init_script) {
+ msleep(20);
/* Save off the current value of register 0x2F5B to be restored at
* the end of this routine. */
@@ -194,13 +232,13 @@ e1000_phy_init_script(struct e1000_hw *hw)
/* Disabled the PHY transmitter */
e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
- msec_delay(20);
+ msleep(20);
e1000_write_phy_reg(hw,0x0000,0x0140);
- msec_delay(5);
+ msleep(5);
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82541:
case e1000_82547:
e1000_write_phy_reg(hw, 0x1F95, 0x0001);
@@ -232,27 +270,27 @@ e1000_phy_init_script(struct e1000_hw *hw)
e1000_write_phy_reg(hw, 0x0000, 0x3300);
- msec_delay(20);
+ msleep(20);
/* Now enable the transmitter */
e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
- if(hw->mac_type == e1000_82547) {
+ if (hw->mac_type == e1000_82547) {
uint16_t fused, fine, coarse;
/* Move to analog registers page */
e1000_read_phy_reg(hw, IGP01E1000_ANALOG_SPARE_FUSE_STATUS, &fused);
- if(!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
+ if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
e1000_read_phy_reg(hw, IGP01E1000_ANALOG_FUSE_STATUS, &fused);
fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
- if(coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
+ if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
- } else if(coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
+ } else if (coarse == IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
@@ -332,6 +370,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
break;
case E1000_DEV_ID_82541EI:
case E1000_DEV_ID_82541EI_MOBILE:
+ case E1000_DEV_ID_82541ER_LOM:
hw->mac_type = e1000_82541;
break;
case E1000_DEV_ID_82541ER:
@@ -341,6 +380,7 @@ e1000_set_mac_type(struct e1000_hw *hw)
hw->mac_type = e1000_82541_rev_2;
break;
case E1000_DEV_ID_82547EI:
+ case E1000_DEV_ID_82547EI_MOBILE:
hw->mac_type = e1000_82547;
break;
case E1000_DEV_ID_82547GI:
@@ -349,11 +389,13 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82571EB_COPPER:
case E1000_DEV_ID_82571EB_FIBER:
case E1000_DEV_ID_82571EB_SERDES:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
hw->mac_type = e1000_82571;
break;
case E1000_DEV_ID_82572EI_COPPER:
case E1000_DEV_ID_82572EI_FIBER:
case E1000_DEV_ID_82572EI_SERDES:
+ case E1000_DEV_ID_82572EI:
hw->mac_type = e1000_82572;
break;
case E1000_DEV_ID_82573E:
@@ -361,16 +403,29 @@ e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82573L:
hw->mac_type = e1000_82573;
break;
+ case E1000_DEV_ID_80003ES2LAN_COPPER_SPT:
+ case E1000_DEV_ID_80003ES2LAN_SERDES_SPT:
case E1000_DEV_ID_80003ES2LAN_COPPER_DPT:
case E1000_DEV_ID_80003ES2LAN_SERDES_DPT:
hw->mac_type = e1000_80003es2lan;
break;
+ case E1000_DEV_ID_ICH8_IGP_M_AMT:
+ case E1000_DEV_ID_ICH8_IGP_AMT:
+ case E1000_DEV_ID_ICH8_IGP_C:
+ case E1000_DEV_ID_ICH8_IFE:
+ case E1000_DEV_ID_ICH8_IGP_M:
+ hw->mac_type = e1000_ich8lan;
+ break;
default:
/* Should never have loaded on this device */
return -E1000_ERR_MAC_TYPE;
}
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
+ case e1000_ich8lan:
+ hw->swfwhw_semaphore_present = TRUE;
+ hw->asf_firmware_present = TRUE;
+ break;
case e1000_80003es2lan:
hw->swfw_sync_present = TRUE;
/* fall through */
@@ -404,7 +459,7 @@ e1000_set_media_type(struct e1000_hw *hw)
DEBUGFUNC("e1000_set_media_type");
- if(hw->mac_type != e1000_82543) {
+ if (hw->mac_type != e1000_82543) {
/* tbi_compatibility is only valid on 82543 */
hw->tbi_compatibility_en = FALSE;
}
@@ -423,6 +478,7 @@ e1000_set_media_type(struct e1000_hw *hw)
case e1000_82542_rev2_1:
hw->media_type = e1000_media_type_fiber;
break;
+ case e1000_ich8lan:
case e1000_82573:
/* The STATUS_TBIMODE bit is reserved or reused for the this
* device.
@@ -463,16 +519,16 @@ e1000_reset_hw(struct e1000_hw *hw)
DEBUGFUNC("e1000_reset_hw");
/* For 82542 (rev 2.0), disable MWI before issuing a device reset */
- if(hw->mac_type == e1000_82542_rev2_0) {
+ if (hw->mac_type == e1000_82542_rev2_0) {
DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
e1000_pci_clear_mwi(hw);
}
- if(hw->bus_type == e1000_bus_type_pci_express) {
+ if (hw->bus_type == e1000_bus_type_pci_express) {
/* Prevent the PCI-E bus from sticking if there is no TLP connection
* on the last TLP read/write transaction when MAC is reset.
*/
- if(e1000_disable_pciex_master(hw) != E1000_SUCCESS) {
+ if (e1000_disable_pciex_master(hw) != E1000_SUCCESS) {
DEBUGOUT("PCI-E Master disable polling has failed.\n");
}
}
@@ -495,19 +551,19 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Delay to allow any outstanding PCI transactions to complete before
* resetting the device
*/
- msec_delay(10);
+ msleep(10);
ctrl = E1000_READ_REG(hw, CTRL);
/* Must reset the PHY before resetting the MAC */
- if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_PHY_RST));
- msec_delay(5);
+ msleep(5);
}
/* Must acquire the MDIO ownership before MAC reset.
* Ownership defaults to firmware after a reset. */
- if(hw->mac_type == e1000_82573) {
+ if (hw->mac_type == e1000_82573) {
timeout = 10;
extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
@@ -517,14 +573,22 @@ e1000_reset_hw(struct e1000_hw *hw)
E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
- if(extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP)
break;
else
extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
- msec_delay(2);
+ msleep(2);
timeout--;
- } while(timeout);
+ } while (timeout);
+ }
+
+ /* Workaround for ICH8 bit corruption issue in FIFO memory */
+ if (hw->mac_type == e1000_ich8lan) {
+ /* Set Tx and Rx buffer allocation to 8k apiece. */
+ E1000_WRITE_REG(hw, PBA, E1000_PBA_8K);
+ /* Set Packet Buffer Size to 16k. */
+ E1000_WRITE_REG(hw, PBS, E1000_PBS_16K);
}
/* Issue a global reset to the MAC. This will reset the chip's
@@ -534,7 +598,7 @@ e1000_reset_hw(struct e1000_hw *hw)
*/
DEBUGOUT("Issuing a global reset to MAC\n");
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82544:
case e1000_82540:
case e1000_82545:
@@ -550,6 +614,20 @@ e1000_reset_hw(struct e1000_hw *hw)
/* Reset is performed on a shadow of the control register */
E1000_WRITE_REG(hw, CTRL_DUP, (ctrl | E1000_CTRL_RST));
break;
+ case e1000_ich8lan:
+ if (!hw->phy_reset_disable &&
+ e1000_check_phy_reset_block(hw) == E1000_SUCCESS) {
+ /* e1000_ich8lan PHY HW reset requires MAC CORE reset
+ * at the same time to make sure the interface between
+ * MAC and the external PHY is reset.
+ */
+ ctrl |= E1000_CTRL_PHY_RST;
+ }
+
+ e1000_get_software_flag(hw);
+ E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+ msleep(5);
+ break;
default:
E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
break;
@@ -559,7 +637,7 @@ e1000_reset_hw(struct e1000_hw *hw)
* device. Later controllers reload the EEPROM automatically, so just wait
* for reload to complete.
*/
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -571,14 +649,14 @@ e1000_reset_hw(struct e1000_hw *hw)
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
/* Wait for EEPROM reload */
- msec_delay(2);
+ msleep(2);
break;
case e1000_82541:
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
/* Wait for EEPROM reload */
- msec_delay(20);
+ msleep(20);
break;
case e1000_82573:
if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
@@ -591,26 +669,27 @@ e1000_reset_hw(struct e1000_hw *hw)
/* fall through */
case e1000_82571:
case e1000_82572:
+ case e1000_ich8lan:
case e1000_80003es2lan:
ret_val = e1000_get_auto_rd_done(hw);
- if(ret_val)
+ if (ret_val)
/* We don't want to continue accessing MAC registers. */
return ret_val;
break;
default:
/* Wait for EEPROM reload (it happens automatically) */
- msec_delay(5);
+ msleep(5);
break;
}
/* Disable HW ARPs on ASF enabled adapters */
- if(hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) {
+ if (hw->mac_type >= e1000_82540 && hw->mac_type <= e1000_82547_rev_2) {
manc = E1000_READ_REG(hw, MANC);
manc &= ~(E1000_MANC_ARP_EN);
E1000_WRITE_REG(hw, MANC, manc);
}
- if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
e1000_phy_init_script(hw);
/* Configure activity LED after PHY reset */
@@ -628,11 +707,17 @@ e1000_reset_hw(struct e1000_hw *hw)
icr = E1000_READ_REG(hw, ICR);
/* If MWI was previously enabled, reenable it. */
- if(hw->mac_type == e1000_82542_rev2_0) {
- if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ if (hw->mac_type == e1000_82542_rev2_0) {
+ if (hw->pci_cmd_word & PCI_COMMAND_INVALIDATE)
e1000_pci_set_mwi(hw);
}
+ if (hw->mac_type == e1000_ich8lan) {
+ uint32_t kab = E1000_READ_REG(hw, KABGTXD);
+ kab |= E1000_KABGTXD_BGSQLBIAS;
+ E1000_WRITE_REG(hw, KABGTXD, kab);
+ }
+
return E1000_SUCCESS;
}
@@ -663,9 +748,20 @@ e1000_init_hw(struct e1000_hw *hw)
DEBUGFUNC("e1000_init_hw");
+ /* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */
+ if (hw->mac_type == e1000_ich8lan) {
+ reg_data = E1000_READ_REG(hw, TARC0);
+ reg_data |= 0x30000000;
+ E1000_WRITE_REG(hw, TARC0, reg_data);
+
+ reg_data = E1000_READ_REG(hw, STATUS);
+ reg_data &= ~0x80000000;
+ E1000_WRITE_REG(hw, STATUS, reg_data);
+ }
+
/* Initialize Identification LED */
ret_val = e1000_id_led_init(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Initializing Identification LED\n");
return ret_val;
}
@@ -675,17 +771,20 @@ e1000_init_hw(struct e1000_hw *hw)
/* Disabling VLAN filtering. */
DEBUGOUT("Initializing the IEEE VLAN\n");
- if (hw->mac_type < e1000_82545_rev_3)
- E1000_WRITE_REG(hw, VET, 0);
- e1000_clear_vfta(hw);
+ /* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
+ if (hw->mac_type != e1000_ich8lan) {
+ if (hw->mac_type < e1000_82545_rev_3)
+ E1000_WRITE_REG(hw, VET, 0);
+ e1000_clear_vfta(hw);
+ }
/* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
- if(hw->mac_type == e1000_82542_rev2_0) {
+ if (hw->mac_type == e1000_82542_rev2_0) {
DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
e1000_pci_clear_mwi(hw);
E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
E1000_WRITE_FLUSH(hw);
- msec_delay(5);
+ msleep(5);
}
/* Setup the receive address. This involves initializing all of the Receive
@@ -694,37 +793,43 @@ e1000_init_hw(struct e1000_hw *hw)
e1000_init_rx_addrs(hw);
/* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
- if(hw->mac_type == e1000_82542_rev2_0) {
+ if (hw->mac_type == e1000_82542_rev2_0) {
E1000_WRITE_REG(hw, RCTL, 0);
E1000_WRITE_FLUSH(hw);
- msec_delay(1);
- if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+ msleep(1);
+ if (hw->pci_cmd_word & PCI_COMMAND_INVALIDATE)
e1000_pci_set_mwi(hw);
}
/* Zero out the Multicast HASH table */
DEBUGOUT("Zeroing the MTA\n");
mta_size = E1000_MC_TBL_SIZE;
- for(i = 0; i < mta_size; i++)
+ if (hw->mac_type == e1000_ich8lan)
+ mta_size = E1000_MC_TBL_SIZE_ICH8LAN;
+ for (i = 0; i < mta_size; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ /* use write flush to prevent Memory Write Block (MWB) from
+ * occuring when accessing our register space */
+ E1000_WRITE_FLUSH(hw);
+ }
/* Set the PCI priority bit correctly in the CTRL register. This
* determines if the adapter gives priority to receives, or if it
* gives equal priority to transmits and receives. Valid only on
* 82542 and 82543 silicon.
*/
- if(hw->dma_fairness && hw->mac_type <= e1000_82543) {
+ if (hw->dma_fairness && hw->mac_type <= e1000_82543) {
ctrl = E1000_READ_REG(hw, CTRL);
E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
}
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82545_rev_3:
case e1000_82546_rev_3:
break;
default:
/* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
- if(hw->bus_type == e1000_bus_type_pcix) {
+ if (hw->bus_type == e1000_bus_type_pcix) {
e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI,
&pcix_stat_hi_word);
@@ -732,9 +837,9 @@ e1000_init_hw(struct e1000_hw *hw)
PCIX_COMMAND_MMRBC_SHIFT;
stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
PCIX_STATUS_HI_MMRBC_SHIFT;
- if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+ if (stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
- if(cmd_mmrbc > stat_mmrbc) {
+ if (cmd_mmrbc > stat_mmrbc) {
pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER,
@@ -744,11 +849,15 @@ e1000_init_hw(struct e1000_hw *hw)
break;
}
+ /* More time needed for PHY to initialize */
+ if (hw->mac_type == e1000_ich8lan)
+ msleep(15);
+
/* Call a subroutine to configure the link and setup flow control. */
ret_val = e1000_setup_link(hw);
/* Set the transmit descriptor write-back policy */
- if(hw->mac_type > e1000_82544) {
+ if (hw->mac_type > e1000_82544) {
ctrl = E1000_READ_REG(hw, TXDCTL);
ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
switch (hw->mac_type) {
@@ -757,6 +866,7 @@ e1000_init_hw(struct e1000_hw *hw)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_ich8lan:
case e1000_80003es2lan:
ctrl |= E1000_TXDCTL_COUNT_DESC;
break;
@@ -795,16 +905,16 @@ e1000_init_hw(struct e1000_hw *hw)
/* Fall through */
case e1000_82571:
case e1000_82572:
+ case e1000_ich8lan:
ctrl = E1000_READ_REG(hw, TXDCTL1);
ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
- if(hw->mac_type >= e1000_82571)
+ if (hw->mac_type >= e1000_82571)
ctrl |= E1000_TXDCTL_COUNT_DESC;
E1000_WRITE_REG(hw, TXDCTL1, ctrl);
break;
}
-
if (hw->mac_type == e1000_82573) {
uint32_t gcr = E1000_READ_REG(hw, GCR);
gcr |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
@@ -818,6 +928,11 @@ e1000_init_hw(struct e1000_hw *hw)
*/
e1000_clear_hw_cntrs(hw);
+ /* ICH8 No-snoop bits are opposite polarity.
+ * Set to snoop by default after reset. */
+ if (hw->mac_type == e1000_ich8lan)
+ e1000_set_pci_ex_no_snoop(hw, PCI_EX_82566_SNOOP_ALL);
+
if (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER ||
hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3) {
ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
@@ -843,10 +958,10 @@ e1000_adjust_serdes_amplitude(struct e1000_hw *hw)
DEBUGFUNC("e1000_adjust_serdes_amplitude");
- if(hw->media_type != e1000_media_type_internal_serdes)
+ if (hw->media_type != e1000_media_type_internal_serdes)
return E1000_SUCCESS;
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82545_rev_3:
case e1000_82546_rev_3:
break;
@@ -859,11 +974,11 @@ e1000_adjust_serdes_amplitude(struct e1000_hw *hw)
return ret_val;
}
- if(eeprom_data != EEPROM_RESERVED_WORD) {
+ if (eeprom_data != EEPROM_RESERVED_WORD) {
/* Adjust SERDES output amplitude only. */
eeprom_data &= EEPROM_SERDES_AMPLITUDE_MASK;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_EXT_CTRL, eeprom_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
@@ -905,6 +1020,7 @@ e1000_setup_link(struct e1000_hw *hw)
*/
if (hw->fc == e1000_fc_default) {
switch (hw->mac_type) {
+ case e1000_ich8lan:
case e1000_82573:
hw->fc = e1000_fc_full;
break;
@@ -930,10 +1046,10 @@ e1000_setup_link(struct e1000_hw *hw)
* in case we get disconnected and then reconnected into a different
* hub or switch with different Flow Control capabilities.
*/
- if(hw->mac_type == e1000_82542_rev2_0)
+ if (hw->mac_type == e1000_82542_rev2_0)
hw->fc &= (~e1000_fc_tx_pause);
- if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+ if ((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
hw->fc &= (~e1000_fc_rx_pause);
hw->original_fc = hw->fc;
@@ -948,12 +1064,12 @@ e1000_setup_link(struct e1000_hw *hw)
* or e1000_phy_setup() is called.
*/
if (hw->mac_type == e1000_82543) {
- ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
- 1, &eeprom_data);
- if (ret_val) {
- DEBUGOUT("EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
- }
+ ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
+ 1, &eeprom_data);
+ if (ret_val) {
+ DEBUGOUT("EEPROM Read Error\n");
+ return -E1000_ERR_EEPROM;
+ }
ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) <<
SWDPIO__EXT_SHIFT);
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
@@ -971,9 +1087,12 @@ e1000_setup_link(struct e1000_hw *hw)
*/
DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
- E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
- E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
- E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ /* FCAL/H and FCT are hardcoded to standard values in e1000_ich8lan. */
+ if (hw->mac_type != e1000_ich8lan) {
+ E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+ E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+ E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+ }
E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
@@ -983,14 +1102,14 @@ e1000_setup_link(struct e1000_hw *hw)
* ability to transmit pause frames in not enabled, then these
* registers will be set to 0.
*/
- if(!(hw->fc & e1000_fc_tx_pause)) {
+ if (!(hw->fc & e1000_fc_tx_pause)) {
E1000_WRITE_REG(hw, FCRTL, 0);
E1000_WRITE_REG(hw, FCRTH, 0);
} else {
/* We need to set up the Receive Threshold high and low water marks
* as well as (optionally) enabling the transmission of XON frames.
*/
- if(hw->fc_send_xon) {
+ if (hw->fc_send_xon) {
E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
} else {
@@ -1037,11 +1156,11 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
* the EEPROM.
*/
ctrl = E1000_READ_REG(hw, CTRL);
- if(hw->media_type == e1000_media_type_fiber)
+ if (hw->media_type == e1000_media_type_fiber)
signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
ret_val = e1000_adjust_serdes_amplitude(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Take the link out of reset */
@@ -1049,7 +1168,7 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
/* Adjust VCO speed to improve BER performance */
ret_val = e1000_set_vco_speed(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
e1000_config_collision_dist(hw);
@@ -1112,7 +1231,7 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
hw->txcw = txcw;
- msec_delay(1);
+ msleep(1);
/* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
* indication in the Device Status Register. Time-out if a link isn't
@@ -1120,15 +1239,15 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
* less than 500 milliseconds even if the other end is doing it in SW).
* For internal serdes, we just assume a signal is present, then poll.
*/
- if(hw->media_type == e1000_media_type_internal_serdes ||
+ if (hw->media_type == e1000_media_type_internal_serdes ||
(E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
DEBUGOUT("Looking for Link\n");
- for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
- msec_delay(10);
+ for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+ msleep(10);
status = E1000_READ_REG(hw, STATUS);
- if(status & E1000_STATUS_LU) break;
+ if (status & E1000_STATUS_LU) break;
}
- if(i == (LINK_UP_TIMEOUT / 10)) {
+ if (i == (LINK_UP_TIMEOUT / 10)) {
DEBUGOUT("Never got a valid link from auto-neg!!!\n");
hw->autoneg_failed = 1;
/* AutoNeg failed to achieve a link, so we'll call
@@ -1137,7 +1256,7 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
* non-autonegotiating link partners.
*/
ret_val = e1000_check_for_link(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error while checking for link\n");
return ret_val;
}
@@ -1171,7 +1290,7 @@ e1000_copper_link_preconfig(struct e1000_hw *hw)
* the PHY speed and duplex configuration is. In addition, we need to
* perform a hardware reset on the PHY to take it out of reset.
*/
- if(hw->mac_type > e1000_82543) {
+ if (hw->mac_type > e1000_82543) {
ctrl |= E1000_CTRL_SLU;
ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
E1000_WRITE_REG(hw, CTRL, ctrl);
@@ -1179,13 +1298,13 @@ e1000_copper_link_preconfig(struct e1000_hw *hw)
ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
E1000_WRITE_REG(hw, CTRL, ctrl);
ret_val = e1000_phy_hw_reset(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
/* Make sure we have a valid PHY */
ret_val = e1000_detect_gig_phy(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error, did not detect valid phy.\n");
return ret_val;
}
@@ -1193,19 +1312,19 @@ e1000_copper_link_preconfig(struct e1000_hw *hw)
/* Set PHY to class A mode (if necessary) */
ret_val = e1000_set_phy_mode(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if((hw->mac_type == e1000_82545_rev_3) ||
+ if ((hw->mac_type == e1000_82545_rev_3) ||
(hw->mac_type == e1000_82546_rev_3)) {
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
phy_data |= 0x00000008;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
}
- if(hw->mac_type <= e1000_82543 ||
- hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
- hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2)
+ if (hw->mac_type <= e1000_82543 ||
+ hw->mac_type == e1000_82541 || hw->mac_type == e1000_82547 ||
+ hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2)
hw->phy_reset_disable = FALSE;
return E1000_SUCCESS;
@@ -1235,20 +1354,24 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
return ret_val;
}
- /* Wait 10ms for MAC to configure PHY from eeprom settings */
- msec_delay(15);
-
+ /* Wait 15ms for MAC to configure PHY from eeprom settings */
+ msleep(15);
+ if (hw->mac_type != e1000_ich8lan) {
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
led_ctrl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
E1000_WRITE_REG(hw, LEDCTL, led_ctrl);
+ }
- /* disable lplu d3 during driver init */
- ret_val = e1000_set_d3_lplu_state(hw, FALSE);
- if (ret_val) {
- DEBUGOUT("Error Disabling LPLU D3\n");
- return ret_val;
+ /* The NVM settings will configure LPLU in D3 for IGP2 and IGP3 PHYs */
+ if (hw->phy_type == e1000_phy_igp) {
+ /* disable lplu d3 during driver init */
+ ret_val = e1000_set_d3_lplu_state(hw, FALSE);
+ if (ret_val) {
+ DEBUGOUT("Error Disabling LPLU D3\n");
+ return ret_val;
+ }
}
/* disable lplu d0 during driver init */
@@ -1286,45 +1409,45 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
}
}
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* set auto-master slave resolution settings */
- if(hw->autoneg) {
+ if (hw->autoneg) {
e1000_ms_type phy_ms_setting = hw->master_slave;
- if(hw->ffe_config_state == e1000_ffe_config_active)
+ if (hw->ffe_config_state == e1000_ffe_config_active)
hw->ffe_config_state = e1000_ffe_config_enabled;
- if(hw->dsp_config_state == e1000_dsp_config_activated)
+ if (hw->dsp_config_state == e1000_dsp_config_activated)
hw->dsp_config_state = e1000_dsp_config_enabled;
/* when autonegotiation advertisment is only 1000Mbps then we
* should disable SmartSpeed and enable Auto MasterSlave
* resolution as hardware default. */
- if(hw->autoneg_advertised == ADVERTISE_1000_FULL) {
+ if (hw->autoneg_advertised == ADVERTISE_1000_FULL) {
/* Disable SmartSpeed */
- ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
- if(ret_val)
+ ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ &phy_data);
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
- ret_val = e1000_write_phy_reg(hw,
- IGP01E1000_PHY_PORT_CONFIG,
- phy_data);
- if(ret_val)
+ ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
+ phy_data);
+ if (ret_val)
return ret_val;
/* Set auto Master/Slave resolution process */
ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~CR_1000T_MS_ENABLE;
ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* load defaults for future use */
@@ -1348,7 +1471,7 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
break;
}
ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
@@ -1369,12 +1492,12 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
DEBUGFUNC("e1000_copper_link_ggp_setup");
- if(!hw->phy_reset_disable) {
+ if (!hw->phy_reset_disable) {
/* Enable CRS on TX for half-duplex operation. */
ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX;
@@ -1383,7 +1506,7 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL,
phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Options:
@@ -1394,7 +1517,7 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
* 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
*/
ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK;
@@ -1419,11 +1542,11 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
* 1 - Enabled
*/
phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
- if(hw->disable_polarity_correction == 1)
+ if (hw->disable_polarity_correction == 1)
phy_data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE;
ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* SW Reset the PHY so all changes take effect */
@@ -1478,11 +1601,10 @@ e1000_copper_link_ggp_setup(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* Enable Pass False Carrier on the PHY */
- phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
-
+ phy_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL,
phy_data);
+
if (ret_val)
return ret_val;
}
@@ -1517,12 +1639,12 @@ e1000_copper_link_mgp_setup(struct e1000_hw *hw)
DEBUGFUNC("e1000_copper_link_mgp_setup");
- if(hw->phy_reset_disable)
+ if (hw->phy_reset_disable)
return E1000_SUCCESS;
/* Enable CRS on TX. This must be set for half-duplex operation. */
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
@@ -1559,35 +1681,47 @@ e1000_copper_link_mgp_setup(struct e1000_hw *hw)
* 1 - Enabled
*/
phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
- if(hw->disable_polarity_correction == 1)
+ if (hw->disable_polarity_correction == 1)
phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
- ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
- return ret_val;
-
- /* Force TX_CLK in the Extended PHY Specific Control Register
- * to 25MHz clock.
- */
- ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
return ret_val;
- phy_data |= M88E1000_EPSCR_TX_CLK_25;
-
if (hw->phy_revision < M88E1011_I_REV_4) {
- /* Configure Master and Slave downshift values */
- phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ /* Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+ if ((hw->phy_revision == E1000_REVISION_2) &&
+ (hw->phy_id == M88E1111_I_PHY_ID)) {
+ /* Vidalia Phy, set the downshift counter to 5x */
+ phy_data &= ~(M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK);
+ phy_data |= M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
- phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
- ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
- return ret_val;
+ ret_val = e1000_write_phy_reg(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+ }
}
/* SW Reset the PHY so all changes take effect */
ret_val = e1000_phy_reset(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Resetting the PHY\n");
return ret_val;
}
@@ -1617,12 +1751,16 @@ e1000_copper_link_autoneg(struct e1000_hw *hw)
/* If autoneg_advertised is zero, we assume it was not defaulted
* by the calling code so we set to advertise full capability.
*/
- if(hw->autoneg_advertised == 0)
+ if (hw->autoneg_advertised == 0)
hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+ /* IFE phy only supports 10/100 */
+ if (hw->phy_type == e1000_phy_ife)
+ hw->autoneg_advertised &= AUTONEG_ADVERTISE_10_100_ALL;
+
DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
ret_val = e1000_phy_setup_autoneg(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Setting up Auto-Negotiation\n");
return ret_val;
}
@@ -1632,20 +1770,20 @@ e1000_copper_link_autoneg(struct e1000_hw *hw)
* the Auto Neg Restart bit in the PHY control register.
*/
ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Does the user want to wait for Auto-Neg to complete here, or
* check at a later time (for example, callback routine).
*/
- if(hw->wait_autoneg_complete) {
+ if (hw->wait_autoneg_complete) {
ret_val = e1000_wait_autoneg(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error while waiting for autoneg to complete\n");
return ret_val;
}
@@ -1656,7 +1794,6 @@ e1000_copper_link_autoneg(struct e1000_hw *hw)
return E1000_SUCCESS;
}
-
/******************************************************************************
* Config the MAC and the PHY after link is up.
* 1) Set up the MAC to the current PHY speed/duplex
@@ -1675,25 +1812,25 @@ e1000_copper_link_postconfig(struct e1000_hw *hw)
int32_t ret_val;
DEBUGFUNC("e1000_copper_link_postconfig");
- if(hw->mac_type >= e1000_82544) {
+ if (hw->mac_type >= e1000_82544) {
e1000_config_collision_dist(hw);
} else {
ret_val = e1000_config_mac_to_phy(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error configuring MAC to PHY settings\n");
return ret_val;
}
}
ret_val = e1000_config_fc_after_link_up(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Configuring Flow Control\n");
return ret_val;
}
/* Config DSP to improve Giga link quality */
- if(hw->phy_type == e1000_phy_igp) {
+ if (hw->phy_type == e1000_phy_igp) {
ret_val = e1000_config_dsp_after_link_change(hw, TRUE);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Configuring DSP after link up\n");
return ret_val;
}
@@ -1717,17 +1854,35 @@ e1000_setup_copper_link(struct e1000_hw *hw)
DEBUGFUNC("e1000_setup_copper_link");
+ switch (hw->mac_type) {
+ case e1000_80003es2lan:
+ case e1000_ich8lan:
+ /* Set the mac to wait the maximum time between each
+ * iteration and increase the max iterations when
+ * polling the phy; this fixes erroneous timeouts at 10Mbps. */
+ ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_read_kmrn_reg(hw, GG82563_REG(0x34, 9), &reg_data);
+ if (ret_val)
+ return ret_val;
+ reg_data |= 0x3F;
+ ret_val = e1000_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data);
+ if (ret_val)
+ return ret_val;
+ default:
+ break;
+ }
+
/* Check if it is a valid PHY and set PHY mode if necessary. */
ret_val = e1000_copper_link_preconfig(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
switch (hw->mac_type) {
case e1000_80003es2lan:
- ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
- &reg_data);
- if (ret_val)
- return ret_val;
+ /* Kumeran registers are written-only */
+ reg_data = E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT;
reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING;
ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL,
reg_data);
@@ -1739,32 +1894,33 @@ e1000_setup_copper_link(struct e1000_hw *hw)
}
if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
ret_val = e1000_copper_link_igp_setup(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else if (hw->phy_type == e1000_phy_m88) {
ret_val = e1000_copper_link_mgp_setup(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else if (hw->phy_type == e1000_phy_gg82563) {
ret_val = e1000_copper_link_ggp_setup(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
- if(hw->autoneg) {
+ if (hw->autoneg) {
/* Setup autoneg and flow control advertisement
* and perform autonegotiation */
ret_val = e1000_copper_link_autoneg(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else {
/* PHY will be set to 10H, 10F, 100H,or 100F
* depending on value from forced_speed_duplex. */
DEBUGOUT("Forcing speed and duplex\n");
ret_val = e1000_phy_force_speed_duplex(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Forcing Speed and Duplex\n");
return ret_val;
}
@@ -1773,18 +1929,18 @@ e1000_setup_copper_link(struct e1000_hw *hw)
/* Check link status. Wait up to 100 microseconds for link to become
* valid.
*/
- for(i = 0; i < 10; i++) {
+ for (i = 0; i < 10; i++) {
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(phy_data & MII_SR_LINK_STATUS) {
+ if (phy_data & MII_SR_LINK_STATUS) {
/* Config the MAC and PHY after link is up */
ret_val = e1000_copper_link_postconfig(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
DEBUGOUT("Valid link established!!!\n");
@@ -1803,7 +1959,7 @@ e1000_setup_copper_link(struct e1000_hw *hw)
* hw - Struct containing variables accessed by shared code
******************************************************************************/
static int32_t
-e1000_configure_kmrn_for_10_100(struct e1000_hw *hw)
+e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, uint16_t duplex)
{
int32_t ret_val = E1000_SUCCESS;
uint32_t tipg;
@@ -1823,6 +1979,18 @@ e1000_configure_kmrn_for_10_100(struct e1000_hw *hw)
tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100;
E1000_WRITE_REG(hw, TIPG, tipg);
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ if (duplex == HALF_DUPLEX)
+ reg_data |= GG82563_KMCR_PASS_FALSE_CARRIER;
+ else
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
return ret_val;
}
@@ -1847,6 +2015,14 @@ e1000_configure_kmrn_for_1000(struct e1000_hw *hw)
tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000;
E1000_WRITE_REG(hw, TIPG, tipg);
+ ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, &reg_data);
+
+ if (ret_val)
+ return ret_val;
+
+ reg_data &= ~GG82563_KMCR_PASS_FALSE_CARRIER;
+ ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, reg_data);
+
return ret_val;
}
@@ -1866,13 +2042,16 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
/* Read the MII Auto-Neg Advertisement Register (Address 4). */
ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
- /* Read the MII 1000Base-T Control Register (Address 9). */
- ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
- if(ret_val)
- return ret_val;
+ if (hw->phy_type != e1000_phy_ife) {
+ /* Read the MII 1000Base-T Control Register (Address 9). */
+ ret_val = e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ } else
+ mii_1000t_ctrl_reg=0;
/* Need to parse both autoneg_advertised and fc and set up
* the appropriate PHY registers. First we will parse for
@@ -1891,38 +2070,41 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
/* Do we want to advertise 10 Mb Half Duplex? */
- if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+ if (hw->autoneg_advertised & ADVERTISE_10_HALF) {
DEBUGOUT("Advertise 10mb Half duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
}
/* Do we want to advertise 10 Mb Full Duplex? */
- if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+ if (hw->autoneg_advertised & ADVERTISE_10_FULL) {
DEBUGOUT("Advertise 10mb Full duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
}
/* Do we want to advertise 100 Mb Half Duplex? */
- if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+ if (hw->autoneg_advertised & ADVERTISE_100_HALF) {
DEBUGOUT("Advertise 100mb Half duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
}
/* Do we want to advertise 100 Mb Full Duplex? */
- if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+ if (hw->autoneg_advertised & ADVERTISE_100_FULL) {
DEBUGOUT("Advertise 100mb Full duplex\n");
mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
}
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
- if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ if (hw->autoneg_advertised & ADVERTISE_1000_HALF) {
DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
}
/* Do we want to advertise 1000 Mb Full Duplex? */
- if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+ if (hw->autoneg_advertised & ADVERTISE_1000_FULL) {
DEBUGOUT("Advertise 1000mb Full duplex\n");
mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+ if (hw->phy_type == e1000_phy_ife) {
+ DEBUGOUT("e1000_phy_ife is a 10/100 PHY. Gigabit speed is not supported.\n");
+ }
}
/* Check for a software override of the flow control settings, and
@@ -1979,14 +2161,16 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
}
ret_val = e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
- ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
- if(ret_val)
- return ret_val;
+ if (hw->phy_type != e1000_phy_ife) {
+ ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg);
+ if (ret_val)
+ return ret_val;
+ }
return E1000_SUCCESS;
}
@@ -2025,7 +2209,7 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
/* Read the MII Control Register. */
ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* We need to disable autoneg in order to force link and duplex. */
@@ -2033,8 +2217,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
/* Are we forcing Full or Half Duplex? */
- if(hw->forced_speed_duplex == e1000_100_full ||
- hw->forced_speed_duplex == e1000_10_full) {
+ if (hw->forced_speed_duplex == e1000_100_full ||
+ hw->forced_speed_duplex == e1000_10_full) {
/* We want to force full duplex so we SET the full duplex bits in the
* Device and MII Control Registers.
*/
@@ -2051,7 +2235,7 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
}
/* Are we forcing 100Mbps??? */
- if(hw->forced_speed_duplex == e1000_100_full ||
+ if (hw->forced_speed_duplex == e1000_100_full ||
hw->forced_speed_duplex == e1000_100_half) {
/* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
ctrl |= E1000_CTRL_SPD_100;
@@ -2074,7 +2258,7 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
if ((hw->phy_type == e1000_phy_m88) ||
(hw->phy_type == e1000_phy_gg82563)) {
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
@@ -2082,32 +2266,44 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
*/
phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
/* Need to reset the PHY or these changes will be ignored */
mii_ctrl_reg |= MII_CR_RESET;
+ /* Disable MDI-X support for 10/100 */
+ } else if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IFE_PMC_AUTO_MDIX;
+ phy_data &= ~IFE_PMC_FORCE_MDIX;
+
+ ret_val = e1000_write_phy_reg(hw, IFE_PHY_MDIX_CONTROL, phy_data);
+ if (ret_val)
+ return ret_val;
} else {
/* Clear Auto-Crossover to force MDI manually. IGP requires MDI
* forced whenever speed or duplex are forced.
*/
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PSCR_AUTO_MDIX;
phy_data &= ~IGP01E1000_PSCR_FORCE_MDI_MDIX;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
/* Write back the modified PHY MII control register. */
ret_val = e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
udelay(1);
@@ -2119,50 +2315,50 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
* only if the user has set wait_autoneg_complete to 1, which is
* the default.
*/
- if(hw->wait_autoneg_complete) {
+ if (hw->wait_autoneg_complete) {
/* We will wait for autoneg to complete. */
DEBUGOUT("Waiting for forced speed/duplex link.\n");
mii_status_reg = 0;
/* We will wait for autoneg to complete or 4.5 seconds to expire. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
+ for (i = PHY_FORCE_TIME; i > 0; i--) {
/* Read the MII Status Register and wait for Auto-Neg Complete bit
* to be set.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(mii_status_reg & MII_SR_LINK_STATUS) break;
- msec_delay(100);
+ if (mii_status_reg & MII_SR_LINK_STATUS) break;
+ msleep(100);
}
- if((i == 0) &&
+ if ((i == 0) &&
((hw->phy_type == e1000_phy_m88) ||
(hw->phy_type == e1000_phy_gg82563))) {
/* We didn't get link. Reset the DSP and wait again for link. */
ret_val = e1000_phy_reset_dsp(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error Resetting PHY DSP\n");
return ret_val;
}
}
/* This loop will early-out if the link condition has been met. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
- if(mii_status_reg & MII_SR_LINK_STATUS) break;
- msec_delay(100);
+ for (i = PHY_FORCE_TIME; i > 0; i--) {
+ if (mii_status_reg & MII_SR_LINK_STATUS) break;
+ msleep(100);
/* Read the MII Status Register and wait for Auto-Neg Complete bit
* to be set.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
}
@@ -2173,32 +2369,31 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
* defaults back to a 2.5MHz clock when the PHY is reset.
*/
ret_val = e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= M88E1000_EPSCR_TX_CLK_25;
ret_val = e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* In addition, because of the s/w reset above, we need to enable CRS on
* TX. This must be set for both full and half duplex operation.
*/
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
- (!hw->autoneg) &&
- (hw->forced_speed_duplex == e1000_10_full ||
- hw->forced_speed_duplex == e1000_10_half)) {
+ if ((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
+ (!hw->autoneg) && (hw->forced_speed_duplex == e1000_10_full ||
+ hw->forced_speed_duplex == e1000_10_half)) {
ret_val = e1000_polarity_reversal_workaround(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
} else if (hw->phy_type == e1000_phy_gg82563) {
@@ -2289,10 +2484,10 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
* registers depending on negotiated values.
*/
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(phy_data & M88E1000_PSSR_DPLX)
+ if (phy_data & M88E1000_PSSR_DPLX)
ctrl |= E1000_CTRL_FD;
else
ctrl &= ~E1000_CTRL_FD;
@@ -2302,9 +2497,9 @@ e1000_config_mac_to_phy(struct e1000_hw *hw)
/* Set up speed in the Device Control register depending on
* negotiated values.
*/
- if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
ctrl |= E1000_CTRL_SPD_1000;
- else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+ else if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
ctrl |= E1000_CTRL_SPD_100;
/* Write the configured values back to the Device Control Reg. */
@@ -2372,7 +2567,7 @@ e1000_force_mac_fc(struct e1000_hw *hw)
}
/* Disable TX Flow Control for 82542 (rev 2.0) */
- if(hw->mac_type == e1000_82542_rev2_0)
+ if (hw->mac_type == e1000_82542_rev2_0)
ctrl &= (~E1000_CTRL_TFCE);
E1000_WRITE_REG(hw, CTRL, ctrl);
@@ -2406,11 +2601,12 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* so we had to force link. In this case, we need to force the
* configuration of the MAC to match the "fc" parameter.
*/
- if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
- ((hw->media_type == e1000_media_type_internal_serdes) && (hw->autoneg_failed)) ||
- ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+ if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+ ((hw->media_type == e1000_media_type_internal_serdes) &&
+ (hw->autoneg_failed)) ||
+ ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
ret_val = e1000_force_mac_fc(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
return ret_val;
}
@@ -2421,19 +2617,19 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* has completed, and if so, how the PHY and link partner has
* flow control configured.
*/
- if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+ if ((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
/* Read the MII Status Register and check to see if AutoNeg
* has completed. We read this twice because this reg has
* some "sticky" (latched) bits.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+ if (mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
/* The AutoNeg process has completed, so we now need to
* read both the Auto Negotiation Advertisement Register
* (Address 4) and the Auto_Negotiation Base Page Ability
@@ -2442,11 +2638,11 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
*/
ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_ADV,
&mii_nway_adv_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY,
&mii_nway_lp_ability_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Two bits in the Auto Negotiation Advertisement Register
@@ -2483,15 +2679,15 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* 1 | DC | 1 | DC | e1000_fc_full
*
*/
- if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+ if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
/* Now we need to check if the user selected RX ONLY
* of pause frames. In this case, we had to advertise
* FULL flow control because we could not advertise RX
* ONLY. Hence, we must now check to see if we need to
* turn OFF the TRANSMISSION of PAUSE frames.
*/
- if(hw->original_fc == e1000_fc_full) {
+ if (hw->original_fc == e1000_fc_full) {
hw->fc = e1000_fc_full;
DEBUGOUT("Flow Control = FULL.\n");
} else {
@@ -2507,10 +2703,10 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* 0 | 1 | 1 | 1 | e1000_fc_tx_pause
*
*/
- else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc = e1000_fc_tx_pause;
DEBUGOUT("Flow Control = TX PAUSE frames only.\n");
}
@@ -2522,10 +2718,10 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* 1 | 1 | 0 | 1 | e1000_fc_rx_pause
*
*/
- else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
- (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
- !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
- (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+ else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+ (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+ !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+ (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
hw->fc = e1000_fc_rx_pause;
DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
@@ -2549,9 +2745,9 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
- else if((hw->original_fc == e1000_fc_none ||
- hw->original_fc == e1000_fc_tx_pause) ||
- hw->fc_strict_ieee) {
+ else if ((hw->original_fc == e1000_fc_none ||
+ hw->original_fc == e1000_fc_tx_pause) ||
+ hw->fc_strict_ieee) {
hw->fc = e1000_fc_none;
DEBUGOUT("Flow Control = NONE.\n");
} else {
@@ -2564,19 +2760,19 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* enabled per IEEE 802.3 spec.
*/
ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error getting link speed and duplex\n");
return ret_val;
}
- if(duplex == HALF_DUPLEX)
+ if (duplex == HALF_DUPLEX)
hw->fc = e1000_fc_none;
/* Now we call a subroutine to actually force the MAC
* controller to use the correct flow control settings.
*/
ret_val = e1000_force_mac_fc(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error forcing flow control settings\n");
return ret_val;
}
@@ -2615,13 +2811,13 @@ e1000_check_for_link(struct e1000_hw *hw)
* set when the optics detect a signal. On older adapters, it will be
* cleared when there is a signal. This applies to fiber media only.
*/
- if((hw->media_type == e1000_media_type_fiber) ||
- (hw->media_type == e1000_media_type_internal_serdes)) {
+ if ((hw->media_type == e1000_media_type_fiber) ||
+ (hw->media_type == e1000_media_type_internal_serdes)) {
rxcw = E1000_READ_REG(hw, RXCW);
- if(hw->media_type == e1000_media_type_fiber) {
+ if (hw->media_type == e1000_media_type_fiber) {
signal = (hw->mac_type > e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
- if(status & E1000_STATUS_LU)
+ if (status & E1000_STATUS_LU)
hw->get_link_status = FALSE;
}
}
@@ -2632,20 +2828,20 @@ e1000_check_for_link(struct e1000_hw *hw)
* receive a Link Status Change interrupt or we have Rx Sequence
* Errors.
*/
- if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+ if ((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
/* First we want to see if the MII Status Register reports
* link. If so, then we want to get the current speed/duplex
* of the PHY.
* Read the register twice since the link bit is sticky.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(phy_data & MII_SR_LINK_STATUS) {
+ if (phy_data & MII_SR_LINK_STATUS) {
hw->get_link_status = FALSE;
/* Check if there was DownShift, must be checked immediately after
* link-up */
@@ -2659,10 +2855,10 @@ e1000_check_for_link(struct e1000_hw *hw)
* happen due to the execution of this workaround.
*/
- if((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
- (!hw->autoneg) &&
- (hw->forced_speed_duplex == e1000_10_full ||
- hw->forced_speed_duplex == e1000_10_half)) {
+ if ((hw->mac_type == e1000_82544 || hw->mac_type == e1000_82543) &&
+ (!hw->autoneg) &&
+ (hw->forced_speed_duplex == e1000_10_full ||
+ hw->forced_speed_duplex == e1000_10_half)) {
E1000_WRITE_REG(hw, IMC, 0xffffffff);
ret_val = e1000_polarity_reversal_workaround(hw);
icr = E1000_READ_REG(hw, ICR);
@@ -2679,7 +2875,7 @@ e1000_check_for_link(struct e1000_hw *hw)
/* If we are forcing speed/duplex, then we simply return since
* we have already determined whether we have link or not.
*/
- if(!hw->autoneg) return -E1000_ERR_CONFIG;
+ if (!hw->autoneg) return -E1000_ERR_CONFIG;
/* optimize the dsp settings for the igp phy */
e1000_config_dsp_after_link_change(hw, TRUE);
@@ -2692,11 +2888,11 @@ e1000_check_for_link(struct e1000_hw *hw)
* speed/duplex on the MAC to the current PHY speed/duplex
* settings.
*/
- if(hw->mac_type >= e1000_82544)
+ if (hw->mac_type >= e1000_82544)
e1000_config_collision_dist(hw);
else {
ret_val = e1000_config_mac_to_phy(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error configuring MAC to PHY settings\n");
return ret_val;
}
@@ -2707,7 +2903,7 @@ e1000_check_for_link(struct e1000_hw *hw)
* have had to re-autoneg with a different link partner.
*/
ret_val = e1000_config_fc_after_link_up(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error configuring flow control\n");
return ret_val;
}
@@ -2719,14 +2915,18 @@ e1000_check_for_link(struct e1000_hw *hw)
* at gigabit speed, then TBI compatibility is not needed. If we are
* at gigabit speed, we turn on TBI compatibility.
*/
- if(hw->tbi_compatibility_en) {
+ if (hw->tbi_compatibility_en) {
uint16_t speed, duplex;
- e1000_get_speed_and_duplex(hw, &speed, &duplex);
- if(speed != SPEED_1000) {
+ ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
+ if (ret_val) {
+ DEBUGOUT("Error getting link speed and duplex\n");
+ return ret_val;
+ }
+ if (speed != SPEED_1000) {
/* If link speed is not set to gigabit speed, we do not need
* to enable TBI compatibility.
*/
- if(hw->tbi_compatibility_on) {
+ if (hw->tbi_compatibility_on) {
/* If we previously were in the mode, turn it off. */
rctl = E1000_READ_REG(hw, RCTL);
rctl &= ~E1000_RCTL_SBP;
@@ -2739,7 +2939,7 @@ e1000_check_for_link(struct e1000_hw *hw)
* packets. Some frames have an additional byte on the end and
* will look like CRC errors to to the hardware.
*/
- if(!hw->tbi_compatibility_on) {
+ if (!hw->tbi_compatibility_on) {
hw->tbi_compatibility_on = TRUE;
rctl = E1000_READ_REG(hw, RCTL);
rctl |= E1000_RCTL_SBP;
@@ -2755,12 +2955,12 @@ e1000_check_for_link(struct e1000_hw *hw)
* auto-negotiation time to complete, in case the cable was just plugged
* in. The autoneg_failed flag does this.
*/
- else if((((hw->media_type == e1000_media_type_fiber) &&
+ else if ((((hw->media_type == e1000_media_type_fiber) &&
((ctrl & E1000_CTRL_SWDPIN1) == signal)) ||
- (hw->media_type == e1000_media_type_internal_serdes)) &&
- (!(status & E1000_STATUS_LU)) &&
- (!(rxcw & E1000_RXCW_C))) {
- if(hw->autoneg_failed == 0) {
+ (hw->media_type == e1000_media_type_internal_serdes)) &&
+ (!(status & E1000_STATUS_LU)) &&
+ (!(rxcw & E1000_RXCW_C))) {
+ if (hw->autoneg_failed == 0) {
hw->autoneg_failed = 1;
return 0;
}
@@ -2776,7 +2976,7 @@ e1000_check_for_link(struct e1000_hw *hw)
/* Configure Flow Control after forcing link up. */
ret_val = e1000_config_fc_after_link_up(hw);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error configuring flow control\n");
return ret_val;
}
@@ -2786,9 +2986,9 @@ e1000_check_for_link(struct e1000_hw *hw)
* Device Control register in an attempt to auto-negotiate with our link
* partner.
*/
- else if(((hw->media_type == e1000_media_type_fiber) ||
- (hw->media_type == e1000_media_type_internal_serdes)) &&
- (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
+ else if (((hw->media_type == e1000_media_type_fiber) ||
+ (hw->media_type == e1000_media_type_internal_serdes)) &&
+ (ctrl & E1000_CTRL_SLU) && (rxcw & E1000_RXCW_C)) {
DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\n");
E1000_WRITE_REG(hw, TXCW, hw->txcw);
E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
@@ -2798,12 +2998,12 @@ e1000_check_for_link(struct e1000_hw *hw)
/* If we force link for non-auto-negotiation switch, check link status
* based on MAC synchronization for internal serdes media type.
*/
- else if((hw->media_type == e1000_media_type_internal_serdes) &&
- !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+ else if ((hw->media_type == e1000_media_type_internal_serdes) &&
+ !(E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
/* SYNCH bit and IV bit are sticky. */
udelay(10);
- if(E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) {
- if(!(rxcw & E1000_RXCW_IV)) {
+ if (E1000_RXCW_SYNCH & E1000_READ_REG(hw, RXCW)) {
+ if (!(rxcw & E1000_RXCW_IV)) {
hw->serdes_link_down = FALSE;
DEBUGOUT("SERDES: Link is up.\n");
}
@@ -2812,8 +3012,8 @@ e1000_check_for_link(struct e1000_hw *hw)
DEBUGOUT("SERDES: Link is down.\n");
}
}
- if((hw->media_type == e1000_media_type_internal_serdes) &&
- (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
+ if ((hw->media_type == e1000_media_type_internal_serdes) &&
+ (E1000_TXCW_ANE & E1000_READ_REG(hw, TXCW))) {
hw->serdes_link_down = !(E1000_STATUS_LU & E1000_READ_REG(hw, STATUS));
}
return E1000_SUCCESS;
@@ -2837,12 +3037,12 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
DEBUGFUNC("e1000_get_speed_and_duplex");
- if(hw->mac_type >= e1000_82543) {
+ if (hw->mac_type >= e1000_82543) {
status = E1000_READ_REG(hw, STATUS);
- if(status & E1000_STATUS_SPEED_1000) {
+ if (status & E1000_STATUS_SPEED_1000) {
*speed = SPEED_1000;
DEBUGOUT("1000 Mbs, ");
- } else if(status & E1000_STATUS_SPEED_100) {
+ } else if (status & E1000_STATUS_SPEED_100) {
*speed = SPEED_100;
DEBUGOUT("100 Mbs, ");
} else {
@@ -2850,7 +3050,7 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
DEBUGOUT("10 Mbs, ");
}
- if(status & E1000_STATUS_FD) {
+ if (status & E1000_STATUS_FD) {
*duplex = FULL_DUPLEX;
DEBUGOUT("Full Duplex\n");
} else {
@@ -2867,18 +3067,18 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
* if it is operating at half duplex. Here we set the duplex settings to
* match the duplex in the link partner's capabilities.
*/
- if(hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
+ if (hw->phy_type == e1000_phy_igp && hw->speed_downgraded) {
ret_val = e1000_read_phy_reg(hw, PHY_AUTONEG_EXP, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(!(phy_data & NWAY_ER_LP_NWAY_CAPS))
+ if (!(phy_data & NWAY_ER_LP_NWAY_CAPS))
*duplex = HALF_DUPLEX;
else {
ret_val = e1000_read_phy_reg(hw, PHY_LP_ABILITY, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
+ if ((*speed == SPEED_100 && !(phy_data & NWAY_LPAR_100TX_FD_CAPS)) ||
(*speed == SPEED_10 && !(phy_data & NWAY_LPAR_10T_FD_CAPS)))
*duplex = HALF_DUPLEX;
}
@@ -2889,7 +3089,13 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw,
if (*speed == SPEED_1000)
ret_val = e1000_configure_kmrn_for_1000(hw);
else
- ret_val = e1000_configure_kmrn_for_10_100(hw);
+ ret_val = e1000_configure_kmrn_for_10_100(hw, *duplex);
+ if (ret_val)
+ return ret_val;
+ }
+
+ if ((hw->phy_type == e1000_phy_igp_3) && (*speed == SPEED_1000)) {
+ ret_val = e1000_kumeran_lock_loss_workaround(hw);
if (ret_val)
return ret_val;
}
@@ -2913,20 +3119,20 @@ e1000_wait_autoneg(struct e1000_hw *hw)
DEBUGOUT("Waiting for Auto-Neg to complete.\n");
/* We will wait for autoneg to complete or 4.5 seconds to expire. */
- for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+ for (i = PHY_AUTO_NEG_TIME; i > 0; i--) {
/* Read the MII Status Register and wait for Auto-Neg
* Complete bit to be set.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+ if (phy_data & MII_SR_AUTONEG_COMPLETE) {
return E1000_SUCCESS;
}
- msec_delay(100);
+ msleep(100);
}
return E1000_SUCCESS;
}
@@ -2996,14 +3202,16 @@ e1000_shift_out_mdi_bits(struct e1000_hw *hw,
/* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
- while(mask) {
+ while (mask) {
/* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
* then raising and lowering the Management Data Clock. A "0" is
* shifted out to the PHY by setting the MDIO bit to "0" and then
* raising and lowering the clock.
*/
- if(data & mask) ctrl |= E1000_CTRL_MDIO;
- else ctrl &= ~E1000_CTRL_MDIO;
+ if (data & mask)
+ ctrl |= E1000_CTRL_MDIO;
+ else
+ ctrl &= ~E1000_CTRL_MDIO;
E1000_WRITE_REG(hw, CTRL, ctrl);
E1000_WRITE_FLUSH(hw);
@@ -3054,12 +3262,13 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw)
e1000_raise_mdi_clk(hw, &ctrl);
e1000_lower_mdi_clk(hw, &ctrl);
- for(data = 0, i = 0; i < 16; i++) {
+ for (data = 0, i = 0; i < 16; i++) {
data = data << 1;
e1000_raise_mdi_clk(hw, &ctrl);
ctrl = E1000_READ_REG(hw, CTRL);
/* Check to see if we shifted in a "1". */
- if(ctrl & E1000_CTRL_MDIO) data |= 1;
+ if (ctrl & E1000_CTRL_MDIO)
+ data |= 1;
e1000_lower_mdi_clk(hw, &ctrl);
}
@@ -3069,7 +3278,7 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw)
return data;
}
-int32_t
+static int32_t
e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
{
uint32_t swfw_sync = 0;
@@ -3079,10 +3288,13 @@ e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
DEBUGFUNC("e1000_swfw_sync_acquire");
+ if (hw->swfwhw_semaphore_present)
+ return e1000_get_software_flag(hw);
+
if (!hw->swfw_sync_present)
return e1000_get_hw_eeprom_semaphore(hw);
- while(timeout) {
+ while (timeout) {
if (e1000_get_hw_eeprom_semaphore(hw))
return -E1000_ERR_SWFW_SYNC;
@@ -3094,7 +3306,7 @@ e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
/* firmware currently using resource (fwmask) */
/* or other software thread currently using resource (swmask) */
e1000_put_hw_eeprom_semaphore(hw);
- msec_delay_irq(5);
+ mdelay(5);
timeout--;
}
@@ -3110,7 +3322,7 @@ e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
return E1000_SUCCESS;
}
-void
+static void
e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask)
{
uint32_t swfw_sync;
@@ -3118,6 +3330,11 @@ e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask)
DEBUGFUNC("e1000_swfw_sync_release");
+ if (hw->swfwhw_semaphore_present) {
+ e1000_release_software_flag(hw);
+ return;
+ }
+
if (!hw->swfw_sync_present) {
e1000_put_hw_eeprom_semaphore(hw);
return;
@@ -3160,12 +3377,13 @@ e1000_read_phy_reg(struct e1000_hw *hw,
if (e1000_swfw_sync_acquire(hw, swfw))
return -E1000_ERR_SWFW_SYNC;
- if((hw->phy_type == e1000_phy_igp ||
+ if ((hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(uint16_t)reg_addr);
- if(ret_val) {
+ if (ret_val) {
e1000_swfw_sync_release(hw, swfw);
return ret_val;
}
@@ -3210,12 +3428,12 @@ e1000_read_phy_reg_ex(struct e1000_hw *hw,
DEBUGFUNC("e1000_read_phy_reg_ex");
- if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ if (reg_addr > MAX_PHY_REG_ADDRESS) {
DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
return -E1000_ERR_PARAM;
}
- if(hw->mac_type > e1000_82543) {
+ if (hw->mac_type > e1000_82543) {
/* Set up Op-code, Phy Address, and register address in the MDI
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
@@ -3227,16 +3445,16 @@ e1000_read_phy_reg_ex(struct e1000_hw *hw,
E1000_WRITE_REG(hw, MDIC, mdic);
/* Poll the ready bit to see if the MDI read completed */
- for(i = 0; i < 64; i++) {
+ for (i = 0; i < 64; i++) {
udelay(50);
mdic = E1000_READ_REG(hw, MDIC);
- if(mdic & E1000_MDIC_READY) break;
+ if (mdic & E1000_MDIC_READY) break;
}
- if(!(mdic & E1000_MDIC_READY)) {
+ if (!(mdic & E1000_MDIC_READY)) {
DEBUGOUT("MDI Read did not complete\n");
return -E1000_ERR_PHY;
}
- if(mdic & E1000_MDIC_ERROR) {
+ if (mdic & E1000_MDIC_ERROR) {
DEBUGOUT("MDI Error\n");
return -E1000_ERR_PHY;
}
@@ -3299,12 +3517,13 @@ e1000_write_phy_reg(struct e1000_hw *hw,
if (e1000_swfw_sync_acquire(hw, swfw))
return -E1000_ERR_SWFW_SYNC;
- if((hw->phy_type == e1000_phy_igp ||
+ if ((hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) &&
(reg_addr > MAX_PHY_MULTI_PAGE_REG)) {
ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT,
(uint16_t)reg_addr);
- if(ret_val) {
+ if (ret_val) {
e1000_swfw_sync_release(hw, swfw);
return ret_val;
}
@@ -3349,12 +3568,12 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw,
DEBUGFUNC("e1000_write_phy_reg_ex");
- if(reg_addr > MAX_PHY_REG_ADDRESS) {
+ if (reg_addr > MAX_PHY_REG_ADDRESS) {
DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
return -E1000_ERR_PARAM;
}
- if(hw->mac_type > e1000_82543) {
+ if (hw->mac_type > e1000_82543) {
/* Set up Op-code, Phy Address, register address, and data intended
* for the PHY register in the MDI Control register. The MAC will take
* care of interfacing with the PHY to send the desired data.
@@ -3367,12 +3586,12 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw,
E1000_WRITE_REG(hw, MDIC, mdic);
/* Poll the ready bit to see if the MDI read completed */
- for(i = 0; i < 640; i++) {
+ for (i = 0; i < 641; i++) {
udelay(5);
mdic = E1000_READ_REG(hw, MDIC);
- if(mdic & E1000_MDIC_READY) break;
+ if (mdic & E1000_MDIC_READY) break;
}
- if(!(mdic & E1000_MDIC_READY)) {
+ if (!(mdic & E1000_MDIC_READY)) {
DEBUGOUT("MDI Write did not complete\n");
return -E1000_ERR_PHY;
}
@@ -3401,7 +3620,7 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw,
return E1000_SUCCESS;
}
-int32_t
+static int32_t
e1000_read_kmrn_reg(struct e1000_hw *hw,
uint32_t reg_addr,
uint16_t *data)
@@ -3434,7 +3653,7 @@ e1000_read_kmrn_reg(struct e1000_hw *hw,
return E1000_SUCCESS;
}
-int32_t
+static int32_t
e1000_write_kmrn_reg(struct e1000_hw *hw,
uint32_t reg_addr,
uint16_t data)
@@ -3484,7 +3703,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
DEBUGOUT("Resetting Phy...\n");
- if(hw->mac_type > e1000_82543) {
+ if (hw->mac_type > e1000_82543) {
if ((hw->mac_type == e1000_80003es2lan) &&
(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
swfw = E1000_SWFW_PHY1_SM;
@@ -3506,7 +3725,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
if (hw->mac_type < e1000_82571)
- msec_delay(10);
+ msleep(10);
else
udelay(100);
@@ -3514,7 +3733,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
if (hw->mac_type >= e1000_82571)
- msec_delay(10);
+ mdelay(10);
e1000_swfw_sync_release(hw, swfw);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
@@ -3525,14 +3744,14 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
- msec_delay(10);
+ msleep(10);
ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
E1000_WRITE_FLUSH(hw);
}
udelay(150);
- if((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
+ if ((hw->mac_type == e1000_82541) || (hw->mac_type == e1000_82547)) {
/* Configure activity LED after PHY reset */
led_ctrl = E1000_READ_REG(hw, LEDCTL);
led_ctrl &= IGP_ACTIVITY_LED_MASK;
@@ -3542,8 +3761,13 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
/* Wait for FW to finish PHY configuration. */
ret_val = e1000_get_phy_cfg_done(hw);
+ if (ret_val != E1000_SUCCESS)
+ return ret_val;
e1000_release_software_semaphore(hw);
+ if ((hw->mac_type == e1000_ich8lan) && (hw->phy_type == e1000_phy_igp_3))
+ ret_val = e1000_init_lcd_from_nvm(hw);
+
return ret_val;
}
@@ -3572,36 +3796,147 @@ e1000_phy_reset(struct e1000_hw *hw)
case e1000_82541_rev_2:
case e1000_82571:
case e1000_82572:
+ case e1000_ich8lan:
ret_val = e1000_phy_hw_reset(hw);
- if(ret_val)
+ if (ret_val)
return ret_val;
+
break;
default:
ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= MII_CR_RESET;
ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
udelay(1);
break;
}
- if(hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
+ if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2)
e1000_phy_init_script(hw);
return E1000_SUCCESS;
}
/******************************************************************************
+* Work-around for 82566 power-down: on D3 entry-
+* 1) disable gigabit link
+* 2) write VR power-down enable
+* 3) read it back
+* if successful continue, else issue LCD reset and repeat
+*
+* hw - struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_powerdown_workaround(struct e1000_hw *hw)
+{
+ int32_t reg;
+ uint16_t phy_data;
+ int32_t retry = 0;
+
+ DEBUGFUNC("e1000_phy_powerdown_workaround");
+
+ if (hw->phy_type != e1000_phy_igp_3)
+ return;
+
+ do {
+ /* Disable link */
+ reg = E1000_READ_REG(hw, PHY_CTRL);
+ E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+
+ /* Write VR power-down enable */
+ e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data);
+ e1000_write_phy_reg(hw, IGP3_VR_CTRL, phy_data |
+ IGP3_VR_CTRL_MODE_SHUT);
+
+ /* Read it back and test */
+ e1000_read_phy_reg(hw, IGP3_VR_CTRL, &phy_data);
+ if ((phy_data & IGP3_VR_CTRL_MODE_SHUT) || retry)
+ break;
+
+ /* Issue PHY reset and repeat at most one more time */
+ reg = E1000_READ_REG(hw, CTRL);
+ E1000_WRITE_REG(hw, CTRL, reg | E1000_CTRL_PHY_RST);
+ retry++;
+ } while (retry);
+
+ return;
+
+}
+
+/******************************************************************************
+* Work-around for 82566 Kumeran PCS lock loss:
+* On link status change (i.e. PCI reset, speed change) and link is up and
+* speed is gigabit-
+* 0) if workaround is optionally disabled do nothing
+* 1) wait 1ms for Kumeran link to come up
+* 2) check Kumeran Diagnostic register PCS lock loss bit
+* 3) if not set the link is locked (all is good), otherwise...
+* 4) reset the PHY
+* 5) repeat up to 10 times
+* Note: this is only called for IGP3 copper when speed is 1gb.
+*
+* hw - struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ int32_t reg;
+ int32_t cnt;
+ uint16_t phy_data;
+
+ if (hw->kmrn_lock_loss_workaround_disabled)
+ return E1000_SUCCESS;
+
+ /* Make sure link is up before proceeding. If not just return.
+ * Attempting this while link is negotiating fouled up link
+ * stability */
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+ ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
+
+ if (phy_data & MII_SR_LINK_STATUS) {
+ for (cnt = 0; cnt < 10; cnt++) {
+ /* read once to clear */
+ ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data);
+ if (ret_val)
+ return ret_val;
+ /* and again to get new status */
+ ret_val = e1000_read_phy_reg(hw, IGP3_KMRN_DIAG, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ /* check for PCS lock */
+ if (!(phy_data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS))
+ return E1000_SUCCESS;
+
+ /* Issue PHY reset */
+ e1000_phy_hw_reset(hw);
+ mdelay(5);
+ }
+ /* Disable GigE link negotiation */
+ reg = E1000_READ_REG(hw, PHY_CTRL);
+ E1000_WRITE_REG(hw, PHY_CTRL, reg | E1000_PHY_CTRL_GBE_DISABLE |
+ E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
+
+ /* unable to acquire PCS lock */
+ return E1000_ERR_PHY;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Probes the expected PHY address for known PHY IDs
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-static int32_t
+int32_t
e1000_detect_gig_phy(struct e1000_hw *hw)
{
int32_t phy_init_status, ret_val;
@@ -3613,8 +3948,8 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
/* The 82571 firmware may still be configuring the PHY. In this
* case, we cannot access the PHY until the configuration is done. So
* we explicitly set the PHY values. */
- if(hw->mac_type == e1000_82571 ||
- hw->mac_type == e1000_82572) {
+ if (hw->mac_type == e1000_82571 ||
+ hw->mac_type == e1000_82572) {
hw->phy_id = IGP01E1000_I_PHY_ID;
hw->phy_type = e1000_phy_igp_2;
return E1000_SUCCESS;
@@ -3631,44 +3966,50 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
/* Read the PHY ID Registers to identify which PHY is onboard. */
ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->phy_id = (uint32_t) (phy_id_high << 16);
udelay(20);
ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82543:
- if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
break;
case e1000_82544:
- if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+ if (hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
break;
case e1000_82540:
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
case e1000_82546_rev_3:
- if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+ if (hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
break;
case e1000_82541:
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
- if(hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
+ if (hw->phy_id == IGP01E1000_I_PHY_ID) match = TRUE;
break;
case e1000_82573:
- if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
+ if (hw->phy_id == M88E1111_I_PHY_ID) match = TRUE;
break;
case e1000_80003es2lan:
if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE;
break;
+ case e1000_ich8lan:
+ if (hw->phy_id == IGP03E1000_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == IFE_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == IFE_PLUS_E_PHY_ID) match = TRUE;
+ if (hw->phy_id == IFE_C_E_PHY_ID) match = TRUE;
+ break;
default:
DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
return -E1000_ERR_CONFIG;
@@ -3697,14 +4038,14 @@ e1000_phy_reset_dsp(struct e1000_hw *hw)
do {
if (hw->phy_type != e1000_phy_gg82563) {
ret_val = e1000_write_phy_reg(hw, 29, 0x001d);
- if(ret_val) break;
+ if (ret_val) break;
}
ret_val = e1000_write_phy_reg(hw, 30, 0x00c1);
- if(ret_val) break;
+ if (ret_val) break;
ret_val = e1000_write_phy_reg(hw, 30, 0x0000);
- if(ret_val) break;
+ if (ret_val) break;
ret_val = E1000_SUCCESS;
- } while(0);
+ } while (0);
return ret_val;
}
@@ -3736,23 +4077,23 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
/* Check polarity status */
ret_val = e1000_check_polarity(hw, &polarity);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->cable_polarity = polarity;
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
IGP01E1000_PSSR_MDIX_SHIFT;
- if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
/* Local/Remote Receiver Information are only valid at 1000 Mbps */
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
@@ -3762,19 +4103,19 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
/* Get cable length */
ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Translate to old method */
average = (max_length + min_length) / 2;
- if(average <= e1000_igp_cable_length_50)
+ if (average <= e1000_igp_cable_length_50)
phy_info->cable_length = e1000_cable_length_50;
- else if(average <= e1000_igp_cable_length_80)
+ else if (average <= e1000_igp_cable_length_80)
phy_info->cable_length = e1000_cable_length_50_80;
- else if(average <= e1000_igp_cable_length_110)
+ else if (average <= e1000_igp_cable_length_110)
phy_info->cable_length = e1000_cable_length_80_110;
- else if(average <= e1000_igp_cable_length_140)
+ else if (average <= e1000_igp_cable_length_140)
phy_info->cable_length = e1000_cable_length_110_140;
else
phy_info->cable_length = e1000_cable_length_140;
@@ -3784,6 +4125,53 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
}
/******************************************************************************
+* Get PHY information from various PHY registers for ife PHY only.
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+static int32_t
+e1000_phy_ife_get_info(struct e1000_hw *hw,
+ struct e1000_phy_info *phy_info)
+{
+ int32_t ret_val;
+ uint16_t phy_data, polarity;
+
+ DEBUGFUNC("e1000_phy_ife_get_info");
+
+ phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
+ phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_normal;
+
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+ phy_info->polarity_correction =
+ (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
+ IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT;
+
+ if (phy_info->polarity_correction == e1000_polarity_reversal_enabled) {
+ ret_val = e1000_check_polarity(hw, &polarity);
+ if (ret_val)
+ return ret_val;
+ } else {
+ /* Polarity is forced. */
+ polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >>
+ IFE_PSC_FORCE_POLARITY_SHIFT;
+ }
+ phy_info->cable_polarity = polarity;
+
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_info->mdix_mode =
+ (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
+ IFE_PMC_MDIX_MODE_SHIFT;
+
+ return E1000_SUCCESS;
+}
+
+/******************************************************************************
* Get PHY information from various PHY registers fot m88 PHY only.
*
* hw - Struct containing variables accessed by shared code
@@ -3803,7 +4191,7 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
phy_info->downshift = (e1000_downshift)hw->speed_downgraded;
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->extended_10bt_distance =
@@ -3815,12 +4203,12 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
/* Check polarity status */
ret_val = e1000_check_polarity(hw, &polarity);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->cable_polarity = polarity;
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
@@ -3843,7 +4231,7 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
}
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
@@ -3880,27 +4268,30 @@ e1000_phy_get_info(struct e1000_hw *hw,
phy_info->local_rx = e1000_1000t_rx_status_undefined;
phy_info->remote_rx = e1000_1000t_rx_status_undefined;
- if(hw->media_type != e1000_media_type_copper) {
+ if (hw->media_type != e1000_media_type_copper) {
DEBUGOUT("PHY info is only valid for copper media\n");
return -E1000_ERR_CONFIG;
}
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+ if ((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
DEBUGOUT("PHY info is only valid if link is up\n");
return -E1000_ERR_CONFIG;
}
- if(hw->phy_type == e1000_phy_igp ||
+ if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2)
return e1000_phy_igp_get_info(hw, phy_info);
+ else if (hw->phy_type == e1000_phy_ife)
+ return e1000_phy_ife_get_info(hw, phy_info);
else
return e1000_phy_m88_get_info(hw, phy_info);
}
@@ -3910,7 +4301,7 @@ e1000_validate_mdi_setting(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_validate_mdi_settings");
- if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+ if (!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
DEBUGOUT("Invalid MDI setting detected\n");
hw->mdix = 1;
return -E1000_ERR_CONFIG;
@@ -3957,7 +4348,7 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_microwire;
eeprom->opcode_bits = 3;
eeprom->delay_usec = 50;
- if(eecd & E1000_EECD_SIZE) {
+ if (eecd & E1000_EECD_SIZE) {
eeprom->word_size = 256;
eeprom->address_bits = 8;
} else {
@@ -4025,7 +4416,7 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
}
eeprom->use_eerd = TRUE;
eeprom->use_eewr = TRUE;
- if(e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
+ if (e1000_is_onboard_nvm_eeprom(hw) == FALSE) {
eeprom->type = e1000_eeprom_flash;
eeprom->word_size = 2048;
@@ -4049,6 +4440,35 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->use_eerd = TRUE;
eeprom->use_eewr = FALSE;
break;
+ case e1000_ich8lan:
+ {
+ int32_t i = 0;
+ uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG);
+
+ eeprom->type = e1000_eeprom_ich8;
+ eeprom->use_eerd = FALSE;
+ eeprom->use_eewr = FALSE;
+ eeprom->word_size = E1000_SHADOW_RAM_WORDS;
+
+ /* Zero the shadow RAM structure. But don't load it from NVM
+ * so as to save time for driver init */
+ if (hw->eeprom_shadow_ram != NULL) {
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ hw->eeprom_shadow_ram[i].modified = FALSE;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+ }
+
+ hw->flash_base_addr = (flash_size & ICH8_GFPREG_BASE_MASK) *
+ ICH8_FLASH_SECTOR_SIZE;
+
+ hw->flash_bank_size = ((flash_size >> 16) & ICH8_GFPREG_BASE_MASK) + 1;
+ hw->flash_bank_size -= (flash_size & ICH8_GFPREG_BASE_MASK);
+ hw->flash_bank_size *= ICH8_FLASH_SECTOR_SIZE;
+ hw->flash_bank_size /= 2 * sizeof(uint16_t);
+
+ break;
+ }
default:
break;
}
@@ -4057,17 +4477,17 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
/* eeprom_size will be an enum [0..8] that maps to eeprom sizes 128B to
* 32KB (incremented by powers of 2).
*/
- if(hw->mac_type <= e1000_82547_rev_2) {
+ if (hw->mac_type <= e1000_82547_rev_2) {
/* Set to default value for initial eeprom read. */
eeprom->word_size = 64;
ret_val = e1000_read_eeprom(hw, EEPROM_CFG, 1, &eeprom_size);
- if(ret_val)
+ if (ret_val)
return ret_val;
eeprom_size = (eeprom_size & EEPROM_SIZE_MASK) >> EEPROM_SIZE_SHIFT;
/* 256B eeprom size was not supported in earlier hardware, so we
* bump eeprom_size up one to ensure that "1" (which maps to 256B)
* is never the result used in the shifting logic below. */
- if(eeprom_size)
+ if (eeprom_size)
eeprom_size++;
} else {
eeprom_size = (uint16_t)((eecd & E1000_EECD_SIZE_EX_MASK) >>
@@ -4152,7 +4572,7 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw,
*/
eecd &= ~E1000_EECD_DI;
- if(data & mask)
+ if (data & mask)
eecd |= E1000_EECD_DI;
E1000_WRITE_REG(hw, EECD, eecd);
@@ -4165,7 +4585,7 @@ e1000_shift_out_ee_bits(struct e1000_hw *hw,
mask = mask >> 1;
- } while(mask);
+ } while (mask);
/* We leave the "DI" bit set to "0" when we leave this routine. */
eecd &= ~E1000_EECD_DI;
@@ -4197,14 +4617,14 @@ e1000_shift_in_ee_bits(struct e1000_hw *hw,
eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
data = 0;
- for(i = 0; i < count; i++) {
+ for (i = 0; i < count; i++) {
data = data << 1;
e1000_raise_ee_clk(hw, &eecd);
eecd = E1000_READ_REG(hw, EECD);
eecd &= ~(E1000_EECD_DI);
- if(eecd & E1000_EECD_DO)
+ if (eecd & E1000_EECD_DO)
data |= 1;
e1000_lower_ee_clk(hw, &eecd);
@@ -4235,17 +4655,17 @@ e1000_acquire_eeprom(struct e1000_hw *hw)
if (hw->mac_type != e1000_82573) {
/* Request EEPROM Access */
- if(hw->mac_type > e1000_82544) {
+ if (hw->mac_type > e1000_82544) {
eecd |= E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
eecd = E1000_READ_REG(hw, EECD);
- while((!(eecd & E1000_EECD_GNT)) &&
+ while ((!(eecd & E1000_EECD_GNT)) &&
(i < E1000_EEPROM_GRANT_ATTEMPTS)) {
i++;
udelay(5);
eecd = E1000_READ_REG(hw, EECD);
}
- if(!(eecd & E1000_EECD_GNT)) {
+ if (!(eecd & E1000_EECD_GNT)) {
eecd &= ~E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
DEBUGOUT("Could not acquire EEPROM grant\n");
@@ -4288,7 +4708,7 @@ e1000_standby_eeprom(struct e1000_hw *hw)
eecd = E1000_READ_REG(hw, EECD);
- if(eeprom->type == e1000_eeprom_microwire) {
+ if (eeprom->type == e1000_eeprom_microwire) {
eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
E1000_WRITE_REG(hw, EECD, eecd);
E1000_WRITE_FLUSH(hw);
@@ -4311,7 +4731,7 @@ e1000_standby_eeprom(struct e1000_hw *hw)
E1000_WRITE_REG(hw, EECD, eecd);
E1000_WRITE_FLUSH(hw);
udelay(eeprom->delay_usec);
- } else if(eeprom->type == e1000_eeprom_spi) {
+ } else if (eeprom->type == e1000_eeprom_spi) {
/* Toggle CS to flush commands */
eecd |= E1000_EECD_CS;
E1000_WRITE_REG(hw, EECD, eecd);
@@ -4345,7 +4765,7 @@ e1000_release_eeprom(struct e1000_hw *hw)
E1000_WRITE_REG(hw, EECD, eecd);
udelay(hw->eeprom.delay_usec);
- } else if(hw->eeprom.type == e1000_eeprom_microwire) {
+ } else if (hw->eeprom.type == e1000_eeprom_microwire) {
/* cleanup eeprom */
/* CS on Microwire is active-high */
@@ -4367,7 +4787,7 @@ e1000_release_eeprom(struct e1000_hw *hw)
}
/* Stop requesting EEPROM access */
- if(hw->mac_type > e1000_82544) {
+ if (hw->mac_type > e1000_82544) {
eecd &= ~E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
}
@@ -4405,12 +4825,12 @@ e1000_spi_eeprom_ready(struct e1000_hw *hw)
retry_count += 5;
e1000_standby_eeprom(hw);
- } while(retry_count < EEPROM_MAX_RETRY_SPI);
+ } while (retry_count < EEPROM_MAX_RETRY_SPI);
/* ATMEL SPI write time could vary from 0-20mSec on 3.3V devices (and
* only 0-5mSec on 5V devices)
*/
- if(retry_count >= EEPROM_MAX_RETRY_SPI) {
+ if (retry_count >= EEPROM_MAX_RETRY_SPI) {
DEBUGOUT("SPI EEPROM Status error\n");
return -E1000_ERR_EEPROM;
}
@@ -4441,7 +4861,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
/* A check for invalid values: offset too large, too many words, and not
* enough words.
*/
- if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
(words == 0)) {
DEBUGOUT("\"words\" parameter out of bounds\n");
return -E1000_ERR_EEPROM;
@@ -4449,7 +4869,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
/* FLASH reads without acquiring the semaphore are safe */
if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
- hw->eeprom.use_eerd == FALSE) {
+ hw->eeprom.use_eerd == FALSE) {
switch (hw->mac_type) {
case e1000_80003es2lan:
break;
@@ -4469,11 +4889,14 @@ e1000_read_eeprom(struct e1000_hw *hw,
return ret_val;
}
- if(eeprom->type == e1000_eeprom_spi) {
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_read_eeprom_ich8(hw, offset, words, data);
+
+ if (eeprom->type == e1000_eeprom_spi) {
uint16_t word_in;
uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
- if(e1000_spi_eeprom_ready(hw)) {
+ if (e1000_spi_eeprom_ready(hw)) {
e1000_release_eeprom(hw);
return -E1000_ERR_EEPROM;
}
@@ -4481,7 +4904,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
e1000_standby_eeprom(hw);
/* Some SPI eeproms use the 8th address bit embedded in the opcode */
- if((eeprom->address_bits == 8) && (offset >= 128))
+ if ((eeprom->address_bits == 8) && (offset >= 128))
read_opcode |= EEPROM_A8_OPCODE_SPI;
/* Send the READ command (opcode + addr) */
@@ -4497,7 +4920,7 @@ e1000_read_eeprom(struct e1000_hw *hw,
word_in = e1000_shift_in_ee_bits(hw, 16);
data[i] = (word_in >> 8) | (word_in << 8);
}
- } else if(eeprom->type == e1000_eeprom_microwire) {
+ } else if (eeprom->type == e1000_eeprom_microwire) {
for (i = 0; i < words; i++) {
/* Send the READ command (opcode + addr) */
e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE_MICROWIRE,
@@ -4542,7 +4965,7 @@ e1000_read_eeprom_eerd(struct e1000_hw *hw,
E1000_WRITE_REG(hw, EERD, eerd);
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
- if(error) {
+ if (error) {
break;
}
data[i] = (E1000_READ_REG(hw, EERD) >> E1000_EEPROM_RW_REG_DATA);
@@ -4579,7 +5002,7 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw,
E1000_EEPROM_RW_REG_START;
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
- if(error) {
+ if (error) {
break;
}
@@ -4587,7 +5010,7 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw,
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_WRITE);
- if(error) {
+ if (error) {
break;
}
}
@@ -4608,13 +5031,13 @@ e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
uint32_t i, reg = 0;
int32_t done = E1000_ERR_EEPROM;
- for(i = 0; i < attempts; i++) {
- if(eerd == E1000_EEPROM_POLL_READ)
+ for (i = 0; i < attempts; i++) {
+ if (eerd == E1000_EEPROM_POLL_READ)
reg = E1000_READ_REG(hw, EERD);
else
reg = E1000_READ_REG(hw, EEWR);
- if(reg & E1000_EEPROM_RW_REG_DONE) {
+ if (reg & E1000_EEPROM_RW_REG_DONE) {
done = E1000_SUCCESS;
break;
}
@@ -4636,14 +5059,17 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
DEBUGFUNC("e1000_is_onboard_nvm_eeprom");
- if(hw->mac_type == e1000_82573) {
+ if (hw->mac_type == e1000_ich8lan)
+ return FALSE;
+
+ if (hw->mac_type == e1000_82573) {
eecd = E1000_READ_REG(hw, EECD);
/* Isolate bits 15 & 16 */
eecd = ((eecd >> 15) & 0x03);
/* If both bits are set, device is Flash type */
- if(eecd == 0x03) {
+ if (eecd == 0x03) {
return FALSE;
}
}
@@ -4686,15 +5112,29 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw)
}
}
- for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
- if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ if (hw->mac_type == e1000_ich8lan) {
+ /* Drivers must allocate the shadow ram structure for the
+ * EEPROM checksum to be updated. Otherwise, this bit as well
+ * as the checksum must both be set correctly for this
+ * validation to pass.
+ */
+ e1000_read_eeprom(hw, 0x19, 1, &eeprom_data);
+ if ((eeprom_data & 0x40) == 0) {
+ eeprom_data |= 0x40;
+ e1000_write_eeprom(hw, 0x19, 1, &eeprom_data);
+ e1000_update_eeprom_checksum(hw);
+ }
+ }
+
+ for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+ if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
checksum += eeprom_data;
}
- if(checksum == (uint16_t) EEPROM_SUM)
+ if (checksum == (uint16_t) EEPROM_SUM)
return E1000_SUCCESS;
else {
DEBUGOUT("EEPROM Checksum Invalid\n");
@@ -4713,24 +5153,33 @@ e1000_validate_eeprom_checksum(struct e1000_hw *hw)
int32_t
e1000_update_eeprom_checksum(struct e1000_hw *hw)
{
+ uint32_t ctrl_ext;
uint16_t checksum = 0;
uint16_t i, eeprom_data;
DEBUGFUNC("e1000_update_eeprom_checksum");
- for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
- if(e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
+ for (i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+ if (e1000_read_eeprom(hw, i, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
checksum += eeprom_data;
}
checksum = (uint16_t) EEPROM_SUM - checksum;
- if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
+ if (e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, 1, &checksum) < 0) {
DEBUGOUT("EEPROM Write Error\n");
return -E1000_ERR_EEPROM;
} else if (hw->eeprom.type == e1000_eeprom_flash) {
e1000_commit_shadow_ram(hw);
+ } else if (hw->eeprom.type == e1000_eeprom_ich8) {
+ e1000_commit_shadow_ram(hw);
+ /* Reload the EEPROM, or else modifications will not appear
+ * until after next adapter reset. */
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ msleep(10);
}
return E1000_SUCCESS;
}
@@ -4760,25 +5209,28 @@ e1000_write_eeprom(struct e1000_hw *hw,
/* A check for invalid values: offset too large, too many words, and not
* enough words.
*/
- if((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
+ if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
(words == 0)) {
DEBUGOUT("\"words\" parameter out of bounds\n");
return -E1000_ERR_EEPROM;
}
/* 82573 writes only through eewr */
- if(eeprom->use_eewr == TRUE)
+ if (eeprom->use_eewr == TRUE)
return e1000_write_eeprom_eewr(hw, offset, words, data);
+ if (eeprom->type == e1000_eeprom_ich8)
+ return e1000_write_eeprom_ich8(hw, offset, words, data);
+
/* Prepare the EEPROM for writing */
if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
return -E1000_ERR_EEPROM;
- if(eeprom->type == e1000_eeprom_microwire) {
+ if (eeprom->type == e1000_eeprom_microwire) {
status = e1000_write_eeprom_microwire(hw, offset, words, data);
} else {
status = e1000_write_eeprom_spi(hw, offset, words, data);
- msec_delay(10);
+ msleep(10);
}
/* Done with writing */
@@ -4810,7 +5262,7 @@ e1000_write_eeprom_spi(struct e1000_hw *hw,
while (widx < words) {
uint8_t write_opcode = EEPROM_WRITE_OPCODE_SPI;
- if(e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
+ if (e1000_spi_eeprom_ready(hw)) return -E1000_ERR_EEPROM;
e1000_standby_eeprom(hw);
@@ -4821,7 +5273,7 @@ e1000_write_eeprom_spi(struct e1000_hw *hw,
e1000_standby_eeprom(hw);
/* Some SPI eeproms use the 8th address bit embedded in the opcode */
- if((eeprom->address_bits == 8) && (offset >= 128))
+ if ((eeprom->address_bits == 8) && (offset >= 128))
write_opcode |= EEPROM_A8_OPCODE_SPI;
/* Send the Write command (8-bit opcode + addr) */
@@ -4843,7 +5295,7 @@ e1000_write_eeprom_spi(struct e1000_hw *hw,
* operation, while the smaller eeproms are capable of an 8-byte
* PAGE WRITE operation. Break the inner loop to pass new address
*/
- if((((offset + widx)*2) % eeprom->page_size) == 0) {
+ if ((((offset + widx)*2) % eeprom->page_size) == 0) {
e1000_standby_eeprom(hw);
break;
}
@@ -4909,12 +5361,12 @@ e1000_write_eeprom_microwire(struct e1000_hw *hw,
* signal that the command has been completed by raising the DO signal.
* If DO does not go high in 10 milliseconds, then error out.
*/
- for(i = 0; i < 200; i++) {
+ for (i = 0; i < 200; i++) {
eecd = E1000_READ_REG(hw, EECD);
- if(eecd & E1000_EECD_DO) break;
+ if (eecd & E1000_EECD_DO) break;
udelay(50);
}
- if(i == 200) {
+ if (i == 200) {
DEBUGOUT("EEPROM Write did not complete\n");
return -E1000_ERR_EEPROM;
}
@@ -4957,11 +5409,17 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
uint32_t flop = 0;
uint32_t i = 0;
int32_t error = E1000_SUCCESS;
-
- /* The flop register will be used to determine if flash type is STM */
- flop = E1000_READ_REG(hw, FLOP);
+ uint32_t old_bank_offset = 0;
+ uint32_t new_bank_offset = 0;
+ uint32_t sector_retries = 0;
+ uint8_t low_byte = 0;
+ uint8_t high_byte = 0;
+ uint8_t temp_byte = 0;
+ boolean_t sector_write_failed = FALSE;
if (hw->mac_type == e1000_82573) {
+ /* The flop register will be used to determine if flash type is STM */
+ flop = E1000_READ_REG(hw, FLOP);
for (i=0; i < attempts; i++) {
eecd = E1000_READ_REG(hw, EECD);
if ((eecd & E1000_EECD_FLUPD) == 0) {
@@ -4995,41 +5453,107 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
}
}
- return error;
-}
-
-/******************************************************************************
- * Reads the adapter's part number from the EEPROM
- *
- * hw - Struct containing variables accessed by shared code
- * part_num - Adapter's part number
- *****************************************************************************/
-int32_t
-e1000_read_part_num(struct e1000_hw *hw,
- uint32_t *part_num)
-{
- uint16_t offset = EEPROM_PBA_BYTE_1;
- uint16_t eeprom_data;
+ if (hw->mac_type == e1000_ich8lan && hw->eeprom_shadow_ram != NULL) {
+ /* We're writing to the opposite bank so if we're on bank 1,
+ * write to bank 0 etc. We also need to erase the segment that
+ * is going to be written */
+ if (!(E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL)) {
+ new_bank_offset = hw->flash_bank_size * 2;
+ old_bank_offset = 0;
+ e1000_erase_ich8_4k_segment(hw, 1);
+ } else {
+ old_bank_offset = hw->flash_bank_size * 2;
+ new_bank_offset = 0;
+ e1000_erase_ich8_4k_segment(hw, 0);
+ }
- DEBUGFUNC("e1000_read_part_num");
+ do {
+ sector_write_failed = FALSE;
+ /* Loop for every byte in the shadow RAM,
+ * which is in units of words. */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ /* Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM */
+ if (hw->eeprom_shadow_ram[i].modified == TRUE) {
+ low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+ &temp_byte);
+ udelay(100);
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset,
+ low_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ high_byte =
+ (uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8);
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+ &temp_byte);
+ udelay(100);
+ } else {
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+ &low_byte);
+ udelay(100);
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset, low_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
+ &high_byte);
+ }
- /* Get word 0 from EEPROM */
- if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
- DEBUGOUT("EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
- }
- /* Save word 0 in upper half of part_num */
- *part_num = (uint32_t) (eeprom_data << 16);
+ /* If the word is 0x13, then make sure the signature bits
+ * (15:14) are 11b until the commit has completed.
+ * This will allow us to write 10b which indicates the
+ * signature is valid. We want to do this after the write
+ * has completed so that we don't mark the segment valid
+ * while the write is still in progress */
+ if (i == E1000_ICH8_NVM_SIG_WORD)
+ high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte;
+
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset + 1, high_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+
+ if (sector_write_failed == FALSE) {
+ /* Clear the now not used entry in the cache */
+ hw->eeprom_shadow_ram[i].modified = FALSE;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
+ }
+ }
- /* Get word 1 from EEPROM */
- if(e1000_read_eeprom(hw, ++offset, 1, &eeprom_data) < 0) {
- DEBUGOUT("EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
+ /* Don't bother writing the segment valid bits if sector
+ * programming failed. */
+ if (sector_write_failed == FALSE) {
+ /* Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b */
+ e1000_read_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+ &high_byte);
+ high_byte &= 0xBF;
+ error = e1000_verify_write_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+ high_byte);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+
+ /* And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase */
+ error = e1000_verify_write_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset,
+ 0);
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ }
+ } while (++sector_retries < 10 && sector_write_failed == TRUE);
}
- /* Save word 1 in lower half of part_num */
- *part_num |= eeprom_data;
- return E1000_SUCCESS;
+ return error;
}
/******************************************************************************
@@ -5046,9 +5570,9 @@ e1000_read_mac_addr(struct e1000_hw * hw)
DEBUGFUNC("e1000_read_mac_addr");
- for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+ for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
offset = i >> 1;
- if(e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -5063,12 +5587,12 @@ e1000_read_mac_addr(struct e1000_hw * hw)
case e1000_82546_rev_3:
case e1000_82571:
case e1000_80003es2lan:
- if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+ if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
hw->perm_mac_addr[5] ^= 0x01;
break;
}
- for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+ for (i = 0; i < NODE_ADDRESS_SIZE; i++)
hw->mac_addr[i] = hw->perm_mac_addr[i];
return E1000_SUCCESS;
}
@@ -5102,15 +5626,19 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
* the other port. */
if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
rar_num -= 1;
+ if (hw->mac_type == e1000_ich8lan)
+ rar_num = E1000_RAR_ENTRIES_ICH8LAN;
+
/* Zero out the other 15 receive addresses. */
DEBUGOUT("Clearing RAR[1-15]\n");
- for(i = 1; i < rar_num; i++) {
+ for (i = 1; i < rar_num; i++) {
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ E1000_WRITE_FLUSH(hw);
}
}
-#if 0
/******************************************************************************
* Updates the MAC's list of multicast addresses.
*
@@ -5125,6 +5653,7 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
* for the first 15 multicast addresses, and hashes the rest into the
* multicast table.
*****************************************************************************/
+#if 0
void
e1000_mc_addr_list_update(struct e1000_hw *hw,
uint8_t *mc_addr_list,
@@ -5145,26 +5674,33 @@ e1000_mc_addr_list_update(struct e1000_hw *hw,
/* Clear RAR[1-15] */
DEBUGOUT(" Clearing RAR[1-15]\n");
num_rar_entry = E1000_RAR_ENTRIES;
+ if (hw->mac_type == e1000_ich8lan)
+ num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN;
/* Reserve a spot for the Locally Administered Address to work around
* an 82571 issue in which a reset on one port will reload the MAC on
* the other port. */
if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
num_rar_entry -= 1;
- for(i = rar_used_count; i < num_rar_entry; i++) {
+ for (i = rar_used_count; i < num_rar_entry; i++) {
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+ E1000_WRITE_FLUSH(hw);
}
/* Clear the MTA */
DEBUGOUT(" Clearing MTA\n");
num_mta_entry = E1000_NUM_MTA_REGISTERS;
- for(i = 0; i < num_mta_entry; i++) {
+ if (hw->mac_type == e1000_ich8lan)
+ num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN;
+ for (i = 0; i < num_mta_entry; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ E1000_WRITE_FLUSH(hw);
}
/* Add the new addresses */
- for(i = 0; i < mc_addr_count; i++) {
+ for (i = 0; i < mc_addr_count; i++) {
DEBUGOUT(" Adding the multicast addresses:\n");
DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
@@ -5217,24 +5753,46 @@ e1000_hash_mc_addr(struct e1000_hw *hw,
* LSB MSB
*/
case 0:
- /* [47:36] i.e. 0x563 for above example address */
- hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ if (hw->mac_type == e1000_ich8lan) {
+ /* [47:38] i.e. 0x158 for above example address */
+ hash_value = ((mc_addr[4] >> 6) | (((uint16_t) mc_addr[5]) << 2));
+ } else {
+ /* [47:36] i.e. 0x563 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ }
break;
case 1:
- /* [46:35] i.e. 0xAC6 for above example address */
- hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ if (hw->mac_type == e1000_ich8lan) {
+ /* [46:37] i.e. 0x2B1 for above example address */
+ hash_value = ((mc_addr[4] >> 5) | (((uint16_t) mc_addr[5]) << 3));
+ } else {
+ /* [46:35] i.e. 0xAC6 for above example address */
+ hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+ }
break;
case 2:
- /* [45:34] i.e. 0x5D8 for above example address */
- hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ if (hw->mac_type == e1000_ich8lan) {
+ /*[45:36] i.e. 0x163 for above example address */
+ hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+ } else {
+ /* [45:34] i.e. 0x5D8 for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ }
break;
case 3:
- /* [43:32] i.e. 0x634 for above example address */
- hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ if (hw->mac_type == e1000_ich8lan) {
+ /* [43:34] i.e. 0x18D for above example address */
+ hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+ } else {
+ /* [43:32] i.e. 0x634 for above example address */
+ hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+ }
break;
}
hash_value &= 0xFFF;
+ if (hw->mac_type == e1000_ich8lan)
+ hash_value &= 0x3FF;
return hash_value;
}
@@ -5262,6 +5820,8 @@ e1000_mta_set(struct e1000_hw *hw,
* register are determined by the lower 5 bits of the value.
*/
hash_reg = (hash_value >> 5) & 0x7F;
+ if (hw->mac_type == e1000_ich8lan)
+ hash_reg &= 0x1F;
hash_bit = hash_value & 0x1F;
mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
@@ -5272,12 +5832,15 @@ e1000_mta_set(struct e1000_hw *hw,
* in the MTA, save off the previous entry before writing and
* restore the old value after writing.
*/
- if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+ if ((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+ E1000_WRITE_FLUSH(hw);
} else {
E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+ E1000_WRITE_FLUSH(hw);
}
}
@@ -5334,7 +5897,9 @@ e1000_rar_set(struct e1000_hw *hw,
}
E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+ E1000_WRITE_FLUSH(hw);
}
/******************************************************************************
@@ -5351,12 +5916,18 @@ e1000_write_vfta(struct e1000_hw *hw,
{
uint32_t temp;
- if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+ if (hw->mac_type == e1000_ich8lan)
+ return;
+
+ if ((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+ E1000_WRITE_FLUSH(hw);
} else {
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+ E1000_WRITE_FLUSH(hw);
}
}
@@ -5373,6 +5944,9 @@ e1000_clear_vfta(struct e1000_hw *hw)
uint32_t vfta_offset = 0;
uint32_t vfta_bit_in_reg = 0;
+ if (hw->mac_type == e1000_ich8lan)
+ return;
+
if (hw->mac_type == e1000_82573) {
if (hw->mng_cookie.vlan_id != 0) {
/* The VFTA is a 4096b bit-field, each identifying a single VLAN
@@ -5392,6 +5966,7 @@ e1000_clear_vfta(struct e1000_hw *hw)
* manageability unit */
vfta_value = (offset == vfta_offset) ? vfta_bit_in_reg : 0;
E1000_WRITE_REG_ARRAY(hw, VFTA, offset, vfta_value);
+ E1000_WRITE_FLUSH(hw);
}
}
@@ -5407,7 +5982,7 @@ e1000_id_led_init(struct e1000_hw * hw)
DEBUGFUNC("e1000_id_led_init");
- if(hw->mac_type < e1000_82540) {
+ if (hw->mac_type < e1000_82540) {
/* Nothing to do */
return E1000_SUCCESS;
}
@@ -5417,15 +5992,24 @@ e1000_id_led_init(struct e1000_hw * hw)
hw->ledctl_mode1 = hw->ledctl_default;
hw->ledctl_mode2 = hw->ledctl_default;
- if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
+ if (e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, 1, &eeprom_data) < 0) {
DEBUGOUT("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
- if((eeprom_data== ID_LED_RESERVED_0000) ||
- (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
- for(i = 0; i < 4; i++) {
+
+ if ((hw->mac_type == e1000_82573) &&
+ (eeprom_data == ID_LED_RESERVED_82573))
+ eeprom_data = ID_LED_DEFAULT_82573;
+ else if ((eeprom_data == ID_LED_RESERVED_0000) ||
+ (eeprom_data == ID_LED_RESERVED_FFFF)) {
+ if (hw->mac_type == e1000_ich8lan)
+ eeprom_data = ID_LED_DEFAULT_ICH8LAN;
+ else
+ eeprom_data = ID_LED_DEFAULT;
+ }
+ for (i = 0; i < 4; i++) {
temp = (eeprom_data >> (i << 2)) & led_mask;
- switch(temp) {
+ switch (temp) {
case ID_LED_ON1_DEF2:
case ID_LED_ON1_ON2:
case ID_LED_ON1_OFF2:
@@ -5442,7 +6026,7 @@ e1000_id_led_init(struct e1000_hw * hw)
/* Do nothing */
break;
}
- switch(temp) {
+ switch (temp) {
case ID_LED_DEF1_ON2:
case ID_LED_ON1_ON2:
case ID_LED_OFF1_ON2:
@@ -5476,7 +6060,7 @@ e1000_setup_led(struct e1000_hw *hw)
DEBUGFUNC("e1000_setup_led");
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -5490,16 +6074,16 @@ e1000_setup_led(struct e1000_hw *hw)
/* Turn off PHY Smart Power Down (if enabled) */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO,
&hw->phy_spd_default);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
(uint16_t)(hw->phy_spd_default &
~IGP01E1000_GMII_SPD));
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Fall Through */
default:
- if(hw->media_type == e1000_media_type_fiber) {
+ if (hw->media_type == e1000_media_type_fiber) {
ledctl = E1000_READ_REG(hw, LEDCTL);
/* Save current LEDCTL settings */
hw->ledctl_default = ledctl;
@@ -5510,7 +6094,7 @@ e1000_setup_led(struct e1000_hw *hw)
ledctl |= (E1000_LEDCTL_MODE_LED_OFF <<
E1000_LEDCTL_LED0_MODE_SHIFT);
E1000_WRITE_REG(hw, LEDCTL, ledctl);
- } else if(hw->media_type == e1000_media_type_copper)
+ } else if (hw->media_type == e1000_media_type_copper)
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
break;
}
@@ -5518,6 +6102,45 @@ e1000_setup_led(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+
+/******************************************************************************
+ * Used on 82571 and later Si that has LED blink bits.
+ * Callers must use their own timer and should have already called
+ * e1000_id_led_init()
+ * Call e1000_cleanup led() to stop blinking
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_blink_led_start(struct e1000_hw *hw)
+{
+ int16_t i;
+ uint32_t ledctl_blink = 0;
+
+ DEBUGFUNC("e1000_id_led_blink_on");
+
+ if (hw->mac_type < e1000_82571) {
+ /* Nothing to do */
+ return E1000_SUCCESS;
+ }
+ if (hw->media_type == e1000_media_type_fiber) {
+ /* always blink LED0 for PCI-E fiber */
+ ledctl_blink = E1000_LEDCTL_LED0_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED0_MODE_SHIFT);
+ } else {
+ /* set the blink bit for each LED that's "on" (0x0E) in ledctl_mode2 */
+ ledctl_blink = hw->ledctl_mode2;
+ for (i=0; i < 4; i++)
+ if (((hw->ledctl_mode2 >> (i * 8)) & 0xFF) ==
+ E1000_LEDCTL_MODE_LED_ON)
+ ledctl_blink |= (E1000_LEDCTL_LED0_BLINK << (i * 8));
+ }
+
+ E1000_WRITE_REG(hw, LEDCTL, ledctl_blink);
+
+ return E1000_SUCCESS;
+}
+
/******************************************************************************
* Restores the saved state of the SW controlable LED.
*
@@ -5530,7 +6153,7 @@ e1000_cleanup_led(struct e1000_hw *hw)
DEBUGFUNC("e1000_cleanup_led");
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -5544,10 +6167,14 @@ e1000_cleanup_led(struct e1000_hw *hw)
/* Turn on PHY Smart Power Down (if previously enabled) */
ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO,
hw->phy_spd_default);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Fall Through */
default:
+ if (hw->phy_type == e1000_phy_ife) {
+ e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
+ break;
+ }
/* Restore LEDCTL settings */
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
break;
@@ -5568,7 +6195,7 @@ e1000_led_on(struct e1000_hw *hw)
DEBUGFUNC("e1000_led_on");
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -5577,7 +6204,7 @@ e1000_led_on(struct e1000_hw *hw)
ctrl |= E1000_CTRL_SWDPIO0;
break;
case e1000_82544:
- if(hw->media_type == e1000_media_type_fiber) {
+ if (hw->media_type == e1000_media_type_fiber) {
/* Set SW Defineable Pin 0 to turn on the LED */
ctrl |= E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
@@ -5588,11 +6215,14 @@ e1000_led_on(struct e1000_hw *hw)
}
break;
default:
- if(hw->media_type == e1000_media_type_fiber) {
+ if (hw->media_type == e1000_media_type_fiber) {
/* Clear SW Defineable Pin 0 to turn on the LED */
ctrl &= ~E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
- } else if(hw->media_type == e1000_media_type_copper) {
+ } else if (hw->phy_type == e1000_phy_ife) {
+ e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
+ } else if (hw->media_type == e1000_media_type_copper) {
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
return E1000_SUCCESS;
}
@@ -5616,7 +6246,7 @@ e1000_led_off(struct e1000_hw *hw)
DEBUGFUNC("e1000_led_off");
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -5625,7 +6255,7 @@ e1000_led_off(struct e1000_hw *hw)
ctrl |= E1000_CTRL_SWDPIO0;
break;
case e1000_82544:
- if(hw->media_type == e1000_media_type_fiber) {
+ if (hw->media_type == e1000_media_type_fiber) {
/* Clear SW Defineable Pin 0 to turn off the LED */
ctrl &= ~E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
@@ -5636,11 +6266,14 @@ e1000_led_off(struct e1000_hw *hw)
}
break;
default:
- if(hw->media_type == e1000_media_type_fiber) {
+ if (hw->media_type == e1000_media_type_fiber) {
/* Set SW Defineable Pin 0 to turn off the LED */
ctrl |= E1000_CTRL_SWDPIN0;
ctrl |= E1000_CTRL_SWDPIO0;
- } else if(hw->media_type == e1000_media_type_copper) {
+ } else if (hw->phy_type == e1000_phy_ife) {
+ e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
+ (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
+ } else if (hw->media_type == e1000_media_type_copper) {
E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
return E1000_SUCCESS;
}
@@ -5657,7 +6290,7 @@ e1000_led_off(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-static void
+void
e1000_clear_hw_cntrs(struct e1000_hw *hw)
{
volatile uint32_t temp;
@@ -5678,12 +6311,16 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, XOFFRXC);
temp = E1000_READ_REG(hw, XOFFTXC);
temp = E1000_READ_REG(hw, FCRUC);
+
+ if (hw->mac_type != e1000_ich8lan) {
temp = E1000_READ_REG(hw, PRC64);
temp = E1000_READ_REG(hw, PRC127);
temp = E1000_READ_REG(hw, PRC255);
temp = E1000_READ_REG(hw, PRC511);
temp = E1000_READ_REG(hw, PRC1023);
temp = E1000_READ_REG(hw, PRC1522);
+ }
+
temp = E1000_READ_REG(hw, GPRC);
temp = E1000_READ_REG(hw, BPRC);
temp = E1000_READ_REG(hw, MPRC);
@@ -5703,16 +6340,20 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, TOTH);
temp = E1000_READ_REG(hw, TPR);
temp = E1000_READ_REG(hw, TPT);
+
+ if (hw->mac_type != e1000_ich8lan) {
temp = E1000_READ_REG(hw, PTC64);
temp = E1000_READ_REG(hw, PTC127);
temp = E1000_READ_REG(hw, PTC255);
temp = E1000_READ_REG(hw, PTC511);
temp = E1000_READ_REG(hw, PTC1023);
temp = E1000_READ_REG(hw, PTC1522);
+ }
+
temp = E1000_READ_REG(hw, MPTC);
temp = E1000_READ_REG(hw, BPTC);
- if(hw->mac_type < e1000_82543) return;
+ if (hw->mac_type < e1000_82543) return;
temp = E1000_READ_REG(hw, ALGNERRC);
temp = E1000_READ_REG(hw, RXERRC);
@@ -5721,16 +6362,19 @@ e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = E1000_READ_REG(hw, TSCTC);
temp = E1000_READ_REG(hw, TSCTFC);
- if(hw->mac_type <= e1000_82544) return;
+ if (hw->mac_type <= e1000_82544) return;
temp = E1000_READ_REG(hw, MGTPRC);
temp = E1000_READ_REG(hw, MGTPDC);
temp = E1000_READ_REG(hw, MGTPTC);
- if(hw->mac_type <= e1000_82547_rev_2) return;
+ if (hw->mac_type <= e1000_82547_rev_2) return;
temp = E1000_READ_REG(hw, IAC);
temp = E1000_READ_REG(hw, ICRXOC);
+
+ if (hw->mac_type == e1000_ich8lan) return;
+
temp = E1000_READ_REG(hw, ICRXPTC);
temp = E1000_READ_REG(hw, ICRXATC);
temp = E1000_READ_REG(hw, ICTXPTC);
@@ -5755,8 +6399,8 @@ e1000_reset_adaptive(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_reset_adaptive");
- if(hw->adaptive_ifs) {
- if(!hw->ifs_params_forced) {
+ if (hw->adaptive_ifs) {
+ if (!hw->ifs_params_forced) {
hw->current_ifs_val = 0;
hw->ifs_min_val = IFS_MIN;
hw->ifs_max_val = IFS_MAX;
@@ -5783,12 +6427,12 @@ e1000_update_adaptive(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_update_adaptive");
- if(hw->adaptive_ifs) {
- if((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
- if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+ if (hw->adaptive_ifs) {
+ if ((hw->collision_delta * hw->ifs_ratio) > hw->tx_packet_delta) {
+ if (hw->tx_packet_delta > MIN_NUM_XMITS) {
hw->in_ifs_mode = TRUE;
- if(hw->current_ifs_val < hw->ifs_max_val) {
- if(hw->current_ifs_val == 0)
+ if (hw->current_ifs_val < hw->ifs_max_val) {
+ if (hw->current_ifs_val == 0)
hw->current_ifs_val = hw->ifs_min_val;
else
hw->current_ifs_val += hw->ifs_step_size;
@@ -5796,7 +6440,7 @@ e1000_update_adaptive(struct e1000_hw *hw)
}
}
} else {
- if(hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+ if (hw->in_ifs_mode && (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
hw->current_ifs_val = 0;
hw->in_ifs_mode = FALSE;
E1000_WRITE_REG(hw, AIT, 0);
@@ -5843,46 +6487,46 @@ e1000_tbi_adjust_stats(struct e1000_hw *hw,
* This could be simplified if all environments supported
* 64-bit integers.
*/
- if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+ if (carry_bit && ((stats->gorcl & 0x80000000) == 0))
stats->gorch++;
/* Is this a broadcast or multicast? Check broadcast first,
* since the test for a multicast frame will test positive on
* a broadcast frame.
*/
- if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+ if ((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
/* Broadcast packet */
stats->bprc++;
- else if(*mac_addr & 0x01)
+ else if (*mac_addr & 0x01)
/* Multicast packet */
stats->mprc++;
- if(frame_len == hw->max_frame_size) {
+ if (frame_len == hw->max_frame_size) {
/* In this case, the hardware has overcounted the number of
* oversize frames.
*/
- if(stats->roc > 0)
+ if (stats->roc > 0)
stats->roc--;
}
/* Adjust the bin counters when the extra byte put the frame in the
* wrong bin. Remember that the frame_len was adjusted above.
*/
- if(frame_len == 64) {
+ if (frame_len == 64) {
stats->prc64++;
stats->prc127--;
- } else if(frame_len == 127) {
+ } else if (frame_len == 127) {
stats->prc127++;
stats->prc255--;
- } else if(frame_len == 255) {
+ } else if (frame_len == 255) {
stats->prc255++;
stats->prc511--;
- } else if(frame_len == 511) {
+ } else if (frame_len == 511) {
stats->prc511++;
stats->prc1023--;
- } else if(frame_len == 1023) {
+ } else if (frame_len == 1023) {
stats->prc1023++;
stats->prc1522--;
- } else if(frame_len == 1522) {
+ } else if (frame_len == 1522) {
stats->prc1522++;
}
}
@@ -5911,6 +6555,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_width = e1000_bus_width_pciex_1;
break;
case e1000_82571:
+ case e1000_ich8lan:
case e1000_80003es2lan:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
@@ -5921,10 +6566,10 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
e1000_bus_type_pcix : e1000_bus_type_pci;
- if(hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
+ if (hw->device_id == E1000_DEV_ID_82546EB_QUAD_COPPER) {
hw->bus_speed = (hw->bus_type == e1000_bus_type_pci) ?
e1000_bus_speed_66 : e1000_bus_speed_120;
- } else if(hw->bus_type == e1000_bus_type_pci) {
+ } else if (hw->bus_type == e1000_bus_type_pci) {
hw->bus_speed = (status & E1000_STATUS_PCI66) ?
e1000_bus_speed_66 : e1000_bus_speed_33;
} else {
@@ -5948,8 +6593,6 @@ e1000_get_bus_info(struct e1000_hw *hw)
break;
}
}
-
-#if 0
/******************************************************************************
* Reads a value from one of the devices registers using port I/O (as opposed
* memory mapped I/O). Only 82544 and newer devices support port I/O.
@@ -5957,6 +6600,7 @@ e1000_get_bus_info(struct e1000_hw *hw)
* hw - Struct containing variables accessed by shared code
* offset - offset to read from
*****************************************************************************/
+#if 0
uint32_t
e1000_read_reg_io(struct e1000_hw *hw,
uint32_t offset)
@@ -6012,8 +6656,6 @@ e1000_get_cable_length(struct e1000_hw *hw,
{
int32_t ret_val;
uint16_t agc_value = 0;
- uint16_t cur_agc, min_agc = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
- uint16_t max_agc = 0;
uint16_t i, phy_data;
uint16_t cable_length;
@@ -6022,11 +6664,11 @@ e1000_get_cable_length(struct e1000_hw *hw,
*min_length = *max_length = 0;
/* Use old method for Phy older than IGP */
- if(hw->phy_type == e1000_phy_m88) {
+ if (hw->phy_type == e1000_phy_m88) {
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
M88E1000_PSSR_CABLE_LENGTH_SHIFT;
@@ -6085,36 +6727,38 @@ e1000_get_cable_length(struct e1000_hw *hw,
return -E1000_ERR_PHY;
break;
}
- } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+ } else if (hw->phy_type == e1000_phy_igp) { /* For IGP PHY */
+ uint16_t cur_agc_value;
+ uint16_t min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
{IGP01E1000_PHY_AGC_A,
IGP01E1000_PHY_AGC_B,
IGP01E1000_PHY_AGC_C,
IGP01E1000_PHY_AGC_D};
/* Read the AGC registers for all channels */
- for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- cur_agc = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
+ cur_agc_value = phy_data >> IGP01E1000_AGC_LENGTH_SHIFT;
- /* Array bound check. */
- if((cur_agc >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
- (cur_agc == 0))
+ /* Value bound check. */
+ if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
+ (cur_agc_value == 0))
return -E1000_ERR_PHY;
- agc_value += cur_agc;
+ agc_value += cur_agc_value;
/* Update minimal AGC value. */
- if(min_agc > cur_agc)
- min_agc = cur_agc;
+ if (min_agc_value > cur_agc_value)
+ min_agc_value = cur_agc_value;
}
/* Remove the minimal AGC result for length < 50m */
- if(agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
- agc_value -= min_agc;
+ if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * e1000_igp_cable_length_50) {
+ agc_value -= min_agc_value;
/* Get the average length of the remaining 3 channels */
agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
@@ -6130,7 +6774,10 @@ e1000_get_cable_length(struct e1000_hw *hw,
IGP01E1000_AGC_RANGE) : 0;
*max_length = e1000_igp_cable_length_table[agc_value] +
IGP01E1000_AGC_RANGE;
- } else if (hw->phy_type == e1000_phy_igp_2) {
+ } else if (hw->phy_type == e1000_phy_igp_2 ||
+ hw->phy_type == e1000_phy_igp_3) {
+ uint16_t cur_agc_index, max_agc_index = 0;
+ uint16_t min_agc_index = IGP02E1000_AGC_LENGTH_TABLE_SIZE - 1;
uint16_t agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] =
{IGP02E1000_PHY_AGC_A,
IGP02E1000_PHY_AGC_B,
@@ -6142,22 +6789,30 @@ e1000_get_cable_length(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- /* Getting bits 15:9, which represent the combination of course and
+ /* Getting bits 15:9, which represent the combination of course and
* fine gain values. The result is a number that can be put into
* the lookup table to obtain the approximate cable length. */
- cur_agc = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
- IGP02E1000_AGC_LENGTH_MASK;
+ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) &
+ IGP02E1000_AGC_LENGTH_MASK;
- /* Remove min & max AGC values from calculation. */
- if (e1000_igp_2_cable_length_table[min_agc] > e1000_igp_2_cable_length_table[cur_agc])
- min_agc = cur_agc;
- if (e1000_igp_2_cable_length_table[max_agc] < e1000_igp_2_cable_length_table[cur_agc])
- max_agc = cur_agc;
+ /* Array index bound check. */
+ if ((cur_agc_index >= IGP02E1000_AGC_LENGTH_TABLE_SIZE) ||
+ (cur_agc_index == 0))
+ return -E1000_ERR_PHY;
- agc_value += e1000_igp_2_cable_length_table[cur_agc];
+ /* Remove min & max AGC values from calculation. */
+ if (e1000_igp_2_cable_length_table[min_agc_index] >
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ min_agc_index = cur_agc_index;
+ if (e1000_igp_2_cable_length_table[max_agc_index] <
+ e1000_igp_2_cable_length_table[cur_agc_index])
+ max_agc_index = cur_agc_index;
+
+ agc_value += e1000_igp_2_cable_length_table[cur_agc_index];
}
- agc_value -= (e1000_igp_2_cable_length_table[min_agc] + e1000_igp_2_cable_length_table[max_agc]);
+ agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] +
+ e1000_igp_2_cable_length_table[max_agc_index]);
agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2);
/* Calculate cable length with the error range of +/- 10 meters. */
@@ -6199,27 +6854,28 @@ e1000_check_polarity(struct e1000_hw *hw,
/* return the Polarity bit in the Status register. */
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
*polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
M88E1000_PSSR_REV_POLARITY_SHIFT;
- } else if(hw->phy_type == e1000_phy_igp ||
+ } else if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
/* Read the Status register to check the speed */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* If speed is 1000 Mbps, must read the IGP01E1000_PHY_PCS_INIT_REG to
* find the polarity status */
- if((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
+ if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
/* Read the GIG initialization PCS register (0x00B4) */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PCS_INIT_REG,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Check the polarity bits */
@@ -6229,6 +6885,13 @@ e1000_check_polarity(struct e1000_hw *hw,
* 100 Mbps this bit is always 0) */
*polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
}
+ } else if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+ *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >>
+ IFE_PESC_POLARITY_REVERSED_SHIFT;
}
return E1000_SUCCESS;
}
@@ -6256,11 +6919,12 @@ e1000_check_downshift(struct e1000_hw *hw)
DEBUGFUNC("e1000_check_downshift");
- if(hw->phy_type == e1000_phy_igp ||
+ if (hw->phy_type == e1000_phy_igp ||
+ hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_LINK_HEALTH,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0;
@@ -6268,11 +6932,14 @@ e1000_check_downshift(struct e1000_hw *hw)
(hw->phy_type == e1000_phy_gg82563)) {
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
M88E1000_PSSR_DOWNSHIFT_SHIFT;
+ } else if (hw->phy_type == e1000_phy_ife) {
+ /* e1000_phy_ife supports 10/100 speed only */
+ hw->speed_downgraded = FALSE;
}
return E1000_SUCCESS;
@@ -6305,40 +6972,42 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw,
DEBUGFUNC("e1000_config_dsp_after_link_change");
- if(hw->phy_type != e1000_phy_igp)
+ if (hw->phy_type != e1000_phy_igp)
return E1000_SUCCESS;
- if(link_up) {
+ if (link_up) {
ret_val = e1000_get_speed_and_duplex(hw, &speed, &duplex);
- if(ret_val) {
+ if (ret_val) {
DEBUGOUT("Error getting link speed and duplex\n");
return ret_val;
}
- if(speed == SPEED_1000) {
+ if (speed == SPEED_1000) {
- e1000_get_cable_length(hw, &min_length, &max_length);
+ ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
+ if (ret_val)
+ return ret_val;
- if((hw->dsp_config_state == e1000_dsp_config_enabled) &&
+ if ((hw->dsp_config_state == e1000_dsp_config_enabled) &&
min_length >= e1000_igp_cable_length_50) {
- for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i],
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
ret_val = e1000_write_phy_reg(hw, dsp_reg_array[i],
phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
hw->dsp_config_state = e1000_dsp_config_activated;
}
- if((hw->ffe_config_state == e1000_ffe_config_enabled) &&
+ if ((hw->ffe_config_state == e1000_ffe_config_enabled) &&
(min_length < e1000_igp_cable_length_50)) {
uint16_t ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
@@ -6347,119 +7016,119 @@ e1000_config_dsp_after_link_change(struct e1000_hw *hw,
/* clear previous idle error counts */
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
- for(i = 0; i < ffe_idle_err_timeout; i++) {
+ for (i = 0; i < ffe_idle_err_timeout; i++) {
udelay(1000);
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
- if(idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
+ if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
hw->ffe_config_state = e1000_ffe_config_active;
ret_val = e1000_write_phy_reg(hw,
IGP01E1000_PHY_DSP_FFE,
IGP01E1000_PHY_DSP_FFE_CM_CP);
- if(ret_val)
+ if (ret_val)
return ret_val;
break;
}
- if(idle_errs)
+ if (idle_errs)
ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_100;
}
}
}
} else {
- if(hw->dsp_config_state == e1000_dsp_config_activated) {
+ if (hw->dsp_config_state == e1000_dsp_config_activated) {
/* Save off the current value of register 0x2F5B to be restored at
* the end of the routines. */
ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Disable the PHY transmitter */
ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(20);
+ mdelay(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_FORCE_GIGA);
- if(ret_val)
+ if (ret_val)
return ret_val;
- for(i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
+ for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
ret_val = e1000_read_phy_reg(hw, dsp_reg_array[i], &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
ret_val = e1000_write_phy_reg(hw,dsp_reg_array[i], phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_RESTART_AUTONEG);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(20);
+ mdelay(20);
/* Now enable the transmitter */
ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->dsp_config_state = e1000_dsp_config_enabled;
}
- if(hw->ffe_config_state == e1000_ffe_config_active) {
+ if (hw->ffe_config_state == e1000_ffe_config_active) {
/* Save off the current value of register 0x2F5B to be restored at
* the end of the routines. */
ret_val = e1000_read_phy_reg(hw, 0x2F5B, &phy_saved_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Disable the PHY transmitter */
ret_val = e1000_write_phy_reg(hw, 0x2F5B, 0x0003);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(20);
+ mdelay(20);
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_FORCE_GIGA);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_DSP_FFE,
IGP01E1000_PHY_DSP_FFE_DEFAULT);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, 0x0000,
IGP01E1000_IEEE_RESTART_AUTONEG);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(20);
+ mdelay(20);
/* Now enable the transmitter */
ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->ffe_config_state = e1000_ffe_config_enabled;
@@ -6484,20 +7153,20 @@ e1000_set_phy_mode(struct e1000_hw *hw)
DEBUGFUNC("e1000_set_phy_mode");
- if((hw->mac_type == e1000_82545_rev_3) &&
- (hw->media_type == e1000_media_type_copper)) {
+ if ((hw->mac_type == e1000_82545_rev_3) &&
+ (hw->media_type == e1000_media_type_copper)) {
ret_val = e1000_read_eeprom(hw, EEPROM_PHY_CLASS_WORD, 1, &eeprom_data);
- if(ret_val) {
+ if (ret_val) {
return ret_val;
}
- if((eeprom_data != EEPROM_RESERVED_WORD) &&
- (eeprom_data & EEPROM_PHY_CLASS_A)) {
+ if ((eeprom_data != EEPROM_RESERVED_WORD) &&
+ (eeprom_data & EEPROM_PHY_CLASS_A)) {
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x000B);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x8104);
- if(ret_val)
+ if (ret_val)
return ret_val;
hw->phy_reset_disable = FALSE;
@@ -6525,39 +7194,51 @@ static int32_t
e1000_set_d3_lplu_state(struct e1000_hw *hw,
boolean_t active)
{
+ uint32_t phy_ctrl = 0;
int32_t ret_val;
uint16_t phy_data;
DEBUGFUNC("e1000_set_d3_lplu_state");
- if(hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2)
+ if (hw->phy_type != e1000_phy_igp && hw->phy_type != e1000_phy_igp_2
+ && hw->phy_type != e1000_phy_igp_3)
return E1000_SUCCESS;
/* During driver activity LPLU should not be used or it will attain link
* from the lowest speeds starting from 10Mbps. The capability is used for
* Dx transitions and states */
- if(hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
+ if (hw->mac_type == e1000_82541_rev_2 || hw->mac_type == e1000_82547_rev_2) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_GMII_FIFO, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
+ } else if (hw->mac_type == e1000_ich8lan) {
+ /* MAC writes into PHY register based on the state transition
+ * and start auto-negotiation. SW driver can overwrite the settings
+ * in CSR PHY power control E1000_PHY_CTRL register. */
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
} else {
ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
- if(!active) {
- if(hw->mac_type == e1000_82541_rev_2 ||
- hw->mac_type == e1000_82547_rev_2) {
+ if (!active) {
+ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
phy_data &= ~IGP01E1000_GMII_FLEX_SPD;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data &= ~IGP02E1000_PM_D3_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
phy_data);
if (ret_val)
return ret_val;
+ }
}
/* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
@@ -6567,13 +7248,13 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw,
if (hw->smart_speed == e1000_smart_speed_on) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else if (hw->smart_speed == e1000_smart_speed_off) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
@@ -6584,36 +7265,41 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw,
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
- } else if((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
- (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
- (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
+ } else if ((hw->autoneg_advertised == AUTONEG_ADVERTISE_SPEED_DEFAULT) ||
+ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_ALL ) ||
+ (hw->autoneg_advertised == AUTONEG_ADVERTISE_10_100_ALL)) {
- if(hw->mac_type == e1000_82541_rev_2 ||
- hw->mac_type == e1000_82547_rev_2) {
+ if (hw->mac_type == e1000_82541_rev_2 ||
+ hw->mac_type == e1000_82547_rev_2) {
phy_data |= IGP01E1000_GMII_FLEX_SPD;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_GMII_FIFO, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data |= IGP02E1000_PM_D3_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
phy_data);
if (ret_val)
return ret_val;
+ }
}
/* When LPLU is enabled we should disable SmartSpeed */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
@@ -6638,22 +7324,32 @@ static int32_t
e1000_set_d0_lplu_state(struct e1000_hw *hw,
boolean_t active)
{
+ uint32_t phy_ctrl = 0;
int32_t ret_val;
uint16_t phy_data;
DEBUGFUNC("e1000_set_d0_lplu_state");
- if(hw->mac_type <= e1000_82547_rev_2)
+ if (hw->mac_type <= e1000_82547_rev_2)
return E1000_SUCCESS;
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
+ } else {
ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
+ }
if (!active) {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data &= ~IGP02E1000_PM_D0_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
if (ret_val)
return ret_val;
+ }
/* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
* Dx states where the power conservation is most important. During
@@ -6662,13 +7358,13 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw,
if (hw->smart_speed == e1000_smart_speed_on) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
&phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
} else if (hw->smart_speed == e1000_smart_speed_off) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
@@ -6679,26 +7375,31 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw,
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
} else {
+ if (hw->mac_type == e1000_ich8lan) {
+ phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
+ E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
+ } else {
phy_data |= IGP02E1000_PM_D0_LPLU;
ret_val = e1000_write_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT, phy_data);
if (ret_val)
return ret_val;
+ }
/* When LPLU is enabled we should disable SmartSpeed */
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
ret_val = e1000_write_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
}
@@ -6719,7 +7420,7 @@ e1000_set_vco_speed(struct e1000_hw *hw)
DEBUGFUNC("e1000_set_vco_speed");
- switch(hw->mac_type) {
+ switch (hw->mac_type) {
case e1000_82545_rev_3:
case e1000_82546_rev_3:
break;
@@ -6730,39 +7431,39 @@ e1000_set_vco_speed(struct e1000_hw *hw)
/* Set PHY register 30, page 5, bit 8 to 0 */
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, &default_page);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* Set PHY register 30, page 4, bit 11 to 1 */
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
phy_data |= M88E1000_PHY_VCO_REG_BIT11;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, default_page);
- if(ret_val)
+ if (ret_val)
return ret_val;
return E1000_SUCCESS;
@@ -6818,7 +7519,7 @@ e1000_mng_enable_host_if(struct e1000_hw * hw)
hicr = E1000_READ_REG(hw, HICR);
if (!(hicr & E1000_HICR_C))
break;
- msec_delay_irq(1);
+ mdelay(1);
}
if (i == E1000_MNG_DHCP_COMMAND_TIMEOUT) {
@@ -6841,7 +7542,7 @@ e1000_mng_host_if_write(struct e1000_hw * hw, uint8_t *buffer,
{
uint8_t *tmp;
uint8_t *bufptr = buffer;
- uint32_t data;
+ uint32_t data = 0;
uint16_t remaining, i, j, prev_bytes;
/* sum = only sum of the data and it is not checksum */
@@ -6921,15 +7622,17 @@ e1000_mng_write_cmd_header(struct e1000_hw * hw,
buffer = (uint8_t *) hdr;
i = length;
- while(i--)
+ while (i--)
sum += buffer[i];
hdr->checksum = 0 - sum;
length >>= 2;
/* The device driver writes the relevant command block into the ram area. */
- for (i = 0; i < length; i++)
+ for (i = 0; i < length; i++) {
E1000_WRITE_REG_ARRAY_DWORD(hw, HOST_IF, i, *((uint32_t *) hdr + i));
+ E1000_WRITE_FLUSH(hw);
+ }
return E1000_SUCCESS;
}
@@ -6942,8 +7645,7 @@ e1000_mng_write_cmd_header(struct e1000_hw * hw,
* returns - E1000_SUCCESS for success.
****************************************************************************/
static int32_t
-e1000_mng_write_commit(
- struct e1000_hw * hw)
+e1000_mng_write_commit(struct e1000_hw * hw)
{
uint32_t hicr;
@@ -6961,15 +7663,18 @@ e1000_mng_write_commit(
* returns - TRUE when the mode is IAMT or FALSE.
****************************************************************************/
boolean_t
-e1000_check_mng_mode(
- struct e1000_hw *hw)
+e1000_check_mng_mode(struct e1000_hw *hw)
{
uint32_t fwsm;
fwsm = E1000_READ_REG(hw, FWSM);
- if((fwsm & E1000_FWSM_MODE_MASK) ==
- (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ if (hw->mac_type == e1000_ich8lan) {
+ if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_ICH_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
+ return TRUE;
+ } else if ((fwsm & E1000_FWSM_MODE_MASK) ==
+ (E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT))
return TRUE;
return FALSE;
@@ -7112,75 +7817,75 @@ e1000_polarity_reversal_workaround(struct e1000_hw *hw)
/* Disable the transmitter on the PHY */
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFFF);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* This loop will early-out if the NO link condition has been met. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
+ for (i = PHY_FORCE_TIME; i > 0; i--) {
/* Read the MII Status Register and wait for Link Status bit
* to be clear.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
- msec_delay_irq(100);
+ if ((mii_status_reg & ~MII_SR_LINK_STATUS) == 0) break;
+ mdelay(100);
}
/* Recommended delay time after link has been lost */
- msec_delay_irq(1000);
+ mdelay(1000);
/* Now we will re-enable th transmitter on the PHY */
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0019);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(50);
+ mdelay(50);
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFFF0);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(50);
+ mdelay(50);
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xFF00);
- if(ret_val)
+ if (ret_val)
return ret_val;
- msec_delay_irq(50);
+ mdelay(50);
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0x0000);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0000);
- if(ret_val)
+ if (ret_val)
return ret_val;
/* This loop will early-out if the link condition has been met. */
- for(i = PHY_FORCE_TIME; i > 0; i--) {
+ for (i = PHY_FORCE_TIME; i > 0; i--) {
/* Read the MII Status Register and wait for Link Status bit
* to be set.
*/
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg);
- if(ret_val)
+ if (ret_val)
return ret_val;
- if(mii_status_reg & MII_SR_LINK_STATUS) break;
- msec_delay_irq(100);
+ if (mii_status_reg & MII_SR_LINK_STATUS) break;
+ mdelay(100);
}
return E1000_SUCCESS;
}
@@ -7209,7 +7914,6 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw)
E1000_WRITE_REG(hw, CTRL, ctrl);
}
-#if 0
/***************************************************************************
*
* Enables PCI-Express master access.
@@ -7219,6 +7923,7 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw)
* returns: - none.
*
***************************************************************************/
+#if 0
void
e1000_enable_pciex_master(struct e1000_hw *hw)
{
@@ -7258,15 +7963,15 @@ e1000_disable_pciex_master(struct e1000_hw *hw)
e1000_set_pci_express_master_disable(hw);
- while(timeout) {
- if(!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
+ while (timeout) {
+ if (!(E1000_READ_REG(hw, STATUS) & E1000_STATUS_GIO_MASTER_ENABLE))
break;
else
udelay(100);
timeout--;
}
- if(!timeout) {
+ if (!timeout) {
DEBUGOUT("Master requests are pending.\n");
return -E1000_ERR_MASTER_REQUESTS_PENDING;
}
@@ -7293,19 +7998,21 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
switch (hw->mac_type) {
default:
- msec_delay(5);
+ msleep(5);
break;
case e1000_82571:
case e1000_82572:
case e1000_82573:
case e1000_80003es2lan:
- while(timeout) {
- if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break;
- else msec_delay(1);
+ case e1000_ich8lan:
+ while (timeout) {
+ if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD)
+ break;
+ else msleep(1);
timeout--;
}
- if(!timeout) {
+ if (!timeout) {
DEBUGOUT("Auto read by HW from EEPROM has not completed.\n");
return -E1000_ERR_RESET;
}
@@ -7316,7 +8023,7 @@ e1000_get_auto_rd_done(struct e1000_hw *hw)
* Need to wait for PHY configuration completion before accessing NVM
* and PHY. */
if (hw->mac_type == e1000_82573)
- msec_delay(25);
+ msleep(25);
return E1000_SUCCESS;
}
@@ -7340,7 +8047,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw)
switch (hw->mac_type) {
default:
- msec_delay(10);
+ mdelay(10);
break;
case e1000_80003es2lan:
/* Separate *_CFG_DONE_* bit for each port */
@@ -7353,7 +8060,7 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw)
if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
break;
else
- msec_delay(1);
+ msleep(1);
timeout--;
}
@@ -7386,7 +8093,7 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
DEBUGFUNC("e1000_get_hw_eeprom_semaphore");
- if(!hw->eeprom_semaphore_present)
+ if (!hw->eeprom_semaphore_present)
return E1000_SUCCESS;
if (hw->mac_type == e1000_80003es2lan) {
@@ -7397,20 +8104,20 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw)
/* Get the FW semaphore. */
timeout = hw->eeprom.word_size + 1;
- while(timeout) {
+ while (timeout) {
swsm = E1000_READ_REG(hw, SWSM);
swsm |= E1000_SWSM_SWESMBI;
E1000_WRITE_REG(hw, SWSM, swsm);
/* if we managed to set the bit we got the semaphore. */
swsm = E1000_READ_REG(hw, SWSM);
- if(swsm & E1000_SWSM_SWESMBI)
+ if (swsm & E1000_SWSM_SWESMBI)
break;
udelay(50);
timeout--;
}
- if(!timeout) {
+ if (!timeout) {
/* Release semaphores */
e1000_put_hw_eeprom_semaphore(hw);
DEBUGOUT("Driver can't access the Eeprom - SWESMBI bit is set.\n");
@@ -7435,7 +8142,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
DEBUGFUNC("e1000_put_hw_eeprom_semaphore");
- if(!hw->eeprom_semaphore_present)
+ if (!hw->eeprom_semaphore_present)
return;
swsm = E1000_READ_REG(hw, SWSM);
@@ -7457,7 +8164,7 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw)
* E1000_SUCCESS at any other case.
*
***************************************************************************/
-int32_t
+static int32_t
e1000_get_software_semaphore(struct e1000_hw *hw)
{
int32_t timeout = hw->eeprom.word_size + 1;
@@ -7468,16 +8175,16 @@ e1000_get_software_semaphore(struct e1000_hw *hw)
if (hw->mac_type != e1000_80003es2lan)
return E1000_SUCCESS;
- while(timeout) {
+ while (timeout) {
swsm = E1000_READ_REG(hw, SWSM);
/* If SMBI bit cleared, it is now set and we hold the semaphore */
- if(!(swsm & E1000_SWSM_SMBI))
+ if (!(swsm & E1000_SWSM_SMBI))
break;
- msec_delay_irq(1);
+ mdelay(1);
timeout--;
}
- if(!timeout) {
+ if (!timeout) {
DEBUGOUT("Driver can't access device - SMBI bit is set.\n");
return -E1000_ERR_RESET;
}
@@ -7492,7 +8199,7 @@ e1000_get_software_semaphore(struct e1000_hw *hw)
* hw: Struct containing variables accessed by shared code
*
***************************************************************************/
-void
+static void
e1000_release_software_semaphore(struct e1000_hw *hw)
{
uint32_t swsm;
@@ -7523,6 +8230,13 @@ int32_t
e1000_check_phy_reset_block(struct e1000_hw *hw)
{
uint32_t manc = 0;
+ uint32_t fwsm = 0;
+
+ if (hw->mac_type == e1000_ich8lan) {
+ fwsm = E1000_READ_REG(hw, FWSM);
+ return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS
+ : E1000_BLK_PHY_RESET;
+ }
if (hw->mac_type > e1000_82547_rev_2)
manc = E1000_READ_REG(hw, MANC);
@@ -7546,9 +8260,11 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
case e1000_82573:
case e1000_80003es2lan:
fwsm = E1000_READ_REG(hw, FWSM);
- if((fwsm & E1000_FWSM_MODE_MASK) != 0)
+ if ((fwsm & E1000_FWSM_MODE_MASK) != 0)
return TRUE;
break;
+ case e1000_ich8lan:
+ return TRUE;
default:
break;
}
@@ -7556,4 +8272,854 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw)
}
+/******************************************************************************
+ * Configure PCI-Ex no-snoop
+ *
+ * hw - Struct containing variables accessed by shared code.
+ * no_snoop - Bitmap of no-snoop events.
+ *
+ * returns: E1000_SUCCESS
+ *
+ *****************************************************************************/
+static int32_t
+e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop)
+{
+ uint32_t gcr_reg = 0;
+
+ DEBUGFUNC("e1000_set_pci_ex_no_snoop");
+
+ if (hw->bus_type == e1000_bus_type_unknown)
+ e1000_get_bus_info(hw);
+
+ if (hw->bus_type != e1000_bus_type_pci_express)
+ return E1000_SUCCESS;
+
+ if (no_snoop) {
+ gcr_reg = E1000_READ_REG(hw, GCR);
+ gcr_reg &= ~(PCI_EX_NO_SNOOP_ALL);
+ gcr_reg |= no_snoop;
+ E1000_WRITE_REG(hw, GCR, gcr_reg);
+ }
+ if (hw->mac_type == e1000_ich8lan) {
+ uint32_t ctrl_ext;
+
+ E1000_WRITE_REG(hw, GCR, PCI_EX_82566_SNOOP_ALL);
+
+ ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
+ E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Get software semaphore FLAG bit (SWFLAG).
+ * SWFLAG is used to synchronize the access to all shared resource between
+ * SW, FW and HW.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+static int32_t
+e1000_get_software_flag(struct e1000_hw *hw)
+{
+ int32_t timeout = PHY_CFG_TIMEOUT;
+ uint32_t extcnf_ctrl;
+
+ DEBUGFUNC("e1000_get_software_flag");
+
+ if (hw->mac_type == e1000_ich8lan) {
+ while (timeout) {
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+ extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+
+ extcnf_ctrl = E1000_READ_REG(hw, EXTCNF_CTRL);
+ if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
+ break;
+ mdelay(1);
+ timeout--;
+ }
+
+ if (!timeout) {
+ DEBUGOUT("FW or HW locks the resource too long.\n");
+ return -E1000_ERR_CONFIG;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+/***************************************************************************
+ *
+ * Release software semaphore FLAG bit (SWFLAG).
+ * SWFLAG is used to synchronize the access to all shared resource between
+ * SW, FW and HW.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+static void
+e1000_release_software_flag(struct e1000_hw *hw)
+{
+ uint32_t extcnf_ctrl;
+
+ DEBUGFUNC("e1000_release_software_flag");
+
+ if (hw->mac_type == e1000_ich8lan) {
+ extcnf_ctrl= E1000_READ_REG(hw, EXTCNF_CTRL);
+ extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
+ E1000_WRITE_REG(hw, EXTCNF_CTRL, extcnf_ctrl);
+ }
+
+ return;
+}
+
+/***************************************************************************
+ *
+ * Disable dynamic power down mode in ife PHY.
+ * It can be used to workaround band-gap problem.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+#if 0
+int32_t
+e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+ int32_t ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_ife_disable_dynamic_power_down");
+
+ if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+ ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+ }
+
+ return ret_val;
+}
+#endif /* 0 */
+
+/***************************************************************************
+ *
+ * Enable dynamic power down mode in ife PHY.
+ * It can be used to workaround band-gap problem.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ ***************************************************************************/
+#if 0
+int32_t
+e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw)
+{
+ uint16_t phy_data;
+ int32_t ret_val = E1000_SUCCESS;
+
+ DEBUGFUNC("e1000_ife_enable_dynamic_power_down");
+
+ if (hw->phy_type == e1000_phy_ife) {
+ ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data &= ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
+ ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
+ }
+
+ return ret_val;
+}
+#endif /* 0 */
+
+/******************************************************************************
+ * Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
+ * register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to read
+ * data - word read from the EEPROM
+ * words - number of words to read
+ *****************************************************************************/
+static int32_t
+e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words,
+ uint16_t *data)
+{
+ int32_t error = E1000_SUCCESS;
+ uint32_t flash_bank = 0;
+ uint32_t act_offset = 0;
+ uint32_t bank_offset = 0;
+ uint16_t word = 0;
+ uint16_t i = 0;
+
+ /* We need to know which is the valid flash bank. In the event
+ * that we didn't allocate eeprom_shadow_ram, we may not be
+ * managing flash_bank. So it cannot be trusted and needs
+ * to be updated with each read.
+ */
+ /* Value of bit 22 corresponds to the flash bank we're on. */
+ flash_bank = (E1000_READ_REG(hw, EECD) & E1000_EECD_SEC1VAL) ? 1 : 0;
+
+ /* Adjust offset appropriately if we're on bank 1 - adjust for word size */
+ bank_offset = flash_bank * (hw->flash_bank_size * 2);
+
+ error = e1000_get_software_flag(hw);
+ if (error != E1000_SUCCESS)
+ return error;
+
+ for (i = 0; i < words; i++) {
+ if (hw->eeprom_shadow_ram != NULL &&
+ hw->eeprom_shadow_ram[offset+i].modified == TRUE) {
+ data[i] = hw->eeprom_shadow_ram[offset+i].eeprom_word;
+ } else {
+ /* The NVM part needs a byte offset, hence * 2 */
+ act_offset = bank_offset + ((offset + i) * 2);
+ error = e1000_read_ich8_word(hw, act_offset, &word);
+ if (error != E1000_SUCCESS)
+ break;
+ data[i] = word;
+ }
+ }
+
+ e1000_release_software_flag(hw);
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word or words to the EEPROM using the ICH8's flash access
+ * register. Actually, writes are written to the shadow ram cache in the hw
+ * structure hw->e1000_shadow_ram. e1000_commit_shadow_ram flushes this to
+ * the NVM, which occurs when the NVM checksum is updated.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of word in the EEPROM to write
+ * words - number of words to write
+ * data - words to write to the EEPROM
+ *****************************************************************************/
+static int32_t
+e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words,
+ uint16_t *data)
+{
+ uint32_t i = 0;
+ int32_t error = E1000_SUCCESS;
+
+ error = e1000_get_software_flag(hw);
+ if (error != E1000_SUCCESS)
+ return error;
+
+ /* A driver can write to the NVM only if it has eeprom_shadow_ram
+ * allocated. Subsequent reads to the modified words are read from
+ * this cached structure as well. Writes will only go into this
+ * cached structure unless it's followed by a call to
+ * e1000_update_eeprom_checksum() where it will commit the changes
+ * and clear the "modified" field.
+ */
+ if (hw->eeprom_shadow_ram != NULL) {
+ for (i = 0; i < words; i++) {
+ if ((offset + i) < E1000_SHADOW_RAM_WORDS) {
+ hw->eeprom_shadow_ram[offset+i].modified = TRUE;
+ hw->eeprom_shadow_ram[offset+i].eeprom_word = data[i];
+ } else {
+ error = -E1000_ERR_EEPROM;
+ break;
+ }
+ }
+ } else {
+ /* Drivers have the option to not allocate eeprom_shadow_ram as long
+ * as they don't perform any NVM writes. An attempt in doing so
+ * will result in this error.
+ */
+ error = -E1000_ERR_EEPROM;
+ }
+
+ e1000_release_software_flag(hw);
+
+ return error;
+}
+
+/******************************************************************************
+ * This function does initial flash setup so that a new read/write/erase cycle
+ * can be started.
+ *
+ * hw - The pointer to the hw structure
+ ****************************************************************************/
+static int32_t
+e1000_ich8_cycle_init(struct e1000_hw *hw)
+{
+ union ich8_hws_flash_status hsfsts;
+ int32_t error = E1000_ERR_EEPROM;
+ int32_t i = 0;
+
+ DEBUGFUNC("e1000_ich8_cycle_init");
+
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+
+ /* May be check the Flash Des Valid bit in Hw status */
+ if (hsfsts.hsf_status.fldesvalid == 0) {
+ DEBUGOUT("Flash descriptor invalid. SW Sequencing must be used.");
+ return error;
+ }
+
+ /* Clear FCERR in Hw status by writing 1 */
+ /* Clear DAEL in Hw status by writing a 1 */
+ hsfsts.hsf_status.flcerr = 1;
+ hsfsts.hsf_status.dael = 1;
+
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+
+ /* Either we should have a hardware SPI cycle in progress bit to check
+ * against, in order to start a new cycle or FDONE bit should be changed
+ * in the hardware so that it is 1 after harware reset, which can then be
+ * used as an indication whether a cycle is in progress or has been
+ * completed .. we should also have some software semaphore mechanism to
+ * guard FDONE or the cycle in progress bit so that two threads access to
+ * those bits can be sequentiallized or a way so that 2 threads dont
+ * start the cycle at the same time */
+
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ /* There is no cycle running at present, so we can start a cycle */
+ /* Begin by setting Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+ error = E1000_SUCCESS;
+ } else {
+ /* otherwise poll for sometime so the current cycle has a chance
+ * to end before giving up. */
+ for (i = 0; i < ICH8_FLASH_COMMAND_TIMEOUT; i++) {
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcinprog == 0) {
+ error = E1000_SUCCESS;
+ break;
+ }
+ udelay(1);
+ }
+ if (error == E1000_SUCCESS) {
+ /* Successful in waiting for previous cycle to timeout,
+ * now set the Flash Cycle Done. */
+ hsfsts.hsf_status.flcdone = 1;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFSTS, hsfsts.regval);
+ } else {
+ DEBUGOUT("Flash controller busy, cannot get access");
+ }
+ }
+ return error;
+}
+
+/******************************************************************************
+ * This function starts a flash cycle and waits for its completion
+ *
+ * hw - The pointer to the hw structure
+ ****************************************************************************/
+static int32_t
+e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout)
+{
+ union ich8_hws_flash_ctrl hsflctl;
+ union ich8_hws_flash_status hsfsts;
+ int32_t error = E1000_ERR_EEPROM;
+ uint32_t i = 0;
+
+ /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcgo = 1;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* wait till FDONE bit is set to 1 */
+ do {
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcdone == 1)
+ break;
+ udelay(1);
+ i++;
+ } while (i < timeout);
+ if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0) {
+ error = E1000_SUCCESS;
+ }
+ return error;
+}
+
+/******************************************************************************
+ * Reads a byte or word from the NVM using the ICH8 flash access registers.
+ *
+ * hw - The pointer to the hw structure
+ * index - The index of the byte or word to read.
+ * size - Size of data to read, 1=byte 2=word
+ * data - Pointer to the word to store the value read.
+ *****************************************************************************/
+static int32_t
+e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index,
+ uint32_t size, uint16_t* data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ uint32_t flash_data = 0;
+ int32_t error = -E1000_ERR_EEPROM;
+ int32_t count = 0;
+
+ DEBUGFUNC("e1000_read_ich8_data");
+
+ if (size < 1 || size > 2 || data == 0x0 ||
+ index > ICH8_FLASH_LINEAR_ADDR_MASK)
+ return error;
+
+ flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) +
+ hw->flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ error = e1000_ich8_cycle_init(hw);
+ if (error != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size - 1;
+ hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_READ;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of index into Flash Linear address field in
+ * Flash Address */
+ /* TODO: TBD maybe check the index against the size of flash */
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+ error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT);
+
+ /* Check if FCERR is set to 1, if set to 1, clear it and try the whole
+ * sequence a few more times, else read in (shift in) the Flash Data0,
+ * the order is least significant byte first msb to lsb */
+ if (error == E1000_SUCCESS) {
+ flash_data = E1000_READ_ICH8_REG(hw, ICH8_FLASH_FDATA0);
+ if (size == 1) {
+ *data = (uint8_t)(flash_data & 0x000000FF);
+ } else if (size == 2) {
+ *data = (uint16_t)(flash_data & 0x0000FFFF);
+ }
+ break;
+ } else {
+ /* If we've gotten here, then things are probably completely hosed,
+ * but if the error condition is detected, it won't hurt to give
+ * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT);
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes One /two bytes to the NVM using the ICH8 flash access registers.
+ *
+ * hw - The pointer to the hw structure
+ * index - The index of the byte/word to read.
+ * size - Size of data to read, 1=byte 2=word
+ * data - The byte(s) to write to the NVM.
+ *****************************************************************************/
+static int32_t
+e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size,
+ uint16_t data)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ uint32_t flash_data = 0;
+ int32_t error = -E1000_ERR_EEPROM;
+ int32_t count = 0;
+
+ DEBUGFUNC("e1000_write_ich8_data");
+
+ if (size < 1 || size > 2 || data > size * 0xff ||
+ index > ICH8_FLASH_LINEAR_ADDR_MASK)
+ return error;
+
+ flash_linear_address = (ICH8_FLASH_LINEAR_ADDR_MASK & index) +
+ hw->flash_base_addr;
+
+ do {
+ udelay(1);
+ /* Steps */
+ error = e1000_ich8_cycle_init(hw);
+ if (error != E1000_SUCCESS)
+ break;
+
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
+ hsflctl.hsf_ctrl.fldbcount = size -1;
+ hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_WRITE;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of index into Flash Linear address field in
+ * Flash Address */
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+ if (size == 1)
+ flash_data = (uint32_t)data & 0x00FF;
+ else
+ flash_data = (uint32_t)data;
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FDATA0, flash_data);
+
+ /* check if FCERR is set to 1 , if set to 1, clear it and try the whole
+ * sequence a few more times else done */
+ error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_COMMAND_TIMEOUT);
+ if (error == E1000_SUCCESS) {
+ break;
+ } else {
+ /* If we're here, then things are most likely completely hosed,
+ * but if the error condition is detected, it won't hurt to give
+ * it another try...ICH8_FLASH_CYCLE_REPEAT_COUNT times.
+ */
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* Repeat for some time before giving up. */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ DEBUGOUT("Timeout error - flash cycle did not complete.");
+ break;
+ }
+ }
+ } while (count++ < ICH8_FLASH_CYCLE_REPEAT_COUNT);
+
+ return error;
+}
+
+/******************************************************************************
+ * Reads a single byte from the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to read.
+ * data - Pointer to a byte to store the value read.
+ *****************************************************************************/
+static int32_t
+e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t* data)
+{
+ int32_t status = E1000_SUCCESS;
+ uint16_t word = 0;
+
+ status = e1000_read_ich8_data(hw, index, 1, &word);
+ if (status == E1000_SUCCESS) {
+ *data = (uint8_t)word;
+ }
+
+ return status;
+}
+
+/******************************************************************************
+ * Writes a single byte to the NVM using the ICH8 flash access registers.
+ * Performs verification by reading back the value and then going through
+ * a retry algorithm before giving up.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to write.
+ * byte - The byte to write to the NVM.
+ *****************************************************************************/
+static int32_t
+e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
+{
+ int32_t error = E1000_SUCCESS;
+ int32_t program_retries;
+ uint8_t temp_byte;
+
+ e1000_write_ich8_byte(hw, index, byte);
+ udelay(100);
+
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ e1000_read_ich8_byte(hw, index, &temp_byte);
+ if (temp_byte == byte)
+ break;
+ udelay(10);
+ e1000_write_ich8_byte(hw, index, byte);
+ udelay(100);
+ }
+ if (program_retries == 100)
+ error = E1000_ERR_EEPROM;
+
+ return error;
+}
+
+/******************************************************************************
+ * Writes a single byte to the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The index of the byte to read.
+ * data - The byte to write to the NVM.
+ *****************************************************************************/
+static int32_t
+e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t data)
+{
+ int32_t status = E1000_SUCCESS;
+ uint16_t word = (uint16_t)data;
+
+ status = e1000_write_ich8_data(hw, index, 1, word);
+
+ return status;
+}
+
+/******************************************************************************
+ * Reads a word from the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The starting byte index of the word to read.
+ * data - Pointer to a word to store the value read.
+ *****************************************************************************/
+static int32_t
+e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data)
+{
+ int32_t status = E1000_SUCCESS;
+ status = e1000_read_ich8_data(hw, index, 2, data);
+ return status;
+}
+
+/******************************************************************************
+ * Writes a word to the NVM using the ICH8 flash access registers.
+ *
+ * hw - pointer to e1000_hw structure
+ * index - The starting byte index of the word to read.
+ * data - The word to write to the NVM.
+ *****************************************************************************/
+#if 0
+int32_t
+e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data)
+{
+ int32_t status = E1000_SUCCESS;
+ status = e1000_write_ich8_data(hw, index, 2, data);
+ return status;
+}
+#endif /* 0 */
+
+/******************************************************************************
+ * Erases the bank specified. Each bank is a 4k block. Segments are 0 based.
+ * segment N is 4096 * N + flash_reg_addr.
+ *
+ * hw - pointer to e1000_hw structure
+ * segment - 0 for first segment, 1 for second segment, etc.
+ *****************************************************************************/
+static int32_t
+e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
+{
+ union ich8_hws_flash_status hsfsts;
+ union ich8_hws_flash_ctrl hsflctl;
+ uint32_t flash_linear_address;
+ int32_t count = 0;
+ int32_t error = E1000_ERR_EEPROM;
+ int32_t iteration, seg_size;
+ int32_t sector_size;
+ int32_t j = 0;
+ int32_t error_flag = 0;
+
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+
+ /* Determine HW Sector size: Read BERASE bits of Hw flash Status register */
+ /* 00: The Hw sector is 256 bytes, hence we need to erase 16
+ * consecutive sectors. The start index for the nth Hw sector can be
+ * calculated as = segment * 4096 + n * 256
+ * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
+ * The start index for the nth Hw sector can be calculated
+ * as = segment * 4096
+ * 10: Error condition
+ * 11: The Hw sector size is much bigger than the size asked to
+ * erase...error condition */
+ if (hsfsts.hsf_status.berasesz == 0x0) {
+ /* Hw sector size 256 */
+ sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256;
+ iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256;
+ } else if (hsfsts.hsf_status.berasesz == 0x1) {
+ sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K;
+ iteration = 1;
+ } else if (hsfsts.hsf_status.berasesz == 0x3) {
+ sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K;
+ iteration = 1;
+ } else {
+ return error;
+ }
+
+ for (j = 0; j < iteration ; j++) {
+ do {
+ count++;
+ /* Steps */
+ error = e1000_ich8_cycle_init(hw);
+ if (error != E1000_SUCCESS) {
+ error_flag = 1;
+ break;
+ }
+
+ /* Write a value 11 (block Erase) in Flash Cycle field in Hw flash
+ * Control */
+ hsflctl.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFCTL);
+ hsflctl.hsf_ctrl.flcycle = ICH8_CYCLE_ERASE;
+ E1000_WRITE_ICH8_REG16(hw, ICH8_FLASH_HSFCTL, hsflctl.regval);
+
+ /* Write the last 24 bits of an index within the block into Flash
+ * Linear address field in Flash Address. This probably needs to
+ * be calculated here based off the on-chip segment size and the
+ * software segment size assumed (4K) */
+ /* TBD */
+ flash_linear_address = segment * sector_size + j * seg_size;
+ flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
+ flash_linear_address += hw->flash_base_addr;
+
+ E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
+
+ error = e1000_ich8_flash_cycle(hw, 1000000);
+ /* Check if FCERR is set to 1. If 1, clear it and try the whole
+ * sequence a few more times else Done */
+ if (error == E1000_SUCCESS) {
+ break;
+ } else {
+ hsfsts.regval = E1000_READ_ICH8_REG16(hw, ICH8_FLASH_HSFSTS);
+ if (hsfsts.hsf_status.flcerr == 1) {
+ /* repeat for some time before giving up */
+ continue;
+ } else if (hsfsts.hsf_status.flcdone == 0) {
+ error_flag = 1;
+ break;
+ }
+ }
+ } while ((count < ICH8_FLASH_CYCLE_REPEAT_COUNT) && !error_flag);
+ if (error_flag == 1)
+ break;
+ }
+ if (error_flag != 1)
+ error = E1000_SUCCESS;
+ return error;
+}
+
+/******************************************************************************
+ *
+ * Reverse duplex setting without breaking the link.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ *****************************************************************************/
+#if 0
+int32_t
+e1000_duplex_reversal(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ if (hw->phy_type != e1000_phy_igp_3)
+ return E1000_SUCCESS;
+
+ ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data ^= MII_CR_FULL_DUPLEX;
+
+ ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET;
+ ret_val = e1000_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data);
+
+ return ret_val;
+}
+#endif /* 0 */
+
+static int32_t
+e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw,
+ uint32_t cnf_base_addr, uint32_t cnf_size)
+{
+ uint32_t ret_val = E1000_SUCCESS;
+ uint16_t word_addr, reg_data, reg_addr;
+ uint16_t i;
+
+ /* cnf_base_addr is in DWORD */
+ word_addr = (uint16_t)(cnf_base_addr << 1);
+
+ /* cnf_size is returned in size of dwords */
+ for (i = 0; i < cnf_size; i++) {
+ ret_val = e1000_read_eeprom(hw, (word_addr + i*2), 1, &reg_data);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_read_eeprom(hw, (word_addr + i*2 + 1), 1, &reg_addr);
+ if (ret_val)
+ return ret_val;
+
+ ret_val = e1000_get_software_flag(hw);
+ if (ret_val != E1000_SUCCESS)
+ return ret_val;
+
+ ret_val = e1000_write_phy_reg_ex(hw, (uint32_t)reg_addr, reg_data);
+
+ e1000_release_software_flag(hw);
+ }
+
+ return ret_val;
+}
+
+
+static int32_t
+e1000_init_lcd_from_nvm(struct e1000_hw *hw)
+{
+ uint32_t reg_data, cnf_base_addr, cnf_size, ret_val, loop;
+
+ if (hw->phy_type != e1000_phy_igp_3)
+ return E1000_SUCCESS;
+
+ /* Check if SW needs configure the PHY */
+ reg_data = E1000_READ_REG(hw, FEXTNVM);
+ if (!(reg_data & FEXTNVM_SW_CONFIG))
+ return E1000_SUCCESS;
+
+ /* Wait for basic configuration completes before proceeding*/
+ loop = 0;
+ do {
+ reg_data = E1000_READ_REG(hw, STATUS) & E1000_STATUS_LAN_INIT_DONE;
+ udelay(100);
+ loop++;
+ } while ((!reg_data) && (loop < 50));
+
+ /* Clear the Init Done bit for the next init event */
+ reg_data = E1000_READ_REG(hw, STATUS);
+ reg_data &= ~E1000_STATUS_LAN_INIT_DONE;
+ E1000_WRITE_REG(hw, STATUS, reg_data);
+
+ /* Make sure HW does not configure LCD from PHY extended configuration
+ before SW configuration */
+ reg_data = E1000_READ_REG(hw, EXTCNF_CTRL);
+ if ((reg_data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE) == 0x0000) {
+ reg_data = E1000_READ_REG(hw, EXTCNF_SIZE);
+ cnf_size = reg_data & E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH;
+ cnf_size >>= 16;
+ if (cnf_size) {
+ reg_data = E1000_READ_REG(hw, EXTCNF_CTRL);
+ cnf_base_addr = reg_data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER;
+ /* cnf_base_addr is in DWORD */
+ cnf_base_addr >>= 16;
+
+ /* Configure LCD from extended configuration region. */
+ ret_val = e1000_init_lcd_from_nvm_config_region(hw, cnf_base_addr,
+ cnf_size);
+ if (ret_val)
+ return ret_val;
+ }
+ }
+
+ return E1000_SUCCESS;
+}
+
+
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index 467c9ed944f..4020acb5500 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -62,6 +62,7 @@ typedef enum {
e1000_82572,
e1000_82573,
e1000_80003es2lan,
+ e1000_ich8lan,
e1000_num_macs
} e1000_mac_type;
@@ -70,6 +71,7 @@ typedef enum {
e1000_eeprom_spi,
e1000_eeprom_microwire,
e1000_eeprom_flash,
+ e1000_eeprom_ich8,
e1000_eeprom_none, /* No NVM support */
e1000_num_eeprom_types
} e1000_eeprom_type;
@@ -98,6 +100,11 @@ typedef enum {
e1000_fc_default = 0xFF
} e1000_fc_type;
+struct e1000_shadow_ram {
+ uint16_t eeprom_word;
+ boolean_t modified;
+};
+
/* PCI bus types */
typedef enum {
e1000_bus_type_unknown = 0,
@@ -218,6 +225,8 @@ typedef enum {
e1000_phy_igp,
e1000_phy_igp_2,
e1000_phy_gg82563,
+ e1000_phy_igp_3,
+ e1000_phy_ife,
e1000_phy_undefined = 0xFF
} e1000_phy_type;
@@ -313,10 +322,9 @@ int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy
int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
int32_t e1000_phy_reset(struct e1000_hw *hw);
+void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
-int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data);
-int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
/* EEPROM Functions */
int32_t e1000_init_eeprom_params(struct e1000_hw *hw);
@@ -328,9 +336,10 @@ uint32_t e1000_enable_mng_pass_thru(struct e1000_hw *hw);
#define E1000_HI_MAX_MNG_DATA_LENGTH 0x6F8 /* Host Interface data length */
#define E1000_MNG_DHCP_COMMAND_TIMEOUT 10 /* Time in ms to process MNG command */
-#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */
-#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */
-#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_DHCP_COOKIE_OFFSET 0x6F0 /* Cookie offset */
+#define E1000_MNG_DHCP_COOKIE_LENGTH 0x10 /* Cookie length */
+#define E1000_MNG_IAMT_MODE 0x3
+#define E1000_MNG_ICH_IAMT_MODE 0x2
#define E1000_IAMT_SIGNATURE 0x544D4149 /* Intel(R) Active Management Technology signature */
#define E1000_MNG_DHCP_COOKIE_STATUS_PARSING_SUPPORT 0x1 /* DHCP parsing enabled */
@@ -376,7 +385,7 @@ struct e1000_host_mng_dhcp_cookie{
#endif
int32_t e1000_mng_write_dhcp_info(struct e1000_hw *hw, uint8_t *buffer,
- uint16_t length);
+ uint16_t length);
boolean_t e1000_check_mng_mode(struct e1000_hw *hw);
boolean_t e1000_enable_tx_pkt_filtering(struct e1000_hw *hw);
@@ -386,11 +395,8 @@ int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
int32_t e1000_read_mac_addr(struct e1000_hw * hw);
-int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
-void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
/* Filters (multicast, vlan, receive) */
-void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad, uint32_t rar_used_count);
uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr);
void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value);
void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
@@ -401,6 +407,7 @@ int32_t e1000_setup_led(struct e1000_hw *hw);
int32_t e1000_cleanup_led(struct e1000_hw *hw);
int32_t e1000_led_on(struct e1000_hw *hw);
int32_t e1000_led_off(struct e1000_hw *hw);
+int32_t e1000_blink_led_start(struct e1000_hw *hw);
/* Adaptive IFS Functions */
@@ -414,15 +421,16 @@ void e1000_pci_clear_mwi(struct e1000_hw *hw);
void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
/* Port I/O is only supported on 82544 and newer */
-uint32_t e1000_io_read(struct e1000_hw *hw, unsigned long port);
-uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset);
void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value);
-void e1000_enable_pciex_master(struct e1000_hw *hw);
int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
-int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
-void e1000_release_software_semaphore(struct e1000_hw *hw);
int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
+
+#define E1000_READ_REG_IO(a, reg) \
+ e1000_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+ e1000_write_reg_io((a), E1000_##reg, val)
+
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
#define E1000_DEV_ID_82543GC_FIBER 0x1001
@@ -446,6 +454,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
#define E1000_DEV_ID_82546EB_QUAD_COPPER 0x101D
#define E1000_DEV_ID_82541EI 0x1013
#define E1000_DEV_ID_82541EI_MOBILE 0x1018
+#define E1000_DEV_ID_82541ER_LOM 0x1014
#define E1000_DEV_ID_82541ER 0x1078
#define E1000_DEV_ID_82547GI 0x1075
#define E1000_DEV_ID_82541GI 0x1076
@@ -457,18 +466,29 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
#define E1000_DEV_ID_82546GB_PCIE 0x108A
#define E1000_DEV_ID_82546GB_QUAD_COPPER 0x1099
#define E1000_DEV_ID_82547EI 0x1019
+#define E1000_DEV_ID_82547EI_MOBILE 0x101A
#define E1000_DEV_ID_82571EB_COPPER 0x105E
#define E1000_DEV_ID_82571EB_FIBER 0x105F
#define E1000_DEV_ID_82571EB_SERDES 0x1060
+#define E1000_DEV_ID_82571EB_QUAD_COPPER 0x10A4
#define E1000_DEV_ID_82572EI_COPPER 0x107D
#define E1000_DEV_ID_82572EI_FIBER 0x107E
#define E1000_DEV_ID_82572EI_SERDES 0x107F
+#define E1000_DEV_ID_82572EI 0x10B9
#define E1000_DEV_ID_82573E 0x108B
#define E1000_DEV_ID_82573E_IAMT 0x108C
#define E1000_DEV_ID_82573L 0x109A
#define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
+#define E1000_DEV_ID_80003ES2LAN_COPPER_SPT 0x10BA
+#define E1000_DEV_ID_80003ES2LAN_SERDES_SPT 0x10BB
+
+#define E1000_DEV_ID_ICH8_IGP_M_AMT 0x1049
+#define E1000_DEV_ID_ICH8_IGP_AMT 0x104A
+#define E1000_DEV_ID_ICH8_IGP_C 0x104B
+#define E1000_DEV_ID_ICH8_IFE 0x104C
+#define E1000_DEV_ID_ICH8_IGP_M 0x104D
#define NODE_ADDRESS_SIZE 6
@@ -504,7 +524,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
/* 802.1q VLAN Packet Sizes */
-#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */
+#define VLAN_TAG_SIZE 4 /* 802.3ac tag (not DMAed) */
/* Ethertype field values */
#define ETHERNET_IEEE_VLAN_TYPE 0x8100 /* 802.3ac packet */
@@ -539,6 +559,14 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
E1000_IMS_RXSEQ | \
E1000_IMS_LSC)
+/* Additional interrupts need to be handled for e1000_ich8lan:
+ DSW = The FW changed the status of the DISSW bit in FWSM
+ PHYINT = The LAN connected device generates an interrupt
+ EPRST = Manageability reset event */
+#define IMS_ICH8LAN_ENABLE_MASK (\
+ E1000_IMS_DSW | \
+ E1000_IMS_PHYINT | \
+ E1000_IMS_EPRST)
/* Number of high/low register pairs in the RAR. The RAR (Receive Address
* Registers) holds the directed and multicast addresses that we monitor. We
@@ -546,6 +574,7 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
* E1000_RAR_ENTRIES - 1 multicast addresses.
*/
#define E1000_RAR_ENTRIES 15
+#define E1000_RAR_ENTRIES_ICH8LAN 7
#define MIN_NUMBER_OF_DESCRIPTORS 8
#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
@@ -669,6 +698,7 @@ union e1000_rx_desc_packet_split {
E1000_RXDEXT_STATERR_CXE | \
E1000_RXDEXT_STATERR_RXE)
+
/* Transmit Descriptor */
struct e1000_tx_desc {
uint64_t buffer_addr; /* Address of the descriptor's data buffer */
@@ -767,6 +797,9 @@ struct e1000_data_desc {
#define E1000_MC_TBL_SIZE 128 /* Multicast Filter Table (4096 bits) */
#define E1000_VLAN_FILTER_TBL_SIZE 128 /* VLAN Filter Table (4096 bits) */
+#define E1000_NUM_UNICAST_ICH8LAN 7
+#define E1000_MC_TBL_SIZE_ICH8LAN 32
+
/* Receive Address Register */
struct e1000_rar {
@@ -776,6 +809,7 @@ struct e1000_rar {
/* Number of entries in the Multicast Table Array (MTA). */
#define E1000_NUM_MTA_REGISTERS 128
+#define E1000_NUM_MTA_REGISTERS_ICH8LAN 32
/* IPv4 Address Table Entry */
struct e1000_ipv4_at_entry {
@@ -786,6 +820,7 @@ struct e1000_ipv4_at_entry {
/* Four wakeup IP addresses are supported */
#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
#define E1000_IP4AT_SIZE E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP4AT_SIZE_ICH8LAN 3
#define E1000_IP6AT_SIZE 1
/* IPv6 Address Table Entry */
@@ -844,6 +879,7 @@ struct e1000_ffvt_entry {
#define E1000_FLA 0x0001C /* Flash Access - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_SCTL 0x00024 /* SerDes Control - RW */
+#define E1000_FEXTNVM 0x00028 /* Future Extended NVM register */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
#define E1000_FCAH 0x0002C /* Flow Control Address High -RW */
#define E1000_FCT 0x00030 /* Flow Control Type - RW */
@@ -872,6 +908,8 @@ struct e1000_ffvt_entry {
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
+#define E1000_PHY_CTRL 0x00F10 /* PHY Control Register in CSR */
+#define FEXTNVM_SW_CONFIG 0x0001
#define E1000_PBA 0x01000 /* Packet Buffer Allocation - RW */
#define E1000_PBS 0x01008 /* Packet Buffer Size */
#define E1000_EEMNGCTL 0x01010 /* MNG EEprom Control */
@@ -899,11 +937,13 @@ struct e1000_ffvt_entry {
#define E1000_RDH0 E1000_RDH /* RX Desc Head (0) - RW */
#define E1000_RDT0 E1000_RDT /* RX Desc Tail (0) - RW */
#define E1000_RDTR0 E1000_RDTR /* RX Delay Timer (0) - RW */
-#define E1000_RXDCTL 0x02828 /* RX Descriptor Control - RW */
+#define E1000_RXDCTL 0x02828 /* RX Descriptor Control queue 0 - RW */
+#define E1000_RXDCTL1 0x02928 /* RX Descriptor Control queue 1 - RW */
#define E1000_RADV 0x0282C /* RX Interrupt Absolute Delay Timer - RW */
#define E1000_RSRPD 0x02C00 /* RX Small Packet Detect - RW */
#define E1000_RAID 0x02C08 /* Receive Ack Interrupt Delay - RW */
#define E1000_TXDMAC 0x03000 /* TX DMA Control - RW */
+#define E1000_KABGTXD 0x03004 /* AFE Band Gap Transmit Ref Data */
#define E1000_TDFH 0x03410 /* TX Data FIFO Head - RW */
#define E1000_TDFT 0x03418 /* TX Data FIFO Tail - RW */
#define E1000_TDFHS 0x03420 /* TX Data FIFO Head Saved - RW */
@@ -1050,6 +1090,7 @@ struct e1000_ffvt_entry {
#define E1000_82542_FLA E1000_FLA
#define E1000_82542_MDIC E1000_MDIC
#define E1000_82542_SCTL E1000_SCTL
+#define E1000_82542_FEXTNVM E1000_FEXTNVM
#define E1000_82542_FCAL E1000_FCAL
#define E1000_82542_FCAH E1000_FCAH
#define E1000_82542_FCT E1000_FCT
@@ -1073,6 +1114,19 @@ struct e1000_ffvt_entry {
#define E1000_82542_RDLEN0 E1000_82542_RDLEN
#define E1000_82542_RDH0 E1000_82542_RDH
#define E1000_82542_RDT0 E1000_82542_RDT
+#define E1000_82542_SRRCTL(_n) (0x280C + ((_n) << 8)) /* Split and Replication
+ * RX Control - RW */
+#define E1000_82542_DCA_RXCTRL(_n) (0x02814 + ((_n) << 8))
+#define E1000_82542_RDBAH3 0x02B04 /* RX Desc Base High Queue 3 - RW */
+#define E1000_82542_RDBAL3 0x02B00 /* RX Desc Low Queue 3 - RW */
+#define E1000_82542_RDLEN3 0x02B08 /* RX Desc Length Queue 3 - RW */
+#define E1000_82542_RDH3 0x02B10 /* RX Desc Head Queue 3 - RW */
+#define E1000_82542_RDT3 0x02B18 /* RX Desc Tail Queue 3 - RW */
+#define E1000_82542_RDBAL2 0x02A00 /* RX Desc Base Low Queue 2 - RW */
+#define E1000_82542_RDBAH2 0x02A04 /* RX Desc Base High Queue 2 - RW */
+#define E1000_82542_RDLEN2 0x02A08 /* RX Desc Length Queue 2 - RW */
+#define E1000_82542_RDH2 0x02A10 /* RX Desc Head Queue 2 - RW */
+#define E1000_82542_RDT2 0x02A18 /* RX Desc Tail Queue 2 - RW */
#define E1000_82542_RDTR1 0x00130
#define E1000_82542_RDBAL1 0x00138
#define E1000_82542_RDBAH1 0x0013C
@@ -1110,11 +1164,14 @@ struct e1000_ffvt_entry {
#define E1000_82542_FLOP E1000_FLOP
#define E1000_82542_EXTCNF_CTRL E1000_EXTCNF_CTRL
#define E1000_82542_EXTCNF_SIZE E1000_EXTCNF_SIZE
+#define E1000_82542_PHY_CTRL E1000_PHY_CTRL
#define E1000_82542_ERT E1000_ERT
#define E1000_82542_RXDCTL E1000_RXDCTL
+#define E1000_82542_RXDCTL1 E1000_RXDCTL1
#define E1000_82542_RADV E1000_RADV
#define E1000_82542_RSRPD E1000_RSRPD
#define E1000_82542_TXDMAC E1000_TXDMAC
+#define E1000_82542_KABGTXD E1000_KABGTXD
#define E1000_82542_TDFHS E1000_TDFHS
#define E1000_82542_TDFTS E1000_TDFTS
#define E1000_82542_TDFPC E1000_TDFPC
@@ -1311,12 +1368,15 @@ struct e1000_hw_stats {
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
uint8_t __iomem *hw_addr;
- uint8_t *flash_address;
+ uint8_t __iomem *flash_address;
e1000_mac_type mac_type;
e1000_phy_type phy_type;
uint32_t phy_init_script;
e1000_media_type media_type;
void *back;
+ struct e1000_shadow_ram *eeprom_shadow_ram;
+ uint32_t flash_bank_size;
+ uint32_t flash_base_addr;
e1000_fc_type fc;
e1000_bus_speed bus_speed;
e1000_bus_width bus_width;
@@ -1328,6 +1388,7 @@ struct e1000_hw {
uint32_t asf_firmware_present;
uint32_t eeprom_semaphore_present;
uint32_t swfw_sync_present;
+ uint32_t swfwhw_semaphore_present;
unsigned long io_base;
uint32_t phy_id;
uint32_t phy_revision;
@@ -1387,6 +1448,7 @@ struct e1000_hw {
boolean_t in_ifs_mode;
boolean_t mng_reg_access_disabled;
boolean_t leave_av_bit_off;
+ boolean_t kmrn_lock_loss_workaround_disabled;
};
@@ -1435,6 +1497,7 @@ struct e1000_hw {
#define E1000_CTRL_RTE 0x20000000 /* Routing tag enable */
#define E1000_CTRL_VME 0x40000000 /* IEEE VLAN mode enable */
#define E1000_CTRL_PHY_RST 0x80000000 /* PHY Reset */
+#define E1000_CTRL_SW2FW_INT 0x02000000 /* Initiate an interrupt to manageability engine */
/* Device Status */
#define E1000_STATUS_FD 0x00000001 /* Full duplex.0=half,1=full */
@@ -1449,6 +1512,8 @@ struct e1000_hw {
#define E1000_STATUS_SPEED_10 0x00000000 /* Speed 10Mb/s */
#define E1000_STATUS_SPEED_100 0x00000040 /* Speed 100Mb/s */
#define E1000_STATUS_SPEED_1000 0x00000080 /* Speed 1000Mb/s */
+#define E1000_STATUS_LAN_INIT_DONE 0x00000200 /* Lan Init Completion
+ by EEPROM/Flash */
#define E1000_STATUS_ASDV 0x00000300 /* Auto speed detect value */
#define E1000_STATUS_DOCK_CI 0x00000800 /* Change in Dock/Undock state. Clear on write '0'. */
#define E1000_STATUS_GIO_MASTER_ENABLE 0x00080000 /* Status of Master requests. */
@@ -1506,6 +1571,10 @@ struct e1000_hw {
#define E1000_STM_OPCODE 0xDB00
#define E1000_HICR_FW_RESET 0xC0
+#define E1000_SHADOW_RAM_WORDS 2048
+#define E1000_ICH8_NVM_SIG_WORD 0x13
+#define E1000_ICH8_NVM_SIG_MASK 0xC0
+
/* EEPROM Read */
#define E1000_EERD_START 0x00000001 /* Start Read */
#define E1000_EERD_DONE 0x00000010 /* Read Done */
@@ -1551,7 +1620,6 @@ struct e1000_hw {
#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
-#define E1000_CTRL_EXT_CANC 0x04000000 /* Interrupt delay cancellation */
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
@@ -1591,12 +1659,31 @@ struct e1000_hw {
#define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800
/* In-Band Control */
+#define E1000_KUMCTRLSTA_INB_CTRL_LINK_STATUS_TX_TIMEOUT_DEFAULT 0x00000500
#define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010
/* Half-Duplex Control */
#define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004
#define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000
+#define E1000_KUMCTRLSTA_OFFSET_K0S_CTRL 0x0000001E
+
+#define E1000_KUMCTRLSTA_DIAG_FELPBK 0x2000
+#define E1000_KUMCTRLSTA_DIAG_NELPBK 0x1000
+
+#define E1000_KUMCTRLSTA_K0S_100_EN 0x2000
+#define E1000_KUMCTRLSTA_K0S_GBE_EN 0x1000
+#define E1000_KUMCTRLSTA_K0S_ENTRY_LATENCY_MASK 0x0003
+
+#define E1000_KABGTXD_BGSQLBIAS 0x00050000
+
+#define E1000_PHY_CTRL_SPD_EN 0x00000001
+#define E1000_PHY_CTRL_D0A_LPLU 0x00000002
+#define E1000_PHY_CTRL_NOND0A_LPLU 0x00000004
+#define E1000_PHY_CTRL_NOND0A_GBE_DISABLE 0x00000008
+#define E1000_PHY_CTRL_GBE_DISABLE 0x00000040
+#define E1000_PHY_CTRL_B2B_EN 0x00000080
+
/* LED Control */
#define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F
#define E1000_LEDCTL_LED0_MODE_SHIFT 0
@@ -1666,6 +1753,9 @@ struct e1000_hw {
#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */
#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */
+#define E1000_ICR_DSW 0x00000020 /* FW changed the status of DISSW bit in the FWSM */
+#define E1000_ICR_PHYINT 0x00001000 /* LAN connected device generates an interrupt */
+#define E1000_ICR_EPRST 0x00100000 /* ME handware reset occurs */
/* Interrupt Cause Set */
#define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -1692,6 +1782,9 @@ struct e1000_hw {
#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_ICS_DSW E1000_ICR_DSW
+#define E1000_ICS_PHYINT E1000_ICR_PHYINT
+#define E1000_ICS_EPRST E1000_ICR_EPRST
/* Interrupt Mask Set */
#define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -1718,6 +1811,9 @@ struct e1000_hw {
#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMS_DSW E1000_ICR_DSW
+#define E1000_IMS_PHYINT E1000_ICR_PHYINT
+#define E1000_IMS_EPRST E1000_ICR_EPRST
/* Interrupt Mask Clear */
#define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */
@@ -1744,6 +1840,9 @@ struct e1000_hw {
#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */
#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */
#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */
+#define E1000_IMC_DSW E1000_ICR_DSW
+#define E1000_IMC_PHYINT E1000_ICR_PHYINT
+#define E1000_IMC_EPRST E1000_ICR_EPRST
/* Receive Control */
#define E1000_RCTL_RST 0x00000001 /* Software reset */
@@ -1918,9 +2017,10 @@ struct e1000_hw {
#define E1000_MRQC_RSS_FIELD_MASK 0xFFFF0000
#define E1000_MRQC_RSS_FIELD_IPV4_TCP 0x00010000
#define E1000_MRQC_RSS_FIELD_IPV4 0x00020000
-#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00040000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP_EX 0x00040000
#define E1000_MRQC_RSS_FIELD_IPV6_EX 0x00080000
#define E1000_MRQC_RSS_FIELD_IPV6 0x00100000
+#define E1000_MRQC_RSS_FIELD_IPV6_TCP 0x00200000
/* Definitions for power management and wakeup registers */
/* Wake Up Control */
@@ -1988,7 +2088,7 @@ struct e1000_hw {
#define E1000_MANC_EN_IP_ADDR_FILTER 0x00400000 /* Enable IP address
* filtering */
#define E1000_MANC_EN_XSUM_FILTER 0x00800000 /* Enable checksum filtering */
-#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
+#define E1000_MANC_BR_EN 0x01000000 /* Enable broadcast filtering */
#define E1000_MANC_SMB_REQ 0x01000000 /* SMBus Request */
#define E1000_MANC_SMB_GNT 0x02000000 /* SMBus Grant */
#define E1000_MANC_SMB_CLK_IN 0x04000000 /* SMBus Clock In */
@@ -2010,6 +2110,15 @@ struct e1000_hw {
#define E1000_FWSM_MODE_SHIFT 1
#define E1000_FWSM_FW_VALID 0x00008000 /* FW established a valid mode */
+#define E1000_FWSM_RSPCIPHY 0x00000040 /* Reset PHY on PCI reset */
+#define E1000_FWSM_DISSW 0x10000000 /* FW disable SW Write Access */
+#define E1000_FWSM_SKUSEL_MASK 0x60000000 /* LAN SKU select */
+#define E1000_FWSM_SKUEL_SHIFT 29
+#define E1000_FWSM_SKUSEL_EMB 0x0 /* Embedded SKU */
+#define E1000_FWSM_SKUSEL_CONS 0x1 /* Consumer SKU */
+#define E1000_FWSM_SKUSEL_PERF_100 0x2 /* Perf & Corp 10/100 SKU */
+#define E1000_FWSM_SKUSEL_PERF_GBE 0x3 /* Perf & Copr GbE SKU */
+
/* FFLT Debug Register */
#define E1000_FFLT_DBG_INVC 0x00100000 /* Invalid /C/ code handling */
@@ -2065,7 +2174,7 @@ struct e1000_host_command_info {
#define E1000_MDALIGN 4096
-/* PCI-Ex registers */
+/* PCI-Ex registers*/
/* PCI-Ex Control Register */
#define E1000_GCR_RXD_NO_SNOOP 0x00000001
@@ -2082,6 +2191,8 @@ struct e1000_host_command_info {
E1000_GCR_TXDSCW_NO_SNOOP | \
E1000_GCR_TXDSCR_NO_SNOOP)
+#define PCI_EX_82566_SNOOP_ALL PCI_EX_NO_SNOOP_ALL
+
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
/* Function Active and Power State to MNG */
#define E1000_FACTPS_FUNC0_POWER_STATE_MASK 0x00000003
@@ -2115,7 +2226,7 @@ struct e1000_host_command_info {
#define EEPROM_EWDS_OPCODE_MICROWIRE 0x10 /* EEPROM erast/write disable */
/* EEPROM Commands - SPI */
-#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
+#define EEPROM_MAX_RETRY_SPI 5000 /* Max wait of 5ms, for RDY signal */
#define EEPROM_READ_OPCODE_SPI 0x03 /* EEPROM read opcode */
#define EEPROM_WRITE_OPCODE_SPI 0x02 /* EEPROM write opcode */
#define EEPROM_A8_OPCODE_SPI 0x08 /* opcode bit-3 = address bit-8 */
@@ -2140,8 +2251,10 @@ struct e1000_host_command_info {
#define EEPROM_PHY_CLASS_WORD 0x0007
#define EEPROM_INIT_CONTROL1_REG 0x000A
#define EEPROM_INIT_CONTROL2_REG 0x000F
+#define EEPROM_SWDEF_PINS_CTRL_PORT_1 0x0010
#define EEPROM_INIT_CONTROL3_PORT_B 0x0014
#define EEPROM_INIT_3GIO_3 0x001A
+#define EEPROM_SWDEF_PINS_CTRL_PORT_0 0x0020
#define EEPROM_INIT_CONTROL3_PORT_A 0x0024
#define EEPROM_CFG 0x0012
#define EEPROM_FLASH_VERSION 0x0032
@@ -2153,10 +2266,16 @@ struct e1000_host_command_info {
/* Word definitions for ID LED Settings */
#define ID_LED_RESERVED_0000 0x0000
#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_RESERVED_82573 0xF746
+#define ID_LED_DEFAULT_82573 0x1811
#define ID_LED_DEFAULT ((ID_LED_OFF1_ON2 << 12) | \
(ID_LED_OFF1_OFF2 << 8) | \
(ID_LED_DEF1_DEF2 << 4) | \
(ID_LED_DEF1_DEF2))
+#define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \
+ (ID_LED_DEF1_OFF2 << 8) | \
+ (ID_LED_DEF1_ON2 << 4) | \
+ (ID_LED_DEF1_DEF2))
#define ID_LED_DEF1_DEF2 0x1
#define ID_LED_DEF1_ON2 0x2
#define ID_LED_DEF1_OFF2 0x3
@@ -2191,6 +2310,11 @@ struct e1000_host_command_info {
#define EEPROM_WORD0F_ASM_DIR 0x2000
#define EEPROM_WORD0F_ANE 0x0800
#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+#define EEPROM_WORD0F_LPLU 0x0001
+
+/* Mask bits for fields in Word 0x10/0x20 of the EEPROM */
+#define EEPROM_WORD1020_GIGA_DISABLE 0x0010
+#define EEPROM_WORD1020_GIGA_DISABLE_NON_D0A 0x0008
/* Mask bits for fields in Word 0x1a of the EEPROM */
#define EEPROM_WORD1A_ASPM_MASK 0x000C
@@ -2265,23 +2389,29 @@ struct e1000_host_command_info {
#define E1000_EXTCNF_CTRL_D_UD_OWNER 0x00000010
#define E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP 0x00000020
#define E1000_EXTCNF_CTRL_MDIO_HW_OWNERSHIP 0x00000040
-#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x1FFF0000
+#define E1000_EXTCNF_CTRL_EXT_CNF_POINTER 0x0FFF0000
#define E1000_EXTCNF_SIZE_EXT_PHY_LENGTH 0x000000FF
#define E1000_EXTCNF_SIZE_EXT_DOCK_LENGTH 0x0000FF00
#define E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH 0x00FF0000
+#define E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE 0x00000001
+#define E1000_EXTCNF_CTRL_SWFLAG 0x00000020
/* PBA constants */
+#define E1000_PBA_8K 0x0008 /* 8KB, default Rx allocation */
#define E1000_PBA_12K 0x000C /* 12KB, default Rx allocation */
#define E1000_PBA_16K 0x0010 /* 16KB, default TX allocation */
#define E1000_PBA_22K 0x0016
#define E1000_PBA_24K 0x0018
#define E1000_PBA_30K 0x001E
#define E1000_PBA_32K 0x0020
+#define E1000_PBA_34K 0x0022
#define E1000_PBA_38K 0x0026
#define E1000_PBA_40K 0x0028
#define E1000_PBA_48K 0x0030 /* 48KB, default RX allocation */
+#define E1000_PBS_16K E1000_PBA_16K
+
/* Flow Control Constants */
#define FLOW_CONTROL_ADDRESS_LOW 0x00C28001
#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
@@ -2336,7 +2466,7 @@ struct e1000_host_command_info {
/* Number of milliseconds we wait for Eeprom auto read bit done after MAC reset */
#define AUTO_READ_DONE_TIMEOUT 10
/* Number of milliseconds we wait for PHY configuration done after MAC reset */
-#define PHY_CFG_TIMEOUT 40
+#define PHY_CFG_TIMEOUT 100
#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
@@ -2764,6 +2894,17 @@ struct e1000_host_command_info {
#define M88E1000_EPSCR_TX_CLK_25 0x0070 /* 25 MHz TX_CLK */
#define M88E1000_EPSCR_TX_CLK_0 0x0000 /* NO TX_CLK */
+/* M88EC018 Rev 2 specific DownShift settings */
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_MASK 0x0E00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_1X 0x0000
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_2X 0x0200
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_3X 0x0400
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_4X 0x0600
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_5X 0x0800
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_6X 0x0A00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_7X 0x0C00
+#define M88EC018_EPSCR_DOWNSHIFT_COUNTER_8X 0x0E00
+
/* IGP01E1000 Specific Port Config Register - R/W */
#define IGP01E1000_PSCFR_AUTO_MDIX_PAR_DETECT 0x0010
#define IGP01E1000_PSCFR_PRE_EN 0x0020
@@ -2943,10 +3084,10 @@ struct e1000_host_command_info {
/* DSP Distance Register (Page 5, Register 26) */
#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M;
- 1 = 50-80M;
- 2 = 80-110M;
- 3 = 110-140M;
- 4 = >140M */
+ 1 = 50-80M;
+ 2 = 80-110M;
+ 3 = 110-140M;
+ 4 = >140M */
/* Kumeran Mode Control Register (Page 193, Register 16) */
#define GG82563_KMCR_PHY_LEDS_EN 0x0020 /* 1=PHY LEDs, 0=Kumeran Inband LEDs */
@@ -2990,6 +3131,221 @@ struct e1000_host_command_info {
#define L1LXT971A_PHY_ID 0x001378E0
#define GG82563_E_PHY_ID 0x01410CA0
+
+/* Bits...
+ * 15-5: page
+ * 4-0: register offset
+ */
+#define PHY_PAGE_SHIFT 5
+#define PHY_REG(page, reg) \
+ (((page) << PHY_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS))
+
+#define IGP3_PHY_PORT_CTRL \
+ PHY_REG(769, 17) /* Port General Configuration */
+#define IGP3_PHY_RATE_ADAPT_CTRL \
+ PHY_REG(769, 25) /* Rate Adapter Control Register */
+
+#define IGP3_KMRN_FIFO_CTRL_STATS \
+ PHY_REG(770, 16) /* KMRN FIFO's control/status register */
+#define IGP3_KMRN_POWER_MNG_CTRL \
+ PHY_REG(770, 17) /* KMRN Power Management Control Register */
+#define IGP3_KMRN_INBAND_CTRL \
+ PHY_REG(770, 18) /* KMRN Inband Control Register */
+#define IGP3_KMRN_DIAG \
+ PHY_REG(770, 19) /* KMRN Diagnostic register */
+#define IGP3_KMRN_DIAG_PCS_LOCK_LOSS 0x0002 /* RX PCS is not synced */
+#define IGP3_KMRN_ACK_TIMEOUT \
+ PHY_REG(770, 20) /* KMRN Acknowledge Timeouts register */
+
+#define IGP3_VR_CTRL \
+ PHY_REG(776, 18) /* Voltage regulator control register */
+#define IGP3_VR_CTRL_MODE_SHUT 0x0200 /* Enter powerdown, shutdown VRs */
+
+#define IGP3_CAPABILITY \
+ PHY_REG(776, 19) /* IGP3 Capability Register */
+
+/* Capabilities for SKU Control */
+#define IGP3_CAP_INITIATE_TEAM 0x0001 /* Able to initiate a team */
+#define IGP3_CAP_WFM 0x0002 /* Support WoL and PXE */
+#define IGP3_CAP_ASF 0x0004 /* Support ASF */
+#define IGP3_CAP_LPLU 0x0008 /* Support Low Power Link Up */
+#define IGP3_CAP_DC_AUTO_SPEED 0x0010 /* Support AC/DC Auto Link Speed */
+#define IGP3_CAP_SPD 0x0020 /* Support Smart Power Down */
+#define IGP3_CAP_MULT_QUEUE 0x0040 /* Support 2 tx & 2 rx queues */
+#define IGP3_CAP_RSS 0x0080 /* Support RSS */
+#define IGP3_CAP_8021PQ 0x0100 /* Support 802.1Q & 802.1p */
+#define IGP3_CAP_AMT_CB 0x0200 /* Support active manageability and circuit breaker */
+
+#define IGP3_PPC_JORDAN_EN 0x0001
+#define IGP3_PPC_JORDAN_GIGA_SPEED 0x0002
+
+#define IGP3_KMRN_PMC_EE_IDLE_LINK_DIS 0x0001
+#define IGP3_KMRN_PMC_K0S_ENTRY_LATENCY_MASK 0x001E
+#define IGP3_KMRN_PMC_K0S_MODE1_EN_GIGA 0x0020
+#define IGP3_KMRN_PMC_K0S_MODE1_EN_100 0x0040
+
+#define IGP3E1000_PHY_MISC_CTRL 0x1B /* Misc. Ctrl register */
+#define IGP3_PHY_MISC_DUPLEX_MANUAL_SET 0x1000 /* Duplex Manual Set */
+
+#define IGP3_KMRN_EXT_CTRL PHY_REG(770, 18)
+#define IGP3_KMRN_EC_DIS_INBAND 0x0080
+
+#define IGP03E1000_E_PHY_ID 0x02A80390
+#define IFE_E_PHY_ID 0x02A80330 /* 10/100 PHY */
+#define IFE_PLUS_E_PHY_ID 0x02A80320
+#define IFE_C_E_PHY_ID 0x02A80310
+
+#define IFE_PHY_EXTENDED_STATUS_CONTROL 0x10 /* 100BaseTx Extended Status, Control and Address */
+#define IFE_PHY_SPECIAL_CONTROL 0x11 /* 100BaseTx PHY special control register */
+#define IFE_PHY_RCV_FALSE_CARRIER 0x13 /* 100BaseTx Receive False Carrier Counter */
+#define IFE_PHY_RCV_DISCONNECT 0x14 /* 100BaseTx Receive Disconnet Counter */
+#define IFE_PHY_RCV_ERROT_FRAME 0x15 /* 100BaseTx Receive Error Frame Counter */
+#define IFE_PHY_RCV_SYMBOL_ERR 0x16 /* Receive Symbol Error Counter */
+#define IFE_PHY_PREM_EOF_ERR 0x17 /* 100BaseTx Receive Premature End Of Frame Error Counter */
+#define IFE_PHY_RCV_EOF_ERR 0x18 /* 10BaseT Receive End Of Frame Error Counter */
+#define IFE_PHY_TX_JABBER_DETECT 0x19 /* 10BaseT Transmit Jabber Detect Counter */
+#define IFE_PHY_EQUALIZER 0x1A /* PHY Equalizer Control and Status */
+#define IFE_PHY_SPECIAL_CONTROL_LED 0x1B /* PHY special control and LED configuration */
+#define IFE_PHY_MDIX_CONTROL 0x1C /* MDI/MDI-X Control register */
+#define IFE_PHY_HWI_CONTROL 0x1D /* Hardware Integrity Control (HWI) */
+
+#define IFE_PESC_REDUCED_POWER_DOWN_DISABLE 0x2000 /* Defaut 1 = Disable auto reduced power down */
+#define IFE_PESC_100BTX_POWER_DOWN 0x0400 /* Indicates the power state of 100BASE-TX */
+#define IFE_PESC_10BTX_POWER_DOWN 0x0200 /* Indicates the power state of 10BASE-T */
+#define IFE_PESC_POLARITY_REVERSED 0x0100 /* Indicates 10BASE-T polarity */
+#define IFE_PESC_PHY_ADDR_MASK 0x007C /* Bit 6:2 for sampled PHY address */
+#define IFE_PESC_SPEED 0x0002 /* Auto-negotiation speed result 1=100Mbs, 0=10Mbs */
+#define IFE_PESC_DUPLEX 0x0001 /* Auto-negotiation duplex result 1=Full, 0=Half */
+#define IFE_PESC_POLARITY_REVERSED_SHIFT 8
+
+#define IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN 0x0100 /* 1 = Dyanmic Power Down disabled */
+#define IFE_PSC_FORCE_POLARITY 0x0020 /* 1=Reversed Polarity, 0=Normal */
+#define IFE_PSC_AUTO_POLARITY_DISABLE 0x0010 /* 1=Auto Polarity Disabled, 0=Enabled */
+#define IFE_PSC_JABBER_FUNC_DISABLE 0x0001 /* 1=Jabber Disabled, 0=Normal Jabber Operation */
+#define IFE_PSC_FORCE_POLARITY_SHIFT 5
+#define IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT 4
+
+#define IFE_PMC_AUTO_MDIX 0x0080 /* 1=enable MDI/MDI-X feature, default 0=disabled */
+#define IFE_PMC_FORCE_MDIX 0x0040 /* 1=force MDIX-X, 0=force MDI */
+#define IFE_PMC_MDIX_STATUS 0x0020 /* 1=MDI-X, 0=MDI */
+#define IFE_PMC_AUTO_MDIX_COMPLETE 0x0010 /* Resolution algorthm is completed */
+#define IFE_PMC_MDIX_MODE_SHIFT 6
+#define IFE_PHC_MDIX_RESET_ALL_MASK 0x0000 /* Disable auto MDI-X */
+
+#define IFE_PHC_HWI_ENABLE 0x8000 /* Enable the HWI feature */
+#define IFE_PHC_ABILITY_CHECK 0x4000 /* 1= Test Passed, 0=failed */
+#define IFE_PHC_TEST_EXEC 0x2000 /* PHY launch test pulses on the wire */
+#define IFE_PHC_HIGHZ 0x0200 /* 1 = Open Circuit */
+#define IFE_PHC_LOWZ 0x0400 /* 1 = Short Circuit */
+#define IFE_PHC_LOW_HIGH_Z_MASK 0x0600 /* Mask for indication type of problem on the line */
+#define IFE_PHC_DISTANCE_MASK 0x01FF /* Mask for distance to the cable problem, in 80cm granularity */
+#define IFE_PHC_RESET_ALL_MASK 0x0000 /* Disable HWI */
+#define IFE_PSCL_PROBE_MODE 0x0020 /* LED Probe mode */
+#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
+#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
+
+#define ICH8_FLASH_COMMAND_TIMEOUT 500 /* 500 ms , should be adjusted */
+#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles , should be adjusted */
+#define ICH8_FLASH_SEG_SIZE_256 256
+#define ICH8_FLASH_SEG_SIZE_4K 4096
+#define ICH8_FLASH_SEG_SIZE_64K 65536
+
+#define ICH8_CYCLE_READ 0x0
+#define ICH8_CYCLE_RESERVED 0x1
+#define ICH8_CYCLE_WRITE 0x2
+#define ICH8_CYCLE_ERASE 0x3
+
+#define ICH8_FLASH_GFPREG 0x0000
+#define ICH8_FLASH_HSFSTS 0x0004
+#define ICH8_FLASH_HSFCTL 0x0006
+#define ICH8_FLASH_FADDR 0x0008
+#define ICH8_FLASH_FDATA0 0x0010
+#define ICH8_FLASH_FRACC 0x0050
+#define ICH8_FLASH_FREG0 0x0054
+#define ICH8_FLASH_FREG1 0x0058
+#define ICH8_FLASH_FREG2 0x005C
+#define ICH8_FLASH_FREG3 0x0060
+#define ICH8_FLASH_FPR0 0x0074
+#define ICH8_FLASH_FPR1 0x0078
+#define ICH8_FLASH_SSFSTS 0x0090
+#define ICH8_FLASH_SSFCTL 0x0092
+#define ICH8_FLASH_PREOP 0x0094
+#define ICH8_FLASH_OPTYPE 0x0096
+#define ICH8_FLASH_OPMENU 0x0098
+
+#define ICH8_FLASH_REG_MAPSIZE 0x00A0
+#define ICH8_FLASH_SECTOR_SIZE 4096
+#define ICH8_GFPREG_BASE_MASK 0x1FFF
+#define ICH8_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
+
+/* ICH8 GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
+/* Offset 04h HSFSTS */
+union ich8_hws_flash_status {
+ struct ich8_hsfsts {
+#ifdef E1000_BIG_ENDIAN
+ uint16_t reserved2 :6;
+ uint16_t fldesvalid :1;
+ uint16_t flockdn :1;
+ uint16_t flcdone :1;
+ uint16_t flcerr :1;
+ uint16_t dael :1;
+ uint16_t berasesz :2;
+ uint16_t flcinprog :1;
+ uint16_t reserved1 :2;
+#else
+ uint16_t flcdone :1; /* bit 0 Flash Cycle Done */
+ uint16_t flcerr :1; /* bit 1 Flash Cycle Error */
+ uint16_t dael :1; /* bit 2 Direct Access error Log */
+ uint16_t berasesz :2; /* bit 4:3 Block/Sector Erase Size */
+ uint16_t flcinprog :1; /* bit 5 flash SPI cycle in Progress */
+ uint16_t reserved1 :2; /* bit 13:6 Reserved */
+ uint16_t reserved2 :6; /* bit 13:6 Reserved */
+ uint16_t fldesvalid :1; /* bit 14 Flash Descriptor Valid */
+ uint16_t flockdn :1; /* bit 15 Flash Configuration Lock-Down */
+#endif
+ } hsf_status;
+ uint16_t regval;
+};
+
+/* ICH8 GbE Flash Hardware Sequencing Flash control Register bit breakdown */
+/* Offset 06h FLCTL */
+union ich8_hws_flash_ctrl {
+ struct ich8_hsflctl {
+#ifdef E1000_BIG_ENDIAN
+ uint16_t fldbcount :2;
+ uint16_t flockdn :6;
+ uint16_t flcgo :1;
+ uint16_t flcycle :2;
+ uint16_t reserved :5;
+#else
+ uint16_t flcgo :1; /* 0 Flash Cycle Go */
+ uint16_t flcycle :2; /* 2:1 Flash Cycle */
+ uint16_t reserved :5; /* 7:3 Reserved */
+ uint16_t fldbcount :2; /* 9:8 Flash Data Byte Count */
+ uint16_t flockdn :6; /* 15:10 Reserved */
+#endif
+ } hsf_ctrl;
+ uint16_t regval;
+};
+
+/* ICH8 Flash Region Access Permissions */
+union ich8_hws_flash_regacc {
+ struct ich8_flracc {
+#ifdef E1000_BIG_ENDIAN
+ uint32_t gmwag :8;
+ uint32_t gmrag :8;
+ uint32_t grwa :8;
+ uint32_t grra :8;
+#else
+ uint32_t grra :8; /* 0:7 GbE region Read Access */
+ uint32_t grwa :8; /* 8:15 GbE region Write Access */
+ uint32_t gmrag :8; /* 23:16 GbE Master Read Access Grant */
+ uint32_t gmwag :8; /* 31:24 GbE Master Write Access Grant */
+#endif
+ } hsf_flregacc;
+ uint16_t regval;
+};
+
/* Miscellaneous PHY bit definitions. */
#define PHY_PREAMBLE 0xFFFFFFFF
#define PHY_SOF 0x01
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 32b7d444b37..3f6a752700a 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "7.0.38-k4"DRIVERNAPI
+#define DRV_VERSION "7.2.7-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -73,6 +73,11 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x1026),
INTEL_E1000_ETHERNET_DEVICE(0x1027),
INTEL_E1000_ETHERNET_DEVICE(0x1028),
+ INTEL_E1000_ETHERNET_DEVICE(0x1049),
+ INTEL_E1000_ETHERNET_DEVICE(0x104A),
+ INTEL_E1000_ETHERNET_DEVICE(0x104B),
+ INTEL_E1000_ETHERNET_DEVICE(0x104C),
+ INTEL_E1000_ETHERNET_DEVICE(0x104D),
INTEL_E1000_ETHERNET_DEVICE(0x105E),
INTEL_E1000_ETHERNET_DEVICE(0x105F),
INTEL_E1000_ETHERNET_DEVICE(0x1060),
@@ -94,8 +99,11 @@ static struct pci_device_id e1000_pci_tbl[] = {
INTEL_E1000_ETHERNET_DEVICE(0x1098),
INTEL_E1000_ETHERNET_DEVICE(0x1099),
INTEL_E1000_ETHERNET_DEVICE(0x109A),
+ INTEL_E1000_ETHERNET_DEVICE(0x10A4),
INTEL_E1000_ETHERNET_DEVICE(0x10B5),
INTEL_E1000_ETHERNET_DEVICE(0x10B9),
+ INTEL_E1000_ETHERNET_DEVICE(0x10BA),
+ INTEL_E1000_ETHERNET_DEVICE(0x10BB),
/* required last entry */
{0,}
};
@@ -133,7 +141,6 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
static void e1000_set_multi(struct net_device *netdev);
static void e1000_update_phy_info(unsigned long data);
static void e1000_watchdog(unsigned long data);
-static void e1000_watchdog_task(struct e1000_adapter *adapter);
static void e1000_82547_tx_fifo_stall(unsigned long data);
static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
@@ -178,8 +185,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
static void e1000_restore_vlan(struct e1000_adapter *adapter);
-#ifdef CONFIG_PM
static int e1000_suspend(struct pci_dev *pdev, pm_message_t state);
+#ifdef CONFIG_PM
static int e1000_resume(struct pci_dev *pdev);
#endif
static void e1000_shutdown(struct pci_dev *pdev);
@@ -206,8 +213,8 @@ static struct pci_driver e1000_driver = {
.probe = e1000_probe,
.remove = __devexit_p(e1000_remove),
/* Power Managment Hooks */
-#ifdef CONFIG_PM
.suspend = e1000_suspend,
+#ifdef CONFIG_PM
.resume = e1000_resume,
#endif
.shutdown = e1000_shutdown,
@@ -239,7 +246,7 @@ e1000_init_module(void)
printk(KERN_INFO "%s\n", e1000_copyright);
- ret = pci_module_init(&e1000_driver);
+ ret = pci_register_driver(&e1000_driver);
return ret;
}
@@ -261,6 +268,44 @@ e1000_exit_module(void)
module_exit(e1000_exit_module);
+static int e1000_request_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+ int flags, err = 0;
+
+ flags = IRQF_SHARED;
+#ifdef CONFIG_PCI_MSI
+ if (adapter->hw.mac_type > e1000_82547_rev_2) {
+ adapter->have_msi = TRUE;
+ if ((err = pci_enable_msi(adapter->pdev))) {
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate MSI interrupt Error: %d\n", err);
+ adapter->have_msi = FALSE;
+ }
+ }
+ if (adapter->have_msi)
+ flags &= ~IRQF_SHARED;
+#endif
+ if ((err = request_irq(adapter->pdev->irq, &e1000_intr, flags,
+ netdev->name, netdev)))
+ DPRINTK(PROBE, ERR,
+ "Unable to allocate interrupt Error: %d\n", err);
+
+ return err;
+}
+
+static void e1000_free_irq(struct e1000_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ free_irq(adapter->pdev->irq, netdev);
+
+#ifdef CONFIG_PCI_MSI
+ if (adapter->have_msi)
+ pci_disable_msi(adapter->pdev);
+#endif
+}
+
/**
* e1000_irq_disable - Mask off interrupt generation on the NIC
* @adapter: board private structure
@@ -329,6 +374,7 @@ e1000_release_hw_control(struct e1000_adapter *adapter)
{
uint32_t ctrl_ext;
uint32_t swsm;
+ uint32_t extcnf;
/* Let firmware taken over control of h/w */
switch (adapter->hw.mac_type) {
@@ -343,6 +389,11 @@ e1000_release_hw_control(struct e1000_adapter *adapter)
swsm = E1000_READ_REG(&adapter->hw, SWSM);
E1000_WRITE_REG(&adapter->hw, SWSM,
swsm & ~E1000_SWSM_DRV_LOAD);
+ case e1000_ich8lan:
+ extcnf = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+ E1000_WRITE_REG(&adapter->hw, CTRL_EXT,
+ extcnf & ~E1000_CTRL_EXT_DRV_LOAD);
+ break;
default:
break;
}
@@ -364,6 +415,7 @@ e1000_get_hw_control(struct e1000_adapter *adapter)
{
uint32_t ctrl_ext;
uint32_t swsm;
+ uint32_t extcnf;
/* Let firmware know the driver has taken over */
switch (adapter->hw.mac_type) {
case e1000_82571:
@@ -378,6 +430,11 @@ e1000_get_hw_control(struct e1000_adapter *adapter)
E1000_WRITE_REG(&adapter->hw, SWSM,
swsm | E1000_SWSM_DRV_LOAD);
break;
+ case e1000_ich8lan:
+ extcnf = E1000_READ_REG(&adapter->hw, EXTCNF_CTRL);
+ E1000_WRITE_REG(&adapter->hw, EXTCNF_CTRL,
+ extcnf | E1000_EXTCNF_CTRL_SWFLAG);
+ break;
default:
break;
}
@@ -387,18 +444,10 @@ int
e1000_up(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- int i, err;
+ int i;
/* hardware has been reset, we need to reload some things */
- /* Reset the PHY if it was previously powered down */
- if (adapter->hw.media_type == e1000_media_type_copper) {
- uint16_t mii_reg;
- e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
- if (mii_reg & MII_CR_POWER_DOWN)
- e1000_phy_hw_reset(&adapter->hw);
- }
-
e1000_set_multi(netdev);
e1000_restore_vlan(adapter);
@@ -415,24 +464,6 @@ e1000_up(struct e1000_adapter *adapter)
E1000_DESC_UNUSED(ring));
}
-#ifdef CONFIG_PCI_MSI
- if (adapter->hw.mac_type > e1000_82547_rev_2) {
- adapter->have_msi = TRUE;
- if ((err = pci_enable_msi(adapter->pdev))) {
- DPRINTK(PROBE, ERR,
- "Unable to allocate MSI interrupt Error: %d\n", err);
- adapter->have_msi = FALSE;
- }
- }
-#endif
- if ((err = request_irq(adapter->pdev->irq, &e1000_intr,
- SA_SHIRQ | SA_SAMPLE_RANDOM,
- netdev->name, netdev))) {
- DPRINTK(PROBE, ERR,
- "Unable to allocate interrupt Error: %d\n", err);
- return err;
- }
-
adapter->tx_queue_len = netdev->tx_queue_len;
mod_timer(&adapter->watchdog_timer, jiffies);
@@ -445,21 +476,60 @@ e1000_up(struct e1000_adapter *adapter)
return 0;
}
+/**
+ * e1000_power_up_phy - restore link in case the phy was powered down
+ * @adapter: address of board private structure
+ *
+ * The phy may be powered down to save power and turn off link when the
+ * driver is unloaded and wake on lan is not enabled (among others)
+ * *** this routine MUST be followed by a call to e1000_reset ***
+ *
+ **/
+
+void e1000_power_up_phy(struct e1000_adapter *adapter)
+{
+ uint16_t mii_reg = 0;
+
+ /* Just clear the power down bit to wake the phy back up */
+ if (adapter->hw.media_type == e1000_media_type_copper) {
+ /* according to the manual, the phy will retain its
+ * settings across a power-down/up cycle */
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+ mii_reg &= ~MII_CR_POWER_DOWN;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+ }
+}
+
+static void e1000_power_down_phy(struct e1000_adapter *adapter)
+{
+ boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
+ e1000_check_mng_mode(&adapter->hw);
+ /* Power down the PHY so no link is implied when interface is down
+ * The PHY cannot be powered down if any of the following is TRUE
+ * (a) WoL is enabled
+ * (b) AMT is active
+ * (c) SoL/IDER session is active */
+ if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
+ adapter->hw.media_type == e1000_media_type_copper &&
+ !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
+ !mng_mode_enabled &&
+ !e1000_check_phy_reset_block(&adapter->hw)) {
+ uint16_t mii_reg = 0;
+ e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
+ mii_reg |= MII_CR_POWER_DOWN;
+ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
+ mdelay(1);
+ }
+}
+
void
e1000_down(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
- boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
- e1000_check_mng_mode(&adapter->hw);
e1000_irq_disable(adapter);
- free_irq(adapter->pdev->irq, netdev);
-#ifdef CONFIG_PCI_MSI
- if (adapter->hw.mac_type > e1000_82547_rev_2 &&
- adapter->have_msi == TRUE)
- pci_disable_msi(adapter->pdev);
-#endif
del_timer_sync(&adapter->tx_fifo_stall_timer);
del_timer_sync(&adapter->watchdog_timer);
del_timer_sync(&adapter->phy_info_timer);
@@ -476,23 +546,17 @@ e1000_down(struct e1000_adapter *adapter)
e1000_reset(adapter);
e1000_clean_all_tx_rings(adapter);
e1000_clean_all_rx_rings(adapter);
+}
- /* Power down the PHY so no link is implied when interface is down *
- * The PHY cannot be powered down if any of the following is TRUE *
- * (a) WoL is enabled
- * (b) AMT is active
- * (c) SoL/IDER session is active */
- if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
- adapter->hw.media_type == e1000_media_type_copper &&
- !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
- !mng_mode_enabled &&
- !e1000_check_phy_reset_block(&adapter->hw)) {
- uint16_t mii_reg;
- e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
- mii_reg |= MII_CR_POWER_DOWN;
- e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
- mdelay(1);
- }
+void
+e1000_reinit_locked(struct e1000_adapter *adapter)
+{
+ WARN_ON(in_interrupt());
+ while (test_and_set_bit(__E1000_RESETTING, &adapter->flags))
+ msleep(1);
+ e1000_down(adapter);
+ e1000_up(adapter);
+ clear_bit(__E1000_RESETTING, &adapter->flags);
}
void
@@ -518,6 +582,9 @@ e1000_reset(struct e1000_adapter *adapter)
case e1000_82573:
pba = E1000_PBA_12K;
break;
+ case e1000_ich8lan:
+ pba = E1000_PBA_8K;
+ break;
default:
pba = E1000_PBA_48K;
break;
@@ -542,6 +609,12 @@ e1000_reset(struct e1000_adapter *adapter)
/* Set the FC high water mark to 90% of the FIFO size.
* Required to clear last 3 LSB */
fc_high_water_mark = ((pba * 9216)/10) & 0xFFF8;
+ /* We can't use 90% on small FIFOs because the remainder
+ * would be less than 1 full frame. In this case, we size
+ * it to allow at least a full frame above the high water
+ * mark. */
+ if (pba < E1000_PBA_16K)
+ fc_high_water_mark = (pba * 1024) - 1600;
adapter->hw.fc_high_water = fc_high_water_mark;
adapter->hw.fc_low_water = fc_high_water_mark - 8;
@@ -564,6 +637,23 @@ e1000_reset(struct e1000_adapter *adapter)
e1000_reset_adaptive(&adapter->hw);
e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+
+ if (!adapter->smart_power_down &&
+ (adapter->hw.mac_type == e1000_82571 ||
+ adapter->hw.mac_type == e1000_82572)) {
+ uint16_t phy_data = 0;
+ /* speed up time to link by disabling smart power down, ignore
+ * the return value of this function because there is nothing
+ * different we would do if it failed */
+ e1000_read_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
+ &phy_data);
+ phy_data &= ~IGP02E1000_PM_SPD;
+ e1000_write_phy_reg(&adapter->hw, IGP02E1000_PHY_POWER_MGMT,
+ phy_data);
+ }
+
+ if (adapter->hw.mac_type < e1000_ich8lan)
+ /* FIXME: this code is duplicate and wrong for PCI Express */
if (adapter->en_mng_pt) {
manc = E1000_READ_REG(&adapter->hw, MANC);
manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
@@ -590,35 +680,37 @@ e1000_probe(struct pci_dev *pdev,
struct net_device *netdev;
struct e1000_adapter *adapter;
unsigned long mmio_start, mmio_len;
+ unsigned long flash_start, flash_len;
static int cards_found = 0;
- static int e1000_ksp3_port_a = 0; /* global ksp3 port a indication */
+ static int global_quad_port_a = 0; /* global ksp3 port a indication */
int i, err, pci_using_dac;
- uint16_t eeprom_data;
+ uint16_t eeprom_data = 0;
uint16_t eeprom_apme_mask = E1000_EEPROM_APME;
if ((err = pci_enable_device(pdev)))
return err;
- if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
+ if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) &&
+ !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) {
pci_using_dac = 1;
} else {
- if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) &&
+ (err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))) {
E1000_ERR("No usable DMA configuration, aborting\n");
- return err;
+ goto err_dma;
}
pci_using_dac = 0;
}
if ((err = pci_request_regions(pdev, e1000_driver_name)))
- return err;
+ goto err_pci_reg;
pci_set_master(pdev);
+ err = -ENOMEM;
netdev = alloc_etherdev(sizeof(struct e1000_adapter));
- if (!netdev) {
- err = -ENOMEM;
+ if (!netdev)
goto err_alloc_etherdev;
- }
SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &pdev->dev);
@@ -633,11 +725,10 @@ e1000_probe(struct pci_dev *pdev,
mmio_start = pci_resource_start(pdev, BAR_0);
mmio_len = pci_resource_len(pdev, BAR_0);
+ err = -EIO;
adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
- if (!adapter->hw.hw_addr) {
- err = -EIO;
+ if (!adapter->hw.hw_addr)
goto err_ioremap;
- }
for (i = BAR_1; i <= BAR_5; i++) {
if (pci_resource_len(pdev, i) == 0)
@@ -682,17 +773,20 @@ e1000_probe(struct pci_dev *pdev,
if ((err = e1000_sw_init(adapter)))
goto err_sw_init;
- if ((err = e1000_check_phy_reset_block(&adapter->hw)))
- DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
+ err = -EIO;
+ /* Flash BAR mapping must happen after e1000_sw_init
+ * because it depends on mac_type */
+ if ((adapter->hw.mac_type == e1000_ich8lan) &&
+ (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+ flash_start = pci_resource_start(pdev, 1);
+ flash_len = pci_resource_len(pdev, 1);
+ adapter->hw.flash_address = ioremap(flash_start, flash_len);
+ if (!adapter->hw.flash_address)
+ goto err_flashmap;
+ }
- /* if ksp3, indicate if it's port a being setup */
- if (pdev->device == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 &&
- e1000_ksp3_port_a == 0)
- adapter->ksp3_port_a = 1;
- e1000_ksp3_port_a++;
- /* Reset for multiple KP3 adapters */
- if (e1000_ksp3_port_a == 4)
- e1000_ksp3_port_a = 0;
+ if (e1000_check_phy_reset_block(&adapter->hw))
+ DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n");
if (adapter->hw.mac_type >= e1000_82543) {
netdev->features = NETIF_F_SG |
@@ -700,6 +794,8 @@ e1000_probe(struct pci_dev *pdev,
NETIF_F_HW_VLAN_TX |
NETIF_F_HW_VLAN_RX |
NETIF_F_HW_VLAN_FILTER;
+ if (adapter->hw.mac_type == e1000_ich8lan)
+ netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
}
#ifdef NETIF_F_TSO
@@ -715,11 +811,17 @@ e1000_probe(struct pci_dev *pdev,
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
- /* hard_start_xmit is safe against parallel locking */
netdev->features |= NETIF_F_LLTX;
adapter->en_mng_pt = e1000_enable_mng_pass_thru(&adapter->hw);
+ /* initialize eeprom parameters */
+
+ if (e1000_init_eeprom_params(&adapter->hw)) {
+ E1000_ERR("EEPROM initialization failed\n");
+ goto err_eeprom;
+ }
+
/* before reading the EEPROM, reset the controller to
* put the device in a known good starting state */
@@ -729,7 +831,6 @@ e1000_probe(struct pci_dev *pdev,
if (e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
DPRINTK(PROBE, ERR, "The EEPROM Checksum Is Not Valid\n");
- err = -EIO;
goto err_eeprom;
}
@@ -742,12 +843,9 @@ e1000_probe(struct pci_dev *pdev,
if (!is_valid_ether_addr(netdev->perm_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC Address\n");
- err = -EIO;
goto err_eeprom;
}
- e1000_read_part_num(&adapter->hw, &(adapter->part_num));
-
e1000_get_bus_info(&adapter->hw);
init_timer(&adapter->tx_fifo_stall_timer);
@@ -758,9 +856,6 @@ e1000_probe(struct pci_dev *pdev,
adapter->watchdog_timer.function = &e1000_watchdog;
adapter->watchdog_timer.data = (unsigned long) adapter;
- INIT_WORK(&adapter->watchdog_task,
- (void (*)(void *))e1000_watchdog_task, adapter);
-
init_timer(&adapter->phy_info_timer);
adapter->phy_info_timer.function = &e1000_update_phy_info;
adapter->phy_info_timer.data = (unsigned long) adapter;
@@ -790,6 +885,11 @@ e1000_probe(struct pci_dev *pdev,
EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
eeprom_apme_mask = E1000_EEPROM_82544_APM;
break;
+ case e1000_ich8lan:
+ e1000_read_eeprom(&adapter->hw,
+ EEPROM_INIT_CONTROL1_REG, 1, &eeprom_data);
+ eeprom_apme_mask = E1000_EEPROM_ICH8_APME;
+ break;
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82571:
@@ -806,7 +906,38 @@ e1000_probe(struct pci_dev *pdev,
break;
}
if (eeprom_data & eeprom_apme_mask)
- adapter->wol |= E1000_WUFC_MAG;
+ adapter->eeprom_wol |= E1000_WUFC_MAG;
+
+ /* now that we have the eeprom settings, apply the special cases
+ * where the eeprom may be wrong or the board simply won't support
+ * wake on lan on a particular port */
+ switch (pdev->device) {
+ case E1000_DEV_ID_82546GB_PCIE:
+ adapter->eeprom_wol = 0;
+ break;
+ case E1000_DEV_ID_82546EB_FIBER:
+ case E1000_DEV_ID_82546GB_FIBER:
+ case E1000_DEV_ID_82571EB_FIBER:
+ /* Wake events only supported on port A for dual fiber
+ * regardless of eeprom setting */
+ if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1)
+ adapter->eeprom_wol = 0;
+ break;
+ case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3:
+ case E1000_DEV_ID_82571EB_QUAD_COPPER:
+ /* if quad port adapter, disable WoL on all but port A */
+ if (global_quad_port_a != 0)
+ adapter->eeprom_wol = 0;
+ else
+ adapter->quad_port_a = 1;
+ /* Reset for multiple quad port adapters */
+ if (++global_quad_port_a == 4)
+ global_quad_port_a = 0;
+ break;
+ }
+
+ /* initialize the wol settings based on the eeprom settings */
+ adapter->wol = adapter->eeprom_wol;
/* print bus type/speed/width info */
{
@@ -849,13 +980,33 @@ e1000_probe(struct pci_dev *pdev,
return 0;
err_register:
-err_sw_init:
+ e1000_release_hw_control(adapter);
err_eeprom:
+ if (!e1000_check_phy_reset_block(&adapter->hw))
+ e1000_phy_hw_reset(&adapter->hw);
+
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
+err_flashmap:
+#ifdef CONFIG_E1000_NAPI
+ for (i = 0; i < adapter->num_rx_queues; i++)
+ dev_put(&adapter->polling_netdev[i]);
+#endif
+
+ kfree(adapter->tx_ring);
+ kfree(adapter->rx_ring);
+#ifdef CONFIG_E1000_NAPI
+ kfree(adapter->polling_netdev);
+#endif
+err_sw_init:
iounmap(adapter->hw.hw_addr);
err_ioremap:
free_netdev(netdev);
err_alloc_etherdev:
pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+ pci_disable_device(pdev);
return err;
}
@@ -882,6 +1033,7 @@ e1000_remove(struct pci_dev *pdev)
flush_scheduled_work();
if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
if (manc & E1000_MANC_SMBUS_EN) {
@@ -910,6 +1062,8 @@ e1000_remove(struct pci_dev *pdev)
#endif
iounmap(adapter->hw.hw_addr);
+ if (adapter->hw.flash_address)
+ iounmap(adapter->hw.flash_address);
pci_release_regions(pdev);
free_netdev(netdev);
@@ -947,7 +1101,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
- adapter->rx_buffer_len = MAXIMUM_ETHERNET_FRAME_SIZE;
+ adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
adapter->rx_ps_bsize0 = E1000_RXBUFFER_128;
hw->max_frame_size = netdev->mtu +
ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
@@ -960,13 +1114,6 @@ e1000_sw_init(struct e1000_adapter *adapter)
return -EIO;
}
- /* initialize eeprom parameters */
-
- if (e1000_init_eeprom_params(hw)) {
- E1000_ERR("EEPROM initialization failed\n");
- return -EIO;
- }
-
switch (hw->mac_type) {
default:
break;
@@ -1078,6 +1225,10 @@ e1000_open(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
int err;
+ /* disallow open during test */
+ if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags))
+ return -EBUSY;
+
/* allocate transmit descriptors */
if ((err = e1000_setup_all_tx_resources(adapter)))
@@ -1088,6 +1239,12 @@ e1000_open(struct net_device *netdev)
if ((err = e1000_setup_all_rx_resources(adapter)))
goto err_setup_rx;
+ err = e1000_request_irq(adapter);
+ if (err)
+ goto err_req_irq;
+
+ e1000_power_up_phy(adapter);
+
if ((err = e1000_up(adapter)))
goto err_up;
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
@@ -1105,6 +1262,9 @@ e1000_open(struct net_device *netdev)
return E1000_SUCCESS;
err_up:
+ e1000_power_down_phy(adapter);
+ e1000_free_irq(adapter);
+err_req_irq:
e1000_free_all_rx_resources(adapter);
err_setup_rx:
e1000_free_all_tx_resources(adapter);
@@ -1131,7 +1291,10 @@ e1000_close(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
e1000_down(adapter);
+ e1000_power_down_phy(adapter);
+ e1000_free_irq(adapter);
e1000_free_all_tx_resources(adapter);
e1000_free_all_rx_resources(adapter);
@@ -1189,8 +1352,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter,
int size;
size = sizeof(struct e1000_buffer) * txdr->count;
-
- txdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
+ txdr->buffer_info = vmalloc(size);
if (!txdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the transmit descriptor ring\n");
@@ -1255,10 +1417,6 @@ setup_tx_desc_die:
* (Descriptors) for all queues
* @adapter: board private structure
*
- * If this function returns with an error, then it's possible one or
- * more of the rings is populated (while the rest are not). It is the
- * callers duty to clean those orphaned rings.
- *
* Return 0 on success, negative on failure
**/
@@ -1272,6 +1430,9 @@ e1000_setup_all_tx_resources(struct e1000_adapter *adapter)
if (err) {
DPRINTK(PROBE, ERR,
"Allocation for Tx Queue %u failed\n", i);
+ for (i-- ; i >= 0; i--)
+ e1000_free_tx_resources(adapter,
+ &adapter->tx_ring[i]);
break;
}
}
@@ -1302,13 +1463,13 @@ e1000_configure_tx(struct e1000_adapter *adapter)
tdba = adapter->tx_ring[0].dma;
tdlen = adapter->tx_ring[0].count *
sizeof(struct e1000_tx_desc);
- E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
E1000_WRITE_REG(hw, TDLEN, tdlen);
- E1000_WRITE_REG(hw, TDH, 0);
+ E1000_WRITE_REG(hw, TDBAH, (tdba >> 32));
+ E1000_WRITE_REG(hw, TDBAL, (tdba & 0x00000000ffffffffULL));
E1000_WRITE_REG(hw, TDT, 0);
- adapter->tx_ring[0].tdh = E1000_TDH;
- adapter->tx_ring[0].tdt = E1000_TDT;
+ E1000_WRITE_REG(hw, TDH, 0);
+ adapter->tx_ring[0].tdh = ((hw->mac_type >= e1000_82543) ? E1000_TDH : E1000_82542_TDH);
+ adapter->tx_ring[0].tdt = ((hw->mac_type >= e1000_82543) ? E1000_TDT : E1000_82542_TDT);
break;
}
@@ -1373,8 +1534,6 @@ e1000_configure_tx(struct e1000_adapter *adapter)
} else if (hw->mac_type == e1000_80003es2lan) {
tarc = E1000_READ_REG(hw, TARC0);
tarc |= 1;
- if (hw->media_type == e1000_media_type_internal_serdes)
- tarc |= (1 << 20);
E1000_WRITE_REG(hw, TARC0, tarc);
tarc = E1000_READ_REG(hw, TARC1);
tarc |= 1;
@@ -1418,7 +1577,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter,
int size, desc_len;
size = sizeof(struct e1000_buffer) * rxdr->count;
- rxdr->buffer_info = vmalloc_node(size, pcibus_to_node(pdev->bus));
+ rxdr->buffer_info = vmalloc(size);
if (!rxdr->buffer_info) {
DPRINTK(PROBE, ERR,
"Unable to allocate memory for the receive descriptor ring\n");
@@ -1513,10 +1672,6 @@ setup_rx_desc_die:
* (Descriptors) for all queues
* @adapter: board private structure
*
- * If this function returns with an error, then it's possible one or
- * more of the rings is populated (while the rest are not). It is the
- * callers duty to clean those orphaned rings.
- *
* Return 0 on success, negative on failure
**/
@@ -1530,6 +1685,9 @@ e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
if (err) {
DPRINTK(PROBE, ERR,
"Allocation for Rx Queue %u failed\n", i);
+ for (i-- ; i >= 0; i--)
+ e1000_free_rx_resources(adapter,
+ &adapter->rx_ring[i]);
break;
}
}
@@ -1560,9 +1718,6 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
(adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
- if (adapter->hw.mac_type > e1000_82543)
- rctl |= E1000_RCTL_SECRC;
-
if (adapter->hw.tbi_compatibility_on == 1)
rctl |= E1000_RCTL_SBP;
else
@@ -1628,7 +1783,7 @@ e1000_setup_rctl(struct e1000_adapter *adapter)
rfctl |= E1000_RFCTL_IPV6_DIS;
E1000_WRITE_REG(&adapter->hw, RFCTL, rfctl);
- rctl |= E1000_RCTL_DTYP_PS | E1000_RCTL_SECRC;
+ rctl |= E1000_RCTL_DTYP_PS;
psrctl |= adapter->rx_ps_bsize0 >>
E1000_PSRCTL_BSIZE0_SHIFT;
@@ -1712,13 +1867,13 @@ e1000_configure_rx(struct e1000_adapter *adapter)
case 1:
default:
rdba = adapter->rx_ring[0].dma;
- E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
- E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
E1000_WRITE_REG(hw, RDLEN, rdlen);
- E1000_WRITE_REG(hw, RDH, 0);
+ E1000_WRITE_REG(hw, RDBAH, (rdba >> 32));
+ E1000_WRITE_REG(hw, RDBAL, (rdba & 0x00000000ffffffffULL));
E1000_WRITE_REG(hw, RDT, 0);
- adapter->rx_ring[0].rdh = E1000_RDH;
- adapter->rx_ring[0].rdt = E1000_RDT;
+ E1000_WRITE_REG(hw, RDH, 0);
+ adapter->rx_ring[0].rdh = ((hw->mac_type >= e1000_82543) ? E1000_RDH : E1000_82542_RDH);
+ adapter->rx_ring[0].rdt = ((hw->mac_type >= e1000_82543) ? E1000_RDT : E1000_82542_RDT);
break;
}
@@ -1741,9 +1896,6 @@ e1000_configure_rx(struct e1000_adapter *adapter)
E1000_WRITE_REG(hw, RXCSUM, rxcsum);
}
- if (hw->mac_type == e1000_82573)
- E1000_WRITE_REG(hw, ERT, 0x0100);
-
/* Enable Receives */
E1000_WRITE_REG(hw, RCTL, rctl);
}
@@ -2083,6 +2235,12 @@ e1000_set_multi(struct net_device *netdev)
uint32_t rctl;
uint32_t hash_value;
int i, rar_entries = E1000_RAR_ENTRIES;
+ int mta_reg_count = (hw->mac_type == e1000_ich8lan) ?
+ E1000_NUM_MTA_REGISTERS_ICH8LAN :
+ E1000_NUM_MTA_REGISTERS;
+
+ if (adapter->hw.mac_type == e1000_ich8lan)
+ rar_entries = E1000_RAR_ENTRIES_ICH8LAN;
/* reserve RAR[14] for LAA over-write work-around */
if (adapter->hw.mac_type == e1000_82571)
@@ -2121,14 +2279,18 @@ e1000_set_multi(struct net_device *netdev)
mc_ptr = mc_ptr->next;
} else {
E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+ E1000_WRITE_FLUSH(hw);
E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
+ E1000_WRITE_FLUSH(hw);
}
}
/* clear the old settings from the multicast hash table */
- for (i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
+ for (i = 0; i < mta_reg_count; i++) {
E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+ E1000_WRITE_FLUSH(hw);
+ }
/* load any remaining addresses into the hash table */
@@ -2201,19 +2363,19 @@ static void
e1000_watchdog(unsigned long data)
{
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
-
- /* Do the rest outside of interrupt context */
- schedule_work(&adapter->watchdog_task);
-}
-
-static void
-e1000_watchdog_task(struct e1000_adapter *adapter)
-{
struct net_device *netdev = adapter->netdev;
struct e1000_tx_ring *txdr = adapter->tx_ring;
uint32_t link, tctl;
-
- e1000_check_for_link(&adapter->hw);
+ int32_t ret_val;
+
+ ret_val = e1000_check_for_link(&adapter->hw);
+ if ((ret_val == E1000_ERR_PHY) &&
+ (adapter->hw.phy_type == e1000_phy_igp_3) &&
+ (E1000_READ_REG(&adapter->hw, CTRL) & E1000_PHY_CTRL_GBE_DISABLE)) {
+ /* See e1000_kumeran_lock_loss_workaround() */
+ DPRINTK(LINK, INFO,
+ "Gigabit has been disabled, downgrading speed\n");
+ }
if (adapter->hw.mac_type == e1000_82573) {
e1000_enable_tx_pkt_filtering(&adapter->hw);
if (adapter->mng_vlan_id != adapter->hw.mng_cookie.vlan_id)
@@ -2312,10 +2474,9 @@ e1000_watchdog_task(struct e1000_adapter *adapter)
* disable receives in the ISR and
* reset device here in the watchdog
*/
- if (adapter->hw.mac_type == e1000_80003es2lan) {
+ if (adapter->hw.mac_type == e1000_80003es2lan)
/* reset device */
schedule_work(&adapter->reset_task);
- }
}
e1000_smartspeed(adapter);
@@ -2394,7 +2555,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
int err;
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -2415,7 +2576,7 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
cmd_length = E1000_TXD_CMD_IP;
ipcse = skb->h.raw - skb->data - 1;
#ifdef NETIF_F_TSO_IPV6
- } else if (skb->protocol == ntohs(ETH_P_IPV6)) {
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
skb->nh.ipv6h->payload_len = 0;
skb->h.th->check =
~csum_ipv6_magic(&skb->nh.ipv6h->saddr,
@@ -2470,7 +2631,7 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
unsigned int i;
uint8_t css;
- if (likely(skb->ip_summed == CHECKSUM_HW)) {
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
css = skb->h.raw - skb->data;
i = tx_ring->next_to_use;
@@ -2519,7 +2680,7 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
* tso gets written back prematurely before the data is fully
* DMA'd to the controller */
if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->gso_size) {
+ !skb_is_gso(skb)) {
tx_ring->last_tx_tso = 0;
size -= 4;
}
@@ -2779,9 +2940,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_ich8lan:
pull_size = min((unsigned int)4, skb->data_len);
if (!__pskb_pull_tail(skb, pull_size)) {
- printk(KERN_ERR
+ DPRINTK(DRV, ERR,
"__pskb_pull_tail failed.\n");
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -2796,18 +2958,17 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
/* reserve a descriptor for the offload context */
- if ((mss) || (skb->ip_summed == CHECKSUM_HW))
+ if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
count++;
count++;
#else
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
count++;
#endif
#ifdef NETIF_F_TSO
/* Controller Erratum workaround */
- if (!skb->data_len && tx_ring->last_tx_tso &&
- !skb_shinfo(skb)->gso_size)
+ if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
count++;
#endif
@@ -2919,8 +3080,7 @@ e1000_reset_task(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
- e1000_down(adapter);
- e1000_up(adapter);
+ e1000_reinit_locked(adapter);
}
/**
@@ -2964,6 +3124,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
/* Adapter-specific max frame size limits. */
switch (adapter->hw.mac_type) {
case e1000_undefined ... e1000_82542_rev2_1:
+ case e1000_ich8lan:
if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n");
return -EINVAL;
@@ -2997,7 +3158,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
break;
}
- /* NOTE: dev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
+ /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN
* means we reserve 2 more, this pushes us to allocate from the next
* larger slab size
* i.e. RXBUFFER_2048 --> size-4096 slab */
@@ -3018,7 +3179,6 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
adapter->rx_buffer_len = E1000_RXBUFFER_16384;
/* adjust allocation if LPE protects us, and we aren't using SBP */
-#define MAXIMUM_ETHERNET_VLAN_SIZE 1522
if (!adapter->hw.tbi_compatibility_on &&
((max_frame == MAXIMUM_ETHERNET_FRAME_SIZE) ||
(max_frame == MAXIMUM_ETHERNET_VLAN_SIZE)))
@@ -3026,10 +3186,8 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
netdev->mtu = new_mtu;
- if (netif_running(netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- }
+ if (netif_running(netdev))
+ e1000_reinit_locked(adapter);
adapter->hw.max_frame_size = max_frame;
@@ -3074,12 +3232,15 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
adapter->stats.roc += E1000_READ_REG(hw, ROC);
+
+ if (adapter->hw.mac_type != e1000_ich8lan) {
adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
+ }
adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
adapter->stats.mpc += E1000_READ_REG(hw, MPC);
@@ -3107,12 +3268,16 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.totl += E1000_READ_REG(hw, TOTL);
adapter->stats.toth += E1000_READ_REG(hw, TOTH);
adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+
+ if (adapter->hw.mac_type != e1000_ich8lan) {
adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+ }
+
adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
@@ -3134,6 +3299,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
if (hw->mac_type > e1000_82547_rev_2) {
adapter->stats.iac += E1000_READ_REG(hw, IAC);
adapter->stats.icrxoc += E1000_READ_REG(hw, ICRXOC);
+
+ if (adapter->hw.mac_type != e1000_ich8lan) {
adapter->stats.icrxptc += E1000_READ_REG(hw, ICRXPTC);
adapter->stats.icrxatc += E1000_READ_REG(hw, ICRXATC);
adapter->stats.ictxptc += E1000_READ_REG(hw, ICTXPTC);
@@ -3141,6 +3308,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.ictxqec += E1000_READ_REG(hw, ICTXQEC);
adapter->stats.ictxqmtc += E1000_READ_REG(hw, ICTXQMTC);
adapter->stats.icrxdmtc += E1000_READ_REG(hw, ICRXDMTC);
+ }
}
/* Fill out the OS statistics structure */
@@ -3249,8 +3417,8 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
E1000_WRITE_REG(hw, IMC, ~0);
E1000_WRITE_FLUSH(hw);
}
- if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0])))
- __netif_rx_schedule(&adapter->polling_netdev[0]);
+ if (likely(netif_rx_schedule_prep(netdev)))
+ __netif_rx_schedule(netdev);
else
e1000_irq_enable(adapter);
#else
@@ -3293,34 +3461,26 @@ e1000_clean(struct net_device *poll_dev, int *budget)
{
struct e1000_adapter *adapter;
int work_to_do = min(*budget, poll_dev->quota);
- int tx_cleaned = 0, i = 0, work_done = 0;
+ int tx_cleaned = 0, work_done = 0;
/* Must NOT use netdev_priv macro here. */
adapter = poll_dev->priv;
/* Keep link state information with original netdev */
- if (!netif_carrier_ok(adapter->netdev))
+ if (!netif_carrier_ok(poll_dev))
goto quit_polling;
- while (poll_dev != &adapter->polling_netdev[i]) {
- i++;
- BUG_ON(i == adapter->num_rx_queues);
+ /* e1000_clean is called per-cpu. This lock protects
+ * tx_ring[0] from being cleaned by multiple cpus
+ * simultaneously. A failure obtaining the lock means
+ * tx_ring[0] is currently being cleaned anyway. */
+ if (spin_trylock(&adapter->tx_queue_lock)) {
+ tx_cleaned = e1000_clean_tx_irq(adapter,
+ &adapter->tx_ring[0]);
+ spin_unlock(&adapter->tx_queue_lock);
}
- if (likely(adapter->num_tx_queues == 1)) {
- /* e1000_clean is called per-cpu. This lock protects
- * tx_ring[0] from being cleaned by multiple cpus
- * simultaneously. A failure obtaining the lock means
- * tx_ring[0] is currently being cleaned anyway. */
- if (spin_trylock(&adapter->tx_queue_lock)) {
- tx_cleaned = e1000_clean_tx_irq(adapter,
- &adapter->tx_ring[0]);
- spin_unlock(&adapter->tx_queue_lock);
- }
- } else
- tx_cleaned = e1000_clean_tx_irq(adapter, &adapter->tx_ring[i]);
-
- adapter->clean_rx(adapter, &adapter->rx_ring[i],
+ adapter->clean_rx(adapter, &adapter->rx_ring[0],
&work_done, work_to_do);
*budget -= work_done;
@@ -3328,7 +3488,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
/* If no Tx and not enough Rx work done, exit the polling mode */
if ((!tx_cleaned && (work_done == 0)) ||
- !netif_running(adapter->netdev)) {
+ !netif_running(poll_dev)) {
quit_polling:
netif_rx_complete(poll_dev);
e1000_irq_enable(adapter);
@@ -3479,7 +3639,7 @@ e1000_rx_checksum(struct e1000_adapter *adapter,
*/
csum = ntohl(csum ^ 0xFFFF);
skb->csum = csum;
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
}
adapter->hw_csum_good++;
}
@@ -3543,11 +3703,15 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
length = le16_to_cpu(rx_desc->length);
+ /* adjust length to remove Ethernet CRC */
+ length -= 4;
+
if (unlikely(!(status & E1000_RXD_STAT_EOP))) {
/* All receives must fit into a single buffer */
E1000_DBG("%s: Receive packet consumed multiple"
" buffers\n", netdev->name);
- dev_kfree_skb_irq(skb);
+ /* recycle */
+ buffer_info->skb = skb;
goto next_desc;
}
@@ -3575,10 +3739,9 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter,
#define E1000_CB_LENGTH 256
if (length < E1000_CB_LENGTH) {
struct sk_buff *new_skb =
- dev_alloc_skb(length + NET_IP_ALIGN);
+ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
if (new_skb) {
skb_reserve(new_skb, NET_IP_ALIGN);
- new_skb->dev = netdev;
memcpy(new_skb->data - NET_IP_ALIGN,
skb->data - NET_IP_ALIGN,
length + NET_IP_ALIGN);
@@ -3675,7 +3838,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
buffer_info = &rx_ring->buffer_info[i];
while (staterr & E1000_RXD_STAT_DD) {
- buffer_info = &rx_ring->buffer_info[i];
ps_page = &rx_ring->ps_page[i];
ps_page_dma = &rx_ring->ps_page_dma[i];
#ifdef CONFIG_E1000_NAPI
@@ -3747,8 +3909,9 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
pci_dma_sync_single_for_device(pdev,
ps_page_dma->ps_page_dma[0],
PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ /* remove the CRC */
+ l1 -= 4;
skb_put(skb, l1);
- length += l1;
goto copydone;
} /* if */
}
@@ -3767,6 +3930,10 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
skb->truesize += length;
}
+ /* strip the ethernet crc, problem is we're using pages now so
+ * this whole operation can get a little cpu intensive */
+ pskb_trim(skb, skb->len - 4);
+
copydone:
e1000_rx_checksum(adapter, staterr,
le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
@@ -3841,13 +4008,13 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
buffer_info = &rx_ring->buffer_info[i];
while (cleaned_count--) {
- if (!(skb = buffer_info->skb))
- skb = dev_alloc_skb(bufsz);
- else {
+ skb = buffer_info->skb;
+ if (skb) {
skb_trim(skb, 0);
goto map_skb;
}
+ skb = netdev_alloc_skb(netdev, bufsz);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
@@ -3860,7 +4027,7 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
DPRINTK(RX_ERR, ERR, "skb align check failed: %u bytes "
"at %p\n", bufsz, skb->data);
/* Try again, without freeing the previous */
- skb = dev_alloc_skb(bufsz);
+ skb = netdev_alloc_skb(netdev, bufsz);
/* Failed allocation, critical failure */
if (!skb) {
dev_kfree_skb(oldskb);
@@ -3872,10 +4039,10 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
dev_kfree_skb(skb);
dev_kfree_skb(oldskb);
break; /* while !buffer_info->skb */
- } else {
- /* Use new allocation */
- dev_kfree_skb(oldskb);
}
+
+ /* Use new allocation */
+ dev_kfree_skb(oldskb);
}
/* Make buffer alignment 2 beyond a 16 byte boundary
* this will result in a 16 byte aligned IP header after
@@ -3883,8 +4050,6 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
*/
skb_reserve(skb, NET_IP_ALIGN);
- skb->dev = netdev;
-
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
map_skb:
@@ -3984,7 +4149,8 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
rx_desc->read.buffer_addr[j+1] = ~0;
}
- skb = dev_alloc_skb(adapter->rx_ps_bsize0 + NET_IP_ALIGN);
+ skb = netdev_alloc_skb(netdev,
+ adapter->rx_ps_bsize0 + NET_IP_ALIGN);
if (unlikely(!skb)) {
adapter->alloc_rx_buff_failed++;
@@ -3997,8 +4163,6 @@ e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
*/
skb_reserve(skb, NET_IP_ALIGN);
- skb->dev = netdev;
-
buffer_info->skb = skb;
buffer_info->length = adapter->rx_ps_bsize0;
buffer_info->dma = pci_map_single(pdev, skb->data,
@@ -4180,10 +4344,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
return retval;
}
}
- if (netif_running(adapter->netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(adapter->netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
break;
case M88E1000_PHY_SPEC_CTRL:
@@ -4200,10 +4363,9 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
case PHY_CTRL:
if (mii_reg & MII_CR_POWER_DOWN)
break;
- if (netif_running(adapter->netdev)) {
- e1000_down(adapter);
- e1000_up(adapter);
- } else
+ if (netif_running(adapter->netdev))
+ e1000_reinit_locked(adapter);
+ else
e1000_reset(adapter);
break;
}
@@ -4250,11 +4412,13 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
pci_write_config_word(adapter->pdev, reg, *value);
}
+#if 0
uint32_t
e1000_io_read(struct e1000_hw *hw, unsigned long port)
{
return inl(port);
}
+#endif /* 0 */
void
e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
@@ -4277,18 +4441,21 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
ctrl |= E1000_CTRL_VME;
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+ if (adapter->hw.mac_type != e1000_ich8lan) {
/* enable VLAN receive filtering */
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_VFE;
rctl &= ~E1000_RCTL_CFIEN;
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
e1000_update_mng_vlan(adapter);
+ }
} else {
/* disable VLAN tag insert/strip */
ctrl = E1000_READ_REG(&adapter->hw, CTRL);
ctrl &= ~E1000_CTRL_VME;
E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+ if (adapter->hw.mac_type != e1000_ich8lan) {
/* disable VLAN filtering */
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl &= ~E1000_RCTL_VFE;
@@ -4297,6 +4464,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
}
+ }
}
e1000_irq_enable(adapter);
@@ -4458,12 +4626,16 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, ctrl_ext, rctl, manc, status;
uint32_t wufc = adapter->wol;
+#ifdef CONFIG_PM
int retval = 0;
+#endif
netif_device_detach(netdev);
- if (netif_running(netdev))
+ if (netif_running(netdev)) {
+ WARN_ON(test_bit(__E1000_RESETTING, &adapter->flags));
e1000_down(adapter);
+ }
#ifdef CONFIG_PM
/* Implement our own version of pci_save_state(pdev) because pci-
@@ -4482,7 +4654,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
e1000_set_multi(netdev);
/* turn on all-multi mode if wake on multicast is enabled */
- if (adapter->wol & E1000_WUFC_MC) {
+ if (wufc & E1000_WUFC_MC) {
rctl = E1000_READ_REG(&adapter->hw, RCTL);
rctl |= E1000_RCTL_MPE;
E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
@@ -4521,7 +4693,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, PCI_D3cold, 0);
}
+ /* FIXME: this code is incorrect for PCI Express */
if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
if (manc & E1000_MANC_SMBUS_EN) {
@@ -4532,6 +4706,9 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
}
}
+ if (adapter->hw.phy_type == e1000_phy_igp_3)
+ e1000_phy_powerdown_workaround(&adapter->hw);
+
/* Release control of h/w to f/w. If f/w is AMT enabled, this
* would have already happened in close and is redundant. */
e1000_release_hw_control(adapter);
@@ -4549,11 +4726,14 @@ e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct e1000_adapter *adapter = netdev_priv(netdev);
- uint32_t manc, ret_val;
+ uint32_t manc, err;
pci_set_power_state(pdev, PCI_D0);
e1000_pci_restore_state(adapter);
- ret_val = pci_enable_device(pdev);
+ if ((err = pci_enable_device(pdev))) {
+ printk(KERN_ERR "e1000: Cannot enable PCI device from suspend\n");
+ return err;
+ }
pci_set_master(pdev);
pci_enable_wake(pdev, PCI_D3hot, 0);
@@ -4567,7 +4747,9 @@ e1000_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
+ /* FIXME: this code is incorrect for PCI Express */
if (adapter->hw.mac_type >= e1000_82540 &&
+ adapter->hw.mac_type != e1000_ich8lan &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
manc &= ~(E1000_MANC_ARP_EN);
@@ -4601,6 +4783,7 @@ static void
e1000_netpoll(struct net_device *netdev)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
+
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev, NULL);
e1000_clean_tx_irq(adapter, adapter->tx_ring);
@@ -4628,6 +4811,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channe
if (netif_running(netdev))
e1000_down(adapter);
+ pci_disable_device(pdev);
/* Request a slot slot reset. */
return PCI_ERS_RESULT_NEED_RESET;
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 048d052be29..46bc49df15e 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -42,25 +42,6 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
-#ifndef msec_delay
-#define msec_delay(x) do { if(in_interrupt()) { \
- /* Don't mdelay in interrupt context! */ \
- BUG(); \
- } else { \
- msleep(x); \
- } } while (0)
-
-/* Some workarounds require millisecond delays and are run during interrupt
- * context. Most notably, when establishing link, the phy may need tweaking
- * but cannot process phy register reads/writes faster than millisecond
- * intervals...and we establish link due to a "link status change" interrupt.
- */
-#define msec_delay_irq(x) mdelay(x)
-#endif
-
-#define PCI_COMMAND_REGISTER PCI_COMMAND
-#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
-
typedef enum {
#undef FALSE
FALSE = 0,
@@ -127,4 +108,17 @@ typedef enum {
#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
+#define E1000_WRITE_ICH8_REG(a, reg, value) ( \
+ writel((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_ICH8_REG(a, reg) ( \
+ readl((a)->flash_address + reg))
+
+#define E1000_WRITE_ICH8_REG16(a, reg, value) ( \
+ writew((value), ((a)->flash_address + reg)))
+
+#define E1000_READ_ICH8_REG16(a, reg) ( \
+ readw((a)->flash_address + reg))
+
+
#endif /* _E1000_OSDEP_H_ */
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index e55f8969a0f..21284273897 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -45,6 +45,16 @@
*/
#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
#define E1000_PARAM(X, desc) \
static int __devinitdata X[E1000_MAX_NIC+1] = E1000_PARAM_INIT; \
static int num_##X = 0; \
@@ -183,6 +193,24 @@ E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
+/* Enable Smart Power Down of the PHY
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 0 (disabled)
+ */
+
+E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
+
+/* Enable Kumeran Lock Loss workaround
+ *
+ * Valid Range: 0, 1
+ *
+ * Default Value: 1 (enabled)
+ */
+
+E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
+
#define AUTONEG_ADV_DEFAULT 0x2F
#define AUTONEG_ADV_MASK 0x2F
#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
@@ -405,7 +433,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_TxIntDelay > bd) {
adapter->tx_int_delay = TxIntDelay[bd];
e1000_validate_option(&adapter->tx_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->tx_int_delay = opt.def;
}
@@ -423,7 +451,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_TxAbsIntDelay > bd) {
adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
e1000_validate_option(&adapter->tx_abs_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->tx_abs_int_delay = opt.def;
}
@@ -441,7 +469,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_RxIntDelay > bd) {
adapter->rx_int_delay = RxIntDelay[bd];
e1000_validate_option(&adapter->rx_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->rx_int_delay = opt.def;
}
@@ -459,7 +487,7 @@ e1000_check_options(struct e1000_adapter *adapter)
if (num_RxAbsIntDelay > bd) {
adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
e1000_validate_option(&adapter->rx_abs_int_delay, &opt,
- adapter);
+ adapter);
} else {
adapter->rx_abs_int_delay = opt.def;
}
@@ -479,21 +507,53 @@ e1000_check_options(struct e1000_adapter *adapter)
switch (adapter->itr) {
case 0:
DPRINTK(PROBE, INFO, "%s turned off\n",
- opt.name);
+ opt.name);
break;
case 1:
DPRINTK(PROBE, INFO, "%s set to dynamic mode\n",
- opt.name);
+ opt.name);
break;
default:
e1000_validate_option(&adapter->itr, &opt,
- adapter);
+ adapter);
break;
}
} else {
adapter->itr = opt.def;
}
}
+ { /* Smart Power Down */
+ struct e1000_option opt = {
+ .type = enable_option,
+ .name = "PHY Smart Power Down",
+ .err = "defaulting to Disabled",
+ .def = OPTION_DISABLED
+ };
+
+ if (num_SmartPowerDownEnable > bd) {
+ int spd = SmartPowerDownEnable[bd];
+ e1000_validate_option(&spd, &opt, adapter);
+ adapter->smart_power_down = spd;
+ } else {
+ adapter->smart_power_down = opt.def;
+ }
+ }
+ { /* Kumeran Lock Loss Workaround */
+ struct e1000_option opt = {
+ .type = enable_option,
+ .name = "Kumeran Lock Loss Workaround",
+ .err = "defaulting to Enabled",
+ .def = OPTION_ENABLED
+ };
+
+ if (num_KumeranLockLoss > bd) {
+ int kmrn_lock_loss = KumeranLockLoss[bd];
+ e1000_validate_option(&kmrn_lock_loss, &opt, adapter);
+ adapter->hw.kmrn_lock_loss_workaround_disabled = !kmrn_lock_loss;
+ } else {
+ adapter->hw.kmrn_lock_loss_workaround_disabled = !opt.def;
+ }
+ }
switch (adapter->hw.media_type) {
case e1000_media_type_fiber:
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index e5c5cd2a271..d39e8480ca5 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -110,7 +110,7 @@ static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
static int e21_close(struct net_device *dev);
-
+
/* Probe for the E2100 series ethercards. These cards have an 8390 at the
base address and the station address at both offset 0x10 and 0x18. I read
the station address from offset 0x18 to avoid the dataport of NE2000
@@ -403,7 +403,7 @@ e21_close(struct net_device *dev)
return 0;
}
-
+
#ifdef MODULE
#define MAX_E21_CARDS 4 /* Max number of E21 cards per module */
static struct net_device *dev_e21[MAX_E21_CARDS];
@@ -425,8 +425,8 @@ MODULE_LICENSE("GPL");
/* This is set up so that only a single autoprobe takes place per call.
ISA device autoprobes on a running machine are not recommended. */
-int
-init_module(void)
+
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index e70f172699d..09ff9b9418f 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -154,7 +154,7 @@ static const char version[] =
#include <asm/dma.h>
#define DRV_NAME "eepro"
-#define DRV_VERSION "0.13b"
+#define DRV_VERSION "0.13c"
#define compat_dev_kfree_skb( skb, mode ) dev_kfree_skb( (skb) )
/* I had reports of looong delays with SLOW_DOWN defined as udelay(2) */
@@ -743,7 +743,7 @@ static void __init eepro_print_info (struct net_device *dev)
printEEPROMInfo(dev);
}
-static struct ethtool_ops eepro_ethtool_ops;
+static const struct ethtool_ops eepro_ethtool_ops;
/* This is the real probe routine. Linux has a history of friendly device
probes on the ISA bus. A good device probe avoids doing writes, and
@@ -920,7 +920,7 @@ static int eepro_grab_irq(struct net_device *dev)
eepro_sw2bank0(ioaddr); /* Switch back to Bank 0 */
- if (request_irq (*irqp, NULL, SA_SHIRQ, "bogus", dev) != EBUSY) {
+ if (request_irq (*irqp, NULL, IRQF_SHARED, "bogus", dev) != EBUSY) {
unsigned long irq_mask;
/* Twinkle the interrupt, and check if it's seen */
irq_mask = probe_irq_on();
@@ -1333,7 +1333,6 @@ set_multicast_list(struct net_device *dev)
mode = inb(ioaddr + REG3);
outb(mode, ioaddr + REG3); /* writing reg. 3 to complete the update */
eepro_sw2bank0(ioaddr); /* Return to BANK 0 now */
- printk(KERN_INFO "%s: promiscuous mode enabled.\n", dev->name);
}
else if (dev->mc_count==0 )
@@ -1772,7 +1771,7 @@ static void eepro_ethtool_get_drvinfo(struct net_device *dev,
sprintf(drvinfo->bus_info, "ISA 0x%lx", dev->base_addr);
}
-static struct ethtool_ops eepro_ethtool_ops = {
+static const struct ethtool_ops eepro_ethtool_ops = {
.get_settings = eepro_ethtool_get_settings,
.get_drvinfo = eepro_ethtool_get_drvinfo,
};
@@ -1807,8 +1806,7 @@ MODULE_PARM_DESC(irq, "EtherExpress Pro/10 IRQ number(s)");
MODULE_PARM_DESC(mem, "EtherExpress Pro/10 Rx buffer size(es) in kB (3-29)");
MODULE_PARM_DESC(autodetect, "EtherExpress Pro/10 force board(s) detection (0-1)");
-int
-init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int i;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 467fc861360..499e93b31f5 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -87,7 +87,6 @@ static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
#define PKT_BUF_SZ 1536
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -278,11 +277,6 @@ having to sign an Intel NDA when I'm helping Intel sell their own product!
static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state);
-enum pci_flags_bit {
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
-};
-
/* Offsets to the various registers.
All accesses need not be longword aligned. */
enum speedo_offsets {
@@ -500,9 +494,9 @@ static struct net_device_stats *speedo_get_stats(struct net_device *dev);
static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
static void speedo_show_state(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
+
-
#ifdef honor_default_port
/* Optional driver feature to allow forcing the transceiver setting.
@@ -561,12 +555,12 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
if (!request_region(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1), "eepro100")) {
- printk (KERN_ERR "eepro100: cannot reserve I/O ports\n");
+ dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n");
goto err_out_none;
}
if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), "eepro100")) {
- printk (KERN_ERR "eepro100: cannot reserve MMIO region\n");
+ dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n");
goto err_out_free_pio_region;
}
@@ -579,7 +573,7 @@ static int __devinit eepro100_init_one (struct pci_dev *pdev,
ioaddr = pci_iomap(pdev, pci_bar, 0);
if (!ioaddr) {
- printk (KERN_ERR "eepro100: cannot remap IO\n");
+ dev_err(&pdev->dev, "eepro100: cannot remap IO\n");
goto err_out_free_mmio_region;
}
@@ -652,7 +646,7 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
option = 0;
rtnl_lock();
- if (dev_alloc_name(dev, dev->name) < 0)
+ if (dev_alloc_name(dev, dev->name) < 0)
goto err_free_unlock;
/* Read the station address EEPROM before doing the reset.
@@ -831,10 +825,10 @@ static int __devinit speedo_found1(struct pci_dev *pdev,
sp->mii_if.dev = dev;
sp->mii_if.mdio_read = mdio_read;
sp->mii_if.mdio_write = mdio_write;
-
+
sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1;
- if (((pdev->device > 0x1030 && (pdev->device < 0x103F)))
- || (pdev->device == 0x2449) || (pdev->device == 0x2459)
+ if (((pdev->device > 0x1030 && (pdev->device < 0x103F)))
+ || (pdev->device == 0x2449) || (pdev->device == 0x2459)
|| (pdev->device == 0x245D)) {
sp->chip_id = 1;
}
@@ -983,7 +977,7 @@ speedo_open(struct net_device *dev)
sp->in_interrupt = 0;
/* .. we can safely take handler calls during init. */
- retval = request_irq(dev->irq, &speedo_interrupt, SA_SHIRQ, dev->name, dev);
+ retval = request_irq(dev->irq, &speedo_interrupt, IRQF_SHARED, dev->name, dev);
if (retval) {
return retval;
}
@@ -1214,7 +1208,7 @@ static void speedo_show_state(struct net_device *dev)
int i;
if (netif_msg_pktdata(sp)) {
- printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n",
+ printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n",
dev->name, sp->cur_tx, sp->dirty_tx);
for (i = 0; i < TX_RING_SIZE; i++)
printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name,
@@ -1592,7 +1586,7 @@ static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs
/* Always check if all rx buffers are allocated. --SAW */
speedo_refill_rx_buffers(dev, 0);
-
+
spin_lock(&sp->lock);
/*
* The chip may have suspended reception for various reasons.
@@ -1613,8 +1607,8 @@ static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs
/* these are all reserved values */
break;
}
-
-
+
+
/* User interrupt, Command/Tx unit interrupt or CU not active. */
if (status & 0xA400) {
speedo_tx_buffer_gc(dev);
@@ -1625,7 +1619,7 @@ static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs
netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */
}
}
-
+
spin_unlock(&sp->lock);
if (--boguscnt < 0) {
@@ -2021,7 +2015,7 @@ static void speedo_set_msglevel(struct net_device *dev, u32 v)
sp->msg_enable = v;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = speedo_get_drvinfo,
.get_settings = speedo_get_settings,
.set_settings = speedo_set_settings,
@@ -2269,7 +2263,7 @@ static void set_rx_mode(struct net_device *dev)
sp->rx_mode = new_rx_mode;
}
-
+
#ifdef CONFIG_PM
static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -2281,12 +2275,12 @@ static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev))
return 0;
-
+
del_timer_sync(&sp->timer);
netif_device_detach(dev);
iowrite32(PortPartialReset, ioaddr + SCBPort);
-
+
/* XXX call pci_set_power_state ()? */
pci_disable_device(pdev);
pci_set_power_state (pdev, PCI_D3hot);
@@ -2330,7 +2324,7 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
struct speedo_private *sp = netdev_priv(dev);
-
+
unregister_netdev(dev);
release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
@@ -2343,7 +2337,7 @@ static void __devexit eepro100_remove_one (struct pci_dev *pdev)
pci_disable_device(pdev);
free_netdev(dev);
}
-
+
static struct pci_device_id eepro100_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, },
@@ -2374,7 +2368,7 @@ static struct pci_device_id eepro100_pci_tbl[] = {
{ 0,}
};
MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);
-
+
static struct pci_driver eepro100_driver = {
.name = "eepro100",
.id_table = eepro100_pci_tbl,
@@ -2391,7 +2385,7 @@ static int __init eepro100_init_module(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&eepro100_driver);
+ return pci_register_driver(&eepro100_driver);
}
static void __exit eepro100_cleanup_module(void)
@@ -2401,7 +2395,7 @@ static void __exit eepro100_cleanup_module(void)
module_init(eepro100_init_module);
module_exit(eepro100_cleanup_module);
-
+
/*
* Local variables:
* compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index a74b2071575..9cb05d99ee1 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -77,7 +77,7 @@
* CU before submitting a packet for transmission, and then restarts it as soon
* as the process of handing the packet is complete. This is definitely an
* unnecessary slowdown if the card is running in 16-bit mode; therefore one
- * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
+ * should detect 16-bit vs 8-bit mode from the EEPROM settings and act
* accordingly. In 8-bit mode with this bugfix I'm getting about 150 K/s for
* ftp's, which is significantly better than I get in DOS, so the overhead of
* stopping and restarting the CU with each transmit is not prohibitive in
@@ -96,8 +96,7 @@
#ifndef LOCKUP16
#define LOCKUP16 0
#endif
-
-#include <linux/config.h>
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -178,7 +177,7 @@ static unsigned short start_code[] = {
/* 0x20 -- start of 82586 CU program */
#define CONF_LINK 0x20
- 0x0000,Cmd_Config,
+ 0x0000,Cmd_Config,
0x0032, /* link to next command */
0x080c, /* 12 bytes follow : fifo threshold=8 */
0x2e40, /* don't rx bad frames
@@ -188,10 +187,10 @@ static unsigned short start_code[] = {
*/
0x6000, /* default backoff method & priority
* interframe spacing = 0x60 */
- 0xf200, /* slot time=0x200
+ 0xf200, /* slot time=0x200
* max collision retry = 0xf */
#define CONF_PROMISC 0x2e
- 0x0000, /* no HDLC : normal CRC : enable broadcast
+ 0x0000, /* no HDLC : normal CRC : enable broadcast
* disable promiscuous/multicast modes */
0x003c, /* minimum frame length = 60 octets) */
@@ -238,7 +237,7 @@ static unsigned short mca_iomap[] = {
};
/* bits 5-7 of the second POS register */
static char mca_irqmap[] = { 12, 9, 3, 4, 5, 10, 11, 15 };
-#endif
+#endif
/*
* Prototypes for Linux interface
@@ -357,7 +356,7 @@ static int __init do_express_probe(struct net_device *dev)
*/
while (slot != MCA_NOTFOUND) {
int pos0, pos1;
-
+
slot = mca_find_unused_adapter(0x628B, slot);
if (slot == MCA_NOTFOUND)
break;
@@ -367,10 +366,10 @@ static int __init do_express_probe(struct net_device *dev)
ioaddr = mca_iomap[pos1&0xf];
dev->irq = mca_irqmap[(pos1>>4)&0x7];
-
+
/*
* XXX: Transciever selection is done
- * differently on the MCA version.
+ * differently on the MCA version.
* How to get it to select something
* other than external/AUI is currently
* unknown. This code is just for looks. -- ASF
@@ -483,7 +482,7 @@ static int eexp_open(struct net_device *dev)
, ioaddr+0xc000);
goto err_out4;
}
-
+
if (lp->width) {
printk("%s: forcing ASIC to 8-bit mode\n", dev->name);
outb(inb(dev->base_addr+Config)&~4, dev->base_addr+Config);
@@ -519,7 +518,7 @@ static int eexp_close(struct net_device *dev)
int irq = dev->irq;
netif_stop_queue(dev);
-
+
outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
lp->started = 0;
scb_command(dev, SCB_CUsuspend|SCB_RUsuspend);
@@ -631,14 +630,14 @@ static void eexp_timeout(struct net_device *dev)
unsigned long flags;
#endif
int status;
-
+
disable_irq(dev->irq);
/*
* Best would be to use synchronize_irq(); spin_lock() here
* lets make it work first..
*/
-
+
#ifdef CONFIG_SMP
spin_lock_irqsave(&lp->lock, flags);
#endif
@@ -654,7 +653,7 @@ static void eexp_timeout(struct net_device *dev)
scb_command(dev, SCB_CUabort);
outb(0,dev->base_addr+SIGNAL_CA);
}
- netif_wake_queue(dev);
+ netif_wake_queue(dev);
#ifdef CONFIG_SMP
spin_unlock_irqrestore(&lp->lock, flags);
#endif
@@ -688,11 +687,11 @@ static int eexp_xmit(struct sk_buff *buf, struct net_device *dev)
* Best would be to use synchronize_irq(); spin_lock() here
* lets make it work first..
*/
-
+
#ifdef CONFIG_SMP
spin_lock_irqsave(&lp->lock, flags);
#endif
-
+
{
unsigned short *data = (unsigned short *)buf->data;
@@ -740,7 +739,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
outw(CONF_DIAG_RESULT & ~31, ioaddr + SM_PTR);
diag_status = inw(ioaddr + SHADOW(CONF_DIAG_RESULT));
if (diag_status & 1<<11) {
- printk(KERN_WARNING "%s: 82586 failed self-test\n",
+ printk(KERN_WARNING "%s: 82586 failed self-test\n",
dev->name);
} else if (!(diag_status & 1<<13)) {
printk(KERN_WARNING "%s: 82586 self-test failed to complete\n", dev->name);
@@ -750,7 +749,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
tdr_status = inw(ioaddr + SHADOW(CONF_TDR_RESULT));
if (tdr_status & (TDR_SHORT|TDR_OPEN)) {
printk(KERN_WARNING "%s: TDR reports cable %s at %d tick%s\n", dev->name, (tdr_status & TDR_SHORT)?"short":"broken", tdr_status & TDR_TIME, ((tdr_status & TDR_TIME) != 1) ? "s" : "");
- }
+ }
else if (tdr_status & TDR_XCVRPROBLEM) {
printk(KERN_WARNING "%s: TDR reports transceiver problem\n", dev->name);
}
@@ -762,7 +761,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
printk("%s: TDR is ga-ga (status %04x)\n", dev->name,
tdr_status);
}
-
+
lp->started |= STARTED_CU;
scb_wrcbl(dev, lp->tx_link);
/* if the RU isn't running, start it now */
@@ -775,7 +774,7 @@ static unsigned short eexp_start_irq(struct net_device *dev,
ack_cmd |= SCB_CUstart | 0x2000;
}
- if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
+ if ((dev->flags & IFF_UP) && !(lp->started & STARTED_RU) && SCB_RUstat(status)==4)
lp->started|=STARTED_RU;
return ack_cmd;
@@ -789,7 +788,7 @@ static void eexp_cmd_clear(struct net_device *dev)
printk("%s: command didn't clear\n", dev->name);
}
}
-
+
static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
{
struct net_device *dev = dev_info;
@@ -814,7 +813,7 @@ static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
outb(SIRQ_dis|irqrmap[irq],ioaddr+SET_IRQ);
-
+
status = scb_status(dev);
#if NET_DEBUG > 4
@@ -837,14 +836,14 @@ static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
printk("%s: tx interrupt but no status\n", dev->name);
}
}
-
- if (SCB_rxdframe(status))
+
+ if (SCB_rxdframe(status))
eexp_hw_rx_pio(dev);
status = scb_status(dev);
} while (status & 0xc000);
- if (SCB_RUdead(status))
+ if (SCB_RUdead(status))
{
printk(KERN_WARNING "%s: RU stopped: status %04x\n",
dev->name,status);
@@ -868,9 +867,9 @@ static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
scb_wrrfa(dev, lp->rx_buf_start);
scb_command(dev, SCB_RUstart);
outb(0,ioaddr+SIGNAL_CA);
- }
+ }
} else {
- if (status & 0x8000)
+ if (status & 0x8000)
ack_cmd = eexp_start_irq(dev, status);
else
ack_cmd = SCB_ack(status);
@@ -880,14 +879,14 @@ static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
eexp_cmd_clear(dev);
- outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
+ outb(SIRQ_en|irqrmap[irq],ioaddr+SET_IRQ);
-#if NET_DEBUG > 6
+#if NET_DEBUG > 6
printk("%s: leaving eexp_irq()\n", dev->name);
#endif
outw(old_read_ptr, ioaddr+READ_PTR);
outw(old_write_ptr, ioaddr+WRITE_PTR);
-
+
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
@@ -935,7 +934,7 @@ static void eexp_hw_rx_pio(struct net_device *dev)
do {
unsigned short rfd_cmd, rx_next, pbuf, pkt_len;
-
+
outw(rx_block, ioaddr + READ_PTR);
status = inw(ioaddr + DATAPORT);
@@ -944,7 +943,7 @@ static void eexp_hw_rx_pio(struct net_device *dev)
rfd_cmd = inw(ioaddr + DATAPORT);
rx_next = inw(ioaddr + DATAPORT);
pbuf = inw(ioaddr + DATAPORT);
-
+
outw(pbuf, ioaddr + READ_PTR);
pkt_len = inw(ioaddr + DATAPORT);
@@ -956,17 +955,17 @@ static void eexp_hw_rx_pio(struct net_device *dev)
}
else if (pbuf!=rx_block+0x16)
{
- printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
+ printk(KERN_WARNING "%s: rfd and rbd out of sync 0x%04x 0x%04x\n",
dev->name, rx_block+0x16, pbuf);
continue;
}
- else if ((pkt_len & 0xc000)!=0xc000)
+ else if ((pkt_len & 0xc000)!=0xc000)
{
printk(KERN_WARNING "%s: EOF or F not set on received buffer (%04x)\n",
dev->name, pkt_len & 0xc000);
continue;
}
- else if (!FD_OK(status))
+ else if (!FD_OK(status))
{
lp->stats.rx_errors++;
if (FD_CRC(status))
@@ -1026,9 +1025,9 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
if (LOCKUP16 || lp->width) {
/* Stop the CU so that there is no chance that it
jumps off to a bogus address while we are writing the
- pointer to the next transmit packet in 8-bit mode --
+ pointer to the next transmit packet in 8-bit mode --
this eliminates the "CU wedged" errors in 8-bit mode.
- (Zoltan Szilagyi 10-12-96) */
+ (Zoltan Szilagyi 10-12-96) */
scb_command(dev, SCB_CUsuspend);
outw(0xFFFF, ioaddr+SIGNAL_CA);
}
@@ -1062,7 +1061,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf,
lp->tx_head += TX_BUF_SIZE;
if (lp->tx_head != lp->tx_reap)
netif_wake_queue(dev);
-
+
if (LOCKUP16 || lp->width) {
/* Restart the CU so that the packet can actually
be transmitted. (Zoltan Szilagyi 10-12-96) */
@@ -1103,7 +1102,7 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
/* Standard Address or Compaq LTE Address */
if (!((hw_addr[2]==0x00aa && ((hw_addr[1] & 0xff00)==0x0000)) ||
- (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
+ (hw_addr[2]==0x0080 && ((hw_addr[1] & 0xff00)==0x5F00))))
{
printk(" rejected: invalid address %04x%04x%04x\n",
hw_addr[2],hw_addr[1],hw_addr[0]);
@@ -1141,16 +1140,16 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
memset(lp, 0, sizeof(struct net_local));
spin_lock_init(&lp->lock);
- printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
+ printk("(IRQ %d, %s connector, %d-bit bus", dev->irq,
eexp_ifmap[dev->if_port], buswidth?8:16);
-
+
if (!request_region(dev->base_addr + 0x300e, 1, "EtherExpress"))
return -EBUSY;
eexp_hw_set_interface(dev);
-
+
release_region(dev->base_addr + 0x300e, 1);
-
+
/* Find out how much RAM we have on the card */
outw(0, dev->base_addr + WRITE_PTR);
for (i = 0; i < 32768; i++)
@@ -1285,7 +1284,7 @@ static unsigned short eexp_hw_lasttxstat(struct net_device *dev)
{
char *whatsup = NULL;
lp->stats.tx_errors++;
- if (Stat_Abort(status))
+ if (Stat_Abort(status))
lp->stats.tx_aborted_errors++;
if (Stat_TNoCar(status)) {
whatsup = "aborted, no carrier";
@@ -1461,11 +1460,11 @@ static void eexp_hw_rxinit(struct net_device *dev)
/* Close Rx frame descriptor ring */
outw(lp->rx_last + 4, ioaddr+WRITE_PTR);
outw(lp->rx_first, ioaddr+DATAPORT);
-
+
/* Close Rx buffer descriptor ring */
outw(lp->rx_last + 0x16 + 2, ioaddr+WRITE_PTR);
outw(lp->rx_first + 0x16, ioaddr+DATAPORT);
-
+
}
/*
@@ -1513,7 +1512,7 @@ static void eexp_hw_init586(struct net_device *dev)
/* Do we want promiscuous mode or multicast? */
outw(CONF_PROMISC & ~31, ioaddr+SM_PTR);
i = inw(ioaddr+SHADOW(CONF_PROMISC));
- outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
+ outw((dev->flags & IFF_PROMISC)?(i|1):(i & ~1),
ioaddr+SHADOW(CONF_PROMISC));
lp->was_promisc = dev->flags & IFF_PROMISC;
#if 0
@@ -1523,7 +1522,7 @@ static void eexp_hw_init586(struct net_device *dev)
/* Write our hardware address */
outw(CONF_HWADDR & ~31, ioaddr+SM_PTR);
outw(((unsigned short *)dev->dev_addr)[0], ioaddr+SHADOW(CONF_HWADDR));
- outw(((unsigned short *)dev->dev_addr)[1],
+ outw(((unsigned short *)dev->dev_addr)[1],
ioaddr+SHADOW(CONF_HWADDR+2));
outw(((unsigned short *)dev->dev_addr)[2],
ioaddr+SHADOW(CONF_HWADDR+4));
@@ -1609,7 +1608,7 @@ static void eexp_setup_filter(struct net_device *dev)
dev->name, count);
count = 8;
}
-
+
outw(CONF_NR_MULTICAST & ~31, ioaddr+SM_PTR);
outw(count, ioaddr+SHADOW(CONF_NR_MULTICAST));
for (i = 0; i < count; i++) {
@@ -1699,7 +1698,7 @@ MODULE_LICENSE("GPL");
* are specified, we verify and then use them. If no parameters are given, we
* autoprobe for one card only.
*/
-int init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/eexpress.h b/drivers/net/eexpress.h
index 28b43126848..707df3fcfe4 100644
--- a/drivers/net/eexpress.h
+++ b/drivers/net/eexpress.h
@@ -53,8 +53,8 @@
#define SCB_START 0x0008
/* Start of buffer region. Everything before this is used for control
- * structures and the CU configuration program. The memory layout is
- * determined in eexp_hw_probe(), once we know how much memory is
+ * structures and the CU configuration program. The memory layout is
+ * determined in eexp_hw_probe(), once we know how much memory is
* available on the card.
*/
@@ -64,7 +64,7 @@
#define RX_BUF_SIZE ((32+ETH_FRAME_LEN+31)&~0x1f)
/*
- * SCB defines
+ * SCB defines
*/
/* these functions take the SCB status word and test the relevant status bit */
@@ -95,7 +95,7 @@
#define SCB_RUabort 0x0040
/*
- * Command block defines
+ * Command block defines
*/
#define Stat_Done(s) ((s&0x8000)!=0)
@@ -158,9 +158,9 @@ struct rfd_header {
volatile unsigned short srcaddr2;
volatile unsigned short srcaddr3;
volatile unsigned short length;
-
- /* This is actually a Receive Buffer Descriptor. The way we
- * arrange memory means that an RBD always follows the RFD that
+
+ /* This is actually a Receive Buffer Descriptor. The way we
+ * arrange memory means that an RBD always follows the RFD that
* points to it, so they might as well be in the same structure.
*/
volatile unsigned short actual_count;
diff --git a/drivers/net/ehea/Makefile b/drivers/net/ehea/Makefile
new file mode 100644
index 00000000000..775d9969b5c
--- /dev/null
+++ b/drivers/net/ehea/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the eHEA ethernet device driver for IBM eServer System p
+#
+ehea-y = ehea_main.o ehea_phyp.o ehea_qmr.o ehea_ethtool.o ehea_phyp.o
+obj-$(CONFIG_EHEA) += ehea.o
+
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
new file mode 100644
index 00000000000..23b451a8ae1
--- /dev/null
+++ b/drivers/net/ehea/ehea.h
@@ -0,0 +1,447 @@
+/*
+ * linux/drivers/net/ehea/ehea.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 __EHEA_H__
+#define __EHEA_H__
+
+#include <linux/module.h>
+#include <linux/ethtool.h>
+#include <linux/vmalloc.h>
+#include <linux/if_vlan.h>
+
+#include <asm/ibmebus.h>
+#include <asm/abs_addr.h>
+#include <asm/io.h>
+
+#define DRV_NAME "ehea"
+#define DRV_VERSION "EHEA_0028"
+
+#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
+ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+#define EHEA_MAX_ENTRIES_RQ1 32767
+#define EHEA_MAX_ENTRIES_RQ2 16383
+#define EHEA_MAX_ENTRIES_RQ3 16383
+#define EHEA_MAX_ENTRIES_SQ 32767
+#define EHEA_MIN_ENTRIES_QP 127
+
+#define EHEA_NUM_TX_QP 1
+
+#ifdef EHEA_SMALL_QUEUES
+#define EHEA_MAX_CQE_COUNT 1023
+#define EHEA_DEF_ENTRIES_SQ 1023
+#define EHEA_DEF_ENTRIES_RQ1 4095
+#define EHEA_DEF_ENTRIES_RQ2 1023
+#define EHEA_DEF_ENTRIES_RQ3 1023
+#else
+#define EHEA_MAX_CQE_COUNT 32000
+#define EHEA_DEF_ENTRIES_SQ 16000
+#define EHEA_DEF_ENTRIES_RQ1 32080
+#define EHEA_DEF_ENTRIES_RQ2 4020
+#define EHEA_DEF_ENTRIES_RQ3 4020
+#endif
+
+#define EHEA_MAX_ENTRIES_EQ 20
+
+#define EHEA_SG_SQ 2
+#define EHEA_SG_RQ1 1
+#define EHEA_SG_RQ2 0
+#define EHEA_SG_RQ3 0
+
+#define EHEA_MAX_PACKET_SIZE 9022 /* for jumbo frames */
+#define EHEA_RQ2_PKT_SIZE 1522
+#define EHEA_L_PKT_SIZE 256 /* low latency */
+
+#define EHEA_POLL_MAX_RWQE 1000
+
+/* Send completion signaling */
+#define EHEA_SIG_IV_LONG 1
+
+/* Protection Domain Identifier */
+#define EHEA_PD_ID 0xaabcdeff
+
+#define EHEA_RQ2_THRESHOLD 1
+#define EHEA_RQ3_THRESHOLD 9 /* use RQ3 threshold of 1522 bytes */
+
+#define EHEA_SPEED_10G 10000
+#define EHEA_SPEED_1G 1000
+#define EHEA_SPEED_100M 100
+#define EHEA_SPEED_10M 10
+#define EHEA_SPEED_AUTONEG 0
+
+/* Broadcast/Multicast registration types */
+#define EHEA_BCMC_SCOPE_ALL 0x08
+#define EHEA_BCMC_SCOPE_SINGLE 0x00
+#define EHEA_BCMC_MULTICAST 0x04
+#define EHEA_BCMC_BROADCAST 0x00
+#define EHEA_BCMC_UNTAGGED 0x02
+#define EHEA_BCMC_TAGGED 0x00
+#define EHEA_BCMC_VLANID_ALL 0x01
+#define EHEA_BCMC_VLANID_SINGLE 0x00
+
+/* Use this define to kmallocate pHYP control blocks */
+#define H_CB_ALIGNMENT 4096
+
+#define EHEA_CACHE_LINE 128
+
+/* Memory Regions */
+#define EHEA_MR_MAX_TX_PAGES 20
+#define EHEA_MR_TX_DATA_PN 3
+#define EHEA_MR_ACC_CTRL 0x00800000
+#define EHEA_RWQES_PER_MR_RQ2 10
+#define EHEA_RWQES_PER_MR_RQ3 10
+
+#define EHEA_WATCH_DOG_TIMEOUT 10*HZ
+
+/* utility functions */
+
+#define ehea_info(fmt, args...) \
+ printk(KERN_INFO DRV_NAME ": " fmt "\n", ## args)
+
+#define ehea_error(fmt, args...) \
+ printk(KERN_ERR DRV_NAME ": Error in %s: " fmt "\n", __func__, ## args)
+
+#ifdef DEBUG
+#define ehea_debug(fmt, args...) \
+ printk(KERN_DEBUG DRV_NAME ": " fmt, ## args)
+#else
+#define ehea_debug(fmt, args...) do {} while (0)
+#endif
+
+void ehea_dump(void *adr, int len, char *msg);
+
+#define EHEA_BMASK(pos, length) (((pos) << 16) + (length))
+
+#define EHEA_BMASK_IBM(from, to) (((63 - to) << 16) + ((to) - (from) + 1))
+
+#define EHEA_BMASK_SHIFTPOS(mask) (((mask) >> 16) & 0xffff)
+
+#define EHEA_BMASK_MASK(mask) \
+ (0xffffffffffffffffULL >> ((64 - (mask)) & 0xffff))
+
+#define EHEA_BMASK_SET(mask, value) \
+ ((EHEA_BMASK_MASK(mask) & ((u64)(value))) << EHEA_BMASK_SHIFTPOS(mask))
+
+#define EHEA_BMASK_GET(mask, value) \
+ (EHEA_BMASK_MASK(mask) & (((u64)(value)) >> EHEA_BMASK_SHIFTPOS(mask)))
+
+/*
+ * Generic ehea page
+ */
+struct ehea_page {
+ u8 entries[PAGE_SIZE];
+};
+
+/*
+ * Generic queue in linux kernel virtual memory
+ */
+struct hw_queue {
+ u64 current_q_offset; /* current queue entry */
+ struct ehea_page **queue_pages; /* array of pages belonging to queue */
+ u32 qe_size; /* queue entry size */
+ u32 queue_length; /* queue length allocated in bytes */
+ u32 pagesize;
+ u32 toggle_state; /* toggle flag - per page */
+ u32 reserved; /* 64 bit alignment */
+};
+
+/*
+ * For pSeries this is a 64bit memory address where
+ * I/O memory is mapped into CPU address space
+ */
+struct h_epa {
+ void __iomem *addr;
+};
+
+struct h_epa_user {
+ u64 addr;
+};
+
+struct h_epas {
+ struct h_epa kernel; /* kernel space accessible resource,
+ set to 0 if unused */
+ struct h_epa_user user; /* user space accessible resource
+ set to 0 if unused */
+};
+
+struct ehea_qp;
+struct ehea_cq;
+struct ehea_eq;
+struct ehea_port;
+struct ehea_av;
+
+/*
+ * Queue attributes passed to ehea_create_qp()
+ */
+struct ehea_qp_init_attr {
+ /* input parameter */
+ u32 qp_token; /* queue token */
+ u8 low_lat_rq1;
+ u8 signalingtype; /* cqe generation flag */
+ u8 rq_count; /* num of receive queues */
+ u8 eqe_gen; /* eqe generation flag */
+ u16 max_nr_send_wqes; /* max number of send wqes */
+ u16 max_nr_rwqes_rq1; /* max number of receive wqes */
+ u16 max_nr_rwqes_rq2;
+ u16 max_nr_rwqes_rq3;
+ u8 wqe_size_enc_sq;
+ u8 wqe_size_enc_rq1;
+ u8 wqe_size_enc_rq2;
+ u8 wqe_size_enc_rq3;
+ u8 swqe_imm_data_len; /* immediate data length for swqes */
+ u16 port_nr;
+ u16 rq2_threshold;
+ u16 rq3_threshold;
+ u64 send_cq_handle;
+ u64 recv_cq_handle;
+ u64 aff_eq_handle;
+
+ /* output parameter */
+ u32 qp_nr;
+ u16 act_nr_send_wqes;
+ u16 act_nr_rwqes_rq1;
+ u16 act_nr_rwqes_rq2;
+ u16 act_nr_rwqes_rq3;
+ u8 act_wqe_size_enc_sq;
+ u8 act_wqe_size_enc_rq1;
+ u8 act_wqe_size_enc_rq2;
+ u8 act_wqe_size_enc_rq3;
+ u32 nr_sq_pages;
+ u32 nr_rq1_pages;
+ u32 nr_rq2_pages;
+ u32 nr_rq3_pages;
+ u32 liobn_sq;
+ u32 liobn_rq1;
+ u32 liobn_rq2;
+ u32 liobn_rq3;
+};
+
+/*
+ * Event Queue attributes, passed as paramter
+ */
+struct ehea_eq_attr {
+ u32 type;
+ u32 max_nr_of_eqes;
+ u8 eqe_gen; /* generate eqe flag */
+ u64 eq_handle;
+ u32 act_nr_of_eqes;
+ u32 nr_pages;
+ u32 ist1; /* Interrupt service token */
+ u32 ist2;
+ u32 ist3;
+ u32 ist4;
+};
+
+
+/*
+ * Event Queue
+ */
+struct ehea_eq {
+ struct ehea_adapter *adapter;
+ struct hw_queue hw_queue;
+ u64 fw_handle;
+ struct h_epas epas;
+ spinlock_t spinlock;
+ struct ehea_eq_attr attr;
+};
+
+/*
+ * HEA Queues
+ */
+struct ehea_qp {
+ struct ehea_adapter *adapter;
+ u64 fw_handle; /* QP handle for firmware calls */
+ struct hw_queue hw_squeue;
+ struct hw_queue hw_rqueue1;
+ struct hw_queue hw_rqueue2;
+ struct hw_queue hw_rqueue3;
+ struct h_epas epas;
+ struct ehea_qp_init_attr init_attr;
+};
+
+/*
+ * Completion Queue attributes
+ */
+struct ehea_cq_attr {
+ /* input parameter */
+ u32 max_nr_of_cqes;
+ u32 cq_token;
+ u64 eq_handle;
+
+ /* output parameter */
+ u32 act_nr_of_cqes;
+ u32 nr_pages;
+};
+
+/*
+ * Completion Queue
+ */
+struct ehea_cq {
+ struct ehea_adapter *adapter;
+ u64 fw_handle;
+ struct hw_queue hw_queue;
+ struct h_epas epas;
+ struct ehea_cq_attr attr;
+};
+
+/*
+ * Memory Region
+ */
+struct ehea_mr {
+ u64 handle;
+ u64 vaddr;
+ u32 lkey;
+};
+
+/*
+ * Port state information
+ */
+struct port_state {
+ int poll_max_processed;
+ int poll_receive_errors;
+ int ehea_poll;
+ int queue_stopped;
+ int min_swqe_avail;
+ u64 sqc_stop_sum;
+ int pkt_send;
+ int pkt_xmit;
+ int send_tasklet;
+ int nwqe;
+};
+
+#define EHEA_IRQ_NAME_SIZE 20
+
+/*
+ * Queue SKB Array
+ */
+struct ehea_q_skb_arr {
+ struct sk_buff **arr; /* skb array for queue */
+ int len; /* array length */
+ int index; /* array index */
+ int os_skbs; /* rq2/rq3 only: outstanding skbs */
+};
+
+/*
+ * Port resources
+ */
+struct ehea_port_res {
+ struct ehea_mr send_mr; /* send memory region */
+ struct ehea_mr recv_mr; /* receive memory region */
+ spinlock_t xmit_lock;
+ struct ehea_port *port;
+ char int_recv_name[EHEA_IRQ_NAME_SIZE];
+ char int_send_name[EHEA_IRQ_NAME_SIZE];
+ struct ehea_qp *qp;
+ struct ehea_cq *send_cq;
+ struct ehea_cq *recv_cq;
+ struct ehea_eq *send_eq;
+ struct ehea_eq *recv_eq;
+ spinlock_t send_lock;
+ struct ehea_q_skb_arr rq1_skba;
+ struct ehea_q_skb_arr rq2_skba;
+ struct ehea_q_skb_arr rq3_skba;
+ struct ehea_q_skb_arr sq_skba;
+ spinlock_t netif_queue;
+ int queue_stopped;
+ int swqe_refill_th;
+ atomic_t swqe_avail;
+ int swqe_ll_count;
+ int swqe_count;
+ u32 swqe_id_counter;
+ u64 tx_packets;
+ struct tasklet_struct send_comp_task;
+ spinlock_t recv_lock;
+ struct port_state p_state;
+ u64 rx_packets;
+ u32 poll_counter;
+};
+
+
+struct ehea_adapter {
+ u64 handle;
+ u8 num_ports;
+ struct ehea_port *port[16];
+ struct ehea_eq *neq; /* notification event queue */
+ struct workqueue_struct *ehea_wq;
+ struct tasklet_struct neq_tasklet;
+ struct ehea_mr mr;
+ u32 pd; /* protection domain */
+ u64 max_mc_mac; /* max number of multicast mac addresses */
+};
+
+
+struct ehea_mc_list {
+ struct list_head list;
+ u64 macaddr;
+};
+
+#define EHEA_PORT_UP 1
+#define EHEA_PORT_DOWN 0
+#define EHEA_MAX_PORT_RES 16
+struct ehea_port {
+ struct ehea_adapter *adapter; /* adapter that owns this port */
+ struct net_device *netdev;
+ struct net_device_stats stats;
+ struct ehea_port_res port_res[EHEA_MAX_PORT_RES];
+ struct device_node *of_dev_node; /* Open Firmware Device Node */
+ struct ehea_mc_list *mc_list; /* Multicast MAC addresses */
+ struct vlan_group *vgrp;
+ struct ehea_eq *qp_eq;
+ struct work_struct reset_task;
+ struct semaphore port_lock;
+ char int_aff_name[EHEA_IRQ_NAME_SIZE];
+ int allmulti; /* Indicates IFF_ALLMULTI state */
+ int promisc; /* Indicates IFF_PROMISC state */
+ int num_add_tx_qps;
+ int resets;
+ u64 mac_addr;
+ u32 logical_port_id;
+ u32 port_speed;
+ u32 msg_enable;
+ u32 sig_comp_iv;
+ u32 state;
+ u8 full_duplex;
+ u8 autoneg;
+ u8 num_def_qps;
+};
+
+struct port_res_cfg {
+ int max_entries_rcq;
+ int max_entries_scq;
+ int max_entries_sq;
+ int max_entries_rq1;
+ int max_entries_rq2;
+ int max_entries_rq3;
+};
+
+
+void ehea_set_ethtool_ops(struct net_device *netdev);
+int ehea_sense_port_attr(struct ehea_port *port);
+int ehea_set_portspeed(struct ehea_port *port, u32 port_speed);
+
+#endif /* __EHEA_H__ */
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c
new file mode 100644
index 00000000000..82eb2fb8c75
--- /dev/null
+++ b/drivers/net/ehea/ehea_ethtool.c
@@ -0,0 +1,294 @@
+/*
+ * linux/drivers/net/ehea/ehea_ethtool.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 "ehea.h"
+#include "ehea_phyp.h"
+
+static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ int ret;
+
+ ret = ehea_sense_port_attr(port);
+
+ if (ret)
+ return ret;
+
+ if (netif_carrier_ok(dev)) {
+ switch(port->port_speed) {
+ case EHEA_SPEED_10M: cmd->speed = SPEED_10; break;
+ case EHEA_SPEED_100M: cmd->speed = SPEED_100; break;
+ case EHEA_SPEED_1G: cmd->speed = SPEED_1000; break;
+ case EHEA_SPEED_10G: cmd->speed = SPEED_10000; break;
+ }
+ cmd->duplex = port->full_duplex == 1 ?
+ DUPLEX_FULL : DUPLEX_HALF;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+
+ cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full
+ | SUPPORTED_100baseT_Full | SUPPORTED_100baseT_Half
+ | SUPPORTED_10baseT_Full | SUPPORTED_10baseT_Half
+ | SUPPORTED_Autoneg | SUPPORTED_FIBRE);
+
+ cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_Autoneg
+ | ADVERTISED_FIBRE);
+
+ cmd->port = PORT_FIBRE;
+ cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+ return 0;
+}
+
+static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ int ret = 0;
+ u32 sp;
+
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ sp = EHEA_SPEED_AUTONEG;
+ goto doit;
+ }
+
+ switch(cmd->speed) {
+ case SPEED_10:
+ if (cmd->duplex == DUPLEX_FULL)
+ sp = H_SPEED_10M_F;
+ else
+ sp = H_SPEED_10M_H;
+ break;
+
+ case SPEED_100:
+ if (cmd->duplex == DUPLEX_FULL)
+ sp = H_SPEED_100M_F;
+ else
+ sp = H_SPEED_100M_H;
+ break;
+
+ case SPEED_1000:
+ if (cmd->duplex == DUPLEX_FULL)
+ sp = H_SPEED_1G_F;
+ else
+ ret = -EINVAL;
+ break;
+
+ case SPEED_10000:
+ if (cmd->duplex == DUPLEX_FULL)
+ sp = H_SPEED_10G_F;
+ else
+ ret = -EINVAL;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret)
+ goto out;
+doit:
+ ret = ehea_set_portspeed(port, sp);
+
+ if (!ret)
+ ehea_info("%s: Port speed succesfully set: %dMbps "
+ "%s Duplex",
+ port->netdev->name, port->port_speed,
+ port->full_duplex == 1 ? "Full" : "Half");
+out:
+ return ret;
+}
+
+static int ehea_nway_reset(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ int ret;
+
+ ret = ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
+
+ if (!ret)
+ ehea_info("%s: Port speed succesfully set: %dMbps "
+ "%s Duplex",
+ port->netdev->name, port->port_speed,
+ port->full_duplex == 1 ? "Full" : "Half");
+ return ret;
+}
+
+static void ehea_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1);
+ strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1);
+}
+
+static u32 ehea_get_msglevel(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ return port->msg_enable;
+}
+
+static void ehea_set_msglevel(struct net_device *dev, u32 value)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ port->msg_enable = value;
+}
+
+static u32 ehea_get_rx_csum(struct net_device *dev)
+{
+ return 1;
+}
+
+static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = {
+ {"poll_max_processed"},
+ {"queue_stopped"},
+ {"min_swqe_avail"},
+ {"poll_receive_err"},
+ {"pkt_send"},
+ {"pkt_xmit"},
+ {"send_tasklet"},
+ {"ehea_poll"},
+ {"nwqe"},
+ {"swqe_available_0"},
+ {"sig_comp_iv"},
+ {"swqe_refill_th"},
+ {"port resets"},
+ {"rxo"},
+ {"rx64"},
+ {"rx65"},
+ {"rx128"},
+ {"rx256"},
+ {"rx512"},
+ {"rx1024"},
+ {"txo"},
+ {"tx64"},
+ {"tx65"},
+ {"tx128"},
+ {"tx256"},
+ {"tx512"},
+ {"tx1024"},
+};
+
+static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ if (stringset == ETH_SS_STATS) {
+ memcpy(data, &ehea_ethtool_stats_keys,
+ sizeof(ehea_ethtool_stats_keys));
+ }
+}
+
+static int ehea_get_stats_count(struct net_device *dev)
+{
+ return ARRAY_SIZE(ehea_ethtool_stats_keys);
+}
+
+static void ehea_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ u64 hret;
+ int i;
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ struct ehea_port_res *pr = &port->port_res[0];
+ struct port_state *p_state = &pr->p_state;
+ struct hcp_ehea_port_cb6 *cb6;
+
+ for (i = 0; i < ehea_get_stats_count(dev); i++)
+ data[i] = 0;
+
+ i = 0;
+
+ data[i++] = p_state->poll_max_processed;
+ data[i++] = p_state->queue_stopped;
+ data[i++] = p_state->min_swqe_avail;
+ data[i++] = p_state->poll_receive_errors;
+ data[i++] = p_state->pkt_send;
+ data[i++] = p_state->pkt_xmit;
+ data[i++] = p_state->send_tasklet;
+ data[i++] = p_state->ehea_poll;
+ data[i++] = p_state->nwqe;
+ data[i++] = atomic_read(&port->port_res[0].swqe_avail);
+ data[i++] = port->sig_comp_iv;
+ data[i++] = port->port_res[0].swqe_refill_th;
+ data[i++] = port->resets;
+
+ cb6 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb6) {
+ ehea_error("no mem for cb6");
+ return;
+ }
+
+ hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+ H_PORT_CB6, H_PORT_CB6_ALL, cb6);
+ if (netif_msg_hw(port))
+ ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats");
+
+ if (hret == H_SUCCESS) {
+ data[i++] = cb6->rxo;
+ data[i++] = cb6->rx64;
+ data[i++] = cb6->rx65;
+ data[i++] = cb6->rx128;
+ data[i++] = cb6->rx256;
+ data[i++] = cb6->rx512;
+ data[i++] = cb6->rx1024;
+ data[i++] = cb6->txo;
+ data[i++] = cb6->tx64;
+ data[i++] = cb6->tx65;
+ data[i++] = cb6->tx128;
+ data[i++] = cb6->tx256;
+ data[i++] = cb6->tx512;
+ data[i++] = cb6->tx1024;
+ } else
+ ehea_error("query_ehea_port failed");
+
+ kfree(cb6);
+}
+
+const struct ethtool_ops ehea_ethtool_ops = {
+ .get_settings = ehea_get_settings,
+ .get_drvinfo = ehea_get_drvinfo,
+ .get_msglevel = ehea_get_msglevel,
+ .set_msglevel = ehea_set_msglevel,
+ .get_link = ethtool_op_get_link,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+ .get_strings = ehea_get_strings,
+ .get_stats_count = ehea_get_stats_count,
+ .get_ethtool_stats = ehea_get_ethtool_stats,
+ .get_rx_csum = ehea_get_rx_csum,
+ .set_settings = ehea_set_settings,
+ .nway_reset = ehea_nway_reset, /* Restart autonegotiation */
+};
+
+void ehea_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &ehea_ethtool_ops);
+}
diff --git a/drivers/net/ehea/ehea_hcall.h b/drivers/net/ehea/ehea_hcall.h
new file mode 100644
index 00000000000..8e7d1c3edc6
--- /dev/null
+++ b/drivers/net/ehea/ehea_hcall.h
@@ -0,0 +1,51 @@
+/*
+ * linux/drivers/net/ehea/ehea_hcall.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 __EHEA_HCALL_H__
+#define __EHEA_HCALL_H__
+
+/**
+ * This file contains HCALL defines that are to be included in the appropriate
+ * kernel files later
+ */
+
+#define H_ALLOC_HEA_RESOURCE 0x278
+#define H_MODIFY_HEA_QP 0x250
+#define H_QUERY_HEA_QP 0x254
+#define H_QUERY_HEA 0x258
+#define H_QUERY_HEA_PORT 0x25C
+#define H_MODIFY_HEA_PORT 0x260
+#define H_REG_BCMC 0x264
+#define H_DEREG_BCMC 0x268
+#define H_REGISTER_HEA_RPAGES 0x26C
+#define H_DISABLE_AND_GET_HEA 0x270
+#define H_GET_HEA_INFO 0x274
+#define H_ADD_CONN 0x284
+#define H_DEL_CONN 0x288
+
+#endif /* __EHEA_HCALL_H__ */
diff --git a/drivers/net/ehea/ehea_hw.h b/drivers/net/ehea/ehea_hw.h
new file mode 100644
index 00000000000..1246757f2c2
--- /dev/null
+++ b/drivers/net/ehea/ehea_hw.h
@@ -0,0 +1,292 @@
+/*
+ * linux/drivers/net/ehea/ehea_hw.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 __EHEA_HW_H__
+#define __EHEA_HW_H__
+
+#define QPX_SQA_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48,63)
+#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48,63)
+
+#define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x)
+
+struct ehea_qptemm {
+ u64 qpx_hcr;
+ u64 qpx_c;
+ u64 qpx_herr;
+ u64 qpx_aer;
+ u64 qpx_sqa;
+ u64 qpx_sqc;
+ u64 qpx_rq1a;
+ u64 qpx_rq1c;
+ u64 qpx_st;
+ u64 qpx_aerr;
+ u64 qpx_tenure;
+ u64 qpx_reserved1[(0x098 - 0x058) / 8];
+ u64 qpx_portp;
+ u64 qpx_reserved2[(0x100 - 0x0A0) / 8];
+ u64 qpx_t;
+ u64 qpx_sqhp;
+ u64 qpx_sqptp;
+ u64 qpx_reserved3[(0x140 - 0x118) / 8];
+ u64 qpx_sqwsize;
+ u64 qpx_reserved4[(0x170 - 0x148) / 8];
+ u64 qpx_sqsize;
+ u64 qpx_reserved5[(0x1B0 - 0x178) / 8];
+ u64 qpx_sigt;
+ u64 qpx_wqecnt;
+ u64 qpx_rq1hp;
+ u64 qpx_rq1ptp;
+ u64 qpx_rq1size;
+ u64 qpx_reserved6[(0x220 - 0x1D8) / 8];
+ u64 qpx_rq1wsize;
+ u64 qpx_reserved7[(0x240 - 0x228) / 8];
+ u64 qpx_pd;
+ u64 qpx_scqn;
+ u64 qpx_rcqn;
+ u64 qpx_aeqn;
+ u64 reserved49;
+ u64 qpx_ram;
+ u64 qpx_reserved8[(0x300 - 0x270) / 8];
+ u64 qpx_rq2a;
+ u64 qpx_rq2c;
+ u64 qpx_rq2hp;
+ u64 qpx_rq2ptp;
+ u64 qpx_rq2size;
+ u64 qpx_rq2wsize;
+ u64 qpx_rq2th;
+ u64 qpx_rq3a;
+ u64 qpx_rq3c;
+ u64 qpx_rq3hp;
+ u64 qpx_rq3ptp;
+ u64 qpx_rq3size;
+ u64 qpx_rq3wsize;
+ u64 qpx_rq3th;
+ u64 qpx_lpn;
+ u64 qpx_reserved9[(0x400 - 0x378) / 8];
+ u64 reserved_ext[(0x500 - 0x400) / 8];
+ u64 reserved2[(0x1000 - 0x500) / 8];
+};
+
+#define MRx_HCR_LPARID_VALID EHEA_BMASK_IBM(0, 0)
+
+#define MRMWMM_OFFSET(x) offsetof(struct ehea_mrmwmm, x)
+
+struct ehea_mrmwmm {
+ u64 mrx_hcr;
+ u64 mrx_c;
+ u64 mrx_herr;
+ u64 mrx_aer;
+ u64 mrx_pp;
+ u64 reserved1;
+ u64 reserved2;
+ u64 reserved3;
+ u64 reserved4[(0x200 - 0x40) / 8];
+ u64 mrx_ctl[64];
+};
+
+#define QPEDMM_OFFSET(x) offsetof(struct ehea_qpedmm, x)
+
+struct ehea_qpedmm {
+
+ u64 reserved0[(0x400) / 8];
+ u64 qpedx_phh;
+ u64 qpedx_ppsgp;
+ u64 qpedx_ppsgu;
+ u64 qpedx_ppdgp;
+ u64 qpedx_ppdgu;
+ u64 qpedx_aph;
+ u64 qpedx_apsgp;
+ u64 qpedx_apsgu;
+ u64 qpedx_apdgp;
+ u64 qpedx_apdgu;
+ u64 qpedx_apav;
+ u64 qpedx_apsav;
+ u64 qpedx_hcr;
+ u64 reserved1[4];
+ u64 qpedx_rrl0;
+ u64 qpedx_rrrkey0;
+ u64 qpedx_rrva0;
+ u64 reserved2;
+ u64 qpedx_rrl1;
+ u64 qpedx_rrrkey1;
+ u64 qpedx_rrva1;
+ u64 reserved3;
+ u64 qpedx_rrl2;
+ u64 qpedx_rrrkey2;
+ u64 qpedx_rrva2;
+ u64 reserved4;
+ u64 qpedx_rrl3;
+ u64 qpedx_rrrkey3;
+ u64 qpedx_rrva3;
+};
+
+#define CQX_FECADDER EHEA_BMASK_IBM(32, 63)
+#define CQX_FEC_CQE_CNT EHEA_BMASK_IBM(32, 63)
+#define CQX_N1_GENERATE_COMP_EVENT EHEA_BMASK_IBM(0, 0)
+#define CQX_EP_EVENT_PENDING EHEA_BMASK_IBM(0, 0)
+
+#define CQTEMM_OFFSET(x) offsetof(struct ehea_cqtemm, x)
+
+struct ehea_cqtemm {
+ u64 cqx_hcr;
+ u64 cqx_c;
+ u64 cqx_herr;
+ u64 cqx_aer;
+ u64 cqx_ptp;
+ u64 cqx_tp;
+ u64 cqx_fec;
+ u64 cqx_feca;
+ u64 cqx_ep;
+ u64 cqx_eq;
+ u64 reserved1;
+ u64 cqx_n0;
+ u64 cqx_n1;
+ u64 reserved2[(0x1000 - 0x60) / 8];
+};
+
+#define EQTEMM_OFFSET(x) offsetof(struct ehea_eqtemm, x)
+
+struct ehea_eqtemm {
+ u64 eqx_hcr;
+ u64 eqx_c;
+ u64 eqx_herr;
+ u64 eqx_aer;
+ u64 eqx_ptp;
+ u64 eqx_tp;
+ u64 eqx_ssba;
+ u64 eqx_psba;
+ u64 eqx_cec;
+ u64 eqx_meql;
+ u64 eqx_xisbi;
+ u64 eqx_xisc;
+ u64 eqx_it;
+};
+
+/*
+ * These access functions will be changed when the dissuccsion about
+ * the new access methods for POWER has settled.
+ */
+
+static inline u64 epa_load(struct h_epa epa, u32 offset)
+{
+ return __raw_readq((void __iomem *)(epa.addr + offset));
+}
+
+static inline void epa_store(struct h_epa epa, u32 offset, u64 value)
+{
+ __raw_writeq(value, (void __iomem *)(epa.addr + offset));
+ epa_load(epa, offset); /* synchronize explicitly to eHEA */
+}
+
+static inline void epa_store_acc(struct h_epa epa, u32 offset, u64 value)
+{
+ __raw_writeq(value, (void __iomem *)(epa.addr + offset));
+}
+
+#define epa_store_eq(epa, offset, value)\
+ epa_store(epa, EQTEMM_OFFSET(offset), value)
+#define epa_load_eq(epa, offset)\
+ epa_load(epa, EQTEMM_OFFSET(offset))
+
+#define epa_store_cq(epa, offset, value)\
+ epa_store(epa, CQTEMM_OFFSET(offset), value)
+#define epa_load_cq(epa, offset)\
+ epa_load(epa, CQTEMM_OFFSET(offset))
+
+#define epa_store_qp(epa, offset, value)\
+ epa_store(epa, QPTEMM_OFFSET(offset), value)
+#define epa_load_qp(epa, offset)\
+ epa_load(epa, QPTEMM_OFFSET(offset))
+
+#define epa_store_qped(epa, offset, value)\
+ epa_store(epa, QPEDMM_OFFSET(offset), value)
+#define epa_load_qped(epa, offset)\
+ epa_load(epa, QPEDMM_OFFSET(offset))
+
+#define epa_store_mrmw(epa, offset, value)\
+ epa_store(epa, MRMWMM_OFFSET(offset), value)
+#define epa_load_mrmw(epa, offset)\
+ epa_load(epa, MRMWMM_OFFSET(offset))
+
+#define epa_store_base(epa, offset, value)\
+ epa_store(epa, HCAGR_OFFSET(offset), value)
+#define epa_load_base(epa, offset)\
+ epa_load(epa, HCAGR_OFFSET(offset))
+
+static inline void ehea_update_sqa(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_epa epa = qp->epas.kernel;
+ epa_store_acc(epa, QPTEMM_OFFSET(qpx_sqa),
+ EHEA_BMASK_SET(QPX_SQA_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_rq3a(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_epa epa = qp->epas.kernel;
+ epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq3a),
+ EHEA_BMASK_SET(QPX_RQ1A_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_rq2a(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_epa epa = qp->epas.kernel;
+ epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq2a),
+ EHEA_BMASK_SET(QPX_RQ2A_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_rq1a(struct ehea_qp *qp, u16 nr_wqes)
+{
+ struct h_epa epa = qp->epas.kernel;
+ epa_store_acc(epa, QPTEMM_OFFSET(qpx_rq1a),
+ EHEA_BMASK_SET(QPX_RQ3A_VALUE, nr_wqes));
+}
+
+static inline void ehea_update_feca(struct ehea_cq *cq, u32 nr_cqes)
+{
+ struct h_epa epa = cq->epas.kernel;
+ epa_store_acc(epa, CQTEMM_OFFSET(cqx_feca),
+ EHEA_BMASK_SET(CQX_FECADDER, nr_cqes));
+}
+
+static inline void ehea_reset_cq_n1(struct ehea_cq *cq)
+{
+ struct h_epa epa = cq->epas.kernel;
+ epa_store_cq(epa, cqx_n1,
+ EHEA_BMASK_SET(CQX_N1_GENERATE_COMP_EVENT, 1));
+}
+
+static inline void ehea_reset_cq_ep(struct ehea_cq *my_cq)
+{
+ struct h_epa epa = my_cq->epas.kernel;
+ epa_store_acc(epa, CQTEMM_OFFSET(cqx_ep),
+ EHEA_BMASK_SET(CQX_EP_EVENT_PENDING, 0));
+}
+
+#endif /* __EHEA_HW_H__ */
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
new file mode 100644
index 00000000000..263d1c5b3f2
--- /dev/null
+++ b/drivers/net/ehea/ehea_main.c
@@ -0,0 +1,2654 @@
+/*
+ * linux/drivers/net/ehea/ehea_main.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if.h>
+#include <linux/list.h>
+#include <linux/if_ether.h>
+#include <net/ip.h>
+
+#include "ehea.h"
+#include "ehea_qmr.h"
+#include "ehea_phyp.h"
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
+MODULE_DESCRIPTION("IBM eServer HEA Driver");
+MODULE_VERSION(DRV_VERSION);
+
+
+static int msg_level = -1;
+static int rq1_entries = EHEA_DEF_ENTRIES_RQ1;
+static int rq2_entries = EHEA_DEF_ENTRIES_RQ2;
+static int rq3_entries = EHEA_DEF_ENTRIES_RQ3;
+static int sq_entries = EHEA_DEF_ENTRIES_SQ;
+
+module_param(msg_level, int, 0);
+module_param(rq1_entries, int, 0);
+module_param(rq2_entries, int, 0);
+module_param(rq3_entries, int, 0);
+module_param(sq_entries, int, 0);
+
+MODULE_PARM_DESC(msg_level, "msg_level");
+MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 "
+ "[2^x - 1], x = [6..14]. Default = "
+ __MODULE_STRING(EHEA_DEF_ENTRIES_RQ3) ")");
+MODULE_PARM_DESC(rq2_entries, "Number of entries for Receive Queue 2 "
+ "[2^x - 1], x = [6..14]. Default = "
+ __MODULE_STRING(EHEA_DEF_ENTRIES_RQ2) ")");
+MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 "
+ "[2^x - 1], x = [6..14]. Default = "
+ __MODULE_STRING(EHEA_DEF_ENTRIES_RQ1) ")");
+MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue "
+ "[2^x - 1], x = [6..14]. Default = "
+ __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")");
+
+void ehea_dump(void *adr, int len, char *msg) {
+ int x;
+ unsigned char *deb = adr;
+ for (x = 0; x < len; x += 16) {
+ printk(DRV_NAME "%s adr=%p ofs=%04x %016lx %016lx\n", msg,
+ deb, x, *((u64*)&deb[0]), *((u64*)&deb[8]));
+ deb += 16;
+ }
+}
+
+static struct net_device_stats *ehea_get_stats(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct net_device_stats *stats = &port->stats;
+ struct hcp_ehea_port_cb2 *cb2;
+ u64 hret, rx_packets;
+ int i;
+
+ memset(stats, 0, sizeof(*stats));
+
+ cb2 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb2) {
+ ehea_error("no mem for cb2");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_port(port->adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB2, H_PORT_CB2_ALL, cb2);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_port failed");
+ goto out_herr;
+ }
+
+ if (netif_msg_hw(port))
+ ehea_dump(cb2, sizeof(*cb2), "net_device_stats");
+
+ rx_packets = 0;
+ for (i = 0; i < port->num_def_qps; i++)
+ rx_packets += port->port_res[i].rx_packets;
+
+ stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp;
+ stats->multicast = cb2->rxmcp;
+ stats->rx_errors = cb2->rxuerr;
+ stats->rx_bytes = cb2->rxo;
+ stats->tx_bytes = cb2->txo;
+ stats->rx_packets = rx_packets;
+
+out_herr:
+ kfree(cb2);
+out:
+ return stats;
+}
+
+static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
+{
+ struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
+ struct net_device *dev = pr->port->netdev;
+ int max_index_mask = pr->rq1_skba.len - 1;
+ int i;
+
+ if (!nr_of_wqes)
+ return;
+
+ for (i = 0; i < nr_of_wqes; i++) {
+ if (!skb_arr_rq1[index]) {
+ skb_arr_rq1[index] = netdev_alloc_skb(dev,
+ EHEA_L_PKT_SIZE);
+ if (!skb_arr_rq1[index]) {
+ ehea_error("%s: no mem for skb/%d wqes filled",
+ dev->name, i);
+ break;
+ }
+ }
+ index--;
+ index &= max_index_mask;
+ }
+ /* Ring doorbell */
+ ehea_update_rq1a(pr->qp, i);
+}
+
+static int ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
+{
+ int ret = 0;
+ struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
+ struct net_device *dev = pr->port->netdev;
+ int i;
+
+ for (i = 0; i < pr->rq1_skba.len; i++) {
+ skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
+ if (!skb_arr_rq1[i]) {
+ ehea_error("%s: no mem for skb/%d wqes filled",
+ dev->name, i);
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ /* Ring doorbell */
+ ehea_update_rq1a(pr->qp, nr_rq1a);
+out:
+ return ret;
+}
+
+static int ehea_refill_rq_def(struct ehea_port_res *pr,
+ struct ehea_q_skb_arr *q_skba, int rq_nr,
+ int num_wqes, int wqe_type, int packet_size)
+{
+ struct net_device *dev = pr->port->netdev;
+ struct ehea_qp *qp = pr->qp;
+ struct sk_buff **skb_arr = q_skba->arr;
+ struct ehea_rwqe *rwqe;
+ int i, index, max_index_mask, fill_wqes;
+ int ret = 0;
+
+ fill_wqes = q_skba->os_skbs + num_wqes;
+
+ if (!fill_wqes)
+ return ret;
+
+ index = q_skba->index;
+ max_index_mask = q_skba->len - 1;
+ for (i = 0; i < fill_wqes; i++) {
+ struct sk_buff *skb = netdev_alloc_skb(dev, packet_size);
+ if (!skb) {
+ ehea_error("%s: no mem for skb/%d wqes filled",
+ dev->name, i);
+ q_skba->os_skbs = fill_wqes - i;
+ ret = -ENOMEM;
+ break;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ skb_arr[index] = skb;
+
+ rwqe = ehea_get_next_rwqe(qp, rq_nr);
+ rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, wqe_type)
+ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index);
+ rwqe->sg_list[0].l_key = pr->recv_mr.lkey;
+ rwqe->sg_list[0].vaddr = (u64)skb->data;
+ rwqe->sg_list[0].len = packet_size;
+ rwqe->data_segments = 1;
+
+ index++;
+ index &= max_index_mask;
+ }
+ q_skba->index = index;
+
+ /* Ring doorbell */
+ iosync();
+ if (rq_nr == 2)
+ ehea_update_rq2a(pr->qp, i);
+ else
+ ehea_update_rq3a(pr->qp, i);
+
+ return ret;
+}
+
+
+static int ehea_refill_rq2(struct ehea_port_res *pr, int nr_of_wqes)
+{
+ return ehea_refill_rq_def(pr, &pr->rq2_skba, 2,
+ nr_of_wqes, EHEA_RWQE2_TYPE,
+ EHEA_RQ2_PKT_SIZE + NET_IP_ALIGN);
+}
+
+
+static int ehea_refill_rq3(struct ehea_port_res *pr, int nr_of_wqes)
+{
+ return ehea_refill_rq_def(pr, &pr->rq3_skba, 3,
+ nr_of_wqes, EHEA_RWQE3_TYPE,
+ EHEA_MAX_PACKET_SIZE + NET_IP_ALIGN);
+}
+
+static inline int ehea_check_cqe(struct ehea_cqe *cqe, int *rq_num)
+{
+ *rq_num = (cqe->type & EHEA_CQE_TYPE_RQ) >> 5;
+ if ((cqe->status & EHEA_CQE_STAT_ERR_MASK) == 0)
+ return 0;
+ if (((cqe->status & EHEA_CQE_STAT_ERR_TCP) != 0) &&
+ (cqe->header_length == 0))
+ return 0;
+ return -EINVAL;
+}
+
+static inline void ehea_fill_skb(struct net_device *dev,
+ struct sk_buff *skb, struct ehea_cqe *cqe)
+{
+ int length = cqe->num_bytes_transfered - 4; /*remove CRC */
+
+ skb_put(skb, length);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb->protocol = eth_type_trans(skb, dev);
+}
+
+static inline struct sk_buff *get_skb_by_index(struct sk_buff **skb_array,
+ int arr_len,
+ struct ehea_cqe *cqe)
+{
+ int skb_index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+ struct sk_buff *skb;
+ void *pref;
+ int x;
+
+ x = skb_index + 1;
+ x &= (arr_len - 1);
+
+ pref = skb_array[x];
+ prefetchw(pref);
+ prefetchw(pref + EHEA_CACHE_LINE);
+
+ pref = (skb_array[x]->data);
+ prefetch(pref);
+ prefetch(pref + EHEA_CACHE_LINE);
+ prefetch(pref + EHEA_CACHE_LINE * 2);
+ prefetch(pref + EHEA_CACHE_LINE * 3);
+ skb = skb_array[skb_index];
+ skb_array[skb_index] = NULL;
+ return skb;
+}
+
+static inline struct sk_buff *get_skb_by_index_ll(struct sk_buff **skb_array,
+ int arr_len, int wqe_index)
+{
+ struct sk_buff *skb;
+ void *pref;
+ int x;
+
+ x = wqe_index + 1;
+ x &= (arr_len - 1);
+
+ pref = skb_array[x];
+ prefetchw(pref);
+ prefetchw(pref + EHEA_CACHE_LINE);
+
+ pref = (skb_array[x]->data);
+ prefetchw(pref);
+ prefetchw(pref + EHEA_CACHE_LINE);
+
+ skb = skb_array[wqe_index];
+ skb_array[wqe_index] = NULL;
+ return skb;
+}
+
+static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq,
+ struct ehea_cqe *cqe, int *processed_rq2,
+ int *processed_rq3)
+{
+ struct sk_buff *skb;
+
+ if (netif_msg_rx_err(pr->port)) {
+ ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr);
+ ehea_dump(cqe, sizeof(*cqe), "CQE");
+ }
+
+ if (rq == 2) {
+ *processed_rq2 += 1;
+ skb = get_skb_by_index(pr->rq2_skba.arr, pr->rq2_skba.len, cqe);
+ dev_kfree_skb(skb);
+ } else if (rq == 3) {
+ *processed_rq3 += 1;
+ skb = get_skb_by_index(pr->rq3_skba.arr, pr->rq3_skba.len, cqe);
+ dev_kfree_skb(skb);
+ }
+
+ if (cqe->status & EHEA_CQE_STAT_FAT_ERR_MASK) {
+ ehea_error("Critical receive error. Resetting port.");
+ queue_work(pr->port->adapter->ehea_wq, &pr->port->reset_task);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ehea_poll(struct net_device *dev, int *budget)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_port_res *pr = &port->port_res[0];
+ struct ehea_qp *qp = pr->qp;
+ struct ehea_cqe *cqe;
+ struct sk_buff *skb;
+ struct sk_buff **skb_arr_rq1 = pr->rq1_skba.arr;
+ struct sk_buff **skb_arr_rq2 = pr->rq2_skba.arr;
+ struct sk_buff **skb_arr_rq3 = pr->rq3_skba.arr;
+ int skb_arr_rq1_len = pr->rq1_skba.len;
+ int skb_arr_rq2_len = pr->rq2_skba.len;
+ int skb_arr_rq3_len = pr->rq3_skba.len;
+ int processed, processed_rq1, processed_rq2, processed_rq3;
+ int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset;
+
+ processed = processed_rq1 = processed_rq2 = processed_rq3 = 0;
+ last_wqe_index = 0;
+ my_quota = min(*budget, dev->quota);
+ my_quota = min(my_quota, EHEA_POLL_MAX_RWQE);
+
+ /* rq0 is low latency RQ */
+ cqe = ehea_poll_rq1(qp, &wqe_index);
+ while ((my_quota > 0) && cqe) {
+ ehea_inc_rq1(qp);
+ processed_rq1++;
+ processed++;
+ my_quota--;
+ if (netif_msg_rx_status(port))
+ ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+ last_wqe_index = wqe_index;
+ rmb();
+ if (!ehea_check_cqe(cqe, &rq)) {
+ if (rq == 1) { /* LL RQ1 */
+ skb = get_skb_by_index_ll(skb_arr_rq1,
+ skb_arr_rq1_len,
+ wqe_index);
+ if (unlikely(!skb)) {
+ if (netif_msg_rx_err(port))
+ ehea_error("LL rq1: skb=NULL");
+ skb = netdev_alloc_skb(dev,
+ EHEA_L_PKT_SIZE);
+ if (!skb)
+ break;
+ }
+ memcpy(skb->data, ((char*)cqe) + 64,
+ cqe->num_bytes_transfered - 4);
+ ehea_fill_skb(dev, skb, cqe);
+ } else if (rq == 2) { /* RQ2 */
+ skb = get_skb_by_index(skb_arr_rq2,
+ skb_arr_rq2_len, cqe);
+ if (unlikely(!skb)) {
+ if (netif_msg_rx_err(port))
+ ehea_error("rq2: skb=NULL");
+ break;
+ }
+ ehea_fill_skb(dev, skb, cqe);
+ processed_rq2++;
+ } else { /* RQ3 */
+ skb = get_skb_by_index(skb_arr_rq3,
+ skb_arr_rq3_len, cqe);
+ if (unlikely(!skb)) {
+ if (netif_msg_rx_err(port))
+ ehea_error("rq3: skb=NULL");
+ break;
+ }
+ ehea_fill_skb(dev, skb, cqe);
+ processed_rq3++;
+ }
+
+ if (cqe->status & EHEA_CQE_VLAN_TAG_XTRACT)
+ vlan_hwaccel_receive_skb(skb, port->vgrp,
+ cqe->vlan_tag);
+ else
+ netif_receive_skb(skb);
+
+ } else { /* Error occured */
+ pr->p_state.poll_receive_errors++;
+ port_reset = ehea_treat_poll_error(pr, rq, cqe,
+ &processed_rq2,
+ &processed_rq3);
+ if (port_reset)
+ break;
+ }
+ cqe = ehea_poll_rq1(qp, &wqe_index);
+ }
+
+ dev->quota -= processed;
+ *budget -= processed;
+
+ pr->p_state.ehea_poll += 1;
+ pr->rx_packets += processed;
+
+ ehea_refill_rq1(pr, last_wqe_index, processed_rq1);
+ ehea_refill_rq2(pr, processed_rq2);
+ ehea_refill_rq3(pr, processed_rq3);
+
+ intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF);
+
+ if (!cqe || intreq) {
+ netif_rx_complete(dev);
+ ehea_reset_cq_ep(pr->recv_cq);
+ ehea_reset_cq_n1(pr->recv_cq);
+ cqe = hw_qeit_get_valid(&qp->hw_rqueue1);
+ if (!cqe || intreq)
+ return 0;
+ if (!netif_rx_reschedule(dev, my_quota))
+ return 0;
+ }
+ return 1;
+}
+
+void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr)
+{
+ struct sk_buff *skb;
+ int index, max_index_mask, i;
+
+ index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id);
+ max_index_mask = pr->sq_skba.len - 1;
+ for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) {
+ skb = pr->sq_skba.arr[index];
+ if (likely(skb)) {
+ dev_kfree_skb(skb);
+ pr->sq_skba.arr[index] = NULL;
+ } else {
+ ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d",
+ cqe->wr_id, i, index);
+ }
+ index--;
+ index &= max_index_mask;
+ }
+}
+
+#define MAX_SENDCOMP_QUOTA 400
+void ehea_send_irq_tasklet(unsigned long data)
+{
+ struct ehea_port_res *pr = (struct ehea_port_res*)data;
+ struct ehea_cq *send_cq = pr->send_cq;
+ struct ehea_cqe *cqe;
+ int quota = MAX_SENDCOMP_QUOTA;
+ int cqe_counter = 0;
+ int swqe_av = 0;
+ unsigned long flags;
+
+ do {
+ cqe = ehea_poll_cq(send_cq);
+ if (!cqe) {
+ ehea_reset_cq_ep(send_cq);
+ ehea_reset_cq_n1(send_cq);
+ cqe = ehea_poll_cq(send_cq);
+ if (!cqe)
+ break;
+ }
+ cqe_counter++;
+ rmb();
+ if (cqe->status & EHEA_CQE_STAT_ERR_MASK) {
+ ehea_error("Send Completion Error: Resetting port");
+ if (netif_msg_tx_err(pr->port))
+ ehea_dump(cqe, sizeof(*cqe), "Send CQE");
+ queue_work(pr->port->adapter->ehea_wq,
+ &pr->port->reset_task);
+ break;
+ }
+
+ if (netif_msg_tx_done(pr->port))
+ ehea_dump(cqe, sizeof(*cqe), "CQE");
+
+ if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id)
+ == EHEA_SWQE2_TYPE))
+ free_sent_skbs(cqe, pr);
+
+ swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id);
+ quota--;
+ } while (quota > 0);
+
+ ehea_update_feca(send_cq, cqe_counter);
+ atomic_add(swqe_av, &pr->swqe_avail);
+
+ spin_lock_irqsave(&pr->netif_queue, flags);
+ if (pr->queue_stopped && (atomic_read(&pr->swqe_avail)
+ >= pr->swqe_refill_th)) {
+ netif_wake_queue(pr->port->netdev);
+ pr->queue_stopped = 0;
+ }
+ spin_unlock_irqrestore(&pr->netif_queue, flags);
+
+ if (unlikely(cqe))
+ tasklet_hi_schedule(&pr->send_comp_task);
+}
+
+static irqreturn_t ehea_send_irq_handler(int irq, void *param,
+ struct pt_regs *regs)
+{
+ struct ehea_port_res *pr = param;
+ tasklet_hi_schedule(&pr->send_comp_task);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ehea_recv_irq_handler(int irq, void *param,
+ struct pt_regs *regs)
+{
+ struct ehea_port_res *pr = param;
+ struct ehea_port *port = pr->port;
+ netif_rx_schedule(port->netdev);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param,
+ struct pt_regs *regs)
+{
+ struct ehea_port *port = param;
+ struct ehea_eqe *eqe;
+ u32 qp_token;
+
+ eqe = ehea_poll_eq(port->qp_eq);
+ ehea_debug("eqe=%p", eqe);
+ while (eqe) {
+ ehea_debug("*eqe=%lx", *(u64*)eqe);
+ eqe = ehea_poll_eq(port->qp_eq);
+ qp_token = EHEA_BMASK_GET(EHEA_EQE_QP_TOKEN, eqe->entry);
+ ehea_debug("next eqe=%p", eqe);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter,
+ int logical_port)
+{
+ int i;
+
+ for (i = 0; i < adapter->num_ports; i++)
+ if (adapter->port[i]->logical_port_id == logical_port)
+ return adapter->port[i];
+ return NULL;
+}
+
+int ehea_sense_port_attr(struct ehea_port *port)
+{
+ int ret;
+ u64 hret;
+ struct hcp_ehea_port_cb0 *cb0;
+
+ cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb0) {
+ ehea_error("no mem for cb0");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_port(port->adapter->handle,
+ port->logical_port_id, H_PORT_CB0,
+ EHEA_BMASK_SET(H_PORT_CB0_ALL, 0xFFFF),
+ cb0);
+ if (hret != H_SUCCESS) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ /* MAC address */
+ port->mac_addr = cb0->port_mac_addr << 16;
+
+ if (!is_valid_ether_addr((u8*)&port->mac_addr)) {
+ ret = -EADDRNOTAVAIL;
+ goto out_free;
+ }
+
+ /* Port speed */
+ switch (cb0->port_speed) {
+ case H_SPEED_10M_H:
+ port->port_speed = EHEA_SPEED_10M;
+ port->full_duplex = 0;
+ break;
+ case H_SPEED_10M_F:
+ port->port_speed = EHEA_SPEED_10M;
+ port->full_duplex = 1;
+ break;
+ case H_SPEED_100M_H:
+ port->port_speed = EHEA_SPEED_100M;
+ port->full_duplex = 0;
+ break;
+ case H_SPEED_100M_F:
+ port->port_speed = EHEA_SPEED_100M;
+ port->full_duplex = 1;
+ break;
+ case H_SPEED_1G_F:
+ port->port_speed = EHEA_SPEED_1G;
+ port->full_duplex = 1;
+ break;
+ case H_SPEED_10G_F:
+ port->port_speed = EHEA_SPEED_10G;
+ port->full_duplex = 1;
+ break;
+ default:
+ port->port_speed = 0;
+ port->full_duplex = 0;
+ break;
+ }
+
+ /* Number of default QPs */
+ port->num_def_qps = cb0->num_default_qps;
+
+ if (!port->num_def_qps) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ if (port->num_def_qps >= EHEA_NUM_TX_QP)
+ port->num_add_tx_qps = 0;
+ else
+ port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps;
+
+ ret = 0;
+out_free:
+ if (ret || netif_msg_probe(port))
+ ehea_dump(cb0, sizeof(*cb0), "ehea_sense_port_attr");
+ kfree(cb0);
+out:
+ return ret;
+}
+
+int ehea_set_portspeed(struct ehea_port *port, u32 port_speed)
+{
+ struct hcp_ehea_port_cb4 *cb4;
+ u64 hret;
+ int ret = 0;
+
+ cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb4) {
+ ehea_error("no mem for cb4");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cb4->port_speed = port_speed;
+
+ netif_carrier_off(port->netdev);
+
+ hret = ehea_h_modify_ehea_port(port->adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB4, H_PORT_CB4_SPEED, cb4);
+ if (hret == H_SUCCESS) {
+ port->autoneg = port_speed == EHEA_SPEED_AUTONEG ? 1 : 0;
+
+ hret = ehea_h_query_ehea_port(port->adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB4, H_PORT_CB4_SPEED,
+ cb4);
+ if (hret == H_SUCCESS) {
+ switch (cb4->port_speed) {
+ case H_SPEED_10M_H:
+ port->port_speed = EHEA_SPEED_10M;
+ port->full_duplex = 0;
+ break;
+ case H_SPEED_10M_F:
+ port->port_speed = EHEA_SPEED_10M;
+ port->full_duplex = 1;
+ break;
+ case H_SPEED_100M_H:
+ port->port_speed = EHEA_SPEED_100M;
+ port->full_duplex = 0;
+ break;
+ case H_SPEED_100M_F:
+ port->port_speed = EHEA_SPEED_100M;
+ port->full_duplex = 1;
+ break;
+ case H_SPEED_1G_F:
+ port->port_speed = EHEA_SPEED_1G;
+ port->full_duplex = 1;
+ break;
+ case H_SPEED_10G_F:
+ port->port_speed = EHEA_SPEED_10G;
+ port->full_duplex = 1;
+ break;
+ default:
+ port->port_speed = 0;
+ port->full_duplex = 0;
+ break;
+ }
+ } else {
+ ehea_error("Failed sensing port speed");
+ ret = -EIO;
+ }
+ } else {
+ if (hret == H_AUTHORITY) {
+ ehea_info("Hypervisor denied setting port speed. Either"
+ " this partition is not authorized to set "
+ "port speed or another partition has modified"
+ " port speed first.");
+ ret = -EPERM;
+ } else {
+ ret = -EIO;
+ ehea_error("Failed setting port speed");
+ }
+ }
+ netif_carrier_on(port->netdev);
+ kfree(cb4);
+out:
+ return ret;
+}
+
+static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
+{
+ int ret;
+ u8 ec;
+ u8 portnum;
+ struct ehea_port *port;
+
+ ec = EHEA_BMASK_GET(NEQE_EVENT_CODE, eqe);
+ portnum = EHEA_BMASK_GET(NEQE_PORTNUM, eqe);
+ port = ehea_get_port(adapter, portnum);
+
+ switch (ec) {
+ case EHEA_EC_PORTSTATE_CHG: /* port state change */
+
+ if (!port) {
+ ehea_error("unknown portnum %x", portnum);
+ break;
+ }
+
+ if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
+ if (!netif_carrier_ok(port->netdev)) {
+ ret = ehea_sense_port_attr(
+ adapter->port[portnum]);
+ if (ret) {
+ ehea_error("failed resensing port "
+ "attributes");
+ break;
+ }
+
+ if (netif_msg_link(port))
+ ehea_info("%s: Logical port up: %dMbps "
+ "%s Duplex",
+ port->netdev->name,
+ port->port_speed,
+ port->full_duplex ==
+ 1 ? "Full" : "Half");
+
+ netif_carrier_on(port->netdev);
+ netif_wake_queue(port->netdev);
+ }
+ } else
+ if (netif_carrier_ok(port->netdev)) {
+ if (netif_msg_link(port))
+ ehea_info("%s: Logical port down",
+ port->netdev->name);
+ netif_carrier_off(port->netdev);
+ netif_stop_queue(port->netdev);
+ }
+
+ if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PORT_UP, eqe)) {
+ if (netif_msg_link(port))
+ ehea_info("%s: Physical port up",
+ port->netdev->name);
+ } else {
+ if (netif_msg_link(port))
+ ehea_info("%s: Physical port down",
+ port->netdev->name);
+ }
+
+ if (EHEA_BMASK_GET(NEQE_EXTSWITCH_PRIMARY, eqe))
+ ehea_info("External switch port is primary port");
+ else
+ ehea_info("External switch port is backup port");
+
+ break;
+ case EHEA_EC_ADAPTER_MALFUNC:
+ ehea_error("Adapter malfunction");
+ break;
+ case EHEA_EC_PORT_MALFUNC:
+ ehea_info("Port malfunction: Device: %s", port->netdev->name);
+ netif_carrier_off(port->netdev);
+ netif_stop_queue(port->netdev);
+ break;
+ default:
+ ehea_error("unknown event code %x", ec);
+ break;
+ }
+}
+
+static void ehea_neq_tasklet(unsigned long data)
+{
+ struct ehea_adapter *adapter = (struct ehea_adapter*)data;
+ struct ehea_eqe *eqe;
+ u64 event_mask;
+
+ eqe = ehea_poll_eq(adapter->neq);
+ ehea_debug("eqe=%p", eqe);
+
+ while (eqe) {
+ ehea_debug("*eqe=%lx", eqe->entry);
+ ehea_parse_eqe(adapter, eqe->entry);
+ eqe = ehea_poll_eq(adapter->neq);
+ ehea_debug("next eqe=%p", eqe);
+ }
+
+ event_mask = EHEA_BMASK_SET(NELR_PORTSTATE_CHG, 1)
+ | EHEA_BMASK_SET(NELR_ADAPTER_MALFUNC, 1)
+ | EHEA_BMASK_SET(NELR_PORT_MALFUNC, 1);
+
+ ehea_h_reset_events(adapter->handle,
+ adapter->neq->fw_handle, event_mask);
+}
+
+static irqreturn_t ehea_interrupt_neq(int irq, void *param,
+ struct pt_regs *regs)
+{
+ struct ehea_adapter *adapter = param;
+ tasklet_hi_schedule(&adapter->neq_tasklet);
+ return IRQ_HANDLED;
+}
+
+
+static int ehea_fill_port_res(struct ehea_port_res *pr)
+{
+ int ret;
+ struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr;
+
+ ret = ehea_init_fill_rq1(pr, init_attr->act_nr_rwqes_rq1
+ - init_attr->act_nr_rwqes_rq2
+ - init_attr->act_nr_rwqes_rq3 - 1);
+
+ ret |= ehea_refill_rq2(pr, init_attr->act_nr_rwqes_rq2 - 1);
+
+ ret |= ehea_refill_rq3(pr, init_attr->act_nr_rwqes_rq3 - 1);
+
+ return ret;
+}
+
+static int ehea_reg_interrupts(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_port_res *pr;
+ int i, ret;
+
+ for (i = 0; i < port->num_def_qps; i++) {
+ pr = &port->port_res[i];
+ snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1
+ , "%s-recv%d", dev->name, i);
+ ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1,
+ ehea_recv_irq_handler,
+ SA_INTERRUPT, pr->int_recv_name, pr);
+ if (ret) {
+ ehea_error("failed registering irq for ehea_recv_int:"
+ "port_res_nr:%d, ist=%X", i,
+ pr->recv_eq->attr.ist1);
+ goto out_free_seq;
+ }
+ if (netif_msg_ifup(port))
+ ehea_info("irq_handle 0x%X for funct ehea_recv_int %d "
+ "registered", pr->recv_eq->attr.ist1, i);
+ }
+
+ snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff",
+ dev->name);
+
+ ret = ibmebus_request_irq(NULL, port->qp_eq->attr.ist1,
+ ehea_qp_aff_irq_handler,
+ SA_INTERRUPT, port->int_aff_name, port);
+ if (ret) {
+ ehea_error("failed registering irq for qp_aff_irq_handler:"
+ "ist=%X", port->qp_eq->attr.ist1);
+ goto out_free_qpeq;
+ }
+
+ if (netif_msg_ifup(port))
+ ehea_info("irq_handle 0x%X for function qp_aff_irq_handler "
+ "registered", port->qp_eq->attr.ist1);
+
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ pr = &port->port_res[i];
+ snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1,
+ "%s-send%d", dev->name, i);
+ ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1,
+ ehea_send_irq_handler,
+ SA_INTERRUPT, pr->int_send_name,
+ pr);
+ if (ret) {
+ ehea_error("failed registering irq for ehea_send "
+ "port_res_nr:%d, ist=%X", i,
+ pr->send_eq->attr.ist1);
+ goto out_free_req;
+ }
+ if (netif_msg_ifup(port))
+ ehea_info("irq_handle 0x%X for function ehea_send_int "
+ "%d registered", pr->send_eq->attr.ist1, i);
+ }
+out:
+ return ret;
+
+out_free_req:
+ while (--i >= 0) {
+ u32 ist = port->port_res[i].send_eq->attr.ist1;
+ ibmebus_free_irq(NULL, ist, &port->port_res[i]);
+ }
+out_free_qpeq:
+ ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+ i = port->num_def_qps;
+out_free_seq:
+ while (--i >= 0) {
+ u32 ist = port->port_res[i].recv_eq->attr.ist1;
+ ibmebus_free_irq(NULL, ist, &port->port_res[i]);
+ }
+ goto out;
+}
+
+static void ehea_free_interrupts(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_port_res *pr;
+ int i;
+
+ /* send */
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ pr = &port->port_res[i];
+ ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr);
+ if (netif_msg_intr(port))
+ ehea_info("free send irq for res %d with handle 0x%X",
+ i, pr->send_eq->attr.ist1);
+ }
+
+ /* receive */
+ for (i = 0; i < port->num_def_qps; i++) {
+ pr = &port->port_res[i];
+ ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr);
+ if (netif_msg_intr(port))
+ ehea_info("free recv irq for res %d with handle 0x%X",
+ i, pr->recv_eq->attr.ist1);
+ }
+
+ /* associated events */
+ ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port);
+ if (netif_msg_intr(port))
+ ehea_info("associated event interrupt for handle 0x%X freed",
+ port->qp_eq->attr.ist1);
+}
+
+static int ehea_configure_port(struct ehea_port *port)
+{
+ int ret, i;
+ u64 hret, mask;
+ struct hcp_ehea_port_cb0 *cb0;
+
+ ret = -ENOMEM;
+ cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb0)
+ goto out;
+
+ cb0->port_rc = EHEA_BMASK_SET(PXLY_RC_VALID, 1)
+ | EHEA_BMASK_SET(PXLY_RC_IP_CHKSUM, 1)
+ | EHEA_BMASK_SET(PXLY_RC_TCP_UDP_CHKSUM, 1)
+ | EHEA_BMASK_SET(PXLY_RC_VLAN_XTRACT, 1)
+ | EHEA_BMASK_SET(PXLY_RC_VLAN_TAG_FILTER,
+ PXLY_RC_VLAN_FILTER)
+ | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1);
+
+ for (i = 0; i < port->num_def_qps; i++)
+ cb0->default_qpn_arr[i] = port->port_res[i].qp->init_attr.qp_nr;
+
+ if (netif_msg_ifup(port))
+ ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port");
+
+ mask = EHEA_BMASK_SET(H_PORT_CB0_PRC, 1)
+ | EHEA_BMASK_SET(H_PORT_CB0_DEFQPNARRAY, 1);
+
+ hret = ehea_h_modify_ehea_port(port->adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB0, mask, cb0);
+ ret = -EIO;
+ if (hret != H_SUCCESS)
+ goto out_free;
+
+ ret = 0;
+
+out_free:
+ kfree(cb0);
+out:
+ return ret;
+}
+
+static int ehea_gen_smrs(struct ehea_port_res *pr)
+{
+ u64 hret;
+ struct ehea_adapter *adapter = pr->port->adapter;
+
+ hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
+ adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
+ adapter->pd, &pr->send_mr);
+ if (hret != H_SUCCESS)
+ goto out;
+
+ hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle,
+ adapter->mr.vaddr, EHEA_MR_ACC_CTRL,
+ adapter->pd, &pr->recv_mr);
+ if (hret != H_SUCCESS)
+ goto out_freeres;
+
+ return 0;
+
+out_freeres:
+ hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
+ if (hret != H_SUCCESS)
+ ehea_error("failed freeing SMR");
+out:
+ return -EIO;
+}
+
+static int ehea_rem_smrs(struct ehea_port_res *pr)
+{
+ struct ehea_adapter *adapter = pr->port->adapter;
+ int ret = 0;
+ u64 hret;
+
+ hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle);
+ if (hret != H_SUCCESS) {
+ ret = -EIO;
+ ehea_error("failed freeing send SMR for pr=%p", pr);
+ }
+
+ hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle);
+ if (hret != H_SUCCESS) {
+ ret = -EIO;
+ ehea_error("failed freeing recv SMR for pr=%p", pr);
+ }
+
+ return ret;
+}
+
+static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries)
+{
+ int arr_size = sizeof(void*) * max_q_entries;
+
+ q_skba->arr = vmalloc(arr_size);
+ if (!q_skba->arr)
+ return -ENOMEM;
+
+ memset(q_skba->arr, 0, arr_size);
+
+ q_skba->len = max_q_entries;
+ q_skba->index = 0;
+ q_skba->os_skbs = 0;
+
+ return 0;
+}
+
+static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr,
+ struct port_res_cfg *pr_cfg, int queue_token)
+{
+ struct ehea_adapter *adapter = port->adapter;
+ enum ehea_eq_type eq_type = EHEA_EQ;
+ struct ehea_qp_init_attr *init_attr = NULL;
+ int ret = -EIO;
+
+ memset(pr, 0, sizeof(struct ehea_port_res));
+
+ pr->port = port;
+ spin_lock_init(&pr->send_lock);
+ spin_lock_init(&pr->recv_lock);
+ spin_lock_init(&pr->xmit_lock);
+ spin_lock_init(&pr->netif_queue);
+
+ pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
+ if (!pr->recv_eq) {
+ ehea_error("create_eq failed (recv_eq)");
+ goto out_free;
+ }
+
+ pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0);
+ if (!pr->send_eq) {
+ ehea_error("create_eq failed (send_eq)");
+ goto out_free;
+ }
+
+ pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq,
+ pr->recv_eq->fw_handle,
+ port->logical_port_id);
+ if (!pr->recv_cq) {
+ ehea_error("create_cq failed (cq_recv)");
+ goto out_free;
+ }
+
+ pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq,
+ pr->send_eq->fw_handle,
+ port->logical_port_id);
+ if (!pr->send_cq) {
+ ehea_error("create_cq failed (cq_send)");
+ goto out_free;
+ }
+
+ if (netif_msg_ifup(port))
+ ehea_info("Send CQ: act_nr_cqes=%d, Recv CQ: act_nr_cqes=%d",
+ pr->send_cq->attr.act_nr_of_cqes,
+ pr->recv_cq->attr.act_nr_of_cqes);
+
+ init_attr = kzalloc(sizeof(*init_attr), GFP_KERNEL);
+ if (!init_attr) {
+ ret = -ENOMEM;
+ ehea_error("no mem for ehea_qp_init_attr");
+ goto out_free;
+ }
+
+ init_attr->low_lat_rq1 = 1;
+ init_attr->signalingtype = 1; /* generate CQE if specified in WQE */
+ init_attr->rq_count = 3;
+ init_attr->qp_token = queue_token;
+ init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq;
+ init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1;
+ init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2;
+ init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3;
+ init_attr->wqe_size_enc_sq = EHEA_SG_SQ;
+ init_attr->wqe_size_enc_rq1 = EHEA_SG_RQ1;
+ init_attr->wqe_size_enc_rq2 = EHEA_SG_RQ2;
+ init_attr->wqe_size_enc_rq3 = EHEA_SG_RQ3;
+ init_attr->rq2_threshold = EHEA_RQ2_THRESHOLD;
+ init_attr->rq3_threshold = EHEA_RQ3_THRESHOLD;
+ init_attr->port_nr = port->logical_port_id;
+ init_attr->send_cq_handle = pr->send_cq->fw_handle;
+ init_attr->recv_cq_handle = pr->recv_cq->fw_handle;
+ init_attr->aff_eq_handle = port->qp_eq->fw_handle;
+
+ pr->qp = ehea_create_qp(adapter, adapter->pd, init_attr);
+ if (!pr->qp) {
+ ehea_error("create_qp failed");
+ ret = -EIO;
+ goto out_free;
+ }
+
+ if (netif_msg_ifup(port))
+ ehea_info("QP: qp_nr=%d\n act_nr_snd_wqe=%d\n nr_rwqe_rq1=%d\n "
+ "nr_rwqe_rq2=%d\n nr_rwqe_rq3=%d", init_attr->qp_nr,
+ init_attr->act_nr_send_wqes,
+ init_attr->act_nr_rwqes_rq1,
+ init_attr->act_nr_rwqes_rq2,
+ init_attr->act_nr_rwqes_rq3);
+
+ ret = ehea_init_q_skba(&pr->sq_skba, init_attr->act_nr_send_wqes + 1);
+ ret |= ehea_init_q_skba(&pr->rq1_skba, init_attr->act_nr_rwqes_rq1 + 1);
+ ret |= ehea_init_q_skba(&pr->rq2_skba, init_attr->act_nr_rwqes_rq2 + 1);
+ ret |= ehea_init_q_skba(&pr->rq3_skba, init_attr->act_nr_rwqes_rq3 + 1);
+ if (ret)
+ goto out_free;
+
+ pr->swqe_refill_th = init_attr->act_nr_send_wqes / 10;
+ if (ehea_gen_smrs(pr) != 0) {
+ ret = -EIO;
+ goto out_free;
+ }
+ tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet,
+ (unsigned long)pr);
+ atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1);
+
+ kfree(init_attr);
+ ret = 0;
+ goto out;
+
+out_free:
+ kfree(init_attr);
+ vfree(pr->sq_skba.arr);
+ vfree(pr->rq1_skba.arr);
+ vfree(pr->rq2_skba.arr);
+ vfree(pr->rq3_skba.arr);
+ ehea_destroy_qp(pr->qp);
+ ehea_destroy_cq(pr->send_cq);
+ ehea_destroy_cq(pr->recv_cq);
+ ehea_destroy_eq(pr->send_eq);
+ ehea_destroy_eq(pr->recv_eq);
+out:
+ return ret;
+}
+
+static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr)
+{
+ int ret, i;
+
+ ret = ehea_destroy_qp(pr->qp);
+
+ if (!ret) {
+ ehea_destroy_cq(pr->send_cq);
+ ehea_destroy_cq(pr->recv_cq);
+ ehea_destroy_eq(pr->send_eq);
+ ehea_destroy_eq(pr->recv_eq);
+
+ for (i = 0; i < pr->rq1_skba.len; i++)
+ if (pr->rq1_skba.arr[i])
+ dev_kfree_skb(pr->rq1_skba.arr[i]);
+
+ for (i = 0; i < pr->rq2_skba.len; i++)
+ if (pr->rq2_skba.arr[i])
+ dev_kfree_skb(pr->rq2_skba.arr[i]);
+
+ for (i = 0; i < pr->rq3_skba.len; i++)
+ if (pr->rq3_skba.arr[i])
+ dev_kfree_skb(pr->rq3_skba.arr[i]);
+
+ for (i = 0; i < pr->sq_skba.len; i++)
+ if (pr->sq_skba.arr[i])
+ dev_kfree_skb(pr->sq_skba.arr[i]);
+
+ vfree(pr->rq1_skba.arr);
+ vfree(pr->rq2_skba.arr);
+ vfree(pr->rq3_skba.arr);
+ vfree(pr->sq_skba.arr);
+ ret = ehea_rem_smrs(pr);
+ }
+ return ret;
+}
+
+/*
+ * The write_* functions store information in swqe which is used by
+ * the hardware to calculate the ip/tcp/udp checksum
+ */
+
+static inline void write_ip_start_end(struct ehea_swqe *swqe,
+ const struct sk_buff *skb)
+{
+ swqe->ip_start = (u8)(((u64)skb->nh.iph) - ((u64)skb->data));
+ swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl * 4 - 1);
+}
+
+static inline void write_tcp_offset_end(struct ehea_swqe *swqe,
+ const struct sk_buff *skb)
+{
+ swqe->tcp_offset =
+ (u8)(swqe->ip_end + 1 + offsetof(struct tcphdr, check));
+
+ swqe->tcp_end = (u16)skb->len - 1;
+}
+
+static inline void write_udp_offset_end(struct ehea_swqe *swqe,
+ const struct sk_buff *skb)
+{
+ swqe->tcp_offset =
+ (u8)(swqe->ip_end + 1 + offsetof(struct udphdr, check));
+
+ swqe->tcp_end = (u16)skb->len - 1;
+}
+
+
+static void write_swqe2_TSO(struct sk_buff *skb,
+ struct ehea_swqe *swqe, u32 lkey)
+{
+ struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
+ u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
+ int skb_data_size = skb->len - skb->data_len;
+ int headersize;
+ u64 tmp_addr;
+
+ /* Packet is TCP with TSO enabled */
+ swqe->tx_control |= EHEA_SWQE_TSO;
+ swqe->mss = skb_shinfo(skb)->gso_size;
+ /* copy only eth/ip/tcp headers to immediate data and
+ * the rest of skb->data to sg1entry
+ */
+ headersize = ETH_HLEN + (skb->nh.iph->ihl * 4) + (skb->h.th->doff * 4);
+
+ skb_data_size = skb->len - skb->data_len;
+
+ if (skb_data_size >= headersize) {
+ /* copy immediate data */
+ memcpy(imm_data, skb->data, headersize);
+ swqe->immediate_data_length = headersize;
+
+ if (skb_data_size > headersize) {
+ /* set sg1entry data */
+ sg1entry->l_key = lkey;
+ sg1entry->len = skb_data_size - headersize;
+
+ tmp_addr = (u64)(skb->data + headersize);
+ sg1entry->vaddr = tmp_addr;
+ swqe->descriptors++;
+ }
+ } else
+ ehea_error("cannot handle fragmented headers");
+}
+
+static void write_swqe2_nonTSO(struct sk_buff *skb,
+ struct ehea_swqe *swqe, u32 lkey)
+{
+ int skb_data_size = skb->len - skb->data_len;
+ u8 *imm_data = &swqe->u.immdata_desc.immediate_data[0];
+ struct ehea_vsgentry *sg1entry = &swqe->u.immdata_desc.sg_entry;
+ u64 tmp_addr;
+
+ /* Packet is any nonTSO type
+ *
+ * Copy as much as possible skb->data to immediate data and
+ * the rest to sg1entry
+ */
+ if (skb_data_size >= SWQE2_MAX_IMM) {
+ /* copy immediate data */
+ memcpy(imm_data, skb->data, SWQE2_MAX_IMM);
+
+ swqe->immediate_data_length = SWQE2_MAX_IMM;
+
+ if (skb_data_size > SWQE2_MAX_IMM) {
+ /* copy sg1entry data */
+ sg1entry->l_key = lkey;
+ sg1entry->len = skb_data_size - SWQE2_MAX_IMM;
+ tmp_addr = (u64)(skb->data + SWQE2_MAX_IMM);
+ sg1entry->vaddr = tmp_addr;
+ swqe->descriptors++;
+ }
+ } else {
+ memcpy(imm_data, skb->data, skb_data_size);
+ swqe->immediate_data_length = skb_data_size;
+ }
+}
+
+static inline void write_swqe2_data(struct sk_buff *skb, struct net_device *dev,
+ struct ehea_swqe *swqe, u32 lkey)
+{
+ struct ehea_vsgentry *sg_list, *sg1entry, *sgentry;
+ skb_frag_t *frag;
+ int nfrags, sg1entry_contains_frag_data, i;
+ u64 tmp_addr;
+
+ nfrags = skb_shinfo(skb)->nr_frags;
+ sg1entry = &swqe->u.immdata_desc.sg_entry;
+ sg_list = (struct ehea_vsgentry*)&swqe->u.immdata_desc.sg_list;
+ swqe->descriptors = 0;
+ sg1entry_contains_frag_data = 0;
+
+ if ((dev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size)
+ write_swqe2_TSO(skb, swqe, lkey);
+ else
+ write_swqe2_nonTSO(skb, swqe, lkey);
+
+ /* write descriptors */
+ if (nfrags > 0) {
+ if (swqe->descriptors == 0) {
+ /* sg1entry not yet used */
+ frag = &skb_shinfo(skb)->frags[0];
+
+ /* copy sg1entry data */
+ sg1entry->l_key = lkey;
+ sg1entry->len = frag->size;
+ tmp_addr = (u64)(page_address(frag->page)
+ + frag->page_offset);
+ sg1entry->vaddr = tmp_addr;
+ swqe->descriptors++;
+ sg1entry_contains_frag_data = 1;
+ }
+
+ for (i = sg1entry_contains_frag_data; i < nfrags; i++) {
+
+ frag = &skb_shinfo(skb)->frags[i];
+ sgentry = &sg_list[i - sg1entry_contains_frag_data];
+
+ sgentry->l_key = lkey;
+ sgentry->len = frag->size;
+
+ tmp_addr = (u64)(page_address(frag->page)
+ + frag->page_offset);
+ sgentry->vaddr = tmp_addr;
+ swqe->descriptors++;
+ }
+ }
+}
+
+static int ehea_broadcast_reg_helper(struct ehea_port *port, u32 hcallid)
+{
+ int ret = 0;
+ u64 hret;
+ u8 reg_type;
+
+ /* De/Register untagged packets */
+ reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_UNTAGGED;
+ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+ port->logical_port_id,
+ reg_type, port->mac_addr, 0, hcallid);
+ if (hret != H_SUCCESS) {
+ ehea_error("reg_dereg_bcmc failed (tagged)");
+ ret = -EIO;
+ goto out_herr;
+ }
+
+ /* De/Register VLAN packets */
+ reg_type = EHEA_BCMC_BROADCAST | EHEA_BCMC_VLANID_ALL;
+ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+ port->logical_port_id,
+ reg_type, port->mac_addr, 0, hcallid);
+ if (hret != H_SUCCESS) {
+ ehea_error("reg_dereg_bcmc failed (vlan)");
+ ret = -EIO;
+ }
+out_herr:
+ return ret;
+}
+
+static int ehea_set_mac_addr(struct net_device *dev, void *sa)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct sockaddr *mac_addr = sa;
+ struct hcp_ehea_port_cb0 *cb0;
+ int ret;
+ u64 hret;
+
+ if (!is_valid_ether_addr(mac_addr->sa_data)) {
+ ret = -EADDRNOTAVAIL;
+ goto out;
+ }
+
+ cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb0) {
+ ehea_error("no mem for cb0");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memcpy(&(cb0->port_mac_addr), &(mac_addr->sa_data[0]), ETH_ALEN);
+
+ cb0->port_mac_addr = cb0->port_mac_addr >> 16;
+
+ hret = ehea_h_modify_ehea_port(port->adapter->handle,
+ port->logical_port_id, H_PORT_CB0,
+ EHEA_BMASK_SET(H_PORT_CB0_MAC, 1), cb0);
+ if (hret != H_SUCCESS) {
+ ret = -EIO;
+ goto out_free;
+ }
+
+ memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
+
+ /* Deregister old MAC in pHYP */
+ ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+ if (ret)
+ goto out_free;
+
+ port->mac_addr = cb0->port_mac_addr << 16;
+
+ /* Register new MAC in pHYP */
+ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+ if (ret)
+ goto out_free;
+
+ ret = 0;
+out_free:
+ kfree(cb0);
+out:
+ return ret;
+}
+
+static void ehea_promiscuous_error(u64 hret, int enable)
+{
+ ehea_info("Hypervisor denied %sabling promiscuous mode.%s",
+ enable == 1 ? "en" : "dis",
+ hret != H_AUTHORITY ? "" : " Another partition owning a "
+ "logical port on the same physical port might have altered "
+ "promiscuous mode first.");
+}
+
+static void ehea_promiscuous(struct net_device *dev, int enable)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct hcp_ehea_port_cb7 *cb7;
+ u64 hret;
+
+ if ((enable && port->promisc) || (!enable && !port->promisc))
+ return;
+
+ cb7 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb7) {
+ ehea_error("no mem for cb7");
+ goto out;
+ }
+
+ /* Modify Pxs_DUCQPN in CB7 */
+ cb7->def_uc_qpn = enable == 1 ? port->port_res[0].qp->fw_handle : 0;
+
+ hret = ehea_h_modify_ehea_port(port->adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB7, H_PORT_CB7_DUCQPN, cb7);
+ if (hret) {
+ ehea_promiscuous_error(hret, enable);
+ goto out;
+ }
+
+ port->promisc = enable;
+out:
+ kfree(cb7);
+ return;
+}
+
+static u64 ehea_multicast_reg_helper(struct ehea_port *port, u64 mc_mac_addr,
+ u32 hcallid)
+{
+ u64 hret;
+ u8 reg_type;
+
+ reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
+ | EHEA_BCMC_UNTAGGED;
+
+ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+ port->logical_port_id,
+ reg_type, mc_mac_addr, 0, hcallid);
+ if (hret)
+ goto out;
+
+ reg_type = EHEA_BCMC_SCOPE_ALL | EHEA_BCMC_MULTICAST
+ | EHEA_BCMC_VLANID_ALL;
+
+ hret = ehea_h_reg_dereg_bcmc(port->adapter->handle,
+ port->logical_port_id,
+ reg_type, mc_mac_addr, 0, hcallid);
+out:
+ return hret;
+}
+
+static int ehea_drop_multicast_list(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_mc_list *mc_entry = port->mc_list;
+ struct list_head *pos;
+ struct list_head *temp;
+ int ret = 0;
+ u64 hret;
+
+ list_for_each_safe(pos, temp, &(port->mc_list->list)) {
+ mc_entry = list_entry(pos, struct ehea_mc_list, list);
+
+ hret = ehea_multicast_reg_helper(port, mc_entry->macaddr,
+ H_DEREG_BCMC);
+ if (hret) {
+ ehea_error("failed deregistering mcast MAC");
+ ret = -EIO;
+ }
+
+ list_del(pos);
+ kfree(mc_entry);
+ }
+ return ret;
+}
+
+static void ehea_allmulti(struct net_device *dev, int enable)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ u64 hret;
+
+ if (!port->allmulti) {
+ if (enable) {
+ /* Enable ALLMULTI */
+ ehea_drop_multicast_list(dev);
+ hret = ehea_multicast_reg_helper(port, 0, H_REG_BCMC);
+ if (!hret)
+ port->allmulti = 1;
+ else
+ ehea_error("failed enabling IFF_ALLMULTI");
+ }
+ } else
+ if (!enable) {
+ /* Disable ALLMULTI */
+ hret = ehea_multicast_reg_helper(port, 0, H_DEREG_BCMC);
+ if (!hret)
+ port->allmulti = 0;
+ else
+ ehea_error("failed disabling IFF_ALLMULTI");
+ }
+}
+
+static void ehea_add_multicast_entry(struct ehea_port* port, u8* mc_mac_addr)
+{
+ struct ehea_mc_list *ehea_mcl_entry;
+ u64 hret;
+
+ ehea_mcl_entry = kzalloc(sizeof(*ehea_mcl_entry), GFP_KERNEL);
+ if (!ehea_mcl_entry) {
+ ehea_error("no mem for mcl_entry");
+ return;
+ }
+
+ INIT_LIST_HEAD(&ehea_mcl_entry->list);
+
+ memcpy(&ehea_mcl_entry->macaddr, mc_mac_addr, ETH_ALEN);
+
+ hret = ehea_multicast_reg_helper(port, ehea_mcl_entry->macaddr,
+ H_REG_BCMC);
+ if (!hret)
+ list_add(&ehea_mcl_entry->list, &port->mc_list->list);
+ else {
+ ehea_error("failed registering mcast MAC");
+ kfree(ehea_mcl_entry);
+ }
+}
+
+static void ehea_set_multicast_list(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct dev_mc_list *k_mcl_entry;
+ int ret, i;
+
+ if (dev->flags & IFF_PROMISC) {
+ ehea_promiscuous(dev, 1);
+ return;
+ }
+ ehea_promiscuous(dev, 0);
+
+ if (dev->flags & IFF_ALLMULTI) {
+ ehea_allmulti(dev, 1);
+ return;
+ }
+ ehea_allmulti(dev, 0);
+
+ if (dev->mc_count) {
+ ret = ehea_drop_multicast_list(dev);
+ if (ret) {
+ /* Dropping the current multicast list failed.
+ * Enabling ALL_MULTI is the best we can do.
+ */
+ ehea_allmulti(dev, 1);
+ }
+
+ if (dev->mc_count > port->adapter->max_mc_mac) {
+ ehea_info("Mcast registration limit reached (0x%lx). "
+ "Use ALLMULTI!",
+ port->adapter->max_mc_mac);
+ goto out;
+ }
+
+ for (i = 0, k_mcl_entry = dev->mc_list;
+ i < dev->mc_count;
+ i++, k_mcl_entry = k_mcl_entry->next) {
+ ehea_add_multicast_entry(port, k_mcl_entry->dmi_addr);
+ }
+ }
+out:
+ return;
+}
+
+static int ehea_change_mtu(struct net_device *dev, int new_mtu)
+{
+ if ((new_mtu < 68) || (new_mtu > EHEA_MAX_PACKET_SIZE))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
+}
+
+static void ehea_xmit2(struct sk_buff *skb, struct net_device *dev,
+ struct ehea_swqe *swqe, u32 lkey)
+{
+ if (skb->protocol == htons(ETH_P_IP)) {
+ /* IPv4 */
+ swqe->tx_control |= EHEA_SWQE_CRC
+ | EHEA_SWQE_IP_CHECKSUM
+ | EHEA_SWQE_TCP_CHECKSUM
+ | EHEA_SWQE_IMM_DATA_PRESENT
+ | EHEA_SWQE_DESCRIPTORS_PRESENT;
+
+ write_ip_start_end(swqe, skb);
+
+ if (skb->nh.iph->protocol == IPPROTO_UDP) {
+ if ((skb->nh.iph->frag_off & IP_MF) ||
+ (skb->nh.iph->frag_off & IP_OFFSET))
+ /* IP fragment, so don't change cs */
+ swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM;
+ else
+ write_udp_offset_end(swqe, skb);
+
+ } else if (skb->nh.iph->protocol == IPPROTO_TCP) {
+ write_tcp_offset_end(swqe, skb);
+ }
+
+ /* icmp (big data) and ip segmentation packets (all other ip
+ packets) do not require any special handling */
+
+ } else {
+ /* Other Ethernet Protocol */
+ swqe->tx_control |= EHEA_SWQE_CRC
+ | EHEA_SWQE_IMM_DATA_PRESENT
+ | EHEA_SWQE_DESCRIPTORS_PRESENT;
+ }
+
+ write_swqe2_data(skb, dev, swqe, lkey);
+}
+
+static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev,
+ struct ehea_swqe *swqe)
+{
+ int nfrags = skb_shinfo(skb)->nr_frags;
+ u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0];
+ skb_frag_t *frag;
+ int i;
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ /* IPv4 */
+ write_ip_start_end(swqe, skb);
+
+ if (skb->nh.iph->protocol == IPPROTO_TCP) {
+ swqe->tx_control |= EHEA_SWQE_CRC
+ | EHEA_SWQE_IP_CHECKSUM
+ | EHEA_SWQE_TCP_CHECKSUM
+ | EHEA_SWQE_IMM_DATA_PRESENT;
+
+ write_tcp_offset_end(swqe, skb);
+
+ } else if (skb->nh.iph->protocol == IPPROTO_UDP) {
+ if ((skb->nh.iph->frag_off & IP_MF) ||
+ (skb->nh.iph->frag_off & IP_OFFSET))
+ /* IP fragment, so don't change cs */
+ swqe->tx_control |= EHEA_SWQE_CRC
+ | EHEA_SWQE_IMM_DATA_PRESENT;
+ else {
+ swqe->tx_control |= EHEA_SWQE_CRC
+ | EHEA_SWQE_IP_CHECKSUM
+ | EHEA_SWQE_TCP_CHECKSUM
+ | EHEA_SWQE_IMM_DATA_PRESENT;
+
+ write_udp_offset_end(swqe, skb);
+ }
+ } else {
+ /* icmp (big data) and
+ ip segmentation packets (all other ip packets) */
+ swqe->tx_control |= EHEA_SWQE_CRC
+ | EHEA_SWQE_IP_CHECKSUM
+ | EHEA_SWQE_IMM_DATA_PRESENT;
+ }
+ } else {
+ /* Other Ethernet Protocol */
+ swqe->tx_control |= EHEA_SWQE_CRC | EHEA_SWQE_IMM_DATA_PRESENT;
+ }
+ /* copy (immediate) data */
+ if (nfrags == 0) {
+ /* data is in a single piece */
+ memcpy(imm_data, skb->data, skb->len);
+ } else {
+ /* first copy data from the skb->data buffer ... */
+ memcpy(imm_data, skb->data, skb->len - skb->data_len);
+ imm_data += skb->len - skb->data_len;
+
+ /* ... then copy data from the fragments */
+ for (i = 0; i < nfrags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ memcpy(imm_data,
+ page_address(frag->page) + frag->page_offset,
+ frag->size);
+ imm_data += frag->size;
+ }
+ }
+ swqe->immediate_data_length = skb->len;
+ dev_kfree_skb(skb);
+}
+
+static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_swqe *swqe;
+ unsigned long flags;
+ u32 lkey;
+ int swqe_index;
+ struct ehea_port_res *pr = &port->port_res[0];
+
+ spin_lock(&pr->xmit_lock);
+
+ swqe = ehea_get_swqe(pr->qp, &swqe_index);
+ memset(swqe, 0, SWQE_HEADER_SIZE);
+ atomic_dec(&pr->swqe_avail);
+
+ if (skb->len <= SWQE3_MAX_IMM) {
+ u32 sig_iv = port->sig_comp_iv;
+ u32 swqe_num = pr->swqe_id_counter;
+ ehea_xmit3(skb, dev, swqe);
+ swqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE3_TYPE)
+ | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, swqe_num);
+ if (pr->swqe_ll_count >= (sig_iv - 1)) {
+ swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
+ sig_iv);
+ swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
+ pr->swqe_ll_count = 0;
+ } else
+ pr->swqe_ll_count += 1;
+ } else {
+ swqe->wr_id =
+ EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE)
+ | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter)
+ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index);
+ pr->sq_skba.arr[pr->sq_skba.index] = skb;
+
+ pr->sq_skba.index++;
+ pr->sq_skba.index &= (pr->sq_skba.len - 1);
+
+ lkey = pr->send_mr.lkey;
+ ehea_xmit2(skb, dev, swqe, lkey);
+
+ if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) {
+ swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL,
+ EHEA_SIG_IV_LONG);
+ swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION;
+ pr->swqe_count = 0;
+ } else
+ pr->swqe_count += 1;
+ }
+ pr->swqe_id_counter += 1;
+
+ if (port->vgrp && vlan_tx_tag_present(skb)) {
+ swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
+ swqe->vlan_tag = vlan_tx_tag_get(skb);
+ }
+
+ if (netif_msg_tx_queued(port)) {
+ ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
+ ehea_dump(swqe, sizeof(*swqe), "swqe");
+ }
+
+ ehea_post_swqe(pr->qp, swqe);
+ pr->tx_packets++;
+
+ if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+ spin_lock_irqsave(&pr->netif_queue, flags);
+ if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) {
+ netif_stop_queue(dev);
+ pr->queue_stopped = 1;
+ }
+ spin_unlock_irqrestore(&pr->netif_queue, flags);
+ }
+ dev->trans_start = jiffies;
+ spin_unlock(&pr->xmit_lock);
+
+ return NETDEV_TX_OK;
+}
+
+static void ehea_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ struct hcp_ehea_port_cb1 *cb1;
+ u64 hret;
+
+ port->vgrp = grp;
+
+ cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb1) {
+ ehea_error("no mem for cb1");
+ goto out;
+ }
+
+ if (grp)
+ memset(cb1->vlan_filter, 0, sizeof(cb1->vlan_filter));
+ else
+ memset(cb1->vlan_filter, 0xFF, sizeof(cb1->vlan_filter));
+
+ hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+ if (hret != H_SUCCESS)
+ ehea_error("modify_ehea_port failed");
+
+ kfree(cb1);
+out:
+ return;
+}
+
+static void ehea_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ struct hcp_ehea_port_cb1 *cb1;
+ int index;
+ u64 hret;
+
+ cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb1) {
+ ehea_error("no mem for cb1");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_port failed");
+ goto out;
+ }
+
+ index = (vid / 64);
+ cb1->vlan_filter[index] |= ((u64)(1 << (vid & 0x3F)));
+
+ hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+ if (hret != H_SUCCESS)
+ ehea_error("modify_ehea_port failed");
+out:
+ kfree(cb1);
+ return;
+}
+
+static void ehea_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+ struct ehea_port *port = netdev_priv(dev);
+ struct ehea_adapter *adapter = port->adapter;
+ struct hcp_ehea_port_cb1 *cb1;
+ int index;
+ u64 hret;
+
+ if (port->vgrp)
+ port->vgrp->vlan_devices[vid] = NULL;
+
+ cb1 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb1) {
+ ehea_error("no mem for cb1");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id,
+ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_port failed");
+ goto out;
+ }
+
+ index = (vid / 64);
+ cb1->vlan_filter[index] &= ~((u64)(1 << (vid & 0x3F)));
+
+ hret = ehea_h_modify_ehea_port(adapter->handle, port->logical_port_id,
+ H_PORT_CB1, H_PORT_CB1_ALL, cb1);
+ if (hret != H_SUCCESS)
+ ehea_error("modify_ehea_port failed");
+out:
+ kfree(cb1);
+ return;
+}
+
+int ehea_activate_qp(struct ehea_adapter *adapter, struct ehea_qp *qp)
+{
+ int ret = -EIO;
+ u64 hret;
+ u16 dummy16 = 0;
+ u64 dummy64 = 0;
+ struct hcp_modify_qp_cb0* cb0;
+
+ cb0 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb0) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (1)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = H_QP_CR_STATE_INITIALIZED;
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+ &dummy64, &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (1)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (2)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_INITIALIZED;
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+ &dummy64, &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (2)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (3)");
+ goto out;
+ }
+
+ cb0->qp_ctl_reg = H_QP_CR_ENABLED | H_QP_CR_STATE_RDY2SND;
+ hret = ehea_h_modify_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_QP_CTL_REG, 1), cb0,
+ &dummy64, &dummy64, &dummy16, &dummy16);
+ if (hret != H_SUCCESS) {
+ ehea_error("modify_ehea_qp failed (3)");
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea_qp(adapter->handle, 0, qp->fw_handle,
+ EHEA_BMASK_SET(H_QPCB0_ALL, 0xFFFF), cb0);
+ if (hret != H_SUCCESS) {
+ ehea_error("query_ehea_qp failed (4)");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ kfree(cb0);
+ return ret;
+}
+
+static int ehea_port_res_setup(struct ehea_port *port, int def_qps,
+ int add_tx_qps)
+{
+ int ret, i;
+ struct port_res_cfg pr_cfg, pr_cfg_small_rx;
+ enum ehea_eq_type eq_type = EHEA_EQ;
+
+ port->qp_eq = ehea_create_eq(port->adapter, eq_type,
+ EHEA_MAX_ENTRIES_EQ, 1);
+ if (!port->qp_eq) {
+ ret = -EINVAL;
+ ehea_error("ehea_create_eq failed (qp_eq)");
+ goto out_kill_eq;
+ }
+
+ pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries;
+ pr_cfg.max_entries_scq = sq_entries;
+ pr_cfg.max_entries_sq = sq_entries;
+ pr_cfg.max_entries_rq1 = rq1_entries;
+ pr_cfg.max_entries_rq2 = rq2_entries;
+ pr_cfg.max_entries_rq3 = rq3_entries;
+
+ pr_cfg_small_rx.max_entries_rcq = 1;
+ pr_cfg_small_rx.max_entries_scq = sq_entries;
+ pr_cfg_small_rx.max_entries_sq = sq_entries;
+ pr_cfg_small_rx.max_entries_rq1 = 1;
+ pr_cfg_small_rx.max_entries_rq2 = 1;
+ pr_cfg_small_rx.max_entries_rq3 = 1;
+
+ for (i = 0; i < def_qps; i++) {
+ ret = ehea_init_port_res(port, &port->port_res[i], &pr_cfg, i);
+ if (ret)
+ goto out_clean_pr;
+ }
+ for (i = def_qps; i < def_qps + add_tx_qps; i++) {
+ ret = ehea_init_port_res(port, &port->port_res[i],
+ &pr_cfg_small_rx, i);
+ if (ret)
+ goto out_clean_pr;
+ }
+
+ return 0;
+
+out_clean_pr:
+ while (--i >= 0)
+ ehea_clean_portres(port, &port->port_res[i]);
+
+out_kill_eq:
+ ehea_destroy_eq(port->qp_eq);
+ return ret;
+}
+
+static int ehea_clean_all_portres(struct ehea_port *port)
+{
+ int ret = 0;
+ int i;
+
+ for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ ret |= ehea_clean_portres(port, &port->port_res[i]);
+
+ ret |= ehea_destroy_eq(port->qp_eq);
+
+ return ret;
+}
+
+static int ehea_up(struct net_device *dev)
+{
+ int ret, i;
+ struct ehea_port *port = netdev_priv(dev);
+ u64 mac_addr = 0;
+
+ if (port->state == EHEA_PORT_UP)
+ return 0;
+
+ ret = ehea_port_res_setup(port, port->num_def_qps,
+ port->num_add_tx_qps);
+ if (ret) {
+ ehea_error("port_res_failed");
+ goto out;
+ }
+
+ /* Set default QP for this port */
+ ret = ehea_configure_port(port);
+ if (ret) {
+ ehea_error("ehea_configure_port failed. ret:%d", ret);
+ goto out_clean_pr;
+ }
+
+ ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
+ if (ret) {
+ ret = -EIO;
+ ehea_error("out_clean_pr");
+ goto out_clean_pr;
+ }
+ mac_addr = (*(u64*)dev->dev_addr) >> 16;
+
+ ret = ehea_reg_interrupts(dev);
+ if (ret) {
+ ehea_error("out_dereg_bc");
+ goto out_dereg_bc;
+ }
+
+ for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
+ ret = ehea_activate_qp(port->adapter, port->port_res[i].qp);
+ if (ret) {
+ ehea_error("activate_qp failed");
+ goto out_free_irqs;
+ }
+ }
+
+ for(i = 0; i < port->num_def_qps; i++) {
+ ret = ehea_fill_port_res(&port->port_res[i]);
+ if (ret) {
+ ehea_error("out_free_irqs");
+ goto out_free_irqs;
+ }
+ }
+
+ ret = 0;
+ port->state = EHEA_PORT_UP;
+ goto out;
+
+out_free_irqs:
+ ehea_free_interrupts(dev);
+
+out_dereg_bc:
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+
+out_clean_pr:
+ ehea_clean_all_portres(port);
+out:
+ return ret;
+}
+
+static int ehea_open(struct net_device *dev)
+{
+ int ret;
+ struct ehea_port *port = netdev_priv(dev);
+
+ down(&port->port_lock);
+
+ if (netif_msg_ifup(port))
+ ehea_info("enabling port %s", dev->name);
+
+ ret = ehea_up(dev);
+ if (!ret)
+ netif_start_queue(dev);
+
+ up(&port->port_lock);
+
+ return ret;
+}
+
+static int ehea_down(struct net_device *dev)
+{
+ int ret, i;
+ struct ehea_port *port = netdev_priv(dev);
+
+ if (port->state == EHEA_PORT_DOWN)
+ return 0;
+
+ ehea_drop_multicast_list(dev);
+ ehea_free_interrupts(dev);
+
+ for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++)
+ tasklet_kill(&port->port_res[i].send_comp_task);
+
+ ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
+ ret = ehea_clean_all_portres(port);
+ port->state = EHEA_PORT_DOWN;
+ return ret;
+}
+
+static int ehea_stop(struct net_device *dev)
+{
+ int ret;
+ struct ehea_port *port = netdev_priv(dev);
+
+ if (netif_msg_ifdown(port))
+ ehea_info("disabling port %s", dev->name);
+
+ flush_workqueue(port->adapter->ehea_wq);
+ down(&port->port_lock);
+ netif_stop_queue(dev);
+ ret = ehea_down(dev);
+ up(&port->port_lock);
+ return ret;
+}
+
+static void ehea_reset_port(void *data)
+{
+ int ret;
+ struct net_device *dev = data;
+ struct ehea_port *port = netdev_priv(dev);
+
+ port->resets++;
+ down(&port->port_lock);
+ netif_stop_queue(dev);
+ netif_poll_disable(dev);
+
+ ret = ehea_down(dev);
+ if (ret)
+ ehea_error("ehea_down failed. not all resources are freed");
+
+ ret = ehea_up(dev);
+ if (ret) {
+ ehea_error("Reset device %s failed: ret=%d", dev->name, ret);
+ goto out;
+ }
+
+ if (netif_msg_timer(port))
+ ehea_info("Device %s resetted successfully", dev->name);
+
+ netif_poll_enable(dev);
+ netif_wake_queue(dev);
+out:
+ up(&port->port_lock);
+ return;
+}
+
+static void ehea_tx_watchdog(struct net_device *dev)
+{
+ struct ehea_port *port = netdev_priv(dev);
+
+ if (netif_carrier_ok(dev))
+ queue_work(port->adapter->ehea_wq, &port->reset_task);
+}
+
+int ehea_sense_adapter_attr(struct ehea_adapter *adapter)
+{
+ struct hcp_query_ehea *cb;
+ u64 hret;
+ int ret;
+
+ cb = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ hret = ehea_h_query_ehea(adapter->handle, cb);
+
+ if (hret != H_SUCCESS) {
+ ret = -EIO;
+ goto out_herr;
+ }
+
+ adapter->num_ports = cb->num_ports;
+ adapter->max_mc_mac = cb->max_mc_mac - 1;
+ ret = 0;
+
+out_herr:
+ kfree(cb);
+out:
+ return ret;
+}
+
+static int ehea_setup_single_port(struct ehea_port *port,
+ struct device_node *dn)
+{
+ int ret;
+ u64 hret;
+ struct net_device *dev = port->netdev;
+ struct ehea_adapter *adapter = port->adapter;
+ struct hcp_ehea_port_cb4 *cb4;
+ u32 *dn_log_port_id;
+
+ sema_init(&port->port_lock, 1);
+ port->state = EHEA_PORT_DOWN;
+ port->sig_comp_iv = sq_entries / 10;
+
+ if (!dn) {
+ ehea_error("bad device node: dn=%p", dn);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ port->of_dev_node = dn;
+
+ /* Determine logical port id */
+ dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL);
+
+ if (!dn_log_port_id) {
+ ehea_error("bad device node: dn_log_port_id=%p",
+ dn_log_port_id);
+ ret = -EINVAL;
+ goto out;
+ }
+ port->logical_port_id = *dn_log_port_id;
+
+ port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL);
+ if (!port->mc_list) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&port->mc_list->list);
+
+ ehea_set_portspeed(port, EHEA_SPEED_AUTONEG);
+
+ ret = ehea_sense_port_attr(port);
+ if (ret)
+ goto out;
+
+ /* Enable Jumbo frames */
+ cb4 = kzalloc(H_CB_ALIGNMENT, GFP_KERNEL);
+ if (!cb4) {
+ ehea_error("no mem for cb4");
+ } else {
+ cb4->jumbo_frame = 1;
+ hret = ehea_h_modify_ehea_port(adapter->handle,
+ port->logical_port_id,
+ H_PORT_CB4, H_PORT_CB4_JUMBO,
+ cb4);
+ if (hret != H_SUCCESS) {
+ ehea_info("Jumbo frames not activated");
+ }
+ kfree(cb4);
+ }
+
+ /* initialize net_device structure */
+ SET_MODULE_OWNER(dev);
+
+ memcpy(dev->dev_addr, &port->mac_addr, ETH_ALEN);
+
+ dev->open = ehea_open;
+ dev->poll = ehea_poll;
+ dev->weight = 64;
+ dev->stop = ehea_stop;
+ dev->hard_start_xmit = ehea_start_xmit;
+ dev->get_stats = ehea_get_stats;
+ dev->set_multicast_list = ehea_set_multicast_list;
+ dev->set_mac_address = ehea_set_mac_addr;
+ dev->change_mtu = ehea_change_mtu;
+ dev->vlan_rx_register = ehea_vlan_rx_register;
+ dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid;
+ dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid;
+ dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO
+ | NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_TX
+ | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER
+ | NETIF_F_LLTX;
+ dev->tx_timeout = &ehea_tx_watchdog;
+ dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
+
+ INIT_WORK(&port->reset_task, ehea_reset_port, dev);
+
+ ehea_set_ethtool_ops(dev);
+
+ ret = register_netdev(dev);
+ if (ret) {
+ ehea_error("register_netdev failed. ret=%d", ret);
+ goto out_free;
+ }
+
+ port->netdev = dev;
+ ret = 0;
+ goto out;
+
+out_free:
+ kfree(port->mc_list);
+out:
+ return ret;
+}
+
+static int ehea_setup_ports(struct ehea_adapter *adapter)
+{
+ int ret;
+ int port_setup_ok = 0;
+ struct ehea_port *port;
+ struct device_node *dn = NULL;
+ struct net_device *dev;
+ int i;
+
+ /* get port properties for all ports */
+ for (i = 0; i < adapter->num_ports; i++) {
+
+ if (adapter->port[i])
+ continue; /* port already up and running */
+
+ /* allocate memory for the port structures */
+ dev = alloc_etherdev(sizeof(struct ehea_port));
+
+ if (!dev) {
+ ehea_error("no mem for net_device");
+ break;
+ }
+
+ port = netdev_priv(dev);
+ port->adapter = adapter;
+ port->netdev = dev;
+ adapter->port[i] = port;
+ port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT);
+
+ dn = of_find_node_by_name(dn, "ethernet");
+ ret = ehea_setup_single_port(port, dn);
+ if (ret) {
+ /* Free mem for this port struct. The others will be
+ processed on rollback */
+ free_netdev(dev);
+ adapter->port[i] = NULL;
+ ehea_error("eHEA port %d setup failed, ret=%d", i, ret);
+ }
+ }
+
+ of_node_put(dn);
+
+ /* Check for succesfully set up ports */
+ for (i = 0; i < adapter->num_ports; i++)
+ if (adapter->port[i])
+ port_setup_ok++;
+
+ if (port_setup_ok)
+ ret = 0; /* At least some ports are setup correctly */
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int __devinit ehea_probe(struct ibmebus_dev *dev,
+ const struct of_device_id *id)
+{
+ struct ehea_adapter *adapter;
+ u64 *adapter_handle;
+ int ret;
+
+ adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+ if (!adapter) {
+ ret = -ENOMEM;
+ dev_err(&dev->ofdev.dev, "no mem for ehea_adapter\n");
+ goto out;
+ }
+
+ adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle",
+ NULL);
+ if (!adapter_handle) {
+ dev_err(&dev->ofdev.dev, "failed getting handle for adapter"
+ " '%s'\n", dev->ofdev.node->full_name);
+ ret = -ENODEV;
+ goto out_free_ad;
+ }
+
+ adapter->handle = *adapter_handle;
+ adapter->pd = EHEA_PD_ID;
+
+ dev->ofdev.dev.driver_data = adapter;
+
+ ret = ehea_reg_mr_adapter(adapter);
+ if (ret) {
+ dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n");
+ goto out_free_ad;
+ }
+
+ /* initialize adapter and ports */
+ /* get adapter properties */
+ ret = ehea_sense_adapter_attr(adapter);
+ if (ret) {
+ dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret);
+ goto out_free_res;
+ }
+ dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports);
+
+ adapter->neq = ehea_create_eq(adapter,
+ EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1);
+ if (!adapter->neq) {
+ dev_err(&dev->ofdev.dev, "NEQ creation failed");
+ goto out_free_res;
+ }
+
+ tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet,
+ (unsigned long)adapter);
+
+ ret = ibmebus_request_irq(NULL, adapter->neq->attr.ist1,
+ ehea_interrupt_neq, SA_INTERRUPT,
+ "ehea_neq", adapter);
+ if (ret) {
+ dev_err(&dev->ofdev.dev, "requesting NEQ IRQ failed");
+ goto out_kill_eq;
+ }
+
+ adapter->ehea_wq = create_workqueue("ehea_wq");
+ if (!adapter->ehea_wq)
+ goto out_free_irq;
+
+ ret = ehea_setup_ports(adapter);
+ if (ret) {
+ dev_err(&dev->ofdev.dev, "setup_ports failed");
+ goto out_kill_wq;
+ }
+
+ ret = 0;
+ goto out;
+
+out_kill_wq:
+ destroy_workqueue(adapter->ehea_wq);
+
+out_free_irq:
+ ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+
+out_kill_eq:
+ ehea_destroy_eq(adapter->neq);
+
+out_free_res:
+ ehea_h_free_resource(adapter->handle, adapter->mr.handle);
+
+out_free_ad:
+ kfree(adapter);
+out:
+ return ret;
+}
+
+static void ehea_shutdown_single_port(struct ehea_port *port)
+{
+ unregister_netdev(port->netdev);
+ kfree(port->mc_list);
+ free_netdev(port->netdev);
+}
+
+static int __devexit ehea_remove(struct ibmebus_dev *dev)
+{
+ struct ehea_adapter *adapter = dev->ofdev.dev.driver_data;
+ u64 hret;
+ int i;
+
+ for (i = 0; i < adapter->num_ports; i++)
+ if (adapter->port[i]) {
+ ehea_shutdown_single_port(adapter->port[i]);
+ adapter->port[i] = NULL;
+ }
+ destroy_workqueue(adapter->ehea_wq);
+
+ ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter);
+
+ ehea_destroy_eq(adapter->neq);
+
+ hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle);
+ if (hret) {
+ dev_err(&dev->ofdev.dev, "free_resource_mr failed");
+ return -EIO;
+ }
+ kfree(adapter);
+ return 0;
+}
+
+static int check_module_parm(void)
+{
+ int ret = 0;
+
+ if ((rq1_entries < EHEA_MIN_ENTRIES_QP) ||
+ (rq1_entries > EHEA_MAX_ENTRIES_RQ1)) {
+ ehea_info("Bad parameter: rq1_entries");
+ ret = -EINVAL;
+ }
+ if ((rq2_entries < EHEA_MIN_ENTRIES_QP) ||
+ (rq2_entries > EHEA_MAX_ENTRIES_RQ2)) {
+ ehea_info("Bad parameter: rq2_entries");
+ ret = -EINVAL;
+ }
+ if ((rq3_entries < EHEA_MIN_ENTRIES_QP) ||
+ (rq3_entries > EHEA_MAX_ENTRIES_RQ3)) {
+ ehea_info("Bad parameter: rq3_entries");
+ ret = -EINVAL;
+ }
+ if ((sq_entries < EHEA_MIN_ENTRIES_QP) ||
+ (sq_entries > EHEA_MAX_ENTRIES_SQ)) {
+ ehea_info("Bad parameter: sq_entries");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static struct of_device_id ehea_device_table[] = {
+ {
+ .name = "lhea",
+ .compatible = "IBM,lhea",
+ },
+ {},
+};
+
+static struct ibmebus_driver ehea_driver = {
+ .name = "ehea",
+ .id_table = ehea_device_table,
+ .probe = ehea_probe,
+ .remove = ehea_remove,
+};
+
+int __init ehea_module_init(void)
+{
+ int ret;
+
+ printk(KERN_INFO "IBM eHEA ethernet device driver (Release %s)\n",
+ DRV_VERSION);
+
+ ret = check_module_parm();
+ if (ret)
+ goto out;
+ ret = ibmebus_register_driver(&ehea_driver);
+ if (ret)
+ ehea_error("failed registering eHEA device driver on ebus");
+
+out:
+ return ret;
+}
+
+static void __exit ehea_module_exit(void)
+{
+ ibmebus_unregister_driver(&ehea_driver);
+}
+
+module_init(ehea_module_init);
+module_exit(ehea_module_exit);
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
new file mode 100644
index 00000000000..4a85aca4c7e
--- /dev/null
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -0,0 +1,705 @@
+/*
+ * linux/drivers/net/ehea/ehea_phyp.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 "ehea_phyp.h"
+
+
+static inline u16 get_order_of_qentries(u16 queue_entries)
+{
+ u8 ld = 1; /* logarithmus dualis */
+ while (((1U << ld) - 1) < queue_entries)
+ ld++;
+ return ld - 1;
+}
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
+
+static long ehea_hcall_9arg_9ret(unsigned long opcode,
+ unsigned long arg1, unsigned long arg2,
+ unsigned long arg3, unsigned long arg4,
+ unsigned long arg5, unsigned long arg6,
+ unsigned long arg7, unsigned long arg8,
+ unsigned long arg9, unsigned long *out1,
+ unsigned long *out2,unsigned long *out3,
+ unsigned long *out4,unsigned long *out5,
+ unsigned long *out6,unsigned long *out7,
+ unsigned long *out8,unsigned long *out9)
+{
+ long hret;
+ int i, sleep_msecs;
+
+ for (i = 0; i < 5; i++) {
+ hret = plpar_hcall_9arg_9ret(opcode,arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7, arg8, arg9, out1,
+ out2, out3, out4, out5, out6, out7,
+ out8, out9);
+ if (H_IS_LONG_BUSY(hret)) {
+ sleep_msecs = get_longbusy_msecs(hret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (hret < H_SUCCESS)
+ ehea_error("op=%lx hret=%lx "
+ "i1=%lx i2=%lx i3=%lx i4=%lx i5=%lx i6=%lx "
+ "i7=%lx i8=%lx i9=%lx "
+ "o1=%lx o2=%lx o3=%lx o4=%lx o5=%lx o6=%lx "
+ "o7=%lx o8=%lx o9=%lx",
+ opcode, hret, arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9, *out1, *out2, *out3,
+ *out4, *out5, *out6, *out7, *out8, *out9);
+ return hret;
+ }
+ return H_BUSY;
+}
+
+u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask, void *cb_addr)
+{
+ u64 dummy;
+
+ if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) {
+ ehea_error("not on pageboundary");
+ return H_PARAMETER;
+ }
+
+ return ehea_hcall_9arg_9ret(H_QUERY_HEA_QP,
+ adapter_handle, /* R4 */
+ qp_category, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
+
+/* input param R5 */
+#define H_ALL_RES_QP_EQPO EHEA_BMASK_IBM(9, 11)
+#define H_ALL_RES_QP_QPP EHEA_BMASK_IBM(12, 12)
+#define H_ALL_RES_QP_RQR EHEA_BMASK_IBM(13, 15)
+#define H_ALL_RES_QP_EQEG EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_QP_LL_QP EHEA_BMASK_IBM(17, 17)
+#define H_ALL_RES_QP_DMA128 EHEA_BMASK_IBM(19, 19)
+#define H_ALL_RES_QP_HSM EHEA_BMASK_IBM(20, 21)
+#define H_ALL_RES_QP_SIGT EHEA_BMASK_IBM(22, 23)
+#define H_ALL_RES_QP_TENURE EHEA_BMASK_IBM(48, 55)
+#define H_ALL_RES_QP_RES_TYP EHEA_BMASK_IBM(56, 63)
+
+/* input param R9 */
+#define H_ALL_RES_QP_TOKEN EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_PD EHEA_BMASK_IBM(32,63)
+
+/* input param R10 */
+#define H_ALL_RES_QP_MAX_SWQE EHEA_BMASK_IBM(4, 7)
+#define H_ALL_RES_QP_MAX_R1WQE EHEA_BMASK_IBM(12, 15)
+#define H_ALL_RES_QP_MAX_R2WQE EHEA_BMASK_IBM(20, 23)
+#define H_ALL_RES_QP_MAX_R3WQE EHEA_BMASK_IBM(28, 31)
+/* Max Send Scatter Gather Elements */
+#define H_ALL_RES_QP_MAX_SSGE EHEA_BMASK_IBM(37, 39)
+#define H_ALL_RES_QP_MAX_R1SGE EHEA_BMASK_IBM(45, 47)
+/* Max Receive SG Elements RQ1 */
+#define H_ALL_RES_QP_MAX_R2SGE EHEA_BMASK_IBM(53, 55)
+#define H_ALL_RES_QP_MAX_R3SGE EHEA_BMASK_IBM(61, 63)
+
+/* input param R11 */
+#define H_ALL_RES_QP_SWQE_IDL EHEA_BMASK_IBM(0, 7)
+/* max swqe immediate data length */
+#define H_ALL_RES_QP_PORT_NUM EHEA_BMASK_IBM(48, 63)
+
+/* input param R12 */
+#define H_ALL_RES_QP_TH_RQ2 EHEA_BMASK_IBM(0, 15)
+/* Threshold RQ2 */
+#define H_ALL_RES_QP_TH_RQ3 EHEA_BMASK_IBM(16, 31)
+/* Threshold RQ3 */
+
+/* output param R6 */
+#define H_ALL_RES_QP_ACT_SWQE EHEA_BMASK_IBM(0, 15)
+#define H_ALL_RES_QP_ACT_R1WQE EHEA_BMASK_IBM(16, 31)
+#define H_ALL_RES_QP_ACT_R2WQE EHEA_BMASK_IBM(32, 47)
+#define H_ALL_RES_QP_ACT_R3WQE EHEA_BMASK_IBM(48, 63)
+
+/* output param, R7 */
+#define H_ALL_RES_QP_ACT_SSGE EHEA_BMASK_IBM(0, 7)
+#define H_ALL_RES_QP_ACT_R1SGE EHEA_BMASK_IBM(8, 15)
+#define H_ALL_RES_QP_ACT_R2SGE EHEA_BMASK_IBM(16, 23)
+#define H_ALL_RES_QP_ACT_R3SGE EHEA_BMASK_IBM(24, 31)
+#define H_ALL_RES_QP_ACT_SWQE_IDL EHEA_BMASK_IBM(32, 39)
+
+/* output param R8,R9 */
+#define H_ALL_RES_QP_SIZE_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_SIZE_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_SIZE_RQ3 EHEA_BMASK_IBM(32, 63)
+
+/* output param R11,R12 */
+#define H_ALL_RES_QP_LIOBN_SQ EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ1 EHEA_BMASK_IBM(32, 63)
+#define H_ALL_RES_QP_LIOBN_RQ2 EHEA_BMASK_IBM(0, 31)
+#define H_ALL_RES_QP_LIOBN_RQ3 EHEA_BMASK_IBM(32, 63)
+
+u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
+ struct ehea_qp_init_attr *init_attr, const u32 pd,
+ u64 *qp_handle, struct h_epas *h_epas)
+{
+ u64 hret;
+
+ u64 allocate_controls =
+ EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_QPP, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_RQR, 6) /* rq1 & rq2 & rq3 */
+ | EHEA_BMASK_SET(H_ALL_RES_QP_EQEG, 0) /* EQE gen. disabled */
+ | EHEA_BMASK_SET(H_ALL_RES_QP_LL_QP, init_attr->low_lat_rq1)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_DMA128, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_HSM, 0)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_SIGT, init_attr->signalingtype)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_RES_TYP, H_ALL_RES_TYPE_QP);
+
+ u64 r9_reg = EHEA_BMASK_SET(H_ALL_RES_QP_PD, pd)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_TOKEN, init_attr->qp_token);
+
+ u64 max_r10_reg =
+ EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SWQE,
+ get_order_of_qentries(init_attr->max_nr_send_wqes))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq1))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq2))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3WQE,
+ get_order_of_qentries(init_attr->max_nr_rwqes_rq3))
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_SSGE, init_attr->wqe_size_enc_sq)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R1SGE,
+ init_attr->wqe_size_enc_rq1)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R2SGE,
+ init_attr->wqe_size_enc_rq2)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_MAX_R3SGE,
+ init_attr->wqe_size_enc_rq3);
+
+ u64 r11_in =
+ EHEA_BMASK_SET(H_ALL_RES_QP_SWQE_IDL, init_attr->swqe_imm_data_len)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_PORT_NUM, init_attr->port_nr);
+ u64 threshold =
+ EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
+ | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
+
+ u64 r5_out = 0;
+ u64 r6_out = 0;
+ u64 r7_out = 0;
+ u64 r8_out = 0;
+ u64 r9_out = 0;
+ u64 g_la_user_out = 0;
+ u64 r11_out = 0;
+ u64 r12_out = 0;
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+ adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ init_attr->send_cq_handle, /* R6 */
+ init_attr->recv_cq_handle, /* R7 */
+ init_attr->aff_eq_handle, /* R8 */
+ r9_reg, /* R9 */
+ max_r10_reg, /* R10 */
+ r11_in, /* R11 */
+ threshold, /* R12 */
+ qp_handle, /* R4 */
+ &r5_out, /* R5 */
+ &r6_out, /* R6 */
+ &r7_out, /* R7 */
+ &r8_out, /* R8 */
+ &r9_out, /* R9 */
+ &g_la_user_out, /* R10 */
+ &r11_out, /* R11 */
+ &r12_out); /* R12 */
+
+ init_attr->qp_nr = (u32)r5_out;
+
+ init_attr->act_nr_send_wqes =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out);
+ init_attr->act_nr_rwqes_rq1 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out);
+ init_attr->act_nr_rwqes_rq2 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out);
+ init_attr->act_nr_rwqes_rq3 =
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out);
+
+ init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
+ init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
+ init_attr->act_wqe_size_enc_rq2 = init_attr->wqe_size_enc_rq2;
+ init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
+
+ init_attr->nr_sq_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out);
+ init_attr->nr_rq1_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out);
+ init_attr->nr_rq2_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out);
+ init_attr->nr_rq3_pages =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out);
+
+ init_attr->liobn_sq =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out);
+ init_attr->liobn_rq1 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out);
+ init_attr->liobn_rq2 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out);
+ init_attr->liobn_rq3 =
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out);
+
+ if (!hret)
+ hcp_epas_ctor(h_epas, g_la_user_out, g_la_user_out);
+
+ return hret;
+}
+
+u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
+ struct ehea_cq_attr *cq_attr,
+ u64 *cq_handle, struct h_epas *epas)
+{
+ u64 hret, dummy, act_nr_of_cqes_out, act_pages_out;
+ u64 g_la_privileged_out, g_la_user_out;
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+ adapter_handle, /* R4 */
+ H_ALL_RES_TYPE_CQ, /* R5 */
+ cq_attr->eq_handle, /* R6 */
+ cq_attr->cq_token, /* R7 */
+ cq_attr->max_nr_of_cqes, /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ cq_handle, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &act_nr_of_cqes_out, /* R7 */
+ &act_pages_out, /* R8 */
+ &g_la_privileged_out, /* R9 */
+ &g_la_user_out, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+
+ cq_attr->act_nr_of_cqes = act_nr_of_cqes_out;
+ cq_attr->nr_pages = act_pages_out;
+
+ if (!hret)
+ hcp_epas_ctor(epas, g_la_privileged_out, g_la_user_out);
+
+ return hret;
+}
+
+/* Defines for H_CALL H_ALLOC_RESOURCE */
+#define H_ALL_RES_TYPE_QP 1
+#define H_ALL_RES_TYPE_CQ 2
+#define H_ALL_RES_TYPE_EQ 3
+#define H_ALL_RES_TYPE_MR 5
+#define H_ALL_RES_TYPE_MW 6
+
+/* input param R5 */
+#define H_ALL_RES_EQ_NEQ EHEA_BMASK_IBM(0, 0)
+#define H_ALL_RES_EQ_NON_NEQ_ISN EHEA_BMASK_IBM(6, 7)
+#define H_ALL_RES_EQ_INH_EQE_GEN EHEA_BMASK_IBM(16, 16)
+#define H_ALL_RES_EQ_RES_TYPE EHEA_BMASK_IBM(56, 63)
+/* input param R6 */
+#define H_ALL_RES_EQ_MAX_EQE EHEA_BMASK_IBM(32, 63)
+
+/* output param R6 */
+#define H_ALL_RES_EQ_LIOBN EHEA_BMASK_IBM(32, 63)
+
+/* output param R7 */
+#define H_ALL_RES_EQ_ACT_EQE EHEA_BMASK_IBM(32, 63)
+
+/* output param R8 */
+#define H_ALL_RES_EQ_ACT_PS EHEA_BMASK_IBM(32, 63)
+
+/* output param R9 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_C EHEA_BMASK_IBM(30, 31)
+#define H_ALL_RES_EQ_ACT_EQ_IST_1 EHEA_BMASK_IBM(40, 63)
+
+/* output param R10 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_2 EHEA_BMASK_IBM(40, 63)
+
+/* output param R11 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_3 EHEA_BMASK_IBM(40, 63)
+
+/* output param R12 */
+#define H_ALL_RES_EQ_ACT_EQ_IST_4 EHEA_BMASK_IBM(40, 63)
+
+u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
+ struct ehea_eq_attr *eq_attr, u64 *eq_handle)
+{
+ u64 hret, dummy, eq_liobn, allocate_controls;
+ u64 ist1_out, ist2_out, ist3_out, ist4_out;
+ u64 act_nr_of_eqes_out, act_pages_out;
+
+ /* resource type */
+ allocate_controls =
+ EHEA_BMASK_SET(H_ALL_RES_EQ_RES_TYPE, H_ALL_RES_TYPE_EQ)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_NEQ, eq_attr->type ? 1 : 0)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
+ | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+ adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ eq_attr->max_nr_of_eqes, /* R6 */
+ 0, 0, 0, 0, 0, 0, /* R7-R10 */
+ eq_handle, /* R4 */
+ &dummy, /* R5 */
+ &eq_liobn, /* R6 */
+ &act_nr_of_eqes_out, /* R7 */
+ &act_pages_out, /* R8 */
+ &ist1_out, /* R9 */
+ &ist2_out, /* R10 */
+ &ist3_out, /* R11 */
+ &ist4_out); /* R12 */
+
+ eq_attr->act_nr_of_eqes = act_nr_of_eqes_out;
+ eq_attr->nr_pages = act_pages_out;
+ eq_attr->ist1 = ist1_out;
+ eq_attr->ist2 = ist2_out;
+ eq_attr->ist3 = ist3_out;
+ eq_attr->ist4 = ist4_out;
+
+ return hret;
+}
+
+u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat,
+ const u64 qp_handle, const u64 sel_mask,
+ void *cb_addr, u64 *inv_attr_id, u64 *proc_mask,
+ u16 *out_swr, u16 *out_rwr)
+{
+ u64 hret, dummy, act_out_swr, act_out_rwr;
+
+ if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) {
+ ehea_error("not on page boundary");
+ return H_PARAMETER;
+ }
+
+ hret = ehea_hcall_9arg_9ret(H_MODIFY_HEA_QP,
+ adapter_handle, /* R4 */
+ (u64) cat, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ inv_attr_id, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &act_out_swr, /* R7 */
+ &act_out_rwr, /* R8 */
+ proc_mask, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+ *out_swr = act_out_swr;
+ *out_rwr = act_out_rwr;
+
+ return hret;
+}
+
+u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize,
+ const u8 queue_type, const u64 resource_handle,
+ const u64 log_pageaddr, u64 count)
+{
+ u64 dummy, reg_control;
+
+ reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
+ | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
+
+ return ehea_hcall_9arg_9ret(H_REGISTER_HEA_RPAGES,
+ adapter_handle, /* R4 */
+ reg_control, /* R5 */
+ resource_handle, /* R6 */
+ log_pageaddr, /* R7 */
+ count, /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
+
+u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
+ const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
+ struct ehea_mr *mr)
+{
+ u64 hret, dummy, lkey_out;
+
+ hret = ehea_hcall_9arg_9ret(H_REGISTER_SMR,
+ adapter_handle , /* R4 */
+ orig_mr_handle, /* R5 */
+ vaddr_in, /* R6 */
+ (((u64)access_ctrl) << 32ULL), /* R7 */
+ pd, /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ &mr->handle, /* R4 */
+ &dummy, /* R5 */
+ &lkey_out, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+ mr->lkey = (u32)lkey_out;
+
+ return hret;
+}
+
+u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
+{
+ u64 hret, dummy, ladr_next_sq_wqe_out;
+ u64 ladr_next_rq1_wqe_out, ladr_next_rq2_wqe_out, ladr_next_rq3_wqe_out;
+
+ hret = ehea_hcall_9arg_9ret(H_DISABLE_AND_GET_HEA,
+ adapter_handle, /* R4 */
+ H_DISABLE_GET_EHEA_WQE_P, /* R5 */
+ qp_handle, /* R6 */
+ 0, 0, 0, 0, 0, 0, /* R7-R12 */
+ &ladr_next_sq_wqe_out, /* R4 */
+ &ladr_next_rq1_wqe_out, /* R5 */
+ &ladr_next_rq2_wqe_out, /* R6 */
+ &ladr_next_rq3_wqe_out, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+ return hret;
+}
+
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
+{
+ u64 dummy;
+
+ return ehea_hcall_9arg_9ret(H_FREE_RESOURCE,
+ adapter_handle, /* R4 */
+ res_handle, /* R5 */
+ 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
+
+u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
+ const u64 length, const u32 access_ctrl,
+ const u32 pd, u64 *mr_handle, u32 *lkey)
+{
+ u64 hret, dummy, lkey_out;
+
+ hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
+ adapter_handle, /* R4 */
+ 5, /* R5 */
+ vaddr, /* R6 */
+ length, /* R7 */
+ (((u64) access_ctrl) << 32ULL),/* R8 */
+ pd, /* R9 */
+ 0, 0, 0, /* R10-R12 */
+ mr_handle, /* R4 */
+ &dummy, /* R5 */
+ &lkey_out, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+ *lkey = (u32) lkey_out;
+
+ return hret;
+}
+
+u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
+ const u8 pagesize, const u8 queue_type,
+ const u64 log_pageaddr, const u64 count)
+{
+ if ((count > 1) && (log_pageaddr & 0xfff)) {
+ ehea_error("not on pageboundary");
+ return H_PARAMETER;
+ }
+
+ return ehea_h_register_rpage(adapter_handle, pagesize,
+ queue_type, mr_handle,
+ log_pageaddr, count);
+}
+
+u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr)
+{
+ u64 hret, dummy, cb_logaddr;
+
+ cb_logaddr = virt_to_abs(cb_addr);
+
+ hret = ehea_hcall_9arg_9ret(H_QUERY_HEA,
+ adapter_handle, /* R4 */
+ cb_logaddr, /* R5 */
+ 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+#ifdef DEBUG
+ ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
+#endif
+ return hret;
+}
+
+u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
+ const u8 cb_cat, const u64 select_mask,
+ void *cb_addr)
+{
+ u64 port_info, dummy;
+ u64 cb_logaddr = virt_to_abs(cb_addr);
+ u64 arr_index = 0;
+
+ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+
+ return ehea_hcall_9arg_9ret(H_QUERY_HEA_PORT,
+ adapter_handle, /* R4 */
+ port_info, /* R5 */
+ select_mask, /* R6 */
+ arr_index, /* R7 */
+ cb_logaddr, /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
+
+u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
+ const u8 cb_cat, const u64 select_mask,
+ void *cb_addr)
+{
+ u64 port_info, dummy, inv_attr_ident, proc_mask;
+ u64 arr_index = 0;
+ u64 cb_logaddr = virt_to_abs(cb_addr);
+
+ port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
+ | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
+#ifdef DEBUG
+ ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL");
+#endif
+ return ehea_hcall_9arg_9ret(H_MODIFY_HEA_PORT,
+ adapter_handle, /* R4 */
+ port_info, /* R5 */
+ select_mask, /* R6 */
+ arr_index, /* R7 */
+ cb_logaddr, /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ &inv_attr_ident, /* R4 */
+ &proc_mask, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
+
+u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
+ const u8 reg_type, const u64 mc_mac_addr,
+ const u16 vlan_id, const u32 hcall_id)
+{
+ u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id, dummy;
+ u64 mac_addr = mc_mac_addr >> 16;
+
+ r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
+ r6_reg_type = EHEA_BMASK_SET(H_REGBCMC_REGTYPE, reg_type);
+ r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
+ r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
+
+ return ehea_hcall_9arg_9ret(hcall_id,
+ adapter_handle, /* R4 */
+ r5_port_num, /* R5 */
+ r6_reg_type, /* R6 */
+ r7_mc_mac_addr, /* R7 */
+ r8_vlan_id, /* R8 */
+ 0, 0, 0, 0, /* R9-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
+
+u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
+ const u64 event_mask)
+{
+ u64 dummy;
+
+ return ehea_hcall_9arg_9ret(H_RESET_EVENTS,
+ adapter_handle, /* R4 */
+ neq_handle, /* R5 */
+ event_mask, /* R6 */
+ 0, 0, 0, 0, 0, 0, /* R7-R12 */
+ &dummy, /* R4 */
+ &dummy, /* R5 */
+ &dummy, /* R6 */
+ &dummy, /* R7 */
+ &dummy, /* R8 */
+ &dummy, /* R9 */
+ &dummy, /* R10 */
+ &dummy, /* R11 */
+ &dummy); /* R12 */
+}
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h
new file mode 100644
index 00000000000..fa51e3b5bb0
--- /dev/null
+++ b/drivers/net/ehea/ehea_phyp.h
@@ -0,0 +1,455 @@
+/*
+ * linux/drivers/net/ehea/ehea_phyp.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 __EHEA_PHYP_H__
+#define __EHEA_PHYP_H__
+
+#include <linux/delay.h>
+#include <asm/hvcall.h>
+#include "ehea.h"
+#include "ehea_hw.h"
+#include "ehea_hcall.h"
+
+/* Some abbreviations used here:
+ *
+ * hcp_* - structures, variables and functions releated to Hypervisor Calls
+ */
+
+static inline u32 get_longbusy_msecs(int long_busy_ret_code)
+{
+ switch (long_busy_ret_code) {
+ case H_LONG_BUSY_ORDER_1_MSEC:
+ return 1;
+ case H_LONG_BUSY_ORDER_10_MSEC:
+ return 10;
+ case H_LONG_BUSY_ORDER_100_MSEC:
+ return 100;
+ case H_LONG_BUSY_ORDER_1_SEC:
+ return 1000;
+ case H_LONG_BUSY_ORDER_10_SEC:
+ return 10000;
+ case H_LONG_BUSY_ORDER_100_SEC:
+ return 100000;
+ default:
+ return 1;
+ }
+}
+
+/* Notification Event Queue (NEQ) Entry bit masks */
+#define NEQE_EVENT_CODE EHEA_BMASK_IBM(2, 7)
+#define NEQE_PORTNUM EHEA_BMASK_IBM(32, 47)
+#define NEQE_PORT_UP EHEA_BMASK_IBM(16, 16)
+#define NEQE_EXTSWITCH_PORT_UP EHEA_BMASK_IBM(17, 17)
+#define NEQE_EXTSWITCH_PRIMARY EHEA_BMASK_IBM(18, 18)
+#define NEQE_PLID EHEA_BMASK_IBM(16, 47)
+
+/* Notification Event Codes */
+#define EHEA_EC_PORTSTATE_CHG 0x30
+#define EHEA_EC_ADAPTER_MALFUNC 0x32
+#define EHEA_EC_PORT_MALFUNC 0x33
+
+/* Notification Event Log Register (NELR) bit masks */
+#define NELR_PORT_MALFUNC EHEA_BMASK_IBM(61, 61)
+#define NELR_ADAPTER_MALFUNC EHEA_BMASK_IBM(62, 62)
+#define NELR_PORTSTATE_CHG EHEA_BMASK_IBM(63, 63)
+
+static inline void hcp_epas_ctor(struct h_epas *epas, u64 paddr_kernel,
+ u64 paddr_user)
+{
+ epas->kernel.addr = ioremap(paddr_kernel, PAGE_SIZE);
+ epas->user.addr = paddr_user;
+}
+
+static inline void hcp_epas_dtor(struct h_epas *epas)
+{
+ if (epas->kernel.addr)
+ iounmap(epas->kernel.addr);
+
+ epas->user.addr = 0;
+ epas->kernel.addr = 0;
+}
+
+struct hcp_modify_qp_cb0 {
+ u64 qp_ctl_reg; /* 00 */
+ u32 max_swqe; /* 02 */
+ u32 max_rwqe; /* 03 */
+ u32 port_nb; /* 04 */
+ u32 reserved0; /* 05 */
+ u64 qp_aer; /* 06 */
+ u64 qp_tenure; /* 08 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 0 Selection Mask Bits */
+#define H_QPCB0_ALL EHEA_BMASK_IBM(0, 5)
+#define H_QPCB0_QP_CTL_REG EHEA_BMASK_IBM(0, 0)
+#define H_QPCB0_MAX_SWQE EHEA_BMASK_IBM(1, 1)
+#define H_QPCB0_MAX_RWQE EHEA_BMASK_IBM(2, 2)
+#define H_QPCB0_PORT_NB EHEA_BMASK_IBM(3, 3)
+#define H_QPCB0_QP_AER EHEA_BMASK_IBM(4, 4)
+#define H_QPCB0_QP_TENURE EHEA_BMASK_IBM(5, 5)
+
+/* Queue Pair Control Register Status Bits */
+#define H_QP_CR_ENABLED 0x8000000000000000ULL /* QP enabled */
+ /* QP States: */
+#define H_QP_CR_STATE_RESET 0x0000010000000000ULL /* Reset */
+#define H_QP_CR_STATE_INITIALIZED 0x0000020000000000ULL /* Initialized */
+#define H_QP_CR_STATE_RDY2RCV 0x0000030000000000ULL /* Ready to recv */
+#define H_QP_CR_STATE_RDY2SND 0x0000050000000000ULL /* Ready to send */
+#define H_QP_CR_STATE_ERROR 0x0000800000000000ULL /* Error */
+
+struct hcp_modify_qp_cb1 {
+ u32 qpn; /* 00 */
+ u32 qp_asyn_ev_eq_nb; /* 01 */
+ u64 sq_cq_handle; /* 02 */
+ u64 rq_cq_handle; /* 04 */
+ /* sgel = scatter gather element */
+ u32 sgel_nb_sq; /* 06 */
+ u32 sgel_nb_rq1; /* 07 */
+ u32 sgel_nb_rq2; /* 08 */
+ u32 sgel_nb_rq3; /* 09 */
+};
+
+/* Hcall Query/Modify Queue Pair Control Block 1 Selection Mask Bits */
+#define H_QPCB1_ALL EHEA_BMASK_IBM(0, 7)
+#define H_QPCB1_QPN EHEA_BMASK_IBM(0, 0)
+#define H_QPCB1_ASYN_EV_EQ_NB EHEA_BMASK_IBM(1, 1)
+#define H_QPCB1_SQ_CQ_HANDLE EHEA_BMASK_IBM(2, 2)
+#define H_QPCB1_RQ_CQ_HANDLE EHEA_BMASK_IBM(3, 3)
+#define H_QPCB1_SGEL_NB_SQ EHEA_BMASK_IBM(4, 4)
+#define H_QPCB1_SGEL_NB_RQ1 EHEA_BMASK_IBM(5, 5)
+#define H_QPCB1_SGEL_NB_RQ2 EHEA_BMASK_IBM(6, 6)
+#define H_QPCB1_SGEL_NB_RQ3 EHEA_BMASK_IBM(7, 7)
+
+struct hcp_query_ehea {
+ u32 cur_num_qps; /* 00 */
+ u32 cur_num_cqs; /* 01 */
+ u32 cur_num_eqs; /* 02 */
+ u32 cur_num_mrs; /* 03 */
+ u32 auth_level; /* 04 */
+ u32 max_num_qps; /* 05 */
+ u32 max_num_cqs; /* 06 */
+ u32 max_num_eqs; /* 07 */
+ u32 max_num_mrs; /* 08 */
+ u32 reserved0; /* 09 */
+ u32 int_clock_freq; /* 10 */
+ u32 max_num_pds; /* 11 */
+ u32 max_num_addr_handles; /* 12 */
+ u32 max_num_cqes; /* 13 */
+ u32 max_num_wqes; /* 14 */
+ u32 max_num_sgel_rq1wqe; /* 15 */
+ u32 max_num_sgel_rq2wqe; /* 16 */
+ u32 max_num_sgel_rq3wqe; /* 17 */
+ u32 mr_page_size; /* 18 */
+ u32 reserved1; /* 19 */
+ u64 max_mr_size; /* 20 */
+ u64 reserved2; /* 22 */
+ u32 num_ports; /* 24 */
+ u32 reserved3; /* 25 */
+ u32 reserved4; /* 26 */
+ u32 reserved5; /* 27 */
+ u64 max_mc_mac; /* 28 */
+ u64 ehea_cap; /* 30 */
+ u32 max_isn_per_eq; /* 32 */
+ u32 max_num_neq; /* 33 */
+ u64 max_num_vlan_ids; /* 34 */
+ u32 max_num_port_group; /* 36 */
+ u32 max_num_phys_port; /* 37 */
+
+};
+
+/* Hcall Query/Modify Port Control Block defines */
+#define H_PORT_CB0 0
+#define H_PORT_CB1 1
+#define H_PORT_CB2 2
+#define H_PORT_CB3 3
+#define H_PORT_CB4 4
+#define H_PORT_CB5 5
+#define H_PORT_CB6 6
+#define H_PORT_CB7 7
+
+struct hcp_ehea_port_cb0 {
+ u64 port_mac_addr;
+ u64 port_rc;
+ u64 reserved0;
+ u32 port_op_state;
+ u32 port_speed;
+ u32 ext_swport_op_state;
+ u32 neg_tpf_prpf;
+ u32 num_default_qps;
+ u32 reserved1;
+ u64 default_qpn_arr[16];
+};
+
+/* Hcall Query/Modify Port Control Block 0 Selection Mask Bits */
+#define H_PORT_CB0_ALL EHEA_BMASK_IBM(0, 7) /* Set all bits */
+#define H_PORT_CB0_MAC EHEA_BMASK_IBM(0, 0) /* MAC address */
+#define H_PORT_CB0_PRC EHEA_BMASK_IBM(1, 1) /* Port Recv Control */
+#define H_PORT_CB0_DEFQPNARRAY EHEA_BMASK_IBM(7, 7) /* Default QPN Array */
+
+/* Hcall Query Port: Returned port speed values */
+#define H_SPEED_10M_H 1 /* 10 Mbps, Half Duplex */
+#define H_SPEED_10M_F 2 /* 10 Mbps, Full Duplex */
+#define H_SPEED_100M_H 3 /* 100 Mbps, Half Duplex */
+#define H_SPEED_100M_F 4 /* 100 Mbps, Full Duplex */
+#define H_SPEED_1G_F 6 /* 1 Gbps, Full Duplex */
+#define H_SPEED_10G_F 8 /* 10 Gbps, Full Duplex */
+
+/* Port Receive Control Status Bits */
+#define PXLY_RC_VALID EHEA_BMASK_IBM(49, 49)
+#define PXLY_RC_VLAN_XTRACT EHEA_BMASK_IBM(50, 50)
+#define PXLY_RC_TCP_6_TUPLE EHEA_BMASK_IBM(51, 51)
+#define PXLY_RC_UDP_6_TUPLE EHEA_BMASK_IBM(52, 52)
+#define PXLY_RC_TCP_3_TUPLE EHEA_BMASK_IBM(53, 53)
+#define PXLY_RC_TCP_2_TUPLE EHEA_BMASK_IBM(54, 54)
+#define PXLY_RC_LLC_SNAP EHEA_BMASK_IBM(55, 55)
+#define PXLY_RC_JUMBO_FRAME EHEA_BMASK_IBM(56, 56)
+#define PXLY_RC_FRAG_IP_PKT EHEA_BMASK_IBM(57, 57)
+#define PXLY_RC_TCP_UDP_CHKSUM EHEA_BMASK_IBM(58, 58)
+#define PXLY_RC_IP_CHKSUM EHEA_BMASK_IBM(59, 59)
+#define PXLY_RC_MAC_FILTER EHEA_BMASK_IBM(60, 60)
+#define PXLY_RC_UNTAG_FILTER EHEA_BMASK_IBM(61, 61)
+#define PXLY_RC_VLAN_TAG_FILTER EHEA_BMASK_IBM(62, 63)
+
+#define PXLY_RC_VLAN_FILTER 2
+#define PXLY_RC_VLAN_PERM 0
+
+
+#define H_PORT_CB1_ALL 0x8000000000000000ULL
+
+struct hcp_ehea_port_cb1 {
+ u64 vlan_filter[64];
+};
+
+#define H_PORT_CB2_ALL 0xFFE0000000000000ULL
+
+struct hcp_ehea_port_cb2 {
+ u64 rxo;
+ u64 rxucp;
+ u64 rxufd;
+ u64 rxuerr;
+ u64 rxftl;
+ u64 rxmcp;
+ u64 rxbcp;
+ u64 txo;
+ u64 txucp;
+ u64 txmcp;
+ u64 txbcp;
+};
+
+struct hcp_ehea_port_cb3 {
+ u64 vlan_bc_filter[64];
+ u64 vlan_mc_filter[64];
+ u64 vlan_un_filter[64];
+ u64 port_mac_hash_array[64];
+};
+
+#define H_PORT_CB4_ALL 0xF000000000000000ULL
+#define H_PORT_CB4_JUMBO 0x1000000000000000ULL
+#define H_PORT_CB4_SPEED 0x8000000000000000ULL
+
+struct hcp_ehea_port_cb4 {
+ u32 port_speed;
+ u32 pause_frame;
+ u32 ens_port_op_state;
+ u32 jumbo_frame;
+ u32 ens_port_wrap;
+};
+
+/* Hcall Query/Modify Port Control Block 5 Selection Mask Bits */
+#define H_PORT_CB5_RCU 0x0001000000000000ULL
+#define PXS_RCU EHEA_BMASK_IBM(61, 63)
+
+struct hcp_ehea_port_cb5 {
+ u64 prc; /* 00 */
+ u64 uaa; /* 01 */
+ u64 macvc; /* 02 */
+ u64 xpcsc; /* 03 */
+ u64 xpcsp; /* 04 */
+ u64 pcsid; /* 05 */
+ u64 xpcsst; /* 06 */
+ u64 pthlb; /* 07 */
+ u64 pthrb; /* 08 */
+ u64 pqu; /* 09 */
+ u64 pqd; /* 10 */
+ u64 prt; /* 11 */
+ u64 wsth; /* 12 */
+ u64 rcb; /* 13 */
+ u64 rcm; /* 14 */
+ u64 rcu; /* 15 */
+ u64 macc; /* 16 */
+ u64 pc; /* 17 */
+ u64 pst; /* 18 */
+ u64 ducqpn; /* 19 */
+ u64 mcqpn; /* 20 */
+ u64 mma; /* 21 */
+ u64 pmc0h; /* 22 */
+ u64 pmc0l; /* 23 */
+ u64 lbc; /* 24 */
+};
+
+#define H_PORT_CB6_ALL 0xFFFFFE7FFFFF8000ULL
+
+struct hcp_ehea_port_cb6 {
+ u64 rxo; /* 00 */
+ u64 rx64; /* 01 */
+ u64 rx65; /* 02 */
+ u64 rx128; /* 03 */
+ u64 rx256; /* 04 */
+ u64 rx512; /* 05 */
+ u64 rx1024; /* 06 */
+ u64 rxbfcs; /* 07 */
+ u64 rxime; /* 08 */
+ u64 rxrle; /* 09 */
+ u64 rxorle; /* 10 */
+ u64 rxftl; /* 11 */
+ u64 rxjab; /* 12 */
+ u64 rxse; /* 13 */
+ u64 rxce; /* 14 */
+ u64 rxrf; /* 15 */
+ u64 rxfrag; /* 16 */
+ u64 rxuoc; /* 17 */
+ u64 rxcpf; /* 18 */
+ u64 rxsb; /* 19 */
+ u64 rxfd; /* 20 */
+ u64 rxoerr; /* 21 */
+ u64 rxaln; /* 22 */
+ u64 ducqpn; /* 23 */
+ u64 reserved0; /* 24 */
+ u64 rxmcp; /* 25 */
+ u64 rxbcp; /* 26 */
+ u64 txmcp; /* 27 */
+ u64 txbcp; /* 28 */
+ u64 txo; /* 29 */
+ u64 tx64; /* 30 */
+ u64 tx65; /* 31 */
+ u64 tx128; /* 32 */
+ u64 tx256; /* 33 */
+ u64 tx512; /* 34 */
+ u64 tx1024; /* 35 */
+ u64 txbfcs; /* 36 */
+ u64 txcpf; /* 37 */
+ u64 txlf; /* 38 */
+ u64 txrf; /* 39 */
+ u64 txime; /* 40 */
+ u64 txsc; /* 41 */
+ u64 txmc; /* 42 */
+ u64 txsqe; /* 43 */
+ u64 txdef; /* 44 */
+ u64 txlcol; /* 45 */
+ u64 txexcol; /* 46 */
+ u64 txcse; /* 47 */
+ u64 txbor; /* 48 */
+};
+
+#define H_PORT_CB7_DUCQPN 0x8000000000000000ULL
+
+struct hcp_ehea_port_cb7 {
+ u64 def_uc_qpn;
+};
+
+u64 ehea_h_query_ehea_qp(const u64 adapter_handle,
+ const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask,
+ void *cb_addr);
+
+u64 ehea_h_modify_ehea_qp(const u64 adapter_handle,
+ const u8 cat,
+ const u64 qp_handle,
+ const u64 sel_mask,
+ void *cb_addr,
+ u64 * inv_attr_id,
+ u64 * proc_mask, u16 * out_swr, u16 * out_rwr);
+
+u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
+ struct ehea_eq_attr *eq_attr, u64 * eq_handle);
+
+u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
+ struct ehea_cq_attr *cq_attr,
+ u64 * cq_handle, struct h_epas *epas);
+
+u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
+ struct ehea_qp_init_attr *init_attr,
+ const u32 pd,
+ u64 * qp_handle, struct h_epas *h_epas);
+
+#define H_REG_RPAGE_PAGE_SIZE EHEA_BMASK_IBM(48,55)
+#define H_REG_RPAGE_QT EHEA_BMASK_IBM(62,63)
+
+u64 ehea_h_register_rpage(const u64 adapter_handle,
+ const u8 pagesize,
+ const u8 queue_type,
+ const u64 resource_handle,
+ const u64 log_pageaddr, u64 count);
+
+#define H_DISABLE_GET_EHEA_WQE_P 1
+#define H_DISABLE_GET_SQ_WQE_P 2
+#define H_DISABLE_GET_RQC 3
+
+u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle);
+
+u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle);
+
+u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
+ const u64 length, const u32 access_ctrl,
+ const u32 pd, u64 * mr_handle, u32 * lkey);
+
+u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
+ const u8 pagesize, const u8 queue_type,
+ const u64 log_pageaddr, const u64 count);
+
+u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
+ const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
+ struct ehea_mr *mr);
+
+u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr);
+
+/* output param R5 */
+#define H_MEHEAPORT_CAT EHEA_BMASK_IBM(40,47)
+#define H_MEHEAPORT_PN EHEA_BMASK_IBM(48,63)
+
+u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
+ const u8 cb_cat, const u64 select_mask,
+ void *cb_addr);
+
+u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
+ const u8 cb_cat, const u64 select_mask,
+ void *cb_addr);
+
+#define H_REGBCMC_PN EHEA_BMASK_IBM(48, 63)
+#define H_REGBCMC_REGTYPE EHEA_BMASK_IBM(61, 63)
+#define H_REGBCMC_MACADDR EHEA_BMASK_IBM(16, 63)
+#define H_REGBCMC_VLANID EHEA_BMASK_IBM(52, 63)
+
+u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
+ const u8 reg_type, const u64 mc_mac_addr,
+ const u16 vlan_id, const u32 hcall_id);
+
+u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
+ const u64 event_mask);
+
+#endif /* __EHEA_PHYP_H__ */
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c
new file mode 100644
index 00000000000..3e1862326c8
--- /dev/null
+++ b/drivers/net/ehea/ehea_qmr.c
@@ -0,0 +1,582 @@
+/*
+ * linux/drivers/net/ehea/ehea_qmr.c
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 "ehea.h"
+#include "ehea_phyp.h"
+#include "ehea_qmr.h"
+
+static void *hw_qpageit_get_inc(struct hw_queue *queue)
+{
+ void *retvalue = hw_qeit_get(queue);
+
+ queue->current_q_offset += queue->pagesize;
+ if (queue->current_q_offset > queue->queue_length) {
+ queue->current_q_offset -= queue->pagesize;
+ retvalue = NULL;
+ } else if (((u64) retvalue) & (EHEA_PAGESIZE-1)) {
+ ehea_error("not on pageboundary");
+ retvalue = NULL;
+ }
+ return retvalue;
+}
+
+static int hw_queue_ctor(struct hw_queue *queue, const u32 nr_of_pages,
+ const u32 pagesize, const u32 qe_size)
+{
+ int pages_per_kpage = PAGE_SIZE / pagesize;
+ int i, k;
+
+ if ((pagesize > PAGE_SIZE) || (!pages_per_kpage)) {
+ ehea_error("pagesize conflict! kernel pagesize=%d, "
+ "ehea pagesize=%d", (int)PAGE_SIZE, (int)pagesize);
+ return -EINVAL;
+ }
+
+ queue->queue_length = nr_of_pages * pagesize;
+ queue->queue_pages = kmalloc(nr_of_pages * sizeof(void*), GFP_KERNEL);
+ if (!queue->queue_pages) {
+ ehea_error("no mem for queue_pages");
+ return -ENOMEM;
+ }
+
+ /*
+ * allocate pages for queue:
+ * outer loop allocates whole kernel pages (page aligned) and
+ * inner loop divides a kernel page into smaller hea queue pages
+ */
+ i = 0;
+ while (i < nr_of_pages) {
+ u8 *kpage = (u8*)get_zeroed_page(GFP_KERNEL);
+ if (!kpage)
+ goto out_nomem;
+ for (k = 0; k < pages_per_kpage && i < nr_of_pages; k++) {
+ (queue->queue_pages)[i] = (struct ehea_page*)kpage;
+ kpage += pagesize;
+ i++;
+ }
+ }
+
+ queue->current_q_offset = 0;
+ queue->qe_size = qe_size;
+ queue->pagesize = pagesize;
+ queue->toggle_state = 1;
+
+ return 0;
+out_nomem:
+ for (i = 0; i < nr_of_pages; i += pages_per_kpage) {
+ if (!(queue->queue_pages)[i])
+ break;
+ free_page((unsigned long)(queue->queue_pages)[i]);
+ }
+ return -ENOMEM;
+}
+
+static void hw_queue_dtor(struct hw_queue *queue)
+{
+ int pages_per_kpage = PAGE_SIZE / queue->pagesize;
+ int i, nr_pages;
+
+ if (!queue || !queue->queue_pages)
+ return;
+
+ nr_pages = queue->queue_length / queue->pagesize;
+
+ for (i = 0; i < nr_pages; i += pages_per_kpage)
+ free_page((unsigned long)(queue->queue_pages)[i]);
+
+ kfree(queue->queue_pages);
+}
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter,
+ int nr_of_cqe, u64 eq_handle, u32 cq_token)
+{
+ struct ehea_cq *cq;
+ struct h_epa epa;
+ u64 *cq_handle_ref, hret, rpage;
+ u32 act_nr_of_entries, act_pages, counter;
+ int ret;
+ void *vpage;
+
+ cq = kzalloc(sizeof(*cq), GFP_KERNEL);
+ if (!cq) {
+ ehea_error("no mem for cq");
+ goto out_nomem;
+ }
+
+ cq->attr.max_nr_of_cqes = nr_of_cqe;
+ cq->attr.cq_token = cq_token;
+ cq->attr.eq_handle = eq_handle;
+
+ cq->adapter = adapter;
+
+ cq_handle_ref = &cq->fw_handle;
+ act_nr_of_entries = 0;
+ act_pages = 0;
+
+ hret = ehea_h_alloc_resource_cq(adapter->handle, &cq->attr,
+ &cq->fw_handle, &cq->epas);
+ if (hret != H_SUCCESS) {
+ ehea_error("alloc_resource_cq failed");
+ goto out_freemem;
+ }
+
+ ret = hw_queue_ctor(&cq->hw_queue, cq->attr.nr_pages,
+ EHEA_PAGESIZE, sizeof(struct ehea_cqe));
+ if (ret)
+ goto out_freeres;
+
+ for (counter = 0; counter < cq->attr.nr_pages; counter++) {
+ vpage = hw_qpageit_get_inc(&cq->hw_queue);
+ if (!vpage) {
+ ehea_error("hw_qpageit_get_inc failed");
+ goto out_kill_hwq;
+ }
+
+ rpage = virt_to_abs(vpage);
+ hret = ehea_h_register_rpage(adapter->handle,
+ 0, EHEA_CQ_REGISTER_ORIG,
+ cq->fw_handle, rpage, 1);
+ if (hret < H_SUCCESS) {
+ ehea_error("register_rpage_cq failed ehea_cq=%p "
+ "hret=%lx counter=%i act_pages=%i",
+ cq, hret, counter, cq->attr.nr_pages);
+ goto out_kill_hwq;
+ }
+
+ if (counter == (cq->attr.nr_pages - 1)) {
+ vpage = hw_qpageit_get_inc(&cq->hw_queue);
+
+ if ((hret != H_SUCCESS) || (vpage)) {
+ ehea_error("registration of pages not "
+ "complete hret=%lx\n", hret);
+ goto out_kill_hwq;
+ }
+ } else {
+ if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+ ehea_error("CQ: registration of page failed "
+ "hret=%lx\n", hret);
+ goto out_kill_hwq;
+ }
+ }
+ }
+
+ hw_qeit_reset(&cq->hw_queue);
+ epa = cq->epas.kernel;
+ ehea_reset_cq_ep(cq);
+ ehea_reset_cq_n1(cq);
+
+ return cq;
+
+out_kill_hwq:
+ hw_queue_dtor(&cq->hw_queue);
+
+out_freeres:
+ ehea_h_free_resource(adapter->handle, cq->fw_handle);
+
+out_freemem:
+ kfree(cq);
+
+out_nomem:
+ return NULL;
+}
+
+int ehea_destroy_cq(struct ehea_cq *cq)
+{
+ u64 adapter_handle, hret;
+
+ adapter_handle = cq->adapter->handle;
+
+ if (!cq)
+ return 0;
+
+ /* deregister all previous registered pages */
+ hret = ehea_h_free_resource(adapter_handle, cq->fw_handle);
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy CQ failed");
+ return -EIO;
+ }
+
+ hw_queue_dtor(&cq->hw_queue);
+ kfree(cq);
+
+ return 0;
+}
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+ const enum ehea_eq_type type,
+ const u32 max_nr_of_eqes, const u8 eqe_gen)
+{
+ int ret, i;
+ u64 hret, rpage;
+ void *vpage;
+ struct ehea_eq *eq;
+
+ eq = kzalloc(sizeof(*eq), GFP_KERNEL);
+ if (!eq) {
+ ehea_error("no mem for eq");
+ return NULL;
+ }
+
+ eq->adapter = adapter;
+ eq->attr.type = type;
+ eq->attr.max_nr_of_eqes = max_nr_of_eqes;
+ eq->attr.eqe_gen = eqe_gen;
+ spin_lock_init(&eq->spinlock);
+
+ hret = ehea_h_alloc_resource_eq(adapter->handle,
+ &eq->attr, &eq->fw_handle);
+ if (hret != H_SUCCESS) {
+ ehea_error("alloc_resource_eq failed");
+ goto out_freemem;
+ }
+
+ ret = hw_queue_ctor(&eq->hw_queue, eq->attr.nr_pages,
+ EHEA_PAGESIZE, sizeof(struct ehea_eqe));
+ if (ret) {
+ ehea_error("can't allocate eq pages");
+ goto out_freeres;
+ }
+
+ for (i = 0; i < eq->attr.nr_pages; i++) {
+ vpage = hw_qpageit_get_inc(&eq->hw_queue);
+ if (!vpage) {
+ ehea_error("hw_qpageit_get_inc failed");
+ hret = H_RESOURCE;
+ goto out_kill_hwq;
+ }
+
+ rpage = virt_to_abs(vpage);
+
+ hret = ehea_h_register_rpage(adapter->handle, 0,
+ EHEA_EQ_REGISTER_ORIG,
+ eq->fw_handle, rpage, 1);
+
+ if (i == (eq->attr.nr_pages - 1)) {
+ /* last page */
+ vpage = hw_qpageit_get_inc(&eq->hw_queue);
+ if ((hret != H_SUCCESS) || (vpage)) {
+ goto out_kill_hwq;
+ }
+ } else {
+ if ((hret != H_PAGE_REGISTERED) || (!vpage)) {
+ goto out_kill_hwq;
+ }
+ }
+ }
+
+ hw_qeit_reset(&eq->hw_queue);
+ return eq;
+
+out_kill_hwq:
+ hw_queue_dtor(&eq->hw_queue);
+
+out_freeres:
+ ehea_h_free_resource(adapter->handle, eq->fw_handle);
+
+out_freemem:
+ kfree(eq);
+ return NULL;
+}
+
+struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq)
+{
+ struct ehea_eqe *eqe;
+ unsigned long flags;
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+ eqe = (struct ehea_eqe*)hw_eqit_eq_get_inc_valid(&eq->hw_queue);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ return eqe;
+}
+
+int ehea_destroy_eq(struct ehea_eq *eq)
+{
+ u64 hret;
+ unsigned long flags;
+
+ if (!eq)
+ return 0;
+
+ spin_lock_irqsave(&eq->spinlock, flags);
+
+ hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle);
+ spin_unlock_irqrestore(&eq->spinlock, flags);
+
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy_eq failed");
+ return -EIO;
+ }
+
+ hw_queue_dtor(&eq->hw_queue);
+ kfree(eq);
+
+ return 0;
+}
+
+/**
+ * allocates memory for a queue and registers pages in phyp
+ */
+int ehea_qp_alloc_register(struct ehea_qp *qp, struct hw_queue *hw_queue,
+ int nr_pages, int wqe_size, int act_nr_sges,
+ struct ehea_adapter *adapter, int h_call_q_selector)
+{
+ u64 hret, rpage;
+ int ret, cnt;
+ void *vpage;
+
+ ret = hw_queue_ctor(hw_queue, nr_pages, EHEA_PAGESIZE, wqe_size);
+ if (ret)
+ return ret;
+
+ for (cnt = 0; cnt < nr_pages; cnt++) {
+ vpage = hw_qpageit_get_inc(hw_queue);
+ if (!vpage) {
+ ehea_error("hw_qpageit_get_inc failed");
+ goto out_kill_hwq;
+ }
+ rpage = virt_to_abs(vpage);
+ hret = ehea_h_register_rpage(adapter->handle,
+ 0, h_call_q_selector,
+ qp->fw_handle, rpage, 1);
+ if (hret < H_SUCCESS) {
+ ehea_error("register_rpage_qp failed");
+ goto out_kill_hwq;
+ }
+ }
+ hw_qeit_reset(hw_queue);
+ return 0;
+
+out_kill_hwq:
+ hw_queue_dtor(hw_queue);
+ return -EIO;
+}
+
+static inline u32 map_wqe_size(u8 wqe_enc_size)
+{
+ return 128 << wqe_enc_size;
+}
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter *adapter,
+ u32 pd, struct ehea_qp_init_attr *init_attr)
+{
+ int ret;
+ u64 hret;
+ struct ehea_qp *qp;
+ u32 wqe_size_in_bytes_sq, wqe_size_in_bytes_rq1;
+ u32 wqe_size_in_bytes_rq2, wqe_size_in_bytes_rq3;
+
+
+ qp = kzalloc(sizeof(*qp), GFP_KERNEL);
+ if (!qp) {
+ ehea_error("no mem for qp");
+ return NULL;
+ }
+
+ qp->adapter = adapter;
+
+ hret = ehea_h_alloc_resource_qp(adapter->handle, init_attr, pd,
+ &qp->fw_handle, &qp->epas);
+ if (hret != H_SUCCESS) {
+ ehea_error("ehea_h_alloc_resource_qp failed");
+ goto out_freemem;
+ }
+
+ wqe_size_in_bytes_sq = map_wqe_size(init_attr->act_wqe_size_enc_sq);
+ wqe_size_in_bytes_rq1 = map_wqe_size(init_attr->act_wqe_size_enc_rq1);
+ wqe_size_in_bytes_rq2 = map_wqe_size(init_attr->act_wqe_size_enc_rq2);
+ wqe_size_in_bytes_rq3 = map_wqe_size(init_attr->act_wqe_size_enc_rq3);
+
+ ret = ehea_qp_alloc_register(qp, &qp->hw_squeue, init_attr->nr_sq_pages,
+ wqe_size_in_bytes_sq,
+ init_attr->act_wqe_size_enc_sq, adapter,
+ 0);
+ if (ret) {
+ ehea_error("can't register for sq ret=%x", ret);
+ goto out_freeres;
+ }
+
+ ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue1,
+ init_attr->nr_rq1_pages,
+ wqe_size_in_bytes_rq1,
+ init_attr->act_wqe_size_enc_rq1,
+ adapter, 1);
+ if (ret) {
+ ehea_error("can't register for rq1 ret=%x", ret);
+ goto out_kill_hwsq;
+ }
+
+ if (init_attr->rq_count > 1) {
+ ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue2,
+ init_attr->nr_rq2_pages,
+ wqe_size_in_bytes_rq2,
+ init_attr->act_wqe_size_enc_rq2,
+ adapter, 2);
+ if (ret) {
+ ehea_error("can't register for rq2 ret=%x", ret);
+ goto out_kill_hwr1q;
+ }
+ }
+
+ if (init_attr->rq_count > 2) {
+ ret = ehea_qp_alloc_register(qp, &qp->hw_rqueue3,
+ init_attr->nr_rq3_pages,
+ wqe_size_in_bytes_rq3,
+ init_attr->act_wqe_size_enc_rq3,
+ adapter, 3);
+ if (ret) {
+ ehea_error("can't register for rq3 ret=%x", ret);
+ goto out_kill_hwr2q;
+ }
+ }
+
+ qp->init_attr = *init_attr;
+
+ return qp;
+
+out_kill_hwr2q:
+ hw_queue_dtor(&qp->hw_rqueue2);
+
+out_kill_hwr1q:
+ hw_queue_dtor(&qp->hw_rqueue1);
+
+out_kill_hwsq:
+ hw_queue_dtor(&qp->hw_squeue);
+
+out_freeres:
+ ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle);
+ ehea_h_free_resource(adapter->handle, qp->fw_handle);
+
+out_freemem:
+ kfree(qp);
+ return NULL;
+}
+
+int ehea_destroy_qp(struct ehea_qp *qp)
+{
+ u64 hret;
+ struct ehea_qp_init_attr *qp_attr = &qp->init_attr;
+
+ if (!qp)
+ return 0;
+
+ hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle);
+ if (hret != H_SUCCESS) {
+ ehea_error("destroy_qp failed");
+ return -EIO;
+ }
+
+ hw_queue_dtor(&qp->hw_squeue);
+ hw_queue_dtor(&qp->hw_rqueue1);
+
+ if (qp_attr->rq_count > 1)
+ hw_queue_dtor(&qp->hw_rqueue2);
+ if (qp_attr->rq_count > 2)
+ hw_queue_dtor(&qp->hw_rqueue3);
+ kfree(qp);
+
+ return 0;
+}
+
+int ehea_reg_mr_adapter(struct ehea_adapter *adapter)
+{
+ int i, k, ret;
+ u64 hret, pt_abs, start, end, nr_pages;
+ u32 acc_ctrl = EHEA_MR_ACC_CTRL;
+ u64 *pt;
+
+ start = KERNELBASE;
+ end = (u64)high_memory;
+ nr_pages = (end - start) / PAGE_SIZE;
+
+ pt = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!pt) {
+ ehea_error("no mem");
+ ret = -ENOMEM;
+ goto out;
+ }
+ pt_abs = virt_to_abs(pt);
+
+ hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start,
+ acc_ctrl, adapter->pd,
+ &adapter->mr.handle, &adapter->mr.lkey);
+ if (hret != H_SUCCESS) {
+ ehea_error("alloc_resource_mr failed");
+ ret = -EIO;
+ goto out;
+ }
+
+ adapter->mr.vaddr = KERNELBASE;
+ k = 0;
+
+ while (nr_pages > 0) {
+ if (nr_pages > 1) {
+ u64 num_pages = min(nr_pages, (u64)512);
+ for (i = 0; i < num_pages; i++)
+ pt[i] = virt_to_abs((void*)(((u64)start)
+ + ((k++) *
+ PAGE_SIZE)));
+
+ hret = ehea_h_register_rpage_mr(adapter->handle,
+ adapter->mr.handle, 0,
+ 0, (u64)pt_abs,
+ num_pages);
+ nr_pages -= num_pages;
+ } else {
+ u64 abs_adr = virt_to_abs((void*)(((u64)start)
+ + (k * PAGE_SIZE)));
+ hret = ehea_h_register_rpage_mr(adapter->handle,
+ adapter->mr.handle, 0,
+ 0, abs_adr,1);
+ nr_pages--;
+ }
+
+ if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) {
+ ehea_h_free_resource(adapter->handle,
+ adapter->mr.handle);
+ ehea_error("register_rpage_mr failed: hret = %lX",
+ hret);
+ ret = -EIO;
+ goto out;
+ }
+ }
+
+ if (hret != H_SUCCESS) {
+ ehea_h_free_resource(adapter->handle, adapter->mr.handle);
+ ehea_error("register_rpage failed for last page: hret = %lX",
+ hret);
+ ret = -EIO;
+ goto out;
+ }
+ ret = 0;
+out:
+ kfree(pt);
+ return ret;
+}
+
+
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h
new file mode 100644
index 00000000000..7efdc96919c
--- /dev/null
+++ b/drivers/net/ehea/ehea_qmr.h
@@ -0,0 +1,358 @@
+/*
+ * linux/drivers/net/ehea/ehea_qmr.h
+ *
+ * eHEA ethernet device driver for IBM eServer System p
+ *
+ * (C) Copyright IBM Corp. 2006
+ *
+ * Authors:
+ * Christoph Raisch <raisch@de.ibm.com>
+ * Jan-Bernd Themann <themann@de.ibm.com>
+ * Thomas Klein <tklein@de.ibm.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 __EHEA_QMR_H__
+#define __EHEA_QMR_H__
+
+#include "ehea.h"
+#include "ehea_hw.h"
+
+/*
+ * page size of ehea hardware queues
+ */
+
+#define EHEA_PAGESHIFT 12
+#define EHEA_PAGESIZE 4096UL
+
+/* Some abbreviations used here:
+ *
+ * WQE - Work Queue Entry
+ * SWQE - Send Work Queue Entry
+ * RWQE - Receive Work Queue Entry
+ * CQE - Completion Queue Entry
+ * EQE - Event Queue Entry
+ * MR - Memory Region
+ */
+
+/* Use of WR_ID field for EHEA */
+#define EHEA_WR_ID_COUNT EHEA_BMASK_IBM(0, 19)
+#define EHEA_WR_ID_TYPE EHEA_BMASK_IBM(20, 23)
+#define EHEA_SWQE2_TYPE 0x1
+#define EHEA_SWQE3_TYPE 0x2
+#define EHEA_RWQE2_TYPE 0x3
+#define EHEA_RWQE3_TYPE 0x4
+#define EHEA_WR_ID_INDEX EHEA_BMASK_IBM(24, 47)
+#define EHEA_WR_ID_REFILL EHEA_BMASK_IBM(48, 63)
+
+struct ehea_vsgentry {
+ u64 vaddr;
+ u32 l_key;
+ u32 len;
+};
+
+/* maximum number of sg entries allowed in a WQE */
+#define EHEA_MAX_WQE_SG_ENTRIES 252
+#define SWQE2_MAX_IMM (0xD0 - 0x30)
+#define SWQE3_MAX_IMM 224
+
+/* tx control flags for swqe */
+#define EHEA_SWQE_CRC 0x8000
+#define EHEA_SWQE_IP_CHECKSUM 0x4000
+#define EHEA_SWQE_TCP_CHECKSUM 0x2000
+#define EHEA_SWQE_TSO 0x1000
+#define EHEA_SWQE_SIGNALLED_COMPLETION 0x0800
+#define EHEA_SWQE_VLAN_INSERT 0x0400
+#define EHEA_SWQE_IMM_DATA_PRESENT 0x0200
+#define EHEA_SWQE_DESCRIPTORS_PRESENT 0x0100
+#define EHEA_SWQE_WRAP_CTL_REC 0x0080
+#define EHEA_SWQE_WRAP_CTL_FORCE 0x0040
+#define EHEA_SWQE_BIND 0x0020
+#define EHEA_SWQE_PURGE 0x0010
+
+/* sizeof(struct ehea_swqe) less the union */
+#define SWQE_HEADER_SIZE 32
+
+struct ehea_swqe {
+ u64 wr_id;
+ u16 tx_control;
+ u16 vlan_tag;
+ u8 reserved1;
+ u8 ip_start;
+ u8 ip_end;
+ u8 immediate_data_length;
+ u8 tcp_offset;
+ u8 reserved2;
+ u16 tcp_end;
+ u8 wrap_tag;
+ u8 descriptors; /* number of valid descriptors in WQE */
+ u16 reserved3;
+ u16 reserved4;
+ u16 mss;
+ u32 reserved5;
+ union {
+ /* Send WQE Format 1 */
+ struct {
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+ } no_immediate_data;
+
+ /* Send WQE Format 2 */
+ struct {
+ struct ehea_vsgentry sg_entry;
+ /* 0x30 */
+ u8 immediate_data[SWQE2_MAX_IMM];
+ /* 0xd0 */
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES-1];
+ } immdata_desc __attribute__ ((packed));
+
+ /* Send WQE Format 3 */
+ struct {
+ u8 immediate_data[SWQE3_MAX_IMM];
+ } immdata_nodesc;
+ } u;
+};
+
+struct ehea_rwqe {
+ u64 wr_id; /* work request ID */
+ u8 reserved1[5];
+ u8 data_segments;
+ u16 reserved2;
+ u64 reserved3;
+ u64 reserved4;
+ struct ehea_vsgentry sg_list[EHEA_MAX_WQE_SG_ENTRIES];
+};
+
+#define EHEA_CQE_VLAN_TAG_XTRACT 0x0400
+
+#define EHEA_CQE_TYPE_RQ 0x60
+#define EHEA_CQE_STAT_ERR_MASK 0x721F
+#define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F
+#define EHEA_CQE_STAT_ERR_TCP 0x4000
+
+struct ehea_cqe {
+ u64 wr_id; /* work request ID from WQE */
+ u8 type;
+ u8 valid;
+ u16 status;
+ u16 reserved1;
+ u16 num_bytes_transfered;
+ u16 vlan_tag;
+ u16 inet_checksum_value;
+ u8 reserved2;
+ u8 header_length;
+ u16 reserved3;
+ u16 page_offset;
+ u16 wqe_count;
+ u32 qp_token;
+ u32 timestamp;
+ u32 reserved4;
+ u64 reserved5[3];
+};
+
+#define EHEA_EQE_VALID EHEA_BMASK_IBM(0, 0)
+#define EHEA_EQE_IS_CQE EHEA_BMASK_IBM(1, 1)
+#define EHEA_EQE_IDENTIFIER EHEA_BMASK_IBM(2, 7)
+#define EHEA_EQE_QP_CQ_NUMBER EHEA_BMASK_IBM(8, 31)
+#define EHEA_EQE_QP_TOKEN EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_CQ_TOKEN EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_KEY EHEA_BMASK_IBM(32, 63)
+#define EHEA_EQE_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
+#define EHEA_EQE_EQ_NUMBER EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_ID EHEA_BMASK_IBM(48, 63)
+#define EHEA_EQE_SM_MECH_NUMBER EHEA_BMASK_IBM(48, 55)
+#define EHEA_EQE_SM_PORT_NUMBER EHEA_BMASK_IBM(56, 63)
+
+struct ehea_eqe {
+ u64 entry;
+};
+
+static inline void *hw_qeit_calc(struct hw_queue *queue, u64 q_offset)
+{
+ struct ehea_page *current_page;
+
+ if (q_offset >= queue->queue_length)
+ q_offset -= queue->queue_length;
+ current_page = (queue->queue_pages)[q_offset >> EHEA_PAGESHIFT];
+ return &current_page->entries[q_offset & (EHEA_PAGESIZE - 1)];
+}
+
+static inline void *hw_qeit_get(struct hw_queue *queue)
+{
+ return hw_qeit_calc(queue, queue->current_q_offset);
+}
+
+static inline void hw_qeit_inc(struct hw_queue *queue)
+{
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset >= queue->queue_length) {
+ queue->current_q_offset = 0;
+ /* toggle the valid flag */
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+}
+
+static inline void *hw_qeit_get_inc(struct hw_queue *queue)
+{
+ void *retvalue = hw_qeit_get(queue);
+ hw_qeit_inc(queue);
+ return retvalue;
+}
+
+static inline void *hw_qeit_get_inc_valid(struct hw_queue *queue)
+{
+ struct ehea_cqe *retvalue = hw_qeit_get(queue);
+ u8 valid = retvalue->valid;
+ void *pref;
+
+ if ((valid >> 7) == (queue->toggle_state & 1)) {
+ /* this is a good one */
+ hw_qeit_inc(queue);
+ pref = hw_qeit_calc(queue, queue->current_q_offset);
+ prefetch(pref);
+ prefetch(pref + 128);
+ } else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline void *hw_qeit_get_valid(struct hw_queue *queue)
+{
+ struct ehea_cqe *retvalue = hw_qeit_get(queue);
+ void *pref;
+ u8 valid;
+
+ pref = hw_qeit_calc(queue, queue->current_q_offset);
+ prefetch(pref);
+ prefetch(pref + 128);
+ prefetch(pref + 256);
+ valid = retvalue->valid;
+ if (!((valid >> 7) == (queue->toggle_state & 1)))
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline void *hw_qeit_reset(struct hw_queue *queue)
+{
+ queue->current_q_offset = 0;
+ return hw_qeit_get(queue);
+}
+
+static inline void *hw_qeit_eq_get_inc(struct hw_queue *queue)
+{
+ u64 last_entry_in_q = queue->queue_length - queue->qe_size;
+ void *retvalue;
+
+ retvalue = hw_qeit_get(queue);
+ queue->current_q_offset += queue->qe_size;
+ if (queue->current_q_offset > last_entry_in_q) {
+ queue->current_q_offset = 0;
+ queue->toggle_state = (~queue->toggle_state) & 1;
+ }
+ return retvalue;
+}
+
+static inline void *hw_eqit_eq_get_inc_valid(struct hw_queue *queue)
+{
+ void *retvalue = hw_qeit_get(queue);
+ u32 qe = *(u8*)retvalue;
+ if ((qe >> 7) == (queue->toggle_state & 1))
+ hw_qeit_eq_get_inc(queue);
+ else
+ retvalue = NULL;
+ return retvalue;
+}
+
+static inline struct ehea_rwqe *ehea_get_next_rwqe(struct ehea_qp *qp,
+ int rq_nr)
+{
+ struct hw_queue *queue;
+
+ if (rq_nr == 1)
+ queue = &qp->hw_rqueue1;
+ else if (rq_nr == 2)
+ queue = &qp->hw_rqueue2;
+ else
+ queue = &qp->hw_rqueue3;
+
+ return hw_qeit_get_inc(queue);
+}
+
+static inline struct ehea_swqe *ehea_get_swqe(struct ehea_qp *my_qp,
+ int *wqe_index)
+{
+ struct hw_queue *queue = &my_qp->hw_squeue;
+ struct ehea_swqe *wqe_p;
+
+ *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_SQ);
+ wqe_p = hw_qeit_get_inc(&my_qp->hw_squeue);
+
+ return wqe_p;
+}
+
+static inline void ehea_post_swqe(struct ehea_qp *my_qp, struct ehea_swqe *swqe)
+{
+ iosync();
+ ehea_update_sqa(my_qp, 1);
+}
+
+static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index)
+{
+ struct hw_queue *queue = &qp->hw_rqueue1;
+
+ *wqe_index = (queue->current_q_offset) >> (7 + EHEA_SG_RQ1);
+ return hw_qeit_get_valid(queue);
+}
+
+static inline void ehea_inc_rq1(struct ehea_qp *qp)
+{
+ hw_qeit_inc(&qp->hw_rqueue1);
+}
+
+static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq)
+{
+ return hw_qeit_get_inc_valid(&my_cq->hw_queue);
+}
+
+#define EHEA_CQ_REGISTER_ORIG 0
+#define EHEA_EQ_REGISTER_ORIG 0
+
+enum ehea_eq_type {
+ EHEA_EQ = 0, /* event queue */
+ EHEA_NEQ /* notification event queue */
+};
+
+struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter,
+ enum ehea_eq_type type,
+ const u32 length, const u8 eqe_gen);
+
+int ehea_destroy_eq(struct ehea_eq *eq);
+
+struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq);
+
+struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, int cqe,
+ u64 eq_handle, u32 cq_token);
+
+int ehea_destroy_cq(struct ehea_cq *cq);
+
+struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd,
+ struct ehea_qp_init_attr *init_attr);
+
+int ehea_destroy_qp(struct ehea_qp *qp);
+
+int ehea_reg_mr_adapter(struct ehea_adapter *adapter);
+
+#endif /* __EHEA_QMR_H__ */
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 724d7dc35fa..ba2565ee043 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -19,62 +19,15 @@
Information and updates available at
http://www.scyld.com/network/epic100.html
+ [this link no longer provides anything useful -jgarzik]
---------------------------------------------------------------------
- Linux kernel-specific changes:
-
- LK1.1.2 (jgarzik):
- * Merge becker version 1.09 (4/08/2000)
-
- LK1.1.3:
- * Major bugfix to 1.09 driver (Francis Romieu)
-
- LK1.1.4 (jgarzik):
- * Merge becker test version 1.09 (5/29/2000)
-
- LK1.1.5:
- * Fix locking (jgarzik)
- * Limit 83c175 probe to ethernet-class PCI devices (rgooch)
-
- LK1.1.6:
- * Merge becker version 1.11
- * Move pci_enable_device before any PCI BAR len checks
-
- LK1.1.7:
- * { fill me in }
-
- LK1.1.8:
- * ethtool driver info support (jgarzik)
-
- LK1.1.9:
- * ethtool media get/set support (jgarzik)
-
- LK1.1.10:
- * revert MII transceiver init change (jgarzik)
-
- LK1.1.11:
- * implement ETHTOOL_[GS]SET, _NWAY_RST, _[GS]MSGLVL, _GLINK (jgarzik)
- * replace some MII-related magic numbers with constants
-
- LK1.1.12:
- * fix power-up sequence
-
- LK1.1.13:
- * revert version 1.1.12, power-up sequence "fix"
-
- LK1.1.14 (Kryzsztof Halasa):
- * fix spurious bad initializations
- * pound phy a la SMSC's app note on the subject
-
- AC1.1.14ac
- * fix power up/down for ethtool that broke in 1.11
-
*/
#define DRV_NAME "epic100"
-#define DRV_VERSION "1.11+LK1.1.14+AC1.1.14"
-#define DRV_RELDATE "June 2, 2004"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "Sept 11, 2006"
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
@@ -114,7 +67,6 @@ static int rx_copybreak;
#define TX_FIFO_THRESH 256
#define RX_FIFO_THRESH 1 /* 0-3, 0==32, 64,96, or 3==128 bytes */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -191,23 +143,10 @@ IVc. Errata
*/
-enum pci_id_flags_bits {
- /* Set PCI command register bits before calling probe1(). */
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- /* Read and map the single following PCI BAR. */
- PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
- PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
-
enum chip_capability_flags { MII_PWRDWN=1, TYPE2_INTR=2, NO_MII=4 };
#define EPIC_TOTAL_SIZE 0x100
#define USE_IO_OPS 1
-#ifdef USE_IO_OPS
-#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR0
-#else
-#define EPIC_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR1
-#endif
typedef enum {
SMSC_83C170_0,
@@ -218,20 +157,15 @@ typedef enum {
struct epic_chip_info {
const char *name;
- enum pci_id_flags_bits pci_flags;
- int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
};
/* indexed by chip_t */
static const struct epic_chip_info pci_id_tbl[] = {
- { "SMSC EPIC/100 83c170",
- EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN },
- { "SMSC EPIC/100 83c170",
- EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR },
- { "SMSC EPIC/C 83c175",
- EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | MII_PWRDWN },
+ { "SMSC EPIC/100 83c170", TYPE2_INTR | NO_MII | MII_PWRDWN },
+ { "SMSC EPIC/100 83c170", TYPE2_INTR },
+ { "SMSC EPIC/C 83c175", TYPE2_INTR | MII_PWRDWN },
};
@@ -365,7 +299,7 @@ static int epic_rx(struct net_device *dev, int budget);
static int epic_poll(struct net_device *dev, int *budget);
static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static int epic_close(struct net_device *dev);
static struct net_device_stats *epic_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
@@ -400,8 +334,8 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
goto out;
irq = pdev->irq;
- if (pci_resource_len(pdev, 0) < pci_id_tbl[chip_idx].io_size) {
- printk (KERN_ERR "card %d: no PCI region space\n", card_idx);
+ if (pci_resource_len(pdev, 0) < EPIC_TOTAL_SIZE) {
+ dev_err(&pdev->dev, "no PCI region space\n");
ret = -ENODEV;
goto err_out_disable;
}
@@ -416,7 +350,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
dev = alloc_etherdev(sizeof (*ep));
if (!dev) {
- printk (KERN_ERR "card %d: no memory for eth device\n", card_idx);
+ dev_err(&pdev->dev, "no memory for eth device\n");
goto err_out_free_res;
}
SET_MODULE_OWNER(dev);
@@ -428,7 +362,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
ioaddr = pci_resource_start (pdev, 1);
ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1));
if (!ioaddr) {
- printk (KERN_ERR DRV_NAME " %d: ioremap failed\n", card_idx);
+ dev_err(&pdev->dev, "ioremap failed\n");
goto err_out_free_netdev;
}
#endif
@@ -488,8 +422,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
((u16 *)dev->dev_addr)[i] = le16_to_cpu(inw(ioaddr + LAN0 + i*4));
if (debug > 2) {
- printk(KERN_DEBUG DRV_NAME "(%s): EEPROM contents\n",
- pci_name(pdev));
+ dev_printk(KERN_DEBUG, &pdev->dev, "EEPROM contents:\n");
for (i = 0; i < 64; i++)
printk(" %4.4x%s", read_eeprom(ioaddr, i),
i % 16 == 15 ? "\n" : "");
@@ -511,21 +444,23 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
int mii_status = mdio_read(dev, phy, MII_BMSR);
if (mii_status != 0xffff && mii_status != 0x0000) {
ep->phys[phy_idx++] = phy;
- printk(KERN_INFO DRV_NAME "(%s): MII transceiver #%d control "
- "%4.4x status %4.4x.\n",
- pci_name(pdev), phy, mdio_read(dev, phy, 0), mii_status);
+ dev_info(&pdev->dev,
+ "MII transceiver #%d control "
+ "%4.4x status %4.4x.\n",
+ phy, mdio_read(dev, phy, 0), mii_status);
}
}
ep->mii_phy_cnt = phy_idx;
if (phy_idx != 0) {
phy = ep->phys[0];
ep->mii.advertising = mdio_read(dev, phy, MII_ADVERTISE);
- printk(KERN_INFO DRV_NAME "(%s): Autonegotiation advertising %4.4x link "
+ dev_info(&pdev->dev,
+ "Autonegotiation advertising %4.4x link "
"partner %4.4x.\n",
- pci_name(pdev), ep->mii.advertising, mdio_read(dev, phy, 5));
+ ep->mii.advertising, mdio_read(dev, phy, 5));
} else if ( ! (ep->chip_flags & NO_MII)) {
- printk(KERN_WARNING DRV_NAME "(%s): ***WARNING***: No MII transceiver found!\n",
- pci_name(pdev));
+ dev_warn(&pdev->dev,
+ "***WARNING***: No MII transceiver found!\n");
/* Use the known PHY address of the EPII. */
ep->phys[0] = 3;
}
@@ -540,8 +475,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev,
/* The lower four bits are the media type. */
if (duplex) {
ep->mii.force_media = ep->mii.full_duplex = 1;
- printk(KERN_INFO DRV_NAME "(%s): Forced full duplex operation requested.\n",
- pci_name(pdev));
+ dev_info(&pdev->dev, "Forced full duplex requested.\n");
}
dev->if_port = ep->default_port = option;
@@ -728,7 +662,7 @@ static int epic_open(struct net_device *dev)
/* Soft reset the chip. */
outl(0x4001, ioaddr + GENCTL);
- if ((retval = request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, dev->name, dev)))
+ if ((retval = request_irq(dev->irq, &epic_interrupt, IRQF_SHARED, dev->name, dev)))
return retval;
epic_init_ring(dev);
@@ -1452,7 +1386,6 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
outl(0x002C, ioaddr + RxCtrl);
/* Unconditionally log net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
} else if ((dev->mc_count > 0) || (dev->flags & IFF_ALLMULTI)) {
/* There is apparently a chip bug, so the multicast filter
@@ -1559,7 +1492,7 @@ static void ethtool_complete(struct net_device *dev)
}
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.set_settings = netdev_set_settings,
@@ -1670,7 +1603,7 @@ static int __init epic_init (void)
version, version2, version3);
#endif
- return pci_module_init (&epic_driver);
+ return pci_register_driver(&epic_driver);
}
diff --git a/drivers/net/eql.c b/drivers/net/eql.c
index 815436c6170..a93700e5661 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -8,7 +8,7 @@
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
- *
+ *
* The author may be reached as simon@ncm.com, or C/O
* NCM
* Attn: Simon Janes
@@ -23,7 +23,7 @@
* Inspirations:
* The Harried and Overworked Alan Cox
* Conspiracies:
- * The Alan Cox and Mike McLagan plot to get someone else to do the code,
+ * The Alan Cox and Mike McLagan plot to get someone else to do the code,
* which turned out to be me.
*/
@@ -138,7 +138,7 @@ static void eql_timer(unsigned long param)
{
equalizer_t *eql = (equalizer_t *) param;
struct list_head *this, *tmp, *head;
-
+
spin_lock_bh(&eql->queue.lock);
head = &eql->queue.all_slaves;
list_for_each_safe(this, tmp, head) {
@@ -159,7 +159,7 @@ static void eql_timer(unsigned long param)
add_timer(&eql->timer);
}
-static char version[] __initdata =
+static char version[] __initdata =
"Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)\n";
static void __init eql_setup(struct net_device *dev)
@@ -182,12 +182,12 @@ static void __init eql_setup(struct net_device *dev)
dev->do_ioctl = eql_ioctl;
dev->hard_start_xmit = eql_slave_xmit;
dev->get_stats = eql_get_stats;
-
+
/*
* Now we undo some of the things that eth_setup does
- * that we don't like
+ * that we don't like
*/
-
+
dev->mtu = EQL_DEFAULT_MTU; /* set to 576 in if_eql.h */
dev->flags = IFF_MASTER;
@@ -223,7 +223,7 @@ static void eql_kill_one_slave(slave_queue_t *queue, slave_t *slave)
}
static void eql_kill_slave_queue(slave_queue_t *queue)
-{
+{
struct list_head *head, *tmp, *this;
spin_lock_bh(&queue->lock);
@@ -244,7 +244,7 @@ static int eql_close(struct net_device *dev)
/*
* The timer has to be stopped first before we start hacking away
- * at the data structure it scans every so often...
+ * at the data structure it scans every so often...
*/
del_timer_sync(&eql->timer);
@@ -264,7 +264,7 @@ static int eql_g_master_cfg(struct net_device *dev, master_config_t __user *mc);
static int eql_s_master_cfg(struct net_device *dev, master_config_t __user *mc);
static int eql_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
+{
if (cmd != EQL_GETMASTRCFG && cmd != EQL_GETSLAVECFG &&
!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -300,15 +300,15 @@ static slave_t *__eql_schedule_slaves(slave_queue_t *queue)
head = &queue->all_slaves;
list_for_each_safe(this, tmp, head) {
slave_t *slave = list_entry(this, slave_t, list);
- unsigned long slave_load, bytes_queued, priority_Bps;
+ unsigned long slave_load, bytes_queued, priority_Bps;
/* Go through the slave list once, updating best_slave
* whenever a new best_load is found.
*/
bytes_queued = slave->bytes_queued;
- priority_Bps = slave->priority_Bps;
+ priority_Bps = slave->priority_Bps;
if ((slave->dev->flags & IFF_UP) == IFF_UP) {
- slave_load = (~0UL - (~0UL / 2)) -
+ slave_load = (~0UL - (~0UL / 2)) -
(priority_Bps) + bytes_queued * 8;
if (slave_load < best_load) {
@@ -336,13 +336,13 @@ static int eql_slave_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dev = slave_dev;
skb->priority = 1;
- slave->bytes_queued += skb->len;
+ slave->bytes_queued += skb->len;
dev_queue_xmit(skb);
eql->stats.tx_packets++;
} else {
eql->stats.tx_dropped++;
dev_kfree_skb(skb);
- }
+ }
spin_unlock(&eql->queue.lock);
@@ -596,7 +596,7 @@ static int __init eql_init_module(void)
return -ENOMEM;
err = register_netdev(dev_eql);
- if (err)
+ if (err)
free_netdev(dev_eql);
return err;
}
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index 6b0ab1eac3f..fd7b32a24ea 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -421,8 +421,7 @@ MODULE_PARM_DESC(mem, "memory base address(es)");
MODULE_DESCRIPTION("Racal-Interlan ES3210 EISA ethernet driver");
MODULE_LICENSE("GPL");
-int
-init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index 4bf76f86d8e..f16b6a5aaa3 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -1,7 +1,7 @@
/* eth16i.c An ICL EtherTeam 16i and 32 EISA ethernet driver for Linux
-
+
Written 1994-1999 by Mika Kuoppala
-
+
Copyright (C) 1994-1999 by Mika Kuoppala
Based on skeleton.c and heavily on at1700.c by Donald Becker
@@ -12,7 +12,7 @@
This driver supports following cards :
- ICL EtherTeam 16i
- - ICL EtherTeam 32 EISA
+ - ICL EtherTeam 32 EISA
(Uses true 32 bit transfers rather than 16i compability mode)
Example Module usage:
@@ -25,26 +25,26 @@
I have benchmarked driver with PII/300Mhz as a ftp client
and 486/33Mhz as a ftp server. Top speed was 1128.37 kilobytes/sec.
-
+
Sources:
- skeleton.c a sample network driver core for linux,
written by Donald Becker <becker@scyld.com>
- - at1700.c a driver for Allied Telesis AT1700, written
+ - at1700.c a driver for Allied Telesis AT1700, written
by Donald Becker.
- e16iSRV.asm a Netware 3.X Server Driver for ICL EtherTeam16i
written by Markku Viima
- The Fujitsu MB86965 databook.
-
- Author thanks following persons due to their valueble assistance:
+
+ Author thanks following persons due to their valueble assistance:
Markku Viima (ICL)
- Ari Valve (ICL)
+ Ari Valve (ICL)
Donald Becker
Kurt Huwig <kurt@huwig.de>
Revision history:
Version Date Description
-
+
0.01 15.12-94 Initial version (card detection)
0.02 23.01-95 Interrupt is now hooked correctly
0.03 01.02-95 Rewrote initialization part
@@ -58,7 +58,7 @@
0.05 08.02-95 If there were more than one packet to send,
transmit was jammed due to invalid
register write...now fixed
- 0.06 19.02-95 Rewrote interrupt handling
+ 0.06 19.02-95 Rewrote interrupt handling
0.07 13.04-95 Wrote EEPROM read routines
Card configuration now set according to
data read from EEPROM
@@ -66,34 +66,34 @@
port if AUTO is selected
0.09 01.09-95 Added module support
-
+
0.10 04.09-95 Fixed receive packet allocation to work
with kernels > 1.3.x
-
- 0.20 20.09-95 Added support for EtherTeam32 EISA
- 0.21 17.10-95 Removed the unnecessary extern
+ 0.20 20.09-95 Added support for EtherTeam32 EISA
+
+ 0.21 17.10-95 Removed the unnecessary extern
init_etherdev() declaration. Some
other cleanups.
-
+
0.22 22.02-96 Receive buffer was not flushed
correctly when faulty packet was
received. Now fixed.
- 0.23 26.02-96 Made resetting the adapter
+ 0.23 26.02-96 Made resetting the adapter
more reliable.
-
+
0.24 27.02-96 Rewrote faulty packet handling in eth16i_rx
0.25 22.05-96 kfree() was missing from cleanup_module.
- 0.26 11.06-96 Sometimes card was not found by
+ 0.26 11.06-96 Sometimes card was not found by
check_signature(). Now made more reliable.
-
- 0.27 23.06-96 Oops. 16 consecutive collisions halted
- adapter. Now will try to retransmit
+
+ 0.27 23.06-96 Oops. 16 consecutive collisions halted
+ adapter. Now will try to retransmit
MAX_COL_16 times before finally giving up.
-
+
0.28 28.10-97 Added dev_id parameter (NULL) for free_irq
0.29 29.10-97 Multiple card support for module users
@@ -103,16 +103,16 @@
0.30a 21.08-98 Card detection made more relaxed. Driver
had problems with some TCP/IP-PROM boots
- to find the card. Suggested by
+ to find the card. Suggested by
Kurt Huwig <kurt@huwig.de>
0.31 28.08-98 Media interface port can now be selected
with module parameters or kernel
- boot parameters.
+ boot parameters.
- 0.32 31.08-98 IRQ was never freed if open/close
+ 0.32 31.08-98 IRQ was never freed if open/close
pair wasn't called. Now fixed.
-
+
0.33 10.09-98 When eth16i_open() was called after
eth16i_close() chip never recovered.
Now more shallow reset is made on
@@ -122,15 +122,15 @@
Changed ioaddr -> io for consistency
0.35 01.07-99 transmit,-receive bytes were never
- updated in stats.
+ updated in stats.
Bugs:
- In some cases the media interface autoprobing code doesn't find
- the correct interface type. In this case you can
- manually choose the interface type in DOS with E16IC.EXE which is
+ In some cases the media interface autoprobing code doesn't find
+ the correct interface type. In this case you can
+ manually choose the interface type in DOS with E16IC.EXE which is
configuration software for EtherTeam16i and EtherTeam32 cards.
This is also true for IRQ setting. You cannot use module
- parameter to configure IRQ of the card (yet).
+ parameter to configure IRQ of the card (yet).
To do:
- Real multicast support
@@ -142,18 +142,18 @@
irq without configuration utility.
*/
-static char *version =
+static char *version =
"eth16i.c: v0.35 01-Jul-1999 Mika Kuoppala (miku@iki.fi)\n";
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -163,15 +163,15 @@ static char *version =
#include <linux/bitops.h>
#include <linux/jiffies.h>
-#include <asm/system.h>
-#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/io.h>
#include <asm/dma.h>
/* Few macros */
-#define BIT(a) ( (1 << (a)) )
-#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
+#define BIT(a) ( (1 << (a)) )
+#define BITSET(ioaddr, bnum) ((outb(((inb(ioaddr)) | (bnum)), ioaddr)))
#define BITCLR(ioaddr, bnum) ((outb(((inb(ioaddr)) & (~(bnum))), ioaddr)))
/* This is the I/O address space for Etherteam 16i adapter. */
@@ -186,7 +186,7 @@ static char *version =
/* Some interrupt masks */
#define ETH16I_INTR_ON 0xef8a /* Higher is receive mask */
#define ETH16I_INTR_OFF 0x0000
-
+
/* Buffers header status byte meanings */
#define PKT_GOOD BIT(5)
#define PKT_GOOD_RMT BIT(4)
@@ -213,7 +213,7 @@ static char *version =
#define ALIGN_ERR BIT(2)
#define CRC_ERR BIT(1)
#define RX_BUF_OVERFLOW BIT(0)
-
+
/* Transmit Interrupt Enable Register (DLCR2) */
#define TX_INTR_REG 2
#define TX_INTR_DONE BIT(7)
@@ -252,14 +252,14 @@ static char *version =
#define SRAM_CYCLE_TIME_100NS BIT(6)
#define SYSTEM_BUS_WIDTH_8 BIT(5) /* 1 = 8bit, 0 = 16bit */
#define BUFFER_WIDTH_8 BIT(4) /* 1 = 8bit, 0 = 16bit */
-#define TBS1 BIT(3)
+#define TBS1 BIT(3)
#define TBS0 BIT(2)
#define SRAM_BS1 BIT(1) /* 00=8kb, 01=16kb */
#define SRAM_BS0 BIT(0) /* 10=32kb, 11=64kb */
-#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
+#ifndef ETH16I_TX_BUF_SIZE /* 0 = 2kb, 1 = 4kb */
#define ETH16I_TX_BUF_SIZE 3 /* 2 = 8kb, 3 = 16kb */
-#endif
+#endif
#define TX_BUF_1x2048 0
#define TX_BUF_2x2048 1
#define TX_BUF_2x4098 2
@@ -297,7 +297,7 @@ static char *version =
/* DMA Burst and Transceiver Mode Register (BMPR13) */
#define TRANSCEIVER_MODE_REG 13
-#define TRANSCEIVER_MODE_RB 2
+#define TRANSCEIVER_MODE_RB 2
#define IO_BASE_UNLOCK BIT(7)
#define LOWER_SQUELCH_TRESH BIT(6)
#define LINK_TEST_DISABLE BIT(5)
@@ -337,7 +337,7 @@ static char *version =
#define E_PORT_AUTO 0x03
#define E_PORT_FROM_EPROM 0x04
#define E_PRODUCT_CFG 0x30
-
+
/* Macro to slow down io between EEPROM clock transitions */
#define eeprom_slow_io() do { int _i = 40; while(--_i > 0) { inb(0x80); }}while(0)
@@ -352,12 +352,12 @@ static char *version =
/* This is the I/O address list to be probed when seeking the card */
static unsigned int eth16i_portlist[] __initdata = {
- 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+ 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
};
-static unsigned int eth32i_portlist[] __initdata = {
+static unsigned int eth32i_portlist[] __initdata = {
0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
};
/* This is the Interrupt lookup table for Eth16i card */
@@ -365,7 +365,7 @@ static unsigned int eth16i_irqmap[] __initdata = { 9, 10, 5, 15, 0 };
#define NUM_OF_ISA_IRQS 4
/* This is the Interrupt lookup table for Eth32i card */
-static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
+static unsigned int eth32i_irqmap[] __initdata = { 3, 5, 7, 9, 10, 11, 12, 15, 0 };
#define EISA_IRQ_REG 0xc89
#define NUM_OF_EISA_IRQS 8
@@ -384,7 +384,7 @@ struct eth16i_local {
unsigned char tx_started;
unsigned char tx_buf_busy;
unsigned short tx_queue; /* Number of packets in transmit buffer */
- unsigned short tx_queue_len;
+ unsigned short tx_queue_len;
unsigned int tx_buf_size;
unsigned long open_time;
unsigned long tx_buffered_packets;
@@ -414,7 +414,7 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void eth16i_reset(struct net_device *dev);
static void eth16i_timeout(struct net_device *dev);
static void eth16i_skip_packet(struct net_device *dev);
-static void eth16i_multicast(struct net_device *dev);
+static void eth16i_multicast(struct net_device *dev);
static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
static void eth16i_initialize(struct net_device *dev, int boot);
@@ -435,10 +435,10 @@ static int __init do_eth16i_probe(struct net_device *dev)
int i;
int ioaddr;
int base_addr = dev->base_addr;
-
+
SET_MODULE_OWNER(dev);
- if(eth16i_debug > 4)
+ if(eth16i_debug > 4)
printk(KERN_DEBUG "Probing started for %s\n", cardname);
if(base_addr > 0x1ff) /* Check only single location */
@@ -492,14 +492,14 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
return -EBUSY;
/*
- The MB86985 chip has on register which holds information in which
+ The MB86985 chip has on register which holds information in which
io address the chip lies. First read this register and compare
it to our current io address and if match then this could
be our chip.
*/
if(ioaddr < 0x1000) {
- if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
+ if(eth16i_portlist[(inb(ioaddr + JUMPERLESS_CONFIG) & 0x07)]
!= ioaddr) {
retval = -ENODEV;
goto out;
@@ -513,9 +513,9 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
goto out;
}
- /*
+ /*
Now it seems that we have found a ethernet chip in this particular
- ioaddr. The MB86985 chip has this feature, that when you read a
+ ioaddr. The MB86985 chip has this feature, that when you read a
certain register it will increase it's io base address to next
configurable slot. Now when we have found the chip, first thing is
to make sure that the chip's ioaddr will hold still here.
@@ -536,7 +536,7 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
/* Try to obtain interrupt vector */
if ((retval = request_irq(dev->irq, (void *)&eth16i_interrupt, 0, cardname, dev))) {
- printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
+ printk(KERN_WARNING "%s at %#3x, but is unusable due to conflicting IRQ %d.\n",
cardname, ioaddr, dev->irq);
goto out;
}
@@ -547,7 +547,7 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
/* Now we will have to lock the chip's io address */
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
- outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
+ outb(0x38, ioaddr + TRANSCEIVER_MODE_REG);
eth16i_initialize(dev, 1); /* Initialize rest of the chip's registers */
@@ -590,7 +590,7 @@ static void eth16i_initialize(struct net_device *dev, int boot)
((unsigned short *)dev->dev_addr)[i] = ntohs(node_val);
}
- for(i = 0; i < 6; i++) {
+ for(i = 0; i < 6; i++) {
outb( ((unsigned char *)dev->dev_addr)[i], ioaddr + NODE_ID_0 + i);
if(boot) {
printk("%02x", inb(ioaddr + NODE_ID_0 + i));
@@ -601,11 +601,11 @@ static void eth16i_initialize(struct net_device *dev, int boot)
/* Now we will set multicast addresses to accept none */
eth16i_select_regbank(HASH_TABLE_RB, ioaddr);
- for(i = 0; i < 8; i++)
+ for(i = 0; i < 8; i++)
outb(0x00, ioaddr + HASH_TABLE_0 + i);
/*
- Now let's disable the transmitter and receiver, set the buffer ram
+ Now let's disable the transmitter and receiver, set the buffer ram
cycle time, bus width and buffer data path width. Also we shall
set transmit buffer size and total buffer size.
*/
@@ -633,7 +633,7 @@ static void eth16i_initialize(struct net_device *dev, int boot)
#ifdef MODULE
/* if_port already set by init_module() */
#else
- dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
+ dev->if_port = (dev->mem_start < E_PORT_FROM_EPROM) ?
dev->mem_start : E_PORT_FROM_EPROM;
#endif
@@ -651,7 +651,7 @@ static void eth16i_initialize(struct net_device *dev, int boot)
case E_PORT_AUTO:
dev->if_port = eth16i_probe_port(ioaddr);
break;
-
+
case E_PORT_BNC:
case E_PORT_TP:
case E_PORT_DIX:
@@ -721,7 +721,7 @@ static int eth16i_probe_port(int ioaddr)
}
static void eth16i_set_port(int ioaddr, int porttype)
-{
+{
unsigned short temp = 0;
eth16i_select_regbank(TRANSCEIVER_MODE_RB, ioaddr);
@@ -742,13 +742,13 @@ static void eth16i_set_port(int ioaddr, int porttype)
temp |= AUI_SELECT;
BITSET(ioaddr + TRANSMIT_MODE_REG, CONTROL_OUTPUT);
break;
- }
+ }
outb(temp, ioaddr + TRANSCEIVER_MODE_REG);
if(eth16i_debug > 1) {
printk(KERN_DEBUG "TRANSMIT_MODE_REG = %x\n", inb(ioaddr + TRANSMIT_MODE_REG));
- printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
+ printk(KERN_DEBUG "TRANSCEIVER_MODE_REG = %x\n",
inb(ioaddr+TRANSCEIVER_MODE_REG));
}
}
@@ -760,10 +760,10 @@ static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l)
outb(0xff, ioaddr + TX_STATUS_REG);
outw(l, ioaddr + DATAPORT);
- outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
+ outsw(ioaddr + DATAPORT, (unsigned short *)b, (l + 1) >> 1);
starttime = jiffies;
- outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
+ outb(TX_START | 1, ioaddr + TRANSMIT_START_REG);
while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) {
if( time_after(jiffies, starttime + TX_TIMEOUT)) {
@@ -815,10 +815,10 @@ static int eth16i_set_irq(struct net_device* dev)
const int irq = dev->irq;
int i = 0;
- if(ioaddr < 0x1000) {
+ if(ioaddr < 0x1000) {
while(eth16i_irqmap[i] && eth16i_irqmap[i] != irq)
i++;
-
+
if(i < NUM_OF_ISA_IRQS) {
u8 cbyte = inb(ioaddr + JUMPERLESS_CONFIG);
cbyte = (cbyte & 0x3F) | (i << 6);
@@ -829,7 +829,7 @@ static int eth16i_set_irq(struct net_device* dev)
else {
printk(KERN_NOTICE "%s: EISA Interrupt cannot be set. Use EISA Configuration utility.\n", dev->name);
}
-
+
return -1;
}
@@ -863,7 +863,7 @@ static int __init eth16i_check_signature(int ioaddr)
creg[i] = inb(ioaddr + TRANSMIT_MODE_REG + i);
if(eth16i_debug > 1)
- printk("eth16i: read signature byte %x at %x\n",
+ printk("eth16i: read signature byte %x at %x\n",
creg[i],
ioaddr + TRANSMIT_MODE_REG + i);
}
@@ -872,7 +872,7 @@ static int __init eth16i_check_signature(int ioaddr)
creg[2] &= 0x7F; /* Mask DCLEN bit */
#if 0
- /*
+ /*
This was removed because the card was sometimes left to state
from which it couldn't be find anymore. If there is need
to more strict check still this have to be fixed.
@@ -886,14 +886,14 @@ static int __init eth16i_check_signature(int ioaddr)
if( !((creg[2] == 0x36) && (creg[3] == 0xE0)) ) {
creg[2] &= 0x40;
creg[3] &= 0x03;
-
+
if( !((creg[2] == 0x40) && (creg[3] == 0x00)) )
return -1;
}
-
+
if(eth16i_read_eeprom(ioaddr, E_NODEID_0) != 0)
return -1;
-
+
if((eth16i_read_eeprom(ioaddr, E_NODEID_1) & 0xFF00) != 0x4B00)
return -1;
@@ -909,22 +909,22 @@ static int eth16i_read_eeprom(int ioaddr, int offset)
data = eth16i_read_eeprom_word(ioaddr);
outb(CS_0 | SK_0, ioaddr + EEPROM_CTRL_REG);
- return(data);
+ return(data);
}
static int eth16i_read_eeprom_word(int ioaddr)
{
int i;
int data = 0;
-
+
for(i = 16; i > 0; i--) {
outb(CS_1 | SK_0, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
- data = (data << 1) |
+ data = (data << 1) |
((inb(ioaddr + EEPROM_DATA_REG) & DI_1) ? 1 : 0);
-
+
eeprom_slow_io();
}
@@ -948,25 +948,25 @@ static void eth16i_eeprom_cmd(int ioaddr, unsigned char command)
eeprom_slow_io();
outb(CS_1 | SK_1, ioaddr + EEPROM_CTRL_REG);
eeprom_slow_io();
- }
+ }
}
static int eth16i_open(struct net_device *dev)
{
struct eth16i_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
-
+
/* Powerup the chip */
outb(0xc0 | POWERUP, ioaddr + CONFIG_REG_1);
/* Initialize the chip */
- eth16i_initialize(dev, 0);
+ eth16i_initialize(dev, 0);
/* Set the transmit buffer size */
lp->tx_buf_size = eth16i_tx_buf_map[ETH16I_TX_BUF_SIZE & 0x03];
if(eth16i_debug > 0)
- printk(KERN_DEBUG "%s: transmit buffer size %d\n",
+ printk(KERN_DEBUG "%s: transmit buffer size %d\n",
dev->name, lp->tx_buf_size);
/* Now enable Transmitter and Receiver sections */
@@ -981,7 +981,7 @@ static int eth16i_open(struct net_device *dev)
lp->tx_queue_len = 0;
/* Turn on interrupts*/
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
netif_start_queue(dev);
return 0;
@@ -995,10 +995,10 @@ static int eth16i_close(struct net_device *dev)
eth16i_reset(dev);
/* Turn off interrupts*/
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
netif_stop_queue(dev);
-
+
lp->open_time = 0;
/* Disable transmit and receive */
@@ -1007,7 +1007,7 @@ static int eth16i_close(struct net_device *dev)
/* Reset the chip */
/* outb(0xff, ioaddr + RESET); */
/* outw(0xffff, ioaddr + TX_STATUS_REG); */
-
+
outb(0x00, ioaddr + CONFIG_REG_1);
return 0;
@@ -1017,26 +1017,26 @@ static void eth16i_timeout(struct net_device *dev)
{
struct eth16i_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
- /*
- If we get here, some higher level has decided that
- we are broken. There should really be a "kick me"
- function call instead.
+ /*
+ If we get here, some higher level has decided that
+ we are broken. There should really be a "kick me"
+ function call instead.
*/
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
dev->name,
- inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
"IRQ conflict" : "network cable problem");
dev->trans_start = jiffies;
/* Let's dump all registers */
- if(eth16i_debug > 0) {
+ if(eth16i_debug > 0) {
printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0),
- inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4),
+ dev->name, inb(ioaddr + 0),
+ inb(ioaddr + 1), inb(ioaddr + 2),
+ inb(ioaddr + 3), inb(ioaddr + 4),
inb(ioaddr + 5),
inb(ioaddr + 6), inb(ioaddr + 7));
@@ -1071,31 +1071,31 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
buf = skb->data;
netif_stop_queue(dev);
-
+
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
+
/* We would be better doing the disable_irq tricks the 3c509 does,
that would make this suck a lot less */
-
+
spin_lock_irqsave(&lp->lock, flags);
if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
- }
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+ }
else {
outw(length, ioaddr + DATAPORT);
- if( ioaddr < 0x1000 )
+ if( ioaddr < 0x1000 )
outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
else {
unsigned char frag = length % 4;
outsl(ioaddr + DATAPORT, buf, length >> 2);
if( frag != 0 ) {
outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT,
+ if( frag == 3 )
+ outsw(ioaddr + DATAPORT,
(buf + (length & 0xFFFC) + 2), 1);
}
}
@@ -1119,9 +1119,9 @@ static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
/* There is still more room for one more packet in tx buffer */
netif_wake_queue(dev);
}
-
+
spin_unlock_irqrestore(&lp->lock, flags);
-
+
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
/* Turn TX interrupts back on */
/* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
@@ -1139,36 +1139,36 @@ static void eth16i_rx(struct net_device *dev)
/* Loop until all packets have been read */
while( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) {
- /* Read status byte from receive buffer */
+ /* Read status byte from receive buffer */
ushort status = inw(ioaddr + DATAPORT);
/* Get the size of the packet from receive buffer */
ushort pkt_len = inw(ioaddr + DATAPORT);
if(eth16i_debug > 4)
- printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
- dev->name,
+ printk(KERN_DEBUG "%s: Receiving packet mode %02x status %04x.\n",
+ dev->name,
inb(ioaddr + RECEIVE_MODE_REG), status);
-
+
if( !(status & PKT_GOOD) ) {
lp->stats.rx_errors++;
if( (pkt_len < ETH_ZLEN) || (pkt_len > ETH_FRAME_LEN) ) {
lp->stats.rx_length_errors++;
eth16i_reset(dev);
- return;
+ return;
}
- else {
+ else {
eth16i_skip_packet(dev);
lp->stats.rx_dropped++;
- }
+ }
}
else { /* Ok so now we should have a good packet */
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len + 3);
if( skb == NULL ) {
- printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
+ printk(KERN_WARNING "%s: Could'n allocate memory for packet (len %d)\n",
dev->name, pkt_len);
eth16i_skip_packet(dev);
lp->stats.rx_dropped++;
@@ -1177,17 +1177,17 @@ static void eth16i_rx(struct net_device *dev)
skb->dev = dev;
skb_reserve(skb,2);
-
- /*
+
+ /*
Now let's get the packet out of buffer.
size is (pkt_len + 1) >> 1, cause we are now reading words
and it have to be even aligned.
- */
-
- if(ioaddr < 0x1000)
- insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
+ */
+
+ if(ioaddr < 0x1000)
+ insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
(pkt_len + 1) >> 1);
- else {
+ else {
unsigned char *buf = skb_put(skb, pkt_len);
unsigned char frag = pkt_len % 4;
@@ -1207,9 +1207,9 @@ static void eth16i_rx(struct net_device *dev)
if( eth16i_debug > 5 ) {
int i;
- printk(KERN_DEBUG "%s: Received packet of length %d.\n",
+ printk(KERN_DEBUG "%s: Received packet of length %d.\n",
dev->name, pkt_len);
- for(i = 0; i < 14; i++)
+ for(i = 0; i < 14; i++)
printk(KERN_DEBUG " %02x", skb->data[i]);
printk(KERN_DEBUG ".\n");
}
@@ -1255,7 +1255,7 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lp->stats.rx_errors++;
- if(status & (BUS_RD_ERR << 8) )
+ if(status & (BUS_RD_ERR << 8) )
printk(KERN_WARNING "%s: Bus read error.\n",dev->name);
if(status & (SHORT_PKT_ERR << 8) ) lp->stats.rx_length_errors++;
if(status & (ALIGN_ERR << 8) ) lp->stats.rx_frame_errors++;
@@ -1269,14 +1269,14 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if(status & CR_LOST) lp->stats.tx_carrier_errors++;
if(status & TX_JABBER_ERR) lp->stats.tx_window_errors++;
-#if 0
+#if 0
if(status & COLLISION) {
- lp->stats.collisions +=
+ lp->stats.collisions +=
((inb(ioaddr+TRANSMIT_MODE_REG) & 0xF0) >> 4);
}
#endif
if(status & COLLISIONS_16) {
- if(lp->col_16 < MAX_COL_16) {
+ if(lp->col_16 < MAX_COL_16) {
lp->col_16++;
lp->stats.collisions++;
/* Resume transmitting, skip failed packet */
@@ -1293,7 +1293,7 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if(status & TX_DONE) { /* The transmit has been done */
lp->stats.tx_packets = lp->tx_buffered_packets;
lp->stats.tx_bytes += lp->tx_buffered_bytes;
- lp->col_16 = 0;
+ lp->col_16 = 0;
if(lp->tx_queue) { /* Is there still packets ? */
/* There was packet(s) so start transmitting and write also
@@ -1310,26 +1310,26 @@ static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
- if( ( status & 0x8000 ) ||
+ if( ( status & 0x8000 ) ||
( (inb(ioaddr + RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) == 0) ) {
eth16i_rx(dev); /* We have packet in receive buffer */
- }
-
+ }
+
/* Turn interrupts back on */
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+
if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
/* There is still more room for one more packet in tx buffer */
netif_wake_queue(dev);
}
-
+
spin_unlock(&lp->lock);
-
+
return IRQ_RETVAL(handled);
}
static void eth16i_skip_packet(struct net_device *dev)
-{
+{
int ioaddr = dev->base_addr;
inw(ioaddr + DATAPORT);
@@ -1345,28 +1345,28 @@ static void eth16i_reset(struct net_device *dev)
struct eth16i_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
- if(eth16i_debug > 1)
+ if(eth16i_debug > 1)
printk(KERN_DEBUG "%s: Resetting device.\n", dev->name);
BITSET(ioaddr + CONFIG_REG_0, DLC_EN);
- outw(0xffff, ioaddr + TX_STATUS_REG);
+ outw(0xffff, ioaddr + TX_STATUS_REG);
eth16i_select_regbank(2, ioaddr);
lp->tx_started = 0;
lp->tx_buf_busy = 0;
lp->tx_queue = 0;
- lp->tx_queue_len = 0;
+ lp->tx_queue_len = 0;
BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
}
static void eth16i_multicast(struct net_device *dev)
{
int ioaddr = dev->base_addr;
-
- if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
+
+ if(dev->mc_count || dev->flags&(IFF_ALLMULTI|IFF_PROMISC))
{
dev->flags|=IFF_PROMISC; /* Must do this */
- outb(3, ioaddr + RECEIVE_MODE_REG);
+ outb(3, ioaddr + RECEIVE_MODE_REG);
} else {
outb(2, ioaddr + RECEIVE_MODE_REG);
}
@@ -1383,7 +1383,7 @@ static void eth16i_select_regbank(unsigned char banknbr, int ioaddr)
unsigned char data;
data = inb(ioaddr + CONFIG_REG_1);
- outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
+ outb( ((data & 0xF3) | ( (banknbr & 0x03) << 2)), ioaddr + CONFIG_REG_1);
}
#ifdef MODULE
@@ -1392,7 +1392,7 @@ static ushort eth16i_parse_mediatype(const char* s)
{
if(!s)
return E_PORT_FROM_EPROM;
-
+
if (!strncmp(s, "bnc", 3))
return E_PORT_BNC;
else if (!strncmp(s, "tp", 2))
@@ -1434,7 +1434,7 @@ MODULE_PARM_DESC(mediatype, "eth16i media type of interface(s) (bnc,tp,dix,auto,
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "eth16i debug level (0-6)");
-int init_module(void)
+int __init init_module(void)
{
int this_dev, found = 0;
struct net_device *dev;
@@ -1474,14 +1474,14 @@ int init_module(void)
return 0;
return -ENXIO;
}
-
+
void cleanup_module(void)
{
int this_dev;
for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) {
struct net_device *dev = dev_eth16i[this_dev];
-
+
if(dev->priv) {
unregister_netdev(dev);
free_irq(dev->irq, dev);
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index b987f947473..75a43f7c70c 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -305,8 +305,8 @@ static int ewrk3_close(struct net_device *dev);
static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops ethtool_ops_203;
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops_203;
+static const struct ethtool_ops ethtool_ops;
/*
** Private functions
@@ -359,13 +359,13 @@ struct net_device * __init ewrk3_probe(int unit)
SET_MODULE_OWNER(dev);
err = ewrk3_probe1(dev, dev->base_addr, dev->irq);
- if (err)
+ if (err)
goto out;
return dev;
out:
free_netdev(dev);
return ERR_PTR(err);
-
+
}
#endif
@@ -378,7 +378,7 @@ static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq)
/* Address PROM pattern */
err = isa_probe(dev, iobase);
- if (err != 0)
+ if (err != 0)
err = eisa_probe(dev, iobase);
if (err)
@@ -391,7 +391,7 @@ static int __init ewrk3_probe1(struct net_device *dev, u_long iobase, int irq)
return err;
}
-static int __init
+static int __init
ewrk3_hw_init(struct net_device *dev, u_long iobase)
{
struct ewrk3_private *lp;
@@ -435,19 +435,19 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
printk("%s: Device has a bad on-board EEPROM.\n", dev->name);
return -ENXIO;
}
-
+
EthwrkSignature(name, eeprom_image);
- if (*name == '\0')
+ if (*name == '\0')
return -ENXIO;
dev->base_addr = iobase;
-
+
if (iobase > 0x400) {
outb(eisa_cr, EISA_CR); /* Rewrite the EISA CR */
}
lemac = eeprom_image[EEPROM_CHIPVER];
cmr = inb(EWRK3_CMR);
-
+
if (((lemac == LeMAC) && ((cmr & CMR_NO_EEPROM) != CMR_NO_EEPROM)) ||
((lemac == LeMAC2) && !(cmr & CMR_HS))) {
printk("%s: %s at %#4lx", dev->name, name, iobase);
@@ -468,7 +468,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
printk("%2.2x:", dev->dev_addr[i]);
}
printk("%2.2x,\n", dev->dev_addr[i]);
-
+
if (status) {
printk(" which has an EEPROM CRC error.\n");
return -ENXIO;
@@ -490,7 +490,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
if (eeprom_image[EEPROM_SETUP] & SETUP_DRAM)
cmr |= CMR_DRAM;
outb(cmr, EWRK3_CMR);
-
+
cr = inb(EWRK3_CR); /* Set up the Control Register */
cr |= eeprom_image[EEPROM_SETUP] & SETUP_APD;
if (cr & SETUP_APD)
@@ -524,7 +524,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
** uncommenting this line.
*/
/* FORCE_2K_MODE; */
-
+
if (hard_strapped) {
printk(" is hard strapped.\n");
} else if (mem_start) {
@@ -544,44 +544,44 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
lp->hard_strapped = hard_strapped;
lp->led_mask = CR_LED;
spin_lock_init(&lp->hw_lock);
-
+
lp->mPage = 64;
if (cmr & CMR_DRAM)
lp->mPage <<= 1; /* 2 DRAMS on module */
-
+
sprintf(lp->adapter_name, "%s (%s)", name, dev->name);
-
+
lp->irq_mask = ICR_TNEM | ICR_TXDM | ICR_RNEM | ICR_RXDM;
-
+
if (!hard_strapped) {
/*
** Enable EWRK3 board interrupts for autoprobing
*/
icr |= ICR_IE; /* Enable interrupts */
outb(icr, EWRK3_ICR);
-
+
/* The DMA channel may be passed in on this parameter. */
dev->dma = 0;
-
+
/* To auto-IRQ we enable the initialization-done and DMA err,
interrupts. For now we will always get a DMA error. */
if (dev->irq < 2) {
#ifndef MODULE
u_char irqnum;
unsigned long irq_mask;
-
+
irq_mask = probe_irq_on();
-
+
/*
** Trigger a TNE interrupt.
*/
icr |= ICR_TNEM;
outb(1, EWRK3_TDQ); /* Write to the TX done queue */
outb(icr, EWRK3_ICR); /* Unmask the TXD interrupt */
-
+
irqnum = irq[((icr & IRQ_SEL) >> 4)];
-
+
mdelay(20);
dev->irq = probe_irq_off(irq_mask);
if ((dev->irq) && (irqnum == dev->irq)) {
@@ -622,12 +622,12 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase)
SET_ETHTOOL_OPS(dev, &ethtool_ops);
dev->tx_timeout = ewrk3_timeout;
dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
-
+
dev->mem_start = 0;
return 0;
}
-
+
static int ewrk3_open(struct net_device *dev)
{
@@ -732,14 +732,14 @@ static void ewrk3_init(struct net_device *dev)
/*
* Transmit timeout
*/
-
+
static void ewrk3_timeout(struct net_device *dev)
{
struct ewrk3_private *lp = netdev_priv(dev);
u_char icr, csr;
u_long iobase = dev->base_addr;
-
- if (!lp->hard_strapped)
+
+ if (!lp->hard_strapped)
{
printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
dev->name, inb(EWRK3_CSR));
@@ -1108,7 +1108,7 @@ static int ewrk3_close(struct net_device *dev)
u_char icr, csr;
netif_stop_queue(dev);
-
+
if (ewrk3_debug > 1) {
printk("%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inb(EWRK3_CSR));
@@ -1666,14 +1666,14 @@ static int ewrk3_phys_id(struct net_device *dev, u32 data)
return signal_pending(current) ? -ERESTARTSYS : 0;
}
-static struct ethtool_ops ethtool_ops_203 = {
+static const struct ethtool_ops ethtool_ops_203 = {
.get_drvinfo = ewrk3_get_drvinfo,
.get_settings = ewrk3_get_settings,
.set_settings = ewrk3_set_settings,
.phys_id = ewrk3_phys_id,
};
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = ewrk3_get_drvinfo,
.get_settings = ewrk3_get_settings,
.set_settings = ewrk3_set_settings,
@@ -1697,7 +1697,7 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
u_char addr[HASH_TABLE_LEN * ETH_ALEN];
u_short val[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
};
-
+
union ewrk3_addr *tmp;
/* All we handle are private IOCTLs */
@@ -1717,7 +1717,7 @@ static int ewrk3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (copy_to_user(ioc->data, tmp->addr, ioc->len))
status = -EFAULT;
break;
-
+
case EWRK3_SET_HWADDR: /* Set the hardware address */
if (capable(CAP_NET_ADMIN)) {
spin_lock_irqsave(&lp->hw_lock, flags);
@@ -1990,7 +1990,7 @@ module_init(ewrk3_init_module);
#endif /* MODULE */
MODULE_LICENSE("GPL");
-
+
/*
* Local variables:
diff --git a/drivers/net/ewrk3.h b/drivers/net/ewrk3.h
index fb74bd05367..8e0ee906567 100644
--- a/drivers/net/ewrk3.h
+++ b/drivers/net/ewrk3.h
@@ -63,7 +63,7 @@
*/
#define CSR_RA 0x80 /* Runt Accept */
#define CSR_PME 0x40 /* Promiscuous Mode Enable */
-#define CSR_MCE 0x20 /* Multicast Enable */
+#define CSR_MCE 0x20 /* Multicast Enable */
#define CSR_TNE 0x08 /* TX Done Queue Not Empty */
#define CSR_RNE 0x04 /* RX Queue Not Empty */
#define CSR_TXD 0x02 /* TX Disable */
@@ -127,7 +127,7 @@
#define CMR_DRAM 0x02 /* 0-> 1DRAM, 1-> 2 DRAM on board */
#define CMR_0WS 0x01 /* Zero Wait State */
-/*
+/*
** MAC Receive Status Register bit definitions
*/
@@ -138,7 +138,7 @@
#define R_CRC 0x02 /* CRC error */
#define R_PLL 0x01 /* Phase Lock Lost */
-/*
+/*
** MAC Transmit Control Register bit definitions
*/
@@ -150,7 +150,7 @@
#define TCR_IFC 0x02 /* Insert Frame Check */
#define TCR_ISA 0x01 /* Insert Source Address */
-/*
+/*
** MAC Transmit Status Register bit definitions
*/
@@ -168,15 +168,15 @@
#define T_XUR 0x03 /* Excessive Underruns */
#define T_TXE 0x7f /* TX Errors */
-/*
-** EISA Configuration Register bit definitions
+/*
+** EISA Configuration Register bit definitions
*/
-#define EISA_ID iobase + 0x0c80 /* EISA ID Registers */
-#define EISA_ID0 iobase + 0x0c80 /* EISA ID Register 0 */
-#define EISA_ID1 iobase + 0x0c81 /* EISA ID Register 1 */
-#define EISA_ID2 iobase + 0x0c82 /* EISA ID Register 2 */
-#define EISA_ID3 iobase + 0x0c83 /* EISA ID Register 3 */
+#define EISA_ID iobase + 0x0c80 /* EISA ID Registers */
+#define EISA_ID0 iobase + 0x0c80 /* EISA ID Register 0 */
+#define EISA_ID1 iobase + 0x0c81 /* EISA ID Register 1 */
+#define EISA_ID2 iobase + 0x0c82 /* EISA ID Register 2 */
+#define EISA_ID3 iobase + 0x0c83 /* EISA ID Register 3 */
#define EISA_CR iobase + 0x0c84 /* EISA Control Register */
/*
@@ -223,7 +223,7 @@
/*
** EEPROM MISCELLANEOUS FLAGS
*/
-#define RBE_SHADOW 0x0100 /* Remote Boot Enable Shadow */
+#define RBE_SHADOW 0x0100 /* Remote Boot Enable Shadow */
#define READ_AHEAD 0x0080 /* Read Ahead feature */
#define IRQ_SEL2 0x0070 /* IRQ line selection (LeMAC2) */
#define IRQ_SEL 0x0060 /* IRQ line selection */
@@ -242,7 +242,7 @@
/*
** EEPROM SW FLAGS
*/
-#define SW_SQE 0x10 /* Signal Quality Error */
+#define SW_SQE 0x10 /* Signal Quality Error */
#define SW_LAB 0x08 /* Less Aggressive Backoff */
#define SW_INIT 0x04 /* Initialized */
#define SW_TIMEOUT 0x02 /* 0:2.5 mins, 1: 30 secs */
@@ -299,8 +299,8 @@ struct ewrk3_ioctl {
unsigned char __user *data; /* Pointer to the data buffer */
};
-/*
-** Recognised commands for the driver
+/*
+** Recognised commands for the driver
*/
#define EWRK3_GET_HWADDR 0x01 /* Get the hardware address */
#define EWRK3_SET_HWADDR 0x02 /* Get the hardware address */
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index a8449265e5f..191bd429076 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -25,8 +25,8 @@
*/
#define DRV_NAME "fealnx"
-#define DRV_VERSION "2.51"
-#define DRV_RELDATE "Nov-17-2001"
+#define DRV_VERSION "2.52"
+#define DRV_RELDATE "Sep-11-2006"
static int debug; /* 1-> print debug message */
static int max_interrupt_work = 20;
@@ -92,7 +92,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
#include <asm/uaccess.h>
/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static char version[] =
KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n";
@@ -124,16 +124,8 @@ MODULE_PARM_DESC(multicast_filter_limit, "fealnx maximum number of filtered mult
MODULE_PARM_DESC(options, "fealnx: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "fealnx full duplex setting(s) (1)");
-#define MIN_REGION_SIZE 136
-
-enum pci_flags_bit {
- PCI_USES_IO = 1,
- PCI_USES_MEM = 2,
- PCI_USES_MASTER = 4,
- PCI_ADDR0 = 0x10 << 0,
- PCI_ADDR1 = 0x10 << 1,
- PCI_ADDR2 = 0x10 << 2,
- PCI_ADDR3 = 0x10 << 3,
+enum {
+ MIN_REGION_SIZE = 136,
};
/* A chip capabilities table, matching the entries in pci_tbl[] above. */
@@ -156,14 +148,13 @@ enum phy_type_flags {
struct chip_info {
char *chip_name;
- int io_size;
int flags;
};
-static const struct chip_info skel_netdrv_tbl[] = {
- {"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
- {"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR},
- {"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR},
+static const struct chip_info skel_netdrv_tbl[] __devinitdata = {
+ { "100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
+ { "100/10M Ethernet PCI Adapter", HAS_CHIP_XCVR },
+ { "1000/100/10M Ethernet PCI Adapter", HAS_MII_XCVR },
};
/* Offsets to the Command and Status Registers. */
@@ -449,7 +440,7 @@ static void set_rx_mode(struct net_device *dev);
static void __set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static int netdev_close(struct net_device *dev);
static void reset_rx_descriptors(struct net_device *dev);
static void reset_tx_descriptors(struct net_device *dev);
@@ -495,33 +486,34 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
#else
int bar = 1;
#endif
-
+
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
static int printed_version;
if (!printed_version++)
printk(version);
#endif
-
+
card_idx++;
sprintf(boardname, "fealnx%d", card_idx);
-
+
option = card_idx < MAX_UNITS ? options[card_idx] : 0;
i = pci_enable_device(pdev);
if (i) return i;
pci_set_master(pdev);
-
+
len = pci_resource_len(pdev, bar);
if (len < MIN_REGION_SIZE) {
- printk(KERN_ERR "%s: region size %ld too small, aborting\n",
- boardname, len);
+ dev_err(&pdev->dev,
+ "region size %ld too small, aborting\n", len);
return -ENODEV;
}
i = pci_request_regions(pdev, boardname);
- if (i) return i;
-
+ if (i)
+ return i;
+
irq = pdev->irq;
ioaddr = pci_iomap(pdev, bar, len);
@@ -586,9 +578,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
if (mii_status != 0xffff && mii_status != 0x0000) {
np->phys[phy_idx++] = phy;
- printk(KERN_INFO
- "%s: MII PHY found at address %d, status "
- "0x%4.4x.\n", dev->name, phy, mii_status);
+ dev_info(&pdev->dev,
+ "MII PHY found at address %d, status "
+ "0x%4.4x.\n", phy, mii_status);
/* get phy type */
{
unsigned int data;
@@ -611,10 +603,10 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
}
np->mii_cnt = phy_idx;
- if (phy_idx == 0) {
- printk(KERN_WARNING "%s: MII PHY not found -- this device may "
- "not operate correctly.\n", dev->name);
- }
+ if (phy_idx == 0)
+ dev_warn(&pdev->dev,
+ "MII PHY not found -- this device may "
+ "not operate correctly.\n");
} else {
np->phys[0] = 32;
/* 89/6/23 add, (begin) */
@@ -640,7 +632,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
np->mii.full_duplex = full_duplex[card_idx];
if (np->mii.full_duplex) {
- printk(KERN_INFO "%s: Media type forced to Full Duplex.\n", dev->name);
+ dev_info(&pdev->dev, "Media type forced to Full Duplex.\n");
/* 89/6/13 add, (begin) */
// if (np->PHYType==MarvellPHY)
if ((np->PHYType == MarvellPHY) || (np->PHYType == LevelOnePHY)) {
@@ -668,7 +660,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
dev->ethtool_ops = &netdev_ethtool_ops;
dev->tx_timeout = &tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
-
+
err = register_netdev(dev);
if (err)
goto err_out_free_tx;
@@ -844,7 +836,7 @@ static int netdev_open(struct net_device *dev)
iowrite32(0x00000001, ioaddr + BCR); /* Reset */
- if (request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev))
return -EAGAIN;
for (i = 0; i < 3; i++)
@@ -873,25 +865,25 @@ static int netdev_open(struct net_device *dev)
Tx and Rx queues and the address filter list.
FIXME (Ueimor): optimistic for alpha + posted writes ? */
#if defined(__powerpc__) || defined(__sparc__)
-// 89/9/1 modify,
+// 89/9/1 modify,
// np->bcrvalue=0x04 | 0x0x38; /* big-endian, 256 burst length */
np->bcrvalue = 0x04 | 0x10; /* big-endian, tx 8 burst length */
np->crvalue = 0xe00; /* rx 128 burst length */
#elif defined(__alpha__) || defined(__x86_64__)
-// 89/9/1 modify,
+// 89/9/1 modify,
// np->bcrvalue=0x38; /* little-endian, 256 burst length */
np->bcrvalue = 0x10; /* little-endian, 8 burst length */
np->crvalue = 0xe00; /* rx 128 burst length */
#elif defined(__i386__)
#if defined(MODULE)
-// 89/9/1 modify,
+// 89/9/1 modify,
// np->bcrvalue=0x38; /* little-endian, 256 burst length */
np->bcrvalue = 0x10; /* little-endian, 8 burst length */
np->crvalue = 0xe00; /* rx 128 burst length */
#else
/* When not a module we can work around broken '486 PCI boards. */
#define x86 boot_cpu_data.x86
-// 89/9/1 modify,
+// 89/9/1 modify,
// np->bcrvalue=(x86 <= 4 ? 0x10 : 0x38);
np->bcrvalue = 0x10;
np->crvalue = (x86 <= 4 ? 0xa00 : 0xe00);
@@ -1168,7 +1160,7 @@ static void reset_and_disable_rxtx(struct net_device *dev)
/* Reset the chip to erase previous misconfiguration. */
iowrite32(0x00000001, ioaddr + BCR);
- /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
+ /* Ueimor: wait for 50 PCI cycles (and flush posted writes btw).
We surely wait too long (address+data phase). Who cares? */
while (--delay) {
ioread32(ioaddr + BCR);
@@ -1221,7 +1213,7 @@ static void reset_timer(unsigned long data)
reset_tx_descriptors(dev); */
enable_rxtx(dev);
netif_start_queue(dev); /* FIXME: or netif_wake_queue(dev); ? */
-
+
np->reset_timer_armed = 0;
spin_unlock_irqrestore(&np->lock, flags);
@@ -1247,7 +1239,7 @@ static void tx_timeout(struct net_device *dev)
printk(" %4.4x", np->tx_ring[i].status);
printk("\n");
}
-
+
spin_lock_irqsave(&np->lock, flags);
reset_and_disable_rxtx(dev);
@@ -1517,7 +1509,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
stop_nic_rx(ioaddr, np->crvalue);
reset_rx_descriptors(dev);
iowrite32(np->crvalue, ioaddr + TCRRCR);
- }
+ }
}
while (np->really_tx_count) {
@@ -1579,7 +1571,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
}
num_tx++;
} /* end of for loop */
-
+
if (num_tx && np->free_tx_count >= 2)
netif_wake_queue(dev);
@@ -1736,7 +1728,7 @@ static int netdev_rx(struct net_device *dev)
/* Call copy + cksum if available. */
#if ! defined(__alpha__)
- eth_copy_and_sum(skb,
+ eth_copy_and_sum(skb,
np->cur_rx->skbuff->data, pkt_len, 0);
skb_put(skb, pkt_len);
#else
@@ -1808,8 +1800,6 @@ static void __set_rx_mode(struct net_device *dev)
u32 rx_mode;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = CR_W_PROM | CR_W_AB | CR_W_AM;
} else if ((dev->mc_count > multicast_filter_limit)
@@ -1895,7 +1885,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value)
debug = value;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.set_settings = netdev_set_settings,
@@ -1992,7 +1982,7 @@ static int __init fealnx_init(void)
printk(version);
#endif
- return pci_module_init(&fealnx_driver);
+ return pci_register_driver(&fealnx_driver);
}
static void __exit fealnx_exit(void)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index bd6983d1afb..55d86bc4c10 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -22,10 +22,9 @@
* Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com)
*
* Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
- * Copyright (c) 2004-2005 Macq Electronique SA.
+ * Copyright (c) 2004-2006 Macq Electronique SA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -51,7 +50,7 @@
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x)
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
#include "fec.h"
@@ -80,6 +79,8 @@ static unsigned int fec_hw[] = {
(MCF_MBAR + 0x1000),
#elif defined(CONFIG_M520x)
(MCF_MBAR+0x30000),
+#elif defined(CONFIG_M532x)
+ (MCF_MBAR+0xfc030000),
#else
&(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
#endif
@@ -143,7 +144,7 @@ typedef struct {
#define TX_RING_MOD_MASK 15 /* for this to work */
#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
-#error "FEC: descriptor ring size contants too large"
+#error "FEC: descriptor ring size constants too large"
#endif
/* Interrupt events/masks.
@@ -167,12 +168,12 @@ typedef struct {
/*
- * The 5270/5271/5280/5282 RX control register also contains maximum frame
+ * The 5270/5271/5280/5282/532x RX control register also contains maximum frame
* size bits. Other FEC hardware does not, so we need to take that into
* account when setting it.
*/
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x)
#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16)
#else
#define OPT_FRAME_SIZE 0
@@ -255,7 +256,7 @@ static mii_list_t *mii_free;
static mii_list_t *mii_head;
static mii_list_t *mii_tail;
-static int mii_queue(struct net_device *dev, int request,
+static int mii_queue(struct net_device *dev, int request,
void (*func)(uint, struct net_device *));
/* Make MII read/write commands for the FEC.
@@ -276,7 +277,7 @@ static int mii_queue(struct net_device *dev, int request,
#define MII_REG_SR 1 /* Status Register */
#define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */
#define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */
-#define MII_REG_ANAR 4 /* A-N Advertisement Register */
+#define MII_REG_ANAR 4 /* A-N Advertisement Register */
#define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */
#define MII_REG_ANER 6 /* A-N Expansion Register */
#define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */
@@ -288,18 +289,18 @@ static int mii_queue(struct net_device *dev, int request,
#define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */
#define PHY_CONF_SPMASK 0x00f0 /* mask for speed */
#define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */
-#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */
+#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */
#define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */
-#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */
+#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */
#define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */
#define PHY_STAT_FAULT 0x0200 /* 1 remote fault */
#define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */
#define PHY_STAT_SPMASK 0xf000 /* mask for speed */
#define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */
-#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */
+#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */
#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */
-#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */
+#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */
static int
@@ -308,6 +309,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct fec_enet_private *fep;
volatile fec_t *fecp;
volatile cbd_t *bdp;
+ unsigned short status;
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
@@ -320,8 +322,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
+ status = bdp->cbd_sc;
#ifndef final_version
- if (bdp->cbd_sc & BD_ENET_TX_READY) {
+ if (status & BD_ENET_TX_READY) {
/* Ooops. All transmit buffers are full. Bail out.
* This should not happen, since dev->tbusy should be set.
*/
@@ -332,7 +335,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Clear all of the status flags.
*/
- bdp->cbd_sc &= ~BD_ENET_TX_STATS;
+ status &= ~BD_ENET_TX_STATS;
/* Set buffer length and buffer pointer.
*/
@@ -357,7 +360,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
fep->stats.tx_bytes += skb->len;
fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
-
+
/* Push the data cache so the CPM does not get stale memory
* data.
*/
@@ -366,21 +369,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&fep->lock);
- /* Send it on its way. Tell FEC its ready, interrupt when done,
- * its the last BD of the frame, and to put the CRC on the end.
+ /* Send it on its way. Tell FEC it's ready, interrupt when done,
+ * it's the last BD of the frame, and to put the CRC on the end.
*/
- bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+ status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
| BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ bdp->cbd_sc = status;
dev->trans_start = jiffies;
/* Trigger transmission start */
- fecp->fec_x_des_active = 0x01000000;
+ fecp->fec_x_des_active = 0;
/* If this was the last BD in the ring, start at the beginning again.
*/
- if (bdp->cbd_sc & BD_ENET_TX_WRAP) {
+ if (status & BD_ENET_TX_WRAP) {
bdp = fep->tx_bd_base;
} else {
bdp++;
@@ -418,7 +422,7 @@ fec_timeout(struct net_device *dev)
bdp = fep->tx_bd_base;
printk(" tx: %u buffers\n", TX_RING_SIZE);
for (i = 0 ; i < TX_RING_SIZE; i++) {
- printk(" %08x: %04x %04x %08x\n",
+ printk(" %08x: %04x %04x %08x\n",
(uint) bdp,
bdp->cbd_sc,
bdp->cbd_datlen,
@@ -480,7 +484,7 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
handled = 1;
fec_enet_mii(dev);
}
-
+
}
return IRQ_RETVAL(handled);
}
@@ -491,58 +495,59 @@ fec_enet_tx(struct net_device *dev)
{
struct fec_enet_private *fep;
volatile cbd_t *bdp;
+ unsigned short status;
struct sk_buff *skb;
fep = netdev_priv(dev);
spin_lock(&fep->lock);
bdp = fep->dirty_tx;
- while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) {
+ while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
if (bdp == fep->cur_tx && fep->tx_full == 0) break;
skb = fep->tx_skbuff[fep->skb_dirty];
/* Check for errors. */
- if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN |
BD_ENET_TX_CSL)) {
fep->stats.tx_errors++;
- if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */
+ if (status & BD_ENET_TX_HB) /* No heartbeat */
fep->stats.tx_heartbeat_errors++;
- if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */
+ if (status & BD_ENET_TX_LC) /* Late collision */
fep->stats.tx_window_errors++;
- if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */
+ if (status & BD_ENET_TX_RL) /* Retrans limit */
fep->stats.tx_aborted_errors++;
- if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */
+ if (status & BD_ENET_TX_UN) /* Underrun */
fep->stats.tx_fifo_errors++;
- if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+ if (status & BD_ENET_TX_CSL) /* Carrier lost */
fep->stats.tx_carrier_errors++;
} else {
fep->stats.tx_packets++;
}
#ifndef final_version
- if (bdp->cbd_sc & BD_ENET_TX_READY)
+ if (status & BD_ENET_TX_READY)
printk("HEY! Enet xmit interrupt and TX_READY.\n");
#endif
/* Deferred means some collisions occurred during transmit,
* but we eventually sent the packet OK.
*/
- if (bdp->cbd_sc & BD_ENET_TX_DEF)
+ if (status & BD_ENET_TX_DEF)
fep->stats.collisions++;
-
+
/* Free the sk buffer associated with this last transmit.
*/
dev_kfree_skb_any(skb);
fep->tx_skbuff[fep->skb_dirty] = NULL;
fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
-
+
/* Update pointer to next buffer descriptor to be transmitted.
*/
- if (bdp->cbd_sc & BD_ENET_TX_WRAP)
+ if (status & BD_ENET_TX_WRAP)
bdp = fep->tx_bd_base;
else
bdp++;
-
+
/* Since we have freed up a buffer, the ring is no longer
* full.
*/
@@ -568,10 +573,15 @@ fec_enet_rx(struct net_device *dev)
struct fec_enet_private *fep;
volatile fec_t *fecp;
volatile cbd_t *bdp;
+ unsigned short status;
struct sk_buff *skb;
ushort pkt_len;
__u8 *data;
+#ifdef CONFIG_M532x
+ flush_cache_all();
+#endif
+
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
@@ -580,13 +590,13 @@ fec_enet_rx(struct net_device *dev)
*/
bdp = fep->cur_rx;
-while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
+while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
#ifndef final_version
/* Since we have allocated space to hold a complete frame,
* the last indicator should be set.
*/
- if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0)
+ if ((status & BD_ENET_RX_LAST) == 0)
printk("FEC ENET: rcv is not +last\n");
#endif
@@ -594,26 +604,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
goto rx_processing_done;
/* Check for errors. */
- if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
BD_ENET_RX_CR | BD_ENET_RX_OV)) {
- fep->stats.rx_errors++;
- if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+ fep->stats.rx_errors++;
+ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
/* Frame too long or too short. */
fep->stats.rx_length_errors++;
}
- if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */
+ if (status & BD_ENET_RX_NO) /* Frame alignment */
fep->stats.rx_frame_errors++;
- if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */
- fep->stats.rx_crc_errors++;
- if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */
+ if (status & BD_ENET_RX_CR) /* CRC Error */
fep->stats.rx_crc_errors++;
+ if (status & BD_ENET_RX_OV) /* FIFO overrun */
+ fep->stats.rx_fifo_errors++;
}
/* Report late collisions as a frame error.
* On this error, the BD is closed, but we don't know what we
* have in the buffer. So, just drop this frame on the floor.
*/
- if (bdp->cbd_sc & BD_ENET_RX_CL) {
+ if (status & BD_ENET_RX_CL) {
fep->stats.rx_errors++;
fep->stats.rx_frame_errors++;
goto rx_processing_done;
@@ -639,9 +649,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
} else {
skb->dev = dev;
skb_put(skb,pkt_len-4); /* Make room */
- eth_copy_and_sum(skb,
- (unsigned char *)__va(bdp->cbd_bufaddr),
- pkt_len-4, 0);
+ eth_copy_and_sum(skb, data, pkt_len-4, 0);
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
}
@@ -649,27 +657,28 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
/* Clear the status flags for this buffer.
*/
- bdp->cbd_sc &= ~BD_ENET_RX_STATS;
+ status &= ~BD_ENET_RX_STATS;
/* Mark the buffer empty.
*/
- bdp->cbd_sc |= BD_ENET_RX_EMPTY;
+ status |= BD_ENET_RX_EMPTY;
+ bdp->cbd_sc = status;
/* Update BD pointer to next entry.
*/
- if (bdp->cbd_sc & BD_ENET_RX_WRAP)
+ if (status & BD_ENET_RX_WRAP)
bdp = fep->rx_bd_base;
else
bdp++;
-
+
#if 1
/* Doing this here will keep the FEC running while we process
* incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources.
*/
- fecp->fec_r_des_active = 0x01000000;
+ fecp->fec_r_des_active = 0;
#endif
- } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */
+ } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
fep->cur_rx = (cbd_t *)bdp;
#if 0
@@ -680,11 +689,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
* our way back to the interrupt return only to come right back
* here.
*/
- fecp->fec_r_des_active = 0x01000000;
+ fecp->fec_r_des_active = 0;
#endif
}
+/* called from interrupt context */
static void
fec_enet_mii(struct net_device *dev)
{
@@ -696,10 +706,12 @@ fec_enet_mii(struct net_device *dev)
fep = netdev_priv(dev);
ep = fep->hwp;
mii_reg = ep->fec_mii_data;
-
+
+ spin_lock(&fep->lock);
+
if ((mip = mii_head) == NULL) {
printk("MII and no head!\n");
- return;
+ goto unlock;
}
if (mip->mii_func != NULL)
@@ -711,6 +723,9 @@ fec_enet_mii(struct net_device *dev)
if ((mip = mii_head) != NULL)
ep->fec_mii_data = mip->mii_regval;
+
+unlock:
+ spin_unlock(&fep->lock);
}
static int
@@ -728,8 +743,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
retval = 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&fep->lock,flags);
if ((mip = mii_free) != NULL) {
mii_free = mip->mii_next;
@@ -749,7 +763,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
retval = 1;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&fep->lock,flags);
return(retval);
}
@@ -872,14 +886,14 @@ static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */
{ mk_mii_end, }
};
static phy_info_t const phy_info_lxt970 = {
- .id = 0x07810000,
+ .id = 0x07810000,
.name = "LXT970",
.config = phy_cmd_lxt970_config,
.startup = phy_cmd_lxt970_startup,
.ack_int = phy_cmd_lxt970_ack_int,
.shutdown = phy_cmd_lxt970_shutdown
};
-
+
/* ------------------------------------------------------------------------- */
/* The Level one LXT971 is used on some of my custom boards */
@@ -892,7 +906,7 @@ static phy_info_t const phy_info_lxt970 = {
#define MII_LXT971_LCR 20 /* LED Control Register */
#define MII_LXT971_TCR 30 /* Transmit Control Register */
-/*
+/*
* I had some nice ideas of running the MDIO faster...
* The 971 should support 8MHz and I tried it, but things acted really
* weird, so 2.5 MHz ought to be enough for anyone...
@@ -930,9 +944,9 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
*s = status;
}
-
+
static phy_cmd_t const phy_cmd_lxt971_config[] = {
- /* limit to 10MBit because my prototype board
+ /* limit to 10MBit because my prototype board
* doesn't work with 100. */
{ mk_mii_read(MII_REG_CR), mii_parse_cr },
{ mk_mii_read(MII_REG_ANAR), mii_parse_anar },
@@ -946,7 +960,7 @@ static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */
/* Somehow does the 971 tell me that the link is down
* the first read after power-up.
* read here to get a valid value in ack_int */
- { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_read(MII_REG_SR), mii_parse_sr },
{ mk_mii_end, }
};
static phy_cmd_t const phy_cmd_lxt971_ack_int[] = {
@@ -962,7 +976,7 @@ static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */
{ mk_mii_end, }
};
static phy_info_t const phy_info_lxt971 = {
- .id = 0x0001378e,
+ .id = 0x0001378e,
.name = "LXT971",
.config = phy_cmd_lxt971_config,
.startup = phy_cmd_lxt971_startup,
@@ -1001,7 +1015,7 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
}
static phy_cmd_t const phy_cmd_qs6612_config[] = {
- /* The PHY powers up isolated on the RPX,
+ /* The PHY powers up isolated on the RPX,
* so send a command to allow operation.
*/
{ mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL },
@@ -1031,7 +1045,7 @@ static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */
{ mk_mii_end, }
};
static phy_info_t const phy_info_qs6612 = {
- .id = 0x00181440,
+ .id = 0x00181440,
.name = "QS6612",
.config = phy_cmd_qs6612_config,
.startup = phy_cmd_qs6612_startup,
@@ -1079,7 +1093,7 @@ static phy_cmd_t const phy_cmd_am79c874_config[] = {
static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */
{ mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL },
{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
- { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_read(MII_REG_SR), mii_parse_sr },
{ mk_mii_end, }
};
static phy_cmd_t const phy_cmd_am79c874_ack_int[] = {
@@ -1121,7 +1135,7 @@ static phy_cmd_t const phy_cmd_ks8721bl_config[] = {
static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */
{ mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL },
{ mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
- { mk_mii_read(MII_REG_SR), mii_parse_sr },
+ { mk_mii_read(MII_REG_SR), mii_parse_sr },
{ mk_mii_end, }
};
static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = {
@@ -1136,7 +1150,7 @@ static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */
{ mk_mii_end, }
};
static phy_info_t const phy_info_ks8721bl = {
- .id = 0x00022161,
+ .id = 0x00022161,
.name = "KS8721BL",
.config = phy_cmd_ks8721bl_config,
.startup = phy_cmd_ks8721bl_startup,
@@ -1216,7 +1230,7 @@ static phy_info_t const * const phy_info[] = {
};
/* ------------------------------------------------------------------------- */
-
+#if !defined(CONFIG_M532x)
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id);
@@ -1224,6 +1238,7 @@ mii_link_interrupt(void *dev_id);
static irqreturn_t
mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
#endif
+#endif
#if defined(CONFIG_M5272)
@@ -1384,13 +1399,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
{
volatile unsigned char *icrp;
volatile unsigned long *imrp;
- int i;
+ int i, ilip;
b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
MCFINTC_ICR0);
- for (i = 23; (i < 36); i++)
- icrp[i] = 0x23;
+ for (i = 23, ilip = 0x28; (i < 36); i++)
+ icrp[i] = ilip--;
imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
MCFINTC_IMRH);
@@ -1405,7 +1420,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
{
volatile u16 *gpio_paspar;
volatile u8 *gpio_pehlpar;
-
+
gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
*gpio_paspar |= 0x0f00;
@@ -1618,6 +1633,159 @@ static void __inline__ fec_uncache(unsigned long addr)
/* ------------------------------------------------------------------------- */
+#elif defined(CONFIG_M532x)
+/*
+ * Code specific for M532x
+ */
+static void __inline__ fec_request_intrs(struct net_device *dev)
+{
+ struct fec_enet_private *fep;
+ int b;
+ static const struct idesc {
+ char *name;
+ unsigned short irq;
+ } *idp, id[] = {
+ { "fec(TXF)", 36 },
+ { "fec(TXB)", 37 },
+ { "fec(TXFIFO)", 38 },
+ { "fec(TXCR)", 39 },
+ { "fec(RXF)", 40 },
+ { "fec(RXB)", 41 },
+ { "fec(MII)", 42 },
+ { "fec(LC)", 43 },
+ { "fec(HBERR)", 44 },
+ { "fec(GRA)", 45 },
+ { "fec(EBERR)", 46 },
+ { "fec(BABT)", 47 },
+ { "fec(BABR)", 48 },
+ { NULL },
+ };
+
+ fep = netdev_priv(dev);
+ b = (fep->index) ? 128 : 64;
+
+ /* Setup interrupt handlers. */
+ for (idp = id; idp->name; idp++) {
+ if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0)
+ printk("FEC: Could not allocate %s IRQ(%d)!\n",
+ idp->name, b+idp->irq);
+ }
+
+ /* Unmask interrupts */
+ MCF_INTC0_ICR36 = 0x2;
+ MCF_INTC0_ICR37 = 0x2;
+ MCF_INTC0_ICR38 = 0x2;
+ MCF_INTC0_ICR39 = 0x2;
+ MCF_INTC0_ICR40 = 0x2;
+ MCF_INTC0_ICR41 = 0x2;
+ MCF_INTC0_ICR42 = 0x2;
+ MCF_INTC0_ICR43 = 0x2;
+ MCF_INTC0_ICR44 = 0x2;
+ MCF_INTC0_ICR45 = 0x2;
+ MCF_INTC0_ICR46 = 0x2;
+ MCF_INTC0_ICR47 = 0x2;
+ MCF_INTC0_ICR48 = 0x2;
+
+ MCF_INTC0_IMRH &= ~(
+ MCF_INTC_IMRH_INT_MASK36 |
+ MCF_INTC_IMRH_INT_MASK37 |
+ MCF_INTC_IMRH_INT_MASK38 |
+ MCF_INTC_IMRH_INT_MASK39 |
+ MCF_INTC_IMRH_INT_MASK40 |
+ MCF_INTC_IMRH_INT_MASK41 |
+ MCF_INTC_IMRH_INT_MASK42 |
+ MCF_INTC_IMRH_INT_MASK43 |
+ MCF_INTC_IMRH_INT_MASK44 |
+ MCF_INTC_IMRH_INT_MASK45 |
+ MCF_INTC_IMRH_INT_MASK46 |
+ MCF_INTC_IMRH_INT_MASK47 |
+ MCF_INTC_IMRH_INT_MASK48 );
+
+ /* Set up gpio outputs for MII lines */
+ MCF_GPIO_PAR_FECI2C |= (0 |
+ MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+ MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+ MCF_GPIO_PAR_FEC = (0 |
+ MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+ MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+}
+
+static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
+{
+ volatile fec_t *fecp;
+
+ fecp = fep->hwp;
+ fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+ fecp->fec_x_cntrl = 0x00;
+
+ /*
+ * Set MII speed to 2.5 MHz
+ */
+ fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
+ fecp->fec_mii_speed = fep->phy_speed;
+
+ fec_restart(dev, 0);
+}
+
+static void __inline__ fec_get_mac(struct net_device *dev)
+{
+ struct fec_enet_private *fep = netdev_priv(dev);
+ volatile fec_t *fecp;
+ unsigned char *iap, tmpaddr[ETH_ALEN];
+
+ fecp = fep->hwp;
+
+ if (FEC_FLASHMAC) {
+ /*
+ * Get MAC address from FLASH.
+ * If it is all 1's or 0's, use the default.
+ */
+ iap = FEC_FLASHMAC;
+ if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+ (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+ iap = fec_mac_default;
+ if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+ (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+ iap = fec_mac_default;
+ } else {
+ *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+ *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+ iap = &tmpaddr[0];
+ }
+
+ memcpy(dev->dev_addr, iap, ETH_ALEN);
+
+ /* Adjust MAC if using default MAC address */
+ if (iap == fec_mac_default)
+ dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+}
+
+static void __inline__ fec_enable_phy_intr(void)
+{
+}
+
+static void __inline__ fec_disable_phy_intr(void)
+{
+}
+
+static void __inline__ fec_phy_ack_intr(void)
+{
+}
+
+static void __inline__ fec_localhw_setup(void)
+{
+}
+
+/*
+ * Do not need to make region uncached on 532x.
+ */
+static void __inline__ fec_uncache(unsigned long addr)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+
#else
/*
@@ -1688,10 +1856,10 @@ static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_priva
immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */
else
immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */
-
+
/* Set MII speed to 2.5 MHz
*/
- fecp->fec_mii_speed = fep->phy_speed =
+ fecp->fec_mii_speed = fep->phy_speed =
((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;
}
@@ -1701,7 +1869,7 @@ static void __inline__ fec_enable_phy_intr(void)
fecp = fep->hwp;
- /* Enable MII command finished interrupt
+ /* Enable MII command finished interrupt
*/
fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
}
@@ -1803,7 +1971,7 @@ static void mii_display_config(struct net_device *dev)
if (status & PHY_CONF_LOOP)
printk(", loopback enabled");
-
+
printk(".\n");
fep->sequence_done = 1;
@@ -1825,7 +1993,7 @@ static void mii_relink(struct net_device *dev)
if (fep->link) {
duplex = 0;
- if (fep->phy_status
+ if (fep->phy_status
& (PHY_STAT_100FDX | PHY_STAT_10FDX))
duplex = 1;
fec_restart(dev, duplex);
@@ -1902,7 +2070,7 @@ mii_discover_phy3(uint mii_reg, struct net_device *dev)
printk(" -- %s\n", phy_info[i]->name);
else
printk(" -- unknown PHY!\n");
-
+
fep->phy = phy_info[i];
fep->phy_id_done = 1;
}
@@ -1922,7 +2090,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
if (fep->phy_addr < 32) {
if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {
-
+
/* Got first part of ID, now get remainder.
*/
fep->phy_id = phytype << 16;
@@ -1985,9 +2153,12 @@ fec_enet_open(struct net_device *dev)
mii_do_cmd(dev, fep->phy->config);
mii_do_cmd(dev, phy_cmd_config); /* display configuration */
- /* FIXME: use netif_carrier_{on,off} ; this polls
- * until link is up which is wrong... could be
- * 30 seconds or more we are trapped in here. -jgarzik
+ /* Poll until the PHY tells us its configuration
+ * (not link state).
+ * Request is initiated by mii_do_cmd above, but answer
+ * comes by interrupt.
+ * This should take about 25 usec per register at 2.5 MHz,
+ * and we read approximately 5 registers.
*/
while(!fep->sequence_done)
schedule();
@@ -2056,8 +2227,6 @@ static void set_multicast_list(struct net_device *dev)
ep = fep->hwp;
if (dev->flags&IFF_PROMISC) {
- /* Log any net taps. */
- printk("%s: Promiscuous mode enabled.\n", dev->name);
ep->fec_r_cntrl |= 0x0008;
} else {
@@ -2074,7 +2243,7 @@ static void set_multicast_list(struct net_device *dev)
*/
ep->fec_hash_table_high = 0;
ep->fec_hash_table_low = 0;
-
+
dmi = dev->mc_list;
for (j = 0; j < dev->mc_count; j++, dmi = dmi->next)
@@ -2083,7 +2252,7 @@ static void set_multicast_list(struct net_device *dev)
*/
if (!(dmi->dmi_addr[0] & 1))
continue;
-
+
/* calculate crc32 value of mac address
*/
crc = 0xffffffff;
@@ -2102,7 +2271,7 @@ static void set_multicast_list(struct net_device *dev)
which point to specific bit in he hash registers
*/
hash = (crc >> (32 - HASH_BITS)) & 0x3f;
-
+
if (hash > 31)
ep->fec_hash_table_high |= 1 << (hash - 32);
else
@@ -2253,15 +2422,11 @@ int __init fec_enet_init(struct net_device *dev)
*/
fec_request_intrs(dev);
- /* Clear and enable interrupts */
- fecp->fec_ievent = 0xffc00000;
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
fecp->fec_hash_table_high = 0;
fecp->fec_hash_table_low = 0;
fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
fecp->fec_ecntrl = 2;
- fecp->fec_r_des_active = 0x01000000;
+ fecp->fec_r_des_active = 0;
dev->base_addr = (unsigned long)fecp;
@@ -2281,6 +2446,11 @@ int __init fec_enet_init(struct net_device *dev)
/* setup MII interface */
fec_set_mii(dev, fep);
+ /* Clear and enable interrupts */
+ fecp->fec_ievent = 0xffc00000;
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
+ FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+
/* Queue up command to detect the PHY and initialize the
* remainder of the interface.
*/
@@ -2312,11 +2482,6 @@ fec_restart(struct net_device *dev, int duplex)
fecp->fec_ecntrl = 1;
udelay(10);
- /* Enable interrupts we wish to service.
- */
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
-
/* Clear any outstanding interrupt.
*/
fecp->fec_ievent = 0xffc00000;
@@ -2408,7 +2573,12 @@ fec_restart(struct net_device *dev, int duplex)
/* And last, enable the transmit and receive processing.
*/
fecp->fec_ecntrl = 2;
- fecp->fec_r_des_active = 0x01000000;
+ fecp->fec_r_des_active = 0;
+
+ /* Enable interrupts we wish to service.
+ */
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
+ FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
}
static void
@@ -2420,9 +2590,16 @@ fec_stop(struct net_device *dev)
fep = netdev_priv(dev);
fecp = fep->hwp;
- fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */
-
- while(!(fecp->fec_ievent & FEC_ENET_GRA));
+ /*
+ ** We cannot expect a graceful transmit stop without link !!!
+ */
+ if (fep->link)
+ {
+ fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */
+ udelay(10);
+ if (!(fecp->fec_ievent & FEC_ENET_GRA))
+ printk("fec_stop : Graceful transmit stop did not complete !\n");
+ }
/* Whack a reset. We should wait for this.
*/
diff --git a/drivers/net/fec.h b/drivers/net/fec.h
index 965c5c49fcd..1d421606984 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/fec.h
@@ -14,7 +14,7 @@
/****************************************************************************/
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x)
/*
* Just figures, Motorola would have to change the offsets for
* registers in the same peripheral device on different models
diff --git a/drivers/net/fec_8xx/fec_8xx-netta.c b/drivers/net/fec_8xx/fec_8xx-netta.c
index 29c275e1d56..790d9dbe42d 100644
--- a/drivers/net/fec_8xx/fec_8xx-netta.c
+++ b/drivers/net/fec_8xx/fec_8xx-netta.c
@@ -2,7 +2,6 @@
* FEC instantatiation file for NETTA
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index 7e433809713..e17a1449ee1 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -10,7 +10,6 @@
* Released under the GPL
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -31,6 +30,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
@@ -38,7 +38,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/commproc.h>
-#include <asm/dma-mapping.h>
#include "fec_8xx.h"
@@ -1035,20 +1034,20 @@ static void fec_set_msglevel(struct net_device *dev, __u32 value)
fep->msg_enable = value;
}
-static struct ethtool_ops fec_ethtool_ops = {
- .get_drvinfo = fec_get_drvinfo,
- .get_regs_len = fec_get_regs_len,
- .get_settings = fec_get_settings,
- .set_settings = fec_set_settings,
- .nway_reset = fec_nway_reset,
- .get_link = ethtool_op_get_link,
- .get_msglevel = fec_get_msglevel,
- .set_msglevel = fec_set_msglevel,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum, /* local! */
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_regs = fec_get_regs,
+static const struct ethtool_ops fec_ethtool_ops = {
+ .get_drvinfo = fec_get_drvinfo,
+ .get_regs_len = fec_get_regs_len,
+ .get_settings = fec_get_settings,
+ .set_settings = fec_set_settings,
+ .nway_reset = fec_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = fec_get_msglevel,
+ .set_msglevel = fec_set_msglevel,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum, /* local! */
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_regs = fec_get_regs,
};
static int fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
diff --git a/drivers/net/fec_8xx/fec_mii.c b/drivers/net/fec_8xx/fec_mii.c
index 3b44ac1a7bf..d3c16b85d9a 100644
--- a/drivers/net/fec_8xx/fec_mii.c
+++ b/drivers/net/fec_8xx/fec_mii.c
@@ -10,7 +10,6 @@
* Released under the GPL
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 21be4fa071b..eea1d66c530 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -109,6 +109,7 @@
* 0.54: 21 Mar 2006: Fix spin locks for multi irqs and cleanup.
* 0.55: 22 Mar 2006: Add flow control (pause frame).
* 0.56: 22 Mar 2006: Additional ethtool config and moduleparam support.
+ * 0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -120,7 +121,12 @@
* DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
* superfluous timer interrupts from the nic.
*/
-#define FORCEDETH_VERSION "0.56"
+#ifdef CONFIG_FORCEDETH_NAPI
+#define DRIVERNAPI "-NAPI"
+#else
+#define DRIVERNAPI
+#endif
+#define FORCEDETH_VERSION "0.57"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -240,10 +246,12 @@ enum {
#define NVREG_RNDSEED_FORCE2 0x2d00
#define NVREG_RNDSEED_FORCE3 0x7400
- NvRegUnknownSetupReg1 = 0xA0,
-#define NVREG_UNKSETUP1_VAL 0x16070f
- NvRegUnknownSetupReg2 = 0xA4,
-#define NVREG_UNKSETUP2_VAL 0x16
+ NvRegTxDeferral = 0xA0,
+#define NVREG_TX_DEFERRAL_DEFAULT 0x15050f
+#define NVREG_TX_DEFERRAL_RGMII_10_100 0x16070f
+#define NVREG_TX_DEFERRAL_RGMII_1000 0x14050f
+ NvRegRxDeferral = 0xA4,
+#define NVREG_RX_DEFERRAL_DEFAULT 0x16
NvRegMacAddrA = 0xA8,
NvRegMacAddrB = 0xAC,
NvRegMulticastAddrA = 0xB0,
@@ -260,7 +268,8 @@ enum {
NvRegRingSizes = 0x108,
#define NVREG_RINGSZ_TXSHIFT 0
#define NVREG_RINGSZ_RXSHIFT 16
- NvRegUnknownTransmitterReg = 0x10c,
+ NvRegTransmitPoll = 0x10c,
+#define NVREG_TRANSMITPOLL_MAC_ADDR_REV 0x00008000
NvRegLinkSpeed = 0x110,
#define NVREG_LINKSPEED_FORCE 0x10000
#define NVREG_LINKSPEED_10 1000
@@ -269,8 +278,10 @@ enum {
#define NVREG_LINKSPEED_MASK (0xFFF)
NvRegUnknownSetupReg5 = 0x130,
#define NVREG_UNKSETUP5_BIT31 (1<<31)
- NvRegUnknownSetupReg3 = 0x13c,
-#define NVREG_UNKSETUP3_VAL1 0x200010
+ NvRegTxWatermark = 0x13c,
+#define NVREG_TX_WM_DESC1_DEFAULT 0x0200010
+#define NVREG_TX_WM_DESC2_3_DEFAULT 0x1e08000
+#define NVREG_TX_WM_DESC2_3_1000 0xfe08000
NvRegTxRxControl = 0x144,
#define NVREG_TXRXCTL_KICK 0x0001
#define NVREG_TXRXCTL_BIT1 0x0002
@@ -377,21 +388,21 @@ enum {
/* Big endian: should work, but is untested */
struct ring_desc {
- u32 PacketBuffer;
- u32 FlagLen;
+ __le32 buf;
+ __le32 flaglen;
};
struct ring_desc_ex {
- u32 PacketBufferHigh;
- u32 PacketBufferLow;
- u32 TxVlan;
- u32 FlagLen;
+ __le32 bufhigh;
+ __le32 buflow;
+ __le32 txvlan;
+ __le32 flaglen;
};
-typedef union _ring_type {
+union ring_type {
struct ring_desc* orig;
struct ring_desc_ex* ex;
-} ring_type;
+};
#define FLAG_MASK_V1 0xffff0000
#define FLAG_MASK_V2 0xffffc000
@@ -532,6 +543,9 @@ typedef union _ring_type {
#define PHYID1_OUI_SHFT 6
#define PHYID2_OUI_MASK 0xfc00
#define PHYID2_OUI_SHFT 10
+#define PHYID2_MODEL_MASK 0x03f0
+#define PHY_MODEL_MARVELL_E3016 0x220
+#define PHY_MARVELL_E3016_INITMASK 0x0300
#define PHY_INIT1 0x0f000
#define PHY_INIT2 0x0e00
#define PHY_INIT3 0x01000
@@ -649,8 +663,8 @@ static const struct nv_ethtool_str nv_etests_str[] = {
};
struct register_test {
- u32 reg;
- u32 mask;
+ __le32 reg;
+ __le32 mask;
};
static const struct register_test nv_registers_test[] = {
@@ -658,7 +672,7 @@ static const struct register_test nv_registers_test[] = {
{ NvRegMisc1, 0x03c },
{ NvRegOffloadConfig, 0x03ff },
{ NvRegMulticastAddrA, 0xffffffff },
- { NvRegUnknownSetupReg3, 0x0ff },
+ { NvRegTxWatermark, 0x0ff },
{ NvRegWakeUpFlags, 0x07777 },
{ 0,0 }
};
@@ -690,6 +704,7 @@ struct fe_priv {
int phyaddr;
int wolenabled;
unsigned int phy_oui;
+ unsigned int phy_model;
u16 gigabit;
int intr_test;
@@ -703,13 +718,14 @@ struct fe_priv {
u32 vlanctl_bits;
u32 driver_data;
u32 register_size;
+ int rx_csum;
void __iomem *base;
/* rx specific fields.
* Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
*/
- ring_type rx_ring;
+ union ring_type rx_ring;
unsigned int cur_rx, refill_rx;
struct sk_buff **rx_skbuff;
dma_addr_t *rx_dma;
@@ -729,7 +745,7 @@ struct fe_priv {
/*
* tx specific fields.
*/
- ring_type tx_ring;
+ union ring_type tx_ring;
unsigned int next_tx, nic_tx;
struct sk_buff **tx_skbuff;
dma_addr_t *tx_dma;
@@ -822,13 +838,13 @@ static inline void pci_push(u8 __iomem *base)
static inline u32 nv_descr_getlength(struct ring_desc *prd, u32 v)
{
- return le32_to_cpu(prd->FlagLen)
+ return le32_to_cpu(prd->flaglen)
& ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2);
}
static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v)
{
- return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2;
+ return le32_to_cpu(prd->flaglen) & LEN_MASK_V2;
}
static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
@@ -881,7 +897,7 @@ static void free_rings(struct net_device *dev)
struct fe_priv *np = get_nvpriv(dev);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if(np->rx_ring.orig)
+ if (np->rx_ring.orig)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (np->rx_ring_size + np->tx_ring_size),
np->rx_ring.orig, np->ring_addr);
} else {
@@ -1016,14 +1032,13 @@ static int mii_rw(struct net_device *dev, int addr, int miireg, int value)
return retval;
}
-static int phy_reset(struct net_device *dev)
+static int phy_reset(struct net_device *dev, u32 bmcr_setup)
{
struct fe_priv *np = netdev_priv(dev);
u32 miicontrol;
unsigned int tries = 0;
- miicontrol = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
- miicontrol |= BMCR_RESET;
+ miicontrol = BMCR_RESET | bmcr_setup;
if (mii_rw(dev, np->phyaddr, MII_BMCR, miicontrol)) {
return -1;
}
@@ -1048,6 +1063,16 @@ static int phy_init(struct net_device *dev)
u8 __iomem *base = get_hwbase(dev);
u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg;
+ /* phy errata for E3016 phy */
+ if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
+ reg = mii_rw(dev, np->phyaddr, MII_NCONFIG, MII_READ);
+ reg &= ~PHY_MARVELL_E3016_INITMASK;
+ if (mii_rw(dev, np->phyaddr, MII_NCONFIG, reg)) {
+ printk(KERN_INFO "%s: phy write to errata reg failed.\n", pci_name(np->pci_dev));
+ return PHY_ERROR;
+ }
+ }
+
/* set advertise register */
reg = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ);
reg |= (ADVERTISE_10HALF|ADVERTISE_10FULL|ADVERTISE_100HALF|ADVERTISE_100FULL|ADVERTISE_PAUSE_ASYM|ADVERTISE_PAUSE_CAP);
@@ -1078,8 +1103,13 @@ static int phy_init(struct net_device *dev)
else
np->gigabit = 0;
- /* reset the phy */
- if (phy_reset(dev)) {
+ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
+ mii_control |= BMCR_ANENABLE;
+
+ /* reset the phy
+ * (certain phys need bmcr to be setup with reset)
+ */
+ if (phy_reset(dev, mii_control)) {
printk(KERN_INFO "%s: phy reset failed\n", pci_name(np->pci_dev));
return PHY_ERROR;
}
@@ -1174,7 +1204,7 @@ static void nv_stop_tx(struct net_device *dev)
KERN_INFO "nv_stop_tx: TransmitterStatus remained busy");
udelay(NV_TXSTOP_DELAY2);
- writel(0, base + NvRegUnknownTransmitterReg);
+ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
}
static void nv_txrx_reset(struct net_device *dev)
@@ -1254,14 +1284,14 @@ static int nv_alloc_rx(struct net_device *dev)
np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
skb->end-skb->data, PCI_DMA_FROMDEVICE);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]);
+ np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
wmb();
- np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+ np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
} else {
- np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
- np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
+ np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
+ np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
wmb();
- np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+ np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
}
dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
dev->name, refill_rx);
@@ -1273,6 +1303,16 @@ static int nv_alloc_rx(struct net_device *dev)
return 0;
}
+/* If rx bufs are exhausted called after 50ms to attempt to refresh */
+#ifdef CONFIG_FORCEDETH_NAPI
+static void nv_do_rx_refill(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *) data;
+
+ /* Just reschedule NAPI rx processing */
+ netif_rx_schedule(dev);
+}
+#else
static void nv_do_rx_refill(unsigned long data)
{
struct net_device *dev = (struct net_device *) data;
@@ -1301,6 +1341,7 @@ static void nv_do_rx_refill(unsigned long data)
enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
}
+#endif
static void nv_init_rx(struct net_device *dev)
{
@@ -1311,9 +1352,9 @@ static void nv_init_rx(struct net_device *dev)
np->refill_rx = 0;
for (i = 0; i < np->rx_ring_size; i++)
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->rx_ring.orig[i].FlagLen = 0;
+ np->rx_ring.orig[i].flaglen = 0;
else
- np->rx_ring.ex[i].FlagLen = 0;
+ np->rx_ring.ex[i].flaglen = 0;
}
static void nv_init_tx(struct net_device *dev)
@@ -1324,9 +1365,9 @@ static void nv_init_tx(struct net_device *dev)
np->next_tx = np->nic_tx = 0;
for (i = 0; i < np->tx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[i].FlagLen = 0;
+ np->tx_ring.orig[i].flaglen = 0;
else
- np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_ring.ex[i].flaglen = 0;
np->tx_skbuff[i] = NULL;
np->tx_dma[i] = 0;
}
@@ -1369,9 +1410,9 @@ static void nv_drain_tx(struct net_device *dev)
for (i = 0; i < np->tx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->tx_ring.orig[i].FlagLen = 0;
+ np->tx_ring.orig[i].flaglen = 0;
else
- np->tx_ring.ex[i].FlagLen = 0;
+ np->tx_ring.ex[i].flaglen = 0;
if (nv_release_txskb(dev, i))
np->stats.tx_dropped++;
}
@@ -1383,9 +1424,9 @@ static void nv_drain_rx(struct net_device *dev)
int i;
for (i = 0; i < np->rx_ring_size; i++) {
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- np->rx_ring.orig[i].FlagLen = 0;
+ np->rx_ring.orig[i].flaglen = 0;
else
- np->rx_ring.ex[i].FlagLen = 0;
+ np->rx_ring.ex[i].flaglen = 0;
wmb();
if (np->rx_skbuff[i]) {
pci_unmap_single(np->pci_dev, np->rx_dma[i],
@@ -1446,17 +1487,17 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_dma_len[nr] = bcnt;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
} else {
- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
}
tx_flags = np->tx_flags;
offset += bcnt;
size -= bcnt;
- } while(size);
+ } while (size);
/* setup the fragments */
for (i = 0; i < fragments; i++) {
@@ -1473,12 +1514,12 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
np->tx_dma_len[nr] = bcnt;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]);
- np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
+ np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
} else {
- np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
- np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
- np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags);
+ np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
+ np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
+ np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
}
offset += bcnt;
size -= bcnt;
@@ -1487,19 +1528,20 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set last fragment flag */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
} else {
- np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra);
+ np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
}
np->tx_skbuff[nr] = skb;
#ifdef NETIF_F_TSO
- if (skb_shinfo(skb)->gso_size)
+ if (skb_is_gso(skb))
tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
else
#endif
- tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
+ tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+ NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
/* vlan tag */
if (np->vlangrp && vlan_tx_tag_present(skb)) {
@@ -1508,10 +1550,10 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* set tx flags */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
} else {
- np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan);
- np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra);
+ np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
+ np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
}
dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
@@ -1543,7 +1585,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
static void nv_tx_done(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- u32 Flags;
+ u32 flags;
unsigned int i;
struct sk_buff *skb;
@@ -1551,22 +1593,22 @@ static void nv_tx_done(struct net_device *dev)
i = np->nic_tx % np->tx_ring_size;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
- Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen);
+ flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
else
- Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen);
+ flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
- dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n",
- dev->name, np->nic_tx, Flags);
- if (Flags & NV_TX_VALID)
+ dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
+ dev->name, np->nic_tx, flags);
+ if (flags & NV_TX_VALID)
break;
if (np->desc_ver == DESC_VER_1) {
- if (Flags & NV_TX_LASTPACKET) {
+ if (flags & NV_TX_LASTPACKET) {
skb = np->tx_skbuff[i];
- if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
+ if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
NV_TX_UNDERFLOW|NV_TX_ERROR)) {
- if (Flags & NV_TX_UNDERFLOW)
+ if (flags & NV_TX_UNDERFLOW)
np->stats.tx_fifo_errors++;
- if (Flags & NV_TX_CARRIERLOST)
+ if (flags & NV_TX_CARRIERLOST)
np->stats.tx_carrier_errors++;
np->stats.tx_errors++;
} else {
@@ -1575,13 +1617,13 @@ static void nv_tx_done(struct net_device *dev)
}
}
} else {
- if (Flags & NV_TX2_LASTPACKET) {
+ if (flags & NV_TX2_LASTPACKET) {
skb = np->tx_skbuff[i];
- if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
+ if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
- if (Flags & NV_TX2_UNDERFLOW)
+ if (flags & NV_TX2_UNDERFLOW)
np->stats.tx_fifo_errors++;
- if (Flags & NV_TX2_CARRIERLOST)
+ if (flags & NV_TX2_CARRIERLOST)
np->stats.tx_carrier_errors++;
np->stats.tx_errors++;
} else {
@@ -1634,29 +1676,29 @@ static void nv_tx_timeout(struct net_device *dev)
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n",
i,
- le32_to_cpu(np->tx_ring.orig[i].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i].FlagLen),
- le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i+1].FlagLen),
- le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i+2].FlagLen),
- le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer),
- le32_to_cpu(np->tx_ring.orig[i+3].FlagLen));
+ le32_to_cpu(np->tx_ring.orig[i].buf),
+ le32_to_cpu(np->tx_ring.orig[i].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+1].buf),
+ le32_to_cpu(np->tx_ring.orig[i+1].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+2].buf),
+ le32_to_cpu(np->tx_ring.orig[i+2].flaglen),
+ le32_to_cpu(np->tx_ring.orig[i+3].buf),
+ le32_to_cpu(np->tx_ring.orig[i+3].flaglen));
} else {
printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n",
i,
- le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i].FlagLen),
- le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i+1].FlagLen),
- le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i+2].FlagLen),
- le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh),
- le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow),
- le32_to_cpu(np->tx_ring.ex[i+3].FlagLen));
+ le32_to_cpu(np->tx_ring.ex[i].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i].buflow),
+ le32_to_cpu(np->tx_ring.ex[i].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+1].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+1].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+1].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+2].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+2].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+2].flaglen),
+ le32_to_cpu(np->tx_ring.ex[i+3].bufhigh),
+ le32_to_cpu(np->tx_ring.ex[i+3].buflow),
+ le32_to_cpu(np->tx_ring.ex[i+3].flaglen));
}
}
}
@@ -1693,7 +1735,7 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
int protolen; /* length as stored in the proto field */
/* 1) calculate len according to header */
- if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) {
+ if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == htons(ETH_P_8021Q)) {
protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto );
hdrlen = VLAN_HLEN;
} else {
@@ -1736,13 +1778,14 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
}
}
-static void nv_rx_process(struct net_device *dev)
+static int nv_rx_process(struct net_device *dev, int limit)
{
struct fe_priv *np = netdev_priv(dev);
- u32 Flags;
+ u32 flags;
u32 vlanflags = 0;
+ int count;
- for (;;) {
+ for (count = 0; count < limit; ++count) {
struct sk_buff *skb;
int len;
int i;
@@ -1751,18 +1794,18 @@ static void nv_rx_process(struct net_device *dev)
i = np->cur_rx % np->rx_ring_size;
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
} else {
- Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
- vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow);
+ vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
}
- dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n",
- dev->name, np->cur_rx, Flags);
+ dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
+ dev->name, np->cur_rx, flags);
- if (Flags & NV_RX_AVAIL)
+ if (flags & NV_RX_AVAIL)
break; /* still owned by hardware, */
/*
@@ -1776,7 +1819,7 @@ static void nv_rx_process(struct net_device *dev)
{
int j;
- dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",Flags);
+ dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
for (j=0; j<64; j++) {
if ((j%16) == 0)
dprintk("\n%03x:", j);
@@ -1786,30 +1829,30 @@ static void nv_rx_process(struct net_device *dev)
}
/* look at what we actually got: */
if (np->desc_ver == DESC_VER_1) {
- if (!(Flags & NV_RX_DESCRIPTORVALID))
+ if (!(flags & NV_RX_DESCRIPTORVALID))
goto next_pkt;
- if (Flags & NV_RX_ERROR) {
- if (Flags & NV_RX_MISSEDFRAME) {
+ if (flags & NV_RX_ERROR) {
+ if (flags & NV_RX_MISSEDFRAME) {
np->stats.rx_missed_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
+ if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_CRCERR) {
+ if (flags & NV_RX_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_OVERFLOW) {
+ if (flags & NV_RX_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX_ERROR4) {
+ if (flags & NV_RX_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
@@ -1817,32 +1860,32 @@ static void nv_rx_process(struct net_device *dev)
}
}
/* framing errors are soft errors. */
- if (Flags & NV_RX_FRAMINGERR) {
- if (Flags & NV_RX_SUBSTRACT1) {
+ if (flags & NV_RX_FRAMINGERR) {
+ if (flags & NV_RX_SUBSTRACT1) {
len--;
}
}
}
} else {
- if (!(Flags & NV_RX2_DESCRIPTORVALID))
+ if (!(flags & NV_RX2_DESCRIPTORVALID))
goto next_pkt;
- if (Flags & NV_RX2_ERROR) {
- if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
+ if (flags & NV_RX2_ERROR) {
+ if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_CRCERR) {
+ if (flags & NV_RX2_CRCERR) {
np->stats.rx_crc_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_OVERFLOW) {
+ if (flags & NV_RX2_OVERFLOW) {
np->stats.rx_over_errors++;
np->stats.rx_errors++;
goto next_pkt;
}
- if (Flags & NV_RX2_ERROR4) {
+ if (flags & NV_RX2_ERROR4) {
len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
if (len < 0) {
np->stats.rx_errors++;
@@ -1850,17 +1893,17 @@ static void nv_rx_process(struct net_device *dev)
}
}
/* framing errors are soft errors */
- if (Flags & NV_RX2_FRAMINGERR) {
- if (Flags & NV_RX2_SUBSTRACT1) {
+ if (flags & NV_RX2_FRAMINGERR) {
+ if (flags & NV_RX2_SUBSTRACT1) {
len--;
}
}
}
- if (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) {
- Flags &= NV_RX2_CHECKSUMMASK;
- if (Flags == NV_RX2_CHECKSUMOK1 ||
- Flags == NV_RX2_CHECKSUMOK2 ||
- Flags == NV_RX2_CHECKSUMOK3) {
+ if (np->rx_csum) {
+ flags &= NV_RX2_CHECKSUMMASK;
+ if (flags == NV_RX2_CHECKSUMOK1 ||
+ flags == NV_RX2_CHECKSUMOK2 ||
+ flags == NV_RX2_CHECKSUMOK3) {
dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
} else {
@@ -1876,17 +1919,27 @@ static void nv_rx_process(struct net_device *dev)
skb->protocol = eth_type_trans(skb, dev);
dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
dev->name, np->cur_rx, len, skb->protocol);
- if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) {
- vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK);
- } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+ vlan_hwaccel_receive_skb(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+ else
+ netif_receive_skb(skb);
+#else
+ if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
+ vlan_hwaccel_rx(skb, np->vlangrp,
+ vlanflags & NV_RX3_VLAN_TAG_MASK);
+ else
netif_rx(skb);
- }
+#endif
dev->last_rx = jiffies;
np->stats.rx_packets++;
np->stats.rx_bytes += len;
next_pkt:
np->cur_rx++;
}
+
+ return count;
}
static void set_bufsize(struct net_device *dev)
@@ -1986,7 +2039,7 @@ static int nv_set_mac_address(struct net_device *dev, void *addr)
struct fe_priv *np = netdev_priv(dev);
struct sockaddr *macaddr = (struct sockaddr*)addr;
- if(!is_valid_ether_addr(macaddr->sa_data))
+ if (!is_valid_ether_addr(macaddr->sa_data))
return -EADDRNOTAVAIL;
/* synchronized against open : rtnl_lock() held by caller */
@@ -2028,7 +2081,6 @@ static void nv_set_multicast(struct net_device *dev)
memset(mask, 0, sizeof(mask));
if (dev->flags & IFF_PROMISC) {
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
pff |= NVREG_PFF_PROMISC;
} else {
pff |= NVREG_PFF_MYADDR;
@@ -2127,7 +2179,7 @@ static int nv_update_linkspeed(struct net_device *dev)
int newdup = np->duplex;
int mii_status;
int retval = 0;
- u32 control_1000, status_1000, phyreg, pause_flags;
+ u32 control_1000, status_1000, phyreg, pause_flags, txreg;
/* BMSR_LSTATUS is latched, read it twice:
* we want the current value.
@@ -2245,6 +2297,26 @@ set_speed:
phyreg |= PHY_1000;
writel(phyreg, base + NvRegPhyInterface);
+ if (phyreg & PHY_RGMII) {
+ if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
+ txreg = NVREG_TX_DEFERRAL_RGMII_1000;
+ else
+ txreg = NVREG_TX_DEFERRAL_RGMII_10_100;
+ } else {
+ txreg = NVREG_TX_DEFERRAL_DEFAULT;
+ }
+ writel(txreg, base + NvRegTxDeferral);
+
+ if (np->desc_ver == DESC_VER_1) {
+ txreg = NVREG_TX_WM_DESC1_DEFAULT;
+ } else {
+ if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000)
+ txreg = NVREG_TX_WM_DESC2_3_1000;
+ else
+ txreg = NVREG_TX_WM_DESC2_3_DEFAULT;
+ }
+ writel(txreg, base + NvRegTxWatermark);
+
writel(NVREG_MISC1_FORCE | ( np->duplex ? 0 : NVREG_MISC1_HD),
base + NvRegMisc1);
pci_push(base);
@@ -2259,20 +2331,20 @@ set_speed:
lpa_pause = lpa & (LPA_PAUSE_CAP| LPA_PAUSE_ASYM);
switch (adv_pause) {
- case (ADVERTISE_PAUSE_CAP):
+ case ADVERTISE_PAUSE_CAP:
if (lpa_pause & LPA_PAUSE_CAP) {
pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
if (np->pause_flags & NV_PAUSEFRAME_TX_REQ)
pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
}
break;
- case (ADVERTISE_PAUSE_ASYM):
+ case ADVERTISE_PAUSE_ASYM:
if (lpa_pause == (LPA_PAUSE_CAP| LPA_PAUSE_ASYM))
{
pause_flags |= NV_PAUSEFRAME_TX_ENABLE;
}
break;
- case (ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM):
+ case ADVERTISE_PAUSE_CAP| ADVERTISE_PAUSE_ASYM:
if (lpa_pause & LPA_PAUSE_CAP)
{
pause_flags |= NV_PAUSEFRAME_RX_ENABLE;
@@ -2352,14 +2424,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
nv_tx_done(dev);
spin_unlock(&np->lock);
- nv_rx_process(dev);
- if (nv_alloc_rx(dev)) {
- spin_lock(&np->lock);
- if (!np->in_shutdown)
- mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock(&np->lock);
- }
-
if (events & NVREG_IRQ_LINK) {
spin_lock(&np->lock);
nv_link_irq(dev);
@@ -2379,6 +2443,29 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
dev->name, events);
}
+#ifdef CONFIG_FORCEDETH_NAPI
+ if (events & NVREG_IRQ_RX_ALL) {
+ netif_rx_schedule(dev);
+
+ /* Disable furthur receive irq's */
+ spin_lock(&np->lock);
+ np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock(&np->lock);
+ }
+#else
+ nv_rx_process(dev, dev->weight);
+ if (nv_alloc_rx(dev)) {
+ spin_lock(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock(&np->lock);
+ }
+#endif
if (i > max_interrupt_work) {
spin_lock(&np->lock);
/* disable interrupts on the nic */
@@ -2450,6 +2537,63 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
return IRQ_RETVAL(i);
}
+#ifdef CONFIG_FORCEDETH_NAPI
+static int nv_napi_poll(struct net_device *dev, int *budget)
+{
+ int pkts, limit = min(*budget, dev->quota);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
+
+ pkts = nv_rx_process(dev, limit);
+
+ if (nv_alloc_rx(dev)) {
+ spin_lock_irq(&np->lock);
+ if (!np->in_shutdown)
+ mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+ spin_unlock_irq(&np->lock);
+ }
+
+ if (pkts < limit) {
+ /* all done, no more packets present */
+ netif_rx_complete(dev);
+
+ /* re-enable receive interrupts */
+ spin_lock_irq(&np->lock);
+ np->irqmask |= NVREG_IRQ_RX_ALL;
+ if (np->msi_flags & NV_MSI_X_ENABLED)
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ else
+ writel(np->irqmask, base + NvRegIrqMask);
+ spin_unlock_irq(&np->lock);
+ return 0;
+ } else {
+ /* used up our quantum, so reschedule */
+ dev->quota -= pkts;
+ *budget -= pkts;
+ return 1;
+ }
+}
+#endif
+
+#ifdef CONFIG_FORCEDETH_NAPI
+static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *) data;
+ u8 __iomem *base = get_hwbase(dev);
+ u32 events;
+
+ events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
+ writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
+
+ if (events) {
+ netif_rx_schedule(dev);
+ /* disable receive interrupts on the nic */
+ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+ pci_push(base);
+ }
+ return IRQ_HANDLED;
+}
+#else
static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) data;
@@ -2468,7 +2612,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
if (!(events & np->irqmask))
break;
- nv_rx_process(dev);
+ nv_rx_process(dev, dev->weight);
if (nv_alloc_rx(dev)) {
spin_lock_irq(&np->lock);
if (!np->in_shutdown)
@@ -2490,12 +2634,12 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
spin_unlock_irq(&np->lock);
break;
}
-
}
dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name);
return IRQ_RETVAL(i);
}
+#endif
static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
{
@@ -2622,21 +2766,21 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
np->msi_flags |= NV_MSI_X_ENABLED;
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) {
/* Request irq for rx handling */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
goto out_err;
}
/* Request irq for tx handling */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
goto out_free_rx;
}
/* Request irq for link and timer handling */
- if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) {
+ if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, IRQF_SHARED, dev->name, dev) != 0) {
printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2651,9 +2795,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
} else {
/* Request irq for all interrupts */
if ((!intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
+ request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
(intr_test &&
- request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0)) {
+ request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msix(np->pci_dev);
np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2669,8 +2813,8 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
np->msi_flags |= NV_MSI_ENABLED;
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0)) {
+ if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
+ (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
pci_disable_msi(np->pci_dev);
np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2685,8 +2829,8 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
}
}
if (ret != 0) {
- if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) ||
- (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, SA_SHIRQ, dev->name, dev) != 0))
+ if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
+ (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
goto out_err;
}
@@ -2735,21 +2879,21 @@ static void nv_do_nic_poll(unsigned long data)
if (!using_multi_irqs(dev)) {
if (np->msi_flags & NV_MSI_X_ENABLED)
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- disable_irq(dev->irq);
+ disable_irq_lockdep(dev->irq);
mask = np->irqmask;
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+ disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
mask |= NVREG_IRQ_RX_ALL;
}
if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+ disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
mask |= NVREG_IRQ_TX_ALL;
}
if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
- disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+ disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
mask |= NVREG_IRQ_OTHER;
}
}
@@ -2761,23 +2905,23 @@ static void nv_do_nic_poll(unsigned long data)
pci_push(base);
if (!using_multi_irqs(dev)) {
- nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL);
+ nv_nic_irq(0, dev, NULL);
if (np->msi_flags & NV_MSI_X_ENABLED)
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
- enable_irq(dev->irq);
+ enable_irq_lockdep(dev->irq);
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
- nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs *) NULL);
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
+ nv_nic_irq_rx(0, dev, NULL);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
- nv_nic_irq_tx((int) 0, (void *) data, (struct pt_regs *) NULL);
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
+ nv_nic_irq_tx(0, dev, NULL);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
}
if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
- nv_nic_irq_other((int) 0, (void *) data, (struct pt_regs *) NULL);
- enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
+ nv_nic_irq_other(0, dev, NULL);
+ enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
}
}
}
@@ -3033,9 +3177,18 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
if (netif_running(dev))
printk(KERN_INFO "%s: link down.\n", dev->name);
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
- bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
- mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
-
+ if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
+ bmcr |= BMCR_ANENABLE;
+ /* reset the phy in order for settings to stick,
+ * and cause autoneg to start */
+ if (phy_reset(dev, bmcr)) {
+ printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ return -EINVAL;
+ }
+ } else {
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ }
} else {
int adv, bmcr;
@@ -3075,17 +3228,19 @@ static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
bmcr |= BMCR_FULLDPLX;
if (np->fixed_mode & (ADVERTISE_100HALF|ADVERTISE_100FULL))
bmcr |= BMCR_SPEED100;
- mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
if (np->phy_oui == PHY_OUI_MARVELL) {
- /* reset the phy */
- if (phy_reset(dev)) {
+ /* reset the phy in order for forced mode settings to stick */
+ if (phy_reset(dev, bmcr)) {
printk(KERN_INFO "%s: phy reset failed\n", dev->name);
return -EINVAL;
}
- } else if (netif_running(dev)) {
- /* Wait a bit and then reconfigure the nic. */
- udelay(10);
- nv_linkchange(dev);
+ } else {
+ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ if (netif_running(dev)) {
+ /* Wait a bit and then reconfigure the nic. */
+ udelay(10);
+ nv_linkchange(dev);
+ }
}
}
@@ -3142,8 +3297,17 @@ static int nv_nway_reset(struct net_device *dev)
}
bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ);
- bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
- mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ if (np->phy_model == PHY_MODEL_MARVELL_E3016) {
+ bmcr |= BMCR_ANENABLE;
+ /* reset the phy in order for settings to stick*/
+ if (phy_reset(dev, bmcr)) {
+ printk(KERN_INFO "%s: phy reset failed\n", dev->name);
+ return -EINVAL;
+ }
+ } else {
+ bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ mii_rw(dev, np->phyaddr, MII_BMCR, bmcr);
+ }
if (netif_running(dev)) {
nv_start_rx(dev);
@@ -3221,7 +3385,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
/* fall back to old rings */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- if(rxtx_ring)
+ if (rxtx_ring)
pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (ring->rx_pending + ring->tx_pending),
rxtx_ring, ring_addr);
} else {
@@ -3394,7 +3558,7 @@ static int nv_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam*
static u32 nv_get_rx_csum(struct net_device *dev)
{
struct fe_priv *np = netdev_priv(dev);
- return (np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) != 0;
+ return (np->rx_csum) != 0;
}
static int nv_set_rx_csum(struct net_device *dev, u32 data)
@@ -3404,22 +3568,15 @@ static int nv_set_rx_csum(struct net_device *dev, u32 data)
int retcode = 0;
if (np->driver_data & DEV_HAS_CHECKSUM) {
-
- if (((np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) && data) ||
- (!(np->txrxctl_bits & NVREG_TXRXCTL_RXCHECK) && !data)) {
- /* already set or unset */
- return 0;
- }
-
if (data) {
+ np->rx_csum = 1;
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
- } else if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE)) {
- np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
} else {
- printk(KERN_INFO "Can not disable rx checksum if vlan is enabled\n");
- return -EINVAL;
+ np->rx_csum = 0;
+ /* vlan is dependent on rx checksum offload */
+ if (!(np->vlanctl_bits & NVREG_VLANCONTROL_ENABLE))
+ np->txrxctl_bits &= ~NVREG_TXRXCTL_RXCHECK;
}
-
if (netif_running(dev)) {
spin_lock_irq(&np->lock);
writel(np->txrxctl_bits, base + NvRegTxRxControl);
@@ -3457,7 +3614,7 @@ static int nv_get_stats_count(struct net_device *dev)
struct fe_priv *np = netdev_priv(dev);
if (np->driver_data & DEV_HAS_STATISTICS)
- return (sizeof(struct nv_ethtool_stats)/sizeof(u64));
+ return sizeof(struct nv_ethtool_stats)/sizeof(u64);
else
return 0;
}
@@ -3595,7 +3752,7 @@ static int nv_loopback_test(struct net_device *dev)
struct sk_buff *tx_skb, *rx_skb;
dma_addr_t test_dma_addr;
u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
- u32 Flags;
+ u32 flags;
int len, i, pkt_len;
u8 *pkt_data;
u32 filter_flags = 0;
@@ -3632,6 +3789,12 @@ static int nv_loopback_test(struct net_device *dev)
/* setup packet for tx */
pkt_len = ETH_DATA_LEN;
tx_skb = dev_alloc_skb(pkt_len);
+ if (!tx_skb) {
+ printk(KERN_ERR "dev_alloc_skb() failed during loopback test"
+ " of %s\n", dev->name);
+ ret = 0;
+ goto out;
+ }
pkt_data = skb_put(tx_skb, pkt_len);
for (i = 0; i < pkt_len; i++)
pkt_data[i] = (u8)(i & 0xff);
@@ -3639,12 +3802,12 @@ static int nv_loopback_test(struct net_device *dev)
tx_skb->end-tx_skb->data, PCI_DMA_FROMDEVICE);
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- np->tx_ring.orig[0].PacketBuffer = cpu_to_le32(test_dma_addr);
- np->tx_ring.orig[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.orig[0].buf = cpu_to_le32(test_dma_addr);
+ np->tx_ring.orig[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
} else {
- np->tx_ring.ex[0].PacketBufferHigh = cpu_to_le64(test_dma_addr) >> 32;
- np->tx_ring.ex[0].PacketBufferLow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
- np->tx_ring.ex[0].FlagLen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
+ np->tx_ring.ex[0].bufhigh = cpu_to_le64(test_dma_addr) >> 32;
+ np->tx_ring.ex[0].buflow = cpu_to_le64(test_dma_addr) & 0x0FFFFFFFF;
+ np->tx_ring.ex[0].flaglen = cpu_to_le32((pkt_len-1) | np->tx_flags | tx_flags_extra);
}
writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
pci_push(get_hwbase(dev));
@@ -3653,21 +3816,21 @@ static int nv_loopback_test(struct net_device *dev)
/* check for rx of the packet */
if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
- Flags = le32_to_cpu(np->rx_ring.orig[0].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.orig[0].flaglen);
len = nv_descr_getlength(&np->rx_ring.orig[0], np->desc_ver);
} else {
- Flags = le32_to_cpu(np->rx_ring.ex[0].FlagLen);
+ flags = le32_to_cpu(np->rx_ring.ex[0].flaglen);
len = nv_descr_getlength_ex(&np->rx_ring.ex[0], np->desc_ver);
}
- if (Flags & NV_RX_AVAIL) {
+ if (flags & NV_RX_AVAIL) {
ret = 0;
} else if (np->desc_ver == DESC_VER_1) {
- if (Flags & NV_RX_ERROR)
+ if (flags & NV_RX_ERROR)
ret = 0;
} else {
- if (Flags & NV_RX2_ERROR) {
+ if (flags & NV_RX2_ERROR) {
ret = 0;
}
}
@@ -3696,7 +3859,7 @@ static int nv_loopback_test(struct net_device *dev)
tx_skb->end-tx_skb->data,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(tx_skb);
-
+ out:
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
@@ -3729,6 +3892,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (netif_running(dev)) {
netif_stop_queue(dev);
+ netif_poll_disable(dev);
netif_tx_lock_bh(dev);
spin_lock_irq(&np->lock);
nv_disable_hw_interrupts(dev, np->irqmask);
@@ -3787,6 +3951,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
+ netif_poll_enable(dev);
nv_enable_hw_interrupts(dev, np->irqmask);
}
}
@@ -3804,7 +3969,7 @@ static void nv_get_strings(struct net_device *dev, u32 stringset, u8 *buffer)
}
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = nv_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_wol = nv_get_wol,
@@ -3871,10 +4036,9 @@ static int nv_open(struct net_device *dev)
dprintk(KERN_DEBUG "nv_open: begin\n");
- /* 1) erase previous misconfiguration */
+ /* erase previous misconfiguration */
if (np->driver_data & DEV_HAS_POWER_CNTRL)
nv_mac_reset(dev);
- /* 4.1-1: stop adapter: ignored, 4.3 seems to be overkill */
writel(NVREG_MCASTADDRA_FORCE, base + NvRegMulticastAddrA);
writel(0, base + NvRegMulticastAddrB);
writel(0, base + NvRegMulticastMaskA);
@@ -3889,28 +4053,27 @@ static int nv_open(struct net_device *dev)
if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE)
writel(NVREG_TX_PAUSEFRAME_DISABLE, base + NvRegTxPauseFrame);
- /* 2) initialize descriptor rings */
+ /* initialize descriptor rings */
set_bufsize(dev);
oom = nv_init_ring(dev);
writel(0, base + NvRegLinkSpeed);
- writel(0, base + NvRegUnknownTransmitterReg);
+ writel(readl(base + NvRegTransmitPoll) & NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
nv_txrx_reset(dev);
writel(0, base + NvRegUnknownSetupReg6);
np->in_shutdown = 0;
- /* 3) set mac address */
- nv_copy_mac_to_hw(dev);
-
- /* 4) give hw rings */
+ /* give hw rings */
setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING);
writel( ((np->rx_ring_size-1) << NVREG_RINGSZ_RXSHIFT) + ((np->tx_ring_size-1) << NVREG_RINGSZ_TXSHIFT),
base + NvRegRingSizes);
- /* 5) continue setup */
writel(np->linkspeed, base + NvRegLinkSpeed);
- writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3);
+ if (np->desc_ver == DESC_VER_1)
+ writel(NVREG_TX_WM_DESC1_DEFAULT, base + NvRegTxWatermark);
+ else
+ writel(NVREG_TX_WM_DESC2_3_DEFAULT, base + NvRegTxWatermark);
writel(np->txrxctl_bits, base + NvRegTxRxControl);
writel(np->vlanctl_bits, base + NvRegVlanControl);
pci_push(base);
@@ -3923,7 +4086,6 @@ static int nv_open(struct net_device *dev)
writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
writel(NVREG_MIISTAT_MASK2, base + NvRegMIIStatus);
- /* 6) continue setup */
writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1);
writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus);
writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags);
@@ -3932,8 +4094,8 @@ static int nv_open(struct net_device *dev)
writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus);
get_random_bytes(&i, sizeof(i));
writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed);
- writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1);
- writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2);
+ writel(NVREG_TX_DEFERRAL_DEFAULT, base + NvRegTxDeferral);
+ writel(NVREG_RX_DEFERRAL_DEFAULT, base + NvRegRxDeferral);
if (poll_interval == -1) {
if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT)
writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval);
@@ -3993,6 +4155,8 @@ static int nv_open(struct net_device *dev)
nv_start_rx(dev);
nv_start_tx(dev);
netif_start_queue(dev);
+ netif_poll_enable(dev);
+
if (ret) {
netif_carrier_on(dev);
} else {
@@ -4022,6 +4186,7 @@ static int nv_close(struct net_device *dev)
spin_lock_irq(&np->lock);
np->in_shutdown = 1;
spin_unlock_irq(&np->lock);
+ netif_poll_disable(dev);
synchronize_irq(dev->irq);
del_timer_sync(&np->oom_kick);
@@ -4049,12 +4214,6 @@ static int nv_close(struct net_device *dev)
if (np->wolenabled)
nv_start_rx(dev);
- /* special op: write back the misordered MAC address - otherwise
- * the next nv_probe would see a wrong address.
- */
- writel(np->orig_mac[0], base + NvRegMacAddrA);
- writel(np->orig_mac[1], base + NvRegMacAddrB);
-
/* FIXME: power down nic */
return 0;
@@ -4067,7 +4226,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
unsigned long addr;
u8 __iomem *base;
int err, i;
- u32 powerstate;
+ u32 powerstate, txreg;
dev = alloc_etherdev(sizeof(struct fe_priv));
err = -ENOMEM;
@@ -4163,6 +4322,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->pkt_limit = NV_PKTLIMIT_2;
if (id->driver_data & DEV_HAS_CHECKSUM) {
+ np->rx_csum = 1;
np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
#ifdef NETIF_F_TSO
@@ -4243,6 +4403,10 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = nv_poll_controller;
#endif
+ dev->weight = 64;
+#ifdef CONFIG_FORCEDETH_NAPI
+ dev->poll = nv_napi_poll;
+#endif
SET_ETHTOOL_OPS(dev, &ops);
dev->tx_timeout = nv_tx_timeout;
dev->watchdog_timeo = NV_WATCHDOG_TIMEO;
@@ -4254,12 +4418,30 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
np->orig_mac[0] = readl(base + NvRegMacAddrA);
np->orig_mac[1] = readl(base + NvRegMacAddrB);
- dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
- dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
- dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
- dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
- dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
- dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
+ /* check the workaround bit for correct mac address order */
+ txreg = readl(base + NvRegTransmitPoll);
+ if (txreg & NVREG_TRANSMITPOLL_MAC_ADDR_REV) {
+ /* mac address is already in correct order */
+ dev->dev_addr[0] = (np->orig_mac[0] >> 0) & 0xff;
+ dev->dev_addr[1] = (np->orig_mac[0] >> 8) & 0xff;
+ dev->dev_addr[2] = (np->orig_mac[0] >> 16) & 0xff;
+ dev->dev_addr[3] = (np->orig_mac[0] >> 24) & 0xff;
+ dev->dev_addr[4] = (np->orig_mac[1] >> 0) & 0xff;
+ dev->dev_addr[5] = (np->orig_mac[1] >> 8) & 0xff;
+ } else {
+ /* need to reverse mac address to correct order */
+ dev->dev_addr[0] = (np->orig_mac[1] >> 8) & 0xff;
+ dev->dev_addr[1] = (np->orig_mac[1] >> 0) & 0xff;
+ dev->dev_addr[2] = (np->orig_mac[0] >> 24) & 0xff;
+ dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff;
+ dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
+ dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
+ /* set permanent address to be correct aswell */
+ np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) +
+ (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24);
+ np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8);
+ writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
+ }
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
if (!is_valid_ether_addr(dev->perm_addr)) {
@@ -4282,6 +4464,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+ /* set mac address */
+ nv_copy_mac_to_hw(dev);
+
/* disable WOL */
writel(0, base + NvRegWakeUpFlags);
np->wolenabled = 0;
@@ -4342,6 +4527,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
if (id2 < 0 || id2 == 0xffff)
continue;
+ np->phy_model = id2 & PHYID2_MODEL_MASK;
id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT;
id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT;
dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n",
@@ -4394,9 +4580,17 @@ out:
static void __devexit nv_remove(struct pci_dev *pci_dev)
{
struct net_device *dev = pci_get_drvdata(pci_dev);
+ struct fe_priv *np = netdev_priv(dev);
+ u8 __iomem *base = get_hwbase(dev);
unregister_netdev(dev);
+ /* special op: write back the misordered MAC address - otherwise
+ * the next nv_probe would see a wrong address.
+ */
+ writel(np->orig_mac[0], base + NvRegMacAddrA);
+ writel(np->orig_mac[1], base + NvRegMacAddrB);
+
/* free all structures */
free_rings(dev);
iounmap(get_hwbase(dev));
@@ -4513,7 +4707,7 @@ static struct pci_driver driver = {
static int __init init_nic(void)
{
printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION);
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit exit_nic(void)
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile
index d6dd3f2fb43..02d4dc18ba6 100644
--- a/drivers/net/fs_enet/Makefile
+++ b/drivers/net/fs_enet/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_FS_ENET) += fs_enet.o
-obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o
-obj-$(CONFIG_8260) += mac-fcc.o
+obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o mii-fec.o
+obj-$(CONFIG_CPM2) += mac-fcc.o mii-bitbang.o
-fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o
+fs_enet-objs := fs_enet-main.o
diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/fs_enet/fec.h
new file mode 100644
index 00000000000..e980527e2b9
--- /dev/null
+++ b/drivers/net/fs_enet/fec.h
@@ -0,0 +1,42 @@
+#ifndef FS_ENET_FEC_H
+#define FS_ENET_FEC_H
+
+/* CRC polynomium used by the FEC for the multicast group filtering */
+#define FEC_CRC_POLY 0x04C11DB7
+
+#define FEC_MAX_MULTICAST_ADDRS 64
+
+/* Interrupt events/masks.
+*/
+#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */
+#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */
+#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */
+#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */
+#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */
+#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */
+#define FEC_ENET_RXF 0x02000000U /* Full frame received */
+#define FEC_ENET_RXB 0x01000000U /* A buffer was received */
+#define FEC_ENET_MII 0x00800000U /* MII interrupt */
+#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */
+
+#define FEC_ECNTRL_PINMUX 0x00000004
+#define FEC_ECNTRL_ETHER_EN 0x00000002
+#define FEC_ECNTRL_RESET 0x00000001
+
+#define FEC_RCNTRL_BC_REJ 0x00000010
+#define FEC_RCNTRL_PROM 0x00000008
+#define FEC_RCNTRL_MII_MODE 0x00000004
+#define FEC_RCNTRL_DRT 0x00000002
+#define FEC_RCNTRL_LOOP 0x00000001
+
+#define FEC_TCNTRL_FDEN 0x00000004
+#define FEC_TCNTRL_HBC 0x00000002
+#define FEC_TCNTRL_GTS 0x00000001
+
+
+
+/*
+ * Delay to wait for FEC reset command to complete (in us)
+ */
+#define FEC_RESET_DELAY 50
+#endif
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 196298f33db..34412bc7c4b 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -15,7 +15,6 @@
* kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -38,6 +37,7 @@
#include <linux/bitops.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
+#include <linux/phy.h>
#include <linux/vmalloc.h>
#include <asm/pgtable.h>
@@ -672,7 +672,7 @@ static int fs_request_irq(struct net_device *dev, int irq, const char *name,
struct fs_enet_private *fep = netdev_priv(dev);
(*fep->ops->pre_request_irq)(dev, irq);
- return request_irq(irq, irqf, SA_SHIRQ, name, dev);
+ return request_irq(irq, irqf, IRQF_SHARED, name, dev);
}
static void fs_free_irq(struct net_device *dev, int irq)
@@ -683,35 +683,6 @@ static void fs_free_irq(struct net_device *dev, int irq)
(*fep->ops->post_free_irq)(dev, irq);
}
-/**********************************************************************************/
-
-/* This interrupt occurs when the PHY detects a link change. */
-static irqreturn_t
-fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct net_device *dev = dev_id;
- struct fs_enet_private *fep;
- const struct fs_platform_info *fpi;
-
- fep = netdev_priv(dev);
- fpi = fep->fpi;
-
- /*
- * Acknowledge the interrupt if possible. If we have not
- * found the PHY yet we can't process or acknowledge the
- * interrupt now. Instead we ignore this interrupt for now,
- * which we can do since it is edge triggered. It will be
- * acknowledged later by fs_enet_open().
- */
- if (!fep->phy)
- return IRQ_NONE;
-
- fs_mii_ack_int(dev);
- fs_mii_link_status_change_check(dev, 0);
-
- return IRQ_HANDLED;
-}
-
static void fs_timeout(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -723,10 +694,13 @@ static void fs_timeout(struct net_device *dev)
spin_lock_irqsave(&fep->lock, flags);
if (dev->flags & IFF_UP) {
+ phy_stop(fep->phydev);
(*fep->ops->stop)(dev);
(*fep->ops->restart)(dev);
+ phy_start(fep->phydev);
}
+ phy_start(fep->phydev);
wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY);
spin_unlock_irqrestore(&fep->lock, flags);
@@ -734,35 +708,112 @@ static void fs_timeout(struct net_device *dev)
netif_wake_queue(dev);
}
+/*-----------------------------------------------------------------------------
+ * generic link-change handler - should be sufficient for most cases
+ *-----------------------------------------------------------------------------*/
+static void generic_adjust_link(struct net_device *dev)
+{
+ struct fs_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev = fep->phydev;
+ int new_state = 0;
+
+ if (phydev->link) {
+
+ /* adjust to duplex mode */
+ if (phydev->duplex != fep->oldduplex){
+ new_state = 1;
+ fep->oldduplex = phydev->duplex;
+ }
+
+ if (phydev->speed != fep->oldspeed) {
+ new_state = 1;
+ fep->oldspeed = phydev->speed;
+ }
+
+ if (!fep->oldlink) {
+ new_state = 1;
+ fep->oldlink = 1;
+ netif_schedule(dev);
+ netif_carrier_on(dev);
+ netif_start_queue(dev);
+ }
+
+ if (new_state)
+ fep->ops->restart(dev);
+
+ } else if (fep->oldlink) {
+ new_state = 1;
+ fep->oldlink = 0;
+ fep->oldspeed = 0;
+ fep->oldduplex = -1;
+ netif_carrier_off(dev);
+ netif_stop_queue(dev);
+ }
+
+ if (new_state && netif_msg_link(fep))
+ phy_print_status(phydev);
+}
+
+
+static void fs_adjust_link(struct net_device *dev)
+{
+ struct fs_enet_private *fep = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fep->lock, flags);
+
+ if(fep->ops->adjust_link)
+ fep->ops->adjust_link(dev);
+ else
+ generic_adjust_link(dev);
+
+ spin_unlock_irqrestore(&fep->lock, flags);
+}
+
+static int fs_init_phy(struct net_device *dev)
+{
+ struct fs_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phydev;
+
+ fep->oldlink = 0;
+ fep->oldspeed = 0;
+ fep->oldduplex = -1;
+ if(fep->fpi->bus_id)
+ phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0);
+ else {
+ printk("No phy bus ID specified in BSP code\n");
+ return -EINVAL;
+ }
+ if (IS_ERR(phydev)) {
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ fep->phydev = phydev;
+
+ return 0;
+}
+
+
static int fs_enet_open(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
int r;
+ int err;
/* Install our interrupt handler. */
r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
if (r != 0) {
printk(KERN_ERR DRV_MODULE_NAME
- ": %s Could not allocate FEC IRQ!", dev->name);
+ ": %s Could not allocate FS_ENET IRQ!", dev->name);
return -EINVAL;
}
- /* Install our phy interrupt handler */
- if (fpi->phy_irq != -1) {
-
- r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt);
- if (r != 0) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s Could not allocate PHY IRQ!", dev->name);
- fs_free_irq(dev, fep->interrupt);
- return -EINVAL;
- }
- }
+ err = fs_init_phy(dev);
+ if(err)
+ return err;
- fs_mii_startup(dev);
- netif_carrier_off(dev);
- fs_mii_link_status_change_check(dev, 1);
+ phy_start(fep->phydev);
return 0;
}
@@ -770,20 +821,19 @@ static int fs_enet_open(struct net_device *dev)
static int fs_enet_close(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
unsigned long flags;
netif_stop_queue(dev);
netif_carrier_off(dev);
- fs_mii_shutdown(dev);
+ phy_stop(fep->phydev);
spin_lock_irqsave(&fep->lock, flags);
(*fep->ops->stop)(dev);
spin_unlock_irqrestore(&fep->lock, flags);
/* release any irqs */
- if (fpi->phy_irq != -1)
- fs_free_irq(dev, fpi->phy_irq);
+ phy_disconnect(fep->phydev);
+ fep->phydev = NULL;
fs_free_irq(dev, fep->interrupt);
return 0;
@@ -831,33 +881,19 @@ static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct fs_enet_private *fep = netdev_priv(dev);
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&fep->lock, flags);
- rc = mii_ethtool_gset(&fep->mii_if, cmd);
- spin_unlock_irqrestore(&fep->lock, flags);
-
- return rc;
+ return phy_ethtool_gset(fep->phydev, cmd);
}
static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct fs_enet_private *fep = netdev_priv(dev);
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&fep->lock, flags);
- rc = mii_ethtool_sset(&fep->mii_if, cmd);
- spin_unlock_irqrestore(&fep->lock, flags);
-
- return rc;
+ phy_ethtool_sset(fep->phydev, cmd);
+ return 0;
}
static int fs_nway_reset(struct net_device *dev)
{
- struct fs_enet_private *fep = netdev_priv(dev);
- return mii_nway_restart(&fep->mii_if);
+ return 0;
}
static u32 fs_get_msglevel(struct net_device *dev)
@@ -872,7 +908,7 @@ static void fs_set_msglevel(struct net_device *dev, u32 value)
fep->msg_enable = value;
}
-static struct ethtool_ops fs_ethtool_ops = {
+static const struct ethtool_ops fs_ethtool_ops = {
.get_drvinfo = fs_get_drvinfo,
.get_regs_len = fs_get_regs_len,
.get_settings = fs_get_settings,
@@ -899,7 +935,7 @@ static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EINVAL;
spin_lock_irqsave(&fep->lock, flags);
- rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL);
+ rc = phy_mii_ioctl(fep->phydev, mii, cmd);
spin_unlock_irqrestore(&fep->lock, flags);
return rc;
}
@@ -1031,12 +1067,6 @@ static struct net_device *fs_init_instance(struct device *dev,
}
registered = 1;
- err = fs_mii_connect(ndev);
- if (err != 0) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s fs_mii_connect failed.\n", ndev->name);
- goto err;
- }
return ndev;
@@ -1074,8 +1104,6 @@ static int fs_cleanup_instance(struct net_device *ndev)
fpi = fep->fpi;
- fs_mii_disconnect(ndev);
-
unregister_netdev(ndev);
dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t),
@@ -1197,17 +1225,39 @@ static int __init fs_init(void)
r = setup_immap();
if (r != 0)
return r;
- r = driver_register(&fs_enet_fec_driver);
+
+#ifdef CONFIG_FS_ENET_HAS_FCC
+ /* let's insert mii stuff */
+ r = fs_enet_mdio_bb_init();
+
+ if (r != 0) {
+ printk(KERN_ERR DRV_MODULE_NAME
+ "BB PHY init failed.\n");
+ return r;
+ }
+ r = driver_register(&fs_enet_fcc_driver);
if (r != 0)
goto err;
+#endif
- r = driver_register(&fs_enet_fcc_driver);
+#ifdef CONFIG_FS_ENET_HAS_FEC
+ r = fs_enet_mdio_fec_init();
+ if (r != 0) {
+ printk(KERN_ERR DRV_MODULE_NAME
+ "FEC PHY init failed.\n");
+ return r;
+ }
+
+ r = driver_register(&fs_enet_fec_driver);
if (r != 0)
goto err;
+#endif
+#ifdef CONFIG_FS_ENET_HAS_SCC
r = driver_register(&fs_enet_scc_driver);
if (r != 0)
goto err;
+#endif
return 0;
err:
diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c
deleted file mode 100644
index c6770377ef8..00000000000
--- a/drivers/net/fs_enet/fs_enet-mii.c
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
- *
- * Copyright (c) 2003 Intracom S.A.
- * by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com>
- * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "fs_enet.h"
-
-/*************************************************/
-
-/*
- * Generic PHY support.
- * Should work for all PHYs, but link change is detected by polling
- */
-
-static void generic_timer_callback(unsigned long data)
-{
- struct net_device *dev = (struct net_device *)data;
- struct fs_enet_private *fep = netdev_priv(dev);
-
- fep->phy_timer_list.expires = jiffies + HZ / 2;
-
- add_timer(&fep->phy_timer_list);
-
- fs_mii_link_status_change_check(dev, 0);
-}
-
-static void generic_startup(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */
- fep->phy_timer_list.data = (unsigned long)dev;
- fep->phy_timer_list.function = generic_timer_callback;
- add_timer(&fep->phy_timer_list);
-}
-
-static void generic_shutdown(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- del_timer_sync(&fep->phy_timer_list);
-}
-
-/* ------------------------------------------------------------------------- */
-/* The Davicom DM9161 is used on the NETTA board */
-
-/* register definitions */
-
-#define MII_DM9161_ANAR 4 /* Aux. Config Register */
-#define MII_DM9161_ACR 16 /* Aux. Config Register */
-#define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */
-#define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */
-#define MII_DM9161_INTR 21 /* Interrupt Register */
-#define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */
-#define MII_DM9161_DISCR 23 /* Disconnect Counter Register */
-
-static void dm9161_startup(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000);
- /* Start autonegotiation */
- fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200);
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ*8);
-}
-
-static void dm9161_ack_int(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR);
-}
-
-static void dm9161_shutdown(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00);
-}
-
-/**********************************************************************************/
-
-static const struct phy_info phy_info[] = {
- {
- .id = 0x00181b88,
- .name = "DM9161",
- .startup = dm9161_startup,
- .ack_int = dm9161_ack_int,
- .shutdown = dm9161_shutdown,
- }, {
- .id = 0,
- .name = "GENERIC",
- .startup = generic_startup,
- .shutdown = generic_shutdown,
- },
-};
-
-/**********************************************************************************/
-
-static int phy_id_detect(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
- struct fs_enet_mii_bus *bus = fep->mii_bus;
- int i, r, start, end, phytype, physubtype;
- const struct phy_info *phy;
- int phy_hwid, phy_id;
-
- phy_hwid = -1;
- fep->phy = NULL;
-
- /* auto-detect? */
- if (fpi->phy_addr == -1) {
- start = 1;
- end = 32;
- } else { /* direct */
- start = fpi->phy_addr;
- end = start + 1;
- }
-
- for (phy_id = start; phy_id < end; phy_id++) {
- /* skip already used phy addresses on this bus */
- if (bus->usage_map & (1 << phy_id))
- continue;
- r = fs_mii_read(dev, phy_id, MII_PHYSID1);
- if (r == -1 || (phytype = (r & 0xffff)) == 0xffff)
- continue;
- r = fs_mii_read(dev, phy_id, MII_PHYSID2);
- if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff)
- continue;
- phy_hwid = (phytype << 16) | physubtype;
- if (phy_hwid != -1)
- break;
- }
-
- if (phy_hwid == -1) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s No PHY detected! range=0x%02x-0x%02x\n",
- dev->name, start, end);
- return -1;
- }
-
- for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++)
- if (phy->id == (phy_hwid >> 4) || phy->id == 0)
- break;
-
- if (i >= ARRAY_SIZE(phy_info)) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s PHY id 0x%08x is not supported!\n",
- dev->name, phy_hwid);
- return -1;
- }
-
- fep->phy = phy;
-
- /* mark this address as used */
- bus->usage_map |= (1 << phy_id);
-
- printk(KERN_INFO DRV_MODULE_NAME
- ": %s Phy @ 0x%x, type %s (0x%08x)%s\n",
- dev->name, phy_id, fep->phy->name, phy_hwid,
- fpi->phy_addr == -1 ? " (auto-detected)" : "");
-
- return phy_id;
-}
-
-void fs_mii_startup(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- if (fep->phy->startup)
- (*fep->phy->startup) (dev);
-}
-
-void fs_mii_shutdown(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- if (fep->phy->shutdown)
- (*fep->phy->shutdown) (dev);
-}
-
-void fs_mii_ack_int(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
-
- if (fep->phy->ack_int)
- (*fep->phy->ack_int) (dev);
-}
-
-#define MII_LINK 0x0001
-#define MII_HALF 0x0002
-#define MII_FULL 0x0004
-#define MII_BASE4 0x0008
-#define MII_10M 0x0010
-#define MII_100M 0x0020
-#define MII_1G 0x0040
-#define MII_10G 0x0080
-
-/* return full mii info at one gulp, with a usable form */
-static unsigned int mii_full_status(struct mii_if_info *mii)
-{
- unsigned int status;
- int bmsr, adv, lpa, neg;
- struct fs_enet_private* fep = netdev_priv(mii->dev);
-
- /* first, a dummy read, needed to latch some MII phys */
- (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
- bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
-
- /* no link */
- if ((bmsr & BMSR_LSTATUS) == 0)
- return 0;
-
- status = MII_LINK;
-
- /* Lets look what ANEG says if it's supported - otherwize we shall
- take the right values from the platform info*/
- if(!mii->force_media) {
- /* autoneg not completed; don't bother */
- if ((bmsr & BMSR_ANEGCOMPLETE) == 0)
- return 0;
-
- adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE);
- lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA);
-
- neg = lpa & adv;
- } else {
- neg = fep->fpi->bus_info->lpa;
- }
-
- if (neg & LPA_100FULL)
- status |= MII_FULL | MII_100M;
- else if (neg & LPA_100BASE4)
- status |= MII_FULL | MII_BASE4 | MII_100M;
- else if (neg & LPA_100HALF)
- status |= MII_HALF | MII_100M;
- else if (neg & LPA_10FULL)
- status |= MII_FULL | MII_10M;
- else
- status |= MII_HALF | MII_10M;
-
- return status;
-}
-
-void fs_mii_link_status_change_check(struct net_device *dev, int init_media)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- struct mii_if_info *mii = &fep->mii_if;
- unsigned int mii_status;
- int ok_to_print, link, duplex, speed;
- unsigned long flags;
-
- ok_to_print = netif_msg_link(fep);
-
- mii_status = mii_full_status(mii);
-
- if (!init_media && mii_status == fep->last_mii_status)
- return;
-
- fep->last_mii_status = mii_status;
-
- link = !!(mii_status & MII_LINK);
- duplex = !!(mii_status & MII_FULL);
- speed = (mii_status & MII_100M) ? 100 : 10;
-
- if (link == 0) {
- netif_carrier_off(mii->dev);
- netif_stop_queue(dev);
- if (!init_media) {
- spin_lock_irqsave(&fep->lock, flags);
- (*fep->ops->stop)(dev);
- spin_unlock_irqrestore(&fep->lock, flags);
- }
-
- if (ok_to_print)
- printk(KERN_INFO "%s: link down\n", mii->dev->name);
-
- } else {
-
- mii->full_duplex = duplex;
-
- netif_carrier_on(mii->dev);
-
- spin_lock_irqsave(&fep->lock, flags);
- fep->duplex = duplex;
- fep->speed = speed;
- (*fep->ops->restart)(dev);
- spin_unlock_irqrestore(&fep->lock, flags);
-
- netif_start_queue(dev);
-
- if (ok_to_print)
- printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n",
- dev->name, speed, duplex ? "full" : "half");
- }
-}
-
-/**********************************************************************************/
-
-int fs_mii_read(struct net_device *dev, int phy_id, int location)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- struct fs_enet_mii_bus *bus = fep->mii_bus;
-
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&bus->mii_lock, flags);
- ret = (*bus->mii_read)(bus, phy_id, location);
- spin_unlock_irqrestore(&bus->mii_lock, flags);
-
- return ret;
-}
-
-void fs_mii_write(struct net_device *dev, int phy_id, int location, int value)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- struct fs_enet_mii_bus *bus = fep->mii_bus;
- unsigned long flags;
-
- spin_lock_irqsave(&bus->mii_lock, flags);
- (*bus->mii_write)(bus, phy_id, location, value);
- spin_unlock_irqrestore(&bus->mii_lock, flags);
-}
-
-/*****************************************************************************/
-
-/* list of all registered mii buses */
-static LIST_HEAD(fs_mii_bus_list);
-
-static struct fs_enet_mii_bus *lookup_bus(int method, int id)
-{
- struct list_head *ptr;
- struct fs_enet_mii_bus *bus;
-
- list_for_each(ptr, &fs_mii_bus_list) {
- bus = list_entry(ptr, struct fs_enet_mii_bus, list);
- if (bus->bus_info->method == method &&
- bus->bus_info->id == id)
- return bus;
- }
- return NULL;
-}
-
-static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi)
-{
- struct fs_enet_mii_bus *bus;
- int ret = 0;
-
- bus = kmalloc(sizeof(*bus), GFP_KERNEL);
- if (bus == NULL) {
- ret = -ENOMEM;
- goto err;
- }
- memset(bus, 0, sizeof(*bus));
- spin_lock_init(&bus->mii_lock);
- bus->bus_info = bi;
- bus->refs = 0;
- bus->usage_map = 0;
-
- /* perform initialization */
- switch (bi->method) {
-
- case fsmii_fixed:
- ret = fs_mii_fixed_init(bus);
- if (ret != 0)
- goto err;
- break;
-
- case fsmii_bitbang:
- ret = fs_mii_bitbang_init(bus);
- if (ret != 0)
- goto err;
- break;
-#ifdef CONFIG_FS_ENET_HAS_FEC
- case fsmii_fec:
- ret = fs_mii_fec_init(bus);
- if (ret != 0)
- goto err;
- break;
-#endif
- default:
- ret = -EINVAL;
- goto err;
- }
-
- list_add(&bus->list, &fs_mii_bus_list);
-
- return bus;
-
-err:
- if (bus)
- kfree(bus);
- return ERR_PTR(ret);
-}
-
-static void destroy_bus(struct fs_enet_mii_bus *bus)
-{
- /* remove from bus list */
- list_del(&bus->list);
-
- /* nothing more needed */
- kfree(bus);
-}
-
-int fs_mii_connect(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- const struct fs_platform_info *fpi = fep->fpi;
- struct fs_enet_mii_bus *bus = NULL;
-
- /* check method validity */
- switch (fpi->bus_info->method) {
- case fsmii_fixed:
- case fsmii_bitbang:
- break;
-#ifdef CONFIG_FS_ENET_HAS_FEC
- case fsmii_fec:
- break;
-#endif
- default:
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s Unknown MII bus method (%d)!\n",
- dev->name, fpi->bus_info->method);
- return -EINVAL;
- }
-
- bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id);
-
- /* if not found create new bus */
- if (bus == NULL) {
- bus = create_bus(fpi->bus_info);
- if (IS_ERR(bus)) {
- printk(KERN_ERR DRV_MODULE_NAME
- ": %s MII bus creation failure!\n", dev->name);
- return PTR_ERR(bus);
- }
- }
-
- bus->refs++;
-
- fep->mii_bus = bus;
-
- fep->mii_if.dev = dev;
- fep->mii_if.phy_id_mask = 0x1f;
- fep->mii_if.reg_num_mask = 0x1f;
- fep->mii_if.mdio_read = fs_mii_read;
- fep->mii_if.mdio_write = fs_mii_write;
- fep->mii_if.force_media = fpi->bus_info->disable_aneg;
- fep->mii_if.phy_id = phy_id_detect(dev);
-
- return 0;
-}
-
-void fs_mii_disconnect(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- struct fs_enet_mii_bus *bus = NULL;
-
- bus = fep->mii_bus;
- fep->mii_bus = NULL;
-
- if (--bus->refs <= 0)
- destroy_bus(bus);
-}
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index e7ec96c964a..92590d8fc24 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -5,19 +5,37 @@
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/phy.h>
+#include <linux/dma-mapping.h>
#include <linux/fs_enet_pd.h>
-#include <asm/dma-mapping.h>
-
#ifdef CONFIG_CPM1
#include <asm/commproc.h>
+
+struct fec_info {
+ fec_t* fecp;
+ u32 mii_speed;
+};
#endif
#ifdef CONFIG_CPM2
#include <asm/cpm2.h>
#endif
+/* This is used to operate with pins.
+ Note that the actual port size may
+ be different; cpm(s) handle it OK */
+struct bb_info {
+ u8 mdio_dat_msk;
+ u8 mdio_dir_msk;
+ u8 *mdio_dir;
+ u8 *mdio_dat;
+ u8 mdc_msk;
+ u8 *mdc_dat;
+ int delay;
+};
+
/* hw driver ops */
struct fs_ops {
int (*setup_data)(struct net_device *dev);
@@ -25,6 +43,7 @@ struct fs_ops {
void (*free_bd)(struct net_device *dev);
void (*cleanup_data)(struct net_device *dev);
void (*set_multicast_list)(struct net_device *dev);
+ void (*adjust_link)(struct net_device *dev);
void (*restart)(struct net_device *dev);
void (*stop)(struct net_device *dev);
void (*pre_request_irq)(struct net_device *dev, int irq);
@@ -100,10 +119,6 @@ struct fs_enet_mii_bus {
};
};
-int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus);
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
-int fs_mii_fec_init(struct fs_enet_mii_bus *bus);
-
struct fs_enet_private {
struct device *dev; /* pointer back to the device (must be initialized first) */
spinlock_t lock; /* during all ops except TX pckt processing */
@@ -130,7 +145,8 @@ struct fs_enet_private {
struct fs_enet_mii_bus *mii_bus;
int interrupt;
- int duplex, speed; /* current settings */
+ struct phy_device *phydev;
+ int oldduplex, oldspeed, oldlink; /* current settings */
/* event masks */
u32 ev_napi_rx; /* mask of NAPI rx events */
@@ -168,15 +184,9 @@ struct fs_enet_private {
};
/***************************************************************************/
-
-int fs_mii_read(struct net_device *dev, int phy_id, int location);
-void fs_mii_write(struct net_device *dev, int phy_id, int location, int value);
-
-void fs_mii_startup(struct net_device *dev);
-void fs_mii_shutdown(struct net_device *dev);
-void fs_mii_ack_int(struct net_device *dev);
-
-void fs_mii_link_status_change_check(struct net_device *dev, int init_media);
+int fs_enet_mdio_bb_init(void);
+int fs_mii_fixed_init(struct fs_enet_mii_bus *bus);
+int fs_enet_mdio_fec_init(void);
void fs_init_bds(struct net_device *dev);
void fs_cleanup_bds(struct net_device *dev);
@@ -194,7 +204,6 @@ int fs_enet_platform_init(void);
void fs_enet_platform_cleanup(void);
/***************************************************************************/
-
/* buffer descriptor access macros */
/* access macros */
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c
index 95e2bb8dd7b..1ff2597b849 100644
--- a/drivers/net/fs_enet/mac-fcc.c
+++ b/drivers/net/fs_enet/mac-fcc.c
@@ -12,7 +12,6 @@
* kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -35,6 +34,7 @@
#include <linux/bitops.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
+#include <linux/phy.h>
#include <asm/immap_cpm2.h>
#include <asm/mpc8260.h>
@@ -123,22 +123,32 @@ static int do_pd_setup(struct fs_enet_private *fep)
/* Attach the memory for the FCC Parameter RAM */
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram");
- fep->fcc.ep = (void *)r->start;
-
+ fep->fcc.ep = (void *)ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.ep == NULL)
return -EINVAL;
r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs");
- fep->fcc.fccp = (void *)r->start;
-
+ fep->fcc.fccp = (void *)ioremap(r->start, r->end - r->start + 1);
if (fep->fcc.fccp == NULL)
return -EINVAL;
- fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+ if (fep->fpi->fcc_regs_c) {
+
+ fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c;
+ } else {
+ r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "fcc_regs_c");
+ fep->fcc.fcccp = (void *)ioremap(r->start,
+ r->end - r->start + 1);
+ }
if (fep->fcc.fcccp == NULL)
return -EINVAL;
+ fep->fcc.mem = (void *)fep->fpi->mem_offset;
+ if (fep->fcc.mem == NULL)
+ return -EINVAL;
+
return 0;
}
@@ -156,8 +166,6 @@ static int setup_data(struct net_device *dev)
if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */
return -EINVAL;
- fep->fcc.mem = (void *)fpi->mem_offset;
-
if (do_pd_setup(fep) != 0)
return -EINVAL;
@@ -395,7 +403,7 @@ static void restart(struct net_device *dev)
/* adjust to speed (for RMII mode) */
if (fpi->use_rmii) {
- if (fep->speed == 100)
+ if (fep->phydev->speed == 100)
C8(fcccp, fcc_gfemr, 0x20);
else
S8(fcccp, fcc_gfemr, 0x20);
@@ -421,7 +429,7 @@ static void restart(struct net_device *dev)
S32(fccp, fcc_fpsmr, FCC_PSMR_RMII);
/* adjust to duplex mode */
- if (fep->duplex)
+ if (fep->phydev->duplex)
S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
else
C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB);
@@ -487,7 +495,10 @@ static void rx_bd_done(struct net_device *dev)
static void tx_kickstart(struct net_device *dev)
{
- /* nothing */
+ struct fs_enet_private *fep = netdev_priv(dev);
+ fcc_t *fccp = fep->fcc.fccp;
+
+ S32(fccp, fcc_ftodr, 0x80);
}
static u32 get_int_events(struct net_device *dev)
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c
index 3dad69dfdb2..c2c5fd419bd 100644
--- a/drivers/net/fs_enet/mac-fec.c
+++ b/drivers/net/fs_enet/mac-fec.c
@@ -12,7 +12,6 @@
* kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -47,6 +46,7 @@
#endif
#include "fs_enet.h"
+#include "fec.h"
/*************************************************/
@@ -76,50 +76,8 @@
/* clear bits */
#define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v))
-
-/* CRC polynomium used by the FEC for the multicast group filtering */
-#define FEC_CRC_POLY 0x04C11DB7
-
-#define FEC_MAX_MULTICAST_ADDRS 64
-
-/* Interrupt events/masks.
-*/
-#define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */
-#define FEC_ENET_BABR 0x40000000U /* Babbling receiver */
-#define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */
-#define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */
-#define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */
-#define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */
-#define FEC_ENET_RXF 0x02000000U /* Full frame received */
-#define FEC_ENET_RXB 0x01000000U /* A buffer was received */
-#define FEC_ENET_MII 0x00800000U /* MII interrupt */
-#define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */
-
-#define FEC_ECNTRL_PINMUX 0x00000004
-#define FEC_ECNTRL_ETHER_EN 0x00000002
-#define FEC_ECNTRL_RESET 0x00000001
-
-#define FEC_RCNTRL_BC_REJ 0x00000010
-#define FEC_RCNTRL_PROM 0x00000008
-#define FEC_RCNTRL_MII_MODE 0x00000004
-#define FEC_RCNTRL_DRT 0x00000002
-#define FEC_RCNTRL_LOOP 0x00000001
-
-#define FEC_TCNTRL_FDEN 0x00000004
-#define FEC_TCNTRL_HBC 0x00000002
-#define FEC_TCNTRL_GTS 0x00000001
-
-
-/* Make MII read/write commands for the FEC.
-*/
-#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
-#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
-#define mk_mii_end 0
-
-#define FEC_MII_LOOPS 10000
-
/*
- * Delay to wait for FEC reset command to complete (in us)
+ * Delay to wait for FEC reset command to complete (in us)
*/
#define FEC_RESET_DELAY 50
@@ -304,13 +262,15 @@ static void restart(struct net_device *dev)
int r;
u32 addrhi, addrlo;
+ struct mii_bus* mii = fep->phydev->bus;
+ struct fec_info* fec_inf = mii->priv;
+
r = whack_reset(fep->fec.fecp);
if (r != 0)
printk(KERN_ERR DRV_MODULE_NAME
": %s FEC Reset FAILED!\n", dev->name);
-
/*
- * Set station address.
+ * Set station address.
*/
addrhi = ((u32) dev->dev_addr[0] << 24) |
((u32) dev->dev_addr[1] << 16) |
@@ -351,12 +311,12 @@ static void restart(struct net_device *dev)
FW(fecp, fun_code, 0x78000000);
/*
- * Set MII speed.
+ * Set MII speed.
*/
- FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed);
+ FW(fecp, mii_speed, fec_inf->mii_speed);
/*
- * Clear any outstanding interrupt.
+ * Clear any outstanding interrupt.
*/
FW(fecp, ievent, 0xffc0);
FW(fecp, ivec, (fep->interrupt / 2) << 29);
@@ -391,11 +351,12 @@ static void restart(struct net_device *dev)
}
#endif
+
FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
/*
- * adjust to duplex mode
+ * adjust to duplex mode
*/
- if (fep->duplex) {
+ if (fep->phydev->duplex) {
FC(fecp, r_cntrl, FEC_RCNTRL_DRT);
FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */
} else {
@@ -419,9 +380,11 @@ static void restart(struct net_device *dev)
static void stop(struct net_device *dev)
{
struct fs_enet_private *fep = netdev_priv(dev);
+ const struct fs_platform_info *fpi = fep->fpi;
fec_t *fecp = fep->fec.fecp;
- struct fs_enet_mii_bus *bus = fep->mii_bus;
- const struct fs_mii_bus_info *bi = bus->bus_info;
+
+ struct fec_info* feci= fep->phydev->bus->priv;
+
int i;
if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0)
@@ -445,11 +408,11 @@ static void stop(struct net_device *dev)
fs_cleanup_bds(dev);
/* shut down FEC1? that's where the mii bus is */
- if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) {
+ if (fpi->has_phy) {
FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
FW(fecp, ievent, FEC_ENET_MII);
- FW(fecp, mii_speed, bus->fec.mii_speed);
+ FW(fecp, mii_speed, feci->mii_speed);
}
}
@@ -584,73 +547,3 @@ const struct fs_ops fs_fec_ops = {
.free_bd = free_bd,
};
-/***********************************************************************/
-
-static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
-{
- fec_t *fecp = bus->fec.fecp;
- int i, ret = -1;
-
- if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
- BUG();
-
- /* Add PHY address to register command. */
- FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location));
-
- for (i = 0; i < FEC_MII_LOOPS; i++)
- if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
- break;
-
- if (i < FEC_MII_LOOPS) {
- FW(fecp, ievent, FEC_ENET_MII);
- ret = FR(fecp, mii_data) & 0xffff;
- }
-
- return ret;
-}
-
-static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value)
-{
- fec_t *fecp = bus->fec.fecp;
- int i;
-
- /* this must never happen */
- if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
- BUG();
-
- /* Add PHY address to register command. */
- FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value));
-
- for (i = 0; i < FEC_MII_LOOPS; i++)
- if ((FR(fecp, ievent) & FEC_ENET_MII) != 0)
- break;
-
- if (i < FEC_MII_LOOPS)
- FW(fecp, ievent, FEC_ENET_MII);
-}
-
-int fs_mii_fec_init(struct fs_enet_mii_bus *bus)
-{
- bd_t *bd = (bd_t *)__res;
- const struct fs_mii_bus_info *bi = bus->bus_info;
- fec_t *fecp;
-
- if (bi->id != 0)
- return -1;
-
- bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec;
- bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2)
- & 0x3F) << 1;
-
- fecp = bus->fec.fecp;
-
- FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
- FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
- FW(fecp, ievent, FEC_ENET_MII);
- FW(fecp, mii_speed, bus->fec.mii_speed);
-
- bus->mii_read = mii_read;
- bus->mii_write = mii_write;
-
- return 0;
-}
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c
index a772b286f96..95ec5872c50 100644
--- a/drivers/net/fs_enet/mac-scc.c
+++ b/drivers/net/fs_enet/mac-scc.c
@@ -12,7 +12,6 @@
* kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -370,7 +369,7 @@ static void restart(struct net_device *dev)
W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22);
/* Set full duplex mode if needed */
- if (fep->duplex)
+ if (fep->phydev->duplex)
S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE);
S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT);
@@ -501,6 +500,8 @@ static void tx_restart(struct net_device *dev)
scc_cr_cmd(fep, CPM_CR_RESTART_TX);
}
+
+
/*************************************************************************/
const struct fs_ops fs_scc_ops = {
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 24a5e2e23d1..0b9b8b5c847 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -13,7 +13,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -34,6 +33,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/platform_device.h>
#include <asm/pgtable.h>
#include <asm/irq.h>
@@ -41,129 +41,25 @@
#include "fs_enet.h"
-#ifdef CONFIG_8xx
-static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
+static int bitbang_prep_bit(u8 **datp, u8 *mskp,
+ struct fs_mii_bit *mii_bit)
{
- immap_t *im = (immap_t *)fs_enet_immap;
- void *dir, *dat, *ppar;
+ void *dat;
int adv;
u8 msk;
- switch (port) {
- case fsiop_porta:
- dir = &im->im_ioport.iop_padir;
- dat = &im->im_ioport.iop_padat;
- ppar = &im->im_ioport.iop_papar;
- break;
-
- case fsiop_portb:
- dir = &im->im_cpm.cp_pbdir;
- dat = &im->im_cpm.cp_pbdat;
- ppar = &im->im_cpm.cp_pbpar;
- break;
-
- case fsiop_portc:
- dir = &im->im_ioport.iop_pcdir;
- dat = &im->im_ioport.iop_pcdat;
- ppar = &im->im_ioport.iop_pcpar;
- break;
-
- case fsiop_portd:
- dir = &im->im_ioport.iop_pddir;
- dat = &im->im_ioport.iop_pddat;
- ppar = &im->im_ioport.iop_pdpar;
- break;
-
- case fsiop_porte:
- dir = &im->im_cpm.cp_pedir;
- dat = &im->im_cpm.cp_pedat;
- ppar = &im->im_cpm.cp_pepar;
- break;
-
- default:
- printk(KERN_ERR DRV_MODULE_NAME
- "Illegal port value %d!\n", port);
- return -EINVAL;
- }
-
- adv = bit >> 3;
- dir = (char *)dir + adv;
- dat = (char *)dat + adv;
- ppar = (char *)ppar + adv;
-
- msk = 1 << (7 - (bit & 7));
- if ((in_8(ppar) & msk) != 0) {
- printk(KERN_ERR DRV_MODULE_NAME
- "pin %d on port %d is not general purpose!\n", bit, port);
- return -EINVAL;
- }
-
- *dirp = dir;
- *datp = dat;
- *mskp = msk;
-
- return 0;
-}
-#endif
-
-#ifdef CONFIG_8260
-static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit)
-{
- iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport;
- void *dir, *dat, *ppar;
- int adv;
- u8 msk;
-
- switch (port) {
- case fsiop_porta:
- dir = &io->iop_pdira;
- dat = &io->iop_pdata;
- ppar = &io->iop_ppara;
- break;
-
- case fsiop_portb:
- dir = &io->iop_pdirb;
- dat = &io->iop_pdatb;
- ppar = &io->iop_pparb;
- break;
-
- case fsiop_portc:
- dir = &io->iop_pdirc;
- dat = &io->iop_pdatc;
- ppar = &io->iop_pparc;
- break;
-
- case fsiop_portd:
- dir = &io->iop_pdird;
- dat = &io->iop_pdatd;
- ppar = &io->iop_ppard;
- break;
-
- default:
- printk(KERN_ERR DRV_MODULE_NAME
- "Illegal port value %d!\n", port);
- return -EINVAL;
- }
+ dat = (void*) mii_bit->offset;
- adv = bit >> 3;
- dir = (char *)dir + adv;
+ adv = mii_bit->bit >> 3;
dat = (char *)dat + adv;
- ppar = (char *)ppar + adv;
- msk = 1 << (7 - (bit & 7));
- if ((in_8(ppar) & msk) != 0) {
- printk(KERN_ERR DRV_MODULE_NAME
- "pin %d on port %d is not general purpose!\n", bit, port);
- return -EINVAL;
- }
+ msk = 1 << (7 - (mii_bit->bit & 7));
- *dirp = dir;
*datp = dat;
*mskp = msk;
return 0;
}
-#endif
static inline void bb_set(u8 *p, u8 m)
{
@@ -180,44 +76,44 @@ static inline int bb_read(u8 *p, u8 m)
return (in_8(p) & m) != 0;
}
-static inline void mdio_active(struct fs_enet_mii_bus *bus)
+static inline void mdio_active(struct bb_info *bitbang)
{
- bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);
+ bb_set(bitbang->mdio_dir, bitbang->mdio_dir_msk);
}
-static inline void mdio_tristate(struct fs_enet_mii_bus *bus)
+static inline void mdio_tristate(struct bb_info *bitbang )
{
- bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk);
+ bb_clr(bitbang->mdio_dir, bitbang->mdio_dir_msk);
}
-static inline int mdio_read(struct fs_enet_mii_bus *bus)
+static inline int mdio_read(struct bb_info *bitbang )
{
- return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+ return bb_read(bitbang->mdio_dat, bitbang->mdio_dat_msk);
}
-static inline void mdio(struct fs_enet_mii_bus *bus, int what)
+static inline void mdio(struct bb_info *bitbang , int what)
{
if (what)
- bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+ bb_set(bitbang->mdio_dat, bitbang->mdio_dat_msk);
else
- bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk);
+ bb_clr(bitbang->mdio_dat, bitbang->mdio_dat_msk);
}
-static inline void mdc(struct fs_enet_mii_bus *bus, int what)
+static inline void mdc(struct bb_info *bitbang , int what)
{
if (what)
- bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);
+ bb_set(bitbang->mdc_dat, bitbang->mdc_msk);
else
- bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk);
+ bb_clr(bitbang->mdc_dat, bitbang->mdc_msk);
}
-static inline void mii_delay(struct fs_enet_mii_bus *bus)
+static inline void mii_delay(struct bb_info *bitbang )
{
- udelay(bus->bus_info->i.bitbang.delay);
+ udelay(bitbang->delay);
}
/* Utility to send the preamble, address, and register (common to read and write). */
-static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg)
+static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg)
{
int j;
@@ -229,177 +125,284 @@ static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg)
* but it is safer and will be much more robust.
*/
- mdio_active(bus);
- mdio(bus, 1);
+ mdio_active(bitbang);
+ mdio(bitbang, 1);
for (j = 0; j < 32; j++) {
- mdc(bus, 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
}
/* send the start bit (01) and the read opcode (10) or write (10) */
- mdc(bus, 0);
- mdio(bus, 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
- mdc(bus, 0);
- mdio(bus, 1);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
- mdc(bus, 0);
- mdio(bus, read);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
- mdc(bus, 0);
- mdio(bus, !read);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mdio(bitbang, 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 0);
+ mdio(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 0);
+ mdio(bitbang, read);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 0);
+ mdio(bitbang, !read);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
/* send the PHY address */
for (j = 0; j < 5; j++) {
- mdc(bus, 0);
- mdio(bus, (addr & 0x10) != 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mdio(bitbang, (addr & 0x10) != 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
addr <<= 1;
}
/* send the register address */
for (j = 0; j < 5; j++) {
- mdc(bus, 0);
- mdio(bus, (reg & 0x10) != 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mdio(bitbang, (reg & 0x10) != 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
reg <<= 1;
}
}
-static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
+static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location)
{
u16 rdreg;
int ret, j;
u8 addr = phy_id & 0xff;
u8 reg = location & 0xff;
+ struct bb_info* bitbang = bus->priv;
- bitbang_pre(bus, 1, addr, reg);
+ bitbang_pre(bitbang, 1, addr, reg);
/* tri-state our MDIO I/O pin so we can read */
- mdc(bus, 0);
- mdio_tristate(bus);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mdio_tristate(bitbang);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
/* check the turnaround bit: the PHY should be driving it to zero */
- if (mdio_read(bus) != 0) {
+ if (mdio_read(bitbang) != 0) {
/* PHY didn't drive TA low */
for (j = 0; j < 32; j++) {
- mdc(bus, 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
}
ret = -1;
goto out;
}
- mdc(bus, 0);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mii_delay(bitbang);
/* read 16 bits of register data, MSB first */
rdreg = 0;
for (j = 0; j < 16; j++) {
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
rdreg <<= 1;
- rdreg |= mdio_read(bus);
- mdc(bus, 0);
- mii_delay(bus);
+ rdreg |= mdio_read(bitbang);
+ mdc(bitbang, 0);
+ mii_delay(bitbang);
}
- mdc(bus, 1);
- mii_delay(bus);
- mdc(bus, 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
ret = rdreg;
out:
return ret;
}
-static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
+static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val)
{
int j;
+ struct bb_info* bitbang = bus->priv;
+
u8 addr = phy_id & 0xff;
u8 reg = location & 0xff;
u16 value = val & 0xffff;
- bitbang_pre(bus, 0, addr, reg);
+ bitbang_pre(bitbang, 0, addr, reg);
/* send the turnaround (10) */
- mdc(bus, 0);
- mdio(bus, 1);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
- mdc(bus, 0);
- mdio(bus, 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mdio(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
+ mdc(bitbang, 0);
+ mdio(bitbang, 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
/* write 16 bits of register data, MSB first */
for (j = 0; j < 16; j++) {
- mdc(bus, 0);
- mdio(bus, (value & 0x8000) != 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdc(bitbang, 0);
+ mdio(bitbang, (value & 0x8000) != 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
value <<= 1;
}
/*
* Tri-state the MDIO line.
*/
- mdio_tristate(bus);
- mdc(bus, 0);
- mii_delay(bus);
- mdc(bus, 1);
- mii_delay(bus);
+ mdio_tristate(bitbang);
+ mdc(bitbang, 0);
+ mii_delay(bitbang);
+ mdc(bitbang, 1);
+ mii_delay(bitbang);
+ return 0;
}
-int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus)
+static int fs_enet_mii_bb_reset(struct mii_bus *bus)
+{
+ /*nothing here - dunno how to reset it*/
+ return 0;
+}
+
+static int fs_mii_bitbang_init(struct bb_info *bitbang, struct fs_mii_bb_platform_info* fmpi)
{
- const struct fs_mii_bus_info *bi = bus->bus_info;
int r;
- r = bitbang_prep_bit(&bus->bitbang.mdio_dir,
- &bus->bitbang.mdio_dat,
- &bus->bitbang.mdio_msk,
- bi->i.bitbang.mdio_port,
- bi->i.bitbang.mdio_bit);
+ bitbang->delay = fmpi->delay;
+
+ r = bitbang_prep_bit(&bitbang->mdio_dir,
+ &bitbang->mdio_dir_msk,
+ &fmpi->mdio_dir);
if (r != 0)
return r;
- r = bitbang_prep_bit(&bus->bitbang.mdc_dir,
- &bus->bitbang.mdc_dat,
- &bus->bitbang.mdc_msk,
- bi->i.bitbang.mdc_port,
- bi->i.bitbang.mdc_bit);
+ r = bitbang_prep_bit(&bitbang->mdio_dat,
+ &bitbang->mdio_dat_msk,
+ &fmpi->mdio_dat);
if (r != 0)
return r;
- bus->mii_read = mii_read;
- bus->mii_write = mii_write;
+ r = bitbang_prep_bit(&bitbang->mdc_dat,
+ &bitbang->mdc_msk,
+ &fmpi->mdc_dat);
+ if (r != 0)
+ return r;
return 0;
}
+
+
+static int __devinit fs_enet_mdio_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fs_mii_bb_platform_info *pdata;
+ struct mii_bus *new_bus;
+ struct bb_info *bitbang;
+ int err = 0;
+
+ if (NULL == dev)
+ return -EINVAL;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus)
+ return -ENOMEM;
+
+ bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
+
+ if (NULL == bitbang)
+ return -ENOMEM;
+
+ new_bus->name = "BB MII Bus",
+ new_bus->read = &fs_enet_mii_bb_read,
+ new_bus->write = &fs_enet_mii_bb_write,
+ new_bus->reset = &fs_enet_mii_bb_reset,
+ new_bus->id = pdev->id;
+
+ new_bus->phy_mask = ~0x9;
+ pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data;
+
+ if (NULL == pdata) {
+ printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id);
+ return -ENODEV;
+ }
+
+ /*set up workspace*/
+ fs_mii_bitbang_init(bitbang, pdata);
+
+ new_bus->priv = bitbang;
+
+ new_bus->irq = pdata->irq;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+ printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+ new_bus->name);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ kfree(bitbang);
+ kfree(new_bus);
+
+ return err;
+}
+
+
+static int fs_enet_mdio_remove(struct device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(dev);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(dev, NULL);
+
+ iounmap((void *) (&bus->priv));
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct device_driver fs_enet_bb_mdio_driver = {
+ .name = "fsl-bb-mdio",
+ .bus = &platform_bus_type,
+ .probe = fs_enet_mdio_probe,
+ .remove = fs_enet_mdio_remove,
+};
+
+int fs_enet_mdio_bb_init(void)
+{
+ return driver_register(&fs_enet_bb_mdio_driver);
+}
+
+void fs_enet_mdio_bb_exit(void)
+{
+ driver_unregister(&fs_enet_bb_mdio_driver);
+}
+
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
new file mode 100644
index 00000000000..1328e10caa3
--- /dev/null
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -0,0 +1,243 @@
+/*
+ * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
+ *
+ * Copyright (c) 2003 Intracom S.A.
+ * by Pantelis Antoniou <panto@intracom.gr>
+ *
+ * 2005 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "fs_enet.h"
+#include "fec.h"
+
+/* Make MII read/write commands for the FEC.
+*/
+#define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18))
+#define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff))
+#define mk_mii_end 0
+
+#define FEC_MII_LOOPS 10000
+
+static int match_has_phy (struct device *dev, void* data)
+{
+ struct platform_device* pdev = container_of(dev, struct platform_device, dev);
+ struct fs_platform_info* fpi;
+ if(strcmp(pdev->name, (char*)data))
+ {
+ return 0;
+ }
+
+ fpi = pdev->dev.platform_data;
+ if((fpi)&&(fpi->has_phy))
+ return 1;
+ return 0;
+}
+
+static int fs_mii_fec_init(struct fec_info* fec, struct fs_mii_fec_platform_info *fmpi)
+{
+ struct resource *r;
+ fec_t *fecp;
+ char* name = "fsl-cpm-fec";
+
+ /* we need fec in order to be useful */
+ struct platform_device *fec_pdev =
+ container_of(bus_find_device(&platform_bus_type, NULL, name, match_has_phy),
+ struct platform_device, dev);
+
+ if(fec_pdev == NULL) {
+ printk(KERN_ERR"Unable to find PHY for %s", name);
+ return -ENODEV;
+ }
+
+ r = platform_get_resource_byname(fec_pdev, IORESOURCE_MEM, "regs");
+
+ fec->fecp = fecp = (fec_t*)ioremap(r->start,sizeof(fec_t));
+ fec->mii_speed = fmpi->mii_speed;
+
+ setbits32(&fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */
+ setbits32(&fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN);
+ out_be32(&fecp->fec_ievent, FEC_ENET_MII);
+ out_be32(&fecp->fec_mii_speed, fec->mii_speed);
+
+ return 0;
+}
+
+static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location)
+{
+ struct fec_info* fec = bus->priv;
+ fec_t *fecp = fec->fecp;
+ int i, ret = -1;
+
+ if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+ BUG();
+
+ /* Add PHY address to register command. */
+ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location));
+
+ for (i = 0; i < FEC_MII_LOOPS; i++)
+ if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0)
+ break;
+
+ if (i < FEC_MII_LOOPS) {
+ out_be32(&fecp->fec_ievent, FEC_ENET_MII);
+ ret = in_be32(&fecp->fec_mii_data) & 0xffff;
+ }
+
+ return ret;
+
+}
+
+static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+ struct fec_info* fec = bus->priv;
+ fec_t *fecp = fec->fecp;
+ int i;
+
+ /* this must never happen */
+ if ((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0)
+ BUG();
+
+ /* Add PHY address to register command. */
+ out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val));
+
+ for (i = 0; i < FEC_MII_LOOPS; i++)
+ if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0)
+ break;
+
+ if (i < FEC_MII_LOOPS)
+ out_be32(&fecp->fec_ievent, FEC_ENET_MII);
+
+ return 0;
+
+}
+
+static int fs_enet_fec_mii_reset(struct mii_bus *bus)
+{
+ /* nothing here - for now */
+ return 0;
+}
+
+static int __devinit fs_enet_fec_mdio_probe(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct fs_mii_fec_platform_info *pdata;
+ struct mii_bus *new_bus;
+ struct fec_info *fec;
+ int err = 0;
+ if (NULL == dev)
+ return -EINVAL;
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus)
+ return -ENOMEM;
+
+ fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL);
+
+ if (NULL == fec)
+ return -ENOMEM;
+
+ new_bus->name = "FEC MII Bus",
+ new_bus->read = &fs_enet_fec_mii_read,
+ new_bus->write = &fs_enet_fec_mii_write,
+ new_bus->reset = &fs_enet_fec_mii_reset,
+ new_bus->id = pdev->id;
+
+ pdata = (struct fs_mii_fec_platform_info *)pdev->dev.platform_data;
+
+ if (NULL == pdata) {
+ printk(KERN_ERR "fs_enet FEC mdio %d: Missing platform data!\n", pdev->id);
+ return -ENODEV;
+ }
+
+ /*set up workspace*/
+
+ fs_mii_fec_init(fec, pdata);
+ new_bus->priv = fec;
+
+ new_bus->irq = pdata->irq;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ err = mdiobus_register(new_bus);
+
+ if (0 != err) {
+ printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+ new_bus->name);
+ goto bus_register_fail;
+ }
+
+ return 0;
+
+bus_register_fail:
+ kfree(new_bus);
+
+ return err;
+}
+
+
+static int fs_enet_fec_mdio_remove(struct device *dev)
+{
+ struct mii_bus *bus = dev_get_drvdata(dev);
+
+ mdiobus_unregister(bus);
+
+ dev_set_drvdata(dev, NULL);
+ kfree(bus->priv);
+
+ bus->priv = NULL;
+ kfree(bus);
+
+ return 0;
+}
+
+static struct device_driver fs_enet_fec_mdio_driver = {
+ .name = "fsl-cpm-fec-mdio",
+ .bus = &platform_bus_type,
+ .probe = fs_enet_fec_mdio_probe,
+ .remove = fs_enet_fec_mdio_remove,
+};
+
+int fs_enet_mdio_fec_init(void)
+{
+ return driver_register(&fs_enet_fec_mdio_driver);
+}
+
+void fs_enet_mdio_fec_exit(void)
+{
+ driver_unregister(&fs_enet_fec_mdio_driver);
+}
+
diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c
deleted file mode 100644
index b3e192d612e..00000000000
--- a/drivers/net/fs_enet/mii-fixed.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
- *
- * Copyright (c) 2003 Intracom S.A.
- * by Pantelis Antoniou <panto@intracom.gr>
- *
- * 2005 (c) MontaVista Software, Inc.
- * Vitaly Bordug <vbordug@ru.mvista.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mii.h>
-#include <linux/ethtool.h>
-#include <linux/bitops.h>
-
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "fs_enet.h"
-
-static const u16 mii_regs[7] = {
- 0x3100,
- 0x786d,
- 0x0fff,
- 0x0fff,
- 0x01e1,
- 0x45e1,
- 0x0003,
-};
-
-static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location)
-{
- int ret = 0;
-
- if ((unsigned int)location >= ARRAY_SIZE(mii_regs))
- return -1;
-
- if (location != 5)
- ret = mii_regs[location];
- else
- ret = bus->fixed.lpa;
-
- return ret;
-}
-
-static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val)
-{
- /* do nothing */
-}
-
-int fs_mii_fixed_init(struct fs_enet_mii_bus *bus)
-{
- const struct fs_mii_bus_info *bi = bus->bus_info;
-
- bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */
-
- /* if speed is fixed at 10Mb, remove 100Mb modes */
- if (bi->i.fixed.speed == 10)
- bus->fixed.lpa &= ~LPA_100;
-
- /* if duplex is half, remove full duplex modes */
- if (bi->i.fixed.duplex == 0)
- bus->fixed.lpa &= ~LPA_DUPLEX;
-
- bus->mii_read = mii_read;
- bus->mii_write = mii_write;
-
- return 0;
-}
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 218d31764c5..280b114e253 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -64,7 +64,6 @@
* The driver then cleans up the buffer.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -144,7 +143,7 @@ void gfar_start(struct net_device *dev);
static void gfar_clear_exact_match(struct net_device *dev);
static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
-extern struct ethtool_ops gfar_ethtool_ops;
+extern const struct ethtool_ops gfar_ethtool_ops;
MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
@@ -948,7 +947,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Set up checksumming */
if (likely((dev->features & NETIF_F_IP_CSUM)
- && (CHECKSUM_HW == skb->ip_summed))) {
+ && (CHECKSUM_PARTIAL == skb->ip_summed))) {
fcb = gfar_add_fcb(skb, txbdp);
status |= TXBD_TOE;
gfar_tx_checksum(skb, fcb);
@@ -1064,7 +1063,7 @@ static void gfar_vlan_rx_register(struct net_device *dev,
tempval |= TCTRL_VLINS;
gfar_write(&priv->regs->tctrl, tempval);
-
+
/* Enable VLAN tag extraction */
tempval = gfar_read(&priv->regs->rctrl);
tempval |= RCTRL_VLEX;
@@ -1709,9 +1708,6 @@ static void gfar_set_multi(struct net_device *dev)
u32 tempval;
if(dev->flags & IFF_PROMISC) {
- if (netif_msg_drv(priv))
- printk(KERN_INFO "%s: Entering promiscuous mode.\n",
- dev->name);
/* Set RCTRL to PROM */
tempval = gfar_read(&regs->rctrl);
tempval |= RCTRL_PROM;
@@ -1722,7 +1718,7 @@ static void gfar_set_multi(struct net_device *dev)
tempval &= ~(RCTRL_PROM);
gfar_write(&regs->rctrl, tempval);
}
-
+
if(dev->flags & IFF_ALLMULTI) {
/* Set the hash to rx all multicast frames */
gfar_write(&regs->igaddr0, 0xffffffff);
@@ -1958,7 +1954,7 @@ static int __init gfar_init(void)
if (err)
gfar_mdio_exit();
-
+
return err;
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 127c98cf333..c35d47c40c3 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -22,7 +22,6 @@
#ifndef __GIANFAR_H
#define __GIANFAR_H
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -755,8 +754,6 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
out_be32(addr, val);
}
-extern struct ethtool_ops *gfar_op_array[];
-
extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index d69698c695e..6d71bea5e90 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -10,12 +10,11 @@
*
* Copyright (c) 2003,2004 Freescale Semiconductor, Inc.
*
- * This software may be used and distributed according to
- * the terms of the GNU Public License, Version 2, incorporated herein
+ * This software may be used and distributed according to
+ * the terms of the GNU Public License, Version 2, incorporated herein
* by reference.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -203,7 +202,7 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
if (NULL == phydev)
return -ENODEV;
-
+
cmd->maxtxpkt = priv->txcount;
cmd->maxrxpkt = priv->rxcount;
@@ -282,7 +281,7 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
-
+
if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
return -EOPNOTSUPP;
@@ -556,19 +555,19 @@ static uint32_t gfar_get_tx_csum(struct net_device *dev)
}
static uint32_t gfar_get_msglevel(struct net_device *dev)
-{
+{
struct gfar_private *priv = netdev_priv(dev);
return priv->msg_enable;
-}
-
+}
+
static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
-{
+{
struct gfar_private *priv = netdev_priv(dev);
priv->msg_enable = data;
}
-struct ethtool_ops gfar_ethtool_ops = {
+const struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
.set_settings = gfar_ssettings,
.get_drvinfo = gfar_gdrvinfo,
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index c6b725529af..ff684d4be96 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar_mii.c
*
* Gianfar Ethernet Driver -- MIIM bus implementation
@@ -16,7 +16,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -172,7 +171,7 @@ int gfar_mdio_probe(struct device *dev)
err = mdiobus_register(new_bus);
if (0 != err) {
- printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
+ printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
new_bus->name);
goto bus_register_fail;
}
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index d527cf2f9c1..5d340046951 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar_mii.h
*
* Gianfar Ethernet Driver -- MII Management Bus Implementation
diff --git a/drivers/net/gianfar_sysfs.c b/drivers/net/gianfar_sysfs.c
index a6d5c43199c..9dd387fb3d7 100644
--- a/drivers/net/gianfar_sysfs.c
+++ b/drivers/net/gianfar_sysfs.c
@@ -19,7 +19,6 @@
* Sysfs file creation and management
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -88,7 +87,7 @@ static ssize_t gfar_set_bd_stash(struct class_device *cdev,
priv->bd_stash_en = new_setting;
temp = gfar_read(&priv->regs->attr);
-
+
if (new_setting)
temp |= ATTR_BDSTASH;
else
diff --git a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h
deleted file mode 100644
index 7e7af0d5658..00000000000
--- a/drivers/net/gt64240eth.h
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * 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.
- *
- * Copyright (C) 2001 Patton Electronics Company
- * Copyright (C) 2002 Momentum Computer
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or support@mvista.com
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * Ethernet driver definitions for the MIPS GT96100 Advanced
- * Communication Controller.
- *
- * Modified for the Marvellous GT64240 Retarded Communication Controller.
- */
-#ifndef _GT64240ETH_H
-#define _GT64240ETH_H
-
-#include <asm/gt64240.h>
-
-#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400
-
-/* Translate those weanie names from Galileo/VxWorks header files: */
-
-#define GT64240_MRR MAIN_ROUTING_REGISTER
-#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER
-#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL
-#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER
-#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER
-#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW
-#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH
-#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER
-
-#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER
-#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER
-#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER
-#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER
-#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER
-#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS
-#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER
-#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE
-#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER
-#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER
-#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER
-#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER
-#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0
-#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1
-#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0
-#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0
-#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER
-
-/* Turn on NAPI by default */
-
-#define GT64240_NAPI 1
-
-/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */
-/* (Board-specific to the DSL3224 Rev A board ONLY!) */
-#define D3224_MPP_CTRL0_SETTING 0x66669900
-#define D3224_MPP_CTRL1_SETTING 0x00000000
-#define D3224_MPP_CTRL2_SETTING 0x00887700
-#define D3224_MPP_CTRL3_SETTING 0x00000044
-#define D3224_GPP_IO_CTRL_SETTING 0x0000e800
-#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703
-#define D3224_GPP_VALUE_SETTING 0x00000000
-
-/* Keep the ring sizes a power of two for efficiency. */
-//-#define TX_RING_SIZE 16
-#define TX_RING_SIZE 64 /* TESTING !!! */
-#define RX_RING_SIZE 32
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
-
-#define RX_HASH_TABLE_SIZE 16384
-#define HASH_HOP_NUMBER 12
-
-#define NUM_INTERFACES 3
-
-#define GT64240ETH_TX_TIMEOUT HZ/4
-
-#define MIPS_GT64240_BASE 0xf4000000
-#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG)
-#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE)
-#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE)
-
-#if defined(CONFIG_MIPS_DSL3224)
-#define GT64240_ETHER0_IRQ 4
-#define GT64240_ETHER1_IRQ 4
-#else
-#define GT64240_ETHER0_IRQ -1
-#define GT64240_ETHER1_IRQ -1
-#endif
-
-#define REV_GT64240 0x1
-#define REV_GT64240A 0x10
-
-#define GT64240ETH_READ(gp, offset) \
- GT_READ((gp)->port_offset + (offset))
-
-#define GT64240ETH_WRITE(gp, offset, data) \
- GT_WRITE((gp)->port_offset + (offset), (data))
-
-#define GT64240ETH_SETBIT(gp, offset, bits) \
- GT64240ETH_WRITE((gp), (offset), \
- GT64240ETH_READ((gp), (offset)) | (bits))
-
-#define GT64240ETH_CLRBIT(gp, offset, bits) \
- GT64240ETH_WRITE((gp), (offset), \
- GT64240ETH_READ((gp), (offset)) & ~(bits))
-
-#define GT64240_READ(ofs) GT_READ(ofs)
-#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data))
-
-/* Bit definitions of the SMI Reg */
-enum {
- smirDataMask = 0xffff,
- smirPhyAdMask = 0x1f << 16,
- smirPhyAdBit = 16,
- smirRegAdMask = 0x1f << 21,
- smirRegAdBit = 21,
- smirOpCode = 1 << 26,
- smirReadValid = 1 << 27,
- smirBusy = 1 << 28
-};
-
-/* Bit definitions of the Port Config Reg */
-enum pcr_bits {
- pcrPM = 1 << 0,
- pcrRBM = 1 << 1,
- pcrPBF = 1 << 2,
- pcrEN = 1 << 7,
- pcrLPBKMask = 0x3 << 8,
- pcrLPBKBit = 1 << 8,
- pcrFC = 1 << 10,
- pcrHS = 1 << 12,
- pcrHM = 1 << 13,
- pcrHDM = 1 << 14,
- pcrHD = 1 << 15,
- pcrISLMask = 0x7 << 28,
- pcrISLBit = 28,
- pcrACCS = 1 << 31
-};
-
-/* Bit definitions of the Port Config Extend Reg */
-enum pcxr_bits {
- pcxrIGMP = 1,
- pcxrSPAN = 2,
- pcxrPAR = 4,
- pcxrPRIOtxMask = 0x7 << 3,
- pcxrPRIOtxBit = 3,
- pcxrPRIOrxMask = 0x3 << 6,
- pcxrPRIOrxBit = 6,
- pcxrPRIOrxOverride = 1 << 8,
- pcxrDPLXen = 1 << 9,
- pcxrFCTLen = 1 << 10,
- pcxrFLP = 1 << 11,
- pcxrFCTL = 1 << 12,
- pcxrMFLMask = 0x3 << 14,
- pcxrMFLBit = 14,
- pcxrMIBclrMode = 1 << 16,
- pcxrSpeed = 1 << 18,
- pcxrSpeeden = 1 << 19,
- pcxrRMIIen = 1 << 20,
- pcxrDSCPen = 1 << 21
-};
-
-/* Bit definitions of the Port Command Reg */
-enum pcmr_bits {
- pcmrFJ = 1 << 15
-};
-
-
-/* Bit definitions of the Port Status Reg */
-enum psr_bits {
- psrSpeed = 1,
- psrDuplex = 2,
- psrFctl = 4,
- psrLink = 8,
- psrPause = 1 << 4,
- psrTxLow = 1 << 5,
- psrTxHigh = 1 << 6,
- psrTxInProg = 1 << 7
-};
-
-/* Bit definitions of the SDMA Config Reg */
-enum sdcr_bits {
- sdcrRCMask = 0xf << 2,
- sdcrRCBit = 2,
- sdcrBLMR = 1 << 6,
- sdcrBLMT = 1 << 7,
- sdcrPOVR = 1 << 8,
- sdcrRIFB = 1 << 9,
- sdcrBSZMask = 0x3 << 12,
- sdcrBSZBit = 12
-};
-
-/* Bit definitions of the SDMA Command Reg */
-enum sdcmr_bits {
- sdcmrERD = 1 << 7,
- sdcmrAR = 1 << 15,
- sdcmrSTDH = 1 << 16,
- sdcmrSTDL = 1 << 17,
- sdcmrTXDH = 1 << 23,
- sdcmrTXDL = 1 << 24,
- sdcmrAT = 1 << 31
-};
-
-/* Bit definitions of the Interrupt Cause Reg */
-enum icr_bits {
- icrRxBuffer = 1,
- icrTxBufferHigh = 1 << 2,
- icrTxBufferLow = 1 << 3,
- icrTxEndHigh = 1 << 6,
- icrTxEndLow = 1 << 7,
- icrRxError = 1 << 8,
- icrTxErrorHigh = 1 << 10,
- icrTxErrorLow = 1 << 11,
- icrRxOVR = 1 << 12,
- icrTxUdr = 1 << 13,
- icrRxBufferQ0 = 1 << 16,
- icrRxBufferQ1 = 1 << 17,
- icrRxBufferQ2 = 1 << 18,
- icrRxBufferQ3 = 1 << 19,
- icrRxErrorQ0 = 1 << 20,
- icrRxErrorQ1 = 1 << 21,
- icrRxErrorQ2 = 1 << 22,
- icrRxErrorQ3 = 1 << 23,
- icrMIIPhySTC = 1 << 28,
- icrSMIdone = 1 << 29,
- icrEtherIntSum = 1 << 31
-};
-
-
-/* The Rx and Tx descriptor lists. */
-#ifdef __LITTLE_ENDIAN
-typedef struct {
- u32 cmdstat;
- u16 reserved; //-prk21aug01 u32 reserved:16;
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u32 buff_ptr;
- u32 next;
-} gt64240_td_t;
-
-typedef struct {
- u32 cmdstat;
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
- u32 buff_ptr;
- u32 next;
-} gt64240_rd_t;
-#elif defined(__BIG_ENDIAN)
-typedef struct {
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u16 reserved; //-prk21aug01 u32 reserved:16;
- u32 cmdstat;
- u32 next;
- u32 buff_ptr;
-} gt64240_td_t;
-
-typedef struct {
- u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u32 cmdstat;
- u32 next;
- u32 buff_ptr;
-} gt64240_rd_t;
-#else
-#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined!
-#endif
-
-
-/* Values for the Tx command-status descriptor entry. */
-enum td_cmdstat {
- txOwn = 1 << 31,
- txAutoMode = 1 << 30,
- txEI = 1 << 23,
- txGenCRC = 1 << 22,
- txPad = 1 << 18,
- txFirst = 1 << 17,
- txLast = 1 << 16,
- txErrorSummary = 1 << 15,
- txReTxCntMask = 0x0f << 10,
- txReTxCntBit = 10,
- txCollision = 1 << 9,
- txReTxLimit = 1 << 8,
- txUnderrun = 1 << 6,
- txLateCollision = 1 << 5
-};
-
-
-/* Values for the Rx command-status descriptor entry. */
-enum rd_cmdstat {
- rxOwn = 1 << 31,
- rxAutoMode = 1 << 30,
- rxEI = 1 << 23,
- rxFirst = 1 << 17,
- rxLast = 1 << 16,
- rxErrorSummary = 1 << 15,
- rxIGMP = 1 << 14,
- rxHashExpired = 1 << 13,
- rxMissedFrame = 1 << 12,
- rxFrameType = 1 << 11,
- rxShortFrame = 1 << 8,
- rxMaxFrameLen = 1 << 7,
- rxOverrun = 1 << 6,
- rxCollision = 1 << 4,
- rxCRCError = 1
-};
-
-/* Bit fields of a Hash Table Entry */
-enum hash_table_entry {
- hteValid = 1,
- hteSkip = 2,
- hteRD = 4
-};
-
-// The MIB counters
-typedef struct {
- u32 byteReceived;
- u32 byteSent;
- u32 framesReceived;
- u32 framesSent;
- u32 totalByteReceived;
- u32 totalFramesReceived;
- u32 broadcastFramesReceived;
- u32 multicastFramesReceived;
- u32 cRCError;
- u32 oversizeFrames;
- u32 fragments;
- u32 jabber;
- u32 collision;
- u32 lateCollision;
- u32 frames64;
- u32 frames65_127;
- u32 frames128_255;
- u32 frames256_511;
- u32 frames512_1023;
- u32 frames1024_MaxSize;
- u32 macRxError;
- u32 droppedFrames;
- u32 outMulticastFrames;
- u32 outBroadcastFrames;
- u32 undersizeFrames;
-} mib_counters_t;
-
-
-struct gt64240_private {
- gt64240_rd_t *rx_ring;
- gt64240_td_t *tx_ring;
- // The Rx and Tx rings must be 16-byte aligned
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_ring_dma;
- char *hash_table;
- // The Hash Table must be 8-byte aligned
- dma_addr_t hash_table_dma;
- int hash_mode;
-
- // The Rx buffers must be 8-byte aligned
- char *rx_buff;
- dma_addr_t rx_buff_dma;
- // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
- // of payload must be 8-byte aligned
- struct sk_buff *tx_skbuff[TX_RING_SIZE];
- int rx_next_out; /* The next free ring entry to receive */
- int tx_next_in; /* The next free ring entry to send */
- int tx_next_out; /* The last ring entry the ISR processed */
- int tx_count; /* current # of pkts waiting to be sent in Tx ring */
- int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
- int tx_full; /* Tx ring is full */
-
- mib_counters_t mib;
- struct net_device_stats stats;
-
- int io_size;
- int port_num; // 0 or 1
- u32 port_offset;
-
- int phy_addr; // PHY address
- u32 last_psr; // last value of the port status register
-
- int options; /* User-settable misc. driver options. */
- int drv_flags;
- spinlock_t lock; /* Serialise access to device */
- struct mii_if_info mii_if;
-
- u32 msg_enable;
-};
-
-#endif /* _GT64240ETH_H */
diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c
deleted file mode 100644
index 2d243540461..00000000000
--- a/drivers/net/gt96100eth.c
+++ /dev/null
@@ -1,1567 +0,0 @@
-/*
- * Copyright 2000, 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.com
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * Ethernet driver for the MIPS GT96100 Advanced Communication Controller.
- *
- * Revision history
- *
- * 11.11.2001 Moved to 2.4.14, ppopov@mvista.com. Modified driver to add
- * proper gt96100A support.
- * 12.05.2001 Moved eth port 0 to irq 3 (mapped to GT_SERINT0 on EV96100A)
- * in order for both ports to work. Also cleaned up boot
- * option support (mac address string parsing), fleshed out
- * gt96100_cleanup_module(), and other general code cleanups
- * <stevel@mvista.com>.
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/in.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/bitops.h>
-
-#include <asm/irq.h>
-#include <asm/io.h>
-
-#define DESC_BE 1
-#define DESC_DATA_BE 1
-
-#define GT96100_DEBUG 2
-
-#include "gt96100eth.h"
-
-// prototypes
-static void* dmaalloc(size_t size, dma_addr_t *dma_handle);
-static void dmafree(size_t size, void *vaddr);
-static void gt96100_delay(int msec);
-static int gt96100_add_hash_entry(struct net_device *dev,
- unsigned char* addr);
-static void read_mib_counters(struct gt96100_private *gp);
-static int read_MII(int phy_addr, u32 reg);
-static int write_MII(int phy_addr, u32 reg, u16 data);
-static int gt96100_init_module(void);
-static void gt96100_cleanup_module(void);
-static void dump_MII(int dbg_lvl, struct net_device *dev);
-static void dump_tx_desc(int dbg_lvl, struct net_device *dev, int i);
-static void dump_rx_desc(int dbg_lvl, struct net_device *dev, int i);
-static void dump_skb(int dbg_lvl, struct net_device *dev,
- struct sk_buff *skb);
-static void update_stats(struct gt96100_private *gp);
-static void abort(struct net_device *dev, u32 abort_bits);
-static void hard_stop(struct net_device *dev);
-static void enable_ether_irq(struct net_device *dev);
-static void disable_ether_irq(struct net_device *dev);
-static int gt96100_probe1(struct pci_dev *pci, int port_num);
-static void reset_tx(struct net_device *dev);
-static void reset_rx(struct net_device *dev);
-static int gt96100_check_tx_consistent(struct gt96100_private *gp);
-static int gt96100_init(struct net_device *dev);
-static int gt96100_open(struct net_device *dev);
-static int gt96100_close(struct net_device *dev);
-static int gt96100_tx(struct sk_buff *skb, struct net_device *dev);
-static int gt96100_rx(struct net_device *dev, u32 status);
-static irqreturn_t gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void gt96100_tx_timeout(struct net_device *dev);
-static void gt96100_set_rx_mode(struct net_device *dev);
-static struct net_device_stats* gt96100_get_stats(struct net_device *dev);
-
-extern char * __init prom_getcmdline(void);
-
-static int max_interrupt_work = 32;
-
-#define nibswap(x) ((((x) >> 4) & 0x0f) | (((x) << 4) & 0xf0))
-
-#define RUN_AT(x) (jiffies + (x))
-
-// For reading/writing 32-bit words and half-words from/to DMA memory
-#ifdef DESC_BE
-#define cpu_to_dma32 cpu_to_be32
-#define dma32_to_cpu be32_to_cpu
-#define cpu_to_dma16 cpu_to_be16
-#define dma16_to_cpu be16_to_cpu
-#else
-#define cpu_to_dma32 cpu_to_le32
-#define dma32_to_cpu le32_to_cpu
-#define cpu_to_dma16 cpu_to_le16
-#define dma16_to_cpu le16_to_cpu
-#endif
-
-static char mac0[18] = "00.02.03.04.05.06";
-static char mac1[18] = "00.01.02.03.04.05";
-module_param_string(mac0, mac0, 18, 0);
-module_param_string(mac1, mac0, 18, 0);
-MODULE_PARM_DESC(mac0, "MAC address for GT96100 ethernet port 0");
-MODULE_PARM_DESC(mac1, "MAC address for GT96100 ethernet port 1");
-
-/*
- * Info for the GT96100 ethernet controller's ports.
- */
-static struct gt96100_if_t {
- struct net_device *dev;
- unsigned int iobase; // IO Base address of this port
- int irq; // IRQ number of this port
- char *mac_str;
-} gt96100_iflist[NUM_INTERFACES] = {
- {
- NULL,
- GT96100_ETH0_BASE, GT96100_ETHER0_IRQ,
- mac0
- },
- {
- NULL,
- GT96100_ETH1_BASE, GT96100_ETHER1_IRQ,
- mac1
- }
-};
-
-static inline const char*
-chip_name(int chip_rev)
-{
- switch (chip_rev) {
- case REV_GT96100:
- return "GT96100";
- case REV_GT96100A_1:
- case REV_GT96100A:
- return "GT96100A";
- default:
- return "Unknown GT96100";
- }
-}
-
-/*
- DMA memory allocation, derived from pci_alloc_consistent.
-*/
-static void * dmaalloc(size_t size, dma_addr_t *dma_handle)
-{
- void *ret;
-
- ret = (void *)__get_free_pages(GFP_ATOMIC | GFP_DMA, get_order(size));
-
- if (ret != NULL) {
- dma_cache_inv((unsigned long)ret, size);
- if (dma_handle != NULL)
- *dma_handle = virt_to_phys(ret);
-
- /* bump virtual address up to non-cached area */
- ret = (void*)KSEG1ADDR(ret);
- }
-
- return ret;
-}
-
-static void dmafree(size_t size, void *vaddr)
-{
- vaddr = (void*)KSEG0ADDR(vaddr);
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static void gt96100_delay(int ms)
-{
- if (in_interrupt())
- return;
- else
- msleep_interruptible(ms);
-}
-
-static int
-parse_mac_addr(struct net_device *dev, char* macstr)
-{
- int i, j;
- unsigned char result, value;
-
- for (i=0; i<6; i++) {
- result = 0;
- if (i != 5 && *(macstr+2) != '.') {
- err(__FILE__ "invalid mac address format: %d %c\n",
- i, *(macstr+2));
- return -EINVAL;
- }
-
- for (j=0; j<2; j++) {
- if (isxdigit(*macstr) &&
- (value = isdigit(*macstr) ? *macstr-'0' :
- toupper(*macstr)-'A'+10) < 16) {
- result = result*16 + value;
- macstr++;
- } else {
- err(__FILE__ "invalid mac address "
- "character: %c\n", *macstr);
- return -EINVAL;
- }
- }
-
- macstr++; // step over '.'
- dev->dev_addr[i] = result;
- }
-
- return 0;
-}
-
-
-static int
-read_MII(int phy_addr, u32 reg)
-{
- int timedout = 20;
- u32 smir = smirOpCode | (phy_addr << smirPhyAdBit) |
- (reg << smirRegAdBit);
-
- // wait for last operation to complete
- while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
- // snooze for 1 msec and check again
- gt96100_delay(1);
-
- if (--timedout == 0) {
- printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
- return -ENODEV;
- }
- }
-
- GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
-
- timedout = 20;
- // wait for read to complete
- while (!((smir = GT96100_READ(GT96100_ETH_SMI_REG)) & smirReadValid)) {
- // snooze for 1 msec and check again
- gt96100_delay(1);
-
- if (--timedout == 0) {
- printk(KERN_ERR "%s: timeout!!\n", __FUNCTION__);
- return -ENODEV;
- }
- }
-
- return (int)(smir & smirDataMask);
-}
-
-static void
-dump_tx_desc(int dbg_lvl, struct net_device *dev, int i)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- gt96100_td_t *td = &gp->tx_ring[i];
-
- dbg(dbg_lvl, "Tx descriptor at 0x%08lx:\n", virt_to_phys(td));
- dbg(dbg_lvl,
- " cmdstat=%04x, byte_cnt=%04x, buff_ptr=%04x, next=%04x\n",
- dma32_to_cpu(td->cmdstat),
- dma16_to_cpu(td->byte_cnt),
- dma32_to_cpu(td->buff_ptr),
- dma32_to_cpu(td->next));
-}
-
-static void
-dump_rx_desc(int dbg_lvl, struct net_device *dev, int i)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- gt96100_rd_t *rd = &gp->rx_ring[i];
-
- dbg(dbg_lvl, "Rx descriptor at 0x%08lx:\n", virt_to_phys(rd));
- dbg(dbg_lvl, " cmdstat=%04x, buff_sz=%04x, byte_cnt=%04x, "
- "buff_ptr=%04x, next=%04x\n",
- dma32_to_cpu(rd->cmdstat),
- dma16_to_cpu(rd->buff_sz),
- dma16_to_cpu(rd->byte_cnt),
- dma32_to_cpu(rd->buff_ptr),
- dma32_to_cpu(rd->next));
-}
-
-static int
-write_MII(int phy_addr, u32 reg, u16 data)
-{
- int timedout = 20;
- u32 smir = (phy_addr << smirPhyAdBit) |
- (reg << smirRegAdBit) | data;
-
- // wait for last operation to complete
- while (GT96100_READ(GT96100_ETH_SMI_REG) & smirBusy) {
- // snooze for 1 msec and check again
- gt96100_delay(1);
-
- if (--timedout == 0) {
- printk(KERN_ERR "%s: busy timeout!!\n", __FUNCTION__);
- return -1;
- }
- }
-
- GT96100_WRITE(GT96100_ETH_SMI_REG, smir);
- return 0;
-}
-
-static void
-dump_MII(int dbg_lvl, struct net_device *dev)
-{
- int i, val;
- struct gt96100_private *gp = netdev_priv(dev);
-
- if (dbg_lvl <= GT96100_DEBUG) {
- for (i=0; i<7; i++) {
- if ((val = read_MII(gp->phy_addr, i)) >= 0)
- printk("MII Reg %d=%x\n", i, val);
- }
- for (i=16; i<21; i++) {
- if ((val = read_MII(gp->phy_addr, i)) >= 0)
- printk("MII Reg %d=%x\n", i, val);
- }
- }
-}
-
-static void
-dump_hw_addr(int dbg_lvl, struct net_device *dev, const char* pfx,
- const char* func, unsigned char* addr_str)
-{
- int i;
- char buf[100], octet[5];
-
- if (dbg_lvl <= GT96100_DEBUG) {
- sprintf(buf, pfx, func);
- for (i = 0; i < 6; i++) {
- sprintf(octet, "%2.2x%s",
- addr_str[i], i<5 ? ":" : "\n");
- strcat(buf, octet);
- }
- info("%s", buf);
- }
-}
-
-
-static void
-dump_skb(int dbg_lvl, struct net_device *dev, struct sk_buff *skb)
-{
- int i;
- unsigned char* skbdata;
-
- if (dbg_lvl <= GT96100_DEBUG) {
- dbg(dbg_lvl, "%s: skb=%p, skb->data=%p, skb->len=%d\n",
- __FUNCTION__, skb, skb->data, skb->len);
-
- skbdata = (unsigned char*)KSEG1ADDR(skb->data);
-
- for (i=0; i<skb->len; i++) {
- if (!(i % 16))
- printk(KERN_DEBUG "\n %3.3x: %2.2x,",
- i, skbdata[i]);
- else
- printk(KERN_DEBUG "%2.2x,", skbdata[i]);
- }
- printk(KERN_DEBUG "\n");
- }
-}
-
-
-static int
-gt96100_add_hash_entry(struct net_device *dev, unsigned char* addr)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- //u16 hashResult, stmp;
- //unsigned char ctmp, hash_ea[6];
- u32 tblEntry1, tblEntry0, *tblEntryAddr;
- int i;
-
- tblEntry1 = hteValid | hteRD;
- tblEntry1 |= (u32)addr[5] << 3;
- tblEntry1 |= (u32)addr[4] << 11;
- tblEntry1 |= (u32)addr[3] << 19;
- tblEntry1 |= ((u32)addr[2] & 0x1f) << 27;
- dbg(3, "%s: tblEntry1=%x\n", __FUNCTION__, tblEntry1);
- tblEntry0 = ((u32)addr[2] >> 5) & 0x07;
- tblEntry0 |= (u32)addr[1] << 3;
- tblEntry0 |= (u32)addr[0] << 11;
- dbg(3, "%s: tblEntry0=%x\n", __FUNCTION__, tblEntry0);
-
-#if 0
-
- for (i=0; i<6; i++) {
- // nibble swap
- ctmp = nibswap(addr[i]);
- // invert every nibble
- hash_ea[i] = ((ctmp&1)<<3) | ((ctmp&8)>>3) |
- ((ctmp&2)<<1) | ((ctmp&4)>>1);
- hash_ea[i] |= ((ctmp&0x10)<<3) | ((ctmp&0x80)>>3) |
- ((ctmp&0x20)<<1) | ((ctmp&0x40)>>1);
- }
-
- dump_hw_addr(3, dev, "%s: nib swap/invt addr=", __FUNCTION__, hash_ea);
-
- if (gp->hash_mode == 0) {
- hashResult = ((u16)hash_ea[0] & 0xfc) << 7;
- stmp = ((u16)hash_ea[0] & 0x03) |
- (((u16)hash_ea[1] & 0x7f) << 2);
- stmp ^= (((u16)hash_ea[1] >> 7) & 0x01) |
- ((u16)hash_ea[2] << 1);
- stmp ^= (u16)hash_ea[3] | (((u16)hash_ea[4] & 1) << 8);
- hashResult |= stmp;
- } else {
- return -1; // don't support hash mode 1
- }
-
- dbg(3, "%s: hashResult=%x\n", __FUNCTION__, hashResult);
-
- tblEntryAddr =
- (u32 *)(&gp->hash_table[((u32)hashResult & 0x7ff) << 3]);
-
- dbg(3, "%s: tblEntryAddr=%p\n", tblEntryAddr, __FUNCTION__);
-
- for (i=0; i<HASH_HOP_NUMBER; i++) {
- if ((*tblEntryAddr & hteValid) &&
- !(*tblEntryAddr & hteSkip)) {
- // This entry is already occupied, go to next entry
- tblEntryAddr += 2;
- dbg(3, "%s: skipping to %p\n", __FUNCTION__,
- tblEntryAddr);
- } else {
- memset(tblEntryAddr, 0, 8);
- tblEntryAddr[1] = cpu_to_dma32(tblEntry1);
- tblEntryAddr[0] = cpu_to_dma32(tblEntry0);
- break;
- }
- }
-
- if (i >= HASH_HOP_NUMBER) {
- err("%s: expired!\n", __FUNCTION__);
- return -1; // Couldn't find an unused entry
- }
-
-#else
-
- tblEntryAddr = (u32 *)gp->hash_table;
- for (i=0; i<RX_HASH_TABLE_SIZE/4; i+=2) {
- tblEntryAddr[i+1] = cpu_to_dma32(tblEntry1);
- tblEntryAddr[i] = cpu_to_dma32(tblEntry0);
- }
-
-#endif
-
- return 0;
-}
-
-
-static void
-read_mib_counters(struct gt96100_private *gp)
-{
- u32* mib_regs = (u32*)&gp->mib;
- int i;
-
- for (i=0; i<sizeof(mib_counters_t)/sizeof(u32); i++)
- mib_regs[i] = GT96100ETH_READ(gp, GT96100_ETH_MIB_COUNT_BASE +
- i*sizeof(u32));
-}
-
-
-static void
-update_stats(struct gt96100_private *gp)
-{
- mib_counters_t *mib = &gp->mib;
- struct net_device_stats *stats = &gp->stats;
-
- read_mib_counters(gp);
-
- stats->rx_packets = mib->totalFramesReceived;
- stats->tx_packets = mib->framesSent;
- stats->rx_bytes = mib->totalByteReceived;
- stats->tx_bytes = mib->byteSent;
- stats->rx_errors = mib->totalFramesReceived - mib->framesReceived;
- //the tx error counters are incremented by the ISR
- //rx_dropped incremented by gt96100_rx
- //tx_dropped incremented by gt96100_tx
- stats->multicast = mib->multicastFramesReceived;
- // collisions incremented by gt96100_tx_complete
- stats->rx_length_errors = mib->oversizeFrames + mib->fragments;
- // The RxError condition means the Rx DMA encountered a
- // CPU owned descriptor, which, if things are working as
- // they should, means the Rx ring has overflowed.
- stats->rx_over_errors = mib->macRxError;
- stats->rx_crc_errors = mib->cRCError;
-}
-
-static void
-abort(struct net_device *dev, u32 abort_bits)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- int timedout = 100; // wait up to 100 msec for hard stop to complete
-
- dbg(3, "%s\n", __FUNCTION__);
-
- // Return if neither Rx or Tx abort bits are set
- if (!(abort_bits & (sdcmrAR | sdcmrAT)))
- return;
-
- // make sure only the Rx/Tx abort bits are set
- abort_bits &= (sdcmrAR | sdcmrAT);
-
- spin_lock(&gp->lock);
-
- // abort any Rx/Tx DMA immediately
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, abort_bits);
-
- dbg(3, "%s: SDMA comm = %x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
-
- // wait for abort to complete
- while (GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM) & abort_bits) {
- // snooze for 1 msec and check again
- gt96100_delay(1);
-
- if (--timedout == 0) {
- err("%s: timeout!!\n", __FUNCTION__);
- break;
- }
- }
-
- spin_unlock(&gp->lock);
-}
-
-
-static void
-hard_stop(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
-
- dbg(3, "%s\n", __FUNCTION__);
-
- disable_ether_irq(dev);
-
- abort(dev, sdcmrAR | sdcmrAT);
-
- // disable port
- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, 0);
-}
-
-
-static void
-enable_ether_irq(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- u32 intMask;
- /*
- * route ethernet interrupt to GT_SERINT0 for port 0,
- * GT_INT0 for port 1.
- */
- int intr_mask_reg = (gp->port_num == 0) ?
- GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;
-
- if (gp->chip_rev >= REV_GT96100A_1) {
- intMask = icrTxBufferLow | icrTxEndLow |
- icrTxErrorLow | icrRxOVR | icrTxUdr |
- icrRxBufferQ0 | icrRxErrorQ0 |
- icrMIIPhySTC | icrEtherIntSum;
- }
- else {
- intMask = icrTxBufferLow | icrTxEndLow |
- icrTxErrorLow | icrRxOVR | icrTxUdr |
- icrRxBuffer | icrRxError |
- icrMIIPhySTC | icrEtherIntSum;
- }
-
- // unmask interrupts
- GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, intMask);
-
- intMask = GT96100_READ(intr_mask_reg);
- intMask |= 1<<gp->port_num;
- GT96100_WRITE(intr_mask_reg, intMask);
-}
-
-static void
-disable_ether_irq(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- u32 intMask;
- int intr_mask_reg = (gp->port_num == 0) ?
- GT96100_SERINT0_MASK : GT96100_INT0_HIGH_MASK;
-
- intMask = GT96100_READ(intr_mask_reg);
- intMask &= ~(1<<gp->port_num);
- GT96100_WRITE(intr_mask_reg, intMask);
-
- GT96100ETH_WRITE(gp, GT96100_ETH_INT_MASK, 0);
-}
-
-
-/*
- * Init GT96100 ethernet controller driver
- */
-static int gt96100_init_module(void)
-{
- struct pci_dev *pci;
- int i, retval=0;
- u32 cpuConfig;
-
- /*
- * Stupid probe because this really isn't a PCI device
- */
- if (!(pci = pci_find_device(PCI_VENDOR_ID_MARVELL,
- PCI_DEVICE_ID_MARVELL_GT96100, NULL)) &&
- !(pci = pci_find_device(PCI_VENDOR_ID_MARVELL,
- PCI_DEVICE_ID_MARVELL_GT96100A, NULL))) {
- printk(KERN_ERR __FILE__ ": GT96100 not found!\n");
- return -ENODEV;
- }
-
- cpuConfig = GT96100_READ(GT96100_CPU_INTERF_CONFIG);
- if (cpuConfig & (1<<12)) {
- printk(KERN_ERR __FILE__
- ": must be in Big Endian mode!\n");
- return -ENODEV;
- }
-
- for (i=0; i < NUM_INTERFACES; i++)
- retval |= gt96100_probe1(pci, i);
-
- return retval;
-}
-
-static int __init gt96100_probe1(struct pci_dev *pci, int port_num)
-{
- struct gt96100_private *gp = NULL;
- struct gt96100_if_t *gtif = &gt96100_iflist[port_num];
- int phy_addr, phy_id1, phy_id2;
- u32 phyAD;
- int retval;
- unsigned char chip_rev;
- struct net_device *dev = NULL;
-
- if (gtif->irq < 0) {
- printk(KERN_ERR "%s: irq unknown - probing not supported\n",
- __FUNCTION__);
- return -ENODEV;
- }
-
- pci_read_config_byte(pci, PCI_REVISION_ID, &chip_rev);
-
- if (chip_rev >= REV_GT96100A_1) {
- phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);
- phy_addr = (phyAD >> (5*port_num)) & 0x1f;
- } else {
- /*
- * not sure what's this about -- probably a gt bug
- */
- phy_addr = port_num;
- phyAD = GT96100_READ(GT96100_ETH_PHY_ADDR_REG);
- phyAD &= ~(0x1f << (port_num*5));
- phyAD |= phy_addr << (port_num*5);
- GT96100_WRITE(GT96100_ETH_PHY_ADDR_REG, phyAD);
- }
-
- // probe for the external PHY
- if ((phy_id1 = read_MII(phy_addr, 2)) <= 0 ||
- (phy_id2 = read_MII(phy_addr, 3)) <= 0) {
- printk(KERN_ERR "%s: no PHY found on MII%d\n", __FUNCTION__, port_num);
- return -ENODEV;
- }
-
- if (!request_region(gtif->iobase, GT96100_ETH_IO_SIZE, "GT96100ETH")) {
- printk(KERN_ERR "%s: request_region failed\n", __FUNCTION__);
- return -EBUSY;
- }
-
- dev = alloc_etherdev(sizeof(struct gt96100_private));
- if (!dev)
- goto out;
- gtif->dev = dev;
-
- /* private struct aligned and zeroed by alloc_etherdev */
- /* Fill in the 'dev' fields. */
- dev->base_addr = gtif->iobase;
- dev->irq = gtif->irq;
-
- if ((retval = parse_mac_addr(dev, gtif->mac_str))) {
- err("%s: MAC address parse failed\n", __FUNCTION__);
- retval = -EINVAL;
- goto out1;
- }
-
- gp = netdev_priv(dev);
-
- memset(gp, 0, sizeof(*gp)); // clear it
-
- gp->port_num = port_num;
- gp->io_size = GT96100_ETH_IO_SIZE;
- gp->port_offset = port_num * GT96100_ETH_IO_SIZE;
- gp->phy_addr = phy_addr;
- gp->chip_rev = chip_rev;
-
- info("%s found at 0x%x, irq %d\n",
- chip_name(gp->chip_rev), gtif->iobase, gtif->irq);
- dump_hw_addr(0, dev, "%s: HW Address ", __FUNCTION__, dev->dev_addr);
- info("%s chip revision=%d\n", chip_name(gp->chip_rev), gp->chip_rev);
- info("%s ethernet port %d\n", chip_name(gp->chip_rev), gp->port_num);
- info("external PHY ID1=0x%04x, ID2=0x%04x\n", phy_id1, phy_id2);
-
- // Allocate Rx and Tx descriptor rings
- if (gp->rx_ring == NULL) {
- // All descriptors in ring must be 16-byte aligned
- gp->rx_ring = dmaalloc(sizeof(gt96100_rd_t) * RX_RING_SIZE
- + sizeof(gt96100_td_t) * TX_RING_SIZE,
- &gp->rx_ring_dma);
- if (gp->rx_ring == NULL) {
- retval = -ENOMEM;
- goto out1;
- }
-
- gp->tx_ring = (gt96100_td_t *)(gp->rx_ring + RX_RING_SIZE);
- gp->tx_ring_dma =
- gp->rx_ring_dma + sizeof(gt96100_rd_t) * RX_RING_SIZE;
- }
-
- // Allocate the Rx Data Buffers
- if (gp->rx_buff == NULL) {
- gp->rx_buff = dmaalloc(PKT_BUF_SZ*RX_RING_SIZE,
- &gp->rx_buff_dma);
- if (gp->rx_buff == NULL) {
- retval = -ENOMEM;
- goto out2;
- }
- }
-
- dbg(3, "%s: rx_ring=%p, tx_ring=%p\n", __FUNCTION__,
- gp->rx_ring, gp->tx_ring);
-
- // Allocate Rx Hash Table
- if (gp->hash_table == NULL) {
- gp->hash_table = (char*)dmaalloc(RX_HASH_TABLE_SIZE,
- &gp->hash_table_dma);
- if (gp->hash_table == NULL) {
- retval = -ENOMEM;
- goto out3;
- }
- }
-
- dbg(3, "%s: hash=%p\n", __FUNCTION__, gp->hash_table);
-
- spin_lock_init(&gp->lock);
-
- dev->open = gt96100_open;
- dev->hard_start_xmit = gt96100_tx;
- dev->stop = gt96100_close;
- dev->get_stats = gt96100_get_stats;
- //dev->do_ioctl = gt96100_ioctl;
- dev->set_multicast_list = gt96100_set_rx_mode;
- dev->tx_timeout = gt96100_tx_timeout;
- dev->watchdog_timeo = GT96100ETH_TX_TIMEOUT;
-
- retval = register_netdev(dev);
- if (retval)
- goto out4;
- return 0;
-
-out4:
- dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma);
-out3:
- dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff);
-out2:
- dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE
- + sizeof(gt96100_td_t) * TX_RING_SIZE,
- gp->rx_ring);
-out1:
- free_netdev (dev);
-out:
- release_region(gtif->iobase, GT96100_ETH_IO_SIZE);
-
- err("%s failed. Returns %d\n", __FUNCTION__, retval);
- return retval;
-}
-
-
-static void
-reset_tx(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- int i;
-
- abort(dev, sdcmrAT);
-
- for (i=0; i<TX_RING_SIZE; i++) {
- if (gp->tx_skbuff[i]) {
- if (in_interrupt())
- dev_kfree_skb_irq(gp->tx_skbuff[i]);
- else
- dev_kfree_skb(gp->tx_skbuff[i]);
- gp->tx_skbuff[i] = NULL;
- }
-
- gp->tx_ring[i].cmdstat = 0; // CPU owns
- gp->tx_ring[i].byte_cnt = 0;
- gp->tx_ring[i].buff_ptr = 0;
- gp->tx_ring[i].next =
- cpu_to_dma32(gp->tx_ring_dma +
- sizeof(gt96100_td_t) * (i+1));
- dump_tx_desc(4, dev, i);
- }
- /* Wrap the ring. */
- gp->tx_ring[i-1].next = cpu_to_dma32(gp->tx_ring_dma);
-
- // setup only the lowest priority TxCDP reg
- GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR0, gp->tx_ring_dma);
- GT96100ETH_WRITE(gp, GT96100_ETH_CURR_TX_DESC_PTR1, 0);
-
- // init Tx indeces and pkt counter
- gp->tx_next_in = gp->tx_next_out = 0;
- gp->tx_count = 0;
-
-}
-
-static void
-reset_rx(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- int i;
-
- abort(dev, sdcmrAR);
-
- for (i=0; i<RX_RING_SIZE; i++) {
- gp->rx_ring[i].next =
- cpu_to_dma32(gp->rx_ring_dma +
- sizeof(gt96100_rd_t) * (i+1));
- gp->rx_ring[i].buff_ptr =
- cpu_to_dma32(gp->rx_buff_dma + i*PKT_BUF_SZ);
- gp->rx_ring[i].buff_sz = cpu_to_dma16(PKT_BUF_SZ);
- // Give ownership to device, set first and last, enable intr
- gp->rx_ring[i].cmdstat =
- cpu_to_dma32((u32)(rxFirst | rxLast | rxOwn | rxEI));
- dump_rx_desc(4, dev, i);
- }
- /* Wrap the ring. */
- gp->rx_ring[i-1].next = cpu_to_dma32(gp->rx_ring_dma);
-
- // Setup only the lowest priority RxFDP and RxCDP regs
- for (i=0; i<4; i++) {
- if (i == 0) {
- GT96100ETH_WRITE(gp, GT96100_ETH_1ST_RX_DESC_PTR0,
- gp->rx_ring_dma);
- GT96100ETH_WRITE(gp, GT96100_ETH_CURR_RX_DESC_PTR0,
- gp->rx_ring_dma);
- } else {
- GT96100ETH_WRITE(gp,
- GT96100_ETH_1ST_RX_DESC_PTR0 + i*4,
- 0);
- GT96100ETH_WRITE(gp,
- GT96100_ETH_CURR_RX_DESC_PTR0 + i*4,
- 0);
- }
- }
-
- // init Rx NextOut index
- gp->rx_next_out = 0;
-}
-
-
-// Returns 1 if the Tx counter and indeces don't gel
-static int
-gt96100_check_tx_consistent(struct gt96100_private *gp)
-{
- int diff = gp->tx_next_in - gp->tx_next_out;
-
- diff = diff<0 ? TX_RING_SIZE + diff : diff;
- diff = gp->tx_count == TX_RING_SIZE ? diff + TX_RING_SIZE : diff;
-
- return (diff != gp->tx_count);
-}
-
-static int
-gt96100_init(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- u32 tmp;
- u16 mii_reg;
-
- dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
- dbg(3, "%s: scs10_lo=%4x, scs10_hi=%4x\n", __FUNCTION__,
- GT96100_READ(0x8), GT96100_READ(0x10));
- dbg(3, "%s: scs32_lo=%4x, scs32_hi=%4x\n", __FUNCTION__,
- GT96100_READ(0x18), GT96100_READ(0x20));
-
- // Stop and disable Port
- hard_stop(dev);
-
- // Setup CIU Arbiter
- tmp = GT96100_READ(GT96100_CIU_ARBITER_CONFIG);
- tmp |= (0x0c << (gp->port_num*2)); // set Ether DMA req priority to hi
-#ifndef DESC_BE
- tmp &= ~(1<<31); // set desc endianess to little
-#else
- tmp |= (1<<31);
-#endif
- GT96100_WRITE(GT96100_CIU_ARBITER_CONFIG, tmp);
- dbg(3, "%s: CIU Config=%x/%x\n", __FUNCTION__,
- tmp, GT96100_READ(GT96100_CIU_ARBITER_CONFIG));
-
- // Set routing.
- tmp = GT96100_READ(GT96100_ROUTE_MAIN) & (0x3f << 18);
- tmp |= (0x07 << (18 + gp->port_num*3));
- GT96100_WRITE(GT96100_ROUTE_MAIN, tmp);
-
- /* set MII as peripheral func */
- tmp = GT96100_READ(GT96100_GPP_CONFIG2);
- tmp |= 0x7fff << (gp->port_num*16);
- GT96100_WRITE(GT96100_GPP_CONFIG2, tmp);
-
- /* Set up MII port pin directions */
- tmp = GT96100_READ(GT96100_GPP_IO2);
- tmp |= 0x003d << (gp->port_num*16);
- GT96100_WRITE(GT96100_GPP_IO2, tmp);
-
- // Set-up hash table
- memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE); // clear it
- gp->hash_mode = 0;
- // Add a single entry to hash table - our ethernet address
- gt96100_add_hash_entry(dev, dev->dev_addr);
- // Set-up DMA ptr to hash table
- GT96100ETH_WRITE(gp, GT96100_ETH_HASH_TBL_PTR, gp->hash_table_dma);
- dbg(3, "%s: Hash Tbl Ptr=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_HASH_TBL_PTR));
-
- // Setup Tx
- reset_tx(dev);
-
- dbg(3, "%s: Curr Tx Desc Ptr0=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0));
-
- // Setup Rx
- reset_rx(dev);
-
- dbg(3, "%s: 1st/Curr Rx Desc Ptr0=%x/%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0),
- GT96100ETH_READ(gp, GT96100_ETH_CURR_RX_DESC_PTR0));
-
- // eth port config register
- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
- pcxrFCTL | pcxrFCTLen | pcxrFLP | pcxrDPLXen);
-
- mii_reg = read_MII(gp->phy_addr, 0x11); /* int enable register */
- mii_reg |= 2; /* enable mii interrupt */
- write_MII(gp->phy_addr, 0x11, mii_reg);
-
- dbg(3, "%s: PhyAD=%x\n", __FUNCTION__,
- GT96100_READ(GT96100_ETH_PHY_ADDR_REG));
-
- // setup DMA
-
- // We want the Rx/Tx DMA to write/read data to/from memory in
- // Big Endian mode. Also set DMA Burst Size to 8 64Bit words.
-#ifdef DESC_DATA_BE
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,
- (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
-#else
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_CONFIG,
- sdcrBLMR | sdcrBLMT |
- (0xf<<sdcrRCBit) | sdcrRIFB | (3<<sdcrBSZBit));
-#endif
- dbg(3, "%s: SDMA Config=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_SDMA_CONFIG));
-
- // start Rx DMA
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
- dbg(3, "%s: SDMA Comm=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_SDMA_COMM));
-
- // enable this port (set hash size to 1/2K)
- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG, pcrEN | pcrHS);
- dbg(3, "%s: Port Config=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG));
-
- /*
- * Disable all Type-of-Service queueing. All Rx packets will be
- * treated normally and will be sent to the lowest priority
- * queue.
- *
- * Disable flow-control for now. FIXME: support flow control?
- */
-
- // clear all the MIB ctr regs
- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
- pcxrFCTL | pcxrFCTLen | pcxrFLP |
- pcxrPRIOrxOverride);
- read_mib_counters(gp);
- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG_EXT,
- pcxrFCTL | pcxrFCTLen | pcxrFLP |
- pcxrPRIOrxOverride | pcxrMIBclrMode);
-
- dbg(3, "%s: Port Config Ext=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_PORT_CONFIG_EXT));
-
- netif_start_queue(dev);
-
- dump_MII(4, dev);
-
- // enable interrupts
- enable_ether_irq(dev);
-
- // we should now be receiving frames
- return 0;
-}
-
-
-static int
-gt96100_open(struct net_device *dev)
-{
- int retval;
-
- dbg(2, "%s: dev=%p\n", __FUNCTION__, dev);
-
- // Initialize and startup the GT-96100 ethernet port
- if ((retval = gt96100_init(dev))) {
- err("error in gt96100_init\n");
- free_irq(dev->irq, dev);
- return retval;
- }
-
- if ((retval = request_irq(dev->irq, &gt96100_interrupt,
- SA_SHIRQ, dev->name, dev))) {
- err("unable to get IRQ %d\n", dev->irq);
- return retval;
- }
-
- dbg(2, "%s: Initialization done.\n", __FUNCTION__);
-
- return 0;
-}
-
-static int
-gt96100_close(struct net_device *dev)
-{
- dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
-
- // stop the device
- if (netif_device_present(dev)) {
- netif_stop_queue(dev);
- hard_stop(dev);
- }
-
- free_irq(dev->irq, dev);
-
- return 0;
-}
-
-
-static int
-gt96100_tx(struct sk_buff *skb, struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- unsigned long flags;
- int nextIn;
-
- spin_lock_irqsave(&gp->lock, flags);
-
- nextIn = gp->tx_next_in;
-
- dbg(3, "%s: nextIn=%d\n", __FUNCTION__, nextIn);
-
- if (gp->tx_count >= TX_RING_SIZE) {
- warn("Tx Ring full, pkt dropped.\n");
- gp->stats.tx_dropped++;
- spin_unlock_irqrestore(&gp->lock, flags);
- return 1;
- }
-
- if (!(gp->last_psr & psrLink)) {
- err("%s: Link down, pkt dropped.\n", __FUNCTION__);
- gp->stats.tx_dropped++;
- spin_unlock_irqrestore(&gp->lock, flags);
- return 1;
- }
-
- if (dma32_to_cpu(gp->tx_ring[nextIn].cmdstat) & txOwn) {
- err("%s: device owns descriptor, pkt dropped.\n", __FUNCTION__);
- gp->stats.tx_dropped++;
- // stop the queue, so Tx timeout can fix it
- netif_stop_queue(dev);
- spin_unlock_irqrestore(&gp->lock, flags);
- return 1;
- }
-
- // Prepare the Descriptor at tx_next_in
- gp->tx_skbuff[nextIn] = skb;
- gp->tx_ring[nextIn].byte_cnt = cpu_to_dma16(skb->len);
- gp->tx_ring[nextIn].buff_ptr = cpu_to_dma32(virt_to_phys(skb->data));
- // make sure packet gets written back to memory
- dma_cache_wback_inv((unsigned long)(skb->data), skb->len);
- // Give ownership to device, set first and last desc, enable interrupt
- // Setting of ownership bit must be *last*!
- gp->tx_ring[nextIn].cmdstat =
- cpu_to_dma32((u32)(txOwn | txGenCRC | txEI |
- txPad | txFirst | txLast));
-
- dump_tx_desc(4, dev, nextIn);
- dump_skb(4, dev, skb);
-
- // increment tx_next_in with wrap
- gp->tx_next_in = (nextIn + 1) % TX_RING_SIZE;
- // If DMA is stopped, restart
- if (!(GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS) & psrTxLow))
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
- sdcmrERD | sdcmrTXDL);
-
- // increment count and stop queue if full
- if (++gp->tx_count == TX_RING_SIZE) {
- gp->tx_full = 1;
- netif_stop_queue(dev);
- dbg(2, "Tx Ring now full, queue stopped.\n");
- }
-
- dev->trans_start = jiffies;
- spin_unlock_irqrestore(&gp->lock, flags);
-
- return 0;
-}
-
-
-static int
-gt96100_rx(struct net_device *dev, u32 status)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- struct sk_buff *skb;
- int pkt_len, nextOut, cdp;
- gt96100_rd_t *rd;
- u32 cmdstat;
-
- dbg(3, "%s: dev=%p, status=%x\n", __FUNCTION__, dev, status);
-
- cdp = (GT96100ETH_READ(gp, GT96100_ETH_1ST_RX_DESC_PTR0)
- - gp->rx_ring_dma) / sizeof(gt96100_rd_t);
-
- // Continue until we reach 1st descriptor pointer
- for (nextOut = gp->rx_next_out; nextOut != cdp;
- nextOut = (nextOut + 1) % RX_RING_SIZE) {
-
- if (--gp->intr_work_done == 0)
- break;
-
- rd = &gp->rx_ring[nextOut];
- cmdstat = dma32_to_cpu(rd->cmdstat);
-
- dbg(4, "%s: Rx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
- cmdstat, nextOut);
-
- if (cmdstat & (u32)rxOwn) {
- //err("%s: device owns descriptor!\n", __FUNCTION__);
- // DMA is not finished updating descriptor???
- // Leave and come back later to pick-up where
- // we left off.
- break;
- }
-
- // Drop this received pkt if there were any errors
- if (((cmdstat & (u32)(rxErrorSummary)) &&
- (cmdstat & (u32)(rxFirst))) || (status & icrRxError)) {
- // update the detailed rx error counters that
- // are not covered by the MIB counters.
- if (cmdstat & (u32)rxOverrun)
- gp->stats.rx_fifo_errors++;
- cmdstat |= (u32)rxOwn;
- rd->cmdstat = cpu_to_dma32(cmdstat);
- continue;
- }
-
- /*
- * Must be first and last (ie only) descriptor of packet. We
- * ignore (drop) any packets that do not fit in one descriptor.
- * Every descriptor's receive buffer is large enough to hold
- * the maximum 802.3 frame size, so a multi-descriptor packet
- * indicates an error. Most if not all corrupted packets will
- * have already been dropped by the above check for the
- * rxErrorSummary status bit.
- */
- if (!(cmdstat & (u32)rxFirst) || !(cmdstat & (u32)rxLast)) {
- if (cmdstat & (u32)rxFirst) {
- /*
- * This is the first descriptor of a
- * multi-descriptor packet. It isn't corrupted
- * because the above check for rxErrorSummary
- * would have dropped it already, so what's
- * the deal with this packet? Good question,
- * let's dump it out.
- */
- err("%s: desc not first and last!\n", __FUNCTION__);
- dump_rx_desc(0, dev, nextOut);
- }
- cmdstat |= (u32)rxOwn;
- rd->cmdstat = cpu_to_dma32(cmdstat);
- // continue to drop every descriptor of this packet
- continue;
- }
-
- pkt_len = dma16_to_cpu(rd->byte_cnt);
-
- /* Create new skb. */
- skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL) {
- err("%s: Memory squeeze, dropping packet.\n", __FUNCTION__);
- gp->stats.rx_dropped++;
- cmdstat |= (u32)rxOwn;
- rd->cmdstat = cpu_to_dma32(cmdstat);
- continue;
- }
- skb->dev = dev;
- skb_reserve(skb, 2); /* 16 byte IP header align */
- memcpy(skb_put(skb, pkt_len),
- &gp->rx_buff[nextOut*PKT_BUF_SZ], pkt_len);
- skb->protocol = eth_type_trans(skb, dev);
- dump_skb(4, dev, skb);
-
- netif_rx(skb); /* pass the packet to upper layers */
- dev->last_rx = jiffies;
-
- // now we can release ownership of this desc back to device
- cmdstat |= (u32)rxOwn;
- rd->cmdstat = cpu_to_dma32(cmdstat);
- }
-
- if (nextOut == gp->rx_next_out)
- dbg(3, "%s: RxCDP did not increment?\n", __FUNCTION__);
-
- gp->rx_next_out = nextOut;
- return 0;
-}
-
-
-static void
-gt96100_tx_complete(struct net_device *dev, u32 status)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- int nextOut, cdp;
- gt96100_td_t *td;
- u32 cmdstat;
-
- cdp = (GT96100ETH_READ(gp, GT96100_ETH_CURR_TX_DESC_PTR0)
- - gp->tx_ring_dma) / sizeof(gt96100_td_t);
-
- // Continue until we reach the current descriptor pointer
- for (nextOut = gp->tx_next_out; nextOut != cdp;
- nextOut = (nextOut + 1) % TX_RING_SIZE) {
-
- if (--gp->intr_work_done == 0)
- break;
-
- td = &gp->tx_ring[nextOut];
- cmdstat = dma32_to_cpu(td->cmdstat);
-
- dbg(3, "%s: Tx desc cmdstat=%x, nextOut=%d\n", __FUNCTION__,
- cmdstat, nextOut);
-
- if (cmdstat & (u32)txOwn) {
- /*
- * DMA is not finished writing descriptor???
- * Leave and come back later to pick-up where
- * we left off.
- */
- break;
- }
-
- // increment Tx error stats
- if (cmdstat & (u32)txErrorSummary) {
- dbg(2, "%s: Tx error, cmdstat = %x\n", __FUNCTION__,
- cmdstat);
- gp->stats.tx_errors++;
- if (cmdstat & (u32)txReTxLimit)
- gp->stats.tx_aborted_errors++;
- if (cmdstat & (u32)txUnderrun)
- gp->stats.tx_fifo_errors++;
- if (cmdstat & (u32)txLateCollision)
- gp->stats.tx_window_errors++;
- }
-
- if (cmdstat & (u32)txCollision)
- gp->stats.collisions +=
- (u32)((cmdstat & txReTxCntMask) >>
- txReTxCntBit);
-
- // Wake the queue if the ring was full
- if (gp->tx_full) {
- gp->tx_full = 0;
- if (gp->last_psr & psrLink) {
- netif_wake_queue(dev);
- dbg(2, "%s: Tx Ring was full, queue waked\n",
- __FUNCTION__);
- }
- }
-
- // decrement tx ring buffer count
- if (gp->tx_count) gp->tx_count--;
-
- // free the skb
- if (gp->tx_skbuff[nextOut]) {
- dbg(3, "%s: good Tx, skb=%p\n", __FUNCTION__,
- gp->tx_skbuff[nextOut]);
- dev_kfree_skb_irq(gp->tx_skbuff[nextOut]);
- gp->tx_skbuff[nextOut] = NULL;
- } else {
- err("%s: no skb!\n", __FUNCTION__);
- }
- }
-
- gp->tx_next_out = nextOut;
-
- if (gt96100_check_tx_consistent(gp)) {
- err("%s: Tx queue inconsistent!\n", __FUNCTION__);
- }
-
- if ((status & icrTxEndLow) && gp->tx_count != 0) {
- // we must restart the DMA
- dbg(3, "%s: Restarting Tx DMA\n", __FUNCTION__);
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM,
- sdcmrERD | sdcmrTXDL);
- }
-}
-
-
-static irqreturn_t
-gt96100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct net_device *dev = (struct net_device *)dev_id;
- struct gt96100_private *gp = netdev_priv(dev);
- u32 status;
- int handled = 0;
-
- if (dev == NULL) {
- err("%s: null dev ptr\n", __FUNCTION__);
- return IRQ_NONE;
- }
-
- dbg(3, "%s: entry, icr=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
-
- spin_lock(&gp->lock);
-
- gp->intr_work_done = max_interrupt_work;
-
- while (gp->intr_work_done > 0) {
-
- status = GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE);
- // ACK interrupts
- GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, ~status);
-
- if ((status & icrEtherIntSum) == 0 &&
- !(status & (icrTxBufferLow|icrTxBufferHigh|icrRxBuffer)))
- break;
-
- handled = 1;
-
- if (status & icrMIIPhySTC) {
- u32 psr = GT96100ETH_READ(gp, GT96100_ETH_PORT_STATUS);
- if (gp->last_psr != psr) {
- dbg(0, "port status:\n");
- dbg(0, " %s MBit/s, %s-duplex, "
- "flow-control %s, link is %s,\n",
- psr & psrSpeed ? "100":"10",
- psr & psrDuplex ? "full":"half",
- psr & psrFctl ? "disabled":"enabled",
- psr & psrLink ? "up":"down");
- dbg(0, " TxLowQ is %s, TxHighQ is %s, "
- "Transmitter is %s\n",
- psr & psrTxLow ? "running":"stopped",
- psr & psrTxHigh ? "running":"stopped",
- psr & psrTxInProg ? "on":"off");
-
- if ((psr & psrLink) && !gp->tx_full &&
- netif_queue_stopped(dev)) {
- dbg(0, "%s: Link up, waking queue.\n",
- __FUNCTION__);
- netif_wake_queue(dev);
- } else if (!(psr & psrLink) &&
- !netif_queue_stopped(dev)) {
- dbg(0, "%s: Link down, stopping queue.\n",
- __FUNCTION__);
- netif_stop_queue(dev);
- }
-
- gp->last_psr = psr;
- }
-
- if (--gp->intr_work_done == 0)
- break;
- }
-
- if (status & (icrTxBufferLow | icrTxEndLow))
- gt96100_tx_complete(dev, status);
-
- if (status & (icrRxBuffer | icrRxError)) {
- gt96100_rx(dev, status);
- }
-
- // Now check TX errors (RX errors were handled in gt96100_rx)
- if (status & icrTxErrorLow) {
- err("%s: Tx resource error\n", __FUNCTION__);
- if (--gp->intr_work_done == 0)
- break;
- }
-
- if (status & icrTxUdr) {
- err("%s: Tx underrun error\n", __FUNCTION__);
- if (--gp->intr_work_done == 0)
- break;
- }
- }
-
- if (gp->intr_work_done == 0) {
- // ACK any remaining pending interrupts
- GT96100ETH_WRITE(gp, GT96100_ETH_INT_CAUSE, 0);
- dbg(3, "%s: hit max work\n", __FUNCTION__);
- }
-
- dbg(3, "%s: exit, icr=%x\n", __FUNCTION__,
- GT96100ETH_READ(gp, GT96100_ETH_INT_CAUSE));
-
- spin_unlock(&gp->lock);
- return IRQ_RETVAL(handled);
-}
-
-
-static void
-gt96100_tx_timeout(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- unsigned long flags;
-
- spin_lock_irqsave(&gp->lock, flags);
-
- if (!(gp->last_psr & psrLink)) {
- err("tx_timeout: link down.\n");
- spin_unlock_irqrestore(&gp->lock, flags);
- } else {
- if (gt96100_check_tx_consistent(gp))
- err("tx_timeout: Tx ring error.\n");
-
- disable_ether_irq(dev);
- spin_unlock_irqrestore(&gp->lock, flags);
- reset_tx(dev);
- enable_ether_irq(dev);
-
- netif_wake_queue(dev);
- }
-}
-
-
-static void
-gt96100_set_rx_mode(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- unsigned long flags;
- //struct dev_mc_list *mcptr;
-
- dbg(3, "%s: dev=%p, flags=%x\n", __FUNCTION__, dev, dev->flags);
-
- // stop the Receiver DMA
- abort(dev, sdcmrAR);
-
- spin_lock_irqsave(&gp->lock, flags);
-
- if (dev->flags & IFF_PROMISC) {
- GT96100ETH_WRITE(gp, GT96100_ETH_PORT_CONFIG,
- pcrEN | pcrHS | pcrPM);
- }
-
-#if 0
- /*
- FIXME: currently multicast doesn't work - need to get hash table
- working first.
- */
- if (dev->mc_count) {
- // clear hash table
- memset(gp->hash_table, 0, RX_HASH_TABLE_SIZE);
- // Add our ethernet address
- gt96100_add_hash_entry(dev, dev->dev_addr);
-
- for (mcptr = dev->mc_list; mcptr; mcptr = mcptr->next) {
- dump_hw_addr(2, dev, "%s: addr=", __FUNCTION__,
- mcptr->dmi_addr);
- gt96100_add_hash_entry(dev, mcptr->dmi_addr);
- }
- }
-#endif
-
- // restart Rx DMA
- GT96100ETH_WRITE(gp, GT96100_ETH_SDMA_COMM, sdcmrERD);
-
- spin_unlock_irqrestore(&gp->lock, flags);
-}
-
-static struct net_device_stats *
-gt96100_get_stats(struct net_device *dev)
-{
- struct gt96100_private *gp = netdev_priv(dev);
- unsigned long flags;
-
- dbg(3, "%s: dev=%p\n", __FUNCTION__, dev);
-
- if (netif_device_present(dev)) {
- spin_lock_irqsave (&gp->lock, flags);
- update_stats(gp);
- spin_unlock_irqrestore (&gp->lock, flags);
- }
-
- return &gp->stats;
-}
-
-static void gt96100_cleanup_module(void)
-{
- int i;
- for (i=0; i<NUM_INTERFACES; i++) {
- struct gt96100_if_t *gtif = &gt96100_iflist[i];
- if (gtif->dev != NULL) {
- struct gt96100_private *gp = (struct gt96100_private *)
- netdev_priv(gtif->dev);
- unregister_netdev(gtif->dev);
- dmafree(RX_HASH_TABLE_SIZE, gp->hash_table_dma);
- dmafree(PKT_BUF_SZ*RX_RING_SIZE, gp->rx_buff);
- dmafree(sizeof(gt96100_rd_t) * RX_RING_SIZE
- + sizeof(gt96100_td_t) * TX_RING_SIZE,
- gp->rx_ring);
- free_netdev(gtif->dev);
- release_region(gtif->iobase, gp->io_size);
- }
- }
-}
-
-static int __init gt96100_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep (&options, ",")) != NULL) {
- if (!*this_opt)
- continue;
- if (!strncmp(this_opt, "mac0:", 5)) {
- memcpy(mac0, this_opt+5, 17);
- mac0[17]= '\0';
- } else if (!strncmp(this_opt, "mac1:", 5)) {
- memcpy(mac1, this_opt+5, 17);
- mac1[17]= '\0';
- }
- }
-
- return 1;
-}
-
-__setup("gt96100eth=", gt96100_setup);
-
-module_init(gt96100_init_module);
-module_exit(gt96100_cleanup_module);
-
-MODULE_AUTHOR("Steve Longerbeam <stevel@mvista.com>");
-MODULE_DESCRIPTION("GT96100 Ethernet driver");
diff --git a/drivers/net/gt96100eth.h b/drivers/net/gt96100eth.h
deleted file mode 100644
index 395869c5ed3..00000000000
--- a/drivers/net/gt96100eth.h
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.com
- *
- * ########################################################################
- *
- * This program is free software; you can distribute it and/or modify it
- * under the terms of the GNU General Public License (Version 2) as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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.
- *
- * ########################################################################
- *
- * Ethernet driver definitions for the MIPS GT96100 Advanced
- * Communication Controller.
- *
- */
-#ifndef _GT96100ETH_H
-#define _GT96100ETH_H
-
-#include <linux/config.h>
-#include <asm/galileo-boards/gt96100.h>
-
-#define dbg(lvl, format, arg...) \
- if (lvl <= GT96100_DEBUG) \
- printk(KERN_DEBUG "%s: " format, dev->name , ## arg)
-#define err(format, arg...) \
- printk(KERN_ERR "%s: " format, dev->name , ## arg)
-#define info(format, arg...) \
- printk(KERN_INFO "%s: " format, dev->name , ## arg)
-#define warn(format, arg...) \
- printk(KERN_WARNING "%s: " format, dev->name , ## arg)
-
-/* Keep the ring sizes a power of two for efficiency. */
-#define TX_RING_SIZE 16
-#define RX_RING_SIZE 32
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
-
-#define RX_HASH_TABLE_SIZE 16384
-#define HASH_HOP_NUMBER 12
-
-#define NUM_INTERFACES 2
-
-#define GT96100ETH_TX_TIMEOUT HZ/4
-
-#define GT96100_ETH0_BASE (MIPS_GT96100_BASE + GT96100_ETH_PORT_CONFIG)
-#define GT96100_ETH1_BASE (GT96100_ETH0_BASE + GT96100_ETH_IO_SIZE)
-
-#ifdef CONFIG_MIPS_EV96100
-#define GT96100_ETHER0_IRQ 3
-#define GT96100_ETHER1_IRQ 4
-#else
-#define GT96100_ETHER0_IRQ -1
-#define GT96100_ETHER1_IRQ -1
-#endif
-
-#define REV_GT96100 1
-#define REV_GT96100A_1 2
-#define REV_GT96100A 3
-
-#define GT96100ETH_READ(gp, offset) \
- GT96100_READ((gp->port_offset + offset))
-
-#define GT96100ETH_WRITE(gp, offset, data) \
- GT96100_WRITE((gp->port_offset + offset), data)
-
-#define GT96100ETH_SETBIT(gp, offset, bits) {\
- u32 val = GT96100ETH_READ(gp, offset); val |= (u32)(bits); \
- GT96100ETH_WRITE(gp, offset, val); }
-
-#define GT96100ETH_CLRBIT(gp, offset, bits) {\
- u32 val = GT96100ETH_READ(gp, offset); val &= (u32)(~(bits)); \
- GT96100ETH_WRITE(gp, offset, val); }
-
-
-/* Bit definitions of the SMI Reg */
-enum {
- smirDataMask = 0xffff,
- smirPhyAdMask = 0x1f<<16,
- smirPhyAdBit = 16,
- smirRegAdMask = 0x1f<<21,
- smirRegAdBit = 21,
- smirOpCode = 1<<26,
- smirReadValid = 1<<27,
- smirBusy = 1<<28
-};
-
-/* Bit definitions of the Port Config Reg */
-enum pcr_bits {
- pcrPM = 1,
- pcrRBM = 2,
- pcrPBF = 4,
- pcrEN = 1<<7,
- pcrLPBKMask = 0x3<<8,
- pcrLPBKBit = 8,
- pcrFC = 1<<10,
- pcrHS = 1<<12,
- pcrHM = 1<<13,
- pcrHDM = 1<<14,
- pcrHD = 1<<15,
- pcrISLMask = 0x7<<28,
- pcrISLBit = 28,
- pcrACCS = 1<<31
-};
-
-/* Bit definitions of the Port Config Extend Reg */
-enum pcxr_bits {
- pcxrIGMP = 1,
- pcxrSPAN = 2,
- pcxrPAR = 4,
- pcxrPRIOtxMask = 0x7<<3,
- pcxrPRIOtxBit = 3,
- pcxrPRIOrxMask = 0x3<<6,
- pcxrPRIOrxBit = 6,
- pcxrPRIOrxOverride = 1<<8,
- pcxrDPLXen = 1<<9,
- pcxrFCTLen = 1<<10,
- pcxrFLP = 1<<11,
- pcxrFCTL = 1<<12,
- pcxrMFLMask = 0x3<<14,
- pcxrMFLBit = 14,
- pcxrMIBclrMode = 1<<16,
- pcxrSpeed = 1<<18,
- pcxrSpeeden = 1<<19,
- pcxrRMIIen = 1<<20,
- pcxrDSCPen = 1<<21
-};
-
-/* Bit definitions of the Port Command Reg */
-enum pcmr_bits {
- pcmrFJ = 1<<15
-};
-
-
-/* Bit definitions of the Port Status Reg */
-enum psr_bits {
- psrSpeed = 1,
- psrDuplex = 2,
- psrFctl = 4,
- psrLink = 8,
- psrPause = 1<<4,
- psrTxLow = 1<<5,
- psrTxHigh = 1<<6,
- psrTxInProg = 1<<7
-};
-
-/* Bit definitions of the SDMA Config Reg */
-enum sdcr_bits {
- sdcrRCMask = 0xf<<2,
- sdcrRCBit = 2,
- sdcrBLMR = 1<<6,
- sdcrBLMT = 1<<7,
- sdcrPOVR = 1<<8,
- sdcrRIFB = 1<<9,
- sdcrBSZMask = 0x3<<12,
- sdcrBSZBit = 12
-};
-
-/* Bit definitions of the SDMA Command Reg */
-enum sdcmr_bits {
- sdcmrERD = 1<<7,
- sdcmrAR = 1<<15,
- sdcmrSTDH = 1<<16,
- sdcmrSTDL = 1<<17,
- sdcmrTXDH = 1<<23,
- sdcmrTXDL = 1<<24,
- sdcmrAT = 1<<31
-};
-
-/* Bit definitions of the Interrupt Cause Reg */
-enum icr_bits {
- icrRxBuffer = 1,
- icrTxBufferHigh = 1<<2,
- icrTxBufferLow = 1<<3,
- icrTxEndHigh = 1<<6,
- icrTxEndLow = 1<<7,
- icrRxError = 1<<8,
- icrTxErrorHigh = 1<<10,
- icrTxErrorLow = 1<<11,
- icrRxOVR = 1<<12,
- icrTxUdr = 1<<13,
- icrRxBufferQ0 = 1<<16,
- icrRxBufferQ1 = 1<<17,
- icrRxBufferQ2 = 1<<18,
- icrRxBufferQ3 = 1<<19,
- icrRxErrorQ0 = 1<<20,
- icrRxErrorQ1 = 1<<21,
- icrRxErrorQ2 = 1<<22,
- icrRxErrorQ3 = 1<<23,
- icrMIIPhySTC = 1<<28,
- icrSMIdone = 1<<29,
- icrEtherIntSum = 1<<31
-};
-
-
-/* The Rx and Tx descriptor lists. */
-typedef struct {
-#ifdef DESC_BE
- u16 byte_cnt;
- u16 reserved;
-#else
- u16 reserved;
- u16 byte_cnt;
-#endif
- u32 cmdstat;
- u32 next;
- u32 buff_ptr;
-} __attribute__ ((packed)) gt96100_td_t;
-
-typedef struct {
-#ifdef DESC_BE
- u16 buff_sz;
- u16 byte_cnt;
-#else
- u16 byte_cnt;
- u16 buff_sz;
-#endif
- u32 cmdstat;
- u32 next;
- u32 buff_ptr;
-} __attribute__ ((packed)) gt96100_rd_t;
-
-
-/* Values for the Tx command-status descriptor entry. */
-enum td_cmdstat {
- txOwn = 1<<31,
- txAutoMode = 1<<30,
- txEI = 1<<23,
- txGenCRC = 1<<22,
- txPad = 1<<18,
- txFirst = 1<<17,
- txLast = 1<<16,
- txErrorSummary = 1<<15,
- txReTxCntMask = 0x0f<<10,
- txReTxCntBit = 10,
- txCollision = 1<<9,
- txReTxLimit = 1<<8,
- txUnderrun = 1<<6,
- txLateCollision = 1<<5
-};
-
-
-/* Values for the Rx command-status descriptor entry. */
-enum rd_cmdstat {
- rxOwn = 1<<31,
- rxAutoMode = 1<<30,
- rxEI = 1<<23,
- rxFirst = 1<<17,
- rxLast = 1<<16,
- rxErrorSummary = 1<<15,
- rxIGMP = 1<<14,
- rxHashExpired = 1<<13,
- rxMissedFrame = 1<<12,
- rxFrameType = 1<<11,
- rxShortFrame = 1<<8,
- rxMaxFrameLen = 1<<7,
- rxOverrun = 1<<6,
- rxCollision = 1<<4,
- rxCRCError = 1
-};
-
-/* Bit fields of a Hash Table Entry */
-enum hash_table_entry {
- hteValid = 1,
- hteSkip = 2,
- hteRD = 4
-};
-
-// The MIB counters
-typedef struct {
- u32 byteReceived;
- u32 byteSent;
- u32 framesReceived;
- u32 framesSent;
- u32 totalByteReceived;
- u32 totalFramesReceived;
- u32 broadcastFramesReceived;
- u32 multicastFramesReceived;
- u32 cRCError;
- u32 oversizeFrames;
- u32 fragments;
- u32 jabber;
- u32 collision;
- u32 lateCollision;
- u32 frames64;
- u32 frames65_127;
- u32 frames128_255;
- u32 frames256_511;
- u32 frames512_1023;
- u32 frames1024_MaxSize;
- u32 macRxError;
- u32 droppedFrames;
- u32 outMulticastFrames;
- u32 outBroadcastFrames;
- u32 undersizeFrames;
-} mib_counters_t;
-
-
-struct gt96100_private {
- gt96100_rd_t* rx_ring;
- gt96100_td_t* tx_ring;
- // The Rx and Tx rings must be 16-byte aligned
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_ring_dma;
- char* hash_table;
- // The Hash Table must be 8-byte aligned
- dma_addr_t hash_table_dma;
- int hash_mode;
-
- // The Rx buffers must be 8-byte aligned
- char* rx_buff;
- dma_addr_t rx_buff_dma;
- // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
- // of payload must be 8-byte aligned
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- int rx_next_out; /* The next free ring entry to receive */
- int tx_next_in; /* The next free ring entry to send */
- int tx_next_out; /* The last ring entry the ISR processed */
- int tx_count; /* current # of pkts waiting to be sent in Tx ring */
- int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
- int tx_full; /* Tx ring is full */
-
- mib_counters_t mib;
- struct net_device_stats stats;
-
- int io_size;
- int port_num; // 0 or 1
- int chip_rev;
- u32 port_offset;
-
- int phy_addr; // PHY address
- u32 last_psr; // last value of the port status register
-
- int options; /* User-settable misc. driver options. */
- int drv_flags;
- struct timer_list timer;
- spinlock_t lock; /* Serialise access to device */
-};
-
-#endif
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 0ea4cb4a0d8..5c89ae78a51 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -3,7 +3,7 @@
Written 1998-2000 by Donald Becker.
Updates 2000 by Keith Underwood.
- This software may be used and distributed according to the terms of
+ This software may be used and distributed according to the terms of
the GNU General Public License (GPL), incorporated herein by reference.
Drivers based on or derived from this code fall under the GPL and must
retain the authorship, copyright and license notice. This file is not
@@ -20,22 +20,15 @@
Support and updates available at
http://www.scyld.com/network/hamachi.html
+ [link no longer provides useful info -jgarzik]
or
http://www.parl.clemson.edu/~keithu/hamachi.html
-
-
- Linux kernel changelog:
-
- LK1.0.1:
- - fix lack of pci_dev<->dev association
- - ethtool support (jgarzik)
-
*/
#define DRV_NAME "hamachi"
-#define DRV_VERSION "1.01+LK1.0.1"
-#define DRV_RELDATE "5/18/2001"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "Sept 11, 2006"
/* A few user-configurable values. */
@@ -53,7 +46,7 @@ static int mtu;
static int max_rx_latency = 0x11;
static int max_rx_gap = 0x05;
static int min_rx_pkt = 0x18;
-static int max_tx_latency = 0x00;
+static int max_tx_latency = 0x00;
static int max_tx_gap = 0x00;
static int min_tx_pkt = 0x30;
@@ -83,7 +76,7 @@ static int force32;
- The next bit can be used to force half-duplex. This is a bad
idea since no known implementations implement half-duplex, and,
in general, half-duplex for gigabit ethernet is a bad idea.
- 0x00000080 : Force half-duplex
+ 0x00000080 : Force half-duplex
Default is full-duplex.
- In the original driver, the ninth bit could be used to force
full-duplex. Maintain that for compatibility
@@ -94,7 +87,7 @@ static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* The Hamachi chipset supports 3 parameters each for Rx and Tx
* interruput management. Parameters will be loaded as specified into
- * the TxIntControl and RxIntControl registers.
+ * the TxIntControl and RxIntControl registers.
*
* The registers are arranged as follows:
* 23 - 16 15 - 8 7 - 0
@@ -102,10 +95,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
* | min_pkt | max_gap | max_latency |
* ---------------------------------
* min_pkt : The minimum number of packets processed between
- * interrupts.
+ * interrupts.
* max_gap : The maximum inter-packet gap in units of 8.192 us
* max_latency : The absolute time between interrupts in units of 8.192 us
- *
+ *
*/
static int rx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
@@ -190,7 +183,7 @@ KERN_INFO " Further modifications by Keith Underwood <keithu@parl.clemson.edu>
other linux headers causing many compiler warnings.
*/
#ifndef IP_MF
- #define IP_MF 0x2000 /* IP more frags from <netinet/ip.h> */
+ #define IP_MF 0x2000 /* IP more frags from <netinet/ip.h> */
#endif
/* Define IP_OFFSET to be IPOPT_OFFSET */
@@ -211,9 +204,9 @@ KERN_INFO " Further modifications by Keith Underwood <keithu@parl.clemson.edu>
/* Condensed bus+endian portability operations. */
#if ADDRLEN == 64
#define cpu_to_leXX(addr) cpu_to_le64(addr)
-#else
+#else
#define cpu_to_leXX(addr) cpu_to_le32(addr)
-#endif
+#endif
/*
@@ -298,30 +291,30 @@ Hamachi Engineering Design Specification, 5/15/97
IVc. Errata
-None noted.
+None noted.
V. Recent Changes
-01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears
+01/15/1999 EPK Enlargement of the TX and RX ring sizes. This appears
to help avoid some stall conditions -- this needs further research.
-01/15/1999 EPK Creation of the hamachi_tx function. This function cleans
+01/15/1999 EPK Creation of the hamachi_tx function. This function cleans
the Tx ring and is called from hamachi_start_xmit (this used to be
called from hamachi_interrupt but it tends to delay execution of the
interrupt handler and thus reduce bandwidth by reducing the latency
- between hamachi_rx()'s). Notably, some modification has been made so
- that the cleaning loop checks only to make sure that the DescOwn bit
- isn't set in the status flag since the card is not required
+ between hamachi_rx()'s). Notably, some modification has been made so
+ that the cleaning loop checks only to make sure that the DescOwn bit
+ isn't set in the status flag since the card is not required
to set the entire flag to zero after processing.
-01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is
+01/15/1999 EPK In the hamachi_start_tx function, the Tx ring full flag is
checked before attempting to add a buffer to the ring. If the ring is full
an attempt is made to free any dirty buffers and thus find space for
the new buffer or the function returns non-zero which should case the
scheduler to reschedule the buffer later.
-01/15/1999 EPK Some adjustments were made to the chip initialization.
- End-to-end flow control should now be fully active and the interrupt
+01/15/1999 EPK Some adjustments were made to the chip initialization.
+ End-to-end flow control should now be fully active and the interrupt
algorithm vars have been changed. These could probably use further tuning.
01/15/1999 EPK Added the max_{rx,tx}_latency options. These are used to
@@ -329,7 +322,7 @@ V. Recent Changes
problems with network stalls, try setting these to higher values.
Valid values are 0x00 through 0xff.
-01/15/1999 EPK In general, the overall bandwidth has increased and
+01/15/1999 EPK In general, the overall bandwidth has increased and
latencies are better (sometimes by a factor of 2). Stalls are rare at
this point, however there still appears to be a bug somewhere between the
hardware and driver. TCP checksum errors under load also appear to be
@@ -341,20 +334,20 @@ V. Recent Changes
rings was typically getting set correctly, but the Tx ring wasn't getting
the DescEndRing bit set during initialization. ??? Does this mean the
hamachi card is using the DescEndRing in processing even if a particular
- slot isn't in use -- hypothetically, the card might be searching the
+ slot isn't in use -- hypothetically, the card might be searching the
entire Tx ring for slots with the DescOwn bit set and then processing
them. If the DescEndRing bit isn't set, then it might just wander off
through memory until it hits a chunk of data with that bit set
and then looping back.
-02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout
+02/09/1999 EPK Added Michel Mueller's TxDMA Interrupt and Tx-timeout
problem (TxCmd and RxCmd need only to be set when idle or stopped.
02/09/1999 EPK Added code to check/reset dev->tbusy in hamachi_interrupt.
- (Michel Mueller pointed out the ``permanently busy'' potential
+ (Michel Mueller pointed out the ``permanently busy'' potential
problem here).
-02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies.
+02/22/1999 EPK Added Pete Wyckoff's ioctl to control the Tx/Rx latencies.
02/23/1999 EPK Verified that the interrupt status field bits for Tx were
incorrectly defined and corrected (as per Michel Mueller).
@@ -370,7 +363,7 @@ V. Recent Changes
02/20/2000 KDU Some of the control was just plain odd. Cleaned up the
hamachi_start_xmit() and hamachi_interrupt() code. There is still some
-re-structuring I would like to do.
+re-structuring I would like to do.
03/01/2000 KDU Experimenting with a WIDE range of interrupt mitigation
parameters on a dual P3-450 setup yielded the new default interrupt
@@ -378,25 +371,25 @@ mitigation parameters. Tx should interrupt VERY infrequently due to
Eric's scheme. Rx should be more often...
03/13/2000 KDU Added a patch to make the Rx Checksum code interact
-nicely with non-linux machines.
+nicely with non-linux machines.
-03/13/2000 KDU Experimented with some of the configuration values:
+03/13/2000 KDU Experimented with some of the configuration values:
-It seems that enabling PCI performance commands for descriptors
- (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal
- performance impact for any of my tests. (ttcp, netpipe, netperf) I will
+ (changing RxDMACtrl and TxDMACtrl lower nibble from 5 to D) has minimal
+ performance impact for any of my tests. (ttcp, netpipe, netperf) I will
leave them that way until I hear further feedback.
- -Increasing the PCI_LATENCY_TIMER to 130
+ -Increasing the PCI_LATENCY_TIMER to 130
(2 + (burst size of 128 * (0 wait states + 1))) seems to slightly
degrade performance. Leaving default at 64 pending further information.
-03/14/2000 KDU Further tuning:
+03/14/2000 KDU Further tuning:
-adjusted boguscnt in hamachi_rx() to depend on interrupt
mitigation parameters chosen.
- -Selected a set of interrupt parameters based on some extensive testing.
+ -Selected a set of interrupt parameters based on some extensive testing.
These may change with more testing.
TO DO:
@@ -405,14 +398,14 @@ TO DO:
PCI_COMMAND_INVALIDATE. Set maximum burst size to cache line size in
that case.
--fix the reset procedure. It doesn't quite work.
+-fix the reset procedure. It doesn't quite work.
*/
/* A few values that may be tweaked. */
/* Size of each temporary Rx buffer, calculated as:
* 1518 bytes (ethernet packet) + 2 bytes (to get 8 byte alignment for
* the card) + 8 bytes of status info + 8 bytes for the Rx Checksum +
- * 2 more because we use skb_reserve.
+ * 2 more because we use skb_reserve.
*/
#define PKT_BUF_SZ 1538
@@ -472,7 +465,7 @@ enum intr_status_bits {
/* The Hamachi Rx and Tx buffer descriptors. */
struct hamachi_desc {
- u32 status_n_length;
+ u32 status_n_length;
#if ADDRLEN == 64
u32 pad;
u64 addr;
@@ -483,7 +476,7 @@ struct hamachi_desc {
/* Bits in hamachi_desc.status_n_length */
enum desc_status_bits {
- DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000,
+ DescOwn=0x80000000, DescEndPacket=0x40000000, DescEndRing=0x20000000,
DescIntr=0x10000000,
};
@@ -553,7 +546,7 @@ MODULE_PARM_DESC(tx_params, "GNIC-II min_tx_pkt+max_tx_gap+max_tx_latency");
MODULE_PARM_DESC(options, "GNIC-II Bits 0-3: media type, bits 4-6: as force32, bit 7: half duplex, bit 9 full duplex");
MODULE_PARM_DESC(full_duplex, "GNIC-II full duplex setting(s) (1)");
MODULE_PARM_DESC(force32, "GNIC-II: Bit 0: 32 bit PCI, bit 1: disable parity, bit 2: 64 bit PCI (all boards)");
-
+
static int read_eeprom(void __iomem *ioaddr, int location);
static int mdio_read(struct net_device *dev, int phy_id, int location);
static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
@@ -570,8 +563,8 @@ static void hamachi_error(struct net_device *dev, int intr_status);
static int hamachi_close(struct net_device *dev);
static struct net_device_stats *hamachi_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
-static struct ethtool_ops ethtool_ops_no_mii;
+static const struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops_no_mii;
static int __devinit hamachi_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -608,7 +601,8 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
pci_set_master(pdev);
i = pci_request_regions(pdev, DRV_NAME);
- if (i) return i;
+ if (i)
+ return i;
irq = pdev->irq;
ioaddr = ioremap(base, 0x400);
@@ -665,7 +659,7 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
option = dev->mem_start;
/* If the bus size is misidentified, do the following. */
- force32 = force32 ? force32 :
+ force32 = force32 ? force32 :
((option >= 0) ? ((option & 0x00000070) >> 4) : 0 );
if (force32)
writeb(force32, ioaddr + VirtualJumpers);
@@ -677,11 +671,11 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
* be valid for a moment. Wait for a little while until it is. If
* it takes more than 10ms, forget it.
*/
- udelay(10);
+ udelay(10);
i = readb(ioaddr + PCIClkMeas);
for (boguscnt = 0; (!(i & 0x080)) && boguscnt < 1000; boguscnt++){
- udelay(10);
- i = readb(ioaddr + PCIClkMeas);
+ udelay(10);
+ i = readb(ioaddr + PCIClkMeas);
}
hmp->base = ioaddr;
@@ -720,9 +714,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
rx_int_var = card_idx < MAX_UNITS ? rx_params[card_idx] : -1;
tx_int_var = card_idx < MAX_UNITS ? tx_params[card_idx] : -1;
- hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var :
+ hmp->rx_int_var = rx_int_var >= 0 ? rx_int_var :
(min_rx_pkt << 16 | max_rx_gap << 8 | max_rx_latency);
- hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var :
+ hmp->tx_int_var = tx_int_var >= 0 ? tx_int_var :
(min_tx_pkt << 16 | max_tx_gap << 8 | max_tx_latency);
@@ -789,10 +783,10 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev,
return 0;
err_out_unmap_rx:
- pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
+ pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
hmp->rx_ring_dma);
err_out_unmap_tx:
- pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
+ pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
hmp->tx_ring_dma);
err_out_cleardev:
free_netdev (dev);
@@ -862,7 +856,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
return;
}
-
+
static int hamachi_open(struct net_device *dev)
{
struct hamachi_private *hmp = netdev_priv(dev);
@@ -871,7 +865,7 @@ static int hamachi_open(struct net_device *dev)
u32 rx_int_var, tx_int_var;
u16 fifo_info;
- i = request_irq(dev->irq, &hamachi_interrupt, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &hamachi_interrupt, IRQF_SHARED, dev->name, dev);
if (i)
return i;
@@ -892,7 +886,7 @@ static int hamachi_open(struct net_device *dev)
writel(cpu_to_le32(hmp->tx_ring_dma), ioaddr + TxPtr);
#endif
- /* TODO: It would make sense to organize this as words since the card
+ /* TODO: It would make sense to organize this as words since the card
* documentation does. -KDU
*/
for (i = 0; i < 6; i++)
@@ -904,36 +898,36 @@ static int hamachi_open(struct net_device *dev)
/* Configure the FIFO */
fifo_info = (readw(ioaddr + GPIO) & 0x00C0) >> 6;
switch (fifo_info){
- case 0 :
+ case 0 :
/* No FIFO */
writew(0x0000, ioaddr + FIFOcfg);
break;
- case 1 :
+ case 1 :
/* Configure the FIFO for 512K external, 16K used for Tx. */
writew(0x0028, ioaddr + FIFOcfg);
break;
- case 2 :
+ case 2 :
/* Configure the FIFO for 1024 external, 32K used for Tx. */
writew(0x004C, ioaddr + FIFOcfg);
break;
- case 3 :
+ case 3 :
/* Configure the FIFO for 2048 external, 32K used for Tx. */
writew(0x006C, ioaddr + FIFOcfg);
break;
- default :
+ default :
printk(KERN_WARNING "%s: Unsupported external memory config!\n",
dev->name);
/* Default to no FIFO */
writew(0x0000, ioaddr + FIFOcfg);
break;
}
-
+
if (dev->if_port == 0)
dev->if_port = hmp->default_port;
/* Setting the Rx mode will start the Rx process. */
- /* If someone didn't choose a duplex, default to full-duplex */
+ /* If someone didn't choose a duplex, default to full-duplex */
if (hmp->duplex_lock != 1)
hmp->mii_if.full_duplex = 1;
@@ -946,7 +940,7 @@ static int hamachi_open(struct net_device *dev)
#endif
writew(0x8000, ioaddr + MACCnfg); /* Soft reset the MAC */
writew(0x215F, ioaddr + MACCnfg);
- writew(0x000C, ioaddr + FrameGap0);
+ writew(0x000C, ioaddr + FrameGap0);
/* WHAT?!?!? Why isn't this documented somewhere? -KDU */
writew(0x1018, ioaddr + FrameGap1);
/* Why do we enable receives/transmits here? -KDU */
@@ -968,16 +962,16 @@ static int hamachi_open(struct net_device *dev)
if (hamachi_debug > 1) {
printk("max_tx_latency: %d, max_tx_gap: %d, min_tx_pkt: %d\n",
- tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8,
+ tx_int_var & 0x00ff, (tx_int_var & 0x00ff00) >> 8,
(tx_int_var & 0x00ff0000) >> 16);
printk("max_rx_latency: %d, max_rx_gap: %d, min_rx_pkt: %d\n",
- rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8,
+ rx_int_var & 0x00ff, (rx_int_var & 0x00ff00) >> 8,
(rx_int_var & 0x00ff0000) >> 16);
printk("rx_int_var: %x, tx_int_var: %x\n", rx_int_var, tx_int_var);
}
- writel(tx_int_var, ioaddr + TxIntrCtrl);
- writel(rx_int_var, ioaddr + RxIntrCtrl);
+ writel(tx_int_var, ioaddr + TxIntrCtrl);
+ writel(rx_int_var, ioaddr + RxIntrCtrl);
set_rx_mode(dev);
@@ -1022,21 +1016,21 @@ static inline int hamachi_tx(struct net_device *dev)
int entry = hmp->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb;
- if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
+ if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
break;
/* Free the original skb. */
skb = hmp->tx_skbuff[entry];
if (skb != 0) {
- pci_unmap_single(hmp->pci_dev,
- hmp->tx_ring[entry].addr, skb->len,
+ pci_unmap_single(hmp->pci_dev,
+ hmp->tx_ring[entry].addr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
hmp->tx_skbuff[entry] = NULL;
}
hmp->tx_ring[entry].status_n_length = 0;
- if (entry >= TX_RING_SIZE-1)
+ if (entry >= TX_RING_SIZE-1)
hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
- cpu_to_le32(DescEndRing);
+ cpu_to_le32(DescEndRing);
hmp->stats.tx_packets++;
}
@@ -1088,7 +1082,7 @@ static void hamachi_tx_timeout(struct net_device *dev)
printk("\n");
}
- /* Reinit the hardware and make sure the Rx and Tx processes
+ /* Reinit the hardware and make sure the Rx and Tx processes
are up and running.
*/
dev->if_port = 0;
@@ -1098,7 +1092,7 @@ static void hamachi_tx_timeout(struct net_device *dev)
* -Turn off MAC receiver
* -Issue Reset
*/
-
+
for (i = 0; i < RX_RING_SIZE; i++)
hmp->rx_ring[i].status_n_length &= cpu_to_le32(~DescOwn);
@@ -1112,11 +1106,11 @@ static void hamachi_tx_timeout(struct net_device *dev)
hmp->tx_ring[i].status_n_length = cpu_to_le32(
DescEndRing |
(hmp->tx_ring[i].status_n_length & 0x0000FFFF));
- else
+ else
hmp->tx_ring[i].status_n_length &= 0x0000ffff;
skb = hmp->tx_skbuff[i];
if (skb){
- pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr,
+ pci_unmap_single(hmp->pci_dev, hmp->tx_ring[i].addr,
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
hmp->tx_skbuff[i] = NULL;
@@ -1125,20 +1119,20 @@ static void hamachi_tx_timeout(struct net_device *dev)
udelay(60); /* Sleep 60 us just for safety sake */
writew(0x0002, ioaddr + RxCmd); /* STOP Rx */
-
- writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */
+
+ writeb(0x01, ioaddr + ChipReset); /* Reinit the hardware */
hmp->tx_full = 0;
hmp->cur_rx = hmp->cur_tx = 0;
hmp->dirty_rx = hmp->dirty_tx = 0;
/* Rx packets are also presumed lost; however, we need to make sure a
* ring of buffers is in tact. -KDU
- */
+ */
for (i = 0; i < RX_RING_SIZE; i++){
struct sk_buff *skb = hmp->rx_skbuff[i];
if (skb){
- pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr,
+ pci_unmap_single(hmp->pci_dev, hmp->rx_ring[i].addr,
hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
hmp->rx_skbuff[i] = NULL;
@@ -1152,9 +1146,9 @@ static void hamachi_tx_timeout(struct net_device *dev)
break;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
- hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
- hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
+ hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2));
}
hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1193,11 +1187,11 @@ static void hamachi_init_ring(struct net_device *dev)
#endif
/* My attempt at a reasonable correction */
/* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
- * card needs room to do 8 byte alignment, +2 so we can reserve
- * the first 2 bytes, and +16 gets room for the status word from the
+ * card needs room to do 8 byte alignment, +2 so we can reserve
+ * the first 2 bytes, and +16 gets room for the status word from the
* card. -KDU
*/
- hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ :
+ hmp->rx_buf_sz = (dev->mtu <= 1492 ? PKT_BUF_SZ :
(((dev->mtu+26+7) & ~7) + 2 + 16));
/* Initialize all Rx descriptors. */
@@ -1213,10 +1207,10 @@ static void hamachi_init_ring(struct net_device *dev)
break;
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
- hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
/* -2 because it doesn't REALLY have that first 2 bytes -KDU */
- hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
+ hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
DescEndPacket | DescIntr | (hmp->rx_buf_sz -2));
}
hmp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1273,7 +1267,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned entry;
u16 status;
- /* Ok, now make sure that the queue has space before trying to
+ /* Ok, now make sure that the queue has space before trying to
add another skbuff. if we return non-zero the scheduler
should interpret this as a queue full and requeue the buffer
for later.
@@ -1288,7 +1282,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
if( !(status & 0x0001) || (status & 0x0002))
writew(0x0001, hmp->base + TxCmd);
return 1;
- }
+ }
/* Caution: the write order is important here, set the field
with the "ownership" bits last. */
@@ -1328,15 +1322,15 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
#endif
- hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ hmp->tx_ring[entry].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, skb->len, PCI_DMA_TODEVICE));
-
+
/* Hmmmm, could probably put a DescIntr on these, but the way
the driver is currently coded makes Tx interrupts unnecessary
since the clearing of the Tx ring is handled by the start_xmit
routine. This organization helps mitigate the interrupts a
bit and probably renders the max_tx_latency param useless.
-
+
Update: Putting a DescIntr bit on all of the descriptors and
mitigating interrupt frequency with the tx_min_pkt parameter. -KDU
*/
@@ -1365,7 +1359,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
* hence, any packet that got put off because we were in the transmit
* routine should IMMEDIATELY get a chance to be re-queued. -KDU
*/
- if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4))
+ if ((hmp->cur_tx - hmp->dirty_tx) < (TX_RING_SIZE - 4))
netif_wake_queue(dev); /* Typical path */
else {
hmp->tx_full = 1;
@@ -1418,27 +1412,27 @@ static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs
/* This code should RARELY need to execute. After all, this is
* a gigabit link, it should consume packets as fast as we put
* them in AND we clear the Tx ring in hamachi_start_xmit().
- */
+ */
if (hmp->tx_full){
for (; hmp->cur_tx - hmp->dirty_tx > 0; hmp->dirty_tx++){
int entry = hmp->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb;
- if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
+ if (hmp->tx_ring[entry].status_n_length & cpu_to_le32(DescOwn))
break;
skb = hmp->tx_skbuff[entry];
/* Free the original skb. */
if (skb){
- pci_unmap_single(hmp->pci_dev,
- hmp->tx_ring[entry].addr,
+ pci_unmap_single(hmp->pci_dev,
+ hmp->tx_ring[entry].addr,
skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
hmp->tx_skbuff[entry] = NULL;
}
hmp->tx_ring[entry].status_n_length = 0;
- if (entry >= TX_RING_SIZE-1)
- hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
+ if (entry >= TX_RING_SIZE-1)
+ hmp->tx_ring[TX_RING_SIZE-1].status_n_length |=
cpu_to_le32(DescEndRing);
hmp->stats.tx_packets++;
}
@@ -1504,9 +1498,9 @@ static int hamachi_rx(struct net_device *dev)
struct hamachi_desc *desc = &(hmp->rx_ring[entry]);
u32 desc_status = le32_to_cpu(desc->status_n_length);
u16 data_size = desc_status; /* Implicit truncate */
- u8 *buf_addr;
+ u8 *buf_addr;
s32 frame_status;
-
+
if (desc_status & DescOwn)
break;
pci_dma_sync_single_for_cpu(hmp->pci_dev,
@@ -1546,7 +1540,7 @@ static int hamachi_rx(struct net_device *dev)
} else {
struct sk_buff *skb;
/* Omit CRC */
- u16 pkt_len = (frame_status & 0x07ff) - 4;
+ u16 pkt_len = (frame_status & 0x07ff) - 4;
#ifdef RX_CHECKSUM
u32 pfck = *(u32 *) &buf_addr[data_size - 8];
#endif
@@ -1582,7 +1576,7 @@ static int hamachi_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE);
/* Call copy + cksum if available. */
#if 1 || USE_IP_COPYSUM
- eth_copy_and_sum(skb,
+ eth_copy_and_sum(skb,
hmp->rx_skbuff[entry]->data, pkt_len, 0);
skb_put(skb, pkt_len);
#else
@@ -1594,7 +1588,7 @@ static int hamachi_rx(struct net_device *dev)
hmp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
} else {
- pci_unmap_single(hmp->pci_dev,
+ pci_unmap_single(hmp->pci_dev,
hmp->rx_ring[entry].addr,
hmp->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb_put(skb = hmp->rx_skbuff[entry], pkt_len);
@@ -1625,18 +1619,18 @@ static int hamachi_rx(struct net_device *dev)
p_r = *p;
p_r1 = *(p-1);
switch (inv) {
- case 0:
+ case 0:
crc = (p_r & 0xffff) + (p_r >> 16);
break;
- case 1:
+ case 1:
crc = (p_r >> 16) + (p_r & 0xffff)
- + (p_r1 >> 16 & 0xff00);
+ + (p_r1 >> 16 & 0xff00);
break;
- case 2:
- crc = p_r + (p_r1 >> 16);
+ case 2:
+ crc = p_r + (p_r1 >> 16);
break;
- case 3:
- crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16);
+ case 3:
+ crc = p_r + (p_r1 & 0xff00) + (p_r1 >> 16);
break;
default: /*NOTREACHED*/ crc = 0;
}
@@ -1654,9 +1648,9 @@ static int hamachi_rx(struct net_device *dev)
* could do the pseudo myself and return
* CHECKSUM_UNNECESSARY
*/
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
}
- }
+ }
}
#endif /* RX_CHECKSUM */
@@ -1681,15 +1675,15 @@ static int hamachi_rx(struct net_device *dev)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
+ desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
}
desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz);
if (entry >= RX_RING_SIZE-1)
- desc->status_n_length |= cpu_to_le32(DescOwn |
+ desc->status_n_length |= cpu_to_le32(DescOwn |
DescEndPacket | DescEndRing | DescIntr);
else
- desc->status_n_length |= cpu_to_le32(DescOwn |
+ desc->status_n_length |= cpu_to_le32(DescOwn |
DescEndPacket | DescIntr);
}
@@ -1800,8 +1794,8 @@ static int hamachi_close(struct net_device *dev)
hmp->rx_ring[i].status_n_length = 0;
hmp->rx_ring[i].addr = 0xBADF00D0; /* An invalid address. */
if (skb) {
- pci_unmap_single(hmp->pci_dev,
- hmp->rx_ring[i].addr, hmp->rx_buf_sz,
+ pci_unmap_single(hmp->pci_dev,
+ hmp->rx_ring[i].addr, hmp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
hmp->rx_skbuff[i] = NULL;
@@ -1810,8 +1804,8 @@ static int hamachi_close(struct net_device *dev)
for (i = 0; i < TX_RING_SIZE; i++) {
skb = hmp->tx_skbuff[i];
if (skb) {
- pci_unmap_single(hmp->pci_dev,
- hmp->tx_ring[i].addr, skb->len,
+ pci_unmap_single(hmp->pci_dev,
+ hmp->tx_ring[i].addr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
hmp->tx_skbuff[i] = NULL;
@@ -1835,7 +1829,7 @@ static struct net_device_stats *hamachi_get_stats(struct net_device *dev)
according to ifconfig. It does get incremented in hamachi_tx(),
so I think I'll comment it out here and see if better things
happen.
- */
+ */
/* hmp->stats.tx_packets = readl(ioaddr + 0x000); */
hmp->stats.rx_bytes = readl(ioaddr + 0x330); /* Total Uni+Brd+Multi */
@@ -1857,8 +1851,6 @@ static void set_rx_mode(struct net_device *dev)
void __iomem *ioaddr = hmp->base;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
writew(0x000F, ioaddr + AddrMode);
} else if ((dev->mc_count > 63) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
@@ -1927,7 +1919,7 @@ static u32 hamachi_get_link(struct net_device *dev)
return mii_link_ok(&np->mii_if);
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.begin = check_if_running,
.get_drvinfo = hamachi_get_drvinfo,
.get_settings = hamachi_get_settings,
@@ -1936,7 +1928,7 @@ static struct ethtool_ops ethtool_ops = {
.get_link = hamachi_get_link,
};
-static struct ethtool_ops ethtool_ops_no_mii = {
+static const struct ethtool_ops ethtool_ops_no_mii = {
.begin = check_if_running,
.get_drvinfo = hamachi_get_drvinfo,
};
@@ -1984,9 +1976,9 @@ static void __devexit hamachi_remove_one (struct pci_dev *pdev)
if (dev) {
struct hamachi_private *hmp = netdev_priv(dev);
- pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
+ pci_free_consistent(pdev, RX_TOTAL_SIZE, hmp->rx_ring,
hmp->rx_ring_dma);
- pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
+ pci_free_consistent(pdev, TX_TOTAL_SIZE, hmp->tx_ring,
hmp->tx_ring_dma);
unregister_netdev(dev);
iounmap(hmp->base);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index d12605f0ac7..86b3bb9bec2 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -12,7 +12,6 @@
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <asm/uaccess.h>
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 232793d2ce6..55906c7b4bb 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -434,7 +434,7 @@ static int ser12_open(struct net_device *dev)
outb(0, FCR(dev->base_addr)); /* disable FIFOs */
outb(0x0d, MCR(dev->base_addr));
outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ if (request_irq(dev->irq, ser12_interrupt, IRQF_DISABLED | IRQF_SHARED,
"baycom_ser_fdx", dev)) {
release_region(dev->base_addr, SER12_EXTENT);
return -EBUSY;
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index be596a3eb3f..de95de8983d 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -488,7 +488,7 @@ static int ser12_open(struct net_device *dev)
outb(0, FCR(dev->base_addr)); /* disable FIFOs */
outb(0x0d, MCR(dev->base_addr));
outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ if (request_irq(dev->irq, ser12_interrupt, IRQF_DISABLED | IRQF_SHARED,
"baycom_ser12", dev)) {
release_region(dev->base_addr, SER12_EXTENT);
return -EBUSY;
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index cb43a9d2877..889f338132f 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -54,7 +54,6 @@
* BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
@@ -123,6 +122,12 @@ struct bpqdev {
static LIST_HEAD(bpq_devices);
+/*
+ * bpqether network devices are paired with ethernet devices below them, so
+ * form a special "super class" of normal ethernet devices; split their locks
+ * off into a separate class since they always nest.
+ */
+static struct lock_class_key bpq_netdev_xmit_lock_key;
/* ------------------------------------------------------------------------ */
@@ -529,6 +534,7 @@ static int bpq_new_device(struct net_device *edev)
err = register_netdevice(ndev);
if (err)
goto error;
+ lockdep_set_class(&ndev->_xmit_lock, &bpq_netdev_xmit_lock_key);
/* List protected by RTNL */
list_add_rcu(&bpq->bpq_list, &bpq_devices);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index 0d5fccc984b..c9a46b89942 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -436,7 +436,7 @@ static int __init dmascc_init(void)
module_init(dmascc_init);
module_exit(dmascc_exit);
-static void dev_setup(struct net_device *dev)
+static void __init dev_setup(struct net_device *dev)
{
dev->type = ARPHRD_AX25;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 3ebbbe56b6e..d8715b200c1 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -16,7 +16,6 @@
* Copyright (C) 2004, 05 Ralf Baechle DL5RB <ralf@linux-mips.org>
* Copyright (C) 2004, 05 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/system.h>
#include <linux/bitops.h>
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index 5927784df3f..df4b68142ac 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -148,7 +148,6 @@
/* ----------------------------------------------------------------------- */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -1737,7 +1736,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!Ivec[hwcfg.irq].used && hwcfg.irq)
{
- if (request_irq(hwcfg.irq, scc_isr, SA_INTERRUPT, "AX.25 SCC", NULL))
+ if (request_irq(hwcfg.irq, scc_isr, IRQF_DISABLED, "AX.25 SCC", NULL))
printk(KERN_WARNING "z8530drv: warning, cannot get IRQ %d\n", hwcfg.irq);
else
Ivec[hwcfg.irq].used = 1;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index b49884048ca..f98f5777dfb 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -42,7 +42,6 @@
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/net.h>
@@ -874,7 +873,7 @@ static int yam_open(struct net_device *dev)
goto out_release_base;
}
outb(0, IER(dev->base_addr));
- if (request_irq(dev->irq, yam_interrupt, SA_INTERRUPT | SA_SHIRQ, dev->name, dev)) {
+ if (request_irq(dev->irq, yam_interrupt, IRQF_DISABLED | IRQF_SHARED, dev->name, dev)) {
printk(KERN_ERR "%s: irq %d busy\n", dev->name, dev->irq);
ret = -EBUSY;
goto out_release_base;
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index e26a3e407d7..6abcfd2a4b2 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -112,7 +112,7 @@ static void hpp_io_block_output(struct net_device *dev, int count,
static void hpp_io_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page);
-
+
/* Probe a list of addresses for an HP LAN+ adaptor.
This routine is almost boilerplate. */
@@ -430,7 +430,7 @@ hpp_mem_block_output(struct net_device *dev, int count,
return;
}
-
+
#ifdef MODULE
#define MAX_HPP_CARDS 4 /* Max number of HPP cards per module */
static struct net_device *dev_hpp[MAX_HPP_CARDS];
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 551a71b3c5f..29470970aa2 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -75,7 +75,7 @@ static void hp_init_card(struct net_device *dev);
/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */
static char irqmap[16] __initdata= { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
-
+
/* Probe for an HP LAN adaptor.
Also initialize the card and fill in STATION_ADDR with the station
address. */
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index dd1dc32dc98..03b3df33d81 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -1,24 +1,24 @@
/*
-** hp100.c
+** hp100.c
** HP CASCADE Architecture Driver for 100VG-AnyLan Network Adapters
**
** $Id: hp100.c,v 1.58 2001/09/24 18:03:01 perex Exp perex $
**
** Based on the HP100 driver written by Jaroslav Kysela <perex@jcu.cz>
-** Extended for new busmaster capable chipsets by
+** Extended for new busmaster capable chipsets by
** Siegfried "Frieder" Loeffler (dg1sek) <floeff@mathematik.uni-stuttgart.de>
**
** Maintained by: Jaroslav Kysela <perex@suse.cz>
-**
+**
** This driver has only been tested with
** -- HP J2585B 10/100 Mbit/s PCI Busmaster
-** -- HP J2585A 10/100 Mbit/s PCI
+** -- HP J2585A 10/100 Mbit/s PCI
** -- HP J2970A 10 Mbit/s PCI Combo 10base-T/BNC
** -- HP J2973A 10 Mbit/s PCI 10base-T
** -- HP J2573 10/100 ISA
** -- Compex ReadyLink ENET100-VG4 10/100 Mbit/s PCI / EISA
** -- Compex FreedomLine 100/VG 10/100 Mbit/s ISA / EISA / PCI
-**
+**
** but it should also work with the other CASCADE based adapters.
**
** TODO:
@@ -65,7 +65,7 @@
** - timing changes in xmit routines, relogin to 100VG hub added when
** driver does reset
** - included fix for Compex FreedomLine PCI adapter
-**
+**
** 1.54 -> 1.55
** - fixed bad initialization in init_module
** - added Compex FreedomLine adapter
@@ -73,10 +73,10 @@
**
** 1.53 -> 1.54
** - added hardware multicast filter support (doesn't work)
-** - little changes in hp100_sense_lan routine
+** - little changes in hp100_sense_lan routine
** - added support for Coax and AUI (J2970)
** - fix for multiple cards and hp100_mode parameter (insmod)
-** - fix for shared IRQ
+** - fix for shared IRQ
**
** 1.52 -> 1.53
** - fixed bug in multicast support
@@ -111,7 +111,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/types.h>
-#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/bitops.h>
@@ -287,7 +286,7 @@ static inline dma_addr_t virt_to_whatever(struct net_device *dev, u32 * ptr)
static inline u_int pdl_map_data(struct hp100_private *lp, void *data)
{
- return pci_map_single(lp->pci_dev, data,
+ return pci_map_single(lp->pci_dev, data,
MAX_ETHER_SIZE, PCI_DMA_FROMDEVICE);
}
@@ -354,7 +353,7 @@ static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
goto err;
for (i = 0; i < ARRAY_SIZE(hp100_isa_tbl); i++) {
- if (!strcmp(hp100_isa_tbl[i], sig))
+ if (!strcmp(hp100_isa_tbl[i], sig))
break;
}
@@ -374,11 +373,11 @@ static int __init hp100_isa_probe(struct net_device *dev, int addr)
{
int err = -ENODEV;
- /* Probe for a specific ISA address */
+ /* Probe for a specific ISA address */
if (addr > 0xff && addr < 0x400)
err = hp100_isa_probe1(dev, addr);
- else if (addr != 0)
+ else if (addr != 0)
err = -ENXIO;
else {
@@ -449,7 +448,7 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
if (!request_region(ioaddr, HP100_REGION_SIZE, "hp100"))
goto out1;
- if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE)
+ if (hp100_inw(HW_ID) != HP100_HW_ID_CASCADE)
goto out2;
chip = hp100_inw(PAGING) & HP100_CHIPID_MASK;
@@ -492,7 +491,7 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
* Use the variable "hp100_mode" upon insmod or as kernel parameter to
* force driver modes:
* hp100_mode=1 -> default, use busmaster mode if configured.
- * hp100_mode=2 -> enable shared memory mode
+ * hp100_mode=2 -> enable shared memory mode
* hp100_mode=3 -> force use of i/o mapped mode.
* hp100_mode=4 -> same as 1, but re-set the enable bit on the card.
*/
@@ -690,9 +689,9 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
hp100_clear_stats(lp, ioaddr);
/* If busmaster mode is wanted, a dma-capable memory area is needed for
- * the rx and tx PDLs
+ * the rx and tx PDLs
* PCI cards can access the whole PC memory. Therefore GFP_DMA is not
- * needed for the allocation of the memory area.
+ * needed for the allocation of the memory area.
*/
/* TODO: We do not need this with old cards, where PDLs are stored
@@ -719,7 +718,7 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
}
/* Initialise the card. */
- /* (I'm not really sure if it's a good idea to do this during probing, but
+ /* (I'm not really sure if it's a good idea to do this during probing, but
* like this it's assured that the lan connection type can be sensed
* correctly)
*/
@@ -779,8 +778,8 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
return 0;
out3:
if (local_mode == 1)
- pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
- lp->page_vaddr_algn,
+ pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
+ lp->page_vaddr_algn,
virt_to_whatever(dev, lp->page_vaddr_algn));
if (mem_ptr_virt)
iounmap(mem_ptr_virt);
@@ -861,7 +860,7 @@ static void hp100_hwinit(struct net_device *dev)
/* Next comes code from mmuinit procedure of SCO BM driver which is
* called from HWconfigure in the SCO driver. */
- /* Initialise MMU, eventually switch on Busmaster Mode, initialise
+ /* Initialise MMU, eventually switch on Busmaster Mode, initialise
* multicast filter...
*/
hp100_mmuinit(dev);
@@ -879,11 +878,11 @@ static void hp100_hwinit(struct net_device *dev)
hp100_login_to_vg_hub(dev, 0); /* relogin */
}
-
-/*
+
+/*
* mmuinit - Reinitialise Cascade MMU and MAC settings.
- * Note: Must already be in reset and leaves card in reset.
+ * Note: Must already be in reset and leaves card in reset.
*/
static void hp100_mmuinit(struct net_device *dev)
{
@@ -909,7 +908,7 @@ static void hp100_mmuinit(struct net_device *dev)
hp100_outw(0xffff, IRQ_STATUS); /* ack IRQ */
/*
- * Enable Hardware
+ * Enable Hardware
* - Clear Debug En, Rx Hdr Pipe, EE En, I/O En, Fake Int and Intr En
* - Set Tri-State Int, Bus Master Rd/Wr, and Mem Map Disable
* - Clear Priority, Advance Pkt and Xmit Cmd
@@ -984,7 +983,7 @@ static void hp100_mmuinit(struct net_device *dev)
* 4 bytes for header). We will leave NUM_RXPDLS * 508 (rounded
* to the next higher 1k boundary) bytes for the rx-pdl's
* Note: For non-etr chips the transmit stop register must be
- * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
+ * programmed on a 1k boundary, i.e. bits 9:0 must be zero.
*/
pdl_stop = lp->memory_size;
xmit_stop = (pdl_stop - 508 * (MAX_RX_PDL) - 16) & ~(0x03ff);
@@ -1079,7 +1078,7 @@ static int hp100_open(struct net_device *dev)
/* New: if bus is PCI or EISA, interrupts might be shared interrupts */
if (request_irq(dev->irq, hp100_interrupt,
lp->bus == HP100_BUS_PCI || lp->bus ==
- HP100_BUS_EISA ? SA_SHIRQ : SA_INTERRUPT,
+ HP100_BUS_EISA ? IRQF_SHARED : IRQF_DISABLED,
"hp100", dev)) {
printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq);
return -EAGAIN;
@@ -1132,10 +1131,10 @@ static int hp100_close(struct net_device *dev)
return 0;
}
-
+
/*
- * Configure the PDL Rx rings and LAN
+ * Configure the PDL Rx rings and LAN
*/
static void hp100_init_pdls(struct net_device *dev)
{
@@ -1183,7 +1182,7 @@ static void hp100_init_pdls(struct net_device *dev)
}
}
}
-
+
/* These functions "format" the entries in the pdl structure */
/* They return how much memory the fragments need. */
@@ -1201,10 +1200,10 @@ static int hp100_init_rxpdl(struct net_device *dev,
ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr + 1);
ringptr->skb = (void *) NULL;
- /*
+ /*
* Write address and length of first PDL Fragment (which is used for
* storing the RX-Header
- * We use the 4 bytes _before_ the PDH in the pdl memory area to
+ * We use the 4 bytes _before_ the PDH in the pdl memory area to
* store this information. (PDH is at offset 0x04)
*/
/* Note that pdlptr+1 and not pdlptr is the pointer to the PDH */
@@ -1231,9 +1230,9 @@ static int hp100_init_txpdl(struct net_device *dev,
}
/*
- * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
+ * hp100_build_rx_pdl allocates an skb_buff of maximum size plus two bytes
* for possible odd word alignment rounding up to next dword and set PDL
- * address for fragment#2
+ * address for fragment#2
* Returns: 0 if unable to allocate skb_buff
* 1 if successful
*/
@@ -1253,13 +1252,13 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr,
#endif
/* Allocate skb buffer of maximum size */
- /* Note: This depends on the alloc_skb functions allocating more
+ /* Note: This depends on the alloc_skb functions allocating more
* space than requested, i.e. aligning to 16bytes */
ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4);
if (NULL != ringptr->skb) {
- /*
+ /*
* Reserve 2 bytes at the head of the buffer to land the IP header
* on a long word boundary (According to the Network Driver section
* in the Linux KHG, this should help to increase performance.)
@@ -1271,10 +1270,10 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr,
/* ringptr->pdl points to the beginning of the PDL, i.e. the PDH */
/* Note: 1st Fragment is used for the 4 byte packet status
- * (receive header). Its PDL entries are set up by init_rxpdl. So
+ * (receive header). Its PDL entries are set up by init_rxpdl. So
* here we only have to set up the PDL fragment entries for the data
- * part. Those 4 bytes will be stored in the DMA memory region
- * directly before the PDL.
+ * part. Those 4 bytes will be stored in the DMA memory region
+ * directly before the PDL.
*/
#ifdef HP100_DEBUG_BM
printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n",
@@ -1286,7 +1285,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr,
/* Conversion to new PCI API : map skbuf data to PCI bus.
* Doc says it's OK for EISA as well - Jean II */
ringptr->pdl[0] = 0x00020000; /* Write PDH */
- ringptr->pdl[3] = pdl_map_data(netdev_priv(dev),
+ ringptr->pdl[3] = pdl_map_data(netdev_priv(dev),
ringptr->skb->data);
ringptr->pdl[4] = MAX_ETHER_SIZE; /* Length of Data */
@@ -1407,7 +1406,7 @@ static void hp100_BM_shutdown(struct net_device *dev)
}
} else { /* Shasta or Rainier Shutdown/Reset */
/* To ensure all bus master inloading activity has ceased,
- * wait for no Rx PDAs or no Rx packets on card.
+ * wait for no Rx PDAs or no Rx packets on card.
*/
hp100_page(PERFORMANCE);
/* 100 ms timeout */
@@ -1423,7 +1422,7 @@ static void hp100_BM_shutdown(struct net_device *dev)
/* To ensure all bus master outloading activity has ceased,
* wait until the Tx PDA count goes to zero or no more Tx space
- * available in the Tx region of the card.
+ * available in the Tx region of the card.
*/
/* 100 ms timeout */
for (time = 0; time < 10000; time++) {
@@ -1462,7 +1461,7 @@ static int hp100_check_lan(struct net_device *dev)
return 0;
}
-/*
+/*
* transmit functions
*/
@@ -1486,7 +1485,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
if (skb->len <= 0)
return 0;
-
+
if (lp->chip == HP100_CHIPID_SHASTA && skb_padto(skb, ETH_ZLEN))
return 0;
@@ -1576,14 +1575,14 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-
+
/* clean_txring checks if packets have been sent by the card by reading
* the TX_PDL register from the performance page and comparing it to the
* number of commited packets. It then frees the skb's of the packets that
* obviously have been sent to the network.
*
- * Needs the PERFORMANCE page selected.
+ * Needs the PERFORMANCE page selected.
*/
static void hp100_clean_txring(struct net_device *dev)
{
@@ -1744,15 +1743,15 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-
+
/*
* Receive Function (Non-Busmaster mode)
- * Called when an "Receive Packet" interrupt occurs, i.e. the receive
+ * Called when an "Receive Packet" interrupt occurs, i.e. the receive
* packet counter is non-zero.
* For non-busmaster, this function does the whole work of transfering
* the packet to the host memory and then up to higher layers via skb
- * and netif_rx.
+ * and netif_rx.
*/
static void hp100_rx(struct net_device *dev)
@@ -1855,7 +1854,7 @@ static void hp100_rx(struct net_device *dev)
#endif
}
-/*
+/*
* Receive Function for Busmaster Mode
*/
static void hp100_rx_bm(struct net_device *dev)
@@ -1876,7 +1875,7 @@ static void hp100_rx_bm(struct net_device *dev)
printk("hp100: %s: rx_bm called although no PDLs were committed to adapter?\n", dev->name);
return;
} else
- /* RX_PKT_CNT states how many PDLs are currently formatted and available to
+ /* RX_PKT_CNT states how many PDLs are currently formatted and available to
* the cards BM engine */
if ((hp100_inw(RX_PKT_CNT) & 0x00ff) >= lp->rxrcommit) {
printk("hp100: %s: More packets received than commited? RX_PKT_CNT=0x%x, commit=0x%x\n",
@@ -1889,7 +1888,7 @@ static void hp100_rx_bm(struct net_device *dev)
while ((lp->rxrcommit > hp100_inb(RX_PDL))) {
/*
* The packet was received into the pdl pointed to by lp->rxrhead (
- * the oldest pdl in the ring
+ * the oldest pdl in the ring
*/
/* First we get the header, which contains information about the */
@@ -2044,7 +2043,7 @@ static void hp100_clear_stats(struct hp100_private *lp, int ioaddr)
hp100_page(PERFORMANCE);
spin_unlock_irqrestore(&lp->lock, flags);
}
-
+
/*
* multicast setup
@@ -2221,9 +2220,9 @@ static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* We're only interested in those interrupts we really enabled. */
/* val &= hp100_inw( IRQ_MASK ); */
- /*
- * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
- * is considered executed whenever the RX_PDL data structure is no longer
+ /*
+ * RX_PDL_FILL_COMPL is set whenever a RX_PDL has been executed. A RX_PDL
+ * is considered executed whenever the RX_PDL data structure is no longer
* needed.
*/
if (val & HP100_RX_PDL_FILL_COMPL) {
@@ -2234,7 +2233,7 @@ static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
- /*
+ /*
* The RX_PACKET interrupt is set, when the receive packet counter is
* non zero. We use this interrupt for receiving in slave mode. In
* busmaster mode, we use it to make sure we did not miss any rx_pdl_fill
@@ -2260,10 +2259,10 @@ static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
hp100_outw(val, IRQ_STATUS);
/*
- * RX_ERROR is set when a packet is dropped due to no memory resources on
- * the card or when a RCV_ERR occurs.
- * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
- * only in the 802.3 MAC and happens when 16 collisions occur during a TX
+ * RX_ERROR is set when a packet is dropped due to no memory resources on
+ * the card or when a RCV_ERR occurs.
+ * TX_ERROR is set when a TX_ABORT condition occurs in the MAC->exists
+ * only in the 802.3 MAC and happens when 16 collisions occur during a TX
*/
if (val & (HP100_TX_ERROR | HP100_RX_ERROR)) {
#ifdef HP100_DEBUG_IRQ
@@ -2276,20 +2275,20 @@ static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
}
- /*
- * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
+ /*
+ * RX_PDA_ZERO is set when the PDA count goes from non-zero to zero.
*/
if ((lp->mode == 1) && (val & (HP100_RX_PDA_ZERO)))
hp100_rxfill(dev);
- /*
- * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
- * is completed
+ /*
+ * HP100_TX_COMPLETE interrupt occurs when packet transmitted on wire
+ * is completed
*/
if ((lp->mode == 1) && (val & (HP100_TX_COMPLETE)))
hp100_clean_txring(dev);
- /*
+ /*
* MISC_ERROR is set when either the LAN link goes down or a detected
* bus error occurs.
*/
@@ -2472,12 +2471,12 @@ static int hp100_sense_lan(struct net_device *dev)
/* Those cards don't have a 100 Mbit connector */
if ( !strcmp(lp->id, "HWP1920") ||
- (lp->pci_dev &&
- lp->pci_dev->vendor == PCI_VENDOR_ID &&
+ (lp->pci_dev &&
+ lp->pci_dev->vendor == PCI_VENDOR_ID &&
(lp->pci_dev->device == PCI_DEVICE_ID_HP_J2970A ||
lp->pci_dev->device == PCI_DEVICE_ID_HP_J2973A)))
return HP100_LAN_ERR;
-
+
if (val_VG & HP100_LINK_CABLE_ST) /* Can hear the HUBs tone. */
return HP100_LAN_100;
return HP100_LAN_ERR;
@@ -2823,8 +2822,8 @@ static void cleanup_dev(struct net_device *d)
release_region(d->base_addr, HP100_REGION_SIZE);
if (p->mode == 1) /* busmaster */
- pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f,
- p->page_vaddr_algn,
+ pci_free_consistent(p->pci_dev, MAX_RINGSIZE + 0x0f,
+ p->page_vaddr_algn,
virt_to_whatever(d, p->page_vaddr_algn));
if (p->mem_ptr_virt)
iounmap(p->mem_ptr_virt);
@@ -2850,7 +2849,7 @@ static int __init hp100_eisa_probe (struct device *gendev)
goto out1;
#ifdef HP100_DEBUG
- printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name,
+ printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name,
dev->base_addr);
#endif
gendev->driver_data = dev;
@@ -2914,12 +2913,12 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
pci_command |= PCI_COMMAND_MASTER;
pci_write_config_word(pdev, PCI_COMMAND, pci_command);
}
-
+
ioaddr = pci_resource_start(pdev, 0);
err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev);
- if (err)
+ if (err)
goto out1;
-
+
#ifdef HP100_DEBUG
printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr);
#endif
@@ -3004,7 +3003,7 @@ static int __init hp100_isa_init(void)
return cards > 0 ? 0 : -ENODEV;
}
-static void __exit hp100_isa_cleanup(void)
+static void __exit hp100_isa_cleanup(void)
{
int i;
@@ -3028,12 +3027,12 @@ static int __init hp100_module_init(void)
goto out;
#ifdef CONFIG_EISA
err = eisa_driver_register(&hp100_eisa_driver);
- if (err && err != -ENODEV)
+ if (err && err != -ENODEV)
goto out2;
#endif
#ifdef CONFIG_PCI
err = pci_module_init(&hp100_pci_driver);
- if (err && err != -ENODEV)
+ if (err && err != -ENODEV)
goto out3;
#endif
out:
diff --git a/drivers/net/hp100.h b/drivers/net/hp100.h
index 236d945987a..e6ca128a556 100644
--- a/drivers/net/hp100.h
+++ b/drivers/net/hp100.h
@@ -8,9 +8,9 @@
*
* This driver is based on the 'hpfepkt' crynwr packet driver.
*
- * This source/code is public free; you can distribute it and/or modify
+ * This source/code is public free; you can distribute it and/or modify
* it under terms of the GNU General Public License (published by the
- * Free Software Foundation) either version two of this License, or any
+ * Free Software Foundation) either version two of this License, or any
* later version.
*/
@@ -18,7 +18,7 @@
* Hardware Constants
****************************************************************************/
-/*
+/*
* Page Identifiers
* (Swap Paging Register, PAGING, bits 3:0, Offset 0x02)
*/
@@ -143,15 +143,15 @@
/* ------------------------------------------------------------------------ */
-/*
+/*
* Hardware ID Register I (Always available, HW_ID, Offset 0x00)
*/
#define HP100_HW_ID_CASCADE 0x4850 /* Identifies Cascade Chip */
-/*
+/*
* Hardware ID Register 2 & Paging Register
* (Always available, PAGING, Offset 0x02)
- * Bits 15:4 are for the Chip ID
+ * Bits 15:4 are for the Chip ID
*/
#define HP100_CHIPID_MASK 0xFFF0
#define HP100_CHIPID_SHASTA 0x5350 /* Not 802.12 compliant */
@@ -162,7 +162,7 @@
/* LRF supported */
/*
- * Option Registers I and II
+ * Option Registers I and II
* (Always available, OPTION_LSW, Offset 0x04-0x05)
*/
#define HP100_DEBUG_EN 0x8000 /* 0:Dis., 1:Enable Debug Dump Ptr. */
@@ -187,7 +187,7 @@
/* NIC reset on 0 to 1 transition */
/*
- * Option Register III
+ * Option Register III
* (Always available, OPTION_MSW, Offset 0x06)
*/
#define HP100_PRIORITY_TX 0x0080 /* 1:Do all Tx pkts as priority */
@@ -253,7 +253,7 @@
#define HP100_BM_PCI_8CLK 0x40 /* ... cycles 8 clocks apart */
-/*
+/*
* Mode Control Register I
* (Page HW_MAP, MODECTRL1, Offset0x10)
*/
@@ -281,7 +281,7 @@
#define HP100_EN_BUS_FAIL 0x80 /* Enables bus-fail portion of misc */
/* interrupt */
-/*
+/*
* PCI Configuration and Control Register I
* (Page HW_MAP, PCICTRL1, Offset 0x12)
*/
@@ -378,7 +378,7 @@
/*
* 100MB LAN Control and Configuration Register
- * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
+ * (Page MAC_CTRL, VG_LAN_CFG_1, Offset 0x0a)
*/
#define HP100_VG_SEL 0x80 /* 0:No, 1:Yes use 100 Mbit MAC */
#define HP100_LINK_UP_ST 0x40 /* 0:No, 1:Yes endnode logged in */
@@ -422,7 +422,7 @@
#define HP100_MAC1MODE7 HP100_MAC1MODE6 | HP100_ACC_ERRORED
/*
- * MAC Configuration Register II
+ * MAC Configuration Register II
* (Page MAC_CTRL, MAC_CFG_2, Offset 0x0d)
*/
#define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */
@@ -447,8 +447,8 @@
#define HP100_MAC2MODE7 KEEP_CRC
/*
- * MAC Configuration Register III
- * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
+ * MAC Configuration Register III
+ * (Page MAC_CTRL, MAC_CFG_3, Offset 0x0e)
*/
#define HP100_PACKET_PACE 0x03 /* Packet Pacing:
* 00: No packet pacing
@@ -461,7 +461,7 @@
#define HP100_AUTO_MODE 0x10 /* 1: AutoSelect between 10/100 */
/*
- * MAC Configuration Register IV
+ * MAC Configuration Register IV
* (Page MAC_CTRL, MAC_CFG_4, Offset 0x0f)
*/
#define HP100_MAC_SEL_ST 0x01 /* (R): Status of external VGSEL
@@ -469,18 +469,18 @@
#define HP100_LINK_FAIL_ST 0x02 /* (R): Status of Link Fail portion
* of the Misc. Interrupt */
-/*
- * 100 MB LAN Training Request/Allowed Registers
+/*
+ * 100 MB LAN Training Request/Allowed Registers
* (Page MAC_CTRL, TRAIN_REQUEST and TRAIN_ALLOW, Offset 0x14-0x16)(ETR parts only)
*/
-#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be
+#define HP100_MACRQ_REPEATER 0x0001 /* 1: MAC tells HUB it wants to be
* a cascaded repeater
* 0: ... wants to be a DTE */
#define HP100_MACRQ_PROMSC 0x0006 /* 2 bits: Promiscious mode
* 00: Rcv only unicast packets
* specifically addr to this
* endnode
- * 10: Rcv all pckts fwded by
+ * 10: Rcv all pckts fwded by
* the local repeater */
#define HP100_MACRQ_FRAMEFMT_EITHER 0x0018 /* 11: either format allowed */
#define HP100_MACRQ_FRAMEFMT_802_3 0x0000 /* 00: 802.3 is requested */
@@ -492,7 +492,7 @@
* 00: Rcv only unicast packets
* specifically addr to this
* endnode
- * 10: Rcv all pckts fwded by
+ * 10: Rcv all pckts fwded by
* the local repeater */
#define HP100_MALLOW_FRAMEFMT 0x00e0 /* 2 bits: Frame Format
* 00: 802.3 format will be used
@@ -521,7 +521,7 @@
#define HP100_LAN_COAX 9 /* lan_type value for Coax */
#define HP100_LAN_ERR (-1) /* lan_type value for link down */
-/*
+/*
* Bus Master Data Structures ----------------------------------------------
*/
@@ -554,7 +554,7 @@ typedef struct hp100_ring {
#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length */
-/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
+/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
bit in the MAC Configuration Register 1 is set. */
#define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */
#define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */
diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c
index 68569346460..9c643f2a8d5 100644
--- a/drivers/net/hplance.c
+++ b/drivers/net/hplance.c
@@ -45,12 +45,12 @@ struct hplance_private {
/* function prototypes... This is easy because all the grot is in the
* generic LANCE support. All we have to support is probing for boards,
- * plus board-specific init, open and close actions.
+ * plus board-specific init, open and close actions.
* Oh, and we need to tell the generic code how to read and write LANCE registers...
*/
static int __devinit hplance_init_one(struct dio_dev *d,
const struct dio_device_id *ent);
-static void __devinit hplance_init(struct net_device *dev,
+static void __devinit hplance_init(struct net_device *dev,
struct dio_dev *d);
static void __devexit hplance_remove_one(struct dio_dev *d);
static void hplance_writerap(void *priv, unsigned short value);
@@ -118,7 +118,7 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
struct hplance_private *lp;
int i;
-
+
printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
/* reset the board */
@@ -136,7 +136,7 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
dev->get_stats = &lance_get_stats;
dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0;
-
+
for (i=0; i<6; i++) {
/* The NVRAM holds our ethernet address, one nibble per byte,
* at bytes NVRAMOFF+1,3,5,7,9...
@@ -145,7 +145,7 @@ static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
| (in_8(va + HPLANCE_NVRAMOFF + i*4 + 3) & 0xF);
printk("%c%2.2x", i == 0 ? ' ' : ':', dev->dev_addr[i]);
}
-
+
lp = netdev_priv(dev);
lp->lance.name = (char*)d->name; /* discards const, shut up gcc */
lp->lance.base = va;
@@ -196,7 +196,7 @@ static int hplance_open(struct net_device *dev)
{
int status;
struct lance_private *lp = netdev_priv(dev);
-
+
status = lance_open(dev); /* call generic lance open code */
if (status)
return status;
diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c
index d9fb8e74e63..91326ea3e12 100644
--- a/drivers/net/hydra.c
+++ b/drivers/net/hydra.c
@@ -117,7 +117,7 @@ static int __devinit hydra_init(struct zorro_dev *z)
dev->irq = IRQ_AMIGA_PORTS;
/* Install the Interrupt handler */
- if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, "Hydra Ethernet",
+ if (request_irq(IRQ_AMIGA_PORTS, ei_interrupt, IRQF_SHARED, "Hydra Ethernet",
dev)) {
free_netdev(dev);
return -EAGAIN;
diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h
index c2dae6092c4..97ed22bb432 100644
--- a/drivers/net/ibm_emac/ibm_emac.h
+++ b/drivers/net/ibm_emac/ibm_emac.h
@@ -20,7 +20,6 @@
#ifndef __IBM_EMAC_H_
#define __IBM_EMAC_H_
-#include <linux/config.h>
#include <linux/types.h>
/* This is a simple check to prevent use of this driver on non-tested SoCs */
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index 7e49522b8b3..d52e3bd0130 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -1037,7 +1036,7 @@ static inline u16 emac_tx_csum(struct ocp_enet_private *dev,
struct sk_buff *skb)
{
#if defined(CONFIG_IBM_EMAC_TAH)
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
++dev->stats.tx_packets_csum;
return EMAC_TX_CTRL_TAH_CSUM;
}
@@ -1884,7 +1883,7 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
info->regdump_len = emac_ethtool_get_regs_len(ndev);
}
-static struct ethtool_ops emac_ethtool_ops = {
+static const struct ethtool_ops emac_ethtool_ops = {
.get_settings = emac_ethtool_get_settings,
.set_settings = emac_ethtool_set_settings,
.get_drvinfo = emac_ethtool_get_drvinfo,
diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h
index f61273b2e94..dabb94afeb9 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.h
+++ b/drivers/net/ibm_emac/ibm_emac_core.h
@@ -20,7 +20,6 @@
#ifndef __IBM_EMAC_CORE_H_
#define __IBM_EMAC_CORE_H_
-#include <linux/config.h>
#include <linux/netdevice.h>
#include <linux/dma-mapping.h>
#include <asm/ocp.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c
index c7e1ecfa08f..c3645908034 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.c
+++ b/drivers/net/ibm_emac/ibm_emac_debug.c
@@ -12,7 +12,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h
index e85fbe0a8da..5761389495d 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.h
+++ b/drivers/net/ibm_emac/ibm_emac_debug.h
@@ -15,7 +15,6 @@
#ifndef __IBM_EMAC_DEBUG_H_
#define __IBM_EMAC_DEBUG_H_
-#include <linux/config.h>
#include <linux/init.h>
#include "ibm_emac_core.h"
#include "ibm_emac_mal.h"
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index da88d43081c..af50e7b2e0d 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -19,7 +19,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h
index 2a2d3b24b03..f73f10a0a56 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.h
+++ b/drivers/net/ibm_emac/ibm_emac_mal.h
@@ -19,7 +19,6 @@
#ifndef __IBM_EMAC_MAL_H_
#define __IBM_EMAC_MAL_H_
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_phy.c b/drivers/net/ibm_emac/ibm_emac_phy.c
index 67935dd33a6..4a97024061e 100644
--- a/drivers/net/ibm_emac/ibm_emac_phy.c
+++ b/drivers/net/ibm_emac/ibm_emac_phy.c
@@ -12,7 +12,6 @@
* (c) 2004-2005, Eugene Surovegin <ebs@ebshome.net>
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.c b/drivers/net/ibm_emac/ibm_emac_rgmii.c
index f0b1ffb2dbb..53d281cb9a1 100644
--- a/drivers/net/ibm_emac/ibm_emac_rgmii.c
+++ b/drivers/net/ibm_emac/ibm_emac_rgmii.c
@@ -16,7 +16,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ethtool.h>
#include <asm/io.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h
index 7f03d536c9a..94abde55e2e 100644
--- a/drivers/net/ibm_emac/ibm_emac_rgmii.h
+++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h
@@ -21,7 +21,6 @@
#ifndef _IBM_EMAC_RGMII_H_
#define _IBM_EMAC_RGMII_H_
-#include <linux/config.h>
/* RGMII bridge */
struct rgmii_regs {
diff --git a/drivers/net/ibm_emac/ibm_emac_tah.c b/drivers/net/ibm_emac/ibm_emac_tah.c
index af08afc22f9..e287b451bb4 100644
--- a/drivers/net/ibm_emac/ibm_emac_tah.c
+++ b/drivers/net/ibm_emac/ibm_emac_tah.c
@@ -13,7 +13,6 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
-#include <linux/config.h>
#include <asm/io.h>
#include "ibm_emac_core.h"
diff --git a/drivers/net/ibm_emac/ibm_emac_tah.h b/drivers/net/ibm_emac/ibm_emac_tah.h
index 9299b5dd7eb..38153945a24 100644
--- a/drivers/net/ibm_emac/ibm_emac_tah.h
+++ b/drivers/net/ibm_emac/ibm_emac_tah.h
@@ -17,7 +17,6 @@
#ifndef _IBM_EMAC_TAH_H
#define _IBM_EMAC_TAH_H
-#include <linux/config.h>
#include <linux/init.h>
#include <asm/ocp.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.c b/drivers/net/ibm_emac/ibm_emac_zmii.c
index e129e0aaa04..37dc8f34286 100644
--- a/drivers/net/ibm_emac/ibm_emac_zmii.c
+++ b/drivers/net/ibm_emac/ibm_emac_zmii.c
@@ -16,7 +16,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ethtool.h>
#include <asm/io.h>
diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.h b/drivers/net/ibm_emac/ibm_emac_zmii.h
index 92c85441075..972e3a44a09 100644
--- a/drivers/net/ibm_emac/ibm_emac_zmii.h
+++ b/drivers/net/ibm_emac/ibm_emac_zmii.h
@@ -19,7 +19,6 @@
#ifndef _IBM_EMAC_ZMII_H_
#define _IBM_EMAC_ZMII_H_
-#include <linux/config.h>
#include <linux/init.h>
#include <asm/ocp.h>
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 51fd51609ea..2a95d72fa59 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -782,7 +782,7 @@ static int ibmlana_open(struct net_device *dev)
/* register resources - only necessary for IRQ */
- result = request_irq(priv->realirq, irq_handler, SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+ result = request_irq(priv->realirq, irq_handler, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
if (result != 0) {
printk(KERN_ERR "%s: failed to register irq %d\n", dev->name, dev->irq);
return result;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 4c2e7279ba3..767203d35bc 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -33,7 +33,6 @@
- possibly remove procfs support
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -607,7 +606,7 @@ static u32 netdev_get_link(struct net_device *dev) {
return 1;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.get_link = netdev_get_link,
@@ -703,7 +702,8 @@ static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev)
desc[3].desc,
desc[4].desc,
desc[5].desc,
- correlator);
+ correlator,
+ &correlator);
} while ((lpar_rc == H_BUSY) && (retry_count--));
if(lpar_rc != H_SUCCESS && lpar_rc != H_DROPPED) {
diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h
index 8385bf83650..f5b25bff154 100644
--- a/drivers/net/ibmveth.h
+++ b/drivers/net/ibmveth.h
@@ -41,16 +41,6 @@
#define IbmVethMcastRemoveFilter 0x2UL
#define IbmVethMcastClearFilterTable 0x3UL
-/* hcall numbers */
-#define H_VIO_SIGNAL 0x104
-#define H_REGISTER_LOGICAL_LAN 0x114
-#define H_FREE_LOGICAL_LAN 0x118
-#define H_ADD_LOGICAL_LAN_BUFFER 0x11C
-#define H_SEND_LOGICAL_LAN 0x120
-#define H_MULTICAST_CTRL 0x130
-#define H_CHANGE_LOGICAL_LAN_MAC 0x14C
-#define H_FREE_LOGICAL_LAN_BUFFER 0x1D4
-
/* hcall macros */
#define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \
plpar_hcall_norets(H_REGISTER_LOGICAL_LAN, ua, buflst, rxq, fltlst, mac)
@@ -61,8 +51,21 @@
#define h_add_logical_lan_buffer(ua, buf) \
plpar_hcall_norets(H_ADD_LOGICAL_LAN_BUFFER, ua, buf)
-#define h_send_logical_lan(ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator) \
- plpar_hcall_8arg_2ret(H_SEND_LOGICAL_LAN, ua, buf1, buf2, buf3, buf4, buf5, buf6, correlator, &correlator)
+static inline long h_send_logical_lan(unsigned long unit_address,
+ unsigned long desc1, unsigned long desc2, unsigned long desc3,
+ unsigned long desc4, unsigned long desc5, unsigned long desc6,
+ unsigned long corellator_in, unsigned long *corellator_out)
+{
+ long rc;
+ unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
+
+ rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, desc1,
+ desc2, desc3, desc4, desc5, desc6, corellator_in);
+
+ *corellator_out = retbuf[0];
+
+ return rc;
+}
#define h_multicast_ctrl(ua, cmd, mac) \
plpar_hcall_norets(H_MULTICAST_CTRL, ua, cmd, mac)
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 2e222ef91e2..6469130c141 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -1,4 +1,4 @@
-/* drivers/net/ifb.c:
+/* drivers/net/ifb.c:
The purpose of this driver is to provide a device that allows
for sharing of resources:
@@ -8,8 +8,8 @@
an impression of sharing.
2) Allows for queueing incoming traffic for shaping instead of
- dropping.
-
+ dropping.
+
The original concept is based on what is known as the IMQ
driver initially written by Martin Devera, later rewritten
by Patrick McHardy and then maintained by Andre Correa.
@@ -21,23 +21,22 @@
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.
-
+
Authors: Jamal Hadi Salim (2005)
-
+
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
-#include <net/pkt_sched.h>
+#include <net/pkt_sched.h>
#define TX_TIMEOUT (2*HZ)
-
+
#define TX_Q_LIMIT 32
struct ifb_private {
struct net_device_stats stats;
@@ -65,7 +64,7 @@ static struct net_device_stats *ifb_get_stats(struct net_device *dev);
static int ifb_open(struct net_device *dev);
static int ifb_close(struct net_device *dev);
-static void ri_tasklet(unsigned long dev)
+static void ri_tasklet(unsigned long dev)
{
struct net_device *_dev = (struct net_device *)dev;
@@ -164,7 +163,7 @@ dropped:
stats->rx_dropped++;
return ret;
} else {
- /*
+ /*
* note we could be going
* ingress -> egress or
* egress -> ingress
@@ -200,7 +199,7 @@ static struct net_device_stats *ifb_get_stats(struct net_device *dev)
struct net_device_stats *stats = &dp->stats;
pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
- dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
+ dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
dp->st_rx2tx_tran dp->st_rxq_notenter, dp->st_rx_frm_egr,
dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch );
@@ -251,7 +250,7 @@ static int __init ifb_init_one(int index)
free_netdev(dev_ifb);
dev_ifb = NULL;
} else {
- ifbs[index] = dev_ifb;
+ ifbs[index] = dev_ifb;
}
return err;
@@ -261,31 +260,32 @@ static void ifb_free_one(int index)
{
unregister_netdev(ifbs[index]);
free_netdev(ifbs[index]);
-}
+}
static int __init ifb_init_module(void)
-{
+{
int i, err = 0;
- ifbs = kmalloc(numifbs * sizeof(void *), GFP_KERNEL);
+ ifbs = kmalloc(numifbs * sizeof(void *), GFP_KERNEL);
if (!ifbs)
- return -ENOMEM;
+ return -ENOMEM;
for (i = 0; i < numifbs && !err; i++)
- err = ifb_init_one(i);
- if (err) {
+ err = ifb_init_one(i);
+ if (err) {
+ i--;
while (--i >= 0)
ifb_free_one(i);
}
return err;
-}
+}
static void __exit ifb_cleanup_module(void)
{
int i;
- for (i = 0; i < numifbs; i++)
- ifb_free_one(i);
- kfree(ifbs);
+ for (i = 0; i < numifbs; i++)
+ ifb_free_one(i);
+ kfree(ifbs);
}
module_init(ifb_init_module);
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index e76e6e7be0b..87650237dc5 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -28,9 +28,8 @@
*/
#define IOC3_NAME "ioc3-eth"
-#define IOC3_VERSION "2.6.3-3"
+#define IOC3_VERSION "2.6.3-4"
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/kernel.h>
@@ -116,7 +115,7 @@ static inline void ioc3_stop(struct ioc3_private *ip);
static void ioc3_init(struct net_device *dev);
static const char ioc3_str[] = "IOC3 Ethernet";
-static struct ethtool_ops ioc3_ethtool_ops;
+static const struct ethtool_ops ioc3_ethtool_ops;
/* We use this to acquire receive skb's that we can DMA directly into. */
@@ -1064,7 +1063,7 @@ static int ioc3_open(struct net_device *dev)
{
struct ioc3_private *ip = netdev_priv(dev);
- if (request_irq(dev->irq, ioc3_interrupt, SA_SHIRQ, ioc3_str, dev)) {
+ if (request_irq(dev->irq, ioc3_interrupt, IRQF_SHARED, ioc3_str, dev)) {
printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
return -EAGAIN;
@@ -1388,7 +1387,7 @@ static int ioc3_start_xmit(struct sk_buff *skb, struct net_device *dev)
* MAC header which should not be summed and the TCP/UDP pseudo headers
* manually.
*/
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
int proto = ntohs(skb->nh.iph->protocol);
unsigned int csoff;
struct iphdr *ih = skb->nh.iph;
@@ -1581,7 +1580,7 @@ static u32 ioc3_get_link(struct net_device *dev)
return rc;
}
-static struct ethtool_ops ioc3_ethtool_ops = {
+static const struct ethtool_ops ioc3_ethtool_ops = {
.get_drvinfo = ioc3_get_drvinfo,
.get_settings = ioc3_get_settings,
.set_settings = ioc3_set_settings,
@@ -1612,8 +1611,6 @@ static void ioc3_set_multicast_list(struct net_device *dev)
netif_stop_queue(dev); /* Lock out others. */
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
ip->emcr |= EMCR_PROMISC;
ioc3_w_emcr(ip->emcr);
(void) ioc3_r_emcr();
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index d2ce4896abf..7c8ccc09b60 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -287,6 +287,7 @@ comment "FIR device drivers"
config USB_IRDA
tristate "IrDA USB dongles"
depends on IRDA && USB
+ select FW_LOADER
---help---
Say Y here if you want to build support for the USB IrDA FIR Dongle
device driver. To compile it as a module, choose M here: the module
@@ -350,7 +351,7 @@ config TOSHIBA_FIR
config AU1000_FIR
tristate "Alchemy Au1000 SIR/FIR"
- depends on MIPS_AU1000 && IRDA
+ depends on SOC_AU1000 && IRDA
config SMC_IRCC_FIR
tristate "SMSC IrCC (EXPERIMENTAL)"
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index bf1fca5a3fa..68d4c418cb9 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -146,7 +146,7 @@ static int __init ali_ircc_init(void)
{
ali_chip_t *chip;
chipio_t info;
- int ret = -ENODEV;
+ int ret;
int cfg, cfg_base;
int reg, revision;
int i = 0;
@@ -160,6 +160,7 @@ static int __init ali_ircc_init(void)
return ret;
}
+ ret = -ENODEV;
/* Probe for all the ALi chipsets we know about */
for (chip= chips; chip->name; chip++, i++)
@@ -248,7 +249,7 @@ static void __exit ali_ircc_cleanup(void)
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
- for (i=0; i < 4; i++) {
+ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
ali_ircc_close(dev_self[i]);
}
@@ -272,6 +273,12 @@ static int ali_ircc_open(int i, chipio_t *info)
int err;
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
+
+ if (i >= ARRAY_SIZE(dev_self)) {
+ IRDA_ERROR("%s(), maximum number of supported chips reached!\n",
+ __FUNCTION__);
+ return -ENOMEM;
+ }
/* Set FIR FIFO and DMA Threshold */
if ((ali_ircc_setup(info)) == -1)
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index e6b1985767c..7b2b4135bb2 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -18,7 +18,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 910c0cab35b..33c07d5275d 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -1372,7 +1372,7 @@ toshoboe_net_open (struct net_device *dev)
return 0;
if (request_irq (self->io.irq, toshoboe_interrupt,
- SA_SHIRQ | SA_INTERRUPT, dev->name, (void *) self))
+ IRQF_SHARED | IRQF_DISABLED, dev->name, (void *) self))
{
return -EAGAIN;
}
@@ -1573,7 +1573,7 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid)
self->io.fir_base = self->base;
self->io.fir_ext = OBOE_IO_EXTENT;
self->io.irq = pci_dev->irq;
- self->io.irqflags = SA_SHIRQ | SA_INTERRUPT;
+ self->io.irqflags = IRQF_SHARED | IRQF_DISABLED;
self->speed = self->io.speed = 9600;
self->async = 0;
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 844fa74ac9e..383cef1f599 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -671,10 +671,8 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* Jean II */
done = 1;
break;
- case -ECONNABORTED: /* -103 */
- case -ECONNRESET: /* -104 */
- case -ETIMEDOUT: /* -110 */
- case -ENOENT: /* -2 (urb unlinked by us) */
+ case -ECONNRESET:
+ case -ENOENT: /* urb unlinked by us */
default: /* ??? - Play safe */
urb->status = 0;
netif_wake_queue(self->netdev);
@@ -712,10 +710,8 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* Jean II */
done = 1;
break;
- case -ECONNABORTED: /* -103 */
- case -ECONNRESET: /* -104 */
- case -ETIMEDOUT: /* -110 */
- case -ENOENT: /* -2 (urb unlinked by us) */
+ case -ECONNRESET:
+ case -ENOENT: /* urb unlinked by us */
default: /* ??? - Play safe */
if(skb != NULL) {
dev_kfree_skb_any(skb);
@@ -845,14 +841,14 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
self->stats.rx_crc_errors++;
/* Also precursor to a hot-unplug on UHCI. */
/* Fallthrough... */
- case -ECONNRESET: /* -104 */
+ case -ECONNRESET:
/* Random error, if I remember correctly */
/* uhci_cleanup_unlink() is going to kill the Rx
* URB just after we return. No problem, at this
* point the URB will be idle ;-) - Jean II */
- case -ESHUTDOWN: /* -108 */
+ case -ESHUTDOWN:
/* That's usually a hot-unplug. Submit will fail... */
- case -ETIMEDOUT: /* -110 */
+ case -ETIME:
/* Usually precursor to a hot-unplug on OHCI. */
default:
self->stats.rx_errors++;
@@ -1105,7 +1101,7 @@ static int stir421x_patch_device(struct irda_usb_cb *self)
return ret;
/* We get a patch from userspace */
- IRDA_MESSAGE("%s(): Received firmware %s (%u bytes)\n",
+ IRDA_MESSAGE("%s(): Received firmware %s (%zu bytes)\n",
__FUNCTION__, stir421x_fw_name, fw->size);
ret = -EINVAL;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index 98fa5319e5c..ba4f3eb988b 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -386,7 +386,7 @@ static int __irport_change_speed(struct irda_task *task)
/* Locking notes : this function may be called from irq context with
* spinlock, via irport_write_wakeup(), or from non-interrupt without
* spinlock (from the task timer). Yuck !
- * This is ugly, and unsafe is the spinlock is not already aquired.
+ * This is ugly, and unsafe is the spinlock is not already acquired.
* This will be fixed when irda-task get rewritten.
* Jean II */
if (!spin_is_locked(&self->lock)) {
@@ -1090,7 +1090,7 @@ static int __init irport_init(void)
{
int i;
- for (i=0; (io[i] < 2000) && (i < 4); i++) {
+ for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) {
if (irport_open(i, io[i], irq[i]) != NULL)
return 0;
}
@@ -1112,7 +1112,7 @@ static void __exit irport_cleanup(void)
IRDA_DEBUG( 4, "%s()\n", __FUNCTION__);
- for (i=0; i < 4; i++) {
+ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
irport_close(dev_self[i]);
}
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 754297fc8f2..415ba8dc94c 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -45,7 +45,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -101,7 +100,7 @@ static int transceiver_type = MCS_TSC_VISHAY;
module_param(transceiver_type, int, 0444);
MODULE_PARM_DESC(transceiver_type, "IR transceiver type, see mcs7780.h.");
-struct usb_driver mcs_driver = {
+static struct usb_driver mcs_driver = {
.name = "mcs7780",
.probe = mcs_probe,
.disconnect = mcs_disconnect,
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index cc7ff8f00e4..7185a4ee3c1 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -110,13 +110,17 @@ static nsc_chip_t chips[] = {
{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8,
nsc_ircc_probe_338, nsc_ircc_init_338 },
/* Contributed by Steffen Pingel - IBM X40 */
- { "PC8738x", { 0x164e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+ { "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
/* Contributed by Jan Frey - IBM A30/A31 */
{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
- { "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
- nsc_ircc_probe_39x, nsc_ircc_init_39x },
+ /* IBM ThinkPads using PC8738x (T60/X60/Z60) */
+ { "IBM-PC8738x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+ nsc_ircc_probe_39x, nsc_ircc_init_39x },
+ /* IBM ThinkPads using PC8394T (T43/R52/?) */
+ { "IBM-PC8394T", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf9, 0xff,
+ nsc_ircc_probe_39x, nsc_ircc_init_39x },
{ NULL }
};
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index e1aa9910503..afb19e8d95c 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -12,7 +12,6 @@
* Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index f530686bd09..8d5a288d797 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -18,7 +18,6 @@
* power_leve:level - set the transmitter power level
* tx_lpm:0|1 - set transmit low power mode
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index a4674044bd6..22358ff68c4 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -2353,7 +2353,27 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
#ifdef CONFIG_PCI
#define PCIID_VENDOR_INTEL 0x8086
#define PCIID_VENDOR_ALI 0x10b9
-static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitdata = {
+static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
+ /*
+ * Subsystems needing entries:
+ * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
+ * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family
+ * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family
+ */
+ {
+ /* Guessed entry */
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+ .subvendor = 0x103c,
+ .subdevice = 0x08bc,
+ .sir_io = 0x02f8,
+ .fir_io = 0x0130,
+ .fir_irq = 0x05,
+ .fir_dma = 0x03,
+ .cfg_base = 0x004e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "HP nx5000 family",
+ },
{
.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
.device = 0x24cc,
@@ -2366,7 +2386,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev
.fir_dma = 0x03,
.cfg_base = 0x004e,
.preconfigure = preconfigure_through_82801,
- .name = "HP nc8000",
+ .name = "HP nc8000 family",
},
{
.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
@@ -2379,7 +2399,21 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __dev
.fir_dma = 0x03,
.cfg_base = 0x004e,
.preconfigure = preconfigure_through_82801,
- .name = "HP nc6000",
+ .name = "HP nc6000 family",
+ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+ .subvendor = 0x0e11,
+ .subdevice = 0x0860,
+ /* I assume these are the same for x1000 as for the others */
+ .sir_io = 0x02e8,
+ .fir_io = 0x02f8,
+ .fir_irq = 0x07,
+ .fir_dma = 0x03,
+ .cfg_base = 0x002e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "Compaq x1000 family",
},
{
/* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index d61b208b52a..12103c93f7e 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -149,8 +149,6 @@ enum StirFifoCtlMask {
FIFOCTL_DIR = 0x10,
FIFOCTL_CLR = 0x08,
FIFOCTL_EMPTY = 0x04,
- FIFOCTL_RXERR = 0x02,
- FIFOCTL_TXERR = 0x01,
};
enum StirDiagMask {
@@ -615,19 +613,6 @@ static int fifo_txwait(struct stir_cb *stir, int space)
pr_debug("fifo status 0x%lx count %lu\n", status, count);
- /* error when receive/transmit fifo gets confused */
- if (status & FIFOCTL_RXERR) {
- stir->stats.rx_fifo_errors++;
- stir->stats.rx_errors++;
- break;
- }
-
- if (status & FIFOCTL_TXERR) {
- stir->stats.tx_fifo_errors++;
- stir->stats.tx_errors++;
- break;
- }
-
/* is fifo receiving already, or empty */
if (!(status & FIFOCTL_DIR)
|| (status & FIFOCTL_EMPTY))
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 8bafb455c10..d916e1257c4 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -279,7 +279,7 @@ static void via_ircc_clean(void)
IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
- for (i=0; i < 4; i++) {
+ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
via_ircc_close(dev_self[i]);
}
@@ -327,6 +327,9 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
+ if (i >= ARRAY_SIZE(dev_self))
+ return -ENOMEM;
+
/* Allocate new instance of the driver */
dev = alloc_irdadev(sizeof(struct via_ircc_cb));
if (dev == NULL)
@@ -1220,8 +1223,13 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase)
IRDA_DEBUG(2, "%s(): len=%x\n", __FUNCTION__, len);
+ if ((len - 4) < 2) {
+ self->stats.rx_dropped++;
+ return FALSE;
+ }
+
skb = dev_alloc_skb(len + 1);
- if ((skb == NULL) || ((len - 4) < 2)) {
+ if (skb == NULL) {
self->stats.rx_dropped++;
return FALSE;
}
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index d70b9e8d6e6..92d646cc9ed 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -21,7 +21,6 @@
*
********************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#define DRIVER_NAME "vlsi_ir"
@@ -1518,7 +1517,7 @@ static int vlsi_open(struct net_device *ndev)
outb(IRINTR_INT_MASK, ndev->base_addr+VLSI_PIO_IRINTR);
- if (request_irq(ndev->irq, vlsi_interrupt, SA_SHIRQ,
+ if (request_irq(ndev->irq, vlsi_interrupt, IRQF_SHARED,
drivername, ndev)) {
IRDA_WARNING("%s: couldn't get IRQ: %d\n",
__FUNCTION__, ndev->irq);
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index a82a4ba8de4..c37f0bc4c7f 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -58,7 +58,7 @@ typedef void irqreturn_t;
/* PDE() introduced in 2.5.4 */
#ifdef CONFIG_PROC_FS
-#define PDE(inode) ((inode)->u.generic_ip)
+#define PDE(inode) ((inode)->i_private)
#endif
/* irda crc16 calculation exported in 2.5.42 */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 0ea65c4c6f8..7de1afdeec3 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -40,7 +40,6 @@
********************************************************************/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/skbuff.h>
@@ -117,7 +116,7 @@ static int __init w83977af_init(void)
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
- for (i=0; (io[i] < 2000) && (i < 4); i++) {
+ for (i=0; (io[i] < 2000) && (i < ARRAY_SIZE(dev_self)); i++) {
if (w83977af_open(i, io[i], irq[i], dma[i]) == 0)
return 0;
}
@@ -136,7 +135,7 @@ static void __exit w83977af_cleanup(void)
IRDA_DEBUG(4, "%s()\n", __FUNCTION__ );
- for (i=0; i < 4; i++) {
+ for (i=0; i < ARRAY_SIZE(dev_self); i++) {
if (dev_self[i])
w83977af_close(dev_self[i]);
}
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index 88ae8a04fab..984c31d1b3f 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -149,7 +149,7 @@ static int __init do_netcard_probe(struct net_device *dev)
return -ENODEV;
}
-
+
static void cleanup_card(struct net_device *dev)
{
#ifdef jumpered_dma
@@ -200,10 +200,10 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
return -EBUSY;
/*
- * For ethernet adaptors the first three octets of the station address
+ * For ethernet adaptors the first three octets of the station address
* contains the manufacturer's unique code. That might be a good probe
* method. Ideally you would add additional checks.
- */
+ */
if (inb(ioaddr + 0) != SA_ADDR0
|| inb(ioaddr + 1) != SA_ADDR1
|| inb(ioaddr + 2) != SA_ADDR2)
@@ -292,7 +292,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
if (i <= 0) {
printk("DMA probe failed.\n");
goto out1;
- }
+ }
if (request_dma(dev->dma, cardname)) {
printk("probed DMA %d allocation failed.\n", dev->dma);
goto out1;
@@ -310,7 +310,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
dev->set_multicast_list = &set_multicast_list;
dev->tx_timeout = &net_tx_timeout;
- dev->watchdog_timeo = MY_TX_TIMEOUT;
+ dev->watchdog_timeo = MY_TX_TIMEOUT;
err = register_netdev(dev);
if (err)
@@ -551,7 +551,7 @@ net_rx(struct net_device *dev)
do {
int status = inw(ioaddr);
int pkt_len = inw(ioaddr);
-
+
if (pkt_len == 0) /* Read all the frames? */
break; /* Done for now */
@@ -566,7 +566,7 @@ net_rx(struct net_device *dev)
struct sk_buff *skb;
lp->stats.rx_bytes+=pkt_len;
-
+
skb = dev_alloc_skb(pkt_len);
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -663,7 +663,7 @@ set_multicast_list(struct net_device *dev)
outw(MULTICAST, ioaddr);
}
- else
+ else
outw(0, ioaddr);
}
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 93394d76587..41b1d08fd57 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -56,7 +56,6 @@
* number of packets outstanding to a remote partition at a time.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -1030,7 +1029,7 @@ static u32 veth_get_link(struct net_device *dev)
return 1;
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = veth_get_drvinfo,
.get_settings = veth_get_settings,
.get_link = veth_get_link,
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index a83ef28dadb..a51604b3651 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -30,7 +30,6 @@
#define _IXGB_H_
#include <linux/stddef.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <asm/byteorder.h>
@@ -111,9 +110,6 @@ struct ixgb_adapter;
#define IXGB_RXBUFFER_8192 8192
#define IXGB_RXBUFFER_16384 16384
-/* How many Tx Descriptors do we need to call netif_wake_queue? */
-#define IXGB_TX_QUEUE_WAKE 16
-
/* How many Rx Buffers do we bundle into one write to the hardware ? */
#define IXGB_RX_BUFFER_WRITE 4 /* Must be power of 2 */
@@ -174,7 +170,7 @@ struct ixgb_adapter {
unsigned long led_status;
/* TX */
- struct ixgb_desc_ring tx_ring;
+ struct ixgb_desc_ring tx_ring ____cacheline_aligned_in_smp;
unsigned long timeo_start;
uint32_t tx_cmd_type;
uint64_t hw_csum_tx_good;
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index cf19b898ba9..64a383e4e89 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -654,11 +654,7 @@ ixgb_phys_id(struct net_device *netdev, uint32_t data)
mod_timer(&adapter->blink_timer, jiffies);
- if (data)
- schedule_timeout_interruptible(data * HZ);
- else
- schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT);
-
+ msleep_interruptible(data * 1000);
del_timer_sync(&adapter->blink_timer);
ixgb_led_off(&adapter->hw);
clear_bit(IXGB_LED_ON, &adapter->led_status);
@@ -703,7 +699,7 @@ ixgb_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
}
}
-static struct ethtool_ops ixgb_ethtool_ops = {
+static const struct ethtool_ops ixgb_ethtool_ops = {
.get_settings = ixgb_get_settings,
.set_settings = ixgb_set_settings,
.get_drvinfo = ixgb_get_drvinfo,
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index f7fa10e47fa..acc6df7a6b3 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -83,7 +83,7 @@ static uint32_t ixgb_mac_reset(struct ixgb_hw *hw)
#endif
/* Delay a few ms just to allow the reset to complete */
- msec_delay(IXGB_DELAY_AFTER_RESET);
+ msleep(IXGB_DELAY_AFTER_RESET);
ctrl_reg = IXGB_READ_REG(hw, CTRL0);
#ifdef DBG
/* Make sure the self-clearing global reset bit did self clear */
@@ -133,7 +133,7 @@ ixgb_adapter_stop(struct ixgb_hw *hw)
*/
IXGB_WRITE_REG(hw, RCTL, IXGB_READ_REG(hw, RCTL) & ~IXGB_RCTL_RXEN);
IXGB_WRITE_REG(hw, TCTL, IXGB_READ_REG(hw, TCTL) & ~IXGB_TCTL_TXEN);
- msec_delay(IXGB_DELAY_BEFORE_RESET);
+ msleep(IXGB_DELAY_BEFORE_RESET);
/* Issue a global reset to the MAC. This will reset the chip's
* transmit, receive, DMA, and link units. It will not effect
@@ -236,6 +236,17 @@ ixgb_identify_phy(struct ixgb_hw *hw)
DEBUGOUT("Identified G6104 optics\n");
phy_type = ixgb_phy_type_g6104;
break;
+ case IXGB_DEVICE_ID_82597EX_CX4:
+ DEBUGOUT("Identified CX4\n");
+ xpak_vendor = ixgb_identify_xpak_vendor(hw);
+ if (xpak_vendor == ixgb_xpak_vendor_intel) {
+ DEBUGOUT("Identified TXN17201 optics\n");
+ phy_type = ixgb_phy_type_txn17201;
+ } else {
+ DEBUGOUT("Identified G6005 optics\n");
+ phy_type = ixgb_phy_type_g6005;
+ }
+ break;
default:
DEBUGOUT("Unknown physical layer module\n");
phy_type = ixgb_phy_type_unknown;
@@ -289,7 +300,7 @@ ixgb_init_hw(struct ixgb_hw *hw)
#endif
/* Delay a few ms just to allow the reset to complete */
- msec_delay(IXGB_DELAY_AFTER_EE_RESET);
+ msleep(IXGB_DELAY_AFTER_EE_RESET);
if (ixgb_get_eeprom_data(hw) == FALSE) {
return(FALSE);
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
index 40a085f94c7..9fd61189b4b 100644
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ixgb/ixgb_ids.h
@@ -45,6 +45,7 @@
#define IXGB_DEVICE_ID_82597EX_CX4 0x109E
#define IXGB_SUBDEVICE_ID_A00C 0xA00C
+#define IXGB_SUBDEVICE_ID_A01C 0xA01C
#endif /* #ifndef _IXGB_IDS_H_ */
/* End of File */
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 8bb32f94699..2e0f4b950a9 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "1.0.109-k2"DRIVERNAPI
+#define DRV_VERSION "1.0.112-k2"DRIVERNAPI
char ixgb_driver_version[] = DRV_VERSION;
static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -118,15 +118,26 @@ static void ixgb_restore_vlan(struct ixgb_adapter *adapter);
static void ixgb_netpoll(struct net_device *dev);
#endif
-/* Exported from other modules */
+static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
+ enum pci_channel_state state);
+static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev);
+static void ixgb_io_resume (struct pci_dev *pdev);
+/* Exported from other modules */
extern void ixgb_check_options(struct ixgb_adapter *adapter);
+static struct pci_error_handlers ixgb_err_handler = {
+ .error_detected = ixgb_io_error_detected,
+ .slot_reset = ixgb_io_slot_reset,
+ .resume = ixgb_io_resume,
+};
+
static struct pci_driver ixgb_driver = {
.name = ixgb_driver_name,
.id_table = ixgb_pci_tbl,
.probe = ixgb_probe,
.remove = __devexit_p(ixgb_remove),
+ .err_handler = &ixgb_err_handler
};
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
@@ -140,12 +151,12 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
/* some defines for controlling descriptor fetches in h/w */
-#define RXDCTL_WTHRESH_DEFAULT 16 /* chip writes back at this many or RXT0 */
-#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below
- * this */
-#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail
- * is pushed this many descriptors
- * from head */
+#define RXDCTL_WTHRESH_DEFAULT 15 /* chip writes back at this many or RXT0 */
+#define RXDCTL_PTHRESH_DEFAULT 0 /* chip considers prefech below
+ * this */
+#define RXDCTL_HTHRESH_DEFAULT 0 /* chip will only prefetch if tail
+ * is pushed this many descriptors
+ * from head */
/**
* ixgb_init_module - Driver Registration Routine
@@ -162,7 +173,7 @@ ixgb_init_module(void)
printk(KERN_INFO "%s\n", ixgb_copyright);
- return pci_module_init(&ixgb_driver);
+ return pci_register_driver(&ixgb_driver);
}
module_init(ixgb_init_module);
@@ -253,7 +264,7 @@ ixgb_up(struct ixgb_adapter *adapter)
#endif
if((err = request_irq(adapter->pdev->irq, &ixgb_intr,
- SA_SHIRQ | SA_SAMPLE_RANDOM,
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM,
netdev->name, netdev))) {
DPRINTK(PROBE, ERR,
"Unable to allocate interrupt Error: %d\n", err);
@@ -1173,7 +1184,8 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
uint16_t ipcse, tucse, mss;
int err;
- if(likely(skb_shinfo(skb)->gso_size)) {
+ if (likely(skb_is_gso(skb))) {
+ struct ixgb_buffer *buffer_info;
if (skb_header_cloned(skb)) {
err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
if (err)
@@ -1196,6 +1208,8 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
i = adapter->tx_ring.next_to_use;
context_desc = IXGB_CONTEXT_DESC(adapter->tx_ring, i);
+ buffer_info = &adapter->tx_ring.buffer_info[i];
+ WARN_ON(buffer_info->dma != 0);
context_desc->ipcss = ipcss;
context_desc->ipcso = ipcso;
@@ -1232,12 +1246,15 @@ ixgb_tx_csum(struct ixgb_adapter *adapter, struct sk_buff *skb)
unsigned int i;
uint8_t css, cso;
- if(likely(skb->ip_summed == CHECKSUM_HW)) {
+ if(likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+ struct ixgb_buffer *buffer_info;
css = skb->h.raw - skb->data;
cso = (skb->h.raw + skb->csum) - skb->data;
i = adapter->tx_ring.next_to_use;
context_desc = IXGB_CONTEXT_DESC(adapter->tx_ring, i);
+ buffer_info = &adapter->tx_ring.buffer_info[i];
+ WARN_ON(buffer_info->dma != 0);
context_desc->tucss = css;
context_desc->tucso = cso;
@@ -1281,8 +1298,9 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
while(len) {
buffer_info = &tx_ring->buffer_info[i];
- size = min(len, IXGB_MAX_JUMBO_FRAME_SIZE);
+ size = min(len, IXGB_MAX_DATA_PER_TXD);
buffer_info->length = size;
+ WARN_ON(buffer_info->dma != 0);
buffer_info->dma =
pci_map_single(adapter->pdev,
skb->data + offset,
@@ -1306,7 +1324,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
while(len) {
buffer_info = &tx_ring->buffer_info[i];
- size = min(len, IXGB_MAX_JUMBO_FRAME_SIZE);
+ size = min(len, IXGB_MAX_DATA_PER_TXD);
buffer_info->length = size;
buffer_info->dma =
pci_map_page(adapter->pdev,
@@ -1543,6 +1561,11 @@ void
ixgb_update_stats(struct ixgb_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ struct pci_dev *pdev = adapter->pdev;
+
+ /* Prevent stats update while adapter is being reset */
+ if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+ return;
if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
(netdev->mc_count > IXGB_MAX_NUM_MULTICAST_ADDRESSES)) {
@@ -1787,7 +1810,7 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter)
if (unlikely(netif_queue_stopped(netdev))) {
spin_lock(&adapter->tx_lock);
if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
- (IXGB_DESC_UNUSED(tx_ring) > IXGB_TX_QUEUE_WAKE))
+ (IXGB_DESC_UNUSED(tx_ring) >= DESC_NEEDED))
netif_wake_queue(netdev);
spin_unlock(&adapter->tx_lock);
}
@@ -1948,10 +1971,9 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter)
#define IXGB_CB_LENGTH 256
if (length < IXGB_CB_LENGTH) {
struct sk_buff *new_skb =
- dev_alloc_skb(length + NET_IP_ALIGN);
+ netdev_alloc_skb(netdev, length + NET_IP_ALIGN);
if (new_skb) {
skb_reserve(new_skb, NET_IP_ALIGN);
- new_skb->dev = netdev;
memcpy(new_skb->data - NET_IP_ALIGN,
skb->data - NET_IP_ALIGN,
length + NET_IP_ALIGN);
@@ -2031,14 +2053,14 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
/* leave three descriptors unused */
while(--cleancount > 2) {
/* recycle! its good for you */
- if (!(skb = buffer_info->skb))
- skb = dev_alloc_skb(adapter->rx_buffer_len
- + NET_IP_ALIGN);
- else {
+ skb = buffer_info->skb;
+ if (skb) {
skb_trim(skb, 0);
goto map_skb;
}
+ skb = netdev_alloc_skb(netdev, adapter->rx_buffer_len
+ + NET_IP_ALIGN);
if (unlikely(!skb)) {
/* Better luck next round */
adapter->alloc_rx_buff_failed++;
@@ -2051,8 +2073,6 @@ ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter)
*/
skb_reserve(skb, NET_IP_ALIGN);
- skb->dev = netdev;
-
buffer_info->skb = skb;
buffer_info->length = adapter->rx_buffer_len;
map_skb:
@@ -2190,7 +2210,7 @@ ixgb_restore_vlan(struct ixgb_adapter *adapter)
static void ixgb_netpoll(struct net_device *dev)
{
- struct ixgb_adapter *adapter = dev->priv;
+ struct ixgb_adapter *adapter = netdev_priv(dev);
disable_irq(adapter->pdev->irq);
ixgb_intr(adapter->pdev->irq, dev, NULL);
@@ -2198,4 +2218,98 @@ static void ixgb_netpoll(struct net_device *dev)
}
#endif
+/**
+ * ixgb_io_error_detected() - called when PCI error is detected
+ * @pdev pointer to pci device with error
+ * @state pci channel state after error
+ *
+ * This callback is called by the PCI subsystem whenever
+ * a PCI bus error is detected.
+ */
+static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
+ enum pci_channel_state state)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgb_adapter *adapter = netdev->priv;
+
+ if(netif_running(netdev))
+ ixgb_down(adapter, TRUE);
+
+ pci_disable_device(pdev);
+
+ /* Request a slot reset. */
+ return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * ixgb_io_slot_reset - called after the pci bus has been reset.
+ * @pdev pointer to pci device with error
+ *
+ * This callback is called after the PCI buss has been reset.
+ * Basically, this tries to restart the card from scratch.
+ * This is a shortened version of the device probe/discovery code,
+ * it resembles the first-half of the ixgb_probe() routine.
+ */
+static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgb_adapter *adapter = netdev->priv;
+
+ if(pci_enable_device(pdev)) {
+ DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ /* Perform card reset only on one instance of the card */
+ if (0 != PCI_FUNC (pdev->devfn))
+ return PCI_ERS_RESULT_RECOVERED;
+
+ pci_set_master(pdev);
+
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ ixgb_reset(adapter);
+
+ /* Make sure the EEPROM is good */
+ if(!ixgb_validate_eeprom_checksum(&adapter->hw)) {
+ DPRINTK(PROBE, ERR, "After reset, the EEPROM checksum is not valid.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ ixgb_get_ee_mac_addr(&adapter->hw, netdev->dev_addr);
+ memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
+
+ if(!is_valid_ether_addr(netdev->perm_addr)) {
+ DPRINTK(PROBE, ERR, "After reset, invalid MAC address.\n");
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * ixgb_io_resume - called when its OK to resume normal operations
+ * @pdev pointer to pci device with error
+ *
+ * The error recovery driver tells us that its OK to resume
+ * normal operation. Implementation resembles the second-half
+ * of the ixgb_probe() routine.
+ */
+static void ixgb_io_resume (struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct ixgb_adapter *adapter = netdev->priv;
+
+ pci_set_master(pdev);
+
+ if(netif_running(netdev)) {
+ if(ixgb_up(adapter)) {
+ printk ("ixgb: can't bring device back up after reset\n");
+ return;
+ }
+ }
+
+ netif_device_attach(netdev);
+ mod_timer(&adapter->watchdog_timer, jiffies);
+}
+
/* ixgb_main.c */
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
index ee982feac64..19cb1d586de 100644
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ixgb/ixgb_osdep.h
@@ -40,18 +40,6 @@
#include <linux/interrupt.h>
#include <linux/sched.h>
-#ifndef msec_delay
-#define msec_delay(x) do { if(in_interrupt()) { \
- /* Don't mdelay in interrupt context! */ \
- BUG(); \
- } else { \
- msleep(x); \
- } } while(0)
-#endif
-
-#define PCI_COMMAND_REGISTER PCI_COMMAND
-#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
-
typedef enum {
#undef FALSE
FALSE = 0,
diff --git a/drivers/net/ixp2000/caleb.c b/drivers/net/ixp2000/caleb.c
index 3595e107df2..7dea5b95012 100644
--- a/drivers/net/ixp2000/caleb.c
+++ b/drivers/net/ixp2000/caleb.c
@@ -9,7 +9,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <asm/io.h>
diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c
index b67f586d739..d3f4235c585 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ixp2000/enp2611.c
@@ -9,7 +9,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/ixp2000/ixp2400-msf.c b/drivers/net/ixp2000/ixp2400-msf.c
index 48a3a891d3a..9ec38eebfb5 100644
--- a/drivers/net/ixp2000/ixp2400-msf.c
+++ b/drivers/net/ixp2000/ixp2400-msf.c
@@ -11,7 +11,6 @@
* License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/hardware.h>
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index fbc2d21020f..6eeb965b4d7 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -9,7 +9,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
@@ -236,7 +235,7 @@ static int ixpdev_open(struct net_device *dev)
if (!nds_open++) {
err = request_irq(IRQ_IXP2000_THDA0, ixpdev_interrupt,
- SA_SHIRQ, "ixp2000_eth", nds);
+ IRQF_SHARED, "ixp2000_eth", nds);
if (err) {
nds_open--;
return err;
diff --git a/drivers/net/ixp2000/pm3386.c b/drivers/net/ixp2000/pm3386.c
index 5224651c9aa..e08d3f9863b 100644
--- a/drivers/net/ixp2000/pm3386.c
+++ b/drivers/net/ixp2000/pm3386.c
@@ -9,7 +9,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c
index 272d331d29c..d34afb52ea7 100644
--- a/drivers/net/jazzsonic.c
+++ b/drivers/net/jazzsonic.c
@@ -7,10 +7,10 @@
* dhd's support for 16-bit cards.
*
* (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- *
+ *
* This driver is based on work from Andreas Busse, but most of
* the code is rewritten.
- *
+ *
* (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
*
* A driver for the onboard Sonic ethernet controller on Mips Jazz
@@ -65,7 +65,7 @@ do { \
/* use 0 for production, 1 for verification, >1 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
-#else
+#else
static unsigned int sonic_debug = 1;
#endif
@@ -80,7 +80,7 @@ static struct {
/*
* We cannot use station (ethernet) address prefixes to detect the
* sonic controller since these are board manufacturer depended.
- * So we check for known Silicon Revision IDs instead.
+ * So we check for known Silicon Revision IDs instead.
*/
static unsigned short known_revisions[] =
{
@@ -119,7 +119,7 @@ static int __init sonic_probe1(struct net_device *dev)
silicon_revision);
goto out;
}
-
+
if (sonic_debug && version_printed++ == 0)
printk(version);
@@ -138,7 +138,7 @@ static int __init sonic_probe1(struct net_device *dev)
}
err = -ENOMEM;
-
+
/* Initialize the device structure. */
lp->dma_bitmode = SONIC_BITMODE32;
@@ -260,7 +260,7 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet driver");
module_param(sonic_debug, int, 0);
MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)");
-#define SONIC_IRQ_FLAG SA_INTERRUPT
+#define SONIC_IRQ_FLAG IRQF_DISABLED
#include "sonic.c"
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index c1c3452c90c..f349e88e0dd 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -19,7 +19,7 @@
- alignment problem with 1.3.* kernel and some minor changes.
Thomas Bogendoerfer (tsbogend@bigbug.franken.de):
- added support for Linux/Alpha, but removed most of it, because
- it worked only for the PCI chip.
+ it worked only for the PCI chip.
- added hook for the 32bit lance driver
- added PCnetPCI II (79C970A) to chip table
Paul Gortmaker (gpg109@rsphy1.anu.edu.au):
@@ -31,7 +31,7 @@
before unregister_netdev() which caused NULL pointer
reference later in the chain (in rtnetlink_fill_ifinfo())
-- Mika Kuoppala <miku@iki.fi>
-
+
Forward ported v1.14 to 2.1.129, merged the PCI and misc changes from
the 2.1 version of the old driver - Alan Cox
@@ -42,7 +42,7 @@
Vesselin Kostadinov <vesok at yahoo dot com > - 22/4/2004
*/
-static const char version[] = "lance.c:v1.15ac 1999/11/13 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] = "lance.c:v1.16 2006/11/09 dplatt@3do.com, becker@cesdis.gsfc.nasa.gov\n";
#include <linux/module.h>
#include <linux/kernel.h>
@@ -307,7 +307,7 @@ static struct net_device_stats *lance_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
static void lance_tx_timeout (struct net_device *dev);
-
+
#ifdef MODULE
#define MAX_CARDS 8 /* Max number of interfaces (cards) per module */
@@ -326,7 +326,7 @@ MODULE_PARM_DESC(dma, "LANCE/PCnet ISA DMA channel (ignored for some devices)");
MODULE_PARM_DESC(irq, "LANCE/PCnet IRQ number (ignored for some devices)");
MODULE_PARM_DESC(lance_debug, "LANCE/PCnet debug level (0-7)");
-int init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
@@ -374,7 +374,7 @@ void cleanup_module(void)
for (this_dev = 0; this_dev < MAX_CARDS; this_dev++) {
struct net_device *dev = dev_lance[this_dev];
if (dev) {
- unregister_netdev(dev);
+ unregister_netdev(dev);
cleanup_card(dev);
free_netdev(dev);
}
@@ -531,7 +531,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dev->base_addr = ioaddr;
/* Make certain the data structures used by the LANCE are aligned and DMAble. */
-
+
lp = kmalloc(sizeof(*lp), GFP_DMA | GFP_KERNEL);
if(lp==NULL)
return -ENODEV;
@@ -656,7 +656,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
outw(0x7f04, ioaddr+LANCE_DATA); /* Clear the memory error bits. */
if (request_dma(dma, chipname))
continue;
-
+
flags=claim_dma_lock();
set_dma_mode(dma, DMA_MODE_CASCADE);
enable_dma(dma);
@@ -737,7 +737,7 @@ out_lp:
return err;
}
-
+
static int
lance_open(struct net_device *dev)
{
@@ -801,7 +801,7 @@ lance_open(struct net_device *dev)
while (i++ < 100)
if (inw(ioaddr+LANCE_DATA) & 0x0100)
break;
- /*
+ /*
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
@@ -826,7 +826,7 @@ lance_open(struct net_device *dev)
restarting the chip, but I'm too lazy to do so right now. dplatt@3do.com
*/
-static void
+static void
lance_purge_ring(struct net_device *dev)
{
struct lance_private *lp = dev->priv;
@@ -972,7 +972,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out;
lp->tx_ring[entry].length = -ETH_ZLEN;
}
- else
+ else
lp->tx_ring[entry].length = -skb->len;
} else
lp->tx_ring[entry].length = -skb->len;
@@ -1027,7 +1027,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
ioaddr = dev->base_addr;
lp = dev->priv;
-
+
spin_lock (&lp->devlock);
outw(0x00, dev->base_addr + LANCE_ADDR);
@@ -1051,7 +1051,7 @@ lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
while (dirty_tx < lp->cur_tx) {
int entry = dirty_tx & TX_RING_MOD_MASK;
int status = lp->tx_ring[entry].base;
-
+
if (status < 0)
break; /* It still hasn't been Txed */
@@ -1142,7 +1142,7 @@ lance_rx(struct net_device *dev)
struct lance_private *lp = dev->priv;
int entry = lp->cur_rx & RX_RING_MOD_MASK;
int i;
-
+
/* If we own the next entry, it's a new packet. Send it up. */
while (lp->rx_ring[entry].base >= 0) {
int status = lp->rx_ring[entry].base >> 24;
@@ -1160,12 +1160,12 @@ lance_rx(struct net_device *dev)
if (status & 0x04) lp->stats.rx_fifo_errors++;
lp->rx_ring[entry].base &= 0x03ffffff;
}
- else
+ else
{
/* Malloc up new buffer, compatible with net3. */
short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4;
struct sk_buff *skb;
-
+
if(pkt_len<60)
{
printk("%s: Runt packet!\n",dev->name);
@@ -1174,14 +1174,14 @@ lance_rx(struct net_device *dev)
else
{
skb = dev_alloc_skb(pkt_len+2);
- if (skb == NULL)
+ if (skb == NULL)
{
printk("%s: Memory squeeze, deferring packet.\n", dev->name);
for (i=0; i < RX_RING_SIZE; i++)
if (lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].base < 0)
break;
- if (i > RX_RING_SIZE -2)
+ if (i > RX_RING_SIZE -2)
{
lp->stats.rx_dropped++;
lp->rx_ring[entry].base |= 0x80000000;
@@ -1281,8 +1281,6 @@ static void set_multicast_list(struct net_device *dev)
outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */
if (dev->flags&IFF_PROMISC) {
- /* Log any net taps. */
- printk("%s: Promiscuous mode enabled.\n", dev->name);
outw(15, ioaddr+LANCE_ADDR);
outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
} else {
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 1ab09447baa..da1eedef0b5 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -5,14 +5,14 @@
but there were too many hoops which HP wants jumped through to
keep this code in there in a sane manner.
- 3 primary sources of the mess --
+ 3 primary sources of the mess --
1) hppa needs *lots* of cacheline flushing to keep this kind of
MMIO running.
2) The 82596 needs to see all of its pointers as their physical
address. Thus virt_to_bus/bus_to_virt are *everywhere*.
- 3) The implementation HP is using seems to be significantly pickier
+ 3) The implementation HP is using seems to be significantly pickier
about when and how the command and RX units are started. some
command ordering was changed.
@@ -21,7 +21,7 @@
full rewrite can be my guest.
Split 02/13/2000 Sam Creasey (sammy@oh.verio.com)
-
+
02/01/2000 Initial modifications for parisc by Helge Deller (deller@gmx.de)
03/02/2000 changes for better/correct(?) cache-flushing (deller)
*/
@@ -172,7 +172,7 @@
#define PORT_ALTSCP 0x02 /* alternate SCB address */
#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
-static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
+static int i596_debug = (DEB_SERIOUS|DEB_PROBE);
MODULE_AUTHOR("Richard Hirst");
MODULE_DESCRIPTION("i82596 driver");
@@ -265,9 +265,9 @@ struct tx_cmd {
dma_addr_t dma_addr;
#ifdef __LP64__
u32 cache_pad[6]; /* Total 64 bytes... */
-#else
+#else
u32 cache_pad[1]; /* Total 32 bytes... */
-#endif
+#endif
};
struct tdr_cmd {
@@ -301,9 +301,9 @@ struct i596_rfd {
unsigned short size;
struct i596_rfd *v_next; /* Address from CPUs viewpoint */
struct i596_rfd *v_prev;
-#ifndef __LP64__
+#ifndef __LP64__
u32 cache_pad[2]; /* Total 32 bytes... */
-#endif
+#endif
};
struct i596_rbd {
@@ -322,7 +322,7 @@ struct i596_rbd {
/* Total 32 bytes... */
#ifdef __LP64__
u32 cache_pad[4];
-#endif
+#endif
};
/* These values as chosen so struct i596_private fits in one page... */
@@ -605,7 +605,7 @@ static inline void remove_rx_bufs(struct net_device *dev)
if (rbd->skb == NULL)
break;
dma_unmap_single(lp->dev,
- (dma_addr_t)WSWAPchar(rbd->b_data),
+ (dma_addr_t)WSWAPchar(rbd->b_data),
PKT_BUF_SZ, DMA_FROM_DEVICE);
dev_kfree_skb(rbd->skb);
}
@@ -643,7 +643,7 @@ static int init_i596_mem(struct net_device *dev)
printk("RESET 82596 port: %lx (with IRQ %d disabled)\n",
(dev->base_addr + PA_I82596_RESET),
dev->irq));
-
+
gsc_writel(0, (dev->base_addr + PA_I82596_RESET)); /* Hard Reset */
udelay(100); /* Wait 100us - seems to help */
@@ -666,7 +666,7 @@ static int init_i596_mem(struct net_device *dev)
CHECK_WBACK(&(lp->scp), sizeof(struct i596_scp));
CHECK_WBACK(&(lp->iscp), sizeof(struct i596_iscp));
- MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));
+ MPU_PORT(dev, PORT_ALTSCP, virt_to_dma(lp,&lp->scp));
CA(dev);
@@ -755,7 +755,7 @@ static inline int i596_rx(struct net_device *dev)
}
DEB(DEB_RXFRAME, printk(" rfd %p, rfd.rbd %08x, rfd.stat %04x\n",
rfd, rfd->rbd, rfd->stat));
-
+
if (rbd != NULL && ((rfd->stat) & STAT_OK)) {
/* a good frame */
int pkt_len = rbd->count & 0x3fff;
@@ -996,7 +996,7 @@ static int i596_test(struct net_device *dev)
tint = (volatile int *)(&(lp->scp));
data = virt_to_dma(lp,tint);
-
+
tint[1] = -1;
CHECK_WBACK(tint,PAGE_SIZE);
@@ -1087,7 +1087,7 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
length = ETH_ZLEN;
}
-
+
netif_stop_queue(dev);
tx_cmd = lp->tx_cmds + lp->next_tx_cmd;
@@ -1194,7 +1194,7 @@ static int __devinit i82596_probe(struct net_device *dev,
printk(KERN_INFO "%s: MAC of HP700 LAN read from EEPROM\n", __FILE__);
}
- dev->mem_start = (unsigned long) dma_alloc_noncoherent(gen_dev,
+ dev->mem_start = (unsigned long) dma_alloc_noncoherent(gen_dev,
sizeof(struct i596_private), &dma_addr, GFP_KERNEL);
if (!dev->mem_start) {
printk(KERN_ERR "%s: Couldn't get shared memory\n", __FILE__);
@@ -1233,7 +1233,7 @@ static int __devinit i82596_probe(struct net_device *dev,
i = register_netdev(dev);
if (i) {
lp = dev->priv;
- dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
+ dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
(void *)dev->mem_start, lp->dma_addr);
return i;
};
@@ -1400,7 +1400,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
CHECK_WBACK(&lp->scb, sizeof(struct i596_scb));
/* DANGER: I suspect that some kind of interrupt
- acknowledgement aside from acking the 82596 might be needed
+ acknowledgement aside from acking the 82596 might be needed
here... but it's running acceptably without */
CA(dev);
@@ -1498,7 +1498,7 @@ static void set_multicast_list(struct net_device *dev)
printk("%s: Only %d multicast addresses supported",
dev->name, cnt);
}
-
+
if (dev->mc_count > 0) {
struct dev_mc_list *dmi;
unsigned char *cp;
@@ -1539,7 +1539,7 @@ lan_init_chip(struct parisc_device *dev)
if (num_drivers == 0)
printk(KERN_INFO LASI_82596_DRIVER_VERSION "\n");
-
+
if (!dev->irq) {
printk(KERN_ERR "%s: IRQ not found for i82596 at 0x%lx\n",
__FILE__, dev->hpa.start);
@@ -1602,15 +1602,15 @@ static void __exit lasi_82596_exit(void)
for (i=0; i<MAX_DRIVERS; i++) {
struct i596_private *lp;
struct net_device *netdevice;
-
+
netdevice = netdevs[i];
- if (!netdevice)
+ if (!netdevice)
continue;
-
+
unregister_netdev(netdevice);
lp = netdevice->priv;
- dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
+ dma_free_noncoherent(lp->dev, sizeof(struct i596_private),
(void *)netdevice->mem_start, lp->dma_addr);
free_netdev(netdevice);
}
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 646e89fc356..5795ee11620 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -188,7 +188,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
}
revision = (eisa_id >> 24) & 0x01; /* 0 = rev A, 1 rev B */
-
+
#if 0
/* Check the Mylex vendor ID as well. Not really required. */
if (inb(ioaddr + LNE390_SA_PROM + 0) != LNE390_ADDR0
@@ -341,7 +341,7 @@ lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
}
-/*
+/*
* Block input and output are easy on shared memory ethercards, the only
* complication is when the ring buffer wraps. The count will already
* be rounded up to a doubleword value via lne390_get_8390_hdr() above.
@@ -406,7 +406,7 @@ MODULE_PARM_DESC(mem, "memory base address(es)");
MODULE_DESCRIPTION("Mylex LNE390A/B EISA Ethernet driver");
MODULE_LICENSE("GPL");
-int init_module(void)
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 43fef7de8cb..4178b4b1d2d 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
#ifdef LOOPBACK_TSO
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
BUG_ON(skb->protocol != htons(ETH_P_IP));
BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
@@ -161,15 +161,13 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
return(0);
}
+static struct net_device_stats loopback_stats;
+
static struct net_device_stats *get_stats(struct net_device *dev)
{
- struct net_device_stats *stats = dev->priv;
+ struct net_device_stats *stats = &loopback_stats;
int i;
- if (!stats) {
- return NULL;
- }
-
memset(stats, 0, sizeof(struct net_device_stats));
for_each_possible_cpu(i) {
@@ -181,23 +179,32 @@ static struct net_device_stats *get_stats(struct net_device *dev)
stats->rx_packets += lb_stats->rx_packets;
stats->tx_packets += lb_stats->tx_packets;
}
-
+
return stats;
}
-static u32 loopback_get_link(struct net_device *dev)
+static u32 always_on(struct net_device *dev)
{
return 1;
}
-static struct ethtool_ops loopback_ethtool_ops = {
- .get_link = loopback_get_link,
+static const struct ethtool_ops loopback_ethtool_ops = {
+ .get_link = always_on,
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
+ .get_tx_csum = always_on,
+ .get_sg = always_on,
+ .get_rx_csum = always_on,
};
+/*
+ * The loopback device is special. There is only one instance and
+ * it is statically allocated. Don't do this for other devices.
+ */
struct net_device loopback_dev = {
.name = "lo",
+ .get_stats = &get_stats,
+ .priv = &loopback_stats,
.mtu = (16 * 1024) + 20 + 20 + 12,
.hard_start_xmit = loopback_xmit,
.hard_header = eth_header,
@@ -221,16 +228,6 @@ struct net_device loopback_dev = {
/* Setup and register the loopback device. */
int __init loopback_init(void)
{
- struct net_device_stats *stats;
-
- /* Can survive without statistics */
- stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
- if (stats) {
- memset(stats, 0, sizeof(struct net_device_stats));
- loopback_dev.priv = stats;
- loopback_dev.get_stats = &get_stats;
- }
-
return register_netdev(&loopback_dev);
};
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index bf3f343ae71..0258aaca9ed 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -277,7 +277,7 @@ struct i596_rbd {
phys_addr pa_next; /* va_to_pa(struct i596_tbd *next) */
phys_addr pa_data; /* va_to_pa(char *data) */
phys_addr pa_prev; /* va_to_pa(struct i596_tbd *prev) */
-
+
/* Driver private part */
struct sk_buff *skb;
};
@@ -442,16 +442,16 @@ init_rx_bufs(struct net_device *dev, int num) {
if (rbd) {
rbd->pad = 0;
rbd->count = 0;
- rbd->skb = dev_alloc_skb(RX_SKB_SIZE);
+ rbd->skb = dev_alloc_skb(RX_SKBSIZE);
if (!rbd->skb) {
printk("dev_alloc_skb failed");
}
rbd->next = rfd->rbd;
if (i) {
rfd->rbd->prev = rbd;
- rbd->size = RX_SKB_SIZE;
+ rbd->size = RX_SKBSIZE;
} else {
- rbd->size = (RX_SKB_SIZE | RBD_EL);
+ rbd->size = (RX_SKBSIZE | RBD_EL);
lp->rbd_tail = rbd;
}
@@ -647,7 +647,7 @@ init_i596(struct net_device *dev) {
CA();
barrier();
-
+
if (lp->scb.command && i596_timeout(dev, "Receive Unit start", 100))
return 1;
@@ -676,7 +676,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp,
return 1;
}
- skb->dev = dev;
+ skb->dev = dev;
memcpy(skb_put(skb,pkt_len), rfd->data, pkt_len);
skb->protocol = eth_type_trans(skb,dev);
@@ -797,7 +797,7 @@ static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioad
lp->scb.command = CUC_ABORT | RX_ABORT;
CA();
barrier();
-
+
/* wait for shutdown */
if (lp->scb.command && i596_timeout(dev, "i596_reset(2)", 400))
;
@@ -820,7 +820,7 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
cmd->pa_next = I596_NULL;
spin_lock_irqsave(&lp->cmd_lock, flags);
-
+
if (lp->cmd_head) {
lp->cmd_tail->pa_next = va_to_pa(cmd);
} else {
@@ -847,11 +847,11 @@ static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) {
}
}
-static int i596_open(struct net_device *dev)
+static int i596_open(struct net_device *dev)
{
int i;
- i = request_irq(dev->irq, &i596_interrupt, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &i596_interrupt, IRQF_SHARED, dev->name, dev);
if (i) {
printk(KERN_ERR "%s: IRQ %d not free\n", dev->name, dev->irq);
return i;
@@ -875,13 +875,13 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) {
short length;
length = skb->len;
-
+
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN))
return 0;
length = ETH_ZLEN;
}
-
+
dev->trans_start = jiffies;
tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC);
@@ -941,7 +941,7 @@ i596_tx_timeout (struct net_device *dev) {
netif_wake_queue(dev);
}
-static void print_eth(char *add)
+static void print_eth(char *add)
{
int i;
@@ -978,7 +978,7 @@ static int __init lp486e_probe(struct net_device *dev) {
lp = (struct i596_private *) dev->priv;
spin_lock_init(&lp->cmd_lock);
-
+
/*
* Do we really have this thing?
*/
@@ -1132,7 +1132,7 @@ i596_handle_CU_completion(struct net_device *dev,
default:
cmd->pa_next = I596_NULL;
lp->last_cmd = jiffies;
-
+
}
barrier();
}
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c
index 06cb460361a..ade6ff852e1 100644
--- a/drivers/net/mac8390.c
+++ b/drivers/net/mac8390.c
@@ -7,12 +7,12 @@
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference. */
-/* 2000-02-28: support added for Dayna and Kinetics cards by
+/* 2000-02-28: support added for Dayna and Kinetics cards by
A.G.deWijn@phys.uu.nl */
/* 2000-04-04: support added for Dayna2 by bart@etpmod.phys.tue.nl */
/* 2001-04-18: support for DaynaPort E/LC-M by rayk@knightsmanor.org */
/* 2001-05-15: support for Cabletron ported from old daynaport driver
- * and fixed access to Sonic Sys card which masquerades as a Farallon
+ * and fixed access to Sonic Sys card which masquerades as a Farallon
* by rayk@knightsmanor.org */
#include <linux/module.h>
@@ -55,7 +55,7 @@
#define KINETICS_8390_BASE 0x80000
#define KINETICS_8390_MEM 0x00000
-#define CABLETRON_8390_BASE 0x90000
+#define CABLETRON_8390_BASE 0x90000
#define CABLETRON_8390_MEM 0x00000
enum mac8390_type {
@@ -118,7 +118,7 @@ static int useresources[] = {
static char version[] __initdata =
"mac8390.c: v0.4 2001-05-15 David Huggins-Daines <dhd@debian.org> and others\n";
-
+
extern enum mac8390_type mac8390_ident(struct nubus_dev * dev);
extern int mac8390_memsize(unsigned long membase);
extern int mac8390_memtest(struct net_device * dev);
@@ -168,7 +168,7 @@ enum mac8390_type __init mac8390_ident(struct nubus_dev * dev)
{
if (dev->dr_sw == NUBUS_DRSW_ASANTE)
return MAC8390_ASANTE;
- if (dev->dr_sw == NUBUS_DRSW_FARALLON)
+ if (dev->dr_sw == NUBUS_DRSW_FARALLON)
return MAC8390_FARALLON;
if (dev->dr_sw == NUBUS_DRSW_KINETICS)
return MAC8390_KINETICS;
@@ -187,7 +187,7 @@ int __init mac8390_memsize(unsigned long membase)
{
unsigned long flags;
int i, j;
-
+
local_irq_save(flags);
/* Check up to 32K in 4K increments */
for (i = 0; i < 8; i++) {
@@ -197,7 +197,7 @@ int __init mac8390_memsize(unsigned long membase)
RAM end located */
if (hwreg_present(m) == 0)
break;
-
+
/* write a distinctive byte */
*m = 0xA5A0 | i;
/* check that we read back what we wrote */
@@ -224,7 +224,7 @@ struct net_device * __init mac8390_probe(int unit)
int version_disp = 0;
struct nubus_dev * ndev = NULL;
int err = -ENODEV;
-
+
struct nubus_dir dir;
struct nubus_dirent ent;
int offset;
@@ -273,7 +273,7 @@ struct net_device * __init mac8390_probe(int unit)
dev->name, ndev->board->slot);
continue;
}
-
+
/* Get the MAC address */
if ((nubus_find_rsrc(&dir, NUBUS_RESID_MAC_ADDRESS, &ent)) == -1) {
printk(KERN_INFO "%s: Couldn't get MAC address!\n",
@@ -282,7 +282,7 @@ struct net_device * __init mac8390_probe(int unit)
} else {
nubus_get_rsrc_mem(dev->dev_addr, &ent, 6);
/* Some Sonic Sys cards masquerade as Farallon */
- if (cardtype == MAC8390_FARALLON &&
+ if (cardtype == MAC8390_FARALLON &&
dev->dev_addr[0] == 0x0 &&
dev->dev_addr[1] == 0x40 &&
dev->dev_addr[2] == 0x10) {
@@ -290,7 +290,7 @@ struct net_device * __init mac8390_probe(int unit)
cardtype = MAC8390_SONICSYS;
}
}
-
+
if (useresources[cardtype] == 1) {
nubus_rewinddir(&dir);
if (nubus_find_rsrc(&dir, NUBUS_RESID_MINOR_BASEOS, &ent) == -1) {
@@ -318,10 +318,10 @@ struct net_device * __init mac8390_probe(int unit)
switch (cardtype) {
case MAC8390_KINETICS:
case MAC8390_DAYNA: /* it's the same */
- dev->base_addr =
+ dev->base_addr =
(int)(ndev->board->slot_addr +
DAYNA_8390_BASE);
- dev->mem_start =
+ dev->mem_start =
(int)(ndev->board->slot_addr +
DAYNA_8390_MEM);
dev->mem_end =
@@ -343,11 +343,11 @@ struct net_device * __init mac8390_probe(int unit)
*/
i = (void *)dev->base_addr;
*i = 0x21;
- dev->mem_end =
+ dev->mem_end =
dev->mem_start +
mac8390_memsize(dev->mem_start);
break;
-
+
default:
printk(KERN_ERR "Card type %s is"
" unsupported, sorry\n",
@@ -433,7 +433,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
};
int access_bitmode;
-
+
/* Now fill in our stuff */
dev->open = &mac8390_open;
dev->stop = &mac8390_close;
@@ -459,7 +459,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
ei_status.rmem_start = dev->mem_start + TX_PAGES*256;
ei_status.rmem_end = dev->mem_end;
}
-
+
/* Fill in model-specific information and functions */
switch(type) {
case MAC8390_SONICSYS:
@@ -509,7 +509,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]);
return -ENODEV;
}
-
+
NS8390_init(dev, 0);
/* Good, done, now spit out some messages */
@@ -525,7 +525,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd
}
}
printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n",
- dev->irq, dev->mem_start, dev->mem_end-1,
+ dev->irq, dev->mem_start, dev->mem_end-1,
access_bitmode?32:16);
return 0;
}
@@ -536,7 +536,7 @@ static int mac8390_open(struct net_device *dev)
if (request_irq(dev->irq, ei_interrupt, 0, "8390 Ethernet", dev)) {
printk ("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
return -EAGAIN;
- }
+ }
return 0;
}
@@ -639,7 +639,7 @@ static void sane_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page)
{
long shmem = (start_page - WD_START_PG)<<8;
-
+
memcpy_toio((char *)dev->mem_start + shmem, buf, count);
}
@@ -681,12 +681,12 @@ static void dayna_block_output(struct net_device *dev, int count, const unsigned
int start_page)
{
long shmem = (start_page - WD_START_PG)<<8;
-
+
dayna_memcpy_tocard(dev, shmem, buf, count);
}
/* Cabletron block I/O */
-static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+static void slow_sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page)
{
unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
@@ -750,4 +750,4 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count)
*to++=*from++;
}
-
+
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index cd3c9a5a98b..8472b71641d 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -12,24 +12,24 @@
Changelog:
Mike Cruse : mcruse@cti-ltd.com
- : Changes for Linux 2.0 compatibility.
+ : Changes for Linux 2.0 compatibility.
: Added dev_id parameter in net_interrupt(),
: request_irq() and free_irq(). Just NULL for now.
Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros
: in net_open() and net_close() so kerneld would know
- : that the module is in use and wouldn't eject the
+ : that the module is in use and wouldn't eject the
: driver prematurely.
Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c
: as an example. Disabled autoprobing in init_module(),
: not a good thing to do to other devices while Linux
: is running from all accounts.
-
+
Alan Cox : Removed 1.2 support, added 2.1 extra counters.
David Huggins-Daines <dhd@debian.org>
-
+
Split this off into mac89x0.c, and gutted it of all parts which are
not relevant to the existing CS8900 cards on the Macintosh
(i.e. basically the Daynaport CS and LC cards). To be precise:
@@ -210,7 +210,7 @@ struct net_device * __init mac89x0_probe(int unit)
{
unsigned long flags;
int card_present;
-
+
local_irq_save(flags);
card_present = hwreg_present((void*) ioaddr+4)
&& hwreg_present((void*) ioaddr + DATA_PORT);
@@ -230,7 +230,7 @@ struct net_device * __init mac89x0_probe(int unit)
/* Fill in the 'dev' fields. */
dev->base_addr = ioaddr;
- dev->mem_start = (unsigned long)
+ dev->mem_start = (unsigned long)
nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE);
dev->mem_end = dev->mem_start + 0x1000;
@@ -428,7 +428,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-
+
/* The typical workload of the driver:
Handle the network interface interrupts. */
static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
@@ -596,7 +596,7 @@ static void set_multicast_list(struct net_device *dev)
/* The multicast-accept list is initialized to accept-all, and we
rely on higher-level filtering for now. */
lp->rx_mode = RX_MULTCAST_ACCEPT;
- }
+ }
else
lp->rx_mode = 0;
@@ -653,7 +653,7 @@ cleanup_module(void)
free_netdev(dev_cs89x0);
}
#endif /* MODULE */
-
+
/*
* Local variables:
* compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c"
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 77792b28602..27c24eaa241 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -5,7 +5,6 @@
* Copyright (C) 1996 Paul Mackerras.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
@@ -114,7 +113,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
struct device_node *mace = macio_get_of_node(mdev);
struct net_device *dev;
struct mace_data *mp;
- unsigned char *addr;
+ const unsigned char *addr;
int j, rev, rc = -EBUSY;
if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) {
@@ -178,7 +177,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
}
mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
in_8(&mp->mace->chipid_lo);
-
+
mp = (struct mace_data *) dev->priv;
mp->maccc = ENXMT | ENRCV;
@@ -220,7 +219,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
mp->port_aaui = 1;
#else
mp->port_aaui = 0;
-#endif
+#endif
}
}
@@ -243,12 +242,12 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
}
rc = request_irq(mp->tx_dma_intr, mace_txdma_intr, 0, "MACE-txdma", dev);
if (rc) {
- printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[1].line);
+ printk(KERN_ERR "MACE: can't get irq %d\n", mp->tx_dma_intr);
goto err_free_irq;
}
rc = request_irq(mp->rx_dma_intr, mace_rxdma_intr, 0, "MACE-rxdma", dev);
if (rc) {
- printk(KERN_ERR "MACE: can't get irq %d\n", mace->intrs[2].line);
+ printk(KERN_ERR "MACE: can't get irq %d\n", mp->rx_dma_intr);
goto err_free_tx_irq;
}
@@ -265,7 +264,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
printk(", chip revision %d.%d\n", mp->chipid >> 8, mp->chipid & 0xff);
return 0;
-
+
err_free_rx_irq:
free_irq(macio_irq(mdev, 2), dev);
err_free_tx_irq:
@@ -1009,7 +1008,7 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static struct of_device_id mace_match[] =
+static struct of_device_id mace_match[] =
{
{
.name = "mace",
@@ -1018,7 +1017,7 @@ static struct of_device_id mace_match[] =
};
MODULE_DEVICE_TABLE (of, mace_match);
-static struct macio_driver mace_driver =
+static struct macio_driver mace_driver =
{
.name = "mace",
.match_table = mace_match,
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 79a6fc13975..696d5513e55 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -63,7 +63,7 @@ struct mace_frame {
u16 rcvcc;
u32 pad1;
u32 pad2;
- u8 data[1];
+ u8 data[1];
/* And frame continues.. */
};
@@ -118,17 +118,17 @@ static void mace_rxdma_reset(struct net_device *dev)
struct mace_data *mp = (struct mace_data *) dev->priv;
volatile struct mace *mace = mp->mace;
u8 maccc = mace->maccc;
-
+
mace->maccc = maccc & ~ENRCV;
-
+
psc_write_word(PSC_ENETRD_CTL, 0x8800);
mace_load_rxdma_base(dev, 0x00);
psc_write_word(PSC_ENETRD_CTL, 0x0400);
-
+
psc_write_word(PSC_ENETRD_CTL, 0x8800);
mace_load_rxdma_base(dev, 0x10);
psc_write_word(PSC_ENETRD_CTL, 0x0400);
-
+
mace->maccc = maccc;
mp->rx_slot = 0;
@@ -139,7 +139,7 @@ static void mace_rxdma_reset(struct net_device *dev)
/*
* Reset the transmit DMA subsystem
*/
-
+
static void mace_txdma_reset(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -161,7 +161,7 @@ static void mace_txdma_reset(struct net_device *dev)
/*
* Disable DMA
*/
-
+
static void mace_dma_off(struct net_device *dev)
{
psc_write_word(PSC_ENETRD_CTL, 0x8800);
@@ -179,7 +179,7 @@ static void mace_dma_off(struct net_device *dev)
* Not really much of a probe. The hardware table tells us if this
* model of Macintrash has a MACE (AV macintoshes)
*/
-
+
struct net_device *mace_probe(int unit)
{
int j;
@@ -189,7 +189,7 @@ struct net_device *mace_probe(int unit)
unsigned char checksum = 0;
static int found = 0;
int err;
-
+
if (found || macintosh_config->ether_type != MAC_ETHER_MACE)
return ERR_PTR(-ENODEV);
@@ -205,7 +205,7 @@ struct net_device *mace_probe(int unit)
mp = (struct mace_data *) dev->priv;
dev->base_addr = (u32)MACE_BASE;
mp->mace = (volatile struct mace *) MACE_BASE;
-
+
dev->irq = IRQ_MAC_MACE;
mp->dma_intr = IRQ_MAC_MACE_DMA;
@@ -217,7 +217,7 @@ struct net_device *mace_probe(int unit)
*/
addr = (void *)MACE_PROM;
-
+
for (j = 0; j < 6; ++j) {
u8 v=bitrev(addr[j<<4]);
checksum ^= v;
@@ -226,7 +226,7 @@ struct net_device *mace_probe(int unit)
for (; j < 8; ++j) {
checksum ^= bitrev(addr[j<<4]);
}
-
+
if (checksum != 0xFF) {
free_netdev(dev);
return ERR_PTR(-ENODEV);
@@ -275,7 +275,7 @@ static int mace_set_address(struct net_device *dev, void *addr)
/* load up the hardware address */
mb->iac = ADDRCHG | PHYADDR;
while ((mb->iac & ADDRCHG) != 0);
-
+
for (i = 0; i < 6; ++i) {
mb->padr = dev->dev_addr[i] = p[i];
}
@@ -290,7 +290,7 @@ static int mace_set_address(struct net_device *dev, void *addr)
* Open the Macintosh MACE. Most of this is playing with the DMA
* engine. The ethernet chip is quite friendly.
*/
-
+
static int mace_open(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -333,7 +333,7 @@ static int mace_open(struct net_device *dev)
mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES);
mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0);
-
+
if (mp->tx_ring==NULL || mp->rx_ring==NULL) {
if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES);
if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0);
@@ -348,7 +348,7 @@ static int mace_open(struct net_device *dev)
/* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */
- kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER);
+ kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER);
kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH);
mace_dma_off(dev);
@@ -362,11 +362,11 @@ static int mace_open(struct net_device *dev)
#if 0
/* load up the hardware address */
-
+
mb->iac = ADDRCHG | PHYADDR;
-
+
while ((mb->iac & ADDRCHG) != 0);
-
+
for (i = 0; i < 6; ++i)
mb->padr = dev->dev_addr[i];
@@ -374,7 +374,7 @@ static int mace_open(struct net_device *dev)
mb->iac = ADDRCHG | LOGADDR;
while ((mb->iac & ADDRCHG) != 0);
-
+
for (i = 0; i < 8; ++i)
mb->ladrf = 0;
@@ -386,14 +386,14 @@ static int mace_open(struct net_device *dev)
mace_rxdma_reset(dev);
mace_txdma_reset(dev);
-
+
return 0;
}
/*
* Shut down the mace and its interrupt channel
*/
-
+
static int mace_close(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -415,7 +415,7 @@ static int mace_close(struct net_device *dev)
/*
* Transmit a frame
*/
-
+
static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -427,7 +427,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev)
return 1;
}
mp->tx_count--;
-
+
mp->stats.tx_packets++;
mp->stats.tx_bytes += skb->len;
@@ -488,7 +488,7 @@ static void mace_set_multicast(struct net_device *dev)
mb->iac = ADDRCHG | LOGADDR;
while (mb->iac & ADDRCHG);
-
+
for (i = 0; i < 8; ++i) {
mb->ladrf = multicast_filter[i];
}
@@ -498,10 +498,10 @@ static void mace_set_multicast(struct net_device *dev)
}
/*
- * Miscellaneous interrupts are handled here. We may end up
+ * Miscellaneous interrupts are handled here. We may end up
* having to bash the chip on the head for bad errors
*/
-
+
static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
{
volatile struct mace *mb = mp->mace;
@@ -536,16 +536,16 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
* A transmit error has occurred. (We kick the transmit side from
* the DMA completion)
*/
-
+
static void mace_xmit_error(struct net_device *dev)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
volatile struct mace *mb = mp->mace;
u8 xmtfs, xmtrc;
-
+
xmtfs = mb->xmtfs;
xmtrc = mb->xmtrc;
-
+
if (xmtfs & XMTSV) {
if (xmtfs & UFLO) {
printk("%s: DMA underrun.\n", dev->name);
@@ -556,13 +556,13 @@ static void mace_xmit_error(struct net_device *dev)
if (xmtfs & RTRY) {
mp->stats.collisions++;
}
- }
+ }
}
/*
* A receive interrupt occurred.
*/
-
+
static void mace_recv_interrupt(struct net_device *dev)
{
/* struct mace_data *mp = (struct mace_data *) dev->priv; */
@@ -572,17 +572,17 @@ static void mace_recv_interrupt(struct net_device *dev)
/*
* Process the chip interrupt
*/
-
+
static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
struct mace_data *mp = (struct mace_data *) dev->priv;
volatile struct mace *mb = mp->mace;
u8 ir;
-
+
ir = mb->ir;
mace_handle_misc_intrs(mp, ir);
-
+
if (ir & XMTINT) {
mace_xmit_error(dev);
}
@@ -601,7 +601,7 @@ static void mace_tx_timeout(struct net_device *dev)
/*
* Handle a newly arrived frame
*/
-
+
static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
{
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -614,7 +614,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
}
if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR))
mp->stats.rx_errors++;
-
+
if (mf->status&RS_CLSN) {
mp->stats.collisions++;
}
@@ -624,7 +624,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
if (mf->status&RS_FCSERR) {
mp->stats.rx_crc_errors++;
}
-
+
skb = dev_alloc_skb(mf->len+2);
if (!skb) {
mp->stats.rx_dropped++;
@@ -632,7 +632,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
}
skb_reserve(skb,2);
memcpy(skb_put(skb, mf->len), mf->data, mf->len);
-
+
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
@@ -644,7 +644,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
/*
* The PSC has passed us a DMA interrupt event.
*/
-
+
static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
@@ -661,9 +661,9 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
/*
* Process the read queue
*/
-
+
status = psc_read_word(PSC_ENETRD_CTL);
-
+
if (status & 0x2000) {
mace_rxdma_reset(dev);
} else if (status & 0x0100) {
@@ -678,7 +678,7 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800)));
mp->rx_tail++;
}
-
+
/* If we're out of buffers in this ring then switch to */
/* the other set, otherwise just reactivate this one. */
@@ -689,7 +689,7 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
psc_write_word(PSC_ENETRD_CMD + mp->rx_slot, 0x9800);
}
}
-
+
/*
* Process the write queue
*/
diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c
index f6f3dafe83e..393d995f191 100644
--- a/drivers/net/macsonic.c
+++ b/drivers/net/macsonic.c
@@ -13,20 +13,20 @@
*
* Based on code
* (C) 1996 by Thomas Bogendoerfer (tsbogend@bigbug.franken.de)
- *
+ *
* This driver is based on work from Andreas Busse, but most of
* the code is rewritten.
- *
+ *
* (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
*
* A driver for the Mac onboard Sonic ethernet chip.
*
- * 98/12/21 MSch: judged from tests on Q800, it's basically working,
+ * 98/12/21 MSch: judged from tests on Q800, it's basically working,
* but eating up both receive and transmit resources
* and duplicating packets. Needs more testing.
*
* 99/01/03 MSch: upgraded to version 0.92 of the core driver, fixed.
- *
+ *
* 00/10/31 sammy@oh.verio.com: Updated driver for 2.4 kernels, fixed problems
* on centris.
*/
@@ -76,7 +76,7 @@ static struct platform_device *mac_sonic_device;
/* use 0 for production, 1 for verification, >1 for debug */
#ifdef SONIC_DEBUG
static unsigned int sonic_debug = SONIC_DEBUG;
-#else
+#else
static unsigned int sonic_debug = 1;
#endif
@@ -129,7 +129,7 @@ static inline void bit_reverse_addr(unsigned char addr[6])
int i;
for(i = 0; i < 6; i++)
- addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
+ addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
nibbletab[(addr[i] >> 4) &0xf]);
}
@@ -215,7 +215,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
unsigned short val;
printk(KERN_INFO "macsonic: PROM seems to be wrong, trying CAM entry 15\n");
-
+
SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
SONIC_WRITE(SONIC_CEP, 15);
@@ -228,7 +228,7 @@ int __init mac_onboard_sonic_ethernet_addr(struct net_device* dev)
val = SONIC_READ(SONIC_CAP0);
dev->dev_addr[1] = val >> 8;
dev->dev_addr[0] = val & 0xff;
-
+
printk(KERN_INFO "HW Address from CAM 15: ");
for (i = 0; i < 6; i++) {
printk("%2.2x", dev->dev_addr[i]);
@@ -258,7 +258,7 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
struct sonic_local* lp = netdev_priv(dev);
int sr;
int commslot = 0;
-
+
if (once_is_more_than_enough)
return -ENODEV;
once_is_more_than_enough = 1;
@@ -268,9 +268,9 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
if (macintosh_config->ether_type != MAC_ETHER_SONIC)
return -ENODEV;
-
+
printk(KERN_INFO "Checking for internal Macintosh ethernet (SONIC).. ");
-
+
/* Bogus probing, on the models which may or may not have
Ethernet (BTW, the Ethernet *is* always at the same
address, and nothing else lives there, at least if Apple's
@@ -293,7 +293,7 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
commslot = 1;
}
- printk("yes\n");
+ printk("yes\n");
/* Danger! My arms are flailing wildly! You *must* set lp->reg_offset
* and dev->base_addr before using SONIC_READ() or SONIC_WRITE() */
@@ -325,7 +325,7 @@ int __init mac_onboard_sonic_probe(struct net_device* dev)
lp->dma_bitmode = SONIC_BITMODE16;
sr = SONIC_READ(SONIC_SR);
- if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101)
+ if (sr == 0x0004 || sr == 0x0006 || sr == 0x0100 || sr == 0x0101)
/* 83932 is 0x0004 or 0x0006, 83934 is 0x0100 or 0x0101 */
lp->dma_bitmode = SONIC_BITMODE32;
else {
@@ -389,7 +389,7 @@ int __init mac_nubus_sonic_ethernet_addr(struct net_device* dev,
int __init macsonic_ident(struct nubus_dev* ndev)
{
- if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
+ if (ndev->dr_hw == NUBUS_DRHW_ASANTE_LC &&
ndev->dr_sw == NUBUS_DRSW_SONIC_LC)
return MACSONIC_DAYNALINK;
if (ndev->dr_hw == NUBUS_DRHW_SONIC &&
@@ -400,11 +400,11 @@ int __init macsonic_ident(struct nubus_dev* ndev)
else
return MACSONIC_APPLE;
}
-
+
if (ndev->dr_hw == NUBUS_DRHW_SMC9194 &&
ndev->dr_sw == NUBUS_DRSW_DAYNA)
return MACSONIC_DAYNA;
-
+
if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC &&
ndev->dr_sw == 0) { /* huh? */
return MACSONIC_APPLE16;
@@ -421,7 +421,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
u16 sonic_dcr;
int id = -1;
int reg_offset, dma_bitmode;
-
+
/* Find the first SONIC that hasn't been initialized already */
while ((ndev = nubus_find_type(NUBUS_CAT_NETWORK,
NUBUS_TYPE_ETHERNET, ndev)) != NULL)
@@ -459,7 +459,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + APPLE_SONIC_PROM_BASE;
sonic_dcr = SONIC_DCR_EXBUS | SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
- SONIC_DCR_PO1 | SONIC_DCR_BMS;
+ SONIC_DCR_PO1 | SONIC_DCR_BMS;
reg_offset = 0;
dma_bitmode = SONIC_BITMODE16;
break;
@@ -467,7 +467,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev)
base_addr = ndev->board->slot_addr + APPLE_SONIC_REGISTERS;
prom_addr = ndev->board->slot_addr + DAYNALINK_PROM_BASE;
sonic_dcr = SONIC_DCR_RFT1 | SONIC_DCR_TFT0 |
- SONIC_DCR_PO1 | SONIC_DCR_BMS;
+ SONIC_DCR_PO1 | SONIC_DCR_BMS;
reg_offset = 0;
dma_bitmode = SONIC_BITMODE16;
break;
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index d644bf3a933..55b1495a70d 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -93,7 +93,7 @@ struct meth_private {
static void meth_tx_timeout(struct net_device *dev);
static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs);
-
+
/* global, initialized in ip32-setup.c */
char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
@@ -232,7 +232,7 @@ static int meth_init_rx_ring(struct meth_private *priv)
skb_reserve(priv->rx_skbs[i],METH_RX_HEAD);
priv->rx_ring[i]=(rx_packet*)(priv->rx_skbs[i]->head);
/* I'll need to re-sync it after each RX */
- priv->rx_ring_dmas[i] =
+ priv->rx_ring_dmas[i] =
dma_map_single(NULL, priv->rx_ring[i],
METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
mace->eth.rx_fifo = priv->rx_ring_dmas[i];
@@ -281,7 +281,7 @@ int meth_reset(struct net_device *dev)
/* Load ethernet address */
load_eaddr(dev);
/* Should load some "errata", but later */
-
+
/* Check for device */
if (mdio_probe(priv) < 0) {
DPRINTK("Unable to find PHY\n");
@@ -452,7 +452,7 @@ static void meth_rx(struct net_device* dev, unsigned long int_status)
}
priv->rx_ring[priv->rx_write] = (rx_packet*)skb->head;
priv->rx_ring[priv->rx_write]->status.raw = 0;
- priv->rx_ring_dmas[priv->rx_write] =
+ priv->rx_ring_dmas[priv->rx_write] =
dma_map_single(NULL, priv->rx_ring[priv->rx_write],
METH_RX_BUFF_SIZE, DMA_FROM_DEVICE);
mace->eth.rx_fifo = priv->rx_ring_dmas[priv->rx_write];
@@ -555,7 +555,7 @@ static void meth_error(struct net_device* dev, unsigned status)
printk(KERN_WARNING "meth: Rx underflow\n");
spin_lock(&priv->meth_lock);
mace->eth.int_stat = METH_INT_RX_UNDERFLOW;
- /* more underflow interrupts will be delivered,
+ /* more underflow interrupts will be delivered,
* effectively throwing us into an infinite loop.
* Thus I stop processing Rx in this case. */
priv->dma_ctrl &= ~METH_DMA_RX_EN;
@@ -761,12 +761,12 @@ static void meth_tx_timeout(struct net_device *dev)
}
/*
- * Ioctl commands
+ * Ioctl commands
*/
static int meth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
/* XXX Not yet implemented */
- switch(cmd) {
+ switch(cmd) {
case SIOCGMIIPHY:
case SIOCGMIIREG:
case SIOCSMIIREG:
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index e42aa797f08..2912a34f597 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -83,9 +83,9 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
if (bmcr & BMCR_ANENABLE) {
ecmd->advertising |= ADVERTISED_Autoneg;
ecmd->autoneg = AUTONEG_ENABLE;
-
+
nego = mii_nway_result(advert & lpa);
- if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
+ if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
(lpa2 >> 2))
ecmd->speed = SPEED_1000;
else if (nego == LPA_100FULL || nego == LPA_100HALF)
@@ -103,7 +103,7 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
} else {
ecmd->autoneg = AUTONEG_DISABLE;
- ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
+ ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
(bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
(bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
@@ -118,8 +118,8 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
struct net_device *dev = mii->dev;
- if (ecmd->speed != SPEED_10 &&
- ecmd->speed != SPEED_100 &&
+ if (ecmd->speed != SPEED_10 &&
+ ecmd->speed != SPEED_100 &&
ecmd->speed != SPEED_1000)
return -EINVAL;
if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
@@ -134,9 +134,9 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
return -EINVAL;
if ((ecmd->speed == SPEED_1000) && (!mii->supports_gmii))
return -EINVAL;
-
+
/* ignore supported, maxtxpkt, maxrxpkt */
-
+
if (ecmd->autoneg == AUTONEG_ENABLE) {
u32 bmcr, advert, tmp;
u32 advert2 = 0, tmp2 = 0;
@@ -176,7 +176,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
}
if ((mii->supports_gmii) && (advert2 != tmp2))
mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
-
+
/* turn on autonegotiation, and force a renegotiate */
bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
@@ -188,7 +188,7 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
/* turn off auto negotiation, set speed and duplexity */
bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
- tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
+ tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
BMCR_SPEED1000 | BMCR_FULLDPLX);
if (ecmd->speed == SPEED_1000)
tmp |= BMCR_SPEED1000;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index bbffb585b3b..07e58f4a291 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -179,7 +179,7 @@ static int mipsnet_open(struct net_device *dev)
pr_debug("%s: mipsnet_open\n", dev->name);
err = request_irq(dev->irq, &mipsnet_interrupt,
- SA_SHIRQ, dev->name, (void *) dev);
+ IRQF_SHARED, dev->name, (void *) dev);
if (err) {
pr_debug("%s: %s(): can't get irq %d\n",
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 625ff61c998..7f8e5ad1b70 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -74,7 +74,7 @@ static int ethernet_phy_detect(unsigned int eth_port_num);
static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location);
static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val);
static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static struct ethtool_ops mv643xx_ethtool_ops;
+static const struct ethtool_ops mv643xx_ethtool_ops;
static char mv643xx_driver_name[] = "mv643xx_eth";
static char mv643xx_driver_version[] = "1.0";
@@ -385,6 +385,8 @@ static int mv643xx_eth_receive_queue(struct net_device *dev, int budget)
struct pkt_info pkt_info;
while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) {
+ dma_unmap_single(NULL, pkt_info.buf_ptr, ETH_RX_SKB_SIZE,
+ DMA_FROM_DEVICE);
mp->rx_desc_count--;
received_packets++;
@@ -778,7 +780,7 @@ static int mv643xx_eth_open(struct net_device *dev)
int err;
err = request_irq(dev->irq, mv643xx_eth_int_handler,
- SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
if (err) {
printk(KERN_ERR "Can not assign IRQ number to MV643XX_eth%d\n",
port_num);
@@ -1145,7 +1147,7 @@ static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp,
desc->byte_cnt = length;
desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE);
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
BUG_ON(skb->protocol != ETH_P_IP);
cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM |
@@ -2721,7 +2723,7 @@ static void mv643xx_get_ethtool_stats(struct net_device *netdev,
eth_update_mib_counters(mp);
for (i = 0; i < MV643XX_STATS_LEN; i++) {
- char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;
+ char *p = (char *)mp+mv643xx_gstrings_stats[i].stat_offset;
data[i] = (mv643xx_gstrings_stats[i].sizeof_stat ==
sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p;
}
@@ -2764,7 +2766,7 @@ static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int c
return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL);
}
-static struct ethtool_ops mv643xx_ethtool_ops = {
+static const struct ethtool_ops mv643xx_ethtool_ops = {
.get_settings = mv643xx_get_settings,
.set_settings = mv643xx_set_settings,
.get_drvinfo = mv643xx_get_drvinfo,
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h
index 4262c1da6d4..33c5fafdbbd 100644
--- a/drivers/net/mv643xx_eth.h
+++ b/drivers/net/mv643xx_eth.h
@@ -258,7 +258,7 @@ struct pkt_info {
struct sk_buff *return_info; /* User resource return information */
};
-/* Ethernet port specific infomation */
+/* Ethernet port specific information */
struct mv643xx_mib_counters {
u64 good_octets_received;
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index dbdf189436f..4330197994d 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -177,6 +177,7 @@ struct myri10ge_priv {
struct work_struct watchdog_work;
struct timer_list watchdog_timer;
int watchdog_tx_done;
+ int watchdog_tx_req;
int watchdog_resets;
int tx_linearized;
int pause;
@@ -186,12 +187,14 @@ struct myri10ge_priv {
u8 mac_addr[6]; /* eeprom mac address */
unsigned long serial_number;
int vendor_specific_offset;
+ int fw_multicast_support;
u32 devctl;
u16 msi_flags;
- u32 pm_state[16];
u32 read_dma;
u32 write_dma;
u32 read_write_dma;
+ u32 link_changes;
+ u32 msg_enable;
};
static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";
@@ -257,6 +260,12 @@ module_param(myri10ge_max_irq_loops, int, S_IRUGO);
MODULE_PARM_DESC(myri10ge_max_irq_loops,
"Set stuck legacy IRQ detection threshold\n");
+#define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINK
+
+static int myri10ge_debug = -1; /* defaults above */
+module_param(myri10ge_debug, int, 0);
+MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
+
#define MYRI10GE_FW_OFFSET 1024*1024
#define MYRI10GE_HIGHPART_TO_U32(X) \
(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)
@@ -271,7 +280,7 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
struct mcp_cmd *buf;
char buf_bytes[sizeof(*buf) + 8];
struct mcp_cmd_response *response = mgp->cmd;
- char __iomem *cmd_addr = mgp->sram + MXGEFW_CMD_OFFSET;
+ char __iomem *cmd_addr = mgp->sram + MXGEFW_ETH_CMD;
u32 dma_low, dma_high, result, value;
int sleep_total = 0;
@@ -320,6 +329,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
if (result == 0) {
data->data0 = value;
return 0;
+ } else if (result == MXGEFW_CMD_UNKNOWN) {
+ return -ENOSYS;
} else {
dev_err(&mgp->pdev->dev,
"command %d failed, result = %d\n",
@@ -404,7 +415,7 @@ static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable)
buf[4] = htonl(dma_low); /* dummy addr LSW */
buf[5] = htonl(enable); /* enable? */
- submit = mgp->sram + 0xfc01c0;
+ submit = mgp->sram + MXGEFW_BOOT_DUMMY_RDMA;
myri10ge_pio_copy(submit, &buf, sizeof(buf));
for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++)
@@ -449,6 +460,7 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
struct mcp_gen_header *hdr;
size_t hdr_offset;
int status;
+ unsigned i;
if ((status = request_firmware(&fw, mgp->fw_name, dev)) < 0) {
dev_err(dev, "Unable to load %s firmware image via hotplug\n",
@@ -480,18 +492,12 @@ static int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size)
goto abort_with_fw;
crc = crc32(~0, fw->data, fw->size);
- if (mgp->tx.boundary == 2048) {
- /* Avoid PCI burst on chipset with unaligned completions. */
- int i;
- __iomem u32 *ptr = (__iomem u32 *) (mgp->sram +
- MYRI10GE_FW_OFFSET);
- for (i = 0; i < fw->size / 4; i++) {
- __raw_writel(((u32 *) fw->data)[i], ptr + i);
- wmb();
- }
- } else {
- myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET, fw->data,
- fw->size);
+ for (i = 0; i < fw->size; i += 256) {
+ myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i,
+ fw->data + i,
+ min(256U, (unsigned)(fw->size - i)));
+ mb();
+ readb(mgp->sram);
}
/* corruption checking is good for parity recovery and buggy chipset */
memcpy_fromio(fw->data, mgp->sram + MYRI10GE_FW_OFFSET, fw->size);
@@ -605,7 +611,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
buf[5] = htonl(8); /* where to copy to */
buf[6] = htonl(0); /* where to jump to */
- submit = mgp->sram + 0xfc0000;
+ submit = mgp->sram + MXGEFW_BOOT_HANDOFF;
myri10ge_pio_copy(submit, &buf, sizeof(buf));
mb();
@@ -621,7 +627,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp)
return -ENXIO;
}
dev_info(&mgp->pdev->dev, "handoff confirmed\n");
- myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096);
+ myri10ge_dummy_rdma(mgp, 1);
return 0;
}
@@ -769,6 +775,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
mgp->rx_small.cnt = 0;
mgp->rx_done.idx = 0;
mgp->rx_done.cnt = 0;
+ mgp->link_changes = 0;
status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
myri10ge_change_promisc(mgp, 0, 0);
myri10ge_change_pause(mgp, mgp->pause);
@@ -803,12 +810,13 @@ myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst,
* pages directly and building a fraglist in the near future.
*/
-static inline struct sk_buff *myri10ge_alloc_big(int bytes)
+static inline struct sk_buff *myri10ge_alloc_big(struct net_device *dev,
+ int bytes)
{
struct sk_buff *skb;
unsigned long data, roundup;
- skb = dev_alloc_skb(bytes + 4096 + MXGEFW_PAD);
+ skb = netdev_alloc_skb(dev, bytes + 4096 + MXGEFW_PAD);
if (skb == NULL)
return NULL;
@@ -826,12 +834,13 @@ static inline struct sk_buff *myri10ge_alloc_big(int bytes)
/* Allocate 2x as much space as required and use whichever portion
* does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes)
+static inline struct sk_buff *myri10ge_alloc_small_safe(struct net_device *dev,
+ unsigned int bytes)
{
struct sk_buff *skb;
unsigned long data, boundary;
- skb = dev_alloc_skb(2 * (bytes + MXGEFW_PAD) - 1);
+ skb = netdev_alloc_skb(dev, 2 * (bytes + MXGEFW_PAD) - 1);
if (unlikely(skb == NULL))
return NULL;
@@ -852,12 +861,13 @@ static inline struct sk_buff *myri10ge_alloc_small_safe(unsigned int bytes)
/* Allocate just enough space, and verify that the allocated
* space does not cross a 4KB boundary */
-static inline struct sk_buff *myri10ge_alloc_small(int bytes)
+static inline struct sk_buff *myri10ge_alloc_small(struct net_device *dev,
+ int bytes)
{
struct sk_buff *skb;
unsigned long roundup, data, end;
- skb = dev_alloc_skb(bytes + 16 + MXGEFW_PAD);
+ skb = netdev_alloc_skb(dev, bytes + 16 + MXGEFW_PAD);
if (unlikely(skb == NULL))
return NULL;
@@ -873,15 +883,17 @@ static inline struct sk_buff *myri10ge_alloc_small(int bytes)
"myri10ge_alloc_small: small skb crossed 4KB boundary\n");
myri10ge_skb_cross_4k = 1;
dev_kfree_skb_any(skb);
- skb = myri10ge_alloc_small_safe(bytes);
+ skb = myri10ge_alloc_small_safe(dev, bytes);
}
return skb;
}
static inline int
-myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes,
- int idx)
+myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct myri10ge_priv *mgp,
+ int bytes, int idx)
{
+ struct net_device *dev = mgp->dev;
+ struct pci_dev *pdev = mgp->pdev;
struct sk_buff *skb;
dma_addr_t bus;
int len, retval = 0;
@@ -889,11 +901,11 @@ myri10ge_getbuf(struct myri10ge_rx_buf *rx, struct pci_dev *pdev, int bytes,
bytes += VLAN_HLEN; /* account for 802.1q vlan tag */
if ((bytes + MXGEFW_PAD) > (4096 - 16) /* linux overhead */ )
- skb = myri10ge_alloc_big(bytes);
+ skb = myri10ge_alloc_big(dev, bytes);
else if (myri10ge_skb_cross_4k)
- skb = myri10ge_alloc_small_safe(bytes);
+ skb = myri10ge_alloc_small_safe(dev, bytes);
else
- skb = myri10ge_alloc_small(bytes);
+ skb = myri10ge_alloc_small(dev, bytes);
if (unlikely(skb == NULL)) {
rx->alloc_fail++;
@@ -935,7 +947,7 @@ static inline void myri10ge_vlan_ip_csum(struct sk_buff *skb, u16 hw_csum)
(vh->h_vlan_encapsulated_proto == htons(ETH_P_IP) ||
vh->h_vlan_encapsulated_proto == htons(ETH_P_IPV6))) {
skb->csum = hw_csum;
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
}
}
@@ -956,7 +968,7 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
unmap_len = pci_unmap_len(&rx->info[idx], len);
/* try to replace the received skb */
- if (myri10ge_getbuf(rx, mgp->pdev, bytes, idx)) {
+ if (myri10ge_getbuf(rx, mgp, bytes, idx)) {
/* drop the frame -- the old skbuf is re-cycled */
mgp->stats.rx_dropped += 1;
return 0;
@@ -973,12 +985,11 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
skb_put(skb, len);
skb->protocol = eth_type_trans(skb, mgp->dev);
- skb->dev = mgp->dev;
if (mgp->csum_flag) {
if ((skb->protocol == ntohs(ETH_P_IP)) ||
(skb->protocol == ntohs(ETH_P_IPV6))) {
skb->csum = ntohs((u16) csum);
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
} else
myri10ge_vlan_ip_csum(skb, ntohs((u16) csum));
}
@@ -1086,13 +1097,19 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp)
if (mgp->link_state != stats->link_up) {
mgp->link_state = stats->link_up;
if (mgp->link_state) {
- printk(KERN_INFO "myri10ge: %s: link up\n",
- mgp->dev->name);
+ if (netif_msg_link(mgp))
+ printk(KERN_INFO
+ "myri10ge: %s: link up\n",
+ mgp->dev->name);
netif_carrier_on(mgp->dev);
+ mgp->link_changes++;
} else {
- printk(KERN_INFO "myri10ge: %s: link down\n",
- mgp->dev->name);
+ if (netif_msg_link(mgp))
+ printk(KERN_INFO
+ "myri10ge: %s: link down\n",
+ mgp->dev->name);
netif_carrier_off(mgp->dev);
+ mgp->link_changes++;
}
}
if (mgp->rdma_tags_available !=
@@ -1289,11 +1306,13 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
"tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
"tx_heartbeat_errors", "tx_window_errors",
/* device-specific stats */
+ "tx_boundary", "WC", "irq", "MSI",
"read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs",
"serial_number", "tx_pkt_start", "tx_pkt_done",
"tx_req", "tx_done", "rx_small_cnt", "rx_big_cnt",
"wake_queue", "stop_queue", "watchdog_resets", "tx_linearized",
- "link_up", "dropped_link_overflow", "dropped_link_error_or_filtered",
+ "link_changes", "link_up", "dropped_link_overflow",
+ "dropped_link_error_or_filtered", "dropped_multicast_filtered",
"dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
"dropped_no_big_buffer"
};
@@ -1327,6 +1346,10 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
data[i] = ((unsigned long *)&mgp->stats)[i];
+ data[i++] = (unsigned int)mgp->tx.boundary;
+ data[i++] = (unsigned int)(mgp->mtrr >= 0);
+ data[i++] = (unsigned int)mgp->pdev->irq;
+ data[i++] = (unsigned int)mgp->msi_enabled;
data[i++] = (unsigned int)mgp->read_dma;
data[i++] = (unsigned int)mgp->write_dma;
data[i++] = (unsigned int)mgp->read_write_dma;
@@ -1341,17 +1364,32 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
data[i++] = (unsigned int)mgp->stop_queue;
data[i++] = (unsigned int)mgp->watchdog_resets;
data[i++] = (unsigned int)mgp->tx_linearized;
+ data[i++] = (unsigned int)mgp->link_changes;
data[i++] = (unsigned int)ntohl(mgp->fw_stats->link_up);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_link_overflow);
data[i++] =
(unsigned int)ntohl(mgp->fw_stats->dropped_link_error_or_filtered);
+ data[i++] =
+ (unsigned int)ntohl(mgp->fw_stats->dropped_multicast_filtered);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_runt);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
}
-static struct ethtool_ops myri10ge_ethtool_ops = {
+static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ mgp->msg_enable = value;
+}
+
+static u32 myri10ge_get_msglevel(struct net_device *netdev)
+{
+ struct myri10ge_priv *mgp = netdev_priv(netdev);
+ return mgp->msg_enable;
+}
+
+static const struct ethtool_ops myri10ge_ethtool_ops = {
.get_settings = myri10ge_get_settings,
.get_drvinfo = myri10ge_get_drvinfo,
.get_coalesce = myri10ge_get_coalesce,
@@ -1371,7 +1409,9 @@ static struct ethtool_ops myri10ge_ethtool_ops = {
#endif
.get_strings = myri10ge_get_strings,
.get_stats_count = myri10ge_get_stats_count,
- .get_ethtool_stats = myri10ge_get_ethtool_stats
+ .get_ethtool_stats = myri10ge_get_ethtool_stats,
+ .set_msglevel = myri10ge_set_msglevel,
+ .get_msglevel = myri10ge_get_msglevel
};
static int myri10ge_allocate_rings(struct net_device *dev)
@@ -1439,7 +1479,7 @@ static int myri10ge_allocate_rings(struct net_device *dev)
/* Fill the receive rings */
for (i = 0; i <= mgp->rx_small.mask; i++) {
- status = myri10ge_getbuf(&mgp->rx_small, mgp->pdev,
+ status = myri10ge_getbuf(&mgp->rx_small, mgp,
mgp->small_bytes, i);
if (status) {
printk(KERN_ERR
@@ -1451,8 +1491,7 @@ static int myri10ge_allocate_rings(struct net_device *dev)
for (i = 0; i <= mgp->rx_big.mask; i++) {
status =
- myri10ge_getbuf(&mgp->rx_big, mgp->pdev,
- dev->mtu + ETH_HLEN, i);
+ myri10ge_getbuf(&mgp->rx_big, mgp, dev->mtu + ETH_HLEN, i);
if (status) {
printk(KERN_ERR
"myri10ge: %s: alloced only %d big bufs\n",
@@ -1648,9 +1687,11 @@ static int myri10ge_open(struct net_device *dev)
}
if (mgp->mtrr >= 0) {
- mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + 0x200000;
- mgp->rx_small.wc_fifo = (u8 __iomem *) mgp->sram + 0x300000;
- mgp->rx_big.wc_fifo = (u8 __iomem *) mgp->sram + 0x340000;
+ mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
+ mgp->rx_small.wc_fifo =
+ (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
+ mgp->rx_big.wc_fifo =
+ (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_BIG;
} else {
mgp->tx.wc_fifo = NULL;
mgp->rx_small.wc_fifo = NULL;
@@ -1686,7 +1727,21 @@ static int myri10ge_open(struct net_device *dev)
cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->fw_stats_bus);
cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->fw_stats_bus);
- status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA, &cmd, 0);
+ cmd.data2 = sizeof(struct mcp_irq_data);
+ status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0);
+ if (status == -ENOSYS) {
+ dma_addr_t bus = mgp->fw_stats_bus;
+ bus += offsetof(struct mcp_irq_data, send_done_count);
+ cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus);
+ cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus);
+ status = myri10ge_send_cmd(mgp,
+ MXGEFW_CMD_SET_STATS_DMA_OBSOLETE,
+ &cmd, 0);
+ /* Firmware cannot support multicast without STATS_DMA_V2 */
+ mgp->fw_multicast_support = 0;
+ } else {
+ mgp->fw_multicast_support = 1;
+ }
if (status) {
printk(KERN_ERR "myri10ge: %s: Couldn't set stats DMA\n",
dev->name);
@@ -1841,7 +1896,8 @@ myri10ge_submit_req_wc(struct myri10ge_tx_buf *tx,
if (cnt > 0) {
/* pad it to 64 bytes. The src is 64 bytes bigger than it
* needs to be so that we don't overrun it */
- myri10ge_pio_copy(tx->wc_fifo + (cnt << 18), src, 64);
+ myri10ge_pio_copy(tx->wc_fifo + MXGEFW_ETH_SEND_OFFSET(cnt),
+ src, 64);
mb();
}
}
@@ -1897,13 +1953,13 @@ again:
pseudo_hdr_offset = 0;
odd_flag = 0;
flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST);
- if (likely(skb->ip_summed == CHECKSUM_HW)) {
+ if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
cksum_offset = (skb->h.raw - skb->data);
pseudo_hdr_offset = (skb->h.raw + skb->csum) - skb->data;
/* If the headers are excessively large, then we must
* fall back to a software checksum */
if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) {
- if (skb_checksum_help(skb, 0))
+ if (skb_checksum_help(skb))
goto drop;
cksum_offset = 0;
pseudo_hdr_offset = 0;
@@ -2112,7 +2168,7 @@ abort_linearize:
}
idx = (idx + 1) & tx->mask;
} while (idx != last_idx);
- if (skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
printk(KERN_ERR
"myri10ge: %s: TSO but wanted to linearize?!?!?\n",
mgp->dev->name);
@@ -2140,9 +2196,81 @@ static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
static void myri10ge_set_multicast_list(struct net_device *dev)
{
+ struct myri10ge_cmd cmd;
+ struct myri10ge_priv *mgp;
+ struct dev_mc_list *mc_list;
+ int err;
+
+ mgp = netdev_priv(dev);
/* can be called from atomic contexts,
* pass 1 to force atomicity in myri10ge_send_cmd() */
- myri10ge_change_promisc(netdev_priv(dev), dev->flags & IFF_PROMISC, 1);
+ myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
+
+ /* This firmware is known to not support multicast */
+ if (!mgp->fw_multicast_support)
+ return;
+
+ /* Disable multicast filtering */
+
+ err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
+ if (err != 0) {
+ printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_ENABLE_ALLMULTI,"
+ " error status: %d\n", dev->name, err);
+ goto abort;
+ }
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /* request to disable multicast filtering, so quit here */
+ return;
+ }
+
+ /* Flush the filters */
+
+ err = myri10ge_send_cmd(mgp, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
+ &cmd, 1);
+ if (err != 0) {
+ printk(KERN_ERR
+ "myri10ge: %s: Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS"
+ ", error status: %d\n", dev->name, err);
+ goto abort;
+ }
+
+ /* Walk the multicast list, and add each address */
+ for (mc_list = dev->mc_list; mc_list != NULL; mc_list = mc_list->next) {
+ memcpy(&cmd.data0, &mc_list->dmi_addr, 4);
+ memcpy(&cmd.data1, ((char *)&mc_list->dmi_addr) + 4, 2);
+ cmd.data0 = htonl(cmd.data0);
+ cmd.data1 = htonl(cmd.data1);
+ err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP,
+ &cmd, 1);
+
+ if (err != 0) {
+ printk(KERN_ERR "myri10ge: %s: Failed "
+ "MXGEFW_JOIN_MULTICAST_GROUP, error status:"
+ "%d\t", dev->name, err);
+ printk(KERN_ERR "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ((unsigned char *)&mc_list->dmi_addr)[0],
+ ((unsigned char *)&mc_list->dmi_addr)[1],
+ ((unsigned char *)&mc_list->dmi_addr)[2],
+ ((unsigned char *)&mc_list->dmi_addr)[3],
+ ((unsigned char *)&mc_list->dmi_addr)[4],
+ ((unsigned char *)&mc_list->dmi_addr)[5]
+ );
+ goto abort;
+ }
+ }
+ /* Enable multicast filtering */
+ err = myri10ge_send_cmd(mgp, MXGEFW_DISABLE_ALLMULTI, &cmd, 1);
+ if (err != 0) {
+ printk(KERN_ERR "myri10ge: %s: Failed MXGEFW_DISABLE_ALLMULTI,"
+ "error status: %d\n", dev->name, err);
+ goto abort;
+ }
+
+ return;
+
+abort:
+ return;
}
static int myri10ge_set_mac_address(struct net_device *dev, void *addr)
@@ -2197,8 +2325,6 @@ static int myri10ge_change_mtu(struct net_device *dev, int new_mtu)
* any other device, except if forced with myri10ge_ecrc_enable > 1.
*/
-#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE 0x005d
-
static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
{
struct pci_dev *bridge = mgp->pdev->bus->self;
@@ -2291,6 +2417,8 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
*/
#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
+#define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7
+#define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa
static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
{
@@ -2300,15 +2428,34 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
mgp->fw_name = myri10ge_fw_unaligned;
if (myri10ge_force_firmware == 0) {
+ int link_width, exp_cap;
+ u16 lnk;
+
+ exp_cap = pci_find_capability(mgp->pdev, PCI_CAP_ID_EXP);
+ pci_read_config_word(mgp->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
+ link_width = (lnk >> 4) & 0x3f;
+
myri10ge_enable_ecrc(mgp);
- /* Check to see if the upstream bridge is known to
- * provide aligned completions */
- if (bridge
- /* ServerWorks HT2000/HT1000 */
- && bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
- && bridge->device ==
- PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE) {
+ /* Check to see if Link is less than 8 or if the
+ * upstream bridge is known to provide aligned
+ * completions */
+ if (link_width < 8) {
+ dev_info(&mgp->pdev->dev, "PCIE x%d Link\n",
+ link_width);
+ mgp->tx.boundary = 4096;
+ mgp->fw_name = myri10ge_fw_aligned;
+ } else if (bridge &&
+ /* ServerWorks HT2000/HT1000 */
+ ((bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
+ && bridge->device ==
+ PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE)
+ /* All Intel E5000 PCIE ports */
+ || (bridge->vendor == PCI_VENDOR_ID_INTEL
+ && bridge->device >=
+ PCI_DEVICE_ID_INTEL_E5000_PCIE23
+ && bridge->device <=
+ PCI_DEVICE_ID_INTEL_E5000_PCIE47))) {
dev_info(&mgp->pdev->dev,
"Assuming aligned completions (0x%x:0x%x)\n",
bridge->vendor, bridge->device);
@@ -2410,18 +2557,24 @@ static int myri10ge_resume(struct pci_dev *pdev)
return -EIO;
}
myri10ge_restore_state(mgp);
- pci_enable_device(pdev);
+
+ status = pci_enable_device(pdev);
+ if (status < 0) {
+ dev_err(&pdev->dev, "failed to enable device\n");
+ return -EIO;
+ }
+
pci_set_master(pdev);
- status = request_irq(pdev->irq, myri10ge_intr, SA_SHIRQ,
+ status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
netdev->name, mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed to allocate IRQ\n");
- goto abort_with_msi;
+ goto abort_with_enabled;
}
myri10ge_reset(mgp);
- myri10ge_dummy_rdma(mgp, mgp->tx.boundary != 4096);
+ myri10ge_dummy_rdma(mgp, 1);
/* Save configuration space to be restored if the
* nic resets due to a parity error */
@@ -2436,7 +2589,8 @@ static int myri10ge_resume(struct pci_dev *pdev)
return 0;
-abort_with_msi:
+abort_with_enabled:
+ pci_disable_device(pdev);
return -EIO;
}
@@ -2538,7 +2692,8 @@ static void myri10ge_watchdog_timer(unsigned long arg)
mgp = (struct myri10ge_priv *)arg;
if (mgp->tx.req != mgp->tx.done &&
- mgp->tx.done == mgp->watchdog_tx_done)
+ mgp->tx.done == mgp->watchdog_tx_done &&
+ mgp->watchdog_tx_req != mgp->watchdog_tx_done)
/* nic seems like it might be stuck.. */
schedule_work(&mgp->watchdog_work);
else
@@ -2547,6 +2702,7 @@ static void myri10ge_watchdog_timer(unsigned long arg)
jiffies + myri10ge_watchdog_timeout * HZ);
mgp->watchdog_tx_done = mgp->tx.done;
+ mgp->watchdog_tx_req = mgp->tx.req;
}
static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -2574,6 +2730,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mgp->csum_flag = MXGEFW_FLAGS_CKSUM;
mgp->pause = myri10ge_flow_control;
mgp->intr_coal_delay = myri10ge_intr_coal_delay;
+ mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT);
init_waitqueue_head(&mgp->down_wq);
if (pci_enable_device(pdev)) {
@@ -2694,7 +2851,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
mgp->msi_enabled = 1;
}
- status = request_irq(pdev->irq, myri10ge_intr, SA_SHIRQ,
+ status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED,
netdev->name, mgp);
if (status != 0) {
dev_err(&pdev->dev, "failed to allocate IRQ\n");
@@ -2737,11 +2894,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dev_err(&pdev->dev, "register_netdev failed: %d\n", status);
goto abort_with_irq;
}
-
- printk(KERN_INFO "myri10ge: %s: %s IRQ %d, tx bndry %d, fw %s, WC %s\n",
- netdev->name, (mgp->msi_enabled ? "MSI" : "xPIC"),
- pdev->irq, mgp->tx.boundary, mgp->fw_name,
- (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+ dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
+ (mgp->msi_enabled ? "MSI" : "xPIC"),
+ pdev->irq, mgp->tx.boundary, mgp->fw_name,
+ (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
return 0;
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h
index 0a6cae6cb18..9519ae7cd5e 100644
--- a/drivers/net/myri10ge/myri10ge_mcp.h
+++ b/drivers/net/myri10ge/myri10ge_mcp.h
@@ -91,7 +91,19 @@ struct mcp_kreq_ether_recv {
/* Commands */
-#define MXGEFW_CMD_OFFSET 0xf80000
+#define MXGEFW_BOOT_HANDOFF 0xfc0000
+#define MXGEFW_BOOT_DUMMY_RDMA 0xfc01c0
+
+#define MXGEFW_ETH_CMD 0xf80000
+#define MXGEFW_ETH_SEND_4 0x200000
+#define MXGEFW_ETH_SEND_1 0x240000
+#define MXGEFW_ETH_SEND_2 0x280000
+#define MXGEFW_ETH_SEND_3 0x2c0000
+#define MXGEFW_ETH_RECV_SMALL 0x300000
+#define MXGEFW_ETH_RECV_BIG 0x340000
+
+#define MXGEFW_ETH_SEND(n) (0x200000 + (((n) & 0x03) * 0x40000))
+#define MXGEFW_ETH_SEND_OFFSET(n) (MXGEFW_ETH_SEND(n) - MXGEFW_ETH_SEND_4)
enum myri10ge_mcp_cmd_type {
MXGEFW_CMD_NONE = 0,
@@ -154,7 +166,7 @@ enum myri10ge_mcp_cmd_type {
MXGEFW_CMD_SET_MTU,
MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */
MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */
- MXGEFW_CMD_SET_STATS_DMA,
+ MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, /* replaced by SET_STATS_DMA_V2 */
MXGEFW_ENABLE_PROMISC,
MXGEFW_DISABLE_PROMISC,
@@ -168,7 +180,26 @@ enum myri10ge_mcp_cmd_type {
* data2 = RDMA length (MSH), WDMA length (LSH)
* command return data = repetitions (MSH), 0.5-ms ticks (LSH)
*/
- MXGEFW_DMA_TEST
+ MXGEFW_DMA_TEST,
+
+ MXGEFW_ENABLE_ALLMULTI,
+ MXGEFW_DISABLE_ALLMULTI,
+
+ /* returns MXGEFW_CMD_ERROR_MULTICAST
+ * if there is no room in the cache
+ * data0,MSH(data1) = multicast group address */
+ MXGEFW_JOIN_MULTICAST_GROUP,
+ /* returns MXGEFW_CMD_ERROR_MULTICAST
+ * if the address is not in the cache,
+ * or is equal to FF-FF-FF-FF-FF-FF
+ * data0,MSH(data1) = multicast group address */
+ MXGEFW_LEAVE_MULTICAST_GROUP,
+ MXGEFW_LEAVE_ALL_MULTICAST_GROUPS,
+
+ MXGEFW_CMD_SET_STATS_DMA_V2,
+ /* data0, data1 = bus addr,
+ * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows
+ * adding new stuff to mcp_irq_data without changing the ABI */
};
enum myri10ge_mcp_cmd_status {
@@ -180,11 +211,17 @@ enum myri10ge_mcp_cmd_status {
MXGEFW_CMD_ERROR_CLOSED,
MXGEFW_CMD_ERROR_HASH_ERROR,
MXGEFW_CMD_ERROR_BAD_PORT,
- MXGEFW_CMD_ERROR_RESOURCES
+ MXGEFW_CMD_ERROR_RESOURCES,
+ MXGEFW_CMD_ERROR_MULTICAST
};
-/* 40 Bytes */
+#define MXGEFW_OLD_IRQ_DATA_LEN 40
+
struct mcp_irq_data {
+ /* add new counters at the beginning */
+ u32 future_use[5];
+ u32 dropped_multicast_filtered;
+ /* 40 Bytes */
u32 send_done_count;
u32 link_up;
diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h
index e9c6e569d1f..e21ec9b2c70 100644
--- a/drivers/net/myri_code.h
+++ b/drivers/net/myri_code.h
@@ -1,4778 +1,4778 @@
-/* This is the Myrinet MCP code for LANai4.x */
+/* This is the Myrinet MCP code for LANai4.x */
/* Generated by cat $MYRI_HOME/lib/lanai/mcp4.dat > myri_code4.h */
-static unsigned int lanai4_code_off = 0x0000; /* half-word offset */
+static unsigned int lanai4_code_off = 0x0000; /* half-word offset */
static unsigned char lanai4_code[76256] __initdata = {
-0xF2,0x0E,
-0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x02, 0x05,0x3C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x02, 0x0A,0xBC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x02, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x04, 0x4A,0x9C, 0x85,0x16, 0x00,0x00, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
-0x01,0x01, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x01,0x00, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x01,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0xF4,0x82, 0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x01,0xE0, 0xB4,0xBA,
-0x68,0x02, 0xE0,0x00, 0x01,0xE0, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x3B,0x64, 0xF5,0x84,
-0x4F,0x54, 0xF7,0x05, 0x7A,0x10, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x01,0x99, 0x97,0x2A,
-0x00,0x20, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x26,0xAC, 0x00,0x01, 0x77,0x35,
-0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA4,0xBA,
-0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xD7,0x00, 0x0A,0x01, 0xE0,0x00,
-0x01,0xD0, 0xF7,0x05, 0x7A,0x18, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x06,0xAC,
-0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38,
-0x00,0x0C, 0xA4,0xBA, 0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38,
-0x60,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05, 0x7A,0x18, 0x97,0x2A, 0x00,0x14, 0xF5,0x05,
-0x79,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
-0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x02,0x4C, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x02,0x4C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x02,0x85, 0xF4,0x82, 0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
-0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x02,0x74, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF3,0x06, 0x2A,0x6C, 0xF3,0x05, 0x2C,0x10, 0xE0,0x00, 0x05,0x28, 0xF0,0x05,
-0x7A,0x18, 0xF3,0x84, 0x79,0xD8, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
-0xFF,0xC4, 0x84,0x1E, 0x00,0x10, 0x96,0x96, 0xFF,0xD4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16,
-0xFF,0xE0, 0x85,0x1E, 0x00,0x14, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x03,0x6C, 0x95,0x16,
-0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
-0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00, 0x02,0xFC, 0xC6,0x24,
-0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
-0x03,0x00, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x03,0x0D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
-0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x03,0x48, 0xF5,0x02,
-0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x03,0x50, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
-0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0x03,0x51, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
-0x03,0x61, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
-0x03,0x70, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
-0x03,0xA5, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x04,0x18, 0x96,0x96,
-0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x04,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x04,0x1C, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x04,0x2C, 0xF4,0x82,
-0x00,0x01, 0xE0,0x00, 0x04,0x84, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
-0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
-0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
-0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
-0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x05,0x25, 0xF3,0x06, 0x29,0xE0, 0x86,0x96,
-0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
-0x6A,0x00, 0xEC,0x00, 0x04,0xF0, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
-0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
-0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
-0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x04,0xB1, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
-0x00,0x03, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
-0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
-0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
-0x29,0xE0, 0xF3,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x04, 0x7A,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x05,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x05,0xCD, 0xF5,0x86, 0x4A,0x98, 0xF6,0x04, 0x79,0xD8, 0xF6,0x84, 0x4F,0x54, 0x00,0x00,
-0x00,0x01, 0x96,0xB2, 0x00,0x1C, 0x06,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA5,0x3A, 0x58,0x02, 0x00,0x00,
-0x00,0x01, 0x95,0x32, 0x00,0x10, 0xC7,0x38, 0x58,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05,
-0x7A,0x18, 0x97,0x32, 0x00,0x14, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0x05,0xFC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
-0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x05,0xF4, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF5,0x06, 0x2A,0x6C, 0xF5,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF7,0x04, 0x75,0xEC, 0x85,0x2E,
-0x00,0x20, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0xF5,0x05, 0x7A,0x08, 0xF7,0x04,
-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x06,0xCC, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x1C, 0xF6,0x84, 0x4F,0x54, 0xF7,0x05,
-0x7A,0x00, 0xC7,0x34, 0x72,0x00, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x06,0x8D, 0xF5,0x02,
-0x00,0x01, 0xE0,0x00, 0x06,0x90, 0xF5,0x05, 0x79,0xF8, 0xF0,0x85, 0x79,0xF8, 0xF6,0x84,
-0x7A,0x00, 0xC7,0x38, 0x70,0x00, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x79,0xF8, 0xF6,0x85,
-0x79,0xE8, 0xC7,0x38, 0x70,0x00, 0xC6,0x34, 0x70,0x00, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x06,0xCC, 0xF6,0x05, 0x79,0xF0, 0x20,0x36,
-0x00,0x00, 0xEC,0x00, 0x06,0xF8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
-0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x07,0x38, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00,
-0x07,0x38, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
-0x72,0x00, 0xEE,0x00, 0x07,0x19, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x4A,0x9C, 0xE0,0x00,
-0x07,0x28, 0xF7,0x05, 0x79,0xF0, 0x20,0x32, 0x00,0x00, 0xEC,0x00, 0x07,0x28, 0x00,0x00,
-0x00,0x01, 0xF0,0x85, 0x79,0xF0, 0xF5,0x85, 0x79,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xD5, 0xF4,0x02,
-0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x07,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x00, 0x0A,0xA4, 0xF3,0x06,
-0x2B,0x84, 0xF6,0x84, 0x79,0xE8, 0xF6,0x06, 0x4A,0x98, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x84, 0x79,0xE0, 0x07,0x38, 0x00,0x0C, 0xA3,0x3A,
-0x60,0x02, 0xC3,0xB4, 0x00,0x00, 0x93,0x36, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
-0x00,0x04, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x97,0x36, 0x00,0x14, 0x84,0x9E,
-0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x94,0x96, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E,
-0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
-0x08,0xEC, 0x95,0x16, 0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
-0x00,0x02, 0xC6,0xB8, 0x60,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x08,0x7C, 0xC6,0x20,
-0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
-0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x08,0x8D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
-0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x08,0xC8, 0xF5,0x02,
-0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x08,0xD0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
-0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0x08,0xD1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
-0x08,0xE1, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
-0x08,0xF0, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x09,0x25, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x09,0x98, 0x96,0x96,
-0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x09,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x09,0x9C, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x09,0xAC, 0xF4,0x82,
-0x00,0x01, 0xE0,0x00, 0x0A,0x04, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
-0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
-0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
-0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
-0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x0A,0xA5, 0xF3,0x06, 0x2A,0xF8, 0x86,0x96,
-0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
-0x6A,0x00, 0xEC,0x00, 0x0A,0x70, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
-0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
-0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
-0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x0A,0x31, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
-0x00,0x02, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
-0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
-0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
-0x2A,0xF8, 0xF3,0x05, 0x2C,0x1C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF6,0x84, 0x79,0xE8, 0xF7,0x04, 0x79,0xF8, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
-0x70,0x00, 0xF7,0x04, 0x7A,0x20, 0xF6,0x85, 0x79,0xE8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x7A,0x20, 0xF7,0x04, 0x79,0xF0, 0xF6,0x04, 0x7A,0x20, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x0B,0x2C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x82, 0x00,0x13, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x0B,0x20, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86,
-0x2B,0x84, 0xE0,0x00, 0x0B,0x38, 0xF5,0x85, 0x2C,0x1C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x06, 0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF0,0x05,
-0x2D,0x38, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x18, 0xFF,0x85, 0x2E,0xDC, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
-0x74,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x29, 0x97,0x16, 0xFF,0xF4, 0x47,0x38,
-0xFF,0xFB, 0xF6,0x84, 0x6F,0x50, 0xCF,0xB8, 0x00,0x00, 0x83,0x96, 0xFF,0xF4, 0xF7,0x02,
-0x00,0x3F, 0xC3,0x9C, 0x6D,0x80, 0xC7,0x1C, 0x74,0x00, 0x20,0x3A, 0x00,0x3F, 0xE2,0x00,
-0x12,0x60, 0x93,0x96, 0xFF,0xF4, 0x77,0x39, 0x00,0x02, 0xF6,0x82, 0x0C,0x5C, 0xA6,0xB6,
-0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x00, 0x12,0x60, 0x00,0x00,
-0x12,0x60, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x5C, 0x00,0x00,
-0x0D,0x5C, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x12,0x50, 0x00,0x00,
-0x12,0x50, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE0, 0x00,0x00,
-0x0D,0xE0, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE8, 0x00,0x00,
-0x0D,0xF4, 0x00,0x00, 0x0E,0x00, 0x00,0x00, 0x0E,0x20, 0x00,0x00, 0x0E,0x40, 0x00,0x00,
-0x0E,0x60, 0x00,0x00, 0x0E,0x80, 0x00,0x00, 0x0E,0xA0, 0x00,0x00, 0x0E,0xC0, 0x00,0x00,
-0x0E,0xC8, 0x00,0x00, 0x0E,0xD0, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0E,0xD8, 0x00,0x00,
-0x0E,0xF4, 0x00,0x00, 0x0F,0x10, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0F,0x18, 0x00,0x00,
-0x0F,0x18, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x44, 0x00,0x00,
-0x0F,0x44, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x84, 0x00,0x00,
-0x0F,0x84, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x94, 0x00,0x00,
-0x0F,0x94, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB8, 0x00,0x00,
-0x0F,0xD8, 0x00,0x00, 0x0F,0xF8, 0x00,0x00, 0x10,0x2C, 0x00,0x00, 0x10,0x60, 0x00,0x00,
-0x10,0x94, 0x00,0x00, 0x10,0xC8, 0x00,0x00, 0x10,0xFC, 0x00,0x00, 0x11,0x30, 0x00,0x00,
-0x11,0x4C, 0x00,0x00, 0x11,0x68, 0x00,0x00, 0x12,0x14, 0x00,0x00, 0x11,0x84, 0x00,0x00,
-0x11,0xB4, 0x00,0x00, 0x11,0xE4, 0x00,0x00, 0x12,0x14, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF6,0x02, 0x00,0x05, 0x20,0x32, 0x00,0x14, 0xE6,0x00,
-0x0D,0xB5, 0x27,0x00, 0x00,0x10, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x0D,0xB5, 0xF7,0x06,
-0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00, 0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E,
-0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06,
-0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x0D,0xB5, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05,
-0x2E,0xCC, 0xF7,0x04, 0x2D,0x58, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x87,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x60, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
-0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xE0,0x00,
-0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
-0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
-0x00,0x06, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
-0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
-0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
-0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
-0x12,0x2C, 0xF3,0x82, 0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00,
-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
-0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
-0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
-0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
-0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF7,0x04,
-0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x13,0xCC, 0xF7,0x05,
-0x35,0x44, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x90,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x77,0x9C, 0x00,0x14, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0x12,0x9D, 0xF7,0x06, 0x04,0x00, 0xF7,0x04, 0x6F,0x5C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x6F,0x5C, 0xF7,0x04, 0x6F,0x5C, 0xE0,0x00, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0xF7,0x06, 0x04,0x00, 0xC0,0x1E, 0x74,0x00, 0xE6,0x00,
-0x14,0x29, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2E,0xD0, 0xF6,0x84, 0x35,0x24, 0x07,0x38,
-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF7,0x05, 0x2E,0xD0, 0xF7,0x04,
-0xE0,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF6,0x82,
-0x00,0x00, 0xF6,0x85, 0xE0,0x14, 0xF7,0x04, 0x2E,0xD8, 0xC5,0x34, 0x00,0x00, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x2E,0xD8, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x13,0xCC, 0xF6,0x82,
-0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x13,0xA0, 0x05,0xB4, 0x00,0x08, 0x95,0x93,
-0xFF,0xFC, 0x95,0x16, 0xFF,0xE8, 0x95,0x96, 0xFF,0xE4, 0x96,0x96, 0xFF,0xE0, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x64, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xE8, 0x85,0x96,
-0xFF,0xE4, 0x86,0x96, 0xFF,0xE0, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x13,0x90, 0xF7,0x02,
-0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00,
-0x13,0x75, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x13,0x90, 0xF7,0x02,
-0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38,
-0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x12,0x00, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04,
-0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x13,0xC0, 0x07,0x34,
-0x14,0x94, 0xF3,0x84, 0x6F,0x44, 0xE0,0x00, 0x13,0xC4, 0xF3,0x85, 0x35,0x28, 0xF7,0x05,
-0x35,0x28, 0xE0,0x00, 0x12,0xE8, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
-0x14,0x29, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05, 0x35,0x24, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x14,0x28, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x14,0x28, 0xF0,0x05,
-0x2D,0x38, 0xF7,0x04, 0xE0,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x14,0x29, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0xE0,0x10, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x02,0x98, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84, 0x2D,0x38, 0xF7,0x04, 0x2D,0x3C, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x0C,0x09, 0xF6,0x86, 0x2C,0x28, 0x77,0x39,
-0x00,0x02, 0xA5,0x3A, 0x68,0x02, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00,
-0x14,0x91, 0x27,0x28, 0x00,0x15, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x14,0x91, 0xF7,0x06,
-0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E,
-0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36,
-0x00,0x1F, 0xE2,0x00, 0x14,0x91, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x06,
-0x2D,0x44, 0x76,0xA9, 0x00,0x02, 0xA7,0x36, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x04, 0x94,0x96,
-0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x2D,0x3C, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0x20,0x3A, 0x00,0x44, 0xE6,0x00,
-0x14,0x2C, 0xF7,0x05, 0x2D,0x3C, 0xE0,0x00, 0x14,0x2C, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16, 0x00,0x00, 0xF7,0x02,
-0x00,0x00, 0x85,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x21, 0xEE,0x00, 0x15,0x34, 0x95,0xA2,
-0x00,0x00, 0xF6,0x06, 0x23,0x38, 0x07,0x20, 0x00,0x84, 0xC6,0xA0, 0x00,0x00, 0x96,0x3A,
-0x00,0x04, 0x27,0x38, 0x00,0x04, 0xC0,0x3A, 0x6A,0x00, 0xEC,0x00, 0x15,0x20, 0x00,0x00,
-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96,
-0x00,0x00, 0x87,0x16, 0x00,0x04, 0xF6,0x04, 0x2D,0x40, 0x97,0x36, 0x00,0x00, 0x97,0x36,
-0x00,0x04, 0x07,0x30, 0x00,0x01, 0xF7,0x05, 0x2D,0x40, 0x96,0x36, 0x00,0x08, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00, 0x15,0xD9, 0x27,0x28, 0x00,0x15, 0x20,0x3A,
-0x00,0x01, 0xE2,0x00, 0x15,0xD9, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02,
-0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
-0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x15,0xD9, 0xB6,0x2E,
-0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF6,0x86, 0x2D,0x44, 0x77,0x29, 0x00,0x02, 0xA6,0xBA,
-0x68,0x02, 0x00,0x00, 0x00,0x01, 0x86,0xB6, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x87,0x16, 0x00,0x00, 0x86,0x96, 0x00,0x04, 0xF6,0x06, 0x2D,0x44, 0x76,0xB5,
-0x00,0x02, 0x85,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xB5,0xB6, 0x60,0x02, 0xC6,0xB4,
-0x70,0x00, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xB6, 0x00,0x04, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2,
-0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00, 0x16,0xB4, 0xC5,0xB4, 0x00,0x00, 0x20,0x36,
-0x00,0x0F, 0xEE,0x00, 0x16,0xB4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00,
-0x16,0xB5, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEC,0x00, 0x16,0xD0, 0x00,0x00,
-0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32,
-0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00, 0x16,0xD8, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A,
-0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x34,0x58, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
-0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x3F,0x94, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2F,0xF8, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
-0x3B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x02, 0x26,0xE4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x13, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x26,0xA0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
-0x00,0x11, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05,
-0x7A,0x78, 0xF0,0x05, 0x32,0xE8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x18,0x55, 0xF6,0x86, 0x71,0xC4, 0xE0,0x00, 0x18,0x6C, 0xF6,0x02,
-0x00,0x00, 0xF7,0x04, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
-0x68,0x00, 0x86,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x32,0xC4, 0x86,0xB2,
-0x00,0x08, 0x07,0x01, 0x80,0x00, 0xC5,0xB4, 0x74,0x00, 0xF5,0x85, 0x32,0xD0, 0x87,0x32,
-0x00,0x18, 0xF6,0x86, 0x6F,0x44, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x2E,
-0x00,0x00, 0xF7,0x05, 0x32,0xC0, 0x07,0x38, 0x09,0xD8, 0x86,0xB2, 0x00,0x04, 0xF7,0x05,
-0x32,0xCC, 0xE6,0x00, 0x19,0x41, 0xF6,0x85, 0x32,0xC8, 0xF7,0x04, 0x71,0x98, 0xF6,0x84,
-0x7A,0x78, 0x27,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x19,0x10, 0xF7,0x05,
-0x71,0x98, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x18,0xE8, 0xF3,0x02, 0x00,0x11, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05, 0x76,0xFC, 0xE0,0x00,
-0x18,0xF8, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05,
-0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x19,0x14, 0xF3,0x02,
-0x00,0x01, 0xF3,0x06, 0x31,0x10, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF3,0x02,
-0x00,0x01, 0xF3,0x05, 0x7A,0x78, 0xF3,0x06, 0x30,0x84, 0xF3,0x05, 0x32,0xD4, 0xF3,0x04,
-0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x26,0x8C, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
-0x00,0x00, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x1C,0xB9, 0x93,0x16, 0xFF,0xE4, 0x87,0x32,
-0x00,0x08, 0x86,0x96, 0xFF,0xE4, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
-0x19,0x84, 0x20,0x36, 0x00,0x00, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x32,0x00, 0xE6,0x00, 0x19,0x84, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02, 0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16,
-0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A, 0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C,
-0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00,
-0x1A,0x70, 0x96,0x16, 0xFF,0xEC, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
-0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E,
-0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x00, 0xC4,0x84,
-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x1A,0x04, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
-0x00,0x00, 0xE6,0x00, 0x1A,0x11, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2,
-0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0x1A,0x4C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x54, 0x20,0x2E,
-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0x1A,0x55, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0x1A,0x65, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26,
-0x00,0x00, 0xE6,0x00, 0x1A,0x70, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16,
-0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1A,0xB1, 0xF6,0x02,
-0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1B,0x18, 0x96,0x96, 0xFF,0xF4, 0x27,0x14,
-0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96,
-0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1B,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x1B,0x1C, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02,
-0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0,
-0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xEC,0x00, 0x1C,0x04, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8, 0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE,
-0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x1B,0x94, 0xC4,0x84, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1B,0x98, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
-0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x1B,0xA5, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
-0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0x1B,0xE0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x1B,0xE8, 0x20,0x32, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x1B,0xE9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1B,0xF9, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
-0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x1C,0x04, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
-0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00,
-0x1C,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1C,0xAC, 0x96,0x96,
-0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93,
-0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1C,0xA9, 0xF6,0x02,
-0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00,
-0x1C,0xB0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x1E,0x15, 0xF3,0x02, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6,
-0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E, 0x00,0x10, 0xE2,0x00, 0x1C,0xDC, 0x20,0x32,
-0x00,0x10, 0xE2,0x00, 0x1C,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00,
-0x1D,0x24, 0xF7,0x02, 0x00,0x00, 0x07,0x30, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00,
-0x1D,0x1D, 0xF6,0x82, 0x00,0x00, 0x20,0x32, 0x00,0x10, 0xE6,0x00, 0x1D,0x20, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0x1D,0x24, 0xC7,0x34, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34,
-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0x14, 0xF3,0x02, 0x00,0x01, 0xF3,0x04,
-0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x1D,0x91, 0x76,0xB1,
-0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A,
-0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00, 0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0xF3,0x02,
-0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
-0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
-0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16,
-0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
-0x1D,0xEC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00,
-0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16,
-0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1E,0x18, 0xF3,0x02,
-0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
-0x00,0x00, 0xE6,0x00, 0x1F,0x35, 0xF6,0x82, 0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16,
-0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A,
-0x00,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
-0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04,
-0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0xAD, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x1E,0xAC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
-0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x1E,0xC8, 0xF7,0x05,
-0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
-0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
-0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
-0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04, 0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA,
-0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1F,0x60, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02,
-0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00, 0x1F,0x68, 0xF7,0x02, 0x00,0x01, 0xF3,0x05,
-0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1F,0x7C, 0xF3,0x06,
-0x2F,0x6C, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94,
-0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00, 0x22,0x84, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02,
-0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05, 0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84,
-0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02, 0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84,
-0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02,
-0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05, 0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96,
-0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06,
-0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05,
-0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x34, 0x00,0x00,
-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x25, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x26,0x8C, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82, 0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38,
-0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x20,0x90, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04,
-0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x20,0x84, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x20,0x94, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05,
-0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x21,0xC0, 0x00,0x00,
-0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05,
-0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32,
-0x00,0x10, 0xE2,0x00, 0x21,0x19, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00,
-0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13,
-0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
-0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
-0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96,
-0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x21,0x78, 0x00,0x00,
-0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
-0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x21,0xC0, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0x21,0xC1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04,
-0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x21,0xFD, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x21,0xFC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
-0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x22,0x18, 0xF7,0x05,
-0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
-0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
-0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
-0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02, 0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02,
-0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06, 0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04,
-0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05,
-0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x22,0xD5, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A,
-0x5A,0x00, 0xE6,0x00, 0x26,0x20, 0xC0,0x32, 0x6A,0x00, 0xEE,0x00, 0x26,0x21, 0x00,0x00,
-0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00,
-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04,
-0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04,
-0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04,
-0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x23,0x45, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x23,0x48, 0xF7,0x05,
-0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
-0x00,0x21, 0xE2,0x00, 0x23,0x8C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x23,0x80, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
-0x00,0x22, 0xE0,0x00, 0x23,0x90, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84,
-0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0x87,0x02,
-0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13,
-0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93,
-0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x24,0x78, 0x00,0x00,
-0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00,
-0x24,0x15, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x24,0x78, 0x00,0x00,
-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1,
-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16,
-0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13,
-0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30,
-0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x24,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
-0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A,
-0x32,0x00, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
-0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x24,0xBD, 0x00,0x00,
-0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x24,0xF9, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x24,0xF8, 0xB3,0x3A,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38,
-0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x25,0x14, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05,
-0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36,
-0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x25,0xD1, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
-0x00,0x21, 0xE2,0x00, 0x25,0xC4, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x25,0xB0, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
-0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x00, 0x25,0xC8, 0xF3,0x05,
-0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00, 0x25,0xD8, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00,
-0x25,0xDC, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06, 0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04,
-0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x26,0x8C, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x26,0x8C, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x26,0x8C, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
-0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xEE,0x00, 0x26,0x41, 0xC5,0xB4,
-0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00, 0x26,0x48, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8,
-0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84, 0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35,
-0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6,
-0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04, 0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02,
-0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85,
-0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x7A,0x78, 0xF7,0x06,
-0x30,0x84, 0xF7,0x05, 0x32,0xD4, 0xF7,0x04, 0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04,
-0x32,0xD0, 0xF3,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x2A,0x71, 0x93,0x16,
-0xFF,0xE4, 0xF6,0x84, 0x32,0xC4, 0x86,0x16, 0xFF,0xE4, 0x87,0x36, 0x00,0x08, 0xC3,0x04,
-0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32, 0x00,0x00, 0x87,0x36,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02,
-0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A,
-0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C, 0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00,
-0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00, 0x28,0x28, 0x96,0x16, 0xFF,0xEC, 0x77,0x31,
-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30,
-0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E, 0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x27,0xB8, 0xC4,0x84, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x27,0xBC, 0x20,0x2A,
-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x27,0xC9, 0x00,0x00,
-0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x04, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x28,0x0C, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x0D, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x28,0x1D, 0x20,0x26,
-0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x28,0x28, 0xF3,0x02,
-0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
-0x00,0x00, 0xE6,0x00, 0x28,0x69, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
-0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
-0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
-0x28,0xD0, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13,
-0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x28,0xCD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E,
-0x00,0x08, 0xE0,0x00, 0x28,0xD4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02, 0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16,
-0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0, 0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32,
-0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x29,0xBC, 0x96,0x96,
-0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8,
-0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE, 0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16,
-0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0x4C, 0xC4,0x84, 0x00,0x00, 0x86,0xAE,
-0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x29,0x50, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
-0x29,0x5D, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x29,0x98, 0xF6,0x02,
-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0xA0, 0x20,0x32, 0x00,0x00, 0x86,0xAE,
-0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0x29,0xA1, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x29,0xB1, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
-0x29,0xBC, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00,
-0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x29,0xFD, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xF0, 0xE0,0x00, 0x2A,0x64, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13,
-0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x2A,0x61, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
-0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
-0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96,
-0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x2A,0x68, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2B,0xCD, 0xF3,0x02, 0x00,0x01, 0xF6,0x84,
-0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6, 0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E,
-0x00,0x10, 0xE2,0x00, 0x2A,0x94, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2A,0xB1, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00, 0x2A,0xDC, 0xF7,0x02, 0x00,0x00, 0x07,0x30,
-0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x2A,0xD5, 0xF6,0x82, 0x00,0x00, 0x20,0x32,
-0x00,0x10, 0xE6,0x00, 0x2A,0xD8, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x2A,0xDC, 0xC7,0x34,
-0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x2B,0xCC, 0xF3,0x02, 0x00,0x01, 0xF3,0x04, 0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16,
-0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0x83,0x16,
-0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32,
-0x00,0x10, 0xE2,0x00, 0x2B,0x49, 0x76,0xB1, 0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A, 0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00,
-0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0xF3,0x02, 0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4,
-0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38,
-0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
-0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30,
-0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x2B,0xA4, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
-0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02,
-0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16, 0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
-0x00,0x00, 0xE6,0x00, 0x2B,0xD0, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16,
-0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0xED, 0xF6,0x82,
-0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16, 0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0x28, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
-0x2C,0x28, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x2C,0x65, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
-0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2C,0x64, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xE6,0x00, 0x2C,0x80, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
-0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
-0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
-0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
-0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04,
-0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA, 0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x2D,0x18, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00,
-0x2D,0x20, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x2D,0x34, 0xF3,0x06, 0x2F,0x6C, 0xE0,0x00, 0x34,0x44, 0xF3,0x05,
-0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94, 0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
-0x30,0x3C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
-0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
-0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
-0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
-0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
-0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
-0x74,0x00, 0xE6,0x00, 0x2D,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
-0x2D,0xDD, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
-0x00,0x10, 0xE6,0x00, 0x34,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
-0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
-0x2E,0x48, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x2E,0x3C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
-0x2E,0x4C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
-0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x02, 0xE6,0x00, 0x2F,0x78, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C,
-0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96,
-0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
-0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
-0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2E,0xD1, 0xF3,0x02,
-0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
-0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x13,
-0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
-0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38,
-0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
-0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
-0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32,
-0x00,0x11, 0xE6,0x00, 0x2F,0x30, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
-0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
-0x2F,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
-0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x2F,0x79, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
-0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x2F,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
-0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2F,0xB4, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xE6,0x00, 0x2F,0xD0, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
-0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
-0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
-0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
-0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
-0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06,
-0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
-0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x30,0x8D, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x33,0xD8, 0xC0,0x32,
-0x6A,0x00, 0xEE,0x00, 0x33,0xD9, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x30,0xFD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0x31,0x00, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x31,0x44, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x31,0x38, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x31,0x48, 0xF3,0x05,
-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
-0x32,0x74, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16,
-0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x31,0xCD, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E,
-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
-0x0F,0x00, 0xE0,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06,
-0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
-0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16,
-0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
-0x32,0x2C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
-0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x32,0x74, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x00, 0x32,0x75, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x32,0xB1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x32,0xB0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x32,0xCC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x33,0x91, 0xF7,0x05,
-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x89, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x33,0x7C, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x33,0x68, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
-0x77,0x00, 0xE0,0x00, 0x33,0x80, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
-0x33,0x90, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06,
-0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x34,0x44, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x34,0x44, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00,
-0x34,0x44, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xEE,0x00, 0x33,0xF9, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
-0x34,0x00, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84,
-0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35, 0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4,
-0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6, 0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04,
-0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02, 0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2,
-0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85, 0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05,
-0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x20, 0xF5,0x84, 0x7A,0x70, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
-0x37,0x6C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
-0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
-0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
-0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
-0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
-0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
-0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF4,0x86, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF4,0x85, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
-0x74,0x00, 0xE6,0x00, 0x35,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
-0x35,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
-0x00,0x10, 0xE6,0x00, 0x3B,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
-0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
-0x35,0x78, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x35,0x6C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
-0x35,0x7C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
-0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x02, 0xE6,0x00, 0x36,0xA8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC,
-0x0E,0xF4, 0x94,0x96, 0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
-0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
-0xFF,0xDC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
-0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x36,0x01, 0xF4,0x82,
-0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
-0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93,
-0xFF,0xFC, 0xF4,0x86, 0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
-0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38,
-0x60,0x00, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
-0xFF,0xDC, 0x96,0x16, 0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
-0xFF,0xFC, 0x86,0x16, 0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32,
-0x00,0x11, 0xE6,0x00, 0x36,0x60, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
-0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
-0x36,0xA8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
-0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x36,0xA9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
-0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x36,0xE5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
-0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x36,0xE4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xE6,0x00, 0x37,0x00, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
-0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
-0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
-0x3A,0xC1, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00,
-0x00,0x01, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
-0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF4,0x86,
-0x32,0x28, 0xF4,0x85, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
-0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x37,0xBD, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x3B,0x08, 0xC0,0x32,
-0x6A,0x00, 0xEE,0x00, 0x3B,0x09, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x38,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0x38,0x30, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x38,0x74, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x38,0x68, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x38,0x78, 0xF4,0x85,
-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
-0x39,0xA4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
-0xFF,0xE4, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xDC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x38,0xFD, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
-0x0F,0x00, 0xE0,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
-0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xE4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
-0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x96,0x16,
-0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
-0x39,0x5C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
-0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x39,0xA4, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x00, 0x39,0xA5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x39,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x39,0xE0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x39,0xFC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3A,0xC1, 0xF7,0x05,
-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0xB9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3A,0xAC, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3A,0x98, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
-0x77,0x00, 0xE0,0x00, 0x3A,0xB0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
-0x3A,0xC0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
-0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x3B,0x70, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3B,0x70, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
-0x3B,0x70, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xEE,0x00, 0x3B,0x29, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
-0x3B,0x30, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
-0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
-0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
-0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF5,0x04,
-0x7A,0x88, 0xF7,0x06, 0x7A,0x2C, 0xF5,0x84, 0x7A,0x90, 0x76,0xA9, 0x00,0x03, 0xA6,0xB6,
-0x70,0x02, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x3B,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x7A,0xA0, 0x00,0x00, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x3F,0x18, 0xC0,0x2E,
-0x6A,0x00, 0xEE,0x00, 0x3F,0x19, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0xF6,0x04,
-0x32,0xC8, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
-0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
-0x3C,0x3D, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x32,0xE0, 0xF6,0x85, 0x7A,0x70, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0x3C,0x40, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3C,0x84, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3C,0x78, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x3C,0x88, 0xF4,0x85,
-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
-0x3D,0xB4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
-0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xE4, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x3D,0x0D, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
-0x0F,0x00, 0xE0,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
-0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
-0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x96,0x16,
-0xFF,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xE0, 0x85,0x96, 0xFF,0xE4, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
-0x3D,0x6C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
-0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x3D,0xB4, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x00, 0x3D,0xB5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x3D,0xF1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x3D,0xF0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x3E,0x0C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3E,0xD1, 0xF7,0x05,
-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x3E,0x71, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x3E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3E,0xC9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3E,0xBC, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3E,0xA8, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
-0x77,0x00, 0xE0,0x00, 0x3E,0xC0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
-0x3E,0xD0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3E,0xD4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
-0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x3F,0x80, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0x80, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
-0x3F,0x80, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xEE,0x00, 0x3F,0x39, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
-0x3F,0x40, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
-0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
-0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
-0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF5,0x84,
-0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3F,0xE4, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0xD8, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xE0,0x00, 0x3F,0xE8, 0xF5,0x05,
-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
-0x41,0x14, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x05,0x2C, 0x0E,0xF4, 0x95,0x16,
-0xFF,0xF4, 0xF7,0x05, 0x7A,0x68, 0x95,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x40,0x6D, 0xF5,0x02, 0x00,0x4C, 0x87,0x2E,
-0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
-0x0F,0x00, 0xE0,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
-0x7A,0x28, 0x95,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
-0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x85,0x16, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
-0x50,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x96,0x16,
-0xFF,0xE8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xE8, 0x85,0x96, 0xFF,0xEC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
-0x40,0xCC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
-0x32,0xC0, 0xF5,0x06, 0xE0,0x30, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0x41,0x14, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x00, 0x41,0x15, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
-0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
-0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x41,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0A, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x41,0x50, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
-0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x41,0x6C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
-0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
-0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x42,0x31, 0xF7,0x05,
-0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x41,0xD1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x41,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x42,0x29, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
-0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x42,0x1C, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x08, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04,
-0x77,0x00, 0xE0,0x00, 0x42,0x20, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
-0x42,0x30, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x42,0x34, 0xF5,0x06, 0x31,0x9C, 0xF5,0x06,
-0x2E,0xE0, 0xF5,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x42,0x74, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
-0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x74, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
-0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x2F,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
-0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x43,0xD0, 0x00,0x00,
-0x00,0x01, 0x20,0x36, 0x00,0x10, 0xE2,0x00, 0x43,0xED, 0x07,0x34, 0x00,0x01, 0x87,0x2E,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x0C, 0x87,0x2E,
-0x00,0x0C, 0xE0,0x00, 0x44,0x14, 0xF4,0x02, 0x00,0x00, 0xC0,0x3A, 0x62,0x00, 0xE6,0x00,
-0x44,0x11, 0xF4,0x02, 0x00,0x00, 0x20,0x36, 0x00,0x10, 0xE6,0x00, 0x44,0x14, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x44,0x14, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
-0x00,0x01, 0xF7,0x05, 0x35,0x24, 0xF7,0x04, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x05,
-0x35,0x28, 0xF7,0x06, 0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
-0x45,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0D, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x02, 0x4A,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0F, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x4E,0xEC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
-0x00,0x08, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x57,0x64, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x02, 0x00,0x07, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
-0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x2D, 0xF6,0x86,
-0x75,0xF8, 0xE0,0x00, 0x45,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
-0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x5C, 0xF7,0x05, 0x35,0x48, 0xF4,0x86,
-0x33,0x80, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0x6F,0x54, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x80, 0xF4,0x82, 0x00,0x08, 0xF4,0x82,
-0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x45,0x88, 0xF7,0x02, 0x00,0x01, 0xF4,0x85,
-0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0xA0, 0xF4,0x82,
-0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF6,0x84,
-0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82,
-0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36,
-0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2,
-0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00,
-0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
-0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2,
-0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82,
-0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02,
-0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82,
-0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2,
-0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96,
-0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2,
-0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E,
-0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
-0x49,0xF0, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0xA4, 0x00,0x00,
-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0x95, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x49,0xF0, 0x00,0x00,
-0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
-0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
-0x47,0x08, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x46,0xFC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
-0x47,0x0C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
-0x47,0x71, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x47,0x69, 0xC6,0x38,
-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x0F, 0xE2,0x00, 0x47,0xBD, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
-0x47,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
-0x00,0x08, 0xE0,0x00, 0x49,0x68, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
-0x47,0xCC, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x48,0x1C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0x48,0x81, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86,
-0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x48,0x81, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x48,0x80, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x49,0x68, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x02, 0xE6,0x00, 0x49,0x3C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x49,0x11, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x47,0xA8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0x5C, 0x07,0x34, 0x14,0x94, 0xF4,0x84,
-0x6F,0x44, 0xE0,0x00, 0x49,0x60, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
-0x48,0x84, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x49,0xA1, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x49,0xA8, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00, 0x49,0xA8, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82,
-0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86,
-0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04,
-0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0x49,0xF1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
-0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x2D, 0xF6,0x86,
-0x75,0xF8, 0xE0,0x00, 0x4A,0x40, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
-0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04,
-0x6F,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x64, 0xF6,0x85,
-0x35,0x48, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x4A,0x70, 0xF7,0x02,
-0x00,0x01, 0xF4,0x82, 0x00,0x08, 0xF4,0x85, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x4A,0x88, 0xF4,0x82, 0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00,
-0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7,
-0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32,
-0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85,
-0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
-0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6,
-0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00,
-0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85,
-0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86,
-0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4,
-0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85,
-0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04,
-0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05,
-0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00,
-0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x4E,0xD8, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
-0x74,0x00, 0xE6,0x00, 0x4B,0x8C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
-0x4B,0x7D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
-0x00,0x10, 0xE6,0x00, 0x4E,0xD8, 0x00,0x00, 0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82,
-0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38,
-0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x4B,0xF0, 0xF7,0x05, 0x35,0x58, 0xF7,0x04,
-0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4B,0xE4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x4B,0xF4, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05,
-0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84,
-0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x4C,0x59, 0x00,0x00, 0x00,0x01, 0x86,0x36,
-0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
-0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4,
-0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38,
-0x00,0x24, 0xE6,0x00, 0x4C,0x51, 0xC6,0x38, 0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04,
-0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00, 0x4C,0xA5, 0x07,0x38,
-0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x4C,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x4E,0x50, 0xF7,0x05,
-0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x4C,0xB4, 0x00,0x00, 0x00,0x01, 0xF7,0x02,
-0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6,
-0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x4D,0x04, 0xF7,0x05, 0x76,0x04, 0xF0,0x05,
-0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36,
-0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF7,0x05,
-0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4D,0x68, 0xB4,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00,
-0x4E,0x50, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x4E,0x24, 0x05,0xB4,
-0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96,
-0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
-0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32,
-0x00,0x0F, 0xE2,0x00, 0x4D,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00,
-0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
-0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C,
-0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4C,0x90, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84,
-0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x4E,0x44, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00, 0x4E,0x48, 0xF4,0x85,
-0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x4D,0x6C, 0x05,0x28, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0x4E,0x89, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
-0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
-0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4E,0x90, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
-0x4E,0x90, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84,
-0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
-0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x4E,0xD9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
-0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0x82,
-0x00,0x04, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB,
-0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32,
-0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00,
-0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
-0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6,
-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00,
-0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04,
-0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2,
-0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32,
-0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05,
-0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38,
-0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
-0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32,
-0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x53,0x4C, 0xF7,0x06,
-0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x50,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x7E,
-0x74,0x00, 0xE6,0x00, 0x4F,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
-0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x53,0x4C, 0x00,0x00, 0x00,0x01, 0xFF,0x82,
-0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85,
-0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x50,0x64, 0xF7,0x05,
-0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x50,0x58, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x50,0x68, 0xF4,0x85,
-0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x50,0xCD, 0x00,0x00,
-0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4,
-0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16,
-0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E,
-0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x50,0xC5, 0xC6,0x38, 0x60,0x00, 0x06,0xB4,
-0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00,
-0x51,0x19, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x51,0x2C, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00,
-0x52,0xC4, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x51,0x28, 0x00,0x00,
-0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84,
-0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36,
-0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04,
-0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84,
-0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x51,0x78, 0xF7,0x05,
-0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05,
-0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0x51,0xDD, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A,
-0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0xDD, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x51,0xDC, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A,
-0x00,0x02, 0xEE,0x00, 0x52,0xC4, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
-0x52,0x98, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96,
-0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93,
-0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x52,0x6D, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36,
-0x00,0x14, 0xE0,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
-0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38,
-0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0x04, 0xF7,0x05,
-0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x52,0xB8, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00,
-0x52,0xBC, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x51,0xE0, 0x05,0x28,
-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x52,0xFD, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x53,0x04, 0xB4,0xBA,
-0x68,0x02, 0xE0,0x00, 0x53,0x04, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85,
-0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x53,0x4C, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
-0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x53,0x4D, 0x00,0x00,
-0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF4,0x84, 0x35,0x54, 0xF6,0x84,
-0x35,0x4C, 0xF5,0x84, 0x35,0x2C, 0x94,0x82, 0xFF,0x38, 0x76,0xB5, 0x00,0x03, 0xA5,0x2E,
-0x68,0x02, 0x00,0x00, 0x00,0x01, 0x95,0x02, 0xFF,0x3C, 0xF3,0x84, 0x35,0x50, 0xC6,0xAC,
-0x68,0x00, 0x93,0x82, 0xFF,0x40, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02,
-0xFF,0x44, 0x86,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x60,0x00, 0xF7,0x05, 0x35,0x40, 0xF6,0x04, 0x35,0x28, 0x86,0xB6, 0x00,0x04, 0x87,0x32,
-0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x97,0x32, 0x14,0x14, 0x87,0x2E,
-0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x57,0x50, 0x95,0x16,
-0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x54,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x53,0xF5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x57,0x50, 0x00,0x00,
-0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
-0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
-0x54,0x68, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x54,0x5C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82, 0x00,0x22, 0xE0,0x00,
-0x54,0x6C, 0xF3,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x84, 0x00,0x00, 0xC0,0x3A, 0x3A,0x00, 0xE6,0x00,
-0x54,0xD1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x54,0xC9, 0xC6,0x38,
-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x0F, 0xE2,0x00, 0x55,0x1D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
-0x55,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
-0x00,0x08, 0xE0,0x00, 0x56,0xC8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
-0x55,0x2C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x55,0x7C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0x55,0xE1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x86,
-0x72,0x18, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x55,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0E, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x55,0xE0, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x56,0xC8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x02, 0xE6,0x00, 0x56,0x9C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x56,0x71, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x55,0x08, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x56,0xBC, 0x07,0x34, 0x14,0x94, 0xF3,0x84,
-0x6F,0x44, 0xE0,0x00, 0x56,0xC0, 0xF3,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
-0x55,0xE4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x57,0x01, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x57,0x08, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x57,0x08, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82,
-0x00,0x01, 0xF3,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x86,
-0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x57,0x50, 0xF3,0x85, 0x35,0x30, 0xF7,0x04,
-0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0x57,0x51, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0x87,0x02,
-0xFF,0x38, 0xF3,0x84, 0x35,0x2C, 0xF7,0x05, 0x35,0x54, 0x87,0x1E, 0x00,0x80, 0xF5,0x04,
-0x35,0x4C, 0x27,0x38, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x5A,0x4C, 0x00,0x00,
-0x00,0x01, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
-0x57,0xD8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x57,0xCC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
-0x57,0xDC, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
-0x58,0x41, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x58,0x39, 0xC6,0x38,
-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x0F, 0xE2,0x00, 0x58,0x8D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
-0x58,0xA0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
-0x00,0x08, 0xE0,0x00, 0x5A,0x38, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
-0x58,0x9C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x58,0xEC, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0x59,0x51, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
-0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x59,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x59,0x50, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5A,0x38, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x02, 0xE6,0x00, 0x5A,0x0C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x59,0xE1, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x58,0x78, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5A,0x2C, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
-0x6F,0x44, 0xE0,0x00, 0x5A,0x30, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
-0x59,0x54, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xC4, 0xF3,0x02,
-0x00,0x01, 0xE0,0x00, 0x5D,0xF0, 0x00,0x00, 0x00,0x01, 0x77,0x29, 0x00,0x03, 0xC7,0x1C,
-0x70,0x00, 0x87,0x3A, 0x00,0x04, 0x05,0x28, 0x00,0x01, 0x76,0xA9, 0x00,0x03, 0xF4,0x84,
-0x35,0x54, 0xF6,0x04, 0x35,0x50, 0x94,0x82, 0xFF,0x38, 0xA4,0x1E, 0x68,0x02, 0xC6,0x30,
-0x70,0x00, 0x94,0x02, 0xFF,0x3C, 0x96,0x02, 0xFF,0x40, 0xC6,0x9C, 0x68,0x00, 0x87,0x36,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02, 0xFF,0x44, 0x85,0xB6, 0x00,0x04, 0xF7,0x04,
-0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x35,0x40, 0x85,0xB6,
-0x00,0x04, 0xF5,0x05, 0x35,0x4C, 0xF6,0x84, 0x35,0x28, 0xF6,0x05, 0x35,0x50, 0x87,0x36,
-0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x58,0x00, 0x97,0x36, 0x14,0x14, 0x87,0x1E,
-0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x5E,0x3C, 0x94,0x16,
-0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xF4, 0x00,0x00,
-0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
-0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x5E,0x3C, 0x00,0x00,
-0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
-0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
-0x5B,0x58, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x5B,0x4C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
-0x5B,0x5C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
-0x5B,0xC1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
-0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
-0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
-0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x5B,0xB9, 0xC6,0x38,
-0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
-0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x0F, 0xE2,0x00, 0x5C,0x0D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
-0x5C,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
-0x00,0x08, 0xE0,0x00, 0x5D,0xB8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
-0x5C,0x1C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
-0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
-0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
-0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
-0x5C,0x6C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
-0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0x5C,0xD1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
-0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x5C,0xD1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x5C,0xD0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
-0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5D,0xB8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
-0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x02, 0xE6,0x00, 0x5D,0x8C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
-0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
-0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x5D,0x61, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
-0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
-0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x5B,0xF8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5D,0xAC, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
-0x6F,0x44, 0xE0,0x00, 0x5D,0xB0, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
-0x5C,0xD4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xF1, 0xF3,0x02,
-0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x5D,0xF4, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x5D,0xF4, 0xF0,0x05, 0x2D,0x38, 0xF3,0x05,
-0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x06, 0x32,0xF4, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x5E,0x3C, 0xF3,0x05, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
-0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x5E,0x3D, 0x00,0x00,
-0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2, 0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00,
-0x5F,0x2C, 0xC5,0xB4, 0x00,0x00, 0x20,0x36, 0x00,0x0F, 0xEE,0x00, 0x5F,0x2C, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0x5F,0x2D, 0x00,0x00, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xEC,0x00, 0x5F,0x48, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32, 0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00,
-0x5F,0x50, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A, 0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
-0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x66,0xF8, 0x96,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
-0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
-0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x16, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x62,0x7C, 0x96,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
-0x66,0xF8, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
-0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x82, 0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x16, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
-0x62,0x7C, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
-0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x61,0x15, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0xE0,0x00, 0x61,0x18, 0x77,0x39,
-0x00,0x02, 0xF7,0x02, 0x00,0xF0, 0xF7,0x05, 0x42,0x28, 0xF7,0x06, 0x40,0x8A, 0xF0,0x3B,
-0x28,0x00, 0xF7,0x06, 0x40,0x8C, 0xF0,0x3B, 0x28,0x00, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
-0x7A,0xC0, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x05, 0x7A,0xB0, 0xF7,0x05, 0x7A,0xC8, 0xF6,0x82,
-0xC3,0x50, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x16, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
-0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04,
-0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x61,0xED, 0x76,0xB1,
-0x00,0x1E, 0x87,0x32, 0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00, 0x61,0xEC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
-0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0x61,0xEC, 0xF5,0x06, 0x35,0xEC, 0xF7,0x04,
-0x42,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x62,0x11, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06,
-0x42,0xA2, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x62,0x68, 0xF7,0x33, 0x28,0x00, 0x87,0x32,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0xE0,0x00, 0x86,0xB2, 0x00,0x08, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x62,0x3C, 0xF6,0x85, 0xE0,0x04, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
-0x62,0x40, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
-0x62,0x65, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x04, 0x42,0x3C, 0xF6,0x84, 0x6F,0x34, 0x07,0x38, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0x62,0xB1, 0xF7,0x05, 0x42,0x3C, 0x87,0x36, 0x00,0x00, 0xF5,0x9E,
-0x00,0x02, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x62,0xBD, 0xF5,0x86, 0x35,0xEC, 0xF7,0x04,
-0x42,0xA0, 0xE0,0x00, 0x62,0xDC, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x62,0xF9, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
-0x63,0x0C, 0xF7,0x33, 0x28,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x63,0x20, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x20, 0x83,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x87,0x1A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x63,0x6C, 0xF7,0x02, 0x00,0x00, 0x83,0x9A, 0x00,0x1C, 0x00,0x00, 0x00,0x01, 0xF3,0x85,
-0x7A,0xC0, 0x84,0x9A, 0x00,0x14, 0xF7,0x05, 0x7A,0xC8, 0xF4,0x85, 0x7A,0xB0, 0xF7,0x05,
-0x7A,0xB8, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x14, 0xF7,0x04,
-0x7A,0xB0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0xF6,0x02,
-0x00,0x00, 0x86,0x9A, 0x00,0x1C, 0xF7,0x04, 0x7A,0xC0, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x18, 0xF7,0x04,
-0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00,
-0x00,0x01, 0x86,0x9A, 0x00,0x20, 0xF7,0x04, 0x7A,0xC8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x20,0x3A, 0x00,0x64, 0xEE,0x00, 0x63,0xD9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x64,0x58, 0x00,0x00, 0x00,0x01, 0x83,0x96,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x64,0x3C, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0x40,0x80, 0xF7,0x05,
-0x40,0x84, 0xF6,0x84, 0x6E,0x50, 0xF4,0x82, 0xFF,0xFF, 0x83,0x1E, 0x00,0x0C, 0xF4,0x85,
-0x4F,0x54, 0x93,0x36, 0x00,0x10, 0x83,0x9E, 0x00,0x10, 0x84,0x96, 0x00,0x00, 0x93,0xB6,
-0x00,0x14, 0x84,0xA6, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x1D,0xDC, 0xF6,0x82,
-0x00,0x64, 0xF6,0x85, 0x4A,0x98, 0xF7,0x05, 0x4A,0x9C, 0x83,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00,
-0x64,0x7C, 0xF3,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA4, 0xF6,0x06, 0x42,0xA6, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0x66,0xE4, 0xF7,0x33, 0x28,0x00, 0x93,0x96, 0xFF,0xF4, 0x84,0x16,
-0x00,0x00, 0xF4,0x86, 0x42,0xC8, 0x94,0x96, 0xFF,0xEC, 0xF3,0x02, 0x00,0x0C, 0x93,0x16,
-0xFF,0xE4, 0x83,0x96, 0x00,0x00, 0x84,0x96, 0xFF,0xF4, 0x87,0x1E, 0x00,0x20, 0x00,0x00,
-0x00,0x01, 0xC0,0x26, 0x72,0x00, 0xEC,0x00, 0x66,0x48, 0xF3,0x86, 0x4A,0x98, 0x84,0xA2,
-0x00,0x24, 0x83,0x16, 0xFF,0xE4, 0xC5,0x04, 0x00,0x00, 0xB4,0x9A, 0x38,0x02, 0xC7,0x18,
-0x38,0x00, 0x83,0x22, 0x00,0x28, 0x83,0x96, 0xFF,0xF4, 0x84,0x96, 0xFF,0xE4, 0x93,0x3A,
-0x00,0x04, 0x93,0xBA, 0x00,0x08, 0xF6,0x04, 0xE0,0x00, 0xF3,0x06, 0x4A,0x98, 0xA6,0xA6,
-0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x32, 0x6A,0x00, 0xE6,0x00, 0x65,0x10, 0xC6,0x38,
-0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x65,0x14, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0x65,0x21, 0x00,0x00, 0x00,0x01, 0xF5,0x02, 0x00,0x00, 0xF6,0x84,
-0xE0,0x00, 0x87,0x32, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0x65,0x5C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x65,0x64, 0x20,0x2E,
-0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0x65,0x65, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0x65,0x75, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
-0x00,0x00, 0xE6,0x00, 0x65,0x88, 0x00,0x00, 0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0x00,0x00,
-0x00,0x01, 0xF3,0x85, 0x4F,0x54, 0x87,0x22, 0x00,0x2C, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x05,0xA0, 0x00,0x2E, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xF4,0x82,
-0x00,0x00, 0x94,0x96, 0xFF,0xDC, 0x83,0x16, 0xFF,0xEC, 0x20,0x26, 0x00,0x07, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0x98,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE2,0x00, 0x66,0x1C, 0xF7,0x37,
-0x28,0x00, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0xC7,0x2C,
-0x40,0x00, 0x86,0xBA, 0x00,0x30, 0x06,0x28, 0x00,0x04, 0x05,0x28, 0x00,0x02, 0x05,0xAC,
-0x00,0x02, 0x83,0x96, 0xFF,0xDC, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x03,0x9C,
-0x00,0x01, 0x93,0x96, 0xFF,0xDC, 0x20,0x1E, 0x00,0x07, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
-0xFF,0xF0, 0xE2,0x00, 0x65,0xE1, 0xF6,0xB3, 0x28,0x00, 0x04,0x20, 0x00,0x1C, 0x84,0x96,
-0xFF,0xEC, 0x83,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xF4, 0x04,0xA4, 0x00,0x14, 0x94,0x96,
-0xFF,0xEC, 0x03,0x18, 0x00,0x0C, 0x93,0x16, 0xFF,0xE4, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
-0x64,0x94, 0x93,0x96, 0xFF,0xF4, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x26,
-0x00,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x4A,0x9C, 0x85,0xA6, 0x00,0x20, 0xF7,0x04,
-0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x04,
-0x7A,0xB8, 0xF6,0x84, 0x7A,0xC8, 0x86,0x26, 0x00,0x18, 0xC6,0xB4, 0x58,0x00, 0x87,0x26,
-0x00,0x1C, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0x47,0x0C,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x66,0xE5, 0xF6,0x85, 0x7A,0xC8, 0x83,0x26,
-0x00,0x08, 0xF7,0x04, 0x6E,0x50, 0xF3,0x05, 0x3B,0x64, 0x83,0xA6, 0x00,0x08, 0xF6,0x82,
-0x00,0x00, 0x93,0xBA, 0x1D,0xDC, 0x84,0xA6, 0x00,0x0C, 0x83,0x16, 0x00,0x00, 0x94,0xBA,
-0x00,0x10, 0x83,0x1A, 0x00,0x10, 0xF6,0x85, 0x7A,0xC8, 0x93,0x3A, 0x00,0x14, 0xF7,0x02,
-0x00,0x01, 0xF7,0x05, 0x40,0x84, 0xF6,0x85, 0x7A,0xC0, 0xF6,0x85, 0x7A,0xB8, 0xF6,0x85,
-0x7A,0xB0, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x08, 0xF3,0x84, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0xF6,0x84,
-0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x67,0x29, 0xF7,0x02,
-0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE8, 0xF5,0x82,
-0x00,0x01, 0xF7,0x04, 0xE0,0x1C, 0x86,0x9E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE9, 0xC5,0x84,
-0x00,0x00, 0x86,0x9E, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x67,0x88, 0x05,0x1C, 0x00,0x10, 0x86,0x9E, 0x00,0x14, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x67,0x8C, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0x99, 0x00,0x00,
-0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xAA, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xD4, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x67,0xDC, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xDD, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0xED, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x68,0x10, 0xF6,0x06,
-0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
-0x75,0xF4, 0x75,0xAC, 0xFF,0xE1, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x68,0x45, 0x95,0x96,
-0xFF,0xF4, 0xF7,0x04, 0x42,0x98, 0xF6,0x06, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x04,0x1C, 0x00,0x20, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00,
-0x68,0xC4, 0xF3,0x06, 0x15,0x54, 0xF5,0x02, 0x00,0x00, 0x05,0x9C, 0x00,0x22, 0xC4,0xAC,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00,
-0x68,0xC0, 0xC6,0xA4, 0x60,0x00, 0xA7,0x26, 0x60,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x05,0x28, 0x00,0x01, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xE8, 0xF7,0x2F,
-0x68,0x00, 0x05,0xAC, 0x00,0x01, 0xE0,0x00, 0x68,0x78, 0x06,0x30, 0x00,0x02, 0xF3,0x06,
-0x15,0x54, 0x93,0x13, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
-0xE0,0x00, 0x93,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x02, 0x00,0x01, 0x93,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x69,0x28, 0xF6,0x06, 0x42,0x9E, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
-0x00,0x00, 0xE6,0x00, 0x69,0x6C, 0xF3,0x06, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x69,0x6D, 0xF0,0x05, 0x42,0x28, 0xF3,0x06, 0x35,0x60, 0xF3,0x05, 0x42,0x30, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x04, 0x6F,0x34, 0xF7,0x04,
-0x42,0x40, 0x86,0x2A, 0x00,0x18, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0xE0,0x1C, 0xF7,0x05,
-0x42,0x40, 0xC0,0x36, 0x62,0x00, 0xEC,0x00, 0x69,0xB5, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x80, 0xF7,0x02, 0x00,0x01, 0xF7,0x04,
-0xE0,0x1C, 0x86,0xAA, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x7D, 0xC5,0x84, 0x00,0x00, 0x86,0xAA,
-0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x6A,0x14, 0x04,0xA8, 0x00,0x10, 0x86,0xAA, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x6A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x25, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
-0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0x6A,0x60, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x6A,0x68, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x6A,0x69, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x81, 0xC7,0x2C, 0x00,0x00, 0xF5,0x82,
-0x00,0x01, 0xE0,0x00, 0x6A,0x80, 0xC7,0x2C, 0x00,0x00, 0xC7,0x04, 0x00,0x00, 0x20,0x3A,
-0x00,0x00, 0xEE,0x00, 0x6B,0x3D, 0xF6,0x86, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x6B,0x3C, 0xF6,0x82, 0x00,0x00, 0xF6,0x85, 0x40,0x80, 0xF6,0x85,
-0x40,0x84, 0x96,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00,
-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x86, 0xE0,0x00, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
-0xFF,0xFC, 0xF3,0x82, 0x00,0x02, 0x93,0x93, 0xFF,0xFC, 0x96,0x96, 0xFF,0xF4, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0x86,0x96,
-0xFF,0xF4, 0xF7,0x04, 0x6E,0x50, 0xF3,0x86, 0x35,0xEC, 0xF6,0x85, 0x40,0x90, 0xF6,0x85,
-0x40,0x94, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x85, 0x42,0x28, 0xF7,0x05, 0x3B,0x64, 0xF7,0x04,
-0x42,0x30, 0xF4,0x05, 0x40,0x80, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x6B,0x3D, 0xF3,0x86, 0x35,0x60, 0xF3,0x85, 0x42,0x30, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x6D,0xD9, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x40,0x8C, 0xF6,0x06, 0x40,0x8C, 0x76,0x31,
-0x00,0x1E, 0xF6,0x84, 0x42,0x28, 0x76,0x30, 0xFF,0xE5, 0x06,0xB4, 0x00,0x01, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6B,0xC8, 0xF6,0x85,
-0x42,0x28, 0xF7,0x04, 0x40,0x88, 0xF6,0x86, 0x40,0x8A, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x6D,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x6C,0x35, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x6C,0x34, 0xF4,0x86, 0x36,0x78, 0xF7,0x04, 0x42,0x44, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x6C,0x35, 0xF4,0x82, 0x00,0x01, 0xF4,0xB3, 0x28,0x00, 0xE0,0x00, 0x6D,0x10, 0xF0,0x05,
-0x42,0x2C, 0xF7,0x04, 0x40,0x8C, 0xF5,0x06, 0x40,0x8C, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x6C,0xC1, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x6C,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x2C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x20,0x3A, 0x00,0x09, 0xEE,0x00, 0x6D,0x11, 0xF7,0x05, 0x42,0x2C, 0xF0,0x2B,
-0x28,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0xF6,0x06,
-0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x6D,0x10, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
-0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6D,0x14, 0x20,0x2E,
-0x00,0x00, 0xF7,0x04, 0x40,0x88, 0xF6,0x06, 0x40,0x8A, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x6D,0x15, 0x20,0x2E, 0x00,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0x6D,0xB5, 0xF4,0x86, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x6D,0x59, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0x3C, 0xF6,0x84, 0xE0,0x28, 0xE0,0x00,
-0x6D,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0xF0, 0xF7,0x04, 0xE0,0x28, 0x00,0x00,
-0x00,0x01, 0x76,0xB9, 0x00,0x02, 0xF7,0x04, 0x42,0x28, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x6A,0x00, 0xEC,0x00, 0x6D,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05,
-0x42,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
-0x00,0x19, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x6D,0xB4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF4,0x82, 0xC3,0x50, 0x94,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x16, 0x94,0x93,
-0xFF,0xFC, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86,
-0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x82, 0x74,0x18, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x19, 0x95,0x93,
-0xFF,0xFC, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x74,0xAC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x78,0x00, 0x95,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
-0x78,0xFC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
-0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x82, 0x80,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x86, 0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x81,0x74, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x87,0x74, 0x95,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
-0x94,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
-0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x82, 0x8A,0x00, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x8E,0x08, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x96,0x9C, 0x95,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0xA8, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
-0x9B,0x2C, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
-0x38,0xA8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x82, 0xA2,0xDC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x9E,0x54, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xA3,0xC0, 0x95,0x93,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
-0xA7,0x64, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
-0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x82, 0xAA,0x04, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xAE,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0x4C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x50, 0xF0,0x3B,
-0x28,0x00, 0xF7,0x06, 0x40,0x88, 0xF0,0x3B, 0x28,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x05,
-0x40,0x80, 0xF6,0x05, 0x40,0x84, 0xF7,0x06, 0x3B,0x70, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06,
-0x3B,0x72, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xCA,0x20, 0xF5,0x85, 0x3B,0x74, 0xF7,0x06,
-0x3B,0x78, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x7A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
-0xB1,0x94, 0xF5,0x85, 0x3B,0x7C, 0xF7,0x06, 0x3B,0x80, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
-0x3B,0x82, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x54, 0xF5,0x85, 0x3B,0x84, 0xF7,0x06,
-0x3B,0x88, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x8A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
-0xBE,0xF8, 0xF5,0x85, 0x3B,0x8C, 0xF7,0x06, 0x3B,0x90, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
-0x3B,0x92, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC8,0xF8, 0xF5,0x85, 0x3B,0x94, 0xF7,0x06,
-0x3B,0x98, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x9A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
-0xC5,0xD8, 0xF5,0x85, 0x3B,0x9C, 0xF7,0x06, 0x3B,0xA0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
-0x3B,0xA2, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x70, 0xF5,0x85, 0x3B,0xA4, 0xF7,0x06,
-0x3B,0xA8, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0xAA, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
-0xC1,0xB4, 0xF5,0x85, 0x3B,0xAC, 0x96,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD5,0x40, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
-0x00,0x01, 0x96,0x36, 0x1D,0xDC, 0xF6,0x05, 0x3B,0x64, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
-0x28,0x00, 0x26,0x14, 0x00,0x38, 0xF0,0x33, 0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04,
-0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x72,0x1D, 0xF5,0x02, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02,
-0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x04, 0x86,0x16, 0x00,0x00, 0xF6,0x82,
-0x00,0xFF, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x6C,0x00, 0xF7,0x33, 0x28,0x00, 0xF7,0x06,
-0xE0,0x06, 0x87,0x3A, 0x00,0x00, 0x06,0xB0, 0x00,0x02, 0xF7,0x37, 0x28,0x00, 0xF6,0x84,
-0x3B,0x64, 0x07,0x30, 0x00,0x04, 0xF6,0xBB, 0x28,0x00, 0x87,0x02, 0xFF,0x34, 0x06,0x30,
-0x00,0x06, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x30, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x27,0x14,
-0x00,0x38, 0xF0,0x3B, 0x28,0x00, 0x97,0x13, 0xFF,0xFC, 0x90,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x73,0x19, 0xF5,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
-0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x1B, 0x95,0x93,
-0xFF,0xFC, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x40, 0x26,0x14, 0x00,0x20, 0x96,0x16, 0xFF,0xC4, 0xF0,0x33,
-0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x96,0x16,
-0xFF,0xBC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
-0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13,
-0xFF,0xFC, 0x86,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x73,0xE5, 0xF6,0x02,
-0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05,
-0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0xF6,0x02, 0x00,0x1B, 0x96,0x13, 0xFF,0xFC, 0xF6,0x06,
-0x42,0x44, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x04, 0xF5,0x82, 0x00,0x00, 0xF5,0x85, 0x40,0x80, 0x95,0x96, 0xFF,0xF4, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCB,0x50, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0xF5,0x02,
-0x00,0x64, 0xF5,0x05, 0x3B,0xB4, 0xF7,0x04, 0x42,0x50, 0xF4,0x86, 0x42,0x50, 0x76,0xA5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x4F,0x5C, 0xF4,0x02, 0x00,0x06, 0xF4,0x05,
-0x42,0x54, 0xF5,0x85, 0x3B,0x6C, 0xF5,0x85, 0x3B,0xB8, 0x95,0x32, 0x00,0x00, 0x95,0xB2,
-0x00,0x04, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x27,
-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x06,
-0x37,0x04, 0xF4,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2,
-0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x77,0xEC, 0xC5,0x04,
-0x00,0x00, 0x86,0xB2, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF3,0x02, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x75,0x18, 0x04,0xB0, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x75,0x1C, 0x20,0x1A,
-0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x75,0x29, 0x00,0x00,
-0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x64, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x75,0x6C, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x6D, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x75,0x7D, 0x20,0x2A,
-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x77,0xEC, 0x00,0x00,
-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14,
-0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0, 0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF5,0x82,
-0x00,0x00, 0x23,0x94, 0x00,0x22, 0xF5,0x9F, 0x28,0x00, 0x03,0xA0, 0x00,0x1A, 0x93,0x96,
-0xFF,0xD4, 0x25,0x94, 0x00,0x22, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x15, 0x00,0x1E, 0xF5,0x9F,
-0x28,0x00, 0xF3,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0xA2, 0x00,0x1C, 0xF5,0x84,
-0xE0,0x04, 0x73,0x99, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xCC, 0x23,0x94, 0x00,0x42, 0x95,0xA2,
-0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96,
-0xFF,0xB4, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96, 0xFF,0xC4, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A,
-0x00,0x00, 0xC4,0xA0, 0x4A,0x00, 0x74,0xA4, 0xFF,0xFA, 0xC5,0xA4, 0x00,0x00, 0xF5,0x9F,
-0x28,0x00, 0x83,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x85,0x96, 0xFF,0xB4, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xCC, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x96, 0xFF,0xC4, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82,
-0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x04,0x20, 0x00,0x18, 0x25,0x94, 0x00,0x22, 0x85,0xAE,
-0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD,
-0xFF,0xF0, 0x83,0x96, 0xFF,0xD4, 0xF5,0xA3, 0x28,0x00, 0xF4,0x9F, 0x28,0x00, 0x25,0x94,
-0x00,0x42, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC,
-0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x44,0xAD, 0x00,0x00, 0x94,0x93, 0xFF,0xFC, 0xF7,0x86,
-0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x40,0x84, 0xF7,0x86,
-0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x04, 0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x87,0x3A, 0x1D,0xDC, 0x00,0x00,
-0x00,0x01, 0xF7,0x05, 0x3B,0x64, 0xF5,0x86, 0x36,0x78, 0xF5,0x85, 0x42,0x44, 0xF3,0x86,
-0x35,0x60, 0xF3,0x85, 0x42,0x30, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x78,0x89, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xEE,0x00, 0x78,0x51, 0xF6,0x06, 0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x78,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85,
-0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
-0x37,0x90, 0xF5,0x85, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF6,0x06, 0x36,0x78, 0xF6,0x05, 0x42,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
-0x40,0x80, 0xF7,0x05, 0x40,0x94, 0xF6,0x84, 0x6E,0x50, 0xF7,0x05, 0x40,0x90, 0x97,0x36,
-0x1D,0xDC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
-0x00,0x01, 0xF7,0x05, 0x40,0x80, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0xA8, 0xF7,0x04, 0x42,0x50, 0xF5,0x86, 0x42,0x50, 0x76,0xAD,
-0x00,0x1E, 0xF4,0x84, 0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xC4, 0xC7,0x38,
-0x6F,0xC0, 0x86,0xA6, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x79,0x55, 0xF6,0x06, 0x42,0x9A, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0xF7,0x04, 0x42,0x50, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16,
-0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0xAA, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x80,0xA8, 0xF6,0x06, 0x42,0x9A, 0x87,0x2A, 0x00,0x10, 0x86,0x2A,
-0x00,0x1C, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xA8, 0xF6,0x82, 0x00,0x00, 0x87,0x2A,
-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xAC, 0x20,0x36,
-0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x7A,0x05, 0x24,0x94,
-0x00,0x20, 0x94,0x96, 0xFF,0xBC, 0x85,0x16, 0xFF,0xC4, 0xF0,0x27, 0x28,0x00, 0x05,0x28,
-0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x94,0x93,
-0xFF,0xFC, 0x85,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x80,0xC4, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x80,0x6C, 0x00,0x00, 0x00,0x01, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
-0x28,0x00, 0x04,0xA0, 0x00,0x02, 0x94,0x96, 0xFF,0x5C, 0xF0,0x27, 0x28,0x00, 0xF4,0x82,
-0x00,0x00, 0x25,0x14, 0x00,0x5A, 0xF4,0xAB, 0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x25,0x14,
-0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28,
-0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x23,0x14,
-0x00,0x1E, 0x76,0x19, 0x00,0x1E, 0xF5,0x3B, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x76,0x30,
-0xFF,0xE5, 0x94,0xA2, 0x00,0x1C, 0xF5,0x04, 0xE0,0x04, 0x84,0x96, 0xFF,0x5C, 0x95,0x22,
-0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
-0xFF,0x9C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x74,0x95,
-0x00,0x1E, 0x85,0x16, 0xFF,0x5C, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x8C, 0x84,0x96,
-0xFF,0x54, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x94, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
-0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF5,0x3B,
-0x28,0x00, 0x94,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
-0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x24,0x94, 0x00,0x5A, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x05,0xA0,
-0x00,0x02, 0x06,0xAC, 0x00,0x02, 0x23,0x94, 0x00,0x36, 0x75,0x1D, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x07,0x20, 0x00,0x1A, 0xF4,0xB3, 0x28,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
-0xFF,0x5C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x74,0x95,
-0x00,0x1E, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x74, 0x85,0x2A,
-0x00,0x34, 0x24,0x94, 0x00,0x5A, 0x95,0x16, 0xFF,0x84, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x25,0x14,
-0x00,0x5A, 0xF4,0xAF, 0x28,0x00, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
-0x28,0x00, 0x84,0xA6, 0x00,0x10, 0x85,0x16, 0xFF,0xC4, 0x94,0xA2, 0x00,0x1C, 0x85,0x2A,
-0x00,0x14, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x6C, 0x95,0x22,
-0x00,0x20, 0x87,0x16, 0xFF,0xC8, 0x85,0x16, 0xFF,0x54, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x84,0x96, 0xFF,0x5C, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0xCC, 0x23,0x94, 0x00,0x32, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x85,0x16,
-0xFF,0x7C, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD0, 0x23,0x94, 0x00,0x2E, 0x76,0x1D,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x74, 0x85,0x16,
-0xFF,0x6C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x23,0x94, 0x00,0x2A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x16, 0xFF,0xD8, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3, 0x28,0x00, 0x07,0x20,
-0x00,0x18, 0x25,0x14, 0x00,0x7A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
-0x28,0x00, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xF7,0x04,
-0x4F,0x58, 0xE6,0x00, 0x7E,0xF9, 0x94,0x16, 0xFF,0x54, 0xC7,0x20, 0x72,0x00, 0xF6,0x84,
-0x6E,0x50, 0x86,0x26, 0x00,0x2C, 0x77,0x38, 0xFF,0xFA, 0x25,0x14, 0x00,0x5A, 0x84,0x2A,
-0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0x20, 0x7F,0xC0, 0x74,0x21,
-0xFF,0xF0, 0x47,0x39, 0x00,0x00, 0x86,0xB6, 0x1D,0xDC, 0x77,0x39, 0x00,0x02, 0xC0,0x32,
-0x6A,0x00, 0x46,0x8C, 0x00,0x01, 0xD6,0x80, 0x0A,0x68, 0x20,0x36, 0x00,0x00, 0xF6,0x86,
-0x40,0x98, 0xE6,0x00, 0x7E,0xC0, 0xC3,0xB8, 0x68,0x00, 0xC5,0x84, 0x00,0x00, 0x86,0xA6,
-0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x7E,0x54, 0x03,0x24, 0x00,0x24, 0x86,0xA6, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x7E,0x58, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0x65, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
-0x00,0x00, 0x86,0x9A, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0x7E,0xA0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x7E,0xA8, 0x20,0x32, 0x00,0x00, 0x86,0x9A, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x7E,0xA9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0xB9, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x7E,0xC5, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
-0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x1F, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0x85,0x16,
-0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x2A,
-0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
-0x7F,0x4C, 0xF6,0x3B, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0xF6,0x06, 0x40,0x98, 0xC7,0x24,
-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0xB8, 0x00,0x00, 0x46,0xB5, 0x00,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x37, 0x28,0x00, 0x47,0x39,
-0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x24,0x94, 0x00,0x5A, 0x84,0xA6,
-0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5,
-0xFF,0xF0, 0x07,0x38, 0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x85,0x16,
-0xFF,0x54, 0x84,0x96, 0xFF,0xAC, 0xC6,0xA8, 0x72,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x24,
-0x00,0x1A, 0xF6,0xB3, 0x28,0x00, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x06,0xA8,
-0x00,0x1A, 0xF7,0x37, 0x28,0x00, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24,
-0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x72,0x00, 0x77,0x38,
-0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x1C, 0x97,0x13,
-0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x1D,0xDC, 0x87,0x36,
-0x1D,0xDC, 0xF0,0x05, 0x40,0x84, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0xF7,0x04,
-0x6E,0x50, 0xF0,0x05, 0x42,0x5C, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x86, 0x2C,0x28, 0xF7,0x05,
-0x3B,0x64, 0xF7,0x04, 0x2D,0x38, 0xF5,0x06, 0x3A,0x4C, 0xF5,0x05, 0x42,0x44, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x1C, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x80,0x60, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06,
-0x35,0xEC, 0xE0,0x00, 0x80,0x8C, 0xF5,0x05, 0x42,0x30, 0x20,0x32, 0x00,0x01, 0xE6,0x00,
-0x80,0xC4, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
-0xFF,0xFC, 0xF4,0x86, 0x35,0x60, 0xF4,0x85, 0x42,0x30, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0x80,0xC4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86,
-0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x81,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x81,0x29, 0xF6,0x06,
-0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0x81,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85, 0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0xF5,0x85, 0x42,0x44, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x58, 0xF7,0x04,
-0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04,
-0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x82,0x50, 0xF4,0x82, 0x00,0x00, 0xC5,0x04, 0x00,0x00, 0x86,0xB2,
-0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xC5,0xA4, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x81,0xE4, 0x04,0x30, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x81,0xE8, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x81,0xF5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
-0x00,0x00, 0x86,0xA2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0x82,0x30, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0x82,0x38, 0x20,0x32, 0x00,0x00, 0x86,0xA2, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x82,0x39, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x82,0x49, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
-0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x82,0x59, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
-0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x87,0x60, 0x00,0x00, 0x00,0x01, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
-0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x05, 0x3B,0xB0, 0x06,0xA0, 0x00,0x14, 0xC7,0x20,
-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x16, 0xF7,0x37,
-0x28,0x00, 0xF3,0x02, 0x00,0x01, 0xF3,0x23, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0,
-0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF3,0x02, 0x00,0x00, 0x23,0x94, 0x00,0x2A, 0xF3,0x1F,
-0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0xF3,0xBB,
-0x28,0x00, 0xF3,0x04, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0x22, 0x00,0x1C, 0xF3,0x84,
-0xE0,0x04, 0x23,0x14, 0x00,0x1E, 0x93,0x16, 0xFF,0xA4, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
-0xFF,0xA4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
-0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96,
-0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x94, 0x00,0x1A, 0x93,0x96, 0xFF,0xA4, 0x76,0x1D,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
-0x00,0x16, 0x93,0x16, 0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xAC, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x93,0x16,
-0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xCC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16,
-0xFF,0xF0, 0x83,0x16, 0xFF,0xC4, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82, 0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x23,0x14,
-0x00,0x2A, 0x83,0x1A, 0x00,0x00, 0x77,0x99, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18,
-0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF3,0x3B, 0x28,0x00, 0x94,0x16,
-0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20,
-0x00,0x02, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x24,0x80, 0x00,0x07, 0x05,0x20,
-0x00,0x0A, 0xF3,0xBB, 0x28,0x00, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x84,0xE0, 0x06,0x28,
-0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1,
-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4, 0x00,0x01, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3,
-0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0xC7,0x38, 0x34,0x00, 0xE0,0x00, 0x84,0x88, 0xF7,0x33, 0x28,0x00, 0x05,0x20,
-0x00,0x26, 0x86,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0xF5,0x84, 0x4F,0x58, 0x76,0xB4,
-0xFF,0xE5, 0x83,0x96, 0xFF,0xDC, 0xF3,0x02, 0x00,0xFF, 0x94,0x16, 0xFF,0xBC, 0xC7,0x1C,
-0x5A,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
-0x00,0x00, 0xC7,0x38, 0x34,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30, 0x6C,0x00, 0xC7,0x38,
-0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2B, 0x28,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
-0xFF,0xFA, 0x83,0x16, 0xFF,0xDC, 0x07,0x34, 0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x20,
-0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x20, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x82,
-0x00,0x03, 0xF3,0xA3, 0x28,0x00, 0x07,0x18, 0x00,0x1A, 0xF5,0xBB, 0x28,0x00, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
-0x28,0x00, 0x24,0x80, 0x00,0x07, 0x05,0x20, 0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00,
-0x85,0xD4, 0x06,0x28, 0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4,
-0x00,0x01, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
-0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x82, 0x00,0xFF, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xE0,0x00, 0x85,0x7C, 0xF7,0x33,
-0x28,0x00, 0x05,0xA0, 0x00,0x26, 0x86,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC5,0x20, 0x00,0x00, 0x24,0x00, 0x00,0x07, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
-0xFF,0xA4, 0xF7,0x04, 0x4F,0x58, 0x83,0x96, 0xFF,0xBC, 0x24,0x80, 0x00,0x0E, 0xC7,0x1C,
-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
-0x00,0x00, 0xF6,0x82, 0x00,0xFF, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30,
-0x6C,0x00, 0xC7,0x38, 0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2F, 0x28,0x00, 0x07,0x34,
-0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x28, 0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x28,
-0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x02, 0x00,0x03, 0xF3,0x2B, 0x28,0x00, 0x20,0x22,
-0x00,0x07, 0xEE,0x00, 0x86,0x94, 0xC6,0x28, 0x48,0x00, 0x06,0x30, 0x00,0x26, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x04,0x20,
-0x00,0x01, 0x83,0x96, 0xFF,0xA4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82,
-0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC7,0x1C, 0x70,0x00, 0xE0,0x00, 0x86,0x50, 0xF7,0x33,
-0x28,0x00, 0x06,0x28, 0x00,0x26, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
-0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0xF3,0x04, 0x3B,0xB0, 0x00,0x00,
-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xB4, 0xF0,0x05, 0x40,0x7C, 0x83,0x96,
-0xFF,0xBC, 0x23,0x00, 0x00,0x07, 0xF3,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x50, 0xF6,0x06,
-0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x39,0x34, 0xF3,0x05,
-0x42,0x44, 0xF5,0x05, 0x40,0x74, 0xF3,0x85, 0x42,0x60, 0xF3,0x82, 0x00,0x06, 0xF3,0x85,
-0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06,
-0x2C,0x28, 0x76,0xB5, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0x87,0x4C, 0xB3,0xB6, 0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x06, 0x42,0x44, 0x93,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x48, 0xF3,0x86,
-0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x89,0xED, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x87,0xC9, 0x00,0x00,
-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0x89,0xEC, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
-0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x05,0xA0, 0x00,0x02, 0xF0,0x2F,
-0x28,0x00, 0xF3,0x82, 0x00,0x00, 0x24,0x94, 0x00,0x22, 0xF3,0xA7, 0x28,0x00, 0x04,0xA0,
-0x00,0x1A, 0x94,0x96, 0xFF,0xD4, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xAC, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x19,
-0x00,0x1E, 0xF3,0xA7, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x94,0xA2,
-0x00,0x1C, 0xF3,0x84, 0xE0,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
-0xFF,0xB4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xCC, 0x84,0x96,
-0xFF,0xB4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
-0xFF,0xE5, 0x93,0x96, 0xFF,0xBC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
-0xFF,0xC4, 0x83,0x96, 0xFF,0xBC, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F,
-0x28,0x00, 0xF5,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
-0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x45,0xAD, 0x00,0x00, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0xCC, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
-0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
-0x28,0x00, 0x04,0x20, 0x00,0x18, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x84,0x96,
-0xFF,0xD4, 0xF3,0xA3, 0x28,0x00, 0xF3,0x82, 0x00,0x01, 0xF3,0xA7, 0x28,0x00, 0x95,0x93,
-0xFF,0xFC, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x86,
-0x36,0x78, 0xF4,0x85, 0x42,0x44, 0xF0,0x05, 0x40,0x84, 0xF6,0x84, 0x4F,0x5C, 0xF7,0x02,
-0x00,0x64, 0x97,0x36, 0x00,0x00, 0x90,0x36, 0x00,0x04, 0xF7,0x02, 0x00,0x01, 0xF7,0x05,
-0x40,0x84, 0xF3,0x86, 0x35,0xEC, 0xF3,0x85, 0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF7,0x04, 0x42,0x60, 0xF5,0x02,
-0x00,0x00, 0x05,0xB8, 0x00,0x18, 0xF6,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x32,
-0x00,0x07, 0xEE,0x00, 0x8A,0x70, 0xC7,0x30, 0x60,0x00, 0xC7,0x38, 0x58,0x00, 0x07,0x38,
-0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0xC0,0x36,
-0x52,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x8A,0x71, 0x07,0x30, 0x00,0x01, 0xE0,0x00, 0x8A,0x18, 0xF7,0x05, 0x42,0x58, 0xF4,0x04,
-0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x07, 0xEE,0x00, 0x8D,0x94, 0x24,0x94,
-0x00,0x36, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x38, 0x23,0x94, 0x00,0x20, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
-0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
-0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0x7C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x7E, 0x25,0x14, 0x00,0x80, 0x23,0x94,
-0x00,0x68, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7C, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7A, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x78, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x76, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x74, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x72, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0x74, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x42,0x58, 0x23,0x94, 0x00,0x50, 0xC7,0x00, 0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0x6C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFF,0x6C, 0xF6,0x86, 0x42,0x50, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
-0x42,0x58, 0x76,0xB5, 0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96,
-0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x8D,0x95, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00,
-0x8D,0xD4, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0x8D,0xF4, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x8D,0xF4, 0xF0,0x05,
-0x2D,0x38, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86,
-0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x88, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0xF3,0x84,
-0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x93,0x96, 0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0x9E,
-0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x8E,0x65, 0xF6,0x06,
-0x42,0xA0, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x94,0xE4, 0xF7,0x33,
-0x28,0x00, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x36, 0x85,0x16, 0xFF,0xC4, 0x23,0x94,
-0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x85,0x2A, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x95,0x16, 0xFF,0xBC, 0xF7,0x1F, 0x28,0x00, 0x87,0x32,
-0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x85,0x16, 0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
-0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14, 0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00,
-0x00,0x01, 0x87,0x1E, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0x8F,0xF0, 0xF6,0x82, 0x00,0x00, 0x87,0x1E, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0x8F,0xF4, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0x90,0x41, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xC4, 0x00,0x00,
-0x00,0x01, 0x05,0x28, 0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x27,0x14,
-0x00,0x20, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16,
-0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x94,0xBC, 0x00,0x00,
-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x02,
-0x00,0x00, 0x23,0x94, 0x00,0x62, 0xF5,0x1F, 0x28,0x00, 0x75,0x95, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0x06,0x20, 0x00,0x02, 0x06,0xB0, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x73,0x99,
-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x74, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
-0xFF,0x8C, 0x85,0x16, 0xFF,0xC4, 0x73,0x95, 0x00,0x1E, 0x93,0x96, 0xFF,0x84, 0x85,0x2A,
-0x00,0x34, 0x23,0x94, 0x00,0x62, 0x95,0x16, 0xFF,0xAC, 0xF0,0x33, 0x28,0x00, 0x05,0x20,
-0x00,0x1A, 0x95,0x16, 0xFF,0x94, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x74,0x95, 0x00,0x1E, 0xF3,0xAB,
-0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x85,0x2A, 0x00,0x10, 0x83,0x96,
-0xFF,0xC4, 0x95,0x22, 0x00,0x1C, 0x83,0x9E, 0x00,0x14, 0x85,0x16, 0xFF,0x84, 0x93,0xA2,
-0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x84, 0xF3,0x84,
-0x4F,0x58, 0x85,0x16, 0xFF,0x74, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96, 0xFF,0xA4, 0xC0,0x22, 0x3A,0x00, 0x83,0x96,
-0xFF,0x7C, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0x83,0x96,
-0xFF,0x84, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF5,0x02, 0x00,0x02, 0xF5,0x23, 0x28,0x00, 0x23,0x94,
-0x00,0x52, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
-0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x03,0x20, 0x00,0x18, 0xE6,0x00, 0x92,0x30, 0xF3,0x9B,
-0x28,0x00, 0xF7,0x04, 0x42,0x70, 0xE0,0x00, 0x92,0x9C, 0xF6,0x06, 0x42,0x72, 0x85,0x16,
-0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0xAA, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x07,0x34,
-0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00, 0x92,0x94, 0xC7,0x34, 0x68,0x00, 0xF5,0x84,
-0x42,0x60, 0xF3,0x82, 0x00,0xFF, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
-0x00,0x00, 0x97,0x16, 0xFF,0x74, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x3C,0x00, 0x20,0x36, 0x00,0x00, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x92,0xC9, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x42,0x74, 0xF6,0x06, 0x42,0x74, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xA4, 0x83,0x96, 0xFF,0x74, 0xC7,0x20,
-0x52,0x00, 0x74,0xB8, 0xFF,0xFA, 0xC6,0x24, 0x00,0x00, 0x87,0x1E, 0x00,0x00, 0x76,0x9D,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x52,0x00, 0x75,0xAC, 0xFF,0xFA, 0x46,0x31,
-0x00,0x00, 0xF5,0x02, 0x00,0xFF, 0xC6,0x30, 0x54,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x1F,
-0x28,0x00, 0x83,0x96, 0xFF,0x94, 0x85,0x16, 0xFF,0xC4, 0xF5,0x9F, 0x28,0x00, 0x87,0x2A,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xE6,0x00, 0x94,0x69, 0xF6,0x86,
-0x40,0x98, 0xF7,0x04, 0x6E,0x50, 0x86,0x2A, 0x00,0x2C, 0xC6,0xA4, 0x00,0x00, 0x23,0x94,
-0x00,0x62, 0x84,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4,
-0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x46,0xB5, 0x00,0x00, 0x87,0x3A, 0x1D,0xDC, 0x76,0xB5,
-0x00,0x02, 0xC0,0x32, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
-0x00,0x00, 0xF7,0x06, 0x40,0x98, 0xE6,0x00, 0x94,0x34, 0xC3,0x34, 0x70,0x00, 0xC5,0x84,
-0x00,0x00, 0x86,0xAA, 0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0x05,0x28, 0x00,0x24, 0xE6,0x00, 0x93,0xC4, 0x95,0x16, 0xFF,0x74, 0x83,0x96,
-0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0x9E, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x93,0xC8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x93,0xD5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
-0x00,0x00, 0x85,0x16, 0xFF,0x74, 0xF7,0x04, 0xE0,0x00, 0x86,0xAA, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x14, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0x94,0x1C, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x1D, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x94,0x2D, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x94,0x39, 0x00,0x00,
-0x00,0x01, 0xF4,0x82, 0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x9B, 0x28,0x00, 0x83,0x96,
-0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x1E,
-0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
-0x94,0xE4, 0xF6,0x3B, 0x28,0x00, 0x47,0x25, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
-0x68,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0x23,0x94,
-0x00,0x62, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
-0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x25,0x14, 0x00,0x62, 0xF3,0xBB, 0x28,0x00, 0x85,0x2A,
-0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29,
-0xFF,0xF0, 0xE0,0x00, 0x94,0xE4, 0xF5,0x1B, 0x28,0x00, 0x83,0x96, 0xFF,0xBC, 0x00,0x00,
-0x00,0x01, 0x20,0x1E, 0x00,0x01, 0xE6,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x35,0x60, 0xF5,0x05,
-0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x06,
-0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x96,0x89, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEE,0x00, 0x95,0x8D, 0xF5,0x86,
-0x42,0x50, 0xF7,0x04, 0x42,0x50, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x26,0xB4,
-0x00,0x01, 0xF6,0x85, 0x42,0x54, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF6,0x84,
-0x2D,0x38, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x2F,
-0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
-0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x96,0x88, 0xB5,0x36,
-0x70,0x02, 0xE0,0x00, 0x96,0x88, 0xF0,0x05, 0x2D,0x38, 0xF5,0x04, 0x42,0x60, 0x00,0x00,
-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB2,0x84, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x34, 0x00,0x40, 0xC0,0x22,
-0x72,0x00, 0xE6,0x00, 0x95,0xEC, 0xF6,0x06, 0x42,0x76, 0xF7,0x04, 0x42,0x74, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x60, 0x00,0x00,
-0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00, 0x96,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0xF5,0x04, 0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x40, 0x00,0x00,
-0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE6,0x00, 0x96,0x71, 0x00,0x00, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04,
-0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF5,0x04,
-0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xC1,0xB4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x70, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x9B,0x18, 0x06,0xB0,
-0x00,0x02, 0x87,0x36, 0x00,0x00, 0xF4,0x04, 0x40,0x7C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00,
-0x9B,0x18, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x23,0x94, 0x00,0x38, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
-0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14,
-0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04,
-0x40,0x74, 0x94,0x16, 0xFF,0xC4, 0x07,0x20, 0x00,0x02, 0xF0,0x3B, 0x28,0x00, 0x24,0x80,
-0x00,0x07, 0xF4,0x02, 0x00,0xFF, 0x83,0x96, 0xFF,0xC4, 0x95,0x16, 0xFF,0xBC, 0x03,0x1C,
-0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x98,0xA8, 0x06,0x18, 0x00,0x0E, 0x86,0xB2,
-0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
-0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x04,0xA4,
-0x00,0x01, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x44,0x00, 0xE0,0x00,
-0x98,0x54, 0xF7,0x33, 0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
-0xFF,0xE5, 0x83,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x1E, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
-0xFF,0xE5, 0x05,0x28, 0x00,0x26, 0x95,0x16, 0xFF,0x8C, 0x85,0xAA, 0x00,0x00, 0x76,0xA9,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x03,0x9C, 0x00,0x02, 0x93,0x96, 0xFF,0xB4, 0x06,0x1C,
-0x00,0x02, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x9C, 0x83,0x96, 0xFF,0xBC, 0x75,0x15,
-0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x95,0x16, 0xFF,0xA4, 0x85,0x16, 0xFF,0xC4, 0xC5,0xAC, 0x6F,0xC0, 0x75,0xAD,
-0xFF,0xF0, 0xF5,0x05, 0x42,0x60, 0xF5,0x04, 0x4F,0x58, 0xF6,0x82, 0x00,0xFF, 0xC7,0x1C,
-0x52,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82,
-0xFF,0x00, 0xC5,0xAC, 0x6C,0x00, 0xC7,0x38, 0x58,0x00, 0x83,0x96, 0xFF,0x8C, 0xF5,0x84,
-0x3B,0x6C, 0x85,0x16, 0xFF,0xB4, 0xF7,0x1F, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x06,0xAC,
-0x00,0x01, 0xF6,0x85, 0x3B,0x6C, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xF5,0x04, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC0,0x1E,
-0x52,0x00, 0xC7,0x38, 0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
-0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x99, 0x00,0x1E, 0x83,0x96,
-0xFF,0x94, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
-0x00,0x16, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16, 0xFF,0xAC, 0x83,0x96,
-0xFF,0xA4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x06,0x30, 0x00,0x02, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14,
-0x00,0x12, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0x83,0x96,
-0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16,
-0xFF,0xF0, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
-0x28,0x00, 0x07,0x1C, 0x00,0x3A, 0xF5,0xBB, 0x28,0x00, 0x07,0x1C, 0x00,0x36, 0xF0,0x3B,
-0x28,0x00, 0xF5,0x02, 0x00,0x03, 0xE6,0x00, 0x9A,0xA4, 0xF5,0x1F, 0x28,0x00, 0xF7,0x04,
-0x42,0x78, 0xF6,0x06, 0x42,0x78, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9B,0x18, 0x00,0x00,
-0x00,0x01, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF7,0x04,
-0x42,0x50, 0xF6,0x06, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x82,
-0x00,0x06, 0xF3,0x85, 0x42,0x54, 0xF5,0x06, 0x39,0x34, 0xF5,0x05, 0x42,0x44, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
-0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x9B,0x18, 0xB3,0xB6,
-0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x78, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0x9E,0x41, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xEE,0x00, 0x9D,0x85, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14,
-0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
-0xFF,0x94, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94,
-0x00,0x68, 0x93,0x96, 0xFF,0x8C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x84, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
-0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x84, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0x9D,0x5D, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00,
-0x00,0x01, 0xF5,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC7,0x28, 0x50,0x00, 0xC7,0x24,
-0x70,0x00, 0x05,0xB8, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xE6,0x00,
-0x9D,0xFD, 0xF6,0x02, 0x00,0xFF, 0xF7,0x04, 0x42,0x78, 0xF6,0x06, 0x42,0x7A, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
-0x00,0x01, 0xC7,0x38, 0x64,0x00, 0xF6,0x02, 0xFF,0x00, 0xC6,0xB4, 0x64,0x00, 0xC7,0x38,
-0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0x07,0x28, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x94,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xD8, 0xF3,0x86,
-0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA2,0xC9, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xA0,0x35, 0x24,0x94,
-0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14, 0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1,
-0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32,
-0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
-0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96, 0xFF,0x4C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x44, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
-0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x44, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xA2,0x80, 0x93,0x93,
-0xFF,0xFC, 0xF4,0x04, 0x40,0x7C, 0xF6,0x04, 0x40,0x74, 0xF3,0x82, 0x00,0x00, 0xC7,0x20,
-0x40,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E,
-0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xA0,0xAD, 0x93,0x96, 0xFF,0x3C, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06, 0x42,0xA0, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0xA2,0xC8, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x7E, 0x25,0x14,
-0x00,0x80, 0x23,0x94, 0x00,0x68, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
-0x00,0x7C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
-0x00,0x7A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
-0x00,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
-0x00,0x76, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
-0x00,0x74, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
-0x00,0x72, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13,
-0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x34, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0xB0, 0x93,0x96, 0xFF,0x2C, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0x2C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x3C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x98, 0x93,0x96, 0xFF,0x24, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
-0x00,0x06, 0xF3,0x85, 0x42,0x54, 0x87,0x02, 0xFF,0x34, 0xF3,0x86, 0x38,0xA8, 0xF3,0x85,
-0x42,0x44, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0xA2,0xA9, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
-0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xA3,0xAC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
-0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0xF6,0x84,
-0x40,0x7C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0xA3,0xAC, 0xC7,0x34,
-0x68,0x00, 0xF5,0x84, 0x40,0x74, 0xF6,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC6,0x2C,
-0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0xAC, 0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
-0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02,
-0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0xF5,0x06,
-0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0xF5,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x80, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA3,0xF4, 0x20,0x3A, 0x00,0x07, 0xF5,0x02,
-0x00,0x01, 0xF5,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x07, 0xEE,0x00, 0xA6,0xF0, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x23,0x14,
-0x00,0x66, 0xF4,0x84, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x74,0x25, 0x00,0x1E, 0x74,0x20,
-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16,
-0xFF,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x25,0x14, 0x00,0x20, 0x95,0x16,
-0xFF,0x94, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x85,0x16, 0xFF,0x7C, 0x05,0xA4,
-0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x25,0x14, 0x00,0x50, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
-0x00,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
-0x00,0x62, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
-0x00,0x60, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
-0x00,0x5E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
-0x00,0x5C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
-0x00,0x5A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x05,0xAC,
-0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x58, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
-0xFF,0xFC, 0x95,0x16, 0xFF,0x8C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
-0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x25,0x14,
-0x00,0x38, 0x95,0x16, 0xFF,0x84, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13,
-0xFF,0xFC, 0xF5,0x04, 0x42,0x64, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
-0xFF,0x84, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16, 0xFF,0x94, 0x00,0x00,
-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA6,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04,
-0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00, 0xA7,0x30, 0xF5,0x02,
-0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
-0xA7,0x50, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00, 0xA7,0x50, 0xF0,0x05, 0x2D,0x38, 0x95,0x13,
-0xFF,0xFC, 0xF5,0x02, 0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0xF6,0x04,
-0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0xA9,0xF0, 0x07,0x30, 0x00,0x02, 0x86,0x3A, 0x00,0x00, 0xF5,0x82,
-0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x30,
-0x77,0xC0, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0x76,0x31, 0xFF,0xF0, 0xC6,0x00,
-0x62,0x00, 0x96,0x16, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
-0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0xA8,0x34, 0xF6,0x02, 0x00,0xFF, 0x83,0x16, 0xFF,0xF4, 0x83,0x96,
-0xFF,0xF4, 0xF7,0x04, 0x40,0x78, 0xC6,0x98, 0x38,0x00, 0xC7,0x38, 0x68,0x00, 0x07,0x38,
-0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x64,0x00, 0xC0,0x36, 0x5A,0x00, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA8,0x3D, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xA8,0x75, 0xF6,0x06,
-0x42,0x7C, 0xF7,0x04, 0x42,0x7C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xA9,0xF0, 0x00,0x00,
-0x00,0x01, 0xF3,0x04, 0x42,0x60, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF4,0x04, 0x40,0x78, 0xF7,0x04,
-0x4F,0x58, 0xF5,0x04, 0x40,0x74, 0xF3,0x84, 0x40,0x7C, 0xF3,0x04, 0x40,0x7C, 0xC6,0x20,
-0x72,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0x9C, 0x30,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC,
-0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x74,0xAD, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x73,0xAD,
-0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xD4, 0xC5,0x28, 0x72,0x00, 0x75,0x28,
-0xFF,0xFA, 0x83,0x16, 0xFF,0xF4, 0x83,0x96, 0xFF,0xF4, 0x46,0x31, 0x00,0x00, 0x45,0x29,
-0x00,0x00, 0xC7,0x18, 0x38,0x00, 0xC4,0x20, 0x70,0x00, 0x04,0x20, 0x00,0x26, 0x73,0x21,
-0x00,0x1E, 0xC6,0xB4, 0x4F,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC6,0x30,
-0x4C,0x00, 0xF3,0x82, 0xFF,0x00, 0xC6,0xB4, 0x3C,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
-0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
-0xFF,0xD4, 0x83,0x96, 0xFF,0xF4, 0xC5,0x28, 0x4C,0x00, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x76,0x9D, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4,
-0x70,0x00, 0xF6,0xAF, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x83,0x16,
-0xFF,0xCC, 0xF3,0x82, 0xFF,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
-0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x23, 0x28,0x00, 0x87,0x22,
-0x00,0x00, 0xF3,0x04, 0x40,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19,
-0x00,0x10, 0x93,0x16, 0xFF,0xEC, 0x73,0x99, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC7,0x1C,
-0x70,0x00, 0x97,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x83,0x1A, 0x00,0x00, 0x77,0x99,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18, 0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0xF3,0x23,
-0x28,0x00, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x98, 0xF3,0x06,
-0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xAE,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xAD,0x89, 0x27,0x38,
-0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x24,0x94,
-0x00,0x66, 0x94,0x96, 0xFF,0x64, 0xF3,0x04, 0x40,0x78, 0x24,0x94, 0x00,0x20, 0x94,0x96,
-0xFF,0x94, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0x93,0x16, 0xFF,0x74, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
-0xFF,0xE5, 0x05,0x98, 0x00,0x02, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28,
-0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x85,0x16, 0xFF,0x64, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
-0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14,
-0x00,0x64, 0x93,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x24,0x94, 0x00,0x62, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x25,0x14, 0x00,0x60, 0x95,0x16, 0xFF,0x64, 0x05,0xAC,
-0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
-0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x24,0x94,
-0x00,0x5C, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x95,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x50, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x58, 0x05,0xAC,
-0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x93,0x16, 0xFF,0x64, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
-0xFF,0xFC, 0x94,0x96, 0xFF,0x8C, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x23,0x14, 0x00,0x38, 0x95,0x13,
-0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x93,0x16, 0xFF,0x84, 0x93,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x27,0x80,
-0x00,0x07, 0xF7,0x85, 0x42,0x58, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84,
-0x42,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x84, 0x00,0x00,
-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xAD,0x5D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
-0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xAE,0xE4, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
-0xAE,0xE4, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x40,0x78, 0xF5,0x84, 0x4F,0x58, 0x07,0x38,
-0x00,0x16, 0x86,0xBA, 0x00,0x00, 0xF4,0x06, 0x3B,0x90, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x76,0x35, 0x00,0x06, 0xA7,0x2E,
-0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38,
-0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x73,0xB7, 0xFF,0xF0, 0xEE,0x00, 0xAE,0x55, 0x95,0x16, 0xFF,0x64, 0xA7,0x2E,
-0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x23,0x14,
-0x00,0x88, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
-0x00,0x08, 0x85,0x3A, 0x00,0x04, 0x84,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x1A,
-0x00,0x04, 0x94,0x9A, 0x00,0x00, 0x85,0x96, 0xFF,0x7C, 0xE0,0x00, 0xAE,0x78, 0x00,0x00,
-0x00,0x01, 0x84,0x96, 0xFF,0x64, 0xA7,0x2E, 0x60,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
-0x40,0x00, 0x85,0xBA, 0x00,0x04, 0x85,0x16, 0xFF,0x64, 0xF6,0x06, 0x3B,0x90, 0x87,0x2A,
-0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38,
-0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00,
-0xAE,0xC9, 0x76,0xB5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x78, 0x00,0x00, 0x00,0x01, 0x77,0x19,
-0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0x84,0x96, 0xFF,0x64, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
-0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x10, 0xF7,0x04, 0x40,0x84, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xAF,0x3C, 0xF6,0x06, 0x42,0xB8, 0xF7,0x04, 0x42,0xB8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF3,0x06, 0x36,0x78, 0xF3,0x05, 0x42,0x44, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x5C, 0xF3,0x84,
-0x42,0x5C, 0x83,0x3A, 0x00,0x04, 0xC4,0x38, 0x00,0x00, 0x93,0x16, 0xFF,0xEC, 0x77,0x1D,
-0x00,0x01, 0xC7,0x38, 0x38,0x00, 0x77,0x39, 0x00,0x02, 0x04,0xB8, 0x00,0x0C, 0x83,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00, 0xB0,0x70, 0xC5,0x04,
-0x00,0x00, 0xA6,0xA2, 0x48,0x02, 0xF7,0x04, 0xE0,0x00, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0xAF,0xA8, 0xC6,0x20, 0x48,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xAF,0xAC, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xAF,0xB9, 0x00,0x00,
-0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xF4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0xAF,0xFC, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
-0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xFD, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xB0,0x0D, 0x20,0x2A,
-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xB0,0x59, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x7A,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xB0,0x64, 0xC7,0x20, 0x48,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x06, 0x40,0x98, 0x77,0x39,
-0x00,0x02, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
-0xB0,0x64, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x0C, 0xE0,0x00, 0xAF,0x60, 0x03,0x9C,
-0x00,0x01, 0x83,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00,
-0xB1,0x04, 0xF3,0x06, 0x36,0x78, 0xF6,0x84, 0x4F,0x5C, 0x77,0x1D, 0x00,0x01, 0xC7,0x38,
-0x38,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xC6,0xB4, 0x70,0x00, 0x87,0x36,
-0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x96,0x93,
-0xFF,0xFC, 0x93,0x96, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFA,0x98, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xF6,0x84, 0x42,0x6C, 0x83,0x96, 0xFF,0xF4, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0xC7,0x1C, 0x70,0x00, 0xF7,0x05, 0x42,0x5C, 0x06,0xB4,
-0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x85, 0x42,0x6C, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x1C, 0x20,0x32,
-0x00,0x44, 0xE6,0x00, 0xB1,0x08, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0xB1,0x08, 0xF0,0x05,
-0x2D,0x38, 0xF3,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF4,0x02, 0x00,0x00, 0xC5,0xA0, 0x00,0x00, 0xF6,0x82, 0x07,0x70, 0xF7,0x04,
-0x6E,0x50, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0xB1,0x6D, 0x06,0x38, 0x00,0x1C, 0x87,0x32,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC4,0x20, 0x70,0x00, 0xC0,0x22, 0x72,0x00, 0xE4,0x00,
-0xB1,0x5D, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x01, 0x26,0xB4, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0xB1,0x40, 0x06,0x30, 0x00,0x04, 0xC4,0x20, 0x58,0x00, 0xC0,0x22,
-0x5A,0x00, 0xE4,0x00, 0xB1,0x81, 0x00,0x00, 0x00,0x01, 0x04,0x20, 0x00,0x01, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB1,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x04, 0x40,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00,
-0xB1,0xED, 0xF4,0x05, 0x40,0x90, 0xF7,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x86,0xBA,
-0x1D,0xDC, 0xF5,0x82, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x96,0xBA, 0x1D,0xDC, 0x87,0x3A,
-0x1D,0xDC, 0xE0,0x00, 0xB1,0xF0, 0xF5,0x85, 0x7A,0xD0, 0xF0,0x05, 0x7A,0xD0, 0xF5,0x84,
-0x40,0x90, 0xF0,0x05, 0x40,0x84, 0xF5,0x85, 0x40,0x94, 0xF5,0x86, 0xE0,0x00, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x85,0xBA, 0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0xF5,0x85,
-0x3B,0x64, 0xF5,0x84, 0xE0,0x00, 0xF0,0x05, 0x42,0x5C, 0x95,0xBA, 0x00,0x10, 0xF5,0x84,
-0xE0,0x04, 0xF6,0x86, 0x2C,0x28, 0x95,0xBA, 0x00,0x14, 0xF7,0x04, 0x2D,0x38, 0xF5,0x86,
-0x3A,0x4C, 0xF5,0x85, 0x42,0x44, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0xF5,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xB2,0x68, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86, 0x35,0xEC, 0xF5,0x85, 0x42,0x30, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xC8, 0xF3,0x02,
-0x00,0x00, 0x93,0x16, 0xFF,0x94, 0x24,0x80, 0x00,0x08, 0x94,0x96, 0xFF,0x84, 0x23,0x80,
-0x00,0x07, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0x54, 0x20,0x1E,
-0x00,0x07, 0xEE,0x00, 0xB5,0x64, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84,
-0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB3,0x2D, 0x20,0x36,
-0x00,0x01, 0xE6,0x00, 0xB3,0x2D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38,
-0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB3,0x31, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C,
-0x00,0x00, 0xE0,0x00, 0xB3,0x30, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04,
-0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB5,0x5D, 0x00,0x00,
-0x00,0x01, 0xF6,0x84, 0x3B,0xBC, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFF,0x3C, 0x04,0x28,
-0x00,0x1C, 0xF7,0x04, 0x3B,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
-0xB4,0x40, 0x96,0x96, 0xFF,0xAC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
-0x00,0x02, 0xF4,0x86, 0x3B,0xB4, 0xC6,0x38, 0x48,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x04,
-0x00,0x00, 0x93,0x16, 0xFF,0x34, 0x86,0xB2, 0x00,0x00, 0x87,0x2A, 0x00,0x1C, 0x85,0x96,
-0xFF,0x3C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0x86,0xB2,
-0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
-0xB3,0xD1, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x34, 0x86,0xB2,
-0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0xB4,0x0C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB4,0x14, 0x20,0x2E,
-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0xB4,0x15, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0xB4,0x25, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
-0xFF,0x34, 0x84,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
-0xB4,0x40, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0x3C, 0x84,0x96,
-0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xB4,0x81, 0xF6,0x02,
-0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06, 0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
-0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0xE0,0x00, 0xB4,0xF4, 0x96,0x96, 0xFF,0xB4, 0x27,0x14,
-0x00,0x54, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0xF4,0x86, 0x3B,0xB4, 0x94,0x93,
-0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xB4,0xF1, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06,
-0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
-0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0x96,0x96,
-0xFF,0xB4, 0xF7,0x05, 0x3B,0xBC, 0xE0,0x00, 0xB4,0xF8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xB5,0x2D, 0x27,0x14, 0x00,0x08, 0x84,0x96,
-0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x83,0x16, 0xFF,0xB4, 0x04,0xA4,
-0x00,0x04, 0x94,0x96, 0xFF,0x54, 0x84,0x96, 0xFF,0x94, 0x93,0x3A, 0xFF,0xC0, 0x04,0xA4,
-0x00,0x01, 0xE0,0x00, 0xB5,0x54, 0x94,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0x54, 0x00,0x00,
-0x00,0x01, 0xC7,0x18, 0x70,0x00, 0xF4,0x84, 0x4F,0x58, 0x03,0x18, 0x00,0x04, 0x93,0x16,
-0xFF,0x54, 0x83,0x16, 0xFF,0x94, 0x94,0xBA, 0xFF,0xC0, 0x03,0x18, 0x00,0x01, 0x93,0x16,
-0xFF,0x94, 0x95,0x16, 0xFF,0x3C, 0x93,0x96, 0xFF,0x8C, 0xE0,0x00, 0xB2,0xB0, 0x03,0x9C,
-0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
-0xB5,0x84, 0xF3,0x82, 0x00,0x01, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x00,0x00,
-0x00,0x01, 0x83,0x16, 0xFF,0xB8, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
-0x4A,0x00, 0xEC,0x00, 0xB5,0xCC, 0x93,0x16, 0xFF,0x7C, 0x26,0x94, 0x00,0x04, 0x87,0x36,
-0xFF,0xC0, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
-0xBB,0x98, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
-0x4A,0x00, 0xEC,0x00, 0xB5,0xA1, 0x06,0xB4, 0x00,0x04, 0xF4,0x04, 0x4F,0x58, 0x83,0x16,
-0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x42,0x00, 0xE6,0x00, 0xBA,0x2D, 0xF4,0x82,
-0x00,0x00, 0x94,0x96, 0xFF,0x74, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
-0xB7,0x48, 0xC7,0x1C, 0x38,0x00, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC7,0x18,
-0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
-0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB6,0x69, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
-0xB6,0x69, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
-0x00,0x02, 0xE6,0x00, 0xB6,0x6D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
-0xB6,0x6C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
-0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB7,0x41, 0xC5,0x84, 0x00,0x00, 0x84,0x96,
-0xFF,0x74, 0x86,0xAA, 0x00,0x1C, 0x83,0x16, 0xFF,0x3C, 0xF6,0x02, 0x00,0x00, 0x04,0xA4,
-0x00,0x01, 0x94,0x96, 0xFF,0x74, 0x87,0x1A, 0x00,0x1C, 0x04,0xA8, 0x00,0x1C, 0x94,0x96,
-0xFF,0x34, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB6,0xCC, 0x04,0x18, 0x00,0x1C, 0x86,0xAA,
-0x00,0x20, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0xB6,0xD0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0xB6,0xDD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0x87,0x22,
-0x00,0x00, 0x86,0x9A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0xB7,0x1C, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB7,0x24, 0x20,0x32,
-0x00,0x00, 0x86,0x9A, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0xB7,0x25, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0xB7,0x35, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0xB7,0x40, 0x00,0x00, 0x00,0x01, 0x93,0x96, 0xFF,0x84, 0xE0,0x00,
-0xB5,0xEC, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x74, 0x83,0x16, 0xFF,0x94, 0x00,0x00,
-0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x00, 0x00,0x08, 0x84,0x96,
-0xFF,0x84, 0x00,0x00, 0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x99, 0xF6,0x02,
-0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0xC7,0x38,
-0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x04, 0xF5,0x82,
-0x00,0xFF, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
-0x32,0x00, 0x84,0x96, 0xFF,0x7C, 0xC7,0x38, 0x70,0x00, 0xC7,0x24, 0x70,0x00, 0x07,0x38,
-0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x5C,0x00, 0xC0,0x36, 0x62,0x00, 0x47,0x0C,
-0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x0D, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x80,
-0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00, 0xB8,0xC8, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
-0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
-0xB8,0x91, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xB8,0x91, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
-0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
-0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB8,0x95, 0xC6,0xB8,
-0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00, 0xB8,0x94, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84,
-0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00,
-0xB8,0xC1, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00,
-0xB8,0x14, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0xF3,0x84,
-0x40,0x7C, 0xF5,0x04, 0x40,0x74, 0xC4,0xA4, 0x32,0x00, 0x94,0x96, 0xFF,0x34, 0x83,0x16,
-0xFF,0x34, 0xC5,0x9C, 0x38,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
-0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x74,0x2D, 0x00,0x1E, 0x74,0x20,
-0xFF,0xE5, 0x73,0x9D, 0x00,0x10, 0x73,0x9D, 0xFF,0xF8, 0xC4,0xA4, 0x30,0x00, 0x94,0x96,
-0xFF,0x3C, 0x83,0x16, 0xFF,0x7C, 0xC6,0xB4, 0x77,0xC0, 0xC4,0x98, 0x48,0x00, 0x94,0x96,
-0xFF,0x3C, 0x04,0xA4, 0x00,0x26, 0x94,0x96, 0xFF,0x3C, 0x73,0x25, 0x00,0x1E, 0x73,0x18,
-0xFF,0xE5, 0x93,0x16, 0xFF,0x6C, 0x74,0xA5, 0x00,0x1E, 0x94,0x96, 0xFF,0x64, 0x74,0xA4,
-0xFF,0xE5, 0x94,0x96, 0xFF,0x64, 0x83,0x16, 0xFF,0x7C, 0xF4,0x84, 0x4F,0x58, 0x76,0xB5,
-0xFF,0xF0, 0xC6,0x18, 0x4A,0x00, 0x76,0x30, 0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xF3,0x02,
-0x00,0xFF, 0xC6,0x30, 0x34,0x00, 0xF4,0x82, 0xFF,0x00, 0xC6,0xB4, 0x4C,0x00, 0xC6,0x30,
-0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0xC7,0x38,
-0x47,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19, 0x00,0x10, 0x93,0x16, 0xFF,0x34, 0x74,0x99,
-0xFF,0xF8, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x34,0x00, 0xC7,0x24, 0x70,0x00, 0x97,0x16,
-0xFF,0x34, 0x24,0x94, 0x00,0xCA, 0x84,0xA6, 0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC,
-0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x3C, 0xF4,0xAF,
-0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0x28, 0x4A,0x00, 0x75,0x28,
-0xFF,0xFA, 0x83,0x16, 0xFF,0x6C, 0x45,0x29, 0x00,0x00, 0xF4,0x82, 0x00,0xFF, 0xC5,0x28,
-0x4C,0x00, 0x84,0x96, 0xFF,0x3C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF3,0x02,
-0xFF,0x00, 0xC7,0x38, 0x34,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x27, 0x28,0x00, 0x87,0x26,
-0x00,0x00, 0x83,0x16, 0xFF,0x64, 0x84,0x16, 0xFF,0x7C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
-0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC7,0x38, 0x4C,0x00, 0x83,0x16, 0xFF,0x3C, 0xC3,0x9C,
-0x70,0x00, 0xE0,0x00, 0xBE,0xE4, 0xF3,0x9B, 0x28,0x00, 0xF7,0x04, 0x40,0x7C, 0xF6,0x04,
-0x40,0x74, 0xC7,0x38, 0x70,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
-0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0xBA,0x7D, 0x25,0x80, 0x00,0x07, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
-0x00,0x40, 0xE0,0x00, 0xBA,0xD8, 0xC4,0x2C, 0x00,0x00, 0xC7,0x30, 0x42,0x00, 0x84,0x96,
-0x00,0x00, 0x75,0x38, 0xFF,0xFA, 0x06,0x24, 0x00,0x0A, 0x20,0x2E, 0x00,0x07, 0xEE,0x00,
-0xBA,0xD4, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
-0x74,0x00, 0x47,0x29, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0xBA,0x74, 0x06,0x30, 0x00,0x02, 0xE0,0x00, 0xBA,0x8C, 0x05,0xAC,
-0x00,0x01, 0xF4,0x02, 0x00,0x08, 0x07,0x20, 0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00,
-0xBB,0xA4, 0xC5,0xA0, 0x40,0x00, 0x83,0x16, 0x00,0x00, 0xF5,0x04, 0x40,0x7C, 0xF4,0x82,
-0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC5,0x98, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
-0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x18, 0x62,0x00, 0x76,0x30,
-0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xC6,0x30, 0x4C,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0x77,0x29, 0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0xC6,0xB4, 0x4C,0x00, 0xC7,0x38,
-0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0xF5,0x84, 0x40,0x74, 0xC5,0x28, 0x50,0x00, 0xC5,0xAC,
-0x50,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0x75,0x2D, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
-0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xA1, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38,
-0x57,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4, 0x70,0x00, 0xE0,0x00,
-0xBB,0xF8, 0xF6,0xAF, 0x28,0x00, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
-0x00,0x40, 0xF6,0x04, 0x4F,0x58, 0x83,0x16, 0x00,0x00, 0xF7,0x04, 0x40,0x7C, 0xF5,0x84,
-0x40,0x74, 0xC6,0x18, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x70,0x00, 0xC5,0xAC,
-0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
-0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30,
-0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
-0xBE,0xE0, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
-0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
-0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xBC,0x79, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
-0xBC,0x79, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
-0x00,0x02, 0xE6,0x00, 0xBC,0x7D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
-0xBC,0x7C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
-0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xBE,0xD9, 0x06,0xA8, 0x00,0x1C, 0x83,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF4,0x86,
-0x3B,0xB4, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x96,0x96,
-0xFF,0x40, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF3,0x04,
-0x4F,0x5C, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x5C, 0x86,0x96, 0xFF,0x40, 0x83,0x96,
-0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x93,0x16, 0xFF,0x34, 0x86,0x1A, 0x00,0x08, 0x96,0x96,
-0xFF,0x3C, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xEC,0x00,
-0xBD,0xB8, 0x96,0x16, 0xFF,0x9C, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
-0x00,0x02, 0xC6,0x38, 0x30,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2A,
-0x00,0x1C, 0x85,0x96, 0xFF,0x5C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xBD,0x40, 0xC4,0x04,
-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0xBD,0x44, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
-0x00,0x00, 0xE6,0x00, 0xBD,0x51, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x00, 0x83,0x16,
-0xFF,0x3C, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0xBD,0x90, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0xBD,0x98, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xBD,0x99, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xBD,0xA9, 0x20,0x22, 0x00,0x00, 0xF4,0x02,
-0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBD,0xB8, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
-0x00,0x01, 0x94,0x96, 0xFF,0x5C, 0x83,0x16, 0xFF,0x5C, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
-0x00,0x00, 0xE6,0x00, 0xBD,0xF9, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0x9C, 0x84,0x96,
-0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
-0x48,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xA0, 0xE0,0x00,
-0xBE,0x70, 0x96,0x96, 0xFF,0xA4, 0x27,0x14, 0x00,0x64, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
-0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x34, 0x00,0x00,
-0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16,
-0xFF,0x44, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBE,0x71, 0xF6,0x02, 0x00,0x00, 0x87,0x16,
-0xFF,0x9C, 0x83,0x16, 0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xA0, 0x96,0x96, 0xFF,0xA4, 0x97,0x1A, 0x00,0x08, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0xBE,0x99, 0xF6,0x06, 0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC7,0x28,
-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x28,
-0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF4,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x94,0x93,
-0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xBB,0xFC, 0x03,0x9C, 0x00,0x01, 0x84,0x16,
-0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x60, 0x85,0x16, 0x00,0x00, 0x86,0x16, 0x00,0x04, 0x06,0xA8, 0x00,0x18, 0xC7,0x30,
-0x60,0x00, 0xC5,0xB8, 0x68,0x00, 0x20,0x32, 0x00,0x07, 0xEE,0x00, 0xBF,0x64, 0x07,0x2C,
-0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
-0x00,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xBF,0x61, 0x05,0xAC, 0x00,0x02, 0xE0,0x00, 0xBF,0x18, 0x06,0x30, 0x00,0x01, 0x20,0x32,
-0x00,0x07, 0xEE,0x00, 0xC0,0x4C, 0x06,0xA8, 0x00,0x16, 0xF5,0x05, 0x40,0x74, 0xF6,0x05,
-0x40,0x7C, 0xF3,0x02, 0x00,0x06, 0xF3,0x05, 0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0x05,0x28,
-0x00,0x02, 0x95,0x16, 0xFF,0xC4, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
-0xFF,0xBC, 0x93,0x93, 0xFF,0xFC, 0x96,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x38, 0x94,0x93,
-0xFF,0xFC, 0x93,0x16, 0xFF,0xB4, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x86,0x16, 0xFF,0xAC, 0xF7,0x05,
-0x42,0x64, 0x96,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x94,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xC0,0x1D, 0xF3,0x06, 0x3A,0xD8, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
-0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0xF3,0x05, 0x42,0x44, 0xF3,0x82,
-0x17,0x70, 0x93,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x1B, 0x94,0x93, 0xFF,0xFC, 0xF3,0x06,
-0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0xC1,0xA0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0xF5,0x84,
-0x4F,0x58, 0xF4,0x06, 0x3B,0x70, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C,
-0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7,
-0xFF,0xF0, 0xEE,0x00, 0xC1,0x15, 0x96,0x96, 0xFF,0x9C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94,
-0x00,0x60, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
-0x00,0x08, 0x83,0xBA, 0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6,
-0x00,0x04, 0x93,0x26, 0x00,0x00, 0x85,0x96, 0xFF,0xA4, 0xE0,0x00, 0xC1,0x38, 0x23,0x00,
-0x00,0x07, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x85,0xBA,
-0x00,0x04, 0x23,0x00, 0x00,0x07, 0x93,0x13, 0xFF,0xFC, 0x87,0x2A, 0x00,0x00, 0x76,0xA9,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E,
-0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0xEE,0x00, 0xC1,0x8D, 0x76,0xB5, 0xFF,0xF0, 0x84,0x96, 0xFF,0xA0, 0x00,0x00,
-0x00,0x01, 0x77,0x25, 0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x70, 0x25,0x00,
-0x00,0x07, 0x20,0x2A, 0x00,0x07, 0xEE,0x00, 0xC3,0xB8, 0xC7,0x28, 0x50,0x00, 0x83,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
-0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
-0xC2,0x3D, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xC2,0x3D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
-0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
-0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xC2,0x4D, 0xC0,0x3A,
-0x5A,0x00, 0xE0,0x00, 0xC2,0x48, 0xC7,0x2C, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF5,0x84,
-0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0xC3,0xB1, 0xF4,0x86,
-0x3B,0x90, 0x83,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x06,0x9C, 0x00,0x16, 0x87,0x36,
-0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7, 0xFF,0xF0, 0xEE,0x00,
-0xC3,0x21, 0x96,0x96, 0xFF,0x8C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x83,0x16, 0xFF,0x8C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94, 0x00,0x70, 0x77,0x39,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAA,
-0x68,0x02, 0x77,0x19, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x83,0xBA,
-0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6, 0x00,0x04, 0x93,0x26,
-0x00,0x00, 0x86,0x16, 0xFF,0x94, 0xE0,0x00, 0xC3,0x44, 0x00,0x00, 0x00,0x01, 0xA7,0x2E,
-0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x3B,0x90, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x30,0x00, 0x86,0x3A,
-0x00,0x04, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96,
-0xFF,0x8C, 0xF4,0x86, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xA6,0xBA, 0x48,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38, 0x48,0x00, 0x77,0x39,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC3,0x95, 0x76,0xB5,
-0xFF,0xF0, 0x83,0x16, 0xFF,0x90, 0x00,0x00, 0x00,0x01, 0x77,0x19, 0xFF,0xF0, 0xC6,0xB8,
-0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x30,
-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xC5,0xC4, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
-0xC1,0xC4, 0x05,0x28, 0x00,0x01, 0x83,0x96, 0x00,0x00, 0xF4,0x82, 0x00,0x06, 0xF4,0x85,
-0x42,0x54, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x1E, 0x23,0x14, 0x00,0x20, 0x93,0x16,
-0xFF,0xAC, 0xF3,0x85, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
-0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
-0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
-0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
-0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
-0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x25,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x07,0x1C,
-0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0xA4, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x84,0x96,
-0xFF,0xA4, 0x23,0x14, 0x00,0x38, 0x94,0x93, 0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93,
-0xFF,0xFC, 0x93,0x16, 0xFF,0x9C, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x27,0x80, 0x00,0x07, 0xF7,0x85,
-0x42,0x58, 0xF7,0x05, 0x42,0x64, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x97,0x13,
-0xFF,0xFC, 0x83,0x96, 0xFF,0x9C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96,
-0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xC5,0x95, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x39,0xC0, 0xF3,0x05, 0x42,0x44, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82,
-0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xC5,0xC4, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x25,0x00,
-0x00,0x07, 0xF7,0x04, 0x40,0x74, 0xF6,0x84, 0x4F,0x58, 0xF6,0x04, 0x42,0x60, 0xC7,0x38,
-0x6A,0x00, 0x75,0xB8, 0xFF,0xFA, 0x06,0x30, 0x00,0x0A, 0x20,0x2A, 0x00,0x07, 0xEE,0x00,
-0xC6,0x48, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
-0x74,0x00, 0x47,0x2D, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0xC6,0x4C, 0xC3,0x28, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xE0,0x00,
-0xC5,0xFC, 0x05,0x28, 0x00,0x01, 0xF3,0x02, 0x00,0x08, 0xC5,0x18, 0x30,0x00, 0xF3,0x84,
-0x42,0x60, 0xF6,0x04, 0x4F,0x58, 0xF7,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC5,0x1C,
-0x50,0x00, 0x05,0x28, 0x00,0x26, 0x85,0xAA, 0x00,0x00, 0x74,0x29, 0x00,0x1E, 0x74,0x20,
-0xFF,0xE5, 0xC6,0x1C, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC6,0xB8, 0x70,0x00, 0xC4,0xA4,
-0x68,0x00, 0x04,0xA4, 0x00,0x26, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x77,0x39,
-0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0x46,0x31, 0x00,0x00, 0xC5,0xAC, 0x47,0xC0, 0x75,0xAD,
-0xFF,0xF0, 0xF4,0x02, 0x00,0xFF, 0xC5,0xAC, 0x44,0x00, 0xC7,0x38, 0x58,0x00, 0xF7,0x2B,
-0x28,0x00, 0x87,0x26, 0x00,0x00, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30, 0x44,0x00, 0x75,0xAC,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38,
-0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x27, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x76,0x99,
-0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
-0x44,0x00, 0xC6,0xB4, 0x70,0x00, 0xF6,0xA7, 0x28,0x00, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
-0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x84, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
-0x42,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x30, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x35,0xEC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x36,0x78, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x04, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x90, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x38,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x38,0xA8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0x34, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0xC0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x3A,0x4C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x3A,0xD8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
-0x00,0x00, 0xF5,0x06, 0x3B,0x90, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
-0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37, 0xFF,0xF0, 0xEE,0x00, 0xC9,0x95, 0x00,0x00,
-0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA,
-0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
-0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A, 0x00,0x00, 0xE0,0x00, 0xC9,0xB4, 0xC5,0x24,
-0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A,
-0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32,
-0x00,0x00, 0xF6,0x06, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC9,0xF9, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
-0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF5,0x06, 0x3B,0x70, 0x87,0x2E,
-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37,
-0xFF,0xF0, 0xEE,0x00, 0xCA,0xBD, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA, 0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31,
-0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A,
-0x00,0x00, 0xE0,0x00, 0xCA,0xDC, 0xC5,0x24, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A, 0x00,0x04, 0x83,0x96, 0x00,0x04, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32, 0x00,0x00, 0x93,0x93, 0xFF,0xFC, 0x87,0x2E,
-0x00,0x00, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
-0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xCB,0x29, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
-0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x04, 0x4F,0x58, 0xF5,0x82, 0x00,0x02, 0x06,0x28,
-0x00,0x80, 0x20,0x2E, 0x00,0x62, 0xEE,0x00, 0xCB,0x90, 0x07,0x30, 0x00,0x40, 0xF0,0x33,
-0x28,0x00, 0xC6,0xB8, 0x52,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x30, 0x00,0x14, 0xF6,0xB3,
-0x28,0x00, 0xC6,0x38, 0x00,0x00, 0xE0,0x00, 0xCB,0x64, 0x05,0xAC, 0x00,0x01, 0xF7,0x04,
-0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x06,0xB8, 0x18,0xD4, 0xF4,0x82, 0x00,0x01, 0xF4,0xB7,
-0x28,0x00, 0x07,0x38, 0x18,0xC0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x42,0xC0, 0xF4,0x82,
-0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF6,0x84, 0x42,0xC0, 0xF6,0x06, 0x42,0xC0, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
-0x4F,0x58, 0x76,0xB5, 0x00,0x06, 0xC4,0x38, 0x68,0x00, 0x87,0x22, 0x00,0x14, 0x76,0xA1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
-0x28,0x00, 0xF7,0x04, 0x42,0xC0, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0xCC,0x4C, 0xF6,0x06, 0x42,0x90, 0xF7,0x04,
-0x42,0x90, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0x85,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0xCC,0xBC, 0xF5,0x86, 0x42,0xC0, 0xF7,0x04, 0x42,0x90, 0xF6,0x06, 0x42,0x92, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0xCC,0xEC, 0xF7,0x33, 0x28,0x00, 0xF0,0x2B, 0x28,0x00, 0xF6,0x84,
-0x42,0xC0, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x06,0x28, 0x00,0x14, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x4F,0x58, 0xF6,0xB3, 0x28,0x00, 0xC7,0x28,
-0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x2F, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x02,
-0x00,0x00, 0xC6,0xB4, 0x72,0x00, 0x77,0x34, 0xFF,0xFA, 0x27,0x38, 0x00,0x02, 0x20,0x3A,
-0x00,0x61, 0xF7,0x02, 0x00,0x3F, 0xE2,0x00, 0xCD,0x40, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
-0x00,0x00, 0xE6,0x00, 0xCD,0x40, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x87,0x16,
-0x00,0x08, 0x85,0x96, 0x00,0x04, 0xC5,0x30, 0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE6,0x00,
-0xCD,0xA1, 0x00,0x00, 0x00,0x01, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xAF, 0x68,0x00, 0x06,0x30,
-0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE6,0x00, 0xCD,0x78, 0x05,0xAC, 0x00,0x01, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x96,
-0x00,0x00, 0x84,0x16, 0x00,0x04, 0x85,0x96, 0x00,0x08, 0x86,0xA6, 0x00,0x00, 0x77,0x25,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x75,0x35, 0xFF,0xF0, 0x20,0x2A,
-0x00,0x10, 0xE2,0x00, 0xCE,0x0D, 0xF6,0x06, 0x42,0x8E, 0xF5,0x02, 0x00,0x10, 0xF7,0x04,
-0x42,0x8C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
-0xCE,0x70, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xCE,0x71, 0x07,0x24, 0x00,0x02, 0x25,0x28,
-0x00,0x01, 0xA5,0xBA, 0x50,0x02, 0x86,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC5,0xAC,
-0x77,0xC0, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x75,0xAD, 0xFF,0xE8, 0xF6,0x82,
-0x00,0xFF, 0xF7,0x02, 0xF1,0x54, 0x75,0xAD, 0x00,0x02, 0xA7,0x2E, 0x70,0x02, 0xC6,0x30,
-0x6C,0x00, 0xC6,0x30, 0x75,0x80, 0xF6,0x23, 0x28,0x00, 0x24,0x20, 0x00,0x02, 0x25,0xA8,
-0x00,0x01, 0xF3,0x02, 0xF2,0x46, 0x03,0xA4, 0x00,0x02, 0xC4,0xAC, 0x38,0x00, 0x25,0x2C,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xCF,0x11, 0x00,0x00, 0x00,0x01, 0xE6,0x00,
-0xCE,0xA0, 0xC7,0x1C, 0x50,0x00, 0xE0,0x00, 0xCE,0xB4, 0xF6,0x02, 0x00,0x00, 0xA6,0x9E,
-0x50,0x02, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x35,
-0xFF,0xE8, 0x86,0xA6, 0x00,0x00, 0x77,0x25, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x25,0x28,
-0x00,0x02, 0x25,0xAC, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0x77,0x31,
-0x00,0x04, 0xC7,0x38, 0x62,0x00, 0x77,0x39, 0x00,0x01, 0xC7,0x38, 0x30,0x00, 0xC6,0xB4,
-0x68,0x00, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x0E, 0x87,0x36, 0x00,0x00, 0x24,0xA4,
-0x00,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xE0,0x00, 0xCE,0x84, 0x24,0x20, 0x00,0x02, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x08, 0x83,0x16,
-0x00,0x04, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x74,0x1D,
-0x00,0x1E, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x05,0xAC, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x74,0x20,
-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x1F,
-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x04,0x9C, 0x00,0x02, 0xC7,0x38, 0x47,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x25,0x38, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xD0,0xBD, 0x26,0x28,
-0x00,0x01, 0xA7,0x26, 0x60,0x02, 0xC6,0xA4, 0x60,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC5,0xA4, 0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xE8, 0xE0,0x00, 0xD0,0x88, 0xF7,0x2F, 0x68,0x00, 0x07,0x1C, 0x00,0x02, 0xF3,0x3B,
-0x68,0x00, 0xC4,0x1C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x86,0x16, 0x00,0x04, 0x84,0x16, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0xA0, 0x00,0x02, 0x74,0xA1, 0x00,0x1E, 0x74,0xA4,
-0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x06,0xA0, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x22,
-0x00,0x00, 0x76,0x21, 0x00,0x1E, 0x85,0x96, 0x00,0x08, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF5,0xB7, 0x68,0x00, 0x87,0x22, 0x00,0x00, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x23,
-0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x20, 0x27,0x14, 0x00,0x20, 0xF0,0x3B, 0x28,0x00, 0x84,0x96, 0x00,0x04, 0xF5,0x02,
-0x00,0x00, 0x86,0xA6, 0x00,0x00, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x04,0x24,
-0x00,0x02, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xBB, 0x28,0x00, 0x87,0x26,
-0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00, 0xD2,0xF8, 0x76,0xA5, 0x00,0x1E, 0x87,0x26,
-0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0x06,0x28, 0x00,0x01, 0x25,0x94, 0x00,0x1E, 0xC5,0xAC,
-0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
-0x52,0x00, 0xA6,0xA2, 0x70,0x02, 0xC7,0x20, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xC6,0x80, 0x6A,0x00, 0xE0,0x00,
-0xD2,0x90, 0xF6,0xAF, 0x68,0x00, 0x87,0x16, 0xFF,0xE0, 0x76,0x15, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x83,0x96, 0x00,0x00, 0x23,0x14, 0x00,0x1E, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
-0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x06,0x9C, 0x00,0x02, 0x73,0x95,
-0x00,0x1E, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x67,0xC0, 0x83,0x96, 0x00,0x00, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x83,0x96, 0xFF,0xDC, 0x87,0x1A, 0x00,0x00, 0x73,0x9C,
-0xFF,0xE5, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
-0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0x84,0x16, 0x00,0x00, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x86,0x16, 0x00,0x00, 0x84,0x16, 0x00,0x04, 0xF6,0x84, 0x4F,0x58, 0x87,0x32,
-0x00,0x14, 0x03,0x30, 0x00,0x14, 0x75,0x19, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC3,0xA0,
-0x6A,0x00, 0x73,0x9C, 0xFF,0xFA, 0x04,0xA0, 0x00,0x14, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30,
-0x6A,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0xF3,0x9B, 0x28,0x00, 0x07,0x20, 0x00,0x16, 0xF6,0x3B, 0x28,0x00, 0x87,0x22,
-0x00,0x14, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39,
-0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x16, 0xF3,0xB7, 0x28,0x00, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0xF5,0x84,
-0x4F,0x58, 0x05,0x30, 0x00,0x16, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC4,0x2C,
-0x70,0x00, 0xC0,0x22, 0x62,0x00, 0xE6,0x00, 0xD5,0x29, 0x06,0xA0, 0x00,0x16, 0x87,0x36,
-0x00,0x00, 0xC6,0x30, 0x5A,0x00, 0x76,0x30, 0xFF,0xFA, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0x76,0xB8,
-0xFF,0xFA, 0xF6,0xAB, 0x28,0x00, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x14, 0xE0,0x00,
-0xD5,0x2C, 0xF6,0x3B, 0x28,0x00, 0xC4,0x2C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x4F,0x84, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05,
-0x6F,0x30, 0xF6,0x86, 0x50,0x5C, 0x46,0xB4, 0xFF,0xFC, 0xF6,0x85, 0x6E,0x50, 0xF7,0x06,
-0x6E,0x7C, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05, 0x6E,0x54, 0x07,0x34, 0x19,0x1C, 0xF7,0x05,
-0x4F,0x5C, 0xF7,0x02, 0x00,0x64, 0x97,0x36, 0x19,0x1C, 0xF7,0x02, 0x00,0x00, 0x97,0x36,
-0x19,0x20, 0x06,0xB4, 0x00,0x1C, 0xF6,0x85, 0x4F,0x58, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF3,0x02, 0xFF,0xFF, 0xF3,0x05,
-0x4F,0x54, 0xF3,0x82, 0x00,0x00, 0x93,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x20, 0x93,0x16,
-0xFF,0x9C, 0x23,0x94, 0x00,0x38, 0x93,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0xAC, 0xF7,0x04,
-0x4F,0x5C, 0xF3,0x82, 0x00,0x0C, 0x93,0x96, 0xFF,0x74, 0x93,0x16, 0xFF,0x8C, 0x87,0x3A,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xA4, 0x83,0x16, 0xFF,0xAC, 0x83,0x96,
-0xFF,0xA4, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x3A,0x00, 0xEC,0x00, 0xDB,0x78, 0xF3,0x02,
-0x04,0xBC, 0xF7,0x04, 0x4F,0x5C, 0x83,0x16, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x30,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC4,0xB4,
-0x70,0x00, 0x94,0x93, 0xFF,0xFC, 0x94,0x96, 0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0x7C, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0xD6,0x54, 0xC5,0x04, 0x00,0x00, 0xF7,0x04, 0x42,0x88, 0xE0,0x00, 0xD8,0x7C, 0xF6,0x06,
-0x42,0x88, 0xF6,0x04, 0x4F,0x5C, 0x83,0x96, 0x00,0x00, 0x83,0x16, 0xFF,0x74, 0x86,0x9E,
-0x00,0x00, 0xA7,0x32, 0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0xD6,0x94, 0xC6,0x30, 0x30,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xD6,0x98, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xA5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
-0x00,0x00, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xE4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0xE6,0x00, 0xD6,0xEC, 0x20,0x2E, 0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xED, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xFD, 0x20,0x2A,
-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xD7,0x28, 0x04,0xA4,
-0x00,0x02, 0x83,0x16, 0xFF,0xAC, 0xF7,0x06, 0x42,0xC8, 0x83,0x96, 0xFF,0x8C, 0xF3,0x05,
-0x4F,0x54, 0xC7,0x1C, 0x70,0x00, 0xF0,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0xE0,0x00,
-0xDB,0x50, 0xF0,0x3B, 0x28,0x00, 0x94,0x96, 0xFF,0x6C, 0x87,0x26, 0x00,0x00, 0x76,0xA5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16, 0xFF,0x6C, 0x83,0x96, 0xFF,0x9C, 0x24,0x94,
-0x00,0x1E, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x1D,
-0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x24,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x10, 0x76,0x31,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0xF6,0x82, 0xFF,0xFC, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x03, 0xC4,0xB8, 0x6C,0x00, 0x20,0x26, 0x00,0x10, 0xE2,0x00,
-0xD8,0x9D, 0xF6,0x06, 0x42,0x8A, 0xF7,0x04, 0x42,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0xDB,0xA0, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x6C, 0x25,0x14,
-0x00,0x36, 0x83,0x96, 0xFF,0x94, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x34, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x32, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x30, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2E, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2C, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2A, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x28, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x26,0xA4, 0x00,0x02, 0x74,0xA4, 0xFF,0xFF, 0x76,0x31,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
-0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x8C, 0xF7,0x06, 0x42,0xCC, 0xC7,0x18,
-0x70,0x00, 0xC7,0x38, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x94,0x96,
-0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0x6C, 0x24,0x14, 0x00,0x4E, 0x25,0x14, 0x00,0x50, 0x83,0x16, 0xFF,0x8C, 0x84,0x96,
-0xFF,0x7C, 0x87,0x1E, 0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x1C,
-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x29, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x4C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x4A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x48, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x46, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x44, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x42, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x40, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x86,0x96,
-0xFF,0xB0, 0xF6,0x06, 0x42,0xC8, 0xC6,0x18, 0x60,0x00, 0xF7,0x02, 0x00,0x03, 0xC6,0xB4,
-0x57,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
-0x6A,0x00, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xF4,0xB3, 0x28,0x00, 0x83,0x96,
-0xFF,0x8C, 0x83,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x14, 0x93,0x96, 0xFF,0x8C, 0x03,0x18,
-0x00,0x0C, 0x83,0x96, 0xFF,0xAC, 0x93,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
-0xD5,0xEC, 0x93,0x96, 0xFF,0xAC, 0x93,0x13, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
-0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x01,0xA0, 0xF5,0x02,
-0x00,0x00, 0xF3,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x1C, 0x20,0x2A, 0x00,0x63, 0xEE,0x00,
-0xDC,0x08, 0xC5,0x9C, 0x60,0x00, 0xA6,0x9E, 0x60,0x02, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x03, 0xE6,0x00,
-0xDB,0xFC, 0x07,0x2C, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0x06,0x30, 0x00,0x40, 0xE0,0x00,
-0xDB,0xCC, 0x05,0x28, 0x00,0x01, 0xF5,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x86,0xAE,
-0x00,0x08, 0xF4,0x02, 0x00,0x00, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xEC,0x00, 0xDC,0xF0, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x58,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x84,
-0x00,0x00, 0x83,0x16, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0x7C, 0xC5,0x20, 0x00,0x00, 0x86,0xB2,
-0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0xDC,0x80, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
-0xDC,0x8D, 0x00,0x00, 0x00,0x01, 0xF3,0x82, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x86,0xB2,
-0x00,0x00, 0x87,0x26, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0xDC,0xCC, 0xF5,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0xD4, 0x20,0x2A,
-0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x00, 0xDC,0xD5, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
-0x00,0x00, 0xE6,0x00, 0xDC,0xE5, 0x20,0x1E, 0x00,0x00, 0xF3,0x82, 0x00,0x01, 0x20,0x1E,
-0x00,0x00, 0xE6,0x00, 0xDC,0xF4, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xDD,0x29, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
-0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
-0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
-0xDD,0x98, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96,
-0xFE,0x70, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
-0xFE,0x70, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDD,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x2E, 0x00,0x08, 0xE0,0x00, 0xDD,0x9C, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xDD,0xB0, 0xF4,0x82,
-0x00,0x00, 0xF7,0x04, 0x42,0x7C, 0xE0,0x00, 0xE0,0x9C, 0xF6,0x06, 0x42,0x7E, 0x94,0x96,
-0xFF,0x44, 0x87,0x16, 0xFF,0xF4, 0xF6,0x04, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC7,0x30,
-0x70,0x00, 0x97,0x16, 0xFF,0x54, 0x06,0xB8, 0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16,
-0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x93,0x13,
-0xFF,0xFC, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC6,0x30, 0x70,0x00, 0x96,0x16,
-0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xDE,0x35, 0xF3,0x02, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00,
-0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDE,0x38, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
-0x00,0x01, 0x93,0x16, 0xFF,0x44, 0x84,0x96, 0xFF,0x44, 0x00,0x00, 0x00,0x01, 0x20,0x26,
-0x00,0x00, 0xE6,0x00, 0xDE,0x59, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0xE0,0x00,
-0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x83,0x16, 0xFF,0x4C, 0x86,0x16, 0xFF,0x4C, 0x87,0x1A,
-0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0xDE,0x85, 0x00,0x00, 0x00,0x01, 0xF6,0x04,
-0x4F,0x58, 0xF5,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
-0xE0,0x25, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00, 0x00,0x01, 0x06,0xA4,
-0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16, 0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC7,0x2C,
-0x70,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0xDE,0xDD, 0xF6,0x06, 0x42,0x80, 0xF7,0x04,
-0x42,0x80, 0xE0,0x00, 0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x26,0x14, 0x00,0x30, 0xF0,0x33,
-0x28,0x00, 0x87,0x16, 0xFF,0xD0, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
-0xFF,0x4C, 0x23,0x14, 0x00,0x2E, 0x93,0x16, 0xFE,0x64, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
-0xFF,0xE5, 0x93,0x16, 0xFF,0x34, 0x83,0x16, 0xFE,0x64, 0x04,0x24, 0x00,0x02, 0x06,0xA0,
-0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x3C, 0x74,0x95,
-0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x2C, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x24,0x94,
-0x00,0x2A, 0x94,0x96, 0xFE,0x64, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xD8, 0x23,0x14, 0x00,0x26, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
-0x00,0x1E, 0x84,0x96, 0xFF,0x3C, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96,
-0xFF,0x34, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x83,0x16, 0xFF,0x2C, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0xA0, 0xF7,0x37,
-0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x06,0xA0,
-0x00,0x02, 0xF7,0x04, 0x4F,0x58, 0xF0,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x14, 0x94,0x16,
-0xFF,0x24, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0,
-0x00,0x16, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x01, 0xF4,0xA3, 0x28,0x00, 0x94,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xE0,0xBC, 0x26,0x94, 0x00,0x48, 0xF7,0x04, 0x42,0x80, 0xE0,0x00,
-0xE0,0x9C, 0xF6,0x06, 0x42,0x82, 0x86,0x96, 0xFE,0xF4, 0xE0,0x00, 0xE2,0x94, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x42,0x84, 0xF6,0x06, 0x42,0x84, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0xEA,0xA4, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x4C, 0x75,0x15,
-0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x93,0x16, 0xFF,0x1C, 0x07,0x18, 0x00,0x36, 0xF4,0x82,
-0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0xF0,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB8, 0x76,0xB5,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0x18, 0x00,0x02, 0x06,0x20, 0x00,0x02, 0x23,0x14,
-0x00,0x46, 0x93,0x16, 0xFF,0x14, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x95,
-0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x0C, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
-0xFF,0xE5, 0x93,0x16, 0xFF,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
-0xFE,0xFC, 0x23,0x00, 0x00,0x07, 0x93,0x16, 0xFE,0xF4, 0x84,0x96, 0xFF,0x1C, 0x83,0x16,
-0xFF,0x14, 0x04,0xA4, 0x00,0x0A, 0x94,0x96, 0xFE,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xF6,0x84, 0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x87,0x1A,
-0x00,0x00, 0xC6,0xA4, 0x6A,0x00, 0x74,0x34, 0xFF,0xFA, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xBC, 0x23,0x14,
-0x00,0x42, 0x93,0x16, 0xFF,0x14, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30,
-0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
-0x00,0x02, 0x87,0x16, 0xFF,0xC0, 0x24,0x94, 0x00,0x3E, 0x94,0x96, 0xFF,0x14, 0x76,0xA5,
-0x00,0x1E, 0x83,0x16, 0xFF,0x0C, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16,
-0xFF,0xC4, 0x24,0x94, 0x00,0x3A, 0x94,0x96, 0xFF,0x14, 0x76,0xA5, 0x00,0x1E, 0x83,0x16,
-0xFF,0x04, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
-0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0x84,0x96, 0xFE,0xFC, 0x06,0x30,
-0x00,0x02, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x83,0x16,
-0xFE,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x07, 0xEE,0x00, 0xE2,0x94, 0xF6,0x82,
-0x00,0x08, 0x84,0x96, 0xFE,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x0E, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x47,0x21, 0x00,0x00, 0xC0,0x36,
-0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xE0,0x88, 0x04,0xA4,
-0x00,0x02, 0x94,0x96, 0xFE,0x7C, 0x03,0x18, 0x00,0x01, 0xE0,0x00, 0xE2,0x30, 0x93,0x16,
-0xFE,0xF4, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x38, 0xF6,0xBB,
-0x28,0x00, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x23,0x14,
-0x00,0x78, 0x93,0x16, 0xFE,0xBC, 0x84,0x96, 0x00,0x00, 0x23,0x14, 0x00,0xA8, 0x86,0xA6,
-0x00,0x04, 0x87,0x26, 0x00,0x00, 0x93,0x16, 0xFE,0x9C, 0xC6,0xB4, 0x70,0x00, 0x96,0x96,
-0xFE,0xEC, 0xF7,0x02, 0x00,0x01, 0xC7,0x34, 0x74,0x00, 0x97,0x16, 0xFE,0xE4, 0x84,0x96,
-0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD4,0xB4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x22,
-0x72,0x00, 0xE6,0x00, 0xEA,0xA1, 0x94,0x16, 0xFF,0x1C, 0x86,0xA2, 0x00,0x38, 0x77,0x21,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFE,0xD4, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x96,0x96, 0xFE,0xDC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
-0x00,0x01, 0x20,0x26, 0x00,0x0E, 0xEE,0x00, 0xE2,0xF0, 0xF3,0x02, 0x00,0x0F, 0x93,0x13,
-0xFF,0xFC, 0x83,0x16, 0xFE,0xEC, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x48,0x00, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x27,0xE8, 0x97,0x93, 0xFF,0xFC, 0xC3,0xA0,
-0x00,0x00, 0x84,0x96, 0xFE,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
-0xE3,0x8D, 0x23,0x9C, 0x00,0x07, 0xC3,0x80, 0x3A,0x00, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
-0xFF,0x1C, 0xF4,0x82, 0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC7,0x18, 0x70,0x00, 0x07,0x38,
-0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x97,0x16, 0xFE,0xC4, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x4C,0x00, 0x76,0xB5,
-0x00,0x06, 0xC3,0x30, 0x68,0x00, 0x07,0x30, 0x00,0x40, 0xC0,0x1A, 0x72,0x00, 0xE6,0x00,
-0xE4,0x0D, 0x93,0x16, 0xFE,0xCC, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFE,0x74, 0x96,0x16,
-0xFE,0x6C, 0x96,0x96, 0xFE,0x68, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
-0xFF,0xFC, 0x83,0x96, 0xFE,0x74, 0x86,0x16, 0xFE,0x6C, 0x86,0x96, 0xFE,0x68, 0x20,0x22,
-0x00,0x00, 0xE6,0x00, 0xE0,0x95, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x4F,0x58, 0x84,0x96,
-0xFE,0xCC, 0x07,0x2C, 0x00,0x40, 0xC0,0x26, 0x72,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00,
-0x00,0x01, 0xA7,0x32, 0x68,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x86,0x16,
-0xFE,0xCC, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
-0xE4,0x51, 0xC0,0x32, 0x5A,0x00, 0xC6,0x2C, 0x00,0x00, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
-0xE6,0xE5, 0x25,0x14, 0x00,0x76, 0x83,0x16, 0xFF,0x1C, 0x84,0x96, 0xFE,0xBC, 0x06,0x18,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16,
-0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x74, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x72, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x70, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6E, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6C, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6A, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x25,0x14, 0x00,0x68, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
-0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x60, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
-0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
-0xFF,0xA0, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
-0xFE,0x5C, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20,
-0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFE,0xAC, 0x83,0x16,
-0xFE,0x5C, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8,
-0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xB4, 0x74,0x95,
-0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
-0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xA4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA4, 0x24,0x94,
-0x00,0x5A, 0x94,0x96, 0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x83,0x16, 0xFE,0xB4, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA8, 0x24,0x94, 0x00,0x56, 0x94,0x96,
-0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x47,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0xAC, 0x23,0x14, 0x00,0x52, 0x93,0x16, 0xFE,0x5C, 0x76,0x19, 0x00,0x1E, 0x84,0x96,
-0xFE,0xAC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB0, 0x83,0x16, 0xFE,0xA4, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0x8C, 0xF7,0x37,
-0x28,0x00, 0x84,0x96, 0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x36, 0x94,0x96,
-0xFE,0x5C, 0x87,0x26, 0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFE,0xCC, 0x84,0x96,
-0xFF,0x1C, 0x06,0x18, 0x00,0x3A, 0x85,0xB2, 0x00,0x00, 0x07,0x24, 0x00,0x3A, 0x86,0xBA,
-0x00,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC5,0xAC, 0x67,0xC0, 0xC6,0xB4, 0x77,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0xB5,
-0xFF,0xF0, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x00, 0xE7,0x64, 0xF5,0x02, 0x00,0x02, 0xF5,0x02,
-0x00,0x01, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x36, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xE7,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x2A,
-0x00,0x01, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFE,0x5C, 0x83,0x16,
-0xFF,0x1C, 0xF5,0x27, 0x28,0x00, 0x06,0x18, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x25,0x14, 0x00,0xA6, 0x84,0x96, 0xFE,0x9C, 0x83,0x16,
-0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA4, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA2, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA0, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9E, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9C, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9A, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
-0x00,0x00, 0x25,0x14, 0x00,0x98, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
-0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x90, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
-0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
-0xFF,0x70, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x94, 0x00,0x8E, 0x75,0x9D,
-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16,
-0xFE,0x94, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
-0xFF,0xE5, 0x93,0x16, 0xFE,0x84, 0x83,0x16, 0xFE,0x94, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8, 0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
-0xFF,0xE5, 0x94,0x96, 0xFE,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
-0x28,0x00, 0x84,0x96, 0xFE,0xC4, 0x87,0x1E, 0x00,0x00, 0x75,0x25, 0x00,0x1E, 0xC7,0x38,
-0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0x74, 0x23,0x94, 0x00,0x8A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
-0xFE,0x8C, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
-0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x16, 0xFE,0x84, 0xC7,0x38,
-0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
-0xFF,0x78, 0x23,0x94, 0x00,0x86, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4,
-0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
-0x00,0x02, 0x87,0x16, 0xFF,0x7C, 0x23,0x94, 0x00,0x82, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
-0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFE,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0x80, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
-0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0xF3,0x02,
-0x00,0xFF, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xE8, 0xC6,0xB8, 0x34,0x00, 0xF7,0x02,
-0x00,0x80, 0xC7,0x34, 0x74,0x00, 0x77,0x39, 0x00,0x10, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
-0x00,0x00, 0xE6,0x00, 0xEA,0x61, 0x27,0x00, 0x01,0x00, 0xC6,0xB4, 0x75,0x80, 0x84,0x96,
-0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x38, 0xF6,0xBB, 0x28,0x00, 0x94,0x93,
-0xFF,0xFC, 0x83,0x16, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
-0x00,0x01, 0x04,0xA4, 0x00,0x01, 0xE0,0x00, 0xE3,0x3C, 0x94,0x96, 0xFE,0xD4, 0xF4,0x02,
-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
-0x00,0x08, 0x86,0x96, 0x00,0x0C, 0xF5,0x02, 0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x84,0x16,
-0x00,0x10, 0xF4,0x84, 0xE0,0x00, 0x07,0x30, 0x00,0x02, 0x94,0xB2, 0x00,0x10, 0xF4,0x84,
-0xE0,0x04, 0x06,0xB4, 0x00,0x03, 0x94,0xB2, 0x00,0x14, 0xF4,0x84, 0xE0,0x1C, 0xC6,0xB4,
-0x54,0x00, 0x94,0xB2, 0x00,0x18, 0xF4,0x82, 0x00,0x05, 0xF4,0xB3, 0x28,0x00, 0xF4,0x82,
-0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x27,0x34, 0x00,0x08, 0x97,0x32, 0x00,0x04, 0x86,0x16,
-0x00,0x00, 0x07,0x2C, 0x00,0x03, 0xC7,0x38, 0x54,0x00, 0xC6,0xB8, 0x68,0x00, 0x96,0x93,
-0xFF,0xFC, 0xC6,0x30, 0x72,0x00, 0x96,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0xAC,
-0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38, 0x5A,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xC1,0x20, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0x83,0xBA, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x93,0x96, 0xFF,0xF0, 0xF3,0x84,
-0x6E,0x54, 0x87,0x3A, 0x00,0x04, 0x93,0x96, 0xFF,0xEC, 0x97,0x16, 0xFF,0xF4, 0x90,0x13,
-0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x20, 0x97,0x13,
-0xFF,0xFC, 0x94,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
-0xFF,0xFC, 0x84,0x96, 0xFF,0xE4, 0x83,0x96, 0x00,0x08, 0x87,0x26, 0x00,0x18, 0x85,0x16,
-0xFF,0xEC, 0xC0,0x3A, 0x3A,0x00, 0xEE,0x00, 0xEC,0x7C, 0xF5,0x82, 0x00,0x01, 0x87,0x26,
-0x00,0x18, 0x83,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x72,0x00, 0xE6,0x00,
-0xEC,0x7C, 0xC5,0x84, 0x00,0x00, 0x86,0xA6, 0x00,0x10, 0x87,0x16, 0xFF,0xF0, 0xF6,0x02,
-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x1C, 0x04,0x24, 0x00,0x10, 0x86,0xA6,
-0x00,0x14, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
-0xEC,0x20, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0xEC,0x2D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xA2, 0x00,0x00, 0x87,0x16,
-0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEC,0x68, 0xF6,0x02,
-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x70, 0x20,0x32, 0x00,0x00, 0x86,0xA2,
-0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
-0xEC,0x71, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0xEC,0x81, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
-0xEC,0xAC, 0xF7,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0x9C, 0xF6,0x06, 0x42,0x9C, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x02, 0x00,0x01, 0x97,0x2A, 0x00,0x08, 0x83,0xA6,
-0x00,0x0C, 0x77,0x2C, 0xFF,0xE1, 0x93,0xAA, 0x00,0x0C, 0x97,0x2A, 0x00,0x1C, 0x83,0xA6,
-0x00,0x1C, 0xF7,0x04, 0x6E,0x50, 0x93,0xAA, 0x00,0x20, 0x83,0xBA, 0x1D,0xDC, 0xF6,0x82,
-0x00,0x00, 0x93,0xAA, 0x00,0x2C, 0x83,0x96, 0x00,0x0C, 0xC5,0xB4, 0x00,0x00, 0x93,0xAA,
-0x00,0x30, 0x83,0xBA, 0x00,0x10, 0xC6,0x34, 0x00,0x00, 0x93,0xAA, 0x00,0x24, 0x87,0x3A,
-0x00,0x14, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x28, 0x20,0x36, 0x00,0x1F, 0xEE,0x00,
-0xED,0x1C, 0xC7,0x30, 0x50,0x00, 0x07,0x38, 0x00,0x34, 0x95,0xBA, 0x00,0x00, 0x06,0x30,
-0x00,0x04, 0xE0,0x00, 0xEC,0xFC, 0x06,0xB4, 0x00,0x01, 0x83,0x96, 0x00,0x10, 0x76,0xA5,
-0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0xB4, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
-0xFF,0xFC, 0x87,0x26, 0x00,0x20, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x86,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x16,
-0xFF,0xF0, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0xF6,0x02,
-0x1D,0xE0, 0x96,0x13, 0xFF,0xFC, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x13,
-0xFF,0xFC, 0xF6,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x26,0x14,
-0x00,0x10, 0x96,0x16, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x00, 0x87,0x36, 0x1D,0xD8, 0x96,0x16,
-0xFF,0xE4, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF6,0x86, 0x42,0xC0, 0xF7,0x37, 0x28,0x00, 0x86,0x16, 0xFF,0xEC, 0x00,0x00,
-0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xDB,0xB4, 0x97,0x93,
-0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00, 0x00,0x01, 0x86,0x16,
-0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00,
-0x00,0x01, 0xF6,0x02, 0x00,0x01, 0x96,0x16, 0xFF,0xE4, 0x84,0x16, 0xFF,0xE4, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x04, 0x86,0x16,
-0x00,0x00, 0x87,0x36, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xEE,0x99, 0x20,0x3A, 0x00,0x03, 0xE6,0x00, 0xEE,0xE9, 0xF4,0x02, 0x00,0x00, 0xE0,0x00,
-0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0xEF,0x0D, 0xF4,0x02, 0x00,0x00, 0x85,0x16, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x95,0x13,
-0xFF,0xFC, 0x85,0x16, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
-0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x96,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEB,0x60, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0xEF,0x0D, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xED,0x74, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x18, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF4,0x82, 0x00,0x00, 0x86,0x96,
-0x00,0x00, 0xF6,0x04, 0x4A,0xA0, 0x23,0x94, 0x00,0x10, 0x84,0x36, 0x00,0x00, 0x96,0x16,
-0xFF,0xE4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16, 0xFF,0xF0, 0x85,0x36, 0x00,0x04, 0xC0,0x32,
-0x72,0x00, 0xEC,0x00, 0xF0,0x14, 0x95,0x16, 0xFF,0xF4, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
-0x60,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4,
-0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x42,0x00, 0xE6,0x00, 0xEF,0xA4, 0xC6,0x24, 0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0xEF,0xA8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xEF,0xB5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
-0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
-0x72,0x00, 0xE2,0x00, 0xEF,0xF0, 0xF5,0x02, 0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00,
-0xEF,0xF8, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEF,0xF9, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
-0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xF0,0x09, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xF0,0x18, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
-0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xF0,0x4D, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xE8, 0xE0,0x00, 0xF0,0xB0, 0x96,0x96, 0xFF,0xEC, 0x27,0x14, 0x00,0x1C, 0x97,0x13,
-0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
-0xF0,0xAD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xE8, 0x96,0x96, 0xFF,0xEC, 0xF7,0x05,
-0x4A,0xA0, 0xE0,0x00, 0xF0,0xB4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
-0x00,0x00, 0xE6,0x00, 0xF1,0x21, 0xF4,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE8, 0xF6,0x06,
-0x42,0xC8, 0x76,0xB9, 0x00,0x02, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xA7,0x36,
-0x60,0x02, 0x83,0x16, 0x00,0x04, 0xC6,0xB4, 0x60,0x00, 0x76,0x35, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x05,0x34, 0x00,0x02, 0x75,0xA9, 0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
-0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x83,0x16,
-0x00,0x08, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x83,0x16,
-0x00,0x0C, 0x06,0xB4, 0x00,0x04, 0xE0,0x00, 0xF1,0x24, 0x96,0x9A, 0x00,0x00, 0xF4,0x02,
-0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0xB9,0x00, 0x00,0x00, 0xBA,0x00, 0x00,0x00,
-0xBB,0x00, 0x00,0x00, 0xBC,0x00, 0x00,0x00, 0xBD,0x00, 0x00,0x00, 0xBE,0x00, 0x00,0x00,
-0xBF,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x81,0x00, 0x00,0x00, 0x82,0x00, 0x00,0x00,
-0x83,0x00, 0x00,0x00, 0x84,0x00, 0x00,0x00, 0x85,0x00, 0x00,0x00, 0x86,0x00, 0x00,0x00,
-0x87,0x00, 0xB9,0xB9, 0xB9,0xBA, 0xB9,0xBB, 0xB9,0xBC, 0xB9,0xBD, 0xB9,0xBE, 0xB9,0xBF,
-0xB9,0x80, 0xB9,0x81, 0xB9,0x82, 0xB9,0x83, 0xB9,0x84, 0xB9,0x85, 0xB9,0x86, 0xB9,0x87,
-0xBA,0xB9, 0xBA,0xBA, 0xBA,0xBB, 0xBA,0xBC, 0xBA,0xBD, 0xBA,0xBE, 0xBA,0xBF, 0xBA,0x80,
-0xBA,0x81, 0xBA,0x82, 0xBA,0x83, 0xBA,0x84, 0xBA,0x85, 0xBA,0x86, 0xBA,0x87, 0xBB,0xB9,
-0xBB,0xBA, 0xBB,0xBB, 0xBB,0xBC, 0xBB,0xBD, 0xBB,0xBE, 0xBB,0xBF, 0xBB,0x80, 0xBB,0x81,
-0xBB,0x82, 0xBB,0x83, 0xBB,0x84, 0xBB,0x85, 0xBB,0x86, 0xBB,0x87, 0xBC,0xB9, 0xBC,0xBA,
-0xBC,0xBB, 0xBC,0xBC, 0xBC,0xBD, 0xBC,0xBE, 0xBC,0xBF, 0xBC,0x80, 0xBC,0x81, 0xBC,0x82,
-0xBC,0x83, 0xBC,0x84, 0xBC,0x85, 0xBC,0x86, 0xBC,0x87, 0xBD,0xB9, 0xBD,0xBA, 0xBD,0xBB,
-0xBD,0xBC, 0xBD,0xBD, 0xBD,0xBE, 0xBD,0xBF, 0xBD,0x80, 0xBD,0x81, 0xBD,0x82, 0xBD,0x83,
-0xBD,0x84, 0xBD,0x85, 0xBD,0x86, 0xBD,0x87, 0xBE,0xB9, 0xBE,0xBA, 0xBE,0xBB, 0xBE,0xBC,
-0xBE,0xBD, 0xBE,0xBE, 0xBE,0xBF, 0xBE,0x80, 0xBE,0x81, 0xBE,0x82, 0xBE,0x83, 0xBE,0x84,
-0xBE,0x85, 0xBE,0x86, 0xBE,0x87, 0xBF,0xB9, 0xBF,0xBA, 0xBF,0xBB, 0xBF,0xBC, 0xBF,0xBD,
-0xBF,0xBE, 0xBF,0xBF, 0xBF,0x80, 0xBF,0x81, 0xBF,0x82, 0xBF,0x83, 0xBF,0x84, 0xBF,0x85,
-0xBF,0x86, 0xBF,0x87, 0x80,0xB9, 0x80,0xBA, 0x80,0xBB, 0x80,0xBC, 0x80,0xBD, 0x80,0xBE,
-0x80,0xBF, 0x80,0x80, 0x80,0x81, 0x80,0x82, 0x80,0x83, 0x80,0x84, 0x80,0x85, 0x80,0x86,
-0x80,0x87, 0x81,0xB9, 0x81,0xBA, 0x81,0xBB, 0x81,0xBC, 0x81,0xBD, 0x81,0xBE, 0x81,0xBF,
-0x81,0x80, 0x81,0x81, 0x81,0x82, 0x81,0x83, 0x81,0x84, 0x81,0x85, 0x81,0x86, 0x81,0x87,
-0x82,0xB9, 0x82,0xBA, 0x82,0xBB, 0x82,0xBC, 0x82,0xBD, 0x82,0xBE, 0x82,0xBF, 0x82,0x80,
-0x82,0x81, 0x82,0x82, 0x82,0x83, 0x82,0x84, 0x82,0x85, 0x82,0x86, 0x82,0x87, 0x83,0xB9,
-0x83,0xBA, 0x83,0xBB, 0x83,0xBC, 0x83,0xBD, 0x83,0xBE, 0x83,0xBF, 0x83,0x80, 0x83,0x81,
-0x83,0x82, 0x83,0x83, 0x83,0x84, 0x83,0x85, 0x83,0x86, 0x83,0x87, 0x84,0xB9, 0x84,0xBA,
-0x84,0xBB, 0x84,0xBC, 0x84,0xBD, 0x84,0xBE, 0x84,0xBF, 0x84,0x80, 0x84,0x81, 0x84,0x82,
-0x84,0x83, 0x84,0x84, 0x84,0x85, 0x84,0x86, 0x84,0x87, 0x85,0xB9, 0x85,0xBA, 0x85,0xBB,
-0x85,0xBC, 0x85,0xBD, 0x85,0xBE, 0x85,0xBF, 0x85,0x80, 0x85,0x81, 0x85,0x82, 0x85,0x83,
-0x85,0x84, 0x85,0x85, 0x85,0x86, 0x85,0x87, 0x86,0xB9, 0x86,0xBA, 0x86,0xBB, 0x86,0xBC,
-0x86,0xBD, 0x86,0xBE, 0x86,0xBF, 0x86,0x80, 0x86,0x81, 0x86,0x82, 0x86,0x83, 0x86,0x84,
-0x86,0x85, 0x86,0x86, 0x86,0x87, 0x87,0xB9, 0x87,0xBA, 0x87,0xBB, 0x87,0xBC, 0x87,0xBD,
-0x87,0xBE, 0x87,0xBF, 0x87,0x80, 0x87,0x81, 0x87,0x82, 0x87,0x83, 0x87,0x84, 0x87,0x85,
-0x87,0x86, 0x87,0x87, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x18, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xF3,0x7D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0xF5,0xE0, 0xF7,0x33, 0x28,0x00, 0xF3,0x84, 0x6F,0x30, 0x90,0x13,
-0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0xF7,0x02, 0x00,0x00, 0x97,0x1E,
-0x00,0x08, 0x83,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0x1E, 0x00,0x0C, 0x83,0x16,
-0x00,0x08, 0x04,0x9C, 0x00,0x22, 0x93,0x1E, 0x00,0x1C, 0x83,0x16, 0x00,0x0C, 0x93,0x96,
-0xFF,0xF4, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x18,
-0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0x06,0x9C, 0x00,0x20, 0xF7,0x37, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x96,0x96,
-0xFF,0xE4, 0x75,0x35, 0x00,0x1E, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x04,0x9C, 0x00,0x24, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x04,0x9C, 0x00,0x26, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x04,0x9C, 0x00,0x28, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x04,0x9C, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x04,0x9C, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x04,0x9C, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x04,0x9C, 0x00,0x30, 0x76,0x31,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
-0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00, 0xF5,0x98, 0xF3,0x06, 0x14,0xD8, 0x83,0x16,
-0xFF,0xE4, 0x87,0x1E, 0x00,0x20, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x25,0xB8, 0x00,0x01, 0xC4,0xAC, 0x58,0x00, 0x04,0x24,
-0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xF5,0x95, 0xF5,0x02, 0x00,0x00, 0x83,0x16,
-0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x06,0x18, 0x00,0x02, 0xA7,0x32, 0x58,0x02, 0xC6,0xB0,
-0x58,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xE8, 0xC6,0xB0, 0x40,0x00, 0x77,0xB8, 0x00,0x18, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
-0xF5,0x7D, 0xF7,0x37, 0x68,0x00, 0xF5,0x02, 0xFF,0xFF, 0xC7,0x30, 0x48,0x00, 0xF5,0x3B,
-0x68,0x00, 0x24,0xA4, 0x00,0x02, 0x24,0x20, 0x00,0x02, 0xE0,0x00, 0xF5,0x34, 0x25,0xAC,
-0x00,0x01, 0xF3,0x06, 0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x34, 0x93,0x13,
-0xFF,0xFC, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF7,0x04,
-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xF6,0x39, 0xF6,0x06,
-0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
-0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
-0xF7,0x48, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00, 0x00,0x01, 0x95,0x16,
-0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
-0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00, 0xF6,0x99, 0x96,0x96,
-0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x85,0x16,
-0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28, 0x72,0x00, 0x97,0x13,
-0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0xF7,0x02,
-0x00,0x02, 0x97,0x2A, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xAA,
-0x00,0x0C, 0x85,0x96, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0xAA, 0x00,0x1C, 0xF5,0x06,
-0x14,0xD8, 0x95,0x13, 0xFF,0xFC, 0xF5,0x82, 0x00,0x20, 0x95,0x93, 0xFF,0xFC, 0x85,0x16,
-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16,
-0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0x00,0x04, 0x87,0x16, 0x00,0x08, 0xF6,0x02,
-0xFF,0xFC, 0x06,0xA8, 0x00,0x03, 0xC6,0xB4, 0x64,0x00, 0x07,0x38, 0x00,0x03, 0xC7,0x38,
-0x64,0x00, 0xC7,0x34, 0x70,0x00, 0x97,0x13, 0xFF,0xFC, 0xC5,0xAC, 0x6A,0x00, 0x95,0x93,
-0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0x28, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
-0x52,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x14,0xD8, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x10, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xF8,0x0D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0xF9,0x20, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00,
-0x00,0x01, 0x95,0x16, 0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
-0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02,
-0x00,0x00, 0x86,0xAA, 0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00,
-0xF8,0x6D, 0x96,0x96, 0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96,
-0xFF,0xEC, 0x85,0x16, 0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28,
-0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
-0xFF,0xF4, 0xF5,0x82, 0x00,0x06, 0xF5,0xAB, 0x28,0x00, 0x85,0x96, 0x00,0x08, 0x07,0x28,
-0x00,0x02, 0x95,0xAA, 0x00,0x04, 0x05,0x14, 0x00,0x0E, 0x85,0x2A, 0x00,0x00, 0x77,0xA9,
-0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0xF5,0x3B,
-0x28,0x00, 0xF5,0x86, 0x14,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF5,0x02, 0x00,0x08, 0x95,0x13,
-0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
-0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04,
-0x75,0xEC, 0x83,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xFA,0x64, 0xF6,0x06,
-0x42,0x96, 0xF5,0x04, 0x6F,0x30, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
-0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0xF4, 0x95,0x16, 0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
-0xFF,0xFC, 0x85,0x16, 0xFF,0xF0, 0xF3,0x02, 0x00,0x07, 0x83,0x96, 0xFF,0xF4, 0xF3,0x2B,
-0x28,0x00, 0x07,0x28, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x3B, 0x28,0x00, 0x87,0x1E,
-0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x76,0x2D,
-0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x04,0x1C,
-0x00,0x06, 0x83,0x16, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x06,0xA8,
-0x00,0x04, 0xF7,0x37, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0xA8, 0x00,0x06, 0x75,0xA1,
-0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
-0x00,0x04, 0x75,0xAC, 0xFF,0xE5, 0x06,0xA8, 0x00,0x08, 0x76,0x19, 0x00,0x1E, 0xC7,0x38,
-0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x06,0xA8,
-0x00,0x0A, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x06,
-0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x0C, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
-0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xFA,0x84, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
-0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
-0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x48, 0xF7,0x04, 0x75,0xEC, 0x85,0x96, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
-0xFD,0x98, 0xF6,0x06, 0x42,0x96, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x14, 0x00,0x1E, 0x06,0x2C, 0x00,0x02, 0x75,0x31,
-0x00,0x1E, 0x24,0x94, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xF3,0x84, 0x6E,0x50, 0xC7,0x38,
-0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x93,0x96,
-0xFF,0xC4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
-0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
-0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x90,0x13,
-0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
-0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
-0xFF,0xBC, 0x23,0x14, 0x00,0x36, 0x24,0x94, 0x00,0x38, 0x73,0xA5, 0x00,0x1E, 0x73,0x9C,
-0xFF,0xE5, 0xF4,0x04, 0x42,0xC0, 0xF6,0x86, 0x42,0xC0, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0x87,0x2E, 0x00,0x00, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC4,0x20,
-0x6F,0xC0, 0x74,0x20, 0xFF,0xF0, 0x05,0xAC, 0x00,0x02, 0x75,0x2D, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2E,
-0x00,0x00, 0xF6,0x04, 0x6E,0x50, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x23,0x14, 0x00,0x34, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x23,0x14, 0x00,0x32, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x23,0x14, 0x00,0x30, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x23,0x14, 0x00,0x2E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x23,0x14, 0x00,0x2C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x23,0x14, 0x00,0x2A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x28, 0x75,0xAD,
-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
-0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0xF6,0x82, 0x00,0x03, 0xC7,0x38, 0x3F,0xC0, 0x96,0xB2,
-0x00,0x08, 0x06,0xB0, 0x1D,0xD8, 0xF4,0x37, 0x28,0x00, 0xF3,0x86, 0x14,0xD8, 0x93,0x93,
-0xFF,0xFC, 0xF3,0x82, 0x1D,0xE0, 0x93,0x93, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x77,0x39,
-0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
-0xFD,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
-0x00,0x06, 0xE6,0x00, 0xFE,0x21, 0xF5,0x82, 0x00,0x1E, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06,
-0x42,0xA8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
-0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0xFE,0x34, 0xF7,0x33, 0x28,0x00, 0xF6,0x05,
-0x6F,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
-0x00,0x00, 0x85,0x96, 0x00,0x04, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00,
-0xFE,0x9D, 0xF4,0x02, 0x00,0x00, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06, 0x42,0xAA, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xE0,0x00, 0xFF,0x1C, 0xF7,0x33, 0x28,0x00, 0x07,0x30, 0x00,0x02, 0x86,0xBA,
-0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
-0xFF,0xF0, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xFE,0xD5, 0xF6,0x05, 0x6F,0x34, 0x20,0x36,
-0x00,0x02, 0xE6,0x00, 0xFE,0xE5, 0xF5,0x02, 0x00,0x20, 0xE0,0x00, 0xFE,0xFC, 0xF6,0x06,
-0x42,0xAC, 0x20,0x2E, 0x00,0x0C, 0xE6,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x00, 0xF5,0x02,
-0x00,0x1F, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x08, 0x97,0x36, 0x00,0x04, 0x87,0x36,
-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0xFF,0x7D, 0xF6,0x85,
-0x6F,0x34, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x03, 0xEE,0x00,
-0xFF,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
-0xFF,0xBD, 0xF6,0x06, 0x42,0xAE, 0xF7,0x04, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
-0x00,0x08, 0xF6,0x82, 0xFF,0xEC, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x00,0x00,
-0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x00, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
-0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
-0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x17, 0x00,0x00,
-0x00,0x1A, 0x00,0x00, 0x00,0x1D, 0x00,0x00, 0x00,0x18, 0x00,0x00, 0x00,0x00, 0x56,0x65,
-0x72,0x73, 0x69,0x6F, 0x6E,0x53, 0x74,0x72, 0x69,0x6E, 0x67,0x3A, 0x20,0x6D, 0x63,0x70,
-0x2D,0x6C, 0x34,0x76, 0x33,0x20, 0x33,0x2E, 0x30,0x38, 0x63,0x20, 0x44,0x65, 0x63,0x20,
-0x31,0x31, 0x20,0x31, 0x39,0x39, 0x36,0x20, 0x31,0x33, 0x3A,0x30, 0x36,0x3A, 0x31,0x36,
-0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x0C, 0xFF,0x02,
-0x00,0x00, 0x97,0x02, 0xFF,0x84, 0xF7,0x06, 0x0C,0x3E, 0xCF,0xFC, 0x75,0x80, 0xF6,0x02,
-0x00,0x02, 0x96,0x02, 0xFF,0x8C, 0x90,0x02, 0xFF,0x88, 0xF7,0x04, 0xE0,0x20, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x00,0x74, 0xF6,0x82, 0x00,0x00, 0xF6,0x82,
-0x00,0x03, 0x96,0x82, 0xFF,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x0C, 0xF5,0x02, 0x14,0x94, 0xF5,0x05, 0x7B,0x00, 0xF5,0x0E,
-0xF0,0x14, 0xF5,0x05, 0x7B,0x08, 0xF7,0x06, 0xE0,0x00, 0xF6,0x86, 0x7B,0x68, 0xC7,0x38,
-0x6A,0x00, 0xF7,0x05, 0x7A,0xF0, 0xF5,0x02, 0x00,0x4C, 0xF6,0x82, 0x00,0x00, 0x20,0x36,
-0x00,0x02, 0xEE,0x01, 0x01,0x24, 0xF5,0x05, 0x7A,0xF8, 0xC5,0xB4, 0x00,0x00, 0xC6,0x34,
-0x00,0x00, 0xF7,0x06, 0xE0,0x30, 0xC7,0x2C, 0x70,0x00, 0xF5,0x06, 0x6F,0x44, 0xB7,0x32,
-0x50,0x02, 0x90,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
-0xFF,0xF0, 0x96,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93,
-0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x86,0x16, 0xFF,0xF0, 0x86,0x96, 0xFF,0xEC, 0x05,0xAC,
-0x14,0x94, 0x06,0xB4, 0x00,0x01, 0x20,0x36, 0x00,0x02, 0xEE,0x01, 0x00,0xD5, 0x06,0x30,
-0x00,0x04, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF0,0x05,
-0x6F,0x50, 0xF0,0x05, 0x2D,0x40, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x29,0x58, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
-0x00,0x03, 0xF7,0x05, 0xE0,0x08, 0xF7,0x04, 0x7A,0xD8, 0xF6,0x02, 0x00,0x01, 0x96,0x02,
-0xFF,0x94, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x01,0x91, 0xF7,0x06, 0x7A,0xE8, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x03,0xDC, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7A,0xE8, 0xF6,0x02,
-0x00,0x05, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06, 0x7A,0xE0, 0x86,0x82, 0xFF,0x44, 0xF6,0x02,
-0x00,0x03, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x01,0xC9, 0xF6,0x3B, 0x28,0x00, 0xF7,0x04,
-0x6F,0x64, 0x86,0x82, 0xFF,0x44, 0x07,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
-0x01,0xB0, 0xF7,0x05, 0x6F,0x64, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x34, 0x97,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x8C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x44,0x28, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0xF0, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x0C,0x60, 0x97,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x04,0x08, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x0B,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1D,0x68, 0x97,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0x50, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x5F,0x68, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x6D,0xEC, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x21,0xD0, 0x97,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x22,0x2C, 0x97,0x93, 0xFF,0xFC, 0x90,0x02,
-0xFF,0x94, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x0B,0xFC, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02,
-0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x08, 0xF6,0x02, 0x00,0x00, 0xC5,0xB0, 0x00,0x00, 0x20,0x32, 0x00,0x02, 0xEE,0x01,
-0x03,0x08, 0xF5,0x06, 0x6F,0x44, 0xA6,0xAE, 0x50,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xE6,0x01, 0x02,0xFC, 0xF5,0x02,
-0x00,0x02, 0x95,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
-0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
-0xFF,0xF0, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x04, 0xE0,0x01,
-0x02,0xAC, 0x06,0x30, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x87,0x16, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x82, 0x00,0x08, 0x96,0x3A,
-0x00,0x08, 0x96,0x3A, 0x00,0x0C, 0x96,0x3A, 0x09,0xD8, 0x96,0x3A, 0x09,0xDC, 0x96,0x3A,
-0x0E,0xF4, 0x96,0x3A, 0x0E,0xF8, 0x96,0xBA, 0x14,0x20, 0x96,0x3A, 0x14,0x24, 0x90,0xBA,
-0x14,0x8C, 0x86,0x96, 0x00,0x04, 0x90,0xBA, 0x14,0x90, 0x96,0xBA, 0x00,0x00, 0x96,0x3A,
-0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
-0x00,0x00, 0x87,0x16, 0x00,0x08, 0x86,0x16, 0x00,0x04, 0x77,0x38, 0xFF,0xFF, 0xC5,0x30,
-0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x03,0xC9, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE4,0x01,
-0x03,0xA0, 0x05,0xAC, 0x00,0x02, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xE0,0x01, 0x03,0xE8, 0xF7,0x05, 0x7A,0xD8, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02,
-0x00,0x0A, 0xF5,0x05, 0x71,0xCC, 0xF0,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD0, 0xF0,0x05,
-0x71,0xC4, 0xF5,0x02, 0x00,0x01, 0xF6,0x82, 0x00,0x00, 0x20,0x36, 0x00,0x0A, 0xEC,0x01,
-0x04,0x64, 0xF5,0x05, 0x71,0xC8, 0xF5,0x8A, 0x1E,0x00, 0xF6,0x06, 0x71,0xC4, 0x47,0x2C,
-0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30, 0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04,
-0x71,0xCC, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x04,0x41, 0x05,0xAC,
-0x21,0x4C, 0xF0,0x05, 0x71,0x98, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
-0x7B,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x06, 0x05,0xD4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0xA0, 0x95,0x13,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x70,0x80, 0x95,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
-0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
-0x70,0x80, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x06, 0x05,0x58, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x0A, 0x95,0x13,
-0xFF,0xFC, 0xF5,0x06, 0x71,0x0C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
-0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0x7D, 0xF6,0x86,
-0x71,0xC4, 0xE0,0x01, 0x05,0x94, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x71,0xD0, 0x00,0x00,
-0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0xAC, 0xF7,0x05, 0x7B,0x10, 0xF6,0x06,
-0x71,0x0C, 0xE0,0x01, 0x05,0xC0, 0xF6,0x05, 0x7B,0x18, 0xF6,0x06, 0x6F,0x68, 0xF6,0x05,
-0x7B,0x18, 0x97,0x02, 0xFF,0x48, 0x07,0x38, 0x21,0x28, 0x97,0x02, 0xFF,0x4C, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0x86,0x82,
-0xFF,0x48, 0xF4,0x86, 0x6F,0x68, 0xF4,0x85, 0x7B,0x18, 0xF5,0x04, 0x7B,0x10, 0x26,0xB4,
-0x00,0x02, 0x85,0xB6, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x76,0x29, 0x00,0x1E, 0x76,0x30,
-0xFF,0xE5, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x6F,0xC0, 0xC7,0x38,
-0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0xB8, 0x00,0x10, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x06,0x45, 0x75,0xAC, 0xFF,0xF0, 0xF7,0x04, 0x71,0xAC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x71,0xAC, 0xF7,0x04, 0x71,0xAC, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
-0x00,0x01, 0x77,0x2C, 0xFF,0xF8, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x06,0x71, 0x76,0xA9,
-0x00,0x1E, 0xF7,0x04, 0x71,0xA8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x71,0xA8, 0xF7,0x04, 0x71,0xA8, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A,
-0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38,
-0x00,0x04, 0x20,0x3A, 0x00,0x03, 0xE2,0x01, 0x08,0xA4, 0x00,0x00, 0x00,0x01, 0x77,0x39,
-0x00,0x02, 0xF6,0x86, 0x06,0xA4, 0xA6,0xB6, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34,
-0x00,0x00, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x07,0x7C, 0x00,0x01, 0x07,0xEC, 0x00,0x01,
-0x08,0x44, 0x87,0x2A, 0x00,0x04, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x01,
-0x06,0xD8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
-0x52,0x00, 0x97,0x2A, 0x00,0x04, 0x87,0x2A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x21,0x00, 0xEE,0x01, 0x07,0x3C, 0xF6,0x02, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0x87,0x02,
-0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x28, 0xC0,0x36,
-0x72,0x00, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x01, 0x07,0x3D, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E,
-0xFF,0xE1, 0xE6,0x01, 0x07,0x44, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x01, 0x08,0x88, 0x00,0x00, 0x00,0x01, 0x87,0x2A, 0x00,0x18, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xEE,0x01, 0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x71,0xA4, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xA4, 0xF7,0x04,
-0x71,0xA4, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x21,0x00, 0xEE,0x01, 0x07,0xE0, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
-0x00,0x04, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38,
-0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
-0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
-0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE1, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
-0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
-0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x04, 0x20,0x3A, 0x00,0x08, 0xE6,0x01,
-0x08,0x38, 0xF6,0x82, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x08,0x38, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x08,0x39, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x08,0x80, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x36,
-0x00,0x00, 0xF7,0x02, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x08,0x78, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x08,0x79, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
-0x08,0x80, 0x20,0x3A, 0x00,0x00, 0xF7,0x02, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xA0, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x71,0xA0, 0xF7,0x04, 0x71,0xA0, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
-0x00,0x01, 0xF7,0x04, 0x71,0x9C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x71,0x9C, 0xF7,0x04, 0x71,0x9C, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x68, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
-0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
-0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38, 0x00,0x04, 0x20,0x3A,
-0x00,0x03, 0xE2,0x01, 0x0B,0x50, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x09,0x0C, 0xA6,0xB6,
-0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x01, 0x09,0x1C, 0x00,0x01,
-0x0A,0xE0, 0x00,0x01, 0x0A,0xAC, 0x00,0x01, 0x0B,0x14, 0xF7,0x04, 0x71,0xD0, 0xF6,0x04,
-0x71,0xCC, 0x06,0xB8, 0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0x38, 0xC7,0x34,
-0x00,0x00, 0xF7,0x02, 0x00,0x00, 0xF5,0x84, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x85, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x71,0xB0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x71,0xB0, 0xF7,0x04, 0x71,0xB0, 0xF7,0x04, 0x71,0xB4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x71,0xB4, 0xF7,0x04, 0x71,0xB4, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
-0x00,0x01, 0xF4,0x84, 0x71,0xC8, 0xF6,0x85, 0x71,0xD0, 0x94,0x96, 0xFF,0xF4, 0xF4,0x84,
-0x7B,0x10, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0xA4, 0x94,0x96, 0xFF,0xEC, 0xF0,0x05,
-0x71,0xD0, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC8, 0x84,0x96, 0xFF,0xEC, 0xC0,0x3A,
-0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0xF7,0x05, 0x71,0xC4, 0x87,0x26, 0x00,0x08, 0x00,0x00,
-0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x09,0xE1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x71,0x98, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0x98, 0x84,0x96,
-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x0A,0x71, 0x00,0x00,
-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0xF6,0x02,
-0x00,0x09, 0x20,0x32, 0x00,0x14, 0xE6,0x01, 0x0A,0x4D, 0x27,0x00, 0x00,0x0C, 0x20,0x3A,
-0x00,0x01, 0xE2,0x01, 0x0A,0x4D, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00,
-0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
-0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x01,
-0x0A,0x4D, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x04, 0x2D,0x68, 0x00,0x00,
-0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x28, 0x00,0x00,
-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
-0x71,0xBC, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xBC, 0xF7,0x04,
-0x71,0xBC, 0x86,0xA6, 0x00,0x04, 0x84,0x96, 0xFF,0xF4, 0xF7,0x04, 0x71,0xB8, 0x20,0x26,
-0x00,0x00, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x71,0xB8, 0xE6,0x01, 0x0B,0x51, 0x00,0x00,
-0x00,0x01, 0xE0,0x01, 0x0B,0x5C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00,
-0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF4,0x84,
-0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0xFD,0xCC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04,
-0x71,0xC0, 0xF4,0x84, 0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0xFF,0x30, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF6,0x84, 0x7B,0x10, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
-0x00,0x01, 0xC7,0x38, 0x6A,0x00, 0x27,0x38, 0x00,0x04, 0x97,0x13, 0xFF,0xFC, 0x96,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFE,0x48, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x70,0x80, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x6F,0x68, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x6F,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x6F,0xF4, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x70,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x71,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02, 0x00,0x04, 0xF5,0x05, 0x76,0x00, 0xF0,0x05,
-0x76,0x08, 0xF0,0x05, 0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF5,0x02, 0x00,0x01, 0xF6,0x82,
-0x00,0x00, 0x20,0x36, 0x00,0x04, 0xEC,0x01, 0x0C,0xBC, 0xF5,0x05, 0x75,0xFC, 0xF5,0x8E,
-0x6A,0xF8, 0xF6,0x06, 0x75,0xF8, 0x47,0x2C, 0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30,
-0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xEC,0x01, 0x0C,0x99, 0x05,0xAC, 0x21,0x4C, 0xF5,0x06, 0x72,0x18, 0x95,0x13,
-0xFF,0xFC, 0xF5,0x06, 0x76,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0xA4, 0x95,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
-0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
-0x73,0x30, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x06, 0x16,0xC8, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93,
-0xFF,0xFC, 0xF5,0x06, 0x73,0xBC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x18,0x00, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
-0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x16,0x40, 0x95,0x13,
-0xFF,0xFC, 0xF7,0x82, 0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0xD4, 0x95,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
-0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x12, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
-0x75,0x60, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
-0xFF,0xFC, 0xF0,0x05, 0x75,0xF0, 0xF0,0x05, 0x75,0xEC, 0xF0,0x05, 0x75,0xF4, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x28, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x0E,0x3D, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x59, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01,
-0x0E,0x6C, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39,
-0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04, 0x76,0xFC, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x90, 0xF6,0x85, 0x76,0x60, 0xF3,0x06,
-0x76,0x48, 0xF3,0x05, 0x76,0xFC, 0xE0,0x01, 0x0E,0xA4, 0xF7,0x02, 0x00,0x01, 0xF3,0x02,
-0x00,0x10, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x76,0x48, 0xF3,0x05, 0x77,0x00, 0xF7,0x02,
-0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x15, 0xF3,0x06, 0x74,0x48, 0xF7,0x04,
-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0xD8, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x0E,0xED, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00,
-0x00,0x01, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01,
-0x0F,0x21, 0xF4,0x82, 0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x00,0xBC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4,
-0x00,0x00, 0x84,0x1E, 0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
-0xFF,0xC4, 0x94,0x16, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04,
-0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x10,0x0C, 0x95,0x16,
-0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
-0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x0F,0x9C, 0xC6,0x24,
-0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01,
-0x0F,0xA0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
-0x0F,0xAD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
-0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x0F,0xE8, 0xF5,0x02,
-0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x01, 0x0F,0xF0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
-0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01,
-0x0F,0xF1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01,
-0x10,0x01, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01,
-0x10,0x10, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01,
-0x10,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
-0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
-0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x10,0xB8, 0x96,0x96,
-0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
-0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
-0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
-0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x01, 0x10,0xB5, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
-0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
-0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x10,0xBC, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x10,0xCC, 0xF4,0x82,
-0x00,0x01, 0xE0,0x01, 0x11,0x24, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
-0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
-0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
-0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
-0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
-0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
-0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x11,0x38, 0xF5,0x82, 0x00,0x00, 0xE0,0x01,
-0x11,0xCC, 0xF6,0x02, 0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34,
-0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x11,0x98, 0xC5,0x24,
-0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2,
-0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
-0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28,
-0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01,
-0x11,0x59, 0x06,0x30, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02,
-0x00,0x01, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38,
-0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02,
-0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
-0x13,0x10, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01,
-0x12,0x30, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
-0x12,0x1C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05,
-0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x01, 0x12,0x34, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05,
-0x76,0xFC, 0xF7,0x04, 0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x12,0x71, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32,
-0x00,0x44, 0xE6,0x01, 0x12,0x70, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
-0x76,0x08, 0xF6,0x84, 0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01,
-0x12,0x8C, 0xF7,0x05, 0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04,
-0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x12,0xB9, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01,
-0x12,0xC8, 0xF7,0x02, 0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x09, 0xF7,0x05,
-0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
-0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x13,0x18, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01,
-0x13,0x18, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x72,0x18, 0xF3,0x06,
-0x73,0x30, 0xF3,0x05, 0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x04, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x04, 0xF7,0x04,
-0x76,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x76,0x54, 0xF7,0x04,
-0x76,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x76,0x58, 0xF7,0x04,
-0x75,0xF8, 0xF6,0x84, 0x76,0x58, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x9D, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
-0x13,0x9C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
-0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x13,0xB8, 0xF7,0x05,
-0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF7,0x04, 0x76,0x08, 0xF6,0x84, 0x76,0x04, 0xF0,0x05,
-0x75,0xF8, 0xF5,0x84, 0x76,0xF8, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x2E,
-0x00,0x21, 0xE2,0x01, 0x14,0x14, 0xF7,0x05, 0x75,0xFC, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
-0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
-0x00,0x44, 0xE6,0x01, 0x14,0x00, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
-0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01, 0x14,0x18, 0xF5,0x05,
-0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04, 0x75,0xEC, 0xF5,0x06, 0x72,0x18, 0x20,0x3A,
-0x00,0x00, 0xE6,0x01, 0x14,0x40, 0xF5,0x05, 0x76,0x48, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0x55, 0x00,0x00, 0x00,0x01, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x14,0xC4, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x14,0x71, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x14,0x88, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
-0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0xC5, 0xF7,0x05,
-0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
-0x14,0xBC, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06, 0x72,0xA4, 0xF5,0x05,
-0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
-0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x40, 0xF4,0x02,
-0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xEC, 0x86,0x96,
-0x00,0x08, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x7B,0x38, 0x86,0x96, 0x00,0x00, 0xF7,0x04,
-0x76,0x48, 0xF6,0x85, 0x7B,0x30, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x41, 0xF4,0x02, 0x00,0x01, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x75,0xF4, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0xBC, 0xF4,0x02, 0x00,0x00, 0x86,0x96,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xF0, 0x86,0x96, 0x00,0x08, 0x00,0x00,
-0x00,0x01, 0xF6,0x85, 0x7B,0x48, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x76,0x48, 0xF6,0x85,
-0x7B,0x40, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x01, 0x15,0xBD, 0xF4,0x02, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x01, 0x15,0xFC, 0xF6,0x82, 0x00,0x10, 0xF6,0x86, 0x76,0x48, 0xF6,0x85,
-0x76,0xFC, 0xE0,0x01, 0x16,0x0C, 0xF7,0x02, 0x00,0x01, 0xF6,0x85, 0x76,0xF8, 0xF6,0x86,
-0x76,0x48, 0xF6,0x85, 0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x16,0x20, 0xF6,0x86, 0x74,0xD4, 0xE0,0x01, 0x16,0x2C, 0xF6,0x85, 0x76,0x48, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0xE6,0x01, 0x16,0x85, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x75,0xF4, 0xF6,0x84,
-0x7B,0x48, 0xF7,0x05, 0x76,0xF4, 0xF7,0x04, 0x7B,0x40, 0xC6,0xB0, 0x68,0x00, 0x26,0xB4,
-0x00,0x04, 0x97,0x02, 0xFF,0x6C, 0x96,0x02, 0xFF,0x50, 0xE0,0x01, 0x16,0xA8, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0xF6,0x84, 0x7B,0x38, 0xF5,0x82, 0x00,0x01, 0xF5,0x85,
-0x76,0xF4, 0xF6,0x04, 0x7B,0x30, 0xC6,0xB8, 0x68,0x00, 0x26,0xB4, 0x00,0x04, 0x96,0x02,
-0xFF,0x6C, 0x97,0x02, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF5,0x86, 0x73,0xBC, 0xF5,0x85,
-0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
-0x7B,0x28, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7B,0x28, 0xF7,0x04,
-0x75,0xF4, 0xF6,0x84, 0x7B,0x28, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x21, 0x00,0x00,
-0x00,0x01, 0xF0,0x05, 0x75,0xF4, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x01, 0x17,0x25, 0xF0,0x05, 0x75,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x17,0xEC, 0x00,0x00, 0x00,0x01, 0xF0,0x05,
-0x75,0xEC, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
-0x17,0x41, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x17,0x58, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
-0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x95, 0xF7,0x05,
-0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
-0x17,0x8C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x17,0x98, 0xF5,0x06,
-0x72,0xA4, 0xF5,0x06, 0x72,0x18, 0xF5,0x05, 0x76,0x48, 0xF5,0x84, 0x76,0xF8, 0x00,0x00,
-0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x17,0xE8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
-0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
-0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x17,0xD4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
-0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01,
-0x17,0xEC, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x49, 0x00,0x00,
-0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01,
-0x1C,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x87,0x36,
-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x18,0x7D, 0xF4,0x82,
-0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x00,0xBC, 0x97,0x93,
-0xFF,0xFC, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4, 0x00,0x00, 0x84,0x1E,
-0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x94,0x16,
-0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x19,0x68, 0x95,0x16, 0xFF,0xE4, 0x77,0x35,
-0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8,
-0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x18,0xF8, 0xC6,0x24, 0x00,0x00, 0x87,0x36,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01, 0x18,0xFC, 0x20,0x32,
-0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x19,0x09, 0x00,0x00,
-0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xE0, 0x00,0x00,
-0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x19,0x44, 0xF5,0x02, 0x00,0x00, 0xC0,0x32,
-0x72,0x00, 0xE6,0x01, 0x19,0x4C, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16,
-0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01, 0x19,0x4D, 0x20,0x2A,
-0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01, 0x19,0x5D, 0x20,0x2E,
-0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01, 0x19,0x6C, 0x20,0x26,
-0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x19,0xA1, 0xF6,0x02,
-0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
-0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
-0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x1A,0x14, 0x96,0x96, 0xFF,0xDC, 0x27,0x14,
-0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13,
-0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xCC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xCC, 0x20,0x22,
-0x00,0x00, 0xE6,0x01, 0x1A,0x11, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06,
-0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
-0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0x96,0x96,
-0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x1A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1A,0x28, 0xF4,0x82, 0x00,0x01, 0xE0,0x01,
-0x1A,0x80, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0x77,0x35,
-0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x42,0xC8, 0xA6,0x3A,
-0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x05,0xB8,
-0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16, 0xFF,0xEC, 0xC6,0x30,
-0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
-0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF0, 0x20,0x26,
-0x00,0x00, 0xE6,0x01, 0x1A,0x94, 0xF5,0x82, 0x00,0x00, 0xE0,0x01, 0x1B,0x28, 0xF6,0x02,
-0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C,
-0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x1A,0xF4, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C,
-0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC,
-0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
-0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16,
-0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01, 0x1A,0xB5, 0x06,0x30,
-0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
-0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4,
-0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82,
-0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1C,0x6C, 0x00,0x00,
-0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
-0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x1B,0x8C, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x1B,0x78, 0xB5,0xBA,
-0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
-0x77,0x00, 0xE0,0x01, 0x1B,0x90, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04,
-0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1B,0xCD, 0xF6,0x86,
-0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
-0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
-0x1B,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
-0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x1B,0xE8, 0xF7,0x05,
-0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04, 0x76,0x04, 0xF0,0x05,
-0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x01, 0x1C,0x15, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01, 0x1C,0x24, 0xF7,0x02,
-0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1C,0x65, 0xF7,0x05, 0x76,0x60, 0xF7,0x04,
-0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
-0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
-0x00,0x44, 0xE6,0x01, 0x1C,0x74, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01, 0x1C,0x74, 0xF0,0x05,
-0x2D,0x38, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x72,0x18, 0xF3,0x06, 0x73,0x30, 0xF3,0x05,
-0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
-0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x72,0x18, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x72,0xA4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x73,0x30, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x73,0xBC, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
-0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x74,0x48, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x74,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x75,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
-0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x77,0x04, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x1D,0xD4, 0x96,0x93,
-0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF6,0x86, 0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
-0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x00,0x22, 0xF7,0x05,
-0x76,0xF4, 0xF7,0x05, 0x76,0xF8, 0xF0,0x05, 0x76,0xFC, 0xF0,0x05, 0x77,0x00, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xF4, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x22, 0xE6,0x01, 0x1E,0x01, 0x00,0x00, 0x00,0x01, 0x97,0x13,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x77,0x04, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x76,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
-0x78,0xA4, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF6,0x86, 0x1F,0xBC, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x14, 0x96,0x93,
-0xFF,0xFC, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x78,0x9C, 0x90,0x02, 0xFF,0x34, 0xF7,0x02,
-0x7F,0xFF, 0xF7,0x05, 0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x78,0x9C, 0x87,0x16, 0x00,0x00, 0x84,0x96,
-0x00,0x08, 0xF5,0x86, 0x77,0x10, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x75,0x39,
-0x00,0x04, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x32, 0x00,0x00, 0xC6,0xA8,
-0x58,0x00, 0x84,0x16, 0x00,0x04, 0xC6,0x30, 0x75,0x80, 0x94,0x36, 0x00,0x04, 0xB4,0xAA,
-0x58,0x02, 0x87,0x36, 0x00,0x08, 0xF6,0x05, 0x78,0x9C, 0x07,0x38, 0x00,0x01, 0xE6,0x01,
-0x1F,0x2D, 0x97,0x36, 0x00,0x08, 0x87,0x02, 0xFF,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
-0x4A,0x00, 0xEE,0x01, 0x1F,0x35, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x78,0xA0, 0x94,0x82,
-0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x77,0x39,
-0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0xF6,0x04, 0x78,0x9C, 0xC7,0x04, 0x76,0x00, 0x86,0xAE,
-0x00,0x08, 0xC6,0x30, 0x74,0x00, 0xF7,0x06, 0x77,0x10, 0xF6,0x05, 0x78,0x9C, 0x76,0xB5,
-0x00,0x04, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x08, 0x20,0x32, 0x00,0x00, 0x07,0x38,
-0x00,0x01, 0xE6,0x01, 0x1F,0xA8, 0x97,0x36, 0x00,0x08, 0xF7,0x02, 0x7F,0xFF, 0xF7,0x05,
-0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04, 0x78,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
-0x00,0x00, 0xE6,0x01, 0x20,0xD1, 0xF6,0x02, 0x7F,0xFF, 0x96,0x16, 0xFF,0xF4, 0xF6,0x84,
-0x2D,0x40, 0xF6,0x06, 0x77,0x10, 0x26,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x04, 0xC4,0xB8,
-0x60,0x00, 0xC3,0x38, 0x00,0x00, 0x74,0x35, 0x00,0x02, 0xF6,0x06, 0x77,0x10, 0xC0,0x26,
-0x62,0x00, 0xEC,0x01, 0x20,0xC1, 0xF6,0x06, 0x21,0x8C, 0xF3,0x84, 0x78,0x9C, 0xA7,0x22,
-0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x74,0x00, 0xE6,0x01, 0x20,0xB1, 0x00,0x00,
-0x00,0x01, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0x78,0xA0, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
-0x72,0x00, 0x20,0x36, 0x00,0x00, 0xEE,0x01, 0x20,0x98, 0x96,0xA6, 0x00,0x00, 0xF7,0x04,
-0x2D,0x38, 0xF6,0x06, 0x77,0x10, 0xC5,0x18, 0x60,0x00, 0xF6,0x86, 0x2C,0x28, 0x86,0x2A,
-0x00,0x04, 0x05,0xB8, 0x00,0x01, 0xF5,0x85, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x2E,
-0x00,0x44, 0xE6,0x01, 0x20,0x70, 0xB6,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0x86,0x2A,
-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x96,0x2A, 0x00,0x0C, 0xF6,0x06, 0x21,0x8C, 0xA7,0x22,
-0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC7,0x04, 0x76,0x00, 0xC7,0x1C, 0x74,0x00, 0xE0,0x01,
-0x20,0xB0, 0xF7,0x05, 0x78,0x9C, 0x86,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x62,0x00, 0xEC,0x01, 0x20,0xB0, 0x00,0x00, 0x00,0x01, 0x96,0x96, 0xFF,0xF4, 0x24,0xA4,
-0x00,0x10, 0x23,0x18, 0x00,0x10, 0xE0,0x01, 0x1F,0xFC, 0x24,0x20, 0x00,0x04, 0x86,0x16,
-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x78,0xA0, 0x96,0x02, 0xFF,0x30, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x77,0x10, 0x77,0x39, 0x00,0x04, 0xC7,0x38,
-0x68,0x00, 0x86,0xBA, 0x00,0x0C, 0x87,0x3A, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF7,0x02, 0x00,0x0F, 0x20,0x3A, 0x00,0x00, 0xEC,0x01, 0x21,0x5D, 0xF6,0x86,
-0x77,0x18, 0x90,0x36, 0x00,0x00, 0x27,0x38, 0x00,0x01, 0xC6,0x04, 0x00,0x00, 0xC0,0x3A,
-0x62,0x00, 0xE6,0x01, 0x21,0x44, 0x06,0xB4, 0x00,0x10, 0xF6,0x06, 0x78,0xA4, 0x96,0x13,
-0xFF,0xFC, 0xF6,0x06, 0x78,0x10, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x01, 0x00,0x00,
-0x00,0x02, 0x00,0x00, 0x00,0x04, 0x00,0x00, 0x00,0x08, 0x00,0x00, 0x00,0x10, 0x00,0x00,
-0x00,0x20, 0x00,0x00, 0x00,0x40, 0x00,0x00, 0x00,0x80, 0x00,0x00, 0x01,0x00, 0x00,0x00,
-0x02,0x00, 0x00,0x00, 0x04,0x00, 0x00,0x00, 0x08,0x00, 0x00,0x00, 0x10,0x00, 0x00,0x00,
-0x20,0x00, 0x00,0x00, 0x40,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x00,0x00, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
-0xFF,0xFC, 0xF7,0x06, 0x22,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x15, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
-0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
-0x00,0x08, 0xF6,0x84, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x01, 0x22,0x70, 0xF6,0x02, 0x00,0x00, 0x87,0x36,
-0x0E,0xF4, 0x86,0xB6, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0x78, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x22,0x94, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
-0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0xB1, 0xF5,0x82,
-0x03,0xE8, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF5,0x82, 0x03,0xE8, 0x95,0x93,
-0xFF,0xFC, 0xF5,0x82, 0x00,0x15, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86, 0x79,0xCC, 0x95,0x93,
-0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x79,0xCC, 0x97,0x13,
-0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
-0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
-0x79,0x3C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC1,0x3C, 0x00,0x00, 0x02,0x10, 0x00,0x04, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
-0x23,0x84, 0x27,0x14, 0x00,0x0C, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0xE0,0x01, 0x24,0x34, 0x96,0x96,
-0xFF,0xF4, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x13,
-0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
-0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
-0x24,0x34, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
-0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xEE,0x01, 0x24,0x21, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0xB8, 0x58,0x00, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
-0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x36,
-0x00,0x10, 0x85,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x14, 0x26,0xB4,
-0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEE,0x01, 0x23,0xEC, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E,
-0x00,0x04, 0x86,0x96, 0xFF,0xF4, 0x85,0x16, 0x00,0x04, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
-0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x2C, 0x70,0x00, 0x85,0x2A, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x95,0x3A, 0x00,0x0C, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x85,0x2A,
-0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x3A, 0x00,0x10, 0x85,0x16, 0x00,0x08, 0xF4,0x02,
-0x00,0x01, 0x95,0x3A, 0x00,0x14, 0x96,0xAE, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x84,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
-0x25,0x55, 0x27,0x14, 0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00,
-0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
-0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
-0x00,0x00, 0xE6,0x01, 0x25,0x55, 0x00,0x00, 0x00,0x01, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
-0x00,0x01, 0x20,0x32, 0x00,0x00, 0xEE,0x01, 0x25,0x45, 0x77,0x31, 0x00,0x01, 0xC6,0xAC,
-0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36,
-0x00,0x18, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x1C, 0x00,0x00,
-0x00,0x01, 0x95,0x36, 0x00,0x10, 0x85,0x36, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x95,0x36,
-0x00,0x14, 0x06,0xB4, 0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x25,0x11, 0x00,0x00,
-0x00,0x01, 0x87,0x2E, 0x00,0x04, 0xF4,0x02, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0x97,0x2E,
-0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x08, 0x83,0x96, 0x00,0x04, 0x83,0x16, 0x00,0x00, 0xC5,0x00, 0x00,0x00, 0x84,0x1A,
-0x00,0x04, 0xC4,0xA8, 0x00,0x00, 0x94,0x16, 0xFF,0xF4, 0xC0,0x26, 0x42,0x00, 0xE6,0x01,
-0x26,0xD1, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x2A,
-0x32,0x00, 0xE6,0x01, 0x26,0xD1, 0xC7,0x20, 0x4A,0x00, 0x95,0x16, 0xFF,0xF4, 0x76,0xB8,
-0xFF,0xE1, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0xFF,0xFF, 0xC5,0x24, 0x70,0x00, 0x77,0x29,
-0x00,0x01, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x02, 0x83,0x16, 0x00,0x00, 0x86,0x9E,
-0x00,0x00, 0xC5,0xB8, 0x30,0x00, 0x05,0xAC, 0x00,0x0C, 0x87,0x2E, 0x00,0x00, 0xC6,0x00,
-0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x26,0x10, 0x20,0x32, 0x00,0x00, 0x86,0x9E,
-0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x01,
-0x26,0x10, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
-0x26,0x25, 0x00,0x00, 0x00,0x01, 0xC7,0x00, 0x00,0x00, 0xE0,0x01, 0x26,0x78, 0x20,0x3A,
-0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x01, 0x26,0x5C, 0x00,0x00, 0x00,0x01, 0xE6,0x01, 0x26,0x64, 0x20,0x32,
-0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
-0x72,0x00, 0xE2,0x01, 0x26,0x65, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
-0x00,0x00, 0x47,0x04, 0xFF,0xFF, 0xE6,0x01, 0x26,0x79, 0x20,0x3A, 0x00,0x00, 0xF7,0x02,
-0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x26,0xB1, 0x20,0x3A, 0x00,0x00, 0xEE,0x01,
-0x26,0xA0, 0x20,0x3A, 0x00,0x01, 0x43,0x04, 0xFF,0xFF, 0xC0,0x3A, 0x32,0x00, 0xE6,0x01,
-0x26,0xC9, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0xE6,0x01,
-0x26,0xC1, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0x83,0x16,
-0x00,0x08, 0xF4,0x02, 0x00,0x01, 0xE0,0x01, 0x26,0xE0, 0x95,0x1A, 0x00,0x00, 0xE0,0x01,
-0x25,0x8C, 0xC4,0xA8, 0x00,0x00, 0xE0,0x01, 0x25,0x8C, 0xC4,0x28, 0x00,0x00, 0x83,0x16,
-0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0x1A, 0x00,0x00, 0xC4,0x00, 0x00,0x00, 0x87,0x96,
-0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
-0x00,0x04, 0x84,0x16, 0x00,0x00, 0x84,0x96, 0x00,0x08, 0xF7,0x02, 0x00,0x03, 0xC6,0xA0,
-0x4D,0x80, 0xC6,0xB6, 0x74,0x00, 0xE6,0x01, 0x27,0x71, 0xC6,0x20, 0x00,0x00, 0x20,0x36,
-0x00,0x02, 0xE6,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20, 0x48,0x00, 0x27,0x38,
-0x00,0x02, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0x9C, 0xC5,0x38, 0x00,0x00, 0x87,0x2E,
-0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
-0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE2,0x01,
-0x27,0x41, 0x05,0xAC, 0x00,0x02, 0xE0,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20,
-0x48,0x00, 0x27,0x38, 0x00,0x04, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0xA0, 0xC5,0x20,
-0x48,0x00, 0x83,0xAD, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0xB1, 0x00,0x04, 0xC0,0x32,
-0x72,0x00, 0xE2,0x01, 0x27,0x85, 0x00,0x00, 0x00,0x01, 0xC5,0x20, 0x48,0x00, 0xC0,0x32,
-0x52,0x00, 0xE4,0x01, 0x27,0xD5, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
-0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xB3,
-0x68,0x00, 0x06,0x30, 0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x27,0xAC, 0x05,0xAC,
-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16,
-0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC7,0x22, 0x6D,0x80, 0xE6,0x01,
-0x28,0x10, 0x20,0x36, 0x00,0x00, 0xE0,0x01, 0x28,0x74, 0xC4,0x38, 0x00,0x00, 0xF7,0x02,
-0x00,0x01, 0xEE,0x01, 0x28,0x41, 0xF6,0x02, 0x00,0x00, 0x76,0xB5, 0x00,0x01, 0x20,0x36,
-0x00,0x00, 0xEE,0x01, 0x28,0x1C, 0x77,0x39, 0x00,0x01, 0xE0,0x01, 0x28,0x44, 0x20,0x22,
-0x00,0x00, 0x74,0x21, 0x00,0x01, 0x77,0x38, 0xFF,0xFF, 0x06,0x30, 0x00,0x01, 0x20,0x22,
-0x00,0x00, 0xEE,0x01, 0x28,0x34, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x28,0x71, 0x00,0x00,
-0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE4,0x01, 0x28,0x64, 0x00,0x00, 0x00,0x01, 0xC4,0x20,
-0x6A,0x00, 0x77,0x3A, 0xFF,0xFF, 0xE6,0x01, 0x28,0x54, 0x76,0xB4, 0xFF,0xFF, 0xD4,0x20,
-0x07,0x62, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
-0x00,0x04, 0xE0,0x01, 0x28,0xCC, 0xF7,0x06, 0x29,0xDC, 0x86,0xBA, 0x00,0x00, 0x00,0x00,
-0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x28,0xC9, 0x00,0x00, 0x00,0x01, 0x97,0x16,
-0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
-0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A,
-0x62,0x00, 0xE4,0x01, 0x28,0x9D, 0x00,0x00, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
-0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
-0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xE0,0x01, 0x29,0x34, 0xF7,0x06,
-0x29,0x98, 0x86,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
-0x29,0x31, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34,
-0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
-0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A, 0x62,0x00, 0xE4,0x01, 0x29,0x04, 0x00,0x00,
-0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
-0x7B,0x50, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x29,0x84, 0xF6,0x82,
-0x00,0x01, 0xF6,0x85, 0x7B,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x28,0xF0, 0x97,0x93,
-0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
-0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x0B,0x4C, 0x00,0x00, 0x00,0x00, 0x00,0x00,
-0x42,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x5E,0x50, 0x00,0x00, 0x00,0x00, 0x00,0x00,
-0xC7,0xA8, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x0B,0xD0, 0x00,0x00, 0x00,0x00, 0x00,0x01,
-0x1C,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x1E,0x14, 0x00,0x00, 0x00,0x00, 0x00,0x01,
+0xF2,0x0E,
+0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x02, 0x05,0x3C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x02, 0x0A,0xBC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x02, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x04, 0x4A,0x9C, 0x85,0x16, 0x00,0x00, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
+0x01,0x01, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x01,0x00, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x01,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0xF4,0x82, 0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x01,0xE0, 0xB4,0xBA,
+0x68,0x02, 0xE0,0x00, 0x01,0xE0, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x3B,0x64, 0xF5,0x84,
+0x4F,0x54, 0xF7,0x05, 0x7A,0x10, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x01,0x99, 0x97,0x2A,
+0x00,0x20, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x26,0xAC, 0x00,0x01, 0x77,0x35,
+0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA4,0xBA,
+0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
+0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xD7,0x00, 0x0A,0x01, 0xE0,0x00,
+0x01,0xD0, 0xF7,0x05, 0x7A,0x18, 0x95,0xAA, 0x00,0x1C, 0xF6,0x06, 0x4A,0x98, 0x06,0xAC,
+0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38,
+0x00,0x0C, 0xA4,0xBA, 0x60,0x02, 0x00,0x00, 0x00,0x01, 0x94,0xAA, 0x00,0x10, 0xC7,0x38,
+0x60,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05, 0x7A,0x18, 0x97,0x2A, 0x00,0x14, 0xF5,0x05,
+0x79,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
+0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x02,0x4C, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x02,0x4C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x02,0x85, 0xF4,0x82, 0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x02,0x74, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF3,0x06, 0x2A,0x6C, 0xF3,0x05, 0x2C,0x10, 0xE0,0x00, 0x05,0x28, 0xF0,0x05,
+0x7A,0x18, 0xF3,0x84, 0x79,0xD8, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+0xFF,0xC4, 0x84,0x1E, 0x00,0x10, 0x96,0x96, 0xFF,0xD4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16,
+0xFF,0xE0, 0x85,0x1E, 0x00,0x14, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x03,0x6C, 0x95,0x16,
+0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
+0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00, 0x02,0xFC, 0xC6,0x24,
+0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
+0x03,0x00, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x03,0x0D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
+0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x03,0x48, 0xF5,0x02,
+0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x03,0x50, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
+0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0x03,0x51, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+0x03,0x61, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+0x03,0x70, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+0x03,0xA5, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x04,0x18, 0x96,0x96,
+0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
+0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x04,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x04,0x1C, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x04,0x2C, 0xF4,0x82,
+0x00,0x01, 0xE0,0x00, 0x04,0x84, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
+0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
+0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
+0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
+0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
+0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x05,0x25, 0xF3,0x06, 0x29,0xE0, 0x86,0x96,
+0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
+0x6A,0x00, 0xEC,0x00, 0x04,0xF0, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
+0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
+0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
+0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x04,0xB1, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
+0x00,0x03, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
+0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
+0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
+0x29,0xE0, 0xF3,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x04, 0x7A,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x05,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x7A,0x10, 0xF6,0x84, 0x3B,0x64, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x05,0xCD, 0xF5,0x86, 0x4A,0x98, 0xF6,0x04, 0x79,0xD8, 0xF6,0x84, 0x4F,0x54, 0x00,0x00,
+0x00,0x01, 0x96,0xB2, 0x00,0x1C, 0x06,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xA5,0x3A, 0x58,0x02, 0x00,0x00,
+0x00,0x01, 0x95,0x32, 0x00,0x10, 0xC7,0x38, 0x58,0x00, 0x87,0x3A, 0x00,0x04, 0xF0,0x05,
+0x7A,0x18, 0x97,0x32, 0x00,0x14, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x01,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0x05,0xFC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
+0x00,0x12, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x05,0xF4, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF5,0x06, 0x2A,0x6C, 0xF5,0x05, 0x2C,0x10, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF7,0x04, 0x75,0xEC, 0x85,0x2E,
+0x00,0x20, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0xF5,0x05, 0x7A,0x08, 0xF7,0x04,
+0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x06,0xCC, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x06,0xCC, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x1C, 0xF6,0x84, 0x4F,0x54, 0xF7,0x05,
+0x7A,0x00, 0xC7,0x34, 0x72,0x00, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x06,0x8D, 0xF5,0x02,
+0x00,0x01, 0xE0,0x00, 0x06,0x90, 0xF5,0x05, 0x79,0xF8, 0xF0,0x85, 0x79,0xF8, 0xF6,0x84,
+0x7A,0x00, 0xC7,0x38, 0x70,0x00, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x79,0xF8, 0xF6,0x85,
+0x79,0xE8, 0xC7,0x38, 0x70,0x00, 0xC6,0x34, 0x70,0x00, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x06,0xCC, 0xF6,0x05, 0x79,0xF0, 0x20,0x36,
+0x00,0x00, 0xEC,0x00, 0x06,0xF8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
+0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x07,0x38, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00,
+0x07,0x38, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
+0x72,0x00, 0xEE,0x00, 0x07,0x19, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x4A,0x9C, 0xE0,0x00,
+0x07,0x28, 0xF7,0x05, 0x79,0xF0, 0x20,0x32, 0x00,0x00, 0xEC,0x00, 0x07,0x28, 0x00,0x00,
+0x00,0x01, 0xF0,0x85, 0x79,0xF0, 0xF5,0x85, 0x79,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xA4, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x7A,0x08, 0xF6,0x84, 0x3B,0x64, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x07,0xD5, 0xF4,0x02,
+0x00,0x00, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x13, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x07,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x00, 0x0A,0xA4, 0xF3,0x06,
+0x2B,0x84, 0xF6,0x84, 0x79,0xE8, 0xF6,0x06, 0x4A,0x98, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x84, 0x79,0xE0, 0x07,0x38, 0x00,0x0C, 0xA3,0x3A,
+0x60,0x02, 0xC3,0xB4, 0x00,0x00, 0x93,0x36, 0x00,0x10, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
+0x00,0x04, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x97,0x36, 0x00,0x14, 0x84,0x9E,
+0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x94,0x96, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E,
+0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
+0x08,0xEC, 0x95,0x16, 0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
+0x00,0x02, 0xC6,0xB8, 0x60,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x08,0x7C, 0xC6,0x20,
+0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00,
+0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x08,0x8D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
+0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x00, 0x08,0xC8, 0xF5,0x02,
+0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00, 0x08,0xD0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
+0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0x08,0xD1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+0x08,0xE1, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+0x08,0xF0, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x09,0x25, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x00, 0x09,0x98, 0x96,0x96,
+0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
+0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x09,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x00, 0x09,0x9C, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x09,0xAC, 0xF4,0x82,
+0x00,0x01, 0xE0,0x00, 0x0A,0x04, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
+0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
+0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
+0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
+0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
+0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x0A,0xA5, 0xF3,0x06, 0x2A,0xF8, 0x86,0x96,
+0xFF,0xF0, 0xF5,0x82, 0x00,0x00, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E,
+0x6A,0x00, 0xEC,0x00, 0x0A,0x70, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30,
+0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
+0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00,
+0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x00, 0x0A,0x31, 0x06,0x30, 0x00,0x02, 0xF3,0x02,
+0x00,0x02, 0xF3,0x05, 0x76,0xF4, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38,
+0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4,
+0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF3,0x06,
+0x2A,0xF8, 0xF3,0x05, 0x2C,0x1C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF6,0x84, 0x79,0xE8, 0xF7,0x04, 0x79,0xF8, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
+0x70,0x00, 0xF7,0x04, 0x7A,0x20, 0xF6,0x85, 0x79,0xE8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x7A,0x20, 0xF7,0x04, 0x79,0xF0, 0xF6,0x04, 0x7A,0x20, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x0B,0x2C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x82, 0x00,0x13, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x0B,0x20, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86,
+0x2B,0x84, 0xE0,0x00, 0x0B,0x38, 0xF5,0x85, 0x2C,0x1C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x07,0x4C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x06, 0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x29,0xE0, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x2C,0x10, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2A,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x2A,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2C,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x2B,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF0,0x05,
+0x2D,0x38, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x18, 0xFF,0x85, 0x2E,0xDC, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
+0x74,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x29, 0x97,0x16, 0xFF,0xF4, 0x47,0x38,
+0xFF,0xFB, 0xF6,0x84, 0x6F,0x50, 0xCF,0xB8, 0x00,0x00, 0x83,0x96, 0xFF,0xF4, 0xF7,0x02,
+0x00,0x3F, 0xC3,0x9C, 0x6D,0x80, 0xC7,0x1C, 0x74,0x00, 0x20,0x3A, 0x00,0x3F, 0xE2,0x00,
+0x12,0x60, 0x93,0x96, 0xFF,0xF4, 0x77,0x39, 0x00,0x02, 0xF6,0x82, 0x0C,0x5C, 0xA6,0xB6,
+0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x00, 0x12,0x60, 0x00,0x00,
+0x12,0x60, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x5C, 0x00,0x00,
+0x0D,0x5C, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x0D,0x68, 0x00,0x00, 0x12,0x50, 0x00,0x00,
+0x12,0x50, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE0, 0x00,0x00,
+0x0D,0xE0, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x12,0x3C, 0x00,0x00, 0x0D,0xE8, 0x00,0x00,
+0x0D,0xF4, 0x00,0x00, 0x0E,0x00, 0x00,0x00, 0x0E,0x20, 0x00,0x00, 0x0E,0x40, 0x00,0x00,
+0x0E,0x60, 0x00,0x00, 0x0E,0x80, 0x00,0x00, 0x0E,0xA0, 0x00,0x00, 0x0E,0xC0, 0x00,0x00,
+0x0E,0xC8, 0x00,0x00, 0x0E,0xD0, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0E,0xD8, 0x00,0x00,
+0x0E,0xF4, 0x00,0x00, 0x0F,0x10, 0x00,0x00, 0x12,0x28, 0x00,0x00, 0x0F,0x18, 0x00,0x00,
+0x0F,0x18, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x24, 0x00,0x00, 0x0F,0x44, 0x00,0x00,
+0x0F,0x44, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x64, 0x00,0x00, 0x0F,0x84, 0x00,0x00,
+0x0F,0x84, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x8C, 0x00,0x00, 0x0F,0x94, 0x00,0x00,
+0x0F,0x94, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB0, 0x00,0x00, 0x0F,0xB8, 0x00,0x00,
+0x0F,0xD8, 0x00,0x00, 0x0F,0xF8, 0x00,0x00, 0x10,0x2C, 0x00,0x00, 0x10,0x60, 0x00,0x00,
+0x10,0x94, 0x00,0x00, 0x10,0xC8, 0x00,0x00, 0x10,0xFC, 0x00,0x00, 0x11,0x30, 0x00,0x00,
+0x11,0x4C, 0x00,0x00, 0x11,0x68, 0x00,0x00, 0x12,0x14, 0x00,0x00, 0x11,0x84, 0x00,0x00,
+0x11,0xB4, 0x00,0x00, 0x11,0xE4, 0x00,0x00, 0x12,0x14, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF6,0x02, 0x00,0x05, 0x20,0x32, 0x00,0x14, 0xE6,0x00,
+0x0D,0xB5, 0x27,0x00, 0x00,0x10, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x0D,0xB5, 0xF7,0x06,
+0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00, 0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E,
+0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06,
+0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x0D,0xB5, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05,
+0x2E,0xCC, 0xF7,0x04, 0x2D,0x58, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x87,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
+0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x60, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
+0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xE0,0x00,
+0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
+0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
+0x00,0x06, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x14, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
+0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+0x12,0x2C, 0xF3,0x82, 0x00,0x14, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0xE0,0x00,
+0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0xE0,0x00,
+0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00, 0x12,0x54, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x06, 0xE0,0x00,
+0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0xE0,0x00, 0x12,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82, 0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0x12,0x40, 0xF3,0x82, 0x00,0x07, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82,
+0x00,0x0B, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x0B, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
+0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x40, 0xF3,0x82,
+0x00,0x06, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x12,0x2C, 0xF3,0x82, 0x00,0x0B, 0xF7,0x04,
+0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x13,0xCC, 0xF7,0x05,
+0x35,0x44, 0xF3,0x82, 0x00,0x14, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x07, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x05, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x90,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x77,0x9C, 0x00,0x14, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0x12,0x9D, 0xF7,0x06, 0x04,0x00, 0xF7,0x04, 0x6F,0x5C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x6F,0x5C, 0xF7,0x04, 0x6F,0x5C, 0xE0,0x00, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0xF7,0x06, 0x04,0x00, 0xC0,0x1E, 0x74,0x00, 0xE6,0x00,
+0x14,0x29, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x2E,0xD0, 0xF6,0x84, 0x35,0x24, 0x07,0x38,
+0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF7,0x05, 0x2E,0xD0, 0xF7,0x04,
+0xE0,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x14,0x05, 0xF6,0x82,
+0x00,0x00, 0xF6,0x85, 0xE0,0x14, 0xF7,0x04, 0x2E,0xD8, 0xC5,0x34, 0x00,0x00, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x2E,0xD8, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x13,0xCC, 0xF6,0x82,
+0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x13,0xA0, 0x05,0xB4, 0x00,0x08, 0x95,0x93,
+0xFF,0xFC, 0x95,0x16, 0xFF,0xE8, 0x95,0x96, 0xFF,0xE4, 0x96,0x96, 0xFF,0xE0, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x64, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xE8, 0x85,0x96,
+0xFF,0xE4, 0x86,0x96, 0xFF,0xE0, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x13,0x90, 0xF7,0x02,
+0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00,
+0x13,0x75, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x13,0x90, 0xF7,0x02,
+0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38,
+0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x12,0x00, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04,
+0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x13,0xC0, 0x07,0x34,
+0x14,0x94, 0xF3,0x84, 0x6F,0x44, 0xE0,0x00, 0x13,0xC4, 0xF3,0x85, 0x35,0x28, 0xF7,0x05,
+0x35,0x28, 0xE0,0x00, 0x12,0xE8, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+0x14,0x29, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05, 0x35,0x24, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x14,0x28, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x14,0x28, 0xF0,0x05,
+0x2D,0x38, 0xF7,0x04, 0xE0,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x14,0x29, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0xE0,0x10, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x02,0x98, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84, 0x2D,0x38, 0xF7,0x04, 0x2D,0x3C, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x0C,0x09, 0xF6,0x86, 0x2C,0x28, 0x77,0x39,
+0x00,0x02, 0xA5,0x3A, 0x68,0x02, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00,
+0x14,0x91, 0x27,0x28, 0x00,0x15, 0x20,0x3A, 0x00,0x01, 0xE2,0x00, 0x14,0x91, 0xF7,0x06,
+0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E,
+0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85, 0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36,
+0x00,0x1F, 0xE2,0x00, 0x14,0x91, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x06,
+0x2D,0x44, 0x76,0xA9, 0x00,0x02, 0xA7,0x36, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x04, 0x94,0x96,
+0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x2D,0x3C, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0x20,0x3A, 0x00,0x44, 0xE6,0x00,
+0x14,0x2C, 0xF7,0x05, 0x2D,0x3C, 0xE0,0x00, 0x14,0x2C, 0xF0,0x05, 0x2D,0x3C, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16, 0x00,0x00, 0xF7,0x02,
+0x00,0x00, 0x85,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x21, 0xEE,0x00, 0x15,0x34, 0x95,0xA2,
+0x00,0x00, 0xF6,0x06, 0x23,0x38, 0x07,0x20, 0x00,0x84, 0xC6,0xA0, 0x00,0x00, 0x96,0x3A,
+0x00,0x04, 0x27,0x38, 0x00,0x04, 0xC0,0x3A, 0x6A,0x00, 0xEC,0x00, 0x15,0x20, 0x00,0x00,
+0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96,
+0x00,0x00, 0x87,0x16, 0x00,0x04, 0xF6,0x04, 0x2D,0x40, 0x97,0x36, 0x00,0x00, 0x97,0x36,
+0x00,0x04, 0x07,0x30, 0x00,0x01, 0xF7,0x05, 0x2D,0x40, 0x96,0x36, 0x00,0x08, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x20,0x2A, 0x00,0x14, 0xE6,0x00, 0x15,0xD9, 0x27,0x28, 0x00,0x15, 0x20,0x3A,
+0x00,0x01, 0xE2,0x00, 0x15,0xD9, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x86,0x02,
+0xFF,0x34, 0x75,0xB5, 0x00,0x02, 0xB5,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
+0x2E,0xCC, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x00, 0x15,0xD9, 0xB6,0x2E,
+0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF6,0x86, 0x2D,0x44, 0x77,0x29, 0x00,0x02, 0xA6,0xBA,
+0x68,0x02, 0x00,0x00, 0x00,0x01, 0x86,0xB6, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38,
+0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x87,0x16, 0x00,0x00, 0x86,0x96, 0x00,0x04, 0xF6,0x06, 0x2D,0x44, 0x76,0xB5,
+0x00,0x02, 0x85,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xB5,0xB6, 0x60,0x02, 0xC6,0xB4,
+0x70,0x00, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xB6, 0x00,0x04, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2,
+0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00, 0x16,0xB4, 0xC5,0xB4, 0x00,0x00, 0x20,0x36,
+0x00,0x0F, 0xEE,0x00, 0x16,0xB4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00,
+0x16,0xB5, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEC,0x00, 0x16,0xD0, 0x00,0x00,
+0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32,
+0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00, 0x16,0xD8, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A,
+0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x34,0x58, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
+0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x3F,0x94, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x2F,0xF8, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
+0x3B,0x84, 0x97,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x0B, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x02, 0x26,0xE4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x13, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x26,0xA0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
+0x00,0x11, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x18,0x2C, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x09, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05,
+0x7A,0x78, 0xF0,0x05, 0x32,0xE8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x18,0x55, 0xF6,0x86, 0x71,0xC4, 0xE0,0x00, 0x18,0x6C, 0xF6,0x02,
+0x00,0x00, 0xF7,0x04, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
+0x68,0x00, 0x86,0x3A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x32,0xC4, 0x86,0xB2,
+0x00,0x08, 0x07,0x01, 0x80,0x00, 0xC5,0xB4, 0x74,0x00, 0xF5,0x85, 0x32,0xD0, 0x87,0x32,
+0x00,0x18, 0xF6,0x86, 0x6F,0x44, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x2E,
+0x00,0x00, 0xF7,0x05, 0x32,0xC0, 0x07,0x38, 0x09,0xD8, 0x86,0xB2, 0x00,0x04, 0xF7,0x05,
+0x32,0xCC, 0xE6,0x00, 0x19,0x41, 0xF6,0x85, 0x32,0xC8, 0xF7,0x04, 0x71,0x98, 0xF6,0x84,
+0x7A,0x78, 0x27,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x19,0x10, 0xF7,0x05,
+0x71,0x98, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x18,0xE8, 0xF3,0x02, 0x00,0x11, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05, 0x76,0xFC, 0xE0,0x00,
+0x18,0xF8, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x32,0xD4, 0xF3,0x05,
+0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x19,0x14, 0xF3,0x02,
+0x00,0x01, 0xF3,0x06, 0x31,0x10, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF3,0x02,
+0x00,0x01, 0xF3,0x05, 0x7A,0x78, 0xF3,0x06, 0x30,0x84, 0xF3,0x05, 0x32,0xD4, 0xF3,0x04,
+0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x26,0x8C, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
+0x00,0x00, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x1C,0xB9, 0x93,0x16, 0xFF,0xE4, 0x87,0x32,
+0x00,0x08, 0x86,0x96, 0xFF,0xE4, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+0x19,0x84, 0x20,0x36, 0x00,0x00, 0x87,0x32, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x32,0x00, 0xE6,0x00, 0x19,0x84, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02, 0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16,
+0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A, 0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C,
+0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00,
+0x1A,0x70, 0x96,0x16, 0xFF,0xEC, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
+0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E,
+0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x00, 0xC4,0x84,
+0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x1A,0x04, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
+0x00,0x00, 0xE6,0x00, 0x1A,0x11, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2,
+0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0x1A,0x4C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1A,0x54, 0x20,0x2E,
+0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0x1A,0x55, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0x1A,0x65, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26,
+0x00,0x00, 0xE6,0x00, 0x1A,0x70, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16,
+0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1A,0xB1, 0xF6,0x02,
+0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1B,0x18, 0x96,0x96, 0xFF,0xF4, 0x27,0x14,
+0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96,
+0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1B,0x15, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x1B,0x1C, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1C,0xB8, 0xF3,0x02,
+0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0,
+0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32, 0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xEC,0x00, 0x1C,0x04, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8, 0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE,
+0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x1B,0x94, 0xC4,0x84, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x1B,0x98, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
+0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x1B,0xA5, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
+0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0x1B,0xE0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x1B,0xE8, 0x20,0x32, 0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x1B,0xE9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1B,0xF9, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
+0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x1C,0x04, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
+0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00,
+0x1C,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
+0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
+0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00, 0x1C,0xAC, 0x96,0x96,
+0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93,
+0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x1C,0xA9, 0xF6,0x02,
+0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00,
+0x1C,0xB0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x1E,0x15, 0xF3,0x02, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6,
+0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E, 0x00,0x10, 0xE2,0x00, 0x1C,0xDC, 0x20,0x32,
+0x00,0x10, 0xE2,0x00, 0x1C,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00,
+0x1D,0x24, 0xF7,0x02, 0x00,0x00, 0x07,0x30, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00,
+0x1D,0x1D, 0xF6,0x82, 0x00,0x00, 0x20,0x32, 0x00,0x10, 0xE6,0x00, 0x1D,0x20, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0x1D,0x24, 0xC7,0x34, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34,
+0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0x14, 0xF3,0x02, 0x00,0x01, 0xF3,0x04,
+0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x1D,0x91, 0x76,0xB1,
+0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A,
+0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00, 0x1D,0xFC, 0xF3,0x02, 0x00,0x00, 0xF3,0x02,
+0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
+0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
+0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16,
+0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+0x1D,0xEC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00,
+0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16,
+0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x1E,0x18, 0xF3,0x02,
+0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+0x00,0x00, 0xE6,0x00, 0x1F,0x35, 0xF6,0x82, 0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16,
+0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A,
+0x00,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
+0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x1E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04,
+0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1E,0xAD, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x1E,0xAC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
+0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x1E,0xC8, 0xF7,0x05,
+0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
+0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
+0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
+0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
+0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04, 0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA,
+0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x1F,0x60, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02,
+0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00, 0x1F,0x68, 0xF7,0x02, 0x00,0x01, 0xF3,0x05,
+0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x1F,0x7C, 0xF3,0x06,
+0x2F,0x6C, 0xE0,0x00, 0x26,0x8C, 0xF3,0x05, 0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94,
+0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00, 0x22,0x84, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02,
+0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05, 0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84,
+0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02, 0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84,
+0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02,
+0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05, 0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96,
+0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06,
+0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05,
+0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x34, 0x00,0x00,
+0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x20,0x25, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x26,0x8C, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82, 0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38,
+0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x20,0x90, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04,
+0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x20,0x84, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x20,0x94, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05,
+0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x21,0xC0, 0x00,0x00,
+0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05,
+0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+0x00,0x10, 0xE2,0x00, 0x21,0x19, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00,
+0x21,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13,
+0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38,
+0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38,
+0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96,
+0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x21,0x78, 0x00,0x00,
+0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06,
+0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x21,0xC0, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0x21,0xC1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04,
+0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x21,0xFD, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x21,0xFC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84,
+0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x22,0x18, 0xF7,0x05,
+0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05,
+0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00,
+0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04,
+0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x25,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00, 0x00,0x01, 0xE0,0x00, 0x25,0xDC, 0xF3,0x06,
+0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02, 0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02,
+0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06, 0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04,
+0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05,
+0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x22,0xD5, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A,
+0x5A,0x00, 0xE6,0x00, 0x26,0x20, 0xC0,0x32, 0x6A,0x00, 0xEE,0x00, 0x26,0x21, 0x00,0x00,
+0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00,
+0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04,
+0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04,
+0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04,
+0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x23,0x45, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x23,0x48, 0xF7,0x05,
+0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
+0x00,0x21, 0xE2,0x00, 0x23,0x8C, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x23,0x80, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
+0x00,0x22, 0xE0,0x00, 0x23,0x90, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84,
+0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0x87,0x02,
+0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16, 0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13,
+0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93,
+0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x24,0x78, 0x00,0x00,
+0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00,
+0x24,0x15, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x24,0x78, 0x00,0x00,
+0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1,
+0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16,
+0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13,
+0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30,
+0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x24,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
+0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A,
+0x32,0x00, 0xE6,0x00, 0x24,0xBC, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
+0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x24,0xBD, 0x00,0x00,
+0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x24,0xF9, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x24,0xF8, 0xB3,0x3A,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38,
+0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x25,0x14, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05,
+0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36,
+0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0x25,0xD9, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x79, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x25,0x78, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x25,0xD1, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E,
+0x00,0x21, 0xE2,0x00, 0x25,0xC4, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x25,0xB0, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02,
+0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x00, 0x25,0xC8, 0xF3,0x05,
+0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00, 0x25,0xD8, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00,
+0x25,0xDC, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06, 0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04,
+0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x26,0x8C, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x26,0x8C, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x26,0x8C, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xEE,0x00, 0x26,0x41, 0xC5,0xB4,
+0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00, 0x26,0x48, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8,
+0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84, 0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35,
+0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6,
+0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04, 0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02,
+0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85,
+0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x7A,0x78, 0xF7,0x06,
+0x30,0x84, 0xF7,0x05, 0x32,0xD4, 0xF7,0x04, 0x32,0xC4, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x06,0x10, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04,
+0x32,0xD0, 0xF3,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x2A,0x71, 0x93,0x16,
+0xFF,0xE4, 0xF6,0x84, 0x32,0xC4, 0x86,0x16, 0xFF,0xE4, 0x87,0x36, 0x00,0x08, 0xC3,0x04,
+0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32, 0x00,0x00, 0x87,0x36,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x27,0x3C, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02,
+0x00,0x00, 0xF7,0x04, 0x32,0xC0, 0x93,0x16, 0xFF,0xAC, 0xF5,0x84, 0x32,0xC4, 0x86,0x3A,
+0x14,0x28, 0x03,0xB8, 0x14,0x20, 0x04,0x2C, 0x00,0x08, 0x86,0xBA, 0x14,0x24, 0x00,0x00,
+0x00,0x01, 0xC0,0x32, 0x6A,0x00, 0xEC,0x00, 0x28,0x28, 0x96,0x16, 0xFF,0xEC, 0x77,0x31,
+0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x38,0x00, 0x06,0x30,
+0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2E, 0x00,0x08, 0x85,0x16, 0xFF,0xAC, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x27,0xB8, 0xC4,0x84, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x27,0xBC, 0x20,0x2A,
+0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x27,0xC9, 0x00,0x00,
+0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x04, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x28,0x0C, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x28,0x0D, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x28,0x1D, 0x20,0x26,
+0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x28,0x28, 0xF3,0x02,
+0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+0x00,0x00, 0xE6,0x00, 0x28,0x69, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
+0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
+0x28,0xD0, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x94,0x13,
+0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x28,0xCD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9,
+0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4,
+0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x1E,
+0x00,0x08, 0xE0,0x00, 0x28,0xD4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0x2A,0x70, 0xF3,0x02, 0x00,0x00, 0xF6,0x04, 0x32,0xC0, 0x93,0x16,
+0xFF,0xAC, 0x86,0xB2, 0x14,0x28, 0x03,0xB0, 0x14,0x20, 0x04,0x30, 0x14,0x8C, 0x87,0x32,
+0x14,0x24, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x29,0xBC, 0x96,0x96,
+0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC5,0xB8,
+0x38,0x00, 0x05,0xAC, 0x00,0x0C, 0x86,0xAE, 0x00,0x00, 0x87,0x32, 0x14,0x8C, 0x85,0x16,
+0xFF,0xAC, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0x4C, 0xC4,0x84, 0x00,0x00, 0x86,0xAE,
+0x00,0x04, 0x87,0x32, 0x14,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x29,0x50, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+0x29,0x5D, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x86,0xAE, 0x00,0x00, 0x87,0x22,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x29,0x98, 0xF6,0x02,
+0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x29,0xA0, 0x20,0x32, 0x00,0x00, 0x86,0xAE,
+0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0x29,0xA1, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x29,0xB1, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+0x29,0xBC, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xAC, 0x83,0x16, 0xFF,0xAC, 0x00,0x00,
+0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x29,0xFD, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xF0, 0xE0,0x00, 0x2A,0x64, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13,
+0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0xBC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xBC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x2A,0x61, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
+0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+0x38,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0x96,0x96,
+0xFF,0xF4, 0x97,0x1E, 0x00,0x08, 0xE0,0x00, 0x2A,0x68, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x2B,0xCD, 0xF3,0x02, 0x00,0x01, 0xF6,0x84,
+0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x85,0xB6, 0x0E,0xF4, 0x86,0x36, 0x0E,0xF8, 0x20,0x2E,
+0x00,0x10, 0xE2,0x00, 0x2A,0x94, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2A,0xB1, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x0F,0x00, 0x87,0x36, 0x0F,0x00, 0xE0,0x00, 0x2A,0xDC, 0xF7,0x02, 0x00,0x00, 0x07,0x30,
+0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x2A,0xD5, 0xF6,0x82, 0x00,0x00, 0x20,0x32,
+0x00,0x10, 0xE6,0x00, 0x2A,0xD8, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x2A,0xDC, 0xC7,0x34,
+0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xC7,0x34, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x2B,0xCC, 0xF3,0x02, 0x00,0x01, 0xF3,0x04, 0x32,0xCC, 0x00,0x00, 0x00,0x01, 0x93,0x16,
+0xFF,0xDC, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0x68, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0x83,0x16,
+0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x86,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+0x00,0x10, 0xE2,0x00, 0x2B,0x49, 0x76,0xB1, 0x00,0x02, 0x87,0x1A, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x1A, 0x00,0x0C, 0x87,0x1A, 0x00,0x0C, 0xE0,0x00,
+0x2B,0xB4, 0xF3,0x02, 0x00,0x00, 0xF3,0x02, 0x00,0x4C, 0x93,0x13, 0xFF,0xFC, 0xC6,0xB4,
+0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xDC, 0xC7,0x38,
+0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
+0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x06,0x30,
+0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00, 0x2B,0xA4, 0x00,0x00, 0x00,0x01, 0xF6,0x02,
+0x00,0x00, 0x83,0x16, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0x96,0x1A, 0x00,0x00, 0xF3,0x02,
+0x00,0x01, 0x93,0x16, 0xFF,0xD4, 0x83,0x16, 0xFF,0xD4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+0x00,0x00, 0xE6,0x00, 0x2B,0xD0, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0xE4, 0x83,0x16,
+0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0xED, 0xF6,0x82,
+0x0C,0xAB, 0xF7,0x04, 0x32,0xB4, 0x83,0x16, 0xFF,0xD4, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x32,0xB4, 0xF7,0x04, 0x32,0xB4, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x2C,0x28, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+0x2C,0x28, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x32,0xE8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x2C,0x65, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2C,0x64, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xE6,0x00, 0x2C,0x80, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
+0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
+0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x32,0xE8, 0xF7,0x04,
+0x32,0xC0, 0xF6,0x04, 0x6F,0x54, 0x96,0xBA, 0x00,0x04, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x2D,0x18, 0xF3,0x02, 0x00,0x0C, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x54, 0xE0,0x00,
+0x2D,0x20, 0xF7,0x02, 0x00,0x01, 0xF3,0x05, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x2D,0x34, 0xF3,0x06, 0x2F,0x6C, 0xE0,0x00, 0x34,0x44, 0xF3,0x05,
+0x32,0xD4, 0xF5,0x84, 0x7A,0x70, 0x24,0x94, 0x00,0x10, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
+0x30,0x3C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
+0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
+0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
+0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
+0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
+0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
+0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF3,0x06, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF3,0x05, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
+0x74,0x00, 0xE6,0x00, 0x2D,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
+0x2D,0xDD, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
+0x00,0x10, 0xE6,0x00, 0x34,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
+0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+0x2E,0x48, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x2E,0x3C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
+0x2E,0x4C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
+0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x02, 0xE6,0x00, 0x2F,0x78, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C,
+0x0E,0xF4, 0x93,0x16, 0xFF,0xCC, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96,
+0xFF,0xB8, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+0xFF,0xB8, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
+0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x2E,0xD1, 0xF3,0x02,
+0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
+0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x2F,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+0xFF,0xFC, 0xF3,0x06, 0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
+0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xCC, 0xC7,0x38,
+0x60,0x00, 0xC7,0x38, 0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
+0xFF,0xB8, 0x96,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
+0xFF,0xFC, 0x86,0x16, 0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32,
+0x00,0x11, 0xE6,0x00, 0x2F,0x30, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
+0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+0x2F,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
+0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x2F,0x79, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
+0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x2F,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x2F,0xB4, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xE6,0x00, 0x2F,0xD0, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
+0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+0x33,0x91, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00,
+0x00,0x01, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
+0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF3,0x06,
+0x32,0x28, 0xF3,0x05, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
+0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x30,0x8D, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x33,0xD8, 0xC0,0x32,
+0x6A,0x00, 0xEE,0x00, 0x33,0xD9, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x30,0xFD, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0x31,0x00, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
+0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x31,0x44, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x31,0x38, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00, 0x31,0x48, 0xF3,0x05,
+0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+0x32,0x74, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x03,0x2C, 0x0E,0xF4, 0x93,0x16,
+0xFF,0xC4, 0xF7,0x05, 0x7A,0x68, 0x93,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xB8, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x31,0xCD, 0xF3,0x02, 0x00,0x4C, 0x87,0x2E,
+0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+0x0F,0x00, 0xE0,0x00, 0x32,0x30, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06,
+0x7A,0x28, 0x93,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x83,0x16, 0xFF,0xC4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+0x30,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xB8, 0x96,0x16,
+0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xB4, 0x85,0x96, 0xFF,0xB8, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+0x32,0x2C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+0x32,0xC0, 0xF3,0x06, 0xE0,0x30, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0x32,0x74, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x00, 0x32,0x75, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x32,0xB1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0A, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x32,0xB0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x32,0xCC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x33,0x91, 0xF7,0x05,
+0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x33,0x31, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x33,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x33,0x89, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x33,0x7C, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x33,0x68, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
+0x77,0x00, 0xE0,0x00, 0x33,0x80, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+0x33,0x90, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x33,0x94, 0xF3,0x06, 0x31,0x9C, 0xF3,0x06,
+0x2E,0xE0, 0xF3,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x34,0x44, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x34,0x44, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00,
+0x34,0x44, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xEE,0x00, 0x33,0xF9, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
+0x34,0x00, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF6,0x84,
+0x7A,0x88, 0xF7,0x06, 0x7A,0x28, 0x76,0x35, 0x00,0x03, 0xA7,0x32, 0x70,0x02, 0x06,0xB4,
+0x00,0x01, 0x97,0x16, 0xFF,0xEC, 0x84,0xA6, 0xFF,0xFC, 0xF7,0x06, 0x7A,0x2C, 0xF3,0x04,
+0x7A,0x98, 0x94,0x82, 0xFF,0x3C, 0x93,0x02, 0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2,
+0x70,0x02, 0xF7,0x04, 0x7A,0x98, 0xF6,0x85, 0x7A,0x88, 0xC7,0x38, 0x58,0x00, 0xF7,0x05,
+0x7A,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x20, 0xF5,0x84, 0x7A,0x70, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
+0x37,0x6C, 0xF5,0x85, 0x7A,0xA0, 0xF7,0x02, 0x00,0x01, 0xF6,0x04, 0x32,0xC8, 0xF7,0x05,
+0x7A,0x70, 0xF7,0x04, 0x32,0xC4, 0xF6,0x84, 0x32,0xC0, 0xF6,0x05, 0x7A,0x2C, 0x90,0x02,
+0xFF,0x80, 0x90,0x02, 0xFF,0x38, 0xF5,0x84, 0x7A,0x28, 0x07,0x38, 0x00,0x24, 0x95,0x82,
+0xFF,0x3C, 0x97,0x02, 0xFF,0x40, 0x96,0x02, 0xFF,0x44, 0x87,0x36, 0x14,0x10, 0x00,0x00,
+0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36, 0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF0,0x05,
+0x6F,0x50, 0xF7,0x04, 0x32,0xB8, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xF7,0x05,
+0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0xF4,0x86, 0x2F,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0xF4,0x85, 0x32,0xD4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
+0x74,0x00, 0xE6,0x00, 0x35,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
+0x35,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
+0x00,0x10, 0xE6,0x00, 0x3B,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE4, 0xFF,0x82,
+0x00,0x10, 0xF5,0x84, 0x6F,0x58, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+0x35,0x78, 0xF7,0x05, 0x32,0xE4, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x35,0x6C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
+0x35,0x7C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00,
+0x00,0x01, 0x90,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x02, 0xE6,0x00, 0x36,0xA8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC,
+0x0E,0xF4, 0x94,0x96, 0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
+0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+0xFF,0xDC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
+0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x36,0x01, 0xF4,0x82,
+0x00,0x4C, 0x87,0x2E, 0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E,
+0x0F,0x00, 0x87,0x2E, 0x0F,0x00, 0xE0,0x00, 0x36,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+0xFF,0xFC, 0xF4,0x86, 0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
+0x60,0x00, 0x77,0x35, 0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38,
+0x60,0x00, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96,
+0xFF,0xDC, 0x96,0x16, 0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
+0xFF,0xFC, 0x86,0x16, 0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32,
+0x00,0x11, 0xE6,0x00, 0x36,0x60, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E,
+0x0E,0xF8, 0xF7,0x04, 0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
+0x36,0xA8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
+0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x36,0xA9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
+0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x36,0xE5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+0x00,0x0A, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x36,0xE4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF7,0x04, 0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xE6,0x00, 0x37,0x00, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84,
+0x71,0xD4, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+0x00,0x01, 0xF6,0x84, 0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+0x3A,0xC1, 0xF7,0x05, 0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00,
+0x00,0x01, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF0,0x05, 0x7A,0x88, 0x90,0x02,
+0xFF,0x38, 0xF0,0x05, 0x6F,0x50, 0x90,0x02, 0xFF,0x80, 0xF7,0x04, 0x32,0xC4, 0xF4,0x86,
+0x32,0x28, 0xF4,0x85, 0x32,0xD4, 0xF6,0x04, 0x32,0xC8, 0xF6,0x84, 0x7A,0x2C, 0xF5,0x02,
+0x00,0x00, 0x07,0x38, 0x00,0x24, 0xF7,0x05, 0x7A,0x98, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x37,0xBD, 0xF6,0x05, 0x7A,0x90, 0xC0,0x2A, 0x5A,0x00, 0xE6,0x00, 0x3B,0x08, 0xC0,0x32,
+0x6A,0x00, 0xEE,0x00, 0x3B,0x09, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x38,0x2D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0x38,0x30, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
+0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x38,0x74, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x38,0x68, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x38,0x78, 0xF4,0x85,
+0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+0x39,0xA4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
+0xFF,0xE4, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xDC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x38,0xFD, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
+0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+0x0F,0x00, 0xE0,0x00, 0x39,0x60, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
+0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xE4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xDC, 0x96,0x16,
+0xFF,0xD8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xD8, 0x85,0x96, 0xFF,0xDC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+0x39,0x5C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x39,0xA4, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x00, 0x39,0xA5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x39,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x39,0xE0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x39,0xFC, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3A,0xC1, 0xF7,0x05,
+0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x3A,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x3A,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3A,0xB9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3A,0xAC, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3A,0x98, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
+0x77,0x00, 0xE0,0x00, 0x3A,0xB0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+0x3A,0xC0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3A,0xC4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
+0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x3B,0x70, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3B,0x70, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+0x3B,0x70, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xEE,0x00, 0x3B,0x29, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
+0x3B,0x30, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
+0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
+0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
+0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF5,0x04,
+0x7A,0x88, 0xF7,0x06, 0x7A,0x2C, 0xF5,0x84, 0x7A,0x90, 0x76,0xA9, 0x00,0x03, 0xA6,0xB6,
+0x70,0x02, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x3B,0xCD, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x7A,0xA0, 0x00,0x00, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x3F,0x18, 0xC0,0x2E,
+0x6A,0x00, 0xEE,0x00, 0x3F,0x19, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x32,0xC0, 0xF6,0x04,
+0x32,0xC8, 0x87,0x36, 0x14,0x10, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x97,0x36,
+0x14,0x10, 0x87,0x36, 0x14,0x18, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x18, 0x87,0x36, 0x14,0x18, 0xF7,0x04, 0x32,0xB8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x60,0x00, 0xF7,0x05, 0x32,0xB8, 0xF7,0x04, 0x32,0xBC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x32,0xBC, 0xF7,0x04, 0x32,0xBC, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+0x3C,0x3D, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x32,0xE0, 0xF6,0x85, 0x7A,0x70, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0x3C,0x40, 0xF7,0x05, 0x32,0xE0, 0xF5,0x05, 0x7A,0x70, 0xF5,0x84,
+0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3C,0x84, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3C,0x78, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x3C,0x88, 0xF4,0x85,
+0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+0x3D,0xB4, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x04,0xAC, 0x0E,0xF4, 0x94,0x96,
+0xFF,0xEC, 0xF7,0x05, 0x7A,0x68, 0x94,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xE4, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x3D,0x0D, 0xF4,0x82, 0x00,0x4C, 0x87,0x2E,
+0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+0x0F,0x00, 0xE0,0x00, 0x3D,0x70, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0xF4,0x86,
+0x7A,0x28, 0x94,0x93, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x84,0x96, 0xFF,0xEC, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+0x48,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xE4, 0x96,0x16,
+0xFF,0xE0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xE0, 0x85,0x96, 0xFF,0xE4, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+0x3D,0x6C, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+0x32,0xC0, 0xF4,0x86, 0xE0,0x30, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x3D,0xB4, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x00, 0x3D,0xB5, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x3D,0xF1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0A, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x3D,0xF0, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x3E,0x0C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x3E,0xD1, 0xF7,0x05,
+0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x3E,0x71, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x3E,0x70, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x3E,0xC9, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3E,0xBC, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3E,0xA8, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xF4,0x85, 0x76,0xF8, 0xF4,0x84,
+0x77,0x00, 0xE0,0x00, 0x3E,0xC0, 0xF4,0x85, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+0x3E,0xD0, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x3E,0xD4, 0xF4,0x86, 0x31,0x9C, 0xF4,0x86,
+0x2E,0xE0, 0xF4,0x85, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x3F,0x80, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0x80, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+0x3F,0x80, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x7A,0x90, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xEE,0x00, 0x3F,0x39, 0xC5,0xB4, 0x00,0x00, 0xC7,0x38, 0x5A,0x00, 0xE0,0x00,
+0x3F,0x40, 0xF7,0x05, 0x7A,0x90, 0xC5,0xB8, 0x00,0x00, 0xF0,0x05, 0x7A,0x90, 0xF7,0x04,
+0x7A,0x88, 0xF6,0x86, 0x7A,0x28, 0x76,0x39, 0x00,0x03, 0xA6,0xB2, 0x68,0x02, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x7A,0x88, 0xF7,0x04, 0x7A,0x98, 0x96,0x96, 0xFF,0xF4, 0x96,0x82,
+0xFF,0x3C, 0xF4,0x84, 0x7A,0x98, 0xF6,0x86, 0x7A,0x2C, 0xC7,0x38, 0x58,0x00, 0x94,0x82,
+0xFF,0x40, 0x95,0x82, 0xFF,0x44, 0xB5,0xB2, 0x68,0x02, 0xF7,0x05, 0x7A,0x98, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF5,0x84,
+0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x3F,0xE4, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x3F,0xD8, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xE0,0x00, 0x3F,0xE8, 0xF5,0x05,
+0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF5,0x84, 0x32,0xC0, 0x00,0x00, 0x00,0x01, 0x90,0x2E,
+0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+0x41,0x14, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x38, 0x05,0x2C, 0x0E,0xF4, 0x95,0x16,
+0xFF,0xF4, 0xF7,0x05, 0x7A,0x68, 0x95,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x43,0xA0, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x2E, 0x0E,0xF8, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x40,0x6D, 0xF5,0x02, 0x00,0x4C, 0x87,0x2E,
+0x0F,0x00, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x0F,0x00, 0x87,0x2E,
+0x0F,0x00, 0xE0,0x00, 0x40,0xD0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
+0x7A,0x28, 0x95,0x13, 0xFF,0xFC, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+0x00,0x04, 0xC7,0x38, 0x6A,0x00, 0x85,0x16, 0xFF,0xF4, 0xC7,0x38, 0x60,0x00, 0xC7,0x38,
+0x50,0x00, 0x07,0x38, 0x00,0x10, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x96,0x16,
+0xFF,0xE8, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xE8, 0x85,0x96, 0xFF,0xEC, 0x06,0x30, 0x00,0x01, 0x20,0x32, 0x00,0x11, 0xE6,0x00,
+0x40,0xCC, 0x00,0x00, 0x00,0x01, 0xF6,0x02, 0x00,0x00, 0x96,0x2E, 0x0E,0xF8, 0xF7,0x04,
+0x32,0xC0, 0xF5,0x06, 0xE0,0x30, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0x41,0x14, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1E, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x00, 0x41,0x15, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04,
+0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04,
+0x79,0xC8, 0xF7,0x04, 0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x41,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0A, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x41,0x50, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+0x71,0xD4, 0xF6,0x84, 0x71,0xCC, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x41,0x6C, 0xF7,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD4, 0xF6,0x84, 0x71,0xD4, 0xF7,0x04,
+0x71,0xD0, 0xF0,0x05, 0x71,0xC4, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xF6,0x84,
+0x32,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x42,0x31, 0xF7,0x05,
+0x71,0xC8, 0xF7,0x04, 0x71,0x98, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x41,0xD1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x41,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x42,0x29, 0x00,0x00, 0x00,0x01, 0xF5,0x84,
+0x76,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x42,0x1C, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x08, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04,
+0x77,0x00, 0xE0,0x00, 0x42,0x20, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xE0,0x00,
+0x42,0x30, 0xF0,0x05, 0x7A,0x78, 0xE0,0x00, 0x42,0x34, 0xF5,0x06, 0x31,0x9C, 0xF5,0x06,
+0x2E,0xE0, 0xF5,0x05, 0x32,0xD4, 0xF7,0x04, 0x71,0xC8, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x42,0x74, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02,
+0x00,0x09, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x42,0x74, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
+0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x2E,0xE0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x2F,0x6C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x2F,0xF8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x30,0x84, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x31,0x10, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x31,0x9C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x32,0xD4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x32,0x28, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x00, 0x87,0x3A, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x2E,
+0x00,0x00, 0x86,0xAE, 0x00,0x04, 0x20,0x32, 0x00,0x10, 0xE2,0x00, 0x43,0xD0, 0x00,0x00,
+0x00,0x01, 0x20,0x36, 0x00,0x10, 0xE2,0x00, 0x43,0xED, 0x07,0x34, 0x00,0x01, 0x87,0x2E,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x0C, 0x87,0x2E,
+0x00,0x0C, 0xE0,0x00, 0x44,0x14, 0xF4,0x02, 0x00,0x00, 0xC0,0x3A, 0x62,0x00, 0xE6,0x00,
+0x44,0x11, 0xF4,0x02, 0x00,0x00, 0x20,0x36, 0x00,0x10, 0xE6,0x00, 0x44,0x14, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x44,0x14, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
+0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
+0x00,0x01, 0xF7,0x05, 0x35,0x24, 0xF7,0x04, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0xF7,0x05,
+0x35,0x28, 0xF7,0x06, 0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
+0x45,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0D, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x02, 0x4A,0x04, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x0F, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x4E,0xEC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02,
+0x00,0x08, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x57,0x64, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x02, 0x00,0x07, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
+0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x2D, 0xF6,0x86,
+0x75,0xF8, 0xE0,0x00, 0x45,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
+0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x5C, 0xF7,0x05, 0x35,0x48, 0xF4,0x86,
+0x33,0x80, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0x6F,0x54, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0x80, 0xF4,0x82, 0x00,0x08, 0xF4,0x82,
+0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x45,0x88, 0xF7,0x02, 0x00,0x01, 0xF4,0x85,
+0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x45,0xA0, 0xF4,0x82,
+0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF6,0x84,
+0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82,
+0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36,
+0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2,
+0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00,
+0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
+0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2,
+0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82,
+0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02,
+0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82,
+0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2,
+0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96,
+0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2,
+0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E,
+0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00,
+0x49,0xF0, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0xA4, 0x00,0x00,
+0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x46,0x95, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x49,0xF0, 0x00,0x00,
+0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
+0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+0x47,0x08, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x46,0xFC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00,
+0x47,0x0C, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00,
+0x47,0x71, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x47,0x69, 0xC6,0x38,
+0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x0F, 0xE2,0x00, 0x47,0xBD, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+0x47,0xD0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+0x00,0x08, 0xE0,0x00, 0x49,0x68, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+0x47,0xCC, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x48,0x1C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0x48,0x81, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86,
+0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x48,0x81, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x48,0x80, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x49,0x68, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x02, 0xE6,0x00, 0x49,0x3C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x49,0x11, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x49,0x2C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x47,0xA8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0x5C, 0x07,0x34, 0x14,0x94, 0xF4,0x84,
+0x6F,0x44, 0xE0,0x00, 0x49,0x60, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+0x48,0x84, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x49,0xA1, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x49,0xA8, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00, 0x49,0xA8, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82,
+0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86,
+0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x49,0xF0, 0xF4,0x85, 0x35,0x30, 0xF7,0x04,
+0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0x49,0xF1, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF7,0x04,
+0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x2D, 0xF6,0x86,
+0x75,0xF8, 0xE0,0x00, 0x4A,0x40, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x04, 0x00,0x00,
+0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04,
+0x6F,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4A,0x64, 0xF6,0x85,
+0x35,0x48, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x6F,0x54, 0xE0,0x00, 0x4A,0x70, 0xF7,0x02,
+0x00,0x01, 0xF4,0x82, 0x00,0x08, 0xF4,0x85, 0x6F,0x58, 0xF7,0x02, 0x00,0x00, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x4A,0x88, 0xF4,0x82, 0x00,0x04, 0xF4,0x86, 0x34,0x0C, 0xE0,0x00,
+0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0xB7,
+0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x87,0x32,
+0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32, 0x00,0x90, 0xF4,0x85,
+0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
+0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x14, 0x84,0xB6,
+0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6, 0x00,0x14, 0x00,0x00,
+0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00, 0x00,0x01, 0xF4,0x85,
+0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04, 0x35,0x54, 0xF4,0x86,
+0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2, 0x00,0x00, 0x06,0xB4,
+0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32, 0x00,0x04, 0xF6,0x85,
+0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05, 0x35,0x4C, 0xF7,0x04,
+0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0xF7,0x05,
+0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E, 0x14,0x14, 0x00,0x00,
+0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32, 0x00,0x80, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x4E,0xD8, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E,
+0x74,0x00, 0xE6,0x00, 0x4B,0x8C, 0x00,0x00, 0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00,
+0x4B,0x7D, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A,
+0x00,0x10, 0xE6,0x00, 0x4E,0xD8, 0x00,0x00, 0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82,
+0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38,
+0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x4B,0xF0, 0xF7,0x05, 0x35,0x58, 0xF7,0x04,
+0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4B,0xE4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x4B,0xF4, 0xF4,0x85, 0x6F,0x58, 0xF0,0x05,
+0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC4,0x84,
+0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x4C,0x59, 0x00,0x00, 0x00,0x01, 0x86,0x36,
+0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
+0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4,
+0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38,
+0x00,0x24, 0xE6,0x00, 0x4C,0x51, 0xC6,0x38, 0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04,
+0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00, 0x4C,0xA5, 0x07,0x38,
+0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x4C,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00, 0x4E,0x50, 0xF7,0x05,
+0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x4C,0xB4, 0x00,0x00, 0x00,0x01, 0xF7,0x02,
+0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6,
+0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x4D,0x04, 0xF7,0x05, 0x76,0x04, 0xF0,0x05,
+0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36,
+0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF7,0x05,
+0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4D,0x69, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4D,0x68, 0xB4,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00,
+0x4E,0x50, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0x4E,0x24, 0x05,0xB4,
+0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96,
+0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
+0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+0x00,0x0F, 0xE2,0x00, 0x4D,0xF9, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00,
+0x4E,0x14, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35,
+0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C,
+0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x4C,0x90, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84,
+0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x4E,0x44, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00, 0x4E,0x48, 0xF4,0x85,
+0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x4D,0x6C, 0x05,0x28, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0x4E,0x89, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00,
+0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x4E,0x90, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+0x4E,0x90, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85, 0x35,0x24, 0xF6,0x84,
+0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x4E,0xD8, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8,
+0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x4E,0xD9, 0x00,0x00, 0x00,0x01, 0x0F,0x81,
+0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF6,0x84, 0x35,0x48, 0xF6,0x04, 0x35,0x2C, 0xF4,0x82,
+0x00,0x04, 0xF4,0xB7, 0x28,0x00, 0x07,0x34, 0x00,0x02, 0xF4,0x82, 0x00,0x01, 0xF4,0xBB,
+0x28,0x00, 0x87,0x32, 0x00,0x8C, 0xF4,0x82, 0x00,0x01, 0x97,0x36, 0x00,0x18, 0x87,0x32,
+0x00,0x90, 0xF4,0x85, 0x6F,0x50, 0x97,0x36, 0x00,0x04, 0x84,0xB2, 0x00,0x84, 0x00,0x00,
+0x00,0x01, 0x94,0xB6, 0x00,0x10, 0x84,0xB2, 0x00,0x88, 0x00,0x00, 0x00,0x01, 0x94,0xB6,
+0x00,0x14, 0x84,0xB6, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x08, 0x84,0xB6,
+0x00,0x14, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x00,0x0C, 0x84,0xB2, 0x00,0x98, 0x00,0x00,
+0x00,0x01, 0xF4,0x85, 0x35,0x54, 0xF4,0x82, 0x00,0x01, 0x94,0x82, 0xFF,0x80, 0xF5,0x04,
+0x35,0x54, 0xF4,0x86, 0x34,0x98, 0xF4,0x85, 0x35,0x30, 0x95,0x02, 0xFF,0x38, 0x85,0xB2,
+0x00,0x00, 0x06,0xB4, 0x00,0x24, 0x95,0x82, 0xFF,0x3C, 0x96,0x82, 0xFF,0x40, 0x87,0x32,
+0x00,0x04, 0xF6,0x85, 0x35,0x50, 0x97,0x02, 0xFF,0x44, 0x86,0xB2, 0x00,0x04, 0xF0,0x05,
+0x35,0x4C, 0xF7,0x04, 0x35,0x40, 0x95,0x16, 0xFF,0xF4, 0x95,0x96, 0xFF,0xF4, 0xC7,0x38,
+0x68,0x00, 0xF7,0x05, 0x35,0x40, 0xF5,0x84, 0x35,0x28, 0x86,0xB2, 0x00,0x04, 0x87,0x2E,
+0x14,0x14, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x97,0x2E, 0x14,0x14, 0x87,0x32,
+0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x53,0x4C, 0xF7,0x06,
+0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x50,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x7E,
+0x74,0x00, 0xE6,0x00, 0x4F,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x06, 0x0C,0x3E, 0xC7,0x7C,
+0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x53,0x4C, 0x00,0x00, 0x00,0x01, 0xFF,0x82,
+0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84, 0x6F,0x58, 0xF6,0x85,
+0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00, 0x50,0x64, 0xF7,0x05,
+0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x50,0x58, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x22, 0xE0,0x00, 0x50,0x68, 0xF4,0x85,
+0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x94, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x00, 0x50,0xCD, 0x00,0x00,
+0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00, 0x00,0x01, 0x76,0xB4,
+0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39, 0x00,0x00, 0x97,0x16,
+0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4, 0x00,0x0F, 0x70,0x3E,
+0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x50,0xC5, 0xC6,0x38, 0x60,0x00, 0x06,0xB4,
+0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84, 0x35,0x44, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0xE2,0x00,
+0x51,0x19, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00, 0x51,0x2C, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38, 0x00,0x08, 0xE0,0x00,
+0x52,0xC4, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x51,0x28, 0x00,0x00,
+0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x3C, 0xF6,0x84,
+0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04, 0x35,0x3C, 0x87,0x36,
+0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x14,0x1C, 0xF7,0x04,
+0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38, 0x00,0x01, 0xF6,0x84,
+0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0x51,0x78, 0xF7,0x05,
+0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04, 0x76,0x08, 0xF0,0x05,
+0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0x51,0xDD, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF4,0x86, 0x72,0x18, 0xC0,0x3A,
+0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0xDD, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x51,0xDC, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02, 0x00,0x00, 0x20,0x2A,
+0x00,0x02, 0xEE,0x00, 0x52,0xC4, 0xF6,0x82, 0x00,0x00, 0xF6,0x84, 0x35,0x28, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+0x52,0x98, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16, 0xFF,0xEC, 0x95,0x96,
+0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x5E,0xDC, 0x97,0x93,
+0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96, 0xFF,0xE4, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x86,0x36, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x52,0x6D, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x14, 0x87,0x36,
+0x00,0x14, 0xE0,0x00, 0x52,0x88, 0xF7,0x02, 0x00,0x00, 0x76,0xB1, 0x00,0x02, 0xC6,0xB4,
+0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38, 0x60,0x00, 0x07,0x38,
+0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x51,0x04, 0xF7,0x05,
+0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x52,0xB8, 0x07,0x34, 0x14,0x94, 0xF4,0x84, 0x6F,0x44, 0xE0,0x00,
+0x52,0xBC, 0xF4,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00, 0x51,0xE0, 0x05,0x28,
+0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x52,0xFD, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0xF4,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x53,0x04, 0xB4,0xBA,
+0x68,0x02, 0xE0,0x00, 0x53,0x04, 0xF0,0x05, 0x2D,0x38, 0xF4,0x82, 0x00,0x01, 0xF4,0x85,
+0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF4,0x86, 0x32,0xF4, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x53,0x4C, 0xF4,0x85, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
+0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x53,0x4D, 0x00,0x00,
+0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0xF4,0x84, 0x35,0x54, 0xF6,0x84,
+0x35,0x4C, 0xF5,0x84, 0x35,0x2C, 0x94,0x82, 0xFF,0x38, 0x76,0xB5, 0x00,0x03, 0xA5,0x2E,
+0x68,0x02, 0x00,0x00, 0x00,0x01, 0x95,0x02, 0xFF,0x3C, 0xF3,0x84, 0x35,0x50, 0xC6,0xAC,
+0x68,0x00, 0x93,0x82, 0xFF,0x40, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02,
+0xFF,0x44, 0x86,0x36, 0x00,0x04, 0xF7,0x04, 0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x60,0x00, 0xF7,0x05, 0x35,0x40, 0xF6,0x04, 0x35,0x28, 0x86,0xB6, 0x00,0x04, 0x87,0x32,
+0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x97,0x32, 0x14,0x14, 0x87,0x2E,
+0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x57,0x50, 0x95,0x16,
+0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x54,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x53,0xF5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x57,0x50, 0x00,0x00,
+0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
+0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+0x54,0x68, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x54,0x5C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82, 0x00,0x22, 0xE0,0x00,
+0x54,0x6C, 0xF3,0x85, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x84, 0x00,0x00, 0xC0,0x3A, 0x3A,0x00, 0xE6,0x00,
+0x54,0xD1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x54,0xC9, 0xC6,0x38,
+0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x0F, 0xE2,0x00, 0x55,0x1D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+0x55,0x30, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+0x00,0x08, 0xE0,0x00, 0x56,0xC8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+0x55,0x2C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x55,0x7C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0x55,0xE1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x86,
+0x72,0x18, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x55,0xE1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0E, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x55,0xE0, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x56,0xC8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x02, 0xE6,0x00, 0x56,0x9C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x56,0x71, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x56,0x8C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x55,0x08, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x56,0xBC, 0x07,0x34, 0x14,0x94, 0xF3,0x84,
+0x6F,0x44, 0xE0,0x00, 0x56,0xC0, 0xF3,0x85, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+0x55,0xE4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x57,0x01, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x57,0x08, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x57,0x08, 0xF0,0x05, 0x2D,0x38, 0xF3,0x82,
+0x00,0x01, 0xF3,0x85, 0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x86,
+0x32,0xF4, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x57,0x50, 0xF3,0x85, 0x35,0x30, 0xF7,0x04,
+0xE0,0x18, 0x00,0x00, 0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0x57,0x51, 0x00,0x00, 0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x14, 0x87,0x02,
+0xFF,0x38, 0xF3,0x84, 0x35,0x2C, 0xF7,0x05, 0x35,0x54, 0x87,0x1E, 0x00,0x80, 0xF5,0x04,
+0x35,0x4C, 0x27,0x38, 0x00,0x01, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0x5A,0x4C, 0x00,0x00,
+0x00,0x01, 0xF5,0x84, 0x6F,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+0x57,0xD8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x57,0xCC, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
+0x57,0xDC, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+0x58,0x41, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x58,0x39, 0xC6,0x38,
+0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x0F, 0xE2,0x00, 0x58,0x8D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+0x58,0xA0, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+0x00,0x08, 0xE0,0x00, 0x5A,0x38, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+0x58,0x9C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x58,0xEC, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0x59,0x51, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
+0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x59,0x51, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x59,0x50, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5A,0x38, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x02, 0xE6,0x00, 0x5A,0x0C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x59,0xE1, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x59,0xFC, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x58,0x78, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5A,0x2C, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
+0x6F,0x44, 0xE0,0x00, 0x5A,0x30, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+0x59,0x54, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xC4, 0xF3,0x02,
+0x00,0x01, 0xE0,0x00, 0x5D,0xF0, 0x00,0x00, 0x00,0x01, 0x77,0x29, 0x00,0x03, 0xC7,0x1C,
+0x70,0x00, 0x87,0x3A, 0x00,0x04, 0x05,0x28, 0x00,0x01, 0x76,0xA9, 0x00,0x03, 0xF4,0x84,
+0x35,0x54, 0xF6,0x04, 0x35,0x50, 0x94,0x82, 0xFF,0x38, 0xA4,0x1E, 0x68,0x02, 0xC6,0x30,
+0x70,0x00, 0x94,0x02, 0xFF,0x3C, 0x96,0x02, 0xFF,0x40, 0xC6,0x9C, 0x68,0x00, 0x87,0x36,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x02, 0xFF,0x44, 0x85,0xB6, 0x00,0x04, 0xF7,0x04,
+0x35,0x40, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x58,0x00, 0xF7,0x05, 0x35,0x40, 0x85,0xB6,
+0x00,0x04, 0xF5,0x05, 0x35,0x4C, 0xF6,0x84, 0x35,0x28, 0xF6,0x05, 0x35,0x50, 0x87,0x36,
+0x14,0x14, 0x94,0x96, 0xFF,0xF4, 0xC7,0x38, 0x58,0x00, 0x97,0x36, 0x14,0x14, 0x87,0x1E,
+0x00,0x80, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xEE,0x00, 0x5E,0x3C, 0x94,0x16,
+0xFF,0xF4, 0xF7,0x06, 0x0C,0x3E, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xF4, 0x00,0x00,
+0x00,0x01, 0xC0,0x7E, 0x74,0x00, 0xE6,0x00, 0x5A,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x06,
+0x0C,0x3E, 0xC7,0x7C, 0x74,0x00, 0x20,0x3A, 0x00,0x10, 0xE6,0x00, 0x5E,0x3C, 0x00,0x00,
+0x00,0x01, 0xFF,0x82, 0x00,0x10, 0x86,0x82, 0xFF,0x38, 0xF7,0x04, 0x35,0x58, 0xF5,0x84,
+0x6F,0x58, 0xF6,0x85, 0x35,0x54, 0x07,0x38, 0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x00,
+0x5B,0x58, 0xF7,0x05, 0x35,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x5B,0x4C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xE0,0x00,
+0x5B,0x5C, 0xF3,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF6,0x84, 0x35,0x2C, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x94, 0xC3,0x04, 0x00,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+0x5B,0xC1, 0x00,0x00, 0x00,0x01, 0x86,0x36, 0x00,0x94, 0xF6,0x84, 0x35,0x54, 0x00,0x00,
+0x00,0x01, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x35,0x54, 0x96,0x96, 0xFF,0xF4, 0x47,0x39,
+0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF7,0x04, 0x35,0x48, 0x77,0xB4,
+0x00,0x0F, 0x70,0x3E, 0xFF,0xE1, 0x07,0x38, 0x00,0x24, 0xE6,0x00, 0x5B,0xB9, 0xC6,0x38,
+0x60,0x00, 0x06,0xB4, 0x00,0x01, 0xC7,0x04, 0x6E,0x00, 0xF7,0x33, 0x28,0x00, 0xF6,0x84,
+0x35,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x0F, 0xE2,0x00, 0x5C,0x0D, 0x07,0x38, 0x00,0x01, 0x87,0x36, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x00,0x0C, 0x87,0x36, 0x00,0x0C, 0xE0,0x00,
+0x5C,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x35,0x28, 0xF6,0x82, 0x00,0x01, 0x07,0x38,
+0x00,0x08, 0xE0,0x00, 0x5D,0xB8, 0xF7,0x05, 0x35,0x44, 0x20,0x3A, 0x00,0x10, 0xE6,0x00,
+0x5C,0x1C, 0x00,0x00, 0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x97,0x36, 0x00,0x04, 0xF7,0x04,
+0x35,0x3C, 0xF6,0x84, 0x35,0x28, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x35,0x3C, 0xF7,0x04,
+0x35,0x3C, 0x87,0x36, 0x14,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x14,0x1C, 0xF7,0x04, 0x76,0x04, 0x86,0xB6, 0x14,0x1C, 0xF6,0x04, 0x75,0xFC, 0x07,0x38,
+0x00,0x01, 0xF6,0x84, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00,
+0x5C,0x6C, 0xF7,0x05, 0x76,0x04, 0xF0,0x05, 0x76,0x04, 0xF6,0x84, 0x76,0x04, 0xF7,0x04,
+0x76,0x08, 0xF0,0x05, 0x75,0xFC, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0x5C,0xD1, 0xF7,0x05, 0x75,0xF8, 0xF7,0x04, 0x76,0x48, 0xF3,0x06,
+0x72,0x18, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x5C,0xD1, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x5C,0xD0, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+0x00,0x00, 0x20,0x2A, 0x00,0x02, 0xEE,0x00, 0x5D,0xB8, 0xF6,0x82, 0x00,0x00, 0xF6,0x84,
+0x35,0x28, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x02, 0xE6,0x00, 0x5D,0x8C, 0x05,0xB4, 0x00,0x08, 0x95,0x93, 0xFF,0xFC, 0x95,0x16,
+0xFF,0xEC, 0x95,0x96, 0xFF,0xE8, 0x96,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x5E,0xDC, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xE8, 0x86,0x96,
+0xFF,0xE4, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x86,0x36,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x0F, 0xE2,0x00, 0x5D,0x61, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36,
+0x00,0x14, 0x87,0x36, 0x00,0x14, 0xE0,0x00, 0x5D,0x7C, 0xF7,0x02, 0x00,0x00, 0x76,0xB1,
+0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0x77,0x35, 0x00,0x05, 0xC7,0x38, 0x6A,0x00, 0xC7,0x38,
+0x60,0x00, 0x07,0x38, 0x00,0x10, 0xC7,0x2C, 0x70,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x5B,0xF8, 0xF7,0x05, 0x35,0x2C, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x4C, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x5D,0xAC, 0x07,0x34, 0x14,0x94, 0xF3,0x04,
+0x6F,0x44, 0xE0,0x00, 0x5D,0xB0, 0xF3,0x05, 0x35,0x28, 0xF7,0x05, 0x35,0x28, 0xE0,0x00,
+0x5C,0xD4, 0x05,0x28, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x5D,0xF1, 0xF3,0x02,
+0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0D, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x5D,0xF4, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0x5D,0xF4, 0xF0,0x05, 0x2D,0x38, 0xF3,0x05,
+0x35,0x24, 0xF6,0x84, 0x35,0x28, 0xF7,0x04, 0x6F,0x44, 0xF3,0x06, 0x32,0xF4, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x5E,0x3C, 0xF3,0x05, 0x35,0x30, 0xF7,0x04, 0xE0,0x18, 0x00,0x00,
+0x00,0x01, 0x77,0xB8, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00, 0x5E,0x3D, 0x00,0x00,
+0x00,0x01, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x32,0xF4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x33,0x80, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x35,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x34,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x35,0x30, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x34,0x98, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x0F, 0x86,0xB2, 0x00,0x00, 0xC5,0x38, 0x00,0x00, 0xEE,0x00,
+0x5F,0x2C, 0xC5,0xB4, 0x00,0x00, 0x20,0x36, 0x00,0x0F, 0xEE,0x00, 0x5F,0x2C, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0x5F,0x2D, 0x00,0x00, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xEC,0x00, 0x5F,0x48, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x0C, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x32, 0x00,0x0C, 0x87,0x32, 0x00,0x0C, 0xE0,0x00,
+0x5F,0x50, 0xF4,0x02, 0x00,0x00, 0xC0,0x2A, 0x5A,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
+0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x66,0xF8, 0x96,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
+0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
+0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x16, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x62,0x7C, 0x96,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0x60, 0x96,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
+0x66,0xF8, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x17, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
+0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x82, 0x69,0x80, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x18, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x6B,0x50, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x16, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82, 0x61,0x78, 0x96,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x1F, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x35,0xEC, 0x96,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF6,0x82,
+0x62,0x7C, 0x96,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86,
+0x35,0xEC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x61,0x15, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0xE0,0x00, 0x61,0x18, 0x77,0x39,
+0x00,0x02, 0xF7,0x02, 0x00,0xF0, 0xF7,0x05, 0x42,0x28, 0xF7,0x06, 0x40,0x8A, 0xF0,0x3B,
+0x28,0x00, 0xF7,0x06, 0x40,0x8C, 0xF0,0x3B, 0x28,0x00, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
+0x7A,0xC0, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x05, 0x7A,0xB0, 0xF7,0x05, 0x7A,0xC8, 0xF6,0x82,
+0xC3,0x50, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x16, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
+0x42,0x30, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04,
+0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x61,0xED, 0x76,0xB1,
+0x00,0x1E, 0x87,0x32, 0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00, 0x61,0xEC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
+0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0x61,0xEC, 0xF5,0x06, 0x35,0xEC, 0xF7,0x04,
+0x42,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x62,0x11, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06,
+0x42,0xA2, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x62,0x68, 0xF7,0x33, 0x28,0x00, 0x87,0x32,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0xE0,0x00, 0x86,0xB2, 0x00,0x08, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x62,0x3C, 0xF6,0x85, 0xE0,0x04, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+0x62,0x40, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+0x62,0x65, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x04, 0x42,0x3C, 0xF6,0x84, 0x6F,0x34, 0x07,0x38, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0x62,0xB1, 0xF7,0x05, 0x42,0x3C, 0x87,0x36, 0x00,0x00, 0xF5,0x9E,
+0x00,0x02, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0x62,0xBD, 0xF5,0x86, 0x35,0xEC, 0xF7,0x04,
+0x42,0xA0, 0xE0,0x00, 0x62,0xDC, 0xF6,0x06, 0x42,0xA2, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x62,0xF9, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
+0x63,0x0C, 0xF7,0x33, 0x28,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x63,0x20, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x42,0x28, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x20, 0x83,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x87,0x1A, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x63,0x6C, 0xF7,0x02, 0x00,0x00, 0x83,0x9A, 0x00,0x1C, 0x00,0x00, 0x00,0x01, 0xF3,0x85,
+0x7A,0xC0, 0x84,0x9A, 0x00,0x14, 0xF7,0x05, 0x7A,0xC8, 0xF4,0x85, 0x7A,0xB0, 0xF7,0x05,
+0x7A,0xB8, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x14, 0xF7,0x04,
+0x7A,0xB0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0xF6,0x02,
+0x00,0x00, 0x86,0x9A, 0x00,0x1C, 0xF7,0x04, 0x7A,0xC0, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00, 0x00,0x01, 0x86,0x9A, 0x00,0x18, 0xF7,0x04,
+0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x63,0xD0, 0x00,0x00,
+0x00,0x01, 0x86,0x9A, 0x00,0x20, 0xF7,0x04, 0x7A,0xC8, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x20,0x3A, 0x00,0x64, 0xEE,0x00, 0x63,0xD9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x64,0x58, 0x00,0x00, 0x00,0x01, 0x83,0x96,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x64,0x3C, 0xF7,0x02, 0x00,0x00, 0xF7,0x05, 0x40,0x80, 0xF7,0x05,
+0x40,0x84, 0xF6,0x84, 0x6E,0x50, 0xF4,0x82, 0xFF,0xFF, 0x83,0x1E, 0x00,0x0C, 0xF4,0x85,
+0x4F,0x54, 0x93,0x36, 0x00,0x10, 0x83,0x9E, 0x00,0x10, 0x84,0x96, 0x00,0x00, 0x93,0xB6,
+0x00,0x14, 0x84,0xA6, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0xB6, 0x1D,0xDC, 0xF6,0x82,
+0x00,0x64, 0xF6,0x85, 0x4A,0x98, 0xF7,0x05, 0x4A,0x9C, 0x83,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00,
+0x64,0x7C, 0xF3,0x82, 0x00,0x00, 0xF7,0x04, 0x42,0xA4, 0xF6,0x06, 0x42,0xA6, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0x66,0xE4, 0xF7,0x33, 0x28,0x00, 0x93,0x96, 0xFF,0xF4, 0x84,0x16,
+0x00,0x00, 0xF4,0x86, 0x42,0xC8, 0x94,0x96, 0xFF,0xEC, 0xF3,0x02, 0x00,0x0C, 0x93,0x16,
+0xFF,0xE4, 0x83,0x96, 0x00,0x00, 0x84,0x96, 0xFF,0xF4, 0x87,0x1E, 0x00,0x20, 0x00,0x00,
+0x00,0x01, 0xC0,0x26, 0x72,0x00, 0xEC,0x00, 0x66,0x48, 0xF3,0x86, 0x4A,0x98, 0x84,0xA2,
+0x00,0x24, 0x83,0x16, 0xFF,0xE4, 0xC5,0x04, 0x00,0x00, 0xB4,0x9A, 0x38,0x02, 0xC7,0x18,
+0x38,0x00, 0x83,0x22, 0x00,0x28, 0x83,0x96, 0xFF,0xF4, 0x84,0x96, 0xFF,0xE4, 0x93,0x3A,
+0x00,0x04, 0x93,0xBA, 0x00,0x08, 0xF6,0x04, 0xE0,0x00, 0xF3,0x06, 0x4A,0x98, 0xA6,0xA6,
+0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x32, 0x6A,0x00, 0xE6,0x00, 0x65,0x10, 0xC6,0x38,
+0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x65,0x14, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0x65,0x21, 0x00,0x00, 0x00,0x01, 0xF5,0x02, 0x00,0x00, 0xF6,0x84,
+0xE0,0x00, 0x87,0x32, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0x65,0x5C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x65,0x64, 0x20,0x2E,
+0x00,0x00, 0xF6,0x84, 0xE0,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0x65,0x65, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0x65,0x75, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
+0x00,0x00, 0xE6,0x00, 0x65,0x88, 0x00,0x00, 0x00,0x01, 0x83,0x96, 0xFF,0xF4, 0x00,0x00,
+0x00,0x01, 0xF3,0x85, 0x4F,0x54, 0x87,0x22, 0x00,0x2C, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x05,0xA0, 0x00,0x2E, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xF4,0x82,
+0x00,0x00, 0x94,0x96, 0xFF,0xDC, 0x83,0x16, 0xFF,0xEC, 0x20,0x26, 0x00,0x07, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0x98,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE2,0x00, 0x66,0x1C, 0xF7,0x37,
+0x28,0x00, 0x85,0x16, 0xFF,0xEC, 0x85,0x96, 0xFF,0xDC, 0x00,0x00, 0x00,0x01, 0xC7,0x2C,
+0x40,0x00, 0x86,0xBA, 0x00,0x30, 0x06,0x28, 0x00,0x04, 0x05,0x28, 0x00,0x02, 0x05,0xAC,
+0x00,0x02, 0x83,0x96, 0xFF,0xDC, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x03,0x9C,
+0x00,0x01, 0x93,0x96, 0xFF,0xDC, 0x20,0x1E, 0x00,0x07, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4,
+0xFF,0xF0, 0xE2,0x00, 0x65,0xE1, 0xF6,0xB3, 0x28,0x00, 0x04,0x20, 0x00,0x1C, 0x84,0x96,
+0xFF,0xEC, 0x83,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xF4, 0x04,0xA4, 0x00,0x14, 0x94,0x96,
+0xFF,0xEC, 0x03,0x18, 0x00,0x0C, 0x93,0x16, 0xFF,0xE4, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
+0x64,0x94, 0x93,0x96, 0xFF,0xF4, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x26,
+0x00,0x20, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x4A,0x9C, 0x85,0xA6, 0x00,0x20, 0xF7,0x04,
+0x7A,0xB8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7A,0xB8, 0xF7,0x04,
+0x7A,0xB8, 0xF6,0x84, 0x7A,0xC8, 0x86,0x26, 0x00,0x18, 0xC6,0xB4, 0x58,0x00, 0x87,0x26,
+0x00,0x1C, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0x47,0x0C,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x66,0xE5, 0xF6,0x85, 0x7A,0xC8, 0x83,0x26,
+0x00,0x08, 0xF7,0x04, 0x6E,0x50, 0xF3,0x05, 0x3B,0x64, 0x83,0xA6, 0x00,0x08, 0xF6,0x82,
+0x00,0x00, 0x93,0xBA, 0x1D,0xDC, 0x84,0xA6, 0x00,0x0C, 0x83,0x16, 0x00,0x00, 0x94,0xBA,
+0x00,0x10, 0x83,0x1A, 0x00,0x10, 0xF6,0x85, 0x7A,0xC8, 0x93,0x3A, 0x00,0x14, 0xF7,0x02,
+0x00,0x01, 0xF7,0x05, 0x40,0x84, 0xF6,0x85, 0x7A,0xC0, 0xF6,0x85, 0x7A,0xB8, 0xF6,0x85,
+0x7A,0xB0, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x08, 0xF3,0x84, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x1E, 0x00,0x18, 0xF6,0x84,
+0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00, 0x67,0x29, 0xF7,0x02,
+0x00,0x01, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE8, 0xF5,0x82,
+0x00,0x01, 0xF7,0x04, 0xE0,0x1C, 0x86,0x9E, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x67,0xE9, 0xC5,0x84,
+0x00,0x00, 0x86,0x9E, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x67,0x88, 0x05,0x1C, 0x00,0x10, 0x86,0x9E, 0x00,0x14, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x67,0x8C, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0x99, 0x00,0x00,
+0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xAA, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xD4, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x67,0xDC, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x67,0xDD, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x67,0xED, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x68,0x10, 0xF6,0x06,
+0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
+0x75,0xF4, 0x75,0xAC, 0xFF,0xE1, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x68,0x45, 0x95,0x96,
+0xFF,0xF4, 0xF7,0x04, 0x42,0x98, 0xF6,0x06, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x04,0x1C, 0x00,0x20, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00,
+0x68,0xC4, 0xF3,0x06, 0x15,0x54, 0xF5,0x02, 0x00,0x00, 0x05,0x9C, 0x00,0x22, 0xC4,0xAC,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00,
+0x68,0xC0, 0xC6,0xA4, 0x60,0x00, 0xA7,0x26, 0x60,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x05,0x28, 0x00,0x01, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xE8, 0xF7,0x2F,
+0x68,0x00, 0x05,0xAC, 0x00,0x01, 0xE0,0x00, 0x68,0x78, 0x06,0x30, 0x00,0x02, 0xF3,0x06,
+0x15,0x54, 0x93,0x13, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x06,
+0xE0,0x00, 0x93,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x02, 0x00,0x01, 0x93,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x69,0x28, 0xF6,0x06, 0x42,0x9E, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+0x00,0x00, 0xE6,0x00, 0x69,0x6C, 0xF3,0x06, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x69,0x6D, 0xF0,0x05, 0x42,0x28, 0xF3,0x06, 0x35,0x60, 0xF3,0x05, 0x42,0x30, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x04, 0x6F,0x34, 0xF7,0x04,
+0x42,0x40, 0x86,0x2A, 0x00,0x18, 0x07,0x38, 0x00,0x01, 0xF6,0x84, 0xE0,0x1C, 0xF7,0x05,
+0x42,0x40, 0xC0,0x36, 0x62,0x00, 0xEC,0x00, 0x69,0xB5, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
+0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x80, 0xF7,0x02, 0x00,0x01, 0xF7,0x04,
+0xE0,0x1C, 0x86,0xAA, 0x00,0x18, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6A,0x7D, 0xC5,0x84, 0x00,0x00, 0x86,0xAA,
+0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x6A,0x14, 0x04,0xA8, 0x00,0x10, 0x86,0xAA, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x6A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x25, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0x6A,0x60, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x6A,0x68, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x6A,0x69, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x6A,0x81, 0xC7,0x2C, 0x00,0x00, 0xF5,0x82,
+0x00,0x01, 0xE0,0x00, 0x6A,0x80, 0xC7,0x2C, 0x00,0x00, 0xC7,0x04, 0x00,0x00, 0x20,0x3A,
+0x00,0x00, 0xEE,0x00, 0x6B,0x3D, 0xF6,0x86, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x6B,0x3C, 0xF6,0x82, 0x00,0x00, 0xF6,0x85, 0x40,0x80, 0xF6,0x85,
+0x40,0x84, 0x96,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF7,0x04, 0xE0,0x1C, 0x00,0x00,
+0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x86, 0xE0,0x00, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
+0xFF,0xFC, 0xF3,0x82, 0x00,0x02, 0x93,0x93, 0xFF,0xFC, 0x96,0x96, 0xFF,0xF4, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xEE,0x64, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0x86,0x96,
+0xFF,0xF4, 0xF7,0x04, 0x6E,0x50, 0xF3,0x86, 0x35,0xEC, 0xF6,0x85, 0x40,0x90, 0xF6,0x85,
+0x40,0x94, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x85, 0x42,0x28, 0xF7,0x05, 0x3B,0x64, 0xF7,0x04,
+0x42,0x30, 0xF4,0x05, 0x40,0x80, 0xC0,0x3A, 0x3A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x6B,0x3D, 0xF3,0x86, 0x35,0x60, 0xF3,0x85, 0x42,0x30, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x6D,0xD9, 0xF5,0x82, 0x00,0x00, 0xF7,0x04, 0x40,0x8C, 0xF6,0x06, 0x40,0x8C, 0x76,0x31,
+0x00,0x1E, 0xF6,0x84, 0x42,0x28, 0x76,0x30, 0xFF,0xE5, 0x06,0xB4, 0x00,0x01, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6B,0xC8, 0xF6,0x85,
+0x42,0x28, 0xF7,0x04, 0x40,0x88, 0xF6,0x86, 0x40,0x8A, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x6D,0x0D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x6C,0x35, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x6C,0x34, 0xF4,0x86, 0x36,0x78, 0xF7,0x04, 0x42,0x44, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x6C,0x35, 0xF4,0x82, 0x00,0x01, 0xF4,0xB3, 0x28,0x00, 0xE0,0x00, 0x6D,0x10, 0xF0,0x05,
+0x42,0x2C, 0xF7,0x04, 0x40,0x8C, 0xF5,0x06, 0x40,0x8C, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x6C,0xC1, 0xF6,0x06, 0x40,0x8A, 0xF7,0x04, 0x40,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x6C,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x2C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x20,0x3A, 0x00,0x09, 0xEE,0x00, 0x6D,0x11, 0xF7,0x05, 0x42,0x2C, 0xF0,0x2B,
+0x28,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0xF6,0x06,
+0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x6D,0x10, 0xF7,0x33, 0x28,0x00, 0xF7,0x04,
+0x40,0x8C, 0xF6,0x86, 0x40,0x8C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x6D,0x14, 0x20,0x2E,
+0x00,0x00, 0xF7,0x04, 0x40,0x88, 0xF6,0x06, 0x40,0x8A, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x6D,0x15, 0x20,0x2E, 0x00,0x00, 0xF0,0x33, 0x28,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0x6D,0xB5, 0xF4,0x86, 0x35,0xEC, 0xF7,0x04, 0x42,0x30, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x4A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x6D,0x59, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0x3C, 0xF6,0x84, 0xE0,0x28, 0xE0,0x00,
+0x6D,0x78, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0xE0,0x28, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x6D,0x79, 0xF6,0x82, 0x00,0xF0, 0xF7,0x04, 0xE0,0x28, 0x00,0x00,
+0x00,0x01, 0x76,0xB9, 0x00,0x02, 0xF7,0x04, 0x42,0x28, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x6A,0x00, 0xEC,0x00, 0x6D,0xB5, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0xF0,0x05,
+0x42,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+0x00,0x19, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x6D,0xB4, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF4,0x82, 0xC3,0x50, 0x94,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x16, 0x94,0x93,
+0xFF,0xFC, 0xF4,0x86, 0x42,0x30, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x04, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86,
+0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x82, 0x74,0x18, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x19, 0x95,0x93,
+0xFF,0xFC, 0xF5,0x86, 0x36,0x78, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x74,0xAC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x78,0x00, 0x95,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x37,0x04, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+0x78,0xFC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x82, 0x80,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x86, 0x37,0x90, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x81,0x74, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x1D, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x87,0x74, 0x95,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+0x94,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x82, 0x8A,0x00, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x8E,0x08, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x1A, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x96,0x9C, 0x95,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0xA8, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+0x9B,0x2C, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+0x38,0xA8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x82, 0xA2,0xDC, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0x9E,0x54, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x1B, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0xD8, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xA3,0xC0, 0x95,0x93,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82,
+0xA7,0x64, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x82, 0xAA,0x04, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82, 0x00,0x1B, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x86, 0x39,0xC0, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x82, 0xAE,0xF8, 0x95,0x93, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x3A,0x4C, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x50, 0xF0,0x3B,
+0x28,0x00, 0xF7,0x06, 0x40,0x88, 0xF0,0x3B, 0x28,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x05,
+0x40,0x80, 0xF6,0x05, 0x40,0x84, 0xF7,0x06, 0x3B,0x70, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06,
+0x3B,0x72, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xCA,0x20, 0xF5,0x85, 0x3B,0x74, 0xF7,0x06,
+0x3B,0x78, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x7A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+0xB1,0x94, 0xF5,0x85, 0x3B,0x7C, 0xF7,0x06, 0x3B,0x80, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
+0x3B,0x82, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x54, 0xF5,0x85, 0x3B,0x84, 0xF7,0x06,
+0x3B,0x88, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x8A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+0xBE,0xF8, 0xF5,0x85, 0x3B,0x8C, 0xF7,0x06, 0x3B,0x90, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
+0x3B,0x92, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC8,0xF8, 0xF5,0x85, 0x3B,0x94, 0xF7,0x06,
+0x3B,0x98, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0x9A, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+0xC5,0xD8, 0xF5,0x85, 0x3B,0x9C, 0xF7,0x06, 0x3B,0xA0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06,
+0x3B,0xA2, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82, 0xC7,0x70, 0xF5,0x85, 0x3B,0xA4, 0xF7,0x06,
+0x3B,0xA8, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x3B,0xAA, 0xF0,0xBB, 0x28,0x00, 0xF5,0x82,
+0xC1,0xB4, 0xF5,0x85, 0x3B,0xAC, 0x96,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD5,0x40, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
+0x00,0x01, 0x96,0x36, 0x1D,0xDC, 0xF6,0x05, 0x3B,0x64, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
+0x28,0x00, 0x26,0x14, 0x00,0x38, 0xF0,0x33, 0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04,
+0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x72,0x1D, 0xF5,0x02, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
+0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02,
+0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x04, 0x86,0x16, 0x00,0x00, 0xF6,0x82,
+0x00,0xFF, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x6C,0x00, 0xF7,0x33, 0x28,0x00, 0xF7,0x06,
+0xE0,0x06, 0x87,0x3A, 0x00,0x00, 0x06,0xB0, 0x00,0x02, 0xF7,0x37, 0x28,0x00, 0xF6,0x84,
+0x3B,0x64, 0x07,0x30, 0x00,0x04, 0xF6,0xBB, 0x28,0x00, 0x87,0x02, 0xFF,0x34, 0x06,0x30,
+0x00,0x06, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x30, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x27,0x14,
+0x00,0x38, 0xF0,0x3B, 0x28,0x00, 0x97,0x13, 0xFF,0xFC, 0x90,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x73,0x19, 0xF5,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
+0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x95,0x93, 0xFF,0xFC, 0xF5,0x82, 0x00,0x1B, 0x95,0x93,
+0xFF,0xFC, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x40, 0x26,0x14, 0x00,0x20, 0x96,0x16, 0xFF,0xC4, 0xF0,0x33,
+0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x96,0x16,
+0xFF,0xBC, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13,
+0xFF,0xFC, 0x86,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x73,0xE5, 0xF6,0x02,
+0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05,
+0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0xF6,0x02, 0x00,0x1B, 0x96,0x13, 0xFF,0xFC, 0xF6,0x06,
+0x42,0x44, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x04, 0xF5,0x82, 0x00,0x00, 0xF5,0x85, 0x40,0x80, 0x95,0x96, 0xFF,0xF4, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCB,0x50, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0xF5,0x02,
+0x00,0x64, 0xF5,0x05, 0x3B,0xB4, 0xF7,0x04, 0x42,0x50, 0xF4,0x86, 0x42,0x50, 0x76,0xA5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x4F,0x5C, 0xF4,0x02, 0x00,0x06, 0xF4,0x05,
+0x42,0x54, 0xF5,0x85, 0x3B,0x6C, 0xF5,0x85, 0x3B,0xB8, 0x95,0x32, 0x00,0x00, 0x95,0xB2,
+0x00,0x04, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x27,
+0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x06,
+0x37,0x04, 0xF4,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x50, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04, 0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2,
+0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x77,0xEC, 0xC5,0x04,
+0x00,0x00, 0x86,0xB2, 0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xF3,0x02, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x75,0x18, 0x04,0xB0, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x75,0x1C, 0x20,0x1A,
+0x00,0x00, 0xF3,0x02, 0x00,0x01, 0x20,0x1A, 0x00,0x00, 0xE6,0x00, 0x75,0x29, 0x00,0x00,
+0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x64, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x75,0x6C, 0x20,0x32, 0x00,0x00, 0x86,0xA6, 0x00,0x04, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x75,0x6D, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x75,0x7D, 0x20,0x2A,
+0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x77,0xEC, 0x00,0x00,
+0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14,
+0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0, 0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF5,0x82,
+0x00,0x00, 0x23,0x94, 0x00,0x22, 0xF5,0x9F, 0x28,0x00, 0x03,0xA0, 0x00,0x1A, 0x93,0x96,
+0xFF,0xD4, 0x25,0x94, 0x00,0x22, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x15, 0x00,0x1E, 0xF5,0x9F,
+0x28,0x00, 0xF3,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0xA2, 0x00,0x1C, 0xF5,0x84,
+0xE0,0x04, 0x73,0x99, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
+0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xCC, 0x23,0x94, 0x00,0x42, 0x95,0xA2,
+0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96,
+0xFF,0xB4, 0x75,0x95, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x95,0x96, 0xFF,0xC4, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A,
+0x00,0x00, 0xC4,0xA0, 0x4A,0x00, 0x74,0xA4, 0xFF,0xFA, 0xC5,0xA4, 0x00,0x00, 0xF5,0x9F,
+0x28,0x00, 0x83,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x85,0x96, 0xFF,0xB4, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x83,0x96, 0xFF,0xCC, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x96, 0xFF,0xC4, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82,
+0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x04,0x20, 0x00,0x18, 0x25,0x94, 0x00,0x22, 0x85,0xAE,
+0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC, 0x7F,0xC0, 0x75,0xAD,
+0xFF,0xF0, 0x83,0x96, 0xFF,0xD4, 0xF5,0xA3, 0x28,0x00, 0xF4,0x9F, 0x28,0x00, 0x25,0x94,
+0x00,0x42, 0x85,0xAE, 0x00,0x00, 0x77,0xAD, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0xAC,
+0x7F,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x44,0xAD, 0x00,0x00, 0x94,0x93, 0xFF,0xFC, 0xF7,0x86,
+0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x40,0x84, 0xF7,0x86,
+0xE0,0x00, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x04, 0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x87,0x3A, 0x1D,0xDC, 0x00,0x00,
+0x00,0x01, 0xF7,0x05, 0x3B,0x64, 0xF5,0x86, 0x36,0x78, 0xF5,0x85, 0x42,0x44, 0xF3,0x86,
+0x35,0x60, 0xF3,0x85, 0x42,0x30, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86, 0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x78,0x89, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xEE,0x00, 0x78,0x51, 0xF6,0x06, 0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x71,0xB0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x78,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85,
+0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86,
+0x37,0x90, 0xF5,0x85, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF6,0x06, 0x36,0x78, 0xF6,0x05, 0x42,0x44, 0xF7,0x02, 0x00,0x00, 0xF7,0x05,
+0x40,0x80, 0xF7,0x05, 0x40,0x94, 0xF6,0x84, 0x6E,0x50, 0xF7,0x05, 0x40,0x90, 0x97,0x36,
+0x1D,0xDC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x02,
+0x00,0x01, 0xF7,0x05, 0x40,0x80, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0xA8, 0xF7,0x04, 0x42,0x50, 0xF5,0x86, 0x42,0x50, 0x76,0xAD,
+0x00,0x1E, 0xF4,0x84, 0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xC4, 0xC7,0x38,
+0x6F,0xC0, 0x86,0xA6, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x79,0x55, 0xF6,0x06, 0x42,0x9A, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0xF7,0x04, 0x42,0x50, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16,
+0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0xAA, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x80,0xA8, 0xF6,0x06, 0x42,0x9A, 0x87,0x2A, 0x00,0x10, 0x86,0x2A,
+0x00,0x1C, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xA8, 0xF6,0x82, 0x00,0x00, 0x87,0x2A,
+0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x79,0xAC, 0x20,0x36,
+0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0x7A,0x05, 0x24,0x94,
+0x00,0x20, 0x94,0x96, 0xFF,0xBC, 0x85,0x16, 0xFF,0xC4, 0xF0,0x27, 0x28,0x00, 0x05,0x28,
+0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xB4, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+0xFF,0xFC, 0x85,0x16, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x80,0xC4, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x80,0x6C, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x25,0x94, 0x00,0x20, 0xF0,0x2F,
+0x28,0x00, 0x04,0xA0, 0x00,0x02, 0x94,0x96, 0xFF,0x5C, 0xF0,0x27, 0x28,0x00, 0xF4,0x82,
+0x00,0x00, 0x25,0x14, 0x00,0x5A, 0xF4,0xAB, 0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x25,0x14,
+0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28,
+0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x23,0x14,
+0x00,0x1E, 0x76,0x19, 0x00,0x1E, 0xF5,0x3B, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x76,0x30,
+0xFF,0xE5, 0x94,0xA2, 0x00,0x1C, 0xF5,0x04, 0xE0,0x04, 0x84,0x96, 0xFF,0x5C, 0x95,0x22,
+0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+0xFF,0x9C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x74,0x95,
+0x00,0x1E, 0x85,0x16, 0xFF,0x5C, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x8C, 0x84,0x96,
+0xFF,0x54, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x94, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
+0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF5,0x3B,
+0x28,0x00, 0x94,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
+0xFF,0xFC, 0x26,0x14, 0x00,0x38, 0x24,0x94, 0x00,0x5A, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x05,0xA0,
+0x00,0x02, 0x06,0xAC, 0x00,0x02, 0x23,0x94, 0x00,0x36, 0x75,0x1D, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x07,0x20, 0x00,0x1A, 0xF4,0xB3, 0x28,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x95,0x16, 0xFF,0x54, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+0xFF,0x5C, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x74,0x95,
+0x00,0x1E, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x74, 0x85,0x2A,
+0x00,0x34, 0x24,0x94, 0x00,0x5A, 0x95,0x16, 0xFF,0x84, 0x84,0xA6, 0x00,0x00, 0x77,0xA5,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x25,0x14,
+0x00,0x5A, 0xF4,0xAF, 0x28,0x00, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
+0x28,0x00, 0x84,0xA6, 0x00,0x10, 0x85,0x16, 0xFF,0xC4, 0x94,0xA2, 0x00,0x1C, 0x85,0x2A,
+0x00,0x14, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x6C, 0x95,0x22,
+0x00,0x20, 0x87,0x16, 0xFF,0xC8, 0x85,0x16, 0xFF,0x54, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x84,0x96, 0xFF,0x5C, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0xCC, 0x23,0x94, 0x00,0x32, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x85,0x16,
+0xFF,0x7C, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD0, 0x23,0x94, 0x00,0x2E, 0x76,0x1D,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0x74, 0x85,0x16,
+0xFF,0x6C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x23,0x94, 0x00,0x2A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x16, 0xFF,0xD8, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3, 0x28,0x00, 0x07,0x20,
+0x00,0x18, 0x25,0x14, 0x00,0x7A, 0x85,0x2A, 0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0x84,0x96, 0xFF,0xC4, 0xF5,0x3B,
+0x28,0x00, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xF7,0x04,
+0x4F,0x58, 0xE6,0x00, 0x7E,0xF9, 0x94,0x16, 0xFF,0x54, 0xC7,0x20, 0x72,0x00, 0xF6,0x84,
+0x6E,0x50, 0x86,0x26, 0x00,0x2C, 0x77,0x38, 0xFF,0xFA, 0x25,0x14, 0x00,0x5A, 0x84,0x2A,
+0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0x20, 0x7F,0xC0, 0x74,0x21,
+0xFF,0xF0, 0x47,0x39, 0x00,0x00, 0x86,0xB6, 0x1D,0xDC, 0x77,0x39, 0x00,0x02, 0xC0,0x32,
+0x6A,0x00, 0x46,0x8C, 0x00,0x01, 0xD6,0x80, 0x0A,0x68, 0x20,0x36, 0x00,0x00, 0xF6,0x86,
+0x40,0x98, 0xE6,0x00, 0x7E,0xC0, 0xC3,0xB8, 0x68,0x00, 0xC5,0x84, 0x00,0x00, 0x86,0xA6,
+0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x7E,0x54, 0x03,0x24, 0x00,0x24, 0x86,0xA6, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x7E,0x58, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0x65, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+0x00,0x00, 0x86,0x9A, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0x7E,0xA0, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x7E,0xA8, 0x20,0x32, 0x00,0x00, 0x86,0x9A, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x7E,0xA9, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x7E,0xB9, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x7E,0xC5, 0x00,0x00, 0x00,0x01, 0xF4,0x02,
+0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x1F, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0x85,0x16,
+0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x2A,
+0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
+0x7F,0x4C, 0xF6,0x3B, 0x28,0x00, 0x84,0x96, 0xFF,0x54, 0xF6,0x06, 0x40,0x98, 0xC7,0x24,
+0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0xB8, 0x00,0x00, 0x46,0xB5, 0x00,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x60,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x37, 0x28,0x00, 0x47,0x39,
+0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x24,0x94, 0x00,0x5A, 0x84,0xA6,
+0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5,
+0xFF,0xF0, 0x07,0x38, 0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x85,0x16,
+0xFF,0x54, 0x84,0x96, 0xFF,0xAC, 0xC6,0xA8, 0x72,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x24,
+0x00,0x1A, 0xF6,0xB3, 0x28,0x00, 0xC7,0x24, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x06,0xA8,
+0x00,0x1A, 0xF7,0x37, 0x28,0x00, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24,
+0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x72,0x00, 0x77,0x38,
+0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x1C, 0x97,0x13,
+0xFF,0xFC, 0xF5,0x04, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x36, 0x1D,0xDC, 0x87,0x36,
+0x1D,0xDC, 0xF0,0x05, 0x40,0x84, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x05, 0x40,0x84, 0xF7,0x04,
+0x6E,0x50, 0xF0,0x05, 0x42,0x5C, 0x87,0x3A, 0x1D,0xDC, 0xF6,0x86, 0x2C,0x28, 0xF7,0x05,
+0x3B,0x64, 0xF7,0x04, 0x2D,0x38, 0xF5,0x06, 0x3A,0x4C, 0xF5,0x05, 0x42,0x44, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82, 0x00,0x1C, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x80,0x60, 0xB4,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06,
+0x35,0xEC, 0xE0,0x00, 0x80,0x8C, 0xF5,0x05, 0x42,0x30, 0x20,0x32, 0x00,0x01, 0xE6,0x00,
+0x80,0xC4, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+0xFF,0xFC, 0xF4,0x86, 0x35,0x60, 0xF4,0x85, 0x42,0x30, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0x80,0xC4, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x98, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x86,
+0x42,0x44, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x81,0x61, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x81,0x29, 0xF6,0x06,
+0x42,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x72,0xAC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0x81,0x60, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF5,0x82, 0x00,0x06, 0xF5,0x85, 0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x86, 0x38,0x1C, 0xF5,0x85, 0x42,0x44, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x58, 0xF7,0x04,
+0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF6,0x04,
+0x6F,0x34, 0xC7,0x38, 0x6F,0xC0, 0x86,0xB2, 0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x82,0x50, 0xF4,0x82, 0x00,0x00, 0xC5,0x04, 0x00,0x00, 0x86,0xB2,
+0x00,0x10, 0xF7,0x04, 0xE0,0x00, 0xC5,0xA4, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x81,0xE4, 0x04,0x30, 0x00,0x10, 0x86,0xB2, 0x00,0x14, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x81,0xE8, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x81,0xF5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
+0x00,0x00, 0x86,0xA2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0x82,0x30, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0x82,0x38, 0x20,0x32, 0x00,0x00, 0x86,0xA2, 0x00,0x04, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x82,0x39, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x82,0x49, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
+0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x82,0x59, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
+0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0x87,0x60, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
+0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x05, 0x3B,0xB0, 0x06,0xA0, 0x00,0x14, 0xC7,0x20,
+0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x16, 0xF7,0x37,
+0x28,0x00, 0xF3,0x02, 0x00,0x01, 0xF3,0x23, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x04,0xA0,
+0x00,0x02, 0xF0,0x27, 0x28,0x00, 0xF3,0x02, 0x00,0x00, 0x23,0x94, 0x00,0x2A, 0xF3,0x1F,
+0x28,0x00, 0x07,0x20, 0x00,0x1A, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xA4, 0x00,0x02, 0x75,0x15, 0x00,0x1E, 0xF3,0xBB,
+0x28,0x00, 0xF3,0x04, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x93,0x22, 0x00,0x1C, 0xF3,0x84,
+0xE0,0x04, 0x23,0x14, 0x00,0x1E, 0x93,0x16, 0xFF,0xA4, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
+0xFF,0xA4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
+0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96,
+0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x94, 0x00,0x1A, 0x93,0x96, 0xFF,0xA4, 0x76,0x1D,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
+0x00,0x16, 0x93,0x16, 0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xAC, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x93,0x16,
+0xFF,0xA4, 0x76,0x19, 0x00,0x1E, 0x83,0x96, 0xFF,0xCC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16,
+0xFF,0xF0, 0x83,0x16, 0xFF,0xC4, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x82, 0x00,0x02, 0xF3,0xA3, 0x28,0x00, 0x23,0x14,
+0x00,0x2A, 0x83,0x1A, 0x00,0x00, 0x77,0x99, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18,
+0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0x07,0x20, 0x00,0x18, 0xF3,0x3B, 0x28,0x00, 0x94,0x16,
+0xFF,0xDC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20,
+0x00,0x02, 0x23,0x94, 0x00,0x2A, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x24,0x80, 0x00,0x07, 0x05,0x20,
+0x00,0x0A, 0xF3,0xBB, 0x28,0x00, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x84,0xE0, 0x06,0x28,
+0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1,
+0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4, 0x00,0x01, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3,
+0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0xC7,0x38, 0x34,0x00, 0xE0,0x00, 0x84,0x88, 0xF7,0x33, 0x28,0x00, 0x05,0x20,
+0x00,0x26, 0x86,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0xF5,0x84, 0x4F,0x58, 0x76,0xB4,
+0xFF,0xE5, 0x83,0x96, 0xFF,0xDC, 0xF3,0x02, 0x00,0xFF, 0x94,0x16, 0xFF,0xBC, 0xC7,0x1C,
+0x5A,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
+0x00,0x00, 0xC7,0x38, 0x34,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30, 0x6C,0x00, 0xC7,0x38,
+0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2B, 0x28,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
+0xFF,0xFA, 0x83,0x16, 0xFF,0xDC, 0x07,0x34, 0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x20,
+0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x20, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x82,
+0x00,0x03, 0xF3,0xA3, 0x28,0x00, 0x07,0x18, 0x00,0x1A, 0xF5,0xBB, 0x28,0x00, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x07,0x20, 0x00,0x02, 0xF0,0x3B,
+0x28,0x00, 0x24,0x80, 0x00,0x07, 0x05,0x20, 0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00,
+0x85,0xD4, 0x06,0x28, 0x00,0x0E, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x05,0x28, 0x00,0x02, 0x04,0xA4,
+0x00,0x01, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
+0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0xF3,0x82, 0x00,0xFF, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xE0,0x00, 0x85,0x7C, 0xF7,0x33,
+0x28,0x00, 0x05,0xA0, 0x00,0x26, 0x86,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC5,0x20, 0x00,0x00, 0x24,0x00, 0x00,0x07, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
+0xFF,0xA4, 0xF7,0x04, 0x4F,0x58, 0x83,0x96, 0xFF,0xBC, 0x24,0x80, 0x00,0x0E, 0xC7,0x1C,
+0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x47,0x39,
+0x00,0x00, 0xF6,0x82, 0x00,0xFF, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82, 0xFF,0x00, 0xC6,0x30,
+0x6C,0x00, 0xC7,0x38, 0x60,0x00, 0xF6,0x84, 0x3B,0x6C, 0xF7,0x2F, 0x28,0x00, 0x07,0x34,
+0x00,0x01, 0xF7,0x05, 0x3B,0x6C, 0x07,0x28, 0x00,0x3A, 0xF6,0xBB, 0x28,0x00, 0x07,0x28,
+0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0xF3,0x02, 0x00,0x03, 0xF3,0x2B, 0x28,0x00, 0x20,0x22,
+0x00,0x07, 0xEE,0x00, 0x86,0x94, 0xC6,0x28, 0x48,0x00, 0x06,0x30, 0x00,0x26, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x04,0x20,
+0x00,0x01, 0x83,0x96, 0xFF,0xA4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82,
+0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC7,0x1C, 0x70,0x00, 0xE0,0x00, 0x86,0x50, 0xF7,0x33,
+0x28,0x00, 0x06,0x28, 0x00,0x26, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4,
+0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0xF3,0x04, 0x3B,0xB0, 0x00,0x00,
+0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xB4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xB4, 0xF0,0x05, 0x40,0x7C, 0x83,0x96,
+0xFF,0xBC, 0x23,0x00, 0x00,0x07, 0xF3,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x50, 0xF6,0x06,
+0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x39,0x34, 0xF3,0x05,
+0x42,0x44, 0xF5,0x05, 0x40,0x74, 0xF3,0x85, 0x42,0x60, 0xF3,0x82, 0x00,0x06, 0xF3,0x85,
+0x42,0x54, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06,
+0x2C,0x28, 0x76,0xB5, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0x87,0x4C, 0xB3,0xB6, 0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x06, 0x42,0x44, 0x93,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x48, 0xF3,0x86,
+0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x89,0xED, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0x87,0xC9, 0x00,0x00,
+0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x73,0x4C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0x89,0xEC, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93,
+0xFF,0xFC, 0x26,0x14, 0x00,0x20, 0xF0,0x33, 0x28,0x00, 0x05,0xA0, 0x00,0x02, 0xF0,0x2F,
+0x28,0x00, 0xF3,0x82, 0x00,0x00, 0x24,0x94, 0x00,0x22, 0xF3,0xA7, 0x28,0x00, 0x04,0xA0,
+0x00,0x1A, 0x94,0x96, 0xFF,0xD4, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x76,0x31,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x06,0xAC, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x75,0x19,
+0x00,0x1E, 0xF3,0xA7, 0x28,0x00, 0xF4,0x84, 0xE0,0x00, 0x75,0x28, 0xFF,0xE5, 0x94,0xA2,
+0x00,0x1C, 0xF3,0x84, 0xE0,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+0xFF,0xB4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0xCC, 0x84,0x96,
+0xFF,0xB4, 0x93,0xA2, 0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x73,0x95, 0x00,0x1E, 0x73,0x9C,
+0xFF,0xE5, 0x93,0x96, 0xFF,0xBC, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
+0xFF,0xC4, 0x83,0x96, 0xFF,0xBC, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F,
+0x28,0x00, 0xF5,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0xA0, 0x5A,0x00, 0x75,0xAC,
+0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x45,0xAD, 0x00,0x00, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFF,0xCC, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x02, 0xF4,0xA3,
+0x28,0x00, 0x04,0x20, 0x00,0x18, 0x23,0x94, 0x00,0x22, 0x83,0x9E, 0x00,0x00, 0x77,0x9D,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x84,0x96,
+0xFF,0xD4, 0xF3,0xA3, 0x28,0x00, 0xF3,0x82, 0x00,0x01, 0xF3,0xA7, 0x28,0x00, 0x95,0x93,
+0xFF,0xFC, 0xF4,0x86, 0xE0,0x00, 0x94,0x93, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x86,
+0x36,0x78, 0xF4,0x85, 0x42,0x44, 0xF0,0x05, 0x40,0x84, 0xF6,0x84, 0x4F,0x5C, 0xF7,0x02,
+0x00,0x64, 0x97,0x36, 0x00,0x00, 0x90,0x36, 0x00,0x04, 0xF7,0x02, 0x00,0x01, 0xF7,0x05,
+0x40,0x84, 0xF3,0x86, 0x35,0xEC, 0xF3,0x85, 0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF7,0x04, 0x42,0x60, 0xF5,0x02,
+0x00,0x00, 0x05,0xB8, 0x00,0x18, 0xF6,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+0x00,0x07, 0xEE,0x00, 0x8A,0x70, 0xC7,0x30, 0x60,0x00, 0xC7,0x38, 0x58,0x00, 0x07,0x38,
+0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0xC0,0x36,
+0x52,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x8A,0x71, 0x07,0x30, 0x00,0x01, 0xE0,0x00, 0x8A,0x18, 0xF7,0x05, 0x42,0x58, 0xF4,0x04,
+0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x07, 0xEE,0x00, 0x8D,0x94, 0x24,0x94,
+0x00,0x36, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x38, 0x23,0x94, 0x00,0x20, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
+0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
+0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
+0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0x7C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x7E, 0x25,0x14, 0x00,0x80, 0x23,0x94,
+0x00,0x68, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7C, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x7A, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x78, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x76, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x74, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x72, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x95,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0x74, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x42,0x58, 0x23,0x94, 0x00,0x50, 0xC7,0x00, 0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0x6C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFF,0x6C, 0xF6,0x86, 0x42,0x50, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
+0x42,0x58, 0x76,0xB5, 0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF7,0x04, 0x42,0x50, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96,
+0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xF3,0x38, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x8D,0x95, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00,
+0x8D,0xD4, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0x8D,0xF4, 0xB3,0xBA, 0x68,0x02, 0xE0,0x00, 0x8D,0xF4, 0xF0,0x05,
+0x2D,0x38, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86,
+0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x88, 0xF7,0x04, 0x42,0x50, 0xF6,0x86, 0x42,0x50, 0x76,0xB5, 0x00,0x1E, 0xF3,0x84,
+0x6F,0x34, 0x76,0xB4, 0xFF,0xE5, 0x93,0x96, 0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x86,0x9E,
+0x00,0x0C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x8E,0x65, 0xF6,0x06,
+0x42,0xA0, 0xF7,0x04, 0x42,0xA0, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0x94,0xE4, 0xF7,0x33,
+0x28,0x00, 0xF6,0x04, 0x42,0x60, 0x24,0x94, 0x00,0x36, 0x85,0x16, 0xFF,0xC4, 0x23,0x94,
+0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x85,0x2A, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x95,0x16, 0xFF,0xBC, 0xF7,0x1F, 0x28,0x00, 0x87,0x32,
+0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x85,0x16, 0xFF,0xC4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
+0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14, 0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00,
+0x00,0x01, 0x87,0x1E, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0x8F,0xF0, 0xF6,0x82, 0x00,0x00, 0x87,0x1E, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0x8F,0xF4, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0x90,0x41, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xC4, 0x00,0x00,
+0x00,0x01, 0x05,0x28, 0x00,0x10, 0x95,0x16, 0xFF,0xB4, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x72,0x50, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x27,0x14,
+0x00,0x20, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xF9,0x34, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16,
+0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0x94,0xBC, 0x00,0x00,
+0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x02,
+0x00,0x00, 0x23,0x94, 0x00,0x62, 0xF5,0x1F, 0x28,0x00, 0x75,0x95, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0x06,0x20, 0x00,0x02, 0x06,0xB0, 0x00,0x02, 0x23,0x14, 0x00,0x1E, 0x73,0x99,
+0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x74, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x95,0x16, 0xFF,0x7C, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96,
+0xFF,0x8C, 0x85,0x16, 0xFF,0xC4, 0x73,0x95, 0x00,0x1E, 0x93,0x96, 0xFF,0x84, 0x85,0x2A,
+0x00,0x34, 0x23,0x94, 0x00,0x62, 0x95,0x16, 0xFF,0xAC, 0xF0,0x33, 0x28,0x00, 0x05,0x20,
+0x00,0x1A, 0x95,0x16, 0xFF,0x94, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC3,0x9C, 0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x74,0x95, 0x00,0x1E, 0xF3,0xAB,
+0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0xA4, 0xFF,0xE5, 0x85,0x2A, 0x00,0x10, 0x83,0x96,
+0xFF,0xC4, 0x95,0x22, 0x00,0x1C, 0x83,0x9E, 0x00,0x14, 0x85,0x16, 0xFF,0x84, 0x93,0xA2,
+0x00,0x20, 0x87,0x16, 0xFF,0xE0, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x84, 0xF3,0x84,
+0x4F,0x58, 0x85,0x16, 0xFF,0x74, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x93,0x96, 0xFF,0xA4, 0xC0,0x22, 0x3A,0x00, 0x83,0x96,
+0xFF,0x7C, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14, 0x00,0x16, 0x76,0x19,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x85,0x16, 0xFF,0x8C, 0x83,0x96,
+0xFF,0x84, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF5,0x02, 0x00,0x02, 0xF5,0x23, 0x28,0x00, 0x23,0x94,
+0x00,0x52, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
+0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x03,0x20, 0x00,0x18, 0xE6,0x00, 0x92,0x30, 0xF3,0x9B,
+0x28,0x00, 0xF7,0x04, 0x42,0x70, 0xE0,0x00, 0x92,0x9C, 0xF6,0x06, 0x42,0x72, 0x85,0x16,
+0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0xAA, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x07,0x34,
+0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00, 0x92,0x94, 0xC7,0x34, 0x68,0x00, 0xF5,0x84,
+0x42,0x60, 0xF3,0x82, 0x00,0xFF, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+0x00,0x00, 0x97,0x16, 0xFF,0x74, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x3C,0x00, 0x20,0x36, 0x00,0x00, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0x92,0xC9, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x42,0x74, 0xF6,0x06, 0x42,0x74, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x85,0x16, 0xFF,0xA4, 0x83,0x96, 0xFF,0x74, 0xC7,0x20,
+0x52,0x00, 0x74,0xB8, 0xFF,0xFA, 0xC6,0x24, 0x00,0x00, 0x87,0x1E, 0x00,0x00, 0x76,0x9D,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x52,0x00, 0x75,0xAC, 0xFF,0xFA, 0x46,0x31,
+0x00,0x00, 0xF5,0x02, 0x00,0xFF, 0xC6,0x30, 0x54,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38, 0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x1F,
+0x28,0x00, 0x83,0x96, 0xFF,0x94, 0x85,0x16, 0xFF,0xC4, 0xF5,0x9F, 0x28,0x00, 0x87,0x2A,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x24, 0xE6,0x00, 0x94,0x69, 0xF6,0x86,
+0x40,0x98, 0xF7,0x04, 0x6E,0x50, 0x86,0x2A, 0x00,0x2C, 0xC6,0xA4, 0x00,0x00, 0x23,0x94,
+0x00,0x62, 0x84,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC4,0xA4,
+0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x46,0xB5, 0x00,0x00, 0x87,0x3A, 0x1D,0xDC, 0x76,0xB5,
+0x00,0x02, 0xC0,0x32, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
+0x00,0x00, 0xF7,0x06, 0x40,0x98, 0xE6,0x00, 0x94,0x34, 0xC3,0x34, 0x70,0x00, 0xC5,0x84,
+0x00,0x00, 0x86,0xAA, 0x00,0x24, 0xF7,0x04, 0xE0,0x00, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0x05,0x28, 0x00,0x24, 0xE6,0x00, 0x93,0xC4, 0x95,0x16, 0xFF,0x74, 0x83,0x96,
+0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x86,0x9E, 0x00,0x28, 0xF7,0x04, 0xE0,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x93,0xC8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x93,0xD5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+0x00,0x00, 0x85,0x16, 0xFF,0x74, 0xF7,0x04, 0xE0,0x00, 0x86,0xAA, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x14, 0xF6,0x02, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0x94,0x1C, 0x20,0x32, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0x94,0x1D, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0x94,0x2D, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0x94,0x39, 0x00,0x00,
+0x00,0x01, 0xF4,0x82, 0x00,0x01, 0xF7,0x04, 0x4F,0x58, 0xF4,0x9B, 0x28,0x00, 0x83,0x96,
+0xFF,0xC4, 0xF6,0x86, 0x40,0x9A, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x86,0x1E,
+0x00,0x30, 0x47,0x39, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0xE0,0x00,
+0x94,0xE4, 0xF6,0x3B, 0x28,0x00, 0x47,0x25, 0x00,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38,
+0x68,0x00, 0xF5,0x02, 0x00,0x01, 0xF5,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0x23,0x94,
+0x00,0x62, 0x83,0x9E, 0x00,0x00, 0x77,0x9D, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x9C,
+0x7F,0xC0, 0x73,0x9D, 0xFF,0xF0, 0x25,0x14, 0x00,0x62, 0xF3,0xBB, 0x28,0x00, 0x85,0x2A,
+0x00,0x00, 0x77,0xA9, 0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29,
+0xFF,0xF0, 0xE0,0x00, 0x94,0xE4, 0xF5,0x1B, 0x28,0x00, 0x83,0x96, 0xFF,0xBC, 0x00,0x00,
+0x00,0x01, 0x20,0x1E, 0x00,0x01, 0xE6,0x00, 0x94,0xE4, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x35,0x60, 0xF5,0x05,
+0x42,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x06,
+0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0x96,0x89, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
+0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xEE,0x00, 0x95,0x8D, 0xF5,0x86,
+0x42,0x50, 0xF7,0x04, 0x42,0x50, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x26,0xB4,
+0x00,0x01, 0xF6,0x85, 0x42,0x54, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF6,0x84,
+0x2D,0x38, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x2F,
+0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
+0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x96,0x88, 0xB5,0x36,
+0x70,0x02, 0xE0,0x00, 0x96,0x88, 0xF0,0x05, 0x2D,0x38, 0xF5,0x04, 0x42,0x60, 0x00,0x00,
+0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB2,0x84, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x34, 0x00,0x40, 0xC0,0x22,
+0x72,0x00, 0xE6,0x00, 0x95,0xEC, 0xF6,0x06, 0x42,0x76, 0xF7,0x04, 0x42,0x74, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x60, 0x00,0x00,
+0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00, 0x96,0x24, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0xF5,0x04, 0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x40, 0x00,0x00,
+0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE6,0x00, 0x96,0x71, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF5,0x04,
+0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x96,0x88, 0x00,0x00, 0x00,0x01, 0xF5,0x04,
+0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xC1,0xB4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x70, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0x9B,0x18, 0x06,0xB0,
+0x00,0x02, 0x87,0x36, 0x00,0x00, 0xF4,0x04, 0x40,0x7C, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x42,0x00, 0xE6,0x00,
+0x9B,0x18, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x23,0x94, 0x00,0x38, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30,
+0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94,
+0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x27,0x14,
+0x00,0x20, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04,
+0x40,0x74, 0x94,0x16, 0xFF,0xC4, 0x07,0x20, 0x00,0x02, 0xF0,0x3B, 0x28,0x00, 0x24,0x80,
+0x00,0x07, 0xF4,0x02, 0x00,0xFF, 0x83,0x96, 0xFF,0xC4, 0x95,0x16, 0xFF,0xBC, 0x03,0x1C,
+0x00,0x0A, 0x20,0x26, 0x00,0x07, 0xEE,0x00, 0x98,0xA8, 0x06,0x18, 0x00,0x0E, 0x86,0xB2,
+0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xF6,0xB3, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x04,0xA4,
+0x00,0x01, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x44,0x00, 0xE0,0x00,
+0x98,0x54, 0xF7,0x33, 0x28,0x00, 0x85,0x16, 0xFF,0xC4, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
+0xFF,0xE5, 0x83,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x1E, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
+0xFF,0xE5, 0x05,0x28, 0x00,0x26, 0x95,0x16, 0xFF,0x8C, 0x85,0xAA, 0x00,0x00, 0x76,0xA9,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x03,0x9C, 0x00,0x02, 0x93,0x96, 0xFF,0xB4, 0x06,0x1C,
+0x00,0x02, 0x73,0x95, 0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xAC, 0x73,0x95,
+0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0x9C, 0x83,0x96, 0xFF,0xBC, 0x75,0x15,
+0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16, 0xFF,0x94, 0x75,0x15, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x95,0x16, 0xFF,0xA4, 0x85,0x16, 0xFF,0xC4, 0xC5,0xAC, 0x6F,0xC0, 0x75,0xAD,
+0xFF,0xF0, 0xF5,0x05, 0x42,0x60, 0xF5,0x04, 0x4F,0x58, 0xF6,0x82, 0x00,0xFF, 0xC7,0x1C,
+0x52,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0xC7,0x38, 0x6C,0x00, 0xF6,0x82,
+0xFF,0x00, 0xC5,0xAC, 0x6C,0x00, 0xC7,0x38, 0x58,0x00, 0x83,0x96, 0xFF,0x8C, 0xF5,0x84,
+0x3B,0x6C, 0x85,0x16, 0xFF,0xB4, 0xF7,0x1F, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x06,0xAC,
+0x00,0x01, 0xF6,0x85, 0x3B,0x6C, 0x83,0x96, 0xFF,0xC4, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xF5,0x04, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC0,0x1E,
+0x52,0x00, 0xC7,0x38, 0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
+0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x99, 0x00,0x1E, 0x83,0x96,
+0xFF,0x94, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
+0x00,0x16, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x85,0x16, 0xFF,0xAC, 0x83,0x96,
+0xFF,0xA4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x06,0x30, 0x00,0x02, 0x85,0x16, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xEC, 0x23,0x14,
+0x00,0x12, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0x83,0x96,
+0xFF,0xC4, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16,
+0xFF,0xF0, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+0x28,0x00, 0x07,0x1C, 0x00,0x3A, 0xF5,0xBB, 0x28,0x00, 0x07,0x1C, 0x00,0x36, 0xF0,0x3B,
+0x28,0x00, 0xF5,0x02, 0x00,0x03, 0xE6,0x00, 0x9A,0xA4, 0xF5,0x1F, 0x28,0x00, 0xF7,0x04,
+0x42,0x78, 0xF6,0x06, 0x42,0x78, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9B,0x18, 0x00,0x00,
+0x00,0x01, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0x25,0x00, 0x00,0x07, 0xF5,0x05, 0x42,0x58, 0xF7,0x04,
+0x42,0x50, 0xF6,0x06, 0x42,0x50, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x82,
+0x00,0x06, 0xF3,0x85, 0x42,0x54, 0xF5,0x06, 0x39,0x34, 0xF5,0x05, 0x42,0x44, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x84, 0x2D,0x38, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0x06,0x34, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0xF7,0x06, 0x2C,0x28, 0x76,0xB5,
+0x00,0x02, 0xF3,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0x9B,0x18, 0xB3,0xB6,
+0x70,0x02, 0xF0,0x05, 0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x78, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0x9E,0x41, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xEE,0x00, 0x9D,0x85, 0x24,0x94, 0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14,
+0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
+0xFF,0x94, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94,
+0x00,0x68, 0x93,0x96, 0xFF,0x8C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x84, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
+0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x84, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0x9D,0x5D, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
+0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x1B, 0x93,0x93, 0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00,
+0x00,0x01, 0xF5,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC7,0x28, 0x50,0x00, 0xC7,0x24,
+0x70,0x00, 0x05,0xB8, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xE6,0x00,
+0x9D,0xFD, 0xF6,0x02, 0x00,0xFF, 0xF7,0x04, 0x42,0x78, 0xF6,0x06, 0x42,0x7A, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0x9E,0x40, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+0x00,0x01, 0xC7,0x38, 0x64,0x00, 0xF6,0x02, 0xFF,0x00, 0xC6,0xB4, 0x64,0x00, 0xC7,0x38,
+0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0x07,0x28, 0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x94,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xD8, 0xF3,0x86,
+0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA2,0xC9, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xA0,0x35, 0x24,0x94,
+0x00,0x36, 0xF6,0x04, 0x40,0x74, 0x25,0x14, 0x00,0x38, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1,
+0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32,
+0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x34, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x32, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x30, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x28, 0x76,0x31,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
+0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96, 0xFF,0x4C, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0x44, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02,
+0xFF,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x44, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xA2,0x80, 0x93,0x93,
+0xFF,0xFC, 0xF4,0x04, 0x40,0x7C, 0xF6,0x04, 0x40,0x74, 0xF3,0x82, 0x00,0x00, 0xC7,0x20,
+0x40,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E,
+0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xA0,0xAD, 0x93,0x96, 0xFF,0x3C, 0xF7,0x04, 0x42,0xA0, 0xF6,0x06, 0x42,0xA0, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0xA2,0xC8, 0x00,0x00, 0x00,0x01, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x7E, 0x25,0x14,
+0x00,0x80, 0x23,0x94, 0x00,0x68, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
+0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+0x00,0x7C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+0x00,0x7A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+0x00,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+0x00,0x76, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+0x00,0x74, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x24,0x94,
+0x00,0x72, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x70, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x94,0x13,
+0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x34, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0xB0, 0x93,0x96, 0xFF,0x2C, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0x2C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x3C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x23,0x94, 0x00,0x98, 0x93,0x96, 0xFF,0x24, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF3,0x82,
+0x00,0x06, 0xF3,0x85, 0x42,0x54, 0x87,0x02, 0xFF,0x34, 0xF3,0x86, 0x38,0xA8, 0xF3,0x85,
+0x42,0x44, 0xF7,0x05, 0x42,0x64, 0xF3,0x84, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0xA2,0xA9, 0xF3,0x82, 0x17,0x70, 0xF7,0x04, 0x42,0x54, 0x00,0x00, 0x00,0x01, 0x27,0x38,
+0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0x1B, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF6,0x04, 0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xA3,0xAC, 0x06,0xB0, 0x00,0x02, 0x87,0x36,
+0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0xF6,0x84,
+0x40,0x7C, 0x77,0x39, 0xFF,0xF0, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x00, 0xA3,0xAC, 0xC7,0x34,
+0x68,0x00, 0xF5,0x84, 0x40,0x74, 0xF6,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC6,0x2C,
+0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0xAC, 0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
+0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02,
+0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0xF5,0x06,
+0x42,0x44, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1F,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0xF5,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x80, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA3,0xF4, 0x20,0x3A, 0x00,0x07, 0xF5,0x02,
+0x00,0x01, 0xF5,0x05, 0x42,0x58, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x07, 0xEE,0x00, 0xA6,0xF0, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x23,0x14,
+0x00,0x66, 0xF4,0x84, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0xA4, 0x00,0x02, 0x74,0x25, 0x00,0x1E, 0x74,0x20,
+0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x95,0x16,
+0xFF,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x25,0x14, 0x00,0x20, 0x95,0x16,
+0xFF,0x94, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x85,0x16, 0xFF,0x7C, 0x05,0xA4,
+0x00,0x02, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
+0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x25,0x14, 0x00,0x50, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
+0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+0x00,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+0x00,0x62, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+0x00,0x60, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+0x00,0x5E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+0x00,0x5C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x23,0x14,
+0x00,0x5A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x05,0xAC,
+0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x58, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
+0xFF,0xFC, 0x95,0x16, 0xFF,0x8C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x25,0x14,
+0x00,0x38, 0x95,0x16, 0xFF,0x84, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0xF5,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+0xFF,0xFC, 0xF5,0x04, 0x42,0x64, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
+0xFF,0x84, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16, 0xFF,0x94, 0x00,0x00,
+0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xA6,0xF1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04,
+0x42,0x58, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x07, 0xEE,0x00, 0xA7,0x30, 0xF5,0x02,
+0x17,0x70, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00,
+0xA7,0x50, 0xB5,0x3A, 0x68,0x02, 0xE0,0x00, 0xA7,0x50, 0xF0,0x05, 0x2D,0x38, 0x95,0x13,
+0xFF,0xFC, 0xF5,0x02, 0x00,0x1B, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06, 0x42,0x44, 0x95,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x30, 0xF6,0x04,
+0x6F,0x34, 0xF7,0x04, 0x42,0x64, 0x86,0xB2, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0xA9,0xF0, 0x07,0x30, 0x00,0x02, 0x86,0x3A, 0x00,0x00, 0xF5,0x82,
+0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x30,
+0x77,0xC0, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0x76,0x31, 0xFF,0xF0, 0xC6,0x00,
+0x62,0x00, 0x96,0x16, 0xFF,0xF4, 0xC7,0x38, 0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
+0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0xA8,0x34, 0xF6,0x02, 0x00,0xFF, 0x83,0x16, 0xFF,0xF4, 0x83,0x96,
+0xFF,0xF4, 0xF7,0x04, 0x40,0x78, 0xC6,0x98, 0x38,0x00, 0xC7,0x38, 0x68,0x00, 0x07,0x38,
+0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x64,0x00, 0xC0,0x36, 0x5A,0x00, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xA8,0x3D, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xA8,0x75, 0xF6,0x06,
+0x42,0x7C, 0xF7,0x04, 0x42,0x7C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x78,0x9C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xA9,0xF0, 0x00,0x00,
+0x00,0x01, 0xF3,0x04, 0x42,0x60, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0xF4,0x04, 0x40,0x78, 0xF7,0x04,
+0x4F,0x58, 0xF5,0x04, 0x40,0x74, 0xF3,0x84, 0x40,0x7C, 0xF3,0x04, 0x40,0x7C, 0xC6,0x20,
+0x72,0x00, 0x76,0x30, 0xFF,0xFA, 0xC5,0x9C, 0x30,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC,
+0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x74,0xAD, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x73,0xAD,
+0x00,0x1E, 0x73,0x9C, 0xFF,0xE5, 0x93,0x96, 0xFF,0xD4, 0xC5,0x28, 0x72,0x00, 0x75,0x28,
+0xFF,0xFA, 0x83,0x16, 0xFF,0xF4, 0x83,0x96, 0xFF,0xF4, 0x46,0x31, 0x00,0x00, 0x45,0x29,
+0x00,0x00, 0xC7,0x18, 0x38,0x00, 0xC4,0x20, 0x70,0x00, 0x04,0x20, 0x00,0x26, 0x73,0x21,
+0x00,0x1E, 0xC6,0xB4, 0x4F,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC6,0x30,
+0x4C,0x00, 0xF3,0x82, 0xFF,0x00, 0xC6,0xB4, 0x3C,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
+0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFF,0xCC, 0x83,0x16,
+0xFF,0xD4, 0x83,0x96, 0xFF,0xF4, 0xC5,0x28, 0x4C,0x00, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x76,0x9D, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4,
+0x70,0x00, 0xF6,0xAF, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x83,0x16,
+0xFF,0xCC, 0xF3,0x82, 0xFF,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
+0xFF,0xF0, 0xC7,0x38, 0x3C,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x23, 0x28,0x00, 0x87,0x22,
+0x00,0x00, 0xF3,0x04, 0x40,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19,
+0x00,0x10, 0x93,0x16, 0xFF,0xEC, 0x73,0x99, 0xFF,0xF8, 0xC7,0x38, 0x4C,0x00, 0xC7,0x1C,
+0x70,0x00, 0x97,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x83,0x1A, 0x00,0x00, 0x77,0x99,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC3,0x18, 0x7F,0xC0, 0x73,0x19, 0xFF,0xF0, 0xF3,0x23,
+0x28,0x00, 0xF3,0x86, 0x42,0x44, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x1F,0x48, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x04, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x98, 0xF3,0x06,
+0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x20,0xE4, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xAE,0xE5, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x42,0x54, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEE,0x00, 0xAD,0x89, 0x27,0x38,
+0x00,0x01, 0xF7,0x05, 0x42,0x54, 0x23,0x94, 0x00,0x1E, 0xF6,0x04, 0x42,0x60, 0x24,0x94,
+0x00,0x66, 0x94,0x96, 0xFF,0x64, 0xF3,0x04, 0x40,0x78, 0x24,0x94, 0x00,0x20, 0x94,0x96,
+0xFF,0x94, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x03,0x18, 0x00,0x02, 0x93,0x16, 0xFF,0x74, 0x74,0x19, 0x00,0x1E, 0x74,0x20,
+0xFF,0xE5, 0x05,0x98, 0x00,0x02, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28,
+0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x23,0x94,
+0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x85,0x16, 0xFF,0x64, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F,
+0x28,0x00, 0x23,0x94, 0x00,0x10, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x26,0x14, 0x00,0x68, 0xC7,0x38,
+0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14,
+0x00,0x64, 0x93,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x24,0x94, 0x00,0x62, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
+0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x25,0x14, 0x00,0x60, 0x95,0x16, 0xFF,0x64, 0x05,0xAC,
+0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
+0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x24,0x94,
+0x00,0x5C, 0x94,0x96, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x25,0x14, 0x00,0x5A, 0x95,0x16, 0xFF,0x64, 0x05,0xAC, 0x00,0x02, 0x87,0x2E,
+0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x94, 0x00,0x50, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x23,0x14, 0x00,0x58, 0x05,0xAC,
+0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x93,0x16, 0xFF,0x64, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x96,0x13,
+0xFF,0xFC, 0x94,0x96, 0xFF,0x8C, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x8C, 0x23,0x14, 0x00,0x38, 0x95,0x13,
+0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x93,0x16, 0xFF,0x84, 0x93,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x27,0x80,
+0x00,0x07, 0xF7,0x85, 0x42,0x58, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0xF4,0x84,
+0x42,0x64, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0x84, 0x00,0x00,
+0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xAD,0x5D, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF4,0x82,
+0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xAE,0xE4, 0xB4,0xBA, 0x68,0x02, 0xE0,0x00,
+0xAE,0xE4, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x40,0x78, 0xF5,0x84, 0x4F,0x58, 0x07,0x38,
+0x00,0x16, 0x86,0xBA, 0x00,0x00, 0xF4,0x06, 0x3B,0x90, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x76,0x35, 0x00,0x06, 0xA7,0x2E,
+0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38,
+0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x73,0xB7, 0xFF,0xF0, 0xEE,0x00, 0xAE,0x55, 0x95,0x16, 0xFF,0x64, 0xA7,0x2E,
+0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x23,0x14,
+0x00,0x88, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
+0x00,0x08, 0x85,0x3A, 0x00,0x04, 0x84,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x1A,
+0x00,0x04, 0x94,0x9A, 0x00,0x00, 0x85,0x96, 0xFF,0x7C, 0xE0,0x00, 0xAE,0x78, 0x00,0x00,
+0x00,0x01, 0x84,0x96, 0xFF,0x64, 0xA7,0x2E, 0x60,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
+0x40,0x00, 0x85,0xBA, 0x00,0x04, 0x85,0x16, 0xFF,0x64, 0xF6,0x06, 0x3B,0x90, 0x87,0x2A,
+0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38,
+0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00,
+0xAE,0xC9, 0x76,0xB5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x78, 0x00,0x00, 0x00,0x01, 0x77,0x19,
+0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0x84,0x96, 0xFF,0x64, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
+0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x10, 0xF7,0x04, 0x40,0x84, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xAF,0x3C, 0xF6,0x06, 0x42,0xB8, 0xF7,0x04, 0x42,0xB8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF3,0x06, 0x36,0x78, 0xF3,0x05, 0x42,0x44, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x5C, 0xF3,0x84,
+0x42,0x5C, 0x83,0x3A, 0x00,0x04, 0xC4,0x38, 0x00,0x00, 0x93,0x16, 0xFF,0xEC, 0x77,0x1D,
+0x00,0x01, 0xC7,0x38, 0x38,0x00, 0x77,0x39, 0x00,0x02, 0x04,0xB8, 0x00,0x0C, 0x83,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00, 0xB0,0x70, 0xC5,0x04,
+0x00,0x00, 0xA6,0xA2, 0x48,0x02, 0xF7,0x04, 0xE0,0x00, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0xAF,0xA8, 0xC6,0x20, 0x48,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xAF,0xAC, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xAF,0xB9, 0x00,0x00,
+0x00,0x01, 0xF5,0x02, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0xF7,0x04, 0xE0,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xF4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0xAF,0xFC, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0xF7,0x04,
+0xE0,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xAF,0xFD, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xB0,0x0D, 0x20,0x2A,
+0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xB0,0x59, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x7A,0xD0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xB0,0x64, 0xC7,0x20, 0x48,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x06, 0x40,0x98, 0x77,0x39,
+0x00,0x02, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x00, 0xE6,0x00,
+0xB0,0x64, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x0C, 0xE0,0x00, 0xAF,0x60, 0x03,0x9C,
+0x00,0x01, 0x83,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x32,0x00, 0xEC,0x00,
+0xB1,0x04, 0xF3,0x06, 0x36,0x78, 0xF6,0x84, 0x4F,0x5C, 0x77,0x1D, 0x00,0x01, 0xC7,0x38,
+0x38,0x00, 0x77,0x39, 0x00,0x02, 0x07,0x38, 0x00,0x0C, 0xC6,0xB4, 0x70,0x00, 0x87,0x36,
+0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x96,0x93,
+0xFF,0xFC, 0x93,0x96, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFA,0x98, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xF6,0x84, 0x42,0x6C, 0x83,0x96, 0xFF,0xF4, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0xC7,0x1C, 0x70,0x00, 0xF7,0x05, 0x42,0x5C, 0x06,0xB4,
+0x00,0x01, 0xF7,0x04, 0x2D,0x38, 0xF6,0x85, 0x42,0x6C, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x1C, 0x20,0x32,
+0x00,0x44, 0xE6,0x00, 0xB1,0x08, 0xB3,0x3A, 0x68,0x02, 0xE0,0x00, 0xB1,0x08, 0xF0,0x05,
+0x2D,0x38, 0xF3,0x05, 0x42,0x44, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF4,0x02, 0x00,0x00, 0xC5,0xA0, 0x00,0x00, 0xF6,0x82, 0x07,0x70, 0xF7,0x04,
+0x6E,0x50, 0x20,0x36, 0x00,0x00, 0xE6,0x00, 0xB1,0x6D, 0x06,0x38, 0x00,0x1C, 0x87,0x32,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC4,0x20, 0x70,0x00, 0xC0,0x22, 0x72,0x00, 0xE4,0x00,
+0xB1,0x5D, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x01, 0x26,0xB4, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0xB1,0x40, 0x06,0x30, 0x00,0x04, 0xC4,0x20, 0x58,0x00, 0xC0,0x22,
+0x5A,0x00, 0xE4,0x00, 0xB1,0x81, 0x00,0x00, 0x00,0x01, 0x04,0x20, 0x00,0x01, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x78,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xB1,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x04, 0x40,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x22, 0x72,0x00, 0xE6,0x00,
+0xB1,0xED, 0xF4,0x05, 0x40,0x90, 0xF7,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x86,0xBA,
+0x1D,0xDC, 0xF5,0x82, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x96,0xBA, 0x1D,0xDC, 0x87,0x3A,
+0x1D,0xDC, 0xE0,0x00, 0xB1,0xF0, 0xF5,0x85, 0x7A,0xD0, 0xF0,0x05, 0x7A,0xD0, 0xF5,0x84,
+0x40,0x90, 0xF0,0x05, 0x40,0x84, 0xF5,0x85, 0x40,0x94, 0xF5,0x86, 0xE0,0x00, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x6E,0x50, 0xF4,0x05, 0x40,0x84, 0x85,0xBA, 0x1D,0xDC, 0x00,0x00, 0x00,0x01, 0xF5,0x85,
+0x3B,0x64, 0xF5,0x84, 0xE0,0x00, 0xF0,0x05, 0x42,0x5C, 0x95,0xBA, 0x00,0x10, 0xF5,0x84,
+0xE0,0x04, 0xF6,0x86, 0x2C,0x28, 0x95,0xBA, 0x00,0x14, 0xF7,0x04, 0x2D,0x38, 0xF5,0x86,
+0x3A,0x4C, 0xF5,0x85, 0x42,0x44, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0xF5,0x82, 0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xB2,0x68, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x86, 0x35,0xEC, 0xF5,0x85, 0x42,0x30, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0xC8, 0xF3,0x02,
+0x00,0x00, 0x93,0x16, 0xFF,0x94, 0x24,0x80, 0x00,0x08, 0x94,0x96, 0xFF,0x84, 0x23,0x80,
+0x00,0x07, 0x83,0x16, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x93,0x16, 0xFF,0x54, 0x20,0x1E,
+0x00,0x07, 0xEE,0x00, 0xB5,0x64, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84,
+0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB3,0x2D, 0x20,0x36,
+0x00,0x01, 0xE6,0x00, 0xB3,0x2D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38,
+0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB3,0x31, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C,
+0x00,0x00, 0xE0,0x00, 0xB3,0x30, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04,
+0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB5,0x5D, 0x00,0x00,
+0x00,0x01, 0xF6,0x84, 0x3B,0xBC, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFF,0x3C, 0x04,0x28,
+0x00,0x1C, 0xF7,0x04, 0x3B,0xB8, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x00,
+0xB4,0x40, 0x96,0x96, 0xFF,0xAC, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39,
+0x00,0x02, 0xF4,0x86, 0x3B,0xB4, 0xC6,0x38, 0x48,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x04,
+0x00,0x00, 0x93,0x16, 0xFF,0x34, 0x86,0xB2, 0x00,0x00, 0x87,0x2A, 0x00,0x1C, 0x85,0x96,
+0xFF,0x3C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0x86,0xB2,
+0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0xB3,0xC0, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+0xB3,0xD1, 0x00,0x00, 0x00,0x01, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x34, 0x86,0xB2,
+0x00,0x00, 0x87,0x22, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0xB4,0x0C, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB4,0x14, 0x20,0x2E,
+0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0xB4,0x15, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0xB4,0x25, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16,
+0xFF,0x34, 0x84,0x96, 0xFF,0x34, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+0xB4,0x40, 0x00,0x00, 0x00,0x01, 0xF3,0x02, 0x00,0x01, 0x93,0x16, 0xFF,0x3C, 0x84,0x96,
+0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xB4,0x81, 0xF6,0x02,
+0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06, 0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0xE0,0x00, 0xB4,0xF4, 0x96,0x96, 0xFF,0xB4, 0x27,0x14,
+0x00,0x54, 0x97,0x13, 0xFF,0xFC, 0x94,0x13, 0xFF,0xFC, 0xF4,0x86, 0x3B,0xB4, 0x94,0x93,
+0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xB4,0xF1, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xAC, 0xF3,0x06,
+0x3B,0xB4, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xB0, 0x96,0x96,
+0xFF,0xB4, 0xF7,0x05, 0x3B,0xBC, 0xE0,0x00, 0xB4,0xF8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xB5,0x2D, 0x27,0x14, 0x00,0x08, 0x84,0x96,
+0xFF,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x24, 0x70,0x00, 0x83,0x16, 0xFF,0xB4, 0x04,0xA4,
+0x00,0x04, 0x94,0x96, 0xFF,0x54, 0x84,0x96, 0xFF,0x94, 0x93,0x3A, 0xFF,0xC0, 0x04,0xA4,
+0x00,0x01, 0xE0,0x00, 0xB5,0x54, 0x94,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0x54, 0x00,0x00,
+0x00,0x01, 0xC7,0x18, 0x70,0x00, 0xF4,0x84, 0x4F,0x58, 0x03,0x18, 0x00,0x04, 0x93,0x16,
+0xFF,0x54, 0x83,0x16, 0xFF,0x94, 0x94,0xBA, 0xFF,0xC0, 0x03,0x18, 0x00,0x01, 0x93,0x16,
+0xFF,0x94, 0x95,0x16, 0xFF,0x3C, 0x93,0x96, 0xFF,0x8C, 0xE0,0x00, 0xB2,0xB0, 0x03,0x9C,
+0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+0xB5,0x84, 0xF3,0x82, 0x00,0x01, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x00,0x00,
+0x00,0x01, 0x83,0x16, 0xFF,0xB8, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
+0x4A,0x00, 0xEC,0x00, 0xB5,0xCC, 0x93,0x16, 0xFF,0x7C, 0x26,0x94, 0x00,0x04, 0x87,0x36,
+0xFF,0xC0, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00,
+0xBB,0x98, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x94, 0x00,0x00, 0x00,0x01, 0xC0,0x1E,
+0x4A,0x00, 0xEC,0x00, 0xB5,0xA1, 0x06,0xB4, 0x00,0x04, 0xF4,0x04, 0x4F,0x58, 0x83,0x16,
+0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x42,0x00, 0xE6,0x00, 0xBA,0x2D, 0xF4,0x82,
+0x00,0x00, 0x94,0x96, 0xFF,0x74, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
+0xB7,0x48, 0xC7,0x1C, 0x38,0x00, 0x83,0x16, 0xFF,0x7C, 0x00,0x00, 0x00,0x01, 0xC7,0x18,
+0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xB6,0x69, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
+0xB6,0x69, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
+0x00,0x02, 0xE6,0x00, 0xB6,0x6D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
+0xB6,0x6C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
+0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xB7,0x41, 0xC5,0x84, 0x00,0x00, 0x84,0x96,
+0xFF,0x74, 0x86,0xAA, 0x00,0x1C, 0x83,0x16, 0xFF,0x3C, 0xF6,0x02, 0x00,0x00, 0x04,0xA4,
+0x00,0x01, 0x94,0x96, 0xFF,0x74, 0x87,0x1A, 0x00,0x1C, 0x04,0xA8, 0x00,0x1C, 0x94,0x96,
+0xFF,0x34, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB6,0xCC, 0x04,0x18, 0x00,0x1C, 0x86,0xAA,
+0x00,0x20, 0x87,0x1A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0xB6,0xD0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0xB6,0xDD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0x87,0x22,
+0x00,0x00, 0x86,0x9A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0xB7,0x1C, 0xF6,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xB7,0x24, 0x20,0x32,
+0x00,0x00, 0x86,0x9A, 0x00,0x04, 0x87,0x22, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0xB7,0x25, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0xB7,0x35, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0xB7,0x40, 0x00,0x00, 0x00,0x01, 0x93,0x96, 0xFF,0x84, 0xE0,0x00,
+0xB5,0xEC, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x74, 0x83,0x16, 0xFF,0x94, 0x00,0x00,
+0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x00, 0x00,0x08, 0x84,0x96,
+0xFF,0x84, 0x00,0x00, 0x00,0x01, 0xC0,0x26, 0x32,0x00, 0xE6,0x00, 0xBB,0x99, 0xF6,0x02,
+0x00,0x00, 0xF6,0x84, 0x40,0x7C, 0xF7,0x04, 0x40,0x74, 0xC6,0xB4, 0x68,0x00, 0xC7,0x38,
+0x68,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4, 0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x04, 0xF5,0x82,
+0x00,0xFF, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
+0x32,0x00, 0x84,0x96, 0xFF,0x7C, 0xC7,0x38, 0x70,0x00, 0xC7,0x24, 0x70,0x00, 0x07,0x38,
+0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x5C,0x00, 0xC0,0x36, 0x62,0x00, 0x47,0x0C,
+0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xB8,0x0D, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xBB,0x98, 0x23,0x80,
+0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00, 0xB8,0xC8, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
+0xB8,0x91, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xB8,0x91, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
+0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
+0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xB8,0x95, 0xC6,0xB8,
+0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00, 0xB8,0x94, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84,
+0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34, 0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00,
+0xB8,0xC1, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCC,0x60, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00,
+0xB8,0x14, 0x03,0x9C, 0x00,0x01, 0x84,0x96, 0xFF,0x84, 0x83,0x16, 0xFF,0x8C, 0xF3,0x84,
+0x40,0x7C, 0xF5,0x04, 0x40,0x74, 0xC4,0xA4, 0x32,0x00, 0x94,0x96, 0xFF,0x34, 0x83,0x16,
+0xFF,0x34, 0xC5,0x9C, 0x38,0x00, 0xC5,0xA8, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
+0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x74,0x2D, 0x00,0x1E, 0x74,0x20,
+0xFF,0xE5, 0x73,0x9D, 0x00,0x10, 0x73,0x9D, 0xFF,0xF8, 0xC4,0xA4, 0x30,0x00, 0x94,0x96,
+0xFF,0x3C, 0x83,0x16, 0xFF,0x7C, 0xC6,0xB4, 0x77,0xC0, 0xC4,0x98, 0x48,0x00, 0x94,0x96,
+0xFF,0x3C, 0x04,0xA4, 0x00,0x26, 0x94,0x96, 0xFF,0x3C, 0x73,0x25, 0x00,0x1E, 0x73,0x18,
+0xFF,0xE5, 0x93,0x16, 0xFF,0x6C, 0x74,0xA5, 0x00,0x1E, 0x94,0x96, 0xFF,0x64, 0x74,0xA4,
+0xFF,0xE5, 0x94,0x96, 0xFF,0x64, 0x83,0x16, 0xFF,0x7C, 0xF4,0x84, 0x4F,0x58, 0x76,0xB5,
+0xFF,0xF0, 0xC6,0x18, 0x4A,0x00, 0x76,0x30, 0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xF3,0x02,
+0x00,0xFF, 0xC6,0x30, 0x34,0x00, 0xF4,0x82, 0xFF,0x00, 0xC6,0xB4, 0x4C,0x00, 0xC6,0x30,
+0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x83,0x16, 0xFF,0x34, 0xC7,0x38,
+0x47,0xC0, 0x77,0x39, 0xFF,0xF0, 0x73,0x19, 0x00,0x10, 0x93,0x16, 0xFF,0x34, 0x74,0x99,
+0xFF,0xF8, 0xF3,0x02, 0x00,0xFF, 0xC7,0x38, 0x34,0x00, 0xC7,0x24, 0x70,0x00, 0x97,0x16,
+0xFF,0x34, 0x24,0x94, 0x00,0xCA, 0x84,0xA6, 0x00,0x00, 0x77,0xA5, 0x00,0x1E, 0x77,0xBC,
+0xFF,0xE5, 0xC4,0xA4, 0x7F,0xC0, 0x74,0xA5, 0xFF,0xF0, 0x83,0x16, 0xFF,0x3C, 0xF4,0xAF,
+0x28,0x00, 0xF4,0x84, 0x4F,0x58, 0x87,0x1A, 0x00,0x00, 0xC5,0x28, 0x4A,0x00, 0x75,0x28,
+0xFF,0xFA, 0x83,0x16, 0xFF,0x6C, 0x45,0x29, 0x00,0x00, 0xF4,0x82, 0x00,0xFF, 0xC5,0x28,
+0x4C,0x00, 0x84,0x96, 0xFF,0x3C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF3,0x02,
+0xFF,0x00, 0xC7,0x38, 0x34,0x00, 0xC5,0x28, 0x70,0x00, 0xF5,0x27, 0x28,0x00, 0x87,0x26,
+0x00,0x00, 0x83,0x16, 0xFF,0x64, 0x84,0x16, 0xFF,0x7C, 0xC7,0x38, 0x37,0xC0, 0x77,0x39,
+0xFF,0xF0, 0xF4,0x82, 0x00,0xFF, 0xC7,0x38, 0x4C,0x00, 0x83,0x16, 0xFF,0x3C, 0xC3,0x9C,
+0x70,0x00, 0xE0,0x00, 0xBE,0xE4, 0xF3,0x9B, 0x28,0x00, 0xF7,0x04, 0x40,0x7C, 0xF6,0x04,
+0x40,0x74, 0xC7,0x38, 0x70,0x00, 0xC7,0x30, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x77,0xB4,
+0x00,0x08, 0x70,0x3E, 0xFF,0xE8, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0xBA,0x7D, 0x25,0x80, 0x00,0x07, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
+0x00,0x40, 0xE0,0x00, 0xBA,0xD8, 0xC4,0x2C, 0x00,0x00, 0xC7,0x30, 0x42,0x00, 0x84,0x96,
+0x00,0x00, 0x75,0x38, 0xFF,0xFA, 0x06,0x24, 0x00,0x0A, 0x20,0x2E, 0x00,0x07, 0xEE,0x00,
+0xBA,0xD4, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
+0x74,0x00, 0x47,0x29, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0xBA,0x74, 0x06,0x30, 0x00,0x02, 0xE0,0x00, 0xBA,0x8C, 0x05,0xAC,
+0x00,0x01, 0xF4,0x02, 0x00,0x08, 0x07,0x20, 0x00,0x07, 0x20,0x3A, 0x00,0x0E, 0xE2,0x00,
+0xBB,0xA4, 0xC5,0xA0, 0x40,0x00, 0x83,0x16, 0x00,0x00, 0xF5,0x04, 0x40,0x7C, 0xF4,0x82,
+0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC5,0x98, 0x58,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE,
+0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0x18, 0x62,0x00, 0x76,0x30,
+0xFF,0xFA, 0x46,0x31, 0x00,0x00, 0xC6,0x30, 0x4C,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0x77,0x29, 0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0xC6,0xB4, 0x4C,0x00, 0xC7,0x38,
+0x68,0x00, 0xF7,0x2F, 0x28,0x00, 0xF5,0x84, 0x40,0x74, 0xC5,0x28, 0x50,0x00, 0xC5,0xAC,
+0x50,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0x75,0x2D, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30, 0x68,0x00, 0xF6,0x2F,
+0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xA1, 0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38,
+0x57,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x4C,0x00, 0xC6,0xB4, 0x70,0x00, 0xE0,0x00,
+0xBB,0xF8, 0xF6,0xAF, 0x28,0x00, 0xF4,0x04, 0x4F,0x58, 0xE0,0x00, 0xBE,0xE4, 0x04,0x20,
+0x00,0x40, 0xF6,0x04, 0x4F,0x58, 0x83,0x16, 0x00,0x00, 0xF7,0x04, 0x40,0x7C, 0xF5,0x84,
+0x40,0x74, 0xC6,0x18, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x70,0x00, 0xC5,0xAC,
+0x70,0x00, 0x05,0xAC, 0x00,0x26, 0x86,0xAE, 0x00,0x00, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0x46,0x31, 0x00,0x00, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+0x00,0xFF, 0xC6,0x30, 0x74,0x00, 0xF7,0x02, 0xFF,0x00, 0xC6,0xB4, 0x74,0x00, 0xC6,0x30,
+0x68,0x00, 0xF6,0x2F, 0x28,0x00, 0x23,0x80, 0x00,0x07, 0x20,0x1E, 0x00,0x07, 0xEE,0x00,
+0xBE,0xE0, 0xC7,0x1C, 0x38,0x00, 0x84,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x24,
+0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA, 0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02,
+0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00, 0xBC,0x79, 0x20,0x36, 0x00,0x01, 0xE6,0x00,
+0xBC,0x79, 0x77,0x35, 0x00,0x06, 0xA6,0xBA, 0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36,
+0x00,0x02, 0xE6,0x00, 0xBC,0x7D, 0xC6,0xB8, 0x00,0x00, 0xC7,0x2C, 0x00,0x00, 0xE0,0x00,
+0xBC,0x7C, 0xC6,0xB8, 0x00,0x00, 0xF6,0x84, 0x4F,0x58, 0xF7,0x04, 0x4F,0x58, 0xC5,0x34,
+0x00,0x00, 0xC0,0x2A, 0x72,0x00, 0xE6,0x00, 0xBE,0xD9, 0x06,0xA8, 0x00,0x1C, 0x83,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0xF4,0x86,
+0x3B,0xB4, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x96,0x96,
+0xFF,0x40, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93, 0xFF,0xFC, 0xF3,0x04,
+0x4F,0x5C, 0xF4,0x82, 0x00,0x00, 0x94,0x96, 0xFF,0x5C, 0x86,0x96, 0xFF,0x40, 0x83,0x96,
+0xFF,0x4C, 0x85,0x16, 0xFF,0x44, 0x93,0x16, 0xFF,0x34, 0x86,0x1A, 0x00,0x08, 0x96,0x96,
+0xFF,0x3C, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xEC,0x00,
+0xBD,0xB8, 0x96,0x16, 0xFF,0x9C, 0x77,0x31, 0x00,0x01, 0xC7,0x38, 0x60,0x00, 0x77,0x39,
+0x00,0x02, 0xC6,0x38, 0x30,0x00, 0x06,0x30, 0x00,0x0C, 0x86,0xB2, 0x00,0x00, 0x87,0x2A,
+0x00,0x1C, 0x85,0x96, 0xFF,0x5C, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xBD,0x40, 0xC4,0x04,
+0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x2A, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0xBD,0x44, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E,
+0x00,0x00, 0xE6,0x00, 0xBD,0x51, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x00, 0x83,0x16,
+0xFF,0x3C, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0xBD,0x90, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0xBD,0x98, 0x20,0x2E, 0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xBD,0x99, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xBD,0xA9, 0x20,0x22, 0x00,0x00, 0xF4,0x02,
+0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBD,0xB8, 0x00,0x00, 0x00,0x01, 0xF4,0x82,
+0x00,0x01, 0x94,0x96, 0xFF,0x5C, 0x83,0x16, 0xFF,0x5C, 0x00,0x00, 0x00,0x01, 0x20,0x1A,
+0x00,0x00, 0xE6,0x00, 0xBD,0xF9, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0x9C, 0x84,0x96,
+0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+0x48,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xA0, 0xE0,0x00,
+0xBE,0x70, 0x96,0x96, 0xFF,0xA4, 0x27,0x14, 0x00,0x64, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
+0xFF,0x3C, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x34, 0x00,0x00,
+0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x95,0x16, 0xFF,0x44, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0x85,0x16,
+0xFF,0x44, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xBE,0x71, 0xF6,0x02, 0x00,0x00, 0x87,0x16,
+0xFF,0x9C, 0x83,0x16, 0xFF,0x34, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xA0, 0x96,0x96, 0xFF,0xA4, 0x97,0x1A, 0x00,0x08, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0xBE,0x99, 0xF6,0x06, 0x42,0x9C, 0xF7,0x04, 0x42,0x9C, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC7,0x28,
+0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0x47,0x39, 0x00,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x28,
+0x00,0x1C, 0x97,0x13, 0xFF,0xFC, 0xF4,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+0xFF,0xFC, 0x93,0x96, 0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x23,0x40, 0x97,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFF,0x4C, 0xE0,0x00, 0xBB,0xFC, 0x03,0x9C, 0x00,0x01, 0x84,0x16,
+0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x60, 0x85,0x16, 0x00,0x00, 0x86,0x16, 0x00,0x04, 0x06,0xA8, 0x00,0x18, 0xC7,0x30,
+0x60,0x00, 0xC5,0xB8, 0x68,0x00, 0x20,0x32, 0x00,0x07, 0xEE,0x00, 0xBF,0x64, 0x07,0x2C,
+0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
+0x00,0x00, 0x47,0x0C, 0x00,0x01, 0xD7,0x00, 0x0A,0x70, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xBF,0x61, 0x05,0xAC, 0x00,0x02, 0xE0,0x00, 0xBF,0x18, 0x06,0x30, 0x00,0x01, 0x20,0x32,
+0x00,0x07, 0xEE,0x00, 0xC0,0x4C, 0x06,0xA8, 0x00,0x16, 0xF5,0x05, 0x40,0x74, 0xF6,0x05,
+0x40,0x7C, 0xF3,0x02, 0x00,0x06, 0xF3,0x05, 0x42,0x54, 0x96,0x13, 0xFF,0xFC, 0x05,0x28,
+0x00,0x02, 0x95,0x16, 0xFF,0xC4, 0x95,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x20, 0x93,0x96,
+0xFF,0xBC, 0x93,0x93, 0xFF,0xFC, 0x96,0x16, 0xFF,0xAC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xC4, 0x23,0x14, 0x00,0x38, 0x94,0x93,
+0xFF,0xFC, 0x93,0x16, 0xFF,0xB4, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x86,0x16, 0xFF,0xAC, 0xF7,0x05,
+0x42,0x64, 0x96,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xB4, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0xBC, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0xC8, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xC0,0x1D, 0xF3,0x06, 0x3A,0xD8, 0xF7,0x04, 0x42,0x54, 0x00,0x00,
+0x00,0x01, 0x27,0x38, 0x00,0x01, 0xF7,0x05, 0x42,0x54, 0xF3,0x05, 0x42,0x44, 0xF3,0x82,
+0x17,0x70, 0x93,0x93, 0xFF,0xFC, 0xF4,0x82, 0x00,0x1B, 0x94,0x93, 0xFF,0xFC, 0xF3,0x06,
+0x42,0x44, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0xC1,0xA0, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0xF5,0x84,
+0x4F,0x58, 0xF4,0x06, 0x3B,0x70, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C,
+0x60,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7,
+0xFF,0xF0, 0xEE,0x00, 0xC1,0x15, 0x96,0x96, 0xFF,0x9C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94,
+0x00,0x60, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xA6,0xAA, 0x68,0x02, 0x77,0x1D, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
+0x00,0x08, 0x83,0xBA, 0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6,
+0x00,0x04, 0x93,0x26, 0x00,0x00, 0x85,0x96, 0xFF,0xA4, 0xE0,0x00, 0xC1,0x38, 0x23,0x00,
+0x00,0x07, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x40,0x00, 0x85,0xBA,
+0x00,0x04, 0x23,0x00, 0x00,0x07, 0x93,0x13, 0xFF,0xFC, 0x87,0x2A, 0x00,0x00, 0x76,0xA9,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96, 0xFF,0x9C, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0x20,0x1E,
+0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0xEE,0x00, 0xC1,0x8D, 0x76,0xB5, 0xFF,0xF0, 0x84,0x96, 0xFF,0xA0, 0x00,0x00,
+0x00,0x01, 0x77,0x25, 0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x2C, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x70, 0x25,0x00,
+0x00,0x07, 0x20,0x2A, 0x00,0x07, 0xEE,0x00, 0xC3,0xB8, 0xC7,0x28, 0x50,0x00, 0x83,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x70,0x00, 0x07,0x38, 0x00,0x26, 0x86,0xBA,
+0x00,0x00, 0xF5,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB6, 0x74,0x00, 0xE6,0x00,
+0xC2,0x3D, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xC2,0x3D, 0x77,0x35, 0x00,0x06, 0xA6,0xBA,
+0x58,0x02, 0xC7,0x38, 0x58,0x00, 0x76,0x39, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC6,0xB4,
+0x67,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xC2,0x4D, 0xC0,0x3A,
+0x5A,0x00, 0xE0,0x00, 0xC2,0x48, 0xC7,0x2C, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF5,0x84,
+0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x5A,0x00, 0xE6,0x00, 0xC3,0xB1, 0xF4,0x86,
+0x3B,0x90, 0x83,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x06,0x9C, 0x00,0x16, 0x87,0x36,
+0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0x76,0x39, 0x00,0x06, 0xA7,0x2E, 0x60,0x02, 0xC5,0x2C, 0x60,0x00, 0x76,0xA9,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB7, 0xFF,0xF0, 0xEE,0x00,
+0xC3,0x21, 0x96,0x96, 0xFF,0x8C, 0xA7,0x2E, 0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x83,0x16, 0xFF,0x8C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xC7,0x38, 0x48,0x00, 0x86,0xBA, 0x00,0x04, 0x24,0x94, 0x00,0x70, 0x77,0x39,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAA,
+0x68,0x02, 0x77,0x19, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x83,0xBA,
+0x00,0x04, 0x83,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0xA6, 0x00,0x04, 0x93,0x26,
+0x00,0x00, 0x86,0x16, 0xFF,0x94, 0xE0,0x00, 0xC3,0x44, 0x00,0x00, 0x00,0x01, 0xA7,0x2E,
+0x60,0x02, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF3,0x06, 0x3B,0x90, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x30,0x00, 0x86,0x3A,
+0x00,0x04, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x96,
+0xFF,0x8C, 0xF4,0x86, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xA6,0xBA, 0x48,0x02, 0x20,0x1E, 0x00,0x00, 0xC7,0x38, 0x48,0x00, 0x77,0x39,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC3,0x95, 0x76,0xB5,
+0xFF,0xF0, 0x83,0x16, 0xFF,0x90, 0x00,0x00, 0x00,0x01, 0x77,0x19, 0xFF,0xF0, 0xC6,0xB8,
+0x68,0x00, 0xC7,0x28, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xC1,0x30,
+0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xC5,0xC4, 0x00,0x00, 0x00,0x01, 0xE0,0x00,
+0xC1,0xC4, 0x05,0x28, 0x00,0x01, 0x83,0x96, 0x00,0x00, 0xF4,0x82, 0x00,0x06, 0xF4,0x85,
+0x42,0x54, 0xF6,0x04, 0x42,0x60, 0x25,0x14, 0x00,0x1E, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+0xFF,0xAC, 0xF3,0x85, 0x40,0x78, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC,
+0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14,
+0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x25,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x07,0x1C,
+0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x23,0x94, 0x00,0x50, 0x93,0x96, 0xFF,0xA4, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD2,0x58, 0x97,0x93, 0xFF,0xFC, 0x84,0x96,
+0xFF,0xA4, 0x23,0x14, 0x00,0x38, 0x94,0x93, 0xFF,0xFC, 0x27,0x80, 0x00,0x07, 0x97,0x93,
+0xFF,0xFC, 0x93,0x16, 0xFF,0x9C, 0x93,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCF,0x24, 0x97,0x93, 0xFF,0xFC, 0x87,0x02, 0xFF,0x34, 0x27,0x80, 0x00,0x07, 0xF7,0x85,
+0x42,0x58, 0xF7,0x05, 0x42,0x64, 0x27,0x80, 0x00,0x07, 0x97,0x93, 0xFF,0xFC, 0x97,0x13,
+0xFF,0xFC, 0x83,0x96, 0xFF,0x9C, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x84,0x96,
+0xFF,0xAC, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xF5,0xF4, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xC5,0x95, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x42,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x42,0x58, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x39,0xC0, 0xF3,0x05, 0x42,0x44, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x82,
+0x00,0x1C, 0x20,0x32, 0x00,0x44, 0xE6,0x00, 0xC5,0xC4, 0xB3,0xBA, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x25,0x00,
+0x00,0x07, 0xF7,0x04, 0x40,0x74, 0xF6,0x84, 0x4F,0x58, 0xF6,0x04, 0x42,0x60, 0xC7,0x38,
+0x6A,0x00, 0x75,0xB8, 0xFF,0xFA, 0x06,0x30, 0x00,0x0A, 0x20,0x2A, 0x00,0x07, 0xEE,0x00,
+0xC6,0x48, 0x07,0x30, 0x00,0x0E, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4,
+0x74,0x00, 0x47,0x2D, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0xC6,0x4C, 0xC3,0x28, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xE0,0x00,
+0xC5,0xFC, 0x05,0x28, 0x00,0x01, 0xF3,0x02, 0x00,0x08, 0xC5,0x18, 0x30,0x00, 0xF3,0x84,
+0x42,0x60, 0xF6,0x04, 0x4F,0x58, 0xF7,0x04, 0x40,0x7C, 0xF4,0x84, 0x40,0x74, 0xC5,0x1C,
+0x50,0x00, 0x05,0x28, 0x00,0x26, 0x85,0xAA, 0x00,0x00, 0x74,0x29, 0x00,0x1E, 0x74,0x20,
+0xFF,0xE5, 0xC6,0x1C, 0x62,0x00, 0x76,0x30, 0xFF,0xFA, 0xC6,0xB8, 0x70,0x00, 0xC4,0xA4,
+0x68,0x00, 0x04,0xA4, 0x00,0x26, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x77,0x39,
+0x00,0x10, 0x77,0x39, 0xFF,0xF8, 0x46,0x31, 0x00,0x00, 0xC5,0xAC, 0x47,0xC0, 0x75,0xAD,
+0xFF,0xF0, 0xF4,0x02, 0x00,0xFF, 0xC5,0xAC, 0x44,0x00, 0xC7,0x38, 0x58,0x00, 0xF7,0x2B,
+0x28,0x00, 0x87,0x26, 0x00,0x00, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30, 0x44,0x00, 0x75,0xAC,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xF6,0x82, 0xFF,0x00, 0xC7,0x38,
+0x6C,0x00, 0xC6,0x30, 0x70,0x00, 0xF6,0x27, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x76,0x99,
+0x00,0x10, 0x76,0xB5, 0xFF,0xF8, 0xC7,0x38, 0x5F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
+0x44,0x00, 0xC6,0xB4, 0x70,0x00, 0xF6,0xA7, 0x28,0x00, 0x93,0x93, 0xFF,0xFC, 0xF3,0x84,
+0x3B,0xB0, 0x00,0x00, 0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x40,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0xF3,0x84, 0x40,0x74, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xBE,0xF8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
+0x42,0x30, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x35,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x30, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x35,0xEC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x36,0x78, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x04, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x37,0x90, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x38,0x1C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x38,0xA8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0x34, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x39,0xC0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x3A,0x4C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x42,0x44, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x3A,0xD8, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+0x00,0x00, 0xF5,0x06, 0x3B,0x90, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38,
+0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA, 0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37, 0xFF,0xF0, 0xEE,0x00, 0xC9,0x95, 0x00,0x00,
+0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA,
+0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31, 0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38,
+0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A, 0x00,0x00, 0xE0,0x00, 0xC9,0xB4, 0xC5,0x24,
+0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A,
+0x00,0x04, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32,
+0x00,0x00, 0xF6,0x06, 0x3B,0x90, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xC9,0xF9, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
+0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96, 0x00,0x00, 0xF5,0x06, 0x3B,0x70, 0x87,0x2E,
+0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x77,0x39, 0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x07,0x38, 0x00,0x02, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x37,
+0xFF,0xF0, 0xEE,0x00, 0xCA,0xBD, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x86,0xBA, 0x00,0x04, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xA6,0xAE, 0x68,0x02, 0x77,0x31,
+0x00,0x03, 0xC7,0x38, 0x68,0x00, 0x27,0x38, 0x00,0x08, 0x84,0xBA, 0x00,0x04, 0x84,0x3A,
+0x00,0x00, 0xE0,0x00, 0xCA,0xDC, 0xC5,0x24, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xC7,0x38, 0x50,0x00, 0x85,0x3A, 0x00,0x04, 0x83,0x96, 0x00,0x04, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x20,0x32, 0x00,0x00, 0x93,0x93, 0xFF,0xFC, 0x87,0x2E,
+0x00,0x00, 0xF6,0x06, 0x3B,0x70, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0x39,
+0x00,0x03, 0xA6,0xBA, 0x60,0x02, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0xEE,0x00, 0xCB,0x29, 0x76,0xB5, 0xFF,0xF0, 0x77,0x21,
+0xFF,0xF0, 0xC6,0xB8, 0x68,0x00, 0xC7,0x2C, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xC1,0x28, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x04, 0x4F,0x58, 0xF5,0x82, 0x00,0x02, 0x06,0x28,
+0x00,0x80, 0x20,0x2E, 0x00,0x62, 0xEE,0x00, 0xCB,0x90, 0x07,0x30, 0x00,0x40, 0xF0,0x33,
+0x28,0x00, 0xC6,0xB8, 0x52,0x00, 0x76,0xB4, 0xFF,0xFA, 0x06,0x30, 0x00,0x14, 0xF6,0xB3,
+0x28,0x00, 0xC6,0x38, 0x00,0x00, 0xE0,0x00, 0xCB,0x64, 0x05,0xAC, 0x00,0x01, 0xF7,0x04,
+0x4F,0x58, 0x00,0x00, 0x00,0x01, 0x06,0xB8, 0x18,0xD4, 0xF4,0x82, 0x00,0x01, 0xF4,0xB7,
+0x28,0x00, 0x07,0x38, 0x18,0xC0, 0xF0,0x3B, 0x28,0x00, 0xF7,0x06, 0x42,0xC0, 0xF4,0x82,
+0x00,0x02, 0xF4,0xBB, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF6,0x84, 0x42,0xC0, 0xF6,0x06, 0x42,0xC0, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0x75,0xB1, 0x00,0x1E, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04,
+0x4F,0x58, 0x76,0xB5, 0x00,0x06, 0xC4,0x38, 0x68,0x00, 0x87,0x22, 0x00,0x14, 0x76,0xA1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+0x28,0x00, 0xF7,0x04, 0x42,0xC0, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0x20,0x3A, 0x00,0x01, 0xE6,0x00, 0xCC,0x4C, 0xF6,0x06, 0x42,0x90, 0xF7,0x04,
+0x42,0x90, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0x85,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0xCC,0xBC, 0xF5,0x86, 0x42,0xC0, 0xF7,0x04, 0x42,0x90, 0xF6,0x06, 0x42,0x92, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0xCC,0xEC, 0xF7,0x33, 0x28,0x00, 0xF0,0x2B, 0x28,0x00, 0xF6,0x84,
+0x42,0xC0, 0x77,0x2D, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x06,0x28, 0x00,0x14, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF7,0x04, 0x4F,0x58, 0xF6,0xB3, 0x28,0x00, 0xC7,0x28,
+0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x2F, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x4F,0x58, 0xF4,0x02,
+0x00,0x00, 0xC6,0xB4, 0x72,0x00, 0x77,0x34, 0xFF,0xFA, 0x27,0x38, 0x00,0x02, 0x20,0x3A,
+0x00,0x61, 0xF7,0x02, 0x00,0x3F, 0xE2,0x00, 0xCD,0x40, 0xC6,0xB4, 0x74,0x00, 0x20,0x36,
+0x00,0x00, 0xE6,0x00, 0xCD,0x40, 0x00,0x00, 0x00,0x01, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0x87,0x16,
+0x00,0x08, 0x85,0x96, 0x00,0x04, 0xC5,0x30, 0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE6,0x00,
+0xCD,0xA1, 0x00,0x00, 0x00,0x01, 0x86,0xB2, 0x00,0x00, 0x77,0x31, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xAF, 0x68,0x00, 0x06,0x30,
+0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE6,0x00, 0xCD,0x78, 0x05,0xAC, 0x00,0x01, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x96,
+0x00,0x00, 0x84,0x16, 0x00,0x04, 0x85,0x96, 0x00,0x08, 0x86,0xA6, 0x00,0x00, 0x77,0x25,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x75,0x35, 0xFF,0xF0, 0x20,0x2A,
+0x00,0x10, 0xE2,0x00, 0xCE,0x0D, 0xF6,0x06, 0x42,0x8E, 0xF5,0x02, 0x00,0x10, 0xF7,0x04,
+0x42,0x8C, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x20,0x2E, 0x00,0x01, 0xE6,0x00,
+0xCE,0x70, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xCE,0x71, 0x07,0x24, 0x00,0x02, 0x25,0x28,
+0x00,0x01, 0xA5,0xBA, 0x50,0x02, 0x86,0x22, 0x00,0x00, 0x76,0xA1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC5,0xAC,
+0x77,0xC0, 0xC6,0x30, 0x6F,0xC0, 0x76,0x31, 0xFF,0xF0, 0x75,0xAD, 0xFF,0xE8, 0xF6,0x82,
+0x00,0xFF, 0xF7,0x02, 0xF1,0x54, 0x75,0xAD, 0x00,0x02, 0xA7,0x2E, 0x70,0x02, 0xC6,0x30,
+0x6C,0x00, 0xC6,0x30, 0x75,0x80, 0xF6,0x23, 0x28,0x00, 0x24,0x20, 0x00,0x02, 0x25,0xA8,
+0x00,0x01, 0xF3,0x02, 0xF2,0x46, 0x03,0xA4, 0x00,0x02, 0xC4,0xAC, 0x38,0x00, 0x25,0x2C,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xCF,0x11, 0x00,0x00, 0x00,0x01, 0xE6,0x00,
+0xCE,0xA0, 0xC7,0x1C, 0x50,0x00, 0xE0,0x00, 0xCE,0xB4, 0xF6,0x02, 0x00,0x00, 0xA6,0x9E,
+0x50,0x02, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0x35,
+0xFF,0xE8, 0x86,0xA6, 0x00,0x00, 0x77,0x25, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0x25,0x28,
+0x00,0x02, 0x25,0xAC, 0x00,0x02, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0x77,0x31,
+0x00,0x04, 0xC7,0x38, 0x62,0x00, 0x77,0x39, 0x00,0x01, 0xC7,0x38, 0x30,0x00, 0xC6,0xB4,
+0x68,0x00, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x0E, 0x87,0x36, 0x00,0x00, 0x24,0xA4,
+0x00,0x02, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xE0,0x00, 0xCE,0x84, 0x24,0x20, 0x00,0x02, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x08, 0x83,0x16,
+0x00,0x04, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x74,0x1D,
+0x00,0x1E, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x05,0xAC, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x74,0x20,
+0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x1F,
+0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x04,0x9C, 0x00,0x02, 0xC7,0x38, 0x47,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x25,0x38, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xEE,0x00, 0xD0,0xBD, 0x26,0x28,
+0x00,0x01, 0xA7,0x26, 0x60,0x02, 0xC6,0xA4, 0x60,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC5,0xA4, 0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xE8, 0xE0,0x00, 0xD0,0x88, 0xF7,0x2F, 0x68,0x00, 0x07,0x1C, 0x00,0x02, 0xF3,0x3B,
+0x68,0x00, 0xC4,0x1C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x86,0x16, 0x00,0x04, 0x84,0x16, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0xA0, 0x00,0x02, 0x74,0xA1, 0x00,0x1E, 0x74,0xA4,
+0xFF,0xE5, 0x06,0x30, 0x00,0x02, 0x75,0x31, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x06,0xA0, 0x00,0x02, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2F, 0x28,0x00, 0x87,0x22,
+0x00,0x00, 0x76,0x21, 0x00,0x1E, 0x85,0x96, 0x00,0x08, 0xC7,0x38, 0x4F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0xC6,0xB4, 0x70,0x00, 0xF5,0xB7, 0x68,0x00, 0x87,0x22, 0x00,0x00, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x23,
+0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x20, 0x27,0x14, 0x00,0x20, 0xF0,0x3B, 0x28,0x00, 0x84,0x96, 0x00,0x04, 0xF5,0x02,
+0x00,0x00, 0x86,0xA6, 0x00,0x00, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x04,0x24,
+0x00,0x02, 0xC6,0xB4, 0x67,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xBB, 0x28,0x00, 0x87,0x26,
+0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0xC0,0x2A, 0x72,0x00, 0xEC,0x00, 0xD2,0xF8, 0x76,0xA5, 0x00,0x1E, 0x87,0x26,
+0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0x06,0x28, 0x00,0x01, 0x25,0x94, 0x00,0x1E, 0xC5,0xAC,
+0x50,0x00, 0xC5,0x30, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
+0x52,0x00, 0xA6,0xA2, 0x70,0x02, 0xC7,0x20, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xC6,0x80, 0x6A,0x00, 0xE0,0x00,
+0xD2,0x90, 0xF6,0xAF, 0x68,0x00, 0x87,0x16, 0xFF,0xE0, 0x76,0x15, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x83,0x96, 0x00,0x00, 0x23,0x14, 0x00,0x1E, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
+0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x06,0x9C, 0x00,0x02, 0x73,0x95,
+0x00,0x1E, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x67,0xC0, 0x83,0x96, 0x00,0x00, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x83,0x96, 0xFF,0xDC, 0x87,0x1A, 0x00,0x00, 0x73,0x9C,
+0xFF,0xE5, 0x93,0x96, 0xFF,0xDC, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE4, 0x23,0x14, 0x00,0x1A, 0x76,0x19,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xE8, 0x23,0x14,
+0x00,0x16, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0xEC, 0x23,0x14, 0x00,0x12, 0x76,0x19, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0x84,0x16, 0x00,0x00, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x16, 0xFF,0xF0, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x3F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x86,0x16, 0x00,0x00, 0x84,0x16, 0x00,0x04, 0xF6,0x84, 0x4F,0x58, 0x87,0x32,
+0x00,0x14, 0x03,0x30, 0x00,0x14, 0x75,0x19, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC3,0xA0,
+0x6A,0x00, 0x73,0x9C, 0xFF,0xFA, 0x04,0xA0, 0x00,0x14, 0x75,0xA5, 0x00,0x1E, 0xC6,0x30,
+0x6A,0x00, 0x76,0x30, 0xFF,0xFA, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0xF3,0x9B, 0x28,0x00, 0x07,0x20, 0x00,0x16, 0xF6,0x3B, 0x28,0x00, 0x87,0x22,
+0x00,0x14, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39,
+0x00,0x06, 0xC6,0xB4, 0x70,0x00, 0x06,0xB4, 0x00,0x16, 0xF3,0xB7, 0x28,0x00, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16, 0x00,0x00, 0xF5,0x84,
+0x4F,0x58, 0x05,0x30, 0x00,0x16, 0x87,0x2A, 0x00,0x00, 0x76,0xA9, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC4,0x2C,
+0x70,0x00, 0xC0,0x22, 0x62,0x00, 0xE6,0x00, 0xD5,0x29, 0x06,0xA0, 0x00,0x16, 0x87,0x36,
+0x00,0x00, 0xC6,0x30, 0x5A,0x00, 0x76,0x30, 0xFF,0xFA, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0x76,0xB8,
+0xFF,0xFA, 0xF6,0xAB, 0x28,0x00, 0xC7,0x2C, 0x70,0x00, 0x07,0x38, 0x00,0x14, 0xE0,0x00,
+0xD5,0x2C, 0xF6,0x3B, 0x28,0x00, 0xC4,0x2C, 0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x4F,0x84, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05,
+0x6F,0x30, 0xF6,0x86, 0x50,0x5C, 0x46,0xB4, 0xFF,0xFC, 0xF6,0x85, 0x6E,0x50, 0xF7,0x06,
+0x6E,0x7C, 0x47,0x38, 0xFF,0xFC, 0xF7,0x05, 0x6E,0x54, 0x07,0x34, 0x19,0x1C, 0xF7,0x05,
+0x4F,0x5C, 0xF7,0x02, 0x00,0x64, 0x97,0x36, 0x19,0x1C, 0xF7,0x02, 0x00,0x00, 0x97,0x36,
+0x19,0x20, 0x06,0xB4, 0x00,0x1C, 0xF6,0x85, 0x4F,0x58, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x90, 0xF3,0x02, 0xFF,0xFF, 0xF3,0x05,
+0x4F,0x54, 0xF3,0x82, 0x00,0x00, 0x93,0x96, 0xFF,0xAC, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+0xFF,0x9C, 0x23,0x94, 0x00,0x38, 0x93,0x96, 0xFF,0x94, 0x83,0x16, 0xFF,0xAC, 0xF7,0x04,
+0x4F,0x5C, 0xF3,0x82, 0x00,0x0C, 0x93,0x96, 0xFF,0x74, 0x93,0x16, 0xFF,0x8C, 0x87,0x3A,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xA4, 0x83,0x16, 0xFF,0xAC, 0x83,0x96,
+0xFF,0xA4, 0x00,0x00, 0x00,0x01, 0xC0,0x1A, 0x3A,0x00, 0xEC,0x00, 0xDB,0x78, 0xF3,0x02,
+0x04,0xBC, 0xF7,0x04, 0x4F,0x5C, 0x83,0x16, 0xFF,0x74, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x30,0x00, 0x87,0x3A, 0x00,0x08, 0xF6,0x84, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC4,0xB4,
+0x70,0x00, 0x94,0x93, 0xFF,0xFC, 0x94,0x96, 0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFF,0x7C, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0xD6,0x54, 0xC5,0x04, 0x00,0x00, 0xF7,0x04, 0x42,0x88, 0xE0,0x00, 0xD8,0x7C, 0xF6,0x06,
+0x42,0x88, 0xF6,0x04, 0x4F,0x5C, 0x83,0x96, 0x00,0x00, 0x83,0x16, 0xFF,0x74, 0x86,0x9E,
+0x00,0x00, 0xA7,0x32, 0x30,0x02, 0xF5,0x82, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0xD6,0x94, 0xC6,0x30, 0x30,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xD6,0x98, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xA5, 0x00,0x00, 0x00,0x01, 0xF5,0x02,
+0x00,0x00, 0x83,0x96, 0x00,0x00, 0x87,0x32, 0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xE4, 0xF5,0x82, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0xE6,0x00, 0xD6,0xEC, 0x20,0x2E, 0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x32,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xD6,0xED, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xD6,0xFD, 0x20,0x2A,
+0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xD7,0x28, 0x04,0xA4,
+0x00,0x02, 0x83,0x16, 0xFF,0xAC, 0xF7,0x06, 0x42,0xC8, 0x83,0x96, 0xFF,0x8C, 0xF3,0x05,
+0x4F,0x54, 0xC7,0x1C, 0x70,0x00, 0xF0,0x3B, 0x28,0x00, 0x07,0x38, 0x00,0x02, 0xE0,0x00,
+0xDB,0x50, 0xF0,0x3B, 0x28,0x00, 0x94,0x96, 0xFF,0x6C, 0x87,0x26, 0x00,0x00, 0x76,0xA5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16, 0xFF,0x6C, 0x83,0x96, 0xFF,0x9C, 0x24,0x94,
+0x00,0x1E, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x1D,
+0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x24,0x94, 0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x94, 0x00,0x10, 0x76,0x31,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0xF6,0x82, 0xFF,0xFC, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x03, 0xC4,0xB8, 0x6C,0x00, 0x20,0x26, 0x00,0x10, 0xE2,0x00,
+0xD8,0x9D, 0xF6,0x06, 0x42,0x8A, 0xF7,0x04, 0x42,0x88, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0xDB,0xA0, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x6C, 0x25,0x14,
+0x00,0x36, 0x83,0x96, 0xFF,0x94, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x06,0x18, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x1F, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x34, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x32, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x30, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2E, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2C, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x2A, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x28, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x26,0xA4, 0x00,0x02, 0x74,0xA4, 0xFF,0xFF, 0x76,0x31,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
+0x28,0x00, 0x90,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0x8C, 0xF7,0x06, 0x42,0xCC, 0xC7,0x18,
+0x70,0x00, 0xC7,0x38, 0x68,0x00, 0x97,0x13, 0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0x94,0x96,
+0xFF,0x7C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0x6C, 0x24,0x14, 0x00,0x4E, 0x25,0x14, 0x00,0x50, 0x83,0x16, 0xFF,0x8C, 0x84,0x96,
+0xFF,0x7C, 0x87,0x1E, 0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x1C,
+0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0x29, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x4C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x4A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x48, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x46, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x44, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x42, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x40, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x86,0x96,
+0xFF,0xB0, 0xF6,0x06, 0x42,0xC8, 0xC6,0x18, 0x60,0x00, 0xF7,0x02, 0x00,0x03, 0xC6,0xB4,
+0x57,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
+0x6A,0x00, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xF4,0xB3, 0x28,0x00, 0x83,0x96,
+0xFF,0x8C, 0x83,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x14, 0x93,0x96, 0xFF,0x8C, 0x03,0x18,
+0x00,0x0C, 0x83,0x96, 0xFF,0xAC, 0x93,0x16, 0xFF,0x74, 0x03,0x9C, 0x00,0x01, 0xE0,0x00,
+0xD5,0xEC, 0x93,0x96, 0xFF,0xAC, 0x93,0x13, 0xFF,0xFC, 0xF3,0x84, 0x4F,0x5C, 0x00,0x00,
+0x00,0x01, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x01,0xA0, 0xF5,0x02,
+0x00,0x00, 0xF3,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x1C, 0x20,0x2A, 0x00,0x63, 0xEE,0x00,
+0xDC,0x08, 0xC5,0x9C, 0x60,0x00, 0xA6,0x9E, 0x60,0x02, 0x77,0x2D, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x20,0x36, 0x00,0x03, 0xE6,0x00,
+0xDB,0xFC, 0x07,0x2C, 0x00,0x36, 0xF0,0x3B, 0x28,0x00, 0x06,0x30, 0x00,0x40, 0xE0,0x00,
+0xDB,0xCC, 0x05,0x28, 0x00,0x01, 0xF5,0x84, 0x4F,0x5C, 0x00,0x00, 0x00,0x01, 0x86,0xAE,
+0x00,0x08, 0xF4,0x02, 0x00,0x00, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xEC,0x00, 0xDC,0xF0, 0x96,0x96, 0xFF,0xEC, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0x38, 0x58,0x00, 0x06,0x30, 0x00,0x0C, 0xC3,0x84,
+0x00,0x00, 0x83,0x16, 0x00,0x00, 0x86,0xB2, 0x00,0x00, 0x87,0x1A, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0x7C, 0xC5,0x20, 0x00,0x00, 0x86,0xB2,
+0x00,0x04, 0x87,0x1A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0xDC,0x80, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00,
+0xDC,0x8D, 0x00,0x00, 0x00,0x01, 0xF3,0x82, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x86,0xB2,
+0x00,0x00, 0x87,0x26, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0xDC,0xCC, 0xF5,0x02, 0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xDC,0xD4, 0x20,0x2A,
+0x00,0x00, 0x86,0xB2, 0x00,0x04, 0x87,0x26, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x00, 0xDC,0xD5, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A,
+0x00,0x00, 0xE6,0x00, 0xDC,0xE5, 0x20,0x1E, 0x00,0x00, 0xF3,0x82, 0x00,0x01, 0x20,0x1E,
+0x00,0x00, 0xE6,0x00, 0xDC,0xF4, 0x20,0x22, 0x00,0x00, 0xF4,0x02, 0x00,0x01, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xDD,0x29, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xEC, 0x00,0x00,
+0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xF0, 0xE0,0x00,
+0xDD,0x98, 0x96,0x96, 0xFF,0xF4, 0x27,0x14, 0x00,0x14, 0x97,0x13, 0xFF,0xFC, 0x83,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96,
+0xFE,0x70, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+0xFE,0x70, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDD,0x95, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x58,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xF0, 0x96,0x96, 0xFF,0xF4, 0x97,0x2E, 0x00,0x08, 0xE0,0x00, 0xDD,0x9C, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xDD,0xB0, 0xF4,0x82,
+0x00,0x00, 0xF7,0x04, 0x42,0x7C, 0xE0,0x00, 0xE0,0x9C, 0xF6,0x06, 0x42,0x7E, 0x94,0x96,
+0xFF,0x44, 0x87,0x16, 0xFF,0xF4, 0xF6,0x04, 0x4F,0x58, 0x77,0x39, 0x00,0x06, 0xC7,0x30,
+0x70,0x00, 0x97,0x16, 0xFF,0x54, 0x06,0xB8, 0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16,
+0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x93,0x13,
+0xFF,0xFC, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC6,0x30, 0x70,0x00, 0x96,0x16,
+0xFF,0x4C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xDE,0x35, 0xF3,0x02, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00,
+0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xDE,0x38, 0x00,0x00, 0x00,0x01, 0xF3,0x02,
+0x00,0x01, 0x93,0x16, 0xFF,0x44, 0x84,0x96, 0xFF,0x44, 0x00,0x00, 0x00,0x01, 0x20,0x26,
+0x00,0x00, 0xE6,0x00, 0xDE,0x59, 0xF6,0x06, 0x42,0xA4, 0xF7,0x04, 0x42,0xA4, 0xE0,0x00,
+0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x83,0x16, 0xFF,0x4C, 0x86,0x16, 0xFF,0x4C, 0x87,0x1A,
+0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00, 0xDE,0x85, 0x00,0x00, 0x00,0x01, 0xF6,0x04,
+0x4F,0x58, 0xF5,0x84, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
+0xE0,0x25, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFF,0x4C, 0x00,0x00, 0x00,0x01, 0x06,0xA4,
+0x00,0x1A, 0x87,0x36, 0x00,0x00, 0x83,0x16, 0xFF,0x54, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x77,0x39, 0x00,0x06, 0xC7,0x2C,
+0x70,0x00, 0xC0,0x3A, 0x32,0x00, 0xE6,0x00, 0xDE,0xDD, 0xF6,0x06, 0x42,0x80, 0xF7,0x04,
+0x42,0x80, 0xE0,0x00, 0xE0,0xA0, 0x76,0xB1, 0x00,0x1E, 0x26,0x14, 0x00,0x30, 0xF0,0x33,
+0x28,0x00, 0x87,0x16, 0xFF,0xD0, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
+0xFF,0x4C, 0x23,0x14, 0x00,0x2E, 0x93,0x16, 0xFE,0x64, 0x75,0x99, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0x75,0x15, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
+0xFF,0xE5, 0x93,0x16, 0xFF,0x34, 0x83,0x16, 0xFE,0x64, 0x04,0x24, 0x00,0x02, 0x06,0xA0,
+0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x3C, 0x74,0x95,
+0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x2C, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xD4, 0x24,0x94,
+0x00,0x2A, 0x94,0x96, 0xFE,0x64, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xD8, 0x23,0x14, 0x00,0x26, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
+0x00,0x1E, 0x84,0x96, 0xFF,0x3C, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96,
+0xFF,0x34, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0xDC, 0x23,0x14, 0x00,0x22, 0x93,0x16, 0xFE,0x64, 0x76,0x19,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xE0, 0x83,0x16, 0xFF,0x2C, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0xA0, 0xF7,0x37,
+0x28,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCB,0xCC, 0x97,0x93, 0xFF,0xFC, 0x06,0xA0,
+0x00,0x02, 0xF7,0x04, 0x4F,0x58, 0xF0,0x37, 0x28,0x00, 0x06,0xA0, 0x00,0x14, 0x94,0x16,
+0xFF,0x24, 0xC7,0x20, 0x72,0x00, 0x77,0x38, 0xFF,0xFA, 0xF7,0x37, 0x28,0x00, 0x06,0xA0,
+0x00,0x16, 0xF7,0x37, 0x28,0x00, 0xF4,0x82, 0x00,0x01, 0xF4,0xA3, 0x28,0x00, 0x94,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93, 0xFF,0xFC, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xE0,0xBC, 0x26,0x94, 0x00,0x48, 0xF7,0x04, 0x42,0x80, 0xE0,0x00,
+0xE0,0x9C, 0xF6,0x06, 0x42,0x82, 0x86,0x96, 0xFE,0xF4, 0xE0,0x00, 0xE2,0x94, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x42,0x84, 0xF6,0x06, 0x42,0x84, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0xEA,0xA4, 0xF7,0x33, 0x28,0x00, 0x83,0x16, 0xFF,0x4C, 0x75,0x15,
+0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x93,0x16, 0xFF,0x1C, 0x07,0x18, 0x00,0x36, 0xF4,0x82,
+0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0xF0,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB8, 0x76,0xB5,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x04,0x18, 0x00,0x02, 0x06,0x20, 0x00,0x02, 0x23,0x14,
+0x00,0x46, 0x93,0x16, 0xFF,0x14, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x95,
+0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFF,0x0C, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
+0xFF,0xE5, 0x93,0x16, 0xFF,0x04, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96,
+0xFE,0xFC, 0x23,0x00, 0x00,0x07, 0x93,0x16, 0xFE,0xF4, 0x84,0x96, 0xFF,0x1C, 0x83,0x16,
+0xFF,0x14, 0x04,0xA4, 0x00,0x0A, 0x94,0x96, 0xFE,0x7C, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0xF6,0x84, 0x4F,0x58, 0x84,0x96, 0xFF,0x54, 0x87,0x1A,
+0x00,0x00, 0xC6,0xA4, 0x6A,0x00, 0x74,0x34, 0xFF,0xFA, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16, 0xFF,0xBC, 0x23,0x14,
+0x00,0x42, 0x93,0x16, 0xFF,0x14, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0x30,
+0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30,
+0x00,0x02, 0x87,0x16, 0xFF,0xC0, 0x24,0x94, 0x00,0x3E, 0x94,0x96, 0xFF,0x14, 0x76,0xA5,
+0x00,0x1E, 0x83,0x16, 0xFF,0x0C, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x16,
+0xFF,0xC4, 0x24,0x94, 0x00,0x3A, 0x94,0x96, 0xFF,0x14, 0x76,0xA5, 0x00,0x1E, 0x83,0x16,
+0xFF,0x04, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33,
+0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0x30, 0x00,0x02, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0x84,0x96, 0xFE,0xFC, 0x06,0x30,
+0x00,0x02, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x83,0x16,
+0xFE,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x1A, 0x00,0x07, 0xEE,0x00, 0xE2,0x94, 0xF6,0x82,
+0x00,0x08, 0x84,0x96, 0xFE,0x7C, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x0E, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xF7,0x02, 0x00,0xFF, 0xC6,0xB4, 0x74,0x00, 0x47,0x21, 0x00,0x00, 0xC0,0x36,
+0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xE0,0x88, 0x04,0xA4,
+0x00,0x02, 0x94,0x96, 0xFE,0x7C, 0x03,0x18, 0x00,0x01, 0xE0,0x00, 0xE2,0x30, 0x93,0x16,
+0xFE,0xF4, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x38, 0xF6,0xBB,
+0x28,0x00, 0x93,0x13, 0xFF,0xFC, 0x84,0x96, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x23,0x14,
+0x00,0x78, 0x93,0x16, 0xFE,0xBC, 0x84,0x96, 0x00,0x00, 0x23,0x14, 0x00,0xA8, 0x86,0xA6,
+0x00,0x04, 0x87,0x26, 0x00,0x00, 0x93,0x16, 0xFE,0x9C, 0xC6,0xB4, 0x70,0x00, 0x96,0x96,
+0xFE,0xEC, 0xF7,0x02, 0x00,0x01, 0xC7,0x34, 0x74,0x00, 0x97,0x16, 0xFE,0xE4, 0x84,0x96,
+0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD4,0xB4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04, 0x4F,0x58, 0x00,0x00, 0x00,0x01, 0xC0,0x22,
+0x72,0x00, 0xE6,0x00, 0xEA,0xA1, 0x94,0x16, 0xFF,0x1C, 0x86,0xA2, 0x00,0x38, 0x77,0x21,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xF3,0x02, 0x00,0x00, 0x93,0x16, 0xFE,0xD4, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0x96,0x96, 0xFE,0xDC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
+0x00,0x01, 0x20,0x26, 0x00,0x0E, 0xEE,0x00, 0xE2,0xF0, 0xF3,0x02, 0x00,0x0F, 0x93,0x13,
+0xFF,0xFC, 0x83,0x16, 0xFE,0xEC, 0x00,0x00, 0x00,0x01, 0xC7,0x18, 0x48,0x00, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x27,0xE8, 0x97,0x93, 0xFF,0xFC, 0xC3,0xA0,
+0x00,0x00, 0x84,0x96, 0xFE,0xE4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00,
+0xE3,0x8D, 0x23,0x9C, 0x00,0x07, 0xC3,0x80, 0x3A,0x00, 0xC7,0x1C, 0x38,0x00, 0x83,0x16,
+0xFF,0x1C, 0xF4,0x82, 0x00,0xFF, 0xF6,0x04, 0x4F,0x58, 0xC7,0x18, 0x70,0x00, 0x07,0x38,
+0x00,0x26, 0x86,0xBA, 0x00,0x00, 0x97,0x16, 0xFE,0xC4, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xC6,0xB4, 0x4C,0x00, 0x76,0xB5,
+0x00,0x06, 0xC3,0x30, 0x68,0x00, 0x07,0x30, 0x00,0x40, 0xC0,0x1A, 0x72,0x00, 0xE6,0x00,
+0xE4,0x0D, 0x93,0x16, 0xFE,0xCC, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFE,0x74, 0x96,0x16,
+0xFE,0x6C, 0x96,0x96, 0xFE,0x68, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0x00, 0x97,0x93,
+0xFF,0xFC, 0x83,0x96, 0xFE,0x74, 0x86,0x16, 0xFE,0x6C, 0x86,0x96, 0xFE,0x68, 0x20,0x22,
+0x00,0x00, 0xE6,0x00, 0xE0,0x95, 0x00,0x00, 0x00,0x01, 0xF5,0x84, 0x4F,0x58, 0x84,0x96,
+0xFE,0xCC, 0x07,0x2C, 0x00,0x40, 0xC0,0x26, 0x72,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00,
+0x00,0x01, 0xA7,0x32, 0x68,0x02, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x86,0x16,
+0xFE,0xCC, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x02, 0xE6,0x00,
+0xE4,0x51, 0xC0,0x32, 0x5A,0x00, 0xC6,0x2C, 0x00,0x00, 0xC0,0x32, 0x5A,0x00, 0xE6,0x00,
+0xE6,0xE5, 0x25,0x14, 0x00,0x76, 0x83,0x16, 0xFF,0x1C, 0x84,0x96, 0xFE,0xBC, 0x06,0x18,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x83,0x16,
+0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x74, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x72, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x70, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6E, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6C, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x6A, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x25,0x14, 0x00,0x68, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
+0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x60, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
+0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
+0xFF,0xA0, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x14, 0x00,0x5E, 0x93,0x16,
+0xFE,0x5C, 0x75,0x99, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x74,0x15, 0x00,0x1E, 0x74,0x20,
+0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16, 0xFE,0xAC, 0x83,0x16,
+0xFE,0x5C, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8,
+0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xB4, 0x74,0x95,
+0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x87,0x1A,
+0x00,0x00, 0x74,0xA4, 0xFF,0xE5, 0x94,0x96, 0xFE,0xA4, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA4, 0x24,0x94,
+0x00,0x5A, 0x94,0x96, 0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x83,0x16, 0xFE,0xB4, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16, 0xFF,0xA8, 0x24,0x94, 0x00,0x56, 0x94,0x96,
+0xFE,0x5C, 0x76,0x25, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x47,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0xAC, 0x23,0x14, 0x00,0x52, 0x93,0x16, 0xFE,0x5C, 0x76,0x19, 0x00,0x1E, 0x84,0x96,
+0xFE,0xAC, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1A, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0xB0, 0x83,0x16, 0xFE,0xA4, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xE0,0x00, 0xEA,0x8C, 0xF7,0x37,
+0x28,0x00, 0x84,0x96, 0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x04,0xA4, 0x00,0x36, 0x94,0x96,
+0xFE,0x5C, 0x87,0x26, 0x00,0x00, 0x76,0xA5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFE,0xCC, 0x84,0x96,
+0xFF,0x1C, 0x06,0x18, 0x00,0x3A, 0x85,0xB2, 0x00,0x00, 0x07,0x24, 0x00,0x3A, 0x86,0xBA,
+0x00,0x00, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC5,0xAC, 0x67,0xC0, 0xC6,0xB4, 0x77,0xC0, 0x75,0xAD, 0xFF,0xF0, 0x76,0xB5,
+0xFF,0xF0, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x00, 0xE7,0x64, 0xF5,0x02, 0x00,0x02, 0xF5,0x02,
+0x00,0x01, 0x83,0x16, 0xFF,0x1C, 0x00,0x00, 0x00,0x01, 0x07,0x18, 0x00,0x36, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0x20,0x36, 0x00,0x02, 0xE6,0x00, 0xE7,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x2A,
+0x00,0x01, 0xE6,0x00, 0xEA,0x8D, 0x00,0x00, 0x00,0x01, 0x84,0x96, 0xFE,0x5C, 0x83,0x16,
+0xFF,0x1C, 0xF5,0x27, 0x28,0x00, 0x06,0x18, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x25,0x14, 0x00,0xA6, 0x84,0x96, 0xFE,0x9C, 0x83,0x16,
+0xFE,0xDC, 0x06,0x30, 0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA4, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA2, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0xA0, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9E, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9C, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x25,0x14, 0x00,0x9A, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32,
+0x00,0x00, 0x25,0x14, 0x00,0x98, 0x76,0x31, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B, 0x28,0x00, 0xC7,0x1C, 0x32,0x00, 0x97,0x13,
+0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x26,0x14, 0x00,0x90, 0x96,0x13, 0xFF,0xFC, 0x96,0x16,
+0xFE,0x6C, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xD0,0xDC, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
+0xFF,0x70, 0x86,0x16, 0xFE,0x6C, 0x84,0x96, 0xFE,0xCC, 0x23,0x94, 0x00,0x8E, 0x75,0x9D,
+0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18, 0xFF,0xE5, 0x93,0x16,
+0xFE,0x94, 0x74,0x15, 0x00,0x1E, 0x74,0x20, 0xFF,0xE5, 0x73,0x15, 0x00,0x1E, 0x73,0x18,
+0xFF,0xE5, 0x93,0x16, 0xFE,0x84, 0x83,0x16, 0xFE,0x94, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x05,0x24, 0x00,0x02, 0x06,0xA8, 0x00,0x02, 0x74,0x95, 0x00,0x1E, 0x74,0xA4,
+0xFF,0xE5, 0x94,0x96, 0xFE,0x8C, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x2B,
+0x28,0x00, 0x84,0x96, 0xFE,0xC4, 0x87,0x1E, 0x00,0x00, 0x75,0x25, 0x00,0x1E, 0xC7,0x38,
+0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0x74, 0x23,0x94, 0x00,0x8A, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x84,0x96,
+0xFE,0x8C, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37,
+0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x83,0x16, 0xFE,0x84, 0xC7,0x38,
+0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4, 0x00,0x02, 0x87,0x16,
+0xFF,0x78, 0x23,0x94, 0x00,0x86, 0x76,0x1D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x47,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E, 0x00,0x00, 0x06,0xB4,
+0x00,0x02, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x06,0xB4,
+0x00,0x02, 0x87,0x16, 0xFF,0x7C, 0x23,0x94, 0x00,0x82, 0x76,0x1D, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+0x00,0x00, 0x06,0xB4, 0x00,0x02, 0x84,0x96, 0xFE,0xC4, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x16, 0xFF,0x80, 0x06,0xB4, 0x00,0x02, 0xC7,0x38,
+0x37,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x26, 0x00,0x00, 0xF3,0x02,
+0x00,0xFF, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xE8, 0xC6,0xB8, 0x34,0x00, 0xF7,0x02,
+0x00,0x80, 0xC7,0x34, 0x74,0x00, 0x77,0x39, 0x00,0x10, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
+0x00,0x00, 0xE6,0x00, 0xEA,0x61, 0x27,0x00, 0x01,0x00, 0xC6,0xB4, 0x75,0x80, 0x84,0x96,
+0xFE,0xCC, 0x00,0x00, 0x00,0x01, 0x07,0x24, 0x00,0x38, 0xF6,0xBB, 0x28,0x00, 0x94,0x93,
+0xFF,0xFC, 0x83,0x16, 0xFF,0x24, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xD4,0x2C, 0x97,0x93, 0xFF,0xFC, 0x84,0x96, 0xFE,0xD4, 0x00,0x00,
+0x00,0x01, 0x04,0xA4, 0x00,0x01, 0xE0,0x00, 0xE3,0x3C, 0x94,0x96, 0xFE,0xD4, 0xF4,0x02,
+0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
+0x00,0x08, 0x86,0x96, 0x00,0x0C, 0xF5,0x02, 0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x84,0x16,
+0x00,0x10, 0xF4,0x84, 0xE0,0x00, 0x07,0x30, 0x00,0x02, 0x94,0xB2, 0x00,0x10, 0xF4,0x84,
+0xE0,0x04, 0x06,0xB4, 0x00,0x03, 0x94,0xB2, 0x00,0x14, 0xF4,0x84, 0xE0,0x1C, 0xC6,0xB4,
+0x54,0x00, 0x94,0xB2, 0x00,0x18, 0xF4,0x82, 0x00,0x05, 0xF4,0xB3, 0x28,0x00, 0xF4,0x82,
+0x00,0x01, 0xF4,0xBB, 0x28,0x00, 0x27,0x34, 0x00,0x08, 0x97,0x32, 0x00,0x04, 0x86,0x16,
+0x00,0x00, 0x07,0x2C, 0x00,0x03, 0xC7,0x38, 0x54,0x00, 0xC6,0xB8, 0x68,0x00, 0x96,0x93,
+0xFF,0xFC, 0xC6,0x30, 0x72,0x00, 0x96,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0xAC,
+0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38, 0x5A,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xC1,0x20, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0x83,0xBA, 0x00,0x00, 0x84,0x96, 0x00,0x00, 0x93,0x96, 0xFF,0xF0, 0xF3,0x84,
+0x6E,0x54, 0x87,0x3A, 0x00,0x04, 0x93,0x96, 0xFF,0xEC, 0x97,0x16, 0xFF,0xF4, 0x90,0x13,
+0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x07,0x24, 0x00,0x20, 0x97,0x13,
+0xFF,0xFC, 0x94,0x96, 0xFF,0xE4, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
+0xFF,0xFC, 0x84,0x96, 0xFF,0xE4, 0x83,0x96, 0x00,0x08, 0x87,0x26, 0x00,0x18, 0x85,0x16,
+0xFF,0xEC, 0xC0,0x3A, 0x3A,0x00, 0xEE,0x00, 0xEC,0x7C, 0xF5,0x82, 0x00,0x01, 0x87,0x26,
+0x00,0x18, 0x83,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x72,0x00, 0xE6,0x00,
+0xEC,0x7C, 0xC5,0x84, 0x00,0x00, 0x86,0xA6, 0x00,0x10, 0x87,0x16, 0xFF,0xF0, 0xF6,0x02,
+0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x1C, 0x04,0x24, 0x00,0x10, 0x86,0xA6,
+0x00,0x14, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x00,
+0xEC,0x20, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0xEC,0x2D, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0xA2, 0x00,0x00, 0x87,0x16,
+0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEC,0x68, 0xF6,0x02,
+0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x00, 0xEC,0x70, 0x20,0x32, 0x00,0x00, 0x86,0xA2,
+0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00,
+0xEC,0x71, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0xEC,0x81, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00,
+0xEC,0xAC, 0xF7,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0x9C, 0xF6,0x06, 0x42,0x9C, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF7,0x02, 0x00,0x01, 0x97,0x2A, 0x00,0x08, 0x83,0xA6,
+0x00,0x0C, 0x77,0x2C, 0xFF,0xE1, 0x93,0xAA, 0x00,0x0C, 0x97,0x2A, 0x00,0x1C, 0x83,0xA6,
+0x00,0x1C, 0xF7,0x04, 0x6E,0x50, 0x93,0xAA, 0x00,0x20, 0x83,0xBA, 0x1D,0xDC, 0xF6,0x82,
+0x00,0x00, 0x93,0xAA, 0x00,0x2C, 0x83,0x96, 0x00,0x0C, 0xC5,0xB4, 0x00,0x00, 0x93,0xAA,
+0x00,0x30, 0x83,0xBA, 0x00,0x10, 0xC6,0x34, 0x00,0x00, 0x93,0xAA, 0x00,0x24, 0x87,0x3A,
+0x00,0x14, 0x00,0x00, 0x00,0x01, 0x97,0x2A, 0x00,0x28, 0x20,0x36, 0x00,0x1F, 0xEE,0x00,
+0xED,0x1C, 0xC7,0x30, 0x50,0x00, 0x07,0x38, 0x00,0x34, 0x95,0xBA, 0x00,0x00, 0x06,0x30,
+0x00,0x04, 0xE0,0x00, 0xEC,0xFC, 0x06,0xB4, 0x00,0x01, 0x83,0x96, 0x00,0x10, 0x76,0xA5,
+0x00,0x1E, 0x93,0x93, 0xFF,0xFC, 0xF3,0x82, 0x00,0xB4, 0x93,0x93, 0xFF,0xFC, 0x95,0x13,
+0xFF,0xFC, 0x87,0x26, 0x00,0x20, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x14, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0x87,0x16,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x86,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x16,
+0xFF,0xF0, 0x87,0x3A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0xF6,0x02,
+0x1D,0xE0, 0x96,0x13, 0xFF,0xFC, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x96,0x13,
+0xFF,0xFC, 0xF6,0x04, 0x6E,0x50, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x26,0x14,
+0x00,0x10, 0x96,0x16, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x26,0xF8, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x84, 0x6E,0x50, 0xF6,0x02, 0x00,0x00, 0x87,0x36, 0x1D,0xD8, 0x96,0x16,
+0xFF,0xE4, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF6,0x86, 0x42,0xC0, 0xF7,0x37, 0x28,0x00, 0x86,0x16, 0xFF,0xEC, 0x00,0x00,
+0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xDB,0xB4, 0x97,0x93,
+0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00, 0x00,0x01, 0x86,0x16,
+0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xD5,0xA0, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00, 0xEE,0x4D, 0x00,0x00,
+0x00,0x01, 0xF6,0x02, 0x00,0x01, 0x96,0x16, 0xFF,0xE4, 0x84,0x16, 0xFF,0xE4, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x04, 0x86,0x16,
+0x00,0x00, 0x87,0x36, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xEE,0x99, 0x20,0x3A, 0x00,0x03, 0xE6,0x00, 0xEE,0xE9, 0xF4,0x02, 0x00,0x00, 0xE0,0x00,
+0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1F, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0xEF,0x0D, 0xF4,0x02, 0x00,0x00, 0x85,0x16, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+0xFF,0xFC, 0x85,0x16, 0x00,0x10, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x16,
+0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x96,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEB,0x60, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0xEF,0x0C, 0x00,0x00, 0x00,0x01, 0x77,0xB0, 0x00,0x1E, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0xEF,0x0D, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xED,0x74, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x18, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x18, 0xF4,0x82, 0x00,0x00, 0x86,0x96,
+0x00,0x00, 0xF6,0x04, 0x4A,0xA0, 0x23,0x94, 0x00,0x10, 0x84,0x36, 0x00,0x00, 0x96,0x16,
+0xFF,0xE4, 0xF7,0x04, 0x4A,0x9C, 0x94,0x16, 0xFF,0xF0, 0x85,0x36, 0x00,0x04, 0xC0,0x32,
+0x72,0x00, 0xEC,0x00, 0xF0,0x14, 0x95,0x16, 0xFF,0xF4, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
+0x60,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4,
+0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x42,0x00, 0xE6,0x00, 0xEF,0xA4, 0xC6,0x24, 0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x00, 0xEF,0xA8, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00, 0xEF,0xB5, 0x00,0x00, 0x00,0x01, 0xF5,0x82,
+0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x32,
+0x72,0x00, 0xE2,0x00, 0xEF,0xF0, 0xF5,0x02, 0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x00,
+0xEF,0xF8, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16, 0xFF,0xF4, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x00, 0xEF,0xF9, 0x20,0x2A, 0x00,0x00, 0xF5,0x02,
+0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x00, 0xF0,0x09, 0x20,0x2E, 0x00,0x00, 0xF5,0x82,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x00, 0xF0,0x18, 0x20,0x26, 0x00,0x00, 0xF4,0x82,
+0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x00, 0xF0,0x4D, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xE8, 0xE0,0x00, 0xF0,0xB0, 0x96,0x96, 0xFF,0xEC, 0x27,0x14, 0x00,0x1C, 0x97,0x13,
+0xFF,0xFC, 0x93,0x93, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x20,0x22, 0x00,0x00, 0xE6,0x00,
+0xF0,0xAD, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xE8, 0x96,0x96, 0xFF,0xEC, 0xF7,0x05,
+0x4A,0xA0, 0xE0,0x00, 0xF0,0xB4, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32,
+0x00,0x00, 0xE6,0x00, 0xF1,0x21, 0xF4,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xE8, 0xF6,0x06,
+0x42,0xC8, 0x76,0xB9, 0x00,0x02, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xA7,0x36,
+0x60,0x02, 0x83,0x16, 0x00,0x04, 0xC6,0xB4, 0x60,0x00, 0x76,0x35, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x05,0x34, 0x00,0x02, 0x75,0xA9, 0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38,
+0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x75,0xAC, 0xFF,0xE5, 0x83,0x16,
+0x00,0x08, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x97,0x1A, 0x00,0x00, 0x83,0x16,
+0x00,0x0C, 0x06,0xB4, 0x00,0x04, 0xE0,0x00, 0xF1,0x24, 0x96,0x9A, 0x00,0x00, 0xF4,0x02,
+0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0xB9,0x00, 0x00,0x00, 0xBA,0x00, 0x00,0x00,
+0xBB,0x00, 0x00,0x00, 0xBC,0x00, 0x00,0x00, 0xBD,0x00, 0x00,0x00, 0xBE,0x00, 0x00,0x00,
+0xBF,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x81,0x00, 0x00,0x00, 0x82,0x00, 0x00,0x00,
+0x83,0x00, 0x00,0x00, 0x84,0x00, 0x00,0x00, 0x85,0x00, 0x00,0x00, 0x86,0x00, 0x00,0x00,
+0x87,0x00, 0xB9,0xB9, 0xB9,0xBA, 0xB9,0xBB, 0xB9,0xBC, 0xB9,0xBD, 0xB9,0xBE, 0xB9,0xBF,
+0xB9,0x80, 0xB9,0x81, 0xB9,0x82, 0xB9,0x83, 0xB9,0x84, 0xB9,0x85, 0xB9,0x86, 0xB9,0x87,
+0xBA,0xB9, 0xBA,0xBA, 0xBA,0xBB, 0xBA,0xBC, 0xBA,0xBD, 0xBA,0xBE, 0xBA,0xBF, 0xBA,0x80,
+0xBA,0x81, 0xBA,0x82, 0xBA,0x83, 0xBA,0x84, 0xBA,0x85, 0xBA,0x86, 0xBA,0x87, 0xBB,0xB9,
+0xBB,0xBA, 0xBB,0xBB, 0xBB,0xBC, 0xBB,0xBD, 0xBB,0xBE, 0xBB,0xBF, 0xBB,0x80, 0xBB,0x81,
+0xBB,0x82, 0xBB,0x83, 0xBB,0x84, 0xBB,0x85, 0xBB,0x86, 0xBB,0x87, 0xBC,0xB9, 0xBC,0xBA,
+0xBC,0xBB, 0xBC,0xBC, 0xBC,0xBD, 0xBC,0xBE, 0xBC,0xBF, 0xBC,0x80, 0xBC,0x81, 0xBC,0x82,
+0xBC,0x83, 0xBC,0x84, 0xBC,0x85, 0xBC,0x86, 0xBC,0x87, 0xBD,0xB9, 0xBD,0xBA, 0xBD,0xBB,
+0xBD,0xBC, 0xBD,0xBD, 0xBD,0xBE, 0xBD,0xBF, 0xBD,0x80, 0xBD,0x81, 0xBD,0x82, 0xBD,0x83,
+0xBD,0x84, 0xBD,0x85, 0xBD,0x86, 0xBD,0x87, 0xBE,0xB9, 0xBE,0xBA, 0xBE,0xBB, 0xBE,0xBC,
+0xBE,0xBD, 0xBE,0xBE, 0xBE,0xBF, 0xBE,0x80, 0xBE,0x81, 0xBE,0x82, 0xBE,0x83, 0xBE,0x84,
+0xBE,0x85, 0xBE,0x86, 0xBE,0x87, 0xBF,0xB9, 0xBF,0xBA, 0xBF,0xBB, 0xBF,0xBC, 0xBF,0xBD,
+0xBF,0xBE, 0xBF,0xBF, 0xBF,0x80, 0xBF,0x81, 0xBF,0x82, 0xBF,0x83, 0xBF,0x84, 0xBF,0x85,
+0xBF,0x86, 0xBF,0x87, 0x80,0xB9, 0x80,0xBA, 0x80,0xBB, 0x80,0xBC, 0x80,0xBD, 0x80,0xBE,
+0x80,0xBF, 0x80,0x80, 0x80,0x81, 0x80,0x82, 0x80,0x83, 0x80,0x84, 0x80,0x85, 0x80,0x86,
+0x80,0x87, 0x81,0xB9, 0x81,0xBA, 0x81,0xBB, 0x81,0xBC, 0x81,0xBD, 0x81,0xBE, 0x81,0xBF,
+0x81,0x80, 0x81,0x81, 0x81,0x82, 0x81,0x83, 0x81,0x84, 0x81,0x85, 0x81,0x86, 0x81,0x87,
+0x82,0xB9, 0x82,0xBA, 0x82,0xBB, 0x82,0xBC, 0x82,0xBD, 0x82,0xBE, 0x82,0xBF, 0x82,0x80,
+0x82,0x81, 0x82,0x82, 0x82,0x83, 0x82,0x84, 0x82,0x85, 0x82,0x86, 0x82,0x87, 0x83,0xB9,
+0x83,0xBA, 0x83,0xBB, 0x83,0xBC, 0x83,0xBD, 0x83,0xBE, 0x83,0xBF, 0x83,0x80, 0x83,0x81,
+0x83,0x82, 0x83,0x83, 0x83,0x84, 0x83,0x85, 0x83,0x86, 0x83,0x87, 0x84,0xB9, 0x84,0xBA,
+0x84,0xBB, 0x84,0xBC, 0x84,0xBD, 0x84,0xBE, 0x84,0xBF, 0x84,0x80, 0x84,0x81, 0x84,0x82,
+0x84,0x83, 0x84,0x84, 0x84,0x85, 0x84,0x86, 0x84,0x87, 0x85,0xB9, 0x85,0xBA, 0x85,0xBB,
+0x85,0xBC, 0x85,0xBD, 0x85,0xBE, 0x85,0xBF, 0x85,0x80, 0x85,0x81, 0x85,0x82, 0x85,0x83,
+0x85,0x84, 0x85,0x85, 0x85,0x86, 0x85,0x87, 0x86,0xB9, 0x86,0xBA, 0x86,0xBB, 0x86,0xBC,
+0x86,0xBD, 0x86,0xBE, 0x86,0xBF, 0x86,0x80, 0x86,0x81, 0x86,0x82, 0x86,0x83, 0x86,0x84,
+0x86,0x85, 0x86,0x86, 0x86,0x87, 0x87,0xB9, 0x87,0xBA, 0x87,0xBB, 0x87,0xBC, 0x87,0xBD,
+0x87,0xBE, 0x87,0xBF, 0x87,0x80, 0x87,0x81, 0x87,0x82, 0x87,0x83, 0x87,0x84, 0x87,0x85,
+0x87,0x86, 0x87,0x87, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x18, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xF3,0x7D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0xF5,0xE0, 0xF7,0x33, 0x28,0x00, 0xF3,0x84, 0x6F,0x30, 0x90,0x13,
+0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xEC, 0xF7,0x02, 0x00,0x00, 0x97,0x1E,
+0x00,0x08, 0x83,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0x1E, 0x00,0x0C, 0x83,0x16,
+0x00,0x08, 0x04,0x9C, 0x00,0x22, 0x93,0x1E, 0x00,0x1C, 0x83,0x16, 0x00,0x0C, 0x93,0x96,
+0xFF,0xF4, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x06,0x18,
+0x00,0x02, 0x75,0xB1, 0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0x06,0x9C, 0x00,0x20, 0xF7,0x37, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x96,0x96,
+0xFF,0xE4, 0x75,0x35, 0x00,0x1E, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x04,0x9C, 0x00,0x24, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x04,0x9C, 0x00,0x26, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x04,0x9C, 0x00,0x28, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x04,0x9C, 0x00,0x2A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x04,0x9C, 0x00,0x2C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x04,0x9C, 0x00,0x2E, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x04,0x9C, 0x00,0x30, 0x76,0x31,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27,
+0x28,0x00, 0x87,0x1E, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xC7,0x38, 0x57,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x20,0x3A, 0x00,0x08, 0xEE,0x00, 0xF5,0x98, 0xF3,0x06, 0x14,0xD8, 0x83,0x16,
+0xFF,0xE4, 0x87,0x1E, 0x00,0x20, 0x76,0x99, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x25,0xB8, 0x00,0x01, 0xC4,0xAC, 0x58,0x00, 0x04,0x24,
+0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xEC,0x00, 0xF5,0x95, 0xF5,0x02, 0x00,0x00, 0x83,0x16,
+0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0x06,0x18, 0x00,0x02, 0xA7,0x32, 0x58,0x02, 0xC6,0xB0,
+0x58,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xE8, 0xC6,0xB0, 0x40,0x00, 0x77,0xB8, 0x00,0x18, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x00,
+0xF5,0x7D, 0xF7,0x37, 0x68,0x00, 0xF5,0x02, 0xFF,0xFF, 0xC7,0x30, 0x48,0x00, 0xF5,0x3B,
+0x68,0x00, 0x24,0xA4, 0x00,0x02, 0x24,0x20, 0x00,0x02, 0xE0,0x00, 0xF5,0x34, 0x25,0xAC,
+0x00,0x01, 0xF3,0x06, 0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x34, 0x93,0x13,
+0xFF,0xFC, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x99, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0xF7,0x04,
+0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xF6,0x39, 0xF6,0x06,
+0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
+0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00,
+0xF7,0x48, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00, 0x00,0x01, 0x95,0x16,
+0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
+0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00, 0xF6,0x99, 0x96,0x96,
+0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x85,0x16,
+0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28, 0x72,0x00, 0x97,0x13,
+0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0xFF,0xF4, 0xF7,0x02,
+0x00,0x02, 0x97,0x2A, 0x00,0x08, 0x85,0x96, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0xAA,
+0x00,0x0C, 0x85,0x96, 0x00,0x0C, 0x00,0x00, 0x00,0x01, 0x95,0xAA, 0x00,0x1C, 0xF5,0x06,
+0x14,0xD8, 0x95,0x13, 0xFF,0xFC, 0xF5,0x82, 0x00,0x20, 0x95,0x93, 0xFF,0xFC, 0x85,0x16,
+0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16,
+0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38, 0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96,
+0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0x00,0x04, 0x87,0x16, 0x00,0x08, 0xF6,0x02,
+0xFF,0xFC, 0x06,0xA8, 0x00,0x03, 0xC6,0xB4, 0x64,0x00, 0x07,0x38, 0x00,0x03, 0xC7,0x38,
+0x64,0x00, 0xC7,0x34, 0x70,0x00, 0x97,0x13, 0xFF,0xFC, 0xC5,0xAC, 0x6A,0x00, 0x95,0x93,
+0xFF,0xFC, 0xF7,0x02, 0x00,0x03, 0xC5,0x28, 0x74,0x00, 0xF7,0x02, 0x00,0x04, 0xC7,0x38,
+0x52,0x00, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x14,0xD8, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x10, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xF8,0x0D, 0xF6,0x06, 0x42,0x96, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0xF9,0x20, 0xF7,0x33, 0x28,0x00, 0xF5,0x04, 0x6F,0x30, 0x00,0x00,
+0x00,0x01, 0x95,0x16, 0xFF,0xF4, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
+0xFF,0xFC, 0x85,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0xF6,0x02,
+0x00,0x00, 0x86,0xAA, 0x00,0x00, 0x77,0x29, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB5, 0xFF,0xF0, 0xF7,0x02, 0x00,0x01, 0xC0,0x36, 0x74,0x00, 0xE6,0x00,
+0xF8,0x6D, 0x96,0x96, 0xFF,0xEC, 0xC6,0x38, 0x00,0x00, 0x96,0x13, 0xFF,0xFC, 0x85,0x96,
+0xFF,0xEC, 0x85,0x16, 0xFF,0xF4, 0x47,0x2C, 0xFF,0xFE, 0x07,0x38, 0x00,0x02, 0xC7,0x28,
+0x72,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x16,
+0xFF,0xF4, 0xF5,0x82, 0x00,0x06, 0xF5,0xAB, 0x28,0x00, 0x85,0x96, 0x00,0x08, 0x07,0x28,
+0x00,0x02, 0x95,0xAA, 0x00,0x04, 0x05,0x14, 0x00,0x0E, 0x85,0x2A, 0x00,0x00, 0x77,0xA9,
+0x00,0x1E, 0x77,0xBC, 0xFF,0xE5, 0xC5,0x28, 0x7F,0xC0, 0x75,0x29, 0xFF,0xF0, 0xF5,0x3B,
+0x28,0x00, 0xF5,0x86, 0x14,0xD8, 0x95,0x93, 0xFF,0xFC, 0xF5,0x02, 0x00,0x08, 0x95,0x13,
+0xFF,0xFC, 0x85,0x96, 0x00,0x00, 0x85,0x16, 0xFF,0xEC, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0xC7,0x38,
+0x50,0x00, 0x97,0x13, 0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x10, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04,
+0x75,0xEC, 0x83,0x96, 0x00,0x04, 0x20,0x3A, 0x00,0x00, 0xE6,0x00, 0xFA,0x64, 0xF6,0x06,
+0x42,0x96, 0xF5,0x04, 0x6F,0x30, 0x90,0x13, 0xFF,0xFC, 0x27,0x28, 0x00,0x02, 0x97,0x13,
+0xFF,0xFC, 0x83,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0xF4, 0x95,0x16, 0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93,
+0xFF,0xFC, 0x85,0x16, 0xFF,0xF0, 0xF3,0x02, 0x00,0x07, 0x83,0x96, 0xFF,0xF4, 0xF3,0x2B,
+0x28,0x00, 0x07,0x28, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x3B, 0x28,0x00, 0x87,0x1E,
+0x00,0x00, 0x76,0x9D, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x05,0x9C, 0x00,0x02, 0x76,0x2D,
+0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0x74,0x9D, 0x00,0x1E, 0x74,0xA4, 0xFF,0xE5, 0x04,0x1C,
+0x00,0x06, 0x83,0x16, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0x06,0xA8,
+0x00,0x04, 0xF7,0x37, 0x28,0x00, 0x87,0x2E, 0x00,0x00, 0x06,0xA8, 0x00,0x06, 0x75,0xA1,
+0x00,0x1E, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x1E,
+0x00,0x04, 0x75,0xAC, 0xFF,0xE5, 0x06,0xA8, 0x00,0x08, 0x76,0x19, 0x00,0x1E, 0xC7,0x38,
+0x4F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0x87,0x22, 0x00,0x00, 0x06,0xA8,
+0x00,0x0A, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x37, 0x28,0x00, 0xF3,0x06,
+0x14,0xD8, 0x93,0x13, 0xFF,0xFC, 0xF3,0x02, 0x00,0x0C, 0x93,0x13, 0xFF,0xFC, 0x83,0x16,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x1A, 0x00,0x00, 0x76,0x30, 0xFF,0xE5, 0xC7,0x38,
+0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xF7,0x5C, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00, 0xFA,0x84, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xF4,0x02,
+0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xF7,0x33,
+0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x48, 0xF7,0x04, 0x75,0xEC, 0x85,0x96, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x00,
+0xFD,0x98, 0xF6,0x06, 0x42,0x96, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0x24,0x14, 0x00,0x1E, 0x06,0x2C, 0x00,0x02, 0x75,0x31,
+0x00,0x1E, 0x24,0x94, 0x00,0x20, 0x75,0x28, 0xFF,0xE5, 0xF3,0x84, 0x6E,0x50, 0xC7,0x38,
+0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x32, 0x00,0x00, 0x93,0x96,
+0xFF,0xC4, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x1C, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x1A, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x18, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x16, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x14, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x24,0x14,
+0x00,0x12, 0x06,0x30, 0x00,0x02, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x06,0x30,
+0x00,0x02, 0x87,0x32, 0x00,0x00, 0x24,0x14, 0x00,0x10, 0x76,0x31, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x23, 0x28,0x00, 0x90,0x13,
+0xFF,0xFC, 0x27,0x1C, 0x00,0x02, 0x97,0x13, 0xFF,0xFC, 0x94,0x93, 0xFF,0xFC, 0x95,0x96,
+0xFF,0xBC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xCD,0xB8, 0x97,0x93, 0xFF,0xFC, 0x85,0x96,
+0xFF,0xBC, 0x23,0x14, 0x00,0x36, 0x24,0x94, 0x00,0x38, 0x73,0xA5, 0x00,0x1E, 0x73,0x9C,
+0xFF,0xE5, 0xF4,0x04, 0x42,0xC0, 0xF6,0x86, 0x42,0xC0, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0x87,0x2E, 0x00,0x00, 0x76,0x2D, 0x00,0x1E, 0x76,0x30, 0xFF,0xE5, 0xC4,0x20,
+0x6F,0xC0, 0x74,0x20, 0xFF,0xF0, 0x05,0xAC, 0x00,0x02, 0x75,0x2D, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0xC7,0x38, 0x67,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x27, 0x28,0x00, 0x87,0x2E,
+0x00,0x00, 0xF6,0x04, 0x6E,0x50, 0xC7,0x38, 0x57,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x23,0x14, 0x00,0x34, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x23,0x14, 0x00,0x32, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x23,0x14, 0x00,0x30, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x23,0x14, 0x00,0x2E, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x23,0x14, 0x00,0x2C, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x23,0x14, 0x00,0x2A, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x76,0xAD,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x05,0xAC, 0x00,0x02, 0x87,0x2E, 0x00,0x00, 0x23,0x14, 0x00,0x28, 0x75,0xAD,
+0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC7,0x38, 0x5F,0xC0, 0x77,0x38, 0xFF,0xF0, 0xF7,0x1B,
+0x28,0x00, 0x87,0x16, 0xFF,0xC8, 0xF6,0x82, 0x00,0x03, 0xC7,0x38, 0x3F,0xC0, 0x96,0xB2,
+0x00,0x08, 0x06,0xB0, 0x1D,0xD8, 0xF4,0x37, 0x28,0x00, 0xF3,0x86, 0x14,0xD8, 0x93,0x93,
+0xFF,0xFC, 0xF3,0x82, 0x1D,0xE0, 0x93,0x93, 0xFF,0xFC, 0x96,0x13, 0xFF,0xFC, 0x77,0x39,
+0xFF,0xF0, 0x97,0x13, 0xFF,0xFC, 0x83,0x96, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xEA,0xB8, 0x97,0x93, 0xFF,0xFC, 0xE0,0x00,
+0xFD,0xB8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0x94, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xF4,0x02, 0x00,0x00, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x86,0x16, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x32, 0x00,0x00, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A,
+0x00,0x06, 0xE6,0x00, 0xFE,0x21, 0xF5,0x82, 0x00,0x1E, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06,
+0x42,0xA8, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39,
+0xFF,0xF0, 0x07,0x38, 0x00,0x01, 0xE0,0x00, 0xFE,0x34, 0xF7,0x33, 0x28,0x00, 0xF6,0x05,
+0x6F,0x34, 0x95,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x04, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x16,
+0x00,0x00, 0x85,0x96, 0x00,0x04, 0x87,0x32, 0x00,0x00, 0x76,0xB1, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x20,0x3A, 0x00,0x07, 0xE6,0x00,
+0xFE,0x9D, 0xF4,0x02, 0x00,0x00, 0xF7,0x04, 0x42,0xA8, 0xF6,0x06, 0x42,0xAA, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xE0,0x00, 0xFF,0x1C, 0xF7,0x33, 0x28,0x00, 0x07,0x30, 0x00,0x02, 0x86,0xBA,
+0x00,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5,
+0xFF,0xF0, 0x20,0x36, 0x00,0x01, 0xE6,0x00, 0xFE,0xD5, 0xF6,0x05, 0x6F,0x34, 0x20,0x36,
+0x00,0x02, 0xE6,0x00, 0xFE,0xE5, 0xF5,0x02, 0x00,0x20, 0xE0,0x00, 0xFE,0xFC, 0xF6,0x06,
+0x42,0xAC, 0x20,0x2E, 0x00,0x0C, 0xE6,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x00, 0xF5,0x02,
+0x00,0x1F, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0xFF,0x1C, 0xF4,0x02, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x86,0x96, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x04, 0xF6,0x02, 0x00,0x00, 0x07,0x38, 0x00,0x08, 0x97,0x36, 0x00,0x04, 0x87,0x36,
+0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xEC,0x00, 0xFF,0x7D, 0xF6,0x85,
+0x6F,0x34, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x03, 0xEE,0x00,
+0xFF,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x00,
+0xFF,0xBD, 0xF6,0x06, 0x42,0xAE, 0xF7,0x04, 0x6F,0x34, 0x00,0x00, 0x00,0x01, 0x87,0x3A,
+0x00,0x08, 0xF6,0x82, 0xFF,0xEC, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x00,0x00,
+0x00,0x01, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x00, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x42,0xAC, 0x76,0xB1,
+0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x07,0x38,
+0x00,0x01, 0xF7,0x33, 0x28,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x17, 0x00,0x00,
+0x00,0x1A, 0x00,0x00, 0x00,0x1D, 0x00,0x00, 0x00,0x18, 0x00,0x00, 0x00,0x00, 0x56,0x65,
+0x72,0x73, 0x69,0x6F, 0x6E,0x53, 0x74,0x72, 0x69,0x6E, 0x67,0x3A, 0x20,0x6D, 0x63,0x70,
+0x2D,0x6C, 0x34,0x76, 0x33,0x20, 0x33,0x2E, 0x30,0x38, 0x63,0x20, 0x44,0x65, 0x63,0x20,
+0x31,0x31, 0x20,0x31, 0x39,0x39, 0x36,0x20, 0x31,0x33, 0x3A,0x30, 0x36,0x3A, 0x31,0x36,
+0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0xE0,0x0C, 0xFF,0x02,
+0x00,0x00, 0x97,0x02, 0xFF,0x84, 0xF7,0x06, 0x0C,0x3E, 0xCF,0xFC, 0x75,0x80, 0xF6,0x02,
+0x00,0x02, 0x96,0x02, 0xFF,0x8C, 0x90,0x02, 0xFF,0x88, 0xF7,0x04, 0xE0,0x20, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x00,0x74, 0xF6,0x82, 0x00,0x00, 0xF6,0x82,
+0x00,0x03, 0x96,0x82, 0xFF,0x98, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x0C, 0xF5,0x02, 0x14,0x94, 0xF5,0x05, 0x7B,0x00, 0xF5,0x0E,
+0xF0,0x14, 0xF5,0x05, 0x7B,0x08, 0xF7,0x06, 0xE0,0x00, 0xF6,0x86, 0x7B,0x68, 0xC7,0x38,
+0x6A,0x00, 0xF7,0x05, 0x7A,0xF0, 0xF5,0x02, 0x00,0x4C, 0xF6,0x82, 0x00,0x00, 0x20,0x36,
+0x00,0x02, 0xEE,0x01, 0x01,0x24, 0xF5,0x05, 0x7A,0xF8, 0xC5,0xB4, 0x00,0x00, 0xC6,0x34,
+0x00,0x00, 0xF7,0x06, 0xE0,0x30, 0xC7,0x2C, 0x70,0x00, 0xF5,0x06, 0x6F,0x44, 0xB7,0x32,
+0x50,0x02, 0x90,0x13, 0xFF,0xFC, 0x97,0x13, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
+0xFF,0xF0, 0x96,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93,
+0xFF,0xFC, 0x85,0x96, 0xFF,0xF4, 0x86,0x16, 0xFF,0xF0, 0x86,0x96, 0xFF,0xEC, 0x05,0xAC,
+0x14,0x94, 0x06,0xB4, 0x00,0x01, 0x20,0x36, 0x00,0x02, 0xEE,0x01, 0x00,0xD5, 0x06,0x30,
+0x00,0x04, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x6F,0x58, 0xF0,0x05, 0x6F,0x54, 0xF0,0x05,
+0x6F,0x50, 0xF0,0x05, 0x2D,0x40, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x29,0x58, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02,
+0x00,0x03, 0xF7,0x05, 0xE0,0x08, 0xF7,0x04, 0x7A,0xD8, 0xF6,0x02, 0x00,0x01, 0x96,0x02,
+0xFF,0x94, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x01,0x91, 0xF7,0x06, 0x7A,0xE8, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x03,0xDC, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7A,0xE8, 0xF6,0x02,
+0x00,0x05, 0xF6,0x3B, 0x28,0x00, 0xF7,0x06, 0x7A,0xE0, 0x86,0x82, 0xFF,0x44, 0xF6,0x02,
+0x00,0x03, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x01,0xC9, 0xF6,0x3B, 0x28,0x00, 0xF7,0x04,
+0x6F,0x64, 0x86,0x82, 0xFF,0x44, 0x07,0x38, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
+0x01,0xB0, 0xF7,0x05, 0x6F,0x64, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x34, 0x97,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x00,0x8C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x44,0x28, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0xF0, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x0C,0x60, 0x97,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x04,0x08, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x00,0x20, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x0B,0xD8, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1D,0x68, 0x97,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0x50, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x5F,0x68, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x6D,0xEC, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x21,0xD0, 0x97,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x22,0x2C, 0x97,0x93, 0xFF,0xFC, 0x90,0x02,
+0xFF,0x94, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x0B,0xFC, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02,
+0x00,0x00, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x08, 0xF6,0x02, 0x00,0x00, 0xC5,0xB0, 0x00,0x00, 0x20,0x32, 0x00,0x02, 0xEE,0x01,
+0x03,0x08, 0xF5,0x06, 0x6F,0x44, 0xA6,0xAE, 0x50,0x02, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x01, 0xE6,0x01, 0x02,0xFC, 0xF5,0x02,
+0x00,0x02, 0x95,0x13, 0xFF,0xFC, 0x96,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xF4, 0x96,0x16,
+0xFF,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x03,0x1C, 0x97,0x93, 0xFF,0xFC, 0x86,0x16,
+0xFF,0xF0, 0x85,0x96, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x05,0xAC, 0x00,0x04, 0xE0,0x01,
+0x02,0xAC, 0x06,0x30, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x87,0x16, 0x00,0x00, 0xF6,0x02, 0x00,0x00, 0xF6,0x82, 0x00,0x08, 0x96,0x3A,
+0x00,0x08, 0x96,0x3A, 0x00,0x0C, 0x96,0x3A, 0x09,0xD8, 0x96,0x3A, 0x09,0xDC, 0x96,0x3A,
+0x0E,0xF4, 0x96,0x3A, 0x0E,0xF8, 0x96,0xBA, 0x14,0x20, 0x96,0x3A, 0x14,0x24, 0x90,0xBA,
+0x14,0x8C, 0x86,0x96, 0x00,0x04, 0x90,0xBA, 0x14,0x90, 0x96,0xBA, 0x00,0x00, 0x96,0x3A,
+0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+0x00,0x00, 0x87,0x16, 0x00,0x08, 0x86,0x16, 0x00,0x04, 0x77,0x38, 0xFF,0xFF, 0xC5,0x30,
+0x70,0x00, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x03,0xC9, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
+0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE4,0x01,
+0x03,0xA0, 0x05,0xAC, 0x00,0x02, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x02, 0x00,0x01, 0xE0,0x01, 0x03,0xE8, 0xF7,0x05, 0x7A,0xD8, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02,
+0x00,0x0A, 0xF5,0x05, 0x71,0xCC, 0xF0,0x05, 0x71,0xD4, 0xF0,0x05, 0x71,0xD0, 0xF0,0x05,
+0x71,0xC4, 0xF5,0x02, 0x00,0x01, 0xF6,0x82, 0x00,0x00, 0x20,0x36, 0x00,0x0A, 0xEC,0x01,
+0x04,0x64, 0xF5,0x05, 0x71,0xC8, 0xF5,0x8A, 0x1E,0x00, 0xF6,0x06, 0x71,0xC4, 0x47,0x2C,
+0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30, 0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04,
+0x71,0xCC, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x04,0x41, 0x05,0xAC,
+0x21,0x4C, 0xF0,0x05, 0x71,0x98, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
+0x7B,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x06, 0x05,0xD4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x6F,0x68, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0B,0xA0, 0x95,0x13,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x05, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x70,0x80, 0x95,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+0x0B,0x70, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x06, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+0x70,0x80, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x06, 0x05,0x58, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x0A, 0x95,0x13,
+0xFF,0xFC, 0xF5,0x06, 0x71,0x0C, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+0x71,0xC4, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0x7D, 0xF6,0x86,
+0x71,0xC4, 0xE0,0x01, 0x05,0x94, 0xF7,0x02, 0x00,0x00, 0xF7,0x04, 0x71,0xD0, 0x00,0x00,
+0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x05,0xAC, 0xF7,0x05, 0x7B,0x10, 0xF6,0x06,
+0x71,0x0C, 0xE0,0x01, 0x05,0xC0, 0xF6,0x05, 0x7B,0x18, 0xF6,0x06, 0x6F,0x68, 0xF6,0x05,
+0x7B,0x18, 0x97,0x02, 0xFF,0x48, 0x07,0x38, 0x21,0x28, 0x97,0x02, 0xFF,0x4C, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x10, 0x86,0x82,
+0xFF,0x48, 0xF4,0x86, 0x6F,0x68, 0xF4,0x85, 0x7B,0x18, 0xF5,0x04, 0x7B,0x10, 0x26,0xB4,
+0x00,0x02, 0x85,0xB6, 0x00,0x00, 0x87,0x2A, 0x00,0x00, 0x76,0x29, 0x00,0x1E, 0x76,0x30,
+0xFF,0xE5, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC5,0xAC, 0x6F,0xC0, 0xC7,0x38,
+0x67,0xC0, 0x77,0x39, 0xFF,0xF0, 0x77,0xB8, 0x00,0x10, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x06,0x45, 0x75,0xAC, 0xFF,0xF0, 0xF7,0x04, 0x71,0xAC, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x71,0xAC, 0xF7,0x04, 0x71,0xAC, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
+0x00,0x01, 0x77,0x2C, 0xFF,0xF8, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x06,0x71, 0x76,0xA9,
+0x00,0x1E, 0xF7,0x04, 0x71,0xA8, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x71,0xA8, 0xF7,0x04, 0x71,0xA8, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A,
+0x00,0x00, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38,
+0x00,0x04, 0x20,0x3A, 0x00,0x03, 0xE2,0x01, 0x08,0xA4, 0x00,0x00, 0x00,0x01, 0x77,0x39,
+0x00,0x02, 0xF6,0x86, 0x06,0xA4, 0xA6,0xB6, 0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34,
+0x00,0x00, 0x00,0x01, 0x06,0xB4, 0x00,0x01, 0x07,0x7C, 0x00,0x01, 0x07,0xEC, 0x00,0x01,
+0x08,0x44, 0x87,0x2A, 0x00,0x04, 0xC4,0x84, 0x00,0x00, 0xC0,0x3A, 0x4A,0x00, 0xE6,0x01,
+0x06,0xD8, 0x00,0x00, 0x00,0x01, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38,
+0x52,0x00, 0x97,0x2A, 0x00,0x04, 0x87,0x2A, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x21,0x00, 0xEE,0x01, 0x07,0x3C, 0xF6,0x02, 0x00,0x00, 0x86,0xAA, 0x00,0x04, 0x87,0x02,
+0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x28, 0xC0,0x36,
+0x72,0x00, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x01, 0x07,0x3C, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x01, 0x07,0x3D, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E,
+0xFF,0xE1, 0xE6,0x01, 0x07,0x44, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x01, 0x08,0x88, 0x00,0x00, 0x00,0x01, 0x87,0x2A, 0x00,0x18, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xEE,0x01, 0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x71,0xA4, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xA4, 0xF7,0x04,
+0x71,0xA4, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0x87,0x2A, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x21,0x00, 0xEE,0x01, 0x07,0xE0, 0xF6,0x02, 0x00,0x00, 0x86,0xAA,
+0x00,0x04, 0x87,0x02, 0xFF,0x48, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38,
+0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
+0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE0, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
+0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x07,0xE1, 0x00,0x00, 0x00,0x01, 0x77,0xFC,
+0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x32, 0x00,0x00, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
+0x00,0x01, 0xC7,0x38, 0x52,0x00, 0x27,0x38, 0x00,0x04, 0x20,0x3A, 0x00,0x08, 0xE6,0x01,
+0x08,0x38, 0xF6,0x82, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x08,0x38, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x08,0x39, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x08,0x80, 0x20,0x36, 0x00,0x00, 0xF6,0x82, 0x00,0x01, 0xE0,0x01, 0x08,0x80, 0x20,0x36,
+0x00,0x00, 0xF7,0x02, 0x00,0x00, 0x77,0xFC, 0x00,0x1D, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x08,0x78, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x17, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x08,0x79, 0x00,0x00, 0x00,0x01, 0x77,0xFC, 0x00,0x16, 0x70,0x3E, 0xFF,0xE1, 0xE6,0x01,
+0x08,0x80, 0x20,0x3A, 0x00,0x00, 0xF7,0x02, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x08,0xC1, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xA0, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x71,0xA0, 0xF7,0x04, 0x71,0xA0, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02,
+0x00,0x01, 0xF7,0x04, 0x71,0x9C, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x71,0x9C, 0xF7,0x04, 0x71,0x9C, 0xE0,0x01, 0x08,0xC4, 0xF7,0x02, 0x00,0x01, 0xF7,0x02,
+0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x68, 0x00,0x00, 0x00,0x01, 0xF6,0x84,
+0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x76,0xB5, 0x00,0x1E, 0x76,0xB4,
+0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x39, 0xFF,0xF0, 0x27,0x38, 0x00,0x04, 0x20,0x3A,
+0x00,0x03, 0xE2,0x01, 0x0B,0x50, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x09,0x0C, 0xA6,0xB6,
+0x70,0x02, 0x00,0x00, 0x00,0x01, 0xC1,0x34, 0x00,0x00, 0x00,0x01, 0x09,0x1C, 0x00,0x01,
+0x0A,0xE0, 0x00,0x01, 0x0A,0xAC, 0x00,0x01, 0x0B,0x14, 0xF7,0x04, 0x71,0xD0, 0xF6,0x04,
+0x71,0xCC, 0x06,0xB8, 0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0x38, 0xC7,0x34,
+0x00,0x00, 0xF7,0x02, 0x00,0x00, 0xF5,0x84, 0x71,0xD4, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x09,0x85, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x71,0xB0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x71,0xB0, 0xF7,0x04, 0x71,0xB0, 0xF7,0x04, 0x71,0xB4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x71,0xB4, 0xF7,0x04, 0x71,0xB4, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
+0x00,0x01, 0xF4,0x84, 0x71,0xC8, 0xF6,0x85, 0x71,0xD0, 0x94,0x96, 0xFF,0xF4, 0xF4,0x84,
+0x7B,0x10, 0xC0,0x36, 0x62,0x00, 0xE6,0x01, 0x09,0xA4, 0x94,0x96, 0xFF,0xEC, 0xF0,0x05,
+0x71,0xD0, 0xF7,0x04, 0x71,0xD0, 0xF0,0x05, 0x71,0xC8, 0x84,0x96, 0xFF,0xEC, 0xC0,0x3A,
+0x5A,0x00, 0x47,0x0C, 0x00,0x01, 0xF7,0x05, 0x71,0xC4, 0x87,0x26, 0x00,0x08, 0x00,0x00,
+0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x09,0xE1, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x71,0x98, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0x98, 0x84,0x96,
+0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x0A,0x71, 0x00,0x00,
+0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0xF6,0x02,
+0x00,0x09, 0x20,0x32, 0x00,0x14, 0xE6,0x01, 0x0A,0x4D, 0x27,0x00, 0x00,0x0C, 0x20,0x3A,
+0x00,0x01, 0xE2,0x01, 0x0A,0x4D, 0xF7,0x06, 0x2D,0xCC, 0xF6,0x84, 0x2E,0xCC, 0x00,0x00,
+0x00,0x01, 0x75,0xB5, 0x00,0x02, 0xB6,0x2E, 0x70,0x02, 0x06,0xB4, 0x00,0x01, 0xF6,0x85,
+0x2E,0xCC, 0x86,0x02, 0xFF,0x34, 0xF7,0x06, 0x2E,0x4C, 0x20,0x36, 0x00,0x1F, 0xE2,0x01,
+0x0A,0x4D, 0xB6,0x2E, 0x70,0x02, 0xF0,0x05, 0x2E,0xCC, 0xF7,0x04, 0x2D,0x68, 0x00,0x00,
+0x00,0x01, 0x87,0x3A, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x3A, 0x00,0x28, 0x00,0x00,
+0x00,0x01, 0x07,0x88, 0x00,0x08, 0xC1,0x38, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0xF7,0x04,
+0x71,0xBC, 0x84,0x96, 0xFF,0xEC, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xBC, 0xF7,0x04,
+0x71,0xBC, 0x86,0xA6, 0x00,0x04, 0x84,0x96, 0xFF,0xF4, 0xF7,0x04, 0x71,0xB8, 0x20,0x26,
+0x00,0x00, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x71,0xB8, 0xE6,0x01, 0x0B,0x51, 0x00,0x00,
+0x00,0x01, 0xE0,0x01, 0x0B,0x5C, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00,
+0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF4,0x84,
+0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0xFD,0xCC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x71,0xC0, 0xF7,0x04,
+0x71,0xC0, 0xF4,0x84, 0x7B,0x10, 0x00,0x00, 0x00,0x01, 0x94,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0xFF,0x30, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x0B,0x50, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x71,0xC0, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x71,0xC0, 0xF7,0x04, 0x71,0xC0, 0xF6,0x84, 0x7B,0x10, 0x87,0x02, 0xFF,0x48, 0x00,0x00,
+0x00,0x01, 0xC7,0x38, 0x6A,0x00, 0x27,0x38, 0x00,0x04, 0x97,0x13, 0xFF,0xFC, 0x96,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0xFE,0x48, 0x97,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x70,0x80, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x6F,0x68, 0xF7,0x05, 0x7B,0x18, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x05,0x58, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x6F,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x6F,0xF4, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x7B,0x18, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x70,0x80, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x7B,0x18, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x71,0x0C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF5,0x02, 0x00,0x04, 0xF5,0x05, 0x76,0x00, 0xF0,0x05,
+0x76,0x08, 0xF0,0x05, 0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF5,0x02, 0x00,0x01, 0xF6,0x82,
+0x00,0x00, 0x20,0x36, 0x00,0x04, 0xEC,0x01, 0x0C,0xBC, 0xF5,0x05, 0x75,0xFC, 0xF5,0x8E,
+0x6A,0xF8, 0xF6,0x06, 0x75,0xF8, 0x47,0x2C, 0xFF,0xFC, 0x97,0x32, 0x00,0x18, 0x06,0x30,
+0x00,0x04, 0x06,0xB4, 0x00,0x01, 0xF7,0x04, 0x76,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xEC,0x01, 0x0C,0x99, 0x05,0xAC, 0x21,0x4C, 0xF5,0x06, 0x72,0x18, 0x95,0x13,
+0xFF,0xFC, 0xF5,0x06, 0x76,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0x18, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x0D,0xF4, 0x95,0x13,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x0E, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x72,0xA4, 0x95,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+0x73,0x30, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x06, 0x16,0xC8, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82, 0x00,0x01, 0x97,0x93,
+0xFF,0xFC, 0xF5,0x06, 0x73,0xBC, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x18,0x00, 0x95,0x13, 0xFF,0xFC, 0xF7,0x82,
+0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0x48, 0x95,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x16,0x40, 0x95,0x13,
+0xFF,0xFC, 0xF7,0x82, 0x00,0x10, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06, 0x74,0xD4, 0x95,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF5,0x06,
+0x13,0x2C, 0x95,0x13, 0xFF,0xFC, 0xF5,0x02, 0x00,0x12, 0x95,0x13, 0xFF,0xFC, 0xF5,0x06,
+0x75,0x60, 0x95,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93,
+0xFF,0xFC, 0xF0,0x05, 0x75,0xF0, 0xF0,0x05, 0x75,0xEC, 0xF0,0x05, 0x75,0xF4, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04,
+0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x28, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x0E,0x3D, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x59, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01,
+0x0E,0x6C, 0xF6,0x82, 0x00,0x00, 0xF7,0x04, 0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39,
+0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x86,0xBA, 0x00,0x18, 0xF7,0x04, 0x76,0xFC, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0x90, 0xF6,0x85, 0x76,0x60, 0xF3,0x06,
+0x76,0x48, 0xF3,0x05, 0x76,0xFC, 0xE0,0x01, 0x0E,0xA4, 0xF7,0x02, 0x00,0x01, 0xF3,0x02,
+0x00,0x10, 0xF3,0x05, 0x76,0xF8, 0xF3,0x06, 0x76,0x48, 0xF3,0x05, 0x77,0x00, 0xF7,0x02,
+0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x15, 0xF3,0x06, 0x74,0x48, 0xF7,0x04,
+0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x0E,0xD8, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x0E,0xED, 0x00,0x00, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x01, 0x13,0x18, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00,
+0x00,0x01, 0x87,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01,
+0x0F,0x21, 0xF4,0x82, 0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x00,0xBC, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4,
+0x00,0x00, 0x84,0x1E, 0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16,
+0xFF,0xC4, 0x94,0x16, 0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04,
+0x4A,0x9C, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x10,0x0C, 0x95,0x16,
+0xFF,0xE4, 0x77,0x35, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06,
+0x4A,0x98, 0xC6,0xB8, 0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x0F,0x9C, 0xC6,0x24,
+0x00,0x00, 0x87,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01,
+0x0F,0xA0, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
+0x0F,0xAD, 0x00,0x00, 0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16,
+0xFF,0xE0, 0x00,0x00, 0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x0F,0xE8, 0xF5,0x02,
+0x00,0x00, 0xC0,0x32, 0x72,0x00, 0xE6,0x01, 0x0F,0xF0, 0x20,0x2A, 0x00,0x00, 0x86,0xB6,
+0x00,0x04, 0x87,0x16, 0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01,
+0x0F,0xF1, 0x20,0x2A, 0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01,
+0x10,0x01, 0x20,0x2E, 0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01,
+0x10,0x10, 0x20,0x26, 0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01,
+0x10,0x45, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9,
+0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4,
+0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x10,0xB8, 0x96,0x96,
+0xFF,0xDC, 0x27,0x14, 0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00,
+0x00,0x01, 0x93,0x13, 0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96,
+0xFF,0xCC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96,
+0xFF,0xCC, 0x20,0x22, 0x00,0x00, 0xE6,0x01, 0x10,0xB5, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5,
+0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16,
+0xFF,0xD8, 0x96,0x96, 0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x10,0xBC, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x10,0xCC, 0xF4,0x82,
+0x00,0x01, 0xE0,0x01, 0x11,0x24, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00,
+0x00,0x01, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86,
+0x42,0xC8, 0xA6,0x3A, 0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28,
+0xFF,0xE5, 0x05,0xB8, 0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16,
+0xFF,0xEC, 0xC6,0x30, 0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD,
+0x00,0x1E, 0x75,0xAC, 0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96,
+0xFF,0xF0, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x11,0x38, 0xF5,0x82, 0x00,0x00, 0xE0,0x01,
+0x11,0xCC, 0xF6,0x02, 0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34,
+0x68,0x00, 0xC4,0x9C, 0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x11,0x98, 0xC5,0x24,
+0x00,0x00, 0xC6,0x2C, 0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2,
+0x70,0x02, 0x05,0xAC, 0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38,
+0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28,
+0x00,0x02, 0x87,0x16, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01,
+0x11,0x59, 0x06,0x30, 0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02,
+0x00,0x01, 0x87,0x16, 0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38,
+0x48,0x00, 0xC6,0xB4, 0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02,
+0xFF,0x6C, 0x94,0x82, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
+0x13,0x10, 0x00,0x00, 0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01,
+0x12,0x30, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+0x12,0x1C, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05,
+0x76,0xF8, 0xF3,0x04, 0x77,0x00, 0xE0,0x01, 0x12,0x34, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05,
+0x76,0xFC, 0xF7,0x04, 0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x12,0x71, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32,
+0x00,0x44, 0xE6,0x01, 0x12,0x70, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04,
+0x76,0x08, 0xF6,0x84, 0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01,
+0x12,0x8C, 0xF7,0x05, 0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04,
+0x76,0x04, 0xF0,0x05, 0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x12,0xB9, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01,
+0x12,0xC8, 0xF7,0x02, 0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A,
+0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x09, 0xF7,0x05,
+0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02,
+0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x13,0x18, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01,
+0x13,0x18, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x13,0x14, 0xF3,0x06, 0x72,0x18, 0xF3,0x06,
+0x73,0x30, 0xF3,0x05, 0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x04, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x86,0xBA, 0x00,0x04, 0xF7,0x04,
+0x76,0x54, 0x00,0x00, 0x00,0x01, 0xC7,0x38, 0x68,0x00, 0xF7,0x05, 0x76,0x54, 0xF7,0x04,
+0x76,0x58, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x76,0x58, 0xF7,0x04,
+0x75,0xF8, 0xF6,0x84, 0x76,0x58, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x13,0x9D, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+0x13,0x9C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
+0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x13,0xB8, 0xF7,0x05,
+0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF7,0x04, 0x76,0x08, 0xF6,0x84, 0x76,0x04, 0xF0,0x05,
+0x75,0xF8, 0xF5,0x84, 0x76,0xF8, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x2E,
+0x00,0x21, 0xE2,0x01, 0x14,0x14, 0xF7,0x05, 0x75,0xFC, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86,
+0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32,
+0x00,0x44, 0xE6,0x01, 0x14,0x00, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x02,
+0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01, 0x14,0x18, 0xF5,0x05,
+0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04, 0x75,0xEC, 0xF5,0x06, 0x72,0x18, 0x20,0x3A,
+0x00,0x00, 0xE6,0x01, 0x14,0x40, 0xF5,0x05, 0x76,0x48, 0xF7,0x04, 0x75,0xF0, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0x55, 0x00,0x00, 0x00,0x01, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x14,0xC4, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x14,0x71, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x14,0x88, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
+0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
+0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x14,0xC5, 0xF7,0x05,
+0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+0x14,0xBC, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF5,0x06, 0x72,0xA4, 0xF5,0x05,
+0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x40, 0xF4,0x02,
+0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xEC, 0x86,0x96,
+0x00,0x08, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x7B,0x38, 0x86,0x96, 0x00,0x00, 0xF7,0x04,
+0x76,0x48, 0xF6,0x85, 0x7B,0x30, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0x41, 0xF4,0x02, 0x00,0x01, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x75,0xF4, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x15,0xBC, 0xF4,0x02, 0x00,0x00, 0x86,0x96,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0xF6,0x85, 0x75,0xF0, 0x86,0x96, 0x00,0x08, 0x00,0x00,
+0x00,0x01, 0xF6,0x85, 0x7B,0x48, 0x86,0x96, 0x00,0x00, 0xF7,0x04, 0x76,0x48, 0xF6,0x85,
+0x7B,0x40, 0xF6,0x86, 0x72,0x18, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x01, 0x15,0xBD, 0xF4,0x02, 0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x15,0xD0, 0x97,0x93, 0xFF,0xFC, 0xF4,0x02, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x01, 0x15,0xFC, 0xF6,0x82, 0x00,0x10, 0xF6,0x86, 0x76,0x48, 0xF6,0x85,
+0x76,0xFC, 0xE0,0x01, 0x16,0x0C, 0xF7,0x02, 0x00,0x01, 0xF6,0x85, 0x76,0xF8, 0xF6,0x86,
+0x76,0x48, 0xF6,0x85, 0x77,0x00, 0xF7,0x02, 0x00,0x00, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x16,0x20, 0xF6,0x86, 0x74,0xD4, 0xE0,0x01, 0x16,0x2C, 0xF6,0x85, 0x76,0x48, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0xE6,0x01, 0x16,0x85, 0xF7,0x02, 0x00,0x01, 0xF7,0x05, 0x75,0xF4, 0xF6,0x84,
+0x7B,0x48, 0xF7,0x05, 0x76,0xF4, 0xF7,0x04, 0x7B,0x40, 0xC6,0xB0, 0x68,0x00, 0x26,0xB4,
+0x00,0x04, 0x97,0x02, 0xFF,0x6C, 0x96,0x02, 0xFF,0x50, 0xE0,0x01, 0x16,0xA8, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x75,0xEC, 0xF6,0x84, 0x7B,0x38, 0xF5,0x82, 0x00,0x01, 0xF5,0x85,
+0x76,0xF4, 0xF6,0x04, 0x7B,0x30, 0xC6,0xB8, 0x68,0x00, 0x26,0xB4, 0x00,0x04, 0x96,0x02,
+0xFF,0x6C, 0x97,0x02, 0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0xF5,0x86, 0x73,0xBC, 0xF5,0x85,
+0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+0x7B,0x28, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0xF7,0x05, 0x7B,0x28, 0xF7,0x04,
+0x75,0xF4, 0xF6,0x84, 0x7B,0x28, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x21, 0x00,0x00,
+0x00,0x01, 0xF0,0x05, 0x75,0xF4, 0xF7,0x04, 0x75,0xEC, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x01, 0x17,0x25, 0xF0,0x05, 0x75,0xF0, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01, 0x17,0xEC, 0x00,0x00, 0x00,0x01, 0xF0,0x05,
+0x75,0xEC, 0xF7,0x04, 0x75,0xFC, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01,
+0x17,0x41, 0xF6,0x86, 0x75,0xF8, 0xE0,0x01, 0x17,0x58, 0xF7,0x02, 0x00,0x00, 0xF7,0x04,
+0x76,0x08, 0x00,0x00, 0x00,0x01, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x87,0x3A,
+0x00,0x18, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x17,0x95, 0xF7,0x05,
+0x76,0x60, 0xF7,0x04, 0x2D,0x38, 0xF6,0x86, 0x2C,0x28, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF5,0x02, 0x00,0x0E, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+0x17,0x8C, 0xB5,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xE0,0x01, 0x17,0x98, 0xF5,0x06,
+0x72,0xA4, 0xF5,0x06, 0x72,0x18, 0xF5,0x05, 0x76,0x48, 0xF5,0x84, 0x76,0xF8, 0x00,0x00,
+0x00,0x01, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x17,0xE8, 0xF6,0x86, 0x2C,0x28, 0xF7,0x04,
+0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39,
+0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x17,0xD4, 0xB5,0xBA, 0x68,0x02, 0xF0,0x05,
+0x2D,0x38, 0xF5,0x02, 0x00,0x22, 0xF5,0x05, 0x76,0xF8, 0xF5,0x04, 0x77,0x00, 0xE0,0x01,
+0x17,0xEC, 0xF5,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x38, 0xF7,0x04, 0x75,0xEC, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x34, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x75,0xF0, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x18,0x49, 0x00,0x00,
+0x00,0x01, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x16,0x40, 0x97,0x93, 0xFF,0xFC, 0xE0,0x01,
+0x1C,0x74, 0x00,0x00, 0x00,0x01, 0xF6,0x84, 0x76,0x60, 0x00,0x00, 0x00,0x01, 0x87,0x36,
+0x00,0x08, 0x00,0x00, 0x00,0x01, 0x70,0x3A, 0xFF,0xE1, 0xE6,0x01, 0x18,0x7D, 0xF4,0x82,
+0x00,0x00, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x00,0xBC, 0x97,0x93,
+0xFF,0xFC, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x75,0x60, 0xC3,0xB4, 0x00,0x00, 0x84,0x1E,
+0x00,0x10, 0xF6,0x84, 0x4A,0xA0, 0x23,0x14, 0x00,0x20, 0x93,0x16, 0xFF,0xC4, 0x94,0x16,
+0xFF,0xE0, 0x96,0x96, 0xFF,0xD4, 0x85,0x1E, 0x00,0x14, 0xF7,0x04, 0x4A,0x9C, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x19,0x68, 0x95,0x16, 0xFF,0xE4, 0x77,0x35,
+0x00,0x01, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF3,0x06, 0x4A,0x98, 0xC6,0xB8,
+0x30,0x00, 0x06,0xB4, 0x00,0x0C, 0xC5,0x84, 0x00,0x00, 0x87,0x36, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0xC0,0x3A, 0x42,0x00, 0xE6,0x01, 0x18,0xF8, 0xC6,0x24, 0x00,0x00, 0x87,0x36,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x52,0x00, 0xE6,0x01, 0x18,0xFC, 0x20,0x32,
+0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x19,0x09, 0x00,0x00,
+0x00,0x01, 0xF5,0x82, 0x00,0x00, 0x86,0x36, 0x00,0x00, 0x87,0x16, 0xFF,0xE0, 0x00,0x00,
+0x00,0x01, 0xC0,0x32, 0x72,0x00, 0xE2,0x01, 0x19,0x44, 0xF5,0x02, 0x00,0x00, 0xC0,0x32,
+0x72,0x00, 0xE6,0x01, 0x19,0x4C, 0x20,0x2A, 0x00,0x00, 0x86,0xB6, 0x00,0x04, 0x87,0x16,
+0xFF,0xE4, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE2,0x01, 0x19,0x4D, 0x20,0x2A,
+0x00,0x00, 0xF5,0x02, 0x00,0x01, 0x20,0x2A, 0x00,0x00, 0xE6,0x01, 0x19,0x5D, 0x20,0x2E,
+0x00,0x00, 0xF5,0x82, 0x00,0x01, 0x20,0x2E, 0x00,0x00, 0xE6,0x01, 0x19,0x6C, 0x20,0x26,
+0x00,0x00, 0xF4,0x82, 0x00,0x01, 0x20,0x26, 0x00,0x00, 0xE6,0x01, 0x19,0xA1, 0xF6,0x02,
+0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06, 0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4,
+0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4, 0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6,
+0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0xE0,0x01, 0x1A,0x14, 0x96,0x96, 0xFF,0xDC, 0x27,0x14,
+0x00,0x2C, 0x97,0x13, 0xFF,0xFC, 0x83,0x16, 0xFF,0xC4, 0x00,0x00, 0x00,0x01, 0x93,0x13,
+0xFF,0xFC, 0xF3,0x06, 0x4A,0x98, 0x93,0x13, 0xFF,0xFC, 0x93,0x96, 0xFF,0xCC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x83,0x96, 0xFF,0xCC, 0x20,0x22,
+0x00,0x00, 0xE6,0x01, 0x1A,0x11, 0xF6,0x02, 0x00,0x01, 0x87,0x16, 0xFF,0xD4, 0xF3,0x06,
+0x4A,0x98, 0x76,0xB9, 0x00,0x01, 0xC6,0xB4, 0x70,0x00, 0x76,0xB5, 0x00,0x02, 0xC6,0xB4,
+0x30,0x00, 0x06,0xB4, 0x00,0x14, 0x86,0xB6, 0x00,0x00, 0x97,0x16, 0xFF,0xD8, 0x96,0x96,
+0xFF,0xDC, 0xF7,0x05, 0x4A,0xA0, 0xE0,0x01, 0x1A,0x18, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x00, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1A,0x28, 0xF4,0x82, 0x00,0x01, 0xE0,0x01,
+0x1A,0x80, 0xF4,0x82, 0x00,0x00, 0x86,0x96, 0xFF,0xD8, 0x00,0x00, 0x00,0x01, 0x77,0x35,
+0x00,0x02, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0x00,0x02, 0xF6,0x86, 0x42,0xC8, 0xA6,0x3A,
+0x68,0x02, 0xC7,0x38, 0x68,0x00, 0x75,0x39, 0x00,0x1E, 0x75,0x28, 0xFF,0xE5, 0x05,0xB8,
+0x00,0x02, 0x86,0xAE, 0x00,0x00, 0x07,0x38, 0x00,0x04, 0x97,0x16, 0xFF,0xEC, 0xC6,0x30,
+0x57,0xC0, 0x76,0x30, 0xFF,0xF0, 0x96,0x16, 0xFF,0xF4, 0x75,0xAD, 0x00,0x1E, 0x75,0xAC,
+0xFF,0xE5, 0xC6,0xB4, 0x5F,0xC0, 0x76,0xB4, 0xFF,0xF0, 0x96,0x96, 0xFF,0xF0, 0x20,0x26,
+0x00,0x00, 0xE6,0x01, 0x1A,0x94, 0xF5,0x82, 0x00,0x00, 0xE0,0x01, 0x1B,0x28, 0xF6,0x02,
+0x00,0x00, 0x86,0x96, 0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC7,0x34, 0x68,0x00, 0xC4,0x9C,
+0x72,0x00, 0xC0,0x2E, 0x6A,0x00, 0xEC,0x01, 0x1A,0xF4, 0xC5,0x24, 0x00,0x00, 0xC6,0x2C,
+0x00,0x00, 0x87,0x16, 0xFF,0xEC, 0x00,0x00, 0x00,0x01, 0xA6,0xB2, 0x70,0x02, 0x05,0xAC,
+0x00,0x01, 0xC7,0x30, 0x70,0x00, 0x77,0x39, 0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4,
+0x77,0xC0, 0x76,0xB4, 0xFF,0xF0, 0xF6,0xAB, 0x28,0x00, 0x05,0x28, 0x00,0x02, 0x87,0x16,
+0xFF,0xF0, 0x00,0x00, 0x00,0x01, 0xC0,0x2E, 0x72,0x00, 0xEC,0x01, 0x1A,0xB5, 0x06,0x30,
+0x00,0x02, 0xF3,0x02, 0x00,0x01, 0xF3,0x05, 0x76,0xF4, 0xF6,0x02, 0x00,0x01, 0x87,0x16,
+0xFF,0xF0, 0x86,0x9E, 0x00,0x04, 0xC7,0x38, 0x70,0x00, 0xC7,0x38, 0x48,0x00, 0xC6,0xB4,
+0x70,0x00, 0x87,0x16, 0xFF,0xF4, 0x06,0xB4, 0x00,0x20, 0x97,0x02, 0xFF,0x6C, 0x94,0x82,
+0xFF,0x50, 0x96,0x82, 0xFF,0x58, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x1C,0x6C, 0x00,0x00,
+0x00,0x01, 0xF7,0x04, 0x76,0x5C, 0xF5,0x84, 0x76,0xF8, 0x07,0x38, 0x00,0x01, 0xF7,0x05,
+0x76,0x5C, 0xF7,0x04, 0x76,0x5C, 0x20,0x2E, 0x00,0x21, 0xE2,0x01, 0x1B,0x8C, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x32, 0x00,0x44, 0xE6,0x01, 0x1B,0x78, 0xB5,0xBA,
+0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF3,0x02, 0x00,0x22, 0xF3,0x05, 0x76,0xF8, 0xF3,0x04,
+0x77,0x00, 0xE0,0x01, 0x1B,0x90, 0xF3,0x05, 0x76,0xFC, 0xF0,0x05, 0x76,0xFC, 0xF7,0x04,
+0x75,0xF8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1B,0xCD, 0xF6,0x86,
+0x2C,0x28, 0xF7,0x04, 0x2D,0x38, 0x00,0x00, 0x00,0x01, 0x06,0x38, 0x00,0x01, 0xF6,0x05,
+0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0F, 0x20,0x32, 0x00,0x44, 0xE6,0x01,
+0x1B,0xCC, 0xB3,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0xF7,0x04, 0x76,0x08, 0xF6,0x84,
+0x76,0x00, 0x07,0x38, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0xE6,0x01, 0x1B,0xE8, 0xF7,0x05,
+0x76,0x08, 0xF0,0x05, 0x76,0x08, 0xF6,0x84, 0x76,0x08, 0xF7,0x04, 0x76,0x04, 0xF0,0x05,
+0x75,0xF8, 0xF6,0x06, 0x75,0xF8, 0xC0,0x36, 0x72,0x00, 0x47,0x0C, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x01, 0x1C,0x15, 0xF7,0x05, 0x75,0xFC, 0xE0,0x01, 0x1C,0x24, 0xF7,0x02,
+0x00,0x00, 0x77,0x35, 0x00,0x02, 0xC7,0x38, 0x60,0x00, 0x87,0x3A, 0x00,0x18, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x1C,0x65, 0xF7,0x05, 0x76,0x60, 0xF7,0x04,
+0x2D,0x38, 0xF3,0x06, 0x72,0xA4, 0xF3,0x05, 0x76,0x48, 0xF6,0x86, 0x2C,0x28, 0x06,0x38,
+0x00,0x01, 0xF6,0x05, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0xF3,0x02, 0x00,0x0E, 0x20,0x32,
+0x00,0x44, 0xE6,0x01, 0x1C,0x74, 0xB3,0x3A, 0x68,0x02, 0xE0,0x01, 0x1C,0x74, 0xF0,0x05,
+0x2D,0x38, 0xE0,0x01, 0x1C,0x70, 0xF3,0x06, 0x72,0x18, 0xF3,0x06, 0x73,0x30, 0xF3,0x05,
+0x76,0x48, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06,
+0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x72,0x18, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x72,0xA4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x73,0x30, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x73,0xBC, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06,
+0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06, 0x74,0x48, 0x97,0x13, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x74,0xD4, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x76,0x48, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x75,0x60, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86,
+0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86, 0x77,0x04, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93, 0xFF,0xFC, 0xF6,0x86, 0x1D,0xD4, 0x96,0x93,
+0xFF,0xFC, 0x90,0x13, 0xFF,0xFC, 0xF6,0x86, 0x76,0x68, 0x96,0x93, 0xFF,0xFC, 0x07,0x88,
+0x00,0x08, 0xE0,0x00, 0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF7,0x02, 0x00,0x22, 0xF7,0x05,
+0x76,0xF4, 0xF7,0x05, 0x76,0xF8, 0xF0,0x05, 0x76,0xFC, 0xF0,0x05, 0x77,0x00, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04, 0x76,0xF4, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x22, 0xE6,0x01, 0x1E,0x01, 0x00,0x00, 0x00,0x01, 0x97,0x13,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x84, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x77,0x04, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x76,0x68, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0xF6,0x86,
+0x78,0xA4, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF6,0x86, 0x1F,0xBC, 0x96,0x93, 0xFF,0xFC, 0xF6,0x82, 0x00,0x14, 0x96,0x93,
+0xFF,0xFC, 0xF6,0x86, 0x78,0x10, 0x96,0x93, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0xF0,0x05, 0x78,0x9C, 0x90,0x02, 0xFF,0x34, 0xF7,0x02,
+0x7F,0xFF, 0xF7,0x05, 0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF6,0x04, 0x78,0x9C, 0x87,0x16, 0x00,0x00, 0x84,0x96,
+0x00,0x08, 0xF5,0x86, 0x77,0x10, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x75,0x39,
+0x00,0x04, 0x77,0x39, 0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0x20,0x32, 0x00,0x00, 0xC6,0xA8,
+0x58,0x00, 0x84,0x16, 0x00,0x04, 0xC6,0x30, 0x75,0x80, 0x94,0x36, 0x00,0x04, 0xB4,0xAA,
+0x58,0x02, 0x87,0x36, 0x00,0x08, 0xF6,0x05, 0x78,0x9C, 0x07,0x38, 0x00,0x01, 0xE6,0x01,
+0x1F,0x2D, 0x97,0x36, 0x00,0x08, 0x87,0x02, 0xFF,0x30, 0x00,0x00, 0x00,0x01, 0xC0,0x3A,
+0x4A,0x00, 0xEE,0x01, 0x1F,0x35, 0x00,0x00, 0x00,0x01, 0xF4,0x85, 0x78,0xA0, 0x94,0x82,
+0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x87,0x2E, 0x00,0x08, 0xF6,0x86, 0x21,0x8C, 0x77,0x39,
+0x00,0x02, 0xA7,0x3A, 0x68,0x02, 0xF6,0x04, 0x78,0x9C, 0xC7,0x04, 0x76,0x00, 0x86,0xAE,
+0x00,0x08, 0xC6,0x30, 0x74,0x00, 0xF7,0x06, 0x77,0x10, 0xF6,0x05, 0x78,0x9C, 0x76,0xB5,
+0x00,0x04, 0xC6,0xB4, 0x70,0x00, 0x87,0x36, 0x00,0x08, 0x20,0x32, 0x00,0x00, 0x07,0x38,
+0x00,0x01, 0xE6,0x01, 0x1F,0xA8, 0x97,0x36, 0x00,0x08, 0xF7,0x02, 0x7F,0xFF, 0xF7,0x05,
+0x78,0xA0, 0x97,0x02, 0xFF,0x30, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0x22,0x10, 0x00,0x08, 0xF7,0x04, 0x78,0x9C, 0x00,0x00, 0x00,0x01, 0x20,0x3A,
+0x00,0x00, 0xE6,0x01, 0x20,0xD1, 0xF6,0x02, 0x7F,0xFF, 0x96,0x16, 0xFF,0xF4, 0xF6,0x84,
+0x2D,0x40, 0xF6,0x06, 0x77,0x10, 0x26,0xB4, 0x00,0x01, 0x77,0x35, 0x00,0x04, 0xC4,0xB8,
+0x60,0x00, 0xC3,0x38, 0x00,0x00, 0x74,0x35, 0x00,0x02, 0xF6,0x06, 0x77,0x10, 0xC0,0x26,
+0x62,0x00, 0xEC,0x01, 0x20,0xC1, 0xF6,0x06, 0x21,0x8C, 0xF3,0x84, 0x78,0x9C, 0xA7,0x22,
+0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC0,0x1E, 0x74,0x00, 0xE6,0x01, 0x20,0xB1, 0x00,0x00,
+0x00,0x01, 0x86,0xA6, 0x00,0x00, 0xF7,0x04, 0x78,0xA0, 0x00,0x00, 0x00,0x01, 0xC6,0xB4,
+0x72,0x00, 0x20,0x36, 0x00,0x00, 0xEE,0x01, 0x20,0x98, 0x96,0xA6, 0x00,0x00, 0xF7,0x04,
+0x2D,0x38, 0xF6,0x06, 0x77,0x10, 0xC5,0x18, 0x60,0x00, 0xF6,0x86, 0x2C,0x28, 0x86,0x2A,
+0x00,0x04, 0x05,0xB8, 0x00,0x01, 0xF5,0x85, 0x2D,0x38, 0x77,0x39, 0x00,0x02, 0x20,0x2E,
+0x00,0x44, 0xE6,0x01, 0x20,0x70, 0xB6,0x3A, 0x68,0x02, 0xF0,0x05, 0x2D,0x38, 0x86,0x2A,
+0x00,0x08, 0x00,0x00, 0x00,0x01, 0x96,0x2A, 0x00,0x0C, 0xF6,0x06, 0x21,0x8C, 0xA7,0x22,
+0x60,0x02, 0x00,0x00, 0x00,0x01, 0xC7,0x04, 0x76,0x00, 0xC7,0x1C, 0x74,0x00, 0xE0,0x01,
+0x20,0xB0, 0xF7,0x05, 0x78,0x9C, 0x86,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x62,0x00, 0xEC,0x01, 0x20,0xB0, 0x00,0x00, 0x00,0x01, 0x96,0x96, 0xFF,0xF4, 0x24,0xA4,
+0x00,0x10, 0x23,0x18, 0x00,0x10, 0xE0,0x01, 0x1F,0xFC, 0x24,0x20, 0x00,0x04, 0x86,0x16,
+0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xF6,0x05, 0x78,0xA0, 0x96,0x02, 0xFF,0x30, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x87,0x16, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x87,0x3A, 0x00,0x08, 0xF6,0x86, 0x77,0x10, 0x77,0x39, 0x00,0x04, 0xC7,0x38,
+0x68,0x00, 0x86,0xBA, 0x00,0x0C, 0x87,0x3A, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0x44,0x0C, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x04, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF7,0x02, 0x00,0x0F, 0x20,0x3A, 0x00,0x00, 0xEC,0x01, 0x21,0x5D, 0xF6,0x86,
+0x77,0x18, 0x90,0x36, 0x00,0x00, 0x27,0x38, 0x00,0x01, 0xC6,0x04, 0x00,0x00, 0xC0,0x3A,
+0x62,0x00, 0xE6,0x01, 0x21,0x44, 0x06,0xB4, 0x00,0x10, 0xF6,0x06, 0x78,0xA4, 0x96,0x13,
+0xFF,0xFC, 0xF6,0x06, 0x78,0x10, 0x96,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x01, 0x00,0x00,
+0x00,0x02, 0x00,0x00, 0x00,0x04, 0x00,0x00, 0x00,0x08, 0x00,0x00, 0x00,0x10, 0x00,0x00,
+0x00,0x20, 0x00,0x00, 0x00,0x40, 0x00,0x00, 0x00,0x80, 0x00,0x00, 0x01,0x00, 0x00,0x00,
+0x02,0x00, 0x00,0x00, 0x04,0x00, 0x00,0x00, 0x08,0x00, 0x00,0x00, 0x10,0x00, 0x00,0x00,
+0x20,0x00, 0x00,0x00, 0x40,0x00, 0x00,0x00, 0x80,0x00, 0x00,0x00, 0x00,0x00, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x15,0x48, 0x97,0x93,
+0xFF,0xFC, 0xF7,0x06, 0x22,0x2C, 0x97,0x13, 0xFF,0xFC, 0xF7,0x02, 0x00,0x15, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x16,0x1C, 0x97,0x93, 0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14,
+0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90,
+0x00,0x08, 0xF6,0x84, 0x6F,0x44, 0x00,0x00, 0x00,0x01, 0x87,0x36, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x20,0x3A, 0x00,0x02, 0xE6,0x01, 0x22,0x70, 0xF6,0x02, 0x00,0x00, 0x87,0x36,
+0x0E,0xF4, 0x86,0xB6, 0x0E,0xF8, 0x00,0x00, 0x00,0x01, 0xC0,0x3A, 0x6A,0x00, 0x47,0x0C,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0x78, 0x20,0x32, 0x00,0x00, 0xF6,0x02,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01, 0x22,0x94, 0x00,0x00, 0x00,0x01, 0xF7,0x04,
+0x32,0xE8, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x22,0xB1, 0xF5,0x82,
+0x03,0xE8, 0x0F,0x81, 0x40,0x00, 0xF7,0x04, 0x79,0xC8, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0xF7,0x05, 0x79,0xC8, 0xF7,0x04, 0x79,0xC8, 0xF5,0x82, 0x03,0xE8, 0x95,0x93,
+0xFF,0xFC, 0xF5,0x82, 0x00,0x15, 0x95,0x93, 0xFF,0xFC, 0xF5,0x86, 0x79,0xCC, 0x95,0x93,
+0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x1E,0xC0, 0x97,0x93, 0xFF,0xFC, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x06, 0x79,0xCC, 0x97,0x13,
+0xFF,0xFC, 0xF7,0x06, 0x78,0xB0, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00,
+0x14,0xF4, 0x97,0x93, 0xFF,0xFC, 0xF7,0x06, 0x79,0xCC, 0x97,0x13, 0xFF,0xFC, 0xF7,0x06,
+0x79,0x3C, 0x97,0x13, 0xFF,0xFC, 0x07,0x88, 0x00,0x08, 0xE0,0x00, 0x14,0xF4, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC1,0x3C, 0x00,0x00, 0x02,0x10, 0x00,0x04, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
+0x23,0x84, 0x27,0x14, 0x00,0x0C, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0xE0,0x01, 0x24,0x34, 0x96,0x96,
+0xFF,0xF4, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x13,
+0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88, 0x00,0x08, 0xE0,0x01,
+0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
+0x24,0x34, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x04, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
+0x00,0x01, 0xC0,0x36, 0x62,0x00, 0xEE,0x01, 0x24,0x21, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC6,0xB8, 0x58,0x00, 0x77,0x31, 0x00,0x01, 0xC7,0x38,
+0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x36,
+0x00,0x10, 0x85,0x36, 0x00,0x08, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x14, 0x26,0xB4,
+0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEE,0x01, 0x23,0xEC, 0x00,0x00, 0x00,0x01, 0x87,0x2E,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x07,0x38, 0x00,0x01, 0x97,0x2E, 0x00,0x04, 0x87,0x2E,
+0x00,0x04, 0x86,0x96, 0xFF,0xF4, 0x85,0x16, 0x00,0x04, 0x77,0x35, 0x00,0x01, 0xC7,0x38,
+0x68,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x2C, 0x70,0x00, 0x85,0x2A, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x95,0x3A, 0x00,0x0C, 0x85,0x16, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x85,0x2A,
+0x00,0x04, 0x00,0x00, 0x00,0x01, 0x95,0x3A, 0x00,0x10, 0x85,0x16, 0x00,0x08, 0xF4,0x02,
+0x00,0x01, 0x95,0x3A, 0x00,0x14, 0x96,0xAE, 0x00,0x08, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x0C, 0x85,0x96, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x84,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x20,0x22, 0x00,0x00, 0xE6,0x01,
+0x25,0x55, 0x27,0x14, 0x00,0x0C, 0x97,0x13, 0xFF,0xFC, 0x85,0x16, 0x00,0x04, 0x00,0x00,
+0x00,0x01, 0x95,0x13, 0xFF,0xFC, 0x95,0x93, 0xFF,0xFC, 0x95,0x96, 0xFF,0xEC, 0x07,0x88,
+0x00,0x08, 0xE0,0x01, 0x25,0x68, 0x97,0x93, 0xFF,0xFC, 0x85,0x96, 0xFF,0xEC, 0x20,0x22,
+0x00,0x00, 0xE6,0x01, 0x25,0x55, 0x00,0x00, 0x00,0x01, 0x86,0x16, 0xFF,0xF4, 0x00,0x00,
+0x00,0x01, 0x20,0x32, 0x00,0x00, 0xEE,0x01, 0x25,0x45, 0x77,0x31, 0x00,0x01, 0xC6,0xAC,
+0x00,0x00, 0xC7,0x38, 0x60,0x00, 0x77,0x39, 0x00,0x02, 0xC7,0x38, 0x58,0x00, 0x85,0x36,
+0x00,0x18, 0x00,0x00, 0x00,0x01, 0x95,0x36, 0x00,0x0C, 0x85,0x36, 0x00,0x1C, 0x00,0x00,
+0x00,0x01, 0x95,0x36, 0x00,0x10, 0x85,0x36, 0x00,0x20, 0x00,0x00, 0x00,0x01, 0x95,0x36,
+0x00,0x14, 0x06,0xB4, 0x00,0x0C, 0xC0,0x36, 0x72,0x00, 0xEC,0x01, 0x25,0x11, 0x00,0x00,
+0x00,0x01, 0x87,0x2E, 0x00,0x04, 0xF4,0x02, 0x00,0x01, 0x27,0x38, 0x00,0x01, 0x97,0x2E,
+0x00,0x04, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x08, 0x83,0x96, 0x00,0x04, 0x83,0x16, 0x00,0x00, 0xC5,0x00, 0x00,0x00, 0x84,0x1A,
+0x00,0x04, 0xC4,0xA8, 0x00,0x00, 0x94,0x16, 0xFF,0xF4, 0xC0,0x26, 0x42,0x00, 0xE6,0x01,
+0x26,0xD1, 0x00,0x00, 0x00,0x01, 0x83,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0xC0,0x2A,
+0x32,0x00, 0xE6,0x01, 0x26,0xD1, 0xC7,0x20, 0x4A,0x00, 0x95,0x16, 0xFF,0xF4, 0x76,0xB8,
+0xFF,0xE1, 0xC7,0x38, 0x68,0x00, 0x77,0x39, 0xFF,0xFF, 0xC5,0x24, 0x70,0x00, 0x77,0x29,
+0x00,0x01, 0xC7,0x38, 0x50,0x00, 0x77,0x39, 0x00,0x02, 0x83,0x16, 0x00,0x00, 0x86,0x9E,
+0x00,0x00, 0xC5,0xB8, 0x30,0x00, 0x05,0xAC, 0x00,0x0C, 0x87,0x2E, 0x00,0x00, 0xC6,0x00,
+0x00,0x00, 0xC0,0x36, 0x72,0x00, 0xE6,0x01, 0x26,0x10, 0x20,0x32, 0x00,0x00, 0x86,0x9E,
+0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36, 0x72,0x00, 0xE6,0x01,
+0x26,0x10, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32, 0x00,0x00, 0xE6,0x01,
+0x26,0x25, 0x00,0x00, 0x00,0x01, 0xC7,0x00, 0x00,0x00, 0xE0,0x01, 0x26,0x78, 0x20,0x3A,
+0x00,0x00, 0x86,0x9E, 0x00,0x00, 0x87,0x2E, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x01, 0x26,0x5C, 0x00,0x00, 0x00,0x01, 0xE6,0x01, 0x26,0x64, 0x20,0x32,
+0x00,0x00, 0x86,0x9E, 0x00,0x04, 0x87,0x2E, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC0,0x36,
+0x72,0x00, 0xE2,0x01, 0x26,0x65, 0x20,0x32, 0x00,0x00, 0xF6,0x02, 0x00,0x01, 0x20,0x32,
+0x00,0x00, 0x47,0x04, 0xFF,0xFF, 0xE6,0x01, 0x26,0x79, 0x20,0x3A, 0x00,0x00, 0xF7,0x02,
+0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x26,0xB1, 0x20,0x3A, 0x00,0x00, 0xEE,0x01,
+0x26,0xA0, 0x20,0x3A, 0x00,0x01, 0x43,0x04, 0xFF,0xFF, 0xC0,0x3A, 0x32,0x00, 0xE6,0x01,
+0x26,0xC9, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0xE6,0x01,
+0x26,0xC1, 0xC0,0x26, 0x42,0x00, 0xE0,0x01, 0x25,0x90, 0x00,0x00, 0x00,0x01, 0x83,0x16,
+0x00,0x08, 0xF4,0x02, 0x00,0x01, 0xE0,0x01, 0x26,0xE0, 0x95,0x1A, 0x00,0x00, 0xE0,0x01,
+0x25,0x8C, 0xC4,0xA8, 0x00,0x00, 0xE0,0x01, 0x25,0x8C, 0xC4,0x28, 0x00,0x00, 0x83,0x16,
+0x00,0x08, 0x00,0x00, 0x00,0x01, 0x94,0x1A, 0x00,0x00, 0xC4,0x00, 0x00,0x00, 0x87,0x96,
+0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x85,0x96,
+0x00,0x04, 0x84,0x16, 0x00,0x00, 0x84,0x96, 0x00,0x08, 0xF7,0x02, 0x00,0x03, 0xC6,0xA0,
+0x4D,0x80, 0xC6,0xB6, 0x74,0x00, 0xE6,0x01, 0x27,0x71, 0xC6,0x20, 0x00,0x00, 0x20,0x36,
+0x00,0x02, 0xE6,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20, 0x48,0x00, 0x27,0x38,
+0x00,0x02, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0x9C, 0xC5,0x38, 0x00,0x00, 0x87,0x2E,
+0x00,0x00, 0x76,0xAD, 0x00,0x1E, 0x76,0xB4, 0xFF,0xE5, 0xC7,0x38, 0x6F,0xC0, 0x77,0x38,
+0xFF,0xF0, 0xF7,0x33, 0x28,0x00, 0x06,0x30, 0x00,0x02, 0xC0,0x32, 0x52,0x00, 0xE2,0x01,
+0x27,0x41, 0x05,0xAC, 0x00,0x02, 0xE0,0x01, 0x27,0xA0, 0xC5,0x20, 0x48,0x00, 0xC7,0x20,
+0x48,0x00, 0x27,0x38, 0x00,0x04, 0xC0,0x22, 0x72,0x00, 0xE2,0x01, 0x27,0xA0, 0xC5,0x20,
+0x48,0x00, 0x83,0xAD, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0x93,0xB1, 0x00,0x04, 0xC0,0x32,
+0x72,0x00, 0xE2,0x01, 0x27,0x85, 0x00,0x00, 0x00,0x01, 0xC5,0x20, 0x48,0x00, 0xC0,0x32,
+0x52,0x00, 0xE4,0x01, 0x27,0xD5, 0x00,0x00, 0x00,0x01, 0x86,0xAE, 0x00,0x00, 0x77,0x2D,
+0x00,0x1E, 0x77,0x38, 0xFF,0xE5, 0xC6,0xB4, 0x77,0xC0, 0x76,0xB5, 0xFF,0xE8, 0xF6,0xB3,
+0x68,0x00, 0x06,0x30, 0x00,0x01, 0xC0,0x32, 0x52,0x00, 0xE4,0x01, 0x27,0xAC, 0x05,0xAC,
+0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x0C, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x84,0x16,
+0x00,0x00, 0x86,0x96, 0x00,0x04, 0x00,0x00, 0x00,0x01, 0xC7,0x22, 0x6D,0x80, 0xE6,0x01,
+0x28,0x10, 0x20,0x36, 0x00,0x00, 0xE0,0x01, 0x28,0x74, 0xC4,0x38, 0x00,0x00, 0xF7,0x02,
+0x00,0x01, 0xEE,0x01, 0x28,0x41, 0xF6,0x02, 0x00,0x00, 0x76,0xB5, 0x00,0x01, 0x20,0x36,
+0x00,0x00, 0xEE,0x01, 0x28,0x1C, 0x77,0x39, 0x00,0x01, 0xE0,0x01, 0x28,0x44, 0x20,0x22,
+0x00,0x00, 0x74,0x21, 0x00,0x01, 0x77,0x38, 0xFF,0xFF, 0x06,0x30, 0x00,0x01, 0x20,0x22,
+0x00,0x00, 0xEE,0x01, 0x28,0x34, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x28,0x71, 0x00,0x00,
+0x00,0x01, 0xC0,0x22, 0x6A,0x00, 0xE4,0x01, 0x28,0x64, 0x00,0x00, 0x00,0x01, 0xC4,0x20,
+0x6A,0x00, 0x77,0x3A, 0xFF,0xFF, 0xE6,0x01, 0x28,0x54, 0x76,0xB4, 0xFF,0xFF, 0xD4,0x20,
+0x07,0x62, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x08, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10,
+0x00,0x04, 0xE0,0x01, 0x28,0xCC, 0xF7,0x06, 0x29,0xDC, 0x86,0xBA, 0x00,0x00, 0x00,0x00,
+0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01, 0x28,0xC9, 0x00,0x00, 0x00,0x01, 0x97,0x16,
+0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34, 0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16,
+0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x27,0x38, 0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A,
+0x62,0x00, 0xE4,0x01, 0x28,0x9D, 0x00,0x00, 0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96,
+0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93,
+0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0x22,0x10, 0x00,0x04, 0xE0,0x01, 0x29,0x34, 0xF7,0x06,
+0x29,0x98, 0x86,0xBA, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x20,0x36, 0x00,0x00, 0xE6,0x01,
+0x29,0x31, 0x00,0x00, 0x00,0x01, 0x97,0x16, 0xFF,0xF4, 0x07,0x88, 0x00,0x08, 0xC1,0x34,
+0x00,0x00, 0x97,0x93, 0xFF,0xFC, 0x87,0x16, 0xFF,0xF4, 0x00,0x00, 0x00,0x01, 0x07,0x38,
+0x00,0x04, 0xF6,0x06, 0x29,0xE0, 0xC0,0x3A, 0x62,0x00, 0xE4,0x01, 0x29,0x04, 0x00,0x00,
+0x00,0x01, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x92,0x93, 0xFF,0xFC, 0x02,0x90, 0x00,0x08, 0xF7,0x04,
+0x7B,0x50, 0x00,0x00, 0x00,0x01, 0x20,0x3A, 0x00,0x00, 0xE6,0x01, 0x29,0x84, 0xF6,0x82,
+0x00,0x01, 0xF6,0x85, 0x7B,0x50, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x28,0xF0, 0x97,0x93,
+0xFF,0xFC, 0x87,0x96, 0xFF,0xFC, 0x82,0x96, 0xFF,0xF8, 0x02,0x14, 0x00,0x00, 0x01,0x3C,
+0x00,0x00, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x0B,0x4C, 0x00,0x00, 0x00,0x00, 0x00,0x00,
+0x42,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x5E,0x50, 0x00,0x00, 0x00,0x00, 0x00,0x00,
+0xC7,0xA8, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x0B,0xD0, 0x00,0x00, 0x00,0x00, 0x00,0x01,
+0x1C,0x88, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x1E,0x14, 0x00,0x00, 0x00,0x00, 0x00,0x01,
0x21,0x2C, 0x00,0x00, 0x00,0x00, 0x00,0x01, 0x22,0xE4, 0x00,0x00, 0x00,0x00, } ;
-/* This is the LANai data */
+/* This is the LANai data */
static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */
static unsigned char lanai4_data[20472] __initdata;
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 6c86dca62e2..a925bc9db4a 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1,13 +1,12 @@
-/* myri_sbus.h: MyriCOM MyriNET SBUS card driver.
+/* myri_sbus.c: MyriCOM MyriNET SBUS card driver.
*
- * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2006 David S. Miller (davem@davemloft.net)
*/
static char version[] =
- "myri_sbus.c:v1.9 12/Sep/99 David S. Miller (davem@redhat.com)\n";
+ "myri_sbus.c:v2.0 June 23, 2006 David S. Miller (davem@davemloft.net)\n";
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -81,10 +80,6 @@ static char version[] =
#define DHDR(x)
#endif
-#ifdef MODULE
-static struct myri_eth *root_myri_dev;
-#endif
-
static void myri_reset_off(void __iomem *lp, void __iomem *cregs)
{
/* Clear IRQ mask. */
@@ -365,7 +360,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
mp->tx_old = entry;
}
-/* Determine the packet's protocol ID. The rule here is that we
+/* Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*/
@@ -373,11 +368,11 @@ static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
-
+
skb->mac.raw = (((unsigned char *)skb->data) + MYRI_PAD_LEN);
skb_pull(skb, dev->hard_header_len);
eth = eth_hdr(skb);
-
+
#ifdef DEBUG_HEADER
DHDR(("myri_type_trans: "));
dump_ehdr(eth);
@@ -391,12 +386,12 @@ static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev)
if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
skb->pkt_type = PACKET_OTHERHOST;
}
-
+
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
-
+
rawp = skb->data;
-
+
/* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
@@ -404,7 +399,7 @@ static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev)
*/
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
-
+
/* Real 802.2 LLC */
return htons(ETH_P_802_2);
}
@@ -683,7 +678,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-/* Create the MyriNet MAC header for an arbitrary protocol layer
+/* Create the MyriNet MAC header for an arbitrary protocol layer
*
* saddr=NULL means use device source address
* daddr=NULL means leave destination address (eg unresolved arp)
@@ -706,7 +701,7 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned sho
/* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
* in here instead. It is up to the 802.2 layer to carry protocol information.
*/
- if (type != ETH_P_802_3)
+ if (type != ETH_P_802_3)
eth->h_proto = htons(type);
else
eth->h_proto = htons(len);
@@ -724,7 +719,7 @@ static int myri_header(struct sk_buff *skb, struct net_device *dev, unsigned sho
eth->h_dest[i] = 0;
return(dev->hard_header_len);
}
-
+
if (daddr) {
memcpy(eth->h_dest, daddr, dev->addr_len);
return dev->hard_header_len;
@@ -759,16 +754,16 @@ static int myri_rebuild_header(struct sk_buff *skb)
#endif
default:
- printk(KERN_DEBUG
- "%s: unable to resolve type %X addresses.\n",
+ printk(KERN_DEBUG
+ "%s: unable to resolve type %X addresses.\n",
dev->name, (int)eth->h_proto);
-
+
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return 0;
break;
}
- return 0;
+ return 0;
}
int myri_header_cache(struct neighbour *neigh, struct hh_cache *hh)
@@ -896,8 +891,9 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
-static int __init myri_ether_init(struct sbus_dev *sdev, int num)
+static int __init myri_ether_init(struct sbus_dev *sdev)
{
+ static int num;
static unsigned version_printed;
struct net_device *dev;
struct myri_eth *mp;
@@ -913,6 +909,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
if (version_printed++ == 0)
printk(version);
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+
mp = (struct myri_eth *) dev->priv;
spin_lock_init(&mp->irq_lock);
mp->myri_sdev = sdev;
@@ -1070,7 +1069,7 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
/* Register interrupt handler now. */
DET(("Requesting MYRIcom IRQ line.\n"));
if (request_irq(dev->irq, &myri_interrupt,
- SA_SHIRQ, "MyriCOM Ethernet", (void *) dev)) {
+ IRQF_SHARED, "MyriCOM Ethernet", (void *) dev)) {
printk("MyriCOM: Cannot register interrupt handler.\n");
goto err;
}
@@ -1092,10 +1091,9 @@ static int __init myri_ether_init(struct sbus_dev *sdev, int num)
goto err_free_irq;
}
-#ifdef MODULE
- mp->next_module = root_myri_dev;
- root_myri_dev = mp;
-#endif
+ dev_set_drvdata(&sdev->ofdev.dev, mp);
+
+ num++;
printk("%s: MyriCOM MyriNET Ethernet ", dev->name);
@@ -1114,61 +1112,68 @@ err:
return -ENODEV;
}
-static int __init myri_sbus_match(struct sbus_dev *sdev)
-{
- char *name = sdev->prom_name;
- if (!strcmp(name, "MYRICOM,mlanai") ||
- !strcmp(name, "myri"))
- return 1;
+static int __devinit myri_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- return 0;
+ return myri_ether_init(sdev);
}
-static int __init myri_sbus_probe(void)
+static int __devexit myri_sbus_remove(struct of_device *dev)
{
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
- static int called;
- int cards = 0, v;
+ struct myri_eth *mp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = mp->dev;
-#ifdef MODULE
- root_myri_dev = NULL;
-#endif
+ unregister_netdevice(net_dev);
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(bus) {
- for_each_sbusdev(sdev, bus) {
- if (myri_sbus_match(sdev)) {
- cards++;
- DET(("Found myricom myrinet as %s\n", sdev->prom_name));
- if ((v = myri_ether_init(sdev, (cards - 1))))
- return v;
- }
- }
+ free_irq(net_dev->irq, net_dev);
+
+ if (mp->eeprom.cpuvers < CPUVERS_4_0) {
+ sbus_iounmap(mp->regs, mp->reg_size);
+ } else {
+ sbus_iounmap(mp->cregs, PAGE_SIZE);
+ sbus_iounmap(mp->lregs, (256 * 1024));
+ sbus_iounmap(mp->lanai, (512 * 1024));
}
- if (!cards)
- return -ENODEV;
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit myri_sbus_cleanup(void)
+static struct of_device_id myri_sbus_match[] = {
+ {
+ .name = "MYRICOM,mlanai",
+ },
+ {
+ .name = "myri",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, myri_sbus_match);
+
+static struct of_platform_driver myri_sbus_driver = {
+ .name = "myri",
+ .match_table = myri_sbus_match,
+ .probe = myri_sbus_probe,
+ .remove = __devexit_p(myri_sbus_remove),
+};
+
+static int __init myri_sbus_init(void)
+{
+ return of_register_driver(&myri_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit myri_sbus_exit(void)
{
-#ifdef MODULE
- while (root_myri_dev) {
- struct myri_eth *next = root_myri_dev->next_module;
-
- unregister_netdev(root_myri_dev->dev);
- /* this will also free the co-allocated 'root_myri_dev' */
- free_netdev(root_myri_dev->dev);
- root_myri_dev = next;
- }
-#endif /* MODULE */
+ of_unregister_driver(&myri_sbus_driver);
}
-module_init(myri_sbus_probe);
-module_exit(myri_sbus_cleanup);
+module_init(myri_sbus_init);
+module_exit(myri_sbus_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/net/myri_sbus.h b/drivers/net/myri_sbus.h
index 47722f708a4..2f69ef7cdcc 100644
--- a/drivers/net/myri_sbus.h
+++ b/drivers/net/myri_sbus.h
@@ -290,7 +290,6 @@ struct myri_eth {
unsigned int reg_size; /* Size of register space. */
unsigned int shmem_base; /* Offset to shared ram. */
struct sbus_dev *myri_sdev; /* Our SBUS device struct. */
- struct myri_eth *next_module; /* Next in adapter chain. */
};
/* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index 2e4ecedba05..d7b241f7d7b 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -20,125 +20,13 @@
Support information and updates available at
http://www.scyld.com/network/netsemi.html
+ [link no longer provides useful info -jgarzik]
- Linux kernel modifications:
-
- Version 1.0.1:
- - Spinlock fixes
- - Bug fixes and better intr performance (Tjeerd)
- Version 1.0.2:
- - Now reads correct MAC address from eeprom
- Version 1.0.3:
- - Eliminate redundant priv->tx_full flag
- - Call netif_start_queue from dev->tx_timeout
- - wmb() in start_tx() to flush data
- - Update Tx locking
- - Clean up PCI enable (davej)
- Version 1.0.4:
- - Merge Donald Becker's natsemi.c version 1.07
- Version 1.0.5:
- - { fill me in }
- Version 1.0.6:
- * ethtool support (jgarzik)
- * Proper initialization of the card (which sometimes
- fails to occur and leaves the card in a non-functional
- state). (uzi)
-
- * Some documented register settings to optimize some
- of the 100Mbit autodetection circuitry in rev C cards. (uzi)
-
- * Polling of the PHY intr for stuff like link state
- change and auto- negotiation to finally work properly. (uzi)
-
- * One-liner removal of a duplicate declaration of
- netdev_error(). (uzi)
-
- Version 1.0.7: (Manfred Spraul)
- * pci dma
- * SMP locking update
- * full reset added into tx_timeout
- * correct multicast hash generation (both big and little endian)
- [copied from a natsemi driver version
- from Myrio Corporation, Greg Smith]
- * suspend/resume
-
- version 1.0.8 (Tim Hockin <thockin@sun.com>)
- * ETHTOOL_* support
- * Wake on lan support (Erik Gilling)
- * MXDMA fixes for serverworks
- * EEPROM reload
-
- version 1.0.9 (Manfred Spraul)
- * Main change: fix lack of synchronize
- netif_close/netif_suspend against a last interrupt
- or packet.
- * do not enable superflous interrupts (e.g. the
- drivers relies on TxDone - TxIntr not needed)
- * wait that the hardware has really stopped in close
- and suspend.
- * workaround for the (at least) gcc-2.95.1 compiler
- problem. Also simplifies the code a bit.
- * disable_irq() in tx_timeout - needed to protect
- against rx interrupts.
- * stop the nic before switching into silent rx mode
- for wol (required according to docu).
-
- version 1.0.10:
- * use long for ee_addr (various)
- * print pointers properly (DaveM)
- * include asm/irq.h (?)
-
- version 1.0.11:
- * check and reset if PHY errors appear (Adrian Sun)
- * WoL cleanup (Tim Hockin)
- * Magic number cleanup (Tim Hockin)
- * Don't reload EEPROM on every reset (Tim Hockin)
- * Save and restore EEPROM state across reset (Tim Hockin)
- * MDIO Cleanup (Tim Hockin)
- * Reformat register offsets/bits (jgarzik)
-
- version 1.0.12:
- * ETHTOOL_* further support (Tim Hockin)
-
- version 1.0.13:
- * ETHTOOL_[G]EEPROM support (Tim Hockin)
-
- version 1.0.13:
- * crc cleanup (Matt Domsch <Matt_Domsch@dell.com>)
-
- version 1.0.14:
- * Cleanup some messages and autoneg in ethtool (Tim Hockin)
-
- version 1.0.15:
- * Get rid of cable_magic flag
- * use new (National provided) solution for cable magic issue
-
- version 1.0.16:
- * call netdev_rx() for RxErrors (Manfred Spraul)
- * formatting and cleanups
- * change options and full_duplex arrays to be zero
- initialized
- * enable only the WoL and PHY interrupts in wol mode
-
- version 1.0.17:
- * only do cable_magic on 83815 and early 83816 (Tim Hockin)
- * create a function for rx refill (Manfred Spraul)
- * combine drain_ring and init_ring (Manfred Spraul)
- * oom handling (Manfred Spraul)
- * hands_off instead of playing with netif_device_{de,a}ttach
- (Manfred Spraul)
- * be sure to write the MAC back to the chip (Manfred Spraul)
- * lengthen EEPROM timeout, and always warn about timeouts
- (Manfred Spraul)
- * comments update (Manfred)
- * do the right thing on a phy-reset (Manfred and Tim)
-
TODO:
* big endian support with CFG:BEM instead of cpu_to_le32
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -166,8 +54,8 @@
#include <asm/uaccess.h>
#define DRV_NAME "natsemi"
-#define DRV_VERSION "1.07+LK1.0.17"
-#define DRV_RELDATE "Sep 27, 2002"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "Sept 11, 2006"
#define RX_OFFSET 2
@@ -226,7 +114,6 @@ static int full_duplex[MAX_UNITS];
NATSEMI_PG1_NREGS)
#define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */
#define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32))
-#define NATSEMI_DEF_EEPROM_SIZE 24 /* 12 16-bit values */
/* Buffer sizes:
* The nic writes 32-bit values, even if the upper bytes of
@@ -256,9 +143,9 @@ module_param_array(options, int, NULL, 0);
module_param_array(full_duplex, int, NULL, 0);
MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)");
MODULE_PARM_DESC(debug, "DP8381x default debug level");
-MODULE_PARM_DESC(rx_copybreak,
+MODULE_PARM_DESC(rx_copybreak,
"DP8381x copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options,
+MODULE_PARM_DESC(options,
"DP8381x: Bits 0-3: media type, bit 17: full duplex");
MODULE_PARM_DESC(full_duplex, "DP8381x full duplex setting(s) (1)");
@@ -344,18 +231,6 @@ None characterised.
-enum pcistuff {
- PCI_USES_IO = 0x01,
- PCI_USES_MEM = 0x02,
- PCI_USES_MASTER = 0x04,
- PCI_ADDR0 = 0x08,
- PCI_ADDR1 = 0x10,
-};
-
-/* MMIO operations required */
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-
-
/*
* Support for fibre connections on Am79C874:
* This phy needs a special setup when connected to a fibre cable.
@@ -363,22 +238,25 @@ enum pcistuff {
*/
#define PHYID_AM79C874 0x0022561b
-#define MII_MCTRL 0x15 /* mode control register */
-#define MII_FX_SEL 0x0001 /* 100BASE-FX (fiber) */
-#define MII_EN_SCRM 0x0004 /* enable scrambler (tp) */
+enum {
+ MII_MCTRL = 0x15, /* mode control register */
+ MII_FX_SEL = 0x0001, /* 100BASE-FX (fiber) */
+ MII_EN_SCRM = 0x0004, /* enable scrambler (tp) */
+};
+
-
/* array of board data directly indexed by pci_tbl[x].driver_data */
static const struct {
const char *name;
unsigned long flags;
+ unsigned int eeprom_size;
} natsemi_pci_info[] __devinitdata = {
- { "NatSemi DP8381[56]", PCI_IOTYPE },
+ { "NatSemi DP8381[56]", 0, 24 },
};
-static struct pci_device_id natsemi_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_83815, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, },
+static const struct pci_device_id natsemi_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_NS, 0x0020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, natsemi_pci_tbl);
@@ -536,7 +414,7 @@ enum TxConfig_bits {
TxCarrierIgn = 0x80000000
};
-/*
+/*
* Tx Configuration:
* - 256 byte DMA burst length
* - fill threshold 512 bytes (i.e. restart DMA when 512 bytes are free)
@@ -769,7 +647,7 @@ static void enable_wol_mode(struct net_device *dev, int enable_intr);
static int netdev_close(struct net_device *dev);
static int netdev_get_regs(struct net_device *dev, u8 *buf);
static int netdev_get_eeprom(struct net_device *dev, u8 *buf);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
static inline void __iomem *ns_ioaddr(struct net_device *dev)
{
@@ -794,7 +672,7 @@ static void move_int_phy(struct net_device *dev, int addr)
void __iomem *ioaddr = ns_ioaddr(dev);
int target = 31;
- /*
+ /*
* The internal phy is visible on the external mii bus. Therefore we must
* move it away before we can send commands to an external phy.
* There are two addresses we must avoid:
@@ -813,6 +691,42 @@ static void move_int_phy(struct net_device *dev, int addr)
udelay(1);
}
+static void __devinit natsemi_init_media (struct net_device *dev)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ u32 tmp;
+
+ netif_carrier_off(dev);
+
+ /* get the initial settings from hardware */
+ tmp = mdio_read(dev, MII_BMCR);
+ np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10;
+ np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF;
+ np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
+ np->advertising= mdio_read(dev, MII_ADVERTISE);
+
+ if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
+ && netif_msg_probe(np)) {
+ printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
+ "10%s %s duplex.\n",
+ pci_name(np->pci_dev),
+ (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
+ "enabled, advertise" : "disabled, force",
+ (np->advertising &
+ (ADVERTISE_100FULL|ADVERTISE_100HALF))?
+ "0" : "",
+ (np->advertising &
+ (ADVERTISE_100FULL|ADVERTISE_10FULL))?
+ "full" : "half");
+ }
+ if (netif_msg_probe(np))
+ printk(KERN_INFO
+ "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
+ pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
+ np->advertising);
+
+}
+
static int __devinit natsemi_probe1 (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -852,8 +766,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
iosize = pci_resource_len(pdev, pcibar);
irq = pdev->irq;
- if (natsemi_pci_info[chip_idx].flags & PCI_USES_MASTER)
- pci_set_master(pdev);
+ pci_set_master(pdev);
dev = alloc_etherdev(sizeof (struct netdev_private));
if (!dev)
@@ -892,7 +805,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
np->msg_enable = (debug >= 0) ? (1<<debug)-1 : NATSEMI_DEF_MSG;
np->hands_off = 0;
np->intr_status = 0;
- np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE;
+ np->eeprom_size = natsemi_pci_info[chip_idx].eeprom_size;
/* Initial port:
* - If the nic was configured to use an external phy and if find_mii
@@ -957,34 +870,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev,
if (mtu)
dev->mtu = mtu;
- netif_carrier_off(dev);
-
- /* get the initial settings from hardware */
- tmp = mdio_read(dev, MII_BMCR);
- np->speed = (tmp & BMCR_SPEED100)? SPEED_100 : SPEED_10;
- np->duplex = (tmp & BMCR_FULLDPLX)? DUPLEX_FULL : DUPLEX_HALF;
- np->autoneg = (tmp & BMCR_ANENABLE)? AUTONEG_ENABLE: AUTONEG_DISABLE;
- np->advertising= mdio_read(dev, MII_ADVERTISE);
-
- if ((np->advertising & ADVERTISE_ALL) != ADVERTISE_ALL
- && netif_msg_probe(np)) {
- printk(KERN_INFO "natsemi %s: Transceiver default autonegotiation %s "
- "10%s %s duplex.\n",
- pci_name(np->pci_dev),
- (mdio_read(dev, MII_BMCR) & BMCR_ANENABLE)?
- "enabled, advertise" : "disabled, force",
- (np->advertising &
- (ADVERTISE_100FULL|ADVERTISE_100HALF))?
- "0" : "",
- (np->advertising &
- (ADVERTISE_100FULL|ADVERTISE_10FULL))?
- "full" : "half");
- }
- if (netif_msg_probe(np))
- printk(KERN_INFO
- "natsemi %s: Transceiver status %#04x advertising %#04x.\n",
- pci_name(np->pci_dev), mdio_read(dev, MII_BMSR),
- np->advertising);
+ natsemi_init_media(dev);
/* save the silicon revision for later querying */
np->srr = readl(ioaddr + SiliconRev);
@@ -1209,7 +1095,7 @@ static void init_phy_fixup(struct net_device *dev)
tmp |= BMCR_SPEED100;
if (np->duplex == DUPLEX_FULL)
tmp |= BMCR_FULLDPLX;
- /*
+ /*
* Note: there is no good way to inform the link partner
* that our capabilities changed. The user has to unplug
* and replug the network cable after some changes, e.g.
@@ -1350,7 +1236,7 @@ static int switch_port_internal(struct net_device *dev)
writel(cfg, ioaddr + ChipConfig);
readl(ioaddr + ChipConfig);
udelay(1);
-
+
/* 2) reset the internal phy: */
bmcr = readw(ioaddr+BasicControl+(MII_BMCR<<2));
writel(bmcr | BMCR_RESET, ioaddr+BasicControl+(MII_BMCR<<2));
@@ -1390,7 +1276,7 @@ static int find_mii(struct net_device *dev)
/* Switch to external phy */
did_switch = switch_port_external(dev);
-
+
/* Scan the possible phy addresses:
*
* PHY address 0 means that the phy is in isolate mode. Not yet
@@ -1577,7 +1463,7 @@ static int netdev_open(struct net_device *dev)
/* Reset the chip, just in case. */
natsemi_reset(dev);
- i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);
if (i) return i;
if (netif_msg_ifup(np))
@@ -1687,7 +1573,7 @@ static void check_link(struct net_device *dev)
void __iomem * ioaddr = ns_ioaddr(dev);
int duplex;
u16 bmsr;
-
+
/* The link status field is latched: it remains low after a temporary
* link failure until it's read. We need the current link status,
* thus read twice.
@@ -2210,7 +2096,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
if (np->hands_off)
return IRQ_NONE;
-
+
/* Reading automatically acknowledges. */
np->intr_status = readl(ioaddr + IntrStatus);
@@ -2220,7 +2106,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
dev->name, np->intr_status,
readl(ioaddr + IntrMask));
- if (!np->intr_status)
+ if (!np->intr_status)
return IRQ_NONE;
prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]);
@@ -2255,13 +2141,13 @@ static int natsemi_poll(struct net_device *dev, int *budget)
/* Abnormal error summary/uncommon events handlers. */
if (np->intr_status & IntrAbnormalSummary)
netdev_error(dev, np->intr_status);
-
+
if (np->intr_status &
(IntrRxDone | IntrRxIntr | RxStatusFIFOOver |
IntrRxErr | IntrRxOverrun)) {
netdev_rx(dev, &work_done, work_to_do);
}
-
+
*budget -= work_done;
dev->quota -= work_done;
@@ -2501,9 +2387,6 @@ static void __set_rx_mode(struct net_device *dev)
u32 rx_mode;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode = RxFilterEnable | AcceptBroadcast
| AcceptAllMulticast | AcceptAllPhys | AcceptMyPhys;
} else if ((dev->mc_count > multicast_filter_limit)
@@ -2690,7 +2573,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8
return res;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = get_drvinfo,
.get_regs_len = get_regs_len,
.get_eeprom_len = get_eeprom_len,
@@ -2861,7 +2744,7 @@ static int netdev_get_ecmd(struct net_device *dev, struct ethtool_cmd *ecmd)
* phy, even if the internal phy is used. This is necessary
* to work around a deficiency of the ethtool interface:
* It's only possible to query the settings of the active
- * port. Therefore
+ * port. Therefore
* # ethtool -s ethX port mii
* actually sends an ioctl to switch to port mii with the
* settings that are used for the current active port.
@@ -3360,7 +3243,7 @@ static int __init natsemi_init_mod (void)
printk(version);
#endif
- return pci_module_init (&natsemi_driver);
+ return pci_register_driver(&natsemi_driver);
}
static void __exit natsemi_exit_mod (void)
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index 7ea3d596ac3..eb893d7e883 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -593,7 +593,7 @@ retry:
return;
}
-
+
#ifdef MODULE
#define MAX_NE_CARDS 1 /* Max number of NE cards per module */
static struct net_device *dev_ne[MAX_NE_CARDS];
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 963a11fa9fe..787aa422152 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -160,7 +160,7 @@ static void ne_block_input(struct net_device *dev, int count,
static void ne_block_output(struct net_device *dev, const int count,
const unsigned char *buf, const int start_page);
-
+
/* Probe for various non-shared-memory ethercards.
NEx000-clone boards have a Station Address PROM (SAPROM) in the packet
@@ -807,7 +807,7 @@ retry:
return;
}
-
+
#ifdef MODULE
#define MAX_NE_CARDS 4 /* Max number of NE cards per module */
static struct net_device *dev_ne[MAX_NE_CARDS];
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index eebf5f02b47..5fccfea66d8 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -28,7 +28,7 @@
- added support for Arco Electronics AE/2-card (experimental)
Mon Sep 14 09:53:42 CET 1998 (David Weinehall)
- - added support for Compex ENET-16MC/P (experimental)
+ - added support for Compex ENET-16MC/P (experimental)
Tue Sep 15 16:21:12 CET 1998 (David Weinehall, Magnus Jonsson, Tomas Ogren)
- Miscellaneous bugfixes
@@ -44,11 +44,11 @@
- Version# bump
Mon Nov 16 15:28:23 CET 1998 (Wim Dumon)
- - pass 'dev' as last parameter of request_irq in stead of 'NULL'
+ - pass 'dev' as last parameter of request_irq in stead of 'NULL'
Wed Feb 7 21:24:00 CET 2001 (Alfred Arnold)
- added support for the D-Link DE-320CT
-
+
* WARNING
-------
This is alpha-test software. It is not guaranteed to work. As a
@@ -150,9 +150,9 @@ static void ne_block_output(struct net_device *dev, const int count,
/*
- * special code to read the DE-320's MAC address EEPROM. In contrast to a
+ * special code to read the DE-320's MAC address EEPROM. In contrast to a
* standard NE design, this is a serial EEPROM (93C46) that has to be read
- * bit by bit. The EEPROM cotrol port at base + 0x1e has the following
+ * bit by bit. The EEPROM cotrol port at base + 0x1e has the following
* layout:
*
* Bit 0 = Data out (read from EEPROM)
@@ -218,7 +218,7 @@ static unsigned int __init dlink_get_eeprom(unsigned int eeaddr, unsigned int ad
{
int z;
unsigned int value = 0;
-
+
/* pull the CS line low for a moment. This resets the EEPROM-
internal logic, and makes it ready for a new command. */
@@ -253,23 +253,23 @@ static int __init do_ne2_probe(struct net_device *dev)
SET_MODULE_OWNER(dev);
- /* Do not check any supplied i/o locations.
+ /* Do not check any supplied i/o locations.
POS registers usually don't fail :) */
- /* MCA cards have POS registers.
- Autodetecting MCA cards is extremely simple.
+ /* MCA cards have POS registers.
+ Autodetecting MCA cards is extremely simple.
Just search for the card. */
for(i = 0; (ne2_adapters[i].name != NULL) && !adapter_found; i++) {
- current_mca_slot =
+ current_mca_slot =
mca_find_unused_adapter(ne2_adapters[i].id, 0);
if((current_mca_slot != MCA_NOTFOUND) && !adapter_found) {
int res;
- mca_set_adapter_name(current_mca_slot,
+ mca_set_adapter_name(current_mca_slot,
ne2_adapters[i].name);
mca_mark_as_used(current_mca_slot);
-
+
res = ne2_probe1(dev, current_mca_slot);
if (res)
mca_mark_as_unused(current_mca_slot);
@@ -307,7 +307,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" );
len += sprintf(buf+len, "Driver written by Wim Dumon ");
- len += sprintf(buf+len, "<wimpie@kotnet.org>\n");
+ len += sprintf(buf+len, "<wimpie@kotnet.org>\n");
len += sprintf(buf+len, "Modified by ");
len += sprintf(buf+len, "David Weinehall <tao@acc.umu.se>\n");
len += sprintf(buf+len, "and by Magnus Jonsson <bigfoot@acc.umu.se>\n");
@@ -316,8 +316,8 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev)
len += sprintf(buf+len, "IRQ : %d\n", dev->irq);
#define HW_ADDR(i) dev->dev_addr[i]
- len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
- HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
+ len += sprintf(buf+len, "HW addr : %x:%x:%x:%x:%x:%x\n",
+ HW_ADDR(0), HW_ADDR(1), HW_ADDR(2),
HW_ADDR(3), HW_ADDR(4), HW_ADDR(5) );
#undef HW_ADDR
@@ -370,7 +370,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
#ifndef CRYNWR_WAY
/* Reset the card the way they do it in the Crynwr packet driver */
- for (i=0; i<8; i++)
+ for (i=0; i<8; i++)
outb(0x0, base_addr + NE_RESET);
inb(base_addr + NE_RESET);
outb(0x21, base_addr + NE_CMD);
@@ -388,10 +388,10 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
#else /* _I_ never tested it this way .. Go ahead and try ...*/
/* Reset card. Who knows what dain-bramaged state it was left in. */
- {
+ {
unsigned long reset_start_time = jiffies;
- /* DON'T change these to inb_p/outb_p or reset will fail on
+ /* DON'T change these to inb_p/outb_p or reset will fail on
clones.. */
outb(inb(base_addr + NE_RESET), base_addr + NE_RESET);
@@ -408,16 +408,16 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
/* Read the 16 bytes of station address PROM.
- We must first initialize registers, similar to
+ We must first initialize registers, similar to
NS8390_init(eifdev, 0).
We can't reliably read the SAPROM address without this.
(I learned the hard way!). */
{
- struct {
- unsigned char value, offset;
+ struct {
+ unsigned char value, offset;
} program_seq[] = {
/* Select page 0 */
- {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD},
+ {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD},
{0x49, EN0_DCFG}, /* Set WORD-wide (0x49) access. */
{0x00, EN0_RCNTLO}, /* Clear the count regs. */
{0x00, EN0_RCNTHI},
@@ -433,7 +433,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
};
for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
- outb_p(program_seq[i].value, base_addr +
+ outb_p(program_seq[i].value, base_addr +
program_seq[i].offset);
}
@@ -464,7 +464,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
share and the board will usually be enabled. */
retval = request_irq(dev->irq, ei_interrupt, 0, DRV_NAME, dev);
if (retval) {
- printk (" unable to get IRQ %d (irqval=%d).\n",
+ printk (" unable to get IRQ %d (irqval=%d).\n",
dev->irq, retval);
goto out;
}
@@ -496,9 +496,9 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
ei_status.block_input = &ne_block_input;
ei_status.block_output = &ne_block_output;
ei_status.get_8390_hdr = &ne_get_8390_hdr;
-
+
ei_status.priv = slot;
-
+
dev->open = &ne_open;
dev->stop = &ne_close;
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -538,7 +538,7 @@ static void ne_reset_8390(struct net_device *dev)
{
unsigned long reset_start_time = jiffies;
- if (ei_debug > 1)
+ if (ei_debug > 1)
printk("resetting the 8390 t=%ld...", jiffies);
/* DON'T change these to inb_p/outb_p or reset will fail on clones. */
@@ -550,7 +550,7 @@ static void ne_reset_8390(struct net_device *dev)
/* This check _should_not_ be necessary, omit eventually. */
while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0)
if (time_after(jiffies, reset_start_time + 2*HZ/100)) {
- printk("%s: ne_reset_8390() did not complete.\n",
+ printk("%s: ne_reset_8390() did not complete.\n",
dev->name);
break;
}
@@ -561,13 +561,13 @@ static void ne_reset_8390(struct net_device *dev)
we don't need to be concerned with ring wrap as the header will be at
the start of a page, so we optimize accordingly. */
-static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
+static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
int ring_page)
{
int nic_base = dev->base_addr;
- /* This *shouldn't* happen.
+ /* This *shouldn't* happen.
If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_get_8390_hdr "
@@ -585,10 +585,10 @@ static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
if (ei_status.word16)
- insw(NE_BASE + NE_DATAPORT, hdr,
+ insw(NE_BASE + NE_DATAPORT, hdr,
sizeof(struct e8390_pkt_hdr)>>1);
else
- insb(NE_BASE + NE_DATAPORT, hdr,
+ insb(NE_BASE + NE_DATAPORT, hdr,
sizeof(struct e8390_pkt_hdr));
outb_p(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
@@ -600,7 +600,7 @@ static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
hints. The NEx000 doesn't share the on-board packet memory -- you have
to put the packet out through the "remote DMA" dataport using outb. */
-static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb,
+static void ne_block_input(struct net_device *dev, int count, struct sk_buff *skb,
int ring_offset)
{
#ifdef NE_SANITY_CHECK
@@ -609,7 +609,7 @@ static void ne_block_input(struct net_device *dev, int count, struct sk_buff *sk
int nic_base = dev->base_addr;
char *buf = skb->data;
- /* This *shouldn't* happen.
+ /* This *shouldn't* happen.
If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_block_input "
@@ -677,7 +677,7 @@ static void ne_block_output(struct net_device *dev, int count,
if (ei_status.word16 && (count & 0x01))
count++;
- /* This *shouldn't* happen.
+ /* This *shouldn't* happen.
If it does, it's the last thing you'll see */
if (ei_status.dmaing) {
printk("%s: DMAing conflict in ne_block_output."
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index ced9fdb8335..589785d1e76 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -175,9 +175,9 @@ static void ne2k_pci_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void ne2k_pci_block_output(struct net_device *dev, const int count,
const unsigned char *buf, const int start_page);
-static struct ethtool_ops ne2k_pci_ethtool_ops;
+static const struct ethtool_ops ne2k_pci_ethtool_ops;
+
-
/* There is no room in the standard 8390 structure for extra info we need,
so we build a meta/outer-wrapper structure.. */
@@ -231,12 +231,12 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
irq = pdev->irq;
if (!ioaddr || ((pci_resource_flags (pdev, 0) & IORESOURCE_IO) == 0)) {
- printk (KERN_ERR PFX "no I/O resource at PCI BAR #0\n");
+ dev_err(&pdev->dev, "no I/O resource at PCI BAR #0\n");
return -ENODEV;
}
if (request_region (ioaddr, NE_IO_EXTENT, DRV_NAME) == NULL) {
- printk (KERN_ERR PFX "I/O resource 0x%x @ 0x%lx busy\n",
+ dev_err(&pdev->dev, "I/O resource 0x%x @ 0x%lx busy\n",
NE_IO_EXTENT, ioaddr);
return -EBUSY;
}
@@ -263,7 +263,7 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
/* Allocate net_device, dev->priv; fill in 8390 specific dev fields. */
dev = alloc_ei_netdev();
if (!dev) {
- printk (KERN_ERR PFX "cannot allocate ethernet device\n");
+ dev_err(&pdev->dev, "cannot allocate ethernet device\n");
goto err_out_free_res;
}
SET_MODULE_OWNER(dev);
@@ -281,7 +281,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev,
while ((inb(ioaddr + EN0_ISR) & ENISR_RESET) == 0)
/* Limit wait: '2' avoids jiffy roll-over. */
if (jiffies - reset_start_time > 2) {
- printk(KERN_ERR PFX "Card failure (no reset ack).\n");
+ dev_err(&pdev->dev,
+ "Card failure (no reset ack).\n");
goto err_out_free_netdev;
}
@@ -385,7 +386,7 @@ err_out_free_res:
}
-/*
+/*
* Magic incantation sequence for full duplex on the supported cards.
*/
static inline int set_realtek_fdx(struct net_device *dev)
@@ -410,7 +411,7 @@ static inline int set_holtek_fdx(struct net_device *dev)
static int ne2k_pci_set_fdx(struct net_device *dev)
{
- if (ei_status.ne2k_flags & REALTEK_FDX)
+ if (ei_status.ne2k_flags & REALTEK_FDX)
return set_realtek_fdx(dev);
else if (ei_status.ne2k_flags & HOLTEK_FDX)
return set_holtek_fdx(dev);
@@ -420,7 +421,7 @@ static int ne2k_pci_set_fdx(struct net_device *dev)
static int ne2k_pci_open(struct net_device *dev)
{
- int ret = request_irq(dev->irq, ei_interrupt, SA_SHIRQ, dev->name, dev);
+ int ret = request_irq(dev->irq, ei_interrupt, IRQF_SHARED, dev->name, dev);
if (ret)
return ret;
@@ -634,7 +635,7 @@ static void ne2k_pci_get_drvinfo(struct net_device *dev,
strcpy(info->bus_info, pci_name(pci_dev));
}
-static struct ethtool_ops ne2k_pci_ethtool_ops = {
+static const struct ethtool_ops ne2k_pci_ethtool_ops = {
.get_drvinfo = ne2k_pci_get_drvinfo,
.get_tx_csum = ethtool_op_get_tx_csum,
.get_sg = ethtool_op_get_sg,
@@ -701,7 +702,7 @@ static int __init ne2k_pci_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init (&ne2k_driver);
+ return pci_register_driver(&ne2k_driver);
}
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 73501d84658..d6632897542 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -14,10 +14,10 @@
2) The existing myriad of other Linux 8390 drivers by Donald Becker.
3) Info for getting IRQ and sh-mem gleaned from the EISA cfg file
- The NE3210 is an EISA shared memory NS8390 implementation. Shared
+ The NE3210 is an EISA shared memory NS8390 implementation. Shared
memory address > 1MB should work with this driver.
- Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
+ Note that the .cfg file (3/11/93, v1.0) has AUI and BNC switched
around (or perhaps there are some defective/backwards cards ???)
This driver WILL NOT WORK FOR THE NE3200 - it is completely different
@@ -133,7 +133,7 @@ static int __init ne3210_eisa_probe (struct device *device)
edev->slot, ifmap[port_index]);
for(i = 0; i < ETHER_ADDR_LEN; i++)
printk(" %02x", (dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i)));
-
+
/* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */
dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07];
@@ -161,13 +161,13 @@ static int __init ne3210_eisa_probe (struct device *device)
goto out3;
}
}
-
+
if (!request_mem_region (phys_mem, NE3210_STOP_PG*0x100, DRV_NAME)) {
printk ("ne3210.c: Unable to request shared memory at physical address %#lx\n",
phys_mem);
goto out3;
}
-
+
printk("%dkB memory at physical address %#lx\n",
NE3210_STOP_PG/4, phys_mem);
@@ -210,7 +210,7 @@ static int __init ne3210_eisa_probe (struct device *device)
if ((retval = register_netdev (dev)))
goto out5;
-
+
NS8390_init(dev, 0);
return 0;
@@ -226,7 +226,7 @@ static int __init ne3210_eisa_probe (struct device *device)
release_region (ioaddr, NE3210_IO_EXTENT);
out:
free_netdev (dev);
-
+
return retval;
}
@@ -289,7 +289,7 @@ ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_
hdr->count = (hdr->count + 3) & ~3; /* Round up allocation. */
}
-/*
+/*
* Block input and output are easy on shared memory ethercards, the only
* complication is when the ring buffer wraps. The count will already
* be rounded up to a doubleword value via ne3210_get_8390_hdr() above.
@@ -343,6 +343,7 @@ static struct eisa_device_id ne3210_ids[] = {
{ "NVL1801" },
{ "" },
};
+MODULE_DEVICE_TABLE(eisa, ne3210_ids);
static struct eisa_driver ne3210_eisa_driver = {
.id_table = ne3210_ids,
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index b92430c4e3a..30ed9a5a40e 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -223,7 +222,7 @@ static int netx_eth_open(struct net_device *ndev)
struct netx_eth_priv *priv = netdev_priv(ndev);
if (request_irq
- (ndev->irq, &netx_eth_interrupt, SA_SHIRQ, ndev->name, ndev))
+ (ndev->irq, &netx_eth_interrupt, IRQF_SHARED, ndev->name, ndev))
return -EAGAIN;
writel(ndev->dev_addr[0] |
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index a68bf474f6e..383c690eefe 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -1,17 +1,12 @@
/* ni5010.c: A network driver for the MiCom-Interlan NI5010 ethercard.
*
- * Copyright 1996,1997 Jan-Pascal van Best and Andreas Mohr.
+ * Copyright 1996,1997,2006 Jan-Pascal van Best and Andreas Mohr.
*
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
* The authors may be reached as:
- * jvbest@wi.leidenuniv.nl a.mohr@mailto.de
- * or by snail mail as
- * Jan-Pascal van Best Andreas Mohr
- * Klikspaanweg 58-4 Stauferstr. 6
- * 2324 LZ Leiden D-71272 Renningen
- * The Netherlands Germany
+ * janpascal@vanbest.org andi@lisas.de
*
* Sources:
* Donald Becker's "skeleton.c"
@@ -27,8 +22,9 @@
* 970503 v0.93: Fixed auto-irq failure on warm reboot (JB)
* 970623 v1.00: First kernel version (AM)
* 970814 v1.01: Added detection of onboard receive buffer size (AM)
+ * 060611 v1.02: slight cleanup: email addresses, driver modernization.
* Bugs:
- * - None known...
+ * - not SMP-safe (no locking of I/O accesses)
* - Note that you have to patch ifconfig for the new /proc/net/dev
* format. It gives incorrect stats otherwise.
*
@@ -39,15 +35,15 @@
* Complete merge with Andreas' driver
* Implement ring buffers (Is this useful? You can't squeeze
* too many packet in a 2k buffer!)
- * Implement DMA (Again, is this useful? Some docs says DMA is
+ * Implement DMA (Again, is this useful? Some docs say DMA is
* slower than programmed I/O)
*
* Compile with:
* gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ \
- * -DMODULE -c ni5010.c
+ * -DMODULE -c ni5010.c
*
* Insert with e.g.:
- * insmod ni5010.o io=0x300 irq=5
+ * insmod ni5010.ko io=0x300 irq=5
*/
#include <linux/module.h>
@@ -69,15 +65,15 @@
#include "ni5010.h"
-static const char *boardname = "NI5010";
-static char *version =
- "ni5010.c: v1.00 06/23/97 Jan-Pascal van Best and Andreas Mohr\n";
-
+static const char boardname[] = "NI5010";
+static char version[] __initdata =
+ "ni5010.c: v1.02 20060611 Jan-Pascal van Best and Andreas Mohr\n";
+
/* bufsize_rcv == 0 means autoprobing */
static unsigned int bufsize_rcv;
-#define jumpered_interrupts /* IRQ line jumpered on board */
-#undef jumpered_dma /* No DMA used */
+#define JUMPERED_INTERRUPTS /* IRQ line jumpered on board */
+#undef JUMPERED_DMA /* No DMA used */
#undef FULL_IODETECT /* Only detect in portlist */
#ifndef FULL_IODETECT
@@ -232,7 +228,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
* - Andreas
*/
- PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
+ PRINTK2((KERN_DEBUG "%s: entering ni5010_probe1(%#3x)\n",
dev->name, ioaddr));
if (inb(ioaddr+0) == 0xff)
@@ -281,7 +277,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name));
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
if (dev->irq == 0xff)
;
else if (dev->irq < 2) {
@@ -305,7 +301,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
} else if (dev->irq == 2) {
dev->irq = 9;
}
-#endif /* jumpered_irq */
+#endif /* JUMPERED_INTERRUPTS */
PRINTK2((KERN_DEBUG "%s: I/O #9 passed!\n", dev->name));
/* DMA is not supported (yet?), so no use detecting it */
@@ -334,9 +330,9 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
outw(0, IE_GP); /* Point GP at start of packet */
outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */
}
- printk("// bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
+ printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE);
memset(dev->priv, 0, sizeof(struct ni5010_local));
-
+
dev->open = ni5010_open;
dev->stop = ni5010_close;
dev->hard_start_xmit = ni5010_send_packet;
@@ -354,33 +350,31 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr)
outb(0xff, EDLC_XCLR); /* Kill all pending xmt interrupts */
printk(KERN_INFO "%s: NI5010 found at 0x%x, using IRQ %d", dev->name, ioaddr, dev->irq);
- if (dev->dma) printk(" & DMA %d", dev->dma);
+ if (dev->dma)
+ printk(" & DMA %d", dev->dma);
printk(".\n");
-
- printk(KERN_INFO "Join the NI5010 driver development team!\n");
- printk(KERN_INFO "Mail to a.mohr@mailto.de or jvbest@wi.leidenuniv.nl\n");
return 0;
out:
release_region(dev->base_addr, NI5010_IO_EXTENT);
return err;
}
-/*
+/*
* Open/initialize the board. This is called (in the current kernel)
* sometime after booting when the 'ifconfig' program is run.
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
+ * there is a non-reboot way to recover if something goes wrong.
*/
-
+
static int ni5010_open(struct net_device *dev)
{
int ioaddr = dev->base_addr;
int i;
- PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
-
+ PRINTK2((KERN_DEBUG "%s: entering ni5010_open()\n", dev->name));
+
if (request_irq(dev->irq, &ni5010_interrupt, 0, boardname, dev)) {
printk(KERN_WARNING "%s: Cannot get irq %#2x\n", dev->name, dev->irq);
return -EAGAIN;
@@ -390,13 +384,13 @@ static int ni5010_open(struct net_device *dev)
* Always allocate the DMA channel after the IRQ,
* and clean up on failure.
*/
-#ifdef jumpered_dma
+#ifdef JUMPERED_DMA
if (request_dma(dev->dma, cardname)) {
printk(KERN_WARNING "%s: Cannot get dma %#2x\n", dev->name, dev->dma);
free_irq(dev->irq, NULL);
return -EAGAIN;
}
-#endif /* jumpered_dma */
+#endif /* JUMPERED_DMA */
PRINTK3((KERN_DEBUG "%s: passed open() #2\n", dev->name));
/* Reset the hardware here. Don't forget to set the station address. */
@@ -410,21 +404,21 @@ static int ni5010_open(struct net_device *dev)
for(i = 0;i < 6; i++) {
outb(dev->dev_addr[i], EDLC_ADDR + i);
}
-
- PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
+
+ PRINTK3((KERN_DEBUG "%s: Initialising ni5010\n", dev->name));
outb(0, EDLC_XMASK); /* No xmit interrupts for now */
- outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
+ outb(XMD_IG_PAR | XMD_T_MODE | XMD_LBC, EDLC_XMODE);
/* Normal packet xmit mode */
outb(0xff, EDLC_XCLR); /* Clear all pending xmit interrupts */
outb(RMD_BROADCAST, EDLC_RMODE);
/* Receive broadcast and normal packets */
reset_receiver(dev); /* Ready ni5010 for receiving packets */
-
+
outb(0, EDLC_RESET); /* Un-reset the ni5010 */
-
+
netif_start_queue(dev);
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
+
+ if (NI5010_DEBUG) ni5010_show_registers(dev);
PRINTK((KERN_DEBUG "%s: open successful\n", dev->name));
return 0;
@@ -433,7 +427,7 @@ static int ni5010_open(struct net_device *dev)
static void reset_receiver(struct net_device *dev)
{
int ioaddr = dev->base_addr;
-
+
PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name));
outw(0, IE_GP); /* Receive packet at start of buffer */
outb(0xff, EDLC_RCLR); /* Clear all pending rcv interrupts */
@@ -459,10 +453,10 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name));
- /*
+ /*
* Block sending
*/
-
+
netif_stop_queue(dev);
hardware_send_packet(dev, (unsigned char *)skb->data, skb->len, length-skb->len);
dev->trans_start = jiffies;
@@ -470,9 +464,9 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-/*
+/*
* The typical workload of the driver:
- * Handle the network interface interrupts.
+ * Handle the network interface interrupts.
*/
static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
@@ -485,11 +479,11 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
-
+
spin_lock(&lp->lock);
- status = inb(IE_ISTAT);
+ status = inb(IE_ISTAT);
PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status));
-
+
if ((status & IS_R_INT) == 0) ni5010_rx(dev);
if ((status & IS_X_INT) == 0) {
@@ -501,8 +495,8 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
outb(0, IE_DMA_RST); /* Reset DMA int */
}
- if (!xmit_was_error)
- reset_receiver(dev);
+ if (!xmit_was_error)
+ reset_receiver(dev);
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
@@ -511,7 +505,7 @@ static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void dump_packet(void *buf, int len)
{
int i;
-
+
printk(KERN_DEBUG "Packet length = %#4x\n", len);
for (i = 0; i < len; i++){
if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i);
@@ -520,7 +514,7 @@ static void dump_packet(void *buf, int len)
if (i % 16 == 15) printk("\n");
}
printk("\n");
-
+
return;
}
@@ -532,12 +526,12 @@ static void ni5010_rx(struct net_device *dev)
unsigned char rcv_stat;
struct sk_buff *skb;
int i_pkt_size;
-
- PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
-
+
+ PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name));
+
rcv_stat = inb(EDLC_RSTAT);
- PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
-
+ PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat));
+
if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) {
PRINTK((KERN_INFO "%s: receive error.\n", dev->name));
lp->stats.rx_errors++;
@@ -548,12 +542,12 @@ static void ni5010_rx(struct net_device *dev)
outb(0xff, EDLC_RCLR); /* Clear the interrupt */
return;
}
-
+
outb(0xff, EDLC_RCLR); /* Clear the interrupt */
i_pkt_size = inw(IE_RCNT);
if (i_pkt_size > ETH_FRAME_LEN || i_pkt_size < 10 ) {
- PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
+ PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n",
dev->name, i_pkt_size));
lp->stats.rx_errors++;
lp->stats.rx_length_errors++;
@@ -567,27 +561,27 @@ static void ni5010_rx(struct net_device *dev)
lp->stats.rx_dropped++;
return;
}
-
+
skb->dev = dev;
skb_reserve(skb, 2);
-
+
/* Read packet into buffer */
outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */
outw(0, IE_GP); /* Seek to beginning of packet */
- insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
-
- if (NI5010_DEBUG >= 4)
- dump_packet(skb->data, skb->len);
-
+ insb(IE_RBUF, skb_put(skb, i_pkt_size), i_pkt_size);
+
+ if (NI5010_DEBUG >= 4)
+ dump_packet(skb->data, skb->len);
+
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
lp->stats.rx_packets++;
lp->stats.rx_bytes += i_pkt_size;
- PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
+ PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n",
dev->name, i_pkt_size));
-
+
}
static int process_xmt_interrupt(struct net_device *dev)
@@ -600,12 +594,12 @@ static int process_xmt_interrupt(struct net_device *dev)
xmit_stat = inb(EDLC_XSTAT);
PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat));
-
+
outb(0, EDLC_XMASK); /* Disable xmit IRQ's */
outb(0xff, EDLC_XCLR); /* Clear all pending xmit IRQ's */
-
+
if (xmit_stat & XS_COLL){
- PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
+ PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n",
dev->name));
outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP);
/* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */
@@ -620,8 +614,8 @@ static int process_xmt_interrupt(struct net_device *dev)
lp->stats.tx_packets++;
lp->stats.tx_bytes += lp->o_pkt_size;
netif_wake_queue(dev);
-
- PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
+
+ PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n",
dev->name, lp->o_pkt_size));
return 0;
@@ -633,7 +627,7 @@ static int ni5010_close(struct net_device *dev)
int ioaddr = dev->base_addr;
PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));
-#ifdef jumpered_interrupts
+#ifdef JUMPERED_INTERRUPTS
free_irq(dev->irq, NULL);
#endif
/* Put card in held-RESET state */
@@ -641,7 +635,7 @@ static int ni5010_close(struct net_device *dev)
outb(RS_RESET, EDLC_RESET);
netif_stop_queue(dev);
-
+
PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname));
return 0;
@@ -654,9 +648,9 @@ static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
struct ni5010_local *lp = netdev_priv(dev);
PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name));
-
+
if (NI5010_DEBUG) ni5010_show_registers(dev);
-
+
/* cli(); */
/* Update the statistics from the device registers. */
/* We do this in the interrupt handler */
@@ -673,7 +667,7 @@ static struct net_device_stats *ni5010_get_stats(struct net_device *dev)
*/
static void ni5010_set_multicast_list(struct net_device *dev)
{
- short ioaddr = dev->base_addr;
+ short ioaddr = dev->base_addr;
PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name));
@@ -699,7 +693,7 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length,
unsigned int buf_offs;
PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name));
-
+
if (length > ETH_FRAME_LEN) {
PRINTK((KERN_WARNING "%s: packet too large, not possible\n",
dev->name));
@@ -709,11 +703,11 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length,
if (NI5010_DEBUG) ni5010_show_registers(dev);
if (inb(IE_ISTAT) & IS_EN_XMT) {
- PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
+ PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n",
dev->name));
return;
}
-
+
if (NI5010_DEBUG > 3) dump_packet(buf, length);
buf_offs = NI5010_BUFSIZE - length - pad;
@@ -729,7 +723,7 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length,
outsb(IE_XBUF, buf, length); /* Put data in buffer */
while(pad--)
outb(0, IE_XBUF);
-
+
outw(buf_offs, IE_GP); /* Rewrite where packet starts */
/* should work without that outb() (Crynwr used it) */
@@ -740,8 +734,8 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length,
spin_unlock_irqrestore(&lp->lock, flags);
netif_wake_queue(dev);
-
- if (NI5010_DEBUG) ni5010_show_registers(dev);
+
+ if (NI5010_DEBUG) ni5010_show_registers(dev);
}
static void chipset_init(struct net_device *dev, int startp)
@@ -753,7 +747,7 @@ static void chipset_init(struct net_device *dev, int startp)
static void ni5010_show_registers(struct net_device *dev)
{
int ioaddr = dev->base_addr;
-
+
PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT)));
PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK)));
PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT)));
@@ -771,7 +765,7 @@ module_param(irq, int, 0);
MODULE_PARM_DESC(io, "ni5010 I/O base address");
MODULE_PARM_DESC(irq, "ni5010 IRQ number");
-int init_module(void)
+static int __init ni5010_init_module(void)
{
PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname));
/*
@@ -792,13 +786,15 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+static void __exit ni5010_cleanup_module(void)
{
PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname));
unregister_netdev(dev_ni5010);
release_region(dev_ni5010->base_addr, NI5010_IO_EXTENT);
free_netdev(dev_ni5010);
}
+module_init(ni5010_init_module);
+module_exit(ni5010_cleanup_module);
#endif /* MODULE */
MODULE_LICENSE("GPL");
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index fa854c8fde7..e8889235996 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -639,7 +639,7 @@ static int init586(struct net_device *dev)
/*
* TDR, wire check .. e.g. no resistor e.t.c
*/
-
+
tdr_cmd = (struct tdr_cmd_struct *)ptr;
tdr_cmd->cmd_status = 0;
@@ -1323,7 +1323,7 @@ MODULE_PARM_DESC(irq, "NI5210 IRQ number,required");
MODULE_PARM_DESC(memstart, "NI5210 memory base address,required");
MODULE_PARM_DESC(memend, "NI5210 memory end address,required");
-int init_module(void)
+int __init init_module(void)
{
if(io <= 0x0 || !memend || !memstart || irq < 2) {
printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n");
diff --git a/drivers/net/ni52.h b/drivers/net/ni52.h
index 68f19175afb..a33ea0884aa 100644
--- a/drivers/net/ni52.h
+++ b/drivers/net/ni52.h
@@ -11,7 +11,7 @@
* Garret A. Wollman's i82586-driver for BSD
*/
-
+
#define NI52_RESET 0 /* writing to this address, resets the i82586 */
#define NI52_ATTENTION 1 /* channel attention, kick the 586 */
#define NI52_TENA 3 /* 2-5 possibly wrong, Xmit enable */
@@ -151,7 +151,7 @@ struct rfd_struct
/*
* Receive Buffer Descriptor (RBD)
*/
-struct rbd_struct
+struct rbd_struct
{
unsigned short status; /* status word,number of used bytes in buff */
unsigned short next; /* pointeroffset to next RBD */
@@ -203,7 +203,7 @@ struct nop_cmd_struct
/*
* IA Setup command
*/
-struct iasetup_cmd_struct
+struct iasetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
@@ -212,7 +212,7 @@ struct iasetup_cmd_struct
};
/*
- * Configure command
+ * Configure command
*/
struct configure_cmd_struct
{
@@ -234,9 +234,9 @@ struct configure_cmd_struct
};
/*
- * Multicast Setup command
+ * Multicast Setup command
*/
-struct mcsetup_cmd_struct
+struct mcsetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
@@ -257,9 +257,9 @@ struct dump_cmd_struct
};
/*
- * transmit command
+ * transmit command
*/
-struct transmit_cmd_struct
+struct transmit_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index bb42ff21848..fab3c8593ac 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -324,7 +324,7 @@ static int ni65_close(struct net_device *dev)
struct priv *p = (struct priv *) dev->priv;
netif_stop_queue(dev);
-
+
outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
#ifdef XMT_VIA_SKB
@@ -489,20 +489,20 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
int dma = dmatab[i];
if(test_bit(dma,&dma_channels) || request_dma(dma,"ni6510"))
continue;
-
+
flags=claim_dma_lock();
disable_dma(dma);
set_dma_mode(dma,DMA_MODE_CASCADE);
enable_dma(dma);
release_dma_lock(flags);
-
+
ni65_init_lance(p,dev->dev_addr,0,0); /* trigger memory access */
-
+
flags=claim_dma_lock();
disable_dma(dma);
free_dma(dma);
release_dma_lock(flags);
-
+
if(readreg(CSR0) & CSR0_IDON)
break;
}
@@ -881,7 +881,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
p = (struct priv *) dev->priv;
spin_lock(&p->ring_lock);
-
+
while(--bcnt) {
csr0 = inw(PORT+L_DATAREG);
@@ -1139,7 +1139,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0)
/*
* kick xmitter ..
*/
-
+
static void ni65_timeout(struct net_device *dev)
{
int i;
@@ -1163,7 +1163,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
struct priv *p = (struct priv *) dev->priv;
netif_stop_queue(dev);
-
+
if (test_and_set_bit(0, (void*)&p->lock)) {
printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
return 1;
@@ -1209,10 +1209,10 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
if(p->tmdnum != p->tmdlast)
netif_wake_queue(dev);
-
+
p->lock = 0;
dev->trans_start = jiffies;
-
+
spin_unlock_irqrestore(&p->ring_lock, flags);
}
@@ -1253,7 +1253,7 @@ MODULE_PARM_DESC(irq, "ni6510 IRQ number (ignored for some cards)");
MODULE_PARM_DESC(io, "ni6510 I/O base address");
MODULE_PARM_DESC(dma, "ni6510 ISA DMA channel (ignored for some cards)");
-int init_module(void)
+int __init init_module(void)
{
dev_ni65 = ni65_probe(-1);
return IS_ERR(dev_ni65) ? PTR_ERR(dev_ni65) : 0;
diff --git a/drivers/net/ni65.h b/drivers/net/ni65.h
index b01cef1b62c..e6217e35edf 100644
--- a/drivers/net/ni65.h
+++ b/drivers/net/ni65.h
@@ -1,12 +1,12 @@
/* am7990 (lance) definitions
- *
+ *
* This is an extension to the Linux operating system, and is covered by
* same GNU General Public License that covers that work.
- *
+ *
* Michael Hipp
* email: mhipp@student.uni-tuebingen.de
*
- * sources: (mail me or ask archie if you need them)
+ * sources: (mail me or ask archie if you need them)
* crynwr-packet-driver
*/
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index 706aed7d717..e10da1aa3d3 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -65,7 +65,7 @@
* 0.20 - fix stupid RFEN thinko. i am such a smurf.
* 20040828 0.21 - add hardware vlan accleration
* by Neil Horman <nhorman@redhat.com>
- * 20050406 0.22 - improved DAC ifdefs from Andi Kleen
+ * 20050406 0.22 - improved DAC ifdefs from Andi Kleen
* - removal of dead code from Adrian Bunk
* - fix half duplex collision behaviour
* Driver Overview
@@ -96,7 +96,6 @@
//#define dprintk printk
#define dprintk(x...) do { } while (0)
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
@@ -378,7 +377,7 @@ static int lnksts = 0; /* CFG_LNKSTS bit polarity */
#define LINK_DOWN 0x02
#define LINK_UP 0x04
-#define HW_ADDR_LEN sizeof(dma_addr_t)
+#define HW_ADDR_LEN sizeof(dma_addr_t)
#define desc_addr_set(desc, addr) \
do { \
((desc)[0] = cpu_to_le32(addr)); \
@@ -494,7 +493,7 @@ static inline void kick_rx(struct net_device *ndev)
(((NR_TX_DESC-2 + dev->tx_done_idx - dev->tx_free_idx) % NR_TX_DESC) > MIN_TX_DESC_FREE)
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
+#ifdef NS83820_VLAN_ACCEL_SUPPORT
static void ns83820_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp)
{
struct ns83820 *dev = PRIV(ndev);
@@ -804,7 +803,7 @@ static int ns83820_setup_rx(struct net_device *ndev)
writel(dev->IMR_cache, dev->base + IMR);
writel(1, dev->base + IER);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock(&dev->misc_lock);
kick_rx(ndev);
@@ -866,7 +865,7 @@ static void fastcall ns83820_rx_kick(struct net_device *ndev)
}
/* rx_irq
- *
+ *
*/
static void FASTCALL(rx_irq(struct net_device *ndev));
static void fastcall rx_irq(struct net_device *ndev)
@@ -922,14 +921,14 @@ static void fastcall rx_irq(struct net_device *ndev)
* that are 64 bytes with a vlan header appended
* like arp frames, or pings, are flagged as Runts
* when the tag is stripped and hardware. This
- * also means that the OK bit in the descriptor
+ * also means that the OK bit in the descriptor
* is cleared when the frame comes in so we have
* to do a specific length check here to make sure
* the frame would have been ok, had we not stripped
* the tag.
- */
+ */
if (likely((CMDSTS_OK & cmdsts) ||
- ((cmdsts & CMDSTS_RUNT) && len >= 56))) {
+ ((cmdsts & CMDSTS_RUNT) && len >= 56))) {
#else
if (likely(CMDSTS_OK & cmdsts)) {
#endif
@@ -946,7 +945,7 @@ static void fastcall rx_irq(struct net_device *ndev)
skb->ip_summed = CHECKSUM_NONE;
}
skb->protocol = eth_type_trans(skb, ndev);
-#ifdef NS83820_VLAN_ACCEL_SUPPORT
+#ifdef NS83820_VLAN_ACCEL_SUPPORT
if(extsts & EXTSTS_VPKT) {
unsigned short tag;
tag = ntohs(extsts & EXTSTS_VTG_MASK);
@@ -1013,8 +1012,6 @@ static void do_tx_done(struct net_device *ndev)
struct ns83820 *dev = PRIV(ndev);
u32 cmdsts, tx_done_idx, *desc;
- spin_lock_irq(&dev->tx_lock);
-
dprintk("do_tx_done(%p)\n", ndev);
tx_done_idx = dev->tx_done_idx;
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1050,7 +1047,7 @@ static void do_tx_done(struct net_device *ndev)
dev_kfree_skb_irq(skb);
atomic_dec(&dev->nr_tx_skbs);
} else
- pci_unmap_page(dev->pci_dev,
+ pci_unmap_page(dev->pci_dev,
addr,
len,
PCI_DMA_TODEVICE);
@@ -1070,7 +1067,6 @@ static void do_tx_done(struct net_device *ndev)
netif_start_queue(ndev);
netif_wake_queue(ndev);
}
- spin_unlock_irq(&dev->tx_lock);
}
static void ns83820_cleanup_tx(struct ns83820 *dev)
@@ -1157,7 +1153,7 @@ again:
if (!nr_frags)
frag = NULL;
extsts = 0;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
extsts |= EXTSTS_IPPKT;
if (IPPROTO_TCP == skb->nh.iph->protocol)
extsts |= EXTSTS_TCPPKT;
@@ -1277,16 +1273,18 @@ static u32 ns83820_get_link(struct net_device *ndev)
return cfg & CFG_LNKSTS ? 1 : 0;
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = ns83820_get_drvinfo,
.get_link = ns83820_get_link
};
+/* this function is called in irq context from the ISR */
static void ns83820_mib_isr(struct ns83820 *dev)
{
- spin_lock(&dev->misc_lock);
+ unsigned long flags;
+ spin_lock_irqsave(&dev->misc_lock, flags);
ns83820_update_stats(dev);
- spin_unlock(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
static void ns83820_do_isr(struct net_device *ndev, u32 isr);
@@ -1308,6 +1306,8 @@ static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
static void ns83820_do_isr(struct net_device *ndev, u32 isr)
{
struct ns83820 *dev = PRIV(ndev);
+ unsigned long flags;
+
#ifdef DEBUG
if (isr & ~(ISR_PHY | ISR_RXDESC | ISR_RXEARLY | ISR_RXOK | ISR_RXERR | ISR_TXIDLE | ISR_TXOK | ISR_TXDESC))
Dprintk("odd isr? 0x%08x\n", isr);
@@ -1322,10 +1322,10 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
if ((ISR_RXDESC | ISR_RXOK) & isr) {
prefetch(dev->rx_info.next_rx_desc);
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~(ISR_RXDESC | ISR_RXOK);
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
tasklet_schedule(&dev->rx_tasklet);
//rx_irq(ndev);
@@ -1359,8 +1359,8 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
dev->tx_idx = 0;
}
/* The may have been a race between a pci originated read
- * and the descriptor update from the cpu. Just in case,
- * kick the transmitter if the hardware thinks it is on a
+ * and the descriptor update from the cpu. Just in case,
+ * kick the transmitter if the hardware thinks it is on a
* different descriptor than we are.
*/
if (dev->tx_idx != dev->tx_free_idx)
@@ -1371,30 +1371,32 @@ static void ns83820_do_isr(struct net_device *ndev, u32 isr)
* work has accumulated
*/
if ((ISR_TXDESC | ISR_TXIDLE | ISR_TXOK | ISR_TXERR) & isr) {
+ spin_lock_irqsave(&dev->tx_lock, flags);
do_tx_done(ndev);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
/* Disable TxOk if there are no outstanding tx packets.
*/
if ((dev->tx_done_idx == dev->tx_free_idx) &&
(dev->IMR_cache & ISR_TXOK)) {
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache &= ~ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
}
/* The TxIdle interrupt can come in before the transmit has
* completed. Normally we reap packets off of the combination
- * of TxDesc and TxIdle and leave TxOk disabled (since it
- * occurs on every packet), but when no further irqs of this
+ * of TxDesc and TxIdle and leave TxOk disabled (since it
+ * occurs on every packet), but when no further irqs of this
* nature are expected, we must enable TxOk.
*/
if ((ISR_TXIDLE & isr) && (dev->tx_done_idx != dev->tx_free_idx)) {
- spin_lock_irq(&dev->misc_lock);
+ spin_lock_irqsave(&dev->misc_lock, flags);
dev->IMR_cache |= ISR_TXOK;
writel(dev->IMR_cache, dev->base + IMR);
- spin_unlock_irq(&dev->misc_lock);
+ spin_unlock_irqrestore(&dev->misc_lock, flags);
}
/* MIB interrupt: one of the statistics counters is about to overflow */
@@ -1456,7 +1458,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
u32 tx_done_idx, *desc;
unsigned long flags;
- local_irq_save(flags);
+ spin_lock_irqsave(&dev->tx_lock, flags);
tx_done_idx = dev->tx_done_idx;
desc = dev->tx_descs + (tx_done_idx * DESC_SIZE);
@@ -1483,7 +1485,7 @@ static void ns83820_tx_timeout(struct net_device *ndev)
ndev->name,
tx_done_idx, dev->tx_free_idx, le32_to_cpu(desc[DESC_CMDSTS]));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&dev->tx_lock, flags);
}
static void ns83820_tx_watch(unsigned long data)
@@ -1833,7 +1835,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
} else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) {
using_dac = 0;
} else {
- printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n");
+ dev_warn(&pci_dev->dev, "pci_set_dma_mask failed!\n");
return -ENODEV;
}
@@ -1856,7 +1858,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
err = pci_enable_device(pci_dev);
if (err) {
- printk(KERN_INFO "ns83820: pci_enable_dev failed: %d\n", err);
+ dev_info(&pci_dev->dev, "pci_enable_dev failed: %d\n", err);
goto out_free;
}
@@ -1882,11 +1884,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
dev->IMR_cache = 0;
- err = request_irq(pci_dev->irq, ns83820_irq, SA_SHIRQ,
+ err = request_irq(pci_dev->irq, ns83820_irq, IRQF_SHARED,
DRV_NAME, ndev);
if (err) {
- printk(KERN_INFO "ns83820: unable to register irq %d\n",
- pci_dev->irq);
+ dev_info(&pci_dev->dev, "unable to register irq %d, err %d\n",
+ pci_dev->irq, err);
goto out_disable;
}
@@ -1900,7 +1902,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
rtnl_lock();
err = dev_alloc_name(ndev, ndev->name);
if (err < 0) {
- printk(KERN_INFO "ns83820: unable to get netdev name: %d\n", err);
+ dev_info(&pci_dev->dev, "unable to get netdev name: %d\n", err);
goto out_free_irq;
}
@@ -1954,7 +1956,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
/* When compiled with 64 bit addressing, we must always enable
* the 64 bit descriptor format.
*/
- if (sizeof(dma_addr_t) == 8)
+ if (sizeof(dma_addr_t) == 8)
dev->CFG_cache |= CFG_M64ADDR;
if (using_dac)
dev->CFG_cache |= CFG_T64ADDR;
@@ -1992,7 +1994,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
writel(dev->CFG_cache, dev->base + CFG);
}
-#if 0 /* Huh? This sets the PCI latency register. Should be done via
+#if 0 /* Huh? This sets the PCI latency register. Should be done via
* the PCI layer. FIXME.
*/
if (readl(dev->base + SRR))
@@ -2004,7 +2006,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
* can be transmitted is 8192 - FLTH - burst size.
* If only the transmit fifo was larger...
*/
- /* Ramit : 1024 DMA is not a good idea, it ends up banging
+ /* Ramit : 1024 DMA is not a good idea, it ends up banging
* some DELL and COMPAQ SMP systems */
writel(TXCFG_CSI | TXCFG_HBI | TXCFG_ATP | TXCFG_MXDMA512
| ((1600 / 32) * 0x100),
@@ -2018,8 +2020,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
/* Set Rx to full duplex, don't accept runt, errored, long or length
* range errored packets. Use 512 byte DMA.
*/
- /* Ramit : 1024 DMA is not a good idea, it ends up banging
- * some DELL and COMPAQ SMP systems
+ /* Ramit : 1024 DMA is not a good idea, it ends up banging
+ * some DELL and COMPAQ SMP systems
* Turn on ALP, only we are accpeting Jumbo Packets */
writel(RXCFG_AEP | RXCFG_ARP | RXCFG_AIRL | RXCFG_RX_FD
| RXCFG_STRIPCRC
@@ -2043,7 +2045,7 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_
* also turn on tag stripping if hardware acceleration is enabled
*/
#ifdef NS83820_VLAN_ACCEL_SUPPORT
-#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN)
+#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN|VRCR_VTREN)
#else
#define VRCR_INIT_VALUE (VRCR_IPEN|VRCR_VTDEN)
#endif
@@ -2176,7 +2178,7 @@ static struct pci_driver driver = {
static int __init ns83820_init(void)
{
printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n");
- return pci_module_init(&driver);
+ return pci_register_driver(&driver);
}
static void __exit ns83820_exit(void)
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
index d0f686d6eaa..702e3e95612 100644
--- a/drivers/net/oaknet.c
+++ b/drivers/net/oaknet.c
@@ -9,7 +9,7 @@
* on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
* various other 8390 drivers written by Donald Becker and Paul Gortmaker.
*
- * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
+ * Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
* and "enetLib.c" from IBM.
*
*/
@@ -98,7 +98,7 @@ static int __init oaknet_init(void)
int ret = -ENOMEM;
struct net_device *dev;
#if 0
- unsigned long ioaddr = OAKNET_IO_BASE;
+ unsigned long ioaddr = OAKNET_IO_BASE;
#else
unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
#endif
@@ -201,7 +201,7 @@ static int __init oaknet_init(void)
ret = register_netdev(dev);
if (ret)
goto out_irq;
-
+
oaknet_devs = dev;
return 0;
@@ -447,8 +447,8 @@ oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
* Input(s):
* *dev - Pointer to the device structure for this driver.
* count - Number of bytes to be transferred.
- * *buf -
- * start_page -
+ * *buf -
+ * start_page -
*
* Output(s):
* N/A
@@ -584,7 +584,7 @@ retry:
* This was for the ALPHA version only, but enough people have
* been encountering problems so it is still here.
*/
-
+
{
/* DMA termination address check... */
int addr, tries = 20;
@@ -614,7 +614,7 @@ retry:
break;
}
}
-
+
ei_obp(ENISR_RDC, base + EN0_ISR); /* Ack intr. */
ei_status.dmaing &= ~0x01;
}
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index a7bb54df75a..2687e747657 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -85,7 +85,6 @@ IVc. Errata
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -99,7 +98,7 @@ IVc. Errata
#include <linux/crc32.h>
#include <asm/io.h>
-#define NETDRV_VERSION "1.0.0"
+#define NETDRV_VERSION "1.0.1"
#define MODNAME "netdrv"
#define NETDRV_DRIVER_LOAD_MSG "MyVendor Fast Ethernet driver " NETDRV_VERSION " loaded"
#define PFX MODNAME ": "
@@ -602,7 +601,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* dev zeroed in alloc_etherdev */
dev = alloc_etherdev (sizeof (*tp));
if (dev == NULL) {
- printk (KERN_ERR PFX "unable to alloc new ethernet\n");
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
DPRINTK ("EXIT, returning -ENOMEM\n");
return -ENOMEM;
}
@@ -632,14 +631,14 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* make sure PCI base addr 0 is PIO */
if (!(pio_flags & IORESOURCE_IO)) {
- printk (KERN_ERR PFX "region #0 not a PIO resource, aborting\n");
+ dev_err(&pdev->dev, "region #0 not a PIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
/* make sure PCI base addr 1 is MMIO */
if (!(mmio_flags & IORESOURCE_MEM)) {
- printk (KERN_ERR PFX "region #1 not an MMIO resource, aborting\n");
+ dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n");
rc = -ENODEV;
goto err_out;
}
@@ -647,12 +646,12 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* check for weird/broken PCI region reporting */
if ((pio_len < NETDRV_MIN_IO_SIZE) ||
(mmio_len < NETDRV_MIN_IO_SIZE)) {
- printk (KERN_ERR PFX "Invalid PCI region size(s), aborting\n");
+ dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n");
rc = -ENODEV;
goto err_out;
}
- rc = pci_request_regions (pdev, "pci-skeleton");
+ rc = pci_request_regions (pdev, MODNAME);
if (rc)
goto err_out;
@@ -664,7 +663,7 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
/* ioremap MMIO region */
ioaddr = ioremap (mmio_start, mmio_len);
if (ioaddr == NULL) {
- printk (KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
goto err_out_free_res;
}
@@ -700,9 +699,10 @@ static int __devinit netdrv_init_board (struct pci_dev *pdev,
}
/* if unknown chip, assume array element #0, original RTL-8139 in this case */
- printk (KERN_DEBUG PFX "PCI device %s: unknown chip version, assuming RTL-8139\n",
- pci_name(pdev));
- printk (KERN_DEBUG PFX "PCI device %s: TxConfig = 0x%lx\n", pci_name(pdev), NETDRV_R32 (TxConfig));
+ dev_printk (KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming RTL-8139\n");
+ dev_printk (KERN_DEBUG, &pdev->dev, "TxConfig = 0x%lx\n",
+ NETDRV_R32 (TxConfig));
tp->chipset = 0;
match:
@@ -1076,7 +1076,7 @@ static int netdrv_open (struct net_device *dev)
DPRINTK ("ENTER\n");
- retval = request_irq (dev->irq, netdrv_interrupt, SA_SHIRQ, dev->name, dev);
+ retval = request_irq (dev->irq, netdrv_interrupt, IRQF_SHARED, dev->name, dev);
if (retval) {
DPRINTK ("EXIT, returning %d\n", retval);
return retval;
@@ -1318,7 +1318,7 @@ static void netdrv_tx_timeout (struct net_device *dev)
/* Stop a shared interrupt from scavenging while we are. */
spin_lock_irqsave (&tp->lock, flags);
-
+
netdrv_tx_clear (tp);
spin_unlock_irqrestore (&tp->lock, flags);
@@ -1853,9 +1853,6 @@ static void netdrv_set_rx_mode (struct net_device *dev)
/* Note: do not reorder, GCC is clever about common statements. */
if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
@@ -1963,7 +1960,7 @@ static int __init netdrv_init_module (void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init (&netdrv_pci_driver);
+ return pci_register_driver(&netdrv_pci_driver);
}
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index fab93360f01..2418cdb9d31 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -245,7 +245,7 @@ static int el3_rx(struct net_device *dev, int worklimit);
static int el3_close(struct net_device *dev);
static void el3_tx_timeout(struct net_device *dev);
static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void set_rx_mode(struct net_device *dev);
static void tc574_detach(struct pcmcia_device *p_dev);
@@ -1095,7 +1095,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
strcpy(info->driver, "3c574_cs");
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 875a0fe251e..a0e2b01c027 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -158,7 +158,7 @@ static int el3_rx(struct net_device *dev);
static int el3_close(struct net_device *dev);
static void el3_tx_timeout(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void tc589_detach(struct pcmcia_device *p_dev);
@@ -530,7 +530,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
}
#endif /* PCMCIA_DEBUG */
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
#ifdef PCMCIA_DEBUG
.get_msglevel = netdev_get_msglevel,
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 2ea66aca648..a8891a9000a 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -91,7 +91,7 @@ static void axnet_release(struct pcmcia_device *link);
static int axnet_open(struct net_device *dev);
static int axnet_close(struct net_device *dev);
static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
static void ei_watchdog(u_long arg);
static void axnet_reset_8390(struct net_device *dev);
@@ -535,7 +535,7 @@ static int axnet_open(struct net_device *dev)
link->open++;
- request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, "axnet_cs", dev);
+ request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, "axnet_cs", dev);
info->link_status = 0x00;
init_timer(&info->watchdog);
@@ -671,7 +671,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
strcpy(info->driver, "axnet_cs");
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
@@ -771,6 +771,7 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+ PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202),
PCMCIA_DEVICE_PROD_ID12("AmbiCom,Inc.", "Fast Ethernet PC Card(AMB8110)", 0x49b020a7, 0x119cc9fc),
PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
@@ -786,8 +787,6 @@ static struct pcmcia_device_id axnet_ids[] = {
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6, 0xab9be5ef),
- /* this is not specific enough */
- /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
PCMCIA_DEVICE_NULL,
};
MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 441de824ab6..48434d7924e 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -387,7 +387,10 @@ static int com20020_resume(struct pcmcia_device *link)
}
static struct pcmcia_device_id com20020_ids[] = {
- PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
+ PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
+ "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
+ PCMCIA_DEVICE_PROD_ID12("SoHard AG",
+ "SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index ea93b8f1860..d682f30dea6 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -29,7 +29,7 @@
======================================================================*/
#define DRV_NAME "fmvj18x_cs"
-#define DRV_VERSION "2.8"
+#define DRV_VERSION "2.9"
#include <linux/module.h>
#include <linux/kernel.h>
@@ -103,7 +103,7 @@ static void fjn_reset(struct net_device *dev);
static struct net_device_stats *fjn_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void fjn_tx_timeout(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
/*
card type
@@ -1092,7 +1092,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
}
#endif /* PCMCIA_DEBUG */
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
#ifdef PCMCIA_DEBUG
.get_msglevel = netdev_get_msglevel,
@@ -1193,8 +1193,6 @@ static void set_rx_mode(struct net_device *dev)
outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- printk("%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
outb(3, ioaddr + RX_MODE); /* Enable promiscuous mode */
} else if (dev->mc_count > MC_FILTERBREAK
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index b8fe70b8564..bc0ca41a054 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -126,7 +126,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
strcpy(info->driver, "ibmtr_cs");
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index a8f6bfc96fd..7d5687e9460 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -431,7 +431,7 @@ static struct net_device_stats *mace_get_stats(struct net_device *dev);
static int mace_rx(struct net_device *dev, unsigned char RxCnt);
static void restore_multicast_list(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void nmclan_detach(struct pcmcia_device *p_dev);
@@ -907,7 +907,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 level)
}
#endif /* PCMCIA_DEBUG */
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
#ifdef PCMCIA_DEBUG
.get_msglevel = netdev_get_msglevel,
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 661bfe54ff5..a09c22840f6 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -108,7 +108,7 @@ static void pcnet_release(struct pcmcia_device *link);
static int pcnet_open(struct net_device *dev);
static int pcnet_close(struct net_device *dev);
static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
static void ei_watchdog(u_long arg);
static void pcnet_reset_8390(struct net_device *dev);
@@ -654,11 +654,8 @@ static int pcnet_config(struct pcmcia_device *link)
SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
if (info->flags & (IS_DL10019|IS_DL10022)) {
- u_char id = inb(dev->base_addr + 0x1a);
dev->do_ioctl = &ei_ioctl;
mii_phy_probe(dev);
- if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
- info->eth_phy = 0;
}
link->dev_node = &info->node;
@@ -821,15 +818,6 @@ static void mdio_write(kio_addr_t addr, int phy_id, int loc, int value)
}
}
-static void mdio_reset(kio_addr_t addr, int phy_id)
-{
- outb_p(0x08, addr);
- outb_p(0x0c, addr);
- outb_p(0x08, addr);
- outb_p(0x0c, addr);
- outb_p(0x00, addr);
-}
-
/*======================================================================
EEPROM access routines for DL10019 and DL10022 based cards
@@ -942,7 +930,8 @@ static void set_misc_reg(struct net_device *dev)
}
if (info->flags & IS_DL10022) {
if (info->flags & HAS_MII) {
- mdio_reset(nic_base + DLINK_GPIO, info->eth_phy);
+ /* Advertise 100F, 100H, 10F, 10H */
+ mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 4, 0x01e1);
/* Restart MII autonegotiation */
mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x0000);
mdio_write(nic_base + DLINK_GPIO, info->eth_phy, 0, 0x1200);
@@ -998,7 +987,7 @@ static int pcnet_open(struct net_device *dev)
link->open++;
set_misc_reg(dev);
- request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
+ request_irq(dev->irq, ei_irq_wrapper, IRQF_SHARED, dev_info, dev);
info->phy_id = info->eth_phy;
info->link_status = 0x00;
@@ -1192,7 +1181,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
strcpy(info->driver, "pcnet_cs");
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index e74bf5014ef..a2f3a0e2a00 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -80,14 +80,14 @@ INT_MODULE_PARM(if_port, 0);
#ifdef PCMCIA_DEBUG
INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
static const char *version =
-"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@scyld.com.\n";
+"smc91c92_cs.c 1.123 2006/11/09 Donald Becker, becker@scyld.com.\n";
#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
#else
#define DEBUG(n, args...)
#endif
#define DRV_NAME "smc91c92_cs"
-#define DRV_VERSION "1.122"
+#define DRV_VERSION "1.123"
/*====================================================================*/
@@ -299,7 +299,7 @@ static void mdio_sync(kio_addr_t addr);
static int mdio_read(struct net_device *dev, int phy_id, int loc);
static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
static int smc_link_ok(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
/*======================================================================
@@ -1780,7 +1780,6 @@ static void set_rx_mode(struct net_device *dev)
u_short rx_cfg_setting;
if (dev->flags & IFF_PROMISC) {
- printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
} else if (dev->flags & IFF_ALLMULTI)
rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
@@ -1883,7 +1882,7 @@ static void smc_reset(struct net_device *dev)
/* Set the Window 1 control, configuration and station addr registers.
No point in writing the I/O base register ;-> */
SMC_SELECT_BANK(1);
- /* Automatically release succesfully transmitted packets,
+ /* Automatically release successfully transmitted packets,
Accept link errors, counter and Tx error interrupts. */
outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
ioaddr + CONTROL);
@@ -2208,7 +2207,7 @@ static int smc_nway_reset(struct net_device *dev)
return -EOPNOTSUPP;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.begin = check_if_running,
.get_drvinfo = smc_get_drvinfo,
.get_settings = smc_get_settings,
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 9bae77ce131..62664c01eb4 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -345,6 +345,7 @@ typedef struct local_info_t {
void __iomem *dingo_ccr; /* only used for CEM56 cards */
unsigned last_ptr_value; /* last packets transmitted value */
const char *manf_str;
+ struct work_struct tx_timeout_task;
} local_info_t;
/****************
@@ -352,6 +353,7 @@ typedef struct local_info_t {
*/
static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void do_tx_timeout(struct net_device *dev);
+static void xirc2ps_tx_timeout_task(void *data);
static struct net_device_stats *do_get_stats(struct net_device *dev);
static void set_addresses(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -359,7 +361,7 @@ static int set_card_type(struct pcmcia_device *link, const void *s);
static int do_config(struct net_device *dev, struct ifmap *map);
static int do_open(struct net_device *dev);
static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void hardreset(struct net_device *dev);
static void do_reset(struct net_device *dev, int full);
static int init_mii(struct net_device *dev);
@@ -589,6 +591,7 @@ xirc2ps_probe(struct pcmcia_device *link)
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = do_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev);
#endif
return xirc2ps_config(link);
@@ -1341,17 +1344,24 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*====================================================================*/
static void
-do_tx_timeout(struct net_device *dev)
+xirc2ps_tx_timeout_task(void *data)
{
- local_info_t *lp = netdev_priv(dev);
- printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
- lp->stats.tx_errors++;
+ struct net_device *dev = data;
/* reset the card */
do_reset(dev,1);
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
+static void
+do_tx_timeout(struct net_device *dev)
+{
+ local_info_t *lp = netdev_priv(dev);
+ lp->stats.tx_errors++;
+ printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
+ schedule_work(&lp->tx_timeout_task);
+}
+
static int
do_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
@@ -1543,7 +1553,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
sprintf(info->bus_info, "PCMCIA 0x%lx", dev->base_addr);
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index fc08c4af506..21dc68eff51 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -21,9 +21,15 @@
*
*************************************************************************/
+#include <linux/config.h>
+
#define DRV_NAME "pcnet32"
-#define DRV_VERSION "1.32"
-#define DRV_RELDATE "18.Mar.2006"
+#ifdef CONFIG_PCNET32_NAPI
+#define DRV_VERSION "1.33-NAPI"
+#else
+#define DRV_VERSION "1.33"
+#endif
+#define DRV_RELDATE "27.Jun.2006"
#define PFX DRV_NAME ": "
static const char *const version =
@@ -58,18 +64,15 @@ static const char *const version =
* PCI device identifiers for "new style" Linux PCI Device Drivers
*/
static struct pci_device_id pcnet32_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME), },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE), },
/*
* Adapters that were sold with IBM's RS/6000 or pSeries hardware have
* the incorrect vendor id.
*/
- { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE,
- PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE),
+ .class = (PCI_CLASS_NETWORK_ETHERNET << 8), .class_mask = 0xffff00, },
{ } /* terminate list */
};
@@ -188,10 +191,29 @@ static int homepna[MAX_UNITS];
#define PCNET32_TOTAL_SIZE 0x20
+#define CSR0 0
+#define CSR0_INIT 0x1
+#define CSR0_START 0x2
+#define CSR0_STOP 0x4
+#define CSR0_TXPOLL 0x8
+#define CSR0_INTEN 0x40
+#define CSR0_IDON 0x0100
+#define CSR0_NORMAL (CSR0_START | CSR0_INTEN)
+#define PCNET32_INIT_LOW 1
+#define PCNET32_INIT_HIGH 2
+#define CSR3 3
+#define CSR4 4
+#define CSR5 5
+#define CSR5_SUSPEND 0x0001
+#define CSR15 15
+#define PCNET32_MC_FILTER 8
+
+#define PCNET32_79C970A 0x2621
+
/* The PCNET32 Rx and Tx ring descriptors. */
struct pcnet32_rx_head {
u32 base;
- s16 buf_length;
+ s16 buf_length; /* two`s complement of length */
s16 status;
u32 msg_length;
u32 reserved;
@@ -199,7 +221,7 @@ struct pcnet32_rx_head {
struct pcnet32_tx_head {
u32 base;
- s16 length;
+ s16 length; /* two`s complement of length */
s16 status;
u32 misc;
u32 reserved;
@@ -275,15 +297,14 @@ struct pcnet32_private {
/* each bit indicates an available PHY */
u32 phymask;
+ unsigned short chip_version; /* which variant this is */
};
-static void pcnet32_probe_vlbus(void);
static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *);
static int pcnet32_probe1(unsigned long, int, struct pci_dev *);
static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
-static int pcnet32_rx(struct net_device *);
static void pcnet32_tx_timeout(struct net_device *dev);
static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
static int pcnet32_close(struct net_device *);
@@ -309,12 +330,6 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name);
static void pcnet32_free_ring(struct net_device *dev);
static void pcnet32_check_media(struct net_device *dev, int verbose);
-enum pci_flags_bit {
- PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4,
- PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 =
- 0x10 << 2, PCI_ADDR3 = 0x10 << 3,
-};
-
static u16 pcnet32_wio_read_csr(unsigned long addr, int index)
{
outw(index, addr + PCNET32_WIO_RAP);
@@ -425,6 +440,238 @@ static struct pcnet32_access pcnet32_dwio = {
.reset = pcnet32_dwio_reset
};
+static void pcnet32_netif_stop(struct net_device *dev)
+{
+ dev->trans_start = jiffies;
+ netif_poll_disable(dev);
+ netif_tx_disable(dev);
+}
+
+static void pcnet32_netif_start(struct net_device *dev)
+{
+ netif_wake_queue(dev);
+ netif_poll_enable(dev);
+}
+
+/*
+ * Allocate space for the new sized tx ring.
+ * Free old resources
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_tx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_tx_head *new_tx_ring;
+ struct sk_buff **new_skb_list;
+
+ pcnet32_purge_tx_ring(dev);
+
+ new_tx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_tx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_tx_ring, 0, sizeof(struct pcnet32_tx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_tx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ kfree(lp->tx_skbuff);
+ kfree(lp->tx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ lp->tx_ring_size, lp->tx_ring,
+ lp->tx_ring_dma_addr);
+
+ lp->tx_ring_size = (1 << size);
+ lp->tx_mod_mask = lp->tx_ring_size - 1;
+ lp->tx_len_bits = (size << 12);
+ lp->tx_ring = new_tx_ring;
+ lp->tx_ring_dma_addr = new_ring_dma_addr;
+ lp->tx_dma_addr = new_dma_addr_list;
+ lp->tx_skbuff = new_skb_list;
+ return;
+
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_tx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_tx_head) *
+ (1 << size),
+ new_tx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+/*
+ * Allocate space for the new sized rx ring.
+ * Re-use old receive buffers.
+ * alloc extra buffers
+ * free unneeded buffers
+ * free unneeded buffers
+ * Save new resources.
+ * Any failure keeps old resources.
+ * Must be called with lp->lock held.
+ */
+static void pcnet32_realloc_rx_ring(struct net_device *dev,
+ struct pcnet32_private *lp,
+ unsigned int size)
+{
+ dma_addr_t new_ring_dma_addr;
+ dma_addr_t *new_dma_addr_list;
+ struct pcnet32_rx_head *new_rx_ring;
+ struct sk_buff **new_skb_list;
+ int new, overlap;
+
+ new_rx_ring = pci_alloc_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ &new_ring_dma_addr);
+ if (new_rx_ring == NULL) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Consistent memory allocation failed.\n",
+ dev->name);
+ return;
+ }
+ memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size));
+
+ new_dma_addr_list = kcalloc((1 << size), sizeof(dma_addr_t),
+ GFP_ATOMIC);
+ if (!new_dma_addr_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_rx_ring;
+ }
+
+ new_skb_list = kcalloc((1 << size), sizeof(struct sk_buff *),
+ GFP_ATOMIC);
+ if (!new_skb_list) {
+ if (netif_msg_drv(lp))
+ printk("\n" KERN_ERR
+ "%s: Memory allocation failed.\n", dev->name);
+ goto free_new_lists;
+ }
+
+ /* first copy the current receive buffers */
+ overlap = min(size, lp->rx_ring_size);
+ for (new = 0; new < overlap; new++) {
+ new_rx_ring[new] = lp->rx_ring[new];
+ new_dma_addr_list[new] = lp->rx_dma_addr[new];
+ new_skb_list[new] = lp->rx_skbuff[new];
+ }
+ /* now allocate any new buffers needed */
+ for (; new < size; new++ ) {
+ struct sk_buff *rx_skbuff;
+ new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ);
+ if (!(rx_skbuff = new_skb_list[new])) {
+ /* keep the original lists and buffers */
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: pcnet32_realloc_rx_ring dev_alloc_skb failed.\n",
+ dev->name);
+ goto free_all_new;
+ }
+ skb_reserve(rx_skbuff, 2);
+
+ new_dma_addr_list[new] =
+ pci_map_single(lp->pci_dev, rx_skbuff->data,
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ new_rx_ring[new].base = (u32) le32_to_cpu(new_dma_addr_list[new]);
+ new_rx_ring[new].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ new_rx_ring[new].status = le16_to_cpu(0x8000);
+ }
+ /* and free any unneeded buffers */
+ for (; new < lp->rx_ring_size; new++) {
+ if (lp->rx_skbuff[new]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(lp->rx_skbuff[new]);
+ }
+ }
+
+ kfree(lp->rx_skbuff);
+ kfree(lp->rx_dma_addr);
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ lp->rx_ring_size, lp->rx_ring,
+ lp->rx_ring_dma_addr);
+
+ lp->rx_ring_size = (1 << size);
+ lp->rx_mod_mask = lp->rx_ring_size - 1;
+ lp->rx_len_bits = (size << 4);
+ lp->rx_ring = new_rx_ring;
+ lp->rx_ring_dma_addr = new_ring_dma_addr;
+ lp->rx_dma_addr = new_dma_addr_list;
+ lp->rx_skbuff = new_skb_list;
+ return;
+
+ free_all_new:
+ for (; --new >= lp->rx_ring_size; ) {
+ if (new_skb_list[new]) {
+ pci_unmap_single(lp->pci_dev, new_dma_addr_list[new],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(new_skb_list[new]);
+ }
+ }
+ kfree(new_skb_list);
+ free_new_lists:
+ kfree(new_dma_addr_list);
+ free_new_rx_ring:
+ pci_free_consistent(lp->pci_dev,
+ sizeof(struct pcnet32_rx_head) *
+ (1 << size),
+ new_rx_ring,
+ new_ring_dma_addr);
+ return;
+}
+
+static void pcnet32_purge_rx_ring(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int i;
+
+ /* free all allocated skbuffs */
+ for (i = 0; i < lp->rx_ring_size; i++) {
+ lp->rx_ring[i].status = 0; /* CPU owns buffer */
+ wmb(); /* Make sure adapter sees owner change */
+ if (lp->rx_skbuff[i]) {
+ pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
+ PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb_any(lp->rx_skbuff[i]);
+ }
+ lp->rx_skbuff[i] = NULL;
+ lp->rx_dma_addr[i] = 0;
+ }
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void pcnet32_poll_controller(struct net_device *dev)
{
@@ -485,9 +732,11 @@ static u32 pcnet32_get_link(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
if (lp->mii) {
r = mii_link_ok(&lp->mii_if);
- } else {
+ } else if (lp->chip_version >= PCNET32_79C970A) {
ulong ioaddr = dev->base_addr; /* card base I/O address */
r = (lp->a.read_bcr(ioaddr, 4) != 0xc0);
+ } else { /* can not detect link on really old chips */
+ r = 1;
}
spin_unlock_irqrestore(&lp->lock, flags);
@@ -525,10 +774,10 @@ static void pcnet32_get_ringparam(struct net_device *dev,
{
struct pcnet32_private *lp = dev->priv;
- ering->tx_max_pending = TX_MAX_RING_SIZE - 1;
- ering->tx_pending = lp->tx_ring_size - 1;
- ering->rx_max_pending = RX_MAX_RING_SIZE - 1;
- ering->rx_pending = lp->rx_ring_size - 1;
+ ering->tx_max_pending = TX_MAX_RING_SIZE;
+ ering->tx_pending = lp->tx_ring_size;
+ ering->rx_max_pending = RX_MAX_RING_SIZE;
+ ering->rx_pending = lp->rx_ring_size;
}
static int pcnet32_set_ringparam(struct net_device *dev,
@@ -536,56 +785,53 @@ static int pcnet32_set_ringparam(struct net_device *dev,
{
struct pcnet32_private *lp = dev->priv;
unsigned long flags;
+ unsigned int size;
+ ulong ioaddr = dev->base_addr;
int i;
if (ering->rx_mini_pending || ering->rx_jumbo_pending)
return -EINVAL;
if (netif_running(dev))
- pcnet32_close(dev);
+ pcnet32_netif_stop(dev);
spin_lock_irqsave(&lp->lock, flags);
- pcnet32_free_ring(dev);
- lp->tx_ring_size =
- min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
- lp->rx_ring_size =
- min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ size = min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE);
/* set the minimum ring size to 4, to allow the loopback test to work
* unchanged.
*/
for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) {
- if (lp->tx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->tx_ring_size = (1 << i);
- lp->tx_mod_mask = lp->tx_ring_size - 1;
- lp->tx_len_bits = (i << 12);
+ if ((1 << i) != lp->tx_ring_size)
+ pcnet32_realloc_tx_ring(dev, lp, i);
+ size = min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE);
for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) {
- if (lp->rx_ring_size <= (1 << i))
+ if (size <= (1 << i))
break;
}
- lp->rx_ring_size = (1 << i);
- lp->rx_mod_mask = lp->rx_ring_size - 1;
- lp->rx_len_bits = (i << 4);
+ if ((1 << i) != lp->rx_ring_size)
+ pcnet32_realloc_rx_ring(dev, lp, i);
- if (pcnet32_alloc_ring(dev, dev->name)) {
- pcnet32_free_ring(dev);
- spin_unlock_irqrestore(&lp->lock, flags);
- return -ENOMEM;
+ dev->weight = lp->rx_ring_size / 2;
+
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, CSR0_NORMAL);
}
spin_unlock_irqrestore(&lp->lock, flags);
- if (pcnet32_debug & NETIF_MSG_DRV)
- printk(KERN_INFO PFX
+ if (netif_msg_drv(lp))
+ printk(KERN_INFO
"%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name,
lp->rx_ring_size, lp->tx_ring_size);
- if (netif_running(dev))
- pcnet32_open(dev);
-
return 0;
}
@@ -639,29 +885,31 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
unsigned long flags;
unsigned long ticks;
- *data1 = 1; /* status of test, default to fail */
rc = 1; /* default to fail */
if (netif_running(dev))
+#ifdef CONFIG_PCNET32_NAPI
+ pcnet32_netif_stop(dev);
+#else
pcnet32_close(dev);
+#endif
spin_lock_irqsave(&lp->lock, flags);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
+
+ numbuffs = min(numbuffs, (int)min(lp->rx_ring_size, lp->tx_ring_size));
/* Reset the PCNET32 */
lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
/* switch pcnet32 to 32bit mode */
lp->a.write_bcr(ioaddr, 20, 2);
- lp->init_block.mode =
- le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
- lp->init_block.filter[0] = 0;
- lp->init_block.filter[1] = 0;
-
/* purge & init rings but don't actually restart */
pcnet32_restart(dev, 0x0000);
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
/* Initialize Transmit buffers. */
size = data_len + 15;
@@ -703,14 +951,15 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */
- x = x | 0x0002;
- a->write_bcr(ioaddr, 32, x);
+ x = a->read_bcr(ioaddr, 32); /* set internal loopback in BCR32 */
+ a->write_bcr(ioaddr, 32, x | 0x0002);
- lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */
+ /* set int loopback in CSR15 */
+ x = a->read_csr(ioaddr, CSR15) & 0xfffc;
+ lp->a.write_csr(ioaddr, CSR15, x | 0x0044);
teststatus = le16_to_cpu(0x8000);
- lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_START); /* Set STRT bit */
/* Check status of descriptors */
for (x = 0; x < numbuffs; x++) {
@@ -718,7 +967,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
rmb();
while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) {
spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
+ msleep(1);
spin_lock_irqsave(&lp->lock, flags);
rmb();
ticks++;
@@ -731,7 +980,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP); /* Set STOP bit */
wmb();
if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) {
printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name);
@@ -764,26 +1013,36 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
}
x++;
}
- if (!rc) {
- *data1 = 0;
- }
clean_up:
+ *data1 = rc;
pcnet32_purge_tx_ring(dev);
- x = a->read_csr(ioaddr, 15) & 0xFFFF;
- a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */
+
+ x = a->read_csr(ioaddr, CSR15);
+ a->write_csr(ioaddr, CSR15, (x & ~0x0044)); /* reset bits 6 and 2 */
x = a->read_bcr(ioaddr, 32); /* reset internal loopback */
- x = x & ~0x0002;
- a->write_bcr(ioaddr, 32, x);
+ a->write_bcr(ioaddr, 32, (x & ~0x0002));
+#ifdef CONFIG_PCNET32_NAPI
+ if (netif_running(dev)) {
+ pcnet32_netif_start(dev);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ } else {
+ pcnet32_purge_rx_ring(dev);
+ lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ }
spin_unlock_irqrestore(&lp->lock, flags);
-
+#else
if (netif_running(dev)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
pcnet32_open(dev);
} else {
+ pcnet32_purge_rx_ring(dev);
lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
+ spin_unlock_irqrestore(&lp->lock, flags);
}
+#endif
return (rc);
} /* end pcnet32_loopback_test */
@@ -845,6 +1104,329 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
return 0;
}
+/*
+ * lp->lock must be held.
+ */
+static int pcnet32_suspend(struct net_device *dev, unsigned long *flags,
+ int can_sleep)
+{
+ int csr5;
+ struct pcnet32_private *lp = dev->priv;
+ struct pcnet32_access *a = &lp->a;
+ ulong ioaddr = dev->base_addr;
+ int ticks;
+
+ /* really old chips have to be stopped. */
+ if (lp->chip_version < PCNET32_79C970A)
+ return 0;
+
+ /* set SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 | CSR5_SUSPEND);
+
+ /* poll waiting for bit to be set */
+ ticks = 0;
+ while (!(a->read_csr(ioaddr, CSR5) & CSR5_SUSPEND)) {
+ spin_unlock_irqrestore(&lp->lock, *flags);
+ if (can_sleep)
+ msleep(1);
+ else
+ mdelay(1);
+ spin_lock_irqsave(&lp->lock, *flags);
+ ticks++;
+ if (ticks > 200) {
+ if (netif_msg_hw(lp))
+ printk(KERN_DEBUG
+ "%s: Error getting into suspend!\n",
+ dev->name);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * process one receive descriptor entry
+ */
+
+static void pcnet32_rx_entry(struct net_device *dev,
+ struct pcnet32_private *lp,
+ struct pcnet32_rx_head *rxp,
+ int entry)
+{
+ int status = (short)le16_to_cpu(rxp->status) >> 8;
+ int rx_in_place = 0;
+ struct sk_buff *skb;
+ short pkt_len;
+
+ if (status != 0x03) { /* There was an error. */
+ /*
+ * There is a tricky error noted by John Murphy,
+ * <murf@perftech.com> to Russ Nelson: Even with full-sized
+ * buffers it's possible for a jabber packet to use two
+ * buffers, with only the last correctly noting the error.
+ */
+ if (status & 0x01) /* Only count a general error at the */
+ lp->stats.rx_errors++; /* end of a packet. */
+ if (status & 0x20)
+ lp->stats.rx_frame_errors++;
+ if (status & 0x10)
+ lp->stats.rx_over_errors++;
+ if (status & 0x08)
+ lp->stats.rx_crc_errors++;
+ if (status & 0x04)
+ lp->stats.rx_fifo_errors++;
+ return;
+ }
+
+ pkt_len = (le32_to_cpu(rxp->msg_length) & 0xfff) - 4;
+
+ /* Discard oversize frames. */
+ if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR "%s: Impossible packet size %d!\n",
+ dev->name, pkt_len);
+ lp->stats.rx_errors++;
+ return;
+ }
+ if (pkt_len < 60) {
+ if (netif_msg_rx_err(lp))
+ printk(KERN_ERR "%s: Runt packet!\n", dev->name);
+ lp->stats.rx_errors++;
+ return;
+ }
+
+ if (pkt_len > rx_copybreak) {
+ struct sk_buff *newskb;
+
+ if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) {
+ skb_reserve(newskb, 2);
+ skb = lp->rx_skbuff[entry];
+ pci_unmap_single(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ skb_put(skb, pkt_len);
+ lp->rx_skbuff[entry] = newskb;
+ newskb->dev = dev;
+ lp->rx_dma_addr[entry] =
+ pci_map_single(lp->pci_dev,
+ newskb->data,
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ rxp->base = le32_to_cpu(lp->rx_dma_addr[entry]);
+ rx_in_place = 1;
+ } else
+ skb = NULL;
+ } else {
+ skb = dev_alloc_skb(pkt_len + 2);
+ }
+
+ if (skb == NULL) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: Memory squeeze, dropping packet.\n",
+ dev->name);
+ lp->stats.rx_dropped++;
+ return;
+ }
+ skb->dev = dev;
+ if (!rx_in_place) {
+ skb_reserve(skb, 2); /* 16 byte align */
+ skb_put(skb, pkt_len); /* Make room */
+ pci_dma_sync_single_for_cpu(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ eth_copy_and_sum(skb,
+ (unsigned char *)(lp->rx_skbuff[entry]->data),
+ pkt_len, 0);
+ pci_dma_sync_single_for_device(lp->pci_dev,
+ lp->rx_dma_addr[entry],
+ PKT_BUF_SZ - 2,
+ PCI_DMA_FROMDEVICE);
+ }
+ lp->stats.rx_bytes += skb->len;
+ skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_PCNET32_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif
+ dev->last_rx = jiffies;
+ lp->stats.rx_packets++;
+ return;
+}
+
+static int pcnet32_rx(struct net_device *dev, int quota)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int entry = lp->cur_rx & lp->rx_mod_mask;
+ struct pcnet32_rx_head *rxp = &lp->rx_ring[entry];
+ int npackets = 0;
+
+ /* If we own the next entry, it's a new packet. Send it up. */
+ while (quota > npackets && (short)le16_to_cpu(rxp->status) >= 0) {
+ pcnet32_rx_entry(dev, lp, rxp, entry);
+ npackets += 1;
+ /*
+ * The docs say that the buffer length isn't touched, but Andrew
+ * Boyd of QNX reports that some revs of the 79C965 clear it.
+ */
+ rxp->buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
+ wmb(); /* Make sure owner changes after others are visible */
+ rxp->status = le16_to_cpu(0x8000);
+ entry = (++lp->cur_rx) & lp->rx_mod_mask;
+ rxp = &lp->rx_ring[entry];
+ }
+
+ return npackets;
+}
+
+static int pcnet32_tx(struct net_device *dev)
+{
+ struct pcnet32_private *lp = dev->priv;
+ unsigned int dirty_tx = lp->dirty_tx;
+ int delta;
+ int must_restart = 0;
+
+ while (dirty_tx != lp->cur_tx) {
+ int entry = dirty_tx & lp->tx_mod_mask;
+ int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+
+ if (status < 0)
+ break; /* It still hasn't been Txed */
+
+ lp->tx_ring[entry].base = 0;
+
+ if (status & 0x4000) {
+ /* There was a major error, log it. */
+ int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
+ lp->stats.tx_errors++;
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx error status=%04x err_status=%08x\n",
+ dev->name, status,
+ err_status);
+ if (err_status & 0x04000000)
+ lp->stats.tx_aborted_errors++;
+ if (err_status & 0x08000000)
+ lp->stats.tx_carrier_errors++;
+ if (err_status & 0x10000000)
+ lp->stats.tx_window_errors++;
+#ifndef DO_DXSUFLO
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx FIFO error!\n",
+ dev->name);
+ must_restart = 1;
+ }
+#else
+ if (err_status & 0x40000000) {
+ lp->stats.tx_fifo_errors++;
+ if (!lp->dxsuflo) { /* If controller doesn't recover ... */
+ /* Ackk! On FIFO errors the Tx unit is turned off! */
+ /* Remove this verbosity later! */
+ if (netif_msg_tx_err(lp))
+ printk(KERN_ERR
+ "%s: Tx FIFO error!\n",
+ dev->name);
+ must_restart = 1;
+ }
+ }
+#endif
+ } else {
+ if (status & 0x1800)
+ lp->stats.collisions++;
+ lp->stats.tx_packets++;
+ }
+
+ /* We must free the original skb */
+ if (lp->tx_skbuff[entry]) {
+ pci_unmap_single(lp->pci_dev,
+ lp->tx_dma_addr[entry],
+ lp->tx_skbuff[entry]->
+ len, PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(lp->tx_skbuff[entry]);
+ lp->tx_skbuff[entry] = NULL;
+ lp->tx_dma_addr[entry] = 0;
+ }
+ dirty_tx++;
+ }
+
+ delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size);
+ if (delta > lp->tx_ring_size) {
+ if (netif_msg_drv(lp))
+ printk(KERN_ERR
+ "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+ dev->name, dirty_tx, lp->cur_tx,
+ lp->tx_full);
+ dirty_tx += lp->tx_ring_size;
+ delta -= lp->tx_ring_size;
+ }
+
+ if (lp->tx_full &&
+ netif_queue_stopped(dev) &&
+ delta < lp->tx_ring_size - 2) {
+ /* The ring is no longer full, clear tbusy. */
+ lp->tx_full = 0;
+ netif_wake_queue(dev);
+ }
+ lp->dirty_tx = dirty_tx;
+
+ return must_restart;
+}
+
+#ifdef CONFIG_PCNET32_NAPI
+static int pcnet32_poll(struct net_device *dev, int *budget)
+{
+ struct pcnet32_private *lp = dev->priv;
+ int quota = min(dev->quota, *budget);
+ unsigned long ioaddr = dev->base_addr;
+ unsigned long flags;
+ u16 val;
+
+ quota = pcnet32_rx(dev, quota);
+
+ spin_lock_irqsave(&lp->lock, flags);
+ if (pcnet32_tx(dev)) {
+ /* reset the chip to clear the error condition, then restart */
+ lp->a.reset(ioaddr);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ pcnet32_restart(dev, CSR0_START);
+ netif_wake_queue(dev);
+ }
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ *budget -= quota;
+ dev->quota -= quota;
+
+ if (dev->quota == 0) {
+ return 1;
+ }
+
+ netif_rx_complete(dev);
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ /* clear interrupt masks */
+ val = lp->a.read_csr(ioaddr, CSR3);
+ val &= 0x00ff;
+ lp->a.write_csr(ioaddr, CSR3, val);
+
+ /* Set interrupt enable. */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+ mmiowb();
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+}
+#endif
+
#define PCNET32_REGS_PER_PHY 32
#define PCNET32_MAX_PHYS 32
static int pcnet32_get_regs_len(struct net_device *dev)
@@ -863,32 +1445,13 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
struct pcnet32_private *lp = dev->priv;
struct pcnet32_access *a = &lp->a;
ulong ioaddr = dev->base_addr;
- int ticks;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- csr0 = a->read_csr(ioaddr, 0);
- if (!(csr0 & 0x0004)) { /* If not stopped */
- /* set SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0001);
-
- /* poll waiting for bit to be set */
- ticks = 0;
- while (!(a->read_csr(ioaddr, 5) & 0x0001)) {
- spin_unlock_irqrestore(&lp->lock, flags);
- mdelay(1);
- spin_lock_irqsave(&lp->lock, flags);
- ticks++;
- if (ticks > 200) {
- if (netif_msg_hw(lp))
- printk(KERN_DEBUG
- "%s: Error getting into suspend!\n",
- dev->name);
- break;
- }
- }
- }
+ csr0 = a->read_csr(ioaddr, CSR0);
+ if (!(csr0 & CSR0_STOP)) /* If not stopped */
+ pcnet32_suspend(dev, &flags, 1);
/* read address PROM */
for (i = 0; i < 16; i += 2)
@@ -925,15 +1488,18 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs,
}
}
- if (!(csr0 & 0x0004)) { /* If not stopped */
+ if (!(csr0 & CSR0_STOP)) { /* If not stopped */
+ int csr5;
+
/* clear SUSPEND (SPND) - CSR5 bit 0 */
- a->write_csr(ioaddr, 5, 0x0000);
+ csr5 = a->read_csr(ioaddr, CSR5);
+ a->write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
}
spin_unlock_irqrestore(&lp->lock, flags);
}
-static struct ethtool_ops pcnet32_ethtool_ops = {
+static const struct ethtool_ops pcnet32_ethtool_ops = {
.get_settings = pcnet32_get_settings,
.set_settings = pcnet32_set_settings,
.get_drvinfo = pcnet32_get_drvinfo,
@@ -958,7 +1524,7 @@ static struct ethtool_ops pcnet32_ethtool_ops = {
/* only probes for non-PCI devices, the rest are handled by
* pci_register_driver via pcnet32_probe_pci */
-static void __devinit pcnet32_probe_vlbus(void)
+static void __devinit pcnet32_probe_vlbus(unsigned int *pcnet32_portlist)
{
unsigned int *port, ioaddr;
@@ -1274,6 +1840,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
lp->mii_if.reg_num_mask = 0x1f;
lp->dxsuflo = dxsuflo;
lp->mii = mii;
+ lp->chip_version = chip_version;
lp->msg_enable = pcnet32_debug;
if ((cards_found >= MAX_UNITS)
|| (options[cards_found] > sizeof(options_mapping)))
@@ -1337,7 +1904,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
* boards will work.
*/
/* Trigger an initialization just for the interrupt. */
- a->write_csr(ioaddr, 0, 0x41);
+ a->write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_INIT);
mdelay(1);
dev->irq = probe_irq_off(irq_mask);
@@ -1396,6 +1963,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev)
dev->ethtool_ops = &pcnet32_ethtool_ops;
dev->tx_timeout = pcnet32_tx_timeout;
dev->watchdog_timeo = (5 * HZ);
+ dev->weight = lp->rx_ring_size / 2;
+#ifdef CONFIG_PCNET32_NAPI
+ dev->poll = pcnet32_poll;
+#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = pcnet32_poll_controller;
@@ -1442,7 +2013,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
lp->tx_ring_size,
&lp->tx_ring_dma_addr);
if (lp->tx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
@@ -1454,52 +2025,48 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name)
lp->rx_ring_size,
&lp->rx_ring_dma_addr);
if (lp->rx_ring == NULL) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Consistent memory allocation failed.\n",
name);
return -ENOMEM;
}
- lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size,
+ lp->tx_dma_addr = kcalloc(lp->tx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->tx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size);
- lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size,
+ lp->rx_dma_addr = kcalloc(lp->rx_ring_size, sizeof(dma_addr_t),
GFP_ATOMIC);
if (!lp->rx_dma_addr) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size);
- lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size,
+ lp->tx_skbuff = kcalloc(lp->tx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->tx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size);
- lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size,
+ lp->rx_skbuff = kcalloc(lp->rx_ring_size, sizeof(struct sk_buff *),
GFP_ATOMIC);
if (!lp->rx_skbuff) {
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk("\n" KERN_ERR PFX
"%s: Memory allocation failed.\n", name);
return -ENOMEM;
}
- memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size);
return 0;
}
@@ -1547,7 +2114,7 @@ static int pcnet32_open(struct net_device *dev)
unsigned long flags;
if (request_irq(dev->irq, &pcnet32_interrupt,
- lp->shared_irq ? SA_SHIRQ : 0, dev->name,
+ lp->shared_irq ? IRQF_SHARED : 0, dev->name,
(void *)dev)) {
return -EAGAIN;
}
@@ -1588,10 +2155,7 @@ static int pcnet32_open(struct net_device *dev)
val |= 2;
} else if (lp->options & PCNET32_PORT_ASEL) {
/* workaround of xSeries250, turn on for 79C975 only */
- i = ((lp->a.read_csr(ioaddr, 88) |
- (lp->a.
- read_csr(ioaddr, 89) << 16)) >> 12) & 0xffff;
- if (i == 0x2627)
+ if (lp->chip_version == 0x2627)
val |= 3;
}
lp->a.write_bcr(ioaddr, 9, val);
@@ -1707,9 +2271,9 @@ static int pcnet32_open(struct net_device *dev)
#ifdef DO_DXSUFLO
if (lp->dxsuflo) { /* Disable transmit stop on underflow */
- val = lp->a.read_csr(ioaddr, 3);
+ val = lp->a.read_csr(ioaddr, CSR3);
val |= 0x40;
- lp->a.write_csr(ioaddr, 3, val);
+ lp->a.write_csr(ioaddr, CSR3, val);
}
#endif
@@ -1730,24 +2294,26 @@ static int pcnet32_open(struct net_device *dev)
(lp->dma_addr +
offsetof(struct pcnet32_private, init_block)) >> 16);
- lp->a.write_csr(ioaddr, 4, 0x0915);
- lp->a.write_csr(ioaddr, 0, 0x0001);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
netif_start_queue(dev);
- /* Print the link status and start the watchdog */
- pcnet32_check_media(dev, 1);
- mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+ if (lp->chip_version >= PCNET32_79C970A) {
+ /* Print the link status and start the watchdog */
+ pcnet32_check_media(dev, 1);
+ mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT);
+ }
i = 0;
while (i++ < 100)
- if (lp->a.read_csr(ioaddr, 0) & 0x0100)
+ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
break;
/*
* We used to clear the InitDone bit, 0x0100, here but Mark Stockton
* reports that doing so triggers a bug in the '974.
*/
- lp->a.write_csr(ioaddr, 0, 0x0042);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_NORMAL);
if (netif_msg_ifup(lp))
printk(KERN_DEBUG
@@ -1755,7 +2321,7 @@ static int pcnet32_open(struct net_device *dev)
dev->name, i,
(u32) (lp->dma_addr +
offsetof(struct pcnet32_private, init_block)),
- lp->a.read_csr(ioaddr, 0));
+ lp->a.read_csr(ioaddr, CSR0));
spin_unlock_irqrestore(&lp->lock, flags);
@@ -1763,16 +2329,7 @@ static int pcnet32_open(struct net_device *dev)
err_free_ring:
/* free any allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -1835,7 +2392,7 @@ static int pcnet32_init_ring(struct net_device *dev)
(rx_skbuff = lp->rx_skbuff[i] =
dev_alloc_skb(PKT_BUF_SZ))) {
/* there is not much, we can do at this point */
- if (pcnet32_debug & NETIF_MSG_DRV)
+ if (netif_msg_drv(lp))
printk(KERN_ERR
"%s: pcnet32_init_ring dev_alloc_skb failed.\n",
dev->name);
@@ -1885,7 +2442,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
/* wait for stop */
for (i = 0; i < 100; i++)
- if (lp->a.read_csr(ioaddr, 0) & 0x0004)
+ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_STOP)
break;
if (i >= 100 && netif_msg_drv(lp))
@@ -1898,13 +2455,13 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits)
return;
/* ReInit Ring */
- lp->a.write_csr(ioaddr, 0, 1);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INIT);
i = 0;
while (i++ < 1000)
- if (lp->a.read_csr(ioaddr, 0) & 0x0100)
+ if (lp->a.read_csr(ioaddr, CSR0) & CSR0_IDON)
break;
- lp->a.write_csr(ioaddr, 0, csr0_bits);
+ lp->a.write_csr(ioaddr, CSR0, csr0_bits);
}
static void pcnet32_tx_timeout(struct net_device *dev)
@@ -1917,8 +2474,8 @@ static void pcnet32_tx_timeout(struct net_device *dev)
if (pcnet32_debug & NETIF_MSG_DRV)
printk(KERN_ERR
"%s: transmit timed out, status %4.4x, resetting.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
- lp->a.write_csr(ioaddr, 0, 0x0004);
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
lp->stats.tx_errors++;
if (netif_msg_tx_err(lp)) {
int i;
@@ -1940,7 +2497,7 @@ static void pcnet32_tx_timeout(struct net_device *dev)
le16_to_cpu(lp->tx_ring[i].status));
printk("\n");
}
- pcnet32_restart(dev, 0x0042);
+ pcnet32_restart(dev, CSR0_NORMAL);
dev->trans_start = jiffies;
netif_wake_queue(dev);
@@ -1961,7 +2518,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (netif_msg_tx_queued(lp)) {
printk(KERN_DEBUG
"%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
}
/* Default status -- will not enable Successful-TxDone
@@ -1992,7 +2549,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
lp->stats.tx_bytes += skb->len;
/* Trigger an immediate send poll. */
- lp->a.write_csr(ioaddr, 0, 0x0048);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN | CSR0_TXPOLL);
dev->trans_start = jiffies;
@@ -2011,9 +2568,8 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct net_device *dev = dev_id;
struct pcnet32_private *lp;
unsigned long ioaddr;
- u16 csr0, rap;
+ u16 csr0;
int boguscnt = max_interrupt_work;
- int must_restart;
if (!dev) {
if (pcnet32_debug & NETIF_MSG_INTR)
@@ -2027,141 +2583,34 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock(&lp->lock);
- rap = lp->a.read_rap(ioaddr);
- while ((csr0 = lp->a.read_csr(ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) {
+ csr0 = lp->a.read_csr(ioaddr, CSR0);
+ while ((csr0 & 0x8f00) && --boguscnt >= 0) {
if (csr0 == 0xffff) {
break; /* PCMCIA remove happened */
}
/* Acknowledge all of the current interrupt sources ASAP. */
- lp->a.write_csr(ioaddr, 0, csr0 & ~0x004f);
-
- must_restart = 0;
+ lp->a.write_csr(ioaddr, CSR0, csr0 & ~0x004f);
if (netif_msg_intr(lp))
printk(KERN_DEBUG
"%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
- dev->name, csr0, lp->a.read_csr(ioaddr, 0));
-
- if (csr0 & 0x0400) /* Rx interrupt */
- pcnet32_rx(dev);
-
- if (csr0 & 0x0200) { /* Tx-done interrupt */
- unsigned int dirty_tx = lp->dirty_tx;
- int delta;
-
- while (dirty_tx != lp->cur_tx) {
- int entry = dirty_tx & lp->tx_mod_mask;
- int status =
- (short)le16_to_cpu(lp->tx_ring[entry].
- status);
-
- if (status < 0)
- break; /* It still hasn't been Txed */
-
- lp->tx_ring[entry].base = 0;
-
- if (status & 0x4000) {
- /* There was an major error, log it. */
- int err_status =
- le32_to_cpu(lp->tx_ring[entry].
- misc);
- lp->stats.tx_errors++;
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx error status=%04x err_status=%08x\n",
- dev->name, status,
- err_status);
- if (err_status & 0x04000000)
- lp->stats.tx_aborted_errors++;
- if (err_status & 0x08000000)
- lp->stats.tx_carrier_errors++;
- if (err_status & 0x10000000)
- lp->stats.tx_window_errors++;
-#ifndef DO_DXSUFLO
- if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
- /* Ackk! On FIFO errors the Tx unit is turned off! */
- /* Remove this verbosity later! */
- if (netif_msg_tx_err(lp))
- printk(KERN_ERR
- "%s: Tx FIFO error! CSR0=%4.4x\n",
- dev->name, csr0);
- must_restart = 1;
- }
-#else
- if (err_status & 0x40000000) {
- lp->stats.tx_fifo_errors++;
- if (!lp->dxsuflo) { /* If controller doesn't recover ... */
- /* Ackk! On FIFO errors the Tx unit is turned off! */
- /* Remove this verbosity later! */
- if (netif_msg_tx_err
- (lp))
- printk(KERN_ERR
- "%s: Tx FIFO error! CSR0=%4.4x\n",
- dev->
- name,
- csr0);
- must_restart = 1;
- }
- }
-#endif
- } else {
- if (status & 0x1800)
- lp->stats.collisions++;
- lp->stats.tx_packets++;
- }
-
- /* We must free the original skb */
- if (lp->tx_skbuff[entry]) {
- pci_unmap_single(lp->pci_dev,
- lp->tx_dma_addr[entry],
- lp->tx_skbuff[entry]->
- len, PCI_DMA_TODEVICE);
- dev_kfree_skb_irq(lp->tx_skbuff[entry]);
- lp->tx_skbuff[entry] = NULL;
- lp->tx_dma_addr[entry] = 0;
- }
- dirty_tx++;
- }
-
- delta =
- (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask +
- lp->tx_ring_size);
- if (delta > lp->tx_ring_size) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
- dev->name, dirty_tx, lp->cur_tx,
- lp->tx_full);
- dirty_tx += lp->tx_ring_size;
- delta -= lp->tx_ring_size;
- }
-
- if (lp->tx_full &&
- netif_queue_stopped(dev) &&
- delta < lp->tx_ring_size - 2) {
- /* The ring is no longer full, clear tbusy. */
- lp->tx_full = 0;
- netif_wake_queue(dev);
- }
- lp->dirty_tx = dirty_tx;
- }
+ dev->name, csr0, lp->a.read_csr(ioaddr, CSR0));
/* Log misc errors. */
if (csr0 & 0x4000)
lp->stats.tx_errors++; /* Tx babble. */
if (csr0 & 0x1000) {
/*
- * this happens when our receive ring is full. This shouldn't
- * be a problem as we will see normal rx interrupts for the frames
- * in the receive ring. But there are some PCI chipsets (I can
- * reproduce this on SP3G with Intel saturn chipset) which have
- * sometimes problems and will fill up the receive ring with
- * error descriptors. In this situation we don't get a rx
- * interrupt, but a missed frame interrupt sooner or later.
- * So we try to clean up our receive ring here.
+ * This happens when our receive ring is full. This
+ * shouldn't be a problem as we will see normal rx
+ * interrupts for the frames in the receive ring. But
+ * there are some PCI chipsets (I can reproduce this
+ * on SP3G with Intel saturn chipset) which have
+ * sometimes problems and will fill up the receive
+ * ring with error descriptors. In this situation we
+ * don't get a rx interrupt, but a missed frame
+ * interrupt sooner or later.
*/
- pcnet32_rx(dev);
lp->stats.rx_errors++; /* Missed a Rx frame. */
}
if (csr0 & 0x0800) {
@@ -2171,190 +2620,48 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev->name, csr0);
/* unlike for the lance, there is no restart needed */
}
-
- if (must_restart) {
+#ifdef CONFIG_PCNET32_NAPI
+ if (netif_rx_schedule_prep(dev)) {
+ u16 val;
+ /* set interrupt masks */
+ val = lp->a.read_csr(ioaddr, CSR3);
+ val |= 0x5f00;
+ lp->a.write_csr(ioaddr, CSR3, val);
+ mmiowb();
+ __netif_rx_schedule(dev);
+ break;
+ }
+#else
+ pcnet32_rx(dev, dev->weight);
+ if (pcnet32_tx(dev)) {
/* reset the chip to clear the error condition, then restart */
lp->a.reset(ioaddr);
- lp->a.write_csr(ioaddr, 4, 0x0915);
- pcnet32_restart(dev, 0x0002);
+ lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */
+ pcnet32_restart(dev, CSR0_START);
netif_wake_queue(dev);
}
+#endif
+ csr0 = lp->a.read_csr(ioaddr, CSR0);
}
+#ifndef CONFIG_PCNET32_NAPI
/* Set interrupt enable. */
- lp->a.write_csr(ioaddr, 0, 0x0040);
- lp->a.write_rap(ioaddr, rap);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_INTEN);
+#endif
if (netif_msg_intr(lp))
printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
spin_unlock(&lp->lock);
return IRQ_HANDLED;
}
-static int pcnet32_rx(struct net_device *dev)
-{
- struct pcnet32_private *lp = dev->priv;
- int entry = lp->cur_rx & lp->rx_mod_mask;
- int boguscnt = lp->rx_ring_size / 2;
-
- /* If we own the next entry, it's a new packet. Send it up. */
- while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
- int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
-
- if (status != 0x03) { /* There was an error. */
- /*
- * There is a tricky error noted by John Murphy,
- * <murf@perftech.com> to Russ Nelson: Even with full-sized
- * buffers it's possible for a jabber packet to use two
- * buffers, with only the last correctly noting the error.
- */
- if (status & 0x01) /* Only count a general error at the */
- lp->stats.rx_errors++; /* end of a packet. */
- if (status & 0x20)
- lp->stats.rx_frame_errors++;
- if (status & 0x10)
- lp->stats.rx_over_errors++;
- if (status & 0x08)
- lp->stats.rx_crc_errors++;
- if (status & 0x04)
- lp->stats.rx_fifo_errors++;
- lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
- } else {
- /* Malloc up new buffer, compatible with net-2e. */
- short pkt_len =
- (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)
- - 4;
- struct sk_buff *skb;
-
- /* Discard oversize frames. */
- if (unlikely(pkt_len > PKT_BUF_SZ - 2)) {
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Impossible packet size %d!\n",
- dev->name, pkt_len);
- lp->stats.rx_errors++;
- } else if (pkt_len < 60) {
- if (netif_msg_rx_err(lp))
- printk(KERN_ERR "%s: Runt packet!\n",
- dev->name);
- lp->stats.rx_errors++;
- } else {
- int rx_in_place = 0;
-
- if (pkt_len > rx_copybreak) {
- struct sk_buff *newskb;
-
- if ((newskb =
- dev_alloc_skb(PKT_BUF_SZ))) {
- skb_reserve(newskb, 2);
- skb = lp->rx_skbuff[entry];
- pci_unmap_single(lp->pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ - 2,
- PCI_DMA_FROMDEVICE);
- skb_put(skb, pkt_len);
- lp->rx_skbuff[entry] = newskb;
- newskb->dev = dev;
- lp->rx_dma_addr[entry] =
- pci_map_single(lp->pci_dev,
- newskb->data,
- PKT_BUF_SZ -
- 2,
- PCI_DMA_FROMDEVICE);
- lp->rx_ring[entry].base =
- le32_to_cpu(lp->
- rx_dma_addr
- [entry]);
- rx_in_place = 1;
- } else
- skb = NULL;
- } else {
- skb = dev_alloc_skb(pkt_len + 2);
- }
-
- if (skb == NULL) {
- int i;
- if (netif_msg_drv(lp))
- printk(KERN_ERR
- "%s: Memory squeeze, deferring packet.\n",
- dev->name);
- for (i = 0; i < lp->rx_ring_size; i++)
- if ((short)
- le16_to_cpu(lp->
- rx_ring[(entry +
- i)
- & lp->
- rx_mod_mask].
- status) < 0)
- break;
-
- if (i > lp->rx_ring_size - 2) {
- lp->stats.rx_dropped++;
- lp->rx_ring[entry].status |=
- le16_to_cpu(0x8000);
- wmb(); /* Make sure adapter sees owner change */
- lp->cur_rx++;
- }
- break;
- }
- skb->dev = dev;
- if (!rx_in_place) {
- skb_reserve(skb, 2); /* 16 byte align */
- skb_put(skb, pkt_len); /* Make room */
- pci_dma_sync_single_for_cpu(lp->pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ -
- 2,
- PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb,
- (unsigned char *)(lp->
- rx_skbuff
- [entry]->
- data),
- pkt_len, 0);
- pci_dma_sync_single_for_device(lp->
- pci_dev,
- lp->
- rx_dma_addr
- [entry],
- PKT_BUF_SZ
- - 2,
- PCI_DMA_FROMDEVICE);
- }
- lp->stats.rx_bytes += skb->len;
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- }
- }
- /*
- * The docs say that the buffer length isn't touched, but Andrew Boyd
- * of QNX reports that some revs of the 79C965 clear it.
- */
- lp->rx_ring[entry].buf_length = le16_to_cpu(2 - PKT_BUF_SZ);
- wmb(); /* Make sure owner changes after all others are visible */
- lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
- entry = (++lp->cur_rx) & lp->rx_mod_mask;
- if (--boguscnt <= 0)
- break; /* don't stay in loop forever */
- }
-
- return 0;
-}
-
static int pcnet32_close(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr;
struct pcnet32_private *lp = dev->priv;
- int i;
unsigned long flags;
del_timer_sync(&lp->watchdog_timer);
@@ -2368,10 +2675,10 @@ static int pcnet32_close(struct net_device *dev)
if (netif_msg_ifdown(lp))
printk(KERN_DEBUG
"%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, lp->a.read_csr(ioaddr, 0));
+ dev->name, lp->a.read_csr(ioaddr, CSR0));
/* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
- lp->a.write_csr(ioaddr, 0, 0x0004);
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
/*
* Switch back to 16bit mode to avoid problems with dumb
@@ -2385,31 +2692,8 @@ static int pcnet32_close(struct net_device *dev)
spin_lock_irqsave(&lp->lock, flags);
- /* free all allocated skbuffs */
- for (i = 0; i < lp->rx_ring_size; i++) {
- lp->rx_ring[i].status = 0;
- wmb(); /* Make sure adapter sees owner change */
- if (lp->rx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i],
- PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE);
- dev_kfree_skb(lp->rx_skbuff[i]);
- }
- lp->rx_skbuff[i] = NULL;
- lp->rx_dma_addr[i] = 0;
- }
-
- for (i = 0; i < lp->tx_ring_size; i++) {
- lp->tx_ring[i].status = 0; /* CPU owns buffer */
- wmb(); /* Make sure adapter sees owner change */
- if (lp->tx_skbuff[i]) {
- pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i],
- lp->tx_skbuff[i]->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(lp->tx_skbuff[i]);
- }
- lp->tx_skbuff[i] = NULL;
- lp->tx_dma_addr[i] = 0;
- }
+ pcnet32_purge_rx_ring(dev);
+ pcnet32_purge_tx_ring(dev);
spin_unlock_irqrestore(&lp->lock, flags);
@@ -2420,13 +2704,10 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev)
{
struct pcnet32_private *lp = dev->priv;
unsigned long ioaddr = dev->base_addr;
- u16 saved_addr;
unsigned long flags;
spin_lock_irqsave(&lp->lock, flags);
- saved_addr = lp->a.read_rap(ioaddr);
lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112);
- lp->a.write_rap(ioaddr, saved_addr);
spin_unlock_irqrestore(&lp->lock, flags);
return &lp->stats;
@@ -2439,6 +2720,7 @@ static void pcnet32_load_multicast(struct net_device *dev)
volatile struct pcnet32_init_block *ib = &lp->init_block;
volatile u16 *mcast_table = (u16 *) & ib->filter;
struct dev_mc_list *dmi = dev->mc_list;
+ unsigned long ioaddr = dev->base_addr;
char *addrs;
int i;
u32 crc;
@@ -2447,6 +2729,10 @@ static void pcnet32_load_multicast(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI) {
ib->filter[0] = 0xffffffff;
ib->filter[1] = 0xffffffff;
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+1, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+2, 0xffff);
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER+3, 0xffff);
return;
}
/* clear the multicast filter */
@@ -2468,6 +2754,9 @@ static void pcnet32_load_multicast(struct net_device *dev)
le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) |
(1 << (crc & 0xf)));
}
+ for (i = 0; i < 4; i++)
+ lp->a.write_csr(ioaddr, PCNET32_MC_FILTER + i,
+ le16_to_cpu(mcast_table[i]));
return;
}
@@ -2478,8 +2767,11 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
{
unsigned long ioaddr = dev->base_addr, flags;
struct pcnet32_private *lp = dev->priv;
+ int csr15, suspended;
spin_lock_irqsave(&lp->lock, flags);
+ suspended = pcnet32_suspend(dev, &flags, 0);
+ csr15 = lp->a.read_csr(ioaddr, CSR15);
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
if (netif_msg_hw(lp))
@@ -2488,15 +2780,24 @@ static void pcnet32_set_multicast_list(struct net_device *dev)
lp->init_block.mode =
le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) <<
7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000);
} else {
lp->init_block.mode =
le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7);
+ lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff);
pcnet32_load_multicast(dev);
}
- lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
- pcnet32_restart(dev, 0x0042); /* Resume normal operation */
- netif_wake_queue(dev);
+ if (suspended) {
+ int csr5;
+ /* clear SUSPEND (SPND) - CSR5 bit 0 */
+ csr5 = lp->a.read_csr(ioaddr, CSR5);
+ lp->a.write_csr(ioaddr, CSR5, csr5 & (~CSR5_SUSPEND));
+ } else {
+ lp->a.write_csr(ioaddr, CSR0, CSR0_STOP);
+ pcnet32_restart(dev, CSR0_NORMAL);
+ netif_wake_queue(dev);
+ }
spin_unlock_irqrestore(&lp->lock, flags);
}
@@ -2731,12 +3032,12 @@ static int __init pcnet32_init_module(void)
tx_start = tx_start_pt;
/* find the PCI devices */
- if (!pci_module_init(&pcnet32_driver))
+ if (!pci_register_driver(&pcnet32_driver))
pcnet32_have_pci = 1;
/* should we find any remaining VLbus devices ? */
if (pcnet32vlb)
- pcnet32_probe_vlbus();
+ pcnet32_probe_vlbus(pcnet32_portlist);
if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE))
printk(KERN_INFO PFX "%d cards_found.\n", cards_found);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 2ba6d3a40e2..b79ec0d7480 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -56,5 +56,22 @@ config SMSC_PHY
---help---
Currently supports the LAN83C185 PHY
+config FIXED_PHY
+ tristate "Drivers for PHY emulation on fixed speed/link"
+ depends on PHYLIB
+ ---help---
+ Adds the driver to PHY layer to cover the boards that do not have any PHY bound,
+ but with the ability to manipulate with speed/link in software. The relavant MII
+ speed/duplex parameters could be effectively handled in user-specified fuction.
+ Currently tested with mpc866ads.
+
+config FIXED_MII_10_FDX
+ bool "Emulation for 10M Fdx fixed PHY behavior"
+ depends on FIXED_PHY
+
+config FIXED_MII_100_FDX
+ bool "Emulation for 100M Fdx fixed PHY behavior"
+ depends on FIXED_PHY
+
endmenu
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index a00e6194252..320f8323123 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_QSEMI_PHY) += qsemi.o
obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
+obj-$(CONFIG_FIXED_PHY) += fixed.o
diff --git a/drivers/net/phy/cicada.c b/drivers/net/phy/cicada.c
index 7d8d534255c..ae60e6e4107 100644
--- a/drivers/net/phy/cicada.c
+++ b/drivers/net/phy/cicada.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -104,7 +103,22 @@ static int cis820x_config_intr(struct phy_device *phydev)
return err;
}
-/* Cicada 820x */
+/* Cicada 8201, a.k.a Vitesse VSC8201 */
+static struct phy_driver cis8201_driver = {
+ .phy_id = 0x000fc410,
+ .name = "Cicada Cis8201",
+ .phy_id_mask = 0x000ffff0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &cis820x_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &cis820x_ack_interrupt,
+ .config_intr = &cis820x_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+/* Cicada 8204 */
static struct phy_driver cis8204_driver = {
.phy_id = 0x000fc440,
.name = "Cicada Cis8204",
@@ -119,15 +133,30 @@ static struct phy_driver cis8204_driver = {
.driver = { .owner = THIS_MODULE,},
};
-static int __init cis8204_init(void)
+static int __init cicada_init(void)
{
- return phy_driver_register(&cis8204_driver);
+ int ret;
+
+ ret = phy_driver_register(&cis8204_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register(&cis8201_driver);
+ if (ret)
+ goto err2;
+ return 0;
+
+err2:
+ phy_driver_unregister(&cis8204_driver);
+err1:
+ return ret;
}
-static void __exit cis8204_exit(void)
+static void __exit cicada_exit(void)
{
phy_driver_unregister(&cis8204_driver);
+ phy_driver_unregister(&cis8201_driver);
}
-module_init(cis8204_init);
-module_exit(cis8204_exit);
+module_init(cicada_init);
+module_exit(cicada_exit);
diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c
index 5e9002e444c..aa7983f5583 100644
--- a/drivers/net/phy/davicom.c
+++ b/drivers/net/phy/davicom.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
new file mode 100644
index 00000000000..19f7ee63276
--- /dev/null
+++ b/drivers/net/phy/fixed.c
@@ -0,0 +1,362 @@
+/*
+ * drivers/net/phy/fixed.c
+ *
+ * Driver for fixed PHYs, when transceiver is able to operate in one fixed mode.
+ *
+ * Author: Vitaly Bordug
+ *
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/phy.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#define MII_REGS_NUM 7
+
+/*
+ The idea is to emulate normal phy behavior by responding with
+ pre-defined values to mii BMCR read, so that read_status hook could
+ take all the needed info.
+*/
+
+struct fixed_phy_status {
+ u8 link;
+ u16 speed;
+ u8 duplex;
+};
+
+/*-----------------------------------------------------------------------------
+ * Private information hoder for mii_bus
+ *-----------------------------------------------------------------------------*/
+struct fixed_info {
+ u16 *regs;
+ u8 regs_num;
+ struct fixed_phy_status phy_status;
+ struct phy_device *phydev; /* pointer to the container */
+ /* link & speed cb */
+ int(*link_update)(struct net_device*, struct fixed_phy_status*);
+
+};
+
+/*-----------------------------------------------------------------------------
+ * If something weird is required to be done with link/speed,
+ * network driver is able to assign a function to implement this.
+ * May be useful for PHY's that need to be software-driven.
+ *-----------------------------------------------------------------------------*/
+int fixed_mdio_set_link_update(struct phy_device* phydev,
+ int(*link_update)(struct net_device*, struct fixed_phy_status*))
+{
+ struct fixed_info *fixed;
+
+ if(link_update == NULL)
+ return -EINVAL;
+
+ if(phydev) {
+ if(phydev->bus) {
+ fixed = phydev->bus->priv;
+ fixed->link_update = link_update;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(fixed_mdio_set_link_update);
+
+/*-----------------------------------------------------------------------------
+ * This is used for updating internal mii regs from the status
+ *-----------------------------------------------------------------------------*/
+static int fixed_mdio_update_regs(struct fixed_info *fixed)
+{
+ u16 *regs = fixed->regs;
+ u16 bmsr = 0;
+ u16 bmcr = 0;
+
+ if(!regs) {
+ printk(KERN_ERR "%s: regs not set up", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if(fixed->phy_status.link)
+ bmsr |= BMSR_LSTATUS;
+
+ if(fixed->phy_status.duplex) {
+ bmcr |= BMCR_FULLDPLX;
+
+ switch ( fixed->phy_status.speed ) {
+ case 100:
+ bmsr |= BMSR_100FULL;
+ bmcr |= BMCR_SPEED100;
+ break;
+
+ case 10:
+ bmsr |= BMSR_10FULL;
+ break;
+ }
+ } else {
+ switch ( fixed->phy_status.speed ) {
+ case 100:
+ bmsr |= BMSR_100HALF;
+ bmcr |= BMCR_SPEED100;
+ break;
+
+ case 10:
+ bmsr |= BMSR_100HALF;
+ break;
+ }
+ }
+
+ regs[MII_BMCR] = bmcr;
+ regs[MII_BMSR] = bmsr | 0x800; /*we are always capable of 10 hdx*/
+
+ return 0;
+}
+
+static int fixed_mii_read(struct mii_bus *bus, int phy_id, int location)
+{
+ struct fixed_info *fixed = bus->priv;
+
+ /* if user has registered link update callback, use it */
+ if(fixed->phydev)
+ if(fixed->phydev->attached_dev) {
+ if(fixed->link_update) {
+ fixed->link_update(fixed->phydev->attached_dev,
+ &fixed->phy_status);
+ fixed_mdio_update_regs(fixed);
+ }
+ }
+
+ if ((unsigned int)location >= fixed->regs_num)
+ return -1;
+ return fixed->regs[location];
+}
+
+static int fixed_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val)
+{
+ /* do nothing for now*/
+ return 0;
+}
+
+static int fixed_mii_reset(struct mii_bus *bus)
+{
+ /*nothing here - no way/need to reset it*/
+ return 0;
+}
+
+static int fixed_config_aneg(struct phy_device *phydev)
+{
+ /* :TODO:03/13/2006 09:45:37 PM::
+ The full autoneg funcionality can be emulated,
+ but no need to have anything here for now
+ */
+ return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * the manual bind will do the magic - with phy_id_mask == 0
+ * match will never return true...
+ *-----------------------------------------------------------------------------*/
+static struct phy_driver fixed_mdio_driver = {
+ .name = "Fixed PHY",
+ .features = PHY_BASIC_FEATURES,
+ .config_aneg = fixed_config_aneg,
+ .read_status = genphy_read_status,
+ .driver = { .owner = THIS_MODULE,},
+};
+
+/*-----------------------------------------------------------------------------
+ * This func is used to create all the necessary stuff, bind
+ * the fixed phy driver and register all it on the mdio_bus_type.
+ * speed is either 10 or 100, duplex is boolean.
+ * number is used to create multiple fixed PHYs, so that several devices can
+ * utilize them simultaneously.
+ *-----------------------------------------------------------------------------*/
+static int fixed_mdio_register_device(int number, int speed, int duplex)
+{
+ struct mii_bus *new_bus;
+ struct fixed_info *fixed;
+ struct phy_device *phydev;
+ int err = 0;
+
+ struct device* dev = kzalloc(sizeof(struct device), GFP_KERNEL);
+
+ if (NULL == dev)
+ return -ENOMEM;
+
+ new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
+
+ if (NULL == new_bus) {
+ kfree(dev);
+ return -ENOMEM;
+ }
+ fixed = kzalloc(sizeof(struct fixed_info), GFP_KERNEL);
+
+ if (NULL == fixed) {
+ kfree(dev);
+ kfree(new_bus);
+ return -ENOMEM;
+ }
+
+ fixed->regs = kzalloc(MII_REGS_NUM*sizeof(int), GFP_KERNEL);
+ fixed->regs_num = MII_REGS_NUM;
+ fixed->phy_status.speed = speed;
+ fixed->phy_status.duplex = duplex;
+ fixed->phy_status.link = 1;
+
+ new_bus->name = "Fixed MII Bus",
+ new_bus->read = &fixed_mii_read,
+ new_bus->write = &fixed_mii_write,
+ new_bus->reset = &fixed_mii_reset,
+
+ /*set up workspace*/
+ fixed_mdio_update_regs(fixed);
+ new_bus->priv = fixed;
+
+ new_bus->dev = dev;
+ dev_set_drvdata(dev, new_bus);
+
+ /* create phy_device and register it on the mdio bus */
+ phydev = phy_device_create(new_bus, 0, 0);
+
+ /*
+ Put the phydev pointer into the fixed pack so that bus read/write code could
+ be able to access for instance attached netdev. Well it doesn't have to do
+ so, only in case of utilizing user-specified link-update...
+ */
+ fixed->phydev = phydev;
+
+ if(NULL == phydev) {
+ err = -ENOMEM;
+ goto device_create_fail;
+ }
+
+ phydev->irq = -1;
+ phydev->dev.bus = &mdio_bus_type;
+
+ if(number)
+ snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
+ "fixed_%d@%d:%d", number, speed, duplex);
+ else
+ snprintf(phydev->dev.bus_id, BUS_ID_SIZE,
+ "fixed@%d:%d", speed, duplex);
+ phydev->bus = new_bus;
+
+ err = device_register(&phydev->dev);
+ if(err) {
+ printk(KERN_ERR "Phy %s failed to register\n",
+ phydev->dev.bus_id);
+ goto bus_register_fail;
+ }
+
+ /*
+ the mdio bus has phy_id match... In order not to do it
+ artificially, we are binding the driver here by hand;
+ it will be the same for all the fixed phys anyway.
+ */
+ down_write(&phydev->dev.bus->subsys.rwsem);
+
+ phydev->dev.driver = &fixed_mdio_driver.driver;
+
+ err = phydev->dev.driver->probe(&phydev->dev);
+ if(err < 0) {
+ printk(KERN_ERR "Phy %s: problems with fixed driver\n",phydev->dev.bus_id);
+ up_write(&phydev->dev.bus->subsys.rwsem);
+ goto probe_fail;
+ }
+
+ device_bind_driver(&phydev->dev);
+ up_write(&phydev->dev.bus->subsys.rwsem);
+
+ return 0;
+
+probe_fail:
+ device_unregister(&phydev->dev);
+bus_register_fail:
+ kfree(phydev);
+device_create_fail:
+ kfree(dev);
+ kfree(new_bus);
+ kfree(fixed);
+
+ return err;
+}
+
+
+MODULE_DESCRIPTION("Fixed PHY device & driver for PAL");
+MODULE_AUTHOR("Vitaly Bordug");
+MODULE_LICENSE("GPL");
+
+static int __init fixed_init(void)
+{
+#if 0
+ int ret;
+ int duplex = 0;
+#endif
+
+ /* register on the bus... Not expected to be matched with anything there... */
+ phy_driver_register(&fixed_mdio_driver);
+
+ /* So let the fun begin...
+ We will create several mdio devices here, and will bound the upper
+ driver to them.
+
+ Then the external software can lookup the phy bus by searching
+ fixed@speed:duplex, e.g. fixed@100:1, to be connected to the
+ virtual 100M Fdx phy.
+
+ In case several virtual PHYs required, the bus_id will be in form
+ fixed_<num>@<speed>:<duplex>, which make it able even to define
+ driver-specific link control callback, if for instance PHY is completely
+ SW-driven.
+
+ */
+
+#ifdef CONFIG_FIXED_MII_DUPLEX
+#if 0
+ duplex = 1;
+#endif
+#endif
+
+#ifdef CONFIG_FIXED_MII_100_FDX
+ fixed_mdio_register_device(0, 100, 1);
+#endif
+
+#ifdef CONFIX_FIXED_MII_10_FDX
+ fixed_mdio_register_device(0, 10, 1);
+#endif
+ return 0;
+}
+
+static void __exit fixed_exit(void)
+{
+ phy_driver_unregister(&fixed_mdio_driver);
+ /* :WARNING:02/18/2006 04:32:40 AM:: Cleanup all the created stuff */
+}
+
+module_init(fixed_init);
+module_exit(fixed_exit);
diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c
index bef79e454c3..69d2325f848 100644
--- a/drivers/net/phy/lxt.c
+++ b/drivers/net/phy/lxt.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -123,9 +122,9 @@ static int lxt971_config_intr(struct phy_device *phydev)
}
static struct phy_driver lxt970_driver = {
- .phy_id = 0x07810000,
+ .phy_id = 0x78100000,
.name = "LXT970",
- .phy_id_mask = 0x0fffffff,
+ .phy_id_mask = 0xfffffff0,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_init = lxt970_config_init,
@@ -137,9 +136,9 @@ static struct phy_driver lxt970_driver = {
};
static struct phy_driver lxt971_driver = {
- .phy_id = 0x0001378e,
+ .phy_id = 0x001378e0,
.name = "LXT971",
- .phy_id_mask = 0x0fffffff,
+ .phy_id_mask = 0xfffffff0,
.features = PHY_BASIC_FEATURES,
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index a2d6386d13b..0ad253282d0 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 1b236bdf6b9..cf6660c93ff 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -160,6 +159,7 @@ struct bus_type mdio_bus_type = {
.suspend = mdio_bus_suspend,
.resume = mdio_bus_resume,
};
+EXPORT_SYMBOL(mdio_bus_type);
int __init mdio_bus_init(void)
{
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 33cec2dab94..f5aad77288f 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -14,7 +14,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -420,9 +419,8 @@ void phy_start_machine(struct phy_device *phydev,
/* phy_stop_machine
*
- * description: Stops the state machine timer, sets the state to
- * UP (unless it wasn't up yet), and then frees the interrupt,
- * if it is in use. This function must be called BEFORE
+ * description: Stops the state machine timer, sets the state to UP
+ * (unless it wasn't up yet). This function must be called BEFORE
* phy_detach.
*/
void phy_stop_machine(struct phy_device *phydev)
@@ -434,9 +432,6 @@ void phy_stop_machine(struct phy_device *phydev)
phydev->state = PHY_UP;
spin_unlock(&phydev->lock);
- if (phydev->irq != PHY_POLL)
- phy_stop_interrupts(phydev);
-
phydev->adjust_state = NULL;
}
@@ -557,7 +552,7 @@ int phy_start_interrupts(struct phy_device *phydev)
INIT_WORK(&phydev->phy_queue, phy_change, phydev);
if (request_irq(phydev->irq, phy_interrupt,
- SA_SHIRQ,
+ IRQF_SHARED,
"phy_interrupt",
phydev) < 0) {
printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 7da0e3dd5fe..ecd3da151e2 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -14,7 +14,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -46,6 +45,35 @@ static struct phy_driver genphy_driver;
extern int mdio_bus_init(void);
extern void mdio_bus_exit(void);
+struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
+{
+ struct phy_device *dev;
+ /* We allocate the device, and initialize the
+ * default values */
+ dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
+
+ if (NULL == dev)
+ return (struct phy_device*) PTR_ERR((void*)-ENOMEM);
+
+ dev->speed = 0;
+ dev->duplex = -1;
+ dev->pause = dev->asym_pause = 0;
+ dev->link = 1;
+
+ dev->autoneg = AUTONEG_ENABLE;
+
+ dev->addr = addr;
+ dev->phy_id = phy_id;
+ dev->bus = bus;
+
+ dev->state = PHY_DOWN;
+
+ spin_lock_init(&dev->lock);
+
+ return dev;
+}
+EXPORT_SYMBOL(phy_device_create);
+
/* get_phy_device
*
* description: Reads the ID registers of the PHY at addr on the
@@ -79,27 +107,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
if (0xffffffff == phy_id)
return NULL;
- /* Otherwise, we allocate the device, and initialize the
- * default values */
- dev = kcalloc(1, sizeof(*dev), GFP_KERNEL);
-
- if (NULL == dev)
- return ERR_PTR(-ENOMEM);
-
- dev->speed = 0;
- dev->duplex = -1;
- dev->pause = dev->asym_pause = 0;
- dev->link = 1;
-
- dev->autoneg = AUTONEG_ENABLE;
-
- dev->addr = addr;
- dev->phy_id = phy_id;
- dev->bus = bus;
-
- dev->state = PHY_DOWN;
-
- spin_lock_init(&dev->lock);
+ dev = phy_device_create(bus, addr, phy_id);
return dev;
}
@@ -514,7 +522,7 @@ EXPORT_SYMBOL(genphy_read_status);
static int genphy_config_init(struct phy_device *phydev)
{
- u32 val;
+ int val;
u32 features;
/* For now, I'll claim that the generic driver supports
diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c
index 65d995b02b2..2b50e1739aa 100644
--- a/drivers/net/phy/qsemi.c
+++ b/drivers/net/phy/qsemi.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 25e31fb5cb3..b1d8ed40ad9 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index ffd215d9a9b..792716beb05 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index d4449d6d1fe..d4f54e9798c 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -16,7 +16,7 @@
* parport-sharing awareness code by Philip Blundell.
* SMP locking by Niibe Yutaka.
* Support for parallel ports with no IRQ (poll mode),
- * Modifications to use the parallel port API
+ * Modifications to use the parallel port API
* by Nimrod Zimerman.
*
* Fixes:
@@ -383,7 +383,7 @@ static void
plip_timer_bh(struct net_device *dev)
{
struct net_local *nl = netdev_priv(dev);
-
+
if (!(atomic_read (&nl->kill_timer))) {
plip_interrupt (-1, dev, NULL);
@@ -527,7 +527,7 @@ plip_receive(unsigned short nibble_timeout, struct net_device *dev,
}
/*
- * Determine the packet's protocol ID. The rule here is that we
+ * Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*
@@ -537,16 +537,16 @@ plip_receive(unsigned short nibble_timeout, struct net_device *dev,
* We can't fix the daddr thing as that quirk (more bug) is embedded
* in far too many old systems not all even running Linux.
*/
-
+
static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
-
+
skb->mac.raw=skb->data;
skb_pull(skb,dev->hard_header_len);
eth = eth_hdr(skb);
-
+
if(*eth->h_dest&1)
{
if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
@@ -554,17 +554,17 @@ static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev)
else
skb->pkt_type=PACKET_MULTICAST;
}
-
+
/*
* This ALLMULTI check should be redundant by 1.4
* so don't forget to remove it.
*/
-
+
if (ntohs(eth->h_proto) >= 1536)
return eth->h_proto;
-
+
rawp = skb->data;
-
+
/*
* This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC
@@ -573,7 +573,7 @@ static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev)
*/
if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3);
-
+
/*
* Real 802.2 LLC
*/
@@ -972,7 +972,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
}
netif_stop_queue (dev);
-
+
if (skb->len > dev->mtu + dev->hard_header_len) {
printk(KERN_WARNING "%s: packet too big, %d.\n", dev->name, (int)skb->len);
netif_start_queue (dev);
@@ -993,7 +993,7 @@ plip_tx_packet(struct sk_buff *skb, struct net_device *dev)
}
schedule_work(&nl->immediate);
spin_unlock_irq(&nl->lock);
-
+
return 0;
}
@@ -1032,7 +1032,7 @@ int plip_hard_header_cache(struct neighbour *neigh,
{
struct net_local *nl = neigh->dev->priv;
int ret;
-
+
if ((ret = nl->orig_hard_header_cache(neigh, hh)) == 0)
{
struct ethhdr *eth;
@@ -1041,9 +1041,9 @@ int plip_hard_header_cache(struct neighbour *neigh,
HH_DATA_OFF(sizeof(*eth)));
plip_rewrite_address (neigh->dev, eth);
}
-
+
return ret;
-}
+}
/* Open/initialize the board. This is called (in the current kernel)
sometime after booting when the 'ifconfig' program is run.
@@ -1187,7 +1187,7 @@ plip_wakeup(void *handle)
else
return;
}
-
+
if (!(dev->flags & IFF_UP))
/* Don't need the port when the interface is down */
return;
@@ -1264,7 +1264,7 @@ static void plip_attach (struct parport *port)
struct net_local *nl;
char name[IFNAMSIZ];
- if ((parport[0] == -1 && (!timid || !port->devices)) ||
+ if ((parport[0] == -1 && (!timid || !port->devices)) ||
plip_searchfor(parport, port->number)) {
if (unit == PLIP_MAX) {
printk(KERN_ERR "plip: too many devices\n");
@@ -1277,7 +1277,7 @@ static void plip_attach (struct parport *port)
printk(KERN_ERR "plip: memory squeeze\n");
return;
}
-
+
strcpy(dev->name, name);
SET_MODULE_OWNER(dev);
@@ -1290,7 +1290,7 @@ static void plip_attach (struct parport *port)
nl = netdev_priv(dev);
nl->pardev = parport_register_device(port, name, plip_preempt,
- plip_wakeup, plip_interrupt,
+ plip_wakeup, plip_interrupt,
0, dev);
if (!nl->pardev) {
@@ -1384,7 +1384,7 @@ static int __init plip_setup(char *str)
/* disable driver on "plip=" or "plip=0" */
parport[0] = -2;
} else {
- printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n",
+ printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n",
ints[1]);
}
}
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 23659fd7c3a..933e2f3c77a 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -125,8 +125,8 @@ static struct ppp_channel_ops async_ops = {
* way to fix this is to use a rwlock in the tty struct, but for now
* we use a single global rwlock for all ttys in ppp line discipline.
*
- * FIXME: this is no longer true. The _close path for the ldisc is
- * now guaranteed to be sane.
+ * FIXME: this is no longer true. The _close path for the ldisc is
+ * now guaranteed to be sane.
*/
static DEFINE_RWLOCK(disc_data_lock);
@@ -277,7 +277,7 @@ ppp_asynctty_write(struct tty_struct *tty, struct file *file,
* Called in process context only. May be re-entered by multiple
* ioctl calling threads.
*/
-
+
static int
ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
diff --git a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
index 3872088fdd1..f54c55242f4 100644
--- a/drivers/net/ppp_deflate.c
+++ b/drivers/net/ppp_deflate.c
@@ -635,7 +635,7 @@ static struct compressor ppp_deflate_draft = {
};
static int __init deflate_init(void)
-{
+{
int answer = ppp_register_compressor(&ppp_deflate);
if (answer == 0)
printk(KERN_INFO
@@ -643,7 +643,7 @@ static int __init deflate_init(void)
ppp_register_compressor(&ppp_deflate_draft);
return answer;
}
-
+
static void __exit deflate_cleanup(void)
{
ppp_unregister_compressor(&ppp_deflate);
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 01cd8ec751e..f5802e7b08e 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -22,13 +22,11 @@
* ==FILEVERSION 20041108==
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/netdevice.h>
#include <linux/poll.h>
#include <linux/ppp_defs.h>
@@ -194,7 +192,7 @@ struct cardmap {
void *ptr[CARDMAP_WIDTH];
};
static void *cardmap_get(struct cardmap *map, unsigned int nr);
-static void cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
+static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr);
static unsigned int cardmap_find_first_free(struct cardmap *map);
static void cardmap_destroy(struct cardmap **map);
@@ -306,7 +304,7 @@ static const int npindex_to_proto[NUM_NP] = {
PPP_MPLS_UC,
PPP_MPLS_MC,
};
-
+
/* Translates an ethertype into an NP index */
static inline int ethertype_to_npindex(int ethertype)
{
@@ -863,10 +861,6 @@ static int __init ppp_init(void)
goto out_chrdev;
}
class_device_create(ppp_class, NULL, MKDEV(PPP_MAJOR, 0), NULL, "ppp");
- err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0),
- S_IFCHR|S_IRUSR|S_IWUSR, "ppp");
- if (err)
- goto out_class;
}
out:
@@ -874,9 +868,6 @@ out:
printk(KERN_ERR "failed to register PPP device (%d)\n", err);
return err;
-out_class:
- class_device_destroy(ppp_class, MKDEV(PPP_MAJOR,0));
- class_destroy(ppp_class);
out_chrdev:
unregister_chrdev(PPP_MAJOR, "ppp");
goto out;
@@ -1628,11 +1619,11 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
case PPP_VJC_UNCOMP:
if (ppp->vj == 0 || (ppp->flags & SC_REJ_COMP_TCP))
goto err;
-
+
/* Until we fix the decompressor need to make sure
* data portion is linear.
*/
- if (!pskb_may_pull(skb, skb->len))
+ if (!pskb_may_pull(skb, skb->len))
goto err;
if (slhc_remember(ppp->vj, skb->data + 2, skb->len - 2) <= 0) {
@@ -2004,10 +1995,9 @@ ppp_register_channel(struct ppp_channel *chan)
{
struct channel *pch;
- pch = kmalloc(sizeof(struct channel), GFP_KERNEL);
+ pch = kzalloc(sizeof(struct channel), GFP_KERNEL);
if (pch == 0)
return -ENOMEM;
- memset(pch, 0, sizeof(struct channel));
pch->ppp = NULL;
pch->chan = chan;
chan->ppp = pch;
@@ -2195,7 +2185,7 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
switch (CCP_CODE(dp)) {
case CCP_CONFREQ:
- /* A ConfReq starts negotiation of compression
+ /* A ConfReq starts negotiation of compression
* in one direction of transmission,
* and hence brings it down...but which way?
*
@@ -2205,16 +2195,16 @@ ppp_ccp_peek(struct ppp *ppp, struct sk_buff *skb, int inbound)
if(inbound)
/* He is proposing what I should send */
ppp->xstate &= ~SC_COMP_RUN;
- else
+ else
/* I am proposing to what he should send */
ppp->rstate &= ~SC_DECOMP_RUN;
-
+
break;
-
+
case CCP_TERMREQ:
case CCP_TERMACK:
/*
- * CCP is going down, both directions of transmission
+ * CCP is going down, both directions of transmission
*/
ppp->rstate &= ~SC_DECOMP_RUN;
ppp->xstate &= ~SC_COMP_RUN;
@@ -2417,13 +2407,12 @@ ppp_create_interface(int unit, int *retp)
int ret = -ENOMEM;
int i;
- ppp = kmalloc(sizeof(struct ppp), GFP_KERNEL);
+ ppp = kzalloc(sizeof(struct ppp), GFP_KERNEL);
if (!ppp)
goto out;
dev = alloc_netdev(0, "", ppp_setup);
if (!dev)
goto out1;
- memset(ppp, 0, sizeof(struct ppp));
ppp->mru = PPP_MRU;
init_ppp_file(&ppp->file, INTERFACE);
@@ -2463,11 +2452,16 @@ ppp_create_interface(int unit, int *retp)
}
atomic_inc(&ppp_unit_count);
- cardmap_set(&all_ppp_units, unit, ppp);
+ ret = cardmap_set(&all_ppp_units, unit, ppp);
+ if (ret != 0)
+ goto out3;
+
mutex_unlock(&all_ppp_mutex);
*retp = 0;
return ppp;
+out3:
+ atomic_dec(&ppp_unit_count);
out2:
mutex_unlock(&all_ppp_mutex);
free_netdev(dev);
@@ -2578,8 +2572,7 @@ ppp_find_channel(int unit)
list_for_each_entry(pch, &new_channels, list) {
if (pch->file.index == unit) {
- list_del(&pch->list);
- list_add(&pch->list, &all_channels);
+ list_move(&pch->list, &all_channels);
return pch;
}
}
@@ -2682,7 +2675,6 @@ static void __exit ppp_cleanup(void)
cardmap_destroy(&all_ppp_units);
if (unregister_chrdev(PPP_MAJOR, "ppp") != 0)
printk(KERN_ERR "PPP: failed to unregister PPP device\n");
- devfs_remove("ppp");
class_device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0));
class_destroy(ppp_class);
}
@@ -2706,7 +2698,7 @@ static void *cardmap_get(struct cardmap *map, unsigned int nr)
return NULL;
}
-static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
+static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
{
struct cardmap *p;
int i;
@@ -2715,8 +2707,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) {
do {
/* need a new top level */
- struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
- memset(np, 0, sizeof(*np));
+ struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
+ if (!np)
+ goto enomem;
np->ptr[0] = p;
if (p != NULL) {
np->shift = p->shift + CARDMAP_ORDER;
@@ -2730,8 +2723,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
while (p->shift > 0) {
i = (nr >> p->shift) & CARDMAP_MASK;
if (p->ptr[i] == NULL) {
- struct cardmap *np = kmalloc(sizeof(*np), GFP_KERNEL);
- memset(np, 0, sizeof(*np));
+ struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL);
+ if (!np)
+ goto enomem;
np->shift = p->shift - CARDMAP_ORDER;
np->parent = p;
p->ptr[i] = np;
@@ -2746,6 +2740,9 @@ static void cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr)
set_bit(i, &p->inuse);
else
clear_bit(i, &p->inuse);
+ return 0;
+ enomem:
+ return -ENOMEM;
}
static unsigned int cardmap_find_first_free(struct cardmap *map)
diff --git a/drivers/net/ppp_mppe.c b/drivers/net/ppp_mppe.c
index 1985d1b57c4..f3655fd772f 100644
--- a/drivers/net/ppp_mppe.c
+++ b/drivers/net/ppp_mppe.c
@@ -43,7 +43,7 @@
* deprecated in 2.6
*/
-#include <linux/config.h>
+#include <linux/err.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
@@ -65,12 +65,13 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS("ppp-compress-" __stringify(CI_MPPE));
MODULE_VERSION("1.0.2");
-static void
+static unsigned int
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;
+ return length;
}
#define SHA1_PAD_SIZE 40
@@ -96,8 +97,8 @@ static inline void sha_pad_init(struct sha_pad *shapad)
* State for an MPPE (de)compressor.
*/
struct ppp_mppe_state {
- struct crypto_tfm *arc4;
- struct crypto_tfm *sha1;
+ struct crypto_blkcipher *arc4;
+ struct crypto_hash *sha1;
unsigned char *sha1_digest;
unsigned char master_key[MPPE_MAX_KEY_LEN];
unsigned char session_key[MPPE_MAX_KEY_LEN];
@@ -137,14 +138,21 @@ struct ppp_mppe_state {
*/
static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey)
{
+ struct hash_desc desc;
struct scatterlist sg[4];
+ unsigned int nbytes;
- 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));
+ nbytes = setup_sg(&sg[0], state->master_key, state->keylen);
+ nbytes += setup_sg(&sg[1], sha_pad->sha_pad1,
+ sizeof(sha_pad->sha_pad1));
+ nbytes += setup_sg(&sg[2], state->session_key, state->keylen);
+ nbytes += setup_sg(&sg[3], sha_pad->sha_pad2,
+ sizeof(sha_pad->sha_pad2));
- crypto_digest_digest (state->sha1, sg, 4, state->sha1_digest);
+ desc.tfm = state->sha1;
+ desc.flags = 0;
+
+ crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);
memcpy(InterimKey, state->sha1_digest, state->keylen);
}
@@ -157,14 +165,15 @@ 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];
+ struct blkcipher_desc desc = { .tfm = state->arc4 };
get_new_key_from_sha(state, InterimKey);
if (!initial_key) {
- crypto_cipher_setkey(state->arc4, InterimKey, state->keylen);
+ crypto_blkcipher_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) {
+ if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
+ state->keylen) != 0) {
printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
}
} else {
@@ -176,7 +185,7 @@ static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
state->session_key[1] = 0x26;
state->session_key[2] = 0x9e;
}
- crypto_cipher_setkey(state->arc4, state->session_key, state->keylen);
+ crypto_blkcipher_setkey(state->arc4, state->session_key, state->keylen);
}
/*
@@ -197,15 +206,19 @@ static void *mppe_alloc(unsigned char *options, int optlen)
memset(state, 0, sizeof(*state));
- state->arc4 = crypto_alloc_tfm("arc4", 0);
- if (!state->arc4)
+ state->arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(state->arc4)) {
+ state->arc4 = NULL;
goto out_free;
+ }
- state->sha1 = crypto_alloc_tfm("sha1", 0);
- if (!state->sha1)
+ state->sha1 = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
+ if (IS_ERR(state->sha1)) {
+ state->sha1 = NULL;
goto out_free;
+ }
- digestsize = crypto_tfm_alg_digestsize(state->sha1);
+ digestsize = crypto_hash_digestsize(state->sha1);
if (digestsize < MPPE_MAX_KEY_LEN)
goto out_free;
@@ -230,9 +243,9 @@ static void *mppe_alloc(unsigned char *options, int optlen)
if (state->sha1_digest)
kfree(state->sha1_digest);
if (state->sha1)
- crypto_free_tfm(state->sha1);
+ crypto_free_hash(state->sha1);
if (state->arc4)
- crypto_free_tfm(state->arc4);
+ crypto_free_blkcipher(state->arc4);
kfree(state);
out:
return NULL;
@@ -248,9 +261,9 @@ static void mppe_free(void *arg)
if (state->sha1_digest)
kfree(state->sha1_digest);
if (state->sha1)
- crypto_free_tfm(state->sha1);
+ crypto_free_hash(state->sha1);
if (state->arc4)
- crypto_free_tfm(state->arc4);
+ crypto_free_blkcipher(state->arc4);
kfree(state);
}
}
@@ -357,6 +370,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
int isize, int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+ struct blkcipher_desc desc = { .tfm = state->arc4 };
int proto;
struct scatterlist sg_in[1], sg_out[1];
@@ -414,7 +428,7 @@ mppe_compress(void *arg, unsigned char *ibuf, unsigned char *obuf,
/* 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) {
+ if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, isize) != 0) {
printk(KERN_DEBUG "crypto_cypher_encrypt failed\n");
return -1;
}
@@ -463,6 +477,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
int osize)
{
struct ppp_mppe_state *state = (struct ppp_mppe_state *) arg;
+ struct blkcipher_desc desc = { .tfm = state->arc4 };
unsigned ccount;
int flushed = MPPE_BITS(ibuf) & MPPE_BIT_FLUSHED;
int sanity = 0;
@@ -600,7 +615,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
*/
setup_sg(sg_in, ibuf, 1);
setup_sg(sg_out, obuf, 1);
- if (crypto_cipher_decrypt(state->arc4, sg_out, sg_in, 1) != 0) {
+ if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, 1) != 0) {
printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
return DECOMP_ERROR;
}
@@ -620,7 +635,7 @@ mppe_decompress(void *arg, unsigned char *ibuf, int isize, unsigned char *obuf,
/* 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) {
+ if (crypto_blkcipher_decrypt(&desc, sg_out, sg_in, isize - 1)) {
printk(KERN_DEBUG "crypto_cypher_decrypt failed\n");
return DECOMP_ERROR;
}
@@ -695,8 +710,8 @@ static struct compressor ppp_mppe = {
static int __init ppp_mppe_init(void)
{
int answer;
- if (!(crypto_alg_available("arc4", 0) &&
- crypto_alg_available("sha1", 0)))
+ if (!(crypto_has_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC) &&
+ crypto_has_hash("sha1", 0, CRYPTO_ALG_ASYNC)))
return -ENODEV;
sha_pad = kmalloc(sizeof(struct sha_pad), GFP_KERNEL);
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 33255fe8031..b6f0e9a25e2 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -6,7 +6,7 @@
*
* Complete PPP frames without encoding/decoding are exchanged between
* the channel driver and the device driver.
- *
+ *
* The async map IOCTL codes are implemented to keep the user mode
* applications happy if they call them. Synchronous PPP does not use
* the async maps.
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 0d101a18026..0adee733b76 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -386,13 +386,13 @@ static int pppoe_rcv(struct sk_buff *skb,
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto drop;
- if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+ if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
ph = (struct pppoe_hdr *) skb->nh.raw;
po = get_item((unsigned long) ph->sid, eth_hdr(skb)->h_source);
- if (po != NULL)
+ if (po != NULL)
return sk_receive_skb(sk_pppox(po), skb);
drop:
kfree_skb(skb);
@@ -418,7 +418,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb,
if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr)))
goto abort;
- if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
+ if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
goto out;
ph = (struct pppoe_hdr *) skb->nh.raw;
@@ -600,6 +600,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
dev->hard_header_len);
+ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);
po->chan.private = sk;
po->chan.ops = &pppoe_chan_ops;
@@ -745,7 +746,7 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd,
}
-static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
+static int pppoe_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *m, size_t total_len)
{
struct sk_buff *skb = NULL;
@@ -907,8 +908,8 @@ static int pppoe_xmit(struct ppp_channel *chan, struct sk_buff *skb)
}
-static struct ppp_channel_ops pppoe_chan_ops = {
- .start_xmit = pppoe_xmit,
+static struct ppp_channel_ops pppoe_chan_ops = {
+ .start_xmit = pppoe_xmit,
};
static int pppoe_recvmsg(struct kiocb *iocb, struct socket *sock,
@@ -1010,7 +1011,7 @@ static void *pppoe_seq_next(struct seq_file *seq, void *v, loff_t *pos)
goto out;
}
po = v;
- if (po->next)
+ if (po->next)
po = po->next;
else {
int hash = hash_item(po->pppoe_pa.sid, po->pppoe_pa.remote);
@@ -1106,7 +1107,7 @@ static int __init pppoe_init(void)
err = pppoe_proc_init();
if (err)
goto out_unregister_pppox_proto;
-
+
dev_add_pack(&pppoes_ptype);
dev_add_pack(&pppoed_ptype);
register_netdevice_notifier(&pppoe_notifier);
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
new file mode 100644
index 00000000000..15747184634
--- /dev/null
+++ b/drivers/net/qla3xxx.c
@@ -0,0 +1,3536 @@
+/*
+ * QLogic QLA3xxx NIC HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla3xxx for copyright and licensing details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/ip.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_vlan.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+
+#include "qla3xxx.h"
+
+#define DRV_NAME "qla3xxx"
+#define DRV_STRING "QLogic ISP3XXX Network Driver"
+#define DRV_VERSION "v2.02.00-k36"
+#define PFX DRV_NAME " "
+
+static const char ql3xxx_driver_name[] = DRV_NAME;
+static const char ql3xxx_driver_version[] = DRV_VERSION;
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP3XXX Network Driver " DRV_VERSION " ");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+static const u32 default_msg
+ = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
+ | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
+
+static int debug = -1; /* defaults above */
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+static int msi;
+module_param(msi, int, 0);
+MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
+
+static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+ /* required last entry */
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl);
+
+/*
+ * Caller must take hw_lock.
+ */
+static int ql_sem_spinlock(struct ql3_adapter *qdev,
+ u32 sem_mask, u32 sem_bits)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value;
+ unsigned int seconds = 3;
+
+ do {
+ writel((sem_mask | sem_bits),
+ &port_regs->CommonRegs.semaphoreReg);
+ value = readl(&port_regs->CommonRegs.semaphoreReg);
+ if ((value & (sem_mask >> 16)) == sem_bits)
+ return 0;
+ ssleep(1);
+ } while(--seconds);
+ return -1;
+}
+
+static void ql_sem_unlock(struct ql3_adapter *qdev, u32 sem_mask)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ writel(sem_mask, &port_regs->CommonRegs.semaphoreReg);
+ readl(&port_regs->CommonRegs.semaphoreReg);
+}
+
+static int ql_sem_lock(struct ql3_adapter *qdev, u32 sem_mask, u32 sem_bits)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value;
+
+ writel((sem_mask | sem_bits), &port_regs->CommonRegs.semaphoreReg);
+ value = readl(&port_regs->CommonRegs.semaphoreReg);
+ return ((value & (sem_mask >> 16)) == sem_bits);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_wait_for_drvr_lock(struct ql3_adapter *qdev)
+{
+ int i = 0;
+
+ while (1) {
+ if (!ql_sem_lock(qdev,
+ QL_DRVR_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+ * 2) << 1)) {
+ if (i < 10) {
+ ssleep(1);
+ i++;
+ } else {
+ printk(KERN_ERR PFX "%s: Timed out waiting for "
+ "driver lock...\n",
+ qdev->ndev->name);
+ return 0;
+ }
+ } else {
+ printk(KERN_DEBUG PFX
+ "%s: driver lock acquired.\n",
+ qdev->ndev->name);
+ return 1;
+ }
+ }
+}
+
+static void ql_set_register_page(struct ql3_adapter *qdev, u32 page)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ writel(((ISP_CONTROL_NP_MASK << 16) | page),
+ &port_regs->CommonRegs.ispControlStatus);
+ readl(&port_regs->CommonRegs.ispControlStatus);
+ qdev->current_page = page;
+}
+
+static u32 ql_read_common_reg_l(struct ql3_adapter *qdev,
+ u32 __iomem * reg)
+{
+ u32 value;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ value = readl(reg);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ return value;
+}
+
+static u32 ql_read_common_reg(struct ql3_adapter *qdev,
+ u32 __iomem * reg)
+{
+ return readl(reg);
+}
+
+static u32 ql_read_page0_reg_l(struct ql3_adapter *qdev, u32 __iomem *reg)
+{
+ u32 value;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ if (qdev->current_page != 0)
+ ql_set_register_page(qdev,0);
+ value = readl(reg);
+
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return value;
+}
+
+static u32 ql_read_page0_reg(struct ql3_adapter *qdev, u32 __iomem *reg)
+{
+ if (qdev->current_page != 0)
+ ql_set_register_page(qdev,0);
+ return readl(reg);
+}
+
+static void ql_write_common_reg_l(struct ql3_adapter *qdev,
+ u32 __iomem *reg, u32 value)
+{
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ writel(value, reg);
+ readl(reg);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return;
+}
+
+static void ql_write_common_reg(struct ql3_adapter *qdev,
+ u32 __iomem *reg, u32 value)
+{
+ writel(value, reg);
+ readl(reg);
+ return;
+}
+
+static void ql_write_page0_reg(struct ql3_adapter *qdev,
+ u32 __iomem *reg, u32 value)
+{
+ if (qdev->current_page != 0)
+ ql_set_register_page(qdev,0);
+ writel(value, reg);
+ readl(reg);
+ return;
+}
+
+/*
+ * Caller holds hw_lock. Only called during init.
+ */
+static void ql_write_page1_reg(struct ql3_adapter *qdev,
+ u32 __iomem *reg, u32 value)
+{
+ if (qdev->current_page != 1)
+ ql_set_register_page(qdev,1);
+ writel(value, reg);
+ readl(reg);
+ return;
+}
+
+/*
+ * Caller holds hw_lock. Only called during init.
+ */
+static void ql_write_page2_reg(struct ql3_adapter *qdev,
+ u32 __iomem *reg, u32 value)
+{
+ if (qdev->current_page != 2)
+ ql_set_register_page(qdev,2);
+ writel(value, reg);
+ readl(reg);
+ return;
+}
+
+static void ql_disable_interrupts(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
+ (ISP_IMR_ENABLE_INT << 16));
+
+}
+
+static void ql_enable_interrupts(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ ql_write_common_reg_l(qdev, &port_regs->CommonRegs.ispInterruptMaskReg,
+ ((0xff << 16) | ISP_IMR_ENABLE_INT));
+
+}
+
+static void ql_release_to_lrg_buf_free_list(struct ql3_adapter *qdev,
+ struct ql_rcv_buf_cb *lrg_buf_cb)
+{
+ u64 map;
+ lrg_buf_cb->next = NULL;
+
+ if (qdev->lrg_buf_free_tail == NULL) { /* The list is empty */
+ qdev->lrg_buf_free_head = qdev->lrg_buf_free_tail = lrg_buf_cb;
+ } else {
+ qdev->lrg_buf_free_tail->next = lrg_buf_cb;
+ qdev->lrg_buf_free_tail = lrg_buf_cb;
+ }
+
+ if (!lrg_buf_cb->skb) {
+ lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ if (unlikely(!lrg_buf_cb->skb)) {
+ printk(KERN_ERR PFX "%s: failed dev_alloc_skb().\n",
+ qdev->ndev->name);
+ qdev->lrg_buf_skb_check++;
+ } else {
+ /*
+ * We save some space to copy the ethhdr from first
+ * buffer
+ */
+ skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
+ map = pci_map_single(qdev->pdev,
+ lrg_buf_cb->skb->data,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE,
+ PCI_DMA_FROMDEVICE);
+ lrg_buf_cb->buf_phy_addr_low =
+ cpu_to_le32(LS_64BITS(map));
+ lrg_buf_cb->buf_phy_addr_high =
+ cpu_to_le32(MS_64BITS(map));
+ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+ pci_unmap_len_set(lrg_buf_cb, maplen,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE);
+ }
+ }
+
+ qdev->lrg_buf_free_count++;
+}
+
+static struct ql_rcv_buf_cb *ql_get_from_lrg_buf_free_list(struct ql3_adapter
+ *qdev)
+{
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+
+ if ((lrg_buf_cb = qdev->lrg_buf_free_head) != NULL) {
+ if ((qdev->lrg_buf_free_head = lrg_buf_cb->next) == NULL)
+ qdev->lrg_buf_free_tail = NULL;
+ qdev->lrg_buf_free_count--;
+ }
+
+ return lrg_buf_cb;
+}
+
+static u32 addrBits = EEPROM_NO_ADDR_BITS;
+static u32 dataBits = EEPROM_NO_DATA_BITS;
+
+static void fm93c56a_deselect(struct ql3_adapter *qdev);
+static void eeprom_readword(struct ql3_adapter *qdev, u32 eepromAddr,
+ unsigned short *value);
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_select(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_1;
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ((ISP_NVRAM_MASK << 16) | qdev->eeprom_cmd_data));
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_cmd(struct ql3_adapter *qdev, u32 cmd, u32 eepromAddr)
+{
+ int i;
+ u32 mask;
+ u32 dataBit;
+ u32 previousBit;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ /* Clock in a zero, then do the start bit */
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_DO_1);
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_FALL);
+
+ mask = 1 << (FM93C56A_CMD_BITS - 1);
+ /* Force the previous data bit to be different */
+ previousBit = 0xffff;
+ for (i = 0; i < FM93C56A_CMD_BITS; i++) {
+ dataBit =
+ (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
+ if (previousBit != dataBit) {
+ /*
+ * If the bit changed, then change the DO state to
+ * match
+ */
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit);
+ previousBit = dataBit;
+ }
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_FALL);
+ cmd = cmd << 1;
+ }
+
+ mask = 1 << (addrBits - 1);
+ /* Force the previous data bit to be different */
+ previousBit = 0xffff;
+ for (i = 0; i < addrBits; i++) {
+ dataBit =
+ (eepromAddr & mask) ? AUBURN_EEPROM_DO_1 :
+ AUBURN_EEPROM_DO_0;
+ if (previousBit != dataBit) {
+ /*
+ * If the bit changed, then change the DO state to
+ * match
+ */
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit);
+ previousBit = dataBit;
+ }
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->
+ eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_FALL);
+ eepromAddr = eepromAddr << 1;
+ }
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_deselect(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ qdev->eeprom_cmd_data = AUBURN_EEPROM_CS_0;
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void fm93c56a_datain(struct ql3_adapter *qdev, unsigned short *value)
+{
+ int i;
+ u32 data = 0;
+ u32 dataBit;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ /* Read the data bits */
+ /* The first bit is a dummy. Clock right over it. */
+ for (i = 0; i < dataBits; i++) {
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_RISE);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg,
+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_FALL);
+ dataBit =
+ (ql_read_common_reg
+ (qdev,
+ &port_regs->CommonRegs.
+ serialPortInterfaceReg) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+ data = (data << 1) | dataBit;
+ }
+ *value = (u16) data;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void eeprom_readword(struct ql3_adapter *qdev,
+ u32 eepromAddr, unsigned short *value)
+{
+ fm93c56a_select(qdev);
+ fm93c56a_cmd(qdev, (int)FM93C56A_READ, eepromAddr);
+ fm93c56a_datain(qdev, value);
+ fm93c56a_deselect(qdev);
+}
+
+static void ql_swap_mac_addr(u8 * macAddress)
+{
+#ifdef __BIG_ENDIAN
+ u8 temp;
+ temp = macAddress[0];
+ macAddress[0] = macAddress[1];
+ macAddress[1] = temp;
+ temp = macAddress[2];
+ macAddress[2] = macAddress[3];
+ macAddress[3] = temp;
+ temp = macAddress[4];
+ macAddress[4] = macAddress[5];
+ macAddress[5] = temp;
+#endif
+}
+
+static int ql_get_nvram_params(struct ql3_adapter *qdev)
+{
+ u16 *pEEPROMData;
+ u16 checksum = 0;
+ u32 index;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ pEEPROMData = (u16 *) & qdev->nvram_data;
+ qdev->eeprom_cmd_data = 0;
+ if(ql_sem_spinlock(qdev, QL_NVRAM_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 10)) {
+ printk(KERN_ERR PFX"%s: Failed ql_sem_spinlock().\n",
+ __func__);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return -1;
+ }
+
+ for (index = 0; index < EEPROM_SIZE; index++) {
+ eeprom_readword(qdev, index, pEEPROMData);
+ checksum += *pEEPROMData;
+ pEEPROMData++;
+ }
+ ql_sem_unlock(qdev, QL_NVRAM_SEM_MASK);
+
+ if (checksum != 0) {
+ printk(KERN_ERR PFX "%s: checksum should be zero, is %x!!\n",
+ qdev->ndev->name, checksum);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return -1;
+ }
+
+ /*
+ * We have a problem with endianness for the MAC addresses
+ * and the two 8-bit values version, and numPorts. We
+ * have to swap them on big endian systems.
+ */
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn0.macAddress);
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn1.macAddress);
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn2.macAddress);
+ ql_swap_mac_addr(qdev->nvram_data.funcCfg_fn3.macAddress);
+ pEEPROMData = (u16 *) & qdev->nvram_data.version;
+ *pEEPROMData = le16_to_cpu(*pEEPROMData);
+
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return checksum;
+}
+
+static const u32 PHYAddr[2] = {
+ PORT0_PHY_ADDRESS, PORT1_PHY_ADDRESS
+};
+
+static int ql_wait_for_mii_ready(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 temp;
+ int count = 1000;
+
+ while (count) {
+ temp = ql_read_page0_reg(qdev, &port_regs->macMIIStatusReg);
+ if (!(temp & MAC_MII_STATUS_BSY))
+ return 0;
+ udelay(10);
+ count--;
+ }
+ return -1;
+}
+
+static void ql_mii_enable_scan_mode(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 scanControl;
+
+ if (qdev->numPorts > 1) {
+ /* Auto scan will cycle through multiple ports */
+ scanControl = MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC;
+ } else {
+ scanControl = MAC_MII_CONTROL_SC;
+ }
+
+ /*
+ * Scan register 1 of PHY/PETBI,
+ * Set up to scan both devices
+ * The autoscan starts from the first register, completes
+ * the last one before rolling over to the first
+ */
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[0] | MII_SCAN_REGISTER);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (scanControl) |
+ ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS) << 16));
+}
+
+static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev)
+{
+ u8 ret;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ /* See if scan mode is enabled before we turn it off */
+ if (ql_read_page0_reg(qdev, &port_regs->macMIIMgmtControlReg) &
+ (MAC_MII_CONTROL_AS | MAC_MII_CONTROL_SC)) {
+ /* Scan is enabled */
+ ret = 1;
+ } else {
+ /* Scan is disabled */
+ ret = 0;
+ }
+
+ /*
+ * When disabling scan mode you must first change the MII register
+ * address
+ */
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[0] | MII_SCAN_REGISTER);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ ((MAC_MII_CONTROL_SC | MAC_MII_CONTROL_AS |
+ MAC_MII_CONTROL_RC) << 16));
+
+ return ret;
+}
+
+static int ql_mii_write_reg_ex(struct ql3_adapter *qdev,
+ u16 regAddr, u16 value, u32 mac_index)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u8 scanWasEnabled;
+
+ scanWasEnabled = ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[mac_index] | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
+
+ /* Wait for write to complete 9/10/04 SJP */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to"
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ if (scanWasEnabled)
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr,
+ u16 * value, u32 mac_index)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u8 scanWasEnabled;
+ u32 temp;
+
+ scanWasEnabled = ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ PHYAddr[mac_index] | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16));
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
+
+ /* Wait for the read to complete */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free after issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
+ *value = (u16) temp;
+
+ if (scanWasEnabled)
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static int ql_mii_write_reg(struct ql3_adapter *qdev, u16 regAddr, u16 value)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ qdev->PHYAddr | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value);
+
+ /* Wait for write to complete. */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static int ql_mii_read_reg(struct ql3_adapter *qdev, u16 regAddr, u16 *value)
+{
+ u32 temp;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ ql_mii_disable_scan_mode(qdev);
+
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg,
+ qdev->PHYAddr | regAddr);
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16));
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ (MAC_MII_CONTROL_RC << 16) | MAC_MII_CONTROL_RC);
+
+ /* Wait for the read to complete */
+ if (ql_wait_for_mii_ready(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Timed out waiting for management port to "
+ "get free before issuing command.\n",
+ qdev->ndev->name);
+ return -1;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->macMIIMgmtDataReg);
+ *value = (u16) temp;
+
+ ql_mii_enable_scan_mode(qdev);
+
+ return 0;
+}
+
+static void ql_petbi_reset(struct ql3_adapter *qdev)
+{
+ ql_mii_write_reg(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET);
+}
+
+static void ql_petbi_start_neg(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ /* Enable Auto-negotiation sense */
+ ql_mii_read_reg(qdev, PETBI_TBI_CTRL, &reg);
+ reg |= PETBI_TBI_AUTO_SENSE;
+ ql_mii_write_reg(qdev, PETBI_TBI_CTRL, reg);
+
+ ql_mii_write_reg(qdev, PETBI_NEG_ADVER,
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX);
+
+ ql_mii_write_reg(qdev, PETBI_CONTROL_REG,
+ PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
+ PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000);
+
+}
+
+static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET,
+ mac_index);
+}
+
+static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ u16 reg;
+
+ /* Enable Auto-negotiation sense */
+ ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, &reg, mac_index);
+ reg |= PETBI_TBI_AUTO_SENSE;
+ ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index);
+
+ ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER,
+ PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index);
+
+ ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG,
+ PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG |
+ PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000,
+ mac_index);
+}
+
+static void ql_petbi_init(struct ql3_adapter *qdev)
+{
+ ql_petbi_reset(qdev);
+ ql_petbi_start_neg(qdev);
+}
+
+static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_petbi_reset_ex(qdev, mac_index);
+ ql_petbi_start_neg_ex(qdev, mac_index);
+}
+
+static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, PETBI_NEG_PARTNER, &reg) < 0)
+ return 0;
+
+ return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE;
+}
+
+static int ql_phy_get_speed(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
+
+ reg = (((reg & 0x18) >> 3) & 3);
+
+ if (reg == 2)
+ return SPEED_1000;
+ else if (reg == 1)
+ return SPEED_100;
+ else if (reg == 0)
+ return SPEED_10;
+ else
+ return -1;
+}
+
+static int ql_is_full_dup(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, &reg) < 0)
+ return 0;
+
+ return (reg & PHY_AUX_DUPLEX_STAT) != 0;
+}
+
+static int ql_is_phy_neg_pause(struct ql3_adapter *qdev)
+{
+ u16 reg;
+
+ if (ql_mii_read_reg(qdev, PHY_NEG_PARTNER, &reg) < 0)
+ return 0;
+
+ return (reg & PHY_NEG_PAUSE) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_enable(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_PE | (MAC_CONFIG_REG_PE << 16));
+ else
+ value = (MAC_CONFIG_REG_PE << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_soft_reset(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_SR | (MAC_CONFIG_REG_SR << 16));
+ else
+ value = (MAC_CONFIG_REG_SR << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_gig(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_GM | (MAC_CONFIG_REG_GM << 16));
+ else
+ value = (MAC_CONFIG_REG_GM << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_full_dup(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value = (MAC_CONFIG_REG_FD | (MAC_CONFIG_REG_FD << 16));
+ else
+ value = (MAC_CONFIG_REG_FD << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_mac_cfg_pause(struct ql3_adapter *qdev, u32 enable)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 value;
+
+ if (enable)
+ value =
+ ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) |
+ ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16));
+ else
+ value = ((MAC_CONFIG_REG_TF | MAC_CONFIG_REG_RF) << 16);
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev, &port_regs->mac1ConfigReg, value);
+ else
+ ql_write_page0_reg(qdev, &port_regs->mac0ConfigReg, value);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_is_fiber(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_SM0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_SM1;
+ break;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ return (temp & bitToCheck) != 0;
+}
+
+static int ql_is_auto_cfg(struct ql3_adapter *qdev)
+{
+ u16 reg;
+ ql_mii_read_reg(qdev, 0x00, &reg);
+ return (reg & 0x1000) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_is_auto_neg_complete(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_AC0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_AC1;
+ break;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (temp & bitToCheck) {
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX
+ "%s: Auto-Negotiate complete.\n",
+ qdev->ndev->name);
+ return 1;
+ } else {
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Auto-Negotiate incomplete.\n",
+ qdev->ndev->name);
+ return 0;
+ }
+}
+
+/*
+ * ql_is_neg_pause() returns 1 if pause was negotiated to be on
+ */
+static int ql_is_neg_pause(struct ql3_adapter *qdev)
+{
+ if (ql_is_fiber(qdev))
+ return ql_is_petbi_neg_pause(qdev);
+ else
+ return ql_is_phy_neg_pause(qdev);
+}
+
+static int ql_auto_neg_error(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_AE0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_AE1;
+ break;
+ }
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ return (temp & bitToCheck) != 0;
+}
+
+static u32 ql_get_link_speed(struct ql3_adapter *qdev)
+{
+ if (ql_is_fiber(qdev))
+ return SPEED_1000;
+ else
+ return ql_phy_get_speed(qdev);
+}
+
+static int ql_is_link_full_dup(struct ql3_adapter *qdev)
+{
+ if (ql_is_fiber(qdev))
+ return 1;
+ else
+ return ql_is_full_dup(qdev);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_link_down_detect(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = ISP_CONTROL_LINK_DN_0;
+ break;
+ case 1:
+ bitToCheck = ISP_CONTROL_LINK_DN_1;
+ break;
+ }
+
+ temp =
+ ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
+ return (temp & bitToCheck) != 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_link_down_detect_clear(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ switch (qdev->mac_index) {
+ case 0:
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus,
+ (ISP_CONTROL_LINK_DN_0) |
+ (ISP_CONTROL_LINK_DN_0 << 16));
+ break;
+
+ case 1:
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus,
+ (ISP_CONTROL_LINK_DN_1) |
+ (ISP_CONTROL_LINK_DN_1 << 16));
+ break;
+
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_this_adapter_controls_port(struct ql3_adapter *qdev,
+ u32 mac_index)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp;
+
+ switch (mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_F1_ENABLED;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_F3_ENABLED;
+ break;
+ default:
+ break;
+ }
+
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (temp & bitToCheck) {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: is not link master.\n", qdev->ndev->name);
+ return 0;
+ } else {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: is link master.\n", qdev->ndev->name);
+ return 1;
+ }
+}
+
+static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index);
+}
+
+static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ u16 reg;
+
+ ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER,
+ PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index);
+
+ ql_mii_read_reg_ex(qdev, CONTROL_REG, &reg, mac_index);
+ ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG,
+ mac_index);
+}
+
+static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index)
+{
+ ql_phy_reset_ex(qdev, mac_index);
+ ql_phy_start_neg_ex(qdev, mac_index);
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static u32 ql_get_link_state(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ u32 bitToCheck = 0;
+ u32 temp, linkState;
+
+ switch (qdev->mac_index) {
+ case 0:
+ bitToCheck = PORT_STATUS_UP0;
+ break;
+ case 1:
+ bitToCheck = PORT_STATUS_UP1;
+ break;
+ }
+ temp = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (temp & bitToCheck) {
+ linkState = LS_UP;
+ } else {
+ linkState = LS_DOWN;
+ if (netif_msg_link(qdev))
+ printk(KERN_WARNING PFX
+ "%s: Link is down.\n", qdev->ndev->name);
+ }
+ return linkState;
+}
+
+static int ql_port_start(struct ql3_adapter *qdev)
+{
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return -1;
+
+ if (ql_is_fiber(qdev)) {
+ ql_petbi_init(qdev);
+ } else {
+ /* Copper port */
+ ql_phy_init_ex(qdev, qdev->mac_index);
+ }
+
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ return 0;
+}
+
+static int ql_finish_auto_neg(struct ql3_adapter *qdev)
+{
+
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return -1;
+
+ if (!ql_auto_neg_error(qdev)) {
+ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ /* configure the MAC */
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Configuring link.\n",
+ qdev->ndev->
+ name);
+ ql_mac_cfg_soft_reset(qdev, 1);
+ ql_mac_cfg_gig(qdev,
+ (ql_get_link_speed
+ (qdev) ==
+ SPEED_1000));
+ ql_mac_cfg_full_dup(qdev,
+ ql_is_link_full_dup
+ (qdev));
+ ql_mac_cfg_pause(qdev,
+ ql_is_neg_pause
+ (qdev));
+ ql_mac_cfg_soft_reset(qdev, 0);
+
+ /* enable the MAC */
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Enabling mac.\n",
+ qdev->ndev->
+ name);
+ ql_mac_enable(qdev, 1);
+ }
+
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Change port_link_state LS_DOWN to LS_UP.\n",
+ qdev->ndev->name);
+ qdev->port_link_state = LS_UP;
+ netif_start_queue(qdev->ndev);
+ netif_carrier_on(qdev->ndev);
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX
+ "%s: Link is up at %d Mbps, %s duplex.\n",
+ qdev->ndev->name,
+ ql_get_link_speed(qdev),
+ ql_is_link_full_dup(qdev)
+ ? "full" : "half");
+
+ } else { /* Remote error detected */
+
+ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: Remote error detected. "
+ "Calling ql_port_start().\n",
+ qdev->ndev->
+ name);
+ /*
+ * ql_port_start() is shared code and needs
+ * to lock the PHY on it's own.
+ */
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ if(ql_port_start(qdev)) {/* Restart port */
+ return -1;
+ } else
+ return 0;
+ }
+ }
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ return 0;
+}
+
+static void ql_link_state_machine(struct ql3_adapter *qdev)
+{
+ u32 curr_link_state;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ curr_link_state = ql_get_link_state(qdev);
+
+ if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX
+ "%s: Reset in progress, skip processing link "
+ "state.\n", qdev->ndev->name);
+ return;
+ }
+
+ switch (qdev->port_link_state) {
+ default:
+ if (test_bit(QL_LINK_MASTER,&qdev->flags)) {
+ ql_port_start(qdev);
+ }
+ qdev->port_link_state = LS_DOWN;
+ /* Fall Through */
+
+ case LS_DOWN:
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: port_link_state = LS_DOWN.\n",
+ qdev->ndev->name);
+ if (curr_link_state == LS_UP) {
+ if (netif_msg_link(qdev))
+ printk(KERN_DEBUG PFX
+ "%s: curr_link_state = LS_UP.\n",
+ qdev->ndev->name);
+ if (ql_is_auto_neg_complete(qdev))
+ ql_finish_auto_neg(qdev);
+
+ if (qdev->port_link_state == LS_UP)
+ ql_link_down_detect_clear(qdev);
+
+ }
+ break;
+
+ case LS_UP:
+ /*
+ * See if the link is currently down or went down and came
+ * back up
+ */
+ if ((curr_link_state == LS_DOWN) || ql_link_down_detect(qdev)) {
+ if (netif_msg_link(qdev))
+ printk(KERN_INFO PFX "%s: Link is down.\n",
+ qdev->ndev->name);
+ qdev->port_link_state = LS_DOWN;
+ }
+ break;
+ }
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+}
+
+/*
+ * Caller must take hw_lock and QL_PHY_GIO_SEM.
+ */
+static void ql_get_phy_owner(struct ql3_adapter *qdev)
+{
+ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ set_bit(QL_LINK_MASTER,&qdev->flags);
+ else
+ clear_bit(QL_LINK_MASTER,&qdev->flags);
+}
+
+/*
+ * Caller must take hw_lock and QL_PHY_GIO_SEM.
+ */
+static void ql_init_scan_mode(struct ql3_adapter *qdev)
+{
+ ql_mii_enable_scan_mode(qdev);
+
+ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ ql_petbi_init_ex(qdev, qdev->mac_index);
+ } else {
+ if (ql_this_adapter_controls_port(qdev, qdev->mac_index))
+ ql_phy_init_ex(qdev, qdev->mac_index);
+ }
+}
+
+/*
+ * MII_Setup needs to be called before taking the PHY out of reset so that the
+ * management interface clock speed can be set properly. It would be better if
+ * we had a way to disable MDC until after the PHY is out of reset, but we
+ * don't have that capability.
+ */
+static int ql_mii_setup(struct ql3_adapter *qdev)
+{
+ u32 reg;
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return -1;
+
+ /* Divide 125MHz clock by 28 to meet PHY timing requirements */
+ reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
+
+ ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg,
+ reg | ((MAC_MII_CONTROL_CLK_SEL_MASK) << 16));
+
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ return 0;
+}
+
+static u32 ql_supported_modes(struct ql3_adapter *qdev)
+{
+ u32 supported;
+
+ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+ | SUPPORTED_Autoneg;
+ } else {
+ supported = SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP;
+ }
+
+ return supported;
+}
+
+static int ql_get_auto_cfg_status(struct ql3_adapter *qdev)
+{
+ int status;
+ unsigned long hw_flags;
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return 0;
+ status = ql_is_auto_cfg(qdev);
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return status;
+}
+
+static u32 ql_get_speed(struct ql3_adapter *qdev)
+{
+ u32 status;
+ unsigned long hw_flags;
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return 0;
+ status = ql_get_link_speed(qdev);
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return status;
+}
+
+static int ql_get_full_dup(struct ql3_adapter *qdev)
+{
+ int status;
+ unsigned long hw_flags;
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7))
+ return 0;
+ status = ql_is_link_full_dup(qdev);
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ return status;
+}
+
+
+static int ql_get_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = ql_supported_modes(qdev);
+
+ if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) {
+ ecmd->port = PORT_FIBRE;
+ } else {
+ ecmd->port = PORT_TP;
+ ecmd->phy_address = qdev->PHYAddr;
+ }
+ ecmd->advertising = ql_supported_modes(qdev);
+ ecmd->autoneg = ql_get_auto_cfg_status(qdev);
+ ecmd->speed = ql_get_speed(qdev);
+ ecmd->duplex = ql_get_full_dup(qdev);
+ return 0;
+}
+
+static void ql_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ strncpy(drvinfo->driver, ql3xxx_driver_name, 32);
+ strncpy(drvinfo->version, ql3xxx_driver_version, 32);
+ strncpy(drvinfo->fw_version, "N/A", 32);
+ strncpy(drvinfo->bus_info, pci_name(qdev->pdev), 32);
+ drvinfo->n_stats = 0;
+ drvinfo->testinfo_len = 0;
+ drvinfo->regdump_len = 0;
+ drvinfo->eedump_len = 0;
+}
+
+static u32 ql_get_msglevel(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ return qdev->msg_enable;
+}
+
+static void ql_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ qdev->msg_enable = value;
+}
+
+static const struct ethtool_ops ql3xxx_ethtool_ops = {
+ .get_settings = ql_get_settings,
+ .get_drvinfo = ql_get_drvinfo,
+ .get_perm_addr = ethtool_op_get_perm_addr,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = ql_get_msglevel,
+ .set_msglevel = ql_set_msglevel,
+};
+
+static int ql_populate_free_queue(struct ql3_adapter *qdev)
+{
+ struct ql_rcv_buf_cb *lrg_buf_cb = qdev->lrg_buf_free_head;
+ u64 map;
+
+ while (lrg_buf_cb) {
+ if (!lrg_buf_cb->skb) {
+ lrg_buf_cb->skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ if (unlikely(!lrg_buf_cb->skb)) {
+ printk(KERN_DEBUG PFX
+ "%s: Failed dev_alloc_skb().\n",
+ qdev->ndev->name);
+ break;
+ } else {
+ /*
+ * We save some space to copy the ethhdr from
+ * first buffer
+ */
+ skb_reserve(lrg_buf_cb->skb, QL_HEADER_SPACE);
+ map = pci_map_single(qdev->pdev,
+ lrg_buf_cb->skb->data,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE,
+ PCI_DMA_FROMDEVICE);
+ lrg_buf_cb->buf_phy_addr_low =
+ cpu_to_le32(LS_64BITS(map));
+ lrg_buf_cb->buf_phy_addr_high =
+ cpu_to_le32(MS_64BITS(map));
+ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+ pci_unmap_len_set(lrg_buf_cb, maplen,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE);
+ --qdev->lrg_buf_skb_check;
+ if (!qdev->lrg_buf_skb_check)
+ return 1;
+ }
+ }
+ lrg_buf_cb = lrg_buf_cb->next;
+ }
+ return 0;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static void ql_update_lrg_bufq_prod_index(struct ql3_adapter *qdev)
+{
+ struct bufq_addr_element *lrg_buf_q_ele;
+ int i;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+
+ if ((qdev->lrg_buf_free_count >= 8)
+ && (qdev->lrg_buf_release_cnt >= 16)) {
+
+ if (qdev->lrg_buf_skb_check)
+ if (!ql_populate_free_queue(qdev))
+ return;
+
+ lrg_buf_q_ele = qdev->lrg_buf_next_free;
+
+ while ((qdev->lrg_buf_release_cnt >= 16)
+ && (qdev->lrg_buf_free_count >= 8)) {
+
+ for (i = 0; i < 8; i++) {
+ lrg_buf_cb =
+ ql_get_from_lrg_buf_free_list(qdev);
+ lrg_buf_q_ele->addr_high =
+ lrg_buf_cb->buf_phy_addr_high;
+ lrg_buf_q_ele->addr_low =
+ lrg_buf_cb->buf_phy_addr_low;
+ lrg_buf_q_ele++;
+
+ qdev->lrg_buf_release_cnt--;
+ }
+
+ qdev->lrg_buf_q_producer_index++;
+
+ if (qdev->lrg_buf_q_producer_index == NUM_LBUFQ_ENTRIES)
+ qdev->lrg_buf_q_producer_index = 0;
+
+ if (qdev->lrg_buf_q_producer_index ==
+ (NUM_LBUFQ_ENTRIES - 1)) {
+ lrg_buf_q_ele = qdev->lrg_buf_q_virt_addr;
+ }
+ }
+
+ qdev->lrg_buf_next_free = lrg_buf_q_ele;
+
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ rxLargeQProducerIndex,
+ qdev->lrg_buf_q_producer_index);
+ }
+}
+
+static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
+ struct ob_mac_iocb_rsp *mac_rsp)
+{
+ struct ql_tx_buf_cb *tx_cb;
+
+ tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(tx_cb, mapaddr),
+ pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ dev_kfree_skb_irq(tx_cb->skb);
+ qdev->stats.tx_packets++;
+ qdev->stats.tx_bytes += tx_cb->skb->len;
+ tx_cb->skb = NULL;
+ atomic_inc(&qdev->tx_count);
+}
+
+static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
+ struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
+{
+ long int offset;
+ u32 lrg_buf_phy_addr_low = 0;
+ struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
+ struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
+ u32 *curr_ial_ptr;
+ struct sk_buff *skb;
+ u16 length = le16_to_cpu(ib_mac_rsp_ptr->length);
+
+ /*
+ * Get the inbound address list (small buffer).
+ */
+ offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
+ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+ qdev->small_buf_index = 0;
+
+ curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
+ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
+ qdev->small_buf_release_cnt++;
+
+ /* start of first buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+
+ /* start of second buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+
+ /*
+ * Second buffer gets sent up the stack.
+ */
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb = lrg_buf_cb2->skb;
+
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
+
+ skb_put(skb, length);
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(lrg_buf_cb2, mapaddr),
+ pci_unmap_len(lrg_buf_cb2, maplen),
+ PCI_DMA_FROMDEVICE);
+ prefetch(skb->data);
+ skb->dev = qdev->ndev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->protocol = eth_type_trans(skb, qdev->ndev);
+
+ netif_receive_skb(skb);
+ qdev->ndev->last_rx = jiffies;
+ lrg_buf_cb2->skb = NULL;
+
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
+}
+
+static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
+ struct ib_ip_iocb_rsp *ib_ip_rsp_ptr)
+{
+ long int offset;
+ u32 lrg_buf_phy_addr_low = 0;
+ struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
+ struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
+ u32 *curr_ial_ptr;
+ struct sk_buff *skb1, *skb2;
+ struct net_device *ndev = qdev->ndev;
+ u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
+ u16 size = 0;
+
+ /*
+ * Get the inbound address list (small buffer).
+ */
+
+ offset = qdev->small_buf_index * QL_SMALL_BUFFER_SIZE;
+ if (++qdev->small_buf_index == NUM_SMALL_BUFFERS)
+ qdev->small_buf_index = 0;
+ curr_ial_ptr = (u32 *) (qdev->small_buf_virt_addr + offset);
+ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
+ qdev->small_buf_release_cnt++;
+
+ /* start of first buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+ skb1 = lrg_buf_cb1->skb;
+ curr_ial_ptr++; /* 64-bit pointers require two incs. */
+ curr_ial_ptr++;
+
+ /* start of second buffer */
+ lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+ lrg_buf_cb2 = &qdev->lrg_buf[qdev->lrg_buf_index];
+ skb2 = lrg_buf_cb2->skb;
+ qdev->lrg_buf_release_cnt++;
+ if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+ qdev->lrg_buf_index = 0;
+
+ qdev->stats.rx_packets++;
+ qdev->stats.rx_bytes += length;
+
+ /*
+ * Copy the ethhdr from first buffer to second. This
+ * is necessary for IP completions.
+ */
+ if (*((u16 *) skb1->data) != 0xFFFF)
+ size = VLAN_ETH_HLEN;
+ else
+ size = ETH_HLEN;
+
+ skb_put(skb2, length); /* Just the second buffer length here. */
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(lrg_buf_cb2, mapaddr),
+ pci_unmap_len(lrg_buf_cb2, maplen),
+ PCI_DMA_FROMDEVICE);
+ prefetch(skb2->data);
+
+ memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+ skb2->dev = qdev->ndev;
+ skb2->ip_summed = CHECKSUM_NONE;
+ skb2->protocol = eth_type_trans(skb2, qdev->ndev);
+
+ netif_receive_skb(skb2);
+ ndev->last_rx = jiffies;
+ lrg_buf_cb2->skb = NULL;
+
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+ ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
+}
+
+static int ql_tx_rx_clean(struct ql3_adapter *qdev,
+ int *tx_cleaned, int *rx_cleaned, int work_to_do)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct net_rsp_iocb *net_rsp;
+ struct net_device *ndev = qdev->ndev;
+ unsigned long hw_flags;
+
+ /* While there are entries in the completion queue. */
+ while ((cpu_to_le32(*(qdev->prsp_producer_index)) !=
+ qdev->rsp_consumer_index) && (*rx_cleaned < work_to_do)) {
+
+ net_rsp = qdev->rsp_current;
+ switch (net_rsp->opcode) {
+
+ case OPCODE_OB_MAC_IOCB_FN0:
+ case OPCODE_OB_MAC_IOCB_FN2:
+ ql_process_mac_tx_intr(qdev, (struct ob_mac_iocb_rsp *)
+ net_rsp);
+ (*tx_cleaned)++;
+ break;
+
+ case OPCODE_IB_MAC_IOCB:
+ ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
+ net_rsp);
+ (*rx_cleaned)++;
+ break;
+
+ case OPCODE_IB_IP_IOCB:
+ ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
+ net_rsp);
+ (*rx_cleaned)++;
+ break;
+ default:
+ {
+ u32 *tmp = (u32 *) net_rsp;
+ printk(KERN_ERR PFX
+ "%s: Hit default case, not "
+ "handled!\n"
+ " dropping the packet, opcode = "
+ "%x.\n",
+ ndev->name, net_rsp->opcode);
+ printk(KERN_ERR PFX
+ "0x%08lx 0x%08lx 0x%08lx 0x%08lx \n",
+ (unsigned long int)tmp[0],
+ (unsigned long int)tmp[1],
+ (unsigned long int)tmp[2],
+ (unsigned long int)tmp[3]);
+ }
+ }
+
+ qdev->rsp_consumer_index++;
+
+ if (qdev->rsp_consumer_index == NUM_RSP_Q_ENTRIES) {
+ qdev->rsp_consumer_index = 0;
+ qdev->rsp_current = qdev->rsp_q_virt_addr;
+ } else {
+ qdev->rsp_current++;
+ }
+ }
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ ql_update_lrg_bufq_prod_index(qdev);
+
+ if (qdev->small_buf_release_cnt >= 16) {
+ while (qdev->small_buf_release_cnt >= 16) {
+ qdev->small_buf_q_producer_index++;
+
+ if (qdev->small_buf_q_producer_index ==
+ NUM_SBUFQ_ENTRIES)
+ qdev->small_buf_q_producer_index = 0;
+ qdev->small_buf_release_cnt -= 8;
+ }
+
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ rxSmallQProducerIndex,
+ qdev->small_buf_q_producer_index);
+ }
+
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.rspQConsumerIndex,
+ qdev->rsp_consumer_index);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ if (unlikely(netif_queue_stopped(qdev->ndev))) {
+ if (netif_queue_stopped(qdev->ndev) &&
+ (atomic_read(&qdev->tx_count) > (NUM_REQ_Q_ENTRIES / 4)))
+ netif_wake_queue(qdev->ndev);
+ }
+
+ return *tx_cleaned + *rx_cleaned;
+}
+
+static int ql_poll(struct net_device *ndev, int *budget)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ int work_to_do = min(*budget, ndev->quota);
+ int rx_cleaned = 0, tx_cleaned = 0;
+
+ if (!netif_carrier_ok(ndev))
+ goto quit_polling;
+
+ ql_tx_rx_clean(qdev, &tx_cleaned, &rx_cleaned, work_to_do);
+ *budget -= rx_cleaned;
+ ndev->quota -= rx_cleaned;
+
+ if ((!tx_cleaned && !rx_cleaned) || !netif_running(ndev)) {
+quit_polling:
+ netif_rx_complete(ndev);
+ ql_enable_interrupts(qdev);
+ return 0;
+ }
+ return 1;
+}
+
+static irqreturn_t ql3xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+
+ struct net_device *ndev = dev_id;
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value;
+ int handled = 1;
+ u32 var;
+
+ port_regs = qdev->mem_map_registers;
+
+ value =
+ ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+
+ if (value & (ISP_CONTROL_FE | ISP_CONTROL_RI)) {
+ spin_lock(&qdev->adapter_lock);
+ netif_stop_queue(qdev->ndev);
+ netif_carrier_off(qdev->ndev);
+ ql_disable_interrupts(qdev);
+ qdev->port_link_state = LS_DOWN;
+ set_bit(QL_RESET_ACTIVE,&qdev->flags) ;
+
+ if (value & ISP_CONTROL_FE) {
+ /*
+ * Chip Fatal Error.
+ */
+ var =
+ ql_read_page0_reg_l(qdev,
+ &port_regs->PortFatalErrStatus);
+ printk(KERN_WARNING PFX
+ "%s: Resetting chip. PortFatalErrStatus "
+ "register = 0x%x\n", ndev->name, var);
+ set_bit(QL_RESET_START,&qdev->flags) ;
+ } else {
+ /*
+ * Soft Reset Requested.
+ */
+ set_bit(QL_RESET_PER_SCSI,&qdev->flags) ;
+ printk(KERN_ERR PFX
+ "%s: Another function issued a reset to the "
+ "chip. ISR value = %x.\n", ndev->name, value);
+ }
+ queue_work(qdev->workqueue, &qdev->reset_work);
+ spin_unlock(&qdev->adapter_lock);
+ } else if (value & ISP_IMR_DISABLE_CMPL_INT) {
+ ql_disable_interrupts(qdev);
+ if (likely(netif_rx_schedule_prep(ndev)))
+ __netif_rx_schedule(ndev);
+ else
+ ql_enable_interrupts(qdev);
+ } else {
+ return IRQ_NONE;
+ }
+
+ return IRQ_RETVAL(handled);
+}
+
+static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql_tx_buf_cb *tx_cb;
+ struct ob_mac_iocb_req *mac_iocb_ptr;
+ u64 map;
+
+ if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
+ if (!netif_queue_stopped(ndev))
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
+ }
+ tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+ mac_iocb_ptr = tx_cb->queue_entry;
+ memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
+ mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
+ mac_iocb_ptr->flags |= qdev->mb_bit_mask;
+ mac_iocb_ptr->transaction_id = qdev->req_producer_index;
+ mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+ tx_cb->skb = skb;
+ map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
+ mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
+ mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
+ pci_unmap_addr_set(tx_cb, mapaddr, map);
+ pci_unmap_len_set(tx_cb, maplen, skb->len);
+ atomic_dec(&qdev->tx_count);
+
+ qdev->req_producer_index++;
+ if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
+ qdev->req_producer_index = 0;
+ wmb();
+ ql_write_common_reg_l(qdev,
+ &port_regs->CommonRegs.reqQProducerIndex,
+ qdev->req_producer_index);
+
+ ndev->trans_start = jiffies;
+ if (netif_msg_tx_queued(qdev))
+ printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
+ ndev->name, qdev->req_producer_index, skb->len);
+
+ return NETDEV_TX_OK;
+}
+static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
+{
+ qdev->req_q_size =
+ (u32) (NUM_REQ_Q_ENTRIES * sizeof(struct ob_mac_iocb_req));
+
+ qdev->req_q_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ (size_t) qdev->req_q_size,
+ &qdev->req_q_phy_addr);
+
+ if ((qdev->req_q_virt_addr == NULL) ||
+ LS_64BITS(qdev->req_q_phy_addr) & (qdev->req_q_size - 1)) {
+ printk(KERN_ERR PFX "%s: reqQ failed.\n",
+ qdev->ndev->name);
+ return -ENOMEM;
+ }
+
+ qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb);
+
+ qdev->rsp_q_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ (size_t) qdev->rsp_q_size,
+ &qdev->rsp_q_phy_addr);
+
+ if ((qdev->rsp_q_virt_addr == NULL) ||
+ LS_64BITS(qdev->rsp_q_phy_addr) & (qdev->rsp_q_size - 1)) {
+ printk(KERN_ERR PFX
+ "%s: rspQ allocation failed\n",
+ qdev->ndev->name);
+ pci_free_consistent(qdev->pdev, (size_t) qdev->req_q_size,
+ qdev->req_q_virt_addr,
+ qdev->req_q_phy_addr);
+ return -ENOMEM;
+ }
+
+ set_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+
+ return 0;
+}
+
+static void ql_free_net_req_rsp_queues(struct ql3_adapter *qdev)
+{
+ if (!test_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: Already done.\n", qdev->ndev->name);
+ return;
+ }
+
+ pci_free_consistent(qdev->pdev,
+ qdev->req_q_size,
+ qdev->req_q_virt_addr, qdev->req_q_phy_addr);
+
+ qdev->req_q_virt_addr = NULL;
+
+ pci_free_consistent(qdev->pdev,
+ qdev->rsp_q_size,
+ qdev->rsp_q_virt_addr, qdev->rsp_q_phy_addr);
+
+ qdev->rsp_q_virt_addr = NULL;
+
+ clear_bit(QL_ALLOC_REQ_RSP_Q_DONE,&qdev->flags);
+}
+
+static int ql_alloc_buffer_queues(struct ql3_adapter *qdev)
+{
+ /* Create Large Buffer Queue */
+ qdev->lrg_buf_q_size =
+ NUM_LBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+ if (qdev->lrg_buf_q_size < PAGE_SIZE)
+ qdev->lrg_buf_q_alloc_size = PAGE_SIZE;
+ else
+ qdev->lrg_buf_q_alloc_size = qdev->lrg_buf_q_size * 2;
+
+ qdev->lrg_buf_q_alloc_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ qdev->lrg_buf_q_alloc_size,
+ &qdev->lrg_buf_q_alloc_phy_addr);
+
+ if (qdev->lrg_buf_q_alloc_virt_addr == NULL) {
+ printk(KERN_ERR PFX
+ "%s: lBufQ failed\n", qdev->ndev->name);
+ return -ENOMEM;
+ }
+ qdev->lrg_buf_q_virt_addr = qdev->lrg_buf_q_alloc_virt_addr;
+ qdev->lrg_buf_q_phy_addr = qdev->lrg_buf_q_alloc_phy_addr;
+
+ /* Create Small Buffer Queue */
+ qdev->small_buf_q_size =
+ NUM_SBUFQ_ENTRIES * sizeof(struct lrg_buf_q_entry);
+ if (qdev->small_buf_q_size < PAGE_SIZE)
+ qdev->small_buf_q_alloc_size = PAGE_SIZE;
+ else
+ qdev->small_buf_q_alloc_size = qdev->small_buf_q_size * 2;
+
+ qdev->small_buf_q_alloc_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ qdev->small_buf_q_alloc_size,
+ &qdev->small_buf_q_alloc_phy_addr);
+
+ if (qdev->small_buf_q_alloc_virt_addr == NULL) {
+ printk(KERN_ERR PFX
+ "%s: Small Buffer Queue allocation failed.\n",
+ qdev->ndev->name);
+ pci_free_consistent(qdev->pdev, qdev->lrg_buf_q_alloc_size,
+ qdev->lrg_buf_q_alloc_virt_addr,
+ qdev->lrg_buf_q_alloc_phy_addr);
+ return -ENOMEM;
+ }
+
+ qdev->small_buf_q_virt_addr = qdev->small_buf_q_alloc_virt_addr;
+ qdev->small_buf_q_phy_addr = qdev->small_buf_q_alloc_phy_addr;
+ set_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+ return 0;
+}
+
+static void ql_free_buffer_queues(struct ql3_adapter *qdev)
+{
+ if (!test_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: Already done.\n", qdev->ndev->name);
+ return;
+ }
+
+ pci_free_consistent(qdev->pdev,
+ qdev->lrg_buf_q_alloc_size,
+ qdev->lrg_buf_q_alloc_virt_addr,
+ qdev->lrg_buf_q_alloc_phy_addr);
+
+ qdev->lrg_buf_q_virt_addr = NULL;
+
+ pci_free_consistent(qdev->pdev,
+ qdev->small_buf_q_alloc_size,
+ qdev->small_buf_q_alloc_virt_addr,
+ qdev->small_buf_q_alloc_phy_addr);
+
+ qdev->small_buf_q_virt_addr = NULL;
+
+ clear_bit(QL_ALLOC_BUFQS_DONE,&qdev->flags);
+}
+
+static int ql_alloc_small_buffers(struct ql3_adapter *qdev)
+{
+ int i;
+ struct bufq_addr_element *small_buf_q_entry;
+
+ /* Currently we allocate on one of memory and use it for smallbuffers */
+ qdev->small_buf_total_size =
+ (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES *
+ QL_SMALL_BUFFER_SIZE);
+
+ qdev->small_buf_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ qdev->small_buf_total_size,
+ &qdev->small_buf_phy_addr);
+
+ if (qdev->small_buf_virt_addr == NULL) {
+ printk(KERN_ERR PFX
+ "%s: Failed to get small buffer memory.\n",
+ qdev->ndev->name);
+ return -ENOMEM;
+ }
+
+ qdev->small_buf_phy_addr_low = LS_64BITS(qdev->small_buf_phy_addr);
+ qdev->small_buf_phy_addr_high = MS_64BITS(qdev->small_buf_phy_addr);
+
+ small_buf_q_entry = qdev->small_buf_q_virt_addr;
+
+ qdev->last_rsp_offset = qdev->small_buf_phy_addr_low;
+
+ /* Initialize the small buffer queue. */
+ for (i = 0; i < (QL_ADDR_ELE_PER_BUFQ_ENTRY * NUM_SBUFQ_ENTRIES); i++) {
+ small_buf_q_entry->addr_high =
+ cpu_to_le32(qdev->small_buf_phy_addr_high);
+ small_buf_q_entry->addr_low =
+ cpu_to_le32(qdev->small_buf_phy_addr_low +
+ (i * QL_SMALL_BUFFER_SIZE));
+ small_buf_q_entry++;
+ }
+ qdev->small_buf_index = 0;
+ set_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags);
+ return 0;
+}
+
+static void ql_free_small_buffers(struct ql3_adapter *qdev)
+{
+ if (!test_bit(QL_ALLOC_SMALL_BUF_DONE,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: Already done.\n", qdev->ndev->name);
+ return;
+ }
+ if (qdev->small_buf_virt_addr != NULL) {
+ pci_free_consistent(qdev->pdev,
+ qdev->small_buf_total_size,
+ qdev->small_buf_virt_addr,
+ qdev->small_buf_phy_addr);
+
+ qdev->small_buf_virt_addr = NULL;
+ }
+}
+
+static void ql_free_large_buffers(struct ql3_adapter *qdev)
+{
+ int i = 0;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+
+ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ if (lrg_buf_cb->skb) {
+ dev_kfree_skb(lrg_buf_cb->skb);
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(lrg_buf_cb, mapaddr),
+ pci_unmap_len(lrg_buf_cb, maplen),
+ PCI_DMA_FROMDEVICE);
+ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+ } else {
+ break;
+ }
+ }
+}
+
+static void ql_init_large_buffers(struct ql3_adapter *qdev)
+{
+ int i;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct bufq_addr_element *buf_addr_ele = qdev->lrg_buf_q_virt_addr;
+
+ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ buf_addr_ele->addr_high = lrg_buf_cb->buf_phy_addr_high;
+ buf_addr_ele->addr_low = lrg_buf_cb->buf_phy_addr_low;
+ buf_addr_ele++;
+ }
+ qdev->lrg_buf_index = 0;
+ qdev->lrg_buf_skb_check = 0;
+}
+
+static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
+{
+ int i;
+ struct ql_rcv_buf_cb *lrg_buf_cb;
+ struct sk_buff *skb;
+ u64 map;
+
+ for (i = 0; i < NUM_LARGE_BUFFERS; i++) {
+ skb = dev_alloc_skb(qdev->lrg_buffer_len);
+ if (unlikely(!skb)) {
+ /* Better luck next round */
+ printk(KERN_ERR PFX
+ "%s: large buff alloc failed, "
+ "for %d bytes at index %d.\n",
+ qdev->ndev->name,
+ qdev->lrg_buffer_len * 2, i);
+ ql_free_large_buffers(qdev);
+ return -ENOMEM;
+ } else {
+
+ lrg_buf_cb = &qdev->lrg_buf[i];
+ memset(lrg_buf_cb, 0, sizeof(struct ql_rcv_buf_cb));
+ lrg_buf_cb->index = i;
+ lrg_buf_cb->skb = skb;
+ /*
+ * We save some space to copy the ethhdr from first
+ * buffer
+ */
+ skb_reserve(skb, QL_HEADER_SPACE);
+ map = pci_map_single(qdev->pdev,
+ skb->data,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_addr_set(lrg_buf_cb, mapaddr, map);
+ pci_unmap_len_set(lrg_buf_cb, maplen,
+ qdev->lrg_buffer_len -
+ QL_HEADER_SPACE);
+ lrg_buf_cb->buf_phy_addr_low =
+ cpu_to_le32(LS_64BITS(map));
+ lrg_buf_cb->buf_phy_addr_high =
+ cpu_to_le32(MS_64BITS(map));
+ }
+ }
+ return 0;
+}
+
+static void ql_create_send_free_list(struct ql3_adapter *qdev)
+{
+ struct ql_tx_buf_cb *tx_cb;
+ int i;
+ struct ob_mac_iocb_req *req_q_curr =
+ qdev->req_q_virt_addr;
+
+ /* Create free list of transmit buffers */
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ tx_cb = &qdev->tx_buf[i];
+ tx_cb->skb = NULL;
+ tx_cb->queue_entry = req_q_curr;
+ req_q_curr++;
+ }
+}
+
+static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
+{
+ if (qdev->ndev->mtu == NORMAL_MTU_SIZE)
+ qdev->lrg_buffer_len = NORMAL_MTU_SIZE;
+ else if (qdev->ndev->mtu == JUMBO_MTU_SIZE) {
+ qdev->lrg_buffer_len = JUMBO_MTU_SIZE;
+ } else {
+ printk(KERN_ERR PFX
+ "%s: Invalid mtu size. Only 1500 and 9000 are accepted.\n",
+ qdev->ndev->name);
+ return -ENOMEM;
+ }
+ qdev->lrg_buffer_len += VLAN_ETH_HLEN + VLAN_ID_LEN + QL_HEADER_SPACE;
+ qdev->max_frame_size =
+ (qdev->lrg_buffer_len - QL_HEADER_SPACE) + ETHERNET_CRC_SIZE;
+
+ /*
+ * First allocate a page of shared memory and use it for shadow
+ * locations of Network Request Queue Consumer Address Register and
+ * Network Completion Queue Producer Index Register
+ */
+ qdev->shadow_reg_virt_addr =
+ pci_alloc_consistent(qdev->pdev,
+ PAGE_SIZE, &qdev->shadow_reg_phy_addr);
+
+ if (qdev->shadow_reg_virt_addr != NULL) {
+ qdev->preq_consumer_index = (u16 *) qdev->shadow_reg_virt_addr;
+ qdev->req_consumer_index_phy_addr_high =
+ MS_64BITS(qdev->shadow_reg_phy_addr);
+ qdev->req_consumer_index_phy_addr_low =
+ LS_64BITS(qdev->shadow_reg_phy_addr);
+
+ qdev->prsp_producer_index =
+ (u32 *) (((u8 *) qdev->preq_consumer_index) + 8);
+ qdev->rsp_producer_index_phy_addr_high =
+ qdev->req_consumer_index_phy_addr_high;
+ qdev->rsp_producer_index_phy_addr_low =
+ qdev->req_consumer_index_phy_addr_low + 8;
+ } else {
+ printk(KERN_ERR PFX
+ "%s: shadowReg Alloc failed.\n", qdev->ndev->name);
+ return -ENOMEM;
+ }
+
+ if (ql_alloc_net_req_rsp_queues(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_net_req_rsp_queues failed.\n",
+ qdev->ndev->name);
+ goto err_req_rsp;
+ }
+
+ if (ql_alloc_buffer_queues(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_buffer_queues failed.\n",
+ qdev->ndev->name);
+ goto err_buffer_queues;
+ }
+
+ if (ql_alloc_small_buffers(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_small_buffers failed\n", qdev->ndev->name);
+ goto err_small_buffers;
+ }
+
+ if (ql_alloc_large_buffers(qdev) != 0) {
+ printk(KERN_ERR PFX
+ "%s: ql_alloc_large_buffers failed\n", qdev->ndev->name);
+ goto err_small_buffers;
+ }
+
+ /* Initialize the large buffer queue. */
+ ql_init_large_buffers(qdev);
+ ql_create_send_free_list(qdev);
+
+ qdev->rsp_current = qdev->rsp_q_virt_addr;
+
+ return 0;
+
+err_small_buffers:
+ ql_free_buffer_queues(qdev);
+err_buffer_queues:
+ ql_free_net_req_rsp_queues(qdev);
+err_req_rsp:
+ pci_free_consistent(qdev->pdev,
+ PAGE_SIZE,
+ qdev->shadow_reg_virt_addr,
+ qdev->shadow_reg_phy_addr);
+
+ return -ENOMEM;
+}
+
+static void ql_free_mem_resources(struct ql3_adapter *qdev)
+{
+ ql_free_large_buffers(qdev);
+ ql_free_small_buffers(qdev);
+ ql_free_buffer_queues(qdev);
+ ql_free_net_req_rsp_queues(qdev);
+ if (qdev->shadow_reg_virt_addr != NULL) {
+ pci_free_consistent(qdev->pdev,
+ PAGE_SIZE,
+ qdev->shadow_reg_virt_addr,
+ qdev->shadow_reg_phy_addr);
+ qdev->shadow_reg_virt_addr = NULL;
+ }
+}
+
+static int ql_init_misc_registers(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_local_ram_registers __iomem *local_ram =
+ (void __iomem *)qdev->mem_map_registers;
+
+ if(ql_sem_spinlock(qdev, QL_DDR_RAM_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 4))
+ return -1;
+
+ ql_write_page2_reg(qdev,
+ &local_ram->bufletSize, qdev->nvram_data.bufletSize);
+
+ ql_write_page2_reg(qdev,
+ &local_ram->maxBufletCount,
+ qdev->nvram_data.bufletCount);
+
+ ql_write_page2_reg(qdev,
+ &local_ram->freeBufletThresholdLow,
+ (qdev->nvram_data.tcpWindowThreshold25 << 16) |
+ (qdev->nvram_data.tcpWindowThreshold0));
+
+ ql_write_page2_reg(qdev,
+ &local_ram->freeBufletThresholdHigh,
+ qdev->nvram_data.tcpWindowThreshold50);
+
+ ql_write_page2_reg(qdev,
+ &local_ram->ipHashTableBase,
+ (qdev->nvram_data.ipHashTableBaseHi << 16) |
+ qdev->nvram_data.ipHashTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->ipHashTableCount,
+ qdev->nvram_data.ipHashTableSize);
+ ql_write_page2_reg(qdev,
+ &local_ram->tcpHashTableBase,
+ (qdev->nvram_data.tcpHashTableBaseHi << 16) |
+ qdev->nvram_data.tcpHashTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->tcpHashTableCount,
+ qdev->nvram_data.tcpHashTableSize);
+ ql_write_page2_reg(qdev,
+ &local_ram->ncbBase,
+ (qdev->nvram_data.ncbTableBaseHi << 16) |
+ qdev->nvram_data.ncbTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->maxNcbCount,
+ qdev->nvram_data.ncbTableSize);
+ ql_write_page2_reg(qdev,
+ &local_ram->drbBase,
+ (qdev->nvram_data.drbTableBaseHi << 16) |
+ qdev->nvram_data.drbTableBaseLo);
+ ql_write_page2_reg(qdev,
+ &local_ram->maxDrbCount,
+ qdev->nvram_data.drbTableSize);
+ ql_sem_unlock(qdev, QL_DDR_RAM_SEM_MASK);
+ return 0;
+}
+
+static int ql_adapter_initialize(struct ql3_adapter *qdev)
+{
+ u32 value;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ struct ql3xxx_host_memory_registers __iomem *hmem_regs =
+ (void __iomem *)port_regs;
+ u32 delay = 10;
+ int status = 0;
+
+ if(ql_mii_setup(qdev))
+ return -1;
+
+ /* Bring out PHY out of reset */
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ (ISP_SERIAL_PORT_IF_WE |
+ (ISP_SERIAL_PORT_IF_WE << 16)));
+
+ qdev->port_link_state = LS_DOWN;
+ netif_carrier_off(qdev->ndev);
+
+ /* V2 chip fix for ARS-39168. */
+ ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,
+ (ISP_SERIAL_PORT_IF_SDE |
+ (ISP_SERIAL_PORT_IF_SDE << 16)));
+
+ /* Request Queue Registers */
+ *((u32 *) (qdev->preq_consumer_index)) = 0;
+ atomic_set(&qdev->tx_count,NUM_REQ_Q_ENTRIES);
+ qdev->req_producer_index = 0;
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqConsumerIndexAddrHigh,
+ qdev->req_consumer_index_phy_addr_high);
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqConsumerIndexAddrLow,
+ qdev->req_consumer_index_phy_addr_low);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqBaseAddrHigh,
+ MS_64BITS(qdev->req_q_phy_addr));
+ ql_write_page1_reg(qdev,
+ &hmem_regs->reqBaseAddrLow,
+ LS_64BITS(qdev->req_q_phy_addr));
+ ql_write_page1_reg(qdev, &hmem_regs->reqLength, NUM_REQ_Q_ENTRIES);
+
+ /* Response Queue Registers */
+ *((u16 *) (qdev->prsp_producer_index)) = 0;
+ qdev->rsp_consumer_index = 0;
+ qdev->rsp_current = qdev->rsp_q_virt_addr;
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspProducerIndexAddrHigh,
+ qdev->rsp_producer_index_phy_addr_high);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspProducerIndexAddrLow,
+ qdev->rsp_producer_index_phy_addr_low);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspBaseAddrHigh,
+ MS_64BITS(qdev->rsp_q_phy_addr));
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rspBaseAddrLow,
+ LS_64BITS(qdev->rsp_q_phy_addr));
+
+ ql_write_page1_reg(qdev, &hmem_regs->rspLength, NUM_RSP_Q_ENTRIES);
+
+ /* Large Buffer Queue */
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeQBaseAddrHigh,
+ MS_64BITS(qdev->lrg_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeQBaseAddrLow,
+ LS_64BITS(qdev->lrg_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev, &hmem_regs->rxLargeQLength, NUM_LBUFQ_ENTRIES);
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxLargeBufferLength,
+ qdev->lrg_buffer_len);
+
+ /* Small Buffer Queue */
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxSmallQBaseAddrHigh,
+ MS_64BITS(qdev->small_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxSmallQBaseAddrLow,
+ LS_64BITS(qdev->small_buf_q_phy_addr));
+
+ ql_write_page1_reg(qdev, &hmem_regs->rxSmallQLength, NUM_SBUFQ_ENTRIES);
+ ql_write_page1_reg(qdev,
+ &hmem_regs->rxSmallBufferLength,
+ QL_SMALL_BUFFER_SIZE);
+
+ qdev->small_buf_q_producer_index = NUM_SBUFQ_ENTRIES - 1;
+ qdev->small_buf_release_cnt = 8;
+ qdev->lrg_buf_q_producer_index = NUM_LBUFQ_ENTRIES - 1;
+ qdev->lrg_buf_release_cnt = 8;
+ qdev->lrg_buf_next_free =
+ (struct bufq_addr_element *)qdev->lrg_buf_q_virt_addr;
+ qdev->small_buf_index = 0;
+ qdev->lrg_buf_index = 0;
+ qdev->lrg_buf_free_count = 0;
+ qdev->lrg_buf_free_head = NULL;
+ qdev->lrg_buf_free_tail = NULL;
+
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ rxSmallQProducerIndex,
+ qdev->small_buf_q_producer_index);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ rxLargeQProducerIndex,
+ qdev->lrg_buf_q_producer_index);
+
+ /*
+ * Find out if the chip has already been initialized. If it has, then
+ * we skip some of the initialization.
+ */
+ clear_bit(QL_LINK_MASTER, &qdev->flags);
+ value = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if ((value & PORT_STATUS_IC) == 0) {
+
+ /* Chip has not been configured yet, so let it rip. */
+ if(ql_init_misc_registers(qdev)) {
+ status = -1;
+ goto out;
+ }
+
+ if (qdev->mac_index)
+ ql_write_page0_reg(qdev,
+ &port_regs->mac1MaxFrameLengthReg,
+ qdev->max_frame_size);
+ else
+ ql_write_page0_reg(qdev,
+ &port_regs->mac0MaxFrameLengthReg,
+ qdev->max_frame_size);
+
+ value = qdev->nvram_data.tcpMaxWindowSize;
+ ql_write_page0_reg(qdev, &port_regs->tcpMaxWindow, value);
+
+ value = (0xFFFF << 16) | qdev->nvram_data.extHwConfig;
+
+ if(ql_sem_spinlock(qdev, QL_FLASH_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index)
+ * 2) << 13)) {
+ status = -1;
+ goto out;
+ }
+ ql_write_page0_reg(qdev, &port_regs->ExternalHWConfig, value);
+ ql_write_page0_reg(qdev, &port_regs->InternalChipConfig,
+ (((INTERNAL_CHIP_SD | INTERNAL_CHIP_WE) <<
+ 16) | (INTERNAL_CHIP_SD |
+ INTERNAL_CHIP_WE)));
+ ql_sem_unlock(qdev, QL_FLASH_SEM_MASK);
+ }
+
+
+ if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK,
+ (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) *
+ 2) << 7)) {
+ status = -1;
+ goto out;
+ }
+
+ ql_init_scan_mode(qdev);
+ ql_get_phy_owner(qdev);
+
+ /* Load the MAC Configuration */
+
+ /* Program lower 32 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((qdev->ndev->dev_addr[2] << 24)
+ | (qdev->ndev->dev_addr[3] << 16)
+ | (qdev->ndev->dev_addr[4] << 8)
+ | qdev->ndev->dev_addr[5]));
+
+ /* Program top 16 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((qdev->ndev->dev_addr[0] << 8)
+ | qdev->ndev->dev_addr[1]));
+
+ /* Enable Primary MAC */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ ((MAC_ADDR_INDIRECT_PTR_REG_PE << 16) |
+ MAC_ADDR_INDIRECT_PTR_REG_PE));
+
+ /* Clear Primary and Secondary IP addresses */
+ ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
+ ((IP_ADDR_INDEX_REG_MASK << 16) |
+ (qdev->mac_index << 2)));
+ ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
+
+ ql_write_page0_reg(qdev, &port_regs->ipAddrIndexReg,
+ ((IP_ADDR_INDEX_REG_MASK << 16) |
+ ((qdev->mac_index << 2) + 1)));
+ ql_write_page0_reg(qdev, &port_regs->ipAddrDataReg, 0);
+
+ ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK);
+
+ /* Indicate Configuration Complete */
+ ql_write_page0_reg(qdev,
+ &port_regs->portControl,
+ ((PORT_CONTROL_CC << 16) | PORT_CONTROL_CC));
+
+ do {
+ value = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ if (value & PORT_STATUS_IC)
+ break;
+ msleep(500);
+ } while (--delay);
+
+ if (delay == 0) {
+ printk(KERN_ERR PFX
+ "%s: Hw Initialization timeout.\n", qdev->ndev->name);
+ status = -1;
+ goto out;
+ }
+
+ /* Enable Ethernet Function */
+ value =
+ (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+ PORT_CONTROL_HH);
+ ql_write_page0_reg(qdev, &port_regs->portControl,
+ ((value << 16) | value));
+
+out:
+ return status;
+}
+
+/*
+ * Caller holds hw_lock.
+ */
+static int ql_adapter_reset(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ int status = 0;
+ u16 value;
+ int max_wait_time;
+
+ set_bit(QL_RESET_ACTIVE, &qdev->flags);
+ clear_bit(QL_RESET_DONE, &qdev->flags);
+
+ /*
+ * Issue soft reset to chip.
+ */
+ printk(KERN_DEBUG PFX
+ "%s: Issue soft reset to chip.\n",
+ qdev->ndev->name);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus,
+ ((ISP_CONTROL_SR << 16) | ISP_CONTROL_SR));
+
+ /* Wait 3 seconds for reset to complete. */
+ printk(KERN_DEBUG PFX
+ "%s: Wait 10 milliseconds for reset to complete.\n",
+ qdev->ndev->name);
+
+ /* Wait until the firmware tells us the Soft Reset is done */
+ max_wait_time = 5;
+ do {
+ value =
+ ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.ispControlStatus);
+ if ((value & ISP_CONTROL_SR) == 0)
+ break;
+
+ ssleep(1);
+ } while ((--max_wait_time));
+
+ /*
+ * Also, make sure that the Network Reset Interrupt bit has been
+ * cleared after the soft reset has taken place.
+ */
+ value =
+ ql_read_common_reg(qdev, &port_regs->CommonRegs.ispControlStatus);
+ if (value & ISP_CONTROL_RI) {
+ printk(KERN_DEBUG PFX
+ "ql_adapter_reset: clearing RI after reset.\n");
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
+ }
+
+ if (max_wait_time == 0) {
+ /* Issue Force Soft Reset */
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_FSR << 16) |
+ ISP_CONTROL_FSR));
+ /*
+ * Wait until the firmware tells us the Force Soft Reset is
+ * done
+ */
+ max_wait_time = 5;
+ do {
+ value =
+ ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus);
+ if ((value & ISP_CONTROL_FSR) == 0) {
+ break;
+ }
+ ssleep(1);
+ } while ((--max_wait_time));
+ }
+ if (max_wait_time == 0)
+ status = 1;
+
+ clear_bit(QL_RESET_ACTIVE, &qdev->flags);
+ set_bit(QL_RESET_DONE, &qdev->flags);
+ return status;
+}
+
+static void ql_set_mac_info(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value, port_status;
+ u8 func_number;
+
+ /* Get the function number */
+ value =
+ ql_read_common_reg_l(qdev, &port_regs->CommonRegs.ispControlStatus);
+ func_number = (u8) ((value >> 4) & OPCODE_FUNC_ID_MASK);
+ port_status = ql_read_page0_reg(qdev, &port_regs->portStatus);
+ switch (value & ISP_CONTROL_FN_MASK) {
+ case ISP_CONTROL_FN0_NET:
+ qdev->mac_index = 0;
+ qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
+ qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
+ qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
+ qdev->mb_bit_mask = FN0_MA_BITS_MASK;
+ qdev->PHYAddr = PORT0_PHY_ADDRESS;
+ if (port_status & PORT_STATUS_SM0)
+ set_bit(QL_LINK_OPTICAL,&qdev->flags);
+ else
+ clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+ break;
+
+ case ISP_CONTROL_FN1_NET:
+ qdev->mac_index = 1;
+ qdev->mac_ob_opcode = OUTBOUND_MAC_IOCB | func_number;
+ qdev->tcp_ob_opcode = OUTBOUND_TCP_IOCB | func_number;
+ qdev->update_ob_opcode = UPDATE_NCB_IOCB | func_number;
+ qdev->mb_bit_mask = FN1_MA_BITS_MASK;
+ qdev->PHYAddr = PORT1_PHY_ADDRESS;
+ if (port_status & PORT_STATUS_SM1)
+ set_bit(QL_LINK_OPTICAL,&qdev->flags);
+ else
+ clear_bit(QL_LINK_OPTICAL,&qdev->flags);
+ break;
+
+ case ISP_CONTROL_FN0_SCSI:
+ case ISP_CONTROL_FN1_SCSI:
+ default:
+ printk(KERN_DEBUG PFX
+ "%s: Invalid function number, ispControlStatus = 0x%x\n",
+ qdev->ndev->name,value);
+ break;
+ }
+ qdev->numPorts = qdev->nvram_data.numPorts;
+}
+
+static void ql_display_dev_info(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct pci_dev *pdev = qdev->pdev;
+
+ printk(KERN_INFO PFX
+ "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
+ DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+ printk(KERN_INFO PFX
+ "%s Interface.\n",
+ test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
+
+ /*
+ * Print PCI bus width/type.
+ */
+ printk(KERN_INFO PFX
+ "Bus interface is %s %s.\n",
+ ((qdev->pci_width == 64) ? "64-bit" : "32-bit"),
+ ((qdev->pci_x) ? "PCI-X" : "PCI"));
+
+ printk(KERN_INFO PFX
+ "mem IO base address adjusted = 0x%p\n",
+ qdev->mem_map_registers);
+ printk(KERN_INFO PFX "Interrupt number = %d\n", pdev->irq);
+
+ if (netif_msg_probe(qdev))
+ printk(KERN_INFO PFX
+ "%s: MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
+ ndev->name, ndev->dev_addr[0], ndev->dev_addr[1],
+ ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4],
+ ndev->dev_addr[5]);
+}
+
+static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset)
+{
+ struct net_device *ndev = qdev->ndev;
+ int retval = 0;
+
+ netif_stop_queue(ndev);
+ netif_carrier_off(ndev);
+
+ clear_bit(QL_ADAPTER_UP,&qdev->flags);
+ clear_bit(QL_LINK_MASTER,&qdev->flags);
+
+ ql_disable_interrupts(qdev);
+
+ free_irq(qdev->pdev->irq, ndev);
+
+ if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: calling pci_disable_msi().\n", qdev->ndev->name);
+ clear_bit(QL_MSI_ENABLED,&qdev->flags);
+ pci_disable_msi(qdev->pdev);
+ }
+
+ del_timer_sync(&qdev->adapter_timer);
+
+ netif_poll_disable(ndev);
+
+ if (do_reset) {
+ int soft_reset;
+ unsigned long hw_flags;
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ if (ql_wait_for_drvr_lock(qdev)) {
+ if ((soft_reset = ql_adapter_reset(qdev))) {
+ printk(KERN_ERR PFX
+ "%s: ql_adapter_reset(%d) FAILED!\n",
+ ndev->name, qdev->index);
+ }
+ printk(KERN_ERR PFX
+ "%s: Releaseing driver lock via chip reset.\n",ndev->name);
+ } else {
+ printk(KERN_ERR PFX
+ "%s: Could not acquire driver lock to do "
+ "reset!\n", ndev->name);
+ retval = -1;
+ }
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+ }
+ ql_free_mem_resources(qdev);
+ return retval;
+}
+
+static int ql_adapter_up(struct ql3_adapter *qdev)
+{
+ struct net_device *ndev = qdev->ndev;
+ int err;
+ unsigned long irq_flags = SA_SAMPLE_RANDOM | SA_SHIRQ;
+ unsigned long hw_flags;
+
+ if (ql_alloc_mem_resources(qdev)) {
+ printk(KERN_ERR PFX
+ "%s Unable to allocate buffers.\n", ndev->name);
+ return -ENOMEM;
+ }
+
+ if (qdev->msi) {
+ if (pci_enable_msi(qdev->pdev)) {
+ printk(KERN_ERR PFX
+ "%s: User requested MSI, but MSI failed to "
+ "initialize. Continuing without MSI.\n",
+ qdev->ndev->name);
+ qdev->msi = 0;
+ } else {
+ printk(KERN_INFO PFX "%s: MSI Enabled...\n", qdev->ndev->name);
+ set_bit(QL_MSI_ENABLED,&qdev->flags);
+ irq_flags &= ~SA_SHIRQ;
+ }
+ }
+
+ if ((err = request_irq(qdev->pdev->irq,
+ ql3xxx_isr,
+ irq_flags, ndev->name, ndev))) {
+ printk(KERN_ERR PFX
+ "%s: Failed to reserve interrupt %d already in use.\n",
+ ndev->name, qdev->pdev->irq);
+ goto err_irq;
+ }
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+
+ if ((err = ql_wait_for_drvr_lock(qdev))) {
+ if ((err = ql_adapter_initialize(qdev))) {
+ printk(KERN_ERR PFX
+ "%s: Unable to initialize adapter.\n",
+ ndev->name);
+ goto err_init;
+ }
+ printk(KERN_ERR PFX
+ "%s: Releaseing driver lock.\n",ndev->name);
+ ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+ } else {
+ printk(KERN_ERR PFX
+ "%s: Could not aquire driver lock.\n",
+ ndev->name);
+ goto err_lock;
+ }
+
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ set_bit(QL_ADAPTER_UP,&qdev->flags);
+
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+
+ netif_poll_enable(ndev);
+ ql_enable_interrupts(qdev);
+ return 0;
+
+err_init:
+ ql_sem_unlock(qdev, QL_DRVR_SEM_MASK);
+err_lock:
+ free_irq(qdev->pdev->irq, ndev);
+err_irq:
+ if (qdev->msi && test_bit(QL_MSI_ENABLED,&qdev->flags)) {
+ printk(KERN_INFO PFX
+ "%s: calling pci_disable_msi().\n",
+ qdev->ndev->name);
+ clear_bit(QL_MSI_ENABLED,&qdev->flags);
+ pci_disable_msi(qdev->pdev);
+ }
+ return err;
+}
+
+static int ql_cycle_adapter(struct ql3_adapter *qdev, int reset)
+{
+ if( ql_adapter_down(qdev,reset) || ql_adapter_up(qdev)) {
+ printk(KERN_ERR PFX
+ "%s: Driver up/down cycle failed, "
+ "closing device\n",qdev->ndev->name);
+ dev_close(qdev->ndev);
+ return -1;
+ }
+ return 0;
+}
+
+static int ql3xxx_close(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+
+ /*
+ * Wait for device to recover from a reset.
+ * (Rarely happens, but possible.)
+ */
+ while (!test_bit(QL_ADAPTER_UP,&qdev->flags))
+ msleep(50);
+
+ ql_adapter_down(qdev,QL_DO_RESET);
+ return 0;
+}
+
+static int ql3xxx_open(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ return (ql_adapter_up(qdev));
+}
+
+static struct net_device_stats *ql3xxx_get_stats(struct net_device *dev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)dev->priv;
+ return &qdev->stats;
+}
+
+static int ql3xxx_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+ printk(KERN_ERR PFX "%s: new mtu size = %d.\n", ndev->name, new_mtu);
+ if (new_mtu != NORMAL_MTU_SIZE && new_mtu != JUMBO_MTU_SIZE) {
+ printk(KERN_ERR PFX
+ "%s: mtu size of %d is not valid. Use exactly %d or "
+ "%d.\n", ndev->name, new_mtu, NORMAL_MTU_SIZE,
+ JUMBO_MTU_SIZE);
+ return -EINVAL;
+ }
+
+ if (!netif_running(ndev)) {
+ ndev->mtu = new_mtu;
+ return 0;
+ }
+
+ ndev->mtu = new_mtu;
+ return ql_cycle_adapter(qdev,QL_DO_RESET);
+}
+
+static void ql3xxx_set_multicast_list(struct net_device *ndev)
+{
+ /*
+ * We are manually parsing the list in the net_device structure.
+ */
+ return;
+}
+
+static int ql3xxx_set_mac_address(struct net_device *ndev, void *p)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+ struct ql3xxx_port_registers __iomem *port_regs =
+ qdev->mem_map_registers;
+ struct sockaddr *addr = p;
+ unsigned long hw_flags;
+
+ if (netif_running(ndev))
+ return -EBUSY;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
+
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ /* Program lower 32 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ (MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((ndev->dev_addr[2] << 24) | (ndev->
+ dev_addr[3] << 16) |
+ (ndev->dev_addr[4] << 8) | ndev->dev_addr[5]));
+
+ /* Program top 16 bits of the MAC address */
+ ql_write_page0_reg(qdev, &port_regs->macAddrIndirectPtrReg,
+ ((MAC_ADDR_INDIRECT_PTR_REG_RP_MASK << 16) | 1));
+ ql_write_page0_reg(qdev, &port_regs->macAddrDataReg,
+ ((ndev->dev_addr[0] << 8) | ndev->dev_addr[1]));
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ return 0;
+}
+
+static void ql3xxx_tx_timeout(struct net_device *ndev)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
+
+ printk(KERN_ERR PFX "%s: Resetting...\n", ndev->name);
+ /*
+ * Stop the queues, we've got a problem.
+ */
+ netif_stop_queue(ndev);
+
+ /*
+ * Wake up the worker to process this event.
+ */
+ queue_work(qdev->workqueue, &qdev->tx_timeout_work);
+}
+
+static void ql_reset_work(struct ql3_adapter *qdev)
+{
+ struct net_device *ndev = qdev->ndev;
+ u32 value;
+ struct ql_tx_buf_cb *tx_cb;
+ int max_wait_time, i;
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ unsigned long hw_flags;
+
+ if (test_bit((QL_RESET_PER_SCSI | QL_RESET_START),&qdev->flags)) {
+ clear_bit(QL_LINK_MASTER,&qdev->flags);
+
+ /*
+ * Loop through the active list and return the skb.
+ */
+ for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+ tx_cb = &qdev->tx_buf[i];
+ if (tx_cb->skb) {
+
+ printk(KERN_DEBUG PFX
+ "%s: Freeing lost SKB.\n",
+ qdev->ndev->name);
+ pci_unmap_single(qdev->pdev,
+ pci_unmap_addr(tx_cb, mapaddr),
+ pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+ dev_kfree_skb(tx_cb->skb);
+ tx_cb->skb = NULL;
+ }
+ }
+
+ printk(KERN_ERR PFX
+ "%s: Clearing NRI after reset.\n", qdev->ndev->name);
+ spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+ ql_write_common_reg(qdev,
+ &port_regs->CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_RI << 16) | ISP_CONTROL_RI));
+ /*
+ * Wait the for Soft Reset to Complete.
+ */
+ max_wait_time = 10;
+ do {
+ value = ql_read_common_reg(qdev,
+ &port_regs->CommonRegs.
+
+ ispControlStatus);
+ if ((value & ISP_CONTROL_SR) == 0) {
+ printk(KERN_DEBUG PFX
+ "%s: reset completed.\n",
+ qdev->ndev->name);
+ break;
+ }
+
+ if (value & ISP_CONTROL_RI) {
+ printk(KERN_DEBUG PFX
+ "%s: clearing NRI after reset.\n",
+ qdev->ndev->name);
+ ql_write_common_reg(qdev,
+ &port_regs->
+ CommonRegs.
+ ispControlStatus,
+ ((ISP_CONTROL_RI <<
+ 16) | ISP_CONTROL_RI));
+ }
+
+ ssleep(1);
+ } while (--max_wait_time);
+ spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+
+ if (value & ISP_CONTROL_SR) {
+
+ /*
+ * Set the reset flags and clear the board again.
+ * Nothing else to do...
+ */
+ printk(KERN_ERR PFX
+ "%s: Timed out waiting for reset to "
+ "complete.\n", ndev->name);
+ printk(KERN_ERR PFX
+ "%s: Do a reset.\n", ndev->name);
+ clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
+ clear_bit(QL_RESET_START,&qdev->flags);
+ ql_cycle_adapter(qdev,QL_DO_RESET);
+ return;
+ }
+
+ clear_bit(QL_RESET_ACTIVE,&qdev->flags);
+ clear_bit(QL_RESET_PER_SCSI,&qdev->flags);
+ clear_bit(QL_RESET_START,&qdev->flags);
+ ql_cycle_adapter(qdev,QL_NO_RESET);
+ }
+}
+
+static void ql_tx_timeout_work(struct ql3_adapter *qdev)
+{
+ ql_cycle_adapter(qdev,QL_DO_RESET);
+}
+
+static void ql_get_board_info(struct ql3_adapter *qdev)
+{
+ struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
+ u32 value;
+
+ value = ql_read_page0_reg_l(qdev, &port_regs->portStatus);
+
+ qdev->chip_rev_id = ((value & PORT_STATUS_REV_ID_MASK) >> 12);
+ if (value & PORT_STATUS_64)
+ qdev->pci_width = 64;
+ else
+ qdev->pci_width = 32;
+ if (value & PORT_STATUS_X)
+ qdev->pci_x = 1;
+ else
+ qdev->pci_x = 0;
+ qdev->pci_slot = (u8) PCI_SLOT(qdev->pdev->devfn);
+}
+
+static void ql3xxx_timer(unsigned long ptr)
+{
+ struct ql3_adapter *qdev = (struct ql3_adapter *)ptr;
+
+ if (test_bit(QL_RESET_ACTIVE,&qdev->flags)) {
+ printk(KERN_DEBUG PFX
+ "%s: Reset in progress.\n",
+ qdev->ndev->name);
+ goto end;
+ }
+
+ ql_link_state_machine(qdev);
+
+ /* Restart timer on 2 second interval. */
+end:
+ mod_timer(&qdev->adapter_timer, jiffies + HZ * 1);
+}
+
+static int __devinit ql3xxx_probe(struct pci_dev *pdev,
+ const struct pci_device_id *pci_entry)
+{
+ struct net_device *ndev = NULL;
+ struct ql3_adapter *qdev = NULL;
+ static int cards_found = 0;
+ int pci_using_dac, err;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR PFX "%s cannot enable PCI device\n",
+ pci_name(pdev));
+ goto err_out;
+ }
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err) {
+ printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
+ pci_name(pdev));
+ goto err_out_disable_pdev;
+ }
+
+ pci_set_master(pdev);
+
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+ pci_using_dac = 1;
+ err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+ } else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
+ pci_using_dac = 0;
+ err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ }
+
+ if (err) {
+ printk(KERN_ERR PFX "%s no usable DMA configuration\n",
+ pci_name(pdev));
+ goto err_out_free_regions;
+ }
+
+ ndev = alloc_etherdev(sizeof(struct ql3_adapter));
+ if (!ndev)
+ goto err_out_free_regions;
+
+ SET_MODULE_OWNER(ndev);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ ndev->features = NETIF_F_LLTX;
+ if (pci_using_dac)
+ ndev->features |= NETIF_F_HIGHDMA;
+
+ pci_set_drvdata(pdev, ndev);
+
+ qdev = netdev_priv(ndev);
+ qdev->index = cards_found;
+ qdev->ndev = ndev;
+ qdev->pdev = pdev;
+ qdev->port_link_state = LS_DOWN;
+ if (msi)
+ qdev->msi = 1;
+
+ qdev->msg_enable = netif_msg_init(debug, default_msg);
+
+ qdev->mem_map_registers =
+ ioremap_nocache(pci_resource_start(pdev, 1),
+ pci_resource_len(qdev->pdev, 1));
+ if (!qdev->mem_map_registers) {
+ printk(KERN_ERR PFX "%s: cannot map device registers\n",
+ pci_name(pdev));
+ goto err_out_free_ndev;
+ }
+
+ spin_lock_init(&qdev->adapter_lock);
+ spin_lock_init(&qdev->hw_lock);
+
+ /* Set driver entry points */
+ ndev->open = ql3xxx_open;
+ ndev->hard_start_xmit = ql3xxx_send;
+ ndev->stop = ql3xxx_close;
+ ndev->get_stats = ql3xxx_get_stats;
+ ndev->change_mtu = ql3xxx_change_mtu;
+ ndev->set_multicast_list = ql3xxx_set_multicast_list;
+ SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops);
+ ndev->set_mac_address = ql3xxx_set_mac_address;
+ ndev->tx_timeout = ql3xxx_tx_timeout;
+ ndev->watchdog_timeo = 5 * HZ;
+
+ ndev->poll = &ql_poll;
+ ndev->weight = 64;
+
+ ndev->irq = pdev->irq;
+
+ /* make sure the EEPROM is good */
+ if (ql_get_nvram_params(qdev)) {
+ printk(KERN_ALERT PFX
+ "ql3xxx_probe: Adapter #%d, Invalid NVRAM parameters.\n",
+ qdev->index);
+ goto err_out_iounmap;
+ }
+
+ ql_set_mac_info(qdev);
+
+ /* Validate and set parameters */
+ if (qdev->mac_index) {
+ memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn2.macAddress,
+ ETH_ALEN);
+ } else {
+ memcpy(ndev->dev_addr, &qdev->nvram_data.funcCfg_fn0.macAddress,
+ ETH_ALEN);
+ }
+ memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
+
+ ndev->tx_queue_len = NUM_REQ_Q_ENTRIES;
+
+ /* Turn off support for multicasting */
+ ndev->flags &= ~IFF_MULTICAST;
+
+ /* Record PCI bus information. */
+ ql_get_board_info(qdev);
+
+ /*
+ * Set the Maximum Memory Read Byte Count value. We do this to handle
+ * jumbo frames.
+ */
+ if (qdev->pci_x) {
+ pci_write_config_word(pdev, (int)0x4e, (u16) 0x0036);
+ }
+
+ err = register_netdev(ndev);
+ if (err) {
+ printk(KERN_ERR PFX "%s: cannot register net device\n",
+ pci_name(pdev));
+ goto err_out_iounmap;
+ }
+
+ /* we're going to reset, so assume we have no link for now */
+
+ netif_carrier_off(ndev);
+ netif_stop_queue(ndev);
+
+ qdev->workqueue = create_singlethread_workqueue(ndev->name);
+ INIT_WORK(&qdev->reset_work, (void (*)(void *))ql_reset_work, qdev);
+ INIT_WORK(&qdev->tx_timeout_work,
+ (void (*)(void *))ql_tx_timeout_work, qdev);
+
+ init_timer(&qdev->adapter_timer);
+ qdev->adapter_timer.function = ql3xxx_timer;
+ qdev->adapter_timer.expires = jiffies + HZ * 2; /* two second delay */
+ qdev->adapter_timer.data = (unsigned long)qdev;
+
+ if(!cards_found) {
+ printk(KERN_ALERT PFX "%s\n", DRV_STRING);
+ printk(KERN_ALERT PFX "Driver name: %s, Version: %s.\n",
+ DRV_NAME, DRV_VERSION);
+ }
+ ql_display_dev_info(ndev);
+
+ cards_found++;
+ return 0;
+
+err_out_iounmap:
+ iounmap(qdev->mem_map_registers);
+err_out_free_ndev:
+ free_netdev(ndev);
+err_out_free_regions:
+ pci_release_regions(pdev);
+err_out_disable_pdev:
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+err_out:
+ return err;
+}
+
+static void __devexit ql3xxx_remove(struct pci_dev *pdev)
+{
+ struct net_device *ndev = pci_get_drvdata(pdev);
+ struct ql3_adapter *qdev = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+ qdev = netdev_priv(ndev);
+
+ ql_disable_interrupts(qdev);
+
+ if (qdev->workqueue) {
+ cancel_delayed_work(&qdev->reset_work);
+ cancel_delayed_work(&qdev->tx_timeout_work);
+ destroy_workqueue(qdev->workqueue);
+ qdev->workqueue = NULL;
+ }
+
+ iounmap(qdev->mem_map_registers);
+ pci_release_regions(pdev);
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+}
+
+static struct pci_driver ql3xxx_driver = {
+
+ .name = DRV_NAME,
+ .id_table = ql3xxx_pci_tbl,
+ .probe = ql3xxx_probe,
+ .remove = __devexit_p(ql3xxx_remove),
+};
+
+static int __init ql3xxx_init_module(void)
+{
+ return pci_register_driver(&ql3xxx_driver);
+}
+
+static void __exit ql3xxx_exit(void)
+{
+ pci_unregister_driver(&ql3xxx_driver);
+}
+
+module_init(ql3xxx_init_module);
+module_exit(ql3xxx_exit);
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h
new file mode 100644
index 00000000000..65da2c0bfda
--- /dev/null
+++ b/drivers/net/qla3xxx.h
@@ -0,0 +1,1194 @@
+/*
+ * QLogic QLA3xxx NIC HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla3xxx for copyright and licensing details.
+ */
+#ifndef _QLA3XXX_H_
+#define _QLA3XXX_H_
+
+/*
+ * IOCB Definitions...
+ */
+#pragma pack(1)
+
+#define OPCODE_OB_MAC_IOCB_FN0 0x01
+#define OPCODE_OB_MAC_IOCB_FN2 0x21
+#define OPCODE_OB_TCP_IOCB_FN0 0x03
+#define OPCODE_OB_TCP_IOCB_FN2 0x23
+#define OPCODE_UPDATE_NCB_IOCB_FN0 0x00
+#define OPCODE_UPDATE_NCB_IOCB_FN2 0x20
+
+#define OPCODE_UPDATE_NCB_IOCB 0xF0
+#define OPCODE_IB_MAC_IOCB 0xF9
+#define OPCODE_IB_IP_IOCB 0xFA
+#define OPCODE_IB_TCP_IOCB 0xFB
+#define OPCODE_DUMP_PROTO_IOCB 0xFE
+#define OPCODE_BUFFER_ALERT_IOCB 0xFB
+
+#define OPCODE_FUNC_ID_MASK 0x30
+#define OUTBOUND_MAC_IOCB 0x01 /* plus function bits */
+#define OUTBOUND_TCP_IOCB 0x03 /* plus function bits */
+#define UPDATE_NCB_IOCB 0x00 /* plus function bits */
+
+#define FN0_MA_BITS_MASK 0x00
+#define FN1_MA_BITS_MASK 0x80
+
+struct ob_mac_iocb_req {
+ u8 opcode;
+ u8 flags;
+#define OB_MAC_IOCB_REQ_MA 0xC0
+#define OB_MAC_IOCB_REQ_F 0x20
+#define OB_MAC_IOCB_REQ_X 0x10
+#define OB_MAC_IOCB_REQ_D 0x02
+#define OB_MAC_IOCB_REQ_I 0x01
+ __le16 reserved0;
+
+ __le32 transaction_id;
+ __le16 data_len;
+ __le16 reserved1;
+ __le32 reserved2;
+ __le32 reserved3;
+ __le32 buf_addr0_low;
+ __le32 buf_addr0_high;
+ __le32 buf_0_len;
+ __le32 buf_addr1_low;
+ __le32 buf_addr1_high;
+ __le32 buf_1_len;
+ __le32 buf_addr2_low;
+ __le32 buf_addr2_high;
+ __le32 buf_2_len;
+ __le32 reserved4;
+ __le32 reserved5;
+};
+/*
+ * The following constants define control bits for buffer
+ * length fields for all IOCB's.
+ */
+#define OB_MAC_IOCB_REQ_E 0x80000000 /* Last valid buffer in list. */
+#define OB_MAC_IOCB_REQ_C 0x40000000 /* points to an OAL. (continuation) */
+#define OB_MAC_IOCB_REQ_L 0x20000000 /* Auburn local address pointer. */
+#define OB_MAC_IOCB_REQ_R 0x10000000 /* 32-bit address pointer. */
+
+struct ob_mac_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define OB_MAC_IOCB_RSP_P 0x08
+#define OB_MAC_IOCB_RSP_S 0x02
+#define OB_MAC_IOCB_RSP_I 0x01
+
+ __le16 reserved0;
+ __le32 transaction_id;
+ __le32 reserved1;
+ __le32 reserved2;
+};
+
+struct ib_mac_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define IB_MAC_IOCB_RSP_S 0x80
+#define IB_MAC_IOCB_RSP_H1 0x40
+#define IB_MAC_IOCB_RSP_H0 0x20
+#define IB_MAC_IOCB_RSP_B 0x10
+#define IB_MAC_IOCB_RSP_M 0x08
+#define IB_MAC_IOCB_RSP_MA 0x07
+
+ __le16 length;
+ __le32 reserved;
+ __le32 ial_low;
+ __le32 ial_high;
+
+};
+
+struct ob_ip_iocb_req {
+ u8 opcode;
+ __le16 flags;
+#define OB_IP_IOCB_REQ_O 0x100
+#define OB_IP_IOCB_REQ_H 0x008
+#define OB_IP_IOCB_REQ_U 0x004
+#define OB_IP_IOCB_REQ_D 0x002
+#define OB_IP_IOCB_REQ_I 0x001
+
+ u8 reserved0;
+
+ __le32 transaction_id;
+ __le16 data_len;
+ __le16 reserved1;
+ __le32 hncb_ptr_low;
+ __le32 hncb_ptr_high;
+ __le32 buf_addr0_low;
+ __le32 buf_addr0_high;
+ __le32 buf_0_len;
+ __le32 buf_addr1_low;
+ __le32 buf_addr1_high;
+ __le32 buf_1_len;
+ __le32 buf_addr2_low;
+ __le32 buf_addr2_high;
+ __le32 buf_2_len;
+ __le32 reserved2;
+ __le32 reserved3;
+};
+
+/* defines for BufferLength fields above */
+#define OB_IP_IOCB_REQ_E 0x80000000
+#define OB_IP_IOCB_REQ_C 0x40000000
+#define OB_IP_IOCB_REQ_L 0x20000000
+#define OB_IP_IOCB_REQ_R 0x10000000
+
+struct ob_ip_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define OB_MAC_IOCB_RSP_E 0x08
+#define OB_MAC_IOCB_RSP_L 0x04
+#define OB_MAC_IOCB_RSP_S 0x02
+#define OB_MAC_IOCB_RSP_I 0x01
+
+ __le16 reserved0;
+ __le32 transaction_id;
+ __le32 reserved1;
+ __le32 reserved2;
+};
+
+struct ob_tcp_iocb_req {
+ u8 opcode;
+
+ u8 flags0;
+#define OB_TCP_IOCB_REQ_P 0x80
+#define OB_TCP_IOCB_REQ_CI 0x20
+#define OB_TCP_IOCB_REQ_H 0x10
+#define OB_TCP_IOCB_REQ_LN 0x08
+#define OB_TCP_IOCB_REQ_K 0x04
+#define OB_TCP_IOCB_REQ_D 0x02
+#define OB_TCP_IOCB_REQ_I 0x01
+
+ u8 flags1;
+#define OB_TCP_IOCB_REQ_OSM 0x40
+#define OB_TCP_IOCB_REQ_URG 0x20
+#define OB_TCP_IOCB_REQ_ACK 0x10
+#define OB_TCP_IOCB_REQ_PSH 0x08
+#define OB_TCP_IOCB_REQ_RST 0x04
+#define OB_TCP_IOCB_REQ_SYN 0x02
+#define OB_TCP_IOCB_REQ_FIN 0x01
+
+ u8 options_len;
+#define OB_TCP_IOCB_REQ_OMASK 0xF0
+#define OB_TCP_IOCB_REQ_SHIFT 4
+
+ __le32 transaction_id;
+ __le32 data_len;
+ __le32 hncb_ptr_low;
+ __le32 hncb_ptr_high;
+ __le32 buf_addr0_low;
+ __le32 buf_addr0_high;
+ __le32 buf_0_len;
+ __le32 buf_addr1_low;
+ __le32 buf_addr1_high;
+ __le32 buf_1_len;
+ __le32 buf_addr2_low;
+ __le32 buf_addr2_high;
+ __le32 buf_2_len;
+ __le32 time_stamp;
+ __le32 reserved1;
+};
+
+struct ob_tcp_iocb_rsp {
+ u8 opcode;
+
+ u8 flags0;
+#define OB_TCP_IOCB_RSP_C 0x20
+#define OB_TCP_IOCB_RSP_H 0x10
+#define OB_TCP_IOCB_RSP_LN 0x08
+#define OB_TCP_IOCB_RSP_K 0x04
+#define OB_TCP_IOCB_RSP_D 0x02
+#define OB_TCP_IOCB_RSP_I 0x01
+
+ u8 flags1;
+#define OB_TCP_IOCB_RSP_E 0x10
+#define OB_TCP_IOCB_RSP_W 0x08
+#define OB_TCP_IOCB_RSP_P 0x04
+#define OB_TCP_IOCB_RSP_T 0x02
+#define OB_TCP_IOCB_RSP_F 0x01
+
+ u8 state;
+#define OB_TCP_IOCB_RSP_SMASK 0xF0
+#define OB_TCP_IOCB_RSP_SHIFT 4
+
+ __le32 transaction_id;
+ __le32 local_ncb_ptr;
+ __le32 reserved0;
+};
+
+struct ib_ip_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define IB_IP_IOCB_RSP_S 0x80
+#define IB_IP_IOCB_RSP_H1 0x40
+#define IB_IP_IOCB_RSP_H0 0x20
+#define IB_IP_IOCB_RSP_B 0x10
+#define IB_IP_IOCB_RSP_M 0x08
+#define IB_IP_IOCB_RSP_MA 0x07
+
+ __le16 length;
+ __le16 checksum;
+ __le16 reserved;
+#define IB_IP_IOCB_RSP_R 0x01
+ __le32 ial_low;
+ __le32 ial_high;
+};
+
+struct ib_tcp_iocb_rsp {
+ u8 opcode;
+ u8 flags;
+#define IB_TCP_IOCB_RSP_P 0x80
+#define IB_TCP_IOCB_RSP_T 0x40
+#define IB_TCP_IOCB_RSP_D 0x20
+#define IB_TCP_IOCB_RSP_N 0x10
+#define IB_TCP_IOCB_RSP_IP 0x03
+#define IB_TCP_FLAG_MASK 0xf0
+#define IB_TCP_FLAG_IOCB_SYN 0x00
+
+#define TCP_IB_RSP_FLAGS(x) (x->flags & ~IB_TCP_FLAG_MASK)
+
+ __le16 length;
+ __le32 hncb_ref_num;
+ __le32 ial_low;
+ __le32 ial_high;
+};
+
+struct net_rsp_iocb {
+ u8 opcode;
+ u8 flags;
+ __le16 reserved0;
+ __le32 reserved[3];
+};
+#pragma pack()
+
+/*
+ * Register Definitions...
+ */
+#define PORT0_PHY_ADDRESS 0x1e00
+#define PORT1_PHY_ADDRESS 0x1f00
+
+#define ETHERNET_CRC_SIZE 4
+
+#define MII_SCAN_REGISTER 0x00000001
+
+/* 32-bit ispControlStatus */
+enum {
+ ISP_CONTROL_NP_MASK = 0x0003,
+ ISP_CONTROL_NP_PCSR = 0x0000,
+ ISP_CONTROL_NP_HMCR = 0x0001,
+ ISP_CONTROL_NP_LRAMCR = 0x0002,
+ ISP_CONTROL_NP_PSR = 0x0003,
+ ISP_CONTROL_RI = 0x0008,
+ ISP_CONTROL_CI = 0x0010,
+ ISP_CONTROL_PI = 0x0020,
+ ISP_CONTROL_IN = 0x0040,
+ ISP_CONTROL_BE = 0x0080,
+ ISP_CONTROL_FN_MASK = 0x0700,
+ ISP_CONTROL_FN0_NET = 0x0400,
+ ISP_CONTROL_FN0_SCSI = 0x0500,
+ ISP_CONTROL_FN1_NET = 0x0600,
+ ISP_CONTROL_FN1_SCSI = 0x0700,
+ ISP_CONTROL_LINK_DN_0 = 0x0800,
+ ISP_CONTROL_LINK_DN_1 = 0x1000,
+ ISP_CONTROL_FSR = 0x2000,
+ ISP_CONTROL_FE = 0x4000,
+ ISP_CONTROL_SR = 0x8000,
+};
+
+/* 32-bit ispInterruptMaskReg */
+enum {
+ ISP_IMR_ENABLE_INT = 0x0004,
+ ISP_IMR_DISABLE_RESET_INT = 0x0008,
+ ISP_IMR_DISABLE_CMPL_INT = 0x0010,
+ ISP_IMR_DISABLE_PROC_INT = 0x0020,
+};
+
+/* 32-bit serialPortInterfaceReg */
+enum {
+ ISP_SERIAL_PORT_IF_CLK = 0x0001,
+ ISP_SERIAL_PORT_IF_CS = 0x0002,
+ ISP_SERIAL_PORT_IF_D0 = 0x0004,
+ ISP_SERIAL_PORT_IF_DI = 0x0008,
+ ISP_NVRAM_MASK = (0x000F << 16),
+ ISP_SERIAL_PORT_IF_WE = 0x0010,
+ ISP_SERIAL_PORT_IF_NVR_MASK = 0x001F,
+ ISP_SERIAL_PORT_IF_SCI = 0x0400,
+ ISP_SERIAL_PORT_IF_SC0 = 0x0800,
+ ISP_SERIAL_PORT_IF_SCE = 0x1000,
+ ISP_SERIAL_PORT_IF_SDI = 0x2000,
+ ISP_SERIAL_PORT_IF_SDO = 0x4000,
+ ISP_SERIAL_PORT_IF_SDE = 0x8000,
+ ISP_SERIAL_PORT_IF_I2C_MASK = 0xFC00,
+};
+
+/* semaphoreReg */
+enum {
+ QL_RESOURCE_MASK_BASE_CODE = 0x7,
+ QL_RESOURCE_BITS_BASE_CODE = 0x4,
+ QL_DRVR_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 1),
+ QL_DDR_RAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 4),
+ QL_PHY_GIO_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 7),
+ QL_NVRAM_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 10),
+ QL_FLASH_SEM_BITS = (QL_RESOURCE_BITS_BASE_CODE << 13),
+ QL_DRVR_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (1 + 16)),
+ QL_DDR_RAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (4 + 16)),
+ QL_PHY_GIO_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (7 + 16)),
+ QL_NVRAM_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (10 + 16)),
+ QL_FLASH_SEM_MASK = (QL_RESOURCE_MASK_BASE_CODE << (13 + 16)),
+};
+
+ /*
+ * QL3XXX memory-mapped registers
+ * QL3XXX has 4 "pages" of registers, each page occupying
+ * 256 bytes. Each page has a "common" area at the start and then
+ * page-specific registers after that.
+ */
+struct ql3xxx_common_registers {
+ u32 MB0; /* Offset 0x00 */
+ u32 MB1; /* Offset 0x04 */
+ u32 MB2; /* Offset 0x08 */
+ u32 MB3; /* Offset 0x0c */
+ u32 MB4; /* Offset 0x10 */
+ u32 MB5; /* Offset 0x14 */
+ u32 MB6; /* Offset 0x18 */
+ u32 MB7; /* Offset 0x1c */
+ u32 flashBiosAddr;
+ u32 flashBiosData;
+ u32 ispControlStatus;
+ u32 ispInterruptMaskReg;
+ u32 serialPortInterfaceReg;
+ u32 semaphoreReg;
+ u32 reqQProducerIndex;
+ u32 rspQConsumerIndex;
+
+ u32 rxLargeQProducerIndex;
+ u32 rxSmallQProducerIndex;
+ u32 arcMadiCommand;
+ u32 arcMadiData;
+};
+
+enum {
+ EXT_HW_CONFIG_SP_MASK = 0x0006,
+ EXT_HW_CONFIG_SP_NONE = 0x0000,
+ EXT_HW_CONFIG_SP_BYTE_PARITY = 0x0002,
+ EXT_HW_CONFIG_SP_ECC = 0x0004,
+ EXT_HW_CONFIG_SP_ECCx = 0x0006,
+ EXT_HW_CONFIG_SIZE_MASK = 0x0060,
+ EXT_HW_CONFIG_SIZE_128M = 0x0000,
+ EXT_HW_CONFIG_SIZE_256M = 0x0020,
+ EXT_HW_CONFIG_SIZE_512M = 0x0040,
+ EXT_HW_CONFIG_SIZE_INVALID = 0x0060,
+ EXT_HW_CONFIG_PD = 0x0080,
+ EXT_HW_CONFIG_FW = 0x0200,
+ EXT_HW_CONFIG_US = 0x0400,
+ EXT_HW_CONFIG_DCS_MASK = 0x1800,
+ EXT_HW_CONFIG_DCS_9MA = 0x0000,
+ EXT_HW_CONFIG_DCS_15MA = 0x0800,
+ EXT_HW_CONFIG_DCS_18MA = 0x1000,
+ EXT_HW_CONFIG_DCS_24MA = 0x1800,
+ EXT_HW_CONFIG_DDS_MASK = 0x6000,
+ EXT_HW_CONFIG_DDS_9MA = 0x0000,
+ EXT_HW_CONFIG_DDS_15MA = 0x2000,
+ EXT_HW_CONFIG_DDS_18MA = 0x4000,
+ EXT_HW_CONFIG_DDS_24MA = 0x6000,
+};
+
+/* InternalChipConfig */
+enum {
+ INTERNAL_CHIP_DM = 0x0001,
+ INTERNAL_CHIP_SD = 0x0002,
+ INTERNAL_CHIP_RAP_MASK = 0x000C,
+ INTERNAL_CHIP_RAP_RR = 0x0000,
+ INTERNAL_CHIP_RAP_NRM = 0x0004,
+ INTERNAL_CHIP_RAP_ERM = 0x0008,
+ INTERNAL_CHIP_RAP_ERMx = 0x000C,
+ INTERNAL_CHIP_WE = 0x0010,
+ INTERNAL_CHIP_EF = 0x0020,
+ INTERNAL_CHIP_FR = 0x0040,
+ INTERNAL_CHIP_FW = 0x0080,
+ INTERNAL_CHIP_FI = 0x0100,
+ INTERNAL_CHIP_FT = 0x0200,
+};
+
+/* portControl */
+enum {
+ PORT_CONTROL_DS = 0x0001,
+ PORT_CONTROL_HH = 0x0002,
+ PORT_CONTROL_EI = 0x0004,
+ PORT_CONTROL_ET = 0x0008,
+ PORT_CONTROL_EF = 0x0010,
+ PORT_CONTROL_DRM = 0x0020,
+ PORT_CONTROL_RLB = 0x0040,
+ PORT_CONTROL_RCB = 0x0080,
+ PORT_CONTROL_MAC = 0x0100,
+ PORT_CONTROL_IPV = 0x0200,
+ PORT_CONTROL_IFP = 0x0400,
+ PORT_CONTROL_ITP = 0x0800,
+ PORT_CONTROL_FI = 0x1000,
+ PORT_CONTROL_DFP = 0x2000,
+ PORT_CONTROL_OI = 0x4000,
+ PORT_CONTROL_CC = 0x8000,
+};
+
+/* portStatus */
+enum {
+ PORT_STATUS_SM0 = 0x0001,
+ PORT_STATUS_SM1 = 0x0002,
+ PORT_STATUS_X = 0x0008,
+ PORT_STATUS_DL = 0x0080,
+ PORT_STATUS_IC = 0x0200,
+ PORT_STATUS_MRC = 0x0400,
+ PORT_STATUS_NL = 0x0800,
+ PORT_STATUS_REV_ID_MASK = 0x7000,
+ PORT_STATUS_REV_ID_1 = 0x1000,
+ PORT_STATUS_REV_ID_2 = 0x2000,
+ PORT_STATUS_REV_ID_3 = 0x3000,
+ PORT_STATUS_64 = 0x8000,
+ PORT_STATUS_UP0 = 0x10000,
+ PORT_STATUS_AC0 = 0x20000,
+ PORT_STATUS_AE0 = 0x40000,
+ PORT_STATUS_UP1 = 0x100000,
+ PORT_STATUS_AC1 = 0x200000,
+ PORT_STATUS_AE1 = 0x400000,
+ PORT_STATUS_F0_ENABLED = 0x1000000,
+ PORT_STATUS_F1_ENABLED = 0x2000000,
+ PORT_STATUS_F2_ENABLED = 0x4000000,
+ PORT_STATUS_F3_ENABLED = 0x8000000,
+};
+
+/* macMIIMgmtControlReg */
+enum {
+ MAC_ADDR_INDIRECT_PTR_REG_RP_MASK = 0x0003,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_LWR = 0x0000,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_PRI_UPR = 0x0001,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_LWR = 0x0002,
+ MAC_ADDR_INDIRECT_PTR_REG_RP_SEC_UPR = 0x0003,
+ MAC_ADDR_INDIRECT_PTR_REG_PR = 0x0008,
+ MAC_ADDR_INDIRECT_PTR_REG_SS = 0x0010,
+ MAC_ADDR_INDIRECT_PTR_REG_SE = 0x0020,
+ MAC_ADDR_INDIRECT_PTR_REG_SP = 0x0040,
+ MAC_ADDR_INDIRECT_PTR_REG_PE = 0x0080,
+};
+
+/* macMIIMgmtControlReg */
+enum {
+ MAC_MII_CONTROL_RC = 0x0001,
+ MAC_MII_CONTROL_SC = 0x0002,
+ MAC_MII_CONTROL_AS = 0x0004,
+ MAC_MII_CONTROL_NP = 0x0008,
+ MAC_MII_CONTROL_CLK_SEL_MASK = 0x0070,
+ MAC_MII_CONTROL_CLK_SEL_DIV2 = 0x0000,
+ MAC_MII_CONTROL_CLK_SEL_DIV4 = 0x0010,
+ MAC_MII_CONTROL_CLK_SEL_DIV6 = 0x0020,
+ MAC_MII_CONTROL_CLK_SEL_DIV8 = 0x0030,
+ MAC_MII_CONTROL_CLK_SEL_DIV10 = 0x0040,
+ MAC_MII_CONTROL_CLK_SEL_DIV14 = 0x0050,
+ MAC_MII_CONTROL_CLK_SEL_DIV20 = 0x0060,
+ MAC_MII_CONTROL_CLK_SEL_DIV28 = 0x0070,
+ MAC_MII_CONTROL_RM = 0x8000,
+};
+
+/* macMIIStatusReg */
+enum {
+ MAC_MII_STATUS_BSY = 0x0001,
+ MAC_MII_STATUS_SC = 0x0002,
+ MAC_MII_STATUS_NV = 0x0004,
+};
+
+enum {
+ MAC_CONFIG_REG_PE = 0x0001,
+ MAC_CONFIG_REG_TF = 0x0002,
+ MAC_CONFIG_REG_RF = 0x0004,
+ MAC_CONFIG_REG_FD = 0x0008,
+ MAC_CONFIG_REG_GM = 0x0010,
+ MAC_CONFIG_REG_LB = 0x0020,
+ MAC_CONFIG_REG_SR = 0x8000,
+};
+
+enum {
+ MAC_HALF_DUPLEX_REG_ED = 0x10000,
+ MAC_HALF_DUPLEX_REG_NB = 0x20000,
+ MAC_HALF_DUPLEX_REG_BNB = 0x40000,
+ MAC_HALF_DUPLEX_REG_ALT = 0x80000,
+};
+
+enum {
+ IP_ADDR_INDEX_REG_MASK = 0x000f,
+ IP_ADDR_INDEX_REG_FUNC_0_PRI = 0x0000,
+ IP_ADDR_INDEX_REG_FUNC_0_SEC = 0x0001,
+ IP_ADDR_INDEX_REG_FUNC_1_PRI = 0x0002,
+ IP_ADDR_INDEX_REG_FUNC_1_SEC = 0x0003,
+ IP_ADDR_INDEX_REG_FUNC_2_PRI = 0x0004,
+ IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
+ IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
+ IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+};
+
+enum {
+ PROBE_MUX_ADDR_REG_MUX_SEL_MASK = 0x003f,
+ PROBE_MUX_ADDR_REG_SYSCLK = 0x0000,
+ PROBE_MUX_ADDR_REG_PCICLK = 0x0040,
+ PROBE_MUX_ADDR_REG_NRXCLK = 0x0080,
+ PROBE_MUX_ADDR_REG_CPUCLK = 0x00C0,
+ PROBE_MUX_ADDR_REG_MODULE_SEL_MASK = 0x3f00,
+ PROBE_MUX_ADDR_REG_UP = 0x4000,
+ PROBE_MUX_ADDR_REG_RE = 0x8000,
+};
+
+enum {
+ STATISTICS_INDEX_REG_MASK = 0x01ff,
+ STATISTICS_INDEX_REG_MAC0_TX_FRAME = 0x0000,
+ STATISTICS_INDEX_REG_MAC0_TX_BYTES = 0x0001,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT1 = 0x0002,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT2 = 0x0003,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT3 = 0x0004,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT4 = 0x0005,
+ STATISTICS_INDEX_REG_MAC0_TX_STAT5 = 0x0006,
+ STATISTICS_INDEX_REG_MAC0_RX_FRAME = 0x0007,
+ STATISTICS_INDEX_REG_MAC0_RX_BYTES = 0x0008,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT1 = 0x0009,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT2 = 0x000a,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT3 = 0x000b,
+ STATISTICS_INDEX_REG_MAC0_RX_ERR_CRC = 0x000c,
+ STATISTICS_INDEX_REG_MAC0_RX_ERR_ENC = 0x000d,
+ STATISTICS_INDEX_REG_MAC0_RX_ERR_LEN = 0x000e,
+ STATISTICS_INDEX_REG_MAC0_RX_STAT4 = 0x000f,
+ STATISTICS_INDEX_REG_MAC1_TX_FRAME = 0x0010,
+ STATISTICS_INDEX_REG_MAC1_TX_BYTES = 0x0011,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT1 = 0x0012,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT2 = 0x0013,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT3 = 0x0014,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT4 = 0x0015,
+ STATISTICS_INDEX_REG_MAC1_TX_STAT5 = 0x0016,
+ STATISTICS_INDEX_REG_MAC1_RX_FRAME = 0x0017,
+ STATISTICS_INDEX_REG_MAC1_RX_BYTES = 0x0018,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT1 = 0x0019,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT2 = 0x001a,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT3 = 0x001b,
+ STATISTICS_INDEX_REG_MAC1_RX_ERR_CRC = 0x001c,
+ STATISTICS_INDEX_REG_MAC1_RX_ERR_ENC = 0x001d,
+ STATISTICS_INDEX_REG_MAC1_RX_ERR_LEN = 0x001e,
+ STATISTICS_INDEX_REG_MAC1_RX_STAT4 = 0x001f,
+ STATISTICS_INDEX_REG_IP_TX_PKTS = 0x0020,
+ STATISTICS_INDEX_REG_IP_TX_BYTES = 0x0021,
+ STATISTICS_INDEX_REG_IP_TX_FRAG = 0x0022,
+ STATISTICS_INDEX_REG_IP_RX_PKTS = 0x0023,
+ STATISTICS_INDEX_REG_IP_RX_BYTES = 0x0024,
+ STATISTICS_INDEX_REG_IP_RX_FRAG = 0x0025,
+ STATISTICS_INDEX_REG_IP_DGRM_REASSEMBLY = 0x0026,
+ STATISTICS_INDEX_REG_IP_V6_RX_PKTS = 0x0027,
+ STATISTICS_INDEX_REG_IP_RX_PKTERR = 0x0028,
+ STATISTICS_INDEX_REG_IP_REASSEMBLY_ERR = 0x0029,
+ STATISTICS_INDEX_REG_TCP_TX_SEG = 0x0030,
+ STATISTICS_INDEX_REG_TCP_TX_BYTES = 0x0031,
+ STATISTICS_INDEX_REG_TCP_RX_SEG = 0x0032,
+ STATISTICS_INDEX_REG_TCP_RX_BYTES = 0x0033,
+ STATISTICS_INDEX_REG_TCP_TIMER_EXP = 0x0034,
+ STATISTICS_INDEX_REG_TCP_RX_ACK = 0x0035,
+ STATISTICS_INDEX_REG_TCP_TX_ACK = 0x0036,
+ STATISTICS_INDEX_REG_TCP_RX_ERR = 0x0037,
+ STATISTICS_INDEX_REG_TCP_RX_WIN_PROBE = 0x0038,
+ STATISTICS_INDEX_REG_TCP_ECC_ERR_CORR = 0x003f,
+};
+
+enum {
+ PORT_FATAL_ERROR_STATUS_OFB_RE_MAC0 = 0x00000001,
+ PORT_FATAL_ERROR_STATUS_OFB_RE_MAC1 = 0x00000002,
+ PORT_FATAL_ERROR_STATUS_OFB_WE = 0x00000004,
+ PORT_FATAL_ERROR_STATUS_IFB_RE = 0x00000008,
+ PORT_FATAL_ERROR_STATUS_IFB_WE_MAC0 = 0x00000010,
+ PORT_FATAL_ERROR_STATUS_IFB_WE_MAC1 = 0x00000020,
+ PORT_FATAL_ERROR_STATUS_ODE_RE = 0x00000040,
+ PORT_FATAL_ERROR_STATUS_ODE_WE = 0x00000080,
+ PORT_FATAL_ERROR_STATUS_IDE_RE = 0x00000100,
+ PORT_FATAL_ERROR_STATUS_IDE_WE = 0x00000200,
+ PORT_FATAL_ERROR_STATUS_SDE_RE = 0x00000400,
+ PORT_FATAL_ERROR_STATUS_SDE_WE = 0x00000800,
+ PORT_FATAL_ERROR_STATUS_BLE = 0x00001000,
+ PORT_FATAL_ERROR_STATUS_SPE = 0x00002000,
+ PORT_FATAL_ERROR_STATUS_EP0 = 0x00004000,
+ PORT_FATAL_ERROR_STATUS_EP1 = 0x00008000,
+ PORT_FATAL_ERROR_STATUS_ICE = 0x00010000,
+ PORT_FATAL_ERROR_STATUS_ILE = 0x00020000,
+ PORT_FATAL_ERROR_STATUS_OPE = 0x00040000,
+ PORT_FATAL_ERROR_STATUS_TA = 0x00080000,
+ PORT_FATAL_ERROR_STATUS_MA = 0x00100000,
+ PORT_FATAL_ERROR_STATUS_SCE = 0x00200000,
+ PORT_FATAL_ERROR_STATUS_RPE = 0x00400000,
+ PORT_FATAL_ERROR_STATUS_MPE = 0x00800000,
+ PORT_FATAL_ERROR_STATUS_OCE = 0x01000000,
+};
+
+/*
+ * port control and status page - page 0
+ */
+
+struct ql3xxx_port_registers {
+ struct ql3xxx_common_registers CommonRegs;
+
+ u32 ExternalHWConfig;
+ u32 InternalChipConfig;
+ u32 portControl;
+ u32 portStatus;
+ u32 macAddrIndirectPtrReg;
+ u32 macAddrDataReg;
+ u32 macMIIMgmtControlReg;
+ u32 macMIIMgmtAddrReg;
+ u32 macMIIMgmtDataReg;
+ u32 macMIIStatusReg;
+ u32 mac0ConfigReg;
+ u32 mac0IpgIfgReg;
+ u32 mac0HalfDuplexReg;
+ u32 mac0MaxFrameLengthReg;
+ u32 mac0PauseThresholdReg;
+ u32 mac1ConfigReg;
+ u32 mac1IpgIfgReg;
+ u32 mac1HalfDuplexReg;
+ u32 mac1MaxFrameLengthReg;
+ u32 mac1PauseThresholdReg;
+ u32 ipAddrIndexReg;
+ u32 ipAddrDataReg;
+ u32 ipReassemblyTimeout;
+ u32 tcpMaxWindow;
+ u32 currentTcpTimestamp[2];
+ u32 internalRamRWAddrReg;
+ u32 internalRamWDataReg;
+ u32 reclaimedBufferAddrRegLow;
+ u32 reclaimedBufferAddrRegHigh;
+ u32 reserved[2];
+ u32 fpgaRevID;
+ u32 localRamAddr;
+ u32 localRamDataAutoIncr;
+ u32 localRamDataNonIncr;
+ u32 gpOutput;
+ u32 gpInput;
+ u32 probeMuxAddr;
+ u32 probeMuxData;
+ u32 statisticsIndexReg;
+ u32 statisticsReadDataRegAutoIncr;
+ u32 statisticsReadDataRegNoIncr;
+ u32 PortFatalErrStatus;
+};
+
+/*
+ * port host memory config page - page 1
+ */
+struct ql3xxx_host_memory_registers {
+ struct ql3xxx_common_registers CommonRegs;
+
+ u32 reserved[12];
+
+ /* Network Request Queue */
+ u32 reqConsumerIndex;
+ u32 reqConsumerIndexAddrLow;
+ u32 reqConsumerIndexAddrHigh;
+ u32 reqBaseAddrLow;
+ u32 reqBaseAddrHigh;
+ u32 reqLength;
+
+ /* Network Completion Queue */
+ u32 rspProducerIndex;
+ u32 rspProducerIndexAddrLow;
+ u32 rspProducerIndexAddrHigh;
+ u32 rspBaseAddrLow;
+ u32 rspBaseAddrHigh;
+ u32 rspLength;
+
+ /* RX Large Buffer Queue */
+ u32 rxLargeQConsumerIndex;
+ u32 rxLargeQBaseAddrLow;
+ u32 rxLargeQBaseAddrHigh;
+ u32 rxLargeQLength;
+ u32 rxLargeBufferLength;
+
+ /* RX Small Buffer Queue */
+ u32 rxSmallQConsumerIndex;
+ u32 rxSmallQBaseAddrLow;
+ u32 rxSmallQBaseAddrHigh;
+ u32 rxSmallQLength;
+ u32 rxSmallBufferLength;
+
+};
+
+/*
+ * port local RAM page - page 2
+ */
+struct ql3xxx_local_ram_registers {
+ struct ql3xxx_common_registers CommonRegs;
+ u32 bufletSize;
+ u32 maxBufletCount;
+ u32 currentBufletCount;
+ u32 reserved;
+ u32 freeBufletThresholdLow;
+ u32 freeBufletThresholdHigh;
+ u32 ipHashTableBase;
+ u32 ipHashTableCount;
+ u32 tcpHashTableBase;
+ u32 tcpHashTableCount;
+ u32 ncbBase;
+ u32 maxNcbCount;
+ u32 currentNcbCount;
+ u32 drbBase;
+ u32 maxDrbCount;
+ u32 currentDrbCount;
+};
+
+/*
+ * definitions for Semaphore bits in Semaphore/Serial NVRAM interface register
+ */
+
+#define LS_64BITS(x) (u32)(0xffffffff & ((u64)x))
+#define MS_64BITS(x) (u32)(0xffffffff & (((u64)x)>>16>>16) )
+
+/*
+ * I/O register
+ */
+
+enum {
+ CONTROL_REG = 0,
+ STATUS_REG = 1,
+ PHY_STAT_LINK_UP = 0x0004,
+ PHY_CTRL_LOOPBACK = 0x4000,
+
+ PETBI_CONTROL_REG = 0x00,
+ PETBI_CTRL_SOFT_RESET = 0x8000,
+ PETBI_CTRL_AUTO_NEG = 0x1000,
+ PETBI_CTRL_RESTART_NEG = 0x0200,
+ PETBI_CTRL_FULL_DUPLEX = 0x0100,
+ PETBI_CTRL_SPEED_1000 = 0x0040,
+
+ PETBI_STATUS_REG = 0x01,
+ PETBI_STAT_NEG_DONE = 0x0020,
+ PETBI_STAT_LINK_UP = 0x0004,
+
+ PETBI_NEG_ADVER = 0x04,
+ PETBI_NEG_PAUSE = 0x0080,
+ PETBI_NEG_PAUSE_MASK = 0x0180,
+ PETBI_NEG_DUPLEX = 0x0020,
+ PETBI_NEG_DUPLEX_MASK = 0x0060,
+
+ PETBI_NEG_PARTNER = 0x05,
+ PETBI_NEG_ERROR_MASK = 0x3000,
+
+ PETBI_EXPANSION_REG = 0x06,
+ PETBI_EXP_PAGE_RX = 0x0002,
+
+ PETBI_TBI_CTRL = 0x11,
+ PETBI_TBI_RESET = 0x8000,
+ PETBI_TBI_AUTO_SENSE = 0x0100,
+ PETBI_TBI_SERDES_MODE = 0x0010,
+ PETBI_TBI_SERDES_WRAP = 0x0002,
+
+ AUX_CONTROL_STATUS = 0x1c,
+ PHY_AUX_NEG_DONE = 0x8000,
+ PHY_NEG_PARTNER = 5,
+ PHY_AUX_DUPLEX_STAT = 0x0020,
+ PHY_AUX_SPEED_STAT = 0x0018,
+ PHY_AUX_NO_HW_STRAP = 0x0004,
+ PHY_AUX_RESET_STICK = 0x0002,
+ PHY_NEG_PAUSE = 0x0400,
+ PHY_CTRL_SOFT_RESET = 0x8000,
+ PHY_NEG_ADVER = 4,
+ PHY_NEG_ADV_SPEED = 0x01e0,
+ PHY_CTRL_RESTART_NEG = 0x0200,
+};
+enum {
+/* AM29LV Flash definitions */
+ FM93C56A_START = 0x1,
+/* Commands */
+ FM93C56A_READ = 0x2,
+ FM93C56A_WEN = 0x0,
+ FM93C56A_WRITE = 0x1,
+ FM93C56A_WRITE_ALL = 0x0,
+ FM93C56A_WDS = 0x0,
+ FM93C56A_ERASE = 0x3,
+ FM93C56A_ERASE_ALL = 0x0,
+/* Command Extentions */
+ FM93C56A_WEN_EXT = 0x3,
+ FM93C56A_WRITE_ALL_EXT = 0x1,
+ FM93C56A_WDS_EXT = 0x0,
+ FM93C56A_ERASE_ALL_EXT = 0x2,
+/* Special Bits */
+ FM93C56A_READ_DUMMY_BITS = 1,
+ FM93C56A_READY = 0,
+ FM93C56A_BUSY = 1,
+ FM93C56A_CMD_BITS = 2,
+/* AM29LV Flash definitions */
+ FM93C56A_SIZE_8 = 0x100,
+ FM93C56A_SIZE_16 = 0x80,
+ FM93C66A_SIZE_8 = 0x200,
+ FM93C66A_SIZE_16 = 0x100,
+ FM93C86A_SIZE_16 = 0x400,
+/* Address Bits */
+ FM93C56A_NO_ADDR_BITS_16 = 8,
+ FM93C56A_NO_ADDR_BITS_8 = 9,
+ FM93C86A_NO_ADDR_BITS_16 = 10,
+/* Data Bits */
+ FM93C56A_DATA_BITS_16 = 16,
+ FM93C56A_DATA_BITS_8 = 8,
+};
+enum {
+/* Auburn Bits */
+ AUBURN_EEPROM_DI = 0x8,
+ AUBURN_EEPROM_DI_0 = 0x0,
+ AUBURN_EEPROM_DI_1 = 0x8,
+ AUBURN_EEPROM_DO = 0x4,
+ AUBURN_EEPROM_DO_0 = 0x0,
+ AUBURN_EEPROM_DO_1 = 0x4,
+ AUBURN_EEPROM_CS = 0x2,
+ AUBURN_EEPROM_CS_0 = 0x0,
+ AUBURN_EEPROM_CS_1 = 0x2,
+ AUBURN_EEPROM_CLK_RISE = 0x1,
+ AUBURN_EEPROM_CLK_FALL = 0x0,
+};
+enum {EEPROM_SIZE = FM93C86A_SIZE_16,
+ EEPROM_NO_ADDR_BITS = FM93C86A_NO_ADDR_BITS_16,
+ EEPROM_NO_DATA_BITS = FM93C56A_DATA_BITS_16,
+};
+
+/*
+ * MAC Config data structure
+ */
+ struct eeprom_port_cfg {
+ u16 etherMtu_mac;
+ u16 pauseThreshold_mac;
+ u16 resumeThreshold_mac;
+ u16 portConfiguration;
+#define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000
+#define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000
+#define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000
+#define PORT_CONFIG_HALF_DUPLEX_ENABLED 0x1000
+#define PORT_CONFIG_1000MB_SPEED 0x0400
+#define PORT_CONFIG_100MB_SPEED 0x0200
+#define PORT_CONFIG_10MB_SPEED 0x0100
+#define PORT_CONFIG_LINK_SPEED_MASK 0x0F00
+ u16 reserved[12];
+
+};
+
+/*
+ * BIOS data structure
+ */
+struct eeprom_bios_cfg {
+ u16 SpinDlyEn:1, disBios:1, EnMemMap:1, EnSelectBoot:1, Reserved:12;
+
+ u8 bootID0:7, boodID0Valid:1;
+ u8 bootLun0[8];
+
+ u8 bootID1:7, boodID1Valid:1;
+ u8 bootLun1[8];
+
+ u16 MaxLunsTrgt;
+ u8 reserved[10];
+};
+
+/*
+ * Function Specific Data structure
+ */
+struct eeprom_function_cfg {
+ u8 reserved[30];
+ u8 macAddress[6];
+ u8 macAddressSecondary[6];
+
+ u16 subsysVendorId;
+ u16 subsysDeviceId;
+};
+
+/*
+ * EEPROM format
+ */
+struct eeprom_data {
+ u8 asicId[4];
+ u8 version;
+ u8 numPorts;
+ u16 boardId;
+
+#define EEPROM_BOARDID_STR_SIZE 16
+#define EEPROM_SERIAL_NUM_SIZE 16
+
+ u8 boardIdStr[16];
+ u8 serialNumber[16];
+ u16 extHwConfig;
+ struct eeprom_port_cfg macCfg_port0;
+ struct eeprom_port_cfg macCfg_port1;
+ u16 bufletSize;
+ u16 bufletCount;
+ u16 tcpWindowThreshold50;
+ u16 tcpWindowThreshold25;
+ u16 tcpWindowThreshold0;
+ u16 ipHashTableBaseHi;
+ u16 ipHashTableBaseLo;
+ u16 ipHashTableSize;
+ u16 tcpHashTableBaseHi;
+ u16 tcpHashTableBaseLo;
+ u16 tcpHashTableSize;
+ u16 ncbTableBaseHi;
+ u16 ncbTableBaseLo;
+ u16 ncbTableSize;
+ u16 drbTableBaseHi;
+ u16 drbTableBaseLo;
+ u16 drbTableSize;
+ u16 reserved_142[4];
+ u16 ipReassemblyTimeout;
+ u16 tcpMaxWindowSize;
+ u16 ipSecurity;
+#define IPSEC_CONFIG_PRESENT 0x0001
+ u8 reserved_156[294];
+ u16 qDebug[8];
+ struct eeprom_function_cfg funcCfg_fn0;
+ u16 reserved_510;
+ u8 oemSpace[432];
+ struct eeprom_bios_cfg biosCfg_fn1;
+ struct eeprom_function_cfg funcCfg_fn1;
+ u16 reserved_1022;
+ u8 reserved_1024[464];
+ struct eeprom_function_cfg funcCfg_fn2;
+ u16 reserved_1534;
+ u8 reserved_1536[432];
+ struct eeprom_bios_cfg biosCfg_fn3;
+ struct eeprom_function_cfg funcCfg_fn3;
+ u16 checksum;
+};
+
+/*
+ * General definitions...
+ */
+
+/*
+ * Below are a number compiler switches for controlling driver behavior.
+ * Some are not supported under certain conditions and are notated as such.
+ */
+
+#define QL3XXX_VENDOR_ID 0x1077
+#define QL3022_DEVICE_ID 0x3022
+
+/* MTU & Frame Size stuff */
+#define NORMAL_MTU_SIZE ETH_DATA_LEN
+#define JUMBO_MTU_SIZE 9000
+#define VLAN_ID_LEN 2
+
+/* Request Queue Related Definitions */
+#define NUM_REQ_Q_ENTRIES 256 /* so that 64 * 64 = 4096 (1 page) */
+
+/* Response Queue Related Definitions */
+#define NUM_RSP_Q_ENTRIES 256 /* so that 256 * 16 = 4096 (1 page) */
+
+/* Transmit and Receive Buffers */
+#define NUM_LBUFQ_ENTRIES 128
+#define NUM_SBUFQ_ENTRIES 64
+#define QL_SMALL_BUFFER_SIZE 32
+#define QL_ADDR_ELE_PER_BUFQ_ENTRY \
+(sizeof(struct lrg_buf_q_entry) / sizeof(struct bufq_addr_element))
+ /* Each send has at least control block. This is how many we keep. */
+#define NUM_SMALL_BUFFERS NUM_SBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+#define NUM_LARGE_BUFFERS NUM_LBUFQ_ENTRIES * QL_ADDR_ELE_PER_BUFQ_ENTRY
+#define QL_HEADER_SPACE 32 /* make header space at top of skb. */
+/*
+ * Large & Small Buffers for Receives
+ */
+struct lrg_buf_q_entry {
+
+ u32 addr0_lower;
+#define IAL_LAST_ENTRY 0x00000001
+#define IAL_CONT_ENTRY 0x00000002
+#define IAL_FLAG_MASK 0x00000003
+ u32 addr0_upper;
+ u32 addr1_lower;
+ u32 addr1_upper;
+ u32 addr2_lower;
+ u32 addr2_upper;
+ u32 addr3_lower;
+ u32 addr3_upper;
+ u32 addr4_lower;
+ u32 addr4_upper;
+ u32 addr5_lower;
+ u32 addr5_upper;
+ u32 addr6_lower;
+ u32 addr6_upper;
+ u32 addr7_lower;
+ u32 addr7_upper;
+
+};
+
+struct bufq_addr_element {
+ u32 addr_low;
+ u32 addr_high;
+};
+
+#define QL_NO_RESET 0
+#define QL_DO_RESET 1
+
+enum link_state_t {
+ LS_UNKNOWN = 0,
+ LS_DOWN,
+ LS_DEGRADE,
+ LS_RECOVER,
+ LS_UP,
+};
+
+struct ql_rcv_buf_cb {
+ struct ql_rcv_buf_cb *next;
+ struct sk_buff *skb;
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+ __le32 buf_phy_addr_low;
+ __le32 buf_phy_addr_high;
+ int index;
+};
+
+struct ql_tx_buf_cb {
+ struct sk_buff *skb;
+ struct ob_mac_iocb_req *queue_entry ;
+ DECLARE_PCI_UNMAP_ADDR(mapaddr);
+ DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
+/* definitions for type field */
+#define QL_BUF_TYPE_MACIOCB 0x01
+#define QL_BUF_TYPE_IPIOCB 0x02
+#define QL_BUF_TYPE_TCPIOCB 0x03
+
+/* qdev->flags definitions. */
+enum { QL_RESET_DONE = 1, /* Reset finished. */
+ QL_RESET_ACTIVE = 2, /* Waiting for reset to finish. */
+ QL_RESET_START = 3, /* Please reset the chip. */
+ QL_RESET_PER_SCSI = 4, /* SCSI driver requests reset. */
+ QL_TX_TIMEOUT = 5, /* Timeout in progress. */
+ QL_LINK_MASTER = 6, /* This driver controls the link. */
+ QL_ADAPTER_UP = 7, /* Adapter has been brought up. */
+ QL_THREAD_UP = 8, /* This flag is available. */
+ QL_LINK_UP = 9, /* Link Status. */
+ QL_ALLOC_REQ_RSP_Q_DONE = 10,
+ QL_ALLOC_BUFQS_DONE = 11,
+ QL_ALLOC_SMALL_BUF_DONE = 12,
+ QL_LINK_OPTICAL = 13,
+ QL_MSI_ENABLED = 14,
+};
+
+/*
+ * ql3_adapter - The main Adapter structure definition.
+ * This structure has all fields relevant to the hardware.
+ */
+
+struct ql3_adapter {
+ u32 reserved_00;
+ unsigned long flags;
+
+ /* PCI Configuration information for this device */
+ struct pci_dev *pdev;
+ struct net_device *ndev; /* Parent NET device */
+
+ /* Hardware information */
+ u8 chip_rev_id;
+ u8 pci_slot;
+ u8 pci_width;
+ u8 pci_x;
+ u32 msi;
+ int index;
+ struct timer_list adapter_timer; /* timer used for various functions */
+
+ spinlock_t adapter_lock;
+ spinlock_t hw_lock;
+
+ /* PCI Bus Relative Register Addresses */
+ u8 __iomem *mmap_virt_base; /* stores return value from ioremap() */
+ struct ql3xxx_port_registers __iomem *mem_map_registers;
+ u32 current_page; /* tracks current register page */
+
+ u32 msg_enable;
+ u8 reserved_01[2];
+ u8 reserved_02[2];
+
+ /* Page for Shadow Registers */
+ void *shadow_reg_virt_addr;
+ dma_addr_t shadow_reg_phy_addr;
+
+ /* Net Request Queue */
+ u32 req_q_size;
+ u32 reserved_03;
+ struct ob_mac_iocb_req *req_q_virt_addr;
+ dma_addr_t req_q_phy_addr;
+ u16 req_producer_index;
+ u16 reserved_04;
+ u16 *preq_consumer_index;
+ u32 req_consumer_index_phy_addr_high;
+ u32 req_consumer_index_phy_addr_low;
+ atomic_t tx_count;
+ struct ql_tx_buf_cb tx_buf[NUM_REQ_Q_ENTRIES];
+
+ /* Net Response Queue */
+ u32 rsp_q_size;
+ u32 eeprom_cmd_data;
+ struct net_rsp_iocb *rsp_q_virt_addr;
+ dma_addr_t rsp_q_phy_addr;
+ struct net_rsp_iocb *rsp_current;
+ u16 rsp_consumer_index;
+ u16 reserved_06;
+ u32 *prsp_producer_index;
+ u32 rsp_producer_index_phy_addr_high;
+ u32 rsp_producer_index_phy_addr_low;
+
+ /* Large Buffer Queue */
+ u32 lrg_buf_q_alloc_size;
+ u32 lrg_buf_q_size;
+ void *lrg_buf_q_alloc_virt_addr;
+ void *lrg_buf_q_virt_addr;
+ dma_addr_t lrg_buf_q_alloc_phy_addr;
+ dma_addr_t lrg_buf_q_phy_addr;
+ u32 lrg_buf_q_producer_index;
+ u32 lrg_buf_release_cnt;
+ struct bufq_addr_element *lrg_buf_next_free;
+
+ /* Large (Receive) Buffers */
+ struct ql_rcv_buf_cb lrg_buf[NUM_LARGE_BUFFERS];
+ struct ql_rcv_buf_cb *lrg_buf_free_head;
+ struct ql_rcv_buf_cb *lrg_buf_free_tail;
+ u32 lrg_buf_free_count;
+ u32 lrg_buffer_len;
+ u32 lrg_buf_index;
+ u32 lrg_buf_skb_check;
+
+ /* Small Buffer Queue */
+ u32 small_buf_q_alloc_size;
+ u32 small_buf_q_size;
+ u32 small_buf_q_producer_index;
+ void *small_buf_q_alloc_virt_addr;
+ void *small_buf_q_virt_addr;
+ dma_addr_t small_buf_q_alloc_phy_addr;
+ dma_addr_t small_buf_q_phy_addr;
+ u32 small_buf_index;
+
+ /* Small (Receive) Buffers */
+ void *small_buf_virt_addr;
+ dma_addr_t small_buf_phy_addr;
+ u32 small_buf_phy_addr_low;
+ u32 small_buf_phy_addr_high;
+ u32 small_buf_release_cnt;
+ u32 small_buf_total_size;
+
+ /* ISR related, saves status for DPC. */
+ u32 control_status;
+
+ struct eeprom_data nvram_data;
+ struct timer_list ioctl_timer;
+ u32 port_link_state;
+ u32 last_rsp_offset;
+
+ /* 4022 specific */
+ u32 mac_index; /* Driver's MAC number can be 0 or 1 for first and second networking functions respectively */
+ u32 PHYAddr; /* Address of PHY 0x1e00 Port 0 and 0x1f00 Port 1 */
+ u32 mac_ob_opcode; /* Opcode to use on mac transmission */
+ u32 tcp_ob_opcode; /* Opcode to use on tcp transmission */
+ u32 update_ob_opcode; /* Opcode to use for updating NCB */
+ u32 mb_bit_mask; /* MA Bits mask to use on transmission */
+ u32 numPorts;
+ struct net_device_stats stats;
+ struct workqueue_struct *workqueue;
+ struct work_struct reset_work;
+ struct work_struct tx_timeout_work;
+ u32 max_frame_size;
+};
+
+#endif /* _QLA3XXX_H_ */
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 12d1cb289bb..4c47c5b10ba 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -6,26 +6,26 @@
History:
Feb 4 2002 - created initially by ShuChen <shuchen@realtek.com.tw>.
May 20 2002 - Add link status force-mode and TBI mode support.
- 2004 - Massive updates. See kernel SCM system for details.
+ 2004 - Massive updates. See kernel SCM system for details.
=========================================================================
1. [DEPRECATED: use ethtool instead] The media can be forced in 5 modes.
Command: 'insmod r8169 media = SET_MEDIA'
Ex: 'insmod r8169 media = 0x04' will force PHY to operate in 100Mpbs Half-duplex.
-
+
SET_MEDIA can be:
_10_Half = 0x01
_10_Full = 0x02
_100_Half = 0x04
_100_Full = 0x08
_1000_Full = 0x10
-
+
2. Support TBI mode.
=========================================================================
VERSION 1.1 <2002/10/4>
The bit4:0 of MII register 4 is called "selector field", and have to be
00001b to indicate support of IEEE std 802.3 during NWay process of
- exchanging Link Code Word (FLP).
+ exchanging Link Code Word (FLP).
VERSION 1.2 <2002/11/30>
@@ -81,10 +81,10 @@ VERSION 2.2LK <2005/01/25>
#ifdef RTL8169_DEBUG
#define assert(expr) \
- if(!(expr)) { \
- printk( "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
- }
+ if (!(expr)) { \
+ printk( "Assertion failed! %s,%s,%s,line=%d\n", \
+ #expr,__FILE__,__FUNCTION__,__LINE__); \
+ }
#define dprintk(fmt, args...) do { printk(PFX fmt, ## args); } while (0)
#else
#define assert(expr) do {} while (0)
@@ -150,11 +150,16 @@ static const int multicast_filter_limit = 32;
#define RTL_R32(reg) ((unsigned long) readl (ioaddr + (reg)))
enum mac_version {
- RTL_GIGA_MAC_VER_B = 0x00,
- /* RTL_GIGA_MAC_VER_C = 0x03, */
- RTL_GIGA_MAC_VER_D = 0x01,
- RTL_GIGA_MAC_VER_E = 0x02,
- RTL_GIGA_MAC_VER_X = 0x04 /* Greater than RTL_GIGA_MAC_VER_E */
+ RTL_GIGA_MAC_VER_01 = 0x00,
+ RTL_GIGA_MAC_VER_02 = 0x01,
+ RTL_GIGA_MAC_VER_03 = 0x02,
+ RTL_GIGA_MAC_VER_04 = 0x03,
+ RTL_GIGA_MAC_VER_05 = 0x04,
+ RTL_GIGA_MAC_VER_11 = 0x0b,
+ RTL_GIGA_MAC_VER_12 = 0x0c,
+ RTL_GIGA_MAC_VER_13 = 0x0d,
+ RTL_GIGA_MAC_VER_14 = 0x0e,
+ RTL_GIGA_MAC_VER_15 = 0x0f
};
enum phy_version {
@@ -166,7 +171,6 @@ enum phy_version {
RTL_GIGA_PHY_VER_H = 0x08, /* PHY Reg 0x03 bit0-3 == 0x0003 */
};
-
#define _R(NAME,MAC,MASK) \
{ .name = NAME, .mac_version = MAC, .RxConfigMask = MASK }
@@ -175,19 +179,44 @@ static const struct {
u8 mac_version;
u32 RxConfigMask; /* Clears the bits supported by this chip */
} rtl_chip_info[] = {
- _R("RTL8169", RTL_GIGA_MAC_VER_B, 0xff7e1880),
- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_D, 0xff7e1880),
- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_E, 0xff7e1880),
- _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_X, 0xff7e1880),
+ _R("RTL8169", RTL_GIGA_MAC_VER_01, 0xff7e1880),
+ _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_02, 0xff7e1880),
+ _R("RTL8169s/8110s", RTL_GIGA_MAC_VER_03, 0xff7e1880),
+ _R("RTL8169sb/8110sb", RTL_GIGA_MAC_VER_04, 0xff7e1880),
+ _R("RTL8169sc/8110sc", RTL_GIGA_MAC_VER_05, 0xff7e1880),
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_11, 0xff7e1880), // PCI-E
+ _R("RTL8168b/8111b", RTL_GIGA_MAC_VER_12, 0xff7e1880), // PCI-E
+ _R("RTL8101e", RTL_GIGA_MAC_VER_13, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_14, 0xff7e1880), // PCI-E 8139
+ _R("RTL8100e", RTL_GIGA_MAC_VER_15, 0xff7e1880) // PCI-E 8139
};
#undef _R
+enum cfg_version {
+ RTL_CFG_0 = 0x00,
+ RTL_CFG_1,
+ RTL_CFG_2
+};
+
+static const struct {
+ unsigned int region;
+ unsigned int align;
+} rtl_cfg_info[] = {
+ [RTL_CFG_0] = { 1, NET_IP_ALIGN },
+ [RTL_CFG_1] = { 2, NET_IP_ALIGN },
+ [RTL_CFG_2] = { 2, 8 }
+};
+
static struct pci_device_id rtl8169_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
- { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), },
- { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), },
- { PCI_DEVICE(0x16ec, 0x0116), },
- { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024, },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8136), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8167), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8168), 0, 0, RTL_CFG_2 },
+ { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4300), 0, 0, RTL_CFG_0 },
+ { PCI_DEVICE(0x16ec, 0x0116), 0, 0, RTL_CFG_0 },
+ { PCI_VENDOR_ID_LINKSYS, 0x1032,
+ PCI_ANY_ID, 0x0024, 0, 0, RTL_CFG_0 },
{0,},
};
@@ -257,10 +286,11 @@ enum RTL8169_register_content {
RxOK = 0x01,
/* RxStatusDesc */
- RxRES = 0x00200000,
- RxCRC = 0x00080000,
- RxRUNT = 0x00100000,
- RxRWT = 0x00400000,
+ RxFOVF = (1 << 23),
+ RxRWT = (1 << 22),
+ RxRES = (1 << 21),
+ RxRUNT = (1 << 20),
+ RxCRC = (1 << 19),
/* ChipCmdBits */
CmdReset = 0x10,
@@ -326,30 +356,6 @@ enum RTL8169_register_content {
LinkStatus = 0x02,
FullDup = 0x01,
- /* GIGABIT_PHY_registers */
- PHY_CTRL_REG = 0,
- PHY_STAT_REG = 1,
- PHY_AUTO_NEGO_REG = 4,
- PHY_1000_CTRL_REG = 9,
-
- /* GIGABIT_PHY_REG_BIT */
- PHY_Restart_Auto_Nego = 0x0200,
- PHY_Enable_Auto_Nego = 0x1000,
-
- /* PHY_STAT_REG = 1 */
- PHY_Auto_Neco_Comp = 0x0020,
-
- /* PHY_AUTO_NEGO_REG = 4 */
- PHY_Cap_10_Half = 0x0020,
- PHY_Cap_10_Full = 0x0040,
- PHY_Cap_100_Half = 0x0080,
- PHY_Cap_100_Full = 0x0100,
-
- /* PHY_1000_CTRL_REG = 9 */
- PHY_Cap_1000_Full = 0x0200,
-
- PHY_Cap_Null = 0x0,
-
/* _MediaType */
_10_Half = 0x01,
_10_Full = 0x02,
@@ -433,6 +439,7 @@ struct rtl8169_private {
dma_addr_t RxPhyAddr;
struct sk_buff *Rx_skbuff[NUM_RX_DESC]; /* Rx data buffers */
struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */
+ unsigned align;
unsigned rx_buf_sz;
struct timer_list timer;
u16 cp_cmd;
@@ -488,12 +495,7 @@ static const u16 rtl8169_intr_mask =
static const u16 rtl8169_napi_event =
RxOK | RxOverflow | RxFIFOOver | TxOK | TxErr;
static const unsigned int rtl8169_rx_config =
- (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
-
-#define PHY_Cap_10_Half_Or_Less PHY_Cap_10_Half
-#define PHY_Cap_10_Full_Or_Less PHY_Cap_10_Full | PHY_Cap_10_Half_Or_Less
-#define PHY_Cap_100_Half_Or_Less PHY_Cap_100_Half | PHY_Cap_10_Full_Or_Less
-#define PHY_Cap_100_Full_Or_Less PHY_Cap_100_Full | PHY_Cap_100_Half_Or_Less
+ (RX_FIFO_THRESH << RxCfgFIFOShift) | (RX_DMA_BURST << RxCfgDMAShift);
static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
{
@@ -503,7 +505,7 @@ static void mdio_write(void __iomem *ioaddr, int RegAddr, int value)
for (i = 20; i > 0; i--) {
/* Check if the RTL8169 has completed writing to the specified MII register */
- if (!(RTL_R32(PHYAR) & 0x80000000))
+ if (!(RTL_R32(PHYAR) & 0x80000000))
break;
udelay(25);
}
@@ -547,7 +549,7 @@ static unsigned int rtl8169_tbi_reset_pending(void __iomem *ioaddr)
static unsigned int rtl8169_xmii_reset_pending(void __iomem *ioaddr)
{
- return mdio_read(ioaddr, 0) & 0x8000;
+ return mdio_read(ioaddr, MII_BMCR) & BMCR_RESET;
}
static unsigned int rtl8169_tbi_link_ok(void __iomem *ioaddr)
@@ -569,8 +571,8 @@ static void rtl8169_xmii_reset_enable(void __iomem *ioaddr)
{
unsigned int val;
- val = (mdio_read(ioaddr, PHY_CTRL_REG) | 0x8000) & 0xffff;
- mdio_write(ioaddr, PHY_CTRL_REG, val);
+ val = (mdio_read(ioaddr, MII_BMCR) | BMCR_RESET) & 0xffff;
+ mdio_write(ioaddr, MII_BMCR, val);
}
static void rtl8169_check_link_status(struct net_device *dev,
@@ -608,7 +610,7 @@ static void rtl8169_link_option(int idx, u8 *autoneg, u16 *speed, u8 *duplex)
{ SPEED_1000, DUPLEX_FULL, AUTONEG_ENABLE, 0xff }
}, *p;
unsigned char option;
-
+
option = ((idx < MAX_UNITS) && (idx >= 0)) ? media[idx] : 0xff;
if ((option != 0xff) && !idx && netif_msg_drv(&debug))
@@ -650,9 +652,9 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (options & UWF)
wol->wolopts |= WAKE_UCAST;
if (options & BWF)
- wol->wolopts |= WAKE_BCAST;
+ wol->wolopts |= WAKE_BCAST;
if (options & MWF)
- wol->wolopts |= WAKE_MCAST;
+ wol->wolopts |= WAKE_MCAST;
out_unlock:
spin_unlock_irq(&tp->lock);
@@ -745,38 +747,57 @@ static int rtl8169_set_speed_xmii(struct net_device *dev,
void __iomem *ioaddr = tp->mmio_addr;
int auto_nego, giga_ctrl;
- auto_nego = mdio_read(ioaddr, PHY_AUTO_NEGO_REG);
- auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_10_Full |
- PHY_Cap_100_Half | PHY_Cap_100_Full);
- giga_ctrl = mdio_read(ioaddr, PHY_1000_CTRL_REG);
- giga_ctrl &= ~(PHY_Cap_1000_Full | PHY_Cap_Null);
+ auto_nego = mdio_read(ioaddr, MII_ADVERTISE);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl = mdio_read(ioaddr, MII_CTRL1000);
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
if (autoneg == AUTONEG_ENABLE) {
- auto_nego |= (PHY_Cap_10_Half | PHY_Cap_10_Full |
- PHY_Cap_100_Half | PHY_Cap_100_Full);
- giga_ctrl |= PHY_Cap_1000_Full;
+ auto_nego |= (ADVERTISE_10HALF | ADVERTISE_10FULL |
+ ADVERTISE_100HALF | ADVERTISE_100FULL);
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
} else {
if (speed == SPEED_10)
- auto_nego |= PHY_Cap_10_Half | PHY_Cap_10_Full;
+ auto_nego |= ADVERTISE_10HALF | ADVERTISE_10FULL;
else if (speed == SPEED_100)
- auto_nego |= PHY_Cap_100_Half | PHY_Cap_100_Full;
+ auto_nego |= ADVERTISE_100HALF | ADVERTISE_100FULL;
else if (speed == SPEED_1000)
- giga_ctrl |= PHY_Cap_1000_Full;
+ giga_ctrl |= ADVERTISE_1000FULL | ADVERTISE_1000HALF;
if (duplex == DUPLEX_HALF)
- auto_nego &= ~(PHY_Cap_10_Full | PHY_Cap_100_Full);
+ auto_nego &= ~(ADVERTISE_10FULL | ADVERTISE_100FULL);
if (duplex == DUPLEX_FULL)
- auto_nego &= ~(PHY_Cap_10_Half | PHY_Cap_100_Half);
+ auto_nego &= ~(ADVERTISE_10HALF | ADVERTISE_100HALF);
+
+ /* This tweak comes straight from Realtek's driver. */
+ if ((speed == SPEED_100) && (duplex == DUPLEX_HALF) &&
+ (tp->mac_version == RTL_GIGA_MAC_VER_13)) {
+ auto_nego = ADVERTISE_100HALF | ADVERTISE_CSMA;
+ }
}
+ /* The 8100e/8101e do Fast Ethernet only. */
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+ if ((giga_ctrl & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
+ netif_msg_link(tp)) {
+ printk(KERN_INFO "%s: PHY does not support 1000Mbps.\n",
+ dev->name);
+ }
+ giga_ctrl &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF);
+ }
+
+ auto_nego |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
tp->phy_auto_nego_reg = auto_nego;
tp->phy_1000_ctrl_reg = giga_ctrl;
- mdio_write(ioaddr, PHY_AUTO_NEGO_REG, auto_nego);
- mdio_write(ioaddr, PHY_1000_CTRL_REG, giga_ctrl);
- mdio_write(ioaddr, PHY_CTRL_REG, PHY_Enable_Auto_Nego |
- PHY_Restart_Auto_Nego);
+ mdio_write(ioaddr, MII_ADVERTISE, auto_nego);
+ mdio_write(ioaddr, MII_CTRL1000, giga_ctrl);
+ mdio_write(ioaddr, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART);
return 0;
}
@@ -788,7 +809,7 @@ static int rtl8169_set_speed(struct net_device *dev,
ret = tp->set_speed(dev, autoneg, speed, duplex);
- if (netif_running(dev) && (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+ if (netif_running(dev) && (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
mod_timer(&tp->timer, jiffies + RTL8169_PHY_TIMEOUT);
return ret;
@@ -803,7 +824,7 @@ static int rtl8169_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
spin_lock_irqsave(&tp->lock, flags);
ret = rtl8169_set_speed(dev, cmd->autoneg, cmd->speed, cmd->duplex);
spin_unlock_irqrestore(&tp->lock, flags);
-
+
return ret;
}
@@ -936,20 +957,20 @@ static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
SUPPORTED_100baseT_Full |
SUPPORTED_1000baseT_Full |
SUPPORTED_Autoneg |
- SUPPORTED_TP;
+ SUPPORTED_TP;
cmd->autoneg = 1;
cmd->advertising = ADVERTISED_TP | ADVERTISED_Autoneg;
- if (tp->phy_auto_nego_reg & PHY_Cap_10_Half)
+ if (tp->phy_auto_nego_reg & ADVERTISE_10HALF)
cmd->advertising |= ADVERTISED_10baseT_Half;
- if (tp->phy_auto_nego_reg & PHY_Cap_10_Full)
+ if (tp->phy_auto_nego_reg & ADVERTISE_10FULL)
cmd->advertising |= ADVERTISED_10baseT_Full;
- if (tp->phy_auto_nego_reg & PHY_Cap_100_Half)
+ if (tp->phy_auto_nego_reg & ADVERTISE_100HALF)
cmd->advertising |= ADVERTISED_100baseT_Half;
- if (tp->phy_auto_nego_reg & PHY_Cap_100_Full)
+ if (tp->phy_auto_nego_reg & ADVERTISE_100FULL)
cmd->advertising |= ADVERTISED_100baseT_Full;
- if (tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full)
+ if (tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL)
cmd->advertising |= ADVERTISED_1000baseT_Full;
status = RTL_R8(PHYstatus);
@@ -961,6 +982,11 @@ static void rtl8169_gset_xmii(struct net_device *dev, struct ethtool_cmd *cmd)
else if (status & _10bps)
cmd->speed = SPEED_10;
+ if (status & TxFlowCtrl)
+ cmd->advertising |= ADVERTISED_Asym_Pause;
+ if (status & RxFlowCtrl)
+ cmd->advertising |= ADVERTISED_Pause;
+
cmd->duplex = ((status & _1000bpsF) || (status & FullDup)) ?
DUPLEX_FULL : DUPLEX_HALF;
}
@@ -981,15 +1007,15 @@ static int rtl8169_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
static void rtl8169_get_regs(struct net_device *dev, struct ethtool_regs *regs,
void *p)
{
- struct rtl8169_private *tp = netdev_priv(dev);
- unsigned long flags;
+ struct rtl8169_private *tp = netdev_priv(dev);
+ unsigned long flags;
- if (regs->len > R8169_REGS_SIZE)
- regs->len = R8169_REGS_SIZE;
+ if (regs->len > R8169_REGS_SIZE)
+ regs->len = R8169_REGS_SIZE;
- spin_lock_irqsave(&tp->lock, flags);
- memcpy_fromio(p, tp->mmio_addr, regs->len);
- spin_unlock_irqrestore(&tp->lock, flags);
+ spin_lock_irqsave(&tp->lock, flags);
+ memcpy_fromio(p, tp->mmio_addr, regs->len);
+ spin_unlock_irqrestore(&tp->lock, flags);
}
static u32 rtl8169_get_msglevel(struct net_device *dev)
@@ -1071,7 +1097,7 @@ static void rtl8169_get_ethtool_stats(struct net_device *dev,
RTL_W32(CounterAddrLow, 0);
RTL_W32(CounterAddrHigh, 0);
- data[0] = le64_to_cpu(counters->tx_packets);
+ data[0] = le64_to_cpu(counters->tx_packets);
data[1] = le64_to_cpu(counters->rx_packets);
data[2] = le64_to_cpu(counters->tx_errors);
data[3] = le32_to_cpu(counters->rx_errors);
@@ -1098,7 +1124,7 @@ static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data)
}
-static struct ethtool_ops rtl8169_ethtool_ops = {
+static const struct ethtool_ops rtl8169_ethtool_ops = {
.get_drvinfo = rtl8169_get_drvinfo,
.get_regs_len = rtl8169_get_regs_len,
.get_link = ethtool_op_get_link,
@@ -1131,7 +1157,7 @@ static void rtl8169_write_gmii_reg_bit(void __iomem *ioaddr, int reg, int bitnum
val = mdio_read(ioaddr, reg);
val = (bitval == 1) ?
val | (bitval << bitnum) : val & ~(0x0001 << bitnum);
- mdio_write(ioaddr, reg, val & 0xffff);
+ mdio_write(ioaddr, reg, val & 0xffff);
}
static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *ioaddr)
@@ -1140,10 +1166,16 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *io
u32 mask;
int mac_version;
} mac_info[] = {
- { 0x1 << 28, RTL_GIGA_MAC_VER_X },
- { 0x1 << 26, RTL_GIGA_MAC_VER_E },
- { 0x1 << 23, RTL_GIGA_MAC_VER_D },
- { 0x00000000, RTL_GIGA_MAC_VER_B } /* Catch-all */
+ { 0x38800000, RTL_GIGA_MAC_VER_15 },
+ { 0x38000000, RTL_GIGA_MAC_VER_12 },
+ { 0x34000000, RTL_GIGA_MAC_VER_13 },
+ { 0x30800000, RTL_GIGA_MAC_VER_14 },
+ { 0x30000000, RTL_GIGA_MAC_VER_11 },
+ { 0x18000000, RTL_GIGA_MAC_VER_05 },
+ { 0x10000000, RTL_GIGA_MAC_VER_04 },
+ { 0x04000000, RTL_GIGA_MAC_VER_03 },
+ { 0x00800000, RTL_GIGA_MAC_VER_02 },
+ { 0x00000000, RTL_GIGA_MAC_VER_01 } /* Catch-all */
}, *p = mac_info;
u32 reg;
@@ -1155,24 +1187,7 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp, void __iomem *io
static void rtl8169_print_mac_version(struct rtl8169_private *tp)
{
- struct {
- int version;
- char *msg;
- } mac_print[] = {
- { RTL_GIGA_MAC_VER_E, "RTL_GIGA_MAC_VER_E" },
- { RTL_GIGA_MAC_VER_D, "RTL_GIGA_MAC_VER_D" },
- { RTL_GIGA_MAC_VER_B, "RTL_GIGA_MAC_VER_B" },
- { 0, NULL }
- }, *p;
-
- for (p = mac_print; p->msg; p++) {
- if (tp->mac_version == p->version) {
- dprintk("mac_version == %s (%04d)\n", p->msg,
- p->version);
- return;
- }
- }
- dprintk("mac_version == Unknown\n");
+ dprintk("mac_version = 0x%02x\n", tp->mac_version);
}
static void rtl8169_get_phy_version(struct rtl8169_private *tp, void __iomem *ioaddr)
@@ -1189,7 +1204,7 @@ static void rtl8169_get_phy_version(struct rtl8169_private *tp, void __iomem *io
}, *p = phy_info;
u16 reg;
- reg = mdio_read(ioaddr, 3) & 0xffff;
+ reg = mdio_read(ioaddr, MII_PHYSID2) & 0xffff;
while ((reg & p->mask) != p->set)
p++;
tp->phy_version = p->phy_version;
@@ -1257,7 +1272,7 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
rtl8169_print_mac_version(tp);
rtl8169_print_phy_version(tp);
- if (tp->mac_version <= RTL_GIGA_MAC_VER_B)
+ if (tp->mac_version <= RTL_GIGA_MAC_VER_01)
return;
if (tp->phy_version >= RTL_GIGA_PHY_VER_H)
return;
@@ -1267,7 +1282,7 @@ static void rtl8169_hw_phy_config(struct net_device *dev)
/* Shazam ! */
- if (tp->mac_version == RTL_GIGA_MAC_VER_X) {
+ if (tp->mac_version == RTL_GIGA_MAC_VER_04) {
mdio_write(ioaddr, 31, 0x0001);
mdio_write(ioaddr, 9, 0x273a);
mdio_write(ioaddr, 14, 0x7bfb);
@@ -1306,16 +1321,16 @@ static void rtl8169_phy_timer(unsigned long __opaque)
void __iomem *ioaddr = tp->mmio_addr;
unsigned long timeout = RTL8169_PHY_TIMEOUT;
- assert(tp->mac_version > RTL_GIGA_MAC_VER_B);
+ assert(tp->mac_version > RTL_GIGA_MAC_VER_01);
assert(tp->phy_version < RTL_GIGA_PHY_VER_H);
- if (!(tp->phy_1000_ctrl_reg & PHY_Cap_1000_Full))
+ if (!(tp->phy_1000_ctrl_reg & ADVERTISE_1000FULL))
return;
spin_lock_irq(&tp->lock);
if (tp->phy_reset_pending(ioaddr)) {
- /*
+ /*
* A busy loop could burn quite a few cycles on nowadays CPU.
* Let's delay the execution of the timer for a few ticks.
*/
@@ -1342,7 +1357,7 @@ static inline void rtl8169_delete_timer(struct net_device *dev)
struct rtl8169_private *tp = netdev_priv(dev);
struct timer_list *timer = &tp->timer;
- if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
+ if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
(tp->phy_version >= RTL_GIGA_PHY_VER_H))
return;
@@ -1354,7 +1369,7 @@ static inline void rtl8169_request_timer(struct net_device *dev)
struct rtl8169_private *tp = netdev_priv(dev);
struct timer_list *timer = &tp->timer;
- if ((tp->mac_version <= RTL_GIGA_MAC_VER_B) ||
+ if ((tp->mac_version <= RTL_GIGA_MAC_VER_01) ||
(tp->phy_version >= RTL_GIGA_PHY_VER_H))
return;
@@ -1382,6 +1397,41 @@ static void rtl8169_netpoll(struct net_device *dev)
}
#endif
+static void __rtl8169_set_mac_addr(struct net_device *dev, void __iomem *ioaddr)
+{
+ unsigned int i, j;
+
+ RTL_W8(Cfg9346, Cfg9346_Unlock);
+ for (i = 0; i < 2; i++) {
+ __le32 l = 0;
+
+ for (j = 0; j < 4; j++) {
+ l <<= 8;
+ l |= dev->dev_addr[4*i + j];
+ }
+ RTL_W32(MAC0 + 4*i, cpu_to_be32(l));
+ }
+ RTL_W8(Cfg9346, Cfg9346_Lock);
+}
+
+static int rtl8169_set_mac_addr(struct net_device *dev, void *p)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ struct sockaddr *addr = p;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EINVAL;
+
+ memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+ if (netif_running(dev)) {
+ spin_lock_irq(&tp->lock);
+ __rtl8169_set_mac_addr(dev, tp->mmio_addr);
+ spin_unlock_irq(&tp->lock);
+ }
+ return 0;
+}
+
static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
void __iomem *ioaddr)
{
@@ -1391,23 +1441,87 @@ static void rtl8169_release_board(struct pci_dev *pdev, struct net_device *dev,
free_netdev(dev);
}
+static void rtl8169_init_phy(struct net_device *dev, struct rtl8169_private *tp)
+{
+ void __iomem *ioaddr = tp->mmio_addr;
+ static int board_idx = -1;
+ u8 autoneg, duplex;
+ u16 speed;
+
+ board_idx++;
+
+ rtl8169_hw_phy_config(dev);
+
+ dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+ RTL_W8(0x82, 0x01);
+
+ if (tp->mac_version < RTL_GIGA_MAC_VER_03) {
+ dprintk("Set PCI Latency=0x40\n");
+ pci_write_config_byte(tp->pci_dev, PCI_LATENCY_TIMER, 0x40);
+ }
+
+ if (tp->mac_version == RTL_GIGA_MAC_VER_02) {
+ dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
+ RTL_W8(0x82, 0x01);
+ dprintk("Set PHY Reg 0x0bh = 0x00h\n");
+ mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
+ }
+
+ rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
+
+ rtl8169_set_speed(dev, autoneg, speed, duplex);
+
+ if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
+ printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
+}
+
+static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+ struct rtl8169_private *tp = netdev_priv(dev);
+ struct mii_ioctl_data *data = if_mii(ifr);
+
+ if (!netif_running(dev))
+ return -ENODEV;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ data->phy_id = 32; /* Internal PHY */
+ return 0;
+
+ case SIOCGMIIREG:
+ data->val_out = mdio_read(tp->mmio_addr, data->reg_num & 0x1f);
+ return 0;
+
+ case SIOCSMIIREG:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ mdio_write(tp->mmio_addr, data->reg_num & 0x1f, data->val_in);
+ return 0;
+ }
+ return -EOPNOTSUPP;
+}
+
static int __devinit
-rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
- void __iomem **ioaddr_out)
+rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
- void __iomem *ioaddr;
- struct net_device *dev;
+ const unsigned int region = rtl_cfg_info[ent->driver_data].region;
struct rtl8169_private *tp;
- int rc = -ENOMEM, i, acpi_idle_state = 0, pm_cap;
+ struct net_device *dev;
+ void __iomem *ioaddr;
+ unsigned int i, pm_cap;
+ int rc;
- assert(ioaddr_out != NULL);
+ if (netif_msg_drv(&debug)) {
+ printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
+ MODULENAME, RTL8169_VERSION);
+ }
- /* dev zeroed in alloc_etherdev */
dev = alloc_etherdev(sizeof (*tp));
- if (dev == NULL) {
+ if (!dev) {
if (netif_msg_drv(&debug))
- printk(KERN_ERR PFX "unable to alloc new ethernet\n");
- goto err_out;
+ dev_err(&pdev->dev, "unable to alloc new ethernet\n");
+ rc = -ENOMEM;
+ goto out;
}
SET_MODULE_OWNER(dev);
@@ -1418,57 +1532,55 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pci_enable_device(pdev);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX "%s: enable failure\n",
- pci_name(pdev));
- }
- goto err_out_free_dev;
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "enable failure\n");
+ goto err_out_free_dev_1;
}
rc = pci_set_mwi(pdev);
if (rc < 0)
- goto err_out_disable;
+ goto err_out_disable_2;
/* save power state before pci_enable_device overwrites it */
pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
if (pm_cap) {
- u16 pwr_command;
+ u16 pwr_command, acpi_idle_state;
pci_read_config_word(pdev, pm_cap + PCI_PM_CTRL, &pwr_command);
acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK;
} else {
if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
- "PowerManagement capability not found.\n");
+ dev_err(&pdev->dev,
+ "PowerManagement capability not found.\n");
}
}
/* make sure PCI base addr 1 is MMIO */
- if (!(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) {
+ if (!(pci_resource_flags(pdev, region) & IORESOURCE_MEM)) {
if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
- "region #1 not an MMIO resource, aborting\n");
+ dev_err(&pdev->dev,
+ "region #%d not an MMIO resource, aborting\n",
+ region);
}
rc = -ENODEV;
- goto err_out_mwi;
+ goto err_out_mwi_3;
}
+
/* check for weird/broken PCI region reporting */
- if (pci_resource_len(pdev, 1) < R8169_REGS_SIZE) {
+ if (pci_resource_len(pdev, region) < R8169_REGS_SIZE) {
if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
- "Invalid PCI region size(s), aborting\n");
+ dev_err(&pdev->dev,
+ "Invalid PCI region size(s), aborting\n");
}
rc = -ENODEV;
- goto err_out_mwi;
+ goto err_out_mwi_3;
}
rc = pci_request_regions(pdev, MODULENAME);
if (rc < 0) {
- if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX "%s: could not request regions.\n",
- pci_name(pdev));
- }
- goto err_out_mwi;
+ if (netif_msg_probe(tp))
+ dev_err(&pdev->dev, "could not request regions.\n");
+ goto err_out_mwi_3;
}
tp->cp_cmd = PCIMulRW | RxChkSum;
@@ -1481,22 +1593,22 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc < 0) {
if (netif_msg_probe(tp)) {
- printk(KERN_ERR PFX
- "DMA configuration failed.\n");
+ dev_err(&pdev->dev,
+ "DMA configuration failed.\n");
}
- goto err_out_free_res;
+ goto err_out_free_res_4;
}
}
pci_set_master(pdev);
/* ioremap MMIO region */
- ioaddr = ioremap(pci_resource_start(pdev, 1), R8169_REGS_SIZE);
- if (ioaddr == NULL) {
+ ioaddr = ioremap(pci_resource_start(pdev, region), R8169_REGS_SIZE);
+ if (!ioaddr) {
if (netif_msg_probe(tp))
- printk(KERN_ERR PFX "cannot remap MMIO, aborting\n");
+ dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
rc = -EIO;
- goto err_out_free_res;
+ goto err_out_free_res_4;
}
/* Unneeded ? Don't mess with Mrs. Murphy. */
@@ -1506,10 +1618,10 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
RTL_W8(ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
+ for (i = 100; i > 0; i--) {
if ((RTL_R8(ChipCmd) & CmdReset) == 0)
break;
- udelay(10);
+ msleep_interruptible(1);
}
/* Identify chip attached to board */
@@ -1526,9 +1638,9 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
if (i < 0) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
- printk(KERN_DEBUG PFX "PCI device %s: "
- "unknown chip version, assuming %s\n",
- pci_name(pdev), rtl_chip_info[0].name);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "unknown chip version, assuming %s\n",
+ rtl_chip_info[0].name);
}
i++;
}
@@ -1539,56 +1651,6 @@ rtl8169_init_board(struct pci_dev *pdev, struct net_device **dev_out,
RTL_W8(Config5, RTL_R8(Config5) & PMEStatus);
RTL_W8(Cfg9346, Cfg9346_Lock);
- *ioaddr_out = ioaddr;
- *dev_out = dev;
-out:
- return rc;
-
-err_out_free_res:
- pci_release_regions(pdev);
-
-err_out_mwi:
- pci_clear_mwi(pdev);
-
-err_out_disable:
- pci_disable_device(pdev);
-
-err_out_free_dev:
- free_netdev(dev);
-err_out:
- *ioaddr_out = NULL;
- *dev_out = NULL;
- goto out;
-}
-
-static int __devinit
-rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct net_device *dev = NULL;
- struct rtl8169_private *tp;
- void __iomem *ioaddr = NULL;
- static int board_idx = -1;
- u8 autoneg, duplex;
- u16 speed;
- int i, rc;
-
- assert(pdev != NULL);
- assert(ent != NULL);
-
- board_idx++;
-
- if (netif_msg_drv(&debug)) {
- printk(KERN_INFO "%s Gigabit Ethernet driver %s loaded\n",
- MODULENAME, RTL8169_VERSION);
- }
-
- rc = rtl8169_init_board(pdev, &dev, &ioaddr);
- if (rc)
- return rc;
-
- tp = netdev_priv(dev);
- assert(ioaddr != NULL);
-
if (RTL_R8(PHYstatus) & TBI_Enable) {
tp->set_speed = rtl8169_set_speed_tbi;
tp->get_settings = rtl8169_gset_tbi;
@@ -1596,13 +1658,15 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->phy_reset_pending = rtl8169_tbi_reset_pending;
tp->link_ok = rtl8169_tbi_link_ok;
- tp->phy_1000_ctrl_reg = PHY_Cap_1000_Full; /* Implied by TBI */
+ tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */
} else {
tp->set_speed = rtl8169_set_speed_xmii;
tp->get_settings = rtl8169_gset_xmii;
tp->phy_reset_enable = rtl8169_xmii_reset_enable;
tp->phy_reset_pending = rtl8169_xmii_reset_pending;
tp->link_ok = rtl8169_xmii_link_ok;
+
+ dev->do_ioctl = rtl8169_ioctl;
}
/* Get MAC address. FIXME: read EEPROM */
@@ -1617,6 +1681,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dev->stop = rtl8169_close;
dev->tx_timeout = rtl8169_tx_timeout;
dev->set_multicast_list = rtl8169_set_rx_mode;
+ dev->set_mac_address = rtl8169_set_mac_addr;
dev->watchdog_timeo = RTL8169_TX_TIMEOUT;
dev->irq = pdev->irq;
dev->base_addr = (unsigned long) ioaddr;
@@ -1640,19 +1705,13 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
tp->intr_mask = 0xffff;
tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
+ tp->align = rtl_cfg_info[ent->driver_data].align;
spin_lock_init(&tp->lock);
rc = register_netdev(dev);
- if (rc) {
- rtl8169_release_board(pdev, dev, ioaddr);
- return rc;
- }
-
- if (netif_msg_probe(tp)) {
- printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n",
- dev->name, rtl_chip_info[tp->chipset].name);
- }
+ if (rc < 0)
+ goto err_out_unmap_5;
pci_set_drvdata(pdev, dev);
@@ -1661,38 +1720,29 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
"%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, "
"IRQ %d\n",
dev->name,
- rtl_chip_info[ent->driver_data].name,
+ rtl_chip_info[tp->chipset].name,
dev->base_addr,
dev->dev_addr[0], dev->dev_addr[1],
dev->dev_addr[2], dev->dev_addr[3],
dev->dev_addr[4], dev->dev_addr[5], dev->irq);
}
- rtl8169_hw_phy_config(dev);
-
- dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
-
- if (tp->mac_version < RTL_GIGA_MAC_VER_E) {
- dprintk("Set PCI Latency=0x40\n");
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40);
- }
+ rtl8169_init_phy(dev, tp);
- if (tp->mac_version == RTL_GIGA_MAC_VER_D) {
- dprintk("Set MAC Reg C+CR Offset 0x82h = 0x01h\n");
- RTL_W8(0x82, 0x01);
- dprintk("Set PHY Reg 0x0bh = 0x00h\n");
- mdio_write(ioaddr, 0x0b, 0x0000); //w 0x0b 15 0 0
- }
-
- rtl8169_link_option(board_idx, &autoneg, &speed, &duplex);
-
- rtl8169_set_speed(dev, autoneg, speed, duplex);
-
- if ((RTL_R8(PHYstatus) & TBI_Enable) && netif_msg_link(tp))
- printk(KERN_INFO PFX "%s: TBI auto-negotiating\n", dev->name);
+out:
+ return rc;
- return 0;
+err_out_unmap_5:
+ iounmap(ioaddr);
+err_out_free_res_4:
+ pci_release_regions(pdev);
+err_out_mwi_3:
+ pci_clear_mwi(pdev);
+err_out_disable_2:
+ pci_disable_device(pdev);
+err_out_free_dev_1:
+ free_netdev(dev);
+ goto out;
}
static void __devexit
@@ -1726,7 +1776,7 @@ static int rtl8169_open(struct net_device *dev)
rtl8169_set_rxbufsize(tp, dev);
retval =
- request_irq(dev->irq, rtl8169_interrupt, SA_SHIRQ, dev->name, dev);
+ request_irq(dev->irq, rtl8169_interrupt, IRQF_SHARED, dev->name, dev);
if (retval < 0)
goto out;
@@ -1788,20 +1838,41 @@ rtl8169_hw_start(struct net_device *dev)
{
struct rtl8169_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->mmio_addr;
+ struct pci_dev *pdev = tp->pci_dev;
u32 i;
/* Soft reset the chip. */
RTL_W8(ChipCmd, CmdReset);
/* Check that the chip has finished the reset. */
- for (i = 1000; i > 0; i--) {
+ for (i = 100; i > 0; i--) {
if ((RTL_R8(ChipCmd) & CmdReset) == 0)
break;
- udelay(10);
+ msleep_interruptible(1);
}
+ if (tp->mac_version == RTL_GIGA_MAC_VER_13) {
+ pci_write_config_word(pdev, 0x68, 0x00);
+ pci_write_config_word(pdev, 0x69, 0x08);
+ }
+
+ /* Undocumented stuff. */
+ if (tp->mac_version == RTL_GIGA_MAC_VER_05) {
+ u16 cmd;
+
+ /* Realtek's r1000_n.c driver uses '&& 0x01' here. Well... */
+ if ((RTL_R8(Config2) & 0x07) & 0x01)
+ RTL_W32(0x7c, 0x0007ffff);
+
+ RTL_W32(0x7c, 0x0007ff00);
+
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd);
+ cmd = cmd & 0xef;
+ pci_write_config_word(pdev, PCI_COMMAND, cmd);
+ }
+
+
RTL_W8(Cfg9346, Cfg9346_Unlock);
- RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(EarlyTxThres, EarlyTxThld);
/* Low hurts. Let's disable the filtering. */
@@ -1813,32 +1884,40 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W32(RxConfig, i);
/* Set DMA burst size and Interframe Gap Time */
- RTL_W32(TxConfig,
- (TX_DMA_BURST << TxDMAShift) | (InterFrameGap <<
- TxInterFrameGapShift));
- tp->cp_cmd |= RTL_R16(CPlusCmd);
- RTL_W16(CPlusCmd, tp->cp_cmd);
+ RTL_W32(TxConfig, (TX_DMA_BURST << TxDMAShift) |
+ (InterFrameGap << TxInterFrameGapShift));
- if ((tp->mac_version == RTL_GIGA_MAC_VER_D) ||
- (tp->mac_version == RTL_GIGA_MAC_VER_E)) {
+ tp->cp_cmd |= RTL_R16(CPlusCmd) | PCIMulRW;
+
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_02) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_03)) {
dprintk(KERN_INFO PFX "Set MAC Reg C+CR Offset 0xE0. "
"Bit-3 and bit-14 MUST be 1\n");
- tp->cp_cmd |= (1 << 14) | PCIMulRW;
- RTL_W16(CPlusCmd, tp->cp_cmd);
+ tp->cp_cmd |= (1 << 14);
}
+ RTL_W16(CPlusCmd, tp->cp_cmd);
+
/*
* Undocumented corner. Supposedly:
* (TxTimer << 12) | (TxPackets << 8) | (RxTimer << 4) | RxPackets
*/
RTL_W16(IntrMitigate, 0x0000);
- RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
+ /*
+ * Magic spell: some iop3xx ARM board needs the TxDescAddrHigh
+ * register to be written before TxDescAddrLow to work.
+ * Switching from MMIO to I/O access fixes the issue as well.
+ */
RTL_W32(TxDescStartAddrHigh, ((u64) tp->TxPhyAddr >> 32));
- RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
+ RTL_W32(TxDescStartAddrLow, ((u64) tp->TxPhyAddr & DMA_32BIT_MASK));
RTL_W32(RxDescAddrHigh, ((u64) tp->RxPhyAddr >> 32));
+ RTL_W32(RxDescAddrLow, ((u64) tp->RxPhyAddr & DMA_32BIT_MASK));
+ RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(Cfg9346, Cfg9346_Lock);
- udelay(10);
+
+ /* Initially a 10 us delay. Turned it into a PCI commit. - FR */
+ RTL_R8(IntrMask);
RTL_W32(RxMissed, 0);
@@ -1850,6 +1929,8 @@ rtl8169_hw_start(struct net_device *dev)
/* Enable all known interrupts by setting the interrupt mask. */
RTL_W16(IntrMask, rtl8169_intr_mask);
+ __rtl8169_set_mac_addr(dev, ioaddr);
+
netif_start_queue(dev);
}
@@ -1918,17 +1999,18 @@ static inline void rtl8169_map_to_asic(struct RxDesc *desc, dma_addr_t mapping,
}
static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
- struct RxDesc *desc, int rx_buf_sz)
+ struct RxDesc *desc, int rx_buf_sz,
+ unsigned int align)
{
struct sk_buff *skb;
dma_addr_t mapping;
int ret = 0;
- skb = dev_alloc_skb(rx_buf_sz + NET_IP_ALIGN);
+ skb = dev_alloc_skb(rx_buf_sz + align);
if (!skb)
goto err_out;
- skb_reserve(skb, NET_IP_ALIGN);
+ skb_reserve(skb, align);
*sk_buff = skb;
mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
@@ -1961,15 +2043,15 @@ static u32 rtl8169_rx_fill(struct rtl8169_private *tp, struct net_device *dev,
u32 start, u32 end)
{
u32 cur;
-
+
for (cur = start; end - cur > 0; cur++) {
int ret, i = cur % NUM_RX_DESC;
if (tp->Rx_skbuff[i])
continue;
-
+
ret = rtl8169_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
- tp->RxDescArray + i, tp->rx_buf_sz);
+ tp->RxDescArray + i, tp->rx_buf_sz, tp->align);
if (ret < 0)
break;
}
@@ -2177,7 +2259,7 @@ static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
if (mss)
return LargeSend | ((mss & MSSMask) << MSSShift);
}
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
const struct iphdr *ip = skb->nh.iph;
if (ip->protocol == IPPROTO_TCP)
@@ -2198,8 +2280,8 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
dma_addr_t mapping;
u32 status, len;
u32 opts1;
- int ret = 0;
-
+ int ret = NETDEV_TX_OK;
+
if (unlikely(TX_BUFFS_AVAIL(tp) < skb_shinfo(skb)->nr_frags)) {
if (netif_msg_drv(tp)) {
printk(KERN_ERR
@@ -2263,7 +2345,7 @@ out:
err_stop:
netif_stop_queue(dev);
- ret = 1;
+ ret = NETDEV_TX_BUSY;
err_update_stats:
tp->stats.tx_dropped++;
goto out;
@@ -2380,16 +2462,17 @@ static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
}
static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
- struct RxDesc *desc, int rx_buf_sz)
+ struct RxDesc *desc, int rx_buf_sz,
+ unsigned int align)
{
int ret = -1;
if (pkt_size < rx_copybreak) {
struct sk_buff *skb;
- skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+ skb = dev_alloc_skb(pkt_size + align);
if (skb) {
- skb_reserve(skb, NET_IP_ALIGN);
+ skb_reserve(skb, align);
eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
*sk_buff = skb;
rtl8169_mark_to_asic(desc, rx_buf_sz);
@@ -2435,6 +2518,10 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
tp->stats.rx_length_errors++;
if (status & RxCRC)
tp->stats.rx_crc_errors++;
+ if (status & RxFOVF) {
+ rtl8169_schedule_work(dev, rtl8169_reset_task);
+ tp->stats.rx_fifo_errors++;
+ }
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else {
struct sk_buff *skb = tp->Rx_skbuff[entry];
@@ -2455,13 +2542,13 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
}
rtl8169_rx_csum(skb, desc);
-
+
pci_dma_sync_single_for_cpu(tp->pci_dev,
le64_to_cpu(desc->addr), tp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
if (rtl8169_try_rx_copy(&skb, pkt_size, desc,
- tp->rx_buf_sz)) {
+ tp->rx_buf_sz, tp->align)) {
pci_action = pci_unmap_single;
tp->Rx_skbuff[entry] = NULL;
}
@@ -2551,7 +2638,7 @@ rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
__netif_rx_schedule(dev);
else if (netif_msg_intr(tp)) {
printk(KERN_INFO "%s: interrupt %04x taken in poll\n",
- dev->name, status);
+ dev->name, status);
}
break;
#else
@@ -2724,6 +2811,15 @@ rtl8169_set_rx_mode(struct net_device *dev)
tmp = rtl8169_rx_config | rx_mode |
(RTL_R32(RxConfig) & rtl_chip_info[tp->chipset].RxConfigMask);
+ if ((tp->mac_version == RTL_GIGA_MAC_VER_11) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_12) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_13) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_14) ||
+ (tp->mac_version == RTL_GIGA_MAC_VER_15)) {
+ mc_filter[0] = 0xffffffff;
+ mc_filter[1] = 0xffffffff;
+ }
+
RTL_W32(RxConfig, tmp);
RTL_W32(MAR0 + 0, mc_filter[0]);
RTL_W32(MAR0 + 4, mc_filter[1]);
@@ -2749,7 +2845,7 @@ static struct net_device_stats *rtl8169_get_stats(struct net_device *dev)
RTL_W32(RxMissed, 0);
spin_unlock_irqrestore(&tp->lock, flags);
}
-
+
return &tp->stats;
}
@@ -2817,7 +2913,7 @@ static struct pci_driver rtl8169_pci_driver = {
static int __init
rtl8169_init_module(void)
{
- return pci_module_init(&rtl8169_pci_driver);
+ return pci_register_driver(&rtl8169_pci_driver);
}
static void __exit
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 12cde060458..b7ff484af3e 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -427,7 +427,7 @@ static void rionet_set_msglevel(struct net_device *ndev, u32 value)
rnet->msg_enable = value;
}
-static struct ethtool_ops rionet_ethtool_ops = {
+static const struct ethtool_ops rionet_ethtool_ops = {
.get_drvinfo = rionet_get_drvinfo,
.get_msglevel = rionet_get_msglevel,
.set_msglevel = rionet_set_msglevel,
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 19c2df9c86f..6108bac8d56 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -28,7 +28,6 @@
#define RX_DMA_SKBUFF 1
#define PKT_COPY_THRESHOLD 512
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -215,13 +214,13 @@ static int __devinit rr_init_one(struct pci_dev *pdev,
out:
if (rrpriv->rx_ring)
- pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring,
+ pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring,
rrpriv->rx_ring_dma);
if (rrpriv->tx_ring)
pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring,
rrpriv->tx_ring_dma);
if (rrpriv->regs)
- iounmap(rrpriv->regs);
+ iounmap(rrpriv->regs);
if (pdev) {
pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
@@ -560,7 +559,7 @@ static int __init rr_init(struct net_device *dev)
htons(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA));
*(u32 *)(dev->dev_addr+2) =
htonl(rr_read_eeprom_word(rrpriv, &hw->manf.BoardULA[4]));
-
+
printk(" MAC: ");
for (i = 0; i < 5; i++)
@@ -737,8 +736,8 @@ static int rr_init1(struct net_device *dev)
struct sk_buff *skb = rrpriv->rx_skbuff[i];
if (skb) {
- pci_unmap_single(rrpriv->pci_dev,
- rrpriv->rx_ring[i].addr.addrlo,
+ pci_unmap_single(rrpriv->pci_dev,
+ rrpriv->rx_ring[i].addr.addrlo,
dev->mtu + HIPPI_HLEN,
PCI_DMA_FROMDEVICE);
rrpriv->rx_ring[i].size = 0;
@@ -793,14 +792,14 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_INTERN_ERR:
printk(KERN_ERR "%s: HIPPI Internal NIC error\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
case E_HOST_ERR:
printk(KERN_ERR "%s: Host software error\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
@@ -824,7 +823,7 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_INT_PRTY:
printk(KERN_ERR "%s: HIPPI Internal Parity error\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
@@ -836,28 +835,28 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
printk(KERN_WARNING "%s: Link lost during transmit\n",
dev->name);
rrpriv->stats.tx_aborted_errors++;
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
case E_TX_INV_RNG:
printk(KERN_ERR "%s: Invalid send ring block\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
case E_TX_INV_BUF:
printk(KERN_ERR "%s: Invalid send buffer address\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
case E_TX_INV_DSC:
printk(KERN_ERR "%s: Invalid descriptor address\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
@@ -911,21 +910,21 @@ static u32 rr_handle_event(struct net_device *dev, u32 prodidx, u32 eidx)
case E_RX_INV_BUF:
printk(KERN_ERR "%s: Invalid receive buffer "
"address\n", dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
case E_RX_INV_DSC:
printk(KERN_ERR "%s: Invalid receive descriptor "
"address\n", dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
case E_RNG_BLK:
printk(KERN_ERR "%s: Invalid ring block\n",
dev->name);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
wmb();
break;
@@ -1012,15 +1011,15 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
if (newskb){
dma_addr_t addr;
- pci_unmap_single(rrpriv->pci_dev,
- desc->addr.addrlo, dev->mtu +
+ pci_unmap_single(rrpriv->pci_dev,
+ desc->addr.addrlo, dev->mtu +
HIPPI_HLEN, PCI_DMA_FROMDEVICE);
skb = rx_skb;
skb_put(skb, pkt_len);
rrpriv->rx_skbuff[index] = newskb;
- addr = pci_map_single(rrpriv->pci_dev,
- newskb->data,
- dev->mtu + HIPPI_HLEN,
+ addr = pci_map_single(rrpriv->pci_dev,
+ newskb->data,
+ dev->mtu + HIPPI_HLEN,
PCI_DMA_FROMDEVICE);
set_rraddr(&desc->addr, addr);
} else {
@@ -1200,7 +1199,7 @@ static void rr_timer(unsigned long data)
if (rr_init1(dev)) {
spin_lock_irqsave(&rrpriv->lock, flags);
- writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
+ writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT,
&regs->HostCtrl);
spin_unlock_irqrestore(&rrpriv->lock, flags);
}
@@ -1253,7 +1252,7 @@ static int rr_open(struct net_device *dev)
readl(&regs->HostCtrl);
spin_unlock_irqrestore(&rrpriv->lock, flags);
- if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, dev->name, dev)) {
+ if (request_irq(dev->irq, rr_interrupt, IRQF_SHARED, dev->name, dev)) {
printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
dev->name, dev->irq);
ecode = -EAGAIN;
@@ -1292,7 +1291,7 @@ static int rr_open(struct net_device *dev)
}
netif_stop_queue(dev);
-
+
return ecode;
}
@@ -1528,7 +1527,7 @@ static int rr_load_firmware(struct net_device *dev)
return -EBUSY;
if (!(readl(&regs->HostCtrl) & NIC_HALTED)){
- printk("%s: Trying to load firmware to a running NIC.\n",
+ printk("%s: Trying to load firmware to a running NIC.\n",
dev->name);
return -EBUSY;
}
@@ -1661,7 +1660,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
gf_out:
kfree(image);
return error;
-
+
case SIOCRRPFW:
if (!capable(CAP_SYS_RAWIO)){
return -EPERM;
@@ -1713,7 +1712,7 @@ static int rr_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
kfree(oldimage);
kfree(image);
return error;
-
+
case SIOCRRID:
return put_user(0x52523032, (int __user *)rq->ifr_data);
default:
@@ -1737,7 +1736,7 @@ static struct pci_driver rr_driver = {
static int __init rr_init_module(void)
{
- return pci_module_init(&rr_driver);
+ return pci_register_driver(&rr_driver);
}
static void __exit rr_cleanup_module(void)
diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h
index 10baae55953..99451b52339 100644
--- a/drivers/net/rrunner.h
+++ b/drivers/net/rrunner.h
@@ -1,7 +1,6 @@
#ifndef _RRUNNER_H_
#define _RRUNNER_H_
-#include <linux/config.h>
#include <linux/interrupt.h>
#if ((BITS_PER_LONG != 32) && (BITS_PER_LONG != 64))
@@ -168,7 +167,7 @@ struct rr_regs {
/*
* Host control register bits.
*/
-
+
#define RR_INT 0x01
#define RR_CLEAR_INT 0x02
#define NO_SWAP 0x04000004
@@ -239,9 +238,9 @@ struct rr_regs {
/*
* Receive state
*
- * RoadRunner HIPPI Receive State Register controls and monitors the
+ * RoadRunner HIPPI Receive State Register controls and monitors the
* HIPPI receive interface in the NIC. Look at err bits when a HIPPI
- * receive Error Event occurs.
+ * receive Error Event occurs.
*/
#define ENABLE_NEW_CON 0x01
@@ -701,7 +700,7 @@ struct rr_stats {
u32 StatUpdtT;
u32 StatUpdtC;
u32 WatchDog;
- u32 Trace;
+ u32 Trace;
/* Serial HIPPI */
u32 LnkRdyEst;
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h
index 0ef52589956..a914fef4430 100644
--- a/drivers/net/s2io-regs.h
+++ b/drivers/net/s2io-regs.h
@@ -656,8 +656,8 @@ typedef struct _XENA_dev_config {
u64 rmac_addr_cfg;
#define RMAC_ADDR_UCASTn_EN(n) mBIT(0)_n(n)
#define RMAC_ADDR_MCASTn_EN(n) mBIT(0)_n(n)
-#define RMAC_ADDR_BCAST_EN vBIT(0)_48
-#define RMAC_ADDR_ALL_ADDR_EN vBIT(0)_49
+#define RMAC_ADDR_BCAST_EN vBIT(0)_48
+#define RMAC_ADDR_ALL_ADDR_EN vBIT(0)_49
*/
u64 tmac_ipg_cfg;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 3defe5d4f7d..1bf23e41f58 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -44,7 +44,6 @@
* aggregated as a single large packet
************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -72,12 +71,13 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/div64.h>
+#include <asm/irq.h>
/* local include */
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.14.2"
+#define DRV_VERSION "2.0.15.2"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -371,38 +371,50 @@ static const u64 fix_mac[] = {
END_SIGN
};
+MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+
/* Module Loadable parameters. */
-static unsigned int tx_fifo_num = 1;
-static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
- {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
-static unsigned int rx_ring_num = 1;
-static unsigned int rx_ring_sz[MAX_RX_RINGS] =
- {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
-static unsigned int rts_frm_len[MAX_RX_RINGS] =
- {[0 ...(MAX_RX_RINGS - 1)] = 0 };
-static unsigned int rx_ring_mode = 1;
-static unsigned int use_continuous_tx_intrs = 1;
-static unsigned int rmac_pause_time = 0x100;
-static unsigned int mc_pause_threshold_q0q3 = 187;
-static unsigned int mc_pause_threshold_q4q7 = 187;
-static unsigned int shared_splits;
-static unsigned int tmac_util_period = 5;
-static unsigned int rmac_util_period = 5;
-static unsigned int bimodal = 0;
-static unsigned int l3l4hdr_size = 128;
-#ifndef CONFIG_S2IO_NAPI
-static unsigned int indicate_max_pkts;
-#endif
+S2IO_PARM_INT(tx_fifo_num, 1);
+S2IO_PARM_INT(rx_ring_num, 1);
+
+
+S2IO_PARM_INT(rx_ring_mode, 1);
+S2IO_PARM_INT(use_continuous_tx_intrs, 1);
+S2IO_PARM_INT(rmac_pause_time, 0x100);
+S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
+S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
+S2IO_PARM_INT(shared_splits, 0);
+S2IO_PARM_INT(tmac_util_period, 5);
+S2IO_PARM_INT(rmac_util_period, 5);
+S2IO_PARM_INT(bimodal, 0);
+S2IO_PARM_INT(l3l4hdr_size, 128);
/* Frequency of Rx desc syncs expressed as power of 2 */
-static unsigned int rxsync_frequency = 3;
+S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
-static unsigned int intr_type = 0;
+S2IO_PARM_INT(intr_type, 0);
/* Large receive offload feature */
-static unsigned int lro = 0;
+S2IO_PARM_INT(lro, 0);
/* Max pkts to be aggregated by LRO at one time. If not specified,
* aggregation happens until we hit max IP pkt size(64K)
*/
-static unsigned int lro_max_pkts = 0xFFFF;
+S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
+#ifndef CONFIG_S2IO_NAPI
+S2IO_PARM_INT(indicate_max_pkts, 0);
+#endif
+
+static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
+ {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
+static unsigned int rx_ring_sz[MAX_RX_RINGS] =
+ {[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
+static unsigned int rts_frm_len[MAX_RX_RINGS] =
+ {[0 ...(MAX_RX_RINGS - 1)] = 0 };
+
+module_param_array(tx_fifo_len, uint, NULL, 0);
+module_param_array(rx_ring_sz, uint, NULL, 0);
+module_param_array(rts_frm_len, uint, NULL, 0);
/*
* S2IO device table.
@@ -465,10 +477,9 @@ static int init_shared_mem(struct s2io_nic *nic)
size += config->tx_cfg[i].fifo_len;
}
if (size > MAX_AVAILABLE_TXDS) {
- DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
- __FUNCTION__);
+ DBG_PRINT(ERR_DBG, "s2io: Requested TxDs too high, ");
DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
- return FAILURE;
+ return -EINVAL;
}
lst_size = (sizeof(TxD_t) * config->max_txds);
@@ -519,9 +530,9 @@ static int init_shared_mem(struct s2io_nic *nic)
*/
if (!tmp_p) {
mac_control->zerodma_virt_addr = tmp_v;
- DBG_PRINT(INIT_DBG,
+ DBG_PRINT(INIT_DBG,
"%s: Zero DMA address for TxDL. ", dev->name);
- DBG_PRINT(INIT_DBG,
+ DBG_PRINT(INIT_DBG,
"Virtual address %p\n", tmp_v);
tmp_v = pci_alloc_consistent(nic->pdev,
PAGE_SIZE, &tmp_p);
@@ -548,6 +559,7 @@ static int init_shared_mem(struct s2io_nic *nic)
nic->ufo_in_band_v = kmalloc((sizeof(u64) * size), GFP_KERNEL);
if (!nic->ufo_in_band_v)
return -ENOMEM;
+ memset(nic->ufo_in_band_v, 0, size);
/* Allocation and initialization of RXDs in Rings */
size = 0;
@@ -744,7 +756,7 @@ static void free_shared_mem(struct s2io_nic *nic)
for (j = 0; j < page_num; j++) {
int mem_blks = (j * lst_per_page);
if (!mac_control->fifos[i].list_info)
- return;
+ return;
if (!mac_control->fifos[i].list_info[mem_blks].
list_virt_addr)
break;
@@ -763,7 +775,7 @@ static void free_shared_mem(struct s2io_nic *nic)
pci_free_consistent(nic->pdev, PAGE_SIZE,
mac_control->zerodma_virt_addr,
(dma_addr_t)0);
- DBG_PRINT(INIT_DBG,
+ DBG_PRINT(INIT_DBG,
"%s: Freeing TxDL with zero DMA addr. ",
dev->name);
DBG_PRINT(INIT_DBG, "Virtual address %p\n",
@@ -843,9 +855,10 @@ static int s2io_verify_pci_mode(nic_t *nic)
static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
{
struct pci_dev *tdev = NULL;
- while ((tdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
- if ((tdev->vendor == NEC_VENID) && (tdev->device == NEC_DEVID)){
+ while ((tdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, tdev)) != NULL) {
+ if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
if (tdev->bus == s2io_pdev->bus->parent)
+ pci_dev_put(tdev);
return 1;
}
}
@@ -1214,7 +1227,7 @@ static int init_nic(struct s2io_nic *nic)
break;
}
- /* Enable Tx FIFO partition 0. */
+ /* Enable all configured Tx FIFO partitions */
val64 = readq(&bar0->tx_fifo_partition_0);
val64 |= (TX_FIFO_PARTITION_EN);
writeq(val64, &bar0->tx_fifo_partition_0);
@@ -1264,7 +1277,7 @@ static int init_nic(struct s2io_nic *nic)
writeq(val64, &bar0->rx_w_round_robin_1);
val64 = 0x0200010000010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001000001ULL;
+ val64 = 0x0001020001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
val64 = 0x0203000100000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
@@ -1651,7 +1664,7 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
writeq(temp64, &bar0->general_int_mask);
/*
* If Hercules adapter enable GPIO otherwise
- * disabled all PCIX, Flash, MDIO, IIC and GPIO
+ * disable all PCIX, Flash, MDIO, IIC and GPIO
* interrupts for now.
* TODO
*/
@@ -1977,7 +1990,6 @@ static int start_nic(struct s2io_nic *nic)
XENA_dev_config_t __iomem *bar0 = nic->bar0;
struct net_device *dev = nic->dev;
register u64 val64 = 0;
- u16 interruptible;
u16 subid, i;
mac_info_t *mac_control;
struct config_param *config;
@@ -2048,16 +2060,6 @@ static int start_nic(struct s2io_nic *nic)
return FAILURE;
}
- /* Enable select interrupts */
- if (nic->intr_type != INTA)
- en_dis_able_nic_intrs(nic, ENA_ALL_INTRS, DISABLE_INTRS);
- else {
- interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
- interruptible |= TX_PIC_INTR | RX_PIC_INTR;
- interruptible |= TX_MAC_INTR | RX_MAC_INTR;
- en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
- }
-
/*
* With some switches, link might be already up at this point.
* Because of this weird behavior, when we enable laser,
@@ -2126,12 +2128,12 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
skb_frag_t *frag = &skb_shinfo(skb)->frags[j];
if (!txds->Buffer_Pointer)
break;
- pci_unmap_page(nic->pdev, (dma_addr_t)
+ pci_unmap_page(nic->pdev, (dma_addr_t)
txds->Buffer_Pointer,
frag->size, PCI_DMA_TODEVICE);
}
}
- txdlp->Host_Control = 0;
+ memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
return(skb);
}
@@ -2383,25 +2385,33 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
skb->data = (void *) (unsigned long)tmp;
skb->tail = (void *) (unsigned long)tmp;
- ((RxD3_t*)rxdp)->Buffer0_ptr =
- pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
+ if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
+ ((RxD3_t*)rxdp)->Buffer0_ptr =
+ pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
PCI_DMA_FROMDEVICE);
+ else
+ pci_dma_sync_single_for_device(nic->pdev,
+ (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
if (nic->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
/*
- * Buffer2 will have L3/L4 header plus
+ * Buffer2 will have L3/L4 header plus
* L4 payload
*/
((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
(nic->pdev, skb->data, dev->mtu + 4,
PCI_DMA_FROMDEVICE);
- /* Buffer-1 will be dummy buffer not used */
- ((RxD3_t*)rxdp)->Buffer1_ptr =
- pci_map_single(nic->pdev, ba->ba_1, BUF1_LEN,
- PCI_DMA_FROMDEVICE);
+ /* Buffer-1 will be dummy buffer. Not used */
+ if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
+ ((RxD3_t*)rxdp)->Buffer1_ptr =
+ pci_map_single(nic->pdev,
+ ba->ba_1, BUF1_LEN,
+ PCI_DMA_FROMDEVICE);
+ }
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
(dev->mtu + 4);
@@ -2500,7 +2510,7 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
+ ((RxD3_t*)rxdp)->Buffer1_ptr,
l3l4hdr_size + 4,
PCI_DMA_FROMDEVICE);
pci_unmap_single(sp->pdev, (dma_addr_t)
@@ -2626,23 +2636,23 @@ no_rx:
}
#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
/**
- * s2io_netpoll - Rx interrupt service handler for netpoll support
+ * s2io_netpoll - netpoll event handler entry point
* @dev : pointer to the device structure.
* Description:
- * Polling 'interrupt' - used by things like netconsole to send skbs
- * without having to re-enable interrupts. It's not called while
- * the interrupt routine is executing.
+ * This function will be called by upper layer to check for events on the
+ * interface in situations where interrupts are disabled. It is used for
+ * specific in-kernel networking tasks, such as remote consoles and kernel
+ * debugging over the network (example netdump in RedHat).
*/
-
-#ifdef CONFIG_NET_POLL_CONTROLLER
static void s2io_netpoll(struct net_device *dev)
{
nic_t *nic = dev->priv;
mac_info_t *mac_control;
struct config_param *config;
XENA_dev_config_t __iomem *bar0 = nic->bar0;
- u64 val64;
+ u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
int i;
disable_irq(dev->irq);
@@ -2651,9 +2661,17 @@ static void s2io_netpoll(struct net_device *dev)
mac_control = &nic->mac_control;
config = &nic->config;
- val64 = readq(&bar0->rx_traffic_int);
writeq(val64, &bar0->rx_traffic_int);
+ writeq(val64, &bar0->tx_traffic_int);
+ /* we need to free up the transmitted skbufs or else netpoll will
+ * run out of skbs and will fail and eventually netpoll application such
+ * as netdump will fail.
+ */
+ for (i = 0; i < config->tx_fifo_num; i++)
+ tx_intr_handler(&mac_control->fifos[i]);
+
+ /* check for received packet and indicate up to network */
for (i = 0; i < config->rx_ring_num; i++)
rx_intr_handler(&mac_control->rings[i]);
@@ -2720,7 +2738,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
/* If your are next to put index then it's FIFO full condition */
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
- DBG_PRINT(ERR_DBG, "%s: Ring Full\n",dev->name);
+ DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
break;
}
skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
@@ -2740,18 +2758,15 @@ static void rx_intr_handler(ring_info_t *ring_data)
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
} else if (nic->rxd_mode == RXD_MODE_3B) {
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
((RxD3_t*)rxdp)->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
- ((RxD3_t*)rxdp)->Buffer1_ptr,
- BUF1_LEN, PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
((RxD3_t*)rxdp)->Buffer2_ptr,
dev->mtu + 4,
PCI_DMA_FROMDEVICE);
} else {
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
PCI_DMA_FROMDEVICE);
pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -2889,7 +2904,7 @@ static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device
{
u64 val64 = 0x0;
nic_t *sp = dev->priv;
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
//address transaction
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2938,7 +2953,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
u64 val64 = 0x0;
u64 rval64 = 0x0;
nic_t *sp = dev->priv;
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
/* address transaction */
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3195,7 +3210,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
if (val64 & SERR_SOURCE_ANY) {
nic->mac_control.stats_info->sw_stat.serious_err_cnt++;
DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
- DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
+ DBG_PRINT(ERR_DBG, "serious error %llx!!\n",
(unsigned long long)val64);
netif_stop_queue(dev);
schedule_work(&nic->rst_timer_task);
@@ -3261,7 +3276,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
* SUCCESS on success and FAILURE on failure.
*/
-static int wait_for_cmd_complete(void *addr, u64 busy_bit)
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
{
int ret = FAILURE, cnt = 0;
u64 val64;
@@ -3339,7 +3354,7 @@ static void s2io_reset(nic_t * sp)
/* Clear certain PCI/PCI-X fields after reset */
if (sp->device_type == XFRAME_II_DEVICE) {
- /* Clear parity err detect bit */
+ /* Clear "detected parity error" bit */
pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
/* Clearing PCIX Ecc status register */
@@ -3540,7 +3555,7 @@ static void restore_xmsi_data(nic_t *nic)
u64 val64;
int i;
- for (i=0; i< nic->avail_msix_vectors; i++) {
+ for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
writeq(nic->msix_info[i].addr, &bar0->xmsi_address);
writeq(nic->msix_info[i].data, &bar0->xmsi_data);
val64 = (BIT(7) | BIT(15) | vBIT(i, 26, 6));
@@ -3559,7 +3574,7 @@ static void store_xmsi_data(nic_t *nic)
int i;
/* Store and display */
- for (i=0; i< nic->avail_msix_vectors; i++) {
+ for (i=0; i < MAX_REQUESTED_MSI_X; i++) {
val64 = (BIT(15) | vBIT(i, 26, 6));
writeq(val64, &bar0->xmsi_access);
if (wait_for_msix_trans(nic, i)) {
@@ -3750,101 +3765,19 @@ static int s2io_open(struct net_device *dev)
if (err) {
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
dev->name);
- if (err == -ENODEV)
- goto hw_init_failed;
- else
- goto hw_enable_failed;
- }
-
- /* Store the values of the MSIX table in the nic_t structure */
- store_xmsi_data(sp);
-
- /* After proper initialization of H/W, register ISR */
- if (sp->intr_type == MSI) {
- err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
- SA_SHIRQ, sp->name, dev);
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: MSI registration \
-failed\n", dev->name);
- goto isr_registration_failed;
- }
- }
- if (sp->intr_type == MSI_X) {
- int i;
-
- for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
- if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
- sprintf(sp->desc1, "%s:MSI-X-%d-TX",
- dev->name, i);
- err = request_irq(sp->entries[i].vector,
- s2io_msix_fifo_handle, 0, sp->desc1,
- sp->s2io_entries[i].arg);
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc1,
- (unsigned long long)sp->msix_info[i].addr);
- } else {
- sprintf(sp->desc2, "%s:MSI-X-%d-RX",
- dev->name, i);
- err = request_irq(sp->entries[i].vector,
- s2io_msix_ring_handle, 0, sp->desc2,
- sp->s2io_entries[i].arg);
- DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc2,
- (unsigned long long)sp->msix_info[i].addr);
- }
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: MSI-X-%d registration \
-failed\n", dev->name, i);
- DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
- goto isr_registration_failed;
- }
- sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
- }
- }
- if (sp->intr_type == INTA) {
- err = request_irq((int) sp->pdev->irq, s2io_isr, SA_SHIRQ,
- sp->name, dev);
- if (err) {
- DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
- dev->name);
- goto isr_registration_failed;
- }
+ goto hw_init_failed;
}
if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) {
DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n");
+ s2io_card_down(sp);
err = -ENODEV;
- goto setting_mac_address_failed;
+ goto hw_init_failed;
}
netif_start_queue(dev);
return 0;
-setting_mac_address_failed:
- if (sp->intr_type != MSI_X)
- free_irq(sp->pdev->irq, dev);
-isr_registration_failed:
- del_timer_sync(&sp->alarm_timer);
- if (sp->intr_type == MSI_X) {
- int i;
- u16 msi_control; /* Temp variable */
-
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
-
- free_irq(vector, arg);
- }
- pci_disable_msix(sp->pdev);
-
- /* Temp */
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
- }
- else if (sp->intr_type == MSI)
- pci_disable_msi(sp->pdev);
-hw_enable_failed:
- s2io_reset(sp);
hw_init_failed:
if (sp->intr_type == MSI_X) {
if (sp->entries)
@@ -3875,7 +3808,7 @@ static int s2io_close(struct net_device *dev)
flush_scheduled_work();
netif_stop_queue(dev);
/* Reset card, kill tasklet and free Tx and Rx buffers. */
- s2io_card_down(sp, 1);
+ s2io_card_down(sp);
sp->device_close_flag = TRUE; /* Device is shut down. */
return 0;
@@ -3902,13 +3835,11 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
TxD_t *txdp;
TxFIFO_element_t __iomem *tx_fifo;
unsigned long flags;
-#ifdef NETIF_F_TSO
- int mss;
-#endif
u16 vlan_tag = 0;
int vlan_priority = 0;
mac_info_t *mac_control;
struct config_param *config;
+ int offload_type;
mac_control = &sp->mac_control;
config = &sp->config;
@@ -3956,16 +3887,14 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
- txdp->Control_1 = 0;
- txdp->Control_2 = 0;
+ offload_type = s2io_offload_type(skb);
#ifdef NETIF_F_TSO
- mss = skb_shinfo(skb)->gso_size;
- if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) {
+ if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
txdp->Control_1 |= TXD_TCP_LSO_EN;
- txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
+ txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
}
#endif
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
txdp->Control_2 |=
(TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
TXD_TX_CKO_UDP_EN);
@@ -3980,10 +3909,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
frg_len = skb->len - skb->data_len;
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) {
+ if (offload_type == SKB_GSO_UDP) {
int ufo_size;
- ufo_size = skb_shinfo(skb)->gso_size;
+ ufo_size = s2io_udp_mss(skb);
ufo_size &= ~7;
txdp->Control_1 |= TXD_UFO_EN;
txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
@@ -4000,16 +3929,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
sp->ufo_in_band_v,
sizeof(u64), PCI_DMA_TODEVICE);
txdp++;
- txdp->Control_1 = 0;
- txdp->Control_2 = 0;
}
txdp->Buffer_Pointer = pci_map_single
(sp->pdev, skb->data, frg_len, PCI_DMA_TODEVICE);
txdp->Host_Control = (unsigned long) skb;
txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
-
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+ if (offload_type == SKB_GSO_UDP)
txdp->Control_1 |= TXD_UFO_EN;
frg_cnt = skb_shinfo(skb)->nr_frags;
@@ -4024,12 +3950,12 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
(sp->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+ if (offload_type == SKB_GSO_UDP)
txdp->Control_1 |= TXD_UFO_EN;
}
txdp->Control_1 |= TXD_GATHER_CODE_LAST;
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+ if (offload_type == SKB_GSO_UDP)
frg_cnt++; /* as Txd0 was used for inband header */
tx_fifo = mac_control->tx_FIFO_start[queue];
@@ -4038,13 +3964,9 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
TX_FIFO_LAST_LIST);
-
-#ifdef NETIF_F_TSO
- if (mss)
- val64 |= TX_FIFO_SPECIAL_FUNC;
-#endif
- if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
+ if (offload_type)
val64 |= TX_FIFO_SPECIAL_FUNC;
+
writeq(val64, &tx_fifo->List_Control);
mmiowb();
@@ -4078,13 +4000,41 @@ s2io_alarm_handle(unsigned long data)
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
+static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+{
+ int rxb_size, level;
+
+ if (!sp->lro) {
+ rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
+ level = rx_buffer_level(sp, rxb_size, rng_n);
+
+ if ((level == PANIC) && (!TASKLET_IN_USE)) {
+ int ret;
+ DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
+ DBG_PRINT(INTR_DBG, "PANIC levels\n");
+ if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "Out of memory in %s",
+ __FUNCTION__);
+ clear_bit(0, (&sp->tasklet_status));
+ return -1;
+ }
+ clear_bit(0, (&sp->tasklet_status));
+ } else if (level == LOW)
+ tasklet_schedule(&sp->task);
+
+ } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
+ DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name);
+ DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
+ }
+ return 0;
+}
+
static irqreturn_t
s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = (struct net_device *) dev_id;
nic_t *sp = dev->priv;
int i;
- int ret;
mac_info_t *mac_control;
struct config_param *config;
@@ -4106,35 +4056,8 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
* reallocate the buffers from the interrupt handler itself,
* else schedule a tasklet to reallocate the buffers.
*/
- for (i = 0; i < config->rx_ring_num; i++) {
- if (!sp->lro) {
- int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
- int level = rx_buffer_level(sp, rxb_size, i);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
- dev->name);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in ISR!!\n");
- clear_bit(0, (&sp->tasklet_status));
- atomic_dec(&sp->isr_cnt);
- return IRQ_HANDLED;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW) {
- tasklet_schedule(&sp->task);
- }
- }
- else if (fill_rx_buffers(sp, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
- break;
- }
- }
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
atomic_dec(&sp->isr_cnt);
return IRQ_HANDLED;
@@ -4145,39 +4068,13 @@ s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
{
ring_info_t *ring = (ring_info_t *)dev_id;
nic_t *sp = ring->nic;
- struct net_device *dev = (struct net_device *) dev_id;
- int rxb_size, level, rng_n;
atomic_inc(&sp->isr_cnt);
- rx_intr_handler(ring);
- rng_n = ring->ring_no;
- if (!sp->lro) {
- rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
- level = rx_buffer_level(sp, rxb_size, rng_n);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- int ret;
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "Out of memory in %s",
- __FUNCTION__);
- clear_bit(0, (&sp->tasklet_status));
- return IRQ_HANDLED;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW) {
- tasklet_schedule(&sp->task);
- }
- }
- else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
- DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
- }
+ rx_intr_handler(ring);
+ s2io_chk_rx_buffers(sp, ring->ring_no);
atomic_dec(&sp->isr_cnt);
-
return IRQ_HANDLED;
}
@@ -4342,37 +4239,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
* else schedule a tasklet to reallocate the buffers.
*/
#ifndef CONFIG_S2IO_NAPI
- for (i = 0; i < config->rx_ring_num; i++) {
- if (!sp->lro) {
- int ret;
- int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
- int level = rx_buffer_level(sp, rxb_size, i);
-
- if ((level == PANIC) && (!TASKLET_IN_USE)) {
- DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
- dev->name);
- DBG_PRINT(INTR_DBG, "PANIC levels\n");
- if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in ISR!!\n");
- clear_bit(0, (&sp->tasklet_status));
- atomic_dec(&sp->isr_cnt);
- writeq(org_mask, &bar0->general_int_mask);
- return IRQ_HANDLED;
- }
- clear_bit(0, (&sp->tasklet_status));
- } else if (level == LOW) {
- tasklet_schedule(&sp->task);
- }
- }
- else if (fill_rx_buffers(sp, i) == -ENOMEM) {
- DBG_PRINT(ERR_DBG, "%s:Out of memory",
- dev->name);
- DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
- break;
- }
- }
+ for (i = 0; i < config->rx_ring_num; i++)
+ s2io_chk_rx_buffers(sp, i);
#endif
writeq(org_mask, &bar0->general_int_mask);
atomic_dec(&sp->isr_cnt);
@@ -4402,6 +4270,8 @@ static void s2io_updt_stats(nic_t *sp)
if (cnt == 5)
break; /* Updt failed */
} while(1);
+ } else {
+ memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
}
}
@@ -4433,11 +4303,11 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
sp->stats.tx_errors =
le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
sp->stats.rx_errors =
- le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
+ le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
sp->stats.multicast =
le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
sp->stats.rx_length_errors =
- le32_to_cpu(mac_control->stats_info->rmac_long_frms);
+ le64_to_cpu(mac_control->stats_info->rmac_long_frms);
return (&sp->stats);
}
@@ -4947,7 +4817,7 @@ static int read_eeprom(nic_t * sp, int off, u64 * data)
if (sp->device_type == XFRAME_II_DEVICE) {
val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
- SPI_CONTROL_BYTECNT(0x3) |
+ SPI_CONTROL_BYTECNT(0x3) |
SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off);
SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
val64 |= SPI_CONTROL_REQ;
@@ -5014,7 +4884,7 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
writeq(SPI_DATA_WRITE(data,(cnt<<3)), &bar0->spi_data);
val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 |
- SPI_CONTROL_BYTECNT(write_cnt) |
+ SPI_CONTROL_BYTECNT(write_cnt) |
SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off);
SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF);
val64 |= SPI_CONTROL_REQ;
@@ -5036,7 +4906,8 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
}
static void s2io_vpd_read(nic_t *nic)
{
- u8 vpd_data[256],data;
+ u8 *vpd_data;
+ u8 data;
int i=0, cnt, fail = 0;
int vpd_addr = 0x80;
@@ -5049,6 +4920,10 @@ static void s2io_vpd_read(nic_t *nic)
vpd_addr = 0x50;
}
+ vpd_data = kmalloc(256, GFP_KERNEL);
+ if (!vpd_data)
+ return;
+
for (i = 0; i < 256; i +=4 ) {
pci_write_config_byte(nic->pdev, (vpd_addr + 2), i);
pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data);
@@ -5071,6 +4946,7 @@ static void s2io_vpd_read(nic_t *nic)
memset(nic->product_name, 0, vpd_data[1]);
memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
}
+ kfree(vpd_data);
}
/**
@@ -5389,7 +5265,7 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
else
*data = 0;
- return 0;
+ return *data;
}
/**
@@ -5771,7 +5647,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
if (stat_info->sw_stat.num_aggregations) {
u64 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
int count = 0;
- /*
+ /*
* Since 64-bit divide does not work on all platforms,
* do repeated subtraction.
*/
@@ -5847,8 +5723,21 @@ static int s2io_ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
return 0;
}
+static u32 s2io_ethtool_op_get_tso(struct net_device *dev)
+{
+ return (dev->features & NETIF_F_TSO) != 0;
+}
+static int s2io_ethtool_op_set_tso(struct net_device *dev, u32 data)
+{
+ if (data)
+ dev->features |= (NETIF_F_TSO | NETIF_F_TSO6);
+ else
+ dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+
+ return 0;
+}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_settings = s2io_ethtool_gset,
.set_settings = s2io_ethtool_sset,
.get_drvinfo = s2io_ethtool_gdrvinfo,
@@ -5867,8 +5756,8 @@ static struct ethtool_ops netdev_ethtool_ops = {
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
#ifdef NETIF_F_TSO
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .get_tso = s2io_ethtool_op_get_tso,
+ .set_tso = s2io_ethtool_op_set_tso,
#endif
.get_ufo = ethtool_op_get_ufo,
.set_ufo = ethtool_op_set_ufo,
@@ -5920,7 +5809,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
dev->mtu = new_mtu;
if (netif_running(dev)) {
- s2io_card_down(sp, 0);
+ s2io_card_down(sp);
netif_stop_queue(dev);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
@@ -6217,43 +6106,106 @@ static int rxd_owner_bit_reset(nic_t *sp)
}
-static void s2io_card_down(nic_t * sp, int flag)
+static int s2io_add_isr(nic_t * sp)
{
- int cnt = 0;
- XENA_dev_config_t __iomem *bar0 = sp->bar0;
- unsigned long flags;
- register u64 val64 = 0;
+ int ret = 0;
struct net_device *dev = sp->dev;
+ int err = 0;
- del_timer_sync(&sp->alarm_timer);
- /* If s2io_set_link task is executing, wait till it completes. */
- while (test_and_set_bit(0, &(sp->link_state))) {
- msleep(50);
+ if (sp->intr_type == MSI)
+ ret = s2io_enable_msi(sp);
+ else if (sp->intr_type == MSI_X)
+ ret = s2io_enable_msi_x(sp);
+ if (ret) {
+ DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
+ sp->intr_type = INTA;
}
- atomic_set(&sp->card_state, CARD_DOWN);
- /* disable Tx and Rx traffic on the NIC */
- stop_nic(sp);
- if (flag) {
- if (sp->intr_type == MSI_X) {
- int i;
- u16 msi_control;
+ /* Store the values of the MSIX table in the nic_t structure */
+ store_xmsi_data(sp);
- for (i=1; (sp->s2io_entries[i].in_use ==
- MSIX_REGISTERED_SUCCESS); i++) {
- int vector = sp->entries[i].vector;
- void *arg = sp->s2io_entries[i].arg;
+ /* After proper initialization of H/W, register ISR */
+ if (sp->intr_type == MSI) {
+ err = request_irq((int) sp->pdev->irq, s2io_msi_handle,
+ IRQF_SHARED, sp->name, dev);
+ if (err) {
+ pci_disable_msi(sp->pdev);
+ DBG_PRINT(ERR_DBG, "%s: MSI registration failed\n",
+ dev->name);
+ return -1;
+ }
+ }
+ if (sp->intr_type == MSI_X) {
+ int i;
- free_irq(vector, arg);
+ for (i=1; (sp->s2io_entries[i].in_use == MSIX_FLG); i++) {
+ if (sp->s2io_entries[i].type == MSIX_FIFO_TYPE) {
+ sprintf(sp->desc[i], "%s:MSI-X-%d-TX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_fifo_handle, 0, sp->desc[i],
+ sp->s2io_entries[i].arg);
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
+ (unsigned long long)sp->msix_info[i].addr);
+ } else {
+ sprintf(sp->desc[i], "%s:MSI-X-%d-RX",
+ dev->name, i);
+ err = request_irq(sp->entries[i].vector,
+ s2io_msix_ring_handle, 0, sp->desc[i],
+ sp->s2io_entries[i].arg);
+ DBG_PRINT(ERR_DBG, "%s @ 0x%llx\n", sp->desc[i],
+ (unsigned long long)sp->msix_info[i].addr);
}
- pci_read_config_word(sp->pdev, 0x42, &msi_control);
- msi_control &= 0xFFFE; /* Disable MSI */
- pci_write_config_word(sp->pdev, 0x42, msi_control);
- pci_disable_msix(sp->pdev);
- } else {
- free_irq(sp->pdev->irq, dev);
- if (sp->intr_type == MSI)
- pci_disable_msi(sp->pdev);
+ if (err) {
+ DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
+ "failed\n", dev->name, i);
+ DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
+ return -1;
+ }
+ sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
+ }
+ }
+ if (sp->intr_type == INTA) {
+ err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
+ sp->name, dev);
+ if (err) {
+ DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n",
+ dev->name);
+ return -1;
+ }
+ }
+ return 0;
+}
+static void s2io_rem_isr(nic_t * sp)
+{
+ int cnt = 0;
+ struct net_device *dev = sp->dev;
+
+ if (sp->intr_type == MSI_X) {
+ int i;
+ u16 msi_control;
+
+ for (i=1; (sp->s2io_entries[i].in_use ==
+ MSIX_REGISTERED_SUCCESS); i++) {
+ int vector = sp->entries[i].vector;
+ void *arg = sp->s2io_entries[i].arg;
+
+ free_irq(vector, arg);
+ }
+ pci_read_config_word(sp->pdev, 0x42, &msi_control);
+ msi_control &= 0xFFFE; /* Disable MSI */
+ pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+ pci_disable_msix(sp->pdev);
+ } else {
+ free_irq(sp->pdev->irq, dev);
+ if (sp->intr_type == MSI) {
+ u16 val;
+
+ pci_disable_msi(sp->pdev);
+ pci_read_config_word(sp->pdev, 0x4c, &val);
+ val ^= 0x1;
+ pci_write_config_word(sp->pdev, 0x4c, val);
}
}
/* Waiting till all Interrupt handlers are complete */
@@ -6264,6 +6216,26 @@ static void s2io_card_down(nic_t * sp, int flag)
break;
cnt++;
} while(cnt < 5);
+}
+
+static void s2io_card_down(nic_t * sp)
+{
+ int cnt = 0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
+ unsigned long flags;
+ register u64 val64 = 0;
+
+ del_timer_sync(&sp->alarm_timer);
+ /* If s2io_set_link task is executing, wait till it completes. */
+ while (test_and_set_bit(0, &(sp->link_state))) {
+ msleep(50);
+ }
+ atomic_set(&sp->card_state, CARD_DOWN);
+
+ /* disable Tx and Rx traffic on the NIC */
+ stop_nic(sp);
+
+ s2io_rem_isr(sp);
/* Kill tasklet. */
tasklet_kill(&sp->task);
@@ -6315,23 +6287,16 @@ static int s2io_card_up(nic_t * sp)
mac_info_t *mac_control;
struct config_param *config;
struct net_device *dev = (struct net_device *) sp->dev;
+ u16 interruptible;
/* Initialize the H/W I/O registers */
if (init_nic(sp) != 0) {
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
dev->name);
+ s2io_reset(sp);
return -ENODEV;
}
- if (sp->intr_type == MSI)
- ret = s2io_enable_msi(sp);
- else if (sp->intr_type == MSI_X)
- ret = s2io_enable_msi_x(sp);
- if (ret) {
- DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
- sp->intr_type = INTA;
- }
-
/*
* Initializing the Rx buffers. For now we are considering only 1
* Rx ring and initializing buffers into 30 Rx blocks
@@ -6355,28 +6320,46 @@ static int s2io_card_up(nic_t * sp)
s2io_set_multicast(dev);
if (sp->lro) {
- /* Initialize max aggregatable pkts based on MTU */
+ /* Initialize max aggregatable pkts per session based on MTU */
sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
/* Check if we can use(if specified) user provided value */
if (lro_max_pkts < sp->lro_max_aggr_per_sess)
sp->lro_max_aggr_per_sess = lro_max_pkts;
}
- /* Enable tasklet for the device */
- tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
-
/* Enable Rx Traffic and interrupts on the NIC */
if (start_nic(sp)) {
DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
- tasklet_kill(&sp->task);
s2io_reset(sp);
- free_irq(dev->irq, dev);
+ free_rx_buffers(sp);
+ return -ENODEV;
+ }
+
+ /* Add interrupt service routine */
+ if (s2io_add_isr(sp) != 0) {
+ if (sp->intr_type == MSI_X)
+ s2io_rem_isr(sp);
+ s2io_reset(sp);
free_rx_buffers(sp);
return -ENODEV;
}
S2IO_TIMER_CONF(sp->alarm_timer, s2io_alarm_handle, sp, (HZ/2));
+ /* Enable tasklet for the device */
+ tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
+
+ /* Enable select interrupts */
+ if (sp->intr_type != INTA)
+ en_dis_able_nic_intrs(sp, ENA_ALL_INTRS, DISABLE_INTRS);
+ else {
+ interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+ interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+ interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+ en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS);
+ }
+
+
atomic_set(&sp->card_state, CARD_UP);
return 0;
}
@@ -6396,7 +6379,7 @@ static void s2io_restart_nic(unsigned long data)
struct net_device *dev = (struct net_device *) data;
nic_t *sp = dev->priv;
- s2io_card_down(sp, 0);
+ s2io_card_down(sp);
if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
dev->name);
@@ -6438,7 +6421,7 @@ static void s2io_tx_watchdog(struct net_device *dev)
* @cksum : FCS checksum of the frame.
* @ring_no : the ring from which this RxD was extracted.
* Description:
- * This function is called by the Tx interrupt serivce routine to perform
+ * This function is called by the Rx interrupt serivce routine to perform
* some OS related operations on the SKB before passing it to the upper
* layers. It mainly checks if the checksum is OK, if so adds it to the
* SKBs cksum variable, increments the Rx packet count and passes the SKB
@@ -6615,7 +6598,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
} else {
send_up:
queue_rx_frame(skb);
- }
+ }
dev->last_rx = jiffies;
aggregate:
atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -6698,33 +6681,6 @@ static void s2io_init_pci(nic_t * sp)
pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
}
-MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-module_param(tx_fifo_num, int, 0);
-module_param(rx_ring_num, int, 0);
-module_param(rx_ring_mode, int, 0);
-module_param_array(tx_fifo_len, uint, NULL, 0);
-module_param_array(rx_ring_sz, uint, NULL, 0);
-module_param_array(rts_frm_len, uint, NULL, 0);
-module_param(use_continuous_tx_intrs, int, 1);
-module_param(rmac_pause_time, int, 0);
-module_param(mc_pause_threshold_q0q3, int, 0);
-module_param(mc_pause_threshold_q4q7, int, 0);
-module_param(shared_splits, int, 0);
-module_param(tmac_util_period, int, 0);
-module_param(rmac_util_period, int, 0);
-module_param(bimodal, bool, 0);
-module_param(l3l4hdr_size, int , 0);
-#ifndef CONFIG_S2IO_NAPI
-module_param(indicate_max_pkts, int, 0);
-#endif
-module_param(rxsync_frequency, int, 0);
-module_param(intr_type, int, 0);
-module_param(lro, int, 0);
-module_param(lro_max_pkts, int, 0);
-
static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
{
if ( tx_fifo_num > 8) {
@@ -6762,7 +6718,7 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
if ((*dev_intr_type == MSI_X) &&
((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
(pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
- DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
+ DBG_PRINT(ERR_DBG, "s2io: Xframe I does not support MSI_X. "
"Defaulting to INTA\n");
*dev_intr_type = INTA;
}
@@ -6832,8 +6788,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
}
if (dev_intr_type != MSI_X) {
if (pci_request_regions(pdev, s2io_driver_name)) {
- DBG_PRINT(ERR_DBG, "Request Regions failed\n"),
- pci_disable_device(pdev);
+ DBG_PRINT(ERR_DBG, "Request Regions failed\n");
+ pci_disable_device(pdev);
return -ENODEV;
}
}
@@ -6890,7 +6846,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
sp->device_type = XFRAME_I_DEVICE;
sp->lro = lro;
-
+
/* Initialize some PCI/PCI-X fields of the NIC. */
s2io_init_pci(sp);
@@ -6957,7 +6913,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
/* initialize the shared memory used by the NIC and the host */
if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
- __FUNCTION__);
+ dev->name);
ret = -ENOMEM;
goto mem_alloc_failed;
}
@@ -7021,6 +6977,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
#ifdef NETIF_F_TSO
dev->features |= NETIF_F_TSO;
#endif
+#ifdef NETIF_F_TSO6
+ dev->features |= NETIF_F_TSO6;
+#endif
if (sp->device_type & XFRAME_II_DEVICE) {
dev->features |= NETIF_F_UFO;
dev->features |= NETIF_F_HW_CSUM;
@@ -7091,6 +7050,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
dev->addr_len = ETH_ALEN;
memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN);
+ /* reset Nic and bring it to known state */
+ s2io_reset(sp);
+
/*
* Initialize the tasklet status and link state flags
* and the card state parameter
@@ -7128,11 +7090,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
goto register_failed;
}
s2io_vpd_read(sp);
- DBG_PRINT(ERR_DBG, "%s: Neterion %s",dev->name, sp->product_name);
- DBG_PRINT(ERR_DBG, "(rev %d), Driver version %s\n",
- get_xena_rev_id(sp->pdev),
- s2io_driver_version);
DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n");
+ DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name,
+ sp->product_name, get_xena_rev_id(sp->pdev));
+ DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
+ s2io_driver_version);
DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
"%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
sp->def_mac_addr[0].mac_addr[0],
@@ -7272,7 +7234,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
int __init s2io_starter(void)
{
- return pci_module_init(&s2io_driver);
+ return pci_register_driver(&s2io_driver);
}
/**
@@ -7289,7 +7251,7 @@ static void s2io_closer(void)
module_init(s2io_starter);
module_exit(s2io_closer);
-static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
+static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
struct tcphdr **tcp, RxD_t *rxdp)
{
int ip_off;
@@ -7351,7 +7313,7 @@ static void initiate_new_session(lro_t *lro, u8 *l2h,
lro->sg_num = 1;
lro->total_len = ntohs(ip->tot_len);
lro->frags_len = 0;
- /*
+ /*
* check if we saw TCP timestamp. Other consistency checks have
* already been done.
*/
@@ -7408,12 +7370,12 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
/* Update ack seq no. and window ad(from this pkt) in LRO object */
lro->tcp_ack = tcp->ack_seq;
lro->window = tcp->window;
-
+
if (lro->saw_ts) {
u32 *ptr;
/* Update tsecr and tsval from this packet */
ptr = (u32 *) (tcp + 1);
- lro->cur_tsval = *(ptr + 1);
+ lro->cur_tsval = *(ptr + 1);
lro->cur_tsecr = *(ptr + 2);
}
}
@@ -7433,8 +7395,13 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
if (ip->ihl != 5) /* IP has options */
return -1;
+ /* If we see CE codepoint in IP header, packet is not mergeable */
+ if (INET_ECN_is_ce(ipv4_get_dsfield(ip)))
+ return -1;
+
+ /* If we see ECE or CWR flags in TCP header, packet is not mergeable */
if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
- !tcp->ack) {
+ tcp->ece || tcp->cwr || !tcp->ack) {
/*
* Currently recognize only the ack control word and
* any other control field being set would result in
@@ -7443,7 +7410,7 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
return -1;
}
- /*
+ /*
* Allow only one TCP timestamp option. Don't aggregate if
* any other options are detected.
*/
@@ -7451,7 +7418,7 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
return -1;
if (tcp->doff == 8) {
- ptr = (u8 *)(tcp + 1);
+ ptr = (u8 *)(tcp + 1);
while (*ptr == TCPOPT_NOP)
ptr++;
if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
@@ -7463,7 +7430,7 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
return -1;
/* timestamp echo reply should be non-zero */
- if (*((u32 *)(ptr+6)) == 0)
+ if (*((u32 *)(ptr+6)) == 0)
return -1;
}
@@ -7588,18 +7555,16 @@ static void queue_rx_frame(struct sk_buff *skb)
static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
u32 tcp_len)
{
- struct sk_buff *tmp, *first = lro->parent;
+ struct sk_buff *first = lro->parent;
first->len += tcp_len;
first->data_len = lro->frags_len;
skb_pull(skb, (skb->len - tcp_len));
- if ((tmp = skb_shinfo(first)->frag_list)) {
- while (tmp->next)
- tmp = tmp->next;
- tmp->next = skb;
- }
+ if (skb_shinfo(first)->frag_list)
+ lro->last_frag->next = skb;
else
skb_shinfo(first)->frag_list = skb;
+ lro->last_frag = skb;
sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
return;
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3203732a668..3afd9126a59 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -652,7 +652,7 @@ typedef struct fifo_info {
nic_t *nic;
}fifo_info_t;
-/* Infomation related to the Tx and Rx FIFOs and Rings of Xena
+/* Information related to the Tx and Rx FIFOs and Rings of Xena
* is maintained in this structure.
*/
typedef struct mac_info {
@@ -719,6 +719,7 @@ struct msix_info_st {
/* Data structure to represent a LRO session */
typedef struct lro {
struct sk_buff *parent;
+ struct sk_buff *last_frag;
u8 *l2h;
struct iphdr *iph;
struct tcphdr *tcph;
@@ -829,8 +830,7 @@ struct s2io_nic {
#define MSIX_FLG 0xA5
struct msix_entry *entries;
struct s2io_msix_entry *s2io_entries;
- char desc1[35];
- char desc2[35];
+ char desc[MAX_REQUESTED_MSI_X][25];
int avail_msix_vectors; /* No. of MSI-X vectors granted by system */
@@ -883,10 +883,10 @@ static inline void writeq(u64 val, void __iomem *addr)
}
#endif
-/*
- * Some registers have to be written in a particular order to
- * expect correct hardware operation. The macro SPECIAL_REG_WRITE
- * is used to perform such ordered writes. Defines UF (Upper First)
+/*
+ * Some registers have to be written in a particular order to
+ * expect correct hardware operation. The macro SPECIAL_REG_WRITE
+ * is used to perform such ordered writes. Defines UF (Upper First)
* and LF (Lower First) will be used to specify the required write order.
*/
#define UF 1
@@ -999,10 +999,10 @@ static irqreturn_t
s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(unsigned long data);
static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic, int flag);
+static void s2io_card_down(nic_t *nic);
static int s2io_card_up(nic_t *nic);
static int get_xena_rev_id(struct pci_dev *pdev);
static void restore_xmsi_data(nic_t *nic);
@@ -1012,4 +1012,13 @@ static void clear_lro_session(lro_t *lro);
static void queue_rx_frame(struct sk_buff *skb);
static void update_L3L4_header(nic_t *sp, lro_t *lro);
static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
+
+#define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
+#define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
+#define s2io_offload_type(skb) skb_shinfo(skb)->gso_type
+
+#define S2IO_PARM_INT(X, def_val) \
+ static unsigned int X = def_val;\
+ module_param(X , uint, 0);
+
#endif /* _S2IO_H */
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index b2acedbefa8..c479b07be78 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -1131,7 +1131,7 @@ static struct pci_driver saa9730_driver = {
static int __init saa9730_init(void)
{
- return pci_module_init(&saa9730_driver);
+ return pci_register_driver(&saa9730_driver);
}
static void __exit saa9730_cleanup(void)
diff --git a/drivers/net/saa9730.h b/drivers/net/saa9730.h
index a7e9d29a86a..f656f2f40bb 100644
--- a/drivers/net/saa9730.h
+++ b/drivers/net/saa9730.h
@@ -34,9 +34,9 @@
/* TX and RX packet size: fixed to 2048 bytes, according to HW requirements. */
#define LAN_SAA9730_PACKET_SIZE 2048
-/*
- * Number of TX buffers = number of RX buffers = 2, which is fixed according
- * to HW requirements.
+/*
+ * Number of TX buffers = number of RX buffers = 2, which is fixed according
+ * to HW requirements.
*/
#define LAN_SAA9730_BUFFERS 2
@@ -47,10 +47,10 @@
#define LAN_SAA9730_TXM_Q_SIZE 15
/*
- * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
- * packets received.
+ * We get an interrupt for each LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
+ * packets received.
* If however we receive less than LAN_SAA9730_DEFAULT_RCV_Q_INT_THRESHOLD
- * packets, the hardware can timeout after a certain time and still tell
+ * packets, the hardware can timeout after a certain time and still tell
* us packets have arrived.
* The timeout value in unit of 32 PCI clocks (33Mhz).
* The value 200 approximates 0.0002 seconds.
@@ -79,8 +79,8 @@
#define MACCM_10MB 1
#define MACCM_MII 2
-/*
- * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board)
+/*
+ * PHY definitions for Basic registers of QS6612 (used on MIPS ATLAS board)
*/
#define PHY_CONTROL 0x0
#define PHY_STATUS 0x1
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index 66cf226c4ee..a1789ae5927 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -28,7 +28,7 @@
Small changes to make it work with 2.1.x kernels. Hopefully,
nothing major will change before official release of Linux 2.2.
-
+
Merged with 2.2 - Alan Cox
*/
@@ -143,7 +143,7 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
unsigned short ioaddr[2], irq;
unsigned int serial_number;
int error = -ENODEV;
-
+
if (pnp_device_attach(pdev) < 0)
return -ENODEV;
if (pnp_activate_dev(pdev) < 0)
@@ -153,12 +153,12 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
goto out_disable;
if (!pnp_irq_valid(pdev, 0))
goto out_disable;
-
+
serial_number = pdev->card->serial;
-
+
ioaddr[0] = pnp_port_start(pdev, 0);
ioaddr[1] = pnp_port_start(pdev, 0);
-
+
irq = pnp_irq(pdev, 0);
if (!request_region(ioaddr[0], 16, "sb1000"))
@@ -172,7 +172,7 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
goto out_release_regions;
}
-
+
dev->base_addr = ioaddr[0];
/* mem_start holds the second I/O address */
dev->mem_start = ioaddr[1];
@@ -246,7 +246,7 @@ static struct pnp_driver sb1000_driver = {
.remove = sb1000_remove_one,
};
-
+
/*
* SB1000 hardware routines to be used during open/configuration phases
*/
@@ -351,7 +351,7 @@ card_send_command(const int ioaddr[], const char* name,
return 0;
}
-
+
/*
* SB1000 hardware routines to be used during frame rx interrupt
*/
@@ -449,7 +449,7 @@ sb1000_issue_read_command(const int ioaddr[], const char* name)
return;
}
-
+
/*
* SB1000 commands for open/configuration
*/
@@ -697,7 +697,7 @@ sb1000_set_PIDs(const int ioaddr[], const char* name, const short PID[])
return sb1000_end_get_set_command(ioaddr, name);
}
-
+
static inline void
sb1000_print_status_buffer(const char* name, unsigned char st[],
unsigned char buffer[], int size)
@@ -916,7 +916,7 @@ sb1000_error_dpc(struct net_device *dev)
return;
}
-
+
/*
* Linux interface functions
*/
@@ -1155,7 +1155,7 @@ static int sb1000_close(struct net_device *dev)
printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name);
netif_stop_queue(dev);
-
+
ioaddr[0] = dev->base_addr;
/* mem_start holds the second I/O address */
ioaddr[1] = dev->mem_start;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index f2be9f83f09..e4c8896b76c 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -31,7 +31,6 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/bitops.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/io.h>
@@ -2451,7 +2450,7 @@ static int sbmac_open(struct net_device *dev)
*/
__raw_readq(sc->sbm_isr);
- if (request_irq(dev->irq, &sbmac_intr, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, &sbmac_intr, IRQF_SHARED, dev->name, dev))
return -EBUSY;
/*
@@ -2709,7 +2708,6 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev)
static void sbmac_set_rx_mode(struct net_device *dev)
{
unsigned long flags;
- int msg_flag = 0;
struct sbmac_softc *sc = netdev_priv(dev);
spin_lock_irqsave(&sc->sbm_lock, flags);
@@ -2719,22 +2717,14 @@ static void sbmac_set_rx_mode(struct net_device *dev)
*/
if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- msg_flag = 1;
sbmac_promiscuous_mode(sc,1);
}
else {
- msg_flag = 2;
sbmac_promiscuous_mode(sc,0);
}
}
spin_unlock_irqrestore(&sc->sbm_lock, flags);
- if (msg_flag) {
- printk(KERN_NOTICE "%s: Promiscuous mode %sabled.\n",
- dev->name,(msg_flag==1)?"en":"dis");
- }
-
/*
* Program the multicasts. Do this every time.
*/
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index efd0f235020..20afdc7f2b9 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -20,7 +20,7 @@ static const char version[] =
/*
Sources:
SEEQ 8005 databook
-
+
Version history:
1.00 Public release. cosmetic changes (no warnings now)
0.68 Turning per- packet,interrupt debug messages off - testing for release.
@@ -95,7 +95,7 @@ static void hardware_send_packet(struct net_device *dev, char *buf, int length);
extern void seeq8005_init(struct net_device *dev, int startp);
static inline void wait_for_buffer(struct net_device *dev);
-
+
/* Check for a network adaptor of this type, and return '0' iff one exists.
If dev->base_addr == 0, probe all likely locations.
If dev->base_addr == 1, always return failure.
@@ -196,11 +196,11 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
retval = -ENODEV;
goto out;
}
-
+
old_cfg2 = inw(SEEQ_CFG2); /* read CFG2 register */
old_cfg1 = inw(SEEQ_CFG1);
old_dmaar = inw(SEEQ_DMAAR);
-
+
if (net_debug>4) {
printk("seeq8005: stat = 0x%04x\n",old_stat);
printk("seeq8005: cfg1 = 0x%04x\n",old_cfg1);
@@ -208,7 +208,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
printk("seeq8005: raer = 0x%04x\n",old_rear);
printk("seeq8005: dmaar= 0x%04x\n",old_dmaar);
}
-
+
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD); /* setup for reading PROM */
outw( 0, SEEQ_DMAAR); /* set starting PROM address */
outw( SEEQCFG1_BUFFER_PROM, SEEQ_CFG1); /* set buffer to look at PROM */
@@ -236,7 +236,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
outw( SEEQCFG2_RESET, SEEQ_CFG2); /* reset the card */
udelay(5);
outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
-
+
if (net_debug) {
printk("seeq8005: prom sum = 0x%08x\n",j);
for(j=0; j<32; j+=16) {
@@ -256,10 +256,10 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
}
}
-#if 0
- /*
+#if 0
+ /*
* testing the packet buffer memory doesn't work yet
- * but all other buffer accesses do
+ * but all other buffer accesses do
* - fixing is not a priority
*/
if (net_debug>1) { /* test packet buffer memory */
@@ -309,16 +309,16 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr)
; /* Do nothing: a user-level program will set it. */
else if (dev->irq < 2) { /* "Auto-IRQ" */
unsigned long cookie = probe_irq_on();
-
+
outw( SEEQCMD_RX_INT_EN | SEEQCMD_SET_RX_ON | SEEQCMD_SET_RX_OFF, SEEQ_CMD );
dev->irq = probe_irq_off(cookie);
-
+
if (net_debug >= 2)
printk(" autoirq is %d\n", dev->irq);
} else if (dev->irq == 2)
/* Fixup for users that don't know that IRQ 2 is really IRQ 9,
- * or don't know which one to set.
+ * or don't know which one to set.
*/
dev->irq = 9;
@@ -348,7 +348,7 @@ out:
return retval;
}
-
+
/* Open/initialize the board. This is called (in the current kernel)
sometime after booting when the 'ifconfig' program is run.
@@ -404,8 +404,8 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
/* Block a timer-based transmit from overlapping */
netif_stop_queue(dev);
-
- hardware_send_packet(dev, buf, length);
+
+ hardware_send_packet(dev, buf, length);
dev->trans_start = jiffies;
lp->stats.tx_bytes += length;
dev_kfree_skb (skb);
@@ -413,7 +413,7 @@ static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0;
}
-
+
/*
* wait_for_buffer
*
@@ -426,15 +426,15 @@ inline void wait_for_buffer(struct net_device * dev)
int ioaddr = dev->base_addr;
unsigned long tmp;
int status;
-
+
tmp = jiffies + HZ;
while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
cpu_relax();
-
+
if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
}
-
+
/* The typical workload of the driver:
Handle the network interface interrupts. */
static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
@@ -452,7 +452,7 @@ static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * re
if (net_debug >2) {
printk("%s: int, status=0x%04x\n",dev->name,status);
}
-
+
if (status & SEEQSTAT_WINDOW_INT) {
handled = 1;
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
@@ -500,32 +500,32 @@ static void seeq8005_rx(struct net_device *dev)
wait_for_buffer(dev);
next_packet = ntohs(inw(SEEQ_BUFFER));
pkt_hdr = inw(SEEQ_BUFFER);
-
+
if (net_debug>2) {
printk("%s: 0x%04x recv next=0x%04x, hdr=0x%04x\n",dev->name,lp->receive_ptr,next_packet,pkt_hdr);
}
-
+
if ((next_packet == 0) || ((pkt_hdr & SEEQPKTH_CHAIN)==0)) { /* Read all the frames? */
return; /* Done for now */
}
-
+
if ((pkt_hdr & SEEQPKTS_DONE)==0)
break;
-
+
if (next_packet < lp->receive_ptr) {
pkt_len = (next_packet + 0x10000 - ((DEFAULT_TEA+1)<<8)) - lp->receive_ptr - 4;
} else {
pkt_len = next_packet - lp->receive_ptr - 4;
}
-
+
if (next_packet < ((DEFAULT_TEA+1)<<8)) { /* is the next_packet address sane? */
printk("%s: recv packet ring corrupt, resetting board\n",dev->name);
seeq8005_init(dev,1);
return;
}
-
+
lp->receive_ptr = next_packet;
-
+
if (net_debug>2) {
printk("%s: recv len=0x%04x\n",dev->name,pkt_len);
}
@@ -553,9 +553,9 @@ static void seeq8005_rx(struct net_device *dev)
skb->dev = dev;
skb_reserve(skb, 2); /* align data on 16 byte */
buf = skb_put(skb,pkt_len);
-
+
insw(SEEQ_BUFFER, buf, (pkt_len + 1) >> 1);
-
+
if (net_debug>2) {
char * p = buf;
printk("%s: recv ",dev->name);
@@ -588,7 +588,7 @@ static int seeq8005_close(struct net_device *dev)
lp->open_time = 0;
netif_stop_queue(dev);
-
+
/* Flush the Tx and disable Rx here. */
outw( SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
@@ -627,7 +627,7 @@ static void set_multicast_list(struct net_device *dev)
* hmm, not even sure if my matching works _anyway_ - seem to be receiving
* _everything_ . . .
*/
-
+
if (num_addrs) { /* Enable promiscuous mode */
outw( (inw(SEEQ_CFG1) & ~SEEQCFG1_MATCH_MASK)| SEEQCFG1_MATCH_ALL, SEEQ_CFG1);
dev->flags|=IFF_PROMISC;
@@ -642,26 +642,26 @@ void seeq8005_init(struct net_device *dev, int startp)
struct net_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int i;
-
+
outw(SEEQCFG2_RESET, SEEQ_CFG2); /* reset device */
udelay(5);
-
+
outw( SEEQCMD_FIFO_WRITE | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
outw( 0, SEEQ_DMAAR); /* load start address into both low and high byte */
/* wait_for_buffer(dev); */ /* I think that you only need a wait for memory buffer */
outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
+
for(i=0;i<6;i++) { /* set Station address */
outb(dev->dev_addr[i], SEEQ_BUFFER);
udelay(2);
}
-
+
outw( SEEQCFG1_BUFFER_TEA, SEEQ_CFG1); /* set xmit end area pointer to 16K */
outb( DEFAULT_TEA, SEEQ_BUFFER); /* this gives us 16K of send buffer and 48K of recv buffer */
-
+
lp->receive_ptr = (DEFAULT_TEA+1)<<8; /* so we can find our packet_header */
outw( lp->receive_ptr, SEEQ_RPR); /* Receive Pointer Register is set to recv buffer memory */
-
+
outw( 0x00ff, SEEQ_REA); /* Receive Area End */
if (net_debug>4) {
@@ -670,13 +670,13 @@ void seeq8005_init(struct net_device *dev, int startp)
outw( SEEQCMD_FIFO_READ | SEEQCMD_SET_ALL_OFF, SEEQ_CMD);
outw( 0, SEEQ_DMAAR);
outw( SEEQCFG1_BUFFER_MAC0, SEEQ_CFG1);
-
+
for(i=0;i<6;i++) {
printk("%02x ",inb(SEEQ_BUFFER));
}
printk("\n");
}
-
+
outw( SEEQCFG1_MAC0_EN | SEEQCFG1_MATCH_BROAD | SEEQCFG1_BUFFER_BUFFER, SEEQ_CFG1);
outw( SEEQCFG2_AUTO_REA | SEEQCFG2_CTRLO, SEEQ_CFG2);
outw( SEEQCMD_SET_RX_ON | SEEQCMD_TX_INT_EN | SEEQCMD_RX_INT_EN, SEEQ_CMD);
@@ -689,9 +689,9 @@ void seeq8005_init(struct net_device *dev, int startp)
printk("%s: cfg2 = 0x%04x\n",dev->name,inw(SEEQ_CFG2));
printk("%s: raer = 0x%04x\n",dev->name,inw(SEEQ_REA));
printk("%s: dmaar= 0x%04x\n",dev->name,inw(SEEQ_DMAAR));
-
+
}
-}
+}
static void hardware_send_packet(struct net_device * dev, char *buf, int length)
@@ -704,32 +704,32 @@ static void hardware_send_packet(struct net_device * dev, char *buf, int length)
if (net_debug>4) {
printk("%s: send 0x%04x\n",dev->name,length);
}
-
+
/* Set FIFO to writemode and set packet-buffer address */
outw( SEEQCMD_FIFO_WRITE | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
outw( transmit_ptr, SEEQ_DMAAR);
-
+
/* output SEEQ Packet header barfage */
outw( htons(length + 4), SEEQ_BUFFER);
outw( SEEQPKTH_XMIT | SEEQPKTH_DATA_FOLLOWS | SEEQPKTH_XMIT_INT_EN, SEEQ_BUFFER );
-
+
/* blat the buffer */
outsw( SEEQ_BUFFER, buf, (length +1) >> 1);
/* paranoia !! */
outw( 0, SEEQ_BUFFER);
outw( 0, SEEQ_BUFFER);
-
+
/* set address of start of transmit chain */
outw( transmit_ptr, SEEQ_TPR);
-
+
/* drain FIFO */
tmp = jiffies;
while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ))
mb();
-
+
/* doit ! */
outw( SEEQCMD_WINDOW_INT_ACK | SEEQCMD_SET_TX_ON | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
-
+
}
@@ -742,7 +742,7 @@ module_param(irq, int, 0);
MODULE_PARM_DESC(io, "SEEQ 8005 I/O base address");
MODULE_PARM_DESC(irq, "SEEQ 8005 IRQ number");
-int init_module(void)
+int __init init_module(void)
{
dev_seeq = seeq8005_probe(-1);
if (IS_ERR(dev_seeq))
@@ -758,7 +758,7 @@ void cleanup_module(void)
}
#endif /* MODULE */
-
+
/*
* Local variables:
* compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
diff --git a/drivers/net/seeq8005.h b/drivers/net/seeq8005.h
index 809ba6dc8fb..5dfb0098c6c 100644
--- a/drivers/net/seeq8005.h
+++ b/drivers/net/seeq8005.h
@@ -1,7 +1,7 @@
-/*
+/*
* defines, etc for the seeq8005
*/
-
+
/*
* This file is distributed under GPL.
*
diff --git a/drivers/net/sgiseeq.h b/drivers/net/sgiseeq.h
index ebcca688dac..523104de683 100644
--- a/drivers/net/sgiseeq.h
+++ b/drivers/net/sgiseeq.h
@@ -16,7 +16,7 @@ struct sgiseeq_rregs {
volatile unsigned int collision_tx[2];
volatile unsigned int collision_all[2];
volatile unsigned int _unused0;
- volatile unsigned int rflags;
+ volatile unsigned int rflags;
};
struct sgiseeq_regs {
@@ -73,7 +73,7 @@ struct sgiseeq_regs {
#define SEEQ_TCMD_IC 0x02 /* IRQ on collisions */
#define SEEQ_TCMD_I16 0x04 /* IRQ after 16 failed attempts to tx frame */
#define SEEQ_TCMD_IPT 0x08 /* IRQ when packet successfully transmitted */
-#define SEEQ_TCMD_RB1 0x20 /* Register bank one w/multi-cast low byte */
+#define SEEQ_TCMD_RB1 0x20 /* Register bank one w/multi-cast low byte */
#define SEEQ_TCMD_RB2 0x40 /* Register bank two w/multi-cast high byte */
/* Seeq8003 control register */
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index 88e212043a4..e886e8d7cfd 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -8,12 +8,12 @@
* 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.
- *
- * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
- * warranty for any of this software. This material is provided
- * "AS-IS" and at no charge.
*
- *
+ * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
+ * warranty for any of this software. This material is provided
+ * "AS-IS" and at no charge.
+ *
+ *
* Algorithm:
*
* Queue Frame:
@@ -26,7 +26,7 @@
*
* SHAPER_QLEN Maximum queued frames
* SHAPER_LATENCY Bounding latency on a frame. Leaving this latency
- * window drops the frame. This stops us queueing
+ * window drops the frame. This stops us queueing
* frames for a long time and confusing a remote
* host.
* SHAPER_MAXSLIP Maximum time a priority frame may jump forward.
@@ -42,8 +42,8 @@
* run off a 100-150Hz base clock typically. This gives us a resolution at
* 200Kbit/second of about 2Kbit or 256 bytes. Above that our timer
* resolution may start to cause much more burstiness in the traffic. We
- * could avoid a lot of that by calling kick_shaper() at the end of the
- * tied device transmissions. If you run above about 100K second you
+ * could avoid a lot of that by calling kick_shaper() at the end of the
+ * tied device transmissions. If you run above about 100K second you
* may need to tune the supposed speed rate for the right values.
*
* BUGS:
@@ -68,8 +68,7 @@
* Use skb->cb for private data.
* 2000/03 Andi Kleen
*/
-
-#include <linux/config.h>
+
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
@@ -88,13 +87,13 @@
#include <net/dst.h>
#include <net/arp.h>
-struct shaper_cb {
+struct shaper_cb {
unsigned long shapeclock; /* Time it should go out */
unsigned long shapestamp; /* Stamp for shaper */
__u32 shapelatency; /* Latency on frame */
__u32 shapelen; /* Frame length in clocks */
__u16 shapepend; /* Pending */
-};
+};
#define SHAPERCB(skb) ((struct shaper_cb *) ((skb)->cb))
static int sh_debug; /* Debug flag */
@@ -106,7 +105,7 @@ static void shaper_kick(struct shaper *sh);
/*
* Compute clocks on a buffer
*/
-
+
static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb)
{
int t=skb->len/shaper->bytespertick;
@@ -116,9 +115,9 @@ static int shaper_clocks(struct shaper *shaper, struct sk_buff *skb)
/*
* Set the speed of a shaper. We compute this in bytes per tick since
* thats how the machine wants to run. Quoted input is in bits per second
- * as is traditional (note not BAUD). We assume 8 bit bytes.
+ * as is traditional (note not BAUD). We assume 8 bit bytes.
*/
-
+
static void shaper_setspeed(struct shaper *shaper, int bitspersec)
{
shaper->bitspersec=bitspersec;
@@ -130,40 +129,40 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
/*
* Throw a frame at a shaper.
*/
-
+
static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct shaper *shaper = dev->priv;
struct sk_buff *ptr;
-
+
spin_lock(&shaper->lock);
ptr=shaper->sendq.prev;
-
+
/*
* Set up our packet details
*/
-
+
SHAPERCB(skb)->shapelatency=0;
SHAPERCB(skb)->shapeclock=shaper->recovery;
if(time_before(SHAPERCB(skb)->shapeclock, jiffies))
SHAPERCB(skb)->shapeclock=jiffies;
skb->priority=0; /* short term bug fix */
SHAPERCB(skb)->shapestamp=jiffies;
-
+
/*
* Time slots for this packet.
*/
-
+
SHAPERCB(skb)->shapelen= shaper_clocks(shaper,skb);
-
+
{
struct sk_buff *tmp;
/*
* Up our shape clock by the time pending on the queue
* (Should keep this in the shaper as a variable..)
*/
- for(tmp=skb_peek(&shaper->sendq); tmp!=NULL &&
+ for(tmp=skb_peek(&shaper->sendq); tmp!=NULL &&
tmp!=(struct sk_buff *)&shaper->sendq; tmp=tmp->next)
SHAPERCB(skb)->shapeclock+=SHAPERCB(tmp)->shapelen;
/*
@@ -192,7 +191,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
/*
* Transmit from a shaper
*/
-
+
static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
{
struct sk_buff *newskb=skb_clone(skb, GFP_ATOMIC);
@@ -219,7 +218,7 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
/*
* Timer handler for shaping clock
*/
-
+
static void shaper_timer(unsigned long data)
{
struct shaper *shaper = (struct shaper *)data;
@@ -230,25 +229,25 @@ static void shaper_timer(unsigned long data)
}
/*
- * Kick a shaper queue and try and do something sensible with the
- * queue.
+ * Kick a shaper queue and try and do something sensible with the
+ * queue.
*/
static void shaper_kick(struct shaper *shaper)
{
struct sk_buff *skb;
-
+
/*
* Walk the list (may be empty)
*/
-
+
while((skb=skb_peek(&shaper->sendq))!=NULL)
{
/*
* Each packet due to go out by now (within an error
- * of SHAPER_BURST) gets kicked onto the link
+ * of SHAPER_BURST) gets kicked onto the link
*/
-
+
if(sh_debug)
printk("Clock = %ld, jiffies = %ld\n", SHAPERCB(skb)->shapeclock, jiffies);
if(time_before_eq(SHAPERCB(skb)->shapeclock, jiffies + SHAPER_BURST))
@@ -256,16 +255,16 @@ static void shaper_kick(struct shaper *shaper)
/*
* Pull the frame and get interrupts back on.
*/
-
+
skb_unlink(skb, &shaper->sendq);
- if (shaper->recovery <
+ if (shaper->recovery <
SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen)
shaper->recovery = SHAPERCB(skb)->shapeclock + SHAPERCB(skb)->shapelen;
/*
* Pass on to the physical target device via
* our low level packet thrower.
*/
-
+
SHAPERCB(skb)->shapepend=0;
shaper_queue_xmit(shaper, skb); /* Fire */
}
@@ -276,27 +275,27 @@ static void shaper_kick(struct shaper *shaper)
/*
* Next kick.
*/
-
+
if(skb!=NULL)
mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
}
/*
- * Bring the interface up. We just disallow this until a
+ * Bring the interface up. We just disallow this until a
* bind.
*/
static int shaper_open(struct net_device *dev)
{
struct shaper *shaper=dev->priv;
-
+
/*
* Can't open until attached.
* Also can't open until speed is set, or we'll get
* a division by zero.
*/
-
+
if(shaper->dev==NULL)
return -ENODEV;
if(shaper->bitspersec==0)
@@ -307,7 +306,7 @@ static int shaper_open(struct net_device *dev)
/*
* Closing a shaper flushes the queues.
*/
-
+
static int shaper_close(struct net_device *dev)
{
struct shaper *shaper=dev->priv;
@@ -336,7 +335,7 @@ static struct net_device_stats *shaper_get_stats(struct net_device *dev)
return &sh->stats;
}
-static int shaper_header(struct sk_buff *skb, struct net_device *dev,
+static int shaper_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
struct shaper *sh=dev->priv;
@@ -396,7 +395,7 @@ static int shaper_neigh_setup(struct neighbour *n)
n->ops = &arp_broken_ops;
n->output = n->ops->output;
}
-#endif
+#endif
return 0;
}
@@ -408,7 +407,7 @@ static int shaper_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p)
p->ucast_probes = 0;
p->mcast_probes = 0;
}
-#endif
+#endif
return 0;
}
@@ -433,7 +432,7 @@ static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net
}
else
shdev->hard_header = NULL;
-
+
if(dev->rebuild_header)
{
sh->rebuild_header = dev->rebuild_header;
@@ -441,7 +440,7 @@ static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net
}
else
shdev->rebuild_header = NULL;
-
+
#if 0
if(dev->hard_header_cache)
{
@@ -452,7 +451,7 @@ static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net
{
shdev->hard_header_cache= NULL;
}
-
+
if(dev->header_cache_update)
{
sh->header_cache_update = dev->header_cache_update;
@@ -465,7 +464,7 @@ static int shaper_attach(struct net_device *shdev, struct shaper *sh, struct net
shdev->hard_header_cache = NULL;
#endif
shdev->neigh_setup = shaper_neigh_setup_dev;
-
+
shdev->hard_header_len=dev->hard_header_len;
shdev->type=dev->type;
shdev->addr_len=dev->addr_len;
@@ -478,13 +477,13 @@ static int shaper_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
struct shaperconf *ss= (struct shaperconf *)&ifr->ifr_ifru;
struct shaper *sh=dev->priv;
-
+
if(ss->ss_cmd == SHAPER_SET_DEV || ss->ss_cmd == SHAPER_SET_SPEED)
{
if(!capable(CAP_NET_ADMIN))
return -EPERM;
}
-
+
switch(ss->ss_cmd)
{
case SHAPER_SET_DEV:
@@ -526,7 +525,7 @@ static void shaper_init_priv(struct net_device *dev)
/*
* Add a shaper device to the system
*/
-
+
static void __init shaper_setup(struct net_device *dev)
{
/*
@@ -542,11 +541,11 @@ static void __init shaper_setup(struct net_device *dev)
dev->hard_start_xmit = shaper_start_xmit;
dev->get_stats = shaper_get_stats;
dev->set_multicast_list = NULL;
-
+
/*
* Intialise the packet queues
*/
-
+
/*
* Handlers for when we attach to a device.
*/
@@ -567,7 +566,7 @@ static void __init shaper_setup(struct net_device *dev)
dev->tx_queue_len = 10;
dev->flags = 0;
}
-
+
static int shapers = 1;
#ifdef MODULE
@@ -611,7 +610,7 @@ static int __init shaper_init(void)
snprintf(name, IFNAMSIZ, "shaper%d", i);
dev = alloc_netdev(sizeof(struct shaper), name,
shaper_setup);
- if (!dev)
+ if (!dev)
break;
if (register_netdev(dev)) {
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index df39f344765..e8f26b79bba 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -821,9 +821,6 @@ static void sis190_set_rx_mode(struct net_device *dev)
u16 rx_mode;
if (dev->flags & IFF_PROMISC) {
- /* Unconditionally log net taps. */
- net_drv(tp, KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode =
AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
AcceptAllPhys;
@@ -1054,7 +1051,7 @@ static int sis190_open(struct net_device *dev)
sis190_request_timer(dev);
- rc = request_irq(dev->irq, sis190_interrupt, SA_SHIRQ, dev->name, dev);
+ rc = request_irq(dev->irq, sis190_interrupt, IRQF_SHARED, dev->name, dev);
if (rc < 0)
goto err_release_timer_2;
@@ -1750,7 +1747,7 @@ static void sis190_set_msglevel(struct net_device *dev, u32 value)
tp->msg_enable = value;
}
-static struct ethtool_ops sis190_ethtool_ops = {
+static const struct ethtool_ops sis190_ethtool_ops = {
.get_settings = sis190_get_settings,
.set_settings = sis190_set_settings,
.get_drvinfo = sis190_get_drvinfo,
@@ -1871,7 +1868,7 @@ static struct pci_driver sis190_pci_driver = {
static int __init sis190_init_module(void)
{
- return pci_module_init(&sis190_pci_driver);
+ return pci_register_driver(&sis190_pci_driver);
}
static void __exit sis190_cleanup_module(void)
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index d0587417220..28606e20df1 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -1,14 +1,14 @@
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
- Copyright 1999 Silicon Integrated System Corporation
+ Copyright 1999 Silicon Integrated System Corporation
Revision: 1.08.10 Apr. 2 2006
-
+
Modified from the driver which is originally written by Donald Becker.
-
+
This software may be used and distributed according to the terms
of the GNU General Public License (GPL), incorporated herein by reference.
Drivers based on this skeleton fall under the GPL and must retain
the authorship (implicit copyright) notice.
-
+
References:
SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
preliminary Rev. 1.0 Jan. 14, 1998
@@ -29,7 +29,7 @@
Rev 1.08.01 Aug. 25 2001 Hui-Fen Hsu update for 630ET & workaround for ICS1893 PHY
Rev 1.08.00 Jun. 11 2001 Hui-Fen Hsu workaround for RTL8201 PHY and some bug fix
Rev 1.07.11 Apr. 2 2001 Hui-Fen Hsu updates PCI drivers to use the new pci_set_dma_mask for kernel 2.4.3
- Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support
+ Rev 1.07.10 Mar. 1 2001 Hui-Fen Hsu <hfhsu@sis.com.tw> some bug fix & 635M/B support
Rev 1.07.09 Feb. 9 2001 Dave Jones <davej@suse.de> PCI enable cleanup
Rev 1.07.08 Jan. 8 2001 Lei-Chun Chang added RTL8201 PHY support
Rev 1.07.07 Nov. 29 2000 Lei-Chun Chang added kernel-doc extractable documentation and 630 workaround fix
@@ -134,6 +134,7 @@ static const struct mii_chip_info {
{ "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN },
{ "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME},
{ "ICS LAN PHY", 0x0015, 0xF440, LAN },
+ { "ICS LAN PHY", 0x0143, 0xBC70, LAN },
{ "NS 83851 PHY", 0x2000, 0x5C20, MIX },
{ "NS 83847 PHY", 0x2000, 0x5C30, MIX },
{ "Realtek RTL8201 PHY", 0x0000, 0x8200, LAN },
@@ -231,12 +232,12 @@ static void sis900_set_capability( struct net_device *net_dev ,struct mii_phy *p
static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr);
static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr);
static void sis900_set_mode (long ioaddr, int speed, int duplex);
-static struct ethtool_ops sis900_ethtool_ops;
+static const struct ethtool_ops sis900_ethtool_ops;
/**
* sis900_get_mac_addr - Get MAC address for stand alone SiS900 model
* @pci_dev: the sis900 pci device
- * @net_dev: the net device to get address for
+ * @net_dev: the net device to get address for
*
* Older SiS900 and friends, use EEPROM to store MAC address.
* MAC address is read from read_eeprom() into @net_dev->dev_addr.
@@ -249,9 +250,9 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de
int i;
/* check to see if we have sane EEPROM */
- signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
+ signature = (u16) read_eeprom(ioaddr, EEPROMSignature);
if (signature == 0xffff || signature == 0x0000) {
- printk (KERN_WARNING "%s: Error EERPOM read %x\n",
+ printk (KERN_WARNING "%s: Error EERPOM read %x\n",
pci_name(pci_dev), signature);
return 0;
}
@@ -266,7 +267,7 @@ static int __devinit sis900_get_mac_addr(struct pci_dev * pci_dev, struct net_de
/**
* sis630e_get_mac_addr - Get MAC address for SiS630E model
* @pci_dev: the sis900 pci device
- * @net_dev: the net device to get address for
+ * @net_dev: the net device to get address for
*
* SiS630E model, use APC CMOS RAM to store MAC address.
* APC CMOS RAM is accessed through ISA bridge.
@@ -293,7 +294,7 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev,
for (i = 0; i < 6; i++) {
outb(0x09 + i, 0x70);
- ((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
+ ((u8 *)(net_dev->dev_addr))[i] = inb(0x71);
}
pci_write_config_byte(isa_bridge, 0x48, reg & ~0x40);
pci_dev_put(isa_bridge);
@@ -305,10 +306,10 @@ static int __devinit sis630e_get_mac_addr(struct pci_dev * pci_dev,
/**
* sis635_get_mac_addr - Get MAC address for SIS635 model
* @pci_dev: the sis900 pci device
- * @net_dev: the net device to get address for
+ * @net_dev: the net device to get address for
*
* SiS635 model, set MAC Reload Bit to load Mac address from APC
- * to rfdr. rfdr is accessed through rfcr. MAC address is read into
+ * to rfdr. rfdr is accessed through rfcr. MAC address is read into
* @net_dev->dev_addr.
*/
@@ -342,16 +343,16 @@ static int __devinit sis635_get_mac_addr(struct pci_dev * pci_dev,
/**
* sis96x_get_mac_addr - Get MAC address for SiS962 or SiS963 model
* @pci_dev: the sis900 pci device
- * @net_dev: the net device to get address for
+ * @net_dev: the net device to get address for
*
- * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
+ * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM
* is shared by
- * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
- * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
+ * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first
+ * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access
* by LAN, otherwise is not. After MAC address is read from EEPROM, send
- * EEDONE signal to refuse EEPROM access by LAN.
- * The EEPROM map of SiS962 or SiS963 is different to SiS900.
- * The signature field in SiS962 or SiS963 spec is meaningless.
+ * EEDONE signal to refuse EEPROM access by LAN.
+ * The EEPROM map of SiS962 or SiS963 is different to SiS900.
+ * The signature field in SiS962 or SiS963 spec is meaningless.
* MAC address is read into @net_dev->dev_addr.
*/
@@ -362,7 +363,7 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev,
long ee_addr = ioaddr + mear;
u32 waittime = 0;
int i;
-
+
outl(EEREQ, ee_addr);
while(waittime < 2000) {
if(inl(ee_addr) & EEGNT) {
@@ -374,7 +375,7 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev,
outl(EEDONE, ee_addr);
return 1;
} else {
- udelay(1);
+ udelay(1);
waittime ++;
}
}
@@ -388,7 +389,7 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev,
* @pci_id: the pci device ID
*
* Check and probe sis900 net device for @pci_dev.
- * Get mac address according to the chip revision,
+ * Get mac address according to the chip revision,
* and assign SiS900-specific entries in the device structure.
* ie: sis900_open(), sis900_start_xmit(), sis900_close(), etc.
*/
@@ -416,16 +417,16 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
/* setup various bits in PCI command register */
ret = pci_enable_device(pci_dev);
if(ret) return ret;
-
+
i = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
if(i){
printk(KERN_ERR "sis900.c: architecture does not support"
"32bit PCI busmaster DMA\n");
return i;
}
-
+
pci_set_master(pci_dev);
-
+
net_dev = alloc_etherdev(sizeof(struct sis900_private));
if (!net_dev)
return -ENOMEM;
@@ -433,7 +434,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
SET_NETDEV_DEV(net_dev, &pci_dev->dev);
/* We do a request_region() to register /proc/ioports info. */
- ioaddr = pci_resource_start(pci_dev, 0);
+ ioaddr = pci_resource_start(pci_dev, 0);
ret = pci_request_regions(pci_dev, "sis900");
if (ret)
goto err_out;
@@ -461,7 +462,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
}
sis_priv->rx_ring = (BufferDesc *)ring_space;
sis_priv->rx_ring_dma = ring_dma;
-
+
/* The SiS900-specific entries in the device structure. */
net_dev->open = &sis900_open;
net_dev->hard_start_xmit = &sis900_start_xmit;
@@ -495,7 +496,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
printk(KERN_DEBUG "%s: detected revision %2.2x, "
"trying to get MAC address...\n",
dev_name, sis_priv->chipset_rev);
-
+
ret = 0;
if (sis_priv->chipset_rev == SIS630E_900_REV)
ret = sis630e_get_mac_addr(pci_dev, net_dev);
@@ -511,7 +512,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
ret = -ENODEV;
goto err_unmap_rx;
}
-
+
/* 630ET : set the mii access mode as software-mode */
if (sis_priv->chipset_rev == SIS630ET_900_REV)
outl(ACCESSMODE | inl(ioaddr + cr), ioaddr + cr);
@@ -566,7 +567,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
/**
* sis900_mii_probe - Probe MII PHY for sis900
* @net_dev: the net device to probe for
- *
+ *
* Search for total of 32 possible mii phy addresses.
* Identify and set current phy if found one,
* return error if it failed to found.
@@ -583,7 +584,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
sis_priv->mii = NULL;
/* search for total of 32 possible mii phy addresses */
- for (phy_addr = 0; phy_addr < 32; phy_addr++) {
+ for (phy_addr = 0; phy_addr < 32; phy_addr++) {
struct mii_phy * mii_phy = NULL;
u16 mii_status;
int i;
@@ -599,7 +600,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
dev_name, phy_addr);
continue;
}
-
+
if ((mii_phy = kmalloc(sizeof(struct mii_phy), GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "Cannot allocate mem for struct mii_phy\n");
mii_phy = sis_priv->first_mii;
@@ -611,9 +612,9 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
}
return 0;
}
-
+
mii_phy->phy_id0 = mdio_read(net_dev, phy_addr, MII_PHY_ID0);
- mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
+ mii_phy->phy_id1 = mdio_read(net_dev, phy_addr, MII_PHY_ID1);
mii_phy->phy_addr = phy_addr;
mii_phy->status = mii_status;
mii_phy->next = sis_priv->mii;
@@ -634,14 +635,14 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
phy_addr);
break;
}
-
+
if( !mii_chip_table[i].phy_id1 ) {
printk(KERN_INFO "%s: Unknown PHY transceiver found at address %d.\n",
dev_name, phy_addr);
mii_phy->phy_types = UNKNOWN;
}
}
-
+
if (sis_priv->mii == NULL) {
printk(KERN_INFO "%s: No MII transceivers found!\n", dev_name);
return 0;
@@ -655,7 +656,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
if ((sis_priv->mii->phy_id0 == 0x001D) &&
((sis_priv->mii->phy_id1&0xFFF0) == 0x8000))
status = sis900_reset_phy(net_dev, sis_priv->cur_phy);
-
+
/* workaround for ICS1893 PHY */
if ((sis_priv->mii->phy_id0 == 0x0015) &&
((sis_priv->mii->phy_id1&0xFFF0) == 0xF440))
@@ -680,7 +681,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG1, 0x22);
mdio_write(net_dev, sis_priv->cur_phy, MII_CONFIG2, 0xff00);
mdio_write(net_dev, sis_priv->cur_phy, MII_MASK, 0xffc0);
- //mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);
+ //mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, 0x1000);
}
if (sis_priv->mii->status & MII_STAT_LINK)
@@ -703,7 +704,7 @@ static int __init sis900_mii_probe(struct net_device * net_dev)
static u16 sis900_default_phy(struct net_device * net_dev)
{
struct sis900_private * sis_priv = net_dev->priv;
- struct mii_phy *phy = NULL, *phy_home = NULL,
+ struct mii_phy *phy = NULL, *phy_home = NULL,
*default_phy = NULL, *phy_lan = NULL;
u16 status;
@@ -739,17 +740,17 @@ static u16 sis900_default_phy(struct net_device * net_dev)
printk(KERN_INFO "%s: Using transceiver found at address %d as default\n",
pci_name(sis_priv->pci_dev), sis_priv->cur_phy);
}
-
+
sis_priv->mii_info.phy_id = sis_priv->cur_phy;
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
status &= (~MII_CNTL_ISOLATE);
- mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status);
+ mdio_write(net_dev, sis_priv->cur_phy, MII_CONTROL, status);
status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
status = mdio_read(net_dev, sis_priv->cur_phy, MII_STATUS);
- return status;
+ return status;
}
@@ -761,15 +762,15 @@ static u16 sis900_default_phy(struct net_device * net_dev)
* Set the media capability of network adapter according to
* mii status register. It's necessary before auto-negotiate.
*/
-
+
static void sis900_set_capability(struct net_device *net_dev, struct mii_phy *phy)
{
u16 cap;
u16 status;
-
+
status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
status = mdio_read(net_dev, phy->phy_addr, MII_STATUS);
-
+
cap = MII_NWAY_CSMA_CD |
((phy->status & MII_STAT_CAN_TX_FDX)? MII_NWAY_TX_FDX:0) |
((phy->status & MII_STAT_CAN_TX) ? MII_NWAY_TX:0) |
@@ -974,7 +975,7 @@ static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr)
status = mdio_read(net_dev, phy_addr, MII_STATUS);
mdio_write( net_dev, phy_addr, MII_CONTROL, MII_CNTL_RESET );
-
+
return status;
}
@@ -1013,7 +1014,7 @@ sis900_open(struct net_device *net_dev)
/* Equalizer workaround Rule */
sis630_set_eq(net_dev, sis_priv->chipset_rev);
- ret = request_irq(net_dev->irq, &sis900_interrupt, SA_SHIRQ,
+ ret = request_irq(net_dev->irq, &sis900_interrupt, IRQF_SHARED,
net_dev->name, net_dev);
if (ret)
return ret;
@@ -1091,7 +1092,7 @@ sis900_init_rxfilter (struct net_device * net_dev)
* sis900_init_tx_ring - Initialize the Tx descriptor ring
* @net_dev: the net device to initialize for
*
- * Initialize the Tx descriptor ring,
+ * Initialize the Tx descriptor ring,
*/
static void
@@ -1124,11 +1125,11 @@ sis900_init_tx_ring(struct net_device *net_dev)
* sis900_init_rx_ring - Initialize the Rx descriptor ring
* @net_dev: the net device to initialize for
*
- * Initialize the Rx descriptor ring,
+ * Initialize the Rx descriptor ring,
* and pre-allocate recevie buffers (socket buffer)
*/
-static void
+static void
sis900_init_rx_ring(struct net_device *net_dev)
{
struct sis900_private *sis_priv = net_dev->priv;
@@ -1238,8 +1239,8 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision)
max_value+6 : max_value+5;
}
/* 630B0&B1 rule to determine the equalizer value */
- if (revision == SIS630A_900_REV &&
- (sis_priv->host_bridge_rev == SIS630B0 ||
+ if (revision == SIS630A_900_REV &&
+ (sis_priv->host_bridge_rev == SIS630B0 ||
sis_priv->host_bridge_rev == SIS630B1)) {
if (max_value == 0)
eq_value = 3;
@@ -1253,9 +1254,9 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision)
mdio_write(net_dev, sis_priv->cur_phy, MII_RESV, reg14h);
} else {
reg14h = mdio_read(net_dev, sis_priv->cur_phy, MII_RESV);
- if (revision == SIS630A_900_REV &&
- (sis_priv->host_bridge_rev == SIS630B0 ||
- sis_priv->host_bridge_rev == SIS630B1))
+ if (revision == SIS630A_900_REV &&
+ (sis_priv->host_bridge_rev == SIS630B0 ||
+ sis_priv->host_bridge_rev == SIS630B1))
mdio_write(net_dev, sis_priv->cur_phy, MII_RESV,
(reg14h | 0x2200) & 0xBFFF);
else
@@ -1269,7 +1270,7 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision)
* sis900_timer - sis900 timer routine
* @data: pointer to sis900 net device
*
- * On each timer ticks we check two things,
+ * On each timer ticks we check two things,
* link status (ON/OFF) and link mode (10/100/Full/Half)
*/
@@ -1318,12 +1319,12 @@ static void sis900_timer(unsigned long data)
printk(KERN_INFO "%s: Media Link Off\n", net_dev->name);
/* Change mode issue */
- if ((mii_phy->phy_id0 == 0x001D) &&
+ if ((mii_phy->phy_id0 == 0x001D) &&
((mii_phy->phy_id1 & 0xFFF0) == 0x8000))
sis900_reset_phy(net_dev, sis_priv->cur_phy);
-
+
sis630_set_eq(net_dev, sis_priv->chipset_rev);
-
+
goto LookForLink;
}
}
@@ -1428,7 +1429,7 @@ static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr)
struct sis900_private *sis_priv = net_dev->priv;
int i = 0;
u32 status;
-
+
while (i++ < 2)
status = mdio_read(net_dev, phy_addr, MII_STATUS);
@@ -1477,7 +1478,7 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex
autoadv = mdio_read(net_dev, phy_addr, MII_ANADV);
autorec = mdio_read(net_dev, phy_addr, MII_ANLPAR);
status = autoadv & autorec;
-
+
*speed = HW_SPEED_10_MBPS;
*duplex = FDX_CAPABLE_HALF_SELECTED;
@@ -1485,7 +1486,7 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex
*speed = HW_SPEED_100_MBPS;
if (status & ( MII_NWAY_TX_FDX | MII_NWAY_T_FDX))
*duplex = FDX_CAPABLE_FULL_SELECTED;
-
+
sis_priv->autong_complete = 1;
/* Workaround for Realtek RTL8201 PHY issue */
@@ -1536,7 +1537,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
struct sk_buff *skb = sis_priv->tx_skbuff[i];
if (skb) {
- pci_unmap_single(sis_priv->pci_dev,
+ pci_unmap_single(sis_priv->pci_dev,
sis_priv->tx_ring[i].bufptr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
@@ -1566,7 +1567,7 @@ static void sis900_tx_timeout(struct net_device *net_dev)
* @skb: socket buffer pointer to put the data being transmitted
* @net_dev: the net device to transmit with
*
- * Set the transmit buffer descriptor,
+ * Set the transmit buffer descriptor,
* and write TxENA to enable transmit state machine.
* tell upper layer if the buffer is full
*/
@@ -1610,7 +1611,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
/* dirty_tx is met in the cycle of cur_tx, buffer full */
sis_priv->tx_full = 1;
netif_stop_queue(net_dev);
- } else if (count_dirty_tx < NUM_TX_DESC) {
+ } else if (count_dirty_tx < NUM_TX_DESC) {
/* Typical path, tell upper layer that more transmission is possible */
netif_start_queue(net_dev);
} else {
@@ -1637,7 +1638,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
* @dev_instance: the client data object
* @regs: snapshot of processor context
*
- * The interrupt handler does all of the Rx thread work,
+ * The interrupt handler does all of the Rx thread work,
* and cleans up after the Tx thread
*/
@@ -1689,7 +1690,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs
printk(KERN_DEBUG "%s: exiting interrupt, "
"interrupt status = 0x%#8.8x.\n",
net_dev->name, inl(ioaddr + isr));
-
+
spin_unlock (&sis_priv->lock);
return IRQ_RETVAL(handled);
}
@@ -1698,7 +1699,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs
* sis900_rx - sis900 receive routine
* @net_dev: the net device which receives data
*
- * Process receive interrupt events,
+ * Process receive interrupt events,
* put buffer to higher layer and refill buffer pool
* Note: This function is called by interrupt handler,
* don't do "too much" work here
@@ -1747,7 +1748,7 @@ static int sis900_rx(struct net_device *net_dev)
sis_priv->stats.rx_length_errors++;
if (rx_status & (RXISERR | FAERR))
sis_priv->stats.rx_frame_errors++;
- if (rx_status & CRCERR)
+ if (rx_status & CRCERR)
sis_priv->stats.rx_crc_errors++;
/* reset buffer descriptor state */
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
@@ -1759,7 +1760,7 @@ static int sis900_rx(struct net_device *net_dev)
we are working on NULL sk_buff :-( */
if (sis_priv->rx_skbuff[entry] == NULL) {
if (netif_msg_rx_err(sis_priv))
- printk(KERN_WARNING "%s: NULL pointer "
+ printk(KERN_WARNING "%s: NULL pointer "
"encountered in Rx ring\n"
"cur_rx:%4.4d, dirty_rx:%4.4d\n",
net_dev->name, sis_priv->cur_rx,
@@ -1767,8 +1768,8 @@ static int sis900_rx(struct net_device *net_dev)
break;
}
- pci_unmap_single(sis_priv->pci_dev,
- sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
+ pci_unmap_single(sis_priv->pci_dev,
+ sis_priv->rx_ring[entry].bufptr, RX_BUF_SIZE,
PCI_DMA_FROMDEVICE);
/* give the socket buffer to upper layers */
skb = sis_priv->rx_skbuff[entry];
@@ -1805,8 +1806,8 @@ static int sis900_rx(struct net_device *net_dev)
skb->dev = net_dev;
sis_priv->rx_skbuff[entry] = skb;
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
- sis_priv->rx_ring[entry].bufptr =
- pci_map_single(sis_priv->pci_dev, skb->data,
+ sis_priv->rx_ring[entry].bufptr =
+ pci_map_single(sis_priv->pci_dev, skb->data,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
sis_priv->dirty_rx++;
}
@@ -1853,7 +1854,7 @@ static int sis900_rx(struct net_device *net_dev)
* sis900_finish_xmit - finish up transmission of packets
* @net_dev: the net device to be transmitted on
*
- * Check for error condition and free socket buffer etc
+ * Check for error condition and free socket buffer etc
* schedule for more transmission as needed
* Note: This function is called by interrupt handler,
* don't do "too much" work here
@@ -1901,7 +1902,7 @@ static void sis900_finish_xmit (struct net_device *net_dev)
}
/* Free the original skb. */
skb = sis_priv->tx_skbuff[entry];
- pci_unmap_single(sis_priv->pci_dev,
+ pci_unmap_single(sis_priv->pci_dev,
sis_priv->tx_ring[entry].bufptr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
@@ -1920,10 +1921,10 @@ static void sis900_finish_xmit (struct net_device *net_dev)
}
/**
- * sis900_close - close sis900 device
+ * sis900_close - close sis900 device
* @net_dev: the net device to be closed
*
- * Disable interrupts, stop the Tx and Rx Status Machine
+ * Disable interrupts, stop the Tx and Rx Status Machine
* free Tx and RX socket buffer
*/
@@ -1951,7 +1952,7 @@ static int sis900_close(struct net_device *net_dev)
for (i = 0; i < NUM_RX_DESC; i++) {
skb = sis_priv->rx_skbuff[i];
if (skb) {
- pci_unmap_single(sis_priv->pci_dev,
+ pci_unmap_single(sis_priv->pci_dev,
sis_priv->rx_ring[i].bufptr,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
dev_kfree_skb(skb);
@@ -1961,7 +1962,7 @@ static int sis900_close(struct net_device *net_dev)
for (i = 0; i < NUM_TX_DESC; i++) {
skb = sis_priv->tx_skbuff[i];
if (skb) {
- pci_unmap_single(sis_priv->pci_dev,
+ pci_unmap_single(sis_priv->pci_dev,
sis_priv->tx_ring[i].bufptr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb(skb);
@@ -1981,7 +1982,7 @@ static int sis900_close(struct net_device *net_dev)
*
* Process ethtool command such as "ehtool -i" to show information
*/
-
+
static void sis900_get_drvinfo(struct net_device *net_dev,
struct ethtool_drvinfo *info)
{
@@ -1997,7 +1998,7 @@ static u32 sis900_get_msglevel(struct net_device *net_dev)
struct sis900_private *sis_priv = net_dev->priv;
return sis_priv->msg_enable;
}
-
+
static void sis900_set_msglevel(struct net_device *net_dev, u32 value)
{
struct sis900_private *sis_priv = net_dev->priv;
@@ -2047,7 +2048,7 @@ static int sis900_nway_reset(struct net_device *net_dev)
* but there is no simple way to filter them to only a subset (broadcast,
* multicast, unicast or arp).
*/
-
+
static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol)
{
struct sis900_private *sis_priv = net_dev->priv;
@@ -2072,7 +2073,7 @@ static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wo
pmctrl_bits |= MAGICPKT;
if (wol->wolopts & WAKE_PHY)
pmctrl_bits |= LINKON;
-
+
outl(pmctrl_bits, pmctrl_addr);
pci_read_config_dword(sis_priv->pci_dev, CFGPMCSR, &cfgpmcsr);
@@ -2098,7 +2099,7 @@ static void sis900_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *w
wol->supported = (WAKE_PHY | WAKE_MAGIC);
}
-static struct ethtool_ops sis900_ethtool_ops = {
+static const struct ethtool_ops sis900_ethtool_ops = {
.get_drvinfo = sis900_get_drvinfo,
.get_msglevel = sis900_get_msglevel,
.set_msglevel = sis900_set_msglevel,
@@ -2111,7 +2112,7 @@ static struct ethtool_ops sis900_ethtool_ops = {
};
/**
- * mii_ioctl - process MII i/o control command
+ * mii_ioctl - process MII i/o control command
* @net_dev: the net device to command for
* @rq: parameter for command
* @cmd: the i/o command
@@ -2144,7 +2145,7 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
}
/**
- * sis900_get_stats - Get sis900 read/write statistics
+ * sis900_get_stats - Get sis900 read/write statistics
* @net_dev: the net device to get statistics for
*
* get tx/rx statistics for sis900
@@ -2159,7 +2160,7 @@ sis900_get_stats(struct net_device *net_dev)
}
/**
- * sis900_set_config - Set media type by net_device.set_config
+ * sis900_set_config - Set media type by net_device.set_config
* @dev: the net device for media type change
* @map: ifmap passed by ifconfig
*
@@ -2169,10 +2170,10 @@ sis900_get_stats(struct net_device *net_dev)
*/
static int sis900_set_config(struct net_device *dev, struct ifmap *map)
-{
+{
struct sis900_private *sis_priv = dev->priv;
struct mii_phy *mii_phy = sis_priv->mii;
-
+
u16 status;
if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
@@ -2180,10 +2181,10 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
* like a definition or standard for the values of that field.
* I think the meaning of those values is device specific. But
* since I would like to change the media type via the ifconfig
- * command I use the definition from linux/netdevice.h
+ * command I use the definition from linux/netdevice.h
* (which seems to be different from the ifport(pcmcia) definition) */
switch(map->port){
- case IF_PORT_UNKNOWN: /* use auto here */
+ case IF_PORT_UNKNOWN: /* use auto here */
dev->if_port = map->port;
/* we are going to change the media type, so the Link
* will be temporary down and we need to reflect that
@@ -2191,10 +2192,10 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
* sensed by the sis_timer procedure, which also does
* all the rest for us */
netif_carrier_off(dev);
-
+
/* read current state */
status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
-
+
/* enable auto negotiation and reset the negotioation
* (I don't really know what the auto negatiotiation
* reset really means, but it sounds for me right to
@@ -2203,54 +2204,54 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
MII_CONTROL, status | MII_CNTL_AUTO | MII_CNTL_RST_AUTO);
break;
-
- case IF_PORT_10BASET: /* 10BaseT */
+
+ case IF_PORT_10BASET: /* 10BaseT */
dev->if_port = map->port;
-
+
/* we are going to change the media type, so the Link
* will be temporary down and we need to reflect that
* here. When the Link comes up again, it will be
* sensed by the sis_timer procedure, which also does
* all the rest for us */
netif_carrier_off(dev);
-
+
/* set Speed to 10Mbps */
/* read current state */
status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
-
+
/* disable auto negotiation and force 10MBit mode*/
mdio_write(dev, mii_phy->phy_addr,
MII_CONTROL, status & ~(MII_CNTL_SPEED |
MII_CNTL_AUTO));
break;
-
+
case IF_PORT_100BASET: /* 100BaseT */
- case IF_PORT_100BASETX: /* 100BaseTx */
+ case IF_PORT_100BASETX: /* 100BaseTx */
dev->if_port = map->port;
-
+
/* we are going to change the media type, so the Link
* will be temporary down and we need to reflect that
* here. When the Link comes up again, it will be
* sensed by the sis_timer procedure, which also does
* all the rest for us */
netif_carrier_off(dev);
-
+
/* set Speed to 100Mbps */
/* disable auto negotiation and enable 100MBit Mode */
status = mdio_read(dev, mii_phy->phy_addr, MII_CONTROL);
mdio_write(dev, mii_phy->phy_addr,
MII_CONTROL, (status & ~MII_CNTL_SPEED) |
MII_CNTL_SPEED);
-
+
break;
-
+
case IF_PORT_10BASE2: /* 10Base2 */
case IF_PORT_AUI: /* AUI */
case IF_PORT_100BASEFX: /* 100BaseFx */
/* These Modes are not supported (are they?)*/
return -EOPNOTSUPP;
break;
-
+
default:
return -EINVAL;
}
@@ -2259,14 +2260,14 @@ static int sis900_set_config(struct net_device *dev, struct ifmap *map)
}
/**
- * sis900_mcast_bitnr - compute hashtable index
+ * sis900_mcast_bitnr - compute hashtable index
* @addr: multicast address
* @revision: revision id of chip
*
* SiS 900 uses the most sigificant 7 bits to index a 128 bits multicast
* hash table, which makes this function a little bit different from other drivers
* SiS 900 B0 & 635 M/B uses the most significat 8 bits to index 256 bits
- * multicast hash table.
+ * multicast hash table.
*/
static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision)
@@ -2282,7 +2283,7 @@ static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision)
}
/**
- * set_rx_mode - Set SiS900 receive mode
+ * set_rx_mode - Set SiS900 receive mode
* @net_dev: the net device to be set
*
* Set SiS900 receive mode for promiscuous, multicast, or broadcast mode.
@@ -2358,7 +2359,7 @@ static void set_rx_mode(struct net_device *net_dev)
}
/**
- * sis900_reset - Reset sis900 MAC
+ * sis900_reset - Reset sis900 MAC
* @net_dev: the net device to reset
*
* reset sis900 MAC and wait until finished
@@ -2378,7 +2379,7 @@ static void sis900_reset(struct net_device *net_dev)
outl(0, ioaddr + rfcr);
outl(RxRESET | TxRESET | RESET | inl(ioaddr + cr), ioaddr + cr);
-
+
/* Check that the chip has finished the reset. */
while (status && (i++ < 1000)) {
status ^= (inl(isr + ioaddr) & status);
@@ -2392,7 +2393,7 @@ static void sis900_reset(struct net_device *net_dev)
}
/**
- * sis900_remove - Remove sis900 device
+ * sis900_remove - Remove sis900 device
* @pci_dev: the pci device to be removed
*
* remove and release SiS900 net device
@@ -2495,7 +2496,7 @@ static int __init sis900_init_module(void)
printk(version);
#endif
- return pci_module_init(&sis900_pci_driver);
+ return pci_register_driver(&sis900_pci_driver);
}
static void __exit sis900_cleanup_module(void)
diff --git a/drivers/net/sis900.h b/drivers/net/sis900.h
index 4834e3a1569..150511a922e 100644
--- a/drivers/net/sis900.h
+++ b/drivers/net/sis900.h
@@ -1,4 +1,4 @@
-/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900
+/* sis900.h Definitions for SiS ethernet controllers including 7014/7016 and 900
* Copyright 1999 Silicon Integrated System Corporation
* References:
* SiS 7016 Fast Ethernet PCI Bus 10/100 Mbps LAN Controller with OnNow Support,
@@ -49,7 +49,7 @@ enum sis900_command_register_bits {
enum sis900_configuration_register_bits {
DESCRFMT = 0x00000100 /* 7016 specific */, REQALG = 0x00000080,
- SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010,
+ SB = 0x00000040, POW = 0x00000020, EXD = 0x00000010,
PESEL = 0x00000008, LPM = 0x00000004, BEM = 0x00000001,
/* 635 & 900B Specific */
RND_CNT = 0x00000400, FAIR_BACKOFF = 0x00000200,
@@ -57,7 +57,7 @@ enum sis900_configuration_register_bits {
};
enum sis900_eeprom_access_reigster_bits {
- MDC = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */
+ MDC = 0x00000040, MDDIR = 0x00000020, MDIO = 0x00000010, /* 7016 specific */
EECS = 0x00000008, EECLK = 0x00000004, EEDO = 0x00000002,
EEDI = 0x00000001
};
@@ -129,9 +129,9 @@ enum sis900_eeprom_address {
/* The EEPROM commands include the alway-set leading bit. Refer to NM93Cxx datasheet */
enum sis900_eeprom_command {
- EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0,
+ EEread = 0x0180, EEwrite = 0x0140, EEerase = 0x01C0,
EEwriteEnable = 0x0130, EEwriteDisable = 0x0100,
- EEeraseAll = 0x0120, EEwriteAll = 0x0110,
+ EEeraseAll = 0x0120, EEwriteAll = 0x0110,
EEaddrMask = 0x013F, EEcmdShift = 16
};
@@ -148,7 +148,7 @@ enum sis900_pci_registers {
/* Power management capabilities bits */
enum sis900_cfgpmc_register_bits {
- PMVER = 0x00070000,
+ PMVER = 0x00070000,
DSI = 0x00100000,
PMESP = 0xf8000000
};
@@ -238,7 +238,7 @@ enum amd_mii_registers {
/* MII Control register bit definitions. */
enum mii_control_register_bits {
- MII_CNTL_FDX = 0x0100, MII_CNTL_RST_AUTO = 0x0200,
+ MII_CNTL_FDX = 0x0100, MII_CNTL_RST_AUTO = 0x0200,
MII_CNTL_ISOLATE = 0x0400, MII_CNTL_PWRDWN = 0x0800,
MII_CNTL_AUTO = 0x1000, MII_CNTL_SPEED = 0x2000,
MII_CNTL_LPBK = 0x4000, MII_CNTL_RESET = 0x8000
@@ -246,8 +246,8 @@ enum mii_control_register_bits {
/* MII Status register bit */
enum mii_status_register_bits {
- MII_STAT_EXT = 0x0001, MII_STAT_JAB = 0x0002,
- MII_STAT_LINK = 0x0004, MII_STAT_CAN_AUTO = 0x0008,
+ MII_STAT_EXT = 0x0001, MII_STAT_JAB = 0x0002,
+ MII_STAT_LINK = 0x0004, MII_STAT_CAN_AUTO = 0x0008,
MII_STAT_FAULT = 0x0010, MII_STAT_AUTO_DONE = 0x0020,
MII_STAT_CAN_T = 0x0800, MII_STAT_CAN_T_FDX = 0x1000,
MII_STAT_CAN_TX = 0x2000, MII_STAT_CAN_TX_FDX = 0x4000,
diff --git a/drivers/net/sk98lin/h/xmac_ii.h b/drivers/net/sk98lin/h/xmac_ii.h
index 2b19f8ad031..7f8e6d0084c 100644
--- a/drivers/net/sk98lin/h/xmac_ii.h
+++ b/drivers/net/sk98lin/h/xmac_ii.h
@@ -1473,7 +1473,7 @@ extern "C" {
#define GM_TXCR_FORCE_JAM (1<<15) /* Bit 15: Force Jam / Flow-Control */
#define GM_TXCR_CRC_DIS (1<<14) /* Bit 14: Disable insertion of CRC */
#define GM_TXCR_PAD_DIS (1<<13) /* Bit 13: Disable padding of packets */
-#define GM_TXCR_COL_THR_MSK (1<<10) /* Bit 12..10: Collision Threshold */
+#define GM_TXCR_COL_THR_MSK (7<<10) /* Bit 12..10: Collision Threshold */
#define TX_COL_THR(x) (SHIFT10(x) & GM_TXCR_COL_THR_MSK)
diff --git a/drivers/net/sk98lin/skethtool.c b/drivers/net/sk98lin/skethtool.c
index 4265ed91a9c..e5cb5b548b8 100644
--- a/drivers/net/sk98lin/skethtool.c
+++ b/drivers/net/sk98lin/skethtool.c
@@ -581,7 +581,7 @@ static int setRxCsum(struct net_device *dev, u32 data)
return 0;
}
-struct ethtool_ops SkGeEthtoolOps = {
+const struct ethtool_ops SkGeEthtoolOps = {
.get_settings = getSettings,
.set_settings = setSettings,
.get_drvinfo = getDriverInfo,
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index f3efbd177ae..99e92627642 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -248,7 +248,7 @@ static void DumpLong(char*, int);
/* global variables *********************************************************/
static SK_BOOL DoPrintInterfaceChange = SK_TRUE;
-extern struct ethtool_ops SkGeEthtoolOps;
+extern const struct ethtool_ops SkGeEthtoolOps;
/* local variables **********************************************************/
static uintptr_t TxQueueAddr[SK_MAX_MACS][2] = {{0x680, 0x600},{0x780, 0x700}};
@@ -570,9 +570,9 @@ SK_BOOL DualNet;
spin_unlock_irqrestore(&pAC->SlowPathLock, Flags);
if (pAC->GIni.GIMacsFound == 2) {
- Ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, "sk98lin", dev);
+ Ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
} else if (pAC->GIni.GIMacsFound == 1) {
- Ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ,
+ Ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED,
"sk98lin", dev);
} else {
printk(KERN_WARNING "sk98lin: Illegal number of ports: %d\n",
@@ -1559,7 +1559,7 @@ struct sk_buff *pMessage) /* pointer to send-message */
pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32);
pTxd->pMBuf = pMessage;
- if (pMessage->ip_summed == CHECKSUM_HW) {
+ if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
u16 hdrlen = pMessage->h.raw - pMessage->data;
u16 offset = hdrlen + pMessage->csum;
@@ -1678,7 +1678,7 @@ struct sk_buff *pMessage) /* pointer to send-message */
/*
** Does the HW need to evaluate checksum for TCP or UDP packets?
*/
- if (pMessage->ip_summed == CHECKSUM_HW) {
+ if (pMessage->ip_summed == CHECKSUM_PARTIAL) {
u16 hdrlen = pMessage->h.raw - pMessage->data;
u16 offset = hdrlen + pMessage->csum;
@@ -2158,7 +2158,7 @@ rx_start:
#ifdef USE_SK_RX_CHECKSUM
pMsg->csum = pRxd->TcpSums & 0xffff;
- pMsg->ip_summed = CHECKSUM_HW;
+ pMsg->ip_summed = CHECKSUM_COMPLETE;
#else
pMsg->ip_summed = CHECKSUM_NONE;
#endif
@@ -5073,9 +5073,9 @@ static int skge_resume(struct pci_dev *pdev)
pci_enable_device(pdev);
pci_set_master(pdev);
if (pAC->GIni.GIMacsFound == 2)
- ret = request_irq(dev->irq, SkGeIsr, SA_SHIRQ, "sk98lin", dev);
+ ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev);
else
- ret = request_irq(dev->irq, SkGeIsrOnePort, SA_SHIRQ, "sk98lin", dev);
+ ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev);
if (ret) {
printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq);
pAC->AllocFlag &= ~SK_ALLOC_IRQ;
@@ -5133,7 +5133,7 @@ static struct pci_driver skge_driver = {
static int __init skge_init(void)
{
- return pci_module_init(&skge_driver);
+ return pci_register_driver(&skge_driver);
}
static void __exit skge_exit(void)
diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c
index 17786056c66..1e662aaebf8 100644
--- a/drivers/net/sk98lin/skvpd.c
+++ b/drivers/net/sk98lin/skvpd.c
@@ -22,7 +22,7 @@
******************************************************************************/
/*
- Please refer skvpd.txt for infomation how to include this module
+ Please refer skvpd.txt for information how to include this module
*/
static const char SysKonnectFileId[] =
"@(#)$Id: skvpd.c,v 1.37 2003/01/13 10:42:45 rschmidt Exp $ (C) SK";
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index e5d6d95960c..37b88da1abe 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -1,4 +1,4 @@
-/*
+/*
net-3-driver for the SKNET MCA-based cards
This is an extension to the Linux operating system, and is covered by the
@@ -10,9 +10,9 @@ Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
This driver is based both on the 3C523 driver and the SK_G16 driver.
paper sources:
- 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
+ 'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
Hans-Peter Messmer for the basic Microchannel stuff
-
+
'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
for help on Ethernet driver programming
@@ -24,7 +24,7 @@ paper sources:
'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
documentation on the MC2 bord
-
+
A big thank you to the S&K support for providing me so quickly with
documentation!
@@ -34,7 +34,7 @@ paper sources:
-> set debug level via ioctl instead of compile-time switches
-> I didn't follow the development of the 2.1.x kernels, so my
- assumptions about which things changed with which kernel version
+ assumptions about which things changed with which kernel version
are probably nonsense
History:
@@ -57,7 +57,7 @@ History:
fixed problem in GetLANCE leaving interrupts turned off
increase TX queue to 4 packets to improve send performance
May 29th, 1999
- a few corrections in statistics, caught rcvr overruns
+ a few corrections in statistics, caught rcvr overruns
reinitialization of LANCE/board in critical situations
MCA info implemented
implemented LANCE multicast filter
@@ -427,7 +427,7 @@ static void InitLANCE(struct net_device *dev)
InitDscrs(dev);
/* next RX descriptor to be read is the first one. Since the LANCE
- will start from the beginning after initialization, we have to
+ will start from the beginning after initialization, we have to
reset out pointers too. */
priv->nextrx = 0;
@@ -824,7 +824,7 @@ static int skmca_open(struct net_device *dev)
/* register resources - only necessary for IRQ */
result =
request_irq(priv->realirq, irq_handler,
- SA_SHIRQ | SA_SAMPLE_RANDOM, "sk_mca", dev);
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev);
if (result != 0) {
printk("%s: failed to register irq %d\n", dev->name,
dev->irq);
@@ -868,7 +868,7 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
int tmplen, retval = 0;
unsigned long flags;
- /* if we get called with a NULL descriptor, the Ethernet layer thinks
+ /* if we get called with a NULL descriptor, the Ethernet layer thinks
our card is stuck an we should reset it. We'll do this completely: */
if (skb == NULL) {
@@ -896,7 +896,7 @@ static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
tmplen = 60;
descr.Len = 65536 - tmplen;
- /* copy filler into RAM - in case we're filling up...
+ /* copy filler into RAM - in case we're filling up...
we're filling a bit more than necessary, but that doesn't harm
since the buffer is far larger... */
if (tmplen > skb->len) {
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
index d6fa1823dfa..0dae056fed9 100644
--- a/drivers/net/sk_mca.h
+++ b/drivers/net/sk_mca.h
@@ -25,11 +25,11 @@ typedef struct {
int nextrx; /* index of next RX descriptor to
be read */
int nexttxput; /* index of next free TX descriptor */
- int nexttxdone; /* index of next TX descriptor to
+ int nexttxdone; /* index of next TX descriptor to
be finished */
int txbusy; /* # of busy TX descriptors */
struct net_device_stats stat; /* packet statistics */
- int realirq; /* memorizes actual IRQ, even when
+ int realirq; /* memorizes actual IRQ, even when
currently not allocated */
skmca_medium medium; /* physical cannector */
spinlock_t lock;
diff --git a/drivers/net/skfp/h/sba.h b/drivers/net/skfp/h/sba.h
index df716cd5784..638cf0283bc 100644
--- a/drivers/net/skfp/h/sba.h
+++ b/drivers/net/skfp/h/sba.h
@@ -13,7 +13,7 @@
******************************************************************************/
/*
- * Synchronous Bandwith Allocation (SBA) structs
+ * Synchronous Bandwidth Allocation (SBA) structs
*/
#ifndef _SBA_
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index c7fb6133047..8e4d18440a5 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -497,7 +497,7 @@ static int skfp_open(struct net_device *dev)
PRINTK(KERN_INFO "entering skfp_open\n");
/* Register IRQ - support shared interrupts by passing device ptr */
- err = request_irq(dev->irq, (void *) skfp_interrupt, SA_SHIRQ,
+ err = request_irq(dev->irq, (void *) skfp_interrupt, IRQF_SHARED,
dev->name, dev);
if (err)
return err;
@@ -2280,7 +2280,7 @@ static struct pci_driver skfddi_pci_driver = {
static int __init skfd_init(void)
{
- return pci_module_init(&skfddi_pci_driver);
+ return pci_register_driver(&skfddi_pci_driver);
}
static void __exit skfd_exit(void)
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 19a4a16055d..705e9a8fa30 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -24,7 +24,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -44,7 +43,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.6"
+#define DRV_VERSION "1.8"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -59,6 +58,7 @@
#define TX_WATCHDOG (5 * HZ)
#define NAPI_WEIGHT 64
#define BLINK_MS 250
+#define LINK_HZ (HZ/2)
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
@@ -92,7 +92,7 @@ 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_phy_reset(struct skge_port *skge);
-static void skge_tx_clean(struct skge_port *skge);
+static void skge_tx_clean(struct net_device *dev);
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);
@@ -106,6 +106,7 @@ static const int txqaddr[] = { Q_XA1, Q_XA2 };
static const int rxqaddr[] = { Q_R1, Q_R2 };
static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 irqmask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F };
static int skge_get_regs_len(struct net_device *dev)
{
@@ -517,10 +518,7 @@ static int skge_set_pauseparam(struct net_device *dev,
/* Chip internal frequency for clock calculations */
static inline u32 hwkhz(const struct skge_hw *hw)
{
- if (hw->chip_id == CHIP_ID_GENESIS)
- return 53215; /* or: 53.125 MHz */
- else
- return 78215; /* or: 78.125 MHz */
+ return (hw->chip_id == CHIP_ID_GENESIS) ? 53125 : 78125;
}
/* Chip HZ to microseconds */
@@ -608,7 +606,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
if (hw->chip_id == CHIP_ID_GENESIS) {
switch (mode) {
case LED_MODE_OFF:
- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
+ if (hw->phy_type == SK_PHY_BCOM)
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
+ else {
+ skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
+ }
skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
@@ -628,8 +631,14 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
- break;
+ if (hw->phy_type == SK_PHY_BCOM)
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
+ else {
+ skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
+ skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
+ }
+
}
} else {
switch (mode) {
@@ -694,7 +703,7 @@ static int skge_phys_id(struct net_device *dev, u32 data)
return 0;
}
-static struct ethtool_ops skge_ethtool_ops = {
+static const struct ethtool_ops skge_ethtool_ops = {
.get_settings = skge_get_settings,
.set_settings = skge_set_settings,
.get_drvinfo = skge_get_drvinfo,
@@ -822,8 +831,9 @@ static void skge_rx_clean(struct skge_port *skge)
/* Allocate buffers for receive ring
* For receive: to_clean is next received frame.
*/
-static int skge_rx_fill(struct skge_port *skge)
+static int skge_rx_fill(struct net_device *dev)
{
+ struct skge_port *skge = netdev_priv(dev);
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
@@ -831,7 +841,8 @@ static int skge_rx_fill(struct skge_port *skge)
do {
struct sk_buff *skb;
- skb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_KERNEL);
+ skb = __netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN,
+ GFP_KERNEL);
if (!skb)
return -ENOMEM;
@@ -880,6 +891,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
*val = xm_read16(hw, port, XM_PHY_DATA);
+ if (hw->phy_type == SK_PHY_XMAC)
+ goto ready;
+
for (i = 0; i < PHY_RETRIES; i++) {
if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
goto ready;
@@ -966,7 +980,8 @@ static void genesis_reset(struct skge_hw *hw, int port)
xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
/* disable Broadcom PHY IRQ */
- xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+ if (hw->phy_type == SK_PHY_BCOM)
+ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
xm_outhash(hw, port, XM_HSM, zero);
}
@@ -1001,60 +1016,64 @@ static void bcom_check_link(struct skge_hw *hw, int port)
if (netif_carrier_ok(dev))
skge_link_down(skge);
- } else {
- if (skge->autoneg == AUTONEG_ENABLE &&
- (status & PHY_ST_AN_OVER)) {
- u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
- u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
-
- if (lpa & PHY_B_AN_RF) {
- printk(KERN_NOTICE PFX "%s: remote fault\n",
- dev->name);
- return;
- }
+ return;
+ }
- /* Check Duplex mismatch */
- switch (aux & PHY_B_AS_AN_RES_MSK) {
- case PHY_B_RES_1000FD:
- skge->duplex = DUPLEX_FULL;
- break;
- case PHY_B_RES_1000HD:
- skge->duplex = DUPLEX_HALF;
- break;
- default:
- printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
- dev->name);
- return;
- }
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ u16 lpa, aux;
+ if (!(status & PHY_ST_AN_OVER))
+ return;
- /* We are using IEEE 802.3z/D5.0 Table 37-4 */
- switch (aux & PHY_B_AS_PAUSE_MSK) {
- case PHY_B_AS_PAUSE_MSK:
- skge->flow_control = FLOW_MODE_SYMMETRIC;
- break;
- case PHY_B_AS_PRR:
- skge->flow_control = FLOW_MODE_REM_SEND;
- break;
- case PHY_B_AS_PRT:
- skge->flow_control = FLOW_MODE_LOC_SEND;
- break;
- default:
- skge->flow_control = FLOW_MODE_NONE;
- }
+ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
+ if (lpa & PHY_B_AN_RF) {
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
+ dev->name);
+ return;
+ }
+
+ aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
- skge->speed = SPEED_1000;
+ /* Check Duplex mismatch */
+ switch (aux & PHY_B_AS_AN_RES_MSK) {
+ case PHY_B_RES_1000FD:
+ skge->duplex = DUPLEX_FULL;
+ break;
+ case PHY_B_RES_1000HD:
+ skge->duplex = DUPLEX_HALF;
+ break;
+ default:
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+ dev->name);
+ return;
}
- if (!netif_carrier_ok(dev))
- genesis_link_up(skge);
+
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ switch (aux & PHY_B_AS_PAUSE_MSK) {
+ case PHY_B_AS_PAUSE_MSK:
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+ break;
+ case PHY_B_AS_PRR:
+ skge->flow_control = FLOW_MODE_REM_SEND;
+ break;
+ case PHY_B_AS_PRT:
+ skge->flow_control = FLOW_MODE_LOC_SEND;
+ break;
+ default:
+ skge->flow_control = FLOW_MODE_NONE;
+ }
+ skge->speed = SPEED_1000;
}
+
+ if (!netif_carrier_ok(dev))
+ genesis_link_up(skge);
}
/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
* Phy on for 100 or 10Mbit operation
*/
-static void bcom_phy_init(struct skge_port *skge, int jumbo)
+static void bcom_phy_init(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
@@ -1145,7 +1164,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
/* Handle Jumbo frames */
- if (jumbo) {
+ if (hw->dev[port]->mtu > ETH_DATA_LEN) {
xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
@@ -1158,8 +1177,154 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
/* Use link status change interrupt */
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+}
+
+static void xm_phy_init(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ u16 ctrl = 0;
+
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ if (skge->advertising & ADVERTISED_1000baseT_Half)
+ ctrl |= PHY_X_AN_HD;
+ if (skge->advertising & ADVERTISED_1000baseT_Full)
+ ctrl |= PHY_X_AN_FD;
+
+ switch(skge->flow_control) {
+ case FLOW_MODE_NONE:
+ ctrl |= PHY_X_P_NO_PAUSE;
+ break;
+ case FLOW_MODE_LOC_SEND:
+ ctrl |= PHY_X_P_ASYM_MD;
+ break;
+ case FLOW_MODE_SYMMETRIC:
+ ctrl |= PHY_X_P_BOTH_MD;
+ break;
+ }
+
+ xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
+
+ /* Restart Auto-negotiation */
+ ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+ } else {
+ /* Set DuplexMode in Config register */
+ if (skge->duplex == DUPLEX_FULL)
+ ctrl |= PHY_CT_DUP_MD;
+ /*
+ * Do NOT enable Auto-negotiation here. This would hold
+ * the link down because no IDLEs are transmitted
+ */
+ }
+
+ xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
+
+ /* Poll PHY for status changes */
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
+}
+
+static void xm_check_link(struct net_device *dev)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ u16 status;
+
+ /* read twice because of latch */
+ (void) xm_phy_read(hw, port, PHY_XMAC_STAT);
+ status = xm_phy_read(hw, port, PHY_XMAC_STAT);
+
+ if ((status & PHY_ST_LSYNC) == 0) {
+ u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
+ cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
+ /* dummy read to ensure writing */
+ (void) xm_read16(hw, port, XM_MMU_CMD);
+
+ if (netif_carrier_ok(dev))
+ skge_link_down(skge);
+ return;
+ }
+
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ u16 lpa, res;
+
+ if (!(status & PHY_ST_AN_OVER))
+ return;
+
+ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
+ if (lpa & PHY_B_AN_RF) {
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
+ dev->name);
+ return;
+ }
+
+ res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
+
+ /* Check Duplex mismatch */
+ switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) {
+ case PHY_X_RS_FD:
+ skge->duplex = DUPLEX_FULL;
+ break;
+ case PHY_X_RS_HD:
+ skge->duplex = DUPLEX_HALF;
+ break;
+ default:
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+ dev->name);
+ return;
+ }
+
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ if (lpa & PHY_X_P_SYM_MD)
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+ else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
+ skge->flow_control = FLOW_MODE_REM_SEND;
+ else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
+ skge->flow_control = FLOW_MODE_LOC_SEND;
+ else
+ skge->flow_control = FLOW_MODE_NONE;
+
+
+ skge->speed = SPEED_1000;
+ }
+
+ if (!netif_carrier_ok(dev))
+ genesis_link_up(skge);
+}
+
+/* Poll to check for link coming up.
+ * Since internal PHY is wired to a level triggered pin, can't
+ * get an interrupt when carrier is detected.
+ */
+static void xm_link_timer(void *arg)
+{
+ struct net_device *dev = arg;
+ struct skge_port *skge = netdev_priv(arg);
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+
+ if (!netif_running(dev))
+ return;
+
+ if (netif_carrier_ok(dev)) {
+ xm_read16(hw, port, XM_ISRC);
+ if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
+ goto nochange;
+ } else {
+ if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
+ goto nochange;
+ xm_read16(hw, port, XM_ISRC);
+ if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
+ goto nochange;
+ }
+
+ mutex_lock(&hw->phy_mutex);
+ xm_check_link(dev);
+ mutex_unlock(&hw->phy_mutex);
- bcom_check_link(hw, port);
+nochange:
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
}
static void genesis_mac_init(struct skge_hw *hw, int port)
@@ -1190,20 +1355,29 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* namely for the 1000baseTX cards that use the XMAC's
* GMII mode.
*/
- /* Take external Phy out of reset */
- r = skge_read32(hw, B2_GP_IO);
- if (port == 0)
- r |= GP_DIR_0|GP_IO_0;
- else
- r |= GP_DIR_2|GP_IO_2;
+ if (hw->phy_type != SK_PHY_XMAC) {
+ /* Take external Phy out of reset */
+ r = skge_read32(hw, B2_GP_IO);
+ if (port == 0)
+ r |= GP_DIR_0|GP_IO_0;
+ else
+ r |= GP_DIR_2|GP_IO_2;
- skge_write32(hw, B2_GP_IO, r);
+ skge_write32(hw, B2_GP_IO, r);
+ /* Enable GMII interface */
+ xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+ }
- /* Enable GMII interface */
- xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
- bcom_phy_init(skge, jumbo);
+ switch(hw->phy_type) {
+ case SK_PHY_XMAC:
+ xm_phy_init(skge);
+ break;
+ case SK_PHY_BCOM:
+ bcom_phy_init(skge);
+ bcom_check_link(hw, port);
+ }
/* Set Station Address */
xm_outaddr(hw, port, XM_SA, dev->dev_addr);
@@ -1336,16 +1510,18 @@ static void genesis_stop(struct skge_port *skge)
skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
/* For external PHYs there must be special handling */
- reg = skge_read32(hw, B2_GP_IO);
- if (port == 0) {
- reg |= GP_DIR_0;
- reg &= ~GP_IO_0;
- } else {
- reg |= GP_DIR_2;
- reg &= ~GP_IO_2;
+ if (hw->phy_type != SK_PHY_XMAC) {
+ reg = skge_read32(hw, B2_GP_IO);
+ if (port == 0) {
+ reg |= GP_DIR_0;
+ reg &= ~GP_IO_0;
+ } else {
+ reg |= GP_DIR_2;
+ reg &= ~GP_IO_2;
+ }
+ skge_write32(hw, B2_GP_IO, reg);
+ skge_read32(hw, B2_GP_IO);
}
- skge_write32(hw, B2_GP_IO, reg);
- skge_read32(hw, B2_GP_IO);
xm_write16(hw, port, XM_MMU_CMD,
xm_read16(hw, port, XM_MMU_CMD)
@@ -1407,7 +1583,7 @@ static void genesis_link_up(struct skge_port *skge)
struct skge_hw *hw = skge->hw;
int port = skge->port;
u16 cmd;
- u32 mode, msk;
+ u32 mode;
cmd = xm_read16(hw, port, XM_MMU_CMD);
@@ -1455,27 +1631,24 @@ static void genesis_link_up(struct skge_port *skge)
}
xm_write32(hw, port, XM_MODE, mode);
-
- msk = XM_DEF_MSK;
- /* disable GP0 interrupt bit for external Phy */
- msk |= XM_IS_INP_ASS;
-
- xm_write16(hw, port, XM_IMSK, msk);
+ xm_write16(hw, port, XM_IMSK, XM_DEF_MSK);
xm_read16(hw, port, XM_ISRC);
/* get MMU Command Reg. */
cmd = xm_read16(hw, port, XM_MMU_CMD);
- if (skge->duplex == DUPLEX_FULL)
+ if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
cmd |= XM_MMU_GMII_FD;
/*
* Workaround BCOM Errata (#10523) for all BCom Phys
* Enable Power Management after link up
*/
- xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
- xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
- & ~PHY_B_AC_DIS_PM);
- xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+ if (hw->phy_type == SK_PHY_BCOM) {
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+ & ~PHY_B_AC_DIS_PM);
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+ }
/* enable Rx/Tx */
xm_write16(hw, port, XM_MMU_CMD,
@@ -2182,7 +2355,7 @@ static int skge_up(struct net_device *dev)
if (err)
goto free_pci_mem;
- err = skge_rx_fill(skge);
+ err = skge_rx_fill(dev);
if (err)
goto free_rx_ring;
@@ -2215,6 +2388,7 @@ static int skge_up(struct net_device *dev)
skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F);
skge_led(skge, LED_MODE_ON);
+ netif_poll_enable(dev);
return 0;
free_rx_ring:
@@ -2240,6 +2414,8 @@ static int skge_down(struct net_device *dev)
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
netif_stop_queue(dev);
+ if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
+ cancel_rearming_delayed_work(&skge->link_thread);
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
if (hw->chip_id == CHIP_ID_GENESIS)
@@ -2283,7 +2459,8 @@ static int skge_down(struct net_device *dev)
skge_led(skge, LED_MODE_OFF);
- skge_tx_clean(skge);
+ netif_poll_disable(dev);
+ skge_tx_clean(dev);
skge_rx_clean(skge);
kfree(skge->rx_ring.start);
@@ -2308,25 +2485,12 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
int i;
u32 control, len;
u64 map;
- unsigned long flags;
if (skb_padto(skb, ETH_ZLEN))
return NETDEV_TX_OK;
- if (!spin_trylock_irqsave(&skge->tx_lock, flags))
- /* Collision - tell upper layer to requeue */
- return NETDEV_TX_LOCKED;
-
- if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) {
- if (!netif_queue_stopped(dev)) {
- netif_stop_queue(dev);
-
- printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
- dev->name);
- }
- spin_unlock_irqrestore(&skge->tx_lock, flags);
+ if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1))
return NETDEV_TX_BUSY;
- }
e = skge->tx_ring.to_use;
td = e->desc;
@@ -2340,7 +2504,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
td->dma_lo = map;
td->dma_hi = map >> 32;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
int offset = skb->h.raw - skb->data;
/* This seems backwards, but it is what the sk98lin
@@ -2401,8 +2565,6 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
}
- spin_unlock_irqrestore(&skge->tx_lock, flags);
-
dev->trans_start = jiffies;
return NETDEV_TX_OK;
@@ -2432,18 +2594,18 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e,
printk(KERN_DEBUG PFX "%s: tx done slot %td\n",
skge->netdev->name, e - skge->tx_ring.start);
- dev_kfree_skb_any(e->skb);
+ dev_kfree_skb(e->skb);
}
e->skb = NULL;
}
/* Free all buffers in transmit ring */
-static void skge_tx_clean(struct skge_port *skge)
+static void skge_tx_clean(struct net_device *dev)
{
+ struct skge_port *skge = netdev_priv(dev);
struct skge_element *e;
- unsigned long flags;
- spin_lock_irqsave(&skge->tx_lock, flags);
+ netif_tx_lock_bh(dev);
for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
struct skge_tx_desc *td = e->desc;
skge_tx_free(skge, e, td->control);
@@ -2451,8 +2613,8 @@ static void skge_tx_clean(struct skge_port *skge)
}
skge->tx_ring.to_clean = e;
- netif_wake_queue(skge->netdev);
- spin_unlock_irqrestore(&skge->tx_lock, flags);
+ netif_wake_queue(dev);
+ netif_tx_unlock_bh(dev);
}
static void skge_tx_timeout(struct net_device *dev)
@@ -2463,7 +2625,7 @@ static void skge_tx_timeout(struct net_device *dev)
printk(KERN_DEBUG PFX "%s: tx timeout\n", dev->name);
skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_STOP);
- skge_tx_clean(skge);
+ skge_tx_clean(dev);
}
static int skge_change_mtu(struct net_device *dev, int new_mtu)
@@ -2586,16 +2748,17 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
/* Get receive buffer from descriptor.
* Handles copy of small buffers and reallocation failures
*/
-static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
- struct skge_element *e,
- u32 control, u32 status, u16 csum)
+static struct sk_buff *skge_rx_get(struct net_device *dev,
+ struct skge_element *e,
+ u32 control, u32 status, u16 csum)
{
+ struct skge_port *skge = netdev_priv(dev);
struct sk_buff *skb;
u16 len = control & BMU_BBC;
if (unlikely(netif_msg_rx_status(skge)))
printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
- skge->netdev->name, e - skge->rx_ring.start,
+ dev->name, e - skge->rx_ring.start,
status, len);
if (len > skge->rx_buf_size)
@@ -2611,7 +2774,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
goto error;
if (len < RX_COPY_THRESHOLD) {
- skb = alloc_skb(len + 2, GFP_ATOMIC);
+ skb = netdev_alloc_skb(dev, len + 2);
if (!skb)
goto resubmit;
@@ -2626,7 +2789,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
skge_rx_reuse(e, skge->rx_buf_size);
} else {
struct sk_buff *nskb;
- nskb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_ATOMIC);
+ nskb = netdev_alloc_skb(dev, skge->rx_buf_size + NET_IP_ALIGN);
if (!nskb)
goto resubmit;
@@ -2641,20 +2804,19 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
}
skb_put(skb, len);
- skb->dev = skge->netdev;
if (skge->rx_csum) {
skb->csum = csum;
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
}
- skb->protocol = eth_type_trans(skb, skge->netdev);
+ skb->protocol = eth_type_trans(skb, dev);
return skb;
error:
if (netif_msg_rx_err(skge))
printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n",
- skge->netdev->name, e - skge->rx_ring.start,
+ dev->name, e - skge->rx_ring.start,
control, status);
if (skge->hw->chip_id == CHIP_ID_GENESIS) {
@@ -2679,15 +2841,15 @@ resubmit:
}
/* Free all buffers in Tx ring which are no longer owned by device */
-static void skge_txirq(struct net_device *dev)
+static void skge_tx_done(struct net_device *dev)
{
struct skge_port *skge = netdev_priv(dev);
struct skge_ring *ring = &skge->tx_ring;
struct skge_element *e;
- rmb();
+ skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
- spin_lock(&skge->tx_lock);
+ netif_tx_lock(dev);
for (e = ring->to_clean; e != ring->to_use; e = e->next) {
struct skge_tx_desc *td = e->desc;
@@ -2698,11 +2860,10 @@ static void skge_txirq(struct net_device *dev)
}
skge->tx_ring.to_clean = e;
- if (netif_queue_stopped(skge->netdev)
- && skge_avail(&skge->tx_ring) > TX_LOW_WATER)
- netif_wake_queue(skge->netdev);
+ if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
+ netif_wake_queue(dev);
- spin_unlock(&skge->tx_lock);
+ netif_tx_unlock(dev);
}
static int skge_poll(struct net_device *dev, int *budget)
@@ -2714,6 +2875,10 @@ static int skge_poll(struct net_device *dev, int *budget)
int to_do = min(dev->quota, *budget);
int work_done = 0;
+ skge_tx_done(dev);
+
+ skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
+
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;
@@ -2724,7 +2889,7 @@ static int skge_poll(struct net_device *dev, int *budget)
if (control & BMU_OWN)
break;
- skb = skge_rx_get(skge, e, control, rd->status, rd->csum2);
+ skb = skge_rx_get(dev, e, control, rd->status, rd->csum2);
if (likely(skb)) {
dev->last_rx = jiffies;
netif_receive_skb(skb);
@@ -2744,12 +2909,11 @@ static int skge_poll(struct net_device *dev, int *budget)
if (work_done >= to_do)
return 1; /* not done */
- netif_rx_complete(dev);
-
spin_lock_irq(&hw->hw_lock);
- hw->intr_mask |= rxirqmask[skge->port];
+ __netif_rx_complete(dev);
+ hw->intr_mask |= irqmask[skge->port];
skge_write32(hw, B0_IMSK, hw->intr_mask);
- mmiowb();
+ skge_read32(hw, B0_IMSK);
spin_unlock_irq(&hw->hw_lock);
return 0;
@@ -2874,7 +3038,7 @@ static void skge_extirq(void *arg)
if (netif_running(dev)) {
if (hw->chip_id != CHIP_ID_GENESIS)
yukon_phy_intr(skge);
- else
+ else if (hw->phy_type == SK_PHY_BCOM)
bcom_phy_intr(skge);
}
}
@@ -2883,6 +3047,7 @@ static void skge_extirq(void *arg)
spin_lock_irq(&hw->hw_lock);
hw->intr_mask |= IS_EXT_REG;
skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_read32(hw, B0_IMSK);
spin_unlock_irq(&hw->hw_lock);
}
@@ -2890,27 +3055,23 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct skge_hw *hw = dev_id;
u32 status;
+ int handled = 0;
+ spin_lock(&hw->hw_lock);
/* Reading this register masks IRQ */
status = skge_read32(hw, B0_SP_ISRC);
- if (status == 0)
- return IRQ_NONE;
+ if (status == 0 || status == ~0)
+ goto out;
- spin_lock(&hw->hw_lock);
+ handled = 1;
status &= hw->intr_mask;
if (status & IS_EXT_REG) {
hw->intr_mask &= ~IS_EXT_REG;
schedule_work(&hw->phy_work);
}
- if (status & IS_XA1_F) {
- skge_write8(hw, Q_ADDR(Q_XA1, Q_CSR), CSR_IRQ_CL_F);
- skge_txirq(hw->dev[0]);
- }
-
- if (status & IS_R1_F) {
- skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F);
- hw->intr_mask &= ~IS_R1_F;
+ if (status & (IS_XA1_F|IS_R1_F)) {
+ hw->intr_mask &= ~(IS_XA1_F|IS_R1_F);
netif_rx_schedule(hw->dev[0]);
}
@@ -2929,14 +3090,8 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
skge_mac_intr(hw, 0);
if (hw->dev[1]) {
- if (status & IS_XA2_F) {
- skge_write8(hw, Q_ADDR(Q_XA2, Q_CSR), CSR_IRQ_CL_F);
- skge_txirq(hw->dev[1]);
- }
-
- if (status & IS_R2_F) {
- skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F);
- hw->intr_mask &= ~IS_R2_F;
+ if (status & (IS_XA2_F|IS_R2_F)) {
+ hw->intr_mask &= ~(IS_XA2_F|IS_R2_F);
netif_rx_schedule(hw->dev[1]);
}
@@ -2957,9 +3112,11 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
skge_error_irq(hw);
skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_read32(hw, B0_IMSK);
+out:
spin_unlock(&hw->hw_lock);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(handled);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3033,7 +3190,7 @@ static int skge_reset(struct skge_hw *hw)
{
u32 reg;
u16 ctst, pci_status;
- u8 t8, mac_cfg, pmd_type, phy_type;
+ u8 t8, mac_cfg, pmd_type;
int i;
ctst = skge_read16(hw, B0_CTST);
@@ -3057,19 +3214,22 @@ static int skge_reset(struct skge_hw *hw)
ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
hw->chip_id = skge_read8(hw, B2_CHIP_ID);
- phy_type = skge_read8(hw, B2_E_1) & 0xf;
+ hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
pmd_type = skge_read8(hw, B2_PMD_TYP);
hw->copper = (pmd_type == 'T' || pmd_type == '1');
switch (hw->chip_id) {
case CHIP_ID_GENESIS:
- switch (phy_type) {
+ switch (hw->phy_type) {
+ case SK_PHY_XMAC:
+ hw->phy_addr = PHY_ADDR_XMAC;
+ break;
case SK_PHY_BCOM:
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
- pci_name(hw->pdev), phy_type);
+ pci_name(hw->pdev), hw->phy_type);
return -EOPNOTSUPP;
}
break;
@@ -3077,7 +3237,7 @@ static int skge_reset(struct skge_hw *hw)
case CHIP_ID_YUKON:
case CHIP_ID_YUKON_LITE:
case CHIP_ID_YUKON_LP:
- if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
+ if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
hw->copper = 1;
hw->phy_addr = PHY_ADDR_MARV;
@@ -3108,11 +3268,13 @@ static int skge_reset(struct skge_hw *hw)
else
hw->ram_size = t8 * 4096;
- spin_lock_init(&hw->hw_lock);
- hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
+ hw->intr_mask = IS_HW_ERR | IS_PORT_1;
if (hw->ports > 1)
hw->intr_mask |= IS_PORT_2;
+ if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
+ hw->intr_mask |= IS_EXT_REG;
+
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_init(hw);
else {
@@ -3224,7 +3386,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
dev->poll_controller = skge_netpoll;
#endif
dev->irq = hw->pdev->irq;
- dev->features = NETIF_F_LLTX;
+
if (highmem)
dev->features |= NETIF_F_HIGHDMA;
@@ -3246,7 +3408,8 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
skge->port = port;
- spin_lock_init(&skge->tx_lock);
+ /* Only used for Genesis XMAC */
+ INIT_WORK(&skge->link_thread, xm_link_timer, dev);
if (hw->chip_id != CHIP_ID_GENESIS) {
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
@@ -3334,6 +3497,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
hw->pdev = pdev;
mutex_init(&hw->phy_mutex);
INIT_WORK(&hw->phy_work, skge_extirq, hw);
+ spin_lock_init(&hw->hw_lock);
hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
if (!hw->regs) {
@@ -3342,23 +3506,16 @@ static int __devinit skge_probe(struct pci_dev *pdev,
goto err_out_free_hw;
}
- err = request_irq(pdev->irq, skge_intr, SA_SHIRQ, DRV_NAME, hw);
- if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
- goto err_out_iounmap;
- }
- pci_set_drvdata(pdev, hw);
-
err = skge_reset(hw);
if (err)
- goto err_out_free_irq;
+ goto err_out_iounmap;
- printk(KERN_INFO PFX DRV_VERSION " addr 0x%lx irq %d chip %s rev %d\n",
- pci_resource_start(pdev, 0), pdev->irq,
+ printk(KERN_INFO PFX DRV_VERSION " addr 0x%llx irq %d chip %s rev %d\n",
+ (unsigned long long)pci_resource_start(pdev, 0), pdev->irq,
skge_board_name(hw), hw->chip_rev);
- if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
+ dev = skge_devinit(hw, 0, using_dac);
+ if (!dev)
goto err_out_led_off;
if (!is_valid_ether_addr(dev->dev_addr)) {
@@ -3368,7 +3525,6 @@ static int __devinit skge_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
-
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "%s: cannot register net device\n",
@@ -3376,6 +3532,12 @@ static int __devinit skge_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
+ err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
+ if (err) {
+ printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+ dev->name, pdev->irq);
+ goto err_out_unregister;
+ }
skge_show_addr(dev);
if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
@@ -3388,15 +3550,16 @@ static int __devinit skge_probe(struct pci_dev *pdev,
free_netdev(dev1);
}
}
+ pci_set_drvdata(pdev, hw);
return 0;
+err_out_unregister:
+ unregister_netdev(dev);
err_out_free_netdev:
free_netdev(dev);
err_out_led_off:
skge_write16(hw, B0_LED, LED_STAT_OFF);
-err_out_free_irq:
- free_irq(pdev->irq, hw);
err_out_iounmap:
iounmap(hw->regs);
err_out_free_hw:
@@ -3426,6 +3589,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
spin_lock_irq(&hw->hw_lock);
hw->intr_mask = 0;
skge_write32(hw, B0_IMSK, 0);
+ skge_read32(hw, B0_IMSK);
spin_unlock_irq(&hw->hw_lock);
skge_write16(hw, B0_LED, LED_STAT_OFF);
@@ -3451,26 +3615,25 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, wol = 0;
- for (i = 0; i < 2; i++) {
+ pci_save_state(pdev);
+ for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- if (dev) {
+ if (netif_running(dev)) {
struct skge_port *skge = netdev_priv(dev);
- if (netif_running(dev)) {
- netif_carrier_off(dev);
- if (skge->wol)
- netif_stop_queue(dev);
- else
- skge_down(dev);
- }
- netif_device_detach(dev);
+
+ netif_carrier_off(dev);
+ if (skge->wol)
+ netif_stop_queue(dev);
+ else
+ skge_down(dev);
wol |= skge->wol;
}
+ netif_device_detach(dev);
}
- pci_save_state(pdev);
+ skge_write32(hw, B0_IMSK, 0);
pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
- pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
@@ -3479,23 +3642,33 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
static int skge_resume(struct pci_dev *pdev)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
- int i;
+ int i, err;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_wake(pdev, PCI_D0, 0);
- skge_reset(hw);
+ err = skge_reset(hw);
+ if (err)
+ goto out;
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- if (dev) {
- netif_device_attach(dev);
- if (netif_running(dev) && skge_up(dev))
+
+ netif_device_attach(dev);
+ if (netif_running(dev)) {
+ err = skge_up(dev);
+
+ if (err) {
+ printk(KERN_ERR PFX "%s: could not up: %d\n",
+ dev->name, err);
dev_close(dev);
+ goto out;
+ }
}
}
- return 0;
+out:
+ return err;
}
#endif
@@ -3512,7 +3685,7 @@ static struct pci_driver skge_driver = {
static int __init skge_init_module(void)
{
- return pci_module_init(&skge_driver);
+ return pci_register_driver(&skge_driver);
}
static void __exit skge_cleanup_module(void)
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index ed19ff47ce1..d0b47d46cf9 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -934,7 +934,7 @@ enum {
PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */
PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
+ PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */
@@ -1097,13 +1097,36 @@ enum {
/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
enum {
- PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */
+ PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */
PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */
PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */
PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */
};
+/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/
+enum {
+ PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */
+ PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */
+};
+
+/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/
+enum {
+ PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */
+ PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */
+ PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */
+ PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */
+ PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */
+};
+
+/* Remote Fault Bits (PHY_X_AN_RFB) encoding */
+enum {
+ X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */
+ X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */
+ X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */
+ X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */
+};
+
/* Broadcom-Specific */
/***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
enum {
@@ -1734,11 +1757,11 @@ enum {
GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */
GM_TXCR_CRC_DIS = 1<<14, /* Bit 14: Disable insertion of CRC */
GM_TXCR_PAD_DIS = 1<<13, /* Bit 13: Disable padding of packets */
- GM_TXCR_COL_THR_MSK = 1<<10, /* Bit 12..10: Collision Threshold */
+ GM_TXCR_COL_THR_MSK = 7<<10, /* Bit 12..10: Collision Threshold */
};
#define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK)
-#define TX_COL_DEF 0x04
+#define TX_COL_DEF 0x04 /* late collision after 64 byte */
/* GM_RX_CTRL 16 bit r/w Receive Control Register */
enum {
@@ -2158,8 +2181,8 @@ enum {
XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */
XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */
XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */
- XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
- XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
+ XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
+ XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */
XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */
XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */
@@ -2172,9 +2195,7 @@ enum {
XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
};
-#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \
- XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \
- XM_IS_RXF_OV | XM_IS_TXF_UR))
+#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR))
/* XM_HW_CFG 16 bit r/w Hardware Config Register */
@@ -2396,6 +2417,7 @@ struct skge_hw {
u8 chip_rev;
u8 copper;
u8 ports;
+ u8 phy_type;
u32 ram_size;
u32 ram_offset;
@@ -2417,12 +2439,12 @@ struct skge_port {
struct net_device *netdev;
int port;
- spinlock_t tx_lock;
struct skge_ring tx_ring;
struct skge_ring rx_ring;
struct net_device_stats net_stats;
+ struct work_struct link_thread;
u8 rx_csum;
u8 blink_on;
u8 flow_control;
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index d3577871be2..7eeefa2d6c8 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -23,7 +23,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/version.h>
@@ -51,7 +50,7 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.4"
+#define DRV_VERSION "1.7"
#define PFX DRV_NAME " "
/*
@@ -66,6 +65,7 @@
#define RX_MAX_PENDING (RX_LE_SIZE/2 - 2)
#define RX_DEF_PENDING RX_MAX_PENDING
#define RX_SKB_ALIGN 8
+#define RX_BUF_WRITE 16
#define TX_RING_SIZE 512
#define TX_DEF_PENDING (TX_RING_SIZE - 1)
@@ -106,6 +106,7 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) },
{ PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) }, /* DGE-560T */
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) }, /* DGE-550SX */
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) },
@@ -117,10 +118,17 @@ static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4350) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4351) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4352) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4353) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4360) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4361) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4362) },
{ PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4363) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4364) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4365) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) },
{ 0 }
};
@@ -190,7 +198,6 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
{
u16 power_control;
- u32 reg1;
int vaux;
pr_debug("sky2_set_power_state %d\n", state);
@@ -223,19 +230,9 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
else
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
- /* Turn off phy power saving */
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
- reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
-
- /* looks like this XL is back asswards .. */
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1) {
- reg1 |= PCI_Y2_PHY1_COMA;
- if (hw->ports > 1)
- reg1 |= PCI_Y2_PHY2_COMA;
- }
-
if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- sky2_write16(hw, B0_CTST, Y2_HW_WOL_ON);
+ u32 reg1;
+
sky2_pci_write32(hw, PCI_DEV_REG3, 0);
reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
reg1 &= P_ASPM_CONTROL_MSK;
@@ -243,20 +240,10 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
sky2_pci_write32(hw, PCI_DEV_REG5, 0);
}
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
-
break;
case PCI_D3hot:
case PCI_D3cold:
- /* Turn on phy power saving */
- reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
- if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
- reg1 &= ~(PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
- else
- reg1 |= (PCI_Y2_PHY1_POWD | PCI_Y2_PHY2_POWD);
- sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
-
if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
sky2_write8(hw, B2_Y2_CLK_GATE, 0);
else
@@ -280,7 +267,7 @@ static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
-static void sky2_phy_reset(struct sky2_hw *hw, unsigned port)
+static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
{
u16 reg;
@@ -302,7 +289,7 @@ static void sky2_phy_reset(struct sky2_hw *hw, unsigned port)
static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
- u16 ctrl, ct1000, adv, pg, ledctrl, ledover;
+ u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
if (sky2->autoneg == AUTONEG_ENABLE &&
!(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
@@ -321,7 +308,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
}
ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
- if (hw->copper) {
+ if (sky2_is_copper(hw)) {
if (hw->chip_id == CHIP_ID_YUKON_FE) {
/* enable automatic crossover */
ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO) >> 1;
@@ -338,25 +325,37 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
}
}
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
} else {
/* workaround for deviation #4.88 (CRC errors) */
/* disable Automatic Crossover */
ctrl &= ~PHY_M_PC_MDIX_MSK;
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+ }
- if (hw->chip_id == CHIP_ID_YUKON_XL) {
- /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
- gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
- ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
- ctrl &= ~PHY_M_MAC_MD_MSK;
- ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX);
- gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+ /* special setup for PHY 88E1112 Fiber */
+ if (hw->chip_id == CHIP_ID_YUKON_XL && !sky2_is_copper(hw)) {
+ pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
+ /* Fiber: select 1000BASE-X only mode MAC Specific Ctrl Reg. */
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 2);
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+ ctrl &= ~PHY_M_MAC_MD_MSK;
+ ctrl |= PHY_M_MAC_MODE_SEL(PHY_M_MAC_MD_1000BX);
+ gm_phy_write(hw, port, PHY_MARV_PHY_CTRL, ctrl);
+
+ if (hw->pmd_type == 'P') {
/* select page 1 to access Fiber registers */
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 1);
+
+ /* for SFP-module set SIGDET polarity to low */
+ ctrl = gm_phy_read(hw, port, PHY_MARV_PHY_CTRL);
+ ctrl |= PHY_M_FIB_SIGD_POL;
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
}
+
+ gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
}
ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
@@ -371,9 +370,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
ctrl = 0;
ct1000 = 0;
adv = PHY_AN_CSMA;
+ reg = 0;
if (sky2->autoneg == AUTONEG_ENABLE) {
- if (hw->copper) {
+ if (sky2_is_copper(hw)) {
if (sky2->advertising & ADVERTISED_1000baseT_Full)
ct1000 |= PHY_M_1000C_AFD;
if (sky2->advertising & ADVERTISED_1000baseT_Half)
@@ -386,8 +386,12 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
adv |= PHY_M_AN_10_FD;
if (sky2->advertising & ADVERTISED_10baseT_Half)
adv |= PHY_M_AN_10_HD;
- } else /* special defines for FIBER (88E1011S only) */
- adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
+ } else { /* special defines for FIBER (88E1040S only) */
+ if (sky2->advertising & ADVERTISED_1000baseT_Full)
+ adv |= PHY_M_AN_1000X_AFD;
+ if (sky2->advertising & ADVERTISED_1000baseT_Half)
+ adv |= PHY_M_AN_1000X_AHD;
+ }
/* Set Flow-control capabilities */
if (sky2->tx_pause && sky2->rx_pause)
@@ -403,21 +407,46 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* forced speed/duplex settings */
ct1000 = PHY_M_1000C_MSE;
- if (sky2->duplex == DUPLEX_FULL)
- ctrl |= PHY_CT_DUP_MD;
+ /* Disable auto update for duplex flow control and speed */
+ reg |= GM_GPCR_AU_ALL_DIS;
switch (sky2->speed) {
case SPEED_1000:
ctrl |= PHY_CT_SP1000;
+ reg |= GM_GPCR_SPEED_1000;
break;
case SPEED_100:
ctrl |= PHY_CT_SP100;
+ reg |= GM_GPCR_SPEED_100;
break;
}
+ if (sky2->duplex == DUPLEX_FULL) {
+ reg |= GM_GPCR_DUP_FULL;
+ ctrl |= PHY_CT_DUP_MD;
+ } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) {
+ /* Turn off flow control for 10/100mbps */
+ sky2->rx_pause = 0;
+ sky2->tx_pause = 0;
+ }
+
+ if (!sky2->rx_pause)
+ reg |= GM_GPCR_FC_RX_DIS;
+
+ if (!sky2->tx_pause)
+ reg |= GM_GPCR_FC_TX_DIS;
+
+ /* Forward pause packets to GMAC? */
+ if (sky2->tx_pause || sky2->rx_pause)
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+ else
+ sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+
ctrl |= PHY_CT_RESET;
}
+ gma_write16(hw, port, GM_GP_CTRL, reg);
+
if (hw->chip_id != CHIP_ID_YUKON_FE)
gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
@@ -521,6 +550,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
}
+
/* Enable phy interrupt on auto-negotiation complete (or link up) */
if (sky2->autoneg == AUTONEG_ENABLE)
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
@@ -528,6 +558,29 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
}
+static void sky2_phy_power(struct sky2_hw *hw, unsigned port, int onoff)
+{
+ u32 reg1;
+ static const u32 phy_power[]
+ = { PCI_Y2_PHY1_POWD, PCI_Y2_PHY2_POWD };
+
+ /* looks like this XL is back asswards .. */
+ if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+ onoff = !onoff;
+
+ reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+
+ if (onoff)
+ /* Turn off phy power saving */
+ reg1 &= ~phy_power[port];
+ else
+ reg1 |= phy_power[port];
+
+ sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+ sky2_pci_read32(hw, PCI_DEV_REG1);
+ udelay(100);
+}
+
/* Force a renegotiation */
static void sky2_phy_reinit(struct sky2_port *sky2)
{
@@ -560,49 +613,11 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
gm_phy_read(hw, 1, PHY_MARV_INT_MASK) != 0);
}
- if (sky2->autoneg == AUTONEG_DISABLE) {
- reg = gma_read16(hw, port, GM_GP_CTRL);
- reg |= GM_GPCR_AU_ALL_DIS;
- gma_write16(hw, port, GM_GP_CTRL, reg);
- gma_read16(hw, port, GM_GP_CTRL);
-
- switch (sky2->speed) {
- case SPEED_1000:
- reg &= ~GM_GPCR_SPEED_100;
- reg |= GM_GPCR_SPEED_1000;
- break;
- case SPEED_100:
- reg &= ~GM_GPCR_SPEED_1000;
- reg |= GM_GPCR_SPEED_100;
- break;
- case SPEED_10:
- reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
- break;
- }
-
- if (sky2->duplex == DUPLEX_FULL)
- reg |= GM_GPCR_DUP_FULL;
-
- /* turn off pause in 10/100mbps half duplex */
- else if (sky2->speed != SPEED_1000 &&
- hw->chip_id != CHIP_ID_YUKON_EC_U)
- sky2->tx_pause = sky2->rx_pause = 0;
- } else
- reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
-
- if (!sky2->tx_pause && !sky2->rx_pause) {
- sky2_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
- reg |=
- GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
- } else if (sky2->tx_pause && !sky2->rx_pause) {
- /* disable Rx flow-control */
- reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
- }
-
- gma_write16(hw, port, GM_GP_CTRL, reg);
-
sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
+ /* Enable Transmit FIFO Underrun */
+ sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
+
spin_lock_bh(&sky2->phy_lock);
sky2_phy_init(hw, port);
spin_unlock_bh(&sky2->phy_lock);
@@ -760,9 +775,10 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2)
/* Update chip's next pointer */
static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
{
+ q = Y2_QADDR(q, PREF_UNIT_PUT_IDX);
wmb();
- sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx);
- mmiowb();
+ sky2_write16(hw, q, idx);
+ sky2_read16(hw, q);
}
@@ -811,7 +827,7 @@ static void rx_set_checksum(struct sky2_port *sky2)
struct sky2_rx_le *le;
le = sky2_next_rx(sky2);
- le->addr = (ETH_HLEN << 16) | ETH_HLEN;
+ le->addr = cpu_to_le32((ETH_HLEN << 16) | ETH_HLEN);
le->ctrl = 0;
le->opcode = OP_TCPSTART | HW_OWNER;
@@ -949,14 +965,16 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
/*
* It appears the hardware has a bug in the FIFO logic that
* cause it to hang if the FIFO gets overrun and the receive buffer
- * is not aligned. ALso alloc_skb() won't align properly if slab
- * debugging is enabled.
+ * is not 64 byte aligned. The buffer returned from netdev_alloc_skb is
+ * aligned except if slab debugging is enabled.
*/
-static inline struct sk_buff *sky2_alloc_skb(unsigned int size, gfp_t gfp_mask)
+static inline struct sk_buff *sky2_alloc_skb(struct net_device *dev,
+ unsigned int length,
+ gfp_t gfp_mask)
{
struct sk_buff *skb;
- skb = alloc_skb(size + RX_SKB_ALIGN, gfp_mask);
+ skb = __netdev_alloc_skb(dev, length + RX_SKB_ALIGN, gfp_mask);
if (likely(skb)) {
unsigned long p = (unsigned long) skb->data;
skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
@@ -992,7 +1010,8 @@ static int sky2_rx_start(struct sky2_port *sky2)
for (i = 0; i < sky2->rx_pending; i++) {
struct ring_info *re = sky2->rx_ring + i;
- re->skb = sky2_alloc_skb(sky2->rx_bufsize, GFP_KERNEL);
+ re->skb = sky2_alloc_skb(sky2->netdev, sky2->rx_bufsize,
+ GFP_KERNEL);
if (!re->skb)
goto nomem;
@@ -1080,6 +1099,8 @@ static int sky2_up(struct net_device *dev)
if (!sky2->rx_ring)
goto err_out;
+ sky2_phy_power(hw, port, 1);
+
sky2_mac_init(hw, port);
/* Determine available ram buffer space (in 4K blocks).
@@ -1160,10 +1181,10 @@ static unsigned tx_le_req(const struct sk_buff *skb)
count = sizeof(dma_addr_t) / sizeof(u32);
count += skb_shinfo(skb)->nr_frags * count;
- if (skb_shinfo(skb)->gso_size)
+ if (skb_is_gso(skb))
++count;
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
++count;
return count;
@@ -1184,7 +1205,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
struct sky2_tx_le *le = NULL;
struct tx_ring_info *re;
unsigned i, len;
- int avail;
dma_addr_t mapping;
u32 addr64;
u16 mss;
@@ -1225,7 +1245,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Send high bits if changed or crosses boundary */
if (addr64 != sky2->tx_addr64 || high32(mapping + len) != sky2->tx_addr64) {
le = get_tx_le(sky2);
- le->tx.addr = cpu_to_le32(addr64);
+ le->addr = cpu_to_le32(addr64);
le->ctrl = 0;
le->opcode = OP_ADDR64 | HW_OWNER;
sky2->tx_addr64 = high32(mapping + len);
@@ -1234,25 +1254,17 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* Check for TCP Segmentation Offload */
mss = skb_shinfo(skb)->gso_size;
if (mss != 0) {
- /* just drop the packet if non-linear expansion fails */
- if (skb_header_cloned(skb) &&
- pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
- dev_kfree_skb(skb);
- goto out_unlock;
- }
-
mss += ((skb->h.th->doff - 5) * 4); /* TCP options */
mss += (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
mss += ETH_HLEN;
- }
- if (mss != sky2->tx_last_mss) {
- le = get_tx_le(sky2);
- le->tx.tso.size = cpu_to_le16(mss);
- le->tx.tso.rsvd = 0;
- le->opcode = OP_LRGLEN | HW_OWNER;
- le->ctrl = 0;
- sky2->tx_last_mss = mss;
+ if (mss != sky2->tx_last_mss) {
+ le = get_tx_le(sky2);
+ le->addr = cpu_to_le32(mss);
+ le->opcode = OP_LRGLEN | HW_OWNER;
+ le->ctrl = 0;
+ sky2->tx_last_mss = mss;
+ }
}
ctrl = 0;
@@ -1261,7 +1273,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
if (sky2->vlgrp && vlan_tx_tag_present(skb)) {
if (!le) {
le = get_tx_le(sky2);
- le->tx.addr = 0;
+ le->addr = 0;
le->opcode = OP_VLAN|HW_OWNER;
le->ctrl = 0;
} else
@@ -1272,24 +1284,30 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
#endif
/* Handle TCP checksum offload */
- if (skb->ip_summed == CHECKSUM_HW) {
- u16 hdr = skb->h.raw - skb->data;
- u16 offset = hdr + skb->csum;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ unsigned offset = skb->h.raw - skb->data;
+ u32 tcpsum;
+
+ tcpsum = offset << 16; /* sum start */
+ tcpsum |= offset + skb->csum; /* sum write */
ctrl = CALSUM | WR_SUM | INIT_SUM | LOCK_SUM;
if (skb->nh.iph->protocol == IPPROTO_UDP)
ctrl |= UDPTCP;
- le = get_tx_le(sky2);
- le->tx.csum.start = cpu_to_le16(hdr);
- le->tx.csum.offset = cpu_to_le16(offset);
- le->length = 0; /* initial checksum value */
- le->ctrl = 1; /* one packet */
- le->opcode = OP_TCPLISW | HW_OWNER;
+ if (tcpsum != sky2->tx_tcpsum) {
+ sky2->tx_tcpsum = tcpsum;
+
+ le = get_tx_le(sky2);
+ le->addr = cpu_to_le32(tcpsum);
+ le->length = 0; /* initial checksum value */
+ le->ctrl = 1; /* one packet */
+ le->opcode = OP_TCPLISW | HW_OWNER;
+ }
}
le = get_tx_le(sky2);
- le->tx.addr = cpu_to_le32((u32) mapping);
+ le->addr = cpu_to_le32((u32) mapping);
le->length = cpu_to_le16(len);
le->ctrl = ctrl;
le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER);
@@ -1307,36 +1325,31 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
addr64 = high32(mapping);
if (addr64 != sky2->tx_addr64) {
le = get_tx_le(sky2);
- le->tx.addr = cpu_to_le32(addr64);
+ le->addr = cpu_to_le32(addr64);
le->ctrl = 0;
le->opcode = OP_ADDR64 | HW_OWNER;
sky2->tx_addr64 = addr64;
}
le = get_tx_le(sky2);
- le->tx.addr = cpu_to_le32((u32) mapping);
+ le->addr = cpu_to_le32((u32) mapping);
le->length = cpu_to_le16(frag->size);
le->ctrl = ctrl;
le->opcode = OP_BUFFER | HW_OWNER;
fre = sky2->tx_ring
- + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE);
+ + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE);
pci_unmap_addr_set(fre, mapaddr, mapping);
}
re->idx = sky2->tx_prod;
le->ctrl |= EOP;
- avail = tx_avail(sky2);
- if (mss != 0 || avail < TX_MIN_PENDING) {
- le->ctrl |= FRC_STAT;
- if (avail <= MAX_SKB_TX_LE)
- netif_stop_queue(dev);
- }
+ if (tx_avail(sky2) <= MAX_SKB_TX_LE)
+ netif_stop_queue(dev);
sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod);
-out_unlock:
spin_unlock(&sky2->tx_lock);
dev->trans_start = jiffies;
@@ -1390,7 +1403,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
}
sky2->tx_cons = put;
- if (tx_avail(sky2) > MAX_SKB_TX_LE)
+ if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
netif_wake_queue(dev);
}
@@ -1421,7 +1434,7 @@ static int sky2_down(struct net_device *dev)
/* Stop more packets from being queued */
netif_stop_queue(dev);
- sky2_phy_reset(hw, port);
+ sky2_gmac_reset(hw, port);
/* Stop transmitter */
sky2_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), BMU_STOP);
@@ -1469,6 +1482,8 @@ static int sky2_down(struct net_device *dev)
imask &= ~portirq_msk[port];
sky2_write32(hw, B0_IMSK, imask);
+ sky2_phy_power(hw, port, 0);
+
/* turn off LED's */
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
@@ -1497,7 +1512,7 @@ static int sky2_down(struct net_device *dev)
static u16 sky2_phy_speed(const struct sky2_hw *hw, u16 aux)
{
- if (!hw->copper)
+ if (!sky2_is_copper(hw))
return SPEED_1000;
if (hw->chip_id == CHIP_ID_YUKON_FE)
@@ -1519,40 +1534,10 @@ static void sky2_link_up(struct sky2_port *sky2)
unsigned port = sky2->port;
u16 reg;
- /* Enable Transmit FIFO Underrun */
- sky2_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK);
-
- reg = gma_read16(hw, port, GM_GP_CTRL);
- if (sky2->autoneg == AUTONEG_DISABLE) {
- reg |= GM_GPCR_AU_ALL_DIS;
-
- /* Is write/read necessary? Copied from sky2_mac_init */
- gma_write16(hw, port, GM_GP_CTRL, reg);
- gma_read16(hw, port, GM_GP_CTRL);
-
- switch (sky2->speed) {
- case SPEED_1000:
- reg &= ~GM_GPCR_SPEED_100;
- reg |= GM_GPCR_SPEED_1000;
- break;
- case SPEED_100:
- reg &= ~GM_GPCR_SPEED_1000;
- reg |= GM_GPCR_SPEED_100;
- break;
- case SPEED_10:
- reg &= ~(GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100);
- break;
- }
- } else
- reg &= ~GM_GPCR_AU_ALL_DIS;
-
- if (sky2->duplex == DUPLEX_FULL || sky2->autoneg == AUTONEG_ENABLE)
- reg |= GM_GPCR_DUP_FULL;
-
/* enable Rx/Tx */
+ reg = gma_read16(hw, port, GM_GP_CTRL);
reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
gma_write16(hw, port, GM_GP_CTRL, reg);
- gma_read16(hw, port, GM_GP_CTRL);
gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
@@ -1606,7 +1591,6 @@ static void sky2_link_down(struct sky2_port *sky2)
reg = gma_read16(hw, port, GM_GP_CTRL);
reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
gma_write16(hw, port, GM_GP_CTRL, reg);
- gma_read16(hw, port, GM_GP_CTRL); /* PCI post */
if (sky2->rx_pause && !sky2->tx_pause) {
/* restore Asymmetric Pause bit */
@@ -1623,6 +1607,7 @@ static void sky2_link_down(struct sky2_port *sky2)
if (netif_msg_link(sky2))
printk(KERN_INFO PFX "%s: Link is down.\n", sky2->netdev->name);
+
sky2_phy_init(hw, port);
}
@@ -1663,8 +1648,11 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0;
- if ((sky2->tx_pause || sky2->rx_pause)
- && !(sky2->speed < SPEED_1000 && sky2->duplex == DUPLEX_HALF))
+ if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000
+ && hw->chip_id != CHIP_ID_YUKON_EC_U)
+ sky2->rx_pause = sky2->tx_pause = 0;
+
+ if (sky2->rx_pause || sky2->tx_pause)
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
else
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1690,7 +1678,7 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
sky2->netdev->name, istatus, phystat);
- if (istatus & PHY_M_IS_AN_COMPL) {
+ if (sky2->autoneg == AUTONEG_ENABLE && (istatus & PHY_M_IS_AN_COMPL)) {
if (sky2_autoneg_done(sky2, phystat) == 0)
sky2_link_up(sky2);
goto out;
@@ -1832,15 +1820,16 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
* For small packets or errors, just reuse existing skb.
* For larger packets, get new buffer.
*/
-static struct sk_buff *sky2_receive(struct sky2_port *sky2,
+static struct sk_buff *sky2_receive(struct net_device *dev,
u16 length, u32 status)
{
+ struct sky2_port *sky2 = netdev_priv(dev);
struct ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL;
if (unlikely(netif_msg_rx_status(sky2)))
printk(KERN_DEBUG PFX "%s: rx slot %u status 0x%x len %d\n",
- sky2->netdev->name, sky2->rx_next, status, length);
+ dev->name, sky2->rx_next, status, length);
sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
prefetch(sky2->rx_ring + sky2->rx_next);
@@ -1851,11 +1840,11 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
if (!(status & GMR_FS_RX_OK))
goto resubmit;
- if (length > sky2->netdev->mtu + ETH_HLEN)
+ if (length > dev->mtu + ETH_HLEN)
goto oversize;
if (length < copybreak) {
- skb = alloc_skb(length + 2, GFP_ATOMIC);
+ skb = netdev_alloc_skb(dev, length + 2);
if (!skb)
goto resubmit;
@@ -1870,7 +1859,7 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
} else {
struct sk_buff *nskb;
- nskb = sky2_alloc_skb(sky2->rx_bufsize, GFP_ATOMIC);
+ nskb = sky2_alloc_skb(dev, sky2->rx_bufsize, GFP_ATOMIC);
if (!nskb)
goto resubmit;
@@ -1889,9 +1878,6 @@ resubmit:
re->skb->ip_summed = CHECKSUM_NONE;
sky2_rx_add(sky2, re->mapaddr);
- /* Tell receiver about new buffers. */
- sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put);
-
return skb;
oversize:
@@ -1903,7 +1889,7 @@ error:
if (netif_msg_rx_err(sky2) && net_ratelimit())
printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n",
- sky2->netdev->name, status, length);
+ dev->name, status, length);
if (status & (GMR_FS_LONG_ERR | GMR_FS_UN_SIZE))
sky2->net_stats.rx_length_errors++;
@@ -1929,16 +1915,12 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
}
}
-/* Is status ring empty or is there more to do? */
-static inline int sky2_more_work(const struct sky2_hw *hw)
-{
- return (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX));
-}
-
/* Process status response ring */
static int sky2_status_intr(struct sky2_hw *hw, int to_do)
{
+ struct sky2_port *sky2;
int work_done = 0;
+ unsigned buf_write[2] = { 0, 0 };
u16 hwidx = sky2_read16(hw, STAT_PUT_IDX);
rmb();
@@ -1946,7 +1928,6 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
while (hw->st_idx != hwidx) {
struct sky2_status_le *le = hw->st_le + hw->st_idx;
struct net_device *dev;
- struct sky2_port *sky2;
struct sk_buff *skb;
u32 status;
u16 length;
@@ -1957,16 +1938,15 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
dev = hw->dev[le->link];
sky2 = netdev_priv(dev);
- length = le->length;
- status = le->status;
+ length = le16_to_cpu(le->length);
+ status = le32_to_cpu(le->status);
switch (le->opcode & ~HW_OWNER) {
case OP_RXSTAT:
- skb = sky2_receive(sky2, length, status);
+ skb = sky2_receive(dev, length, status);
if (!skb)
break;
- skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
dev->last_rx = jiffies;
@@ -1979,6 +1959,14 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
#endif
netif_receive_skb(skb);
+ /* Update receiver after 16 frames */
+ if (++buf_write[le->link] == RX_BUF_WRITE) {
+ sky2_put_idx(hw, rxqaddr[le->link],
+ sky2->rx_put);
+ buf_write[le->link] = 0;
+ }
+
+ /* Stop after net poll weight */
if (++work_done >= to_do)
goto exit_loop;
break;
@@ -1994,8 +1982,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
#endif
case OP_RXCHKS:
skb = sky2->rx_ring[sky2->rx_next].skb;
- skb->ip_summed = CHECKSUM_HW;
- skb->csum = le16_to_cpu(status);
+ skb->ip_summed = CHECKSUM_COMPLETE;
+ skb->csum = status & 0xffff;
break;
case OP_TXINDEXLE:
@@ -2016,7 +2004,20 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
}
}
+ /* Fully processed status ring so clear irq */
+ sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+
exit_loop:
+ if (buf_write[0]) {
+ sky2 = netdev_priv(hw->dev[0]);
+ sky2_put_idx(hw, Q_R1, sky2->rx_put);
+ }
+
+ if (buf_write[1]) {
+ sky2 = netdev_priv(hw->dev[1]);
+ sky2_put_idx(hw, Q_R2, sky2->rx_put);
+ }
+
return work_done;
}
@@ -2187,9 +2188,6 @@ static int sky2_poll(struct net_device *dev0, int *budget)
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
- if (!~status)
- goto out;
-
if (status & Y2_IS_HW_ERR)
sky2_hw_intr(hw);
@@ -2218,19 +2216,16 @@ static int sky2_poll(struct net_device *dev0, int *budget)
sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
work_done = sky2_status_intr(hw, work_limit);
- *budget -= work_done;
- dev0->quota -= work_done;
-
- if (status & Y2_IS_STAT_BMU)
- sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
+ if (work_done < work_limit) {
+ netif_rx_complete(dev0);
- if (sky2_more_work(hw))
+ sky2_read32(hw, B0_Y2_SP_LISR);
+ return 0;
+ } else {
+ *budget -= work_done;
+ dev0->quota -= work_done;
return 1;
-out:
- netif_rx_complete(dev0);
-
- sky2_read32(hw, B0_Y2_SP_LISR);
- return 0;
+ }
}
static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
@@ -2287,10 +2282,10 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
}
-static int __devinit sky2_reset(struct sky2_hw *hw)
+static int sky2_reset(struct sky2_hw *hw)
{
u16 status;
- u8 t8, pmd_type;
+ u8 t8;
int i;
sky2_write8(hw, B0_CTST, CS_RST_CLR);
@@ -2336,9 +2331,7 @@ static int __devinit sky2_reset(struct sky2_hw *hw)
sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
- pmd_type = sky2_read8(hw, B2_PMD_TYP);
- hw->copper = !(pmd_type == 'L' || pmd_type == 'S');
-
+ hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
hw->ports = 1;
t8 = sky2_read8(hw, B2_Y2_HW_RES);
if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
@@ -2396,7 +2389,7 @@ static int __devinit sky2_reset(struct sky2_hw *hw)
sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK);
for (i = 0; i < hw->ports; i++)
- sky2_phy_reset(hw, i);
+ sky2_gmac_reset(hw, i);
memset(hw->st_le, 0, STATUS_LE_BYTES);
hw->st_idx = 0;
@@ -2435,21 +2428,22 @@ static int __devinit sky2_reset(struct sky2_hw *hw)
static u32 sky2_supported_modes(const struct sky2_hw *hw)
{
- u32 modes;
- if (hw->copper) {
- modes = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_Autoneg | SUPPORTED_TP;
+ if (sky2_is_copper(hw)) {
+ u32 modes = SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_Autoneg | SUPPORTED_TP;
if (hw->chip_id != CHIP_ID_YUKON_FE)
modes |= SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full;
+ | SUPPORTED_1000baseT_Full;
+ return modes;
} else
- modes = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
- | SUPPORTED_Autoneg;
- return modes;
+ return SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg
+ | SUPPORTED_FIBRE;
}
static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
@@ -2460,7 +2454,7 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
ecmd->transceiver = XCVR_INTERNAL;
ecmd->supported = sky2_supported_modes(hw);
ecmd->phy_address = PHY_ADDR_MARV;
- if (hw->copper) {
+ if (sky2_is_copper(hw)) {
ecmd->supported = SUPPORTED_10baseT_Half
| SUPPORTED_10baseT_Full
| SUPPORTED_100baseT_Half
@@ -2469,12 +2463,14 @@ static int sky2_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
| SUPPORTED_1000baseT_Full
| SUPPORTED_Autoneg | SUPPORTED_TP;
ecmd->port = PORT_TP;
- } else
+ ecmd->speed = sky2->speed;
+ } else {
+ ecmd->speed = SPEED_1000;
ecmd->port = PORT_FIBRE;
+ }
ecmd->advertising = sky2->advertising;
ecmd->autoneg = sky2->autoneg;
- ecmd->speed = sky2->speed;
ecmd->duplex = sky2->duplex;
return 0;
}
@@ -2873,7 +2869,6 @@ static int sky2_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *ecmd)
{
struct sky2_port *sky2 = netdev_priv(dev);
- int err = 0;
sky2->autoneg = ecmd->autoneg;
sky2->tx_pause = ecmd->tx_pause != 0;
@@ -2881,7 +2876,7 @@ static int sky2_set_pauseparam(struct net_device *dev,
sky2_phy_reinit(sky2);
- return err;
+ return 0;
}
static int sky2_get_coalesce(struct net_device *dev,
@@ -3038,7 +3033,7 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
regs->len - B3_RI_WTO_R1);
}
-static struct ethtool_ops sky2_ethtool_ops = {
+static const struct ethtool_ops sky2_ethtool_ops = {
.get_settings = sky2_get_settings,
.set_settings = sky2_set_settings,
.get_drvinfo = sky2_get_drvinfo,
@@ -3187,19 +3182,19 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
struct pci_dev *pdev = hw->pdev;
int err;
+ init_waitqueue_head (&hw->msi_wait);
+
sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW);
- err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw);
+ err = request_irq(pdev->irq, sky2_test_intr, IRQF_SHARED, DRV_NAME, hw);
if (err) {
printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
pci_name(pdev), pdev->irq);
return err;
}
- init_waitqueue_head (&hw->msi_wait);
-
sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ);
- wmb();
+ sky2_read8(hw, B0_CTST);
wait_event_timeout(hw->msi_wait, hw->msi_detected, HZ/10);
@@ -3291,12 +3286,13 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
hw->pm_cap = pm_cap;
#ifdef __BIG_ENDIAN
- /* byte swap descriptors in hardware */
+ /* The sk98lin vendor driver uses hardware byte swapping but
+ * this driver uses software swapping.
+ */
{
u32 reg;
-
reg = sky2_pci_read32(hw, PCI_DEV_REG2);
- reg |= PCI_REV_DESC;
+ reg &= ~PCI_REV_DESC;
sky2_pci_write32(hw, PCI_DEV_REG2, reg);
}
#endif
@@ -3311,9 +3307,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
if (err)
goto err_out_iounmap;
- printk(KERN_INFO PFX "v%s addr 0x%lx irq %d Yukon-%s (0x%x) rev %d\n",
- DRV_VERSION, pci_resource_start(pdev, 0), pdev->irq,
- yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+ printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+ DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
+ pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
hw->chip_id, hw->chip_rev);
dev = sky2_init_netdev(hw, 0, using_dac);
@@ -3349,7 +3345,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_unregister;
}
- err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw);
+ err = request_irq(pdev->irq, sky2_intr, IRQF_SHARED, DRV_NAME, hw);
if (err) {
printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
pci_name(pdev), pdev->irq);
@@ -3438,17 +3434,14 @@ static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
return -EINVAL;
del_timer_sync(&hw->idle_timer);
+ netif_poll_disable(hw->dev[0]);
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- if (dev) {
- if (!netif_running(dev))
- continue;
-
+ if (netif_running(dev)) {
sky2_down(dev);
netif_device_detach(dev);
- netif_poll_disable(dev);
}
}
@@ -3475,9 +3468,8 @@ static int sky2_resume(struct pci_dev *pdev)
for (i = 0; i < hw->ports; i++) {
struct net_device *dev = hw->dev[i];
- if (dev && netif_running(dev)) {
+ if (netif_running(dev)) {
netif_device_attach(dev);
- netif_poll_enable(dev);
err = sky2_up(dev);
if (err) {
@@ -3489,6 +3481,7 @@ static int sky2_resume(struct pci_dev *pdev)
}
}
+ netif_poll_enable(hw->dev[0]);
sky2_idle_start(hw);
out:
return err;
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 8a0bc5525f0..4c13c371bc2 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -1318,6 +1318,14 @@ enum {
};
/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
+/***** PHY_MARV_PHY_CTRL (page 1) 16 bit r/w Fiber Specific Ctrl *****/
+enum {
+ PHY_M_FIB_FORCE_LNK = 1<<10,/* Force Link Good */
+ PHY_M_FIB_SIGD_POL = 1<<9, /* SIGDET Polarity */
+ PHY_M_FIB_TX_DIS = 1<<3, /* Transmitter Disable */
+};
+
+/* for Yukon-2 Gigabit Ethernet PHY (88E1112 only) */
/***** PHY_MARV_PHY_CTRL (page 2) 16 bit r/w MAC Specific Ctrl *****/
enum {
PHY_M_MAC_MD_MSK = 7<<7, /* Bit 9.. 7: Mode Select Mask */
@@ -1480,7 +1488,7 @@ enum {
GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */
GM_TXCR_CRC_DIS = 1<<14, /* Bit 14: Disable insertion of CRC */
GM_TXCR_PAD_DIS = 1<<13, /* Bit 13: Disable padding of packets */
- GM_TXCR_COL_THR_MSK = 1<<10, /* Bit 12..10: Collision Threshold */
+ GM_TXCR_COL_THR_MSK = 7<<10, /* Bit 12..10: Collision Threshold */
};
#define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK)
@@ -1566,7 +1574,7 @@ enum {
GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
- GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
+ GMR_FS_MII_ERR | GMR_FS_BAD_FC |
GMR_FS_UN_SIZE | GMR_FS_JABBER,
};
@@ -1748,7 +1756,6 @@ enum {
INIT_SUM= 1<<3,
LOCK_SUM= 1<<4,
INS_VLAN= 1<<5,
- FRC_STAT= 1<<6,
EOP = 1<<7,
};
@@ -1784,21 +1791,9 @@ enum {
OP_TXINDEXLE = 0x68,
};
-/* Yukon 2 hardware interface
- * Not tested on big endian
- */
+/* Yukon 2 hardware interface */
struct sky2_tx_le {
- union {
- __le32 addr;
- struct {
- __le16 offset;
- __le16 start;
- } csum __attribute((packed));
- struct {
- __le16 size;
- __le16 rsvd;
- } tso __attribute((packed));
- } tx;
+ __le32 addr;
__le16 length; /* also vlan tag or checksum start */
u8 ctrl;
u8 opcode;
@@ -1844,6 +1839,7 @@ struct sky2_port {
u32 tx_addr64;
u16 tx_pending;
u16 tx_last_mss;
+ u32 tx_tcpsum;
struct ring_info *rx_ring ____cacheline_aligned_in_smp;
struct sky2_rx_le *rx_le;
@@ -1879,7 +1875,7 @@ struct sky2_hw {
int pm_cap;
u8 chip_id;
u8 chip_rev;
- u8 copper;
+ u8 pmd_type;
u8 ports;
struct sky2_status_le *st_le;
@@ -1891,6 +1887,11 @@ struct sky2_hw {
wait_queue_head_t msi_wait;
};
+static inline int sky2_is_copper(const struct sky2_hw *hw)
+{
+ return !(hw->pmd_type == 'L' || hw->pmd_type == 'S' || hw->pmd_type == 'P');
+}
+
/* Register accessor for memory mapped device */
static inline u32 sky2_read32(const struct sky2_hw *hw, unsigned reg)
{
diff --git a/drivers/net/slhc.c b/drivers/net/slhc.c
index c6fbb1ede0e..0adab709ab6 100644
--- a/drivers/net/slhc.c
+++ b/drivers/net/slhc.c
@@ -42,7 +42,7 @@
* Modularization.
* - Jan 1995 Bjorn Ekwall
* Use ip_fast_csum from ip.h
- * - July 1995 Christos A. Polyzols
+ * - July 1995 Christos A. Polyzols
* Spotted bug in tcp option checking
*
*
@@ -50,7 +50,6 @@
* driver code belonging close to PPP and SLIP
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -95,27 +94,23 @@ slhc_init(int rslots, int tslots)
register struct cstate *ts;
struct slcompress *comp;
- comp = (struct slcompress *)kmalloc(sizeof(struct slcompress),
- GFP_KERNEL);
+ comp = kzalloc(sizeof(struct slcompress), GFP_KERNEL);
if (! comp)
goto out_fail;
- memset(comp, 0, sizeof(struct slcompress));
if ( rslots > 0 && rslots < 256 ) {
size_t rsize = rslots * sizeof(struct cstate);
- comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL);
+ comp->rstate = kzalloc(rsize, GFP_KERNEL);
if (! comp->rstate)
goto out_free;
- memset(comp->rstate, 0, rsize);
comp->rslot_limit = rslots - 1;
}
if ( tslots > 0 && tslots < 256 ) {
size_t tsize = tslots * sizeof(struct cstate);
- comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL);
+ comp->tstate = kzalloc(tsize, GFP_KERNEL);
if (! comp->tstate)
goto out_free2;
- memset(comp->tstate, 0, tsize);
comp->tslot_limit = tslots - 1;
}
@@ -142,9 +137,9 @@ slhc_init(int rslots, int tslots)
return comp;
out_free2:
- kfree((unsigned char *)comp->rstate);
+ kfree(comp->rstate);
out_free:
- kfree((unsigned char *)comp);
+ kfree(comp);
out_fail:
return NULL;
}
@@ -243,10 +238,10 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
/*
* Don't play with runt packets.
*/
-
+
if(isize<sizeof(struct iphdr))
return isize;
-
+
ip = (struct iphdr *) icp;
/* Bail if this packet isn't TCP, or is an IP fragment */
@@ -701,20 +696,6 @@ EXPORT_SYMBOL(slhc_compress);
EXPORT_SYMBOL(slhc_uncompress);
EXPORT_SYMBOL(slhc_toss);
-#ifdef MODULE
-
-int init_module(void)
-{
- printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California\n");
- return 0;
-}
-
-void cleanup_module(void)
-{
- return;
-}
-
-#endif /* MODULE */
#else /* CONFIG_INET */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index b2e18d28850..39c2152a07f 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -55,7 +55,6 @@
*/
#define SL_CHECK_TRANSMIT
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -114,7 +113,7 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd);
* on actively running device.
*********************************/
-/*
+/*
Allocate channel buffers.
*/
@@ -208,7 +207,7 @@ sl_free_bufs(struct slip *sl)
#endif
}
-/*
+/*
Reallocate slip channel buffers.
*/
@@ -355,7 +354,7 @@ sl_bump(struct slip *sl)
#endif /* SL_INCLUDE_CSLIP */
sl->rx_bytes+=count;
-
+
skb = dev_alloc_skb(count);
if (skb == NULL) {
printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name);
@@ -603,7 +602,7 @@ static int sl_init(struct net_device *dev)
struct slip *sl = netdev_priv(dev);
/*
- * Finish setting up the DEVICE info.
+ * Finish setting up the DEVICE info.
*/
dev->mtu = sl->mtu;
@@ -659,7 +658,7 @@ static void sl_setup(struct net_device *dev)
* be re-entered while running but other ldisc functions may be called
* in parallel
*/
-
+
static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
struct slip *sl = (struct slip *) tty->disc_data;
@@ -721,7 +720,7 @@ sl_alloc(dev_t line)
struct net_device *dev = NULL;
struct slip *sl;
- if (slip_devs == NULL)
+ if (slip_devs == NULL)
return NULL; /* Master array missing ! */
for (i = 0; i < slip_maxdev; i++) {
@@ -789,7 +788,7 @@ sl_alloc(dev_t line)
slip_devs[i] = NULL;
}
}
-
+
if (!dev) {
char name[IFNAMSIZ];
sprintf(name, "sl%d", i);
@@ -816,7 +815,7 @@ sl_alloc(dev_t line)
sl->outfill_timer.function=sl_outfill;
#endif
slip_devs[i] = dev;
-
+
return sl;
}
@@ -837,7 +836,7 @@ static int slip_open(struct tty_struct *tty)
if(!capable(CAP_NET_ADMIN))
return -EPERM;
-
+
/* RTnetlink lock is misused here to serialize concurrent
opens of slip channels. There are better ways, but it is
the simplest one.
@@ -863,7 +862,7 @@ static int slip_open(struct tty_struct *tty)
tty->disc_data = sl;
sl->line = tty_devnum(tty);
sl->pid = current->pid;
-
+
if (!test_bit(SLF_INUSE, &sl->flags)) {
/* Perform the low-level SLIP initialization. */
if ((err = sl_alloc_bufs(sl, SL_MTU)) != 0)
@@ -909,7 +908,7 @@ err_exit:
/*
FIXME: 1,2 are fixed 3 was never true anyway.
-
+
Let me to blame a bit.
1. TTY module calls this funstion on soft interrupt.
2. TTY module calls this function WITH MASKED INTERRUPTS!
@@ -921,7 +920,7 @@ err_exit:
By-product (not desired): sl? does not feel hangups and remains open.
It is supposed, that user level program (dip, diald, slattach...)
- will catch SIGHUP and make the rest of work.
+ will catch SIGHUP and make the rest of work.
I see no way to make more with current tty code. --ANK
*/
@@ -1292,7 +1291,7 @@ static int sl_ioctl(struct net_device *dev,struct ifreq *rq,int cmd)
break;
case SIOCSLEASE:
- /* Resolve race condition, when ioctl'ing hanged up
+ /* Resolve race condition, when ioctl'ing hanged up
and opened by another process device.
*/
if (sl->tty != current->signal->tty && sl->pid != current->pid) {
@@ -1351,7 +1350,7 @@ static int __init slip_init(void)
}
/* Clear the pointer array, we allocate devices when we need them */
- memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
+ memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev);
/* Fill in our line protocol discipline, and register it */
if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) {
@@ -1369,7 +1368,7 @@ static void __exit slip_exit(void)
unsigned long timeout = jiffies + HZ;
int busy = 0;
- if (slip_devs == NULL)
+ if (slip_devs == NULL)
return;
/* First of all: check for active disciplines and hangup them.
@@ -1406,7 +1405,7 @@ static void __exit slip_exit(void)
dev->name);
/* Intentionally leak the control block. */
dev->destructor = NULL;
- }
+ }
unregister_netdev(dev);
}
diff --git a/drivers/net/slip.h b/drivers/net/slip.h
index ab3efe66a64..853e0f6ec71 100644
--- a/drivers/net/slip.h
+++ b/drivers/net/slip.h
@@ -22,7 +22,6 @@
#ifndef _LINUX_SLIP_H
#define _LINUX_SLIP_H
-#include <linux/config.h>
#if defined(CONFIG_INET) && defined(CONFIG_SLIP_COMPRESSED)
# define SL_INCLUDE_CSLIP
@@ -108,12 +107,12 @@ struct slip {
#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP)
#define SL_MODE_AX25 4
#define SL_MODE_ADAPTIVE 8
-#ifdef CONFIG_SLIP_SMART
+#ifdef CONFIG_SLIP_SMART
unsigned char outfill; /* # of sec between outfill packet */
unsigned char keepalive; /* keepalive seconds */
struct timer_list outfill_timer;
struct timer_list keepalive_timer;
-#endif
+#endif
};
#define SLIP_MAGIC 0x5302
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index f00c476064f..7122932eac9 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -250,9 +250,9 @@ static int __init ultramca_probe(struct device *gen_dev)
break;
}
}
-
- if(!tirq || !tbase
- || (irq && irq != tirq)
+
+ if(!tirq || !tbase
+ || (irq && irq != tirq)
|| (base_addr && tbase != base_addr))
/* FIXME: we're trying to force the ordering of the
* devices here, there should be a way of getting this
@@ -310,7 +310,7 @@ static int __init ultramca_probe(struct device *gen_dev)
* the index of the 0x2000 step.
* beware different number of pages [hs]
*/
- dev->mem_start = (unsigned long)
+ dev->mem_start = (unsigned long)
mca_device_transform_memory(mca_dev, (void *)(0xc0000 + (0x2000 * (pos3 & 0xf))));
num_pages = 0x20 + (2 * (pos3 & 0x10));
break;
@@ -501,7 +501,7 @@ static int ultramca_close_card(struct net_device *dev)
int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
netif_stop_queue(dev);
-
+
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 5b4e8529d4a..7986514883a 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -57,7 +57,6 @@
static const char version[] =
"smc-ultra.c:v2.02 2/3/98 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -112,7 +111,7 @@ static struct isapnp_device_id ultra_device_ids[] __initdata = {
MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
#endif
-
+
#define START_PG 0x00 /* First page of TX buffer */
#define ULTRA_CMDREG 0 /* Offset to ASIC command register. */
@@ -123,7 +122,7 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
#define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
#define ULTRA_IO_EXTENT 32
#define EN0_ERWCNT 0x08 /* Early receive warning count. */
-
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void ultra_poll(struct net_device *dev)
{
@@ -537,7 +536,7 @@ ultra_close_card(struct net_device *dev)
return 0;
}
-
+
#ifdef MODULE
#define MAX_ULTRA_CARDS 4 /* Max number of Ultra cards per module */
static struct net_device *dev_ultra[MAX_ULTRA_CARDS];
diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c
index ff9bd97746d..e10755ec5de 100644
--- a/drivers/net/smc-ultra32.c
+++ b/drivers/net/smc-ultra32.c
@@ -74,7 +74,7 @@ static void ultra32_block_output(struct net_device *dev, int count,
const unsigned char *buf,
const int start_page);
static int ultra32_close(struct net_device *dev);
-
+
#define ULTRA32_CMDREG 0 /* Offset to ASIC command register. */
#define ULTRA32_RESET 0x80 /* Board reset, in ULTRA32_CMDREG. */
#define ULTRA32_MEMENB 0x40 /* Enable the shared memory. */
@@ -290,7 +290,7 @@ out:
static int ultra32_open(struct net_device *dev)
{
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* ASIC addr */
- int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : SA_SHIRQ;
+ int irq_flags = (inb(ioaddr + ULTRA32_CFG5) & 0x08) ? 0 : IRQF_SHARED;
int retval;
retval = request_irq(dev->irq, ei_interrupt, irq_flags, dev->name, dev);
@@ -314,7 +314,7 @@ static int ultra32_close(struct net_device *dev)
int ioaddr = dev->base_addr - ULTRA32_NIC_OFFSET; /* CMDREG */
netif_stop_queue(dev);
-
+
if (ei_debug > 1)
printk("%s: Shutting down ethercard.\n", dev->name);
@@ -413,7 +413,7 @@ static void ultra32_block_output(struct net_device *dev,
memcpy_toio(xfer_start, buf, count);
}
-
+
#ifdef MODULE
#define MAX_ULTRA32_CARDS 4 /* Max number of Ultra cards per module */
static struct net_device *dev_ultra[MAX_ULTRA32_CARDS];
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index bdd8702ead5..a621b17456e 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -55,8 +55,6 @@ static const char version[] =
)
#endif
-
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -1092,6 +1090,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs
/* Spurious interrupt check */
if ((SMC_GET_IRQ_CFG() & (INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) !=
(INT_CFG_IRQ_INT_ | INT_CFG_IRQ_EN_)) {
+ spin_unlock_irqrestore(&lp->lock, flags);
return IRQ_NONE;
}
@@ -1822,7 +1821,7 @@ static int smc911x_ethtool_geteeprom_len(struct net_device *dev)
return SMC911X_EEPROM_LEN;
}
-static struct ethtool_ops smc911x_ethtool_ops = {
+static const struct ethtool_ops smc911x_ethtool_ops = {
.get_settings = smc911x_ethtool_getsettings,
.set_settings = smc911x_ethtool_setsettings,
.get_drvinfo = smc911x_ethtool_getdrvinfo,
@@ -2081,7 +2080,7 @@ static int __init smc911x_probe(struct net_device *dev, unsigned long ioaddr)
lp->ctl_rspeed = 100;
/* Grab the IRQ */
- retval = request_irq(dev->irq, &smc911x_interrupt, SA_SHIRQ, dev->name, dev);
+ retval = request_irq(dev->irq, &smc911x_interrupt, IRQF_SHARED, dev->name, dev);
if (retval)
goto err_out;
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 8b0321f1976..5506a0d3efe 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -529,7 +529,7 @@ static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * de
}
length = ETH_ZLEN;
}
-
+
/*
** The MMU wants the number of pages to be the number of 256 bytes
** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
@@ -1159,7 +1159,7 @@ static int smc_open(struct net_device *dev)
address |= dev->dev_addr[ i ];
outw( address, ioaddr + ADDR0 + i );
}
-
+
netif_start_queue(dev);
return 0;
}
diff --git a/drivers/net/smc9194.h b/drivers/net/smc9194.h
index 393ab909bd8..cf69d0a5a1c 100644
--- a/drivers/net/smc9194.h
+++ b/drivers/net/smc9194.h
@@ -1,18 +1,18 @@
/*------------------------------------------------------------------------
. smc9194.h
- . Copyright (C) 1996 by Erik Stahlman
+ . Copyright (C) 1996 by Erik Stahlman
.
. This software may be used and distributed according to the terms
. of the GNU General Public License, incorporated herein by reference.
.
- . This file contains register information and access macros for
- . the SMC91xxx chipset.
- .
- . Information contained in this file was obtained from the SMC91C94
- . manual from SMC. To get a copy, if you really want one, you can find
+ . This file contains register information and access macros for
+ . the SMC91xxx chipset.
+ .
+ . Information contained in this file was obtained from the SMC91C94
+ . manual from SMC. To get a copy, if you really want one, you can find
. information under www.smc.com in the components division.
. ( this thanks to advice from Donald Becker ).
- .
+ .
. Authors
. Erik Stahlman ( erik@vt.edu )
.
@@ -38,22 +38,22 @@ typedef unsigned long int dword;
/*---------------------------------------------------------------
- .
+ .
. A description of the SMC registers is probably in order here,
- . although for details, the SMC datasheet is invaluable.
- .
+ . although for details, the SMC datasheet is invaluable.
+ .
. Basically, the chip has 4 banks of registers ( 0 to 3 ), which
. are accessed by writing a number into the BANK_SELECT register
. ( I also use a SMC_SELECT_BANK macro for this ).
- .
+ .
. The banks are configured so that for most purposes, bank 2 is all
- . that is needed for simple run time tasks.
+ . that is needed for simple run time tasks.
-----------------------------------------------------------------------*/
/*
- . Bank Select Register:
+ . Bank Select Register:
.
- . yyyy yyyy 0000 00xx
+ . yyyy yyyy 0000 00xx
. xx = bank number
. yyyy yyyy = 0x33, for identification purposes.
*/
@@ -62,23 +62,23 @@ typedef unsigned long int dword;
/* BANK 0 */
#define TCR 0 /* transmit control register */
-#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
+#define TCR_ENABLE 0x0001 /* if this is 1, we can transmit */
#define TCR_FDUPLX 0x0800 /* receive packets sent out */
#define TCR_STP_SQET 0x1000 /* stop transmitting if Signal quality error */
#define TCR_MON_CNS 0x0400 /* monitors the carrier status */
#define TCR_PAD_ENABLE 0x0080 /* pads short packets to 64 bytes */
#define TCR_CLEAR 0 /* do NOTHING */
-/* the normal settings for the TCR register : */
+/* the normal settings for the TCR register : */
/* QUESTION: do I want to enable padding of short packets ? */
-#define TCR_NORMAL TCR_ENABLE
+#define TCR_NORMAL TCR_ENABLE
#define EPH_STATUS 2
#define ES_LINK_OK 0x4000 /* is the link integrity ok ? */
#define RCR 4
-#define RCR_SOFTRESET 0x8000 /* resets the chip */
+#define RCR_SOFTRESET 0x8000 /* resets the chip */
#define RCR_STRIP_CRC 0x200 /* strips CRC */
#define RCR_ENABLE 0x100 /* IFF this is set, we can receive packets */
#define RCR_ALMUL 0x4 /* receive all multicast packets */
@@ -114,12 +114,12 @@ typedef unsigned long int dword;
#define MC_BUSY 1 /* only readable bit in the register */
#define MC_NOP 0
#define MC_ALLOC 0x20 /* or with number of 256 byte packets */
-#define MC_RESET 0x40
+#define MC_RESET 0x40
#define MC_REMOVE 0x60 /* remove the current rx packet */
#define MC_RELEASE 0x80 /* remove and release the current rx packet */
#define MC_FREEPKT 0xA0 /* Release packet in PNR register */
#define MC_ENQUEUE 0xC0 /* Enqueue the packet for transmit */
-
+
#define PNR_ARR 2
#define FIFO_PORTS 4
@@ -139,11 +139,11 @@ typedef unsigned long int dword;
#define INT_MASK 13
#define IM_RCV_INT 0x1
#define IM_TX_INT 0x2
-#define IM_TX_EMPTY_INT 0x4
+#define IM_TX_EMPTY_INT 0x4
#define IM_ALLOC_INT 0x8
#define IM_RX_OVRN_INT 0x10
#define IM_EPH_INT 0x20
-#define IM_ERCV_INT 0x40 /* not on SMC9192 */
+#define IM_ERCV_INT 0x40 /* not on SMC9192 */
/* BANK 3 */
#define MULTICAST1 0
@@ -162,19 +162,19 @@ typedef unsigned long int dword;
#define CHIP_9195 5
#define CHIP_91100 7
-static const char * chip_ids[ 15 ] = {
- NULL, NULL, NULL,
+static const char * chip_ids[ 15 ] = {
+ NULL, NULL, NULL,
/* 3 */ "SMC91C90/91C92",
/* 4 */ "SMC91C94",
/* 5 */ "SMC91C95",
NULL,
- /* 7 */ "SMC91C100",
- /* 8 */ "SMC91C100FD",
- NULL, NULL, NULL,
- NULL, NULL, NULL};
+ /* 7 */ "SMC91C100",
+ /* 8 */ "SMC91C100FD",
+ NULL, NULL, NULL,
+ NULL, NULL, NULL};
-/*
- . Transmit status bits
+/*
+ . Transmit status bits
*/
#define TS_SUCCESS 0x0001
#define TS_LOSTCAR 0x0400
@@ -190,18 +190,18 @@ static const char * chip_ids[ 15 ] = {
#define RS_TOOLONG 0x0800
#define RS_TOOSHORT 0x0400
#define RS_MULTICAST 0x0001
-#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+#define RS_ERRORS (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
static const char * interfaces[ 2 ] = { "TP", "AUI" };
/*-------------------------------------------------------------------------
. I define some macros to make it easier to do somewhat common
- . or slightly complicated, repeated tasks.
+ . or slightly complicated, repeated tasks.
--------------------------------------------------------------------------*/
/* select a register bank, 0 to 3 */
-#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT ); }
+#define SMC_SELECT_BANK(x) { outw( x, ioaddr + BANK_SELECT ); }
/* define a small delay for the reset */
#define SMC_DELAY() { inw( ioaddr + RCR );\
@@ -229,13 +229,13 @@ static const char * interfaces[ 2 ] = { "TP", "AUI" };
/*----------------------------------------------------------------------
. Define the interrupts that I want to receive from the card
- .
- . I want:
+ .
+ . I want:
. IM_EPH_INT, for nasty errors
. IM_RCV_INT, for happy received packets
. IM_RX_OVRN_INT, because I have to kick the receiver
--------------------------------------------------------------------------*/
-#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT)
+#define SMC_INTERRUPT_MASK (IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT)
#endif /* _SMC_9194_H_ */
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index 0e9833adf9f..d7e56438b5d 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -66,7 +66,6 @@ static const char version[] =
#endif
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -155,7 +154,7 @@ MODULE_LICENSE("GPL");
/*
* The maximum number of processing loops allowed for each call to the
- * IRQ handler.
+ * IRQ handler.
*/
#define MAX_IRQ_LOOPS 8
@@ -322,12 +321,12 @@ static void smc_reset(struct net_device *dev)
DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
/* Disable all interrupts, block TX tasklet */
- spin_lock(&lp->lock);
+ spin_lock_irq(&lp->lock);
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
pending_skb = lp->pending_tx_skb;
lp->pending_tx_skb = NULL;
- spin_unlock(&lp->lock);
+ spin_unlock_irq(&lp->lock);
/* free any pending tx skb */
if (pending_skb) {
@@ -449,12 +448,12 @@ static void smc_shutdown(struct net_device *dev)
DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
/* no more interrupts for me */
- spin_lock(&lp->lock);
+ spin_lock_irq(&lp->lock);
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
pending_skb = lp->pending_tx_skb;
lp->pending_tx_skb = NULL;
- spin_unlock(&lp->lock);
+ spin_unlock_irq(&lp->lock);
if (pending_skb)
dev_kfree_skb(pending_skb);
@@ -766,7 +765,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
/*
* Allocation succeeded: push packet to the chip's own memory
* immediately.
- */
+ */
smc_hardware_send_pkt((unsigned long)dev);
}
@@ -1740,7 +1739,7 @@ static void smc_ethtool_setmsglevel(struct net_device *dev, u32 level)
lp->msg_enable = level;
}
-static struct ethtool_ops smc_ethtool_ops = {
+static const struct ethtool_ops smc_ethtool_ops = {
.get_settings = smc_ethtool_getsettings,
.set_settings = smc_ethtool_setsettings,
.get_drvinfo = smc_ethtool_getdrvinfo,
@@ -2345,7 +2344,7 @@ static int __init smc_init(void)
#ifdef MODULE
#ifdef CONFIG_ISA
if (io == -1)
- printk(KERN_WARNING
+ printk(KERN_WARNING
"%s: You shouldn't use auto-probing with insmod!\n",
CARDNAME);
#endif
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index bf776125ca3..fedd1a37bc3 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -136,14 +136,9 @@
#define SMC_CAN_USE_32BIT 0
#define SMC_IO_SHIFT 0
#define SMC_NOWAIT 1
-#define SMC_USE_PXA_DMA 1
-#define SMC_inb(a, r) readb((a) + (r))
#define SMC_inw(a, r) readw((a) + (r))
-#define SMC_inl(a, r) readl((a) + (r))
-#define SMC_outb(v, a, r) writeb(v, (a) + (r))
#define SMC_outw(v, a, r) writew(v, (a) + (r))
-#define SMC_outl(v, a, r) writel(v, (a) + (r))
#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
@@ -189,16 +184,10 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_IO_SHIFT 0
#define SMC_NOWAIT 1
-#define SMC_inb(a, r) readb((a) + (r))
-#define SMC_outb(v, a, r) writeb(v, (a) + (r))
#define SMC_inw(a, r) readw((a) + (r))
#define SMC_outw(v, a, r) writew(v, (a) + (r))
#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
-#define SMC_inl(a, r) readl((a) + (r))
-#define SMC_outl(v, a, r) writel(v, (a) + (r))
-#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
-#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
#include <asm/mach-types.h>
#include <asm/arch/cpu.h>
@@ -206,8 +195,9 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_IRQ_FLAGS (( \
machine_is_omap_h2() \
|| machine_is_omap_h3() \
+ || machine_is_omap_h4() \
|| (machine_is_omap_innovator() && !cpu_is_omap1510()) \
- ) ? SA_TRIGGER_FALLING : SA_TRIGGER_RISING)
+ ) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING)
#elif defined(CONFIG_SH_SH4202_MICRODEV)
@@ -354,6 +344,60 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#define SMC_IRQ_FLAGS (0)
+#elif defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS (0)
+
+#elif defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS (0)
+
+#elif defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS (0)
+
#else
#define SMC_CAN_USE_8BIT 1
@@ -540,7 +584,7 @@ smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs)
#endif
#ifndef SMC_IRQ_FLAGS
-#define SMC_IRQ_FLAGS SA_TRIGGER_RISING
+#define SMC_IRQ_FLAGS IRQF_TRIGGER_RISING
#endif
#ifndef SMC_INTERRUPT_PREAMBLE
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index cab0dd95849..870cf6b0738 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -7,10 +7,10 @@
* (from the mac68k project) introduced dhd's support for 16-bit cards.
*
* (C) 1996,1998 by Thomas Bogendoerfer (tsbogend@alpha.franken.de)
- *
+ *
* This driver is based on work from Andreas Busse, but most of
* the code is rewritten.
- *
+ *
* (C) 1995 by Andreas Busse (andy@waldorf-gmbh.de)
*
* Core code included by system sonic drivers
@@ -46,7 +46,7 @@ static int sonic_open(struct net_device *dev)
{
struct sonic_local *lp = netdev_priv(dev);
int i;
-
+
if (sonic_debug > 2)
printk("sonic_open: initializing sonic driver.\n");
@@ -246,7 +246,7 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
dev_kfree_skb(skb);
return 1;
}
-
+
sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */
sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */
sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
@@ -459,7 +459,7 @@ static void sonic_rx(struct net_device *dev)
new_skb->dev = dev;
/* provide 16 byte IP header alignment unless DMA requires otherwise */
if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
- skb_reserve(new_skb, 2);
+ skb_reserve(new_skb, 2);
new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
SONIC_RBSIZE, DMA_FROM_DEVICE);
@@ -641,7 +641,7 @@ static int sonic_init(struct net_device *dev)
SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
-
+
SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
SONIC_WRITE(SONIC_REA, lp->rra_end);
SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
@@ -652,7 +652,7 @@ static int sonic_init(struct net_device *dev)
/* load the resource pointers */
if (sonic_debug > 3)
printk("sonic_init: issuing RRRA command\n");
-
+
SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
i = 0;
while (i++ < 100) {
@@ -662,14 +662,14 @@ static int sonic_init(struct net_device *dev)
if (sonic_debug > 2)
printk("sonic_init: status=%x i=%d\n", SONIC_READ(SONIC_CMD), i);
-
+
/*
* Initialize the receive descriptors so that they
* become a circular linked list, ie. let the last
* descriptor point to the first again.
*/
if (sonic_debug > 2)
- printk("sonic_init: initialize receive descriptors\n");
+ printk("sonic_init: initialize receive descriptors\n");
for (i=0; i<SONIC_NUM_RDS; i++) {
sonic_rda_put(dev, i, SONIC_RD_STATUS, 0);
sonic_rda_put(dev, i, SONIC_RD_PKTLEN, 0);
@@ -689,7 +689,7 @@ static int sonic_init(struct net_device *dev)
SONIC_WRITE(SONIC_URDA, lp->rda_laddr >> 16);
SONIC_WRITE(SONIC_CRDA, lp->rda_laddr & 0xffff);
- /*
+ /*
* initialize transmit descriptors
*/
if (sonic_debug > 2)
@@ -712,7 +712,7 @@ static int sonic_init(struct net_device *dev)
SONIC_WRITE(SONIC_CTDA, lp->tda_laddr & 0xffff);
lp->cur_tx = lp->next_tx = 0;
lp->eol_tx = SONIC_NUM_TDS - 1;
-
+
/*
* put our own address to CAM desc[0]
*/
diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h
index cede969a8ba..7f886e8ae28 100644
--- a/drivers/net/sonic.h
+++ b/drivers/net/sonic.h
@@ -7,7 +7,7 @@
* NOTE: most of the structure definitions here are endian dependent.
* If you want to use this driver on big endian machines, the data
* and pad structure members must be exchanged. Also, the structures
- * need to be changed accordingly to the bus size.
+ * need to be changed accordingly to the bus size.
*
* 981229 MSch: did just that for the 68k Mac port (32 bit, big endian)
*
@@ -22,7 +22,6 @@
#ifndef SONIC_H
#define SONIC_H
-#include <linux/config.h>
/*
* SONIC register offsets
@@ -182,7 +181,7 @@
#define SONIC_TCR_DEFAULT 0x0000
-/*
+/*
* Constants for the SONIC_INTERRUPT_MASK and
* SONIC_INTERRUPT_STATUS registers.
*/
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 394339d5e87..cc240adb726 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -21,7 +21,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/compiler.h>
#include <linux/crc32.h>
#include <linux/delay.h>
@@ -85,7 +84,7 @@ MODULE_DEVICE_TABLE(pci, spider_net_pci_tbl);
*
* returns the content of the specified SMMIO register.
*/
-static u32
+static inline u32
spider_net_read_reg(struct spider_net_card *card, u32 reg)
{
u32 value;
@@ -102,7 +101,7 @@ spider_net_read_reg(struct spider_net_card *card, u32 reg)
* @reg: register to write to
* @value: value to write into the specified SMMIO register
*/
-static void
+static inline void
spider_net_write_reg(struct spider_net_card *card, u32 reg, u32 value)
{
value = cpu_to_le32(value);
@@ -260,39 +259,10 @@ spider_net_get_mac_address(struct net_device *netdev)
*
* returns the status as in the dmac_cmd_status field of the descriptor
*/
-static enum spider_net_descr_status
+static inline int
spider_net_get_descr_status(struct spider_net_descr *descr)
{
- u32 cmd_status;
-
- cmd_status = descr->dmac_cmd_status;
- cmd_status >>= SPIDER_NET_DESCR_IND_PROC_SHIFT;
- /* no need to mask out any bits, as cmd_status is 32 bits wide only
- * (and unsigned) */
- return cmd_status;
-}
-
-/**
- * spider_net_set_descr_status -- sets the status of a descriptor
- * @descr: descriptor to change
- * @status: status to set in the descriptor
- *
- * changes the status to the specified value. Doesn't change other bits
- * in the status
- */
-static void
-spider_net_set_descr_status(struct spider_net_descr *descr,
- enum spider_net_descr_status status)
-{
- u32 cmd_status;
- /* read the status */
- cmd_status = descr->dmac_cmd_status;
- /* clean the upper 4 bits */
- cmd_status &= SPIDER_NET_DESCR_IND_PROC_MASKO;
- /* add the status to it */
- cmd_status |= ((u32)status)<<SPIDER_NET_DESCR_IND_PROC_SHIFT;
- /* and write it back */
- descr->dmac_cmd_status = cmd_status;
+ return descr->dmac_cmd_status & SPIDER_NET_DESCR_IND_PROC_MASK;
}
/**
@@ -329,24 +299,23 @@ spider_net_free_chain(struct spider_net_card *card,
static int
spider_net_init_chain(struct spider_net_card *card,
struct spider_net_descr_chain *chain,
- struct spider_net_descr *start_descr, int no)
+ struct spider_net_descr *start_descr,
+ int direction, int no)
{
int i;
struct spider_net_descr *descr;
dma_addr_t buf;
- atomic_set(&card->rx_chain_refill,0);
-
descr = start_descr;
memset(descr, 0, sizeof(*descr) * no);
/* set up the hardware pointers in each descriptor */
for (i=0; i<no; i++, descr++) {
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
buf = pci_map_single(card->pdev, descr,
SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ direction);
if (buf == DMA_ERROR_CODE)
goto iommu_error;
@@ -361,10 +330,11 @@ spider_net_init_chain(struct spider_net_card *card,
start_descr->prev = descr-1;
descr = start_descr;
- for (i=0; i < no; i++, descr++) {
- descr->next_descr_addr = descr->next->bus_addr;
- }
+ if (direction == PCI_DMA_FROMDEVICE)
+ for (i=0; i < no; i++, descr++)
+ descr->next_descr_addr = descr->next->bus_addr;
+ spin_lock_init(&chain->lock);
chain->head = start_descr;
chain->tail = start_descr;
@@ -376,7 +346,7 @@ iommu_error:
if (descr->bus_addr)
pci_unmap_single(card->pdev, descr->bus_addr,
SPIDER_NET_DESCR_SIZE,
- PCI_DMA_BIDIRECTIONAL);
+ direction);
return -ENOMEM;
}
@@ -397,7 +367,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
dev_kfree_skb(descr->skb);
pci_unmap_single(card->pdev, descr->buf_addr,
SPIDER_NET_MAX_FRAME,
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_FROMDEVICE);
}
descr = descr->next;
}
@@ -433,6 +403,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
if (!descr->skb) {
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Not enough memory to allocate rx buffer\n");
+ card->spider_stats.alloc_rx_skb_error++;
return -ENOMEM;
}
descr->buf_size = bufsize;
@@ -447,15 +418,17 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
/* io-mmu-map the skb */
buf = pci_map_single(card->pdev, descr->skb->data,
- SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL);
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
descr->buf_addr = buf;
if (buf == DMA_ERROR_CODE) {
dev_kfree_skb_any(descr->skb);
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Could not iommu-map rx buffer\n");
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ card->spider_stats.rx_iommu_map_error++;
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
} else {
- descr->dmac_cmd_status = SPIDER_NET_DMAC_RX_CARDOWNED;
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
+ SPIDER_NET_DMAC_NOINTR_COMPLETE;
}
return error;
@@ -469,7 +442,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
* chip by writing to the appropriate register. DMA is enabled in
* spider_net_enable_rxdmac.
*/
-static void
+static inline void
spider_net_enable_rxchtails(struct spider_net_card *card)
{
/* assume chain is aligned correctly */
@@ -484,7 +457,7 @@ spider_net_enable_rxchtails(struct spider_net_card *card)
* spider_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN
* in the GDADMACCNTR register
*/
-static void
+static inline void
spider_net_enable_rxdmac(struct spider_net_card *card)
{
wmb();
@@ -501,23 +474,24 @@ spider_net_enable_rxdmac(struct spider_net_card *card)
static void
spider_net_refill_rx_chain(struct spider_net_card *card)
{
- struct spider_net_descr_chain *chain;
-
- chain = &card->rx_chain;
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ unsigned long flags;
/* one context doing the refill (and a second context seeing that
* and omitting it) is ok. If called by NAPI, we'll be called again
* as spider_net_decode_one_descr is called several times. If some
* interrupt calls us, the NAPI is about to clean up anyway. */
- if (atomic_inc_return(&card->rx_chain_refill) == 1)
- while (spider_net_get_descr_status(chain->head) ==
- SPIDER_NET_DESCR_NOT_IN_USE) {
- if (spider_net_prepare_rx_descr(card, chain->head))
- break;
- chain->head = chain->head->next;
- }
+ if (!spin_trylock_irqsave(&chain->lock, flags))
+ return;
+
+ while (spider_net_get_descr_status(chain->head) ==
+ SPIDER_NET_DESCR_NOT_IN_USE) {
+ if (spider_net_prepare_rx_descr(card, chain->head))
+ break;
+ chain->head = chain->head->next;
+ }
- atomic_dec(&card->rx_chain_refill);
+ spin_unlock_irqrestore(&chain->lock, flags);
}
/**
@@ -555,111 +529,6 @@ error:
}
/**
- * spider_net_release_tx_descr - processes a used tx descriptor
- * @card: card structure
- * @descr: descriptor to release
- *
- * releases a used tx descriptor (unmapping, freeing of skb)
- */
-static void
-spider_net_release_tx_descr(struct spider_net_card *card,
- struct spider_net_descr *descr)
-{
- struct sk_buff *skb;
-
- /* unmap the skb */
- skb = descr->skb;
- pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
- PCI_DMA_BIDIRECTIONAL);
-
- dev_kfree_skb_any(skb);
-
- /* set status to not used */
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
-}
-
-/**
- * spider_net_release_tx_chain - processes sent tx descriptors
- * @card: adapter structure
- * @brutal: if set, don't care about whether descriptor seems to be in use
- *
- * returns 0 if the tx ring is empty, otherwise 1.
- *
- * spider_net_release_tx_chain releases the tx descriptors that spider has
- * finished with (if non-brutal) or simply release tx descriptors (if brutal).
- * If some other context is calling this function, we return 1 so that we're
- * scheduled again (if we were scheduled) and will not loose initiative.
- */
-static int
-spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
-{
- struct spider_net_descr_chain *tx_chain = &card->tx_chain;
- enum spider_net_descr_status status;
-
- if (atomic_inc_return(&card->tx_chain_release) != 1) {
- atomic_dec(&card->tx_chain_release);
- return 1;
- }
-
- for (;;) {
- status = spider_net_get_descr_status(tx_chain->tail);
- switch (status) {
- case SPIDER_NET_DESCR_CARDOWNED:
- if (!brutal)
- goto out;
- /* fallthrough, if we release the descriptors
- * brutally (then we don't care about
- * SPIDER_NET_DESCR_CARDOWNED) */
- case SPIDER_NET_DESCR_RESPONSE_ERROR:
- case SPIDER_NET_DESCR_PROTECTION_ERROR:
- case SPIDER_NET_DESCR_FORCE_END:
- if (netif_msg_tx_err(card))
- pr_err("%s: forcing end of tx descriptor "
- "with status x%02x\n",
- card->netdev->name, status);
- card->netdev_stats.tx_dropped++;
- break;
-
- case SPIDER_NET_DESCR_COMPLETE:
- card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes +=
- tx_chain->tail->skb->len;
- break;
-
- default: /* any other value (== SPIDER_NET_DESCR_NOT_IN_USE) */
- goto out;
- }
- spider_net_release_tx_descr(card, tx_chain->tail);
- tx_chain->tail = tx_chain->tail->next;
- }
-out:
- atomic_dec(&card->tx_chain_release);
-
- netif_wake_queue(card->netdev);
-
- if (status == SPIDER_NET_DESCR_CARDOWNED)
- return 1;
- return 0;
-}
-
-/**
- * spider_net_cleanup_tx_ring - cleans up the TX ring
- * @card: card structure
- *
- * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
- * interrupts to cleanup our TX ring) and returns sent packets to the stack
- * by freeing them
- */
-static void
-spider_net_cleanup_tx_ring(struct spider_net_card *card)
-{
- if ( (spider_net_release_tx_chain(card, 0)) &&
- (card->netdev->flags & IFF_UP) ) {
- mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
- }
-}
-
-/**
* spider_net_get_multicast_hash - generates hash for multicast filter table
* @addr: multicast address
*
@@ -762,97 +631,6 @@ spider_net_disable_rxdmac(struct spider_net_card *card)
}
/**
- * spider_net_stop - called upon ifconfig down
- * @netdev: interface device structure
- *
- * always returns 0
- */
-int
-spider_net_stop(struct net_device *netdev)
-{
- struct spider_net_card *card = netdev_priv(netdev);
-
- tasklet_kill(&card->rxram_full_tl);
- netif_poll_disable(netdev);
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- del_timer_sync(&card->tx_timer);
-
- /* disable/mask all interrupts */
- spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
- spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
- spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
-
- /* free_irq(netdev->irq, netdev);*/
- free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
-
- spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
- SPIDER_NET_DMA_TX_FEND_VALUE);
-
- /* turn off DMA, force end */
- spider_net_disable_rxdmac(card);
-
- /* release chains */
- spider_net_release_tx_chain(card, 1);
-
- spider_net_free_chain(card, &card->tx_chain);
- spider_net_free_chain(card, &card->rx_chain);
-
- return 0;
-}
-
-/**
- * spider_net_get_next_tx_descr - returns the next available tx descriptor
- * @card: device structure to get descriptor from
- *
- * returns the address of the next descriptor, or NULL if not available.
- */
-static struct spider_net_descr *
-spider_net_get_next_tx_descr(struct spider_net_card *card)
-{
- /* check, if head points to not-in-use descr */
- if ( spider_net_get_descr_status(card->tx_chain.head) ==
- SPIDER_NET_DESCR_NOT_IN_USE ) {
- return card->tx_chain.head;
- } else {
- return NULL;
- }
-}
-
-/**
- * spider_net_set_txdescr_cmdstat - sets the tx descriptor command field
- * @descr: descriptor structure to fill out
- * @skb: packet to consider
- *
- * fills out the command and status field of the descriptor structure,
- * depending on hardware checksum settings.
- */
-static void
-spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr,
- struct sk_buff *skb)
-{
- /* make sure the other fields in the descriptor are written */
- wmb();
-
- if (skb->ip_summed != CHECKSUM_HW) {
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
- return;
- }
-
- /* is packet ip?
- * if yes: tcp? udp? */
- if (skb->protocol == htons(ETH_P_IP)) {
- if (skb->nh.iph->protocol == IPPROTO_TCP)
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_TCPCS;
- else if (skb->nh.iph->protocol == IPPROTO_UDP)
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_UDPCS;
- else /* the stack should checksum non-tcp and non-udp
- packets on his own: NETIF_F_IP_CSUM */
- descr->dmac_cmd_status = SPIDER_NET_DMAC_CMDSTAT_NOCS;
- }
-}
-
-/**
* spider_net_prepare_tx_descr - fill tx descriptor with skb data
* @card: card structure
* @descr: descriptor structure to fill out
@@ -865,26 +643,117 @@ spider_net_set_txdescr_cmdstat(struct spider_net_descr *descr,
*/
static int
spider_net_prepare_tx_descr(struct spider_net_card *card,
- struct spider_net_descr *descr,
struct sk_buff *skb)
{
+ struct spider_net_descr *descr = card->tx_chain.head;
dma_addr_t buf;
- buf = pci_map_single(card->pdev, skb->data,
- skb->len, PCI_DMA_BIDIRECTIONAL);
+ buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
if (buf == DMA_ERROR_CODE) {
if (netif_msg_tx_err(card) && net_ratelimit())
pr_err("could not iommu-map packet (%p, %i). "
"Dropping packet\n", skb->data, skb->len);
+ card->spider_stats.tx_iommu_map_error++;
return -ENOMEM;
}
descr->buf_addr = buf;
descr->buf_size = skb->len;
+ descr->next_descr_addr = 0;
descr->skb = skb;
descr->data_status = 0;
- spider_net_set_txdescr_cmdstat(descr,skb);
+ descr->dmac_cmd_status =
+ SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
+ if (skb->protocol == htons(ETH_P_IP))
+ switch (skb->nh.iph->protocol) {
+ case IPPROTO_TCP:
+ descr->dmac_cmd_status |= SPIDER_NET_DMAC_TCP;
+ break;
+ case IPPROTO_UDP:
+ descr->dmac_cmd_status |= SPIDER_NET_DMAC_UDP;
+ break;
+ }
+
+ descr->prev->next_descr_addr = descr->bus_addr;
+
+ return 0;
+}
+
+/**
+ * spider_net_release_tx_descr - processes a used tx descriptor
+ * @card: card structure
+ * @descr: descriptor to release
+ *
+ * releases a used tx descriptor (unmapping, freeing of skb)
+ */
+static inline void
+spider_net_release_tx_descr(struct spider_net_card *card)
+{
+ struct spider_net_descr *descr = card->tx_chain.tail;
+ struct sk_buff *skb;
+
+ card->tx_chain.tail = card->tx_chain.tail->next;
+ descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+
+ /* unmap the skb */
+ skb = descr->skb;
+ pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
+ PCI_DMA_TODEVICE);
+ dev_kfree_skb_any(skb);
+}
+
+/**
+ * spider_net_release_tx_chain - processes sent tx descriptors
+ * @card: adapter structure
+ * @brutal: if set, don't care about whether descriptor seems to be in use
+ *
+ * returns 0 if the tx ring is empty, otherwise 1.
+ *
+ * spider_net_release_tx_chain releases the tx descriptors that spider has
+ * finished with (if non-brutal) or simply release tx descriptors (if brutal).
+ * If some other context is calling this function, we return 1 so that we're
+ * scheduled again (if we were scheduled) and will not loose initiative.
+ */
+static int
+spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
+{
+ struct spider_net_descr_chain *chain = &card->tx_chain;
+ int status;
+
+ spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR);
+
+ while (chain->tail != chain->head) {
+ status = spider_net_get_descr_status(chain->tail);
+ switch (status) {
+ case SPIDER_NET_DESCR_COMPLETE:
+ card->netdev_stats.tx_packets++;
+ card->netdev_stats.tx_bytes += chain->tail->skb->len;
+ break;
+
+ case SPIDER_NET_DESCR_CARDOWNED:
+ if (!brutal)
+ return 1;
+ /* fallthrough, if we release the descriptors
+ * brutally (then we don't care about
+ * SPIDER_NET_DESCR_CARDOWNED) */
+
+ case SPIDER_NET_DESCR_RESPONSE_ERROR:
+ case SPIDER_NET_DESCR_PROTECTION_ERROR:
+ case SPIDER_NET_DESCR_FORCE_END:
+ if (netif_msg_tx_err(card))
+ pr_err("%s: forcing end of tx descriptor "
+ "with status x%02x\n",
+ card->netdev->name, status);
+ card->netdev_stats.tx_errors++;
+ break;
+
+ default:
+ card->netdev_stats.tx_dropped++;
+ return 1;
+ }
+ spider_net_release_tx_descr(card);
+ }
return 0;
}
@@ -897,18 +766,32 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
* spider_net_kick_tx_dma writes the current tx chain head as start address
* of the tx descriptor chain and enables the transmission DMA engine
*/
-static void
-spider_net_kick_tx_dma(struct spider_net_card *card,
- struct spider_net_descr *descr)
+static inline void
+spider_net_kick_tx_dma(struct spider_net_card *card)
{
- /* this is the only descriptor in the output chain.
- * Enable TX DMA */
+ struct spider_net_descr *descr;
- spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
- descr->bus_addr);
+ if (spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR) &
+ SPIDER_NET_TX_DMA_EN)
+ goto out;
- spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
- SPIDER_NET_DMA_TX_VALUE);
+ descr = card->tx_chain.tail;
+ for (;;) {
+ if (spider_net_get_descr_status(descr) ==
+ SPIDER_NET_DESCR_CARDOWNED) {
+ spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
+ descr->bus_addr);
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_DMA_TX_VALUE);
+ break;
+ }
+ if (descr == card->tx_chain.head)
+ break;
+ descr = descr->next;
+ }
+
+out:
+ mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
}
/**
@@ -916,47 +799,70 @@ spider_net_kick_tx_dma(struct spider_net_card *card,
* @skb: packet to send out
* @netdev: interface device structure
*
- * returns 0 on success, <0 on failure
+ * returns 0 on success, !0 on failure
*/
static int
spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- struct spider_net_descr *descr;
+ struct spider_net_descr_chain *chain = &card->tx_chain;
+ struct spider_net_descr *descr = chain->head;
+ unsigned long flags;
int result;
+ spin_lock_irqsave(&chain->lock, flags);
+
spider_net_release_tx_chain(card, 0);
- descr = spider_net_get_next_tx_descr(card);
+ if (chain->head->next == chain->tail->prev) {
+ card->netdev_stats.tx_dropped++;
+ result = NETDEV_TX_LOCKED;
+ goto out;
+ }
- if (!descr)
- goto error;
+ if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) {
+ card->netdev_stats.tx_dropped++;
+ result = NETDEV_TX_LOCKED;
+ goto out;
+ }
- result = spider_net_prepare_tx_descr(card, descr, skb);
- if (result)
- goto error;
+ if (spider_net_prepare_tx_descr(card, skb) != 0) {
+ card->netdev_stats.tx_dropped++;
+ result = NETDEV_TX_BUSY;
+ goto out;
+ }
+
+ result = NETDEV_TX_OK;
+ spider_net_kick_tx_dma(card);
card->tx_chain.head = card->tx_chain.head->next;
- if (spider_net_get_descr_status(descr->prev) !=
- SPIDER_NET_DESCR_CARDOWNED) {
- /* make sure the current descriptor is in memory. Then
- * kicking it on again makes sense, if the previous is not
- * card-owned anymore. Check the previous descriptor twice
- * to omit an mb() in heavy traffic cases */
- mb();
- if (spider_net_get_descr_status(descr->prev) !=
- SPIDER_NET_DESCR_CARDOWNED)
- spider_net_kick_tx_dma(card, descr);
- }
+out:
+ spin_unlock_irqrestore(&chain->lock, flags);
+ netif_wake_queue(netdev);
+ return result;
+}
- mod_timer(&card->tx_timer, jiffies + SPIDER_NET_TX_TIMER);
+/**
+ * spider_net_cleanup_tx_ring - cleans up the TX ring
+ * @card: card structure
+ *
+ * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
+ * interrupts to cleanup our TX ring) and returns sent packets to the stack
+ * by freeing them
+ */
+static void
+spider_net_cleanup_tx_ring(struct spider_net_card *card)
+{
+ unsigned long flags;
- return NETDEV_TX_OK;
+ spin_lock_irqsave(&card->tx_chain.lock, flags);
-error:
- card->netdev_stats.tx_dropped++;
- return NETDEV_TX_BUSY;
+ if ((spider_net_release_tx_chain(card, 0) != 0) &&
+ (card->netdev->flags & IFF_UP))
+ spider_net_kick_tx_dma(card);
+
+ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
}
/**
@@ -1003,7 +909,7 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
/* unmap descriptor */
pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_FROMDEVICE);
/* the cases we'll throw away the packet immediately */
if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
@@ -1011,6 +917,7 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
pr_err("error in received descriptor found, "
"data_status=x%08x, data_error=x%08x\n",
data_status, data_error);
+ card->spider_stats.rx_desc_error++;
return 0;
}
@@ -1068,14 +975,11 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
static int
spider_net_decode_one_descr(struct spider_net_card *card, int napi)
{
- enum spider_net_descr_status status;
- struct spider_net_descr *descr;
- struct spider_net_descr_chain *chain;
+ struct spider_net_descr_chain *chain = &card->rx_chain;
+ struct spider_net_descr *descr = chain->tail;
+ int status;
int result;
- chain = &card->rx_chain;
- descr = chain->tail;
-
status = spider_net_get_descr_status(descr);
if (status == SPIDER_NET_DESCR_CARDOWNED) {
@@ -1104,23 +1008,25 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
card->netdev->name, status);
card->netdev_stats.rx_dropped++;
pci_unmap_single(card->pdev, descr->buf_addr,
- SPIDER_NET_MAX_FRAME, PCI_DMA_BIDIRECTIONAL);
+ SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
dev_kfree_skb_irq(descr->skb);
goto refill;
}
if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
(status != SPIDER_NET_DESCR_FRAME_END) ) {
- if (netif_msg_rx_err(card))
+ if (netif_msg_rx_err(card)) {
pr_err("%s: RX descriptor with state %d\n",
card->netdev->name, status);
+ card->spider_stats.rx_desc_unk_state++;
+ }
goto refill;
}
/* ok, we've got a packet in descr */
result = spider_net_pass_skb_up(descr, card, napi);
refill:
- spider_net_set_descr_status(descr, SPIDER_NET_DESCR_NOT_IN_USE);
+ descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
/* change the descriptor state: */
if (!napi)
spider_net_refill_rx_chain(card);
@@ -1292,21 +1198,6 @@ spider_net_set_mac(struct net_device *netdev, void *p)
}
/**
- * spider_net_enable_txdmac - enables a TX DMA controller
- * @card: card structure
- *
- * spider_net_enable_txdmac enables the TX DMA controller by setting the
- * descriptor chain tail address
- */
-static void
-spider_net_enable_txdmac(struct spider_net_card *card)
-{
- /* assume chain is aligned correctly */
- spider_net_write_reg(card, SPIDER_NET_GDTDCHA,
- card->tx_chain.tail->bus_addr);
-}
-
-/**
* spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
* @card: card structure
*
@@ -1654,7 +1545,6 @@ spider_net_enable_card(struct spider_net_card *card)
{ SPIDER_NET_GMRWOLCTRL, 0 },
{ SPIDER_NET_GTESTMD, 0x10000000 },
{ SPIDER_NET_GTTQMSK, 0x00400040 },
- { SPIDER_NET_GTESTMD, 0 },
{ SPIDER_NET_GMACINTEN, 0 },
@@ -1693,9 +1583,6 @@ spider_net_enable_card(struct spider_net_card *card)
spider_net_write_reg(card, SPIDER_NET_GRXDMAEN, SPIDER_NET_WOL_VALUE);
- /* set chain tail adress for TX chain */
- spider_net_enable_txdmac(card);
-
spider_net_write_reg(card, SPIDER_NET_GMACLENLMT,
SPIDER_NET_LENLMT_VALUE);
spider_net_write_reg(card, SPIDER_NET_GMACMODE,
@@ -1710,6 +1597,9 @@ spider_net_enable_card(struct spider_net_card *card)
SPIDER_NET_INT1_MASK_VALUE);
spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK,
SPIDER_NET_INT2_MASK_VALUE);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_GDTDCEIDIS);
}
/**
@@ -1728,11 +1618,12 @@ spider_net_open(struct net_device *netdev)
int result;
result = -ENOMEM;
- if (spider_net_init_chain(card, &card->tx_chain,
- card->descr, tx_descriptors))
+ if (spider_net_init_chain(card, &card->tx_chain, card->descr,
+ PCI_DMA_TODEVICE, card->tx_desc))
goto alloc_tx_failed;
if (spider_net_init_chain(card, &card->rx_chain,
- card->descr + tx_descriptors, rx_descriptors))
+ card->descr + card->rx_desc,
+ PCI_DMA_FROMDEVICE, card->rx_desc))
goto alloc_rx_failed;
/* allocate rx skbs */
@@ -1745,7 +1636,7 @@ spider_net_open(struct net_device *netdev)
result = -EBUSY;
if (request_irq(netdev->irq, spider_net_interrupt,
- SA_SHIRQ, netdev->name, netdev))
+ IRQF_SHARED, netdev->name, netdev))
goto register_int_failed;
spider_net_enable_card(card);
@@ -1813,10 +1704,10 @@ spider_net_setup_phy(struct spider_net_card *card)
*/
static int
spider_net_download_firmware(struct spider_net_card *card,
- u8 *firmware_ptr)
+ const void *firmware_ptr)
{
int sequencer, i;
- u32 *fw_ptr = (u32 *)firmware_ptr;
+ const u32 *fw_ptr = firmware_ptr;
/* stop sequencers */
spider_net_write_reg(card, SPIDER_NET_GSINIT,
@@ -1873,7 +1764,7 @@ spider_net_init_firmware(struct spider_net_card *card)
{
struct firmware *firmware = NULL;
struct device_node *dn;
- u8 *fw_prop = NULL;
+ const u8 *fw_prop = NULL;
int err = -ENOENT;
int fw_size;
@@ -1899,7 +1790,7 @@ try_host_fw:
if (!dn)
goto out_err;
- fw_prop = (u8 *)get_property(dn, "firmware", &fw_size);
+ fw_prop = get_property(dn, "firmware", &fw_size);
if (!fw_prop)
goto out_err;
@@ -1939,7 +1830,7 @@ spider_net_workaround_rxramfull(struct spider_net_card *card)
/* empty sequencer data */
for (sequencer = 0; sequencer < SPIDER_NET_FIRMWARE_SEQS;
sequencer++) {
- spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
+ spider_net_write_reg(card, SPIDER_NET_GSnPRGADR +
sequencer * 8, 0x0);
for (i = 0; i < SPIDER_NET_FIRMWARE_SEQWORDS; i++) {
spider_net_write_reg(card, SPIDER_NET_GSnPRGDAT +
@@ -1956,6 +1847,49 @@ spider_net_workaround_rxramfull(struct spider_net_card *card)
}
/**
+ * spider_net_stop - called upon ifconfig down
+ * @netdev: interface device structure
+ *
+ * always returns 0
+ */
+int
+spider_net_stop(struct net_device *netdev)
+{
+ struct spider_net_card *card = netdev_priv(netdev);
+
+ tasklet_kill(&card->rxram_full_tl);
+ netif_poll_disable(netdev);
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ del_timer_sync(&card->tx_timer);
+
+ /* disable/mask all interrupts */
+ spider_net_write_reg(card, SPIDER_NET_GHIINT0MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT1MSK, 0);
+ spider_net_write_reg(card, SPIDER_NET_GHIINT2MSK, 0);
+
+ /* free_irq(netdev->irq, netdev);*/
+ free_irq(to_pci_dev(netdev->class_dev.dev)->irq, netdev);
+
+ spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
+ SPIDER_NET_DMA_TX_FEND_VALUE);
+
+ /* turn off DMA, force end */
+ spider_net_disable_rxdmac(card);
+
+ /* release chains */
+ if (spin_trylock(&card->tx_chain.lock)) {
+ spider_net_release_tx_chain(card, 1);
+ spin_unlock(&card->tx_chain.lock);
+ }
+
+ spider_net_free_chain(card, &card->tx_chain);
+ spider_net_free_chain(card, &card->rx_chain);
+
+ return 0;
+}
+
+/**
* spider_net_tx_timeout_task - task scheduled by the watchdog timeout
* function (to be called not under interrupt status)
* @data: data, is interface device structure
@@ -1983,7 +1917,7 @@ spider_net_tx_timeout_task(void *data)
goto out;
spider_net_open(netdev);
- spider_net_kick_tx_dma(card, card->tx_chain.head);
+ spider_net_kick_tx_dma(card);
netif_device_attach(netdev);
out:
@@ -2007,6 +1941,7 @@ spider_net_tx_timeout(struct net_device *netdev)
schedule_work(&card->tx_timeout_task);
else
atomic_dec(&card->tx_timeout_task_counter);
+ card->spider_stats.tx_timeouts++;
}
/**
@@ -2059,14 +1994,13 @@ spider_net_setup_netdev(struct spider_net_card *card)
struct net_device *netdev = card->netdev;
struct device_node *dn;
struct sockaddr addr;
- u8 *mac;
+ const u8 *mac;
SET_MODULE_OWNER(netdev);
SET_NETDEV_DEV(netdev, &card->pdev->dev);
pci_set_drvdata(card->pdev, netdev);
- atomic_set(&card->tx_chain_release,0);
card->rxram_full_tl.data = (unsigned long) card;
card->rxram_full_tl.func =
(void (*)(unsigned long)) spider_net_handle_rxram_full;
@@ -2078,9 +2012,12 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
+ card->tx_desc = tx_descriptors;
+ card->rx_desc = rx_descriptors;
+
spider_net_setup_netdev_ops(netdev);
- netdev->features = NETIF_F_HW_CSUM;
+ netdev->features = NETIF_F_HW_CSUM | NETIF_F_LLTX;
/* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
* NETIF_F_HW_VLAN_FILTER */
@@ -2090,7 +2027,7 @@ spider_net_setup_netdev(struct spider_net_card *card)
if (!dn)
return -EIO;
- mac = (u8 *)get_property(dn, "local-mac-address", NULL);
+ mac = get_property(dn, "local-mac-address", NULL);
if (!mac)
return -EIO;
memcpy(addr.sa_data, mac, ETH_ALEN);
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index 3b8d951cf73..a59deda2f95 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -29,7 +29,7 @@
extern int spider_net_stop(struct net_device *netdev);
extern int spider_net_open(struct net_device *netdev);
-extern struct ethtool_ops spider_net_ethtool_ops;
+extern const struct ethtool_ops spider_net_ethtool_ops;
extern char spider_net_driver_name[];
@@ -208,7 +208,10 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_DMA_RX_VALUE 0x80000000
#define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003
/* to set TX_DMA_EN */
-#define SPIDER_NET_DMA_TX_VALUE 0x80000000
+#define SPIDER_NET_TX_DMA_EN 0x80000000
+#define SPIDER_NET_GDTDCEIDIS 0x00000002
+#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \
+ SPIDER_NET_GDTDCEIDIS
#define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003
/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
@@ -329,55 +332,23 @@ enum spider_net_int2_status {
(~SPIDER_NET_TXINT) & \
(~SPIDER_NET_RXINT) )
-#define SPIDER_NET_GPREXEC 0x80000000
-#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
+#define SPIDER_NET_GPREXEC 0x80000000
+#define SPIDER_NET_GPRDAT_MASK 0x0000ffff
-/* descriptor bits
- *
- * 1010 descriptor ready
- * 0 descr in middle of chain
- * 000 fixed to 0
- *
- * 0 no interrupt on completion
- * 000 fixed to 0
- * 1 no ipsec processing
- * 1 last descriptor for this frame
- * 00 no checksum
- * 10 tcp checksum
- * 11 udp checksum
- *
- * 00 fixed to 0
- * 0 fixed to 0
- * 0 no interrupt on response errors
- * 0 no interrupt on invalid descr
- * 0 no interrupt on dma process termination
- * 0 no interrupt on descr chain end
- * 0 no interrupt on descr complete
- *
- * 000 fixed to 0
- * 0 response error interrupt status
- * 0 invalid descr status
- * 0 dma termination status
- * 0 descr chain end status
- * 0 descr complete status */
-#define SPIDER_NET_DMAC_CMDSTAT_NOCS 0xa00c0000
-#define SPIDER_NET_DMAC_CMDSTAT_TCPCS 0xa00e0000
-#define SPIDER_NET_DMAC_CMDSTAT_UDPCS 0xa00f0000
-#define SPIDER_NET_DESCR_IND_PROC_SHIFT 28
-#define SPIDER_NET_DESCR_IND_PROC_MASKO 0x0fffffff
-
-/* descr ready, descr is in middle of chain, get interrupt on completion */
-#define SPIDER_NET_DMAC_RX_CARDOWNED 0xa0800000
-
-enum spider_net_descr_status {
- SPIDER_NET_DESCR_COMPLETE = 0x00, /* used in rx and tx */
- SPIDER_NET_DESCR_RESPONSE_ERROR = 0x01, /* used in rx and tx */
- SPIDER_NET_DESCR_PROTECTION_ERROR = 0x02, /* used in rx and tx */
- SPIDER_NET_DESCR_FRAME_END = 0x04, /* used in rx */
- SPIDER_NET_DESCR_FORCE_END = 0x05, /* used in rx and tx */
- SPIDER_NET_DESCR_CARDOWNED = 0x0a, /* used in rx and tx */
- SPIDER_NET_DESCR_NOT_IN_USE /* any other value */
-};
+#define SPIDER_NET_DMAC_NOINTR_COMPLETE 0x00800000
+#define SPIDER_NET_DMAC_NOCS 0x00040000
+#define SPIDER_NET_DMAC_TCP 0x00020000
+#define SPIDER_NET_DMAC_UDP 0x00030000
+#define SPIDER_NET_TXDCEST 0x08000000
+
+#define SPIDER_NET_DESCR_IND_PROC_MASK 0xF0000000
+#define SPIDER_NET_DESCR_COMPLETE 0x00000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_RESPONSE_ERROR 0x10000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_PROTECTION_ERROR 0x20000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_FRAME_END 0x40000000 /* used in rx */
+#define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */
+#define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
struct spider_net_descr {
/* as defined by the hardware */
@@ -398,7 +369,7 @@ struct spider_net_descr {
} __attribute__((aligned(32)));
struct spider_net_descr_chain {
- /* we walk from tail to head */
+ spinlock_t lock;
struct spider_net_descr *head;
struct spider_net_descr *tail;
};
@@ -444,6 +415,15 @@ struct spider_net_options {
NETIF_MSG_HW | \
NETIF_MSG_WOL )
+struct spider_net_extra_stats {
+ unsigned long rx_desc_error;
+ unsigned long tx_timeouts;
+ unsigned long alloc_rx_skb_error;
+ unsigned long rx_iommu_map_error;
+ unsigned long tx_iommu_map_error;
+ unsigned long rx_desc_unk_state;
+};
+
struct spider_net_card {
struct net_device *netdev;
struct pci_dev *pdev;
@@ -453,8 +433,6 @@ struct spider_net_card {
struct spider_net_descr_chain tx_chain;
struct spider_net_descr_chain rx_chain;
- atomic_t rx_chain_refill;
- atomic_t tx_chain_release;
struct net_device_stats netdev_stats;
@@ -470,6 +448,9 @@ struct spider_net_card {
/* for ethtool */
int msg_enable;
+ int rx_desc;
+ int tx_desc;
+ struct spider_net_extra_stats spider_stats;
struct spider_net_descr descr[0];
};
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index a5bb0b7633a..589e43658de 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -27,6 +27,27 @@
#include "spider_net.h"
+
+#define SPIDER_NET_NUM_STATS 13
+
+static struct {
+ const char str[ETH_GSTRING_LEN];
+} ethtool_stats_keys[] = {
+ { "tx_packets" },
+ { "tx_bytes" },
+ { "rx_packets" },
+ { "rx_bytes" },
+ { "tx_errors" },
+ { "tx_dropped" },
+ { "rx_dropped" },
+ { "rx_descriptor_error" },
+ { "tx_timeouts" },
+ { "alloc_rx_skb_error" },
+ { "rx_iommu_map_error" },
+ { "tx_iommu_map_error" },
+ { "rx_desc_unk_state" },
+};
+
static int
spider_net_ethtool_get_settings(struct net_device *netdev,
struct ethtool_cmd *cmd)
@@ -130,7 +151,50 @@ spider_net_ethtool_set_tx_csum(struct net_device *netdev, uint32_t data)
return 0;
}
-struct ethtool_ops spider_net_ethtool_ops = {
+static void
+spider_net_ethtool_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ering)
+{
+ struct spider_net_card *card = netdev->priv;
+
+ ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
+ ering->tx_pending = card->tx_desc;
+ ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
+ ering->rx_pending = card->rx_desc;
+}
+
+static int spider_net_get_stats_count(struct net_device *netdev)
+{
+ return SPIDER_NET_NUM_STATS;
+}
+
+static void spider_net_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct spider_net_card *card = netdev->priv;
+
+ data[0] = card->netdev_stats.tx_packets;
+ data[1] = card->netdev_stats.tx_bytes;
+ data[2] = card->netdev_stats.rx_packets;
+ data[3] = card->netdev_stats.rx_bytes;
+ data[4] = card->netdev_stats.tx_errors;
+ data[5] = card->netdev_stats.tx_dropped;
+ data[6] = card->netdev_stats.rx_dropped;
+ data[7] = card->spider_stats.rx_desc_error;
+ data[8] = card->spider_stats.tx_timeouts;
+ data[9] = card->spider_stats.alloc_rx_skb_error;
+ data[10] = card->spider_stats.rx_iommu_map_error;
+ data[11] = card->spider_stats.tx_iommu_map_error;
+ data[12] = card->spider_stats.rx_desc_unk_state;
+}
+
+static void spider_net_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys));
+}
+
+const struct ethtool_ops spider_net_ethtool_ops = {
.get_settings = spider_net_ethtool_get_settings,
.get_drvinfo = spider_net_ethtool_get_drvinfo,
.get_wol = spider_net_ethtool_get_wol,
@@ -141,5 +205,9 @@ struct ethtool_ops spider_net_ethtool_ops = {
.set_rx_csum = spider_net_ethtool_set_rx_csum,
.get_tx_csum = spider_net_ethtool_get_tx_csum,
.set_tx_csum = spider_net_ethtool_set_tx_csum,
+ .get_ringparam = spider_net_ethtool_get_ringparam,
+ .get_strings = spider_net_get_strings,
+ .get_stats_count = spider_net_get_stats_count,
+ .get_ethtool_stats = spider_net_get_ethtool_stats,
};
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index c158eedc781..3d617e8f54b 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -22,131 +22,14 @@
Support and updates available at
http://www.scyld.com/network/starfire.html
+ [link no longer provides useful info -jgarzik]
- -----------------------------------------------------------
-
- Linux kernel-specific changes:
-
- LK1.1.1 (jgarzik):
- - Use PCI driver interface
- - Fix MOD_xxx races
- - softnet fixups
-
- LK1.1.2 (jgarzik):
- - Merge Becker version 0.15
-
- LK1.1.3 (Andrew Morton)
- - Timer cleanups
-
- LK1.1.4 (jgarzik):
- - Merge Becker version 1.03
-
- LK1.2.1 (Ion Badulescu <ionut@cs.columbia.edu>)
- - Support hardware Rx/Tx checksumming
- - Use the GFP firmware taken from Adaptec's Netware driver
-
- LK1.2.2 (Ion Badulescu)
- - Backported to 2.2.x
-
- LK1.2.3 (Ion Badulescu)
- - Fix the flaky mdio interface
- - More compat clean-ups
-
- LK1.2.4 (Ion Badulescu)
- - More 2.2.x initialization fixes
-
- LK1.2.5 (Ion Badulescu)
- - Several fixes from Manfred Spraul
-
- LK1.2.6 (Ion Badulescu)
- - Fixed ifup/ifdown/ifup problem in 2.4.x
-
- LK1.2.7 (Ion Badulescu)
- - Removed unused code
- - Made more functions static and __init
-
- LK1.2.8 (Ion Badulescu)
- - Quell bogus error messages, inform about the Tx threshold
- - Removed #ifdef CONFIG_PCI, this driver is PCI only
-
- LK1.2.9 (Ion Badulescu)
- - Merged Jeff Garzik's changes from 2.4.4-pre5
- - Added 2.2.x compatibility stuff required by the above changes
-
- LK1.2.9a (Ion Badulescu)
- - More updates from Jeff Garzik
-
- LK1.3.0 (Ion Badulescu)
- - Merged zerocopy support
-
- LK1.3.1 (Ion Badulescu)
- - Added ethtool support
- - Added GPIO (media change) interrupt support
-
- LK1.3.2 (Ion Badulescu)
- - Fixed 2.2.x compatibility issues introduced in 1.3.1
- - Fixed ethtool ioctl returning uninitialized memory
-
- LK1.3.3 (Ion Badulescu)
- - Initialize the TxMode register properly
- - Don't dereference dev->priv after freeing it
-
- LK1.3.4 (Ion Badulescu)
- - Fixed initialization timing problems
- - Fixed interrupt mask definitions
-
- LK1.3.5 (jgarzik)
- - ethtool NWAY_RST, GLINK, [GS]MSGLVL support
-
- LK1.3.6:
- - Sparc64 support and fixes (Ion Badulescu)
- - Better stats and error handling (Ion Badulescu)
- - Use new pci_set_mwi() PCI API function (jgarzik)
-
- LK1.3.7 (Ion Badulescu)
- - minimal implementation of tx_timeout()
- - correctly shutdown the Rx/Tx engines in netdev_close()
- - added calls to netif_carrier_on/off
- (patch from Stefan Rompf <srompf@isg.de>)
- - VLAN support
-
- LK1.3.8 (Ion Badulescu)
- - adjust DMA burst size on sparc64
- - 64-bit support
- - reworked zerocopy support for 64-bit buffers
- - working and usable interrupt mitigation/latency
- - reduced Tx interrupt frequency for lower interrupt overhead
-
- LK1.3.9 (Ion Badulescu)
- - bugfix for mcast filter
- - enable the right kind of Tx interrupts (TxDMADone, not TxDone)
-
- LK1.4.0 (Ion Badulescu)
- - NAPI support
-
- LK1.4.1 (Ion Badulescu)
- - flush PCI posting buffers after disabling Rx interrupts
- - put the chip to a D3 slumber on driver unload
- - added config option to enable/disable NAPI
-
- LK1.4.2 (Ion Badulescu)
- - finally added firmware (GPL'ed by Adaptec)
- - removed compatibility code for 2.2.x
-
- LK1.4.2.1 (Ion Badulescu)
- - fixed 32/64 bit issues on i386 + CONFIG_HIGHMEM
- - added 32-bit padding to outgoing skb's, removed previous workaround
-
-TODO: - fix forced speed/duplexing code (broken a long time ago, when
- somebody converted the driver to use the generic MII code)
- - fix VLAN support
*/
#define DRV_NAME "starfire"
-#define DRV_VERSION "1.03+LK1.4.2.1"
-#define DRV_RELDATE "October 3, 2005"
+#define DRV_VERSION "2.0"
+#define DRV_RELDATE "June 27, 2006"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -759,7 +642,7 @@ static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
static void netdev_media_change(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
#ifdef VLAN_SUPPORT
@@ -847,7 +730,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev,
goto err_out_free_netdev;
}
- /* ioremap is borken in Linux-2.2.x/sparc64 */
base = ioremap(ioaddr, io_size);
if (!base) {
printk(KERN_ERR DRV_NAME " %d: cannot remap %#x @ %#lx, aborting\n",
@@ -1071,7 +953,7 @@ static int netdev_open(struct net_device *dev)
/* Do we ever need to reset the chip??? */
- retval = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+ retval = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);
if (retval)
return retval;
@@ -1348,7 +1230,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
}
#if defined(ZEROCOPY) && defined(HAS_BROKEN_FIRMWARE)
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (skb_padto(skb, (skb->len + PADDING_MASK) & ~PADDING_MASK))
return NETDEV_TX_OK;
}
@@ -1370,7 +1252,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
status |= TxDescIntr;
np->reap_tx = 0;
}
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
status |= TxCalTCP;
np->stats.tx_compressed++;
}
@@ -1617,7 +1499,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
* Until then, the printk stays. :-) -Ion
*/
else if (le16_to_cpu(desc->status2) & 0x0040) {
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
skb->csum = le16_to_cpu(desc->csum);
printk(KERN_DEBUG "%s: checksum_hw, status2 = %#x\n", dev->name, le16_to_cpu(desc->status2));
}
@@ -1986,7 +1868,7 @@ static void set_msglevel(struct net_device *dev, u32 val)
debug = val;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.begin = check_if_running,
.get_drvinfo = get_drvinfo,
.get_settings = get_settings,
@@ -2102,7 +1984,7 @@ static int starfire_suspend(struct pci_dev *pdev, pm_message_t state)
static int starfire_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
-
+
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
@@ -2171,7 +2053,7 @@ static int __init starfire_init (void)
return -ENODEV;
}
- return pci_module_init (&starfire_driver);
+ return pci_register_driver(&starfire_driver);
}
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index b6dfdf8f44d..e6f90427160 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -7,7 +7,6 @@
* Copyright (C) 1999 kaz Kojima
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -20,9 +19,9 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/se/se.h>
+#include <asm/se.h>
#include <asm/machvec.h>
-#ifdef CONFIG_SH_STANDARD_BIOS
+#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
#endif
@@ -99,7 +98,7 @@ STNIC_WRITE (int reg, byte val)
*(vhalf *) (PA_83902 + ((reg) << 1)) = ((half) (val) << 8);
STNIC_DELAY ();
}
-
+
static int __init stnic_probe(void)
{
struct net_device *dev;
@@ -115,7 +114,7 @@ static int __init stnic_probe(void)
return -ENOMEM;
SET_MODULE_OWNER(dev);
-#ifdef CONFIG_SH_STANDARD_BIOS
+#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_get_node_addr (stnic_eadr);
#endif
for (i = 0; i < ETHER_ADDR_LEN; i++)
@@ -141,7 +140,7 @@ static int __init stnic_probe(void)
ei_status.name = dev->name;
ei_status.word16 = 1;
-#ifdef __LITTLE_ENDIAN__
+#ifdef __LITTLE_ENDIAN__
ei_status.bigendian = 0;
#else
ei_status.bigendian = 1;
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index d5a58fb30d3..0605461bc56 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -14,10 +14,10 @@
* Alphacode 0.82 (96/09/29) for Linux 2.0.0 (or later)
* Copyrights (c) 1994,1995,1996 by M.Hipp (hippm@informatik.uni-tuebingen.de)
* --------------------------
- *
+ *
* Consult ni52.c for further notes from the original driver.
*
- * This incarnation currently supports the OBIO version of the i82586 chip
+ * This incarnation currently supports the OBIO version of the i82586 chip
* used in certain sun3 models. It should be fairly doable to expand this
* to support VME if I should every acquire such a board.
*
@@ -227,7 +227,7 @@ static int check586(struct net_device *dev,char *where,unsigned size)
return 0;
iscp_addr = (char *)dvma_btov((unsigned long)where);
-
+
p->iscp = (struct iscp_struct *) iscp_addr;
memset((char *)p->iscp,0, sizeof(struct iscp_struct));
@@ -237,7 +237,7 @@ static int check586(struct net_device *dev,char *where,unsigned size)
sun3_reset586();
sun3_attn586();
DELAY(1); /* wait a while... */
-
+
if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
return 0;
@@ -286,7 +286,7 @@ struct net_device * __init sun3_82586_probe(int unit)
unsigned long ioaddr;
static int found = 0;
int err = -ENOMEM;
-
+
/* check that this machine has an onboard 82586 */
switch(idprom->id_machtype) {
case SM_SUN3|SM_3_160:
@@ -300,12 +300,12 @@ struct net_device * __init sun3_82586_probe(int unit)
if (found)
return ERR_PTR(-ENODEV);
-
+
ioaddr = (unsigned long)ioremap(IE_OBIO, SUN3_82586_TOTAL_SIZE);
if (!ioaddr)
return ERR_PTR(-ENOMEM);
found = 1;
-
+
dev = alloc_etherdev(sizeof(struct priv));
if (!dev)
goto out;
@@ -379,7 +379,7 @@ static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr)
((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32;
printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq);
-
+
dev->open = sun3_82586_open;
dev->stop = sun3_82586_close;
dev->get_stats = sun3_82586_get_stats;
@@ -479,7 +479,7 @@ static int init586(struct net_device *dev)
/*
* TDR, wire check .. e.g. no resistor e.t.c
*/
-
+
tdr_cmd = (struct tdr_cmd_struct *)ptr;
tdr_cmd->cmd_status = 0;
diff --git a/drivers/net/sun3_82586.h b/drivers/net/sun3_82586.h
index 81cfb098bcc..93346f00486 100644
--- a/drivers/net/sun3_82586.h
+++ b/drivers/net/sun3_82586.h
@@ -12,13 +12,13 @@
*/
/*
- * Cloned from ni52.h, copyright as above.
+ * Cloned from ni52.h, copyright as above.
*
* Modified for Sun3 OBIO i82586 by Sam Creasey (sammy@sammy.net)
*/
-/* defines for the obio chip (not vme) */
+/* defines for the obio chip (not vme) */
#define IEOB_NORSET 0x80 /* don't reset the board */
#define IEOB_ONAIR 0x40 /* put us on the air */
#define IEOB_ATTEN 0x20 /* attention! */
@@ -159,7 +159,7 @@ struct rfd_struct
/*
* Receive Buffer Descriptor (RBD)
*/
-struct rbd_struct
+struct rbd_struct
{
unsigned short status; /* status word,number of used bytes in buff */
unsigned short next; /* pointeroffset to next RBD */
@@ -211,7 +211,7 @@ struct nop_cmd_struct
/*
* IA Setup command
*/
-struct iasetup_cmd_struct
+struct iasetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
@@ -220,7 +220,7 @@ struct iasetup_cmd_struct
};
/*
- * Configure command
+ * Configure command
*/
struct configure_cmd_struct
{
@@ -242,9 +242,9 @@ struct configure_cmd_struct
};
/*
- * Multicast Setup command
+ * Multicast Setup command
*/
-struct mcsetup_cmd_struct
+struct mcsetup_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
@@ -265,9 +265,9 @@ struct dump_cmd_struct
};
/*
- * transmit command
+ * transmit command
*/
-struct transmit_cmd_struct
+struct transmit_cmd_struct
{
unsigned short cmd_status;
unsigned short cmd_cmd;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index d4c0002b43d..61a832ce7cc 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -1,24 +1,24 @@
/* sun3lance.c: Ethernet driver for SUN3 Lance chip */
/*
- Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net).
+ Sun3 Lance ethernet driver, by Sam Creasey (sammy@users.qual.net).
This driver is a part of the linux kernel, and is thus distributed
under the GNU General Public License.
-
+
The values used in LANCE_OBIO and LANCE_IRQ seem to be empirically
true for the correct IRQ and address of the lance registers. They
have not been widely tested, however. What we probably need is a
"proper" way to search for a device in the sun3's prom, but, alas,
- linux has no such thing.
+ linux has no such thing.
This driver is largely based on atarilance.c, by Roman Hodek. Other
sources of inspiration were the NetBSD sun3 am7990 driver, and the
- linux sparc lance driver (sunlance.c).
+ linux sparc lance driver (sunlance.c).
There are more assumptions made throughout this driver, it almost
certainly still needs work, but it does work at least for RARP/BOOTP and
mounting the root NFS filesystem.
-
+
*/
static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.net)\n";
@@ -55,7 +55,7 @@ static char *version = "sun3lance.c: v1.2 1/12/2001 Sam Creasey (sammy@sammy.ne
/* sun3/60 addr/irq for the lance chip. If your sun is different,
change this. */
#define LANCE_OBIO 0x120000
-#define LANCE_IRQ IRQ3
+#define LANCE_IRQ IRQ_AUTO_3
/* Debug level:
* 0 = silent, print only serious errors
@@ -294,9 +294,9 @@ out:
}
static int __init lance_probe( struct net_device *dev)
-{
+{
unsigned long ioaddr;
-
+
struct lance_private *lp;
int i;
static int did_version;
@@ -313,7 +313,7 @@ static int __init lance_probe( struct net_device *dev)
/* test to see if there's really a lance here */
/* (CSRO_INIT shouldn't be readable) */
-
+
ioaddr_probe = (volatile unsigned short *)ioaddr;
tmp1 = ioaddr_probe[0];
tmp2 = ioaddr_probe[1];
@@ -339,9 +339,9 @@ static int __init lance_probe( struct net_device *dev)
lp->iobase = (volatile unsigned short *)ioaddr;
dev->base_addr = (unsigned long)ioaddr; /* informational only */
- REGA(CSR0) = CSR0_STOP;
+ REGA(CSR0) = CSR0_STOP;
- request_irq(LANCE_IRQ, lance_interrupt, SA_INTERRUPT, "SUN3 Lance", dev);
+ request_irq(LANCE_IRQ, lance_interrupt, IRQF_DISABLED, "SUN3 Lance", dev);
dev->irq = (unsigned short)LANCE_IRQ;
@@ -378,7 +378,7 @@ static int __init lance_probe( struct net_device *dev)
DPRINTK(2, ("initaddr: %08lx rx_ring: %08lx tx_ring: %08lx\n",
dvma_vtob(&(MEM->init)), dvma_vtob(MEM->rx_head),
- (dvma_vtob(MEM->tx_head))));
+ (dvma_vtob(MEM->tx_head))));
if (did_version++ == 0)
printk( version );
@@ -427,7 +427,7 @@ static int lance_open( struct net_device *dev )
DREG = CSR0_IDON | CSR0_STRT | CSR0_INEA;
netif_start_queue(dev);
-
+
DPRINTK( 2, ( "%s: LANCE is open, csr0 %04x\n", dev->name, DREG ));
return( 0 );
@@ -449,7 +449,7 @@ static void lance_init_ring( struct net_device *dev )
for( i = 0; i < TX_RING_SIZE; i++ ) {
MEM->tx_head[i].base = dvma_vtob(MEM->tx_data[i]);
MEM->tx_head[i].flag = 0;
- MEM->tx_head[i].base_hi =
+ MEM->tx_head[i].base_hi =
(dvma_vtob(MEM->tx_data[i])) >>16;
MEM->tx_head[i].length = 0;
MEM->tx_head[i].misc = 0;
@@ -458,7 +458,7 @@ static void lance_init_ring( struct net_device *dev )
for( i = 0; i < RX_RING_SIZE; i++ ) {
MEM->rx_head[i].base = dvma_vtob(MEM->rx_data[i]);
MEM->rx_head[i].flag = RMD1_OWN_CHIP;
- MEM->rx_head[i].base_hi =
+ MEM->rx_head[i].base_hi =
(dvma_vtob(MEM->rx_data[i])) >> 16;
MEM->rx_head[i].buf_length = -PKT_BUF_SZ | 0xf000;
MEM->rx_head[i].msg_length = 0;
@@ -542,22 +542,22 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
lance_init_ring(dev);
REGA( CSR0 ) = CSR0_INEA | CSR0_INIT | CSR0_STRT;
-
+
netif_start_queue(dev);
dev->trans_start = jiffies;
-
+
return 0;
}
-
+
/* Block a timer-based transmit from overlapping. This could better be
done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
/* Block a timer-based transmit from overlapping with us by
stopping the queue for a bit... */
-
+
netif_stop_queue(dev);
-
+
if (test_and_set_bit( 0, (void*)&lp->lock ) != 0) {
printk( "%s: tx queue lock!.\n", dev->name);
/* don't clear dev->tbusy flag. */
@@ -593,7 +593,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
printk(" data at 0x%08x len %d\n", (int)skb->data,
(int)skb->len );
}
-#endif
+#endif
/* We're not prepared for the int until the last flags are set/reset.
* And the int may happen already after setting the OWN_CHIP... */
local_irq_save(flags);
@@ -632,7 +632,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
lp->lock = 0;
if ((MEM->tx_head[(entry+1) & TX_RING_MOD_MASK].flag & TMD1_OWN) ==
- TMD1_OWN_HOST)
+ TMD1_OWN_HOST)
netif_start_queue(dev);
local_irq_restore(flags);
@@ -657,10 +657,10 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
if (in_interrupt)
DPRINTK( 2, ( "%s: Re-entering the interrupt handler.\n", dev->name ));
in_interrupt = 1;
-
+
still_more:
flush_cache_all();
-
+
AREG = CSR0;
csr0 = DREG;
@@ -680,22 +680,22 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
// if(lance_debug >= 3) {
// int i;
-//
+//
// printk("%s: tx int\n", dev->name);
-//
+//
// for(i = 0; i < TX_RING_SIZE; i++)
// printk("ring %d flag=%04x\n", i,
// MEM->tx_head[i].flag);
// }
-
+
while( old_tx != lp->new_tx) {
- struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
-
+ struct lance_tx_head *head = &(MEM->tx_head[old_tx]);
+
DPRINTK(3, ("on tx_ring %d\n", old_tx));
if (head->flag & TMD1_OWN_CHIP)
break; /* It still hasn't been Txed */
-
+
if (head->flag & TMD1_ERR) {
int status = head->misc;
lp->stats.tx_errors++;
@@ -705,7 +705,7 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
if (status & (TMD3_UFLO | TMD3_BUFF)) {
lp->stats.tx_fifo_errors++;
printk("%s: Tx FIFO error\n",
- dev->name);
+ dev->name);
REGA(CSR0) = CSR0_STOP;
REGA(CSR3) = CSR3_BSWP;
lance_init_ring(dev);
@@ -713,11 +713,11 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
return IRQ_HANDLED;
}
} else if(head->flag & (TMD1_ENP | TMD1_STP)) {
-
+
head->flag &= ~(TMD1_ENP | TMD1_STP);
if(head->flag & (TMD1_ONE | TMD1_MORE))
lp->stats.collisions++;
-
+
lp->stats.tx_packets++;
DPRINTK(3, ("cleared tx ring %d\n", old_tx));
}
@@ -736,7 +736,7 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
if (csr0 & CSR0_RINT) /* Rx interrupt */
lance_rx( dev );
-
+
/* Log misc errors. */
if (csr0 & CSR0_BABL) lp->stats.tx_errors++; /* Tx babble. */
if (csr0 & CSR0_MISS) lp->stats.rx_errors++; /* Missed a Rx frame. */
@@ -778,10 +778,10 @@ static int lance_rx( struct net_device *dev )
while( (MEM->rx_head[entry].flag & RMD1_OWN) == RMD1_OWN_HOST ) {
struct lance_rx_head *head = &(MEM->rx_head[entry]);
int status = head->flag;
-
+
if (status != (RMD1_ENP|RMD1_STP)) { /* There was an error. */
/* There is a tricky error noted by John Murphy,
- <murf@perftech.com> to Russ Nelson: Even with
+ <murf@perftech.com> to Russ Nelson: Even with
full-sized buffers it's possible for a jabber packet to use two
buffers, with only the last correctly noting the error. */
if (status & RMD1_ENP) /* Only count a general error at the */
@@ -806,7 +806,7 @@ static int lance_rx( struct net_device *dev )
if (skb == NULL) {
DPRINTK( 1, ( "%s: Memory squeeze, deferring packet.\n",
dev->name ));
-
+
lp->stats.rx_dropped++;
head->msg_length = 0;
head->flag |= RMD1_OWN_CHIP;
@@ -833,7 +833,7 @@ static int lance_rx( struct net_device *dev )
if (lance_debug >= 3) {
u_char *data = PKTBUF_ADDR(head);
printk( "%s: RX pkt %d type 0x%04x len %d\n ", dev->name, entry, ((u_short *)data)[6], pkt_len);
- }
+ }
skb->dev = dev;
@@ -914,7 +914,7 @@ static void set_multicast_list( struct net_device *dev )
if (dev->flags & IFF_PROMISC) {
/* Log any net taps. */
- DPRINTK( 1, ( "%s: Promiscuous mode enabled.\n", dev->name ));
+ DPRINTK( 3, ( "%s: Promiscuous mode enabled.\n", dev->name ));
REGA( CSR15 ) = 0x8000; /* Set promiscuous mode */
} else {
short multicast_table[4];
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index cfaf47c63c5..9e4be86495a 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -72,8 +72,6 @@ MODULE_LICENSE("GPL");
#define DIRQ(x)
#endif
-static struct bigmac *root_bigmac_dev;
-
#define DEFAULT_JAMSIZE 4 /* Toe jam */
#define QEC_RESET_TRIES 200
@@ -491,7 +489,7 @@ static void bigmac_tcvr_init(struct bigmac *bp)
}
}
-static int bigmac_init(struct bigmac *, int);
+static int bigmac_init_hw(struct bigmac *, int);
static int try_next_permutation(struct bigmac *bp, void __iomem *tregs)
{
@@ -551,7 +549,7 @@ static void bigmac_timer(unsigned long data)
if (ret == -1) {
printk(KERN_ERR "%s: Link down, cable problem?\n",
bp->dev->name);
- ret = bigmac_init(bp, 0);
+ ret = bigmac_init_hw(bp, 0);
if (ret) {
printk(KERN_ERR "%s: Error, cannot re-init the "
"BigMAC.\n", bp->dev->name);
@@ -621,7 +619,7 @@ static void bigmac_begin_auto_negotiation(struct bigmac *bp)
add_timer(&bp->bigmac_timer);
}
-static int bigmac_init(struct bigmac *bp, int from_irq)
+static int bigmac_init_hw(struct bigmac *bp, int from_irq)
{
void __iomem *gregs = bp->gregs;
void __iomem *cregs = bp->creg;
@@ -752,7 +750,7 @@ static void bigmac_is_medium_rare(struct bigmac *bp, u32 qec_status, u32 bmac_st
}
printk(" RESET\n");
- bigmac_init(bp, 1);
+ bigmac_init_hw(bp, 1);
}
/* BigMAC transmit complete service routines. */
@@ -920,13 +918,13 @@ static int bigmac_open(struct net_device *dev)
struct bigmac *bp = (struct bigmac *) dev->priv;
int ret;
- ret = request_irq(dev->irq, &bigmac_interrupt, SA_SHIRQ, dev->name, bp);
+ ret = request_irq(dev->irq, &bigmac_interrupt, IRQF_SHARED, dev->name, bp);
if (ret) {
printk(KERN_ERR "BIGMAC: Can't order irq %d to go.\n", dev->irq);
return ret;
}
init_timer(&bp->bigmac_timer);
- ret = bigmac_init(bp, 0);
+ ret = bigmac_init_hw(bp, 0);
if (ret)
free_irq(dev->irq, bp);
return ret;
@@ -950,7 +948,7 @@ static void bigmac_tx_timeout(struct net_device *dev)
{
struct bigmac *bp = (struct bigmac *) dev->priv;
- bigmac_init(bp, 0);
+ bigmac_init_hw(bp, 0);
netif_wake_queue(dev);
}
@@ -1073,7 +1071,7 @@ static u32 bigmac_get_link(struct net_device *dev)
return (bp->sw_bmsr & BMSR_LSTATUS);
}
-static struct ethtool_ops bigmac_ethtool_ops = {
+static const struct ethtool_ops bigmac_ethtool_ops = {
.get_drvinfo = bigmac_get_drvinfo,
.get_link = bigmac_get_link,
};
@@ -1104,6 +1102,8 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
bp->qec_sdev = qec_sdev;
bp->bigmac_sdev = qec_sdev->child;
+ SET_NETDEV_DEV(dev, &bp->bigmac_sdev->ofdev.dev);
+
spin_lock_init(&bp->lock);
/* Verify the registers we expect, are actually there. */
@@ -1226,11 +1226,7 @@ static int __init bigmac_ether_init(struct sbus_dev *qec_sdev)
goto fail_and_cleanup;
}
- /* Put us into the list of instances attached for later driver
- * exit.
- */
- bp->next_module = root_bigmac_dev;
- root_bigmac_dev = bp;
+ dev_set_drvdata(&bp->bigmac_sdev->ofdev.dev, bp);
printk(KERN_INFO "%s: BigMAC 100baseT Ethernet ", dev->name);
for (i = 0; i < 6; i++)
@@ -1266,69 +1262,68 @@ fail_and_cleanup:
/* QEC can be the parent of either QuadEthernet or
* a BigMAC. We want the latter.
*/
-static int __init bigmac_match(struct sbus_dev *sdev)
+static int __devinit bigmac_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_dev *child = sdev->child;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
- if (strcmp(sdev->prom_name, "qec") != 0)
- return 0;
+ if (!strcmp(dp->name, "be"))
+ sdev = sdev->parent;
- if (child == NULL)
- return 0;
-
- if (strcmp(child->prom_name, "be") != 0)
- return 0;
-
- return 1;
+ return bigmac_ether_init(sdev);
}
-static int __init bigmac_probe(void)
+static int __devexit bigmac_sbus_remove(struct of_device *dev)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev = NULL;
- static int called;
- int cards = 0, v;
-
- root_bigmac_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (bigmac_match(sdev)) {
- cards++;
- if ((v = bigmac_ether_init(sdev)))
- return v;
- }
- }
- }
- if (!cards)
- return -ENODEV;
+ struct bigmac *bp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = bp->dev;
+
+ unregister_netdevice(net_dev);
+
+ sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
+ sbus_iounmap(bp->creg, CREG_REG_SIZE);
+ sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
+ sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
+ sbus_free_consistent(bp->bigmac_sdev,
+ PAGE_SIZE,
+ bp->bmac_block,
+ bp->bblock_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit bigmac_cleanup(void)
-{
- while (root_bigmac_dev) {
- struct bigmac *bp = root_bigmac_dev;
- struct bigmac *bp_nxt = root_bigmac_dev->next_module;
+static struct of_device_id bigmac_sbus_match[] = {
+ {
+ .name = "qec",
+ },
+ {
+ .name = "be",
+ },
+ {},
+};
- sbus_iounmap(bp->gregs, GLOB_REG_SIZE);
- sbus_iounmap(bp->creg, CREG_REG_SIZE);
- sbus_iounmap(bp->bregs, BMAC_REG_SIZE);
- sbus_iounmap(bp->tregs, TCVR_REG_SIZE);
- sbus_free_consistent(bp->bigmac_sdev,
- PAGE_SIZE,
- bp->bmac_block,
- bp->bblock_dvma);
+MODULE_DEVICE_TABLE(of, bigmac_sbus_match);
- unregister_netdev(bp->dev);
- free_netdev(bp->dev);
- root_bigmac_dev = bp_nxt;
- }
+static struct of_platform_driver bigmac_sbus_driver = {
+ .name = "sunbmac",
+ .match_table = bigmac_sbus_match,
+ .probe = bigmac_sbus_probe,
+ .remove = __devexit_p(bigmac_sbus_remove),
+};
+
+static int __init bigmac_init(void)
+{
+ return of_register_driver(&bigmac_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit bigmac_exit(void)
+{
+ of_unregister_driver(&bigmac_sbus_driver);
}
-module_init(bigmac_probe);
-module_exit(bigmac_cleanup);
+module_init(bigmac_init);
+module_exit(bigmac_exit);
diff --git a/drivers/net/sunbmac.h b/drivers/net/sunbmac.h
index b0dbc518714..b563d3c2993 100644
--- a/drivers/net/sunbmac.h
+++ b/drivers/net/sunbmac.h
@@ -332,7 +332,6 @@ struct bigmac {
struct sbus_dev *qec_sdev;
struct sbus_dev *bigmac_sdev;
struct net_device *dev;
- struct bigmac *next_module;
};
/* We use this to acquire receive skb's that we can DMA directly into. */
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index f13b2a195c7..6b8f4baf87f 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -16,91 +16,15 @@
Support and updates available at
http://www.scyld.com/network/sundance.html
+ [link no longer provides useful info -jgarzik]
+ Archives of the mailing list are still available at
+ http://www.beowulf.org/pipermail/netdrivers/
-
- Version LK1.01a (jgarzik):
- - Replace some MII-related magic numbers with constants
-
- Version LK1.02 (D-Link):
- - Add new board to PCI ID list
- - Fix multicast bug
-
- Version LK1.03 (D-Link):
- - New Rx scheme, reduce Rx congestion
- - Option to disable flow control
-
- Version LK1.04 (D-Link):
- - Tx timeout recovery
- - More support for ethtool.
-
- Version LK1.04a:
- - Remove unused/constant members from struct pci_id_info
- (which then allows removal of 'drv_flags' from private struct)
- (jgarzik)
- - If no phy is found, fail to load that board (jgarzik)
- - Always start phy id scan at id 1 to avoid problems (Donald Becker)
- - Autodetect where mii_preable_required is needed,
- default to not needed. (Donald Becker)
-
- Version LK1.04b:
- - Remove mii_preamble_required module parameter (Donald Becker)
- - Add per-interface mii_preamble_required (setting is autodetected)
- (Donald Becker)
- - Remove unnecessary cast from void pointer (jgarzik)
- - Re-align comments in private struct (jgarzik)
-
- Version LK1.04c (jgarzik):
- - Support bitmapped message levels (NETIF_MSG_xxx), and the
- two ethtool ioctls that get/set them
- - Don't hand-code MII ethtool support, use standard API/lib
-
- Version LK1.04d:
- - Merge from Donald Becker's sundance.c: (Jason Lunz)
- * proper support for variably-sized MTUs
- * default to PIO, to fix chip bugs
- - Add missing unregister_netdev (Jason Lunz)
- - Add CONFIG_SUNDANCE_MMIO config option (jgarzik)
- - Better rx buf size calculation (Donald Becker)
-
- Version LK1.05 (D-Link):
- - Fix DFE-580TX packet drop issue (for DL10050C)
- - Fix reset_tx logic
-
- Version LK1.06 (D-Link):
- - Fix crash while unloading driver
-
- Versin LK1.06b (D-Link):
- - New tx scheme, adaptive tx_coalesce
-
- Version LK1.07 (D-Link):
- - Fix tx bugs in big-endian machines
- - Remove unused max_interrupt_work module parameter, the new
- NAPI-like rx scheme doesn't need it.
- - Remove redundancy get_stats() in intr_handler(), those
- I/O access could affect performance in ARM-based system
- - Add Linux software VLAN support
-
- Version LK1.08 (Philippe De Muyter phdm@macqel.be):
- - Fix bug of custom mac address
- (StationAddr register only accept word write)
-
- Version LK1.09 (D-Link):
- - Fix the flowctrl bug.
- - Set Pause bit in MII ANAR if flow control enabled.
-
- Version LK1.09a (ICPlus):
- - Add the delay time in reading the contents of EEPROM
-
- Version LK1.10 (Philippe De Muyter phdm@macqel.be):
- - Make 'unblock interface after Tx underrun' work
-
- Version LK1.11 (Pedro Alejandro Lopez-Valencia palopezv at gmail.com):
- - Add support for IC Plus Corporation IP100A chipset
*/
#define DRV_NAME "sundance"
-#define DRV_VERSION "1.01+LK1.11"
-#define DRV_RELDATE "14-Jun-2006"
+#define DRV_VERSION "1.2"
+#define DRV_RELDATE "11-Sep-2006"
/* The user-configurable values.
@@ -185,7 +109,7 @@ static char *media[MAX_UNITS];
#endif
/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static char version[] =
KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n"
KERN_INFO " http://www.scyld.com/network/sundance.html\n";
@@ -282,15 +206,15 @@ IVc. Errata
#define USE_IO_OPS 1
#endif
-static struct pci_device_id sundance_pci_tbl[] = {
- {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
- {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
- {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
- {0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3},
- {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- {0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- {0,}
+static const struct pci_device_id sundance_pci_tbl[] = {
+ { 0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0 },
+ { 0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1 },
+ { 0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2 },
+ { 0x1186, 0x1002, 0x1186, 0x1040, 0, 0, 3 },
+ { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
+ { 0x13F0, 0x0200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 },
+ { }
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -301,7 +225,7 @@ enum {
struct pci_id_info {
const char *name;
};
-static const struct pci_id_info pci_id_tbl[] = {
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
{"D-Link DFE-550TX FAST Ethernet Adapter"},
{"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"},
{"D-Link DFE-580TX 4 port Server Adapter"},
@@ -309,7 +233,7 @@ static const struct pci_id_info pci_id_tbl[] = {
{"D-Link DL10050-based FAST Ethernet Adapter"},
{"Sundance Technology Alta"},
{"IC Plus Corporation IP100A FAST Ethernet Adapter"},
- {NULL,}, /* 0 terminated list. */
+ { } /* terminate list. */
};
/* This driver was written to use PCI memory space, however x86-oriented
@@ -507,7 +431,7 @@ static int __set_mac_addr(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int netdev_close(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
static void sundance_reset(struct net_device *dev, unsigned long reset_cmd)
{
@@ -724,7 +648,7 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
/* Reset the chip to erase previous misconfiguration. */
if (netif_msg_hw(np))
printk("ASIC Control is %x.\n", ioread32(ioaddr + ASICCtrl));
- iowrite16(0x00ff, ioaddr + ASICCtrl + 2);
+ sundance_reset(dev, 0x00ff << 16);
if (netif_msg_hw(np))
printk("ASIC Control is now %x.\n", ioread32(ioaddr + ASICCtrl));
@@ -870,7 +794,7 @@ static int netdev_open(struct net_device *dev)
/* Do we need to reset the chip??? */
- i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);
if (i)
return i;
@@ -983,7 +907,7 @@ static void tx_timeout(struct net_device *dev)
struct netdev_private *np = netdev_priv(dev);
void __iomem *ioaddr = np->base;
unsigned long flag;
-
+
netif_stop_queue(dev);
tasklet_disable(&np->tx_tasklet);
iowrite16(0, ioaddr + IntrEnable);
@@ -1000,13 +924,13 @@ static void tx_timeout(struct net_device *dev)
le32_to_cpu(np->tx_ring[i].next_desc),
le32_to_cpu(np->tx_ring[i].status),
(le32_to_cpu(np->tx_ring[i].status) >> 2) & 0xff,
- le32_to_cpu(np->tx_ring[i].frag[0].addr),
+ le32_to_cpu(np->tx_ring[i].frag[0].addr),
le32_to_cpu(np->tx_ring[i].frag[0].length));
}
- printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
- ioread32(np->base + TxListPtr),
+ printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+ ioread32(np->base + TxListPtr),
netif_queue_stopped(dev));
- printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+ printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
np->cur_tx, np->cur_tx % TX_RING_SIZE,
np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
@@ -1078,9 +1002,9 @@ static void tx_poll (unsigned long data)
struct net_device *dev = (struct net_device *)data;
struct netdev_private *np = netdev_priv(dev);
unsigned head = np->cur_task % TX_RING_SIZE;
- struct netdev_desc *txdesc =
+ struct netdev_desc *txdesc =
&np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
-
+
/* Chain the next pointer */
for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
int entry = np->cur_task % TX_RING_SIZE;
@@ -1150,21 +1074,16 @@ reset_tx (struct net_device *dev)
struct sk_buff *skb;
int i;
int irq = in_interrupt();
-
+
/* Reset tx logic, TxListPtr will be cleaned */
iowrite16 (TxDisable, ioaddr + MACCtrl1);
- iowrite16 (TxReset | DMAReset | FIFOReset | NetworkReset,
- ioaddr + ASICCtrl + 2);
- for (i=50; i > 0; i--) {
- if ((ioread16(ioaddr + ASICCtrl + 2) & ResetBusy) == 0)
- break;
- mdelay(1);
- }
+ sundance_reset(dev, (NetworkReset|FIFOReset|DMAReset|TxReset) << 16);
+
/* free all tx skbuff */
for (i = 0; i < TX_RING_SIZE; i++) {
skb = np->tx_skbuff[i];
if (skb) {
- pci_unmap_single(np->pci_dev,
+ pci_unmap_single(np->pci_dev,
np->tx_ring[i].frag[0].addr, skb->len,
PCI_DMA_TODEVICE);
if (irq)
@@ -1181,7 +1100,7 @@ reset_tx (struct net_device *dev)
return 0;
}
-/* The interrupt handler cleans up after the Tx thread,
+/* The interrupt handler cleans up after the Tx thread,
and schedule a Rx thread work */
static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
{
@@ -1262,8 +1181,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
} else {
hw_frame_id = ioread8(ioaddr + TxFrameId);
}
-
- if (np->pci_rev_id >= 0x14) {
+
+ if (np->pci_rev_id >= 0x14) {
spin_lock(&np->lock);
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE;
@@ -1275,7 +1194,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
!(le32_to_cpu(np->tx_ring[entry].status)
& 0x00010000))
break;
- if (sw_frame_id == (hw_frame_id + 1) %
+ if (sw_frame_id == (hw_frame_id + 1) %
TX_RING_SIZE)
break;
skb = np->tx_skbuff[entry];
@@ -1294,7 +1213,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
int entry = np->dirty_tx % TX_RING_SIZE;
struct sk_buff *skb;
- if (!(le32_to_cpu(np->tx_ring[entry].status)
+ if (!(le32_to_cpu(np->tx_ring[entry].status)
& 0x00010000))
break;
skb = np->tx_skbuff[entry];
@@ -1309,7 +1228,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
}
spin_unlock(&np->lock);
}
-
+
if (netif_queue_stopped(dev) &&
np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
/* The ring is no longer full, clear busy flag. */
@@ -1545,8 +1464,6 @@ static void set_rx_mode(struct net_device *dev)
int i;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAll | AcceptMyPhys;
} else if ((dev->mc_count > multicast_filter_limit)
@@ -1652,7 +1569,7 @@ static void set_msglevel(struct net_device *dev, u32 val)
np->msg_enable = val;
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.begin = check_if_running,
.get_drvinfo = get_drvinfo,
.get_settings = get_settings,
@@ -1681,18 +1598,18 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCDEVPRIVATE:
for (i=0; i<TX_RING_SIZE; i++) {
printk(KERN_DEBUG "%02x %08llx %08x %08x(%02x) %08x %08x\n", i,
- (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
+ (unsigned long long)(np->tx_ring_dma + i*sizeof(*np->tx_ring)),
le32_to_cpu(np->tx_ring[i].next_desc),
le32_to_cpu(np->tx_ring[i].status),
- (le32_to_cpu(np->tx_ring[i].status) >> 2)
+ (le32_to_cpu(np->tx_ring[i].status) >> 2)
& 0xff,
- le32_to_cpu(np->tx_ring[i].frag[0].addr),
+ le32_to_cpu(np->tx_ring[i].frag[0].addr),
le32_to_cpu(np->tx_ring[i].frag[0].length));
}
- printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
- ioread32(np->base + TxListPtr),
+ printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n",
+ ioread32(np->base + TxListPtr),
netif_queue_stopped(dev));
- printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
+ printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n",
np->cur_tx, np->cur_tx % TX_RING_SIZE,
np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
@@ -1700,7 +1617,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
printk(KERN_DEBUG "TxStatus=%04x\n", ioread16(ioaddr + TxStatus));
return 0;
}
-
+
return rc;
}
@@ -1814,7 +1731,7 @@ static int __init sundance_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&sundance_driver);
+ return pci_register_driver(&sundance_driver);
}
static void __exit sundance_exit(void)
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 38cd30cb7c7..0975695ae31 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -2,21 +2,21 @@
* sungem.c: Sun GEM ethernet driver.
*
* Copyright (C) 2000, 2001, 2002, 2003 David S. Miller (davem@redhat.com)
- *
+ *
* Support for Apple GMAC and assorted PHYs, WOL, Power Management
* (C) 2001,2002,2003 Benjamin Herrenscmidt (benh@kernel.crashing.org)
* (C) 2004,2005 Benjamin Herrenscmidt, IBM Corp.
*
* NAPI and NETPOLL support
* (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com)
- *
- * TODO:
+ *
+ * TODO:
* - Now that the driver was significantly simplified, I need to rework
* the locking. I'm sure we don't need _2_ spinlocks, and we probably
* can avoid taking most of them for so long period of time (and schedule
* instead). The main issues at this point are caused by the netdev layer
* though:
- *
+ *
* gem_change_mtu() and gem_set_multicast() are called with a read_lock()
* help by net/core/dev.c, thus they can't schedule. That means they can't
* call netif_poll_disable() neither, thus force gem_poll() to keep a spinlock
@@ -113,7 +113,7 @@ static struct pci_device_id gem_pci_tbl[] = {
/* These models only differ from the original GEM in
* that their tx/rx fifos are of a different size and
* they only support 10/100 speeds. -DaveM
- *
+ *
* Apple's GMAC does support gigabit on machines with
* the BCM54xx PHYs. -BenH
*/
@@ -855,7 +855,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
}
skb->csum = ntohs((status & RXDCTRL_TCPCSUM) ^ 0xffff);
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
skb->protocol = eth_type_trans(skb, gp->dev);
netif_receive_skb(skb);
@@ -885,7 +885,7 @@ static int gem_poll(struct net_device *dev, int *budget)
unsigned long flags;
/*
- * NAPI locking nightmare: See comment at head of driver
+ * NAPI locking nightmare: See comment at head of driver
*/
spin_lock_irqsave(&gp->lock, flags);
@@ -905,8 +905,8 @@ static int gem_poll(struct net_device *dev, int *budget)
spin_unlock_irqrestore(&gp->lock, flags);
- /* Run RX thread. We don't use any locking here,
- * code willing to do bad things - like cleaning the
+ /* Run RX thread. We don't use any locking here,
+ * code willing to do bad things - like cleaning the
* rx ring - must call netif_poll_disable(), which
* schedule_timeout()'s if polling is already disabled.
*/
@@ -921,7 +921,7 @@ static int gem_poll(struct net_device *dev, int *budget)
return 1;
spin_lock_irqsave(&gp->lock, flags);
-
+
gp->status = readl(gp->regs + GREG_STAT);
} while (gp->status & GREG_STAT_NAPI);
@@ -946,7 +946,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
spin_lock_irqsave(&gp->lock, flags);
-
+
if (netif_rx_schedule_prep(dev)) {
u32 gem_status = readl(gp->regs + GREG_STAT);
@@ -961,9 +961,9 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
spin_unlock_irqrestore(&gp->lock, flags);
-
+
/* If polling was disabled at the time we received that
- * interrupt, we may return IRQ_HANDLED here while we
+ * interrupt, we may return IRQ_HANDLED here while we
* should return IRQ_NONE. No big deal...
*/
return IRQ_HANDLED;
@@ -1026,7 +1026,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned long flags;
ctrl = 0;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
u64 csum_start_off, csum_stuff_off;
csum_start_off = (u64) (skb->h.raw - skb->data);
@@ -1112,7 +1112,7 @@ static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev)
this_ctrl = ctrl;
if (frag == skb_shinfo(skb)->nr_frags - 1)
this_ctrl |= TXDCTRL_EOF;
-
+
txd = &gp->init_block->txd[entry];
txd->buffer = cpu_to_le64(mapping);
wmb();
@@ -1178,7 +1178,7 @@ static void gem_reset(struct gem *gp)
static void gem_start_dma(struct gem *gp)
{
u32 val;
-
+
/* We are ready to rock, turn everything on. */
val = readl(gp->regs + TXDMA_CFG);
writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
@@ -1246,7 +1246,7 @@ static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
autoneg = gp->want_autoneg;
speed = gp->phy_mii.speed;
duplex = gp->phy_mii.duplex;
-
+
/* Setup link parameters */
if (!ep)
goto start_aneg;
@@ -1276,7 +1276,7 @@ start_aneg:
duplex = DUPLEX_HALF;
if (speed == 0)
speed = SPEED_10;
-
+
/* If we are asleep, we don't try to actually setup the PHY, we
* just store the settings
*/
@@ -1345,7 +1345,7 @@ static int gem_set_link_modes(struct gem *gp)
val |= (MAC_TXCFG_ICS | MAC_TXCFG_ICOLL);
} else {
/* MAC_TXCFG_NBO must be zero. */
- }
+ }
writel(val, gp->regs + MAC_TXCFG);
val = (MAC_XIFCFG_OE | MAC_XIFCFG_LLED);
@@ -1470,7 +1470,7 @@ static void gem_link_timer(unsigned long data)
{
struct gem *gp = (struct gem *) data;
int restart_aneg = 0;
-
+
if (gp->asleep)
return;
@@ -1483,7 +1483,7 @@ static void gem_link_timer(unsigned long data)
*/
if (gp->reset_task_pending)
goto restart;
-
+
if (gp->phy_type == phy_serialink ||
gp->phy_type == phy_serdes) {
u32 val = readl(gp->regs + PCS_MIISTAT);
@@ -1660,7 +1660,7 @@ static void gem_init_phy(struct gem *gp)
mifcfg = readl(gp->regs + MIF_CFG);
mifcfg &= ~MIF_CFG_BBMODE;
writel(mifcfg, gp->regs + MIF_CFG);
-
+
if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
int i;
@@ -1823,7 +1823,7 @@ static u32 gem_setup_multicast(struct gem *gp)
{
u32 rxcfg = 0;
int i;
-
+
if ((gp->dev->flags & IFF_ALLMULTI) ||
(gp->dev->mc_count > 256)) {
for (i=0; i<16; i++)
@@ -1985,7 +1985,7 @@ static void gem_init_pause_thresholds(struct gem *gp)
cfg = ((2 << 1) & GREG_CFG_TXDMALIM);
cfg |= ((8 << 6) & GREG_CFG_RXDMALIM);
writel(cfg, gp->regs + GREG_CFG);
- }
+ }
}
static int gem_check_invariants(struct gem *gp)
@@ -2039,7 +2039,7 @@ static int gem_check_invariants(struct gem *gp)
/* Determine initial PHY interface type guess. MDIO1 is the
* external PHY and thus takes precedence over MDIO0.
*/
-
+
if (mif_cfg & MIF_CFG_MDI1) {
gp->phy_type = phy_mii_mdio1;
mif_cfg |= MIF_CFG_PSELECT;
@@ -2141,7 +2141,7 @@ static void gem_stop_phy(struct gem *gp, int wol)
/* Setup wake-on-lan for MAGIC packet */
writel(MAC_RXCFG_HFE | MAC_RXCFG_SFCS | MAC_RXCFG_ENAB,
- gp->regs + MAC_RXCFG);
+ gp->regs + MAC_RXCFG);
writel((e[4] << 8) | e[5], gp->regs + WOL_MATCH0);
writel((e[2] << 8) | e[3], gp->regs + WOL_MATCH1);
writel((e[0] << 8) | e[1], gp->regs + WOL_MATCH2);
@@ -2220,7 +2220,7 @@ static int gem_do_start(struct net_device *dev)
spin_unlock_irqrestore(&gp->lock, flags);
if (request_irq(gp->pdev->irq, gem_interrupt,
- SA_SHIRQ, dev->name, (void *)dev)) {
+ IRQF_SHARED, dev->name, (void *)dev)) {
printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name);
spin_lock_irqsave(&gp->lock, flags);
@@ -2230,7 +2230,7 @@ static int gem_do_start(struct net_device *dev)
gem_reset(gp);
gem_clean_rings(gp);
gem_put_cell(gp);
-
+
spin_unlock(&gp->tx_lock);
spin_unlock_irqrestore(&gp->lock, flags);
@@ -2343,12 +2343,12 @@ static int gem_close(struct net_device *dev)
mutex_lock(&gp->pm_mutex);
- gp->opened = 0;
+ gp->opened = 0;
if (!gp->asleep)
gem_do_stop(dev, 0);
mutex_unlock(&gp->pm_mutex);
-
+
return 0;
}
@@ -2366,7 +2366,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
printk(KERN_INFO "%s: suspending, WakeOnLan %s\n",
dev->name,
(gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
-
+
/* Keep the cell enabled during the entire operation */
spin_lock_irqsave(&gp->lock, flags);
spin_lock(&gp->tx_lock);
@@ -2486,7 +2486,7 @@ static int gem_resume(struct pci_dev *pdev)
spin_unlock_irqrestore(&gp->lock, flags);
netif_poll_enable(dev);
-
+
mutex_unlock(&gp->pm_mutex);
return 0;
@@ -2533,7 +2533,7 @@ static void gem_set_multicast(struct net_device *dev)
struct gem *gp = dev->priv;
u32 rxcfg, rxcfg_new;
int limit = 10000;
-
+
spin_lock_irq(&gp->lock);
spin_lock(&gp->tx_lock);
@@ -2549,7 +2549,7 @@ static void gem_set_multicast(struct net_device *dev)
rxcfg_new |= MAC_RXCFG_SFCS;
#endif
gp->mac_rx_cfg = rxcfg_new;
-
+
writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
if (!limit--)
@@ -2611,12 +2611,12 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct gem *gp = dev->priv;
-
+
strcpy(info->driver, DRV_NAME);
strcpy(info->version, DRV_VERSION);
strcpy(info->bus_info, pci_name(gp->pdev));
}
-
+
static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gem *gp = dev->priv;
@@ -2638,7 +2638,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
spin_lock_irq(&gp->lock);
cmd->autoneg = gp->want_autoneg;
cmd->speed = gp->phy_mii.speed;
- cmd->duplex = gp->phy_mii.duplex;
+ cmd->duplex = gp->phy_mii.duplex;
cmd->advertising = gp->phy_mii.advertising;
/* If we started with a forced mode, we don't have a default
@@ -2683,7 +2683,7 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
(cmd->duplex != DUPLEX_HALF &&
cmd->duplex != DUPLEX_FULL)))
return -EINVAL;
-
+
/* Apply settings and restart link process. */
spin_lock_irq(&gp->lock);
gem_get_cell(gp);
@@ -2716,7 +2716,7 @@ static u32 gem_get_msglevel(struct net_device *dev)
struct gem *gp = dev->priv;
return gp->msg_enable;
}
-
+
static void gem_set_msglevel(struct net_device *dev, u32 value)
{
struct gem *gp = dev->priv;
@@ -2753,7 +2753,7 @@ static int gem_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
-static struct ethtool_ops gem_ethtool_ops = {
+static const struct ethtool_ops gem_ethtool_ops = {
.get_drvinfo = gem_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_settings = gem_get_settings,
@@ -2776,7 +2776,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
* with power management.
*/
mutex_lock(&gp->pm_mutex);
-
+
spin_lock_irqsave(&gp->lock, flags);
gem_get_cell(gp);
spin_unlock_irqrestore(&gp->lock, flags);
@@ -2808,13 +2808,13 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
break;
};
-
+
spin_lock_irqsave(&gp->lock, flags);
gem_put_cell(gp);
spin_unlock_irqrestore(&gp->lock, flags);
mutex_unlock(&gp->pm_mutex);
-
+
return rc;
}
@@ -2880,20 +2880,23 @@ static int __devinit gem_get_device_address(struct gem *gp)
#if defined(__sparc__)
struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
- int node = -1;
+ int use_idprom = 1;
if (pcp != NULL) {
- node = pcp->prom_node;
- if (prom_getproplen(node, "local-mac-address") == 6)
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
- else
- node = -1;
+ unsigned char *addr;
+ int len;
+
+ addr = of_get_property(pcp->prom_node, "local-mac-address",
+ &len);
+ if (addr && len == 6) {
+ use_idprom = 0;
+ memcpy(dev->dev_addr, addr, 6);
+ }
}
- if (node == -1)
+ if (use_idprom)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
#elif defined(CONFIG_PPC_PMAC)
- unsigned char *addr;
+ const unsigned char *addr;
addr = get_property(gp->of_node, "local-mac-address", NULL);
if (addr == NULL) {
@@ -2997,7 +3000,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
}
pci_using_dac = 0;
}
-
+
gemreg_base = pci_resource_start(pdev, 0);
gemreg_len = pci_resource_len(pdev, 0);
@@ -3041,7 +3044,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
gp->link_timer.data = (unsigned long) gp;
INIT_WORK(&gp->reset_task, gem_reset_task, gp);
-
+
gp->lstate = link_down;
gp->timer_ticks = 0;
netif_carrier_off(dev);
@@ -3150,7 +3153,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1)
- printk(KERN_INFO "%s: Found %s PHY\n", dev->name,
+ printk(KERN_INFO "%s: Found %s PHY\n", dev->name,
gp->phy_mii.def ? gp->phy_mii.def->name : "no");
/* GEM can do it all... */
@@ -3191,7 +3194,7 @@ static struct pci_driver gem_driver = {
static int __init gem_init(void)
{
- return pci_module_init(&gem_driver);
+ return pci_register_driver(&gem_driver);
}
static void __exit gem_cleanup(void)
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 89847215d00..a70067c85cc 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -813,7 +813,7 @@
/* MII BCM5400 AUXSTATUS register */
#define MII_BCM5400_AUXSTATUS 0x19
#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
-#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
/* When it can, GEM internally caches 4 aligned TX descriptors
* at a time, so that it can use full cacheline DMA reads.
@@ -984,10 +984,10 @@ struct gem {
unsigned int asleep_wol : 1; /* was asleep with WOL enabled */
unsigned int opened : 1; /* driver opened, protected by pm_mutex */
unsigned int running : 1; /* chip running, protected by lock */
-
+
/* cell enable count, protected by lock */
- int cell_enabled;
-
+ int cell_enabled;
+
struct mutex pm_mutex;
u32 msg_enable;
@@ -1017,7 +1017,7 @@ struct gem {
enum gem_phy_type phy_type;
struct mii_phy phy_mii;
int mii_phy_addr;
-
+
struct gem_init_block *init_block;
struct sk_buff *rx_skbs[RX_RING_SIZE];
struct sk_buff *tx_skbs[TX_RING_SIZE];
@@ -1032,7 +1032,7 @@ struct gem {
#define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) \
&& gp->phy_mii.def && gp->phy_mii.def->ops)
-
+
#define ALIGNED_RX_SKB_ADDR(addr) \
((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr))
static __inline__ struct sk_buff *gem_alloc_skb(int size,
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 9282b4b0c02..49800b25907 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -1,8 +1,8 @@
/*
* PHY drivers for the sungem ethernet driver.
- *
+ *
* This file could be shared with other drivers.
- *
+ *
* (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
*
* TODO:
@@ -19,7 +19,6 @@
* of darwin, still need to reverse engineer that
*/
-#include <linux/config.h>
#include <linux/module.h>
@@ -74,7 +73,7 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
{
u16 val;
int limit = 10000;
-
+
val = __phy_read(phy, phy_id, MII_BMCR);
val &= ~(BMCR_ISOLATE | BMCR_PDOWN);
val |= BMCR_RESET;
@@ -90,7 +89,7 @@ static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
}
if ((val & BMCR_ISOLATE) && limit > 0)
__phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
-
+
return (limit <= 0);
}
@@ -161,16 +160,16 @@ static int bcm5400_init(struct mii_phy* phy)
data = phy_read(phy, MII_BCM5400_AUXCONTROL);
data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
phy_write(phy, MII_BCM5400_AUXCONTROL, data);
-
+
data = phy_read(phy, MII_BCM5400_GB_CONTROL);
data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
phy_write(phy, MII_BCM5400_GB_CONTROL, data);
-
+
udelay(100);
/* Reset and configure cascaded 10/100 PHY */
(void)reset_one_mii_phy(phy, 0x1f);
-
+
data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
data |= MII_BCM5201_MULTIPHY_SERIALMODE;
__phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
@@ -200,7 +199,7 @@ static int bcm5401_init(struct mii_phy* phy)
/* Some revisions of 5401 appear to need this
* initialisation sequence to disable, according
* to OF, "tap power management"
- *
+ *
* WARNING ! OF and Darwin don't agree on the
* register addresses. OF seem to interpret the
* register numbers below as decimal
@@ -220,7 +219,7 @@ static int bcm5401_init(struct mii_phy* phy)
phy_write(phy, 0x17, 0x201f);
phy_write(phy, 0x15, 0x0a20);
}
-
+
/* Configure for gigabit full duplex */
data = phy_read(phy, MII_BCM5400_GB_CONTROL);
data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
@@ -230,7 +229,7 @@ static int bcm5401_init(struct mii_phy* phy)
/* Reset and configure cascaded 10/100 PHY */
(void)reset_one_mii_phy(phy, 0x1f);
-
+
data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
data |= MII_BCM5201_MULTIPHY_SERIALMODE;
__phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
@@ -271,7 +270,7 @@ static int bcm5411_init(struct mii_phy* phy)
/* Reset and configure cascaded 10/100 PHY */
(void)reset_one_mii_phy(phy, 0x1f);
-
+
return 0;
}
@@ -356,7 +355,7 @@ static int bcm5461_enable_fiber(struct mii_phy* phy)
static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
-
+
phy->autoneg = 1;
phy->speed = SPEED_10;
phy->duplex = DUPLEX_HALF;
@@ -396,7 +395,7 @@ static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
{
u16 ctl;
-
+
phy->autoneg = 0;
phy->speed = speed;
phy->duplex = fd;
@@ -422,7 +421,7 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
ctl |= BMCR_FULLDPLX;
// XXX Should we set the sungem to GII now on 1000BT ?
-
+
phy_write(phy, MII_BMCR, ctl);
return 0;
@@ -430,9 +429,9 @@ static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
static int bcm54xx_read_link(struct mii_phy *phy)
{
- int link_mode;
+ int link_mode;
u16 val;
-
+
if (phy->autoneg) {
val = phy_read(phy, MII_BCM5400_AUXSTATUS);
link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
@@ -454,7 +453,7 @@ static int bcm54xx_read_link(struct mii_phy *phy)
static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
-
+
phy->autoneg = 1;
phy->speed = SPEED_10;
phy->duplex = DUPLEX_HALF;
@@ -501,7 +500,7 @@ static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
{
u16 ctl, ctl2;
-
+
phy->autoneg = 0;
phy->speed = speed;
phy->duplex = fd;
@@ -542,7 +541,7 @@ static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
phy_write(phy, MII_1000BASETCONTROL, ctl2);
// XXX Should we set the sungem to GII now on 1000BT ?
-
+
phy_write(phy, MII_BMCR, ctl);
return 0;
@@ -578,7 +577,7 @@ static int marvell_read_link(struct mii_phy *phy)
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
{
u16 ctl, adv;
-
+
phy->autoneg = 1;
phy->speed = SPEED_10;
phy->duplex = DUPLEX_HALF;
@@ -609,7 +608,7 @@ static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
{
u16 ctl;
-
+
phy->autoneg = 0;
phy->speed = speed;
phy->duplex = fd;
@@ -642,7 +641,7 @@ static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
static int genmii_poll_link(struct mii_phy *phy)
{
u16 status;
-
+
(void)phy_read(phy, MII_BMSR);
status = phy_read(phy, MII_BMSR);
if ((status & BMSR_LSTATUS) == 0)
@@ -919,13 +918,13 @@ int mii_phy_probe(struct mii_phy *phy, int mii_id)
* may re-probe the PHY regulary
*/
phy->mii_id = mii_id;
-
+
/* Take PHY out of isloate mode and reset it. */
rc = reset_one_mii_phy(phy, mii_id);
if (rc)
goto fail;
- /* Read ID and find matching entry */
+ /* Read ID and find matching entry */
id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
printk(KERN_DEBUG "PHY ID: %x, addr: %x\n", id, mii_id);
for (i=0; (def = mii_phy_table[i]) != NULL; i++)
@@ -936,7 +935,7 @@ int mii_phy_probe(struct mii_phy *phy, int mii_id)
goto fail;
phy->def = def;
-
+
return 0;
fail:
phy->speed = 0;
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 69e125197fc..8ee1ca0471c 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -96,7 +96,7 @@ extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
/* MII BCM5400 AUXSTATUS register */
#define MII_BCM5400_AUXSTATUS 0x19
#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
-#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
/* 1000BT control (Marvell & BCM54xx at least) */
#define MII_1000BASETCONTROL 0x09
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index bd5d2668a36..f05eea53623 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -1,9 +1,9 @@
-/* $Id: sunhme.c,v 1.124 2002/01/15 06:25:51 davem Exp $
- * sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
+/* sunhme.c: Sparc HME/BigMac 10/100baseT half/full duplex auto switching,
* auto carrier detecting ethernet driver. Also known as the
* "Happy Meal Ethernet" found on SunSwift SBUS cards.
*
- * Copyright (C) 1996, 1998, 1999, 2002, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1998, 1999, 2002, 2003,
+ 2006 David S. Miller (davem@davemloft.net)
*
* Changes :
* 2000/11/11 Willy Tarreau <willy AT meta-x.org>
@@ -13,7 +13,6 @@
* argument : macaddr=0x00,0x10,0x20,0x30,0x40,0x50
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -40,15 +39,13 @@
#include <asm/dma.h>
#include <asm/byteorder.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/idprom.h>
#include <asm/sbus.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/auxio.h>
-#ifndef __sparc_v9__
-#include <asm/io-unit.h>
-#endif
#endif
#include <asm/uaccess.h>
@@ -57,7 +54,7 @@
#ifdef CONFIG_PCI
#include <linux/pci.h>
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
#include <asm/pbm.h>
#endif
#endif
@@ -65,9 +62,9 @@
#include "sunhme.h"
#define DRV_NAME "sunhme"
-#define DRV_VERSION "2.02"
-#define DRV_RELDATE "8/24/03"
-#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION "3.00"
+#define DRV_RELDATE "June 23, 2006"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -83,8 +80,6 @@ static int macaddr[6];
module_param_array(macaddr, int, NULL, 0);
MODULE_PARM_DESC(macaddr, "Happy Meal MAC address to set");
-static struct happy_meal *root_happy_dev;
-
#ifdef CONFIG_SBUS
static struct quattro *qfe_sbus_list;
#endif
@@ -181,26 +176,6 @@ static __inline__ void tx_dump_ring(struct happy_meal *hp)
#define DEFAULT_IPG2 4 /* For all modes */
#define DEFAULT_JAMSIZE 4 /* Toe jam */
-#if defined(CONFIG_PCI) && defined(MODULE)
-/* This happy_pci_ids is declared __initdata because it is only used
- as an advisory to depmod. If this is ported to the new PCI interface
- where it could be referenced at any time due to hot plugging,
- the __initdata reference should be removed. */
-
-static struct pci_device_id happymeal_pci_ids[] = {
- {
- .vendor = PCI_VENDOR_ID_SUN,
- .device = PCI_DEVICE_ID_SUN_HAPPYMEAL,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
-
-#endif
-
/* NOTE: In the descriptor writes one _must_ write the address
* member _first_. The card must not be allowed to see
* the updated descriptor flags until the address is
@@ -530,7 +505,7 @@ static void happy_meal_tcvr_write(struct happy_meal *hp,
unsigned short value)
{
int tries = TCVR_WRITE_TRIES;
-
+
ASD(("happy_meal_tcvr_write: reg=0x%02x value=%04x\n", reg, value));
/* Welcome to Sun Microsystems, can I take your order please? */
@@ -1232,7 +1207,7 @@ static void happy_meal_transceiver_check(struct happy_meal *hp, void __iomem *tr
* flags, thus:
*
* skb->csum = rxd->rx_flags & 0xffff;
- * skb->ip_summed = CHECKSUM_HW;
+ * skb->ip_summed = CHECKSUM_COMPLETE;
*
* before sending off the skb to the protocols, and we are good as gold.
*/
@@ -1610,7 +1585,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("happy_meal_init: old[%08x] bursts<",
hme_read32(hp, gregs + GREG_CFG)));
-#ifndef __sparc__
+#ifndef CONFIG_SPARC
/* It is always PCI and can handle 64byte bursts. */
hme_write32(hp, gregs + GREG_CFG, GREG_CFG_BURST64);
#else
@@ -1647,7 +1622,7 @@ static int happy_meal_init(struct happy_meal *hp)
HMD(("XXX>"));
hme_write32(hp, gregs + GREG_CFG, 0);
}
-#endif /* __sparc__ */
+#endif /* CONFIG_SPARC */
/* Turn off interrupts we do not want to hear. */
HMD((", enable global interrupts, "));
@@ -1803,7 +1778,7 @@ static void happy_meal_set_initial_advertisement(struct happy_meal *hp)
static int happy_meal_is_not_so_happy(struct happy_meal *hp, u32 status)
{
int reset = 0;
-
+
/* Only print messages for non-counter related interrupts. */
if (status & (GREG_STAT_STSTERR | GREG_STAT_TFIFO_UND |
GREG_STAT_MAXPKTERR | GREG_STAT_RXERR |
@@ -2099,7 +2074,7 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
/* This card is _fucking_ hot... */
skb->csum = ntohs(csum ^ 0xffff);
- skb->ip_summed = CHECKSUM_HW;
+ skb->ip_summed = CHECKSUM_COMPLETE;
RXD(("len=%d csum=%4x]", len, csum));
skb->protocol = eth_type_trans(skb, dev);
@@ -2219,7 +2194,7 @@ static int happy_meal_open(struct net_device *dev)
*/
if ((hp->happy_flags & (HFLAG_QUATTRO|HFLAG_PCI)) != HFLAG_QUATTRO) {
if (request_irq(dev->irq, &happy_meal_interrupt,
- SA_SHIRQ, dev->name, (void *)dev)) {
+ IRQF_SHARED, dev->name, (void *)dev)) {
HMD(("EAGAIN\n"));
printk(KERN_ERR "happy_meal(SBUS): Can't order irq %d to go.\n",
dev->irq);
@@ -2293,7 +2268,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev)
u32 tx_flags;
tx_flags = TXFLAG_OWN;
- if (skb->ip_summed == CHECKSUM_HW) {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
u32 csum_start_off, csum_stuff_off;
csum_start_off = (u32) (skb->h.raw - skb->data);
@@ -2537,7 +2512,7 @@ static u32 hme_get_link(struct net_device *dev)
return (hp->sw_bmsr & BMSR_LSTATUS);
}
-static struct ethtool_ops hme_ethtool_ops = {
+static const struct ethtool_ops hme_ethtool_ops = {
.get_settings = hme_get_settings,
.set_settings = hme_set_settings,
.get_drvinfo = hme_get_drvinfo,
@@ -2547,7 +2522,7 @@ static struct ethtool_ops hme_ethtool_ops = {
static int hme_version_printed;
#ifdef CONFIG_SBUS
-void __init quattro_get_ranges(struct quattro *qp)
+void __devinit quattro_get_ranges(struct quattro *qp)
{
struct sbus_dev *sdev = qp->quattro_dev;
int err;
@@ -2563,7 +2538,7 @@ void __init quattro_get_ranges(struct quattro *qp)
qp->nranges = (err / sizeof(struct linux_prom_ranges));
}
-static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
+static void __devinit quattro_apply_ranges(struct quattro *qp, struct happy_meal *hp)
{
struct sbus_dev *sdev = hp->happy_dev;
int rng;
@@ -2590,16 +2565,12 @@ static void __init quattro_apply_ranges(struct quattro *qp, struct happy_meal *h
*
* Return NULL on failure.
*/
-static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
+static struct quattro * __devinit quattro_sbus_find(struct sbus_dev *goal_sdev)
{
- struct sbus_bus *sbus;
struct sbus_dev *sdev;
struct quattro *qp;
int i;
- if (qfe_sbus_list == NULL)
- goto found;
-
for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
for (i = 0, sdev = qp->quattro_dev;
(sdev != NULL) && (i < 4);
@@ -2608,17 +2579,7 @@ static struct quattro * __init quattro_sbus_find(struct sbus_dev *goal_sdev)
return qp;
}
}
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (sdev == goal_sdev)
- goto found;
- }
- }
- /* Cannot find quattro parent, fail. */
- return NULL;
-
-found:
qp = kmalloc(sizeof(struct quattro), GFP_KERNEL);
if (qp != NULL) {
int i;
@@ -2647,7 +2608,7 @@ static void __init quattro_sbus_register_irqs(void)
err = request_irq(sdev->irqs[0],
quattro_sbus_interrupt,
- SA_SHIRQ, "Quattro",
+ IRQF_SHARED, "Quattro",
qp);
if (err != 0) {
printk(KERN_ERR "Quattro: Fatal IRQ registery error %d.\n", err);
@@ -2655,6 +2616,17 @@ static void __init quattro_sbus_register_irqs(void)
}
}
}
+
+static void quattro_sbus_free_irqs(void)
+{
+ struct quattro *qp;
+
+ for (qp = qfe_sbus_list; qp != NULL; qp = qp->next) {
+ struct sbus_dev *sdev = qp->quattro_dev;
+
+ free_irq(sdev->irqs[0], qp);
+ }
+}
#endif /* CONFIG_SBUS */
#ifdef CONFIG_PCI
@@ -2689,8 +2661,9 @@ static struct quattro * __init quattro_pci_find(struct pci_dev *pdev)
#endif /* CONFIG_PCI */
#ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
+static int __devinit happy_meal_sbus_probe_one(struct sbus_dev *sdev, int is_qfe)
{
+ struct device_node *dp = sdev->ofdev.node;
struct quattro *qp = NULL;
struct happy_meal *hp;
struct net_device *dev;
@@ -2713,6 +2686,7 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
if (!dev)
goto err_out;
SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
if (hme_version_printed++ == 0)
printk(KERN_INFO "%s", version);
@@ -2728,13 +2702,16 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
- } else if (qfe_slot != -1 &&
- prom_getproplen(sdev->prom_node,
- "local-mac-address") == 6) {
- prom_getproperty(sdev->prom_node, "local-mac-address",
- dev->dev_addr, 6);
} else {
- memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
+ unsigned char *addr;
+ int len;
+
+ addr = of_get_property(dp, "local-mac-address", &len);
+
+ if (qfe_slot != -1 && addr && len == 6)
+ memcpy(dev->dev_addr, addr, 6);
+ else
+ memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
hp = dev->priv;
@@ -2745,9 +2722,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
err = -ENODEV;
if (sdev->num_registers != 5) {
- printk(KERN_ERR "happymeal: Device does not have 5 regs, it has %d.\n",
+ printk(KERN_ERR "happymeal: Device needs 5 regs, has %d.\n",
sdev->num_registers);
- printk(KERN_ERR "happymeal: Would you like that for here or to go?\n");
goto err_out_free_netdev;
}
@@ -2761,39 +2737,39 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->gregs = sbus_ioremap(&sdev->resource[0], 0,
GREG_REG_SIZE, "HME Global Regs");
if (!hp->gregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal global registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map global registers.\n");
goto err_out_free_netdev;
}
hp->etxregs = sbus_ioremap(&sdev->resource[1], 0,
ETX_REG_SIZE, "HME TX Regs");
if (!hp->etxregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Transmit registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map MAC TX registers.\n");
goto err_out_iounmap;
}
hp->erxregs = sbus_ioremap(&sdev->resource[2], 0,
ERX_REG_SIZE, "HME RX Regs");
if (!hp->erxregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal MAC Receive registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map MAC RX registers.\n");
goto err_out_iounmap;
}
hp->bigmacregs = sbus_ioremap(&sdev->resource[3], 0,
BMAC_REG_SIZE, "HME BIGMAC Regs");
if (!hp->bigmacregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal BIGMAC registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map BIGMAC registers.\n");
goto err_out_iounmap;
}
hp->tcvregs = sbus_ioremap(&sdev->resource[4], 0,
TCVR_REG_SIZE, "HME Tranceiver Regs");
if (!hp->tcvregs) {
- printk(KERN_ERR "happymeal: Cannot map Happy Meal Tranceiver registers.\n");
+ printk(KERN_ERR "happymeal: Cannot map TCVR registers.\n");
goto err_out_iounmap;
}
- hp->hm_revision = prom_getintdefault(sdev->prom_node, "hm-rev", 0xff);
+ hp->hm_revision = of_getintprop_default(dp, "hm-rev", 0xff);
if (hp->hm_revision == 0xff)
hp->hm_revision = 0xa0;
@@ -2807,8 +2783,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
hp->happy_flags |= HFLAG_QUATTRO;
/* Get the supported DVMA burst sizes from our Happy SBUS. */
- hp->happy_bursts = prom_getintdefault(sdev->bus->prom_node,
- "burst-sizes", 0x00);
+ hp->happy_bursts = of_getintprop_default(sdev->bus->ofdev.node,
+ "burst-sizes", 0x00);
hp->happy_block = sbus_alloc_consistent(hp->happy_dev,
PAGE_SIZE,
@@ -2871,6 +2847,8 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
goto err_out_free_consistent;
}
+ dev_set_drvdata(&sdev->ofdev.dev, hp);
+
if (qfe_slot != -1)
printk(KERN_INFO "%s: Quattro HME slot %d (SBUS) 10/100baseT Ethernet ",
dev->name, qfe_slot);
@@ -2883,12 +2861,6 @@ static int __init happy_meal_sbus_init(struct sbus_dev *sdev, int is_qfe)
dev->dev_addr[i], i == 5 ? ' ' : ':');
printk("\n");
- /* We are home free at this point, link us in to the happy
- * device list.
- */
- hp->next_module = root_happy_dev;
- root_happy_dev = hp;
-
return 0;
err_out_free_consistent:
@@ -2918,7 +2890,7 @@ err_out:
#endif
#ifdef CONFIG_PCI
-#ifndef __sparc__
+#ifndef CONFIG_SPARC
static int is_quattro_p(struct pci_dev *pdev)
{
struct pci_dev *busdev = pdev->bus->self;
@@ -3006,14 +2978,14 @@ static void get_hme_mac_nonsparc(struct pci_dev *pdev, unsigned char *dev_addr)
get_random_bytes(&dev_addr[3], 3);
return;
}
-#endif /* !(__sparc__) */
+#endif /* !(CONFIG_SPARC) */
-static int __init happy_meal_pci_init(struct pci_dev *pdev)
+static int __devinit happy_meal_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct quattro *qp = NULL;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
struct pcidev_cookie *pcp;
- int node;
#endif
struct happy_meal *hp;
struct net_device *dev;
@@ -3024,15 +2996,14 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
int err;
/* Now make sure pci_dev cookie is there. */
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
pcp = pdev->sysdata;
- if (pcp == NULL || pcp->prom_node == -1) {
+ if (pcp == NULL) {
printk(KERN_ERR "happymeal(PCI): Some PCI device info missing\n");
return -ENODEV;
}
- node = pcp->prom_node;
-
- prom_getstring(node, "name", prom_name, sizeof(prom_name));
+
+ strcpy(prom_name, pcp->prom_node->name);
#else
if (is_quattro_p(pdev))
strcpy(prom_name, "SUNW,qfe");
@@ -3075,7 +3046,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
hp->qfe_parent = qp;
hp->qfe_ent = qfe_slot;
qp->happy_meals[qfe_slot] = dev;
- }
+ }
hpreg_res = pci_resource_start(pdev, 0);
err = -ENODEV;
@@ -3103,11 +3074,15 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
dev->dev_addr[i] = macaddr[i];
macaddr[5]++;
} else {
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
+ unsigned char *addr;
+ int len;
+
if (qfe_slot != -1 &&
- prom_getproplen(node, "local-mac-address") == 6) {
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
+ (addr = of_get_property(pcp->prom_node,
+ "local-mac-address", &len)) != NULL
+ && len == 6) {
+ memcpy(dev->dev_addr, addr, 6);
} else {
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
}
@@ -3115,7 +3090,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
get_hme_mac_nonsparc(pdev, &dev->dev_addr[0]);
#endif
}
-
+
/* Layout registers. */
hp->gregs = (hpreg_base + 0x0000UL);
hp->etxregs = (hpreg_base + 0x2000UL);
@@ -3123,8 +3098,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
hp->bigmacregs = (hpreg_base + 0x6000UL);
hp->tcvregs = (hpreg_base + 0x7000UL);
-#ifdef __sparc__
- hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
+#ifdef CONFIG_SPARC
+ hp->hm_revision = of_getintprop_default(pcp->prom_node, "hm-rev", 0xff);
if (hp->hm_revision == 0xff) {
unsigned char prev;
@@ -3148,7 +3123,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
/* And of course, indicate this is PCI. */
hp->happy_flags |= HFLAG_PCI;
-#ifdef __sparc__
+#ifdef CONFIG_SPARC
/* Assume PCI happy meals can handle all burst sizes. */
hp->happy_bursts = DMA_BURSTBITS;
#endif
@@ -3211,6 +3186,8 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
goto err_out_iounmap;
}
+ dev_set_drvdata(&pdev->dev, hp);
+
if (!qfe_slot) {
struct pci_dev *qpdev = qp->quattro_dev;
@@ -3224,7 +3201,7 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
qpdev->device == PCI_DEVICE_ID_DEC_21153)
printk("DEC 21153 PCI Bridge\n");
else
- printk("unknown bridge %04x.%04x\n",
+ printk("unknown bridge %04x.%04x\n",
qpdev->vendor, qpdev->device);
}
@@ -3240,12 +3217,6 @@ static int __init happy_meal_pci_init(struct pci_dev *pdev)
printk("\n");
- /* We are home free at this point, link us in to the happy
- * device list.
- */
- hp->next_module = root_happy_dev;
- root_happy_dev = hp;
-
return 0;
err_out_iounmap:
@@ -3263,136 +3234,141 @@ err_out_clear_quattro:
err_out:
return err;
}
-#endif
-#ifdef CONFIG_SBUS
-static int __init happy_meal_sbus_probe(void)
+static void __devexit happy_meal_pci_remove(struct pci_dev *pdev)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int cards = 0;
- char model[128];
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- char *name = sdev->prom_name;
-
- if (!strcmp(name, "SUNW,hme")) {
- cards++;
- prom_getstring(sdev->prom_node, "model",
- model, sizeof(model));
- if (!strcmp(model, "SUNW,sbus-qfe"))
- happy_meal_sbus_init(sdev, 1);
- else
- happy_meal_sbus_init(sdev, 0);
- } else if (!strcmp(name, "qfe") ||
- !strcmp(name, "SUNW,qfe")) {
- cards++;
- happy_meal_sbus_init(sdev, 1);
- }
- }
- }
- if (cards != 0)
- quattro_sbus_register_irqs();
- return cards;
+ struct happy_meal *hp = dev_get_drvdata(&pdev->dev);
+ struct net_device *net_dev = hp->dev;
+
+ unregister_netdev(net_dev);
+
+ pci_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+ iounmap(hp->gregs);
+ pci_release_regions(hp->happy_dev);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&pdev->dev, NULL);
}
-#endif
-#ifdef CONFIG_PCI
-static int __init happy_meal_pci_probe(void)
+static struct pci_device_id happymeal_pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_HAPPYMEAL) },
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, happymeal_pci_ids);
+
+static struct pci_driver hme_pci_driver = {
+ .name = "hme",
+ .id_table = happymeal_pci_ids,
+ .probe = happy_meal_pci_probe,
+ .remove = __devexit_p(happy_meal_pci_remove),
+};
+
+static int __init happy_meal_pci_init(void)
+{
+ return pci_register_driver(&hme_pci_driver);
+}
+
+static void happy_meal_pci_exit(void)
{
- struct pci_dev *pdev = NULL;
- int cards = 0;
+ pci_unregister_driver(&hme_pci_driver);
- while ((pdev = pci_find_device(PCI_VENDOR_ID_SUN,
- PCI_DEVICE_ID_SUN_HAPPYMEAL, pdev)) != NULL) {
- if (pci_enable_device(pdev))
- continue;
- pci_set_master(pdev);
- cards++;
- happy_meal_pci_init(pdev);
+ while (qfe_pci_list) {
+ struct quattro *qfe = qfe_pci_list;
+ struct quattro *next = qfe->next;
+
+ kfree(qfe);
+
+ qfe_pci_list = next;
}
- return cards;
}
+
#endif
-static int __init happy_meal_probe(void)
+#ifdef CONFIG_SBUS
+static int __devinit hme_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- static int called = 0;
- int cards;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ char *model = of_get_property(dp, "model", NULL);
+ int is_qfe = (match->data != NULL);
- root_happy_dev = NULL;
+ if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe"))
+ is_qfe = 1;
- if (called)
- return -ENODEV;
- called++;
+ return happy_meal_sbus_probe_one(sdev, is_qfe);
+}
+
+static int __devexit hme_sbus_remove(struct of_device *dev)
+{
+ struct happy_meal *hp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = hp->dev;
+
+ unregister_netdevice(net_dev);
+
+ /* XXX qfe parent interrupt... */
+
+ sbus_iounmap(hp->gregs, GREG_REG_SIZE);
+ sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
+ sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
+ sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
+ sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
+ sbus_free_consistent(hp->happy_dev,
+ PAGE_SIZE,
+ hp->happy_block,
+ hp->hblock_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
- cards = 0;
-#ifdef CONFIG_SBUS
- cards += happy_meal_sbus_probe();
-#endif
-#ifdef CONFIG_PCI
- cards += happy_meal_pci_probe();
-#endif
- if (!cards)
- return -ENODEV;
return 0;
}
+static struct of_device_id hme_sbus_match[] = {
+ {
+ .name = "SUNW,hme",
+ },
+ {
+ .name = "SUNW,qfe",
+ .data = (void *) 1,
+ },
+ {
+ .name = "qfe",
+ .data = (void *) 1,
+ },
+ {},
+};
-static void __exit happy_meal_cleanup_module(void)
-{
-#ifdef CONFIG_SBUS
- struct quattro *last_seen_qfe = NULL;
-#endif
+MODULE_DEVICE_TABLE(of, hme_sbus_match);
- while (root_happy_dev) {
- struct happy_meal *hp = root_happy_dev;
- struct happy_meal *next = root_happy_dev->next_module;
- struct net_device *dev = hp->dev;
+static struct of_platform_driver hme_sbus_driver = {
+ .name = "hme",
+ .match_table = hme_sbus_match,
+ .probe = hme_sbus_probe,
+ .remove = __devexit_p(hme_sbus_remove),
+};
- /* Unregister netdev before unmapping registers as this
- * call can end up trying to access those registers.
- */
- unregister_netdev(dev);
+static int __init happy_meal_sbus_init(void)
+{
+ int err;
-#ifdef CONFIG_SBUS
- if (!(hp->happy_flags & HFLAG_PCI)) {
- if (hp->happy_flags & HFLAG_QUATTRO) {
- if (hp->qfe_parent != last_seen_qfe) {
- free_irq(dev->irq, hp->qfe_parent);
- last_seen_qfe = hp->qfe_parent;
- }
- }
+ err = of_register_driver(&hme_sbus_driver, &sbus_bus_type);
+ if (!err)
+ quattro_sbus_register_irqs();
- sbus_iounmap(hp->gregs, GREG_REG_SIZE);
- sbus_iounmap(hp->etxregs, ETX_REG_SIZE);
- sbus_iounmap(hp->erxregs, ERX_REG_SIZE);
- sbus_iounmap(hp->bigmacregs, BMAC_REG_SIZE);
- sbus_iounmap(hp->tcvregs, TCVR_REG_SIZE);
- sbus_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
- }
-#endif
-#ifdef CONFIG_PCI
- if ((hp->happy_flags & HFLAG_PCI)) {
- pci_free_consistent(hp->happy_dev,
- PAGE_SIZE,
- hp->happy_block,
- hp->hblock_dvma);
- iounmap(hp->gregs);
- pci_release_regions(hp->happy_dev);
- }
-#endif
- free_netdev(dev);
+ return err;
+}
- root_happy_dev = next;
- }
+static void happy_meal_sbus_exit(void)
+{
+ of_unregister_driver(&hme_sbus_driver);
+ quattro_sbus_free_irqs();
- /* Now cleanup the quattro lists. */
-#ifdef CONFIG_SBUS
while (qfe_sbus_list) {
struct quattro *qfe = qfe_sbus_list;
struct quattro *next = qfe->next;
@@ -3401,18 +3377,39 @@ static void __exit happy_meal_cleanup_module(void)
qfe_sbus_list = next;
}
+}
#endif
-#ifdef CONFIG_PCI
- while (qfe_pci_list) {
- struct quattro *qfe = qfe_pci_list;
- struct quattro *next = qfe->next;
- kfree(qfe);
+static int __init happy_meal_probe(void)
+{
+ int err = 0;
- qfe_pci_list = next;
+#ifdef CONFIG_SBUS
+ err = happy_meal_sbus_init();
+#endif
+#ifdef CONFIG_PCI
+ if (!err) {
+ err = happy_meal_pci_init();
+#ifdef CONFIG_SBUS
+ if (err)
+ happy_meal_sbus_exit();
+#endif
}
#endif
+
+ return err;
+}
+
+
+static void __exit happy_meal_exit(void)
+{
+#ifdef CONFIG_SBUS
+ happy_meal_sbus_exit();
+#endif
+#ifdef CONFIG_PCI
+ happy_meal_pci_exit();
+#endif
}
module_init(happy_meal_probe);
-module_exit(happy_meal_cleanup_module);
+module_exit(happy_meal_exit);
diff --git a/drivers/net/sunhme.h b/drivers/net/sunhme.h
index 34e9f953cea..90f446db9ba 100644
--- a/drivers/net/sunhme.h
+++ b/drivers/net/sunhme.h
@@ -8,7 +8,6 @@
#ifndef _SUNHME_H
#define _SUNHME_H
-#include <linux/config.h>
#include <linux/pci.h>
/* Happy Meal global registers. */
@@ -461,7 +460,6 @@ struct happy_meal {
struct net_device *dev; /* Backpointer */
struct quattro *qfe_parent; /* For Quattro cards */
int qfe_ent; /* Which instance on quattro */
- struct happy_meal *next_module;
};
/* Here are the happy flags. */
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 6381243d8d0..feb42db10ee 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -64,14 +64,13 @@
* David S. Miller (davem@redhat.com)
* 2.01:
* 11/08/01: Use library crc32 functions (Matt_Domsch@dell.com)
- *
+ *
*/
#undef DEBUG_DRIVER
static char lancestr[] = "LANCE";
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -210,7 +209,7 @@ struct lance_tx_desc {
s16 length; /* Length is 2s complement (negative)! */
u16 misc;
};
-
+
/* The LANCE initialization block, described in databook. */
/* On the Sparc, this block should be on a DMA region */
struct lance_init_block {
@@ -223,11 +222,11 @@ struct lance_init_block {
u16 rx_len; /* receive len and high addr */
u16 tx_ptr; /* transmit descriptor addr */
u16 tx_len; /* transmit len and high addr */
-
+
/* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
struct lance_rx_desc brx_ring[RX_RING_SIZE];
struct lance_tx_desc btx_ring[TX_RING_SIZE];
-
+
u8 tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
u8 pad[2]; /* align rx_buf for copy_and_sum(). */
u8 rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
@@ -244,12 +243,12 @@ struct lance_private {
void __iomem *dregs; /* DMA controller regs. */
struct lance_init_block __iomem *init_block_iomem;
struct lance_init_block *init_block_mem;
-
+
spinlock_t lock;
int rx_new, tx_new;
int rx_old, tx_old;
-
+
struct net_device_stats stats;
struct sbus_dma *ledma; /* If set this points to ledma */
char tpe; /* cable-selection is TPE */
@@ -266,7 +265,6 @@ struct lance_private {
char *name;
dma_addr_t init_block_dvma;
struct net_device *dev; /* Backpointer */
- struct lance_private *next_module;
struct sbus_dev *sdev;
struct timer_list multicast_timer;
};
@@ -298,8 +296,6 @@ int sparc_lance_debug = 2;
#define LANCE_ADDR(x) ((long)(x) & ~0xff000000)
-static struct lance_private *root_lance_dev;
-
/* Load the CSR registers */
static void load_csrs(struct lance_private *lp)
{
@@ -329,7 +325,7 @@ static void lance_init_ring_dvma(struct net_device *dev)
dma_addr_t aib = lp->init_block_dvma;
__u32 leptr;
int i;
-
+
/* Lock out other processes while setting up hardware */
netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
@@ -367,12 +363,12 @@ static void lance_init_ring_dvma(struct net_device *dev)
}
/* Setup the initialization block */
-
+
/* Setup rx descriptor pointer */
leptr = LANCE_ADDR(aib + libdesc_offset(brx_ring, 0));
ib->rx_len = (LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16);
ib->rx_ptr = leptr;
-
+
/* Setup tx descriptor pointer */
leptr = LANCE_ADDR(aib + libdesc_offset(btx_ring, 0));
ib->tx_len = (LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16);
@@ -385,7 +381,7 @@ static void lance_init_ring_pio(struct net_device *dev)
struct lance_init_block __iomem *ib = lp->init_block_iomem;
u32 leptr;
int i;
-
+
/* Lock out other processes while setting up hardware */
netif_stop_queue(dev);
lp->rx_new = lp->tx_new = 0;
@@ -426,13 +422,13 @@ static void lance_init_ring_pio(struct net_device *dev)
}
/* Setup the initialization block */
-
+
/* Setup rx descriptor pointer */
leptr = libdesc_offset(brx_ring, 0);
sbus_writew((LANCE_LOG_RX_BUFFERS << 13) | (leptr >> 16),
&ib->rx_len);
sbus_writew(leptr, &ib->rx_ptr);
-
+
/* Setup tx descriptor pointer */
leptr = libdesc_offset(btx_ring, 0);
sbus_writew((LANCE_LOG_TX_BUFFERS << 13) | (leptr >> 16),
@@ -548,7 +544,7 @@ static void lance_rx_dvma(struct net_device *dev)
lp->rx_new = RX_NEXT(entry);
return;
}
-
+
lp->stats.rx_bytes += len;
skb->dev = dev;
@@ -588,10 +584,10 @@ static void lance_tx_dvma(struct net_device *dev)
/* If we hit a packet not owned by us, stop */
if (bits & LE_T1_OWN)
break;
-
+
if (bits & LE_T1_ERR) {
u16 status = td->misc;
-
+
lp->stats.tx_errors++;
if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
@@ -640,7 +636,7 @@ static void lance_tx_dvma(struct net_device *dev)
lp->stats.tx_packets++;
}
-
+
j = TX_NEXT(j);
}
lp->tx_old = j;
@@ -722,7 +718,7 @@ static void lance_rx_pio(struct net_device *dev)
lp->rx_new = RX_NEXT(entry);
return;
}
-
+
lp->stats.rx_bytes += len;
skb->dev = dev;
@@ -760,10 +756,10 @@ static void lance_tx_pio(struct net_device *dev)
/* If we hit a packet not owned by us, stop */
if (bits & LE_T1_OWN)
break;
-
+
if (bits & LE_T1_ERR) {
u16 status = sbus_readw(&td->misc);
-
+
lp->stats.tx_errors++;
if (status & LE_T3_RTY) lp->stats.tx_aborted_errors++;
if (status & LE_T3_LCOL) lp->stats.tx_window_errors++;
@@ -812,7 +808,7 @@ static void lance_tx_pio(struct net_device *dev)
lp->stats.tx_packets++;
}
-
+
j = TX_NEXT(j);
}
lp->tx_old = j;
@@ -829,27 +825,27 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct net_device *dev = (struct net_device *)dev_id;
struct lance_private *lp = netdev_priv(dev);
int csr0;
-
+
sbus_writew(LE_CSR0, lp->lregs + RAP);
csr0 = sbus_readw(lp->lregs + RDP);
/* Acknowledge all the interrupt sources ASAP */
sbus_writew(csr0 & (LE_C0_INTR | LE_C0_TINT | LE_C0_RINT),
lp->lregs + RDP);
-
+
if ((csr0 & LE_C0_ERR) != 0) {
/* Clear the error condition */
sbus_writew((LE_C0_BABL | LE_C0_ERR | LE_C0_MISS |
LE_C0_CERR | LE_C0_MERR),
lp->lregs + RDP);
}
-
+
if (csr0 & LE_C0_RINT)
lp->rx(dev);
-
+
if (csr0 & LE_C0_TINT)
lp->tx(dev);
-
+
if (csr0 & LE_C0_BABL)
lp->stats.tx_errors++;
@@ -934,7 +930,7 @@ static int lance_open(struct net_device *dev)
STOP_LANCE(lp);
- if (request_irq(dev->irq, &lance_interrupt, SA_SHIRQ,
+ if (request_irq(dev->irq, &lance_interrupt, IRQF_SHARED,
lancestr, (void *) dev)) {
printk(KERN_ERR "Lance: Can't get irq %d\n", dev->irq);
return -EAGAIN;
@@ -996,7 +992,7 @@ static int lance_reset(struct net_device *dev)
{
struct lance_private *lp = netdev_priv(dev);
int status;
-
+
STOP_LANCE(lp);
/* On the 4m, reset the dma too */
@@ -1173,7 +1169,7 @@ static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->trans_start = jiffies;
dev_kfree_skb(skb);
-
+
return 0;
}
@@ -1193,7 +1189,7 @@ static void lance_load_multicast(struct net_device *dev)
int i;
u32 crc;
u32 val;
-
+
/* set all multicast bits */
if (dev->flags & IFF_ALLMULTI)
val = ~0;
@@ -1212,7 +1208,7 @@ static void lance_load_multicast(struct net_device *dev)
if (dev->flags & IFF_ALLMULTI)
return;
-
+
/* Add addresses */
for (i = 0; i < dev->mc_count; i++) {
addrs = dmi->dmi_addr;
@@ -1322,14 +1318,14 @@ static u32 sparc_lance_get_link(struct net_device *dev)
return 1;
}
-static struct ethtool_ops sparc_lance_ethtool_ops = {
+static const struct ethtool_ops sparc_lance_ethtool_ops = {
.get_drvinfo = sparc_lance_get_drvinfo,
.get_link = sparc_lance_get_link,
};
-static int __init sparc_lance_init(struct sbus_dev *sdev,
- struct sbus_dma *ledma,
- struct sbus_dev *lebuffer)
+static int __devinit sparc_lance_probe_one(struct sbus_dev *sdev,
+ struct sbus_dma *ledma,
+ struct sbus_dev *lebuffer)
{
static unsigned version_printed;
struct net_device *dev;
@@ -1473,6 +1469,7 @@ no_link_test:
lp->dev = dev;
SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
dev->open = &lance_open;
dev->stop = &lance_close;
dev->hard_start_xmit = &lance_start_xmit;
@@ -1500,8 +1497,7 @@ no_link_test:
goto fail;
}
- lp->next_module = root_lance_dev;
- root_lance_dev = lp;
+ dev_set_drvdata(&sdev->ofdev.dev, lp);
printk(KERN_INFO "%s: LANCE ", dev->name);
@@ -1519,7 +1515,7 @@ fail:
}
/* On 4m, find the associated dma for the lance chip */
-static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
+static struct sbus_dma * __devinit find_ledma(struct sbus_dev *sdev)
{
struct sbus_dma *p;
@@ -1536,88 +1532,107 @@ static inline struct sbus_dma *find_ledma(struct sbus_dev *sdev)
#include <asm/machines.h>
/* Find all the lance cards on the system and initialize them */
-static int __init sparc_lance_probe(void)
+static struct sbus_dev sun4_sdev;
+static int __devinit sparc_lance_init(void)
{
- static struct sbus_dev sdev;
- static int called;
-
- root_lance_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
if ((idprom->id_machtype == (SM_SUN4|SM_4_330)) ||
(idprom->id_machtype == (SM_SUN4|SM_4_470))) {
- memset(&sdev, 0, sizeof(sdev));
- sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
- sdev.irqs[0] = 6;
- return sparc_lance_init(&sdev, NULL, NULL);
+ memset(&sun4_sdev, 0, sizeof(struct sbus_dev));
+ sun4_sdev.reg_addrs[0].phys_addr = sun4_eth_physaddr;
+ sun4_sdev.irqs[0] = 6;
+ return sparc_lance_probe_one(&sun4_sdev, NULL, NULL);
}
return -ENODEV;
}
+static int __exit sunlance_sun4_remove(void)
+{
+ struct lance_private *lp = dev_get_drvdata(&sun4_sdev.ofdev.dev);
+ struct net_device *net_dev = lp->dev;
+
+ unregister_netdevice(net_dev);
+
+ lance_free_hwresources(lp);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&sun4_sdev.ofdev.dev, NULL);
+
+ return 0;
+}
+
#else /* !CONFIG_SUN4 */
-/* Find all the lance cards on the system and initialize them */
-static int __init sparc_lance_probe(void)
+static int __devinit sunlance_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
- struct sbus_dma *ledma = NULL;
- static int called;
- int cards = 0, v;
-
- root_lance_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus (bus) {
- for_each_sbusdev (sdev, bus) {
- if (strcmp(sdev->prom_name, "le") == 0) {
- cards++;
- if ((v = sparc_lance_init(sdev, NULL, NULL)))
- return v;
- continue;
- }
- if (strcmp(sdev->prom_name, "ledma") == 0) {
- cards++;
- ledma = find_ledma(sdev);
- if ((v = sparc_lance_init(sdev->child,
- ledma, NULL)))
- return v;
- continue;
- }
- if (strcmp(sdev->prom_name, "lebuffer") == 0){
- cards++;
- if ((v = sparc_lance_init(sdev->child,
- NULL, sdev)))
- return v;
- continue;
- }
- } /* for each sbusdev */
- } /* for each sbus */
- if (!cards)
- return -ENODEV;
- return 0;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ int err;
+
+ if (sdev->parent) {
+ struct of_device *parent = &sdev->parent->ofdev;
+
+ if (!strcmp(parent->node->name, "ledma")) {
+ struct sbus_dma *ledma = find_ledma(to_sbus_device(&parent->dev));
+
+ err = sparc_lance_probe_one(sdev, ledma, NULL);
+ } else if (!strcmp(parent->node->name, "lebuffer")) {
+ err = sparc_lance_probe_one(sdev, NULL, to_sbus_device(&parent->dev));
+ } else
+ err = sparc_lance_probe_one(sdev, NULL, NULL);
+ } else
+ err = sparc_lance_probe_one(sdev, NULL, NULL);
+
+ return err;
}
-#endif /* !CONFIG_SUN4 */
-static void __exit sparc_lance_cleanup(void)
+static int __devexit sunlance_sbus_remove(struct of_device *dev)
{
- struct lance_private *lp;
+ struct lance_private *lp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = lp->dev;
- while (root_lance_dev) {
- lp = root_lance_dev->next_module;
+ unregister_netdevice(net_dev);
- unregister_netdev(root_lance_dev->dev);
- lance_free_hwresources(root_lance_dev);
- free_netdev(root_lance_dev->dev);
- root_lance_dev = lp;
- }
+ lance_free_hwresources(lp);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
+}
+
+static struct of_device_id sunlance_sbus_match[] = {
+ {
+ .name = "le",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sunlance_sbus_match);
+
+static struct of_platform_driver sunlance_sbus_driver = {
+ .name = "sunlance",
+ .match_table = sunlance_sbus_match,
+ .probe = sunlance_sbus_probe,
+ .remove = __devexit_p(sunlance_sbus_remove),
+};
+
+
+/* Find all the lance cards on the system and initialize them */
+static int __init sparc_lance_init(void)
+{
+ return of_register_driver(&sunlance_sbus_driver, &sbus_bus_type);
+}
+#endif /* !CONFIG_SUN4 */
+
+static void __exit sparc_lance_exit(void)
+{
+#ifdef CONFIG_SUN4
+ sunlance_sun4_remove();
+#else
+ of_unregister_driver(&sunlance_sbus_driver);
+#endif
}
-module_init(sparc_lance_probe);
-module_exit(sparc_lance_cleanup);
+module_init(sparc_lance_init);
+module_exit(sparc_lance_exit);
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 1f2323be60d..9202a1c369d 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -1,10 +1,9 @@
-/* $Id: sunqe.c,v 1.55 2002/01/15 06:48:55 davem Exp $
- * sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
+/* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
* if you make it look like a LANCE.
*
- * Copyright (C) 1996, 1999, 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1996, 1999, 2003, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -41,9 +40,9 @@
#include "sunqe.h"
#define DRV_NAME "sunqe"
-#define DRV_VERSION "3.0"
-#define DRV_RELDATE "8/24/03"
-#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION "4.0"
+#define DRV_RELDATE "June 23, 2006"
+#define DRV_AUTHOR "David S. Miller (davem@davemloft.net)"
static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
@@ -452,7 +451,7 @@ static void qe_rx(struct sunqe *qep)
}
end_rxd->rx_addr = this_qbuf_dvma;
end_rxd->rx_flags = (RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH));
-
+
elem = NEXT_RX(elem);
this = &rxbase[elem];
}
@@ -719,7 +718,7 @@ static u32 qe_get_link(struct net_device *dev)
return (phyconfig & MREGS_PHYCONFIG_LSTAT);
}
-static struct ethtool_ops qe_ethtool_ops = {
+static const struct ethtool_ops qe_ethtool_ops = {
.get_drvinfo = qe_get_drvinfo,
.get_link = qe_get_link,
};
@@ -755,298 +754,269 @@ static inline void qec_init_once(struct sunqec *qecp, struct sbus_dev *qsdev)
qecp->gregs + GLOB_RSIZE);
}
-/* Four QE's per QEC card. */
-static int __init qec_ether_init(struct net_device *dev, struct sbus_dev *sdev)
+static u8 __init qec_get_burst(struct device_node *dp)
{
- static unsigned version_printed;
- struct net_device *qe_devs[4];
- struct sunqe *qeps[4];
- struct sbus_dev *qesdevs[4];
- struct sbus_dev *child;
- struct sunqec *qecp = NULL;
u8 bsizes, bsizes_more;
- int i, j, res = -ENOMEM;
- for (i = 0; i < 4; i++) {
- qe_devs[i] = alloc_etherdev(sizeof(struct sunqe));
- if (!qe_devs[i])
- goto out;
- }
+ /* Find and set the burst sizes for the QEC, since it
+ * does the actual dma for all 4 channels.
+ */
+ bsizes = of_getintprop_default(dp, "burst-sizes", 0xff);
+ bsizes &= 0xff;
+ bsizes_more = of_getintprop_default(dp->parent, "burst-sizes", 0xff);
- if (version_printed++ == 0)
- printk(KERN_INFO "%s", version);
+ if (bsizes_more != 0xff)
+ bsizes &= bsizes_more;
+ if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||
+ (bsizes & DMA_BURST32)==0)
+ bsizes = (DMA_BURST32 - 1);
- for (i = 0; i < 4; i++) {
- qeps[i] = (struct sunqe *) qe_devs[i]->priv;
- for (j = 0; j < 6; j++)
- qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j];
- qeps[i]->channel = i;
- spin_lock_init(&qeps[i]->lock);
- }
+ return bsizes;
+}
- qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL);
- if (qecp == NULL)
- goto out1;
- qecp->qec_sdev = sdev;
+static struct sunqec * __init get_qec(struct sbus_dev *child_sdev)
+{
+ struct sbus_dev *qec_sdev = child_sdev->parent;
+ struct sunqec *qecp;
- for (i = 0; i < 4; i++) {
- qecp->qes[i] = qeps[i];
- qeps[i]->dev = qe_devs[i];
- qeps[i]->parent = qecp;
+ for (qecp = root_qec_dev; qecp; qecp = qecp->next_module) {
+ if (qecp->qec_sdev == qec_sdev)
+ break;
}
+ if (!qecp) {
+ qecp = kzalloc(sizeof(struct sunqec), GFP_KERNEL);
+ if (qecp) {
+ u32 ctrl;
+
+ qecp->qec_sdev = qec_sdev;
+ qecp->gregs = sbus_ioremap(&qec_sdev->resource[0], 0,
+ GLOB_REG_SIZE,
+ "QEC Global Registers");
+ if (!qecp->gregs)
+ goto fail;
+
+ /* Make sure the QEC is in MACE mode. */
+ ctrl = sbus_readl(qecp->gregs + GLOB_CTRL);
+ ctrl &= 0xf0000000;
+ if (ctrl != GLOB_CTRL_MMODE) {
+ printk(KERN_ERR "qec: Not in MACE mode!\n");
+ goto fail;
+ }
- res = -ENODEV;
+ if (qec_global_reset(qecp->gregs))
+ goto fail;
- for (i = 0, child = sdev->child; i < 4; i++, child = child->next) {
- /* Link in channel */
- j = prom_getintdefault(child->prom_node, "channel#", -1);
- if (j == -1)
- goto out2;
- qesdevs[j] = child;
- }
+ qecp->qec_bursts = qec_get_burst(qec_sdev->ofdev.node);
- for (i = 0; i < 4; i++)
- qeps[i]->qe_sdev = qesdevs[i];
+ qec_init_once(qecp, qec_sdev);
- /* Now map in the registers, QEC globals first. */
- qecp->gregs = sbus_ioremap(&sdev->resource[0], 0,
- GLOB_REG_SIZE, "QEC Global Registers");
- if (!qecp->gregs) {
- printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n");
- goto out2;
- }
+ if (request_irq(qec_sdev->irqs[0], &qec_interrupt,
+ IRQF_SHARED, "qec", (void *) qecp)) {
+ printk(KERN_ERR "qec: Can't register irq.\n");
+ goto fail;
+ }
- /* Make sure the QEC is in MACE mode. */
- if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) {
- printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n");
- goto out3;
+ qecp->next_module = root_qec_dev;
+ root_qec_dev = qecp;
+ }
}
- /* Reset the QEC. */
- if (qec_global_reset(qecp->gregs))
- goto out3;
+ return qecp;
- /* Find and set the burst sizes for the QEC, since it does
- * the actual dma for all 4 channels.
- */
- bsizes = prom_getintdefault(sdev->prom_node, "burst-sizes", 0xff);
- bsizes &= 0xff;
- bsizes_more = prom_getintdefault(sdev->bus->prom_node, "burst-sizes", 0xff);
+fail:
+ if (qecp->gregs)
+ sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
+ kfree(qecp);
+ return NULL;
+}
- if (bsizes_more != 0xff)
- bsizes &= bsizes_more;
- if (bsizes == 0xff || (bsizes & DMA_BURST16) == 0 ||
- (bsizes & DMA_BURST32)==0)
- bsizes = (DMA_BURST32 - 1);
+static int __init qec_ether_init(struct sbus_dev *sdev)
+{
+ static unsigned version_printed;
+ struct net_device *dev;
+ struct sunqe *qe;
+ struct sunqec *qecp;
+ int i, res;
- qecp->qec_bursts = bsizes;
+ if (version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
- /* Perform one time QEC initialization, we never touch the QEC
- * globals again after this.
- */
- qec_init_once(qecp, sdev);
-
- for (i = 0; i < 4; i++) {
- struct sunqe *qe = qeps[i];
- /* Map in QEC per-channel control registers. */
- qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
- CREG_REG_SIZE, "QEC Channel Registers");
- if (!qe->qcregs) {
- printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i);
- goto out4;
- }
+ dev = alloc_etherdev(sizeof(struct sunqe));
+ if (!dev)
+ return -ENOMEM;
- /* Map in per-channel AMD MACE registers. */
- qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
- MREGS_REG_SIZE, "QE MACE Registers");
- if (!qe->mregs) {
- printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i);
- goto out4;
- }
+ qe = netdev_priv(dev);
- qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
- PAGE_SIZE,
- &qe->qblock_dvma);
- qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- &qe->buffers_dvma);
- if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
- qe->buffers == NULL || qe->buffers_dvma == 0) {
- goto out4;
+ i = of_getintprop_default(sdev->ofdev.node, "channel#", -1);
+ if (i == -1) {
+ struct sbus_dev *td = sdev->parent->child;
+ i = 0;
+ while (td != sdev) {
+ td = td->next;
+ i++;
}
-
- /* Stop this QE. */
- qe_stop(qe);
}
+ qe->channel = i;
+ spin_lock_init(&qe->lock);
- for (i = 0; i < 4; i++) {
- SET_MODULE_OWNER(qe_devs[i]);
- qe_devs[i]->open = qe_open;
- qe_devs[i]->stop = qe_close;
- qe_devs[i]->hard_start_xmit = qe_start_xmit;
- qe_devs[i]->get_stats = qe_get_stats;
- qe_devs[i]->set_multicast_list = qe_set_multicast;
- qe_devs[i]->tx_timeout = qe_tx_timeout;
- qe_devs[i]->watchdog_timeo = 5*HZ;
- qe_devs[i]->irq = sdev->irqs[0];
- qe_devs[i]->dma = 0;
- qe_devs[i]->ethtool_ops = &qe_ethtool_ops;
- }
+ res = -ENODEV;
+ qecp = get_qec(sdev);
+ if (!qecp)
+ goto fail;
- /* QEC receives interrupts from each QE, then it sends the actual
- * IRQ to the cpu itself. Since QEC is the single point of
- * interrupt for all QE channels we register the IRQ handler
- * for it now.
- */
- if (request_irq(sdev->irqs[0], &qec_interrupt,
- SA_SHIRQ, "QuadEther", (void *) qecp)) {
- printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n");
- res = -EAGAIN;
- goto out4;
- }
+ qecp->qes[qe->channel] = qe;
+ qe->dev = dev;
+ qe->parent = qecp;
+ qe->qe_sdev = sdev;
- for (i = 0; i < 4; i++) {
- if (register_netdev(qe_devs[i]) != 0)
- goto out5;
+ res = -ENOMEM;
+ qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0,
+ CREG_REG_SIZE, "QEC Channel Registers");
+ if (!qe->qcregs) {
+ printk(KERN_ERR "qe: Cannot map channel registers.\n");
+ goto fail;
}
- /* Report the QE channels. */
- for (i = 0; i < 4; i++) {
- printk(KERN_INFO "%s: QuadEthernet channel[%d] ", qe_devs[i]->name, i);
- for (j = 0; j < 6; j++)
- printk ("%2.2x%c",
- qe_devs[i]->dev_addr[j],
- j == 5 ? ' ': ':');
- printk("\n");
+ qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0,
+ MREGS_REG_SIZE, "QE MACE Registers");
+ if (!qe->mregs) {
+ printk(KERN_ERR "qe: Cannot map MACE registers.\n");
+ goto fail;
}
- /* We are home free at this point, link the qe's into
- * the master list for later driver exit.
- */
- qecp->next_module = root_qec_dev;
- root_qec_dev = qecp;
+ qe->qe_block = sbus_alloc_consistent(qe->qe_sdev,
+ PAGE_SIZE,
+ &qe->qblock_dvma);
+ qe->buffers = sbus_alloc_consistent(qe->qe_sdev,
+ sizeof(struct sunqe_buffers),
+ &qe->buffers_dvma);
+ if (qe->qe_block == NULL || qe->qblock_dvma == 0 ||
+ qe->buffers == NULL || qe->buffers_dvma == 0)
+ goto fail;
+
+ /* Stop this QE. */
+ qe_stop(qe);
+
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, &sdev->ofdev.dev);
+
+ dev->open = qe_open;
+ dev->stop = qe_close;
+ dev->hard_start_xmit = qe_start_xmit;
+ dev->get_stats = qe_get_stats;
+ dev->set_multicast_list = qe_set_multicast;
+ dev->tx_timeout = qe_tx_timeout;
+ dev->watchdog_timeo = 5*HZ;
+ dev->irq = sdev->irqs[0];
+ dev->dma = 0;
+ dev->ethtool_ops = &qe_ethtool_ops;
+
+ res = register_netdev(dev);
+ if (res)
+ goto fail;
+
+ dev_set_drvdata(&sdev->ofdev.dev, qe);
+
+ printk(KERN_INFO "%s: qe channel[%d] ", dev->name, qe->channel);
+ for (i = 0; i < 6; i++)
+ printk ("%2.2x%c",
+ dev->dev_addr[i],
+ i == 5 ? ' ': ':');
+ printk("\n");
+
return 0;
-out5:
- while (i--)
- unregister_netdev(qe_devs[i]);
- free_irq(sdev->irqs[0], (void *)qecp);
-out4:
- for (i = 0; i < 4; i++) {
- struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv;
-
- if (qe->qcregs)
- sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
- if (qe->mregs)
- sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
- if (qe->qe_block)
- sbus_free_consistent(qe->qe_sdev,
- PAGE_SIZE,
- qe->qe_block,
- qe->qblock_dvma);
- if (qe->buffers)
- sbus_free_consistent(qe->qe_sdev,
- sizeof(struct sunqe_buffers),
- qe->buffers,
- qe->buffers_dvma);
- }
-out3:
- sbus_iounmap(qecp->gregs, GLOB_REG_SIZE);
-out2:
- kfree(qecp);
-out1:
- i = 4;
-out:
- while (i--)
- free_netdev(qe_devs[i]);
+fail:
+ if (qe->qcregs)
+ sbus_iounmap(qe->qcregs, CREG_REG_SIZE);
+ if (qe->mregs)
+ sbus_iounmap(qe->mregs, MREGS_REG_SIZE);
+ if (qe->qe_block)
+ sbus_free_consistent(qe->qe_sdev,
+ PAGE_SIZE,
+ qe->qe_block,
+ qe->qblock_dvma);
+ if (qe->buffers)
+ sbus_free_consistent(qe->qe_sdev,
+ sizeof(struct sunqe_buffers),
+ qe->buffers,
+ qe->buffers_dvma);
+
+ free_netdev(dev);
+
return res;
}
-static int __init qec_match(struct sbus_dev *sdev)
+static int __devinit qec_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_dev *sibling;
- int i;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
- if (strcmp(sdev->prom_name, "qec") != 0)
- return 0;
-
- /* QEC can be parent of either QuadEthernet or BigMAC
- * children. Do not confuse this with qfe/SUNW,qfe
- * which is a quad-happymeal card and handled by
- * a different driver.
- */
- sibling = sdev->child;
- for (i = 0; i < 4; i++) {
- if (sibling == NULL)
- return 0;
- if (strcmp(sibling->prom_name, "qe") != 0)
- return 0;
- sibling = sibling->next;
- }
- return 1;
+ return qec_ether_init(sdev);
}
-static int __init qec_probe(void)
+static int __devexit qec_sbus_remove(struct of_device *dev)
{
- struct net_device *dev = NULL;
- struct sbus_bus *bus;
- struct sbus_dev *sdev = NULL;
- static int called;
- int cards = 0, v;
-
- root_qec_dev = NULL;
-
- if (called)
- return -ENODEV;
- called++;
-
- for_each_sbus(bus) {
- for_each_sbusdev(sdev, bus) {
- if (cards)
- dev = NULL;
-
- if (qec_match(sdev)) {
- cards++;
- if ((v = qec_ether_init(dev, sdev)))
- return v;
- }
- }
- }
- if (!cards)
- return -ENODEV;
+ struct sunqe *qp = dev_get_drvdata(&dev->dev);
+ struct net_device *net_dev = qp->dev;
+
+ unregister_netdevice(net_dev);
+
+ sbus_iounmap(qp->qcregs, CREG_REG_SIZE);
+ sbus_iounmap(qp->mregs, MREGS_REG_SIZE);
+ sbus_free_consistent(qp->qe_sdev,
+ PAGE_SIZE,
+ qp->qe_block,
+ qp->qblock_dvma);
+ sbus_free_consistent(qp->qe_sdev,
+ sizeof(struct sunqe_buffers),
+ qp->buffers,
+ qp->buffers_dvma);
+
+ free_netdev(net_dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
return 0;
}
-static void __exit qec_cleanup(void)
+static struct of_device_id qec_sbus_match[] = {
+ {
+ .name = "qe",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, qec_sbus_match);
+
+static struct of_platform_driver qec_sbus_driver = {
+ .name = "qec",
+ .match_table = qec_sbus_match,
+ .probe = qec_sbus_probe,
+ .remove = __devexit_p(qec_sbus_remove),
+};
+
+static int __init qec_init(void)
{
- struct sunqec *next_qec;
- int i;
+ return of_register_driver(&qec_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit qec_exit(void)
+{
+ of_unregister_driver(&qec_sbus_driver);
while (root_qec_dev) {
- next_qec = root_qec_dev->next_module;
-
- /* Release all four QE channels, then the QEC itself. */
- for (i = 0; i < 4; i++) {
- unregister_netdev(root_qec_dev->qes[i]->dev);
- sbus_iounmap(root_qec_dev->qes[i]->qcregs, CREG_REG_SIZE);
- sbus_iounmap(root_qec_dev->qes[i]->mregs, MREGS_REG_SIZE);
- sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
- PAGE_SIZE,
- root_qec_dev->qes[i]->qe_block,
- root_qec_dev->qes[i]->qblock_dvma);
- sbus_free_consistent(root_qec_dev->qes[i]->qe_sdev,
- sizeof(struct sunqe_buffers),
- root_qec_dev->qes[i]->buffers,
- root_qec_dev->qes[i]->buffers_dvma);
- free_netdev(root_qec_dev->qes[i]->dev);
- }
- free_irq(root_qec_dev->qec_sdev->irqs[0], (void *)root_qec_dev);
+ struct sunqec *next = root_qec_dev->next_module;
+
+ free_irq(root_qec_dev->qec_sdev->irqs[0],
+ (void *) root_qec_dev);
sbus_iounmap(root_qec_dev->gregs, GLOB_REG_SIZE);
+
kfree(root_qec_dev);
- root_qec_dev = next_qec;
+
+ root_qec_dev = next;
}
}
-module_init(qec_probe);
-module_exit(qec_cleanup);
+module_init(qec_init);
+module_exit(qec_exit);
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index c2ec9fd8c31..60f02650948 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1,7 +1,7 @@
/* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux.
*
* Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
+ * Author: MontaVista Software, Inc.
* ahennessy@mvista.com
*
* Based on skelton.c by Donald Becker.
@@ -663,7 +663,7 @@ tc35815_init_queues(struct net_device *dev)
#endif
}
#ifdef __mips__
- fd_addr = (unsigned long)vtonocache(lp->fd_buf);
+ fd_addr = (unsigned long)vtonocache(lp->fd_buf);
#else
fd_addr = (unsigned long)lp->fd_buf;
#endif
@@ -880,7 +880,7 @@ tc35815_open(struct net_device *dev)
*/
if (dev->irq == 0 ||
- request_irq(dev->irq, &tc35815_interrupt, SA_SHIRQ, cardname, dev)) {
+ request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) {
return -EAGAIN;
}
@@ -1136,7 +1136,7 @@ tc35815_rx(struct net_device *dev)
int cur_bd, offset;
lp->stats.rx_bytes += pkt_len;
-
+
skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
@@ -1523,7 +1523,7 @@ static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr
struct tc35815_local *lp = dev->priv;
unsigned long data;
unsigned long flags;
-
+
spin_lock_irqsave(&lp->lock, flags);
tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA);
@@ -1725,7 +1725,7 @@ static struct pci_driver tc35815_driver = {
static int __init tc35815_init_module(void)
{
- return pci_module_init(&tc35815_driver);
+ return pci_register_driver(&tc35815_driver);
}
static void __exit tc35815_cleanup_module(void)
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e3e380f90f8..c25ba273b74 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -15,7 +15,6 @@
* notice is accompanying it.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -69,8 +68,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.60"
-#define DRV_MODULE_RELDATE "June 17, 2006"
+#define DRV_MODULE_VERSION "3.66"
+#define DRV_MODULE_RELDATE "September 23, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -124,9 +123,6 @@
TG3_RX_RCB_RING_SIZE(tp))
#define TG3_TX_RING_BYTES (sizeof(struct tg3_tx_buffer_desc) * \
TG3_TX_RING_SIZE)
-#define TX_BUFFS_AVAIL(TP) \
- ((TP)->tx_pending - \
- (((TP)->tx_prod - (TP)->tx_cons) & (TG3_TX_RING_SIZE - 1)))
#define NEXT_TX(N) (((N) + 1) & (TG3_TX_RING_SIZE - 1))
#define RX_PKT_BUF_SZ (1536 + tp->rx_offset + 64)
@@ -153,122 +149,71 @@ module_param(tg3_debug, int, 0);
MODULE_PARM_DESC(tg3_debug, "Tigon3 bitmapped debugging message enable value");
static struct pci_device_id tg3_pci_tbl[] = {
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
- { 0, }
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5700)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5701)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705M_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703X)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702A3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703A3)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5782)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5788)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5789)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5901_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704S_2)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751F)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5752M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5756)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
+ {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1003)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100)},
+ {PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_TIGON3)},
+ {}
};
MODULE_DEVICE_TABLE(pci, tg3_pci_tbl);
-static struct {
+static const struct {
const char string[ETH_GSTRING_LEN];
} ethtool_stats_keys[TG3_NUM_STATS] = {
{ "rx_octets" },
@@ -349,7 +294,7 @@ static struct {
{ "nic_tx_threshold_hit" }
};
-static struct {
+static const struct {
const char string[ETH_GSTRING_LEN];
} ethtool_test_keys[TG3_NUM_TEST] = {
{ "nvram test (online) " },
@@ -367,7 +312,7 @@ static void tg3_write32(struct tg3 *tp, u32 off, u32 val)
static u32 tg3_read32(struct tg3 *tp, u32 off)
{
- return (readl(tp->regs + off));
+ return (readl(tp->regs + off));
}
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
@@ -483,6 +428,16 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
readl(mbox);
}
+static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off)
+{
+ return (readl(tp->regs + off + GRCMBOX_BASE));
+}
+
+static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
+{
+ writel(val, tp->regs + off + GRCMBOX_BASE);
+}
+
#define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val)
#define tw32_mailbox_f(reg, val) tw32_mailbox_flush(tp, (reg), (val))
#define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val)
@@ -498,6 +453,10 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+ (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
+ return;
+
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
@@ -519,6 +478,12 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{
unsigned long flags;
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+ (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
+ *val = 0;
+ return;
+ }
+
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
@@ -548,6 +513,9 @@ static inline void tg3_cond_int(struct tg3 *tp)
if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
(tp->hw_status->status & SD_STATUS_UPDATED))
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+ else
+ tw32(HOSTCC_MODE, tp->coalesce_mode |
+ (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
}
static void tg3_enable_ints(struct tg3 *tp)
@@ -588,7 +556,7 @@ static inline unsigned int tg3_has_work(struct tg3 *tp)
/* tg3_restart_ints
* similar to tg3_enable_ints, but it accurately determines whether there
* is new work pending and can return without flushing the PIO write
- * which reenables interrupts
+ * which reenables interrupts
*/
static void tg3_restart_ints(struct tg3 *tp)
{
@@ -677,7 +645,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
frame_val |= ((reg << MI_COM_REG_ADDR_SHIFT) &
MI_COM_REG_ADDR_MASK);
frame_val |= (MI_COM_CMD_READ | MI_COM_START);
-
+
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
@@ -713,6 +681,10 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
unsigned int loops;
int ret;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+ (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
+ return 0;
+
if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
tw32_f(MAC_MI_MODE,
(tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
@@ -725,7 +697,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
MI_COM_REG_ADDR_MASK);
frame_val |= (val & MI_COM_DATA_MASK);
frame_val |= (MI_COM_CMD_WRITE | MI_COM_START);
-
+
tw32_f(MAC_MI_COM, frame_val);
loops = PHY_BUSY_LOOPS;
@@ -1063,6 +1035,24 @@ out:
phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 phy_reg;
+
+ /* adjust output voltage */
+ tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12);
+
+ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phy_reg)) {
+ u32 phy_reg2;
+
+ tg3_writephy(tp, MII_TG3_EPHY_TEST,
+ phy_reg | MII_TG3_EPHY_SHADOW_EN);
+ /* Enable auto-MDIX */
+ if (!tg3_readphy(tp, 0x10, &phy_reg2))
+ tg3_writephy(tp, 0x10, phy_reg2 | 0x4000);
+ tg3_writephy(tp, MII_TG3_EPHY_TEST, phy_reg);
+ }
+ }
+
tg3_phy_set_wirespeed(tp);
return 0;
}
@@ -1176,6 +1166,15 @@ static void tg3_nvram_unlock(struct tg3 *);
static void tg3_power_down_phy(struct tg3 *tp)
{
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ return;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+ tg3_writephy(tp, MII_TG3_EXT_CTRL,
+ MII_TG3_EXT_CTRL_FORCE_LED_OFF);
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
+ }
+
/* The PHY should not be powered down on some chips because
* of bugs.
*/
@@ -1258,7 +1257,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tg3_setup_phy(tp, 0);
}
- if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val;
+
+ val = tr32(GRC_VCPU_EXT_CTRL);
+ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL);
+ } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
int i;
u32 val;
@@ -1282,7 +1286,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
udelay(40);
- mac_mode = MAC_MODE_PORT_MODE_MII;
+ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ mac_mode = MAC_MODE_PORT_MODE_GMII;
+ else
+ mac_mode = MAC_MODE_PORT_MODE_MII;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
@@ -1360,15 +1367,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}
if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
- /* Turn off the PHY */
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
- tg3_writephy(tp, MII_TG3_EXT_CTRL,
- MII_TG3_EXT_CTRL_FORCE_LED_OFF);
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
- tg3_power_down_phy(tp);
- }
- }
+ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ tg3_power_down_phy(tp);
tg3_frob_aux_power(tp);
@@ -1481,7 +1481,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 local_adv, u32 remote_adv
if (old_rx_mode != tp->rx_mode) {
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
-
+
if (new_tg3_flags & TG3_FLAG_TX_PAUSE)
tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE;
else
@@ -1526,6 +1526,13 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
break;
default:
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
+ SPEED_10;
+ *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
+ DUPLEX_HALF;
+ break;
+ }
*speed = SPEED_INVALID;
*duplex = DUPLEX_INVALID;
break;
@@ -1808,7 +1815,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
- else
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tg3_writephy(tp, MII_TG3_IMASK, ~0);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -2465,24 +2472,27 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
expected_sg_dig_ctrl |= (1 << 12);
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
+ if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+ tp->serdes_counter &&
+ ((mac_status & (MAC_STATUS_PCS_SYNCED |
+ MAC_STATUS_RCVD_CFG)) ==
+ MAC_STATUS_PCS_SYNCED)) {
+ tp->serdes_counter--;
+ current_link_up = 1;
+ goto out;
+ }
+restart_autoneg:
if (workaround)
tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
- tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) {
- int i;
-
- /* Giver time to negotiate (~200ms) */
- for (i = 0; i < 40000; i++) {
- sg_dig_status = tr32(SG_DIG_STATUS);
- if (sg_dig_status & (0x3))
- break;
- udelay(5);
- }
+ sg_dig_status = tr32(SG_DIG_STATUS);
mac_status = tr32(MAC_STATUS);
if ((sg_dig_status & (1 << 1)) &&
@@ -2498,10 +2508,11 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
tg3_setup_flow_control(tp, local_adv, remote_adv);
current_link_up = 1;
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter = 0;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
} else if (!(sg_dig_status & (1 << 1))) {
- if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED)
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+ if (tp->serdes_counter)
+ tp->serdes_counter--;
else {
if (workaround) {
u32 val = serdes_cfg;
@@ -2525,9 +2536,17 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
!(mac_status & MAC_STATUS_RCVD_CFG)) {
tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1;
- }
+ tp->tg3_flags2 |=
+ TG3_FLG2_PARALLEL_DETECT;
+ tp->serdes_counter =
+ SERDES_PARALLEL_DET_TIMEOUT;
+ } else
+ goto restart_autoneg;
}
}
+ } else {
+ tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
}
out:
@@ -2546,7 +2565,7 @@ static int tg3_setup_fiber_by_hand(struct tg3 *tp, u32 mac_status)
if (tp->link_config.autoneg == AUTONEG_ENABLE) {
u32 flags;
int i;
-
+
if (fiber_autoneg(tp, &flags)) {
u32 local_adv, remote_adv;
@@ -2658,14 +2677,16 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
MAC_STATUS_CFG_CHANGED));
udelay(5);
if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
- MAC_STATUS_CFG_CHANGED)) == 0)
+ MAC_STATUS_CFG_CHANGED |
+ MAC_STATUS_LNKSTATE_CHANGED)) == 0)
break;
}
mac_status = tr32(MAC_STATUS);
if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
current_link_up = 0;
- if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+ tp->serdes_counter == 0) {
tw32_f(MAC_MODE, (tp->mac_mode |
MAC_MODE_SEND_CONFIGS));
udelay(1);
@@ -2770,7 +2791,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
tg3_writephy(tp, MII_BMCR, bmcr);
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
- tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
return err;
@@ -2875,9 +2896,9 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
static void tg3_serdes_parallel_detect(struct tg3 *tp)
{
- if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) {
+ if (tp->serdes_counter) {
/* Give autoneg time to complete. */
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter--;
return;
}
if (!netif_carrier_ok(tp->dev) &&
@@ -2988,6 +3009,13 @@ static void tg3_tx_recover(struct tg3 *tp)
spin_unlock(&tp->lock);
}
+static inline u32 tg3_tx_avail(struct tg3 *tp)
+{
+ smp_mb();
+ return (tp->tx_pending -
+ ((tp->tx_prod - tp->tx_cons) & (TG3_TX_RING_SIZE - 1)));
+}
+
/* Tigon3 never reports partial packet sends. So we do not
* need special logic to handle SKBs that have not had all
* of their frags sent yet, like SunGEM does.
@@ -3039,12 +3067,20 @@ static void tg3_tx(struct tg3 *tp)
tp->tx_cons = sw_idx;
- if (unlikely(netif_queue_stopped(tp->dev))) {
- spin_lock(&tp->tx_lock);
+ /* Need to make the tx_cons update visible to tg3_start_xmit()
+ * before checking for netif_queue_stopped(). Without the
+ * memory barrier, there is a small possibility that tg3_start_xmit()
+ * will miss it and cause the queue to be stopped forever.
+ */
+ smp_mb();
+
+ if (unlikely(netif_queue_stopped(tp->dev) &&
+ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) {
+ netif_tx_lock(tp->dev);
if (netif_queue_stopped(tp->dev) &&
- (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH))
+ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))
netif_wake_queue(tp->dev);
- spin_unlock(&tp->tx_lock);
+ netif_tx_unlock(tp->dev);
}
}
@@ -3098,11 +3134,10 @@ static int tg3_alloc_rx_skb(struct tg3 *tp, u32 opaque_key,
* Callers depend upon this behavior and assume that
* we leave everything unchanged if we fail.
*/
- skb = dev_alloc_skb(skb_size);
+ skb = netdev_alloc_skb(tp->dev, skb_size);
if (skb == NULL)
return -ENOMEM;
- skb->dev = tp->dev;
skb_reserve(skb, tp->rx_offset);
mapping = pci_map_single(tp->pdev, skb->data,
@@ -3195,7 +3230,7 @@ static int tg3_vlan_rx(struct tg3 *tp, struct sk_buff *skb, u16 vlan_tag)
*/
static int tg3_rx(struct tg3 *tp, int budget)
{
- u32 work_mask;
+ u32 work_mask, rx_std_posted = 0;
u32 sw_idx = tp->rx_rcb_ptr;
u16 hw_idx;
int received;
@@ -3222,6 +3257,7 @@ static int tg3_rx(struct tg3 *tp, int budget)
mapping);
skb = tp->rx_std_buffers[desc_idx].skb;
post_ptr = &tp->rx_std_ptr;
+ rx_std_posted++;
} else if (opaque_key == RXD_OPAQUE_RING_JUMBO) {
dma_addr = pci_unmap_addr(&tp->rx_jumbo_buffers[desc_idx],
mapping);
@@ -3247,7 +3283,7 @@ static int tg3_rx(struct tg3 *tp, int budget)
len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */
- if (len > RX_COPY_THRESHOLD
+ if (len > RX_COPY_THRESHOLD
&& tp->rx_offset == 2
/* rx_offset != 2 iff this is a 5701 card running
* in PCI-X mode [see tg3_get_invariants()] */
@@ -3270,11 +3306,10 @@ static int tg3_rx(struct tg3 *tp, int budget)
tg3_recycle_rx(tp, opaque_key,
desc_idx, *post_ptr);
- copy_skb = dev_alloc_skb(len + 2);
+ copy_skb = netdev_alloc_skb(tp->dev, len + 2);
if (copy_skb == NULL)
goto drop_it_no_recycle;
- copy_skb->dev = tp->dev;
skb_reserve(copy_skb, 2);
skb_put(copy_skb, len);
pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE);
@@ -3309,6 +3344,15 @@ static int tg3_rx(struct tg3 *tp, int budget)
next_pkt:
(*post_ptr)++;
+
+ if (unlikely(rx_std_posted >= tp->rx_std_max_post)) {
+ u32 idx = *post_ptr % TG3_RX_RING_SIZE;
+
+ tw32_rx_mbox(MAILBOX_RCV_STD_PROD_IDX +
+ TG3_64BIT_REG_LOW, idx);
+ work_mask &= ~RXD_OPAQUE_RING_STD;
+ rx_std_posted = 0;
+ }
next_pkt_nopost:
sw_idx++;
sw_idx %= TG3_RX_RCB_RING_SIZE(tp);
@@ -3571,8 +3615,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
if ((sblk->status & SD_STATUS_UPDATED) ||
!(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
- 0x00000001);
+ tg3_disable_ints(tp);
return IRQ_RETVAL(1);
}
return IRQ_RETVAL(0);
@@ -3581,6 +3624,28 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
static int tg3_init_hw(struct tg3 *, int);
static int tg3_halt(struct tg3 *, int, int);
+/* Restart hardware after configuration changes, self-test, etc.
+ * Invoked with tp->lock held.
+ */
+static int tg3_restart_hw(struct tg3 *tp, int reset_phy)
+{
+ int err;
+
+ err = tg3_init_hw(tp, reset_phy);
+ if (err) {
+ printk(KERN_ERR PFX "%s: Failed to re-initialize device, "
+ "aborting.\n", tp->dev->name);
+ tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ tg3_full_unlock(tp);
+ del_timer_sync(&tp->timer);
+ tp->irq_sync = 0;
+ netif_poll_enable(tp->dev);
+ dev_close(tp->dev);
+ tg3_full_lock(tp, 0);
+ }
+ return err;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
static void tg3_poll_controller(struct net_device *dev)
{
@@ -3621,13 +3686,15 @@ static void tg3_reset_task(void *_data)
}
tg3_halt(tp, RESET_KIND_SHUTDOWN, 0);
- tg3_init_hw(tp, 1);
+ if (tg3_init_hw(tp, 1))
+ goto out;
tg3_netif_start(tp);
if (restart_timer)
mod_timer(&tp->timer, jiffies + 1);
+out:
tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
tg3_full_unlock(tp);
@@ -3764,7 +3831,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
- if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
@@ -3789,24 +3856,30 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto out_unlock;
}
- tcp_opt_len = ((skb->h.th->doff - 5) * 4);
- ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+ mss |= (skb_headlen(skb) - ETH_HLEN) << 9;
+ else {
+ tcp_opt_len = ((skb->h.th->doff - 5) * 4);
+ ip_tcp_len = (skb->nh.iph->ihl * 4) +
+ sizeof(struct tcphdr);
+
+ skb->nh.iph->check = 0;
+ skb->nh.iph->tot_len = htons(mss + ip_tcp_len +
+ tcp_opt_len);
+ mss |= (ip_tcp_len + tcp_opt_len) << 9;
+ }
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
- skb->nh.iph->check = 0;
- skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
-
skb->h.th->check = 0;
- mss |= (ip_tcp_len + tcp_opt_len) << 9;
}
- else if (skb->ip_summed == CHECKSUM_HW)
+ else if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
#else
mss = 0;
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
#endif
#if TG3_VLAN_TAG_USED
@@ -3854,12 +3927,10 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
tp->tx_prod = entry;
- if (unlikely(TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))) {
- spin_lock(&tp->tx_lock);
+ if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
netif_stop_queue(dev);
- if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
+ if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
netif_wake_queue(tp->dev);
- spin_unlock(&tp->tx_lock);
}
out_unlock:
@@ -3870,6 +3941,40 @@ out_unlock:
return NETDEV_TX_OK;
}
+#if TG3_TSO_SUPPORT != 0
+static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
+
+/* Use GSO to workaround a rare TSO bug that may be triggered when the
+ * TSO header is greater than 80 bytes.
+ */
+static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb)
+{
+ struct sk_buff *segs, *nskb;
+
+ /* Estimate the number of fragments in the worst case */
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->gso_segs * 3))) {
+ netif_stop_queue(tp->dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
+ if (unlikely(IS_ERR(segs)))
+ goto tg3_tso_bug_end;
+
+ do {
+ nskb = segs;
+ segs = segs->next;
+ nskb->next = NULL;
+ tg3_start_xmit_dma_bug(nskb, tp->dev);
+ } while (segs);
+
+tg3_tso_bug_end:
+ dev_kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+#endif
+
/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
* support TG3_FLG2_HW_TSO_1 or firmware TSO only.
*/
@@ -3887,7 +3992,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
* interrupt. Furthermore, IRQ processing runs lockless so we have
* no IRQ context deadlocks to worry about either. Rejoice!
*/
- if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+ if (unlikely(tg3_tx_avail(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev);
@@ -3900,13 +4005,13 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
entry = tp->tx_prod;
base_flags = 0;
- if (skb->ip_summed == CHECKSUM_HW)
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
base_flags |= TXD_FLAG_TCPUDP_CSUM;
#if TG3_TSO_SUPPORT != 0
mss = 0;
if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
(mss = skb_shinfo(skb)->gso_size) != 0) {
- int tcp_opt_len, ip_tcp_len;
+ int tcp_opt_len, ip_tcp_len, hdr_len;
if (skb_header_cloned(skb) &&
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -3917,11 +4022,16 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
tcp_opt_len = ((skb->h.th->doff - 5) * 4);
ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr);
+ hdr_len = ip_tcp_len + tcp_opt_len;
+ if (unlikely((ETH_HLEN + hdr_len) > 80) &&
+ (tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG))
+ return (tg3_tso_bug(tp, skb));
+
base_flags |= (TXD_FLAG_CPU_PRE_DMA |
TXD_FLAG_CPU_POST_DMA);
skb->nh.iph->check = 0;
- skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
+ skb->nh.iph->tot_len = htons(mss + hdr_len);
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
skb->h.th->check = 0;
base_flags &= ~TXD_FLAG_TCPUDP_CSUM;
@@ -4032,12 +4142,10 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry);
tp->tx_prod = entry;
- if (unlikely(TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1))) {
- spin_lock(&tp->tx_lock);
+ if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
netif_stop_queue(dev);
- if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH)
+ if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
netif_wake_queue(tp->dev);
- spin_unlock(&tp->tx_lock);
}
out_unlock:
@@ -4070,6 +4178,7 @@ static inline void tg3_set_mtu(struct net_device *dev, struct tg3 *tp,
static int tg3_change_mtu(struct net_device *dev, int new_mtu)
{
struct tg3 *tp = netdev_priv(dev);
+ int err;
if (new_mtu < TG3_MIN_MTU || new_mtu > TG3_MAX_MTU(tp))
return -EINVAL;
@@ -4090,13 +4199,14 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_set_mtu(dev, tp, new_mtu);
- tg3_init_hw(tp, 0);
+ err = tg3_restart_hw(tp, 0);
- tg3_netif_start(tp);
+ if (!err)
+ tg3_netif_start(tp);
tg3_full_unlock(tp);
- return 0;
+ return err;
}
/* Free up pending packets in all rx/tx rings.
@@ -4178,7 +4288,7 @@ static void tg3_free_rings(struct tg3 *tp)
* end up in the driver. tp->{tx,}lock are held and thus
* we may not sleep.
*/
-static void tg3_init_rings(struct tg3 *tp)
+static int tg3_init_rings(struct tg3 *tp)
{
u32 i;
@@ -4227,18 +4337,38 @@ static void tg3_init_rings(struct tg3 *tp)
/* Now allocate fresh SKBs for each rx ring. */
for (i = 0; i < tp->rx_pending; i++) {
- if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD,
- -1, i) < 0)
+ if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_STD, -1, i) < 0) {
+ printk(KERN_WARNING PFX
+ "%s: Using a smaller RX standard ring, "
+ "only %d out of %d buffers were allocated "
+ "successfully.\n",
+ tp->dev->name, i, tp->rx_pending);
+ if (i == 0)
+ return -ENOMEM;
+ tp->rx_pending = i;
break;
+ }
}
if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) {
for (i = 0; i < tp->rx_jumbo_pending; i++) {
if (tg3_alloc_rx_skb(tp, RXD_OPAQUE_RING_JUMBO,
- -1, i) < 0)
+ -1, i) < 0) {
+ printk(KERN_WARNING PFX
+ "%s: Using a smaller RX jumbo ring, "
+ "only %d out of %d buffers were "
+ "allocated successfully.\n",
+ tp->dev->name, i, tp->rx_jumbo_pending);
+ if (i == 0) {
+ tg3_free_rings(tp);
+ return -ENOMEM;
+ }
+ tp->rx_jumbo_pending = i;
break;
+ }
}
}
+ return 0;
}
/*
@@ -4593,6 +4723,44 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
}
}
+static int tg3_poll_fw(struct tg3 *tp)
+{
+ int i;
+ u32 val;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ for (i = 0; i < 400; i++) {
+ if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
+ return 0;
+ udelay(10);
+ }
+ return -ENODEV;
+ }
+
+ /* Wait for firmware initialization to complete. */
+ for (i = 0; i < 100000; i++) {
+ tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+ if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+ break;
+ udelay(10);
+ }
+
+ /* Chip might not be fitted with firmware. Some Sun onboard
+ * parts are configured like that. So don't signal the timeout
+ * of the above loop as an error, but do report the lack of
+ * running firmware once.
+ */
+ if (i >= 100000 &&
+ !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
+ tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
+
+ printk(KERN_INFO PFX "%s: No firmware running.\n",
+ tp->dev->name);
+ }
+
+ return 0;
+}
+
static void tg3_stop_fw(struct tg3 *);
/* tp->lock is held. */
@@ -4600,7 +4768,7 @@ static int tg3_chip_reset(struct tg3 *tp)
{
u32 val;
void (*write_op)(struct tg3 *, u32, u32);
- int i;
+ int err;
tg3_nvram_lock(tp);
@@ -4637,6 +4805,12 @@ static int tg3_chip_reset(struct tg3 *tp)
}
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
+ tw32(GRC_VCPU_EXT_CTRL,
+ tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
+ }
+
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
tw32(GRC_MISC_CFG, val);
@@ -4760,26 +4934,9 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32_f(MAC_MODE, 0);
udelay(40);
- /* Wait for firmware initialization to complete. */
- for (i = 0; i < 100000; i++) {
- tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
- if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
- break;
- udelay(10);
- }
-
- /* Chip might not be fitted with firmare. Some Sun onboard
- * parts are configured like that. So don't signal the timeout
- * of the above loop as an error, but do report the lack of
- * running firmware once.
- */
- if (i >= 100000 &&
- !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
- tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
-
- printk(KERN_INFO PFX "%s: No firmware running.\n",
- tp->dev->name);
- }
+ err = tg3_poll_fw(tp);
+ if (err)
+ return err;
if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
@@ -4863,7 +5020,7 @@ static int tg3_halt(struct tg3 *tp, int kind, int silent)
#define TG3_FW_BSS_ADDR 0x08000a70
#define TG3_FW_BSS_LEN 0x10
-static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
+static const u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800,
0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000,
0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034,
@@ -4957,7 +5114,7 @@ static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000
};
-static u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
+static const u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430,
0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
@@ -4985,6 +5142,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
BUG_ON(offset == TX_CPU_BASE &&
(tp->tg3_flags2 & TG3_FLG2_5705_PLUS));
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val = tr32(GRC_VCPU_EXT_CTRL);
+
+ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
+ return 0;
+ }
if (offset == RX_CPU_BASE) {
for (i = 0; i < 10000; i++) {
tw32(offset + CPU_STATE, 0xffffffff);
@@ -5022,13 +5185,13 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
struct fw_info {
unsigned int text_base;
unsigned int text_len;
- u32 *text_data;
+ const u32 *text_data;
unsigned int rodata_base;
unsigned int rodata_len;
- u32 *rodata_data;
+ const u32 *rodata_data;
unsigned int data_base;
unsigned int data_len;
- u32 *data_data;
+ const u32 *data_data;
};
/* tp->lock is held. */
@@ -5160,7 +5323,7 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
#define TG3_TSO_FW_BSS_ADDR 0x08001b80
#define TG3_TSO_FW_BSS_LEN 0x894
-static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
+static const u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
0x0e000003, 0x00000000, 0x08001b24, 0x00000000, 0x10000003, 0x00000000,
0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd4000, 0x03a0f021, 0x3c100800,
0x26100000, 0x0e000010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
@@ -5447,7 +5610,7 @@ static u32 tg3TsoFwText[(TG3_TSO_FW_TEXT_LEN / 4) + 1] = {
0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, 0x00000000, 0x00000000,
};
-static u32 tg3TsoFwRodata[] = {
+static const u32 tg3TsoFwRodata[] = {
0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x496e0000, 0x73746b6f,
0x66662a2a, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000,
@@ -5455,7 +5618,7 @@ static u32 tg3TsoFwRodata[] = {
0x00000000,
};
-static u32 tg3TsoFwData[] = {
+static const u32 tg3TsoFwData[] = {
0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x362e3000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000,
@@ -5477,7 +5640,7 @@ static u32 tg3TsoFwData[] = {
#define TG3_TSO5_FW_BSS_ADDR 0x00010f50
#define TG3_TSO5_FW_BSS_LEN 0x88
-static u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
+static const u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
0x0c004003, 0x00000000, 0x00010f04, 0x00000000, 0x10000003, 0x00000000,
0x0000000d, 0x0000000d, 0x3c1d0001, 0x37bde000, 0x03a0f021, 0x3c100001,
0x26100000, 0x0c004010, 0x00000000, 0x0000000d, 0x27bdffe0, 0x3c04fefe,
@@ -5636,14 +5799,14 @@ static u32 tg3Tso5FwText[(TG3_TSO5_FW_TEXT_LEN / 4) + 1] = {
0x00000000, 0x00000000, 0x00000000,
};
-static u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
+static const u32 tg3Tso5FwRodata[(TG3_TSO5_FW_RODATA_LEN / 4) + 1] = {
0x4d61696e, 0x43707542, 0x00000000, 0x4d61696e, 0x43707541, 0x00000000,
0x00000000, 0x00000000, 0x73746b6f, 0x66666c64, 0x00000000, 0x00000000,
0x73746b6f, 0x66666c64, 0x00000000, 0x00000000, 0x66617461, 0x6c457272,
0x00000000, 0x00000000, 0x00000000,
};
-static u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
+static const u32 tg3Tso5FwData[(TG3_TSO5_FW_DATA_LEN / 4) + 1] = {
0x00000000, 0x73746b6f, 0x66666c64, 0x5f76312e, 0x322e3000, 0x00000000,
0x00000000, 0x00000000, 0x00000000,
};
@@ -5761,6 +5924,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
{
struct tg3 *tp = netdev_priv(dev);
struct sockaddr *addr = p;
+ int err = 0;
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
@@ -5778,9 +5942,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp, 0);
-
- tg3_netif_start(tp);
+ err = tg3_restart_hw(tp, 0);
+ if (!err)
+ tg3_netif_start(tp);
tg3_full_unlock(tp);
} else {
spin_lock_bh(&tp->lock);
@@ -5788,7 +5952,7 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
spin_unlock_bh(&tp->lock);
}
- return 0;
+ return err;
}
/* tp->lock is held. */
@@ -5888,7 +6052,9 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
* can only do this after the hardware has been
* successfully reset.
*/
- tg3_init_rings(tp);
+ err = tg3_init_rings(tp);
+ if (err)
+ return err;
/* This value is determined during the probe time DMA
* engine test, tg3_test_dma.
@@ -5981,7 +6147,20 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
}
/* Setup replenish threshold. */
- tw32(RCVBDI_STD_THRESH, tp->rx_pending / 8);
+ val = tp->rx_pending / 8;
+ if (val == 0)
+ val = 1;
+ else if (val > tp->rx_std_max_post)
+ val = tp->rx_std_max_post;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+ tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
+
+ if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2))
+ val = TG3_RX_INTERNAL_RING_SZ_5906 / 2;
+ }
+
+ tw32(RCVBDI_STD_THRESH, val);
/* Initialize TG3_BDINFO's at:
* RCVDBDI_STD_BD: standard eth size rx ring
@@ -6141,8 +6320,12 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
#endif
/* Receive/send statistics. */
- if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) &&
- (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
+ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
+ val = tr32(RCVLPC_STATS_ENABLE);
+ val &= ~RCVLPC_STATSENAB_DACK_FIX;
+ tw32(RCVLPC_STATS_ENABLE, val);
+ } else if ((rdmac_mode & RDMAC_MODE_FIFO_SIZE_128) &&
+ (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE)) {
val = tr32(RCVLPC_STATS_ENABLE);
val &= ~RCVLPC_STATSENAB_LNGBRST_RFIX;
tw32(RCVLPC_STATS_ENABLE, val);
@@ -6396,7 +6579,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+ if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
u32 tmp;
/* Clear CRC stats. */
@@ -6596,12 +6780,14 @@ static void tg3_timer(unsigned long __opaque)
need_setup = 1;
}
if (need_setup) {
- tw32_f(MAC_MODE,
- (tp->mac_mode &
- ~MAC_MODE_PORT_MODE_MASK));
- udelay(40);
- tw32_f(MAC_MODE, tp->mac_mode);
- udelay(40);
+ if (!tp->serdes_counter) {
+ tw32_f(MAC_MODE,
+ (tp->mac_mode &
+ ~MAC_MODE_PORT_MODE_MASK));
+ udelay(40);
+ tw32_f(MAC_MODE, tp->mac_mode);
+ udelay(40);
+ }
tg3_setup_phy(tp, 0);
}
} else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
@@ -6610,13 +6796,29 @@ static void tg3_timer(unsigned long __opaque)
tp->timer_counter = tp->timer_multiplier;
}
- /* Heartbeat is only sent once every 2 seconds. */
+ /* Heartbeat is only sent once every 2 seconds.
+ *
+ * The heartbeat is to tell the ASF firmware that the host
+ * driver is still alive. In the event that the OS crashes,
+ * ASF needs to reset the hardware to free up the FIFO space
+ * that may be filled with rx packets destined for the host.
+ * If the FIFO is full, ASF will no longer function properly.
+ *
+ * Unintended resets have been reported on real time kernels
+ * where the timer doesn't run on time. Netpoll will also have
+ * same problem.
+ *
+ * The new FWCMD_NICDRV_ALIVE3 command tells the ASF firmware
+ * to check the ring condition when the heartbeat is expiring
+ * before doing the reset. This will prevent most unintended
+ * resets.
+ */
if (!--tp->asf_counter) {
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
- FWCMD_NICDRV_ALIVE2);
+ FWCMD_NICDRV_ALIVE3);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */
tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
@@ -6644,12 +6846,12 @@ static int tg3_request_irq(struct tg3 *tp)
fn = tg3_msi;
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI)
fn = tg3_msi_1shot;
- flags = SA_SAMPLE_RANDOM;
+ flags = IRQF_SAMPLE_RANDOM;
} else {
fn = tg3_interrupt;
if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
fn = tg3_interrupt_tagged;
- flags = SA_SHIRQ | SA_SAMPLE_RANDOM;
+ flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
}
return (request_irq(tp->pdev->irq, fn, flags, dev->name, dev));
}
@@ -6657,8 +6859,7 @@ static int tg3_request_irq(struct tg3 *tp)
static int tg3_test_interrupt(struct tg3 *tp)
{
struct net_device *dev = tp->dev;
- int err, i;
- u32 int_mbox = 0;
+ int err, i, intr_ok = 0;
if (!netif_running(dev))
return -ENODEV;
@@ -6668,7 +6869,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
free_irq(tp->pdev->irq, dev);
err = request_irq(tp->pdev->irq, tg3_test_isr,
- SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
+ IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev);
if (err)
return err;
@@ -6679,23 +6880,31 @@ static int tg3_test_interrupt(struct tg3 *tp)
HOSTCC_MODE_NOW);
for (i = 0; i < 5; i++) {
+ u32 int_mbox, misc_host_ctrl;
+
int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 +
TG3_64BIT_REG_LOW);
- if (int_mbox != 0)
+ misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
+
+ if ((int_mbox != 0) ||
+ (misc_host_ctrl & MISC_HOST_CTRL_MASK_PCI_INT)) {
+ intr_ok = 1;
break;
+ }
+
msleep(10);
}
tg3_disable_ints(tp);
free_irq(tp->pdev->irq, dev);
-
+
err = tg3_request_irq(tp);
if (err)
return err;
- if (int_mbox != 0)
+ if (intr_ok)
return 0;
return -EIO;
@@ -6872,9 +7081,10 @@ static int tg3_open(struct net_device *dev)
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) {
- u32 val = tr32(0x7c04);
+ u32 val = tr32(PCIE_TRANSACTION_CFG);
- tw32(0x7c04, val | (1 << 29));
+ tw32(PCIE_TRANSACTION_CFG,
+ val | PCIE_TRANS_CFG_1SHOT_MSI);
}
}
}
@@ -7316,7 +7526,7 @@ static struct net_device_stats *tg3_get_stats(struct net_device *dev)
get_stat64(&hw_stats->rx_ucast_packets) +
get_stat64(&hw_stats->rx_mcast_packets) +
get_stat64(&hw_stats->rx_bcast_packets);
-
+
stats->tx_packets = old_stats->tx_packets +
get_stat64(&hw_stats->tx_ucast_packets) +
get_stat64(&hw_stats->tx_mcast_packets) +
@@ -7624,7 +7834,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
return 0;
}
-static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf);
+static int tg3_nvram_write_block(struct tg3 *tp, u32 offset, u32 len, u8 *buf);
static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
{
@@ -7688,7 +7898,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = netdev_priv(dev);
-
+
cmd->supported = (SUPPORTED_Autoneg);
if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY))
@@ -7706,7 +7916,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->supported |= SUPPORTED_FIBRE;
cmd->port = PORT_FIBRE;
}
-
+
cmd->advertising = tp->link_config.advertising;
if (netif_running(dev)) {
cmd->speed = tp->link_config.active_speed;
@@ -7719,12 +7929,12 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
cmd->maxrxpkt = 0;
return 0;
}
-
+
static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct tg3 *tp = netdev_priv(dev);
-
- if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+
+ if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
/* These are the only valid advertisement bits allowed. */
if (cmd->autoneg == AUTONEG_ENABLE &&
(cmd->advertising & ~(ADVERTISED_1000baseT_Half |
@@ -7756,69 +7966,69 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
tp->link_config.speed = cmd->speed;
tp->link_config.duplex = cmd->duplex;
}
-
+
if (netif_running(dev))
tg3_setup_phy(tp, 1);
tg3_full_unlock(tp);
-
+
return 0;
}
-
+
static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct tg3 *tp = netdev_priv(dev);
-
+
strcpy(info->driver, DRV_MODULE_NAME);
strcpy(info->version, DRV_MODULE_VERSION);
strcpy(info->fw_version, tp->fw_ver);
strcpy(info->bus_info, pci_name(tp->pdev));
}
-
+
static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tg3 *tp = netdev_priv(dev);
-
+
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
wol->wolopts = WAKE_MAGIC;
memset(&wol->sopass, 0, sizeof(wol->sopass));
}
-
+
static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct tg3 *tp = netdev_priv(dev);
-
+
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
if ((wol->wolopts & WAKE_MAGIC) &&
- tp->tg3_flags2 & TG3_FLG2_PHY_SERDES &&
+ tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
!(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
return -EINVAL;
-
+
spin_lock_bh(&tp->lock);
if (wol->wolopts & WAKE_MAGIC)
tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
else
tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
spin_unlock_bh(&tp->lock);
-
+
return 0;
}
-
+
static u32 tg3_get_msglevel(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
return tp->msg_enable;
}
-
+
static void tg3_set_msglevel(struct net_device *dev, u32 value)
{
struct tg3 *tp = netdev_priv(dev);
tp->msg_enable = value;
}
-
+
#if TG3_TSO_SUPPORT != 0
static int tg3_set_tso(struct net_device *dev, u32 value)
{
@@ -7829,16 +8039,23 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
return -EINVAL;
return 0;
}
+ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
+ if (value)
+ dev->features |= NETIF_F_TSO6;
+ else
+ dev->features &= ~NETIF_F_TSO6;
+ }
return ethtool_op_set_tso(dev, value);
}
#endif
-
+
static int tg3_nway_reset(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
u32 bmcr;
int r;
-
+
if (!netif_running(dev))
return -EAGAIN;
@@ -7856,14 +8073,14 @@ static int tg3_nway_reset(struct net_device *dev)
r = 0;
}
spin_unlock_bh(&tp->lock);
-
+
return r;
}
-
+
static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct tg3 *tp = netdev_priv(dev);
-
+
ering->rx_max_pending = TG3_RX_RING_SIZE - 1;
ering->rx_mini_max_pending = 0;
if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE)
@@ -7882,24 +8099,24 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
ering->tx_pending = tp->tx_pending;
}
-
+
static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct tg3 *tp = netdev_priv(dev);
- int irq_sync = 0;
-
+ int irq_sync = 0, err = 0;
+
if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1))
return -EINVAL;
-
+
if (netif_running(dev)) {
tg3_netif_stop(tp);
irq_sync = 1;
}
tg3_full_lock(tp, irq_sync);
-
+
tp->rx_pending = ering->rx_pending;
if ((tp->tg3_flags2 & TG3_FLG2_MAX_RXPEND_64) &&
@@ -7910,29 +8127,30 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp, 1);
- tg3_netif_start(tp);
+ err = tg3_restart_hw(tp, 1);
+ if (!err)
+ tg3_netif_start(tp);
}
tg3_full_unlock(tp);
-
- return 0;
+
+ return err;
}
-
+
static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = netdev_priv(dev);
-
+
epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0;
epause->rx_pause = (tp->tg3_flags & TG3_FLAG_RX_PAUSE) != 0;
epause->tx_pause = (tp->tg3_flags & TG3_FLAG_TX_PAUSE) != 0;
}
-
+
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = netdev_priv(dev);
- int irq_sync = 0;
-
+ int irq_sync = 0, err = 0;
+
if (netif_running(dev)) {
tg3_netif_stop(tp);
irq_sync = 1;
@@ -7955,51 +8173,52 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
if (netif_running(dev)) {
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- tg3_init_hw(tp, 1);
- tg3_netif_start(tp);
+ err = tg3_restart_hw(tp, 1);
+ if (!err)
+ tg3_netif_start(tp);
}
tg3_full_unlock(tp);
-
- return 0;
+
+ return err;
}
-
+
static u32 tg3_get_rx_csum(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
return (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0;
}
-
+
static int tg3_set_rx_csum(struct net_device *dev, u32 data)
{
struct tg3 *tp = netdev_priv(dev);
-
+
if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
if (data != 0)
return -EINVAL;
return 0;
}
-
+
spin_lock_bh(&tp->lock);
if (data)
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
spin_unlock_bh(&tp->lock);
-
+
return 0;
}
-
+
static int tg3_set_tx_csum(struct net_device *dev, u32 data)
{
struct tg3 *tp = netdev_priv(dev);
-
+
if (tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) {
if (data != 0)
return -EINVAL;
return 0;
}
-
+
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
ethtool_op_set_tx_hw_csum(dev, data);
@@ -8054,7 +8273,7 @@ static int tg3_phys_id(struct net_device *dev, u32 data)
LED_CTRL_TRAFFIC_OVERRIDE |
LED_CTRL_TRAFFIC_BLINK |
LED_CTRL_TRAFFIC_LED);
-
+
else
tw32(MAC_LED_CTRL, LED_CTRL_LNKLED_OVERRIDE |
LED_CTRL_TRAFFIC_OVERRIDE);
@@ -8075,6 +8294,8 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
#define NVRAM_TEST_SIZE 0x100
#define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
+#define NVRAM_SELFBOOT_HW_SIZE 0x20
+#define NVRAM_SELFBOOT_DATA_SIZE 0x1c
static int tg3_test_nvram(struct tg3 *tp)
{
@@ -8086,12 +8307,14 @@ static int tg3_test_nvram(struct tg3 *tp)
if (magic == TG3_EEPROM_MAGIC)
size = NVRAM_TEST_SIZE;
- else if ((magic & 0xff000000) == 0xa5000000) {
+ else if ((magic & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) {
if ((magic & 0xe00000) == 0x200000)
size = NVRAM_SELFBOOT_FORMAT1_SIZE;
else
return 0;
- } else
+ } else if ((magic & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
+ size = NVRAM_SELFBOOT_HW_SIZE;
+ else
return -EIO;
buf = kmalloc(size, GFP_KERNEL);
@@ -8110,7 +8333,8 @@ static int tg3_test_nvram(struct tg3 *tp)
goto out;
/* Selfboot format */
- if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) {
+ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_FW_MSK) ==
+ TG3_EEPROM_MAGIC_FW) {
u8 *buf8 = (u8 *) buf, csum8 = 0;
for (i = 0; i < size; i++)
@@ -8125,6 +8349,51 @@ static int tg3_test_nvram(struct tg3 *tp)
goto out;
}
+ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_HW_MSK) ==
+ TG3_EEPROM_MAGIC_HW) {
+ u8 data[NVRAM_SELFBOOT_DATA_SIZE];
+ u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
+ u8 *buf8 = (u8 *) buf;
+ int j, k;
+
+ /* Separate the parity bits and the data bytes. */
+ for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
+ if ((i == 0) || (i == 8)) {
+ int l;
+ u8 msk;
+
+ for (l = 0, msk = 0x80; l < 7; l++, msk >>= 1)
+ parity[k++] = buf8[i] & msk;
+ i++;
+ }
+ else if (i == 16) {
+ int l;
+ u8 msk;
+
+ for (l = 0, msk = 0x20; l < 6; l++, msk >>= 1)
+ parity[k++] = buf8[i] & msk;
+ i++;
+
+ for (l = 0, msk = 0x80; l < 8; l++, msk >>= 1)
+ parity[k++] = buf8[i] & msk;
+ i++;
+ }
+ data[j++] = buf8[i];
+ }
+
+ err = -EIO;
+ for (i = 0; i < NVRAM_SELFBOOT_DATA_SIZE; i++) {
+ u8 hw8 = hweight8(data[i]);
+
+ if ((hw8 & 0x1) && parity[i])
+ goto out;
+ else if (!(hw8 & 0x1) && !parity[i])
+ goto out;
+ }
+ err = 0;
+ goto out;
+ }
+
/* Bootstrap checksum at offset 0x10 */
csum = calc_crc((unsigned char *) buf, 0x10);
if(csum != cpu_to_le32(buf[0x10/4]))
@@ -8171,7 +8440,7 @@ static int tg3_test_link(struct tg3 *tp)
/* Only test the commonly used registers */
static int tg3_test_registers(struct tg3 *tp)
{
- int i, is_5705;
+ int i, is_5705, is_5750;
u32 offset, read_mask, write_mask, val, save_val, read_val;
static struct {
u16 offset;
@@ -8179,6 +8448,7 @@ static int tg3_test_registers(struct tg3 *tp)
#define TG3_FL_5705 0x1
#define TG3_FL_NOT_5705 0x2
#define TG3_FL_NOT_5788 0x4
+#define TG3_FL_NOT_5750 0x8
u32 read_mask;
u32 write_mask;
} reg_tbl[] = {
@@ -8231,7 +8501,7 @@ static int tg3_test_registers(struct tg3 *tp)
0x00000000, 0xffff0002 },
{ RCVDBDI_STD_BD+0xc, 0x0000,
0x00000000, 0xffffffff },
-
+
/* Receive BD Initiator Control Registers. */
{ RCVBDI_STD_THRESH, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
@@ -8239,7 +8509,7 @@ static int tg3_test_registers(struct tg3 *tp)
0x00000000, 0x000003ff },
{ RCVBDI_JUMBO_THRESH, TG3_FL_NOT_5705,
0x00000000, 0xffffffff },
-
+
/* Host Coalescing Control Registers. */
{ HOSTCC_MODE, TG3_FL_NOT_5705,
0x00000000, 0x00000004 },
@@ -8289,9 +8559,9 @@ static int tg3_test_registers(struct tg3 *tp)
0xffffffff, 0x00000000 },
/* Buffer Manager Control Registers. */
- { BUFMGR_MB_POOL_ADDR, 0x0000,
+ { BUFMGR_MB_POOL_ADDR, TG3_FL_NOT_5750,
0x00000000, 0x007fff80 },
- { BUFMGR_MB_POOL_SIZE, 0x0000,
+ { BUFMGR_MB_POOL_SIZE, TG3_FL_NOT_5750,
0x00000000, 0x007fffff },
{ BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
0x00000000, 0x0000003f },
@@ -8303,7 +8573,7 @@ static int tg3_test_registers(struct tg3 *tp)
0xffffffff, 0x00000000 },
{ BUFMGR_DMA_DESC_POOL_SIZE, TG3_FL_NOT_5705,
0xffffffff, 0x00000000 },
-
+
/* Mailbox Registers */
{ GRCMBOX_RCVSTD_PROD_IDX+4, 0x0000,
0x00000000, 0x000001ff },
@@ -8317,10 +8587,12 @@ static int tg3_test_registers(struct tg3 *tp)
{ 0xffff, 0x0000, 0x00000000, 0x00000000 },
};
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ is_5705 = is_5750 = 0;
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
is_5705 = 1;
- else
- is_5705 = 0;
+ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
+ is_5750 = 1;
+ }
for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
@@ -8333,6 +8605,9 @@ static int tg3_test_registers(struct tg3 *tp)
(reg_tbl[i].flags & TG3_FL_NOT_5788))
continue;
+ if (is_5750 && (reg_tbl[i].flags & TG3_FL_NOT_5750))
+ continue;
+
offset = (u32) reg_tbl[i].offset;
read_mask = reg_tbl[i].read_mask;
write_mask = reg_tbl[i].write_mask;
@@ -8424,6 +8699,13 @@ static int tg3_test_memory(struct tg3 *tp)
{ 0x00008000, 0x02000},
{ 0x00010000, 0x0c000},
{ 0xffffffff, 0x00000}
+ }, mem_tbl_5906[] = {
+ { 0x00000200, 0x00008},
+ { 0x00004000, 0x00400},
+ { 0x00006000, 0x00400},
+ { 0x00008000, 0x01000},
+ { 0x00010000, 0x01000},
+ { 0xffffffff, 0x00000}
};
struct mem_entry *mem_tbl;
int err = 0;
@@ -8433,6 +8715,8 @@ static int tg3_test_memory(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
mem_tbl = mem_tbl_5755;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ mem_tbl = mem_tbl_5906;
else
mem_tbl = mem_tbl_5705;
} else
@@ -8443,7 +8727,7 @@ static int tg3_test_memory(struct tg3 *tp)
mem_tbl[i].len)) != 0)
break;
}
-
+
return err;
}
@@ -8469,13 +8753,41 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
return 0;
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
- MAC_MODE_PORT_MODE_GMII;
+ MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY;
+ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ mac_mode |= MAC_MODE_PORT_MODE_MII;
+ else
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32(MAC_MODE, mac_mode);
} else if (loopback_mode == TG3_PHY_LOOPBACK) {
- tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
- BMCR_SPEED1000);
+ u32 val;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 phytest;
+
+ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phytest)) {
+ u32 phy;
+
+ tg3_writephy(tp, MII_TG3_EPHY_TEST,
+ phytest | MII_TG3_EPHY_SHADOW_EN);
+ if (!tg3_readphy(tp, 0x1b, &phy))
+ tg3_writephy(tp, 0x1b, phy & ~0x20);
+ if (!tg3_readphy(tp, 0x10, &phy))
+ tg3_writephy(tp, 0x10, phy & ~0x4000);
+ tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest);
+ }
+ }
+ val = BMCR_LOOPBACK | BMCR_FULLDPLX;
+ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ val |= BMCR_SPEED100;
+ else
+ val |= BMCR_SPEED1000;
+
+ tg3_writephy(tp, MII_BMCR, val);
udelay(40);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800);
+
/* reset to prevent losing 1st rx packet intermittently */
if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
@@ -8483,7 +8795,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
+ MAC_MODE_LINK_POLARITY;
+ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ mac_mode |= MAC_MODE_PORT_MODE_MII;
+ else
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
mac_mode &= ~MAC_MODE_LINK_POLARITY;
tg3_writephy(tp, MII_TG3_EXT_CTRL,
@@ -8497,7 +8813,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
err = -EIO;
tx_len = 1514;
- skb = dev_alloc_skb(tx_len);
+ skb = netdev_alloc_skb(tp->dev, tx_len);
if (!skb)
return -ENOMEM;
@@ -8532,7 +8848,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
udelay(10);
- for (i = 0; i < 10; i++) {
+ /* 250 usec to allow enough time on some 10/100 Mbps devices. */
+ for (i = 0; i < 25; i++) {
tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
HOSTCC_MODE_NOW);
@@ -8578,7 +8895,7 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
goto out;
}
err = 0;
-
+
/* tg3_free_rings will unmap and free the rx_skb */
out:
return err;
@@ -8596,7 +8913,9 @@ static int tg3_test_loopback(struct tg3 *tp)
if (!netif_running(tp->dev))
return TG3_LOOPBACK_FAILED;
- tg3_reset_hw(tp, 1);
+ err = tg3_reset_hw(tp, 1);
+ if (err)
+ return TG3_LOOPBACK_FAILED;
if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK))
err |= TG3_MAC_LOOPBACK_FAILED;
@@ -8670,8 +8989,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp, 1);
- tg3_netif_start(tp);
+ if (!tg3_restart_hw(tp, 1))
+ tg3_netif_start(tp);
}
tg3_full_unlock(tp);
@@ -8738,6 +9057,9 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct tg3 *tp = netdev_priv(dev);
+ if (netif_running(dev))
+ tg3_netif_stop(tp);
+
tg3_full_lock(tp, 0);
tp->vlgrp = grp;
@@ -8746,16 +9068,25 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
__tg3_set_rx_mode(dev);
tg3_full_unlock(tp);
+
+ if (netif_running(dev))
+ tg3_netif_start(tp);
}
static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct tg3 *tp = netdev_priv(dev);
+ if (netif_running(dev))
+ tg3_netif_stop(tp);
+
tg3_full_lock(tp, 0);
if (tp->vlgrp)
tp->vlgrp->vlan_devices[vid] = NULL;
tg3_full_unlock(tp);
+
+ if (netif_running(dev))
+ tg3_netif_start(tp);
}
#endif
@@ -8821,7 +9152,7 @@ static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
return 0;
}
-static struct ethtool_ops tg3_ethtool_ops = {
+static const struct ethtool_ops tg3_ethtool_ops = {
.get_settings = tg3_get_settings,
.set_settings = tg3_set_settings,
.get_drvinfo = tg3_get_drvinfo,
@@ -8870,7 +9201,9 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
return;
- if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000))
+ if ((magic != TG3_EEPROM_MAGIC) &&
+ ((magic & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW) &&
+ ((magic & TG3_EEPROM_MAGIC_HW_MSK) != TG3_EEPROM_MAGIC_HW))
return;
/*
@@ -8892,7 +9225,7 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
tp->nvram_size = cursize;
}
-
+
static void __devinit tg3_get_nvram_size(struct tg3 *tp)
{
u32 val;
@@ -9108,6 +9441,13 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
}
}
+static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
+{
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+}
+
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void __devinit tg3_nvram_init(struct tg3 *tp)
{
@@ -9144,6 +9484,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
tg3_get_5755_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tg3_get_5787_nvram_info(tp);
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tg3_get_5906_nvram_info(tp);
else
tg3_get_nvram_info(tp);
@@ -9308,7 +9650,7 @@ static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
(addr & EEPROM_ADDR_ADDR_MASK) |
EEPROM_ADDR_START |
EEPROM_ADDR_WRITE);
-
+
for (j = 0; j < 10000; j++) {
val = tr32(GRC_EEPROM_ADDR);
@@ -9344,7 +9686,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
u32 phy_addr, page_off, size;
phy_addr = offset & ~pagemask;
-
+
for (j = 0; j < pagesize; j += 4) {
if ((ret = tg3_nvram_read(tp, phy_addr + j,
(u32 *) (tmp + j))))
@@ -9617,6 +9959,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
/* Assume an onboard device by default. */
tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM))
+ tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
+ return;
+ }
+
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
u32 nic_cfg, led_cfg;
@@ -9800,7 +10148,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
if (!tg3_readphy(tp, MII_BMSR, &bmsr) &&
(bmsr & BMSR_LSTATUS))
goto skip_phy_reset;
-
+
err = tg3_phy_reset(tp);
if (err)
return err;
@@ -9948,7 +10296,10 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
}
out_not_found:
- strcpy(tp->board_part_number, "none");
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ strcpy(tp->board_part_number, "BCM95906");
+ else
+ strcpy(tp->board_part_number, "none");
}
static void __devinit tg3_read_fw_ver(struct tg3 *tp)
@@ -9996,6 +10347,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
static struct pci_device_id write_reorder_chipsets[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_700C) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_8131_BRIDGE) },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA,
PCI_DEVICE_ID_VIA_8385_0) },
{ },
@@ -10148,6 +10501,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -10157,18 +10511,26 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
- } else
- tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1;
+ } else {
+ tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1 |
+ TG3_FLG2_HW_TSO_1_BUG;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) ==
+ ASIC_REV_5750 &&
+ tp->pci_chip_rev_id >= CHIPREV_ID_5750_C2)
+ tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_1_BUG;
+ }
}
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
@@ -10298,6 +10660,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_cmd &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tp->read32_mbox = tg3_read32_mbox_5906;
+ tp->write32_mbox = tg3_write32_mbox_5906;
+ tp->write32_tx_mbox = tg3_write32_mbox_5906;
+ tp->write32_rx_mbox = tg3_write32_mbox_5906;
+ }
if (tp->write32 == tg3_write_indirect_reg32 ||
((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
@@ -10312,7 +10680,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* When the flag is set, it means that GPIO1 is used for eeprom
* write protect and also implies that it is a LOM where GPIOs
* are not used to switch power.
- */
+ */
tg3_get_eeprom_hw_cfg(tp);
/* Set up tp->grc_local_ctrl before calling tg3_set_power_state().
@@ -10369,6 +10737,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
(tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
(tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) ||
(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
@@ -10382,7 +10751,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
- else
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
}
@@ -10472,7 +10841,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
(tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
(tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
- tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)))
+ tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
err = tg3_phy_probe(tp);
@@ -10523,7 +10893,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* straddle the 4GB address boundary in some cases.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->dev->hard_start_xmit = tg3_start_xmit;
else
tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
@@ -10533,6 +10904,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
(tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0)
tp->rx_offset = 0;
+ tp->rx_std_max_post = TG3_RX_RING_SIZE;
+
+ /* Increment the rx prod index on the rx std ring by at most
+ * 8 for these chips to workaround hw errata.
+ */
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755)
+ tp->rx_std_max_post = 8;
+
/* By default, disable wake-on-lan. User can change this
* using ETHTOOL_SWOL.
*/
@@ -10549,11 +10930,13 @@ static int __devinit tg3_get_macaddr_sparc(struct tg3 *tp)
struct pcidev_cookie *pcp = pdev->sysdata;
if (pcp != NULL) {
- int node = pcp->prom_node;
+ unsigned char *addr;
+ int len;
- if (prom_getproplen(node, "local-mac-address") == 6) {
- prom_getproperty(node, "local-mac-address",
- dev->dev_addr, 6);
+ addr = of_get_property(pcp->prom_node, "local-mac-address",
+ &len);
+ if (addr && len == 6) {
+ memcpy(dev->dev_addr, addr, 6);
memcpy(dev->perm_addr, dev->dev_addr, 6);
return 0;
}
@@ -10592,6 +10975,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
else
tg3_nvram_unlock(tp);
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ mac_offset = 0x10;
/* First try to get it from MAC address mailbox. */
tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
@@ -11075,6 +11460,12 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
DEFAULT_MB_MACRX_LOW_WATER_5705;
tp->bufmgr_config.mbuf_high_water =
DEFAULT_MB_HIGH_WATER_5705;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tp->bufmgr_config.mbuf_mac_rx_low_water =
+ DEFAULT_MB_MACRX_LOW_WATER_5906;
+ tp->bufmgr_config.mbuf_high_water =
+ DEFAULT_MB_HIGH_WATER_5906;
+ }
tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
@@ -11118,6 +11509,8 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case PHY_ID_BCM5780: return "5780";
case PHY_ID_BCM5755: return "5755";
case PHY_ID_BCM5787: return "5787";
+ case PHY_ID_BCM5756: return "5722/5756";
+ case PHY_ID_BCM5906: return "5906";
case PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -11319,7 +11712,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
tp->grc_mode |= GRC_MODE_BSWAP_NONFRM_DATA;
#endif
spin_lock_init(&tp->lock);
- spin_lock_init(&tp->tx_lock);
spin_lock_init(&tp->indirect_lock);
INIT_WORK(&tp->reset_task, tg3_reset_task, tp);
@@ -11419,8 +11811,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
* Firmware TSO on older chips gives lower performance, so it
* is off by default, but can be enabled using ethtool.
*/
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
+ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
dev->features |= NETIF_F_TSO;
+ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
+ dev->features |= NETIF_F_TSO6;
+ }
#endif
@@ -11594,7 +11990,8 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp, 1);
+ if (tg3_restart_hw(tp, 1))
+ goto out;
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
@@ -11602,6 +11999,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_attach(dev);
tg3_netif_start(tp);
+out:
tg3_full_unlock(tp);
}
@@ -11628,16 +12026,19 @@ static int tg3_resume(struct pci_dev *pdev)
tg3_full_lock(tp, 0);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
- tg3_init_hw(tp, 1);
+ err = tg3_restart_hw(tp, 1);
+ if (err)
+ goto out;
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
tg3_netif_start(tp);
+out:
tg3_full_unlock(tp);
- return 0;
+ return err;
}
static struct pci_driver tg3_driver = {
@@ -11651,7 +12052,7 @@ static struct pci_driver tg3_driver = {
static int __init tg3_init(void)
{
- return pci_module_init(&tg3_driver);
+ return pci_register_driver(&tg3_driver);
}
static void __exit tg3_cleanup(void)
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 8209da5dd15..92f53000bce 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -24,6 +24,8 @@
#define RX_COPY_THRESHOLD 256
+#define TG3_RX_INTERNAL_RING_SZ_5906 32
+
#define RX_STD_MAX_SIZE 1536
#define RX_STD_MAX_SIZE_5705 512
#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */
@@ -125,9 +127,11 @@
#define CHIPREV_ID_5750_A0 0x4000
#define CHIPREV_ID_5750_A1 0x4001
#define CHIPREV_ID_5750_A3 0x4003
+#define CHIPREV_ID_5750_C2 0x4202
#define CHIPREV_ID_5752_A0_HW 0x5000
#define CHIPREV_ID_5752_A0 0x6000
#define CHIPREV_ID_5752_A1 0x6001
+#define CHIPREV_ID_5906_A1 0xc001
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
@@ -140,6 +144,7 @@
#define ASIC_REV_5714 0x09
#define ASIC_REV_5755 0x0a
#define ASIC_REV_5787 0x0b
+#define ASIC_REV_5906 0x0c
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -645,7 +650,8 @@
#define SNDDATAI_SCTRL_FORCE_ZERO 0x00000010
#define SNDDATAI_STATSENAB 0x00000c0c
#define SNDDATAI_STATSINCMASK 0x00000c10
-/* 0xc14 --> 0xc80 unused */
+#define ISO_PKT_TX 0x00000c20
+/* 0xc24 --> 0xc80 unused */
#define SNDDATAI_COS_CNT_0 0x00000c80
#define SNDDATAI_COS_CNT_1 0x00000c84
#define SNDDATAI_COS_CNT_2 0x00000c88
@@ -760,6 +766,7 @@
#define RCVLPC_STATSCTRL_ENABLE 0x00000001
#define RCVLPC_STATSCTRL_FASTUPD 0x00000002
#define RCVLPC_STATS_ENABLE 0x00002018
+#define RCVLPC_STATSENAB_DACK_FIX 0x00040000
#define RCVLPC_STATSENAB_LNGBRST_RFIX 0x00400000
#define RCVLPC_STATS_INCMASK 0x0000201c
/* 0x2020 --> 0x2100 unused */
@@ -995,11 +1002,13 @@
#define BUFMGR_MB_MACRX_LOW_WATER 0x00004414
#define DEFAULT_MB_MACRX_LOW_WATER 0x00000020
#define DEFAULT_MB_MACRX_LOW_WATER_5705 0x00000010
+#define DEFAULT_MB_MACRX_LOW_WATER_5906 0x00000004
#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b
#define BUFMGR_MB_HIGH_WATER 0x00004418
#define DEFAULT_MB_HIGH_WATER 0x00000060
#define DEFAULT_MB_HIGH_WATER_5705 0x00000060
+#define DEFAULT_MB_HIGH_WATER_5906 0x00000010
#define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c
#define DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096
#define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c
@@ -1136,7 +1145,12 @@
#define TX_CPU_STATE 0x00005404
#define TX_CPU_PGMCTR 0x0000541c
+#define VCPU_STATUS 0x00005100
+#define VCPU_STATUS_INIT_DONE 0x04000000
+#define VCPU_STATUS_DRV_RESET 0x08000000
+
/* Mailboxes */
+#define GRCMBOX_BASE 0x00005600
#define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */
#define GRCMBOX_INTERRUPT_1 0x00005808 /* 64-bit */
#define GRCMBOX_INTERRUPT_2 0x00005810 /* 64-bit */
@@ -1396,7 +1410,10 @@
#define GRC_EEPROM_CTRL 0x00006840
#define GRC_MDI_CTRL 0x00006844
#define GRC_SEEPROM_DELAY 0x00006848
-/* 0x684c --> 0x6c00 unused */
+/* 0x684c --> 0x6890 unused */
+#define GRC_VCPU_EXT_CTRL 0x00006890
+#define GRC_VCPU_EXT_CTRL_HALT_CPU 0x00400000
+#define GRC_VCPU_EXT_CTRL_DISABLE_WOL 0x20000000
#define GRC_FASTBOOT_PC 0x00006894 /* 5752, 5755, 5787 */
/* 0x6c00 --> 0x7000 unused */
@@ -1483,9 +1500,17 @@
#define NVRAM_WRITE1 0x00007028
/* 0x702c --> 0x7400 unused */
-/* 0x7400 --> 0x8000 unused */
+/* 0x7400 --> 0x7c00 unused */
+#define PCIE_TRANSACTION_CFG 0x00007c04
+#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000
+#define PCIE_TRANS_CFG_LOM 0x00000020
+
#define TG3_EEPROM_MAGIC 0x669955aa
+#define TG3_EEPROM_MAGIC_FW 0xa5000000
+#define TG3_EEPROM_MAGIC_FW_MSK 0xff000000
+#define TG3_EEPROM_MAGIC_HW 0xabcd
+#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
/* 32K Window into NIC internal memory */
#define NIC_SRAM_WIN_BASE 0x00008000
@@ -1535,6 +1560,7 @@
#define FWCMD_NICDRV_FIX_DMAR 0x00000005
#define FWCMD_NICDRV_FIX_DMAW 0x00000006
#define FWCMD_NICDRV_ALIVE2 0x0000000d
+#define FWCMD_NICDRV_ALIVE3 0x0000000e
#define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c
#define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80
#define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00
@@ -1602,6 +1628,7 @@
#define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */
#define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */
+#define MII_TG3_EPHY_PTEST 0x17 /* 5906 PHY register */
#define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */
@@ -1615,6 +1642,8 @@
#define MII_TG3_AUX_STAT_100FULL 0x0500
#define MII_TG3_AUX_STAT_1000HALF 0x0600
#define MII_TG3_AUX_STAT_1000FULL 0x0700
+#define MII_TG3_AUX_STAT_100 0x0008
+#define MII_TG3_AUX_STAT_FULL 0x0001
#define MII_TG3_ISTAT 0x1a /* IRQ status register */
#define MII_TG3_IMASK 0x1b /* IRQ mask register */
@@ -1625,6 +1654,9 @@
#define MII_TG3_INT_DUPLEXCHG 0x0008
#define MII_TG3_INT_ANEG_PAGE_RX 0x0400
+#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */
+#define MII_TG3_EPHY_SHADOW_EN 0x80
+
/* There are two ways to manage the TX descriptors on the tigon3.
* Either the descriptors are in host DMA'able memory, or they
* exist only in the cards on-chip SRAM. All 16 send bds are under
@@ -2077,9 +2109,9 @@ struct tg3 {
* lock: Held during reset, PHY access, timer, and when
* updating tg3_flags and tg3_flags2.
*
- * tx_lock: Held during tg3_start_xmit and tg3_tx only
- * when calling netif_[start|stop]_queue.
- * tg3_start_xmit is protected by netif_tx_lock.
+ * netif_tx_lock: Held during tg3_start_xmit. tg3_tx holds
+ * netif_tx_lock when it needs to call
+ * netif_wake_queue.
*
* Both of these locks are to be held with BH safety.
*
@@ -2116,8 +2148,6 @@ struct tg3 {
u32 tx_cons;
u32 tx_pending;
- spinlock_t tx_lock;
-
struct tg3_tx_buffer_desc *tx_ring;
struct tx_ring_info *tx_buffers;
dma_addr_t tx_desc_mapping;
@@ -2137,6 +2167,7 @@ struct tg3 {
struct tg3_rx_buffer_desc *rx_std;
struct ring_info *rx_std_buffers;
dma_addr_t rx_std_mapping;
+ u32 rx_std_max_post;
struct tg3_rx_buffer_desc *rx_jumbo;
struct ring_info *rx_jumbo_buffers;
@@ -2191,7 +2222,7 @@ struct tg3 {
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001
-/* 0x00000002 available */
+#define TG3_FLG2_HW_TSO_1_BUG 0x00000002
#define TG3_FLG2_NO_ETH_WIRE_SPEED 0x00000004
#define TG3_FLG2_IS_5788 0x00000008
#define TG3_FLG2_MAX_RXPEND_64 0x00000010
@@ -2202,7 +2233,6 @@ struct tg3 {
#define TG3_FLG2_PCI_EXPRESS 0x00000200
#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400
#define TG3_FLG2_HW_AUTONEG 0x00000800
-#define TG3_FLG2_PHY_JUST_INITTED 0x00001000
#define TG3_FLG2_PHY_SERDES 0x00002000
#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000
#define TG3_FLG2_FLASH 0x00008000
@@ -2235,6 +2265,12 @@ struct tg3 {
u16 asf_counter;
u16 asf_multiplier;
+ /* 1 second counter for transient serdes link events */
+ u32 serdes_counter;
+#define SERDES_AN_TIMEOUT_5704S 2
+#define SERDES_PARALLEL_DET_TIMEOUT 1
+#define SERDES_AN_TIMEOUT_5714S 1
+
struct tg3_link_config link_config;
struct tg3_bufmgr_config bufmgr_config;
@@ -2275,6 +2311,8 @@ struct tg3 {
#define PHY_ID_BCM5780 0x60008350
#define PHY_ID_BCM5755 0xbc050cc0
#define PHY_ID_BCM5787 0xbc050ce0
+#define PHY_ID_BCM5756 0xbc050ed0
+#define PHY_ID_BCM5906 0xdc00ac40
#define PHY_ID_BCM8002 0x60010140
#define PHY_ID_INVALID 0xffffffff
#define PHY_ID_REV_MASK 0x0000000f
@@ -2301,7 +2339,8 @@ struct tg3 {
(X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
(X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
- (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM8002)
+ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
+ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
struct tg3_hw_stats *hw_stats;
dma_addr_t stats_mapping;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 12076f8f942..8d807bf603a 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -33,33 +33,33 @@
* new PCI BIOS interface.
* Alan Cox <alan@redhat.com>: Fixed the out of memory
* handling.
- *
+ *
* Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
*
* v1.1 Dec 20, 1999 - Removed linux version checking
- * Patch from Tigran Aivazian.
+ * Patch from Tigran Aivazian.
* - v1.1 includes Alan's SMP updates.
* - We still have problems on SMP though,
- * but I'm looking into that.
- *
+ * but I'm looking into that.
+ *
* v1.2 Jan 02, 2000 - Hopefully fixed the SMP deadlock.
* - Removed dependency of HZ being 100.
- * - We now allow higher priority timers to
+ * - We now allow higher priority timers to
* overwrite timers like TLAN_TIMER_ACTIVITY
* Patch from John Cagle <john.cagle@compaq.com>.
* - Fixed a few compiler warnings.
*
* v1.3 Feb 04, 2000 - Fixed the remaining HZ issues.
- * - Removed call to pci_present().
+ * - Removed call to pci_present().
* - Removed SA_INTERRUPT flag from irq handler.
- * - Added __init and __initdata to reduce resisdent
+ * - Added __init and __initdata to reduce resisdent
* code size.
* - Driver now uses module_init/module_exit.
* - Rewrote init_module and tlan_probe to
* share a lot more code. We now use tlan_probe
* with builtin and module driver.
- * - Driver ported to new net API.
- * - tlan.txt has been reworked to reflect current
+ * - Driver ported to new net API.
+ * - tlan.txt has been reworked to reflect current
* driver (almost)
* - Other minor stuff
*
@@ -74,11 +74,11 @@
* Auto-Neg fallback.
*
* v1.6 April 04, 2000 - Fixed driver support for kernel-parameters. Haven't
- * tested it though, as the kernel support is currently
+ * tested it though, as the kernel support is currently
* broken (2.3.99p4p3).
* - Updated tlan.txt accordingly.
* - Adjusted minimum/maximum frame length.
- * - There is now a TLAN website up at
+ * - There is now a TLAN website up at
* http://tlan.kernel.dk
*
* v1.7 April 07, 2000 - Started to implement custom ioctls. Driver now
@@ -92,10 +92,10 @@
* link partner abilities. When forced link is used,
* the driver will report status of the established
* link.
- * Please read tlan.txt for additional information.
- * - Removed call to check_region(), and used
+ * Please read tlan.txt for additional information.
+ * - Removed call to check_region(), and used
* return value of request_region() instead.
- *
+ *
* v1.8a May 28, 2000 - Minor updates.
*
* v1.9 July 25, 2000 - Fixed a few remaining Full-Duplex issues.
@@ -104,25 +104,25 @@
* - Added routine to monitor PHY status.
* - Added activity led support for Proliant devices.
*
- * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers
- * like the Compaq NetFlex3/E.
+ * v1.10 Aug 30, 2000 - Added support for EISA based tlan controllers
+ * like the Compaq NetFlex3/E.
* - Rewrote tlan_probe to better handle multiple
* bus probes. Probing and device setup is now
* done through TLan_Probe and TLan_init_one. Actual
- * hardware probe is done with kernel API and
+ * hardware probe is done with kernel API and
* TLan_EisaProbe.
* - Adjusted debug information for probing.
- * - Fixed bug that would cause general debug information
- * to be printed after driver removal.
+ * - Fixed bug that would cause general debug information
+ * to be printed after driver removal.
* - Added transmit timeout handling.
- * - Fixed OOM return values in tlan_probe.
- * - Fixed possible mem leak in tlan_exit
+ * - Fixed OOM return values in tlan_probe.
+ * - Fixed possible mem leak in tlan_exit
* (now tlan_remove_one).
* - Fixed timer bug in TLan_phyMonitor.
* - This driver version is alpha quality, please
* send me any bug issues you may encounter.
*
- * v1.11 Aug 31, 2000 - Do not try to register irq 0 if no irq line was
+ * v1.11 Aug 31, 2000 - Do not try to register irq 0 if no irq line was
* set for EISA cards.
* - Added support for NetFlex3/E with nibble-rate
* 10Base-T PHY. This is untestet as I haven't got
@@ -142,7 +142,7 @@
* - Added the bbuf option as a kernel parameter.
* - Fixed ioaddr probe bug.
* - Fixed stupid deadlock with MII interrupts.
- * - Added support for speed/duplex selection with
+ * - Added support for speed/duplex selection with
* multiple nics.
* - Added partly fix for TX Channel lockup with
* TLAN v1.0 silicon. This needs to be investigated
@@ -226,7 +226,7 @@ static int tlan_have_pci;
static int tlan_have_eisa;
static const char *media[] = {
- "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
+ "10BaseT-HD ", "10BaseT-FD ","100baseTx-HD ",
"100baseTx-FD", "100baseT4", NULL
};
@@ -249,7 +249,7 @@ static struct board {
{ "Compaq Netelligent 10/100 TX UTP", TLAN_ADAPTER_ACTIVITY_LED, 0x83 },
{ "Compaq Netelligent 10 T/2 PCI UTP/Coax", TLAN_ADAPTER_NONE, 0x83 },
{ "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED | /* EISA card */
- TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
+ TLAN_ADAPTER_UNMANAGED_PHY | TLAN_ADAPTER_BIT_RATE_PHY, 0x83 },
{ "Compaq NetFlex-3/E", TLAN_ADAPTER_ACTIVITY_LED, 0x83 }, /* EISA card */
};
@@ -282,7 +282,7 @@ static struct pci_device_id tlan_pci_tbl[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 },
{ 0,}
};
-MODULE_DEVICE_TABLE(pci, tlan_pci_tbl);
+MODULE_DEVICE_TABLE(pci, tlan_pci_tbl);
static void TLan_EisaProbe( void );
static void TLan_Eisa_Cleanup( void );
@@ -347,7 +347,7 @@ static void TLan_EeReceiveByte( u16, u8 *, int );
static int TLan_EeReadByte( struct net_device *, u8, u8 * );
-static void
+static void
TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb)
{
unsigned long addr = (unsigned long)skb;
@@ -384,11 +384,11 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type )
{
TLanPrivateInfo *priv = netdev_priv(dev);
unsigned long flags = 0;
-
+
if (!in_irq())
spin_lock_irqsave(&priv->lock, flags);
if ( priv->timer.function != NULL &&
- priv->timerType != TLAN_TIMER_ACTIVITY ) {
+ priv->timerType != TLAN_TIMER_ACTIVITY ) {
if (!in_irq())
spin_unlock_irqrestore(&priv->lock, flags);
return;
@@ -401,7 +401,7 @@ TLan_SetTimer( struct net_device *dev, u32 ticks, u32 type )
priv->timerSetAt = jiffies;
priv->timerType = type;
mod_timer(&priv->timer, jiffies + ticks);
-
+
} /* TLan_SetTimer */
@@ -439,7 +439,7 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata( pdev );
TLanPrivateInfo *priv = netdev_priv(dev);
-
+
unregister_netdev( dev );
if ( priv->dmaStorage ) {
@@ -449,25 +449,25 @@ static void __devexit tlan_remove_one( struct pci_dev *pdev)
#ifdef CONFIG_PCI
pci_release_regions(pdev);
#endif
-
+
free_netdev( dev );
-
+
pci_set_drvdata( pdev, NULL );
-}
+}
static struct pci_driver tlan_driver = {
.name = "tlan",
.id_table = tlan_pci_tbl,
.probe = tlan_init_one,
- .remove = __devexit_p(tlan_remove_one),
+ .remove = __devexit_p(tlan_remove_one),
};
static int __init tlan_probe(void)
{
static int pad_allocated;
-
+
printk(KERN_INFO "%s", tlan_banner);
-
+
TLanPadBuffer = (u8 *) pci_alloc_consistent(NULL, TLAN_MIN_FRAME_SIZE, &TLanPadBufferDMA);
if (TLanPadBuffer == NULL) {
@@ -479,15 +479,15 @@ static int __init tlan_probe(void)
pad_allocated = 1;
TLAN_DBG(TLAN_DEBUG_PROBE, "Starting PCI Probe....\n");
-
+
/* Use new style PCI probing. Now the kernel will
do most of this for us */
pci_register_driver(&tlan_driver);
TLAN_DBG(TLAN_DEBUG_PROBE, "Starting EISA Probe....\n");
TLan_EisaProbe();
-
- printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n",
+
+ printk(KERN_INFO "TLAN: %d device%s installed, PCI: %d EISA: %d\n",
TLanDevicesInstalled, TLanDevicesInstalled == 1 ? "" : "s",
tlan_have_pci, tlan_have_eisa);
@@ -498,7 +498,7 @@ static int __init tlan_probe(void)
}
return 0;
}
-
+
static int __devinit tlan_init_one( struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -513,11 +513,11 @@ static int __devinit tlan_init_one( struct pci_dev *pdev,
*
* Returns:
* 0 on success, error code on error
- * Parms:
+ * Parms:
* none
*
* The name is lower case to fit in with all the rest of
- * the netcard_probe names. This function looks for
+ * the netcard_probe names. This function looks for
* another TLan based adapter, setting it up with the
* allocated device struct if one is found.
* tlan_probe has been ported to the new net API and
@@ -526,7 +526,7 @@ static int __devinit tlan_init_one( struct pci_dev *pdev,
*
**************************************************************/
-static int __devinit TLan_probe1(struct pci_dev *pdev,
+static int __devinit TLan_probe1(struct pci_dev *pdev,
long ioaddr, int irq, int rev, const struct pci_device_id *ent )
{
@@ -558,11 +558,11 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
}
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
-
+
priv = netdev_priv(dev);
priv->pciDev = pdev;
-
+
/* Is this a PCI device? */
if (pdev) {
u32 pci_io_base = 0;
@@ -590,10 +590,10 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
rc = -EIO;
goto err_out_free_dev;
}
-
+
dev->base_addr = pci_io_base;
dev->irq = pdev->irq;
- priv->adapterRev = pci_rev;
+ priv->adapterRev = pci_rev;
pci_set_master(pdev);
pci_set_drvdata(pdev, dev);
@@ -618,7 +618,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
priv->aui = dev->mem_start & 0x01;
priv->duplex = ((dev->mem_start & 0x06) == 0x06) ? 0 : (dev->mem_start & 0x06) >> 1;
priv->speed = ((dev->mem_start & 0x18) == 0x18) ? 0 : (dev->mem_start & 0x18) >> 3;
-
+
if (priv->speed == 0x1) {
priv->speed = TLAN_SPEED_10;
} else if (priv->speed == 0x2) {
@@ -631,13 +631,13 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
priv->duplex = duplex[boards_found];
priv->debug = debug;
}
-
+
/* This will be used when we get an adapter error from
* within our irq handler */
INIT_WORK(&priv->tlan_tqueue, (void *)(void*)TLan_tx_timeout, dev);
spin_lock_init(&priv->lock);
-
+
rc = TLan_Init(dev);
if (rc) {
printk(KERN_ERR "TLAN: Could not set up device.\n");
@@ -650,10 +650,10 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
goto err_out_uninit;
}
-
+
TLanDevicesInstalled++;
boards_found++;
-
+
/* pdev is NULL if this is an EISA device */
if (pdev)
tlan_have_pci++;
@@ -662,7 +662,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
TLan_Eisa_Devices = dev;
tlan_have_eisa++;
}
-
+
printk(KERN_INFO "TLAN: %s irq=%2d, io=%04x, %s, Rev. %d\n",
dev->name,
(int) dev->irq,
@@ -692,7 +692,7 @@ static void TLan_Eisa_Cleanup(void)
{
struct net_device *dev;
TLanPrivateInfo *priv;
-
+
while( tlan_have_eisa ) {
dev = TLan_Eisa_Devices;
priv = netdev_priv(dev);
@@ -706,8 +706,8 @@ static void TLan_Eisa_Cleanup(void)
tlan_have_eisa--;
}
}
-
-
+
+
static void __exit tlan_exit(void)
{
pci_unregister_driver(&tlan_driver);
@@ -734,52 +734,52 @@ module_exit(tlan_exit);
* Parms: None
*
*
- * This functions probes for EISA devices and calls
- * TLan_probe1 when one is found.
+ * This functions probes for EISA devices and calls
+ * TLan_probe1 when one is found.
*
*************************************************************/
-static void __init TLan_EisaProbe (void)
+static void __init TLan_EisaProbe (void)
{
long ioaddr;
int rc = -ENODEV;
int irq;
u16 device_id;
- if (!EISA_bus) {
+ if (!EISA_bus) {
TLAN_DBG(TLAN_DEBUG_PROBE, "No EISA bus present\n");
return;
}
-
+
/* Loop through all slots of the EISA bus */
for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) {
-
- TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
+
+ TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC80, inw(ioaddr + EISA_ID));
TLAN_DBG(TLAN_DEBUG_PROBE,"EISA_ID 0x%4x: 0x%4x\n", (int) ioaddr + 0xC82, inw(ioaddr + EISA_ID2));
TLAN_DBG(TLAN_DEBUG_PROBE, "Probing for EISA adapter at IO: 0x%4x : ",
(int) ioaddr);
- if (request_region(ioaddr, 0x10, TLanSignature) == NULL)
+ if (request_region(ioaddr, 0x10, TLanSignature) == NULL)
goto out;
- if (inw(ioaddr + EISA_ID) != 0x110E) {
+ if (inw(ioaddr + EISA_ID) != 0x110E) {
release_region(ioaddr, 0x10);
goto out;
}
-
+
device_id = inw(ioaddr + EISA_ID2);
- if (device_id != 0x20F1 && device_id != 0x40F1) {
+ if (device_id != 0x20F1 && device_id != 0x40F1) {
release_region (ioaddr, 0x10);
goto out;
}
-
+
if (inb(ioaddr + EISA_CR) != 0x1) { /* Check if adapter is enabled */
release_region (ioaddr, 0x10);
goto out2;
}
-
- if (debug == 0x10)
+
+ if (debug == 0x10)
printk("Found one\n");
@@ -799,14 +799,14 @@ static void __init TLan_EisaProbe (void)
break;
default:
goto out;
- }
-
-
+ }
+
+
/* Setup the newly found eisa adapter */
rc = TLan_probe1( NULL, ioaddr, irq,
12, NULL);
continue;
-
+
out:
if (debug == 0x10)
printk("None found\n");
@@ -815,7 +815,7 @@ static void __init TLan_EisaProbe (void)
out2: if (debug == 0x10)
printk("Card found but it is not enabled, skipping\n");
continue;
-
+
}
} /* TLan_EisaProbe */
@@ -829,7 +829,7 @@ static void TLan_Poll(struct net_device *dev)
}
#endif
-
+
/***************************************************************
@@ -846,7 +846,7 @@ static void TLan_Poll(struct net_device *dev)
* addresses, allocates memory for the lists and bounce
* buffers, retrieves the MAC address from the eeprom
* and assignes the device's methods.
- *
+ *
**************************************************************/
static int TLan_Init( struct net_device *dev )
@@ -857,7 +857,7 @@ static int TLan_Init( struct net_device *dev )
TLanPrivateInfo *priv;
priv = netdev_priv(dev);
-
+
if ( bbuf ) {
dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS )
* ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE );
@@ -867,14 +867,14 @@ static int TLan_Init( struct net_device *dev )
}
priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA);
priv->dmaSize = dma_size;
-
+
if ( priv->dmaStorage == NULL ) {
printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n",
dev->name );
return -ENOMEM;
}
memset( priv->dmaStorage, 0, dma_size );
- priv->rxList = (TLanList *)
+ priv->rxList = (TLanList *)
( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 );
priv->rxListDMA = ( ( ( (u32) priv->dmaStorageDMA ) + 7 ) & 0xFFFFFFF8 );
priv->txList = priv->rxList + TLAN_NUM_RX_LISTS;
@@ -941,18 +941,18 @@ static int TLan_Open( struct net_device *dev )
{
TLanPrivateInfo *priv = netdev_priv(dev);
int err;
-
+
priv->tlanRev = TLan_DioRead8( dev->base_addr, TLAN_DEF_REVISION );
- err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev );
-
+ err = request_irq( dev->irq, TLan_HandleInterrupt, IRQF_SHARED, TLanSignature, dev );
+
if ( err ) {
printk(KERN_ERR "TLAN: Cannot open %s because IRQ %d is already in use.\n", dev->name, dev->irq );
return err;
}
-
+
init_timer(&priv->timer);
netif_start_queue(dev);
-
+
/* NOTE: It might not be necessary to read the stats before a
reset if you don't care what the values are.
*/
@@ -970,12 +970,12 @@ static int TLan_Open( struct net_device *dev )
/**************************************************************
* TLan_ioctl
- *
+ *
* Returns:
* 0 on success, error code otherwise
* Params:
* dev structure of device to receive ioctl.
- *
+ *
* rq ifreq structure to hold userspace data.
*
* cmd ioctl command.
@@ -988,7 +988,7 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
TLanPrivateInfo *priv = netdev_priv(dev);
struct mii_ioctl_data *data = if_mii(rq);
u32 phy = priv->phy[priv->phyNum];
-
+
if (!priv->phyOnline)
return -EAGAIN;
@@ -1000,7 +1000,7 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case SIOCGMIIREG: /* Read MII PHY register. */
TLan_MiiReadReg(dev, data->phy_id & 0x1f, data->reg_num & 0x1f, &data->val_out);
return 0;
-
+
case SIOCSMIIREG: /* Write MII PHY register. */
if (!capable(CAP_NET_ADMIN))
@@ -1019,31 +1019,31 @@ static int TLan_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
* Returns: nothing
*
* Params:
- * dev structure of device which timed out
+ * dev structure of device which timed out
* during transmit.
*
**************************************************************/
static void TLan_tx_timeout(struct net_device *dev)
{
-
+
TLAN_DBG( TLAN_DEBUG_GNRL, "%s: Transmit timed out.\n", dev->name);
-
+
/* Ok so we timed out, lets see what we can do about it...*/
TLan_FreeLists( dev );
- TLan_ResetLists( dev );
+ TLan_ResetLists( dev );
TLan_ReadAndClearStats( dev, TLAN_IGNORE );
TLan_ResetAdapter( dev );
dev->trans_start = jiffies;
- netif_wake_queue( dev );
+ netif_wake_queue( dev );
}
-
+
/***************************************************************
* TLan_StartTx
- *
+ *
* Returns:
* 0 on success, non-zero on failure.
* Parms:
@@ -1079,7 +1079,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
tail_list = priv->txList + priv->txTail;
tail_list_phys = priv->txListDMA + sizeof(TLanList) * priv->txTail;
-
+
if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) {
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s is busy (Head=%d Tail=%d)\n", dev->name, priv->txHead, priv->txTail );
netif_stop_queue(dev);
@@ -1132,7 +1132,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
if ( bbuf )
dev_kfree_skb_any(skb);
-
+
dev->trans_start = jiffies;
return 0;
@@ -1143,8 +1143,8 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
/***************************************************************
* TLan_HandleInterrupt
- *
- * Returns:
+ *
+ * Returns:
* Nothing
* Parms:
* irq The line on which the interrupt
@@ -1198,7 +1198,7 @@ static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *r
/***************************************************************
* TLan_Close
- *
+ *
* Returns:
* An error code.
* Parms:
@@ -1224,7 +1224,7 @@ static int TLan_Close(struct net_device *dev)
del_timer_sync( &priv->timer );
priv->timer.function = NULL;
}
-
+
free_irq( dev->irq, dev );
TLan_FreeLists( dev );
TLAN_DBG( TLAN_DEBUG_GNRL, "Device %s closed.\n", dev->name );
@@ -1238,7 +1238,7 @@ static int TLan_Close(struct net_device *dev)
/***************************************************************
* TLan_GetStats
- *
+ *
* Returns:
* A pointer to the device's statistics structure.
* Parms:
@@ -1263,7 +1263,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: %s Busy count = %d\n", dev->name, priv->txBusyCount );
if ( debug & TLAN_DEBUG_GNRL ) {
TLan_PrintDio( dev->base_addr );
- TLan_PhyPrint( dev );
+ TLan_PhyPrint( dev );
}
if ( debug & TLAN_DEBUG_LIST ) {
for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ )
@@ -1271,7 +1271,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ )
TLan_PrintList( priv->txList + i, "TX", i );
}
-
+
return ( &( (TLanPrivateInfo *) netdev_priv(dev) )->stats );
} /* TLan_GetStats */
@@ -1281,7 +1281,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
/***************************************************************
* TLan_SetMulticastList
- *
+ *
* Returns:
* Nothing
* Parms:
@@ -1300,7 +1300,7 @@ static struct net_device_stats *TLan_GetStats( struct net_device *dev )
**************************************************************/
static void TLan_SetMulticastList( struct net_device *dev )
-{
+{
struct dev_mc_list *dmi = dev->mc_list;
u32 hash1 = 0;
u32 hash2 = 0;
@@ -1315,7 +1315,7 @@ static void TLan_SetMulticastList( struct net_device *dev )
tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD );
TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF );
if ( dev->flags & IFF_ALLMULTI ) {
- for ( i = 0; i < 3; i++ )
+ for ( i = 0; i < 3; i++ )
TLan_SetMac( dev, i + 1, NULL );
TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF );
TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF );
@@ -1325,14 +1325,14 @@ static void TLan_SetMulticastList( struct net_device *dev )
TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr );
} else {
offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr );
- if ( offset < 32 )
+ if ( offset < 32 )
hash1 |= ( 1 << offset );
else
hash2 |= ( 1 << ( offset - 32 ) );
}
dmi = dmi->next;
}
- for ( ; i < 3; i++ )
+ for ( ; i < 3; i++ )
TLan_SetMac( dev, i + 1, NULL );
TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 );
TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 );
@@ -1350,7 +1350,7 @@ static void TLan_SetMulticastList( struct net_device *dev )
Please see Chap. 4, "Interrupt Handling" of the "ThunderLAN
Programmer's Guide" for more informations on handling interrupts
- generated by TLAN based adapters.
+ generated by TLAN based adapters.
******************************************************************************
*****************************************************************************/
@@ -1413,7 +1413,7 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
dma_addr_t head_list_phys;
u32 ack = 0;
u16 tmpCStat;
-
+
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOF (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
head_list = priv->txList + priv->txHead;
@@ -1426,21 +1426,21 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
head_list->buffer[8].address = 0;
head_list->buffer[9].address = 0;
}
-
+
if ( tmpCStat & TLAN_CSTAT_EOC )
eoc = 1;
-
+
priv->stats.tx_bytes += head_list->frameSize;
head_list->cStat = TLAN_CSTAT_UNUSED;
- netif_start_queue(dev);
- CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
+ netif_start_queue(dev);
+ CIRC_INC( priv->txHead, TLAN_NUM_TX_LISTS );
head_list = priv->txList + priv->txHead;
}
if (!ack)
printk(KERN_INFO "TLAN: Received interrupt for uncompleted TX frame.\n");
-
+
if ( eoc ) {
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d)\n", priv->txHead, priv->txTail );
head_list = priv->txList + priv->txHead;
@@ -1452,7 +1452,7 @@ u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int )
priv->txInProgress = 0;
}
}
-
+
if ( priv->adapter->flags & TLAN_ADAPTER_ACTIVITY_LED ) {
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT );
if ( priv->timer.function == NULL ) {
@@ -1544,13 +1544,13 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOF (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
head_list = priv->rxList + priv->rxHead;
head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
-
+
while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) {
frameSize = head_list->frameSize;
ack++;
if (tmpCStat & TLAN_CSTAT_EOC)
eoc = 1;
-
+
if (bbuf) {
skb = dev_alloc_skb(frameSize + 7);
if (skb == NULL)
@@ -1560,7 +1560,7 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
skb->dev = dev;
skb_reserve(skb, 2);
t = (void *) skb_put(skb, frameSize);
-
+
priv->stats.rx_bytes += head_list->frameSize;
memcpy( t, head_buffer, frameSize );
@@ -1569,15 +1569,15 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
}
} else {
struct sk_buff *new_skb;
-
+
/*
* I changed the algorithm here. What we now do
* is allocate the new frame. If this fails we
* simply recycle the frame.
*/
-
+
new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 );
-
+
if ( new_skb != NULL ) {
skb = TLan_GetSKB(head_list);
pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
@@ -1587,14 +1587,14 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
skb->protocol = eth_type_trans( skb, dev );
netif_rx( skb );
-
+
new_skb->dev = dev;
skb_reserve( new_skb, 2 );
t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE );
head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE);
head_list->buffer[8].address = (u32) t;
TLan_StoreSKB(head_list, new_skb);
- } else
+ } else
printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" );
}
@@ -1611,11 +1611,11 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
if (!ack)
printk(KERN_INFO "TLAN: Received interrupt for uncompleted RX frame.\n");
-
- if ( eoc ) {
+
+ if ( eoc ) {
TLAN_DBG( TLAN_DEBUG_RX, "RECEIVE: Handling RX EOC (Head=%d Tail=%d)\n", priv->rxHead, priv->rxTail );
head_list = priv->rxList + priv->rxHead;
head_list_phys = priv->rxListDMA + sizeof(TLanList) * priv->rxHead;
@@ -1639,7 +1639,7 @@ u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int )
}
dev->last_rx = jiffies;
-
+
return ack;
} /* TLan_HandleRxEOF */
@@ -1700,7 +1700,7 @@ u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int )
TLanList *head_list;
dma_addr_t head_list_phys;
u32 ack = 1;
-
+
host_int = 0;
if ( priv->tlanRev < 0x30 ) {
TLAN_DBG( TLAN_DEBUG_TX, "TRANSMIT: Handling TX EOC (Head=%d Tail=%d) -- IRQ\n", priv->txHead, priv->txTail );
@@ -1743,7 +1743,7 @@ u32 TLan_HandleTxEOC( struct net_device *dev, u16 host_int )
**************************************************************/
u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
-{
+{
TLanPrivateInfo *priv = netdev_priv(dev);
u32 ack;
u32 error;
@@ -1751,7 +1751,7 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
u32 phy;
u16 tlphy_ctl;
u16 tlphy_sts;
-
+
ack = 1;
if ( host_int & TLAN_HI_IV_MASK ) {
netif_stop_queue( dev );
@@ -1785,7 +1785,7 @@ u32 TLan_HandleStatusCheck( struct net_device *dev, u16 host_int )
}
if (debug) {
- TLan_PhyPrint( dev );
+ TLan_PhyPrint( dev );
}
}
}
@@ -1887,7 +1887,7 @@ void TLan_Timer( unsigned long data )
priv->timer.function = NULL;
switch ( priv->timerType ) {
-#ifdef MONITOR
+#ifdef MONITOR
case TLAN_TIMER_LINK_BEAT:
TLan_PhyMonitor( dev );
break;
@@ -1946,7 +1946,7 @@ void TLan_Timer( unsigned long data )
/***************************************************************
* TLan_ResetLists
- *
+ *
* Returns:
* Nothing
* Parms:
@@ -2055,7 +2055,7 @@ void TLan_FreeLists( struct net_device *dev )
/***************************************************************
* TLan_PrintDio
- *
+ *
* Returns:
* Nothing
* Parms:
@@ -2087,7 +2087,7 @@ void TLan_PrintDio( u16 io_base )
/***************************************************************
* TLan_PrintList
- *
+ *
* Returns:
* Nothing
* Parms:
@@ -2128,7 +2128,7 @@ void TLan_PrintList( TLanList *list, char *type, int num)
* Parms:
* dev Pointer to device structure of adapter
* to which to read stats.
- * record Flag indicating whether to add
+ * record Flag indicating whether to add
*
* This functions reads all the internal status registers
* of the TLAN chip, which clears them as a side effect.
@@ -2158,13 +2158,13 @@ void TLan_ReadAndClearStats( struct net_device *dev, int record )
rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16;
rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
-
+
outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR );
def_tx = inb( dev->base_addr + TLAN_DIO_DATA );
def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 );
code = inb( dev->base_addr + TLAN_DIO_DATA + 3 );
-
+
outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR );
multi_col = inb( dev->base_addr + TLAN_DIO_DATA );
multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8;
@@ -2190,7 +2190,7 @@ void TLan_ReadAndClearStats( struct net_device *dev, int record )
priv->stats.tx_aborted_errors += tx_under;
priv->stats.tx_carrier_errors += loss;
}
-
+
} /* TLan_ReadAndClearStats */
@@ -2231,7 +2231,7 @@ TLan_ResetAdapter( struct net_device *dev )
data = inl(dev->base_addr + TLAN_HOST_CMD);
data |= TLAN_HC_AD_RST;
outl(data, dev->base_addr + TLAN_HOST_CMD);
-
+
udelay(1000);
/* 2. Turn off interrupts. ( Probably isn't necessary ) */
@@ -2270,7 +2270,7 @@ TLan_ResetAdapter( struct net_device *dev )
}
TLan_PhyDetect( dev );
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN;
-
+
if ( priv->adapter->flags & TLAN_ADAPTER_BIT_RATE_PHY ) {
data |= TLAN_NET_CFG_BIT;
if ( priv->aui == 1 ) {
@@ -2320,15 +2320,15 @@ TLan_FinishReset( struct net_device *dev )
data |= TLAN_NET_CMD_DUPLEX;
}
TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, data );
- data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
+ data = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5;
if ( priv->phyNum == 0 ) {
- data |= TLAN_NET_MASK_MASK7;
+ data |= TLAN_NET_MASK_MASK7;
}
TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data );
TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, ((1536)+7)&~7 );
TLan_MiiReadReg( dev, phy, MII_GEN_ID_HI, &tlphy_id1 );
TLan_MiiReadReg( dev, phy, MII_GEN_ID_LO, &tlphy_id2 );
-
+
if ( ( priv->adapter->flags & TLAN_ADAPTER_UNMANAGED_PHY ) || ( priv->aui ) ) {
status = MII_GS_LINK;
printk( "TLAN: %s: Link forced.\n", dev->name );
@@ -2336,15 +2336,15 @@ TLan_FinishReset( struct net_device *dev )
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
udelay( 1000 );
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
- if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */
+ if ( (status & MII_GS_LINK) && /* We only support link info on Nat.Sem. PHY's */
(tlphy_id1 == NAT_SEM_ID1) &&
(tlphy_id2 == NAT_SEM_ID2) ) {
TLan_MiiReadReg( dev, phy, MII_AN_LPA, &partner );
TLan_MiiReadReg( dev, phy, TLAN_TLPHY_PAR, &tlphy_par );
-
+
printk( "TLAN: %s: Link active with ", dev->name );
if (!(tlphy_par & TLAN_PHY_AN_EN_STAT)) {
- printk( "forced 10%sMbps %s-Duplex\n",
+ printk( "forced 10%sMbps %s-Duplex\n",
tlphy_par & TLAN_PHY_SPEED_100 ? "" : "0",
tlphy_par & TLAN_PHY_DUPLEX_FULL ? "Full" : "Half");
} else {
@@ -2359,12 +2359,12 @@ TLan_FinishReset( struct net_device *dev )
}
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
-#ifdef MONITOR
+#ifdef MONITOR
/* We have link beat..for now anyway */
priv->link = 1;
/*Enabling link beat monitoring */
TLan_SetTimer( dev, (10*HZ), TLAN_TIMER_LINK_BEAT );
-#endif
+#endif
} else if (status & MII_GS_LINK) {
printk( "TLAN: %s: Link active\n", dev->name );
TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK );
@@ -2426,7 +2426,7 @@ TLan_FinishReset( struct net_device *dev )
void TLan_SetMac( struct net_device *dev, int areg, char *mac )
{
int i;
-
+
areg *= 6;
if ( mac != NULL ) {
@@ -2460,7 +2460,7 @@ void TLan_SetMac( struct net_device *dev, int areg, char *mac )
* Parms:
* dev A pointer to the device structure of the
* TLAN device having the PHYs to be detailed.
- *
+ *
* This function prints the registers a PHY (aka transceiver).
*
********************************************************************/
@@ -2528,7 +2528,7 @@ void TLan_PhyDetect( struct net_device *dev )
}
TLan_MiiReadReg( dev, TLAN_PHY_MAX_ADDR, MII_GEN_ID_HI, &hi );
-
+
if ( hi != 0xFFFF ) {
priv->phy[0] = TLAN_PHY_MAX_ADDR;
} else {
@@ -2650,10 +2650,10 @@ void TLan_PhyStartLink( struct net_device *dev )
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &ability );
- if ( ( status & MII_GS_AUTONEG ) &&
+ if ( ( status & MII_GS_AUTONEG ) &&
( ! priv->aui ) ) {
ability = status >> 11;
- if ( priv->speed == TLAN_SPEED_10 &&
+ if ( priv->speed == TLAN_SPEED_10 &&
priv->duplex == TLAN_DUPLEX_HALF) {
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x0000);
} else if ( priv->speed == TLAN_SPEED_10 &&
@@ -2668,7 +2668,7 @@ void TLan_PhyStartLink( struct net_device *dev )
priv->tlanFullDuplex = TRUE;
TLan_MiiWriteReg( dev, phy, MII_GEN_CTL, 0x2100);
} else {
-
+
/* Set Auto-Neg advertisement */
TLan_MiiWriteReg( dev, phy, MII_AN_ADV, (ability << 5) | 1);
/* Enablee Auto-Neg */
@@ -2684,9 +2684,9 @@ void TLan_PhyStartLink( struct net_device *dev )
TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_PHY_FINISH_AN );
return;
}
-
- }
-
+
+ }
+
if ( ( priv->aui ) && ( priv->phyNum != 0 ) ) {
priv->phyNum = 0;
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN;
@@ -2698,7 +2698,7 @@ void TLan_PhyStartLink( struct net_device *dev )
TLan_MiiReadReg( dev, phy, TLAN_TLPHY_CTL, &tctl );
if ( priv->aui ) {
tctl |= TLAN_TC_AUISEL;
- } else {
+ } else {
tctl &= ~TLAN_TC_AUISEL;
if ( priv->duplex == TLAN_DUPLEX_FULL ) {
control |= MII_GC_DUPLEX;
@@ -2731,7 +2731,7 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev )
u16 mode;
u16 phy;
u16 status;
-
+
phy = priv->phy[priv->phyNum];
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &status );
@@ -2783,7 +2783,7 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev )
/* Wait for 100 ms. No reason in partiticular.
*/
TLan_SetTimer( dev, (HZ/10), TLAN_TIMER_FINISH_RESET );
-
+
} /* TLan_PhyFinishAutoNeg */
#ifdef MONITOR
@@ -2792,13 +2792,13 @@ void TLan_PhyFinishAutoNeg( struct net_device *dev )
*
* TLan_phyMonitor
*
- * Returns:
+ * Returns:
* None
*
* Params:
* dev The device structure of this device.
*
- *
+ *
* This function monitors PHY condition by reading the status
* register via the MII bus. This can be used to give info
* about link changes (up/down), and possible switch to alternate
@@ -2818,7 +2818,7 @@ void TLan_PhyMonitor( struct net_device *dev )
TLan_MiiReadReg( dev, phy, MII_GEN_STS, &phy_status );
/* Check if link has been lost */
- if (!(phy_status & MII_GS_LINK)) {
+ if (!(phy_status & MII_GS_LINK)) {
if (priv->link) {
priv->link = 0;
printk(KERN_DEBUG "TLAN: %s has lost link\n", dev->name);
@@ -2837,7 +2837,7 @@ void TLan_PhyMonitor( struct net_device *dev )
/* Setup a new monitor */
TLan_SetTimer( dev, (2*HZ), TLAN_TIMER_LINK_BEAT );
-}
+}
#endif /* MONITOR */
@@ -2891,7 +2891,7 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
err = FALSE;
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
-
+
if (!in_irq())
spin_lock_irqsave(&priv->lock, flags);
@@ -2939,7 +2939,7 @@ int TLan_MiiReadReg( struct net_device *dev, u16 phy, u16 reg, u16 *val )
TLan_SetBit(TLAN_NET_SIO_MINTEN, sio);
*val = tmp;
-
+
if (!in_irq())
spin_unlock_irqrestore(&priv->lock, flags);
@@ -3058,7 +3058,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
outw(TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR);
sio = dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO;
-
+
if (!in_irq())
spin_lock_irqsave(&priv->lock, flags);
@@ -3081,7 +3081,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
if ( minten )
TLan_SetBit( TLAN_NET_SIO_MINTEN, sio );
-
+
if (!in_irq())
spin_unlock_irqrestore(&priv->lock, flags);
@@ -3109,7 +3109,7 @@ void TLan_MiiWriteReg( struct net_device *dev, u16 phy, u16 reg, u16 val )
*
* Returns:
* Nothing
- * Parms:
+ * Parms:
* io_base The IO port base address for the
* TLAN device with the EEPROM to
* use.
diff --git a/drivers/net/tlan.h b/drivers/net/tlan.h
index 5d32bc62bef..a44e2f2ef62 100644
--- a/drivers/net/tlan.h
+++ b/drivers/net/tlan.h
@@ -9,13 +9,13 @@
*
* (C) 1997-1998 Caldera, Inc.
* (C) 1999-2001 Torben Mathiasen
- *
+ *
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
** This file is best viewed/edited with tabstop=4, colums>=132
*
- *
+ *
* Dec 10, 1999 Torben Mathiasen <torben.mathiasen@compaq.com>
* New Maintainer
*
@@ -48,7 +48,7 @@
#define TLAN_DBG(lvl, format, args...) if (debug&lvl) printk(KERN_DEBUG "TLAN: " format, ##args );
#define TLAN_DEBUG_GNRL 0x0001
#define TLAN_DEBUG_TX 0x0002
-#define TLAN_DEBUG_RX 0x0004
+#define TLAN_DEBUG_RX 0x0004
#define TLAN_DEBUG_LIST 0x0008
#define TLAN_DEBUG_PROBE 0x0010
@@ -60,7 +60,7 @@
* Device Identification Definitions
*
****************************************************************/
-
+
#define PCI_DEVICE_ID_NETELLIGENT_10_T2 0xB012
#define PCI_DEVICE_ID_NETELLIGENT_10_100_WS_5100 0xB030
#ifndef PCI_DEVICE_ID_OLICOM_OC2183
@@ -102,11 +102,11 @@ typedef struct tlan_adapter_entry {
*
****************************************************************/
-#define EISA_ID 0xc80 /* EISA ID Registers */
-#define EISA_ID0 0xc80 /* EISA ID Register 0 */
-#define EISA_ID1 0xc81 /* EISA ID Register 1 */
-#define EISA_ID2 0xc82 /* EISA ID Register 2 */
-#define EISA_ID3 0xc83 /* EISA ID Register 3 */
+#define EISA_ID 0xc80 /* EISA ID Registers */
+#define EISA_ID0 0xc80 /* EISA ID Register 0 */
+#define EISA_ID1 0xc81 /* EISA ID Register 1 */
+#define EISA_ID2 0xc82 /* EISA ID Register 2 */
+#define EISA_ID3 0xc83 /* EISA ID Register 3 */
#define EISA_CR 0xc84 /* EISA Control Register */
#define EISA_REG0 0xc88 /* EISA Configuration Register 0 */
#define EISA_REG1 0xc89 /* EISA Configuration Register 1 */
@@ -447,7 +447,7 @@ static inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr)
{
outw(internal_addr, base_addr + TLAN_DIO_ADR);
return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3)));
-
+
} /* TLan_DioRead8 */
@@ -505,8 +505,8 @@ static inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data)
#define TLan_SetBit( bit, port ) outb_p(inb_p(port) | bit, port)
/*
- * given 6 bytes, view them as 8 6-bit numbers and return the XOR of those
- * the code below is about seven times as fast as the original code
+ * given 6 bytes, view them as 8 6-bit numbers and return the XOR of those
+ * the code below is about seven times as fast as the original code
*
* The original code was:
*
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 41e0cd8f478..412390ba142 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -42,7 +42,6 @@
#define XL_DEBUG 0
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -577,7 +576,7 @@ static int xl_open(struct net_device *dev)
u16 switchsettings, switchsettings_eeprom ;
- if(request_irq(dev->irq, &xl_interrupt, SA_SHIRQ , "3c359", dev)) {
+ if(request_irq(dev->irq, &xl_interrupt, IRQF_SHARED , "3c359", dev)) {
return -EAGAIN;
}
@@ -1816,7 +1815,7 @@ static struct pci_driver xl_3c359_driver = {
static int __init xl_pci_init (void)
{
- return pci_module_init (&xl_3c359_driver);
+ return pci_register_driver(&xl_3c359_driver);
}
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index 649d8ea354f..1bdd3beefbe 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -123,7 +123,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_
goto err_out_trdev;
}
- ret = request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
+ ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED,
dev->name, dev);
if (ret)
goto err_out_region;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 9f491563944..4470025ff7f 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -140,7 +140,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
/* version and credits */
#ifndef PCMCIA
-static char version[] __initdata =
+static char version[] __devinitdata =
"\nibmtr.c: v1.3.57 8/ 7/94 Peter De Schrijver and Mark Swanson\n"
" v2.1.125 10/20/98 Paul Norton <pnorton@ieee.org>\n"
" v2.2.0 12/30/98 Joel Sloan <jjs@c-me.com>\n"
@@ -216,7 +216,7 @@ static int __devinitdata turbo_irq[IBMTR_MAX_ADAPTERS] = {0};
static int __devinitdata turbo_searched = 0;
#ifndef PCMCIA
-static __u32 ibmtr_mem_base __initdata = 0xd0000;
+static __u32 ibmtr_mem_base __devinitdata = 0xd0000;
#endif
static void __devinit PrtChanID(char *pcid, short stride)
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index c58a4c31d0d..bfc8c3eae9a 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -100,7 +100,6 @@
#define STREAMER_IOCTL 0
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -602,7 +601,7 @@ static int streamer_open(struct net_device *dev)
rc=streamer_reset(dev);
}
- if (request_irq(dev->irq, &streamer_interrupt, SA_SHIRQ, "lanstreamer", dev)) {
+ if (request_irq(dev->irq, &streamer_interrupt, IRQF_SHARED, "lanstreamer", dev)) {
return -EAGAIN;
}
#if STREAMER_DEBUG
@@ -1877,7 +1876,6 @@ static int sprintf_info(char *buffer, struct net_device *dev)
datap[size+1]=io_word & 0xff;
}
-
size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name);
size += sprintf(buffer + size,
@@ -1933,64 +1931,6 @@ static int sprintf_info(char *buffer, struct net_device *dev)
#endif
#endif
-#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- int i;
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
- u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
-
- switch(cmd) {
- case IOCTL_SISR_MASK:
- writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
- break;
- case IOCTL_SPIN_LOCK_TEST:
- printk(KERN_INFO "spin_lock() called.\n");
- spin_lock(&streamer_priv->streamer_lock);
- spin_unlock(&streamer_priv->streamer_lock);
- printk(KERN_INFO "spin_unlock() finished.\n");
- break;
- case IOCTL_PRINT_BDAS:
- printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
- readw(streamer_mmio + RXBDA),
- readw(streamer_mmio + RXLBDA),
- readw(streamer_mmio + TX2FDA),
- readw(streamer_mmio + TX2LFDA));
- break;
- case IOCTL_PRINT_REGISTERS:
- printk(KERN_INFO "registers:\n");
- printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n",
- readw(streamer_mmio + SISR),
- readw(streamer_mmio + MISR_RUM),
- readw(streamer_mmio + LISR),
- readw(streamer_mmio + BCTL),
- readw(streamer_mmio + BMCTL_SUM),
- readw(streamer_mmio + SISR_MASK),
- readw(streamer_mmio + MISR_MASK));
- break;
- case IOCTL_PRINT_RX_BUFS:
- printk(KERN_INFO "Print rx bufs:\n");
- for(i=0; i<STREAMER_RX_RING_SIZE; i++)
- printk(KERN_INFO "rx_ring %d status: 0x%x\n", i,
- streamer_priv->streamer_rx_ring[i].status);
- break;
- case IOCTL_PRINT_TX_BUFS:
- printk(KERN_INFO "Print tx bufs:\n");
- for(i=0; i<STREAMER_TX_RING_SIZE; i++)
- printk(KERN_INFO "tx_ring %d status: 0x%x\n", i,
- streamer_priv->streamer_tx_ring[i].status);
- break;
- case IOCTL_RX_CMD:
- streamer_rx(dev);
- printk(KERN_INFO "Sent rx command.\n");
- break;
- default:
- printk(KERN_INFO "Bad ioctl!\n");
- }
- return 0;
-}
-#endif
-
static struct pci_driver streamer_pci_driver = {
.name = "lanstreamer",
.id_table = streamer_pci_tbl,
@@ -1999,7 +1939,7 @@ static struct pci_driver streamer_pci_driver = {
};
static int __init streamer_init_module(void) {
- return pci_module_init(&streamer_pci_driver);
+ return pci_register_driver(&streamer_pci_driver);
}
static void __exit streamer_cleanup_module(void) {
diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h
index 5557d8e1e22..e7bb3494afc 100644
--- a/drivers/net/tokenring/lanstreamer.h
+++ b/drivers/net/tokenring/lanstreamer.h
@@ -62,18 +62,6 @@
#include <linux/version.h>
-#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include <asm/ioctl.h>
-#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE
-#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1
-#define IOCTL_RX_CMD SIOCDEVPRIVATE+2
-#define IOCTL_TX_CMD SIOCDEVPRIVATE+3
-#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
-#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5
-#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6
-#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7
-#endif
-
/* MAX_INTR - the maximum number of times we can loop
* inside the interrupt function before returning
* control to the OS (maximum value is 256)
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 19e6f4dfd69..666bbaaae82 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -311,7 +311,7 @@ static int __devinit madgemc_probe(struct device *device)
*/
outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */
madgemc_setsifsel(dev, 1);
- if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ,
+ if (request_irq(dev->irq, madgemc_interrupt, IRQF_SHARED,
"madgemc", dev)) {
ret = -EBUSY;
goto getout3;
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index c3cb8d26cfe..85831484bc4 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -80,7 +80,6 @@
#define OLYMPIC_DEBUG 0
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -446,7 +445,7 @@ static int olympic_open(struct net_device *dev)
olympic_init(dev);
- if(request_irq(dev->irq, &olympic_interrupt, SA_SHIRQ , "olympic", dev)) {
+ if(request_irq(dev->irq, &olympic_interrupt, IRQF_SHARED , "olympic", dev)) {
return -EAGAIN;
}
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 67d2b596ce2..85a7f797d34 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -29,7 +29,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fcntl.h>
@@ -532,7 +531,7 @@ static int __init smctr_chk_mca(struct net_device *dev)
dev->irq = 15;
break;
}
- if (request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev)) {
+ if (request_irq(dev->irq, smctr_interrupt, IRQF_SHARED, smctr_name, dev)) {
release_region(dev->base_addr, SMCTR_IO_EXTENT);
return -ENODEV;
}
@@ -1062,7 +1061,7 @@ static int __init smctr_chk_isa(struct net_device *dev)
goto out2;
}
- if (request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev))
+ if (request_irq(dev->irq, smctr_interrupt, IRQF_SHARED, smctr_name, dev))
goto out2;
/* Get 58x Rom Base */
@@ -5667,7 +5666,7 @@ module_param_array(io, int, NULL, 0);
module_param_array(irq, int, NULL, 0);
module_param(ringspeed, int, 0);
-static struct net_device *setup_card(int n)
+static struct net_device * __init setup_card(int n)
{
struct net_device *dev = alloc_trdev(sizeof(struct net_local));
int err;
@@ -5697,9 +5696,8 @@ out:
free_netdev(dev);
return ERR_PTR(err);
}
-
-int init_module(void)
+int __init init_module(void)
{
int i, found = 0;
struct net_device *dev;
diff --git a/drivers/net/tokenring/smctr_firmware.h b/drivers/net/tokenring/smctr_firmware.h
index 48994b043b7..292e50ddf01 100644
--- a/drivers/net/tokenring/smctr_firmware.h
+++ b/drivers/net/tokenring/smctr_firmware.h
@@ -17,7 +17,6 @@
* - Jay Schulist <jschlst@samba.org>
*/
-#include <linux/config.h>
#if defined(CONFIG_SMCTR) || defined(CONFIG_SMCTR_MODULE)
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index ab47c0547a3..7d3e270c4f4 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -122,7 +122,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
goto err_out_trdev;
}
- ret = request_irq(pdev->irq, tms380tr_interrupt, SA_SHIRQ,
+ ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED,
dev->name, dev);
if (ret)
goto err_out_region;
diff --git a/drivers/net/tulip/21142.c b/drivers/net/tulip/21142.c
index 683f14b01c0..fa3a2bb105a 100644
--- a/drivers/net/tulip/21142.c
+++ b/drivers/net/tulip/21142.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/21142.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
@@ -26,9 +26,9 @@ static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
of available transceivers. */
-void t21142_timer(unsigned long data)
+void t21142_media_task(void *data)
{
- struct net_device *dev = (struct net_device *)data;
+ struct net_device *dev = data;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
int csr12 = ioread32(ioaddr + CSR12);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index 5f743b97294..e1b48bd8664 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -31,7 +31,6 @@
#define DRV_VERSION "0.7"
#define DRV_RELDATE "Mar 17, 2004"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
@@ -1372,7 +1371,7 @@ static int de_open (struct net_device *dev)
dw32(IntrMask, 0);
- rc = request_irq(dev->irq, de_interrupt, SA_SHIRQ, dev->name, dev);
+ rc = request_irq(dev->irq, de_interrupt, IRQF_SHARED, dev->name, dev);
if (rc) {
printk(KERN_ERR "%s: IRQ %d request failure, err=%d\n",
dev->name, dev->irq, rc);
@@ -1671,7 +1670,7 @@ static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs,
spin_unlock_irq(&de->lock);
}
-static struct ethtool_ops de_ethtool_ops = {
+static const struct ethtool_ops de_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_tx_csum = ethtool_op_get_tx_csum,
.get_sg = ethtool_op_get_sg,
@@ -2007,8 +2006,8 @@ static int __init de_init_one (struct pci_dev *pdev,
}
if (pci_resource_len(pdev, 1) < DE_REGS_SIZE) {
rc = -EIO;
- printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
- pci_resource_len(pdev, 1), pci_name(pdev));
+ printk(KERN_ERR PFX "MMIO resource (%llx) too small on pci dev %s\n",
+ (unsigned long long)pci_resource_len(pdev, 1), pci_name(pdev));
goto err_out_res;
}
@@ -2016,8 +2015,9 @@ static int __init de_init_one (struct pci_dev *pdev,
regs = ioremap_nocache(pciaddr, DE_REGS_SIZE);
if (!regs) {
rc = -EIO;
- printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
- pci_resource_len(pdev, 1), pciaddr, pci_name(pdev));
+ printk(KERN_ERR PFX "Cannot map PCI MMIO (%llx@%lx) on pci dev %s\n",
+ (unsigned long long)pci_resource_len(pdev, 1),
+ pciaddr, pci_name(pdev));
goto err_out_res;
}
dev->base_addr = (unsigned long) regs;
@@ -2138,17 +2138,21 @@ static int de_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
struct de_private *de = dev->priv;
+ int retval = 0;
rtnl_lock();
if (netif_device_present(dev))
goto out;
- if (netif_running(dev)) {
- pci_enable_device(pdev);
- de_init_hw(de);
- netif_device_attach(dev);
- } else {
- netif_device_attach(dev);
+ if (!netif_running(dev))
+ goto out_attach;
+ if ((retval = pci_enable_device(pdev))) {
+ printk (KERN_ERR "%s: pci_enable_device failed in resume\n",
+ dev->name);
+ goto out;
}
+ de_init_hw(de);
+out_attach:
+ netif_device_attach(dev);
out:
rtnl_unlock();
return 0;
@@ -2172,7 +2176,7 @@ static int __init de_init (void)
#ifdef MODULE
printk("%s", version);
#endif
- return pci_module_init (&de_driver);
+ return pci_register_driver(&de_driver);
}
static void __exit de_exit (void)
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index da8bd0d62a3..fb5fa7d6888 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -292,7 +292,7 @@
0.41 21-Mar-96 Don't check for get_hw_addr checksum unless DEC card
only <niles@axp745gsfc.nasa.gov>
Fix for multiple PCI cards reported by <jos@xos.nl>
- Duh, put the SA_SHIRQ flag into request_interrupt().
+ Duh, put the IRQF_SHARED flag into request_interrupt().
Fix SMC ethernet address in enet_det[].
Print chip name instead of "UNKNOWN" during boot.
0.42 26-Apr-96 Fix MII write TA bit error.
@@ -353,7 +353,7 @@
infoblocks.
Added DC21142 and DC21143 functions.
Added byte counters from <phil@tazenda.demon.co.uk>
- Added SA_INTERRUPT temporary fix from
+ Added IRQF_DISABLED temporary fix from
<mjacob@feral.com>.
0.53 12-Nov-97 Fix the *_probe() to include 'eth??' name during
module load: bug reported by
@@ -443,7 +443,6 @@
=========================================================================
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -1320,10 +1319,10 @@ de4x5_open(struct net_device *dev)
lp->state = OPEN;
de4x5_dbg_open(dev);
- if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ,
+ if (request_irq(dev->irq, (void *)de4x5_interrupt, IRQF_SHARED,
lp->adapter_name, dev)) {
printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
- if (request_irq(dev->irq, de4x5_interrupt, SA_INTERRUPT | SA_SHIRQ,
+ if (request_irq(dev->irq, de4x5_interrupt, IRQF_DISABLED | IRQF_SHARED,
lp->adapter_name, dev)) {
printk("\n Cannot get IRQ- reconfigure your hardware.\n");
disable_ast(dev);
@@ -2115,6 +2114,7 @@ static struct eisa_device_id de4x5_eisa_ids[] = {
{ "DEC4250", 0 }, /* 0 is the board name index... */
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
static struct eisa_driver de4x5_eisa_driver = {
.id_table = de4x5_eisa_ids,
@@ -5755,7 +5755,7 @@ static int __init de4x5_module_init (void)
int err = 0;
#ifdef CONFIG_PCI
- err = pci_module_init (&de4x5_pci_driver);
+ err = pci_register_driver(&de4x5_pci_driver);
#endif
#ifdef CONFIG_EISA
err |= eisa_driver_register (&de4x5_eisa_driver);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index ba5b112093f..ccf2c225f08 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -298,7 +298,7 @@ static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *);
static int dmfe_stop(struct DEVICE *);
static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
static void dmfe_set_filter_mode(struct DEVICE *);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long ,int);
static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -506,7 +506,7 @@ static int dmfe_open(struct DEVICE *dev)
DMFE_DBUG(0, "dmfe_open", 0);
- ret = request_irq(dev->irq, &dmfe_interrupt, SA_SHIRQ, dev->name, dev);
+ ret = request_irq(dev->irq, &dmfe_interrupt, IRQF_SHARED, dev->name, dev);
if (ret)
return ret;
@@ -1048,7 +1048,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
dev->base_addr, dev->irq);
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
@@ -2039,7 +2039,7 @@ static int __init dmfe_init_module(void)
if (HPNA_NoiseFloor > 15)
HPNA_NoiseFloor = 0;
- rc = pci_module_init(&dmfe_driver);
+ rc = pci_register_driver(&dmfe_driver);
if (rc < 0)
return rc;
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index 5ffbd5b300c..206918bad53 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/eeprom.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index da4f7593c50..7f8f5d42a76 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/interrupt.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
@@ -16,7 +16,6 @@
#include <linux/pci.h>
#include "tulip.h"
-#include <linux/config.h>
#include <linux/etherdevice.h>
int tulip_rx_copybreak;
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index e9bc2a958c1..20bd52b8699 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/media.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c
index ca7e53246ad..85a521e0d05 100644
--- a/drivers/net/tulip/pnic.c
+++ b/drivers/net/tulip/pnic.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/pnic.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c
index ab985023fcc..c31be0e377a 100644
--- a/drivers/net/tulip/pnic2.c
+++ b/drivers/net/tulip/pnic2.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/pnic2.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
Modified to hep support PNIC_II by Kevin B. Hendricks
diff --git a/drivers/net/tulip/timer.c b/drivers/net/tulip/timer.c
index e058a9fbfe8..066e5d6bcbd 100644
--- a/drivers/net/tulip/timer.c
+++ b/drivers/net/tulip/timer.c
@@ -1,7 +1,7 @@
/*
drivers/net/tulip/timer.c
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
@@ -18,13 +18,14 @@
#include "tulip.h"
-void tulip_timer(unsigned long data)
+void tulip_media_task(void *data)
{
- struct net_device *dev = (struct net_device *)data;
+ struct net_device *dev = data;
struct tulip_private *tp = netdev_priv(dev);
void __iomem *ioaddr = tp->base_addr;
u32 csr12 = ioread32(ioaddr + CSR12);
int next_tick = 2*HZ;
+ unsigned long flags;
if (tulip_debug > 2) {
printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
@@ -126,6 +127,15 @@ void tulip_timer(unsigned long data)
}
break;
}
+
+
+ spin_lock_irqsave(&tp->lock, flags);
+ if (tp->timeout_recovery) {
+ tulip_tx_timeout_complete(tp, ioaddr);
+ tp->timeout_recovery = 0;
+ }
+ spin_unlock_irqrestore(&tp->lock, flags);
+
/* mod_timer synchronizes us with potential add_timer calls
* from interrupts.
*/
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index d25020da679..25668ddb1f7 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -16,7 +16,6 @@
#ifndef __NET_TULIP_H__
#define __NET_TULIP_H__
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
@@ -31,11 +30,10 @@
/* undefine, or define to various debugging levels (>4 == obscene levels) */
#define TULIP_DEBUG 1
-/* undefine USE_IO_OPS for MMIO, define for PIO */
#ifdef CONFIG_TULIP_MMIO
-# undef USE_IO_OPS
+#define TULIP_BAR 1 /* CBMA */
#else
-# define USE_IO_OPS 1
+#define TULIP_BAR 0 /* CBIO */
#endif
@@ -45,7 +43,8 @@ struct tulip_chip_table {
int io_size;
int valid_intrs; /* CSR7 interrupt enable settings */
int flags;
- void (*media_timer) (unsigned long data);
+ void (*media_timer) (unsigned long);
+ void (*media_task) (void *);
};
@@ -143,6 +142,7 @@ enum status_bits {
RxNoBuf = 0x80,
RxIntr = 0x40,
TxFIFOUnderflow = 0x20,
+ RxErrIntr = 0x10,
TxJabber = 0x08,
TxNoBuf = 0x04,
TxDied = 0x02,
@@ -193,9 +193,14 @@ struct tulip_tx_desc {
enum desc_status_bits {
- DescOwned = 0x80000000,
- RxDescFatalErr = 0x8000,
- RxWholePkt = 0x0300,
+ DescOwned = 0x80000000,
+ DescWholePkt = 0x60000000,
+ DescEndPkt = 0x40000000,
+ DescStartPkt = 0x20000000,
+ DescEndRing = 0x02000000,
+ DescUseLink = 0x01000000,
+ RxDescFatalErr = 0x008000,
+ RxWholePkt = 0x00000300,
};
@@ -367,6 +372,7 @@ struct tulip_private {
unsigned int medialock:1; /* Don't sense media type. */
unsigned int mediasense:1; /* Media sensing in progress. */
unsigned int nway:1, nwayset:1; /* 21143 internal NWay. */
+ unsigned int timeout_recovery:1;
unsigned int csr0; /* CSR0 setting. */
unsigned int csr6; /* Current CSR6 control settings. */
unsigned char eeprom[EEPROM_SIZE]; /* Serial EEPROM contents. */
@@ -385,6 +391,7 @@ struct tulip_private {
void __iomem *base_addr;
int csr12_shadow;
int pad0; /* Used for 8-byte alignment */
+ struct work_struct media_work;
};
@@ -399,7 +406,7 @@ struct eeprom_fixup {
/* 21142.c */
extern u16 t21142_csr14[];
-void t21142_timer(unsigned long data);
+void t21142_media_task(void *data);
void t21142_start_nway(struct net_device *dev);
void t21142_lnk_change(struct net_device *dev, int csr5);
@@ -437,7 +444,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5);
void pnic_timer(unsigned long data);
/* timer.c */
-void tulip_timer(unsigned long data);
+void tulip_media_task(void *data);
void mxic_timer(unsigned long data);
void comet_timer(unsigned long data);
@@ -486,4 +493,14 @@ static inline void tulip_restart_rxtx(struct tulip_private *tp)
tulip_start_rxtx(tp);
}
+static inline void tulip_tx_timeout_complete(struct tulip_private *tp, void __iomem *ioaddr)
+{
+ /* Stop and restart the chip's Tx processes. */
+ tulip_restart_rxtx(tp);
+ /* Trigger an immediate transmit demand. */
+ iowrite32(0, ioaddr + CSR1);
+
+ tp->stats.tx_errors++;
+}
+
#endif /* __NET_TULIP_H__ */
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index cabdf894e21..831919a8191 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1,7 +1,7 @@
/* tulip_core.c: A DEC 21x4x-family ethernet driver for Linux. */
/*
- Maintained by Jeff Garzik <jgarzik@pobox.com>
+ Maintained by Valerie Henson <val_henson@linux.intel.com>
Copyright 2000,2001 The Linux Kernel Team
Written/copyright 1994-2001 by Donald Becker.
@@ -14,13 +14,12 @@
*/
-#include <linux/config.h>
#define DRV_NAME "tulip"
#ifdef CONFIG_TULIP_NAPI
-#define DRV_VERSION "1.1.13-NAPI" /* Keep at least for test */
+#define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */
#else
-#define DRV_VERSION "1.1.13"
+#define DRV_VERSION "1.1.14"
#endif
#define DRV_RELDATE "May 11, 2002"
@@ -131,7 +130,14 @@ int tulip_debug = TULIP_DEBUG;
int tulip_debug = 1;
#endif
+static void tulip_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ struct tulip_private *tp = netdev_priv(dev);
+ if (netif_running(dev))
+ schedule_work(&tp->media_work);
+}
/*
* This table use during operation for capabilities and media timer.
@@ -145,59 +151,60 @@ struct tulip_chip_table tulip_tbl[] = {
/* DC21140 */
{ "Digital DS21140 Tulip", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer },
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_PCI_MWI, tulip_timer,
+ tulip_media_task },
/* DC21142, DC21143 */
- { "Digital DS21143 Tulip", 128, 0x0801fbff,
+ { "Digital DS21142/43 Tulip", 128, 0x0801fbff,
HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI | HAS_NWAY
- | HAS_INTR_MITIGATION | HAS_PCI_MWI, t21142_timer },
+ | HAS_INTR_MITIGATION | HAS_PCI_MWI, tulip_timer, t21142_media_task },
/* LC82C168 */
{ "Lite-On 82c168 PNIC", 256, 0x0001fbef,
- HAS_MII | HAS_PNICNWAY, pnic_timer },
+ HAS_MII | HAS_PNICNWAY, pnic_timer, },
/* MX98713 */
{ "Macronix 98713 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer, },
/* MX98715 */
{ "Macronix 98715 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
+ HAS_MEDIA_TABLE, mxic_timer, },
/* MX98725 */
{ "Macronix 98725 PMAC", 256, 0x0001ebef,
- HAS_MEDIA_TABLE, mxic_timer },
+ HAS_MEDIA_TABLE, mxic_timer, },
/* AX88140 */
{ "ASIX AX88140", 128, 0x0001fbff,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY
- | IS_ASIX, tulip_timer },
+ | IS_ASIX, tulip_timer, tulip_media_task },
/* PNIC2 */
{ "Lite-On PNIC-II", 256, 0x0801fbff,
- HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer },
+ HAS_MII | HAS_NWAY | HAS_8023X | HAS_PCI_MWI, pnic2_timer, },
/* COMET */
{ "ADMtek Comet", 256, 0x0001abef,
- HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer },
+ HAS_MII | MC_HASH_ONLY | COMET_MAC_ADDR, comet_timer, },
/* COMPEX9881 */
{ "Compex 9881 PMAC", 128, 0x0001ebef,
- HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+ HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer, },
/* I21145 */
{ "Intel DS21145 Tulip", 128, 0x0801fbff,
HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_ACPI
- | HAS_NWAY | HAS_PCI_MWI, t21142_timer },
+ | HAS_NWAY | HAS_PCI_MWI, tulip_timer, tulip_media_task },
/* DM910X */
{ "Davicom DM9102/DM9102A", 128, 0x0001ebef,
HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | HAS_ACPI,
- tulip_timer },
+ tulip_timer, tulip_media_task },
/* RS7112 */
{ "Conexant LANfinity", 256, 0x0001ebef,
- HAS_MII | HAS_ACPI, tulip_timer },
+ HAS_MII | HAS_ACPI, tulip_timer, tulip_media_task },
};
@@ -296,12 +303,14 @@ static void tulip_up(struct net_device *dev)
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
iowrite32(0x00000001, ioaddr + CSR0);
+ pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
udelay(100);
/* Deassert reset.
Wait the specified 50 PCI cycles after a reset by initializing
Tx and Rx queues and the address filter list. */
iowrite32(tp->csr0, ioaddr + CSR0);
+ pci_read_config_dword(tp->pdev, PCI_COMMAND, &i); /* flush write */
udelay(100);
if (tulip_debug > 1)
@@ -490,7 +499,7 @@ tulip_open(struct net_device *dev)
{
int retval;
- if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev)))
+ if ((retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev)))
return retval;
tulip_init_ring (dev);
@@ -523,20 +532,9 @@ static void tulip_tx_timeout(struct net_device *dev)
"SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
dev->name, ioread32(ioaddr + CSR5), ioread32(ioaddr + CSR12),
ioread32(ioaddr + CSR13), ioread32(ioaddr + CSR14), ioread32(ioaddr + CSR15));
- if ( ! tp->medialock && tp->mtable) {
- do
- --tp->cur_index;
- while (tp->cur_index >= 0
- && (tulip_media_cap[tp->mtable->mleaf[tp->cur_index].media]
- & MediaIsFD));
- if (--tp->cur_index < 0) {
- /* We start again, but should instead look for default. */
- tp->cur_index = tp->mtable->leafcount - 1;
- }
- tulip_select_media(dev, 0);
- printk(KERN_WARNING "%s: transmit timed out, switching to %s "
- "media.\n", dev->name, medianame[dev->if_port]);
- }
+ tp->timeout_recovery = 1;
+ schedule_work(&tp->media_work);
+ goto out_unlock;
} else if (tp->chip_id == PNIC2) {
printk(KERN_WARNING "%s: PNIC2 transmit timed out, status %8.8x, "
"CSR6/7 %8.8x / %8.8x CSR12 %8.8x, resetting...\n",
@@ -576,14 +574,9 @@ static void tulip_tx_timeout(struct net_device *dev)
}
#endif
- /* Stop and restart the chip's Tx processes . */
-
- tulip_restart_rxtx(tp);
- /* Trigger an immediate transmit demand. */
- iowrite32(0, ioaddr + CSR1);
-
- tp->stats.tx_errors++;
+ tulip_tx_timeout_complete(tp, ioaddr);
+out_unlock:
spin_unlock_irqrestore (&tp->lock, flags);
dev->trans_start = jiffies;
netif_wake_queue (dev);
@@ -733,6 +726,8 @@ static void tulip_down (struct net_device *dev)
void __iomem *ioaddr = tp->base_addr;
unsigned long flags;
+ flush_scheduled_work();
+
del_timer_sync (&tp->timer);
#ifdef CONFIG_TULIP_NAPI
del_timer_sync (&tp->oom_timer);
@@ -842,7 +837,7 @@ static void tulip_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *in
strcpy(info->bus_info, pci_name(np->pdev));
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = tulip_get_drvinfo
};
@@ -1024,8 +1019,6 @@ static void set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
tp->csr6 |= AcceptAllMulticast | AcceptAllPhys;
csr6 |= AcceptAllMulticast | AcceptAllPhys;
- /* Unconditionally log net taps. */
- printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
} else if ((dev->mc_count > 1000) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter well -- accept all multicasts. */
tp->csr6 |= AcceptAllMulticast;
@@ -1350,10 +1343,10 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
- printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
+ printk (KERN_ERR PFX "%s: I/O region (0x%llx@0x%llx) too small, "
"aborting\n", pci_name(pdev),
- pci_resource_len (pdev, 0),
- pci_resource_start (pdev, 0));
+ (unsigned long long)pci_resource_len (pdev, 0),
+ (unsigned long long)pci_resource_start (pdev, 0));
goto err_out_free_netdev;
}
@@ -1362,11 +1355,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (pci_request_regions (pdev, "tulip"))
goto err_out_free_netdev;
-#ifndef USE_IO_OPS
- ioaddr = pci_iomap(pdev, 1, tulip_tbl[chip_idx].io_size);
-#else
- ioaddr = pci_iomap(pdev, 0, tulip_tbl[chip_idx].io_size);
-#endif
+ ioaddr = pci_iomap(pdev, TULIP_BAR, tulip_tbl[chip_idx].io_size);
+
if (!ioaddr)
goto err_out_free_res;
@@ -1399,6 +1389,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
tp->timer.data = (unsigned long)dev;
tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+ INIT_WORK(&tp->media_work, tulip_tbl[tp->chip_id].media_task, dev);
+
dev->base_addr = (unsigned long)ioaddr;
#ifdef CONFIG_TULIP_MWI
@@ -1550,10 +1542,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
dev->dev_addr[i] = last_phys_addr[i];
dev->dev_addr[i] = last_phys_addr[i] + 1;
#if defined(__sparc__)
- if ((pcp != NULL) && prom_getproplen(pcp->prom_node,
- "local-mac-address") == 6) {
- prom_getproperty(pcp->prom_node, "local-mac-address",
- dev->dev_addr, 6);
+ if (pcp) {
+ unsigned char *addr;
+ int len;
+
+ addr = of_get_property(pcp->prom_node,
+ "local-mac-address", &len);
+ if (addr && len == 6)
+ memcpy(dev->dev_addr, addr, 6);
}
#endif
#if defined(__i386__) || defined(__x86_64__) /* Patch up x86 BIOS bug. */
@@ -1641,8 +1637,14 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
if (register_netdev(dev))
goto err_out_free_ring;
- printk(KERN_INFO "%s: %s rev %d at %p,",
- dev->name, chip_name, chip_rev, ioaddr);
+ printk(KERN_INFO "%s: %s rev %d at "
+#ifdef CONFIG_TULIP_MMIO
+ "MMIO"
+#else
+ "Port"
+#endif
+ " %#llx,", dev->name, chip_name, chip_rev,
+ (unsigned long long) pci_resource_start(pdev, TULIP_BAR));
pci_set_drvdata(pdev, dev);
if (eeprom_missing)
@@ -1765,9 +1767,12 @@ static int tulip_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
+ if ((retval = pci_enable_device(pdev))) {
+ printk (KERN_ERR "tulip: pci_enable_device failed in resume\n");
+ return retval;
+ }
- if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
+ if ((retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev))) {
printk (KERN_ERR "tulip: request_irq failed in resume\n");
return retval;
}
@@ -1846,7 +1851,7 @@ static int __init tulip_init (void)
tulip_max_interrupt_work = max_interrupt_work;
/* probe for and init boards */
- return pci_module_init (&tulip_driver);
+ return pci_register_driver(&tulip_driver);
}
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 8b3a28f53c3..0b176be51eb 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -222,7 +222,7 @@ static int uli526x_start_xmit(struct sk_buff *, struct net_device *);
static int uli526x_stop(struct net_device *);
static struct net_device_stats * uli526x_get_stats(struct net_device *);
static void uli526x_set_filter_mode(struct net_device *);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long, int);
static irqreturn_t uli526x_interrupt(int, void *, struct pt_regs *);
static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
@@ -436,7 +436,7 @@ static int uli526x_open(struct net_device *dev)
ULI526X_DBUG(0, "uli526x_open", 0);
- ret = request_irq(dev->irq, &uli526x_interrupt, SA_SHIRQ, dev->name, dev);
+ ret = request_irq(dev->irq, &uli526x_interrupt, IRQF_SHARED, dev->name, dev);
if (ret)
return ret;
@@ -985,7 +985,7 @@ static void uli526x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
wol->wolopts = 0;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.get_link = netdev_get_link,
@@ -1702,7 +1702,6 @@ MODULE_PARM_DESC(mode, "ULi M5261/M5263: Bit 0: 10/100Mbps, bit 2: duplex, bit 8
static int __init uli526x_init_module(void)
{
- int rc;
printk(version);
printed_version = 1;
@@ -1714,22 +1713,19 @@ static int __init uli526x_init_module(void)
if (cr6set)
uli526x_cr6_user_set = cr6set;
- switch(mode) {
+ switch (mode) {
case ULI526X_10MHF:
case ULI526X_100MHF:
case ULI526X_10MFD:
case ULI526X_100MFD:
uli526x_media_mode = mode;
break;
- default:uli526x_media_mode = ULI526X_AUTO;
+ default:
+ uli526x_media_mode = ULI526X_AUTO;
break;
}
- rc = pci_module_init(&uli526x_driver);
- if (rc < 0)
- return rc;
-
- return 0;
+ return pci_register_driver(&uli526x_driver);
}
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 8fea2aa455d..2fca1ee24f5 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -45,8 +45,8 @@
*/
#define DRV_NAME "winbond-840"
-#define DRV_VERSION "1.01-d"
-#define DRV_RELDATE "Nov-17-2001"
+#define DRV_VERSION "1.01-e"
+#define DRV_RELDATE "Sep-11-2006"
/* Automatically extracted configuration info:
@@ -90,10 +90,8 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
Making the Tx ring too large decreases the effectiveness of channel
bonding and packet priority.
There are no ill effects from too-large receive rings. */
-#define TX_RING_SIZE 16
#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
#define TX_QUEUE_LEN_RESTART 5
-#define RX_RING_SIZE 32
#define TX_BUFLIMIT (1024-128)
@@ -137,8 +135,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <asm/io.h>
#include <asm/irq.h>
+#include "tulip.h"
+
/* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static char version[] =
KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE " Donald Becker <becker@scyld.com>\n"
KERN_INFO " http://www.scyld.com/network/drivers.html\n";
@@ -212,53 +212,38 @@ Test with 'ping -s 10000' on a fast computer.
/*
PCI probe table.
*/
-enum pci_id_flags_bits {
- /* Set PCI command register bits before calling probe1(). */
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- /* Read and map the single following PCI BAR. */
- PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
- PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
-};
enum chip_capability_flags {
- CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,};
-#ifdef USE_IO_OPS
-#define W840_FLAGS (PCI_USES_IO | PCI_ADDR0 | PCI_USES_MASTER)
-#else
-#define W840_FLAGS (PCI_USES_MEM | PCI_ADDR1 | PCI_USES_MASTER)
-#endif
+ CanHaveMII=1, HasBrokenTx=2, AlwaysFDX=4, FDXOnNoMII=8,
+};
-static struct pci_device_id w840_pci_tbl[] = {
+static const struct pci_device_id w840_pci_tbl[] = {
{ 0x1050, 0x0840, PCI_ANY_ID, 0x8153, 0, 0, 0 },
{ 0x1050, 0x0840, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
{ 0x11f6, 0x2011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
- { 0, }
+ { }
};
MODULE_DEVICE_TABLE(pci, w840_pci_tbl);
+enum {
+ netdev_res_size = 128, /* size of PCI BAR resource */
+};
+
struct pci_id_info {
const char *name;
- struct match_info {
- int pci, pci_mask, subsystem, subsystem_mask;
- int revision, revision_mask; /* Only 8 bits. */
- } id;
- enum pci_id_flags_bits pci_flags;
- int io_size; /* Needed for I/O region check or ioremap(). */
- int drv_flags; /* Driver use, intended as capability flags. */
+ int drv_flags; /* Driver use, intended as capability flags. */
};
-static struct pci_id_info pci_id_tbl[] = {
- {"Winbond W89c840", /* Sometime a Level-One switch card. */
- { 0x08401050, 0xffffffff, 0x81530000, 0xffff0000 },
- W840_FLAGS, 128, CanHaveMII | HasBrokenTx | FDXOnNoMII},
- {"Winbond W89c840", { 0x08401050, 0xffffffff, },
- W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
- {"Compex RL100-ATX", { 0x201111F6, 0xffffffff,},
- W840_FLAGS, 128, CanHaveMII | HasBrokenTx},
- {NULL,}, /* 0 terminated list. */
+
+static const struct pci_id_info pci_id_tbl[] __devinitdata = {
+ { /* Sometime a Level-One switch card. */
+ "Winbond W89c840", CanHaveMII | HasBrokenTx | FDXOnNoMII},
+ { "Winbond W89c840", CanHaveMII | HasBrokenTx},
+ { "Compex RL100-ATX", CanHaveMII | HasBrokenTx},
+ { } /* terminate list. */
};
/* This driver was written to use PCI memory space, however some x86 systems
- work only with I/O space accesses. Pass -DUSE_IO_OPS to use PCI I/O space
- accesses instead of memory space. */
+ work only with I/O space accesses. See CONFIG_TULIP_MMIO in .config
+*/
/* Offsets to the Command and Status Registers, "CSRs".
While similar to the Tulip, these registers are longword aligned.
@@ -276,21 +261,11 @@ enum w840_offsets {
CurTxDescAddr=0x4C, CurTxBufAddr=0x50,
};
-/* Bits in the interrupt status/enable registers. */
-/* The bits in the Intr Status/Enable registers, mostly interrupt sources. */
-enum intr_status_bits {
- NormalIntr=0x10000, AbnormalIntr=0x8000,
- IntrPCIErr=0x2000, TimerInt=0x800,
- IntrRxDied=0x100, RxNoBuf=0x80, IntrRxDone=0x40,
- TxFIFOUnderflow=0x20, RxErrIntr=0x10,
- TxIdle=0x04, IntrTxStopped=0x02, IntrTxDone=0x01,
-};
-
/* Bits in the NetworkConfig register. */
enum rx_mode_bits {
- AcceptErr=0x80, AcceptRunt=0x40,
- AcceptBroadcast=0x20, AcceptMulticast=0x10,
- AcceptAllPhys=0x08, AcceptMyPhys=0x02,
+ AcceptErr=0x80,
+ RxAcceptBroadcast=0x20, AcceptMulticast=0x10,
+ RxAcceptAllPhys=0x08, AcceptMyPhys=0x02,
};
enum mii_reg_bits {
@@ -312,13 +287,6 @@ struct w840_tx_desc {
u32 buffer1, buffer2;
};
-/* Bits in network_desc.status */
-enum desc_status_bits {
- DescOwn=0x80000000, DescEndRing=0x02000000, DescUseLink=0x01000000,
- DescWholePkt=0x60000000, DescStartPkt=0x20000000, DescEndPkt=0x40000000,
- DescIntr=0x80000000,
-};
-
#define MII_CNT 1 /* winbond only supports one MII */
struct netdev_private {
struct w840_rx_desc *rx_ring;
@@ -371,7 +339,7 @@ static u32 __set_rx_mode(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static struct net_device_stats *get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static int netdev_close(struct net_device *dev);
@@ -386,7 +354,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
int irq;
int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0;
void __iomem *ioaddr;
- int bar = 1;
i = pci_enable_device(pdev);
if (i) return i;
@@ -408,10 +375,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
if (pci_request_regions(pdev, DRV_NAME))
goto err_out_netdev;
-#ifdef USE_IO_OPS
- bar = 0;
-#endif
- ioaddr = pci_iomap(pdev, bar, pci_id_tbl[chip_idx].io_size);
+
+ ioaddr = pci_iomap(pdev, TULIP_BAR, netdev_res_size);
if (!ioaddr)
goto err_out_free_res;
@@ -670,7 +635,7 @@ static int netdev_open(struct net_device *dev)
iowrite32(0x00000001, ioaddr + PCIBusCfg); /* Reset */
netif_device_detach(dev);
- i = request_irq(dev->irq, &intr_handler, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &intr_handler, IRQF_SHARED, dev->name, dev);
if (i)
goto out_err;
@@ -853,7 +818,7 @@ static void init_rxtx_rings(struct net_device *dev)
np->rx_buf_sz,PCI_DMA_FROMDEVICE);
np->rx_ring[i].buffer1 = np->rx_addr[i];
- np->rx_ring[i].status = DescOwn;
+ np->rx_ring[i].status = DescOwned;
}
np->cur_rx = 0;
@@ -938,7 +903,7 @@ static void init_registers(struct net_device *dev)
}
#elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
i |= 0xE000;
-#elif defined(__sparc__)
+#elif defined(__sparc__) || defined (CONFIG_PARISC)
i |= 0x4800;
#else
#warning Processor architecture undefined
@@ -1058,11 +1023,11 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
/* Now acquire the irq spinlock.
* The difficult race is the the ordering between
- * increasing np->cur_tx and setting DescOwn:
+ * increasing np->cur_tx and setting DescOwned:
* - if np->cur_tx is increased first the interrupt
* handler could consider the packet as transmitted
- * since DescOwn is cleared.
- * - If DescOwn is set first the NIC could report the
+ * since DescOwned is cleared.
+ * - If DescOwned is set first the NIC could report the
* packet as sent, but the interrupt handler would ignore it
* since the np->cur_tx was not yet increased.
*/
@@ -1070,7 +1035,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
np->cur_tx++;
wmb(); /* flush length, buffer1, buffer2 */
- np->tx_ring[entry].status = DescOwn;
+ np->tx_ring[entry].status = DescOwned;
wmb(); /* flush status and kick the hardware */
iowrite32(0, np->base_addr + TxStartDemand);
np->tx_q_bytes += skb->len;
@@ -1170,12 +1135,12 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
handled = 1;
- if (intr_status & (IntrRxDone | RxNoBuf))
+ if (intr_status & (RxIntr | RxNoBuf))
netdev_rx(dev);
if (intr_status & RxNoBuf)
iowrite32(0, ioaddr + RxStartDemand);
- if (intr_status & (TxIdle | IntrTxDone) &&
+ if (intr_status & (TxNoBuf | TxIntr) &&
np->cur_tx != np->dirty_tx) {
spin_lock(&np->lock);
netdev_tx_done(dev);
@@ -1183,8 +1148,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs
}
/* Abnormal error summary/uncommon events handlers. */
- if (intr_status & (AbnormalIntr | TxFIFOUnderflow | IntrPCIErr |
- TimerInt | IntrTxStopped))
+ if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError |
+ TimerInt | TxDied))
netdev_error(dev, intr_status);
if (--work_limit < 0) {
@@ -1320,7 +1285,7 @@ static int netdev_rx(struct net_device *dev)
np->rx_ring[entry].buffer1 = np->rx_addr[entry];
}
wmb();
- np->rx_ring[entry].status = DescOwn;
+ np->rx_ring[entry].status = DescOwned;
}
return 0;
@@ -1357,7 +1322,7 @@ static void netdev_error(struct net_device *dev, int intr_status)
dev->name, new);
update_csr6(dev, new);
}
- if (intr_status & IntrRxDied) { /* Missed a Rx frame. */
+ if (intr_status & RxDied) { /* Missed a Rx frame. */
np->stats.rx_errors++;
}
if (intr_status & TimerInt) {
@@ -1393,16 +1358,14 @@ static u32 __set_rx_mode(struct net_device *dev)
u32 rx_mode;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
memset(mc_filter, 0xff, sizeof(mc_filter));
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptAllPhys
+ rx_mode = RxAcceptBroadcast | AcceptMulticast | RxAcceptAllPhys
| AcceptMyPhys;
} else if ((dev->mc_count > multicast_filter_limit)
|| (dev->flags & IFF_ALLMULTI)) {
/* Too many to match, or accept all multicasts. */
memset(mc_filter, 0xff, sizeof(mc_filter));
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
} else {
struct dev_mc_list *mclist;
int i;
@@ -1413,7 +1376,7 @@ static u32 __set_rx_mode(struct net_device *dev)
filterbit &= 0x3f;
mc_filter[filterbit >> 5] |= 1 << (filterbit & 31);
}
- rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ rx_mode = RxAcceptBroadcast | AcceptMulticast | AcceptMyPhys;
}
iowrite32(mc_filter[0], ioaddr + MulticastFilter0);
iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
@@ -1484,7 +1447,7 @@ static void netdev_set_msglevel(struct net_device *dev, u32 value)
debug = value;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.set_settings = netdev_set_settings,
@@ -1639,7 +1602,7 @@ static int w840_suspend (struct pci_dev *pdev, pm_message_t state)
synchronize_irq(dev->irq);
netif_tx_disable(dev);
-
+
np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
/* no more hardware accesses behind this line. */
@@ -1661,14 +1624,18 @@ static int w840_resume (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata (pdev);
struct netdev_private *np = netdev_priv(dev);
+ int retval = 0;
rtnl_lock();
if (netif_device_present(dev))
goto out; /* device not suspended */
if (netif_running(dev)) {
- pci_enable_device(pdev);
- /* pci_power_on(pdev); */
-
+ if ((retval = pci_enable_device(pdev))) {
+ printk (KERN_ERR
+ "%s: pci_enable_device failed in resume\n",
+ dev->name);
+ goto out;
+ }
spin_lock_irq(&np->lock);
iowrite32(1, np->base_addr+PCIBusCfg);
ioread32(np->base_addr+PCIBusCfg);
@@ -1686,7 +1653,7 @@ static int w840_resume (struct pci_dev *pdev)
}
out:
rtnl_unlock();
- return 0;
+ return retval;
}
#endif
@@ -1704,7 +1671,7 @@ static struct pci_driver w840_driver = {
static int __init w840_init(void)
{
printk(version);
- return pci_module_init(&w840_driver);
+ return pci_register_driver(&w840_driver);
}
static void __exit w840_exit(void)
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 63c2175ed13..629eac64528 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -190,7 +190,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
strcpy(info->bus_info, pci_name(private->pdev));
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
@@ -457,7 +457,7 @@ static int xircom_open(struct net_device *dev)
int retval;
enter("xircom_open");
printk(KERN_INFO "xircom cardbus adaptor found, registering as %s, using irq %i \n",dev->name,dev->irq);
- retval = request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev);
+ retval = request_irq(dev->irq, &xircom_interrupt, IRQF_SHARED, dev->name, dev);
if (retval) {
leave("xircom_open - No IRQ");
return retval;
@@ -1264,8 +1264,7 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p
static int __init xircom_init(void)
{
- pci_register_driver(&xircom_ops);
- return 0;
+ return pci_register_driver(&xircom_ops);
}
static void __exit xircom_exit(void)
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index 887d7245fe7..312788caa4c 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -10,26 +10,11 @@
410 Severn Ave., Suite 210
Annapolis MD 21403
- -----------------------------------------------------------
-
- Linux kernel-specific changes:
-
- LK1.0 (Ion Badulescu)
- - Major cleanup
- - Use 2.4 PCI API
- - Support ethtool
- - Rewrite perfect filter/hash code
- - Use interrupts for media changes
-
- LK1.1 (Ion Badulescu)
- - Disallow negotiation of unsupported full-duplex modes
*/
#define DRV_NAME "xircom_tulip_cb"
-#define DRV_VERSION "0.91+LK1.1"
-#define DRV_RELDATE "October 11, 2001"
-
-#define CARDBUS 1
+#define DRV_VERSION "0.92"
+#define DRV_RELDATE "June 27, 2006"
/* A few user-configurable values. */
@@ -98,7 +83,6 @@ static int csr0 = 0x00A00000 | 0x4800;
/* PCI registers */
#define PCI_POWERMGMT 0x40
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -307,10 +291,10 @@ struct xircom_private {
struct xircom_tx_desc tx_ring[TX_RING_SIZE];
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
-#ifdef CARDBUS
+
/* The X3201-3 requires 4-byte aligned tx bufs */
struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
-#endif
+
/* The addresses of receive-in-place skbuffs. */
struct sk_buff* rx_skbuff[RX_RING_SIZE];
u16 setup_frame[PKT_SETUP_SZ / sizeof(u16)]; /* Pseudo-Tx frame to init address table. */
@@ -350,7 +334,7 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev);
static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
static void check_duplex(struct net_device *dev);
-static struct ethtool_ops ops;
+static const struct ethtool_ops ops;
/* The Xircom cards are picky about when certain bits in CSR6 can be
@@ -808,7 +792,7 @@ xircom_open(struct net_device *dev)
{
struct xircom_private *tp = netdev_priv(dev);
- if (request_irq(dev->irq, &xircom_interrupt, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, &xircom_interrupt, IRQF_SHARED, dev->name, dev))
return -EAGAIN;
xircom_up(dev);
@@ -909,10 +893,8 @@ static void xircom_init_ring(struct net_device *dev)
tp->tx_skbuff[i] = NULL;
tp->tx_ring[i].status = 0;
tp->tx_ring[i].buffer2 = virt_to_bus(&tp->tx_ring[i+1]);
-#ifdef CARDBUS
if (tp->chip_id == X3201_3)
tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
-#endif /* CARDBUS */
}
tp->tx_ring[i-1].buffer2 = virt_to_bus(&tp->tx_ring[0]);
}
@@ -932,12 +914,10 @@ xircom_start_xmit(struct sk_buff *skb, struct net_device *dev)
entry = tp->cur_tx % TX_RING_SIZE;
tp->tx_skbuff[entry] = skb;
-#ifdef CARDBUS
if (tp->chip_id == X3201_3) {
memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
tp->tx_ring[entry].buffer1 = virt_to_bus(tp->tx_aligned_skbuff[entry]->data);
} else
-#endif
tp->tx_ring[entry].buffer1 = virt_to_bus(skb->data);
if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
@@ -1450,7 +1430,7 @@ static void xircom_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
strcpy(info->bus_info, pci_name(tp->pdev));
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_settings = xircom_get_settings,
.set_settings = xircom_set_settings,
.get_drvinfo = xircom_get_drvinfo,
@@ -1727,7 +1707,7 @@ static int __init xircom_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&xircom_driver);
+ return pci_register_driver(&xircom_driver);
}
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 6c62d5c8826..de8da6dee1b 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -39,7 +39,6 @@
#define DRV_DESCRIPTION "Universal TUN/TAP device driver"
#define DRV_COPYRIGHT "(C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
@@ -70,7 +69,7 @@ static int debug;
/* Network device part of the driver */
static LIST_HEAD(tun_dev_list);
-static struct ethtool_ops tun_ethtool_ops;
+static const struct ethtool_ops tun_ethtool_ops;
/* Net device open. */
static int tun_net_open(struct net_device *dev)
@@ -178,7 +177,7 @@ static struct net_device_stats *tun_net_stats(struct net_device *dev)
static void tun_net_init(struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
-
+
switch (tun->flags & TUN_TYPE_MASK) {
case TUN_TUN_DEV:
/* Point-to-Point TUN Device */
@@ -187,7 +186,7 @@ static void tun_net_init(struct net_device *dev)
dev->mtu = 1500;
/* Zero header length */
- dev->type = ARPHRD_NONE;
+ dev->type = ARPHRD_NONE;
dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
break;
@@ -207,7 +206,7 @@ static void tun_net_init(struct net_device *dev)
/* Poll */
static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
-{
+{
struct tun_struct *tun = file->private_data;
unsigned int mask = POLLOUT | POLLWRNORM;
@@ -217,7 +216,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
poll_wait(file, &tun->read_wait, wait);
-
+
if (!skb_queue_empty(&tun->readq))
mask |= POLLIN | POLLRDNORM;
@@ -241,7 +240,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV)
align = NET_IP_ALIGN;
-
+
if (!(skb = alloc_skb(len + align, GFP_KERNEL))) {
tun->stats.rx_dropped++;
return -ENOMEM;
@@ -268,29 +267,29 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv,
if (tun->flags & TUN_NOCHECKSUM)
skb->ip_summed = CHECKSUM_UNNECESSARY;
-
+
netif_rx_ni(skb);
tun->dev->last_rx = jiffies;
-
+
tun->stats.rx_packets++;
tun->stats.rx_bytes += len;
return count;
-}
+}
static inline size_t iov_total(const struct iovec *iv, unsigned long count)
{
unsigned long i;
size_t len;
- for (i = 0, len = 0; i < count; i++)
+ for (i = 0, len = 0; i < count; i++)
len += iv[i].iov_len;
return len;
}
/* Writev */
-static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
+static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
unsigned long count, loff_t *pos)
{
struct tun_struct *tun = file->private_data;
@@ -304,7 +303,7 @@ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
}
/* Write */
-static ssize_t tun_chr_write(struct file * file, const char __user * buf,
+static ssize_t tun_chr_write(struct file * file, const char __user * buf,
size_t count, loff_t *pos)
{
struct iovec iv = { (void __user *) buf, count };
@@ -327,11 +326,11 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
/* Packet will be striped */
pi.flags |= TUN_PKT_STRIP;
}
-
+
if (memcpy_toiovec(iv, (void *) &pi, sizeof(pi)))
return -EFAULT;
total += sizeof(pi);
- }
+ }
len = min_t(int, skb->len, len);
@@ -428,7 +427,7 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
}
/* Read */
-static ssize_t tun_chr_read(struct file * file, char __user * buf,
+static ssize_t tun_chr_read(struct file * file, char __user * buf,
size_t count, loff_t *pos)
{
struct iovec iv = { buf, count };
@@ -481,8 +480,8 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
if (tun->owner != -1 &&
current->euid != tun->owner && !capable(CAP_NET_ADMIN))
return -EPERM;
- }
- else if (__dev_get_by_name(ifr->ifr_name))
+ }
+ else if (__dev_get_by_name(ifr->ifr_name))
return -EINVAL;
else {
char *name;
@@ -502,9 +501,9 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
/* TAP device */
flags |= TUN_TAP_DEV;
name = "tap%d";
- } else
+ } else
goto failed;
-
+
if (*ifr->ifr_name)
name = ifr->ifr_name;
@@ -534,7 +533,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
err = register_netdevice(tun->dev);
if (err < 0)
goto err_free_dev;
-
+
list_add(&tun->list, &tun_dev_list);
}
@@ -558,7 +557,7 @@ static int tun_set_iff(struct file *file, struct ifreq *ifr)
return err;
}
-static int tun_chr_ioctl(struct inode *inode, struct file *file,
+static int tun_chr_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct tun_struct *tun = file->private_data;
@@ -712,14 +711,14 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
DBG(KERN_INFO "%s: tun_chr_fasync %d\n", tun->dev->name, on);
if ((ret = fasync_helper(fd, file, on, &tun->fasync)) < 0)
- return ret;
-
+ return ret;
+
if (on) {
ret = f_setown(file, current->pid, 0);
if (ret)
return ret;
tun->flags |= TUN_FASYNC;
- } else
+ } else
tun->flags &= ~TUN_FASYNC;
return 0;
@@ -763,7 +762,7 @@ static int tun_chr_close(struct inode *inode, struct file *file)
}
static struct file_operations tun_fops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.read = tun_chr_read,
.readv = tun_chr_readv,
@@ -773,14 +772,13 @@ static struct file_operations tun_fops = {
.ioctl = tun_chr_ioctl,
.open = tun_chr_open,
.release = tun_chr_close,
- .fasync = tun_chr_fasync
+ .fasync = tun_chr_fasync
};
static struct miscdevice tun_miscdev = {
.minor = TUN_MINOR,
.name = "tun",
.fops = &tun_fops,
- .devfs_name = "net/tun",
};
/* ethtool interface */
@@ -858,7 +856,7 @@ static int tun_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
-static struct ethtool_ops tun_ethtool_ops = {
+static const struct ethtool_ops tun_ethtool_ops = {
.get_settings = tun_get_settings,
.get_drvinfo = tun_get_drvinfo,
.get_msglevel = tun_get_msglevel,
@@ -885,7 +883,7 @@ static void tun_cleanup(void)
{
struct tun_struct *tun, *nxt;
- misc_deregister(&tun_miscdev);
+ misc_deregister(&tun_miscdev);
rtnl_lock();
list_for_each_entry_safe(tun, nxt, &tun_dev_list, list) {
@@ -893,7 +891,7 @@ static void tun_cleanup(void)
unregister_netdevice(tun->dev);
}
rtnl_unlock();
-
+
}
module_init(tun_init);
diff --git a/drivers/net/typhoon-firmware.h b/drivers/net/typhoon-firmware.h
index 2bf47d93b78..182d69e99fc 100644
--- a/drivers/net/typhoon-firmware.h
+++ b/drivers/net/typhoon-firmware.h
@@ -1,5 +1,5 @@
/*
- * Copyright 1999-2004 3Com Corporation. All Rights Reserved.
+ * Copyright 1999-2004 3Com Corporation. All Rights Reserved.
*
* Redistribution and use in source and binary forms of the 3c990img.h
* microcode software are permitted provided that the following conditions
@@ -29,3750 +29,3750 @@
* (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
* EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
* COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
- */
+ */
/* ver 03.001.008 */
static const u8 typhoon_firmware_image[] = {
-0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00,
-0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0xb1, 0xd4,
-0x4c, 0xb8, 0xd0, 0x4b, 0x32, 0x02, 0xd4, 0xee, 0x73, 0x7e, 0x0b, 0x13,
-0x9b, 0xc0, 0xae, 0xf4, 0x40, 0x01, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea,
-0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
-0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc5, 0x14, 0x00, 0xea,
-0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1,
-0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
-0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1,
-0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 0x00, 0xa0, 0xa0, 0xe1,
-0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0xa8, 0x10, 0x9f, 0xe5,
-0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5,
-0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe3,
-0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x6c, 0xd0, 0x9f, 0xe5, 0x9b, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5,
-0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb,
-0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
-0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 0x54, 0x10, 0x9f, 0xe5,
-0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1,
-0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb,
-0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea,
-0x15, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00,
-0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
-0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80,
-0xad, 0xde, 0xad, 0xde, 0xb0, 0xbb, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40,
-0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xbd, 0xba, 0x21, 0x40,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x58, 0x57, 0x00, 0x00, 0x86, 0x4b, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff,
-0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4d, 0x00, 0x24, 0x28, 0x68, 0x00, 0x28,
-0x1e, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x7b, 0xfd, 0x29, 0x68,
-0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x15, 0xd0, 0x38, 0x01, 0x0d, 0x49,
-0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29,
-0x0c, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x28, 0x68, 0xc1, 0x69, 0xc0, 0x46,
-0x29, 0x60, 0x39, 0x07, 0x41, 0x60, 0x04, 0x62, 0xc7, 0x62, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0xe8, 0x17, 0x00, 0x80,
-0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68,
-0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47,
-0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
-0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0x00, 0x10, 0xa0, 0xe1,
-0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
-0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
-0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x80, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
-0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3,
-0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 0x00, 0xf0, 0x21, 0xe1,
-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x91, 0x00, 0x00, 0xe0,
-0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0,
-0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3,
-0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63,
-0x04, 0x49, 0x05, 0xf0, 0x01, 0xfb, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00,
-0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2,
-0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc,
-0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 0xbb, 0x42, 0x05, 0xd2,
-0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 0xc8, 0x63, 0xf1, 0xe7,
-0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x04, 0x48, 0xc1, 0x6b,
-0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
-0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 0x0b, 0xd2, 0xb9, 0x6e,
-0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2,
-0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62,
-0x38, 0x6b, 0x02, 0xf0, 0x2d, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xe8, 0xfa,
-0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49,
-0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18,
-0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
-0xa4, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 0xc0, 0x6d, 0x02, 0x23,
-0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 0x03, 0xd0, 0xd1, 0x63,
-0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 0x07, 0x68, 0x7b, 0x1c,
-0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 0xf3, 0xe7, 0x00, 0x00,
-0xa4, 0x2a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xe0, 0x01, 0x00, 0x80,
-0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 0x10, 0x18, 0x0a, 0x04,
-0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 0x01, 0x0c, 0x05, 0xd0,
-0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 0x01, 0x0c, 0xf9, 0xd1,
-0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 0x00, 0x22, 0x00, 0x29,
-0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f,
-0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b,
-0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 0x00, 0x88, 0x00, 0x06,
-0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c,
-0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c,
-0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 0xc7, 0x89, 0xfb, 0x18,
-0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 0x40, 0x7a, 0x00, 0x02,
-0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 0x00, 0x0c, 0x3b, 0x0c,
-0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 0x11, 0x1c, 0xff, 0xf7,
-0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xff, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 0x82, 0x68, 0x1a, 0x40,
-0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 0x93, 0x69, 0x01, 0x33,
-0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 0x00, 0x68, 0x1c, 0x18,
-0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43,
-0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 0x82, 0x68, 0x1a, 0x40,
-0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 0x52, 0x09, 0x0e, 0xd3,
-0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 0xcb, 0x68, 0x02, 0x68,
-0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68,
-0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x80, 0x23,
-0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 0x15, 0xd0, 0x4a, 0x68,
-0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 0x01, 0x33, 0xd3, 0x61,
-0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a,
-0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 0x00, 0x28, 0x00, 0xd1,
-0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 0x38, 0x69, 0xb9, 0x68,
-0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 0xc0, 0x43, 0x01, 0x04,
-0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x04, 0x1c, 0xb8, 0x68,
-0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 0x0c, 0xd2, 0x2a, 0x68,
-0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x05, 0xf9, 0xc0, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x26, 0xff, 0x04, 0x1c,
-0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 0x1a, 0xd3, 0xb8, 0x6a,
-0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 0xed, 0xf8, 0xc0, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 0x20, 0x23, 0xb9, 0x69,
-0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x07, 0xe0,
-0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x41, 0x6a,
-0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x41, 0x09,
-0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
-0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x53, 0xf8, 0x01, 0x1c,
-0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69,
-0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0,
-0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0xc1, 0x6a,
-0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x81, 0x09,
-0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
-0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 0x40, 0x18, 0x01, 0x23,
-0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 0x05, 0x04, 0x2d, 0x0c,
-0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0x28,
-0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 0x98, 0x42, 0x07, 0xd0,
-0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x60, 0x6b, 0x01, 0x30,
-0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 0xb8, 0x69, 0x18, 0x43,
-0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 0x00, 0x20, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 0xe0, 0x6b, 0x61, 0x6c,
-0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 0x00, 0x20, 0x8a, 0x08,
-0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 0x9f, 0x58, 0x03, 0xae,
-0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 0xf7, 0xd8, 0x60, 0x6a,
-0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
-0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 0xff, 0xf7, 0x87, 0xfe,
-0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x6d, 0xfe,
-0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 0x61, 0x6a, 0x01, 0x23,
-0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x01, 0x91,
-0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 0x0c, 0xd2, 0xa2, 0x6a,
-0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x2f, 0xf8, 0xc0, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0x07, 0x1c,
-0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 0x08, 0x18, 0x69, 0x8a,
-0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 0xa1, 0x6c, 0x62, 0x6c,
-0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
-0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 0x05, 0xd0, 0x08, 0x04,
-0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 0xf9, 0xd1, 0x38, 0x1c,
-0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0xb0,
-0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb4, 0x00, 0x22,
-0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 0xdc, 0x00, 0x47, 0x18,
-0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 0xff, 0x00, 0x80, 0x08,
-0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 0x4d, 0x1e, 0x02, 0xc8,
-0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 0x09, 0xd0, 0x0c, 0x04,
-0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 0x02, 0xc8, 0x1c, 0x1c,
-0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 0x08, 0x1c, 0xf8, 0x40,
-0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 0x42, 0x18, 0x10, 0x0c,
-0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c,
-0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 0x42, 0x00, 0x12, 0x18,
-0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23,
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58,
-0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 0x01, 0x30, 0x04, 0x28,
-0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 0x09, 0x0b, 0x07, 0x48,
-0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 0x02, 0xd0, 0x38, 0x1c,
-0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0xa8, 0x03, 0x00, 0x80,
-0x00, 0x40, 0x14, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x98, 0xb4, 0x14, 0x4a,
-0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 0xc0, 0x58, 0x07, 0x03,
-0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 0x12, 0x0b, 0x11, 0x48,
-0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 0xe4, 0x58, 0x01, 0x23,
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 0xcc, 0x00, 0x01, 0x21,
-0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 0x98, 0x42, 0x03, 0xd9,
-0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 0x18, 0x1a, 0x84, 0x42,
-0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 0x55, 0x55, 0x55, 0x55,
-0x20, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x08, 0x04, 0x00, 0x80,
-0x18, 0x04, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 0x00, 0xd0, 0x01, 0x3a,
-0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 0xc0, 0x46, 0x3b, 0x60,
-0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 0x08, 0x32, 0x10, 0x4b,
-0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 0x12, 0x58, 0x0f, 0x4b,
-0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x1b, 0x68, 0x9b, 0x00,
-0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 0x0a, 0x48, 0xc1, 0x68,
-0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x08, 0x4b,
-0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 0x00, 0x20, 0xf6, 0xe7,
-0x08, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x80,
-0x18, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x10, 0x04, 0x00, 0x80,
-0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 0x01, 0xb6, 0xa0, 0xe3,
-0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 0x01, 0x7a, 0xa0, 0xe3,
-0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 0xc8, 0x60, 0x9f, 0xe5,
-0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 0x00, 0x00, 0x54, 0xe3,
-0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 0x11, 0x00, 0x00, 0x0a,
-0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x21, 0x00, 0x00, 0x0a,
-0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
-0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
-0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 0x02, 0x0a, 0x14, 0xe3,
-0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x02, 0x0a, 0xc0, 0xe3,
-0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x80, 0x85, 0xe5,
-0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
-0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
-0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x00, 0x1b,
-0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 0x02, 0x0b, 0x14, 0xe3,
-0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 0x20, 0x00, 0x00, 0x1b,
-0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x18, 0x00, 0x89, 0xe5,
-0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3,
-0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
-0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8,
-0x04, 0xf0, 0x5e, 0xe2, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
-0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 0x00, 0x20, 0xc3, 0xe1,
-0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x0c, 0x20, 0x81, 0xe5,
-0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0x18, 0x10, 0x9f, 0xe5,
-0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 0xb0, 0x24, 0xc1, 0xe1,
-0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 0x3c, 0x00, 0x81, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 0xff, 0xff, 0xff, 0xea,
-0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 0x01, 0x16, 0xa0, 0xe3,
-0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 0x24, 0x20, 0x91, 0xe5,
-0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20, 0x80, 0xe5,
-0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x80, 0xe5,
-0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 0x2c, 0x20, 0x80, 0xe5,
-0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11,
-0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x10, 0x81, 0xe2,
-0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 0x0b, 0x02, 0xa0, 0xe3,
-0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x04, 0x00, 0x80,
-0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5,
-0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2,
-0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1,
-0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3,
-0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5,
-0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0x00,
-0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
-0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2,
-0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0c, 0x10, 0xa0, 0xe3,
-0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5,
-0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5,
-0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3,
-0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x4c, 0x00, 0x1f, 0xe5,
-0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea,
-0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 0x01, 0x06, 0xa0, 0xe3,
-0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x21, 0x1f, 0xe5,
-0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0xe5,
-0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 0x01, 0x06, 0xa0, 0xe3,
-0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x92, 0xe5,
-0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1,
-0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x82, 0xe5,
-0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 0x0c, 0x00, 0x81, 0xe5,
-0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x81, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0,
-0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c,
-0x00, 0xf0, 0x92, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x00, 0x28,
-0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x84, 0xf8, 0x00, 0x20, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 0x3a, 0x78, 0xd2, 0x07,
-0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 0xff, 0x22, 0x01, 0x32,
-0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02,
-0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 0x5b, 0x02, 0x42, 0x68,
-0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 0x82, 0x60, 0x00, 0xe0,
-0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x08, 0x2a,
-0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
-0x0e, 0x31, 0x3c, 0xe0, 0xc1, 0x23, 0xdb, 0x00, 0x9a, 0x42, 0x03, 0xd1,
-0x41, 0x68, 0x24, 0x4b, 0x19, 0x43, 0x3e, 0xe0, 0x23, 0x4b, 0x9a, 0x42,
-0x04, 0xd1, 0x01, 0x23, 0x1b, 0x03, 0x41, 0x68, 0x19, 0x43, 0x36, 0xe0,
-0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
-0x12, 0x0c, 0x2e, 0x3a, 0x1c, 0x4b, 0x9a, 0x42, 0x2d, 0xd8, 0x01, 0x25,
-0x42, 0x68, 0x15, 0x43, 0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02,
-0x1a, 0x43, 0x18, 0x4b, 0x9a, 0x42, 0x22, 0xd1, 0xfb, 0x1d, 0x09, 0x33,
-0x44, 0xcb, 0x9b, 0x07, 0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33,
-0x9e, 0x40, 0x16, 0x43, 0x03, 0x2e, 0x18, 0xd1, 0x39, 0x7d, 0x7b, 0x7d,
-0x1b, 0x02, 0x19, 0x43, 0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43,
-0x41, 0x60, 0x81, 0x68, 0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x0a, 0xe0,
-0xc1, 0x23, 0xdb, 0x00, 0x99, 0x42, 0x04, 0xd1, 0x01, 0x21, 0x89, 0x03,
-0x29, 0x43, 0x41, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x00, 0x21, 0x08, 0x1c,
-0xf0, 0xbc, 0x70, 0x47, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x00, 0x00,
-0xae, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68,
-0xd1, 0x08, 0x3f, 0xd3, 0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39,
-0x8f, 0x78, 0x3f, 0x07, 0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d,
-0x0d, 0x32, 0xc2, 0x60, 0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60,
-0x08, 0x23, 0x1a, 0x43, 0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f,
-0x92, 0x00, 0x02, 0x61, 0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43,
-0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
-0x12, 0x0c, 0x42, 0x61, 0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76,
-0x80, 0xbc, 0x70, 0x47, 0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78,
-0x1b, 0x02, 0x1a, 0x43, 0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43,
-0x02, 0x60, 0xc9, 0x78, 0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47,
-0x80, 0xb5, 0x07, 0x1c, 0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a,
-0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43,
-0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42,
-0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46,
-0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xda, 0xf8, 0x38, 0x1c, 0x01, 0xf0,
-0x95, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49,
-0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18,
-0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7,
-0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80,
-0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x01, 0x23, 0x9b, 0x07,
-0x01, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02,
-0x12, 0x0e, 0x12, 0x06, 0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40,
-0x10, 0x43, 0x0a, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02,
-0x1b, 0x0a, 0x19, 0x40, 0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07,
-0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04,
-0x1a, 0x40, 0x11, 0x43, 0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43,
-0x00, 0x0e, 0x08, 0x43, 0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23,
-0x81, 0x6b, 0x19, 0x40, 0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d,
-0x39, 0x37, 0x39, 0x7b, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1,
-0x01, 0x6b, 0xc0, 0x46, 0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d,
-0x2d, 0x35, 0x00, 0x22, 0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50,
-0x01, 0x32, 0x07, 0x2a, 0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63,
-0x82, 0x6a, 0xc0, 0x46, 0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33,
-0x5a, 0x83, 0x40, 0x6a, 0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27,
-0x42, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1,
-0x42, 0x69, 0x00, 0x2a, 0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a,
-0x02, 0x29, 0x02, 0xd3, 0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0,
-0x13, 0xf8, 0x09, 0xe0, 0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61,
-0xc1, 0x60, 0x03, 0xe0, 0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61,
-0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7,
-0x6c, 0x06, 0x00, 0x80, 0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68,
-0x00, 0x2b, 0x34, 0xd0, 0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68,
-0x9b, 0x6a, 0xc0, 0x46, 0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19,
-0x7f, 0x02, 0x17, 0x4b, 0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63,
-0x07, 0x63, 0xcb, 0x1d, 0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69,
-0x00, 0x2b, 0x01, 0xd0, 0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61,
-0x0f, 0x1c, 0xc9, 0x68, 0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63,
-0xf8, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60,
-0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30,
-0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0xac, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31,
-0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32,
-0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18,
-0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a,
-0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38,
-0x92, 0x04, 0x92, 0x0c, 0x00, 0x26, 0x25, 0x4d,
-0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 0x04, 0xd0, 0x20, 0x8a,
-0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 0x01, 0x23, 0x9b, 0x07,
-0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30,
-0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c,
-0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c,
-0x02, 0xf0, 0x02, 0xf8, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23,
-0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
-0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8,
-0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43,
-0x20, 0x82, 0x21, 0x8a, 0x38, 0x1c, 0x00, 0xf0, 0xa2, 0xfb, 0xe8, 0x68,
-0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
-0xe8, 0x60, 0x30, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20,
-0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c,
-0xfc, 0x1d, 0xf9, 0x34, 0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35,
-0x38, 0x48, 0xc0, 0x6a, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18,
-0x01, 0x20, 0x80, 0x07, 0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
-0x00, 0x90, 0x01, 0x23, 0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43,
-0x00, 0x68, 0x38, 0x1c, 0x29, 0x1c, 0x00, 0xf0, 0xc2, 0xfa, 0xa8, 0x88,
-0x41, 0x07, 0x01, 0xd0, 0x00, 0x20, 0x51, 0xe0, 0x29, 0x89, 0x09, 0x18,
-0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18,
-0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a,
-0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0,
-0x33, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69,
-0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58,
-0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28,
-0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31,
-0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28,
-0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xae, 0xfb,
-0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b,
-0xff, 0xf7, 0xa6, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43,
-0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0x9e, 0xfb, 0xa1, 0x6b, 0x08, 0x4a,
-0x01, 0x20, 0xff, 0xf7, 0x99, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46,
-0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x4c, 0x2a, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00,
-0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a,
-0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48,
-0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00,
-0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d,
-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68,
-0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a,
-0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b,
-0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69,
-0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x26, 0xf9, 0x28, 0x6b, 0x79, 0x69,
-0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b,
-0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50,
-0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00,
-0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
-0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90,
-0x90, 0x49, 0x42, 0x00, 0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0,
-0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28,
-0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a,
-0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0,
-0x67, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98,
-0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28,
-0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a,
-0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60,
-0x62, 0xe0, 0x0a, 0x98, 0x02, 0x28, 0x5f, 0xd1, 0x09, 0x98, 0x40, 0x0c,
-0x73, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43,
-0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18,
-0x0c, 0x38, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x8a, 0x00, 0x6b, 0x4b,
-0xd6, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
-0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x00, 0x21, 0x83, 0x1e,
-0x0c, 0x93, 0x68, 0x4a, 0x16, 0x6b, 0xc0, 0x46, 0x0b, 0x96, 0x8a, 0x00,
-0x0c, 0x9b, 0x9b, 0x18, 0x0b, 0x9e, 0x9e, 0x19, 0x01, 0x23, 0x9b, 0x07,
-0x33, 0x43, 0x1b, 0x68, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x04, 0x29,
-0xf1, 0xd3, 0x69, 0x46, 0x8b, 0x1c, 0x07, 0x93, 0x00, 0x21, 0x08, 0x91,
-0x04, 0xae, 0x4a, 0x00, 0x07, 0x9b, 0x9b, 0x5a, 0xb2, 0x5a, 0x93, 0x42,
-0x11, 0xd0, 0x58, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xf8, 0x68,
-0x41, 0x1c, 0xf9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x20, 0x23,
-0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x80, 0x23, 0x18, 0x43, 0x38, 0x82,
-0x8f, 0xe7, 0x01, 0x31, 0x06, 0x29, 0xe4, 0xd3, 0x08, 0x99, 0x00, 0x29,
-0x0d, 0xd1, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0x04, 0xd1,
-0x39, 0x8a, 0x02, 0x23, 0x19, 0x43, 0x03, 0xe0, 0x0c, 0xe0, 0x39, 0x8a,
-0x08, 0x23, 0x19, 0x43, 0x39, 0x82, 0x29, 0x6b, 0x08, 0x18, 0x01, 0x23,
-0x9b, 0x07, 0x01, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x20, 0x76,
-0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x11, 0x30, 0x18, 0x43, 0x00, 0x68,
-0x01, 0x06, 0x09, 0x0e, 0x00, 0xe0, 0x19, 0xe0, 0x35, 0x48, 0x2a, 0x6b,
-0xc0, 0x46, 0xea, 0x62, 0x04, 0x29, 0x4f, 0xd1, 0x01, 0x21, 0xc6, 0x1d,
-0xff, 0x36, 0x5a, 0x36, 0x31, 0x72, 0x0a, 0x99, 0x02, 0x29, 0x1e, 0xd1,
-0x09, 0x99, 0x09, 0x0e, 0x49, 0x06, 0x1a, 0xd1, 0xe1, 0x1d, 0x05, 0x31,
-0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x39, 0x1a, 0xe0,
-0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68,
-0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04,
-0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1,
-0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d,
-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60,
-0xe8, 0x6a, 0xc0, 0x46, 0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x88, 0xfc,
-0x20, 0x7e, 0x33, 0x28, 0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21,
-0x14, 0x4c, 0xc0, 0x46, 0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0,
-0x85, 0xf8, 0x28, 0x6b, 0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c,
-0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20,
-0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1,
-0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd,
-0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x70, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00,
-0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80,
-0xac, 0xab, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80,
-0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48,
-0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31,
-0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22,
-0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46,
-0x9a, 0x61, 0xfa, 0x1d, 0xff, 0x32, 0x5a, 0x32, 0x13, 0x7a, 0x1b, 0x4a,
-0x00, 0x2b, 0x0b, 0xd0, 0x15, 0x8a, 0x2e, 0x0a, 0x36, 0x02, 0x33, 0x23,
-0x2b, 0x40, 0x9b, 0x00, 0x1e, 0x43, 0xcc, 0x23, 0x2b, 0x40, 0x9b, 0x08,
-0x33, 0x43, 0x13, 0x82, 0x12, 0x8a, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x83,
-0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46,
-0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46,
-0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a,
-0x01, 0xf0, 0x32, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30,
-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
-0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a,
-0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68,
-0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31,
-0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0,
-0x0f, 0xf8, 0x06, 0xe0, 0x32, 0x2b, 0x08, 0xd1, 0x8b, 0x70, 0x01, 0x1c,
-0x10, 0x1c, 0x00, 0xf0, 0x3c, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x20, 0x88, 0x70, 0xf9, 0xe7, 0x90, 0xb4, 0xca, 0x1d,
-0xf9, 0x32, 0x33, 0x27, 0xcc, 0x1d, 0xff, 0x34, 0x4a, 0x34, 0xd3, 0x6a,
-0xc0, 0x46, 0xa7, 0x70, 0xff, 0x31, 0x41, 0x31, 0x07, 0x6c, 0xc0, 0x46,
-0x4f, 0x61, 0xfb, 0x18, 0x39, 0x1c, 0x9f, 0x1e, 0x01, 0x23, 0x9b, 0x07,
-0xfc, 0x1c, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x9b, 0x00,
-0x1b, 0x04, 0x1b, 0x0c, 0xc9, 0x18, 0x08, 0x31, 0x01, 0x64, 0x01, 0x23,
-0x9b, 0x07, 0xb9, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x34, 0x30, 0x01, 0x76,
-0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d,
-0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43,
-0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32,
-0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d,
-0xff, 0x37, 0x4a, 0x37, 0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d,
-0xff, 0x34, 0x3a, 0x34, 0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30,
-0xe8, 0x60, 0x60, 0x69, 0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07,
-0x38, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43,
-0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63,
-0xf8, 0x1d, 0x03, 0x30, 0xff, 0xf7, 0xfc, 0xfb, 0x20, 0x62, 0xf8, 0x1d,
-0x07, 0x30, 0xff, 0xf7, 0xf7, 0xfb, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76,
-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98,
-0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
-0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40,
-0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c,
-0x80, 0x23, 0x23, 0x40, 0x01, 0x9f, 0xff, 0x37, 0x41, 0x37, 0x00, 0x2b,
-0x3c, 0xd0, 0x0c, 0x23, 0x00, 0x93, 0x00, 0x23, 0x9d, 0x00, 0xae, 0x18,
-0x36, 0x69, 0x6d, 0x18, 0x6e, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3,
-0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 0x76, 0x6a, 0x6d, 0x18, 0xae, 0x62,
-0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x01, 0x9b, 0xff, 0x33, 0x51, 0x33,
-0x9b, 0x78, 0x33, 0x2b, 0x0e, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
-0x01, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23,
-0x9b, 0x07, 0xc5, 0x1d, 0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x16, 0xe0,
-0x7b, 0x69, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
-0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x7d, 0x69, 0x5d, 0x1b, 0x01, 0x23,
-0x9b, 0x07, 0xc6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0xeb, 0x18,
-0x0c, 0x3b, 0x02, 0xe0, 0x00, 0x23, 0x00, 0x93, 0x4b, 0x81, 0xcb, 0x80,
-0x63, 0x09, 0x49, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xc4, 0x1d, 0x05, 0x34,
-0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x81, 0x01, 0x23, 0x9b, 0x07,
-0xc4, 0x1d, 0x0d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0x0c, 0x89, 0x1b, 0x1b,
-0x00, 0x9c, 0x1c, 0x1b, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43,
-0x00, 0x68, 0x20, 0x18, 0x88, 0x80, 0x38, 0x6a, 0x04, 0x0e, 0xff, 0x23,
-0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 0x1c, 0x43, 0xff, 0x23, 0x1b, 0x02,
-0x03, 0x40, 0x1b, 0x02, 0x23, 0x43, 0x00, 0x06, 0x18, 0x43, 0xc8, 0x60,
-0x78, 0x6a, 0x07, 0x0e, 0xff, 0x23, 0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a,
-0x1f, 0x43, 0xff, 0x23, 0x1b, 0x02, 0x03, 0x40, 0x1b, 0x02, 0x3b, 0x43,
-0x00, 0x06, 0x18, 0x43, 0x08, 0x61, 0xd0, 0x6b, 0xc0, 0x46, 0xc8, 0x63,
-0x90, 0x6b, 0xc0, 0x46, 0x08, 0x64, 0x50, 0x6c, 0xc0, 0x46, 0x48, 0x64,
-0x10, 0x6c, 0xc0, 0x46, 0x88, 0x64, 0xd0, 0x6c, 0xc0, 0x46, 0xc8, 0x64,
-0x90, 0x6c, 0xc0, 0x46, 0x08, 0x65, 0x02, 0xe0, 0x00, 0x23, 0x0b, 0x81,
-0x8b, 0x80, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0x0f, 0x4a, 0x93, 0x89, 0x01, 0x33, 0x93, 0x81, 0xc2, 0x1d, 0xf9, 0x32,
-0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61,
-0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b,
-0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83,
-0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xc2, 0xf8,
-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
-0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20,
-0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30,
-0x00, 0x29, 0x15, 0xd0, 0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25,
-0x0a, 0xe0, 0xff, 0xf7, 0x89, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a,
-0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0,
-0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69,
-0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0xa8, 0xfc,
-0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x5a, 0xf8,
-0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80,
-0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x01, 0x24,
-0x00, 0x25, 0x00, 0x28, 0x0b, 0xd1, 0x38, 0x6a, 0x00, 0x28, 0x03, 0xd1,
-0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1f, 0x48, 0x01, 0x6e,
-0x01, 0x31, 0x01, 0x66, 0x03, 0xe0, 0x48, 0x68, 0xc4, 0x23, 0x18, 0x40,
-0x03, 0xd1, 0x38, 0x6a, 0x00, 0xf0, 0x0c, 0xfc, 0x2f, 0xe0, 0x38, 0x1c,
-0x00, 0xf0, 0x1c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7b, 0xfa, 0xb8, 0x68,
-0xc0, 0x08, 0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd1, 0xfb, 0xb8, 0x68,
-0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60,
-0x10, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29,
-0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46,
-0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x14, 0xf8, 0x0b, 0xe0, 0x39, 0x6a,
-0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68,
-0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c,
-0xbd, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
-0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c,
-0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68,
-0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xc3, 0xfb, 0x00, 0x20,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00,
-0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36,
-0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 0x33, 0x4c, 0x34, 0x4b,
-0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x00, 0xf0,
-0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18,
-0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
-0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d,
-0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d,
-0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30,
-0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20,
-0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3,
-0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 0x09, 0x18, 0x78, 0x68,
-0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 0x61, 0x89, 0xe2, 0x88,
-0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x5a, 0xff,
-0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43,
-0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x52, 0xff, 0x01, 0x22, 0x52, 0x04,
-0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x4a, 0xff,
-0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 0x45, 0xff, 0x01, 0x20,
-0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 0xea, 0x1d, 0xf9, 0x32,
-0x51, 0x62, 0xd9, 0xe7, 0x28, 0xac, 0x20, 0x40, 0xff, 0xff, 0x00, 0x00,
-0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00,
-0x14, 0xac, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0,
-0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21,
-0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31,
-0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 0x00, 0x68, 0x03, 0xf0,
-0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34,
-0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 0x44, 0x4a, 0x92, 0x6a,
-0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xea, 0x1d,
-0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68,
-0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 0x3c, 0x4d, 0x01, 0x2b,
-0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68,
-0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 0xc5, 0xfc, 0x20, 0x78,
-0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20,
-0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30,
-0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20,
-0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 0x01, 0x30, 0x06, 0x28,
-0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 0x11, 0x0a, 0x29, 0xd3,
-0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50,
-0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19,
-0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00,
-0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 0x06, 0x29, 0xf8, 0xd3,
-0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 0x00, 0x9d, 0x55, 0x40,
-0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 0x89, 0x6a, 0x08, 0x18,
-0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 0x51, 0x40, 0x41, 0x65,
-0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 0x38, 0x1c,
-0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x08, 0x4a, 0x50, 0x68,
-0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xa4, 0xfa,
-0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 0x01, 0xf0, 0xde, 0xfa,
-0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x6c, 0x06, 0x00, 0x80,
-0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
-0xac, 0xab, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
-0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43,
-0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07,
-0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 0x43, 0x68, 0x1c, 0x04,
-0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 0x33, 0x43, 0x1b, 0x68,
-0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 0xff, 0x26, 0x36, 0x02,
-0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c,
-0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79,
-0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89,
-0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18,
-0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
-0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3,
-0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36,
-0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18,
-0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23,
-0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c,
-0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33,
-0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b,
-0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
-0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x64, 0xab, 0x0e,
-0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x3d, 0x34, 0x23, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
-0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x64, 0x01, 0x23,
-0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46,
-0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x41, 0x34, 0x23, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 0x0f, 0xe0, 0xfb, 0x1f,
-0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 0xff, 0x18, 0x03, 0x69,
-0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 0x2c, 0xe0, 0x00, 0x23,
-0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 0x8b, 0x80, 0x0b, 0x81,
-0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00,
-0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 0x00, 0x20, 0x87, 0x00,
-0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43,
-0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3,
-0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23,
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30,
-0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2,
-0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46,
-0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68,
-0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69,
-0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc,
-0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60,
-0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 0x01, 0x61, 0xf2, 0xe7,
-0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98,
-0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27,
-0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 0x00, 0x2b, 0x19, 0xd0,
-0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18,
-0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04,
-0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0,
-0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23,
-0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b,
-0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43,
-0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68,
-0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0,
-0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0,
-0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89,
-0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68,
-0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c,
-0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46,
-0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87,
-0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b,
-0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c,
-0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 0x07, 0x9b, 0x5b, 0x89,
-0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 0x07, 0x9b, 0x9b, 0x89,
-0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00,
-0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a,
-0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 0xc0, 0x46, 0xab, 0x83,
-0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23,
-0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07,
-0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31,
-0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42,
-0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x05, 0x9b,
-0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b,
-0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33,
-0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 0xbb, 0x08, 0x9b, 0x07,
-0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b,
-0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07,
-0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95,
-0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9d, 0xc0, 0x46,
-0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 0x1b, 0x02, 0x1d, 0x43,
-0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 0x2b, 0x43, 0x55, 0x00,
-0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b,
-0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e,
-0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f,
-0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40,
-0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c,
-0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78,
-0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3,
-0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00,
-0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33,
-0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93,
-0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35,
-0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68,
-0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0,
-0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1,
-0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46,
-0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b,
-0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46,
-0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61,
-0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83,
-0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68,
-0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68,
-0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48,
-0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0,
-0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98,
-0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xe1, 0xff, 0x68, 0x46,
-0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0,
-0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43,
-0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x84, 0xfe,
-0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
-0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46,
-0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68,
-0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68,
-0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69,
-0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28,
-0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7,
-0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60,
-0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22,
-0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 0x03, 0x23, 0xfc, 0x1d,
-0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68,
-0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68,
-0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62,
-0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60,
-0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64,
-0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
-0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
-0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23,
-0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0x20, 0x6b, 0x01, 0x30,
-0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69,
-0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29,
-0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c,
-0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe,
-0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29,
-0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0,
-0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46,
-0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31,
-0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1,
-0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 0x00, 0x28, 0x03, 0xd0,
-0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 0x30, 0x7b, 0x00, 0x28,
-0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 0x1b, 0x23, 0xdb, 0x01,
-0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 0xe0, 0x6a, 0xb0, 0x42,
-0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3,
-0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30,
-0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x90, 0xff,
-0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60,
-0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xe0, 0x6b,
-0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0x07, 0xfc, 0x02, 0x23,
-0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60,
-0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0x64, 0x2d, 0x00, 0x80,
-0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x1d, 0x48,
-0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 0x09, 0x31, 0x01, 0x27,
-0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 0xa3, 0x42, 0x10, 0xd0,
-0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 0x00, 0x2b, 0x0a, 0xd0,
-0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 0x13, 0x4b, 0xc0, 0x46,
-0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 0x93, 0x82, 0xc3, 0x8b,
-0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 0x0e, 0xdb, 0x84, 0x8a,
-0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 0x44, 0x8a, 0xc5, 0x8a,
-0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 0x4f, 0x70, 0x43, 0x82,
-0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 0x51, 0x82, 0x80, 0x8a,
-0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 0xe8, 0x0e, 0x00, 0x80,
-0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0,
-0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20,
-0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00,
-0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00,
-0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28,
-0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46,
-0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3,
-0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73,
-0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c,
-0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06,
-0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9,
-0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0,
-0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22,
-0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9,
-0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18,
-0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d,
-0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 0x08, 0xd0, 0x8b, 0x00,
-0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e,
-0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0,
-0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4,
-0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a,
-0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70,
-0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72,
-0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a,
-0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47,
-0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48,
-0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61,
-0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c,
-0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18,
-0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 0x61, 0xfe, 0x08, 0xbc,
-0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40,
-0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x95, 0x4a, 0xd0, 0x68,
-0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 0x38, 0x89, 0x00, 0x28,
-0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60,
-0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 0x8e, 0x48, 0xc3, 0x6b,
-0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xd4, 0x18,
-0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 0x81, 0x42, 0x05, 0xd1,
-0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf3, 0xe0,
-0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 0x01, 0x20, 0x00, 0x21,
-0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 0x58, 0x70, 0xb9, 0x82,
-0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x05, 0x93, 0x5b, 0x69,
-0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 0xc0, 0x46, 0x39, 0x61,
-0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c,
-0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 0x05, 0xd1, 0x3b, 0x2a,
-0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x73,
-0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x09, 0x04,
-0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 0x09, 0x06, 0x09, 0x0e,
-0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46,
-0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32,
-0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 0xb3, 0x07, 0x1a, 0x43,
-0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20,
-0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b,
-0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 0x01, 0x20, 0x09, 0x01,
-0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 0x65, 0xd1, 0x51, 0x49,
-0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 0x48, 0x69, 0x01, 0x30,
-0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
-0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 0x22, 0x6a, 0xa3, 0x6b,
-0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 0x22, 0x6b, 0xc0, 0x46,
-0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 0x00, 0x22, 0xfa, 0x61,
-0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 0x01, 0x22, 0x00, 0xe0,
-0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 0x7a, 0x68, 0xc0, 0x46,
-0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0xb0, 0x83,
-0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 0x60, 0x20, 0xb0, 0x83,
-0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 0x9a, 0x42, 0x03, 0xd8,
-0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 0x21, 0x6b, 0xc0, 0x46,
-0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 0x2d, 0x49, 0x78, 0x6b,
-0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 0xc0, 0x46, 0xfa, 0x60,
-0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 0xc0, 0x46, 0xb8, 0x61,
-0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 0x37, 0xf9, 0x04, 0x98,
-0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 0x78, 0x8a, 0xf1, 0x8b,
-0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 0x04, 0xe0, 0x38, 0xe0,
-0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 0x81, 0x07, 0x02, 0xd0,
-0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 0x09, 0x1a, 0xa2, 0x6b,
-0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 0x20, 0x62, 0xe8, 0x7b,
-0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 0x05, 0x99, 0x48, 0x69,
-0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 0x73, 0xfa, 0x18, 0x48,
-0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 0x0a, 0xd1, 0x20, 0x6a,
-0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 0x88, 0x42, 0x03, 0xd0,
-0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x40, 0x04,
-0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 0xe0, 0x68, 0x00, 0x28,
-0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 0xa8, 0x73, 0xed, 0xe7,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xa4, 0x2a, 0x00, 0x80,
-0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55,
-0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 0xc4, 0x0b, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89,
-0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c,
-0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2,
-0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31,
-0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b,
-0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0xb3, 0xf8, 0x01, 0x20,
-0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x18, 0x1a, 0x00, 0x80,
-0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c,
-0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89,
-0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7,
-0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 0x00, 0x09, 0x1f, 0xd3,
-0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a,
-0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
-0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
-0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0,
-0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 0x46, 0xe0, 0x01, 0x30,
-0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 0x5c, 0x18, 0xe4, 0x88,
-0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
-0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 0xd8, 0x42, 0xf0, 0xdc,
-0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 0x0b, 0x23, 0x1b, 0x02,
-0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x98,
-0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 0x9b, 0x01,
-0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 0x17, 0xd0, 0xfe, 0x1d,
-0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18,
-0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7b, 0xfc, 0x01, 0x28,
-0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 0x9b, 0x01,
-0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 0x01, 0x2a,
-0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0xf8, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
-0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89,
-0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08,
-0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 0x38, 0x1c, 0x00, 0xf0,
-0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c,
-0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47,
-0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04,
-0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29,
-0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c,
-0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0,
-0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91,
-0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab,
-0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43,
-0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69,
-0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b,
-0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a,
-0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26,
-0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0,
-0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0,
-0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42,
-0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a,
-0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68,
-0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c,
-0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c,
-0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c,
-0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 0x91, 0x42, 0x00, 0xdd,
-0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d,
-0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 0x33, 0x4a, 0xc0, 0x46,
-0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 0xe1, 0x6d, 0x41, 0x18,
-0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0,
-0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 0xb1, 0x6a, 0x81, 0x42,
-0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 0x2f, 0x23, 0x9b, 0x01,
-0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 0x92, 0x00, 0x27, 0x4b,
-0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 0x4a, 0x08, 0x05, 0xd3,
-0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd6, 0xff,
-0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x0b, 0x78, 0x00, 0x2b,
-0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 0x1e, 0x4a, 0xc0, 0x46,
-0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce,
-0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 0xc7, 0xfe, 0x14, 0x48,
-0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 0x00, 0xd3, 0x25, 0x60,
-0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 0x3a, 0x6b, 0xc0, 0x46,
-0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x68, 0x00, 0x29,
-0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0x04, 0xe0, 0x39, 0x6b,
-0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0xc1, 0x60,
-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00,
-0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
-0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02,
-0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35,
-0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 0x01, 0x38, 0x78, 0x61,
-0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0xb8, 0x60,
-0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa,
-0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71,
-0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1b, 0x00, 0x80,
-0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40,
-0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47,
-0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08,
-0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30,
-0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x23,
-0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 0x00, 0x68, 0x16, 0x4c,
-0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68,
-0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 0x00, 0xf0, 0x22, 0xf8,
-0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21,
-0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 0xf2, 0xd0, 0x51, 0x21,
-0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 0x02, 0xd1, 0x60, 0x6b,
-0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xf7, 0xe7,
-0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 0x01, 0x23, 0x9b, 0x07,
-0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c,
-0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00,
-0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 0x4b, 0x6b, 0x9a, 0x42,
-0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
-0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0,
-0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
-0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49,
-0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20,
-0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68,
-0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 0xdf, 0xfd, 0x88, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 0xf5, 0x2c, 0xff, 0xff,
-0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
-0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60,
-0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x4c, 0xfc,
-0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0,
-0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18,
-0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23,
-0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48,
-0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 0x35, 0x4d, 0x10, 0x29,
-0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e,
-0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x68, 0x6a,
-0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2,
-0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 0x68, 0x6a, 0xb8, 0x42,
-0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b,
-0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49,
-0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c,
-0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 0x09, 0x6e, 0x8c, 0x18,
-0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b,
-0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18,
-0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31,
-0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 0x52, 0x05, 0x3a, 0x43,
-0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18,
-0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 0x02, 0xf0, 0x4a, 0xfd,
-0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 0xe9, 0x6a, 0x2a, 0x6b,
-0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66,
-0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 0x68, 0x0e, 0x00, 0x80,
-0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x5d, 0x2e, 0xff, 0xff,
-0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40,
-0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 0xd1, 0x60, 0x02, 0x23,
-0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x90, 0xee, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x01, 0x20, 0x80, 0x02,
-0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23,
-0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c,
-0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 0x68, 0x46, 0x00, 0xf0,
-0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30,
-0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73,
-0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0,
-0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23,
-0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21,
-0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40,
-0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f,
-0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b,
-0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18,
-0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 0x04, 0x68, 0xc0, 0x46,
-0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46,
-0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0x08, 0x69,
-0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 0x38, 0x6a, 0xc0, 0x46,
-0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 0x18, 0x1c, 0x90, 0xbc,
-0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 0xc8, 0x69, 0x19, 0x23,
-0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b,
-0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 0xca, 0x61, 0x70, 0x47,
-0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 0x40, 0x32, 0x00, 0x29,
-0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0xd0, 0x61,
-0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68,
-0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69,
-0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00,
-0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21,
-0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a,
-0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23,
-0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07,
-0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0,
-0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 0x04, 0x29, 0xe4, 0xd3,
-0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0,
-0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a,
-0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40,
-0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 0xa3, 0x40, 0x00, 0x25,
-0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 0x5d, 0xd9, 0x1c, 0x1c,
-0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96,
-0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92,
-0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 0x05, 0x9c, 0xe3, 0x40,
-0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c,
-0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23,
-0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
-0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d,
-0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96,
-0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68,
-0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36,
-0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23,
-0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b,
-0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14,
-0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0,
-0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a,
-0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28,
-0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x2b, 0xf8, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f,
-0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3,
-0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0xde, 0xfe,
-0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20,
-0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28,
-0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60,
-0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28,
-0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28,
-0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7,
-0xb9, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3,
-0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79,
-0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x8c, 0x06, 0x00, 0x80,
-0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
-0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
-0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a,
-0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65,
-0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18,
-0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18,
-0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d,
-0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xfc, 0xf7, 0xca, 0xff,
-0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
-0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 0x01, 0xf0, 0xc6, 0xfb,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20,
-0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x59, 0xfc, 0x07, 0x1c,
-0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01,
-0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46,
-0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d,
-0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 0x89, 0xf9, 0x38, 0x1c,
-0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80,
-0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68,
-0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59,
-0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42,
-0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c,
-0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31,
-0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 0x5d, 0xfc, 0xf8, 0x6d,
-0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02,
-0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73,
-0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x4c, 0xfc, 0xb8, 0x6d, 0xc0, 0x46,
-0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2,
-0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xcc, 0xfc,
-0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0,
-0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64,
-0x20, 0x1c, 0xfc, 0xf7, 0x31, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43,
-0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c,
-0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07,
-0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68,
-0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31,
-0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19,
-0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18,
-0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42,
-0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a,
-0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
-0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
-0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0,
-0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62,
-0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c,
-0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0,
-0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18,
-0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9,
-0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
-0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 0x82, 0x42, 0xf3, 0xd8,
-0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40,
-0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68,
-0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x78, 0x6c,
-0xfc, 0xf7, 0x95, 0xff, 0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c,
-0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04,
-0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
-0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
-0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c,
-0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68,
-0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0,
-0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7,
-0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69,
-0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40,
-0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68,
-0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c,
-0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c,
-0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c,
-0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 0x7d, 0x4e, 0x0b, 0x23,
-0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25,
-0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 0x00, 0x28, 0x12, 0xd0,
-0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x68,
-0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 0x01, 0x35, 0xa8, 0x00,
-0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x68, 0x00, 0x28,
-0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68,
-0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c,
-0x28, 0x1c, 0xfc, 0xf7, 0x10, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e,
-0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18,
-0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88,
-0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04,
-0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
-0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
-0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89,
-0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61,
-0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46,
-0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60,
-0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 0xe8, 0xfe, 0x38, 0x86,
-0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 0x03, 0xff, 0x78, 0x86,
-0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 0xc8, 0xfe, 0x00, 0x90,
-0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04,
-0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02,
-0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42,
-0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02,
-0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c,
-0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xa3, 0xfe,
-0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 0x9e, 0xfe, 0x06, 0x1c,
-0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c,
-0xfc, 0xf7, 0x8f, 0xfe, 0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61,
-0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22,
-0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02,
-0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c,
-0xfc, 0xf7, 0x77, 0xfe, 0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61,
-0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69,
-0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7,
-0x66, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08,
-0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04,
-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46,
-0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c,
-0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81,
-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69,
-0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98,
-0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18,
-0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1,
-0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61,
-0x04, 0x98, 0xfc, 0xf7, 0x09, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69,
-0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42,
-0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a,
-0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62,
-0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1,
-0x38, 0x1c, 0xfc, 0xf7, 0x19, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60,
-0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68,
-0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c,
-0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68,
-0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c,
-0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98,
-0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e,
-0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
-0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x20, 0x8e,
-0xfc, 0xf7, 0xcb, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 0x02, 0x99, 0xfc, 0xf7,
-0xc6, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02,
-0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46,
-0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xb7, 0xfd, 0x61, 0x69, 0x01, 0x31,
-0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e,
-0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
-0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
-0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x71, 0x60, 0x03, 0x98,
-0xfc, 0xf7, 0x9b, 0xfd, 0x21, 0x69, 0x49, 0x19, 0x21, 0x61, 0xa1, 0x68,
-0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43,
-0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x8d, 0xfd, 0x38, 0x82, 0x61, 0x6e,
-0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99,
-0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d,
-0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38,
-0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68,
-0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04,
-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46,
-0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
-0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04,
-0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x51, 0xfd, 0x40, 0xc7, 0x02, 0x9a,
-0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29,
-0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c,
-0x16, 0x1c, 0xfc, 0xf7, 0x40, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e,
-0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32,
-0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0,
-0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5,
-0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b,
-0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99,
-0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0,
-0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91,
-0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42,
-0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a,
-0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88,
-0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21,
-0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06,
-0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1,
-0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a,
-0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c,
-0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 0x07, 0x9b, 0x01, 0xf0,
-0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0,
-0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8,
-0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90,
-0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60,
-0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 0x01, 0x98, 0x01, 0x38,
-0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 0x44, 0x63, 0x01, 0x98,
-0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0,
-0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92,
-0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x09, 0x9b, 0x01, 0xf0,
-0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02,
-0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07,
-0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0x85, 0xfc,
-0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68,
-0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 0x8b, 0xf9, 0x38, 0x1c,
-0xfc, 0xf7, 0x8c, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3,
-0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80,
-0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71,
-0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60,
-0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 0x49, 0x08, 0x49, 0x00,
-0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 0x38, 0x1c, 0x00, 0xf0,
-0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43,
-0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8,
-0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c,
-0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0,
-0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68,
-0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68,
-0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42,
-0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 0x31, 0x1c, 0x01, 0x3e,
-0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
-0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60,
-0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68,
-0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47,
-0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68,
-0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46,
-0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80,
-0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46,
-0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80,
-0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
-0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
-0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b,
-0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7,
-0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7,
-0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb,
-0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xee, 0xe7,
-0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
-0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
-0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43,
-0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88,
-0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xf8, 0xe7, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c,
-0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33,
-0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68,
-0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1,
-0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18,
-0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20,
-0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60,
-0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46,
-0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a,
-0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80,
-0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7,
-0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23,
-0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55,
-0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
-0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40,
-0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18,
-0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08,
-0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c,
-0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d,
-0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65,
-0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68,
-0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60,
-0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20,
-0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c,
-0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80,
-0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x38, 0x1c, 0xfc, 0xf7, 0x07, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18,
-0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63,
-0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27,
-0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 0x42, 0x63, 0x00, 0x2a,
-0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 0xc0, 0x6a, 0x01, 0xf0,
-0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 0x38, 0x01, 0x00, 0x19,
-0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1,
-0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
-0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x0f, 0x49, 0xc8, 0x68,
-0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 0x02, 0x89, 0x00, 0x2a,
-0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 0x00, 0x2a, 0x0d, 0xd1,
-0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 0x02, 0x23, 0x0a, 0x68,
-0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 0x01, 0x21, 0x00, 0xe0,
-0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x01, 0x23, 0xf8, 0x1d,
-0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 0x79, 0x32, 0x54, 0x8a,
-0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 0xac, 0x42, 0x04, 0xdb,
-0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 0xd1, 0x83, 0x01, 0x23,
-0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61,
-0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0x61, 0x41, 0x69,
-0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 0x00, 0x05, 0xc1, 0x60,
-0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a,
-0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8,
-0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3,
-0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23,
-0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e,
-0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1,
-0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72,
-0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 0x00, 0x20, 0xf8, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49,
-0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31,
-0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x63,
-0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22,
-0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1,
-0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18,
-0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92,
-0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0,
-0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e,
-0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x73, 0xfc, 0x20, 0x6b,
-0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8,
-0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7,
-0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a,
-0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7,
-0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a,
-0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x2d, 0xff, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x64, 0x2d, 0x00, 0x80,
-0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48,
-0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31,
-0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x61, 0x6b,
-0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 0x78, 0x68, 0x80, 0x00,
-0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 0x01, 0x23, 0x78, 0x68,
-0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f,
-0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1,
-0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
-0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68,
-0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7,
-0x59, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31,
-0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0,
-0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0,
-0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09,
-0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62,
-0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0,
-0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a,
-0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19,
-0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a,
-0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62,
-0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62,
-0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1,
-0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42,
-0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19,
-0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0,
-0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38,
-0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
-0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90,
-0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0xc0, 0x6a, 0xc0, 0x46,
-0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46,
-0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60,
-0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46,
-0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a,
-0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46,
-0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3,
-0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20,
-0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0,
-0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30,
-0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61,
-0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 0x38, 0x1c, 0x5c, 0xe3,
-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c,
-0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07,
-0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1,
-0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2,
-0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0,
-0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c,
-0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68,
-0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49,
-0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0,
-0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 0x7a, 0x68, 0xc0, 0x46,
-0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49,
-0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c,
-0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a,
-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c,
-0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61,
-0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69,
-0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a,
-0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28,
-0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f,
-0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92,
-0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48,
-0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80,
-0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60,
-0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a,
-0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64,
-0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18,
-0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30,
-0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61,
-0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88,
-0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0,
-0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93,
-0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68,
-0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46,
-0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46,
-0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49,
-0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0,
-0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71,
-0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37,
-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
-0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18,
-0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x7d, 0xfb, 0x01, 0x9a,
-0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65,
-0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20,
-0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8,
-0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07,
-0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99,
-0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c,
-0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c,
-0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 0x41, 0x49, 0x00, 0x20,
-0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b,
-0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
-0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a,
-0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b,
-0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98,
-0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90,
-0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
-0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20,
-0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90,
-0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42,
-0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90,
-0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98,
-0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42,
-0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20,
-0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1,
-0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0,
-0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb,
-0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29,
-0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a,
-0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90,
-0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98,
-0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 0x01, 0x49, 0xff, 0xff,
-0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 0x60, 0x04, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x55, 0x32, 0xff, 0xff,
-0xac, 0x5e, 0x21, 0x40, 0x0d, 0x3d, 0xff, 0xff, 0xcd, 0x31, 0xff, 0xff,
-0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
-0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98,
-0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1,
-0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98,
-0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48,
-0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x51, 0xf9, 0x00, 0x20,
-0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b,
-0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c,
-0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a,
-0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80,
-0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98,
-0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9,
-0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09,
-0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a,
-0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a,
-0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a,
-0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2,
-0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92,
-0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
-0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40,
-0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22,
-0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d,
-0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x02, 0x90,
-0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06,
-0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a,
-0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d,
-0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37,
-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa,
-0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46,
-0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99,
-0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0,
-0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23,
-0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07,
-0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b,
-0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0,
-0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98,
-0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92,
-0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
-0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28,
-0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20,
-0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92,
-0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20,
-0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42,
-0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98,
-0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90,
-0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04,
-0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0,
-0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e,
-0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b,
-0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x89, 0xf9, 0x01, 0x9a,
-0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63,
-0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68,
-0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04,
-0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68,
-0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92,
-0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d,
-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42,
-0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5,
-0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69,
-0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a,
-0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28,
-0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c,
-0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61,
-0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61,
-0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61,
-0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xcc, 0xfa,
-0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18,
-0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0x68, 0x0e, 0x00, 0x80,
-0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
-0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0,
-0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68,
-0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18,
-0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0,
-0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e,
-0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 0x19, 0x43, 0xe9, 0x63,
-0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e,
-0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0xa9, 0x6b,
-0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 0xa8, 0x63, 0x01, 0x20,
-0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xe8, 0x63,
-0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18,
-0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c,
-0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0,
-0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x06, 0xfc, 0x20, 0x1c, 0x00, 0xf0,
-0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0,
-0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30,
-0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c,
-0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68,
-0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a,
-0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42,
-0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 0xf8, 0xe7, 0x78, 0x68,
-0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7,
-0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90,
-0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x80, 0x69,
-0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23,
-0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
-0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23,
-0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0,
-0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0,
-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0,
-0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18,
-0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68,
-0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 0x00, 0x2d, 0x13, 0xd0,
-0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43,
-0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68,
-0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xdf, 0xfe, 0xb8, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7,
-0x90, 0xee, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 0xf8, 0x0e, 0x00, 0x80,
-0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
-0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0xc8, 0x60,
-0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68,
-0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47,
-0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40,
-0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a,
-0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46,
-0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c,
-0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18,
-0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68,
-0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60,
-0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32,
-0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61,
-0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c,
-0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff,
-0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 0x01, 0x20, 0xf9, 0x1d,
-0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61,
-0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48,
-0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe,
-0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02,
-0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68,
-0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9,
-0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00,
-0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00,
-0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02,
-0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71,
-0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
-0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18,
-0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49,
-0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0xe4, 0x2d, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71,
-0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00,
-0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d,
-0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c,
-0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42,
-0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9,
-0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30,
-0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8,
-0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8,
-0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7,
-0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58,
-0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08,
-0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68,
-0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9,
-0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0,
-0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40,
-0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40,
-0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04,
-0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a,
-0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68,
-0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00,
-0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69,
-0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c,
-0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79,
-0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30,
-0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7,
-0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x04, 0x00, 0x80,
-0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
-0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68,
-0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
-0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21,
-0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a,
-0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68,
-0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c,
-0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28,
-0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0,
-0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
-0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b,
-0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18,
-0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63,
-0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b,
-0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00,
-0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
-0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24,
-0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68,
-0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60,
-0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b,
-0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19,
-0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b,
-0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f,
-0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68,
-0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c,
-0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80,
-0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2e, 0x4b,
-0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62,
-0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c,
-0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31,
-0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29,
-0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c,
-0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00,
-0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61,
-0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3,
-0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 0x3a, 0x6f, 0xfd, 0x68,
-0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 0xdb, 0x6d, 0x5b, 0x08,
-0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 0xfd, 0x6f, 0x03, 0x3b,
-0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 0x0b, 0x81, 0x10, 0x60,
-0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 0x00, 0xd0, 0x01, 0x38,
-0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 0x00, 0xd8, 0x07, 0x4a,
-0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 0x82, 0x61, 0x3a, 0x67,
-0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
-0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f,
-0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 0x00, 0x19, 0xe1, 0x60,
-0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28,
-0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69,
-0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0,
-0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0x65, 0x60, 0x20, 0x68,
-0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23,
-0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b,
-0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 0x02, 0x68, 0x15, 0x68,
-0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2,
-0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07,
-0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47,
-0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3,
-0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68,
-0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60,
-0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d,
-0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f,
-0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d,
-0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d,
-0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60,
-0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e,
-0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20,
-0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a,
-0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68,
-0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60,
-0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46,
-0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1,
-0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69,
-0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a,
-0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d,
-0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b,
-0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68,
-0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
-0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47,
-0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5,
-0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a,
-0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5,
-0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5,
-0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
-0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5,
-0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55,
-0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5,
-0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
-0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5,
-0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 0x02, 0x36, 0x83, 0xe3,
-0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 0xf2, 0xff, 0xff, 0x1a,
-0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 0x01, 0x06, 0x1c, 0xe3,
-0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 0x02, 0xc6, 0xcc, 0xe3,
-0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 0x50, 0x10, 0x91, 0xe5,
-0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5,
-0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a,
-0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 0x94, 0x00, 0x00, 0xe0,
-0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5,
-0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3,
-0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5,
-0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
-0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1,
-0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a,
-0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2,
-0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2,
-0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3,
-0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2,
-0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea,
-0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8,
-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1,
-0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3,
-0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
-0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3,
-0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1,
-0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9,
-0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3,
-0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5,
-0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b,
-0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3,
-0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b,
-0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3,
-0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b,
-0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3,
-0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5,
-0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5,
-0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1,
-0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a,
-0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
-0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
-0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15,
-0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x04, 0x14, 0xe3,
-0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11,
-0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11,
-0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
-0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 0x04, 0x00, 0x14, 0xe3,
-0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3,
-0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3,
-0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x02, 0x14, 0xe3,
-0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3,
-0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3,
-0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b,
-0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b,
-0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2,
-0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2,
-0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea,
-0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
-0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5,
-0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
-0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
-0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5,
-0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
-0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
-0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5,
-0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5,
-0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5,
-0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba,
-0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5,
-0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7,
-0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5,
-0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5,
-0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5,
-0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5,
-0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3,
-0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
-0xcc, 0x04, 0x00, 0x80, 0x71, 0x2b, 0xff, 0xff, 0xd1, 0x3d, 0xff, 0xff,
-0xc9, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08,
-0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68,
-0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
-0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0,
-0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1,
-0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2,
-0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5,
-0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 0x74, 0x10, 0x9f, 0xe5,
-0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5,
-0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2,
-0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea,
-0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x4c, 0x00, 0x9f, 0xe5,
-0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5,
-0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a,
-0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a,
-0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80,
-0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80,
-0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
-0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00,
-0x71, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea,
-0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00,
-0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x6b, 0xea, 0xff, 0xea,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-0x28, 0x04, 0x00, 0x00, 0xf8, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80,
-0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54,
-0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00,
-0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff,
-0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 0x01, 0xff, 0x04, 0x00,
-0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
-0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff,
-0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x3d, 0x50, 0xff, 0xff, 0x81, 0x50, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x48, 0x05, 0x00, 0x80, 0x11, 0x75, 0x21, 0x40, 0x1b, 0x75, 0x21, 0x40,
-0x31, 0x75, 0x21, 0x40, 0x49, 0x75, 0x21, 0x40,
-0x55, 0x75, 0x21, 0x40, 0x63, 0x75, 0x21, 0x40, 0x7d, 0x75, 0x21, 0x40,
-0xa9, 0x75, 0x21, 0x40, 0x6d, 0x76, 0x21, 0x40, 0xc5, 0x76, 0x21, 0x40,
-0xd3, 0x76, 0x21, 0x40, 0xdd, 0x76, 0x21, 0x40, 0xe7, 0x76, 0x21, 0x40,
-0x99, 0x77, 0x21, 0x40, 0xa7, 0x77, 0x21, 0x40, 0xb5, 0x77, 0x21, 0x40,
-0x61, 0x78, 0x21, 0x40, 0x5f, 0x7c, 0x21, 0x40, 0xe9, 0x7c, 0x21, 0x40,
-0x89, 0x7d, 0x21, 0x40, 0xbd, 0x7e, 0x21, 0x40, 0xc9, 0x7e, 0x21, 0x40,
-0x29, 0x7f, 0x21, 0x40, 0x8d, 0x7f, 0x21, 0x40, 0xb9, 0x7f, 0x21, 0x40,
-0xdd, 0x7f, 0x21, 0x40, 0x1d, 0x80, 0x21, 0x40, 0x45, 0x80, 0x21, 0x40,
-0x8d, 0x80, 0x21, 0x40, 0x9d, 0x80, 0x21, 0x40, 0xc5, 0x80, 0x21, 0x40,
-0xd5, 0x80, 0x21, 0x40, 0x1d, 0x81, 0x21, 0x40, 0x5b, 0x81, 0x21, 0x40,
-0xb1, 0x81, 0x21, 0x40, 0x11, 0x82, 0x21, 0x40, 0x1b, 0x82, 0x21, 0x40,
-0x1f, 0x82, 0x21, 0x40, 0x8d, 0x82, 0x21, 0x40, 0xd9, 0x82, 0x21, 0x40,
-0x31, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0xd1, 0x83, 0x21, 0x40,
-0x09, 0x84, 0x21, 0x40, 0x19, 0x84, 0x21, 0x40, 0x51, 0x84, 0x21, 0x40,
-0x61, 0x84, 0x21, 0x40, 0x75, 0x84, 0x21, 0x40, 0x9d, 0x84, 0x21, 0x40,
-0xa7, 0x84, 0x21, 0x40, 0xb1, 0x84, 0x21, 0x40, 0x15, 0x85, 0x21, 0x40,
-0x45, 0x85, 0x21, 0x40, 0x51, 0x85, 0x21, 0x40, 0xc5, 0x85, 0x21, 0x40,
-0xcf, 0x85, 0x21, 0x40, 0xd9, 0x85, 0x21, 0x40, 0xe3, 0x85, 0x21, 0x40,
-0xed, 0x85, 0x21, 0x40, 0xf7, 0x85, 0x21, 0x40, 0x01, 0x86, 0x21, 0x40,
-0x0b, 0x86, 0x21, 0x40, 0x15, 0x86, 0x21, 0x40, 0x01, 0x89, 0x21, 0x40,
-0x1f, 0x86, 0x21, 0x40, 0x29, 0x86, 0x21, 0x40, 0x33, 0x86, 0x21, 0x40,
-0x3d, 0x86, 0x21, 0x40, 0x65, 0x86, 0x21, 0x40, 0x6f, 0x86, 0x21, 0x40,
-0xd1, 0x86, 0x21, 0x40, 0xdb, 0x86, 0x21, 0x40, 0xe5, 0x86, 0x21, 0x40,
-0xef, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x03, 0x87, 0x21, 0x40, 0x69, 0x87, 0x21, 0x40, 0xb5, 0x87, 0x21, 0x40,
-0xf9, 0x87, 0x21, 0x40, 0x09, 0x88, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x55, 0x88, 0x21, 0x40, 0x59, 0x88, 0x21, 0x40, 0x5d, 0x88, 0x21, 0x40,
-0xb5, 0x88, 0x21, 0x40, 0xdd, 0x88, 0x21, 0x40, 0xe9, 0x88, 0x21, 0x40,
-0xed, 0x88, 0x21, 0x40, 0xf1, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40,
-0xf9, 0x88, 0x21, 0x40, 0xfd, 0x88, 0x21, 0x40, 0x2d, 0x85, 0x21, 0x40,
-0x89, 0x85, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x0d, 0x89, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0xe1, 0x74, 0x21, 0x40,
-0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x6b, 0x78, 0x21, 0x40, 0xf5, 0x7b, 0x21, 0x40, 0x31, 0x7c, 0x21, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40,
-0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40,
-0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40,
-0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00,
-0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
-0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
-0xd1, 0xa8, 0x21, 0x40, 0x2d, 0xaa, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x89, 0x70, 0x21, 0x40, 0xc9, 0xa1, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x57, 0x89, 0x21, 0x40, 0xd1, 0xa8, 0x21, 0x40, 0xc5, 0x2f, 0xff, 0xff,
-0x05, 0x21, 0xff, 0xff, 0xef, 0x20, 0xff, 0xff, 0x59, 0xa7, 0x21, 0x40,
-0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 0x5c, 0x2e, 0x00, 0x80,
-0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 0x00, 0x30, 0x37, 0x2f,
-0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35,
-0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
-0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43,
-0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
-0x6f, 0x6e, 0x0a, 0x00, 0x08, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x53, 0xff, 0xff,
-0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00,
-0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
-0x69, 0x3e, 0xff, 0xff, 0xc9, 0x4f, 0xff, 0xff, 0xd5, 0x24, 0xff, 0xff,
-0xc9, 0x3b, 0xff, 0xff, 0x29, 0x3c, 0xff, 0xff, 0x19, 0x1a, 0xff, 0xff,
-0x65, 0x11, 0xff, 0xff, 0xcc, 0x53, 0xff, 0xff, 0x21, 0x40, 0xff, 0xff,
-0x89, 0x70, 0x21, 0x40, 0x49, 0x72, 0x21, 0x40, 0xd9, 0x3f, 0xff, 0xff,
-0x21, 0x9a, 0x21, 0x40, 0x85, 0x24, 0xff, 0xff, 0x64, 0x53, 0xff, 0xff,
-0x8c, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x00, 0x00, 0x20, 0x40, 0xb0, 0x50, 0x00, 0x00, 0x7b, 0x0e, 0x00, 0x00,
-0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xed, 0x89, 0x21, 0x40, 0x8b, 0x89, 0x21, 0x40, 0xa5, 0x8c, 0x21, 0x40,
-0x05, 0x8d, 0x21, 0x40, 0xcd, 0x8d, 0x21, 0x40, 0x8b, 0x8b, 0x21, 0x40,
-0xa9, 0x8e, 0x21, 0x40, 0x15, 0x8f, 0x21, 0x40, 0x69, 0x8b, 0x21, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x59, 0xbd, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x2d, 0xbe, 0x21, 0x40,
-0x00, 0x20, 0x0a, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23,
-0x9b, 0x01, 0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32,
-0xc8, 0x60, 0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x03, 0x48, 0xc0, 0x46,
-0x48, 0x60, 0x88, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c,
-0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xde, 0xff, 0x68, 0x49, 0x0b, 0x23,
-0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40,
-0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61,
-0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a,
-0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68,
-0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20,
-0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xd4, 0xfa, 0xf8, 0x68, 0x00, 0x28,
-0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23,
-0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95,
-0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0,
-0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 0x9b, 0x5c, 0x1e, 0x1c,
-0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 0x5b, 0x78, 0x83, 0x42,
-0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 0x03, 0x9d, 0xed, 0x6a,
-0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 0xeb, 0x62, 0x53, 0x68,
-0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 0x86, 0x42, 0x0a, 0xd1,
-0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 0x9b, 0x00, 0x3c, 0x4e,
-0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 0x9d, 0x61, 0x53, 0x78,
-0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 0x5d, 0x1c, 0x01, 0x95,
-0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xeb, 0x18,
-0xda, 0x60, 0x3a, 0x69, 0x01, 0x32, 0x3a, 0x61, 0x64, 0x00, 0x01, 0x31,
-0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xb8, 0xd3, 0x00, 0x20,
-0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02,
-0xc9, 0x18, 0x88, 0x61, 0x01, 0x9b, 0x99, 0x00, 0x89, 0x18, 0x2d, 0x23,
-0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1,
-0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69,
-0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0,
-0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 0x03, 0xd2, 0x30, 0x20,
-0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 0x78, 0x69, 0x00, 0x28,
-0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 0x78, 0x61, 0x00, 0x20,
-0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0,
-0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78,
-0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 0x9b, 0x00, 0x9e, 0x19,
-0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00,
-0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3,
-0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01,
-0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x30, 0x53, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80,
-0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46,
-0x18, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
-0x10, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
-0x08, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x38, 0x52, 0xff, 0xff,
-0x88, 0x51, 0xff, 0xff, 0xd5, 0xb0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20,
-0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01,
-0xf8, 0x18, 0x05, 0x73, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20,
-0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0,
-0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
-0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20,
-0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 0xc3, 0xff, 0x00, 0x28,
-0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61,
-0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61,
-0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
-0x7d, 0x71, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48,
-0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42,
-0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18,
-0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92,
-0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7,
-0x8d, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92,
-0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x82, 0xff,
-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x7c, 0x29, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
-0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68,
-0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 0x63, 0xff, 0x01, 0x20,
-0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c,
-0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29,
-0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1,
-0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0,
-0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff,
-0x22, 0xe0, 0x09, 0x01, 0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a,
-0x17, 0x49, 0xff, 0xf7, 0x35, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73,
-0x04, 0x23, 0xa8, 0x69, 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61,
-0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60,
-0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0,
-0x17, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0,
-0x02, 0x23, 0xf8, 0x6b, 0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00,
-0x28, 0x05, 0x00, 0x80, 0xa5, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0,
-0x68, 0x0e, 0x00, 0x80, 0xe4, 0x01, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
-0x7d, 0x71, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49,
-0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30,
-0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0,
-0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0,
-0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
-0xc1, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80,
-0xe8, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88,
-0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0,
-0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c,
-0xff, 0xf7, 0xcb, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09,
-0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46,
-0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20,
-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b,
-0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0,
-0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00,
-0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01,
-0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46,
-0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0,
-0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c,
-0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30,
-0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48,
-0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a,
-0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8,
-0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0,
-0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43,
-0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c,
-0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18,
-0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x5e, 0xfe,
-0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48,
-0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x53, 0xfe, 0x01, 0x20,
-0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18,
-0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61,
-0x00, 0xe0, 0x88, 0x61, 0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
-0xc1, 0x63, 0x00, 0x20, 0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80,
-0x50, 0xba, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80,
-0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a,
-0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a,
-0x88, 0x66, 0x88, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40,
-0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42,
-0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46,
-0x08, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
-0x90, 0xee, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46,
-0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80,
-0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60,
-0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60,
-0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48,
-0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46,
-0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90,
-0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c,
-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a,
-0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20,
-0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
-0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xa1, 0x21,
-0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
-0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xff, 0x21, 0xa1, 0x22,
-0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
-0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47,
-0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20,
-0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03,
-0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 0x00, 0x20, 0x70, 0x47,
-0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b,
-0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20,
-0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40,
-0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
-0x5b, 0xff, 0xf8, 0x88, 0x04, 0xa9, 0x03, 0xf0, 0xc9, 0xff, 0x01, 0xab,
-0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8,
-0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b,
-0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68,
-0xc0, 0x46, 0x03, 0x90, 0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31,
-0x68, 0x46, 0xff, 0xf7, 0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b,
-0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78,
-0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22,
-0x00, 0xab, 0x5a, 0x80, 0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70,
-0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68,
-0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31,
-0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80,
-0xa4, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
-0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48,
-0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xe4, 0xfc, 0x00, 0x28,
-0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xdf, 0xfc,
-0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x0d, 0x76, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x59, 0xbd, 0x21, 0x40,
-0x00, 0xb5, 0xc0, 0x88, 0x03, 0xf0, 0x2e, 0xff, 0x00, 0x20, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47,
-0xb0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7,
-0xb5, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0xa4, 0xfc, 0x04, 0x1c, 0x20, 0x4a,
-0x00, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 0x27, 0xd0,
-0x04, 0xa9, 0x1d, 0x4a, 0x38, 0x1c, 0xff, 0xf7, 0x99, 0xfc, 0x04, 0xa8,
-0x00, 0x23, 0x01, 0x2f, 0x06, 0xd1, 0x0c, 0xaa, 0x02, 0x32, 0x00, 0x21,
-0x13, 0x60, 0x01, 0x31, 0x10, 0x29, 0xfb, 0xd3, 0x01, 0x68, 0x04, 0x29,
-0x04, 0xd9, 0x89, 0x08, 0x03, 0x39, 0x89, 0x08, 0x01, 0x31, 0x00, 0xe0,
-0x19, 0x1c, 0x00, 0xab, 0x59, 0x70, 0x06, 0xa9, 0x09, 0x78, 0xc0, 0x46,
-0xd9, 0x80, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46,
-0x03, 0x90, 0x04, 0x33, 0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
-0x18, 0x70, 0x09, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x6e, 0xfc, 0x68, 0x46,
-0x29, 0x1c, 0xff, 0xf7, 0xb7, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
-0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c,
-0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xa2, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc,
-0x18, 0x47, 0xf0, 0xb5, 0xc7, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x1c,
-0x01, 0xa9, 0xff, 0xf7, 0x4d, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0x3c, 0xfc,
-0x00, 0x90, 0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a,
-0x25, 0xd8, 0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x21, 0xd8, 0x19, 0x2c,
-0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0xf9, 0x1d,
-0x09, 0x31, 0x06, 0xab, 0x00, 0x20, 0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd,
-0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3,
-0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78,
-0x86, 0x42, 0xf1, 0xdc, 0x20, 0x1c, 0x05, 0xa9, 0x2b, 0x1c, 0xff, 0xf7,
-0x21, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x01, 0xa8, 0x00, 0x78, 0x40, 0x23,
-0x18, 0x43, 0x01, 0xab, 0x18, 0x70, 0x07, 0x49, 0x00, 0x98, 0xff, 0xf7,
-0x06, 0xfc, 0x00, 0x21, 0x01, 0xa8, 0xff, 0xf7, 0x4f, 0xfd, 0x01, 0x20,
-0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff,
-0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x1b, 0xfe, 0x08, 0xbc,
-0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d,
-0x68, 0x68, 0x01, 0x30, 0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7,
-0xf5, 0xfd, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0,
-0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68,
-0x00, 0x2a, 0x15, 0xd9, 0x40, 0xcb, 0x0f, 0x1c,
-0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 0x12, 0x78, 0x40, 0x23,
-0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 0xda, 0x80, 0x02, 0x90,
-0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 0x15, 0xe0, 0x01, 0x30,
-0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 0x02, 0x94, 0x69, 0x68,
-0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a,
-0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42,
-0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 0xf7, 0xfc, 0x01, 0x20,
-0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x9c, 0x03, 0x00, 0x80,
-0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3,
-0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 0x00, 0xd2, 0x02, 0x22,
-0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 0x01, 0x2b, 0x2e, 0xd1,
-0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0x1b, 0x23,
-0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 0x00, 0xd2, 0x04, 0x27,
-0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 0x07, 0xd2, 0xd1, 0x1d,
-0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23,
-0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x79, 0x03, 0x29,
-0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a,
-0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07,
-0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c,
-0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40,
-0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x04, 0xf0, 0x07, 0xfa, 0x39, 0x48,
-0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 0x37, 0x4e, 0xc5, 0x1d,
-0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 0x5b, 0x5c, 0x5b, 0x00,
-0x9f, 0x44, 0x00, 0x1c, 0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20,
-0xb8, 0x71, 0x00, 0x20, 0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23,
-0x98, 0x43, 0x00, 0xf0, 0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff,
-0xc0, 0x08, 0x06, 0xd3, 0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28,
-0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22,
-0x20, 0x1c, 0x2b, 0xe0, 0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a,
-0x00, 0x21, 0x04, 0xf0, 0x99, 0xf9, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68,
-0x99, 0x43, 0x01, 0x60, 0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68,
-0x04, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43,
-0x00, 0xf0, 0x34, 0xf8, 0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x04, 0xf0,
-0x77, 0xf9, 0xe5, 0xe7, 0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43,
-0x00, 0xf0, 0x28, 0xf8, 0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23,
-0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xff, 0xf7, 0xe3, 0xfa, 0xd5, 0xe7,
-0x06, 0x20, 0xb8, 0x71, 0xd2, 0xe7, 0x00, 0x00, 0xa9, 0x79, 0x21, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00,
-0x10, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20,
-0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
-0x04, 0xf0, 0x4e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x98, 0x1c, 0x00, 0x80,
-0xa9, 0x79, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x31, 0x48, 0x00, 0x68,
-0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0,
-0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 0x01, 0x2a, 0x05, 0xd1,
-0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43,
-0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 0x01, 0x60, 0xe0, 0x68,
-0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x80, 0x8b,
-0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43,
-0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20,
-0x02, 0xf0, 0x1a, 0xfb, 0x38, 0x09, 0x07, 0xd3, 0xe0, 0x6f, 0x80, 0x23,
-0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 0x00, 0x68, 0x00, 0xe0,
-0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x15, 0x48,
-0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43,
-0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08,
-0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 0x10, 0x43, 0x88, 0x42,
-0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29,
-0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 0x04, 0x33, 0x18, 0x40,
-0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80,
-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7,
-0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 0xe3, 0x23, 0x1b, 0x01,
-0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 0x01, 0x22, 0x4a, 0x71,
-0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 0x99, 0x43,
-0x01, 0x60, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x02, 0xf0, 0x8c, 0xfc,
-0x07, 0x20, 0x02, 0xf0, 0x5b, 0xfc, 0x38, 0x1c, 0xff, 0xf7, 0x36, 0xfa,
-0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
-0x37, 0xfc, 0xff, 0xf7, 0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48,
-0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46,
-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x67, 0xfb, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
-0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
-0x38, 0x1c, 0xff, 0xf7, 0x17, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff,
-0xff, 0xf7, 0x62, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0x4c, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7,
-0x01, 0xfc, 0x01, 0x24, 0x1a, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8,
-0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20,
-0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x20, 0xe0, 0x14, 0x48, 0xff, 0xf7,
-0xe1, 0xf9, 0x05, 0x1c, 0x13, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7,
-0xdd, 0xf9, 0x12, 0x49, 0x28, 0x1c, 0xff, 0xf7, 0xd8, 0xf9, 0x01, 0x2f,
-0x06, 0xd1, 0x0c, 0xa9, 0x00, 0x20, 0x00, 0x22,
-0x0a, 0x60, 0x01, 0x30, 0x10, 0x28, 0xfb, 0xd3, 0x10, 0x20, 0x00, 0xab,
-0x58, 0x70, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46,
-0x03, 0x90, 0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x0f, 0xfb, 0x20, 0x1c,
-0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x01, 0x00, 0x00,
-0x24, 0x02, 0xff, 0xff, 0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff,
-0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
-0xbb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x01, 0xd1,
-0x19, 0x2c, 0x09, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43,
-0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 0x27, 0xe0,
-0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90,
-0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28,
-0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04,
-0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 0x09, 0x0c,
-0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0b, 0x48, 0xff, 0xf7, 0x7e, 0xf9,
-0x07, 0x1c, 0x0a, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0x7a, 0xf9,
-0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x75, 0xf9, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0xbe, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0xc5, 0xaf, 0x21, 0x40,
-0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27,
-0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0,
-0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0,
-0x04, 0x2e, 0x00, 0xd1, 0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e,
-0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c,
-0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0,
-0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0,
-0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33,
-0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 0x01, 0x23, 0x5b, 0x02,
-0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22,
-0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 0xff, 0x23, 0xe1, 0x33,
-0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 0xff, 0x33, 0x9e, 0x42,
-0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1,
-0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21,
-0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0x40, 0x88,
-0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0,
-0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1,
-0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43,
-0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0,
-0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x09, 0x21,
-0x49, 0x02, 0x00, 0x20, 0x02, 0xf0, 0x70, 0xf9, 0x00, 0x2f, 0x02, 0xd1,
-0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7,
-0xef, 0xfa, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab,
-0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33,
-0xff, 0xf7, 0x22, 0xfa, 0x28, 0x1c, 0x04, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62,
-0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28,
-0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21,
-0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18,
-0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0,
-0x33, 0xf9, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80,
-0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23,
-0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20,
-0x02, 0xf0, 0x20, 0xf9, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28,
-0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23,
-0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01,
-0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c,
-0x10, 0x20, 0x02, 0xf0, 0x01, 0xf9, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01,
-0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18,
-0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02,
-0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xee, 0xf8, 0x00, 0x20, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0,
-0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x69, 0xfa, 0xb8, 0x05,
-0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
-0xa1, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49,
-0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49,
-0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40,
-0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a,
-0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1,
-0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02,
-0x69, 0x46, 0xff, 0xf7, 0x35, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xff, 0xf7, 0x6f, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20,
-0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1,
-0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1,
-0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47,
-0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 0x9f, 0xf8, 0x69, 0x46,
-0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x0a, 0xfa, 0x01, 0xab, 0x5c, 0x80,
-0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0x40, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49,
-0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47,
-0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
-0xe3, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf9, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47,
-0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68,
-0xff, 0xf7, 0xc6, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49,
-0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0,
-0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70,
-0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
-0xef, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68,
-0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0x17, 0xf8, 0x00, 0x20,
-0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0x9a, 0xf9, 0x00, 0xa8, 0x00, 0x78,
-0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80,
-0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xcd, 0xf8, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88,
-0x69, 0x46, 0xff, 0xf7, 0x83, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x72, 0xff,
-0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0xf2, 0xff, 0x00, 0x28, 0x06, 0xd0,
-0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0x36, 0xff, 0x01, 0xab, 0x58, 0x80,
-0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c,
-0xfe, 0xf7, 0x5f, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa8, 0xf8,
-0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0,
-0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x57, 0xf9, 0x10, 0x48,
-0xfe, 0xf7, 0x46, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7,
-0x43, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c,
-0x22, 0x1c, 0xfe, 0xf7, 0x3c, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
-0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 0x32, 0xff, 0x68, 0x46,
-0x00, 0x21, 0xff, 0xf7, 0x7b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
-0x59, 0xb0, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7,
-0x43, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4,
-0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1,
-0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1,
-0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a,
-0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40,
-0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30,
-0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c,
-0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37,
-0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28,
-0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40,
-0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43,
-0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0c, 0x4b,
-0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02,
-0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80,
-0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04,
-0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
-0x40, 0x00, 0x14, 0x00, 0x28, 0x1b, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0,
-0x13, 0x49, 0x0a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12,
-0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02,
-0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02,
-0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c,
-0xff, 0xf7, 0xae, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43,
-0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xe5, 0xff, 0x01, 0x20,
-0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40,
-0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04,
-0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02,
-0x00, 0x12, 0x18, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04,
-0x00, 0x0c, 0x02, 0x02, 0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c,
-0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00,
-0x90, 0xb5, 0x84, 0xb0, 0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c,
-0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c,
-0x17, 0x02, 0x12, 0x12, 0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c,
-0x1f, 0x02, 0x1b, 0x12, 0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23,
-0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b,
-0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04,
-0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
-0x95, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a,
-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
-0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
-0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x79, 0xff, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47,
-0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a,
-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
-0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
-0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x55, 0xff, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47,
-0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7,
-0xf4, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff,
-0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x06, 0x48,
-0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
-0x2f, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xfd, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf8, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf3, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xc6, 0xfd,
-0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21,
-0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c,
-0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a,
-0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48,
-0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xd5, 0x94, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
-0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
-0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0,
-0xf9, 0xff, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0,
-0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xfe, 0xf8, 0x00, 0x28, 0x0c, 0xd1,
-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x82, 0xff, 0x06, 0x48, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xbb, 0xfe, 0x01, 0x20,
-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7,
-0x6d, 0xff, 0x01, 0x27, 0x01, 0xab, 0x5f, 0x80, 0x09, 0x48, 0x81, 0x89,
-0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04,
-0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
-0x9b, 0xfe, 0x38, 0x1c, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0xfe, 0xf7, 0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0xfe, 0xf7, 0x5a, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0x55, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0xfe, 0xf7, 0x41, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0xfe, 0xf7, 0x3c, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0x37, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x32, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7,
-0x13, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x02, 0xf0, 0xa9, 0xff, 0x02, 0x20,
-0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x48, 0xfe,
-0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0x19, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf8, 0xfe, 0xfa, 0x88, 0x12, 0x49,
-0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 0x0f, 0xd0, 0x04, 0x70,
-0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 0xc8, 0x82, 0xb8, 0x68,
-0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 0x48, 0x83, 0xf8, 0x68,
-0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21,
-0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xfe, 0xf7, 0x17, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0xfe, 0xf7, 0xde, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0xd9, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xd4, 0xfe,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xcf, 0xfe, 0x08, 0xbc,
-0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c,
-0xfe, 0xf7, 0xae, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43,
-0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42,
-0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
-0xfe, 0xf7, 0xdc, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68,
-0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80,
-0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xcc, 0xfd,
-0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0,
-0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x7b, 0xfe, 0xf8, 0x88,
-0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b,
-0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xfe, 0xf7, 0xab, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68,
-0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x80, 0xb5, 0x86, 0xb0, 0x02, 0xa9, 0xfe, 0xf7, 0x57, 0xfe, 0x01, 0x27,
-0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68,
-0xc0, 0x46, 0x04, 0x91, 0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68,
-0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46,
-0x02, 0xa8, 0xfe, 0xf7, 0x81, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68,
-0x80, 0x68, 0xfe, 0xf7, 0x47, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c,
-0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x36, 0xfe, 0x01, 0xab, 0x5c, 0x80,
-0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x61, 0xfd, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
-0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x24, 0xfe, 0x01, 0xab, 0x5f, 0x80,
-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x50, 0xfd, 0x04, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
-0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a,
-0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0,
-0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27,
-0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27,
-0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xec, 0xfd, 0x01, 0xab, 0x5f, 0x80,
-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x26, 0xfd, 0x20, 0x1c, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0,
-0x69, 0x46, 0xfe, 0xf7, 0xd7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x0f, 0xfd, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
-0x00, 0xb5, 0xfe, 0xf7, 0xdd, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47,
-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
-0x00, 0xb5, 0xfe, 0xf7, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xab, 0xfd, 0x00, 0x20,
-0x01, 0xab, 0x58, 0x70, 0x0c, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29,
-0x02, 0xd1, 0x03, 0x97, 0x04, 0x97, 0x01, 0xe0, 0x03, 0x97, 0x04, 0x90,
-0x68, 0x46, 0x01, 0xf0, 0x33, 0xfd, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46,
-0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xd3, 0xfc, 0x38, 0x1c,
-0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30,
-0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40,
-0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42,
-0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 0x02, 0xd3, 0x40, 0x1a,
-0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 0x01, 0x1c, 0xff, 0x27,
-0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 0x43, 0x00, 0x1b, 0x18,
-0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 0x4b, 0x00, 0x59, 0x18,
-0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd7, 0x50,
-0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 0x57, 0x60, 0x8b, 0x68,
-0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69,
-0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc,
-0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb,
-0x38, 0x1c, 0xf6, 0xe7, 0x40, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0,
-0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0,
-0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58,
-0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0,
-0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 0x00, 0x28,
-0x5b, 0xd0, 0x00, 0x26, 0x00, 0x22, 0x00, 0x92, 0x40, 0x23, 0x00, 0x21,
-0x00, 0x20, 0x02, 0xaa, 0x00, 0xf0, 0x88, 0xfa, 0x04, 0xa9, 0x00, 0x20,
-0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0xa2, 0x42, 0x03, 0xd1,
-0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c,
-0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22,
-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 0x00, 0xf0, 0x68, 0xfa,
-0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05,
-0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42,
-0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
-0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x50, 0xfa,
-0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06,
-0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22,
-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0,
-0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1,
-0x01, 0x99, 0x00, 0x29, 0x0f, 0xd1, 0xff, 0x20, 0x3d, 0xe0, 0x40, 0xe0,
-0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
-0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x28, 0xfa,
-0x02, 0x9d, 0x01, 0x20, 0x00, 0x04, 0x46, 0x9a, 0x10, 0x43, 0x79, 0x00,
-0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0x30, 0x1c,
-0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x04, 0x2c, 0x00, 0xd0, 0x0c, 0x20,
-0x04, 0x1c, 0xb0, 0x60, 0x00, 0x20, 0x20, 0x21, 0x46, 0x9a, 0x11, 0x40,
-0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 0x28, 0x19, 0xff, 0x21,
-0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 0xff, 0xf7, 0x19, 0xff, 0x43, 0x01,
-0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21,
-0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60,
-0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20,
-0xf9, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23,
-0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06,
-0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06,
-0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28,
-0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x45, 0x91, 0x41, 0x4a,
-0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 0xc0, 0x43, 0x76, 0xe0,
-0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00,
-0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 0x00, 0x21, 0x02, 0x91,
-0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 0xff, 0x21, 0x68, 0x1e,
-0x09, 0x31, 0xff, 0xf7, 0xcd, 0xfe, 0x61, 0x68, 0x40, 0x18, 0x01, 0x90,
-0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 0xaf, 0x1b, 0x09, 0xe0,
-0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe,
-0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 0x00, 0x22, 0x00, 0x92,
-0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 0x00, 0xf0, 0x9e, 0xf9,
-0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, 0x02, 0x99,
-0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 0xed, 0x1b, 0xa0, 0x68,
-0xa8, 0x42, 0x00, 0xd1, 0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99,
-0xcf, 0x43, 0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68,
-0x03, 0xaa, 0x00, 0xf0, 0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90,
-0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43,
-0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21,
-0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99,
-0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90,
-0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xca, 0xf9,
-0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43,
-0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40,
-0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb,
-0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d,
-0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0,
-0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0,
-0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 0x0f, 0xd3, 0x05, 0xe0,
-0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b,
-0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19,
-0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00,
-0x40, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c,
-0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49,
-0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43,
-0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c,
-0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x21, 0x69, 0x8a, 0x42,
-0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 0xa0, 0x68, 0xe1, 0x68,
-0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x0d, 0xfe, 0x61, 0x68,
-0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31,
-0xff, 0xf7, 0x0d, 0xfe, 0xc2, 0x19, 0xff, 0x21, 0x09, 0x31, 0x8a, 0x42,
-0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x0b, 0x1a, 0x03, 0x93,
-0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0xe1, 0xf8, 0xe0, 0x68,
-0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 0x5d, 0x19, 0xff, 0x1a,
-0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 0x01, 0x9a, 0xc0, 0x46,
-0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0,
-0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98,
-0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98,
-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0xab, 0x20, 0x40,
-0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91,
-0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58,
-0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda,
-0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 0x02, 0x9a, 0x54, 0x18,
-0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 0x01, 0xd9, 0x22, 0x69,
-0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 0xa0, 0x68, 0xe1, 0x68,
-0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0xa7, 0xfd, 0x61, 0x68,
-0x40, 0x18, 0x00, 0x90, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21,
-0x09, 0x31, 0xff, 0xf7, 0xa6, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23,
-0x5b, 0x04, 0x19, 0x43, 0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32,
-0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c,
-0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19,
-0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b,
-0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e,
-0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 0xcb, 0xf8, 0xe0, 0x68,
-0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9,
-0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f,
-0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0,
-0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00,
-0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2,
-0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09,
-0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 0x40, 0x68, 0x0c, 0x23,
-0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 0x11, 0x2c, 0x0d, 0xd0,
-0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1,
-0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06,
-0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c,
-0xdb, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20,
-0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47,
-0x40, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x6f, 0xfa, 0x57, 0x20,
-0x02, 0xf0, 0xcc, 0xf9, 0x02, 0xf0, 0x40, 0xf9, 0x00, 0x0a, 0xfb, 0xd3,
-0x02, 0xf0, 0x4e, 0xfa, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0,
-0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23,
-0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32,
-0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c,
-0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x4b, 0xfa, 0x53, 0x20,
-0x02, 0xf0, 0xa8, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0,
-0xa3, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0xa0, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
-0x9d, 0xf9, 0x02, 0xf0, 0x23, 0xfa, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0,
-0x37, 0xfa, 0x54, 0x20, 0x02, 0xf0, 0x94, 0xf9, 0x00, 0x98, 0x02, 0xf0,
-0x91, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x8e, 0xf9, 0x30, 0x1c, 0x14, 0xe0,
-0x02, 0xf0, 0x2a, 0xfa, 0x52, 0x20, 0x02, 0xf0, 0x87, 0xf9, 0x01, 0x98,
-0x02, 0xf0, 0x84, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x81, 0xf9, 0x30, 0x1c,
-0x02, 0xf0, 0x7e, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xf9, 0x00, 0x20,
-0x02, 0xf0, 0x78, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x00, 0x20,
-0x02, 0xf0, 0x72, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0xe4, 0xf8,
-0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xf0, 0xf9,
-0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x42, 0x02, 0x0a, 0x43,
-0x15, 0x1c, 0x01, 0x28, 0x54, 0xd0, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23,
-0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0x02, 0xf0, 0xe6, 0xf9, 0x53, 0x20, 0x02, 0xf0,
-0x43, 0xf9, 0x28, 0x0c, 0x06, 0x1c, 0x02, 0xf0, 0x3f, 0xf9, 0x28, 0x0a,
-0x01, 0x90, 0x00, 0x90, 0x02, 0xf0, 0x3a, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
-0x37, 0xf9, 0x02, 0xf0, 0xbd, 0xf9, 0xff, 0xf7, 0x61, 0xff, 0x02, 0xf0,
-0xd1, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x2e, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
-0x2b, 0xf9, 0x00, 0x98, 0x02, 0xf0, 0x28, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
-0x25, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0,
-0x1f, 0xf9, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xa3, 0xf9, 0x02, 0xf0,
-0xb9, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x16, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
-0x13, 0xf9, 0x01, 0x98, 0x02, 0xf0, 0x10, 0xf9,
-0x28, 0x1c, 0x02, 0xf0, 0x0d, 0xf9, 0x02, 0xf0, 0x93, 0xf9, 0xff, 0xf7,
-0x37, 0xff, 0x07, 0x49, 0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43,
-0x02, 0x60, 0xc8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0xf0, 0x8f, 0xf8, 0x06, 0x4f,
-0xc0, 0x46, 0xf8, 0x60, 0x01, 0xf0, 0xf2, 0xf8, 0x78, 0x80, 0x01, 0xf0,
-0xb1, 0xf8, 0x38, 0x71, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 0x05, 0xf9, 0x02, 0x49,
-0xc0, 0x46, 0x08, 0x80, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x0b, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23,
-0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68,
-0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68,
-0x1a, 0x43, 0x02, 0x60, 0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32,
-0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28,
-0xfa, 0xd3, 0x46, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30,
-0x20, 0x28, 0xfa, 0xd3, 0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50,
-0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65,
-0x8f, 0x65, 0x3f, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60,
-0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00,
-0x09, 0x18, 0x49, 0x01, 0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d,
-0xf9, 0x33, 0x34, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01,
-0xcb, 0x18, 0x63, 0x63, 0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18,
-0xe3, 0x63, 0x23, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30,
-0x02, 0x28, 0xe4, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c,
-0xc0, 0x46, 0xa1, 0x62, 0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62,
-0xc1, 0x18, 0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21,
-0xe1, 0x64, 0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69,
-0xc0, 0x46, 0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66,
-0x8b, 0x68, 0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66,
-0x1e, 0x4b, 0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01,
-0xc3, 0x18, 0xa3, 0x67, 0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33,
-0x66, 0x61, 0xe7, 0x61, 0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b,
-0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d,
-0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46,
-0x53, 0x66, 0x89, 0x69, 0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46,
-0xd1, 0x66, 0x16, 0x67, 0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67,
-0x56, 0x67, 0xd7, 0x61, 0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73,
-0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
-0x64, 0x2d, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00,
-0x7c, 0x29, 0x00, 0x80, 0x00, 0x55, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00,
-0x10, 0x55, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23,
-0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23,
-0xdb, 0x01, 0xd0, 0x18, 0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18,
-0xc1, 0x61, 0x1c, 0x70, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60,
-0xb9, 0x73, 0x59, 0x61, 0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60,
-0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69,
-0xe4, 0x18, 0x44, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02,
-0x84, 0x63, 0x0e, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46,
-0x44, 0x62, 0x84, 0x69, 0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60,
-0x03, 0x6b, 0xc0, 0x46, 0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62,
-0xc1, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
-0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22,
-0x1b, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20,
-0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c,
-0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37,
-0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18,
-0x33, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20,
-0xf8, 0x60, 0xda, 0x61, 0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48,
-0xc0, 0x46, 0xc2, 0x60, 0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e,
-0xf8, 0x63, 0x0a, 0x48, 0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68,
-0xc0, 0x46, 0x59, 0x80, 0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xbc, 0x20, 0x40,
-0x90, 0xee, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40,
-0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33,
-0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46,
-0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23,
-0x1b, 0x01, 0xd1, 0x18, 0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46,
-0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48,
-0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23,
-0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34,
-0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61,
-0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62,
-0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d,
-0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26,
-0xb6, 0x03, 0x37, 0x61, 0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67,
-0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60,
-0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36,
-0x7e, 0x61, 0x19, 0x4f, 0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c,
-0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50,
-0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27,
-0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3,
-0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3,
-0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40,
-0x80, 0x01, 0x18, 0x00, 0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
-0x08, 0x04, 0x00, 0x80, 0xb8, 0xb5, 0x2c, 0x48, 0xfd, 0xf7, 0xba, 0xfd,
-0x01, 0x20, 0x2b, 0x49, 0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68,
-0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20,
-0x04, 0x06, 0x24, 0x0e, 0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23,
-0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3,
-0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61,
-0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62,
-0x00, 0x27, 0x1b, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69,
-0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46,
-0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46,
-0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f,
-0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43,
-0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2,
-0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49,
-0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40,
-0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01,
-0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64,
-0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67,
-0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0xac, 0x66, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80,
-0xd0, 0x2c, 0x00, 0x80, 0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63,
-0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63,
-0x01, 0x64, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20,
-0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60,
-0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a,
-0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28,
-0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80,
-0xf4, 0x2d, 0x00, 0x80, 0x5d, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48,
-0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b,
-0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48,
-0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b,
-0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49,
-0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b,
-0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00,
-0xac, 0x1e, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00,
-0xac, 0xee, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00,
-0xac, 0x3e, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80,
-0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19,
-0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63,
-0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46,
-0x08, 0x63, 0x48, 0x63, 0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d,
-0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72,
-0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32,
-0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70,
-0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72,
-0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22,
-0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73,
-0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
-0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73,
-0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73,
-0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71,
-0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73,
-0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73,
-0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
-0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73,
-0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73,
-0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71,
-0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61,
-0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0xa0, 0x1c, 0x00, 0x80, 0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02,
-0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00,
-0x09, 0x49, 0x0a, 0x4b, 0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60,
-0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31,
-0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00,
-0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20,
-0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61,
-0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
-0x6c, 0x06, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32,
-0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30,
-0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d,
-0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3,
-0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60,
-0x70, 0x47, 0x00, 0x00, 0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
-0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfd, 0xf7, 0xea, 0xfb, 0x0b, 0x48,
-0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46,
-0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
-0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47,
-0xc1, 0xbd, 0x21, 0x40, 0x75, 0x98, 0x21, 0x40,
-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0xb5, 0x0f, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
-0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48,
-0x0c, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xbf, 0xfb, 0x0b, 0x48, 0x41, 0x8d,
-0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a,
-0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x59, 0xbd, 0x21, 0x40,
-0x75, 0x98, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0x1b, 0x4c,
-0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28,
-0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67,
-0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18,
-0xc1, 0x43, 0xe8, 0x61, 0x69, 0x62, 0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03,
-0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x71,
-0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 0xb8, 0x60, 0x00, 0xf0, 0x4c, 0xfa,
-0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x20, 0xb8, 0x60, 0x07, 0x20, 0x78, 0x61,
-0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0xc0, 0x8b, 0x04, 0x23,
-0x18, 0x40, 0xe8, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x02, 0x1c, 0x00, 0x20, 0xff, 0x23,
-0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 0x00, 0xd1, 0x01, 0x20,
-0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 0x90, 0xbc, 0x70, 0x47,
-0x1b, 0x4a, 0xd7, 0x68, 0x1a, 0x4b, 0x19, 0x79, 0x1c, 0x1c, 0x37, 0x23,
-0x9b, 0x01, 0xe3, 0x18, 0x01, 0x2f, 0x0d, 0xd1, 0x57, 0x88, 0x00, 0x2f,
-0x0a, 0xd1, 0x00, 0x29, 0x0a, 0xd1, 0x59, 0x8b, 0x0a, 0x09, 0x00, 0xd3,
-0x02, 0x20, 0x49, 0x09, 0xe8, 0xd3, 0x01, 0x23, 0x18, 0x43, 0xe5, 0xe7,
-0x00, 0x29, 0x03, 0xd0, 0x98, 0x8a, 0x80, 0x07, 0x80, 0x0f, 0xdf, 0xe7,
-0x6d, 0x23, 0x5b, 0x01, 0xd1, 0x18, 0x8a, 0x88, 0xff, 0x27, 0x01, 0x37,
-0x17, 0x40, 0x0a, 0x49, 0xc9, 0x88, 0x03, 0xd0, 0x4b, 0x0a, 0x01, 0xd3,
-0x03, 0x20, 0xd1, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 0x0b, 0x0a, 0x01, 0xd3,
-0x02, 0x20, 0xcb, 0xe7, 0xd2, 0x09, 0xc9, 0xd3, 0xc9, 0x09, 0xc7, 0xd3,
-0x01, 0x20, 0xc5, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x1c, 0x00, 0x80,
-0xf0, 0xb5, 0xc1, 0xb0, 0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0x52, 0x48, 0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03,
-0x48, 0x60, 0x50, 0x48, 0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21,
-0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b,
-0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33,
-0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43,
-0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07,
-0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30,
-0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03,
-0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03,
-0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62,
-0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a,
-0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34,
-0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c,
-0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42,
-0xf5, 0xd1, 0x30, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68,
-0x1b, 0x0c, 0x08, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24,
-0x2b, 0x4b, 0xc0, 0x46, 0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b,
-0x23, 0x4c, 0x51, 0x26, 0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0x3d, 0x6a,
-0xc0, 0x46, 0x75, 0x61, 0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60,
-0x01, 0x25, 0xb5, 0x60, 0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x71, 0x88, 0x42,
-0x21, 0xd0, 0x25, 0x1c, 0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f,
-0x6b, 0x44, 0x34, 0x60, 0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60,
-0x2b, 0x6f, 0x08, 0x33, 0x2b, 0x67, 0x3c, 0x6a, 0xa3, 0x42, 0x02, 0xd3,
-0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44,
-0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03,
-0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b,
-0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfd, 0xf7, 0x74, 0xfa, 0x41, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00,
-0xc9, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22,
-0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33,
-0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61,
-0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61,
-0x3f, 0x4d, 0xab, 0x6f, 0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23,
-0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f,
-0x9e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61,
-0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23,
-0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43,
-0x3b, 0x61, 0x02, 0x23, 0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43,
-0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00,
-0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08,
-0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25,
-0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43,
-0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43,
-0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61,
-0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61,
-0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40,
-0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30,
-0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61,
-0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08,
-0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0x00, 0x14, 0x40, 0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27,
-0x44, 0x4a, 0xc0, 0x46, 0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c,
-0xf9, 0xd3, 0x04, 0x26, 0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61,
-0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61,
-0x3c, 0x4b, 0x9b, 0x6f, 0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c,
-0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f,
-0x9d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
-0x25, 0x43, 0x15, 0x61, 0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23,
-0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61,
-0x2d, 0x4b, 0x9d, 0x6f, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
-0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00,
-0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
-0x15, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
-0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40,
-0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08,
-0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
-0x15, 0x61, 0x02, 0x25, 0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
-0x25, 0x43, 0x15, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c,
-0x33, 0x43, 0x13, 0x61, 0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23,
-0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21,
-0x25, 0x1c, 0xcd, 0x40, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43,
-0x13, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39,
-0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61,
-0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d,
-0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfd, 0xf7, 0x27, 0xf9, 0x4d, 0x4c,
-0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20,
-0x2a, 0x1c, 0xfd, 0xf7, 0x1d, 0xf9, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28,
-0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1,
-0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02,
-0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28,
-0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21,
-0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26,
-0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe,
-0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 0x00, 0x25, 0x05, 0xe0,
-0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x2b, 0xff, 0x01, 0x35,
-0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 0xb5, 0x42,
-0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 0xff, 0x23, 0xe1, 0x33,
-0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 0xff, 0x23, 0x01, 0x33,
-0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01,
-0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28,
-0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23,
-0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28,
-0x03, 0xd1, 0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23,
-0x19, 0x43, 0x04, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0x09, 0x21, 0x49, 0x02,
-0x00, 0x20, 0xff, 0xf7, 0xf3, 0xfe, 0xe0, 0x68, 0x00, 0x28, 0x0c, 0xd1,
-0x00, 0x21, 0x1b, 0x20, 0xff, 0xf7, 0xec, 0xfe, 0x1a, 0x20, 0xff, 0xf7,
-0x4f, 0xfe, 0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7,
-0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f,
-0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19,
-0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f,
-0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xed, 0xaf, 0x21, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48,
-0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91,
-0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91,
-0x01, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91,
-0x81, 0x69, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91,
-0x01, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91,
-0x81, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90,
-0x01, 0xb0, 0x70, 0x47, 0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0,
-0x68, 0x4d, 0x1b, 0x23, 0xdb, 0x01, 0xef, 0x18, 0xf8, 0x8b, 0x04, 0x22,
-0x02, 0x40, 0x02, 0x92, 0x71, 0x23, 0x5b, 0x01, 0xe8, 0x18, 0x01, 0x88,
-0xc0, 0x46, 0x01, 0x91, 0x40, 0x88, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24,
-0x03, 0xe0, 0x08, 0x2c, 0x01, 0xd3, 0x0f, 0x2c, 0x08, 0xd9, 0x20, 0x1c,
-0xff, 0xf7, 0xe8, 0xfd, 0x61, 0x00, 0x49, 0x19, 0x1b, 0x23, 0xdb, 0x01,
-0xc9, 0x18, 0x88, 0x83, 0x01, 0x34, 0x20, 0x2c, 0xef, 0xd3, 0x58, 0x4c,
-0xe0, 0x69, 0x00, 0x28, 0x15, 0xd0, 0x57, 0x4e, 0x20, 0x25, 0x01, 0x3d,
-0x53, 0x49, 0xe0, 0x69, 0x30, 0x40, 0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18,
-0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x8b, 0x28, 0x1c, 0xff, 0xf7,
-0x65, 0xfe, 0xe0, 0x69, 0xb0, 0x43, 0xe0, 0x61, 0x76, 0x08, 0x00, 0x2d,
-0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 0xc2, 0xfd, 0x48, 0x49, 0xc0, 0x46,
-0xf8, 0x83, 0xf8, 0x8b, 0xc2, 0x08, 0x25, 0xd3, 0xca, 0x68, 0x01, 0x2a,
-0x13, 0xd1, 0x0a, 0x79, 0x00, 0x2a, 0x1f, 0xd1, 0x49, 0x88, 0x00, 0x29,
-0x1c, 0xd1, 0x01, 0x99, 0x43, 0x4a, 0x00, 0x29, 0x05, 0xd0, 0x01, 0x29,
-0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b,
-0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1,
-0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40,
-0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x98, 0x43, 0xf8, 0x83,
-0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 0x1f, 0xd0, 0xb9, 0x8b,
-0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 0xff, 0x23, 0x01, 0x98,
-0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 0x00, 0x98, 0x01, 0x28,
-0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23,
-0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0,
-0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20,
-0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2,
-0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20,
-0x40, 0x02, 0xb8, 0x83, 0xf8, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 0x1d, 0x48,
-0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x51, 0xfc, 0xc2, 0x07,
-0xd2, 0x0f, 0x1a, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 0x2b, 0x43,
-0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65,
-0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 0x03, 0xe0,
-0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 0x61, 0x6a,
-0x81, 0x42, 0x0c, 0xd0, 0x60, 0x62, 0x0e, 0x48, 0x00, 0x2a, 0x03, 0xd0,
-0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x21, 0x33,
-0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0x28, 0x1c, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40,
-0xa4, 0x2a, 0x00, 0x80, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22,
-0x20, 0x28, 0x0f, 0xd2, 0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18,
-0x37, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0x9f, 0x83, 0x82, 0x40, 0x07, 0x23,
-0x5b, 0x02, 0xc9, 0x18, 0x10, 0x1c, 0xca, 0x69, 0x10, 0x43, 0xc8, 0x61,
-0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69,
-0x0b, 0x49, 0xc9, 0x8b, 0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0,
-0x01, 0x23, 0xdb, 0x02, 0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43,
-0x05, 0xe0, 0x01, 0x23, 0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08,
-0x52, 0x00, 0xca, 0x65, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
-0xe8, 0x1b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0,
-0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20,
-0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab,
-0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91,
-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfd, 0xf7, 0x79, 0xf8, 0x04, 0xb0,
-0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68,
-0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68,
-0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0,
-0x0a, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x4b, 0x98, 0x42,
-0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x07, 0x4b, 0x98, 0x42,
-0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80,
-0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24,
-0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68,
-0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21,
-0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 0x02, 0xd0, 0x38, 0x68,
-0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x4b,
-0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x05, 0xd0, 0x0e, 0x4b,
-0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29,
-0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0,
-0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e,
-0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40,
-0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00,
-0x07, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2,
-0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x02, 0xd3,
-0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 0x40, 0x6c, 0x00, 0x04,
-0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 0x40, 0x08, 0x01, 0xd3,
-0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 0x00, 0x00, 0x10, 0x40,
-0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x27,
-0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x72, 0xff, 0x03, 0x1c, 0x19, 0x4a,
-0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 0x1b, 0xd1, 0xcb, 0x04,
-0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 0x43, 0x60, 0x06, 0x68,
-0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 0x43, 0x60, 0x03, 0x68,
-0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 0x05, 0x23, 0x0f, 0x4f,
-0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 0xc0, 0x46, 0x3b, 0x60,
-0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 0x23, 0x60, 0x04, 0x23,
-0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x06, 0x60, 0x27, 0x68,
-0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x22, 0x40,
-0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x28, 0x40,
-0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x28, 0x05, 0xd1,
-0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 0x08, 0x40, 0x22, 0xe0,
-0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c,
-0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x14, 0x48, 0x00, 0x68,
-0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c,
-0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 0x01, 0xa3, 0x1b, 0x5c,
-0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03,
-0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21,
-0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x34, 0x6e, 0x21, 0x40,
-0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40,
-0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x82, 0xb0,
-0x07, 0x1c, 0x01, 0x20, 0x01, 0x90, 0xff, 0xf7, 0xe7, 0xfe, 0x01, 0x28,
-0x13, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x07, 0xd1, 0x00, 0x26,
-0xf6, 0x43, 0x34, 0x1c, 0xa8, 0x2f, 0x02, 0xd1, 0x30, 0x1c, 0x00, 0x96,
-0x35, 0x1c, 0x11, 0x20, 0x00, 0x04, 0x06, 0x62, 0x44, 0x62, 0x85, 0x62,
-0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x08, 0x48, 0xc0, 0x46,
-0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21,
-0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x01, 0x98,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x34, 0x6e, 0x21, 0x40,
-0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
-0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 0x0b, 0xd0, 0x00, 0x23,
-0x21, 0x1c, 0xe2, 0x1d, 0xc1, 0x32, 0x00, 0xe0,
-0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xc8, 0x20, 0xa0, 0x80,
-0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48,
-0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19,
-0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80,
-0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80,
-0xee, 0xff, 0xc0, 0xd0, 0x08, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a,
-0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7a, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23,
-0x0b, 0x72, 0x07, 0x1c, 0x08, 0x7a, 0x43, 0x1c, 0x0b, 0x72, 0x80, 0x18,
-0x90, 0x30, 0x47, 0x72, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80,
-0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20,
-0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68,
-0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40,
-0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7,
-0x91, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42,
-0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7,
-0xc5, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x66, 0x21, 0x40,
-0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c,
-0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89,
-0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c,
-0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c,
-0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e,
-0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 0x79, 0x6c, 0x59, 0x43,
-0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 0x01, 0x32, 0x12, 0x04,
-0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22,
-0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88,
-0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23,
-0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49,
-0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81,
-0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20,
-0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfb, 0xf0, 0x88,
-0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04,
-0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80,
-0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0,
-0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 0xf9, 0x7a, 0x00, 0x29,
-0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 0x79, 0x64, 0x2a, 0xd0,
-0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 0x01, 0x31, 0xe1, 0x80,
-0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 0xdb, 0x03, 0x78, 0x6c,
-0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0,
-0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18,
-0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xfb, 0xe0, 0x6a,
-0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39,
-0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 0x89, 0xfb, 0xb6, 0xe7,
-0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04,
-0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80,
-0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b,
-0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d,
-0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
-0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88,
-0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30,
-0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19,
-0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xfa, 0x71, 0x88,
-0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0,
-0x4d, 0xfb, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35,
-0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25,
-0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc,
-0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
-0xc4, 0x66, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03,
-0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d,
-0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a,
-0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e,
-0x6d, 0xd0, 0xed, 0x6a, 0x5e, 0x1e, 0x73, 0x00, 0x9b, 0x19, 0x5b, 0x01,
-0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0,
-0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x35, 0xad, 0x8b, 0xad, 0x00,
-0x35, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0x70, 0x51, 0x55, 0x89, 0x01, 0x35,
-0x55, 0x81, 0x32, 0x4e, 0xf2, 0x6a, 0xd2, 0x18, 0x90, 0x60, 0xf2, 0x6a,
-0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a,
-0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a,
-0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88,
-0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 0x88, 0x81, 0x24, 0x49,
-0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 0x00, 0x2e, 0x38, 0xd9,
-0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 0x00, 0x2b, 0x2c, 0xd0,
-0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 0xad, 0x6a, 0x58, 0x23,
-0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e,
-0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0xa8, 0x60,
-0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0xe8, 0x63,
-0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 0xed, 0x18, 0x68, 0x64,
-0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 0xeb, 0x18, 0xd8, 0x64,
-0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 0xc0, 0x46, 0x48, 0x81,
-0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 0x03, 0xe0, 0x17, 0x80,
-0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81,
-0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49,
-0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0,
-0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69,
-0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61,
-0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a,
-0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46,
-0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 0x4c, 0xd0, 0x08, 0x22,
-0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 0xd9, 0x1d, 0xb9, 0x31,
-0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
-0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
-0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
-0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
-0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
-0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
-0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 0xcc, 0x82, 0x4f, 0x83,
-0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 0x8c, 0x00, 0x05, 0x19,
-0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 0x01, 0x34, 0x65, 0x62,
-0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00,
-0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29,
-0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xac, 0xab, 0x20, 0x40,
-0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
-0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00,
-0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
-0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36,
-0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d,
-0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
-0x44, 0xfb, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c,
-0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x3b, 0xfb, 0x29, 0x1c, 0x23, 0x1c,
-0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x35, 0xfb, 0x39, 0x1c, 0x23, 0x1c,
-0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x2f, 0xfb, 0x00, 0x21, 0x0b, 0x48,
-0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30,
-0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xac, 0xab, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00,
-0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30,
-0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29,
-0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1,
-0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23,
-0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33,
-0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43,
-0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68,
-0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0,
-0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46,
-0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c,
-0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00,
-0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35,
-0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2,
-0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32,
-0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 0xbc, 0xe7, 0x00, 0x21,
-0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31,
-0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43,
-0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46,
-0x50, 0x61, 0x09, 0x48, 0xfc, 0xf7, 0xa4, 0xfa, 0xa4, 0xe7, 0x00, 0x00,
-0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01,
-0xac, 0xab, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00,
-0x5c, 0x5c, 0x5c, 0x5c, 0x11, 0x31, 0xff, 0xff, 0xf0, 0xb5, 0x07, 0x1c,
-0x3b, 0x48, 0x3c, 0x4c, 0x08, 0x21, 0x20, 0x60, 0xa1, 0x80, 0x00, 0x20,
-0x20, 0x81, 0xe1, 0x80, 0x60, 0x81, 0x39, 0x48, 0xc0, 0x46, 0xe0, 0x60,
-0x38, 0x48, 0xc0, 0x46, 0x20, 0x61, 0x38, 0x48, 0xc0, 0x46, 0x60, 0x61,
-0x37, 0x48, 0xc0, 0x46, 0xa0, 0x61, 0x37, 0x48, 0xc0, 0x46, 0xe0, 0x61,
-0x36, 0x48, 0xc0, 0x46, 0x20, 0x62, 0x36, 0x48, 0xc0, 0x46, 0x60, 0x62,
-0x35, 0x48, 0xc0, 0x46, 0xa0, 0x62, 0x35, 0x48, 0xc0, 0x46, 0xe0, 0x62,
-0x34, 0x48, 0xc0, 0x46, 0x20, 0x63, 0x34, 0x48, 0xc0, 0x46, 0x60, 0x63,
-0x33, 0x48, 0xc0, 0x46, 0xa0, 0x63, 0x33, 0x48, 0xc0, 0x46, 0xe0, 0x63,
-0x32, 0x48, 0xc0, 0x46, 0x20, 0x64, 0x32, 0x48, 0xc0, 0x46, 0x60, 0x64,
-0x31, 0x48, 0xc0, 0x46, 0xa0, 0x64, 0x31, 0x48, 0xc0, 0x46, 0xe0, 0x64,
-0x30, 0x48, 0xc0, 0x46, 0x20, 0x65, 0x30, 0x49, 0xc8, 0x68, 0x02, 0x04,
-0x89, 0x69, 0x4a, 0x40, 0xe3, 0x1d, 0x79, 0x33, 0x09, 0x04, 0xc9, 0x43,
-0xc0, 0x43, 0x48, 0x40, 0xe1, 0x1d, 0xb9, 0x31, 0xda, 0x63, 0x08, 0x60,
-0x29, 0x4d, 0x21, 0x1c, 0x2b, 0x1c, 0x29, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
-0x3e, 0xfa, 0x28, 0x4a, 0xe1, 0x1d, 0xb5, 0x31, 0x01, 0x20, 0x2b, 0x1c,
-0x0e, 0x1c, 0xfc, 0xf7, 0x36, 0xfa, 0x24, 0x4a, 0x00, 0x20, 0x31, 0x1c,
-0x2b, 0x1c, 0xfc, 0xf7, 0x30, 0xfa, 0xe1, 0x1d, 0x4d, 0x31, 0x2b, 0x1c,
-0x20, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x29, 0xfa, 0xe0, 0x1d, 0x5d, 0x30,
-0x01, 0x68, 0x00, 0x29, 0xfc, 0xd0, 0x60, 0x6d, 0xc0, 0x46, 0x38, 0x65,
-0x20, 0x6e, 0xc0, 0x46, 0x78, 0x65, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x80, 0x00, 0x08, 0x00, 0x8c, 0xb9, 0x20, 0x40, 0x81, 0x81, 0x48, 0xbd,
-0x79, 0x56, 0x23, 0x8c, 0x93, 0x0c, 0x82, 0x95, 0x1d, 0x0e, 0x12, 0xcf,
-0x9b, 0x3b, 0xc0, 0xe9, 0xe6, 0x55, 0x7c, 0x82, 0x99, 0xf6, 0x78, 0x02,
-0xd1, 0xd7, 0x25, 0x73, 0x72, 0x8c, 0x33, 0x10, 0xf7, 0x03, 0xf1, 0x42,
-0x6c, 0x9b, 0x4a, 0xa7, 0x82, 0x8e, 0x23, 0xa9, 0x90, 0xb1, 0x82, 0x8e,
-0xdc, 0x3f, 0xfb, 0x29, 0x00, 0x62, 0x22, 0x45, 0x88, 0x2b, 0xf1, 0x85,
-0x12, 0x61, 0xd1, 0x73, 0x6e, 0xb1, 0x11, 0x16, 0x08, 0x83, 0x20, 0x40,
-0x75, 0x08, 0xff, 0xff, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00,
-0x14, 0x00, 0x03, 0x00, 0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0,
-0x33, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x4c, 0xff, 0x03, 0x48, 0x01, 0x89,
-0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
-0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68,
-0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43,
-0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06,
-0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69,
-0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
-0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18,
-0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08,
-0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b,
-0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b,
-0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c,
-0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88,
-0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 0x03, 0x7a, 0x1b, 0x04,
-0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 0x43, 0x7a, 0xdb, 0x07,
-0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 0x5a, 0x08, 0x05, 0xd3,
-0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 0x15, 0x22, 0x00, 0xe0,
-0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3,
-0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a,
-0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c,
-0xff, 0xf7, 0x78, 0xfd, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23,
-0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31,
-0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
-0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40,
-0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 0x2e, 0x1c, 0x45, 0x6d,
-0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 0xfd, 0x40, 0x2f, 0x1c,
-0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 0x08, 0xd0, 0x23, 0x69,
-0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 0xbe, 0x00, 0xae, 0x59,
-0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 0x11, 0x43, 0x05, 0x4b,
-0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 0x87, 0x83, 0xf0, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
-0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78,
-0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43,
-0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c,
-0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x9a, 0xf8,
-0x00, 0xf0, 0xb8, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xc7, 0xfa, 0x3d, 0x70,
-0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x93, 0xf8, 0x00, 0xf0,
-0xa7, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x38, 0x0a, 0xf6, 0xd3,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x82, 0xb0, 0x02, 0x98,
-0x41, 0x02, 0x53, 0x20, 0x00, 0xf0, 0x64, 0xf8, 0x00, 0xf0, 0xa8, 0xfa,
-0xff, 0xf7, 0xe8, 0xff, 0x00, 0x24, 0x00, 0x20, 0x01, 0x90, 0x2e, 0x20,
-0x00, 0x90, 0x00, 0x25, 0x00, 0x27, 0x02, 0x98, 0x01, 0x28, 0x04, 0xd1,
-0x00, 0x98, 0x84, 0x42, 0x01, 0xd3, 0x00, 0x26,
-0x09, 0xe0, 0x01, 0x98, 0x41, 0x1c, 0x01, 0x91, 0x00, 0xf0, 0x60, 0xf8,
-0x00, 0xf0, 0x7e, 0xf9, 0x06, 0x1c, 0x00, 0xf0, 0x8d, 0xfa, 0xf8, 0x00,
-0x86, 0x40, 0x35, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xe6, 0xd3,
-0x03, 0x99, 0x20, 0xc1, 0x03, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42,
-0xdd, 0xd3, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5,
-0x04, 0x1c, 0x0f, 0x1c, 0x01, 0x2c, 0x2a, 0xd0, 0x16, 0x48, 0xc0, 0x6f,
-0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x00, 0x26, 0x20, 0xcf,
-0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x28, 0x1c, 0x00, 0xf0,
-0xdf, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xdc, 0xf9, 0x28, 0x0c, 0x00, 0xf0,
-0xd9, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xd6, 0xf9, 0x00, 0xf0, 0x5c, 0xfa,
-0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 0x83, 0x20, 0x00, 0xf0,
-0x0f, 0xf8, 0x00, 0xf0, 0x53, 0xfa, 0xff, 0xf7, 0x93, 0xff, 0x04, 0x48,
-0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
-0x0f, 0x1c, 0x00, 0xf0, 0x59, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9,
-0x38, 0x0c, 0x00, 0xf0, 0xb3, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xb0, 0xf9,
-0x38, 0x1c, 0x00, 0xf0, 0xad, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0x01, 0x1c, 0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20,
-0x00, 0xf0, 0xa2, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
-0x3d, 0xfa, 0x57, 0x20, 0x00, 0xf0, 0x9a, 0xf9, 0x08, 0xbc, 0x18, 0x47,
-0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43,
-0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0xf8, 0x6f, 0x20, 0x23,
-0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23,
-0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x87, 0xff,
-0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x04, 0x1c,
-0x0f, 0x1c, 0x18, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x99, 0x43,
-0x01, 0x60, 0x61, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0x00, 0xf0,
-0xe9, 0xf9, 0xff, 0xf7, 0x29, 0xff, 0xf8, 0x1d, 0x05, 0x30, 0x01, 0x2c,
-0x03, 0xd1, 0x22, 0x2f, 0x01, 0xd3, 0x00, 0x27, 0x0f, 0xe0, 0x44, 0x1c,
-0xff, 0xf7, 0xaa, 0xff, 0x00, 0xf0, 0xc8, 0xf8, 0x07, 0x1c, 0x00, 0xf0,
-0xd7, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 0xa2, 0xff, 0x00, 0xf0, 0xc0, 0xf8,
-0x05, 0x1c, 0x00, 0xf0, 0xcf, 0xf9, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0x28, 0x02, 0x38, 0x43, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0,
-0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0x01, 0x2f, 0x2f, 0xd0, 0x79, 0x02,
-0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
-0x53, 0x20, 0xff, 0xf7, 0x6b, 0xff, 0x00, 0xf0, 0xaf, 0xf9, 0xff, 0xf7,
-0xef, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0xd6, 0xfe, 0x6a, 0x46, 0xe8, 0x1d,
-0x05, 0x30, 0x14, 0x54, 0x21, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46,
-0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xba, 0xfe, 0x02, 0xab, 0x18, 0x70,
-0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21,
-0xff, 0xf7, 0xb2, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x38, 0x1c,
-0xff, 0xf7, 0x15, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43,
-0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x01, 0x2f,
-0x01, 0xd1, 0x01, 0x20, 0x36, 0xe0, 0x6b, 0x46, 0x00, 0x20, 0xc4, 0x43,
-0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30,
-0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46,
-0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31,
-0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c,
-0xff, 0xf7, 0x7c, 0xfe, 0x04, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x02, 0xab,
-0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7,
-0x71, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 0x1d, 0x06, 0x2d, 0x0e,
-0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x3e, 0xff,
-0x01, 0x20, 0xac, 0x42, 0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02,
-0x14, 0x4c, 0xe0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
-0x53, 0x20, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7,
-0x73, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0x5a, 0xfe, 0xe0, 0x6f, 0x20, 0x23,
-0x01, 0x68, 0x19, 0x43, 0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24,
-0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x3c, 0xfe,
-0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c,
-0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3,
-0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x81, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x93, 0xe5, 0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x01, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x93, 0xe5, 0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x81, 0x00, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47,
-0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 0xa0, 0x13, 0xa0, 0xe1,
-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1,
-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1,
-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5,
-0x3c, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40,
-0x04, 0x01, 0x18, 0x40, 0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40,
-0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0,
-0x47, 0xf8, 0x78, 0x1c, 0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1d, 0x48,
-0x02, 0x68, 0x1d, 0x49, 0x8b, 0x69, 0xd2, 0x18, 0x02, 0x60, 0x02, 0x66,
-0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 0x02, 0xd2,
-0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 0xd2, 0x18,
-0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 0xc2, 0x69,
-0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 0xd2, 0x18,
-0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 0x02, 0x6b,
-0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18,
-0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63,
-0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 0xc9, 0x6a,
-0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
-0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8,
-0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22,
-0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42,
-0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
-0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22,
-0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0,
-0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c,
-0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60,
-0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00,
-0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a,
-0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60,
-0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30,
-0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31,
-0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30,
-0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20,
-0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31,
-0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47,
-0x08, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x04, 0x00, 0x80,
-0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x23,
-0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 0x00, 0x22, 0x0a, 0x70,
-0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 0x43, 0x83, 0x7d, 0x21,
-0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
-0x00, 0xf0, 0x8e, 0xfb, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0xb5, 0x22, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48,
-0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x80, 0xfb, 0x01, 0x23, 0xd8, 0x42,
-0x0a, 0xd1, 0x10, 0x48, 0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32,
-0xca, 0x80, 0x81, 0x79, 0x01, 0x31, 0x81, 0x71, 0xfd, 0xf7, 0x70, 0xf9,
-0x0b, 0x48, 0xc0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22,
-0xd2, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x68, 0xfb, 0x08, 0x48, 0xfb, 0xf7,
-0xe1, 0xfc, 0x08, 0x48, 0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x60, 0xfb,
-0x08, 0xbc, 0x18, 0x47, 0x79, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0xa5, 0x7b, 0x21, 0x40,
-0x95, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20,
-0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21,
-0xfb, 0xf7, 0xc6, 0xfc, 0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68,
-0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c,
-0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46,
-0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64,
-0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa5, 0x55, 0xff, 0xff,
-0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 0x01, 0x22, 0x12, 0x04,
-0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68,
-0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x21, 0x48,
-0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 0xc0, 0x46, 0x01, 0x64,
-0x1f, 0x48, 0xfb, 0xf7, 0x87, 0xfc, 0x1f, 0x48, 0xc1, 0x6b, 0xff, 0x29,
-0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 0x0f, 0x1c, 0x1c, 0x4c,
-0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43,
-0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x28, 0x61,
-0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfb, 0xf7, 0x6f, 0xfc, 0x16, 0x4a,
-0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 0x39, 0x1c, 0x32, 0x1c,
-0xfb, 0xf7, 0x6e, 0xfc, 0x13, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1,
-0x12, 0x48, 0xfb, 0xf7, 0x5d, 0xfc, 0x10, 0x23, 0x60, 0x69, 0x98, 0x43,
-0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18,
-0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
-0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
-0xb5, 0xb6, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 0x44, 0x80, 0x20, 0x40,
-0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0xfd, 0xf7,
-0x01, 0xff, 0x06, 0x48, 0xfb, 0xf7, 0x32, 0xfc, 0xfd, 0xf7, 0xd6, 0xfe,
-0xfe, 0xf7, 0x04, 0xf8, 0xfe, 0xf7, 0x16, 0xf8, 0xfe, 0xf7, 0x24, 0xf8,
-0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 0x90, 0xb5, 0xfd, 0xf7,
-0x6b, 0xfc, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 0xf8, 0x1d, 0x79, 0x30,
-0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 0xf9, 0x67, 0x31, 0x49,
-0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 0x0c, 0x60, 0x4c, 0x60,
-0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 0x8c, 0x61, 0x04, 0xe0,
-0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 0x08, 0x38, 0x00, 0x68,
-0x60, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23,
-0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68,
-0x99, 0x43, 0x01, 0x60, 0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x4e, 0xfc,
-0x00, 0xf0, 0x5e, 0xf9, 0xfd, 0xf7, 0x73, 0xf8, 0xff, 0xf7, 0x0c, 0xfe,
-0xfd, 0xf7, 0x2e, 0xfe, 0xfd, 0xf7, 0xb6, 0xfd, 0xfd, 0xf7, 0xc2, 0xfe,
-0xfd, 0xf7, 0x54, 0xfd, 0xfd, 0xf7, 0x0a, 0xfd, 0xfd, 0xf7, 0x94, 0xfd,
-0x00, 0xf0, 0x1a, 0xfa, 0xfd, 0xf7, 0x9c, 0xff, 0xfd, 0xf7, 0x0a, 0xff,
-0xfd, 0xf7, 0xd2, 0xfe, 0xfd, 0xf7, 0x3c, 0xfc, 0xfb, 0xf7, 0xdc, 0xfa,
-0xff, 0xf7, 0x9c, 0xff, 0x71, 0x23, 0x5b, 0x01,
-0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 0xf8, 0x18,
-0x04, 0x63, 0xf8, 0x68, 0x01, 0x28, 0x02, 0xd1, 0xa8, 0x20, 0xfe, 0xf7,
-0xb1, 0xfd, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 0x18, 0xfa,
-0x07, 0x48, 0xfb, 0xf7, 0xbd, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 0x04, 0x01, 0x11, 0x40,
-0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x15, 0x8f, 0x21, 0x40,
-0x00, 0xb5, 0x04, 0x48, 0xfb, 0xf7, 0xaa, 0xfb, 0xfd, 0xf7, 0x5e, 0xff,
-0xfd, 0xf7, 0x24, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x15, 0x99, 0x21, 0x40,
-0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62,
-0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69,
-0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61,
-0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10,
-0x00, 0xb5, 0x02, 0x48, 0xfb, 0xf7, 0x80, 0xfb, 0x08, 0xbc, 0x18, 0x47,
-0xc8, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 0x01, 0x21, 0x09, 0x04,
-0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 0x22, 0x4d, 0x00, 0x29,
-0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a,
-0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 0x1d, 0x48, 0xfb, 0xf7,
-0x65, 0xfb, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 0x01, 0x30, 0x88, 0x61,
-0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 0x00, 0x28, 0x1f, 0xd0,
-0x19, 0x48, 0xfb, 0xf7, 0x57, 0xfb, 0x19, 0x48, 0xfb, 0xf7, 0x54, 0xfb,
-0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x16, 0x48,
-0xfb, 0xf7, 0x4c, 0xfb, 0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40,
-0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1,
-0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x01, 0xe0, 0x28, 0x64,
-0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0x65, 0xfd, 0x0b, 0x48, 0xfb, 0xf7,
-0x35, 0xfb, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
-0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf4, 0x01, 0xff, 0xff,
-0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9f, 0x21, 0x40,
-0x00, 0x20, 0x07, 0x4a, 0x01, 0x21, 0x09, 0x05, 0x50, 0x61, 0xc8, 0x60,
-0xd0, 0x61, 0xc8, 0x61, 0x03, 0x23, 0xdb, 0x04, 0x03, 0x4a, 0x01, 0x21,
-0xd1, 0x63, 0x58, 0x60, 0xfc, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xc0, 0xb0, 0x01, 0x22, 0x00, 0x21,
-0x0a, 0x20, 0xfc, 0xf7, 0xd1, 0xff, 0x07, 0x1c, 0xff, 0x2f, 0x28, 0xd0,
-0x69, 0x46, 0xff, 0x22, 0x38, 0x1c, 0x01, 0x32, 0xfd, 0xf7, 0x54, 0xf9,
-0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x1b, 0xd1, 0x0d, 0x98, 0x00, 0x09,
-0x18, 0xd3, 0x38, 0x1c, 0xfd, 0xf7, 0x8d, 0xf8, 0x0e, 0x49, 0x01, 0x22,
-0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x0d, 0x48, 0x05, 0xd1, 0x0a, 0x68,
-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x0a, 0x49,
-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x64,
-0xff, 0xf7, 0xbc, 0xff, 0x38, 0x1c, 0xfd, 0xf7, 0x74, 0xf8, 0x40, 0xb0,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x07, 0x80, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x17, 0x49, 0x01, 0x22, 0x12, 0x04,
-0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68,
-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x11, 0x49,
-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x64,
-0x03, 0x20, 0xfe, 0xf7, 0xd3, 0xfc, 0xfb, 0xf7, 0x0d, 0xff, 0x01, 0x23,
-0x18, 0x43, 0xfb, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0x83, 0xfe, 0xff, 0xf7,
-0x9d, 0xff, 0xff, 0xf7, 0x05, 0xfe, 0xff, 0xf7, 0xf5, 0xfe, 0xff, 0xf7,
-0x09, 0xff, 0xff, 0xf7, 0x9b, 0xfd, 0xff, 0xf7, 0x21, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03,
-0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88,
-0x40, 0x04, 0x43, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x04, 0x20, 0xaf, 0x60,
-0x41, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x08, 0x20, 0xc8, 0x23, 0x43, 0x43,
-0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3d, 0x4e, 0xc0, 0x46, 0x31, 0x61,
-0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3a, 0x4e, 0xc0, 0x46, 0xf3, 0x61,
-0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 0x81, 0x42,
-0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 0x41, 0x1e,
-0x32, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 0x02, 0x38,
-0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 0x06, 0xe0,
-0x2c, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 0x88, 0x42,
-0xd2, 0xd9, 0x2a, 0x49, 0x00, 0x20, 0xa3, 0x69, 0x9b, 0x08, 0x07, 0xd0,
-0x28, 0x4b, 0x87, 0x00, 0xcb, 0x51, 0xa7, 0x69, 0xbf, 0x08, 0x01, 0x30,
-0x87, 0x42, 0xf8, 0xd8, 0x22, 0x49, 0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89,
-0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 0x00, 0x20, 0x00, 0x22, 0x00, 0x2c,
-0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30,
-0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc,
-0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 0x00, 0x19, 0x40, 0x01, 0xc7, 0x19,
-0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01,
-0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60,
-0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69,
-0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51,
-0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00,
-0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0xb0, 0xbe, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00,
-0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09,
-0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61,
-0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x81, 0x61, 0x01, 0x20, 0x00, 0x06,
-0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18,
-0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61,
-0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05,
-0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20,
-0x40, 0x03, 0x81, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8,
-0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23,
-0x9b, 0x01, 0xfb, 0x18, 0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3,
-0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1d, 0x3e, 0xff, 0xff,
-0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47,
-0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b,
-0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c,
-0x59, 0x69, 0x53, 0x01, 0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43,
-0x87, 0x61, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc,
-0x70, 0x47, 0x18, 0x1c, 0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43,
-0x47, 0x61, 0xd7, 0x60, 0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c,
-0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9d, 0x6a,
-0xbd, 0x42, 0x05, 0xd1, 0x1d, 0x6b, 0x95, 0x42, 0x02, 0xd1, 0xdb, 0x6a,
-0x8b, 0x42, 0x1c, 0xd0, 0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20,
-0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9b, 0x6a,
-0x00, 0x2b, 0x09, 0xd1, 0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01,
-0xe3, 0x18, 0x1a, 0x63, 0xd9, 0x62, 0x5a, 0x63, 0x9f, 0x62, 0x02, 0xe0,
-0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20,
-0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0,
-0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01,
-0xe3, 0x18, 0x9b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19,
-0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61,
-0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62,
-0x53, 0x6b, 0xc0, 0x46, 0x53, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28,
-0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x9a, 0x68, 0x8a, 0x42,
-0x03, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20,
-0xc0, 0x43, 0xfa, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80,
-0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69,
-0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01,
-0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0xc0, 0x46,
-0x43, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61,
-0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x68, 0x0e, 0x00, 0x80,
-0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69,
-0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a,
-0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47,
-0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
-0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0xff, 0xf7, 0xe3, 0xff, 0x01, 0x34,
-0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00,
+0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00,
+0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0xb1, 0xd4,
+0x4c, 0xb8, 0xd0, 0x4b, 0x32, 0x02, 0xd4, 0xee, 0x73, 0x7e, 0x0b, 0x13,
+0x9b, 0xc0, 0xae, 0xf4, 0x40, 0x01, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00,
+0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea,
+0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
+0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc5, 0x14, 0x00, 0xea,
+0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1,
+0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
+0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1,
+0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 0x00, 0xa0, 0xa0, 0xe1,
+0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0xa8, 0x10, 0x9f, 0xe5,
+0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5,
+0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe3,
+0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+0x6c, 0xd0, 0x9f, 0xe5, 0x9b, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3,
+0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5,
+0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb,
+0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
+0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 0x54, 0x10, 0x9f, 0xe5,
+0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1,
+0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb,
+0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea,
+0x15, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00,
+0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
+0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80,
+0xad, 0xde, 0xad, 0xde, 0xb0, 0xbb, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40,
+0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xbd, 0xba, 0x21, 0x40,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x58, 0x57, 0x00, 0x00, 0x86, 0x4b, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff,
+0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4d, 0x00, 0x24, 0x28, 0x68, 0x00, 0x28,
+0x1e, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x7b, 0xfd, 0x29, 0x68,
+0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x15, 0xd0, 0x38, 0x01, 0x0d, 0x49,
+0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29,
+0x0c, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x28, 0x68, 0xc1, 0x69, 0xc0, 0x46,
+0x29, 0x60, 0x39, 0x07, 0x41, 0x60, 0x04, 0x62, 0xc7, 0x62, 0xb0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0xe8, 0x17, 0x00, 0x80,
+0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68,
+0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47,
+0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
+0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0x00, 0x10, 0xa0, 0xe1,
+0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
+0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
+0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
+0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x80, 0xe3,
+0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
+0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
+0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3,
+0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 0x00, 0xf0, 0x21, 0xe1,
+0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
+0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x91, 0x00, 0x00, 0xe0,
+0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0,
+0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3,
+0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63,
+0x04, 0x49, 0x05, 0xf0, 0x01, 0xfb, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00,
+0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2,
+0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc,
+0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 0xbb, 0x42, 0x05, 0xd2,
+0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 0xc8, 0x63, 0xf1, 0xe7,
+0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x04, 0x48, 0xc1, 0x6b,
+0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 0x68, 0x0e, 0x00, 0x80,
+0x00, 0x00, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
+0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 0x0b, 0xd2, 0xb9, 0x6e,
+0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2,
+0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62,
+0x38, 0x6b, 0x02, 0xf0, 0x2d, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xe8, 0xfa,
+0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49,
+0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18,
+0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
+0xa4, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 0xc0, 0x6d, 0x02, 0x23,
+0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 0x03, 0xd0, 0xd1, 0x63,
+0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 0x07, 0x68, 0x7b, 0x1c,
+0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 0xf3, 0xe7, 0x00, 0x00,
+0xa4, 0x2a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xe0, 0x01, 0x00, 0x80,
+0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 0x10, 0x18, 0x0a, 0x04,
+0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 0x01, 0x0c, 0x05, 0xd0,
+0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 0x01, 0x0c, 0xf9, 0xd1,
+0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 0x00, 0x22, 0x00, 0x29,
+0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f,
+0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b,
+0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 0x00, 0x88, 0x00, 0x06,
+0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c,
+0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c,
+0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 0xc7, 0x89, 0xfb, 0x18,
+0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 0x40, 0x7a, 0x00, 0x02,
+0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 0x00, 0x0c, 0x3b, 0x0c,
+0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 0x11, 0x1c, 0xff, 0xf7,
+0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xff, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 0x82, 0x68, 0x1a, 0x40,
+0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 0x93, 0x69, 0x01, 0x33,
+0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 0x00, 0x68, 0x1c, 0x18,
+0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43,
+0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 0x82, 0x68, 0x1a, 0x40,
+0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 0x52, 0x09, 0x0e, 0xd3,
+0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 0xcb, 0x68, 0x02, 0x68,
+0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68,
+0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x80, 0x23,
+0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 0x15, 0xd0, 0x4a, 0x68,
+0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 0x01, 0x33, 0xd3, 0x61,
+0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a,
+0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 0x00, 0x28, 0x00, 0xd1,
+0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 0x38, 0x69, 0xb9, 0x68,
+0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 0xc0, 0x43, 0x01, 0x04,
+0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x04, 0x1c, 0xb8, 0x68,
+0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 0x0c, 0xd2, 0x2a, 0x68,
+0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x05, 0xf9, 0xc0, 0x43,
+0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x26, 0xff, 0x04, 0x1c,
+0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 0x1a, 0xd3, 0xb8, 0x6a,
+0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 0xed, 0xf8, 0xc0, 0x43,
+0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 0x20, 0x23, 0xb9, 0x69,
+0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x07, 0xe0,
+0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x41, 0x6a,
+0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x0c, 0x2b, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x41, 0x09,
+0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
+0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x53, 0xf8, 0x01, 0x1c,
+0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69,
+0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0,
+0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0xc1, 0x6a,
+0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x0c, 0x2b, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x81, 0x09,
+0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
+0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 0x40, 0x18, 0x01, 0x23,
+0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 0x05, 0x04, 0x2d, 0x0c,
+0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0x28,
+0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 0x98, 0x42, 0x07, 0xd0,
+0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x60, 0x6b, 0x01, 0x30,
+0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 0xb8, 0x69, 0x18, 0x43,
+0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 0x00, 0x20, 0xb0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 0xe0, 0x6b, 0x61, 0x6c,
+0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 0x00, 0x20, 0x8a, 0x08,
+0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 0x9f, 0x58, 0x03, 0xae,
+0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 0xf7, 0xd8, 0x60, 0x6a,
+0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
+0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 0xff, 0xf7, 0x87, 0xfe,
+0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x6d, 0xfe,
+0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 0x61, 0x6a, 0x01, 0x23,
+0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x01, 0x91,
+0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 0x0c, 0xd2, 0xa2, 0x6a,
+0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x2f, 0xf8, 0xc0, 0x43,
+0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0x07, 0x1c,
+0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 0x08, 0x18, 0x69, 0x8a,
+0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 0xa1, 0x6c, 0x62, 0x6c,
+0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
+0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 0x05, 0xd0, 0x08, 0x04,
+0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 0xf9, 0xd1, 0x38, 0x1c,
+0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0xb0,
+0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb4, 0x00, 0x22,
+0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 0xdc, 0x00, 0x47, 0x18,
+0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 0xff, 0x00, 0x80, 0x08,
+0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 0x4d, 0x1e, 0x02, 0xc8,
+0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 0x09, 0xd0, 0x0c, 0x04,
+0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 0x02, 0xc8, 0x1c, 0x1c,
+0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 0x08, 0x1c, 0xf8, 0x40,
+0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 0x42, 0x18, 0x10, 0x0c,
+0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c,
+0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00,
+0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 0x42, 0x00, 0x12, 0x18,
+0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23,
+0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58,
+0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 0x01, 0x30, 0x04, 0x28,
+0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 0x09, 0x0b, 0x07, 0x48,
+0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 0x02, 0xd0, 0x38, 0x1c,
+0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0xa8, 0x03, 0x00, 0x80,
+0x00, 0x40, 0x14, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x98, 0xb4, 0x14, 0x4a,
+0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 0xc0, 0x58, 0x07, 0x03,
+0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 0x12, 0x0b, 0x11, 0x48,
+0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 0xe4, 0x58, 0x01, 0x23,
+0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 0xcc, 0x00, 0x01, 0x21,
+0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 0x98, 0x42, 0x03, 0xd9,
+0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 0x18, 0x1a, 0x84, 0x42,
+0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 0x55, 0x55, 0x55, 0x55,
+0x20, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x08, 0x04, 0x00, 0x80,
+0x18, 0x04, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 0x00, 0xd0, 0x01, 0x3a,
+0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 0xc0, 0x46, 0x3b, 0x60,
+0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 0x08, 0x32, 0x10, 0x4b,
+0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 0x12, 0x58, 0x0f, 0x4b,
+0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x1b, 0x68, 0x9b, 0x00,
+0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 0x0a, 0x48, 0xc1, 0x68,
+0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x08, 0x4b,
+0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 0x00, 0x20, 0xf6, 0xe7,
+0x08, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x80,
+0x18, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x10, 0x04, 0x00, 0x80,
+0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 0x01, 0xb6, 0xa0, 0xe3,
+0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 0x01, 0x7a, 0xa0, 0xe3,
+0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 0xc8, 0x60, 0x9f, 0xe5,
+0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 0x00, 0x00, 0x54, 0xe3,
+0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 0x11, 0x00, 0x00, 0x0a,
+0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x21, 0x00, 0x00, 0x0a,
+0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
+0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
+0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 0x02, 0x0a, 0x14, 0xe3,
+0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x02, 0x0a, 0xc0, 0xe3,
+0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x80, 0x85, 0xe5,
+0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
+0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
+0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x00, 0x1b,
+0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 0x02, 0x0b, 0x14, 0xe3,
+0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 0x20, 0x00, 0x00, 0x1b,
+0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x18, 0x00, 0x89, 0xe5,
+0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3,
+0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
+0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8,
+0x04, 0xf0, 0x5e, 0xe2, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
+0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 0x00, 0x20, 0xc3, 0xe1,
+0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x0c, 0x20, 0x81, 0xe5,
+0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0x18, 0x10, 0x9f, 0xe5,
+0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 0xb0, 0x24, 0xc1, 0xe1,
+0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 0x3c, 0x00, 0x81, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 0xff, 0xff, 0xff, 0xea,
+0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 0x01, 0x16, 0xa0, 0xe3,
+0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 0x24, 0x20, 0x91, 0xe5,
+0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20, 0x80, 0xe5,
+0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x80, 0xe5,
+0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 0x2c, 0x20, 0x80, 0xe5,
+0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11,
+0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x10, 0x81, 0xe2,
+0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 0x0b, 0x02, 0xa0, 0xe3,
+0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x04, 0x00, 0x80,
+0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5,
+0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2,
+0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1,
+0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3,
+0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5,
+0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0x00,
+0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
+0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2,
+0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0c, 0x10, 0xa0, 0xe3,
+0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5,
+0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5,
+0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3,
+0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x4c, 0x00, 0x1f, 0xe5,
+0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea,
+0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 0x01, 0x06, 0xa0, 0xe3,
+0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x21, 0x1f, 0xe5,
+0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0xe5,
+0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 0x01, 0x06, 0xa0, 0xe3,
+0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x92, 0xe5,
+0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1,
+0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x82, 0xe5,
+0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 0x0c, 0x00, 0x81, 0xe5,
+0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x81, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0,
+0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c,
+0x00, 0xf0, 0x92, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x00, 0x28,
+0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x84, 0xf8, 0x00, 0x20, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 0x3a, 0x78, 0xd2, 0x07,
+0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 0xff, 0x22, 0x01, 0x32,
+0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02,
+0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 0x5b, 0x02, 0x42, 0x68,
+0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 0x82, 0x60, 0x00, 0xe0,
+0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x08, 0x2a,
+0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
+0x0e, 0x31, 0x3c, 0xe0, 0xc1, 0x23, 0xdb, 0x00, 0x9a, 0x42, 0x03, 0xd1,
+0x41, 0x68, 0x24, 0x4b, 0x19, 0x43, 0x3e, 0xe0, 0x23, 0x4b, 0x9a, 0x42,
+0x04, 0xd1, 0x01, 0x23, 0x1b, 0x03, 0x41, 0x68, 0x19, 0x43, 0x36, 0xe0,
+0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
+0x12, 0x0c, 0x2e, 0x3a, 0x1c, 0x4b, 0x9a, 0x42, 0x2d, 0xd8, 0x01, 0x25,
+0x42, 0x68, 0x15, 0x43, 0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02,
+0x1a, 0x43, 0x18, 0x4b, 0x9a, 0x42, 0x22, 0xd1, 0xfb, 0x1d, 0x09, 0x33,
+0x44, 0xcb, 0x9b, 0x07, 0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33,
+0x9e, 0x40, 0x16, 0x43, 0x03, 0x2e, 0x18, 0xd1, 0x39, 0x7d, 0x7b, 0x7d,
+0x1b, 0x02, 0x19, 0x43, 0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43,
+0x41, 0x60, 0x81, 0x68, 0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x0a, 0xe0,
+0xc1, 0x23, 0xdb, 0x00, 0x99, 0x42, 0x04, 0xd1, 0x01, 0x21, 0x89, 0x03,
+0x29, 0x43, 0x41, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x00, 0x21, 0x08, 0x1c,
+0xf0, 0xbc, 0x70, 0x47, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x00, 0x00,
+0xae, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68,
+0xd1, 0x08, 0x3f, 0xd3, 0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39,
+0x8f, 0x78, 0x3f, 0x07, 0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d,
+0x0d, 0x32, 0xc2, 0x60, 0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60,
+0x08, 0x23, 0x1a, 0x43, 0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f,
+0x92, 0x00, 0x02, 0x61, 0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43,
+0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
+0x12, 0x0c, 0x42, 0x61, 0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23,
+0x42, 0x68, 0x1a, 0x43, 0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23,
+0x42, 0x68, 0x1a, 0x43, 0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23,
+0x42, 0x68, 0x1a, 0x43, 0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23,
+0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76,
+0x80, 0xbc, 0x70, 0x47, 0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78,
+0x1b, 0x02, 0x1a, 0x43, 0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43,
+0x02, 0x60, 0xc9, 0x78, 0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47,
+0x80, 0xb5, 0x07, 0x1c, 0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a,
+0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43,
+0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42,
+0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46,
+0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xda, 0xf8, 0x38, 0x1c, 0x01, 0xf0,
+0x95, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49,
+0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18,
+0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7,
+0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80,
+0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x01, 0x23, 0x9b, 0x07,
+0x01, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02,
+0x12, 0x0e, 0x12, 0x06, 0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40,
+0x10, 0x43, 0x0a, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02,
+0x1b, 0x0a, 0x19, 0x40, 0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07,
+0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04,
+0x1a, 0x40, 0x11, 0x43, 0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43,
+0x00, 0x0e, 0x08, 0x43, 0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23,
+0x81, 0x6b, 0x19, 0x40, 0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d,
+0x39, 0x37, 0x39, 0x7b, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1,
+0x01, 0x6b, 0xc0, 0x46, 0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d,
+0x2d, 0x35, 0x00, 0x22, 0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50,
+0x01, 0x32, 0x07, 0x2a, 0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63,
+0x82, 0x6a, 0xc0, 0x46, 0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33,
+0x5a, 0x83, 0x40, 0x6a, 0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27,
+0x42, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1,
+0x42, 0x69, 0x00, 0x2a, 0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a,
+0x02, 0x29, 0x02, 0xd3, 0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0,
+0x13, 0xf8, 0x09, 0xe0, 0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61,
+0xc1, 0x60, 0x03, 0xe0, 0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61,
+0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7,
+0x6c, 0x06, 0x00, 0x80, 0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68,
+0x00, 0x2b, 0x34, 0xd0, 0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68,
+0x9b, 0x6a, 0xc0, 0x46, 0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19,
+0x7f, 0x02, 0x17, 0x4b, 0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63,
+0x07, 0x63, 0xcb, 0x1d, 0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69,
+0x00, 0x2b, 0x01, 0xd0, 0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61,
+0x0f, 0x1c, 0xc9, 0x68, 0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63,
+0xf8, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60,
+0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30,
+0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+0xac, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31,
+0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32,
+0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18,
+0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a,
+0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38,
+0x92, 0x04, 0x92, 0x0c, 0x00, 0x26, 0x25, 0x4d,
+0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 0x04, 0xd0, 0x20, 0x8a,
+0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 0x01, 0x23, 0x9b, 0x07,
+0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30,
+0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c,
+0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c,
+0x02, 0xf0, 0x02, 0xf8, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23,
+0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
+0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8,
+0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43,
+0x20, 0x82, 0x21, 0x8a, 0x38, 0x1c, 0x00, 0xf0, 0xa2, 0xfb, 0xe8, 0x68,
+0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
+0xe8, 0x60, 0x30, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20,
+0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c,
+0xfc, 0x1d, 0xf9, 0x34, 0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35,
+0x38, 0x48, 0xc0, 0x6a, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18,
+0x01, 0x20, 0x80, 0x07, 0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
+0x00, 0x90, 0x01, 0x23, 0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43,
+0x00, 0x68, 0x38, 0x1c, 0x29, 0x1c, 0x00, 0xf0, 0xc2, 0xfa, 0xa8, 0x88,
+0x41, 0x07, 0x01, 0xd0, 0x00, 0x20, 0x51, 0xe0, 0x29, 0x89, 0x09, 0x18,
+0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18,
+0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a,
+0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0,
+0x33, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69,
+0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58,
+0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28,
+0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31,
+0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28,
+0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xae, 0xfb,
+0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b,
+0xff, 0xf7, 0xa6, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43,
+0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0x9e, 0xfb, 0xa1, 0x6b, 0x08, 0x4a,
+0x01, 0x20, 0xff, 0xf7, 0x99, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46,
+0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x4c, 0x2a, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00,
+0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a,
+0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49,
+0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48,
+0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00,
+0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d,
+0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68,
+0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a,
+0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b,
+0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69,
+0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x26, 0xf9, 0x28, 0x6b, 0x79, 0x69,
+0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b,
+0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50,
+0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00,
+0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
+0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90,
+0x90, 0x49, 0x42, 0x00, 0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0,
+0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28,
+0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a,
+0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0,
+0x67, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98,
+0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28,
+0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a,
+0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60,
+0x62, 0xe0, 0x0a, 0x98, 0x02, 0x28, 0x5f, 0xd1, 0x09, 0x98, 0x40, 0x0c,
+0x73, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43,
+0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18,
+0x0c, 0x38, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x8a, 0x00, 0x6b, 0x4b,
+0xd6, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
+0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x00, 0x21, 0x83, 0x1e,
+0x0c, 0x93, 0x68, 0x4a, 0x16, 0x6b, 0xc0, 0x46, 0x0b, 0x96, 0x8a, 0x00,
+0x0c, 0x9b, 0x9b, 0x18, 0x0b, 0x9e, 0x9e, 0x19, 0x01, 0x23, 0x9b, 0x07,
+0x33, 0x43, 0x1b, 0x68, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x04, 0x29,
+0xf1, 0xd3, 0x69, 0x46, 0x8b, 0x1c, 0x07, 0x93, 0x00, 0x21, 0x08, 0x91,
+0x04, 0xae, 0x4a, 0x00, 0x07, 0x9b, 0x9b, 0x5a, 0xb2, 0x5a, 0x93, 0x42,
+0x11, 0xd0, 0x58, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xf8, 0x68,
+0x41, 0x1c, 0xf9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x20, 0x23,
+0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x80, 0x23, 0x18, 0x43, 0x38, 0x82,
+0x8f, 0xe7, 0x01, 0x31, 0x06, 0x29, 0xe4, 0xd3, 0x08, 0x99, 0x00, 0x29,
+0x0d, 0xd1, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0x04, 0xd1,
+0x39, 0x8a, 0x02, 0x23, 0x19, 0x43, 0x03, 0xe0, 0x0c, 0xe0, 0x39, 0x8a,
+0x08, 0x23, 0x19, 0x43, 0x39, 0x82, 0x29, 0x6b, 0x08, 0x18, 0x01, 0x23,
+0x9b, 0x07, 0x01, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x20, 0x76,
+0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x11, 0x30, 0x18, 0x43, 0x00, 0x68,
+0x01, 0x06, 0x09, 0x0e, 0x00, 0xe0, 0x19, 0xe0, 0x35, 0x48, 0x2a, 0x6b,
+0xc0, 0x46, 0xea, 0x62, 0x04, 0x29, 0x4f, 0xd1, 0x01, 0x21, 0xc6, 0x1d,
+0xff, 0x36, 0x5a, 0x36, 0x31, 0x72, 0x0a, 0x99, 0x02, 0x29, 0x1e, 0xd1,
+0x09, 0x99, 0x09, 0x0e, 0x49, 0x06, 0x1a, 0xd1, 0xe1, 0x1d, 0x05, 0x31,
+0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x39, 0x1a, 0xe0,
+0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68,
+0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04,
+0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1,
+0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d,
+0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60,
+0xe8, 0x6a, 0xc0, 0x46, 0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x88, 0xfc,
+0x20, 0x7e, 0x33, 0x28, 0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21,
+0x14, 0x4c, 0xc0, 0x46, 0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0,
+0x85, 0xf8, 0x28, 0x6b, 0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c,
+0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20,
+0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1,
+0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd,
+0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x70, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00,
+0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80,
+0xac, 0xab, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80,
+0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48,
+0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31,
+0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22,
+0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46,
+0x9a, 0x61, 0xfa, 0x1d, 0xff, 0x32, 0x5a, 0x32, 0x13, 0x7a, 0x1b, 0x4a,
+0x00, 0x2b, 0x0b, 0xd0, 0x15, 0x8a, 0x2e, 0x0a, 0x36, 0x02, 0x33, 0x23,
+0x2b, 0x40, 0x9b, 0x00, 0x1e, 0x43, 0xcc, 0x23, 0x2b, 0x40, 0x9b, 0x08,
+0x33, 0x43, 0x13, 0x82, 0x12, 0x8a, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x83,
+0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46,
+0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46,
+0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a,
+0x01, 0xf0, 0x32, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30,
+0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
+0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a,
+0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68,
+0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31,
+0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0,
+0x0f, 0xf8, 0x06, 0xe0, 0x32, 0x2b, 0x08, 0xd1, 0x8b, 0x70, 0x01, 0x1c,
+0x10, 0x1c, 0x00, 0xf0, 0x3c, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x20, 0x88, 0x70, 0xf9, 0xe7, 0x90, 0xb4, 0xca, 0x1d,
+0xf9, 0x32, 0x33, 0x27, 0xcc, 0x1d, 0xff, 0x34, 0x4a, 0x34, 0xd3, 0x6a,
+0xc0, 0x46, 0xa7, 0x70, 0xff, 0x31, 0x41, 0x31, 0x07, 0x6c, 0xc0, 0x46,
+0x4f, 0x61, 0xfb, 0x18, 0x39, 0x1c, 0x9f, 0x1e, 0x01, 0x23, 0x9b, 0x07,
+0xfc, 0x1c, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x9b, 0x00,
+0x1b, 0x04, 0x1b, 0x0c, 0xc9, 0x18, 0x08, 0x31, 0x01, 0x64, 0x01, 0x23,
+0x9b, 0x07, 0xb9, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x34, 0x30, 0x01, 0x76,
+0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d,
+0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43,
+0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32,
+0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d,
+0xff, 0x37, 0x4a, 0x37, 0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d,
+0xff, 0x34, 0x3a, 0x34, 0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30,
+0xe8, 0x60, 0x60, 0x69, 0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07,
+0x38, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43,
+0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63,
+0xf8, 0x1d, 0x03, 0x30, 0xff, 0xf7, 0xfc, 0xfb, 0x20, 0x62, 0xf8, 0x1d,
+0x07, 0x30, 0xff, 0xf7, 0xf7, 0xfb, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76,
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98,
+0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
+0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40,
+0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c,
+0x80, 0x23, 0x23, 0x40, 0x01, 0x9f, 0xff, 0x37, 0x41, 0x37, 0x00, 0x2b,
+0x3c, 0xd0, 0x0c, 0x23, 0x00, 0x93, 0x00, 0x23, 0x9d, 0x00, 0xae, 0x18,
+0x36, 0x69, 0x6d, 0x18, 0x6e, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3,
+0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 0x76, 0x6a, 0x6d, 0x18, 0xae, 0x62,
+0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x01, 0x9b, 0xff, 0x33, 0x51, 0x33,
+0x9b, 0x78, 0x33, 0x2b, 0x0e, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
+0x01, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23,
+0x9b, 0x07, 0xc5, 0x1d, 0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x16, 0xe0,
+0x7b, 0x69, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
+0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x7d, 0x69, 0x5d, 0x1b, 0x01, 0x23,
+0x9b, 0x07, 0xc6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0xeb, 0x18,
+0x0c, 0x3b, 0x02, 0xe0, 0x00, 0x23, 0x00, 0x93, 0x4b, 0x81, 0xcb, 0x80,
+0x63, 0x09, 0x49, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xc4, 0x1d, 0x05, 0x34,
+0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x81, 0x01, 0x23, 0x9b, 0x07,
+0xc4, 0x1d, 0x0d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0x0c, 0x89, 0x1b, 0x1b,
+0x00, 0x9c, 0x1c, 0x1b, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43,
+0x00, 0x68, 0x20, 0x18, 0x88, 0x80, 0x38, 0x6a, 0x04, 0x0e, 0xff, 0x23,
+0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 0x1c, 0x43, 0xff, 0x23, 0x1b, 0x02,
+0x03, 0x40, 0x1b, 0x02, 0x23, 0x43, 0x00, 0x06, 0x18, 0x43, 0xc8, 0x60,
+0x78, 0x6a, 0x07, 0x0e, 0xff, 0x23, 0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a,
+0x1f, 0x43, 0xff, 0x23, 0x1b, 0x02, 0x03, 0x40, 0x1b, 0x02, 0x3b, 0x43,
+0x00, 0x06, 0x18, 0x43, 0x08, 0x61, 0xd0, 0x6b, 0xc0, 0x46, 0xc8, 0x63,
+0x90, 0x6b, 0xc0, 0x46, 0x08, 0x64, 0x50, 0x6c, 0xc0, 0x46, 0x48, 0x64,
+0x10, 0x6c, 0xc0, 0x46, 0x88, 0x64, 0xd0, 0x6c, 0xc0, 0x46, 0xc8, 0x64,
+0x90, 0x6c, 0xc0, 0x46, 0x08, 0x65, 0x02, 0xe0, 0x00, 0x23, 0x0b, 0x81,
+0x8b, 0x80, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+0x0f, 0x4a, 0x93, 0x89, 0x01, 0x33, 0x93, 0x81, 0xc2, 0x1d, 0xf9, 0x32,
+0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61,
+0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b,
+0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83,
+0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xc2, 0xf8,
+0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
+0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20,
+0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30,
+0x00, 0x29, 0x15, 0xd0, 0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25,
+0x0a, 0xe0, 0xff, 0xf7, 0x89, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a,
+0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0,
+0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69,
+0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0xa8, 0xfc,
+0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x5a, 0xf8,
+0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80,
+0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x01, 0x24,
+0x00, 0x25, 0x00, 0x28, 0x0b, 0xd1, 0x38, 0x6a, 0x00, 0x28, 0x03, 0xd1,
+0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1f, 0x48, 0x01, 0x6e,
+0x01, 0x31, 0x01, 0x66, 0x03, 0xe0, 0x48, 0x68, 0xc4, 0x23, 0x18, 0x40,
+0x03, 0xd1, 0x38, 0x6a, 0x00, 0xf0, 0x0c, 0xfc, 0x2f, 0xe0, 0x38, 0x1c,
+0x00, 0xf0, 0x1c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7b, 0xfa, 0xb8, 0x68,
+0xc0, 0x08, 0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd1, 0xfb, 0xb8, 0x68,
+0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60,
+0x10, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29,
+0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46,
+0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x14, 0xf8, 0x0b, 0xe0, 0x39, 0x6a,
+0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68,
+0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c,
+0xbd, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
+0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c,
+0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68,
+0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xc3, 0xfb, 0x00, 0x20,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00,
+0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36,
+0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 0x33, 0x4c, 0x34, 0x4b,
+0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x00, 0xf0,
+0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18,
+0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
+0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d,
+0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d,
+0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30,
+0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20,
+0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3,
+0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 0x09, 0x18, 0x78, 0x68,
+0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 0x61, 0x89, 0xe2, 0x88,
+0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x5a, 0xff,
+0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43,
+0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x52, 0xff, 0x01, 0x22, 0x52, 0x04,
+0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x4a, 0xff,
+0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 0x45, 0xff, 0x01, 0x20,
+0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 0xea, 0x1d, 0xf9, 0x32,
+0x51, 0x62, 0xd9, 0xe7, 0x28, 0xac, 0x20, 0x40, 0xff, 0xff, 0x00, 0x00,
+0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00,
+0x14, 0xac, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0,
+0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21,
+0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31,
+0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 0x00, 0x68, 0x03, 0xf0,
+0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34,
+0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 0x44, 0x4a, 0x92, 0x6a,
+0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xea, 0x1d,
+0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68,
+0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 0x3c, 0x4d, 0x01, 0x2b,
+0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68,
+0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 0xc5, 0xfc, 0x20, 0x78,
+0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20,
+0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30,
+0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20,
+0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 0x01, 0x30, 0x06, 0x28,
+0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 0x11, 0x0a, 0x29, 0xd3,
+0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50,
+0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19,
+0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00,
+0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 0x06, 0x29, 0xf8, 0xd3,
+0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 0x00, 0x9d, 0x55, 0x40,
+0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 0x89, 0x6a, 0x08, 0x18,
+0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 0x51, 0x40, 0x41, 0x65,
+0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 0x38, 0x1c,
+0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x08, 0x4a, 0x50, 0x68,
+0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xa4, 0xfa,
+0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 0x01, 0xf0, 0xde, 0xfa,
+0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x6c, 0x06, 0x00, 0x80,
+0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
+0xac, 0xab, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
+0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43,
+0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07,
+0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 0x43, 0x68, 0x1c, 0x04,
+0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 0x33, 0x43, 0x1b, 0x68,
+0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 0xff, 0x26, 0x36, 0x02,
+0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c,
+0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79,
+0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89,
+0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18,
+0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
+0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3,
+0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36,
+0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18,
+0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23,
+0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c,
+0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33,
+0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b,
+0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43,
+0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
+0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x64, 0xab, 0x0e,
+0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x3d, 0x34, 0x23, 0x43,
+0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
+0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x64, 0x01, 0x23,
+0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46,
+0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x41, 0x34, 0x23, 0x43,
+0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 0x0f, 0xe0, 0xfb, 0x1f,
+0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 0xff, 0x18, 0x03, 0x69,
+0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 0x2c, 0xe0, 0x00, 0x23,
+0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 0x8b, 0x80, 0x0b, 0x81,
+0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00,
+0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 0x00, 0x20, 0x87, 0x00,
+0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43,
+0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3,
+0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23,
+0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30,
+0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2,
+0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46,
+0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68,
+0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69,
+0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc,
+0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60,
+0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 0x01, 0x61, 0xf2, 0xe7,
+0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98,
+0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27,
+0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 0x00, 0x2b, 0x19, 0xd0,
+0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18,
+0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04,
+0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0,
+0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23,
+0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b,
+0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43,
+0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68,
+0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0,
+0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0,
+0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89,
+0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68,
+0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c,
+0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46,
+0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87,
+0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b,
+0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c,
+0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 0x07, 0x9b, 0x5b, 0x89,
+0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 0x07, 0x9b, 0x9b, 0x89,
+0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00,
+0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a,
+0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 0xc0, 0x46, 0xab, 0x83,
+0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23,
+0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07,
+0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31,
+0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42,
+0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x05, 0x9b,
+0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b,
+0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33,
+0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 0xbb, 0x08, 0x9b, 0x07,
+0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b,
+0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07,
+0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95,
+0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9d, 0xc0, 0x46,
+0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 0x1b, 0x02, 0x1d, 0x43,
+0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 0x2b, 0x43, 0x55, 0x00,
+0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b,
+0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e,
+0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f,
+0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40,
+0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c,
+0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78,
+0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3,
+0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00,
+0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33,
+0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93,
+0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35,
+0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68,
+0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0,
+0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1,
+0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46,
+0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b,
+0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46,
+0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61,
+0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83,
+0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68,
+0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68,
+0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48,
+0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0,
+0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98,
+0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xe1, 0xff, 0x68, 0x46,
+0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0,
+0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43,
+0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x84, 0xfe,
+0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
+0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46,
+0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68,
+0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68,
+0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69,
+0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28,
+0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7,
+0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60,
+0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22,
+0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 0x03, 0x23, 0xfc, 0x1d,
+0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68,
+0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68,
+0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62,
+0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60,
+0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64,
+0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
+0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
+0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23,
+0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0x20, 0x6b, 0x01, 0x30,
+0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69,
+0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29,
+0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68,
+0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c,
+0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe,
+0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29,
+0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0,
+0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46,
+0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31,
+0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1,
+0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 0x00, 0x28, 0x03, 0xd0,
+0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 0x30, 0x7b, 0x00, 0x28,
+0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 0x1b, 0x23, 0xdb, 0x01,
+0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 0xe0, 0x6a, 0xb0, 0x42,
+0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3,
+0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30,
+0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x90, 0xff,
+0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60,
+0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xe0, 0x6b,
+0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0x07, 0xfc, 0x02, 0x23,
+0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60,
+0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0x64, 0x2d, 0x00, 0x80,
+0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x1d, 0x48,
+0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 0x09, 0x31, 0x01, 0x27,
+0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 0xa3, 0x42, 0x10, 0xd0,
+0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 0x00, 0x2b, 0x0a, 0xd0,
+0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 0x13, 0x4b, 0xc0, 0x46,
+0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 0x93, 0x82, 0xc3, 0x8b,
+0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 0x0e, 0xdb, 0x84, 0x8a,
+0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 0x44, 0x8a, 0xc5, 0x8a,
+0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 0x4f, 0x70, 0x43, 0x82,
+0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 0x51, 0x82, 0x80, 0x8a,
+0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 0xe8, 0x0e, 0x00, 0x80,
+0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0,
+0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20,
+0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06,
+0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00,
+0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00,
+0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28,
+0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46,
+0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3,
+0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73,
+0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c,
+0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06,
+0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9,
+0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0,
+0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22,
+0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9,
+0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18,
+0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d,
+0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 0x08, 0xd0, 0x8b, 0x00,
+0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e,
+0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0,
+0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 0x01, 0x30, 0x00, 0x06,
+0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4,
+0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a,
+0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70,
+0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72,
+0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a,
+0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47,
+0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48,
+0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61,
+0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c,
+0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18,
+0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 0x61, 0xfe, 0x08, 0xbc,
+0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40,
+0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x95, 0x4a, 0xd0, 0x68,
+0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 0x38, 0x89, 0x00, 0x28,
+0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60,
+0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 0x8e, 0x48, 0xc3, 0x6b,
+0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xd4, 0x18,
+0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 0x81, 0x42, 0x05, 0xd1,
+0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf3, 0xe0,
+0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 0x01, 0x20, 0x00, 0x21,
+0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 0x58, 0x70, 0xb9, 0x82,
+0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x05, 0x93, 0x5b, 0x69,
+0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 0xc0, 0x46, 0x39, 0x61,
+0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c,
+0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 0x05, 0xd1, 0x3b, 0x2a,
+0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x73,
+0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68,
+0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x09, 0x04,
+0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 0x09, 0x06, 0x09, 0x0e,
+0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46,
+0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32,
+0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 0xb3, 0x07, 0x1a, 0x43,
+0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20,
+0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b,
+0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 0x01, 0x20, 0x09, 0x01,
+0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 0x65, 0xd1, 0x51, 0x49,
+0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 0x48, 0x69, 0x01, 0x30,
+0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
+0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 0x22, 0x6a, 0xa3, 0x6b,
+0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 0x22, 0x6b, 0xc0, 0x46,
+0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 0x00, 0x22, 0xfa, 0x61,
+0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 0x01, 0x22, 0x00, 0xe0,
+0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 0x7a, 0x68, 0xc0, 0x46,
+0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0xb0, 0x83,
+0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 0x60, 0x20, 0xb0, 0x83,
+0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 0x9a, 0x42, 0x03, 0xd8,
+0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 0x21, 0x6b, 0xc0, 0x46,
+0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 0x2d, 0x49, 0x78, 0x6b,
+0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 0xc0, 0x46, 0xfa, 0x60,
+0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 0xc0, 0x46, 0xb8, 0x61,
+0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 0x37, 0xf9, 0x04, 0x98,
+0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 0x78, 0x8a, 0xf1, 0x8b,
+0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 0x04, 0xe0, 0x38, 0xe0,
+0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 0x81, 0x07, 0x02, 0xd0,
+0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 0x09, 0x1a, 0xa2, 0x6b,
+0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 0x20, 0x62, 0xe8, 0x7b,
+0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 0x05, 0x99, 0x48, 0x69,
+0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 0x73, 0xfa, 0x18, 0x48,
+0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 0x0a, 0xd1, 0x20, 0x6a,
+0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 0x88, 0x42, 0x03, 0xd0,
+0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x40, 0x04,
+0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 0xe0, 0x68, 0x00, 0x28,
+0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 0xa8, 0x73, 0xed, 0xe7,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xa4, 0x2a, 0x00, 0x80,
+0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55,
+0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 0xc4, 0x0b, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89,
+0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c,
+0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2,
+0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31,
+0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b,
+0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0xb3, 0xf8, 0x01, 0x20,
+0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x18, 0x1a, 0x00, 0x80,
+0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c,
+0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89,
+0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7,
+0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 0x00, 0x09, 0x1f, 0xd3,
+0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a,
+0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
+0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
+0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0,
+0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 0x46, 0xe0, 0x01, 0x30,
+0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 0x5c, 0x18, 0xe4, 0x88,
+0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
+0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 0xd8, 0x42, 0xf0, 0xdc,
+0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 0x0b, 0x23, 0x1b, 0x02,
+0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x98,
+0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 0x9b, 0x01,
+0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 0x17, 0xd0, 0xfe, 0x1d,
+0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18,
+0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7b, 0xfc, 0x01, 0x28,
+0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 0x9b, 0x01,
+0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 0x01, 0x2a,
+0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0xf8, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
+0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
+0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89,
+0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08,
+0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 0x38, 0x1c, 0x00, 0xf0,
+0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c,
+0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47,
+0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04,
+0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29,
+0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43,
+0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c,
+0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0,
+0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68,
+0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91,
+0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab,
+0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43,
+0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69,
+0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b,
+0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a,
+0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26,
+0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0,
+0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0,
+0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42,
+0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43,
+0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43,
+0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43,
+0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a,
+0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68,
+0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43,
+0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43,
+0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43,
+0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68,
+0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c,
+0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c,
+0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c,
+0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 0x91, 0x42, 0x00, 0xdd,
+0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d,
+0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 0x33, 0x4a, 0xc0, 0x46,
+0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 0xe1, 0x6d, 0x41, 0x18,
+0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0,
+0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 0xb1, 0x6a, 0x81, 0x42,
+0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 0x2f, 0x23, 0x9b, 0x01,
+0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 0x92, 0x00, 0x27, 0x4b,
+0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 0x4a, 0x08, 0x05, 0xd3,
+0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd6, 0xff,
+0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x0b, 0x78, 0x00, 0x2b,
+0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 0x1e, 0x4a, 0xc0, 0x46,
+0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce,
+0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 0xc7, 0xfe, 0x14, 0x48,
+0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 0x00, 0xd3, 0x25, 0x60,
+0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 0x3a, 0x6b, 0xc0, 0x46,
+0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x68, 0x00, 0x29,
+0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0x04, 0xe0, 0x39, 0x6b,
+0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0xc1, 0x60,
+0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00,
+0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
+0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02,
+0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35,
+0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 0x01, 0x38, 0x78, 0x61,
+0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0xb8, 0x60,
+0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa,
+0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71,
+0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1b, 0x00, 0x80,
+0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40,
+0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47,
+0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08,
+0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30,
+0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x23,
+0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 0x00, 0x68, 0x16, 0x4c,
+0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68,
+0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 0x00, 0xf0, 0x22, 0xf8,
+0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21,
+0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 0xf2, 0xd0, 0x51, 0x21,
+0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 0x02, 0xd1, 0x60, 0x6b,
+0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xf7, 0xe7,
+0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 0x01, 0x23, 0x9b, 0x07,
+0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c,
+0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00,
+0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 0x4b, 0x6b, 0x9a, 0x42,
+0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
+0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0,
+0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
+0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49,
+0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20,
+0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68,
+0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 0xdf, 0xfd, 0x88, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 0xf5, 0x2c, 0xff, 0xff,
+0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
+0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60,
+0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x4c, 0xfc,
+0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0,
+0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18,
+0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23,
+0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48,
+0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 0x35, 0x4d, 0x10, 0x29,
+0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e,
+0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x68, 0x6a,
+0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2,
+0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 0x68, 0x6a, 0xb8, 0x42,
+0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b,
+0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49,
+0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c,
+0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 0x09, 0x6e, 0x8c, 0x18,
+0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b,
+0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18,
+0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31,
+0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 0x52, 0x05, 0x3a, 0x43,
+0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18,
+0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 0x02, 0xf0, 0x4a, 0xfd,
+0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 0xe9, 0x6a, 0x2a, 0x6b,
+0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66,
+0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 0x68, 0x0e, 0x00, 0x80,
+0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x5d, 0x2e, 0xff, 0xff,
+0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40,
+0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 0xd1, 0x60, 0x02, 0x23,
+0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0x90, 0xee, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x01, 0x20, 0x80, 0x02,
+0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23,
+0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c,
+0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 0x68, 0x46, 0x00, 0xf0,
+0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30,
+0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73,
+0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0,
+0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23,
+0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21,
+0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40,
+0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f,
+0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b,
+0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18,
+0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 0x04, 0x68, 0xc0, 0x46,
+0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46,
+0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0x08, 0x69,
+0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 0x38, 0x6a, 0xc0, 0x46,
+0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 0x18, 0x1c, 0x90, 0xbc,
+0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 0xc8, 0x69, 0x19, 0x23,
+0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b,
+0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 0xca, 0x61, 0x70, 0x47,
+0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 0x40, 0x32, 0x00, 0x29,
+0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0xd0, 0x61,
+0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68,
+0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69,
+0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00,
+0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21,
+0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a,
+0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23,
+0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07,
+0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0,
+0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 0x04, 0x29, 0xe4, 0xd3,
+0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0,
+0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a,
+0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40,
+0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 0xa3, 0x40, 0x00, 0x25,
+0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 0x5d, 0xd9, 0x1c, 0x1c,
+0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96,
+0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92,
+0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 0x05, 0x9c, 0xe3, 0x40,
+0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c,
+0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23,
+0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
+0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d,
+0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96,
+0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68,
+0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36,
+0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23,
+0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b,
+0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14,
+0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0,
+0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a,
+0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
+0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28,
+0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x2b, 0xf8, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f,
+0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3,
+0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0xde, 0xfe,
+0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20,
+0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28,
+0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60,
+0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28,
+0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28,
+0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7,
+0xb9, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3,
+0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79,
+0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x8c, 0x06, 0x00, 0x80,
+0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
+0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46,
+0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
+0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a,
+0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65,
+0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18,
+0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18,
+0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d,
+0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xfc, 0xf7, 0xca, 0xff,
+0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
+0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 0x01, 0xf0, 0xc6, 0xfb,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20,
+0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x59, 0xfc, 0x07, 0x1c,
+0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01,
+0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46,
+0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d,
+0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 0x89, 0xf9, 0x38, 0x1c,
+0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80,
+0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68,
+0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59,
+0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42,
+0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c,
+0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31,
+0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 0x5d, 0xfc, 0xf8, 0x6d,
+0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02,
+0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73,
+0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x4c, 0xfc, 0xb8, 0x6d, 0xc0, 0x46,
+0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2,
+0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xcc, 0xfc,
+0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0,
+0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64,
+0x20, 0x1c, 0xfc, 0xf7, 0x31, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43,
+0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c,
+0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07,
+0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68,
+0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31,
+0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19,
+0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18,
+0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42,
+0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a,
+0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
+0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
+0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0,
+0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62,
+0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c,
+0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0,
+0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18,
+0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9,
+0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
+0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 0x82, 0x42, 0xf3, 0xd8,
+0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40,
+0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68,
+0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x78, 0x6c,
+0xfc, 0xf7, 0x95, 0xff, 0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c,
+0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04,
+0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
+0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
+0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c,
+0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68,
+0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0,
+0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7,
+0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69,
+0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40,
+0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68,
+0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c,
+0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c,
+0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c,
+0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 0x7d, 0x4e, 0x0b, 0x23,
+0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25,
+0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 0x00, 0x28, 0x12, 0xd0,
+0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x68,
+0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 0x01, 0x35, 0xa8, 0x00,
+0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x68, 0x00, 0x28,
+0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68,
+0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c,
+0x28, 0x1c, 0xfc, 0xf7, 0x10, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e,
+0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18,
+0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88,
+0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04,
+0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
+0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
+0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89,
+0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61,
+0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46,
+0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60,
+0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 0xe8, 0xfe, 0x38, 0x86,
+0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 0x03, 0xff, 0x78, 0x86,
+0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 0xc8, 0xfe, 0x00, 0x90,
+0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04,
+0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02,
+0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42,
+0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02,
+0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c,
+0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xa3, 0xfe,
+0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 0x9e, 0xfe, 0x06, 0x1c,
+0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
+0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c,
+0xfc, 0xf7, 0x8f, 0xfe, 0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61,
+0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22,
+0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02,
+0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c,
+0xfc, 0xf7, 0x77, 0xfe, 0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61,
+0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69,
+0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7,
+0x66, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08,
+0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04,
+0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46,
+0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c,
+0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81,
+0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
+0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69,
+0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98,
+0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18,
+0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1,
+0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61,
+0x04, 0x98, 0xfc, 0xf7, 0x09, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69,
+0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42,
+0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a,
+0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62,
+0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1,
+0x38, 0x1c, 0xfc, 0xf7, 0x19, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60,
+0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68,
+0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c,
+0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68,
+0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c,
+0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98,
+0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e,
+0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
+0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
+0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x20, 0x8e,
+0xfc, 0xf7, 0xcb, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 0x02, 0x99, 0xfc, 0xf7,
+0xc6, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02,
+0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46,
+0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xb7, 0xfd, 0x61, 0x69, 0x01, 0x31,
+0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e,
+0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
+0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
+0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x71, 0x60, 0x03, 0x98,
+0xfc, 0xf7, 0x9b, 0xfd, 0x21, 0x69, 0x49, 0x19, 0x21, 0x61, 0xa1, 0x68,
+0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43,
+0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x8d, 0xfd, 0x38, 0x82, 0x61, 0x6e,
+0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99,
+0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d,
+0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38,
+0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68,
+0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04,
+0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46,
+0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
+0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04,
+0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x51, 0xfd, 0x40, 0xc7, 0x02, 0x9a,
+0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29,
+0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c,
+0x16, 0x1c, 0xfc, 0xf7, 0x40, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e,
+0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32,
+0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0,
+0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5,
+0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b,
+0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99,
+0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0,
+0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91,
+0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42,
+0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a,
+0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88,
+0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21,
+0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06,
+0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1,
+0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a,
+0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c,
+0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 0x07, 0x9b, 0x01, 0xf0,
+0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0,
+0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8,
+0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90,
+0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60,
+0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 0x01, 0x98, 0x01, 0x38,
+0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 0x44, 0x63, 0x01, 0x98,
+0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0,
+0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92,
+0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x09, 0x9b, 0x01, 0xf0,
+0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02,
+0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07,
+0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0x85, 0xfc,
+0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68,
+0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 0x8b, 0xf9, 0x38, 0x1c,
+0xfc, 0xf7, 0x8c, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3,
+0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80,
+0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71,
+0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60,
+0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 0x49, 0x08, 0x49, 0x00,
+0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 0x38, 0x1c, 0x00, 0xf0,
+0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43,
+0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8,
+0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c,
+0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0,
+0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68,
+0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68,
+0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42,
+0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 0x31, 0x1c, 0x01, 0x3e,
+0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
+0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60,
+0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68,
+0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47,
+0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68,
+0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46,
+0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80,
+0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46,
+0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80,
+0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
+0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
+0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b,
+0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7,
+0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7,
+0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb,
+0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xee, 0xe7,
+0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
+0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
+0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43,
+0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88,
+0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47,
+0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xf8, 0xe7, 0x00, 0x00,
+0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c,
+0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33,
+0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68,
+0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1,
+0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18,
+0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20,
+0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60,
+0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46,
+0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a,
+0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80,
+0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7,
+0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23,
+0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55,
+0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 0x7c, 0x29, 0x00, 0x80,
+0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
+0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40,
+0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18,
+0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08,
+0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c,
+0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d,
+0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65,
+0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68,
+0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60,
+0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20,
+0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c,
+0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80,
+0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x38, 0x1c, 0xfc, 0xf7, 0x07, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18,
+0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63,
+0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27,
+0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 0x42, 0x63, 0x00, 0x2a,
+0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 0xc0, 0x6a, 0x01, 0xf0,
+0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 0x38, 0x01, 0x00, 0x19,
+0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1,
+0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x90, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x0f, 0x49, 0xc8, 0x68,
+0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 0x02, 0x89, 0x00, 0x2a,
+0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 0x00, 0x2a, 0x0d, 0xd1,
+0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 0x02, 0x23, 0x0a, 0x68,
+0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 0x01, 0x21, 0x00, 0xe0,
+0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x01, 0x23, 0xf8, 0x1d,
+0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 0x79, 0x32, 0x54, 0x8a,
+0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 0xac, 0x42, 0x04, 0xdb,
+0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 0xd1, 0x83, 0x01, 0x23,
+0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61,
+0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46,
+0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0x61, 0x41, 0x69,
+0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 0x00, 0x05, 0xc1, 0x60,
+0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a,
+0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8,
+0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3,
+0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23,
+0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e,
+0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1,
+0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72,
+0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 0x00, 0x20, 0xf8, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49,
+0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31,
+0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x63,
+0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22,
+0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1,
+0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18,
+0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92,
+0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0,
+0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e,
+0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x73, 0xfc, 0x20, 0x6b,
+0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8,
+0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7,
+0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80,
+0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49,
+0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a,
+0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7,
+0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a,
+0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x2d, 0xff, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x64, 0x2d, 0x00, 0x80,
+0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49,
+0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48,
+0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31,
+0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x61, 0x6b,
+0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 0x78, 0x68, 0x80, 0x00,
+0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 0x01, 0x23, 0x78, 0x68,
+0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f,
+0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1,
+0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
+0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68,
+0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7,
+0x59, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31,
+0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49,
+0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0,
+0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0,
+0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09,
+0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62,
+0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0,
+0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a,
+0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19,
+0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a,
+0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62,
+0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62,
+0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1,
+0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42,
+0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19,
+0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0,
+0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38,
+0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
+0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90,
+0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0xc0, 0x6a, 0xc0, 0x46,
+0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46,
+0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60,
+0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46,
+0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a,
+0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46,
+0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3,
+0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20,
+0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0,
+0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30,
+0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61,
+0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 0x38, 0x1c, 0x5c, 0xe3,
+0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c,
+0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07,
+0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06,
+0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1,
+0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2,
+0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0,
+0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c,
+0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68,
+0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49,
+0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0,
+0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 0x7a, 0x68, 0xc0, 0x46,
+0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49,
+0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c,
+0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a,
+0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c,
+0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61,
+0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69,
+0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a,
+0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28,
+0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f,
+0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92,
+0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48,
+0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80,
+0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60,
+0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a,
+0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64,
+0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18,
+0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30,
+0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61,
+0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88,
+0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0,
+0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93,
+0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68,
+0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46,
+0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46,
+0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49,
+0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0,
+0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71,
+0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37,
+0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
+0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18,
+0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x7d, 0xfb, 0x01, 0x9a,
+0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65,
+0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20,
+0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8,
+0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07,
+0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99,
+0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c,
+0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c,
+0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 0x41, 0x49, 0x00, 0x20,
+0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b,
+0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
+0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a,
+0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b,
+0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98,
+0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90,
+0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
+0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20,
+0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90,
+0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42,
+0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90,
+0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98,
+0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42,
+0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20,
+0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1,
+0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0,
+0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb,
+0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29,
+0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a,
+0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90,
+0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98,
+0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 0x01, 0x49, 0xff, 0xff,
+0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80,
+0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 0x60, 0x04, 0x00, 0x80,
+0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x55, 0x32, 0xff, 0xff,
+0xac, 0x5e, 0x21, 0x40, 0x0d, 0x3d, 0xff, 0xff, 0xcd, 0x31, 0xff, 0xff,
+0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
+0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98,
+0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1,
+0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98,
+0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48,
+0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x51, 0xf9, 0x00, 0x20,
+0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b,
+0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c,
+0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a,
+0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80,
+0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98,
+0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9,
+0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09,
+0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a,
+0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a,
+0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a,
+0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2,
+0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92,
+0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
+0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40,
+0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22,
+0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d,
+0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x02, 0x90,
+0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06,
+0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a,
+0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d,
+0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37,
+0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa,
+0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46,
+0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99,
+0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0,
+0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23,
+0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07,
+0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b,
+0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0,
+0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98,
+0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92,
+0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
+0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28,
+0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20,
+0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92,
+0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20,
+0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42,
+0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98,
+0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90,
+0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04,
+0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0,
+0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e,
+0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b,
+0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x89, 0xf9, 0x01, 0x9a,
+0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63,
+0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68,
+0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04,
+0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68,
+0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92,
+0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d,
+0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d,
+0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42,
+0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5,
+0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69,
+0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a,
+0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28,
+0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c,
+0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61,
+0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61,
+0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61,
+0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xcc, 0xfa,
+0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18,
+0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80,
+0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0x68, 0x0e, 0x00, 0x80,
+0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
+0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0,
+0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68,
+0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18,
+0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0,
+0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e,
+0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 0x19, 0x43, 0xe9, 0x63,
+0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e,
+0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0xa9, 0x6b,
+0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 0xa8, 0x63, 0x01, 0x20,
+0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xe8, 0x63,
+0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18,
+0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c,
+0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0,
+0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x06, 0xfc, 0x20, 0x1c, 0x00, 0xf0,
+0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0,
+0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30,
+0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c,
+0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68,
+0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a,
+0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42,
+0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 0xf8, 0xe7, 0x78, 0x68,
+0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7,
+0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90,
+0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x80, 0x69,
+0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23,
+0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
+0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23,
+0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0,
+0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0,
+0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0,
+0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18,
+0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68,
+0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 0x00, 0x2d, 0x13, 0xd0,
+0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43,
+0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68,
+0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xdf, 0xfe, 0xb8, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7,
+0x90, 0xee, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 0xf8, 0x0e, 0x00, 0x80,
+0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
+0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0xc8, 0x60,
+0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68,
+0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47,
+0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40,
+0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a,
+0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46,
+0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c,
+0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18,
+0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68,
+0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60,
+0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32,
+0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61,
+0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c,
+0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff,
+0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 0x01, 0x20, 0xf9, 0x1d,
+0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61,
+0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48,
+0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe,
+0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02,
+0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68,
+0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9,
+0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00,
+0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00,
+0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02,
+0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71,
+0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
+0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18,
+0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49,
+0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0xe4, 0x2d, 0x00, 0x80,
+0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71,
+0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00,
+0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d,
+0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c,
+0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42,
+0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9,
+0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30,
+0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8,
+0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8,
+0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7,
+0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58,
+0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08,
+0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68,
+0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9,
+0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0,
+0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40,
+0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40,
+0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04,
+0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a,
+0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68,
+0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00,
+0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69,
+0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c,
+0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79,
+0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30,
+0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7,
+0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x04, 0x00, 0x80,
+0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
+0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68,
+0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
+0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21,
+0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a,
+0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68,
+0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c,
+0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28,
+0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0,
+0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
+0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b,
+0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18,
+0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63,
+0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b,
+0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00,
+0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
+0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24,
+0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68,
+0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60,
+0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b,
+0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19,
+0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b,
+0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f,
+0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68,
+0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c,
+0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80,
+0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2e, 0x4b,
+0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62,
+0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c,
+0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31,
+0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29,
+0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c,
+0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00,
+0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61,
+0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3,
+0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 0x3a, 0x6f, 0xfd, 0x68,
+0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 0xdb, 0x6d, 0x5b, 0x08,
+0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 0xfd, 0x6f, 0x03, 0x3b,
+0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 0x0b, 0x81, 0x10, 0x60,
+0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 0x00, 0xd0, 0x01, 0x38,
+0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 0x00, 0xd8, 0x07, 0x4a,
+0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 0x82, 0x61, 0x3a, 0x67,
+0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
+0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
+0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49,
+0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f,
+0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 0x00, 0x19, 0xe1, 0x60,
+0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28,
+0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69,
+0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0,
+0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0x65, 0x60, 0x20, 0x68,
+0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80,
+0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23,
+0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b,
+0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 0x02, 0x68, 0x15, 0x68,
+0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2,
+0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07,
+0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47,
+0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3,
+0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68,
+0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60,
+0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d,
+0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f,
+0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d,
+0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d,
+0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60,
+0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e,
+0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20,
+0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a,
+0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68,
+0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60,
+0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46,
+0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1,
+0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69,
+0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a,
+0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d,
+0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b,
+0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68,
+0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
+0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47,
+0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5,
+0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a,
+0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5,
+0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5,
+0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
+0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5,
+0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55,
+0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5,
+0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
+0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5,
+0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 0x02, 0x36, 0x83, 0xe3,
+0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 0xf2, 0xff, 0xff, 0x1a,
+0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 0x01, 0x06, 0x1c, 0xe3,
+0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 0x02, 0xc6, 0xcc, 0xe3,
+0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 0x50, 0x10, 0x91, 0xe5,
+0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5,
+0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a,
+0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 0x94, 0x00, 0x00, 0xe0,
+0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5,
+0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3,
+0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5,
+0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
+0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1,
+0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a,
+0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2,
+0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2,
+0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3,
+0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2,
+0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea,
+0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8,
+0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1,
+0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3,
+0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
+0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3,
+0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1,
+0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9,
+0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3,
+0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
+0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5,
+0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b,
+0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3,
+0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b,
+0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3,
+0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b,
+0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3,
+0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5,
+0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5,
+0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1,
+0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a,
+0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
+0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
+0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15,
+0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x04, 0x14, 0xe3,
+0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11,
+0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11,
+0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
+0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 0x04, 0x00, 0x14, 0xe3,
+0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3,
+0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3,
+0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x02, 0x14, 0xe3,
+0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3,
+0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3,
+0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b,
+0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b,
+0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2,
+0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2,
+0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea,
+0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
+0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5,
+0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
+0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
+0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5,
+0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
+0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
+0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5,
+0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5,
+0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5,
+0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba,
+0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5,
+0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7,
+0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5,
+0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5,
+0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5,
+0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5,
+0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3,
+0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
+0xcc, 0x04, 0x00, 0x80, 0x71, 0x2b, 0xff, 0xff, 0xd1, 0x3d, 0xff, 0xff,
+0xc9, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08,
+0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68,
+0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
+0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0,
+0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1,
+0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2,
+0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5,
+0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 0x74, 0x10, 0x9f, 0xe5,
+0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5,
+0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2,
+0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea,
+0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x4c, 0x00, 0x9f, 0xe5,
+0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5,
+0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a,
+0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a,
+0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80,
+0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80,
+0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
+0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00,
+0x71, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea,
+0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00,
+0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x6b, 0xea, 0xff, 0xea,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0x28, 0x04, 0x00, 0x00, 0xf8, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80,
+0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54,
+0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00,
+0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff,
+0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 0x01, 0xff, 0x04, 0x00,
+0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
+0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
+0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff,
+0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x3d, 0x50, 0xff, 0xff, 0x81, 0x50, 0xff, 0xff,
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x48, 0x05, 0x00, 0x80, 0x11, 0x75, 0x21, 0x40, 0x1b, 0x75, 0x21, 0x40,
+0x31, 0x75, 0x21, 0x40, 0x49, 0x75, 0x21, 0x40,
+0x55, 0x75, 0x21, 0x40, 0x63, 0x75, 0x21, 0x40, 0x7d, 0x75, 0x21, 0x40,
+0xa9, 0x75, 0x21, 0x40, 0x6d, 0x76, 0x21, 0x40, 0xc5, 0x76, 0x21, 0x40,
+0xd3, 0x76, 0x21, 0x40, 0xdd, 0x76, 0x21, 0x40, 0xe7, 0x76, 0x21, 0x40,
+0x99, 0x77, 0x21, 0x40, 0xa7, 0x77, 0x21, 0x40, 0xb5, 0x77, 0x21, 0x40,
+0x61, 0x78, 0x21, 0x40, 0x5f, 0x7c, 0x21, 0x40, 0xe9, 0x7c, 0x21, 0x40,
+0x89, 0x7d, 0x21, 0x40, 0xbd, 0x7e, 0x21, 0x40, 0xc9, 0x7e, 0x21, 0x40,
+0x29, 0x7f, 0x21, 0x40, 0x8d, 0x7f, 0x21, 0x40, 0xb9, 0x7f, 0x21, 0x40,
+0xdd, 0x7f, 0x21, 0x40, 0x1d, 0x80, 0x21, 0x40, 0x45, 0x80, 0x21, 0x40,
+0x8d, 0x80, 0x21, 0x40, 0x9d, 0x80, 0x21, 0x40, 0xc5, 0x80, 0x21, 0x40,
+0xd5, 0x80, 0x21, 0x40, 0x1d, 0x81, 0x21, 0x40, 0x5b, 0x81, 0x21, 0x40,
+0xb1, 0x81, 0x21, 0x40, 0x11, 0x82, 0x21, 0x40, 0x1b, 0x82, 0x21, 0x40,
+0x1f, 0x82, 0x21, 0x40, 0x8d, 0x82, 0x21, 0x40, 0xd9, 0x82, 0x21, 0x40,
+0x31, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0xd1, 0x83, 0x21, 0x40,
+0x09, 0x84, 0x21, 0x40, 0x19, 0x84, 0x21, 0x40, 0x51, 0x84, 0x21, 0x40,
+0x61, 0x84, 0x21, 0x40, 0x75, 0x84, 0x21, 0x40, 0x9d, 0x84, 0x21, 0x40,
+0xa7, 0x84, 0x21, 0x40, 0xb1, 0x84, 0x21, 0x40, 0x15, 0x85, 0x21, 0x40,
+0x45, 0x85, 0x21, 0x40, 0x51, 0x85, 0x21, 0x40, 0xc5, 0x85, 0x21, 0x40,
+0xcf, 0x85, 0x21, 0x40, 0xd9, 0x85, 0x21, 0x40, 0xe3, 0x85, 0x21, 0x40,
+0xed, 0x85, 0x21, 0x40, 0xf7, 0x85, 0x21, 0x40, 0x01, 0x86, 0x21, 0x40,
+0x0b, 0x86, 0x21, 0x40, 0x15, 0x86, 0x21, 0x40, 0x01, 0x89, 0x21, 0x40,
+0x1f, 0x86, 0x21, 0x40, 0x29, 0x86, 0x21, 0x40, 0x33, 0x86, 0x21, 0x40,
+0x3d, 0x86, 0x21, 0x40, 0x65, 0x86, 0x21, 0x40, 0x6f, 0x86, 0x21, 0x40,
+0xd1, 0x86, 0x21, 0x40, 0xdb, 0x86, 0x21, 0x40, 0xe5, 0x86, 0x21, 0x40,
+0xef, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+0x03, 0x87, 0x21, 0x40, 0x69, 0x87, 0x21, 0x40, 0xb5, 0x87, 0x21, 0x40,
+0xf9, 0x87, 0x21, 0x40, 0x09, 0x88, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+0x55, 0x88, 0x21, 0x40, 0x59, 0x88, 0x21, 0x40, 0x5d, 0x88, 0x21, 0x40,
+0xb5, 0x88, 0x21, 0x40, 0xdd, 0x88, 0x21, 0x40, 0xe9, 0x88, 0x21, 0x40,
+0xed, 0x88, 0x21, 0x40, 0xf1, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40,
+0xf9, 0x88, 0x21, 0x40, 0xfd, 0x88, 0x21, 0x40, 0x2d, 0x85, 0x21, 0x40,
+0x89, 0x85, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+0x0d, 0x89, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0xe1, 0x74, 0x21, 0x40,
+0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
+0x6b, 0x78, 0x21, 0x40, 0xf5, 0x7b, 0x21, 0x40, 0x31, 0x7c, 0x21, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40,
+0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40,
+0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40,
+0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00,
+0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
+0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
+0xd1, 0xa8, 0x21, 0x40, 0x2d, 0xaa, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
+0x89, 0x70, 0x21, 0x40, 0xc9, 0xa1, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x57, 0x89, 0x21, 0x40, 0xd1, 0xa8, 0x21, 0x40, 0xc5, 0x2f, 0xff, 0xff,
+0x05, 0x21, 0xff, 0xff, 0xef, 0x20, 0xff, 0xff, 0x59, 0xa7, 0x21, 0x40,
+0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 0x5c, 0x2e, 0x00, 0x80,
+0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 0x00, 0x30, 0x37, 0x2f,
+0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35,
+0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
+0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43,
+0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
+0x6f, 0x6e, 0x0a, 0x00, 0x08, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x53, 0xff, 0xff,
+0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00,
+0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
+0x69, 0x3e, 0xff, 0xff, 0xc9, 0x4f, 0xff, 0xff, 0xd5, 0x24, 0xff, 0xff,
+0xc9, 0x3b, 0xff, 0xff, 0x29, 0x3c, 0xff, 0xff, 0x19, 0x1a, 0xff, 0xff,
+0x65, 0x11, 0xff, 0xff, 0xcc, 0x53, 0xff, 0xff, 0x21, 0x40, 0xff, 0xff,
+0x89, 0x70, 0x21, 0x40, 0x49, 0x72, 0x21, 0x40, 0xd9, 0x3f, 0xff, 0xff,
+0x21, 0x9a, 0x21, 0x40, 0x85, 0x24, 0xff, 0xff, 0x64, 0x53, 0xff, 0xff,
+0x8c, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+0x00, 0x00, 0x20, 0x40, 0xb0, 0x50, 0x00, 0x00, 0x7b, 0x0e, 0x00, 0x00,
+0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xed, 0x89, 0x21, 0x40, 0x8b, 0x89, 0x21, 0x40, 0xa5, 0x8c, 0x21, 0x40,
+0x05, 0x8d, 0x21, 0x40, 0xcd, 0x8d, 0x21, 0x40, 0x8b, 0x8b, 0x21, 0x40,
+0xa9, 0x8e, 0x21, 0x40, 0x15, 0x8f, 0x21, 0x40, 0x69, 0x8b, 0x21, 0x40,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x59, 0xbd, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x2d, 0xbe, 0x21, 0x40,
+0x00, 0x20, 0x0a, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23,
+0x9b, 0x01, 0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32,
+0xc8, 0x60, 0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x03, 0x48, 0xc0, 0x46,
+0x48, 0x60, 0x88, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c,
+0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xde, 0xff, 0x68, 0x49, 0x0b, 0x23,
+0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40,
+0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61,
+0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a,
+0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68,
+0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20,
+0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xd4, 0xfa, 0xf8, 0x68, 0x00, 0x28,
+0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23,
+0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95,
+0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0,
+0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 0x9b, 0x5c, 0x1e, 0x1c,
+0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 0x5b, 0x78, 0x83, 0x42,
+0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 0x03, 0x9d, 0xed, 0x6a,
+0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 0xeb, 0x62, 0x53, 0x68,
+0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 0x86, 0x42, 0x0a, 0xd1,
+0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 0x9b, 0x00, 0x3c, 0x4e,
+0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 0x9d, 0x61, 0x53, 0x78,
+0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 0x5d, 0x1c, 0x01, 0x95,
+0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xeb, 0x18,
+0xda, 0x60, 0x3a, 0x69, 0x01, 0x32, 0x3a, 0x61, 0x64, 0x00, 0x01, 0x31,
+0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xb8, 0xd3, 0x00, 0x20,
+0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02,
+0xc9, 0x18, 0x88, 0x61, 0x01, 0x9b, 0x99, 0x00, 0x89, 0x18, 0x2d, 0x23,
+0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1,
+0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69,
+0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0,
+0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 0x03, 0xd2, 0x30, 0x20,
+0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 0x78, 0x69, 0x00, 0x28,
+0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 0x78, 0x61, 0x00, 0x20,
+0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0,
+0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78,
+0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 0x9b, 0x00, 0x9e, 0x19,
+0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00,
+0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3,
+0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01,
+0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0x30, 0x53, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80,
+0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46,
+0x18, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
+0x10, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
+0x08, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x38, 0x52, 0xff, 0xff,
+0x88, 0x51, 0xff, 0xff, 0xd5, 0xb0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20,
+0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01,
+0xf8, 0x18, 0x05, 0x73, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20,
+0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0,
+0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
+0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20,
+0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 0xc3, 0xff, 0x00, 0x28,
+0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61,
+0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61,
+0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80,
+0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
+0x7d, 0x71, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48,
+0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42,
+0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18,
+0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92,
+0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7,
+0x8d, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92,
+0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x82, 0xff,
+0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x7c, 0x29, 0x00, 0x80,
+0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
+0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68,
+0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 0x63, 0xff, 0x01, 0x20,
+0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c,
+0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29,
+0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1,
+0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0,
+0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff,
+0x22, 0xe0, 0x09, 0x01, 0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a,
+0x17, 0x49, 0xff, 0xf7, 0x35, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73,
+0x04, 0x23, 0xa8, 0x69, 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61,
+0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60,
+0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0,
+0x17, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0,
+0x02, 0x23, 0xf8, 0x6b, 0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00,
+0x28, 0x05, 0x00, 0x80, 0xa5, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0,
+0x68, 0x0e, 0x00, 0x80, 0xe4, 0x01, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
+0x7d, 0x71, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49,
+0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30,
+0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0,
+0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0,
+0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
+0xc1, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80,
+0xe8, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88,
+0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0,
+0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c,
+0xff, 0xf7, 0xcb, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09,
+0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46,
+0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20,
+0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b,
+0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0,
+0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00,
+0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01,
+0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46,
+0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0,
+0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c,
+0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30,
+0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48,
+0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a,
+0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8,
+0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0,
+0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43,
+0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c,
+0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18,
+0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x5e, 0xfe,
+0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48,
+0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x53, 0xfe, 0x01, 0x20,
+0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18,
+0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61,
+0x00, 0xe0, 0x88, 0x61, 0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
+0xc1, 0x63, 0x00, 0x20, 0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73,
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80,
+0x50, 0xba, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
+0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80,
+0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a,
+0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a,
+0x88, 0x66, 0x88, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40,
+0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42,
+0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46,
+0x08, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
+0x90, 0xee, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46,
+0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80,
+0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60,
+0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60,
+0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48,
+0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46,
+0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90,
+0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46,
+0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c,
+0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a,
+0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20,
+0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
+0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc,
+0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xa1, 0x21,
+0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
+0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xff, 0x21, 0xa1, 0x22,
+0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
+0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47,
+0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20,
+0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03,
+0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 0x00, 0x20, 0x70, 0x47,
+0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b,
+0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab,
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20,
+0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40,
+0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
+0x5b, 0xff, 0xf8, 0x88, 0x04, 0xa9, 0x03, 0xf0, 0xc9, 0xff, 0x01, 0xab,
+0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8,
+0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b,
+0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68,
+0xc0, 0x46, 0x03, 0x90, 0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
+0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31,
+0x68, 0x46, 0xff, 0xf7, 0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b,
+0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78,
+0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22,
+0x00, 0xab, 0x5a, 0x80, 0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70,
+0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68,
+0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31,
+0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80,
+0xa4, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
+0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48,
+0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xe4, 0xfc, 0x00, 0x28,
+0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xdf, 0xfc,
+0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21,
+0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+0x0d, 0x76, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x59, 0xbd, 0x21, 0x40,
+0x00, 0xb5, 0xc0, 0x88, 0x03, 0xf0, 0x2e, 0xff, 0x00, 0x20, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47,
+0xb0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7,
+0xb5, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0xa4, 0xfc, 0x04, 0x1c, 0x20, 0x4a,
+0x00, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 0x27, 0xd0,
+0x04, 0xa9, 0x1d, 0x4a, 0x38, 0x1c, 0xff, 0xf7, 0x99, 0xfc, 0x04, 0xa8,
+0x00, 0x23, 0x01, 0x2f, 0x06, 0xd1, 0x0c, 0xaa, 0x02, 0x32, 0x00, 0x21,
+0x13, 0x60, 0x01, 0x31, 0x10, 0x29, 0xfb, 0xd3, 0x01, 0x68, 0x04, 0x29,
+0x04, 0xd9, 0x89, 0x08, 0x03, 0x39, 0x89, 0x08, 0x01, 0x31, 0x00, 0xe0,
+0x19, 0x1c, 0x00, 0xab, 0x59, 0x70, 0x06, 0xa9, 0x09, 0x78, 0xc0, 0x46,
+0xd9, 0x80, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46,
+0x03, 0x90, 0x04, 0x33, 0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
+0x18, 0x70, 0x09, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x6e, 0xfc, 0x68, 0x46,
+0x29, 0x1c, 0xff, 0xf7, 0xb7, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
+0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c,
+0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xa2, 0xff, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc,
+0x18, 0x47, 0xf0, 0xb5, 0xc7, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x1c,
+0x01, 0xa9, 0xff, 0xf7, 0x4d, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0x3c, 0xfc,
+0x00, 0x90, 0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a,
+0x25, 0xd8, 0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x21, 0xd8, 0x19, 0x2c,
+0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0xf9, 0x1d,
+0x09, 0x31, 0x06, 0xab, 0x00, 0x20, 0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd,
+0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3,
+0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78,
+0x86, 0x42, 0xf1, 0xdc, 0x20, 0x1c, 0x05, 0xa9, 0x2b, 0x1c, 0xff, 0xf7,
+0x21, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x01, 0xa8, 0x00, 0x78, 0x40, 0x23,
+0x18, 0x43, 0x01, 0xab, 0x18, 0x70, 0x07, 0x49, 0x00, 0x98, 0xff, 0xf7,
+0x06, 0xfc, 0x00, 0x21, 0x01, 0xa8, 0xff, 0xf7, 0x4f, 0xfd, 0x01, 0x20,
+0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff,
+0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x1b, 0xfe, 0x08, 0xbc,
+0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d,
+0x68, 0x68, 0x01, 0x30, 0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7,
+0xf5, 0xfd, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
+0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0,
+0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68,
+0x00, 0x2a, 0x15, 0xd9, 0x40, 0xcb, 0x0f, 0x1c,
+0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 0x12, 0x78, 0x40, 0x23,
+0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 0xda, 0x80, 0x02, 0x90,
+0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 0x15, 0xe0, 0x01, 0x30,
+0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 0x02, 0x94, 0x69, 0x68,
+0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a,
+0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42,
+0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 0xf7, 0xfc, 0x01, 0x20,
+0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x9c, 0x03, 0x00, 0x80,
+0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3,
+0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 0x00, 0xd2, 0x02, 0x22,
+0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 0x01, 0x2b, 0x2e, 0xd1,
+0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0x1b, 0x23,
+0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 0x00, 0xd2, 0x04, 0x27,
+0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 0x07, 0xd2, 0xd1, 0x1d,
+0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23,
+0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x79, 0x03, 0x29,
+0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a,
+0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07,
+0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c,
+0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40,
+0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x04, 0xf0, 0x07, 0xfa, 0x39, 0x48,
+0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 0x37, 0x4e, 0xc5, 0x1d,
+0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 0x5b, 0x5c, 0x5b, 0x00,
+0x9f, 0x44, 0x00, 0x1c, 0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20,
+0xb8, 0x71, 0x00, 0x20, 0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23,
+0x98, 0x43, 0x00, 0xf0, 0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff,
+0xc0, 0x08, 0x06, 0xd3, 0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28,
+0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22,
+0x20, 0x1c, 0x2b, 0xe0, 0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68,
+0x19, 0x43, 0x01, 0x60, 0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a,
+0x00, 0x21, 0x04, 0xf0, 0x99, 0xf9, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68,
+0x99, 0x43, 0x01, 0x60, 0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68,
+0x04, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68,
+0x19, 0x43, 0x01, 0x60, 0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43,
+0x00, 0xf0, 0x34, 0xf8, 0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x04, 0xf0,
+0x77, 0xf9, 0xe5, 0xe7, 0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43,
+0x00, 0xf0, 0x28, 0xf8, 0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23,
+0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xff, 0xf7, 0xe3, 0xfa, 0xd5, 0xe7,
+0x06, 0x20, 0xb8, 0x71, 0xd2, 0xe7, 0x00, 0x00, 0xa9, 0x79, 0x21, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00,
+0x10, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20,
+0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
+0x04, 0xf0, 0x4e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x98, 0x1c, 0x00, 0x80,
+0xa9, 0x79, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x31, 0x48, 0x00, 0x68,
+0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0,
+0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 0x01, 0x2a, 0x05, 0xd1,
+0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43,
+0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 0x01, 0x60, 0xe0, 0x68,
+0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x80, 0x8b,
+0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43,
+0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20,
+0x02, 0xf0, 0x1a, 0xfb, 0x38, 0x09, 0x07, 0xd3, 0xe0, 0x6f, 0x80, 0x23,
+0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 0x00, 0x68, 0x00, 0xe0,
+0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x15, 0x48,
+0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43,
+0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08,
+0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 0x10, 0x43, 0x88, 0x42,
+0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29,
+0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 0x04, 0x33, 0x18, 0x40,
+0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80,
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7,
+0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 0xe3, 0x23, 0x1b, 0x01,
+0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 0x01, 0x22, 0x4a, 0x71,
+0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 0x99, 0x43,
+0x01, 0x60, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x02, 0xf0, 0x8c, 0xfc,
+0x07, 0x20, 0x02, 0xf0, 0x5b, 0xfc, 0x38, 0x1c, 0xff, 0xf7, 0x36, 0xfa,
+0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
+0x37, 0xfc, 0xff, 0xf7, 0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48,
+0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46,
+0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x67, 0xfb, 0x01, 0x20,
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
+0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
+0x38, 0x1c, 0xff, 0xf7, 0x17, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff,
+0xff, 0xf7, 0x62, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
+0xff, 0xf7, 0x4c, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7,
+0x01, 0xfc, 0x01, 0x24, 0x1a, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8,
+0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20,
+0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x20, 0xe0, 0x14, 0x48, 0xff, 0xf7,
+0xe1, 0xf9, 0x05, 0x1c, 0x13, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7,
+0xdd, 0xf9, 0x12, 0x49, 0x28, 0x1c, 0xff, 0xf7, 0xd8, 0xf9, 0x01, 0x2f,
+0x06, 0xd1, 0x0c, 0xa9, 0x00, 0x20, 0x00, 0x22,
+0x0a, 0x60, 0x01, 0x30, 0x10, 0x28, 0xfb, 0xd3, 0x10, 0x20, 0x00, 0xab,
+0x58, 0x70, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46,
+0x03, 0x90, 0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x0f, 0xfb, 0x20, 0x1c,
+0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x01, 0x00, 0x00,
+0x24, 0x02, 0xff, 0xff, 0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff,
+0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
+0xbb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x01, 0xd1,
+0x19, 0x2c, 0x09, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43,
+0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 0x27, 0xe0,
+0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90,
+0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28,
+0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04,
+0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 0x09, 0x0c,
+0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0b, 0x48, 0xff, 0xf7, 0x7e, 0xf9,
+0x07, 0x1c, 0x0a, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0x7a, 0xf9,
+0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x75, 0xf9, 0x68, 0x46, 0x00, 0x21,
+0xff, 0xf7, 0xbe, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0xc5, 0xaf, 0x21, 0x40,
+0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27,
+0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0,
+0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0,
+0x04, 0x2e, 0x00, 0xd1, 0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e,
+0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c,
+0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0,
+0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0,
+0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33,
+0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 0x01, 0x23, 0x5b, 0x02,
+0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22,
+0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 0xff, 0x23, 0xe1, 0x33,
+0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 0xff, 0x33, 0x9e, 0x42,
+0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1,
+0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21,
+0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0x40, 0x88,
+0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0,
+0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1,
+0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43,
+0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0,
+0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x09, 0x21,
+0x49, 0x02, 0x00, 0x20, 0x02, 0xf0, 0x70, 0xf9, 0x00, 0x2f, 0x02, 0xd1,
+0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7,
+0xef, 0xfa, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab,
+0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33,
+0xff, 0xf7, 0x22, 0xfa, 0x28, 0x1c, 0x04, 0xb0,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62,
+0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28,
+0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21,
+0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18,
+0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0,
+0x33, 0xf9, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80,
+0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23,
+0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20,
+0x02, 0xf0, 0x20, 0xf9, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28,
+0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23,
+0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01,
+0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c,
+0x10, 0x20, 0x02, 0xf0, 0x01, 0xf9, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01,
+0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18,
+0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02,
+0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xee, 0xf8, 0x00, 0x20, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0,
+0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x69, 0xfa, 0xb8, 0x05,
+0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
+0xa1, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49,
+0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49,
+0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40,
+0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a,
+0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1,
+0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02,
+0x69, 0x46, 0xff, 0xf7, 0x35, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46,
+0x00, 0x21, 0xff, 0xf7, 0x6f, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20,
+0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1,
+0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1,
+0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47,
+0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 0x9f, 0xf8, 0x69, 0x46,
+0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x0a, 0xfa, 0x01, 0xab, 0x5c, 0x80,
+0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21,
+0xff, 0xf7, 0x40, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49,
+0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47,
+0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
+0xe3, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab,
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf9, 0x01, 0x20,
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47,
+0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68,
+0xff, 0xf7, 0xc6, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49,
+0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0,
+0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70,
+0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
+0xef, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68,
+0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0x17, 0xf8, 0x00, 0x20,
+0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0x9a, 0xf9, 0x00, 0xa8, 0x00, 0x78,
+0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80,
+0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xcd, 0xf8, 0x01, 0x20,
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88,
+0x69, 0x46, 0xff, 0xf7, 0x83, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x72, 0xff,
+0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0xf2, 0xff, 0x00, 0x28, 0x06, 0xd0,
+0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0x36, 0xff, 0x01, 0xab, 0x58, 0x80,
+0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c,
+0xfe, 0xf7, 0x5f, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa8, 0xf8,
+0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0,
+0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x57, 0xf9, 0x10, 0x48,
+0xfe, 0xf7, 0x46, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7,
+0x43, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c,
+0x22, 0x1c, 0xfe, 0xf7, 0x3c, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
+0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 0x32, 0xff, 0x68, 0x46,
+0x00, 0x21, 0xff, 0xf7, 0x7b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
+0x59, 0xb0, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7,
+0x43, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4,
+0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1,
+0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1,
+0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a,
+0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40,
+0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30,
+0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c,
+0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37,
+0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28,
+0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40,
+0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43,
+0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0c, 0x4b,
+0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02,
+0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80,
+0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04,
+0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
+0x40, 0x00, 0x14, 0x00, 0x28, 0x1b, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0,
+0x13, 0x49, 0x0a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12,
+0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02,
+0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02,
+0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c,
+0xff, 0xf7, 0xae, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43,
+0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xe5, 0xff, 0x01, 0x20,
+0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40,
+0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04,
+0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02,
+0x00, 0x12, 0x18, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04,
+0x00, 0x0c, 0x02, 0x02, 0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c,
+0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00,
+0x90, 0xb5, 0x84, 0xb0, 0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c,
+0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c,
+0x17, 0x02, 0x12, 0x12, 0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c,
+0x1f, 0x02, 0x1b, 0x12, 0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23,
+0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b,
+0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04,
+0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
+0x95, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a,
+0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
+0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
+0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x79, 0xff, 0x01, 0x20,
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47,
+0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a,
+0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
+0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
+0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x55, 0xff, 0x01, 0x20,
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
+0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47,
+0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7,
+0xf4, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff,
+0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x06, 0x48,
+0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
+0x2f, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xfd, 0xff, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf8, 0xff,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf3, 0xff, 0x08, 0xbc,
+0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xc6, 0xfd,
+0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21,
+0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c,
+0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a,
+0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48,
+0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0xd5, 0x94, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
+0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff,
+0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
+0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff,
+0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0,
+0xf9, 0xff, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0,
+0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xfe, 0xf8, 0x00, 0x28, 0x0c, 0xd1,
+0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x82, 0xff, 0x06, 0x48, 0x01, 0xab,
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xbb, 0xfe, 0x01, 0x20,
+0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7,
+0x6d, 0xff, 0x01, 0x27, 0x01, 0xab, 0x5f, 0x80, 0x09, 0x48, 0x81, 0x89,
+0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04,
+0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
+0x9b, 0xfe, 0x38, 0x1c, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0xb5, 0xfe, 0xf7, 0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+0xfe, 0xf7, 0x5a, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+0x55, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0xb5, 0xfe, 0xf7, 0x41, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+0xfe, 0xf7, 0x3c, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+0x37, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x32, 0xff,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7,
+0x13, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x02, 0xf0, 0xa9, 0xff, 0x02, 0x20,
+0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x48, 0xfe,
+0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+0x19, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
+0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf8, 0xfe, 0xfa, 0x88, 0x12, 0x49,
+0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 0x0f, 0xd0, 0x04, 0x70,
+0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 0xc8, 0x82, 0xb8, 0x68,
+0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 0x48, 0x83, 0xf8, 0x68,
+0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21,
+0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
+0x00, 0x21, 0xfe, 0xf7, 0x17, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
+0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
+0xfe, 0xf7, 0xde, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
+0xd9, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xd4, 0xfe,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xcf, 0xfe, 0x08, 0xbc,
+0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c,
+0xfe, 0xf7, 0xae, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43,
+0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42,
+0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
+0xfe, 0xf7, 0xdc, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68,
+0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80,
+0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xcc, 0xfd,
+0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0,
+0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x7b, 0xfe, 0xf8, 0x88,
+0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b,
+0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
+0x00, 0x21, 0xfe, 0xf7, 0xab, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68,
+0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00,
+0x80, 0xb5, 0x86, 0xb0, 0x02, 0xa9, 0xfe, 0xf7, 0x57, 0xfe, 0x01, 0x27,
+0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68,
+0xc0, 0x46, 0x04, 0x91, 0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68,
+0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46,
+0x02, 0xa8, 0xfe, 0xf7, 0x81, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68,
+0x80, 0x68, 0xfe, 0xf7, 0x47, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c,
+0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x36, 0xfe, 0x01, 0xab, 0x5c, 0x80,
+0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x61, 0xfd, 0x04, 0xb0,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
+0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x24, 0xfe, 0x01, 0xab, 0x5f, 0x80,
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x50, 0xfd, 0x04, 0xb0, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
+0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a,
+0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0,
+0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27,
+0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27,
+0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xec, 0xfd, 0x01, 0xab, 0x5f, 0x80,
+0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x26, 0xfd, 0x20, 0x1c, 0x04, 0xb0,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0,
+0x69, 0x46, 0xfe, 0xf7, 0xd7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab,
+0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x0f, 0xfd, 0x01, 0x20,
+0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
+0x00, 0xb5, 0xfe, 0xf7, 0xdd, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47,
+0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
+0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
+0x00, 0xb5, 0xfe, 0xf7, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xab, 0xfd, 0x00, 0x20,
+0x01, 0xab, 0x58, 0x70, 0x0c, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29,
+0x02, 0xd1, 0x03, 0x97, 0x04, 0x97, 0x01, 0xe0, 0x03, 0x97, 0x04, 0x90,
+0x68, 0x46, 0x01, 0xf0, 0x33, 0xfd, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46,
+0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xd3, 0xfc, 0x38, 0x1c,
+0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30,
+0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40,
+0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42,
+0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 0x02, 0xd3, 0x40, 0x1a,
+0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 0x01, 0x1c, 0xff, 0x27,
+0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 0x43, 0x00, 0x1b, 0x18,
+0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 0x4b, 0x00, 0x59, 0x18,
+0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd7, 0x50,
+0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 0x57, 0x60, 0x8b, 0x68,
+0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69,
+0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc,
+0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb,
+0x38, 0x1c, 0xf6, 0xe7, 0x40, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0,
+0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0,
+0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58,
+0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0,
+0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 0x00, 0x28,
+0x5b, 0xd0, 0x00, 0x26, 0x00, 0x22, 0x00, 0x92, 0x40, 0x23, 0x00, 0x21,
+0x00, 0x20, 0x02, 0xaa, 0x00, 0xf0, 0x88, 0xfa, 0x04, 0xa9, 0x00, 0x20,
+0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0xa2, 0x42, 0x03, 0xd1,
+0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06,
+0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c,
+0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22,
+0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 0x00, 0xf0, 0x68, 0xfa,
+0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05,
+0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42,
+0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
+0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x50, 0xfa,
+0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06,
+0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22,
+0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0,
+0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1,
+0x01, 0x99, 0x00, 0x29, 0x0f, 0xd1, 0xff, 0x20, 0x3d, 0xe0, 0x40, 0xe0,
+0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
+0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x28, 0xfa,
+0x02, 0x9d, 0x01, 0x20, 0x00, 0x04, 0x46, 0x9a, 0x10, 0x43, 0x79, 0x00,
+0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0x30, 0x1c,
+0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x04, 0x2c, 0x00, 0xd0, 0x0c, 0x20,
+0x04, 0x1c, 0xb0, 0x60, 0x00, 0x20, 0x20, 0x21, 0x46, 0x9a, 0x11, 0x40,
+0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 0x28, 0x19, 0xff, 0x21,
+0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 0xff, 0xf7, 0x19, 0xff, 0x43, 0x01,
+0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21,
+0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60,
+0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20,
+0xf9, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23,
+0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06,
+0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06,
+0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28,
+0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x45, 0x91, 0x41, 0x4a,
+0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 0xc0, 0x43, 0x76, 0xe0,
+0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00,
+0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 0x00, 0x21, 0x02, 0x91,
+0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 0xff, 0x21, 0x68, 0x1e,
+0x09, 0x31, 0xff, 0xf7, 0xcd, 0xfe, 0x61, 0x68, 0x40, 0x18, 0x01, 0x90,
+0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 0xaf, 0x1b, 0x09, 0xe0,
+0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe,
+0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 0x00, 0x22, 0x00, 0x92,
+0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 0x00, 0xf0, 0x9e, 0xf9,
+0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, 0x02, 0x99,
+0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 0xed, 0x1b, 0xa0, 0x68,
+0xa8, 0x42, 0x00, 0xd1, 0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99,
+0xcf, 0x43, 0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68,
+0x03, 0xaa, 0x00, 0xf0, 0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90,
+0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43,
+0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21,
+0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99,
+0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90,
+0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xca, 0xf9,
+0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43,
+0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40,
+0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb,
+0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d,
+0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0,
+0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0,
+0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 0x0f, 0xd3, 0x05, 0xe0,
+0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b,
+0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19,
+0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00,
+0x40, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c,
+0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49,
+0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43,
+0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c,
+0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x21, 0x69, 0x8a, 0x42,
+0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 0xa0, 0x68, 0xe1, 0x68,
+0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x0d, 0xfe, 0x61, 0x68,
+0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31,
+0xff, 0xf7, 0x0d, 0xfe, 0xc2, 0x19, 0xff, 0x21, 0x09, 0x31, 0x8a, 0x42,
+0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x0b, 0x1a, 0x03, 0x93,
+0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0xe1, 0xf8, 0xe0, 0x68,
+0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 0x5d, 0x19, 0xff, 0x1a,
+0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 0x01, 0x9a, 0xc0, 0x46,
+0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0,
+0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98,
+0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98,
+0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0xab, 0x20, 0x40,
+0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91,
+0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58,
+0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda,
+0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 0x02, 0x9a, 0x54, 0x18,
+0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 0x01, 0xd9, 0x22, 0x69,
+0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 0xa0, 0x68, 0xe1, 0x68,
+0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0xa7, 0xfd, 0x61, 0x68,
+0x40, 0x18, 0x00, 0x90, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21,
+0x09, 0x31, 0xff, 0xf7, 0xa6, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23,
+0x5b, 0x04, 0x19, 0x43, 0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32,
+0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c,
+0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19,
+0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b,
+0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e,
+0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 0xcb, 0xf8, 0xe0, 0x68,
+0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9,
+0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f,
+0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x40, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0,
+0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00,
+0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2,
+0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09,
+0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 0x40, 0x68, 0x0c, 0x23,
+0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 0x11, 0x2c, 0x0d, 0xd0,
+0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1,
+0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06,
+0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c,
+0xdb, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20,
+0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47,
+0x40, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x6f, 0xfa, 0x57, 0x20,
+0x02, 0xf0, 0xcc, 0xf9, 0x02, 0xf0, 0x40, 0xf9, 0x00, 0x0a, 0xfb, 0xd3,
+0x02, 0xf0, 0x4e, 0xfa, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0,
+0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23,
+0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32,
+0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c,
+0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x4b, 0xfa, 0x53, 0x20,
+0x02, 0xf0, 0xa8, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0,
+0xa3, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0xa0, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
+0x9d, 0xf9, 0x02, 0xf0, 0x23, 0xfa, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0,
+0x37, 0xfa, 0x54, 0x20, 0x02, 0xf0, 0x94, 0xf9, 0x00, 0x98, 0x02, 0xf0,
+0x91, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x8e, 0xf9, 0x30, 0x1c, 0x14, 0xe0,
+0x02, 0xf0, 0x2a, 0xfa, 0x52, 0x20, 0x02, 0xf0, 0x87, 0xf9, 0x01, 0x98,
+0x02, 0xf0, 0x84, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x81, 0xf9, 0x30, 0x1c,
+0x02, 0xf0, 0x7e, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xf9, 0x00, 0x20,
+0x02, 0xf0, 0x78, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x00, 0x20,
+0x02, 0xf0, 0x72, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0xe4, 0xf8,
+0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xf0, 0xf9,
+0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x42, 0x02, 0x0a, 0x43,
+0x15, 0x1c, 0x01, 0x28, 0x54, 0xd0, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23,
+0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68,
+0x19, 0x43, 0x01, 0x60, 0x02, 0xf0, 0xe6, 0xf9, 0x53, 0x20, 0x02, 0xf0,
+0x43, 0xf9, 0x28, 0x0c, 0x06, 0x1c, 0x02, 0xf0, 0x3f, 0xf9, 0x28, 0x0a,
+0x01, 0x90, 0x00, 0x90, 0x02, 0xf0, 0x3a, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
+0x37, 0xf9, 0x02, 0xf0, 0xbd, 0xf9, 0xff, 0xf7, 0x61, 0xff, 0x02, 0xf0,
+0xd1, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x2e, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
+0x2b, 0xf9, 0x00, 0x98, 0x02, 0xf0, 0x28, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
+0x25, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0,
+0x1f, 0xf9, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xa3, 0xf9, 0x02, 0xf0,
+0xb9, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x16, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
+0x13, 0xf9, 0x01, 0x98, 0x02, 0xf0, 0x10, 0xf9,
+0x28, 0x1c, 0x02, 0xf0, 0x0d, 0xf9, 0x02, 0xf0, 0x93, 0xf9, 0xff, 0xf7,
+0x37, 0xff, 0x07, 0x49, 0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43,
+0x02, 0x60, 0xc8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0xf0, 0x8f, 0xf8, 0x06, 0x4f,
+0xc0, 0x46, 0xf8, 0x60, 0x01, 0xf0, 0xf2, 0xf8, 0x78, 0x80, 0x01, 0xf0,
+0xb1, 0xf8, 0x38, 0x71, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 0x05, 0xf9, 0x02, 0x49,
+0xc0, 0x46, 0x08, 0x80, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0x0b, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23,
+0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68,
+0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68,
+0x1a, 0x43, 0x02, 0x60, 0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32,
+0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28,
+0xfa, 0xd3, 0x46, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30,
+0x20, 0x28, 0xfa, 0xd3, 0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50,
+0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65,
+0x8f, 0x65, 0x3f, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60,
+0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00,
+0x09, 0x18, 0x49, 0x01, 0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d,
+0xf9, 0x33, 0x34, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01,
+0xcb, 0x18, 0x63, 0x63, 0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18,
+0xe3, 0x63, 0x23, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30,
+0x02, 0x28, 0xe4, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c,
+0xc0, 0x46, 0xa1, 0x62, 0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62,
+0xc1, 0x18, 0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21,
+0xe1, 0x64, 0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69,
+0xc0, 0x46, 0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66,
+0x8b, 0x68, 0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66,
+0x1e, 0x4b, 0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01,
+0xc3, 0x18, 0xa3, 0x67, 0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33,
+0x66, 0x61, 0xe7, 0x61, 0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b,
+0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d,
+0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46,
+0x53, 0x66, 0x89, 0x69, 0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46,
+0xd1, 0x66, 0x16, 0x67, 0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67,
+0x56, 0x67, 0xd7, 0x61, 0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73,
+0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
+0x64, 0x2d, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00,
+0x7c, 0x29, 0x00, 0x80, 0x00, 0x55, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00,
+0x10, 0x55, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23,
+0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23,
+0xdb, 0x01, 0xd0, 0x18, 0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18,
+0xc1, 0x61, 0x1c, 0x70, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60,
+0xb9, 0x73, 0x59, 0x61, 0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60,
+0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69,
+0xe4, 0x18, 0x44, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02,
+0x84, 0x63, 0x0e, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46,
+0x44, 0x62, 0x84, 0x69, 0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60,
+0x03, 0x6b, 0xc0, 0x46, 0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62,
+0xc1, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc,
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
+0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22,
+0x1b, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20,
+0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c,
+0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37,
+0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18,
+0x33, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20,
+0xf8, 0x60, 0xda, 0x61, 0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48,
+0xc0, 0x46, 0xc2, 0x60, 0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e,
+0xf8, 0x63, 0x0a, 0x48, 0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68,
+0xc0, 0x46, 0x59, 0x80, 0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc,
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xbc, 0x20, 0x40,
+0x90, 0xee, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40,
+0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33,
+0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46,
+0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23,
+0x1b, 0x01, 0xd1, 0x18, 0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80,
+0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46,
+0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48,
+0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23,
+0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34,
+0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61,
+0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62,
+0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d,
+0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26,
+0xb6, 0x03, 0x37, 0x61, 0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67,
+0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60,
+0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36,
+0x7e, 0x61, 0x19, 0x4f, 0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c,
+0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50,
+0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27,
+0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3,
+0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3,
+0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40,
+0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40,
+0x80, 0x01, 0x18, 0x00, 0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
+0x08, 0x04, 0x00, 0x80, 0xb8, 0xb5, 0x2c, 0x48, 0xfd, 0xf7, 0xba, 0xfd,
+0x01, 0x20, 0x2b, 0x49, 0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68,
+0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20,
+0x04, 0x06, 0x24, 0x0e, 0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23,
+0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3,
+0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61,
+0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62,
+0x00, 0x27, 0x1b, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69,
+0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46,
+0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46,
+0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f,
+0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43,
+0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2,
+0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49,
+0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40,
+0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01,
+0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64,
+0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67,
+0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46,
+0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc,
+0x70, 0x47, 0x00, 0x00, 0xac, 0x66, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80,
+0xd0, 0x2c, 0x00, 0x80, 0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63,
+0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63,
+0x01, 0x64, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20,
+0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60,
+0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a,
+0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28,
+0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80,
+0xf4, 0x2d, 0x00, 0x80, 0x5d, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48,
+0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b,
+0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48,
+0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b,
+0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49,
+0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b,
+0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00,
+0xac, 0x1e, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00,
+0xac, 0xee, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00,
+0xac, 0x3e, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80,
+0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19,
+0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63,
+0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46,
+0x08, 0x63, 0x48, 0x63, 0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d,
+0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72,
+0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32,
+0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70,
+0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72,
+0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22,
+0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73,
+0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
+0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73,
+0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73,
+0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71,
+0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73,
+0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73,
+0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
+0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73,
+0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73,
+0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71,
+0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61,
+0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00,
+0xa0, 0x1c, 0x00, 0x80, 0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02,
+0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00,
+0x09, 0x49, 0x0a, 0x4b, 0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60,
+0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31,
+0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61,
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00,
+0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20,
+0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61,
+0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
+0x6c, 0x06, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32,
+0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30,
+0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d,
+0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3,
+0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60,
+0x70, 0x47, 0x00, 0x00, 0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
+0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfd, 0xf7, 0xea, 0xfb, 0x0b, 0x48,
+0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46,
+0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
+0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47,
+0xc1, 0xbd, 0x21, 0x40, 0x75, 0x98, 0x21, 0x40,
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x00, 0xb5, 0x0f, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
+0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48,
+0x0c, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xbf, 0xfb, 0x0b, 0x48, 0x41, 0x8d,
+0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a,
+0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x59, 0xbd, 0x21, 0x40,
+0x75, 0x98, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0x1b, 0x4c,
+0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28,
+0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67,
+0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18,
+0xc1, 0x43, 0xe8, 0x61, 0x69, 0x62, 0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03,
+0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x71,
+0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 0xb8, 0x60, 0x00, 0xf0, 0x4c, 0xfa,
+0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x20, 0xb8, 0x60, 0x07, 0x20, 0x78, 0x61,
+0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0xc0, 0x8b, 0x04, 0x23,
+0x18, 0x40, 0xe8, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x02, 0x1c, 0x00, 0x20, 0xff, 0x23,
+0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 0x00, 0xd1, 0x01, 0x20,
+0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 0x90, 0xbc, 0x70, 0x47,
+0x1b, 0x4a, 0xd7, 0x68, 0x1a, 0x4b, 0x19, 0x79, 0x1c, 0x1c, 0x37, 0x23,
+0x9b, 0x01, 0xe3, 0x18, 0x01, 0x2f, 0x0d, 0xd1, 0x57, 0x88, 0x00, 0x2f,
+0x0a, 0xd1, 0x00, 0x29, 0x0a, 0xd1, 0x59, 0x8b, 0x0a, 0x09, 0x00, 0xd3,
+0x02, 0x20, 0x49, 0x09, 0xe8, 0xd3, 0x01, 0x23, 0x18, 0x43, 0xe5, 0xe7,
+0x00, 0x29, 0x03, 0xd0, 0x98, 0x8a, 0x80, 0x07, 0x80, 0x0f, 0xdf, 0xe7,
+0x6d, 0x23, 0x5b, 0x01, 0xd1, 0x18, 0x8a, 0x88, 0xff, 0x27, 0x01, 0x37,
+0x17, 0x40, 0x0a, 0x49, 0xc9, 0x88, 0x03, 0xd0, 0x4b, 0x0a, 0x01, 0xd3,
+0x03, 0x20, 0xd1, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 0x0b, 0x0a, 0x01, 0xd3,
+0x02, 0x20, 0xcb, 0xe7, 0xd2, 0x09, 0xc9, 0xd3, 0xc9, 0x09, 0xc7, 0xd3,
+0x01, 0x20, 0xc5, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x1c, 0x00, 0x80,
+0xf0, 0xb5, 0xc1, 0xb0, 0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46,
+0x08, 0x60, 0x52, 0x48, 0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03,
+0x48, 0x60, 0x50, 0x48, 0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21,
+0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b,
+0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33,
+0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43,
+0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07,
+0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30,
+0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03,
+0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03,
+0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62,
+0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a,
+0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34,
+0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c,
+0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42,
+0xf5, 0xd1, 0x30, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68,
+0x1b, 0x0c, 0x08, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24,
+0x2b, 0x4b, 0xc0, 0x46, 0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b,
+0x23, 0x4c, 0x51, 0x26, 0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0x3d, 0x6a,
+0xc0, 0x46, 0x75, 0x61, 0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60,
+0x01, 0x25, 0xb5, 0x60, 0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x71, 0x88, 0x42,
+0x21, 0xd0, 0x25, 0x1c, 0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f,
+0x6b, 0x44, 0x34, 0x60, 0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60,
+0x2b, 0x6f, 0x08, 0x33, 0x2b, 0x67, 0x3c, 0x6a, 0xa3, 0x42, 0x02, 0xd3,
+0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44,
+0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03,
+0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b,
+0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfd, 0xf7, 0x74, 0xfa, 0x41, 0xb0,
+0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
+0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80,
+0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00,
+0xc9, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22,
+0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33,
+0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61,
+0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61,
+0x3f, 0x4d, 0xab, 0x6f, 0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23,
+0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f,
+0x9e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61,
+0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23,
+0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43,
+0x3b, 0x61, 0x02, 0x23, 0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43,
+0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00,
+0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
+0x2b, 0x43, 0x3b, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
+0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08,
+0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
+0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
+0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25,
+0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43,
+0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43,
+0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61,
+0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61,
+0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40,
+0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30,
+0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61,
+0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08,
+0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x80, 0x00, 0x14, 0x40, 0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27,
+0x44, 0x4a, 0xc0, 0x46, 0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c,
+0xf9, 0xd3, 0x04, 0x26, 0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61,
+0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61,
+0x3c, 0x4b, 0x9b, 0x6f, 0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c,
+0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f,
+0x9d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
+0x25, 0x43, 0x15, 0x61, 0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23,
+0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61,
+0x2d, 0x4b, 0x9d, 0x6f, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
+0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00,
+0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
+0x15, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
+0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40,
+0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08,
+0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
+0x15, 0x61, 0x02, 0x25, 0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
+0x25, 0x43, 0x15, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c,
+0x33, 0x43, 0x13, 0x61, 0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23,
+0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21,
+0x25, 0x1c, 0xcd, 0x40, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43,
+0x13, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39,
+0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61,
+0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
+0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d,
+0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfd, 0xf7, 0x27, 0xf9, 0x4d, 0x4c,
+0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20,
+0x2a, 0x1c, 0xfd, 0xf7, 0x1d, 0xf9, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28,
+0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1,
+0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02,
+0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28,
+0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21,
+0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26,
+0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe,
+0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 0x00, 0x25, 0x05, 0xe0,
+0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x2b, 0xff, 0x01, 0x35,
+0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 0xb5, 0x42,
+0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 0xff, 0x23, 0xe1, 0x33,
+0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 0xff, 0x23, 0x01, 0x33,
+0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01,
+0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28,
+0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23,
+0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28,
+0x03, 0xd1, 0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23,
+0x19, 0x43, 0x04, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0x09, 0x21, 0x49, 0x02,
+0x00, 0x20, 0xff, 0xf7, 0xf3, 0xfe, 0xe0, 0x68, 0x00, 0x28, 0x0c, 0xd1,
+0x00, 0x21, 0x1b, 0x20, 0xff, 0xf7, 0xec, 0xfe, 0x1a, 0x20, 0xff, 0xf7,
+0x4f, 0xfe, 0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7,
+0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f,
+0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19,
+0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f,
+0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xed, 0xaf, 0x21, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48,
+0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91,
+0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91,
+0x01, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91,
+0x81, 0x69, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91,
+0x01, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91,
+0x81, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90,
+0x01, 0xb0, 0x70, 0x47, 0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0,
+0x68, 0x4d, 0x1b, 0x23, 0xdb, 0x01, 0xef, 0x18, 0xf8, 0x8b, 0x04, 0x22,
+0x02, 0x40, 0x02, 0x92, 0x71, 0x23, 0x5b, 0x01, 0xe8, 0x18, 0x01, 0x88,
+0xc0, 0x46, 0x01, 0x91, 0x40, 0x88, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24,
+0x03, 0xe0, 0x08, 0x2c, 0x01, 0xd3, 0x0f, 0x2c, 0x08, 0xd9, 0x20, 0x1c,
+0xff, 0xf7, 0xe8, 0xfd, 0x61, 0x00, 0x49, 0x19, 0x1b, 0x23, 0xdb, 0x01,
+0xc9, 0x18, 0x88, 0x83, 0x01, 0x34, 0x20, 0x2c, 0xef, 0xd3, 0x58, 0x4c,
+0xe0, 0x69, 0x00, 0x28, 0x15, 0xd0, 0x57, 0x4e, 0x20, 0x25, 0x01, 0x3d,
+0x53, 0x49, 0xe0, 0x69, 0x30, 0x40, 0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18,
+0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x8b, 0x28, 0x1c, 0xff, 0xf7,
+0x65, 0xfe, 0xe0, 0x69, 0xb0, 0x43, 0xe0, 0x61, 0x76, 0x08, 0x00, 0x2d,
+0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 0xc2, 0xfd, 0x48, 0x49, 0xc0, 0x46,
+0xf8, 0x83, 0xf8, 0x8b, 0xc2, 0x08, 0x25, 0xd3, 0xca, 0x68, 0x01, 0x2a,
+0x13, 0xd1, 0x0a, 0x79, 0x00, 0x2a, 0x1f, 0xd1, 0x49, 0x88, 0x00, 0x29,
+0x1c, 0xd1, 0x01, 0x99, 0x43, 0x4a, 0x00, 0x29, 0x05, 0xd0, 0x01, 0x29,
+0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b,
+0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1,
+0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40,
+0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x98, 0x43, 0xf8, 0x83,
+0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 0x1f, 0xd0, 0xb9, 0x8b,
+0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 0xff, 0x23, 0x01, 0x98,
+0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 0x00, 0x98, 0x01, 0x28,
+0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23,
+0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0,
+0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20,
+0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2,
+0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20,
+0x40, 0x02, 0xb8, 0x83, 0xf8, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 0x1d, 0x48,
+0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x51, 0xfc, 0xc2, 0x07,
+0xd2, 0x0f, 0x1a, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 0x2b, 0x43,
+0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65,
+0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 0x03, 0xe0,
+0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 0x61, 0x6a,
+0x81, 0x42, 0x0c, 0xd0, 0x60, 0x62, 0x0e, 0x48, 0x00, 0x2a, 0x03, 0xd0,
+0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x21, 0x33,
+0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
+0x00, 0x00, 0x00, 0x80, 0x28, 0x1c, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40,
+0xa4, 0x2a, 0x00, 0x80, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22,
+0x20, 0x28, 0x0f, 0xd2, 0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18,
+0x37, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0x9f, 0x83, 0x82, 0x40, 0x07, 0x23,
+0x5b, 0x02, 0xc9, 0x18, 0x10, 0x1c, 0xca, 0x69, 0x10, 0x43, 0xc8, 0x61,
+0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69,
+0x0b, 0x49, 0xc9, 0x8b, 0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0,
+0x01, 0x23, 0xdb, 0x02, 0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43,
+0x05, 0xe0, 0x01, 0x23, 0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08,
+0x52, 0x00, 0xca, 0x65, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
+0xe8, 0x1b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0,
+0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20,
+0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab,
+0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91,
+0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfd, 0xf7, 0x79, 0xf8, 0x04, 0xb0,
+0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68,
+0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68,
+0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0,
+0x0a, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x4b, 0x98, 0x42,
+0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x07, 0x4b, 0x98, 0x42,
+0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80,
+0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24,
+0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68,
+0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21,
+0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 0x02, 0xd0, 0x38, 0x68,
+0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x4b,
+0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x05, 0xd0, 0x0e, 0x4b,
+0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29,
+0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0,
+0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e,
+0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40,
+0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00,
+0x07, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2,
+0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x02, 0xd3,
+0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 0x40, 0x6c, 0x00, 0x04,
+0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 0x40, 0x08, 0x01, 0xd3,
+0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 0x00, 0x00, 0x10, 0x40,
+0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x27,
+0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x72, 0xff, 0x03, 0x1c, 0x19, 0x4a,
+0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 0x1b, 0xd1, 0xcb, 0x04,
+0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 0x43, 0x60, 0x06, 0x68,
+0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 0x43, 0x60, 0x03, 0x68,
+0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 0x05, 0x23, 0x0f, 0x4f,
+0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 0xc0, 0x46, 0x3b, 0x60,
+0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 0x23, 0x60, 0x04, 0x23,
+0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x06, 0x60, 0x27, 0x68,
+0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x22, 0x40,
+0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x28, 0x40,
+0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x28, 0x05, 0xd1,
+0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 0x08, 0x40, 0x22, 0xe0,
+0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c,
+0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x14, 0x48, 0x00, 0x68,
+0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c,
+0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 0x01, 0xa3, 0x1b, 0x5c,
+0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03,
+0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21,
+0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e,
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x34, 0x6e, 0x21, 0x40,
+0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40,
+0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x82, 0xb0,
+0x07, 0x1c, 0x01, 0x20, 0x01, 0x90, 0xff, 0xf7, 0xe7, 0xfe, 0x01, 0x28,
+0x13, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x07, 0xd1, 0x00, 0x26,
+0xf6, 0x43, 0x34, 0x1c, 0xa8, 0x2f, 0x02, 0xd1, 0x30, 0x1c, 0x00, 0x96,
+0x35, 0x1c, 0x11, 0x20, 0x00, 0x04, 0x06, 0x62, 0x44, 0x62, 0x85, 0x62,
+0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x08, 0x48, 0xc0, 0x46,
+0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21,
+0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x01, 0x98,
+0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x34, 0x6e, 0x21, 0x40,
+0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
+0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 0x0b, 0xd0, 0x00, 0x23,
+0x21, 0x1c, 0xe2, 0x1d, 0xc1, 0x32, 0x00, 0xe0,
+0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xc8, 0x20, 0xa0, 0x80,
+0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48,
+0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19,
+0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80,
+0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80,
+0xee, 0xff, 0xc0, 0xd0, 0x08, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a,
+0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7a, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23,
+0x0b, 0x72, 0x07, 0x1c, 0x08, 0x7a, 0x43, 0x1c, 0x0b, 0x72, 0x80, 0x18,
+0x90, 0x30, 0x47, 0x72, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80,
+0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20,
+0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68,
+0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40,
+0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7,
+0x91, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42,
+0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7,
+0xc5, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x66, 0x21, 0x40,
+0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c,
+0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89,
+0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c,
+0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c,
+0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e,
+0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 0x79, 0x6c, 0x59, 0x43,
+0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 0x01, 0x32, 0x12, 0x04,
+0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22,
+0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88,
+0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23,
+0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49,
+0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81,
+0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20,
+0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfb, 0xf0, 0x88,
+0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04,
+0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80,
+0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0,
+0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 0xf9, 0x7a, 0x00, 0x29,
+0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 0x79, 0x64, 0x2a, 0xd0,
+0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 0x01, 0x31, 0xe1, 0x80,
+0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 0xdb, 0x03, 0x78, 0x6c,
+0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0,
+0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18,
+0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xfb, 0xe0, 0x6a,
+0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39,
+0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 0x89, 0xfb, 0xb6, 0xe7,
+0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04,
+0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80,
+0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b,
+0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d,
+0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
+0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88,
+0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30,
+0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19,
+0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xfa, 0x71, 0x88,
+0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0,
+0x4d, 0xfb, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35,
+0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25,
+0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc,
+0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
+0xc4, 0x66, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03,
+0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d,
+0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a,
+0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e,
+0x6d, 0xd0, 0xed, 0x6a, 0x5e, 0x1e, 0x73, 0x00, 0x9b, 0x19, 0x5b, 0x01,
+0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0,
+0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x35, 0xad, 0x8b, 0xad, 0x00,
+0x35, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0x70, 0x51, 0x55, 0x89, 0x01, 0x35,
+0x55, 0x81, 0x32, 0x4e, 0xf2, 0x6a, 0xd2, 0x18, 0x90, 0x60, 0xf2, 0x6a,
+0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a,
+0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a,
+0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88,
+0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 0x88, 0x81, 0x24, 0x49,
+0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 0x00, 0x2e, 0x38, 0xd9,
+0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 0x00, 0x2b, 0x2c, 0xd0,
+0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 0xad, 0x6a, 0x58, 0x23,
+0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e,
+0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0xa8, 0x60,
+0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0xe8, 0x63,
+0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 0xed, 0x18, 0x68, 0x64,
+0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 0xeb, 0x18, 0xd8, 0x64,
+0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 0xc0, 0x46, 0x48, 0x81,
+0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 0x03, 0xe0, 0x17, 0x80,
+0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81,
+0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
+0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49,
+0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0,
+0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69,
+0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61,
+0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a,
+0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46,
+0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
+0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 0x4c, 0xd0, 0x08, 0x22,
+0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 0xd9, 0x1d, 0xb9, 0x31,
+0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
+0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
+0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
+0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
+0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
+0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
+0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 0xcc, 0x82, 0x4f, 0x83,
+0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 0x8c, 0x00, 0x05, 0x19,
+0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 0x01, 0x34, 0x65, 0x62,
+0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00,
+0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29,
+0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xac, 0xab, 0x20, 0x40,
+0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
+0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00,
+0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
+0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36,
+0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d,
+0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
+0x44, 0xfb, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c,
+0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x3b, 0xfb, 0x29, 0x1c, 0x23, 0x1c,
+0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x35, 0xfb, 0x39, 0x1c, 0x23, 0x1c,
+0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x2f, 0xfb, 0x00, 0x21, 0x0b, 0x48,
+0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30,
+0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0xac, 0xab, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00,
+0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 0x6c, 0x06, 0x00, 0x80,
+0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30,
+0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29,
+0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1,
+0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23,
+0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33,
+0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43,
+0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68,
+0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0,
+0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46,
+0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c,
+0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00,
+0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35,
+0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2,
+0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32,
+0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 0xbc, 0xe7, 0x00, 0x21,
+0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31,
+0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43,
+0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46,
+0x50, 0x61, 0x09, 0x48, 0xfc, 0xf7, 0xa4, 0xfa, 0xa4, 0xe7, 0x00, 0x00,
+0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01,
+0xac, 0xab, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00,
+0x5c, 0x5c, 0x5c, 0x5c, 0x11, 0x31, 0xff, 0xff, 0xf0, 0xb5, 0x07, 0x1c,
+0x3b, 0x48, 0x3c, 0x4c, 0x08, 0x21, 0x20, 0x60, 0xa1, 0x80, 0x00, 0x20,
+0x20, 0x81, 0xe1, 0x80, 0x60, 0x81, 0x39, 0x48, 0xc0, 0x46, 0xe0, 0x60,
+0x38, 0x48, 0xc0, 0x46, 0x20, 0x61, 0x38, 0x48, 0xc0, 0x46, 0x60, 0x61,
+0x37, 0x48, 0xc0, 0x46, 0xa0, 0x61, 0x37, 0x48, 0xc0, 0x46, 0xe0, 0x61,
+0x36, 0x48, 0xc0, 0x46, 0x20, 0x62, 0x36, 0x48, 0xc0, 0x46, 0x60, 0x62,
+0x35, 0x48, 0xc0, 0x46, 0xa0, 0x62, 0x35, 0x48, 0xc0, 0x46, 0xe0, 0x62,
+0x34, 0x48, 0xc0, 0x46, 0x20, 0x63, 0x34, 0x48, 0xc0, 0x46, 0x60, 0x63,
+0x33, 0x48, 0xc0, 0x46, 0xa0, 0x63, 0x33, 0x48, 0xc0, 0x46, 0xe0, 0x63,
+0x32, 0x48, 0xc0, 0x46, 0x20, 0x64, 0x32, 0x48, 0xc0, 0x46, 0x60, 0x64,
+0x31, 0x48, 0xc0, 0x46, 0xa0, 0x64, 0x31, 0x48, 0xc0, 0x46, 0xe0, 0x64,
+0x30, 0x48, 0xc0, 0x46, 0x20, 0x65, 0x30, 0x49, 0xc8, 0x68, 0x02, 0x04,
+0x89, 0x69, 0x4a, 0x40, 0xe3, 0x1d, 0x79, 0x33, 0x09, 0x04, 0xc9, 0x43,
+0xc0, 0x43, 0x48, 0x40, 0xe1, 0x1d, 0xb9, 0x31, 0xda, 0x63, 0x08, 0x60,
+0x29, 0x4d, 0x21, 0x1c, 0x2b, 0x1c, 0x29, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
+0x3e, 0xfa, 0x28, 0x4a, 0xe1, 0x1d, 0xb5, 0x31, 0x01, 0x20, 0x2b, 0x1c,
+0x0e, 0x1c, 0xfc, 0xf7, 0x36, 0xfa, 0x24, 0x4a, 0x00, 0x20, 0x31, 0x1c,
+0x2b, 0x1c, 0xfc, 0xf7, 0x30, 0xfa, 0xe1, 0x1d, 0x4d, 0x31, 0x2b, 0x1c,
+0x20, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x29, 0xfa, 0xe0, 0x1d, 0x5d, 0x30,
+0x01, 0x68, 0x00, 0x29, 0xfc, 0xd0, 0x60, 0x6d, 0xc0, 0x46, 0x38, 0x65,
+0x20, 0x6e, 0xc0, 0x46, 0x78, 0x65, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x80, 0x00, 0x08, 0x00, 0x8c, 0xb9, 0x20, 0x40, 0x81, 0x81, 0x48, 0xbd,
+0x79, 0x56, 0x23, 0x8c, 0x93, 0x0c, 0x82, 0x95, 0x1d, 0x0e, 0x12, 0xcf,
+0x9b, 0x3b, 0xc0, 0xe9, 0xe6, 0x55, 0x7c, 0x82, 0x99, 0xf6, 0x78, 0x02,
+0xd1, 0xd7, 0x25, 0x73, 0x72, 0x8c, 0x33, 0x10, 0xf7, 0x03, 0xf1, 0x42,
+0x6c, 0x9b, 0x4a, 0xa7, 0x82, 0x8e, 0x23, 0xa9, 0x90, 0xb1, 0x82, 0x8e,
+0xdc, 0x3f, 0xfb, 0x29, 0x00, 0x62, 0x22, 0x45, 0x88, 0x2b, 0xf1, 0x85,
+0x12, 0x61, 0xd1, 0x73, 0x6e, 0xb1, 0x11, 0x16, 0x08, 0x83, 0x20, 0x40,
+0x75, 0x08, 0xff, 0xff, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00,
+0x14, 0x00, 0x03, 0x00, 0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0,
+0x33, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x4c, 0xff, 0x03, 0x48, 0x01, 0x89,
+0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
+0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68,
+0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43,
+0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06,
+0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69,
+0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81,
+0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
+0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18,
+0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08,
+0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b,
+0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b,
+0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c,
+0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88,
+0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 0x03, 0x7a, 0x1b, 0x04,
+0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 0x43, 0x7a, 0xdb, 0x07,
+0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 0x5a, 0x08, 0x05, 0xd3,
+0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 0x15, 0x22, 0x00, 0xe0,
+0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3,
+0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a,
+0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c,
+0xff, 0xf7, 0x78, 0xfd, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23,
+0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31,
+0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
+0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40,
+0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 0x2e, 0x1c, 0x45, 0x6d,
+0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 0xfd, 0x40, 0x2f, 0x1c,
+0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 0x08, 0xd0, 0x23, 0x69,
+0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 0xbe, 0x00, 0xae, 0x59,
+0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 0x11, 0x43, 0x05, 0x4b,
+0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 0x87, 0x83, 0xf0, 0xbc,
+0x70, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
+0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78,
+0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43,
+0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c,
+0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x9a, 0xf8,
+0x00, 0xf0, 0xb8, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xc7, 0xfa, 0x3d, 0x70,
+0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x93, 0xf8, 0x00, 0xf0,
+0xa7, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x38, 0x0a, 0xf6, 0xd3,
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x82, 0xb0, 0x02, 0x98,
+0x41, 0x02, 0x53, 0x20, 0x00, 0xf0, 0x64, 0xf8, 0x00, 0xf0, 0xa8, 0xfa,
+0xff, 0xf7, 0xe8, 0xff, 0x00, 0x24, 0x00, 0x20, 0x01, 0x90, 0x2e, 0x20,
+0x00, 0x90, 0x00, 0x25, 0x00, 0x27, 0x02, 0x98, 0x01, 0x28, 0x04, 0xd1,
+0x00, 0x98, 0x84, 0x42, 0x01, 0xd3, 0x00, 0x26,
+0x09, 0xe0, 0x01, 0x98, 0x41, 0x1c, 0x01, 0x91, 0x00, 0xf0, 0x60, 0xf8,
+0x00, 0xf0, 0x7e, 0xf9, 0x06, 0x1c, 0x00, 0xf0, 0x8d, 0xfa, 0xf8, 0x00,
+0x86, 0x40, 0x35, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xe6, 0xd3,
+0x03, 0x99, 0x20, 0xc1, 0x03, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42,
+0xdd, 0xd3, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5,
+0x04, 0x1c, 0x0f, 0x1c, 0x01, 0x2c, 0x2a, 0xd0, 0x16, 0x48, 0xc0, 0x6f,
+0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x00, 0x26, 0x20, 0xcf,
+0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x28, 0x1c, 0x00, 0xf0,
+0xdf, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xdc, 0xf9, 0x28, 0x0c, 0x00, 0xf0,
+0xd9, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xd6, 0xf9, 0x00, 0xf0, 0x5c, 0xfa,
+0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 0x83, 0x20, 0x00, 0xf0,
+0x0f, 0xf8, 0x00, 0xf0, 0x53, 0xfa, 0xff, 0xf7, 0x93, 0xff, 0x04, 0x48,
+0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
+0x0f, 0x1c, 0x00, 0xf0, 0x59, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9,
+0x38, 0x0c, 0x00, 0xf0, 0xb3, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xb0, 0xf9,
+0x38, 0x1c, 0x00, 0xf0, 0xad, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x00, 0xb5, 0x01, 0x1c, 0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20,
+0x00, 0xf0, 0xa2, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
+0x3d, 0xfa, 0x57, 0x20, 0x00, 0xf0, 0x9a, 0xf9, 0x08, 0xbc, 0x18, 0x47,
+0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43,
+0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0xf8, 0x6f, 0x20, 0x23,
+0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23,
+0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x87, 0xff,
+0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x04, 0x1c,
+0x0f, 0x1c, 0x18, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x99, 0x43,
+0x01, 0x60, 0x61, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0x00, 0xf0,
+0xe9, 0xf9, 0xff, 0xf7, 0x29, 0xff, 0xf8, 0x1d, 0x05, 0x30, 0x01, 0x2c,
+0x03, 0xd1, 0x22, 0x2f, 0x01, 0xd3, 0x00, 0x27, 0x0f, 0xe0, 0x44, 0x1c,
+0xff, 0xf7, 0xaa, 0xff, 0x00, 0xf0, 0xc8, 0xf8, 0x07, 0x1c, 0x00, 0xf0,
+0xd7, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 0xa2, 0xff, 0x00, 0xf0, 0xc0, 0xf8,
+0x05, 0x1c, 0x00, 0xf0, 0xcf, 0xf9, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68,
+0x19, 0x43, 0x01, 0x60, 0x28, 0x02, 0x38, 0x43, 0xf0, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0,
+0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0x01, 0x2f, 0x2f, 0xd0, 0x79, 0x02,
+0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
+0x53, 0x20, 0xff, 0xf7, 0x6b, 0xff, 0x00, 0xf0, 0xaf, 0xf9, 0xff, 0xf7,
+0xef, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0xd6, 0xfe, 0x6a, 0x46, 0xe8, 0x1d,
+0x05, 0x30, 0x14, 0x54, 0x21, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46,
+0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xba, 0xfe, 0x02, 0xab, 0x18, 0x70,
+0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21,
+0xff, 0xf7, 0xb2, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x38, 0x1c,
+0xff, 0xf7, 0x15, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43,
+0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x01, 0x2f,
+0x01, 0xd1, 0x01, 0x20, 0x36, 0xe0, 0x6b, 0x46, 0x00, 0x20, 0xc4, 0x43,
+0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30,
+0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46,
+0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31,
+0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c,
+0xff, 0xf7, 0x7c, 0xfe, 0x04, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x02, 0xab,
+0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7,
+0x71, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 0x1d, 0x06, 0x2d, 0x0e,
+0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x3e, 0xff,
+0x01, 0x20, 0xac, 0x42, 0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02,
+0x14, 0x4c, 0xe0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
+0x53, 0x20, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7,
+0x73, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0x5a, 0xfe, 0xe0, 0x6f, 0x20, 0x23,
+0x01, 0x68, 0x19, 0x43, 0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24,
+0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x3c, 0xfe,
+0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c,
+0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3,
+0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+0x81, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1,
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x93, 0xe5, 0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+0x01, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1,
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x93, 0xe5, 0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+0x81, 0x00, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
+0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47,
+0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 0xa0, 0x13, 0xa0, 0xe1,
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1,
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1,
+0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5,
+0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5,
+0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5,
+0x3c, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
+0x00, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
+0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40,
+0x04, 0x01, 0x18, 0x40, 0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40,
+0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0,
+0x47, 0xf8, 0x78, 0x1c, 0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd,
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1d, 0x48,
+0x02, 0x68, 0x1d, 0x49, 0x8b, 0x69, 0xd2, 0x18, 0x02, 0x60, 0x02, 0x66,
+0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 0x02, 0xd2,
+0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 0xd2, 0x18,
+0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 0xc2, 0x69,
+0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 0xd2, 0x18,
+0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 0x02, 0x6b,
+0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18,
+0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63,
+0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 0xc9, 0x6a,
+0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
+0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8,
+0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22,
+0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42,
+0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
+0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22,
+0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0,
+0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c,
+0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60,
+0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00,
+0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
+0xa0, 0x82, 0x20, 0x40, 0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a,
+0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60,
+0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30,
+0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31,
+0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30,
+0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20,
+0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31,
+0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47,
+0x08, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x04, 0x00, 0x80,
+0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x23,
+0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 0x00, 0x22, 0x0a, 0x70,
+0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 0x43, 0x83, 0x7d, 0x21,
+0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
+0x00, 0xf0, 0x8e, 0xfb, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0xb5, 0x22, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48,
+0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x80, 0xfb, 0x01, 0x23, 0xd8, 0x42,
+0x0a, 0xd1, 0x10, 0x48, 0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32,
+0xca, 0x80, 0x81, 0x79, 0x01, 0x31, 0x81, 0x71, 0xfd, 0xf7, 0x70, 0xf9,
+0x0b, 0x48, 0xc0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22,
+0xd2, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x68, 0xfb, 0x08, 0x48, 0xfb, 0xf7,
+0xe1, 0xfc, 0x08, 0x48, 0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x60, 0xfb,
+0x08, 0xbc, 0x18, 0x47, 0x79, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40,
+0x68, 0x0e, 0x00, 0x80, 0xa5, 0x7b, 0x21, 0x40,
+0x95, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20,
+0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21,
+0xfb, 0xf7, 0xc6, 0xfc, 0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68,
+0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c,
+0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46,
+0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64,
+0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa5, 0x55, 0xff, 0xff,
+0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 0x01, 0x22, 0x12, 0x04,
+0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68,
+0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x21, 0x48,
+0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 0xc0, 0x46, 0x01, 0x64,
+0x1f, 0x48, 0xfb, 0xf7, 0x87, 0xfc, 0x1f, 0x48, 0xc1, 0x6b, 0xff, 0x29,
+0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 0x0f, 0x1c, 0x1c, 0x4c,
+0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43,
+0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x28, 0x61,
+0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfb, 0xf7, 0x6f, 0xfc, 0x16, 0x4a,
+0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 0x39, 0x1c, 0x32, 0x1c,
+0xfb, 0xf7, 0x6e, 0xfc, 0x13, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1,
+0x12, 0x48, 0xfb, 0xf7, 0x5d, 0xfc, 0x10, 0x23, 0x60, 0x69, 0x98, 0x43,
+0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18,
+0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40,
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
+0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
+0xb5, 0xb6, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 0x44, 0x80, 0x20, 0x40,
+0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0xfd, 0xf7,
+0x01, 0xff, 0x06, 0x48, 0xfb, 0xf7, 0x32, 0xfc, 0xfd, 0xf7, 0xd6, 0xfe,
+0xfe, 0xf7, 0x04, 0xf8, 0xfe, 0xf7, 0x16, 0xf8, 0xfe, 0xf7, 0x24, 0xf8,
+0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 0x90, 0xb5, 0xfd, 0xf7,
+0x6b, 0xfc, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 0xf8, 0x1d, 0x79, 0x30,
+0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 0xf9, 0x67, 0x31, 0x49,
+0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 0x0c, 0x60, 0x4c, 0x60,
+0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 0x8c, 0x61, 0x04, 0xe0,
+0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 0x08, 0x38, 0x00, 0x68,
+0x60, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23,
+0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68,
+0x99, 0x43, 0x01, 0x60, 0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x4e, 0xfc,
+0x00, 0xf0, 0x5e, 0xf9, 0xfd, 0xf7, 0x73, 0xf8, 0xff, 0xf7, 0x0c, 0xfe,
+0xfd, 0xf7, 0x2e, 0xfe, 0xfd, 0xf7, 0xb6, 0xfd, 0xfd, 0xf7, 0xc2, 0xfe,
+0xfd, 0xf7, 0x54, 0xfd, 0xfd, 0xf7, 0x0a, 0xfd, 0xfd, 0xf7, 0x94, 0xfd,
+0x00, 0xf0, 0x1a, 0xfa, 0xfd, 0xf7, 0x9c, 0xff, 0xfd, 0xf7, 0x0a, 0xff,
+0xfd, 0xf7, 0xd2, 0xfe, 0xfd, 0xf7, 0x3c, 0xfc, 0xfb, 0xf7, 0xdc, 0xfa,
+0xff, 0xf7, 0x9c, 0xff, 0x71, 0x23, 0x5b, 0x01,
+0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 0xf8, 0x18,
+0x04, 0x63, 0xf8, 0x68, 0x01, 0x28, 0x02, 0xd1, 0xa8, 0x20, 0xfe, 0xf7,
+0xb1, 0xfd, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 0x18, 0xfa,
+0x07, 0x48, 0xfb, 0xf7, 0xbd, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
+0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 0x04, 0x01, 0x11, 0x40,
+0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x15, 0x8f, 0x21, 0x40,
+0x00, 0xb5, 0x04, 0x48, 0xfb, 0xf7, 0xaa, 0xfb, 0xfd, 0xf7, 0x5e, 0xff,
+0xfd, 0xf7, 0x24, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x15, 0x99, 0x21, 0x40,
+0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62,
+0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69,
+0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61,
+0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61,
+0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10,
+0x00, 0xb5, 0x02, 0x48, 0xfb, 0xf7, 0x80, 0xfb, 0x08, 0xbc, 0x18, 0x47,
+0xc8, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 0x01, 0x21, 0x09, 0x04,
+0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 0x22, 0x4d, 0x00, 0x29,
+0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a,
+0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 0x1d, 0x48, 0xfb, 0xf7,
+0x65, 0xfb, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 0x01, 0x30, 0x88, 0x61,
+0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 0x00, 0x28, 0x1f, 0xd0,
+0x19, 0x48, 0xfb, 0xf7, 0x57, 0xfb, 0x19, 0x48, 0xfb, 0xf7, 0x54, 0xfb,
+0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x16, 0x48,
+0xfb, 0xf7, 0x4c, 0xfb, 0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40,
+0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1,
+0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x01, 0xe0, 0x28, 0x64,
+0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0x65, 0xfd, 0x0b, 0x48, 0xfb, 0xf7,
+0x35, 0xfb, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40,
+0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
+0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf4, 0x01, 0xff, 0xff,
+0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9f, 0x21, 0x40,
+0x00, 0x20, 0x07, 0x4a, 0x01, 0x21, 0x09, 0x05, 0x50, 0x61, 0xc8, 0x60,
+0xd0, 0x61, 0xc8, 0x61, 0x03, 0x23, 0xdb, 0x04, 0x03, 0x4a, 0x01, 0x21,
+0xd1, 0x63, 0x58, 0x60, 0xfc, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xc0, 0xb0, 0x01, 0x22, 0x00, 0x21,
+0x0a, 0x20, 0xfc, 0xf7, 0xd1, 0xff, 0x07, 0x1c, 0xff, 0x2f, 0x28, 0xd0,
+0x69, 0x46, 0xff, 0x22, 0x38, 0x1c, 0x01, 0x32, 0xfd, 0xf7, 0x54, 0xf9,
+0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x1b, 0xd1, 0x0d, 0x98, 0x00, 0x09,
+0x18, 0xd3, 0x38, 0x1c, 0xfd, 0xf7, 0x8d, 0xf8, 0x0e, 0x49, 0x01, 0x22,
+0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x0d, 0x48, 0x05, 0xd1, 0x0a, 0x68,
+0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x0a, 0x49,
+0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x64,
+0xff, 0xf7, 0xbc, 0xff, 0x38, 0x1c, 0xfd, 0xf7, 0x74, 0xf8, 0x40, 0xb0,
+0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
+0x00, 0x00, 0x10, 0x40, 0x07, 0x80, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x17, 0x49, 0x01, 0x22, 0x12, 0x04,
+0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68,
+0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x11, 0x49,
+0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x64,
+0x03, 0x20, 0xfe, 0xf7, 0xd3, 0xfc, 0xfb, 0xf7, 0x0d, 0xff, 0x01, 0x23,
+0x18, 0x43, 0xfb, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0x83, 0xfe, 0xff, 0xf7,
+0x9d, 0xff, 0xff, 0xf7, 0x05, 0xfe, 0xff, 0xf7, 0xf5, 0xfe, 0xff, 0xf7,
+0x09, 0xff, 0xff, 0xf7, 0x9b, 0xfd, 0xff, 0xf7, 0x21, 0xff, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
+0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03,
+0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88,
+0x40, 0x04, 0x43, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x04, 0x20, 0xaf, 0x60,
+0x41, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x08, 0x20, 0xc8, 0x23, 0x43, 0x43,
+0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3d, 0x4e, 0xc0, 0x46, 0x31, 0x61,
+0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3a, 0x4e, 0xc0, 0x46, 0xf3, 0x61,
+0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 0x81, 0x42,
+0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 0x41, 0x1e,
+0x32, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 0x02, 0x38,
+0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 0x06, 0xe0,
+0x2c, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 0x88, 0x42,
+0xd2, 0xd9, 0x2a, 0x49, 0x00, 0x20, 0xa3, 0x69, 0x9b, 0x08, 0x07, 0xd0,
+0x28, 0x4b, 0x87, 0x00, 0xcb, 0x51, 0xa7, 0x69, 0xbf, 0x08, 0x01, 0x30,
+0x87, 0x42, 0xf8, 0xd8, 0x22, 0x49, 0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89,
+0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 0x00, 0x20, 0x00, 0x22, 0x00, 0x2c,
+0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30,
+0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc,
+0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 0x00, 0x19, 0x40, 0x01, 0xc7, 0x19,
+0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01,
+0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60,
+0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69,
+0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51,
+0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00,
+0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
+0xb0, 0xbe, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
+0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00,
+0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09,
+0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61,
+0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x81, 0x61, 0x01, 0x20, 0x00, 0x06,
+0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18,
+0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61,
+0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05,
+0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20,
+0x40, 0x03, 0x81, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
+0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8,
+0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23,
+0x9b, 0x01, 0xfb, 0x18, 0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3,
+0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc,
+0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1d, 0x3e, 0xff, 0xff,
+0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47,
+0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b,
+0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c,
+0x59, 0x69, 0x53, 0x01, 0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43,
+0x87, 0x61, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc,
+0x70, 0x47, 0x18, 0x1c, 0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43,
+0x47, 0x61, 0xd7, 0x60, 0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00,
+0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c,
+0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9d, 0x6a,
+0xbd, 0x42, 0x05, 0xd1, 0x1d, 0x6b, 0x95, 0x42, 0x02, 0xd1, 0xdb, 0x6a,
+0x8b, 0x42, 0x1c, 0xd0, 0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20,
+0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9b, 0x6a,
+0x00, 0x2b, 0x09, 0xd1, 0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01,
+0xe3, 0x18, 0x1a, 0x63, 0xd9, 0x62, 0x5a, 0x63, 0x9f, 0x62, 0x02, 0xe0,
+0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20,
+0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
+0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0,
+0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01,
+0xe3, 0x18, 0x9b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19,
+0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61,
+0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62,
+0x53, 0x6b, 0xc0, 0x46, 0x53, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28,
+0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x9a, 0x68, 0x8a, 0x42,
+0x03, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20,
+0xc0, 0x43, 0xfa, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80,
+0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69,
+0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01,
+0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0xc0, 0x46,
+0x43, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61,
+0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x68, 0x0e, 0x00, 0x80,
+0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69,
+0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a,
+0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47,
+0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
+0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0xff, 0xf7, 0xe3, 0xff, 0x01, 0x34,
+0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc,
+0x18, 0x47, 0x00, 0x00,
};
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index e49e8b520c2..d5c32e9caa9 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -86,7 +86,7 @@ static const int multicast_filter_limit = 32;
#define RESPONSE_RING_SIZE (RESPONSE_ENTRIES * sizeof(struct resp_desc))
/* The 3XP will preload and remove 64 entries from the free buffer
- * list, and we need one entry to keep the ring from wrapping, so
+ * list, and we need one entry to keep the ring from wrapping, so
* to keep this a power of two, we use 128 entries.
*/
#define RXFREE_ENTRIES 128
@@ -100,8 +100,8 @@ static const int multicast_filter_limit = 32;
#define PKT_BUF_SZ 1536
#define DRV_MODULE_NAME "typhoon"
-#define DRV_MODULE_VERSION "1.5.7"
-#define DRV_MODULE_RELDATE "05/01/07"
+#define DRV_MODULE_VERSION "1.5.8"
+#define DRV_MODULE_RELDATE "06/11/09"
#define PFX DRV_MODULE_NAME ": "
#define ERR_PFX KERN_ERR PFX
@@ -269,7 +269,7 @@ struct rxbuff_ent {
struct typhoon {
/* Tx cache line section */
- struct transmit_ring txLoRing ____cacheline_aligned;
+ struct transmit_ring txLoRing ____cacheline_aligned;
struct pci_dev * tx_pdev;
void __iomem *tx_ioaddr;
u32 txlo_dma_addr;
@@ -333,11 +333,7 @@ enum state_values {
#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
-#define typhoon_synchronize_irq(x) synchronize_irq()
-#else
#define typhoon_synchronize_irq(x) synchronize_irq(x)
-#endif
#if defined(NETIF_F_TSO)
#define skb_tso_size(x) (skb_shinfo(x)->gso_size)
@@ -805,7 +801,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
* If problems develop with TSO, check this first.
*/
numDesc = skb_shinfo(skb)->nr_frags + 1;
- if(skb_tso_size(skb))
+ if (skb_is_gso(skb))
numDesc++;
/* When checking for free space in the ring, we need to also
@@ -830,7 +826,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
first_txd->addrHi = (u64)((unsigned long) skb) >> 32;
first_txd->processFlags = 0;
- if(skb->ip_summed == CHECKSUM_HW) {
+ if(skb->ip_summed == CHECKSUM_PARTIAL) {
/* The 3XP will figure out if this is UDP/TCP */
first_txd->processFlags |= TYPHOON_TX_PF_TCP_CHKSUM;
first_txd->processFlags |= TYPHOON_TX_PF_UDP_CHKSUM;
@@ -845,7 +841,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
TYPHOON_TX_PF_VLAN_TAG_SHIFT);
}
- if(skb_tso_size(skb)) {
+ if (skb_is_gso(skb)) {
first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
first_txd->numDesc++;
@@ -937,8 +933,6 @@ typhoon_set_rx_mode(struct net_device *dev)
filter = TYPHOON_RX_FILTER_DIRECTED | TYPHOON_RX_FILTER_BROADCAST;
if(dev->flags & IFF_PROMISC) {
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
filter |= TYPHOON_RX_FILTER_PROMISCOUS;
} else if((dev->mc_count > multicast_filter_limit) ||
(dev->flags & IFF_ALLMULTI)) {
@@ -1073,7 +1067,7 @@ typhoon_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
} else {
u32 sleep_ver = xp_resp[0].parm2;
snprintf(info->fw_version, 32, "%02x.%03x.%03x",
- sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
+ sleep_ver >> 24, (sleep_ver >> 12) & 0xfff,
sleep_ver & 0xfff);
}
}
@@ -1243,7 +1237,7 @@ typhoon_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
ering->tx_pending = TXLO_ENTRIES - 1;
}
-static struct ethtool_ops typhoon_ethtool_ops = {
+static const struct ethtool_ops typhoon_ethtool_ops = {
.get_settings = typhoon_get_settings,
.set_settings = typhoon_set_settings,
.get_drvinfo = typhoon_get_drvinfo,
@@ -2131,7 +2125,7 @@ typhoon_open(struct net_device *dev)
goto out_sleep;
}
- err = request_irq(dev->irq, &typhoon_interrupt, SA_SHIRQ,
+ err = request_irq(dev->irq, &typhoon_interrupt, IRQF_SHARED,
dev->name, dev);
if(err < 0)
goto out_sleep;
@@ -2154,7 +2148,7 @@ out_sleep:
goto out;
}
- if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
+ if(typhoon_sleep(tp, PCI_D3hot, 0) < 0)
printk(KERN_ERR "%s: unable to go back to sleep\n", dev->name);
out:
@@ -2568,9 +2562,10 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_drvdata(pdev, dev);
- printk(KERN_INFO "%s: %s at %s 0x%lx, ",
+ printk(KERN_INFO "%s: %s at %s 0x%llx, ",
dev->name, typhoon_card_info[card_id].name,
- use_mmio ? "MMIO" : "IO", pci_resource_start(pdev, use_mmio));
+ use_mmio ? "MMIO" : "IO",
+ (unsigned long long)pci_resource_start(pdev, use_mmio));
for(i = 0; i < 5; i++)
printk("%2.2x:", dev->dev_addr[i]);
printk("%2.2x\n", dev->dev_addr[i]);
@@ -2601,7 +2596,7 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
"(%u:%04x)\n", dev->name, xp_resp[0].numDesc,
le32_to_cpu(xp_resp[0].parm2));
}
-
+
return 0;
error_out_reset:
@@ -2659,7 +2654,7 @@ static struct pci_driver typhoon_driver = {
static int __init
typhoon_init(void)
{
- return pci_module_init(&typhoon_driver);
+ return pci_register_driver(&typhoon_driver);
}
static void __exit
diff --git a/drivers/net/typhoon.h b/drivers/net/typhoon.h
index 738ee71d8df..2f14a050051 100644
--- a/drivers/net/typhoon.h
+++ b/drivers/net/typhoon.h
@@ -46,7 +46,7 @@ struct transmit_ring {
/* The host<->Typhoon ring index structure
* This indicates the current positions in the rings
- *
+ *
* All values must be in little endian format for the 3XP
*
* rxHiCleared: entry we've cleared to in the Hi receive ring
@@ -131,7 +131,7 @@ struct typhoon_interface {
*
* A packet is described by a packet descriptor, followed by option descriptors,
* if any, then one or more fragment descriptors.
- *
+ *
* Packet descriptor:
* flags: Descriptor type
* len:i zero, or length of this packet
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
new file mode 100644
index 00000000000..700ebd7d145
--- /dev/null
+++ b/drivers/net/ucc_geth.c
@@ -0,0 +1,4263 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * QE UCC Gigabit Ethernet Driver
+ *
+ * Changelog:
+ * Jul 6, 2006 Li Yang <LeoLi@freescale.com>
+ * - Rearrange code and style fixes
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/fsl_devices.h>
+#include <linux/ethtool.h>
+#include <linux/platform_device.h>
+#include <linux/mii.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/ucc.h>
+#include <asm/ucc_fast.h>
+
+#include "ucc_geth.h"
+#include "ucc_geth_phy.h"
+
+#undef DEBUG
+
+#define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006"
+#define DRV_NAME "ucc_geth"
+
+#define ugeth_printk(level, format, arg...) \
+ printk(level format "\n", ## arg)
+
+#define ugeth_dbg(format, arg...) \
+ ugeth_printk(KERN_DEBUG , format , ## arg)
+#define ugeth_err(format, arg...) \
+ ugeth_printk(KERN_ERR , format , ## arg)
+#define ugeth_info(format, arg...) \
+ ugeth_printk(KERN_INFO , format , ## arg)
+#define ugeth_warn(format, arg...) \
+ ugeth_printk(KERN_WARNING , format , ## arg)
+
+#ifdef UGETH_VERBOSE_DEBUG
+#define ugeth_vdbg ugeth_dbg
+#else
+#define ugeth_vdbg(fmt, args...) do { } while (0)
+#endif /* UGETH_VERBOSE_DEBUG */
+
+static DEFINE_SPINLOCK(ugeth_lock);
+
+static ucc_geth_info_t ugeth_primary_info = {
+ .uf_info = {
+ .bd_mem_part = MEM_PART_SYSTEM,
+ .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES,
+ .max_rx_buf_length = 1536,
+/* FIXME: should be changed in run time for 1G and 100M */
+#ifdef CONFIG_UGETH_HAS_GIGA
+ .urfs = UCC_GETH_URFS_GIGA_INIT,
+ .urfet = UCC_GETH_URFET_GIGA_INIT,
+ .urfset = UCC_GETH_URFSET_GIGA_INIT,
+ .utfs = UCC_GETH_UTFS_GIGA_INIT,
+ .utfet = UCC_GETH_UTFET_GIGA_INIT,
+ .utftt = UCC_GETH_UTFTT_GIGA_INIT,
+#else
+ .urfs = UCC_GETH_URFS_INIT,
+ .urfet = UCC_GETH_URFET_INIT,
+ .urfset = UCC_GETH_URFSET_INIT,
+ .utfs = UCC_GETH_UTFS_INIT,
+ .utfet = UCC_GETH_UTFET_INIT,
+ .utftt = UCC_GETH_UTFTT_INIT,
+#endif
+ .ufpt = 256,
+ .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET,
+ .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL,
+ .tenc = UCC_FAST_TX_ENCODING_NRZ,
+ .renc = UCC_FAST_RX_ENCODING_NRZ,
+ .tcrc = UCC_FAST_16_BIT_CRC,
+ .synl = UCC_FAST_SYNC_LEN_NOT_USED,
+ },
+ .numQueuesTx = 1,
+ .numQueuesRx = 1,
+ .extendedFilteringChainPointer = ((uint32_t) NULL),
+ .typeorlen = 3072 /*1536 */ ,
+ .nonBackToBackIfgPart1 = 0x40,
+ .nonBackToBackIfgPart2 = 0x60,
+ .miminumInterFrameGapEnforcement = 0x50,
+ .backToBackInterFrameGap = 0x60,
+ .mblinterval = 128,
+ .nortsrbytetime = 5,
+ .fracsiz = 1,
+ .strictpriorityq = 0xff,
+ .altBebTruncation = 0xa,
+ .excessDefer = 1,
+ .maxRetransmission = 0xf,
+ .collisionWindow = 0x37,
+ .receiveFlowControl = 1,
+ .maxGroupAddrInHash = 4,
+ .maxIndAddrInHash = 4,
+ .prel = 7,
+ .maxFrameLength = 1518,
+ .minFrameLength = 64,
+ .maxD1Length = 1520,
+ .maxD2Length = 1520,
+ .vlantype = 0x8100,
+ .ecamptr = ((uint32_t) NULL),
+ .eventRegMask = UCCE_OTHER,
+ .pausePeriod = 0xf000,
+ .interruptcoalescingmaxvalue = {1, 1, 1, 1, 1, 1, 1, 1},
+ .bdRingLenTx = {
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN,
+ TX_BD_RING_LEN},
+
+ .bdRingLenRx = {
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN,
+ RX_BD_RING_LEN},
+
+ .numStationAddresses = UCC_GETH_NUM_OF_STATION_ADDRESSES_1,
+ .largestexternallookupkeysize =
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE,
+ .statisticsMode = UCC_GETH_STATISTICS_GATHERING_MODE_NONE,
+ .vlanOperationTagged = UCC_GETH_VLAN_OPERATION_TAGGED_NOP,
+ .vlanOperationNonTagged = UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP,
+ .rxQoSMode = UCC_GETH_QOS_MODE_DEFAULT,
+ .aufc = UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE,
+ .padAndCrc = MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC,
+ .numThreadsTx = UCC_GETH_NUM_OF_THREADS_4,
+ .numThreadsRx = UCC_GETH_NUM_OF_THREADS_4,
+ .riscTx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+ .riscRx = QE_RISC_ALLOCATION_RISC1_AND_RISC2,
+};
+
+static ucc_geth_info_t ugeth_info[8];
+
+#ifdef DEBUG
+static void mem_disp(u8 *addr, int size)
+{
+ u8 *i;
+ int size16Aling = (size >> 4) << 4;
+ int size4Aling = (size >> 2) << 2;
+ int notAlign = 0;
+ if (size % 16)
+ notAlign = 1;
+
+ for (i = addr; (u32) i < (u32) addr + size16Aling; i += 16)
+ printk("0x%08x: %08x %08x %08x %08x\r\n",
+ (u32) i,
+ *((u32 *) (i)),
+ *((u32 *) (i + 4)),
+ *((u32 *) (i + 8)), *((u32 *) (i + 12)));
+ if (notAlign == 1)
+ printk("0x%08x: ", (u32) i);
+ for (; (u32) i < (u32) addr + size4Aling; i += 4)
+ printk("%08x ", *((u32 *) (i)));
+ for (; (u32) i < (u32) addr + size; i++)
+ printk("%02x", *((u8 *) (i)));
+ if (notAlign == 1)
+ printk("\r\n");
+}
+#endif /* DEBUG */
+
+#ifdef CONFIG_UGETH_FILTERING
+static void enqueue(struct list_head *node, struct list_head *lh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(ugeth_lock, flags);
+ list_add_tail(node, lh);
+ spin_unlock_irqrestore(ugeth_lock, flags);
+}
+#endif /* CONFIG_UGETH_FILTERING */
+
+static struct list_head *dequeue(struct list_head *lh)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(ugeth_lock, flags);
+ if (!list_empty(lh)) {
+ struct list_head *node = lh->next;
+ list_del(node);
+ spin_unlock_irqrestore(ugeth_lock, flags);
+ return node;
+ } else {
+ spin_unlock_irqrestore(ugeth_lock, flags);
+ return NULL;
+ }
+}
+
+static int get_interface_details(enet_interface_e enet_interface,
+ enet_speed_e *speed,
+ int *r10m,
+ int *rmm,
+ int *rpm,
+ int *tbi, int *limited_to_full_duplex)
+{
+ /* Analyze enet_interface according to Interface Mode
+ Configuration table */
+ switch (enet_interface) {
+ case ENET_10_MII:
+ *speed = ENET_SPEED_10BT;
+ break;
+ case ENET_10_RMII:
+ *speed = ENET_SPEED_10BT;
+ *r10m = 1;
+ *rmm = 1;
+ break;
+ case ENET_10_RGMII:
+ *speed = ENET_SPEED_10BT;
+ *rpm = 1;
+ *r10m = 1;
+ *limited_to_full_duplex = 1;
+ break;
+ case ENET_100_MII:
+ *speed = ENET_SPEED_100BT;
+ break;
+ case ENET_100_RMII:
+ *speed = ENET_SPEED_100BT;
+ *rmm = 1;
+ break;
+ case ENET_100_RGMII:
+ *speed = ENET_SPEED_100BT;
+ *rpm = 1;
+ *limited_to_full_duplex = 1;
+ break;
+ case ENET_1000_GMII:
+ *speed = ENET_SPEED_1000BT;
+ *limited_to_full_duplex = 1;
+ break;
+ case ENET_1000_RGMII:
+ *speed = ENET_SPEED_1000BT;
+ *rpm = 1;
+ *limited_to_full_duplex = 1;
+ break;
+ case ENET_1000_TBI:
+ *speed = ENET_SPEED_1000BT;
+ *tbi = 1;
+ *limited_to_full_duplex = 1;
+ break;
+ case ENET_1000_RTBI:
+ *speed = ENET_SPEED_1000BT;
+ *rpm = 1;
+ *tbi = 1;
+ *limited_to_full_duplex = 1;
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+
+ return 0;
+}
+
+static struct sk_buff *get_new_skb(ucc_geth_private_t *ugeth, u8 *bd)
+{
+ struct sk_buff *skb = NULL;
+
+ skb = dev_alloc_skb(ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT);
+
+ if (skb == NULL)
+ return NULL;
+
+ /* We need the data buffer to be aligned properly. We will reserve
+ * as many bytes as needed to align the data properly
+ */
+ skb_reserve(skb,
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT -
+ (((unsigned)skb->data) & (UCC_GETH_RX_DATA_BUF_ALIGNMENT -
+ 1)));
+
+ skb->dev = ugeth->dev;
+
+ BD_BUFFER_SET(bd,
+ dma_map_single(NULL,
+ skb->data,
+ ugeth->ug_info->uf_info.max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT,
+ DMA_FROM_DEVICE));
+
+ BD_STATUS_AND_LENGTH_SET(bd,
+ (R_E | R_I |
+ (BD_STATUS_AND_LENGTH(bd) & R_W)));
+
+ return skb;
+}
+
+static int rx_bd_buffer_set(ucc_geth_private_t *ugeth, u8 rxQ)
+{
+ u8 *bd;
+ u32 bd_status;
+ struct sk_buff *skb;
+ int i;
+
+ bd = ugeth->p_rx_bd_ring[rxQ];
+ i = 0;
+
+ do {
+ bd_status = BD_STATUS_AND_LENGTH(bd);
+ skb = get_new_skb(ugeth, bd);
+
+ if (!skb) /* If can not allocate data buffer,
+ abort. Cleanup will be elsewhere */
+ return -ENOMEM;
+
+ ugeth->rx_skbuff[rxQ][i] = skb;
+
+ /* advance the BD pointer */
+ bd += UCC_GETH_SIZE_OF_BD;
+ i++;
+ } while (!(bd_status & R_W));
+
+ return 0;
+}
+
+static int fill_init_enet_entries(ucc_geth_private_t *ugeth,
+ volatile u32 *p_start,
+ u8 num_entries,
+ u32 thread_size,
+ u32 thread_alignment,
+ qe_risc_allocation_e risc,
+ int skip_page_for_first_entry)
+{
+ u32 init_enet_offset;
+ u8 i;
+ int snum;
+
+ for (i = 0; i < num_entries; i++) {
+ if ((snum = qe_get_snum()) < 0) {
+ ugeth_err("fill_init_enet_entries: Can not get SNUM.");
+ return snum;
+ }
+ if ((i == 0) && skip_page_for_first_entry)
+ /* First entry of Rx does not have page */
+ init_enet_offset = 0;
+ else {
+ init_enet_offset =
+ qe_muram_alloc(thread_size, thread_alignment);
+ if (IS_MURAM_ERR(init_enet_offset)) {
+ ugeth_err
+ ("fill_init_enet_entries: Can not allocate DPRAM memory.");
+ qe_put_snum((u8) snum);
+ return -ENOMEM;
+ }
+ }
+ *(p_start++) =
+ ((u8) snum << ENET_INIT_PARAM_SNUM_SHIFT) | init_enet_offset
+ | risc;
+ }
+
+ return 0;
+}
+
+static int return_init_enet_entries(ucc_geth_private_t *ugeth,
+ volatile u32 *p_start,
+ u8 num_entries,
+ qe_risc_allocation_e risc,
+ int skip_page_for_first_entry)
+{
+ u32 init_enet_offset;
+ u8 i;
+ int snum;
+
+ for (i = 0; i < num_entries; i++) {
+ /* Check that this entry was actually valid --
+ needed in case failed in allocations */
+ if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) {
+ snum =
+ (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >>
+ ENET_INIT_PARAM_SNUM_SHIFT;
+ qe_put_snum((u8) snum);
+ if (!((i == 0) && skip_page_for_first_entry)) {
+ /* First entry of Rx does not have page */
+ init_enet_offset =
+ (in_be32(p_start) &
+ ENET_INIT_PARAM_PTR_MASK);
+ qe_muram_free(init_enet_offset);
+ }
+ *(p_start++) = 0; /* Just for cosmetics */
+ }
+ }
+
+ return 0;
+}
+
+#ifdef DEBUG
+static int dump_init_enet_entries(ucc_geth_private_t *ugeth,
+ volatile u32 *p_start,
+ u8 num_entries,
+ u32 thread_size,
+ qe_risc_allocation_e risc,
+ int skip_page_for_first_entry)
+{
+ u32 init_enet_offset;
+ u8 i;
+ int snum;
+
+ for (i = 0; i < num_entries; i++) {
+ /* Check that this entry was actually valid --
+ needed in case failed in allocations */
+ if ((*p_start & ENET_INIT_PARAM_RISC_MASK) == risc) {
+ snum =
+ (u32) (*p_start & ENET_INIT_PARAM_SNUM_MASK) >>
+ ENET_INIT_PARAM_SNUM_SHIFT;
+ qe_put_snum((u8) snum);
+ if (!((i == 0) && skip_page_for_first_entry)) {
+ /* First entry of Rx does not have page */
+ init_enet_offset =
+ (in_be32(p_start) &
+ ENET_INIT_PARAM_PTR_MASK);
+ ugeth_info("Init enet entry %d:", i);
+ ugeth_info("Base address: 0x%08x",
+ (u32)
+ qe_muram_addr(init_enet_offset));
+ mem_disp(qe_muram_addr(init_enet_offset),
+ thread_size);
+ }
+ p_start++;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_UGETH_FILTERING
+static enet_addr_container_t *get_enet_addr_container(void)
+{
+ enet_addr_container_t *enet_addr_cont;
+
+ /* allocate memory */
+ enet_addr_cont = kmalloc(sizeof(enet_addr_container_t), GFP_KERNEL);
+ if (!enet_addr_cont) {
+ ugeth_err("%s: No memory for enet_addr_container_t object.",
+ __FUNCTION__);
+ return NULL;
+ }
+
+ return enet_addr_cont;
+}
+#endif /* CONFIG_UGETH_FILTERING */
+
+static void put_enet_addr_container(enet_addr_container_t *enet_addr_cont)
+{
+ kfree(enet_addr_cont);
+}
+
+#ifdef CONFIG_UGETH_FILTERING
+static int hw_add_addr_in_paddr(ucc_geth_private_t *ugeth,
+ enet_addr_t *p_enet_addr, u8 paddr_num)
+{
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+
+ if (!(paddr_num < NUM_OF_PADDRS)) {
+ ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ /* Ethernet frames are defined in Little Endian mode, */
+ /* therefore to insert the address we reverse the bytes. */
+ out_be16(&p_82xx_addr_filt->paddr[paddr_num].h,
+ (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) |
+ (u16) (*p_enet_addr)[4]));
+ out_be16(&p_82xx_addr_filt->paddr[paddr_num].m,
+ (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) |
+ (u16) (*p_enet_addr)[2]));
+ out_be16(&p_82xx_addr_filt->paddr[paddr_num].l,
+ (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) |
+ (u16) (*p_enet_addr)[0]));
+
+ return 0;
+}
+#endif /* CONFIG_UGETH_FILTERING */
+
+static int hw_clear_addr_in_paddr(ucc_geth_private_t *ugeth, u8 paddr_num)
+{
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+
+ if (!(paddr_num < NUM_OF_PADDRS)) {
+ ugeth_warn("%s: Illagel paddr_num.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ /* Writing address ff.ff.ff.ff.ff.ff disables address
+ recognition for this register */
+ out_be16(&p_82xx_addr_filt->paddr[paddr_num].h, 0xffff);
+ out_be16(&p_82xx_addr_filt->paddr[paddr_num].m, 0xffff);
+ out_be16(&p_82xx_addr_filt->paddr[paddr_num].l, 0xffff);
+
+ return 0;
+}
+
+static void hw_add_addr_in_hash(ucc_geth_private_t *ugeth,
+ enet_addr_t *p_enet_addr)
+{
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+ u32 cecr_subblock;
+
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+
+ /* Ethernet frames are defined in Little Endian mode,
+ therefor to insert */
+ /* the address to the hash (Big Endian mode), we reverse the bytes.*/
+ out_be16(&p_82xx_addr_filt->taddr.h,
+ (u16) (((u16) (((u16) ((*p_enet_addr)[5])) << 8)) |
+ (u16) (*p_enet_addr)[4]));
+ out_be16(&p_82xx_addr_filt->taddr.m,
+ (u16) (((u16) (((u16) ((*p_enet_addr)[3])) << 8)) |
+ (u16) (*p_enet_addr)[2]));
+ out_be16(&p_82xx_addr_filt->taddr.l,
+ (u16) (((u16) (((u16) ((*p_enet_addr)[1])) << 8)) |
+ (u16) (*p_enet_addr)[0]));
+
+ qe_issue_cmd(QE_SET_GROUP_ADDRESS, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_ETHERNET, 0);
+}
+
+#ifdef CONFIG_UGETH_MAGIC_PACKET
+static void magic_packet_detection_enable(ucc_geth_private_t *ugeth)
+{
+ ucc_fast_private_t *uccf;
+ ucc_geth_t *ug_regs;
+ u32 maccfg2, uccm;
+
+ uccf = ugeth->uccf;
+ ug_regs = ugeth->ug_regs;
+
+ /* Enable interrupts for magic packet detection */
+ uccm = in_be32(uccf->p_uccm);
+ uccm |= UCCE_MPD;
+ out_be32(uccf->p_uccm, uccm);
+
+ /* Enable magic packet detection */
+ maccfg2 = in_be32(&ug_regs->maccfg2);
+ maccfg2 |= MACCFG2_MPE;
+ out_be32(&ug_regs->maccfg2, maccfg2);
+}
+
+static void magic_packet_detection_disable(ucc_geth_private_t *ugeth)
+{
+ ucc_fast_private_t *uccf;
+ ucc_geth_t *ug_regs;
+ u32 maccfg2, uccm;
+
+ uccf = ugeth->uccf;
+ ug_regs = ugeth->ug_regs;
+
+ /* Disable interrupts for magic packet detection */
+ uccm = in_be32(uccf->p_uccm);
+ uccm &= ~UCCE_MPD;
+ out_be32(uccf->p_uccm, uccm);
+
+ /* Disable magic packet detection */
+ maccfg2 = in_be32(&ug_regs->maccfg2);
+ maccfg2 &= ~MACCFG2_MPE;
+ out_be32(&ug_regs->maccfg2, maccfg2);
+}
+#endif /* MAGIC_PACKET */
+
+static inline int compare_addr(enet_addr_t *addr1, enet_addr_t *addr2)
+{
+ return memcmp(addr1, addr2, ENET_NUM_OCTETS_PER_ADDRESS);
+}
+
+#ifdef DEBUG
+static void get_statistics(ucc_geth_private_t *ugeth,
+ ucc_geth_tx_firmware_statistics_t *
+ tx_firmware_statistics,
+ ucc_geth_rx_firmware_statistics_t *
+ rx_firmware_statistics,
+ ucc_geth_hardware_statistics_t *hardware_statistics)
+{
+ ucc_fast_t *uf_regs;
+ ucc_geth_t *ug_regs;
+ ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram;
+ ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram;
+
+ ug_regs = ugeth->ug_regs;
+ uf_regs = (ucc_fast_t *) ug_regs;
+ p_tx_fw_statistics_pram = ugeth->p_tx_fw_statistics_pram;
+ p_rx_fw_statistics_pram = ugeth->p_rx_fw_statistics_pram;
+
+ /* Tx firmware only if user handed pointer and driver actually
+ gathers Tx firmware statistics */
+ if (tx_firmware_statistics && p_tx_fw_statistics_pram) {
+ tx_firmware_statistics->sicoltx =
+ in_be32(&p_tx_fw_statistics_pram->sicoltx);
+ tx_firmware_statistics->mulcoltx =
+ in_be32(&p_tx_fw_statistics_pram->mulcoltx);
+ tx_firmware_statistics->latecoltxfr =
+ in_be32(&p_tx_fw_statistics_pram->latecoltxfr);
+ tx_firmware_statistics->frabortduecol =
+ in_be32(&p_tx_fw_statistics_pram->frabortduecol);
+ tx_firmware_statistics->frlostinmactxer =
+ in_be32(&p_tx_fw_statistics_pram->frlostinmactxer);
+ tx_firmware_statistics->carriersenseertx =
+ in_be32(&p_tx_fw_statistics_pram->carriersenseertx);
+ tx_firmware_statistics->frtxok =
+ in_be32(&p_tx_fw_statistics_pram->frtxok);
+ tx_firmware_statistics->txfrexcessivedefer =
+ in_be32(&p_tx_fw_statistics_pram->txfrexcessivedefer);
+ tx_firmware_statistics->txpkts256 =
+ in_be32(&p_tx_fw_statistics_pram->txpkts256);
+ tx_firmware_statistics->txpkts512 =
+ in_be32(&p_tx_fw_statistics_pram->txpkts512);
+ tx_firmware_statistics->txpkts1024 =
+ in_be32(&p_tx_fw_statistics_pram->txpkts1024);
+ tx_firmware_statistics->txpktsjumbo =
+ in_be32(&p_tx_fw_statistics_pram->txpktsjumbo);
+ }
+
+ /* Rx firmware only if user handed pointer and driver actually
+ * gathers Rx firmware statistics */
+ if (rx_firmware_statistics && p_rx_fw_statistics_pram) {
+ int i;
+ rx_firmware_statistics->frrxfcser =
+ in_be32(&p_rx_fw_statistics_pram->frrxfcser);
+ rx_firmware_statistics->fraligner =
+ in_be32(&p_rx_fw_statistics_pram->fraligner);
+ rx_firmware_statistics->inrangelenrxer =
+ in_be32(&p_rx_fw_statistics_pram->inrangelenrxer);
+ rx_firmware_statistics->outrangelenrxer =
+ in_be32(&p_rx_fw_statistics_pram->outrangelenrxer);
+ rx_firmware_statistics->frtoolong =
+ in_be32(&p_rx_fw_statistics_pram->frtoolong);
+ rx_firmware_statistics->runt =
+ in_be32(&p_rx_fw_statistics_pram->runt);
+ rx_firmware_statistics->verylongevent =
+ in_be32(&p_rx_fw_statistics_pram->verylongevent);
+ rx_firmware_statistics->symbolerror =
+ in_be32(&p_rx_fw_statistics_pram->symbolerror);
+ rx_firmware_statistics->dropbsy =
+ in_be32(&p_rx_fw_statistics_pram->dropbsy);
+ for (i = 0; i < 0x8; i++)
+ rx_firmware_statistics->res0[i] =
+ p_rx_fw_statistics_pram->res0[i];
+ rx_firmware_statistics->mismatchdrop =
+ in_be32(&p_rx_fw_statistics_pram->mismatchdrop);
+ rx_firmware_statistics->underpkts =
+ in_be32(&p_rx_fw_statistics_pram->underpkts);
+ rx_firmware_statistics->pkts256 =
+ in_be32(&p_rx_fw_statistics_pram->pkts256);
+ rx_firmware_statistics->pkts512 =
+ in_be32(&p_rx_fw_statistics_pram->pkts512);
+ rx_firmware_statistics->pkts1024 =
+ in_be32(&p_rx_fw_statistics_pram->pkts1024);
+ rx_firmware_statistics->pktsjumbo =
+ in_be32(&p_rx_fw_statistics_pram->pktsjumbo);
+ rx_firmware_statistics->frlossinmacer =
+ in_be32(&p_rx_fw_statistics_pram->frlossinmacer);
+ rx_firmware_statistics->pausefr =
+ in_be32(&p_rx_fw_statistics_pram->pausefr);
+ for (i = 0; i < 0x4; i++)
+ rx_firmware_statistics->res1[i] =
+ p_rx_fw_statistics_pram->res1[i];
+ rx_firmware_statistics->removevlan =
+ in_be32(&p_rx_fw_statistics_pram->removevlan);
+ rx_firmware_statistics->replacevlan =
+ in_be32(&p_rx_fw_statistics_pram->replacevlan);
+ rx_firmware_statistics->insertvlan =
+ in_be32(&p_rx_fw_statistics_pram->insertvlan);
+ }
+
+ /* Hardware only if user handed pointer and driver actually
+ gathers hardware statistics */
+ if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) {
+ hardware_statistics->tx64 = in_be32(&ug_regs->tx64);
+ hardware_statistics->tx127 = in_be32(&ug_regs->tx127);
+ hardware_statistics->tx255 = in_be32(&ug_regs->tx255);
+ hardware_statistics->rx64 = in_be32(&ug_regs->rx64);
+ hardware_statistics->rx127 = in_be32(&ug_regs->rx127);
+ hardware_statistics->rx255 = in_be32(&ug_regs->rx255);
+ hardware_statistics->txok = in_be32(&ug_regs->txok);
+ hardware_statistics->txcf = in_be16(&ug_regs->txcf);
+ hardware_statistics->tmca = in_be32(&ug_regs->tmca);
+ hardware_statistics->tbca = in_be32(&ug_regs->tbca);
+ hardware_statistics->rxfok = in_be32(&ug_regs->rxfok);
+ hardware_statistics->rxbok = in_be32(&ug_regs->rxbok);
+ hardware_statistics->rbyt = in_be32(&ug_regs->rbyt);
+ hardware_statistics->rmca = in_be32(&ug_regs->rmca);
+ hardware_statistics->rbca = in_be32(&ug_regs->rbca);
+ }
+}
+
+static void dump_bds(ucc_geth_private_t *ugeth)
+{
+ int i;
+ int length;
+
+ for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
+ if (ugeth->p_tx_bd_ring[i]) {
+ length =
+ (ugeth->ug_info->bdRingLenTx[i] *
+ UCC_GETH_SIZE_OF_BD);
+ ugeth_info("TX BDs[%d]", i);
+ mem_disp(ugeth->p_tx_bd_ring[i], length);
+ }
+ }
+ for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
+ if (ugeth->p_rx_bd_ring[i]) {
+ length =
+ (ugeth->ug_info->bdRingLenRx[i] *
+ UCC_GETH_SIZE_OF_BD);
+ ugeth_info("RX BDs[%d]", i);
+ mem_disp(ugeth->p_rx_bd_ring[i], length);
+ }
+ }
+}
+
+static void dump_regs(ucc_geth_private_t *ugeth)
+{
+ int i;
+
+ ugeth_info("UCC%d Geth registers:", ugeth->ug_info->uf_info.ucc_num);
+ ugeth_info("Base address: 0x%08x", (u32) ugeth->ug_regs);
+
+ ugeth_info("maccfg1 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->maccfg1,
+ in_be32(&ugeth->ug_regs->maccfg1));
+ ugeth_info("maccfg2 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->maccfg2,
+ in_be32(&ugeth->ug_regs->maccfg2));
+ ugeth_info("ipgifg : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->ipgifg,
+ in_be32(&ugeth->ug_regs->ipgifg));
+ ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->hafdup,
+ in_be32(&ugeth->ug_regs->hafdup));
+ ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->miimng.miimcfg,
+ in_be32(&ugeth->ug_regs->miimng.miimcfg));
+ ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->miimng.miimcom,
+ in_be32(&ugeth->ug_regs->miimng.miimcom));
+ ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->miimng.miimadd,
+ in_be32(&ugeth->ug_regs->miimng.miimadd));
+ ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->miimng.miimcon,
+ in_be32(&ugeth->ug_regs->miimng.miimcon));
+ ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->miimng.miimstat,
+ in_be32(&ugeth->ug_regs->miimng.miimstat));
+ ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->miimng.miimind,
+ in_be32(&ugeth->ug_regs->miimng.miimind));
+ ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->ifctl,
+ in_be32(&ugeth->ug_regs->ifctl));
+ ugeth_info("ifstat : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->ifstat,
+ in_be32(&ugeth->ug_regs->ifstat));
+ ugeth_info("macstnaddr1: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->macstnaddr1,
+ in_be32(&ugeth->ug_regs->macstnaddr1));
+ ugeth_info("macstnaddr2: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->macstnaddr2,
+ in_be32(&ugeth->ug_regs->macstnaddr2));
+ ugeth_info("uempr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->uempr,
+ in_be32(&ugeth->ug_regs->uempr));
+ ugeth_info("utbipar : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->utbipar,
+ in_be32(&ugeth->ug_regs->utbipar));
+ ugeth_info("uescr : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->ug_regs->uescr,
+ in_be16(&ugeth->ug_regs->uescr));
+ ugeth_info("tx64 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->tx64,
+ in_be32(&ugeth->ug_regs->tx64));
+ ugeth_info("tx127 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->tx127,
+ in_be32(&ugeth->ug_regs->tx127));
+ ugeth_info("tx255 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->tx255,
+ in_be32(&ugeth->ug_regs->tx255));
+ ugeth_info("rx64 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rx64,
+ in_be32(&ugeth->ug_regs->rx64));
+ ugeth_info("rx127 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rx127,
+ in_be32(&ugeth->ug_regs->rx127));
+ ugeth_info("rx255 : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rx255,
+ in_be32(&ugeth->ug_regs->rx255));
+ ugeth_info("txok : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->txok,
+ in_be32(&ugeth->ug_regs->txok));
+ ugeth_info("txcf : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->ug_regs->txcf,
+ in_be16(&ugeth->ug_regs->txcf));
+ ugeth_info("tmca : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->tmca,
+ in_be32(&ugeth->ug_regs->tmca));
+ ugeth_info("tbca : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->tbca,
+ in_be32(&ugeth->ug_regs->tbca));
+ ugeth_info("rxfok : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rxfok,
+ in_be32(&ugeth->ug_regs->rxfok));
+ ugeth_info("rxbok : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rxbok,
+ in_be32(&ugeth->ug_regs->rxbok));
+ ugeth_info("rbyt : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rbyt,
+ in_be32(&ugeth->ug_regs->rbyt));
+ ugeth_info("rmca : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rmca,
+ in_be32(&ugeth->ug_regs->rmca));
+ ugeth_info("rbca : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->rbca,
+ in_be32(&ugeth->ug_regs->rbca));
+ ugeth_info("scar : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->scar,
+ in_be32(&ugeth->ug_regs->scar));
+ ugeth_info("scam : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->ug_regs->scam,
+ in_be32(&ugeth->ug_regs->scam));
+
+ if (ugeth->p_thread_data_tx) {
+ int numThreadsTxNumerical;
+ switch (ugeth->ug_info->numThreadsTx) {
+ case UCC_GETH_NUM_OF_THREADS_1:
+ numThreadsTxNumerical = 1;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_2:
+ numThreadsTxNumerical = 2;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_4:
+ numThreadsTxNumerical = 4;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_6:
+ numThreadsTxNumerical = 6;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_8:
+ numThreadsTxNumerical = 8;
+ break;
+ default:
+ numThreadsTxNumerical = 0;
+ break;
+ }
+
+ ugeth_info("Thread data TXs:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_thread_data_tx);
+ for (i = 0; i < numThreadsTxNumerical; i++) {
+ ugeth_info("Thread data TX[%d]:", i);
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_thread_data_tx[i]);
+ mem_disp((u8 *) & ugeth->p_thread_data_tx[i],
+ sizeof(ucc_geth_thread_data_tx_t));
+ }
+ }
+ if (ugeth->p_thread_data_rx) {
+ int numThreadsRxNumerical;
+ switch (ugeth->ug_info->numThreadsRx) {
+ case UCC_GETH_NUM_OF_THREADS_1:
+ numThreadsRxNumerical = 1;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_2:
+ numThreadsRxNumerical = 2;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_4:
+ numThreadsRxNumerical = 4;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_6:
+ numThreadsRxNumerical = 6;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_8:
+ numThreadsRxNumerical = 8;
+ break;
+ default:
+ numThreadsRxNumerical = 0;
+ break;
+ }
+
+ ugeth_info("Thread data RX:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_thread_data_rx);
+ for (i = 0; i < numThreadsRxNumerical; i++) {
+ ugeth_info("Thread data RX[%d]:", i);
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_thread_data_rx[i]);
+ mem_disp((u8 *) & ugeth->p_thread_data_rx[i],
+ sizeof(ucc_geth_thread_data_rx_t));
+ }
+ }
+ if (ugeth->p_exf_glbl_param) {
+ ugeth_info("EXF global param:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_exf_glbl_param);
+ mem_disp((u8 *) ugeth->p_exf_glbl_param,
+ sizeof(*ugeth->p_exf_glbl_param));
+ }
+ if (ugeth->p_tx_glbl_pram) {
+ ugeth_info("TX global param:");
+ ugeth_info("Base address: 0x%08x", (u32) ugeth->p_tx_glbl_pram);
+ ugeth_info("temoder : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_tx_glbl_pram->temoder,
+ in_be16(&ugeth->p_tx_glbl_pram->temoder));
+ ugeth_info("sqptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->sqptr,
+ in_be32(&ugeth->p_tx_glbl_pram->sqptr));
+ ugeth_info("schedulerbasepointer: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->schedulerbasepointer,
+ in_be32(&ugeth->p_tx_glbl_pram->
+ schedulerbasepointer));
+ ugeth_info("txrmonbaseptr: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->txrmonbaseptr,
+ in_be32(&ugeth->p_tx_glbl_pram->txrmonbaseptr));
+ ugeth_info("tstate : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->tstate,
+ in_be32(&ugeth->p_tx_glbl_pram->tstate));
+ ugeth_info("iphoffset[0] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[0],
+ ugeth->p_tx_glbl_pram->iphoffset[0]);
+ ugeth_info("iphoffset[1] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[1],
+ ugeth->p_tx_glbl_pram->iphoffset[1]);
+ ugeth_info("iphoffset[2] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[2],
+ ugeth->p_tx_glbl_pram->iphoffset[2]);
+ ugeth_info("iphoffset[3] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[3],
+ ugeth->p_tx_glbl_pram->iphoffset[3]);
+ ugeth_info("iphoffset[4] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[4],
+ ugeth->p_tx_glbl_pram->iphoffset[4]);
+ ugeth_info("iphoffset[5] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[5],
+ ugeth->p_tx_glbl_pram->iphoffset[5]);
+ ugeth_info("iphoffset[6] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[6],
+ ugeth->p_tx_glbl_pram->iphoffset[6]);
+ ugeth_info("iphoffset[7] : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_tx_glbl_pram->iphoffset[7],
+ ugeth->p_tx_glbl_pram->iphoffset[7]);
+ ugeth_info("vtagtable[0] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[0],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[0]));
+ ugeth_info("vtagtable[1] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[1],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[1]));
+ ugeth_info("vtagtable[2] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[2],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[2]));
+ ugeth_info("vtagtable[3] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[3],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[3]));
+ ugeth_info("vtagtable[4] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[4],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[4]));
+ ugeth_info("vtagtable[5] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[5],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[5]));
+ ugeth_info("vtagtable[6] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[6],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[6]));
+ ugeth_info("vtagtable[7] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->vtagtable[7],
+ in_be32(&ugeth->p_tx_glbl_pram->vtagtable[7]));
+ ugeth_info("tqptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_tx_glbl_pram->tqptr,
+ in_be32(&ugeth->p_tx_glbl_pram->tqptr));
+ }
+ if (ugeth->p_rx_glbl_pram) {
+ ugeth_info("RX global param:");
+ ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_glbl_pram);
+ ugeth_info("remoder : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->remoder,
+ in_be32(&ugeth->p_rx_glbl_pram->remoder));
+ ugeth_info("rqptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->rqptr,
+ in_be32(&ugeth->p_rx_glbl_pram->rqptr));
+ ugeth_info("typeorlen : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->typeorlen,
+ in_be16(&ugeth->p_rx_glbl_pram->typeorlen));
+ ugeth_info("rxgstpack : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_rx_glbl_pram->rxgstpack,
+ ugeth->p_rx_glbl_pram->rxgstpack);
+ ugeth_info("rxrmonbaseptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->rxrmonbaseptr,
+ in_be32(&ugeth->p_rx_glbl_pram->rxrmonbaseptr));
+ ugeth_info("intcoalescingptr: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->intcoalescingptr,
+ in_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr));
+ ugeth_info("rstate : addr - 0x%08x, val - 0x%02x",
+ (u32) & ugeth->p_rx_glbl_pram->rstate,
+ ugeth->p_rx_glbl_pram->rstate);
+ ugeth_info("mrblr : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->mrblr,
+ in_be16(&ugeth->p_rx_glbl_pram->mrblr));
+ ugeth_info("rbdqptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->rbdqptr,
+ in_be32(&ugeth->p_rx_glbl_pram->rbdqptr));
+ ugeth_info("mflr : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->mflr,
+ in_be16(&ugeth->p_rx_glbl_pram->mflr));
+ ugeth_info("minflr : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->minflr,
+ in_be16(&ugeth->p_rx_glbl_pram->minflr));
+ ugeth_info("maxd1 : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->maxd1,
+ in_be16(&ugeth->p_rx_glbl_pram->maxd1));
+ ugeth_info("maxd2 : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->maxd2,
+ in_be16(&ugeth->p_rx_glbl_pram->maxd2));
+ ugeth_info("ecamptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->ecamptr,
+ in_be32(&ugeth->p_rx_glbl_pram->ecamptr));
+ ugeth_info("l2qt : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l2qt,
+ in_be32(&ugeth->p_rx_glbl_pram->l2qt));
+ ugeth_info("l3qt[0] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[0],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[0]));
+ ugeth_info("l3qt[1] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[1],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[1]));
+ ugeth_info("l3qt[2] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[2],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[2]));
+ ugeth_info("l3qt[3] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[3],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[3]));
+ ugeth_info("l3qt[4] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[4],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[4]));
+ ugeth_info("l3qt[5] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[5],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[5]));
+ ugeth_info("l3qt[6] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[6],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[6]));
+ ugeth_info("l3qt[7] : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->l3qt[7],
+ in_be32(&ugeth->p_rx_glbl_pram->l3qt[7]));
+ ugeth_info("vlantype : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->vlantype,
+ in_be16(&ugeth->p_rx_glbl_pram->vlantype));
+ ugeth_info("vlantci : addr - 0x%08x, val - 0x%04x",
+ (u32) & ugeth->p_rx_glbl_pram->vlantci,
+ in_be16(&ugeth->p_rx_glbl_pram->vlantci));
+ for (i = 0; i < 64; i++)
+ ugeth_info
+ ("addressfiltering[%d]: addr - 0x%08x, val - 0x%02x",
+ i,
+ (u32) & ugeth->p_rx_glbl_pram->addressfiltering[i],
+ ugeth->p_rx_glbl_pram->addressfiltering[i]);
+ ugeth_info("exfGlobalParam : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_glbl_pram->exfGlobalParam,
+ in_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam));
+ }
+ if (ugeth->p_send_q_mem_reg) {
+ ugeth_info("Send Q memory registers:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_send_q_mem_reg);
+ for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
+ ugeth_info("SQQD[%d]:", i);
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_send_q_mem_reg->sqqd[i]);
+ mem_disp((u8 *) & ugeth->p_send_q_mem_reg->sqqd[i],
+ sizeof(ucc_geth_send_queue_qd_t));
+ }
+ }
+ if (ugeth->p_scheduler) {
+ ugeth_info("Scheduler:");
+ ugeth_info("Base address: 0x%08x", (u32) ugeth->p_scheduler);
+ mem_disp((u8 *) ugeth->p_scheduler,
+ sizeof(*ugeth->p_scheduler));
+ }
+ if (ugeth->p_tx_fw_statistics_pram) {
+ ugeth_info("TX FW statistics pram:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_tx_fw_statistics_pram);
+ mem_disp((u8 *) ugeth->p_tx_fw_statistics_pram,
+ sizeof(*ugeth->p_tx_fw_statistics_pram));
+ }
+ if (ugeth->p_rx_fw_statistics_pram) {
+ ugeth_info("RX FW statistics pram:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_rx_fw_statistics_pram);
+ mem_disp((u8 *) ugeth->p_rx_fw_statistics_pram,
+ sizeof(*ugeth->p_rx_fw_statistics_pram));
+ }
+ if (ugeth->p_rx_irq_coalescing_tbl) {
+ ugeth_info("RX IRQ coalescing tables:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_rx_irq_coalescing_tbl);
+ for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
+ ugeth_info("RX IRQ coalescing table entry[%d]:", i);
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i]);
+ ugeth_info
+ ("interruptcoalescingmaxvalue: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].interruptcoalescingmaxvalue,
+ in_be32(&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].
+ interruptcoalescingmaxvalue));
+ ugeth_info
+ ("interruptcoalescingcounter : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].interruptcoalescingcounter,
+ in_be32(&ugeth->p_rx_irq_coalescing_tbl->
+ coalescingentry[i].
+ interruptcoalescingcounter));
+ }
+ }
+ if (ugeth->p_rx_bd_qs_tbl) {
+ ugeth_info("RX BD QS tables:");
+ ugeth_info("Base address: 0x%08x", (u32) ugeth->p_rx_bd_qs_tbl);
+ for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
+ ugeth_info("RX BD QS table[%d]:", i);
+ ugeth_info("Base address: 0x%08x",
+ (u32) & ugeth->p_rx_bd_qs_tbl[i]);
+ ugeth_info
+ ("bdbaseptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_bd_qs_tbl[i].bdbaseptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdbaseptr));
+ ugeth_info
+ ("bdptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_bd_qs_tbl[i].bdptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].bdptr));
+ ugeth_info
+ ("externalbdbaseptr: addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].
+ externalbdbaseptr));
+ ugeth_info
+ ("externalbdptr : addr - 0x%08x, val - 0x%08x",
+ (u32) & ugeth->p_rx_bd_qs_tbl[i].externalbdptr,
+ in_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdptr));
+ ugeth_info("ucode RX Prefetched BDs:");
+ ugeth_info("Base address: 0x%08x",
+ (u32)
+ qe_muram_addr(in_be32
+ (&ugeth->p_rx_bd_qs_tbl[i].
+ bdbaseptr)));
+ mem_disp((u8 *)
+ qe_muram_addr(in_be32
+ (&ugeth->p_rx_bd_qs_tbl[i].
+ bdbaseptr)),
+ sizeof(ucc_geth_rx_prefetched_bds_t));
+ }
+ }
+ if (ugeth->p_init_enet_param_shadow) {
+ int size;
+ ugeth_info("Init enet param shadow:");
+ ugeth_info("Base address: 0x%08x",
+ (u32) ugeth->p_init_enet_param_shadow);
+ mem_disp((u8 *) ugeth->p_init_enet_param_shadow,
+ sizeof(*ugeth->p_init_enet_param_shadow));
+
+ size = sizeof(ucc_geth_thread_rx_pram_t);
+ if (ugeth->ug_info->rxExtendedFiltering) {
+ size +=
+ THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
+ if (ugeth->ug_info->largestexternallookupkeysize ==
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
+ size +=
+ THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8;
+ if (ugeth->ug_info->largestexternallookupkeysize ==
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES)
+ size +=
+ THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16;
+ }
+
+ dump_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+ txthread[0]),
+ ENET_INIT_PARAM_MAX_ENTRIES_TX,
+ sizeof(ucc_geth_thread_tx_pram_t),
+ ugeth->ug_info->riscTx, 0);
+ dump_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+ rxthread[0]),
+ ENET_INIT_PARAM_MAX_ENTRIES_RX, size,
+ ugeth->ug_info->riscRx, 1);
+ }
+}
+#endif /* DEBUG */
+
+static void init_default_reg_vals(volatile u32 *upsmr_register,
+ volatile u32 *maccfg1_register,
+ volatile u32 *maccfg2_register)
+{
+ out_be32(upsmr_register, UCC_GETH_UPSMR_INIT);
+ out_be32(maccfg1_register, UCC_GETH_MACCFG1_INIT);
+ out_be32(maccfg2_register, UCC_GETH_MACCFG2_INIT);
+}
+
+static int init_half_duplex_params(int alt_beb,
+ int back_pressure_no_backoff,
+ int no_backoff,
+ int excess_defer,
+ u8 alt_beb_truncation,
+ u8 max_retransmissions,
+ u8 collision_window,
+ volatile u32 *hafdup_register)
+{
+ u32 value = 0;
+
+ if ((alt_beb_truncation > HALFDUP_ALT_BEB_TRUNCATION_MAX) ||
+ (max_retransmissions > HALFDUP_MAX_RETRANSMISSION_MAX) ||
+ (collision_window > HALFDUP_COLLISION_WINDOW_MAX))
+ return -EINVAL;
+
+ value = (u32) (alt_beb_truncation << HALFDUP_ALT_BEB_TRUNCATION_SHIFT);
+
+ if (alt_beb)
+ value |= HALFDUP_ALT_BEB;
+ if (back_pressure_no_backoff)
+ value |= HALFDUP_BACK_PRESSURE_NO_BACKOFF;
+ if (no_backoff)
+ value |= HALFDUP_NO_BACKOFF;
+ if (excess_defer)
+ value |= HALFDUP_EXCESSIVE_DEFER;
+
+ value |= (max_retransmissions << HALFDUP_MAX_RETRANSMISSION_SHIFT);
+
+ value |= collision_window;
+
+ out_be32(hafdup_register, value);
+ return 0;
+}
+
+static int init_inter_frame_gap_params(u8 non_btb_cs_ipg,
+ u8 non_btb_ipg,
+ u8 min_ifg,
+ u8 btb_ipg,
+ volatile u32 *ipgifg_register)
+{
+ u32 value = 0;
+
+ /* Non-Back-to-back IPG part 1 should be <= Non-Back-to-back
+ IPG part 2 */
+ if (non_btb_cs_ipg > non_btb_ipg)
+ return -EINVAL;
+
+ if ((non_btb_cs_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX) ||
+ (non_btb_ipg > IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX) ||
+ /*(min_ifg > IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX) || */
+ (btb_ipg > IPGIFG_BACK_TO_BACK_IFG_MAX))
+ return -EINVAL;
+
+ value |=
+ ((non_btb_cs_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT) &
+ IPGIFG_NBTB_CS_IPG_MASK);
+ value |=
+ ((non_btb_ipg << IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT) &
+ IPGIFG_NBTB_IPG_MASK);
+ value |=
+ ((min_ifg << IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT) &
+ IPGIFG_MIN_IFG_MASK);
+ value |= (btb_ipg & IPGIFG_BTB_IPG_MASK);
+
+ out_be32(ipgifg_register, value);
+ return 0;
+}
+
+static int init_flow_control_params(u32 automatic_flow_control_mode,
+ int rx_flow_control_enable,
+ int tx_flow_control_enable,
+ u16 pause_period,
+ u16 extension_field,
+ volatile u32 *upsmr_register,
+ volatile u32 *uempr_register,
+ volatile u32 *maccfg1_register)
+{
+ u32 value = 0;
+
+ /* Set UEMPR register */
+ value = (u32) pause_period << UEMPR_PAUSE_TIME_VALUE_SHIFT;
+ value |= (u32) extension_field << UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT;
+ out_be32(uempr_register, value);
+
+ /* Set UPSMR register */
+ value = in_be32(upsmr_register);
+ value |= automatic_flow_control_mode;
+ out_be32(upsmr_register, value);
+
+ value = in_be32(maccfg1_register);
+ if (rx_flow_control_enable)
+ value |= MACCFG1_FLOW_RX;
+ if (tx_flow_control_enable)
+ value |= MACCFG1_FLOW_TX;
+ out_be32(maccfg1_register, value);
+
+ return 0;
+}
+
+static int init_hw_statistics_gathering_mode(int enable_hardware_statistics,
+ int auto_zero_hardware_statistics,
+ volatile u32 *upsmr_register,
+ volatile u16 *uescr_register)
+{
+ u32 upsmr_value = 0;
+ u16 uescr_value = 0;
+ /* Enable hardware statistics gathering if requested */
+ if (enable_hardware_statistics) {
+ upsmr_value = in_be32(upsmr_register);
+ upsmr_value |= UPSMR_HSE;
+ out_be32(upsmr_register, upsmr_value);
+ }
+
+ /* Clear hardware statistics counters */
+ uescr_value = in_be16(uescr_register);
+ uescr_value |= UESCR_CLRCNT;
+ /* Automatically zero hardware statistics counters on read,
+ if requested */
+ if (auto_zero_hardware_statistics)
+ uescr_value |= UESCR_AUTOZ;
+ out_be16(uescr_register, uescr_value);
+
+ return 0;
+}
+
+static int init_firmware_statistics_gathering_mode(int
+ enable_tx_firmware_statistics,
+ int enable_rx_firmware_statistics,
+ volatile u32 *tx_rmon_base_ptr,
+ u32 tx_firmware_statistics_structure_address,
+ volatile u32 *rx_rmon_base_ptr,
+ u32 rx_firmware_statistics_structure_address,
+ volatile u16 *temoder_register,
+ volatile u32 *remoder_register)
+{
+ /* Note: this function does not check if */
+ /* the parameters it receives are NULL */
+ u16 temoder_value;
+ u32 remoder_value;
+
+ if (enable_tx_firmware_statistics) {
+ out_be32(tx_rmon_base_ptr,
+ tx_firmware_statistics_structure_address);
+ temoder_value = in_be16(temoder_register);
+ temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE;
+ out_be16(temoder_register, temoder_value);
+ }
+
+ if (enable_rx_firmware_statistics) {
+ out_be32(rx_rmon_base_ptr,
+ rx_firmware_statistics_structure_address);
+ remoder_value = in_be32(remoder_register);
+ remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE;
+ out_be32(remoder_register, remoder_value);
+ }
+
+ return 0;
+}
+
+static int init_mac_station_addr_regs(u8 address_byte_0,
+ u8 address_byte_1,
+ u8 address_byte_2,
+ u8 address_byte_3,
+ u8 address_byte_4,
+ u8 address_byte_5,
+ volatile u32 *macstnaddr1_register,
+ volatile u32 *macstnaddr2_register)
+{
+ u32 value = 0;
+
+ /* Example: for a station address of 0x12345678ABCD, */
+ /* 0x12 is byte 0, 0x34 is byte 1 and so on and 0xCD is byte 5 */
+
+ /* MACSTNADDR1 Register: */
+
+ /* 0 7 8 15 */
+ /* station address byte 5 station address byte 4 */
+ /* 16 23 24 31 */
+ /* station address byte 3 station address byte 2 */
+ value |= (u32) ((address_byte_2 << 0) & 0x000000FF);
+ value |= (u32) ((address_byte_3 << 8) & 0x0000FF00);
+ value |= (u32) ((address_byte_4 << 16) & 0x00FF0000);
+ value |= (u32) ((address_byte_5 << 24) & 0xFF000000);
+
+ out_be32(macstnaddr1_register, value);
+
+ /* MACSTNADDR2 Register: */
+
+ /* 0 7 8 15 */
+ /* station address byte 1 station address byte 0 */
+ /* 16 23 24 31 */
+ /* reserved reserved */
+ value = 0;
+ value |= (u32) ((address_byte_0 << 16) & 0x00FF0000);
+ value |= (u32) ((address_byte_1 << 24) & 0xFF000000);
+
+ out_be32(macstnaddr2_register, value);
+
+ return 0;
+}
+
+static int init_mac_duplex_mode(int full_duplex,
+ int limited_to_full_duplex,
+ volatile u32 *maccfg2_register)
+{
+ u32 value = 0;
+
+ /* some interfaces must work in full duplex mode */
+ if ((full_duplex == 0) && (limited_to_full_duplex == 1))
+ return -EINVAL;
+
+ value = in_be32(maccfg2_register);
+
+ if (full_duplex)
+ value |= MACCFG2_FDX;
+ else
+ value &= ~MACCFG2_FDX;
+
+ out_be32(maccfg2_register, value);
+ return 0;
+}
+
+static int init_check_frame_length_mode(int length_check,
+ volatile u32 *maccfg2_register)
+{
+ u32 value = 0;
+
+ value = in_be32(maccfg2_register);
+
+ if (length_check)
+ value |= MACCFG2_LC;
+ else
+ value &= ~MACCFG2_LC;
+
+ out_be32(maccfg2_register, value);
+ return 0;
+}
+
+static int init_preamble_length(u8 preamble_length,
+ volatile u32 *maccfg2_register)
+{
+ u32 value = 0;
+
+ if ((preamble_length < 3) || (preamble_length > 7))
+ return -EINVAL;
+
+ value = in_be32(maccfg2_register);
+ value &= ~MACCFG2_PREL_MASK;
+ value |= (preamble_length << MACCFG2_PREL_SHIFT);
+ out_be32(maccfg2_register, value);
+ return 0;
+}
+
+static int init_mii_management_configuration(int reset_mgmt,
+ int preamble_supress,
+ volatile u32 *miimcfg_register,
+ volatile u32 *miimind_register)
+{
+ unsigned int timeout = PHY_INIT_TIMEOUT;
+ u32 value = 0;
+
+ value = in_be32(miimcfg_register);
+ if (reset_mgmt) {
+ value |= MIIMCFG_RESET_MANAGEMENT;
+ out_be32(miimcfg_register, value);
+ }
+
+ value = 0;
+
+ if (preamble_supress)
+ value |= MIIMCFG_NO_PREAMBLE;
+
+ value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT;
+ out_be32(miimcfg_register, value);
+
+ /* Wait until the bus is free */
+ while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--)
+ cpu_relax();
+
+ if (timeout <= 0) {
+ ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int init_rx_parameters(int reject_broadcast,
+ int receive_short_frames,
+ int promiscuous, volatile u32 *upsmr_register)
+{
+ u32 value = 0;
+
+ value = in_be32(upsmr_register);
+
+ if (reject_broadcast)
+ value |= UPSMR_BRO;
+ else
+ value &= ~UPSMR_BRO;
+
+ if (receive_short_frames)
+ value |= UPSMR_RSH;
+ else
+ value &= ~UPSMR_RSH;
+
+ if (promiscuous)
+ value |= UPSMR_PRO;
+ else
+ value &= ~UPSMR_PRO;
+
+ out_be32(upsmr_register, value);
+
+ return 0;
+}
+
+static int init_max_rx_buff_len(u16 max_rx_buf_len,
+ volatile u16 *mrblr_register)
+{
+ /* max_rx_buf_len value must be a multiple of 128 */
+ if ((max_rx_buf_len == 0)
+ || (max_rx_buf_len % UCC_GETH_MRBLR_ALIGNMENT))
+ return -EINVAL;
+
+ out_be16(mrblr_register, max_rx_buf_len);
+ return 0;
+}
+
+static int init_min_frame_len(u16 min_frame_length,
+ volatile u16 *minflr_register,
+ volatile u16 *mrblr_register)
+{
+ u16 mrblr_value = 0;
+
+ mrblr_value = in_be16(mrblr_register);
+ if (min_frame_length >= (mrblr_value - 4))
+ return -EINVAL;
+
+ out_be16(minflr_register, min_frame_length);
+ return 0;
+}
+
+static int adjust_enet_interface(ucc_geth_private_t *ugeth)
+{
+ ucc_geth_info_t *ug_info;
+ ucc_geth_t *ug_regs;
+ ucc_fast_t *uf_regs;
+ enet_speed_e speed;
+ int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm =
+ 0, limited_to_full_duplex = 0;
+ u32 upsmr, maccfg2, utbipar, tbiBaseAddress;
+ u16 value;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ ug_info = ugeth->ug_info;
+ ug_regs = ugeth->ug_regs;
+ uf_regs = ugeth->uccf->uf_regs;
+
+ /* Analyze enet_interface according to Interface Mode Configuration
+ table */
+ ret_val =
+ get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm,
+ &rpm, &tbi, &limited_to_full_duplex);
+ if (ret_val != 0) {
+ ugeth_err
+ ("%s: half duplex not supported in requested configuration.",
+ __FUNCTION__);
+ return ret_val;
+ }
+
+ /* Set MACCFG2 */
+ maccfg2 = in_be32(&ug_regs->maccfg2);
+ maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
+ if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT))
+ maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
+ else if (speed == ENET_SPEED_1000BT)
+ maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
+ maccfg2 |= ug_info->padAndCrc;
+ out_be32(&ug_regs->maccfg2, maccfg2);
+
+ /* Set UPSMR */
+ upsmr = in_be32(&uf_regs->upsmr);
+ upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM);
+ if (rpm)
+ upsmr |= UPSMR_RPM;
+ if (r10m)
+ upsmr |= UPSMR_R10M;
+ if (tbi)
+ upsmr |= UPSMR_TBIM;
+ if (rmm)
+ upsmr |= UPSMR_RMM;
+ out_be32(&uf_regs->upsmr, upsmr);
+
+ /* Set UTBIPAR */
+ utbipar = in_be32(&ug_regs->utbipar);
+ utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK;
+ if (tbi)
+ utbipar |=
+ (ug_info->phy_address +
+ ugeth->ug_info->uf_info.
+ ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
+ else
+ utbipar |=
+ (0x10 +
+ ugeth->ug_info->uf_info.
+ ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT;
+ out_be32(&ug_regs->utbipar, utbipar);
+
+ /* Disable autonegotiation in tbi mode, because by default it
+ comes up in autonegotiation mode. */
+ /* Note that this depends on proper setting in utbipar register. */
+ if (tbi) {
+ tbiBaseAddress = in_be32(&ug_regs->utbipar);
+ tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK;
+ tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT;
+ value =
+ ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress,
+ ENET_TBI_MII_CR);
+ value &= ~0x1000; /* Turn off autonegotiation */
+ ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress,
+ ENET_TBI_MII_CR, value);
+ }
+
+ ret_val = init_mac_duplex_mode(1,
+ limited_to_full_duplex,
+ &ug_regs->maccfg2);
+ if (ret_val != 0) {
+ ugeth_err
+ ("%s: half duplex not supported in requested configuration.",
+ __FUNCTION__);
+ return ret_val;
+ }
+
+ init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2);
+
+ ret_val = init_preamble_length(ug_info->prel, &ug_regs->maccfg2);
+ if (ret_val != 0) {
+ ugeth_err
+ ("%s: Preamble length must be between 3 and 7 inclusive.",
+ __FUNCTION__);
+ return ret_val;
+ }
+
+ return 0;
+}
+
+/* Called every time the controller might need to be made
+ * aware of new link state. The PHY code conveys this
+ * information through variables in the ugeth structure, and this
+ * function converts those variables into the appropriate
+ * register values, and can bring down the device if needed.
+ */
+static void adjust_link(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ ucc_geth_t *ug_regs;
+ u32 tempval;
+ struct ugeth_mii_info *mii_info = ugeth->mii_info;
+
+ ug_regs = ugeth->ug_regs;
+
+ if (mii_info->link) {
+ /* Now we make sure that we can be in full duplex mode.
+ * If not, we operate in half-duplex mode. */
+ if (mii_info->duplex != ugeth->oldduplex) {
+ if (!(mii_info->duplex)) {
+ tempval = in_be32(&ug_regs->maccfg2);
+ tempval &= ~(MACCFG2_FDX);
+ out_be32(&ug_regs->maccfg2, tempval);
+
+ ugeth_info("%s: Half Duplex", dev->name);
+ } else {
+ tempval = in_be32(&ug_regs->maccfg2);
+ tempval |= MACCFG2_FDX;
+ out_be32(&ug_regs->maccfg2, tempval);
+
+ ugeth_info("%s: Full Duplex", dev->name);
+ }
+
+ ugeth->oldduplex = mii_info->duplex;
+ }
+
+ if (mii_info->speed != ugeth->oldspeed) {
+ switch (mii_info->speed) {
+ case 1000:
+#ifdef CONFIG_MPC836x
+/* FIXME: This code is for 100Mbs BUG fixing,
+remove this when it is fixed!!! */
+ if (ugeth->ug_info->enet_interface ==
+ ENET_1000_GMII)
+ /* Run the commands which initialize the PHY */
+ {
+ tempval =
+ (u32) mii_info->mdio_read(ugeth->
+ dev, mii_info->mii_id, 0x1b);
+ tempval |= 0x000f;
+ mii_info->mdio_write(ugeth->dev,
+ mii_info->mii_id, 0x1b,
+ (u16) tempval);
+ tempval =
+ (u32) mii_info->mdio_read(ugeth->
+ dev, mii_info->mii_id,
+ MII_BMCR);
+ mii_info->mdio_write(ugeth->dev,
+ mii_info->mii_id, MII_BMCR,
+ (u16) (tempval | BMCR_RESET));
+ } else if (ugeth->ug_info->enet_interface ==
+ ENET_1000_RGMII)
+ /* Run the commands which initialize the PHY */
+ {
+ tempval =
+ (u32) mii_info->mdio_read(ugeth->
+ dev, mii_info->mii_id, 0x1b);
+ tempval = (tempval & ~0x000f) | 0x000b;
+ mii_info->mdio_write(ugeth->dev,
+ mii_info->mii_id, 0x1b,
+ (u16) tempval);
+ tempval =
+ (u32) mii_info->mdio_read(ugeth->
+ dev, mii_info->mii_id,
+ MII_BMCR);
+ mii_info->mdio_write(ugeth->dev,
+ mii_info->mii_id, MII_BMCR,
+ (u16) (tempval | BMCR_RESET));
+ }
+ msleep(4000);
+#endif /* CONFIG_MPC8360 */
+ adjust_enet_interface(ugeth);
+ break;
+ case 100:
+ case 10:
+#ifdef CONFIG_MPC836x
+/* FIXME: This code is for 100Mbs BUG fixing,
+remove this lines when it will be fixed!!! */
+ ugeth->ug_info->enet_interface = ENET_100_RGMII;
+ tempval =
+ (u32) mii_info->mdio_read(ugeth->dev,
+ mii_info->mii_id,
+ 0x1b);
+ tempval = (tempval & ~0x000f) | 0x000b;
+ mii_info->mdio_write(ugeth->dev,
+ mii_info->mii_id, 0x1b,
+ (u16) tempval);
+ tempval =
+ (u32) mii_info->mdio_read(ugeth->dev,
+ mii_info->mii_id,
+ MII_BMCR);
+ mii_info->mdio_write(ugeth->dev,
+ mii_info->mii_id, MII_BMCR,
+ (u16) (tempval |
+ BMCR_RESET));
+ msleep(4000);
+#endif /* CONFIG_MPC8360 */
+ adjust_enet_interface(ugeth);
+ break;
+ default:
+ ugeth_warn
+ ("%s: Ack! Speed (%d) is not 10/100/1000!",
+ dev->name, mii_info->speed);
+ break;
+ }
+
+ ugeth_info("%s: Speed %dBT", dev->name,
+ mii_info->speed);
+
+ ugeth->oldspeed = mii_info->speed;
+ }
+
+ if (!ugeth->oldlink) {
+ ugeth_info("%s: Link is up", dev->name);
+ ugeth->oldlink = 1;
+ netif_carrier_on(dev);
+ netif_schedule(dev);
+ }
+ } else {
+ if (ugeth->oldlink) {
+ ugeth_info("%s: Link is down", dev->name);
+ ugeth->oldlink = 0;
+ ugeth->oldspeed = 0;
+ ugeth->oldduplex = -1;
+ netif_carrier_off(dev);
+ }
+ }
+}
+
+/* Configure the PHY for dev.
+ * returns 0 if success. -1 if failure
+ */
+static int init_phy(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ struct phy_info *curphy;
+ ucc_mii_mng_t *mii_regs;
+ struct ugeth_mii_info *mii_info;
+ int err;
+
+ mii_regs = &ugeth->ug_regs->miimng;
+
+ ugeth->oldlink = 0;
+ ugeth->oldspeed = 0;
+ ugeth->oldduplex = -1;
+
+ mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL);
+
+ if (NULL == mii_info) {
+ ugeth_err("%s: Could not allocate mii_info", dev->name);
+ return -ENOMEM;
+ }
+
+ mii_info->mii_regs = mii_regs;
+ mii_info->speed = SPEED_1000;
+ mii_info->duplex = DUPLEX_FULL;
+ mii_info->pause = 0;
+ mii_info->link = 0;
+
+ mii_info->advertising = (ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ mii_info->autoneg = 1;
+
+ mii_info->mii_id = ugeth->ug_info->phy_address;
+
+ mii_info->dev = dev;
+
+ mii_info->mdio_read = &read_phy_reg;
+ mii_info->mdio_write = &write_phy_reg;
+
+ ugeth->mii_info = mii_info;
+
+ spin_lock_irq(&ugeth->lock);
+
+ /* Set this UCC to be the master of the MII managment */
+ ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
+
+ if (init_mii_management_configuration(1,
+ ugeth->ug_info->
+ miiPreambleSupress,
+ &mii_regs->miimcfg,
+ &mii_regs->miimind)) {
+ ugeth_err("%s: The MII Bus is stuck!", dev->name);
+ err = -1;
+ goto bus_fail;
+ }
+
+ spin_unlock_irq(&ugeth->lock);
+
+ /* get info for this PHY */
+ curphy = get_phy_info(ugeth->mii_info);
+
+ if (curphy == NULL) {
+ ugeth_err("%s: No PHY found", dev->name);
+ err = -1;
+ goto no_phy;
+ }
+
+ mii_info->phyinfo = curphy;
+
+ /* Run the commands which initialize the PHY */
+ if (curphy->init) {
+ err = curphy->init(ugeth->mii_info);
+ if (err)
+ goto phy_init_fail;
+ }
+
+ return 0;
+
+ phy_init_fail:
+ no_phy:
+ bus_fail:
+ kfree(mii_info);
+
+ return err;
+}
+
+#ifdef CONFIG_UGETH_TX_ON_DEMOND
+static int ugeth_transmit_on_demand(ucc_geth_private_t *ugeth)
+{
+ ucc_fast_transmit_on_demand(ugeth->uccf);
+
+ return 0;
+}
+#endif
+
+static int ugeth_graceful_stop_tx(ucc_geth_private_t *ugeth)
+{
+ ucc_fast_private_t *uccf;
+ u32 cecr_subblock;
+ u32 temp;
+
+ uccf = ugeth->uccf;
+
+ /* Mask GRACEFUL STOP TX interrupt bit and clear it */
+ temp = in_be32(uccf->p_uccm);
+ temp &= ~UCCE_GRA;
+ out_be32(uccf->p_uccm, temp);
+ out_be32(uccf->p_ucce, UCCE_GRA); /* clear by writing 1 */
+
+ /* Issue host command */
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_ETHERNET, 0);
+
+ /* Wait for command to complete */
+ do {
+ temp = in_be32(uccf->p_ucce);
+ } while (!(temp & UCCE_GRA));
+
+ uccf->stopped_tx = 1;
+
+ return 0;
+}
+
+static int ugeth_graceful_stop_rx(ucc_geth_private_t * ugeth)
+{
+ ucc_fast_private_t *uccf;
+ u32 cecr_subblock;
+ u8 temp;
+
+ uccf = ugeth->uccf;
+
+ /* Clear acknowledge bit */
+ temp = ugeth->p_rx_glbl_pram->rxgstpack;
+ temp &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX;
+ ugeth->p_rx_glbl_pram->rxgstpack = temp;
+
+ /* Keep issuing command and checking acknowledge bit until
+ it is asserted, according to spec */
+ do {
+ /* Issue host command */
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.
+ ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock,
+ (u8) QE_CR_PROTOCOL_ETHERNET, 0);
+
+ temp = ugeth->p_rx_glbl_pram->rxgstpack;
+ } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX));
+
+ uccf->stopped_rx = 1;
+
+ return 0;
+}
+
+static int ugeth_restart_tx(ucc_geth_private_t *ugeth)
+{
+ ucc_fast_private_t *uccf;
+ u32 cecr_subblock;
+
+ uccf = ugeth->uccf;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+ qe_issue_cmd(QE_RESTART_TX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
+ 0);
+ uccf->stopped_tx = 0;
+
+ return 0;
+}
+
+static int ugeth_restart_rx(ucc_geth_private_t *ugeth)
+{
+ ucc_fast_private_t *uccf;
+ u32 cecr_subblock;
+
+ uccf = ugeth->uccf;
+
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+ qe_issue_cmd(QE_RESTART_RX, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
+ 0);
+ uccf->stopped_rx = 0;
+
+ return 0;
+}
+
+static int ugeth_enable(ucc_geth_private_t *ugeth, comm_dir_e mode)
+{
+ ucc_fast_private_t *uccf;
+ int enabled_tx, enabled_rx;
+
+ uccf = ugeth->uccf;
+
+ /* check if the UCC number is in range. */
+ if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
+ ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ enabled_tx = uccf->enabled_tx;
+ enabled_rx = uccf->enabled_rx;
+
+ /* Get Tx and Rx going again, in case this channel was actively
+ disabled. */
+ if ((mode & COMM_DIR_TX) && (!enabled_tx) && uccf->stopped_tx)
+ ugeth_restart_tx(ugeth);
+ if ((mode & COMM_DIR_RX) && (!enabled_rx) && uccf->stopped_rx)
+ ugeth_restart_rx(ugeth);
+
+ ucc_fast_enable(uccf, mode); /* OK to do even if not disabled */
+
+ return 0;
+
+}
+
+static int ugeth_disable(ucc_geth_private_t * ugeth, comm_dir_e mode)
+{
+ ucc_fast_private_t *uccf;
+
+ uccf = ugeth->uccf;
+
+ /* check if the UCC number is in range. */
+ if (ugeth->ug_info->uf_info.ucc_num >= UCC_MAX_NUM) {
+ ugeth_err("%s: ucc_num out of range.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* Stop any transmissions */
+ if ((mode & COMM_DIR_TX) && uccf->enabled_tx && !uccf->stopped_tx)
+ ugeth_graceful_stop_tx(ugeth);
+
+ /* Stop any receptions */
+ if ((mode & COMM_DIR_RX) && uccf->enabled_rx && !uccf->stopped_rx)
+ ugeth_graceful_stop_rx(ugeth);
+
+ ucc_fast_disable(ugeth->uccf, mode); /* OK to do even if not enabled */
+
+ return 0;
+}
+
+static void ugeth_dump_regs(ucc_geth_private_t *ugeth)
+{
+#ifdef DEBUG
+ ucc_fast_dump_regs(ugeth->uccf);
+ dump_regs(ugeth);
+ dump_bds(ugeth);
+#endif
+}
+
+#ifdef CONFIG_UGETH_FILTERING
+static int ugeth_ext_filtering_serialize_tad(ucc_geth_tad_params_t *
+ p_UccGethTadParams,
+ qe_fltr_tad_t *qe_fltr_tad)
+{
+ u16 temp;
+
+ /* Zero serialized TAD */
+ memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE);
+
+ qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V; /* Must have this */
+ if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode ||
+ (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
+ || (p_UccGethTadParams->vnontag_op !=
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP)
+ )
+ qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF;
+ if (p_UccGethTadParams->reject_frame)
+ qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ;
+ temp =
+ (u16) (((u16) p_UccGethTadParams->
+ vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT);
+ qe_fltr_tad->serialized[0] |= (u8) (temp >> 8); /* upper bits */
+
+ qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff); /* lower bits */
+ if (p_UccGethTadParams->vnontag_op ==
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT)
+ qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP;
+ qe_fltr_tad->serialized[1] |=
+ p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT;
+
+ qe_fltr_tad->serialized[2] |=
+ p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT;
+ /* upper bits */
+ qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8);
+ /* lower bits */
+ qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff);
+
+ return 0;
+}
+
+static enet_addr_container_t
+ *ugeth_82xx_filtering_get_match_addr_in_hash(ucc_geth_private_t *ugeth,
+ enet_addr_t *p_enet_addr)
+{
+ enet_addr_container_t *enet_addr_cont;
+ struct list_head *p_lh;
+ u16 i, num;
+ int32_t j;
+ u8 *p_counter;
+
+ if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
+ p_lh = &ugeth->group_hash_q;
+ p_counter = &(ugeth->numGroupAddrInHash);
+ } else {
+ p_lh = &ugeth->ind_hash_q;
+ p_counter = &(ugeth->numIndAddrInHash);
+ }
+
+ if (!p_lh)
+ return NULL;
+
+ num = *p_counter;
+
+ for (i = 0; i < num; i++) {
+ enet_addr_cont =
+ (enet_addr_container_t *)
+ ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
+ for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) {
+ if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j])
+ break;
+ if (j == 0)
+ return enet_addr_cont; /* Found */
+ }
+ enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
+ }
+ return NULL;
+}
+
+static int ugeth_82xx_filtering_add_addr_in_hash(ucc_geth_private_t *ugeth,
+ enet_addr_t *p_enet_addr)
+{
+ ucc_geth_enet_address_recognition_location_e location;
+ enet_addr_container_t *enet_addr_cont;
+ struct list_head *p_lh;
+ u8 i;
+ u32 limit;
+ u8 *p_counter;
+
+ if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
+ p_lh = &ugeth->group_hash_q;
+ limit = ugeth->ug_info->maxGroupAddrInHash;
+ location =
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH;
+ p_counter = &(ugeth->numGroupAddrInHash);
+ } else {
+ p_lh = &ugeth->ind_hash_q;
+ limit = ugeth->ug_info->maxIndAddrInHash;
+ location =
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH;
+ p_counter = &(ugeth->numIndAddrInHash);
+ }
+
+ if ((enet_addr_cont =
+ ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) {
+ list_add(p_lh, &enet_addr_cont->node); /* Put it back */
+ return 0;
+ }
+ if ((!p_lh) || (!(*p_counter < limit)))
+ return -EBUSY;
+ if (!(enet_addr_cont = get_enet_addr_container()))
+ return -ENOMEM;
+ for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
+ (enet_addr_cont->address)[i] = (*p_enet_addr)[i];
+ enet_addr_cont->location = location;
+ enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
+ ++(*p_counter);
+
+ hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address));
+
+ return 0;
+}
+
+static int ugeth_82xx_filtering_clear_addr_in_hash(ucc_geth_private_t *ugeth,
+ enet_addr_t *p_enet_addr)
+{
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+ enet_addr_container_t *enet_addr_cont;
+ ucc_fast_private_t *uccf;
+ comm_dir_e comm_dir;
+ u16 i, num;
+ struct list_head *p_lh;
+ u32 *addr_h, *addr_l;
+ u8 *p_counter;
+
+ uccf = ugeth->uccf;
+
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ if (!
+ (enet_addr_cont =
+ ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr)))
+ return -ENOENT;
+
+ /* It's been found and removed from the CQ. */
+ /* Now destroy its container */
+ put_enet_addr_container(enet_addr_cont);
+
+ if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) {
+ addr_h = &(p_82xx_addr_filt->gaddr_h);
+ addr_l = &(p_82xx_addr_filt->gaddr_l);
+ p_lh = &ugeth->group_hash_q;
+ p_counter = &(ugeth->numGroupAddrInHash);
+ } else {
+ addr_h = &(p_82xx_addr_filt->iaddr_h);
+ addr_l = &(p_82xx_addr_filt->iaddr_l);
+ p_lh = &ugeth->ind_hash_q;
+ p_counter = &(ugeth->numIndAddrInHash);
+ }
+
+ comm_dir = 0;
+ if (uccf->enabled_tx)
+ comm_dir |= COMM_DIR_TX;
+ if (uccf->enabled_rx)
+ comm_dir |= COMM_DIR_RX;
+ if (comm_dir)
+ ugeth_disable(ugeth, comm_dir);
+
+ /* Clear the hash table. */
+ out_be32(addr_h, 0x00000000);
+ out_be32(addr_l, 0x00000000);
+
+ /* Add all remaining CQ elements back into hash */
+ num = --(*p_counter);
+ for (i = 0; i < num; i++) {
+ enet_addr_cont =
+ (enet_addr_container_t *)
+ ENET_ADDR_CONT_ENTRY(dequeue(p_lh));
+ hw_add_addr_in_hash(ugeth, &(enet_addr_cont->address));
+ enqueue(p_lh, &enet_addr_cont->node); /* Put it back */
+ }
+
+ if (comm_dir)
+ ugeth_enable(ugeth, comm_dir);
+
+ return 0;
+}
+#endif /* CONFIG_UGETH_FILTERING */
+
+static int ugeth_82xx_filtering_clear_all_addr_in_hash(ucc_geth_private_t *
+ ugeth,
+ enet_addr_type_e
+ enet_addr_type)
+{
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+ ucc_fast_private_t *uccf;
+ comm_dir_e comm_dir;
+ struct list_head *p_lh;
+ u16 i, num;
+ u32 *addr_h, *addr_l;
+ u8 *p_counter;
+
+ uccf = ugeth->uccf;
+
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->p_rx_glbl_pram->
+ addressfiltering;
+
+ if (enet_addr_type == ENET_ADDR_TYPE_GROUP) {
+ addr_h = &(p_82xx_addr_filt->gaddr_h);
+ addr_l = &(p_82xx_addr_filt->gaddr_l);
+ p_lh = &ugeth->group_hash_q;
+ p_counter = &(ugeth->numGroupAddrInHash);
+ } else if (enet_addr_type == ENET_ADDR_TYPE_INDIVIDUAL) {
+ addr_h = &(p_82xx_addr_filt->iaddr_h);
+ addr_l = &(p_82xx_addr_filt->iaddr_l);
+ p_lh = &ugeth->ind_hash_q;
+ p_counter = &(ugeth->numIndAddrInHash);
+ } else
+ return -EINVAL;
+
+ comm_dir = 0;
+ if (uccf->enabled_tx)
+ comm_dir |= COMM_DIR_TX;
+ if (uccf->enabled_rx)
+ comm_dir |= COMM_DIR_RX;
+ if (comm_dir)
+ ugeth_disable(ugeth, comm_dir);
+
+ /* Clear the hash table. */
+ out_be32(addr_h, 0x00000000);
+ out_be32(addr_l, 0x00000000);
+
+ if (!p_lh)
+ return 0;
+
+ num = *p_counter;
+
+ /* Delete all remaining CQ elements */
+ for (i = 0; i < num; i++)
+ put_enet_addr_container(ENET_ADDR_CONT_ENTRY(dequeue(p_lh)));
+
+ *p_counter = 0;
+
+ if (comm_dir)
+ ugeth_enable(ugeth, comm_dir);
+
+ return 0;
+}
+
+#ifdef CONFIG_UGETH_FILTERING
+static int ugeth_82xx_filtering_add_addr_in_paddr(ucc_geth_private_t *ugeth,
+ enet_addr_t *p_enet_addr,
+ u8 paddr_num)
+{
+ int i;
+
+ if ((*p_enet_addr)[0] & ENET_GROUP_ADDR)
+ ugeth_warn
+ ("%s: multicast address added to paddr will have no "
+ "effect - is this what you wanted?",
+ __FUNCTION__);
+
+ ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */
+ /* store address in our database */
+ for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++)
+ ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i];
+ /* put in hardware */
+ return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num);
+}
+#endif /* CONFIG_UGETH_FILTERING */
+
+static int ugeth_82xx_filtering_clear_addr_in_paddr(ucc_geth_private_t *ugeth,
+ u8 paddr_num)
+{
+ ugeth->indAddrRegUsed[paddr_num] = 0; /* mark this paddr as not used */
+ return hw_clear_addr_in_paddr(ugeth, paddr_num);/* clear in hardware */
+}
+
+static void ucc_geth_memclean(ucc_geth_private_t *ugeth)
+{
+ u16 i, j;
+ u8 *bd;
+
+ if (!ugeth)
+ return;
+
+ if (ugeth->uccf)
+ ucc_fast_free(ugeth->uccf);
+
+ if (ugeth->p_thread_data_tx) {
+ qe_muram_free(ugeth->thread_dat_tx_offset);
+ ugeth->p_thread_data_tx = NULL;
+ }
+ if (ugeth->p_thread_data_rx) {
+ qe_muram_free(ugeth->thread_dat_rx_offset);
+ ugeth->p_thread_data_rx = NULL;
+ }
+ if (ugeth->p_exf_glbl_param) {
+ qe_muram_free(ugeth->exf_glbl_param_offset);
+ ugeth->p_exf_glbl_param = NULL;
+ }
+ if (ugeth->p_rx_glbl_pram) {
+ qe_muram_free(ugeth->rx_glbl_pram_offset);
+ ugeth->p_rx_glbl_pram = NULL;
+ }
+ if (ugeth->p_tx_glbl_pram) {
+ qe_muram_free(ugeth->tx_glbl_pram_offset);
+ ugeth->p_tx_glbl_pram = NULL;
+ }
+ if (ugeth->p_send_q_mem_reg) {
+ qe_muram_free(ugeth->send_q_mem_reg_offset);
+ ugeth->p_send_q_mem_reg = NULL;
+ }
+ if (ugeth->p_scheduler) {
+ qe_muram_free(ugeth->scheduler_offset);
+ ugeth->p_scheduler = NULL;
+ }
+ if (ugeth->p_tx_fw_statistics_pram) {
+ qe_muram_free(ugeth->tx_fw_statistics_pram_offset);
+ ugeth->p_tx_fw_statistics_pram = NULL;
+ }
+ if (ugeth->p_rx_fw_statistics_pram) {
+ qe_muram_free(ugeth->rx_fw_statistics_pram_offset);
+ ugeth->p_rx_fw_statistics_pram = NULL;
+ }
+ if (ugeth->p_rx_irq_coalescing_tbl) {
+ qe_muram_free(ugeth->rx_irq_coalescing_tbl_offset);
+ ugeth->p_rx_irq_coalescing_tbl = NULL;
+ }
+ if (ugeth->p_rx_bd_qs_tbl) {
+ qe_muram_free(ugeth->rx_bd_qs_tbl_offset);
+ ugeth->p_rx_bd_qs_tbl = NULL;
+ }
+ if (ugeth->p_init_enet_param_shadow) {
+ return_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+ rxthread[0]),
+ ENET_INIT_PARAM_MAX_ENTRIES_RX,
+ ugeth->ug_info->riscRx, 1);
+ return_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+ txthread[0]),
+ ENET_INIT_PARAM_MAX_ENTRIES_TX,
+ ugeth->ug_info->riscTx, 0);
+ kfree(ugeth->p_init_enet_param_shadow);
+ ugeth->p_init_enet_param_shadow = NULL;
+ }
+ for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) {
+ bd = ugeth->p_tx_bd_ring[i];
+ for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) {
+ if (ugeth->tx_skbuff[i][j]) {
+ dma_unmap_single(NULL,
+ BD_BUFFER_ARG(bd),
+ (BD_STATUS_AND_LENGTH(bd) &
+ BD_LENGTH_MASK),
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(ugeth->tx_skbuff[i][j]);
+ ugeth->tx_skbuff[i][j] = NULL;
+ }
+ }
+
+ kfree(ugeth->tx_skbuff[i]);
+
+ if (ugeth->p_tx_bd_ring[i]) {
+ if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_SYSTEM)
+ kfree((void *)ugeth->tx_bd_ring_offset[i]);
+ else if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_MURAM)
+ qe_muram_free(ugeth->tx_bd_ring_offset[i]);
+ ugeth->p_tx_bd_ring[i] = NULL;
+ }
+ }
+ for (i = 0; i < ugeth->ug_info->numQueuesRx; i++) {
+ if (ugeth->p_rx_bd_ring[i]) {
+ /* Return existing data buffers in ring */
+ bd = ugeth->p_rx_bd_ring[i];
+ for (j = 0; j < ugeth->ug_info->bdRingLenRx[i]; j++) {
+ if (ugeth->rx_skbuff[i][j]) {
+ dma_unmap_single(NULL, BD_BUFFER(bd),
+ ugeth->ug_info->
+ uf_info.
+ max_rx_buf_length +
+ UCC_GETH_RX_DATA_BUF_ALIGNMENT,
+ DMA_FROM_DEVICE);
+
+ dev_kfree_skb_any(ugeth->
+ rx_skbuff[i][j]);
+ ugeth->rx_skbuff[i][j] = NULL;
+ }
+ bd += UCC_GETH_SIZE_OF_BD;
+ }
+
+ kfree(ugeth->rx_skbuff[i]);
+
+ if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_SYSTEM)
+ kfree((void *)ugeth->rx_bd_ring_offset[i]);
+ else if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_MURAM)
+ qe_muram_free(ugeth->rx_bd_ring_offset[i]);
+ ugeth->p_rx_bd_ring[i] = NULL;
+ }
+ }
+ while (!list_empty(&ugeth->group_hash_q))
+ put_enet_addr_container(ENET_ADDR_CONT_ENTRY
+ (dequeue(&ugeth->group_hash_q)));
+ while (!list_empty(&ugeth->ind_hash_q))
+ put_enet_addr_container(ENET_ADDR_CONT_ENTRY
+ (dequeue(&ugeth->ind_hash_q)));
+
+}
+
+static void ucc_geth_set_multi(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth;
+ struct dev_mc_list *dmi;
+ ucc_fast_t *uf_regs;
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+ enet_addr_t tempaddr;
+ u8 *mcptr, *tdptr;
+ int i, j;
+
+ ugeth = netdev_priv(dev);
+
+ uf_regs = ugeth->uccf->uf_regs;
+
+ if (dev->flags & IFF_PROMISC) {
+
+ uf_regs->upsmr |= UPSMR_PRO;
+
+ } else {
+
+ uf_regs->upsmr &= ~UPSMR_PRO;
+
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->
+ p_rx_glbl_pram->addressfiltering;
+
+ if (dev->flags & IFF_ALLMULTI) {
+ /* Catch all multicast addresses, so set the
+ * filter to all 1's.
+ */
+ out_be32(&p_82xx_addr_filt->gaddr_h, 0xffffffff);
+ out_be32(&p_82xx_addr_filt->gaddr_l, 0xffffffff);
+ } else {
+ /* Clear filter and add the addresses in the list.
+ */
+ out_be32(&p_82xx_addr_filt->gaddr_h, 0x0);
+ out_be32(&p_82xx_addr_filt->gaddr_l, 0x0);
+
+ dmi = dev->mc_list;
+
+ for (i = 0; i < dev->mc_count; i++, dmi = dmi->next) {
+
+ /* Only support group multicast for now.
+ */
+ if (!(dmi->dmi_addr[0] & 1))
+ continue;
+
+ /* The address in dmi_addr is LSB first,
+ * and taddr is MSB first. We have to
+ * copy bytes MSB first from dmi_addr.
+ */
+ mcptr = (u8 *) dmi->dmi_addr + 5;
+ tdptr = (u8 *) & tempaddr;
+ for (j = 0; j < 6; j++)
+ *tdptr++ = *mcptr--;
+
+ /* Ask CPM to run CRC and set bit in
+ * filter mask.
+ */
+ hw_add_addr_in_hash(ugeth, &tempaddr);
+
+ }
+ }
+ }
+}
+
+static void ucc_geth_stop(ucc_geth_private_t *ugeth)
+{
+ ucc_geth_t *ug_regs = ugeth->ug_regs;
+ u32 tempval;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ /* Disable the controller */
+ ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
+
+ /* Tell the kernel the link is down */
+ ugeth->mii_info->link = 0;
+ adjust_link(ugeth->dev);
+
+ /* Mask all interrupts */
+ out_be32(ugeth->uccf->p_ucce, 0x00000000);
+
+ /* Clear all interrupts */
+ out_be32(ugeth->uccf->p_ucce, 0xffffffff);
+
+ /* Disable Rx and Tx */
+ tempval = in_be32(&ug_regs->maccfg1);
+ tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX);
+ out_be32(&ug_regs->maccfg1, tempval);
+
+ if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
+ /* Clear any pending interrupts */
+ mii_clear_phy_interrupt(ugeth->mii_info);
+
+ /* Disable PHY Interrupts */
+ mii_configure_phy_interrupt(ugeth->mii_info,
+ MII_INTERRUPT_DISABLED);
+ }
+
+ free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev);
+
+ if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
+ free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev);
+ } else {
+ del_timer_sync(&ugeth->phy_info_timer);
+ }
+
+ ucc_geth_memclean(ugeth);
+}
+
+static int ucc_geth_startup(ucc_geth_private_t *ugeth)
+{
+ ucc_geth_82xx_address_filtering_pram_t *p_82xx_addr_filt;
+ ucc_geth_init_pram_t *p_init_enet_pram;
+ ucc_fast_private_t *uccf;
+ ucc_geth_info_t *ug_info;
+ ucc_fast_info_t *uf_info;
+ ucc_fast_t *uf_regs;
+ ucc_geth_t *ug_regs;
+ int ret_val = -EINVAL;
+ u32 remoder = UCC_GETH_REMODER_INIT;
+ u32 init_enet_pram_offset, cecr_subblock, command, maccfg1;
+ u32 ifstat, i, j, size, l2qt, l3qt, length;
+ u16 temoder = UCC_GETH_TEMODER_INIT;
+ u16 test;
+ u8 function_code = 0;
+ u8 *bd, *endOfRing;
+ u8 numThreadsRxNumerical, numThreadsTxNumerical;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ ug_info = ugeth->ug_info;
+ uf_info = &ug_info->uf_info;
+
+ if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) ||
+ (uf_info->bd_mem_part == MEM_PART_MURAM))) {
+ ugeth_err("%s: Bad memory partition value.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* Rx BD lengths */
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ if ((ug_info->bdRingLenRx[i] < UCC_GETH_RX_BD_RING_SIZE_MIN) ||
+ (ug_info->bdRingLenRx[i] %
+ UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT)) {
+ ugeth_err
+ ("%s: Rx BD ring length must be multiple of 4,"
+ " no smaller than 8.", __FUNCTION__);
+ return -EINVAL;
+ }
+ }
+
+ /* Tx BD lengths */
+ for (i = 0; i < ug_info->numQueuesTx; i++) {
+ if (ug_info->bdRingLenTx[i] < UCC_GETH_TX_BD_RING_SIZE_MIN) {
+ ugeth_err
+ ("%s: Tx BD ring length must be no smaller than 2.",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ }
+
+ /* mrblr */
+ if ((uf_info->max_rx_buf_length == 0) ||
+ (uf_info->max_rx_buf_length % UCC_GETH_MRBLR_ALIGNMENT)) {
+ ugeth_err
+ ("%s: max_rx_buf_length must be non-zero multiple of 128.",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* num Tx queues */
+ if (ug_info->numQueuesTx > NUM_TX_QUEUES) {
+ ugeth_err("%s: number of tx queues too large.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* num Rx queues */
+ if (ug_info->numQueuesRx > NUM_RX_QUEUES) {
+ ugeth_err("%s: number of rx queues too large.", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* l2qt */
+ for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++) {
+ if (ug_info->l2qt[i] >= ug_info->numQueuesRx) {
+ ugeth_err
+ ("%s: VLAN priority table entry must not be"
+ " larger than number of Rx queues.",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ }
+
+ /* l3qt */
+ for (i = 0; i < UCC_GETH_IP_PRIORITY_MAX; i++) {
+ if (ug_info->l3qt[i] >= ug_info->numQueuesRx) {
+ ugeth_err
+ ("%s: IP priority table entry must not be"
+ " larger than number of Rx queues.",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+ }
+
+ if (ug_info->cam && !ug_info->ecamptr) {
+ ugeth_err("%s: If cam mode is chosen, must supply cam ptr.",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ if ((ug_info->numStationAddresses !=
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_1)
+ && ug_info->rxExtendedFiltering) {
+ ugeth_err("%s: Number of station addresses greater than 1 "
+ "not allowed in extended parsing mode.",
+ __FUNCTION__);
+ return -EINVAL;
+ }
+
+ /* Generate uccm_mask for receive */
+ uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */
+ for (i = 0; i < ug_info->numQueuesRx; i++)
+ uf_info->uccm_mask |= (UCCE_RXBF_SINGLE_MASK << i);
+
+ for (i = 0; i < ug_info->numQueuesTx; i++)
+ uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i);
+ /* Initialize the general fast UCC block. */
+ if (ucc_fast_init(uf_info, &uccf)) {
+ ugeth_err("%s: Failed to init uccf.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ ugeth->uccf = uccf;
+
+ switch (ug_info->numThreadsRx) {
+ case UCC_GETH_NUM_OF_THREADS_1:
+ numThreadsRxNumerical = 1;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_2:
+ numThreadsRxNumerical = 2;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_4:
+ numThreadsRxNumerical = 4;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_6:
+ numThreadsRxNumerical = 6;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_8:
+ numThreadsRxNumerical = 8;
+ break;
+ default:
+ ugeth_err("%s: Bad number of Rx threads value.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -EINVAL;
+ break;
+ }
+
+ switch (ug_info->numThreadsTx) {
+ case UCC_GETH_NUM_OF_THREADS_1:
+ numThreadsTxNumerical = 1;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_2:
+ numThreadsTxNumerical = 2;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_4:
+ numThreadsTxNumerical = 4;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_6:
+ numThreadsTxNumerical = 6;
+ break;
+ case UCC_GETH_NUM_OF_THREADS_8:
+ numThreadsTxNumerical = 8;
+ break;
+ default:
+ ugeth_err("%s: Bad number of Tx threads value.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -EINVAL;
+ break;
+ }
+
+ /* Calculate rx_extended_features */
+ ugeth->rx_non_dynamic_extended_features = ug_info->ipCheckSumCheck ||
+ ug_info->ipAddressAlignment ||
+ (ug_info->numStationAddresses !=
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_1);
+
+ ugeth->rx_extended_features = ugeth->rx_non_dynamic_extended_features ||
+ (ug_info->vlanOperationTagged != UCC_GETH_VLAN_OPERATION_TAGGED_NOP)
+ || (ug_info->vlanOperationNonTagged !=
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP);
+
+ uf_regs = uccf->uf_regs;
+ ug_regs = (ucc_geth_t *) (uccf->uf_regs);
+ ugeth->ug_regs = ug_regs;
+
+ init_default_reg_vals(&uf_regs->upsmr,
+ &ug_regs->maccfg1, &ug_regs->maccfg2);
+
+ /* Set UPSMR */
+ /* For more details see the hardware spec. */
+ init_rx_parameters(ug_info->bro,
+ ug_info->rsh, ug_info->pro, &uf_regs->upsmr);
+
+ /* We're going to ignore other registers for now, */
+ /* except as needed to get up and running */
+
+ /* Set MACCFG1 */
+ /* For more details see the hardware spec. */
+ init_flow_control_params(ug_info->aufc,
+ ug_info->receiveFlowControl,
+ 1,
+ ug_info->pausePeriod,
+ ug_info->extensionField,
+ &uf_regs->upsmr,
+ &ug_regs->uempr, &ug_regs->maccfg1);
+
+ maccfg1 = in_be32(&ug_regs->maccfg1);
+ maccfg1 |= MACCFG1_ENABLE_RX;
+ maccfg1 |= MACCFG1_ENABLE_TX;
+ out_be32(&ug_regs->maccfg1, maccfg1);
+
+ /* Set IPGIFG */
+ /* For more details see the hardware spec. */
+ ret_val = init_inter_frame_gap_params(ug_info->nonBackToBackIfgPart1,
+ ug_info->nonBackToBackIfgPart2,
+ ug_info->
+ miminumInterFrameGapEnforcement,
+ ug_info->backToBackInterFrameGap,
+ &ug_regs->ipgifg);
+ if (ret_val != 0) {
+ ugeth_err("%s: IPGIFG initialization parameter too large.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return ret_val;
+ }
+
+ /* Set HAFDUP */
+ /* For more details see the hardware spec. */
+ ret_val = init_half_duplex_params(ug_info->altBeb,
+ ug_info->backPressureNoBackoff,
+ ug_info->noBackoff,
+ ug_info->excessDefer,
+ ug_info->altBebTruncation,
+ ug_info->maxRetransmission,
+ ug_info->collisionWindow,
+ &ug_regs->hafdup);
+ if (ret_val != 0) {
+ ugeth_err("%s: Half Duplex initialization parameter too large.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return ret_val;
+ }
+
+ /* Set IFSTAT */
+ /* For more details see the hardware spec. */
+ /* Read only - resets upon read */
+ ifstat = in_be32(&ug_regs->ifstat);
+
+ /* Clear UEMPR */
+ /* For more details see the hardware spec. */
+ out_be32(&ug_regs->uempr, 0);
+
+ /* Set UESCR */
+ /* For more details see the hardware spec. */
+ init_hw_statistics_gathering_mode((ug_info->statisticsMode &
+ UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE),
+ 0, &uf_regs->upsmr, &ug_regs->uescr);
+
+ /* Allocate Tx bds */
+ for (j = 0; j < ug_info->numQueuesTx; j++) {
+ /* Allocate in multiple of
+ UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT,
+ according to spec */
+ length = ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD)
+ / UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ * UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+ if ((ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD) %
+ UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT)
+ length += UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT;
+ if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
+ u32 align = 4;
+ if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
+ align = UCC_GETH_TX_BD_RING_ALIGNMENT;
+ ugeth->tx_bd_ring_offset[j] =
+ (u32) (kmalloc((u32) (length + align),
+ GFP_KERNEL));
+ if (ugeth->tx_bd_ring_offset[j] != 0)
+ ugeth->p_tx_bd_ring[j] =
+ (void*)((ugeth->tx_bd_ring_offset[j] +
+ align) & ~(align - 1));
+ } else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
+ ugeth->tx_bd_ring_offset[j] =
+ qe_muram_alloc(length,
+ UCC_GETH_TX_BD_RING_ALIGNMENT);
+ if (!IS_MURAM_ERR(ugeth->tx_bd_ring_offset[j]))
+ ugeth->p_tx_bd_ring[j] =
+ (u8 *) qe_muram_addr(ugeth->
+ tx_bd_ring_offset[j]);
+ }
+ if (!ugeth->p_tx_bd_ring[j]) {
+ ugeth_err
+ ("%s: Can not allocate memory for Tx bd rings.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ /* Zero unused end of bd ring, according to spec */
+ memset(ugeth->p_tx_bd_ring[j] +
+ ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD, 0,
+ length - ug_info->bdRingLenTx[j] * UCC_GETH_SIZE_OF_BD);
+ }
+
+ /* Allocate Rx bds */
+ for (j = 0; j < ug_info->numQueuesRx; j++) {
+ length = ug_info->bdRingLenRx[j] * UCC_GETH_SIZE_OF_BD;
+ if (uf_info->bd_mem_part == MEM_PART_SYSTEM) {
+ u32 align = 4;
+ if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
+ align = UCC_GETH_RX_BD_RING_ALIGNMENT;
+ ugeth->rx_bd_ring_offset[j] =
+ (u32) (kmalloc((u32) (length + align), GFP_KERNEL));
+ if (ugeth->rx_bd_ring_offset[j] != 0)
+ ugeth->p_rx_bd_ring[j] =
+ (void*)((ugeth->rx_bd_ring_offset[j] +
+ align) & ~(align - 1));
+ } else if (uf_info->bd_mem_part == MEM_PART_MURAM) {
+ ugeth->rx_bd_ring_offset[j] =
+ qe_muram_alloc(length,
+ UCC_GETH_RX_BD_RING_ALIGNMENT);
+ if (!IS_MURAM_ERR(ugeth->rx_bd_ring_offset[j]))
+ ugeth->p_rx_bd_ring[j] =
+ (u8 *) qe_muram_addr(ugeth->
+ rx_bd_ring_offset[j]);
+ }
+ if (!ugeth->p_rx_bd_ring[j]) {
+ ugeth_err
+ ("%s: Can not allocate memory for Rx bd rings.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ }
+
+ /* Init Tx bds */
+ for (j = 0; j < ug_info->numQueuesTx; j++) {
+ /* Setup the skbuff rings */
+ ugeth->tx_skbuff[j] =
+ (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenTx[j],
+ GFP_KERNEL);
+
+ if (ugeth->tx_skbuff[j] == NULL) {
+ ugeth_err("%s: Could not allocate tx_skbuff",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ugeth->ug_info->bdRingLenTx[j]; i++)
+ ugeth->tx_skbuff[j][i] = NULL;
+
+ ugeth->skb_curtx[j] = ugeth->skb_dirtytx[j] = 0;
+ bd = ugeth->confBd[j] = ugeth->txBd[j] = ugeth->p_tx_bd_ring[j];
+ for (i = 0; i < ug_info->bdRingLenTx[j]; i++) {
+ BD_BUFFER_CLEAR(bd);
+ BD_STATUS_AND_LENGTH_SET(bd, 0);
+ bd += UCC_GETH_SIZE_OF_BD;
+ }
+ bd -= UCC_GETH_SIZE_OF_BD;
+ BD_STATUS_AND_LENGTH_SET(bd, T_W);/* for last BD set Wrap bit */
+ }
+
+ /* Init Rx bds */
+ for (j = 0; j < ug_info->numQueuesRx; j++) {
+ /* Setup the skbuff rings */
+ ugeth->rx_skbuff[j] =
+ (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
+ ugeth->ug_info->bdRingLenRx[j],
+ GFP_KERNEL);
+
+ if (ugeth->rx_skbuff[j] == NULL) {
+ ugeth_err("%s: Could not allocate rx_skbuff",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < ugeth->ug_info->bdRingLenRx[j]; i++)
+ ugeth->rx_skbuff[j][i] = NULL;
+
+ ugeth->skb_currx[j] = 0;
+ bd = ugeth->rxBd[j] = ugeth->p_rx_bd_ring[j];
+ for (i = 0; i < ug_info->bdRingLenRx[j]; i++) {
+ BD_STATUS_AND_LENGTH_SET(bd, R_I);
+ BD_BUFFER_CLEAR(bd);
+ bd += UCC_GETH_SIZE_OF_BD;
+ }
+ bd -= UCC_GETH_SIZE_OF_BD;
+ BD_STATUS_AND_LENGTH_SET(bd, R_W);/* for last BD set Wrap bit */
+ }
+
+ /*
+ * Global PRAM
+ */
+ /* Tx global PRAM */
+ /* Allocate global tx parameter RAM page */
+ ugeth->tx_glbl_pram_offset =
+ qe_muram_alloc(sizeof(ucc_geth_tx_global_pram_t),
+ UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->tx_glbl_pram_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ ugeth->p_tx_glbl_pram =
+ (ucc_geth_tx_global_pram_t *) qe_muram_addr(ugeth->
+ tx_glbl_pram_offset);
+ /* Zero out p_tx_glbl_pram */
+ memset(ugeth->p_tx_glbl_pram, 0, sizeof(ucc_geth_tx_global_pram_t));
+
+ /* Fill global PRAM */
+
+ /* TQPTR */
+ /* Size varies with number of Tx threads */
+ ugeth->thread_dat_tx_offset =
+ qe_muram_alloc(numThreadsTxNumerical *
+ sizeof(ucc_geth_thread_data_tx_t) +
+ 32 * (numThreadsTxNumerical == 1),
+ UCC_GETH_THREAD_DATA_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->thread_dat_tx_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_thread_data_tx.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_thread_data_tx =
+ (ucc_geth_thread_data_tx_t *) qe_muram_addr(ugeth->
+ thread_dat_tx_offset);
+ out_be32(&ugeth->p_tx_glbl_pram->tqptr, ugeth->thread_dat_tx_offset);
+
+ /* vtagtable */
+ for (i = 0; i < UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX; i++)
+ out_be32(&ugeth->p_tx_glbl_pram->vtagtable[i],
+ ug_info->vtagtable[i]);
+
+ /* iphoffset */
+ for (i = 0; i < TX_IP_OFFSET_ENTRY_MAX; i++)
+ ugeth->p_tx_glbl_pram->iphoffset[i] = ug_info->iphoffset[i];
+
+ /* SQPTR */
+ /* Size varies with number of Tx queues */
+ ugeth->send_q_mem_reg_offset =
+ qe_muram_alloc(ug_info->numQueuesTx *
+ sizeof(ucc_geth_send_queue_qd_t),
+ UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->send_q_mem_reg_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_send_q_mem_reg =
+ (ucc_geth_send_queue_mem_region_t *) qe_muram_addr(ugeth->
+ send_q_mem_reg_offset);
+ out_be32(&ugeth->p_tx_glbl_pram->sqptr, ugeth->send_q_mem_reg_offset);
+
+ /* Setup the table */
+ /* Assume BD rings are already established */
+ for (i = 0; i < ug_info->numQueuesTx; i++) {
+ endOfRing =
+ ugeth->p_tx_bd_ring[i] + (ug_info->bdRingLenTx[i] -
+ 1) * UCC_GETH_SIZE_OF_BD;
+ if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) {
+ out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
+ (u32) virt_to_phys(ugeth->p_tx_bd_ring[i]));
+ out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
+ last_bd_completed_address,
+ (u32) virt_to_phys(endOfRing));
+ } else if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_MURAM) {
+ out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].bd_ring_base,
+ (u32) immrbar_virt_to_phys(ugeth->
+ p_tx_bd_ring[i]));
+ out_be32(&ugeth->p_send_q_mem_reg->sqqd[i].
+ last_bd_completed_address,
+ (u32) immrbar_virt_to_phys(endOfRing));
+ }
+ }
+
+ /* schedulerbasepointer */
+
+ if (ug_info->numQueuesTx > 1) {
+ /* scheduler exists only if more than 1 tx queue */
+ ugeth->scheduler_offset =
+ qe_muram_alloc(sizeof(ucc_geth_scheduler_t),
+ UCC_GETH_SCHEDULER_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->scheduler_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_scheduler.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_scheduler =
+ (ucc_geth_scheduler_t *) qe_muram_addr(ugeth->
+ scheduler_offset);
+ out_be32(&ugeth->p_tx_glbl_pram->schedulerbasepointer,
+ ugeth->scheduler_offset);
+ /* Zero out p_scheduler */
+ memset(ugeth->p_scheduler, 0, sizeof(ucc_geth_scheduler_t));
+
+ /* Set values in scheduler */
+ out_be32(&ugeth->p_scheduler->mblinterval,
+ ug_info->mblinterval);
+ out_be16(&ugeth->p_scheduler->nortsrbytetime,
+ ug_info->nortsrbytetime);
+ ugeth->p_scheduler->fracsiz = ug_info->fracsiz;
+ ugeth->p_scheduler->strictpriorityq = ug_info->strictpriorityq;
+ ugeth->p_scheduler->txasap = ug_info->txasap;
+ ugeth->p_scheduler->extrabw = ug_info->extrabw;
+ for (i = 0; i < NUM_TX_QUEUES; i++)
+ ugeth->p_scheduler->weightfactor[i] =
+ ug_info->weightfactor[i];
+
+ /* Set pointers to cpucount registers in scheduler */
+ ugeth->p_cpucount[0] = &(ugeth->p_scheduler->cpucount0);
+ ugeth->p_cpucount[1] = &(ugeth->p_scheduler->cpucount1);
+ ugeth->p_cpucount[2] = &(ugeth->p_scheduler->cpucount2);
+ ugeth->p_cpucount[3] = &(ugeth->p_scheduler->cpucount3);
+ ugeth->p_cpucount[4] = &(ugeth->p_scheduler->cpucount4);
+ ugeth->p_cpucount[5] = &(ugeth->p_scheduler->cpucount5);
+ ugeth->p_cpucount[6] = &(ugeth->p_scheduler->cpucount6);
+ ugeth->p_cpucount[7] = &(ugeth->p_scheduler->cpucount7);
+ }
+
+ /* schedulerbasepointer */
+ /* TxRMON_PTR (statistics) */
+ if (ug_info->
+ statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
+ ugeth->tx_fw_statistics_pram_offset =
+ qe_muram_alloc(sizeof
+ (ucc_geth_tx_firmware_statistics_pram_t),
+ UCC_GETH_TX_STATISTICS_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->tx_fw_statistics_pram_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_tx_fw_statistics_pram.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ ugeth->p_tx_fw_statistics_pram =
+ (ucc_geth_tx_firmware_statistics_pram_t *)
+ qe_muram_addr(ugeth->tx_fw_statistics_pram_offset);
+ /* Zero out p_tx_fw_statistics_pram */
+ memset(ugeth->p_tx_fw_statistics_pram,
+ 0, sizeof(ucc_geth_tx_firmware_statistics_pram_t));
+ }
+
+ /* temoder */
+ /* Already has speed set */
+
+ if (ug_info->numQueuesTx > 1)
+ temoder |= TEMODER_SCHEDULER_ENABLE;
+ if (ug_info->ipCheckSumGenerate)
+ temoder |= TEMODER_IP_CHECKSUM_GENERATE;
+ temoder |= ((ug_info->numQueuesTx - 1) << TEMODER_NUM_OF_QUEUES_SHIFT);
+ out_be16(&ugeth->p_tx_glbl_pram->temoder, temoder);
+
+ test = in_be16(&ugeth->p_tx_glbl_pram->temoder);
+
+ /* Function code register value to be used later */
+ function_code = QE_BMR_BYTE_ORDER_BO_MOT | UCC_FAST_FUNCTION_CODE_GBL;
+ /* Required for QE */
+
+ /* function code register */
+ out_be32(&ugeth->p_tx_glbl_pram->tstate, ((u32) function_code) << 24);
+
+ /* Rx global PRAM */
+ /* Allocate global rx parameter RAM page */
+ ugeth->rx_glbl_pram_offset =
+ qe_muram_alloc(sizeof(ucc_geth_rx_global_pram_t),
+ UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_glbl_pram_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ ugeth->p_rx_glbl_pram =
+ (ucc_geth_rx_global_pram_t *) qe_muram_addr(ugeth->
+ rx_glbl_pram_offset);
+ /* Zero out p_rx_glbl_pram */
+ memset(ugeth->p_rx_glbl_pram, 0, sizeof(ucc_geth_rx_global_pram_t));
+
+ /* Fill global PRAM */
+
+ /* RQPTR */
+ /* Size varies with number of Rx threads */
+ ugeth->thread_dat_rx_offset =
+ qe_muram_alloc(numThreadsRxNumerical *
+ sizeof(ucc_geth_thread_data_rx_t),
+ UCC_GETH_THREAD_DATA_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->thread_dat_rx_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_thread_data_rx.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_thread_data_rx =
+ (ucc_geth_thread_data_rx_t *) qe_muram_addr(ugeth->
+ thread_dat_rx_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->rqptr, ugeth->thread_dat_rx_offset);
+
+ /* typeorlen */
+ out_be16(&ugeth->p_rx_glbl_pram->typeorlen, ug_info->typeorlen);
+
+ /* rxrmonbaseptr (statistics) */
+ if (ug_info->
+ statisticsMode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
+ ugeth->rx_fw_statistics_pram_offset =
+ qe_muram_alloc(sizeof
+ (ucc_geth_rx_firmware_statistics_pram_t),
+ UCC_GETH_RX_STATISTICS_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_fw_statistics_pram_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_rx_fw_statistics_pram.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ ugeth->p_rx_fw_statistics_pram =
+ (ucc_geth_rx_firmware_statistics_pram_t *)
+ qe_muram_addr(ugeth->rx_fw_statistics_pram_offset);
+ /* Zero out p_rx_fw_statistics_pram */
+ memset(ugeth->p_rx_fw_statistics_pram, 0,
+ sizeof(ucc_geth_rx_firmware_statistics_pram_t));
+ }
+
+ /* intCoalescingPtr */
+
+ /* Size varies with number of Rx queues */
+ ugeth->rx_irq_coalescing_tbl_offset =
+ qe_muram_alloc(ug_info->numQueuesRx *
+ sizeof(ucc_geth_rx_interrupt_coalescing_entry_t),
+ UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_rx_irq_coalescing_tbl.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_rx_irq_coalescing_tbl =
+ (ucc_geth_rx_interrupt_coalescing_table_t *)
+ qe_muram_addr(ugeth->rx_irq_coalescing_tbl_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->intcoalescingptr,
+ ugeth->rx_irq_coalescing_tbl_offset);
+
+ /* Fill interrupt coalescing table */
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i].
+ interruptcoalescingmaxvalue,
+ ug_info->interruptcoalescingmaxvalue[i]);
+ out_be32(&ugeth->p_rx_irq_coalescing_tbl->coalescingentry[i].
+ interruptcoalescingcounter,
+ ug_info->interruptcoalescingmaxvalue[i]);
+ }
+
+ /* MRBLR */
+ init_max_rx_buff_len(uf_info->max_rx_buf_length,
+ &ugeth->p_rx_glbl_pram->mrblr);
+ /* MFLR */
+ out_be16(&ugeth->p_rx_glbl_pram->mflr, ug_info->maxFrameLength);
+ /* MINFLR */
+ init_min_frame_len(ug_info->minFrameLength,
+ &ugeth->p_rx_glbl_pram->minflr,
+ &ugeth->p_rx_glbl_pram->mrblr);
+ /* MAXD1 */
+ out_be16(&ugeth->p_rx_glbl_pram->maxd1, ug_info->maxD1Length);
+ /* MAXD2 */
+ out_be16(&ugeth->p_rx_glbl_pram->maxd2, ug_info->maxD2Length);
+
+ /* l2qt */
+ l2qt = 0;
+ for (i = 0; i < UCC_GETH_VLAN_PRIORITY_MAX; i++)
+ l2qt |= (ug_info->l2qt[i] << (28 - 4 * i));
+ out_be32(&ugeth->p_rx_glbl_pram->l2qt, l2qt);
+
+ /* l3qt */
+ for (j = 0; j < UCC_GETH_IP_PRIORITY_MAX; j += 8) {
+ l3qt = 0;
+ for (i = 0; i < 8; i++)
+ l3qt |= (ug_info->l3qt[j + i] << (28 - 4 * i));
+ out_be32(&ugeth->p_rx_glbl_pram->l3qt[j], l3qt);
+ }
+
+ /* vlantype */
+ out_be16(&ugeth->p_rx_glbl_pram->vlantype, ug_info->vlantype);
+
+ /* vlantci */
+ out_be16(&ugeth->p_rx_glbl_pram->vlantci, ug_info->vlantci);
+
+ /* ecamptr */
+ out_be32(&ugeth->p_rx_glbl_pram->ecamptr, ug_info->ecamptr);
+
+ /* RBDQPTR */
+ /* Size varies with number of Rx queues */
+ ugeth->rx_bd_qs_tbl_offset =
+ qe_muram_alloc(ug_info->numQueuesRx *
+ (sizeof(ucc_geth_rx_bd_queues_entry_t) +
+ sizeof(ucc_geth_rx_prefetched_bds_t)),
+ UCC_GETH_RX_BD_QUEUES_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->rx_bd_qs_tbl_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_rx_bd_qs_tbl =
+ (ucc_geth_rx_bd_queues_entry_t *) qe_muram_addr(ugeth->
+ rx_bd_qs_tbl_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->rbdqptr, ugeth->rx_bd_qs_tbl_offset);
+ /* Zero out p_rx_bd_qs_tbl */
+ memset(ugeth->p_rx_bd_qs_tbl,
+ 0,
+ ug_info->numQueuesRx * (sizeof(ucc_geth_rx_bd_queues_entry_t) +
+ sizeof(ucc_geth_rx_prefetched_bds_t)));
+
+ /* Setup the table */
+ /* Assume BD rings are already established */
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ if (ugeth->ug_info->uf_info.bd_mem_part == MEM_PART_SYSTEM) {
+ out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
+ (u32) virt_to_phys(ugeth->p_rx_bd_ring[i]));
+ } else if (ugeth->ug_info->uf_info.bd_mem_part ==
+ MEM_PART_MURAM) {
+ out_be32(&ugeth->p_rx_bd_qs_tbl[i].externalbdbaseptr,
+ (u32) immrbar_virt_to_phys(ugeth->
+ p_rx_bd_ring[i]));
+ }
+ /* rest of fields handled by QE */
+ }
+
+ /* remoder */
+ /* Already has speed set */
+
+ if (ugeth->rx_extended_features)
+ remoder |= REMODER_RX_EXTENDED_FEATURES;
+ if (ug_info->rxExtendedFiltering)
+ remoder |= REMODER_RX_EXTENDED_FILTERING;
+ if (ug_info->dynamicMaxFrameLength)
+ remoder |= REMODER_DYNAMIC_MAX_FRAME_LENGTH;
+ if (ug_info->dynamicMinFrameLength)
+ remoder |= REMODER_DYNAMIC_MIN_FRAME_LENGTH;
+ remoder |=
+ ug_info->vlanOperationTagged << REMODER_VLAN_OPERATION_TAGGED_SHIFT;
+ remoder |=
+ ug_info->
+ vlanOperationNonTagged << REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT;
+ remoder |= ug_info->rxQoSMode << REMODER_RX_QOS_MODE_SHIFT;
+ remoder |= ((ug_info->numQueuesRx - 1) << REMODER_NUM_OF_QUEUES_SHIFT);
+ if (ug_info->ipCheckSumCheck)
+ remoder |= REMODER_IP_CHECKSUM_CHECK;
+ if (ug_info->ipAddressAlignment)
+ remoder |= REMODER_IP_ADDRESS_ALIGNMENT;
+ out_be32(&ugeth->p_rx_glbl_pram->remoder, remoder);
+
+ /* Note that this function must be called */
+ /* ONLY AFTER p_tx_fw_statistics_pram */
+ /* andp_UccGethRxFirmwareStatisticsPram are allocated ! */
+ init_firmware_statistics_gathering_mode((ug_info->
+ statisticsMode &
+ UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX),
+ (ug_info->statisticsMode &
+ UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX),
+ &ugeth->p_tx_glbl_pram->txrmonbaseptr,
+ ugeth->tx_fw_statistics_pram_offset,
+ &ugeth->p_rx_glbl_pram->rxrmonbaseptr,
+ ugeth->rx_fw_statistics_pram_offset,
+ &ugeth->p_tx_glbl_pram->temoder,
+ &ugeth->p_rx_glbl_pram->remoder);
+
+ /* function code register */
+ ugeth->p_rx_glbl_pram->rstate = function_code;
+
+ /* initialize extended filtering */
+ if (ug_info->rxExtendedFiltering) {
+ if (!ug_info->extendedFilteringChainPointer) {
+ ugeth_err("%s: Null Extended Filtering Chain Pointer.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -EINVAL;
+ }
+
+ /* Allocate memory for extended filtering Mode Global
+ Parameters */
+ ugeth->exf_glbl_param_offset =
+ qe_muram_alloc(sizeof(ucc_geth_exf_global_pram_t),
+ UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT);
+ if (IS_MURAM_ERR(ugeth->exf_glbl_param_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for"
+ " p_exf_glbl_param.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+
+ ugeth->p_exf_glbl_param =
+ (ucc_geth_exf_global_pram_t *) qe_muram_addr(ugeth->
+ exf_glbl_param_offset);
+ out_be32(&ugeth->p_rx_glbl_pram->exfGlobalParam,
+ ugeth->exf_glbl_param_offset);
+ out_be32(&ugeth->p_exf_glbl_param->l2pcdptr,
+ (u32) ug_info->extendedFilteringChainPointer);
+
+ } else { /* initialize 82xx style address filtering */
+
+ /* Init individual address recognition registers to disabled */
+
+ for (j = 0; j < NUM_OF_PADDRS; j++)
+ ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j);
+
+ /* Create CQs for hash tables */
+ if (ug_info->maxGroupAddrInHash > 0) {
+ INIT_LIST_HEAD(&ugeth->group_hash_q);
+ }
+ if (ug_info->maxIndAddrInHash > 0) {
+ INIT_LIST_HEAD(&ugeth->ind_hash_q);
+ }
+ p_82xx_addr_filt =
+ (ucc_geth_82xx_address_filtering_pram_t *) ugeth->
+ p_rx_glbl_pram->addressfiltering;
+
+ ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth,
+ ENET_ADDR_TYPE_GROUP);
+ ugeth_82xx_filtering_clear_all_addr_in_hash(ugeth,
+ ENET_ADDR_TYPE_INDIVIDUAL);
+ }
+
+ /*
+ * Initialize UCC at QE level
+ */
+
+ command = QE_INIT_TX_RX;
+
+ /* Allocate shadow InitEnet command parameter structure.
+ * This is needed because after the InitEnet command is executed,
+ * the structure in DPRAM is released, because DPRAM is a premium
+ * resource.
+ * This shadow structure keeps a copy of what was done so that the
+ * allocated resources can be released when the channel is freed.
+ */
+ if (!(ugeth->p_init_enet_param_shadow =
+ (ucc_geth_init_pram_t *) kmalloc(sizeof(ucc_geth_init_pram_t),
+ GFP_KERNEL))) {
+ ugeth_err
+ ("%s: Can not allocate memory for"
+ " p_UccInitEnetParamShadows.", __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ /* Zero out *p_init_enet_param_shadow */
+ memset((char *)ugeth->p_init_enet_param_shadow,
+ 0, sizeof(ucc_geth_init_pram_t));
+
+ /* Fill shadow InitEnet command parameter structure */
+
+ ugeth->p_init_enet_param_shadow->resinit1 =
+ ENET_INIT_PARAM_MAGIC_RES_INIT1;
+ ugeth->p_init_enet_param_shadow->resinit2 =
+ ENET_INIT_PARAM_MAGIC_RES_INIT2;
+ ugeth->p_init_enet_param_shadow->resinit3 =
+ ENET_INIT_PARAM_MAGIC_RES_INIT3;
+ ugeth->p_init_enet_param_shadow->resinit4 =
+ ENET_INIT_PARAM_MAGIC_RES_INIT4;
+ ugeth->p_init_enet_param_shadow->resinit5 =
+ ENET_INIT_PARAM_MAGIC_RES_INIT5;
+ ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=
+ ((u32) ug_info->numThreadsRx) << ENET_INIT_PARAM_RGF_SHIFT;
+ ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=
+ ((u32) ug_info->numThreadsTx) << ENET_INIT_PARAM_TGF_SHIFT;
+
+ ugeth->p_init_enet_param_shadow->rgftgfrxglobal |=
+ ugeth->rx_glbl_pram_offset | ug_info->riscRx;
+ if ((ug_info->largestexternallookupkeysize !=
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE)
+ && (ug_info->largestexternallookupkeysize !=
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
+ && (ug_info->largestexternallookupkeysize !=
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES)) {
+ ugeth_err("%s: Invalid largest External Lookup Key Size.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -EINVAL;
+ }
+ ugeth->p_init_enet_param_shadow->largestexternallookupkeysize =
+ ug_info->largestexternallookupkeysize;
+ size = sizeof(ucc_geth_thread_rx_pram_t);
+ if (ug_info->rxExtendedFiltering) {
+ size += THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING;
+ if (ug_info->largestexternallookupkeysize ==
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES)
+ size +=
+ THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8;
+ if (ug_info->largestexternallookupkeysize ==
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES)
+ size +=
+ THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16;
+ }
+
+ if ((ret_val = fill_init_enet_entries(ugeth, &(ugeth->
+ p_init_enet_param_shadow->rxthread[0]),
+ (u8) (numThreadsRxNumerical + 1)
+ /* Rx needs one extra for terminator */
+ , size, UCC_GETH_THREAD_RX_PRAM_ALIGNMENT,
+ ug_info->riscRx, 1)) != 0) {
+ ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return ret_val;
+ }
+
+ ugeth->p_init_enet_param_shadow->txglobal =
+ ugeth->tx_glbl_pram_offset | ug_info->riscTx;
+ if ((ret_val =
+ fill_init_enet_entries(ugeth,
+ &(ugeth->p_init_enet_param_shadow->
+ txthread[0]), numThreadsTxNumerical,
+ sizeof(ucc_geth_thread_tx_pram_t),
+ UCC_GETH_THREAD_TX_PRAM_ALIGNMENT,
+ ug_info->riscTx, 0)) != 0) {
+ ugeth_err("%s: Can not fill p_init_enet_param_shadow.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return ret_val;
+ }
+
+ /* Load Rx bds with buffers */
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ if ((ret_val = rx_bd_buffer_set(ugeth, (u8) i)) != 0) {
+ ugeth_err("%s: Can not fill Rx bds with buffers.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return ret_val;
+ }
+ }
+
+ /* Allocate InitEnet command parameter structure */
+ init_enet_pram_offset = qe_muram_alloc(sizeof(ucc_geth_init_pram_t), 4);
+ if (IS_MURAM_ERR(init_enet_pram_offset)) {
+ ugeth_err
+ ("%s: Can not allocate DPRAM memory for p_init_enet_pram.",
+ __FUNCTION__);
+ ucc_geth_memclean(ugeth);
+ return -ENOMEM;
+ }
+ p_init_enet_pram =
+ (ucc_geth_init_pram_t *) qe_muram_addr(init_enet_pram_offset);
+
+ /* Copy shadow InitEnet command parameter structure into PRAM */
+ p_init_enet_pram->resinit1 = ugeth->p_init_enet_param_shadow->resinit1;
+ p_init_enet_pram->resinit2 = ugeth->p_init_enet_param_shadow->resinit2;
+ p_init_enet_pram->resinit3 = ugeth->p_init_enet_param_shadow->resinit3;
+ p_init_enet_pram->resinit4 = ugeth->p_init_enet_param_shadow->resinit4;
+ out_be16(&p_init_enet_pram->resinit5,
+ ugeth->p_init_enet_param_shadow->resinit5);
+ p_init_enet_pram->largestexternallookupkeysize =
+ ugeth->p_init_enet_param_shadow->largestexternallookupkeysize;
+ out_be32(&p_init_enet_pram->rgftgfrxglobal,
+ ugeth->p_init_enet_param_shadow->rgftgfrxglobal);
+ for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_RX; i++)
+ out_be32(&p_init_enet_pram->rxthread[i],
+ ugeth->p_init_enet_param_shadow->rxthread[i]);
+ out_be32(&p_init_enet_pram->txglobal,
+ ugeth->p_init_enet_param_shadow->txglobal);
+ for (i = 0; i < ENET_INIT_PARAM_MAX_ENTRIES_TX; i++)
+ out_be32(&p_init_enet_pram->txthread[i],
+ ugeth->p_init_enet_param_shadow->txthread[i]);
+
+ /* Issue QE command */
+ cecr_subblock =
+ ucc_fast_get_qe_cr_subblock(ugeth->ug_info->uf_info.ucc_num);
+ qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET,
+ init_enet_pram_offset);
+
+ /* Free InitEnet command parameter */
+ qe_muram_free(init_enet_pram_offset);
+
+ return 0;
+}
+
+/* returns a net_device_stats structure pointer */
+static struct net_device_stats *ucc_geth_get_stats(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+
+ return &(ugeth->stats);
+}
+
+/* ucc_geth_timeout gets called when a packet has not been
+ * transmitted after a set amount of time.
+ * For now, assume that clearing out all the structures, and
+ * starting over will fix the problem. */
+static void ucc_geth_timeout(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ ugeth->stats.tx_errors++;
+
+ ugeth_dump_regs(ugeth);
+
+ if (dev->flags & IFF_UP) {
+ ucc_geth_stop(ugeth);
+ ucc_geth_startup(ugeth);
+ }
+
+ netif_schedule(dev);
+}
+
+/* This is called by the kernel when a frame is ready for transmission. */
+/* It is pointed to by the dev->hard_start_xmit function pointer */
+static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ u8 *bd; /* BD pointer */
+ u32 bd_status;
+ u8 txQ = 0;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irq(&ugeth->lock);
+
+ ugeth->stats.tx_bytes += skb->len;
+
+ /* Start from the next BD that should be filled */
+ bd = ugeth->txBd[txQ];
+ bd_status = BD_STATUS_AND_LENGTH(bd);
+ /* Save the skb pointer so we can free it later */
+ ugeth->tx_skbuff[txQ][ugeth->skb_curtx[txQ]] = skb;
+
+ /* Update the current skb pointer (wrapping if this was the last) */
+ ugeth->skb_curtx[txQ] =
+ (ugeth->skb_curtx[txQ] +
+ 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
+
+ /* set up the buffer descriptor */
+ BD_BUFFER_SET(bd,
+ dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE));
+
+ //printk(KERN_DEBUG"skb->data is 0x%x\n",skb->data);
+
+ bd_status = (bd_status & T_W) | T_R | T_I | T_L | skb->len;
+
+ BD_STATUS_AND_LENGTH_SET(bd, bd_status);
+
+ dev->trans_start = jiffies;
+
+ /* Move to next BD in the ring */
+ if (!(bd_status & T_W))
+ ugeth->txBd[txQ] = bd + UCC_GETH_SIZE_OF_BD;
+ else
+ ugeth->txBd[txQ] = ugeth->p_tx_bd_ring[txQ];
+
+ /* If the next BD still needs to be cleaned up, then the bds
+ are full. We need to tell the kernel to stop sending us stuff. */
+ if (bd == ugeth->confBd[txQ]) {
+ if (!netif_queue_stopped(dev))
+ netif_stop_queue(dev);
+ }
+
+ if (ugeth->p_scheduler) {
+ ugeth->cpucount[txQ]++;
+ /* Indicate to QE that there are more Tx bds ready for
+ transmission */
+ /* This is done by writing a running counter of the bd
+ count to the scheduler PRAM. */
+ out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]);
+ }
+
+ spin_unlock_irq(&ugeth->lock);
+
+ return 0;
+}
+
+static int ucc_geth_rx(ucc_geth_private_t *ugeth, u8 rxQ, int rx_work_limit)
+{
+ struct sk_buff *skb;
+ u8 *bd;
+ u16 length, howmany = 0;
+ u32 bd_status;
+ u8 *bdBuffer;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock(&ugeth->lock);
+ /* collect received buffers */
+ bd = ugeth->rxBd[rxQ];
+
+ bd_status = BD_STATUS_AND_LENGTH(bd);
+
+ /* while there are received buffers and BD is full (~R_E) */
+ while (!((bd_status & (R_E)) || (--rx_work_limit < 0))) {
+ bdBuffer = (u8 *) BD_BUFFER(bd);
+ length = (u16) ((bd_status & BD_LENGTH_MASK) - 4);
+ skb = ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]];
+
+ /* determine whether buffer is first, last, first and last
+ (single buffer frame) or middle (not first and not last) */
+ if (!skb ||
+ (!(bd_status & (R_F | R_L))) ||
+ (bd_status & R_ERRORS_FATAL)) {
+ ugeth_vdbg("%s, %d: ERROR!!! skb - 0x%08x",
+ __FUNCTION__, __LINE__, (u32) skb);
+ if (skb)
+ dev_kfree_skb_any(skb);
+
+ ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = NULL;
+ ugeth->stats.rx_dropped++;
+ } else {
+ ugeth->stats.rx_packets++;
+ howmany++;
+
+ /* Prep the skb for the packet */
+ skb_put(skb, length);
+
+ /* Tell the skb what kind of packet this is */
+ skb->protocol = eth_type_trans(skb, ugeth->dev);
+
+ ugeth->stats.rx_bytes += length;
+ /* Send the packet up the stack */
+#ifdef CONFIG_UGETH_NAPI
+ netif_receive_skb(skb);
+#else
+ netif_rx(skb);
+#endif /* CONFIG_UGETH_NAPI */
+ }
+
+ ugeth->dev->last_rx = jiffies;
+
+ skb = get_new_skb(ugeth, bd);
+ if (!skb) {
+ ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__);
+ spin_unlock(&ugeth->lock);
+ ugeth->stats.rx_dropped++;
+ break;
+ }
+
+ ugeth->rx_skbuff[rxQ][ugeth->skb_currx[rxQ]] = skb;
+
+ /* update to point at the next skb */
+ ugeth->skb_currx[rxQ] =
+ (ugeth->skb_currx[rxQ] +
+ 1) & RX_RING_MOD_MASK(ugeth->ug_info->bdRingLenRx[rxQ]);
+
+ if (bd_status & R_W)
+ bd = ugeth->p_rx_bd_ring[rxQ];
+ else
+ bd += UCC_GETH_SIZE_OF_BD;
+
+ bd_status = BD_STATUS_AND_LENGTH(bd);
+ }
+
+ ugeth->rxBd[rxQ] = bd;
+ spin_unlock(&ugeth->lock);
+ return howmany;
+}
+
+static int ucc_geth_tx(struct net_device *dev, u8 txQ)
+{
+ /* Start from the next BD that should be filled */
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ u8 *bd; /* BD pointer */
+ u32 bd_status;
+
+ bd = ugeth->confBd[txQ];
+ bd_status = BD_STATUS_AND_LENGTH(bd);
+
+ /* Normal processing. */
+ while ((bd_status & T_R) == 0) {
+ /* BD contains already transmitted buffer. */
+ /* Handle the transmitted buffer and release */
+ /* the BD to be used with the current frame */
+
+ if ((bd = ugeth->txBd[txQ]) && (netif_queue_stopped(dev) == 0))
+ break;
+
+ ugeth->stats.tx_packets++;
+
+ /* Free the sk buffer associated with this TxBD */
+ dev_kfree_skb_irq(ugeth->
+ tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]]);
+ ugeth->tx_skbuff[txQ][ugeth->skb_dirtytx[txQ]] = NULL;
+ ugeth->skb_dirtytx[txQ] =
+ (ugeth->skb_dirtytx[txQ] +
+ 1) & TX_RING_MOD_MASK(ugeth->ug_info->bdRingLenTx[txQ]);
+
+ /* We freed a buffer, so now we can restart transmission */
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+
+ /* Advance the confirmation BD pointer */
+ if (!(bd_status & T_W))
+ ugeth->confBd[txQ] += UCC_GETH_SIZE_OF_BD;
+ else
+ ugeth->confBd[txQ] = ugeth->p_tx_bd_ring[txQ];
+ }
+ return 0;
+}
+
+#ifdef CONFIG_UGETH_NAPI
+static int ucc_geth_poll(struct net_device *dev, int *budget)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ int howmany;
+ int rx_work_limit = *budget;
+ u8 rxQ = 0;
+
+ if (rx_work_limit > dev->quota)
+ rx_work_limit = dev->quota;
+
+ howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit);
+
+ dev->quota -= howmany;
+ rx_work_limit -= howmany;
+ *budget -= howmany;
+
+ if (rx_work_limit >= 0)
+ netif_rx_complete(dev);
+
+ return (rx_work_limit < 0) ? 1 : 0;
+}
+#endif /* CONFIG_UGETH_NAPI */
+
+static irqreturn_t ucc_geth_irq_handler(int irq, void *info,
+ struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)info;
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ ucc_fast_private_t *uccf;
+ ucc_geth_info_t *ug_info;
+ register u32 ucce = 0;
+ register u32 bit_mask = UCCE_RXBF_SINGLE_MASK;
+ register u32 tx_mask = UCCE_TXBF_SINGLE_MASK;
+ register u8 i;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ if (!ugeth)
+ return IRQ_NONE;
+
+ uccf = ugeth->uccf;
+ ug_info = ugeth->ug_info;
+
+ do {
+ ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm));
+
+ /* clear event bits for next time */
+ /* Side effect here is to mask ucce variable
+ for future processing below. */
+ out_be32(uccf->p_ucce, ucce); /* Clear with ones,
+ but only bits in UCCM */
+
+ /* We ignore Tx interrupts because Tx confirmation is
+ done inside Tx routine */
+
+ for (i = 0; i < ug_info->numQueuesRx; i++) {
+ if (ucce & bit_mask)
+ ucc_geth_rx(ugeth, i,
+ (int)ugeth->ug_info->
+ bdRingLenRx[i]);
+ ucce &= ~bit_mask;
+ bit_mask <<= 1;
+ }
+
+ for (i = 0; i < ug_info->numQueuesTx; i++) {
+ if (ucce & tx_mask)
+ ucc_geth_tx(dev, i);
+ ucce &= ~tx_mask;
+ tx_mask <<= 1;
+ }
+
+ /* Exceptions */
+ if (ucce & UCCE_BSY) {
+ ugeth_vdbg("Got BUSY irq!!!!");
+ ugeth->stats.rx_errors++;
+ ucce &= ~UCCE_BSY;
+ }
+ if (ucce & UCCE_OTHER) {
+ ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!",
+ ucce);
+ ugeth->stats.rx_errors++;
+ ucce &= ~ucce;
+ }
+ }
+ while (ucce);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ /* Clear the interrupt */
+ mii_clear_phy_interrupt(ugeth->mii_info);
+
+ /* Disable PHY interrupts */
+ mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED);
+
+ /* Schedule the phy change */
+ schedule_work(&ugeth->tq);
+
+ return IRQ_HANDLED;
+}
+
+/* Scheduled by the phy_interrupt/timer to handle PHY changes */
+static void ugeth_phy_change(void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ ucc_geth_t *ug_regs;
+ int result = 0;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ ug_regs = ugeth->ug_regs;
+
+ /* Delay to give the PHY a chance to change the
+ * register state */
+ msleep(1);
+
+ /* Update the link, speed, duplex */
+ result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info);
+
+ /* Adjust the known status as long as the link
+ * isn't still coming up */
+ if ((0 == result) || (ugeth->mii_info->link == 0))
+ adjust_link(dev);
+
+ /* Reenable interrupts, if needed */
+ if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR)
+ mii_configure_phy_interrupt(ugeth->mii_info,
+ MII_INTERRUPT_ENABLED);
+}
+
+/* Called every so often on systems that don't interrupt
+ * the core for PHY changes */
+static void ugeth_phy_timer(unsigned long data)
+{
+ struct net_device *dev = (struct net_device *)data;
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+
+ schedule_work(&ugeth->tq);
+
+ mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
+}
+
+/* Keep trying aneg for some time
+ * If, after GFAR_AN_TIMEOUT seconds, it has not
+ * finished, we switch to forced.
+ * Either way, once the process has completed, we either
+ * request the interrupt, or switch the timer over to
+ * using ugeth_phy_timer to check status */
+static void ugeth_phy_startup_timer(unsigned long data)
+{
+ struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
+ ucc_geth_private_t *ugeth = netdev_priv(mii_info->dev);
+ static int secondary = UGETH_AN_TIMEOUT;
+ int result;
+
+ /* Configure the Auto-negotiation */
+ result = mii_info->phyinfo->config_aneg(mii_info);
+
+ /* If autonegotiation failed to start, and
+ * we haven't timed out, reset the timer, and return */
+ if (result && secondary--) {
+ mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
+ return;
+ } else if (result) {
+ /* Couldn't start autonegotiation.
+ * Try switching to forced */
+ mii_info->autoneg = 0;
+ result = mii_info->phyinfo->config_aneg(mii_info);
+
+ /* Forcing failed! Give up */
+ if (result) {
+ ugeth_err("%s: Forcing failed!", mii_info->dev->name);
+ return;
+ }
+ }
+
+ /* Kill the timer so it can be restarted */
+ del_timer_sync(&ugeth->phy_info_timer);
+
+ /* Grab the PHY interrupt, if necessary/possible */
+ if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) {
+ if (request_irq(ugeth->ug_info->phy_interrupt,
+ phy_interrupt,
+ SA_SHIRQ, "phy_interrupt", mii_info->dev) < 0) {
+ ugeth_err("%s: Can't get IRQ %d (PHY)",
+ mii_info->dev->name,
+ ugeth->ug_info->phy_interrupt);
+ } else {
+ mii_configure_phy_interrupt(ugeth->mii_info,
+ MII_INTERRUPT_ENABLED);
+ return;
+ }
+ }
+
+ /* Start the timer again, this time in order to
+ * handle a change in status */
+ init_timer(&ugeth->phy_info_timer);
+ ugeth->phy_info_timer.function = &ugeth_phy_timer;
+ ugeth->phy_info_timer.data = (unsigned long)mii_info->dev;
+ mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ);
+}
+
+/* Called when something needs to use the ethernet device */
+/* Returns 0 for success. */
+static int ucc_geth_open(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ int err;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ /* Test station address */
+ if (dev->dev_addr[0] & ENET_GROUP_ADDR) {
+ ugeth_err("%s: Multicast address used for station address"
+ " - is this what you wanted?", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ err = ucc_geth_startup(ugeth);
+ if (err) {
+ ugeth_err("%s: Cannot configure net device, aborting.",
+ dev->name);
+ return err;
+ }
+
+ err = adjust_enet_interface(ugeth);
+ if (err) {
+ ugeth_err("%s: Cannot configure net device, aborting.",
+ dev->name);
+ return err;
+ }
+
+ /* Set MACSTNADDR1, MACSTNADDR2 */
+ /* For more details see the hardware spec. */
+ init_mac_station_addr_regs(dev->dev_addr[0],
+ dev->dev_addr[1],
+ dev->dev_addr[2],
+ dev->dev_addr[3],
+ dev->dev_addr[4],
+ dev->dev_addr[5],
+ &ugeth->ug_regs->macstnaddr1,
+ &ugeth->ug_regs->macstnaddr2);
+
+ err = init_phy(dev);
+ if (err) {
+ ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name);
+ return err;
+ }
+#ifndef CONFIG_UGETH_NAPI
+ err =
+ request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0,
+ "UCC Geth", dev);
+ if (err) {
+ ugeth_err("%s: Cannot get IRQ for net device, aborting.",
+ dev->name);
+ ucc_geth_stop(ugeth);
+ return err;
+ }
+#endif /* CONFIG_UGETH_NAPI */
+
+ /* Set up the PHY change work queue */
+ INIT_WORK(&ugeth->tq, ugeth_phy_change, dev);
+
+ init_timer(&ugeth->phy_info_timer);
+ ugeth->phy_info_timer.function = &ugeth_phy_startup_timer;
+ ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info;
+ mod_timer(&ugeth->phy_info_timer, jiffies + HZ);
+
+ err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
+ if (err) {
+ ugeth_err("%s: Cannot enable net device, aborting.", dev->name);
+ ucc_geth_stop(ugeth);
+ return err;
+ }
+
+ netif_start_queue(dev);
+
+ return err;
+}
+
+/* Stops the kernel queue, and halts the controller */
+static int ucc_geth_close(struct net_device *dev)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ ucc_geth_stop(ugeth);
+
+ /* Shutdown the PHY */
+ if (ugeth->mii_info->phyinfo->close)
+ ugeth->mii_info->phyinfo->close(ugeth->mii_info);
+
+ kfree(ugeth->mii_info);
+
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+const struct ethtool_ops ucc_geth_ethtool_ops = { };
+
+static int ucc_geth_probe(struct device *device)
+{
+ struct platform_device *pdev = to_platform_device(device);
+ struct ucc_geth_platform_data *ugeth_pdata;
+ struct net_device *dev = NULL;
+ struct ucc_geth_private *ugeth = NULL;
+ struct ucc_geth_info *ug_info;
+ int err;
+ static int mii_mng_configured = 0;
+
+ ugeth_vdbg("%s: IN", __FUNCTION__);
+
+ ugeth_pdata = (struct ucc_geth_platform_data *)pdev->dev.platform_data;
+
+ ug_info = &ugeth_info[pdev->id];
+ ug_info->uf_info.ucc_num = pdev->id;
+ ug_info->uf_info.rx_clock = ugeth_pdata->rx_clock;
+ ug_info->uf_info.tx_clock = ugeth_pdata->tx_clock;
+ ug_info->uf_info.regs = ugeth_pdata->phy_reg_addr;
+ ug_info->uf_info.irq = platform_get_irq(pdev, 0);
+ ug_info->phy_address = ugeth_pdata->phy_id;
+ ug_info->enet_interface = ugeth_pdata->phy_interface;
+ ug_info->board_flags = ugeth_pdata->board_flags;
+ ug_info->phy_interrupt = ugeth_pdata->phy_interrupt;
+
+ printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n",
+ ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs,
+ ug_info->uf_info.irq);
+
+ if (ug_info == NULL) {
+ ugeth_err("%s: [%d] Missing additional data!", __FUNCTION__,
+ pdev->id);
+ return -ENODEV;
+ }
+
+ if (!mii_mng_configured) {
+ ucc_set_qe_mux_mii_mng(ug_info->uf_info.ucc_num);
+ mii_mng_configured = 1;
+ }
+
+ /* Create an ethernet device instance */
+ dev = alloc_etherdev(sizeof(*ugeth));
+
+ if (dev == NULL)
+ return -ENOMEM;
+
+ ugeth = netdev_priv(dev);
+ spin_lock_init(&ugeth->lock);
+
+ dev_set_drvdata(device, dev);
+
+ /* Set the dev->base_addr to the gfar reg region */
+ dev->base_addr = (unsigned long)(ug_info->uf_info.regs);
+
+ SET_MODULE_OWNER(dev);
+ SET_NETDEV_DEV(dev, device);
+
+ /* Fill in the dev structure */
+ dev->open = ucc_geth_open;
+ dev->hard_start_xmit = ucc_geth_start_xmit;
+ dev->tx_timeout = ucc_geth_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+#ifdef CONFIG_UGETH_NAPI
+ dev->poll = ucc_geth_poll;
+ dev->weight = UCC_GETH_DEV_WEIGHT;
+#endif /* CONFIG_UGETH_NAPI */
+ dev->stop = ucc_geth_close;
+ dev->get_stats = ucc_geth_get_stats;
+// dev->change_mtu = ucc_geth_change_mtu;
+ dev->mtu = 1500;
+ dev->set_multicast_list = ucc_geth_set_multi;
+ dev->ethtool_ops = &ucc_geth_ethtool_ops;
+
+ err = register_netdev(dev);
+ if (err) {
+ ugeth_err("%s: Cannot register net device, aborting.",
+ dev->name);
+ free_netdev(dev);
+ return err;
+ }
+
+ ugeth->ug_info = ug_info;
+ ugeth->dev = dev;
+ memcpy(dev->dev_addr, ugeth_pdata->mac_addr, 6);
+
+ return 0;
+}
+
+static int ucc_geth_remove(struct device *device)
+{
+ struct net_device *dev = dev_get_drvdata(device);
+ struct ucc_geth_private *ugeth = netdev_priv(dev);
+
+ dev_set_drvdata(device, NULL);
+ ucc_geth_memclean(ugeth);
+ free_netdev(dev);
+
+ return 0;
+}
+
+/* Structure for a device driver */
+static struct device_driver ucc_geth_driver = {
+ .name = DRV_NAME,
+ .bus = &platform_bus_type,
+ .probe = ucc_geth_probe,
+ .remove = ucc_geth_remove,
+};
+
+static int __init ucc_geth_init(void)
+{
+ int i;
+ printk(KERN_INFO "ucc_geth: " DRV_DESC "\n");
+ for (i = 0; i < 8; i++)
+ memcpy(&(ugeth_info[i]), &ugeth_primary_info,
+ sizeof(ugeth_primary_info));
+
+ return driver_register(&ucc_geth_driver);
+}
+
+static void __exit ucc_geth_exit(void)
+{
+ driver_unregister(&ucc_geth_driver);
+}
+
+module_init(ucc_geth_init);
+module_exit(ucc_geth_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc");
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
new file mode 100644
index 00000000000..005965f5dd9
--- /dev/null
+++ b/drivers/net/ucc_geth.h
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * Internal header file for UCC Gigabit Ethernet unit routines.
+ *
+ * Changelog:
+ * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
+ * - Rearrange code and style fixes
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+#ifndef __UCC_GETH_H__
+#define __UCC_GETH_H__
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/fsl_devices.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include <asm/ucc.h>
+#include <asm/ucc_fast.h>
+
+#define NUM_TX_QUEUES 8
+#define NUM_RX_QUEUES 8
+#define NUM_BDS_IN_PREFETCHED_BDS 4
+#define TX_IP_OFFSET_ENTRY_MAX 8
+#define NUM_OF_PADDRS 4
+#define ENET_INIT_PARAM_MAX_ENTRIES_RX 9
+#define ENET_INIT_PARAM_MAX_ENTRIES_TX 8
+
+typedef struct ucc_mii_mng {
+ u32 miimcfg; /* MII management configuration reg */
+ u32 miimcom; /* MII management command reg */
+ u32 miimadd; /* MII management address reg */
+ u32 miimcon; /* MII management control reg */
+ u32 miimstat; /* MII management status reg */
+ u32 miimind; /* MII management indication reg */
+} __attribute__ ((packed)) ucc_mii_mng_t;
+
+typedef struct ucc_geth {
+ ucc_fast_t uccf;
+
+ u32 maccfg1; /* mac configuration reg. 1 */
+ u32 maccfg2; /* mac configuration reg. 2 */
+ u32 ipgifg; /* interframe gap reg. */
+ u32 hafdup; /* half-duplex reg. */
+ u8 res1[0x10];
+ ucc_mii_mng_t miimng; /* MII management structure */
+ u32 ifctl; /* interface control reg */
+ u32 ifstat; /* interface statux reg */
+ u32 macstnaddr1; /* mac station address part 1 reg */
+ u32 macstnaddr2; /* mac station address part 2 reg */
+ u8 res2[0x8];
+ u32 uempr; /* UCC Ethernet Mac parameter reg */
+ u32 utbipar; /* UCC tbi address reg */
+ u16 uescr; /* UCC Ethernet statistics control reg */
+ u8 res3[0x180 - 0x15A];
+ u32 tx64; /* Total number of frames (including bad
+ frames) transmitted that were exactly of the
+ minimal length (64 for un tagged, 68 for
+ tagged, or with length exactly equal to the
+ parameter MINLength */
+ u32 tx127; /* Total number of frames (including bad
+ frames) transmitted that were between
+ MINLength (Including FCS length==4) and 127
+ octets */
+ u32 tx255; /* Total number of frames (including bad
+ frames) transmitted that were between 128
+ (Including FCS length==4) and 255 octets */
+ u32 rx64; /* Total number of frames received including
+ bad frames that were exactly of the mninimal
+ length (64 bytes) */
+ u32 rx127; /* Total number of frames (including bad
+ frames) received that were between MINLength
+ (Including FCS length==4) and 127 octets */
+ u32 rx255; /* Total number of frames (including bad
+ frames) received that were between 128
+ (Including FCS length==4) and 255 octets */
+ u32 txok; /* Total number of octets residing in frames
+ that where involved in succesfull
+ transmission */
+ u16 txcf; /* Total number of PAUSE control frames
+ transmitted by this MAC */
+ u8 res4[0x2];
+ u32 tmca; /* Total number of frames that were transmitted
+ succesfully with the group address bit set
+ that are not broadcast frames */
+ u32 tbca; /* Total number of frames transmitted
+ succesfully that had destination address
+ field equal to the broadcast address */
+ u32 rxfok; /* Total number of frames received OK */
+ u32 rxbok; /* Total number of octets received OK */
+ u32 rbyt; /* Total number of octets received including
+ octets in bad frames. Must be implemented in
+ HW because it includes octets in frames that
+ never even reach the UCC */
+ u32 rmca; /* Total number of frames that were received
+ succesfully with the group address bit set
+ that are not broadcast frames */
+ u32 rbca; /* Total number of frames received succesfully
+ that had destination address equal to the
+ broadcast address */
+ u32 scar; /* Statistics carry register */
+ u32 scam; /* Statistics caryy mask register */
+ u8 res5[0x200 - 0x1c4];
+} __attribute__ ((packed)) ucc_geth_t;
+
+/* UCC GETH TEMODR Register */
+#define TEMODER_TX_RMON_STATISTICS_ENABLE 0x0100 /* enable Tx statistics
+ */
+#define TEMODER_SCHEDULER_ENABLE 0x2000 /* enable scheduler */
+#define TEMODER_IP_CHECKSUM_GENERATE 0x0400 /* generate IPv4
+ checksums */
+#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1 0x0200 /* enable performance
+ optimization
+ enhancement (mode1) */
+#define TEMODER_RMON_STATISTICS 0x0100 /* enable tx statistics
+ */
+#define TEMODER_NUM_OF_QUEUES_SHIFT (15-15) /* Number of queues <<
+ shift */
+
+/* UCC GETH TEMODR Register */
+#define REMODER_RX_RMON_STATISTICS_ENABLE 0x00001000 /* enable Rx
+ statistics */
+#define REMODER_RX_EXTENDED_FEATURES 0x80000000 /* enable
+ extended
+ features */
+#define REMODER_VLAN_OPERATION_TAGGED_SHIFT (31-9 ) /* vlan operation
+ tagged << shift */
+#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT (31-10) /* vlan operation non
+ tagged << shift */
+#define REMODER_RX_QOS_MODE_SHIFT (31-15) /* rx QoS mode << shift
+ */
+#define REMODER_RMON_STATISTICS 0x00001000 /* enable rx
+ statistics */
+#define REMODER_RX_EXTENDED_FILTERING 0x00000800 /* extended
+ filtering
+ vs.
+ mpc82xx-like
+ filtering */
+#define REMODER_NUM_OF_QUEUES_SHIFT (31-23) /* Number of queues <<
+ shift */
+#define REMODER_DYNAMIC_MAX_FRAME_LENGTH 0x00000008 /* enable
+ dynamic max
+ frame length
+ */
+#define REMODER_DYNAMIC_MIN_FRAME_LENGTH 0x00000004 /* enable
+ dynamic min
+ frame length
+ */
+#define REMODER_IP_CHECKSUM_CHECK 0x00000002 /* check IPv4
+ checksums */
+#define REMODER_IP_ADDRESS_ALIGNMENT 0x00000001 /* align ip
+ address to
+ 4-byte
+ boundary */
+
+/* UCC GETH Event Register */
+#define UCCE_MPD 0x80000000 /* Magic packet
+ detection */
+#define UCCE_SCAR 0x40000000
+#define UCCE_GRA 0x20000000 /* Tx graceful
+ stop
+ complete */
+#define UCCE_CBPR 0x10000000
+#define UCCE_BSY 0x08000000
+#define UCCE_RXC 0x04000000
+#define UCCE_TXC 0x02000000
+#define UCCE_TXE 0x01000000
+#define UCCE_TXB7 0x00800000
+#define UCCE_TXB6 0x00400000
+#define UCCE_TXB5 0x00200000
+#define UCCE_TXB4 0x00100000
+#define UCCE_TXB3 0x00080000
+#define UCCE_TXB2 0x00040000
+#define UCCE_TXB1 0x00020000
+#define UCCE_TXB0 0x00010000
+#define UCCE_RXB7 0x00008000
+#define UCCE_RXB6 0x00004000
+#define UCCE_RXB5 0x00002000
+#define UCCE_RXB4 0x00001000
+#define UCCE_RXB3 0x00000800
+#define UCCE_RXB2 0x00000400
+#define UCCE_RXB1 0x00000200
+#define UCCE_RXB0 0x00000100
+#define UCCE_RXF7 0x00000080
+#define UCCE_RXF6 0x00000040
+#define UCCE_RXF5 0x00000020
+#define UCCE_RXF4 0x00000010
+#define UCCE_RXF3 0x00000008
+#define UCCE_RXF2 0x00000004
+#define UCCE_RXF1 0x00000002
+#define UCCE_RXF0 0x00000001
+
+#define UCCE_RXBF_SINGLE_MASK (UCCE_RXF0)
+#define UCCE_TXBF_SINGLE_MASK (UCCE_TXB0)
+
+#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 |\
+ UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0)
+#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 |\
+ UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0)
+#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 |\
+ UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0)
+#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\
+ UCCE_RXC | UCCE_TXC | UCCE_TXE)
+
+/* UCC GETH UPSMR (Protocol Specific Mode Register) */
+#define UPSMR_ECM 0x04000000 /* Enable CAM
+ Miss or
+ Enable
+ Filtering
+ Miss */
+#define UPSMR_HSE 0x02000000 /* Hardware
+ Statistics
+ Enable */
+#define UPSMR_PRO 0x00400000 /* Promiscuous*/
+#define UPSMR_CAP 0x00200000 /* CAM polarity
+ */
+#define UPSMR_RSH 0x00100000 /* Receive
+ Short Frames
+ */
+#define UPSMR_RPM 0x00080000 /* Reduced Pin
+ Mode
+ interfaces */
+#define UPSMR_R10M 0x00040000 /* RGMII/RMII
+ 10 Mode */
+#define UPSMR_RLPB 0x00020000 /* RMII
+ Loopback
+ Mode */
+#define UPSMR_TBIM 0x00010000 /* Ten-bit
+ Interface
+ Mode */
+#define UPSMR_RMM 0x00001000 /* RMII/RGMII
+ Mode */
+#define UPSMR_CAM 0x00000400 /* CAM Address
+ Matching */
+#define UPSMR_BRO 0x00000200 /* Broadcast
+ Address */
+#define UPSMR_RES1 0x00002000 /* Reserved
+ feild - must
+ be 1 */
+
+/* UCC GETH MACCFG1 (MAC Configuration 1 Register) */
+#define MACCFG1_FLOW_RX 0x00000020 /* Flow Control
+ Rx */
+#define MACCFG1_FLOW_TX 0x00000010 /* Flow Control
+ Tx */
+#define MACCFG1_ENABLE_SYNCHED_RX 0x00000008 /* Rx Enable
+ synchronized
+ to Rx stream
+ */
+#define MACCFG1_ENABLE_RX 0x00000004 /* Enable Rx */
+#define MACCFG1_ENABLE_SYNCHED_TX 0x00000002 /* Tx Enable
+ synchronized
+ to Tx stream
+ */
+#define MACCFG1_ENABLE_TX 0x00000001 /* Enable Tx */
+
+/* UCC GETH MACCFG2 (MAC Configuration 2 Register) */
+#define MACCFG2_PREL_SHIFT (31 - 19) /* Preamble
+ Length <<
+ shift */
+#define MACCFG2_PREL_MASK 0x0000f000 /* Preamble
+ Length mask */
+#define MACCFG2_SRP 0x00000080 /* Soft Receive
+ Preamble */
+#define MACCFG2_STP 0x00000040 /* Soft
+ Transmit
+ Preamble */
+#define MACCFG2_RESERVED_1 0x00000020 /* Reserved -
+ must be set
+ to 1 */
+#define MACCFG2_LC 0x00000010 /* Length Check
+ */
+#define MACCFG2_MPE 0x00000008 /* Magic packet
+ detect */
+#define MACCFG2_FDX 0x00000001 /* Full Duplex */
+#define MACCFG2_FDX_MASK 0x00000001 /* Full Duplex
+ mask */
+#define MACCFG2_PAD_CRC 0x00000004
+#define MACCFG2_CRC_EN 0x00000002
+#define MACCFG2_PAD_AND_CRC_MODE_NONE 0x00000000 /* Neither
+ Padding
+ short frames
+ nor CRC */
+#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY 0x00000002 /* Append CRC
+ only */
+#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC 0x00000004
+#define MACCFG2_INTERFACE_MODE_NIBBLE 0x00000100 /* nibble mode
+ (MII/RMII/RGMII
+ 10/100bps) */
+#define MACCFG2_INTERFACE_MODE_BYTE 0x00000200 /* byte mode
+ (GMII/TBI/RTB/RGMII
+ 1000bps ) */
+#define MACCFG2_INTERFACE_MODE_MASK 0x00000300 /* mask
+ covering all
+ relevant
+ bits */
+
+/* UCC GETH IPGIFG (Inter-frame Gap / Inter-Frame Gap Register) */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_SHIFT (31 - 7) /* Non
+ back-to-back
+ inter frame
+ gap part 1.
+ << shift */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_SHIFT (31 - 15) /* Non
+ back-to-back
+ inter frame
+ gap part 2.
+ << shift */
+#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_SHIFT (31 - 23) /* Mimimum IFG
+ Enforcement
+ << shift */
+#define IPGIFG_BACK_TO_BACK_IFG_SHIFT (31 - 31) /* back-to-back
+ inter frame
+ gap << shift
+ */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART1_MAX 127 /* Non back-to-back
+ inter frame gap part
+ 1. max val */
+#define IPGIFG_NON_BACK_TO_BACK_IFG_PART2_MAX 127 /* Non back-to-back
+ inter frame gap part
+ 2. max val */
+#define IPGIFG_MINIMUM_IFG_ENFORCEMENT_MAX 255 /* Mimimum IFG
+ Enforcement max val */
+#define IPGIFG_BACK_TO_BACK_IFG_MAX 127 /* back-to-back inter
+ frame gap max val */
+#define IPGIFG_NBTB_CS_IPG_MASK 0x7F000000
+#define IPGIFG_NBTB_IPG_MASK 0x007F0000
+#define IPGIFG_MIN_IFG_MASK 0x0000FF00
+#define IPGIFG_BTB_IPG_MASK 0x0000007F
+
+/* UCC GETH HAFDUP (Half Duplex Register) */
+#define HALFDUP_ALT_BEB_TRUNCATION_SHIFT (31 - 11) /* Alternate
+ Binary
+ Exponential
+ Backoff
+ Truncation
+ << shift */
+#define HALFDUP_ALT_BEB_TRUNCATION_MAX 0xf /* Alternate Binary
+ Exponential Backoff
+ Truncation max val */
+#define HALFDUP_ALT_BEB 0x00080000 /* Alternate
+ Binary
+ Exponential
+ Backoff */
+#define HALFDUP_BACK_PRESSURE_NO_BACKOFF 0x00040000 /* Back
+ pressure no
+ backoff */
+#define HALFDUP_NO_BACKOFF 0x00020000 /* No Backoff */
+#define HALFDUP_EXCESSIVE_DEFER 0x00010000 /* Excessive
+ Defer */
+#define HALFDUP_MAX_RETRANSMISSION_SHIFT (31 - 19) /* Maximum
+ Retransmission
+ << shift */
+#define HALFDUP_MAX_RETRANSMISSION_MAX 0xf /* Maximum
+ Retransmission max
+ val */
+#define HALFDUP_COLLISION_WINDOW_SHIFT (31 - 31) /* Collision
+ Window <<
+ shift */
+#define HALFDUP_COLLISION_WINDOW_MAX 0x3f /* Collision Window max
+ val */
+#define HALFDUP_ALT_BEB_TR_MASK 0x00F00000
+#define HALFDUP_RETRANS_MASK 0x0000F000
+#define HALFDUP_COL_WINDOW_MASK 0x0000003F
+
+/* UCC GETH UCCS (Ethernet Status Register) */
+#define UCCS_BPR 0x02 /* Back pressure (in
+ half duplex mode) */
+#define UCCS_PAU 0x02 /* Pause state (in full
+ duplex mode) */
+#define UCCS_MPD 0x01 /* Magic Packet
+ Detected */
+
+/* UCC GETH MIIMCFG (MII Management Configuration Register) */
+#define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset
+ management */
+#define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble
+ suppress */
+#define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide
+ << shift */
+#define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80
+ */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by
+ 112 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by
+ 160 */
+#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by
+ 224 */
+
+/* UCC GETH MIIMCOM (MII Management Command Register) */
+#define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */
+#define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */
+
+/* UCC GETH MIIMADD (MII Management Address Register) */
+#define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address
+ << shift */
+#define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register
+ << shift */
+
+/* UCC GETH MIIMCON (MII Management Control Register) */
+#define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control
+ << shift */
+#define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status
+ << shift */
+
+/* UCC GETH MIIMIND (MII Management Indicator Register) */
+#define MIIMIND_NOT_VALID 0x00000004 /* Not valid */
+#define MIIMIND_SCAN 0x00000002 /* Scan in
+ progress */
+#define MIIMIND_BUSY 0x00000001
+
+/* UCC GETH IFSTAT (Interface Status Register) */
+#define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive
+ transmission
+ defer */
+
+/* UCC GETH MACSTNADDR1 (Station Address Part 1 Register) */
+#define MACSTNADDR1_OCTET_6_SHIFT (31 - 7) /* Station
+ address 6th
+ octet <<
+ shift */
+#define MACSTNADDR1_OCTET_5_SHIFT (31 - 15) /* Station
+ address 5th
+ octet <<
+ shift */
+#define MACSTNADDR1_OCTET_4_SHIFT (31 - 23) /* Station
+ address 4th
+ octet <<
+ shift */
+#define MACSTNADDR1_OCTET_3_SHIFT (31 - 31) /* Station
+ address 3rd
+ octet <<
+ shift */
+
+/* UCC GETH MACSTNADDR2 (Station Address Part 2 Register) */
+#define MACSTNADDR2_OCTET_2_SHIFT (31 - 7) /* Station
+ address 2nd
+ octet <<
+ shift */
+#define MACSTNADDR2_OCTET_1_SHIFT (31 - 15) /* Station
+ address 1st
+ octet <<
+ shift */
+
+/* UCC GETH UEMPR (Ethernet Mac Parameter Register) */
+#define UEMPR_PAUSE_TIME_VALUE_SHIFT (31 - 15) /* Pause time
+ value <<
+ shift */
+#define UEMPR_EXTENDED_PAUSE_TIME_VALUE_SHIFT (31 - 31) /* Extended
+ pause time
+ value <<
+ shift */
+
+/* UCC GETH UTBIPAR (Ten Bit Interface Physical Address Register) */
+#define UTBIPAR_PHY_ADDRESS_SHIFT (31 - 31) /* Phy address
+ << shift */
+#define UTBIPAR_PHY_ADDRESS_MASK 0x0000001f /* Phy address
+ mask */
+
+/* UCC GETH UESCR (Ethernet Statistics Control Register) */
+#define UESCR_AUTOZ 0x8000 /* Automatically zero
+ addressed
+ statistical counter
+ values */
+#define UESCR_CLRCNT 0x4000 /* Clear all statistics
+ counters */
+#define UESCR_MAXCOV_SHIFT (15 - 7) /* Max
+ Coalescing
+ Value <<
+ shift */
+#define UESCR_SCOV_SHIFT (15 - 15) /* Status
+ Coalescing
+ Value <<
+ shift */
+
+/* UCC GETH UDSR (Data Synchronization Register) */
+#define UDSR_MAGIC 0x067E
+
+typedef struct ucc_geth_thread_data_tx {
+ u8 res0[104];
+} __attribute__ ((packed)) ucc_geth_thread_data_tx_t;
+
+typedef struct ucc_geth_thread_data_rx {
+ u8 res0[40];
+} __attribute__ ((packed)) ucc_geth_thread_data_rx_t;
+
+/* Send Queue Queue-Descriptor */
+typedef struct ucc_geth_send_queue_qd {
+ u32 bd_ring_base; /* pointer to BD ring base address */
+ u8 res0[0x8];
+ u32 last_bd_completed_address;/* initialize to last entry in BD ring */
+ u8 res1[0x30];
+} __attribute__ ((packed)) ucc_geth_send_queue_qd_t;
+
+typedef struct ucc_geth_send_queue_mem_region {
+ ucc_geth_send_queue_qd_t sqqd[NUM_TX_QUEUES];
+} __attribute__ ((packed)) ucc_geth_send_queue_mem_region_t;
+
+typedef struct ucc_geth_thread_tx_pram {
+ u8 res0[64];
+} __attribute__ ((packed)) ucc_geth_thread_tx_pram_t;
+
+typedef struct ucc_geth_thread_rx_pram {
+ u8 res0[128];
+} __attribute__ ((packed)) ucc_geth_thread_rx_pram_t;
+
+#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING 64
+#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_8 64
+#define THREAD_RX_PRAM_ADDITIONAL_FOR_EXTENDED_FILTERING_16 96
+
+typedef struct ucc_geth_scheduler {
+ u16 cpucount0; /* CPU packet counter */
+ u16 cpucount1; /* CPU packet counter */
+ u16 cecount0; /* QE packet counter */
+ u16 cecount1; /* QE packet counter */
+ u16 cpucount2; /* CPU packet counter */
+ u16 cpucount3; /* CPU packet counter */
+ u16 cecount2; /* QE packet counter */
+ u16 cecount3; /* QE packet counter */
+ u16 cpucount4; /* CPU packet counter */
+ u16 cpucount5; /* CPU packet counter */
+ u16 cecount4; /* QE packet counter */
+ u16 cecount5; /* QE packet counter */
+ u16 cpucount6; /* CPU packet counter */
+ u16 cpucount7; /* CPU packet counter */
+ u16 cecount6; /* QE packet counter */
+ u16 cecount7; /* QE packet counter */
+ u32 weightstatus[NUM_TX_QUEUES]; /* accumulated weight factor */
+ u32 rtsrshadow; /* temporary variable handled by QE */
+ u32 time; /* temporary variable handled by QE */
+ u32 ttl; /* temporary variable handled by QE */
+ u32 mblinterval; /* max burst length interval */
+ u16 nortsrbytetime; /* normalized value of byte time in tsr units */
+ u8 fracsiz; /* radix 2 log value of denom. of
+ NorTSRByteTime */
+ u8 res0[1];
+ u8 strictpriorityq; /* Strict Priority Mask register */
+ u8 txasap; /* Transmit ASAP register */
+ u8 extrabw; /* Extra BandWidth register */
+ u8 oldwfqmask; /* temporary variable handled by QE */
+ u8 weightfactor[NUM_TX_QUEUES];
+ /**< weight factor for queues */
+ u32 minw; /* temporary variable handled by QE */
+ u8 res1[0x70 - 0x64];
+} __attribute__ ((packed)) ucc_geth_scheduler_t;
+
+typedef struct ucc_geth_tx_firmware_statistics_pram {
+ u32 sicoltx; /* single collision */
+ u32 mulcoltx; /* multiple collision */
+ u32 latecoltxfr; /* late collision */
+ u32 frabortduecol; /* frames aborted due to transmit collision */
+ u32 frlostinmactxer; /* frames lost due to internal MAC error
+ transmission that are not counted on any
+ other counter */
+ u32 carriersenseertx; /* carrier sense error */
+ u32 frtxok; /* frames transmitted OK */
+ u32 txfrexcessivedefer; /* frames with defferal time greater than
+ specified threshold */
+ u32 txpkts256; /* total packets (including bad) between 256
+ and 511 octets */
+ u32 txpkts512; /* total packets (including bad) between 512
+ and 1023 octets */
+ u32 txpkts1024; /* total packets (including bad) between 1024
+ and 1518 octets */
+ u32 txpktsjumbo; /* total packets (including bad) between 1024
+ and MAXLength octets */
+} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_pram_t;
+
+typedef struct ucc_geth_rx_firmware_statistics_pram {
+ u32 frrxfcser; /* frames with crc error */
+ u32 fraligner; /* frames with alignment error */
+ u32 inrangelenrxer; /* in range length error */
+ u32 outrangelenrxer; /* out of range length error */
+ u32 frtoolong; /* frame too long */
+ u32 runt; /* runt */
+ u32 verylongevent; /* very long event */
+ u32 symbolerror; /* symbol error */
+ u32 dropbsy; /* drop because of BD not ready */
+ u8 res0[0x8];
+ u32 mismatchdrop; /* drop because of MAC filtering (e.g. address
+ or type mismatch) */
+ u32 underpkts; /* total frames less than 64 octets */
+ u32 pkts256; /* total frames (including bad) between 256 and
+ 511 octets */
+ u32 pkts512; /* total frames (including bad) between 512 and
+ 1023 octets */
+ u32 pkts1024; /* total frames (including bad) between 1024
+ and 1518 octets */
+ u32 pktsjumbo; /* total frames (including bad) between 1024
+ and MAXLength octets */
+ u32 frlossinmacer; /* frames lost because of internal MAC error
+ that is not counted in any other counter */
+ u32 pausefr; /* pause frames */
+ u8 res1[0x4];
+ u32 removevlan; /* total frames that had their VLAN tag removed
+ */
+ u32 replacevlan; /* total frames that had their VLAN tag
+ replaced */
+ u32 insertvlan; /* total frames that had their VLAN tag
+ inserted */
+} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_pram_t;
+
+typedef struct ucc_geth_rx_interrupt_coalescing_entry {
+ u32 interruptcoalescingmaxvalue; /* interrupt coalescing max
+ value */
+ u32 interruptcoalescingcounter; /* interrupt coalescing counter,
+ initialize to
+ interruptcoalescingmaxvalue */
+} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_entry_t;
+
+typedef struct ucc_geth_rx_interrupt_coalescing_table {
+ ucc_geth_rx_interrupt_coalescing_entry_t coalescingentry[NUM_RX_QUEUES];
+ /**< interrupt coalescing entry */
+} __attribute__ ((packed)) ucc_geth_rx_interrupt_coalescing_table_t;
+
+typedef struct ucc_geth_rx_prefetched_bds {
+ qe_bd_t bd[NUM_BDS_IN_PREFETCHED_BDS]; /* prefetched bd */
+} __attribute__ ((packed)) ucc_geth_rx_prefetched_bds_t;
+
+typedef struct ucc_geth_rx_bd_queues_entry {
+ u32 bdbaseptr; /* BD base pointer */
+ u32 bdptr; /* BD pointer */
+ u32 externalbdbaseptr; /* external BD base pointer */
+ u32 externalbdptr; /* external BD pointer */
+} __attribute__ ((packed)) ucc_geth_rx_bd_queues_entry_t;
+
+typedef struct ucc_geth_tx_global_pram {
+ u16 temoder;
+ u8 res0[0x38 - 0x02];
+ u32 sqptr; /* a base pointer to send queue memory region */
+ u32 schedulerbasepointer; /* a base pointer to scheduler memory
+ region */
+ u32 txrmonbaseptr; /* base pointer to Tx RMON statistics counter */
+ u32 tstate; /* tx internal state. High byte contains
+ function code */
+ u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
+ u32 vtagtable[0x8]; /* 8 4-byte VLAN tags */
+ u32 tqptr; /* a base pointer to the Tx Queues Memory
+ Region */
+ u8 res2[0x80 - 0x74];
+} __attribute__ ((packed)) ucc_geth_tx_global_pram_t;
+
+/* structure representing Extended Filtering Global Parameters in PRAM */
+typedef struct ucc_geth_exf_global_pram {
+ u32 l2pcdptr; /* individual address filter, high */
+ u8 res0[0x10 - 0x04];
+} __attribute__ ((packed)) ucc_geth_exf_global_pram_t;
+
+typedef struct ucc_geth_rx_global_pram {
+ u32 remoder; /* ethernet mode reg. */
+ u32 rqptr; /* base pointer to the Rx Queues Memory Region*/
+ u32 res0[0x1];
+ u8 res1[0x20 - 0xC];
+ u16 typeorlen; /* cutoff point less than which, type/len field
+ is considered length */
+ u8 res2[0x1];
+ u8 rxgstpack; /* acknowledgement on GRACEFUL STOP RX command*/
+ u32 rxrmonbaseptr; /* base pointer to Rx RMON statistics counter */
+ u8 res3[0x30 - 0x28];
+ u32 intcoalescingptr; /* Interrupt coalescing table pointer */
+ u8 res4[0x36 - 0x34];
+ u8 rstate; /* rx internal state. High byte contains
+ function code */
+ u8 res5[0x46 - 0x37];
+ u16 mrblr; /* max receive buffer length reg. */
+ u32 rbdqptr; /* base pointer to RxBD parameter table
+ description */
+ u16 mflr; /* max frame length reg. */
+ u16 minflr; /* min frame length reg. */
+ u16 maxd1; /* max dma1 length reg. */
+ u16 maxd2; /* max dma2 length reg. */
+ u32 ecamptr; /* external CAM address */
+ u32 l2qt; /* VLAN priority mapping table. */
+ u32 l3qt[0x8]; /* IP priority mapping table. */
+ u16 vlantype; /* vlan type */
+ u16 vlantci; /* default vlan tci */
+ u8 addressfiltering[64]; /* address filtering data structure */
+ u32 exfGlobalParam; /* base address for extended filtering global
+ parameters */
+ u8 res6[0x100 - 0xC4]; /* Initialize to zero */
+} __attribute__ ((packed)) ucc_geth_rx_global_pram_t;
+
+#define GRACEFUL_STOP_ACKNOWLEDGE_RX 0x01
+
+/* structure representing InitEnet command */
+typedef struct ucc_geth_init_pram {
+ u8 resinit1;
+ u8 resinit2;
+ u8 resinit3;
+ u8 resinit4;
+ u16 resinit5;
+ u8 res1[0x1];
+ u8 largestexternallookupkeysize;
+ u32 rgftgfrxglobal;
+ u32 rxthread[ENET_INIT_PARAM_MAX_ENTRIES_RX]; /* rx threads */
+ u8 res2[0x38 - 0x30];
+ u32 txglobal; /* tx global */
+ u32 txthread[ENET_INIT_PARAM_MAX_ENTRIES_TX]; /* tx threads */
+ u8 res3[0x1];
+} __attribute__ ((packed)) ucc_geth_init_pram_t;
+
+#define ENET_INIT_PARAM_RGF_SHIFT (32 - 4)
+#define ENET_INIT_PARAM_TGF_SHIFT (32 - 8)
+
+#define ENET_INIT_PARAM_RISC_MASK 0x0000003f
+#define ENET_INIT_PARAM_PTR_MASK 0x00ffffc0
+#define ENET_INIT_PARAM_SNUM_MASK 0xff000000
+#define ENET_INIT_PARAM_SNUM_SHIFT 24
+
+#define ENET_INIT_PARAM_MAGIC_RES_INIT1 0x06
+#define ENET_INIT_PARAM_MAGIC_RES_INIT2 0x30
+#define ENET_INIT_PARAM_MAGIC_RES_INIT3 0xff
+#define ENET_INIT_PARAM_MAGIC_RES_INIT4 0x00
+#define ENET_INIT_PARAM_MAGIC_RES_INIT5 0x0400
+
+/* structure representing 82xx Address Filtering Enet Address in PRAM */
+typedef struct ucc_geth_82xx_enet_address {
+ u8 res1[0x2];
+ u16 h; /* address (MSB) */
+ u16 m; /* address */
+ u16 l; /* address (LSB) */
+} __attribute__ ((packed)) ucc_geth_82xx_enet_address_t;
+
+/* structure representing 82xx Address Filtering PRAM */
+typedef struct ucc_geth_82xx_address_filtering_pram {
+ u32 iaddr_h; /* individual address filter, high */
+ u32 iaddr_l; /* individual address filter, low */
+ u32 gaddr_h; /* group address filter, high */
+ u32 gaddr_l; /* group address filter, low */
+ ucc_geth_82xx_enet_address_t taddr;
+ ucc_geth_82xx_enet_address_t paddr[NUM_OF_PADDRS];
+ u8 res0[0x40 - 0x38];
+} __attribute__ ((packed)) ucc_geth_82xx_address_filtering_pram_t;
+
+/* GETH Tx firmware statistics structure, used when calling
+ UCC_GETH_GetStatistics. */
+typedef struct ucc_geth_tx_firmware_statistics {
+ u32 sicoltx; /* single collision */
+ u32 mulcoltx; /* multiple collision */
+ u32 latecoltxfr; /* late collision */
+ u32 frabortduecol; /* frames aborted due to transmit collision */
+ u32 frlostinmactxer; /* frames lost due to internal MAC error
+ transmission that are not counted on any
+ other counter */
+ u32 carriersenseertx; /* carrier sense error */
+ u32 frtxok; /* frames transmitted OK */
+ u32 txfrexcessivedefer; /* frames with defferal time greater than
+ specified threshold */
+ u32 txpkts256; /* total packets (including bad) between 256
+ and 511 octets */
+ u32 txpkts512; /* total packets (including bad) between 512
+ and 1023 octets */
+ u32 txpkts1024; /* total packets (including bad) between 1024
+ and 1518 octets */
+ u32 txpktsjumbo; /* total packets (including bad) between 1024
+ and MAXLength octets */
+} __attribute__ ((packed)) ucc_geth_tx_firmware_statistics_t;
+
+/* GETH Rx firmware statistics structure, used when calling
+ UCC_GETH_GetStatistics. */
+typedef struct ucc_geth_rx_firmware_statistics {
+ u32 frrxfcser; /* frames with crc error */
+ u32 fraligner; /* frames with alignment error */
+ u32 inrangelenrxer; /* in range length error */
+ u32 outrangelenrxer; /* out of range length error */
+ u32 frtoolong; /* frame too long */
+ u32 runt; /* runt */
+ u32 verylongevent; /* very long event */
+ u32 symbolerror; /* symbol error */
+ u32 dropbsy; /* drop because of BD not ready */
+ u8 res0[0x8];
+ u32 mismatchdrop; /* drop because of MAC filtering (e.g. address
+ or type mismatch) */
+ u32 underpkts; /* total frames less than 64 octets */
+ u32 pkts256; /* total frames (including bad) between 256 and
+ 511 octets */
+ u32 pkts512; /* total frames (including bad) between 512 and
+ 1023 octets */
+ u32 pkts1024; /* total frames (including bad) between 1024
+ and 1518 octets */
+ u32 pktsjumbo; /* total frames (including bad) between 1024
+ and MAXLength octets */
+ u32 frlossinmacer; /* frames lost because of internal MAC error
+ that is not counted in any other counter */
+ u32 pausefr; /* pause frames */
+ u8 res1[0x4];
+ u32 removevlan; /* total frames that had their VLAN tag removed
+ */
+ u32 replacevlan; /* total frames that had their VLAN tag
+ replaced */
+ u32 insertvlan; /* total frames that had their VLAN tag
+ inserted */
+} __attribute__ ((packed)) ucc_geth_rx_firmware_statistics_t;
+
+/* GETH hardware statistics structure, used when calling
+ UCC_GETH_GetStatistics. */
+typedef struct ucc_geth_hardware_statistics {
+ u32 tx64; /* Total number of frames (including bad
+ frames) transmitted that were exactly of the
+ minimal length (64 for un tagged, 68 for
+ tagged, or with length exactly equal to the
+ parameter MINLength */
+ u32 tx127; /* Total number of frames (including bad
+ frames) transmitted that were between
+ MINLength (Including FCS length==4) and 127
+ octets */
+ u32 tx255; /* Total number of frames (including bad
+ frames) transmitted that were between 128
+ (Including FCS length==4) and 255 octets */
+ u32 rx64; /* Total number of frames received including
+ bad frames that were exactly of the mninimal
+ length (64 bytes) */
+ u32 rx127; /* Total number of frames (including bad
+ frames) received that were between MINLength
+ (Including FCS length==4) and 127 octets */
+ u32 rx255; /* Total number of frames (including bad
+ frames) received that were between 128
+ (Including FCS length==4) and 255 octets */
+ u32 txok; /* Total number of octets residing in frames
+ that where involved in succesfull
+ transmission */
+ u16 txcf; /* Total number of PAUSE control frames
+ transmitted by this MAC */
+ u32 tmca; /* Total number of frames that were transmitted
+ succesfully with the group address bit set
+ that are not broadcast frames */
+ u32 tbca; /* Total number of frames transmitted
+ succesfully that had destination address
+ field equal to the broadcast address */
+ u32 rxfok; /* Total number of frames received OK */
+ u32 rxbok; /* Total number of octets received OK */
+ u32 rbyt; /* Total number of octets received including
+ octets in bad frames. Must be implemented in
+ HW because it includes octets in frames that
+ never even reach the UCC */
+ u32 rmca; /* Total number of frames that were received
+ succesfully with the group address bit set
+ that are not broadcast frames */
+ u32 rbca; /* Total number of frames received succesfully
+ that had destination address equal to the
+ broadcast address */
+} __attribute__ ((packed)) ucc_geth_hardware_statistics_t;
+
+/* UCC GETH Tx errors returned via TxConf callback */
+#define TX_ERRORS_DEF 0x0200
+#define TX_ERRORS_EXDEF 0x0100
+#define TX_ERRORS_LC 0x0080
+#define TX_ERRORS_RL 0x0040
+#define TX_ERRORS_RC_MASK 0x003C
+#define TX_ERRORS_RC_SHIFT 2
+#define TX_ERRORS_UN 0x0002
+#define TX_ERRORS_CSL 0x0001
+
+/* UCC GETH Rx errors returned via RxStore callback */
+#define RX_ERRORS_CMR 0x0200
+#define RX_ERRORS_M 0x0100
+#define RX_ERRORS_BC 0x0080
+#define RX_ERRORS_MC 0x0040
+
+/* Transmit BD. These are in addition to values defined in uccf. */
+#define T_VID 0x003c0000 /* insert VLAN id index mask. */
+#define T_DEF (((u32) TX_ERRORS_DEF ) << 16)
+#define T_EXDEF (((u32) TX_ERRORS_EXDEF ) << 16)
+#define T_LC (((u32) TX_ERRORS_LC ) << 16)
+#define T_RL (((u32) TX_ERRORS_RL ) << 16)
+#define T_RC_MASK (((u32) TX_ERRORS_RC_MASK ) << 16)
+#define T_UN (((u32) TX_ERRORS_UN ) << 16)
+#define T_CSL (((u32) TX_ERRORS_CSL ) << 16)
+#define T_ERRORS_REPORT (T_DEF | T_EXDEF | T_LC | T_RL | T_RC_MASK \
+ | T_UN | T_CSL) /* transmit errors to report */
+
+/* Receive BD. These are in addition to values defined in uccf. */
+#define R_LG 0x00200000 /* Frame length violation. */
+#define R_NO 0x00100000 /* Non-octet aligned frame. */
+#define R_SH 0x00080000 /* Short frame. */
+#define R_CR 0x00040000 /* CRC error. */
+#define R_OV 0x00020000 /* Overrun. */
+#define R_IPCH 0x00010000 /* IP checksum check failed. */
+#define R_CMR (((u32) RX_ERRORS_CMR ) << 16)
+#define R_M (((u32) RX_ERRORS_M ) << 16)
+#define R_BC (((u32) RX_ERRORS_BC ) << 16)
+#define R_MC (((u32) RX_ERRORS_MC ) << 16)
+#define R_ERRORS_REPORT (R_CMR | R_M | R_BC | R_MC) /* receive errors to
+ report */
+#define R_ERRORS_FATAL (R_LG | R_NO | R_SH | R_CR | \
+ R_OV | R_IPCH) /* receive errors to discard */
+
+/* Alignments */
+#define UCC_GETH_RX_GLOBAL_PRAM_ALIGNMENT 256
+#define UCC_GETH_TX_GLOBAL_PRAM_ALIGNMENT 128
+#define UCC_GETH_THREAD_RX_PRAM_ALIGNMENT 128
+#define UCC_GETH_THREAD_TX_PRAM_ALIGNMENT 64
+#define UCC_GETH_THREAD_DATA_ALIGNMENT 256 /* spec gives values
+ based on num of
+ threads, but always
+ using the maximum is
+ easier */
+#define UCC_GETH_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT 32
+#define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */
+#define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */
+#define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */
+#define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a
+ guess */
+#define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */
+#define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */
+#define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This
+ is a
+ guess
+ */
+#define UCC_GETH_RX_BD_RING_ALIGNMENT 32
+#define UCC_GETH_TX_BD_RING_ALIGNMENT 32
+#define UCC_GETH_MRBLR_ALIGNMENT 128
+#define UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT 4
+#define UCC_GETH_TX_BD_RING_SIZE_MEMORY_ALIGNMENT 32
+#define UCC_GETH_RX_DATA_BUF_ALIGNMENT 64
+
+#define UCC_GETH_TAD_EF 0x80
+#define UCC_GETH_TAD_V 0x40
+#define UCC_GETH_TAD_REJ 0x20
+#define UCC_GETH_TAD_VTAG_OP_RIGHT_SHIFT 2
+#define UCC_GETH_TAD_VTAG_OP_SHIFT 6
+#define UCC_GETH_TAD_V_NON_VTAG_OP 0x20
+#define UCC_GETH_TAD_RQOS_SHIFT 0
+#define UCC_GETH_TAD_V_PRIORITY_SHIFT 5
+#define UCC_GETH_TAD_CFI 0x10
+
+#define UCC_GETH_VLAN_PRIORITY_MAX 8
+#define UCC_GETH_IP_PRIORITY_MAX 64
+#define UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX 8
+#define UCC_GETH_RX_BD_RING_SIZE_MIN 8
+#define UCC_GETH_TX_BD_RING_SIZE_MIN 2
+
+#define UCC_GETH_SIZE_OF_BD QE_SIZEOF_BD
+
+/* Driver definitions */
+#define TX_BD_RING_LEN 0x10
+#define RX_BD_RING_LEN 0x10
+#define UCC_GETH_DEV_WEIGHT TX_BD_RING_LEN
+
+#define TX_RING_MOD_MASK(size) (size-1)
+#define RX_RING_MOD_MASK(size) (size-1)
+
+#define ENET_NUM_OCTETS_PER_ADDRESS 6
+#define ENET_GROUP_ADDR 0x01 /* Group address mask
+ for ethernet
+ addresses */
+
+#define TX_TIMEOUT (1*HZ)
+#define SKB_ALLOC_TIMEOUT 100000
+#define PHY_INIT_TIMEOUT 100000
+#define PHY_CHANGE_TIME 2
+
+/* Fast Ethernet (10/100 Mbps) */
+#define UCC_GETH_URFS_INIT 512 /* Rx virtual FIFO size
+ */
+#define UCC_GETH_URFET_INIT 256 /* 1/2 urfs */
+#define UCC_GETH_URFSET_INIT 384 /* 3/4 urfs */
+#define UCC_GETH_UTFS_INIT 512 /* Tx virtual FIFO size
+ */
+#define UCC_GETH_UTFET_INIT 256 /* 1/2 utfs */
+#define UCC_GETH_UTFTT_INIT 128
+/* Gigabit Ethernet (1000 Mbps) */
+#define UCC_GETH_URFS_GIGA_INIT 4096/*2048*/ /* Rx virtual
+ FIFO size */
+#define UCC_GETH_URFET_GIGA_INIT 2048/*1024*/ /* 1/2 urfs */
+#define UCC_GETH_URFSET_GIGA_INIT 3072/*1536*/ /* 3/4 urfs */
+#define UCC_GETH_UTFS_GIGA_INIT 8192/*2048*/ /* Tx virtual
+ FIFO size */
+#define UCC_GETH_UTFET_GIGA_INIT 4096/*1024*/ /* 1/2 utfs */
+#define UCC_GETH_UTFTT_GIGA_INIT 0x400/*0x40*/ /* */
+
+#define UCC_GETH_REMODER_INIT 0 /* bits that must be
+ set */
+#define UCC_GETH_TEMODER_INIT 0xC000 /* bits that must */
+#define UCC_GETH_UPSMR_INIT (UPSMR_RES1) /* Start value
+ for this
+ register */
+#define UCC_GETH_MACCFG1_INIT 0
+#define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1)
+#define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \
+ (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112)
+
+/* Ethernet speed */
+typedef enum enet_speed {
+ ENET_SPEED_10BT, /* 10 Base T */
+ ENET_SPEED_100BT, /* 100 Base T */
+ ENET_SPEED_1000BT /* 1000 Base T */
+} enet_speed_e;
+
+/* Ethernet Address Type. */
+typedef enum enet_addr_type {
+ ENET_ADDR_TYPE_INDIVIDUAL,
+ ENET_ADDR_TYPE_GROUP,
+ ENET_ADDR_TYPE_BROADCAST
+} enet_addr_type_e;
+
+/* TBI / MII Set Register */
+typedef enum enet_tbi_mii_reg {
+ ENET_TBI_MII_CR = 0x00, /* Control (CR ) */
+ ENET_TBI_MII_SR = 0x01, /* Status (SR ) */
+ ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */
+ ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability
+ (ANLPBPA) */
+ ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */
+ ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */
+ ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page
+ (ANLPANP) */
+ ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */
+ ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */
+ ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */
+} enet_tbi_mii_reg_e;
+
+/* UCC GETH 82xx Ethernet Address Recognition Location */
+typedef enum ucc_geth_enet_address_recognition_location {
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station
+ address */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_FIRST, /* additional
+ station
+ address
+ paddr1 */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR2, /* additional
+ station
+ address
+ paddr2 */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR3, /* additional
+ station
+ address
+ paddr3 */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_PADDR_LAST, /* additional
+ station
+ address
+ paddr4 */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH, /* group hash */
+ UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH /* individual
+ hash */
+} ucc_geth_enet_address_recognition_location_e;
+
+/* UCC GETH vlan operation tagged */
+typedef enum ucc_geth_vlan_operation_tagged {
+ UCC_GETH_VLAN_OPERATION_TAGGED_NOP = 0x0, /* Tagged - nop */
+ UCC_GETH_VLAN_OPERATION_TAGGED_REPLACE_VID_PORTION_OF_Q_TAG
+ = 0x1, /* Tagged - replace vid portion of q tag */
+ UCC_GETH_VLAN_OPERATION_TAGGED_IF_VID0_REPLACE_VID_WITH_DEFAULT_VALUE
+ = 0x2, /* Tagged - if vid0 replace vid with default value */
+ UCC_GETH_VLAN_OPERATION_TAGGED_EXTRACT_Q_TAG_FROM_FRAME
+ = 0x3 /* Tagged - extract q tag from frame */
+} ucc_geth_vlan_operation_tagged_e;
+
+/* UCC GETH vlan operation non-tagged */
+typedef enum ucc_geth_vlan_operation_non_tagged {
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP = 0x0, /* Non tagged - nop */
+ UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT = 0x1 /* Non tagged -
+ q tag insert
+ */
+} ucc_geth_vlan_operation_non_tagged_e;
+
+/* UCC GETH Rx Quality of Service Mode */
+typedef enum ucc_geth_qos_mode {
+ UCC_GETH_QOS_MODE_DEFAULT = 0x0, /* default queue */
+ UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L2_CRITERIA = 0x1, /* queue
+ determined
+ by L2
+ criteria */
+ UCC_GETH_QOS_MODE_QUEUE_NUM_FROM_L3_CRITERIA = 0x2 /* queue
+ determined
+ by L3
+ criteria */
+} ucc_geth_qos_mode_e;
+
+/* UCC GETH Statistics Gathering Mode - These are bit flags, 'or' them together
+ for combined functionality */
+typedef enum ucc_geth_statistics_gathering_mode {
+ UCC_GETH_STATISTICS_GATHERING_MODE_NONE = 0x00000000, /* No
+ statistics
+ gathering */
+ UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE = 0x00000001,/* Enable
+ hardware
+ statistics
+ gathering
+ */
+ UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX = 0x00000004,/*Enable
+ firmware
+ tx
+ statistics
+ gathering
+ */
+ UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX = 0x00000008/* Enable
+ firmware
+ rx
+ statistics
+ gathering
+ */
+} ucc_geth_statistics_gathering_mode_e;
+
+/* UCC GETH Pad and CRC Mode - Note, Padding without CRC is not possible */
+typedef enum ucc_geth_maccfg2_pad_and_crc_mode {
+ UCC_GETH_PAD_AND_CRC_MODE_NONE
+ = MACCFG2_PAD_AND_CRC_MODE_NONE, /* Neither Padding
+ short frames
+ nor CRC */
+ UCC_GETH_PAD_AND_CRC_MODE_CRC_ONLY
+ = MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY, /* Append
+ CRC only */
+ UCC_GETH_PAD_AND_CRC_MODE_PAD_AND_CRC =
+ MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC
+} ucc_geth_maccfg2_pad_and_crc_mode_e;
+
+/* UCC GETH upsmr Flow Control Mode */
+typedef enum ucc_geth_flow_control_mode {
+ UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_NONE = 0x00000000, /* No automatic
+ flow control
+ */
+ UPSMR_AUTOMATIC_FLOW_CONTROL_MODE_PAUSE_WHEN_EMERGENCY
+ = 0x00004000 /* Send pause frame when RxFIFO reaches its
+ emergency threshold */
+} ucc_geth_flow_control_mode_e;
+
+/* UCC GETH number of threads */
+typedef enum ucc_geth_num_of_threads {
+ UCC_GETH_NUM_OF_THREADS_1 = 0x1, /* 1 */
+ UCC_GETH_NUM_OF_THREADS_2 = 0x2, /* 2 */
+ UCC_GETH_NUM_OF_THREADS_4 = 0x0, /* 4 */
+ UCC_GETH_NUM_OF_THREADS_6 = 0x3, /* 6 */
+ UCC_GETH_NUM_OF_THREADS_8 = 0x4 /* 8 */
+} ucc_geth_num_of_threads_e;
+
+/* UCC GETH number of station addresses */
+typedef enum ucc_geth_num_of_station_addresses {
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_1, /* 1 */
+ UCC_GETH_NUM_OF_STATION_ADDRESSES_5 /* 5 */
+} ucc_geth_num_of_station_addresses_e;
+
+typedef u8 enet_addr_t[ENET_NUM_OCTETS_PER_ADDRESS];
+
+/* UCC GETH 82xx Ethernet Address Container */
+typedef struct enet_addr_container {
+ enet_addr_t address; /* ethernet address */
+ ucc_geth_enet_address_recognition_location_e location; /* location in
+ 82xx address
+ recognition
+ hardware */
+ struct list_head node;
+} enet_addr_container_t;
+
+#define ENET_ADDR_CONT_ENTRY(ptr) list_entry(ptr, enet_addr_container_t, node)
+
+/* UCC GETH Termination Action Descriptor (TAD) structure. */
+typedef struct ucc_geth_tad_params {
+ int rx_non_dynamic_extended_features_mode;
+ int reject_frame;
+ ucc_geth_vlan_operation_tagged_e vtag_op;
+ ucc_geth_vlan_operation_non_tagged_e vnontag_op;
+ ucc_geth_qos_mode_e rqos;
+ u8 vpri;
+ u16 vid;
+} ucc_geth_tad_params_t;
+
+/* GETH protocol initialization structure */
+typedef struct ucc_geth_info {
+ ucc_fast_info_t uf_info;
+ u8 numQueuesTx;
+ u8 numQueuesRx;
+ int ipCheckSumCheck;
+ int ipCheckSumGenerate;
+ int rxExtendedFiltering;
+ u32 extendedFilteringChainPointer;
+ u16 typeorlen;
+ int dynamicMaxFrameLength;
+ int dynamicMinFrameLength;
+ u8 nonBackToBackIfgPart1;
+ u8 nonBackToBackIfgPart2;
+ u8 miminumInterFrameGapEnforcement;
+ u8 backToBackInterFrameGap;
+ int ipAddressAlignment;
+ int lengthCheckRx;
+ u32 mblinterval;
+ u16 nortsrbytetime;
+ u8 fracsiz;
+ u8 strictpriorityq;
+ u8 txasap;
+ u8 extrabw;
+ int miiPreambleSupress;
+ u8 altBebTruncation;
+ int altBeb;
+ int backPressureNoBackoff;
+ int noBackoff;
+ int excessDefer;
+ u8 maxRetransmission;
+ u8 collisionWindow;
+ int pro;
+ int cap;
+ int rsh;
+ int rlpb;
+ int cam;
+ int bro;
+ int ecm;
+ int receiveFlowControl;
+ u8 maxGroupAddrInHash;
+ u8 maxIndAddrInHash;
+ u8 prel;
+ u16 maxFrameLength;
+ u16 minFrameLength;
+ u16 maxD1Length;
+ u16 maxD2Length;
+ u16 vlantype;
+ u16 vlantci;
+ u32 ecamptr;
+ u32 eventRegMask;
+ u16 pausePeriod;
+ u16 extensionField;
+ u8 phy_address;
+ u32 board_flags;
+ u32 phy_interrupt;
+ u8 weightfactor[NUM_TX_QUEUES];
+ u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
+ u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
+ u8 l3qt[UCC_GETH_IP_PRIORITY_MAX];
+ u32 vtagtable[UCC_GETH_TX_VTAG_TABLE_ENTRY_MAX];
+ u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX];
+ u16 bdRingLenTx[NUM_TX_QUEUES];
+ u16 bdRingLenRx[NUM_RX_QUEUES];
+ enet_interface_e enet_interface;
+ ucc_geth_num_of_station_addresses_e numStationAddresses;
+ qe_fltr_largest_external_tbl_lookup_key_size_e
+ largestexternallookupkeysize;
+ ucc_geth_statistics_gathering_mode_e statisticsMode;
+ ucc_geth_vlan_operation_tagged_e vlanOperationTagged;
+ ucc_geth_vlan_operation_non_tagged_e vlanOperationNonTagged;
+ ucc_geth_qos_mode_e rxQoSMode;
+ ucc_geth_flow_control_mode_e aufc;
+ ucc_geth_maccfg2_pad_and_crc_mode_e padAndCrc;
+ ucc_geth_num_of_threads_e numThreadsTx;
+ ucc_geth_num_of_threads_e numThreadsRx;
+ qe_risc_allocation_e riscTx;
+ qe_risc_allocation_e riscRx;
+} ucc_geth_info_t;
+
+/* structure representing UCC GETH */
+typedef struct ucc_geth_private {
+ ucc_geth_info_t *ug_info;
+ ucc_fast_private_t *uccf;
+ struct net_device *dev;
+ struct net_device_stats stats; /* linux network statistics */
+ ucc_geth_t *ug_regs;
+ ucc_geth_init_pram_t *p_init_enet_param_shadow;
+ ucc_geth_exf_global_pram_t *p_exf_glbl_param;
+ u32 exf_glbl_param_offset;
+ ucc_geth_rx_global_pram_t *p_rx_glbl_pram;
+ u32 rx_glbl_pram_offset;
+ ucc_geth_tx_global_pram_t *p_tx_glbl_pram;
+ u32 tx_glbl_pram_offset;
+ ucc_geth_send_queue_mem_region_t *p_send_q_mem_reg;
+ u32 send_q_mem_reg_offset;
+ ucc_geth_thread_data_tx_t *p_thread_data_tx;
+ u32 thread_dat_tx_offset;
+ ucc_geth_thread_data_rx_t *p_thread_data_rx;
+ u32 thread_dat_rx_offset;
+ ucc_geth_scheduler_t *p_scheduler;
+ u32 scheduler_offset;
+ ucc_geth_tx_firmware_statistics_pram_t *p_tx_fw_statistics_pram;
+ u32 tx_fw_statistics_pram_offset;
+ ucc_geth_rx_firmware_statistics_pram_t *p_rx_fw_statistics_pram;
+ u32 rx_fw_statistics_pram_offset;
+ ucc_geth_rx_interrupt_coalescing_table_t *p_rx_irq_coalescing_tbl;
+ u32 rx_irq_coalescing_tbl_offset;
+ ucc_geth_rx_bd_queues_entry_t *p_rx_bd_qs_tbl;
+ u32 rx_bd_qs_tbl_offset;
+ u8 *p_tx_bd_ring[NUM_TX_QUEUES];
+ u32 tx_bd_ring_offset[NUM_TX_QUEUES];
+ u8 *p_rx_bd_ring[NUM_RX_QUEUES];
+ u32 rx_bd_ring_offset[NUM_RX_QUEUES];
+ u8 *confBd[NUM_TX_QUEUES];
+ u8 *txBd[NUM_TX_QUEUES];
+ u8 *rxBd[NUM_RX_QUEUES];
+ int badFrame[NUM_RX_QUEUES];
+ u16 cpucount[NUM_TX_QUEUES];
+ volatile u16 *p_cpucount[NUM_TX_QUEUES];
+ int indAddrRegUsed[NUM_OF_PADDRS];
+ enet_addr_t paddr[NUM_OF_PADDRS];
+ u8 numGroupAddrInHash;
+ u8 numIndAddrInHash;
+ u8 numIndAddrInReg;
+ int rx_extended_features;
+ int rx_non_dynamic_extended_features;
+ struct list_head conf_skbs;
+ struct list_head group_hash_q;
+ struct list_head ind_hash_q;
+ u32 saved_uccm;
+ spinlock_t lock;
+ /* pointers to arrays of skbuffs for tx and rx */
+ struct sk_buff **tx_skbuff[NUM_TX_QUEUES];
+ struct sk_buff **rx_skbuff[NUM_RX_QUEUES];
+ /* indices pointing to the next free sbk in skb arrays */
+ u16 skb_curtx[NUM_TX_QUEUES];
+ u16 skb_currx[NUM_RX_QUEUES];
+ /* index of the first skb which hasn't been transmitted yet. */
+ u16 skb_dirtytx[NUM_TX_QUEUES];
+
+ struct work_struct tq;
+ struct timer_list phy_info_timer;
+ struct ugeth_mii_info *mii_info;
+ int oldspeed;
+ int oldduplex;
+ int oldlink;
+} ucc_geth_private_t;
+
+#endif /* __UCC_GETH_H__ */
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
new file mode 100644
index 00000000000..f91028c5386
--- /dev/null
+++ b/drivers/net/ucc_geth_phy.c
@@ -0,0 +1,801 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * UCC GETH Driver -- PHY handling
+ *
+ * Changelog:
+ * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
+ * - Rearrange code and style fixes
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+
+#include "ucc_geth.h"
+#include "ucc_geth_phy.h"
+#include <platforms/83xx/mpc8360e_pb.h>
+
+#define ugphy_printk(level, format, arg...) \
+ printk(level format "\n", ## arg)
+
+#define ugphy_dbg(format, arg...) \
+ ugphy_printk(KERN_DEBUG, format , ## arg)
+#define ugphy_err(format, arg...) \
+ ugphy_printk(KERN_ERR, format , ## arg)
+#define ugphy_info(format, arg...) \
+ ugphy_printk(KERN_INFO, format , ## arg)
+#define ugphy_warn(format, arg...) \
+ ugphy_printk(KERN_WARNING, format , ## arg)
+
+#ifdef UGETH_VERBOSE_DEBUG
+#define ugphy_vdbg ugphy_dbg
+#else
+#define ugphy_vdbg(fmt, args...) do { } while (0)
+#endif /* UGETH_VERBOSE_DEBUG */
+
+static void config_genmii_advert(struct ugeth_mii_info *mii_info);
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_update_link(struct ugeth_mii_info *mii_info);
+static int genmii_read_status(struct ugeth_mii_info *mii_info);
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
+void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val);
+
+static u8 *bcsr_regs = NULL;
+
+/* Write value to the PHY for this device to the register at regnum, */
+/* waiting until the write is done before it returns. All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ ucc_mii_mng_t *mii_regs;
+ enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+ u32 tmp_reg;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irq(&ugeth->lock);
+
+ mii_regs = ugeth->mii_info->mii_regs;
+
+ /* Set this UCC to be the master of the MII managment */
+ ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num);
+
+ /* Stop the MII management read cycle */
+ out_be32(&mii_regs->miimcom, 0);
+ /* Setting up the MII Mangement Address Register */
+ tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+ out_be32(&mii_regs->miimadd, tmp_reg);
+
+ /* Setting up the MII Mangement Control Register with the value */
+ out_be32(&mii_regs->miimcon, (u32) value);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
+ cpu_relax();
+
+ spin_unlock_irq(&ugeth->lock);
+
+ udelay(10000);
+}
+
+/* Reads from register regnum in the PHY for device dev, */
+/* returning the value. Clears miimcom first. All PHY */
+/* configuration has to be done through the TSEC1 MIIM regs */
+int read_phy_reg(struct net_device *dev, int mii_id, int regnum)
+{
+ ucc_geth_private_t *ugeth = netdev_priv(dev);
+ ucc_mii_mng_t *mii_regs;
+ enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+ u32 tmp_reg;
+ u16 value;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irq(&ugeth->lock);
+
+ mii_regs = ugeth->mii_info->mii_regs;
+
+ /* Setting up the MII Mangement Address Register */
+ tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg;
+ out_be32(&mii_regs->miimadd, tmp_reg);
+
+ /* Perform an MII management read cycle */
+ out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE);
+
+ /* Wait till MII management write is complete */
+ while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY)
+ cpu_relax();
+
+ udelay(10000);
+
+ /* Read MII management status */
+ value = (u16) in_be32(&mii_regs->miimstat);
+ out_be32(&mii_regs->miimcom, 0);
+ if (value == 0xffff)
+ ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x",
+ mii_id, mii_reg, (u32) & (mii_regs->miimcfg));
+
+ spin_unlock_irq(&ugeth->lock);
+
+ return (value);
+}
+
+void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->phyinfo->ack_interrupt)
+ mii_info->phyinfo->ack_interrupt(mii_info);
+}
+
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+ u32 interrupts)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ mii_info->interrupts = interrupts;
+ if (mii_info->phyinfo->config_intr)
+ mii_info->phyinfo->config_intr(mii_info);
+}
+
+/* Writes MII_ADVERTISE with the appropriate values, after
+ * sanitizing advertise to make sure only supported features
+ * are advertised
+ */
+static void config_genmii_advert(struct ugeth_mii_info *mii_info)
+{
+ u32 advertise;
+ u16 adv;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Only allow advertising what this PHY supports */
+ mii_info->advertising &= mii_info->phyinfo->features;
+ advertise = mii_info->advertising;
+
+ /* Setup standard advertisement */
+ adv = phy_read(mii_info, MII_ADVERTISE);
+ adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+ if (advertise & ADVERTISED_10baseT_Half)
+ adv |= ADVERTISE_10HALF;
+ if (advertise & ADVERTISED_10baseT_Full)
+ adv |= ADVERTISE_10FULL;
+ if (advertise & ADVERTISED_100baseT_Half)
+ adv |= ADVERTISE_100HALF;
+ if (advertise & ADVERTISED_100baseT_Full)
+ adv |= ADVERTISE_100FULL;
+ phy_write(mii_info, MII_ADVERTISE, adv);
+}
+
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info)
+{
+ u16 ctrl;
+ u32 features = mii_info->phyinfo->features;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ ctrl = phy_read(mii_info, MII_BMCR);
+
+ ctrl &=
+ ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+ ctrl |= BMCR_RESET;
+
+ switch (mii_info->speed) {
+ case SPEED_1000:
+ if (features & (SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full)) {
+ ctrl |= BMCR_SPEED1000;
+ break;
+ }
+ mii_info->speed = SPEED_100;
+ case SPEED_100:
+ if (features & (SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full)) {
+ ctrl |= BMCR_SPEED100;
+ break;
+ }
+ mii_info->speed = SPEED_10;
+ case SPEED_10:
+ if (features & (SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full))
+ break;
+ default: /* Unsupported speed! */
+ ugphy_err("%s: Bad speed!", mii_info->dev->name);
+ break;
+ }
+
+ phy_write(mii_info, MII_BMCR, ctrl);
+}
+
+/* Enable and Restart Autonegotiation */
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info)
+{
+ u16 ctl;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ ctl = phy_read(mii_info, MII_BMCR);
+ ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+ phy_write(mii_info, MII_BMCR, ctl);
+}
+
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info)
+{
+ u16 adv;
+ u32 advertise;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->autoneg) {
+ /* Configure the ADVERTISE register */
+ config_genmii_advert(mii_info);
+ advertise = mii_info->advertising;
+
+ adv = phy_read(mii_info, MII_1000BASETCONTROL);
+ adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
+ MII_1000BASETCONTROL_HALFDUPLEXCAP);
+ if (advertise & SUPPORTED_1000baseT_Half)
+ adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
+ if (advertise & SUPPORTED_1000baseT_Full)
+ adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
+ phy_write(mii_info, MII_1000BASETCONTROL, adv);
+
+ /* Start/Restart aneg */
+ genmii_restart_aneg(mii_info);
+ } else
+ genmii_setup_forced(mii_info);
+
+ return 0;
+}
+
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->autoneg) {
+ config_genmii_advert(mii_info);
+ genmii_restart_aneg(mii_info);
+ } else
+ genmii_setup_forced(mii_info);
+
+ return 0;
+}
+
+static int genmii_update_link(struct ugeth_mii_info *mii_info)
+{
+ u16 status;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Do a fake read */
+ phy_read(mii_info, MII_BMSR);
+
+ /* Read link and autonegotiation status */
+ status = phy_read(mii_info, MII_BMSR);
+ if ((status & BMSR_LSTATUS) == 0)
+ mii_info->link = 0;
+ else
+ mii_info->link = 1;
+
+ /* If we are autonegotiating, and not done,
+ * return an error */
+ if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int genmii_read_status(struct ugeth_mii_info *mii_info)
+{
+ u16 status;
+ int err;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Update the link, but return if there
+ * was an error */
+ err = genmii_update_link(mii_info);
+ if (err)
+ return err;
+
+ if (mii_info->autoneg) {
+ status = phy_read(mii_info, MII_LPA);
+
+ if (status & (LPA_10FULL | LPA_100FULL))
+ mii_info->duplex = DUPLEX_FULL;
+ else
+ mii_info->duplex = DUPLEX_HALF;
+ if (status & (LPA_100FULL | LPA_100HALF))
+ mii_info->speed = SPEED_100;
+ else
+ mii_info->speed = SPEED_10;
+ mii_info->pause = 0;
+ }
+ /* On non-aneg, we assume what we put in BMCR is the speed,
+ * though magic-aneg shouldn't prevent this case from occurring
+ */
+
+ return 0;
+}
+
+static int marvell_init(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ phy_write(mii_info, 0x14, 0x0cd2);
+ phy_write(mii_info, MII_BMCR,
+ phy_read(mii_info, MII_BMCR) | BMCR_RESET);
+ msleep(4000);
+
+ return 0;
+}
+
+static int marvell_config_aneg(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* The Marvell PHY has an errata which requires
+ * that certain registers get written in order
+ * to restart autonegotiation */
+ phy_write(mii_info, MII_BMCR, BMCR_RESET);
+
+ phy_write(mii_info, 0x1d, 0x1f);
+ phy_write(mii_info, 0x1e, 0x200c);
+ phy_write(mii_info, 0x1d, 0x5);
+ phy_write(mii_info, 0x1e, 0);
+ phy_write(mii_info, 0x1e, 0x100);
+
+ gbit_config_aneg(mii_info);
+
+ return 0;
+}
+
+static int marvell_read_status(struct ugeth_mii_info *mii_info)
+{
+ u16 status;
+ int err;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Update the link, but return if there
+ * was an error */
+ err = genmii_update_link(mii_info);
+ if (err)
+ return err;
+
+ /* If the link is up, read the speed and duplex */
+ /* If we aren't autonegotiating, assume speeds
+ * are as set */
+ if (mii_info->autoneg && mii_info->link) {
+ int speed;
+ status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS);
+
+ /* Get the duplexity */
+ if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
+ mii_info->duplex = DUPLEX_FULL;
+ else
+ mii_info->duplex = DUPLEX_HALF;
+
+ /* Get the speed */
+ speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK;
+ switch (speed) {
+ case MII_M1011_PHY_SPEC_STATUS_1000:
+ mii_info->speed = SPEED_1000;
+ break;
+ case MII_M1011_PHY_SPEC_STATUS_100:
+ mii_info->speed = SPEED_100;
+ break;
+ default:
+ mii_info->speed = SPEED_10;
+ break;
+ }
+ mii_info->pause = 0;
+ }
+
+ return 0;
+}
+
+static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Clear the interrupts by reading the reg */
+ phy_read(mii_info, MII_M1011_IEVENT);
+
+ return 0;
+}
+
+static int marvell_config_intr(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
+ phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
+ else
+ phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
+
+ return 0;
+}
+
+static int cis820x_init(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ phy_write(mii_info, MII_CIS8201_AUX_CONSTAT,
+ MII_CIS8201_AUXCONSTAT_INIT);
+ phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT);
+
+ return 0;
+}
+
+static int cis820x_read_status(struct ugeth_mii_info *mii_info)
+{
+ u16 status;
+ int err;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Update the link, but return if there
+ * was an error */
+ err = genmii_update_link(mii_info);
+ if (err)
+ return err;
+
+ /* If the link is up, read the speed and duplex */
+ /* If we aren't autonegotiating, assume speeds
+ * are as set */
+ if (mii_info->autoneg && mii_info->link) {
+ int speed;
+
+ status = phy_read(mii_info, MII_CIS8201_AUX_CONSTAT);
+ if (status & MII_CIS8201_AUXCONSTAT_DUPLEX)
+ mii_info->duplex = DUPLEX_FULL;
+ else
+ mii_info->duplex = DUPLEX_HALF;
+
+ speed = status & MII_CIS8201_AUXCONSTAT_SPEED;
+
+ switch (speed) {
+ case MII_CIS8201_AUXCONSTAT_GBIT:
+ mii_info->speed = SPEED_1000;
+ break;
+ case MII_CIS8201_AUXCONSTAT_100:
+ mii_info->speed = SPEED_100;
+ break;
+ default:
+ mii_info->speed = SPEED_10;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ phy_read(mii_info, MII_CIS8201_ISTAT);
+
+ return 0;
+}
+
+static int cis820x_config_intr(struct ugeth_mii_info *mii_info)
+{
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
+ phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK);
+ else
+ phy_write(mii_info, MII_CIS8201_IMASK, 0);
+
+ return 0;
+}
+
+#define DM9161_DELAY 10
+
+static int dm9161_read_status(struct ugeth_mii_info *mii_info)
+{
+ u16 status;
+ int err;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Update the link, but return if there
+ * was an error */
+ err = genmii_update_link(mii_info);
+ if (err)
+ return err;
+
+ /* If the link is up, read the speed and duplex */
+ /* If we aren't autonegotiating, assume speeds
+ * are as set */
+ if (mii_info->autoneg && mii_info->link) {
+ status = phy_read(mii_info, MII_DM9161_SCSR);
+ if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H))
+ mii_info->speed = SPEED_100;
+ else
+ mii_info->speed = SPEED_10;
+
+ if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F))
+ mii_info->duplex = DUPLEX_FULL;
+ else
+ mii_info->duplex = DUPLEX_HALF;
+ }
+
+ return 0;
+}
+
+static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
+{
+ struct dm9161_private *priv = mii_info->priv;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (0 == priv->resetdone)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static void dm9161_timer(unsigned long data)
+{
+ struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data;
+ struct dm9161_private *priv = mii_info->priv;
+ u16 status = phy_read(mii_info, MII_BMSR);
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (status & BMSR_ANEGCOMPLETE) {
+ priv->resetdone = 1;
+ } else
+ mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
+}
+
+static int dm9161_init(struct ugeth_mii_info *mii_info)
+{
+ struct dm9161_private *priv;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Allocate the private data structure */
+ priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL);
+
+ if (NULL == priv)
+ return -ENOMEM;
+
+ mii_info->priv = priv;
+
+ /* Reset is not done yet */
+ priv->resetdone = 0;
+
+ phy_write(mii_info, MII_BMCR,
+ phy_read(mii_info, MII_BMCR) | BMCR_RESET);
+
+ phy_write(mii_info, MII_BMCR,
+ phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE);
+
+ config_genmii_advert(mii_info);
+ /* Start/Restart aneg */
+ genmii_config_aneg(mii_info);
+
+ /* Start a timer for DM9161_DELAY seconds to wait
+ * for the PHY to be ready */
+ init_timer(&priv->timer);
+ priv->timer.function = &dm9161_timer;
+ priv->timer.data = (unsigned long)mii_info;
+ mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ);
+
+ return 0;
+}
+
+static void dm9161_close(struct ugeth_mii_info *mii_info)
+{
+ struct dm9161_private *priv = mii_info->priv;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ del_timer_sync(&priv->timer);
+ kfree(priv);
+}
+
+static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info)
+{
+/* FIXME: This lines are for BUG fixing in the mpc8325.
+Remove this from here when it's fixed */
+ if (bcsr_regs == NULL)
+ bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+ bcsr_regs[14] |= 0x40;
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Clear the interrupts by reading the reg */
+ phy_read(mii_info, MII_DM9161_INTR);
+
+
+ return 0;
+}
+
+static int dm9161_config_intr(struct ugeth_mii_info *mii_info)
+{
+/* FIXME: This lines are for BUG fixing in the mpc8325.
+Remove this from here when it's fixed */
+ if (bcsr_regs == NULL) {
+ bcsr_regs = (u8 *) ioremap(BCSR_PHYS_ADDR, BCSR_SIZE);
+ bcsr_regs[14] &= ~0x40;
+ }
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ if (mii_info->interrupts == MII_INTERRUPT_ENABLED)
+ phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT);
+ else
+ phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP);
+
+ return 0;
+}
+
+/* Cicada 820x */
+static struct phy_info phy_info_cis820x = {
+ .phy_id = 0x000fc440,
+ .name = "Cicada Cis8204",
+ .phy_id_mask = 0x000fffc0,
+ .features = MII_GBIT_FEATURES,
+ .init = &cis820x_init,
+ .config_aneg = &gbit_config_aneg,
+ .read_status = &cis820x_read_status,
+ .ack_interrupt = &cis820x_ack_interrupt,
+ .config_intr = &cis820x_config_intr,
+};
+
+static struct phy_info phy_info_dm9161 = {
+ .phy_id = 0x0181b880,
+ .phy_id_mask = 0x0ffffff0,
+ .name = "Davicom DM9161E",
+ .init = dm9161_init,
+ .config_aneg = dm9161_config_aneg,
+ .read_status = dm9161_read_status,
+ .close = dm9161_close,
+};
+
+static struct phy_info phy_info_dm9161a = {
+ .phy_id = 0x0181b8a0,
+ .phy_id_mask = 0x0ffffff0,
+ .name = "Davicom DM9161A",
+ .features = MII_BASIC_FEATURES,
+ .init = dm9161_init,
+ .config_aneg = dm9161_config_aneg,
+ .read_status = dm9161_read_status,
+ .ack_interrupt = dm9161_ack_interrupt,
+ .config_intr = dm9161_config_intr,
+ .close = dm9161_close,
+};
+
+static struct phy_info phy_info_marvell = {
+ .phy_id = 0x01410c00,
+ .phy_id_mask = 0xffffff00,
+ .name = "Marvell 88E11x1",
+ .features = MII_GBIT_FEATURES,
+ .init = &marvell_init,
+ .config_aneg = &marvell_config_aneg,
+ .read_status = &marvell_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+};
+
+static struct phy_info phy_info_genmii = {
+ .phy_id = 0x00000000,
+ .phy_id_mask = 0x00000000,
+ .name = "Generic MII",
+ .features = MII_BASIC_FEATURES,
+ .config_aneg = genmii_config_aneg,
+ .read_status = genmii_read_status,
+};
+
+static struct phy_info *phy_info[] = {
+ &phy_info_cis820x,
+ &phy_info_marvell,
+ &phy_info_dm9161,
+ &phy_info_dm9161a,
+ &phy_info_genmii,
+ NULL
+};
+
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum)
+{
+ u16 retval;
+ unsigned long flags;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irqsave(&mii_info->mdio_lock, flags);
+ retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum);
+ spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
+
+ return retval;
+}
+
+void phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val)
+{
+ unsigned long flags;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ spin_lock_irqsave(&mii_info->mdio_lock, flags);
+ mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val);
+ spin_unlock_irqrestore(&mii_info->mdio_lock, flags);
+}
+
+/* Use the PHY ID registers to determine what type of PHY is attached
+ * to device dev. return a struct phy_info structure describing that PHY
+ */
+struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info)
+{
+ u16 phy_reg;
+ u32 phy_ID;
+ int i;
+ struct phy_info *theInfo = NULL;
+ struct net_device *dev = mii_info->dev;
+
+ ugphy_vdbg("%s: IN", __FUNCTION__);
+
+ /* Grab the bits from PHYIR1, and put them in the upper half */
+ phy_reg = phy_read(mii_info, MII_PHYSID1);
+ phy_ID = (phy_reg & 0xffff) << 16;
+
+ /* Grab the bits from PHYIR2, and put them in the lower half */
+ phy_reg = phy_read(mii_info, MII_PHYSID2);
+ phy_ID |= (phy_reg & 0xffff);
+
+ /* loop through all the known PHY types, and find one that */
+ /* matches the ID we read from the PHY. */
+ for (i = 0; phy_info[i]; i++)
+ if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){
+ theInfo = phy_info[i];
+ break;
+ }
+
+ /* This shouldn't happen, as we have generic PHY support */
+ if (theInfo == NULL) {
+ ugphy_info("%s: PHY id %x is not supported!", dev->name,
+ phy_ID);
+ return NULL;
+ } else {
+ ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name,
+ phy_ID);
+ }
+
+ return theInfo;
+}
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h
new file mode 100644
index 00000000000..2f98b8f1bb0
--- /dev/null
+++ b/drivers/net/ucc_geth_phy.h
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Shlomi Gridish <gridish@freescale.com>
+ *
+ * Description:
+ * UCC GETH Driver -- PHY handling
+ *
+ * Changelog:
+ * Jun 28, 2006 Li Yang <LeoLi@freescale.com>
+ * - Rearrange code and style fixes
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#ifndef __UCC_GETH_PHY_H__
+#define __UCC_GETH_PHY_H__
+
+#define MII_end ((u32)-2)
+#define MII_read ((u32)-1)
+
+#define MIIMIND_BUSY 0x00000001
+#define MIIMIND_NOTVALID 0x00000004
+
+#define UGETH_AN_TIMEOUT 2000
+
+/* 1000BT control (Marvell & BCM54xx at least) */
+#define MII_1000BASETCONTROL 0x09
+#define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200
+#define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100
+
+/* Cicada Extended Control Register 1 */
+#define MII_CIS8201_EXT_CON1 0x17
+#define MII_CIS8201_EXTCON1_INIT 0x0000
+
+/* Cicada Interrupt Mask Register */
+#define MII_CIS8201_IMASK 0x19
+#define MII_CIS8201_IMASK_IEN 0x8000
+#define MII_CIS8201_IMASK_SPEED 0x4000
+#define MII_CIS8201_IMASK_LINK 0x2000
+#define MII_CIS8201_IMASK_DUPLEX 0x1000
+#define MII_CIS8201_IMASK_MASK 0xf000
+
+/* Cicada Interrupt Status Register */
+#define MII_CIS8201_ISTAT 0x1a
+#define MII_CIS8201_ISTAT_STATUS 0x8000
+#define MII_CIS8201_ISTAT_SPEED 0x4000
+#define MII_CIS8201_ISTAT_LINK 0x2000
+#define MII_CIS8201_ISTAT_DUPLEX 0x1000
+
+/* Cicada Auxiliary Control/Status Register */
+#define MII_CIS8201_AUX_CONSTAT 0x1c
+#define MII_CIS8201_AUXCONSTAT_INIT 0x0004
+#define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020
+#define MII_CIS8201_AUXCONSTAT_SPEED 0x0018
+#define MII_CIS8201_AUXCONSTAT_GBIT 0x0010
+#define MII_CIS8201_AUXCONSTAT_100 0x0008
+
+/* 88E1011 PHY Status Register */
+#define MII_M1011_PHY_SPEC_STATUS 0x11
+#define MII_M1011_PHY_SPEC_STATUS_1000 0x8000
+#define MII_M1011_PHY_SPEC_STATUS_100 0x4000
+#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000
+#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000
+#define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800
+#define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400
+
+#define MII_M1011_IEVENT 0x13
+#define MII_M1011_IEVENT_CLEAR 0x0000
+
+#define MII_M1011_IMASK 0x12
+#define MII_M1011_IMASK_INIT 0x6400
+#define MII_M1011_IMASK_CLEAR 0x0000
+
+#define MII_DM9161_SCR 0x10
+#define MII_DM9161_SCR_INIT 0x0610
+
+/* DM9161 Specified Configuration and Status Register */
+#define MII_DM9161_SCSR 0x11
+#define MII_DM9161_SCSR_100F 0x8000
+#define MII_DM9161_SCSR_100H 0x4000
+#define MII_DM9161_SCSR_10F 0x2000
+#define MII_DM9161_SCSR_10H 0x1000
+
+/* DM9161 Interrupt Register */
+#define MII_DM9161_INTR 0x15
+#define MII_DM9161_INTR_PEND 0x8000
+#define MII_DM9161_INTR_DPLX_MASK 0x0800
+#define MII_DM9161_INTR_SPD_MASK 0x0400
+#define MII_DM9161_INTR_LINK_MASK 0x0200
+#define MII_DM9161_INTR_MASK 0x0100
+#define MII_DM9161_INTR_DPLX_CHANGE 0x0010
+#define MII_DM9161_INTR_SPD_CHANGE 0x0008
+#define MII_DM9161_INTR_LINK_CHANGE 0x0004
+#define MII_DM9161_INTR_INIT 0x0000
+#define MII_DM9161_INTR_STOP \
+(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \
+ | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK)
+
+/* DM9161 10BT Configuration/Status */
+#define MII_DM9161_10BTCSR 0x12
+#define MII_DM9161_10BTCSR_INIT 0x7800
+
+#define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \
+ SUPPORTED_10baseT_Full | \
+ SUPPORTED_100baseT_Half | \
+ SUPPORTED_100baseT_Full | \
+ SUPPORTED_Autoneg | \
+ SUPPORTED_TP | \
+ SUPPORTED_MII)
+
+#define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \
+ SUPPORTED_1000baseT_Half | \
+ SUPPORTED_1000baseT_Full)
+
+#define MII_READ_COMMAND 0x00000001
+
+#define MII_INTERRUPT_DISABLED 0x0
+#define MII_INTERRUPT_ENABLED 0x1
+/* Taken from mii_if_info and sungem_phy.h */
+struct ugeth_mii_info {
+ /* Information about the PHY type */
+ /* And management functions */
+ struct phy_info *phyinfo;
+
+ ucc_mii_mng_t *mii_regs;
+
+ /* forced speed & duplex (no autoneg)
+ * partner speed & duplex & pause (autoneg)
+ */
+ int speed;
+ int duplex;
+ int pause;
+
+ /* The most recently read link state */
+ int link;
+
+ /* Enabled Interrupts */
+ u32 interrupts;
+
+ u32 advertising;
+ int autoneg;
+ int mii_id;
+
+ /* private data pointer */
+ /* For use by PHYs to maintain extra state */
+ void *priv;
+
+ /* Provided by host chip */
+ struct net_device *dev;
+
+ /* A lock to ensure that only one thing can read/write
+ * the MDIO bus at a time */
+ spinlock_t mdio_lock;
+
+ /* Provided by ethernet driver */
+ int (*mdio_read) (struct net_device * dev, int mii_id, int reg);
+ void (*mdio_write) (struct net_device * dev, int mii_id, int reg,
+ int val);
+};
+
+/* struct phy_info: a structure which defines attributes for a PHY
+ *
+ * id will contain a number which represents the PHY. During
+ * startup, the driver will poll the PHY to find out what its
+ * UID--as defined by registers 2 and 3--is. The 32-bit result
+ * gotten from the PHY will be ANDed with phy_id_mask to
+ * discard any bits which may change based on revision numbers
+ * unimportant to functionality
+ *
+ * There are 6 commands which take a ugeth_mii_info structure.
+ * Each PHY must declare config_aneg, and read_status.
+ */
+struct phy_info {
+ u32 phy_id;
+ char *name;
+ unsigned int phy_id_mask;
+ u32 features;
+
+ /* Called to initialize the PHY */
+ int (*init) (struct ugeth_mii_info * mii_info);
+
+ /* Called to suspend the PHY for power */
+ int (*suspend) (struct ugeth_mii_info * mii_info);
+
+ /* Reconfigures autonegotiation (or disables it) */
+ int (*config_aneg) (struct ugeth_mii_info * mii_info);
+
+ /* Determines the negotiated speed and duplex */
+ int (*read_status) (struct ugeth_mii_info * mii_info);
+
+ /* Clears any pending interrupts */
+ int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
+
+ /* Enables or disables interrupts */
+ int (*config_intr) (struct ugeth_mii_info * mii_info);
+
+ /* Clears up any memory if needed */
+ void (*close) (struct ugeth_mii_info * mii_info);
+};
+
+struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info);
+void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value);
+int read_phy_reg(struct net_device *dev, int mii_id, int regnum);
+void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info);
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+ u32 interrupts);
+
+struct dm9161_private {
+ struct timer_list timer;
+ int resetdone;
+};
+
+#endif /* __UCC_GETH_PHY_H__ */
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index c80a4f1d5f7..cbebf1b96e9 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -25,117 +25,13 @@
version. He may or may not be interested in bug reports on this
code. You can find his versions at:
http://www.scyld.com/network/via-rhine.html
-
-
- Linux kernel version history:
-
- LK1.1.0:
- - Jeff Garzik: softnet 'n stuff
-
- LK1.1.1:
- - Justin Guyett: softnet and locking fixes
- - Jeff Garzik: use PCI interface
-
- LK1.1.2:
- - Urban Widmark: minor cleanups, merges from Becker 1.03a/1.04 versions
-
- LK1.1.3:
- - Urban Widmark: use PCI DMA interface (with thanks to the eepro100.c
- code) update "Theory of Operation" with
- softnet/locking changes
- - Dave Miller: PCI DMA and endian fixups
- - Jeff Garzik: MOD_xxx race fixes, updated PCI resource allocation
-
- LK1.1.4:
- - Urban Widmark: fix gcc 2.95.2 problem and
- remove writel's to fixed address 0x7c
-
- LK1.1.5:
- - Urban Widmark: mdio locking, bounce buffer changes
- merges from Beckers 1.05 version
- added netif_running_on/off support
-
- LK1.1.6:
- - Urban Widmark: merges from Beckers 1.08b version (VT6102 + mdio)
- set netif_running_on/off on startup, del_timer_sync
-
- LK1.1.7:
- - Manfred Spraul: added reset into tx_timeout
-
- LK1.1.9:
- - Urban Widmark: merges from Beckers 1.10 version
- (media selection + eeprom reload)
- - David Vrabel: merges from D-Link "1.11" version
- (disable WOL and PME on startup)
-
- LK1.1.10:
- - Manfred Spraul: use "singlecopy" for unaligned buffers
- don't allocate bounce buffers for !ReqTxAlign cards
-
- LK1.1.11:
- - David Woodhouse: Set dev->base_addr before the first time we call
- wait_for_reset(). It's a lot happier that way.
- Free np->tx_bufs only if we actually allocated it.
-
- LK1.1.12:
- - Martin Eriksson: Allow Memory-Mapped IO to be enabled.
-
- LK1.1.13 (jgarzik):
- - Add ethtool support
- - Replace some MII-related magic numbers with constants
-
- LK1.1.14 (Ivan G.):
- - fixes comments for Rhine-III
- - removes W_MAX_TIMEOUT (unused)
- - adds HasDavicomPhy for Rhine-I (basis: linuxfet driver; my card
- is R-I and has Davicom chip, flag is referenced in kernel driver)
- - sends chip_id as a parameter to wait_for_reset since np is not
- initialized on first call
- - changes mmio "else if (chip_id==VT6102)" to "else" so it will work
- for Rhine-III's (documentation says same bit is correct)
- - transmit frame queue message is off by one - fixed
- - adds IntrNormalSummary to "Something Wicked" exclusion list
- so normal interrupts will not trigger the message (src: Donald Becker)
- (Roger Luethi)
- - show confused chip where to continue after Tx error
- - location of collision counter is chip specific
- - allow selecting backoff algorithm (module parameter)
-
- LK1.1.15 (jgarzik):
- - Use new MII lib helper generic_mii_ioctl
-
- LK1.1.16 (Roger Luethi)
- - Etherleak fix
- - Handle Tx buffer underrun
- - Fix bugs in full duplex handling
- - New reset code uses "force reset" cmd on Rhine-II
- - Various clean ups
-
- LK1.1.17 (Roger Luethi)
- - Fix race in via_rhine_start_tx()
- - On errors, wait for Tx engine to turn off before scavenging
- - Handle Tx descriptor write-back race on Rhine-II
- - Force flushing for PCI posted writes
- - More reset code changes
-
- LK1.1.18 (Roger Luethi)
- - No filtering multicast in promisc mode (Edward Peng)
- - Fix for Rhine-I Tx timeouts
-
- LK1.1.19 (Roger Luethi)
- - Increase Tx threshold for unspecified errors
-
- LK1.2.0-2.6 (Roger Luethi)
- - Massive clean-up
- - Rewrite PHY, media handling (remove options, full_duplex, backoff)
- - Fix Tx engine race for good
- - Craig Brind: Zero padded aligned buffers for short packets.
+ [link no longer provides useful info -jgarzik]
*/
#define DRV_NAME "via-rhine"
-#define DRV_VERSION "1.2.0-2.6"
-#define DRV_RELDATE "June-10-2004"
+#define DRV_VERSION "1.4.2"
+#define DRV_RELDATE "Sept-11-2006"
/* A few user-configurable values.
@@ -148,6 +44,10 @@ static int max_interrupt_work = 20;
Setting to > 1518 effectively disables this feature. */
static int rx_copybreak;
+/* Work-around for broken BIOSes: they are unable to get the chip back out of
+ power state D3 so PXE booting fails. bootparam(7): via-rhine.avoid_D3=1 */
+static int avoid_D3;
+
/*
* In case you are looking for 'options[]' or 'full_duplex[]', they
* are gone. Use ethtool(8) instead.
@@ -167,7 +67,11 @@ static const int multicast_filter_limit = 32;
There are no ill effects from too-large receive rings. */
#define TX_RING_SIZE 16
#define TX_QUEUE_LEN 10 /* Limit ring entries actually used. */
+#ifdef CONFIG_VIA_RHINE_NAPI
+#define RX_RING_SIZE 64
+#else
#define RX_RING_SIZE 16
+#endif
/* Operational parameters that usually are not changed. */
@@ -220,9 +124,11 @@ MODULE_LICENSE("GPL");
module_param(max_interrupt_work, int, 0);
module_param(debug, int, 0);
module_param(rx_copybreak, int, 0);
+module_param(avoid_D3, bool, 0);
MODULE_PARM_DESC(max_interrupt_work, "VIA Rhine maximum events handled per interrupt");
MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
+MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
/*
Theory of Operation
@@ -356,12 +262,11 @@ enum rhine_quirks {
/* Beware of PCI posted writes */
#define IOSYNC do { ioread8(ioaddr + StationAddr); } while (0)
-static struct pci_device_id rhine_pci_tbl[] =
-{
- {0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT86C100A */
- {0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6102 */
- {0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* 6105{,L,LOM} */
- {0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, 0, 0, }, /* VT6105M */
+static const struct pci_device_id rhine_pci_tbl[] = {
+ { 0x1106, 0x3043, PCI_ANY_ID, PCI_ANY_ID, }, /* VT86C100A */
+ { 0x1106, 0x3065, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6102 */
+ { 0x1106, 0x3106, PCI_ANY_ID, PCI_ANY_ID, }, /* 6105{,L,LOM} */
+ { 0x1106, 0x3053, PCI_ANY_ID, PCI_ANY_ID, }, /* VT6105M */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
@@ -501,12 +406,12 @@ static void rhine_tx_timeout(struct net_device *dev);
static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
static void rhine_tx(struct net_device *dev);
-static void rhine_rx(struct net_device *dev);
+static int rhine_rx(struct net_device *dev, int limit);
static void rhine_error(struct net_device *dev, int intr_status);
static void rhine_set_rx_mode(struct net_device *dev);
static struct net_device_stats *rhine_get_stats(struct net_device *dev);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static int rhine_close(struct net_device *dev);
static void rhine_shutdown (struct pci_dev *pdev);
@@ -669,6 +574,32 @@ static void rhine_poll(struct net_device *dev)
}
#endif
+#ifdef CONFIG_VIA_RHINE_NAPI
+static int rhine_napipoll(struct net_device *dev, int *budget)
+{
+ struct rhine_private *rp = netdev_priv(dev);
+ void __iomem *ioaddr = rp->base;
+ int done, limit = min(dev->quota, *budget);
+
+ done = rhine_rx(dev, limit);
+ *budget -= done;
+ dev->quota -= done;
+
+ if (done < limit) {
+ netif_rx_complete(dev);
+
+ iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
+ IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
+ IntrTxDone | IntrTxError | IntrTxUnderrun |
+ IntrPCIErr | IntrStatsMax | IntrLinkChange,
+ ioaddr + IntrEnable);
+ return 0;
+ }
+ else
+ return 1;
+}
+#endif
+
static void rhine_hw_init(struct net_device *dev, long pioaddr)
{
struct rhine_private *rp = netdev_priv(dev);
@@ -849,6 +780,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = rhine_poll;
#endif
+#ifdef CONFIG_VIA_RHINE_NAPI
+ dev->poll = rhine_napipoll;
+ dev->weight = 64;
+#endif
if (rp->quirks & rqRhineI)
dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
@@ -894,6 +829,9 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
}
}
rp->mii_if.phy_id = phy_id;
+ if (debug > 1 && avoid_D3)
+ printk(KERN_INFO "%s: No D3 power state at shutdown.\n",
+ dev->name);
return 0;
@@ -1119,6 +1057,8 @@ static void init_registers(struct net_device *dev)
rhine_set_rx_mode(dev);
+ netif_poll_enable(dev);
+
/* Enable interrupts by setting the interrupt mask. */
iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow |
IntrRxDropped | IntrRxNoBuf | IntrTxAborted |
@@ -1210,7 +1150,7 @@ static int rhine_open(struct net_device *dev)
void __iomem *ioaddr = rp->base;
int rc;
- rc = request_irq(rp->pdev->irq, &rhine_interrupt, SA_SHIRQ, dev->name,
+ rc = request_irq(rp->pdev->irq, &rhine_interrupt, IRQF_SHARED, dev->name,
dev);
if (rc)
return rc;
@@ -1290,7 +1230,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
rp->tx_skbuff[entry] = skb;
if ((rp->quirks & rqRhineI) &&
- (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_HW)) {
+ (((unsigned long)skb->data & 3) || skb_shinfo(skb)->nr_frags != 0 || skb->ip_summed == CHECKSUM_PARTIAL)) {
/* Must use alignment buffer. */
if (skb->len > PKT_BUF_SZ) {
/* packet too long, drop it */
@@ -1373,8 +1313,18 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *
dev->name, intr_status);
if (intr_status & (IntrRxDone | IntrRxErr | IntrRxDropped |
- IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf))
- rhine_rx(dev);
+ IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) {
+#ifdef CONFIG_VIA_RHINE_NAPI
+ iowrite16(IntrTxAborted |
+ IntrTxDone | IntrTxError | IntrTxUnderrun |
+ IntrPCIErr | IntrStatsMax | IntrLinkChange,
+ ioaddr + IntrEnable);
+
+ netif_rx_schedule(dev);
+#else
+ rhine_rx(dev, RX_RING_SIZE);
+#endif
+ }
if (intr_status & (IntrTxErrSummary | IntrTxDone)) {
if (intr_status & IntrTxErrSummary) {
@@ -1472,13 +1422,12 @@ static void rhine_tx(struct net_device *dev)
spin_unlock(&rp->lock);
}
-/* This routine is logically part of the interrupt handler, but isolated
- for clarity and better register allocation. */
-static void rhine_rx(struct net_device *dev)
+/* Process up to limit frames from receive ring */
+static int rhine_rx(struct net_device *dev, int limit)
{
struct rhine_private *rp = netdev_priv(dev);
+ int count;
int entry = rp->cur_rx % RX_RING_SIZE;
- int boguscnt = rp->dirty_rx + RX_RING_SIZE - rp->cur_rx;
if (debug > 4) {
printk(KERN_DEBUG "%s: rhine_rx(), entry %d status %8.8x.\n",
@@ -1487,16 +1436,18 @@ static void rhine_rx(struct net_device *dev)
}
/* If EOP is set on the next entry, it's a new packet. Send it up. */
- while (!(rp->rx_head_desc->rx_status & cpu_to_le32(DescOwn))) {
+ for (count = 0; count < limit; ++count) {
struct rx_desc *desc = rp->rx_head_desc;
u32 desc_status = le32_to_cpu(desc->rx_status);
int data_size = desc_status >> 16;
+ if (desc_status & DescOwn)
+ break;
+
if (debug > 4)
printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
desc_status);
- if (--boguscnt < 0)
- break;
+
if ((desc_status & (RxWholePkt | RxErr)) != RxWholePkt) {
if ((desc_status & RxWholePkt) != RxWholePkt) {
printk(KERN_WARNING "%s: Oversized Ethernet "
@@ -1565,7 +1516,11 @@ static void rhine_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE);
}
skb->protocol = eth_type_trans(skb, dev);
+#ifdef CONFIG_VIA_RHINE_NAPI
+ netif_receive_skb(skb);
+#else
netif_rx(skb);
+#endif
dev->last_rx = jiffies;
rp->stats.rx_bytes += pkt_len;
rp->stats.rx_packets++;
@@ -1592,6 +1547,8 @@ static void rhine_rx(struct net_device *dev)
}
rp->rx_ring[entry].rx_status = cpu_to_le32(DescOwn);
}
+
+ return count;
}
/*
@@ -1722,9 +1679,6 @@ static void rhine_set_rx_mode(struct net_device *dev)
u8 rx_mode; /* Note: 0x02=accept runt, 0x01=accept errs */
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n",
- dev->name);
rx_mode = 0x1C;
iowrite32(0xffffffff, ioaddr + MulticastFilter0);
iowrite32(0xffffffff, ioaddr + MulticastFilter1);
@@ -1842,7 +1796,7 @@ static int rhine_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
.get_settings = netdev_get_settings,
.set_settings = netdev_set_settings,
@@ -1881,6 +1835,7 @@ static int rhine_close(struct net_device *dev)
spin_lock_irq(&rp->lock);
netif_stop_queue(dev);
+ netif_poll_disable(dev);
if (debug > 1)
printk(KERN_DEBUG "%s: Shutting down ethercard, "
@@ -1962,7 +1917,8 @@ static void rhine_shutdown (struct pci_dev *pdev)
}
/* Hit power state D3 (sleep) */
- iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
+ if (!avoid_D3)
+ iowrite8(ioread8(ioaddr + StickyHW) | 0x03, ioaddr + StickyHW);
/* TODO: Check use of pci_enable_wake() */
@@ -1999,7 +1955,7 @@ static int rhine_resume(struct pci_dev *pdev)
if (!netif_running(dev))
return 0;
- if (request_irq(dev->irq, rhine_interrupt, SA_SHIRQ, dev->name, dev))
+ if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name);
ret = pci_set_power_state(pdev, PCI_D0);
@@ -2046,7 +2002,7 @@ static int __init rhine_init(void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init(&rhine_driver);
+ return pci_register_driver(&rhine_driver);
}
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 09e05fe40c3..7d8808ce541 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -47,7 +47,6 @@
#include <linux/module.h>
#include <linux/types.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/errno.h>
@@ -65,7 +64,6 @@
#include <linux/wait.h>
#include <asm/io.h>
#include <linux/if.h>
-#include <linux/config.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/inetdevice.h>
@@ -88,7 +86,7 @@ static int msglevel = MSG_LEVEL_INFO;
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static struct ethtool_ops velocity_ethtool_ops;
+static const struct ethtool_ops velocity_ethtool_ops;
/*
Define module options
@@ -231,7 +229,8 @@ static int rx_copybreak = 200;
module_param(rx_copybreak, int, 0644);
MODULE_PARM_DESC(rx_copybreak, "Copy breakpoint for copy-only-tiny-frames");
-static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info);
+static void velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr,
+ const struct velocity_info_tbl *info);
static int velocity_get_pci_info(struct velocity_info *, struct pci_dev *pdev);
static void velocity_print_info(struct velocity_info *vptr);
static int velocity_open(struct net_device *dev);
@@ -296,9 +295,9 @@ static void velocity_unregister_notifier(void)
* Internal board variants. At the moment we have only one
*/
-static struct velocity_info_tbl chip_info_table[] = {
- {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 256, 1, 0x00FFFFFFUL},
- {0, NULL}
+static const struct velocity_info_tbl chip_info_table[] __devinitdata = {
+ {CHIP_TYPE_VT6110, "VIA Networking Velocity Family Gigabit Ethernet Adapter", 1, 0x00FFFFFFUL},
+ { }
};
/*
@@ -306,10 +305,9 @@ static struct velocity_info_tbl chip_info_table[] = {
* device driver. Used for hotplug autoloading.
*/
-static struct pci_device_id velocity_id_table[] __devinitdata = {
- {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, (unsigned long) chip_info_table},
- {0, }
+static const struct pci_device_id velocity_id_table[] __devinitdata = {
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_612X) },
+ { }
};
MODULE_DEVICE_TABLE(pci, velocity_id_table);
@@ -343,7 +341,7 @@ static char __devinit *get_chip_name(enum chip_type chip_id)
static void __devexit velocity_remove1(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
#ifdef CONFIG_PM
unsigned long flags;
@@ -413,11 +411,11 @@ static void __devinit velocity_set_bool_opt(u32 * opt, int val, int def, u32 fla
if (val == -1)
*opt |= (def ? flag : 0);
else if (val < 0 || val > 1) {
- printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
+ printk(KERN_NOTICE "%s: the value of parameter %s is invalid, the valid range is (0-1)\n",
devname, name);
*opt |= (def ? flag : 0);
} else {
- printk(KERN_INFO "%s: set parameter %s to %s\n",
+ printk(KERN_INFO "%s: set parameter %s to %s\n",
devname, name, val ? "TRUE" : "FALSE");
*opt |= (val ? flag : 0);
}
@@ -529,7 +527,7 @@ static void velocity_rx_reset(struct velocity_info *vptr)
* hardware.
*/
-static void velocity_init_registers(struct velocity_info *vptr,
+static void velocity_init_registers(struct velocity_info *vptr,
enum velocity_init_type type)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
@@ -561,7 +559,7 @@ static void velocity_init_registers(struct velocity_info *vptr,
mac_clear_isr(regs);
writel(CR0_STOP, &regs->CR0Clr);
- writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
+ writel((CR0_DPOLL | CR0_TXON | CR0_RXON | CR0_STRT),
&regs->CR0Set);
break;
@@ -688,33 +686,35 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
static int first = 1;
struct net_device *dev;
int i;
- struct velocity_info_tbl *info = (struct velocity_info_tbl *) ent->driver_data;
+ const struct velocity_info_tbl *info = &chip_info_table[ent->driver_data];
struct velocity_info *vptr;
struct mac_regs __iomem * regs;
int ret = -ENOMEM;
+ /* FIXME: this driver, like almost all other ethernet drivers,
+ * can support more than MAX_UNITS.
+ */
if (velocity_nics >= MAX_UNITS) {
- printk(KERN_NOTICE VELOCITY_NAME ": already found %d NICs.\n",
- velocity_nics);
+ dev_notice(&pdev->dev, "already found %d NICs.\n",
+ velocity_nics);
return -ENODEV;
}
dev = alloc_etherdev(sizeof(struct velocity_info));
-
- if (dev == NULL) {
- printk(KERN_ERR VELOCITY_NAME ": allocate net device failed.\n");
+ if (!dev) {
+ dev_err(&pdev->dev, "allocate net device failed.\n");
goto out;
}
-
+
/* Chain it all together */
-
+
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- vptr = dev->priv;
+ vptr = netdev_priv(dev);
if (first) {
- printk(KERN_INFO "%s Ver. %s\n",
+ printk(KERN_INFO "%s Ver. %s\n",
VELOCITY_FULL_DRV_NAM, VELOCITY_VERSION);
printk(KERN_INFO "Copyright (c) 2002, 2003 VIA Networking Technologies, Inc.\n");
printk(KERN_INFO "Copyright (c) 2004 Red Hat Inc.\n");
@@ -728,22 +728,22 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
dev->irq = pdev->irq;
ret = pci_enable_device(pdev);
- if (ret < 0)
+ if (ret < 0)
goto err_free_dev;
ret = velocity_get_pci_info(vptr, pdev);
if (ret < 0) {
- printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+ /* error message already printed */
goto err_disable;
}
ret = pci_request_regions(pdev, VELOCITY_NAME);
if (ret < 0) {
- printk(KERN_ERR VELOCITY_NAME ": Failed to find PCI device.\n");
+ dev_err(&pdev->dev, "No PCI resources.\n");
goto err_disable;
}
- regs = ioremap(vptr->memaddr, vptr->io_size);
+ regs = ioremap(vptr->memaddr, VELOCITY_IO_SIZE);
if (regs == NULL) {
ret = -EIO;
goto err_release_res;
@@ -761,16 +761,16 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
velocity_get_options(&vptr->options, velocity_nics, dev->name);
- /*
+ /*
* Mask out the options cannot be set to the chip
*/
-
+
vptr->options.flags &= info->flags;
/*
* Enable the chip specified capbilities
*/
-
+
vptr->flags = vptr->options.flags | (info->flags & 0xFF000000UL);
vptr->wol_opts = vptr->options.wol_opts;
@@ -804,9 +804,9 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi
velocity_print_info(vptr);
pci_set_drvdata(pdev, dev);
-
+
/* and leave the chip powered down */
-
+
pci_set_power_state(pdev, PCI_D3hot);
#ifdef CONFIG_PM
{
@@ -845,9 +845,9 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
struct net_device *dev = vptr->dev;
printk(KERN_INFO "%s: %s\n", dev->name, get_chip_name(vptr->chip_id));
- printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
- dev->name,
- dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+ printk(KERN_INFO "%s: Ethernet Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+ dev->name,
+ dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
}
@@ -861,13 +861,14 @@ static void __devinit velocity_print_info(struct velocity_info *vptr)
* discovered.
*/
-static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_info *vptr, struct velocity_info_tbl *info)
+static void __devinit velocity_init_info(struct pci_dev *pdev,
+ struct velocity_info *vptr,
+ const struct velocity_info_tbl *info)
{
memset(vptr, 0, sizeof(struct velocity_info));
vptr->pdev = pdev;
vptr->chip_id = info->chip_id;
- vptr->io_size = info->io_size;
vptr->num_txq = info->txqueue;
vptr->multicast_limit = MCAM_SIZE;
spin_lock_init(&vptr->lock);
@@ -885,33 +886,28 @@ static void __devinit velocity_init_info(struct pci_dev *pdev, struct velocity_i
static int __devinit velocity_get_pci_info(struct velocity_info *vptr, struct pci_dev *pdev)
{
-
- if(pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
+ if (pci_read_config_byte(pdev, PCI_REVISION_ID, &vptr->rev_id) < 0)
return -EIO;
-
+
pci_set_master(pdev);
vptr->ioaddr = pci_resource_start(pdev, 0);
vptr->memaddr = pci_resource_start(pdev, 1);
-
- if(!(pci_resource_flags(pdev, 0) & IORESOURCE_IO))
- {
- printk(KERN_ERR "%s: region #0 is not an I/O resource, aborting.\n",
- pci_name(pdev));
+
+ if (!(pci_resource_flags(pdev, 0) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #0 is not an I/O resource, aborting.\n");
return -EINVAL;
}
- if((pci_resource_flags(pdev, 1) & IORESOURCE_IO))
- {
- printk(KERN_ERR "%s: region #1 is an I/O resource, aborting.\n",
- pci_name(pdev));
+ if ((pci_resource_flags(pdev, 1) & IORESOURCE_IO)) {
+ dev_err(&pdev->dev,
+ "region #1 is an I/O resource, aborting.\n");
return -EINVAL;
}
- if(pci_resource_len(pdev, 1) < 256)
- {
- printk(KERN_ERR "%s: region #1 is too small.\n",
- pci_name(pdev));
+ if (pci_resource_len(pdev, 1) < VELOCITY_IO_SIZE) {
+ dev_err(&pdev->dev, "region #1 is too small.\n");
return -EINVAL;
}
vptr->pdev = pdev;
@@ -936,10 +932,10 @@ static int velocity_init_rings(struct velocity_info *vptr)
u8 *pool;
/*
- * Allocate all RD/TD rings a single pool
+ * Allocate all RD/TD rings a single pool
*/
-
- psize = vptr->options.numrx * sizeof(struct rx_desc) +
+
+ psize = vptr->options.numrx * sizeof(struct rx_desc) +
vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
/*
@@ -949,7 +945,7 @@ static int velocity_init_rings(struct velocity_info *vptr)
pool = pci_alloc_consistent(vptr->pdev, psize, &pool_dma);
if (pool == NULL) {
- printk(KERN_ERR "%s : DMA memory allocation failed.\n",
+ printk(KERN_ERR "%s : DMA memory allocation failed.\n",
vptr->dev->name);
return -ENOMEM;
}
@@ -961,11 +957,11 @@ static int velocity_init_rings(struct velocity_info *vptr)
vptr->rd_pool_dma = pool_dma;
tsize = vptr->options.numtx * PKT_BUF_SZ * vptr->num_txq;
- vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize,
+ vptr->tx_bufs = pci_alloc_consistent(vptr->pdev, tsize,
&vptr->tx_bufs_dma);
if (vptr->tx_bufs == NULL) {
- printk(KERN_ERR "%s: DMA memory allocation failed.\n",
+ printk(KERN_ERR "%s: DMA memory allocation failed.\n",
vptr->dev->name);
pci_free_consistent(vptr->pdev, psize, pool, pool_dma);
return -ENOMEM;
@@ -998,7 +994,7 @@ static void velocity_free_rings(struct velocity_info *vptr)
{
int size;
- size = vptr->options.numrx * sizeof(struct rx_desc) +
+ size = vptr->options.numrx * sizeof(struct rx_desc) +
vptr->options.numtx * sizeof(struct tx_desc) * vptr->num_txq;
pci_free_consistent(vptr->pdev, size, vptr->rd_ring, vptr->rd_pool_dma);
@@ -1050,7 +1046,7 @@ static int velocity_rx_refill(struct velocity_info *vptr)
break;
}
done++;
- dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
+ dirty = (dirty < vptr->options.numrx - 1) ? dirty + 1 : 0;
} while (dirty != vptr->rd_curr);
if (done) {
@@ -1073,7 +1069,7 @@ static int velocity_rx_refill(struct velocity_info *vptr)
static int velocity_init_rd_ring(struct velocity_info *vptr)
{
int ret = -ENOMEM;
- unsigned int rsize = sizeof(struct velocity_rd_info) *
+ unsigned int rsize = sizeof(struct velocity_rd_info) *
vptr->options.numrx;
vptr->rd_info = kmalloc(rsize, GFP_KERNEL);
@@ -1136,14 +1132,14 @@ static void velocity_free_rd_ring(struct velocity_info *vptr)
* Returns zero on success or a negative posix errno code for
* failure.
*/
-
+
static int velocity_init_td_ring(struct velocity_info *vptr)
{
int i, j;
dma_addr_t curr;
struct tx_desc *td;
struct velocity_td_info *td_info;
- unsigned int tsize = sizeof(struct velocity_td_info) *
+ unsigned int tsize = sizeof(struct velocity_td_info) *
vptr->options.numtx;
/* Init the TD ring entries */
@@ -1181,15 +1177,15 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
{
struct velocity_td_info * td_info = &(vptr->td_infos[q][n]);
int i;
-
+
if (td_info == NULL)
return;
-
+
if (td_info->skb) {
for (i = 0; i < td_info->nskb_dma; i++)
{
if (td_info->skb_dma[i]) {
- pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
+ pci_unmap_single(vptr->pdev, td_info->skb_dma[i],
td_info->skb->len, PCI_DMA_TODEVICE);
td_info->skb_dma[i] = (dma_addr_t) NULL;
}
@@ -1206,7 +1202,7 @@ static void velocity_free_td_ring_entry(struct velocity_info *vptr,
* Free up the transmit ring for this particular velocity adapter.
* We free the ring contents but not the ring itself.
*/
-
+
static void velocity_free_td_ring(struct velocity_info *vptr)
{
int i, j;
@@ -1232,7 +1228,7 @@ static void velocity_free_td_ring(struct velocity_info *vptr)
* any received packets from the receive queue. Hand the ring
* slots back to the adapter for reuse.
*/
-
+
static int velocity_rx_srv(struct velocity_info *vptr, int status)
{
struct net_device_stats *stats = &vptr->stats;
@@ -1293,14 +1289,14 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status)
* Process the status bits for the received packet and determine
* if the checksum was computed and verified by the hardware
*/
-
+
static inline void velocity_rx_csum(struct rx_desc *rd, struct sk_buff *skb)
{
skb->ip_summed = CHECKSUM_NONE;
if (rd->rdesc1.CSM & CSM_IPKT) {
if (rd->rdesc1.CSM & CSM_IPOK) {
- if ((rd->rdesc1.CSM & CSM_TCPKT) ||
+ if ((rd->rdesc1.CSM & CSM_TCPKT) ||
(rd->rdesc1.CSM & CSM_UDPKT)) {
if (!(rd->rdesc1.CSM & CSM_TUPOK)) {
return;
@@ -1343,7 +1339,7 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
*rx_skb = new_skb;
ret = 0;
}
-
+
}
return ret;
}
@@ -1374,11 +1370,11 @@ static inline void velocity_iph_realign(struct velocity_info *vptr,
* velocity_receive_frame - received packet processor
* @vptr: velocity we are handling
* @idx: ring index
- *
+ *
* A packet has arrived. We process the packet and if appropriate
* pass the frame up the network stack
*/
-
+
static int velocity_receive_frame(struct velocity_info *vptr, int idx)
{
void (*pci_action)(struct pci_dev *, dma_addr_t, size_t, int);
@@ -1406,7 +1402,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
/*
* Drop frame not meeting IEEE 802.3
*/
-
+
if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
if (rd->rdesc0.RSR & RSR_RL) {
stats->rx_length_errors++;
@@ -1428,7 +1424,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
PCI_DMA_FROMDEVICE);
skb_put(skb, pkt_len - 4);
- skb->protocol = eth_type_trans(skb, skb->dev);
+ skb->protocol = eth_type_trans(skb, skb->dev);
stats->rx_bytes += pkt_len;
netif_rx(skb);
@@ -1446,7 +1442,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
* requires *64* byte alignment of the buffer which makes life
* less fun than would be ideal.
*/
-
+
static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
{
struct rx_desc *rd = &(vptr->rd_ring[idx]);
@@ -1463,11 +1459,11 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
rd_info->skb->dev = vptr->dev;
rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
+
/*
* Fill in the descriptor to match
- */
-
+ */
+
*((u32 *) & (rd->rdesc0)) = 0;
rd->len = cpu_to_le32(vptr->rx_buf_sz);
rd->inten = 1;
@@ -1485,7 +1481,7 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
* we can complete and clean up. Update any statistics as
* neccessary/
*/
-
+
static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
{
struct tx_desc *td;
@@ -1497,7 +1493,7 @@ static int velocity_tx_srv(struct velocity_info *vptr, u32 status)
struct net_device_stats *stats = &vptr->stats;
for (qnum = 0; qnum < vptr->num_txq; qnum++) {
- for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0;
+ for (idx = vptr->td_tail[qnum]; vptr->td_used[qnum] > 0;
idx = (idx + 1) % vptr->options.numtx) {
/*
@@ -1602,12 +1598,12 @@ static void velocity_print_link_status(struct velocity_info *vptr)
* @status: card status
*
* Process an error report from the hardware and attempt to recover
- * the card itself. At the moment we cannot recover from some
+ * the card itself. At the moment we cannot recover from some
* theoretically impossible errors but this could be fixed using
* the pci_device_failed logic to bounce the hardware
*
*/
-
+
static void velocity_error(struct velocity_info *vptr, int status)
{
@@ -1618,7 +1614,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
BYTE_REG_BITS_ON(TXESR_TDSTR, &regs->TXESR);
writew(TRDCSR_RUN, &regs->TDCSRClr);
netif_stop_queue(vptr->dev);
-
+
/* FIXME: port over the pci_device_failed code and use it
here */
}
@@ -1631,7 +1627,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
vptr->mii_status = check_connection_type(regs);
/*
- * If it is a 3119, disable frame bursting in
+ * If it is a 3119, disable frame bursting in
* halfduplex mode and enable it in fullduplex
* mode
*/
@@ -1667,10 +1663,10 @@ static void velocity_error(struct velocity_info *vptr, int status)
enable_flow_control_ability(vptr);
/*
- * Re-enable auto-polling because SRCI will disable
+ * Re-enable auto-polling because SRCI will disable
* auto-polling
*/
-
+
enable_mii_autopoll(regs);
if (vptr->mii_status & VELOCITY_LINK_FAIL)
@@ -1693,7 +1689,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
* Release an transmit buffer. If the buffer was preallocated then
* recycle it, if not then unmap the buffer.
*/
-
+
static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *tdinfo)
{
struct sk_buff *skb = tdinfo->skb;
@@ -1727,10 +1723,10 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
* All the ring allocation and set up is done on open for this
* adapter to minimise memory usage when inactive
*/
-
+
static int velocity_open(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int ret;
vptr->rx_buf_sz = (dev->mtu <= 1504 ? PKT_BUF_SZ : dev->mtu + 32);
@@ -1746,13 +1742,13 @@ static int velocity_open(struct net_device *dev)
ret = velocity_init_td_ring(vptr);
if (ret < 0)
goto err_free_rd_ring;
-
- /* Ensure chip is running */
+
+ /* Ensure chip is running */
pci_set_power_state(vptr->pdev, PCI_D0);
-
+
velocity_init_registers(vptr, VELOCITY_INIT_COLD);
- ret = request_irq(vptr->pdev->irq, &velocity_intr, SA_SHIRQ,
+ ret = request_irq(vptr->pdev->irq, &velocity_intr, IRQF_SHARED,
dev->name, dev);
if (ret < 0) {
/* Power down the chip */
@@ -1775,7 +1771,7 @@ err_free_desc_rings:
goto out;
}
-/**
+/**
* velocity_change_mtu - MTU change callback
* @dev: network device
* @new_mtu: desired MTU
@@ -1784,16 +1780,16 @@ err_free_desc_rings:
* this interface. It gets called on a change by the network layer.
* Return zero for success or negative posix error code.
*/
-
+
static int velocity_change_mtu(struct net_device *dev, int new_mtu)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
unsigned long flags;
int oldmtu = dev->mtu;
int ret = 0;
if ((new_mtu < VELOCITY_MIN_MTU) || new_mtu > (VELOCITY_MAX_MTU)) {
- VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
+ VELOCITY_PRT(MSG_LEVEL_ERR, KERN_NOTICE "%s: Invalid MTU.\n",
vptr->dev->name);
return -EINVAL;
}
@@ -1841,7 +1837,7 @@ out_unlock:
* Shuts down the internal operations of the velocity and
* disables interrupts, autopolling, transmit and receive
*/
-
+
static void velocity_shutdown(struct velocity_info *vptr)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
@@ -1863,7 +1859,7 @@ static void velocity_shutdown(struct velocity_info *vptr)
static int velocity_close(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
netif_stop_queue(dev);
velocity_shutdown(vptr);
@@ -1872,10 +1868,10 @@ static int velocity_close(struct net_device *dev)
velocity_get_ip(vptr);
if (dev->irq != 0)
free_irq(dev->irq, dev);
-
+
/* Power down the chip */
pci_set_power_state(vptr->pdev, PCI_D3hot);
-
+
/* Free the resources */
velocity_free_td_ring(vptr);
velocity_free_rd_ring(vptr);
@@ -1893,10 +1889,10 @@ static int velocity_close(struct net_device *dev)
* Called by the networ layer to request a packet is queued to
* the velocity. Returns zero on success.
*/
-
+
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int qnum = 0;
struct tx_desc *td_ptr;
struct velocity_td_info *tdinfo;
@@ -1923,7 +1919,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
td_ptr->td_buf[0].queue = 0;
/*
- * Pad short frames.
+ * Pad short frames.
*/
if (pktlen < ETH_ZLEN) {
/* Cannot occur until ZC support */
@@ -1946,7 +1942,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
if (nfrags > 6) {
memcpy(tdinfo->buf, skb->data, skb->len);
tdinfo->skb_dma[0] = tdinfo->buf_dma;
- td_ptr->tdesc0.pktsize =
+ td_ptr->tdesc0.pktsize =
td_ptr->td_buf[0].pa_low = cpu_to_le32(tdinfo->skb_dma[0]);
td_ptr->td_buf[0].pa_high = 0;
td_ptr->td_buf[0].bufsize = td_ptr->tdesc0.pktsize;
@@ -2006,7 +2002,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
* Handle hardware checksum
*/
if ((vptr->flags & VELOCITY_FLAGS_TX_CSUM)
- && (skb->ip_summed == CHECKSUM_HW)) {
+ && (skb->ip_summed == CHECKSUM_PARTIAL)) {
struct iphdr *ip = skb->nh.iph;
if (ip->protocol == IPPROTO_TCP)
td_ptr->tdesc1.TCR |= TCR0_TCPCK;
@@ -2047,11 +2043,11 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
* and need to identify initially if we are, and if not exit as
* efficiently as possible.
*/
-
+
static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
{
struct net_device *dev = dev_instance;
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
u32 isr_status;
int max_count = 0;
@@ -2071,7 +2067,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
* Keep processing the ISR until we have completed
* processing and the isr_status becomes zero
*/
-
+
while (isr_status != 0) {
mac_write_isr(vptr->mac_regs, isr_status);
if (isr_status & (~(ISR_PRXI | ISR_PPRXI | ISR_PTXI | ISR_PPTXI)))
@@ -2083,7 +2079,7 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
isr_status = mac_read_isr(vptr->mac_regs);
if (max_count > vptr->options.int_works)
{
- printk(KERN_WARNING "%s: excessive work at interrupt.\n",
+ printk(KERN_WARNING "%s: excessive work at interrupt.\n",
dev->name);
max_count = 0;
}
@@ -2103,18 +2099,16 @@ static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
* for a velocity adapter. Reload the CAMs with the new address
* filter ruleset.
*/
-
+
static void velocity_set_multi(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
u8 rx_mode;
int i;
struct dev_mc_list *mclist;
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
writel(0xffffffff, &regs->MARCAM[0]);
writel(0xffffffff, &regs->MARCAM[4]);
rx_mode = (RCR_AM | RCR_AB | RCR_PROM);
@@ -2152,11 +2146,11 @@ static void velocity_set_multi(struct net_device *dev)
* the hardware into the counters before letting the network
* layer display them.
*/
-
+
static struct net_device_stats *velocity_get_stats(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
-
+ struct velocity_info *vptr = netdev_priv(dev);
+
/* If the hardware is down, don't touch MII */
if(!netif_running(dev))
return &vptr->stats;
@@ -2195,18 +2189,18 @@ static struct net_device_stats *velocity_get_stats(struct net_device *dev)
* Called when the user issues an ioctl request to the network
* device in question. The velocity interface supports MII.
*/
-
+
static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
int ret;
/* If we are asked for information and the device is power
saving then we need to bring the device back up to talk to it */
-
+
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D0);
-
+
switch (cmd) {
case SIOCGMIIPHY: /* Get address of MII PHY in use. */
case SIOCGMIIREG: /* Read MII PHY register. */
@@ -2219,8 +2213,8 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D3hot);
-
-
+
+
return ret;
}
@@ -2228,7 +2222,7 @@ static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
* Definition for our device driver. The PCI layer interface
* uses this to handle all our card discover and plugging
*/
-
+
static struct pci_driver velocity_driver = {
.name = VELOCITY_NAME,
.id_table = velocity_id_table,
@@ -2248,13 +2242,13 @@ static struct pci_driver velocity_driver = {
* the probe functions for each velocity adapter installed
* in the system.
*/
-
+
static int __init velocity_init_module(void)
{
int ret;
velocity_register_notifier();
- ret = pci_module_init(&velocity_driver);
+ ret = pci_register_driver(&velocity_driver);
if (ret < 0)
velocity_unregister_notifier();
return ret;
@@ -2264,11 +2258,11 @@ static int __init velocity_init_module(void)
* velocity_cleanup - module unload
*
* When the velocity hardware is unloaded this function is called.
- * It will clean up the notifiers and the unregister the PCI
+ * It will clean up the notifiers and the unregister the PCI
* driver interface for this hardware. This in turn cleans up
* all discovered interfaces before returning from the function
*/
-
+
static void __exit velocity_cleanup_module(void)
{
velocity_unregister_notifier();
@@ -2282,8 +2276,8 @@ module_exit(velocity_cleanup_module);
/*
* MII access , media link mode setting functions
*/
-
-
+
+
/**
* mii_init - set up MII
* @vptr: velocity adapter
@@ -2291,7 +2285,7 @@ module_exit(velocity_cleanup_module);
*
* Set up the PHY for the current link state.
*/
-
+
static void mii_init(struct velocity_info *vptr, u32 mii_status)
{
u16 BMCR;
@@ -2304,7 +2298,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
MII_REG_BITS_OFF((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
/*
* Turn on ECHODIS bit in NWay-forced full mode and turn it
- * off it in NWay-forced half mode for NWay-forced v.s.
+ * off it in NWay-forced half mode for NWay-forced v.s.
* legacy-forced issue.
*/
if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
@@ -2324,7 +2318,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
/*
* Turn on ECHODIS bit in NWay-forced full mode and turn it
- * off it in NWay-forced half mode for NWay-forced v.s.
+ * off it in NWay-forced half mode for NWay-forced v.s.
* legacy-forced issue
*/
if (vptr->mii_status & VELOCITY_DUPLEX_FULL)
@@ -2336,11 +2330,11 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
case PHYID_MARVELL_1000:
case PHYID_MARVELL_1000S:
/*
- * Assert CRS on Transmit
+ * Assert CRS on Transmit
*/
MII_REG_BITS_ON(PSCR_ACRSTX, MII_REG_PSCR, vptr->mac_regs);
/*
- * Reset to hardware default
+ * Reset to hardware default
*/
MII_REG_BITS_ON((ANAR_ASMDIR | ANAR_PAUSE), MII_REG_ANAR, vptr->mac_regs);
break;
@@ -2360,7 +2354,7 @@ static void mii_init(struct velocity_info *vptr, u32 mii_status)
*
* Turn off the autopoll and wait for it to disable on the chip
*/
-
+
static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs)
{
u16 ww;
@@ -2414,7 +2408,7 @@ static void enable_mii_autopoll(struct mac_regs __iomem * regs)
* Perform a single read of an MII 16bit register. Returns zero
* on success or -ETIMEDOUT if the PHY did not respond.
*/
-
+
static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
{
u16 ww;
@@ -2450,7 +2444,7 @@ static int velocity_mii_read(struct mac_regs __iomem *regs, u8 index, u16 *data)
* Perform a single write to an MII 16bit register. Returns zero
* on success or -ETIMEDOUT if the PHY did not respond.
*/
-
+
static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 data)
{
u16 ww;
@@ -2489,7 +2483,7 @@ static int velocity_mii_write(struct mac_regs __iomem *regs, u8 mii_addr, u16 da
* mii_status accordingly. The requested link state information
* is also returned.
*/
-
+
static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
{
u32 status = 0;
@@ -2521,7 +2515,7 @@ static u32 velocity_get_opt_media_mode(struct velocity_info *vptr)
*
* Enable autonegotation on this interface
*/
-
+
static void mii_set_auto_on(struct velocity_info *vptr)
{
if (MII_REG_BITS_IS_ON(BMCR_AUTO, MII_REG_BMCR, vptr->mac_regs))
@@ -2545,7 +2539,7 @@ static void mii_set_auto_off(struct velocity_info * vptr)
* Set up the flow control on this interface according to
* the supplied user/eeprom options.
*/
-
+
static void set_mii_flow_control(struct velocity_info *vptr)
{
/*Enable or Disable PAUSE in ANAR */
@@ -2582,7 +2576,7 @@ static void set_mii_flow_control(struct velocity_info *vptr)
* PHY and also velocity hardware setup accordingly. In particular
* we need to set up CD polling and frame bursting.
*/
-
+
static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
{
u32 curr_status;
@@ -2692,7 +2686,7 @@ static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status)
* Check the current MII status and determine the link status
* accordingly
*/
-
+
static u32 mii_check_media_mode(struct mac_regs __iomem * regs)
{
u32 status = 0;
@@ -2746,7 +2740,7 @@ static u32 check_connection_type(struct mac_regs __iomem * regs)
if (PHYSR0 & PHYSR0_SPDG)
status |= VELOCITY_SPEED_1000;
- if (PHYSR0 & PHYSR0_SPD10)
+ else if (PHYSR0 & PHYSR0_SPD10)
status |= VELOCITY_SPEED_10;
else
status |= VELOCITY_SPEED_100;
@@ -2824,14 +2818,14 @@ static void enable_flow_control_ability(struct velocity_info *vptr)
* Called before an ethtool operation. We need to make sure the
* chip is out of D3 state before we poke at it.
*/
-
+
static int velocity_ethtool_up(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D0);
return 0;
-}
+}
/**
* velocity_ethtool_down - post hook for ethtool
@@ -2840,23 +2834,32 @@ static int velocity_ethtool_up(struct net_device *dev)
* Called after an ethtool operation. Restore the chip back to D3
* state if it isn't running.
*/
-
+
static void velocity_ethtool_down(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!netif_running(dev))
pci_set_power_state(vptr->pdev, PCI_D3hot);
}
static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
u32 status;
status = check_connection_type(vptr->mac_regs);
- cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
- if (status & VELOCITY_SPEED_100)
+ cmd->supported = SUPPORTED_TP |
+ SUPPORTED_Autoneg |
+ SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full;
+ if (status & VELOCITY_SPEED_1000)
+ cmd->speed = SPEED_1000;
+ else if (status & VELOCITY_SPEED_100)
cmd->speed = SPEED_100;
else
cmd->speed = SPEED_10;
@@ -2869,17 +2872,17 @@ static int velocity_get_settings(struct net_device *dev, struct ethtool_cmd *cmd
cmd->duplex = DUPLEX_FULL;
else
cmd->duplex = DUPLEX_HALF;
-
+
return 0;
}
static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
u32 curr_status;
u32 new_status = 0;
int ret = 0;
-
+
curr_status = check_connection_type(vptr->mac_regs);
curr_status &= (~VELOCITY_LINK_FAIL);
@@ -2898,14 +2901,14 @@ static int velocity_set_settings(struct net_device *dev, struct ethtool_cmd *cmd
static u32 velocity_get_link(struct net_device *dev)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
- return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 0 : 1;
+ return BYTE_REG_BITS_IS_ON(PHYSR0_LINKGD, &regs->PHYSR0) ? 1 : 0;
}
static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
strcpy(info->driver, VELOCITY_NAME);
strcpy(info->version, VELOCITY_VERSION);
strcpy(info->bus_info, pci_name(vptr->pdev));
@@ -2913,7 +2916,7 @@ static void velocity_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
wol->supported = WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP;
wol->wolopts |= WAKE_MAGIC;
/*
@@ -2929,7 +2932,7 @@ static void velocity_ethtool_get_wol(struct net_device *dev, struct ethtool_woli
static int velocity_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
if (!(wol->wolopts & (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_ARP)))
return -EFAULT;
@@ -2968,7 +2971,7 @@ static void velocity_set_msglevel(struct net_device *dev, u32 value)
msglevel = value;
}
-static struct ethtool_ops velocity_ethtool_ops = {
+static const struct ethtool_ops velocity_ethtool_ops = {
.get_settings = velocity_get_settings,
.set_settings = velocity_set_settings,
.get_drvinfo = velocity_get_drvinfo,
@@ -2991,15 +2994,15 @@ static struct ethtool_ops velocity_ethtool_ops = {
* are used by tools like kudzu to interrogate the link state of the
* hardware
*/
-
+
static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct velocity_info *vptr = dev->priv;
+ struct velocity_info *vptr = netdev_priv(dev);
struct mac_regs __iomem * regs = vptr->mac_regs;
unsigned long flags;
struct mii_ioctl_data *miidata = if_mii(ifr);
int err;
-
+
switch (cmd) {
case SIOCGMIIPHY:
miidata->phy_id = readb(&regs->MIIADR) & 0x1f;
@@ -3030,7 +3033,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
/**
* velocity_save_context - save registers
- * @vptr: velocity
+ * @vptr: velocity
* @context: buffer for stored context
*
* Retrieve the current configuration from the velocity hardware
@@ -3038,7 +3041,7 @@ static int velocity_mii_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd
* restore functions. This allows us to save things we need across
* power down states
*/
-
+
static void velocity_save_context(struct velocity_info *vptr, struct velocity_context * context)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
@@ -3058,13 +3061,13 @@ static void velocity_save_context(struct velocity_info *vptr, struct velocity_co
/**
* velocity_restore_context - restore registers
- * @vptr: velocity
+ * @vptr: velocity
* @context: buffer for stored context
*
- * Reload the register configuration from the velocity context
+ * Reload the register configuration from the velocity context
* created by velocity_save_context.
*/
-
+
static void velocity_restore_context(struct velocity_info *vptr, struct velocity_context *context)
{
struct mac_regs __iomem * regs = vptr->mac_regs;
diff --git a/drivers/net/via-velocity.h b/drivers/net/via-velocity.h
index f1b2640ebdc..b9e114d36c0 100644
--- a/drivers/net/via-velocity.h
+++ b/drivers/net/via-velocity.h
@@ -29,7 +29,9 @@
#define VELOCITY_NAME "via-velocity"
#define VELOCITY_FULL_DRV_NAM "VIA Networking Velocity Family Gigabit Ethernet Adapter Driver"
-#define VELOCITY_VERSION "1.13"
+#define VELOCITY_VERSION "1.14"
+
+#define VELOCITY_IO_SIZE 256
#define PKT_BUF_SZ 1540
@@ -244,7 +246,7 @@ struct tdesc1 {
struct td_buf {
u32 pa_low;
u16 pa_high;
- u16 bufsize:14;
+ u16 bufsize:14;
u16 reserved:1;
u16 queue:1;
} __attribute__ ((__packed__));
@@ -260,25 +262,6 @@ struct velocity_rd_info {
dma_addr_t skb_dma;
};
-/**
- * alloc_rd_info - allocate an rd info block
- *
- * Alocate and initialize a receive info structure used for keeping
- * track of kernel side information related to each receive
- * descriptor we are using
- */
-
-static inline struct velocity_rd_info *alloc_rd_info(void)
-{
- struct velocity_rd_info *ptr;
- if ((ptr = kmalloc(sizeof(struct velocity_rd_info), GFP_ATOMIC)) == NULL)
- return NULL;
- else {
- memset(ptr, 0, sizeof(struct velocity_rd_info));
- return ptr;
- }
-}
-
/*
* Used to track transmit side buffers.
*/
@@ -1191,7 +1174,6 @@ enum chip_type {
struct velocity_info_tbl {
enum chip_type chip_id;
char *name;
- int io_size;
int txqueue;
u32 flags;
};
@@ -1751,7 +1733,6 @@ struct velocity_info {
struct mac_regs __iomem * mac_regs;
unsigned long memaddr;
unsigned long ioaddr;
- u32 io_size;
u8 rev_id;
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index b5328b0ff92..58b7efbb075 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -134,18 +134,6 @@ config SEALEVEL_4021
The driver will be compiled as a module: the
module will be called sealevel.
-config SYNCLINK_SYNCPPP
- tristate "SyncLink HDLC/SYNCPPP support"
- depends on WAN
- help
- Enables HDLC/SYNCPPP support for the SyncLink WAN driver.
-
- Normally the SyncLink WAN driver works with the main PPP driver
- <file:drivers/net/ppp_generic.c> and pppd program.
- HDLC/SYNCPPP support allows use of the Cisco HDLC/PPP driver
- <file:drivers/net/wan/syncppp.c>. The SyncLink WAN driver (in
- character devices) must also be enabled.
-
# Generic HDLC
config HDLC
tristate "Generic HDLC layer"
@@ -166,7 +154,7 @@ config HDLC
If unsure, say N.
config HDLC_RAW
- bool "Raw HDLC support"
+ tristate "Raw HDLC support"
depends on HDLC
help
Generic HDLC driver supporting raw HDLC over WAN connections.
@@ -174,7 +162,7 @@ config HDLC_RAW
If unsure, say N.
config HDLC_RAW_ETH
- bool "Raw HDLC Ethernet device support"
+ tristate "Raw HDLC Ethernet device support"
depends on HDLC
help
Generic HDLC driver supporting raw HDLC Ethernet device emulation
@@ -185,7 +173,7 @@ config HDLC_RAW_ETH
If unsure, say N.
config HDLC_CISCO
- bool "Cisco HDLC support"
+ tristate "Cisco HDLC support"
depends on HDLC
help
Generic HDLC driver supporting Cisco HDLC over WAN connections.
@@ -193,7 +181,7 @@ config HDLC_CISCO
If unsure, say N.
config HDLC_FR
- bool "Frame Relay support"
+ tristate "Frame Relay support"
depends on HDLC
help
Generic HDLC driver supporting Frame Relay over WAN connections.
@@ -201,7 +189,7 @@ config HDLC_FR
If unsure, say N.
config HDLC_PPP
- bool "Synchronous Point-to-Point Protocol (PPP) support"
+ tristate "Synchronous Point-to-Point Protocol (PPP) support"
depends on HDLC
help
Generic HDLC driver supporting PPP over WAN connections.
@@ -209,7 +197,7 @@ config HDLC_PPP
If unsure, say N.
config HDLC_X25
- bool "X.25 protocol support"
+ tristate "X.25 protocol support"
depends on HDLC && (LAPB=m && HDLC=m || LAPB=y)
help
Generic HDLC driver supporting X.25 over WAN connections.
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 823c6d5ab90..83ec2c87ba3 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
cyclomx-objs := $(cyclomx-y)
-hdlc-y := hdlc_generic.o
-hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o
-hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
-hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
-hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o
-hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
-hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o
-hdlc-objs := $(hdlc-y)
+obj-$(CONFIG_HDLC) += hdlc.o
+obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
+obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
+obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
+obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
+obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
+obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
pc300-y := pc300_drv.o
pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
@@ -28,7 +27,6 @@ obj-$(CONFIG_COSA) += syncppp.o cosa.o
obj-$(CONFIG_FARSYNC) += syncppp.o farsync.o
obj-$(CONFIG_DSCC4) += dscc4.o
obj-$(CONFIG_LANMEDIA) += syncppp.o
-obj-$(CONFIG_SYNCLINK_SYNCPPP) += syncppp.o
obj-$(CONFIG_X25_ASY) += x25_asy.o
obj-$(CONFIG_LANMEDIA) += lmc/
@@ -39,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
obj-$(CONFIG_PC300) += pc300.o
-obj-$(CONFIG_HDLC) += hdlc.o
-ifeq ($(CONFIG_HDLC_PPP),y)
- obj-$(CONFIG_HDLC) += syncppp.o
-endif
obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c
index b60ef02db7b..6b63b350cd5 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -7,7 +7,7 @@
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
*
* Sources of information:
* Hitachi HD64570 SCA User's Manual
@@ -116,27 +116,34 @@ static inline void openwin(card_t *card, u8 page)
#include "hd6457x.c"
+static inline void set_carrier(port_t *port)
+{
+ if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD))
+ netif_carrier_on(port_to_dev(port));
+ else
+ netif_carrier_off(port_to_dev(port));
+}
+
+
static void sca_msci_intr(port_t *port)
{
- struct net_device *dev = port_to_dev(port);
- card_t* card = port_to_card(port);
- u8 stat = sca_in(MSCI1_OFFSET + ST1, card); /* read MSCI ST1 status */
+ u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */
- /* Reset MSCI TX underrun status bit */
- sca_out(stat & ST1_UDRN, MSCI0_OFFSET + ST1, card);
+ /* Reset MSCI TX underrun and CDCD (ignored) status bit */
+ sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port);
if (stat & ST1_UDRN) {
- struct net_device_stats *stats = hdlc_stats(dev);
+ struct net_device_stats *stats = hdlc_stats(port_to_dev(port));
stats->tx_errors++; /* TX Underrun error detected */
stats->tx_fifo_errors++;
}
+ stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */
/* Reset MSCI CDCD status bit - uses ch#2 DCD input */
- sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, card);
+ sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port);
if (stat & ST1_CDCD)
- hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD),
- dev);
+ set_carrier(port);
}
@@ -190,8 +197,7 @@ static int c101_open(struct net_device *dev)
sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port);
sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port);
- hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD), dev);
- printk(KERN_DEBUG "0x%X\n", sca_in(MSCI1_OFFSET + ST3, port));
+ set_carrier(port);
/* enable MSCI1 CDCD interrupt */
sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port);
@@ -378,7 +384,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase)
}
sca_init_sync_port(card); /* Set up C101 memory */
- hdlc_set_carrier(!(sca_in(MSCI1_OFFSET + ST3, card) & ST3_DCD), dev);
+ set_carrier(card);
printk(KERN_INFO "%s: Moxa C101 on IRQ%u,"
" using %u TX + %u RX packets rings\n",
@@ -443,4 +449,5 @@ module_exit(c101_cleanup);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("Moxa C101 serial port driver");
MODULE_LICENSE("GPL v2");
-module_param(hw, charp, 0444); /* hw=irq,ram:irq,... */
+module_param(hw, charp, 0444);
+MODULE_PARM_DESC(hw, "irq,ram:irq,...");
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index e392ee8b37a..1f95b4864ea 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -79,13 +79,11 @@
/* ---------- Headers, macros, data structures ---------- */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fs.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/errno.h>
@@ -393,7 +391,6 @@ static int __init cosa_init(void)
err = -ENODEV;
goto out;
}
- devfs_mk_dir("cosa");
cosa_class = class_create(THIS_MODULE, "cosa");
if (IS_ERR(cosa_class)) {
err = PTR_ERR(cosa_class);
@@ -402,13 +399,6 @@ static int __init cosa_init(void)
for (i=0; i<nr_cards; i++) {
class_device_create(cosa_class, NULL, MKDEV(cosa_major, i),
NULL, "cosa%d", i);
- err = devfs_mk_cdev(MKDEV(cosa_major, i),
- S_IFCHR|S_IRUSR|S_IWUSR,
- "cosa/%d", i);
- if (err) {
- class_device_destroy(cosa_class, MKDEV(cosa_major, i));
- goto out_chrdev;
- }
}
err = 0;
goto out;
@@ -426,12 +416,9 @@ static void __exit cosa_exit(void)
int i;
printk(KERN_INFO "Unloading the cosa module\n");
- for (i=0; i<nr_cards; i++) {
+ for (i=0; i<nr_cards; i++)
class_device_destroy(cosa_class, MKDEV(cosa_major, i));
- devfs_remove("cosa/%d", i);
- }
class_destroy(cosa_class);
- devfs_remove("cosa");
for (cosa=cosa_cards; nr_cards--; cosa++) {
/* Clean up the per-channel data */
for (i=0; i<cosa->nchannels; i++) {
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index 430b1f630fb..a5e7ce1bd16 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -40,7 +40,6 @@
* 1998/08/08 acme Initial version.
*/
-#include <linux/config.h> /* OS configuration options */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/errno.h> /* return codes */
#include <linux/string.h> /* inline memset(), etc. */
diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
index 6e1ec5bf22f..73698755943 100644
--- a/drivers/net/wan/dlci.c
+++ b/drivers/net/wan/dlci.c
@@ -28,7 +28,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h> /* for CONFIG_DLCI_COUNT */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 4505540e3c5..af4d4155905 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -732,15 +732,15 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
ioaddr = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!ioaddr) {
- printk(KERN_ERR "%s: cannot remap MMIO region %lx @ %lx\n",
- DRV_NAME, pci_resource_len(pdev, 0),
- pci_resource_start(pdev, 0));
+ printk(KERN_ERR "%s: cannot remap MMIO region %llx @ %llx\n",
+ DRV_NAME, (unsigned long long)pci_resource_len(pdev, 0),
+ (unsigned long long)pci_resource_start(pdev, 0));
rc = -EIO;
goto err_free_mmio_regions_2;
}
- printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#lx (regs), %#lx (lbi), IRQ %d\n",
- pci_resource_start(pdev, 0),
- pci_resource_start(pdev, 1), pdev->irq);
+ printk(KERN_DEBUG "Siemens DSCC4, MMIO at %#llx (regs), %#llx (lbi), IRQ %d\n",
+ (unsigned long long)pci_resource_start(pdev, 0),
+ (unsigned long long)pci_resource_start(pdev, 1), pdev->irq);
/* Cf errata DS5 p.2 */
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xf8);
@@ -752,7 +752,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev,
priv = pci_get_drvdata(pdev);
- rc = request_irq(pdev->irq, dscc4_irq, SA_SHIRQ, DRV_NAME, priv->root);
+ rc = request_irq(pdev->irq, dscc4_irq, IRQF_SHARED, DRV_NAME, priv->root);
if (rc < 0) {
printk(KERN_WARNING "%s: IRQ %d busy\n", DRV_NAME, pdev->irq);
goto err_release_4;
@@ -2062,7 +2062,7 @@ static struct pci_driver dscc4_driver = {
static int __init dscc4_init_module(void)
{
- return pci_module_init(&dscc4_driver);
+ return pci_register_driver(&dscc4_driver);
}
static void __exit dscc4_cleanup_module(void)
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 7981a2c7906..564351aafa4 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2519,7 +2519,7 @@ fst_add_one(struct pci_dev *pdev, const struct pci_device_id *ent)
dbg(DBG_PCI, "kernel mem %p, ctlmem %p\n", card->mem, card->ctlmem);
/* Register the interrupt handler */
- if (request_irq(pdev->irq, fst_intr, SA_SHIRQ, FST_DEV_NAME, card)) {
+ if (request_irq(pdev->irq, fst_intr, IRQF_SHARED, FST_DEV_NAME, card)) {
printk_err("Unable to register interrupt %d\n", card->irq);
pci_release_regions(pdev);
pci_disable_device(pdev);
@@ -2697,7 +2697,7 @@ fst_init(void)
for (i = 0; i < FST_MAX_CARDS; i++)
fst_card_array[i] = NULL;
spin_lock_init(&fst_work_q_lock);
- return pci_module_init(&fst_driver);
+ return pci_register_driver(&fst_driver);
}
static void __exit
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
index d3743321a97..dce2bb317b8 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -168,6 +168,23 @@ static inline u32 buffer_offset(port_t *port, u16 desc, int transmit)
}
+static inline void sca_set_carrier(port_t *port)
+{
+ if (!(sca_in(get_msci(port) + ST3, port_to_card(port)) & ST3_DCD)) {
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "%s: sca_set_carrier on\n",
+ port_to_dev(port)->name);
+#endif
+ netif_carrier_on(port_to_dev(port));
+ } else {
+#ifdef DEBUG_LINK
+ printk(KERN_DEBUG "%s: sca_set_carrier off\n",
+ port_to_dev(port)->name);
+#endif
+ netif_carrier_off(port_to_dev(port));
+ }
+}
+
static void sca_init_sync_port(port_t *port)
{
@@ -237,9 +254,7 @@ static void sca_init_sync_port(port_t *port)
sca_out(DIR_BOFE, DIR_TX(phy_node(port)), card);
}
}
-
- hdlc_set_carrier(!(sca_in(get_msci(port) + ST3, card) & ST3_DCD),
- port_to_dev(port));
+ sca_set_carrier(port);
}
@@ -262,8 +277,7 @@ static inline void sca_msci_intr(port_t *port)
}
if (stat & ST1_CDCD)
- hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD),
- port_to_dev(port));
+ sca_set_carrier(port);
}
#endif
@@ -566,7 +580,7 @@ static void sca_open(struct net_device *dev)
- all DMA interrupts
*/
- hdlc_set_carrier(!(sca_in(msci + ST3, card) & ST3_DCD), dev);
+ sca_set_carrier(port);
#ifdef __HD64570_H
/* MSCI TX INT and RX INT A IRQ enable */
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc.c
index 57f9538b8fb..db354e0edbe 100644
--- a/drivers/net/wan/hdlc_generic.c
+++ b/drivers/net/wan/hdlc.c
@@ -1,7 +1,7 @@
/*
* Generic HDLC support routines for Linux
*
- * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -17,12 +17,11 @@
* Use sethdlc utility to set line parameters, protocol and PVCs
*
* How does it work:
- * - proto.open(), close(), start(), stop() calls are serialized.
+ * - proto->open(), close(), start(), stop() calls are serialized.
* The order is: open, [ start, stop ... ] close ...
- * - proto.start() and stop() are called with spin_lock_irq held.
+ * - proto->start() and stop() are called with spin_lock_irq held.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -35,13 +34,16 @@
#include <linux/inetdevice.h>
#include <linux/lapb.h>
#include <linux/rtnetlink.h>
+#include <linux/notifier.h>
#include <linux/hdlc.h>
-static const char* version = "HDLC support module revision 1.18";
+static const char* version = "HDLC support module revision 1.20";
#undef DEBUG_LINK
+static struct hdlc_proto *first_proto = NULL;
+
static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -63,68 +65,62 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p, struct net_device *orig_dev)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->proto.netif_rx)
- return hdlc->proto.netif_rx(skb);
+ struct hdlc_device_desc *desc = dev_to_desc(dev);
+ if (desc->netif_rx)
+ return desc->netif_rx(skb);
- hdlc->stats.rx_dropped++; /* Shouldn't happen */
+ desc->stats.rx_dropped++; /* Shouldn't happen */
dev_kfree_skb(skb);
return NET_RX_DROP;
}
-static void __hdlc_set_carrier_on(struct net_device *dev)
+static inline void hdlc_proto_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->proto.start)
- return hdlc->proto.start(dev);
-#if 0
-#ifdef DEBUG_LINK
- if (netif_carrier_ok(dev))
- printk(KERN_ERR "hdlc_set_carrier_on(): already on\n");
-#endif
- netif_carrier_on(dev);
-#endif
+ if (hdlc->proto->start)
+ return hdlc->proto->start(dev);
}
-static void __hdlc_set_carrier_off(struct net_device *dev)
+static inline void hdlc_proto_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->proto.stop)
- return hdlc->proto.stop(dev);
-
-#if 0
-#ifdef DEBUG_LINK
- if (!netif_carrier_ok(dev))
- printk(KERN_ERR "hdlc_set_carrier_off(): already off\n");
-#endif
- netif_carrier_off(dev);
-#endif
+ if (hdlc->proto->stop)
+ return hdlc->proto->stop(dev);
}
-void hdlc_set_carrier(int on, struct net_device *dev)
+static int hdlc_device_event(struct notifier_block *this, unsigned long event,
+ void *ptr)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct net_device *dev = ptr;
+ hdlc_device *hdlc;
unsigned long flags;
- on = on ? 1 : 0;
+ int on;
+
+ if (dev->get_stats != hdlc_get_stats)
+ return NOTIFY_DONE; /* not an HDLC device */
+
+ if (event != NETDEV_CHANGE)
+ return NOTIFY_DONE; /* Only interrested in carrier changes */
+
+ on = netif_carrier_ok(dev);
#ifdef DEBUG_LINK
- printk(KERN_DEBUG "hdlc_set_carrier %i\n", on);
+ printk(KERN_DEBUG "%s: hdlc_device_event NETDEV_CHANGE, carrier %i\n",
+ dev->name, on);
#endif
+ hdlc = dev_to_hdlc(dev);
spin_lock_irqsave(&hdlc->state_lock, flags);
if (hdlc->carrier == on)
goto carrier_exit; /* no change in DCD line level */
-#ifdef DEBUG_LINK
- printk(KERN_INFO "%s: carrier %s\n", dev->name, on ? "ON" : "off");
-#endif
hdlc->carrier = on;
if (!hdlc->open)
@@ -132,14 +128,15 @@ void hdlc_set_carrier(int on, struct net_device *dev)
if (hdlc->carrier) {
printk(KERN_INFO "%s: Carrier detected\n", dev->name);
- __hdlc_set_carrier_on(dev);
+ hdlc_proto_start(dev);
} else {
printk(KERN_INFO "%s: Carrier lost\n", dev->name);
- __hdlc_set_carrier_off(dev);
+ hdlc_proto_stop(dev);
}
carrier_exit:
spin_unlock_irqrestore(&hdlc->state_lock, flags);
+ return NOTIFY_DONE;
}
@@ -149,15 +146,15 @@ int hdlc_open(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
- printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n",
+ printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
hdlc->carrier, hdlc->open);
#endif
- if (hdlc->proto.id == -1)
+ if (hdlc->proto == NULL)
return -ENOSYS; /* no protocol attached */
- if (hdlc->proto.open) {
- int result = hdlc->proto.open(dev);
+ if (hdlc->proto->open) {
+ int result = hdlc->proto->open(dev);
if (result)
return result;
}
@@ -166,7 +163,7 @@ int hdlc_open(struct net_device *dev)
if (hdlc->carrier) {
printk(KERN_INFO "%s: Carrier detected\n", dev->name);
- __hdlc_set_carrier_on(dev);
+ hdlc_proto_start(dev);
} else
printk(KERN_INFO "%s: No carrier\n", dev->name);
@@ -183,7 +180,7 @@ void hdlc_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
- printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n",
+ printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
hdlc->carrier, hdlc->open);
#endif
@@ -191,72 +188,38 @@ void hdlc_close(struct net_device *dev)
hdlc->open = 0;
if (hdlc->carrier)
- __hdlc_set_carrier_off(dev);
+ hdlc_proto_stop(dev);
spin_unlock_irq(&hdlc->state_lock);
- if (hdlc->proto.close)
- hdlc->proto.close(dev);
+ if (hdlc->proto->close)
+ hdlc->proto->close(dev);
}
-#ifndef CONFIG_HDLC_RAW
-#define hdlc_raw_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_RAW_ETH
-#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_PPP
-#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_CISCO
-#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_FR
-#define hdlc_fr_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_X25
-#define hdlc_x25_ioctl(dev, ifr) -ENOSYS
-#endif
-
-
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
- unsigned int proto;
+ struct hdlc_proto *proto = first_proto;
+ int result;
if (cmd != SIOCWANDEV)
return -EINVAL;
- switch(ifr->ifr_settings.type) {
- case IF_PROTO_HDLC:
- case IF_PROTO_HDLC_ETH:
- case IF_PROTO_PPP:
- case IF_PROTO_CISCO:
- case IF_PROTO_FR:
- case IF_PROTO_X25:
- proto = ifr->ifr_settings.type;
- break;
-
- default:
- proto = hdlc->proto.id;
+ if (dev_to_hdlc(dev)->proto) {
+ result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
+ if (result != -EINVAL)
+ return result;
}
- switch(proto) {
- case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
- case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr);
- case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr);
- case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr);
- case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr);
- case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
- default: return -EINVAL;
+ /* Not handled by currently attached protocol (if any) */
+
+ while (proto) {
+ if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
+ return result;
+ proto = proto->next;
}
+ return -EINVAL;
}
void hdlc_setup(struct net_device *dev)
@@ -272,8 +235,6 @@ void hdlc_setup(struct net_device *dev)
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- hdlc->proto.id = -1;
- hdlc->proto.detach = NULL;
hdlc->carrier = 1;
hdlc->open = 0;
spin_lock_init(&hdlc->state_lock);
@@ -282,7 +243,8 @@ void hdlc_setup(struct net_device *dev)
struct net_device *alloc_hdlcdev(void *priv)
{
struct net_device *dev;
- dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+ dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
+ sizeof(hdlc_device), "hdlc%d", hdlc_setup);
if (dev)
dev_to_hdlc(dev)->priv = priv;
return dev;
@@ -291,24 +253,85 @@ struct net_device *alloc_hdlcdev(void *priv)
void unregister_hdlc_device(struct net_device *dev)
{
rtnl_lock();
- hdlc_proto_detach(dev_to_hdlc(dev));
unregister_netdevice(dev);
+ detach_hdlc_protocol(dev);
rtnl_unlock();
}
+int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
+ int (*rx)(struct sk_buff *skb), size_t size)
+{
+ detach_hdlc_protocol(dev);
+
+ if (!try_module_get(proto->module))
+ return -ENOSYS;
+
+ if (size)
+ if ((dev_to_hdlc(dev)->state = kmalloc(size,
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING "Memory squeeze on"
+ " hdlc_proto_attach()\n");
+ module_put(proto->module);
+ return -ENOBUFS;
+ }
+ dev_to_hdlc(dev)->proto = proto;
+ dev_to_desc(dev)->netif_rx = rx;
+ return 0;
+}
+
+
+void detach_hdlc_protocol(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+
+ if (hdlc->proto) {
+ if (hdlc->proto->detach)
+ hdlc->proto->detach(dev);
+ module_put(hdlc->proto->module);
+ hdlc->proto = NULL;
+ }
+ kfree(hdlc->state);
+ hdlc->state = NULL;
+}
+
+
+void register_hdlc_protocol(struct hdlc_proto *proto)
+{
+ proto->next = first_proto;
+ first_proto = proto;
+}
+
+
+void unregister_hdlc_protocol(struct hdlc_proto *proto)
+{
+ struct hdlc_proto **p = &first_proto;
+ while (*p) {
+ if (*p == proto) {
+ *p = proto->next;
+ return;
+ }
+ p = &((*p)->next);
+ }
+}
+
+
+
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("HDLC support module");
MODULE_LICENSE("GPL v2");
EXPORT_SYMBOL(hdlc_open);
EXPORT_SYMBOL(hdlc_close);
-EXPORT_SYMBOL(hdlc_set_carrier);
EXPORT_SYMBOL(hdlc_ioctl);
EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
EXPORT_SYMBOL(unregister_hdlc_device);
+EXPORT_SYMBOL(register_hdlc_protocol);
+EXPORT_SYMBOL(unregister_hdlc_protocol);
+EXPORT_SYMBOL(attach_hdlc_protocol);
+EXPORT_SYMBOL(detach_hdlc_protocol);
static struct packet_type hdlc_packet_type = {
.type = __constant_htons(ETH_P_HDLC),
@@ -316,9 +339,18 @@ static struct packet_type hdlc_packet_type = {
};
+static struct notifier_block hdlc_notifier = {
+ .notifier_call = hdlc_device_event,
+};
+
+
static int __init hdlc_module_init(void)
{
+ int result;
+
printk(KERN_INFO "%s\n", version);
+ if ((result = register_netdevice_notifier(&hdlc_notifier)) != 0)
+ return result;
dev_add_pack(&hdlc_packet_type);
return 0;
}
@@ -328,6 +360,7 @@ static int __init hdlc_module_init(void)
static void __exit hdlc_module_exit(void)
{
dev_remove_pack(&hdlc_packet_type);
+ unregister_netdevice_notifier(&hdlc_notifier);
}
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 1fd04662c4f..b0bc5ddcf1b 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Cisco HDLC support
*
- * Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -34,17 +34,56 @@
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+struct hdlc_header {
+ u8 address;
+ u8 control;
+ u16 protocol;
+}__attribute__ ((packed));
+
+
+struct cisco_packet {
+ u32 type; /* code */
+ u32 par1;
+ u32 par2;
+ u16 rel; /* reliability */
+ u32 time;
+}__attribute__ ((packed));
+#define CISCO_PACKET_LEN 18
+#define CISCO_BIG_PACKET_LEN 20
+
+
+struct cisco_state {
+ cisco_proto settings;
+
+ struct timer_list timer;
+ unsigned long last_poll;
+ int up;
+ int request_sent;
+ u32 txseq; /* TX sequence number */
+ u32 rxseq; /* RX sequence number */
+};
+
+
+static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+
+static inline struct cisco_state * state(hdlc_device *hdlc)
+{
+ return(struct cisco_state *)(hdlc->state);
+}
+
+
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
u16 type, void *daddr, void *saddr,
unsigned int len)
{
- hdlc_header *data;
+ struct hdlc_header *data;
#ifdef DEBUG_HARD_HEADER
printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
#endif
- skb_push(skb, sizeof(hdlc_header));
- data = (hdlc_header*)skb->data;
+ skb_push(skb, sizeof(struct hdlc_header));
+ data = (struct hdlc_header*)skb->data;
if (type == CISCO_KEEPALIVE)
data->address = CISCO_MULTICAST;
else
@@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
data->control = 0;
data->protocol = htons(type);
- return sizeof(hdlc_header);
+ return sizeof(struct hdlc_header);
}
@@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
u32 par1, u32 par2)
{
struct sk_buff *skb;
- cisco_packet *data;
+ struct cisco_packet *data;
- skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
+ skb = dev_alloc_skb(sizeof(struct hdlc_header) +
+ sizeof(struct cisco_packet));
if (!skb) {
printk(KERN_WARNING
"%s: Memory squeeze on cisco_keepalive_send()\n",
@@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
}
skb_reserve(skb, 4);
cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
- data = (cisco_packet*)(skb->data + 4);
+ data = (struct cisco_packet*)(skb->data + 4);
data->type = htonl(type);
data->par1 = htonl(par1);
@@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
/* we will need do_div here if 1000 % HZ != 0 */
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
- skb_put(skb, sizeof(cisco_packet));
+ skb_put(skb, sizeof(struct cisco_packet));
skb->priority = TC_PRIO_CONTROL;
skb->dev = dev;
skb->nh.raw = skb->data;
@@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
{
- hdlc_header *data = (hdlc_header*)skb->data;
+ struct hdlc_header *data = (struct hdlc_header*)skb->data;
- if (skb->len < sizeof(hdlc_header))
+ if (skb->len < sizeof(struct hdlc_header))
return __constant_htons(ETH_P_HDLC);
if (data->address != CISCO_MULTICAST &&
@@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
case __constant_htons(ETH_P_IP):
case __constant_htons(ETH_P_IPX):
case __constant_htons(ETH_P_IPV6):
- skb_pull(skb, sizeof(hdlc_header));
+ skb_pull(skb, sizeof(struct hdlc_header));
return data->protocol;
default:
return __constant_htons(ETH_P_HDLC);
@@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev);
- hdlc_header *data = (hdlc_header*)skb->data;
- cisco_packet *cisco_data;
+ struct hdlc_header *data = (struct hdlc_header*)skb->data;
+ struct cisco_packet *cisco_data;
struct in_device *in_dev;
- u32 addr, mask;
+ __be32 addr, mask;
- if (skb->len < sizeof(hdlc_header))
+ if (skb->len < sizeof(struct hdlc_header))
goto rx_error;
if (data->address != CISCO_MULTICAST &&
@@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb)
return NET_RX_SUCCESS;
case CISCO_KEEPALIVE:
- if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
- skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
- printk(KERN_INFO "%s: Invalid length of Cisco "
- "control packet (%d bytes)\n",
- dev->name, skb->len);
+ if ((skb->len != sizeof(struct hdlc_header) +
+ CISCO_PACKET_LEN) &&
+ (skb->len != sizeof(struct hdlc_header) +
+ CISCO_BIG_PACKET_LEN)) {
+ printk(KERN_INFO "%s: Invalid length of Cisco control"
+ " packet (%d bytes)\n", dev->name, skb->len);
goto rx_error;
}
- cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header));
+ cisco_data = (struct cisco_packet*)(skb->data + sizeof
+ (struct hdlc_header));
switch(ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
@@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb)
goto rx_error;
case CISCO_KEEPALIVE_REQ:
- hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
- if (hdlc->state.cisco.request_sent &&
- ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
- hdlc->state.cisco.last_poll = jiffies;
- if (!hdlc->state.cisco.up) {
+ state(hdlc)->rxseq = ntohl(cisco_data->par1);
+ if (state(hdlc)->request_sent &&
+ ntohl(cisco_data->par2) == state(hdlc)->txseq) {
+ state(hdlc)->last_poll = jiffies;
+ if (!state(hdlc)->up) {
u32 sec, min, hrs, days;
sec = ntohl(cisco_data->time) / 1000;
min = sec / 60; sec -= min * 60;
@@ -192,10 +234,8 @@ static int cisco_rx(struct sk_buff *skb)
"uptime %ud%uh%um%us)\n",
dev->name, days, hrs,
min, sec);
-#if 0
- netif_carrier_on(dev);
-#endif
- hdlc->state.cisco.up = 1;
+ netif_dormant_off(dev);
+ state(hdlc)->up = 1;
}
}
@@ -210,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
return NET_RX_DROP;
rx_error:
- hdlc->stats.rx_errors++; /* Mark error */
+ dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -222,25 +262,22 @@ static void cisco_timer(unsigned long arg)
struct net_device *dev = (struct net_device *)arg;
hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->state.cisco.up &&
- time_after(jiffies, hdlc->state.cisco.last_poll +
- hdlc->state.cisco.settings.timeout * HZ)) {
- hdlc->state.cisco.up = 0;
+ if (state(hdlc)->up &&
+ time_after(jiffies, state(hdlc)->last_poll +
+ state(hdlc)->settings.timeout * HZ)) {
+ state(hdlc)->up = 0;
printk(KERN_INFO "%s: Link down\n", dev->name);
-#if 0
- netif_carrier_off(dev);
-#endif
+ netif_dormant_on(dev);
}
- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
- ++hdlc->state.cisco.txseq,
- hdlc->state.cisco.rxseq);
- hdlc->state.cisco.request_sent = 1;
- hdlc->state.cisco.timer.expires = jiffies +
- hdlc->state.cisco.settings.interval * HZ;
- hdlc->state.cisco.timer.function = cisco_timer;
- hdlc->state.cisco.timer.data = arg;
- add_timer(&hdlc->state.cisco.timer);
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
+ state(hdlc)->rxseq);
+ state(hdlc)->request_sent = 1;
+ state(hdlc)->timer.expires = jiffies +
+ state(hdlc)->settings.interval * HZ;
+ state(hdlc)->timer.function = cisco_timer;
+ state(hdlc)->timer.data = arg;
+ add_timer(&state(hdlc)->timer);
}
@@ -248,15 +285,15 @@ static void cisco_timer(unsigned long arg)
static void cisco_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- hdlc->state.cisco.up = 0;
- hdlc->state.cisco.request_sent = 0;
- hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
-
- init_timer(&hdlc->state.cisco.timer);
- hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
- hdlc->state.cisco.timer.function = cisco_timer;
- hdlc->state.cisco.timer.data = (unsigned long)dev;
- add_timer(&hdlc->state.cisco.timer);
+ state(hdlc)->up = 0;
+ state(hdlc)->request_sent = 0;
+ state(hdlc)->txseq = state(hdlc)->rxseq = 0;
+
+ init_timer(&state(hdlc)->timer);
+ state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
+ state(hdlc)->timer.function = cisco_timer;
+ state(hdlc)->timer.data = (unsigned long)dev;
+ add_timer(&state(hdlc)->timer);
}
@@ -264,18 +301,24 @@ static void cisco_start(struct net_device *dev)
static void cisco_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- del_timer_sync(&hdlc->state.cisco.timer);
-#if 0
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
-#endif
- hdlc->state.cisco.up = 0;
- hdlc->state.cisco.request_sent = 0;
+ del_timer_sync(&state(hdlc)->timer);
+ netif_dormant_on(dev);
+ state(hdlc)->up = 0;
+ state(hdlc)->request_sent = 0;
}
-int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .start = cisco_start,
+ .stop = cisco_stop,
+ .type_trans = cisco_type_trans,
+ .ioctl = cisco_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
{
cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
const size_t size = sizeof(cisco_proto);
@@ -285,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_CISCO;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
+ if (copy_to_user(cisco_s, &state(hdlc)->settings, size))
return -EFAULT;
return 0;
@@ -309,27 +354,46 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
-
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memcpy(&hdlc->state.cisco.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+ result = attach_hdlc_protocol(dev, &proto, cisco_rx,
+ sizeof(struct cisco_state));
+ if (result)
+ return result;
- hdlc->proto.start = cisco_start;
- hdlc->proto.stop = cisco_stop;
- hdlc->proto.netif_rx = cisco_rx;
- hdlc->proto.type_trans = cisco_type_trans;
- hdlc->proto.id = IF_PROTO_CISCO;
+ memcpy(&state(hdlc)->settings, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = cisco_hard_header;
dev->hard_header_cache = NULL;
dev->type = ARPHRD_CISCO;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->addr_len = 0;
+ netif_dormant_on(dev);
return 0;
}
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 523afe17564..b45ab680d2d 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Frame Relay support
*
- * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -52,6 +52,8 @@
#undef DEBUG_PKT
#undef DEBUG_ECN
#undef DEBUG_LINK
+#undef DEBUG_PROTO
+#undef DEBUG_PVC
#define FR_UI 0x03
#define FR_PAD 0x00
@@ -115,13 +117,53 @@ typedef struct {
}__attribute__ ((packed)) fr_hdr;
+typedef struct pvc_device_struct {
+ struct net_device *frad;
+ struct net_device *main;
+ struct net_device *ether; /* bridged Ethernet interface */
+ struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
+ int dlci;
+ int open_count;
+
+ struct {
+ unsigned int new: 1;
+ unsigned int active: 1;
+ unsigned int exist: 1;
+ unsigned int deleted: 1;
+ unsigned int fecn: 1;
+ unsigned int becn: 1;
+ unsigned int bandwidth; /* Cisco LMI reporting only */
+ }state;
+}pvc_device;
+
+
+struct frad_state {
+ fr_proto settings;
+ pvc_device *first_pvc;
+ int dce_pvc_count;
+
+ struct timer_list timer;
+ unsigned long last_poll;
+ int reliable;
+ int dce_changed;
+ int request;
+ int fullrep_sent;
+ u32 last_errors; /* last errors bit list */
+ u8 n391cnt;
+ u8 txseq; /* TX sequence number */
+ u8 rxseq; /* RX sequence number */
+};
+
+
+static int fr_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+
static inline u16 q922_to_dlci(u8 *hdr)
{
return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
}
-
static inline void dlci_to_q922(u8 *hdr, u16 dlci)
{
hdr[0] = (dlci >> 2) & 0xFC;
@@ -129,10 +171,21 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci)
}
+static inline struct frad_state * state(hdlc_device *hdlc)
+{
+ return(struct frad_state *)(hdlc->state);
+}
+
+
+static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+{
+ return dev->priv;
+}
+
static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
{
- pvc_device *pvc = hdlc->state.fr.first_pvc;
+ pvc_device *pvc = state(hdlc)->first_pvc;
while (pvc) {
if (pvc->dlci == dlci)
@@ -146,10 +199,10 @@ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
}
-static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
+static pvc_device* add_pvc(struct net_device *dev, u16 dlci)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
+ pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc;
while (*pvc_p) {
if ((*pvc_p)->dlci == dlci)
@@ -160,12 +213,15 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
}
pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
+#ifdef DEBUG_PVC
+ printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev);
+#endif
if (!pvc)
return NULL;
memset(pvc, 0, sizeof(pvc_device));
pvc->dlci = dlci;
- pvc->master = dev;
+ pvc->frad = dev;
pvc->next = *pvc_p; /* Put it in the chain */
*pvc_p = pvc;
return pvc;
@@ -174,7 +230,7 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
static inline int pvc_is_used(pvc_device *pvc)
{
- return pvc->main != NULL || pvc->ether != NULL;
+ return pvc->main || pvc->ether;
}
@@ -200,11 +256,14 @@ static inline void pvc_carrier(int on, pvc_device *pvc)
static inline void delete_unused_pvcs(hdlc_device *hdlc)
{
- pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
+ pvc_device **pvc_p = &state(hdlc)->first_pvc;
while (*pvc_p) {
if (!pvc_is_used(*pvc_p)) {
pvc_device *pvc = *pvc_p;
+#ifdef DEBUG_PVC
+ printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc);
+#endif
*pvc_p = pvc->next;
kfree(pvc);
continue;
@@ -295,16 +354,16 @@ static int pvc_open(struct net_device *dev)
{
pvc_device *pvc = dev_to_pvc(dev);
- if ((pvc->master->flags & IFF_UP) == 0)
- return -EIO; /* Master must be UP in order to activate PVC */
+ if ((pvc->frad->flags & IFF_UP) == 0)
+ return -EIO; /* Frad must be UP in order to activate PVC */
if (pvc->open_count++ == 0) {
- hdlc_device *hdlc = dev_to_hdlc(pvc->master);
- if (hdlc->state.fr.settings.lmi == LMI_NONE)
- pvc->state.active = hdlc->carrier;
+ hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
+ if (state(hdlc)->settings.lmi == LMI_NONE)
+ pvc->state.active = netif_carrier_ok(pvc->frad);
pvc_carrier(pvc->state.active, pvc);
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->dce_changed = 1;
}
return 0;
}
@@ -316,12 +375,12 @@ static int pvc_close(struct net_device *dev)
pvc_device *pvc = dev_to_pvc(dev);
if (--pvc->open_count == 0) {
- hdlc_device *hdlc = dev_to_hdlc(pvc->master);
- if (hdlc->state.fr.settings.lmi == LMI_NONE)
+ hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
+ if (state(hdlc)->settings.lmi == LMI_NONE)
pvc->state.active = 0;
- if (hdlc->state.fr.settings.dce) {
- hdlc->state.fr.dce_changed = 1;
+ if (state(hdlc)->settings.dce) {
+ state(hdlc)->dce_changed = 1;
pvc->state.active = 0;
}
}
@@ -348,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
info.dlci = pvc->dlci;
- memcpy(info.master, pvc->master->name, IFNAMSIZ);
+ memcpy(info.master, pvc->frad->name, IFNAMSIZ);
if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
&info, sizeof(info)))
return -EFAULT;
@@ -361,7 +420,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
{
- return netdev_priv(dev);
+ return &dev_to_desc(dev)->stats;
}
@@ -393,7 +452,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_packets++;
if (pvc->state.fecn) /* TX Congestion counter */
stats->tx_compressed++;
- skb->dev = pvc->master;
+ skb->dev = pvc->frad;
dev_queue_xmit(skb);
return 0;
}
@@ -419,7 +478,7 @@ static int pvc_change_mtu(struct net_device *dev, int new_mtu)
static inline void fr_log_dlci_active(pvc_device *pvc)
{
printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
- pvc->master->name,
+ pvc->frad->name,
pvc->dlci,
pvc->main ? pvc->main->name : "",
pvc->main && pvc->ether ? " " : "",
@@ -438,21 +497,20 @@ static inline u8 fr_lmi_nextseq(u8 x)
}
-
static void fr_lmi_send(struct net_device *dev, int fullrep)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
struct sk_buff *skb;
- pvc_device *pvc = hdlc->state.fr.first_pvc;
- int lmi = hdlc->state.fr.settings.lmi;
- int dce = hdlc->state.fr.settings.dce;
+ pvc_device *pvc = state(hdlc)->first_pvc;
+ int lmi = state(hdlc)->settings.lmi;
+ int dce = state(hdlc)->settings.dce;
int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
u8 *data;
int i = 0;
if (dce && fullrep) {
- len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
+ len += state(hdlc)->dce_pvc_count * (2 + stat_len);
if (len > HDLC_MAX_MRU) {
printk(KERN_WARNING "%s: Too many PVCs while sending "
"LMI full report\n", dev->name);
@@ -486,8 +544,9 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
data[i++] = LMI_INTEG_LEN;
- data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
- data[i++] = hdlc->state.fr.rxseq;
+ data[i++] = state(hdlc)->txseq =
+ fr_lmi_nextseq(state(hdlc)->txseq);
+ data[i++] = state(hdlc)->rxseq;
if (dce && fullrep) {
while (pvc) {
@@ -496,7 +555,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
data[i++] = stat_len;
/* LMI start/restart */
- if (hdlc->state.fr.reliable && !pvc->state.exist) {
+ if (state(hdlc)->reliable && !pvc->state.exist) {
pvc->state.exist = pvc->state.new = 1;
fr_log_dlci_active(pvc);
}
@@ -541,19 +600,15 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
static void fr_set_link_state(int reliable, struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- pvc_device *pvc = hdlc->state.fr.first_pvc;
+ pvc_device *pvc = state(hdlc)->first_pvc;
- hdlc->state.fr.reliable = reliable;
+ state(hdlc)->reliable = reliable;
if (reliable) {
-#if 0
- if (!netif_carrier_ok(dev))
- netif_carrier_on(dev);
-#endif
-
- hdlc->state.fr.n391cnt = 0; /* Request full status */
- hdlc->state.fr.dce_changed = 1;
+ netif_dormant_off(dev);
+ state(hdlc)->n391cnt = 0; /* Request full status */
+ state(hdlc)->dce_changed = 1;
- if (hdlc->state.fr.settings.lmi == LMI_NONE) {
+ if (state(hdlc)->settings.lmi == LMI_NONE) {
while (pvc) { /* Activate all PVCs */
pvc_carrier(1, pvc);
pvc->state.exist = pvc->state.active = 1;
@@ -562,16 +617,12 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
}
}
} else {
-#if 0
- if (netif_carrier_ok(dev))
- netif_carrier_off(dev);
-#endif
-
+ netif_dormant_on(dev);
while (pvc) { /* Deactivate all PVCs */
pvc_carrier(0, pvc);
pvc->state.exist = pvc->state.active = 0;
pvc->state.new = 0;
- if (!hdlc->state.fr.settings.dce)
+ if (!state(hdlc)->settings.dce)
pvc->state.bandwidth = 0;
pvc = pvc->next;
}
@@ -579,7 +630,6 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
}
-
static void fr_timer(unsigned long arg)
{
struct net_device *dev = (struct net_device *)arg;
@@ -587,62 +637,61 @@ static void fr_timer(unsigned long arg)
int i, cnt = 0, reliable;
u32 list;
- if (hdlc->state.fr.settings.dce) {
- reliable = hdlc->state.fr.request &&
- time_before(jiffies, hdlc->state.fr.last_poll +
- hdlc->state.fr.settings.t392 * HZ);
- hdlc->state.fr.request = 0;
+ if (state(hdlc)->settings.dce) {
+ reliable = state(hdlc)->request &&
+ time_before(jiffies, state(hdlc)->last_poll +
+ state(hdlc)->settings.t392 * HZ);
+ state(hdlc)->request = 0;
} else {
- hdlc->state.fr.last_errors <<= 1; /* Shift the list */
- if (hdlc->state.fr.request) {
- if (hdlc->state.fr.reliable)
+ state(hdlc)->last_errors <<= 1; /* Shift the list */
+ if (state(hdlc)->request) {
+ if (state(hdlc)->reliable)
printk(KERN_INFO "%s: No LMI status reply "
"received\n", dev->name);
- hdlc->state.fr.last_errors |= 1;
+ state(hdlc)->last_errors |= 1;
}
- list = hdlc->state.fr.last_errors;
- for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
+ list = state(hdlc)->last_errors;
+ for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1)
cnt += (list & 1); /* errors count */
- reliable = (cnt < hdlc->state.fr.settings.n392);
+ reliable = (cnt < state(hdlc)->settings.n392);
}
- if (hdlc->state.fr.reliable != reliable) {
+ if (state(hdlc)->reliable != reliable) {
printk(KERN_INFO "%s: Link %sreliable\n", dev->name,
reliable ? "" : "un");
fr_set_link_state(reliable, dev);
}
- if (hdlc->state.fr.settings.dce)
- hdlc->state.fr.timer.expires = jiffies +
- hdlc->state.fr.settings.t392 * HZ;
+ if (state(hdlc)->settings.dce)
+ state(hdlc)->timer.expires = jiffies +
+ state(hdlc)->settings.t392 * HZ;
else {
- if (hdlc->state.fr.n391cnt)
- hdlc->state.fr.n391cnt--;
+ if (state(hdlc)->n391cnt)
+ state(hdlc)->n391cnt--;
- fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
+ fr_lmi_send(dev, state(hdlc)->n391cnt == 0);
- hdlc->state.fr.last_poll = jiffies;
- hdlc->state.fr.request = 1;
- hdlc->state.fr.timer.expires = jiffies +
- hdlc->state.fr.settings.t391 * HZ;
+ state(hdlc)->last_poll = jiffies;
+ state(hdlc)->request = 1;
+ state(hdlc)->timer.expires = jiffies +
+ state(hdlc)->settings.t391 * HZ;
}
- hdlc->state.fr.timer.function = fr_timer;
- hdlc->state.fr.timer.data = arg;
- add_timer(&hdlc->state.fr.timer);
+ state(hdlc)->timer.function = fr_timer;
+ state(hdlc)->timer.data = arg;
+ add_timer(&state(hdlc)->timer);
}
-
static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
pvc_device *pvc;
u8 rxseq, txseq;
- int lmi = hdlc->state.fr.settings.lmi;
- int dce = hdlc->state.fr.settings.dce;
+ int lmi = state(hdlc)->settings.lmi;
+ int dce = state(hdlc)->settings.dce;
int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
@@ -653,8 +702,8 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
NLPID_CCITT_ANSI_LMI)) {
- printk(KERN_INFO "%s: Received non-LMI frame with LMI"
- " DLCI\n", dev->name);
+ printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
+ dev->name);
return 1;
}
@@ -714,53 +763,53 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
}
i++;
- hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
+ state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */
rxseq = skb->data[i++]; /* Should confirm our sequence */
- txseq = hdlc->state.fr.txseq;
+ txseq = state(hdlc)->txseq;
if (dce)
- hdlc->state.fr.last_poll = jiffies;
+ state(hdlc)->last_poll = jiffies;
error = 0;
- if (!hdlc->state.fr.reliable)
+ if (!state(hdlc)->reliable)
error = 1;
- if (rxseq == 0 || rxseq != txseq) {
- hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
+ if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */
+ state(hdlc)->n391cnt = 0;
error = 1;
}
if (dce) {
- if (hdlc->state.fr.fullrep_sent && !error) {
+ if (state(hdlc)->fullrep_sent && !error) {
/* Stop sending full report - the last one has been confirmed by DTE */
- hdlc->state.fr.fullrep_sent = 0;
- pvc = hdlc->state.fr.first_pvc;
+ state(hdlc)->fullrep_sent = 0;
+ pvc = state(hdlc)->first_pvc;
while (pvc) {
if (pvc->state.new) {
pvc->state.new = 0;
/* Tell DTE that new PVC is now active */
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->dce_changed = 1;
}
pvc = pvc->next;
}
}
- if (hdlc->state.fr.dce_changed) {
+ if (state(hdlc)->dce_changed) {
reptype = LMI_FULLREP;
- hdlc->state.fr.fullrep_sent = 1;
- hdlc->state.fr.dce_changed = 0;
+ state(hdlc)->fullrep_sent = 1;
+ state(hdlc)->dce_changed = 0;
}
- hdlc->state.fr.request = 1; /* got request */
+ state(hdlc)->request = 1; /* got request */
fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
return 0;
}
/* DTE */
- hdlc->state.fr.request = 0; /* got response, no request pending */
+ state(hdlc)->request = 0; /* got response, no request pending */
if (error)
return 0;
@@ -768,7 +817,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
if (reptype != LMI_FULLREP)
return 0;
- pvc = hdlc->state.fr.first_pvc;
+ pvc = state(hdlc)->first_pvc;
while (pvc) {
pvc->state.deleted = 1;
@@ -835,7 +884,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
i += stat_len;
}
- pvc = hdlc->state.fr.first_pvc;
+ pvc = state(hdlc)->first_pvc;
while (pvc) {
if (pvc->state.deleted && pvc->state.exist) {
@@ -849,17 +898,16 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
}
/* Next full report after N391 polls */
- hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
+ state(hdlc)->n391cnt = state(hdlc)->settings.n391;
return 0;
}
-
static int fr_rx(struct sk_buff *skb)
{
- struct net_device *ndev = skb->dev;
- hdlc_device *hdlc = dev_to_hdlc(ndev);
+ struct net_device *frad = skb->dev;
+ hdlc_device *hdlc = dev_to_hdlc(frad);
fr_hdr *fh = (fr_hdr*)skb->data;
u8 *data = skb->data;
u16 dlci;
@@ -872,11 +920,11 @@ static int fr_rx(struct sk_buff *skb)
dlci = q922_to_dlci(skb->data);
if ((dlci == LMI_CCITT_ANSI_DLCI &&
- (hdlc->state.fr.settings.lmi == LMI_ANSI ||
- hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
+ (state(hdlc)->settings.lmi == LMI_ANSI ||
+ state(hdlc)->settings.lmi == LMI_CCITT)) ||
(dlci == LMI_CISCO_DLCI &&
- hdlc->state.fr.settings.lmi == LMI_CISCO)) {
- if (fr_lmi_recv(ndev, skb))
+ state(hdlc)->settings.lmi == LMI_CISCO)) {
+ if (fr_lmi_recv(frad, skb))
goto rx_error;
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
@@ -886,7 +934,7 @@ static int fr_rx(struct sk_buff *skb)
if (!pvc) {
#ifdef DEBUG_PKT
printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
- ndev->name, dlci);
+ frad->name, dlci);
#endif
dev_kfree_skb_any(skb);
return NET_RX_DROP;
@@ -894,7 +942,7 @@ static int fr_rx(struct sk_buff *skb)
if (pvc->state.fecn != fh->fecn) {
#ifdef DEBUG_ECN
- printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name,
+ printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name,
dlci, fh->fecn ? "N" : "FF");
#endif
pvc->state.fecn ^= 1;
@@ -902,7 +950,7 @@ static int fr_rx(struct sk_buff *skb)
if (pvc->state.becn != fh->becn) {
#ifdef DEBUG_ECN
- printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name,
+ printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name,
dlci, fh->becn ? "N" : "FF");
#endif
pvc->state.becn ^= 1;
@@ -910,7 +958,7 @@ static int fr_rx(struct sk_buff *skb)
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- hdlc->stats.rx_dropped++;
+ dev_to_desc(frad)->stats.rx_dropped++;
return NET_RX_DROP;
}
@@ -946,13 +994,13 @@ static int fr_rx(struct sk_buff *skb)
default:
printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
- "PID=%x\n", ndev->name, oui, pid);
+ "PID=%x\n", frad->name, oui, pid);
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
} else {
printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
- "length = %i\n", ndev->name, data[3], skb->len);
+ "length = %i\n", frad->name, data[3], skb->len);
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -972,7 +1020,7 @@ static int fr_rx(struct sk_buff *skb)
}
rx_error:
- hdlc->stats.rx_errors++; /* Mark error */
+ dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -985,44 +1033,42 @@ static void fr_start(struct net_device *dev)
#ifdef DEBUG_LINK
printk(KERN_DEBUG "fr_start\n");
#endif
- if (hdlc->state.fr.settings.lmi != LMI_NONE) {
- hdlc->state.fr.reliable = 0;
- hdlc->state.fr.dce_changed = 1;
- hdlc->state.fr.request = 0;
- hdlc->state.fr.fullrep_sent = 0;
- hdlc->state.fr.last_errors = 0xFFFFFFFF;
- hdlc->state.fr.n391cnt = 0;
- hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
-
- init_timer(&hdlc->state.fr.timer);
+ if (state(hdlc)->settings.lmi != LMI_NONE) {
+ state(hdlc)->reliable = 0;
+ state(hdlc)->dce_changed = 1;
+ state(hdlc)->request = 0;
+ state(hdlc)->fullrep_sent = 0;
+ state(hdlc)->last_errors = 0xFFFFFFFF;
+ state(hdlc)->n391cnt = 0;
+ state(hdlc)->txseq = state(hdlc)->rxseq = 0;
+
+ init_timer(&state(hdlc)->timer);
/* First poll after 1 s */
- hdlc->state.fr.timer.expires = jiffies + HZ;
- hdlc->state.fr.timer.function = fr_timer;
- hdlc->state.fr.timer.data = (unsigned long)dev;
- add_timer(&hdlc->state.fr.timer);
+ state(hdlc)->timer.expires = jiffies + HZ;
+ state(hdlc)->timer.function = fr_timer;
+ state(hdlc)->timer.data = (unsigned long)dev;
+ add_timer(&state(hdlc)->timer);
} else
fr_set_link_state(1, dev);
}
-
static void fr_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
printk(KERN_DEBUG "fr_stop\n");
#endif
- if (hdlc->state.fr.settings.lmi != LMI_NONE)
- del_timer_sync(&hdlc->state.fr.timer);
+ if (state(hdlc)->settings.lmi != LMI_NONE)
+ del_timer_sync(&state(hdlc)->timer);
fr_set_link_state(0, dev);
}
-
static void fr_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- pvc_device *pvc = hdlc->state.fr.first_pvc;
+ pvc_device *pvc = state(hdlc)->first_pvc;
while (pvc) { /* Shutdown all PVCs for this FRAD */
if (pvc->main)
@@ -1033,7 +1079,8 @@ static void fr_close(struct net_device *dev)
}
}
-static void dlci_setup(struct net_device *dev)
+
+static void pvc_setup(struct net_device *dev)
{
dev->type = ARPHRD_DLCI;
dev->flags = IFF_POINTOPOINT;
@@ -1041,9 +1088,9 @@ static void dlci_setup(struct net_device *dev)
dev->addr_len = 2;
}
-static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
+static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
{
- hdlc_device *hdlc = dev_to_hdlc(master);
+ hdlc_device *hdlc = dev_to_hdlc(frad);
pvc_device *pvc = NULL;
struct net_device *dev;
int result, used;
@@ -1052,9 +1099,9 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
if (type == ARPHRD_ETHER)
prefix = "pvceth%d";
- if ((pvc = add_pvc(master, dlci)) == NULL) {
+ if ((pvc = add_pvc(frad, dlci)) == NULL) {
printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
- master->name);
+ frad->name);
return -ENOBUFS;
}
@@ -1068,11 +1115,11 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
"pvceth%d", ether_setup);
else
dev = alloc_netdev(sizeof(struct net_device_stats),
- "pvc%d", dlci_setup);
+ "pvc%d", pvc_setup);
if (!dev) {
printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
- master->name);
+ frad->name);
delete_unused_pvcs(hdlc);
return -ENOBUFS;
}
@@ -1110,8 +1157,8 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
dev->destructor = free_netdev;
*get_dev_p(pvc, type) = dev;
if (!used) {
- hdlc->state.fr.dce_changed = 1;
- hdlc->state.fr.dce_pvc_count++;
+ state(hdlc)->dce_changed = 1;
+ state(hdlc)->dce_pvc_count++;
}
return 0;
}
@@ -1136,8 +1183,8 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
*get_dev_p(pvc, type) = NULL;
if (!pvc_is_used(pvc)) {
- hdlc->state.fr.dce_pvc_count--;
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->dce_pvc_count--;
+ state(hdlc)->dce_changed = 1;
}
delete_unused_pvcs(hdlc);
return 0;
@@ -1145,14 +1192,13 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
-static void fr_destroy(hdlc_device *hdlc)
+static void fr_destroy(struct net_device *frad)
{
- pvc_device *pvc;
-
- pvc = hdlc->state.fr.first_pvc;
- hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
- hdlc->state.fr.dce_pvc_count = 0;
- hdlc->state.fr.dce_changed = 1;
+ hdlc_device *hdlc = dev_to_hdlc(frad);
+ pvc_device *pvc = state(hdlc)->first_pvc;
+ state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */
+ state(hdlc)->dce_pvc_count = 0;
+ state(hdlc)->dce_changed = 1;
while (pvc) {
pvc_device *next = pvc->next;
@@ -1169,8 +1215,17 @@ static void fr_destroy(hdlc_device *hdlc)
}
+static struct hdlc_proto proto = {
+ .close = fr_close,
+ .start = fr_start,
+ .stop = fr_stop,
+ .detach = fr_destroy,
+ .ioctl = fr_ioctl,
+ .module = THIS_MODULE,
+};
+
-int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
{
fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
const size_t size = sizeof(fr_proto);
@@ -1181,12 +1236,14 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_FR;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
+ if (copy_to_user(fr_s, &state(hdlc)->settings, size))
return -EFAULT;
return 0;
@@ -1221,20 +1278,16 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- if (hdlc->proto.id != IF_PROTO_FR) {
- hdlc_proto_detach(hdlc);
- hdlc->state.fr.first_pvc = NULL;
- hdlc->state.fr.dce_pvc_count = 0;
+ if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
+ result = attach_hdlc_protocol(dev, &proto, fr_rx,
+ sizeof(struct frad_state));
+ if (result)
+ return result;
+ state(hdlc)->first_pvc = NULL;
+ state(hdlc)->dce_pvc_count = 0;
}
- memcpy(&hdlc->state.fr.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.close = fr_close;
- hdlc->proto.start = fr_start;
- hdlc->proto.stop = fr_stop;
- hdlc->proto.detach = fr_destroy;
- hdlc->proto.netif_rx = fr_rx;
- hdlc->proto.id = IF_PROTO_FR;
+ memcpy(&state(hdlc)->settings, &new_settings, size);
+
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_FRAD;
@@ -1246,6 +1299,9 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
case IF_PROTO_FR_DEL_PVC:
case IF_PROTO_FR_ADD_ETH_PVC:
case IF_PROTO_FR_DEL_ETH_PVC:
+ if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
+ return -EINVAL;
+
if(!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -1271,3 +1327,24 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index b81263eaede..e9f717070fd 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Point-to-point protocol support
*
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -22,6 +22,21 @@
#include <linux/lapb.h>
#include <linux/rtnetlink.h>
#include <linux/hdlc.h>
+#include <net/syncppp.h>
+
+struct ppp_state {
+ struct ppp_device pppdev;
+ struct ppp_device *syncppp_ptr;
+ int (*old_change_mtu)(struct net_device *dev, int new_mtu);
+};
+
+static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+
+static inline struct ppp_state* state(hdlc_device *hdlc)
+{
+ return(struct ppp_state *)(hdlc->state);
+}
static int ppp_open(struct net_device *dev)
@@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev)
void *old_ioctl;
int result;
- dev->priv = &hdlc->state.ppp.syncppp_ptr;
- hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
- hdlc->state.ppp.pppdev.dev = dev;
+ dev->priv = &state(hdlc)->syncppp_ptr;
+ state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
+ state(hdlc)->pppdev.dev = dev;
old_ioctl = dev->do_ioctl;
- hdlc->state.ppp.old_change_mtu = dev->change_mtu;
- sppp_attach(&hdlc->state.ppp.pppdev);
+ state(hdlc)->old_change_mtu = dev->change_mtu;
+ sppp_attach(&state(hdlc)->pppdev);
/* sppp_attach nukes them. We don't need syncppp's ioctl */
dev->do_ioctl = old_ioctl;
- hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
+ state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
dev->type = ARPHRD_PPP;
result = sppp_open(dev);
if (result) {
@@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev)
sppp_close(dev);
sppp_detach(dev);
dev->rebuild_header = NULL;
- dev->change_mtu = hdlc->state.ppp.old_change_mtu;
+ dev->change_mtu = state(hdlc)->old_change_mtu;
dev->mtu = HDLC_MAX_MTU;
dev->hard_header_len = 16;
}
@@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
-int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .open = ppp_open,
+ .close = ppp_close,
+ .type_trans = ppp_type_trans,
+ .ioctl = ppp_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
int result;
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_PPP;
return 0; /* return protocol only, no settable parameters */
@@ -96,19 +122,39 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.open = ppp_open;
- hdlc->proto.close = ppp_close;
- hdlc->proto.type_trans = ppp_type_trans;
- hdlc->proto.id = IF_PROTO_PPP;
+ result = attach_hdlc_protocol(dev, &proto, NULL,
+ sizeof(struct ppp_state));
+ if (result)
+ return result;
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_PPP;
dev->addr_len = 0;
+ netif_dormant_off(dev);
return 0;
}
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("PPP protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index 9456d31cb1c..fe3cae5c6b9 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* HDLC support
*
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -24,6 +24,8 @@
#include <linux/hdlc.h>
+static int raw_ioctl(struct net_device *dev, struct ifreq *ifr);
+
static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
{
return __constant_htons(ETH_P_IP);
@@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
-int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .type_trans = raw_type_trans,
+ .ioctl = raw_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
{
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto);
@@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_HDLC;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ if (copy_to_user(raw_s, hdlc->state, size))
return -EFAULT;
return 0;
@@ -71,19 +82,41 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.type_trans = raw_type_trans;
- hdlc->proto.id = IF_PROTO_HDLC;
+ result = attach_hdlc_protocol(dev, &proto, NULL,
+ sizeof(raw_hdlc_proto));
+ if (result)
+ return result;
+ memcpy(hdlc->state, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_RAWHDLC;
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
dev->addr_len = 0;
+ netif_dormant_off(dev);
return 0;
}
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
index b1285cc8fee..1a69a9aaa9b 100644
--- a/drivers/net/wan/hdlc_raw_eth.c
+++ b/drivers/net/wan/hdlc_raw_eth.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* HDLC Ethernet emulation support
*
- * Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2002-2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -25,6 +25,7 @@
#include <linux/etherdevice.h>
#include <linux/hdlc.h>
+static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
static int eth_tx(struct sk_buff *skb, struct net_device *dev)
{
@@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev)
}
-int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .type_trans = eth_type_trans,
+ .ioctl = raw_eth_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
{
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto);
@@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ if (copy_to_user(raw_s, hdlc->state, size))
return -EFAULT;
return 0;
@@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.type_trans = eth_type_trans;
- hdlc->proto.id = IF_PROTO_HDLC_ETH;
+ result = attach_hdlc_protocol(dev, &proto, NULL,
+ sizeof(raw_hdlc_proto));
+ if (result)
+ return result;
+ memcpy(hdlc->state, &new_settings, size);
dev->hard_start_xmit = eth_tx;
old_ch_mtu = dev->change_mtu;
old_qlen = dev->tx_queue_len;
@@ -100,8 +109,31 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
dev->tx_queue_len = old_qlen;
memcpy(dev->dev_addr, "\x00\x01", 2);
get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2);
+ netif_dormant_off(dev);
return 0;
}
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index 07e5eef1fe0..e4bb9f8ad43 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* X.25 support
*
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* 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
@@ -25,6 +25,8 @@
#include <net/x25device.h>
+static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
+
/* These functions are callbacks called by LAPB layer */
static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
@@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev)
static int x25_rx(struct sk_buff *skb)
{
- hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+ struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- hdlc->stats.rx_dropped++;
+ desc->stats.rx_dropped++;
return NET_RX_DROP;
}
if (lapb_data_received(skb->dev, skb) == LAPB_OK)
return NET_RX_SUCCESS;
- hdlc->stats.rx_errors++;
+ desc->stats.rx_errors++;
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
+static struct hdlc_proto proto = {
+ .open = x25_open,
+ .close = x25_close,
+ .ioctl = x25_ioctl,
+ .module = THIS_MODULE,
+};
+
-int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
int result;
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_X25;
return 0; /* return protocol only, no settable parameters */
@@ -200,20 +211,38 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.open = x25_open;
- hdlc->proto.close = x25_close;
- hdlc->proto.netif_rx = x25_rx;
- hdlc->proto.type_trans = NULL;
- hdlc->proto.id = IF_PROTO_X25;
+ if ((result = attach_hdlc_protocol(dev, &proto,
+ x25_rx, 0)) != 0)
+ return result;
dev->hard_start_xmit = x25_xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_X25;
dev->addr_len = 0;
+ netif_dormant_off(dev);
return 0;
}
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c
index cf5c805452a..a4f735723c4 100644
--- a/drivers/net/wan/hostess_sv11.c
+++ b/drivers/net/wan/hostess_sv11.c
@@ -264,7 +264,7 @@ static struct sv11_device *sv11_init(int iobase, int irq)
/* We want a fast IRQ for this device. Actually we'd like an even faster
IRQ ;) - This is one driver RtLinux is made for */
- if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "Hostess SV11", dev)<0)
+ if(request_irq(irq, &z8530_interrupt, IRQF_DISABLED, "Hostess SV11", dev)<0)
{
printk(KERN_WARNING "hostess: IRQ %d already in use.\n", irq);
goto fail1;
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 40926d77916..7b5d81deb02 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1058,7 +1058,7 @@ static int lmc_open (struct net_device *dev) /*fold00*/
lmc_softreset (sc);
/* Since we have to use PCI bus, this should work on x86,alpha,ppc */
- if (request_irq (dev->irq, &lmc_interrupt, SA_SHIRQ, dev->name, dev)){
+ if (request_irq (dev->irq, &lmc_interrupt, IRQF_SHARED, dev->name, dev)){
printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq);
lmc_trace(dev, "lmc_open irq failed out");
return -EAGAIN;
@@ -1790,7 +1790,7 @@ static struct pci_driver lmc_driver = {
static int __init init_lmc(void)
{
- return pci_module_init(&lmc_driver);
+ return pci_register_driver(&lmc_driver);
}
static void __exit exit_lmc(void)
diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c
index af8b55fdd9d..ae01555d24c 100644
--- a/drivers/net/wan/lmc/lmc_media.c
+++ b/drivers/net/wan/lmc/lmc_media.c
@@ -1,6 +1,5 @@
/* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/timer.h>
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index b7d88db89a5..dcf46add3ad 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -7,7 +7,7 @@
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
*
* Note: integrated CSU/DSU/DDS are not supported by this driver
*
@@ -564,4 +564,5 @@ module_exit(n2_cleanup);
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("RISCom/N2 serial port driver");
MODULE_LICENSE("GPL v2");
-module_param(hw, charp, 0444); /* hw=io,irq,ram,ports:io,irq,... */
+module_param(hw, charp, 0444);
+MODULE_PARM_DESC(hw, "io,irq,ram,ports:io,irq,...");
diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h
index 2024b26b99e..63e9fcf31fb 100644
--- a/drivers/net/wan/pc300.h
+++ b/drivers/net/wan/pc300.h
@@ -100,6 +100,7 @@
#define _PC300_H
#include <linux/hdlc.h>
+#include <net/syncppp.h>
#include "hd64572.h"
#include "pc300-falc-lh.h"
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index a3e65d1bc19..8d9b959bf15 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -2016,7 +2016,6 @@ static void sca_intr(pc300_t * card)
pc300ch_t *chan = &card->chan[ch];
pc300dev_t *d = &chan->d;
struct net_device *dev = d->dev;
- hdlc_device *hdlc = dev_to_hdlc(dev);
spin_lock(&card->card_lock);
@@ -2049,8 +2048,8 @@ static void sca_intr(pc300_t * card)
}
cpc_net_rx(dev);
/* Discard invalid frames */
- hdlc->stats.rx_errors++;
- hdlc->stats.rx_over_errors++;
+ hdlc_stats(dev)->rx_errors++;
+ hdlc_stats(dev)->rx_over_errors++;
chan->rx_first_bd = 0;
chan->rx_last_bd = N_DMA_RX_BUF - 1;
rx_dma_start(card, ch);
@@ -2116,8 +2115,8 @@ static void sca_intr(pc300_t * card)
card->hw.cpld_reg2) &
~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
}
- hdlc->stats.tx_errors++;
- hdlc->stats.tx_fifo_errors++;
+ hdlc_stats(dev)->tx_errors++;
+ hdlc_stats(dev)->tx_fifo_errors++;
sca_tx_intr(d);
}
}
@@ -2534,7 +2533,6 @@ static int cpc_change_mtu(struct net_device *dev, int new_mtu)
static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -2552,10 +2550,10 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGPC300CONF:
#ifdef CONFIG_PC300_MLPPP
if (conf->proto != PC300_PROTO_MLPPP) {
- conf->proto = hdlc->proto.id;
+ conf->proto = /* FIXME hdlc->proto.id */ 0;
}
#else
- conf->proto = hdlc->proto.id;
+ conf->proto = /* FIXME hdlc->proto.id */ 0;
#endif
memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t));
memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t));
@@ -2588,12 +2586,12 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
} else {
memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- hdlc->proto.id = conf->proto;
+ /* FIXME hdlc->proto.id = conf->proto; */
}
}
#else
memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- hdlc->proto.id = conf->proto;
+ /* FIXME hdlc->proto.id = conf->proto; */
#endif
return 0;
case SIOCGPC300STATUS:
@@ -2606,7 +2604,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGPC300UTILSTATS:
{
if (!arg) { /* clear statistics */
- memset(&hdlc->stats, 0, sizeof(struct net_device_stats));
+ memset(hdlc_stats(dev), 0, sizeof(struct net_device_stats));
if (card->hw.type == PC300_TE) {
memset(&chan->falc, 0, sizeof(falc_t));
}
@@ -2617,7 +2615,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
pc300stats.hw_type = card->hw.type;
pc300stats.line_on = card->chan[ch].d.line_on;
pc300stats.line_off = card->chan[ch].d.line_off;
- memcpy(&pc300stats.gen_stats, &hdlc->stats,
+ memcpy(&pc300stats.gen_stats, hdlc_stats(dev),
sizeof(struct net_device_stats));
if (card->hw.type == PC300_TE)
memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
@@ -3147,7 +3145,6 @@ static void cpc_closech(pc300dev_t * d)
int cpc_open(struct net_device *dev)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
struct ifreq ifr;
int result;
@@ -3156,12 +3153,14 @@ int cpc_open(struct net_device *dev)
printk("pc300: cpc_open");
#endif
+#ifdef FIXME
if (hdlc->proto.id == IF_PROTO_PPP) {
d->if_ptr = &hdlc->state.ppp.pppdev;
}
+#endif
result = hdlc_open(dev);
- if (hdlc->proto.id == IF_PROTO_PPP) {
+ if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
dev->priv = d;
}
if (result) {
@@ -3176,7 +3175,6 @@ int cpc_open(struct net_device *dev)
static int cpc_close(struct net_device *dev)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -3193,7 +3191,7 @@ static int cpc_close(struct net_device *dev)
CPC_UNLOCK(card, flags);
hdlc_close(dev);
- if (hdlc->proto.id == IF_PROTO_PPP) {
+ if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
d->if_ptr = NULL;
}
#ifdef CONFIG_PC300_MLPPP
@@ -3445,9 +3443,9 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
card = (pc300_t *) kmalloc(sizeof(pc300_t), GFP_KERNEL);
if (card == NULL) {
- printk("PC300 found at RAM 0x%08lx, "
+ printk("PC300 found at RAM 0x%016llx, "
"but could not allocate card structure.\n",
- pci_resource_start(pdev, 3));
+ (unsigned long long)pci_resource_start(pdev, 3));
err = -ENOMEM;
goto err_disable_dev;
}
@@ -3600,7 +3598,7 @@ cpc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
/* Allocate IRQ */
- if (request_irq(card->hw.irq, cpc_intr, SA_SHIRQ, "Cyclades-PC300", card)) {
+ if (request_irq(card->hw.irq, cpc_intr, IRQF_SHARED, "Cyclades-PC300", card)) {
printk ("PC300 found at RAM 0x%08x, but could not allocate IRQ%d.\n",
card->hw.ramphys, card->hw.irq);
goto err_io_unmap;
@@ -3677,7 +3675,7 @@ static struct pci_driver cpc_driver = {
static int __init cpc_init(void)
{
- return pci_module_init(&cpc_driver);
+ return pci_register_driver(&cpc_driver);
}
static void __exit cpc_cleanup_module(void)
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index 670e8bd2245..a6b9c33b68e 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -7,7 +7,7 @@
* under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
- * For information see http://hq.pm.waw.pl/hdlc/
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>
*
* Sources of information:
* Hitachi HD64572 SCA-II User's Manual
@@ -402,7 +402,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev,
writew(readw(p) | 0x0040, p);
/* Allocate IRQ */
- if (request_irq(pdev->irq, sca_intr, SA_SHIRQ, devname, card)) {
+ if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n",
pdev->irq);
pci200_pci_remove_one(pdev);
@@ -476,7 +476,7 @@ static int __init pci200_init_module(void)
printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
return -EINVAL;
}
- return pci_module_init(&pci200_pci_driver);
+ return pci_register_driver(&pci200_pci_driver);
}
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index 175ba13bce4..fc75bec1902 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -37,7 +37,6 @@
* Known problem: this driver wasn't tested on multiprocessor machine.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
@@ -1193,7 +1192,7 @@ sbni_open( struct net_device *dev )
}
}
- if( request_irq(dev->irq, sbni_interrupt, SA_SHIRQ, dev->name, dev) ) {
+ if( request_irq(dev->irq, sbni_interrupt, IRQF_SHARED, dev->name, dev) ) {
printk( KERN_ERR "%s: unable to get IRQ %d.\n",
dev->name, dev->irq );
return -EAGAIN;
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 22e794071cf..0ba018f8382 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -32,7 +32,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h> /* for CONFIG_DLCI_MAX */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -60,9 +59,9 @@
static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org";
-static unsigned int valid_port[] __initdata = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
+static unsigned int valid_port[] = { 0x250, 0x270, 0x280, 0x300, 0x350, 0x360, 0x380, 0x390};
-static unsigned int valid_mem[] __initdata = {
+static unsigned int valid_mem[] = {
0xA0000, 0xA2000, 0xA4000, 0xA6000, 0xA8000, 0xAA000, 0xAC000, 0xAE000,
0xB0000, 0xB2000, 0xB4000, 0xB6000, 0xB8000, 0xBA000, 0xBC000, 0xBE000,
0xC0000, 0xC2000, 0xC4000, 0xC6000, 0xC8000, 0xCA000, 0xCC000, 0xCE000,
diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c
index 050e854e777..70fb1b98b1d 100644
--- a/drivers/net/wan/sealevel.c
+++ b/drivers/net/wan/sealevel.c
@@ -322,7 +322,7 @@ static __init struct slvl_board *slvl_init(int iobase, int irq,
/* We want a fast IRQ for this device. Actually we'd like an even faster
IRQ ;) - This is one driver RtLinux is made for */
- if(request_irq(irq, &z8530_interrupt, SA_INTERRUPT, "SeaLevel", dev)<0)
+ if(request_irq(irq, &z8530_interrupt, IRQF_DISABLED, "SeaLevel", dev)<0)
{
printk(KERN_WARNING "sealevel: IRQ %d already in use.\n", irq);
goto fail1_1;
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index 2d1bba06a08..218f7b574ab 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -37,7 +37,6 @@
*/
#undef DEBUG
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -470,7 +469,7 @@ static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
struct net_device *dev = sp->pp_if;
int len = skb->len;
u8 *p, opt[6];
- u32 rmagic;
+ u32 rmagic = 0;
if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
if (sp->pp_flags & PP_DEBUG)
@@ -764,7 +763,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
{
struct in_device *in_dev;
struct in_ifaddr *ifa;
- u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
+ __be32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
#ifdef CONFIG_INET
rcu_read_lock();
if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 437e0e938e3..ec68f7dfd93 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -149,7 +149,10 @@ static inline void wanxl_cable_intr(port_t *port)
printk(KERN_INFO "%s: %s%s module, %s cable%s%s\n",
port->dev->name, pm, dte, cable, dsr, dcd);
- hdlc_set_carrier(value & STATUS_CABLE_DCD, port->dev);
+ if (value & STATUS_CABLE_DCD)
+ netif_carrier_on(port->dev);
+ else
+ netif_carrier_off(port->dev);
}
@@ -755,7 +758,7 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
pci_name(pdev), plx_phy, ramsize / 1024, mem_phy, pdev->irq);
/* Allocate IRQ */
- if (request_irq(pdev->irq, wanxl_intr, SA_SHIRQ, "wanXL", card)) {
+ if (request_irq(pdev->irq, wanxl_intr, IRQF_SHARED, "wanXL", card)) {
printk(KERN_WARNING "wanXL %s: could not allocate IRQ%i.\n",
pci_name(pdev), pdev->irq);
wanxl_pci_remove_one(pdev);
@@ -834,7 +837,7 @@ static int __init wanxl_init_module(void)
#ifdef MODULE
printk(KERN_INFO "%s\n", version);
#endif
- return pci_module_init(&wanxl_pci_driver);
+ return pci_register_driver(&wanxl_pci_driver);
}
static void __exit wanxl_cleanup_module(void)
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 7caa8dc88a5..41f1d677884 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -61,7 +61,7 @@ static void wd_block_output(struct net_device *dev, int count,
const unsigned char *buf, int start_page);
static int wd_close(struct net_device *dev);
-
+
#define WD_START_PG 0x00 /* First page of TX buffer */
#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */
#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */
@@ -75,7 +75,7 @@ static int wd_close(struct net_device *dev);
#define WD_NIC_OFFSET 16 /* Offset to the 8390 from the base_addr. */
#define WD_IO_EXTENT 32
-
+
/* Probe for the WD8003 and WD8013. These cards have the station
address PROM at I/O ports <base>+8 to <base>+13, with a checksum
following. A Soundblaster can have the same checksum as an WDethercard,
@@ -100,7 +100,7 @@ static int __init do_wd_probe(struct net_device *dev)
if ( r == NULL)
return -EBUSY;
i = wd_probe1(dev, base_addr);
- if (i != 0)
+ if (i != 0)
release_region(base_addr, WD_IO_EXTENT);
else
r->name = dev->name;
@@ -272,7 +272,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
a reliable way to trigger an interrupt. */
outb_p(E8390_NODMA + E8390_STOP, nic_addr);
outb(0x00, nic_addr+EN0_IMR); /* Disable all intrs. */
-
+
irq_mask = probe_irq_on();
outb_p(0xff, nic_addr + EN0_IMR); /* Enable all interrupts. */
outb_p(0x00, nic_addr + EN0_RCNTLO);
@@ -280,7 +280,7 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */
mdelay(20);
dev->irq = probe_irq_off(irq_mask);
-
+
outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */
if (ei_debug > 2)
@@ -478,7 +478,7 @@ wd_close(struct net_device *dev)
return 0;
}
-
+
#ifdef MODULE
#define MAX_WD_CARDS 4 /* Max number of wd cards per module */
static struct net_device *dev_wd[MAX_WD_CARDS];
@@ -500,8 +500,8 @@ MODULE_LICENSE("GPL");
/* This is set up so that only a single autoprobe takes place per call.
ISA device autoprobes on a running machine are not recommended. */
-int
-init_module(void)
+
+int __init init_module(void)
{
struct net_device *dev;
int this_dev, found = 0;
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index 30ec235e693..bd4a68c85a4 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -271,25 +271,14 @@ config IPW2200_DEBUG
bool "Enable full debugging output in IPW2200 module."
depends on IPW2200
---help---
- This option will enable debug tracing output for the IPW2200.
+ This option will enable low level debug tracing output for IPW2200.
- This will result in the kernel module being ~100k larger. You can
- control which debug output is sent to the kernel log by setting the
- value in
-
- /sys/bus/pci/drivers/ipw2200/debug_level
-
- This entry will only exist if this option is enabled.
+ Note, normal debug code is already compiled in. This low level
+ debug option enables debug on hot paths (e.g Tx, Rx, ISR) and
+ will result in the kernel module being ~70 larger. Most users
+ will typically not need this high verbosity debug information.
- To set a value, simply echo an 8-byte hex value to the same file:
-
- % echo 0x00000FFO > /sys/bus/pci/drivers/ipw2200/debug_level
-
- You can find the list of debug mask values in
- drivers/net/wireless/ipw2200.h
-
- If you are not trying to debug or develop the IPW2200 driver, you
- most likely want to say N here.
+ If you are not sure, say N here.
config AIRO
tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards"
@@ -447,6 +436,7 @@ config AIRO_CS
tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
depends on NET_RADIO && PCMCIA && (BROKEN || !M32R)
select CRYPTO
+ select CRYPTO_AES
---help---
This is the standard Linux driver to support Cisco/Aironet PCMCIA
802.11 wireless cards. This driver is the same as the Aironet
@@ -550,6 +540,7 @@ config USB_ZD1201
source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/bcm43xx/Kconfig"
+source "drivers/net/wireless/zd1211rw/Kconfig"
# yes, this works even when no drivers are selected
config NET_WIRELESS
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile
index 512603de309..c613af17a15 100644
--- a/drivers/net/wireless/Makefile
+++ b/drivers/net/wireless/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PRISM54) += prism54/
obj-$(CONFIG_HOSTAP) += hostap/
obj-$(CONFIG_BCM43XX) += bcm43xx/
+obj-$(CONFIG_ZD1211RW) += zd1211rw/
# 16-bit wireless PCMCIA client drivers
obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 4069b79d825..ba737c6cebe 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -19,7 +19,7 @@
======================================================================*/
-#include <linux/config.h>
+#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -48,6 +48,7 @@
#include <linux/pci.h>
#include <asm/uaccess.h>
#include <net/ieee80211.h>
+#include <linux/kthread.h>
#include "airo.h"
@@ -1188,11 +1189,10 @@ struct airo_info {
int whichbap);
unsigned short *flash;
tdsRssiEntry *rssi;
- struct task_struct *task;
+ struct task_struct *list_bss_task;
+ struct task_struct *airo_thread_task;
struct semaphore sem;
- pid_t thr_pid;
wait_queue_head_t thr_wait;
- struct completion thr_exited;
unsigned long expires;
struct {
struct sk_buff *skb;
@@ -1204,7 +1204,7 @@ struct airo_info {
struct iw_spy_data spy_data;
struct iw_public_data wireless_data;
/* MIC stuff */
- struct crypto_tfm *tfm;
+ struct crypto_cipher *tfm;
mic_module mod[2];
mic_statistics micstats;
HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors
@@ -1272,7 +1272,8 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev);
static int RxSeqValid (struct airo_info *ai,miccntx *context,int mcast,u32 micSeq);
static void MoveWindow(miccntx *context, u32 micSeq);
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *);
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
+ struct crypto_cipher *tfm);
static void emmh32_init(emmh32_context *context);
static void emmh32_update(emmh32_context *context, u8 *pOctets, int len);
static void emmh32_final(emmh32_context *context, u8 digest[4]);
@@ -1340,10 +1341,11 @@ static int micsetup(struct airo_info *ai) {
int i;
if (ai->tfm == NULL)
- ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP);
+ ai->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
- if (ai->tfm == NULL) {
+ if (IS_ERR(ai->tfm)) {
airo_print_err(ai->dev->name, "failed to load transform for AES");
+ ai->tfm = NULL;
return ERROR;
}
@@ -1609,7 +1611,8 @@ static void MoveWindow(miccntx *context, u32 micSeq)
static unsigned char aes_counter[16];
/* expand the key to fill the MMH coefficient array */
-static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct crypto_tfm *tfm)
+static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen,
+ struct crypto_cipher *tfm)
{
/* take the keying material, expand if necessary, truncate at 16-bytes */
/* run through AES counter mode to generate context->coeff[] */
@@ -1617,7 +1620,6 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct
int i,j;
u32 counter;
u8 *cipher, plain[16];
- struct scatterlist sg[1];
crypto_cipher_setkey(tfm, pkey, 16);
counter = 0;
@@ -1628,9 +1630,8 @@ static void emmh32_setseed(emmh32_context *context, u8 *pkey, int keylen, struct
aes_counter[12] = (u8)(counter >> 24);
counter++;
memcpy (plain, aes_counter, 16);
- sg_set_buf(sg, plain, 16);
- crypto_cipher_encrypt(tfm, sg, sg, 16);
- cipher = kmap(sg->page) + sg->offset;
+ crypto_cipher_encrypt_one(tfm, plain, plain);
+ cipher = plain;
for (j=0; (j<16) && (i< (sizeof(context->coeff)/sizeof(context->coeff[0]))); ) {
context->coeff[i++] = ntohl(*(u32 *)&cipher[j]);
j += 4;
@@ -1734,12 +1735,12 @@ static int readBSSListRid(struct airo_info *ai, int first,
cmd.cmd=CMD_LISTBSS;
if (down_interruptible(&ai->sem))
return -ERESTARTSYS;
+ ai->list_bss_task = current;
issuecommand(ai, &cmd, &rsp);
up(&ai->sem);
/* Let the command take effect */
- ai->task = current;
- ssleep(3);
- ai->task = NULL;
+ schedule_timeout_uninterruptible(3 * HZ);
+ ai->list_bss_task = NULL;
}
rc = PC4500_readrid(ai, first ? ai->bssListFirst : ai->bssListNext,
list, ai->bssListRidLen, 1);
@@ -2401,8 +2402,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
clear_bit(FLAG_REGISTERED, &ai->flags);
}
set_bit(JOB_DIE, &ai->jobs);
- kill_proc(ai->thr_pid, SIGTERM, 1);
- wait_for_completion(&ai->thr_exited);
+ kthread_stop(ai->airo_thread_task);
/*
* Clean out tx queue
@@ -2433,7 +2433,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
ai->shared, ai->shared_dma);
}
}
- crypto_free_tfm(ai->tfm);
+ crypto_free_cipher(ai->tfm);
del_airo_dev( dev );
free_netdev( dev );
}
@@ -2812,9 +2812,8 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->config.len = 0;
ai->pci = pci;
init_waitqueue_head (&ai->thr_wait);
- init_completion (&ai->thr_exited);
- ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES);
- if (ai->thr_pid < 0)
+ ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
+ if (IS_ERR(ai->airo_thread_task))
goto err_out_free;
ai->tfm = NULL;
rc = add_airo_dev( dev );
@@ -2849,7 +2848,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
reset_card (dev, 1);
msleep(400);
- rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
+ rc = request_irq( dev->irq, airo_interrupt, IRQF_SHARED, dev->name, dev );
if (rc) {
airo_print_err(dev->name, "register interrupt %d failed, rc %d",
irq, rc);
@@ -2931,8 +2930,7 @@ err_out_unlink:
del_airo_dev(dev);
err_out_thr:
set_bit(JOB_DIE, &ai->jobs);
- kill_proc(ai->thr_pid, SIGTERM, 1);
- wait_for_completion(&ai->thr_exited);
+ kthread_stop(ai->airo_thread_task);
err_out_free:
free_netdev(dev);
return NULL;
@@ -3064,13 +3062,7 @@ static int airo_thread(void *data) {
struct airo_info *ai = dev->priv;
int locked;
- daemonize("%s", dev->name);
- allow_signal(SIGTERM);
-
while(1) {
- if (signal_pending(current))
- flush_signals(current);
-
/* make swsusp happy with our thread */
try_to_freeze();
@@ -3098,7 +3090,7 @@ static int airo_thread(void *data) {
set_bit(JOB_AUTOWEP, &ai->jobs);
break;
}
- if (!signal_pending(current)) {
+ if (!kthread_should_stop()) {
unsigned long wake_at;
if (!ai->expires || !ai->scan_timeout) {
wake_at = max(ai->expires,
@@ -3110,7 +3102,7 @@ static int airo_thread(void *data) {
schedule_timeout(wake_at - jiffies);
continue;
}
- } else if (!signal_pending(current)) {
+ } else if (!kthread_should_stop()) {
schedule();
continue;
}
@@ -3155,7 +3147,8 @@ static int airo_thread(void *data) {
else /* Shouldn't get here, but we make sure to unlock */
up(&ai->sem);
}
- complete_and_exit (&ai->thr_exited, 0);
+
+ return 0;
}
static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
@@ -3236,8 +3229,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs)
if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) {
if (auto_wep)
apriv->expires = 0;
- if (apriv->task)
- wake_up_process (apriv->task);
+ if (apriv->list_bss_task)
+ wake_up_process(apriv->list_bss_task);
set_bit(FLAG_UPDATE_UNI, &apriv->flags);
set_bit(FLAG_UPDATE_MULTI, &apriv->flags);
@@ -3951,13 +3944,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
pRsp->rsp0 = IN4500(ai, RESP0);
pRsp->rsp1 = IN4500(ai, RESP1);
pRsp->rsp2 = IN4500(ai, RESP2);
- if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) {
- airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd);
- airo_print_err(ai->dev->name, "status= %x\n", pRsp->status);
- airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0);
- airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1);
- airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2);
- }
+ if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET)
+ airo_print_err(ai->dev->name,
+ "cmd:%x status:%x rsp0:%x rsp1:%x rsp2:%x",
+ pCmd->cmd, pRsp->status, pRsp->rsp0, pRsp->rsp1,
+ pRsp->rsp2);
// clear stuck command busy if necessary
if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
@@ -5877,7 +5868,7 @@ static int airo_set_essid(struct net_device *dev,
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
+ if(dwrq->length > IW_ESSID_MAX_SIZE) {
return -E2BIG ;
}
/* Check if index is valid */
@@ -5889,7 +5880,7 @@ static int airo_set_essid(struct net_device *dev,
memset(SSID_rid.ssids[index].ssid, 0,
sizeof(SSID_rid.ssids[index].ssid));
memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
- SSID_rid.ssids[index].len = dwrq->length - 1;
+ SSID_rid.ssids[index].len = dwrq->length;
}
SSID_rid.len = sizeof(SSID_rid);
/* Write it to the card */
@@ -5999,7 +5990,7 @@ static int airo_set_nick(struct net_device *dev,
struct airo_info *local = dev->priv;
/* Check the size of the string */
- if(dwrq->length > 16 + 1) {
+ if(dwrq->length > 16) {
return -E2BIG;
}
readConfigRid(local, 1);
@@ -6024,7 +6015,7 @@ static int airo_get_nick(struct net_device *dev,
readConfigRid(local, 1);
strncpy(extra, local->config.nodeName, 16);
extra[16] = '\0';
- dwrq->length = strlen(extra) + 1;
+ dwrq->length = strlen(extra);
return 0;
}
@@ -6776,9 +6767,9 @@ static int airo_set_retry(struct net_device *dev,
}
readConfigRid(local, 1);
if(vwrq->flags & IW_RETRY_LIMIT) {
- if(vwrq->flags & IW_RETRY_MAX)
+ if(vwrq->flags & IW_RETRY_LONG)
local->config.longRetryLimit = vwrq->value;
- else if (vwrq->flags & IW_RETRY_MIN)
+ else if (vwrq->flags & IW_RETRY_SHORT)
local->config.shortRetryLimit = vwrq->value;
else {
/* No modifier : set both */
@@ -6814,14 +6805,14 @@ static int airo_get_retry(struct net_device *dev,
if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
vwrq->flags = IW_RETRY_LIFETIME;
vwrq->value = (int)local->config.txLifetime * 1024;
- } else if((vwrq->flags & IW_RETRY_MAX)) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ } else if((vwrq->flags & IW_RETRY_LONG)) {
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
vwrq->value = (int)local->config.longRetryLimit;
} else {
vwrq->flags = IW_RETRY_LIMIT;
vwrq->value = (int)local->config.shortRetryLimit;
if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
- vwrq->flags |= IW_RETRY_MIN;
+ vwrq->flags |= IW_RETRY_SHORT;
}
return 0;
@@ -6999,6 +6990,7 @@ static int airo_set_power(struct net_device *dev,
local->config.rmode |= RXMODE_BC_MC_ADDR;
set_bit (FLAG_COMMIT, &local->flags);
case IW_POWER_ON:
+ /* This is broken, fixme ;-) */
break;
default:
return -EINVAL;
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index af0cbb6c5c0..ac9437d497f 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -20,7 +20,6 @@
======================================================================*/
-#include <linux/config.h>
#ifdef __IN_PCMCIA_PACKAGE__
#include <pcmcia/k_compat.h>
#endif
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index 7b321f7cf35..38fac3bbcd8 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -14,7 +14,6 @@
#define DRIVER_NAME "airport"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index bed6823d980..bb6bea4f323 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -5,7 +5,6 @@
* This module provides support for the Arlan 655 card made by Aironet
*/
-#include <linux/config.h>
#include "arlan.h"
#if BITS_PER_LONG != 32
diff --git a/drivers/net/wireless/arlan-proc.c b/drivers/net/wireless/arlan-proc.c
index a2cca521f44..5fa985435ff 100644
--- a/drivers/net/wireless/arlan-proc.c
+++ b/drivers/net/wireless/arlan-proc.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include "arlan.h"
#include <linux/sysctl.h>
diff --git a/drivers/net/wireless/arlan.h b/drivers/net/wireless/arlan.h
index 70a6d7b83c4..3ed1df75900 100644
--- a/drivers/net/wireless/arlan.h
+++ b/drivers/net/wireless/arlan.h
@@ -5,7 +5,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/skbuff.h>
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 8606c88886f..0fc267d626d 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -39,7 +39,6 @@
******************************************************************************/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -1578,7 +1577,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
SET_NETDEV_DEV(dev, sys_dev);
- if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) {
+ if ((rc = request_irq(dev->irq, service_interrupt, IRQF_SHARED, dev->name, dev))) {
printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc);
goto err_out_free;
}
@@ -1657,13 +1656,13 @@ static int atmel_set_essid(struct net_device *dev,
priv->connect_to_any_BSS = 0;
/* Check the size of the string */
- if (dwrq->length > MAX_SSID_LENGTH + 1)
+ if (dwrq->length > MAX_SSID_LENGTH)
return -E2BIG;
if (index != 0)
return -EINVAL;
- memcpy(priv->new_SSID, extra, dwrq->length - 1);
- priv->new_SSID_size = dwrq->length - 1;
+ memcpy(priv->new_SSID, extra, dwrq->length);
+ priv->new_SSID_size = dwrq->length;
}
return -EINPROGRESS;
@@ -2121,9 +2120,9 @@ static int atmel_set_retry(struct net_device *dev,
struct atmel_private *priv = netdev_priv(dev);
if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
- if (vwrq->flags & IW_RETRY_MAX)
+ if (vwrq->flags & IW_RETRY_LONG)
priv->long_retry = vwrq->value;
- else if (vwrq->flags & IW_RETRY_MIN)
+ else if (vwrq->flags & IW_RETRY_SHORT)
priv->short_retry = vwrq->value;
else {
/* No modifier : set both */
@@ -2145,15 +2144,15 @@ static int atmel_get_retry(struct net_device *dev,
vwrq->disabled = 0; /* Can't be disabled */
- /* Note : by default, display the min retry number */
- if (vwrq->flags & IW_RETRY_MAX) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ /* Note : by default, display the short retry number */
+ if (vwrq->flags & IW_RETRY_LONG) {
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
vwrq->value = priv->long_retry;
} else {
vwrq->flags = IW_RETRY_LIMIT;
vwrq->value = priv->short_retry;
if (priv->long_retry != priv->short_retry)
- vwrq->flags |= IW_RETRY_MIN;
+ vwrq->flags |= IW_RETRY_SHORT;
}
return 0;
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index 26bf1127524..785664090bb 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -29,7 +29,6 @@
******************************************************************************/
-#include <linux/config.h>
#ifdef __IN_PCMCIA_PACKAGE__
#include <pcmcia/k_compat.h>
#endif
diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c
index a61b3bc6ccc..3bfa791c323 100644
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -19,7 +19,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
******************************************************************************/
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -77,7 +76,7 @@ static void __devexit atmel_pci_remove(struct pci_dev *pdev)
static int __init atmel_init_module(void)
{
- return pci_module_init(&atmel_driver);
+ return pci_register_driver(&atmel_driver);
}
static void __exit atmel_cleanup_module(void)
diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig
index 25ea4748f0b..533993f538f 100644
--- a/drivers/net/wireless/bcm43xx/Kconfig
+++ b/drivers/net/wireless/bcm43xx/Kconfig
@@ -2,6 +2,7 @@ config BCM43XX
tristate "Broadcom BCM43xx wireless support"
depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
select FW_LOADER
+ select HW_RANDOM
---help---
This is an experimental driver for the Broadcom 43xx wireless chip,
found in the Apple Airport Extreme and various other devices.
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index d8f917c21ea..d6a8bf09878 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -1,6 +1,7 @@
#ifndef BCM43xx_H_
#define BCM43xx_H_
+#include <linux/hw_random.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
@@ -32,14 +33,18 @@
#define BCM43xx_PCICFG_ICR 0x94
/* MMIO offsets */
-#define BCM43xx_MMIO_DMA1_REASON 0x20
-#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24
-#define BCM43xx_MMIO_DMA2_REASON 0x28
-#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C
-#define BCM43xx_MMIO_DMA3_REASON 0x30
-#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34
-#define BCM43xx_MMIO_DMA4_REASON 0x38
-#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C
+#define BCM43xx_MMIO_DMA0_REASON 0x20
+#define BCM43xx_MMIO_DMA0_IRQ_MASK 0x24
+#define BCM43xx_MMIO_DMA1_REASON 0x28
+#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x2C
+#define BCM43xx_MMIO_DMA2_REASON 0x30
+#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x34
+#define BCM43xx_MMIO_DMA3_REASON 0x38
+#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x3C
+#define BCM43xx_MMIO_DMA4_REASON 0x40
+#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x44
+#define BCM43xx_MMIO_DMA5_REASON 0x48
+#define BCM43xx_MMIO_DMA5_IRQ_MASK 0x4C
#define BCM43xx_MMIO_STATUS_BITFIELD 0x120
#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124
#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128
@@ -55,14 +60,27 @@
#define BCM43xx_MMIO_XMITSTAT_1 0x174
#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */
#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */
-#define BCM43xx_MMIO_DMA1_BASE 0x200
-#define BCM43xx_MMIO_DMA2_BASE 0x220
-#define BCM43xx_MMIO_DMA3_BASE 0x240
-#define BCM43xx_MMIO_DMA4_BASE 0x260
+
+/* 32-bit DMA */
+#define BCM43xx_MMIO_DMA32_BASE0 0x200
+#define BCM43xx_MMIO_DMA32_BASE1 0x220
+#define BCM43xx_MMIO_DMA32_BASE2 0x240
+#define BCM43xx_MMIO_DMA32_BASE3 0x260
+#define BCM43xx_MMIO_DMA32_BASE4 0x280
+#define BCM43xx_MMIO_DMA32_BASE5 0x2A0
+/* 64-bit DMA */
+#define BCM43xx_MMIO_DMA64_BASE0 0x200
+#define BCM43xx_MMIO_DMA64_BASE1 0x240
+#define BCM43xx_MMIO_DMA64_BASE2 0x280
+#define BCM43xx_MMIO_DMA64_BASE3 0x2C0
+#define BCM43xx_MMIO_DMA64_BASE4 0x300
+#define BCM43xx_MMIO_DMA64_BASE5 0x340
+/* PIO */
#define BCM43xx_MMIO_PIO1_BASE 0x300
#define BCM43xx_MMIO_PIO2_BASE 0x310
#define BCM43xx_MMIO_PIO3_BASE 0x320
#define BCM43xx_MMIO_PIO4_BASE 0x330
+
#define BCM43xx_MMIO_PHY_VER 0x3E0
#define BCM43xx_MMIO_PHY_RADIO 0x3E2
#define BCM43xx_MMIO_ANTENNA 0x3E8
@@ -82,6 +100,7 @@
#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */
#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */
#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */
+#define BCM43xx_MMIO_RNG 0x65A
#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8
/* SPROM offsets. */
@@ -231,8 +250,14 @@
#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000
/* sbtmstatehigh state flags */
-#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1
-#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4
+#define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001
+#define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004
+#define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020
+#define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000
+#define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000
+#define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000
+#define BCM43xx_SBTMSTATEHIGH_BISTFAILED 0x40000000
+#define BCM43xx_SBTMSTATEHIGH_BISTCOMPLETE 0x80000000
/* sbimstate flags */
#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000
@@ -281,6 +306,13 @@
#define BCM43xx_SBF_TIME_UPDATE 0x10000000
#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/
+/* Microcode */
+#define BCM43xx_UCODE_REVISION 0x0000
+#define BCM43xx_UCODE_PATCHLEVEL 0x0002
+#define BCM43xx_UCODE_DATE 0x0004
+#define BCM43xx_UCODE_TIME 0x0006
+#define BCM43xx_UCODE_STATUS 0x0040
+
/* MicrocodeFlagsBitfield (addr + lo-word values?)*/
#define BCM43xx_UCODEFLAGS_OFFSET 0x005E
@@ -502,6 +534,12 @@ struct bcm43xx_phyinfo {
* This lock is only used by bcm43xx_phy_{un}lock()
*/
spinlock_t lock;
+
+ /* Firmware. */
+ const struct firmware *ucode;
+ const struct firmware *pcm;
+ const struct firmware *initvals0;
+ const struct firmware *initvals1;
};
@@ -566,8 +604,11 @@ struct bcm43xx_dma {
struct bcm43xx_dmaring *tx_ring1;
struct bcm43xx_dmaring *tx_ring2;
struct bcm43xx_dmaring *tx_ring3;
+ struct bcm43xx_dmaring *tx_ring4;
+ struct bcm43xx_dmaring *tx_ring5;
+
struct bcm43xx_dmaring *rx_ring0;
- struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */
+ struct bcm43xx_dmaring *rx_ring3; /* only available on core.rev < 5 */
};
/* Data structures for PIO transmission, per 80211 core. */
@@ -591,12 +632,14 @@ struct bcm43xx_coreinfo {
u8 available:1,
enabled:1,
initialized:1;
- /** core_id ID number */
- u16 id;
/** core_rev revision number */
u8 rev;
/** Index number for _switch_core() */
u8 index;
+ /** core_id ID number */
+ u16 id;
+ /** Core-specific data. */
+ void *priv;
};
/* Additional information for each 80211 core. */
@@ -623,7 +666,6 @@ struct bcm43xx_noise_calculation {
};
struct bcm43xx_stats {
- u8 link_quality;
u8 noise;
struct iw_statistics wstats;
/* Store the last TX/RX times here for updating the leds. */
@@ -645,7 +687,23 @@ enum {
BCM43xx_STAT_RESTARTING, /* controller_restart() called. */
};
#define bcm43xx_status(bcm) atomic_read(&(bcm)->init_status)
-#define bcm43xx_set_status(bcm, stat) atomic_set(&(bcm)->init_status, (stat))
+#define bcm43xx_set_status(bcm, stat) do { \
+ atomic_set(&(bcm)->init_status, (stat)); \
+ smp_wmb(); \
+ } while (0)
+
+/* *** THEORY OF LOCKING ***
+ *
+ * We have two different locks in the bcm43xx driver.
+ * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
+ * and the device registers. This mutex does _not_ protect
+ * against concurrency from the IRQ handler.
+ * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
+ *
+ * Please note that, if you only take the irq_lock, you are not protected
+ * against concurrency from the periodic work handlers.
+ * Most times you want to take _both_ locks.
+ */
struct bcm43xx_private {
struct ieee80211_device *ieee;
@@ -657,7 +715,6 @@ struct bcm43xx_private {
void __iomem *mmio_addr;
- /* Locking, see "theory of locking" text below. */
spinlock_t irq_lock;
struct mutex mutex;
@@ -689,6 +746,7 @@ struct bcm43xx_private {
struct bcm43xx_sprominfo sprom;
#define BCM43xx_NR_LEDS 4
struct bcm43xx_led leds[BCM43xx_NR_LEDS];
+ spinlock_t leds_lock;
/* The currently active core. */
struct bcm43xx_coreinfo *current_core;
@@ -706,10 +764,6 @@ struct bcm43xx_private {
struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ];
/* Additional information, specific to the 80211 cores. */
struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ];
- /* Index of the current 80211 core. If current_core is not
- * an 80211 core, this is -1.
- */
- int current_80211_core_idx;
/* Number of available 80211 cores. */
int nr_80211_available;
@@ -717,11 +771,13 @@ struct bcm43xx_private {
/* Reason code of the last interrupt. */
u32 irq_reason;
- u32 dma_reason[4];
+ u32 dma_reason[6];
/* saved irq enable/disable state bitfield. */
u32 irq_savedstate;
/* Link Quality calculation context. */
struct bcm43xx_noise_calculation noisecalc;
+ /* if > 0 MAC is suspended. if == 0 MAC is enabled. */
+ int mac_suspended;
/* Threshold values. */
//TODO: The RTS thr has to be _used_. Currently, it is only set via WX.
@@ -744,11 +800,9 @@ struct bcm43xx_private {
struct bcm43xx_key key[54];
u8 default_key_idx;
- /* Firmware. */
- const struct firmware *ucode;
- const struct firmware *pcm;
- const struct firmware *initvals0;
- const struct firmware *initvals1;
+ /* Random Number Generator. */
+ struct hwrng rng;
+ char rng_name[20 + 1];
/* Debugging stuff follows. */
#ifdef CONFIG_BCM43XX_DEBUG
@@ -757,55 +811,6 @@ struct bcm43xx_private {
};
-/* *** THEORY OF LOCKING ***
- *
- * We have two different locks in the bcm43xx driver.
- * => bcm->mutex: General sleeping mutex. Protects struct bcm43xx_private
- * and the device registers.
- * => bcm->irq_lock: IRQ spinlock. Protects against IRQ handler concurrency.
- *
- * We have three types of helper function pairs to utilize these locks.
- * (Always use the helper functions.)
- * 1) bcm43xx_{un}lock_noirq():
- * Takes bcm->mutex. Does _not_ protect against IRQ concurrency,
- * so it is almost always unsafe, if device IRQs are enabled.
- * So only use this, if device IRQs are masked.
- * Locking may sleep.
- * You can sleep within the critical section.
- * 2) bcm43xx_{un}lock_irqonly():
- * Takes bcm->irq_lock. Does _not_ protect against
- * bcm43xx_lock_noirq() critical sections.
- * Does only protect against the IRQ handler path and other
- * irqonly() critical sections.
- * Locking does not sleep.
- * You must not sleep within the critical section.
- * 3) bcm43xx_{un}lock_irqsafe():
- * This is the cummulative lock and takes both, mutex and irq_lock.
- * Protects against noirq() and irqonly() critical sections (and
- * the IRQ handler path).
- * Locking may sleep.
- * You must not sleep within the critical section.
- */
-
-/* Lock type 1 */
-#define bcm43xx_lock_noirq(bcm) mutex_lock(&(bcm)->mutex)
-#define bcm43xx_unlock_noirq(bcm) mutex_unlock(&(bcm)->mutex)
-/* Lock type 2 */
-#define bcm43xx_lock_irqonly(bcm, flags) \
- spin_lock_irqsave(&(bcm)->irq_lock, flags)
-#define bcm43xx_unlock_irqonly(bcm, flags) \
- spin_unlock_irqrestore(&(bcm)->irq_lock, flags)
-/* Lock type 3 */
-#define bcm43xx_lock_irqsafe(bcm, flags) do { \
- bcm43xx_lock_noirq(bcm); \
- bcm43xx_lock_irqonly(bcm, flags); \
- } while (0)
-#define bcm43xx_unlock_irqsafe(bcm, flags) do { \
- bcm43xx_unlock_irqonly(bcm, flags); \
- bcm43xx_unlock_noirq(bcm); \
- } while (0)
-
-
static inline
struct bcm43xx_private * bcm43xx_priv(struct net_device *dev)
{
@@ -857,34 +862,33 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm)
* any of these functions.
*/
static inline
+struct bcm43xx_coreinfo_80211 *
+bcm43xx_current_80211_priv(struct bcm43xx_private *bcm)
+{
+ assert(bcm->current_core->id == BCM43xx_COREID_80211);
+ return bcm->current_core->priv;
+}
+static inline
struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm)
{
assert(bcm43xx_using_pio(bcm));
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio);
+ return &(bcm43xx_current_80211_priv(bcm)->pio);
}
static inline
struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm)
{
assert(!bcm43xx_using_pio(bcm));
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma);
+ return &(bcm43xx_current_80211_priv(bcm)->dma);
}
static inline
struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm)
{
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy);
+ return &(bcm43xx_current_80211_priv(bcm)->phy);
}
static inline
struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm)
{
- assert(bcm->current_80211_core_idx >= 0);
- assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES);
- return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio);
+ return &(bcm43xx_current_80211_priv(bcm)->radio);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index ce2e40b29b4..b9df06a06ea 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -54,7 +54,7 @@ static ssize_t write_file_dummy(struct file *file, const char __user *buf,
static int open_file_generic(struct inode *inode, struct file *file)
{
- file->private_data = inode->u.generic_ip;
+ file->private_data = inode->i_private;
return 0;
}
@@ -77,7 +77,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
@@ -121,7 +122,8 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf,
fappend("\n");
out:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -159,7 +161,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
unsigned long flags;
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
@@ -169,7 +172,8 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf,
fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags);
out:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -188,7 +192,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
u64 tsf;
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
fappend("Board not initialized.\n");
goto out;
@@ -199,7 +204,8 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf,
(unsigned int)(tsf & 0xFFFFFFFFULL));
out:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
up(&big_buffer_sem);
return res;
@@ -221,7 +227,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = -EFAULT;
goto out_up;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
res = -EFAULT;
@@ -237,7 +244,8 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf,
res = buf_size;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
out_up:
up(&big_buffer_sem);
return res;
@@ -258,7 +266,8 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
int i, cnt, j = 0;
down(&big_buffer_sem);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
fappend("Last %d logged xmitstatus blobs (Latest first):\n\n",
BCM43xx_NR_LOGGED_XMITSTATUS);
@@ -294,14 +303,51 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf,
i = BCM43xx_NR_LOGGED_XMITSTATUS - 1;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
- bcm43xx_lock_irqsafe(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (*ppos == pos) {
/* Done. Drop the copied data. */
e->xmitstatus_printing = 0;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
+ up(&big_buffer_sem);
+ return res;
+}
+
+static ssize_t restart_write_file(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct bcm43xx_private *bcm = file->private_data;
+ char *buf = really_big_buffer;
+ ssize_t buf_size;
+ ssize_t res;
+ unsigned long flags;
+
+ buf_size = min(count, sizeof (really_big_buffer) - 1);
+ down(&big_buffer_sem);
+ if (copy_from_user(buf, user_buf, buf_size)) {
+ res = -EFAULT;
+ goto out_up;
+ }
+ mutex_lock(&(bcm)->mutex);
+ spin_lock_irqsave(&(bcm)->irq_lock, flags);
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED) {
+ printk(KERN_INFO PFX "debugfs: Board not initialized.\n");
+ res = -EFAULT;
+ goto out_unlock;
+ }
+ if (count > 0 && buf[0] == '1') {
+ bcm43xx_controller_restart(bcm, "manually restarted");
+ res = count;
+ } else
+ res = -EINVAL;
+
+out_unlock:
+ spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+ mutex_unlock(&(bcm)->mutex);
+out_up:
up(&big_buffer_sem);
return res;
}
@@ -339,6 +385,11 @@ static struct file_operations txstat_fops = {
.open = open_file_generic,
};
+static struct file_operations restart_fops = {
+ .write = restart_write_file,
+ .open = open_file_generic,
+};
+
void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
{
@@ -390,6 +441,10 @@ void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm)
bcm, &txstat_fops);
if (!e->dentry_txstat)
printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir);
+ e->dentry_restart = debugfs_create_file("restart", 0222, e->subdir,
+ bcm, &restart_fops);
+ if (!e->dentry_restart)
+ printk(KERN_ERR PFX "debugfs: creating \"restart\" for \"%s\" failed!\n", devdir);
}
void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
@@ -405,6 +460,7 @@ void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm)
debugfs_remove(e->dentry_devinfo);
debugfs_remove(e->dentry_tsf);
debugfs_remove(e->dentry_txstat);
+ debugfs_remove(e->dentry_restart);
debugfs_remove(e->subdir);
kfree(e->xmitstatus_buffer);
kfree(e->xmitstatus_print_buffer);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
index 50ce267f794..a40d1af3554 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h
@@ -20,6 +20,7 @@ struct bcm43xx_dfsentry {
struct dentry *dentry_spromdump;
struct dentry *dentry_tsf;
struct dentry *dentry_txstat;
+ struct dentry *dentry_restart;
struct bcm43xx_private *bcm;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
index d0318e525ba..76e3aed4b47 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c
@@ -4,7 +4,7 @@
DMA ringbuffer and descriptor allocation/management
- Copyright (c) 2005 Michael Buesch <mbuesch@freenet.de>
+ Copyright (c) 2005, 2006 Michael Buesch <mbuesch@freenet.de>
Some code in this file is derived from the b44.c driver
Copyright (C) 2002 David S. Miller
@@ -109,6 +109,35 @@ void return_slot(struct bcm43xx_dmaring *ring, int slot)
}
}
+u16 bcm43xx_dmacontroller_base(int dma64bit, int controller_idx)
+{
+ static const u16 map64[] = {
+ BCM43xx_MMIO_DMA64_BASE0,
+ BCM43xx_MMIO_DMA64_BASE1,
+ BCM43xx_MMIO_DMA64_BASE2,
+ BCM43xx_MMIO_DMA64_BASE3,
+ BCM43xx_MMIO_DMA64_BASE4,
+ BCM43xx_MMIO_DMA64_BASE5,
+ };
+ static const u16 map32[] = {
+ BCM43xx_MMIO_DMA32_BASE0,
+ BCM43xx_MMIO_DMA32_BASE1,
+ BCM43xx_MMIO_DMA32_BASE2,
+ BCM43xx_MMIO_DMA32_BASE3,
+ BCM43xx_MMIO_DMA32_BASE4,
+ BCM43xx_MMIO_DMA32_BASE5,
+ };
+
+ if (dma64bit) {
+ assert(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map64));
+ return map64[controller_idx];
+ }
+ assert(controller_idx >= 0 &&
+ controller_idx < ARRAY_SIZE(map32));
+ return map32[controller_idx];
+}
+
static inline
dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring,
unsigned char *buf,
@@ -172,7 +201,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring,
/* Unmap and free a descriptor buffer. */
static inline
void free_descriptor_buffer(struct bcm43xx_dmaring *ring,
- struct bcm43xx_dmadesc *desc,
struct bcm43xx_dmadesc_meta *meta,
int irq_context)
{
@@ -188,23 +216,13 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring)
{
struct device *dev = &(ring->bcm->pci_dev->dev);
- ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
- &(ring->dmabase), GFP_KERNEL);
- if (!ring->vbase) {
+ ring->descbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
+ &(ring->dmabase), GFP_KERNEL);
+ if (!ring->descbase) {
printk(KERN_ERR PFX "DMA ringmemory allocation failed\n");
return -ENOMEM;
}
- if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) {
- printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G "
- "(0x%llx, len: %lu)\n",
- (unsigned long long)ring->dmabase,
- BCM43xx_DMA_RINGMEMSIZE);
- dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
- ring->vbase, ring->dmabase);
- return -ENOMEM;
- }
- assert(!(ring->dmabase & 0x000003FF));
- memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE);
+ memset(ring->descbase, 0, BCM43xx_DMA_RINGMEMSIZE);
return 0;
}
@@ -214,26 +232,34 @@ static void free_ringmemory(struct bcm43xx_dmaring *ring)
struct device *dev = &(ring->bcm->pci_dev->dev);
dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE,
- ring->vbase, ring->dmabase);
+ ring->descbase, ring->dmabase);
}
/* Reset the RX DMA channel */
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
- u16 mmio_base)
+ u16 mmio_base, int dma64)
{
int i;
u32 value;
+ u16 offset;
- bcm43xx_write32(bcm,
- mmio_base + BCM43xx_DMA_RX_CONTROL,
- 0x00000000);
+ offset = dma64 ? BCM43xx_DMA64_RXCTL : BCM43xx_DMA32_RXCTL;
+ bcm43xx_write32(bcm, mmio_base + offset, 0);
for (i = 0; i < 1000; i++) {
- value = bcm43xx_read32(bcm,
- mmio_base + BCM43xx_DMA_RX_STATUS);
- value &= BCM43xx_DMA_RXSTAT_STAT_MASK;
- if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) {
- i = -1;
- break;
+ offset = dma64 ? BCM43xx_DMA64_RXSTATUS : BCM43xx_DMA32_RXSTATUS;
+ value = bcm43xx_read32(bcm, mmio_base + offset);
+ if (dma64) {
+ value &= BCM43xx_DMA64_RXSTAT;
+ if (value == BCM43xx_DMA64_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= BCM43xx_DMA32_RXSTATE;
+ if (value == BCM43xx_DMA32_RXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
}
udelay(10);
}
@@ -247,31 +273,47 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
/* Reset the RX DMA channel */
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
- u16 mmio_base)
+ u16 mmio_base, int dma64)
{
int i;
u32 value;
+ u16 offset;
for (i = 0; i < 1000; i++) {
- value = bcm43xx_read32(bcm,
- mmio_base + BCM43xx_DMA_TX_STATUS);
- value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
- if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED ||
- value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT ||
- value == BCM43xx_DMA_TXSTAT_STAT_STOPPED)
- break;
+ offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+ value = bcm43xx_read32(bcm, mmio_base + offset);
+ if (dma64) {
+ value &= BCM43xx_DMA64_TXSTAT;
+ if (value == BCM43xx_DMA64_TXSTAT_DISABLED ||
+ value == BCM43xx_DMA64_TXSTAT_IDLEWAIT ||
+ value == BCM43xx_DMA64_TXSTAT_STOPPED)
+ break;
+ } else {
+ value &= BCM43xx_DMA32_TXSTATE;
+ if (value == BCM43xx_DMA32_TXSTAT_DISABLED ||
+ value == BCM43xx_DMA32_TXSTAT_IDLEWAIT ||
+ value == BCM43xx_DMA32_TXSTAT_STOPPED)
+ break;
+ }
udelay(10);
}
- bcm43xx_write32(bcm,
- mmio_base + BCM43xx_DMA_TX_CONTROL,
- 0x00000000);
+ offset = dma64 ? BCM43xx_DMA64_TXCTL : BCM43xx_DMA32_TXCTL;
+ bcm43xx_write32(bcm, mmio_base + offset, 0);
for (i = 0; i < 1000; i++) {
- value = bcm43xx_read32(bcm,
- mmio_base + BCM43xx_DMA_TX_STATUS);
- value &= BCM43xx_DMA_TXSTAT_STAT_MASK;
- if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) {
- i = -1;
- break;
+ offset = dma64 ? BCM43xx_DMA64_TXSTATUS : BCM43xx_DMA32_TXSTATUS;
+ value = bcm43xx_read32(bcm, mmio_base + offset);
+ if (dma64) {
+ value &= BCM43xx_DMA64_TXSTAT;
+ if (value == BCM43xx_DMA64_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
+ } else {
+ value &= BCM43xx_DMA32_TXSTATE;
+ if (value == BCM43xx_DMA32_TXSTAT_DISABLED) {
+ i = -1;
+ break;
+ }
}
udelay(10);
}
@@ -285,47 +327,98 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
return 0;
}
+static void fill_descriptor(struct bcm43xx_dmaring *ring,
+ struct bcm43xx_dmadesc_generic *desc,
+ dma_addr_t dmaaddr,
+ u16 bufsize,
+ int start, int end, int irq)
+{
+ int slot;
+
+ slot = bcm43xx_dma_desc2idx(ring, desc);
+ assert(slot >= 0 && slot < ring->nr_slots);
+
+ if (ring->dma64) {
+ u32 ctl0 = 0, ctl1 = 0;
+ u32 addrlo, addrhi;
+ u32 addrext;
+
+ addrlo = (u32)(dmaaddr & 0xFFFFFFFF);
+ addrhi = (((u64)dmaaddr >> 32) & ~BCM43xx_DMA64_ROUTING);
+ addrext = (((u64)dmaaddr >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+ addrhi |= ring->routing;
+ if (slot == ring->nr_slots - 1)
+ ctl0 |= BCM43xx_DMA64_DCTL0_DTABLEEND;
+ if (start)
+ ctl0 |= BCM43xx_DMA64_DCTL0_FRAMESTART;
+ if (end)
+ ctl0 |= BCM43xx_DMA64_DCTL0_FRAMEEND;
+ if (irq)
+ ctl0 |= BCM43xx_DMA64_DCTL0_IRQ;
+ ctl1 |= (bufsize - ring->frameoffset)
+ & BCM43xx_DMA64_DCTL1_BYTECNT;
+ ctl1 |= (addrext << BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT)
+ & BCM43xx_DMA64_DCTL1_ADDREXT_MASK;
+
+ desc->dma64.control0 = cpu_to_le32(ctl0);
+ desc->dma64.control1 = cpu_to_le32(ctl1);
+ desc->dma64.address_low = cpu_to_le32(addrlo);
+ desc->dma64.address_high = cpu_to_le32(addrhi);
+ } else {
+ u32 ctl;
+ u32 addr;
+ u32 addrext;
+
+ addr = (u32)(dmaaddr & ~BCM43xx_DMA32_ROUTING);
+ addrext = (u32)(dmaaddr & BCM43xx_DMA32_ROUTING)
+ >> BCM43xx_DMA32_ROUTING_SHIFT;
+ addr |= ring->routing;
+ ctl = (bufsize - ring->frameoffset)
+ & BCM43xx_DMA32_DCTL_BYTECNT;
+ if (slot == ring->nr_slots - 1)
+ ctl |= BCM43xx_DMA32_DCTL_DTABLEEND;
+ if (start)
+ ctl |= BCM43xx_DMA32_DCTL_FRAMESTART;
+ if (end)
+ ctl |= BCM43xx_DMA32_DCTL_FRAMEEND;
+ if (irq)
+ ctl |= BCM43xx_DMA32_DCTL_IRQ;
+ ctl |= (addrext << BCM43xx_DMA32_DCTL_ADDREXT_SHIFT)
+ & BCM43xx_DMA32_DCTL_ADDREXT_MASK;
+
+ desc->dma32.control = cpu_to_le32(ctl);
+ desc->dma32.address = cpu_to_le32(addr);
+ }
+}
+
static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
- struct bcm43xx_dmadesc *desc,
+ struct bcm43xx_dmadesc_generic *desc,
struct bcm43xx_dmadesc_meta *meta,
gfp_t gfp_flags)
{
struct bcm43xx_rxhdr *rxhdr;
+ struct bcm43xx_hwxmitstatus *xmitstat;
dma_addr_t dmaaddr;
- u32 desc_addr;
- u32 desc_ctl;
- const int slot = (int)(desc - ring->vbase);
struct sk_buff *skb;
- assert(slot >= 0 && slot < ring->nr_slots);
assert(!ring->tx);
skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
if (unlikely(!skb))
return -ENOMEM;
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
- if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) {
- unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
- dev_kfree_skb_any(skb);
- printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G "
- "(0x%llx, len: %u)\n",
- (unsigned long long)dmaaddr, ring->rx_buffersize);
- return -ENOMEM;
- }
meta->skb = skb;
meta->dmaaddr = dmaaddr;
skb->dev = ring->bcm->net_dev;
- desc_addr = (u32)(dmaaddr + ring->memoffset);
- desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK &
- (u32)(ring->rx_buffersize - ring->frameoffset));
- if (slot == ring->nr_slots - 1)
- desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
- set_desc_addr(desc, desc_addr);
- set_desc_ctl(desc, desc_ctl);
+
+ fill_descriptor(ring, desc, dmaaddr,
+ ring->rx_buffersize, 0, 0, 0);
rxhdr = (struct bcm43xx_rxhdr *)(skb->data);
rxhdr->frame_length = 0;
rxhdr->flags1 = 0;
+ xmitstat = (struct bcm43xx_hwxmitstatus *)(skb->data);
+ xmitstat->cookie = 0;
return 0;
}
@@ -336,17 +429,17 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring,
static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring)
{
int i, err = -ENOMEM;
- struct bcm43xx_dmadesc *desc;
+ struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
for (i = 0; i < ring->nr_slots; i++) {
- desc = ring->vbase + i;
- meta = ring->meta + i;
+ desc = bcm43xx_dma_idx2desc(ring, i, &meta);
err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL);
if (err)
goto err_unwind;
}
+ mb();
ring->used_slots = ring->nr_slots;
err = 0;
out:
@@ -354,8 +447,7 @@ out:
err_unwind:
for (i--; i >= 0; i--) {
- desc = ring->vbase + i;
- meta = ring->meta + i;
+ desc = bcm43xx_dma_idx2desc(ring, i, &meta);
unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0);
dev_kfree_skb(meta->skb);
@@ -371,27 +463,67 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring)
{
int err = 0;
u32 value;
+ u32 addrext;
if (ring->tx) {
- /* Set Transmit Control register to "transmit enable" */
- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
- BCM43xx_DMA_TXCTRL_ENABLE);
- /* Set Transmit Descriptor ring address. */
- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING,
- ring->dmabase + ring->memoffset);
+ if (ring->dma64) {
+ u64 ringbase = (u64)(ring->dmabase);
+
+ addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+ value = BCM43xx_DMA64_TXENABLE;
+ value |= (addrext << BCM43xx_DMA64_TXADDREXT_SHIFT)
+ & BCM43xx_DMA64_TXADDREXT_MASK;
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL, value);
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI,
+ ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+ | ring->routing);
+ } else {
+ u32 ringbase = (u32)(ring->dmabase);
+
+ addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+ value = BCM43xx_DMA32_TXENABLE;
+ value |= (addrext << BCM43xx_DMA32_TXADDREXT_SHIFT)
+ & BCM43xx_DMA32_TXADDREXT_MASK;
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL, value);
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING,
+ (ringbase & ~BCM43xx_DMA32_ROUTING)
+ | ring->routing);
+ }
} else {
err = alloc_initial_descbuffers(ring);
if (err)
goto out;
- /* Set Receive Control "receive enable" and frame offset */
- value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT);
- value |= BCM43xx_DMA_RXCTRL_ENABLE;
- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value);
- /* Set Receive Descriptor ring address. */
- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING,
- ring->dmabase + ring->memoffset);
- /* Init the descriptor pointer. */
- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200);
+ if (ring->dma64) {
+ u64 ringbase = (u64)(ring->dmabase);
+
+ addrext = ((ringbase >> 32) >> BCM43xx_DMA64_ROUTING_SHIFT);
+ value = (ring->frameoffset << BCM43xx_DMA64_RXFROFF_SHIFT);
+ value |= BCM43xx_DMA64_RXENABLE;
+ value |= (addrext << BCM43xx_DMA64_RXADDREXT_SHIFT)
+ & BCM43xx_DMA64_RXADDREXT_MASK;
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXCTL, value);
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO,
+ (ringbase & 0xFFFFFFFF));
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI,
+ ((ringbase >> 32) & ~BCM43xx_DMA64_ROUTING)
+ | ring->routing);
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX, 200);
+ } else {
+ u32 ringbase = (u32)(ring->dmabase);
+
+ addrext = (ringbase >> BCM43xx_DMA32_ROUTING_SHIFT);
+ value = (ring->frameoffset << BCM43xx_DMA32_RXFROFF_SHIFT);
+ value |= BCM43xx_DMA32_RXENABLE;
+ value |= (addrext << BCM43xx_DMA32_RXADDREXT_SHIFT)
+ & BCM43xx_DMA32_RXADDREXT_MASK;
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXCTL, value);
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING,
+ (ringbase & ~BCM43xx_DMA32_ROUTING)
+ | ring->routing);
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX, 200);
+ }
}
out:
@@ -402,27 +534,32 @@ out:
static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring)
{
if (ring->tx) {
- bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base);
- /* Zero out Transmit Descriptor ring address. */
- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0);
+ bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+ if (ring->dma64) {
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGLO, 0);
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXRINGHI, 0);
+ } else
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXRING, 0);
} else {
- bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base);
- /* Zero out Receive Descriptor ring address. */
- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0);
+ bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base, ring->dma64);
+ if (ring->dma64) {
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGLO, 0);
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXRINGHI, 0);
+ } else
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXRING, 0);
}
}
static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
{
- struct bcm43xx_dmadesc *desc;
+ struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
int i;
if (!ring->used_slots)
return;
for (i = 0; i < ring->nr_slots; i++) {
- desc = ring->vbase + i;
- meta = ring->meta + i;
+ desc = bcm43xx_dma_idx2desc(ring, i, &meta);
if (!meta->skb) {
assert(ring->tx);
@@ -430,62 +567,67 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring)
}
if (ring->tx) {
unmap_descbuffer(ring, meta->dmaaddr,
- meta->skb->len, 1);
+ meta->skb->len, 1);
} else {
unmap_descbuffer(ring, meta->dmaaddr,
- ring->rx_buffersize, 0);
+ ring->rx_buffersize, 0);
}
- free_descriptor_buffer(ring, desc, meta, 0);
+ free_descriptor_buffer(ring, meta, 0);
}
}
/* Main initialization function. */
static
struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm,
- u16 dma_controller_base,
- int nr_descriptor_slots,
- int tx)
+ int controller_index,
+ int for_tx,
+ int dma64)
{
struct bcm43xx_dmaring *ring;
int err;
+ int nr_slots;
ring = kzalloc(sizeof(*ring), GFP_KERNEL);
if (!ring)
goto out;
- ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots,
+ nr_slots = BCM43xx_RXRING_SLOTS;
+ if (for_tx)
+ nr_slots = BCM43xx_TXRING_SLOTS;
+
+ ring->meta = kcalloc(nr_slots, sizeof(struct bcm43xx_dmadesc_meta),
GFP_KERNEL);
if (!ring->meta)
goto err_kfree_ring;
- ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET;
+ ring->routing = BCM43xx_DMA32_CLIENTTRANS;
+ if (dma64)
+ ring->routing = BCM43xx_DMA64_CLIENTTRANS;
#ifdef CONFIG_BCM947XX
if (bcm->pci_dev->bus->number == 0)
- ring->memoffset = 0;
+ ring->routing = dma64 ? BCM43xx_DMA64_NOTRANS : BCM43xx_DMA32_NOTRANS;
#endif
ring->bcm = bcm;
- ring->nr_slots = nr_descriptor_slots;
+ ring->nr_slots = nr_slots;
ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100;
ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100;
assert(ring->suspend_mark < ring->resume_mark);
- ring->mmio_base = dma_controller_base;
- if (tx) {
+ ring->mmio_base = bcm43xx_dmacontroller_base(dma64, controller_index);
+ ring->index = controller_index;
+ ring->dma64 = !!dma64;
+ if (for_tx) {
ring->tx = 1;
ring->current_slot = -1;
} else {
- switch (dma_controller_base) {
- case BCM43xx_MMIO_DMA1_BASE:
- ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE;
- ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET;
- break;
- case BCM43xx_MMIO_DMA4_BASE:
- ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE;
- ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET;
- break;
- default:
+ if (ring->index == 0) {
+ ring->rx_buffersize = BCM43xx_DMA0_RX_BUFFERSIZE;
+ ring->frameoffset = BCM43xx_DMA0_RX_FRAMEOFFSET;
+ } else if (ring->index == 3) {
+ ring->rx_buffersize = BCM43xx_DMA3_RX_BUFFERSIZE;
+ ring->frameoffset = BCM43xx_DMA3_RX_FRAMEOFFSET;
+ } else
assert(0);
- }
}
err = alloc_ringmemory(ring);
@@ -514,7 +656,8 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring)
if (!ring)
return;
- dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n",
+ dprintk(KERN_INFO PFX "DMA-%s 0x%04X (%s) max used slots: %d/%d\n",
+ (ring->dma64) ? "64" : "32",
ring->mmio_base,
(ring->tx) ? "TX" : "RX",
ring->max_used_slots, ring->nr_slots);
@@ -537,10 +680,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm)
return;
dma = bcm43xx_current_dma(bcm);
- bcm43xx_destroy_dmaring(dma->rx_ring1);
- dma->rx_ring1 = NULL;
+ bcm43xx_destroy_dmaring(dma->rx_ring3);
+ dma->rx_ring3 = NULL;
bcm43xx_destroy_dmaring(dma->rx_ring0);
dma->rx_ring0 = NULL;
+
+ bcm43xx_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+ bcm43xx_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
bcm43xx_destroy_dmaring(dma->tx_ring3);
dma->tx_ring3 = NULL;
bcm43xx_destroy_dmaring(dma->tx_ring2);
@@ -556,48 +704,59 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm)
struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm);
struct bcm43xx_dmaring *ring;
int err = -ENOMEM;
+ int dma64 = 0;
+ u32 sbtmstatehi;
+
+ sbtmstatehi = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);
+ if (sbtmstatehi & BCM43xx_SBTMSTATEHIGH_DMA64BIT)
+ dma64 = 1;
/* setup TX DMA channels. */
- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
- BCM43xx_TXRING_SLOTS, 1);
+ ring = bcm43xx_setup_dmaring(bcm, 0, 1, dma64);
if (!ring)
goto out;
dma->tx_ring0 = ring;
- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE,
- BCM43xx_TXRING_SLOTS, 1);
+ ring = bcm43xx_setup_dmaring(bcm, 1, 1, dma64);
if (!ring)
goto err_destroy_tx0;
dma->tx_ring1 = ring;
- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE,
- BCM43xx_TXRING_SLOTS, 1);
+ ring = bcm43xx_setup_dmaring(bcm, 2, 1, dma64);
if (!ring)
goto err_destroy_tx1;
dma->tx_ring2 = ring;
- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
- BCM43xx_TXRING_SLOTS, 1);
+ ring = bcm43xx_setup_dmaring(bcm, 3, 1, dma64);
if (!ring)
goto err_destroy_tx2;
dma->tx_ring3 = ring;
- /* setup RX DMA channels. */
- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE,
- BCM43xx_RXRING_SLOTS, 0);
+ ring = bcm43xx_setup_dmaring(bcm, 4, 1, dma64);
if (!ring)
goto err_destroy_tx3;
+ dma->tx_ring4 = ring;
+
+ ring = bcm43xx_setup_dmaring(bcm, 5, 1, dma64);
+ if (!ring)
+ goto err_destroy_tx4;
+ dma->tx_ring5 = ring;
+
+ /* setup RX DMA channels. */
+ ring = bcm43xx_setup_dmaring(bcm, 0, 0, dma64);
+ if (!ring)
+ goto err_destroy_tx5;
dma->rx_ring0 = ring;
if (bcm->current_core->rev < 5) {
- ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE,
- BCM43xx_RXRING_SLOTS, 0);
+ ring = bcm43xx_setup_dmaring(bcm, 3, 0, dma64);
if (!ring)
goto err_destroy_rx0;
- dma->rx_ring1 = ring;
+ dma->rx_ring3 = ring;
}
- dprintk(KERN_INFO PFX "DMA initialized\n");
+ dprintk(KERN_INFO PFX "%s DMA initialized\n",
+ dma64 ? "64-bit" : "32-bit");
err = 0;
out:
return err;
@@ -605,6 +764,12 @@ out:
err_destroy_rx0:
bcm43xx_destroy_dmaring(dma->rx_ring0);
dma->rx_ring0 = NULL;
+err_destroy_tx5:
+ bcm43xx_destroy_dmaring(dma->tx_ring5);
+ dma->tx_ring5 = NULL;
+err_destroy_tx4:
+ bcm43xx_destroy_dmaring(dma->tx_ring4);
+ dma->tx_ring4 = NULL;
err_destroy_tx3:
bcm43xx_destroy_dmaring(dma->tx_ring3);
dma->tx_ring3 = NULL;
@@ -624,7 +789,7 @@ err_destroy_tx0:
static u16 generate_cookie(struct bcm43xx_dmaring *ring,
int slot)
{
- u16 cookie = 0xF000;
+ u16 cookie = 0x1000;
/* Use the upper 4 bits of the cookie as
* DMA controller ID and store the slot number
@@ -632,21 +797,25 @@ static u16 generate_cookie(struct bcm43xx_dmaring *ring,
* Note that the cookie must never be 0, as this
* is a special value used in RX path.
*/
- switch (ring->mmio_base) {
- default:
- assert(0);
- case BCM43xx_MMIO_DMA1_BASE:
+ switch (ring->index) {
+ case 0:
cookie = 0xA000;
break;
- case BCM43xx_MMIO_DMA2_BASE:
+ case 1:
cookie = 0xB000;
break;
- case BCM43xx_MMIO_DMA3_BASE:
+ case 2:
cookie = 0xC000;
break;
- case BCM43xx_MMIO_DMA4_BASE:
+ case 3:
cookie = 0xD000;
break;
+ case 4:
+ cookie = 0xE000;
+ break;
+ case 5:
+ cookie = 0xF000;
+ break;
}
assert(((u16)slot & 0xF000) == 0x0000);
cookie |= (u16)slot;
@@ -675,6 +844,12 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
case 0xD000:
ring = dma->tx_ring3;
break;
+ case 0xE000:
+ ring = dma->tx_ring4;
+ break;
+ case 0xF000:
+ ring = dma->tx_ring5;
+ break;
default:
assert(0);
}
@@ -687,6 +862,9 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm,
static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
int slot)
{
+ u16 offset;
+ int descsize;
+
/* Everything is ready to start. Buffers are DMA mapped and
* associated with slots.
* "slot" is the last slot of the new frame we want to transmit.
@@ -694,25 +872,26 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring,
*/
wmb();
slot = next_slot(ring, slot);
- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX,
- (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+ offset = (ring->dma64) ? BCM43xx_DMA64_TXINDEX : BCM43xx_DMA32_TXINDEX;
+ descsize = (ring->dma64) ? sizeof(struct bcm43xx_dmadesc64)
+ : sizeof(struct bcm43xx_dmadesc32);
+ bcm43xx_dma_write(ring, offset,
+ (u32)(slot * descsize));
}
-static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
- struct sk_buff *skb,
- u8 cur_frag)
+static void dma_tx_fragment(struct bcm43xx_dmaring *ring,
+ struct sk_buff *skb,
+ u8 cur_frag)
{
int slot;
- struct bcm43xx_dmadesc *desc;
+ struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
- u32 desc_ctl;
- u32 desc_addr;
+ dma_addr_t dmaaddr;
assert(skb_shinfo(skb)->nr_frags == 0);
slot = request_slot(ring);
- desc = ring->vbase + slot;
- meta = ring->meta + slot;
+ desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
/* Add a device specific TX header. */
assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr));
@@ -729,29 +908,14 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring,
generate_cookie(ring, slot));
meta->skb = skb;
- meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
- if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) {
- return_slot(ring, slot);
- printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G "
- "(0x%llx, len: %u)\n",
- (unsigned long long)meta->dmaaddr, skb->len);
- return -ENOMEM;
- }
+ dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
+ meta->dmaaddr = dmaaddr;
- desc_addr = (u32)(meta->dmaaddr + ring->memoffset);
- desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND;
- desc_ctl |= BCM43xx_DMADTOR_COMPIRQ;
- desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK &
- (u32)(meta->skb->len - ring->frameoffset));
- if (slot == ring->nr_slots - 1)
- desc_ctl |= BCM43xx_DMADTOR_DTABLEEND;
+ fill_descriptor(ring, desc, dmaaddr,
+ skb->len, 1, 1, 1);
- set_desc_ctl(desc, desc_ctl);
- set_desc_addr(desc, desc_addr);
/* Now transfer the whole frame. */
dmacontroller_poke_tx(ring, slot);
-
- return 0;
}
int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
@@ -781,7 +945,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
/* Take skb from ieee80211_txb_free */
txb->fragments[i] = NULL;
dma_tx_fragment(ring, skb, i);
- //TODO: handle failure of dma_tx_fragment
}
ieee80211_txb_free(txb);
@@ -792,23 +955,28 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
struct bcm43xx_xmitstatus *status)
{
struct bcm43xx_dmaring *ring;
- struct bcm43xx_dmadesc *desc;
+ struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
int is_last_fragment;
int slot;
+ u32 tmp;
ring = parse_cookie(bcm, status->cookie, &slot);
assert(ring);
assert(ring->tx);
- assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART);
while (1) {
assert(slot >= 0 && slot < ring->nr_slots);
- desc = ring->vbase + slot;
- meta = ring->meta + slot;
+ desc = bcm43xx_dma_idx2desc(ring, slot, &meta);
- is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND);
+ if (ring->dma64) {
+ tmp = le32_to_cpu(desc->dma64.control0);
+ is_last_fragment = !!(tmp & BCM43xx_DMA64_DCTL0_FRAMEEND);
+ } else {
+ tmp = le32_to_cpu(desc->dma32.control);
+ is_last_fragment = !!(tmp & BCM43xx_DMA32_DCTL_FRAMEEND);
+ }
unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1);
- free_descriptor_buffer(ring, desc, meta, 1);
+ free_descriptor_buffer(ring, meta, 1);
/* Everything belonging to the slot is unmapped
* and freed, so we can return it.
*/
@@ -824,7 +992,7 @@ void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm,
static void dma_rx(struct bcm43xx_dmaring *ring,
int *slot)
{
- struct bcm43xx_dmadesc *desc;
+ struct bcm43xx_dmadesc_generic *desc;
struct bcm43xx_dmadesc_meta *meta;
struct bcm43xx_rxhdr *rxhdr;
struct sk_buff *skb;
@@ -832,13 +1000,12 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
int err;
dma_addr_t dmaaddr;
- desc = ring->vbase + *slot;
- meta = ring->meta + *slot;
+ desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize);
skb = meta->skb;
- if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) {
+ if (ring->index == 3) {
/* We received an xmit status. */
struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data;
struct bcm43xx_xmitstatus stat;
@@ -894,8 +1061,7 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
s32 tmp = len;
while (1) {
- desc = ring->vbase + *slot;
- meta = ring->meta + *slot;
+ desc = bcm43xx_dma_idx2desc(ring, *slot, &meta);
/* recycle the descriptor buffer. */
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize);
@@ -906,8 +1072,8 @@ static void dma_rx(struct bcm43xx_dmaring *ring,
break;
}
printkl(KERN_ERR PFX "DMA RX buffer too small "
- "(len: %u, buffer: %u, nr-dropped: %d)\n",
- len, ring->rx_buffersize, cnt);
+ "(len: %u, buffer: %u, nr-dropped: %d)\n",
+ len, ring->rx_buffersize, cnt);
goto drop;
}
len -= IEEE80211_FCS_LEN;
@@ -945,9 +1111,15 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
#endif
assert(!ring->tx);
- status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS);
- descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK);
- current_slot = descptr / sizeof(struct bcm43xx_dmadesc);
+ if (ring->dma64) {
+ status = bcm43xx_dma_read(ring, BCM43xx_DMA64_RXSTATUS);
+ descptr = (status & BCM43xx_DMA64_RXSTATDPTR);
+ current_slot = descptr / sizeof(struct bcm43xx_dmadesc64);
+ } else {
+ status = bcm43xx_dma_read(ring, BCM43xx_DMA32_RXSTATUS);
+ descptr = (status & BCM43xx_DMA32_RXDPTR);
+ current_slot = descptr / sizeof(struct bcm43xx_dmadesc32);
+ }
assert(current_slot >= 0 && current_slot < ring->nr_slots);
slot = ring->current_slot;
@@ -958,8 +1130,13 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)
ring->max_used_slots = used_slots;
#endif
}
- bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX,
- (u32)(slot * sizeof(struct bcm43xx_dmadesc)));
+ if (ring->dma64) {
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_RXINDEX,
+ (u32)(slot * sizeof(struct bcm43xx_dmadesc64)));
+ } else {
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_RXINDEX,
+ (u32)(slot * sizeof(struct bcm43xx_dmadesc32)));
+ }
ring->current_slot = slot;
}
@@ -967,16 +1144,28 @@ void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring)
{
assert(ring->tx);
bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1);
- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
- bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
- | BCM43xx_DMA_TXCTRL_SUSPEND);
+ if (ring->dma64) {
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
+ bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
+ | BCM43xx_DMA64_TXSUSPEND);
+ } else {
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
+ bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
+ | BCM43xx_DMA32_TXSUSPEND);
+ }
}
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring)
{
assert(ring->tx);
- bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL,
- bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL)
- & ~BCM43xx_DMA_TXCTRL_SUSPEND);
+ if (ring->dma64) {
+ bcm43xx_dma_write(ring, BCM43xx_DMA64_TXCTL,
+ bcm43xx_dma_read(ring, BCM43xx_DMA64_TXCTL)
+ & ~BCM43xx_DMA64_TXSUSPEND);
+ } else {
+ bcm43xx_dma_write(ring, BCM43xx_DMA32_TXCTL,
+ bcm43xx_dma_read(ring, BCM43xx_DMA32_TXCTL)
+ & ~BCM43xx_DMA32_TXSUSPEND);
+ }
bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
index b7d77638ba8..e04bcaddd1d 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h
@@ -14,63 +14,179 @@
#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13)
#define BCM43xx_DMAIRQ_RX_DONE (1 << 16)
-/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */
-#define BCM43xx_DMA_TX_CONTROL 0x00
-#define BCM43xx_DMA_TX_DESC_RING 0x04
-#define BCM43xx_DMA_TX_DESC_INDEX 0x08
-#define BCM43xx_DMA_TX_STATUS 0x0c
-#define BCM43xx_DMA_RX_CONTROL 0x10
-#define BCM43xx_DMA_RX_DESC_RING 0x14
-#define BCM43xx_DMA_RX_DESC_INDEX 0x18
-#define BCM43xx_DMA_RX_STATUS 0x1c
-
-/* DMA controller channel control word values. */
-#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0)
-#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1)
-#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2)
-#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4)
-#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0)
-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe
-#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1
-#define BCM43xx_DMA_RXCTRL_PIO (1 << 8)
-/* DMA controller channel status word values. */
-#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff
-#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000
-#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000
-#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000
-#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000
-#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000
-#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000
-#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000
-#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20)
-#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff
-#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000
-#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000
-#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000
-#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000
-#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000
-#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000
-#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000
-
-/* DMA descriptor control field values. */
-#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff
-#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */
-#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */
-#define BCM43xx_DMADTOR_FRAMEEND (1 << 30)
-#define BCM43xx_DMADTOR_FRAMESTART (1 << 31)
+
+/*** 32-bit DMA Engine. ***/
+
+/* 32-bit DMA controller registers. */
+#define BCM43xx_DMA32_TXCTL 0x00
+#define BCM43xx_DMA32_TXENABLE 0x00000001
+#define BCM43xx_DMA32_TXSUSPEND 0x00000002
+#define BCM43xx_DMA32_TXLOOPBACK 0x00000004
+#define BCM43xx_DMA32_TXFLUSH 0x00000010
+#define BCM43xx_DMA32_TXADDREXT_MASK 0x00030000
+#define BCM43xx_DMA32_TXADDREXT_SHIFT 16
+#define BCM43xx_DMA32_TXRING 0x04
+#define BCM43xx_DMA32_TXINDEX 0x08
+#define BCM43xx_DMA32_TXSTATUS 0x0C
+#define BCM43xx_DMA32_TXDPTR 0x00000FFF
+#define BCM43xx_DMA32_TXSTATE 0x0000F000
+#define BCM43xx_DMA32_TXSTAT_DISABLED 0x00000000
+#define BCM43xx_DMA32_TXSTAT_ACTIVE 0x00001000
+#define BCM43xx_DMA32_TXSTAT_IDLEWAIT 0x00002000
+#define BCM43xx_DMA32_TXSTAT_STOPPED 0x00003000
+#define BCM43xx_DMA32_TXSTAT_SUSP 0x00004000
+#define BCM43xx_DMA32_TXERROR 0x000F0000
+#define BCM43xx_DMA32_TXERR_NOERR 0x00000000
+#define BCM43xx_DMA32_TXERR_PROT 0x00010000
+#define BCM43xx_DMA32_TXERR_UNDERRUN 0x00020000
+#define BCM43xx_DMA32_TXERR_BUFREAD 0x00030000
+#define BCM43xx_DMA32_TXERR_DESCREAD 0x00040000
+#define BCM43xx_DMA32_TXACTIVE 0xFFF00000
+#define BCM43xx_DMA32_RXCTL 0x10
+#define BCM43xx_DMA32_RXENABLE 0x00000001
+#define BCM43xx_DMA32_RXFROFF_MASK 0x000000FE
+#define BCM43xx_DMA32_RXFROFF_SHIFT 1
+#define BCM43xx_DMA32_RXDIRECTFIFO 0x00000100
+#define BCM43xx_DMA32_RXADDREXT_MASK 0x00030000
+#define BCM43xx_DMA32_RXADDREXT_SHIFT 16
+#define BCM43xx_DMA32_RXRING 0x14
+#define BCM43xx_DMA32_RXINDEX 0x18
+#define BCM43xx_DMA32_RXSTATUS 0x1C
+#define BCM43xx_DMA32_RXDPTR 0x00000FFF
+#define BCM43xx_DMA32_RXSTATE 0x0000F000
+#define BCM43xx_DMA32_RXSTAT_DISABLED 0x00000000
+#define BCM43xx_DMA32_RXSTAT_ACTIVE 0x00001000
+#define BCM43xx_DMA32_RXSTAT_IDLEWAIT 0x00002000
+#define BCM43xx_DMA32_RXSTAT_STOPPED 0x00003000
+#define BCM43xx_DMA32_RXERROR 0x000F0000
+#define BCM43xx_DMA32_RXERR_NOERR 0x00000000
+#define BCM43xx_DMA32_RXERR_PROT 0x00010000
+#define BCM43xx_DMA32_RXERR_OVERFLOW 0x00020000
+#define BCM43xx_DMA32_RXERR_BUFWRITE 0x00030000
+#define BCM43xx_DMA32_RXERR_DESCREAD 0x00040000
+#define BCM43xx_DMA32_RXACTIVE 0xFFF00000
+
+/* 32-bit DMA descriptor. */
+struct bcm43xx_dmadesc32 {
+ __le32 control;
+ __le32 address;
+} __attribute__((__packed__));
+#define BCM43xx_DMA32_DCTL_BYTECNT 0x00001FFF
+#define BCM43xx_DMA32_DCTL_ADDREXT_MASK 0x00030000
+#define BCM43xx_DMA32_DCTL_ADDREXT_SHIFT 16
+#define BCM43xx_DMA32_DCTL_DTABLEEND 0x10000000
+#define BCM43xx_DMA32_DCTL_IRQ 0x20000000
+#define BCM43xx_DMA32_DCTL_FRAMEEND 0x40000000
+#define BCM43xx_DMA32_DCTL_FRAMESTART 0x80000000
+
+/* Address field Routing value. */
+#define BCM43xx_DMA32_ROUTING 0xC0000000
+#define BCM43xx_DMA32_ROUTING_SHIFT 30
+#define BCM43xx_DMA32_NOTRANS 0x00000000
+#define BCM43xx_DMA32_CLIENTTRANS 0x40000000
+
+
+
+/*** 64-bit DMA Engine. ***/
+
+/* 64-bit DMA controller registers. */
+#define BCM43xx_DMA64_TXCTL 0x00
+#define BCM43xx_DMA64_TXENABLE 0x00000001
+#define BCM43xx_DMA64_TXSUSPEND 0x00000002
+#define BCM43xx_DMA64_TXLOOPBACK 0x00000004
+#define BCM43xx_DMA64_TXFLUSH 0x00000010
+#define BCM43xx_DMA64_TXADDREXT_MASK 0x00030000
+#define BCM43xx_DMA64_TXADDREXT_SHIFT 16
+#define BCM43xx_DMA64_TXINDEX 0x04
+#define BCM43xx_DMA64_TXRINGLO 0x08
+#define BCM43xx_DMA64_TXRINGHI 0x0C
+#define BCM43xx_DMA64_TXSTATUS 0x10
+#define BCM43xx_DMA64_TXSTATDPTR 0x00001FFF
+#define BCM43xx_DMA64_TXSTAT 0xF0000000
+#define BCM43xx_DMA64_TXSTAT_DISABLED 0x00000000
+#define BCM43xx_DMA64_TXSTAT_ACTIVE 0x10000000
+#define BCM43xx_DMA64_TXSTAT_IDLEWAIT 0x20000000
+#define BCM43xx_DMA64_TXSTAT_STOPPED 0x30000000
+#define BCM43xx_DMA64_TXSTAT_SUSP 0x40000000
+#define BCM43xx_DMA64_TXERROR 0x14
+#define BCM43xx_DMA64_TXERRDPTR 0x0001FFFF
+#define BCM43xx_DMA64_TXERR 0xF0000000
+#define BCM43xx_DMA64_TXERR_NOERR 0x00000000
+#define BCM43xx_DMA64_TXERR_PROT 0x10000000
+#define BCM43xx_DMA64_TXERR_UNDERRUN 0x20000000
+#define BCM43xx_DMA64_TXERR_TRANSFER 0x30000000
+#define BCM43xx_DMA64_TXERR_DESCREAD 0x40000000
+#define BCM43xx_DMA64_TXERR_CORE 0x50000000
+#define BCM43xx_DMA64_RXCTL 0x20
+#define BCM43xx_DMA64_RXENABLE 0x00000001
+#define BCM43xx_DMA64_RXFROFF_MASK 0x000000FE
+#define BCM43xx_DMA64_RXFROFF_SHIFT 1
+#define BCM43xx_DMA64_RXDIRECTFIFO 0x00000100
+#define BCM43xx_DMA64_RXADDREXT_MASK 0x00030000
+#define BCM43xx_DMA64_RXADDREXT_SHIFT 16
+#define BCM43xx_DMA64_RXINDEX 0x24
+#define BCM43xx_DMA64_RXRINGLO 0x28
+#define BCM43xx_DMA64_RXRINGHI 0x2C
+#define BCM43xx_DMA64_RXSTATUS 0x30
+#define BCM43xx_DMA64_RXSTATDPTR 0x00001FFF
+#define BCM43xx_DMA64_RXSTAT 0xF0000000
+#define BCM43xx_DMA64_RXSTAT_DISABLED 0x00000000
+#define BCM43xx_DMA64_RXSTAT_ACTIVE 0x10000000
+#define BCM43xx_DMA64_RXSTAT_IDLEWAIT 0x20000000
+#define BCM43xx_DMA64_RXSTAT_STOPPED 0x30000000
+#define BCM43xx_DMA64_RXSTAT_SUSP 0x40000000
+#define BCM43xx_DMA64_RXERROR 0x34
+#define BCM43xx_DMA64_RXERRDPTR 0x0001FFFF
+#define BCM43xx_DMA64_RXERR 0xF0000000
+#define BCM43xx_DMA64_RXERR_NOERR 0x00000000
+#define BCM43xx_DMA64_RXERR_PROT 0x10000000
+#define BCM43xx_DMA64_RXERR_UNDERRUN 0x20000000
+#define BCM43xx_DMA64_RXERR_TRANSFER 0x30000000
+#define BCM43xx_DMA64_RXERR_DESCREAD 0x40000000
+#define BCM43xx_DMA64_RXERR_CORE 0x50000000
+
+/* 64-bit DMA descriptor. */
+struct bcm43xx_dmadesc64 {
+ __le32 control0;
+ __le32 control1;
+ __le32 address_low;
+ __le32 address_high;
+} __attribute__((__packed__));
+#define BCM43xx_DMA64_DCTL0_DTABLEEND 0x10000000
+#define BCM43xx_DMA64_DCTL0_IRQ 0x20000000
+#define BCM43xx_DMA64_DCTL0_FRAMEEND 0x40000000
+#define BCM43xx_DMA64_DCTL0_FRAMESTART 0x80000000
+#define BCM43xx_DMA64_DCTL1_BYTECNT 0x00001FFF
+#define BCM43xx_DMA64_DCTL1_ADDREXT_MASK 0x00030000
+#define BCM43xx_DMA64_DCTL1_ADDREXT_SHIFT 16
+
+/* Address field Routing value. */
+#define BCM43xx_DMA64_ROUTING 0xC0000000
+#define BCM43xx_DMA64_ROUTING_SHIFT 30
+#define BCM43xx_DMA64_NOTRANS 0x00000000
+#define BCM43xx_DMA64_CLIENTTRANS 0x80000000
+
+
+
+struct bcm43xx_dmadesc_generic {
+ union {
+ struct bcm43xx_dmadesc32 dma32;
+ struct bcm43xx_dmadesc64 dma64;
+ } __attribute__((__packed__));
+} __attribute__((__packed__));
+
/* Misc DMA constants */
#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE
-#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF
-#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30)
-#define BCM43xx_DMA1_RX_FRAMEOFFSET 30
-#define BCM43xx_DMA4_RX_FRAMEOFFSET 0
+#define BCM43xx_DMA0_RX_FRAMEOFFSET 30
+#define BCM43xx_DMA3_RX_FRAMEOFFSET 0
+
/* DMA engine tuning knobs */
#define BCM43xx_TXRING_SLOTS 512
#define BCM43xx_RXRING_SLOTS 64
-#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100)
-#define BCM43xx_DMA4_RXBUFFERSIZE 16
+#define BCM43xx_DMA0_RX_BUFFERSIZE (2304 + 100)
+#define BCM43xx_DMA3_RX_BUFFERSIZE 16
/* Suspend the tx queue, if less than this percent slots are free. */
#define BCM43xx_TXSUSPEND_PERCENT 20
/* Resume the tx queue, if more than this percent slots are free. */
@@ -86,17 +202,6 @@ struct bcm43xx_private;
struct bcm43xx_xmitstatus;
-struct bcm43xx_dmadesc {
- __le32 _control;
- __le32 _address;
-} __attribute__((__packed__));
-
-/* Macros to access the bcm43xx_dmadesc struct */
-#define get_desc_ctl(desc) le32_to_cpu((desc)->_control)
-#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0)
-#define get_desc_addr(desc) le32_to_cpu((desc)->_address)
-#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0)
-
struct bcm43xx_dmadesc_meta {
/* The kernel DMA-able buffer. */
struct sk_buff *skb;
@@ -105,15 +210,14 @@ struct bcm43xx_dmadesc_meta {
};
struct bcm43xx_dmaring {
- struct bcm43xx_private *bcm;
/* Kernel virtual base address of the ring memory. */
- struct bcm43xx_dmadesc *vbase;
- /* DMA memory offset */
- dma_addr_t memoffset;
- /* (Unadjusted) DMA base bus-address of the ring memory. */
- dma_addr_t dmabase;
+ void *descbase;
/* Meta data about all descriptors. */
struct bcm43xx_dmadesc_meta *meta;
+ /* DMA Routing value. */
+ u32 routing;
+ /* (Unadjusted) DMA base bus-address of the ring memory. */
+ dma_addr_t dmabase;
/* Number of descriptor slots in the ring. */
int nr_slots;
/* Number of used descriptor slots. */
@@ -127,12 +231,17 @@ struct bcm43xx_dmaring {
u32 frameoffset;
/* Descriptor buffer size. */
u16 rx_buffersize;
- /* The MMIO base register of the DMA controller, this
- * ring is posted to.
- */
+ /* The MMIO base register of the DMA controller. */
u16 mmio_base;
- u8 tx:1, /* TRUE, if this is a TX ring. */
- suspended:1; /* TRUE, if transfers are suspended on this ring. */
+ /* DMA controller index number (0-5). */
+ int index;
+ /* Boolean. Is this a TX ring? */
+ u8 tx;
+ /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */
+ u8 dma64;
+ /* Boolean. Are transfers suspended on this ring? */
+ u8 suspended;
+ struct bcm43xx_private *bcm;
#ifdef CONFIG_BCM43XX_DEBUG
/* Maximum number of used slots. */
int max_used_slots;
@@ -141,6 +250,34 @@ struct bcm43xx_dmaring {
static inline
+int bcm43xx_dma_desc2idx(struct bcm43xx_dmaring *ring,
+ struct bcm43xx_dmadesc_generic *desc)
+{
+ if (ring->dma64) {
+ struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
+ return (int)(&(desc->dma64) - dd64);
+ } else {
+ struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
+ return (int)(&(desc->dma32) - dd32);
+ }
+}
+
+static inline
+struct bcm43xx_dmadesc_generic * bcm43xx_dma_idx2desc(struct bcm43xx_dmaring *ring,
+ int slot,
+ struct bcm43xx_dmadesc_meta **meta)
+{
+ *meta = &(ring->meta[slot]);
+ if (ring->dma64) {
+ struct bcm43xx_dmadesc64 *dd64 = ring->descbase;
+ return (struct bcm43xx_dmadesc_generic *)(&(dd64[slot]));
+ } else {
+ struct bcm43xx_dmadesc32 *dd32 = ring->descbase;
+ return (struct bcm43xx_dmadesc_generic *)(&(dd32[slot]));
+ }
+}
+
+static inline
u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring,
u16 offset)
{
@@ -159,9 +296,13 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm);
void bcm43xx_dma_free(struct bcm43xx_private *bcm);
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base);
+ u16 dmacontroller_mmio_base,
+ int dma64);
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base);
+ u16 dmacontroller_mmio_base,
+ int dma64);
+
+u16 bcm43xx_dmacontroller_base(int dma64bit, int dmacontroller_idx);
void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring);
void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring);
@@ -173,7 +314,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm,
struct ieee80211_txb *txb);
void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring);
-
#else /* CONFIG_BCM43XX_DMA */
@@ -188,13 +328,15 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm)
}
static inline
int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base)
+ u16 dmacontroller_mmio_base,
+ int dma64)
{
return 0;
}
static inline
int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm,
- u16 dmacontroller_mmio_base)
+ u16 dmacontroller_mmio_base,
+ int dma64)
{
return 0;
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
index b3ffcf50131..c947025d655 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c
@@ -32,7 +32,7 @@
#include <linux/netdevice.h>
#include <linux/pci.h>
#include <linux/string.h>
-#include <linux/version.h>
+#include <linux/utsrelease.h>
static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -44,7 +44,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *
strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN);
}
-struct ethtool_ops bcm43xx_ethtool_ops = {
+const struct ethtool_ops bcm43xx_ethtool_ops = {
.get_drvinfo = bcm43xx_get_drvinfo,
.get_link = ethtool_op_get_link,
};
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
index 813704991f6..6f8d42d3cdf 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h
@@ -3,6 +3,6 @@
#include <linux/ethtool.h>
-extern struct ethtool_ops bcm43xx_ethtool_ops;
+extern const struct ethtool_ops bcm43xx_ethtool_ops;
#endif /* BCM43xx_ETHTOOL_H_ */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
index ec80692d638..c3f90c8563d 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c
@@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d)
struct bcm43xx_private *bcm = led->bcm;
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->leds_lock, flags);
if (led->blink_interval) {
bcm43xx_led_changestate(led);
mod_timer(&led->blink_timer, jiffies + led->blink_interval);
}
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->leds_lock, flags);
}
static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
@@ -177,7 +177,9 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
int i, turn_on;
unsigned long interval = 0;
u16 ledctl;
+ unsigned long flags;
+ spin_lock_irqsave(&bcm->leds_lock, flags);
ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(bcm->leds[i]);
@@ -266,6 +268,7 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
ledctl &= ~(1 << i);
}
bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&bcm->leds_lock, flags);
}
void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
@@ -274,7 +277,9 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
u16 ledctl;
int i;
int bit_on;
+ unsigned long flags;
+ spin_lock_irqsave(&bcm->leds_lock, flags);
ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
for (i = 0; i < BCM43xx_NR_LEDS; i++) {
led = &(bcm->leds[i]);
@@ -290,4 +295,5 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
ledctl &= ~(1 << i);
}
bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
+ spin_unlock_irqrestore(&bcm->leds_lock, flags);
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index 085d7857fe3..eb65db7393b 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -509,23 +509,20 @@ static void bcm43xx_synchronize_irq(struct bcm43xx_private *bcm)
}
/* Make sure we don't receive more data from the device. */
-static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate)
+static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm)
{
unsigned long flags;
- u32 old;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (unlikely(bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)) {
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
return -EBUSY;
}
- old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_unlock_irqonly(bcm, flags);
+ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); /* flush */
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_synchronize_irq(bcm);
- if (oldstate)
- *oldstate = old;
-
return 0;
}
@@ -537,7 +534,6 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
u16 manufact;
u16 version;
u8 revision;
- s8 i;
if (bcm->chip_id == 0x4317) {
if (bcm->chip_rev == 0x00)
@@ -580,20 +576,11 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
radio->version = version;
radio->revision = revision;
- /* Set default attenuation values. */
- radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
- radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
- radio->txctl1 = bcm43xx_default_txctl1(bcm);
- radio->txctl2 = 0xFFFF;
if (phy->type == BCM43xx_PHYTYPE_A)
radio->txpower_desired = bcm->sprom.maxpower_aphy;
else
radio->txpower_desired = bcm->sprom.maxpower_bgphy;
- /* Initialize the in-memory nrssi Lookup Table. */
- for (i = 0; i < 64; i++)
- radio->nrssi_lt[i] = i;
-
return 0;
err_unsupported_radio:
@@ -1250,10 +1237,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne
goto out;
bcm->current_core = new_core;
- bcm->current_80211_core_idx = -1;
- if (new_core->id == BCM43xx_COREID_80211)
- bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0]));
-
out:
return err;
}
@@ -1389,6 +1372,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
if ((bcm43xx_core_enabled(bcm)) &&
!bcm43xx_using_pio(bcm)) {
//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?
+#if 0
#ifndef CONFIG_BCM947XX
/* reset all used DMA controllers. */
bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE);
@@ -1399,6 +1383,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy)
if (bcm->current_core->rev < 5)
bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);
#endif
+#endif
}
if (bcm43xx_status(bcm) == BCM43xx_STAT_SHUTTINGDOWN) {
bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
@@ -1423,43 +1408,23 @@ static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm)
bcm43xx_core_disable(bcm, 0);
}
-/* Mark the current 80211 core inactive.
- * "active_80211_core" is the other 80211 core, which is used.
- */
-static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm,
- struct bcm43xx_coreinfo *active_80211_core)
+/* Mark the current 80211 core inactive. */
+static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm)
{
u32 sbtmstatelow;
- struct bcm43xx_coreinfo *old_core;
- int err = 0;
bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
bcm43xx_radio_turn_off(bcm);
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= ~0x200a0000;
- sbtmstatelow |= 0xa0000;
+ sbtmstatelow &= 0xDFF5FFFF;
+ sbtmstatelow |= 0x000A0000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
udelay(1);
sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= ~0xa0000;
- sbtmstatelow |= 0x80000;
+ sbtmstatelow &= 0xFFF5FFFF;
+ sbtmstatelow |= 0x00080000;
bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
udelay(1);
-
- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) {
- old_core = bcm->current_core;
- err = bcm43xx_switch_core(bcm, active_80211_core);
- if (err)
- goto out;
- sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
- sbtmstatelow &= ~0x20000000;
- sbtmstatelow |= 0x20000000;
- bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
- err = bcm43xx_switch_core(bcm, old_core);
- }
-
-out:
- return err;
}
static void handle_irq_transmit_status(struct bcm43xx_private *bcm)
@@ -1547,7 +1512,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
goto generate_new;
/* Get the noise samples. */
- assert(bcm->noisecalc.nr_samples <= 8);
+ assert(bcm->noisecalc.nr_samples < 8);
i = bcm->noisecalc.nr_samples;
noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);
@@ -1581,17 +1546,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
else
average -= 48;
-/* FIXME: This is wrong, but people want fancy stats. well... */
-bcm->stats.noise = average;
- if (average > -65)
- bcm->stats.link_quality = 0;
- else if (average > -75)
- bcm->stats.link_quality = 1;
- else if (average > -85)
- bcm->stats.link_quality = 2;
- else
- bcm->stats.link_quality = 3;
-// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average);
+ bcm->stats.noise = average;
drop_calculation:
bcm->noisecalc.calculation_running = 0;
return;
@@ -1709,8 +1664,9 @@ static void handle_irq_beacon(struct bcm43xx_private *bcm)
static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
{
u32 reason;
- u32 dma_reason[4];
- int activity = 0;
+ u32 dma_reason[6];
+ u32 merged_dma_reason = 0;
+ int i, activity = 0;
unsigned long flags;
#ifdef CONFIG_BCM43XX_DEBUG
@@ -1720,12 +1676,12 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
# define bcmirq_handled(irq) do { /* nothing */ } while (0)
#endif /* CONFIG_BCM43XX_DEBUG*/
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
reason = bcm->irq_reason;
- dma_reason[0] = bcm->dma_reason[0];
- dma_reason[1] = bcm->dma_reason[1];
- dma_reason[2] = bcm->dma_reason[2];
- dma_reason[3] = bcm->dma_reason[3];
+ for (i = 5; i >= 0; i--) {
+ dma_reason[i] = bcm->dma_reason[i];
+ merged_dma_reason |= dma_reason[i];
+ }
if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {
/* TX error. We get this when Template Ram is written in wrong endianess
@@ -1736,27 +1692,25 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");
bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);
}
- if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) |
- (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) |
- (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) |
- (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) {
+ if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {
printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "
- "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1],
- dma_reason[2], dma_reason[3]);
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
bcm43xx_controller_restart(bcm, "DMA error");
mmiowb();
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
return;
}
- if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) |
- (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) |
- (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) |
- (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) {
+ if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {
printkl(KERN_ERR PFX "DMA error: "
- "0x%08X, 0x%08X, 0x%08X, 0x%08X\n",
+ "0x%08X, 0x%08X, 0x%08X, "
+ "0x%08X, 0x%08X, 0x%08X\n",
dma_reason[0], dma_reason[1],
- dma_reason[2], dma_reason[3]);
+ dma_reason[2], dma_reason[3],
+ dma_reason[4], dma_reason[5]);
}
if (reason & BCM43xx_IRQ_PS) {
@@ -1791,8 +1745,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
}
/* Check the DMA reason registers for received data. */
- assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
- assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {
if (bcm43xx_using_pio(bcm))
bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);
@@ -1800,13 +1752,17 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);
/* We intentionally don't set "activity" to 1, here. */
}
+ assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));
+ assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));
if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {
if (bcm43xx_using_pio(bcm))
bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);
else
- bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1);
+ bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);
activity = 1;
}
+ assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));
+ assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));
bcmirq_handled(BCM43xx_IRQ_RX);
if (reason & BCM43xx_IRQ_XMIT_STATUS) {
@@ -1834,7 +1790,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
bcm43xx_leds_update(bcm, activity);
bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
mmiowb();
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
}
static void pio_irq_workaround(struct bcm43xx_private *bcm,
@@ -1863,14 +1819,18 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,
bcm->dma_reason[0]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
bcm->dma_reason[1]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,
bcm->dma_reason[2]);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,
bcm->dma_reason[3]);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,
+ bcm->dma_reason[4]);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,
+ bcm->dma_reason[5]);
}
/* Interrupt handler top-half */
@@ -1885,6 +1845,9 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
spin_lock(&bcm->irq_lock);
+ assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
+ assert(bcm->current_core->id == BCM43xx_COREID_80211);
+
reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
if (reason == 0xffffffff) {
/* irq not for us (shared irq) */
@@ -1895,30 +1858,26 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
if (!reason)
goto out;
- bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
- & 0x0001dc00;
- bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
- & 0x0000dc00;
- bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
- & 0x0000dc00;
- bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
- & 0x0001dc00;
+ bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)
+ & 0x0001DC00;
+ bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+ & 0x0000DC00;
+ bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+ & 0x0000DC00;
+ bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+ & 0x0001DC00;
+ bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+ & 0x0000DC00;
+ bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)
+ & 0x0000DC00;
bcm43xx_interrupt_ack(bcm, reason);
- /* Only accept IRQs, if we are initialized properly.
- * This avoids an RX race while initializing.
- * We should probably not enable IRQs before we are initialized
- * completely, but some careful work is needed to fix this. I think it
- * is best to stay with this cheap workaround for now... .
- */
- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
- /* disable all IRQs. They are enabled again in the bottom half. */
- bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- /* save the reason code and call our bottom half. */
- bcm->irq_reason = reason;
- tasklet_schedule(&bcm->isr_tasklet);
- }
+ /* disable all IRQs. They are enabled again in the bottom half. */
+ bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ /* save the reason code and call our bottom half. */
+ bcm->irq_reason = reason;
+ tasklet_schedule(&bcm->isr_tasklet);
out:
mmiowb();
@@ -1929,16 +1888,18 @@ out:
static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force)
{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
+
if (bcm->firmware_norelease && !force)
return; /* Suspending or controller reset. */
- release_firmware(bcm->ucode);
- bcm->ucode = NULL;
- release_firmware(bcm->pcm);
- bcm->pcm = NULL;
- release_firmware(bcm->initvals0);
- bcm->initvals0 = NULL;
- release_firmware(bcm->initvals1);
- bcm->initvals1 = NULL;
+ release_firmware(phy->ucode);
+ phy->ucode = NULL;
+ release_firmware(phy->pcm);
+ phy->pcm = NULL;
+ release_firmware(phy->initvals0);
+ phy->initvals0 = NULL;
+ release_firmware(phy->initvals1);
+ phy->initvals1 = NULL;
}
static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
@@ -1949,11 +1910,11 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
int nr;
char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };
- if (!bcm->ucode) {
+ if (!phy->ucode) {
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",
(rev >= 5 ? 5 : rev),
modparam_fwpostfix);
- err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: Microcode \"%s\" not available or load failed.\n",
@@ -1962,12 +1923,12 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
}
}
- if (!bcm->pcm) {
+ if (!phy->pcm) {
snprintf(buf, ARRAY_SIZE(buf),
"bcm43xx_pcm%d%s.fw",
(rev < 5 ? 4 : 5),
modparam_fwpostfix);
- err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: PCM \"%s\" not available or load failed.\n",
@@ -1976,7 +1937,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
}
}
- if (!bcm->initvals0) {
+ if (!phy->initvals0) {
if (rev == 2 || rev == 4) {
switch (phy->type) {
case BCM43xx_PHYTYPE_A:
@@ -2007,20 +1968,20 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
nr, modparam_fwpostfix);
- err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: InitVals \"%s\" not available or load failed.\n",
buf);
goto error;
}
- if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {
+ if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {
printk(KERN_ERR PFX "InitVals fileformat error.\n");
goto error;
}
}
- if (!bcm->initvals1) {
+ if (!phy->initvals1) {
if (rev >= 5) {
u32 sbtmstatehigh;
@@ -2042,14 +2003,14 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm)
snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",
nr, modparam_fwpostfix);
- err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev);
+ err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);
if (err) {
printk(KERN_ERR PFX
"Error: InitVals \"%s\" not available or load failed.\n",
buf);
goto error;
}
- if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) {
+ if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {
printk(KERN_ERR PFX "InitVals fileformat error.\n");
goto error;
}
@@ -2069,12 +2030,13 @@ err_noinitval:
static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
const u32 *data;
unsigned int i, len;
/* Upload Microcode. */
- data = (u32 *)(bcm->ucode->data);
- len = bcm->ucode->size / sizeof(u32);
+ data = (u32 *)(phy->ucode->data);
+ len = phy->ucode->size / sizeof(u32);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);
for (i = 0; i < len; i++) {
bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,
@@ -2083,8 +2045,8 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm)
}
/* Upload PCM data. */
- data = (u32 *)(bcm->pcm->data);
- len = bcm->pcm->size / sizeof(u32);
+ data = (u32 *)(phy->pcm->data);
+ len = phy->pcm->size / sizeof(u32);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);
bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);
bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);
@@ -2130,15 +2092,16 @@ err_format:
static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm)
{
+ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err;
- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,
- bcm->initvals0->size / sizeof(struct bcm43xx_initval));
+ err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,
+ phy->initvals0->size / sizeof(struct bcm43xx_initval));
if (err)
goto out;
- if (bcm->initvals1) {
- err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,
- bcm->initvals1->size / sizeof(struct bcm43xx_initval));
+ if (phy->initvals1) {
+ err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,
+ phy->initvals1->size / sizeof(struct bcm43xx_initval));
if (err)
goto out;
}
@@ -2155,9 +2118,7 @@ static struct pci_device_id bcm43xx_47xx_ids[] = {
static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
{
- int res;
- unsigned int i;
- u32 data;
+ int err;
bcm->irq = bcm->pci_dev->irq;
#ifdef CONFIG_BCM947XX
@@ -2174,32 +2135,12 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm)
}
}
#endif
- res = request_irq(bcm->irq, bcm43xx_interrupt_handler,
- SA_SHIRQ, KBUILD_MODNAME, bcm);
- if (res) {
+ err = request_irq(bcm->irq, bcm43xx_interrupt_handler,
+ IRQF_SHARED, KBUILD_MODNAME, bcm);
+ if (err)
printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);
- return -ENODEV;
- }
- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
- i = 0;
- while (1) {
- data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (data == BCM43xx_IRQ_READY)
- break;
- i++;
- if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
- printk(KERN_ERR PFX "Card IRQ register not responding. "
- "Giving up.\n");
- free_irq(bcm->irq, bcm);
- return -ENODEV;
- }
- udelay(10);
- }
- // dummy read
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- return 0;
+ return err;
}
/* Switch to the core used to write the GPIO register.
@@ -2297,13 +2238,17 @@ static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm)
/* http://bcm-specs.sipsolutions.net/EnableMac */
void bcm43xx_mac_enable(struct bcm43xx_private *bcm)
{
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
- | BCM43xx_SBF_MAC_ENABLED);
- bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
- bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+ bcm->mac_suspended--;
+ assert(bcm->mac_suspended >= 0);
+ if (bcm->mac_suspended == 0) {
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+ | BCM43xx_SBF_MAC_ENABLED);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+ bcm43xx_power_saving_ctl_bits(bcm, -1, -1);
+ }
}
/* http://bcm-specs.sipsolutions.net/SuspendMAC */
@@ -2312,18 +2257,23 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm)
int i;
u32 tmp;
- bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
- bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
- & ~BCM43xx_SBF_MAC_ENABLED);
- bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
- for (i = 100000; i; i--) {
- tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
- if (tmp & BCM43xx_IRQ_READY)
- return;
- udelay(10);
+ assert(bcm->mac_suspended >= 0);
+ if (bcm->mac_suspended == 0) {
+ bcm43xx_power_saving_ctl_bits(bcm, -1, 1);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+ bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+ & ~BCM43xx_SBF_MAC_ENABLED);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+ for (i = 10000; i; i--) {
+ tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+ if (tmp & BCM43xx_IRQ_READY)
+ goto out;
+ udelay(1);
+ }
+ printkl(KERN_ERR PFX "MAC suspend failed\n");
}
- printkl(KERN_ERR PFX "MAC suspend failed\n");
+out:
+ bcm->mac_suspended++;
}
void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
@@ -2393,7 +2343,6 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm)
if (!modparam_noleds)
bcm43xx_leds_exit(bcm);
bcm43xx_gpio_cleanup(bcm);
- free_irq(bcm->irq, bcm);
bcm43xx_release_firmware(bcm, 0);
}
@@ -2405,7 +2354,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err;
- int tmp;
+ int i, tmp;
u32 value32;
u16 value16;
@@ -2418,13 +2367,54 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
goto out;
bcm43xx_upload_microcode(bcm);
- err = bcm43xx_initialize_irq(bcm);
- if (err)
+ bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);
+ i = 0;
+ while (1) {
+ value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);
+ if (value32 == BCM43xx_IRQ_READY)
+ break;
+ i++;
+ if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {
+ printk(KERN_ERR PFX "IRQ_READY timeout\n");
+ err = -ENODEV;
+ goto err_release_fw;
+ }
+ udelay(10);
+ }
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+
+ value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_REVISION);
+
+ dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "
+ "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", value16,
+ bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_PATCHLEVEL),
+ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_DATE) >> 12) & 0xf,
+ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_DATE) >> 8) & 0xf,
+ bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_DATE) & 0xff,
+ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_TIME) >> 11) & 0x1f,
+ (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_TIME) >> 5) & 0x3f,
+ bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_TIME) & 0x1f);
+
+ if ( value16 > 0x128 ) {
+ printk(KERN_ERR PFX
+ "Firmware: no support for microcode extracted "
+ "from version 4.x binary drivers.\n");
+ err = -EOPNOTSUPP;
goto err_release_fw;
+ }
err = bcm43xx_gpio_init(bcm);
if (err)
- goto err_free_irq;
+ goto err_release_fw;
err = bcm43xx_upload_initvals(bcm);
if (err)
@@ -2488,10 +2478,12 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
bcm43xx_write32(bcm, 0x018C, 0x02000000);
}
bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_IRQ_MASK, 0x0001DC00);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0000DC00);
bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00);
- bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
+ bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
value32 |= 0x00100000;
@@ -2508,8 +2500,6 @@ err_radio_off:
bcm43xx_radio_turn_off(bcm);
err_gpio_cleanup:
bcm43xx_gpio_cleanup(bcm);
-err_free_irq:
- free_irq(bcm->irq, bcm);
err_release_fw:
bcm43xx_release_firmware(bcm, 1);
goto out;
@@ -2549,11 +2539,9 @@ static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
{
/* Initialize a "phyinfo" structure. The structure is already
* zeroed out.
+ * This is called on insmod time to initialize members.
*/
- phy->antenna_diversity = 0xFFFF;
phy->savedpctlreg = 0xFFFF;
- phy->minlowsig[0] = 0xFFFF;
- phy->minlowsig[1] = 0xFFFF;
spin_lock_init(&phy->lock);
}
@@ -2561,14 +2549,11 @@ static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
{
/* Initialize a "radioinfo" structure. The structure is already
* zeroed out.
+ * This is called on insmod time to initialize members.
*/
radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE;
radio->channel = 0xFF;
radio->initial_channel = 0xFF;
- radio->lofcal = 0xFFFF;
- radio->initval = 0xFFFF;
- radio->nrssi[0] = -1000;
- radio->nrssi[1] = -1000;
}
static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
@@ -2586,7 +2571,6 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
* BCM43xx_MAX_80211_CORES);
memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211)
* BCM43xx_MAX_80211_CORES);
- bcm->current_80211_core_idx = -1;
bcm->nr_80211_available = 0;
bcm->current_core = NULL;
bcm->active_80211_core = NULL;
@@ -2756,6 +2740,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
goto out;
}
bcm->nr_80211_available++;
+ core->priv = ext_80211;
bcm43xx_init_struct_phyinfo(&ext_80211->phy);
bcm43xx_init_struct_radioinfo(&ext_80211->radio);
break;
@@ -2856,7 +2841,8 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm)
}
/* http://bcm-specs.sipsolutions.net/80211Init */
-static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
+static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm,
+ int active_wlcore)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
@@ -2938,19 +2924,26 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm)
if (bcm->current_core->rev >= 5)
bcm43xx_write16(bcm, 0x043C, 0x000C);
- if (bcm43xx_using_pio(bcm))
- err = bcm43xx_pio_init(bcm);
- else
- err = bcm43xx_dma_init(bcm);
- if (err)
- goto err_chip_cleanup;
+ if (active_wlcore) {
+ if (bcm43xx_using_pio(bcm))
+ err = bcm43xx_pio_init(bcm);
+ else
+ err = bcm43xx_dma_init(bcm);
+ if (err)
+ goto err_chip_cleanup;
+ }
bcm43xx_write16(bcm, 0x0612, 0x0050);
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050);
bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4);
- bcm43xx_mac_enable(bcm);
- bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
+ if (active_wlcore) {
+ if (radio->initial_channel != 0xFF)
+ bcm43xx_radio_selectchannel(bcm, radio->initial_channel, 0);
+ }
+ /* Don't enable MAC/IRQ here, as it will race with the IRQ handler.
+ * We enable it later.
+ */
bcm->current_core->initialized = 1;
out:
return err;
@@ -3065,11 +3058,6 @@ out:
return err;
}
-static void bcm43xx_softmac_init(struct bcm43xx_private *bcm)
-{
- ieee80211softmac_start(bcm->net_dev);
-}
-
static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -3181,47 +3169,45 @@ static void bcm43xx_periodic_work_handler(void *d)
/* Periodic work will take a long time, so we want it to
* be preemtible.
*/
- bcm43xx_lock_irqonly(bcm, flags);
- netif_stop_queue(bcm->net_dev);
+ mutex_lock(&bcm->mutex);
+ netif_tx_disable(bcm->net_dev);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ bcm43xx_mac_suspend(bcm);
if (bcm43xx_using_pio(bcm))
bcm43xx_pio_freeze_txqueues(bcm);
savedirqs = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_unlock_irqonly(bcm, flags);
- bcm43xx_lock_noirq(bcm);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
bcm43xx_synchronize_irq(bcm);
} else {
/* Periodic work should take short time, so we want low
* locking overhead.
*/
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
}
do_periodic_work(bcm);
if (badness > BADNESS_LIMIT) {
- bcm43xx_lock_irqonly(bcm, flags);
- if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)) {
- tasklet_enable(&bcm->isr_tasklet);
- bcm43xx_interrupt_enable(bcm, savedirqs);
- if (bcm43xx_using_pio(bcm))
- bcm43xx_pio_thaw_txqueues(bcm);
- }
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ tasklet_enable(&bcm->isr_tasklet);
+ bcm43xx_interrupt_enable(bcm, savedirqs);
+ if (bcm43xx_using_pio(bcm))
+ bcm43xx_pio_thaw_txqueues(bcm);
+ bcm43xx_mac_enable(bcm);
netif_wake_queue(bcm->net_dev);
- mmiowb();
- bcm43xx_unlock_irqonly(bcm, flags);
- bcm43xx_unlock_noirq(bcm);
- } else {
- mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
}
+ mmiowb();
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
}
-static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
+void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm)
{
cancel_rearming_delayed_work(&bcm->periodic_work);
}
-static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
+void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm)
{
struct work_struct *work = &(bcm->periodic_work);
@@ -3237,135 +3223,362 @@ static void bcm43xx_security_init(struct bcm43xx_private *bcm)
bcm43xx_clear_keys(bcm);
}
-/* This is the opposite of bcm43xx_init_board() */
-static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+static int bcm43xx_rng_read(struct hwrng *rng, u32 *data)
{
+ struct bcm43xx_private *bcm = (struct bcm43xx_private *)rng->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&(bcm)->irq_lock, flags);
+ *data = bcm43xx_read16(bcm, BCM43xx_MMIO_RNG);
+ spin_unlock_irqrestore(&(bcm)->irq_lock, flags);
+
+ return (sizeof(u16));
+}
+
+static void bcm43xx_rng_exit(struct bcm43xx_private *bcm)
+{
+ hwrng_unregister(&bcm->rng);
+}
+
+static int bcm43xx_rng_init(struct bcm43xx_private *bcm)
+{
+ int err;
+
+ snprintf(bcm->rng_name, ARRAY_SIZE(bcm->rng_name),
+ "%s_%s", KBUILD_MODNAME, bcm->net_dev->name);
+ bcm->rng.name = bcm->rng_name;
+ bcm->rng.data_read = bcm43xx_rng_read;
+ bcm->rng.priv = (unsigned long)bcm;
+ err = hwrng_register(&bcm->rng);
+ if (err)
+ printk(KERN_ERR PFX "RNG init failed (%d)\n", err);
+
+ return err;
+}
+
+static int bcm43xx_shutdown_all_wireless_cores(struct bcm43xx_private *bcm)
+{
+ int ret = 0;
int i, err;
+ struct bcm43xx_coreinfo *core;
- bcm43xx_lock_noirq(bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+ for (i = 0; i < bcm->nr_80211_available; i++) {
+ core = &(bcm->core_80211[i]);
+ assert(core->available);
+ if (!core->initialized)
+ continue;
+ err = bcm43xx_switch_core(bcm, core);
+ if (err) {
+ dprintk(KERN_ERR PFX "shutdown_all_wireless_cores "
+ "switch_core failed (%d)\n", err);
+ ret = err;
+ continue;
+ }
+ bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
+ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */
+ bcm43xx_wireless_core_cleanup(bcm);
+ if (core == bcm->active_80211_core)
+ bcm->active_80211_core = NULL;
+ }
+ free_irq(bcm->irq, bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+
+ return ret;
+}
+
+/* This is the opposite of bcm43xx_init_board() */
+static void bcm43xx_free_board(struct bcm43xx_private *bcm)
+{
+ bcm43xx_rng_exit(bcm);
bcm43xx_sysfs_unregister(bcm);
bcm43xx_periodic_tasks_delete(bcm);
- bcm43xx_set_status(bcm, BCM43xx_STAT_SHUTTINGDOWN);
+ mutex_lock(&(bcm)->mutex);
+ bcm43xx_shutdown_all_wireless_cores(bcm);
+ bcm43xx_pctl_set_crystal(bcm, 0);
+ mutex_unlock(&(bcm)->mutex);
+}
+
+static void prepare_phydata_for_init(struct bcm43xx_phyinfo *phy)
+{
+ phy->antenna_diversity = 0xFFFF;
+ memset(phy->minlowsig, 0xFF, sizeof(phy->minlowsig));
+ memset(phy->minlowsigpos, 0, sizeof(phy->minlowsigpos));
+
+ /* Flags */
+ phy->calibrated = 0;
+ phy->is_locked = 0;
+
+ if (phy->_lo_pairs) {
+ memset(phy->_lo_pairs, 0,
+ sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT);
+ }
+ memset(phy->loopback_gain, 0, sizeof(phy->loopback_gain));
+}
+
+static void prepare_radiodata_for_init(struct bcm43xx_private *bcm,
+ struct bcm43xx_radioinfo *radio)
+{
+ int i;
+ /* Set default attenuation values. */
+ radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+ radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+ radio->txctl1 = bcm43xx_default_txctl1(bcm);
+ radio->txctl2 = 0xFFFF;
+ radio->txpwr_offset = 0;
+
+ /* NRSSI */
+ radio->nrssislope = 0;
+ for (i = 0; i < ARRAY_SIZE(radio->nrssi); i++)
+ radio->nrssi[i] = -1000;
+ for (i = 0; i < ARRAY_SIZE(radio->nrssi_lt); i++)
+ radio->nrssi_lt[i] = i;
+
+ radio->lofcal = 0xFFFF;
+ radio->initval = 0xFFFF;
+
+ radio->aci_enable = 0;
+ radio->aci_wlan_automatic = 0;
+ radio->aci_hw_rssi = 0;
+}
+
+static void prepare_priv_for_init(struct bcm43xx_private *bcm)
+{
+ int i;
+ struct bcm43xx_coreinfo *core;
+ struct bcm43xx_coreinfo_80211 *wlext;
+
+ assert(!bcm->active_80211_core);
+
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+
+ /* Flags */
+ bcm->was_initialized = 0;
+ bcm->reg124_set_0x4 = 0;
+
+ /* Stats */
+ memset(&bcm->stats, 0, sizeof(bcm->stats));
+
+ /* Wireless core data */
for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) {
- if (!bcm->core_80211[i].available)
- continue;
- if (!bcm->core_80211[i].initialized)
+ core = &(bcm->core_80211[i]);
+ wlext = core->priv;
+
+ if (!core->available)
continue;
+ assert(wlext == &(bcm->core_80211_ext[i]));
- err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
- assert(err == 0);
- bcm43xx_wireless_core_cleanup(bcm);
+ prepare_phydata_for_init(&wlext->phy);
+ prepare_radiodata_for_init(bcm, &wlext->radio);
}
- bcm43xx_pctl_set_crystal(bcm, 0);
+ /* IRQ related flags */
+ bcm->irq_reason = 0;
+ memset(bcm->dma_reason, 0, sizeof(bcm->dma_reason));
+ bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
- bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
- bcm43xx_unlock_noirq(bcm);
+ bcm->mac_suspended = 1;
+
+ /* Noise calculation context */
+ memset(&bcm->noisecalc, 0, sizeof(bcm->noisecalc));
+
+ /* Periodic work context */
+ bcm->periodic_state = 0;
}
-static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+static int wireless_core_up(struct bcm43xx_private *bcm,
+ int active_wlcore)
+{
+ int err;
+
+ if (!bcm43xx_core_enabled(bcm))
+ bcm43xx_wireless_core_reset(bcm, 1);
+ if (!active_wlcore)
+ bcm43xx_wireless_core_mark_inactive(bcm);
+ err = bcm43xx_wireless_core_init(bcm, active_wlcore);
+ if (err)
+ goto out;
+ if (!active_wlcore)
+ bcm43xx_radio_turn_off(bcm);
+out:
+ return err;
+}
+
+/* Select and enable the "to be used" wireless core.
+ * Locking: bcm->mutex must be aquired before calling this.
+ * bcm->irq_lock must not be aquired.
+ */
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+ int phytype)
{
int i, err;
- int connect_phy;
+ struct bcm43xx_coreinfo *active_core = NULL;
+ struct bcm43xx_coreinfo_80211 *active_wlext = NULL;
+ struct bcm43xx_coreinfo *core;
+ struct bcm43xx_coreinfo_80211 *wlext;
+ int adjust_active_sbtmstatelow = 0;
might_sleep();
- bcm43xx_lock_noirq(bcm);
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+ if (phytype < 0) {
+ /* If no phytype is requested, select the first core. */
+ assert(bcm->core_80211[0].available);
+ wlext = bcm->core_80211[0].priv;
+ phytype = wlext->phy.type;
+ }
+ /* Find the requested core. */
+ for (i = 0; i < bcm->nr_80211_available; i++) {
+ core = &(bcm->core_80211[i]);
+ wlext = core->priv;
+ if (wlext->phy.type == phytype) {
+ active_core = core;
+ active_wlext = wlext;
+ break;
+ }
+ }
+ if (!active_core)
+ return -ESRCH; /* No such PHYTYPE on this board. */
+
+ if (bcm->active_80211_core) {
+ /* We already selected a wl core in the past.
+ * So first clean up everything.
+ */
+ dprintk(KERN_INFO PFX "select_wireless_core: cleanup\n");
+ ieee80211softmac_stop(bcm->net_dev);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+ err = bcm43xx_disable_interrupts_sync(bcm);
+ assert(!err);
+ tasklet_enable(&bcm->isr_tasklet);
+ err = bcm43xx_shutdown_all_wireless_cores(bcm);
+ if (err)
+ goto error;
+ /* Ok, everything down, continue to re-initialize. */
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZING);
+ }
+
+ /* Reset all data structures. */
+ prepare_priv_for_init(bcm);
- err = bcm43xx_pctl_set_crystal(bcm, 1);
- if (err)
- goto out;
- err = bcm43xx_pctl_init(bcm);
- if (err)
- goto err_crystal_off;
err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST);
if (err)
- goto err_crystal_off;
+ goto error;
- tasklet_enable(&bcm->isr_tasklet);
+ /* Mark all unused cores "inactive". */
for (i = 0; i < bcm->nr_80211_available; i++) {
- err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]);
- assert(err != -ENODEV);
- if (err)
- goto err_80211_unwind;
+ core = &(bcm->core_80211[i]);
+ wlext = core->priv;
- /* Enable the selected wireless core.
- * Connect PHY only on the first core.
- */
- if (!bcm43xx_core_enabled(bcm)) {
- if (bcm->nr_80211_available == 1) {
- connect_phy = bcm43xx_current_phy(bcm)->connected;
- } else {
- if (i == 0)
- connect_phy = 1;
- else
- connect_phy = 0;
- }
- bcm43xx_wireless_core_reset(bcm, connect_phy);
+ if (core == active_core)
+ continue;
+ err = bcm43xx_switch_core(bcm, core);
+ if (err) {
+ dprintk(KERN_ERR PFX "Could not switch to inactive "
+ "802.11 core (%d)\n", err);
+ goto error;
}
+ err = wireless_core_up(bcm, 0);
+ if (err) {
+ dprintk(KERN_ERR PFX "core_up for inactive 802.11 core "
+ "failed (%d)\n", err);
+ goto error;
+ }
+ adjust_active_sbtmstatelow = 1;
+ }
- if (i != 0)
- bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]);
-
- err = bcm43xx_wireless_core_init(bcm);
- if (err)
- goto err_80211_unwind;
+ /* Now initialize the active 802.11 core. */
+ err = bcm43xx_switch_core(bcm, active_core);
+ if (err) {
+ dprintk(KERN_ERR PFX "Could not switch to active "
+ "802.11 core (%d)\n", err);
+ goto error;
+ }
+ if (adjust_active_sbtmstatelow &&
+ active_wlext->phy.type == BCM43xx_PHYTYPE_G) {
+ u32 sbtmstatelow;
- if (i != 0) {
- bcm43xx_mac_suspend(bcm);
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_radio_turn_off(bcm);
- }
+ sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);
+ sbtmstatelow |= 0x20000000;
+ bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);
}
- bcm->active_80211_core = &bcm->core_80211[0];
- if (bcm->nr_80211_available >= 2) {
- bcm43xx_switch_core(bcm, &bcm->core_80211[0]);
- bcm43xx_mac_enable(bcm);
+ err = wireless_core_up(bcm, 1);
+ if (err) {
+ dprintk(KERN_ERR PFX "core_up for active 802.11 core "
+ "failed (%d)\n", err);
+ goto error;
}
+ err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+ if (err)
+ goto error;
+ bcm->active_80211_core = active_core;
+
bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC);
bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr));
- dprintk(KERN_INFO PFX "80211 cores initialized\n");
bcm43xx_security_init(bcm);
- bcm43xx_softmac_init(bcm);
+ ieee80211softmac_start(bcm->net_dev);
- bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC);
+ /* Let's go! Be careful after enabling the IRQs.
+ * Don't switch cores, for example.
+ */
+ bcm43xx_mac_enable(bcm);
+ bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+ err = bcm43xx_initialize_irq(bcm);
+ if (err)
+ goto error;
+ bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);
- if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) {
- bcm43xx_mac_suspend(bcm);
- bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0);
- bcm43xx_mac_enable(bcm);
- }
+ dprintk(KERN_INFO PFX "Selected 802.11 core (phytype %d)\n",
+ active_wlext->phy.type);
- /* Initialization of the board is done. Flag it as such. */
- bcm43xx_set_status(bcm, BCM43xx_STAT_INITIALIZED);
+ return 0;
+
+error:
+ bcm43xx_set_status(bcm, BCM43xx_STAT_UNINIT);
+ bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW);
+ return err;
+}
+
+static int bcm43xx_init_board(struct bcm43xx_private *bcm)
+{
+ int err;
+ mutex_lock(&(bcm)->mutex);
+
+ tasklet_enable(&bcm->isr_tasklet);
+ err = bcm43xx_pctl_set_crystal(bcm, 1);
+ if (err)
+ goto err_tasklet;
+ err = bcm43xx_pctl_init(bcm);
+ if (err)
+ goto err_crystal_off;
+ err = bcm43xx_select_wireless_core(bcm, -1);
+ if (err)
+ goto err_crystal_off;
+ err = bcm43xx_sysfs_register(bcm);
+ if (err)
+ goto err_wlshutdown;
+ err = bcm43xx_rng_init(bcm);
+ if (err)
+ goto err_sysfs_unreg;
bcm43xx_periodic_tasks_setup(bcm);
- bcm43xx_sysfs_register(bcm);
- //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
/*FIXME: This should be handled by softmac instead. */
schedule_work(&bcm->softmac->associnfo.work);
- assert(err == 0);
out:
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&(bcm)->mutex);
return err;
-err_80211_unwind:
- tasklet_disable(&bcm->isr_tasklet);
- /* unwind all 80211 initialization */
- for (i = 0; i < bcm->nr_80211_available; i++) {
- if (!bcm->core_80211[i].initialized)
- continue;
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_wireless_core_cleanup(bcm);
- }
+err_sysfs_unreg:
+ bcm43xx_sysfs_unregister(bcm);
+err_wlshutdown:
+ bcm43xx_shutdown_all_wireless_cores(bcm);
err_crystal_off:
bcm43xx_pctl_set_crystal(bcm, 0);
+err_tasklet:
+ tasklet_disable(&bcm->isr_tasklet);
goto out;
}
@@ -3609,7 +3822,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
struct bcm43xx_radioinfo *radio;
unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
bcm43xx_mac_suspend(bcm);
bcm43xx_radio_selectchannel(bcm, channel, 0);
@@ -3618,7 +3832,8 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
radio = bcm43xx_current_radio(bcm);
radio->initial_channel = channel;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
}
/* set_security() callback in struct ieee80211_device */
@@ -3632,7 +3847,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
dprintk(KERN_INFO PFX "set security called");
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
if (sec->flags & (1<<keyidx)) {
@@ -3661,6 +3877,10 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
secinfo->encrypt = sec->encrypt;
dprintk(", .encrypt = %d", sec->encrypt);
}
+ if (sec->flags & SEC_AUTH_MODE) {
+ secinfo->auth_mode = sec->auth_mode;
+ dprintk(", .auth_mode = %d", sec->auth_mode);
+ }
dprintk("\n");
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED &&
!bcm->ieee->host_encrypt) {
@@ -3697,7 +3917,8 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
} else
bcm43xx_clear_keys(bcm);
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
}
/* hard_start_xmit() callback in struct ieee80211_device */
@@ -3709,12 +3930,14 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb,
int err = -ENODEV;
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (likely(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED))
err = bcm43xx_tx(bcm, txb);
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
- return err;
+ if (unlikely(err))
+ return NETDEV_TX_BUSY;
+ return NETDEV_TX_OK;
}
static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev)
@@ -3727,9 +3950,9 @@ static void bcm43xx_net_tx_timeout(struct net_device *net_dev)
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
unsigned long flags;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm43xx_controller_restart(bcm, "TX timeout");
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -3739,7 +3962,8 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
unsigned long flags;
local_irq_save(flags);
- bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
+ bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
local_irq_restore(flags);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -3757,9 +3981,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev)
int err;
ieee80211softmac_stop(net_dev);
- err = bcm43xx_disable_interrupts_sync(bcm, NULL);
+ err = bcm43xx_disable_interrupts_sync(bcm);
assert(!err);
bcm43xx_free_board(bcm);
+ flush_scheduled_work();
return 0;
}
@@ -3776,10 +4001,12 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm,
bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan;
bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+ bcm->mac_suspended = 1;
bcm->pci_dev = pci_dev;
bcm->net_dev = net_dev;
bcm->bad_frames_preempt = modparam_bad_frames_preempt;
spin_lock_init(&bcm->irq_lock);
+ spin_lock_init(&bcm->leds_lock);
mutex_init(&bcm->mutex);
tasklet_init(&bcm->isr_tasklet,
(void (*)(unsigned long))bcm43xx_interrupt_tasklet,
@@ -3898,7 +4125,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
bcm43xx_debugfs_remove_device(bcm);
unregister_netdev(net_dev);
bcm43xx_detach_board(bcm);
- assert(bcm->ucode == NULL);
free_ieee80211softmac(net_dev);
}
@@ -3908,47 +4134,31 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev)
static void bcm43xx_chip_reset(void *_bcm)
{
struct bcm43xx_private *bcm = _bcm;
- struct net_device *net_dev = bcm->net_dev;
- struct pci_dev *pci_dev = bcm->pci_dev;
- int err;
- int was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
-
- netif_stop_queue(bcm->net_dev);
- tasklet_disable(&bcm->isr_tasklet);
+ struct bcm43xx_phyinfo *phy;
+ int err = -ENODEV;
- bcm->firmware_norelease = 1;
- if (was_initialized)
- bcm43xx_free_board(bcm);
- bcm->firmware_norelease = 0;
- bcm43xx_detach_board(bcm);
- err = bcm43xx_init_private(bcm, net_dev, pci_dev);
- if (err)
- goto failure;
- err = bcm43xx_attach_board(bcm);
- if (err)
- goto failure;
- if (was_initialized) {
- err = bcm43xx_init_board(bcm);
- if (err)
- goto failure;
+ mutex_lock(&(bcm)->mutex);
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ bcm43xx_periodic_tasks_delete(bcm);
+ phy = bcm43xx_current_phy(bcm);
+ err = bcm43xx_select_wireless_core(bcm, phy->type);
+ if (!err)
+ bcm43xx_periodic_tasks_setup(bcm);
}
- netif_wake_queue(bcm->net_dev);
- printk(KERN_INFO PFX "Controller restarted\n");
+ mutex_unlock(&(bcm)->mutex);
- return;
-failure:
- printk(KERN_ERR PFX "Controller restart failed\n");
+ printk(KERN_ERR PFX "Controller restart%s\n",
+ (err == 0) ? "ed" : " failed");
}
/* Hard-reset the chip.
* This can be called from interrupt or process context.
- * Make sure to _not_ re-enable device interrupts after this has been called.
-*/
+ * bcm->irq_lock must be locked.
+ */
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason)
{
- bcm43xx_set_status(bcm, BCM43xx_STAT_RESTARTING);
- bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);
- bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */
+ if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
+ return;
printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason);
INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm);
schedule_work(&bcm->restart_work);
@@ -3960,21 +4170,16 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *net_dev = pci_get_drvdata(pdev);
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- int try_to_shutdown = 0, err;
+ int err;
dprintk(KERN_INFO PFX "Suspending...\n");
- bcm43xx_lock_irqsafe(bcm, flags);
- bcm->was_initialized = (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);
- if (bcm->was_initialized)
- try_to_shutdown = 1;
- bcm43xx_unlock_irqsafe(bcm, flags);
-
netif_device_detach(net_dev);
- if (try_to_shutdown) {
+ bcm->was_initialized = 0;
+ if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
+ bcm->was_initialized = 1;
ieee80211softmac_stop(net_dev);
- err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate);
+ err = bcm43xx_disable_interrupts_sync(bcm);
if (unlikely(err)) {
dprintk(KERN_ERR PFX "Suspend failed.\n");
return -EAGAIN;
@@ -4007,17 +4212,14 @@ static int bcm43xx_resume(struct pci_dev *pdev)
pci_restore_state(pdev);
bcm43xx_chipset_attach(bcm);
- if (bcm->was_initialized) {
- bcm->irq_savedstate = BCM43xx_IRQ_INITIAL;
+ if (bcm->was_initialized)
err = bcm43xx_init_board(bcm);
- }
if (err) {
printk(KERN_ERR PFX "Resume failed!\n");
return err;
}
-
netif_device_attach(net_dev);
-
+
dprintk(KERN_INFO PFX "Device resumed.\n");
return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
index 30a202b258b..f76357178e4 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h
@@ -112,30 +112,6 @@ int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm,
return bcm43xx_channel_to_freq_bg(channel);
}
-/* Lightweight function to check if a channel number is valid.
- * Note that this does _NOT_ check for geographical restrictions!
- */
-static inline
-int bcm43xx_is_valid_channel_a(u8 channel)
-{
- return (channel >= IEEE80211_52GHZ_MIN_CHANNEL
- && channel <= IEEE80211_52GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel_bg(u8 channel)
-{
- return (channel >= IEEE80211_24GHZ_MIN_CHANNEL
- && channel <= IEEE80211_24GHZ_MAX_CHANNEL);
-}
-static inline
-int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm,
- u8 channel)
-{
- if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
- return bcm43xx_is_valid_channel_a(channel);
- return bcm43xx_is_valid_channel_bg(channel);
-}
-
void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf);
void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf);
@@ -157,11 +133,17 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm);
int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core);
+int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm,
+ int phytype);
+
void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy);
void bcm43xx_mac_suspend(struct bcm43xx_private *bcm);
void bcm43xx_mac_enable(struct bcm43xx_private *bcm);
+void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm);
+void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm);
+
void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason);
int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index f8200deecc8..52ce2a9334f 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -81,6 +81,16 @@ static const s8 bcm43xx_tssi2dbm_g_table[] = {
static void bcm43xx_phy_initg(struct bcm43xx_private *bcm);
+static inline
+void bcm43xx_voluntary_preempt(void)
+{
+ assert(!in_atomic() && !in_irq() &&
+ !in_interrupt() && !irqs_disabled());
+#ifndef CONFIG_PREEMPT
+ cond_resched();
+#endif /* CONFIG_PREEMPT */
+}
+
void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
@@ -133,22 +143,14 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val)
void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
- unsigned long flags;
bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */
if (phy->calibrated)
return;
if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) {
- /* We do not want to be preempted while calibrating
- * the hardware.
- */
- local_irq_save(flags);
-
bcm43xx_wireless_core_reset(bcm, 0);
bcm43xx_phy_initg(bcm);
bcm43xx_wireless_core_reset(bcm, 1);
-
- local_irq_restore(flags);
}
phy->calibrated = 1;
}
@@ -359,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev <= 2)
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
- else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
+ else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
else
@@ -369,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev == 2)
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
- else if ((phy->rev > 2) && (phy->rev <= 7))
+ else if ((phy->rev > 2) && (phy->rev <= 8))
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
@@ -1195,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
if (phy->rev == 1)
bcm43xx_phy_initb5(bcm);
- else if (phy->rev >= 2 && phy->rev <= 7)
+ else
bcm43xx_phy_initb6(bcm);
if (phy->rev >= 2 || phy->connected)
bcm43xx_phy_inita(bcm);
@@ -1239,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
bcm43xx_phy_lo_g_measure(bcm);
} else {
if (radio->version == 0x2050 && radio->revision == 8) {
- //FIXME
+ bcm43xx_radio_write16(bcm, 0x0052,
+ (radio->txctl1 << 4) | radio->txctl2);
} else {
bcm43xx_radio_write16(bcm, 0x0052,
(bcm43xx_radio_read16(bcm, 0x0052)
& 0xFFF0) | radio->txctl1);
}
if (phy->rev >= 6) {
- /*
bcm43xx_phy_write(bcm, 0x0036,
(bcm43xx_phy_read(bcm, 0x0036)
- & 0xF000) | (FIXME << 12));
- */
+ & 0xF000) | (radio->txctl2 << 12));
}
if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
bcm43xx_phy_write(bcm, 0x002E, 0x8075);
else
- bcm43xx_phy_write(bcm, 0x003E, 0x807F);
+ bcm43xx_phy_write(bcm, 0x002E, 0x807F);
if (phy->rev < 2)
bcm43xx_phy_write(bcm, 0x002F, 0x0101);
else
@@ -1299,7 +1300,9 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
{
int i;
u16 ret = 0;
+ unsigned long flags;
+ local_irq_save(flags);
for (i = 0; i < 10; i++){
bcm43xx_phy_write(bcm, 0x0015, 0xAFA0);
udelay(1);
@@ -1309,6 +1312,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm)
udelay(40);
ret += bcm43xx_phy_read(bcm, 0x002C);
}
+ local_irq_restore(flags);
+ bcm43xx_voluntary_preempt();
return ret;
}
@@ -1435,6 +1440,7 @@ u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control)
}
ret = bcm43xx_phy_read(bcm, 0x002D);
local_irq_restore(flags);
+ bcm43xx_voluntary_preempt();
return ret;
}
@@ -1760,6 +1766,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
bcm43xx_radio_write16(bcm, 0x43, i);
bcm43xx_radio_write16(bcm, 0x52, radio->txctl2);
udelay(10);
+ bcm43xx_voluntary_preempt();
bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
@@ -1803,6 +1810,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
radio->txctl2
| (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above?
udelay(10);
+ bcm43xx_voluntary_preempt();
bcm43xx_phy_set_baseband_attenuation(bcm, j * 2);
@@ -1824,6 +1832,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm)
bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2);
udelay(2);
bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3);
+ bcm43xx_voluntary_preempt();
} else
bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0);
bcm43xx_phy_lo_adjust(bcm, is_initializing);
@@ -2188,12 +2197,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
{
struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
int err = -ENODEV;
- unsigned long flags;
-
- /* We do not want to be preempted while calibrating
- * the hardware.
- */
- local_irq_save(flags);
switch (phy->type) {
case BCM43xx_PHYTYPE_A:
@@ -2227,7 +2230,6 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm)
err = 0;
break;
}
- local_irq_restore(flags);
if (err)
printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n");
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
index 574085c4615..c60c1743ea0 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c
@@ -262,7 +262,7 @@ static void tx_tasklet(unsigned long d)
int err;
u16 txctl;
- bcm43xx_lock_irqonly(bcm, flags);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (queue->tx_frozen)
goto out_unlock;
@@ -300,7 +300,7 @@ static void tx_tasklet(unsigned long d)
continue;
}
out_unlock:
- bcm43xx_unlock_irqonly(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
}
static void setup_txqueues(struct bcm43xx_pioqueue *queue)
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
index af5c0bff169..bb9c484d7e1 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c
@@ -1594,11 +1594,11 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
u16 r8, tmp;
u16 freq;
+ if (!ieee80211_is_valid_channel(bcm->ieee, channel))
+ return -EINVAL;
if ((radio->manufact == 0x17F) &&
(radio->version == 0x2060) &&
(radio->revision == 1)) {
- if (channel > 200)
- return -EINVAL;
freq = channel2freq_a(channel);
r8 = bcm43xx_radio_read16(bcm, 0x0008);
@@ -1651,9 +1651,6 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm,
TODO(); //TODO: TSSI2dbm workaround
bcm43xx_phy_xmitpower(bcm);//FIXME correct?
} else {
- if ((channel < 1) || (channel > 14))
- return -EINVAL;
-
if (synthetic_pu_workaround)
bcm43xx_synth_pu_workaround(bcm, channel);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
index 6a23bdc7541..c71b998a369 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c
@@ -120,12 +120,14 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev,
GFP_KERNEL);
if (!sprom)
return -ENOMEM;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
err = bcm43xx_sprom_read(bcm, sprom);
if (!err)
err = sprom2hex(sprom, buf, PAGE_SIZE);
mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
kfree(sprom);
return err;
@@ -150,10 +152,14 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev,
err = hex2sprom(sprom, buf, count);
if (err)
goto out_kfree;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ spin_lock(&bcm->leds_lock);
err = bcm43xx_sprom_write(bcm, sprom);
mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock(&bcm->leds_lock);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
out_kfree:
kfree(sprom);
@@ -170,13 +176,12 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- int err;
ssize_t count = 0;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
switch (bcm43xx_current_radio(bcm)->interfmode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -191,11 +196,10 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev,
default:
assert(0);
}
- err = 0;
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
- return err ? err : count;
+ return count;
}
@@ -229,7 +233,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
return -EINVAL;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
@@ -237,7 +242,8 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev,
"supported by device\n");
}
mmiowb();
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err ? err : count;
}
@@ -251,23 +257,21 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev,
char *buf)
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
- int err;
ssize_t count;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
if (bcm->short_preamble)
count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
else
count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
- err = 0;
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
- return err ? err : count;
+ return count;
}
static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
@@ -276,7 +280,6 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
{
struct bcm43xx_private *bcm = dev_to_bcm(dev);
unsigned long flags;
- int err;
int value;
if (!capable(CAP_NET_ADMIN))
@@ -285,20 +288,141 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev,
value = get_boolean(buf, count);
if (value < 0)
return value;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->short_preamble = !!value;
- err = 0;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
- return err ? err : count;
+ return count;
}
static DEVICE_ATTR(shortpreamble, 0644,
bcm43xx_attr_preamble_show,
bcm43xx_attr_preamble_store);
+static ssize_t bcm43xx_attr_phymode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ int phytype;
+ int err = -EINVAL;
+
+ if (count < 1)
+ goto out;
+ switch (buf[0]) {
+ case 'a': case 'A':
+ phytype = BCM43xx_PHYTYPE_A;
+ break;
+ case 'b': case 'B':
+ phytype = BCM43xx_PHYTYPE_B;
+ break;
+ case 'g': case 'G':
+ phytype = BCM43xx_PHYTYPE_G;
+ break;
+ default:
+ goto out;
+ }
+
+ bcm43xx_periodic_tasks_delete(bcm);
+ mutex_lock(&(bcm)->mutex);
+ err = bcm43xx_select_wireless_core(bcm, phytype);
+ if (!err)
+ bcm43xx_periodic_tasks_setup(bcm);
+ mutex_unlock(&(bcm)->mutex);
+ if (err == -ESRCH)
+ err = -ENODEV;
+
+out:
+ return err ? err : count;
+}
+
+static ssize_t bcm43xx_attr_phymode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ ssize_t count = 0;
+
+ mutex_lock(&(bcm)->mutex);
+ switch (bcm43xx_current_phy(bcm)->type) {
+ case BCM43xx_PHYTYPE_A:
+ snprintf(buf, PAGE_SIZE, "A");
+ break;
+ case BCM43xx_PHYTYPE_B:
+ snprintf(buf, PAGE_SIZE, "B");
+ break;
+ case BCM43xx_PHYTYPE_G:
+ snprintf(buf, PAGE_SIZE, "G");
+ break;
+ default:
+ assert(0);
+ }
+ mutex_unlock(&(bcm)->mutex);
+
+ return count;
+}
+
+static DEVICE_ATTR(phymode, 0644,
+ bcm43xx_attr_phymode_show,
+ bcm43xx_attr_phymode_store);
+
+static ssize_t bcm43xx_attr_microcode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ unsigned long flags;
+ struct bcm43xx_private *bcm = dev_to_bcm(dev);
+ ssize_t count = 0;
+ u16 status;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&(bcm)->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ status = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,
+ BCM43xx_UCODE_STATUS);
+
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&(bcm)->mutex);
+ switch (status) {
+ case 0x0000:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (invalid)\n",
+ status);
+ break;
+ case 0x0001:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (init)\n",
+ status);
+ break;
+ case 0x0002:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (active)\n",
+ status);
+ break;
+ case 0x0003:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (suspended)\n",
+ status);
+ break;
+ case 0x0004:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (asleep)\n",
+ status);
+ break;
+ default:
+ count = snprintf(buf, PAGE_SIZE, "0x%.4x (unknown)\n",
+ status);
+ break;
+ }
+
+ return count;
+}
+
+static DEVICE_ATTR(microcodestatus, 0444,
+ bcm43xx_attr_microcode_show,
+ NULL);
+
int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
@@ -315,9 +439,19 @@ int bcm43xx_sysfs_register(struct bcm43xx_private *bcm)
err = device_create_file(dev, &dev_attr_shortpreamble);
if (err)
goto err_remove_interfmode;
+ err = device_create_file(dev, &dev_attr_phymode);
+ if (err)
+ goto err_remove_shortpreamble;
+ err = device_create_file(dev, &dev_attr_microcodestatus);
+ if (err)
+ goto err_remove_phymode;
out:
return err;
+err_remove_phymode:
+ device_remove_file(dev, &dev_attr_phymode);
+err_remove_shortpreamble:
+ device_remove_file(dev, &dev_attr_shortpreamble);
err_remove_interfmode:
device_remove_file(dev, &dev_attr_interference);
err_remove_sprom:
@@ -329,6 +463,8 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm)
{
struct device *dev = &bcm->pci_dev->dev;
+ device_remove_file(dev, &dev_attr_microcodestatus);
+ device_remove_file(dev, &dev_attr_phymode);
device_remove_file(dev, &dev_attr_shortpreamble);
device_remove_file(dev, &dev_attr_interference);
device_remove_file(dev, &dev_attr_sprom);
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index c35cb3a0777..9b7b15cf656 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -47,6 +47,8 @@
#define BCM43xx_WX_VERSION 18
#define MAX_WX_STRING 80
+/* FIXME: the next line is a guess as to what the maximum RSSI value might be */
+#define RX_RSSI_MAX 60
static int bcm43xx_wx_get_name(struct net_device *net_dev,
@@ -56,12 +58,11 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
int i;
- unsigned long flags;
struct bcm43xx_phyinfo *phy;
char suffix[7] = { 0 };
int have_a = 0, have_b = 0, have_g = 0;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
for (i = 0; i < bcm->nr_80211_available; i++) {
phy = &(bcm->core_80211_ext[i].phy);
switch (phy->type) {
@@ -77,7 +78,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev,
assert(0);
}
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
i = 0;
if (have_a) {
@@ -111,7 +112,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
int freq;
int err = -EINVAL;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+
if ((data->freq.m >= 0) && (data->freq.m <= 1000)) {
channel = data->freq.m;
freq = bcm43xx_channel_to_freq(bcm, channel);
@@ -119,7 +122,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
channel = bcm43xx_freq_to_channel(bcm, data->freq.m);
freq = data->freq.m;
}
- if (!bcm43xx_is_valid_channel(bcm, channel))
+ if (!ieee80211_is_valid_channel(bcm->ieee, channel))
goto out_unlock;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
//ieee80211softmac_disassoc(softmac, $REASON);
@@ -131,7 +134,8 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev,
err = 0;
}
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -143,11 +147,10 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct bcm43xx_radioinfo *radio;
- unsigned long flags;
int err = -ENODEV;
u16 channel;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
radio = bcm43xx_current_radio(bcm);
channel = radio->channel;
if (channel == 0xFF) {
@@ -162,7 +165,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -180,13 +183,15 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev,
if (mode == IW_MODE_AUTO)
mode = BCM43xx_INITIAL_IWMODE;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
if (bcm->ieee->iw_mode != mode)
bcm43xx_set_iwmode(bcm, mode);
} else
bcm->ieee->iw_mode = mode;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -197,11 +202,10 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
data->mode = bcm->ieee->iw_mode;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -214,7 +218,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct iw_range *range = (struct iw_range *)extra;
const struct ieee80211_geo *geo;
- unsigned long flags;
int i, j;
struct bcm43xx_phyinfo *phy;
@@ -226,15 +229,14 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
range->throughput = 27 * 1000 * 1000;
range->max_qual.qual = 100;
- /* TODO: Real max RSSI */
- range->max_qual.level = 3;
- range->max_qual.noise = 100;
- range->max_qual.updated = 7;
+ range->max_qual.level = 146; /* set floor at -110 dBm (146 - 256) */
+ range->max_qual.noise = 146;
+ range->max_qual.updated = IW_QUAL_ALL_UPDATED;
- range->avg_qual.qual = 70;
- range->avg_qual.level = 2;
- range->avg_qual.noise = 40;
- range->avg_qual.updated = 7;
+ range->avg_qual.qual = 50;
+ range->avg_qual.level = 0;
+ range->avg_qual.noise = 0;
+ range->avg_qual.updated = IW_QUAL_ALL_UPDATED;
range->min_rts = BCM43xx_MIN_RTS_THRESHOLD;
range->max_rts = BCM43xx_MAX_RTS_THRESHOLD;
@@ -254,7 +256,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
IW_ENC_CAPA_CIPHER_TKIP |
IW_ENC_CAPA_CIPHER_CCMP;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
phy = bcm43xx_current_phy(bcm);
range->num_bitrates = 0;
@@ -301,7 +303,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev,
}
range->num_frequency = j;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -314,11 +316,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
size_t len;
- bcm43xx_lock_noirq(bcm);
+ mutex_lock(&bcm->mutex);
len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE);
memcpy(bcm->nick, extra, len);
bcm->nick[len] = '\0';
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -331,12 +333,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
size_t len;
- bcm43xx_lock_noirq(bcm);
- len = strlen(bcm->nick) + 1;
+ mutex_lock(&bcm->mutex);
+ len = strlen(bcm->nick);
memcpy(extra, bcm->nick, len);
data->data.length = (__u16)len;
data->data.flags = 1;
- bcm43xx_unlock_noirq(bcm);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -350,7 +352,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (data->rts.disabled) {
bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD;
err = 0;
@@ -361,7 +364,8 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -372,13 +376,12 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
data->rts.value = bcm->rts_threshold;
data->rts.fixed = 0;
data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -392,7 +395,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
unsigned long flags;
int err = -EINVAL;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (data->frag.disabled) {
bcm->ieee->fts = MAX_FRAG_THRESHOLD;
err = 0;
@@ -403,7 +407,8 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev,
err = 0;
}
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -414,13 +419,12 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
data->frag.value = bcm->ieee->fts;
data->frag.fixed = 0;
data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -442,7 +446,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
return -EOPNOTSUPP;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
@@ -466,7 +471,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -478,10 +484,9 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct bcm43xx_radioinfo *radio;
- unsigned long flags;
int err = -ENODEV;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
if (bcm43xx_status(bcm) != BCM43xx_STAT_INITIALIZED)
goto out_unlock;
radio = bcm43xx_current_radio(bcm);
@@ -493,7 +498,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev,
err = 0;
out_unlock:
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -580,7 +585,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
return -EINVAL;
}
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED) {
err = bcm43xx_radio_set_interference_mitigation(bcm, mode);
if (err) {
@@ -595,7 +601,8 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev,
} else
bcm43xx_current_radio(bcm)->interfmode = mode;
}
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return err;
}
@@ -606,12 +613,11 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int mode;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
mode = bcm43xx_current_radio(bcm)->interfmode;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
switch (mode) {
case BCM43xx_RADIO_INTERFMODE_NONE:
@@ -641,9 +647,11 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev,
int on;
on = *((int *)extra);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->short_preamble = !!on;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -654,12 +662,11 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int on;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
on = bcm->short_preamble;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
if (on)
strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING);
@@ -681,11 +688,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev,
on = *((int *)extra);
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
bcm->ieee->host_encrypt = !!on;
bcm->ieee->host_decrypt = !!on;
bcm->ieee->host_build_iv = !on;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
return 0;
}
@@ -696,12 +705,11 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev,
char *extra)
{
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
- unsigned long flags;
int on;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
on = bcm->ieee->host_encrypt;
- bcm43xx_unlock_irqsafe(bcm, flags);
+ mutex_unlock(&bcm->mutex);
if (on)
strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING);
@@ -764,11 +772,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev,
if (!sprom)
goto out;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
err = -ENODEV;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_read(bcm, sprom);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
if (!err)
data->data.length = sprom2hex(sprom, extra);
kfree(sprom);
@@ -809,11 +819,15 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev,
if (err)
goto out_kfree;
- bcm43xx_lock_irqsafe(bcm, flags);
+ mutex_lock(&bcm->mutex);
+ spin_lock_irqsave(&bcm->irq_lock, flags);
+ spin_lock(&bcm->leds_lock);
err = -ENODEV;
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
err = bcm43xx_sprom_write(bcm, sprom);
- bcm43xx_unlock_irqsafe(bcm, flags);
+ spin_unlock(&bcm->leds_lock);
+ spin_unlock_irqrestore(&bcm->irq_lock, flags);
+ mutex_unlock(&bcm->mutex);
out_kfree:
kfree(sprom);
out:
@@ -827,6 +841,10 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
struct ieee80211softmac_device *mac = ieee80211_priv(net_dev);
struct iw_statistics *wstats;
+ struct ieee80211_network *network = NULL;
+ static int tmp_level = 0;
+ static int tmp_qual = 0;
+ unsigned long flags;
wstats = &bcm->stats.wstats;
if (!mac->associated) {
@@ -844,16 +862,28 @@ static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_d
wstats->qual.level = 0;
wstats->qual.noise = 0;
wstats->qual.updated = 7;
- wstats->qual.updated |= IW_QUAL_NOISE_INVALID |
- IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID;
+ wstats->qual.updated |= IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
return wstats;
}
/* fill in the real statistics when iface associated */
- wstats->qual.qual = 100; // TODO: get the real signal quality
- wstats->qual.level = 3 - bcm->stats.link_quality;
+ spin_lock_irqsave(&mac->ieee->lock, flags);
+ list_for_each_entry(network, &mac->ieee->network_list, list) {
+ if (!memcmp(mac->associnfo.bssid, network->bssid, ETH_ALEN)) {
+ if (!tmp_level) { /* get initial values */
+ tmp_level = network->stats.signal;
+ tmp_qual = network->stats.rssi;
+ } else { /* smooth results */
+ tmp_level = (15 * tmp_level + network->stats.signal)/16;
+ tmp_qual = (15 * tmp_qual + network->stats.rssi)/16;
+ }
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&mac->ieee->lock, flags);
+ wstats->qual.level = tmp_level;
+ wstats->qual.qual = 100 * tmp_qual / RX_RSSI_MAX;
wstats->qual.noise = bcm->stats.noise;
- wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
- IW_QUAL_NOISE_UPDATED;
+ wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM;
wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable;
wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded;
wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index d8ece28c079..0159e4e9320 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -296,11 +296,14 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm,
u16 control = 0;
u16 wsec_rate = 0;
u16 encrypt_frame;
+ const u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(wireless_header->frame_ctl));
+ const int is_mgt = (ftype == IEEE80211_FTYPE_MGMT);
/* Now construct the TX header. */
memset(txhdr, 0, sizeof(*txhdr));
- bitrate = bcm->softmac->txrates.default_rate;
+ bitrate = ieee80211softmac_suggest_txrate(bcm->softmac,
+ is_multicast_ether_addr(wireless_header->addr1), is_mgt);
ofdm_modulation = !(ieee80211_is_cck_rate(bitrate));
fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate);
fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate));
@@ -489,20 +492,18 @@ int bcm43xx_rx(struct bcm43xx_private *bcm,
memset(&stats, 0, sizeof(stats));
stats.mac_time = le16_to_cpu(rxhdr->mactime);
- stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
+ stats.rssi = rxhdr->rssi;
+ stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
!!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
!!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
- stats.signal = rxhdr->signal_quality; //FIXME
-//TODO stats.noise =
+ stats.noise = bcm->stats.noise;
if (is_ofdm)
stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
else
stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
-//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate);
stats.received_channel = radio->channel;
-//TODO stats.control =
stats.mask = IEEE80211_STATMASK_SIGNAL |
-//TODO IEEE80211_STATMASK_NOISE |
+ IEEE80211_STATMASK_NOISE |
IEEE80211_STATMASK_RATE |
IEEE80211_STATMASK_RSSI;
if (phy->type == BCM43xx_PHYTYPE_A)
diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c
index 2aa2f389c0d..29d39105f5b 100644
--- a/drivers/net/wireless/hermes.c
+++ b/drivers/net/wireless/hermes.c
@@ -38,7 +38,6 @@
* under either the MPL or the GPL.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h
index 5e63765219f..e663518bd57 100644
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -86,7 +86,7 @@ void hostap_info_process(local_info_t *local, struct sk_buff *skb);
/* hostap_ioctl.c */
extern const struct iw_handler_def hostap_iw_handler_def;
-extern struct ethtool_ops prism2_ethtool_ops;
+extern const struct ethtool_ops prism2_ethtool_ops;
int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
index db03dc2646d..686d895116d 100644
--- a/drivers/net/wireless/hostap/hostap_cs.c
+++ b/drivers/net/wireless/hostap/hostap_cs.c
@@ -1,6 +1,5 @@
#define PRISM2_PCCARD
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if.h>
@@ -844,10 +843,11 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
- PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000),
+/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
+ PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002),
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL",
0x74c5e40d),
PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil",
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index 328e9a1d13b..d500012fdc7 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -30,7 +30,6 @@
*/
-#include <linux/config.h>
#include <asm/delay.h>
#include <asm/uaccess.h>
@@ -1043,6 +1042,9 @@ static int prism2_reset_port(struct net_device *dev)
dev->name, local->fragm_threshold);
}
+ /* Some firmwares lose antenna selection settings on reset */
+ (void) hostap_set_antsel(local);
+
return res;
}
@@ -3096,6 +3098,14 @@ static void prism2_clear_set_tim_queue(local_info_t *local)
}
+/*
+ * HostAP uses two layers of net devices, where the inner
+ * layer gets called all the time from the outer layer.
+ * This is a natural nesting, which needs a split lock type.
+ */
+static struct lock_class_key hostap_netdev_xmit_lock_key;
+
+
static struct net_device *
prism2_init_local_data(struct prism2_helper_functions *funcs, int card_idx,
struct device *sdev)
@@ -3260,6 +3270,8 @@ while (0)
SET_NETDEV_DEV(dev, sdev);
if (ret >= 0)
ret = register_netdevice(dev);
+
+ lockdep_set_class(&dev->_xmit_lock, &hostap_netdev_xmit_lock_key);
rtnl_unlock();
if (ret < 0) {
printk(KERN_WARNING "%s: register netdevice failed!\n",
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 8399de58189..d061fb3443f 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1412,9 +1412,9 @@ static int prism2_ioctl_siwretry(struct net_device *dev,
/* what could be done, if firmware would support this.. */
if (rrq->flags & IW_RETRY_LIMIT) {
- if (rrq->flags & IW_RETRY_MAX)
+ if (rrq->flags & IW_RETRY_LONG)
HFA384X_RID_LONGRETRYLIMIT = rrq->value;
- else if (rrq->flags & IW_RETRY_MIN)
+ else if (rrq->flags & IW_RETRY_SHORT)
HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
else {
HFA384X_RID_LONGRETRYLIMIT = rrq->value;
@@ -1468,14 +1468,14 @@ static int prism2_ioctl_giwretry(struct net_device *dev,
rrq->value = le16_to_cpu(altretry);
else
rrq->value = local->manual_retry_count;
- } else if ((rrq->flags & IW_RETRY_MAX)) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ } else if ((rrq->flags & IW_RETRY_LONG)) {
+ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
rrq->value = longretry;
} else {
rrq->flags = IW_RETRY_LIMIT;
rrq->value = shortretry;
if (shortretry != longretry)
- rrq->flags |= IW_RETRY_MIN;
+ rrq->flags |= IW_RETRY_SHORT;
}
}
return 0;
@@ -3908,7 +3908,7 @@ static void prism2_get_drvinfo(struct net_device *dev,
local->sta_fw_ver & 0xff);
}
-struct ethtool_ops prism2_ethtool_ops = {
+const struct ethtool_ops prism2_ethtool_ops = {
.get_drvinfo = prism2_get_drvinfo
};
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c
index 93786f4218f..53374fcba77 100644
--- a/drivers/net/wireless/hostap/hostap_main.c
+++ b/drivers/net/wireless/hostap/hostap_main.c
@@ -12,7 +12,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
index 194f0709758..c2fa011be29 100644
--- a/drivers/net/wireless/hostap/hostap_pci.c
+++ b/drivers/net/wireless/hostap/hostap_pci.c
@@ -4,7 +4,6 @@
* driver patches from Reyk Floeter <reyk@vantronix.net> and
* Andy Warner <andyw@pobox.com> */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if.h>
@@ -338,7 +337,7 @@ static int prism2_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
- if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
+ if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
dev)) {
printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
goto fail;
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
index edaaa943eb8..6dfa041be66 100644
--- a/drivers/net/wireless/hostap/hostap_plx.c
+++ b/drivers/net/wireless/hostap/hostap_plx.c
@@ -7,7 +7,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/if.h>
@@ -67,10 +66,12 @@ static struct pci_device_id prism2_plx_id_table[] __devinitdata = {
PLXDEV(0x10b7, 0x7770, "3Com AirConnect PCI 777A"),
PLXDEV(0x111a, 0x1023, "Siemens SpeedStream SS1023"),
PLXDEV(0x126c, 0x8030, "Nortel emobility"),
+ PLXDEV(0x1562, 0x0001, "Symbol LA-4123"),
PLXDEV(0x1385, 0x4100, "Netgear MA301"),
PLXDEV(0x15e8, 0x0130, "National Datacomm NCP130 (PLX9052)"),
PLXDEV(0x15e8, 0x0131, "National Datacomm NCP130 (TMD7160)"),
PLXDEV(0x1638, 0x1100, "Eumitcom WL11000"),
+ PLXDEV(0x16ab, 0x1100, "Global Sun Tech GL24110P"),
PLXDEV(0x16ab, 0x1101, "Global Sun Tech GL24110P (?)"),
PLXDEV(0x16ab, 0x1102, "Linksys WPC11 with WDT11"),
PLXDEV(0x16ab, 0x1103, "Longshine 8031"),
@@ -551,7 +552,7 @@ static int prism2_plx_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, dev);
- if (request_irq(dev->irq, prism2_interrupt, SA_SHIRQ, dev->name,
+ if (request_irq(dev->irq, prism2_interrupt, IRQF_SHARED, dev->name,
dev)) {
printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
goto fail;
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index 72335c8eb97..6c5add701a6 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -134,7 +134,6 @@ that only one external action is invoked at a time.
*/
#include <linux/compiler.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/if_arp.h>
#include <linux/in6.h>
@@ -1485,7 +1484,7 @@ static int ipw2100_hw_stop_adapter(struct ipw2100_priv *priv)
*
* Sending the PREPARE_FOR_POWER_DOWN will restrict the
* hardware from going into standby mode and will transition
- * out of D0-standy if it is already in that state.
+ * out of D0-standby if it is already in that state.
*
* STATUS_PREPARE_POWER_DOWN_COMPLETE will be sent by the
* driver upon completion. Once received, the driver can
@@ -5358,7 +5357,7 @@ static int ipw2100_set_key(struct ipw2100_priv *priv,
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,
+ * or some other problem is occurring. If the user is setting the key,
* then we push the change */
wep_key->idx = idx;
@@ -5912,7 +5911,7 @@ static u32 ipw2100_ethtool_get_link(struct net_device *dev)
return (priv->status & STATUS_ASSOCIATED) ? 1 : 0;
}
-static struct ethtool_ops ipw2100_ethtool_ops = {
+static const struct ethtool_ops ipw2100_ethtool_ops = {
.get_link = ipw2100_ethtool_get_link,
.get_drvinfo = ipw_ethtool_get_drvinfo,
};
@@ -6230,7 +6229,7 @@ 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, IRQF_SHARED, dev->name, priv);
if (err) {
printk(KERN_WARNING DRV_NAME
"Error calling request_irq: %d.\n", pci_dev->irq);
@@ -6255,13 +6254,14 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
* member to call a function that then just turns and calls ipw2100_up.
* net_dev->init is called after name allocation but before the
* notifier chain is called */
- mutex_lock(&priv->action_mutex);
err = register_netdev(dev);
if (err) {
printk(KERN_WARNING DRV_NAME
"Error calling register_netdev.\n");
- goto fail_unlock;
+ goto fail;
}
+
+ mutex_lock(&priv->action_mutex);
registered = 1;
IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
@@ -6532,7 +6532,7 @@ 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);
- ret = pci_module_init(&ipw2100_pci_driver);
+ ret = pci_register_driver(&ipw2100_pci_driver);
#ifdef CONFIG_IPW2100_DEBUG
ipw2100_debug_level = debug;
@@ -6958,7 +6958,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
}
if (wrqu->essid.flags && wrqu->essid.length) {
- length = wrqu->essid.length - 1;
+ length = wrqu->essid.length;
essid = extra;
}
@@ -7051,7 +7051,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
- wrqu->data.length = strlen(priv->nick) + 1;
+ wrqu->data.length = strlen(priv->nick);
memcpy(extra, priv->nick, wrqu->data.length);
wrqu->data.flags = 1; /* active */
@@ -7343,14 +7343,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
goto done;
}
- if (wrqu->retry.flags & IW_RETRY_MIN) {
+ if (wrqu->retry.flags & IW_RETRY_SHORT) {
err = ipw2100_set_short_retry(priv, wrqu->retry.value);
IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
wrqu->retry.value);
goto done;
}
- if (wrqu->retry.flags & IW_RETRY_MAX) {
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
err = ipw2100_set_long_retry(priv, wrqu->retry.value);
IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
wrqu->retry.value);
@@ -7383,14 +7383,14 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
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;
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
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_SHORT : IW_RETRY_LIMIT;
wrqu->retry.value = priv->short_retry_limit;
}
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 081a8999666..5685d7ba55b 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -70,7 +70,7 @@
#define VQ
#endif
-#define IPW2200_VERSION "1.1.2" VK VD VM VP VR VQ
+#define IPW2200_VERSION "1.1.4" VK VD VM VP VR VQ
#define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation"
#define DRV_VERSION IPW2200_VERSION
@@ -83,9 +83,7 @@ MODULE_AUTHOR(DRV_COPYRIGHT);
MODULE_LICENSE("GPL");
static int cmdlog = 0;
-#ifdef CONFIG_IPW2200_DEBUG
static int debug = 0;
-#endif
static int channel = 0;
static int mode = 0;
@@ -567,7 +565,6 @@ static inline void ipw_disable_interrupts(struct ipw_priv *priv)
spin_unlock_irqrestore(&priv->irq_lock, flags);
}
-#ifdef CONFIG_IPW2200_DEBUG
static char *ipw_error_desc(u32 val)
{
switch (val) {
@@ -634,7 +631,6 @@ static void ipw_dump_error_log(struct ipw_priv *priv,
error->log[i].time,
error->log[i].data, error->log[i].event);
}
-#endif
static inline int ipw_is_init(struct ipw_priv *priv)
{
@@ -1229,12 +1225,6 @@ static struct ipw_fw_error *ipw_alloc_error_log(struct ipw_priv *priv)
return error;
}
-static void ipw_free_error_log(struct ipw_fw_error *error)
-{
- if (error)
- kfree(error);
-}
-
static ssize_t show_event_log(struct device *d,
struct device_attribute *attr, char *buf)
{
@@ -1296,10 +1286,9 @@ static ssize_t clear_error(struct device *d,
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;
- }
+
+ kfree(priv->error);
+ priv->error = NULL;
return count;
}
@@ -1442,9 +1431,7 @@ 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_IPW2200_DEBUG
struct net_device *dev = priv->net_dev;
-#endif
char buffer[] = "00000000";
unsigned long len =
(sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1;
@@ -1965,15 +1952,12 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
IPW_WARNING("Firmware error detected. Restarting.\n");
if (priv->error) {
IPW_DEBUG_FW("Sysfs 'error' log already exists.\n");
-#ifdef CONFIG_IPW2200_DEBUG
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);
+ kfree(error);
}
-#endif
} else {
priv->error = ipw_alloc_error_log(priv);
if (priv->error)
@@ -1981,10 +1965,8 @@ static void ipw_irq_tasklet(struct ipw_priv *priv)
else
IPW_DEBUG_FW("Error allocating sysfs 'error' "
"log.\n");
-#ifdef CONFIG_IPW2200_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,
@@ -2295,7 +2277,7 @@ static int ipw_send_scan_abort(struct ipw_priv *priv)
static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens)
{
struct ipw_sensitivity_calib calib = {
- .beacon_rssi_raw = sens,
+ .beacon_rssi_raw = cpu_to_le16(sens),
};
return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib),
@@ -2361,6 +2343,7 @@ static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off)
return -1;
}
+ phy_off = cpu_to_le32(phy_off);
return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off),
&phy_off);
}
@@ -2422,7 +2405,7 @@ static int ipw_set_tx_power(struct ipw_priv *priv)
static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
{
struct ipw_rts_threshold rts_threshold = {
- .rts_threshold = rts,
+ .rts_threshold = cpu_to_le16(rts),
};
if (!priv) {
@@ -2437,7 +2420,7 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts)
static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag)
{
struct ipw_frag_threshold frag_threshold = {
- .frag_threshold = frag,
+ .frag_threshold = cpu_to_le16(frag),
};
if (!priv) {
@@ -2472,6 +2455,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode)
break;
}
+ param = cpu_to_le32(mode);
return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param),
&param);
}
@@ -2675,7 +2659,7 @@ static void ipw_fw_dma_abort(struct ipw_priv *priv)
IPW_DEBUG_FW(">> :\n");
- //set the Stop and Abort bit
+ /* set the Stop and Abort bit */
control = DMA_CONTROL_SMALL_CB_CONST_VALUE | DMA_CB_STOP_AND_ABORT;
ipw_write_reg32(priv, IPW_DMA_I_DMA_CONTROL, control);
priv->sram_desc.last_cb_index = 0;
@@ -3010,8 +2994,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
if (rc < 0)
return rc;
-// spin_lock_irqsave(&priv->lock, flags);
-
for (addr = IPW_SHARED_LOWER_BOUND;
addr < IPW_REGISTER_DOMAIN1_END; addr += 4) {
ipw_write32(priv, addr, 0);
@@ -3105,8 +3087,6 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len)
firmware have problem getting alive resp. */
ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0);
-// spin_unlock_irqrestore(&priv->lock, flags);
-
return rc;
}
@@ -3927,7 +3907,6 @@ static const struct ipw_status_code ipw_status_codes[] = {
{0x2E, "Cipher suite is rejected per security policy"},
};
-#ifdef CONFIG_IPW2200_DEBUG
static const char *ipw_get_status_code(u16 status)
{
int i;
@@ -3936,7 +3915,6 @@ static const char *ipw_get_status_code(u16 status)
return ipw_status_codes[i].reason;
return "Unknown status value.";
}
-#endif
static void inline average_init(struct average *avg)
{
@@ -4406,7 +4384,6 @@ static void ipw_rx_notification(struct ipw_priv *priv,
if (priv->
status & (STATUS_ASSOCIATED |
STATUS_AUTH)) {
-#ifdef CONFIG_IPW2200_DEBUG
struct notif_authenticate *auth
= &notif->u.auth;
IPW_DEBUG(IPW_DL_NOTIF |
@@ -4424,7 +4401,6 @@ static void ipw_rx_notification(struct ipw_priv *priv,
ipw_get_status_code
(ntohs
(auth->status)));
-#endif
priv->status &=
~(STATUS_ASSOCIATING |
@@ -5067,7 +5043,6 @@ static void ipw_rx_queue_replenish(void *data)
}
list_del(element);
- rxb->rxb = (struct ipw_rx_buffer *)rxb->skb->data;
rxb->dma_addr =
pci_map_single(priv->pci_dev, rxb->skb->data,
IPW_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
@@ -5846,8 +5821,8 @@ static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index)
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;
+ key.tx_counter[0] = cpu_to_le32(0);
+ key.tx_counter[1] = cpu_to_le32(0);
ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key);
}
@@ -5981,7 +5956,6 @@ static void ipw_bg_adhoc_check(void *data)
mutex_unlock(&priv->mutex);
}
-#ifdef CONFIG_IPW2200_DEBUG
static void ipw_debug_config(struct ipw_priv *priv)
{
IPW_DEBUG_INFO("Scan completed, no valid APs matched "
@@ -6006,9 +5980,6 @@ static void ipw_debug_config(struct ipw_priv *priv)
IPW_DEBUG_INFO("PRIVACY off\n");
IPW_DEBUG_INFO("RATE MASK: 0x%08X\n", priv->rates_mask);
}
-#else
-#define ipw_debug_config(x) do {} while (0)
-#endif
static void ipw_set_fixed_rate(struct ipw_priv *priv, int mode)
{
@@ -6196,7 +6167,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv,
}
}
-static int ipw_request_scan(struct ipw_priv *priv)
+static int ipw_request_scan_helper(struct ipw_priv *priv, int type)
{
struct ipw_scan_request_ext scan;
int err = 0, scan_type;
@@ -6227,19 +6198,29 @@ static int ipw_request_scan(struct ipw_priv *priv)
}
memset(&scan, 0, sizeof(scan));
+ scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
- if (priv->config & CFG_SPEED_SCAN)
+ if (type == IW_SCAN_TYPE_PASSIVE) {
+ IPW_DEBUG_WX("use passive scanning\n");
+ scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN;
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
+ cpu_to_le16(120);
+ ipw_add_scan_channels(priv, &scan, scan_type);
+ goto send_request;
+ }
+
+ /* Use active scan by default. */
+ if (priv->config & CFG_SPEED_SCAN)
scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(30);
+ cpu_to_le16(30);
else
scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] =
- cpu_to_le16(20);
+ 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);
+ cpu_to_le16(20);
- scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee));
+ scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120);
#ifdef CONFIG_IPW2200_MONITOR
if (priv->ieee->iw_mode == IW_MODE_MONITOR) {
@@ -6276,7 +6257,7 @@ static int ipw_request_scan(struct ipw_priv *priv)
*
* TODO: Move SPEED SCAN support to all modes and bands */
scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] =
- cpu_to_le16(2000);
+ cpu_to_le16(2000);
} else {
#endif /* CONFIG_IPW2200_MONITOR */
/* If we are roaming, then make this a directed scan for the
@@ -6302,6 +6283,7 @@ static int ipw_request_scan(struct ipw_priv *priv)
}
#endif
+send_request:
err = ipw_send_scan_request_ext(priv, &scan);
if (err) {
IPW_DEBUG_HC("Sending scan command failed: %08X\n", err);
@@ -6312,11 +6294,19 @@ static int ipw_request_scan(struct ipw_priv *priv)
priv->status &= ~STATUS_SCAN_PENDING;
queue_delayed_work(priv->workqueue, &priv->scan_check,
IPW_SCAN_CHECK_WATCHDOG);
- done:
+done:
mutex_unlock(&priv->mutex);
return err;
}
+static int ipw_request_passive_scan(struct ipw_priv *priv) {
+ return ipw_request_scan_helper(priv, IW_SCAN_TYPE_PASSIVE);
+}
+
+static int ipw_request_scan(struct ipw_priv *priv) {
+ return ipw_request_scan_helper(priv, IW_SCAN_TYPE_ACTIVE);
+}
+
static void ipw_bg_abort_scan(void *data)
{
struct ipw_priv *priv = data;
@@ -6395,13 +6385,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
(wrqu->data.length && extra == NULL))
return -EINVAL;
- //mutex_lock(&priv->mutex);
-
- //if (!ieee->wpa_enabled) {
- // err = -EOPNOTSUPP;
- // goto out;
- //}
-
if (wrqu->data.length) {
buf = kmalloc(wrqu->data.length, GFP_KERNEL);
if (buf == NULL) {
@@ -6421,7 +6404,6 @@ static int ipw_wx_set_genie(struct net_device *dev,
ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len);
out:
- //mutex_unlock(&priv->mutex);
return err;
}
@@ -6434,13 +6416,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
struct ieee80211_device *ieee = priv->ieee;
int err = 0;
- //mutex_lock(&priv->mutex);
-
- //if (!ieee->wpa_enabled) {
- // err = -EOPNOTSUPP;
- // goto out;
- //}
-
if (ieee->wpa_ie_len == 0 || ieee->wpa_ie == NULL) {
wrqu->data.length = 0;
goto out;
@@ -6455,7 +6430,6 @@ static int ipw_wx_get_genie(struct net_device *dev,
memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len);
out:
- //mutex_unlock(&priv->mutex);
return err;
}
@@ -6566,7 +6540,6 @@ static int ipw_wx_set_auth(struct net_device *dev,
ieee->ieee802_1x = param->value;
break;
- //case IW_AUTH_ROAMING_CONTROL:
case IW_AUTH_PRIVACY_INVOKED:
ieee->privacy_invoked = param->value;
break;
@@ -6688,7 +6661,7 @@ static int ipw_wx_set_mlme(struct net_device *dev,
switch (mlme->cmd) {
case IW_MLME_DEAUTH:
- // silently ignore
+ /* silently ignore */
break;
case IW_MLME_DISASSOC:
@@ -6819,7 +6792,7 @@ static int ipw_qos_activate(struct ipw_priv *priv,
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;
+ (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",
@@ -6851,11 +6824,20 @@ static int ipw_qos_activate(struct ipw_priv *priv,
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;
+ tx_op_limit[i] = (u16)burst_duration;
}
}
IPW_DEBUG_QOS("QoS sending IPW_CMD_QOS_PARAMETERS\n");
+ for (i = 0; i < 3; i++) {
+ int j;
+ for (j = 0; j < QOS_QUEUE_NUM; j++) {
+ qos_parameters[i].cw_min[j] = cpu_to_le16(qos_parameters[i].cw_min[j]);
+ qos_parameters[i].cw_max[j] = cpu_to_le16(qos_parameters[i].cw_max[j]);
+ qos_parameters[i].tx_op_limit[j] = cpu_to_le16(qos_parameters[i].tx_op_limit[j]);
+ }
+ }
+
err = ipw_send_qos_params_command(priv,
(struct ieee80211_qos_parameters *)
&(qos_parameters[0]));
@@ -7094,7 +7076,7 @@ static int ipw_qos_set_tx_queue_command(struct ipw_priv *priv,
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;
+ tfd->tfd.tfd_26.mchdr.qos_ctrl |= cpu_to_le16(CTRL_QOS_NO_ACK);
}
return 0;
}
@@ -7675,7 +7657,6 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
/* Big bitfield of all the fields we provide in radiotap */
ipw_rt->rt_hdr.it_present =
((1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_TSFT) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
@@ -7684,6 +7665,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
/* Zero the flags, we'll add to them as we go */
ipw_rt->rt_flags = 0;
+ ipw_rt->rt_tsf = 0ULL;
/* Convert signal to DBM */
ipw_rt->rt_dbmsignal = antsignal;
@@ -7802,7 +7784,6 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
s8 noise = frame->noise;
u8 rate = frame->rate;
short len = le16_to_cpu(pkt->u.frame.length);
- u64 tsf = 0;
struct sk_buff *skb;
int hdr_only = 0;
u16 filter = priv->prom_priv->filter;
@@ -7837,17 +7818,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
}
hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE;
- if (ieee80211_is_management(hdr->frame_ctl)) {
+ if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
if (filter & IPW_PROM_NO_MGMT)
return;
if (filter & IPW_PROM_MGMT_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_control(hdr->frame_ctl)) {
+ } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
if (filter & IPW_PROM_NO_CTL)
return;
if (filter & IPW_PROM_CTL_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_data(hdr->frame_ctl)) {
+ } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
if (filter & IPW_PROM_NO_DATA)
return;
if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -7865,7 +7846,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
ipw_rt = (void *)skb->data;
if (hdr_only)
- len = ieee80211_get_hdrlen(hdr->frame_ctl);
+ len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
memcpy(ipw_rt->payload, hdr, len);
@@ -7888,7 +7869,6 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
/* Big bitfield of all the fields we provide in radiotap */
ipw_rt->rt_hdr.it_present =
((1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_TSFT) |
(1 << IEEE80211_RADIOTAP_RATE) |
(1 << IEEE80211_RADIOTAP_CHANNEL) |
(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
@@ -7897,8 +7877,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
/* Zero the flags, we'll add to them as we go */
ipw_rt->rt_flags = 0;
-
- ipw_rt->rt_tsf = tsf;
+ ipw_rt->rt_tsf = 0ULL;
/* Convert to DBM */
ipw_rt->rt_dbmsignal = signal;
@@ -8171,8 +8150,7 @@ 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 =
- le16_to_cpu(pkt->u.frame.rssi_dbm) -
+ .rssi = pkt->u.frame.rssi_dbm -
IPW_RSSI_TO_DBM,
.signal =
le16_to_cpu(pkt->u.frame.rssi_dbm) -
@@ -8607,9 +8585,26 @@ static int ipw_wx_get_freq(struct net_device *dev,
* configured CHANNEL then return that; otherwise return ANY */
mutex_lock(&priv->mutex);
if (priv->config & CFG_STATIC_CHANNEL ||
- priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED))
- wrqu->freq.m = priv->channel;
- else
+ priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) {
+ int i;
+
+ i = ieee80211_channel_to_index(priv->ieee, priv->channel);
+ BUG_ON(i == -1);
+ wrqu->freq.e = 1;
+
+ switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) {
+ case IEEE80211_52GHZ_BAND:
+ wrqu->freq.m = priv->ieee->geo.a[i].freq * 100000;
+ break;
+
+ case IEEE80211_24GHZ_BAND:
+ wrqu->freq.m = priv->ieee->geo.bg[i].freq * 100000;
+ break;
+
+ default:
+ BUG();
+ }
+ } else
wrqu->freq.m = 0;
mutex_unlock(&priv->mutex);
@@ -8865,42 +8860,36 @@ static int ipw_wx_set_essid(struct net_device *dev,
union iwreq_data *wrqu, char *extra)
{
struct ipw_priv *priv = ieee80211_priv(dev);
- char *essid = ""; /* ANY */
- int length = 0;
- mutex_lock(&priv->mutex);
- 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");
- 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);
- }
- mutex_unlock(&priv->mutex);
- return 0;
- }
+ int length;
- length = min(length, IW_ESSID_MAX_SIZE);
+ mutex_lock(&priv->mutex);
+
+ if (!wrqu->essid.flags)
+ {
+ IPW_DEBUG_WX("Setting ESSID to ANY\n");
+ ipw_disassociate(priv);
+ priv->config &= ~CFG_STATIC_ESSID;
+ ipw_associate(priv);
+ mutex_unlock(&priv->mutex);
+ return 0;
+ }
+
+ length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
priv->config |= CFG_STATIC_ESSID;
- if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) {
+ if (priv->essid_len == length && !memcmp(priv->essid, extra, length)
+ && (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) {
IPW_DEBUG_WX("ESSID set to current ESSID.\n");
mutex_unlock(&priv->mutex);
return 0;
}
- IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length),
+ IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length),
length);
priv->essid_len = length;
- memcpy(priv->essid, essid, priv->essid_len);
+ memcpy(priv->essid, extra, priv->essid_len);
/* Network configuration changed -- force [re]association */
IPW_DEBUG_ASSOC("[re]association triggered due to ESSID change.\n");
@@ -8962,7 +8951,7 @@ static int ipw_wx_get_nick(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
IPW_DEBUG_WX("Getting nick\n");
mutex_lock(&priv->mutex);
- wrqu->data.length = strlen(priv->nick) + 1;
+ wrqu->data.length = strlen(priv->nick);
memcpy(extra, priv->nick, wrqu->data.length);
wrqu->data.flags = 1; /* active */
mutex_unlock(&priv->mutex);
@@ -9281,13 +9270,13 @@ static int ipw_wx_set_retry(struct net_device *dev,
if (!(wrqu->retry.flags & IW_RETRY_LIMIT))
return 0;
- if (wrqu->retry.value < 0 || wrqu->retry.value > 255)
+ if (wrqu->retry.value < 0 || wrqu->retry.value >= 255)
return -EINVAL;
mutex_lock(&priv->mutex);
- if (wrqu->retry.flags & IW_RETRY_MIN)
+ if (wrqu->retry.flags & IW_RETRY_SHORT)
priv->short_retry_limit = (u8) wrqu->retry.value;
- else if (wrqu->retry.flags & IW_RETRY_MAX)
+ else if (wrqu->retry.flags & IW_RETRY_LONG)
priv->long_retry_limit = (u8) wrqu->retry.value;
else {
priv->short_retry_limit = (u8) wrqu->retry.value;
@@ -9316,11 +9305,11 @@ static int ipw_wx_get_retry(struct net_device *dev,
return -EINVAL;
}
- if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
wrqu->retry.value = priv->long_retry_limit;
- } else if (wrqu->retry.flags & IW_RETRY_MIN) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ } else if (wrqu->retry.flags & IW_RETRY_SHORT) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
wrqu->retry.value = priv->short_retry_limit;
} else {
wrqu->retry.flags = IW_RETRY_LIMIT;
@@ -9404,15 +9393,19 @@ 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;
+ struct iw_scan_req *req = (struct iw_scan_req *)extra;
+
+ if (wrqu->data.length == sizeof(struct iw_scan_req)) {
if (wrqu->data.flags & IW_SCAN_THIS_ESSID) {
ipw_request_direct_scan(priv, req->essid,
req->essid_len);
return 0;
}
+ if (req->scan_type == IW_SCAN_TYPE_PASSIVE) {
+ queue_work(priv->workqueue,
+ &priv->request_passive_scan);
+ return 0;
+ }
}
IPW_DEBUG_WX("Start scan\n");
@@ -9774,7 +9767,7 @@ static int ipw_wx_set_monitor(struct net_device *dev,
return 0;
}
-#endif // CONFIG_IPW2200_MONITOR
+#endif /* CONFIG_IPW2200_MONITOR */
static int ipw_wx_reset(struct net_device *dev,
struct iw_request_info *info,
@@ -10017,7 +10010,7 @@ static 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; //1 -- fix for 256
+ sys_config->pass_noise_stats_to_host = 1; /* 1 -- fix for 256 */
sys_config->silence_threshold = 0x1e;
}
@@ -10121,7 +10114,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
switch (priv->ieee->sec.level) {
case SEC_LEVEL_3:
tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- IEEE80211_FCTL_PROTECTED;
+ cpu_to_le16(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
@@ -10136,14 +10129,14 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb,
break;
case SEC_LEVEL_2:
tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |=
- IEEE80211_FCTL_PROTECTED;
+ cpu_to_le16(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;
+ cpu_to_le16(IEEE80211_FCTL_PROTECTED);
tfd->u.data.key_index = priv->ieee->tx_keyidx;
if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <=
40)
@@ -10275,17 +10268,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
/* Filtering of fragment chains is done agains the first fragment */
hdr = (void *)txb->fragments[0]->data;
- if (ieee80211_is_management(hdr->frame_ctl)) {
+ if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) {
if (filter & IPW_PROM_NO_MGMT)
return;
if (filter & IPW_PROM_MGMT_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_control(hdr->frame_ctl)) {
+ } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) {
if (filter & IPW_PROM_NO_CTL)
return;
if (filter & IPW_PROM_CTL_HEADER_ONLY)
hdr_only = 1;
- } else if (ieee80211_is_data(hdr->frame_ctl)) {
+ } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) {
if (filter & IPW_PROM_NO_DATA)
return;
if (filter & IPW_PROM_DATA_HEADER_ONLY)
@@ -10300,7 +10293,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
if (hdr_only) {
hdr = (void *)src->data;
- len = ieee80211_get_hdrlen(hdr->frame_ctl);
+ len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
} else
len = src->len;
@@ -10466,7 +10459,7 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev,
return 0;
}
-static struct ethtool_ops ipw_ethtool_ops = {
+static const 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,
@@ -10644,6 +10637,8 @@ static int ipw_setup_deferred_work(struct ipw_priv *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->request_passive_scan,
+ (void (*)(void *))ipw_request_passive_scan, priv);
INIT_WORK(&priv->gather_stats,
(void (*)(void *))ipw_bg_gather_stats, priv);
INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_bg_abort_scan, priv);
@@ -11496,9 +11491,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
priv->net_dev = net_dev;
priv->pci_dev = pdev;
-#ifdef CONFIG_IPW2200_DEBUG
ipw_debug_level = debug;
-#endif
spin_lock_init(&priv->irq_lock);
spin_lock_init(&priv->lock);
for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++)
@@ -11553,7 +11546,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ipw_sw_reset(priv, 1);
- err = request_irq(pdev->irq, ipw_isr, SA_SHIRQ, DRV_NAME, priv);
+ err = request_irq(pdev->irq, ipw_isr, IRQF_SHARED, DRV_NAME, priv);
if (err) {
IPW_ERROR("Error allocating IRQ %d\n", pdev->irq);
goto out_destroy_workqueue;
@@ -11693,10 +11686,8 @@ static void ipw_pci_remove(struct pci_dev *pdev)
}
}
- if (priv->error) {
- ipw_free_error_log(priv->error);
- priv->error = NULL;
- }
+ kfree(priv->error);
+ priv->error = NULL;
#ifdef CONFIG_IPW2200_PROMISCUOUS
ipw_prom_free(priv);
@@ -11765,6 +11756,16 @@ static int ipw_pci_resume(struct pci_dev *pdev)
}
#endif
+static void ipw_pci_shutdown(struct pci_dev *pdev)
+{
+ struct ipw_priv *priv = pci_get_drvdata(pdev);
+
+ /* Take down the device; powers it off, etc. */
+ ipw_down(priv);
+
+ pci_disable_device(pdev);
+}
+
/* driver initialization stuff */
static struct pci_driver ipw_driver = {
.name = DRV_NAME,
@@ -11775,6 +11776,7 @@ static struct pci_driver ipw_driver = {
.suspend = ipw_pci_suspend,
.resume = ipw_pci_resume,
#endif
+ .shutdown = ipw_pci_shutdown,
};
static int __init ipw_init(void)
@@ -11784,7 +11786,7 @@ static int __init ipw_init(void)
printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
- ret = pci_module_init(&ipw_driver);
+ ret = pci_register_driver(&ipw_driver);
if (ret) {
IPW_ERROR("Unable to initialize PCI module\n");
return ret;
@@ -11818,10 +11820,8 @@ 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");
-#ifdef CONFIG_IPW2200_DEBUG
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, "debug output mask");
-#endif
module_param(channel, int, 0444);
MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])");
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h
index ea12ad66b8e..dad5eedefbf 100644
--- a/drivers/net/wireless/ipw2200.h
+++ b/drivers/net/wireless/ipw2200.h
@@ -31,7 +31,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/mutex.h>
@@ -714,7 +713,6 @@ struct ipw_rx_packet {
struct ipw_rx_mem_buffer {
dma_addr_t dma_addr;
- struct ipw_rx_buffer *rxb;
struct sk_buff *skb;
struct list_head list;
}; /* Not transferred over network, so not __attribute__ ((packed)) */
@@ -1298,6 +1296,7 @@ struct ipw_priv {
struct work_struct system_config;
struct work_struct rx_replenish;
struct work_struct request_scan;
+ struct work_struct request_passive_scan;
struct work_struct adapter_restart;
struct work_struct rf_kill;
struct work_struct up;
@@ -1382,13 +1381,18 @@ BITC(x,19),BITC(x,18),BITC(x,17),BITC(x,16),\
BIT_ARG16(x)
-#ifdef CONFIG_IPW2200_DEBUG
#define IPW_DEBUG(level, fmt, args...) \
do { if (ipw_debug_level & (level)) \
printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+
+#ifdef CONFIG_IPW2200_DEBUG
+#define IPW_LL_DEBUG(level, fmt, args...) \
+do { if (ipw_debug_level & (level)) \
+ printk(KERN_DEBUG DRV_NAME": %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
#else
-#define IPW_DEBUG(level, fmt, args...) do {} while (0)
+#define IPW_LL_DEBUG(level, fmt, args...) do {} while (0)
#endif /* CONFIG_IPW2200_DEBUG */
/*
@@ -1458,28 +1462,27 @@ do { if (ipw_debug_level & (level)) \
#define IPW_DEBUG_WX(f, a...) IPW_DEBUG(IPW_DL_WX, f, ## a)
#define IPW_DEBUG_SCAN(f, a...) IPW_DEBUG(IPW_DL_SCAN, f, ## a)
-#define IPW_DEBUG_STATUS(f, a...) IPW_DEBUG(IPW_DL_STATUS, f, ## a)
-#define IPW_DEBUG_TRACE(f, a...) IPW_DEBUG(IPW_DL_TRACE, f, ## a)
-#define IPW_DEBUG_RX(f, a...) IPW_DEBUG(IPW_DL_RX, f, ## a)
-#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_TRACE(f, a...) IPW_LL_DEBUG(IPW_DL_TRACE, f, ## a)
+#define IPW_DEBUG_RX(f, a...) IPW_LL_DEBUG(IPW_DL_RX, f, ## a)
+#define IPW_DEBUG_TX(f, a...) IPW_LL_DEBUG(IPW_DL_TX, f, ## a)
+#define IPW_DEBUG_ISR(f, a...) IPW_LL_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)
-#define IPW_DEBUG_FW(f, a...) IPW_DEBUG(IPW_DL_FW, f, ## a)
+#define IPW_DEBUG_LED(f, a...) IPW_LL_DEBUG(IPW_DL_LED, f, ## a)
+#define IPW_DEBUG_WEP(f, a...) IPW_LL_DEBUG(IPW_DL_WEP, f, ## a)
+#define IPW_DEBUG_HC(f, a...) IPW_LL_DEBUG(IPW_DL_HOST_COMMAND, f, ## a)
+#define IPW_DEBUG_FRAG(f, a...) IPW_LL_DEBUG(IPW_DL_FRAG, f, ## a)
+#define IPW_DEBUG_FW(f, a...) IPW_LL_DEBUG(IPW_DL_FW, f, ## a)
#define IPW_DEBUG_RF_KILL(f, a...) IPW_DEBUG(IPW_DL_RF_KILL, f, ## a)
#define IPW_DEBUG_DROP(f, a...) IPW_DEBUG(IPW_DL_DROP, f, ## a)
-#define IPW_DEBUG_IO(f, a...) IPW_DEBUG(IPW_DL_IO, f, ## a)
-#define IPW_DEBUG_ORD(f, a...) IPW_DEBUG(IPW_DL_ORD, f, ## a)
-#define IPW_DEBUG_FW_INFO(f, a...) IPW_DEBUG(IPW_DL_FW_INFO, f, ## a)
+#define IPW_DEBUG_IO(f, a...) IPW_LL_DEBUG(IPW_DL_IO, f, ## a)
+#define IPW_DEBUG_ORD(f, a...) IPW_LL_DEBUG(IPW_DL_ORD, f, ## a)
+#define IPW_DEBUG_FW_INFO(f, a...) IPW_LL_DEBUG(IPW_DL_FW_INFO, f, ## a)
#define IPW_DEBUG_NOTIF(f, a...) IPW_DEBUG(IPW_DL_NOTIF, f, ## a)
#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)
+#define IPW_DEBUG_STATS(f, a...) IPW_LL_DEBUG(IPW_DL_STATS, f, ## a)
+#define IPW_DEBUG_MERGE(f, a...) IPW_LL_DEBUG(IPW_DL_MERGE, f, ## a)
+#define IPW_DEBUG_QOS(f, a...) IPW_LL_DEBUG(IPW_DL_QOS, f, ## a)
#include <linux/ctype.h>
@@ -1948,10 +1951,17 @@ struct host_cmd {
u32 *param;
} __attribute__ ((packed));
+struct cmdlog_host_cmd {
+ u8 cmd;
+ u8 len;
+ u16 reserved;
+ char param[124];
+} __attribute__ ((packed));
+
struct ipw_cmd_log {
unsigned long jiffies;
int retcode;
- struct host_cmd cmd;
+ struct cmdlog_host_cmd cmd;
};
/* SysConfig command parameters ... */
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 9343d970537..36b5e004305 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -37,7 +37,6 @@
/* To have statistics (just packets sent) define this */
#undef NETWAVE_STATS
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 8a31b591a90..9e19a963feb 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -76,13 +76,13 @@
#define DRIVER_NAME "orinoco"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
+#include <linux/if_arp.h>
#include <linux/wireless.h>
#include <net/iw_handler.h>
#include <net/ieee80211.h>
@@ -165,7 +165,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
#define MAX_RID_LEN 1024
static const struct iw_handler_def orinoco_handler_def;
-static struct ethtool_ops orinoco_ethtool_ops;
+static const struct ethtool_ops orinoco_ethtool_ops;
/********************************************************************/
/* Data tables */
@@ -2876,7 +2876,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- if (erq->pointer) {
+ if (erq->length > 0) {
if ((index < 0) || (index >= ORINOCO_MAX_KEYS))
index = priv->tx_key;
@@ -2919,7 +2919,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev,
if (erq->flags & IW_ENCODE_RESTRICTED)
restricted = 1;
- if (erq->pointer) {
+ if (erq->pointer && erq->length > 0) {
priv->keys[index].len = cpu_to_le16(xlen);
memset(priv->keys[index].data, 0,
sizeof(priv->keys[index].data));
@@ -3037,7 +3037,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
}
erq->flags = 1;
- erq->length = strlen(essidbuf) + 1;
+ erq->length = strlen(essidbuf);
return 0;
}
@@ -3078,7 +3078,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev,
memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
orinoco_unlock(priv, &flags);
- nrq->length = strlen(nickbuf)+1;
+ nrq->length = strlen(nickbuf);
return 0;
}
@@ -3575,14 +3575,14 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
rrq->value = lifetime * 1000; /* ??? */
} else {
/* By default, display the min number */
- if ((rrq->flags & IW_RETRY_MAX)) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if ((rrq->flags & IW_RETRY_LONG)) {
+ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
rrq->value = long_limit;
} else {
rrq->flags = IW_RETRY_LIMIT;
rrq->value = short_limit;
if(short_limit != long_limit)
- rrq->flags |= IW_RETRY_MIN;
+ rrq->flags |= IW_RETRY_SHORT;
}
}
@@ -4293,7 +4293,7 @@ static void orinoco_get_drvinfo(struct net_device *dev,
"PCMCIA %p", priv->hw.iobase);
}
-static struct ethtool_ops orinoco_ethtool_ops = {
+static const struct ethtool_ops orinoco_ethtool_ops = {
.get_drvinfo = orinoco_get_drvinfo,
.get_link = ethtool_op_get_link,
};
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index 16db3e14b7d..fb5700d6c45 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -134,11 +134,7 @@ extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *reg
/* Locking and synchronization functions */
/********************************************************************/
-/* These functions *must* be inline or they will break horribly on
- * SPARC, due to its weird semantics for save/restore flags. extern
- * inline should prevent the kernel from linking or module from
- * loading if they are not inlined. */
-extern inline int orinoco_lock(struct orinoco_private *priv,
+static inline int orinoco_lock(struct orinoco_private *priv,
unsigned long *flags)
{
spin_lock_irqsave(&priv->lock, *flags);
@@ -151,7 +147,7 @@ extern inline int orinoco_lock(struct orinoco_private *priv,
return 0;
}
-extern inline void orinoco_unlock(struct orinoco_private *priv,
+static inline void orinoco_unlock(struct orinoco_private *priv,
unsigned long *flags)
{
spin_unlock_irqrestore(&priv->lock, *flags);
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index b2aec4d9fbb..bc14689cbf2 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -13,7 +13,6 @@
#define DRIVER_NAME "orinoco_cs"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c
index 74b9d5b2ba9..eaf3d13b851 100644
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -40,7 +40,6 @@
#define DRIVER_NAME "orinoco_nortel"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -199,7 +198,7 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
- err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
dev->name, dev);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
@@ -305,7 +304,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_nortel_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_nortel_driver);
+ return pci_register_driver(&orinoco_nortel_driver);
}
static void __exit orinoco_nortel_exit(void)
diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c
index 1c105f40f8d..97a8b4ff32b 100644
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -44,7 +44,6 @@
#define DRIVER_NAME "orinoco_pci"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -154,7 +153,7 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
hermes_struct_init(&priv->hw, hermes_io, HERMES_32BIT_REGSPACING);
- err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
dev->name, dev);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
@@ -245,7 +244,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_pci_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_pci_driver);
+ return pci_register_driver(&orinoco_pci_driver);
}
static void __exit orinoco_pci_exit(void)
diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco_pci.h
index 7eb1e08113e..be1abea4b64 100644
--- a/drivers/net/wireless/orinoco_pci.h
+++ b/drivers/net/wireless/orinoco_pci.h
@@ -63,7 +63,7 @@ static int orinoco_pci_resume(struct pci_dev *pdev)
pci_enable_device(pdev);
pci_restore_state(pdev);
- err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
dev->name, dev);
if (err) {
printk(KERN_ERR "%s: cannot re-allocate IRQ on resume\n",
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c
index 84f696c7755..31162ac25a9 100644
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -86,7 +86,6 @@
#define DRIVER_NAME "orinoco_plx"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -238,7 +237,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
- err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
dev->name, dev);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
@@ -352,7 +351,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_plx_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_plx_driver);
+ return pci_register_driver(&orinoco_plx_driver);
}
static void __exit orinoco_plx_exit(void)
diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c
index d2b4decb7a7..7c7b960c91d 100644
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -40,7 +40,6 @@
#define DRIVER_NAME "orinoco_tmd"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -140,7 +139,7 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
- err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
+ err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
dev->name, dev);
if (err) {
printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
@@ -229,7 +228,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int __init orinoco_tmd_init(void)
{
printk(KERN_DEBUG "%s\n", version);
- return pci_module_init(&orinoco_tmd_driver);
+ return pci_register_driver(&orinoco_tmd_driver);
}
static void __exit orinoco_tmd_exit(void)
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 989599ad33e..286325ca329 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -35,13 +35,21 @@
#include <net/iw_handler.h> /* New driver API */
+#define KEY_SIZE_WEP104 13 /* 104/128-bit WEP keys */
+#define KEY_SIZE_WEP40 5 /* 40/64-bit WEP keys */
+/* KEY_SIZE_TKIP should match isl_oid.h, struct obj_key.key[] size */
+#define KEY_SIZE_TKIP 32 /* TKIP keys */
-static void prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
+static void prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
u8 *wpa_ie, size_t wpa_ie_len);
-static size_t prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
+static size_t prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie);
static int prism54_set_wpa(struct net_device *, struct iw_request_info *,
__u32 *, char *);
+/* In 500 kbps */
+static const unsigned char scan_rate_list[] = { 2, 4, 11, 22,
+ 12, 18, 24, 36,
+ 48, 72, 96, 108 };
/**
* prism54_mib_mode_helper - MIB change mode helper function
@@ -468,6 +476,9 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
range->event_capa[1] = IW_EVENT_CAPA_K_1;
range->event_capa[4] = IW_EVENT_CAPA_MASK(IWEVCUSTOM);
+ range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+ IW_ENC_CAPA_CIPHER_TKIP;
+
if (islpci_get_state(priv) < PRV_STATE_INIT)
return 0;
@@ -567,6 +578,8 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
struct iw_event iwe; /* Temporary buffer */
short cap;
islpci_private *priv = netdev_priv(ndev);
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
/* The first entry must be the MAC address */
memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
@@ -627,28 +640,40 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
current_ev =
iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
- if (priv->wpa) {
- u8 wpa_ie[MAX_WPA_IE_LEN];
- char *buf, *p;
- size_t wpa_ie_len;
+ /* Add WPA/RSN Information Element, if any */
+ wpa_ie_len = prism54_wpa_bss_ie_get(priv, bss->address, wpa_ie);
+ if (wpa_ie_len > 0) {
+ iwe.cmd = IWEVGENIE;
+ iwe.u.data.length = min(wpa_ie_len, (size_t)MAX_WPA_IE_LEN);
+ current_ev = iwe_stream_add_point(current_ev, end_buf,
+ &iwe, wpa_ie);
+ }
+ /* Do the bitrates */
+ {
+ char * current_val = current_ev + IW_EV_LCP_LEN;
int i;
-
- wpa_ie_len = prism54_wpa_ie_get(priv, bss->address, wpa_ie);
- if (wpa_ie_len > 0 &&
- (buf = kmalloc(wpa_ie_len * 2 + 10, GFP_ATOMIC))) {
- p = buf;
- p += sprintf(p, "wpa_ie=");
- for (i = 0; i < wpa_ie_len; i++) {
- p += sprintf(p, "%02x", wpa_ie[i]);
+ int mask;
+
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+
+ /* Parse the bitmask */
+ mask = 0x1;
+ for(i = 0; i < sizeof(scan_rate_list); i++) {
+ if(bss->rates & mask) {
+ iwe.u.bitrate.value = (scan_rate_list[i] * 500000);
+ current_val = iwe_stream_add_value(current_ev, current_val,
+ end_buf, &iwe,
+ IW_EV_PARAM_LEN);
}
- memset(&iwe, 0, sizeof (iwe));
- iwe.cmd = IWEVCUSTOM;
- iwe.u.data.length = strlen(buf);
- current_ev = iwe_stream_add_point(current_ev, end_buf,
- &iwe, buf);
- kfree(buf);
+ mask <<= 1;
}
+ /* Check if we added any event */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
}
+
return current_ev;
}
@@ -717,9 +742,9 @@ prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
/* Check if we were asked for `any' */
if (dwrq->flags && dwrq->length) {
- if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
+ if (dwrq->length > 32)
return -E2BIG;
- essid.length = dwrq->length - 1;
+ essid.length = dwrq->length;
memcpy(essid.octets, extra, dwrq->length);
} else
essid.length = 0;
@@ -789,7 +814,7 @@ prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
dwrq->length = 0;
down_read(&priv->mib_sem);
- dwrq->length = strlen(priv->nickname) + 1;
+ dwrq->length = strlen(priv->nickname);
memcpy(extra, priv->nickname, dwrq->length);
up_read(&priv->mib_sem);
@@ -967,9 +992,9 @@ prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
return -EINVAL;
if (vwrq->flags & IW_RETRY_LIMIT) {
- if (vwrq->flags & IW_RETRY_MIN)
+ if (vwrq->flags & IW_RETRY_SHORT)
slimit = vwrq->value;
- else if (vwrq->flags & IW_RETRY_MAX)
+ else if (vwrq->flags & IW_RETRY_LONG)
llimit = vwrq->value;
else {
/* we are asked to set both */
@@ -1010,18 +1035,18 @@ prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
vwrq->value = r.u * 1024;
vwrq->flags = IW_RETRY_LIFETIME;
- } else if ((vwrq->flags & IW_RETRY_MAX)) {
+ } else if ((vwrq->flags & IW_RETRY_LONG)) {
/* we are asked for the long retry limit */
rvalue |=
mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
vwrq->value = r.u;
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
} else {
/* default. get the short retry limit */
rvalue |=
mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
vwrq->value = r.u;
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
}
return rvalue;
@@ -1051,12 +1076,24 @@ prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
current_index = r.u;
/* Verify that the key is not marked as invalid */
if (!(dwrq->flags & IW_ENCODE_NOKEY)) {
- key.length = dwrq->length > sizeof (key.key) ?
- sizeof (key.key) : dwrq->length;
- memcpy(key.key, extra, key.length);
- if (key.length == 32)
- /* we want WPA-PSK */
+ if (dwrq->length > KEY_SIZE_TKIP) {
+ /* User-provided key data too big */
+ return -EINVAL;
+ }
+ if (dwrq->length > KEY_SIZE_WEP104) {
+ /* WPA-PSK TKIP */
key.type = DOT11_PRIV_TKIP;
+ key.length = KEY_SIZE_TKIP;
+ } else if (dwrq->length > KEY_SIZE_WEP40) {
+ /* WEP 104/128 */
+ key.length = KEY_SIZE_WEP104;
+ } else {
+ /* WEP 40/64 */
+ key.length = KEY_SIZE_WEP40;
+ }
+ memset(key.key, 0, sizeof (key.key));
+ memcpy(key.key, extra, dwrq->length);
+
if ((index < 0) || (index > 3))
/* no index provided use the current one */
index = current_index;
@@ -1210,6 +1247,489 @@ prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
}
}
+static int prism54_set_genie(struct net_device *ndev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ int alen, ret = 0;
+ struct obj_attachment *attach;
+
+ if (data->length > MAX_WPA_IE_LEN ||
+ (data->length && extra == NULL))
+ return -EINVAL;
+
+ memcpy(priv->wpa_ie, extra, data->length);
+ priv->wpa_ie_len = data->length;
+
+ alen = sizeof(*attach) + priv->wpa_ie_len;
+ attach = kzalloc(alen, GFP_KERNEL);
+ if (attach == NULL)
+ return -ENOMEM;
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+
+ /* Note: endianness is covered by mgt_set_varlen */
+ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_ASSOC_REQ << 4);
+ attach->id = -1;
+ attach->size = priv->wpa_ie_len;
+ memcpy(attach->data, extra, priv->wpa_ie_len);
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+ priv->wpa_ie_len);
+ if (ret == 0) {
+ attach->type = (WLAN_FC_TYPE_MGMT << 2) |
+ (WLAN_FC_STYPE_REASSOC_REQ << 4);
+
+ ret = mgt_set_varlen(priv, DOT11_OID_ATTACHMENT, attach,
+ priv->wpa_ie_len);
+ if (ret == 0)
+ printk(KERN_DEBUG "%s: WPA IE Attachment was set\n",
+ ndev->name);
+ }
+
+ kfree(attach);
+ return ret;
+}
+
+
+static int prism54_get_genie(struct net_device *ndev,
+ struct iw_request_info *info,
+ struct iw_point *data, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ int len = priv->wpa_ie_len;
+
+ if (len <= 0) {
+ data->length = 0;
+ return 0;
+ }
+
+ if (data->length < len)
+ return -E2BIG;
+
+ data->length = len;
+ memcpy(extra, priv->wpa_ie, len);
+
+ return 0;
+}
+
+static int prism54_set_auth(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_param *param = &wrqu->param;
+ u32 mlmelevel = 0, authen = 0, dot1x = 0;
+ u32 exunencrypt = 0, privinvoked = 0, wpa = 0;
+ u32 old_wpa;
+ int ret = 0;
+ union oid_res_t r;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* first get the flags */
+ down_write(&priv->mib_sem);
+ wpa = old_wpa = priv->wpa;
+ up_write(&priv->mib_sem);
+ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+ authen = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+ privinvoked = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+ exunencrypt = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+ dot1x = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, NULL, &r);
+ mlmelevel = r.u;
+
+ if (ret < 0)
+ goto out;
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ case IW_AUTH_CIPHER_PAIRWISE:
+ case IW_AUTH_CIPHER_GROUP:
+ case IW_AUTH_KEY_MGMT:
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ /* Do the same thing as IW_AUTH_WPA_VERSION */
+ if (param->value) {
+ wpa = 1;
+ privinvoked = 1; /* For privacy invoked */
+ exunencrypt = 1; /* Filter out all unencrypted frames */
+ dot1x = 0x01; /* To enable eap filter */
+ mlmelevel = DOT11_MLME_EXTENDED;
+ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+ } else {
+ wpa = 0;
+ privinvoked = 0;
+ exunencrypt = 0; /* Do not filter un-encrypted data */
+ dot1x = 0;
+ mlmelevel = DOT11_MLME_AUTO;
+ }
+ break;
+
+ case IW_AUTH_WPA_VERSION:
+ if (param->value & IW_AUTH_WPA_VERSION_DISABLED) {
+ wpa = 0;
+ privinvoked = 0;
+ exunencrypt = 0; /* Do not filter un-encrypted data */
+ dot1x = 0;
+ mlmelevel = DOT11_MLME_AUTO;
+ } else {
+ if (param->value & IW_AUTH_WPA_VERSION_WPA)
+ wpa = 1;
+ else if (param->value & IW_AUTH_WPA_VERSION_WPA2)
+ wpa = 2;
+ privinvoked = 1; /* For privacy invoked */
+ exunencrypt = 1; /* Filter out all unencrypted frames */
+ dot1x = 0x01; /* To enable eap filter */
+ mlmelevel = DOT11_MLME_EXTENDED;
+ authen = DOT11_AUTH_OS; /* Only WEP uses _SK and _BOTH */
+ }
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ dot1x = param->value ? 1 : 0;
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ privinvoked = param->value ? 1 : 0;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ exunencrypt = param->value ? 1 : 0;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ if (param->value & IW_AUTH_ALG_SHARED_KEY) {
+ /* Only WEP uses _SK and _BOTH */
+ if (wpa > 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ authen = DOT11_AUTH_SK;
+ } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) {
+ authen = DOT11_AUTH_OS;
+ } else {
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ /* Set all the values */
+ down_write(&priv->mib_sem);
+ priv->wpa = wpa;
+ up_write(&priv->mib_sem);
+ mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0, &authen);
+ mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0, &privinvoked);
+ mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0, &exunencrypt);
+ mgt_set_request(priv, DOT11_OID_DOT1XENABLE, 0, &dot1x);
+ mgt_set_request(priv, DOT11_OID_MLMEAUTOLEVEL, 0, &mlmelevel);
+
+out:
+ return ret;
+}
+
+static int prism54_get_auth(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_param *param = &wrqu->param;
+ u32 wpa = 0;
+ int ret = 0;
+ union oid_res_t r;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* first get the flags */
+ down_write(&priv->mib_sem);
+ wpa = priv->wpa;
+ up_write(&priv->mib_sem);
+
+ switch (param->flags & IW_AUTH_INDEX) {
+ 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_WPA_VERSION:
+ switch (wpa) {
+ case 1:
+ param->value = IW_AUTH_WPA_VERSION_WPA;
+ break;
+ case 2:
+ param->value = IW_AUTH_WPA_VERSION_WPA2;
+ break;
+ case 0:
+ default:
+ param->value = IW_AUTH_WPA_VERSION_DISABLED;
+ break;
+ }
+ break;
+
+ case IW_AUTH_DROP_UNENCRYPTED:
+ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+ if (ret >= 0)
+ param->value = r.u > 0 ? 1 : 0;
+ break;
+
+ case IW_AUTH_80211_AUTH_ALG:
+ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+ if (ret >= 0) {
+ switch (r.u) {
+ case DOT11_AUTH_OS:
+ param->value = IW_AUTH_ALG_OPEN_SYSTEM;
+ break;
+ case DOT11_AUTH_BOTH:
+ case DOT11_AUTH_SK:
+ param->value = IW_AUTH_ALG_SHARED_KEY;
+ case DOT11_AUTH_NONE:
+ default:
+ param->value = 0;
+ break;
+ }
+ }
+ break;
+
+ case IW_AUTH_WPA_ENABLED:
+ param->value = wpa > 0 ? 1 : 0;
+ break;
+
+ case IW_AUTH_RX_UNENCRYPTED_EAPOL:
+ ret = mgt_get_request(priv, DOT11_OID_DOT1XENABLE, 0, NULL, &r);
+ if (ret >= 0)
+ param->value = r.u > 0 ? 1 : 0;
+ break;
+
+ case IW_AUTH_PRIVACY_INVOKED:
+ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+ if (ret >= 0)
+ param->value = r.u > 0 ? 1 : 0;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+ return ret;
+}
+
+static int prism54_set_encodeext(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_point *encoding = &wrqu->encoding;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int idx, alg = ext->alg, set_key = 1;
+ union oid_res_t r;
+ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
+ int ret = 0;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* Determine and validate the key index */
+ idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+ if (idx) {
+ if (idx < 0 || idx > 3)
+ return -EINVAL;
+ } else {
+ ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+ if (ret < 0)
+ goto out;
+ idx = r.u;
+ }
+
+ if (encoding->flags & IW_ENCODE_DISABLED)
+ alg = IW_ENCODE_ALG_NONE;
+
+ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
+ /* Only set transmit key index here, actual
+ * key is set below if needed.
+ */
+ ret = mgt_set_request(priv, DOT11_OID_DEFKEYID, 0, &idx);
+ set_key = ext->key_len > 0 ? 1 : 0;
+ }
+
+ if (set_key) {
+ struct obj_key key = { DOT11_PRIV_WEP, 0, "" };
+ switch (alg) {
+ case IW_ENCODE_ALG_NONE:
+ break;
+ case IW_ENCODE_ALG_WEP:
+ if (ext->key_len > KEY_SIZE_WEP104) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (ext->key_len > KEY_SIZE_WEP40)
+ key.length = KEY_SIZE_WEP104;
+ else
+ key.length = KEY_SIZE_WEP40;
+ break;
+ case IW_ENCODE_ALG_TKIP:
+ if (ext->key_len > KEY_SIZE_TKIP) {
+ ret = -EINVAL;
+ goto out;
+ }
+ key.type = DOT11_PRIV_TKIP;
+ key.length = KEY_SIZE_TKIP;
+ default:
+ return -EINVAL;
+ }
+
+ if (key.length) {
+ memset(key.key, 0, sizeof(key.key));
+ memcpy(key.key, ext->key, ext->key_len);
+ ret = mgt_set_request(priv, DOT11_OID_DEFKEYX, idx,
+ &key);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
+ /* Read the flags */
+ if (encoding->flags & IW_ENCODE_DISABLED) {
+ /* Encoding disabled,
+ * authen = DOT11_AUTH_OS;
+ * invoke = 0;
+ * exunencrypt = 0; */
+ }
+ if (encoding->flags & IW_ENCODE_OPEN) {
+ /* Encode but accept non-encoded packets. No auth */
+ invoke = 1;
+ }
+ if (encoding->flags & IW_ENCODE_RESTRICTED) {
+ /* Refuse non-encoded packets. Auth */
+ authen = DOT11_AUTH_BOTH;
+ invoke = 1;
+ exunencrypt = 1;
+ }
+
+ /* do the change if requested */
+ if (encoding->flags & IW_ENCODE_MODE) {
+ ret = mgt_set_request(priv, DOT11_OID_AUTHENABLE, 0,
+ &authen);
+ ret = mgt_set_request(priv, DOT11_OID_PRIVACYINVOKED, 0,
+ &invoke);
+ ret = mgt_set_request(priv, DOT11_OID_EXUNENCRYPTED, 0,
+ &exunencrypt);
+ }
+
+out:
+ return ret;
+}
+
+
+static int prism54_get_encodeext(struct net_device *ndev,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu,
+ char *extra)
+{
+ islpci_private *priv = netdev_priv(ndev);
+ struct iw_point *encoding = &wrqu->encoding;
+ struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
+ int idx, max_key_len;
+ union oid_res_t r;
+ int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0, wpa = 0;
+ int ret = 0;
+
+ if (islpci_get_state(priv) < PRV_STATE_INIT)
+ return 0;
+
+ /* first get the flags */
+ ret = mgt_get_request(priv, DOT11_OID_AUTHENABLE, 0, NULL, &r);
+ authen = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_PRIVACYINVOKED, 0, NULL, &r);
+ invoke = r.u;
+ ret = mgt_get_request(priv, DOT11_OID_EXUNENCRYPTED, 0, NULL, &r);
+ exunencrypt = r.u;
+ if (ret < 0)
+ goto out;
+
+ max_key_len = encoding->length - sizeof(*ext);
+ if (max_key_len < 0)
+ return -EINVAL;
+
+ idx = (encoding->flags & IW_ENCODE_INDEX) - 1;
+ if (idx) {
+ if (idx < 0 || idx > 3)
+ return -EINVAL;
+ } else {
+ ret = mgt_get_request(priv, DOT11_OID_DEFKEYID, 0, NULL, &r);
+ if (ret < 0)
+ goto out;
+ idx = r.u;
+ }
+
+ encoding->flags = idx + 1;
+ memset(ext, 0, sizeof(*ext));
+
+ switch (authen) {
+ case DOT11_AUTH_BOTH:
+ case DOT11_AUTH_SK:
+ wrqu->encoding.flags |= IW_ENCODE_RESTRICTED;
+ case DOT11_AUTH_OS:
+ default:
+ wrqu->encoding.flags |= IW_ENCODE_OPEN;
+ break;
+ }
+
+ down_write(&priv->mib_sem);
+ wpa = priv->wpa;
+ up_write(&priv->mib_sem);
+
+ if (authen == DOT11_AUTH_OS && !exunencrypt && !invoke && !wpa) {
+ /* No encryption */
+ ext->alg = IW_ENCODE_ALG_NONE;
+ ext->key_len = 0;
+ wrqu->encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ struct obj_key *key;
+
+ ret = mgt_get_request(priv, DOT11_OID_DEFKEYX, idx, NULL, &r);
+ if (ret < 0)
+ goto out;
+ key = r.ptr;
+ if (max_key_len < key->length) {
+ ret = -E2BIG;
+ goto out;
+ }
+ memcpy(ext->key, key->key, key->length);
+ ext->key_len = key->length;
+
+ switch (key->type) {
+ case DOT11_PRIV_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ default:
+ case DOT11_PRIV_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ }
+ wrqu->encoding.flags |= IW_ENCODE_ENABLED;
+ }
+
+out:
+ return ret;
+}
+
+
static int
prism54_reset(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
@@ -1591,8 +2111,8 @@ static u8 wpa_oid[4] = { 0x00, 0x50, 0xf2, 1 };
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
static void
-prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
- u8 *wpa_ie, size_t wpa_ie_len)
+prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid,
+ u8 *wpa_ie, size_t wpa_ie_len)
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
@@ -1658,7 +2178,7 @@ prism54_wpa_ie_add(islpci_private *priv, u8 *bssid,
}
static size_t
-prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
+prism54_wpa_bss_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
{
struct list_head *ptr;
struct islpci_bss_wpa_ie *bss = NULL;
@@ -1683,14 +2203,14 @@ prism54_wpa_ie_get(islpci_private *priv, u8 *bssid, u8 *wpa_ie)
}
void
-prism54_wpa_ie_init(islpci_private *priv)
+prism54_wpa_bss_ie_init(islpci_private *priv)
{
INIT_LIST_HEAD(&priv->bss_wpa_list);
sema_init(&priv->wpa_sem, 1);
}
void
-prism54_wpa_ie_clean(islpci_private *priv)
+prism54_wpa_bss_ie_clean(islpci_private *priv)
{
struct list_head *ptr, *n;
@@ -1722,7 +2242,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr,
}
if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 &&
memcmp(pos + 2, wpa_oid, 4) == 0) {
- prism54_wpa_ie_add(priv, addr, pos, pos[1] + 2);
+ prism54_wpa_bss_ie_add(priv, addr, pos, pos[1] + 2);
return;
}
pos += 2 + pos[1];
@@ -1879,7 +2399,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
send_formatted_event(priv, "Associate request (ex)", mlme, 1);
if (priv->iw_mode != IW_MODE_MASTER
- && mlmeex->state != DOT11_STATE_AUTHING)
+ && mlmeex->state != DOT11_STATE_ASSOCING)
break;
confirm = kmalloc(sizeof(struct obj_mlmeex), GFP_ATOMIC);
@@ -1893,7 +2413,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
confirm->state = 0; /* not used */
confirm->code = 0;
- wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+ wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
printk(KERN_DEBUG "No WPA IE found from "
@@ -1937,7 +2457,7 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid,
confirm->state = 0; /* not used */
confirm->code = 0;
- wpa_ie_len = prism54_wpa_ie_get(priv, mlmeex->address, wpa_ie);
+ wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie);
if (!wpa_ie_len) {
printk(KERN_DEBUG "No WPA IE found from "
@@ -2553,6 +3073,15 @@ static const iw_handler prism54_handler[] = {
(iw_handler) prism54_get_encode, /* SIOCGIWENCODE */
(iw_handler) NULL, /* SIOCSIWPOWER */
(iw_handler) NULL, /* SIOCGIWPOWER */
+ NULL, /* -- hole -- */
+ NULL, /* -- hole -- */
+ (iw_handler) prism54_set_genie, /* SIOCSIWGENIE */
+ (iw_handler) prism54_get_genie, /* SIOCGIWGENIE */
+ (iw_handler) prism54_set_auth, /* SIOCSIWAUTH */
+ (iw_handler) prism54_get_auth, /* SIOCGIWAUTH */
+ (iw_handler) prism54_set_encodeext, /* SIOCSIWENCODEEXT */
+ (iw_handler) prism54_get_encodeext, /* SIOCGIWENCODEEXT */
+ NULL, /* SIOCSIWPMKSA */
};
/* The low order bit identify a SET (0) or a GET (1) ioctl. */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.h b/drivers/net/wireless/prism54/isl_ioctl.h
index 46d5cde80c8..65f33acd0a4 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.h
+++ b/drivers/net/wireless/prism54/isl_ioctl.h
@@ -27,7 +27,7 @@
#include <net/iw_handler.h> /* New driver API */
-#define SUPPORTED_WIRELESS_EXT 16
+#define SUPPORTED_WIRELESS_EXT 19
void prism54_mib_init(islpci_private *);
@@ -39,8 +39,8 @@ void prism54_acl_clean(struct islpci_acl *);
void prism54_process_trap(void *);
-void prism54_wpa_ie_init(islpci_private *priv);
-void prism54_wpa_ie_clean(islpci_private *priv);
+void prism54_wpa_bss_ie_init(islpci_private *priv);
+void prism54_wpa_bss_ie_clean(islpci_private *priv);
int prism54_set_mac_address(struct net_device *, void *);
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index 5ddf2959903..ab3c5a27efd 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -715,7 +715,7 @@ islpci_alloc_memory(islpci_private *priv)
}
prism54_acl_init(&priv->acl);
- prism54_wpa_ie_init(priv);
+ prism54_wpa_bss_ie_init(priv);
if (mgt_init(priv))
goto out_free;
@@ -774,7 +774,7 @@ islpci_free_memory(islpci_private *priv)
/* Free the acces control list and the WPA list */
prism54_acl_clean(&priv->acl);
- prism54_wpa_ie_clean(priv);
+ prism54_wpa_bss_ie_clean(priv);
mgt_clean(priv);
return 0;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 07053165e4c..5049f37455b 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -179,6 +179,8 @@ typedef struct {
struct list_head bss_wpa_list;
int num_bss_wpa;
struct semaphore wpa_sem;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
struct work_struct reset_task;
int reset_task_pending;
diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c
index bfa0cc319a0..f692dccf0d0 100644
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -189,7 +189,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* request for the interrupt before uploading the firmware */
rvalue = request_irq(pdev->irq, &islpci_interrupt,
- SA_SHIRQ, ndev->name, priv);
+ IRQF_SHARED, ndev->name, priv);
if (rvalue) {
/* error, could not hook the handler to the irq */
@@ -313,7 +313,7 @@ prism54_module_init(void)
__bug_on_wrong_struct_sizes ();
- return pci_module_init(&prism54_driver);
+ return pci_register_driver(&prism54_driver);
}
/* by the time prism54_module_exit() terminates, as a postcondition
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index 6a60c5970cb..2e061a80b29 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -18,7 +18,6 @@
*
*/
-#include <linux/config.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/net/wireless/prism54/prismcompat.h b/drivers/net/wireless/prism54/prismcompat.h
index 55541c01752..d71eca55a30 100644
--- a/drivers/net/wireless/prism54/prismcompat.h
+++ b/drivers/net/wireless/prism54/prismcompat.h
@@ -29,7 +29,6 @@
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/config.h>
#include <linux/moduleparam.h>
#include <linux/workqueue.h>
#include <linux/compiler.h>
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index a915fe6c6aa..e82548ea609 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -30,7 +30,6 @@
*
=============================================================================*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
@@ -53,8 +52,8 @@
#include <pcmcia/ds.h>
#include <pcmcia/mem_op.h>
-#include <net/ieee80211.h>
#include <linux/wireless.h>
+#include <net/iw_handler.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -100,7 +99,7 @@ static int ray_dev_config(struct net_device *dev, struct ifmap *map);
static struct net_device_stats *ray_get_stats(struct net_device *dev);
static int ray_dev_init(struct net_device *dev);
-static struct ethtool_ops netdev_ethtool_ops;
+static const struct ethtool_ops netdev_ethtool_ops;
static int ray_open(struct net_device *dev);
static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
@@ -1093,7 +1092,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
strcpy(info->driver, "ray_cs");
}
-static struct ethtool_ops netdev_ethtool_ops = {
+static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
};
@@ -1174,7 +1173,7 @@ static int ray_set_essid(struct net_device *dev,
return -EOPNOTSUPP;
} else {
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ if(dwrq->length > IW_ESSID_MAX_SIZE) {
return -E2BIG;
}
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c
index 7f9aa139c34..bcc7038130f 100644
--- a/drivers/net/wireless/spectrum_cs.c
+++ b/drivers/net/wireless/spectrum_cs.c
@@ -21,7 +21,6 @@
#define DRIVER_NAME "spectrum_cs"
#define PFX DRIVER_NAME ": "
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -35,8 +34,6 @@
#include "orinoco.h"
-static unsigned char *primsym;
-static unsigned char *secsym;
static const char primary_fw_name[] = "symbol_sp24t_prim_fw";
static const char secondary_fw_name[] = "symbol_sp24t_sec_fw";
@@ -245,7 +242,7 @@ spectrum_reset(struct pcmcia_device *link, int idle)
u_int save_cor;
/* Doing it if hardware is gone is guaranteed crash */
- if (pcmcia_dev_present(link))
+ if (!pcmcia_dev_present(link))
return -ENODEV;
/* Save original COR value */
@@ -441,7 +438,7 @@ spectrum_load_blocks(hermes_t *hw, const struct dblock *first_block)
*/
static int
spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
- const unsigned char *image)
+ const unsigned char *image, int secondary)
{
int ret;
const unsigned char *ptr;
@@ -456,7 +453,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
first_block = (const struct dblock *) ptr;
/* Read the PDA */
- if (image != primsym) {
+ if (secondary) {
ret = spectrum_read_pda(hw, pda, sizeof(pda));
if (ret)
return ret;
@@ -473,7 +470,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
return ret;
/* Write the PDA to the adapter */
- if (image != primsym) {
+ if (secondary) {
ret = spectrum_apply_pda(hw, first_block, pda);
if (ret)
return ret;
@@ -488,7 +485,7 @@ spectrum_dl_image(hermes_t *hw, struct pcmcia_device *link,
ret = hermes_init(hw);
/* hermes_reset() should return 0 with the secondary firmware */
- if (image != primsym && ret != 0)
+ if (secondary && ret != 0)
return -ENODEV;
/* And this should work with any firmware */
@@ -510,33 +507,30 @@ spectrum_dl_firmware(hermes_t *hw, struct pcmcia_device *link)
const struct firmware *fw_entry;
if (request_firmware(&fw_entry, primary_fw_name,
- &handle_to_dev(link)) == 0) {
- primsym = fw_entry->data;
- } else {
+ &handle_to_dev(link)) != 0) {
printk(KERN_ERR PFX "Cannot find firmware: %s\n",
primary_fw_name);
return -ENOENT;
}
- if (request_firmware(&fw_entry, secondary_fw_name,
- &handle_to_dev(link)) == 0) {
- secsym = fw_entry->data;
- } else {
- printk(KERN_ERR PFX "Cannot find firmware: %s\n",
- secondary_fw_name);
- return -ENOENT;
- }
-
/* Load primary firmware */
- ret = spectrum_dl_image(hw, link, primsym);
+ ret = spectrum_dl_image(hw, link, fw_entry->data, 0);
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR PFX "Primary firmware download failed\n");
return ret;
}
- /* Load secondary firmware */
- ret = spectrum_dl_image(hw, link, secsym);
+ if (request_firmware(&fw_entry, secondary_fw_name,
+ &handle_to_dev(link)) != 0) {
+ printk(KERN_ERR PFX "Cannot find firmware: %s\n",
+ secondary_fw_name);
+ return -ENOENT;
+ }
+ /* Load secondary firmware */
+ ret = spectrum_dl_image(hw, link, fw_entry->data, 1);
+ release_firmware(fw_entry);
if (ret) {
printk(KERN_ERR PFX "Secondary firmware download failed\n");
}
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index 18a44580b53..337c692f6fd 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -81,7 +81,6 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE";
/************************************************************************/
/* Header files */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -468,6 +467,7 @@ static int arp_query(unsigned char *haddr, u32 paddr,
struct net_device *dev)
{
struct neighbour *neighbor_entry;
+ int ret = 0;
neighbor_entry = neigh_lookup(&arp_tbl, &paddr, dev);
@@ -475,10 +475,11 @@ static int arp_query(unsigned char *haddr, u32 paddr,
neighbor_entry->used = jiffies;
if (neighbor_entry->nud_state & NUD_VALID) {
memcpy(haddr, neighbor_entry->ha, dev->addr_len);
- return 1;
+ ret = 1;
}
+ neigh_release(neighbor_entry);
}
- return 0;
+ return ret;
}
static void DumpData(char *msg, struct strip *strip_info, __u8 * ptr,
@@ -1341,7 +1342,7 @@ static unsigned char *strip_make_packet(unsigned char *buffer,
* 'broadcast hub' radio (First byte of address being 0xFF means broadcast)
*/
if (haddr.c[0] == 0xFF) {
- u32 brd = 0;
+ __be32 brd = 0;
struct in_device *in_dev;
rcu_read_lock();
@@ -1405,7 +1406,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0;
int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0
&& !doreset;
- u32 addr, brd;
+ __be32 addr, brd;
/*
* 1. If we have a packet, encapsulate it and put it in the buffer
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 561250f73fd..0065f057bb1 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -1837,7 +1837,7 @@ static void wl_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
strncpy(info->driver, "wavelan_cs", sizeof(info->driver)-1);
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = wl_get_drvinfo
};
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index c65fe7a391e..f34a36b0c7b 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -411,7 +411,6 @@
/***************************** INCLUDES *****************************/
/* Linux headers that we need */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e52a650f673..e3ae5f60d5b 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -28,7 +28,6 @@
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/ethtool.h>
@@ -1465,7 +1464,7 @@ static void wl3501_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
strlcpy(info->driver, wl3501_dev_info, sizeof(info->driver));
}
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
.get_drvinfo = wl3501_get_drvinfo
};
@@ -1803,15 +1802,15 @@ static int wl3501_get_retry(struct net_device *dev,
&retry, sizeof(retry));
if (rc)
goto out;
- if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
goto set_value;
}
rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
&retry, sizeof(retry));
if (rc)
goto out;
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
set_value:
wrqu->retry.value = retry;
wrqu->retry.disabled = 0;
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index 662ecc8a33f..80af9a9fcbb 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -119,7 +119,7 @@ static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
switch(urb->status) {
case -EILSEQ:
case -ENODEV:
- case -ETIMEDOUT:
+ case -ETIME:
case -ENOENT:
case -EPIPE:
case -EOVERFLOW:
@@ -201,7 +201,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
switch(urb->status) {
case -EILSEQ:
case -ENODEV:
- case -ETIMEDOUT:
+ case -ETIME:
case -ENOENT:
case -EPIPE:
case -EOVERFLOW:
@@ -1218,7 +1218,7 @@ static int zd1201_set_essid(struct net_device *dev,
return -EINVAL;
if (data->length < 1)
data->length = 1;
- zd->essidlen = data->length-1;
+ zd->essidlen = data->length;
memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
memcpy(zd->essid, essid, data->length);
return zd1201_join(zd, zd->essid, zd->essidlen);
@@ -1820,6 +1820,8 @@ static int zd1201_probe(struct usb_interface *interface,
zd->dev->name);
usb_set_intfdata(interface, zd);
+ zd1201_enable(zd); /* zd1201 likes to startup enabled, */
+ zd1201_disable(zd); /* interfering with all the wifis in range */
return 0;
err_net:
diff --git a/drivers/net/wireless/zd1211rw/Kconfig b/drivers/net/wireless/zd1211rw/Kconfig
new file mode 100644
index 00000000000..66ed55bc546
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/Kconfig
@@ -0,0 +1,19 @@
+config ZD1211RW
+ tristate "ZyDAS ZD1211/ZD1211B USB-wireless support"
+ depends on USB && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL
+ select FW_LOADER
+ ---help---
+ This is an experimental driver for the ZyDAS ZD1211/ZD1211B wireless
+ chip, present in many USB-wireless adapters.
+
+ Device firmware is required alongside this driver. You can download the
+ firmware distribution from http://zd1211.ath.cx/get-firmware
+
+config ZD1211RW_DEBUG
+ bool "ZyDAS ZD1211 debugging"
+ depends on ZD1211RW
+ ---help---
+ ZD1211 debugging messages. Choosing Y will result in additional debug
+ messages being saved to your kernel logs, which may help debug any
+ problems.
+
diff --git a/drivers/net/wireless/zd1211rw/Makefile b/drivers/net/wireless/zd1211rw/Makefile
new file mode 100644
index 00000000000..6603ad5be63
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/Makefile
@@ -0,0 +1,12 @@
+obj-$(CONFIG_ZD1211RW) += zd1211rw.o
+
+zd1211rw-objs := zd_chip.o zd_ieee80211.o \
+ zd_mac.o zd_netdev.o \
+ zd_rf_al2230.o zd_rf_rf2959.o \
+ zd_rf_al7230b.o \
+ zd_rf.o zd_usb.o zd_util.o
+
+ifeq ($(CONFIG_ZD1211RW_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
new file mode 100644
index 00000000000..aa661b2b76c
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -0,0 +1,1655 @@
+/* zd_chip.c
+ *
+ * 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
+ */
+
+/* This file implements all the hardware specific functions for the ZD1211
+ * and ZD1211B chips. Support for the ZD1211B was possible after Timothy
+ * Legge sent me a ZD1211B device. Thank you Tim. -- Uli
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+void zd_chip_init(struct zd_chip *chip,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ memset(chip, 0, sizeof(*chip));
+ mutex_init(&chip->mutex);
+ zd_usb_init(&chip->usb, netdev, intf);
+ zd_rf_init(&chip->rf);
+}
+
+void zd_chip_clear(struct zd_chip *chip)
+{
+ ZD_ASSERT(!mutex_is_locked(&chip->mutex));
+ zd_usb_clear(&chip->usb);
+ zd_rf_clear(&chip->rf);
+ mutex_destroy(&chip->mutex);
+ ZD_MEMCLEAR(chip, sizeof(*chip));
+}
+
+static int scnprint_mac_oui(const u8 *addr, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%02x-%02x-%02x",
+ addr[0], addr[1], addr[2]);
+}
+
+/* Prints an identifier line, which will support debugging. */
+static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size)
+{
+ int i = 0;
+
+ i = scnprintf(buffer, size, "zd1211%s chip ",
+ chip->is_zd1211b ? "b" : "");
+ i += zd_usb_scnprint_id(&chip->usb, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " ");
+ i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i);
+ i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type,
+ chip->patch_cck_gain ? 'g' : '-',
+ chip->patch_cr157 ? '7' : '-',
+ chip->patch_6m_band_edge ? '6' : '-',
+ chip->new_phy_layout ? 'N' : '-');
+ return i;
+}
+
+static void print_id(struct zd_chip *chip)
+{
+ char buffer[80];
+
+ scnprint_id(chip, buffer, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ dev_info(zd_chip_dev(chip), "%s\n", buffer);
+}
+
+/* Read a variable number of 32-bit values. Parameter count is not allowed to
+ * exceed USB_MAX_IOREAD32_COUNT.
+ */
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr,
+ unsigned int count)
+{
+ int r;
+ int i;
+ zd_addr_t *a16 = (zd_addr_t *)NULL;
+ u16 *v16;
+ unsigned int count16;
+
+ if (count > USB_MAX_IOREAD32_COUNT)
+ return -EINVAL;
+
+ /* Allocate a single memory block for values and addresses. */
+ count16 = 2*count;
+ a16 = (zd_addr_t *)kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)),
+ GFP_NOFS);
+ if (!a16) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error ENOMEM in allocation of a16\n");
+ r = -ENOMEM;
+ goto out;
+ }
+ v16 = (u16 *)(a16 + count16);
+
+ for (i = 0; i < count; i++) {
+ int j = 2*i;
+ /* We read the high word always first. */
+ a16[j] = zd_inc_word(addr[i]);
+ a16[j+1] = addr[i];
+ }
+
+ r = zd_ioread16v_locked(chip, v16, a16, count16);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error: zd_ioread16v_locked. Error number %d\n", r);
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ int j = 2*i;
+ values[i] = (v16[j] << 16) | v16[j+1];
+ }
+
+out:
+ kfree((void *)a16);
+ return r;
+}
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count)
+{
+ int i, j, r;
+ struct zd_ioreq16 *ioreqs16;
+ unsigned int count16;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+
+ if (count == 0)
+ return 0;
+ if (count > USB_MAX_IOWRITE32_COUNT)
+ return -EINVAL;
+
+ /* Allocate a single memory block for values and addresses. */
+ count16 = 2*count;
+ ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS);
+ if (!ioreqs16) {
+ r = -ENOMEM;
+ dev_dbg_f(zd_chip_dev(chip),
+ "error %d in ioreqs16 allocation\n", r);
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ j = 2*i;
+ /* We write the high word always first. */
+ ioreqs16[j].value = ioreqs[i].value >> 16;
+ ioreqs16[j].addr = zd_inc_word(ioreqs[i].addr);
+ ioreqs16[j+1].value = ioreqs[i].value;
+ ioreqs16[j+1].addr = ioreqs[i].addr;
+ }
+
+ r = zd_usb_iowrite16v(&chip->usb, ioreqs16, count16);
+#ifdef DEBUG
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error %d in zd_usb_write16v\n", r);
+ }
+#endif /* DEBUG */
+out:
+ kfree(ioreqs16);
+ return r;
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+ const struct zd_ioreq16 *ioreqs, unsigned int count)
+{
+ int r;
+ unsigned int i, j, t, max;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ for (i = 0; i < count; i += j + t) {
+ t = 0;
+ max = count-i;
+ if (max > USB_MAX_IOWRITE16_COUNT)
+ max = USB_MAX_IOWRITE16_COUNT;
+ for (j = 0; j < max; j++) {
+ if (!ioreqs[i+j].addr) {
+ t = 1;
+ break;
+ }
+ }
+
+ r = zd_usb_iowrite16v(&chip->usb, &ioreqs[i], j);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error zd_usb_iowrite16v. Error number %d\n",
+ r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+/* Writes a variable number of 32 bit registers. The functions will split
+ * that in several USB requests. A split can be forced by inserting an IO
+ * request with an zero address field.
+ */
+int zd_iowrite32a_locked(struct zd_chip *chip,
+ const struct zd_ioreq32 *ioreqs, unsigned int count)
+{
+ int r;
+ unsigned int i, j, t, max;
+
+ for (i = 0; i < count; i += j + t) {
+ t = 0;
+ max = count-i;
+ if (max > USB_MAX_IOWRITE32_COUNT)
+ max = USB_MAX_IOWRITE32_COUNT;
+ for (j = 0; j < max; j++) {
+ if (!ioreqs[i+j].addr) {
+ t = 1;
+ break;
+ }
+ }
+
+ r = _zd_iowrite32v_locked(chip, &ioreqs[i], j);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error _zd_iowrite32v_locked."
+ " Error number %d\n", r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite16_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, value, addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+ u32 *values, unsigned int count)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32v_locked(chip, values, addresses, count);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, ioreqs, count);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int read_pod(struct zd_chip *chip, u8 *rf_type)
+{
+ int r;
+ u32 value;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &value, E2P_POD);
+ if (r)
+ goto error;
+ dev_dbg_f(zd_chip_dev(chip), "E2P_POD %#010x\n", value);
+
+ /* FIXME: AL2230 handling (Bit 7 in POD) */
+ *rf_type = value & 0x0f;
+ chip->pa_type = (value >> 16) & 0x0f;
+ chip->patch_cck_gain = (value >> 8) & 0x1;
+ chip->patch_cr157 = (value >> 13) & 0x1;
+ chip->patch_6m_band_edge = (value >> 21) & 0x1;
+ chip->new_phy_layout = (value >> 31) & 0x1;
+ chip->link_led = ((value >> 4) & 1) ? LED1 : LED2;
+ chip->supports_tx_led = 1;
+ if (value & (1 << 24)) { /* LED scenario */
+ if (value & (1 << 29))
+ chip->supports_tx_led = 0;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
+ "patch 6M %d new PHY %d link LED%d tx led %d\n",
+ zd_rf_name(*rf_type), *rf_type,
+ chip->pa_type, chip->patch_cck_gain,
+ chip->patch_cr157, chip->patch_6m_band_edge,
+ chip->new_phy_layout,
+ chip->link_led == LED1 ? 1 : 2,
+ chip->supports_tx_led);
+ return 0;
+error:
+ *rf_type = 0;
+ chip->pa_type = 0;
+ chip->patch_cck_gain = 0;
+ chip->patch_cr157 = 0;
+ chip->patch_6m_band_edge = 0;
+ chip->new_phy_layout = 0;
+ return r;
+}
+
+static int _read_mac_addr(struct zd_chip *chip, u8 *mac_addr,
+ const zd_addr_t *addr)
+{
+ int r;
+ u32 parts[2];
+
+ r = zd_ioread32v_locked(chip, parts, (const zd_addr_t *)addr, 2);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error: couldn't read e2p macs. Error number %d\n", r);
+ return r;
+ }
+
+ mac_addr[0] = parts[0];
+ mac_addr[1] = parts[0] >> 8;
+ mac_addr[2] = parts[0] >> 16;
+ mac_addr[3] = parts[0] >> 24;
+ mac_addr[4] = parts[1];
+ mac_addr[5] = parts[1] >> 8;
+
+ return 0;
+}
+
+static int read_e2p_mac_addr(struct zd_chip *chip)
+{
+ static const zd_addr_t addr[2] = { E2P_MAC_ADDR_P1, E2P_MAC_ADDR_P2 };
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return _read_mac_addr(chip, chip->e2p_mac, (const zd_addr_t *)addr);
+}
+
+/* MAC address: if custom mac addresses are to to be used CR_MAC_ADDR_P1 and
+ * CR_MAC_ADDR_P2 must be overwritten
+ */
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ mutex_lock(&chip->mutex);
+ memcpy(mac_addr, chip->e2p_mac, ETH_ALEN);
+ mutex_unlock(&chip->mutex);
+}
+
+static int read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ static const zd_addr_t addr[2] = { CR_MAC_ADDR_P1, CR_MAC_ADDR_P2 };
+ return _read_mac_addr(chip, mac_addr, (const zd_addr_t *)addr);
+}
+
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr)
+{
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ mutex_lock(&chip->mutex);
+ r = read_mac_addr(chip, mac_addr);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr)
+{
+ int r;
+ struct zd_ioreq32 reqs[2] = {
+ [0] = { .addr = CR_MAC_ADDR_P1 },
+ [1] = { .addr = CR_MAC_ADDR_P2 },
+ };
+
+ reqs[0].value = (mac_addr[3] << 24)
+ | (mac_addr[2] << 16)
+ | (mac_addr[1] << 8)
+ | mac_addr[0];
+ reqs[1].value = (mac_addr[5] << 8)
+ | mac_addr[4];
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "mac addr " MAC_FMT "\n", MAC_ARG(mac_addr));
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+#ifdef DEBUG
+ {
+ u8 tmp[ETH_ALEN];
+ read_mac_addr(chip, tmp);
+ }
+#endif /* DEBUG */
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain)
+{
+ int r;
+ u32 value;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread32_locked(chip, &value, E2P_SUBID);
+ mutex_unlock(&chip->mutex);
+ if (r)
+ return r;
+
+ *regdomain = value >> 16;
+ dev_dbg_f(zd_chip_dev(chip), "regdomain: %#04x\n", *regdomain);
+
+ return 0;
+}
+
+static int read_values(struct zd_chip *chip, u8 *values, size_t count,
+ zd_addr_t e2p_addr, u32 guard)
+{
+ int r;
+ int i;
+ u32 v;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ for (i = 0;;) {
+ r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+ if (r)
+ return r;
+ v -= guard;
+ if (i+4 < count) {
+ values[i++] = v;
+ values[i++] = v >> 8;
+ values[i++] = v >> 16;
+ values[i++] = v >> 24;
+ continue;
+ }
+ for (;i < count; i++)
+ values[i] = v >> (8*(i%3));
+ return 0;
+ }
+}
+
+static int read_pwr_cal_values(struct zd_chip *chip)
+{
+ return read_values(chip, chip->pwr_cal_values,
+ E2P_CHANNEL_COUNT, E2P_PWR_CAL_VALUE1,
+ 0);
+}
+
+static int read_pwr_int_values(struct zd_chip *chip)
+{
+ return read_values(chip, chip->pwr_int_values,
+ E2P_CHANNEL_COUNT, E2P_PWR_INT_VALUE1,
+ E2P_PWR_INT_GUARD);
+}
+
+static int read_ofdm_cal_values(struct zd_chip *chip)
+{
+ int r;
+ int i;
+ static const zd_addr_t addresses[] = {
+ E2P_36M_CAL_VALUE1,
+ E2P_48M_CAL_VALUE1,
+ E2P_54M_CAL_VALUE1,
+ };
+
+ for (i = 0; i < 3; i++) {
+ r = read_values(chip, chip->ofdm_cal_values[i],
+ E2P_CHANNEL_COUNT, addresses[i], 0);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int read_cal_int_tables(struct zd_chip *chip)
+{
+ int r;
+
+ r = read_pwr_cal_values(chip);
+ if (r)
+ return r;
+ r = read_pwr_int_values(chip);
+ if (r)
+ return r;
+ r = read_ofdm_cal_values(chip);
+ if (r)
+ return r;
+ return 0;
+}
+
+/* phy means physical registers */
+int zd_chip_lock_phy_regs(struct zd_chip *chip)
+{
+ int r;
+ u32 tmp;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+ if (r) {
+ dev_err(zd_chip_dev(chip), "error ioread32(CR_REG1): %d\n", r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp & ~UNLOCK_PHY_REGS);
+ tmp &= ~UNLOCK_PHY_REGS;
+
+ r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+ if (r)
+ dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+ return r;
+}
+
+int zd_chip_unlock_phy_regs(struct zd_chip *chip)
+{
+ int r;
+ u32 tmp;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &tmp, CR_REG1);
+ if (r) {
+ dev_err(zd_chip_dev(chip),
+ "error ioread32(CR_REG1): %d\n", r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "CR_REG1: 0x%02x -> 0x%02x\n", tmp, tmp | UNLOCK_PHY_REGS);
+ tmp |= UNLOCK_PHY_REGS;
+
+ r = zd_iowrite32_locked(chip, tmp, CR_REG1);
+ if (r)
+ dev_err(zd_chip_dev(chip), "error iowrite32(CR_REG1): %d\n", r);
+ return r;
+}
+
+/* CR157 can be optionally patched by the EEPROM */
+static int patch_cr157(struct zd_chip *chip)
+{
+ int r;
+ u32 value;
+
+ if (!chip->patch_cr157)
+ return 0;
+
+ r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+ if (r)
+ return r;
+
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value >> 8);
+ return zd_iowrite32_locked(chip, value >> 8, CR157);
+}
+
+/*
+ * 6M band edge can be optionally overwritten for certain RF's
+ * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge
+ * bit (for AL2230, AL2230S)
+ */
+static int patch_6m_band_edge(struct zd_chip *chip, int channel)
+{
+ struct zd_ioreq16 ioreqs[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR47, 0x1e },
+ };
+
+ if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge)
+ return 0;
+
+ /* FIXME: Channel 11 is not the edge for all regulatory domains. */
+ if (channel == 1 || channel == 11)
+ ioreqs[0].value = 0x12;
+
+ dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel);
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211_hw_reset_phy(struct zd_chip *chip)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR0, 0x0a }, { CR1, 0x06 }, { CR2, 0x26 },
+ { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xa0 },
+ { CR10, 0x81 }, { CR11, 0x00 }, { CR12, 0x7f },
+ { CR13, 0x8c }, { CR14, 0x80 }, { CR15, 0x3d },
+ { CR16, 0x20 }, { CR17, 0x1e }, { CR18, 0x0a },
+ { CR19, 0x48 }, { CR20, 0x0c }, { CR21, 0x0c },
+ { CR22, 0x23 }, { CR23, 0x90 }, { CR24, 0x14 },
+ { CR25, 0x40 }, { CR26, 0x10 }, { CR27, 0x19 },
+ { CR28, 0x7f }, { CR29, 0x80 }, { CR30, 0x4b },
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+ { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
+ { CR43, 0x10 }, { CR44, 0x12 }, { CR46, 0xff },
+ { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
+ { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
+ { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
+ { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
+ { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
+ { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
+ { CR79, 0x68 }, { CR80, 0x64 }, { CR81, 0x64 },
+ { CR82, 0x00 }, { CR83, 0x00 }, { CR84, 0x00 },
+ { CR85, 0x02 }, { CR86, 0x00 }, { CR87, 0x00 },
+ { CR88, 0xff }, { CR89, 0xfc }, { CR90, 0x00 },
+ { CR91, 0x00 }, { CR92, 0x00 }, { CR93, 0x08 },
+ { CR94, 0x00 }, { CR95, 0x00 }, { CR96, 0xff },
+ { CR97, 0xe7 }, { CR98, 0x00 }, { CR99, 0x00 },
+ { CR100, 0x00 }, { CR101, 0xae }, { CR102, 0x02 },
+ { CR103, 0x00 }, { CR104, 0x03 }, { CR105, 0x65 },
+ { CR106, 0x04 }, { CR107, 0x00 }, { CR108, 0x0a },
+ { CR109, 0xaa }, { CR110, 0xaa }, { CR111, 0x25 },
+ { CR112, 0x25 }, { CR113, 0x00 }, { CR119, 0x1e },
+ { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { },
+ { CR5, 0x00 }, { CR6, 0x00 }, { CR7, 0x00 },
+ { CR8, 0x00 }, { CR9, 0x20 }, { CR12, 0xf0 },
+ { CR20, 0x0e }, { CR21, 0x0e }, { CR27, 0x10 },
+ { CR44, 0x33 }, { CR47, 0x1E }, { CR83, 0x24 },
+ { CR84, 0x04 }, { CR85, 0x00 }, { CR86, 0x0C },
+ { CR87, 0x12 }, { CR88, 0x0C }, { CR89, 0x00 },
+ { CR90, 0x10 }, { CR91, 0x08 }, { CR93, 0x00 },
+ { CR94, 0x01 }, { CR95, 0x00 }, { CR96, 0x50 },
+ { CR97, 0x37 }, { CR98, 0x35 }, { CR101, 0x13 },
+ { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+ { CR105, 0x12 }, { CR109, 0x27 }, { CR110, 0x27 },
+ { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+ { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+ { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f },
+ { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 },
+ { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 },
+ { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c },
+ { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c },
+ { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 },
+ { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa },
+ { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea },
+ { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a },
+ { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba },
+ /* Note: CR204 must lead the CR203 */
+ { CR204, 0x7d },
+ { },
+ { CR203, 0x30 },
+ };
+
+ int r, t;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto unlock;
+
+ r = patch_cr157(chip);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ return r;
+}
+
+static int zd1211b_hw_reset_phy(struct zd_chip *chip)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR0, 0x14 }, { CR1, 0x06 }, { CR2, 0x26 },
+ { CR3, 0x38 }, { CR4, 0x80 }, { CR9, 0xe0 },
+ { CR10, 0x81 },
+ /* power control { { CR11, 1 << 6 }, */
+ { CR11, 0x00 },
+ { CR12, 0xf0 }, { CR13, 0x8c }, { CR14, 0x80 },
+ { CR15, 0x3d }, { CR16, 0x20 }, { CR17, 0x1e },
+ { CR18, 0x0a }, { CR19, 0x48 },
+ { CR20, 0x10 }, /* Org:0x0E, ComTrend:RalLink AP */
+ { CR21, 0x0e }, { CR22, 0x23 }, { CR23, 0x90 },
+ { CR24, 0x14 }, { CR25, 0x40 }, { CR26, 0x10 },
+ { CR27, 0x10 }, { CR28, 0x7f }, { CR29, 0x80 },
+ { CR30, 0x4b }, /* ASIC/FWT, no jointly decoder */
+ { CR31, 0x60 }, { CR32, 0x43 }, { CR33, 0x08 },
+ { CR34, 0x06 }, { CR35, 0x0a }, { CR36, 0x00 },
+ { CR37, 0x00 }, { CR38, 0x38 }, { CR39, 0x0c },
+ { CR40, 0x84 }, { CR41, 0x2a }, { CR42, 0x80 },
+ { CR43, 0x10 }, { CR44, 0x33 }, { CR46, 0xff },
+ { CR47, 0x1E }, { CR48, 0x26 }, { CR49, 0x5b },
+ { CR64, 0xd0 }, { CR65, 0x04 }, { CR66, 0x58 },
+ { CR67, 0xc9 }, { CR68, 0x88 }, { CR69, 0x41 },
+ { CR70, 0x23 }, { CR71, 0x10 }, { CR72, 0xff },
+ { CR73, 0x32 }, { CR74, 0x30 }, { CR75, 0x65 },
+ { CR76, 0x41 }, { CR77, 0x1b }, { CR78, 0x30 },
+ { CR79, 0xf0 }, { CR80, 0x64 }, { CR81, 0x64 },
+ { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
+ { CR85, 0x00 }, { CR86, 0x0c }, { CR87, 0x12 },
+ { CR88, 0x0c }, { CR89, 0x00 }, { CR90, 0x58 },
+ { CR91, 0x04 }, { CR92, 0x00 }, { CR93, 0x00 },
+ { CR94, 0x01 },
+ { CR95, 0x20 }, /* ZD1211B */
+ { CR96, 0x50 }, { CR97, 0x37 }, { CR98, 0x35 },
+ { CR99, 0x00 }, { CR100, 0x01 }, { CR101, 0x13 },
+ { CR102, 0x27 }, { CR103, 0x27 }, { CR104, 0x18 },
+ { CR105, 0x12 }, { CR106, 0x04 }, { CR107, 0x00 },
+ { CR108, 0x0a }, { CR109, 0x27 }, { CR110, 0x27 },
+ { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 },
+ { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 },
+ { CR117, 0xfc }, { CR118, 0xfa }, { CR119, 0x1e },
+ { CR125, 0x90 }, { CR126, 0x00 }, { CR127, 0x00 },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR131, 0x0c }, { CR136, 0xdf }, { CR137, 0xa0 },
+ { CR138, 0xa8 }, { CR139, 0xb4 }, { CR140, 0x98 },
+ { CR141, 0x82 }, { CR142, 0x53 }, { CR143, 0x1c },
+ { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x40 },
+ { CR149, 0x40 }, /* Org:0x50 ComTrend:RalLink AP */
+ { CR150, 0x14 }, /* Org:0x0E ComTrend:RalLink AP */
+ { CR151, 0x18 }, { CR159, 0x70 }, { CR160, 0xfe },
+ { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa },
+ { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe },
+ { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba },
+ { CR170, 0xba }, { CR171, 0xba },
+ /* Note: CR204 must lead the CR203 */
+ { CR204, 0x7d },
+ {},
+ { CR203, 0x30 },
+ };
+
+ int r, t;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto unlock;
+
+ r = patch_cr157(chip);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ return r;
+}
+
+static int hw_reset_phy(struct zd_chip *chip)
+{
+ return chip->is_zd1211b ? zd1211b_hw_reset_phy(chip) :
+ zd1211_hw_reset_phy(chip);
+}
+
+static int zd1211_hw_init_hmac(struct zd_chip *chip)
+{
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
+ { CR_ZD1211_RETRY_MAX, 0x2 },
+ { CR_SNIFFER_ON, 0 },
+ { CR_RX_FILTER, STA_RX_FILTER },
+ { CR_GROUP_HASH_P1, 0x00 },
+ { CR_GROUP_HASH_P2, 0x80000000 },
+ { CR_REG1, 0xa4 },
+ { CR_ADDA_PWR_DWN, 0x7f },
+ { CR_BCN_PLCP_CFG, 0x00f00401 },
+ { CR_PHY_DELAY, 0x00 },
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+ { CR_RX_THRESHOLD, 0x000c0640 },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+#ifdef DEBUG
+ if (r) {
+ dev_err(zd_chip_dev(chip),
+ "error in zd_iowrite32a_locked. Error number %d\n", r);
+ }
+#endif /* DEBUG */
+ return r;
+}
+
+static int zd1211b_hw_init_hmac(struct zd_chip *chip)
+{
+ static const struct zd_ioreq32 ioreqs[] = {
+ { CR_ACK_TIMEOUT_EXT, 0x20 },
+ { CR_ADDA_MBIAS_WARMTIME, 0x30000808 },
+ { CR_ZD1211B_RETRY_MAX, 0x02020202 },
+ { CR_ZD1211B_TX_PWR_CTL4, 0x007f003f },
+ { CR_ZD1211B_TX_PWR_CTL3, 0x007f003f },
+ { CR_ZD1211B_TX_PWR_CTL2, 0x003f001f },
+ { CR_ZD1211B_TX_PWR_CTL1, 0x001f000f },
+ { CR_ZD1211B_AIFS_CTL1, 0x00280028 },
+ { CR_ZD1211B_AIFS_CTL2, 0x008C003C },
+ { CR_ZD1211B_TXOP, 0x01800824 },
+ { CR_SNIFFER_ON, 0 },
+ { CR_RX_FILTER, STA_RX_FILTER },
+ { CR_GROUP_HASH_P1, 0x00 },
+ { CR_GROUP_HASH_P2, 0x80000000 },
+ { CR_REG1, 0xa4 },
+ { CR_ADDA_PWR_DWN, 0x7f },
+ { CR_BCN_PLCP_CFG, 0x00f00401 },
+ { CR_PHY_DELAY, 0x00 },
+ { CR_ACK_TIMEOUT_EXT, 0x80 },
+ { CR_ADDA_PWR_DWN, 0x00 },
+ { CR_ACK_TIME_80211, 0x100 },
+ { CR_RX_PE_DELAY, 0x70 },
+ { CR_PS_CTRL, 0x10000000 },
+ { CR_RTS_CTS_RATE, 0x02030203 },
+ { CR_RX_THRESHOLD, 0x000c0eff, },
+ { CR_AFTER_PNP, 0x1 },
+ { CR_WEP_PROTECT, 0x114 },
+ };
+
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error in zd_iowrite32a_locked. Error number %d\n", r);
+ }
+ return r;
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+ return chip->is_zd1211b ?
+ zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
+}
+
+struct aw_pt_bi {
+ u32 atim_wnd_period;
+ u32 pre_tbtt;
+ u32 beacon_interval;
+};
+
+static int get_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+ int r;
+ static const zd_addr_t aw_pt_bi_addr[] =
+ { CR_ATIM_WND_PERIOD, CR_PRE_TBTT, CR_BCN_INTERVAL };
+ u32 values[3];
+
+ r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr,
+ ARRAY_SIZE(aw_pt_bi_addr));
+ if (r) {
+ memset(s, 0, sizeof(*s));
+ return r;
+ }
+
+ s->atim_wnd_period = values[0];
+ s->pre_tbtt = values[1];
+ s->beacon_interval = values[2];
+ dev_dbg_f(zd_chip_dev(chip), "aw %u pt %u bi %u\n",
+ s->atim_wnd_period, s->pre_tbtt, s->beacon_interval);
+ return 0;
+}
+
+static int set_aw_pt_bi(struct zd_chip *chip, struct aw_pt_bi *s)
+{
+ struct zd_ioreq32 reqs[3];
+
+ if (s->beacon_interval <= 5)
+ s->beacon_interval = 5;
+ if (s->pre_tbtt < 4 || s->pre_tbtt >= s->beacon_interval)
+ s->pre_tbtt = s->beacon_interval - 1;
+ if (s->atim_wnd_period >= s->pre_tbtt)
+ s->atim_wnd_period = s->pre_tbtt - 1;
+
+ reqs[0].addr = CR_ATIM_WND_PERIOD;
+ reqs[0].value = s->atim_wnd_period;
+ reqs[1].addr = CR_PRE_TBTT;
+ reqs[1].value = s->pre_tbtt;
+ reqs[2].addr = CR_BCN_INTERVAL;
+ reqs[2].value = s->beacon_interval;
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "aw %u pt %u bi %u\n", s->atim_wnd_period, s->pre_tbtt,
+ s->beacon_interval);
+ return zd_iowrite32a_locked(chip, reqs, ARRAY_SIZE(reqs));
+}
+
+
+static int set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+ int r;
+ struct aw_pt_bi s;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = get_aw_pt_bi(chip, &s);
+ if (r)
+ return r;
+ s.beacon_interval = interval;
+ return set_aw_pt_bi(chip, &s);
+}
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = set_beacon_interval(chip, interval);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int hw_init(struct zd_chip *chip)
+{
+ int r;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = hw_reset_phy(chip);
+ if (r)
+ return r;
+
+ r = hw_init_hmac(chip);
+ if (r)
+ return r;
+
+ /* Although the vendor driver defaults to a different value during
+ * init, it overwrites the IFS value with the following every time
+ * the channel changes. We should aim to be more intelligent... */
+ r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
+ if (r)
+ return r;
+
+ return set_beacon_interval(chip, 100);
+}
+
+#ifdef DEBUG
+static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
+ const char *addr_string)
+{
+ int r;
+ u32 value;
+
+ r = zd_ioread32_locked(chip, &value, addr);
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip),
+ "error reading %s. Error number %d\n", addr_string, r);
+ return r;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "%s %#010x\n",
+ addr_string, (unsigned int)value);
+ return 0;
+}
+
+static int test_init(struct zd_chip *chip)
+{
+ int r;
+
+ r = dump_cr(chip, CR_AFTER_PNP, "CR_AFTER_PNP");
+ if (r)
+ return r;
+ r = dump_cr(chip, CR_GPI_EN, "CR_GPI_EN");
+ if (r)
+ return r;
+ return dump_cr(chip, CR_INTERRUPT, "CR_INTERRUPT");
+}
+
+static void dump_fw_registers(struct zd_chip *chip)
+{
+ static const zd_addr_t addr[4] = {
+ FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
+ FW_LINK_STATUS
+ };
+
+ int r;
+ u16 values[4];
+
+ r = zd_ioread16v_locked(chip, values, (const zd_addr_t*)addr,
+ ARRAY_SIZE(addr));
+ if (r) {
+ dev_dbg_f(zd_chip_dev(chip), "error %d zd_ioread16v_locked\n",
+ r);
+ return;
+ }
+
+ dev_dbg_f(zd_chip_dev(chip), "FW_FIRMWARE_VER %#06hx\n", values[0]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_USB_SPEED %#06hx\n", values[1]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_FIX_TX_RATE %#06hx\n", values[2]);
+ dev_dbg_f(zd_chip_dev(chip), "FW_LINK_STATUS %#06hx\n", values[3]);
+}
+#endif /* DEBUG */
+
+static int print_fw_version(struct zd_chip *chip)
+{
+ int r;
+ u16 version;
+
+ r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+ if (r)
+ return r;
+
+ dev_info(zd_chip_dev(chip),"firmware version %04hx\n", version);
+ return 0;
+}
+
+static int set_mandatory_rates(struct zd_chip *chip, enum ieee80211_std std)
+{
+ u32 rates;
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ /* This sets the mandatory rates, which only depend from the standard
+ * that the device is supporting. Until further notice we should try
+ * to support 802.11g also for full speed USB.
+ */
+ switch (std) {
+ case IEEE80211B:
+ rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M;
+ break;
+ case IEEE80211G:
+ rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M|
+ CR_RATE_6M|CR_RATE_12M|CR_RATE_24M;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL);
+}
+
+int zd_chip_enable_hwint(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, HWINT_ENABLED, CR_INTERRUPT);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int disable_hwint(struct zd_chip *chip)
+{
+ return zd_iowrite32_locked(chip, HWINT_DISABLED, CR_INTERRUPT);
+}
+
+int zd_chip_disable_hwint(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = disable_hwint(chip);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
+{
+ int r;
+ u8 rf_type;
+
+ dev_dbg_f(zd_chip_dev(chip), "\n");
+
+ mutex_lock(&chip->mutex);
+ chip->is_zd1211b = (device_type == DEVICE_ZD1211B) != 0;
+
+#ifdef DEBUG
+ r = test_init(chip);
+ if (r)
+ goto out;
+#endif
+ r = zd_iowrite32_locked(chip, 1, CR_AFTER_PNP);
+ if (r)
+ goto out;
+
+ r = zd_usb_init_hw(&chip->usb);
+ if (r)
+ goto out;
+
+ /* GPI is always disabled, also in the other driver.
+ */
+ r = zd_iowrite32_locked(chip, 0, CR_GPI_EN);
+ if (r)
+ goto out;
+ r = zd_iowrite32_locked(chip, CWIN_SIZE, CR_CWMIN_CWMAX);
+ if (r)
+ goto out;
+ /* Currently we support IEEE 802.11g for full and high speed USB.
+ * It might be discussed, whether we should suppport pure b mode for
+ * full speed USB.
+ */
+ r = set_mandatory_rates(chip, IEEE80211G);
+ if (r)
+ goto out;
+ /* Disabling interrupts is certainly a smart thing here.
+ */
+ r = disable_hwint(chip);
+ if (r)
+ goto out;
+ r = read_pod(chip, &rf_type);
+ if (r)
+ goto out;
+ r = hw_init(chip);
+ if (r)
+ goto out;
+ r = zd_rf_init_hw(&chip->rf, rf_type);
+ if (r)
+ goto out;
+
+ r = print_fw_version(chip);
+ if (r)
+ goto out;
+
+#ifdef DEBUG
+ dump_fw_registers(chip);
+ r = test_init(chip);
+ if (r)
+ goto out;
+#endif /* DEBUG */
+
+ r = read_e2p_mac_addr(chip);
+ if (r)
+ goto out;
+
+ r = read_cal_int_tables(chip);
+ if (r)
+ goto out;
+
+ print_id(chip);
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int update_pwr_int(struct zd_chip *chip, u8 channel)
+{
+ u8 value = chip->pwr_int_values[channel - 1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
+ channel, value);
+ return zd_iowrite16_locked(chip, value, CR31);
+}
+
+static int update_pwr_cal(struct zd_chip *chip, u8 channel)
+{
+ u8 value = chip->pwr_cal_values[channel-1];
+ dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
+ channel, value);
+ return zd_iowrite16_locked(chip, value, CR68);
+}
+
+static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
+{
+ struct zd_ioreq16 ioreqs[3];
+
+ ioreqs[0].addr = CR67;
+ ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
+ ioreqs[1].addr = CR66;
+ ioreqs[1].value = chip->ofdm_cal_values[OFDM_48M_INDEX][channel-1];
+ ioreqs[2].addr = CR65;
+ ioreqs[2].value = chip->ofdm_cal_values[OFDM_54M_INDEX][channel-1];
+
+ dev_dbg_f(zd_chip_dev(chip),
+ "channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
+ channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int update_channel_integration_and_calibration(struct zd_chip *chip,
+ u8 channel)
+{
+ int r;
+
+ r = update_pwr_int(chip, channel);
+ if (r)
+ return r;
+ if (chip->is_zd1211b) {
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR69, 0x28 },
+ {},
+ { CR69, 0x2a },
+ };
+
+ r = update_ofdm_cal(chip, channel);
+ if (r)
+ return r;
+ r = update_pwr_cal(chip, channel);
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+/* The CCK baseband gain can be optionally patched by the EEPROM */
+static int patch_cck_gain(struct zd_chip *chip)
+{
+ int r;
+ u32 value;
+
+ if (!chip->patch_cck_gain)
+ return 0;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread32_locked(chip, &value, E2P_PHY_REG);
+ if (r)
+ return r;
+ dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
+ return zd_iowrite16_locked(chip, value & 0xff, CR47);
+}
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
+{
+ int r, t;
+
+ mutex_lock(&chip->mutex);
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ goto out;
+ r = zd_rf_set_channel(&chip->rf, channel);
+ if (r)
+ goto unlock;
+ r = update_channel_integration_and_calibration(chip, channel);
+ if (r)
+ goto unlock;
+ r = patch_cck_gain(chip);
+ if (r)
+ goto unlock;
+ r = patch_6m_band_edge(chip, channel);
+ if (r)
+ goto unlock;
+ r = zd_iowrite32_locked(chip, 0, CR_CONFIG_PHILIPS);
+unlock:
+ t = zd_chip_unlock_phy_regs(chip);
+ if (t && !r)
+ r = t;
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+u8 zd_chip_get_channel(struct zd_chip *chip)
+{
+ u8 channel;
+
+ mutex_lock(&chip->mutex);
+ channel = chip->rf.channel;
+ mutex_unlock(&chip->mutex);
+ return channel;
+}
+
+int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
+{
+ static const zd_addr_t a[] = {
+ FW_LINK_STATUS,
+ CR_LED,
+ };
+
+ int r;
+ u16 v[ARRAY_SIZE(a)];
+ struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
+ [0] = { FW_LINK_STATUS },
+ [1] = { CR_LED },
+ };
+ u16 other_led;
+
+ mutex_lock(&chip->mutex);
+ r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a));
+ if (r)
+ goto out;
+
+ other_led = chip->link_led == LED1 ? LED2 : LED1;
+
+ switch (status) {
+ case LED_OFF:
+ ioreqs[0].value = FW_LINK_OFF;
+ ioreqs[1].value = v[1] & ~(LED1|LED2);
+ break;
+ case LED_SCANNING:
+ ioreqs[0].value = FW_LINK_OFF;
+ ioreqs[1].value = v[1] & ~other_led;
+ if (get_seconds() % 3 == 0) {
+ ioreqs[1].value &= ~chip->link_led;
+ } else {
+ ioreqs[1].value |= chip->link_led;
+ }
+ break;
+ case LED_ASSOCIATED:
+ ioreqs[0].value = FW_LINK_TX;
+ ioreqs[1].value = v[1] & ~other_led;
+ ioreqs[1].value |= chip->link_led;
+ break;
+ default:
+ r = -EINVAL;
+ goto out;
+ }
+
+ if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) {
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ goto out;
+ }
+ r = 0;
+out:
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
+{
+ int r;
+
+ if (cr_rates & ~(CR_RATES_80211B|CR_RATES_80211G))
+ return -EINVAL;
+
+ mutex_lock(&chip->mutex);
+ r = zd_iowrite32_locked(chip, cr_rates, CR_BASIC_RATE_TBL);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+static int ofdm_qual_db(u8 status_quality, u8 rate, unsigned int size)
+{
+ static const u16 constants[] = {
+ 715, 655, 585, 540, 470, 410, 360, 315,
+ 270, 235, 205, 175, 150, 125, 105, 85,
+ 65, 50, 40, 25, 15
+ };
+
+ int i;
+ u32 x;
+
+ /* It seems that their quality parameter is somehow per signal
+ * and is now transferred per bit.
+ */
+ switch (rate) {
+ case ZD_OFDM_RATE_6M:
+ case ZD_OFDM_RATE_12M:
+ case ZD_OFDM_RATE_24M:
+ size *= 2;
+ break;
+ case ZD_OFDM_RATE_9M:
+ case ZD_OFDM_RATE_18M:
+ case ZD_OFDM_RATE_36M:
+ case ZD_OFDM_RATE_54M:
+ size *= 4;
+ size /= 3;
+ break;
+ case ZD_OFDM_RATE_48M:
+ size *= 3;
+ size /= 2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ x = (10000 * status_quality)/size;
+ for (i = 0; i < ARRAY_SIZE(constants); i++) {
+ if (x > constants[i])
+ break;
+ }
+
+ switch (rate) {
+ case ZD_OFDM_RATE_6M:
+ case ZD_OFDM_RATE_9M:
+ i += 3;
+ break;
+ case ZD_OFDM_RATE_12M:
+ case ZD_OFDM_RATE_18M:
+ i += 5;
+ break;
+ case ZD_OFDM_RATE_24M:
+ case ZD_OFDM_RATE_36M:
+ i += 9;
+ break;
+ case ZD_OFDM_RATE_48M:
+ case ZD_OFDM_RATE_54M:
+ i += 15;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return i;
+}
+
+static int ofdm_qual_percent(u8 status_quality, u8 rate, unsigned int size)
+{
+ int r;
+
+ r = ofdm_qual_db(status_quality, rate, size);
+ ZD_ASSERT(r >= 0);
+ if (r < 0)
+ r = 0;
+
+ r = (r * 100)/29;
+ return r <= 100 ? r : 100;
+}
+
+static unsigned int log10times100(unsigned int x)
+{
+ static const u8 log10[] = {
+ 0,
+ 0, 30, 47, 60, 69, 77, 84, 90, 95, 100,
+ 104, 107, 111, 114, 117, 120, 123, 125, 127, 130,
+ 132, 134, 136, 138, 139, 141, 143, 144, 146, 147,
+ 149, 150, 151, 153, 154, 155, 156, 157, 159, 160,
+ 161, 162, 163, 164, 165, 166, 167, 168, 169, 169,
+ 170, 171, 172, 173, 174, 174, 175, 176, 177, 177,
+ 178, 179, 179, 180, 181, 181, 182, 183, 183, 184,
+ 185, 185, 186, 186, 187, 188, 188, 189, 189, 190,
+ 190, 191, 191, 192, 192, 193, 193, 194, 194, 195,
+ 195, 196, 196, 197, 197, 198, 198, 199, 199, 200,
+ 200, 200, 201, 201, 202, 202, 202, 203, 203, 204,
+ 204, 204, 205, 205, 206, 206, 206, 207, 207, 207,
+ 208, 208, 208, 209, 209, 210, 210, 210, 211, 211,
+ 211, 212, 212, 212, 213, 213, 213, 213, 214, 214,
+ 214, 215, 215, 215, 216, 216, 216, 217, 217, 217,
+ 217, 218, 218, 218, 219, 219, 219, 219, 220, 220,
+ 220, 220, 221, 221, 221, 222, 222, 222, 222, 223,
+ 223, 223, 223, 224, 224, 224, 224,
+ };
+
+ return x < ARRAY_SIZE(log10) ? log10[x] : 225;
+}
+
+enum {
+ MAX_CCK_EVM_DB = 45,
+};
+
+static int cck_evm_db(u8 status_quality)
+{
+ return (20 * log10times100(status_quality)) / 100;
+}
+
+static int cck_snr_db(u8 status_quality)
+{
+ int r = MAX_CCK_EVM_DB - cck_evm_db(status_quality);
+ ZD_ASSERT(r >= 0);
+ return r;
+}
+
+static int cck_qual_percent(u8 status_quality)
+{
+ int r;
+
+ r = cck_snr_db(status_quality);
+ r = (100*r)/17;
+ return r <= 100 ? r : 100;
+}
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+ const struct rx_status *status)
+{
+ return (status->frame_status&ZD_RX_OFDM) ?
+ ofdm_qual_percent(status->signal_quality_ofdm,
+ zd_ofdm_plcp_header_rate(rx_frame),
+ size) :
+ cck_qual_percent(status->signal_quality_cck);
+}
+
+u8 zd_rx_strength_percent(u8 rssi)
+{
+ int r = (rssi*100) / 41;
+ if (r > 100)
+ r = 100;
+ return (u8) r;
+}
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status)
+{
+ static const u16 ofdm_rates[] = {
+ [ZD_OFDM_RATE_6M] = 60,
+ [ZD_OFDM_RATE_9M] = 90,
+ [ZD_OFDM_RATE_12M] = 120,
+ [ZD_OFDM_RATE_18M] = 180,
+ [ZD_OFDM_RATE_24M] = 240,
+ [ZD_OFDM_RATE_36M] = 360,
+ [ZD_OFDM_RATE_48M] = 480,
+ [ZD_OFDM_RATE_54M] = 540,
+ };
+ u16 rate;
+ if (status->frame_status & ZD_RX_OFDM) {
+ u8 ofdm_rate = zd_ofdm_plcp_header_rate(rx_frame);
+ rate = ofdm_rates[ofdm_rate & 0xf];
+ } else {
+ u8 cck_rate = zd_cck_plcp_header_rate(rx_frame);
+ switch (cck_rate) {
+ case ZD_CCK_SIGNAL_1M:
+ rate = 10;
+ break;
+ case ZD_CCK_SIGNAL_2M:
+ rate = 20;
+ break;
+ case ZD_CCK_SIGNAL_5M5:
+ rate = 55;
+ break;
+ case ZD_CCK_SIGNAL_11M:
+ rate = 110;
+ break;
+ default:
+ rate = 0;
+ }
+ }
+
+ return rate;
+}
+
+int zd_chip_switch_radio_on(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_switch_radio_on(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_switch_radio_off(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_switch_radio_off(&chip->rf);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+int zd_chip_enable_int(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_usb_enable_int(&chip->usb);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+void zd_chip_disable_int(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_disable_int(&chip->usb);
+ mutex_unlock(&chip->mutex);
+}
+
+int zd_chip_enable_rx(struct zd_chip *chip)
+{
+ int r;
+
+ mutex_lock(&chip->mutex);
+ r = zd_usb_enable_rx(&chip->usb);
+ mutex_unlock(&chip->mutex);
+ return r;
+}
+
+void zd_chip_disable_rx(struct zd_chip *chip)
+{
+ mutex_lock(&chip->mutex);
+ zd_usb_disable_rx(&chip->usb);
+ mutex_unlock(&chip->mutex);
+}
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits)
+{
+ int r;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ r = zd_rfwrite_locked(chip, values[i], bits);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+/*
+ * We can optionally program the RF directly through CR regs, if supported by
+ * the hardware. This is much faster than the older method.
+ */
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value)
+{
+ struct zd_ioreq16 ioreqs[] = {
+ { CR244, (value >> 16) & 0xff },
+ { CR243, (value >> 8) & 0xff },
+ { CR242, value & 0xff },
+ };
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+ const u32 *values, unsigned int count)
+{
+ int r;
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ r = zd_rfwrite_cr_locked(chip, values[i]);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
new file mode 100644
index 00000000000..ae59597ce4e
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -0,0 +1,845 @@
+/* zd_chip.h
+ *
+ * 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
+ */
+
+#ifndef _ZD_CHIP_H
+#define _ZD_CHIP_H
+
+#include "zd_types.h"
+#include "zd_rf.h"
+#include "zd_usb.h"
+
+/* Header for the Media Access Controller (MAC) and the Baseband Processor
+ * (BBP). It appears that the ZD1211 wraps the old ZD1205 with USB glue and
+ * adds a processor for handling the USB protocol.
+ */
+
+/* 8-bit hardware registers */
+#define CR0 CTL_REG(0x0000)
+#define CR1 CTL_REG(0x0004)
+#define CR2 CTL_REG(0x0008)
+#define CR3 CTL_REG(0x000C)
+
+#define CR5 CTL_REG(0x0010)
+/* bit 5: if set short preamble used
+ * bit 6: filter band - Japan channel 14 on, else off
+ */
+#define CR6 CTL_REG(0x0014)
+#define CR7 CTL_REG(0x0018)
+#define CR8 CTL_REG(0x001C)
+
+#define CR4 CTL_REG(0x0020)
+
+#define CR9 CTL_REG(0x0024)
+/* bit 2: antenna switch (together with CR10) */
+#define CR10 CTL_REG(0x0028)
+/* bit 1: antenna switch (together with CR9)
+ * RF2959 controls with CR11 radion on and off
+ */
+#define CR11 CTL_REG(0x002C)
+/* bit 6: TX power control for OFDM
+ * RF2959 controls with CR10 radio on and off
+ */
+#define CR12 CTL_REG(0x0030)
+#define CR13 CTL_REG(0x0034)
+#define CR14 CTL_REG(0x0038)
+#define CR15 CTL_REG(0x003C)
+#define CR16 CTL_REG(0x0040)
+#define CR17 CTL_REG(0x0044)
+#define CR18 CTL_REG(0x0048)
+#define CR19 CTL_REG(0x004C)
+#define CR20 CTL_REG(0x0050)
+#define CR21 CTL_REG(0x0054)
+#define CR22 CTL_REG(0x0058)
+#define CR23 CTL_REG(0x005C)
+#define CR24 CTL_REG(0x0060) /* CCA threshold */
+#define CR25 CTL_REG(0x0064)
+#define CR26 CTL_REG(0x0068)
+#define CR27 CTL_REG(0x006C)
+#define CR28 CTL_REG(0x0070)
+#define CR29 CTL_REG(0x0074)
+#define CR30 CTL_REG(0x0078)
+#define CR31 CTL_REG(0x007C) /* TX power control for RF in CCK mode */
+#define CR32 CTL_REG(0x0080)
+#define CR33 CTL_REG(0x0084)
+#define CR34 CTL_REG(0x0088)
+#define CR35 CTL_REG(0x008C)
+#define CR36 CTL_REG(0x0090)
+#define CR37 CTL_REG(0x0094)
+#define CR38 CTL_REG(0x0098)
+#define CR39 CTL_REG(0x009C)
+#define CR40 CTL_REG(0x00A0)
+#define CR41 CTL_REG(0x00A4)
+#define CR42 CTL_REG(0x00A8)
+#define CR43 CTL_REG(0x00AC)
+#define CR44 CTL_REG(0x00B0)
+#define CR45 CTL_REG(0x00B4)
+#define CR46 CTL_REG(0x00B8)
+#define CR47 CTL_REG(0x00BC) /* CCK baseband gain
+ * (patch value might be in EEPROM)
+ */
+#define CR48 CTL_REG(0x00C0)
+#define CR49 CTL_REG(0x00C4)
+#define CR50 CTL_REG(0x00C8)
+#define CR51 CTL_REG(0x00CC) /* TX power control for RF in 6-36M modes */
+#define CR52 CTL_REG(0x00D0) /* TX power control for RF in 48M mode */
+#define CR53 CTL_REG(0x00D4) /* TX power control for RF in 54M mode */
+#define CR54 CTL_REG(0x00D8)
+#define CR55 CTL_REG(0x00DC)
+#define CR56 CTL_REG(0x00E0)
+#define CR57 CTL_REG(0x00E4)
+#define CR58 CTL_REG(0x00E8)
+#define CR59 CTL_REG(0x00EC)
+#define CR60 CTL_REG(0x00F0)
+#define CR61 CTL_REG(0x00F4)
+#define CR62 CTL_REG(0x00F8)
+#define CR63 CTL_REG(0x00FC)
+#define CR64 CTL_REG(0x0100)
+#define CR65 CTL_REG(0x0104) /* OFDM 54M calibration */
+#define CR66 CTL_REG(0x0108) /* OFDM 48M calibration */
+#define CR67 CTL_REG(0x010C) /* OFDM 36M calibration */
+#define CR68 CTL_REG(0x0110) /* CCK calibration */
+#define CR69 CTL_REG(0x0114)
+#define CR70 CTL_REG(0x0118)
+#define CR71 CTL_REG(0x011C)
+#define CR72 CTL_REG(0x0120)
+#define CR73 CTL_REG(0x0124)
+#define CR74 CTL_REG(0x0128)
+#define CR75 CTL_REG(0x012C)
+#define CR76 CTL_REG(0x0130)
+#define CR77 CTL_REG(0x0134)
+#define CR78 CTL_REG(0x0138)
+#define CR79 CTL_REG(0x013C)
+#define CR80 CTL_REG(0x0140)
+#define CR81 CTL_REG(0x0144)
+#define CR82 CTL_REG(0x0148)
+#define CR83 CTL_REG(0x014C)
+#define CR84 CTL_REG(0x0150)
+#define CR85 CTL_REG(0x0154)
+#define CR86 CTL_REG(0x0158)
+#define CR87 CTL_REG(0x015C)
+#define CR88 CTL_REG(0x0160)
+#define CR89 CTL_REG(0x0164)
+#define CR90 CTL_REG(0x0168)
+#define CR91 CTL_REG(0x016C)
+#define CR92 CTL_REG(0x0170)
+#define CR93 CTL_REG(0x0174)
+#define CR94 CTL_REG(0x0178)
+#define CR95 CTL_REG(0x017C)
+#define CR96 CTL_REG(0x0180)
+#define CR97 CTL_REG(0x0184)
+#define CR98 CTL_REG(0x0188)
+#define CR99 CTL_REG(0x018C)
+#define CR100 CTL_REG(0x0190)
+#define CR101 CTL_REG(0x0194)
+#define CR102 CTL_REG(0x0198)
+#define CR103 CTL_REG(0x019C)
+#define CR104 CTL_REG(0x01A0)
+#define CR105 CTL_REG(0x01A4)
+#define CR106 CTL_REG(0x01A8)
+#define CR107 CTL_REG(0x01AC)
+#define CR108 CTL_REG(0x01B0)
+#define CR109 CTL_REG(0x01B4)
+#define CR110 CTL_REG(0x01B8)
+#define CR111 CTL_REG(0x01BC)
+#define CR112 CTL_REG(0x01C0)
+#define CR113 CTL_REG(0x01C4)
+#define CR114 CTL_REG(0x01C8)
+#define CR115 CTL_REG(0x01CC)
+#define CR116 CTL_REG(0x01D0)
+#define CR117 CTL_REG(0x01D4)
+#define CR118 CTL_REG(0x01D8)
+#define CR119 CTL_REG(0x01DC)
+#define CR120 CTL_REG(0x01E0)
+#define CR121 CTL_REG(0x01E4)
+#define CR122 CTL_REG(0x01E8)
+#define CR123 CTL_REG(0x01EC)
+#define CR124 CTL_REG(0x01F0)
+#define CR125 CTL_REG(0x01F4)
+#define CR126 CTL_REG(0x01F8)
+#define CR127 CTL_REG(0x01FC)
+#define CR128 CTL_REG(0x0200)
+#define CR129 CTL_REG(0x0204)
+#define CR130 CTL_REG(0x0208)
+#define CR131 CTL_REG(0x020C)
+#define CR132 CTL_REG(0x0210)
+#define CR133 CTL_REG(0x0214)
+#define CR134 CTL_REG(0x0218)
+#define CR135 CTL_REG(0x021C)
+#define CR136 CTL_REG(0x0220)
+#define CR137 CTL_REG(0x0224)
+#define CR138 CTL_REG(0x0228)
+#define CR139 CTL_REG(0x022C)
+#define CR140 CTL_REG(0x0230)
+#define CR141 CTL_REG(0x0234)
+#define CR142 CTL_REG(0x0238)
+#define CR143 CTL_REG(0x023C)
+#define CR144 CTL_REG(0x0240)
+#define CR145 CTL_REG(0x0244)
+#define CR146 CTL_REG(0x0248)
+#define CR147 CTL_REG(0x024C)
+#define CR148 CTL_REG(0x0250)
+#define CR149 CTL_REG(0x0254)
+#define CR150 CTL_REG(0x0258)
+#define CR151 CTL_REG(0x025C)
+#define CR152 CTL_REG(0x0260)
+#define CR153 CTL_REG(0x0264)
+#define CR154 CTL_REG(0x0268)
+#define CR155 CTL_REG(0x026C)
+#define CR156 CTL_REG(0x0270)
+#define CR157 CTL_REG(0x0274)
+#define CR158 CTL_REG(0x0278)
+#define CR159 CTL_REG(0x027C)
+#define CR160 CTL_REG(0x0280)
+#define CR161 CTL_REG(0x0284)
+#define CR162 CTL_REG(0x0288)
+#define CR163 CTL_REG(0x028C)
+#define CR164 CTL_REG(0x0290)
+#define CR165 CTL_REG(0x0294)
+#define CR166 CTL_REG(0x0298)
+#define CR167 CTL_REG(0x029C)
+#define CR168 CTL_REG(0x02A0)
+#define CR169 CTL_REG(0x02A4)
+#define CR170 CTL_REG(0x02A8)
+#define CR171 CTL_REG(0x02AC)
+#define CR172 CTL_REG(0x02B0)
+#define CR173 CTL_REG(0x02B4)
+#define CR174 CTL_REG(0x02B8)
+#define CR175 CTL_REG(0x02BC)
+#define CR176 CTL_REG(0x02C0)
+#define CR177 CTL_REG(0x02C4)
+#define CR178 CTL_REG(0x02C8)
+#define CR179 CTL_REG(0x02CC)
+#define CR180 CTL_REG(0x02D0)
+#define CR181 CTL_REG(0x02D4)
+#define CR182 CTL_REG(0x02D8)
+#define CR183 CTL_REG(0x02DC)
+#define CR184 CTL_REG(0x02E0)
+#define CR185 CTL_REG(0x02E4)
+#define CR186 CTL_REG(0x02E8)
+#define CR187 CTL_REG(0x02EC)
+#define CR188 CTL_REG(0x02F0)
+#define CR189 CTL_REG(0x02F4)
+#define CR190 CTL_REG(0x02F8)
+#define CR191 CTL_REG(0x02FC)
+#define CR192 CTL_REG(0x0300)
+#define CR193 CTL_REG(0x0304)
+#define CR194 CTL_REG(0x0308)
+#define CR195 CTL_REG(0x030C)
+#define CR196 CTL_REG(0x0310)
+#define CR197 CTL_REG(0x0314)
+#define CR198 CTL_REG(0x0318)
+#define CR199 CTL_REG(0x031C)
+#define CR200 CTL_REG(0x0320)
+#define CR201 CTL_REG(0x0324)
+#define CR202 CTL_REG(0x0328)
+#define CR203 CTL_REG(0x032C) /* I2C bus template value & flash control */
+#define CR204 CTL_REG(0x0330)
+#define CR205 CTL_REG(0x0334)
+#define CR206 CTL_REG(0x0338)
+#define CR207 CTL_REG(0x033C)
+#define CR208 CTL_REG(0x0340)
+#define CR209 CTL_REG(0x0344)
+#define CR210 CTL_REG(0x0348)
+#define CR211 CTL_REG(0x034C)
+#define CR212 CTL_REG(0x0350)
+#define CR213 CTL_REG(0x0354)
+#define CR214 CTL_REG(0x0358)
+#define CR215 CTL_REG(0x035C)
+#define CR216 CTL_REG(0x0360)
+#define CR217 CTL_REG(0x0364)
+#define CR218 CTL_REG(0x0368)
+#define CR219 CTL_REG(0x036C)
+#define CR220 CTL_REG(0x0370)
+#define CR221 CTL_REG(0x0374)
+#define CR222 CTL_REG(0x0378)
+#define CR223 CTL_REG(0x037C)
+#define CR224 CTL_REG(0x0380)
+#define CR225 CTL_REG(0x0384)
+#define CR226 CTL_REG(0x0388)
+#define CR227 CTL_REG(0x038C)
+#define CR228 CTL_REG(0x0390)
+#define CR229 CTL_REG(0x0394)
+#define CR230 CTL_REG(0x0398)
+#define CR231 CTL_REG(0x039C)
+#define CR232 CTL_REG(0x03A0)
+#define CR233 CTL_REG(0x03A4)
+#define CR234 CTL_REG(0x03A8)
+#define CR235 CTL_REG(0x03AC)
+#define CR236 CTL_REG(0x03B0)
+
+#define CR240 CTL_REG(0x03C0)
+/* bit 7: host-controlled RF register writes
+ * CR241-CR245: for hardware controlled writing of RF bits, not needed for
+ * USB
+ */
+#define CR241 CTL_REG(0x03C4)
+#define CR242 CTL_REG(0x03C8)
+#define CR243 CTL_REG(0x03CC)
+#define CR244 CTL_REG(0x03D0)
+#define CR245 CTL_REG(0x03D4)
+
+#define CR251 CTL_REG(0x03EC) /* only used for activation and deactivation of
+ * Airoha RFs AL2230 and AL7230B
+ */
+#define CR252 CTL_REG(0x03F0)
+#define CR253 CTL_REG(0x03F4)
+#define CR254 CTL_REG(0x03F8)
+#define CR255 CTL_REG(0x03FC)
+
+#define CR_MAX_PHY_REG 255
+
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+ * driver.
+ */
+
+#define CR_RF_IF_CLK CTL_REG(0x0400)
+#define CR_RF_IF_DATA CTL_REG(0x0404)
+#define CR_PE1_PE2 CTL_REG(0x0408)
+#define CR_PE2_DLY CTL_REG(0x040C)
+#define CR_LE1 CTL_REG(0x0410)
+#define CR_LE2 CTL_REG(0x0414)
+/* Seems to enable/disable GPI (General Purpose IO?) */
+#define CR_GPI_EN CTL_REG(0x0418)
+#define CR_RADIO_PD CTL_REG(0x042C)
+#define CR_RF2948_PD CTL_REG(0x042C)
+#define CR_ENABLE_PS_MANUAL_AGC CTL_REG(0x043C)
+#define CR_CONFIG_PHILIPS CTL_REG(0x0440)
+#define CR_SA2400_SER_AP CTL_REG(0x0444)
+#define CR_I2C_WRITE CTL_REG(0x0444)
+#define CR_SA2400_SER_RP CTL_REG(0x0448)
+#define CR_RADIO_PE CTL_REG(0x0458)
+#define CR_RST_BUS_MASTER CTL_REG(0x045C)
+#define CR_RFCFG CTL_REG(0x0464)
+#define CR_HSTSCHG CTL_REG(0x046C)
+#define CR_PHY_ON CTL_REG(0x0474)
+#define CR_RX_DELAY CTL_REG(0x0478)
+#define CR_RX_PE_DELAY CTL_REG(0x047C)
+#define CR_GPIO_1 CTL_REG(0x0490)
+#define CR_GPIO_2 CTL_REG(0x0494)
+#define CR_EncryBufMux CTL_REG(0x04A8)
+#define CR_PS_CTRL CTL_REG(0x0500)
+#define CR_ADDA_PWR_DWN CTL_REG(0x0504)
+#define CR_ADDA_MBIAS_WARMTIME CTL_REG(0x0508)
+#define CR_MAC_PS_STATE CTL_REG(0x050C)
+
+#define CR_INTERRUPT CTL_REG(0x0510)
+#define INT_TX_COMPLETE 0x00000001
+#define INT_RX_COMPLETE 0x00000002
+#define INT_RETRY_FAIL 0x00000004
+#define INT_WAKEUP 0x00000008
+#define INT_DTIM_NOTIFY 0x00000020
+#define INT_CFG_NEXT_BCN 0x00000040
+#define INT_BUS_ABORT 0x00000080
+#define INT_TX_FIFO_READY 0x00000100
+#define INT_UART 0x00000200
+#define INT_TX_COMPLETE_EN 0x00010000
+#define INT_RX_COMPLETE_EN 0x00020000
+#define INT_RETRY_FAIL_EN 0x00040000
+#define INT_WAKEUP_EN 0x00080000
+#define INT_DTIM_NOTIFY_EN 0x00200000
+#define INT_CFG_NEXT_BCN_EN 0x00400000
+#define INT_BUS_ABORT_EN 0x00800000
+#define INT_TX_FIFO_READY_EN 0x01000000
+#define INT_UART_EN 0x02000000
+
+#define CR_TSF_LOW_PART CTL_REG(0x0514)
+#define CR_TSF_HIGH_PART CTL_REG(0x0518)
+
+/* Following three values are in time units (1024us)
+ * Following condition must be met:
+ * atim < tbtt < bcn
+ */
+#define CR_ATIM_WND_PERIOD CTL_REG(0x051C)
+#define CR_BCN_INTERVAL CTL_REG(0x0520)
+#define CR_PRE_TBTT CTL_REG(0x0524)
+/* in units of TU(1024us) */
+
+/* for UART support */
+#define CR_UART_RBR_THR_DLL CTL_REG(0x0540)
+#define CR_UART_DLM_IER CTL_REG(0x0544)
+#define CR_UART_IIR_FCR CTL_REG(0x0548)
+#define CR_UART_LCR CTL_REG(0x054c)
+#define CR_UART_MCR CTL_REG(0x0550)
+#define CR_UART_LSR CTL_REG(0x0554)
+#define CR_UART_MSR CTL_REG(0x0558)
+#define CR_UART_ECR CTL_REG(0x055c)
+#define CR_UART_STATUS CTL_REG(0x0560)
+
+#define CR_PCI_TX_ADDR_P1 CTL_REG(0x0600)
+#define CR_PCI_TX_AddR_P2 CTL_REG(0x0604)
+#define CR_PCI_RX_AddR_P1 CTL_REG(0x0608)
+#define CR_PCI_RX_AddR_P2 CTL_REG(0x060C)
+
+/* must be overwritten if custom MAC address will be used */
+#define CR_MAC_ADDR_P1 CTL_REG(0x0610)
+#define CR_MAC_ADDR_P2 CTL_REG(0x0614)
+#define CR_BSSID_P1 CTL_REG(0x0618)
+#define CR_BSSID_P2 CTL_REG(0x061C)
+#define CR_BCN_PLCP_CFG CTL_REG(0x0620)
+#define CR_GROUP_HASH_P1 CTL_REG(0x0624)
+#define CR_GROUP_HASH_P2 CTL_REG(0x0628)
+#define CR_RX_TIMEOUT CTL_REG(0x062C)
+
+/* Basic rates supported by the BSS. When producing ACK or CTS messages, the
+ * device will use a rate in this table that is less than or equal to the rate
+ * of the incoming frame which prompted the response */
+#define CR_BASIC_RATE_TBL CTL_REG(0x0630)
+#define CR_RATE_1M 0x0001 /* 802.11b */
+#define CR_RATE_2M 0x0002 /* 802.11b */
+#define CR_RATE_5_5M 0x0004 /* 802.11b */
+#define CR_RATE_11M 0x0008 /* 802.11b */
+#define CR_RATE_6M 0x0100 /* 802.11g */
+#define CR_RATE_9M 0x0200 /* 802.11g */
+#define CR_RATE_12M 0x0400 /* 802.11g */
+#define CR_RATE_18M 0x0800 /* 802.11g */
+#define CR_RATE_24M 0x1000 /* 802.11g */
+#define CR_RATE_36M 0x2000 /* 802.11g */
+#define CR_RATE_48M 0x4000 /* 802.11g */
+#define CR_RATE_54M 0x8000 /* 802.11g */
+#define CR_RATES_80211G 0xff00
+#define CR_RATES_80211B 0x000f
+
+/* Mandatory rates required in the BSS. When producing ACK or CTS messages, if
+ * the device could not find an appropriate rate in CR_BASIC_RATE_TBL, it will
+ * look for a rate in this table that is less than or equal to the rate of
+ * the incoming frame. */
+#define CR_MANDATORY_RATE_TBL CTL_REG(0x0634)
+#define CR_RTS_CTS_RATE CTL_REG(0x0638)
+
+#define CR_WEP_PROTECT CTL_REG(0x063C)
+#define CR_RX_THRESHOLD CTL_REG(0x0640)
+
+/* register for controlling the LEDS */
+#define CR_LED CTL_REG(0x0644)
+/* masks for controlling LEDs */
+#define LED1 0x0100
+#define LED2 0x0200
+#define LED_SW 0x0400
+
+/* Seems to indicate that the configuration is over.
+ */
+#define CR_AFTER_PNP CTL_REG(0x0648)
+#define CR_ACK_TIME_80211 CTL_REG(0x0658)
+
+#define CR_RX_OFFSET CTL_REG(0x065c)
+
+#define CR_PHY_DELAY CTL_REG(0x066C)
+#define CR_BCN_FIFO CTL_REG(0x0670)
+#define CR_SNIFFER_ON CTL_REG(0x0674)
+
+#define CR_ENCRYPTION_TYPE CTL_REG(0x0678)
+#define NO_WEP 0
+#define WEP64 1
+#define WEP128 5
+#define WEP256 6
+#define ENC_SNIFFER 8
+
+#define CR_ZD1211_RETRY_MAX CTL_REG(0x067C)
+
+#define CR_REG1 CTL_REG(0x0680)
+/* Setting the bit UNLOCK_PHY_REGS disallows the write access to physical
+ * registers, so one could argue it is a LOCK bit. But calling it
+ * LOCK_PHY_REGS makes it confusing.
+ */
+#define UNLOCK_PHY_REGS 0x0080
+
+#define CR_DEVICE_STATE CTL_REG(0x0684)
+#define CR_UNDERRUN_CNT CTL_REG(0x0688)
+
+#define CR_RX_FILTER CTL_REG(0x068c)
+#define RX_FILTER_ASSOC_RESPONSE 0x0002
+#define RX_FILTER_REASSOC_RESPONSE 0x0008
+#define RX_FILTER_PROBE_RESPONSE 0x0020
+#define RX_FILTER_BEACON 0x0100
+#define RX_FILTER_DISASSOC 0x0400
+#define RX_FILTER_AUTH 0x0800
+#define AP_RX_FILTER 0x0400feff
+#define STA_RX_FILTER 0x0000ffff
+
+/* Monitor mode sets filter to 0xfffff */
+
+#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
+#define CR_BCN_FIFO_SEMAPHORE CTL_REG(0x0694)
+
+#define CR_IFS_VALUE CTL_REG(0x0698)
+#define IFS_VALUE_DIFS_SH 0
+#define IFS_VALUE_EIFS_SH 12
+#define IFS_VALUE_SIFS_SH 24
+#define IFS_VALUE_DEFAULT (( 50 << IFS_VALUE_DIFS_SH) | \
+ (1148 << IFS_VALUE_EIFS_SH) | \
+ ( 10 << IFS_VALUE_SIFS_SH))
+
+#define CR_RX_TIME_OUT CTL_REG(0x069C)
+#define CR_TOTAL_RX_FRM CTL_REG(0x06A0)
+#define CR_CRC32_CNT CTL_REG(0x06A4)
+#define CR_CRC16_CNT CTL_REG(0x06A8)
+#define CR_DECRYPTION_ERR_UNI CTL_REG(0x06AC)
+#define CR_RX_FIFO_OVERRUN CTL_REG(0x06B0)
+
+#define CR_DECRYPTION_ERR_MUL CTL_REG(0x06BC)
+
+#define CR_NAV_CNT CTL_REG(0x06C4)
+#define CR_NAV_CCA CTL_REG(0x06C8)
+#define CR_RETRY_CNT CTL_REG(0x06CC)
+
+#define CR_READ_TCB_ADDR CTL_REG(0x06E8)
+#define CR_READ_RFD_ADDR CTL_REG(0x06EC)
+#define CR_CWMIN_CWMAX CTL_REG(0x06F0)
+#define CR_TOTAL_TX_FRM CTL_REG(0x06F4)
+
+/* CAM: Continuous Access Mode (power management) */
+#define CR_CAM_MODE CTL_REG(0x0700)
+#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
+#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
+#define CR_CAM_ADDRESS CTL_REG(0x070C)
+#define CR_CAM_DATA CTL_REG(0x0710)
+
+#define CR_ROMDIR CTL_REG(0x0714)
+
+#define CR_DECRY_ERR_FLG_LOW CTL_REG(0x0714)
+#define CR_DECRY_ERR_FLG_HIGH CTL_REG(0x0718)
+
+#define CR_WEPKEY0 CTL_REG(0x0720)
+#define CR_WEPKEY1 CTL_REG(0x0724)
+#define CR_WEPKEY2 CTL_REG(0x0728)
+#define CR_WEPKEY3 CTL_REG(0x072C)
+#define CR_WEPKEY4 CTL_REG(0x0730)
+#define CR_WEPKEY5 CTL_REG(0x0734)
+#define CR_WEPKEY6 CTL_REG(0x0738)
+#define CR_WEPKEY7 CTL_REG(0x073C)
+#define CR_WEPKEY8 CTL_REG(0x0740)
+#define CR_WEPKEY9 CTL_REG(0x0744)
+#define CR_WEPKEY10 CTL_REG(0x0748)
+#define CR_WEPKEY11 CTL_REG(0x074C)
+#define CR_WEPKEY12 CTL_REG(0x0750)
+#define CR_WEPKEY13 CTL_REG(0x0754)
+#define CR_WEPKEY14 CTL_REG(0x0758)
+#define CR_WEPKEY15 CTL_REG(0x075c)
+#define CR_TKIP_MODE CTL_REG(0x0760)
+
+#define CR_EEPROM_PROTECT0 CTL_REG(0x0758)
+#define CR_EEPROM_PROTECT1 CTL_REG(0x075C)
+
+#define CR_DBG_FIFO_RD CTL_REG(0x0800)
+#define CR_DBG_SELECT CTL_REG(0x0804)
+#define CR_FIFO_Length CTL_REG(0x0808)
+
+
+#define CR_RSSI_MGC CTL_REG(0x0810)
+
+#define CR_PON CTL_REG(0x0818)
+#define CR_RX_ON CTL_REG(0x081C)
+#define CR_TX_ON CTL_REG(0x0820)
+#define CR_CHIP_EN CTL_REG(0x0824)
+#define CR_LO_SW CTL_REG(0x0828)
+#define CR_TXRX_SW CTL_REG(0x082C)
+#define CR_S_MD CTL_REG(0x0830)
+
+#define CR_USB_DEBUG_PORT CTL_REG(0x0888)
+
+#define CR_ZD1211B_TX_PWR_CTL1 CTL_REG(0x0b00)
+#define CR_ZD1211B_TX_PWR_CTL2 CTL_REG(0x0b04)
+#define CR_ZD1211B_TX_PWR_CTL3 CTL_REG(0x0b08)
+#define CR_ZD1211B_TX_PWR_CTL4 CTL_REG(0x0b0c)
+#define CR_ZD1211B_AIFS_CTL1 CTL_REG(0x0b10)
+#define CR_ZD1211B_AIFS_CTL2 CTL_REG(0x0b14)
+#define CR_ZD1211B_TXOP CTL_REG(0x0b20)
+#define CR_ZD1211B_RETRY_MAX CTL_REG(0x0b28)
+
+#define CWIN_SIZE 0x007f043f
+
+
+#define HWINT_ENABLED 0x004f0000
+#define HWINT_DISABLED 0
+
+#define E2P_PWR_INT_GUARD 8
+#define E2P_CHANNEL_COUNT 14
+
+/* If you compare this addresses with the ZYDAS orignal driver, please notify
+ * that we use word mapping for the EEPROM.
+ */
+
+/*
+ * Upper 16 bit contains the regulatory domain.
+ */
+#define E2P_SUBID E2P_REG(0x00)
+#define E2P_POD E2P_REG(0x02)
+#define E2P_MAC_ADDR_P1 E2P_REG(0x04)
+#define E2P_MAC_ADDR_P2 E2P_REG(0x06)
+#define E2P_PWR_CAL_VALUE1 E2P_REG(0x08)
+#define E2P_PWR_CAL_VALUE2 E2P_REG(0x0a)
+#define E2P_PWR_CAL_VALUE3 E2P_REG(0x0c)
+#define E2P_PWR_CAL_VALUE4 E2P_REG(0x0e)
+#define E2P_PWR_INT_VALUE1 E2P_REG(0x10)
+#define E2P_PWR_INT_VALUE2 E2P_REG(0x12)
+#define E2P_PWR_INT_VALUE3 E2P_REG(0x14)
+#define E2P_PWR_INT_VALUE4 E2P_REG(0x16)
+
+/* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
+ * also only 11 channels. */
+#define E2P_ALLOWED_CHANNEL E2P_REG(0x18)
+
+#define E2P_PHY_REG E2P_REG(0x1a)
+#define E2P_DEVICE_VER E2P_REG(0x20)
+#define E2P_36M_CAL_VALUE1 E2P_REG(0x28)
+#define E2P_36M_CAL_VALUE2 E2P_REG(0x2a)
+#define E2P_36M_CAL_VALUE3 E2P_REG(0x2c)
+#define E2P_36M_CAL_VALUE4 E2P_REG(0x2e)
+#define E2P_11A_INT_VALUE1 E2P_REG(0x30)
+#define E2P_11A_INT_VALUE2 E2P_REG(0x32)
+#define E2P_11A_INT_VALUE3 E2P_REG(0x34)
+#define E2P_11A_INT_VALUE4 E2P_REG(0x36)
+#define E2P_48M_CAL_VALUE1 E2P_REG(0x38)
+#define E2P_48M_CAL_VALUE2 E2P_REG(0x3a)
+#define E2P_48M_CAL_VALUE3 E2P_REG(0x3c)
+#define E2P_48M_CAL_VALUE4 E2P_REG(0x3e)
+#define E2P_48M_INT_VALUE1 E2P_REG(0x40)
+#define E2P_48M_INT_VALUE2 E2P_REG(0x42)
+#define E2P_48M_INT_VALUE3 E2P_REG(0x44)
+#define E2P_48M_INT_VALUE4 E2P_REG(0x46)
+#define E2P_54M_CAL_VALUE1 E2P_REG(0x48) /* ??? */
+#define E2P_54M_CAL_VALUE2 E2P_REG(0x4a)
+#define E2P_54M_CAL_VALUE3 E2P_REG(0x4c)
+#define E2P_54M_CAL_VALUE4 E2P_REG(0x4e)
+#define E2P_54M_INT_VALUE1 E2P_REG(0x50)
+#define E2P_54M_INT_VALUE2 E2P_REG(0x52)
+#define E2P_54M_INT_VALUE3 E2P_REG(0x54)
+#define E2P_54M_INT_VALUE4 E2P_REG(0x56)
+
+/* All 16 bit values */
+#define FW_FIRMWARE_VER FW_REG(0)
+/* non-zero if USB high speed connection */
+#define FW_USB_SPEED FW_REG(1)
+#define FW_FIX_TX_RATE FW_REG(2)
+/* Seems to be able to control LEDs over the firmware */
+#define FW_LINK_STATUS FW_REG(3)
+#define FW_SOFT_RESET FW_REG(4)
+#define FW_FLASH_CHK FW_REG(5)
+
+#define FW_LINK_OFF 0x0
+#define FW_LINK_TX 0x1
+/* 0x2 - link led on? */
+
+enum {
+ CR_BASE_OFFSET = 0x9000,
+ FW_START_OFFSET = 0xee00,
+ FW_BASE_ADDR_OFFSET = FW_START_OFFSET + 0x1d,
+ EEPROM_START_OFFSET = 0xf800,
+ EEPROM_SIZE = 0x800, /* words */
+ LOAD_CODE_SIZE = 0xe, /* words */
+ LOAD_VECT_SIZE = 0x10000 - 0xfff7, /* words */
+ EEPROM_REGS_OFFSET = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
+ EEPROM_REGS_SIZE = 0x7e, /* words */
+ E2P_BASE_OFFSET = EEPROM_START_OFFSET +
+ EEPROM_REGS_OFFSET,
+};
+
+#define FW_REG_TABLE_ADDR USB_ADDR(FW_START_OFFSET + 0x1d)
+
+enum {
+ /* indices for ofdm_cal_values */
+ OFDM_36M_INDEX = 0,
+ OFDM_48M_INDEX = 1,
+ OFDM_54M_INDEX = 2,
+};
+
+struct zd_chip {
+ struct zd_usb usb;
+ struct zd_rf rf;
+ struct mutex mutex;
+ u8 e2p_mac[ETH_ALEN];
+ /* EepSetPoint in the vendor driver */
+ u8 pwr_cal_values[E2P_CHANNEL_COUNT];
+ /* integration values in the vendor driver */
+ u8 pwr_int_values[E2P_CHANNEL_COUNT];
+ /* SetPointOFDM in the vendor driver */
+ u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
+ u16 link_led;
+ unsigned int pa_type:4,
+ patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
+ new_phy_layout:1,
+ is_zd1211b:1, supports_tx_led:1;
+};
+
+static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
+{
+ return container_of(usb, struct zd_chip, usb);
+}
+
+static inline struct zd_chip *zd_rf_to_chip(struct zd_rf *rf)
+{
+ return container_of(rf, struct zd_chip, rf);
+}
+
+#define zd_chip_dev(chip) (&(chip)->usb.intf->dev)
+
+void zd_chip_init(struct zd_chip *chip,
+ struct net_device *netdev,
+ struct usb_interface *intf);
+void zd_chip_clear(struct zd_chip *chip);
+int zd_chip_init_hw(struct zd_chip *chip, u8 device_type);
+int zd_chip_reset(struct zd_chip *chip);
+
+static inline int zd_ioread16v_locked(struct zd_chip *chip, u16 *values,
+ const zd_addr_t *addresses,
+ unsigned int count)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_ioread16v(&chip->usb, values, addresses, count);
+}
+
+static inline int zd_ioread16_locked(struct zd_chip *chip, u16 *value,
+ const zd_addr_t addr)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_ioread16(&chip->usb, value, addr);
+}
+
+int zd_ioread32v_locked(struct zd_chip *chip, u32 *values,
+ const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_ioread32_locked(struct zd_chip *chip, u32 *value,
+ const zd_addr_t addr)
+{
+ return zd_ioread32v_locked(chip, value, (const zd_addr_t *)&addr, 1);
+}
+
+static inline int zd_iowrite16_locked(struct zd_chip *chip, u16 value,
+ zd_addr_t addr)
+{
+ struct zd_ioreq16 ioreq;
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ ioreq.addr = addr;
+ ioreq.value = value;
+
+ return zd_usb_iowrite16v(&chip->usb, &ioreq, 1);
+}
+
+int zd_iowrite16a_locked(struct zd_chip *chip,
+ const struct zd_ioreq16 *ioreqs, unsigned int count);
+
+int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count);
+
+static inline int zd_iowrite32_locked(struct zd_chip *chip, u32 value,
+ zd_addr_t addr)
+{
+ struct zd_ioreq32 ioreq;
+
+ ioreq.addr = addr;
+ ioreq.value = value;
+
+ return _zd_iowrite32v_locked(chip, &ioreq, 1);
+}
+
+int zd_iowrite32a_locked(struct zd_chip *chip,
+ const struct zd_ioreq32 *ioreqs, unsigned int count);
+
+static inline int zd_rfwrite_locked(struct zd_chip *chip, u32 value, u8 bits)
+{
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ return zd_usb_rfwrite(&chip->usb, value, bits);
+}
+
+int zd_rfwrite_cr_locked(struct zd_chip *chip, u32 value);
+
+int zd_rfwritev_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count, u8 bits);
+int zd_rfwritev_cr_locked(struct zd_chip *chip,
+ const u32* values, unsigned int count);
+
+/* Locking functions for reading and writing registers.
+ * The different parameters are intentional.
+ */
+int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value);
+int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value);
+int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value);
+int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value);
+int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
+ u32 *values, unsigned int count);
+int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
+ unsigned int count);
+
+int zd_chip_set_channel(struct zd_chip *chip, u8 channel);
+static inline u8 _zd_chip_get_channel(struct zd_chip *chip)
+{
+ return chip->rf.channel;
+}
+u8 zd_chip_get_channel(struct zd_chip *chip);
+int zd_read_regdomain(struct zd_chip *chip, u8 *regdomain);
+void zd_get_e2p_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_read_mac_addr(struct zd_chip *chip, u8 *mac_addr);
+int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr);
+int zd_chip_switch_radio_on(struct zd_chip *chip);
+int zd_chip_switch_radio_off(struct zd_chip *chip);
+int zd_chip_enable_int(struct zd_chip *chip);
+void zd_chip_disable_int(struct zd_chip *chip);
+int zd_chip_enable_rx(struct zd_chip *chip);
+void zd_chip_disable_rx(struct zd_chip *chip);
+int zd_chip_enable_hwint(struct zd_chip *chip);
+int zd_chip_disable_hwint(struct zd_chip *chip);
+
+static inline int zd_get_encryption_type(struct zd_chip *chip, u32 *type)
+{
+ return zd_ioread32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_set_encryption_type(struct zd_chip *chip, u32 type)
+{
+ return zd_iowrite32(chip, CR_ENCRYPTION_TYPE, type);
+}
+
+static inline int zd_chip_get_basic_rates(struct zd_chip *chip, u16 *cr_rates)
+{
+ return zd_ioread16(chip, CR_BASIC_RATE_TBL, cr_rates);
+}
+
+int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates);
+
+static inline int zd_chip_set_rx_filter(struct zd_chip *chip, u32 filter)
+{
+ return zd_iowrite32(chip, CR_RX_FILTER, filter);
+}
+
+int zd_chip_lock_phy_regs(struct zd_chip *chip);
+int zd_chip_unlock_phy_regs(struct zd_chip *chip);
+
+enum led_status {
+ LED_OFF = 0,
+ LED_SCANNING = 1,
+ LED_ASSOCIATED = 2,
+};
+
+int zd_chip_control_leds(struct zd_chip *chip, enum led_status status);
+
+int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
+
+static inline int zd_get_beacon_interval(struct zd_chip *chip, u32 *interval)
+{
+ return zd_ioread32(chip, CR_BCN_INTERVAL, interval);
+}
+
+struct rx_status;
+
+u8 zd_rx_qual_percent(const void *rx_frame, unsigned int size,
+ const struct rx_status *status);
+u8 zd_rx_strength_percent(u8 rssi);
+
+u16 zd_rx_rate(const void *rx_frame, const struct rx_status *status);
+
+#endif /* _ZD_CHIP_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_def.h b/drivers/net/wireless/zd1211rw/zd_def.h
new file mode 100644
index 00000000000..a13ec72eb30
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_def.h
@@ -0,0 +1,54 @@
+/* zd_def.h
+ *
+ * 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
+ */
+
+#ifndef _ZD_DEF_H
+#define _ZD_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/stringify.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+
+#define dev_printk_f(level, dev, fmt, args...) \
+ dev_printk(level, dev, "%s() " fmt, __func__, ##args)
+
+#ifdef DEBUG
+# define dev_dbg_f(dev, fmt, args...) \
+ dev_printk_f(KERN_DEBUG, dev, fmt, ## args)
+#else
+# define dev_dbg_f(dev, fmt, args...) do { (void)(dev); } while (0)
+#endif /* DEBUG */
+
+#ifdef DEBUG
+# define ZD_ASSERT(x) \
+do { \
+ if (!(x)) { \
+ pr_debug("%s:%d ASSERT %s VIOLATED!\n", \
+ __FILE__, __LINE__, __stringify(x)); \
+ } \
+} while (0)
+#else
+# define ZD_ASSERT(x) do { } while (0)
+#endif
+
+#ifdef DEBUG
+# define ZD_MEMCLEAR(pointer, size) memset((pointer), 0xff, (size))
+#else
+# define ZD_MEMCLEAR(pointer, size) do { } while (0)
+#endif
+
+#endif /* _ZD_DEF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
new file mode 100644
index 00000000000..66905f7b61f
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c
@@ -0,0 +1,191 @@
+/* zd_ieee80211.c
+ *
+ * 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
+ */
+
+/*
+ * A lot of this code is generic and should be moved into the upper layers
+ * at some point.
+ */
+
+#include <linux/errno.h>
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_ieee80211.h"
+#include "zd_mac.h"
+
+static const struct channel_range channel_ranges[] = {
+ [0] = { 0, 0},
+ [ZD_REGDOMAIN_FCC] = { 1, 12},
+ [ZD_REGDOMAIN_IC] = { 1, 12},
+ [ZD_REGDOMAIN_ETSI] = { 1, 14},
+ [ZD_REGDOMAIN_JAPAN] = { 1, 14},
+ [ZD_REGDOMAIN_SPAIN] = { 1, 14},
+ [ZD_REGDOMAIN_FRANCE] = { 1, 14},
+ [ZD_REGDOMAIN_JAPAN_ADD] = {14, 15},
+};
+
+const struct channel_range *zd_channel_range(u8 regdomain)
+{
+ if (regdomain >= ARRAY_SIZE(channel_ranges))
+ regdomain = 0;
+ return &channel_ranges[regdomain];
+}
+
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel)
+{
+ const struct channel_range *range = zd_channel_range(regdomain);
+ return range->start <= channel && channel < range->end;
+}
+
+int zd_regdomain_supported(u8 regdomain)
+{
+ const struct channel_range *range = zd_channel_range(regdomain);
+ return range->start != 0;
+}
+
+/* Stores channel frequencies in MHz. */
+static const u16 channel_frequencies[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442, 2447,
+ 2452, 2457, 2462, 2467, 2472, 2484,
+};
+
+#define NUM_CHANNELS ARRAY_SIZE(channel_frequencies)
+
+static int compute_freq(struct iw_freq *freq, u32 mhz, u32 hz)
+{
+ u32 factor;
+
+ freq->e = 0;
+ if (mhz >= 1000000000U) {
+ pr_debug("zd1211 mhz %u to large\n", mhz);
+ freq->m = 0;
+ return -EINVAL;
+ }
+
+ factor = 1000;
+ while (mhz >= factor) {
+
+ freq->e += 1;
+ factor *= 10;
+ }
+
+ factor /= 1000U;
+ freq->m = mhz * (1000000U/factor) + hz/factor;
+
+ return 0;
+}
+
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel)
+{
+ if (channel > NUM_CHANNELS) {
+ freq->m = 0;
+ freq->e = 0;
+ return -EINVAL;
+ }
+ if (!channel) {
+ freq->m = 0;
+ freq->e = 0;
+ return -EINVAL;
+ }
+ return compute_freq(freq, channel_frequencies[channel-1], 0);
+}
+
+static int freq_to_mhz(const struct iw_freq *freq)
+{
+ u32 factor;
+ int e;
+
+ /* Such high frequencies are not supported. */
+ if (freq->e > 6)
+ return -EINVAL;
+
+ factor = 1;
+ for (e = freq->e; e > 0; --e) {
+ factor *= 10;
+ }
+ factor = 1000000U / factor;
+
+ if (freq->m % factor) {
+ return -EINVAL;
+ }
+
+ return freq->m / factor;
+}
+
+int zd_find_channel(u8 *channel, const struct iw_freq *freq)
+{
+ int i, r;
+ u32 mhz;
+
+ if (!(freq->flags & IW_FREQ_FIXED))
+ return 0;
+
+ if (freq->m < 1000) {
+ if (freq->m > NUM_CHANNELS || freq->m == 0)
+ return -EINVAL;
+ *channel = freq->m;
+ return 1;
+ }
+
+ r = freq_to_mhz(freq);
+ if (r < 0)
+ return r;
+ mhz = r;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (mhz == channel_frequencies[i]) {
+ *channel = i+1;
+ return 1;
+ }
+ }
+
+ return -EINVAL;
+}
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain)
+{
+ struct ieee80211_geo geo;
+ const struct channel_range *range;
+ int i;
+ u8 channel;
+
+ dev_dbg(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+ "regdomain %#04x\n", regdomain);
+
+ range = zd_channel_range(regdomain);
+ if (range->start == 0) {
+ dev_err(zd_mac_dev(zd_netdev_mac(ieee->dev)),
+ "zd1211 regdomain %#04x not supported\n",
+ regdomain);
+ return -EINVAL;
+ }
+
+ memset(&geo, 0, sizeof(geo));
+
+ for (i = 0, channel = range->start; channel < range->end; channel++) {
+ struct ieee80211_channel *chan = &geo.bg[i++];
+ chan->freq = channel_frequencies[channel - 1];
+ chan->channel = channel;
+ }
+
+ geo.bg_channels = i;
+ memcpy(geo.name, "XX ", 4);
+ ieee80211_set_geo(ieee, &geo);
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.h b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
new file mode 100644
index 00000000000..f63245b0d96
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.h
@@ -0,0 +1,85 @@
+#ifndef _ZD_IEEE80211_H
+#define _ZD_IEEE80211_H
+
+#include <net/ieee80211.h>
+#include "zd_types.h"
+
+/* Additional definitions from the standards.
+ */
+
+#define ZD_REGDOMAIN_FCC 0x10
+#define ZD_REGDOMAIN_IC 0x20
+#define ZD_REGDOMAIN_ETSI 0x30
+#define ZD_REGDOMAIN_SPAIN 0x31
+#define ZD_REGDOMAIN_FRANCE 0x32
+#define ZD_REGDOMAIN_JAPAN_ADD 0x40
+#define ZD_REGDOMAIN_JAPAN 0x41
+
+enum {
+ MIN_CHANNEL24 = 1,
+ MAX_CHANNEL24 = 14,
+};
+
+struct channel_range {
+ u8 start;
+ u8 end; /* exclusive (channel must be less than end) */
+};
+
+struct iw_freq;
+
+int zd_geo_init(struct ieee80211_device *ieee, u8 regdomain);
+
+const struct channel_range *zd_channel_range(u8 regdomain);
+int zd_regdomain_supports_channel(u8 regdomain, u8 channel);
+int zd_regdomain_supported(u8 regdomain);
+
+/* for 2.4 GHz band */
+int zd_channel_to_freq(struct iw_freq *freq, u8 channel);
+int zd_find_channel(u8 *channel, const struct iw_freq *freq);
+
+#define ZD_PLCP_SERVICE_LENGTH_EXTENSION 0x80
+
+struct ofdm_plcp_header {
+ u8 prefix[3];
+ __le16 service;
+} __attribute__((packed));
+
+static inline u8 zd_ofdm_plcp_header_rate(
+ const struct ofdm_plcp_header *header)
+{
+ return header->prefix[0] & 0xf;
+}
+
+#define ZD_OFDM_RATE_6M 0xb
+#define ZD_OFDM_RATE_9M 0xf
+#define ZD_OFDM_RATE_12M 0xa
+#define ZD_OFDM_RATE_18M 0xe
+#define ZD_OFDM_RATE_24M 0x9
+#define ZD_OFDM_RATE_36M 0xd
+#define ZD_OFDM_RATE_48M 0x8
+#define ZD_OFDM_RATE_54M 0xc
+
+struct cck_plcp_header {
+ u8 signal;
+ u8 service;
+ __le16 length;
+ __le16 crc16;
+};
+
+static inline u8 zd_cck_plcp_header_rate(const struct cck_plcp_header *header)
+{
+ return header->signal;
+}
+
+#define ZD_CCK_SIGNAL_1M 0x0a
+#define ZD_CCK_SIGNAL_2M 0x14
+#define ZD_CCK_SIGNAL_5M5 0x37
+#define ZD_CCK_SIGNAL_11M 0x6e
+
+enum ieee80211_std {
+ IEEE80211B = 0x01,
+ IEEE80211A = 0x02,
+ IEEE80211G = 0x04,
+};
+
+#endif /* _ZD_IEEE80211_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
new file mode 100644
index 00000000000..2d12837052b
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -0,0 +1,1132 @@
+/* zd_mac.c
+ *
+ * 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/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <linux/usb.h>
+#include <linux/jiffies.h>
+#include <net/ieee80211_radiotap.h>
+
+#include "zd_def.h"
+#include "zd_chip.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+#include "zd_netdev.h"
+#include "zd_rf.h"
+#include "zd_util.h"
+
+static void ieee_init(struct ieee80211_device *ieee);
+static void softmac_init(struct ieee80211softmac_device *sm);
+
+static void housekeeping_init(struct zd_mac *mac);
+static void housekeeping_enable(struct zd_mac *mac);
+static void housekeeping_disable(struct zd_mac *mac);
+
+int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+
+ memset(mac, 0, sizeof(*mac));
+ spin_lock_init(&mac->lock);
+ mac->netdev = netdev;
+
+ ieee_init(ieee);
+ softmac_init(ieee80211_priv(netdev));
+ zd_chip_init(&mac->chip, netdev, intf);
+ housekeeping_init(mac);
+ return 0;
+}
+
+static int reset_channel(struct zd_mac *mac)
+{
+ int r;
+ unsigned long flags;
+ const struct channel_range *range;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ range = zd_channel_range(mac->regdomain);
+ if (!range->start) {
+ r = -EINVAL;
+ goto out;
+ }
+ mac->requested_channel = range->start;
+ r = 0;
+out:
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return r;
+}
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type)
+{
+ int r;
+ struct zd_chip *chip = &mac->chip;
+ u8 addr[ETH_ALEN];
+ u8 default_regdomain;
+
+ r = zd_chip_enable_int(chip);
+ if (r)
+ goto out;
+ r = zd_chip_init_hw(chip, device_type);
+ if (r)
+ goto disable_int;
+
+ zd_get_e2p_mac_addr(chip, addr);
+ r = zd_write_mac_addr(chip, addr);
+ if (r)
+ goto disable_int;
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ memcpy(mac->netdev->dev_addr, addr, ETH_ALEN);
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_read_regdomain(chip, &default_regdomain);
+ if (r)
+ goto disable_int;
+ if (!zd_regdomain_supported(default_regdomain)) {
+ dev_dbg_f(zd_mac_dev(mac),
+ "Regulatory Domain %#04x is not supported.\n",
+ default_regdomain);
+ r = -EINVAL;
+ goto disable_int;
+ }
+ spin_lock_irq(&mac->lock);
+ mac->regdomain = mac->default_regdomain = default_regdomain;
+ spin_unlock_irq(&mac->lock);
+ r = reset_channel(mac);
+ if (r)
+ goto disable_int;
+
+ /* We must inform the device that we are doing encryption/decryption in
+ * software at the moment. */
+ r = zd_set_encryption_type(chip, ENC_SNIFFER);
+ if (r)
+ goto disable_int;
+
+ r = zd_geo_init(zd_mac_to_ieee80211(mac), mac->regdomain);
+ if (r)
+ goto disable_int;
+
+ r = 0;
+disable_int:
+ zd_chip_disable_int(chip);
+out:
+ return r;
+}
+
+void zd_mac_clear(struct zd_mac *mac)
+{
+ zd_chip_clear(&mac->chip);
+ ZD_ASSERT(!spin_is_locked(&mac->lock));
+ ZD_MEMCLEAR(mac, sizeof(struct zd_mac));
+}
+
+static int reset_mode(struct zd_mac *mac)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct zd_ioreq32 ioreqs[3] = {
+ { CR_RX_FILTER, STA_RX_FILTER },
+ { CR_SNIFFER_ON, 0U },
+ };
+
+ if (ieee->iw_mode == IW_MODE_MONITOR) {
+ ioreqs[0].value = 0xffffffff;
+ ioreqs[1].value = 0x1;
+ ioreqs[2].value = ENC_SNIFFER;
+ }
+
+ return zd_iowrite32a(&mac->chip, ioreqs, 3);
+}
+
+int zd_mac_open(struct net_device *netdev)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+ int r;
+
+ r = zd_chip_enable_int(chip);
+ if (r < 0)
+ goto out;
+
+ r = zd_chip_set_basic_rates(chip, CR_RATES_80211B | CR_RATES_80211G);
+ if (r < 0)
+ goto disable_int;
+ r = reset_mode(mac);
+ if (r)
+ goto disable_int;
+ r = zd_chip_switch_radio_on(chip);
+ if (r < 0)
+ goto disable_int;
+ r = zd_chip_set_channel(chip, mac->requested_channel);
+ if (r < 0)
+ goto disable_radio;
+ r = zd_chip_enable_rx(chip);
+ if (r < 0)
+ goto disable_radio;
+ r = zd_chip_enable_hwint(chip);
+ if (r < 0)
+ goto disable_rx;
+
+ housekeeping_enable(mac);
+ ieee80211softmac_start(netdev);
+ return 0;
+disable_rx:
+ zd_chip_disable_rx(chip);
+disable_radio:
+ zd_chip_switch_radio_off(chip);
+disable_int:
+ zd_chip_disable_int(chip);
+out:
+ return r;
+}
+
+int zd_mac_stop(struct net_device *netdev)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+
+ netif_stop_queue(netdev);
+
+ /*
+ * The order here deliberately is a little different from the open()
+ * method, since we need to make sure there is no opportunity for RX
+ * frames to be processed by softmac after we have stopped it.
+ */
+
+ zd_chip_disable_rx(chip);
+ housekeeping_disable(mac);
+ ieee80211softmac_stop(netdev);
+
+ zd_chip_disable_hwint(chip);
+ zd_chip_switch_radio_off(chip);
+ zd_chip_disable_int(chip);
+
+ return 0;
+}
+
+int zd_mac_set_mac_address(struct net_device *netdev, void *p)
+{
+ int r;
+ unsigned long flags;
+ struct sockaddr *addr = p;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_chip *chip = &mac->chip;
+
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ dev_dbg_f(zd_mac_dev(mac),
+ "Setting MAC to " MAC_FMT "\n", MAC_ARG(addr->sa_data));
+
+ r = zd_write_mac_addr(chip, addr->sa_data);
+ if (r)
+ return r;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ memcpy(netdev->dev_addr, addr->sa_data, ETH_ALEN);
+ spin_unlock_irqrestore(&mac->lock, flags);
+
+ return 0;
+}
+
+int zd_mac_set_regdomain(struct zd_mac *mac, u8 regdomain)
+{
+ int r;
+ u8 channel;
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ if (regdomain == 0) {
+ regdomain = mac->default_regdomain;
+ }
+ if (!zd_regdomain_supported(regdomain)) {
+ spin_unlock_irq(&mac->lock);
+ return -EINVAL;
+ }
+ mac->regdomain = regdomain;
+ channel = mac->requested_channel;
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_geo_init(zd_mac_to_ieee80211(mac), regdomain);
+ if (r)
+ return r;
+ if (!zd_regdomain_supports_channel(regdomain, channel)) {
+ r = reset_channel(mac);
+ if (r)
+ return r;
+ }
+
+ return 0;
+}
+
+u8 zd_mac_get_regdomain(struct zd_mac *mac)
+{
+ unsigned long flags;
+ u8 regdomain;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ regdomain = mac->regdomain;
+ spin_unlock_irqrestore(&mac->lock, flags);
+ return regdomain;
+}
+
+static void set_channel(struct net_device *netdev, u8 channel)
+{
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+
+ dev_dbg_f(zd_mac_dev(mac), "channel %d\n", channel);
+
+ zd_chip_set_channel(&mac->chip, channel);
+}
+
+/* TODO: Should not work in Managed mode. */
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel)
+{
+ unsigned long lock_flags;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ if (ieee->iw_mode == IW_MODE_INFRA)
+ return -EPERM;
+
+ spin_lock_irqsave(&mac->lock, lock_flags);
+ if (!zd_regdomain_supports_channel(mac->regdomain, channel)) {
+ spin_unlock_irqrestore(&mac->lock, lock_flags);
+ return -EINVAL;
+ }
+ mac->requested_channel = channel;
+ spin_unlock_irqrestore(&mac->lock, lock_flags);
+ if (netif_running(mac->netdev))
+ return zd_chip_set_channel(&mac->chip, channel);
+ else
+ return 0;
+}
+
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags)
+{
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+
+ *channel = zd_chip_get_channel(&mac->chip);
+ if (ieee->iw_mode != IW_MODE_INFRA) {
+ spin_lock_irq(&mac->lock);
+ *flags = *channel == mac->requested_channel ?
+ MAC_FIXED_CHANNEL : 0;
+ spin_unlock(&mac->lock);
+ } else {
+ *flags = 0;
+ }
+ dev_dbg_f(zd_mac_dev(mac), "channel %u flags %u\n", *channel, *flags);
+ return 0;
+}
+
+/* If wrong rate is given, we are falling back to the slowest rate: 1MBit/s */
+static u8 cs_typed_rate(u8 cs_rate)
+{
+ static const u8 typed_rates[16] = {
+ [ZD_CS_CCK_RATE_1M] = ZD_CS_CCK|ZD_CS_CCK_RATE_1M,
+ [ZD_CS_CCK_RATE_2M] = ZD_CS_CCK|ZD_CS_CCK_RATE_2M,
+ [ZD_CS_CCK_RATE_5_5M] = ZD_CS_CCK|ZD_CS_CCK_RATE_5_5M,
+ [ZD_CS_CCK_RATE_11M] = ZD_CS_CCK|ZD_CS_CCK_RATE_11M,
+ [ZD_OFDM_RATE_6M] = ZD_CS_OFDM|ZD_OFDM_RATE_6M,
+ [ZD_OFDM_RATE_9M] = ZD_CS_OFDM|ZD_OFDM_RATE_9M,
+ [ZD_OFDM_RATE_12M] = ZD_CS_OFDM|ZD_OFDM_RATE_12M,
+ [ZD_OFDM_RATE_18M] = ZD_CS_OFDM|ZD_OFDM_RATE_18M,
+ [ZD_OFDM_RATE_24M] = ZD_CS_OFDM|ZD_OFDM_RATE_24M,
+ [ZD_OFDM_RATE_36M] = ZD_CS_OFDM|ZD_OFDM_RATE_36M,
+ [ZD_OFDM_RATE_48M] = ZD_CS_OFDM|ZD_OFDM_RATE_48M,
+ [ZD_OFDM_RATE_54M] = ZD_CS_OFDM|ZD_OFDM_RATE_54M,
+ };
+
+ ZD_ASSERT(ZD_CS_RATE_MASK == 0x0f);
+ return typed_rates[cs_rate & ZD_CS_RATE_MASK];
+}
+
+/* Fallback to lowest rate, if rate is unknown. */
+static u8 rate_to_cs_rate(u8 rate)
+{
+ switch (rate) {
+ case IEEE80211_CCK_RATE_2MB:
+ return ZD_CS_CCK_RATE_2M;
+ case IEEE80211_CCK_RATE_5MB:
+ return ZD_CS_CCK_RATE_5_5M;
+ case IEEE80211_CCK_RATE_11MB:
+ return ZD_CS_CCK_RATE_11M;
+ case IEEE80211_OFDM_RATE_6MB:
+ return ZD_OFDM_RATE_6M;
+ case IEEE80211_OFDM_RATE_9MB:
+ return ZD_OFDM_RATE_9M;
+ case IEEE80211_OFDM_RATE_12MB:
+ return ZD_OFDM_RATE_12M;
+ case IEEE80211_OFDM_RATE_18MB:
+ return ZD_OFDM_RATE_18M;
+ case IEEE80211_OFDM_RATE_24MB:
+ return ZD_OFDM_RATE_24M;
+ case IEEE80211_OFDM_RATE_36MB:
+ return ZD_OFDM_RATE_36M;
+ case IEEE80211_OFDM_RATE_48MB:
+ return ZD_OFDM_RATE_48M;
+ case IEEE80211_OFDM_RATE_54MB:
+ return ZD_OFDM_RATE_54M;
+ }
+ return ZD_CS_CCK_RATE_1M;
+}
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode)
+{
+ struct ieee80211_device *ieee;
+
+ switch (mode) {
+ case IW_MODE_AUTO:
+ case IW_MODE_ADHOC:
+ case IW_MODE_INFRA:
+ mac->netdev->type = ARPHRD_ETHER;
+ break;
+ case IW_MODE_MONITOR:
+ mac->netdev->type = ARPHRD_IEEE80211_RADIOTAP;
+ break;
+ default:
+ dev_dbg_f(zd_mac_dev(mac), "wrong mode %u\n", mode);
+ return -EINVAL;
+ }
+
+ ieee = zd_mac_to_ieee80211(mac);
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&ieee->lock);
+ ieee->iw_mode = mode;
+ spin_unlock_irq(&ieee->lock);
+
+ if (netif_running(mac->netdev))
+ return reset_mode(mac);
+
+ return 0;
+}
+
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode)
+{
+ unsigned long flags;
+ struct ieee80211_device *ieee;
+
+ ieee = zd_mac_to_ieee80211(mac);
+ spin_lock_irqsave(&ieee->lock, flags);
+ *mode = ieee->iw_mode;
+ spin_unlock_irqrestore(&ieee->lock, flags);
+ return 0;
+}
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range)
+{
+ int i;
+ const struct channel_range *channel_range;
+ u8 regdomain;
+
+ memset(range, 0, sizeof(*range));
+
+ /* FIXME: Not so important and depends on the mode. For 802.11g
+ * usually this value is used. It seems to be that Bit/s number is
+ * given here.
+ */
+ range->throughput = 27 * 1000 * 1000;
+
+ range->max_qual.qual = 100;
+ range->max_qual.level = 100;
+
+ /* FIXME: Needs still to be tuned. */
+ range->avg_qual.qual = 71;
+ range->avg_qual.level = 80;
+
+ /* FIXME: depends on standard? */
+ range->min_rts = 256;
+ range->max_rts = 2346;
+
+ range->min_frag = MIN_FRAG_THRESHOLD;
+ range->max_frag = MAX_FRAG_THRESHOLD;
+
+ range->max_encoding_tokens = WEP_KEYS;
+ range->num_encoding_sizes = 2;
+ range->encoding_size[0] = 5;
+ range->encoding_size[1] = WEP_KEY_LEN;
+
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 20;
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&mac->lock);
+ regdomain = mac->regdomain;
+ spin_unlock_irq(&mac->lock);
+ channel_range = zd_channel_range(regdomain);
+
+ range->num_channels = channel_range->end - channel_range->start;
+ range->old_num_channels = range->num_channels;
+ range->num_frequency = range->num_channels;
+ range->old_num_frequency = range->num_frequency;
+
+ for (i = 0; i < range->num_frequency; i++) {
+ struct iw_freq *freq = &range->freq[i];
+ freq->i = channel_range->start + i;
+ zd_channel_to_freq(freq, freq->i);
+ }
+
+ return 0;
+}
+
+static int zd_calc_tx_length_us(u8 *service, u8 cs_rate, u16 tx_length)
+{
+ static const u8 rate_divisor[] = {
+ [ZD_CS_CCK_RATE_1M] = 1,
+ [ZD_CS_CCK_RATE_2M] = 2,
+ [ZD_CS_CCK_RATE_5_5M] = 11, /* bits must be doubled */
+ [ZD_CS_CCK_RATE_11M] = 11,
+ [ZD_OFDM_RATE_6M] = 6,
+ [ZD_OFDM_RATE_9M] = 9,
+ [ZD_OFDM_RATE_12M] = 12,
+ [ZD_OFDM_RATE_18M] = 18,
+ [ZD_OFDM_RATE_24M] = 24,
+ [ZD_OFDM_RATE_36M] = 36,
+ [ZD_OFDM_RATE_48M] = 48,
+ [ZD_OFDM_RATE_54M] = 54,
+ };
+
+ u32 bits = (u32)tx_length * 8;
+ u32 divisor;
+
+ divisor = rate_divisor[cs_rate];
+ if (divisor == 0)
+ return -EINVAL;
+
+ switch (cs_rate) {
+ case ZD_CS_CCK_RATE_5_5M:
+ bits = (2*bits) + 10; /* round up to the next integer */
+ break;
+ case ZD_CS_CCK_RATE_11M:
+ if (service) {
+ u32 t = bits % 11;
+ *service &= ~ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+ if (0 < t && t <= 3) {
+ *service |= ZD_PLCP_SERVICE_LENGTH_EXTENSION;
+ }
+ }
+ bits += 10; /* round up to the next integer */
+ break;
+ }
+
+ return bits/divisor;
+}
+
+enum {
+ R2M_SHORT_PREAMBLE = 0x01,
+ R2M_11A = 0x02,
+};
+
+static u8 cs_rate_to_modulation(u8 cs_rate, int flags)
+{
+ u8 modulation;
+
+ modulation = cs_typed_rate(cs_rate);
+ if (flags & R2M_SHORT_PREAMBLE) {
+ switch (ZD_CS_RATE(modulation)) {
+ case ZD_CS_CCK_RATE_2M:
+ case ZD_CS_CCK_RATE_5_5M:
+ case ZD_CS_CCK_RATE_11M:
+ modulation |= ZD_CS_CCK_PREA_SHORT;
+ return modulation;
+ }
+ }
+ if (flags & R2M_11A) {
+ if (ZD_CS_TYPE(modulation) == ZD_CS_OFDM)
+ modulation |= ZD_CS_OFDM_MODE_11A;
+ }
+ return modulation;
+}
+
+static void cs_set_modulation(struct zd_mac *mac, struct zd_ctrlset *cs,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct ieee80211softmac_device *softmac = ieee80211_priv(mac->netdev);
+ u16 ftype = WLAN_FC_GET_TYPE(le16_to_cpu(hdr->frame_ctl));
+ u8 rate, cs_rate;
+ int is_mgt = (ftype == IEEE80211_FTYPE_MGMT) != 0;
+
+ /* FIXME: 802.11a? short preamble? */
+ rate = ieee80211softmac_suggest_txrate(softmac,
+ is_multicast_ether_addr(hdr->addr1), is_mgt);
+
+ cs_rate = rate_to_cs_rate(rate);
+ cs->modulation = cs_rate_to_modulation(cs_rate, 0);
+}
+
+static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
+ struct ieee80211_hdr_4addr *header)
+{
+ unsigned int tx_length = le16_to_cpu(cs->tx_length);
+ u16 fctl = le16_to_cpu(header->frame_ctl);
+ u16 ftype = WLAN_FC_GET_TYPE(fctl);
+ u16 stype = WLAN_FC_GET_STYPE(fctl);
+
+ /*
+ * CONTROL:
+ * - start at 0x00
+ * - if fragment 0, enable bit 0
+ * - if backoff needed, enable bit 0
+ * - if burst (backoff not needed) disable bit 0
+ * - if multicast, enable bit 1
+ * - if PS-POLL frame, enable bit 2
+ * - if in INDEPENDENT_BSS mode and zd1205_DestPowerSave, then enable
+ * bit 4 (FIXME: wtf)
+ * - if frag_len > RTS threshold, set bit 5 as long if it isnt
+ * multicast or mgt
+ * - if bit 5 is set, and we are in OFDM mode, unset bit 5 and set bit
+ * 7
+ */
+
+ cs->control = 0;
+
+ /* First fragment */
+ if (WLAN_GET_SEQ_FRAG(le16_to_cpu(header->seq_ctl)) == 0)
+ cs->control |= ZD_CS_NEED_RANDOM_BACKOFF;
+
+ /* Multicast */
+ if (is_multicast_ether_addr(header->addr1))
+ cs->control |= ZD_CS_MULTICAST;
+
+ /* PS-POLL */
+ if (stype == IEEE80211_STYPE_PSPOLL)
+ cs->control |= ZD_CS_PS_POLL_FRAME;
+
+ if (!is_multicast_ether_addr(header->addr1) &&
+ ftype != IEEE80211_FTYPE_MGMT &&
+ tx_length > zd_netdev_ieee80211(mac->netdev)->rts)
+ {
+ /* FIXME: check the logic */
+ if (ZD_CS_TYPE(cs->modulation) == ZD_CS_OFDM) {
+ /* 802.11g */
+ cs->control |= ZD_CS_SELF_CTS;
+ } else { /* 802.11b */
+ cs->control |= ZD_CS_RTS;
+ }
+ }
+
+ /* FIXME: Management frame? */
+}
+
+static int fill_ctrlset(struct zd_mac *mac,
+ struct ieee80211_txb *txb,
+ int frag_num)
+{
+ int r;
+ struct sk_buff *skb = txb->fragments[frag_num];
+ struct ieee80211_hdr_4addr *hdr =
+ (struct ieee80211_hdr_4addr *) skb->data;
+ unsigned int frag_len = skb->len + IEEE80211_FCS_LEN;
+ unsigned int next_frag_len;
+ unsigned int packet_length;
+ struct zd_ctrlset *cs = (struct zd_ctrlset *)
+ skb_push(skb, sizeof(struct zd_ctrlset));
+
+ if (frag_num+1 < txb->nr_frags) {
+ next_frag_len = txb->fragments[frag_num+1]->len +
+ IEEE80211_FCS_LEN;
+ } else {
+ next_frag_len = 0;
+ }
+ ZD_ASSERT(frag_len <= 0xffff);
+ ZD_ASSERT(next_frag_len <= 0xffff);
+
+ cs_set_modulation(mac, cs, hdr);
+
+ cs->tx_length = cpu_to_le16(frag_len);
+
+ cs_set_control(mac, cs, hdr);
+
+ packet_length = frag_len + sizeof(struct zd_ctrlset) + 10;
+ ZD_ASSERT(packet_length <= 0xffff);
+ /* ZD1211B: Computing the length difference this way, gives us
+ * flexibility to compute the packet length.
+ */
+ cs->packet_length = cpu_to_le16(mac->chip.is_zd1211b ?
+ packet_length - frag_len : packet_length);
+
+ /*
+ * CURRENT LENGTH:
+ * - transmit frame length in microseconds
+ * - seems to be derived from frame length
+ * - see Cal_Us_Service() in zdinlinef.h
+ * - if macp->bTxBurstEnable is enabled, then multiply by 4
+ * - bTxBurstEnable is never set in the vendor driver
+ *
+ * SERVICE:
+ * - "for PLCP configuration"
+ * - always 0 except in some situations at 802.11b 11M
+ * - see line 53 of zdinlinef.h
+ */
+ cs->service = 0;
+ r = zd_calc_tx_length_us(&cs->service, ZD_CS_RATE(cs->modulation),
+ le16_to_cpu(cs->tx_length));
+ if (r < 0)
+ return r;
+ cs->current_length = cpu_to_le16(r);
+
+ if (next_frag_len == 0) {
+ cs->next_frame_length = 0;
+ } else {
+ r = zd_calc_tx_length_us(NULL, ZD_CS_RATE(cs->modulation),
+ next_frag_len);
+ if (r < 0)
+ return r;
+ cs->next_frame_length = cpu_to_le16(r);
+ }
+
+ return 0;
+}
+
+static int zd_mac_tx(struct zd_mac *mac, struct ieee80211_txb *txb, int pri)
+{
+ int i, r;
+
+ for (i = 0; i < txb->nr_frags; i++) {
+ struct sk_buff *skb = txb->fragments[i];
+
+ r = fill_ctrlset(mac, txb, i);
+ if (r)
+ return r;
+ r = zd_usb_tx(&mac->chip.usb, skb->data, skb->len);
+ if (r)
+ return r;
+ }
+
+ /* FIXME: shouldn't this be handled by the upper layers? */
+ mac->netdev->trans_start = jiffies;
+
+ ieee80211_txb_free(txb);
+ return 0;
+}
+
+struct zd_rt_hdr {
+ struct ieee80211_radiotap_header rt_hdr;
+ u8 rt_flags;
+ u8 rt_rate;
+ u16 rt_channel;
+ u16 rt_chbitmask;
+};
+
+static void fill_rt_header(void *buffer, struct zd_mac *mac,
+ const struct ieee80211_rx_stats *stats,
+ const struct rx_status *status)
+{
+ struct zd_rt_hdr *hdr = buffer;
+
+ hdr->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION;
+ hdr->rt_hdr.it_pad = 0;
+ hdr->rt_hdr.it_len = cpu_to_le16(sizeof(struct zd_rt_hdr));
+ hdr->rt_hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_RATE));
+
+ hdr->rt_flags = 0;
+ if (status->decryption_type & (ZD_RX_WEP64|ZD_RX_WEP128|ZD_RX_WEP256))
+ hdr->rt_flags |= IEEE80211_RADIOTAP_F_WEP;
+
+ hdr->rt_rate = stats->rate / 5;
+
+ /* FIXME: 802.11a */
+ hdr->rt_channel = cpu_to_le16(ieee80211chan2mhz(
+ _zd_chip_get_channel(&mac->chip)));
+ hdr->rt_chbitmask = cpu_to_le16(IEEE80211_CHAN_2GHZ |
+ ((status->frame_status & ZD_RX_FRAME_MODULATION_MASK) ==
+ ZD_RX_OFDM ? IEEE80211_CHAN_OFDM : IEEE80211_CHAN_CCK));
+}
+
+/* Returns 1 if the data packet is for us and 0 otherwise. */
+static int is_data_packet_for_us(struct ieee80211_device *ieee,
+ struct ieee80211_hdr_4addr *hdr)
+{
+ struct net_device *netdev = ieee->dev;
+ u16 fc = le16_to_cpu(hdr->frame_ctl);
+
+ ZD_ASSERT(WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA);
+
+ switch (ieee->iw_mode) {
+ case IW_MODE_ADHOC:
+ if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 ||
+ memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0)
+ return 0;
+ break;
+ case IW_MODE_AUTO:
+ case IW_MODE_INFRA:
+ if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) !=
+ IEEE80211_FCTL_FROMDS ||
+ memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0)
+ return 0;
+ break;
+ default:
+ ZD_ASSERT(ieee->iw_mode != IW_MODE_MONITOR);
+ return 0;
+ }
+
+ return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 ||
+ is_multicast_ether_addr(hdr->addr1) ||
+ (netdev->flags & IFF_PROMISC);
+}
+
+/* Filters receiving packets. If it returns 1 send it to ieee80211_rx, if 0
+ * return. If an error is detected -EINVAL is returned. ieee80211_rx_mgt() is
+ * called here.
+ *
+ * It has been based on ieee80211_rx_any.
+ */
+static int filter_rx(struct ieee80211_device *ieee,
+ const u8 *buffer, unsigned int length,
+ struct ieee80211_rx_stats *stats)
+{
+ struct ieee80211_hdr_4addr *hdr;
+ u16 fc;
+
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ return 1;
+
+ hdr = (struct ieee80211_hdr_4addr *)buffer;
+ fc = le16_to_cpu(hdr->frame_ctl);
+ if ((fc & IEEE80211_FCTL_VERS) != 0)
+ return -EINVAL;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_MGMT:
+ if (length < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+ ieee80211_rx_mgt(ieee, hdr, stats);
+ return 0;
+ case IEEE80211_FTYPE_CTL:
+ /* Ignore invalid short buffers */
+ return 0;
+ case IEEE80211_FTYPE_DATA:
+ if (length < sizeof(struct ieee80211_hdr_3addr))
+ return -EINVAL;
+ return is_data_packet_for_us(ieee, hdr);
+ }
+
+ return -EINVAL;
+}
+
+static void update_qual_rssi(struct zd_mac *mac,
+ const u8 *buffer, unsigned int length,
+ u8 qual_percent, u8 rssi_percent)
+{
+ unsigned long flags;
+ struct ieee80211_hdr_3addr *hdr;
+ int i;
+
+ hdr = (struct ieee80211_hdr_3addr *)buffer;
+ if (length < offsetof(struct ieee80211_hdr_3addr, addr3))
+ return;
+ if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0)
+ return;
+
+ spin_lock_irqsave(&mac->lock, flags);
+ i = mac->stats_count % ZD_MAC_STATS_BUFFER_SIZE;
+ mac->qual_buffer[i] = qual_percent;
+ mac->rssi_buffer[i] = rssi_percent;
+ mac->stats_count++;
+ spin_unlock_irqrestore(&mac->lock, flags);
+}
+
+static int fill_rx_stats(struct ieee80211_rx_stats *stats,
+ const struct rx_status **pstatus,
+ struct zd_mac *mac,
+ const u8 *buffer, unsigned int length)
+{
+ const struct rx_status *status;
+
+ *pstatus = status = zd_tail(buffer, length, sizeof(struct rx_status));
+ if (status->frame_status & ZD_RX_ERROR) {
+ /* FIXME: update? */
+ return -EINVAL;
+ }
+ memset(stats, 0, sizeof(struct ieee80211_rx_stats));
+ stats->len = length - (ZD_PLCP_HEADER_SIZE + IEEE80211_FCS_LEN +
+ + sizeof(struct rx_status));
+ /* FIXME: 802.11a */
+ stats->freq = IEEE80211_24GHZ_BAND;
+ stats->received_channel = _zd_chip_get_channel(&mac->chip);
+ stats->rssi = zd_rx_strength_percent(status->signal_strength);
+ stats->signal = zd_rx_qual_percent(buffer,
+ length - sizeof(struct rx_status),
+ status);
+ stats->mask = IEEE80211_STATMASK_RSSI | IEEE80211_STATMASK_SIGNAL;
+ stats->rate = zd_rx_rate(buffer, status);
+ if (stats->rate)
+ stats->mask |= IEEE80211_STATMASK_RATE;
+
+ return 0;
+}
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length)
+{
+ int r;
+ struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac);
+ struct ieee80211_rx_stats stats;
+ const struct rx_status *status;
+ struct sk_buff *skb;
+
+ if (length < ZD_PLCP_HEADER_SIZE + IEEE80211_1ADDR_LEN +
+ IEEE80211_FCS_LEN + sizeof(struct rx_status))
+ return -EINVAL;
+
+ r = fill_rx_stats(&stats, &status, mac, buffer, length);
+ if (r)
+ return r;
+
+ length -= ZD_PLCP_HEADER_SIZE+IEEE80211_FCS_LEN+
+ sizeof(struct rx_status);
+ buffer += ZD_PLCP_HEADER_SIZE;
+
+ update_qual_rssi(mac, buffer, length, stats.signal, stats.rssi);
+
+ r = filter_rx(ieee, buffer, length, &stats);
+ if (r <= 0)
+ return r;
+
+ skb = dev_alloc_skb(sizeof(struct zd_rt_hdr) + length);
+ if (!skb)
+ return -ENOMEM;
+ if (ieee->iw_mode == IW_MODE_MONITOR)
+ fill_rt_header(skb_put(skb, sizeof(struct zd_rt_hdr)), mac,
+ &stats, status);
+ memcpy(skb_put(skb, length), buffer, length);
+
+ r = ieee80211_rx(ieee, skb, &stats);
+ if (!r) {
+ ZD_ASSERT(in_irq());
+ dev_kfree_skb_irq(skb);
+ }
+ return 0;
+}
+
+static int netdev_tx(struct ieee80211_txb *txb, struct net_device *netdev,
+ int pri)
+{
+ return zd_mac_tx(zd_netdev_mac(netdev), txb, pri);
+}
+
+static void set_security(struct net_device *netdev,
+ struct ieee80211_security *sec)
+{
+ struct ieee80211_device *ieee = zd_netdev_ieee80211(netdev);
+ struct ieee80211_security *secinfo = &ieee->sec;
+ int keyidx;
+
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+
+ for (keyidx = 0; keyidx<WEP_KEYS; keyidx++)
+ if (sec->flags & (1<<keyidx)) {
+ secinfo->encode_alg[keyidx] = sec->encode_alg[keyidx];
+ secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx];
+ memcpy(secinfo->keys[keyidx], sec->keys[keyidx],
+ SCM_KEY_LEN);
+ }
+
+ if (sec->flags & SEC_ACTIVE_KEY) {
+ secinfo->active_key = sec->active_key;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .active_key = %d\n", sec->active_key);
+ }
+ if (sec->flags & SEC_UNICAST_GROUP) {
+ secinfo->unicast_uses_group = sec->unicast_uses_group;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .unicast_uses_group = %d\n",
+ sec->unicast_uses_group);
+ }
+ if (sec->flags & SEC_LEVEL) {
+ secinfo->level = sec->level;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .level = %d\n", sec->level);
+ }
+ if (sec->flags & SEC_ENABLED) {
+ secinfo->enabled = sec->enabled;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .enabled = %d\n", sec->enabled);
+ }
+ if (sec->flags & SEC_ENCRYPT) {
+ secinfo->encrypt = sec->encrypt;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .encrypt = %d\n", sec->encrypt);
+ }
+ if (sec->flags & SEC_AUTH_MODE) {
+ secinfo->auth_mode = sec->auth_mode;
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)),
+ " .auth_mode = %d\n", sec->auth_mode);
+ }
+}
+
+static void ieee_init(struct ieee80211_device *ieee)
+{
+ ieee->mode = IEEE_B | IEEE_G;
+ ieee->freq_band = IEEE80211_24GHZ_BAND;
+ ieee->modulation = IEEE80211_OFDM_MODULATION | IEEE80211_CCK_MODULATION;
+ ieee->tx_headroom = sizeof(struct zd_ctrlset);
+ ieee->set_security = set_security;
+ ieee->hard_start_xmit = netdev_tx;
+
+ /* Software encryption/decryption for now */
+ ieee->host_build_iv = 0;
+ ieee->host_encrypt = 1;
+ ieee->host_decrypt = 1;
+
+ /* FIXME: default to managed mode, until ieee80211 and zd1211rw can
+ * correctly support AUTO */
+ ieee->iw_mode = IW_MODE_INFRA;
+}
+
+static void softmac_init(struct ieee80211softmac_device *sm)
+{
+ sm->set_channel = set_channel;
+}
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev)
+{
+ struct zd_mac *mac = zd_netdev_mac(ndev);
+ struct iw_statistics *iw_stats = &mac->iw_stats;
+ unsigned int i, count, qual_total, rssi_total;
+
+ memset(iw_stats, 0, sizeof(struct iw_statistics));
+ /* We are not setting the status, because ieee->state is not updated
+ * at all and this driver doesn't track authentication state.
+ */
+ spin_lock_irq(&mac->lock);
+ count = mac->stats_count < ZD_MAC_STATS_BUFFER_SIZE ?
+ mac->stats_count : ZD_MAC_STATS_BUFFER_SIZE;
+ qual_total = rssi_total = 0;
+ for (i = 0; i < count; i++) {
+ qual_total += mac->qual_buffer[i];
+ rssi_total += mac->rssi_buffer[i];
+ }
+ spin_unlock_irq(&mac->lock);
+ iw_stats->qual.updated = IW_QUAL_NOISE_INVALID;
+ if (count > 0) {
+ iw_stats->qual.qual = qual_total / count;
+ iw_stats->qual.level = rssi_total / count;
+ iw_stats->qual.updated |=
+ IW_QUAL_QUAL_UPDATED|IW_QUAL_LEVEL_UPDATED;
+ } else {
+ iw_stats->qual.updated |=
+ IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID;
+ }
+ /* TODO: update counter */
+ return iw_stats;
+}
+
+#ifdef DEBUG
+static const char* decryption_types[] = {
+ [ZD_RX_NO_WEP] = "none",
+ [ZD_RX_WEP64] = "WEP64",
+ [ZD_RX_TKIP] = "TKIP",
+ [ZD_RX_AES] = "AES",
+ [ZD_RX_WEP128] = "WEP128",
+ [ZD_RX_WEP256] = "WEP256",
+};
+
+static const char *decryption_type_string(u8 type)
+{
+ const char *s;
+
+ if (type < ARRAY_SIZE(decryption_types)) {
+ s = decryption_types[type];
+ } else {
+ s = NULL;
+ }
+ return s ? s : "unknown";
+}
+
+static int is_ofdm(u8 frame_status)
+{
+ return (frame_status & ZD_RX_OFDM);
+}
+
+void zd_dump_rx_status(const struct rx_status *status)
+{
+ const char* modulation;
+ u8 quality;
+
+ if (is_ofdm(status->frame_status)) {
+ modulation = "ofdm";
+ quality = status->signal_quality_ofdm;
+ } else {
+ modulation = "cck";
+ quality = status->signal_quality_cck;
+ }
+ pr_debug("rx status %s strength %#04x qual %#04x decryption %s\n",
+ modulation, status->signal_strength, quality,
+ decryption_type_string(status->decryption_type));
+ if (status->frame_status & ZD_RX_ERROR) {
+ pr_debug("rx error %s%s%s%s%s%s\n",
+ (status->frame_status & ZD_RX_TIMEOUT_ERROR) ?
+ "timeout " : "",
+ (status->frame_status & ZD_RX_FIFO_OVERRUN_ERROR) ?
+ "fifo " : "",
+ (status->frame_status & ZD_RX_DECRYPTION_ERROR) ?
+ "decryption " : "",
+ (status->frame_status & ZD_RX_CRC32_ERROR) ?
+ "crc32 " : "",
+ (status->frame_status & ZD_RX_NO_ADDR1_MATCH_ERROR) ?
+ "addr1 " : "",
+ (status->frame_status & ZD_RX_CRC16_ERROR) ?
+ "crc16" : "");
+ }
+}
+#endif /* DEBUG */
+
+#define LINK_LED_WORK_DELAY HZ
+
+static void link_led_handler(void *p)
+{
+ struct zd_mac *mac = p;
+ struct zd_chip *chip = &mac->chip;
+ struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
+ int is_associated;
+ int r;
+
+ spin_lock_irq(&mac->lock);
+ is_associated = sm->associated != 0;
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_chip_control_leds(chip,
+ is_associated ? LED_ASSOCIATED : LED_SCANNING);
+ if (r)
+ dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
+
+ queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
+ LINK_LED_WORK_DELAY);
+}
+
+static void housekeeping_init(struct zd_mac *mac)
+{
+ INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
+}
+
+static void housekeeping_enable(struct zd_mac *mac)
+{
+ dev_dbg_f(zd_mac_dev(mac), "\n");
+ queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
+ 0);
+}
+
+static void housekeeping_disable(struct zd_mac *mac)
+{
+ dev_dbg_f(zd_mac_dev(mac), "\n");
+ cancel_rearming_delayed_workqueue(zd_workqueue,
+ &mac->housekeeping.link_led_work);
+ zd_chip_control_leds(&mac->chip, LED_OFF);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
new file mode 100644
index 00000000000..b8ea3de7924
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -0,0 +1,198 @@
+/* zd_mac.h
+ *
+ * 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
+ */
+
+#ifndef _ZD_MAC_H
+#define _ZD_MAC_H
+
+#include <linux/wireless.h>
+#include <linux/kernel.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+
+#include "zd_chip.h"
+#include "zd_netdev.h"
+
+struct zd_ctrlset {
+ u8 modulation;
+ __le16 tx_length;
+ u8 control;
+ /* stores only the difference to tx_length on ZD1211B */
+ __le16 packet_length;
+ __le16 current_length;
+ u8 service;
+ __le16 next_frame_length;
+} __attribute__((packed));
+
+#define ZD_CS_RESERVED_SIZE 25
+
+/* zd_crtlset field modulation */
+#define ZD_CS_RATE_MASK 0x0f
+#define ZD_CS_TYPE_MASK 0x10
+#define ZD_CS_RATE(modulation) ((modulation) & ZD_CS_RATE_MASK)
+#define ZD_CS_TYPE(modulation) ((modulation) & ZD_CS_TYPE_MASK)
+
+#define ZD_CS_CCK 0x00
+#define ZD_CS_OFDM 0x10
+
+#define ZD_CS_CCK_RATE_1M 0x00
+#define ZD_CS_CCK_RATE_2M 0x01
+#define ZD_CS_CCK_RATE_5_5M 0x02
+#define ZD_CS_CCK_RATE_11M 0x03
+/* The rates for OFDM are encoded as in the PLCP header. Use ZD_OFDM_RATE_*.
+ */
+
+/* bit 5 is preamble (when in CCK mode), or a/g selection (when in OFDM mode) */
+#define ZD_CS_CCK_PREA_LONG 0x00
+#define ZD_CS_CCK_PREA_SHORT 0x20
+#define ZD_CS_OFDM_MODE_11G 0x00
+#define ZD_CS_OFDM_MODE_11A 0x20
+
+/* zd_ctrlset control field */
+#define ZD_CS_NEED_RANDOM_BACKOFF 0x01
+#define ZD_CS_MULTICAST 0x02
+
+#define ZD_CS_FRAME_TYPE_MASK 0x0c
+#define ZD_CS_DATA_FRAME 0x00
+#define ZD_CS_PS_POLL_FRAME 0x04
+#define ZD_CS_MANAGEMENT_FRAME 0x08
+#define ZD_CS_NO_SEQUENCE_CTL_FRAME 0x0c
+
+#define ZD_CS_WAKE_DESTINATION 0x10
+#define ZD_CS_RTS 0x20
+#define ZD_CS_ENCRYPT 0x40
+#define ZD_CS_SELF_CTS 0x80
+
+/* Incoming frames are prepended by a PLCP header */
+#define ZD_PLCP_HEADER_SIZE 5
+
+struct rx_length_info {
+ __le16 length[3];
+ __le16 tag;
+};
+
+#define RX_LENGTH_INFO_TAG 0x697e
+
+struct rx_status {
+ u8 signal_quality_cck;
+ /* rssi */
+ u8 signal_strength;
+ u8 signal_quality_ofdm;
+ u8 decryption_type;
+ u8 frame_status;
+};
+
+/* rx_status field decryption_type */
+#define ZD_RX_NO_WEP 0
+#define ZD_RX_WEP64 1
+#define ZD_RX_TKIP 2
+#define ZD_RX_AES 4
+#define ZD_RX_WEP128 5
+#define ZD_RX_WEP256 6
+
+/* rx_status field frame_status */
+#define ZD_RX_FRAME_MODULATION_MASK 0x01
+#define ZD_RX_CCK 0x00
+#define ZD_RX_OFDM 0x01
+
+#define ZD_RX_TIMEOUT_ERROR 0x02
+#define ZD_RX_FIFO_OVERRUN_ERROR 0x04
+#define ZD_RX_DECRYPTION_ERROR 0x08
+#define ZD_RX_CRC32_ERROR 0x10
+#define ZD_RX_NO_ADDR1_MATCH_ERROR 0x20
+#define ZD_RX_CRC16_ERROR 0x40
+#define ZD_RX_ERROR 0x80
+
+enum mac_flags {
+ MAC_FIXED_CHANNEL = 0x01,
+};
+
+struct housekeeping {
+ struct work_struct link_led_work;
+};
+
+#define ZD_MAC_STATS_BUFFER_SIZE 16
+
+struct zd_mac {
+ struct zd_chip chip;
+ spinlock_t lock;
+ struct net_device *netdev;
+ /* Unlocked reading possible */
+ struct iw_statistics iw_stats;
+ struct housekeeping housekeeping;
+ unsigned int stats_count;
+ u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
+ u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
+ u8 regdomain;
+ u8 default_regdomain;
+ u8 requested_channel;
+};
+
+static inline struct ieee80211_device *zd_mac_to_ieee80211(struct zd_mac *mac)
+{
+ return zd_netdev_ieee80211(mac->netdev);
+}
+
+static inline struct zd_mac *zd_netdev_mac(struct net_device *netdev)
+{
+ return ieee80211softmac_priv(netdev);
+}
+
+static inline struct zd_mac *zd_chip_to_mac(struct zd_chip *chip)
+{
+ return container_of(chip, struct zd_mac, chip);
+}
+
+static inline struct zd_mac *zd_usb_to_mac(struct zd_usb *usb)
+{
+ return zd_chip_to_mac(zd_usb_to_chip(usb));
+}
+
+#define zd_mac_dev(mac) (zd_chip_dev(&(mac)->chip))
+
+int zd_mac_init(struct zd_mac *mac,
+ struct net_device *netdev,
+ struct usb_interface *intf);
+void zd_mac_clear(struct zd_mac *mac);
+
+int zd_mac_init_hw(struct zd_mac *mac, u8 device_type);
+
+int zd_mac_open(struct net_device *netdev);
+int zd_mac_stop(struct net_device *netdev);
+int zd_mac_set_mac_address(struct net_device *dev, void *p);
+
+int zd_mac_rx(struct zd_mac *mac, const u8 *buffer, unsigned int length);
+
+int zd_mac_set_regdomain(struct zd_mac *zd_mac, u8 regdomain);
+u8 zd_mac_get_regdomain(struct zd_mac *zd_mac);
+
+int zd_mac_request_channel(struct zd_mac *mac, u8 channel);
+int zd_mac_get_channel(struct zd_mac *mac, u8 *channel, u8 *flags);
+
+int zd_mac_set_mode(struct zd_mac *mac, u32 mode);
+int zd_mac_get_mode(struct zd_mac *mac, u32 *mode);
+
+int zd_mac_get_range(struct zd_mac *mac, struct iw_range *range);
+
+struct iw_statistics *zd_mac_get_wireless_stats(struct net_device *ndev);
+
+#ifdef DEBUG
+void zd_dump_rx_status(const struct rx_status *status);
+#else
+#define zd_dump_rx_status(status)
+#endif /* DEBUG */
+
+#endif /* _ZD_MAC_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
new file mode 100644
index 00000000000..af3a7b36d07
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -0,0 +1,276 @@
+/* zd_netdev.c
+ *
+ * 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/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <net/ieee80211.h>
+#include <net/ieee80211softmac.h>
+#include <net/ieee80211softmac_wx.h>
+#include <net/iw_handler.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_ieee80211.h"
+
+/* Region 0 means reset regdomain to default. */
+static int zd_set_regdomain(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ const u8 *regdomain = (u8 *)req;
+ return zd_mac_set_regdomain(zd_netdev_mac(netdev), *regdomain);
+}
+
+static int zd_get_regdomain(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ u8 *regdomain = (u8 *)req;
+ if (!regdomain)
+ return -EINVAL;
+ *regdomain = zd_mac_get_regdomain(zd_netdev_mac(netdev));
+ return 0;
+}
+
+static const struct iw_priv_args zd_priv_args[] = {
+ {
+ .cmd = ZD_PRIV_SET_REGDOMAIN,
+ .set_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ .name = "set_regdomain",
+ },
+ {
+ .cmd = ZD_PRIV_GET_REGDOMAIN,
+ .get_args = IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+ .name = "get_regdomain",
+ },
+};
+
+#define PRIV_OFFSET(x) [(x)-SIOCIWFIRSTPRIV]
+
+static const iw_handler zd_priv_handler[] = {
+ PRIV_OFFSET(ZD_PRIV_SET_REGDOMAIN) = zd_set_regdomain,
+ PRIV_OFFSET(ZD_PRIV_GET_REGDOMAIN) = zd_get_regdomain,
+};
+
+static int iw_get_name(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ /* FIXME: check whether 802.11a will also supported */
+ strlcpy(req->name, "IEEE 802.11b/g", IFNAMSIZ);
+ return 0;
+}
+
+static int iw_get_nick(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ strcpy(extra, "zd1211");
+ req->data.length = strlen(extra);
+ req->data.flags = 1;
+ return 0;
+}
+
+static int iw_set_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ int r;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct iw_freq *freq = &req->freq;
+ u8 channel;
+
+ r = zd_find_channel(&channel, freq);
+ if (r < 0)
+ return r;
+ r = zd_mac_request_channel(mac, channel);
+ return r;
+}
+
+static int iw_get_freq(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ int r;
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct iw_freq *freq = &req->freq;
+ u8 channel;
+ u8 flags;
+
+ r = zd_mac_get_channel(mac, &channel, &flags);
+ if (r)
+ return r;
+
+ freq->flags = (flags & MAC_FIXED_CHANNEL) ?
+ IW_FREQ_FIXED : IW_FREQ_AUTO;
+ dev_dbg_f(zd_mac_dev(mac), "channel %s\n",
+ (flags & MAC_FIXED_CHANNEL) ? "fixed" : "auto");
+ return zd_channel_to_freq(freq, channel);
+}
+
+static int iw_set_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ return zd_mac_set_mode(zd_netdev_mac(netdev), req->mode);
+}
+
+static int iw_get_mode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ return zd_mac_get_mode(zd_netdev_mac(netdev), &req->mode);
+}
+
+static int iw_get_range(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *req, char *extra)
+{
+ struct iw_range *range = (struct iw_range *)extra;
+
+ dev_dbg_f(zd_mac_dev(zd_netdev_mac(netdev)), "\n");
+ req->data.length = sizeof(*range);
+ return zd_mac_get_range(zd_netdev_mac(netdev), range);
+}
+
+static int iw_set_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_set_encode(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_get_encode(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_get_encode(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_set_encodeext(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_set_encodeext(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+static int iw_get_encodeext(struct net_device *netdev,
+ struct iw_request_info *info,
+ union iwreq_data *data,
+ char *extra)
+{
+ return ieee80211_wx_get_encodeext(zd_netdev_ieee80211(netdev), info,
+ data, extra);
+}
+
+#define WX(x) [(x)-SIOCIWFIRST]
+
+static const iw_handler zd_standard_iw_handlers[] = {
+ WX(SIOCGIWNAME) = iw_get_name,
+ WX(SIOCGIWNICKN) = iw_get_nick,
+ WX(SIOCSIWFREQ) = iw_set_freq,
+ WX(SIOCGIWFREQ) = iw_get_freq,
+ WX(SIOCSIWMODE) = iw_set_mode,
+ WX(SIOCGIWMODE) = iw_get_mode,
+ WX(SIOCGIWRANGE) = iw_get_range,
+ WX(SIOCSIWENCODE) = iw_set_encode,
+ WX(SIOCGIWENCODE) = iw_get_encode,
+ WX(SIOCSIWENCODEEXT) = iw_set_encodeext,
+ WX(SIOCGIWENCODEEXT) = iw_get_encodeext,
+ WX(SIOCSIWAUTH) = ieee80211_wx_set_auth,
+ WX(SIOCGIWAUTH) = ieee80211_wx_get_auth,
+ WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan,
+ WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results,
+ WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid,
+ WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid,
+ WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap,
+ WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap,
+ WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate,
+ WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate,
+ WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie,
+ WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie,
+ WX(SIOCSIWMLME) = ieee80211softmac_wx_set_mlme,
+};
+
+static const struct iw_handler_def iw_handler_def = {
+ .standard = zd_standard_iw_handlers,
+ .num_standard = ARRAY_SIZE(zd_standard_iw_handlers),
+ .private = zd_priv_handler,
+ .num_private = ARRAY_SIZE(zd_priv_handler),
+ .private_args = zd_priv_args,
+ .num_private_args = ARRAY_SIZE(zd_priv_args),
+ .get_wireless_stats = zd_mac_get_wireless_stats,
+};
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf)
+{
+ int r;
+ struct net_device *netdev;
+ struct zd_mac *mac;
+
+ netdev = alloc_ieee80211softmac(sizeof(struct zd_mac));
+ if (!netdev) {
+ dev_dbg_f(&intf->dev, "out of memory\n");
+ return NULL;
+ }
+
+ mac = zd_netdev_mac(netdev);
+ r = zd_mac_init(mac, netdev, intf);
+ if (r) {
+ usb_set_intfdata(intf, NULL);
+ free_ieee80211(netdev);
+ return NULL;
+ }
+
+ SET_MODULE_OWNER(netdev);
+ SET_NETDEV_DEV(netdev, &intf->dev);
+
+ dev_dbg_f(&intf->dev, "netdev->flags %#06hx\n", netdev->flags);
+ dev_dbg_f(&intf->dev, "netdev->features %#010lx\n", netdev->features);
+
+ netdev->open = zd_mac_open;
+ netdev->stop = zd_mac_stop;
+ /* netdev->get_stats = */
+ /* netdev->set_multicast_list = */
+ netdev->set_mac_address = zd_mac_set_mac_address;
+ netdev->wireless_handlers = &iw_handler_def;
+ /* netdev->ethtool_ops = */
+
+ return netdev;
+}
+
+void zd_netdev_free(struct net_device *netdev)
+{
+ if (!netdev)
+ return;
+
+ zd_mac_clear(zd_netdev_mac(netdev));
+ free_ieee80211(netdev);
+}
+
+void zd_netdev_disconnect(struct net_device *netdev)
+{
+ unregister_netdev(netdev);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.h b/drivers/net/wireless/zd1211rw/zd_netdev.h
new file mode 100644
index 00000000000..374a957073c
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.h
@@ -0,0 +1,45 @@
+/* zd_netdev.h: Header for net device related functions.
+ *
+ * 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
+ */
+
+#ifndef _ZD_NETDEV_H
+#define _ZD_NETDEV_H
+
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <net/ieee80211.h>
+
+#define ZD_PRIV_SET_REGDOMAIN (SIOCIWFIRSTPRIV)
+#define ZD_PRIV_GET_REGDOMAIN (SIOCIWFIRSTPRIV+1)
+
+static inline struct ieee80211_device *zd_netdev_ieee80211(
+ struct net_device *ndev)
+{
+ return netdev_priv(ndev);
+}
+
+static inline struct net_device *zd_ieee80211_to_netdev(
+ struct ieee80211_device *ieee)
+{
+ return ieee->dev;
+}
+
+struct net_device *zd_netdev_alloc(struct usb_interface *intf);
+void zd_netdev_free(struct net_device *netdev);
+
+void zd_netdev_disconnect(struct net_device *netdev);
+
+#endif /* _ZD_NETDEV_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c
new file mode 100644
index 00000000000..f50cff3db91
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf.c
@@ -0,0 +1,156 @@
+/* zd_rf.c
+ *
+ * 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/errno.h>
+#include <linux/string.h>
+
+#include "zd_def.h"
+#include "zd_rf.h"
+#include "zd_ieee80211.h"
+#include "zd_chip.h"
+
+static const char *rfs[] = {
+ [0] = "unknown RF0",
+ [1] = "unknown RF1",
+ [UW2451_RF] = "UW2451_RF",
+ [UCHIP_RF] = "UCHIP_RF",
+ [AL2230_RF] = "AL2230_RF",
+ [AL7230B_RF] = "AL7230B_RF",
+ [THETA_RF] = "THETA_RF",
+ [AL2210_RF] = "AL2210_RF",
+ [MAXIM_NEW_RF] = "MAXIM_NEW_RF",
+ [UW2453_RF] = "UW2453_RF",
+ [AL2230S_RF] = "AL2230S_RF",
+ [RALINK_RF] = "RALINK_RF",
+ [INTERSIL_RF] = "INTERSIL_RF",
+ [RF2959_RF] = "RF2959_RF",
+ [MAXIM_NEW2_RF] = "MAXIM_NEW2_RF",
+ [PHILIPS_RF] = "PHILIPS_RF",
+};
+
+const char *zd_rf_name(u8 type)
+{
+ if (type & 0xf0)
+ type = 0;
+ return rfs[type];
+}
+
+void zd_rf_init(struct zd_rf *rf)
+{
+ memset(rf, 0, sizeof(*rf));
+}
+
+void zd_rf_clear(struct zd_rf *rf)
+{
+ ZD_MEMCLEAR(rf, sizeof(*rf));
+}
+
+int zd_rf_init_hw(struct zd_rf *rf, u8 type)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ switch (type) {
+ case RF2959_RF:
+ r = zd_rf_init_rf2959(rf);
+ if (r)
+ return r;
+ break;
+ case AL2230_RF:
+ r = zd_rf_init_al2230(rf);
+ if (r)
+ return r;
+ break;
+ case AL7230B_RF:
+ r = zd_rf_init_al7230b(rf);
+ if (r)
+ return r;
+ break;
+ default:
+ dev_err(zd_chip_dev(chip),
+ "RF %s %#x is not supported\n", zd_rf_name(type), type);
+ rf->type = 0;
+ return -ENODEV;
+ }
+
+ rf->type = type;
+
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->init_hw(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%s", zd_rf_name(rf->type));
+}
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+
+ ZD_ASSERT(mutex_is_locked(&zd_rf_to_chip(rf)->mutex));
+ if (channel < MIN_CHANNEL24)
+ return -EINVAL;
+ if (channel > MAX_CHANNEL24)
+ return -EINVAL;
+ dev_dbg_f(zd_chip_dev(zd_rf_to_chip(rf)), "channel: %d\n", channel);
+
+ r = rf->set_channel(rf, channel);
+ if (r >= 0)
+ rf->channel = channel;
+ return r;
+}
+
+int zd_switch_radio_on(struct zd_rf *rf)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->switch_radio_on(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
+
+int zd_switch_radio_off(struct zd_rf *rf)
+{
+ int r, t;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ /* TODO: move phy regs handling to zd_chip */
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_chip_lock_phy_regs(chip);
+ if (r)
+ return r;
+ t = rf->switch_radio_off(rf);
+ r = zd_chip_unlock_phy_regs(chip);
+ if (t)
+ r = t;
+ return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h
new file mode 100644
index 00000000000..676b3734f1e
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf.h
@@ -0,0 +1,83 @@
+/* zd_rf.h
+ *
+ * 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
+ */
+
+#ifndef _ZD_RF_H
+#define _ZD_RF_H
+
+#include "zd_types.h"
+
+#define UW2451_RF 0x2
+#define UCHIP_RF 0x3
+#define AL2230_RF 0x4
+#define AL7230B_RF 0x5 /* a,b,g */
+#define THETA_RF 0x6
+#define AL2210_RF 0x7
+#define MAXIM_NEW_RF 0x8
+#define UW2453_RF 0x9
+#define AL2230S_RF 0xa
+#define RALINK_RF 0xb
+#define INTERSIL_RF 0xc
+#define RF2959_RF 0xd
+#define MAXIM_NEW2_RF 0xe
+#define PHILIPS_RF 0xf
+
+#define RF_CHANNEL(ch) [(ch)-1]
+
+/* Provides functions of the RF transceiver. */
+
+enum {
+ RF_REG_BITS = 6,
+ RF_VALUE_BITS = 18,
+ RF_RV_BITS = RF_REG_BITS + RF_VALUE_BITS,
+};
+
+struct zd_rf {
+ u8 type;
+
+ u8 channel;
+ /*
+ * Whether this RF should patch the 6M band edge
+ * (assuming E2P_POD agrees)
+ */
+ u8 patch_6m_band_edge:1;
+
+ /* RF-specific functions */
+ int (*init_hw)(struct zd_rf *rf);
+ int (*set_channel)(struct zd_rf *rf, u8 channel);
+ int (*switch_radio_on)(struct zd_rf *rf);
+ int (*switch_radio_off)(struct zd_rf *rf);
+};
+
+const char *zd_rf_name(u8 type);
+void zd_rf_init(struct zd_rf *rf);
+void zd_rf_clear(struct zd_rf *rf);
+int zd_rf_init_hw(struct zd_rf *rf, u8 type);
+
+int zd_rf_scnprint_id(struct zd_rf *rf, char *buffer, size_t size);
+
+int zd_rf_set_channel(struct zd_rf *rf, u8 channel);
+
+int zd_switch_radio_on(struct zd_rf *rf);
+int zd_switch_radio_off(struct zd_rf *rf);
+
+/* Functions for individual RF chips */
+
+int zd_rf_init_rf2959(struct zd_rf *rf);
+int zd_rf_init_al2230(struct zd_rf *rf);
+int zd_rf_init_al7230b(struct zd_rf *rf);
+
+#endif /* _ZD_RF_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
new file mode 100644
index 00000000000..25323a13a3d
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c
@@ -0,0 +1,373 @@
+/* zd_rf_al2230.c: Functions for the AL2230 RF controller
+ *
+ * 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/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 zd1211_al2230_table[][3] = {
+ RF_CHANNEL( 1) = { 0x03f790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 2) = { 0x03f790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 3) = { 0x03e790, 0x033331, 0x00000d, },
+ RF_CHANNEL( 4) = { 0x03e790, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 5) = { 0x03f7a0, 0x033331, 0x00000d, },
+ RF_CHANNEL( 6) = { 0x03f7a0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 7) = { 0x03e7a0, 0x033331, 0x00000d, },
+ RF_CHANNEL( 8) = { 0x03e7a0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL( 9) = { 0x03f7b0, 0x033331, 0x00000d, },
+ RF_CHANNEL(10) = { 0x03f7b0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL(11) = { 0x03e7b0, 0x033331, 0x00000d, },
+ RF_CHANNEL(12) = { 0x03e7b0, 0x0b3331, 0x00000d, },
+ RF_CHANNEL(13) = { 0x03f7c0, 0x033331, 0x00000d, },
+ RF_CHANNEL(14) = { 0x03e7c0, 0x066661, 0x00000d, },
+};
+
+static const u32 zd1211b_al2230_table[][3] = {
+ RF_CHANNEL( 1) = { 0x09efc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 2) = { 0x09efc0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 3) = { 0x09e7c0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 4) = { 0x09e7c0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 5) = { 0x05efc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 6) = { 0x05efc0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 7) = { 0x05e7c0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL( 8) = { 0x05e7c0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL( 9) = { 0x0defc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL(10) = { 0x0defc0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL(11) = { 0x0de7c0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL(12) = { 0x0de7c0, 0x8cccd0, 0xb00000, },
+ RF_CHANNEL(13) = { 0x03efc0, 0x8cccc0, 0xb00000, },
+ RF_CHANNEL(14) = { 0x03e7c0, 0x866660, 0xb00000, },
+};
+
+static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = {
+ { CR240, 0x57 }, { CR9, 0xe0 },
+};
+
+static int zd1211b_al2230_finalize_rf(struct zd_chip *chip)
+{
+ int r;
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 },
+ { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 },
+ { CR203, 0x06 },
+ { },
+
+ { CR240, 0x80 },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ /* related to antenna selection? */
+ if (chip->new_phy_layout) {
+ r = zd_iowrite16_locked(chip, 0xe1, CR9);
+ if (r)
+ return r;
+ }
+
+ return zd_iowrite16_locked(chip, 0x06, CR203);
+}
+
+static int zd1211_al2230_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
+ { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
+ { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a },
+ { CR109, 0x09 }, { CR110, 0x27 }, { CR111, 0x2b },
+ { CR112, 0x2b }, { CR119, 0x0a }, { CR10, 0x89 },
+ /* for newest (3rd cut) AL2300 */
+ { CR17, 0x28 },
+ { CR26, 0x93 }, { CR34, 0x30 },
+ /* for newest (3rd cut) AL2300 */
+ { CR35, 0x3e },
+ { CR41, 0x24 }, { CR44, 0x32 },
+ /* for newest (3rd cut) AL2300 */
+ { CR46, 0x96 },
+ { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
+ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
+ { CR92, 0x0a }, { CR99, 0x28 }, { CR100, 0x00 },
+ { CR101, 0x13 }, { CR102, 0x27 }, { CR106, 0x24 },
+ { CR107, 0x2a }, { CR109, 0x09 }, { CR110, 0x13 },
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ /* for newest (3rd cut) AL2300 */
+ { CR115, 0x24 },
+ { CR116, 0x24 }, { CR117, 0xf4 }, { CR118, 0xfc },
+ { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 },
+ { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff },
+ { CR253, 0xff },
+
+ /* These following happen separately in the vendor driver */
+ { },
+
+ /* shdnb(PLL_ON)=0 */
+ { CR251, 0x2f },
+ /* shdnb(PLL_ON)=1 */
+ { CR251, 0x3f },
+ { CR138, 0x28 }, { CR203, 0x06 },
+ };
+
+ static const u32 rv[] = {
+ /* Channel 1 */
+ 0x03f790,
+ 0x033331,
+ 0x00000d,
+
+ 0x0b3331,
+ 0x03b812,
+ 0x00fff3,
+ 0x000da4,
+ 0x0f4dc5, /* fix freq shift, 0x04edc5 */
+ 0x0805b6,
+ 0x011687,
+ 0x000688,
+ 0x0403b9, /* external control TX power (CR31) */
+ 0x00dbba,
+ 0x00099b,
+ 0x0bdffc,
+ 0x00000d,
+ 0x00500f,
+
+ /* These writes happen separately in the vendor driver */
+ 0x00d00f,
+ 0x004c0f,
+ 0x00540f,
+ 0x00700f,
+ 0x00500f,
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int zd1211b_al2230_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs1[] = {
+ { CR10, 0x89 }, { CR15, 0x20 },
+ { CR17, 0x2B }, /* for newest(3rd cut) AL2230 */
+ { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 },
+ { CR28, 0x3e }, { CR29, 0x00 },
+ { CR33, 0x28 }, /* 5621 */
+ { CR34, 0x30 },
+ { CR35, 0x3e }, /* for newest(3rd cut) AL2230 */
+ { CR41, 0x24 }, { CR44, 0x32 },
+ { CR46, 0x99 }, /* for newest(3rd cut) AL2230 */
+ { CR47, 0x1e },
+
+ /* ZD1211B 05.06.10 */
+ { CR48, 0x06 }, { CR49, 0xf9 }, { CR51, 0x01 },
+ { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 },
+ { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 },
+ { CR69, 0x28 },
+
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR87, 0x0a }, { CR89, 0x04 },
+ { CR91, 0x00 }, /* 5621 */
+ { CR92, 0x0a },
+ { CR98, 0x8d }, /* 4804, for 1212 new algorithm */
+ { CR99, 0x00 }, /* 5621 */
+ { CR101, 0x13 }, { CR102, 0x27 },
+ { CR106, 0x24 }, /* for newest(3rd cut) AL2230 */
+ { CR107, 0x2a },
+ { CR109, 0x13 }, /* 4804, for 1212 new algorithm */
+ { CR110, 0x1f }, /* 4804, for 1212 new algorithm */
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ { CR115, 0x26 }, /* 24->26 at 4902 for newest(3rd cut) AL2230 */
+ { CR116, 0x24 },
+ { CR117, 0xfa }, /* for 1211b */
+ { CR118, 0xfa }, /* for 1211b */
+ { CR119, 0x10 },
+ { CR120, 0x4f },
+ { CR121, 0x6c }, /* for 1211b */
+ { CR122, 0xfc }, /* E0->FC at 4902 */
+ { CR123, 0x57 }, /* 5623 */
+ { CR125, 0xad }, /* 4804, for 1212 new algorithm */
+ { CR126, 0x6c }, /* 5614 */
+ { CR127, 0x03 }, /* 4804, for 1212 new algorithm */
+ { CR137, 0x50 }, /* 5614 */
+ { CR138, 0xa8 },
+ { CR144, 0xac }, /* 5621 */
+ { CR150, 0x0d }, { CR252, 0x34 }, { CR253, 0x34 },
+ };
+
+ static const u32 rv1[] = {
+ 0x8cccd0,
+ 0x481dc0,
+ 0xcfff00,
+ 0x25a000,
+
+ /* To improve AL2230 yield, improve phase noise, 4713 */
+ 0x25a000,
+ 0xa3b2f0,
+
+ 0x6da010, /* Reg6 update for MP versio */
+ 0xe36280, /* Modified by jxiao for Bor-Chin on 2004/08/02 */
+ 0x116000,
+ 0x9dc020, /* External control TX power (CR31) */
+ 0x5ddb00, /* RegA update for MP version */
+ 0xd99000, /* RegB update for MP version */
+ 0x3ffbd0, /* RegC update for MP version */
+ 0xb00000, /* RegD update for MP version */
+
+ /* improve phase noise and remove phase calibration,4713 */
+ 0xf01a00,
+ };
+
+ static const struct zd_ioreq16 ioreqs2[] = {
+ { CR251, 0x2f }, /* shdnb(PLL_ON)=0 */
+ { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */
+ };
+
+ static const u32 rv2[] = {
+ /* To improve AL2230 yield, 4713 */
+ 0xf01b00,
+ 0xf01e00,
+ 0xf01a00,
+ };
+
+ static const struct zd_ioreq16 ioreqs3[] = {
+ /* related to 6M band edge patching, happens unconditionally */
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ };
+
+ r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+ ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1));
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3);
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1));
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2));
+ if (r)
+ return r;
+ r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2));
+ if (r)
+ return r;
+ r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3));
+ if (r)
+ return r;
+ return zd1211b_al2230_finalize_rf(chip);
+}
+
+static int zd1211_al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = zd1211_al2230_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR138, 0x28 },
+ { CR203, 0x06 },
+ };
+
+ r = zd_rfwritev_locked(chip, rv, 3, RF_RV_BITS);
+ if (r)
+ return r;
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211b_al2230_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int r;
+ const u32 *rv = zd1211b_al2230_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ r = zd_iowrite16a_locked(chip, zd1211b_ioreqs_shared_1,
+ ARRAY_SIZE(zd1211b_ioreqs_shared_1));
+ if (r)
+ return r;
+
+ r = zd_rfwritev_cr_locked(chip, rv, 3);
+ if (r)
+ return r;
+
+ return zd1211b_al2230_finalize_rf(chip);
+}
+
+static int zd1211_al2230_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x3f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int zd1211b_al2230_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x7f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al2230_switch_radio_off(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x04 },
+ { CR251, 0x2f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al2230(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ rf->switch_radio_off = al2230_switch_radio_off;
+ if (chip->is_zd1211b) {
+ rf->init_hw = zd1211b_al2230_init_hw;
+ rf->set_channel = zd1211b_al2230_set_channel;
+ rf->switch_radio_on = zd1211b_al2230_switch_radio_on;
+ } else {
+ rf->init_hw = zd1211_al2230_init_hw;
+ rf->set_channel = zd1211_al2230_set_channel;
+ rf->switch_radio_on = zd1211_al2230_switch_radio_on;
+ }
+ rf->patch_6m_band_edge = 1;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
new file mode 100644
index 00000000000..a289f95187e
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c
@@ -0,0 +1,274 @@
+/* zd_rf_al7230b.c: Functions for the AL7230B RF controller
+ *
+ * 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/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static const u32 chan_rv[][2] = {
+ RF_CHANNEL( 1) = { 0x09ec00, 0x8cccc8 },
+ RF_CHANNEL( 2) = { 0x09ec00, 0x8cccd8 },
+ RF_CHANNEL( 3) = { 0x09ec00, 0x8cccc0 },
+ RF_CHANNEL( 4) = { 0x09ec00, 0x8cccd0 },
+ RF_CHANNEL( 5) = { 0x05ec00, 0x8cccc8 },
+ RF_CHANNEL( 6) = { 0x05ec00, 0x8cccd8 },
+ RF_CHANNEL( 7) = { 0x05ec00, 0x8cccc0 },
+ RF_CHANNEL( 8) = { 0x05ec00, 0x8cccd0 },
+ RF_CHANNEL( 9) = { 0x0dec00, 0x8cccc8 },
+ RF_CHANNEL(10) = { 0x0dec00, 0x8cccd8 },
+ RF_CHANNEL(11) = { 0x0dec00, 0x8cccc0 },
+ RF_CHANNEL(12) = { 0x0dec00, 0x8cccd0 },
+ RF_CHANNEL(13) = { 0x03ec00, 0x8cccc8 },
+ RF_CHANNEL(14) = { 0x03ec00, 0x866660 },
+};
+
+static const u32 std_rv[] = {
+ 0x4ff821,
+ 0xc5fbfc,
+ 0x21ebfe,
+ 0xafd401, /* freq shift 0xaad401 */
+ 0x6cf56a,
+ 0xe04073,
+ 0x193d76,
+ 0x9dd844,
+ 0x500007,
+ 0xd8c010,
+};
+
+static int al7230b_init_hw(struct zd_rf *rf)
+{
+ int i, r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ /* All of these writes are identical to AL2230 unless otherwise
+ * specified */
+ static const struct zd_ioreq16 ioreqs_1[] = {
+ /* This one is 7230-specific, and happens before the rest */
+ { CR240, 0x57 },
+ { },
+
+ { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 },
+ { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 },
+ { CR44, 0x33 },
+ /* This value is different for 7230 (was: 0x2a) */
+ { CR106, 0x22 },
+ { CR107, 0x1a }, { CR109, 0x09 }, { CR110, 0x27 },
+ { CR111, 0x2b }, { CR112, 0x2b }, { CR119, 0x0a },
+ /* This happened further down in AL2230,
+ * and the value changed (was: 0xe0) */
+ { CR122, 0xfc },
+ { CR10, 0x89 },
+ /* for newest (3rd cut) AL2300 */
+ { CR17, 0x28 },
+ { CR26, 0x93 }, { CR34, 0x30 },
+ /* for newest (3rd cut) AL2300 */
+ { CR35, 0x3e },
+ { CR41, 0x24 }, { CR44, 0x32 },
+ /* for newest (3rd cut) AL2300 */
+ { CR46, 0x96 },
+ { CR47, 0x1e }, { CR79, 0x58 }, { CR80, 0x30 },
+ { CR81, 0x30 }, { CR87, 0x0a }, { CR89, 0x04 },
+ { CR92, 0x0a }, { CR99, 0x28 },
+ /* This value is different for 7230 (was: 0x00) */
+ { CR100, 0x02 },
+ { CR101, 0x13 }, { CR102, 0x27 },
+ /* This value is different for 7230 (was: 0x24) */
+ { CR106, 0x22 },
+ /* This value is different for 7230 (was: 0x2a) */
+ { CR107, 0x3f },
+ { CR109, 0x09 },
+ /* This value is different for 7230 (was: 0x13) */
+ { CR110, 0x1f },
+ { CR111, 0x1f }, { CR112, 0x1f }, { CR113, 0x27 },
+ { CR114, 0x27 },
+ /* for newest (3rd cut) AL2300 */
+ { CR115, 0x24 },
+ /* This value is different for 7230 (was: 0x24) */
+ { CR116, 0x3f },
+ /* This value is different for 7230 (was: 0xf4) */
+ { CR117, 0xfa },
+ { CR118, 0xfc }, { CR119, 0x10 }, { CR120, 0x4f },
+ { CR121, 0x77 }, { CR137, 0x88 },
+ /* This one is 7230-specific */
+ { CR138, 0xa8 },
+ /* This value is different for 7230 (was: 0xff) */
+ { CR252, 0x34 },
+ /* This value is different for 7230 (was: 0xff) */
+ { CR253, 0x34 },
+
+ /* PLL_OFF */
+ { CR251, 0x2f },
+ };
+
+ static const struct zd_ioreq16 ioreqs_2[] = {
+ /* PLL_ON */
+ { CR251, 0x3f },
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0x09ec04);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0x8cccc8);
+ if (r)
+ return r;
+
+ for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+ r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xbfffff);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0x700000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+ if (r)
+ return r;
+
+ r = zd_rfwrite_cr_locked(chip, 0xf15d59);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d5c);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16_locked(chip, 0x06, CR203);
+ if (r)
+ return r;
+ r = zd_iowrite16_locked(chip, 0x80, CR240);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int al7230b_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int i, r;
+ const u32 *rv = chan_rv[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ struct zd_ioreq16 ioreqs_1[] = {
+ { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 },
+ { CR38, 0x38 }, { CR136, 0xdf },
+ };
+
+ struct zd_ioreq16 ioreqs_2[] = {
+ /* PLL_ON */
+ { CR251, 0x3f },
+ { CR203, 0x06 }, { CR240, 0x08 },
+ };
+
+ r = zd_iowrite16_locked(chip, 0x57, CR240);
+ if (r)
+ return r;
+
+ /* PLL_OFF */
+ r = zd_iowrite16_locked(chip, 0x2f, CR251);
+ if (r)
+ return r;
+
+ for (i = 0; i < ARRAY_SIZE(std_rv); i++) {
+ r = zd_rfwrite_cr_locked(chip, std_rv[i]);
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+ r = zd_rfwrite_cr_locked(chip, 0xf15d58);
+ if (r)
+ return r;
+
+ r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1));
+ if (r)
+ return r;
+
+ for (i = 0; i < 2; i++) {
+ r = zd_rfwrite_cr_locked(chip, rv[i]);
+ if (r)
+ return r;
+ }
+
+ r = zd_rfwrite_cr_locked(chip, 0x3c9000);
+ if (r)
+ return r;
+
+ return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2));
+}
+
+static int al7230b_switch_radio_on(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x00 },
+ { CR251, 0x3f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int al7230b_switch_radio_off(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR11, 0x04 },
+ { CR251, 0x2f },
+ };
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_al7230b(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ if (chip->is_zd1211b) {
+ dev_err(zd_chip_dev(chip), "AL7230B is currently not "
+ "supported for ZD1211B devices\n");
+ return -ENODEV;
+ }
+
+ rf->init_hw = al7230b_init_hw;
+ rf->set_channel = al7230b_set_channel;
+ rf->switch_radio_on = al7230b_switch_radio_on;
+ rf->switch_radio_off = al7230b_switch_radio_off;
+ rf->patch_6m_band_edge = 1;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
new file mode 100644
index 00000000000..58247271cc2
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c
@@ -0,0 +1,279 @@
+/* zd_rf_rfmd.c: Functions for the RFMD RF controller
+ *
+ * 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/kernel.h>
+
+#include "zd_rf.h"
+#include "zd_usb.h"
+#include "zd_chip.h"
+
+static u32 rf2959_table[][2] = {
+ RF_CHANNEL( 1) = { 0x181979, 0x1e6666 },
+ RF_CHANNEL( 2) = { 0x181989, 0x1e6666 },
+ RF_CHANNEL( 3) = { 0x181999, 0x1e6666 },
+ RF_CHANNEL( 4) = { 0x1819a9, 0x1e6666 },
+ RF_CHANNEL( 5) = { 0x1819b9, 0x1e6666 },
+ RF_CHANNEL( 6) = { 0x1819c9, 0x1e6666 },
+ RF_CHANNEL( 7) = { 0x1819d9, 0x1e6666 },
+ RF_CHANNEL( 8) = { 0x1819e9, 0x1e6666 },
+ RF_CHANNEL( 9) = { 0x1819f9, 0x1e6666 },
+ RF_CHANNEL(10) = { 0x181a09, 0x1e6666 },
+ RF_CHANNEL(11) = { 0x181a19, 0x1e6666 },
+ RF_CHANNEL(12) = { 0x181a29, 0x1e6666 },
+ RF_CHANNEL(13) = { 0x181a39, 0x1e6666 },
+ RF_CHANNEL(14) = { 0x181a60, 0x1c0000 },
+};
+
+#if 0
+static int bits(u32 rw, int from, int to)
+{
+ rw &= ~(0xffffffffU << (to+1));
+ rw >>= from;
+ return rw;
+}
+
+static int bit(u32 rw, int bit)
+{
+ return bits(rw, bit, bit);
+}
+
+static void dump_regwrite(u32 rw)
+{
+ int reg = bits(rw, 18, 22);
+ int rw_flag = bits(rw, 23, 23);
+ PDEBUG("rf2959 %#010x reg %d rw %d", rw, reg, rw_flag);
+
+ switch (reg) {
+ case 0:
+ PDEBUG("reg0 CFG1 ref_sel %d hybernate %d rf_vco_reg_en %d"
+ " if_vco_reg_en %d if_vga_en %d",
+ bits(rw, 14, 15), bit(rw, 3), bit(rw, 2), bit(rw, 1),
+ bit(rw, 0));
+ break;
+ case 1:
+ PDEBUG("reg1 IFPLL1 pll_en1 %d kv_en1 %d vtc_en1 %d lpf1 %d"
+ " cpl1 %d pdp1 %d autocal_en1 %d ld_en1 %d ifloopr %d"
+ " ifloopc %d dac1 %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+ bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+ bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0, 3));
+ break;
+ case 2:
+ PDEBUG("reg2 IFPLL2 n1 %d num1 %d",
+ bits(rw, 6, 17), bits(rw, 0, 5));
+ break;
+ case 3:
+ PDEBUG("reg3 IFPLL3 num %d", bits(rw, 0, 17));
+ break;
+ case 4:
+ PDEBUG("reg4 IFPLL4 dn1 %#04x ct_def1 %d kv_def1 %d",
+ bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+ break;
+ case 5:
+ PDEBUG("reg5 RFPLL1 pll_en %d kv_en %d vtc_en %d lpf %d cpl %d"
+ " pdp %d autocal_en %d ld_en %d rfloopr %d rfloopc %d"
+ " dac %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15), bit(rw, 14),
+ bit(rw, 13), bit(rw, 12), bit(rw, 11), bit(rw, 10),
+ bits(rw, 7, 9), bits(rw, 4, 6), bits(rw, 0,3));
+ break;
+ case 6:
+ PDEBUG("reg6 RFPLL2 n %d num %d",
+ bits(rw, 6, 17), bits(rw, 0, 5));
+ break;
+ case 7:
+ PDEBUG("reg7 RFPLL3 num2 %d", bits(rw, 0, 17));
+ break;
+ case 8:
+ PDEBUG("reg8 RFPLL4 dn %#06x ct_def %d kv_def %d",
+ bits(rw, 8, 16), bits(rw, 4, 7), bits(rw, 0, 3));
+ break;
+ case 9:
+ PDEBUG("reg9 CAL1 tvco %d tlock %d m_ct_value %d ld_window %d",
+ bits(rw, 13, 17), bits(rw, 8, 12), bits(rw, 3, 7),
+ bits(rw, 0, 2));
+ break;
+ case 10:
+ PDEBUG("reg10 TXRX1 rxdcfbbyps %d pcontrol %d txvgc %d"
+ " rxlpfbw %d txlpfbw %d txdiffmode %d txenmode %d"
+ " intbiasen %d tybypass %d",
+ bit(rw, 17), bits(rw, 15, 16), bits(rw, 10, 14),
+ bits(rw, 7, 9), bits(rw, 4, 6), bit(rw, 3), bit(rw, 2),
+ bit(rw, 1), bit(rw, 0));
+ break;
+ case 11:
+ PDEBUG("reg11 PCNT1 mid_bias %d p_desired %d pc_offset %d"
+ " tx_delay %d",
+ bits(rw, 15, 17), bits(rw, 9, 14), bits(rw, 3, 8),
+ bits(rw, 0, 2));
+ break;
+ case 12:
+ PDEBUG("reg12 PCNT2 max_power %d mid_power %d min_power %d",
+ bits(rw, 12, 17), bits(rw, 6, 11), bits(rw, 0, 5));
+ break;
+ case 13:
+ PDEBUG("reg13 VCOT1 rfpll vco comp %d ifpll vco comp %d"
+ " lobias %d if_biasbuf %d if_biasvco %d rf_biasbuf %d"
+ " rf_biasvco %d",
+ bit(rw, 17), bit(rw, 16), bit(rw, 15),
+ bits(rw, 8, 9), bits(rw, 5, 7), bits(rw, 3, 4),
+ bits(rw, 0, 2));
+ break;
+ case 14:
+ PDEBUG("reg14 IQCAL rx_acal %d rx_pcal %d"
+ " tx_acal %d tx_pcal %d",
+ bits(rw, 13, 17), bits(rw, 9, 12), bits(rw, 4, 8),
+ bits(rw, 0, 3));
+ break;
+ }
+}
+#endif /* 0 */
+
+static int rf2959_init_hw(struct zd_rf *rf)
+{
+ int r;
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR2, 0x1E }, { CR9, 0x20 }, { CR10, 0x89 },
+ { CR11, 0x00 }, { CR15, 0xD0 }, { CR17, 0x68 },
+ { CR19, 0x4a }, { CR20, 0x0c }, { CR21, 0x0E },
+ { CR23, 0x48 },
+ /* normal size for cca threshold */
+ { CR24, 0x14 },
+ /* { CR24, 0x20 }, */
+ { CR26, 0x90 }, { CR27, 0x30 }, { CR29, 0x20 },
+ { CR31, 0xb2 }, { CR32, 0x43 }, { CR33, 0x28 },
+ { CR38, 0x30 }, { CR34, 0x0f }, { CR35, 0xF0 },
+ { CR41, 0x2a }, { CR46, 0x7F }, { CR47, 0x1E },
+ { CR51, 0xc5 }, { CR52, 0xc5 }, { CR53, 0xc5 },
+ { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 },
+ { CR82, 0x00 }, { CR83, 0x24 }, { CR84, 0x04 },
+ { CR85, 0x00 }, { CR86, 0x10 }, { CR87, 0x2A },
+ { CR88, 0x10 }, { CR89, 0x24 }, { CR90, 0x18 },
+ /* { CR91, 0x18 }, */
+ /* should solve continous CTS frame problems */
+ { CR91, 0x00 },
+ { CR92, 0x0a }, { CR93, 0x00 }, { CR94, 0x01 },
+ { CR95, 0x00 }, { CR96, 0x40 }, { CR97, 0x37 },
+ { CR98, 0x05 }, { CR99, 0x28 }, { CR100, 0x00 },
+ { CR101, 0x13 }, { CR102, 0x27 }, { CR103, 0x27 },
+ { CR104, 0x18 }, { CR105, 0x12 },
+ /* normal size */
+ { CR106, 0x1a },
+ /* { CR106, 0x22 }, */
+ { CR107, 0x24 }, { CR108, 0x0a }, { CR109, 0x13 },
+ { CR110, 0x2F }, { CR111, 0x27 }, { CR112, 0x27 },
+ { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x40 },
+ { CR116, 0x40 }, { CR117, 0xF0 }, { CR118, 0xF0 },
+ { CR119, 0x16 },
+ /* no TX continuation */
+ { CR122, 0x00 },
+ /* { CR122, 0xff }, */
+ { CR127, 0x03 }, { CR131, 0x08 }, { CR138, 0x28 },
+ { CR148, 0x44 }, { CR150, 0x10 }, { CR169, 0xBB },
+ { CR170, 0xBB },
+ };
+
+ static const u32 rv[] = {
+ 0x000007, /* REG0(CFG1) */
+ 0x07dd43, /* REG1(IFPLL1) */
+ 0x080959, /* REG2(IFPLL2) */
+ 0x0e6666,
+ 0x116a57, /* REG4 */
+ 0x17dd43, /* REG5 */
+ 0x1819f9, /* REG6 */
+ 0x1e6666,
+ 0x214554,
+ 0x25e7fa,
+ 0x27fffa,
+ /* The Zydas driver somehow forgets to set this value. It's
+ * only set for Japan. We are using internal power control
+ * for now.
+ */
+ 0x294128, /* internal power */
+ /* 0x28252c, */ /* External control TX power */
+ /* CR31_CCK, CR51_6-36M, CR52_48M, CR53_54M */
+ 0x2c0000,
+ 0x300000,
+ 0x340000, /* REG13(0xD) */
+ 0x381e0f, /* REG14(0xE) */
+ /* Bogus, RF2959's data sheet doesn't know register 27, which is
+ * actually referenced here. The commented 0x11 is 17.
+ */
+ 0x6c180f, /* REG27(0x11) */
+ };
+
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
+ return r;
+
+ return zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS);
+}
+
+static int rf2959_set_channel(struct zd_rf *rf, u8 channel)
+{
+ int i, r;
+ u32 *rv = rf2959_table[channel-1];
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ for (i = 0; i < 2; i++) {
+ r = zd_rfwrite_locked(chip, rv[i], RF_RV_BITS);
+ if (r)
+ return r;
+ }
+ return 0;
+}
+
+static int rf2959_switch_radio_on(struct zd_rf *rf)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x89 },
+ { CR11, 0x00 },
+ };
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int rf2959_switch_radio_off(struct zd_rf *rf)
+{
+ static const struct zd_ioreq16 ioreqs[] = {
+ { CR10, 0x15 },
+ { CR11, 0x81 },
+ };
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+int zd_rf_init_rf2959(struct zd_rf *rf)
+{
+ struct zd_chip *chip = zd_rf_to_chip(rf);
+
+ if (chip->is_zd1211b) {
+ dev_err(zd_chip_dev(chip),
+ "RF2959 is currently not supported for ZD1211B"
+ " devices\n");
+ return -ENODEV;
+ }
+ rf->init_hw = rf2959_init_hw;
+ rf->set_channel = rf2959_set_channel;
+ rf->switch_radio_on = rf2959_switch_radio_on;
+ rf->switch_radio_off = rf2959_switch_radio_off;
+ return 0;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
new file mode 100644
index 00000000000..0155a1584ed
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_types.h
@@ -0,0 +1,71 @@
+/* zd_types.h
+ *
+ * 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
+ */
+
+#ifndef _ZD_TYPES_H
+#define _ZD_TYPES_H
+
+#include <linux/types.h>
+
+/* We have three register spaces mapped into the overall USB address space of
+ * 64K words (16-bit values). There is the control register space of
+ * double-word registers, the eeprom register space and the firmware register
+ * space. The control register space is byte mapped, the others are word
+ * mapped.
+ *
+ * For that reason, we are using byte offsets for control registers and word
+ * offsets for everything else.
+ */
+
+typedef u32 __nocast zd_addr_t;
+
+enum {
+ ADDR_BASE_MASK = 0xff000000,
+ ADDR_OFFSET_MASK = 0x0000ffff,
+ ADDR_ZERO_MASK = 0x00ff0000,
+ NULL_BASE = 0x00000000,
+ USB_BASE = 0x01000000,
+ CR_BASE = 0x02000000,
+ CR_MAX_OFFSET = 0x0b30,
+ E2P_BASE = 0x03000000,
+ E2P_MAX_OFFSET = 0x007e,
+ FW_BASE = 0x04000000,
+ FW_MAX_OFFSET = 0x0005,
+};
+
+#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
+#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
+
+#define ZD_ADDR(base, offset) \
+ ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
+
+#define ZD_NULL_ADDR ((zd_addr_t)0)
+#define USB_REG(offset) ZD_ADDR(USB_BASE, offset) /* word addressing */
+#define CTL_REG(offset) ZD_ADDR(CR_BASE, offset) /* byte addressing */
+#define E2P_REG(offset) ZD_ADDR(E2P_BASE, offset) /* word addressing */
+#define FW_REG(offset) ZD_ADDR(FW_BASE, offset) /* word addressing */
+
+static inline zd_addr_t zd_inc_word(zd_addr_t addr)
+{
+ u32 base = ZD_ADDR_BASE(addr);
+ u32 offset = ZD_OFFSET(addr);
+
+ offset += base == CR_BASE ? 2 : 1;
+
+ return base | offset;
+}
+
+#endif /* _ZD_TYPES_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
new file mode 100644
index 00000000000..5c265ad0485
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -0,0 +1,1421 @@
+/* zd_usb.c
+ *
+ * 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 <asm/unaligned.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <net/ieee80211.h>
+
+#include "zd_def.h"
+#include "zd_netdev.h"
+#include "zd_mac.h"
+#include "zd_usb.h"
+#include "zd_util.h"
+
+static struct usb_device_id usb_ids[] = {
+ /* ZD1211 */
+ { USB_DEVICE(0x0ace, 0x1211), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x07b8, 0x6001), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x126f, 0xa006), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x6891, 0xa727), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0df6, 0x9071), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x079b, 0x004a), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x1740, 0x2000), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x157e, 0x3204), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0586, 0x3402), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b3b, 0x5630), .driver_info = DEVICE_ZD1211 },
+ { USB_DEVICE(0x0b05, 0x170c), .driver_info = DEVICE_ZD1211 },
+ /* ZD1211B */
+ { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
+ { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
+ /* "Driverless" devices that need ejecting */
+ { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
+ {}
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("USB driver for devices with the ZD1211 chip.");
+MODULE_AUTHOR("Ulrich Kunitz");
+MODULE_AUTHOR("Daniel Drake");
+MODULE_VERSION("1.0");
+MODULE_DEVICE_TABLE(usb, usb_ids);
+
+#define FW_ZD1211_PREFIX "zd1211/zd1211_"
+#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
+
+/* register address handling */
+
+#ifdef DEBUG
+static int check_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+ u32 base = ZD_ADDR_BASE(addr);
+ u32 offset = ZD_OFFSET(addr);
+
+ if ((u32)addr & ADDR_ZERO_MASK)
+ goto invalid_address;
+ switch (base) {
+ case USB_BASE:
+ break;
+ case CR_BASE:
+ if (offset > CR_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "CR offset %#010x larger than"
+ " CR_MAX_OFFSET %#10x\n",
+ offset, CR_MAX_OFFSET);
+ goto invalid_address;
+ }
+ if (offset & 1) {
+ dev_dbg(zd_usb_dev(usb),
+ "CR offset %#010x is not a multiple of 2\n",
+ offset);
+ goto invalid_address;
+ }
+ break;
+ case E2P_BASE:
+ if (offset > E2P_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "E2P offset %#010x larger than"
+ " E2P_MAX_OFFSET %#010x\n",
+ offset, E2P_MAX_OFFSET);
+ goto invalid_address;
+ }
+ break;
+ case FW_BASE:
+ if (!usb->fw_base_offset) {
+ dev_dbg(zd_usb_dev(usb),
+ "ERROR: fw base offset has not been set\n");
+ return -EAGAIN;
+ }
+ if (offset > FW_MAX_OFFSET) {
+ dev_dbg(zd_usb_dev(usb),
+ "FW offset %#10x is larger than"
+ " FW_MAX_OFFSET %#010x\n",
+ offset, FW_MAX_OFFSET);
+ goto invalid_address;
+ }
+ break;
+ default:
+ dev_dbg(zd_usb_dev(usb),
+ "address has unsupported base %#010x\n", addr);
+ goto invalid_address;
+ }
+
+ return 0;
+invalid_address:
+ dev_dbg(zd_usb_dev(usb),
+ "ERROR: invalid address: %#010x\n", addr);
+ return -EINVAL;
+}
+#endif /* DEBUG */
+
+static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
+{
+ u32 base;
+ u16 offset;
+
+ base = ZD_ADDR_BASE(addr);
+ offset = ZD_OFFSET(addr);
+
+ ZD_ASSERT(check_addr(usb, addr) == 0);
+
+ switch (base) {
+ case CR_BASE:
+ offset += CR_BASE_OFFSET;
+ break;
+ case E2P_BASE:
+ offset += E2P_BASE_OFFSET;
+ break;
+ case FW_BASE:
+ offset += usb->fw_base_offset;
+ break;
+ }
+
+ return offset;
+}
+
+/* USB device initialization */
+
+static int request_fw_file(
+ const struct firmware **fw, const char *name, struct device *device)
+{
+ int r;
+
+ dev_dbg_f(device, "fw name %s\n", name);
+
+ r = request_firmware(fw, name, device);
+ if (r)
+ dev_err(device,
+ "Could not load firmware file %s. Error number %d\n",
+ name, r);
+ return r;
+}
+
+static inline u16 get_bcdDevice(const struct usb_device *udev)
+{
+ return le16_to_cpu(udev->descriptor.bcdDevice);
+}
+
+enum upload_code_flags {
+ REBOOT = 1,
+};
+
+/* Ensures that MAX_TRANSFER_SIZE is even. */
+#define MAX_TRANSFER_SIZE (USB_MAX_TRANSFER_SIZE & ~1)
+
+static int upload_code(struct usb_device *udev,
+ const u8 *data, size_t size, u16 code_offset, int flags)
+{
+ u8 *p;
+ int r;
+
+ /* USB request blocks need "kmalloced" buffers.
+ */
+ p = kmalloc(MAX_TRANSFER_SIZE, GFP_KERNEL);
+ if (!p) {
+ dev_err(&udev->dev, "out of memory\n");
+ r = -ENOMEM;
+ goto error;
+ }
+
+ size &= ~1;
+ while (size > 0) {
+ size_t transfer_size = size <= MAX_TRANSFER_SIZE ?
+ size : MAX_TRANSFER_SIZE;
+
+ dev_dbg_f(&udev->dev, "transfer size %zu\n", transfer_size);
+
+ memcpy(p, data, transfer_size);
+ r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_DOWNLOAD,
+ USB_DIR_OUT | USB_TYPE_VENDOR,
+ code_offset, 0, p, transfer_size, 1000 /* ms */);
+ if (r < 0) {
+ dev_err(&udev->dev,
+ "USB control request for firmware upload"
+ " failed. Error number %d\n", r);
+ goto error;
+ }
+ transfer_size = r & ~1;
+
+ size -= transfer_size;
+ data += transfer_size;
+ code_offset += transfer_size/sizeof(u16);
+ }
+
+ if (flags & REBOOT) {
+ u8 ret;
+
+ r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+ USB_REQ_FIRMWARE_CONFIRM,
+ USB_DIR_IN | USB_TYPE_VENDOR,
+ 0, 0, &ret, sizeof(ret), 5000 /* ms */);
+ if (r != sizeof(ret)) {
+ dev_err(&udev->dev,
+ "control request firmeware confirmation failed."
+ " Return value %d\n", r);
+ if (r >= 0)
+ r = -ENODEV;
+ goto error;
+ }
+ if (ret & 0x80) {
+ dev_err(&udev->dev,
+ "Internal error while downloading."
+ " Firmware confirm return value %#04x\n",
+ (unsigned int)ret);
+ r = -ENODEV;
+ goto error;
+ }
+ dev_dbg_f(&udev->dev, "firmware confirm return value %#04x\n",
+ (unsigned int)ret);
+ }
+
+ r = 0;
+error:
+ kfree(p);
+ return r;
+}
+
+static u16 get_word(const void *data, u16 offset)
+{
+ const __le16 *p = data;
+ return le16_to_cpu(p[offset]);
+}
+
+static char *get_fw_name(char *buffer, size_t size, u8 device_type,
+ const char* postfix)
+{
+ scnprintf(buffer, size, "%s%s",
+ device_type == DEVICE_ZD1211B ?
+ FW_ZD1211B_PREFIX : FW_ZD1211_PREFIX,
+ postfix);
+ return buffer;
+}
+
+static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
+ const struct firmware *ub_fw)
+{
+ const struct firmware *ur_fw = NULL;
+ int offset;
+ int r = 0;
+ char fw_name[128];
+
+ r = request_fw_file(&ur_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "ur"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
+ REBOOT);
+ if (r)
+ goto error;
+
+ offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+ r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
+ E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+
+ /* At this point, the vendor driver downloads the whole firmware
+ * image, hacks around with version IDs, and uploads it again,
+ * completely overwriting the boot code. We do not do this here as
+ * it is not required on any tested devices, and it is suspected to
+ * cause problems. */
+error:
+ release_firmware(ur_fw);
+ return r;
+}
+
+static int upload_firmware(struct usb_device *udev, u8 device_type)
+{
+ int r;
+ u16 fw_bcdDevice;
+ u16 bcdDevice;
+ const struct firmware *ub_fw = NULL;
+ const struct firmware *uph_fw = NULL;
+ char fw_name[128];
+
+ bcdDevice = get_bcdDevice(udev);
+
+ r = request_fw_file(&ub_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "ub"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+
+ if (fw_bcdDevice != bcdDevice) {
+ dev_info(&udev->dev,
+ "firmware version %#06x and device bootcode version "
+ "%#06x differ\n", fw_bcdDevice, bcdDevice);
+ if (bcdDevice <= 0x4313)
+ dev_warn(&udev->dev, "device has old bootcode, please "
+ "report success or failure\n");
+
+ r = handle_version_mismatch(udev, device_type, ub_fw);
+ if (r)
+ goto error;
+ } else {
+ dev_dbg_f(&udev->dev,
+ "firmware device id %#06x is equal to the "
+ "actual device id\n", fw_bcdDevice);
+ }
+
+
+ r = request_fw_file(&uph_fw,
+ get_fw_name(fw_name, sizeof(fw_name), device_type, "uphr"),
+ &udev->dev);
+ if (r)
+ goto error;
+
+ r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
+ REBOOT);
+ if (r) {
+ dev_err(&udev->dev,
+ "Could not upload firmware code uph. Error number %d\n",
+ r);
+ }
+
+ /* FALL-THROUGH */
+error:
+ release_firmware(ub_fw);
+ release_firmware(uph_fw);
+ return r;
+}
+
+static void disable_read_regs_int(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock(&intr->lock);
+ intr->read_regs_enabled = 0;
+ spin_unlock(&intr->lock);
+}
+
+#define urb_dev(urb) (&(urb)->dev->dev)
+
+static inline void handle_regs_int(struct urb *urb)
+{
+ struct zd_usb *usb = urb->context;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ int len;
+
+ ZD_ASSERT(in_interrupt());
+ spin_lock(&intr->lock);
+
+ if (intr->read_regs_enabled) {
+ intr->read_regs.length = len = urb->actual_length;
+
+ if (len > sizeof(intr->read_regs.buffer))
+ len = sizeof(intr->read_regs.buffer);
+ memcpy(intr->read_regs.buffer, urb->transfer_buffer, len);
+ intr->read_regs_enabled = 0;
+ complete(&intr->read_regs.completion);
+ goto out;
+ }
+
+ dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
+out:
+ spin_unlock(&intr->lock);
+}
+
+static inline void handle_retry_failed_int(struct urb *urb)
+{
+ dev_dbg_f(urb_dev(urb), "retry failed interrupt\n");
+}
+
+
+static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ int r;
+ struct usb_int_header *hdr;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ goto kfree;
+ default:
+ goto resubmit;
+ }
+
+ if (urb->actual_length < sizeof(hdr)) {
+ dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb);
+ goto resubmit;
+ }
+
+ hdr = urb->transfer_buffer;
+ if (hdr->type != USB_INT_TYPE) {
+ dev_dbg_f(urb_dev(urb), "error: urb %p wrong type\n", urb);
+ goto resubmit;
+ }
+
+ switch (hdr->id) {
+ case USB_INT_ID_REGS:
+ handle_regs_int(urb);
+ break;
+ case USB_INT_ID_RETRY_FAILED:
+ handle_retry_failed_int(urb);
+ break;
+ default:
+ dev_dbg_f(urb_dev(urb), "error: urb %p unknown id %x\n", urb,
+ (unsigned int)hdr->id);
+ goto resubmit;
+ }
+
+resubmit:
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r) {
+ dev_dbg_f(urb_dev(urb), "resubmit urb %p\n", urb);
+ goto kfree;
+ }
+ return;
+kfree:
+ kfree(urb->transfer_buffer);
+}
+
+static inline int int_urb_interval(struct usb_device *udev)
+{
+ switch (udev->speed) {
+ case USB_SPEED_HIGH:
+ return 4;
+ case USB_SPEED_LOW:
+ return 10;
+ case USB_SPEED_FULL:
+ default:
+ return 1;
+ }
+}
+
+static inline int usb_int_enabled(struct zd_usb *usb)
+{
+ unsigned long flags;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct urb *urb;
+
+ spin_lock_irqsave(&intr->lock, flags);
+ urb = intr->urb;
+ spin_unlock_irqrestore(&intr->lock, flags);
+ return urb != NULL;
+}
+
+int zd_usb_enable_int(struct zd_usb *usb)
+{
+ int r;
+ struct usb_device *udev;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ void *transfer_buffer = NULL;
+ struct urb *urb;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ urb = usb_alloc_urb(0, GFP_NOFS);
+ if (!urb) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&intr->lock);
+ if (intr->urb) {
+ spin_unlock_irq(&intr->lock);
+ r = 0;
+ goto error_free_urb;
+ }
+ intr->urb = urb;
+ spin_unlock_irq(&intr->lock);
+
+ /* TODO: make it a DMA buffer */
+ r = -ENOMEM;
+ transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS);
+ if (!transfer_buffer) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "couldn't allocate transfer_buffer\n");
+ goto error_set_urb_null;
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, EP_INT_IN),
+ transfer_buffer, USB_MAX_EP_INT_BUFFER,
+ int_urb_complete, usb,
+ intr->interval);
+
+ dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb);
+ r = usb_submit_urb(urb, GFP_NOFS);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "Couldn't submit urb. Error number %d\n", r);
+ goto error;
+ }
+
+ return 0;
+error:
+ kfree(transfer_buffer);
+error_set_urb_null:
+ spin_lock_irq(&intr->lock);
+ intr->urb = NULL;
+ spin_unlock_irq(&intr->lock);
+error_free_urb:
+ usb_free_urb(urb);
+out:
+ return r;
+}
+
+void zd_usb_disable_int(struct zd_usb *usb)
+{
+ unsigned long flags;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct urb *urb;
+
+ spin_lock_irqsave(&intr->lock, flags);
+ urb = intr->urb;
+ if (!urb) {
+ spin_unlock_irqrestore(&intr->lock, flags);
+ return;
+ }
+ intr->urb = NULL;
+ spin_unlock_irqrestore(&intr->lock, flags);
+
+ usb_kill_urb(urb);
+ dev_dbg_f(zd_usb_dev(usb), "urb %p killed\n", urb);
+ usb_free_urb(urb);
+}
+
+static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
+ unsigned int length)
+{
+ int i;
+ struct zd_mac *mac = zd_usb_to_mac(usb);
+ const struct rx_length_info *length_info;
+
+ if (length < sizeof(struct rx_length_info)) {
+ /* It's not a complete packet anyhow. */
+ return;
+ }
+ length_info = (struct rx_length_info *)
+ (buffer + length - sizeof(struct rx_length_info));
+
+ /* It might be that three frames are merged into a single URB
+ * transaction. We have to check for the length info tag.
+ *
+ * While testing we discovered that length_info might be unaligned,
+ * because if USB transactions are merged, the last packet will not
+ * be padded. Unaligned access might also happen if the length_info
+ * structure is not present.
+ */
+ if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG))
+ {
+ unsigned int l, k, n;
+ for (i = 0, l = 0;; i++) {
+ k = le16_to_cpu(get_unaligned(&length_info->length[i]));
+ n = l+k;
+ if (n > length)
+ return;
+ zd_mac_rx(mac, buffer+l, k);
+ if (i >= 2)
+ return;
+ l = (n+3) & ~3;
+ }
+ } else {
+ zd_mac_rx(mac, buffer, length);
+ }
+}
+
+static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ struct zd_usb *usb;
+ struct zd_usb_rx *rx;
+ const u8 *buffer;
+ unsigned int length;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ return;
+ default:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ goto resubmit;
+ }
+
+ buffer = urb->transfer_buffer;
+ length = urb->actual_length;
+ usb = urb->context;
+ rx = &usb->rx;
+
+ if (length%rx->usb_packet_size > rx->usb_packet_size-4) {
+ /* If there is an old first fragment, we don't care. */
+ dev_dbg_f(urb_dev(urb), "*** first fragment ***\n");
+ ZD_ASSERT(length <= ARRAY_SIZE(rx->fragment));
+ spin_lock(&rx->lock);
+ memcpy(rx->fragment, buffer, length);
+ rx->fragment_length = length;
+ spin_unlock(&rx->lock);
+ goto resubmit;
+ }
+
+ spin_lock(&rx->lock);
+ if (rx->fragment_length > 0) {
+ /* We are on a second fragment, we believe */
+ ZD_ASSERT(length + rx->fragment_length <=
+ ARRAY_SIZE(rx->fragment));
+ dev_dbg_f(urb_dev(urb), "*** second fragment ***\n");
+ memcpy(rx->fragment+rx->fragment_length, buffer, length);
+ handle_rx_packet(usb, rx->fragment,
+ rx->fragment_length + length);
+ rx->fragment_length = 0;
+ spin_unlock(&rx->lock);
+ } else {
+ spin_unlock(&rx->lock);
+ handle_rx_packet(usb, buffer, length);
+ }
+
+resubmit:
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static struct urb *alloc_urb(struct zd_usb *usb)
+{
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+ void *buffer;
+
+ urb = usb_alloc_urb(0, GFP_NOFS);
+ if (!urb)
+ return NULL;
+ buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS,
+ &urb->transfer_dma);
+ if (!buffer) {
+ usb_free_urb(urb);
+ return NULL;
+ }
+
+ usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, EP_DATA_IN),
+ buffer, USB_MAX_RX_SIZE,
+ rx_urb_complete, usb);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ return urb;
+}
+
+static void free_urb(struct urb *urb)
+{
+ if (!urb)
+ return;
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+}
+
+int zd_usb_enable_rx(struct zd_usb *usb)
+{
+ int i, r;
+ struct zd_usb_rx *rx = &usb->rx;
+ struct urb **urbs;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ r = -ENOMEM;
+ urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS);
+ if (!urbs)
+ goto error;
+ for (i = 0; i < URBS_COUNT; i++) {
+ urbs[i] = alloc_urb(usb);
+ if (!urbs[i])
+ goto error;
+ }
+
+ ZD_ASSERT(!irqs_disabled());
+ spin_lock_irq(&rx->lock);
+ if (rx->urbs) {
+ spin_unlock_irq(&rx->lock);
+ r = 0;
+ goto error;
+ }
+ rx->urbs = urbs;
+ rx->urbs_count = URBS_COUNT;
+ spin_unlock_irq(&rx->lock);
+
+ for (i = 0; i < URBS_COUNT; i++) {
+ r = usb_submit_urb(urbs[i], GFP_NOFS);
+ if (r)
+ goto error_submit;
+ }
+
+ return 0;
+error_submit:
+ for (i = 0; i < URBS_COUNT; i++) {
+ usb_kill_urb(urbs[i]);
+ }
+ spin_lock_irq(&rx->lock);
+ rx->urbs = NULL;
+ rx->urbs_count = 0;
+ spin_unlock_irq(&rx->lock);
+error:
+ if (urbs) {
+ for (i = 0; i < URBS_COUNT; i++)
+ free_urb(urbs[i]);
+ }
+ return r;
+}
+
+void zd_usb_disable_rx(struct zd_usb *usb)
+{
+ int i;
+ unsigned long flags;
+ struct urb **urbs;
+ unsigned int count;
+ struct zd_usb_rx *rx = &usb->rx;
+
+ spin_lock_irqsave(&rx->lock, flags);
+ urbs = rx->urbs;
+ count = rx->urbs_count;
+ spin_unlock_irqrestore(&rx->lock, flags);
+ if (!urbs)
+ return;
+
+ for (i = 0; i < count; i++) {
+ usb_kill_urb(urbs[i]);
+ free_urb(urbs[i]);
+ }
+ kfree(urbs);
+
+ spin_lock_irqsave(&rx->lock, flags);
+ rx->urbs = NULL;
+ rx->urbs_count = 0;
+ spin_unlock_irqrestore(&rx->lock, flags);
+}
+
+static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+{
+ int r;
+
+ switch (urb->status) {
+ case 0:
+ break;
+ case -ESHUTDOWN:
+ case -EINVAL:
+ case -ENODEV:
+ case -ENOENT:
+ case -ECONNRESET:
+ case -EPIPE:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ break;
+ default:
+ dev_dbg_f(urb_dev(urb), "urb %p error %d\n", urb, urb->status);
+ goto resubmit;
+ }
+free_urb:
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+ usb_free_urb(urb);
+ return;
+resubmit:
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r) {
+ dev_dbg_f(urb_dev(urb), "error resubmit urb %p %d\n", urb, r);
+ goto free_urb;
+ }
+}
+
+/* Puts the frame on the USB endpoint. It doesn't wait for
+ * completion. The frame must contain the control set.
+ */
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length)
+{
+ int r;
+ struct usb_device *udev = zd_usb_to_usbdev(usb);
+ struct urb *urb;
+ void *buffer;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ r = -ENOMEM;
+ goto out;
+ }
+
+ buffer = usb_buffer_alloc(zd_usb_to_usbdev(usb), length, GFP_ATOMIC,
+ &urb->transfer_dma);
+ if (!buffer) {
+ r = -ENOMEM;
+ goto error_free_urb;
+ }
+ memcpy(buffer, frame, length);
+
+ usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_DATA_OUT),
+ buffer, length, tx_urb_complete, NULL);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ r = usb_submit_urb(urb, GFP_ATOMIC);
+ if (r)
+ goto error;
+ return 0;
+error:
+ usb_buffer_free(zd_usb_to_usbdev(usb), length, buffer,
+ urb->transfer_dma);
+error_free_urb:
+ usb_free_urb(urb);
+out:
+ return r;
+}
+
+static inline void init_usb_interrupt(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock_init(&intr->lock);
+ intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
+ init_completion(&intr->read_regs.completion);
+ intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+}
+
+static inline void init_usb_rx(struct zd_usb *usb)
+{
+ struct zd_usb_rx *rx = &usb->rx;
+ spin_lock_init(&rx->lock);
+ if (interface_to_usbdev(usb->intf)->speed == USB_SPEED_HIGH) {
+ rx->usb_packet_size = 512;
+ } else {
+ rx->usb_packet_size = 64;
+ }
+ ZD_ASSERT(rx->fragment_length == 0);
+}
+
+static inline void init_usb_tx(struct zd_usb *usb)
+{
+ /* FIXME: at this point we will allocate a fixed number of urb's for
+ * use in a cyclic scheme */
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+ struct usb_interface *intf)
+{
+ memset(usb, 0, sizeof(*usb));
+ usb->intf = usb_get_intf(intf);
+ usb_set_intfdata(usb->intf, netdev);
+ init_usb_interrupt(usb);
+ init_usb_tx(usb);
+ init_usb_rx(usb);
+}
+
+int zd_usb_init_hw(struct zd_usb *usb)
+{
+ int r;
+ struct zd_chip *chip = zd_usb_to_chip(usb);
+
+ ZD_ASSERT(mutex_is_locked(&chip->mutex));
+ r = zd_ioread16_locked(chip, &usb->fw_base_offset,
+ USB_REG((u16)FW_BASE_ADDR_OFFSET));
+ if (r)
+ return r;
+ dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
+ usb->fw_base_offset);
+
+ return 0;
+}
+
+void zd_usb_clear(struct zd_usb *usb)
+{
+ usb_set_intfdata(usb->intf, NULL);
+ usb_put_intf(usb->intf);
+ ZD_MEMCLEAR(usb, sizeof(*usb));
+ /* FIXME: usb_interrupt, usb_tx, usb_rx? */
+}
+
+static const char *speed(enum usb_device_speed speed)
+{
+ switch (speed) {
+ case USB_SPEED_LOW:
+ return "low";
+ case USB_SPEED_FULL:
+ return "full";
+ case USB_SPEED_HIGH:
+ return "high";
+ default:
+ return "unknown speed";
+ }
+}
+
+static int scnprint_id(struct usb_device *udev, char *buffer, size_t size)
+{
+ return scnprintf(buffer, size, "%04hx:%04hx v%04hx %s",
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ get_bcdDevice(udev),
+ speed(udev->speed));
+}
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size)
+{
+ struct usb_device *udev = interface_to_usbdev(usb->intf);
+ return scnprint_id(udev, buffer, size);
+}
+
+#ifdef DEBUG
+static void print_id(struct usb_device *udev)
+{
+ char buffer[40];
+
+ scnprint_id(udev, buffer, sizeof(buffer));
+ buffer[sizeof(buffer)-1] = 0;
+ dev_dbg_f(&udev->dev, "%s\n", buffer);
+}
+#else
+#define print_id(udev) do { } while (0)
+#endif
+
+static int eject_installer(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_interface *iface_desc = &intf->altsetting[0];
+ struct usb_endpoint_descriptor *endpoint;
+ unsigned char *cmd;
+ u8 bulk_out_ep;
+ int r;
+
+ /* Find bulk out endpoint */
+ endpoint = &iface_desc->endpoint[1].desc;
+ if ((endpoint->bEndpointAddress & USB_TYPE_MASK) == USB_DIR_OUT &&
+ (endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK) {
+ bulk_out_ep = endpoint->bEndpointAddress;
+ } else {
+ dev_err(&udev->dev,
+ "zd1211rw: Could not find bulk out endpoint\n");
+ return -ENODEV;
+ }
+
+ cmd = kzalloc(31, GFP_KERNEL);
+ if (cmd == NULL)
+ return -ENODEV;
+
+ /* USB bulk command block */
+ cmd[0] = 0x55; /* bulk command signature */
+ cmd[1] = 0x53; /* bulk command signature */
+ cmd[2] = 0x42; /* bulk command signature */
+ cmd[3] = 0x43; /* bulk command signature */
+ cmd[14] = 6; /* command length */
+
+ cmd[15] = 0x1b; /* SCSI command: START STOP UNIT */
+ cmd[19] = 0x2; /* eject disc */
+
+ dev_info(&udev->dev, "Ejecting virtual installer media...\n");
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, bulk_out_ep),
+ cmd, 31, NULL, 2000);
+ kfree(cmd);
+ if (r)
+ return r;
+
+ /* At this point, the device disconnects and reconnects with the real
+ * ID numbers. */
+
+ usb_set_intfdata(intf, NULL);
+ return 0;
+}
+
+static int probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int r;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct net_device *netdev = NULL;
+
+ print_id(udev);
+
+ if (id->driver_info & DEVICE_INSTALLER)
+ return eject_installer(intf);
+
+ switch (udev->speed) {
+ case USB_SPEED_LOW:
+ case USB_SPEED_FULL:
+ case USB_SPEED_HIGH:
+ break;
+ default:
+ dev_dbg_f(&intf->dev, "Unknown USB speed\n");
+ r = -ENODEV;
+ goto error;
+ }
+
+ netdev = zd_netdev_alloc(intf);
+ if (netdev == NULL) {
+ r = -ENOMEM;
+ goto error;
+ }
+
+ r = upload_firmware(udev, id->driver_info);
+ if (r) {
+ dev_err(&intf->dev,
+ "couldn't load firmware. Error number %d\n", r);
+ goto error;
+ }
+
+ r = usb_reset_configuration(udev);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't reset configuration. Error number %d\n", r);
+ goto error;
+ }
+
+ /* At this point the interrupt endpoint is not generally enabled. We
+ * save the USB bandwidth until the network device is opened. But
+ * notify that the initialization of the MAC will require the
+ * interrupts to be temporary enabled.
+ */
+ r = zd_mac_init_hw(zd_netdev_mac(netdev), id->driver_info);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't initialize mac. Error number %d\n", r);
+ goto error;
+ }
+
+ r = register_netdev(netdev);
+ if (r) {
+ dev_dbg_f(&intf->dev,
+ "couldn't register netdev. Error number %d\n", r);
+ goto error;
+ }
+
+ dev_dbg_f(&intf->dev, "successful\n");
+ dev_info(&intf->dev,"%s\n", netdev->name);
+ return 0;
+error:
+ usb_reset_device(interface_to_usbdev(intf));
+ zd_netdev_free(netdev);
+ return r;
+}
+
+static void disconnect(struct usb_interface *intf)
+{
+ struct net_device *netdev = zd_intf_to_netdev(intf);
+ struct zd_mac *mac = zd_netdev_mac(netdev);
+ struct zd_usb *usb = &mac->chip.usb;
+
+ /* Either something really bad happened, or we're just dealing with
+ * a DEVICE_INSTALLER. */
+ if (netdev == NULL)
+ return;
+
+ dev_dbg_f(zd_usb_dev(usb), "\n");
+
+ zd_netdev_disconnect(netdev);
+
+ /* Just in case something has gone wrong! */
+ zd_usb_disable_rx(usb);
+ zd_usb_disable_int(usb);
+
+ /* If the disconnect has been caused by a removal of the
+ * driver module, the reset allows reloading of the driver. If the
+ * reset will not be executed here, the upload of the firmware in the
+ * probe function caused by the reloading of the driver will fail.
+ */
+ usb_reset_device(interface_to_usbdev(intf));
+
+ zd_netdev_free(netdev);
+ dev_dbg(&intf->dev, "disconnected\n");
+}
+
+static struct usb_driver driver = {
+ .name = "zd1211rw",
+ .id_table = usb_ids,
+ .probe = probe,
+ .disconnect = disconnect,
+};
+
+struct workqueue_struct *zd_workqueue;
+
+static int __init usb_init(void)
+{
+ int r;
+
+ pr_debug("usb_init()\n");
+
+ zd_workqueue = create_singlethread_workqueue(driver.name);
+ if (zd_workqueue == NULL) {
+ printk(KERN_ERR "%s: couldn't create workqueue\n", driver.name);
+ return -ENOMEM;
+ }
+
+ r = usb_register(&driver);
+ if (r) {
+ printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
+ return r;
+ }
+
+ pr_debug("zd1211rw initialized\n");
+ return 0;
+}
+
+static void __exit usb_exit(void)
+{
+ pr_debug("usb_exit()\n");
+ usb_deregister(&driver);
+ destroy_workqueue(zd_workqueue);
+}
+
+module_init(usb_init);
+module_exit(usb_exit);
+
+static int usb_int_regs_length(unsigned int count)
+{
+ return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);
+}
+
+static void prepare_read_regs_int(struct zd_usb *usb)
+{
+ struct zd_usb_interrupt *intr = &usb->intr;
+
+ spin_lock(&intr->lock);
+ intr->read_regs_enabled = 1;
+ INIT_COMPLETION(intr->read_regs.completion);
+ spin_unlock(&intr->lock);
+}
+
+static int get_results(struct zd_usb *usb, u16 *values,
+ struct usb_req_read_regs *req, unsigned int count)
+{
+ int r;
+ int i;
+ struct zd_usb_interrupt *intr = &usb->intr;
+ struct read_regs_int *rr = &intr->read_regs;
+ struct usb_int_regs *regs = (struct usb_int_regs *)rr->buffer;
+
+ spin_lock(&intr->lock);
+
+ r = -EIO;
+ /* The created block size seems to be larger than expected.
+ * However results appear to be correct.
+ */
+ if (rr->length < usb_int_regs_length(count)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: actual length %d less than expected %d\n",
+ rr->length, usb_int_regs_length(count));
+ goto error_unlock;
+ }
+ if (rr->length > sizeof(rr->buffer)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: actual length %d exceeds buffer size %zu\n",
+ rr->length, sizeof(rr->buffer));
+ goto error_unlock;
+ }
+
+ for (i = 0; i < count; i++) {
+ struct reg_data *rd = &regs->regs[i];
+ if (rd->addr != req->addr[i]) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "rd[%d] addr %#06hx expected %#06hx\n", i,
+ le16_to_cpu(rd->addr),
+ le16_to_cpu(req->addr[i]));
+ goto error_unlock;
+ }
+ values[i] = le16_to_cpu(rd->value);
+ }
+
+ r = 0;
+error_unlock:
+ spin_unlock(&intr->lock);
+ return r;
+}
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+ const zd_addr_t *addresses, unsigned int count)
+{
+ int r;
+ int i, req_len, actual_req_len;
+ struct usb_device *udev;
+ struct usb_req_read_regs *req = NULL;
+ unsigned long timeout;
+
+ if (count < 1) {
+ dev_dbg_f(zd_usb_dev(usb), "error: count is zero\n");
+ return -EINVAL;
+ }
+ if (count > USB_MAX_IOREAD16_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: count %u exceeds possible max %u\n",
+ count, USB_MAX_IOREAD16_COUNT);
+ return -EINVAL;
+ }
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+ if (!usb_int_enabled(usb)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: usb interrupt not enabled\n");
+ return -EWOULDBLOCK;
+ }
+
+ req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+ req->id = cpu_to_le16(USB_REQ_READ_REGS);
+ for (i = 0; i < count; i++)
+ req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+
+ udev = zd_usb_to_usbdev(usb);
+ prepare_read_regs_int(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto error;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()\n"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto error;
+ }
+
+ timeout = wait_for_completion_timeout(&usb->intr.read_regs.completion,
+ msecs_to_jiffies(1000));
+ if (!timeout) {
+ disable_read_regs_int(usb);
+ dev_dbg_f(zd_usb_dev(usb), "read timed out\n");
+ r = -ETIMEDOUT;
+ goto error;
+ }
+
+ r = get_results(usb, values, req, count);
+error:
+ kfree(req);
+ return r;
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+ unsigned int count)
+{
+ int r;
+ struct usb_device *udev;
+ struct usb_req_write_regs *req = NULL;
+ int i, req_len, actual_req_len;
+
+ if (count == 0)
+ return 0;
+ if (count > USB_MAX_IOWRITE16_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: count %u exceeds possible max %u\n",
+ count, USB_MAX_IOWRITE16_COUNT);
+ return -EINVAL;
+ }
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+
+ req_len = sizeof(struct usb_req_write_regs) +
+ count * sizeof(struct reg_data);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+
+ req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
+ for (i = 0; i < count; i++) {
+ struct reg_data *rw = &req->reg_writes[i];
+ rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+ rw->value = cpu_to_le16(ioreqs[i].value);
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto error;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg()"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto error;
+ }
+
+ /* FALL-THROUGH with r == 0 */
+error:
+ kfree(req);
+ return r;
+}
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
+{
+ int r;
+ struct usb_device *udev;
+ struct usb_req_rfwrite *req = NULL;
+ int i, req_len, actual_req_len;
+ u16 bit_value_template;
+
+ if (in_atomic()) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: io in atomic context not supported\n");
+ return -EWOULDBLOCK;
+ }
+ if (bits < USB_MIN_RFWRITE_BIT_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: bits %d are smaller than"
+ " USB_MIN_RFWRITE_BIT_COUNT %d\n",
+ bits, USB_MIN_RFWRITE_BIT_COUNT);
+ return -EINVAL;
+ }
+ if (bits > USB_MAX_RFWRITE_BIT_COUNT) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: bits %d exceed USB_MAX_RFWRITE_BIT_COUNT %d\n",
+ bits, USB_MAX_RFWRITE_BIT_COUNT);
+ return -EINVAL;
+ }
+#ifdef DEBUG
+ if (value & (~0UL << bits)) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error: value %#09x has bits >= %d set\n",
+ value, bits);
+ return -EINVAL;
+ }
+#endif /* DEBUG */
+
+ dev_dbg_f(zd_usb_dev(usb), "value %#09x bits %d\n", value, bits);
+
+ r = zd_usb_ioread16(usb, &bit_value_template, CR203);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error %d: Couldn't read CR203\n", r);
+ goto out;
+ }
+ bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA);
+
+ req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16);
+ req = kmalloc(req_len, GFP_NOFS);
+ if (!req)
+ return -ENOMEM;
+
+ req->id = cpu_to_le16(USB_REQ_WRITE_RF);
+ /* 1: 3683a, but not used in ZYDAS driver */
+ req->value = cpu_to_le16(2);
+ req->bits = cpu_to_le16(bits);
+
+ for (i = 0; i < bits; i++) {
+ u16 bv = bit_value_template;
+ if (value & (1 << (bits-1-i)))
+ bv |= RF_DATA;
+ req->bit_values[i] = cpu_to_le16(bv);
+ }
+
+ udev = zd_usb_to_usbdev(usb);
+ r = usb_bulk_msg(udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+ req, req_len, &actual_req_len, 1000 /* ms */);
+ if (r) {
+ dev_dbg_f(zd_usb_dev(usb),
+ "error in usb_bulk_msg(). Error number %d\n", r);
+ goto out;
+ }
+ if (req_len != actual_req_len) {
+ dev_dbg_f(zd_usb_dev(usb), "error in usb_bulk_msg()"
+ " req_len %d != actual_req_len %d\n",
+ req_len, actual_req_len);
+ r = -EIO;
+ goto out;
+ }
+
+ /* FALL-THROUGH with r == 0 */
+out:
+ kfree(req);
+ return r;
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
new file mode 100644
index 00000000000..e81a2d3cfff
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -0,0 +1,243 @@
+/* zd_usb.h: Header for USB interface implemented by ZD1211 chip
+ *
+ * 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
+ */
+
+#ifndef _ZD_USB_H
+#define _ZD_USB_H
+
+#include <linux/completion.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+#include <linux/skbuff.h>
+#include <linux/usb.h>
+
+#include "zd_def.h"
+#include "zd_types.h"
+
+enum devicetype {
+ DEVICE_ZD1211 = 0,
+ DEVICE_ZD1211B = 1,
+ DEVICE_INSTALLER = 2,
+};
+
+enum endpoints {
+ EP_CTRL = 0,
+ EP_DATA_OUT = 1,
+ EP_DATA_IN = 2,
+ EP_INT_IN = 3,
+ EP_REGS_OUT = 4,
+};
+
+enum {
+ USB_MAX_TRANSFER_SIZE = 4096, /* bytes */
+ /* FIXME: The original driver uses this value. We have to check,
+ * whether the MAX_TRANSFER_SIZE is sufficient and this needs only be
+ * used if one combined frame is split over two USB transactions.
+ */
+ USB_MAX_RX_SIZE = 4800, /* bytes */
+ USB_MAX_IOWRITE16_COUNT = 15,
+ USB_MAX_IOWRITE32_COUNT = USB_MAX_IOWRITE16_COUNT/2,
+ USB_MAX_IOREAD16_COUNT = 15,
+ USB_MAX_IOREAD32_COUNT = USB_MAX_IOREAD16_COUNT/2,
+ USB_MIN_RFWRITE_BIT_COUNT = 16,
+ USB_MAX_RFWRITE_BIT_COUNT = 28,
+ USB_MAX_EP_INT_BUFFER = 64,
+ USB_ZD1211B_BCD_DEVICE = 0x4810,
+};
+
+enum control_requests {
+ USB_REQ_WRITE_REGS = 0x21,
+ USB_REQ_READ_REGS = 0x22,
+ USB_REQ_WRITE_RF = 0x23,
+ USB_REQ_PROG_FLASH = 0x24,
+ USB_REQ_EEPROM_START = 0x0128, /* ? request is a byte */
+ USB_REQ_EEPROM_MID = 0x28,
+ USB_REQ_EEPROM_END = 0x0228, /* ? request is a byte */
+ USB_REQ_FIRMWARE_DOWNLOAD = 0x30,
+ USB_REQ_FIRMWARE_CONFIRM = 0x31,
+ USB_REQ_FIRMWARE_READ_DATA = 0x32,
+};
+
+struct usb_req_read_regs {
+ __le16 id;
+ __le16 addr[0];
+};
+
+struct reg_data {
+ __le16 addr;
+ __le16 value;
+};
+
+struct usb_req_write_regs {
+ __le16 id;
+ struct reg_data reg_writes[0];
+};
+
+enum {
+ RF_IF_LE = 0x02,
+ RF_CLK = 0x04,
+ RF_DATA = 0x08,
+};
+
+struct usb_req_rfwrite {
+ __le16 id;
+ __le16 value;
+ /* 1: 3683a */
+ /* 2: other (default) */
+ __le16 bits;
+ /* RF2595: 24 */
+ __le16 bit_values[0];
+ /* (CR203 & ~(RF_IF_LE | RF_CLK | RF_DATA)) | (bit ? RF_DATA : 0) */
+};
+
+/* USB interrupt */
+
+enum usb_int_id {
+ USB_INT_TYPE = 0x01,
+ USB_INT_ID_REGS = 0x90,
+ USB_INT_ID_RETRY_FAILED = 0xa0,
+};
+
+enum usb_int_flags {
+ USB_INT_READ_REGS_EN = 0x01,
+};
+
+struct usb_int_header {
+ u8 type; /* must always be 1 */
+ u8 id;
+};
+
+struct usb_int_regs {
+ struct usb_int_header hdr;
+ struct reg_data regs[0];
+};
+
+struct usb_int_retry_fail {
+ struct usb_int_header hdr;
+ u8 new_rate;
+ u8 _dummy;
+ u8 addr[ETH_ALEN];
+ u8 ibss_wakeup_dest;
+};
+
+struct read_regs_int {
+ struct completion completion;
+ /* Stores the USB int structure and contains the USB address of the
+ * first requested register before request.
+ */
+ u8 buffer[USB_MAX_EP_INT_BUFFER];
+ int length;
+ __le16 cr_int_addr;
+};
+
+struct zd_ioreq16 {
+ zd_addr_t addr;
+ u16 value;
+};
+
+struct zd_ioreq32 {
+ zd_addr_t addr;
+ u32 value;
+};
+
+struct zd_usb_interrupt {
+ struct read_regs_int read_regs;
+ spinlock_t lock;
+ struct urb *urb;
+ int interval;
+ u8 read_regs_enabled:1;
+};
+
+static inline struct usb_int_regs *get_read_regs(struct zd_usb_interrupt *intr)
+{
+ return (struct usb_int_regs *)intr->read_regs.buffer;
+}
+
+#define URBS_COUNT 5
+
+struct zd_usb_rx {
+ spinlock_t lock;
+ u8 fragment[2*USB_MAX_RX_SIZE];
+ unsigned int fragment_length;
+ unsigned int usb_packet_size;
+ struct urb **urbs;
+ int urbs_count;
+};
+
+struct zd_usb_tx {
+ spinlock_t lock;
+};
+
+/* Contains the usb parts. The structure doesn't require a lock, because intf
+ * and fw_base_offset, will not be changed after initialization.
+ */
+struct zd_usb {
+ struct zd_usb_interrupt intr;
+ struct zd_usb_rx rx;
+ struct zd_usb_tx tx;
+ struct usb_interface *intf;
+ u16 fw_base_offset;
+};
+
+#define zd_usb_dev(usb) (&usb->intf->dev)
+
+static inline struct usb_device *zd_usb_to_usbdev(struct zd_usb *usb)
+{
+ return interface_to_usbdev(usb->intf);
+}
+
+static inline struct net_device *zd_intf_to_netdev(struct usb_interface *intf)
+{
+ return usb_get_intfdata(intf);
+}
+
+static inline struct net_device *zd_usb_to_netdev(struct zd_usb *usb)
+{
+ return zd_intf_to_netdev(usb->intf);
+}
+
+void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
+ struct usb_interface *intf);
+int zd_usb_init_hw(struct zd_usb *usb);
+void zd_usb_clear(struct zd_usb *usb);
+
+int zd_usb_scnprint_id(struct zd_usb *usb, char *buffer, size_t size);
+
+int zd_usb_enable_int(struct zd_usb *usb);
+void zd_usb_disable_int(struct zd_usb *usb);
+
+int zd_usb_enable_rx(struct zd_usb *usb);
+void zd_usb_disable_rx(struct zd_usb *usb);
+
+int zd_usb_tx(struct zd_usb *usb, const u8 *frame, unsigned int length);
+
+int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
+ const zd_addr_t *addresses, unsigned int count);
+
+static inline int zd_usb_ioread16(struct zd_usb *usb, u16 *value,
+ const zd_addr_t addr)
+{
+ return zd_usb_ioread16v(usb, value, (const zd_addr_t *)&addr, 1);
+}
+
+int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
+ unsigned int count);
+
+int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+
+extern struct workqueue_struct *zd_workqueue;
+
+#endif /* _ZD_USB_H */
diff --git a/drivers/net/wireless/zd1211rw/zd_util.c b/drivers/net/wireless/zd1211rw/zd_util.c
new file mode 100644
index 00000000000..d20036c15d1
--- /dev/null
+++ b/drivers/net/wireless/zd1211rw/zd_util.c
@@ -0,0 +1,82 @@
+/* zd_util.c
+ *
+ * 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
+ *
+ * Utility program
+ */
+
+#include "zd_def.h"
+#include "zd_util.h"
+
+#ifdef DEBUG
+static char hex(u8 v)
+{
+ v &= 0xf;
+ return (v < 10 ? '0' : 'a' - 10) + v;
+}
+
+static char hex_print(u8 c)
+{
+ return (0x20 <= c && c < 0x7f) ? c : '.';
+}
+
+static void dump_line(const u8 *bytes, size_t size)
+{
+ char c;
+ size_t i;
+
+ size = size <= 8 ? size : 8;
+ printk(KERN_DEBUG "zd1211 %p ", bytes);
+ for (i = 0; i < 8; i++) {
+ switch (i) {
+ case 1:
+ case 5:
+ c = '.';
+ break;
+ case 3:
+ c = ':';
+ break;
+ default:
+ c = ' ';
+ }
+ if (i < size) {
+ printk("%c%c%c", hex(bytes[i] >> 4), hex(bytes[i]), c);
+ } else {
+ printk(" %c", c);
+ }
+ }
+
+ for (i = 0; i < size; i++)
+ printk("%c", hex_print(bytes[i]));
+ printk("\n");
+}
+
+void zd_hexdump(const void *bytes, size_t size)
+{
+ size_t i = 0;
+
+ do {
+ dump_line((u8 *)bytes + i, size-i);
+ i += 8;
+ } while (i < size);
+}
+#endif /* DEBUG */
+
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size)
+{
+ if (buffer_size < tail_size)
+ return NULL;
+ return (u8 *)buffer + (buffer_size - tail_size);
+}
diff --git a/drivers/w1/w1_io.h b/drivers/net/wireless/zd1211rw/zd_util.h
index 9a76d2ad69c..ce26f7adea9 100644
--- a/drivers/w1/w1_io.h
+++ b/drivers/net/wireless/zd1211rw/zd_util.h
@@ -1,8 +1,4 @@
-/*
- * w1_io.h
- *
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
- *
+/* zd_util.h
*
* 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
@@ -19,18 +15,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifndef __W1_IO_H
-#define __W1_IO_H
+#ifndef _ZD_UTIL_H
+#define _ZD_UTIL_H
-#include "w1.h"
+void *zd_tail(const void *buffer, size_t buffer_size, size_t tail_size);
-u8 w1_triplet(struct w1_master *dev, int bdir);
-void w1_write_8(struct w1_master *, u8);
-int w1_reset_bus(struct w1_master *);
-u8 w1_calc_crc8(u8 *, int);
-void w1_write_block(struct w1_master *, const u8 *, int);
-u8 w1_read_block(struct w1_master *, u8 *, int);
-void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb);
-int w1_reset_select_slave(struct w1_slave *sl);
+#ifdef DEBUG
+void zd_hexdump(const void *bytes, size_t size);
+#else
+#define zd_hexdump(bytes, size)
+#endif /* DEBUG */
-#endif /* __W1_IO_H */
+#endif /* _ZD_UTIL_H */
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index ecec8e5db78..a4c4953f136 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -19,37 +19,13 @@
Support and updates available at
http://www.scyld.com/network/yellowfin.html
+ [link no longer provides useful info -jgarzik]
-
- Linux kernel changelog:
- -----------------------
-
- LK1.1.1 (jgarzik): Port to 2.4 kernel
-
- LK1.1.2 (jgarzik):
- * Merge in becker version 1.05
-
- LK1.1.3 (jgarzik):
- * Various cleanups
- * Update yellowfin_timer to correctly calculate duplex.
- (suggested by Manfred Spraul)
-
- LK1.1.4 (val@nmt.edu):
- * Fix three endian-ness bugs
- * Support dual function SYM53C885E ethernet chip
-
- LK1.1.5 (val@nmt.edu):
- * Fix forced full-duplex bug I introduced
-
- LK1.1.6 (val@nmt.edu):
- * Only print warning on truly "oversized" packets
- * Fix theoretical bug on gigabit cards - return to 1.1.3 behavior
-
*/
#define DRV_NAME "yellowfin"
-#define DRV_VERSION "1.05+LK1.1.6"
-#define DRV_RELDATE "Feb 11, 2002"
+#define DRV_VERSION "2.1"
+#define DRV_RELDATE "Sep 11, 2006"
#define PFX DRV_NAME ": "
@@ -161,7 +137,7 @@ MODULE_PARM_DESC(gx_fix, "G-NIC: enable GX server chipset bug workaround (0-1)")
I. Board Compatibility
This device driver is designed for the Packet Engines "Yellowfin" Gigabit
-Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the
+Ethernet adapter. The G-NIC 64-bit PCI card is supported, as well as the
Symbios 53C885E dual function chip.
II. Board-specific settings
@@ -232,28 +208,18 @@ IVc. Errata
See Packet Engines confidential appendix (prototype chips only).
*/
-
-enum pci_id_flags_bits {
- /* Set PCI command register bits before calling probe1(). */
- PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
- /* Read and map the single following PCI BAR. */
- PCI_ADDR0=0<<4, PCI_ADDR1=1<<4, PCI_ADDR2=2<<4, PCI_ADDR3=3<<4,
- PCI_ADDR_64BITS=0x100, PCI_NO_ACPI_WAKE=0x200, PCI_NO_MIN_LATENCY=0x400,
- PCI_UNUSED_IRQ=0x800,
-};
+
enum capability_flags {
HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
HasMACAddrBug=32, /* Only on early revs. */
DontUseEeprom=64, /* Don't read the MAC from the EEPROm. */
};
+
/* The PCI I/O space extent. */
-#define YELLOWFIN_SIZE 0x100
-#ifdef USE_IO_OPS
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_IO | PCI_ADDR0)
-#else
-#define PCI_IOTYPE (PCI_USES_MASTER | PCI_USES_MEM | PCI_ADDR1)
-#endif
+enum {
+ YELLOWFIN_SIZE = 0x100,
+};
struct pci_id_info {
const char *name;
@@ -261,24 +227,21 @@ struct pci_id_info {
int pci, pci_mask, subsystem, subsystem_mask;
int revision, revision_mask; /* Only 8 bits. */
} id;
- enum pci_id_flags_bits pci_flags;
- int io_size; /* Needed for I/O region check or ioremap(). */
int drv_flags; /* Driver use, intended as capability flags. */
};
static const struct pci_id_info pci_id_tbl[] = {
{"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff},
- PCI_IOTYPE, YELLOWFIN_SIZE,
FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom},
{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
- PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | DontUseEeprom },
- {NULL,},
+ HasMII | DontUseEeprom },
+ { }
};
-static struct pci_device_id yellowfin_pci_tbl[] = {
+static const struct pci_device_id yellowfin_pci_tbl[] = {
{ 0x1000, 0x0702, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ 0x1000, 0x0701, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { 0, }
+ { }
};
MODULE_DEVICE_TABLE (pci, yellowfin_pci_tbl);
@@ -393,7 +356,7 @@ static void yellowfin_error(struct net_device *dev, int intr_status);
static int yellowfin_close(struct net_device *dev);
static struct net_device_stats *yellowfin_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
-static struct ethtool_ops ethtool_ops;
+static const struct ethtool_ops ethtool_ops;
static int __devinit yellowfin_init_one(struct pci_dev *pdev,
@@ -414,7 +377,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
#else
int bar = 1;
#endif
-
+
/* when built into the kernel, we only print version if device is found */
#ifndef MODULE
static int printed_version;
@@ -545,11 +508,11 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
}
find_cnt++;
-
+
return 0;
err_out_unmap_status:
- pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
+ pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
np->tx_status_dma);
err_out_unmap_rx:
pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
@@ -606,7 +569,7 @@ static void mdio_write(void __iomem *ioaddr, int phy_id, int location, int value
return;
}
-
+
static int yellowfin_open(struct net_device *dev)
{
struct yellowfin_private *yp = netdev_priv(dev);
@@ -616,7 +579,7 @@ static int yellowfin_open(struct net_device *dev)
/* Reset the chip. */
iowrite32(0x80000000, ioaddr + DMACtrl);
- i = request_irq(dev->irq, &yellowfin_interrupt, SA_SHIRQ, dev->name, dev);
+ i = request_irq(dev->irq, &yellowfin_interrupt, IRQF_SHARED, dev->name, dev);
if (i) return i;
if (yellowfin_debug > 1)
@@ -710,7 +673,7 @@ static void yellowfin_timer(unsigned long data)
dev->name, yp->phys[0], bmsr, lpa);
yp->full_duplex = mii_duplex(yp->duplex_lock, negotiated);
-
+
iowrite16(0x101C | (yp->full_duplex ? 2 : 0), ioaddr + Cnfg);
if (bmsr & BMSR_LSTATUS)
@@ -829,10 +792,10 @@ static void yellowfin_init_ring(struct net_device *dev)
/* Om pade ummmmm... */
yp->tx_ring[j].addr = cpu_to_le32(yp->tx_status_dma +
i*sizeof(struct tx_status_words) +
- &(yp->tx_status[0].tx_errs) -
+ &(yp->tx_status[0].tx_errs) -
&(yp->tx_status[0]));
}
- yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
+ yp->tx_ring[j].branch_addr = cpu_to_le32(yp->tx_ring_dma +
((j+1)%(2*TX_RING_SIZE))*sizeof(struct yellowfin_desc));
}
/* Wrap ring */
@@ -872,7 +835,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
yp->tx_skbuff[entry] = skb;
#ifdef NO_TXSTATS
- yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
+ yp->tx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
skb->data, len, PCI_DMA_TODEVICE));
yp->tx_ring[entry].result_status = 0;
if (entry >= TX_RING_SIZE-1) {
@@ -888,9 +851,9 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
yp->cur_tx++;
#else
yp->tx_ring[entry<<1].request_cnt = len;
- yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
+ yp->tx_ring[entry<<1].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
skb->data, len, PCI_DMA_TODEVICE));
- /* The input_last (status-write) command is constant, but we must
+ /* The input_last (status-write) command is constant, but we must
rewrite the subsequent 'stop' command. */
yp->cur_tx++;
@@ -942,7 +905,7 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_re
yp = netdev_priv(dev);
ioaddr = yp->base;
-
+
spin_lock (&yp->lock);
do {
@@ -1030,8 +993,8 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_re
yp->stats.tx_packets++;
}
/* Free the original skb. */
- pci_unmap_single(yp->pci_dev,
- yp->tx_ring[entry<<1].addr, skb->len,
+ pci_unmap_single(yp->pci_dev,
+ yp->tx_ring[entry<<1].addr, skb->len,
PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
yp->tx_skbuff[entry] = 0;
@@ -1110,7 +1073,7 @@ static int yellowfin_rx(struct net_device *dev)
yp->rx_buf_sz, PCI_DMA_FROMDEVICE);
desc_status = le32_to_cpu(desc->result_status) >> 16;
buf_addr = rx_skb->data;
- data_size = (le32_to_cpu(desc->dbdma_cmd) -
+ data_size = (le32_to_cpu(desc->dbdma_cmd) -
le32_to_cpu(desc->result_status)) & 0xffff;
frame_status = le16_to_cpu(get_unaligned((s16*)&(buf_addr[data_size - 2])));
if (yellowfin_debug > 4)
@@ -1146,7 +1109,7 @@ static int yellowfin_rx(struct net_device *dev)
} else if ((yp->flags & HasMACAddrBug) &&
memcmp(le32_to_cpu(yp->rx_ring_dma +
entry*sizeof(struct yellowfin_desc)),
- dev->dev_addr, 6) != 0 &&
+ dev->dev_addr, 6) != 0 &&
memcmp(le32_to_cpu(yp->rx_ring_dma +
entry*sizeof(struct yellowfin_desc)),
"\377\377\377\377\377\377", 6) != 0) {
@@ -1172,9 +1135,9 @@ static int yellowfin_rx(struct net_device *dev)
without copying to a properly sized skbuff. */
if (pkt_len > rx_copybreak) {
skb_put(skb = rx_skb, pkt_len);
- pci_unmap_single(yp->pci_dev,
- yp->rx_ring[entry].addr,
- yp->rx_buf_sz,
+ pci_unmap_single(yp->pci_dev,
+ yp->rx_ring[entry].addr,
+ yp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
yp->rx_skbuff[entry] = NULL;
} else {
@@ -1344,8 +1307,6 @@ static void set_rx_mode(struct net_device *dev)
/* Stop the Rx process to change any value. */
iowrite16(cfg_value & ~0x1000, ioaddr + Cnfg);
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
- /* Unconditionally log net taps. */
- printk(KERN_NOTICE "%s: Promiscuous mode enabled.\n", dev->name);
iowrite16(0x000F, ioaddr + AddrMode);
} else if ((dev->mc_count > 64) || (dev->flags & IFF_ALLMULTI)) {
/* Too many to filter well, or accept all multicasts. */
@@ -1391,7 +1352,7 @@ static void yellowfin_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
strcpy(info->bus_info, pci_name(np->pci_dev));
}
-static struct ethtool_ops ethtool_ops = {
+static const struct ethtool_ops ethtool_ops = {
.get_drvinfo = yellowfin_get_drvinfo
};
@@ -1442,7 +1403,7 @@ static void __devexit yellowfin_remove_one (struct pci_dev *pdev)
BUG_ON(!dev);
np = netdev_priv(dev);
- pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
+ pci_free_consistent(pdev, STATUS_TOTAL_SIZE, np->tx_status,
np->tx_status_dma);
pci_free_consistent(pdev, RX_TOTAL_SIZE, np->rx_ring, np->rx_ring_dma);
pci_free_consistent(pdev, TX_TOTAL_SIZE, np->tx_ring, np->tx_ring_dma);
@@ -1471,7 +1432,7 @@ static int __init yellowfin_init (void)
#ifdef MODULE
printk(version);
#endif
- return pci_module_init (&yellowfin_driver);
+ return pci_register_driver(&yellowfin_driver);
}
@@ -1483,7 +1444,7 @@ static void __exit yellowfin_cleanup (void)
module_init(yellowfin_init);
module_exit(yellowfin_cleanup);
-
+
/*
* Local variables:
* compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c"
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index a7c089df66e..656d5a02908 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -75,7 +75,7 @@
- Now survives unplugging/replugging cable.
Some code was taken from wavelan_cs.
-
+
Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
anything else. Testers (and detailed bug reports) are welcome :-).
@@ -85,7 +85,6 @@
- Understand why some traffic patterns add a 1s latency...
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -172,7 +171,7 @@ static int znet_request_resources (struct net_device *dev)
{
struct znet_private *znet = dev->priv;
unsigned long flags;
-
+
if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev))
goto failed;
if (request_dma (znet->rx_dma, "ZNet rx"))
@@ -206,7 +205,7 @@ static void znet_release_resources (struct net_device *dev)
{
struct znet_private *znet = dev->priv;
unsigned long flags;
-
+
release_region (znet->sia_base, znet->sia_size);
release_region (dev->base_addr, znet->io_size);
flags = claim_dma_lock();
@@ -230,7 +229,7 @@ static void znet_transceiver_power (struct net_device *dev, int on)
v = inb(znet->sia_base + 1) | 0x84;
else
v = inb(znet->sia_base + 1) & ~0x84;
-
+
outb(v, znet->sia_base+1); /* Turn on/off LAN power (bit 2). */
}
@@ -243,7 +242,7 @@ static void znet_set_multicast_list (struct net_device *dev)
struct i82593_conf_block *cfblk = &znet->i593_init;
memset(cfblk, 0x00, sizeof(struct i82593_conf_block));
-
+
/* The configuration block. What an undocumented nightmare.
The first set of values are those suggested (without explanation)
for ethernet in the Intel 82586 databook. The rest appear to be
@@ -252,7 +251,7 @@ static void znet_set_multicast_list (struct net_device *dev)
/* maz : Rewritten to take advantage of the wanvelan includes.
At least we have names, not just blind values */
-
+
/* Byte 0 */
cfblk->fifo_limit = 10; /* = 16 B rx and 80 B tx fifo thresholds */
cfblk->forgnesi = 0; /* 0=82C501, 1=AMD7992B compatibility */
@@ -270,23 +269,23 @@ static void znet_set_multicast_list (struct net_device *dev)
cfblk->acloc = 1; /* Disable source addr insertion by i82593 */
cfblk->preamb_len = 2; /* 8 bytes preamble */
cfblk->loopback = 0; /* Loopback off */
-
+
/* Byte 3 */
cfblk->lin_prio = 0; /* Default priorities & backoff methods. */
cfblk->tbofstop = 0;
cfblk->exp_prio = 0;
cfblk->bof_met = 0;
-
+
/* Byte 4 */
cfblk->ifrm_spc = 6; /* 96 bit times interframe spacing */
-
+
/* Byte 5 */
cfblk->slottim_low = 0; /* 512 bit times slot time (low) */
-
+
/* Byte 6 */
cfblk->slottim_hi = 2; /* 512 bit times slot time (high) */
cfblk->max_retr = 15; /* 15 collisions retries */
-
+
/* Byte 7 */
cfblk->prmisc = ((dev->flags & IFF_PROMISC) ? 1 : 0); /* Promiscuous mode */
cfblk->bc_dis = 0; /* Enable broadcast reception */
@@ -294,15 +293,15 @@ static void znet_set_multicast_list (struct net_device *dev)
cfblk->nocrc_ins = 0; /* i82593 generates CRC */
cfblk->crc_1632 = 0; /* 32-bit Autodin-II CRC */
cfblk->crs_cdt = 0; /* CD not to be interpreted as CS */
-
+
/* Byte 8 */
cfblk->cs_filter = 0; /* CS is recognized immediately */
cfblk->crs_src = 0; /* External carrier sense */
cfblk->cd_filter = 0; /* CD is recognized immediately */
-
+
/* Byte 9 */
cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
-
+
/* Byte A */
cfblk->lng_typ = 1; /* Type/length checks OFF */
cfblk->lng_fld = 1; /* Disable 802.3 length field check */
@@ -312,15 +311,15 @@ static void znet_set_multicast_list (struct net_device *dev)
cfblk->tx_jabber = 0; /* Disable jabber jam sequence */
cfblk->hash_1 = 1; /* Use bits 0-5 in mc address hash */
cfblk->lbpkpol = 0; /* Loopback pin active high */
-
+
/* Byte B */
cfblk->fdx = 0; /* Disable full duplex operation */
-
+
/* Byte C */
cfblk->dummy_6 = 0x3f; /* all ones, Default multicast addresses & backoff. */
cfblk->mult_ia = 0; /* No multiple individual addresses */
cfblk->dis_bof = 0; /* Disable the backoff algorithm ?! */
-
+
/* Byte D */
cfblk->dummy_1 = 1; /* set to 1 */
cfblk->tx_ifs_retrig = 3; /* Hmm... Disabled */
@@ -328,7 +327,7 @@ static void znet_set_multicast_list (struct net_device *dev)
cfblk->rcv_mon = 0; /* Monitor mode disabled */
cfblk->frag_acpt = 0; /* Do not accept fragments */
cfblk->tstrttrs = 0; /* No start transmission threshold */
-
+
/* Byte E */
cfblk->fretx = 1; /* FIFO automatic retransmission */
cfblk->runt_eop = 0; /* drop "runt" packets */
@@ -351,7 +350,7 @@ static void znet_set_multicast_list (struct net_device *dev)
printk ("%02X ", c[i]);
printk ("\n");
}
-
+
*znet->tx_cur++ = sizeof(struct i82593_conf_block);
memcpy(znet->tx_cur, cfblk, sizeof(struct i82593_conf_block));
znet->tx_cur += sizeof(struct i82593_conf_block)/2;
@@ -360,7 +359,7 @@ static void znet_set_multicast_list (struct net_device *dev)
/* XXX FIXME maz : Add multicast addresses here, so having a
* multicast address configured isn't equal to IFF_ALLMULTI */
}
-
+
/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe
BIOS area. We just scan for the signature, and pull the vital parameters
out of the structure. */
@@ -439,7 +438,7 @@ static int __init znet_probe (void)
printk (KERN_WARNING "tx/rx crossing DMA frontiers, giving up\n");
goto free_tx;
}
-
+
znet->rx_end = znet->rx_start + RX_BUF_SIZE/2;
znet->tx_buf_len = TX_BUF_SIZE/2;
znet->tx_end = znet->tx_start + znet->tx_buf_len;
@@ -467,7 +466,7 @@ static int __init znet_probe (void)
return err;
}
-
+
static int znet_open(struct net_device *dev)
{
int ioaddr = dev->base_addr;
@@ -482,7 +481,7 @@ static int znet_open(struct net_device *dev)
}
znet_transceiver_power (dev, 1);
-
+
/* According to the Crynwr driver we should wait 50 msec. for the
LAN clock to stabilize. My experiments indicates that the '593 can
be initialized immediately. The delay is probably needed for the
@@ -497,7 +496,7 @@ static int znet_open(struct net_device *dev)
* all, even if the message is completly harmless on my
* setup. */
mdelay (50);
-
+
/* This follows the packet driver's lead, and checks for success. */
if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00)
printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n",
@@ -548,9 +547,9 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
return 0;
length = ETH_ZLEN;
}
-
+
netif_stop_queue (dev);
-
+
/* Check that the part hasn't reset itself, probably from suspend. */
outb(CR0_STATUS_0, ioaddr);
if (inw(ioaddr) == 0x0010 &&
@@ -566,7 +565,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
unsigned char *buf = (void *)skb->data;
ushort *tx_link = znet->tx_cur - 1;
ushort rnd_len = (length + 1)>>1;
-
+
znet->stats.tx_bytes+=length;
if (znet->tx_cur >= znet->tx_end)
@@ -598,7 +597,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
if (znet_debug > 4)
printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);
}
- dev_kfree_skb(skb);
+ dev_kfree_skb(skb);
return 0;
}
@@ -617,7 +616,7 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
spin_lock (&znet->lock);
-
+
ioaddr = dev->base_addr;
outb(CR0_STATUS_0, ioaddr);
@@ -667,7 +666,7 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* packet. Flip it off, then on to
* reset it. This is very empirical,
* but it seems to work. */
-
+
znet_transceiver_power (dev, 0);
znet_transceiver_power (dev, 1);
}
@@ -683,7 +682,7 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
} while (boguscnt--);
spin_unlock (&znet->lock);
-
+
return IRQ_RETVAL(handled);
}
@@ -749,7 +748,7 @@ static void znet_rx(struct net_device *dev)
ushort *this_rfp_ptr = znet->rx_start + next_frame_end_offset;
int status = this_rfp_ptr[-4];
int pkt_len = this_rfp_ptr[-2];
-
+
if (znet_debug > 5)
printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"
" next %04x.\n", next_frame_end_offset<<1, status, pkt_len,
@@ -830,9 +829,9 @@ static int znet_close(struct net_device *dev)
printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);
/* Turn off transceiver power. */
znet_transceiver_power (dev, 0);
-
+
znet_release_resources (dev);
-
+
return 0;
}
@@ -857,7 +856,7 @@ static void show_dma(struct net_device *dev)
addr |= inb(dma_port) << 8;
residue = get_dma_residue(znet->tx_dma);
-
+
if (znet_debug > 1) {
flags=claim_dma_lock();
printk(KERN_DEBUG "Stat:%02x Addr: %04x cnt:%3x\n",
@@ -895,7 +894,7 @@ static void hardware_init(struct net_device *dev)
set_dma_count(znet->tx_dma, znet->tx_buf_len<<1);
enable_dma(znet->tx_dma);
release_dma_lock(flags);
-
+
if (znet_debug > 1)
printk(KERN_DEBUG "%s: Initializing the i82593, rx buf %p tx buf %p\n",
dev->name, znet->rx_start,znet->tx_start);
diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c
index 8037e5806d0..df04e050c64 100644
--- a/drivers/net/zorro8390.c
+++ b/drivers/net/zorro8390.c
@@ -201,7 +201,7 @@ static int __devinit zorro8390_init(struct net_device *dev,
dev->irq = IRQ_AMIGA_PORTS;
/* Install the Interrupt handler */
- i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, SA_SHIRQ, DRV_NAME, dev);
+ i = request_irq(IRQ_AMIGA_PORTS, ei_interrupt, IRQF_SHARED, DRV_NAME, dev);
if (i) return i;
for(i = 0; i < ETHER_ADDR_LEN; i++) {
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 14cbe34eb89..3a0a3a73493 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -7,7 +7,6 @@
* and others.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/drivers/nubus/nubus_syms.c b/drivers/nubus/nubus_syms.c
index 22c1dc9f87b..9204f04fbf0 100644
--- a/drivers/nubus/nubus_syms.c
+++ b/drivers/nubus/nubus_syms.c
@@ -2,7 +2,6 @@
(c) 1999 David Huggins-Daines <dhd@debian.org> */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/nubus.h>
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index b2e8e49c865..43e521e9912 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -108,10 +108,10 @@ static int module_load_notify(struct notifier_block * self, unsigned long val, v
return 0;
/* FIXME: should we process all CPU buffers ? */
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
add_event_entry(ESCAPE_CODE);
add_event_entry(MODULE_LOADED_CODE);
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
#endif
return 0;
}
@@ -501,7 +501,7 @@ void sync_buffer(int cpu)
sync_buffer_state state = sb_buffer_start;
unsigned long available;
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
add_cpu_switch(cpu);
@@ -550,5 +550,5 @@ void sync_buffer(int cpu)
mark_done(cpu);
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
}
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index b80318f0342..04d641714d3 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -24,7 +24,7 @@
#include "event_buffer.h"
#include "oprofile_stats.h"
-DECLARE_MUTEX(buffer_sem);
+DEFINE_MUTEX(buffer_mutex);
static unsigned long buffer_opened;
static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
@@ -32,7 +32,7 @@ static unsigned long * event_buffer;
static unsigned long buffer_size;
static unsigned long buffer_watershed;
static size_t buffer_pos;
-/* atomic_t because wait_event checks it outside of buffer_sem */
+/* atomic_t because wait_event checks it outside of buffer_mutex */
static atomic_t buffer_ready = ATOMIC_INIT(0);
/* Add an entry to the event buffer. When we
@@ -60,10 +60,10 @@ void add_event_entry(unsigned long value)
*/
void wake_up_buffer_waiter(void)
{
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
atomic_set(&buffer_ready, 1);
wake_up(&buffer_wait);
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
}
@@ -162,7 +162,7 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
if (!atomic_read(&buffer_ready))
return -EAGAIN;
- down(&buffer_sem);
+ mutex_lock(&buffer_mutex);
atomic_set(&buffer_ready, 0);
@@ -177,7 +177,7 @@ static ssize_t event_buffer_read(struct file * file, char __user * buf,
buffer_pos = 0;
out:
- up(&buffer_sem);
+ mutex_unlock(&buffer_mutex);
return retval;
}
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 01802363059..92416276e57 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -11,7 +11,7 @@
#define EVENT_BUFFER_H
#include <linux/types.h>
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
int alloc_event_buffer(void);
@@ -46,6 +46,6 @@ extern struct file_operations event_buffer_fops;
/* mutex between sync_cpu_buffers() and the
* file reading code.
*/
-extern struct semaphore buffer_sem;
+extern struct mutex buffer_mutex;
#endif /* EVENT_BUFFER_H */
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
index b3f1cd6a24c..e5162a64018 100644
--- a/drivers/oprofile/oprof.c
+++ b/drivers/oprofile/oprof.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/oprofile.h>
#include <linux/moduleparam.h>
-#include <asm/semaphore.h>
+#include <asm/mutex.h>
#include "oprof.h"
#include "event_buffer.h"
@@ -25,7 +25,7 @@ struct oprofile_operations oprofile_ops;
unsigned long oprofile_started;
unsigned long backtrace_depth;
static unsigned long is_setup;
-static DECLARE_MUTEX(start_sem);
+static DEFINE_MUTEX(start_mutex);
/* timer
0 - use performance monitoring hardware if available
@@ -37,7 +37,7 @@ int oprofile_setup(void)
{
int err;
- down(&start_sem);
+ mutex_lock(&start_mutex);
if ((err = alloc_cpu_buffers()))
goto out;
@@ -57,7 +57,7 @@ int oprofile_setup(void)
goto out3;
is_setup = 1;
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return 0;
out3:
@@ -68,7 +68,7 @@ out2:
out1:
free_cpu_buffers();
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return err;
}
@@ -78,7 +78,7 @@ int oprofile_start(void)
{
int err = -EINVAL;
- down(&start_sem);
+ mutex_lock(&start_mutex);
if (!is_setup)
goto out;
@@ -95,7 +95,7 @@ int oprofile_start(void)
oprofile_started = 1;
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return err;
}
@@ -103,7 +103,7 @@ out:
/* echo 0>/dev/oprofile/enable */
void oprofile_stop(void)
{
- down(&start_sem);
+ mutex_lock(&start_mutex);
if (!oprofile_started)
goto out;
oprofile_ops.stop();
@@ -111,20 +111,20 @@ void oprofile_stop(void)
/* wake up the daemon to read what remains */
wake_up_buffer_waiter();
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
}
void oprofile_shutdown(void)
{
- down(&start_sem);
+ mutex_lock(&start_mutex);
sync_stop();
if (oprofile_ops.shutdown)
oprofile_ops.shutdown();
is_setup = 0;
free_event_buffer();
free_cpu_buffers();
- up(&start_sem);
+ mutex_unlock(&start_mutex);
}
@@ -132,7 +132,7 @@ int oprofile_set_backtrace(unsigned long val)
{
int err = 0;
- down(&start_sem);
+ mutex_lock(&start_mutex);
if (oprofile_started) {
err = -EBUSY;
@@ -147,7 +147,7 @@ int oprofile_set_backtrace(unsigned long val)
backtrace_depth = val;
out:
- up(&start_sem);
+ mutex_unlock(&start_mutex);
return err;
}
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 71c2da277d6..5756401fb15 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -31,7 +31,6 @@ static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
@@ -110,8 +109,8 @@ static ssize_t ulong_write_file(struct file * file, char const __user * buf, siz
static int default_open(struct inode * inode, struct file * filp)
{
- if (inode->u.generic_ip)
- filp->private_data = inode->u.generic_ip;
+ if (inode->i_private)
+ filp->private_data = inode->i_private;
return 0;
}
@@ -158,7 +157,7 @@ int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
if (!d)
return -EFAULT;
- d->d_inode->u.generic_ip = val;
+ d->d_inode->i_private = val;
return 0;
}
@@ -171,7 +170,7 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
if (!d)
return -EFAULT;
- d->d_inode->u.generic_ip = val;
+ d->d_inode->i_private = val;
return 0;
}
@@ -197,7 +196,7 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
if (!d)
return -EFAULT;
- d->d_inode->u.generic_ip = val;
+ d->d_inode->i_private = val;
return 0;
}
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
index 3f5de867acd..1d3b84b4af3 100644
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -140,18 +140,37 @@ config CHASSIS_LCD_LED
If unsure, say Y.
config PDC_CHASSIS
- bool "PDC chassis State Panel support"
+ bool "PDC chassis state codes support"
default y
help
- Say Y here if you want to enable support for the LED State front
- panel as found on E class, and support for the GSP Virtual Front
- Panel (LED State and message logging) as found on high end
- servers such as A, L and N-class.
-
- This has nothing to do with Chassis LCD and LED support.
+ Say Y here if you want to enable support for Chassis codes.
+ That includes support for LED State front panel as found on E
+ class, and support for the GSP Virtual Front Panel (LED State and
+ message logging) as found on high end servers such as A, L and
+ N-class.
+ This driver will also display progress messages on LCD display,
+ such as "INI", "RUN" and "FLT", and might thus clobber messages
+ shown by the LED/LCD driver.
+ This driver updates the state panel (LED and/or LCD) upon system
+ state change (eg: boot, shutdown or panic).
If unsure, say Y.
+
+config PDC_CHASSIS_WARN
+ bool "PDC chassis warnings support"
+ depends on PROC_FS
+ default y
+ help
+ Say Y here if you want to enable support for Chassis warnings.
+ This will add a proc entry '/proc/chassis' giving some information
+ about the overall health state of the system.
+ This includes NVRAM battery level, overtemp or failures such as
+ fans or power units.
+
+ If unsure, say Y.
+
+
config PDC_STABLE
tristate "PDC Stable Storage support"
depends on SYSFS
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index a5d826237b2..68cb3a08005 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -31,7 +31,6 @@
** the coherency design originally worked out. Only PCX-W does.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 6e8ed0c81a6..0d96c50ffe9 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -43,7 +43,6 @@
** for PCI drivers devices which implement/use MMIO registers.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -299,7 +298,7 @@ struct pci_port_ops dino_port_ops = {
static void dino_disable_irq(unsigned int irq)
{
- struct dino_device *dino_dev = irq_desc[irq].handler_data;
+ struct dino_device *dino_dev = irq_desc[irq].chip_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
DBG(KERN_WARNING "%s(0x%p, %d)\n", __FUNCTION__, dino_dev, irq);
@@ -311,7 +310,7 @@ static void dino_disable_irq(unsigned int irq)
static void dino_enable_irq(unsigned int irq)
{
- struct dino_device *dino_dev = irq_desc[irq].handler_data;
+ struct dino_device *dino_dev = irq_desc[irq].chip_data;
int local_irq = gsc_find_local_irq(irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
u32 tmp;
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 9d3bd15bf53..884965cedec 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -340,7 +340,7 @@ static int __devinit eisa_probe(struct parisc_device *dev)
}
pcibios_register_hba(&eisa_dev.hba);
- result = request_irq(dev->irq, eisa_irq, SA_SHIRQ, "EISA", &eisa_dev);
+ result = request_irq(dev->irq, eisa_irq, IRQF_SHARED, "EISA", &eisa_dev);
if (result) {
printk(KERN_ERR "EISA: request_irq failed!\n");
return result;
@@ -350,7 +350,7 @@ static int __devinit eisa_probe(struct parisc_device *dev)
irq_desc[2].action = &irq2_action;
for (i = 0; i < 16; i++) {
- irq_desc[i].handler = &eisa_interrupt_type;
+ irq_desc[i].chip = &eisa_interrupt_type;
}
EISA_bus = 1;
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index 16d40f95978..b45aa5c675a 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -14,7 +14,6 @@
*/
#include <linux/bitops.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -109,7 +108,7 @@ int gsc_find_local_irq(unsigned int irq, int *global_irqs, int limit)
static void gsc_asic_disable_irq(unsigned int irq)
{
- struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
+ struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
@@ -124,7 +123,7 @@ static void gsc_asic_disable_irq(unsigned int irq)
static void gsc_asic_enable_irq(unsigned int irq)
{
- struct gsc_asic *irq_dev = irq_desc[irq].handler_data;
+ struct gsc_asic *irq_dev = irq_desc[irq].chip_data;
int local_irq = gsc_find_local_irq(irq, irq_dev->global_irq, 32);
u32 imr;
@@ -164,8 +163,8 @@ int gsc_assign_irq(struct hw_interrupt_type *type, void *data)
if (irq > GSC_IRQ_MAX)
return NO_IRQ;
- irq_desc[irq].handler = type;
- irq_desc[irq].handler_data = data;
+ irq_desc[irq].chip = type;
+ irq_desc[irq].chip_data = data;
return irq++;
}
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 7a458d5bc75..1fbda77cefc 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -619,7 +619,7 @@ iosapic_set_irt_data( struct vector_info *vi, u32 *dp0, u32 *dp1)
static struct vector_info *iosapic_get_vector(unsigned int irq)
{
- return irq_desc[irq].handler_data;
+ return irq_desc[irq].chip_data;
}
static void iosapic_disable_irq(unsigned int irq)
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index 298f2ddb2c1..bf00fa2537b 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -23,7 +23,6 @@
* David Pye <dmp@davidmpye.dyndns.org>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/stddef.h> /* for offsetof() */
#include <linux/init.h>
@@ -411,16 +410,17 @@ static __inline__ int led_get_net_activity(void)
static __inline__ int led_get_diskio_activity(void)
{
static unsigned long last_pgpgin, last_pgpgout;
- struct page_state pgstat;
+ unsigned long events[NR_VM_EVENT_ITEMS];
int changed;
- get_full_page_state(&pgstat); /* get no of sectors in & out */
+ all_vm_events(events);
/* Just use a very simple calculation here. Do not care about overflow,
since we only want to know if there was activity or not. */
- changed = (pgstat.pgpgin != last_pgpgin) || (pgstat.pgpgout != last_pgpgout);
- last_pgpgin = pgstat.pgpgin;
- last_pgpgout = pgstat.pgpgout;
+ changed = (events[PGPGIN] != last_pgpgin) ||
+ (events[PGPGOUT] != last_pgpgout);
+ last_pgpgin = events[PGPGIN];
+ last_pgpgout = events[PGPGOUT];
return (changed ? LED_DISK_IO : 0);
}
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index bbeabe3fc4c..ea1b7a63598 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -28,8 +28,15 @@
* following code can deal with just 96 bytes of Stable Storage, and all
* sizes between 96 and 192 bytes (provided they are multiple of struct
* device_path size, eg: 128, 160 and 192) to provide full information.
- * The code makes no use of data above 192 bytes. One last word: there's one
- * path we can always count on: the primary path.
+ * One last word: there's one path we can always count on: the primary path.
+ * Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
+ *
+ * The first OS-dependent area should always be available. Obviously, this is
+ * not true for the other one. Also bear in mind that reading/writing from/to
+ * osdep2 is much more expensive than from/to osdep1.
+ * NOTE: We do not handle the 2 bytes OS-dep area at 0x5D, nor the first
+ * 2 bytes of storage available right after OSID. That's a total of 4 bytes
+ * sacrificed: -ETOOLAZY :P
*
* The current policy wrt file permissions is:
* - write: root only
@@ -64,15 +71,18 @@
#include <asm/uaccess.h>
#include <asm/hardware.h>
-#define PDCS_VERSION "0.22"
+#define PDCS_VERSION "0.30"
#define PDCS_PREFIX "PDC Stable Storage"
#define PDCS_ADDR_PPRI 0x00
#define PDCS_ADDR_OSID 0x40
+#define PDCS_ADDR_OSD1 0x48
+#define PDCS_ADDR_DIAG 0x58
#define PDCS_ADDR_FSIZ 0x5C
#define PDCS_ADDR_PCON 0x60
#define PDCS_ADDR_PALT 0x80
#define PDCS_ADDR_PKBD 0xA0
+#define PDCS_ADDR_OSD2 0xE0
MODULE_AUTHOR("Thibaut VARENE <varenet@parisc-linux.org>");
MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
@@ -82,6 +92,9 @@ MODULE_VERSION(PDCS_VERSION);
/* holds Stable Storage size. Initialized once and for all, no lock needed */
static unsigned long pdcs_size __read_mostly;
+/* holds OS ID. Initialized once and for all, hopefully to 0x0006 */
+static u16 pdcs_osid __read_mostly;
+
/* This struct defines what we need to deal with a parisc pdc path entry */
struct pdcspath_entry {
rwlock_t rw_lock; /* to protect path entry access */
@@ -609,27 +622,64 @@ static ssize_t
pdcs_osid_read(struct subsystem *entry, char *buf)
{
char *out = buf;
- __u32 result;
- char *tmpstr = NULL;
if (!entry || !buf)
return -EINVAL;
- /* get OSID */
- if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+ out += sprintf(out, "%s dependent data (0x%.4x)\n",
+ os_id_to_string(pdcs_osid), pdcs_osid);
+
+ return out - buf;
+}
+
+/**
+ * pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold 16 bytes of OS-Dependent data.
+ */
+static ssize_t
+pdcs_osdep1_read(struct subsystem *entry, char *buf)
+{
+ char *out = buf;
+ u32 result[4];
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ if (pdc_stable_read(PDCS_ADDR_OSD1, &result, sizeof(result)) != PDC_OK)
return -EIO;
- /* the actual result is 16 bits away */
- switch (result >> 16) {
- case 0x0000: tmpstr = "No OS-dependent data"; break;
- case 0x0001: tmpstr = "HP-UX dependent data"; break;
- case 0x0002: tmpstr = "MPE-iX dependent data"; break;
- case 0x0003: tmpstr = "OSF dependent data"; break;
- case 0x0004: tmpstr = "HP-RT dependent data"; break;
- case 0x0005: tmpstr = "Novell Netware dependent data"; break;
- default: tmpstr = "Unknown"; break;
- }
- out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16));
+ out += sprintf(out, "0x%.8x\n", result[0]);
+ out += sprintf(out, "0x%.8x\n", result[1]);
+ out += sprintf(out, "0x%.8x\n", result[2]);
+ out += sprintf(out, "0x%.8x\n", result[3]);
+
+ return out - buf;
+}
+
+/**
+ * pdcs_diagnostic_read - Stable Storage Diagnostic register output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * I have NFC how to interpret the content of that register ;-).
+ */
+static ssize_t
+pdcs_diagnostic_read(struct subsystem *entry, char *buf)
+{
+ char *out = buf;
+ u32 result;
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ /* get diagnostic */
+ if (pdc_stable_read(PDCS_ADDR_DIAG, &result, sizeof(result)) != PDC_OK)
+ return -EIO;
+
+ out += sprintf(out, "0x%.4x\n", (result >> 16));
return out - buf;
}
@@ -645,7 +695,7 @@ static ssize_t
pdcs_fastsize_read(struct subsystem *entry, char *buf)
{
char *out = buf;
- __u32 result;
+ u32 result;
if (!entry || !buf)
return -EINVAL;
@@ -664,6 +714,39 @@ pdcs_fastsize_read(struct subsystem *entry, char *buf)
}
/**
+ * pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
+ */
+static ssize_t
+pdcs_osdep2_read(struct subsystem *entry, char *buf)
+{
+ char *out = buf;
+ unsigned long size;
+ unsigned short i;
+ u32 result;
+
+ if (unlikely(pdcs_size <= 224))
+ return -ENODATA;
+
+ size = pdcs_size - 224;
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ for (i=0; i<size; i+=4) {
+ if (unlikely(pdc_stable_read(PDCS_ADDR_OSD2 + i, &result,
+ sizeof(result)) != PDC_OK))
+ return -EIO;
+ out += sprintf(out, "0x%.8x\n", result);
+ }
+
+ return out - buf;
+}
+
+/**
* pdcs_auto_write - This function handles autoboot/search flag modifying.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The input buffer to read from.
@@ -770,13 +853,100 @@ pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
}
+/**
+ * pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store 16 bytes of OS-Dependent data. We use a byte-by-byte
+ * write approach. It's up to userspace to deal with it when constructing
+ * its input buffer.
+ */
+static ssize_t
+pdcs_osdep1_write(struct subsystem *entry, const char *buf, size_t count)
+{
+ u8 in[16];
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (!entry || !buf || !count)
+ return -EINVAL;
+
+ if (unlikely(pdcs_osid != OS_ID_LINUX))
+ return -EPERM;
+
+ if (count > 16)
+ return -EMSGSIZE;
+
+ /* We'll use a local copy of buf */
+ memset(in, 0, 16);
+ memcpy(in, buf, count);
+
+ if (pdc_stable_write(PDCS_ADDR_OSD1, &in, sizeof(in)) != PDC_OK)
+ return -EIO;
+
+ return count;
+}
+
+/**
+ * pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * This can store pdcs_size - 224 bytes of OS-Dependent data. We use a
+ * byte-by-byte write approach. It's up to userspace to deal with it when
+ * constructing its input buffer.
+ */
+static ssize_t
+pdcs_osdep2_write(struct subsystem *entry, const char *buf, size_t count)
+{
+ unsigned long size;
+ unsigned short i;
+ u8 in[4];
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (!entry || !buf || !count)
+ return -EINVAL;
+
+ if (unlikely(pdcs_size <= 224))
+ return -ENOSYS;
+
+ if (unlikely(pdcs_osid != OS_ID_LINUX))
+ return -EPERM;
+
+ size = pdcs_size - 224;
+
+ if (count > size)
+ return -EMSGSIZE;
+
+ /* We'll use a local copy of buf */
+
+ for (i=0; i<count; i+=4) {
+ memset(in, 0, 4);
+ memcpy(in, buf+i, (count-i < 4) ? count-i : 4);
+ if (unlikely(pdc_stable_write(PDCS_ADDR_OSD2 + i, &in,
+ sizeof(in)) != PDC_OK))
+ return -EIO;
+ }
+
+ return count;
+}
+
/* The remaining attributes. */
static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
-static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL);
+static PDCS_ATTR(osid, 0444, pdcs_osid_read, NULL);
+static PDCS_ATTR(osdep1, 0600, pdcs_osdep1_read, pdcs_osdep1_write);
+static PDCS_ATTR(diagnostic, 0400, pdcs_diagnostic_read, NULL);
static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
+static PDCS_ATTR(osdep2, 0600, pdcs_osdep2_read, pdcs_osdep2_write);
static struct subsys_attribute *pdcs_subsys_attrs[] = {
&pdcs_attr_size,
@@ -784,7 +954,10 @@ static struct subsys_attribute *pdcs_subsys_attrs[] = {
&pdcs_attr_autosearch,
&pdcs_attr_timer,
&pdcs_attr_osid,
+ &pdcs_attr_osdep1,
+ &pdcs_attr_diagnostic,
&pdcs_attr_fastsize,
+ &pdcs_attr_osdep2,
NULL,
};
@@ -865,6 +1038,7 @@ pdc_stable_init(void)
{
struct subsys_attribute *attr;
int i, rc = 0, error = 0;
+ u32 result;
/* find the size of the stable storage */
if (pdc_stable_get_size(&pdcs_size) != PDC_OK)
@@ -876,6 +1050,13 @@ pdc_stable_init(void)
printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
+ /* get OSID */
+ if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
+ return -EIO;
+
+ /* the actual result is 16 bits away */
+ pdcs_osid = (u16)(result >> 16);
+
/* For now we'll register the stable subsys within this driver */
if ((rc = firmware_register(&stable_subsys)))
goto fail_firmreg;
@@ -887,7 +1068,7 @@ pdc_stable_init(void)
/* register the paths subsys as a subsystem of stable subsys */
kset_set_kset_s(&paths_subsys, stable_subsys);
- if ((rc= subsystem_register(&paths_subsys)))
+ if ((rc = subsystem_register(&paths_subsys)))
goto fail_subsysreg;
/* now we create all "files" for the paths subsys */
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index 0bcab83b408..fad5a33bf0f 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -35,7 +35,6 @@
* runtime through the "/proc/sys/kernel/power" procfs entry.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 278f325021e..8b473281551 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -19,7 +19,6 @@
** FIXME: add DMA hint support programming in both sba and lba modules.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
@@ -316,10 +315,10 @@ static int reserve_sba_gart = 1;
**
** Superdome (in particular, REO) allows only 64-bit CSR accesses.
*/
-#define READ_REG32(addr) le32_to_cpu(__raw_readl(addr))
-#define READ_REG64(addr) le64_to_cpu(__raw_readq(addr))
-#define WRITE_REG32(val, addr) __raw_writel(cpu_to_le32(val), addr)
-#define WRITE_REG64(val, addr) __raw_writeq(cpu_to_le64(val), addr)
+#define READ_REG32(addr) readl(addr)
+#define READ_REG64(addr) readq(addr)
+#define WRITE_REG32(val, addr) writel((val), (addr))
+#define WRITE_REG64(val, addr) writeq((val), (addr))
#ifdef CONFIG_64BIT
#define READ_REG(addr) READ_REG64(addr)
@@ -1427,7 +1426,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
iov_order = get_order(iova_space_size >> (IOVP_SHIFT - PAGE_SHIFT));
ioc->pdir_size = (iova_space_size / IOVP_SIZE) * sizeof(u64);
- DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits)\n",
+ DBG_INIT("%s() hpa 0x%p IOV %dMB (%d bits)\n",
__FUNCTION__, ioc->ioc_hpa, iova_space_size >> 20,
iov_order + PAGE_SHIFT);
@@ -1764,7 +1763,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
sba_dev->num_ioc = num_ioc;
for (i = 0; i < num_ioc; i++) {
- unsigned long ioc_hpa = sba_dev->ioc[i].ioc_hpa;
+ void __iomem *ioc_hpa = sba_dev->ioc[i].ioc_hpa;
unsigned int j;
for (j=0; j < sizeof(u64) * ROPES_PER_IOC; j+=sizeof(u64)) {
@@ -1776,7 +1775,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
* Improves netperf UDP_STREAM by ~10% for bcm5701.
*/
if (IS_PLUTO(sba_dev->iodc)) {
- unsigned long rope_cfg, cfg_val;
+ void __iomem *rope_cfg;
+ unsigned long cfg_val;
rope_cfg = ioc_hpa + IOC_ROPE0_CFG + j;
cfg_val = READ_REG(rope_cfg);
@@ -1902,7 +1902,7 @@ sba_common_init(struct sba_device *sba_dev)
* (bit #61, big endian), we have to flush and sync every time
* IO-PDIR is changed in Ike/Astro.
*/
- if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) {
+ if (ioc_needs_fdc) {
printk(KERN_INFO MODULE_NAME " FDC/SYNC required.\n");
} else {
printk(KERN_INFO MODULE_NAME " IOC has cache coherent PDIR.\n");
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 828eb45062d..4ee26a6d9e2 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -271,7 +271,7 @@ superio_init(struct pci_dev *pcidev)
else
printk(KERN_ERR PFX "USB regulator not initialized!\n");
- if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT,
+ if (request_irq(pdev->irq, superio_interrupt, IRQF_DISABLED,
SUPERIO, (void *)sio)) {
printk(KERN_ERR PFX "could not get irq\n");
@@ -360,7 +360,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
#endif
for (i = 0; i < 16; i++) {
- irq_desc[i].handler = &superio_interrupt_type;
+ irq_desc[i].chip = &superio_interrupt_type;
}
/*
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index 4d8dc27ea9d..c7fa28a28b9 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -136,6 +136,18 @@ config PARPORT_SUNBPP
found on many Sun machines. Note that many of the newer Ultras
actually have pc style hardware instead.
+config PARPORT_AX88796
+ tristate "AX88796 Parallel Port"
+ depends on PARPORT
+ select PARPORT_NOT_PC
+ help
+ Say Y here if you need support for the parallel port hardware on
+ the AX88796 network controller chip. This code is also available
+ as a module (say M), called parport_ax88796.
+
+ The driver is not dependant on the AX88796 network driver, and
+ should not interfere with the networking functions of the chip.
+
config PARPORT_1284
bool "IEEE 1284 transfer modes"
depends on PARPORT
diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile
index a19de35f8de..696b8d4ca88 100644
--- a/drivers/parport/Makefile
+++ b/drivers/parport/Makefile
@@ -17,4 +17,5 @@ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o
obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o
obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o
obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o
-obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o
+obj-$(CONFIG_PARPORT_AX88796) += parport_ax88796.o
+obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o \ No newline at end of file
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index 9ee67321b63..fd41e28101e 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -283,7 +283,7 @@ void parport_close (struct pardevice *dev)
*
* This tries to locate a device on the given parallel port,
* multiplexor port and daisy chain address, and returns its
- * device number or -NXIO if no device with those coordinates
+ * device number or %-ENXIO if no device with those coordinates
* exists.
**/
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 690b239ad3a..7ff09f0f858 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -16,7 +16,6 @@
* Various hacks, Fred Barnes <frmb2@ukc.ac.uk>, 04/2000
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/threads.h>
#include <linux/parport.h>
diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c
index d6c77658231..525312f2fe9 100644
--- a/drivers/parport/ieee1284_ops.c
+++ b/drivers/parport/ieee1284_ops.c
@@ -14,7 +14,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/parport.h>
#include <linux/delay.h>
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
new file mode 100644
index 00000000000..1850632590f
--- /dev/null
+++ b/drivers/parport/parport_ax88796.c
@@ -0,0 +1,443 @@
+/* linux/drivers/parport/parport_ax88796.c
+ *
+ * (c) 2005,2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/parport.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#define AX_SPR_BUSY (1<<7)
+#define AX_SPR_ACK (1<<6)
+#define AX_SPR_PE (1<<5)
+#define AX_SPR_SLCT (1<<4)
+#define AX_SPR_ERR (1<<3)
+
+#define AX_CPR_nDOE (1<<5)
+#define AX_CPR_SLCTIN (1<<3)
+#define AX_CPR_nINIT (1<<2)
+#define AX_CPR_ATFD (1<<1)
+#define AX_CPR_STRB (1<<0)
+
+struct ax_drvdata {
+ struct parport *parport;
+ struct parport_state suspend;
+
+ struct device *dev;
+ struct resource *io;
+
+ unsigned char irq_enabled;
+
+ void __iomem *base;
+ void __iomem *spp_data;
+ void __iomem *spp_spr;
+ void __iomem *spp_cpr;
+};
+
+static inline struct ax_drvdata *pp_to_drv(struct parport *p)
+{
+ return p->private_data;
+}
+
+static unsigned char
+parport_ax88796_read_data(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ return readb(dd->spp_data);
+}
+
+static void
+parport_ax88796_write_data(struct parport *p, unsigned char data)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ writeb(data, dd->spp_data);
+}
+
+static unsigned char
+parport_ax88796_read_control(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned int cpr = readb(dd->spp_cpr);
+ unsigned int ret = 0;
+
+ if (!(cpr & AX_CPR_STRB))
+ ret |= PARPORT_CONTROL_STROBE;
+
+ if (!(cpr & AX_CPR_ATFD))
+ ret |= PARPORT_CONTROL_AUTOFD;
+
+ if (cpr & AX_CPR_nINIT)
+ ret |= PARPORT_CONTROL_INIT;
+
+ if (!(cpr & AX_CPR_SLCTIN))
+ ret |= PARPORT_CONTROL_SELECT;
+
+ return ret;
+}
+
+static void
+parport_ax88796_write_control(struct parport *p, unsigned char control)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned int cpr = readb(dd->spp_cpr);
+
+ cpr &= AX_CPR_nDOE;
+
+ if (!(control & PARPORT_CONTROL_STROBE))
+ cpr |= AX_CPR_STRB;
+
+ if (!(control & PARPORT_CONTROL_AUTOFD))
+ cpr |= AX_CPR_ATFD;
+
+ if (control & PARPORT_CONTROL_INIT)
+ cpr |= AX_CPR_nINIT;
+
+ if (!(control & PARPORT_CONTROL_SELECT))
+ cpr |= AX_CPR_SLCTIN;
+
+ dev_dbg(dd->dev, "write_control: ctrl=%02x, cpr=%02x\n", control, cpr);
+ writeb(cpr, dd->spp_cpr);
+
+ if (parport_ax88796_read_control(p) != control) {
+ dev_err(dd->dev, "write_control: read != set (%02x, %02x)\n",
+ parport_ax88796_read_control(p), control);
+ }
+}
+
+static unsigned char
+parport_ax88796_read_status(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned int status = readb(dd->spp_spr);
+ unsigned int ret = 0;
+
+ if (status & AX_SPR_BUSY)
+ ret |= PARPORT_STATUS_BUSY;
+
+ if (status & AX_SPR_ACK)
+ ret |= PARPORT_STATUS_ACK;
+
+ if (status & AX_SPR_ERR)
+ ret |= PARPORT_STATUS_ERROR;
+
+ if (status & AX_SPR_SLCT)
+ ret |= PARPORT_STATUS_SELECT;
+
+ if (status & AX_SPR_PE)
+ ret |= PARPORT_STATUS_PAPEROUT;
+
+ return ret;
+}
+
+static unsigned char
+parport_ax88796_frob_control(struct parport *p, unsigned char mask,
+ unsigned char val)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned char old = parport_ax88796_read_control(p);
+
+ dev_dbg(dd->dev, "frob: mask=%02x, val=%02x, old=%02x\n",
+ mask, val, old);
+
+ parport_ax88796_write_control(p, (old & ~mask) | val);
+ return old;
+}
+
+static void
+parport_ax88796_enable_irq(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (!dd->irq_enabled) {
+ enable_irq(p->irq);
+ dd->irq_enabled = 1;
+ }
+ local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_disable_irq(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (dd->irq_enabled) {
+ disable_irq(p->irq);
+ dd->irq_enabled = 0;
+ }
+ local_irq_restore(flags);
+}
+
+static void
+parport_ax88796_data_forward(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ void __iomem *cpr = dd->spp_cpr;
+
+ writeb((readb(cpr) & ~AX_CPR_nDOE), cpr);
+}
+
+static void
+parport_ax88796_data_reverse(struct parport *p)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+ void __iomem *cpr = dd->spp_cpr;
+
+ writeb(readb(cpr) | AX_CPR_nDOE, cpr);
+}
+
+static void
+parport_ax88796_init_state(struct pardevice *d, struct parport_state *s)
+{
+ struct ax_drvdata *dd = pp_to_drv(d->port);
+
+ memset(s, 0, sizeof(struct parport_state));
+
+ dev_dbg(dd->dev, "init_state: %p: state=%p\n", d, s);
+ s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_save_state(struct parport *p, struct parport_state *s)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ dev_dbg(dd->dev, "save_state: %p: state=%p\n", p, s);
+ s->u.ax88796.cpr = readb(dd->spp_cpr);
+}
+
+static void
+parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
+{
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ dev_dbg(dd->dev, "restore_state: %p: state=%p\n", p, s);
+ writeb(s->u.ax88796.cpr, dd->spp_cpr);
+}
+
+static irqreturn_t
+parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ parport_generic_irq(irq, dev_id, regs);
+ return IRQ_HANDLED;
+}
+
+
+static struct parport_operations parport_ax88796_ops = {
+ .write_data = parport_ax88796_write_data,
+ .read_data = parport_ax88796_read_data,
+
+ .write_control = parport_ax88796_write_control,
+ .read_control = parport_ax88796_read_control,
+ .frob_control = parport_ax88796_frob_control,
+
+ .read_status = parport_ax88796_read_status,
+
+ .enable_irq = parport_ax88796_enable_irq,
+ .disable_irq = parport_ax88796_disable_irq,
+
+ .data_forward = parport_ax88796_data_forward,
+ .data_reverse = parport_ax88796_data_reverse,
+
+ .init_state = parport_ax88796_init_state,
+ .save_state = parport_ax88796_save_state,
+ .restore_state = parport_ax88796_restore_state,
+
+ .epp_write_data = parport_ieee1284_epp_write_data,
+ .epp_read_data = parport_ieee1284_epp_read_data,
+ .epp_write_addr = parport_ieee1284_epp_write_addr,
+ .epp_read_addr = parport_ieee1284_epp_read_addr,
+
+ .ecp_write_data = parport_ieee1284_ecp_write_data,
+ .ecp_read_data = parport_ieee1284_ecp_read_data,
+ .ecp_write_addr = parport_ieee1284_ecp_write_addr,
+
+ .compat_write_data = parport_ieee1284_write_compat,
+ .nibble_read_data = parport_ieee1284_read_nibble,
+ .byte_read_data = parport_ieee1284_read_byte,
+
+ .owner = THIS_MODULE,
+};
+
+static int parport_ax88796_probe(struct platform_device *pdev)
+{
+ struct device *_dev = &pdev->dev;
+ struct ax_drvdata *dd;
+ struct parport *pp = NULL;
+ struct resource *res;
+ unsigned long size;
+ int spacing;
+ int irq;
+ int ret;
+
+ dd = kzalloc(sizeof(struct ax_drvdata), GFP_KERNEL);
+ if (dd == NULL) {
+ dev_err(_dev, "no memory for private data\n");
+ return -ENOMEM;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(_dev, "no MEM specified\n");
+ ret = -ENXIO;
+ goto exit_mem;
+ }
+
+ size = (res->end - res->start) + 1;
+ spacing = size / 3;
+
+ dd->io = request_mem_region(res->start, size, pdev->name);
+ if (dd->io == NULL) {
+ dev_err(_dev, "cannot reserve memory\n");
+ ret = -ENXIO;
+ goto exit_mem;
+ }
+
+ dd->base = ioremap(res->start, size);
+ if (dd->base == NULL) {
+ dev_err(_dev, "cannot ioremap region\n");
+ ret = -ENXIO;
+ goto exit_res;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0)
+ irq = PARPORT_IRQ_NONE;
+
+ pp = parport_register_port((unsigned long)dd->base, irq,
+ PARPORT_DMA_NONE,
+ &parport_ax88796_ops);
+
+ if (pp == NULL) {
+ dev_err(_dev, "failed to register parallel port\n");
+ ret = -ENOMEM;
+ goto exit_unmap;
+ }
+
+ pp->private_data = dd;
+ dd->parport = pp;
+ dd->dev = _dev;
+
+ dd->spp_data = dd->base;
+ dd->spp_spr = dd->base + (spacing * 1);
+ dd->spp_cpr = dd->base + (spacing * 2);
+
+ /* initialise the port controls */
+ writeb(AX_CPR_STRB, dd->spp_cpr);
+
+ if (irq >= 0) {
+ /* request irq */
+ ret = request_irq(irq, parport_ax88796_interrupt,
+ IRQF_TRIGGER_FALLING, pdev->name, pp);
+
+ if (ret < 0)
+ goto exit_port;
+
+ dd->irq_enabled = 1;
+ }
+
+ platform_set_drvdata(pdev, pp);
+
+ dev_info(_dev, "attached parallel port driver\n");
+ parport_announce_port(pp);
+
+ return 0;
+
+ exit_port:
+ parport_remove_port(pp);
+ exit_unmap:
+ iounmap(dd->base);
+ exit_res:
+ release_resource(dd->io);
+ kfree(dd->io);
+ exit_mem:
+ kfree(dd);
+ return ret;
+}
+
+static int parport_ax88796_remove(struct platform_device *pdev)
+{
+ struct parport *p = platform_get_drvdata(pdev);
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ free_irq(p->irq, p);
+ parport_remove_port(p);
+ iounmap(dd->base);
+ release_resource(dd->io);
+ kfree(dd->io);
+ kfree(dd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int parport_ax88796_suspend(struct platform_device *dev,
+ pm_message_t state)
+{
+ struct parport *p = platform_get_drvdata(dev);
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ parport_ax88796_save_state(p, &dd->suspend);
+ writeb(AX_CPR_nDOE | AX_CPR_STRB, dd->spp_cpr);
+ return 0;
+}
+
+static int parport_ax88796_resume(struct platform_device *dev)
+{
+ struct parport *p = platform_get_drvdata(dev);
+ struct ax_drvdata *dd = pp_to_drv(p);
+
+ parport_ax88796_restore_state(p, &dd->suspend);
+ return 0;
+}
+
+#else
+#define parport_ax88796_suspend NULL
+#define parport_ax88796_resume NULL
+#endif
+
+static struct platform_driver axdrv = {
+ .driver = {
+ .name = "ax88796-pp",
+ .owner = THIS_MODULE,
+ },
+ .probe = parport_ax88796_probe,
+ .remove = parport_ax88796_remove,
+ .suspend = parport_ax88796_suspend,
+ .resume = parport_ax88796_resume,
+};
+
+static int __init parport_ax88796_init(void)
+{
+ return platform_driver_register(&axdrv);
+}
+
+static void __exit parport_ax88796_exit(void)
+{
+ platform_driver_unregister(&axdrv);
+}
+
+module_init(parport_ax88796_init)
+module_exit(parport_ax88796_exit)
+
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("AX88796 Parport parallel port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 1de52d9febf..7352104f7b3 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -15,7 +15,7 @@
* Phil Blundell <philb@gnu.org>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
- * David Campbell <campbell@torque.net>
+ * David Campbell
* Andrea Arcangeli
*/
diff --git a/drivers/parport/parport_gsc.h b/drivers/parport/parport_gsc.h
index 662f6c1fee5..fc9c37c5402 100644
--- a/drivers/parport/parport_gsc.h
+++ b/drivers/parport/parport_gsc.h
@@ -24,7 +24,7 @@
* Phil Blundell <Philip.Blundell@pobox.com>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
- * David Campbell <campbell@torque.net>
+ * David Campbell
* Andrea Arcangeli
*/
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index c85364765ef..b2b8092a2b3 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -353,7 +353,7 @@ static int __init parport_mfc3_init(void)
if (p->irq != PARPORT_IRQ_NONE) {
if (use_cnt++ == 0)
- if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, SA_SHIRQ, p->name, &pp_mfc3_ops))
+ if (request_irq(IRQ_AMIGA_PORTS, mfc3_interrupt, IRQF_SHARED, p->name, &pp_mfc3_ops))
goto out_irq;
}
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 48bbf32fd98..fe800dc0be9 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -3,7 +3,7 @@
* Authors: Phil Blundell <philb@gnu.org>
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Jose Renau <renau@acm.org>
- * David Campbell <campbell@torque.net>
+ * David Campbell
* Andrea Arcangeli
*
* based on work by Grant Guenther <grant@torque.net> and Phil Blundell.
@@ -42,7 +42,6 @@
* but rather will start at port->base_hi.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 98b83a85c60..78c0a269a2b 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -374,6 +374,7 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
return;
}
+#ifdef CONFIG_PM
static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state)
{
struct parport_serial_private *priv = pci_get_drvdata(dev);
@@ -407,14 +408,17 @@ static int parport_serial_pci_resume(struct pci_dev *dev)
return 0;
}
+#endif
static struct pci_driver parport_serial_pci_driver = {
.name = "parport_serial",
.id_table = parport_serial_pci_tbl,
.probe = parport_serial_pci_probe,
.remove = __devexit_p(parport_serial_pci_remove),
+#ifdef CONFIG_PM
.suspend = parport_serial_pci_suspend,
.resume = parport_serial_pci_resume,
+#endif
};
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index 36a1556e64c..fac333b279b 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -1,5 +1,4 @@
-/* $Id: parport_sunbpp.c,v 1.12 2001/05/26 03:01:42 davem Exp $
- * Parallel-port routines for Sun architecture
+/* parport_sunbpp.c: Parallel-port routines for SBUS
*
* Author: Derrick J. Brashear <shadow@dementia.org>
*
@@ -14,6 +13,9 @@
* Gus Baldauf (gbaldauf@ix.netcom.com)
* Peter Zaitcev
* Tom Dyas
+ *
+ * Updated to new SBUS device framework: David S. Miller <davem@davemloft.net>
+ *
*/
#include <linux/string.h>
@@ -287,14 +289,7 @@ static struct parport_operations parport_sunbpp_ops =
.owner = THIS_MODULE,
};
-typedef struct {
- struct list_head list;
- struct parport *port;
-} Node;
-/* no locks, everything's serialized */
-static LIST_HEAD(port_list);
-
-static int __init init_one_port(struct sbus_dev *sdev)
+static int __devinit init_one_port(struct sbus_dev *sdev)
{
struct parport *p;
/* at least in theory there may be a "we don't dma" case */
@@ -303,109 +298,120 @@ static int __init init_one_port(struct sbus_dev *sdev)
int irq, dma, err = 0, size;
struct bpp_regs __iomem *regs;
unsigned char value_tcr;
- Node *node;
-
- dprintk((KERN_DEBUG "init_one_port(%p): ranges, alloc_io, ", sdev));
- node = kmalloc(sizeof(Node), GFP_KERNEL);
- if (!node)
- goto out0;
irq = sdev->irqs[0];
base = sbus_ioremap(&sdev->resource[0], 0,
sdev->reg_addrs[0].reg_size,
"sunbpp");
if (!base)
- goto out1;
+ return -ENODEV;
size = sdev->reg_addrs[0].reg_size;
dma = PARPORT_DMA_NONE;
- dprintk(("alloc(ppops), "));
- ops = kmalloc (sizeof (struct parport_operations), GFP_KERNEL);
+ ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
if (!ops)
- goto out2;
+ goto out_unmap;
memcpy (ops, &parport_sunbpp_ops, sizeof (struct parport_operations));
dprintk(("register_port\n"));
if (!(p = parport_register_port((unsigned long)base, irq, dma, ops)))
- goto out3;
+ goto out_free_ops;
p->size = size;
- dprintk((KERN_DEBUG "init_one_port: request_irq(%08x:%p:%x:%s:%p) ",
- p->irq, parport_sunbpp_interrupt, SA_SHIRQ, p->name, p));
if ((err = request_irq(p->irq, parport_sunbpp_interrupt,
- SA_SHIRQ, p->name, p)) != 0) {
- dprintk(("ERROR %d\n", err));
- goto out4;
+ IRQF_SHARED, p->name, p)) != 0) {
+ goto out_put_port;
}
- dprintk(("OK\n"));
+
parport_sunbpp_enable_irq(p);
regs = (struct bpp_regs __iomem *)p->base;
- dprintk((KERN_DEBUG "forward\n"));
+
value_tcr = sbus_readb(&regs->p_tcr);
value_tcr &= ~P_TCR_DIR;
sbus_writeb(value_tcr, &regs->p_tcr);
printk(KERN_INFO "%s: sunbpp at 0x%lx\n", p->name, p->base);
- node->port = p;
- list_add(&node->list, &port_list);
- parport_announce_port (p);
- return 1;
+ dev_set_drvdata(&sdev->ofdev.dev, p);
+
+ parport_announce_port(p);
+
+ return 0;
-out4:
+out_put_port:
parport_put_port(p);
-out3:
+
+out_free_ops:
kfree(ops);
-out2:
+
+out_unmap:
sbus_iounmap(base, size);
-out1:
- kfree(node);
-out0:
+
return err;
}
-static int __init parport_sunbpp_init(void)
+static int __devinit bpp_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int count = 0;
-
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "SUNW,bpp"))
- count += init_one_port(sdev);
- }
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+
+ return init_one_port(sdev);
+}
+
+static int __devexit bpp_remove(struct of_device *dev)
+{
+ struct parport *p = dev_get_drvdata(&dev->dev);
+ struct parport_operations *ops = p->ops;
+
+ parport_remove_port(p);
+
+ if (p->irq != PARPORT_IRQ_NONE) {
+ parport_sunbpp_disable_irq(p);
+ free_irq(p->irq, p);
}
- return count ? 0 : -ENODEV;
+
+ sbus_iounmap((void __iomem *) p->base, p->size);
+ parport_put_port(p);
+ kfree(ops);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
+}
+
+static struct of_device_id bpp_match[] = {
+ {
+ .name = "SUNW,bpp",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, bpp_match);
+
+static struct of_platform_driver bpp_sbus_driver = {
+ .name = "bpp",
+ .match_table = bpp_match,
+ .probe = bpp_probe,
+ .remove = __devexit_p(bpp_remove),
+};
+
+static int __init parport_sunbpp_init(void)
+{
+ return of_register_driver(&bpp_sbus_driver, &sbus_bus_type);
}
static void __exit parport_sunbpp_exit(void)
{
- while (!list_empty(&port_list)) {
- Node *node = list_entry(port_list.next, Node, list);
- struct parport *p = node->port;
- struct parport_operations *ops = p->ops;
- parport_remove_port(p);
-
- if (p->irq != PARPORT_IRQ_NONE) {
- parport_sunbpp_disable_irq(p);
- free_irq(p->irq, p);
- }
- sbus_iounmap((void __iomem *)p->base, p->size);
- parport_put_port(p);
- kfree (ops);
- list_del(&node->list);
- kfree (node);
- }
+ of_unregister_driver(&bpp_sbus_driver);
}
MODULE_AUTHOR("Derrick J Brashear");
MODULE_DESCRIPTION("Parport Driver for Sparc bidirectional Port");
MODULE_SUPPORTED_DEVICE("Sparc Bidirectional Parallel Port");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
module_init(parport_sunbpp_init)
diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c
index cbe17184b9c..2e744a27451 100644
--- a/drivers/parport/procfs.c
+++ b/drivers/parport/procfs.c
@@ -1,6 +1,6 @@
/* Sysctl interface for parport devices.
*
- * Authors: David Campbell <campbell@torque.net>
+ * Authors: David Campbell
* Tim Waugh <tim@cyberelk.demon.co.uk>
* Philip Blundell <philb@gnu.org>
* Andrea Arcangeli
@@ -13,7 +13,6 @@
*/
#include <linux/string.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index bbbfd79adba..94dc506b83d 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -17,7 +17,6 @@
#undef PARPORT_DEBUG_SHARING /* undef for production */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/threads.h>
@@ -218,7 +217,7 @@ static void free_port (struct parport *port)
* parport_get_port - increment a port's reference count
* @port: the port
*
- * This ensure's that a struct parport pointer remains valid
+ * This ensures that a struct parport pointer remains valid
* until the matching parport_put_port() call.
**/
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 4d762fc4878..c27e782e6df 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -17,6 +17,31 @@ config PCI_MSI
If you don't know what to do here, say N.
+config PCI_MULTITHREAD_PROBE
+ bool "PCI Multi-threaded probe (EXPERIMENTAL)"
+ depends on PCI && EXPERIMENTAL
+ help
+ Say Y here if you want the PCI core to spawn a new thread for
+ every PCI device that is probed. This can cause a huge
+ speedup in boot times on multiprocessor machines, and even a
+ smaller speedup on single processor machines.
+
+ But it can also cause lots of bad things to happen. A number
+ of PCI drivers can not properly handle running in this way,
+ some will just not work properly at all, while others might
+ decide to blow up power supplies with a huge load all at once,
+ so use this option at your own risk.
+
+ It is very unwise to use this option if you are not using a
+ boot process that can handle devices being created in any
+ order. A program that can create persistant block and network
+ device names (like udev) is a good idea if you wish to use
+ this option.
+
+ Again, use this option at your own risk, you have been warned!
+
+ When in doubt, say N.
+
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 72309268202..aadaa3c8096 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -34,11 +34,11 @@
*/
int
pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
- unsigned long size, unsigned long align, unsigned long min,
- unsigned int type_mask,
- void (*alignf)(void *, struct resource *,
- unsigned long, unsigned long),
- void *alignf_data)
+ resource_size_t size, resource_size_t align,
+ resource_size_t min, unsigned int type_mask,
+ void (*alignf)(void *, struct resource *, resource_size_t,
+ resource_size_t),
+ void *alignf_data)
{
int i, ret = -ENOMEM;
@@ -77,9 +77,12 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
* This adds a single pci device to the global
* device list and adds sysfs and procfs entries
*/
-void __devinit pci_bus_add_device(struct pci_dev *dev)
+int __devinit pci_bus_add_device(struct pci_dev *dev)
{
- device_add(&dev->dev);
+ int retval;
+ retval = device_add(&dev->dev);
+ if (retval)
+ return retval;
down_write(&pci_bus_sem);
list_add_tail(&dev->global_list, &pci_devices);
@@ -87,6 +90,7 @@ void __devinit pci_bus_add_device(struct pci_dev *dev)
pci_proc_attach_device(dev);
pci_create_sysfs_dev_files(dev);
+ return 0;
}
/**
@@ -104,6 +108,7 @@ void __devinit pci_bus_add_device(struct pci_dev *dev)
void __devinit pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
+ int retval;
list_for_each_entry(dev, &bus->devices, bus_list) {
/*
@@ -112,7 +117,9 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
*/
if (!list_empty(&dev->global_list))
continue;
- pci_bus_add_device(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "Error adding device, continuing\n");
}
list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -129,10 +136,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
list_add_tail(&dev->subordinate->node,
&dev->bus->children);
up_write(&pci_bus_sem);
- }
+ }
pci_bus_add_devices(dev->subordinate);
-
- sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
+ retval = sysfs_create_link(&dev->subordinate->class_dev.kobj,
+ &dev->dev.kobj, "bridge");
+ if (retval)
+ dev_err(&dev->dev, "Error creating sysfs "
+ "bridge symlink, continuing...\n");
}
}
}
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 222a1cc4aa2..8a60f391ffc 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -6,8 +6,7 @@ menu "PCI Hotplug Support"
config HOTPLUG_PCI
tristate "Support for PCI Hotplug (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
- select HOTPLUG
+ depends on PCI && EXPERIMENTAL && HOTPLUG
---help---
Say Y here if you have a motherboard with a PCI Hotplug controller.
This allows you to add and remove PCI cards while the machine is
@@ -77,7 +76,7 @@ config HOTPLUG_PCI_IBM
config HOTPLUG_PCI_ACPI
tristate "ACPI PCI Hotplug driver"
- depends on ACPI && HOTPLUG_PCI
+ depends on (!ACPI_DOCK && ACPI && HOTPLUG_PCI) || (ACPI_DOCK && HOTPLUG_PCI)
help
Say Y here if you have a system that supports PCI Hotplug using
ACPI.
@@ -154,13 +153,6 @@ config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
When in doubt, say N.
-config HOTPLUG_PCI_SHPC_PHPRM_LEGACY
- bool "For AMD SHPC only: Use $HRT for resource/configuration"
- depends on HOTPLUG_PCI_SHPC && !ACPI
- help
- Say Y here for AMD SHPC. You have to select this option if you are
- using this driver on platform with AMD SHPC.
-
config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 421cfffb175..34a1891191f 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -40,8 +40,7 @@ ibmphp-objs := ibmphp_core.o \
ibmphp_hpc.o
acpiphp-objs := acpiphp_core.o \
- acpiphp_glue.o \
- acpiphp_dock.o
+ acpiphp_glue.o
rpaphp-objs := rpaphp_core.o \
rpaphp_pci.o \
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index 17a93f890db..7fff07e877c 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -130,7 +130,7 @@ struct acpiphp_func {
struct list_head sibling;
struct pci_dev *pci_dev;
-
+ struct notifier_block nb;
acpi_handle handle;
u8 function; /* pci function# */
@@ -150,25 +150,12 @@ struct acpiphp_attention_info
struct module *owner;
};
-
-struct dependent_device {
- struct list_head device_list;
- struct list_head pci_list;
- acpi_handle handle;
- struct acpiphp_func *func;
-};
-
-
-struct acpiphp_dock_station {
- acpi_handle handle;
- u32 last_dock_time;
- u32 flags;
- struct acpiphp_func *dock_bridge;
- struct list_head dependent_devices;
- struct list_head pci_dependent_devices;
+struct acpiphp_ioapic {
+ struct pci_dev *dev;
+ u32 gsi_base;
+ struct list_head list;
};
-
/* PCI bus bridge HID */
#define ACPI_PCI_HOST_HID "PNP0A03"
@@ -207,11 +194,6 @@ struct acpiphp_dock_station {
#define FUNC_HAS_PS2 (0x00000040)
#define FUNC_HAS_PS3 (0x00000080)
#define FUNC_HAS_DCK (0x00000100)
-#define FUNC_IS_DD (0x00000200)
-
-/* dock station flags */
-#define DOCK_DOCKING (0x00000001)
-#define DOCK_HAS_BRIDGE (0x00000002)
/* function prototypes */
@@ -226,7 +208,6 @@ extern int acpiphp_glue_init (void);
extern void acpiphp_glue_exit (void);
extern int acpiphp_get_num_slots (void);
typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data);
-void handle_hotplug_event_func(acpi_handle, u32, void*);
extern int acpiphp_enable_slot (struct acpiphp_slot *slot);
extern int acpiphp_disable_slot (struct acpiphp_slot *slot);
@@ -236,16 +217,6 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
-/* acpiphp_dock.c */
-extern int find_dock_station(void);
-extern void remove_dock_station(void);
-extern void add_dependent_device(struct dependent_device *new_dd);
-extern void add_pci_dependent_device(struct dependent_device *new_dd);
-extern struct dependent_device *get_dependent_device(acpi_handle handle);
-extern int is_dependent_device(acpi_handle handle);
-extern int detect_dependent_devices(acpi_handle *bridge_handle);
-extern struct dependent_device *alloc_dependent_device(acpi_handle handle);
-
/* variables */
extern int acpiphp_debug;
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 4f1b0da8e47..e2fef60c2d0 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -27,8 +27,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <gregkh@us.ibm.com>,
- * <t-kochi@bq.jp.nec.com>
+ * Send feedback to <kristen.c.accardi@intel.com>
*
*/
@@ -416,27 +415,12 @@ void acpiphp_unregister_hotplug_slot(struct acpiphp_slot *acpiphp_slot)
static int __init acpiphp_init(void)
{
- int retval;
- int docking_station;
-
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
acpiphp_debug = debug;
- docking_station = find_dock_station();
-
/* read all the ACPI info from the system */
- retval = init_acpi();
-
- /* if we have found a docking station, we should
- * go ahead and load even if init_acpi has found
- * no slots. This handles the case when the _DCK
- * method not defined under the actual dock bridge
- */
- if (docking_station)
- return 0;
- else
- return retval;
+ return init_acpi();
}
@@ -444,8 +428,6 @@ static void __exit acpiphp_exit(void)
{
/* deallocate internal data structures etc. */
acpiphp_glue_exit();
-
- remove_dock_station();
}
module_init(acpiphp_init);
diff --git a/drivers/pci/hotplug/acpiphp_dock.c b/drivers/pci/hotplug/acpiphp_dock.c
deleted file mode 100644
index 4f1aaf12831..00000000000
--- a/drivers/pci/hotplug/acpiphp_dock.c
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * ACPI PCI HotPlug dock functions to ACPI CA subsystem
- *
- * Copyright (C) 2006 Kristen Carlson Accardi (kristen.c.accardi@intel.com)
- * Copyright (C) 2006 Intel Corporation
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or
- * NON INFRINGEMENT. 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.
- *
- * Send feedback to <kristen.c.accardi@intel.com>
- *
- */
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <linux/mutex.h>
-
-#include "../pci.h"
-#include "pci_hotplug.h"
-#include "acpiphp.h"
-
-static struct acpiphp_dock_station *ds;
-#define MY_NAME "acpiphp_dock"
-
-
-int is_dependent_device(acpi_handle handle)
-{
- return (get_dependent_device(handle) ? 1 : 0);
-}
-
-
-static acpi_status
-find_dependent_device(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- int *count = (int *)context;
-
- if (is_dependent_device(handle)) {
- (*count)++;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
-}
-
-
-
-
-void add_dependent_device(struct dependent_device *new_dd)
-{
- list_add_tail(&new_dd->device_list, &ds->dependent_devices);
-}
-
-
-void add_pci_dependent_device(struct dependent_device *new_dd)
-{
- list_add_tail(&new_dd->pci_list, &ds->pci_dependent_devices);
-}
-
-
-
-struct dependent_device * get_dependent_device(acpi_handle handle)
-{
- struct dependent_device *dd;
-
- if (!ds)
- return NULL;
-
- list_for_each_entry(dd, &ds->dependent_devices, device_list) {
- if (handle == dd->handle)
- return dd;
- }
- return NULL;
-}
-
-
-
-struct dependent_device *alloc_dependent_device(acpi_handle handle)
-{
- struct dependent_device *dd;
-
- dd = kzalloc(sizeof(*dd), GFP_KERNEL);
- if (dd) {
- INIT_LIST_HEAD(&dd->pci_list);
- INIT_LIST_HEAD(&dd->device_list);
- dd->handle = handle;
- }
- return dd;
-}
-
-
-
-static int is_dock(acpi_handle handle)
-{
- acpi_status status;
- acpi_handle tmp;
-
- status = acpi_get_handle(handle, "_DCK", &tmp);
- if (ACPI_FAILURE(status)) {
- return 0;
- }
- return 1;
-}
-
-
-
-static int dock_present(void)
-{
- unsigned long sta;
- acpi_status status;
-
- if (ds) {
- status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
- if (ACPI_SUCCESS(status) && sta)
- return 1;
- }
- return 0;
-}
-
-
-
-static void eject_dock(void)
-{
- struct acpi_object_list arg_list;
- union acpi_object arg;
-
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
- if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
- &arg_list, NULL)) || dock_present())
- warn("%s: failed to eject dock!\n", __FUNCTION__);
-
- return;
-}
-
-
-
-
-static acpi_status handle_dock(int dock)
-{
- acpi_status status;
- struct acpi_object_list arg_list;
- union acpi_object arg;
- struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-
- dbg("%s: %s\n", __FUNCTION__, dock ? "docking" : "undocking");
-
- /* _DCK method has one argument */
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = dock;
- status = acpi_evaluate_object(ds->handle, "_DCK",
- &arg_list, &buffer);
- if (ACPI_FAILURE(status))
- err("%s: failed to execute _DCK\n", __FUNCTION__);
- acpi_os_free(buffer.pointer);
-
- return status;
-}
-
-
-
-static inline void dock(void)
-{
- handle_dock(1);
-}
-
-
-
-static inline void undock(void)
-{
- handle_dock(0);
-}
-
-
-
-/*
- * the _DCK method can do funny things... and sometimes not
- * hah-hah funny.
- *
- * TBD - figure out a way to only call fixups for
- * systems that require them.
- */
-static void post_dock_fixups(void)
-{
- struct pci_bus *bus;
- u32 buses;
- struct dependent_device *dd;
-
- list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list) {
- bus = dd->func->slot->bridge->pci_bus;
-
- /* fixup bad _DCK function that rewrites
- * secondary bridge on slot
- */
- pci_read_config_dword(bus->self,
- PCI_PRIMARY_BUS,
- &buses);
-
- if (((buses >> 8) & 0xff) != bus->secondary) {
- buses = (buses & 0xff000000)
- | ((unsigned int)(bus->primary) << 0)
- | ((unsigned int)(bus->secondary) << 8)
- | ((unsigned int)(bus->subordinate) << 16);
- pci_write_config_dword(bus->self,
- PCI_PRIMARY_BUS,
- buses);
- }
- }
-}
-
-
-
-static void hotplug_pci(u32 type)
-{
- struct dependent_device *dd;
-
- list_for_each_entry(dd, &ds->pci_dependent_devices, pci_list)
- handle_hotplug_event_func(dd->handle, type, dd->func);
-}
-
-
-
-static inline void begin_dock(void)
-{
- ds->flags |= DOCK_DOCKING;
-}
-
-
-static inline void complete_dock(void)
-{
- ds->flags &= ~(DOCK_DOCKING);
- ds->last_dock_time = jiffies;
-}
-
-
-static int dock_in_progress(void)
-{
- if (ds->flags & DOCK_DOCKING ||
- ds->last_dock_time == jiffies) {
- dbg("dock in progress\n");
- return 1;
- }
- return 0;
-}
-
-
-
-static void
-handle_hotplug_event_dock(acpi_handle handle, u32 type, void *context)
-{
- dbg("%s: enter\n", __FUNCTION__);
-
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- dbg("BUS Check\n");
- if (!dock_in_progress() && dock_present()) {
- begin_dock();
- dock();
- if (!dock_present()) {
- err("Unable to dock!\n");
- break;
- }
- post_dock_fixups();
- hotplug_pci(type);
- complete_dock();
- }
- break;
- case ACPI_NOTIFY_EJECT_REQUEST:
- dbg("EJECT request\n");
- if (!dock_in_progress() && dock_present()) {
- hotplug_pci(type);
- undock();
- eject_dock();
- if (dock_present())
- err("Unable to undock!\n");
- }
- break;
- }
-}
-
-
-
-
-static acpi_status
-find_dock_ejd(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- acpi_status status;
- acpi_handle tmp;
- acpi_handle dck_handle = (acpi_handle) context;
- char objname[64];
- struct acpi_buffer buffer = { .length = sizeof(objname),
- .pointer = objname };
- struct acpi_buffer ejd_buffer = {ACPI_ALLOCATE_BUFFER, NULL};
- union acpi_object *ejd_obj;
-
- status = acpi_get_handle(handle, "_EJD", &tmp);
- if (ACPI_FAILURE(status))
- return AE_OK;
-
- /* make sure we are dependent on the dock device,
- * by executing the _EJD method, then getting a handle
- * to the device referenced by that name. If that
- * device handle is the same handle as the dock station
- * handle, then we are a device dependent on the dock station
- */
- acpi_get_name(dck_handle, ACPI_FULL_PATHNAME, &buffer);
- status = acpi_evaluate_object(handle, "_EJD", NULL, &ejd_buffer);
- if (ACPI_FAILURE(status)) {
- err("Unable to execute _EJD!\n");
- goto find_ejd_out;
- }
- ejd_obj = ejd_buffer.pointer;
- status = acpi_get_handle(NULL, ejd_obj->string.pointer, &tmp);
- if (ACPI_FAILURE(status))
- goto find_ejd_out;
-
- if (tmp == dck_handle) {
- struct dependent_device *dd;
- dbg("%s: found device dependent on dock\n", __FUNCTION__);
- dd = alloc_dependent_device(handle);
- if (!dd) {
- err("Can't allocate memory for dependent device!\n");
- goto find_ejd_out;
- }
- add_dependent_device(dd);
- }
-
-find_ejd_out:
- acpi_os_free(ejd_buffer.pointer);
- return AE_OK;
-}
-
-
-
-int detect_dependent_devices(acpi_handle *bridge_handle)
-{
- acpi_status status;
- int count;
-
- count = 0;
-
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
- (u32)1, find_dependent_device,
- (void *)&count, NULL);
-
- return count;
-}
-
-
-
-
-
-static acpi_status
-find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
- int *count = (int *)context;
-
- if (is_dock(handle)) {
- dbg("%s: found dock\n", __FUNCTION__);
- ds = kzalloc(sizeof(*ds), GFP_KERNEL);
- ds->handle = handle;
- INIT_LIST_HEAD(&ds->dependent_devices);
- INIT_LIST_HEAD(&ds->pci_dependent_devices);
-
- /* look for devices dependent on dock station */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock_ejd, handle, NULL);
-
- acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_dock, ds);
- (*count)++;
- }
-
- return AE_OK;
-}
-
-
-
-
-int find_dock_station(void)
-{
- int num = 0;
-
- ds = NULL;
-
- /* start from the root object, because some laptops define
- * _DCK methods outside the scope of PCI (IBM x-series laptop)
- */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX, find_dock, &num, NULL);
-
- return num;
-}
-
-
-
-void remove_dock_station(void)
-{
- struct dependent_device *dd, *tmp;
- if (ds) {
- if (ACPI_FAILURE(acpi_remove_notify_handler(ds->handle,
- ACPI_SYSTEM_NOTIFY, handle_hotplug_event_dock)))
- err("failed to remove dock notify handler\n");
-
- /* free all dependent devices */
- list_for_each_entry_safe(dd, tmp, &ds->dependent_devices,
- device_list)
- kfree(dd);
-
- /* no need to touch the pci_dependent_device list,
- * cause all memory was freed above
- */
- kfree(ds);
- }
-}
-
-
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index d370f999782..83e8e4412de 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -26,7 +26,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <t-kochi@bq.jp.nec.com>
+ * Send feedback to <kristen.c.accardi@intel.com>
*
*/
@@ -53,12 +53,15 @@
#include "acpiphp.h"
static LIST_HEAD(bridge_list);
+static LIST_HEAD(ioapic_list);
+static DEFINE_SPINLOCK(ioapic_list_lock);
#define MY_NAME "acpiphp_glue"
static void handle_hotplug_event_bridge (acpi_handle, u32, void *);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus);
+static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context);
/*
@@ -116,6 +119,59 @@ is_ejectable_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
}
}
+/* callback routine to check for the existance of a pci dock device */
+static acpi_status
+is_pci_dock_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+
+ if (is_dock_device(handle)) {
+ (*count)++;
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+}
+
+
+
+
+/*
+ * the _DCK method can do funny things... and sometimes not
+ * hah-hah funny.
+ *
+ * TBD - figure out a way to only call fixups for
+ * systems that require them.
+ */
+static int post_dock_fixups(struct notifier_block *nb, unsigned long val,
+ void *v)
+{
+ struct acpiphp_func *func = container_of(nb, struct acpiphp_func, nb);
+ struct pci_bus *bus = func->slot->bridge->pci_bus;
+ u32 buses;
+
+ if (!bus->self)
+ return NOTIFY_OK;
+
+ /* fixup bad _DCK function that rewrites
+ * secondary bridge on slot
+ */
+ pci_read_config_dword(bus->self,
+ PCI_PRIMARY_BUS,
+ &buses);
+
+ if (((buses >> 8) & 0xff) != bus->secondary) {
+ buses = (buses & 0xff000000)
+ | ((unsigned int)(bus->primary) << 0)
+ | ((unsigned int)(bus->secondary) << 8)
+ | ((unsigned int)(bus->subordinate) << 16);
+ pci_write_config_dword(bus->self, PCI_PRIMARY_BUS, buses);
+ }
+ return NOTIFY_OK;
+}
+
+
+
/* callback routine to register each ACPI PCI slot object */
static acpi_status
@@ -124,7 +180,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context;
struct acpiphp_slot *slot;
struct acpiphp_func *newfunc;
- struct dependent_device *dd;
acpi_handle tmp;
acpi_status status = AE_OK;
unsigned long adr, sun;
@@ -137,7 +192,7 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
status = acpi_get_handle(handle, "_EJ0", &tmp);
- if (ACPI_FAILURE(status) && !(is_dependent_device(handle)))
+ if (ACPI_FAILURE(status) && !(is_dock_device(handle)))
return AE_OK;
device = (adr >> 16) & 0xffff;
@@ -162,22 +217,17 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp)))
newfunc->flags |= FUNC_HAS_PS3;
- if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp))) {
+ if (ACPI_SUCCESS(acpi_get_handle(handle, "_DCK", &tmp)))
newfunc->flags |= FUNC_HAS_DCK;
- /* add to devices dependent on dock station,
- * because this may actually be the dock bridge
- */
- dd = alloc_dependent_device(handle);
- if (!dd)
- err("Can't allocate memory for "
- "new dependent device!\n");
- else
- add_dependent_device(dd);
- }
status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun);
- if (ACPI_FAILURE(status))
- sun = -1;
+ if (ACPI_FAILURE(status)) {
+ /*
+ * use the count of the number of slots we've found
+ * for the number of the slot
+ */
+ sun = bridge->nr_slots+1;
+ }
/* search for objects that share the same slot */
for (slot = bridge->slots; slot; slot = slot->next)
@@ -225,20 +275,23 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
}
- /* if this is a device dependent on a dock station,
- * associate the acpiphp_func to the dependent_device
- * struct.
- */
- if ((dd = get_dependent_device(handle))) {
- newfunc->flags |= FUNC_IS_DD;
- /*
- * we don't want any devices which is dependent
- * on the dock to have it's _EJ0 method executed.
- * because we need to run _DCK first.
+ if (is_dock_device(handle)) {
+ /* we don't want to call this device's _EJ0
+ * because we want the dock notify handler
+ * to call it after it calls _DCK
*/
newfunc->flags &= ~FUNC_HAS_EJ0;
- dd->func = newfunc;
- add_pci_dependent_device(dd);
+ if (register_hotplug_dock_device(handle,
+ handle_hotplug_event_func, newfunc))
+ dbg("failed to register dock device\n");
+
+ /* we need to be notified when dock events happen
+ * outside of the hotplug operation, since we may
+ * need to do fixups before we can hotplug.
+ */
+ newfunc->nb.notifier_call = post_dock_fixups;
+ if (register_dock_notifier(&newfunc->nb))
+ dbg("failed to register a dock notifier");
}
/* install notify handler */
@@ -277,6 +330,15 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle)
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1,
is_ejectable_slot, (void *)&count, NULL);
+ /*
+ * we also need to add this bridge if there is a dock bridge or
+ * other pci device on a dock station (removable)
+ */
+ if (!count)
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle,
+ (u32)1, is_pci_dock_device, (void *)&count,
+ NULL);
+
return count;
}
@@ -487,8 +549,7 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
goto out;
/* check if this bridge has ejectable slots */
- if ((detect_ejectable_slots(handle) > 0) ||
- (detect_dependent_devices(handle) > 0)) {
+ if ((detect_ejectable_slots(handle) > 0)) {
dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
add_p2p_bridge(handle, dev);
}
@@ -605,6 +666,10 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
list_for_each_safe (list, tmp, &slot->funcs) {
struct acpiphp_func *func;
func = list_entry(list, struct acpiphp_func, sibling);
+ if (is_dock_device(func->handle)) {
+ unregister_hotplug_dock_device(func->handle);
+ unregister_dock_notifier(&func->nb);
+ }
if (!(func->flags & FUNC_HAS_DCK)) {
status = acpi_remove_notify_handler(func->handle,
ACPI_SYSTEM_NOTIFY,
@@ -734,6 +799,7 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
struct pci_dev *pdev;
u32 gsi_base;
u64 phys_addr;
+ struct acpiphp_ioapic *ioapic;
/* Evaluate _STA if present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
@@ -748,41 +814,107 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
if (get_gsi_base(handle, &gsi_base))
return AE_OK;
+ ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
+ if (!ioapic)
+ return AE_NO_MEMORY;
+
pdev = get_apic_pci_info(handle);
if (!pdev)
- return AE_OK;
+ goto exit_kfree;
- if (pci_enable_device(pdev)) {
- pci_dev_put(pdev);
- return AE_OK;
- }
+ if (pci_enable_device(pdev))
+ goto exit_pci_dev_put;
pci_set_master(pdev);
- if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) {
- pci_disable_device(pdev);
- pci_dev_put(pdev);
- return AE_OK;
- }
+ if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
+ goto exit_pci_disable_device;
phys_addr = pci_resource_start(pdev, 0);
- if (acpi_register_ioapic(handle, phys_addr, gsi_base)) {
- pci_release_region(pdev, 0);
- pci_disable_device(pdev);
- pci_dev_put(pdev);
+ if (acpi_register_ioapic(handle, phys_addr, gsi_base))
+ goto exit_pci_release_region;
+
+ ioapic->gsi_base = gsi_base;
+ ioapic->dev = pdev;
+ spin_lock(&ioapic_list_lock);
+ list_add_tail(&ioapic->list, &ioapic_list);
+ spin_unlock(&ioapic_list_lock);
+
+ return AE_OK;
+
+ exit_pci_release_region:
+ pci_release_region(pdev, 0);
+ exit_pci_disable_device:
+ pci_disable_device(pdev);
+ exit_pci_dev_put:
+ pci_dev_put(pdev);
+ exit_kfree:
+ kfree(ioapic);
+
+ return AE_OK;
+}
+
+static acpi_status
+ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ acpi_status status;
+ unsigned long sta;
+ acpi_handle tmp;
+ u32 gsi_base;
+ struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
+
+ /* Evaluate _STA if present */
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
+ return AE_CTRL_DEPTH;
+
+ /* Scan only PCI bus scope */
+ status = acpi_get_handle(handle, "_HID", &tmp);
+ if (ACPI_SUCCESS(status))
+ return AE_CTRL_DEPTH;
+
+ if (get_gsi_base(handle, &gsi_base))
return AE_OK;
+
+ acpi_unregister_ioapic(handle, gsi_base);
+
+ spin_lock(&ioapic_list_lock);
+ list_for_each_entry_safe(pos, n, &ioapic_list, list) {
+ if (pos->gsi_base != gsi_base)
+ continue;
+ ioapic = pos;
+ list_del(&ioapic->list);
+ break;
}
+ spin_unlock(&ioapic_list_lock);
+
+ if (!ioapic)
+ return AE_OK;
+
+ pci_release_region(ioapic->dev, 0);
+ pci_disable_device(ioapic->dev);
+ pci_dev_put(ioapic->dev);
+ kfree(ioapic);
return AE_OK;
}
static int acpiphp_configure_ioapics(acpi_handle handle)
{
+ ioapic_add(handle, 0, NULL, NULL);
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
return 0;
}
+static int acpiphp_unconfigure_ioapics(acpi_handle handle)
+{
+ ioapic_remove(handle, 0, NULL, NULL);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, ioapic_remove, NULL, NULL);
+ return 0;
+}
+
static int power_on_slot(struct acpiphp_slot *slot)
{
acpi_status status;
@@ -934,7 +1066,7 @@ acpiphp_bus_add_out:
* @handle: handle to acpi namespace
*
*/
-int acpiphp_bus_trim(acpi_handle handle)
+static int acpiphp_bus_trim(acpi_handle handle)
{
struct acpi_device *device;
int retval;
@@ -1011,10 +1143,11 @@ static int enable_device(struct acpiphp_slot *slot)
pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus);
+ acpiphp_set_hpp_values(slot->bridge->handle, bus);
+ list_for_each_entry(func, &slot->funcs, sibling)
+ acpiphp_configure_ioapics(func->handle);
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
- acpiphp_set_hpp_values(slot->bridge->handle, bus);
- acpiphp_configure_ioapics(slot->bridge->handle);
/* associate pci_dev to our representation */
list_for_each (l, &slot->funcs) {
@@ -1040,6 +1173,16 @@ static int enable_device(struct acpiphp_slot *slot)
return retval;
}
+static void disable_bridges(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->subordinate) {
+ disable_bridges(dev->subordinate);
+ pci_disable_device(dev);
+ }
+ }
+}
/**
* disable_device - disable a slot
@@ -1064,6 +1207,19 @@ static int disable_device(struct acpiphp_slot *slot)
func->bridge = NULL;
}
+ if (func->pci_dev) {
+ pci_stop_bus_device(func->pci_dev);
+ if (func->pci_dev->subordinate) {
+ disable_bridges(func->pci_dev->subordinate);
+ pci_disable_device(func->pci_dev);
+ }
+ }
+ }
+
+ list_for_each (l, &slot->funcs) {
+ func = list_entry(l, struct acpiphp_func, sibling);
+
+ acpiphp_unconfigure_ioapics(func->handle);
acpiphp_bus_trim(func->handle);
/* try to remove anyway.
* acpiphp_bus_add might have been failed */
@@ -1440,7 +1596,7 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
* handles ACPI event notification on slots
*
*/
-void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
+static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *context)
{
struct acpiphp_func *func;
char objname[64];
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index 317457dd401..d0a07d9ab30 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -487,9 +487,7 @@ static void __exit ibm_acpiphp_exit(void)
if (ACPI_FAILURE(status))
err("%s: Notification handler removal failed\n", __FUNCTION__);
/* remove the /sys entries */
- if (sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr))
- err("%s: removal of sysfs file apci_table failed\n",
- __FUNCTION__);
+ sysfs_remove_bin_file(sysdir, &ibm_apci_table_attr);
}
module_init(ibm_acpiphp_init);
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index 037ce4c9168..d5df5871cfa 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -25,7 +25,6 @@
* Send feedback to <scottm@somanetworks.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -348,7 +347,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
dbg("entered cpci_hp_intr");
/* Check to see if it was our interrupt */
- if ((controller->irq_flags & SA_SHIRQ) &&
+ if ((controller->irq_flags & IRQF_SHARED) &&
!controller->ops->check_irq(controller->dev_id)) {
dbg("exited cpci_hp_intr, not our interrupt");
return IRQ_NONE;
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 225b5e551dd..4afcaffd031 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -23,7 +23,6 @@
* Send feedback to <scottm@somanetworks.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -255,8 +254,8 @@ int cpci_led_off(struct slot* slot)
int cpci_configure_slot(struct slot* slot)
{
- unsigned char busnr;
- struct pci_bus *child;
+ struct pci_bus *parent;
+ int fn;
dbg("%s - enter", __FUNCTION__);
@@ -277,23 +276,53 @@ int cpci_configure_slot(struct slot* slot)
*/
n = pci_scan_slot(slot->bus, slot->devfn);
dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
- if (n > 0)
- pci_bus_add_devices(slot->bus);
slot->dev = pci_get_slot(slot->bus, slot->devfn);
if (slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number);
- return 1;
+ return -ENODEV;
}
}
-
- if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &busnr);
- child = pci_add_new_bus(slot->dev->bus, slot->dev, busnr);
- pci_do_scan_bus(child);
- pci_bus_size_bridges(child);
+ parent = slot->dev->bus;
+
+ for (fn = 0; fn < 8; fn++) {
+ struct pci_dev *dev;
+
+ dev = pci_get_slot(parent, PCI_DEVFN(PCI_SLOT(slot->devfn), fn));
+ if (!dev)
+ continue;
+ if ((dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) ||
+ (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)) {
+ /* Find an unused bus number for the new bridge */
+ struct pci_bus *child;
+ unsigned char busnr, start = parent->secondary;
+ unsigned char end = parent->subordinate;
+
+ for (busnr = start; busnr <= end; busnr++) {
+ if (!pci_find_bus(pci_domain_nr(parent),
+ busnr))
+ break;
+ }
+ if (busnr >= end) {
+ err("No free bus for hot-added bridge\n");
+ pci_dev_put(dev);
+ continue;
+ }
+ child = pci_add_new_bus(parent, dev, busnr);
+ if (!child) {
+ err("Cannot add new bus for %s\n",
+ pci_name(dev));
+ pci_dev_put(dev);
+ continue;
+ }
+ child->subordinate = pci_do_scan_bus(child);
+ pci_bus_size_bridges(child);
+ }
+ pci_dev_put(dev);
}
- pci_bus_assign_resources(slot->dev->bus);
+ pci_bus_assign_resources(parent);
+ pci_bus_add_devices(parent);
+ pci_enable_bridges(parent);
dbg("%s - exit", __FUNCTION__);
return 0;
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
index 2d4639d6841..e847f0d6c7f 100644
--- a/drivers/pci/hotplug/cpcihp_generic.c
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -34,7 +34,6 @@
* Send feedback to <scottm@somanetworks.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
diff --git a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c
index f7cb00da38d..1c12e917109 100644
--- a/drivers/pci/hotplug/cpcihp_zt5550.c
+++ b/drivers/pci/hotplug/cpcihp_zt5550.c
@@ -30,13 +30,13 @@
* Send feedback to <scottm@somanetworks.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
-#include <linux/signal.h> /* SA_SHIRQ */
+#include <linux/interrupt.h>
+#include <linux/signal.h> /* IRQF_SHARED */
#include "cpci_hotplug.h"
#include "cpcihp_zt5550.h"
@@ -95,8 +95,8 @@ static int zt5550_hc_config(struct pci_dev *pdev)
hc_dev = pdev;
dbg("hc_dev = %p", hc_dev);
- dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
- dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
+ dbg("pci resource start %llx", (unsigned long long)pci_resource_start(hc_dev, 1));
+ dbg("pci resource len %llx", (unsigned long long)pci_resource_len(hc_dev, 1));
if(!request_mem_region(pci_resource_start(hc_dev, 1),
pci_resource_len(hc_dev, 1), MY_NAME)) {
@@ -108,8 +108,9 @@ static int zt5550_hc_config(struct pci_dev *pdev)
hc_registers =
ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
if(!hc_registers) {
- err("cannot remap MMIO region %lx @ %lx",
- pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
+ err("cannot remap MMIO region %llx @ %llx",
+ (unsigned long long)pci_resource_len(hc_dev, 1),
+ (unsigned long long)pci_resource_start(hc_dev, 1));
ret = -ENODEV;
goto exit_release_region;
}
@@ -219,7 +220,7 @@ static int zt5550_hc_init_one (struct pci_dev *pdev, const struct pci_device_id
zt5550_hpc.ops = &zt5550_hpc_ops;
if(!poll) {
zt5550_hpc.irq = hc_dev->irq;
- zt5550_hpc.irq_flags = SA_SHIRQ;
+ zt5550_hpc.irq_flags = IRQF_SHARED;
zt5550_hpc.dev_id = hc_dev;
zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq;
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 9bc1deb8df5..1fc259913b6 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -29,7 +29,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -1089,8 +1088,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
dbg("pdev = %p\n", pdev);
- dbg("pci resource start %lx\n", pci_resource_start(pdev, 0));
- dbg("pci resource len %lx\n", pci_resource_len(pdev, 0));
+ dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0));
+ dbg("pci resource len %llx\n", (unsigned long long)pci_resource_len(pdev, 0));
if (!request_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0), MY_NAME)) {
@@ -1102,9 +1101,9 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (!ctrl->hpc_reg) {
- err("cannot remap MMIO region %lx @ %lx\n",
- pci_resource_len(pdev, 0),
- pci_resource_start(pdev, 0));
+ err("cannot remap MMIO region %llx @ %llx\n",
+ (unsigned long long)pci_resource_len(pdev, 0),
+ (unsigned long long)pci_resource_start(pdev, 0));
rc = -ENODEV;
goto err_free_mem_region;
}
@@ -1189,7 +1188,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* set up the interrupt */
dbg("HPC interrupt = %d \n", ctrl->interrupt);
if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr,
- SA_SHIRQ, MY_NAME, ctrl)) {
+ IRQF_SHARED, MY_NAME, ctrl)) {
err("Can't get irq %d for the hotplug pci controller\n",
ctrl->interrupt);
rc = -ENODEV;
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index 55d2dc7e39c..ae2dd36efef 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -26,7 +26,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c
index ac98a11bd1e..cf087891753 100644
--- a/drivers/pci/hotplug/cpqphp_nvram.c
+++ b/drivers/pci/hotplug/cpqphp_nvram.c
@@ -26,7 +26,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index 00b81a7bdd2..0d9688952f4 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -26,7 +26,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c
index bbfeed767ff..5bab666cd67 100644
--- a/drivers/pci/hotplug/cpqphp_sysfs.c
+++ b/drivers/pci/hotplug/cpqphp_sysfs.c
@@ -26,7 +26,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -141,7 +140,7 @@ struct ctrl_dbg {
static int open(struct inode *inode, struct file *file)
{
- struct controller *ctrl = inode->u.generic_ip;
+ struct controller *ctrl = inode->i_private;
struct ctrl_dbg *dbg;
int retval = -ENOMEM;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index 71b80c23e8c..05a4f0f9018 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -32,7 +32,6 @@
* Enabling PCI devices is left as an exercise for the reader...
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -177,7 +176,9 @@ static void pci_rescan_slot(struct pci_dev *temp)
struct pci_bus *bus = temp->bus;
struct pci_dev *dev;
int func;
+ int retval;
u8 hdr_type;
+
if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
temp->hdr_type = hdr_type & 0x7f;
if (!pci_find_slot(bus->number, temp->devfn)) {
@@ -186,8 +187,12 @@ static void pci_rescan_slot(struct pci_dev *temp)
dbg("New device on %s function %x:%x\n",
bus->name, temp->devfn >> 3,
temp->devfn & 7);
- pci_bus_add_device(dev);
- add_slot(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "error adding "
+ "device, continuing.\n");
+ else
+ add_slot(dev);
}
}
/* multifunction device? */
@@ -206,8 +211,12 @@ static void pci_rescan_slot(struct pci_dev *temp)
dbg("New device on %s function %x:%x\n",
bus->name, temp->devfn >> 3,
temp->devfn & 7);
- pci_bus_add_device(dev);
- add_slot(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "error adding "
+ "device, continuing.\n");
+ else
+ add_slot(dev);
}
}
}
diff --git a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h
index e929b7c1142..772523dc386 100644
--- a/drivers/pci/hotplug/pci_hotplug.h
+++ b/drivers/pci/hotplug/pci_hotplug.h
@@ -172,8 +172,8 @@ struct hotplug_slot {
extern int pci_hp_register (struct hotplug_slot *slot);
extern int pci_hp_deregister (struct hotplug_slot *slot);
-extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
- struct hotplug_slot_info *info);
+extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
+ struct hotplug_slot_info *info);
extern struct subsystem pci_hotplug_slots_subsys;
/* PCI Setting Record (Type 0) */
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index c4282902cb5..e2823ea9c4e 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -483,31 +482,95 @@ static int has_test_file (struct hotplug_slot *slot)
static int fs_add_slot (struct hotplug_slot *slot)
{
- if (has_power_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+ int retval = 0;
- if (has_attention_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+ if (has_power_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+ if (retval)
+ goto exit_power;
+ }
- if (has_latch_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+ if (has_attention_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_attention.attr);
+ if (retval)
+ goto exit_attention;
+ }
- if (has_adapter_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+ if (has_latch_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_latch.attr);
+ if (retval)
+ goto exit_latch;
+ }
- if (has_address_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+ if (has_adapter_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_presence.attr);
+ if (retval)
+ goto exit_adapter;
+ }
- if (has_max_bus_speed_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+ if (has_address_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_address.attr);
+ if (retval)
+ goto exit_address;
+ }
+ if (has_max_bus_speed_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_max_bus_speed.attr);
+ if (retval)
+ goto exit_max_speed;
+ }
+
+ if (has_cur_bus_speed_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_cur_bus_speed.attr);
+ if (retval)
+ goto exit_cur_speed;
+ }
+
+ if (has_test_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_test.attr);
+ if (retval)
+ goto exit_test;
+ }
+
+ goto exit;
+
+exit_test:
if (has_cur_bus_speed_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
- if (has_test_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr);
+exit_cur_speed:
+ if (has_max_bus_speed_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
- return 0;
+exit_max_speed:
+ if (has_address_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+
+exit_address:
+ if (has_adapter_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+
+exit_adapter:
+ if (has_latch_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+
+exit_latch:
+ if (has_attention_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+
+exit_attention:
+ if (has_power_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+exit_power:
+exit:
+ return retval;
}
static void fs_remove_slot (struct hotplug_slot *slot)
@@ -627,8 +690,11 @@ int pci_hp_deregister (struct hotplug_slot *slot)
*
* Returns 0 if successful, anything else for an error.
*/
-int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info)
+int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
+ struct hotplug_slot_info *info)
{
+ int retval;
+
if ((slot == NULL) || (info == NULL))
return -ENODEV;
@@ -637,32 +703,60 @@ int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info
* for the files referring to the fields that have now changed.
*/
if ((has_power_file(slot) == 0) &&
- (slot->info->power_status != info->power_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+ (slot->info->power_status != info->power_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_power.attr);
+ if (retval)
+ return retval;
+ }
if ((has_attention_file(slot) == 0) &&
- (slot->info->attention_status != info->attention_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+ (slot->info->attention_status != info->attention_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_attention.attr);
+ if (retval)
+ return retval;
+ }
if ((has_latch_file(slot) == 0) &&
- (slot->info->latch_status != info->latch_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+ (slot->info->latch_status != info->latch_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_latch.attr);
+ if (retval)
+ return retval;
+ }
if ((has_adapter_file(slot) == 0) &&
- (slot->info->adapter_status != info->adapter_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+ (slot->info->adapter_status != info->adapter_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_presence.attr);
+ if (retval)
+ return retval;
+ }
if ((has_address_file(slot) == 0) &&
- (slot->info->address != info->address))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+ (slot->info->address != info->address)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_address.attr);
+ if (retval)
+ return retval;
+ }
if ((has_max_bus_speed_file(slot) == 0) &&
- (slot->info->max_bus_speed != info->max_bus_speed))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+ (slot->info->max_bus_speed != info->max_bus_speed)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_max_bus_speed.attr);
+ if (retval)
+ return retval;
+ }
if ((has_cur_bus_speed_file(slot) == 0) &&
- (slot->info->cur_bus_speed != info->cur_bus_speed))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+ (slot->info->cur_bus_speed != info->cur_bus_speed)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_cur_bus_speed.attr);
+ if (retval)
+ return retval;
+ }
memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index ce89f581586..eaea9d36a1b 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -279,6 +279,11 @@ struct hpc_ops {
#ifdef CONFIG_ACPI
+#include <acpi/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/actypes.h>
+#include <linux/pci-acpi.h>
+
#define pciehp_get_hp_hw_control_from_firmware(dev) \
pciehp_acpi_get_hp_hw_control_from_firmware(dev)
static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 33d19876835..41290a106bd 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -762,14 +762,14 @@ int pciehp_enable_slot(struct slot *p_slot)
if (rc || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
}
@@ -778,7 +778,7 @@ int pciehp_enable_slot(struct slot *p_slot)
if (rc || getstatus) {
info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -EINVAL;
}
}
mutex_unlock(&p_slot->ctrl->crit_sect);
@@ -813,7 +813,7 @@ int pciehp_disable_slot(struct slot *p_slot)
if (ret || !getstatus) {
info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
}
@@ -822,7 +822,7 @@ int pciehp_disable_slot(struct slot *p_slot)
if (ret || getstatus) {
info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
}
@@ -831,7 +831,7 @@ int pciehp_disable_slot(struct slot *p_slot)
if (ret || !getstatus) {
info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -EINVAL;
}
}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index d77138ecb09..6ab3b6cd2b5 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -38,10 +38,6 @@
#include "../pci.h"
#include "pciehp.h"
-#include <acpi/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/actypes.h>
-#include <linux/pci-acpi.h>
#ifdef DEBUG
#define DBG_K_TRACE_ENTRY ((unsigned int)0x00000001) /* On function entry */
#define DBG_K_TRACE_EXIT ((unsigned int)0x00000002) /* On function exit */
@@ -1398,8 +1394,9 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
for ( rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
if (pci_resource_len(pdev, rc) > 0)
- dbg("pci resource[%d] start=0x%lx(len=0x%lx)\n", rc,
- pci_resource_start(pdev, rc), pci_resource_len(pdev, rc));
+ dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
+ (unsigned long long)pci_resource_start(pdev, rc),
+ (unsigned long long)pci_resource_len(pdev, rc));
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device);
@@ -1457,7 +1454,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
start_int_poll_timer( php_ctlr, 10 ); /* start with 10 second delay */
} else {
/* Installs the interrupt handler */
- rc = request_irq(php_ctlr->irq, pcie_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+ rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
if (rc) {
err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c
index 0a46f549676..2b9e10e3861 100644
--- a/drivers/pci/hotplug/pcihp_skeleton.c
+++ b/drivers/pci/hotplug/pcihp_skeleton.c
@@ -1,5 +1,5 @@
/*
- * PCI Hot Plug Controller Skeleton Driver - 0.2
+ * PCI Hot Plug Controller Skeleton Driver - 0.3
*
* Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2001,2003 IBM Corp.
@@ -21,14 +21,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * This driver is to be used as a skeleton driver to be show how to interface
+ * This driver is to be used as a skeleton driver to show how to interface
* with the pci hotplug core easily.
*
* Send feedback to <greg@kroah.com>
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -59,8 +58,6 @@ static LIST_HEAD(slot_list);
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
-
-
/* local variables */
static int debug;
static int num_slots;
@@ -110,7 +107,6 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
return retval;
}
-
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
@@ -343,7 +339,7 @@ static int __init pcihp_skel_init(void)
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
/*
* Do specific initialization stuff for your driver here
- * Like initializing your controller hardware (if any) and
+ * like initializing your controller hardware (if any) and
* determining the number of slots you have in the system
* right now.
*/
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 63800454670..7288a3eccfb 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -22,7 +22,6 @@
* Send feedback to <lxie@us.ibm.com>
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
@@ -177,16 +176,16 @@ static int get_max_bus_speed(struct hotplug_slot *hotplug_slot, enum pci_bus_spe
return 0;
}
-static int get_children_props(struct device_node *dn, int **drc_indexes,
- int **drc_names, int **drc_types, int **drc_power_domains)
+static int get_children_props(struct device_node *dn, const int **drc_indexes,
+ const int **drc_names, const int **drc_types,
+ const int **drc_power_domains)
{
- int *indexes, *names;
- int *types, *domains;
+ const int *indexes, *names, *types, *domains;
- indexes = (int *) get_property(dn, "ibm,drc-indexes", NULL);
- names = (int *) get_property(dn, "ibm,drc-names", NULL);
- types = (int *) get_property(dn, "ibm,drc-types", NULL);
- domains = (int *) get_property(dn, "ibm,drc-power-domains", NULL);
+ indexes = get_property(dn, "ibm,drc-indexes", NULL);
+ names = get_property(dn, "ibm,drc-names", NULL);
+ types = get_property(dn, "ibm,drc-types", NULL);
+ domains = get_property(dn, "ibm,drc-power-domains", NULL);
if (!indexes || !names || !types || !domains) {
/* Slot does not have dynamically-removable children */
@@ -213,13 +212,13 @@ static int get_children_props(struct device_node *dn, int **drc_indexes,
int rpaphp_get_drc_props(struct device_node *dn, int *drc_index,
char **drc_name, char **drc_type, int *drc_power_domain)
{
- int *indexes, *names;
- int *types, *domains;
- unsigned int *my_index;
+ const int *indexes, *names;
+ const int *types, *domains;
+ const unsigned int *my_index;
char *name_tmp, *type_tmp;
int i, rc;
- my_index = (int *) get_property(dn, "ibm,my-drc-index", NULL);
+ my_index = get_property(dn, "ibm,my-drc-index", NULL);
if (!my_index) {
/* Node isn't DLPAR/hotplug capable */
return -EINVAL;
@@ -266,10 +265,10 @@ static int is_php_type(char *drc_type)
return 1;
}
-static int is_php_dn(struct device_node *dn, int **indexes, int **names,
- int **types, int **power_domains)
+static int is_php_dn(struct device_node *dn, const int **indexes,
+ const int **names, const int **types, const int **power_domains)
{
- int *drc_types;
+ const int *drc_types;
int rc;
rc = get_children_props(dn, indexes, names, &drc_types, power_domains);
@@ -297,7 +296,7 @@ int rpaphp_add_slot(struct device_node *dn)
struct slot *slot;
int retval = 0;
int i;
- int *indexes, *names, *types, *power_domains;
+ const int *indexes, *names, *types, *power_domains;
char *name, *type;
dbg("Entry %s: dn->full_name=%s\n", __FUNCTION__, dn->full_name);
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 7208b95c6ee..c7103ac5cd0 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -173,7 +173,7 @@ struct controller {
#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
/* sysfs functions for the hotplug controller info */
-extern void shpchp_create_ctrl_files (struct controller *ctrl);
+extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
extern int shpchp_sysfs_enable_slot(struct slot *slot);
extern int shpchp_sysfs_disable_slot(struct slot *slot);
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index a14e7de1984..235c18a2239 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -449,10 +449,14 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ctrl->speed = PCI_SPEED_33MHz;
}
- shpchp_create_ctrl_files(ctrl);
+ rc = shpchp_create_ctrl_files(ctrl);
+ if (rc)
+ goto err_cleanup_slots;
return 0;
+err_cleanup_slots:
+ cleanup_slots(ctrl);
err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 45facaad39b..0f9798df470 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -1246,7 +1246,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
} else
php_ctlr->irq = pdev->irq;
- rc = request_irq(php_ctlr->irq, shpc_isr, SA_SHIRQ, MY_NAME, (void *) ctrl);
+ rc = request_irq(php_ctlr->irq, shpc_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
if (rc) {
err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index f5cfbf2c047..29fa9d26ada 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -51,8 +51,10 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
res = bus->resource[index];
if (res && (res->flags & IORESOURCE_MEM) &&
!(res->flags & IORESOURCE_PREFETCH)) {
- out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
- res->start, (res->end - res->start));
+ out += sprintf(out, "start = %8.8llx, "
+ "length = %8.8llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)(res->end - res->start));
}
}
out += sprintf(out, "Free resources: prefetchable memory\n");
@@ -60,16 +62,20 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
res = bus->resource[index];
if (res && (res->flags & IORESOURCE_MEM) &&
(res->flags & IORESOURCE_PREFETCH)) {
- out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
- res->start, (res->end - res->start));
+ out += sprintf(out, "start = %8.8llx, "
+ "length = %8.8llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)(res->end - res->start));
}
}
out += sprintf(out, "Free resources: IO\n");
for (index = 0; index < PCI_BUS_NUM_RESOURCES; index++) {
res = bus->resource[index];
if (res && (res->flags & IORESOURCE_IO)) {
- out += sprintf(out, "start = %8.8lx, length = %8.8lx\n",
- res->start, (res->end - res->start));
+ out += sprintf(out, "start = %8.8llx, "
+ "length = %8.8llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)(res->end - res->start));
}
}
out += sprintf(out, "Free resources: bus numbers\n");
@@ -85,9 +91,9 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
-void shpchp_create_ctrl_files (struct controller *ctrl)
+int __must_check shpchp_create_ctrl_files (struct controller *ctrl)
{
- device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
+ return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
}
void shpchp_remove_ctrl_files(struct controller *ctrl)
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
index 0eb5fe9003a..5ed798b319c 100644
--- a/drivers/pci/msi-apic.c
+++ b/drivers/pci/msi-apic.c
@@ -4,6 +4,7 @@
#include <linux/pci.h>
#include <linux/irq.h>
+#include <asm/smp.h>
#include "msi.h"
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 7f8429284fa..27a057409ec 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -10,7 +10,6 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/ioport.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
@@ -46,16 +45,10 @@ msi_register(struct msi_ops *ops)
return 0;
}
-static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
-{
- memset(p, 0, NR_IRQS * sizeof(struct msi_desc));
-}
-
static int msi_cache_init(void)
{
- msi_cachep = kmem_cache_create("msi_cache",
- NR_IRQS * sizeof(struct msi_desc),
- 0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
+ msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!msi_cachep)
return -ENOMEM;
@@ -403,11 +396,10 @@ static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
- entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+ entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL);
if (!entry)
return NULL;
- memset(entry, 0, sizeof(struct msi_desc));
entry->link.tail = entry->link.head = 0; /* single message */
entry->dev = NULL;
@@ -429,12 +421,12 @@ static void irq_handler_init(int cap_id, int pos, int mask)
spin_lock_irqsave(&irq_desc[pos].lock, flags);
if (cap_id == PCI_CAP_ID_MSIX)
- irq_desc[pos].handler = &msix_irq_type;
+ irq_desc[pos].chip = &msix_irq_type;
else {
if (!mask)
- irq_desc[pos].handler = &msi_irq_wo_maskbit_type;
+ irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
else
- irq_desc[pos].handler = &msi_irq_w_maskbit_type;
+ irq_desc[pos].chip = &msi_irq_w_maskbit_type;
}
spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
}
@@ -902,6 +894,33 @@ static int msix_capability_init(struct pci_dev *dev,
}
/**
+ * pci_msi_supported - check whether MSI may be enabled on device
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * MSI must be globally enabled and supported by the device and its root
+ * bus. But, the root bus is not easy to find since some architectures
+ * have virtual busses on top of the PCI hierarchy (for instance the
+ * hypertransport bus), while the actual bus where MSI must be supported
+ * is below. So we test the MSI flag on all parent busses and assume
+ * that no quirk will ever set the NO_MSI flag on a non-root bus.
+ **/
+static
+int pci_msi_supported(struct pci_dev * dev)
+{
+ struct pci_bus *bus;
+
+ if (!pci_msi_enable || !dev || dev->no_msi)
+ return -EINVAL;
+
+ /* check MSI flags of all parent busses */
+ for (bus = dev->bus; bus; bus = bus->parent)
+ if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
* pci_enable_msi - configure device's MSI capability structure
* @dev: pointer to the pci_dev data structure of MSI device function
*
@@ -913,19 +932,11 @@ static int msix_capability_init(struct pci_dev *dev,
**/
int pci_enable_msi(struct pci_dev* dev)
{
- struct pci_bus *bus;
- int pos, temp, status = -EINVAL;
+ int pos, temp, status;
u16 control;
- if (!pci_msi_enable || !dev)
- return status;
-
- if (dev->no_msi)
- return status;
-
- for (bus = dev->bus; bus; bus = bus->parent)
- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
- return -EINVAL;
+ if (pci_msi_supported(dev) < 0)
+ return -EINVAL;
temp = dev->irq;
@@ -1135,22 +1146,14 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
**/
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
- struct pci_bus *bus;
int status, pos, nr_entries, free_vectors;
int i, j, temp;
u16 control;
unsigned long flags;
- if (!pci_msi_enable || !dev || !entries)
+ if (!entries || pci_msi_supported(dev) < 0)
return -EINVAL;
- if (dev->no_msi)
- return -EINVAL;
-
- for (bus = dev->bus; bus; bus = bus->parent)
- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
- return -EINVAL;
-
status = msi_init();
if (status < 0)
return status;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 10e1a905c14..b1c0c707d96 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -17,6 +17,16 @@
* Registration of PCI drivers and handling of hot-pluggable devices.
*/
+/* multithreaded probe logic */
+static int pci_multithread_probe =
+#ifdef CONFIG_PCI_MULTITHREAD_PROBE
+ 1;
+#else
+ 0;
+#endif
+__module_param_call("", pci_multithread_probe, param_set_bool, param_get_bool, &pci_multithread_probe, 0644);
+
+
/*
* Dynamic device IDs are disabled for !CONFIG_HOTPLUG
*/
@@ -46,6 +56,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
+ int retval = 0;
fields = sscanf(buf, "%x %x %x %x %x %x %lux",
&vendor, &device, &subvendor, &subdevice,
@@ -72,10 +83,12 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
spin_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->driver)) {
- driver_attach(&pdrv->driver);
+ retval = driver_attach(&pdrv->driver);
put_driver(&pdrv->driver);
}
+ if (retval)
+ return retval;
return count;
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
@@ -139,9 +152,8 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
/**
* pci_match_device - Tell if a PCI device structure has a matching
* PCI device id structure
- * @ids: array of PCI device id structures to search in
- * @dev: the PCI device structure to match against
* @drv: the PCI driver to match against
+ * @dev: the PCI device structure to match against
*
* Used by a driver to check whether a PCI device present in the
* system is in its list of supported devices. Returns the matching
@@ -280,6 +292,18 @@ static int pci_device_suspend(struct device * dev, pm_message_t state)
return i;
}
+static int pci_device_suspend_late(struct device * dev, pm_message_t state)
+{
+ struct pci_dev * pci_dev = to_pci_dev(dev);
+ struct pci_driver * drv = pci_dev->driver;
+ int i = 0;
+
+ if (drv && drv->suspend_late) {
+ i = drv->suspend_late(pci_dev, state);
+ suspend_report_result(drv->suspend_late, i);
+ }
+ return i;
+}
/*
* Default resume method for devices that have no driver provided resume,
@@ -314,6 +338,17 @@ static int pci_device_resume(struct device * dev)
return error;
}
+static int pci_device_resume_early(struct device * dev)
+{
+ int error = 0;
+ struct pci_dev * pci_dev = to_pci_dev(dev);
+ struct pci_driver * drv = pci_dev->driver;
+
+ if (drv && drv->resume_early)
+ error = drv->resume_early(pci_dev);
+ return error;
+}
+
static void pci_device_shutdown(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -387,6 +422,11 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
drv->driver.owner = owner;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
+ if (pci_multithread_probe)
+ drv->driver.multithread_probe = pci_multithread_probe;
+ else
+ drv->driver.multithread_probe = drv->multithread_probe;
+
spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);
@@ -510,8 +550,10 @@ struct bus_type pci_bus_type = {
.probe = pci_device_probe,
.remove = pci_device_remove,
.suspend = pci_device_suspend,
- .shutdown = pci_device_shutdown,
+ .suspend_late = pci_device_suspend_late,
+ .resume_early = pci_device_resume_early,
.resume = pci_device_resume,
+ .shutdown = pci_device_shutdown,
.dev_attrs = pci_dev_attrs,
};
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index bc405c035ce..a1d2e979b17 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -15,7 +15,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/stat.h>
@@ -87,7 +86,7 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
char * str = buf;
int i;
int max = 7;
- u64 start, end;
+ resource_size_t start, end;
if (pci_dev->subordinate)
max = DEVICE_COUNT_RESOURCE;
@@ -118,6 +117,7 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ int retval = 0;
/* this can crash the machine when done on the "wrong" device */
if (!capable(CAP_SYS_ADMIN))
@@ -127,11 +127,53 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
pci_disable_device(pdev);
if (*buf == '1')
- pci_enable_device(pdev);
+ retval = pci_enable_device(pdev);
+ if (retval)
+ return retval;
return count;
}
+static ssize_t
+msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (!pdev->subordinate)
+ return 0;
+
+ return sprintf (buf, "%u\n",
+ !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
+}
+
+static ssize_t
+msi_bus_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ /* bad things may happen if the no_msi flag is changed
+ * while some drivers are loaded */
+ if (!capable(CAP_SYS_ADMIN))
+ return count;
+
+ if (!pdev->subordinate)
+ return count;
+
+ if (*buf == '0') {
+ pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"
+ " bad things could happen.\n");
+ }
+
+ if (*buf == '1') {
+ pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
+ dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
+ " bad things could happen.\n");
+ }
+
+ return count;
+}
struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(resource),
@@ -146,6 +188,7 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR(enable, 0600, is_enabled_show, is_enabled_store),
__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
broken_parity_status_show,broken_parity_status_store),
+ __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
__ATTR_NULL,
};
@@ -365,7 +408,7 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
struct device, kobj));
struct resource *res = (struct resource *)attr->private;
enum pci_mmap_state mmap_type;
- u64 start, end;
+ resource_size_t start, end;
int i;
for (i = 0; i < PCI_ROM_RESOURCE; i++)
@@ -386,15 +429,38 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
}
/**
+ * pci_remove_resource_files - cleanup resource files
+ * @dev: dev to cleanup
+ *
+ * If we created resource files for @dev, remove them from sysfs and
+ * free their resources.
+ */
+static void
+pci_remove_resource_files(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+ struct bin_attribute *res_attr;
+
+ res_attr = pdev->res_attr[i];
+ if (res_attr) {
+ sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+ kfree(res_attr);
+ }
+ }
+}
+
+/**
* pci_create_resource_files - create resource files in sysfs for @dev
* @dev: dev in question
*
* Walk the resources in @dev creating files for each resource available.
*/
-static void
-pci_create_resource_files(struct pci_dev *pdev)
+static int pci_create_resource_files(struct pci_dev *pdev)
{
int i;
+ int retval;
/* Expose the PCI resources from this device as files */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
@@ -417,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev)
res_attr->size = pci_resource_len(pdev, i);
res_attr->mmap = pci_mmap_resource;
res_attr->private = &pdev->resource[i];
- sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
- }
- }
-}
-
-/**
- * pci_remove_resource_files - cleanup resource files
- * @dev: dev to cleanup
- *
- * If we created resource files for @dev, remove them from sysfs and
- * free their resources.
- */
-static void
-pci_remove_resource_files(struct pci_dev *pdev)
-{
- int i;
-
- for (i = 0; i < PCI_ROM_RESOURCE; i++) {
- struct bin_attribute *res_attr;
-
- res_attr = pdev->res_attr[i];
- if (res_attr) {
- sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
- kfree(res_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+ if (retval) {
+ pci_remove_resource_files(pdev);
+ return retval;
+ }
+ } else {
+ return -ENOMEM;
}
}
+ return 0;
}
#else /* !HAVE_PCI_MMAP */
-static inline void pci_create_resource_files(struct pci_dev *dev) { return; }
+static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
#endif /* HAVE_PCI_MMAP */
@@ -530,22 +580,27 @@ static struct bin_attribute pcie_config_attr = {
.write = pci_write_config,
};
-int pci_create_sysfs_dev_files (struct pci_dev *pdev)
+int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
+ struct bin_attribute *rom_attr = NULL;
+ int retval;
+
if (!sysfs_initialized)
return -EACCES;
if (pdev->cfg_size < 4096)
- sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
- sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+ if (retval)
+ goto err;
- pci_create_resource_files(pdev);
+ retval = pci_create_resource_files(pdev);
+ if (retval)
+ goto err_bin_file;
/* If the device has a ROM, try to expose it in sysfs. */
if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
- struct bin_attribute *rom_attr;
-
rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
if (rom_attr) {
pdev->rom_attr = rom_attr;
@@ -555,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev)
rom_attr->attr.owner = THIS_MODULE;
rom_attr->read = pci_read_rom;
rom_attr->write = pci_write_rom;
- sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
+ if (retval)
+ goto err_rom;
+ } else {
+ retval = -ENOMEM;
+ goto err_bin_file;
}
}
/* add platform-specific attributes */
pcibios_add_platform_entries(pdev);
-
+
return 0;
+
+err_rom:
+ kfree(rom_attr);
+err_bin_file:
+ if (pdev->cfg_size < 4096)
+ sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
+ else
+ sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+err:
+ return retval;
}
/**
@@ -590,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
static int __init pci_sysfs_init(void)
{
struct pci_dev *pdev = NULL;
-
+ int retval;
+
sysfs_initialized = 1;
- for_each_pci_dev(pdev)
- pci_create_sysfs_dev_files(pdev);
+ for_each_pci_dev(pdev) {
+ retval = pci_create_sysfs_dev_files(pdev);
+ if (retval)
+ return retval;
+ }
return 0;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index d408a3c3042..a544997399b 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -19,6 +19,7 @@
#include <asm/dma.h> /* isa_dma_bridge_buggy */
#include "pci.h"
+unsigned int pci_pm_d3_delay = 10;
/**
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
@@ -313,6 +314,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
} else if (dev->current_state == state)
return 0; /* we're already there */
+ /*
+ * If the device or the parent bridge can't support PCI PM, ignore
+ * the request if we're doing anything besides putting it into D0
+ * (which would only happen on boot).
+ */
+ if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+ return 0;
+
/* find PCI PM capability in list */
pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -363,13 +372,13 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
/* Mandatory power management transition delays */
/* see PCI PM 1.1 5.6.1 table 18 */
if (state == PCI_D3hot || dev->current_state == PCI_D3hot)
- msleep(10);
+ msleep(pci_pm_d3_delay);
else if (state == PCI_D2 || dev->current_state == PCI_D2)
udelay(200);
/*
* Give firmware a chance to be called, such as ACPI _PRx, _PSx
- * Firmware method after natice method ?
+ * Firmware method after native method ?
*/
if (platform_pci_set_power_state)
platform_pci_set_power_state(dev, state);
@@ -423,10 +432,12 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
case PM_EVENT_ON:
return PCI_D0;
case PM_EVENT_FREEZE:
+ case PM_EVENT_PRETHAW:
+ /* REVISIT both freeze and pre-thaw "should" use D0 */
case PM_EVENT_SUSPEND:
return PCI_D3hot;
default:
- printk("They asked me for state %d\n", state.event);
+ printk("Unrecognized suspend event %d\n", state.event);
BUG();
}
return PCI_D0;
@@ -434,6 +445,51 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
EXPORT_SYMBOL(pci_choose_state);
+static int pci_save_pcie_state(struct pci_dev *dev)
+{
+ int pos, i = 0;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pos <= 0)
+ return 0;
+
+ save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
+ if (!save_state) {
+ dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
+ return -ENOMEM;
+ }
+ cap = (u16 *)&save_state->data[0];
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
+ pci_add_saved_cap(dev, save_state);
+ return 0;
+}
+
+static void pci_restore_pcie_state(struct pci_dev *dev)
+{
+ int i = 0, pos;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!save_state || pos <= 0)
+ return;
+ cap = (u16 *)&save_state->data[0];
+
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
+ pci_remove_saved_cap(save_state);
+ kfree(save_state);
+}
+
/**
* pci_save_state - save the PCI configuration space of a device before suspending
* @dev: - PCI device that we're dealing with
@@ -449,6 +505,8 @@ pci_save_state(struct pci_dev *dev)
return i;
if ((i = pci_save_msix_state(dev)) != 0)
return i;
+ if ((i = pci_save_pcie_state(dev)) != 0)
+ return i;
return 0;
}
@@ -462,6 +520,9 @@ pci_restore_state(struct pci_dev *dev)
int i;
int val;
+ /* PCI Express register must be restored first */
+ pci_restore_pcie_state(dev);
+
/*
* The Base Address register should be programmed before the command
* register(s)
@@ -691,10 +752,12 @@ int pci_request_region(struct pci_dev *pdev, int bar, const char *res_name)
return 0;
err_out:
- printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
+ printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%llx@%llx "
+ "for device %s\n",
pci_resource_flags(pdev, bar) & IORESOURCE_IO ? "I/O" : "mem",
bar + 1, /* PCI BAR # */
- pci_resource_len(pdev, bar), pci_resource_start(pdev, bar),
+ (unsigned long long)pci_resource_len(pdev, bar),
+ (unsigned long long)pci_resource_start(pdev, bar),
pci_name(pdev));
return -EBUSY;
}
@@ -942,13 +1005,12 @@ static int __devinit pci_setup(char *str)
}
str = k;
}
- return 1;
+ return 0;
}
+early_param("pci", pci_setup);
device_initcall(pci_init);
-__setup("pci=", pci_setup);
-
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
/* FIXME: Some boxes have multiple ISA bridges! */
struct pci_dev *isa_bridge;
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 29bdeca031a..6bf327db5c5 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -6,10 +6,10 @@ extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_remove_sysfs_dev_files(struct pci_dev *pdev);
extern void pci_cleanup_rom(struct pci_dev *dev);
extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
- unsigned long size, unsigned long align,
- unsigned long min, unsigned int type_mask,
+ resource_size_t size, resource_size_t align,
+ resource_size_t min, unsigned int type_mask,
void (*alignf)(void *, struct resource *,
- unsigned long, unsigned long),
+ resource_size_t, resource_size_t),
void *alignf_data);
/* Firmware callbacks */
extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
@@ -42,12 +42,12 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_PCI_MSI
extern int pci_msi_quirk;
#else
#define pci_msi_quirk 0
#endif
-
+extern unsigned int pci_pm_d3_delay;
#ifdef CONFIG_PCI_MSI
void disable_msi_mode(struct pci_dev *dev, int pos, int type);
void pci_no_msi(void);
@@ -66,7 +66,15 @@ static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
static inline void pci_restore_msi_state(struct pci_dev *dev) {}
static inline void pci_restore_msix_state(struct pci_dev *dev) {}
#endif
+static inline int pci_no_d1d2(struct pci_dev *dev)
+{
+ unsigned int parent_dstates = 0;
+ if (dev->bus->self)
+ parent_dstates = dev->bus->self->no_d1d2;
+ return (dev->no_d1d2 || parent_dstates);
+
+}
extern int pcie_mch_quirk;
extern struct device_attribute pci_dev_attrs[];
extern struct class_device_attribute class_device_attr_cpuaffinity;
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 1012db8b8b2..0ad92a8ad8b 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -34,3 +34,4 @@ config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
When in doubt, say N.
+source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 984fa87283e..e00fb99acf4 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -5,3 +5,6 @@
pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
+
+# Build PCI Express AER if needed
+obj-$(CONFIG_PCIEAER) += aer/
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
new file mode 100644
index 00000000000..3f37a60a643
--- /dev/null
+++ b/drivers/pci/pcie/aer/Kconfig
@@ -0,0 +1,12 @@
+#
+# PCI Express Root Port Device AER Configuration
+#
+
+config PCIEAER
+ boolean "Root Port Advanced Error Reporting support"
+ depends on PCIEPORTBUS && ACPI
+ default y
+ help
+ This enables PCI Express Root Port Advanced Error Reporting
+ (AER) driver support. Error reporting messages sent to Root
+ Port will be handled by PCI Express AER driver.
diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile
new file mode 100644
index 00000000000..15a4f40d520
--- /dev/null
+++ b/drivers/pci/pcie/aer/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for PCI-Express Root Port Advanced Error Reporting Driver
+#
+
+obj-$(CONFIG_PCIEAER) += aerdriver.o
+
+aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o
+
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
new file mode 100644
index 00000000000..0d4ac027d53
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -0,0 +1,346 @@
+/*
+ * drivers/pci/pcie/aer/aerdrv.c
+ *
+ * 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.
+ *
+ * This file implements the AER root port service driver. The driver will
+ * register an irq handler. When root port triggers an AER interrupt, the irq
+ * handler will collect root port status and schedule a work.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pcieport_if.h>
+
+#include "aerdrv.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
+#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static int __devinit aer_probe (struct pcie_device *dev,
+ const struct pcie_port_service_id *id );
+static void aer_remove(struct pcie_device *dev);
+static int aer_suspend(struct pcie_device *dev, pm_message_t state)
+{return 0;}
+static int aer_resume(struct pcie_device *dev) {return 0;}
+static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error);
+static void aer_error_resume(struct pci_dev *dev);
+static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
+
+/*
+ * PCI Express bus's AER Root service driver data structure
+ */
+static struct pcie_port_service_id aer_id[] = {
+ {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .port_type = PCIE_RC_PORT,
+ .service_type = PCIE_PORT_SERVICE_AER,
+ },
+ { /* end: all zeroes */ }
+};
+
+static struct pci_error_handlers aer_error_handlers = {
+ .error_detected = aer_error_detected,
+ .resume = aer_error_resume,
+};
+
+static struct pcie_port_service_driver aerdrv = {
+ .name = "aer",
+ .id_table = &aer_id[0],
+
+ .probe = aer_probe,
+ .remove = aer_remove,
+
+ .suspend = aer_suspend,
+ .resume = aer_resume,
+
+ .err_handler = &aer_error_handlers,
+
+ .reset_link = aer_root_reset,
+};
+
+/**
+ * aer_irq - Root Port's ISR
+ * @irq: IRQ assigned to Root Port
+ * @context: pointer to Root Port data structure
+ * @r: pointer struct pt_regs
+ *
+ * Invoked when Root Port detects AER messages.
+ **/
+static irqreturn_t aer_irq(int irq, void *context, struct pt_regs * r)
+{
+ unsigned int status, id;
+ struct pcie_device *pdev = (struct pcie_device *)context;
+ struct aer_rpc *rpc = get_service_data(pdev);
+ int next_prod_idx;
+ unsigned long flags;
+ int pos;
+
+ pos = pci_find_aer_capability(pdev->port);
+ /*
+ * Must lock access to Root Error Status Reg, Root Error ID Reg,
+ * and Root error producer/consumer index
+ */
+ spin_lock_irqsave(&rpc->e_lock, flags);
+
+ /* Read error status */
+ pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
+ if (!(status & ROOT_ERR_STATUS_MASKS)) {
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return IRQ_NONE;
+ }
+
+ /* Read error source and clear error status */
+ pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
+ pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
+
+ /* Store error source for later DPC handler */
+ next_prod_idx = rpc->prod_idx + 1;
+ if (next_prod_idx == AER_ERROR_SOURCES_MAX)
+ next_prod_idx = 0;
+ if (next_prod_idx == rpc->cons_idx) {
+ /*
+ * Error Storm Condition - possibly the same error occurred.
+ * Drop the error.
+ */
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return IRQ_HANDLED;
+ }
+ rpc->e_sources[rpc->prod_idx].status = status;
+ rpc->e_sources[rpc->prod_idx].id = id;
+ rpc->prod_idx = next_prod_idx;
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+
+ /* Invoke DPC handler */
+ schedule_work(&rpc->dpc_handler);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * aer_alloc_rpc - allocate Root Port data structure
+ * @dev: pointer to the pcie_dev data structure
+ *
+ * Invoked when Root Port's AER service is loaded.
+ **/
+static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
+{
+ struct aer_rpc *rpc;
+
+ if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc),
+ GFP_KERNEL)))
+ return NULL;
+
+ memset(rpc, 0, sizeof(struct aer_rpc));
+ /*
+ * Initialize Root lock access, e_lock, to Root Error Status Reg,
+ * Root Error ID Reg, and Root error producer/consumer index.
+ */
+ rpc->e_lock = SPIN_LOCK_UNLOCKED;
+
+ rpc->rpd = dev;
+ INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev);
+ rpc->prod_idx = rpc->cons_idx = 0;
+ mutex_init(&rpc->rpc_mutex);
+ init_waitqueue_head(&rpc->wait_release);
+
+ /* Use PCIE bus function to store rpc into PCIE device */
+ set_service_data(dev, rpc);
+
+ return rpc;
+}
+
+/**
+ * aer_remove - clean up resources
+ * @dev: pointer to the pcie_dev data structure
+ *
+ * Invoked when PCI Express bus unloads or AER probe fails.
+ **/
+static void aer_remove(struct pcie_device *dev)
+{
+ struct aer_rpc *rpc = get_service_data(dev);
+
+ if (rpc) {
+ /* If register interrupt service, it must be free. */
+ if (rpc->isr)
+ free_irq(dev->irq, dev);
+
+ wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
+
+ aer_delete_rootport(rpc);
+ set_service_data(dev, NULL);
+ }
+}
+
+/**
+ * aer_probe - initialize resources
+ * @dev: pointer to the pcie_dev data structure
+ * @id: pointer to the service id data structure
+ *
+ * Invoked when PCI Express bus loads AER service driver.
+ **/
+static int __devinit aer_probe (struct pcie_device *dev,
+ const struct pcie_port_service_id *id )
+{
+ int status;
+ struct aer_rpc *rpc;
+ struct device *device = &dev->device;
+
+ /* Init */
+ if ((status = aer_init(dev)))
+ return status;
+
+ /* Alloc rpc data structure */
+ if (!(rpc = aer_alloc_rpc(dev))) {
+ printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n",
+ __FUNCTION__, device->bus_id);
+ aer_remove(dev);
+ return -ENOMEM;
+ }
+
+ /* Request IRQ ISR */
+ if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv",
+ dev))) {
+ printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n",
+ __FUNCTION__, device->bus_id);
+ aer_remove(dev);
+ return status;
+ }
+
+ rpc->isr = 1;
+
+ aer_enable_rootport(rpc);
+
+ return status;
+}
+
+/**
+ * aer_root_reset - reset link on Root Port
+ * @dev: pointer to Root Port's pci_dev data structure
+ *
+ * Invoked by Port Bus driver when performing link reset at Root Port.
+ **/
+static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
+{
+ u16 p2p_ctrl;
+ u32 status;
+ int pos;
+
+ pos = pci_find_aer_capability(dev);
+
+ /* Disable Root's interrupt in response to error messages */
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
+
+ /* Assert Secondary Bus Reset */
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
+ p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+
+ /* De-assert Secondary Bus Reset */
+ p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+
+ /*
+ * System software must wait for at least 100ms from the end
+ * of a reset of one or more device before it is permitted
+ * to issue Configuration Requests to those devices.
+ */
+ msleep(200);
+ printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id);
+
+ /* Enable Root Port's interrupt in response to error messages */
+ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
+ pci_write_config_dword(dev,
+ pos + PCI_ERR_ROOT_COMMAND,
+ ROOT_PORT_INTR_ON_MESG_MASK);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * aer_error_detected - update severity status
+ * @dev: pointer to Root Port's pci_dev data structure
+ * @error: error severity being notified by port bus
+ *
+ * Invoked by Port Bus driver during error recovery.
+ **/
+static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error)
+{
+ /* Root Port has no impact. Always recovers. */
+ return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+/**
+ * aer_error_resume - clean up corresponding error status bits
+ * @dev: pointer to Root Port's pci_dev data structure
+ *
+ * Invoked by Port Bus driver during nonfatal recovery.
+ **/
+static void aer_error_resume(struct pci_dev *dev)
+{
+ int pos;
+ u32 status, mask;
+ u16 reg16;
+
+ /* Clean up Root device status */
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
+ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
+
+ /* Clean AER Root Error Status */
+ pos = pci_find_aer_capability(dev);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
+ if (dev->error_state == pci_channel_io_normal)
+ status &= ~mask; /* Clear corresponding nonfatal bits */
+ else
+ status &= mask; /* Clear corresponding fatal bits */
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
+}
+
+/**
+ * aer_service_init - register AER root service driver
+ *
+ * Invoked when AER root service driver is loaded.
+ **/
+static int __init aer_service_init(void)
+{
+ return pcie_port_service_register(&aerdrv);
+}
+
+/**
+ * aer_service_exit - unregister AER root service driver
+ *
+ * Invoked when AER root service driver is unloaded.
+ **/
+static void __exit aer_service_exit(void)
+{
+ pcie_port_service_unregister(&aerdrv);
+}
+
+module_init(aer_service_init);
+module_exit(aer_service_exit);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
new file mode 100644
index 00000000000..daf0cad88fc
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#ifndef _AERDRV_H_
+#define _AERDRV_H_
+
+#include <linux/pcieport_if.h>
+#include <linux/aer.h>
+
+#define AER_NONFATAL 0
+#define AER_FATAL 1
+#define AER_CORRECTABLE 2
+#define AER_UNCORRECTABLE 4
+#define AER_ERROR_MASK 0x001fffff
+#define AER_ERROR(d) (d & AER_ERROR_MASK)
+
+#define OSC_METHOD_RUN_SUCCESS 0
+#define OSC_METHOD_NOT_SUPPORTED 1
+#define OSC_METHOD_RUN_FAILURE 2
+
+/* Root Error Status Register Bits */
+#define ROOT_ERR_STATUS_MASKS 0x0f
+
+#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \
+ PCI_EXP_RTCTL_SENFEE| \
+ PCI_EXP_RTCTL_SEFEE)
+#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \
+ PCI_ERR_ROOT_CMD_NONFATAL_EN| \
+ PCI_ERR_ROOT_CMD_FATAL_EN)
+#define ERR_COR_ID(d) (d & 0xffff)
+#define ERR_UNCOR_ID(d) (d >> 16)
+
+#define AER_SUCCESS 0
+#define AER_UNSUCCESS 1
+#define AER_ERROR_SOURCES_MAX 100
+
+#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \
+ PCI_ERR_UNC_ECRC| \
+ PCI_ERR_UNC_UNSUP| \
+ PCI_ERR_UNC_COMP_ABORT| \
+ PCI_ERR_UNC_UNX_COMP| \
+ PCI_ERR_UNC_MALF_TLP)
+
+/* AER Error Info Flags */
+#define AER_TLP_HEADER_VALID_FLAG 0x00000001
+#define AER_MULTI_ERROR_VALID_FLAG 0x00000002
+
+#define ERR_CORRECTABLE_ERROR_MASK 0x000031c1
+#define ERR_UNCORRECTABLE_ERROR_MASK 0x001ff010
+
+struct header_log_regs {
+ unsigned int dw0;
+ unsigned int dw1;
+ unsigned int dw2;
+ unsigned int dw3;
+};
+
+struct aer_err_info {
+ int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */
+ int flags;
+ unsigned int status; /* COR/UNCOR Error Status */
+ struct header_log_regs tlp; /* TLP Header */
+};
+
+struct aer_err_source {
+ unsigned int status;
+ unsigned int id;
+};
+
+struct aer_rpc {
+ struct pcie_device *rpd; /* Root Port device */
+ struct work_struct dpc_handler;
+ struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
+ unsigned short prod_idx; /* Error Producer Index */
+ unsigned short cons_idx; /* Error Consumer Index */
+ int isr;
+ spinlock_t e_lock; /*
+ * Lock access to Error Status/ID Regs
+ * and error producer/consumer index
+ */
+ struct mutex rpc_mutex; /*
+ * only one thread could do
+ * recovery on the same
+ * root port hierachy
+ */
+ wait_queue_head_t wait_release;
+};
+
+struct aer_broadcast_data {
+ enum pci_channel_state state;
+ enum pci_ers_result result;
+};
+
+static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
+ enum pci_ers_result new)
+{
+ switch (orig) {
+ case PCI_ERS_RESULT_CAN_RECOVER:
+ case PCI_ERS_RESULT_RECOVERED:
+ orig = new;
+ break;
+ case PCI_ERS_RESULT_DISCONNECT:
+ if (new == PCI_ERS_RESULT_NEED_RESET)
+ orig = new;
+ break;
+ default:
+ break;
+ }
+
+ return orig;
+}
+
+extern struct bus_type pcie_port_bus_type;
+extern void aer_enable_rootport(struct aer_rpc *rpc);
+extern void aer_delete_rootport(struct aer_rpc *rpc);
+extern int aer_init(struct pcie_device *dev);
+extern void aer_isr(void *context);
+extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
+extern int aer_osc_setup(struct pci_dev *dev);
+
+#endif //_AERDRV_H_
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
new file mode 100644
index 00000000000..fa68e89ebec
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -0,0 +1,68 @@
+/*
+ * Access ACPI _OSC method
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/delay.h>
+#include "aerdrv.h"
+
+/**
+ * aer_osc_setup - run ACPI _OSC method
+ *
+ * Return:
+ * Zero if success. Nonzero for otherwise.
+ *
+ * Invoked when PCIE bus loads AER service driver. To avoid conflict with
+ * BIOS AER support requires BIOS to yield AER control to OS native driver.
+ **/
+int aer_osc_setup(struct pci_dev *dev)
+{
+ int retval = OSC_METHOD_RUN_SUCCESS;
+ acpi_status status;
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ struct pci_dev *pdev = dev;
+ struct pci_bus *parent;
+
+ while (!handle) {
+ if (!pdev || !pdev->bus->parent)
+ break;
+ parent = pdev->bus->parent;
+ if (!parent->self)
+ /* Parent must be a host bridge */
+ handle = acpi_get_pci_rootbridge_handle(
+ pci_domain_nr(parent),
+ parent->number);
+ else
+ handle = DEVICE_ACPI_HANDLE(
+ &(parent->self->dev));
+ pdev = parent->self;
+ }
+
+ if (!handle)
+ return OSC_METHOD_NOT_SUPPORTED;
+
+ pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
+ status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL |
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_SUPPORT)
+ retval = OSC_METHOD_NOT_SUPPORTED;
+ else
+ retval = OSC_METHOD_RUN_FAILURE;
+ }
+
+ return retval;
+}
+
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
new file mode 100644
index 00000000000..1c7e660d653
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -0,0 +1,758 @@
+/*
+ * drivers/pci/pcie/aer/aerdrv_core.c
+ *
+ * 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.
+ *
+ * This file implements the core part of PCI-Express AER. When an pci-express
+ * error is delivered, an error message will be collected and printed to
+ * console, then, an error recovery procedure will be executed by following
+ * the pci error recovery rules.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/delay.h>
+#include "aerdrv.h"
+
+static int forceload;
+module_param(forceload, bool, 0);
+
+#define PCI_CFG_SPACE_SIZE (0x100)
+int pci_find_aer_capability(struct pci_dev *dev)
+{
+ int pos;
+ u32 reg32 = 0;
+
+ /* Check if it's a pci-express device */
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return 0;
+
+ /* Check if it supports pci-express AER */
+ pos = PCI_CFG_SPACE_SIZE;
+ while (pos) {
+ if (pci_read_config_dword(dev, pos, &reg32))
+ return 0;
+
+ /* some broken boards return ~0 */
+ if (reg32 == 0xffffffff)
+ return 0;
+
+ if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
+ break;
+
+ pos = reg32 >> 20;
+ }
+
+ return pos;
+}
+
+int pci_enable_pcie_error_reporting(struct pci_dev *dev)
+{
+ u16 reg16 = 0;
+ int pos;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
+ reg16 = reg16 |
+ PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE;
+ pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
+ reg16);
+ return 0;
+}
+
+int pci_disable_pcie_error_reporting(struct pci_dev *dev)
+{
+ u16 reg16 = 0;
+ int pos;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
+ reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE);
+ pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
+ reg16);
+ return 0;
+}
+
+int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
+{
+ int pos;
+ u32 status, mask;
+
+ pos = pci_find_aer_capability(dev);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
+ if (dev->error_state == pci_channel_io_normal)
+ status &= ~mask; /* Clear corresponding nonfatal bits */
+ else
+ status &= mask; /* Clear corresponding fatal bits */
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
+
+ return 0;
+}
+
+static int find_device_iter(struct device *device, void *data)
+{
+ struct pci_dev *dev;
+ u16 id = *(unsigned long *)data;
+ u8 secondary, subordinate, d_bus = id >> 8;
+
+ if (device->bus == &pci_bus_type) {
+ dev = to_pci_dev(device);
+ if (id == ((dev->bus->number << 8) | dev->devfn)) {
+ /*
+ * Device ID match
+ */
+ *(unsigned long*)data = (unsigned long)device;
+ return 1;
+ }
+
+ /*
+ * If device is P2P, check if it is an upstream?
+ */
+ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+ pci_read_config_byte(dev, PCI_SECONDARY_BUS,
+ &secondary);
+ pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
+ &subordinate);
+ if (d_bus >= secondary && d_bus <= subordinate) {
+ *(unsigned long*)data = (unsigned long)device;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * find_source_device - search through device hierarchy for source device
+ * @p_dev: pointer to Root Port pci_dev data structure
+ * @id: device ID of agent who sends an error message to this Root Port
+ *
+ * Invoked when error is detected at the Root Port.
+ **/
+static struct device* find_source_device(struct pci_dev *parent, u16 id)
+{
+ struct pci_dev *dev = parent;
+ struct device *device;
+ unsigned long device_addr;
+ int status;
+
+ /* Is Root Port an agent that sends error message? */
+ if (id == ((dev->bus->number << 8) | dev->devfn))
+ return &dev->dev;
+
+ do {
+ device_addr = id;
+ if ((status = device_for_each_child(&dev->dev,
+ &device_addr, find_device_iter))) {
+ device = (struct device*)device_addr;
+ dev = to_pci_dev(device);
+ if (id == ((dev->bus->number << 8) | dev->devfn))
+ return device;
+ }
+ }while (status);
+
+ return NULL;
+}
+
+static void report_error_detected(struct pci_dev *dev, void *data)
+{
+ pci_ers_result_t vote;
+ struct pci_error_handlers *err_handler;
+ struct aer_broadcast_data *result_data;
+ result_data = (struct aer_broadcast_data *) data;
+
+ dev->error_state = result_data->state;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->error_detected) {
+ if (result_data->state == pci_channel_io_frozen &&
+ !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) {
+ /*
+ * In case of fatal recovery, if one of down-
+ * stream device has no driver. We might be
+ * unable to recover because a later insmod
+ * of a driver for this device is unaware of
+ * its hw state.
+ */
+ printk(KERN_DEBUG "Device ID[%s] has %s\n",
+ dev->dev.bus_id, (dev->driver) ?
+ "no AER-aware driver" : "no driver");
+ }
+ return;
+ }
+
+ err_handler = dev->driver->err_handler;
+ vote = err_handler->error_detected(dev, result_data->state);
+ result_data->result = merge_result(result_data->result, vote);
+ return;
+}
+
+static void report_mmio_enabled(struct pci_dev *dev, void *data)
+{
+ pci_ers_result_t vote;
+ struct pci_error_handlers *err_handler;
+ struct aer_broadcast_data *result_data;
+ result_data = (struct aer_broadcast_data *) data;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->mmio_enabled)
+ return;
+
+ err_handler = dev->driver->err_handler;
+ vote = err_handler->mmio_enabled(dev);
+ result_data->result = merge_result(result_data->result, vote);
+ return;
+}
+
+static void report_slot_reset(struct pci_dev *dev, void *data)
+{
+ pci_ers_result_t vote;
+ struct pci_error_handlers *err_handler;
+ struct aer_broadcast_data *result_data;
+ result_data = (struct aer_broadcast_data *) data;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->slot_reset)
+ return;
+
+ err_handler = dev->driver->err_handler;
+ vote = err_handler->slot_reset(dev);
+ result_data->result = merge_result(result_data->result, vote);
+ return;
+}
+
+static void report_resume(struct pci_dev *dev, void *data)
+{
+ struct pci_error_handlers *err_handler;
+
+ dev->error_state = pci_channel_io_normal;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->slot_reset)
+ return;
+
+ err_handler = dev->driver->err_handler;
+ err_handler->resume(dev);
+ return;
+}
+
+/**
+ * broadcast_error_message - handle message broadcast to downstream drivers
+ * @device: pointer to from where in a hierarchy message is broadcasted down
+ * @api: callback to be broadcasted
+ * @state: error state
+ *
+ * Invoked during error recovery process. Once being invoked, the content
+ * of error severity will be broadcasted to all downstream drivers in a
+ * hierarchy in question.
+ **/
+static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
+ enum pci_channel_state state,
+ char *error_mesg,
+ void (*cb)(struct pci_dev *, void *))
+{
+ struct aer_broadcast_data result_data;
+
+ printk(KERN_DEBUG "Broadcast %s message\n", error_mesg);
+ result_data.state = state;
+ if (cb == report_error_detected)
+ result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
+ else
+ result_data.result = PCI_ERS_RESULT_RECOVERED;
+
+ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+ /*
+ * If the error is reported by a bridge, we think this error
+ * is related to the downstream link of the bridge, so we
+ * do error recovery on all subordinates of the bridge instead
+ * of the bridge and clear the error status of the bridge.
+ */
+ if (cb == report_error_detected)
+ dev->error_state = state;
+ pci_walk_bus(dev->subordinate, cb, &result_data);
+ if (cb == report_resume) {
+ pci_cleanup_aer_uncorrect_error_status(dev);
+ dev->error_state = pci_channel_io_normal;
+ }
+ }
+ else {
+ /*
+ * If the error is reported by an end point, we think this
+ * error is related to the upstream link of the end point.
+ */
+ pci_walk_bus(dev->bus, cb, &result_data);
+ }
+
+ return result_data.result;
+}
+
+struct find_aer_service_data {
+ struct pcie_port_service_driver *aer_driver;
+ int is_downstream;
+};
+
+static int find_aer_service_iter(struct device *device, void *data)
+{
+ struct device_driver *driver;
+ struct pcie_port_service_driver *service_driver;
+ struct pcie_device *pcie_dev;
+ struct find_aer_service_data *result;
+
+ result = (struct find_aer_service_data *) data;
+
+ if (device->bus == &pcie_port_bus_type) {
+ pcie_dev = to_pcie_device(device);
+ if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
+ result->is_downstream = 1;
+
+ driver = device->driver;
+ if (driver) {
+ service_driver = to_service_driver(driver);
+ if (service_driver->id_table->service_type ==
+ PCIE_PORT_SERVICE_AER) {
+ result->aer_driver = service_driver;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void find_aer_service(struct pci_dev *dev,
+ struct find_aer_service_data *data)
+{
+ int retval;
+ retval = device_for_each_child(&dev->dev, data, find_aer_service_iter);
+}
+
+static pci_ers_result_t reset_link(struct pcie_device *aerdev,
+ struct pci_dev *dev)
+{
+ struct pci_dev *udev;
+ pci_ers_result_t status;
+ struct find_aer_service_data data;
+
+ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
+ udev = dev;
+ else
+ udev= dev->bus->self;
+
+ data.is_downstream = 0;
+ data.aer_driver = NULL;
+ find_aer_service(udev, &data);
+
+ /*
+ * Use the aer driver of the error agent firstly.
+ * If it hasn't the aer driver, use the root port's
+ */
+ if (!data.aer_driver || !data.aer_driver->reset_link) {
+ if (data.is_downstream &&
+ aerdev->device.driver &&
+ to_service_driver(aerdev->device.driver)->reset_link) {
+ data.aer_driver =
+ to_service_driver(aerdev->device.driver);
+ } else {
+ printk(KERN_DEBUG "No link-reset support to Device ID"
+ "[%s]\n",
+ dev->dev.bus_id);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ }
+
+ status = data.aer_driver->reset_link(udev);
+ if (status != PCI_ERS_RESULT_RECOVERED) {
+ printk(KERN_DEBUG "Link reset at upstream Device ID"
+ "[%s] failed\n",
+ udev->dev.bus_id);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ return status;
+}
+
+/**
+ * do_recovery - handle nonfatal/fatal error recovery process
+ * @aerdev: pointer to a pcie_device data structure of root port
+ * @dev: pointer to a pci_dev data structure of agent detecting an error
+ * @severity: error severity type
+ *
+ * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
+ * error detected message to all downstream drivers within a hierarchy in
+ * question and return the returned code.
+ **/
+static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
+ struct pci_dev *dev,
+ int severity)
+{
+ pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
+ enum pci_channel_state state;
+
+ if (severity == AER_FATAL)
+ state = pci_channel_io_frozen;
+ else
+ state = pci_channel_io_normal;
+
+ status = broadcast_error_message(dev,
+ state,
+ "error_detected",
+ report_error_detected);
+
+ if (severity == AER_FATAL) {
+ result = reset_link(aerdev, dev);
+ if (result != PCI_ERS_RESULT_RECOVERED) {
+ /* TODO: Should panic here? */
+ return result;
+ }
+ }
+
+ if (status == PCI_ERS_RESULT_CAN_RECOVER)
+ status = broadcast_error_message(dev,
+ state,
+ "mmio_enabled",
+ report_mmio_enabled);
+
+ if (status == PCI_ERS_RESULT_NEED_RESET) {
+ /*
+ * TODO: Should call platform-specific
+ * functions to reset slot before calling
+ * drivers' slot_reset callbacks?
+ */
+ status = broadcast_error_message(dev,
+ state,
+ "slot_reset",
+ report_slot_reset);
+ }
+
+ if (status == PCI_ERS_RESULT_RECOVERED)
+ broadcast_error_message(dev,
+ state,
+ "resume",
+ report_resume);
+
+ return status;
+}
+
+/**
+ * handle_error_source - handle logging error into an event log
+ * @aerdev: pointer to pcie_device data structure of the root port
+ * @dev: pointer to pci_dev data structure of error source device
+ * @info: comprehensive error information
+ *
+ * Invoked when an error being detected by Root Port.
+ **/
+static void handle_error_source(struct pcie_device * aerdev,
+ struct pci_dev *dev,
+ struct aer_err_info info)
+{
+ pci_ers_result_t status = 0;
+ int pos;
+
+ if (info.severity == AER_CORRECTABLE) {
+ /*
+ * Correctable error does not need software intevention.
+ * No need to go through error recovery process.
+ */
+ pos = pci_find_aer_capability(dev);
+ if (pos)
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
+ info.status);
+ } else {
+ status = do_recovery(aerdev, dev, info.severity);
+ if (status == PCI_ERS_RESULT_RECOVERED) {
+ printk(KERN_DEBUG "AER driver successfully recovered\n");
+ } else {
+ /* TODO: Should kernel panic here? */
+ printk(KERN_DEBUG "AER driver didn't recover\n");
+ }
+ }
+}
+
+/**
+ * aer_enable_rootport - enable Root Port's interrupts when receiving messages
+ * @rpc: pointer to a Root Port data structure
+ *
+ * Invoked when PCIE bus loads AER service driver.
+ **/
+void aer_enable_rootport(struct aer_rpc *rpc)
+{
+ struct pci_dev *pdev = rpc->rpd->port;
+ int pos, aer_pos;
+ u16 reg16;
+ u32 reg32;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ /* Clear PCIE Capability's Device Status */
+ pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
+ pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
+
+ /* Disable system error generation in response to error messages */
+ pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
+ reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
+ pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
+
+ aer_pos = pci_find_aer_capability(pdev);
+ /* Clear error status */
+ pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
+ pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
+ pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
+ pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
+ pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
+ pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
+
+ /* Enable Root Port device reporting error itself */
+ pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);
+ reg16 = reg16 |
+ PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE;
+ pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
+ reg16);
+
+ /* Enable Root Port's interrupt in response to error messages */
+ pci_write_config_dword(pdev,
+ aer_pos + PCI_ERR_ROOT_COMMAND,
+ ROOT_PORT_INTR_ON_MESG_MASK);
+}
+
+/**
+ * disable_root_aer - disable Root Port's interrupts when receiving messages
+ * @rpc: pointer to a Root Port data structure
+ *
+ * Invoked when PCIE bus unloads AER service driver.
+ **/
+static void disable_root_aer(struct aer_rpc *rpc)
+{
+ struct pci_dev *pdev = rpc->rpd->port;
+ u32 reg32;
+ int pos;
+
+ pos = pci_find_aer_capability(pdev);
+ /* Disable Root's interrupt in response to error messages */
+ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
+
+ /* Clear Root's error status reg */
+ pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
+}
+
+/**
+ * get_e_source - retrieve an error source
+ * @rpc: pointer to the root port which holds an error
+ *
+ * Invoked by DPC handler to consume an error.
+ **/
+static struct aer_err_source* get_e_source(struct aer_rpc *rpc)
+{
+ struct aer_err_source *e_source;
+ unsigned long flags;
+
+ /* Lock access to Root error producer/consumer index */
+ spin_lock_irqsave(&rpc->e_lock, flags);
+ if (rpc->prod_idx == rpc->cons_idx) {
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return NULL;
+ }
+ e_source = &rpc->e_sources[rpc->cons_idx];
+ rpc->cons_idx++;
+ if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
+ rpc->cons_idx = 0;
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+
+ return e_source;
+}
+
+static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
+{
+ int pos;
+
+ pos = pci_find_aer_capability(dev);
+
+ /* The device might not support AER */
+ if (!pos)
+ return AER_SUCCESS;
+
+ if (info->severity == AER_CORRECTABLE) {
+ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
+ &info->status);
+ if (!(info->status & ERR_CORRECTABLE_ERROR_MASK))
+ return AER_UNSUCCESS;
+ } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||
+ info->severity == AER_NONFATAL) {
+
+ /* Link is still healthy for IO reads */
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+ &info->status);
+ if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK))
+ return AER_UNSUCCESS;
+
+ if (info->status & AER_LOG_TLP_MASKS) {
+ info->flags |= AER_TLP_HEADER_VALID_FLAG;
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
+ }
+ }
+
+ return AER_SUCCESS;
+}
+
+/**
+ * aer_isr_one_error - consume an error detected by root port
+ * @p_device: pointer to error root port service device
+ * @e_src: pointer to an error source
+ **/
+static void aer_isr_one_error(struct pcie_device *p_device,
+ struct aer_err_source *e_src)
+{
+ struct device *s_device;
+ struct aer_err_info e_info = {0, 0, 0,};
+ int i;
+ u16 id;
+
+ /*
+ * There is a possibility that both correctable error and
+ * uncorrectable error being logged. Report correctable error first.
+ */
+ for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {
+ if (i > 4)
+ break;
+ if (!(e_src->status & i))
+ continue;
+
+ /* Init comprehensive error information */
+ if (i & PCI_ERR_ROOT_COR_RCV) {
+ id = ERR_COR_ID(e_src->id);
+ e_info.severity = AER_CORRECTABLE;
+ } else {
+ id = ERR_UNCOR_ID(e_src->id);
+ e_info.severity = ((e_src->status >> 6) & 1);
+ }
+ if (e_src->status &
+ (PCI_ERR_ROOT_MULTI_COR_RCV |
+ PCI_ERR_ROOT_MULTI_UNCOR_RCV))
+ e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
+ if (!(s_device = find_source_device(p_device->port, id))) {
+ printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
+ __FUNCTION__, id);
+ continue;
+ }
+ if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
+ AER_SUCCESS) {
+ aer_print_error(to_pci_dev(s_device), &e_info);
+ handle_error_source(p_device,
+ to_pci_dev(s_device),
+ e_info);
+ }
+ }
+}
+
+/**
+ * aer_isr - consume errors detected by root port
+ * @context: pointer to a private data of pcie device
+ *
+ * Invoked, as DPC, when root port records new detected error
+ **/
+void aer_isr(void *context)
+{
+ struct pcie_device *p_device = (struct pcie_device *) context;
+ struct aer_rpc *rpc = get_service_data(p_device);
+ struct aer_err_source *e_src;
+
+ mutex_lock(&rpc->rpc_mutex);
+ e_src = get_e_source(rpc);
+ while (e_src) {
+ aer_isr_one_error(p_device, e_src);
+ e_src = get_e_source(rpc);
+ }
+ mutex_unlock(&rpc->rpc_mutex);
+
+ wake_up(&rpc->wait_release);
+}
+
+/**
+ * aer_delete_rootport - disable root port aer and delete service data
+ * @rpc: pointer to a root port device being deleted
+ *
+ * Invoked when AER service unloaded on a specific Root Port
+ **/
+void aer_delete_rootport(struct aer_rpc *rpc)
+{
+ /* Disable root port AER itself */
+ disable_root_aer(rpc);
+
+ kfree(rpc);
+}
+
+/**
+ * aer_init - provide AER initialization
+ * @dev: pointer to AER pcie device
+ *
+ * Invoked when AER service driver is loaded.
+ **/
+int aer_init(struct pcie_device *dev)
+{
+ int status;
+
+ /* Run _OSC Method */
+ status = aer_osc_setup(dev->port);
+
+ if(status != OSC_METHOD_RUN_SUCCESS) {
+ printk(KERN_DEBUG "%s: AER service init fails - %s\n",
+ __FUNCTION__,
+ (status == OSC_METHOD_NOT_SUPPORTED) ?
+ "No ACPI _OSC support" : "Run ACPI _OSC fails");
+
+ if (!forceload)
+ return status;
+ }
+
+ return AER_SUCCESS;
+}
+
+EXPORT_SYMBOL_GPL(pci_find_aer_capability);
+EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
+EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
+EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
+
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
new file mode 100644
index 00000000000..3933d4f30e8
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -0,0 +1,248 @@
+/*
+ * drivers/pci/pcie/aer/aerdrv_errprint.c
+ *
+ * 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.
+ *
+ * Format error messages and print them to console.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+
+#include "aerdrv.h"
+
+#define AER_AGENT_RECEIVER 0
+#define AER_AGENT_REQUESTER 1
+#define AER_AGENT_COMPLETER 2
+#define AER_AGENT_TRANSMITTER 3
+
+#define AER_AGENT_REQUESTER_MASK (PCI_ERR_UNC_COMP_TIME| \
+ PCI_ERR_UNC_UNSUP)
+
+#define AER_AGENT_COMPLETER_MASK PCI_ERR_UNC_COMP_ABORT
+
+#define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \
+ ((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0)))
+
+#define AER_GET_AGENT(t, e) \
+ ((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER : \
+ (e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER : \
+ (AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER : \
+ AER_AGENT_RECEIVER)
+
+#define AER_PHYSICAL_LAYER_ERROR_MASK PCI_ERR_COR_RCVR
+#define AER_DATA_LINK_LAYER_ERROR_MASK(t, e) \
+ (PCI_ERR_UNC_DLP| \
+ PCI_ERR_COR_BAD_TLP| \
+ PCI_ERR_COR_BAD_DLLP| \
+ PCI_ERR_COR_REP_ROLL| \
+ ((t == AER_CORRECTABLE) ? \
+ PCI_ERR_COR_REP_TIMER: 0))
+
+#define AER_PHYSICAL_LAYER_ERROR 0
+#define AER_DATA_LINK_LAYER_ERROR 1
+#define AER_TRANSACTION_LAYER_ERROR 2
+
+#define AER_GET_LAYER_ERROR(t, e) \
+ ((e & AER_PHYSICAL_LAYER_ERROR_MASK) ? \
+ AER_PHYSICAL_LAYER_ERROR : \
+ (e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ? \
+ AER_DATA_LINK_LAYER_ERROR : \
+ AER_TRANSACTION_LAYER_ERROR)
+
+/*
+ * AER error strings
+ */
+static char* aer_error_severity_string[] = {
+ "Uncorrected (Non-Fatal)",
+ "Uncorrected (Fatal)",
+ "Corrected"
+};
+
+static char* aer_error_layer[] = {
+ "Physical Layer",
+ "Data Link Layer",
+ "Transaction Layer"
+};
+static char* aer_correctable_error_string[] = {
+ "Receiver Error ", /* Bit Position 0 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Bad TLP ", /* Bit Position 6 */
+ "Bad DLLP ", /* Bit Position 7 */
+ "RELAY_NUM Rollover ", /* Bit Position 8 */
+ NULL,
+ NULL,
+ NULL,
+ "Replay Timer Timeout ", /* Bit Position 12 */
+ "Advisory Non-Fatal ", /* Bit Position 13 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static char* aer_uncorrectable_error_string[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Data Link Protocol ", /* Bit Position 4 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Poisoned TLP ", /* Bit Position 12 */
+ "Flow Control Protocol ", /* Bit Position 13 */
+ "Completion Timeout ", /* Bit Position 14 */
+ "Completer Abort ", /* Bit Position 15 */
+ "Unexpected Completion ", /* Bit Position 16 */
+ "Receiver Overflow ", /* Bit Position 17 */
+ "Malformed TLP ", /* Bit Position 18 */
+ "ECRC ", /* Bit Position 19 */
+ "Unsupported Request ", /* Bit Position 20 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static char* aer_agent_string[] = {
+ "Receiver ID",
+ "Requester ID",
+ "Completer ID",
+ "Transmitter ID"
+};
+
+static char * aer_get_error_source_name(int severity,
+ unsigned int status,
+ char errmsg_buff[])
+{
+ int i;
+ char * errmsg = NULL;
+
+ for (i = 0; i < 32; i++) {
+ if (!(status & (1 << i)))
+ continue;
+
+ if (severity == AER_CORRECTABLE)
+ errmsg = aer_correctable_error_string[i];
+ else
+ errmsg = aer_uncorrectable_error_string[i];
+
+ if (!errmsg) {
+ sprintf(errmsg_buff, "Unknown Error Bit %2d ", i);
+ errmsg = errmsg_buff;
+ }
+
+ break;
+ }
+
+ return errmsg;
+}
+
+static DEFINE_SPINLOCK(logbuf_lock);
+static char errmsg_buff[100];
+void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
+{
+ char * errmsg;
+ int err_layer, agent;
+ char * loglevel;
+
+ if (info->severity == AER_CORRECTABLE)
+ loglevel = KERN_WARNING;
+ else
+ loglevel = KERN_ERR;
+
+ printk("%s+------ PCI-Express Device Error ------+\n", loglevel);
+ printk("%sError Severity\t\t: %s\n", loglevel,
+ aer_error_severity_string[info->severity]);
+
+ if ( info->status == 0) {
+ printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel);
+ printk("%sUnaccessible Received\t: %s\n", loglevel,
+ info->flags & AER_MULTI_ERROR_VALID_FLAG ?
+ "Multiple" : "First");
+ printk("%sUnregistered Agent ID\t: %04x\n", loglevel,
+ (dev->bus->number << 8) | dev->devfn);
+ } else {
+ err_layer = AER_GET_LAYER_ERROR(info->severity, info->status);
+ printk("%sPCIE Bus Error type\t: %s\n", loglevel,
+ aer_error_layer[err_layer]);
+
+ spin_lock(&logbuf_lock);
+ errmsg = aer_get_error_source_name(info->severity,
+ info->status,
+ errmsg_buff);
+ printk("%s%s\t: %s\n", loglevel, errmsg,
+ info->flags & AER_MULTI_ERROR_VALID_FLAG ?
+ "Multiple" : "First");
+ spin_unlock(&logbuf_lock);
+
+ agent = AER_GET_AGENT(info->severity, info->status);
+ printk("%s%s\t\t: %04x\n", loglevel,
+ aer_agent_string[agent],
+ (dev->bus->number << 8) | dev->devfn);
+
+ printk("%sVendorID=%04xh, DeviceID=%04xh,"
+ " Bus=%02xh, Device=%02xh, Function=%02xh\n",
+ loglevel,
+ dev->vendor,
+ dev->device,
+ dev->bus->number,
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+
+ if (info->flags & AER_TLP_HEADER_VALID_FLAG) {
+ unsigned char *tlp = (unsigned char *) &info->tlp;
+ printk("%sTLB Header:\n", loglevel);
+ printk("%s%02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x %02x%02x%02x%02x\n",
+ loglevel,
+ *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+ *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
+ *(tlp + 11), *(tlp + 10), *(tlp + 9),
+ *(tlp + 8), *(tlp + 15), *(tlp + 14),
+ *(tlp + 13), *(tlp + 12));
+ }
+ }
+}
+
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 1d317d22ee8..67fcd176bab 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -39,7 +39,7 @@ extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state);
extern int pcie_port_device_resume(struct pci_dev *dev);
#endif
extern void pcie_port_device_remove(struct pci_dev *dev);
-extern void pcie_port_bus_register(void);
+extern int pcie_port_bus_register(void);
extern void pcie_port_bus_unregister(void);
#endif /* _PORTDRV_H_ */
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
index 3e84b501e6a..3f0976868ed 100644
--- a/drivers/pci/pcie/portdrv_bus.c
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -24,6 +24,7 @@ struct bus_type pcie_port_bus_type = {
.suspend = pcie_port_bus_suspend,
.resume = pcie_port_bus_resume,
};
+EXPORT_SYMBOL_GPL(pcie_port_bus_type);
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 55c66226786..bd6615b4d40 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -6,6 +6,7 @@
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
+#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -339,8 +340,7 @@ static int suspend_iter(struct device *dev, void *data)
int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
{
- device_for_each_child(&dev->dev, &state, suspend_iter);
- return 0;
+ return device_for_each_child(&dev->dev, &state, suspend_iter);
}
static int resume_iter(struct device *dev, void *data)
@@ -358,8 +358,7 @@ static int resume_iter(struct device *dev, void *data)
int pcie_port_device_resume(struct pci_dev *dev)
{
- device_for_each_child(&dev->dev, NULL, resume_iter);
- return 0;
+ return device_for_each_child(&dev->dev, NULL, resume_iter);
}
#endif
@@ -402,9 +401,9 @@ void pcie_port_device_remove(struct pci_dev *dev)
pci_disable_msi(dev);
}
-void pcie_port_bus_register(void)
+int __must_check pcie_port_bus_register(void)
{
- bus_register(&pcie_port_bus_type);
+ return bus_register(&pcie_port_bus_type);
}
void pcie_port_bus_unregister(void)
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 50bfc1b2f3b..037690e08f5 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -14,8 +14,10 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pcieport_if.h>
+#include <linux/aer.h>
#include "portdrv.h"
+#include "aer/aerdrv.h"
/*
* Version Information
@@ -35,6 +37,7 @@ static int pcie_portdrv_save_config(struct pci_dev *dev)
return pci_save_state(dev);
}
+#ifdef CONFIG_PM
static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
int retval;
@@ -47,6 +50,25 @@ static int pcie_portdrv_restore_config(struct pci_dev *dev)
return 0;
}
+static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ int ret = pcie_port_device_suspend(dev, state);
+
+ if (!ret)
+ ret = pcie_portdrv_save_config(dev);
+ return ret;
+}
+
+static int pcie_portdrv_resume(struct pci_dev *dev)
+{
+ pcie_portdrv_restore_config(dev);
+ return pcie_port_device_resume(dev);
+}
+#else
+#define pcie_portdrv_suspend NULL
+#define pcie_portdrv_resume NULL
+#endif
+
/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
@@ -73,8 +95,14 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
"%s->Dev[%04x:%04x] has invalid IRQ. Check vendor BIOS\n",
__FUNCTION__, dev->device, dev->vendor);
}
- if (pcie_port_device_register(dev))
+ if (pcie_port_device_register(dev)) {
+ pci_disable_device(dev);
return -ENOMEM;
+ }
+
+ pcie_portdrv_save_config(dev);
+
+ pci_enable_pcie_error_reporting(dev);
return 0;
}
@@ -85,22 +113,151 @@ static void pcie_portdrv_remove (struct pci_dev *dev)
kfree(pci_get_drvdata(dev));
}
-#ifdef CONFIG_PM
-static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
+static int error_detected_iter(struct device *device, void *data)
{
- int ret = pcie_port_device_suspend(dev, state);
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+ struct aer_broadcast_data *result_data;
+ pci_ers_result_t status;
- if (!ret)
- ret = pcie_portdrv_save_config(dev);
- return ret;
+ result_data = (struct aer_broadcast_data *) data;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (!driver ||
+ !driver->err_handler ||
+ !driver->err_handler->error_detected)
+ return 0;
+
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error detected message to service drivers */
+ status = driver->err_handler->error_detected(
+ pcie_device->port,
+ result_data->state);
+ result_data->result =
+ merge_result(result_data->result, status);
+ }
+
+ return 0;
}
-static int pcie_portdrv_resume (struct pci_dev *dev)
+static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error)
{
- pcie_portdrv_restore_config(dev);
- return pcie_port_device_resume(dev);
+ struct aer_broadcast_data result_data =
+ {error, PCI_ERS_RESULT_CAN_RECOVER};
+ int retval;
+
+ /* can not fail */
+ retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter);
+
+ return result_data.result;
+}
+
+static int mmio_enabled_iter(struct device *device, void *data)
+{
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+ pci_ers_result_t status, *result;
+
+ result = (pci_ers_result_t *) data;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (driver &&
+ driver->err_handler &&
+ driver->err_handler->mmio_enabled) {
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error message to service drivers */
+ status = driver->err_handler->mmio_enabled(
+ pcie_device->port);
+ *result = merge_result(*result, status);
+ }
+ }
+
+ return 0;
+}
+
+static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
+{
+ pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
+ int retval;
+
+ /* get true return value from &status */
+ retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
+ return status;
+}
+
+static int slot_reset_iter(struct device *device, void *data)
+{
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+ pci_ers_result_t status, *result;
+
+ result = (pci_ers_result_t *) data;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (driver &&
+ driver->err_handler &&
+ driver->err_handler->slot_reset) {
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error message to service drivers */
+ status = driver->err_handler->slot_reset(
+ pcie_device->port);
+ *result = merge_result(*result, status);
+ }
+ }
+
+ return 0;
+}
+
+static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
+{
+ pci_ers_result_t status;
+ int retval;
+
+ /* If fatal, restore cfg space for possible link reset at upstream */
+ if (dev->error_state == pci_channel_io_frozen) {
+ pcie_portdrv_restore_config(dev);
+ pci_enable_pcie_error_reporting(dev);
+ }
+
+ /* get true return value from &status */
+ retval = device_for_each_child(&dev->dev, &status, slot_reset_iter);
+
+ return status;
+}
+
+static int resume_iter(struct device *device, void *data)
+{
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (driver &&
+ driver->err_handler &&
+ driver->err_handler->resume) {
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error message to service drivers */
+ driver->err_handler->resume(pcie_device->port);
+ }
+ }
+
+ return 0;
+}
+
+static void pcie_portdrv_err_resume(struct pci_dev *dev)
+{
+ int retval;
+ /* nothing to do with error value, if it ever happens */
+ retval = device_for_each_child(&dev->dev, NULL, resume_iter);
}
-#endif
/*
* LINUX Device Driver Model
@@ -112,6 +269,13 @@ static const struct pci_device_id port_pci_ids[] = { {
};
MODULE_DEVICE_TABLE(pci, port_pci_ids);
+static struct pci_error_handlers pcie_portdrv_err_handler = {
+ .error_detected = pcie_portdrv_error_detected,
+ .mmio_enabled = pcie_portdrv_mmio_enabled,
+ .slot_reset = pcie_portdrv_slot_reset,
+ .resume = pcie_portdrv_err_resume,
+};
+
static struct pci_driver pcie_portdrv = {
.name = (char *)device_name,
.id_table = &port_pci_ids[0],
@@ -119,20 +283,25 @@ static struct pci_driver pcie_portdrv = {
.probe = pcie_portdrv_probe,
.remove = pcie_portdrv_remove,
-#ifdef CONFIG_PM
.suspend = pcie_portdrv_suspend,
.resume = pcie_portdrv_resume,
-#endif /* PM */
+
+ .err_handler = &pcie_portdrv_err_handler,
};
static int __init pcie_portdrv_init(void)
{
- int retval = 0;
+ int retval;
- pcie_port_bus_register();
+ retval = pcie_port_bus_register();
+ if (retval) {
+ printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
+ goto out;
+ }
retval = pci_register_driver(&pcie_portdrv);
if (retval)
pcie_port_bus_unregister();
+ out:
return retval;
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f89dbc3738b..a3b0a5eb505 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -339,6 +339,7 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
{
struct pci_bus *child;
int i;
+ int retval;
/*
* Allocate a new bus, and inherit stuff from the parent..
@@ -356,8 +357,13 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
child->class_dev.class = &pcibus_class;
sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
- class_device_register(&child->class_dev);
- class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity);
+ retval = class_device_register(&child->class_dev);
+ if (retval)
+ goto error_register;
+ retval = class_device_create_file(&child->class_dev,
+ &class_device_attr_cpuaffinity);
+ if (retval)
+ goto error_file_create;
/*
* Set up the primary, secondary and subordinate
@@ -375,6 +381,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
bridge->subordinate = child;
return child;
+
+error_file_create:
+ class_device_unregister(&child->class_dev);
+error_register:
+ kfree(child);
+ return NULL;
}
struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
@@ -815,6 +827,7 @@ pci_scan_device(struct pci_bus *bus, int devfn)
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
dev->cfg_size = pci_cfg_space_size(dev);
+ dev->error_state = pci_channel_io_normal;
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index 54b2ebc9c91..99cf3337976 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -302,12 +302,6 @@ static struct file_operations proc_bus_pci_operations = {
#endif /* HAVE_PCI_MMAP */
};
-#if BITS_PER_LONG == 32
-#define LONG_FORMAT "\t%08lx"
-#else
-#define LONG_FORMAT "\t%16lx"
-#endif
-
/* iterator */
static void *pci_seq_start(struct seq_file *m, loff_t *pos)
{
@@ -356,18 +350,18 @@ static int show_device(struct seq_file *m, void *v)
dev->irq);
/* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
for (i=0; i<7; i++) {
- u64 start, end;
+ resource_size_t start, end;
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
- seq_printf(m, LONG_FORMAT,
- ((unsigned long)start) |
- (dev->resource[i].flags & PCI_REGION_FLAG_MASK));
+ seq_printf(m, "\t%16llx",
+ (unsigned long long)(start |
+ (dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
}
for (i=0; i<7; i++) {
- u64 start, end;
+ resource_size_t start, end;
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
- seq_printf(m, LONG_FORMAT,
+ seq_printf(m, "\t%16llx",
dev->resource[i].start < dev->resource[i].end ?
- (unsigned long)(end - start) + 1 : 0);
+ (unsigned long long)(end - start) + 1 : 0);
}
seq_putc(m, '\t');
if (drv)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 4364d793f73..08cd86a6dd6 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -15,7 +15,6 @@
* use the PowerTweak utility (see http://powertweak.sourceforge.net).
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -401,6 +400,7 @@ static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
piix4_io_quirk(dev, "PIIX4 devres J", 0x7c, 1 << 20);
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, quirk_piix4_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, quirk_piix4_acpi );
/*
* ICH4, ICH4-M, ICH5, ICH5-M ACPI: Three IO regions pointed to by longwords at
@@ -438,6 +438,7 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
pci_read_config_dword(dev, 0x48, &region);
quirk_io_region(dev, region, 64, PCI_BRIDGE_RESOURCES+1, "ICH6 GPIO");
}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
/*
@@ -576,8 +577,6 @@ static void __init quirk_ioapic_rmw(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
-int pci_msi_quirk;
-
#define AMD8131_revA0 0x01
#define AMD8131_revB0 0x11
#define AMD8131_MISC 0x40
@@ -586,12 +585,6 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
{
unsigned char revid, tmp;
- if (dev->subordinate) {
- printk(KERN_WARNING "PCI: MSI quirk detected. "
- "PCI_BUS_FLAGS_NO_MSI set for subordinate bus.\n");
- dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
- }
-
if (nr_ioapics == 0)
return;
@@ -604,13 +597,6 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
-
-static void __init quirk_svw_msi(struct pci_dev *dev)
-{
- pci_msi_quirk = 1;
- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi );
#endif /* CONFIG_X86_IO_APIC */
@@ -666,6 +652,7 @@ DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_vi
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq);
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq);
@@ -683,6 +670,33 @@ static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id );
+#ifdef CONFIG_ACPI_SLEEP
+
+/*
+ * Some VIA systems boot with the abnormal status flag set. This can cause
+ * the BIOS to re-POST the system on resume rather than passing control
+ * back to the OS. Clear the flag on boot
+ */
+static void __devinit quirk_via_abnormal_poweroff(struct pci_dev *dev)
+{
+ u32 reg;
+
+ acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS,
+ &reg);
+
+ if (reg & 0x800) {
+ printk("Clearing abnormal poweroff flag\n");
+ acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_STATUS,
+ (u16)0x800);
+ }
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_via_abnormal_poweroff);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_abnormal_poweroff);
+
+#endif
+
/*
* CardBus controllers have a legacy base address that enables them
* to respond as i82365 pcmcia controllers. We don't want them to
@@ -963,6 +977,11 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
case 0x8070: /* P4G8X Deluxe */
asus_hides_smbus = 1;
}
+ if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+ switch (dev->subsystem_device) {
+ case 0x80c9: /* PU-DLS */
+ asus_hides_smbus = 1;
+ }
if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
switch (dev->subsystem_device) {
case 0x1751: /* M2N notebook */
@@ -1031,6 +1050,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82845G_HB, asu
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82850_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_7205_0, asus_hides_smbus_hostbridge );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7501_MCH, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855PM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855GM_HB, asus_hides_smbus_hostbridge );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82915GM_HB, asus_hides_smbus_hostbridge );
@@ -1054,10 +1074,10 @@ static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, asus_hides_smbus_lpc );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, asus_hides_smbus_lpc );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, asus_hides_smbus_lpc );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, asus_hides_smbus_lpc );
static void __init asus_hides_smbus_lpc_ich6(struct pci_dev *dev)
{
@@ -1175,6 +1195,55 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_962, quirk_sis_96x_
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_963, quirk_sis_96x_smbus );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC, quirk_sis_96x_smbus );
+#if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
+
+/*
+ * If we are using libata we can drive this chip properly but must
+ * do this early on to make the additional device appear during
+ * the PCI scanning.
+ */
+
+static void __devinit quirk_jmicron_dualfn(struct pci_dev *pdev)
+{
+ u32 conf;
+ u8 hdr;
+
+ /* Only poke fn 0 */
+ if (PCI_FUNC(pdev->devfn))
+ return;
+
+ switch(pdev->device) {
+ case PCI_DEVICE_ID_JMICRON_JMB365:
+ case PCI_DEVICE_ID_JMICRON_JMB366:
+ /* Redirect IDE second PATA port to the right spot */
+ pci_read_config_dword(pdev, 0x80, &conf);
+ conf |= (1 << 24);
+ /* Fall through */
+ pci_write_config_dword(pdev, 0x80, conf);
+ case PCI_DEVICE_ID_JMICRON_JMB361:
+ case PCI_DEVICE_ID_JMICRON_JMB363:
+ pci_read_config_dword(pdev, 0x40, &conf);
+ /* Enable dual function mode, AHCI on fn 0, IDE fn1 */
+ /* Set the class codes correctly and then direct IDE 0 */
+ conf &= ~0x000F0200; /* Clear bit 9 and 16-19 */
+ conf |= 0x00C20002; /* Set bit 1, 17, 22, 23 */
+ pci_write_config_dword(pdev, 0x40, conf);
+
+ /* Reconfigure so that the PCI scanner discovers the
+ device is now multifunction */
+
+ pci_read_config_byte(pdev, PCI_HEADER_TYPE, &hdr);
+ pdev->hdr_type = hdr & 0x7f;
+ pdev->multifunction = !!(hdr & 0x80);
+
+ break;
+ }
+}
+
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
+
+#endif
+
#ifdef CONFIG_X86_IO_APIC
static void __init quirk_alder_ioapic(struct pci_dev *pdev)
{
@@ -1216,7 +1285,7 @@ static int __init combined_setup(char *str)
}
__setup("combined_mode=", combined_setup);
-#ifdef CONFIG_SCSI_SATA_INTEL_COMBINED
+#ifdef CONFIG_SATA_INTEL_COMBINED
static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
{
u8 prog, comb, tmp;
@@ -1309,7 +1378,7 @@ static void __devinit quirk_intel_ide_combined(struct pci_dev *pdev)
request_region(0x170, 8, "libata"); /* port 1 */
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_intel_ide_combined );
-#endif /* CONFIG_SCSI_SATA_INTEL_COMBINED */
+#endif /* CONFIG_SATA_INTEL_COMBINED */
int pcie_mch_quirk;
@@ -1342,6 +1411,37 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_pc
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_pcie_pxh);
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_pcie_pxh);
+/*
+ * Some Intel PCI Express chipsets have trouble with downstream
+ * device power management.
+ */
+static void quirk_intel_pcie_pm(struct pci_dev * dev)
+{
+ pci_pm_d3_delay = 120;
+ dev->no_d1d2 = 1;
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e2, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e3, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e4, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e5, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e6, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25e7, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25f7, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25f8, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25f9, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x25fa, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2601, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2602, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2603, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2604, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2605, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2606, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2607, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2608, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2609, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260a, quirk_intel_pcie_pm);
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm);
/*
* Fixup the cardbus bridges on the IBM Dock II docking station
@@ -1404,6 +1504,63 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, quirk_netmos);
+static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
+{
+ u16 command;
+ u32 bar;
+ u8 __iomem *csr;
+ u8 cmd_hi;
+
+ switch (dev->device) {
+ /* PCI IDs taken from drivers/net/e100.c */
+ case 0x1029:
+ case 0x1030 ... 0x1034:
+ case 0x1038 ... 0x103E:
+ case 0x1050 ... 0x1057:
+ case 0x1059:
+ case 0x1064 ... 0x106B:
+ case 0x1091 ... 0x1095:
+ case 0x1209:
+ case 0x1229:
+ case 0x2449:
+ case 0x2459:
+ case 0x245D:
+ case 0x27DC:
+ break;
+ default:
+ return;
+ }
+
+ /*
+ * Some firmware hands off the e100 with interrupts enabled,
+ * which can cause a flood of interrupts if packets are
+ * received before the driver attaches to the device. So
+ * disable all e100 interrupts here. The driver will
+ * re-enable them when it's ready.
+ */
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &bar);
+
+ if (!(command & PCI_COMMAND_MEMORY) || !bar)
+ return;
+
+ csr = ioremap(bar, 8);
+ if (!csr) {
+ printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
+ pci_name(dev));
+ return;
+ }
+
+ cmd_hi = readb(csr + 3);
+ if (cmd_hi == 0) {
+ printk(KERN_WARNING "PCI: Firmware left %s e100 interrupts "
+ "enabled, disabling\n", pci_name(dev));
+ writeb(1, csr + 3);
+ }
+
+ iounmap(csr);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_e100_interrupt);
static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
{
@@ -1518,6 +1675,95 @@ static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_pcie_aer_ext_cap);
+#ifdef CONFIG_PCI_MSI
+/* To disable MSI globally */
+int pci_msi_quirk;
+
+/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
+ * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
+ * some other busses controlled by the chipset even if Linux is not aware of it.
+ * Instead of setting the flag on all busses in the machine, simply disable MSI
+ * globally.
+ */
+static void __init quirk_svw_msi(struct pci_dev *dev)
+{
+ pci_msi_quirk = 1;
+ printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
+
+/* Disable MSI on chipsets that are known to not support it */
+static void __devinit quirk_disable_msi(struct pci_dev *dev)
+{
+ if (dev->subordinate) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
+
+/* Go through the list of Hypertransport capabilities and
+ * return 1 if a HT MSI capability is found and enabled */
+static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
+{
+ u8 pos;
+ int ttl;
+ for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48;
+ pos && ttl;
+ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) {
+ u32 cap_hdr;
+ /* MSI mapping section according to Hypertransport spec */
+ if (pci_read_config_dword(dev, pos, &cap_hdr) == 0
+ && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) {
+ printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n",
+ pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled");
+ return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */
+ }
+ }
+ return 0;
+}
+
+/* Check the hypertransport MSI mapping to know whether MSI is enabled or not */
+static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
+{
+ if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "MSI disabled on chipset %s.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
+ quirk_msi_ht_cap);
+
+/* The nVidia CK804 chipset may have 2 HT MSI mappings.
+ * MSI are supported if the MSI capability set in any of these mappings.
+ */
+static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
+{
+ struct pci_dev *pdev;
+
+ if (!dev->subordinate)
+ return;
+
+ /* check HT MSI cap on this chipset and the root one.
+ * a single one having MSI is enough to be sure that MSI are supported.
+ */
+ pdev = pci_find_slot(dev->bus->number, 0);
+ if (dev->subordinate && !msi_ht_cap_enabled(dev)
+ && !msi_ht_cap_enabled(pdev)) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "MSI disabled on chipset %s.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_msi_ht_cap);
+#endif /* CONFIG_PCI_MSI */
+
EXPORT_SYMBOL(pcie_mch_quirk);
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_fixup_device);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 99ffbd478b2..430281b2e92 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -16,8 +16,11 @@ static void pci_free_resources(struct pci_dev *dev)
}
}
-static void pci_destroy_dev(struct pci_dev *dev)
+static void pci_stop_dev(struct pci_dev *dev)
{
+ if (!dev->global_list.next)
+ return;
+
if (!list_empty(&dev->global_list)) {
pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev);
@@ -27,6 +30,11 @@ static void pci_destroy_dev(struct pci_dev *dev)
dev->global_list.next = dev->global_list.prev = NULL;
up_write(&pci_bus_sem);
}
+}
+
+static void pci_destroy_dev(struct pci_dev *dev)
+{
+ pci_stop_dev(dev);
/* Remove the device from the device lists, and prevent any further
* list accesses from this device */
@@ -119,5 +127,32 @@ void pci_remove_behind_bridge(struct pci_dev *dev)
}
}
+static void pci_stop_bus_devices(struct pci_bus *bus)
+{
+ struct list_head *l, *n;
+
+ list_for_each_safe(l, n, &bus->devices) {
+ struct pci_dev *dev = pci_dev_b(l);
+ pci_stop_bus_device(dev);
+ }
+}
+
+/**
+ * pci_stop_bus_device - stop a PCI device and any children
+ * @dev: the device to stop
+ *
+ * Stop a PCI device (detach the driver, remove from the global list
+ * and so on). This also stop any subordinate buses and children in a
+ * depth-first manner.
+ */
+void pci_stop_bus_device(struct pci_dev *dev)
+{
+ if (dev->subordinate)
+ pci_stop_bus_devices(dev->subordinate);
+
+ pci_stop_dev(dev);
+}
+
EXPORT_SYMBOL(pci_remove_bus_device);
EXPORT_SYMBOL(pci_remove_behind_bridge);
+EXPORT_SYMBOL_GPL(pci_stop_bus_device);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index 598a115cd00..f5ee7ce16fa 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -6,7 +6,6 @@
*
* PCI ROM access routines
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/slab.h>
@@ -80,8 +79,8 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
} else {
if (res->flags & IORESOURCE_ROM_COPY) {
*size = pci_resource_len(pdev, PCI_ROM_RESOURCE);
- return (void __iomem *)pci_resource_start(pdev,
- PCI_ROM_RESOURCE);
+ return (void __iomem *)(unsigned long)
+ pci_resource_start(pdev, PCI_ROM_RESOURCE);
} else {
/* assign the ROM an address if it doesn't have one */
if (res->parent == NULL &&
@@ -170,11 +169,11 @@ void __iomem *pci_map_rom_copy(struct pci_dev *pdev, size_t *size)
return rom;
res->end = res->start + *size;
- memcpy_fromio((void*)res->start, rom, *size);
+ memcpy_fromio((void*)(unsigned long)res->start, rom, *size);
pci_unmap_rom(pdev, rom);
res->flags |= IORESOURCE_ROM_COPY;
- return (void __iomem *)res->start;
+ return (void __iomem *)(unsigned long)res->start;
}
/**
@@ -227,7 +226,7 @@ void pci_cleanup_rom(struct pci_dev *pdev)
{
struct resource *res = &pdev->resource[PCI_ROM_RESOURCE];
if (res->flags & IORESOURCE_ROM_COPY) {
- kfree((void*)res->start);
+ kfree((void*)(unsigned long)res->start);
res->flags &= ~IORESOURCE_ROM_COPY;
res->start = 0;
res->end = 0;
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index 622b3f8ba82..d529462d1b5 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -41,7 +41,7 @@ pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
* in the global list of PCI buses. If the bus is found, a pointer to its
* data structure is returned. If no bus is found, %NULL is returned.
*/
-struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
+struct pci_bus * pci_find_bus(int domain, int busnr)
{
struct pci_bus *bus = NULL;
struct pci_bus *tmp_bus;
@@ -61,7 +61,7 @@ struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
* @from: Previous PCI bus found, or %NULL for new search.
*
* Iterates through the list of known PCI busses. A new search is
- * initiated by passing %NULL to the @from argument. Otherwise if
+ * initiated by passing %NULL as the @from argument. Otherwise if
* @from is not %NULL, searches continue from next device on the
* global list.
*/
@@ -148,13 +148,14 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
* @from: Previous PCI device found in search, or %NULL for new search.
*
* Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
- * device structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ * found with a matching @vendor, @device, @ss_vendor and @ss_device, a
+ * pointer to its device structure is returned. Otherwise, %NULL is returned.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
*
- * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as
- * the pci device returned by this function can disappear at any moment in
+ * NOTE: Do not use this function any more; use pci_get_subsys() instead, as
+ * the PCI device returned by this function can disappear at any moment in
* time.
*/
static struct pci_dev * pci_find_subsys(unsigned int vendor,
@@ -191,14 +192,15 @@ exit:
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor and @device, a pointer to its device structure is
+ * Iterates through the list of known PCI devices. If a PCI device is found
+ * with a matching @vendor and @device, a pointer to its device structure is
* returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from next device on the global list.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from next device
+ * on the global list.
*
- * NOTE: Do not use this function anymore, use pci_get_device() instead, as
- * the pci device returned by this function can disappear at any moment in
+ * NOTE: Do not use this function any more; use pci_get_device() instead, as
+ * the PCI device returned by this function can disappear at any moment in
* time.
*/
struct pci_dev *
@@ -215,11 +217,11 @@ pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *
* @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices. If a PCI device is
- * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
+ * Iterates through the list of known PCI devices. If a PCI device is found
+ * with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
* device structure is returned, and the reference count to the device is
* incremented. Otherwise, %NULL is returned. A new search is initiated by
- * passing %NULL to the @from argument. Otherwise if @from is not %NULL,
+ * passing %NULL as the @from argument. Otherwise if @from is not %NULL,
* searches continue from next device on the global list.
* The reference count for @from is always decremented if it is not %NULL.
*/
@@ -262,7 +264,7 @@ exit:
* found with a matching @vendor and @device, the reference count to the
* device is incremented and a pointer to its device structure is returned.
* Otherwise, %NULL is returned. A new search is initiated by passing %NULL
- * to the @from argument. Otherwise if @from is not %NULL, searches continue
+ * as the @from argument. Otherwise if @from is not %NULL, searches continue
* from next device on the global list. The reference count for @from is
* always decremented if it is not %NULL.
*/
@@ -279,11 +281,13 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
* @from: Previous PCI device found in search, or %NULL for new search.
*
- * Iterates through the list of known PCI devices in the reverse order of pci_find_device().
+ * Iterates through the list of known PCI devices in the reverse order of
+ * pci_find_device().
* If a PCI device is found with a matching @vendor and @device, a pointer to
* its device structure is returned. Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
- * Otherwise if @from is not %NULL, searches continue from previous device on the global list.
+ * A new search is initiated by passing %NULL as the @from argument.
+ * Otherwise if @from is not %NULL, searches continue from previous device
+ * on the global list.
*/
struct pci_dev *
pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
@@ -317,7 +321,7 @@ exit:
* found with a matching @class, the reference count to the device is
* incremented and a pointer to its device structure is returned.
* Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL to the @from argument.
+ * A new search is initiated by passing %NULL as the @from argument.
* Otherwise if @from is not %NULL, searches continue from next device
* on the global list. The reference count for @from is always decremented
* if it is not %NULL.
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 35086e80faa..54404917be9 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -55,12 +55,19 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
list_for_each_entry(dev, &bus->devices, bus_list) {
u16 class = dev->class >> 8;
- /* Don't touch classless devices or host bridges or ioapics. */
+ /* Don't touch classless devices or host bridges. */
if (class == PCI_CLASS_NOT_DEFINED ||
- class == PCI_CLASS_BRIDGE_HOST ||
- class == PCI_CLASS_SYSTEM_PIC)
+ class == PCI_CLASS_BRIDGE_HOST)
continue;
+ /* Don't touch ioapics if it has the assigned resources. */
+ if (class == PCI_CLASS_SYSTEM_PIC) {
+ res = &dev->resource[0];
+ if (res[0].start || res[1].start || res[2].start ||
+ res[3].start || res[4].start || res[5].start)
+ continue;
+ }
+
pdev_sort_resources(dev, &head);
}
@@ -357,8 +364,10 @@ pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
order = __ffs(align) - 20;
if (order > 11) {
printk(KERN_WARNING "PCI: region %s/%d "
- "too large: %lx-%lx\n",
- pci_name(dev), i, r->start, r->end);
+ "too large: %llx-%llx\n",
+ pci_name(dev), i,
+ (unsigned long long)r->start,
+ (unsigned long long)r->end);
r->flags = 0;
continue;
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 577f4b55c46..ab78e4bbdd8 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -40,8 +40,9 @@ pci_update_resource(struct pci_dev *dev, struct resource *res, int resno)
pcibios_resource_to_bus(dev, &region, res);
- pr_debug(" got res [%lx:%lx] bus [%lx:%lx] flags %lx for "
- "BAR %d of %s\n", res->start, res->end,
+ pr_debug(" got res [%llx:%llx] bus [%lx:%lx] flags %lx for "
+ "BAR %d of %s\n", (unsigned long long)res->start,
+ (unsigned long long)res->end,
region.start, region.end, res->flags, resno, pci_name(dev));
new = region.start | (res->flags & PCI_REGION_FLAG_MASK);
@@ -104,10 +105,12 @@ pci_claim_resource(struct pci_dev *dev, int resource)
err = insert_resource(root, res);
if (err) {
- printk(KERN_ERR "PCI: %s region %d of %s %s [%lx:%lx]\n",
- root ? "Address space collision on" :
- "No parent found for",
- resource, dtype, pci_name(dev), res->start, res->end);
+ printk(KERN_ERR "PCI: %s region %d of %s %s [%llx:%llx]\n",
+ root ? "Address space collision on" :
+ "No parent found for",
+ resource, dtype, pci_name(dev),
+ (unsigned long long)res->start,
+ (unsigned long long)res->end);
}
return err;
@@ -118,7 +121,7 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
{
struct pci_bus *bus = dev->bus;
struct resource *res = dev->resource + resno;
- unsigned long size, min, align;
+ resource_size_t size, min, align;
int ret;
size = res->end - res->start + 1;
@@ -145,9 +148,11 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
}
if (ret) {
- printk(KERN_ERR "PCI: Failed to allocate %s resource #%d:%lx@%lx for %s\n",
- res->flags & IORESOURCE_IO ? "I/O" : "mem",
- resno, size, res->start, pci_name(dev));
+ printk(KERN_ERR "PCI: Failed to allocate %s resource "
+ "#%d:%llx@%llx for %s\n",
+ res->flags & IORESOURCE_IO ? "I/O" : "mem",
+ resno, (unsigned long long)size,
+ (unsigned long long)res->start, pci_name(dev));
} else if (resno < PCI_BRIDGE_RESOURCES) {
pci_update_resource(dev, res, resno);
}
@@ -204,7 +209,7 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
for (i = 0; i < PCI_NUM_RESOURCES; i++) {
struct resource *r;
struct resource_list *list, *tmp;
- unsigned long r_align;
+ resource_size_t r_align;
r = &dev->resource[i];
r_align = r->end - r->start;
@@ -213,13 +218,14 @@ pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
continue;
if (!r_align) {
printk(KERN_WARNING "PCI: Ignore bogus resource %d "
- "[%lx:%lx] of %s\n",
- i, r->start, r->end, pci_name(dev));
+ "[%llx:%llx] of %s\n",
+ i, (unsigned long long)r->start,
+ (unsigned long long)r->end, pci_name(dev));
continue;
}
r_align = (i < PCI_BRIDGE_RESOURCES) ? r_align + 1 : r->start;
for (list = head; ; list = list->next) {
- unsigned long align = 0;
+ resource_size_t align = 0;
struct resource_list *ln = list->next;
int idx;
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 61cb4b29f55..35f88649d3b 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -6,7 +6,7 @@ menu "PCCARD (PCMCIA/CardBus) support"
config PCCARD
tristate "PCCard (PCMCIA/CardBus) support"
- select HOTPLUG
+ depends on HOTPLUG
---help---
Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
computer. These are credit-card size devices such as network cards,
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index a4d50940ebe..40569f40e90 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = {
/*--------------------------------------------------------------------------*/
-static int __init at91_cf_probe(struct device *dev)
+static int __init at91_cf_probe(struct platform_device *pdev)
{
struct at91_cf_socket *cf;
- struct at91_cf_data *board = dev->platform_data;
- struct platform_device *pdev = to_platform_device(dev);
+ struct at91_cf_data *board = pdev->dev.platform_data;
struct resource *io;
unsigned int csa;
int status;
@@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev)
cf->board = board;
cf->pdev = pdev;
- dev_set_drvdata(dev, cf);
+ platform_set_drvdata(pdev, cf);
/* CF takes over CS4, CS5, CS6 */
csa = at91_sys_read(AT91_EBI_CSA);
@@ -268,9 +267,10 @@ static int __init at91_cf_probe(struct device *dev)
/* must be a GPIO; ergo must trigger on both edges */
status = request_irq(board->det_pin, at91_cf_irq,
- SA_SAMPLE_RANDOM, driver_name, cf);
+ IRQF_SAMPLE_RANDOM, driver_name, cf);
if (status < 0)
goto fail0;
+ device_init_wakeup(&pdev->dev, 1);
/*
* The card driver will request this irq later as needed.
@@ -280,7 +280,7 @@ static int __init at91_cf_probe(struct device *dev)
*/
if (board->irq_pin) {
status = request_irq(board->irq_pin, at91_cf_irq,
- SA_SHIRQ, driver_name, cf);
+ IRQF_SHARED, driver_name, cf);
if (status < 0)
goto fail0a;
cf->socket.pci_irq = board->irq_pin;
@@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev)
board->det_pin, board->irq_pin);
cf->socket.owner = THIS_MODULE;
- cf->socket.dev.dev = dev;
+ cf->socket.dev.dev = &pdev->dev;
cf->socket.ops = &at91_cf_ops;
cf->socket.resource_ops = &pccard_static_ops;
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
@@ -323,21 +323,25 @@ fail1:
free_irq(board->irq_pin, cf);
fail0a:
free_irq(board->det_pin, cf);
+ device_init_wakeup(&pdev->dev, 0);
fail0:
at91_sys_write(AT91_EBI_CSA, csa);
kfree(cf);
return status;
}
-static int __exit at91_cf_remove(struct device *dev)
+static int __exit at91_cf_remove(struct platform_device *pdev)
{
- struct at91_cf_socket *cf = dev_get_drvdata(dev);
+ struct at91_cf_socket *cf = platform_get_drvdata(pdev);
+ struct at91_cf_data *board = cf->board;
struct resource *io = cf->socket.io[0].res;
unsigned int csa;
pcmcia_unregister_socket(&cf->socket);
- free_irq(cf->board->irq_pin, cf);
- free_irq(cf->board->det_pin, cf);
+ if (board->irq_pin)
+ free_irq(board->irq_pin, cf);
+ free_irq(board->det_pin, cf);
+ device_init_wakeup(&pdev->dev, 0);
iounmap((void __iomem *) cf->socket.io_offset);
release_mem_region(io->start, io->end + 1 - io->start);
@@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev)
return 0;
}
-static struct device_driver at91_cf_driver = {
- .name = (char *) driver_name,
- .bus = &platform_bus_type,
+#ifdef CONFIG_PM
+
+static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct at91_cf_socket *cf = platform_get_drvdata(pdev);
+ struct at91_cf_data *board = cf->board;
+
+ pcmcia_socket_dev_suspend(&pdev->dev, mesg);
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(board->det_pin);
+ else {
+ disable_irq_wake(board->det_pin);
+ disable_irq(board->det_pin);
+ }
+ if (board->irq_pin)
+ disable_irq(board->irq_pin);
+ return 0;
+}
+
+static int at91_cf_resume(struct platform_device *pdev)
+{
+ struct at91_cf_socket *cf = platform_get_drvdata(pdev);
+ struct at91_cf_data *board = cf->board;
+
+ if (board->irq_pin)
+ enable_irq(board->irq_pin);
+ if (!device_may_wakeup(&pdev->dev))
+ enable_irq(board->det_pin);
+ pcmcia_socket_dev_resume(&pdev->dev);
+ return 0;
+}
+
+#else
+#define at91_cf_suspend NULL
+#define at91_cf_resume NULL
+#endif
+
+static struct platform_driver at91_cf_driver = {
+ .driver = {
+ .name = (char *) driver_name,
+ .owner = THIS_MODULE,
+ },
.probe = at91_cf_probe,
.remove = __exit_p(at91_cf_remove),
- .suspend = pcmcia_socket_dev_suspend,
- .resume = pcmcia_socket_dev_resume,
+ .suspend = at91_cf_suspend,
+ .resume = at91_cf_resume,
};
/*--------------------------------------------------------------------------*/
static int __init at91_cf_init(void)
{
- return driver_register(&at91_cf_driver);
+ return platform_driver_register(&at91_cf_driver);
}
module_init(at91_cf_init);
static void __exit at91_cf_exit(void)
{
- driver_unregister(&at91_cf_driver);
+ platform_driver_unregister(&at91_cf_driver);
}
module_exit(at91_cf_exit);
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
index abc13f28ba3..74e051535d6 100644
--- a/drivers/pcmcia/au1000_db1x00.c
+++ b/drivers/pcmcia/au1000_db1x00.c
@@ -30,7 +30,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -296,7 +295,7 @@ struct pcmcia_low_level db1x00_pcmcia_ops = {
.socket_suspend = db1x00_socket_suspend
};
-int __init au1x_board_init(struct device *dev)
+int au1x_board_init(struct device *dev)
{
int ret = -ENODEV;
bcsr->pcmcia = 0; /* turn off power, if it's not already off */
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 971a3528164..d5dd0ce6553 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/cpufreq.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index f2c970b5f4f..1e467bb5407 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -22,7 +22,6 @@
#define __ASM_AU1000_PCMCIA_H
/* include the world */
-#include <linux/config.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index fd5522ede86..86c0808d6a0 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -21,7 +21,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 3162998579c..f9cd831a3f3 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -28,6 +28,7 @@
#include <linux/pm.h>
#include <linux/pci.h>
#include <linux/device.h>
+#include <linux/kthread.h>
#include <asm/system.h>
#include <asm/irq.h>
@@ -176,6 +177,7 @@ static int pccardd(void *__skt);
*/
int pcmcia_register_socket(struct pcmcia_socket *socket)
{
+ struct task_struct *tsk;
int ret;
if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
@@ -239,15 +241,18 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
mutex_init(&socket->skt_mutex);
spin_lock_init(&socket->thread_lock);
- ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
- if (ret < 0)
+ tsk = kthread_run(pccardd, socket, "pccardd");
+ if (IS_ERR(tsk)) {
+ ret = PTR_ERR(tsk);
goto err;
+ }
wait_for_completion(&socket->thread_done);
- if(!socket->thread) {
+ if (!socket->thread) {
printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket);
return -EIO;
}
+
pcmcia_parse_events(socket, SS_DETECT);
return 0;
@@ -272,10 +277,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops);
if (socket->thread) {
- init_completion(&socket->thread_done);
- socket->thread = NULL;
wake_up(&socket->thread_wait);
- wait_for_completion(&socket->thread_done);
+ kthread_stop(socket->thread);
}
release_cis_mem(socket);
@@ -630,8 +633,6 @@ static int pccardd(void *__skt)
DECLARE_WAITQUEUE(wait, current);
int ret;
- daemonize("pccardd");
-
skt->thread = current;
skt->socket = dead_socket;
skt->ops->init(skt);
@@ -643,7 +644,8 @@ static int pccardd(void *__skt)
printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
skt);
skt->thread = NULL;
- complete_and_exit(&skt->thread_done, 0);
+ complete(&skt->thread_done);
+ return 0;
}
add_wait_queue(&skt->thread_wait, &wait);
@@ -674,7 +676,7 @@ static int pccardd(void *__skt)
continue;
}
- if (!skt->thread)
+ if (kthread_should_stop())
break;
schedule();
@@ -688,7 +690,7 @@ static int pccardd(void *__skt)
/* remove from the device core */
class_device_unregister(&skt->dev);
- complete_and_exit(&skt->thread_done, 0);
+ return 0;
}
/*
@@ -697,11 +699,12 @@ static int pccardd(void *__skt)
*/
void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
{
+ unsigned long flags;
cs_dbg(s, 4, "parse_events: events %08x\n", events);
if (s->thread) {
- spin_lock(&s->thread_lock);
+ spin_lock_irqsave(&s->thread_lock, flags);
s->thread_events |= events;
- spin_unlock(&s->thread_lock);
+ spin_unlock_irqrestore(&s->thread_lock, flags);
wake_up(&s->thread_wait);
}
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index b39435bbfae..ad02629c8be 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -244,8 +244,8 @@ static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
hs_mapped_irq[irq].sock = sp;
/* insert ourselves as the irq controller */
- hs_mapped_irq[irq].old_handler = irq_desc[irq].handler;
- irq_desc[irq].handler = &hd64465_ss_irq_type;
+ hs_mapped_irq[irq].old_handler = irq_desc[irq].chip;
+ irq_desc[irq].chip = &hd64465_ss_irq_type;
}
@@ -260,7 +260,7 @@ static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
return;
/* restore the original irq controller */
- irq_desc[irq].handler = hs_mapped_irq[irq].old_handler;
+ irq_desc[irq].chip = hs_mapped_irq[irq].old_handler;
}
/*============================================================*/
@@ -761,7 +761,7 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp);
- if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0)
+ if ((err = request_irq(sp->irq, hs_interrupt, IRQF_DISABLED, MODNAME, sp)) < 0)
return err;
if (request_mem_region(sp->mem_base, sp->mem_length, MODNAME) == 0) {
sp->mem_base = 0;
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index d5f03a338c6..2163aa75a25 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -149,7 +149,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de
/* Register the interrupt handler */
dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq);
- if ((ret = request_irq(dev->irq, i82092aa_interrupt, SA_SHIRQ, "i82092aa", i82092aa_interrupt))) {
+ if ((ret = request_irq(dev->irq, i82092aa_interrupt, IRQF_SHARED, "i82092aa", i82092aa_interrupt))) {
printk(KERN_ERR "i82092aa: Failed to register IRQ %d, aborting\n", dev->irq);
goto err_out_free_res;
}
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index a2f05f48515..1cc2682394b 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -509,7 +509,7 @@ static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs)
static u_int __init test_irq(u_short sock, int irq)
{
debug(2, " testing ISA irq %d\n", irq);
- if (request_irq(irq, i365_count_irq, SA_PROBEIRQ, "scan",
+ if (request_irq(irq, i365_count_irq, IRQF_PROBE_SHARED, "scan",
i365_count_irq) != 0)
return 1;
irq_hits = 0; irq_sock = sock;
@@ -562,7 +562,7 @@ static u_int __init isa_scan(u_short sock, u_int mask0)
} else {
/* Fallback: just find interrupts that aren't in use */
for (i = 0; i < 16; i++)
- if ((mask0 & (1 << i)) && (_check_irq(i, SA_PROBEIRQ) == 0))
+ if ((mask0 & (1 << i)) && (_check_irq(i, IRQF_PROBE_SHARED) == 0))
mask1 |= (1 << i);
printk("default");
/* If scan failed, default to polled status */
@@ -726,7 +726,7 @@ static void __init add_pcic(int ns, int type)
u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
for (cs_irq = 15; cs_irq > 0; cs_irq--)
if ((cs_mask & (1 << cs_irq)) &&
- (_check_irq(cs_irq, SA_PROBEIRQ) == 0))
+ (_check_irq(cs_irq, IRQF_PROBE_SHARED) == 0))
break;
if (cs_irq) {
grab_irq = 1;
@@ -1084,9 +1084,10 @@ static int i365_set_mem_map(u_short sock, struct pccard_mem_map *mem)
u_short base, i;
u_char map;
- debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#lx-%#lx, "
+ debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, %#llx-%#llx, "
"%#x)\n", sock, mem->map, mem->flags, mem->speed,
- mem->res->start, mem->res->end, mem->card_start);
+ (unsigned long long)mem->res->start,
+ (unsigned long long)mem->res->end, mem->card_start);
map = mem->map;
if ((map > 4) || (mem->card_start > 0x3ffffff) ||
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 071cf485e1a..9e768eaef17 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/string.h>
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 70d5f0748d5..61d50b5620d 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/string.h>
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 0e07d953511..d0f68ab8f04 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -157,7 +157,7 @@ MODULE_LICENSE("Dual MPL/GPL");
static int pcmcia_schlvl = PCMCIA_SCHLVL;
-static spinlock_t events_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(events_lock);
#define PCMCIA_SOCKET_KEY_5V 1
@@ -644,7 +644,7 @@ static struct platform_device m8xx_device = {
};
static u32 pending_events[PCMCIA_SOCKETS_NO];
-static spinlock_t pending_event_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(pending_event_lock);
static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs)
{
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 2c23d758439..420e10aec0a 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -232,7 +232,7 @@ static int __init omap_cf_probe(struct device *dev)
dev_set_drvdata(dev, cf);
/* this primarily just shuts up irq handling noise */
- status = request_irq(irq, omap_cf_irq, SA_SHIRQ,
+ status = request_irq(irq, omap_cf_irq, IRQF_SHARED,
driver_name, cf);
if (status < 0)
goto fail0;
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 738b1ef595a..9ad18e62658 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -601,12 +601,8 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = CS_BAD_ARGS;
else {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->config.Function);
- if (p_dev == NULL)
- ret = CS_BAD_ARGS;
- else {
- ret = pccard_get_configuration_info(s, p_dev, &buf->config);
- pcmcia_put_dev(p_dev);
- }
+ ret = pccard_get_configuration_info(s, p_dev, &buf->config);
+ pcmcia_put_dev(p_dev);
}
break;
case DS_GET_FIRST_TUPLE:
@@ -636,12 +632,8 @@ static int ds_ioctl(struct inode * inode, struct file * file,
ret = CS_BAD_ARGS;
else {
struct pcmcia_device *p_dev = get_pcmcia_device(s, buf->status.Function);
- if (p_dev == NULL)
- ret = CS_BAD_ARGS;
- else {
- ret = pccard_get_status(s, p_dev, &buf->status);
- pcmcia_put_dev(p_dev);
- }
+ ret = pccard_get_status(s, p_dev, &buf->status);
+ pcmcia_put_dev(p_dev);
}
break;
case DS_VALIDATE_CIS:
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 3131bb0a009..c8323399e9e 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -245,10 +245,17 @@ int pccard_get_configuration_info(struct pcmcia_socket *s,
return CS_SUCCESS;
}
- /* !!! This is a hack !!! */
- memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
- config->Attributes |= CONF_VALID_CLIENT;
- config->CardValues = c->CardValues;
+ config->Attributes = c->Attributes | CONF_VALID_CLIENT;
+ config->Vcc = s->socket.Vcc;
+ config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ config->IntType = c->IntType;
+ config->ConfigBase = c->ConfigBase;
+ config->Status = c->Status;
+ config->Pin = c->Pin;
+ config->Copy = c->Copy;
+ config->Option = c->Option;
+ config->ExtStatus = c->ExtStatus;
+ config->Present = config->CardValues = c->CardValues;
config->IRQAttributes = c->irq.Attributes;
config->AssignedIRQ = s->irq.AssignedIRQ;
config->BasePort1 = c->io.BasePort1;
@@ -788,6 +795,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
struct pcmcia_socket *s = p_dev->socket;
config_t *c;
int ret = CS_IN_USE, irq = 0;
+ int type;
if (!(s->state & SOCKET_PRESENT))
return CS_NO_CARD;
@@ -797,6 +805,13 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
if (c->state & CONFIG_IRQ_REQ)
return CS_IN_USE;
+ /* Decide what type of interrupt we are registering */
+ type = 0;
+ if (s->functions > 1) /* All of this ought to be handled higher up */
+ type = IRQF_SHARED;
+ if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)
+ type = IRQF_SHARED;
+
#ifdef CONFIG_PCMCIA_PROBE
if (s->irq.AssignedIRQ != 0) {
/* If the interrupt is already assigned, it must be the same */
@@ -822,9 +837,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
* marked as used by the kernel resource management core */
ret = request_irq(irq,
(req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
- ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
- (s->functions > 1) ||
- (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+ type,
p_dev->devname,
(req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
if (!ret) {
@@ -839,18 +852,21 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
if (ret && !s->irq.AssignedIRQ) {
if (!s->pci_irq)
return ret;
+ type = IRQF_SHARED;
irq = s->pci_irq;
}
- if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
- if (request_irq(irq, req->Handler,
- ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
- (s->functions > 1) ||
- (irq == s->pci_irq)) ? SA_SHIRQ : 0,
- p_dev->devname, req->Instance))
+ if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) {
+ if (request_irq(irq, req->Handler, type, p_dev->devname, req->Instance))
return CS_IN_USE;
}
+ /* Make sure the fact the request type was overridden is passed back */
+ if (type == IRQF_SHARED && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
+ req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
+ printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n");
+ printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n");
+ }
c->irq.Attributes = req->Attributes;
s->irq.AssignedIRQ = req->AssignedIRQ = irq;
s->irq.Config++;
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 247ab837f84..22c5e7427dd 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -642,7 +642,8 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
goto err_out_free_mem;
printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge "
- "at 0x%lx on irq %d\n", pci_resource_start(dev, 0), dev->irq);
+ "at 0x%llx on irq %d\n",
+ (unsigned long long)pci_resource_start(dev, 0), dev->irq);
/*
* Since we have no memory BARs some firmware may not
* have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
@@ -688,7 +689,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
pci_set_drvdata(dev, socket);
if (irq_mode == 1) {
/* Register the interrupt handler */
- if ((ret = request_irq(dev->irq, pd6729_interrupt, SA_SHIRQ,
+ if ((ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,
"pd6729", socket))) {
printk(KERN_ERR "pd6729: Failed to register irq %d, "
"aborting\n", dev->irq);
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 7fa18fb814b..b3518131ea0 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -18,7 +18,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/cpufreq.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 0f8b157c971..c3176b16b7b 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -72,7 +72,7 @@ static DEFINE_MUTEX(rsrc_mutex);
======================================================================*/
static struct resource *
-make_resource(unsigned long b, unsigned long n, int flags, char *name)
+make_resource(resource_size_t b, resource_size_t n, int flags, char *name)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
@@ -86,8 +86,8 @@ make_resource(unsigned long b, unsigned long n, int flags, char *name)
}
static struct resource *
-claim_region(struct pcmcia_socket *s, unsigned long base, unsigned long size,
- int type, char *name)
+claim_region(struct pcmcia_socket *s, resource_size_t base,
+ resource_size_t size, int type, char *name)
{
struct resource *res, *parent;
@@ -519,10 +519,10 @@ struct pcmcia_align_data {
static void
pcmcia_common_align(void *align_data, struct resource *res,
- unsigned long size, unsigned long align)
+ resource_size_t size, resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
- unsigned long start;
+ resource_size_t start;
/*
* Ensure that we have the correct start address
*/
@@ -533,8 +533,8 @@ pcmcia_common_align(void *align_data, struct resource *res,
}
static void
-pcmcia_align(void *align_data, struct resource *res,
- unsigned long size, unsigned long align)
+pcmcia_align(void *align_data, struct resource *res, resource_size_t size,
+ resource_size_t align)
{
struct pcmcia_align_data *data = align_data;
struct resource_map *m;
@@ -808,8 +808,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
if (res->flags & IORESOURCE_IO) {
if (res == &ioport_resource)
continue;
- printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
- res->start, res->end);
+ printk(KERN_INFO "pcmcia: parent PCI bridge I/O "
+ "window: 0x%llx - 0x%llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)res->end);
if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
done |= IORESOURCE_IO;
@@ -818,8 +820,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
if (res->flags & IORESOURCE_MEM) {
if (res == &iomem_resource)
continue;
- printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
- res->start, res->end);
+ printk(KERN_INFO "pcmcia: parent PCI bridge Memory "
+ "window: 0x%llx - 0x%llx\n",
+ (unsigned long long)res->start,
+ (unsigned long long)res->end);
if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
done |= IORESOURCE_MEM;
}
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index 6d441ec75c6..c5b2a44b4c3 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/platform_device.h>
#include <pcmcia/cs_types.h>
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index 81ded52c895..658cddfbcf2 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -5,7 +5,6 @@
* basically means we handle everything except controlling the
* power. Power is machine specific...
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index 59c5d968e9f..31a7abc55b2 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/config.h>
#include <linux/cpufreq.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index ea7d9ca160b..ecaa132fa59 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -31,7 +31,6 @@
======================================================================*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -39,12 +38,12 @@
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/spinlock.h>
#include <linux/cpufreq.h>
#include <asm/hardware.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/system.h>
#include "soc_common.h"
@@ -524,7 +523,7 @@ int soc_pcmcia_request_irqs(struct soc_pcmcia_socket *skt,
if (irqs[i].sock != skt->nr)
continue;
res = request_irq(irqs[i].irq, soc_common_pcmcia_interrupt,
- SA_INTERRUPT, irqs[i].str, skt);
+ IRQF_DISABLED, irqs[i].str, skt);
if (res)
break;
set_irq_type(irqs[i].irq, IRQT_NOEDGE);
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 73bad1d5cb2..65a60671659 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -756,8 +756,9 @@ static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *m
u_long base, len, mmap;
debug(1, "SetMemMap(%d, %d, %#2.2x, %d ns, "
- "%#lx-%#lx, %#x)\n", psock, mem->map, mem->flags,
- mem->speed, mem->res->start, mem->res->end, mem->card_start);
+ "%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,
+ mem->speed, (unsigned long long)mem->res->start,
+ (unsigned long long)mem->res->end, mem->card_start);
if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
(mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
(mem->res->start > mem->res->end) || (mem->speed > 1000))
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index 7a3d1b8e16b..62e9ebf967f 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -647,6 +647,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket)
*/
break;
+ case PCI_DEVICE_ID_TI_XX12:
case PCI_DEVICE_ID_TI_X515:
case PCI_DEVICE_ID_TI_X420:
case PCI_DEVICE_ID_TI_X620:
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index 459e6e1946f..e076a13db55 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -730,7 +730,7 @@ static int __devinit vrc4171_card_init(void)
retval = vrc4171_add_sockets();
if (retval == 0)
- retval = request_irq(vrc4171_irq, pccard_interrupt, SA_SHIRQ,
+ retval = request_irq(vrc4171_irq, pccard_interrupt, IRQF_SHARED,
vrc4171_card_name, vrc4171_sockets);
if (retval < 0) {
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index 6004196f7cc..d19a9138135 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -500,7 +500,7 @@ static int __devinit vrc4173_cardu_probe(struct pci_dev *dev,
return -ENOMEM;
}
- if (request_irq(dev->irq, cardu_interrupt, SA_SHIRQ, socket->name, socket) < 0) {
+ if (request_irq(dev->irq, cardu_interrupt, IRQF_SHARED, socket->name, socket) < 0) {
pcmcia_unregister_socket(socket->pcmcia_socket);
socket->pcmcia_socket = NULL;
iounmap(socket->base);
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 4145eb83b9b..1344746381e 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -287,7 +287,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
u16 bridge;
- yenta_set_power(socket, state);
+ /* if powering down: do it immediately */
+ if (state->Vcc == 0)
+ yenta_set_power(socket, state);
+
socket->io_irq = state->io_irq;
bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR);
if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
@@ -339,6 +342,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
/* Socket event mask: get card insert/remove events.. */
cb_writel(socket, CB_SOCKET_EVENT, -1);
cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK);
+
+ /* if powering up: do it as the last step when the socket is configured */
+ if (state->Vcc != 0)
+ yenta_set_power(socket, state);
return 0;
}
@@ -916,7 +923,7 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket)
socket->probe_status = 0;
- if (request_irq(socket->cb_irq, yenta_probe_handler, SA_SHIRQ, "yenta", socket)) {
+ if (request_irq(socket->cb_irq, yenta_probe_handler, IRQF_SHARED, "yenta", socket)) {
printk(KERN_WARNING "Yenta: request_irq() in yenta_probe_cb_irq() failed!\n");
return -1;
}
@@ -998,6 +1005,77 @@ static void yenta_config_init(struct yenta_socket *socket)
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
}
+/**
+ * yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge
+ * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to
+ *
+ * Checks if devices on the bus which the CardBus bridge bridges to would be
+ * invisible during PCI scans because of a misconfigured subordinate number
+ * of the parent brige - some BIOSes seem to be too lazy to set it right.
+ * Does the fixup carefully by checking how far it can go without conflicts.
+ * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
+ */
+static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
+{
+ struct list_head *tmp;
+ unsigned char upper_limit;
+ /*
+ * We only check and fix the parent bridge: All systems which need
+ * this fixup that have been reviewed are laptops and the only bridge
+ * which needed fixing was the parent bridge of the CardBus bridge:
+ */
+ struct pci_bus *bridge_to_fix = cardbus_bridge->parent;
+
+ /* Check bus numbers are already set up correctly: */
+ if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate)
+ return; /* The subordinate number is ok, nothing to do */
+
+ if (!bridge_to_fix->parent)
+ return; /* Root bridges are ok */
+
+ /* stay within the limits of the bus range of the parent: */
+ upper_limit = bridge_to_fix->parent->subordinate;
+
+ /* check the bus ranges of all silbling bridges to prevent overlap */
+ list_for_each(tmp, &bridge_to_fix->parent->children) {
+ struct pci_bus * silbling = pci_bus_b(tmp);
+ /*
+ * If the silbling has a higher secondary bus number
+ * and it's secondary is equal or smaller than our
+ * current upper limit, set the new upper limit to
+ * the bus number below the silbling's range:
+ */
+ if (silbling->secondary > bridge_to_fix->subordinate
+ && silbling->secondary <= upper_limit)
+ upper_limit = silbling->secondary - 1;
+ }
+
+ /* Show that the wanted subordinate number is not possible: */
+ if (cardbus_bridge->subordinate > upper_limit)
+ printk(KERN_WARNING "Yenta: Upper limit for fixing this "
+ "bridge's parent bridge: #%02x\n", upper_limit);
+
+ /* If we have room to increase the bridge's subordinate number, */
+ if (bridge_to_fix->subordinate < upper_limit) {
+
+ /* use the highest number of the hidden bus, within limits */
+ unsigned char subordinate_to_assign =
+ min(cardbus_bridge->subordinate, upper_limit);
+
+ printk(KERN_INFO "Yenta: Raising subordinate bus# of parent "
+ "bus (#%02x) from #%02x to #%02x\n",
+ bridge_to_fix->number,
+ bridge_to_fix->subordinate, subordinate_to_assign);
+
+ /* Save the new subordinate in the bus struct of the bridge */
+ bridge_to_fix->subordinate = subordinate_to_assign;
+
+ /* and update the PCI config space with the new subordinate */
+ pci_write_config_byte(bridge_to_fix->self,
+ PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate);
+ }
+}
+
/*
* Initialize a cardbus controller. Make sure we have a usable
* interrupt, and that we can map the cardbus area. Fill in the
@@ -1094,7 +1172,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
/* We must finish initialization here */
- if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, SA_SHIRQ, "yenta", socket)) {
+ if (!socket->cb_irq || request_irq(socket->cb_irq, yenta_interrupt, IRQF_SHARED, "yenta", socket)) {
/* No IRQ or request_irq failed. Poll */
socket->cb_irq = 0; /* But zero is a valid IRQ number. */
init_timer(&socket->poll_timer);
@@ -1113,6 +1191,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
yenta_get_socket_capabilities(socket, isa_interrupts);
printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
+ yenta_fixup_parent_bridge(dev->subordinate);
+
/* Register it with the pcmcia layer.. */
ret = pcmcia_register_socket(&socket->socket);
if (ret == 0) {
@@ -1232,6 +1312,7 @@ static struct pci_device_id yenta_table [] = {
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX),
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX),
+ CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12, TI12XX),
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX),
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX),
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX),
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index bb19c64073c..227600cd636 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pnp.h>
@@ -60,30 +59,34 @@ static void card_remove_first(struct pnp_dev * dev)
card_remove(dev);
}
-static int card_probe(struct pnp_card * card, struct pnp_card_driver * drv)
+static int card_probe(struct pnp_card *card, struct pnp_card_driver *drv)
{
- const struct pnp_card_device_id *id = match_card(drv,card);
- if (id) {
- struct pnp_card_link * clink = pnp_alloc(sizeof(struct pnp_card_link));
- if (!clink)
- return 0;
- clink->card = card;
- clink->driver = drv;
- clink->pm_state = PMSG_ON;
- if (drv->probe) {
- if (drv->probe(clink, id)>=0)
- return 1;
- else {
- struct pnp_dev * dev;
- card_for_each_dev(card, dev) {
- if (dev->card_link == clink)
- pnp_release_card_device(dev);
- }
- kfree(clink);
- }
- } else
- return 1;
+ const struct pnp_card_device_id *id;
+ struct pnp_card_link *clink;
+ struct pnp_dev *dev;
+
+ if (!drv->probe)
+ return 0;
+ id = match_card(drv,card);
+ if (!id)
+ return 0;
+
+ clink = pnp_alloc(sizeof(*clink));
+ if (!clink)
+ return 0;
+ clink->card = card;
+ clink->driver = drv;
+ clink->pm_state = PMSG_ON;
+
+ if (drv->probe(clink, id) >= 0)
+ return 1;
+
+ /* Recovery */
+ card_for_each_dev(card, dev) {
+ if (dev->card_link == clink)
+ pnp_release_card_device(dev);
}
+ kfree(clink);
return 0;
}
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e54c1538319..e161423b430 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/module.h>
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index a2d8ce7fef9..9d8b415eca7 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -264,9 +264,9 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
pnp_printf(buffer," disabled\n");
else
- pnp_printf(buffer," 0x%lx-0x%lx\n",
- pnp_port_start(dev, i),
- pnp_port_end(dev, i));
+ pnp_printf(buffer," 0x%llx-0x%llx\n",
+ (unsigned long long)pnp_port_start(dev, i),
+ (unsigned long long)pnp_port_end(dev, i));
}
}
for (i = 0; i < PNP_MAX_MEM; i++) {
@@ -275,9 +275,9 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
pnp_printf(buffer," disabled\n");
else
- pnp_printf(buffer," 0x%lx-0x%lx\n",
- pnp_mem_start(dev, i),
- pnp_mem_end(dev, i));
+ pnp_printf(buffer," 0x%llx-0x%llx\n",
+ (unsigned long long)pnp_mem_start(dev, i),
+ (unsigned long long)pnp_mem_end(dev, i));
}
}
for (i = 0; i < PNP_MAX_IRQ; i++) {
@@ -286,8 +286,8 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
pnp_printf(buffer," disabled\n");
else
- pnp_printf(buffer," %ld\n",
- pnp_irq(dev, i));
+ pnp_printf(buffer," %lld\n",
+ (unsigned long long)pnp_irq(dev, i));
}
}
for (i = 0; i < PNP_MAX_DMA; i++) {
@@ -296,8 +296,8 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, struct device_at
if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
pnp_printf(buffer," disabled\n");
else
- pnp_printf(buffer," %ld\n",
- pnp_dma(dev, i));
+ pnp_printf(buffer," %lld\n",
+ (unsigned long long)pnp_dma(dev, i));
}
}
ret = (buffer->curr - buf);
diff --git a/drivers/pnp/isapnp/compat.c b/drivers/pnp/isapnp/compat.c
index 3ff7e76b33b..0697ab88a9a 100644
--- a/drivers/pnp/isapnp/compat.c
+++ b/drivers/pnp/isapnp/compat.c
@@ -8,7 +8,6 @@
/* TODO: see if more isapnp functions are needed here */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/isapnp.h>
#include <linux/string.h>
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index ac7c2bb6c69..f2e0179962e 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -34,7 +34,6 @@
* 2003-08-11 Resource Management Updates - Adam Belay <ambx1@neo.rr.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index cf54b0a3628..958c11bedd0 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/isapnp.h>
#include <linux/proc_fs.h>
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 6fff109bdab..5026b345cb3 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -6,7 +6,6 @@
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -20,7 +19,8 @@ DECLARE_MUTEX(pnp_res_mutex);
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
- unsigned long *start, *end, *flags;
+ resource_size_t *start, *end;
+ unsigned long *flags;
if (!dev || !rule)
return -EINVAL;
@@ -63,7 +63,8 @@ static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
- unsigned long *start, *end, *flags;
+ resource_size_t *start, *end;
+ unsigned long *flags;
if (!dev || !rule)
return -EINVAL;
@@ -116,7 +117,8 @@ static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
{
- unsigned long *start, *end, *flags;
+ resource_size_t *start, *end;
+ unsigned long *flags;
int i;
/* IRQ priority: this table is good for i386 */
@@ -168,7 +170,8 @@ static int pnp_assign_irq(struct pnp_dev * dev, struct pnp_irq *rule, int idx)
static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
- unsigned long *start, *end, *flags;
+ resource_size_t *start, *end;
+ unsigned long *flags;
int i;
/* DMA priority: this table is good for i386 */
@@ -582,7 +585,8 @@ int pnp_disable_dev(struct pnp_dev *dev)
* @size: size of region
*
*/
-void pnp_resource_change(struct resource *resource, unsigned long start, unsigned long size)
+void pnp_resource_change(struct resource *resource, resource_size_t start,
+ resource_size_t size)
{
if (resource == NULL)
return;
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index f104577f73e..6cf34a63c79 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/acpi.h>
#include <linux/pnp.h>
#include <acpi/acpi_bus.h>
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 3a4a644c268..dc79b0a0059 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -74,7 +74,7 @@ static void decode_irq_flags(int flag, int *triggering, int *polarity)
static void
pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
- int triggering, int polarity)
+ int triggering, int polarity, int shareable)
{
int i = 0;
int irq;
@@ -95,6 +95,9 @@ pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res, u32 gsi,
return;
}
+ if (shareable)
+ res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
+
res->irq_resource[i].start = irq;
res->irq_resource[i].end = irq;
pcibios_penalize_isa_irq(irq, 1);
@@ -170,6 +173,9 @@ pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
return;
}
+ if (p->producer_consumer == ACPI_PRODUCER)
+ return;
+
if (p->resource_type == ACPI_MEMORY_RANGE)
pnpacpi_parse_allocated_memresource(res_table,
p->minimum, p->address_length);
@@ -194,7 +200,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
pnpacpi_parse_allocated_irqresource(res_table,
res->data.irq.interrupts[i],
res->data.irq.triggering,
- res->data.irq.polarity);
+ res->data.irq.polarity,
+ res->data.irq.sharable);
}
break;
@@ -248,14 +255,20 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+ if (res->data.ext_address64.producer_consumer == ACPI_PRODUCER)
+ return AE_OK;
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER)
+ return AE_OK;
+
for (i = 0; i < res->data.extended_irq.interrupt_count; i++) {
pnpacpi_parse_allocated_irqresource(res_table,
res->data.extended_irq.interrupts[i],
res->data.extended_irq.triggering,
- res->data.extended_irq.polarity);
+ res->data.extended_irq.polarity,
+ res->data.extended_irq.sharable);
}
break;
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index b154b3f52cb..551f58e2981 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -346,7 +346,7 @@ static int insert_device(struct pnp_dev *dev, struct pnp_bios_node * node)
dev->flags = node->flags;
if (!(dev->flags & PNPBIOS_NO_CONFIG))
dev->capabilities |= PNP_CONFIGURABLE;
- if (!(dev->flags & PNPBIOS_NO_DISABLE))
+ if (!(dev->flags & PNPBIOS_NO_DISABLE) && pnpbios_is_dynamic(dev))
dev->capabilities |= PNP_DISABLE;
dev->capabilities |= PNP_READ;
if (pnpbios_is_dynamic(dev))
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index c89c98a2cca..ef508a4de55 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -3,7 +3,6 @@
*
*/
-#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/pnp.h>
#include <linux/pnpbios.h>
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 8936b0cb2ec..e97ecefe858 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -11,7 +11,6 @@
* Copyright (c) 1999 Martin Mares <mj@ucw.cz>
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 6ded527169f..5c8ec21e108 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -6,7 +6,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@@ -241,7 +240,7 @@ int pnp_check_port(struct pnp_dev * dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
- unsigned long *port, *end, *tport, *tend;
+ resource_size_t *port, *end, *tport, *tend;
port = &dev->res.port_resource[idx].start;
end = &dev->res.port_resource[idx].end;
@@ -297,7 +296,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
- unsigned long *addr, *end, *taddr, *tend;
+ resource_size_t *addr, *end, *taddr, *tend;
addr = &dev->res.mem_resource[idx].start;
end = &dev->res.mem_resource[idx].end;
@@ -358,7 +357,7 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
{
int tmp;
struct pnp_dev *tdev;
- unsigned long * irq = &dev->res.irq_resource[idx].start;
+ resource_size_t * irq = &dev->res.irq_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (cannot_compare(dev->res.irq_resource[idx].flags))
@@ -396,7 +395,8 @@ int pnp_check_irq(struct pnp_dev * dev, int idx)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if(!dev->active) {
- if (request_irq(*irq, pnp_test_handler, SA_INTERRUPT, "pnp", NULL))
+ if (request_irq(*irq, pnp_test_handler,
+ IRQF_DISABLED|IRQF_PROBE_SHARED, "pnp", NULL))
return 0;
free_irq(*irq, NULL);
}
@@ -423,7 +423,7 @@ int pnp_check_dma(struct pnp_dev * dev, int idx)
#ifndef CONFIG_IA64
int tmp;
struct pnp_dev *tdev;
- unsigned long * dma = &dev->res.dma_resource[idx].start;
+ resource_size_t * dma = &dev->res.dma_resource[idx].start;
/* if the resource doesn't exist, don't complain about it */
if (cannot_compare(dev->res.dma_resource[idx].flags))
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 61fe998944b..946a0dcd627 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -5,7 +5,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/ctype.h>
#include <linux/pnp.h>
diff --git a/drivers/rapidio/rio-access.c b/drivers/rapidio/rio-access.c
index b9fab2ae3a3..8b56bbdd011 100644
--- a/drivers/rapidio/rio-access.c
+++ b/drivers/rapidio/rio-access.c
@@ -17,8 +17,8 @@
* These interrupt-safe spinlocks protect all accesses to RIO
* configuration space and doorbell access.
*/
-static spinlock_t rio_config_lock = SPIN_LOCK_UNLOCKED;
-static spinlock_t rio_doorbell_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rio_config_lock);
+static DEFINE_SPINLOCK(rio_doorbell_lock);
/*
* Wrappers for all RIO configuration access functions. They just check
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 94e30fe4b8f..7bf7b2c8824 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index bef9316e95d..5687b8fcbf9 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -10,7 +10,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/rio.h>
#include <linux/rio_drv.h>
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index 5e382470faa..f644807da2f 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -11,7 +11,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 65d090dbef4..62c804af9fb 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -15,7 +15,7 @@ config RTC_CLASS
help
Generic RTC class support. If you say yes here, you will
be allowed to plug one or more RTCs to your system. You will
- probably want to enable one of more of the interfaces below.
+ probably want to enable one or more of the interfaces below.
This driver can also be built as a module. If so, the module
will be called rtc-class.
@@ -27,7 +27,7 @@ config RTC_HCTOSYS
help
If you say yes here, the system time will be set using
the value read from the specified RTC device. This is useful
- in order to avoid unnecessary fschk runs.
+ in order to avoid unnecessary fsck runs.
config RTC_HCTOSYS_DEVICE
string "The RTC to read the time from"
@@ -73,6 +73,13 @@ config RTC_INTF_DEV
This driver can also be built as a module. If so, the module
will be called rtc-dev.
+config RTC_INTF_DEV_UIE_EMUL
+ bool "RTC UIE emulation on dev interface"
+ depends on RTC_INTF_DEV
+ help
+ Provides an emulation for RTC_UIE if the underlaying rtc chip
+ driver did not provide RTC_UIE ioctls.
+
comment "RTC drivers"
depends on RTC_CLASS
@@ -86,6 +93,44 @@ config RTC_DRV_X1205
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
+config RTC_DRV_DS1307
+ tristate "Dallas/Maxim DS1307 and similar I2C RTC chips"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for various compatible RTC
+ chips (often with battery backup) connected with I2C. This driver
+ should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
+ and probably other chips. In some cases the RTC must already
+ have been initialized (by manufacturing or a bootloader).
+
+ The first seven registers on these chips hold an RTC, and other
+ registers may add features such as NVRAM, a trickle charger for
+ the RTC/NVRAM backup power, and alarms. This driver may not
+ expose all those available chip features.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1307.
+
+config RTC_DRV_DS1553
+ tristate "Dallas DS1553"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Dallas DS1553 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1553.
+
+config RTC_DRV_ISL1208
+ tristate "Intersil 1208"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for the
+ Intersil 1208 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-isl1208.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
depends on RTC_CLASS && I2C
@@ -96,6 +141,16 @@ config RTC_DRV_DS1672
This driver can also be built as a module. If so, the module
will be called rtc-ds1672.
+config RTC_DRV_DS1742
+ tristate "Dallas DS1742"
+ depends on RTC_CLASS
+ help
+ If you say yes here you get support for the
+ Dallas DS1742 timekeeping chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1742.
+
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
depends on RTC_CLASS && I2C
@@ -107,6 +162,26 @@ config RTC_DRV_PCF8563
This driver can also be built as a module. If so, the module
will be called rtc-pcf8563.
+config RTC_DRV_PCF8583
+ tristate "Philips PCF8583"
+ depends on RTC_CLASS && I2C
+ help
+ If you say yes here you get support for the
+ Philips PCF8583 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf8583.
+
+config RTC_DRV_RS5C348
+ tristate "Ricoh RS5C348A/B"
+ depends on RTC_CLASS && SPI
+ help
+ If you say yes here you get support for the
+ Ricoh RS5C348A and RS5C348B RTC chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rs5c348.
+
config RTC_DRV_RS5C372
tristate "Ricoh RS5C372A/B"
depends on RTC_CLASS && I2C
@@ -117,6 +192,22 @@ config RTC_DRV_RS5C372
This driver can also be built as a module. If so, the module
will be called rtc-rs5c372.
+config RTC_DRV_S3C
+ tristate "Samsung S3C series SoC RTC"
+ depends on RTC_CLASS && ARCH_S3C2410
+ help
+ RTC (Realtime Clock) driver for the clock inbuilt into the
+ Samsung S3C24XX series of SoCs. This can provide periodic
+ interrupt rates from 1Hz to 64Hz for user programs, and
+ wakeup from Alarm.
+
+ The driver currently supports the common features on all the
+ S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440
+ and S3C2442.
+
+ This driver can also be build as a module. If so, the module
+ will be called rtc-s3c.
+
config RTC_DRV_M48T86
tristate "ST M48T86/Dallas DS12887"
depends on RTC_CLASS
@@ -147,6 +238,16 @@ config RTC_DRV_SA1100
To compile this driver as a module, choose M here: the
module will be called rtc-sa1100.
+config RTC_DRV_SH
+ tristate "SuperH On-Chip RTC"
+ depends on RTC_CLASS && SUPERH
+ help
+ Say Y here to enable support for the on-chip RTC found in
+ most SuperH processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-sh.
+
config RTC_DRV_VR41XX
tristate "NEC VR41XX"
depends on RTC_CLASS && CPU_VR41XX
@@ -157,6 +258,22 @@ config RTC_DRV_VR41XX
To compile this driver as a module, choose M here: the
module will be called rtc-vr41xx.
+config RTC_DRV_PL031
+ tristate "ARM AMBA PL031 RTC"
+ depends on RTC_CLASS && ARM_AMBA
+ help
+ If you say Y here you will get access to ARM AMBA
+ PrimeCell PL031 UART found on certain ARM SOCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-pl031.
+
+config RTC_DRV_AT91
+ tristate "AT91RM9200"
+ depends on RTC_CLASS && ARCH_AT91RM9200
+ help
+ Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
+
config RTC_DRV_TEST
tristate "Test driver/device"
depends on RTC_CLASS
@@ -172,4 +289,24 @@ config RTC_DRV_TEST
This driver can also be built as a module. If so, the module
will be called rtc-test.
+config RTC_DRV_MAX6902
+ tristate "Maxim 6902"
+ depends on RTC_CLASS && SPI
+ help
+ If you say yes here you will get support for the
+ Maxim MAX6902 spi RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max6902.
+
+config RTC_DRV_V3020
+ tristate "EM Microelectronic V3020"
+ depends on RTC_CLASS
+ help
+ If you say yes here you will get support for the
+ EM Microelectronic v3020 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-v3020.
+
endmenu
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index a9ca0f17168..e72d467ab21 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -12,11 +12,23 @@ obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o
obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
+obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
+obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
+obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
+obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
+obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
+obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o
+obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 413c7d54ea1..1cb61a761cb 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -69,6 +69,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
rtc->id = id;
rtc->ops = ops;
rtc->owner = owner;
+ rtc->max_user_freq = 64;
rtc->class_dev.dev = dev;
rtc->class_dev.class = rtc_class;
rtc->class_dev.release = rtc_device_release;
@@ -93,7 +94,9 @@ exit_kfree:
kfree(rtc);
exit_idr:
+ mutex_lock(&idr_lock);
idr_remove(&rtc_idr, id);
+ mutex_unlock(&idr_lock);
exit:
dev_err(dev, "rtc core: unable to register %s, err = %d\n",
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 56e490709b8..579cd667b16 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -229,6 +229,9 @@ int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(class_dev);
+ if (rtc->ops->irq_set_state == NULL)
+ return -ENXIO;
+
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != task)
err = -ENXIO;
@@ -243,25 +246,12 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_state);
int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
{
- int err = 0, tmp = 0;
+ int err = 0;
unsigned long flags;
struct rtc_device *rtc = to_rtc_device(class_dev);
- /* allowed range is 2-8192 */
- if (freq < 2 || freq > 8192)
- return -EINVAL;
-/*
- FIXME: this does not belong here, will move where appropriate
- at a later stage. It cannot hurt right now, trust me :)
- if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
- return -EACCES;
-*/
- /* check if freq is a power of 2 */
- while (freq > (1 << tmp))
- tmp++;
-
- if (freq != (1 << tmp))
- return -EINVAL;
+ if (rtc->ops->irq_set_freq == NULL)
+ return -ENXIO;
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != task)
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c
new file mode 100644
index 00000000000..dfd0ce86f6a
--- /dev/null
+++ b/drivers/rtc/rtc-at91.c
@@ -0,0 +1,407 @@
+/*
+ * Real Time Clock interface for Linux on Atmel AT91RM9200
+ *
+ * Copyright (C) 2002 Rick Bronson
+ *
+ * Converted to RTC class model by Andrew Victor
+ *
+ * Ported to Linux 2.6 by Steven Scholz
+ * Based on s3c2410-rtc.c Simtec Electronics
+ *
+ * Based on sa1100-rtc.c by Nils Faerber
+ * Based on rtc.c by Paul Gortmaker
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+
+#define AT91_RTC_FREQ 1
+#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
+
+static DECLARE_COMPLETION(at91_rtc_updated);
+static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
+
+/*
+ * Decode time/date into rtc_time structure
+ */
+static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
+ struct rtc_time *tm)
+{
+ unsigned int time, date;
+
+ /* must read twice in case it changes */
+ do {
+ time = at91_sys_read(timereg);
+ date = at91_sys_read(calreg);
+ } while ((time != at91_sys_read(timereg)) ||
+ (date != at91_sys_read(calreg)));
+
+ tm->tm_sec = BCD2BIN((time & AT91_RTC_SEC) >> 0);
+ tm->tm_min = BCD2BIN((time & AT91_RTC_MIN) >> 8);
+ tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);
+
+ /*
+ * The Calendar Alarm register does not have a field for
+ * the year - so these will return an invalid value. When an
+ * alarm is set, at91_alarm_year wille store the current year.
+ */
+ tm->tm_year = BCD2BIN(date & AT91_RTC_CENT) * 100; /* century */
+ tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8); /* year */
+
+ tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */
+ tm->tm_mon = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
+ tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
+}
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+ at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm);
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year = tm->tm_year - 1900;
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long cr;
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* Stop Time/Calendar from counting */
+ cr = at91_sys_read(AT91_RTC_CR);
+ at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
+
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
+ wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+
+ at91_sys_write(AT91_RTC_TIMR,
+ BIN2BCD(tm->tm_sec) << 0
+ | BIN2BCD(tm->tm_min) << 8
+ | BIN2BCD(tm->tm_hour) << 16);
+
+ at91_sys_write(AT91_RTC_CALR,
+ BIN2BCD((tm->tm_year + 1900) / 100) /* century */
+ | BIN2BCD(tm->tm_year % 100) << 8 /* year */
+ | BIN2BCD(tm->tm_mon + 1) << 16 /* tm_mon starts at zero */
+ | BIN2BCD(tm->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */
+ | BIN2BCD(tm->tm_mday) << 24);
+
+ /* Restart Time/Calendar */
+ cr = at91_sys_read(AT91_RTC_CR);
+ at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
+
+ return 0;
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time *tm = &alrm->time;
+
+ at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_year = at91_alarm_year - 1900;
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+/*
+ * Set alarm time and date in RTC
+ */
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time tm;
+
+ at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
+
+ at91_alarm_year = tm.tm_year;
+
+ tm.tm_hour = alrm->time.tm_hour;
+ tm.tm_min = alrm->time.tm_min;
+ tm.tm_sec = alrm->time.tm_sec;
+
+ at91_sys_write(AT91_RTC_TIMALR,
+ BIN2BCD(tm.tm_sec) << 0
+ | BIN2BCD(tm.tm_min) << 8
+ | BIN2BCD(tm.tm_hour) << 16
+ | AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
+ at91_sys_write(AT91_RTC_CALALR,
+ BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */
+ | BIN2BCD(tm.tm_mday) << 24
+ | AT91_RTC_DATEEN | AT91_RTC_MTHEN);
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+ tm.tm_min, tm.tm_sec);
+
+ return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = 0;
+
+ pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
+
+ switch (cmd) {
+ case RTC_AIE_OFF: /* alarm off */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+ break;
+ case RTC_AIE_ON: /* alarm on */
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
+ break;
+ case RTC_UIE_OFF: /* update off */
+ case RTC_PIE_OFF: /* periodic off */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
+ break;
+ case RTC_UIE_ON: /* update on */
+ case RTC_PIE_ON: /* periodic on */
+ at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
+ break;
+ case RTC_IRQP_READ: /* read periodic alarm frequency */
+ ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
+ break;
+ case RTC_IRQP_SET: /* set periodic alarm frequency */
+ if (arg != AT91_RTC_FREQ)
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ unsigned long imr = at91_sys_read(AT91_RTC_IMR);
+
+ seq_printf(seq, "alarm_IRQ\t: %s\n",
+ (imr & AT91_RTC_ALARM) ? "yes" : "no");
+ seq_printf(seq, "update_IRQ\t: %s\n",
+ (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
+ seq_printf(seq, "periodic_IRQ\t: %s\n",
+ (imr & AT91_RTC_SECEV) ? "yes" : "no");
+ seq_printf(seq, "periodic_freq\t: %ld\n",
+ (unsigned long) AT91_RTC_FREQ);
+
+ return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+ unsigned int rtsr;
+ unsigned long events = 0;
+
+ rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR);
+ if (rtsr) { /* this interrupt is shared! Is it ours? */
+ if (rtsr & AT91_RTC_ALARM)
+ events |= (RTC_AF | RTC_IRQF);
+ if (rtsr & AT91_RTC_SECEV)
+ events |= (RTC_UF | RTC_IRQF);
+ if (rtsr & AT91_RTC_ACKUPD)
+ complete(&at91_rtc_updated);
+
+ at91_sys_write(AT91_RTC_SCCR, rtsr); /* clear status reg */
+
+ rtc_update_irq(&rtc->class_dev, 1, events);
+
+ pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
+ events >> 8, events & 0x000000FF);
+
+ return IRQ_HANDLED;
+ }
+ return IRQ_NONE; /* not handled */
+}
+
+static struct rtc_class_ops at91_rtc_ops = {
+ .ioctl = at91_rtc_ioctl,
+ .read_time = at91_rtc_readtime,
+ .set_time = at91_rtc_settime,
+ .read_alarm = at91_rtc_readalarm,
+ .set_alarm = at91_rtc_setalarm,
+ .proc = at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ int ret;
+
+ at91_sys_write(AT91_RTC_CR, 0);
+ at91_sys_write(AT91_RTC_MR, 0); /* 24 hour mode */
+
+ /* Disable all interrupts */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+
+ ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+ IRQF_SHARED, "at91_rtc", pdev);
+ if (ret) {
+ printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
+ AT91_ID_SYS);
+ return ret;
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &at91_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ free_irq(AT91_ID_SYS, pdev);
+ return PTR_ERR(rtc);
+ }
+ platform_set_drvdata(pdev, rtc);
+
+ printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+ return 0;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ /* Disable all interrupts */
+ at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+ free_irq(AT91_ID_SYS, pdev);
+
+ rtc_device_unregister(rtc);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* AT91RM9200 RTC Power management control */
+
+static struct timespec at91_rtc_delta;
+
+static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct rtc_time tm;
+ struct timespec time;
+
+ time.tv_nsec = 0;
+
+ /* calculate time delta for suspend */
+ at91_rtc_readtime(&pdev->dev, &tm);
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ save_time_delta(&at91_rtc_delta, &time);
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+ struct rtc_time tm;
+ struct timespec time;
+
+ time.tv_nsec = 0;
+
+ at91_rtc_readtime(&pdev->dev, &tm);
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ restore_time_delta(&at91_rtc_delta, &time);
+
+ pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+ 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+ .probe = at91_rtc_probe,
+ .remove = at91_rtc_remove,
+ .suspend = at91_rtc_suspend,
+ .resume = at91_rtc_resume,
+ .driver = {
+ .name = "at91_rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init at91_rtc_init(void)
+{
+ return platform_driver_register(&at91_rtc_driver);
+}
+
+static void __exit at91_rtc_exit(void)
+{
+ platform_driver_unregister(&at91_rtc_driver);
+}
+
+module_init(at91_rtc_init);
+module_exit(at91_rtc_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 2011567005f..61a58259c93 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -48,6 +48,93 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
return err;
}
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+/*
+ * Routine to poll RTC seconds field for change as often as possible,
+ * after first RTC_UIE use timer to reduce polling
+ */
+static void rtc_uie_task(void *data)
+{
+ struct rtc_device *rtc = data;
+ struct rtc_time tm;
+ int num = 0;
+ int err;
+
+ err = rtc_read_time(&rtc->class_dev, &tm);
+ spin_lock_irq(&rtc->irq_lock);
+ if (rtc->stop_uie_polling || err) {
+ rtc->uie_task_active = 0;
+ } else if (rtc->oldsecs != tm.tm_sec) {
+ num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
+ rtc->oldsecs = tm.tm_sec;
+ rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
+ rtc->uie_timer_active = 1;
+ rtc->uie_task_active = 0;
+ add_timer(&rtc->uie_timer);
+ } else if (schedule_work(&rtc->uie_task) == 0) {
+ rtc->uie_task_active = 0;
+ }
+ spin_unlock_irq(&rtc->irq_lock);
+ if (num)
+ rtc_update_irq(&rtc->class_dev, num, RTC_UF | RTC_IRQF);
+}
+
+static void rtc_uie_timer(unsigned long data)
+{
+ struct rtc_device *rtc = (struct rtc_device *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc->irq_lock, flags);
+ rtc->uie_timer_active = 0;
+ rtc->uie_task_active = 1;
+ if ((schedule_work(&rtc->uie_task) == 0))
+ rtc->uie_task_active = 0;
+ spin_unlock_irqrestore(&rtc->irq_lock, flags);
+}
+
+static void clear_uie(struct rtc_device *rtc)
+{
+ spin_lock_irq(&rtc->irq_lock);
+ if (rtc->irq_active) {
+ rtc->stop_uie_polling = 1;
+ if (rtc->uie_timer_active) {
+ spin_unlock_irq(&rtc->irq_lock);
+ del_timer_sync(&rtc->uie_timer);
+ spin_lock_irq(&rtc->irq_lock);
+ rtc->uie_timer_active = 0;
+ }
+ if (rtc->uie_task_active) {
+ spin_unlock_irq(&rtc->irq_lock);
+ flush_scheduled_work();
+ spin_lock_irq(&rtc->irq_lock);
+ }
+ rtc->irq_active = 0;
+ }
+ spin_unlock_irq(&rtc->irq_lock);
+}
+
+static int set_uie(struct rtc_device *rtc)
+{
+ struct rtc_time tm;
+ int err;
+
+ err = rtc_read_time(&rtc->class_dev, &tm);
+ if (err)
+ return err;
+ spin_lock_irq(&rtc->irq_lock);
+ if (!rtc->irq_active) {
+ rtc->irq_active = 1;
+ rtc->stop_uie_polling = 0;
+ rtc->oldsecs = tm.tm_sec;
+ rtc->uie_task_active = 1;
+ if (schedule_work(&rtc->uie_task) == 0)
+ rtc->uie_task_active = 0;
+ }
+ rtc->irq_data = 0;
+ spin_unlock_irq(&rtc->irq_lock);
+ return 0;
+}
+#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -127,6 +214,28 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
struct rtc_wkalrm alarm;
void __user *uarg = (void __user *) arg;
+ /* check that the calles has appropriate permissions
+ * for certain ioctls. doing this check here is useful
+ * to avoid duplicate code in each driver.
+ */
+ switch (cmd) {
+ case RTC_EPOCH_SET:
+ case RTC_SET_TIME:
+ if (!capable(CAP_SYS_TIME))
+ return -EACCES;
+ break;
+
+ case RTC_IRQP_SET:
+ if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
+ return -EACCES;
+ break;
+
+ case RTC_PIE_ON:
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EACCES;
+ break;
+ }
+
/* avoid conflicting IRQ users */
if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
spin_lock(&rtc->irq_task_lock);
@@ -185,9 +294,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
break;
case RTC_SET_TIME:
- if (!capable(CAP_SYS_TIME))
- return -EACCES;
-
if (copy_from_user(&tm, uarg, sizeof(tm)))
return -EFAULT;
@@ -203,10 +309,6 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
err = -EINVAL;
break;
}
- if (!capable(CAP_SYS_TIME)) {
- err = -EACCES;
- break;
- }
rtc_epoch = arg;
err = 0;
#endif
@@ -232,6 +334,14 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
break;
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ case RTC_UIE_OFF:
+ clear_uie(rtc);
+ return 0;
+
+ case RTC_UIE_ON:
+ return set_uie(rtc);
+#endif
default:
err = -ENOTTY;
break;
@@ -244,6 +354,9 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
{
struct rtc_device *rtc = to_rtc_device(file->private_data);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ clear_uie(rtc);
+#endif
if (rtc->ops->release)
rtc->ops->release(rtc->class_dev.dev);
@@ -284,6 +397,10 @@ static int rtc_dev_add_device(struct class_device *class_dev,
mutex_init(&rtc->char_lock);
spin_lock_init(&rtc->irq_lock);
init_waitqueue_head(&rtc->irq_queue);
+#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
+ INIT_WORK(&rtc->uie_task, rtc_uie_task, rtc);
+ setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
+#endif
cdev_init(&rtc->char_dev, &rtc_dev_fops);
rtc->char_dev.owner = rtc->owner;
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
new file mode 100644
index 00000000000..e8afb938478
--- /dev/null
+++ b/drivers/rtc/rtc-ds1307.c
@@ -0,0 +1,388 @@
+/*
+ * rtc-ds1307.c - RTC driver for some mostly-compatible I2C chips.
+ *
+ * Copyright (C) 2005 James Chapman (ds1337 core)
+ * Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+
+
+/* We can't determine type by probing, but if we expect pre-Linux code
+ * to have set the chip up as a clock (turning on the oscillator and
+ * setting the date and time), Linux can ignore the non-clock features.
+ * That's a natural job for a factory or repair bench.
+ *
+ * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
+ * (Much better would be board-specific tables of I2C devices, along with
+ * the platform_data drivers would use to sort such issues out.)
+ */
+enum ds_type {
+ unknown = 0,
+ ds_1307, /* or ds1338, ... */
+ ds_1337, /* or ds1339, ... */
+ ds_1340, /* or st m41t00, ... */
+ // rs5c372 too? different address...
+};
+
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+
+
+/* RTC registers don't differ much, except for the century flag */
+#define DS1307_REG_SECS 0x00 /* 00-59 */
+# define DS1307_BIT_CH 0x80
+#define DS1307_REG_MIN 0x01 /* 00-59 */
+#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
+# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
+# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
+#define DS1307_REG_WDAY 0x03 /* 01-07 */
+#define DS1307_REG_MDAY 0x04 /* 01-31 */
+#define DS1307_REG_MONTH 0x05 /* 01-12 */
+# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
+#define DS1307_REG_YEAR 0x06 /* 00-99 */
+
+/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+ * start at 7, and they differ a lot. Only control and status matter for RTC;
+ * be careful using them.
+ */
+#define DS1307_REG_CONTROL 0x07
+# define DS1307_BIT_OUT 0x80
+# define DS1307_BIT_SQWE 0x10
+# define DS1307_BIT_RS1 0x02
+# define DS1307_BIT_RS0 0x01
+#define DS1337_REG_CONTROL 0x0e
+# define DS1337_BIT_nEOSC 0x80
+# define DS1337_BIT_RS2 0x10
+# define DS1337_BIT_RS1 0x08
+# define DS1337_BIT_INTCN 0x04
+# define DS1337_BIT_A2IE 0x02
+# define DS1337_BIT_A1IE 0x01
+#define DS1337_REG_STATUS 0x0f
+# define DS1337_BIT_OSF 0x80
+# define DS1337_BIT_A2I 0x02
+# define DS1337_BIT_A1I 0x01
+#define DS1339_REG_TRICKLE 0x10
+
+
+
+struct ds1307 {
+ u8 reg_addr;
+ u8 regs[8];
+ enum ds_type type;
+ struct i2c_msg msg[2];
+ struct i2c_client client;
+ struct rtc_device *rtc;
+};
+
+
+static int ds1307_get_time(struct device *dev, struct rtc_time *t)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ int tmp;
+
+ /* read the RTC registers all at once */
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = 7;
+
+ tmp = i2c_transfer(ds1307->client.adapter, ds1307->msg, 2);
+ if (tmp != 2) {
+ dev_err(dev, "%s error %d\n", "read", tmp);
+ return -EIO;
+ }
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+ "read",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6]);
+
+ t->tm_sec = BCD2BIN(ds1307->regs[DS1307_REG_SECS] & 0x7f);
+ t->tm_min = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+ tmp = ds1307->regs[DS1307_REG_HOUR] & 0x3f;
+ t->tm_hour = BCD2BIN(tmp);
+ t->tm_wday = BCD2BIN(ds1307->regs[DS1307_REG_WDAY] & 0x07) - 1;
+ t->tm_mday = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+ tmp = ds1307->regs[DS1307_REG_MONTH] & 0x1f;
+ t->tm_mon = BCD2BIN(tmp) - 1;
+
+ /* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */
+ t->tm_year = BCD2BIN(ds1307->regs[DS1307_REG_YEAR]) + 100;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "read", t->tm_sec, t->tm_min,
+ t->tm_hour, t->tm_mday,
+ t->tm_mon, t->tm_year, t->tm_wday);
+
+ return 0;
+}
+
+static int ds1307_set_time(struct device *dev, struct rtc_time *t)
+{
+ struct ds1307 *ds1307 = dev_get_drvdata(dev);
+ int result;
+ int tmp;
+ u8 *buf = ds1307->regs;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+ "write", dt->tm_sec, dt->tm_min,
+ dt->tm_hour, dt->tm_mday,
+ dt->tm_mon, dt->tm_year, dt->tm_wday);
+
+ *buf++ = 0; /* first register addr */
+ buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
+ buf[DS1307_REG_MIN] = BIN2BCD(t->tm_min);
+ buf[DS1307_REG_HOUR] = BIN2BCD(t->tm_hour);
+ buf[DS1307_REG_WDAY] = BIN2BCD(t->tm_wday + 1);
+ buf[DS1307_REG_MDAY] = BIN2BCD(t->tm_mday);
+ buf[DS1307_REG_MONTH] = BIN2BCD(t->tm_mon + 1);
+
+ /* assume 20YY not 19YY */
+ tmp = t->tm_year - 100;
+ buf[DS1307_REG_YEAR] = BIN2BCD(tmp);
+
+ if (ds1307->type == ds_1337)
+ buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
+ else if (ds1307->type == ds_1340)
+ buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
+ | DS1340_BIT_CENTURY;
+
+ ds1307->msg[1].flags = 0;
+ ds1307->msg[1].len = 8;
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+ "write", buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6]);
+
+ result = i2c_transfer(ds1307->client.adapter, &ds1307->msg[1], 1);
+ if (result != 1) {
+ dev_err(dev, "%s error %d\n", "write", tmp);
+ return -EIO;
+ }
+ return 0;
+}
+
+static struct rtc_class_ops ds13xx_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+};
+
+static struct i2c_driver ds1307_driver;
+
+static int __devinit
+ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct ds1307 *ds1307;
+ int err = -ENODEV;
+ struct i2c_client *client;
+ int tmp;
+
+ if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ client = &ds1307->client;
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &ds1307_driver;
+ client->flags = 0;
+
+ i2c_set_clientdata(client, ds1307);
+
+ ds1307->msg[0].addr = client->addr;
+ ds1307->msg[0].flags = 0;
+ ds1307->msg[0].len = 1;
+ ds1307->msg[0].buf = &ds1307->reg_addr;
+
+ ds1307->msg[1].addr = client->addr;
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = sizeof(ds1307->regs);
+ ds1307->msg[1].buf = ds1307->regs;
+
+ /* HACK: "force" implies "needs ds1337-style-oscillator setup" */
+ if (kind >= 0) {
+ ds1307->type = ds_1337;
+
+ ds1307->reg_addr = DS1337_REG_CONTROL;
+ ds1307->msg[1].len = 2;
+
+ tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+ if (tmp != 2) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ ds1307->reg_addr = 0;
+ ds1307->msg[1].len = sizeof(ds1307->regs);
+
+ /* oscillator is off; need to turn it on */
+ if ((ds1307->regs[0] & DS1337_BIT_nEOSC)
+ || (ds1307->regs[1] & DS1337_BIT_OSF)) {
+ printk(KERN_ERR "no ds1337 oscillator code\n");
+ goto exit_free;
+ }
+ } else
+ ds1307->type = ds_1307;
+
+read_rtc:
+ /* read RTC registers */
+
+ tmp = i2c_transfer(client->adapter, ds1307->msg, 2);
+ if (tmp != 2) {
+ pr_debug("read error %d\n", tmp);
+ err = -EIO;
+ goto exit_free;
+ }
+
+ /* minimal sanity checking; some chips (like DS1340) don't
+ * specify the extra bits as must-be-zero, but there are
+ * still a few values that are clearly out-of-range.
+ */
+ tmp = ds1307->regs[DS1307_REG_SECS];
+ if (tmp & DS1307_BIT_CH) {
+ if (ds1307->type && ds1307->type != ds_1307) {
+ pr_debug("not a ds1307?\n");
+ goto exit_free;
+ }
+ ds1307->type = ds_1307;
+
+ /* this partial initialization should work for ds1307,
+ * ds1338, ds1340, st m41t00, and more.
+ */
+ dev_warn(&client->dev, "oscillator started; SET TIME!\n");
+ i2c_smbus_write_byte_data(client, 0, 0);
+ goto read_rtc;
+ }
+ tmp = BCD2BIN(tmp & 0x7f);
+ if (tmp > 60)
+ goto exit_free;
+ tmp = BCD2BIN(ds1307->regs[DS1307_REG_MIN] & 0x7f);
+ if (tmp > 60)
+ goto exit_free;
+
+ tmp = BCD2BIN(ds1307->regs[DS1307_REG_MDAY] & 0x3f);
+ if (tmp == 0 || tmp > 31)
+ goto exit_free;
+
+ tmp = BCD2BIN(ds1307->regs[DS1307_REG_MONTH] & 0x1f);
+ if (tmp == 0 || tmp > 12)
+ goto exit_free;
+
+ /* force into in 24 hour mode (most chips) or
+ * disable century bit (ds1340)
+ */
+ tmp = ds1307->regs[DS1307_REG_HOUR];
+ if (tmp & (1 << 6)) {
+ if (tmp & (1 << 5))
+ tmp = BCD2BIN(tmp & 0x1f) + 12;
+ else
+ tmp = BCD2BIN(tmp);
+ i2c_smbus_write_byte_data(client,
+ DS1307_REG_HOUR,
+ BIN2BCD(tmp));
+ }
+
+ /* FIXME chips like 1337 can generate alarm irqs too; those are
+ * worth exposing through the API (especially when the irq is
+ * wakeup-capable).
+ */
+
+ switch (ds1307->type) {
+ case unknown:
+ strlcpy(client->name, "unknown", I2C_NAME_SIZE);
+ break;
+ case ds_1307:
+ strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
+ break;
+ case ds_1337:
+ strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
+ break;
+ case ds_1340:
+ strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
+ break;
+ }
+
+ /* Tell the I2C layer a new client has arrived */
+ if ((err = i2c_attach_client(client)))
+ goto exit_free;
+
+ ds1307->rtc = rtc_device_register(client->name, &client->dev,
+ &ds13xx_rtc_ops, THIS_MODULE);
+ if (IS_ERR(ds1307->rtc)) {
+ err = PTR_ERR(ds1307->rtc);
+ dev_err(&client->dev,
+ "unable to register the class device\n");
+ goto exit_detach;
+ }
+
+ return 0;
+
+exit_detach:
+ i2c_detach_client(client);
+exit_free:
+ kfree(ds1307);
+exit:
+ return err;
+}
+
+static int __devinit
+ds1307_attach_adapter(struct i2c_adapter *adapter)
+{
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
+ return 0;
+ return i2c_probe(adapter, &addr_data, ds1307_detect);
+}
+
+static int __devexit ds1307_detach_client(struct i2c_client *client)
+{
+ int err;
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+
+ rtc_device_unregister(ds1307->rtc);
+ if ((err = i2c_detach_client(client)))
+ return err;
+ kfree(ds1307);
+ return 0;
+}
+
+static struct i2c_driver ds1307_driver = {
+ .driver = {
+ .name = "ds1307",
+ .owner = THIS_MODULE,
+ },
+ .attach_adapter = ds1307_attach_adapter,
+ .detach_client = __devexit_p(ds1307_detach_client),
+};
+
+static int __init ds1307_init(void)
+{
+ return i2c_add_driver(&ds1307_driver);
+}
+module_init(ds1307_init);
+
+static void __exit ds1307_exit(void)
+{
+ i2c_del_driver(&ds1307_driver);
+}
+module_exit(ds1307_exit);
+
+MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
new file mode 100644
index 00000000000..20900149547
--- /dev/null
+++ b/drivers/rtc/rtc-ds1553.c
@@ -0,0 +1,414 @@
+/*
+ * An rtc driver for the Dallas DS1553
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE 0x2000
+#define RTC_OFFSET 0x1ff0
+
+#define RTC_FLAGS (RTC_OFFSET + 0)
+#define RTC_SECONDS_ALARM (RTC_OFFSET + 2)
+#define RTC_MINUTES_ALARM (RTC_OFFSET + 3)
+#define RTC_HOURS_ALARM (RTC_OFFSET + 4)
+#define RTC_DATE_ALARM (RTC_OFFSET + 5)
+#define RTC_INTERRUPTS (RTC_OFFSET + 6)
+#define RTC_WATCHDOG (RTC_OFFSET + 7)
+#define RTC_CONTROL (RTC_OFFSET + 8)
+#define RTC_CENTURY (RTC_OFFSET + 8)
+#define RTC_SECONDS (RTC_OFFSET + 9)
+#define RTC_MINUTES (RTC_OFFSET + 10)
+#define RTC_HOURS (RTC_OFFSET + 11)
+#define RTC_DAY (RTC_OFFSET + 12)
+#define RTC_DATE (RTC_OFFSET + 13)
+#define RTC_MONTH (RTC_OFFSET + 14)
+#define RTC_YEAR (RTC_OFFSET + 15)
+
+#define RTC_CENTURY_MASK 0x3f
+#define RTC_SECONDS_MASK 0x7f
+#define RTC_DAY_MASK 0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE 0x80
+#define RTC_READ 0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP 0x80
+
+/* Bits in the Flags register */
+#define RTC_FLAGS_AF 0x40
+#define RTC_FLAGS_BLF 0x10
+
+/* Bits in the Interrupts register */
+#define RTC_INTS_AE 0x80
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ unsigned long baseaddr;
+ unsigned long last_jiffies;
+ int irq;
+ unsigned int irqen;
+ int alrm_sec;
+ int alrm_min;
+ int alrm_hour;
+ int alrm_mday;
+};
+
+static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ u8 century;
+
+ century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+ writeb(RTC_WRITE, pdata->ioaddr + RTC_CONTROL);
+
+ writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+ /* RTC_CENTURY and RTC_CONTROL share same register */
+ writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+ writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ return 0;
+}
+
+static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned int year, month, day, hour, minute, second, week;
+ unsigned int century;
+
+ /* give enough time to update RTC in case of continuous read */
+ if (pdata->last_jiffies == jiffies)
+ msleep(1);
+ pdata->last_jiffies = jiffies;
+ writeb(RTC_READ, ioaddr + RTC_CONTROL);
+ second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+ minute = readb(ioaddr + RTC_MINUTES);
+ hour = readb(ioaddr + RTC_HOURS);
+ day = readb(ioaddr + RTC_DATE);
+ week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+ month = readb(ioaddr + RTC_MONTH);
+ year = readb(ioaddr + RTC_YEAR);
+ century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(0, ioaddr + RTC_CONTROL);
+ tm->tm_sec = BCD2BIN(second);
+ tm->tm_min = BCD2BIN(minute);
+ tm->tm_hour = BCD2BIN(hour);
+ tm->tm_mday = BCD2BIN(day);
+ tm->tm_wday = BCD2BIN(week);
+ tm->tm_mon = BCD2BIN(month) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+ return 0;
+}
+
+static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+ writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_mday),
+ ioaddr + RTC_DATE_ALARM);
+ writeb(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_hour),
+ ioaddr + RTC_HOURS_ALARM);
+ writeb(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_min),
+ ioaddr + RTC_MINUTES_ALARM);
+ writeb(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+ 0x80 : BIN2BCD(pdata->alrm_sec),
+ ioaddr + RTC_SECONDS_ALARM);
+ writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);
+ readb(ioaddr + RTC_FLAGS); /* clear interrupts */
+ spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+
+static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ pdata->alrm_mday = alrm->time.tm_mday;
+ pdata->alrm_hour = alrm->time.tm_hour;
+ pdata->alrm_min = alrm->time.tm_min;
+ pdata->alrm_sec = alrm->time.tm_sec;
+ if (alrm->enabled)
+ pdata->irqen |= RTC_AF;
+ ds1553_rtc_update_alarm(pdata);
+ return 0;
+}
+
+static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -EINVAL;
+ alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
+ alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
+ alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
+ alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
+ alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
+ return 0;
+}
+
+static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct platform_device *pdev = dev_id;
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned long events = RTC_IRQF;
+
+ /* read and clear interrupt */
+ if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF))
+ return IRQ_NONE;
+ if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
+ events |= RTC_UF;
+ else
+ events |= RTC_AF;
+ rtc_update_irq(&pdata->rtc->class_dev, 1, events);
+ return IRQ_HANDLED;
+}
+
+static void ds1553_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq >= 0) {
+ pdata->irqen = 0;
+ ds1553_rtc_update_alarm(pdata);
+ }
+}
+
+static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
+ unsigned long arg)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ if (pdata->irq < 0)
+ return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ pdata->irqen &= ~RTC_AF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ case RTC_AIE_ON:
+ pdata->irqen |= RTC_AF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_OFF:
+ pdata->irqen &= ~RTC_UF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ case RTC_UIE_ON:
+ pdata->irqen |= RTC_UF;
+ ds1553_rtc_update_alarm(pdata);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+static struct rtc_class_ops ds1553_rtc_ops = {
+ .read_time = ds1553_rtc_read_time,
+ .set_time = ds1553_rtc_set_time,
+ .read_alarm = ds1553_rtc_read_alarm,
+ .set_alarm = ds1553_rtc_set_alarm,
+ .release = ds1553_rtc_release,
+ .ioctl = ds1553_rtc_ioctl,
+};
+
+static ssize_t ds1553_nvram_read(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ *buf++ = readb(ioaddr + pos++);
+ return count;
+}
+
+static ssize_t ds1553_nvram_write(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ writeb(*buf++, ioaddr + pos++);
+ return count;
+}
+
+static struct bin_attribute ds1553_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = RTC_OFFSET,
+ .read = ds1553_nvram_read,
+ .write = ds1553_nvram_write,
+};
+
+static int __init ds1553_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ unsigned int cen, sec;
+ struct rtc_plat_data *pdata = NULL;
+ void __iomem *ioaddr = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ pdata->irq = -1;
+ if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+ if (!ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ioaddr;
+ pdata->irq = platform_get_irq(pdev, 0);
+
+ /* turn RTC on if it was not on */
+ sec = readb(ioaddr + RTC_SECONDS);
+ if (sec & RTC_STOP) {
+ sec &= RTC_SECONDS_MASK;
+ cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+ writeb(sec, ioaddr + RTC_SECONDS);
+ writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ }
+ if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF)
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ if (pdata->irq >= 0) {
+ writeb(0, ioaddr + RTC_INTERRUPTS);
+ if (request_irq(pdata->irq, ds1553_rtc_interrupt, IRQF_SHARED,
+ pdev->name, pdev) < 0) {
+ dev_warn(&pdev->dev, "interrupt not available.\n");
+ pdata->irq = -1;
+ }
+ }
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &ds1553_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+ sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ return 0;
+ out:
+ if (pdata->irq >= 0)
+ free_irq(pdata->irq, pdev);
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ if (pdata->irq >= 0) {
+ writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
+ free_irq(pdata->irq, pdev);
+ }
+ iounmap(pdata->ioaddr);
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver ds1553_rtc_driver = {
+ .probe = ds1553_rtc_probe,
+ .remove = __devexit_p(ds1553_rtc_remove),
+ .driver = {
+ .name = "ds1553",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int ds1553_init(void)
+{
+ return platform_driver_register(&ds1553_rtc_driver);
+}
+
+static __exit void ds1553_exit(void)
+{
+ return platform_driver_unregister(&ds1553_rtc_driver);
+}
+
+module_init(ds1553_init);
+module_exit(ds1553_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1553 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
new file mode 100644
index 00000000000..8e47e5a06d2
--- /dev/null
+++ b/drivers/rtc/rtc-ds1742.c
@@ -0,0 +1,259 @@
+/*
+ * An rtc driver for the Dallas DS1742
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#define DRV_VERSION "0.1"
+
+#define RTC_REG_SIZE 0x800
+#define RTC_OFFSET 0x7f8
+
+#define RTC_CONTROL (RTC_OFFSET + 0)
+#define RTC_CENTURY (RTC_OFFSET + 0)
+#define RTC_SECONDS (RTC_OFFSET + 1)
+#define RTC_MINUTES (RTC_OFFSET + 2)
+#define RTC_HOURS (RTC_OFFSET + 3)
+#define RTC_DAY (RTC_OFFSET + 4)
+#define RTC_DATE (RTC_OFFSET + 5)
+#define RTC_MONTH (RTC_OFFSET + 6)
+#define RTC_YEAR (RTC_OFFSET + 7)
+
+#define RTC_CENTURY_MASK 0x3f
+#define RTC_SECONDS_MASK 0x7f
+#define RTC_DAY_MASK 0x07
+
+/* Bits in the Control/Century register */
+#define RTC_WRITE 0x80
+#define RTC_READ 0x40
+
+/* Bits in the Seconds register */
+#define RTC_STOP 0x80
+
+/* Bits in the Day register */
+#define RTC_BATT_FLAG 0x80
+
+struct rtc_plat_data {
+ struct rtc_device *rtc;
+ void __iomem *ioaddr;
+ unsigned long baseaddr;
+ unsigned long last_jiffies;
+};
+
+static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ u8 century;
+
+ century = BIN2BCD((tm->tm_year + 1900) / 100);
+
+ writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+
+ writeb(BIN2BCD(tm->tm_year % 100), ioaddr + RTC_YEAR);
+ writeb(BIN2BCD(tm->tm_mon + 1), ioaddr + RTC_MONTH);
+ writeb(BIN2BCD(tm->tm_wday) & RTC_DAY_MASK, ioaddr + RTC_DAY);
+ writeb(BIN2BCD(tm->tm_mday), ioaddr + RTC_DATE);
+ writeb(BIN2BCD(tm->tm_hour), ioaddr + RTC_HOURS);
+ writeb(BIN2BCD(tm->tm_min), ioaddr + RTC_MINUTES);
+ writeb(BIN2BCD(tm->tm_sec) & RTC_SECONDS_MASK, ioaddr + RTC_SECONDS);
+
+ /* RTC_CENTURY and RTC_CONTROL share same register */
+ writeb(RTC_WRITE | (century & RTC_CENTURY_MASK), ioaddr + RTC_CENTURY);
+ writeb(century & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ return 0;
+}
+
+static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ unsigned int year, month, day, hour, minute, second, week;
+ unsigned int century;
+
+ /* give enough time to update RTC in case of continuous read */
+ if (pdata->last_jiffies == jiffies)
+ msleep(1);
+ pdata->last_jiffies = jiffies;
+ writeb(RTC_READ, ioaddr + RTC_CONTROL);
+ second = readb(ioaddr + RTC_SECONDS) & RTC_SECONDS_MASK;
+ minute = readb(ioaddr + RTC_MINUTES);
+ hour = readb(ioaddr + RTC_HOURS);
+ day = readb(ioaddr + RTC_DATE);
+ week = readb(ioaddr + RTC_DAY) & RTC_DAY_MASK;
+ month = readb(ioaddr + RTC_MONTH);
+ year = readb(ioaddr + RTC_YEAR);
+ century = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(0, ioaddr + RTC_CONTROL);
+ tm->tm_sec = BCD2BIN(second);
+ tm->tm_min = BCD2BIN(minute);
+ tm->tm_hour = BCD2BIN(hour);
+ tm->tm_mday = BCD2BIN(day);
+ tm->tm_wday = BCD2BIN(week);
+ tm->tm_mon = BCD2BIN(month) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(year) + BCD2BIN(century) * 100 - 1900;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+ return 0;
+}
+
+static struct rtc_class_ops ds1742_rtc_ops = {
+ .read_time = ds1742_rtc_read_time,
+ .set_time = ds1742_rtc_set_time,
+};
+
+static ssize_t ds1742_nvram_read(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ *buf++ = readb(ioaddr + pos++);
+ return count;
+}
+
+static ssize_t ds1742_nvram_write(struct kobject *kobj, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+ void __iomem *ioaddr = pdata->ioaddr;
+ ssize_t count;
+
+ for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--)
+ writeb(*buf++, ioaddr + pos++);
+ return count;
+}
+
+static struct bin_attribute ds1742_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUGO,
+ .owner = THIS_MODULE,
+ },
+ .size = RTC_OFFSET,
+ .read = ds1742_nvram_read,
+ .write = ds1742_nvram_write,
+};
+
+static int __init ds1742_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ unsigned int cen, sec;
+ struct rtc_plat_data *pdata = NULL;
+ void __iomem *ioaddr = NULL;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ pdata->baseaddr = res->start;
+ ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE);
+ if (!ioaddr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ pdata->ioaddr = ioaddr;
+
+ /* turn RTC on if it was not on */
+ sec = readb(ioaddr + RTC_SECONDS);
+ if (sec & RTC_STOP) {
+ sec &= RTC_SECONDS_MASK;
+ cen = readb(ioaddr + RTC_CENTURY) & RTC_CENTURY_MASK;
+ writeb(RTC_WRITE, ioaddr + RTC_CONTROL);
+ writeb(sec, ioaddr + RTC_SECONDS);
+ writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
+ }
+ if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)
+ dev_warn(&pdev->dev, "voltage-low detected.\n");
+
+ rtc = rtc_device_register(pdev->name, &pdev->dev,
+ &ds1742_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ pdata->rtc = rtc;
+ pdata->last_jiffies = jiffies;
+ platform_set_drvdata(pdev, pdata);
+ sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+ return 0;
+ out:
+ if (ioaddr)
+ iounmap(ioaddr);
+ if (pdata->baseaddr)
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+ rtc_device_unregister(pdata->rtc);
+ iounmap(pdata->ioaddr);
+ release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
+ kfree(pdata);
+ return 0;
+}
+
+static struct platform_driver ds1742_rtc_driver = {
+ .probe = ds1742_rtc_probe,
+ .remove = __devexit_p(ds1742_rtc_remove),
+ .driver = {
+ .name = "ds1742",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int ds1742_init(void)
+{
+ return platform_driver_register(&ds1742_rtc_driver);
+}
+
+static __exit void ds1742_exit(void)
+{
+ return platform_driver_unregister(&ds1742_rtc_driver);
+}
+
+module_init(ds1742_init);
+module_exit(ds1742_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Dallas DS1742 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
new file mode 100644
index 00000000000..f324d0a635d
--- /dev/null
+++ b/drivers/rtc/rtc-isl1208.c
@@ -0,0 +1,591 @@
+/*
+ * Intersil ISL1208 rtc class driver
+ *
+ * Copyright 2005,2006 Hebert Valerio Riedel <hvr@gnu.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+#define DRV_NAME "isl1208"
+#define DRV_VERSION "0.2"
+
+/* Register map */
+/* rtc section */
+#define ISL1208_REG_SC 0x00
+#define ISL1208_REG_MN 0x01
+#define ISL1208_REG_HR 0x02
+#define ISL1208_REG_HR_MIL (1<<7) /* 24h/12h mode */
+#define ISL1208_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */
+#define ISL1208_REG_DT 0x03
+#define ISL1208_REG_MO 0x04
+#define ISL1208_REG_YR 0x05
+#define ISL1208_REG_DW 0x06
+#define ISL1208_RTC_SECTION_LEN 7
+
+/* control/status section */
+#define ISL1208_REG_SR 0x07
+#define ISL1208_REG_SR_ARST (1<<7) /* auto reset */
+#define ISL1208_REG_SR_XTOSCB (1<<6) /* crystal oscillator */
+#define ISL1208_REG_SR_WRTC (1<<4) /* write rtc */
+#define ISL1208_REG_SR_ALM (1<<2) /* alarm */
+#define ISL1208_REG_SR_BAT (1<<1) /* battery */
+#define ISL1208_REG_SR_RTCF (1<<0) /* rtc fail */
+#define ISL1208_REG_INT 0x08
+#define ISL1208_REG_09 0x09 /* reserved */
+#define ISL1208_REG_ATR 0x0a
+#define ISL1208_REG_DTR 0x0b
+
+/* alarm section */
+#define ISL1208_REG_SCA 0x0c
+#define ISL1208_REG_MNA 0x0d
+#define ISL1208_REG_HRA 0x0e
+#define ISL1208_REG_DTA 0x0f
+#define ISL1208_REG_MOA 0x10
+#define ISL1208_REG_DWA 0x11
+#define ISL1208_ALARM_SECTION_LEN 6
+
+/* user section */
+#define ISL1208_REG_USR1 0x12
+#define ISL1208_REG_USR2 0x13
+#define ISL1208_USR_SECTION_LEN 2
+
+/* i2c configuration */
+#define ISL1208_I2C_ADDR 0xde
+
+static unsigned short normal_i2c[] = {
+ ISL1208_I2C_ADDR>>1, I2C_CLIENT_END
+};
+I2C_CLIENT_INSMOD; /* defines addr_data */
+
+static int isl1208_attach_adapter(struct i2c_adapter *adapter);
+static int isl1208_detach_client(struct i2c_client *client);
+
+static struct i2c_driver isl1208_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ },
+ .id = I2C_DRIVERID_ISL1208,
+ .attach_adapter = &isl1208_attach_adapter,
+ .detach_client = &isl1208_detach_client,
+};
+
+/* block read */
+static int
+isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[],
+ unsigned len)
+{
+ u8 reg_addr[1] = { reg };
+ struct i2c_msg msgs[2] = {
+ { client->addr, client->flags, sizeof(reg_addr), reg_addr },
+ { client->addr, client->flags | I2C_M_RD, len, buf }
+ };
+ int ret;
+
+ BUG_ON(len == 0);
+ BUG_ON(reg > ISL1208_REG_USR2);
+ BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/* block write */
+static int
+isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[],
+ unsigned len)
+{
+ u8 i2c_buf[ISL1208_REG_USR2 + 2];
+ struct i2c_msg msgs[1] = {
+ { client->addr, client->flags, len + 1, i2c_buf }
+ };
+ int ret;
+
+ BUG_ON(len == 0);
+ BUG_ON(reg > ISL1208_REG_USR2);
+ BUG_ON(reg + len > ISL1208_REG_USR2 + 1);
+
+ i2c_buf[0] = reg;
+ memcpy(&i2c_buf[1], &buf[0], len);
+
+ ret = i2c_transfer(client->adapter, msgs, 1);
+ if (ret > 0)
+ ret = 0;
+ return ret;
+}
+
+/* simple check to see wether we have a isl1208 */
+static int isl1208_i2c_validate_client(struct i2c_client *client)
+{
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+ u8 zero_mask[ISL1208_RTC_SECTION_LEN] = {
+ 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8
+ };
+ int i;
+ int ret;
+
+ ret = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ISL1208_RTC_SECTION_LEN; ++i) {
+ if (regs[i] & zero_mask[i]) /* check if bits are cleared */
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int isl1208_i2c_get_sr(struct i2c_client *client)
+{
+ return i2c_smbus_read_byte_data(client, ISL1208_REG_SR) == -1 ? -EIO:0;
+}
+
+static int isl1208_i2c_get_atr(struct i2c_client *client)
+{
+ int atr = i2c_smbus_read_byte_data(client, ISL1208_REG_ATR);
+
+ if (atr < 0)
+ return -EIO;
+
+ /* The 6bit value in the ATR register controls the load
+ * capacitance C_load * in steps of 0.25pF
+ *
+ * bit (1<<5) of the ATR register is inverted
+ *
+ * C_load(ATR=0x20) = 4.50pF
+ * C_load(ATR=0x00) = 12.50pF
+ * C_load(ATR=0x1f) = 20.25pF
+ *
+ */
+
+ atr &= 0x3f; /* mask out lsb */
+ atr ^= 1<<5; /* invert 6th bit */
+ atr += 2*9; /* add offset of 4.5pF; unit[atr] = 0.25pF */
+
+ return atr;
+}
+
+static int isl1208_i2c_get_dtr(struct i2c_client *client)
+{
+ int dtr = i2c_smbus_read_byte_data(client, ISL1208_REG_DTR);
+
+ if (dtr < 0)
+ return -EIO;
+
+ /* dtr encodes adjustments of {-60,-40,-20,0,20,40,60} ppm */
+ dtr = ((dtr & 0x3) * 20) * (dtr & (1<<2) ? -1 : 1);
+
+ return dtr;
+}
+
+static int isl1208_i2c_get_usr(struct i2c_client *client)
+{
+ u8 buf[ISL1208_USR_SECTION_LEN] = { 0, };
+ int ret;
+
+ ret = isl1208_i2c_read_regs (client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
+ if (ret < 0)
+ return ret;
+
+ return (buf[1] << 8) | buf[0];
+}
+
+static int isl1208_i2c_set_usr(struct i2c_client *client, u16 usr)
+{
+ u8 buf[ISL1208_USR_SECTION_LEN];
+
+ buf[0] = usr & 0xff;
+ buf[1] = (usr >> 8) & 0xff;
+
+ return isl1208_i2c_set_regs (client, ISL1208_REG_USR1, buf,
+ ISL1208_USR_SECTION_LEN);
+}
+
+static int isl1208_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct i2c_client *const client = to_i2c_client(dev);
+ int sr, dtr, atr, usr;
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ seq_printf(seq, "status_reg\t:%s%s%s%s%s%s (0x%.2x)\n",
+ (sr & ISL1208_REG_SR_RTCF) ? " RTCF" : "",
+ (sr & ISL1208_REG_SR_BAT) ? " BAT" : "",
+ (sr & ISL1208_REG_SR_ALM) ? " ALM" : "",
+ (sr & ISL1208_REG_SR_WRTC) ? " WRTC" : "",
+ (sr & ISL1208_REG_SR_XTOSCB) ? " XTOSCB" : "",
+ (sr & ISL1208_REG_SR_ARST) ? " ARST" : "",
+ sr);
+
+ seq_printf(seq, "batt_status\t: %s\n",
+ (sr & ISL1208_REG_SR_RTCF) ? "bad" : "okay");
+
+ dtr = isl1208_i2c_get_dtr(client);
+ if (dtr >= 0 -1)
+ seq_printf(seq, "digital_trim\t: %d ppm\n", dtr);
+
+ atr = isl1208_i2c_get_atr(client);
+ if (atr >= 0)
+ seq_printf(seq, "analog_trim\t: %d.%.2d pF\n",
+ atr>>2, (atr&0x3)*25);
+
+ usr = isl1208_i2c_get_usr(client);
+ if (usr >= 0)
+ seq_printf(seq, "user_data\t: 0x%.4x\n", usr);
+
+ return 0;
+}
+
+
+static int isl1208_i2c_read_time(struct i2c_client *client,
+ struct rtc_time *tm)
+{
+ int sr;
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return -EIO;
+ }
+
+ sr = isl1208_i2c_read_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading RTC section failed\n",
+ __func__);
+ return sr;
+ }
+
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SC]);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MN]);
+ { /* HR field has a more complex interpretation */
+ const u8 _hr = regs[ISL1208_REG_HR];
+ if (_hr & ISL1208_REG_HR_MIL) /* 24h format */
+ tm->tm_hour = BCD2BIN(_hr & 0x3f);
+ else { // 12h format
+ tm->tm_hour = BCD2BIN(_hr & 0x1f);
+ if (_hr & ISL1208_REG_HR_PM) /* PM flag set */
+ tm->tm_hour += 12;
+ }
+ }
+
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DT]);
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MO]) - 1; /* rtc starts at 1 */
+ tm->tm_year = BCD2BIN(regs[ISL1208_REG_YR]) + 100;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DW]);
+
+ return 0;
+}
+
+static int isl1208_i2c_read_alarm(struct i2c_client *client,
+ struct rtc_wkalrm *alarm)
+{
+ struct rtc_time *const tm = &alarm->time;
+ u8 regs[ISL1208_ALARM_SECTION_LEN] = { 0, };
+ int sr;
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ sr = isl1208_i2c_read_regs(client, ISL1208_REG_SCA, regs,
+ ISL1208_ALARM_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading alarm section failed\n",
+ __func__);
+ return sr;
+ }
+
+ /* MSB of each alarm register is an enable bit */
+ tm->tm_sec = BCD2BIN(regs[ISL1208_REG_SCA-ISL1208_REG_SCA] & 0x7f);
+ tm->tm_min = BCD2BIN(regs[ISL1208_REG_MNA-ISL1208_REG_SCA] & 0x7f);
+ tm->tm_hour = BCD2BIN(regs[ISL1208_REG_HRA-ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mday = BCD2BIN(regs[ISL1208_REG_DTA-ISL1208_REG_SCA] & 0x3f);
+ tm->tm_mon = BCD2BIN(regs[ISL1208_REG_MOA-ISL1208_REG_SCA] & 0x1f)-1;
+ tm->tm_wday = BCD2BIN(regs[ISL1208_REG_DWA-ISL1208_REG_SCA] & 0x03);
+
+ return 0;
+}
+
+static int isl1208_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return isl1208_i2c_read_time(to_i2c_client(dev), tm);
+}
+
+static int isl1208_i2c_set_time(struct i2c_client *client,
+ struct rtc_time const *tm)
+{
+ int sr;
+ u8 regs[ISL1208_RTC_SECTION_LEN] = { 0, };
+
+ regs[ISL1208_REG_SC] = BIN2BCD(tm->tm_sec);
+ regs[ISL1208_REG_MN] = BIN2BCD(tm->tm_min);
+ regs[ISL1208_REG_HR] = BIN2BCD(tm->tm_hour) | ISL1208_REG_HR_MIL;
+
+ regs[ISL1208_REG_DT] = BIN2BCD(tm->tm_mday);
+ regs[ISL1208_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+ regs[ISL1208_REG_YR] = BIN2BCD(tm->tm_year - 100);
+
+ regs[ISL1208_REG_DW] = BIN2BCD(tm->tm_wday & 7);
+
+ sr = isl1208_i2c_get_sr(client);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: reading SR failed\n", __func__);
+ return sr;
+ }
+
+ /* set WRTC */
+ sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr | ISL1208_REG_SR_WRTC);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing SR failed\n", __func__);
+ return sr;
+ }
+
+ /* write RTC registers */
+ sr = isl1208_i2c_set_regs(client, 0, regs, ISL1208_RTC_SECTION_LEN);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing RTC section failed\n",
+ __func__);
+ return sr;
+ }
+
+ /* clear WRTC again */
+ sr = i2c_smbus_write_byte_data (client, ISL1208_REG_SR,
+ sr & ~ISL1208_REG_SR_WRTC);
+ if (sr < 0) {
+ dev_err(&client->dev, "%s: writing SR failed\n", __func__);
+ return sr;
+ }
+
+ return 0;
+}
+
+
+static int isl1208_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return isl1208_i2c_set_time(to_i2c_client(dev), tm);
+}
+
+static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
+}
+
+static struct rtc_class_ops isl1208_rtc_ops = {
+ .proc = isl1208_rtc_proc,
+ .read_time = isl1208_rtc_read_time,
+ .set_time = isl1208_rtc_set_time,
+ .read_alarm = isl1208_rtc_read_alarm,
+ //.set_alarm = isl1208_rtc_set_alarm,
+};
+
+/* sysfs interface */
+
+static ssize_t isl1208_sysfs_show_atrim(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int atr;
+
+ atr = isl1208_i2c_get_atr(to_i2c_client(dev));
+ if (atr < 0)
+ return atr;
+
+ return sprintf(buf, "%d.%.2d pF\n", atr>>2, (atr&0x3)*25);
+}
+static DEVICE_ATTR(atrim, S_IRUGO, isl1208_sysfs_show_atrim, NULL);
+
+static ssize_t isl1208_sysfs_show_dtrim(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int dtr;
+
+ dtr = isl1208_i2c_get_dtr(to_i2c_client(dev));
+ if (dtr < 0)
+ return dtr;
+
+ return sprintf(buf, "%d ppm\n", dtr);
+}
+static DEVICE_ATTR(dtrim, S_IRUGO, isl1208_sysfs_show_dtrim, NULL);
+
+static ssize_t isl1208_sysfs_show_usr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int usr;
+
+ usr = isl1208_i2c_get_usr(to_i2c_client(dev));
+ if (usr < 0)
+ return usr;
+
+ return sprintf(buf, "0x%.4x\n", usr);
+}
+
+static ssize_t isl1208_sysfs_store_usr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int usr = -1;
+
+ if (buf[0] == '0' && (buf[1] == 'x' || buf[1] == 'X')) {
+ if (sscanf(buf, "%x", &usr) != 1)
+ return -EINVAL;
+ } else {
+ if (sscanf(buf, "%d", &usr) != 1)
+ return -EINVAL;
+ }
+
+ if (usr < 0 || usr > 0xffff)
+ return -EINVAL;
+
+ return isl1208_i2c_set_usr(to_i2c_client(dev), usr) ? -EIO : count;
+}
+static DEVICE_ATTR(usr, S_IRUGO | S_IWUSR, isl1208_sysfs_show_usr,
+ isl1208_sysfs_store_usr);
+
+static int
+isl1208_probe(struct i2c_adapter *adapter, int addr, int kind)
+{
+ int rc = 0;
+ struct i2c_client *new_client = NULL;
+ struct rtc_device *rtc = NULL;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+ rc = -ENODEV;
+ goto failout;
+ }
+
+ new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (new_client == NULL) {
+ rc = -ENOMEM;
+ goto failout;
+ }
+
+ new_client->addr = addr;
+ new_client->adapter = adapter;
+ new_client->driver = &isl1208_driver;
+ new_client->flags = 0;
+ strcpy(new_client->name, DRV_NAME);
+
+ if (kind < 0) {
+ rc = isl1208_i2c_validate_client(new_client);
+ if (rc < 0)
+ goto failout;
+ }
+
+ rc = i2c_attach_client(new_client);
+ if (rc < 0)
+ goto failout;
+
+ dev_info(&new_client->dev,
+ "chip found, driver version " DRV_VERSION "\n");
+
+ rtc = rtc_device_register(isl1208_driver.driver.name,
+ &new_client->dev,
+ &isl1208_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ rc = PTR_ERR(rtc);
+ goto failout_detach;
+ }
+
+ i2c_set_clientdata(new_client, rtc);
+
+ rc = isl1208_i2c_get_sr(new_client);
+ if (rc < 0) {
+ dev_err(&new_client->dev, "reading status failed\n");
+ goto failout_unregister;
+ }
+
+ if (rc & ISL1208_REG_SR_RTCF)
+ dev_warn(&new_client->dev, "rtc power failure detected, "
+ "please set clock.\n");
+
+ rc = device_create_file(&new_client->dev, &dev_attr_atrim);
+ if (rc < 0)
+ goto failout_unregister;
+ rc = device_create_file(&new_client->dev, &dev_attr_dtrim);
+ if (rc < 0)
+ goto failout_atrim;
+ rc = device_create_file(&new_client->dev, &dev_attr_usr);
+ if (rc < 0)
+ goto failout_dtrim;
+
+ return 0;
+
+ failout_dtrim:
+ device_remove_file(&new_client->dev, &dev_attr_dtrim);
+ failout_atrim:
+ device_remove_file(&new_client->dev, &dev_attr_atrim);
+ failout_unregister:
+ rtc_device_unregister(rtc);
+ failout_detach:
+ i2c_detach_client(new_client);
+ failout:
+ kfree(new_client);
+ return rc;
+}
+
+static int
+isl1208_attach_adapter (struct i2c_adapter *adapter)
+{
+ return i2c_probe(adapter, &addr_data, isl1208_probe);
+}
+
+static int
+isl1208_detach_client(struct i2c_client *client)
+{
+ int rc;
+ struct rtc_device *const rtc = i2c_get_clientdata(client);
+
+ if (rtc)
+ rtc_device_unregister(rtc); /* do we need to kfree? */
+
+ rc = i2c_detach_client(client);
+ if (rc)
+ return rc;
+
+ kfree(client);
+
+ return 0;
+}
+
+/* module management */
+
+static int __init isl1208_init(void)
+{
+ return i2c_add_driver(&isl1208_driver);
+}
+
+static void __exit isl1208_exit(void)
+{
+ i2c_del_driver(&isl1208_driver);
+}
+
+MODULE_AUTHOR("Herbert Valerio Riedel <hvr@gnu.org>");
+MODULE_DESCRIPTION("Intersil ISL1208 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(isl1208_init);
+module_exit(isl1208_exit);
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index cfedc1d28ee..9812120f3a7 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -18,9 +18,19 @@ static const unsigned char rtc_days_in_month[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
+static const unsigned short rtc_ydays[2][13] = {
+ /* Normal years */
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
+ /* Leap years */
+ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
+};
+
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+/*
+ * The number of days in the month.
+ */
int rtc_month_days(unsigned int month, unsigned int year)
{
return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
@@ -28,6 +38,15 @@ int rtc_month_days(unsigned int month, unsigned int year)
EXPORT_SYMBOL(rtc_month_days);
/*
+ * The number of days since January 1. (0 to 365)
+ */
+int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
+{
+ return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
+}
+EXPORT_SYMBOL(rtc_year_days);
+
+/*
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
new file mode 100644
index 00000000000..2c9739562b5
--- /dev/null
+++ b/drivers/rtc/rtc-max6902.c
@@ -0,0 +1,286 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for MAX6902 spi RTC
+ *
+ * Changelog:
+ *
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ * - Major rework
+ * Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ * - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+#include <linux/delay.h>
+
+#define MAX6902_REG_SECONDS 0x01
+#define MAX6902_REG_MINUTES 0x03
+#define MAX6902_REG_HOURS 0x05
+#define MAX6902_REG_DATE 0x07
+#define MAX6902_REG_MONTH 0x09
+#define MAX6902_REG_DAY 0x0B
+#define MAX6902_REG_YEAR 0x0D
+#define MAX6902_REG_CONTROL 0x0F
+#define MAX6902_REG_CENTURY 0x13
+
+#undef MAX6902_DEBUG
+
+struct max6902 {
+ struct rtc_device *rtc;
+ u8 buf[9]; /* Burst read cmd + 8 registers */
+ u8 tx_buf[2];
+ u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address,
+ unsigned char data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[2];
+
+ /* MSB must be '0' to write */
+ buf[0] = address & 0x7f;
+ buf[1] = data;
+
+ spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address,
+ unsigned char *data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct max6902 *chip = dev_get_drvdata(dev);
+ struct spi_message message;
+ struct spi_transfer xfer;
+ int status;
+
+ if (!data)
+ return -EINVAL;
+
+ /* Build our spi message */
+ spi_message_init(&message);
+ memset(&xfer, 0, sizeof(xfer));
+ xfer.len = 2;
+ /* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+ xfer.tx_buf = chip->tx_buf;
+ xfer.rx_buf = chip->rx_buf;
+
+ /* Set MSB to indicate read */
+ chip->tx_buf[0] = address | 0x80;
+
+ spi_message_add_tail(&xfer, &message);
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ status = message.status;
+ else
+ return status;
+
+ *data = chip->rx_buf[1];
+
+ return status;
+}
+
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+ unsigned char tmp;
+ int century;
+ int err;
+ struct spi_device *spi = to_spi_device(dev);
+ struct max6902 *chip = dev_get_drvdata(dev);
+ struct spi_message message;
+ struct spi_transfer xfer;
+ int status;
+
+ err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+ if (err)
+ return err;
+
+ /* build the message */
+ spi_message_init(&message);
+ memset(&xfer, 0, sizeof(xfer));
+ xfer.len = 1 + 7; /* Burst read command + 7 registers */
+ xfer.tx_buf = chip->buf;
+ xfer.rx_buf = chip->buf;
+ chip->buf[0] = 0xbf; /* Burst read */
+ spi_message_add_tail(&xfer, &message);
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ status = message.status;
+ else
+ return status;
+
+ /* The chip sends data in this order:
+ * Seconds, Minutes, Hours, Date, Month, Day, Year */
+ dt->tm_sec = BCD2BIN(chip->buf[1]);
+ dt->tm_min = BCD2BIN(chip->buf[2]);
+ dt->tm_hour = BCD2BIN(chip->buf[3]);
+ dt->tm_mday = BCD2BIN(chip->buf[4]);
+ dt->tm_mon = BCD2BIN(chip->buf[5] - 1);
+ dt->tm_wday = BCD2BIN(chip->buf[6]);
+ dt->tm_year = BCD2BIN(chip->buf[7]);
+
+ century = BCD2BIN(tmp) * 100;
+
+ dt->tm_year += century;
+ dt->tm_year -= 1900;
+
+#ifdef MAX6902_DEBUG
+ printk("\n%s : Read RTC values\n",__FUNCTION__);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_year: %i\n",dt->tm_year);
+ printk("tm_mon : %i\n",dt->tm_mon);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+ return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+ dt->tm_year = dt->tm_year+1900;
+
+#ifdef MAX6902_DEBUG
+ printk("\n%s : Setting RTC values\n",__FUNCTION__);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+ printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+ /* Remove write protection */
+ max6902_set_reg(dev, 0xF, 0);
+
+ max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+ max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+ max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+ max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+ max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+ max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+ max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+ max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+ /* Compulab used a delay here. However, the datasheet
+ * does not mention a delay being required anywhere... */
+ /* delay(2000); */
+
+ /* Write protect */
+ max6902_set_reg(dev, 0xF, 0x80);
+
+ return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+ .read_time = max6902_read_time,
+ .set_time = max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char tmp;
+ struct max6902 *chip;
+ int res;
+
+ rtc = rtc_device_register("max6902",
+ &spi->dev, &max6902_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ spi->mode = SPI_MODE_3;
+ spi->bits_per_word = 8;
+ spi_setup(spi);
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip) {
+ rtc_device_unregister(rtc);
+ return -ENOMEM;
+ }
+ chip->rtc = rtc;
+ dev_set_drvdata(&spi->dev, chip);
+
+ res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+ if (res) {
+ rtc_device_unregister(rtc);
+ return res;
+ }
+
+ return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+ struct max6902 *chip = platform_get_drvdata(spi);
+ struct rtc_device *rtc = chip->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ kfree(chip);
+
+ return 0;
+}
+
+static struct spi_driver max6902_driver = {
+ .driver = {
+ .name = "max6902",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = max6902_probe,
+ .remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+ printk("max6902 spi driver\n");
+ return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+ spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
new file mode 100644
index 00000000000..b235a30cb66
--- /dev/null
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -0,0 +1,394 @@
+/*
+ * drivers/rtc/rtc-pcf8583.c
+ *
+ * Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for PCF8583 RTC & RAM chip
+ *
+ * Converted to the generic RTC susbsystem by G. Liakhovetski (2006)
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/mc146818rtc.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/bcd.h>
+
+struct rtc_mem {
+ unsigned int loc;
+ unsigned int nr;
+ unsigned char *data;
+};
+
+struct pcf8583 {
+ struct i2c_client client;
+ struct rtc_device *rtc;
+ unsigned char ctrl;
+};
+
+#define CTRL_STOP 0x80
+#define CTRL_HOLD 0x40
+#define CTRL_32KHZ 0x00
+#define CTRL_MASK 0x08
+#define CTRL_ALARMEN 0x04
+#define CTRL_ALARM 0x02
+#define CTRL_TIMER 0x01
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Module parameters */
+I2C_CLIENT_INSMOD;
+
+static struct i2c_driver pcf8583_driver;
+
+#define get_ctrl(x) ((struct pcf8583 *)i2c_get_clientdata(x))->ctrl
+#define set_ctrl(x, v) get_ctrl(x) = v
+
+#define CMOS_YEAR (64 + 128)
+#define CMOS_CHECKSUM (63)
+
+static int pcf8583_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+ unsigned char buf[8], addr[1] = { 1 };
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 6,
+ .buf = buf,
+ }
+ };
+ int ret;
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = i2c_transfer(client->adapter, msgs, 2);
+ if (ret == 2) {
+ dt->tm_year = buf[4] >> 6;
+ dt->tm_wday = buf[5] >> 5;
+
+ buf[4] &= 0x3f;
+ buf[5] &= 0x1f;
+
+ dt->tm_sec = BCD_TO_BIN(buf[1]);
+ dt->tm_min = BCD_TO_BIN(buf[2]);
+ dt->tm_hour = BCD_TO_BIN(buf[3]);
+ dt->tm_mday = BCD_TO_BIN(buf[4]);
+ dt->tm_mon = BCD_TO_BIN(buf[5]);
+ }
+
+ return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
+{
+ unsigned char buf[8];
+ int ret, len = 6;
+
+ buf[0] = 0;
+ buf[1] = get_ctrl(client) | 0x80;
+ buf[2] = 0;
+ buf[3] = BIN_TO_BCD(dt->tm_sec);
+ buf[4] = BIN_TO_BCD(dt->tm_min);
+ buf[5] = BIN_TO_BCD(dt->tm_hour);
+
+ if (datetoo) {
+ len = 8;
+ buf[6] = BIN_TO_BCD(dt->tm_mday) | (dt->tm_year << 6);
+ buf[7] = BIN_TO_BCD(dt->tm_mon) | (dt->tm_wday << 5);
+ }
+
+ ret = i2c_master_send(client, (char *)buf, len);
+ if (ret != len)
+ return -EIO;
+
+ buf[1] = get_ctrl(client);
+ ret = i2c_master_send(client, (char *)buf, 2);
+
+ return ret == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+ *ctrl = get_ctrl(client);
+ return 0;
+}
+
+static int pcf8583_set_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+ unsigned char buf[2];
+
+ buf[0] = 0;
+ buf[1] = *ctrl;
+ set_ctrl(client, *ctrl);
+
+ return i2c_master_send(client, (char *)buf, 2);
+}
+
+static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+ unsigned char addr[1];
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = mem->nr,
+ .buf = mem->data,
+ }
+ };
+
+ if (mem->loc < 8)
+ return -EINVAL;
+
+ addr[0] = mem->loc;
+
+ return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+ unsigned char addr[1];
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = addr,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_NOSTART,
+ .len = mem->nr,
+ .buf = mem->data,
+ }
+ };
+
+ if (mem->loc < 8)
+ return -EINVAL;
+
+ addr[0] = mem->loc;
+
+ return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char ctrl, year[2];
+ struct rtc_mem mem = { CMOS_YEAR, sizeof(year), year };
+ int real_year, year_offset, err;
+
+ /*
+ * Ensure that the RTC is running.
+ */
+ pcf8583_get_ctrl(client, &ctrl);
+ if (ctrl & (CTRL_STOP | CTRL_HOLD)) {
+ unsigned char new_ctrl = ctrl & ~(CTRL_STOP | CTRL_HOLD);
+
+ printk(KERN_WARNING "RTC: resetting control %02x -> %02x\n",
+ ctrl, new_ctrl);
+
+ if ((err = pcf8583_set_ctrl(client, &new_ctrl)) < 0)
+ return err;
+ }
+
+ if (pcf8583_get_datetime(client, tm) ||
+ pcf8583_read_mem(client, &mem))
+ return -EIO;
+
+ real_year = year[0];
+
+ /*
+ * The RTC year holds the LSB two bits of the current
+ * year, which should reflect the LSB two bits of the
+ * CMOS copy of the year. Any difference indicates
+ * that we have to correct the CMOS version.
+ */
+ year_offset = tm->tm_year - (real_year & 3);
+ if (year_offset < 0)
+ /*
+ * RTC year wrapped. Adjust it appropriately.
+ */
+ year_offset += 4;
+
+ tm->tm_year = real_year + year_offset + year[1] * 100;
+
+ return 0;
+}
+
+static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char year[2], chk;
+ struct rtc_mem cmos_year = { CMOS_YEAR, sizeof(year), year };
+ struct rtc_mem cmos_check = { CMOS_CHECKSUM, 1, &chk };
+ int ret;
+
+ /*
+ * The RTC's own 2-bit year must reflect the least
+ * significant two bits of the CMOS year.
+ */
+
+ ret = pcf8583_set_datetime(client, tm, 1);
+ if (ret)
+ return ret;
+
+ ret = pcf8583_read_mem(client, &cmos_check);
+ if (ret)
+ return ret;
+
+ ret = pcf8583_read_mem(client, &cmos_year);
+ if (ret)
+ return ret;
+
+ chk -= year[1] + year[0];
+
+ year[1] = tm->tm_year / 100;
+ year[0] = tm->tm_year % 100;
+
+ chk += year[1] + year[0];
+
+ ret = pcf8583_write_mem(client, &cmos_year);
+
+ if (ret)
+ return ret;
+
+ ret = pcf8583_write_mem(client, &cmos_check);
+
+ return ret;
+}
+
+static struct rtc_class_ops pcf8583_rtc_ops = {
+ .read_time = pcf8583_rtc_read_time,
+ .set_time = pcf8583_rtc_set_time,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind);
+
+static int pcf8583_attach(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, pcf8583_probe);
+}
+
+static int pcf8583_detach(struct i2c_client *client)
+{
+ int err;
+ struct pcf8583 *pcf = i2c_get_clientdata(client);
+ struct rtc_device *rtc = pcf->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ if ((err = i2c_detach_client(client)))
+ return err;
+
+ kfree(pcf);
+ return 0;
+}
+
+static struct i2c_driver pcf8583_driver = {
+ .driver = {
+ .name = "pcf8583",
+ },
+ .id = I2C_DRIVERID_PCF8583,
+ .attach_adapter = pcf8583_attach,
+ .detach_client = pcf8583_detach,
+};
+
+static int pcf8583_probe(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct pcf8583 *pcf;
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ unsigned char buf[1], ad[1] = { 0 };
+ int err;
+ struct i2c_msg msgs[2] = {
+ {
+ .addr = addr,
+ .flags = 0,
+ .len = 1,
+ .buf = ad,
+ }, {
+ .addr = addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = buf,
+ }
+ };
+
+ pcf = kzalloc(sizeof(*pcf), GFP_KERNEL);
+ if (!pcf)
+ return -ENOMEM;
+
+ client = &pcf->client;
+
+ client->addr = addr;
+ client->adapter = adap;
+ client->driver = &pcf8583_driver;
+
+ strlcpy(client->name, pcf8583_driver.driver.name, I2C_NAME_SIZE);
+
+ if (i2c_transfer(client->adapter, msgs, 2) != 2) {
+ err = -EIO;
+ goto exit_kfree;
+ }
+
+ err = i2c_attach_client(client);
+
+ if (err)
+ goto exit_kfree;
+
+ rtc = rtc_device_register(pcf8583_driver.driver.name, &client->dev,
+ &pcf8583_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ err = PTR_ERR(rtc);
+ goto exit_detach;
+ }
+
+ pcf->rtc = rtc;
+ i2c_set_clientdata(client, pcf);
+ set_ctrl(client, buf[0]);
+
+ return 0;
+
+exit_detach:
+ i2c_detach_client(client);
+
+exit_kfree:
+ kfree(pcf);
+
+ return err;
+}
+
+static __init int pcf8583_init(void)
+{
+ return i2c_add_driver(&pcf8583_driver);
+}
+
+static __exit void pcf8583_exit(void)
+{
+ i2c_del_driver(&pcf8583_driver);
+}
+
+module_init(pcf8583_init);
+module_exit(pcf8583_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("PCF8583 I2C RTC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
new file mode 100644
index 00000000000..d6d1c5726b0
--- /dev/null
+++ b/drivers/rtc/rtc-pl031.c
@@ -0,0 +1,233 @@
+/*
+ * drivers/rtc/rtc-pl031.c
+ *
+ * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2006 (c) MontaVista Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+
+#include <linux/amba/bus.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+/*
+ * Register definitions
+ */
+#define RTC_DR 0x00 /* Data read register */
+#define RTC_MR 0x04 /* Match register */
+#define RTC_LR 0x08 /* Data load register */
+#define RTC_CR 0x0c /* Control register */
+#define RTC_IMSC 0x10 /* Interrupt mask and set register */
+#define RTC_RIS 0x14 /* Raw interrupt status register */
+#define RTC_MIS 0x18 /* Masked interrupt status register */
+#define RTC_ICR 0x1c /* Interrupt clear register */
+
+struct pl031_local {
+ struct rtc_device *rtc;
+ void __iomem *base;
+};
+
+static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct rtc_device *rtc = dev_id;
+
+ rtc_update_irq(&rtc->class_dev, 1, RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static int pl031_open(struct device *dev)
+{
+ /*
+ * We request IRQ in pl031_probe, so nothing to do here...
+ */
+ return 0;
+}
+
+static void pl031_release(struct device *dev)
+{
+}
+
+static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ __raw_writel(1, ldata->base + RTC_MIS);
+ return 0;
+ case RTC_AIE_ON:
+ __raw_writel(0, ldata->base + RTC_MIS);
+ return 0;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int pl031_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm);
+
+ return 0;
+}
+
+static int pl031_set_time(struct device *dev, struct rtc_time *tm)
+{
+ unsigned long time;
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ rtc_tm_to_time(tm, &time);
+ __raw_writel(time, ldata->base + RTC_LR);
+
+ return 0;
+}
+
+static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+
+ rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time);
+ alarm->pending = __raw_readl(ldata->base + RTC_RIS);
+ alarm->enabled = __raw_readl(ldata->base + RTC_IMSC);
+
+ return 0;
+}
+
+static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct pl031_local *ldata = dev_get_drvdata(dev);
+ unsigned long time;
+
+ rtc_tm_to_time(&alarm->time, &time);
+
+ __raw_writel(time, ldata->base + RTC_MR);
+ __raw_writel(!alarm->enabled, ldata->base + RTC_MIS);
+
+ return 0;
+}
+
+static struct rtc_class_ops pl031_ops = {
+ .open = pl031_open,
+ .release = pl031_release,
+ .ioctl = pl031_ioctl,
+ .read_time = pl031_read_time,
+ .set_time = pl031_set_time,
+ .read_alarm = pl031_read_alarm,
+ .set_alarm = pl031_set_alarm,
+};
+
+static int pl031_remove(struct amba_device *adev)
+{
+ struct pl031_local *ldata = dev_get_drvdata(&adev->dev);
+
+ if (ldata) {
+ dev_set_drvdata(&adev->dev, NULL);
+ free_irq(adev->irq[0], ldata->rtc);
+ rtc_device_unregister(ldata->rtc);
+ iounmap(ldata->base);
+ kfree(ldata);
+ }
+
+ return 0;
+}
+
+static int pl031_probe(struct amba_device *adev, void *id)
+{
+ int ret;
+ struct pl031_local *ldata;
+
+
+ ldata = kmalloc(sizeof(struct pl031_local), GFP_KERNEL);
+ if (!ldata) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ dev_set_drvdata(&adev->dev, ldata);
+
+ ldata->base = ioremap(adev->res.start,
+ adev->res.end - adev->res.start + 1);
+ if (!ldata->base) {
+ ret = -ENOMEM;
+ goto out_no_remap;
+ }
+
+ if (request_irq(adev->irq[0], pl031_interrupt, IRQF_DISABLED,
+ "rtc-pl031", ldata->rtc)) {
+ ret = -EIO;
+ goto out_no_irq;
+ }
+
+ ldata->rtc = rtc_device_register("pl031", &adev->dev, &pl031_ops,
+ THIS_MODULE);
+ if (IS_ERR(ldata->rtc)) {
+ ret = PTR_ERR(ldata->rtc);
+ goto out_no_rtc;
+ }
+
+ return 0;
+
+out_no_rtc:
+ free_irq(adev->irq[0], ldata->rtc);
+out_no_irq:
+ iounmap(ldata->base);
+out_no_remap:
+ dev_set_drvdata(&adev->dev, NULL);
+ kfree(ldata);
+out:
+ return ret;
+}
+
+static struct amba_id pl031_ids[] __initdata = {
+ {
+ .id = 0x00041031,
+ .mask = 0x000fffff, },
+ {0, 0},
+};
+
+static struct amba_driver pl031_driver = {
+ .drv = {
+ .name = "rtc-pl031",
+ },
+ .id_table = pl031_ids,
+ .probe = pl031_probe,
+ .remove = pl031_remove,
+};
+
+static int __init pl031_init(void)
+{
+ return amba_driver_register(&pl031_driver);
+}
+
+static void __exit pl031_exit(void)
+{
+ amba_driver_unregister(&pl031_driver);
+}
+
+module_init(pl031_init);
+module_exit(pl031_exit);
+
+MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
+MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
new file mode 100644
index 00000000000..25589061f93
--- /dev/null
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -0,0 +1,253 @@
+/*
+ * A SPI driver for the Ricoh RS5C348 RTC
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * 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.
+ *
+ * The board specific init code should provide characteristics of this
+ * device:
+ * Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS
+ */
+
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/rtc.h>
+#include <linux/workqueue.h>
+#include <linux/spi/spi.h>
+
+#define DRV_VERSION "0.2"
+
+#define RS5C348_REG_SECS 0
+#define RS5C348_REG_MINS 1
+#define RS5C348_REG_HOURS 2
+#define RS5C348_REG_WDAY 3
+#define RS5C348_REG_DAY 4
+#define RS5C348_REG_MONTH 5
+#define RS5C348_REG_YEAR 6
+#define RS5C348_REG_CTL1 14
+#define RS5C348_REG_CTL2 15
+
+#define RS5C348_SECS_MASK 0x7f
+#define RS5C348_MINS_MASK 0x7f
+#define RS5C348_HOURS_MASK 0x3f
+#define RS5C348_WDAY_MASK 0x03
+#define RS5C348_DAY_MASK 0x3f
+#define RS5C348_MONTH_MASK 0x1f
+
+#define RS5C348_BIT_PM 0x20 /* REG_HOURS */
+#define RS5C348_BIT_Y2K 0x80 /* REG_MONTH */
+#define RS5C348_BIT_24H 0x20 /* REG_CTL1 */
+#define RS5C348_BIT_XSTP 0x10 /* REG_CTL2 */
+#define RS5C348_BIT_VDET 0x40 /* REG_CTL2 */
+
+#define RS5C348_CMD_W(addr) (((addr) << 4) | 0x08) /* single write */
+#define RS5C348_CMD_R(addr) (((addr) << 4) | 0x0c) /* single read */
+#define RS5C348_CMD_MW(addr) (((addr) << 4) | 0x00) /* burst write */
+#define RS5C348_CMD_MR(addr) (((addr) << 4) | 0x04) /* burst read */
+
+struct rs5c348_plat_data {
+ struct rtc_device *rtc;
+ int rtc_24h;
+};
+
+static int
+rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+ u8 txbuf[5+7], *txp;
+ int ret;
+
+ /* Transfer 5 bytes before writing SEC. This gives 31us for carry. */
+ txp = txbuf;
+ txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+ txbuf[1] = 0; /* dummy */
+ txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+ txbuf[3] = 0; /* dummy */
+ txbuf[4] = RS5C348_CMD_MW(RS5C348_REG_SECS); /* cmd, sec, ... */
+ txp = &txbuf[5];
+ txp[RS5C348_REG_SECS] = BIN2BCD(tm->tm_sec);
+ txp[RS5C348_REG_MINS] = BIN2BCD(tm->tm_min);
+ if (pdata->rtc_24h) {
+ txp[RS5C348_REG_HOURS] = BIN2BCD(tm->tm_hour);
+ } else {
+ /* hour 0 is AM12, noon is PM12 */
+ txp[RS5C348_REG_HOURS] = BIN2BCD((tm->tm_hour + 11) % 12 + 1) |
+ (tm->tm_hour >= 12 ? RS5C348_BIT_PM : 0);
+ }
+ txp[RS5C348_REG_WDAY] = BIN2BCD(tm->tm_wday);
+ txp[RS5C348_REG_DAY] = BIN2BCD(tm->tm_mday);
+ txp[RS5C348_REG_MONTH] = BIN2BCD(tm->tm_mon + 1) |
+ (tm->tm_year >= 100 ? RS5C348_BIT_Y2K : 0);
+ txp[RS5C348_REG_YEAR] = BIN2BCD(tm->tm_year % 100);
+ /* write in one transfer to avoid data inconsistency */
+ ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), NULL, 0);
+ udelay(62); /* Tcsr 62us */
+ return ret;
+}
+
+static int
+rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+ u8 txbuf[5], rxbuf[7];
+ int ret;
+
+ /* Transfer 5 byte befores reading SEC. This gives 31us for carry. */
+ txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+ txbuf[1] = 0; /* dummy */
+ txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
+ txbuf[3] = 0; /* dummy */
+ txbuf[4] = RS5C348_CMD_MR(RS5C348_REG_SECS); /* cmd, sec, ... */
+
+ /* read in one transfer to avoid data inconsistency */
+ ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
+ rxbuf, sizeof(rxbuf));
+ udelay(62); /* Tcsr 62us */
+ if (ret < 0)
+ return ret;
+
+ tm->tm_sec = BCD2BIN(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK);
+ tm->tm_min = BCD2BIN(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
+ tm->tm_hour = BCD2BIN(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
+ if (!pdata->rtc_24h) {
+ tm->tm_hour %= 12;
+ if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM)
+ tm->tm_hour += 12;
+ }
+ tm->tm_wday = BCD2BIN(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
+ tm->tm_mday = BCD2BIN(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
+ tm->tm_mon =
+ BCD2BIN(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1;
+ /* year is 1900 + tm->tm_year */
+ tm->tm_year = BCD2BIN(rxbuf[RS5C348_REG_YEAR]) +
+ ((rxbuf[RS5C348_REG_MONTH] & RS5C348_BIT_Y2K) ? 100 : 0);
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(&spi->dev, "retrieved date/time is not valid.\n");
+ rtc_time_to_tm(0, tm);
+ }
+
+ return 0;
+}
+
+static struct rtc_class_ops rs5c348_rtc_ops = {
+ .read_time = rs5c348_rtc_read_time,
+ .set_time = rs5c348_rtc_set_time,
+};
+
+static struct spi_driver rs5c348_driver;
+
+static int __devinit rs5c348_probe(struct spi_device *spi)
+{
+ int ret;
+ struct rtc_device *rtc;
+ struct rs5c348_plat_data *pdata;
+
+ pdata = kzalloc(sizeof(struct rs5c348_plat_data), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ spi->dev.platform_data = pdata;
+
+ /* Check D7 of SECOND register */
+ ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS));
+ if (ret < 0 || (ret & 0x80)) {
+ dev_err(&spi->dev, "not found.\n");
+ goto kfree_exit;
+ }
+
+ dev_info(&spi->dev, "chip found, driver version " DRV_VERSION "\n");
+ dev_info(&spi->dev, "spiclk %u KHz.\n",
+ (spi->max_speed_hz + 500) / 1000);
+
+ /* turn RTC on if it was not on */
+ ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
+ if (ret < 0)
+ goto kfree_exit;
+ if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
+ u8 buf[2];
+ struct rtc_time tm;
+ if (ret & RS5C348_BIT_VDET)
+ dev_warn(&spi->dev, "voltage-low detected.\n");
+ if (ret & RS5C348_BIT_XSTP)
+ dev_warn(&spi->dev, "oscillator-stop detected.\n");
+ rtc_time_to_tm(0, &tm); /* 1970/1/1 */
+ ret = rs5c348_rtc_set_time(&spi->dev, &tm);
+ if (ret < 0)
+ goto kfree_exit;
+ buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
+ buf[1] = 0;
+ ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
+ if (ret < 0)
+ goto kfree_exit;
+ }
+
+ ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
+ if (ret < 0)
+ goto kfree_exit;
+ if (ret & RS5C348_BIT_24H)
+ pdata->rtc_24h = 1;
+
+ rtc = rtc_device_register(rs5c348_driver.driver.name, &spi->dev,
+ &rs5c348_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto kfree_exit;
+ }
+
+ pdata->rtc = rtc;
+
+ return 0;
+ kfree_exit:
+ kfree(pdata);
+ return ret;
+}
+
+static int __devexit rs5c348_remove(struct spi_device *spi)
+{
+ struct rs5c348_plat_data *pdata = spi->dev.platform_data;
+ struct rtc_device *rtc = pdata->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+ kfree(pdata);
+ return 0;
+}
+
+static struct spi_driver rs5c348_driver = {
+ .driver = {
+ .name = "rs5c348",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = rs5c348_probe,
+ .remove = __devexit_p(rs5c348_remove),
+};
+
+static __init int rs5c348_init(void)
+{
+ return spi_register_driver(&rs5c348_driver);
+}
+
+static __exit void rs5c348_exit(void)
+{
+ spi_unregister_driver(&rs5c348_driver);
+}
+
+module_init(rs5c348_init);
+module_exit(rs5c348_exit);
+
+MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
+MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
new file mode 100644
index 00000000000..2c7de79c83b
--- /dev/null
+++ b/drivers/rtc/rtc-s3c.c
@@ -0,0 +1,621 @@
+/* drivers/rtc/rtc-s3c.c
+ *
+ * Copyright (c) 2004,2006 Simtec Electronics
+ * Ben Dooks, <ben@simtec.co.uk>
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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.
+ *
+ * S3C2410/S3C2440/S3C24XX Internal RTC Driver
+*/
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/clk.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+
+#include <asm/arch/regs-rtc.h>
+
+/* I have yet to find an S3C implementation with more than one
+ * of these rtc blocks in */
+
+static struct resource *s3c_rtc_mem;
+
+static void __iomem *s3c_rtc_base;
+static int s3c_rtc_alarmno = NO_IRQ;
+static int s3c_rtc_tickno = NO_IRQ;
+static int s3c_rtc_freq = 1;
+
+static DEFINE_SPINLOCK(s3c_rtc_pie_lock);
+static unsigned int tick_count;
+
+/* IRQ Handlers */
+
+static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
+{
+ struct rtc_device *rdev = id;
+
+ rtc_update_irq(&rdev->class_dev, 1, RTC_AF | RTC_IRQF);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c_rtc_tickirq(int irq, void *id, struct pt_regs *r)
+{
+ struct rtc_device *rdev = id;
+
+ rtc_update_irq(&rdev->class_dev, tick_count++, RTC_PF | RTC_IRQF);
+ return IRQ_HANDLED;
+}
+
+/* Update control registers */
+static void s3c_rtc_setaie(int to)
+{
+ unsigned int tmp;
+
+ pr_debug("%s: aie=%d\n", __FUNCTION__, to);
+
+ tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
+
+ if (to)
+ tmp |= S3C2410_RTCALM_ALMEN;
+
+ writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
+}
+
+static void s3c_rtc_setpie(int to)
+{
+ unsigned int tmp;
+
+ pr_debug("%s: pie=%d\n", __FUNCTION__, to);
+
+ spin_lock_irq(&s3c_rtc_pie_lock);
+ tmp = readb(s3c_rtc_base + S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
+
+ if (to)
+ tmp |= S3C2410_TICNT_ENABLE;
+
+ writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
+ spin_unlock_irq(&s3c_rtc_pie_lock);
+}
+
+static void s3c_rtc_setfreq(int freq)
+{
+ unsigned int tmp;
+
+ spin_lock_irq(&s3c_rtc_pie_lock);
+ tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
+
+ s3c_rtc_freq = freq;
+
+ tmp |= (128 / freq)-1;
+
+ writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
+ spin_unlock_irq(&s3c_rtc_pie_lock);
+}
+
+/* Time read/write */
+
+static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+{
+ unsigned int have_retried = 0;
+ void __iomem *base = s3c_rtc_base;
+
+ retry_get_time:
+ rtc_tm->tm_min = readb(base + S3C2410_RTCMIN);
+ rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
+ rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
+ rtc_tm->tm_mon = readb(base + S3C2410_RTCMON);
+ rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
+ rtc_tm->tm_sec = readb(base + S3C2410_RTCSEC);
+
+ /* the only way to work out wether the system was mid-update
+ * when we read it is to check the second counter, and if it
+ * is zero, then we re-try the entire read
+ */
+
+ if (rtc_tm->tm_sec == 0 && !have_retried) {
+ have_retried = 1;
+ goto retry_get_time;
+ }
+
+ pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
+ rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
+ BCD_TO_BIN(rtc_tm->tm_sec);
+ BCD_TO_BIN(rtc_tm->tm_min);
+ BCD_TO_BIN(rtc_tm->tm_hour);
+ BCD_TO_BIN(rtc_tm->tm_mday);
+ BCD_TO_BIN(rtc_tm->tm_mon);
+ BCD_TO_BIN(rtc_tm->tm_year);
+
+ rtc_tm->tm_year += 100;
+ rtc_tm->tm_mon -= 1;
+
+ return 0;
+}
+
+static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ void __iomem *base = s3c_rtc_base;
+ int year = tm->tm_year - 100;
+
+ pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ /* we get around y2k by simply not supporting it */
+
+ if (year < 0 || year >= 100) {
+ dev_err(dev, "rtc only supports 100 years\n");
+ return -EINVAL;
+ }
+
+ writeb(BIN2BCD(tm->tm_sec), base + S3C2410_RTCSEC);
+ writeb(BIN2BCD(tm->tm_min), base + S3C2410_RTCMIN);
+ writeb(BIN2BCD(tm->tm_hour), base + S3C2410_RTCHOUR);
+ writeb(BIN2BCD(tm->tm_mday), base + S3C2410_RTCDATE);
+ writeb(BIN2BCD(tm->tm_mon + 1), base + S3C2410_RTCMON);
+ writeb(BIN2BCD(year), base + S3C2410_RTCYEAR);
+
+ return 0;
+}
+
+static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time *alm_tm = &alrm->time;
+ void __iomem *base = s3c_rtc_base;
+ unsigned int alm_en;
+
+ alm_tm->tm_sec = readb(base + S3C2410_ALMSEC);
+ alm_tm->tm_min = readb(base + S3C2410_ALMMIN);
+ alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
+ alm_tm->tm_mon = readb(base + S3C2410_ALMMON);
+ alm_tm->tm_mday = readb(base + S3C2410_ALMDATE);
+ alm_tm->tm_year = readb(base + S3C2410_ALMYEAR);
+
+ alm_en = readb(base + S3C2410_RTCALM);
+
+ pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
+ alm_en,
+ alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+ alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+
+
+ /* decode the alarm enable field */
+
+ if (alm_en & S3C2410_RTCALM_SECEN)
+ BCD_TO_BIN(alm_tm->tm_sec);
+ else
+ alm_tm->tm_sec = 0xff;
+
+ if (alm_en & S3C2410_RTCALM_MINEN)
+ BCD_TO_BIN(alm_tm->tm_min);
+ else
+ alm_tm->tm_min = 0xff;
+
+ if (alm_en & S3C2410_RTCALM_HOUREN)
+ BCD_TO_BIN(alm_tm->tm_hour);
+ else
+ alm_tm->tm_hour = 0xff;
+
+ if (alm_en & S3C2410_RTCALM_DAYEN)
+ BCD_TO_BIN(alm_tm->tm_mday);
+ else
+ alm_tm->tm_mday = 0xff;
+
+ if (alm_en & S3C2410_RTCALM_MONEN) {
+ BCD_TO_BIN(alm_tm->tm_mon);
+ alm_tm->tm_mon -= 1;
+ } else {
+ alm_tm->tm_mon = 0xff;
+ }
+
+ if (alm_en & S3C2410_RTCALM_YEAREN)
+ BCD_TO_BIN(alm_tm->tm_year);
+ else
+ alm_tm->tm_year = 0xffff;
+
+ return 0;
+}
+
+static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time *tm = &alrm->time;
+ void __iomem *base = s3c_rtc_base;
+ unsigned int alrm_en;
+
+ pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
+ alrm->enabled,
+ tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
+ tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
+
+
+ alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
+ writeb(0x00, base + S3C2410_RTCALM);
+
+ if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
+ alrm_en |= S3C2410_RTCALM_SECEN;
+ writeb(BIN2BCD(tm->tm_sec), base + S3C2410_ALMSEC);
+ }
+
+ if (tm->tm_min < 60 && tm->tm_min >= 0) {
+ alrm_en |= S3C2410_RTCALM_MINEN;
+ writeb(BIN2BCD(tm->tm_min), base + S3C2410_ALMMIN);
+ }
+
+ if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
+ alrm_en |= S3C2410_RTCALM_HOUREN;
+ writeb(BIN2BCD(tm->tm_hour), base + S3C2410_ALMHOUR);
+ }
+
+ pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
+
+ writeb(alrm_en, base + S3C2410_RTCALM);
+
+ if (0) {
+ alrm_en = readb(base + S3C2410_RTCALM);
+ alrm_en &= ~S3C2410_RTCALM_ALMEN;
+ writeb(alrm_en, base + S3C2410_RTCALM);
+ disable_irq_wake(s3c_rtc_alarmno);
+ }
+
+ if (alrm->enabled)
+ enable_irq_wake(s3c_rtc_alarmno);
+ else
+ disable_irq_wake(s3c_rtc_alarmno);
+
+ return 0;
+}
+
+static int s3c_rtc_ioctl(struct device *dev,
+ unsigned int cmd, unsigned long arg)
+{
+ unsigned int ret = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ s3c_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
+ ret = 0;
+ break;
+
+ case RTC_PIE_OFF:
+ case RTC_PIE_ON:
+ tick_count = 0;
+ s3c_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
+ ret = 0;
+ break;
+
+ case RTC_IRQP_READ:
+ ret = put_user(s3c_rtc_freq, (unsigned long __user *)arg);
+ break;
+
+ case RTC_IRQP_SET:
+ /* check for power of 2 */
+
+ if ((arg & (arg-1)) != 0 || arg < 1) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
+
+ s3c_rtc_setfreq(arg);
+ ret = 0;
+ break;
+
+ case RTC_UIE_ON:
+ case RTC_UIE_OFF:
+ ret = -EINVAL;
+ }
+
+ exit:
+ return ret;
+}
+
+static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ unsigned int rtcalm = readb(s3c_rtc_base + S3C2410_RTCALM);
+ unsigned int ticnt = readb(s3c_rtc_base + S3C2410_TICNT);
+
+ seq_printf(seq, "alarm_IRQ\t: %s\n",
+ (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
+
+ seq_printf(seq, "periodic_IRQ\t: %s\n",
+ (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
+
+ seq_printf(seq, "periodic_freq\t: %d\n", s3c_rtc_freq);
+
+ return 0;
+}
+
+static int s3c_rtc_open(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
+ SA_INTERRUPT, "s3c2410-rtc alarm", rtc_dev);
+
+ if (ret) {
+ dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
+ return ret;
+ }
+
+ ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
+ SA_INTERRUPT, "s3c2410-rtc tick", rtc_dev);
+
+ if (ret) {
+ dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
+ goto tick_err;
+ }
+
+ return ret;
+
+ tick_err:
+ free_irq(s3c_rtc_alarmno, rtc_dev);
+ return ret;
+}
+
+static void s3c_rtc_release(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
+
+ /* do not clear AIE here, it may be needed for wake */
+
+ s3c_rtc_setpie(0);
+ free_irq(s3c_rtc_alarmno, rtc_dev);
+ free_irq(s3c_rtc_tickno, rtc_dev);
+}
+
+static struct rtc_class_ops s3c_rtcops = {
+ .open = s3c_rtc_open,
+ .release = s3c_rtc_release,
+ .ioctl = s3c_rtc_ioctl,
+ .read_time = s3c_rtc_gettime,
+ .set_time = s3c_rtc_settime,
+ .read_alarm = s3c_rtc_getalarm,
+ .set_alarm = s3c_rtc_setalarm,
+ .proc = s3c_rtc_proc,
+};
+
+static void s3c_rtc_enable(struct platform_device *pdev, int en)
+{
+ void __iomem *base = s3c_rtc_base;
+ unsigned int tmp;
+
+ if (s3c_rtc_base == NULL)
+ return;
+
+ if (!en) {
+ tmp = readb(base + S3C2410_RTCCON);
+ writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
+
+ tmp = readb(base + S3C2410_TICNT);
+ writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
+ } else {
+ /* re-enable the device, and check it is ok */
+
+ if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
+ dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
+
+ tmp = readb(base + S3C2410_RTCCON);
+ writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON);
+ }
+
+ if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
+ dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
+
+ tmp = readb(base + S3C2410_RTCCON);
+ writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON);
+ }
+
+ if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
+ dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
+
+ tmp = readb(base + S3C2410_RTCCON);
+ writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON);
+ }
+ }
+}
+
+static int s3c_rtc_remove(struct platform_device *dev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ platform_set_drvdata(dev, NULL);
+ rtc_device_unregister(rtc);
+
+ s3c_rtc_setpie(0);
+ s3c_rtc_setaie(0);
+
+ iounmap(s3c_rtc_base);
+ release_resource(s3c_rtc_mem);
+ kfree(s3c_rtc_mem);
+
+ return 0;
+}
+
+static int s3c_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ int ret;
+
+ pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
+
+ /* find the IRQs */
+
+ s3c_rtc_tickno = platform_get_irq(pdev, 1);
+ if (s3c_rtc_tickno < 0) {
+ dev_err(&pdev->dev, "no irq for rtc tick\n");
+ return -ENOENT;
+ }
+
+ s3c_rtc_alarmno = platform_get_irq(pdev, 0);
+ if (s3c_rtc_alarmno < 0) {
+ dev_err(&pdev->dev, "no irq for alarm\n");
+ return -ENOENT;
+ }
+
+ pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
+ s3c_rtc_tickno, s3c_rtc_alarmno);
+
+ /* get the memory region */
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to get memory region resource\n");
+ return -ENOENT;
+ }
+
+ s3c_rtc_mem = request_mem_region(res->start,
+ res->end-res->start+1,
+ pdev->name);
+
+ if (s3c_rtc_mem == NULL) {
+ dev_err(&pdev->dev, "failed to reserve memory region\n");
+ ret = -ENOENT;
+ goto err_nores;
+ }
+
+ s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);
+ if (s3c_rtc_base == NULL) {
+ dev_err(&pdev->dev, "failed ioremap()\n");
+ ret = -EINVAL;
+ goto err_nomap;
+ }
+
+ /* check to see if everything is setup correctly */
+
+ s3c_rtc_enable(pdev, 1);
+
+ pr_debug("s3c2410_rtc: RTCCON=%02x\n",
+ readb(s3c_rtc_base + S3C2410_RTCCON));
+
+ s3c_rtc_setfreq(s3c_rtc_freq);
+
+ /* register RTC and exit */
+
+ rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
+ THIS_MODULE);
+
+ if (IS_ERR(rtc)) {
+ dev_err(&pdev->dev, "cannot attach rtc\n");
+ ret = PTR_ERR(rtc);
+ goto err_nortc;
+ }
+
+ rtc->max_user_freq = 128;
+
+ platform_set_drvdata(pdev, rtc);
+ return 0;
+
+ err_nortc:
+ s3c_rtc_enable(pdev, 0);
+ iounmap(s3c_rtc_base);
+
+ err_nomap:
+ release_resource(s3c_rtc_mem);
+
+ err_nores:
+ return ret;
+}
+
+#ifdef CONFIG_PM
+
+/* RTC Power management control */
+
+static struct timespec s3c_rtc_delta;
+
+static int ticnt_save;
+
+static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct rtc_time tm;
+ struct timespec time;
+
+ time.tv_nsec = 0;
+
+ /* save TICNT for anyone using periodic interrupts */
+
+ ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);
+
+ /* calculate time delta for suspend */
+
+ s3c_rtc_gettime(&pdev->dev, &tm);
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ save_time_delta(&s3c_rtc_delta, &time);
+ s3c_rtc_enable(pdev, 0);
+
+ return 0;
+}
+
+static int s3c_rtc_resume(struct platform_device *pdev)
+{
+ struct rtc_time tm;
+ struct timespec time;
+
+ time.tv_nsec = 0;
+
+ s3c_rtc_enable(pdev, 1);
+ s3c_rtc_gettime(&pdev->dev, &tm);
+ rtc_tm_to_time(&tm, &time.tv_sec);
+ restore_time_delta(&s3c_rtc_delta, &time);
+
+ writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);
+ return 0;
+}
+#else
+#define s3c_rtc_suspend NULL
+#define s3c_rtc_resume NULL
+#endif
+
+static struct platform_driver s3c2410_rtcdrv = {
+ .probe = s3c_rtc_probe,
+ .remove = s3c_rtc_remove,
+ .suspend = s3c_rtc_suspend,
+ .resume = s3c_rtc_resume,
+ .driver = {
+ .name = "s3c2410-rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";
+
+static int __init s3c_rtc_init(void)
+{
+ printk(banner);
+ return platform_driver_register(&s3c2410_rtcdrv);
+}
+
+static void __exit s3c_rtc_exit(void)
+{
+ platform_driver_unregister(&s3c2410_rtcdrv);
+}
+
+module_init(s3c_rtc_init);
+module_exit(s3c_rtc_exit);
+
+MODULE_DESCRIPTION("Samsung S3C RTC Driver");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index a997529f892..ee4b61ee67b 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -45,7 +45,7 @@
static unsigned long rtc_freq = 1024;
static struct rtc_time rtc_alarm;
-static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(sa1100_rtc_lock);
static int rtc_update_alarm(struct rtc_time *alrm)
{
@@ -157,19 +157,19 @@ static int sa1100_rtc_open(struct device *dev)
{
int ret;
- ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT,
+ ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, IRQF_DISABLED,
"rtc 1Hz", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz);
goto fail_ui;
}
- ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT,
+ ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, IRQF_DISABLED,
"rtc Alrm", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm);
goto fail_ai;
}
- ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT,
+ ret = request_irq(IRQ_OST1, timer1_interrupt, IRQF_DISABLED,
"rtc timer", dev);
if (ret) {
dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1);
@@ -229,8 +229,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
spin_unlock_irq(&sa1100_rtc_lock);
return 0;
case RTC_PIE_ON:
- if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
- return -EACCES;
spin_lock_irq(&sa1100_rtc_lock);
OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
OIER |= OIER_E1;
@@ -242,8 +240,6 @@ static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
case RTC_IRQP_SET:
if (arg < 1 || arg > TIMER_FREQ)
return -EINVAL;
- if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
- return -EACCES;
rtc_freq = arg;
return 0;
}
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
new file mode 100644
index 00000000000..d2ce0c8bb8f
--- /dev/null
+++ b/drivers/rtc/rtc-sh.c
@@ -0,0 +1,467 @@
+/*
+ * SuperH On-Chip RTC Support
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * Based on the old arch/sh/kernel/cpu/rtc.c by:
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_CPU_SH3
+#define rtc_reg_size sizeof(u16)
+#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
+#elif defined(CONFIG_CPU_SH4)
+#define rtc_reg_size sizeof(u32)
+#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
+#endif
+
+#define RTC_REG(r) ((r) * rtc_reg_size)
+
+#define R64CNT RTC_REG(0)
+#define RSECCNT RTC_REG(1)
+#define RMINCNT RTC_REG(2)
+#define RHRCNT RTC_REG(3)
+#define RWKCNT RTC_REG(4)
+#define RDAYCNT RTC_REG(5)
+#define RMONCNT RTC_REG(6)
+#define RYRCNT RTC_REG(7)
+#define RSECAR RTC_REG(8)
+#define RMINAR RTC_REG(9)
+#define RHRAR RTC_REG(10)
+#define RWKAR RTC_REG(11)
+#define RDAYAR RTC_REG(12)
+#define RMONAR RTC_REG(13)
+#define RCR1 RTC_REG(14)
+#define RCR2 RTC_REG(15)
+
+/* RCR1 Bits */
+#define RCR1_CF 0x80 /* Carry Flag */
+#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
+#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
+#define RCR1_AF 0x01 /* Alarm Flag */
+
+/* RCR2 Bits */
+#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
+#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
+#define RCR2_RTCEN 0x08 /* ENable RTC */
+#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
+#define RCR2_RESET 0x02 /* Reset bit */
+#define RCR2_START 0x01 /* Start bit */
+
+struct sh_rtc {
+ void __iomem *regbase;
+ unsigned long regsize;
+ struct resource *res;
+ unsigned int alarm_irq, periodic_irq, carry_irq;
+ struct rtc_device *rtc_dev;
+ spinlock_t lock;
+};
+
+static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs)
+{
+ struct platform_device *pdev = id;
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int tmp, events = 0;
+
+ spin_lock(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+
+ if (tmp & RCR1_AF)
+ events |= RTC_AF | RTC_IRQF;
+
+ tmp &= ~(RCR1_CF | RCR1_AF);
+
+ writeb(tmp, rtc->regbase + RCR1);
+
+ rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+
+ spin_unlock(&rtc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(id);
+
+ spin_lock(&rtc->lock);
+
+ rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF);
+
+ spin_unlock(&rtc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static inline void sh_rtc_setpie(struct device *dev, unsigned int enable)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR2);
+
+ if (enable) {
+ tmp &= ~RCR2_PESMASK;
+ tmp |= RCR2_PEF | (2 << 4);
+ } else
+ tmp &= ~(RCR2_PESMASK | RCR2_PEF);
+
+ writeb(tmp, rtc->regbase + RCR2);
+
+ spin_unlock_irq(&rtc->lock);
+}
+
+static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+
+ if (enable)
+ tmp |= RCR1_AIE;
+ else
+ tmp &= ~RCR1_AIE;
+
+ writeb(tmp, rtc->regbase + RCR1);
+
+ spin_unlock_irq(&rtc->lock);
+}
+
+static int sh_rtc_open(struct device *dev)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+ int ret;
+
+ tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~RCR1_CF;
+ tmp |= RCR1_CIE;
+ writeb(tmp, rtc->regbase + RCR1);
+
+ ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, SA_INTERRUPT,
+ "sh-rtc period", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request period IRQ failed with %d, IRQ %d\n",
+ ret, rtc->periodic_irq);
+ return ret;
+ }
+
+ ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, SA_INTERRUPT,
+ "sh-rtc carry", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n",
+ ret, rtc->carry_irq);
+ free_irq(rtc->periodic_irq, dev);
+ goto err_bad_carry;
+ }
+
+ ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT,
+ "sh-rtc alarm", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
+ ret, rtc->alarm_irq);
+ goto err_bad_alarm;
+ }
+
+ return 0;
+
+err_bad_alarm:
+ free_irq(rtc->carry_irq, dev);
+err_bad_carry:
+ free_irq(rtc->periodic_irq, dev);
+
+ return ret;
+}
+
+static void sh_rtc_release(struct device *dev)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+
+ sh_rtc_setpie(dev, 0);
+
+ free_irq(rtc->periodic_irq, dev);
+ free_irq(rtc->carry_irq, dev);
+ free_irq(rtc->alarm_irq, dev);
+}
+
+static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+
+ tmp = readb(rtc->regbase + RCR1);
+ seq_printf(seq, "alarm_IRQ\t: %s\n",
+ (tmp & RCR1_AIE) ? "yes" : "no");
+ seq_printf(seq, "carry_IRQ\t: %s\n",
+ (tmp & RCR1_CIE) ? "yes" : "no");
+
+ tmp = readb(rtc->regbase + RCR2);
+ seq_printf(seq, "periodic_IRQ\t: %s\n",
+ (tmp & RCR2_PEF) ? "yes" : "no");
+
+ return 0;
+}
+
+static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ unsigned int ret = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case RTC_PIE_OFF:
+ case RTC_PIE_ON:
+ sh_rtc_setpie(dev, cmd == RTC_PIE_ON);
+ ret = 0;
+ break;
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int sec128, sec2, yr, yr100, cf_bit;
+
+ do {
+ unsigned int tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~RCR1_CF; /* Clear CF-bit */
+ tmp |= RCR1_CIE;
+ writeb(tmp, rtc->regbase + RCR1);
+
+ sec128 = readb(rtc->regbase + R64CNT);
+
+ tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
+ tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
+ tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
+ tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
+ tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
+ tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT));
+
+#if defined(CONFIG_CPU_SH4)
+ yr = readw(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN(yr >> 8);
+ yr &= 0xff;
+#else
+ yr = readb(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+#endif
+
+ tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
+
+ sec2 = readb(rtc->regbase + R64CNT);
+ cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF;
+
+ spin_unlock_irq(&rtc->lock);
+ } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
+
+#if RTC_BIT_INVERTED != 0
+ if ((sec128 & RTC_BIT_INVERTED))
+ tm->tm_sec--;
+#endif
+
+ dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __FUNCTION__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ if (rtc_valid_tm(tm) < 0)
+ dev_err(dev, "invalid date\n");
+
+ return 0;
+}
+
+static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int tmp;
+ int year;
+
+ spin_lock_irq(&rtc->lock);
+
+ /* Reset pre-scaler & stop RTC */
+ tmp = readb(rtc->regbase + RCR2);
+ tmp |= RCR2_RESET;
+ writeb(tmp, rtc->regbase + RCR2);
+
+ writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
+ writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
+ writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
+ writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
+ writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
+ writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT);
+
+#ifdef CONFIG_CPU_SH3
+ year = tm->tm_year % 100;
+ writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+#else
+ year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
+ BIN2BCD(tm->tm_year % 100);
+ writew(year, rtc->regbase + RYRCNT);
+#endif
+
+ /* Start RTC */
+ tmp = readb(rtc->regbase + RCR2);
+ tmp &= ~RCR2_RESET;
+ tmp |= RCR2_RTCEN | RCR2_START;
+ writeb(tmp, rtc->regbase + RCR2);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static struct rtc_class_ops sh_rtc_ops = {
+ .open = sh_rtc_open,
+ .release = sh_rtc_release,
+ .ioctl = sh_rtc_ioctl,
+ .read_time = sh_rtc_read_time,
+ .set_time = sh_rtc_set_time,
+ .proc = sh_rtc_proc,
+};
+
+static int __devinit sh_rtc_probe(struct platform_device *pdev)
+{
+ struct sh_rtc *rtc;
+ struct resource *res;
+ int ret = -ENOENT;
+
+ rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
+ if (unlikely(!rtc))
+ return -ENOMEM;
+
+ spin_lock_init(&rtc->lock);
+
+ rtc->periodic_irq = platform_get_irq(pdev, 0);
+ if (unlikely(rtc->periodic_irq < 0)) {
+ dev_err(&pdev->dev, "No IRQ for period\n");
+ goto err_badres;
+ }
+
+ rtc->carry_irq = platform_get_irq(pdev, 1);
+ if (unlikely(rtc->carry_irq < 0)) {
+ dev_err(&pdev->dev, "No IRQ for carry\n");
+ goto err_badres;
+ }
+
+ rtc->alarm_irq = platform_get_irq(pdev, 2);
+ if (unlikely(rtc->alarm_irq < 0)) {
+ dev_err(&pdev->dev, "No IRQ for alarm\n");
+ goto err_badres;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (unlikely(res == NULL)) {
+ dev_err(&pdev->dev, "No IO resource\n");
+ goto err_badres;
+ }
+
+ rtc->regsize = res->end - res->start + 1;
+
+ rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name);
+ if (unlikely(!rtc->res)) {
+ ret = -EBUSY;
+ goto err_badres;
+ }
+
+ rtc->regbase = (void __iomem *)rtc->res->start;
+ if (unlikely(!rtc->regbase)) {
+ ret = -EINVAL;
+ goto err_badmap;
+ }
+
+ rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
+ &sh_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err_badmap;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ return 0;
+
+err_badmap:
+ release_resource(rtc->res);
+err_badres:
+ kfree(rtc);
+
+ return ret;
+}
+
+static int __devexit sh_rtc_remove(struct platform_device *pdev)
+{
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (likely(rtc->rtc_dev))
+ rtc_device_unregister(rtc->rtc_dev);
+
+ sh_rtc_setpie(&pdev->dev, 0);
+ sh_rtc_setaie(&pdev->dev, 0);
+
+ release_resource(rtc->res);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(rtc);
+
+ return 0;
+}
+static struct platform_driver sh_rtc_platform_driver = {
+ .driver = {
+ .name = "sh-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = sh_rtc_probe,
+ .remove = __devexit_p(sh_rtc_remove),
+};
+
+static int __init sh_rtc_init(void)
+{
+ return platform_driver_register(&sh_rtc_platform_driver);
+}
+
+static void __exit sh_rtc_exit(void)
+{
+ platform_driver_unregister(&sh_rtc_platform_driver);
+}
+
+module_init(sh_rtc_init);
+module_exit(sh_rtc_exit);
+
+MODULE_DESCRIPTION("SuperH on-chip RTC driver");
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
new file mode 100644
index 00000000000..a40f400acff
--- /dev/null
+++ b/drivers/rtc/rtc-v3020.c
@@ -0,0 +1,264 @@
+/* drivers/rtc/rtc-v3020.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for the V3020 RTC
+ *
+ * Changelog:
+ *
+ * 10-May-2006: Raphael Assenat <raph@8d.com>
+ * - Converted to platform driver
+ * - Use the generic rtc class
+ *
+ * ??-???-2004: Someone at Compulab
+ * - Initial driver creation.
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/bcd.h>
+#include <linux/rtc-v3020.h>
+
+#include <asm/io.h>
+
+#undef DEBUG
+
+struct v3020 {
+ void __iomem *ioaddress;
+ int leftshift;
+ struct rtc_device *rtc;
+};
+
+static void v3020_set_reg(struct v3020 *chip, unsigned char address,
+ unsigned char data)
+{
+ int i;
+ unsigned char tmp;
+
+ tmp = address;
+ for (i = 0; i < 4; i++) {
+ writel((tmp & 1) << chip->leftshift, chip->ioaddress);
+ tmp >>= 1;
+ }
+
+ /* Commands dont have data */
+ if (!V3020_IS_COMMAND(address)) {
+ for (i = 0; i < 8; i++) {
+ writel((data & 1) << chip->leftshift, chip->ioaddress);
+ data >>= 1;
+ }
+ }
+}
+
+static unsigned char v3020_get_reg(struct v3020 *chip, unsigned char address)
+{
+ unsigned int data=0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ writel((address & 1) << chip->leftshift, chip->ioaddress);
+ address >>= 1;
+ }
+
+ for (i = 0; i < 8; i++) {
+ data >>= 1;
+ if (readl(chip->ioaddress) & (1 << chip->leftshift))
+ data |= 0x80;
+ }
+
+ return data;
+}
+
+static int v3020_read_time(struct device *dev, struct rtc_time *dt)
+{
+ struct v3020 *chip = dev_get_drvdata(dev);
+ int tmp;
+
+ /* Copy the current time to ram... */
+ v3020_set_reg(chip, V3020_CMD_CLOCK2RAM, 0);
+
+ /* ...and then read constant values. */
+ tmp = v3020_get_reg(chip, V3020_SECONDS);
+ dt->tm_sec = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_MINUTES);
+ dt->tm_min = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_HOURS);
+ dt->tm_hour = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_MONTH_DAY);
+ dt->tm_mday = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_MONTH);
+ dt->tm_mon = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_WEEK_DAY);
+ dt->tm_wday = BCD2BIN(tmp);
+ tmp = v3020_get_reg(chip, V3020_YEAR);
+ dt->tm_year = BCD2BIN(tmp)+100;
+
+#ifdef DEBUG
+ printk("\n%s : Read RTC values\n",__FUNCTION__);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_year: %i\n",dt->tm_year);
+ printk("tm_mon : %i\n",dt->tm_mon);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+ return 0;
+}
+
+
+static int v3020_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct v3020 *chip = dev_get_drvdata(dev);
+
+#ifdef DEBUG
+ printk("\n%s : Setting RTC values\n",__FUNCTION__);
+ printk("tm_sec : %i\n",dt->tm_sec);
+ printk("tm_min : %i\n",dt->tm_min);
+ printk("tm_hour: %i\n",dt->tm_hour);
+ printk("tm_mday: %i\n",dt->tm_mday);
+ printk("tm_wday: %i\n",dt->tm_wday);
+ printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+ /* Write all the values to ram... */
+ v3020_set_reg(chip, V3020_SECONDS, BIN2BCD(dt->tm_sec));
+ v3020_set_reg(chip, V3020_MINUTES, BIN2BCD(dt->tm_min));
+ v3020_set_reg(chip, V3020_HOURS, BIN2BCD(dt->tm_hour));
+ v3020_set_reg(chip, V3020_MONTH_DAY, BIN2BCD(dt->tm_mday));
+ v3020_set_reg(chip, V3020_MONTH, BIN2BCD(dt->tm_mon));
+ v3020_set_reg(chip, V3020_WEEK_DAY, BIN2BCD(dt->tm_wday));
+ v3020_set_reg(chip, V3020_YEAR, BIN2BCD(dt->tm_year % 100));
+
+ /* ...and set the clock. */
+ v3020_set_reg(chip, V3020_CMD_RAM2CLOCK, 0);
+
+ /* Compulab used this delay here. I dont know why,
+ * the datasheet does not specify a delay. */
+ /*mdelay(5);*/
+
+ return 0;
+}
+
+static struct rtc_class_ops v3020_rtc_ops = {
+ .read_time = v3020_read_time,
+ .set_time = v3020_set_time,
+};
+
+static int rtc_probe(struct platform_device *pdev)
+{
+ struct v3020_platform_data *pdata = pdev->dev.platform_data;
+ struct v3020 *chip;
+ struct rtc_device *rtc;
+ int retval = -EBUSY;
+ int i;
+ int temp;
+
+ if (pdev->num_resources != 1)
+ return -EBUSY;
+
+ if (pdev->resource[0].flags != IORESOURCE_MEM)
+ return -EBUSY;
+
+ if (pdev == NULL)
+ return -EBUSY;
+
+ chip = kzalloc(sizeof *chip, GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->leftshift = pdata->leftshift;
+ chip->ioaddress = ioremap(pdev->resource[0].start, 1);
+ if (chip->ioaddress == NULL)
+ goto err_chip;
+
+ /* Make sure the v3020 expects a communication cycle
+ * by reading 8 times */
+ for (i = 0; i < 8; i++)
+ temp = readl(chip->ioaddress);
+
+ /* Test chip by doing a write/read sequence
+ * to the chip ram */
+ v3020_set_reg(chip, V3020_SECONDS, 0x33);
+ if(v3020_get_reg(chip, V3020_SECONDS) != 0x33) {
+ retval = -ENODEV;
+ goto err_io;
+ }
+
+ /* Make sure frequency measurment mode, test modes, and lock
+ * are all disabled */
+ v3020_set_reg(chip, V3020_STATUS_0, 0x0);
+
+ dev_info(&pdev->dev, "Chip available at physical address 0x%p,"
+ "data connected to D%d\n",
+ (void*)pdev->resource[0].start,
+ chip->leftshift);
+
+ platform_set_drvdata(pdev, chip);
+
+ rtc = rtc_device_register("v3020",
+ &pdev->dev, &v3020_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ retval = PTR_ERR(rtc);
+ goto err_io;
+ }
+ chip->rtc = rtc;
+
+ return 0;
+
+err_io:
+ iounmap(chip->ioaddress);
+err_chip:
+ kfree(chip);
+
+ return retval;
+}
+
+static int rtc_remove(struct platform_device *dev)
+{
+ struct v3020 *chip = platform_get_drvdata(dev);
+ struct rtc_device *rtc = chip->rtc;
+
+ if (rtc)
+ rtc_device_unregister(rtc);
+
+ iounmap(chip->ioaddress);
+ kfree(chip);
+
+ return 0;
+}
+
+static struct platform_driver rtc_device_driver = {
+ .probe = rtc_probe,
+ .remove = rtc_remove,
+ .driver = {
+ .name = "v3020",
+ .owner = THIS_MODULE,
+ },
+};
+
+static __init int v3020_init(void)
+{
+ return platform_driver_register(&rtc_device_driver);
+}
+
+static __exit void v3020_exit(void)
+{
+ platform_driver_unregister(&rtc_device_driver);
+}
+
+module_init(v3020_init);
+module_exit(v3020_exit);
+
+MODULE_DESCRIPTION("V3020 RTC");
+MODULE_AUTHOR("Raphael Assenat");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 277596c302e..596764fd29f 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -30,7 +30,7 @@
#include <asm/div64.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <asm/vr41xx/vr41xx.h>
+#include <asm/vr41xx/irq.h>
MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
MODULE_DESCRIPTION("NEC VR4100 series RTC driver");
@@ -81,7 +81,6 @@ MODULE_LICENSE("GPL");
#define RTC_FREQUENCY 32768
#define MAX_PERIODIC_RATE 6553
-#define MAX_USER_PERIODIC_RATE 64
static void __iomem *rtc1_base;
static void __iomem *rtc2_base;
@@ -94,7 +93,7 @@ static void __iomem *rtc2_base;
static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */
-static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(rtc_lock);
static char rtc_name[] = "RTC";
static unsigned long periodic_frequency;
static unsigned long periodic_count;
@@ -240,9 +239,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
if (arg > MAX_PERIODIC_RATE)
return -EINVAL;
- if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0)
- return -EACCES;
-
periodic_frequency = arg;
count = RTC_FREQUENCY;
@@ -263,10 +259,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
/* Doesn't support before 1900 */
if (arg < 1900)
return -EINVAL;
-
- if (capable(CAP_SYS_TIME) == 0)
- return -EACCES;
-
epoch = arg;
break;
default:
@@ -353,11 +345,11 @@ static int __devinit rtc_probe(struct platform_device *pdev)
spin_unlock_irq(&rtc_lock);
irq = ELAPSEDTIME_IRQ;
- retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT,
+ retval = request_irq(irq, elapsedtime_interrupt, IRQF_DISABLED,
"elapsed_time", pdev);
if (retval == 0) {
irq = RTCLONG1_IRQ;
- retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT,
+ retval = request_irq(irq, rtclong1_interrupt, IRQF_DISABLED,
"rtclong1", pdev);
}
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
index 4d36208ff8d..ae89b9b8874 100644
--- a/drivers/s390/Kconfig
+++ b/drivers/s390/Kconfig
@@ -213,17 +213,35 @@ config MONREADER
help
Character device driver for reading z/VM monitor service records
+config MONWRITER
+ tristate "API for writing z/VM monitor service records"
+ default "m"
+ help
+ Character device driver for writing z/VM monitor service records
+
endmenu
menu "Cryptographic devices"
-config Z90CRYPT
+config ZCRYPT
tristate "Support for PCI-attached cryptographic adapters"
- default "m"
- help
+ select ZCRYPT_MONOLITHIC if ZCRYPT="y"
+ default "m"
+ help
Select this option if you want to use a PCI-attached cryptographic
- adapter like the PCI Cryptographic Accelerator (PCICA) or the PCI
- Cryptographic Coprocessor (PCICC). This option is also available
- as a module called z90crypt.ko.
+ adapter like:
+ + PCI Cryptographic Accelerator (PCICA)
+ + PCI Cryptographic Coprocessor (PCICC)
+ + PCI-X Cryptographic Coprocessor (PCIXCC)
+ + Crypto Express2 Coprocessor (CEX2C)
+ + Crypto Express2 Accelerator (CEX2A)
+
+config ZCRYPT_MONOLITHIC
+ bool "Monolithic zcrypt module"
+ depends on ZCRYPT="m"
+ help
+ Select this option if you want to have a single module z90crypt.ko
+ that contains all parts of the crypto device driver (ap bus,
+ request router and all the card drivers).
endmenu
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index cfb1fff3787..d0647d116ea 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -53,7 +52,7 @@ static void dasd_setup_queue(struct dasd_device * device);
static void dasd_free_queue(struct dasd_device * device);
static void dasd_flush_request_queue(struct dasd_device *);
static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
-static void dasd_flush_ccw_queue(struct dasd_device *, int);
+static int dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data);
@@ -61,6 +60,7 @@ static void do_kick_device(void *data);
* SECTION: Operations on the device structure.
*/
static wait_queue_head_t dasd_init_waitq;
+static wait_queue_head_t dasd_flush_wq;
/*
* Allocate memory for a new device structure.
@@ -95,7 +95,7 @@ dasd_alloc_device(void)
spin_lock_init(&device->mem_lock);
spin_lock_init(&device->request_queue_lock);
atomic_set (&device->tasklet_scheduled, 0);
- tasklet_init(&device->tasklet,
+ tasklet_init(&device->tasklet,
(void (*)(unsigned long)) dasd_tasklet,
(unsigned long) device);
INIT_LIST_HEAD(&device->ccw_queue);
@@ -122,13 +122,13 @@ dasd_free_device(struct dasd_device *device)
/*
* Make a new device known to the system.
*/
-static inline int
+static int
dasd_state_new_to_known(struct dasd_device *device)
{
int rc;
/*
- * As long as the device is not in state DASD_STATE_NEW we want to
+ * As long as the device is not in state DASD_STATE_NEW we want to
* keep the reference count > 0.
*/
dasd_get_device(device);
@@ -146,7 +146,7 @@ dasd_state_new_to_known(struct dasd_device *device)
/*
* Let the system forget about a device.
*/
-static inline void
+static int
dasd_state_known_to_new(struct dasd_device * device)
{
/* Disable extended error reporting for this device. */
@@ -164,12 +164,13 @@ dasd_state_known_to_new(struct dasd_device * device)
/* Give up reference we took in dasd_state_new_to_known. */
dasd_put_device(device);
+ return 0;
}
/*
* Request the irq line for the device.
*/
-static inline int
+static int
dasd_state_known_to_basic(struct dasd_device * device)
{
int rc;
@@ -183,7 +184,7 @@ dasd_state_known_to_basic(struct dasd_device * device)
device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
8 * sizeof (long));
debug_register_view(device->debug_area, &debug_sprintf_view);
- debug_set_level(device->debug_area, DBF_EMERG);
+ debug_set_level(device->debug_area, DBF_WARNING);
DBF_DEV_EVENT(DBF_EMERG, device, "%s", "debug area created");
device->state = DASD_STATE_BASIC;
@@ -193,17 +194,23 @@ dasd_state_known_to_basic(struct dasd_device * device)
/*
* Release the irq line for the device. Terminate any running i/o.
*/
-static inline void
+static int
dasd_state_basic_to_known(struct dasd_device * device)
{
+ int rc;
+
dasd_gendisk_free(device);
- dasd_flush_ccw_queue(device, 1);
+ rc = dasd_flush_ccw_queue(device, 1);
+ if (rc)
+ return rc;
+
DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
if (device->debug_area != NULL) {
debug_unregister(device->debug_area);
device->debug_area = NULL;
}
device->state = DASD_STATE_KNOWN;
+ return 0;
}
/*
@@ -220,7 +227,7 @@ dasd_state_basic_to_known(struct dasd_device * device)
* In case the analysis returns an error, the device setup is stopped
* (a fake disk was already added to allow formatting).
*/
-static inline int
+static int
dasd_state_basic_to_ready(struct dasd_device * device)
{
int rc;
@@ -248,25 +255,31 @@ dasd_state_basic_to_ready(struct dasd_device * device)
* Forget format information. Check if the target level is basic
* and if it is create fake disk for formatting.
*/
-static inline void
+static int
dasd_state_ready_to_basic(struct dasd_device * device)
{
- dasd_flush_ccw_queue(device, 0);
+ int rc;
+
+ rc = dasd_flush_ccw_queue(device, 0);
+ if (rc)
+ return rc;
dasd_destroy_partitions(device);
dasd_flush_request_queue(device);
device->blocks = 0;
device->bp_block = 0;
device->s2b_shift = 0;
device->state = DASD_STATE_BASIC;
+ return 0;
}
/*
* Back to basic.
*/
-static inline void
+static int
dasd_state_unfmt_to_basic(struct dasd_device * device)
{
device->state = DASD_STATE_BASIC;
+ return 0;
}
/*
@@ -274,7 +287,7 @@ dasd_state_unfmt_to_basic(struct dasd_device * device)
* the requeueing of requests from the linux request queue to the
* ccw queue.
*/
-static inline int
+static int
dasd_state_ready_to_online(struct dasd_device * device)
{
device->state = DASD_STATE_ONLINE;
@@ -285,16 +298,17 @@ dasd_state_ready_to_online(struct dasd_device * device)
/*
* Stop the requeueing of requests again.
*/
-static inline void
+static int
dasd_state_online_to_ready(struct dasd_device * device)
{
device->state = DASD_STATE_READY;
+ return 0;
}
/*
* Device startup state changes.
*/
-static inline int
+static int
dasd_increase_state(struct dasd_device *device)
{
int rc;
@@ -330,30 +344,37 @@ dasd_increase_state(struct dasd_device *device)
/*
* Device shutdown state changes.
*/
-static inline int
+static int
dasd_decrease_state(struct dasd_device *device)
{
+ int rc;
+
+ rc = 0;
if (device->state == DASD_STATE_ONLINE &&
device->target <= DASD_STATE_READY)
- dasd_state_online_to_ready(device);
-
- if (device->state == DASD_STATE_READY &&
+ rc = dasd_state_online_to_ready(device);
+
+ if (!rc &&
+ device->state == DASD_STATE_READY &&
device->target <= DASD_STATE_BASIC)
- dasd_state_ready_to_basic(device);
+ rc = dasd_state_ready_to_basic(device);
- if (device->state == DASD_STATE_UNFMT &&
+ if (!rc &&
+ device->state == DASD_STATE_UNFMT &&
device->target <= DASD_STATE_BASIC)
- dasd_state_unfmt_to_basic(device);
+ rc = dasd_state_unfmt_to_basic(device);
- if (device->state == DASD_STATE_BASIC &&
+ if (!rc &&
+ device->state == DASD_STATE_BASIC &&
device->target <= DASD_STATE_KNOWN)
- dasd_state_basic_to_known(device);
-
- if (device->state == DASD_STATE_KNOWN &&
+ rc = dasd_state_basic_to_known(device);
+
+ if (!rc &&
+ device->state == DASD_STATE_KNOWN &&
device->target <= DASD_STATE_NEW)
- dasd_state_known_to_new(device);
+ rc = dasd_state_known_to_new(device);
- return 0;
+ return rc;
}
/*
@@ -702,6 +723,7 @@ dasd_term_IO(struct dasd_ccw_req * cqr)
cqr->retries--;
cqr->status = DASD_CQR_CLEAR;
cqr->stopclk = get_clock();
+ cqr->starttime = 0;
DBF_DEV_EVENT(DBF_DEBUG, device,
"terminate cqr %p successful",
cqr);
@@ -871,7 +893,7 @@ dasd_handle_killed_request(struct ccw_device *cdev, unsigned long intparm)
device = (struct dasd_device *) cqr->device;
if (device == NULL ||
- device != dasd_device_from_cdev(cdev) ||
+ device != dasd_device_from_cdev_locked(cdev) ||
strncmp(device->discipline->ebcname, (char *) &cqr->magic, 4)) {
MESSAGE(KERN_DEBUG, "invalid device in request: bus_id %s",
cdev->dev.bus_id);
@@ -948,7 +970,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
/* first of all check for state change pending interrupt */
mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP;
if ((irb->scsw.dstat & mask) == mask) {
- device = dasd_device_from_cdev(cdev);
+ device = dasd_device_from_cdev_locked(cdev);
if (!IS_ERR(device)) {
dasd_handle_state_change_pending(device);
dasd_put_device(device);
@@ -979,6 +1001,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) {
cqr->status = DASD_CQR_QUEUED;
dasd_clear_timer(device);
+ wake_up(&dasd_flush_wq);
dasd_schedule_bh(device);
return;
}
@@ -994,7 +1017,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr);
/* Find out the appropriate era_action. */
- if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
+ if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC)
era = dasd_era_fatal;
else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) &&
irb->scsw.cstat == 0 &&
@@ -1004,7 +1027,7 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
era = dasd_era_fatal; /* don't recover this request */
else if (irb->esw.esw0.erw.cons)
era = device->discipline->examine_error(cqr, irb);
- else
+ else
era = dasd_era_recover;
DBF_DEV_EVENT(DBF_DEBUG, device, "era_code %d", era);
@@ -1242,6 +1265,10 @@ __dasd_check_expire(struct dasd_device * device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
if (cqr->status == DASD_CQR_IN_IO && cqr->expires != 0) {
if (time_after_eq(jiffies, cqr->expires + cqr->starttime)) {
+ DEV_MESSAGE(KERN_ERR, device,
+ "internal error - timeout (%is) expired "
+ "for cqr %p (%i retries left)",
+ (cqr->expires/HZ), cqr, cqr->retries);
if (device->discipline->term_IO(cqr) != 0)
/* Hmpf, try again in 1/10 sec */
dasd_set_timer(device, 10);
@@ -1286,46 +1313,100 @@ __dasd_start_head(struct dasd_device * device)
dasd_set_timer(device, 50);
}
+static inline int
+_wait_for_clear(struct dasd_ccw_req *cqr)
+{
+ return (cqr->status == DASD_CQR_QUEUED);
+}
+
/*
- * Remove requests from the ccw queue.
+ * Remove all requests from the ccw queue (all = '1') or only block device
+ * requests in case all = '0'.
+ * Take care of the erp-chain (chained via cqr->refers) and remove either
+ * the whole erp-chain or none of the erp-requests.
+ * If a request is currently running, term_IO is called and the request
+ * is re-queued. Prior to removing the terminated request we need to wait
+ * for the clear-interrupt.
+ * In case termination is not possible we stop processing and just finishing
+ * the already moved requests.
*/
-static void
+static int
dasd_flush_ccw_queue(struct dasd_device * device, int all)
{
+ struct dasd_ccw_req *cqr, *orig, *n;
+ int rc, i;
+
struct list_head flush_queue;
- struct list_head *l, *n;
- struct dasd_ccw_req *cqr;
INIT_LIST_HEAD(&flush_queue);
spin_lock_irq(get_ccwdev_lock(device->cdev));
- list_for_each_safe(l, n, &device->ccw_queue) {
- cqr = list_entry(l, struct dasd_ccw_req, list);
+ rc = 0;
+restart:
+ list_for_each_entry_safe(cqr, n, &device->ccw_queue, list) {
+ /* get original request of erp request-chain */
+ for (orig = cqr; orig->refers != NULL; orig = orig->refers);
+
/* Flush all request or only block device requests? */
- if (all == 0 && cqr->callback == dasd_end_request_cb)
+ if (all == 0 && cqr->callback != dasd_end_request_cb &&
+ orig->callback != dasd_end_request_cb) {
continue;
- if (cqr->status == DASD_CQR_IN_IO)
- device->discipline->term_IO(cqr);
- if (cqr->status != DASD_CQR_DONE ||
- cqr->status != DASD_CQR_FAILED) {
- cqr->status = DASD_CQR_FAILED;
+ }
+ /* Check status and move request to flush_queue */
+ switch (cqr->status) {
+ case DASD_CQR_IN_IO:
+ rc = device->discipline->term_IO(cqr);
+ if (rc) {
+ /* unable to terminate requeust */
+ DEV_MESSAGE(KERN_ERR, device,
+ "dasd flush ccw_queue is unable "
+ " to terminate request %p",
+ cqr);
+ /* stop flush processing */
+ goto finished;
+ }
+ break;
+ case DASD_CQR_QUEUED:
+ case DASD_CQR_ERROR:
+ /* set request to FAILED */
cqr->stopclk = get_clock();
+ cqr->status = DASD_CQR_FAILED;
+ break;
+ default: /* do not touch the others */
+ break;
+ }
+ /* Rechain request (including erp chain) */
+ for (i = 0; cqr != NULL; cqr = cqr->refers, i++) {
+ cqr->endclk = get_clock();
+ list_move_tail(&cqr->list, &flush_queue);
+ }
+ if (i > 1)
+ /* moved more than one request - need to restart */
+ goto restart;
+ }
+
+finished:
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+ /* Now call the callback function of flushed requests */
+restart_cb:
+ list_for_each_entry_safe(cqr, n, &flush_queue, list) {
+ if (cqr->status == DASD_CQR_CLEAR) {
+ /* wait for clear interrupt! */
+ wait_event(dasd_flush_wq, _wait_for_clear(cqr));
+ cqr->status = DASD_CQR_FAILED;
}
/* Process finished ERP request. */
if (cqr->refers) {
__dasd_process_erp(device, cqr);
- continue;
+ /* restart list_for_xx loop since dasd_process_erp
+ * might remove multiple elements */
+ goto restart_cb;
}
- /* Rechain request on device request queue */
+ /* call the callback function */
cqr->endclk = get_clock();
- list_move_tail(&cqr->list, &flush_queue);
- }
- spin_unlock_irq(get_ccwdev_lock(device->cdev));
- /* Now call the callback function of flushed requests */
- list_for_each_safe(l, n, &flush_queue) {
- cqr = list_entry(l, struct dasd_ccw_req, list);
if (cqr->callback != NULL)
(cqr->callback)(cqr, cqr->callback_data);
}
+ return rc;
}
/*
@@ -1450,23 +1531,23 @@ dasd_sleep_on(struct dasd_ccw_req * cqr)
wait_queue_head_t wait_q;
struct dasd_device *device;
int rc;
-
+
device = cqr->device;
spin_lock_irq(get_ccwdev_lock(device->cdev));
-
+
init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb;
cqr->callback_data = (void *) &wait_q;
cqr->status = DASD_CQR_QUEUED;
list_add_tail(&cqr->list, &device->ccw_queue);
-
+
/* let the bh start the request to keep them in order */
dasd_schedule_bh(device);
-
+
spin_unlock_irq(get_ccwdev_lock(device->cdev));
wait_event(wait_q, _wait_for_wakeup(cqr));
-
+
/* Request status is either done or failed. */
rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
return rc;
@@ -1511,10 +1592,8 @@ dasd_sleep_on_interruptible(struct dasd_ccw_req * cqr)
if (device->discipline->term_IO) {
cqr->retries = -1;
device->discipline->term_IO(cqr);
- /*nished =
- * wait (non-interruptible) for final status
- * because signal ist still pending
- */
+ /* wait (non-interruptible) for final status
+ * because signal ist still pending */
spin_unlock_irq(get_ccwdev_lock(device->cdev));
wait_event(wait_q, _wait_for_wakeup(cqr));
spin_lock_irq(get_ccwdev_lock(device->cdev));
@@ -1547,19 +1626,11 @@ static inline int
_dasd_term_running_cqr(struct dasd_device *device)
{
struct dasd_ccw_req *cqr;
- int rc;
if (list_empty(&device->ccw_queue))
return 0;
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
- rc = device->discipline->term_IO(cqr);
- if (rc == 0) {
- /* termination successful */
- cqr->status = DASD_CQR_QUEUED;
- cqr->startclk = cqr->stopclk = 0;
- cqr->starttime = 0;
- }
- return rc;
+ return device->discipline->term_IO(cqr);
}
int
@@ -1568,7 +1639,7 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
wait_queue_head_t wait_q;
struct dasd_device *device;
int rc;
-
+
device = cqr->device;
spin_lock_irq(get_ccwdev_lock(device->cdev));
rc = _dasd_term_running_cqr(device);
@@ -1576,20 +1647,20 @@ dasd_sleep_on_immediatly(struct dasd_ccw_req * cqr)
spin_unlock_irq(get_ccwdev_lock(device->cdev));
return rc;
}
-
+
init_waitqueue_head (&wait_q);
cqr->callback = dasd_wakeup_cb;
cqr->callback_data = (void *) &wait_q;
cqr->status = DASD_CQR_QUEUED;
list_add(&cqr->list, &device->ccw_queue);
-
+
/* let the bh start the request to keep them in order */
dasd_schedule_bh(device);
-
+
spin_unlock_irq(get_ccwdev_lock(device->cdev));
wait_event(wait_q, _wait_for_wakeup(cqr));
-
+
/* Request status is either done or failed. */
rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
return rc;
@@ -1725,14 +1796,11 @@ dasd_flush_request_queue(struct dasd_device * device)
if (!device->request_queue)
return;
-
+
spin_lock_irq(&device->request_queue_lock);
- while (!list_empty(&device->request_queue->queue_head)) {
- req = elv_next_request(device->request_queue);
- if (req == NULL)
- break;
- dasd_end_request(req, 0);
+ while ((req = elv_next_request(device->request_queue))) {
blkdev_dequeue_request(req);
+ dasd_end_request(req, 0);
}
spin_unlock_irq(&device->request_queue_lock);
}
@@ -1834,7 +1902,6 @@ dasd_exit(void)
}
dasd_gendisk_exit();
dasd_devmap_exit();
- devfs_remove("dasd");
if (dasd_debug_area != NULL) {
debug_unregister(dasd_debug_area);
dasd_debug_area = NULL;
@@ -1855,15 +1922,34 @@ dasd_generic_probe (struct ccw_device *cdev,
{
int ret;
+ ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+ if (ret) {
+ printk(KERN_WARNING
+ "dasd_generic_probe: could not set ccw-device options "
+ "for %s\n", cdev->dev.bus_id);
+ return ret;
+ }
ret = dasd_add_sysfs_files(cdev);
if (ret) {
printk(KERN_WARNING
"dasd_generic_probe: could not add sysfs entries "
"for %s\n", cdev->dev.bus_id);
- } else {
- cdev->handler = &dasd_int_handler;
+ return ret;
}
+ cdev->handler = &dasd_int_handler;
+ /*
+ * Automatically online either all dasd devices (dasd_autodetect)
+ * or all devices specified with dasd= parameters during
+ * initial probe.
+ */
+ if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) ||
+ (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0))
+ ret = ccw_device_set_online(cdev);
+ if (ret)
+ printk(KERN_WARNING
+ "dasd_generic_probe: could not initially online "
+ "ccw-device %s\n", cdev->dev.bus_id);
return ret;
}
@@ -1911,6 +1997,8 @@ dasd_generic_set_online (struct ccw_device *cdev,
struct dasd_device *device;
int rc;
+ /* first online clears initial online feature flag */
+ dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0);
device = dasd_create_device(cdev);
if (IS_ERR(device))
return PTR_ERR(device);
@@ -2065,31 +2153,6 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
return ret;
}
-/*
- * Automatically online either all dasd devices (dasd_autodetect) or
- * all devices specified with dasd= parameters.
- */
-static int
-__dasd_auto_online(struct device *dev, void *data)
-{
- struct ccw_device *cdev;
-
- cdev = to_ccwdev(dev);
- if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
- ccw_device_set_online(cdev);
- return 0;
-}
-
-void
-dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
-{
- struct device_driver *drv;
-
- drv = get_driver(&dasd_discipline_driver->driver);
- driver_for_each_device(drv, NULL, NULL, __dasd_auto_online);
- put_driver(drv);
-}
-
static int __init
dasd_init(void)
@@ -2097,6 +2160,7 @@ dasd_init(void)
int rc;
init_waitqueue_head(&dasd_init_waitq);
+ init_waitqueue_head(&dasd_flush_wq);
/* register 'common' DASD debug area, used for all DBF_XXX calls */
dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
@@ -2105,15 +2169,12 @@ dasd_init(void)
goto failed;
}
debug_register_view(dasd_debug_area, &debug_sprintf_view);
- debug_set_level(dasd_debug_area, DBF_EMERG);
+ debug_set_level(dasd_debug_area, DBF_WARNING);
DBF_EVENT(DBF_EMERG, "%s", "debug area created");
dasd_diag_discipline_pointer = NULL;
- rc = devfs_mk_dir("dasd");
- if (rc)
- goto failed;
rc = dasd_devmap_init();
if (rc)
goto failed;
@@ -2170,23 +2231,4 @@ EXPORT_SYMBOL_GPL(dasd_generic_remove);
EXPORT_SYMBOL_GPL(dasd_generic_notify);
EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
-EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_3370_erp.c b/drivers/s390/block/dasd_3370_erp.c
index 1d11c2a9525..1ddab8991d9 100644
--- a/drivers/s390/block/dasd_3370_erp.c
+++ b/drivers/s390/block/dasd_3370_erp.c
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_3370_erp.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
@@ -12,10 +12,10 @@
/*
- * DASD_3370_ERP_EXAMINE
+ * DASD_3370_ERP_EXAMINE
*
* DESCRIPTION
- * Checks only for fatal/no/recover error.
+ * Checks only for fatal/no/recover error.
* A detailed examination of the sense data is done later outside
* the interrupt handler.
*
@@ -23,7 +23,7 @@
* 'Chapter 7. 3370 Sense Data'.
*
* RETURN VALUES
- * dasd_era_none no error
+ * dasd_era_none no error
* dasd_era_fatal for all fatal (unrecoverable errors)
* dasd_era_recover for all others.
*/
@@ -82,22 +82,3 @@ dasd_3370_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
return dasd_era_recover;
} /* END dasd_3370_erp_examine */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 2ed51562319..669805d4402 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1,6 +1,6 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_3990_erp.c
- * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com>
+ * Author(s)......: Horst Hummel <Horst.Hummel@de.ibm.com>
* Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000, 2001
@@ -25,23 +25,23 @@ struct DCTL_data {
} __attribute__ ((packed));
/*
- *****************************************************************************
+ *****************************************************************************
* SECTION ERP EXAMINATION
- *****************************************************************************
+ *****************************************************************************
*/
/*
- * DASD_3990_ERP_EXAMINE_24
+ * DASD_3990_ERP_EXAMINE_24
*
* DESCRIPTION
- * Checks only for fatal (unrecoverable) error.
+ * Checks only for fatal (unrecoverable) error.
* A detailed examination of the sense data is done later outside
* the interrupt handler.
*
* Each bit configuration leading to an action code 2 (Exit with
* programming error or unusual condition indication)
* are handled as fatal error´s.
- *
+ *
* All other configurations are handled as recoverable errors.
*
* RETURN VALUES
@@ -93,15 +93,15 @@ dasd_3990_erp_examine_24(struct dasd_ccw_req * cqr, char *sense)
} /* END dasd_3990_erp_examine_24 */
/*
- * DASD_3990_ERP_EXAMINE_32
+ * DASD_3990_ERP_EXAMINE_32
*
* DESCRIPTION
- * Checks only for fatal/no/recoverable error.
+ * Checks only for fatal/no/recoverable error.
* A detailed examination of the sense data is done later outside
* the interrupt handler.
*
* RETURN VALUES
- * dasd_era_none no error
+ * dasd_era_none no error
* dasd_era_fatal for all fatal (unrecoverable errors)
* dasd_era_recover for recoverable others.
*/
@@ -128,10 +128,10 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
} /* end dasd_3990_erp_examine_32 */
/*
- * DASD_3990_ERP_EXAMINE
+ * DASD_3990_ERP_EXAMINE
*
* DESCRIPTION
- * Checks only for fatal/no/recover error.
+ * Checks only for fatal/no/recover error.
* A detailed examination of the sense data is done later outside
* the interrupt handler.
*
@@ -139,7 +139,7 @@ dasd_3990_erp_examine_32(struct dasd_ccw_req * cqr, char *sense)
* 'Chapter 7. Error Recovery Procedures'.
*
* RETURN VALUES
- * dasd_era_none no error
+ * dasd_era_none no error
* dasd_era_fatal for all fatal (unrecoverable errors)
* dasd_era_recover for all others.
*/
@@ -178,18 +178,18 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
} /* END dasd_3990_erp_examine */
/*
- *****************************************************************************
+ *****************************************************************************
* SECTION ERP HANDLING
- *****************************************************************************
+ *****************************************************************************
*/
/*
- *****************************************************************************
+ *****************************************************************************
* 24 and 32 byte sense ERP functions
- *****************************************************************************
+ *****************************************************************************
*/
/*
- * DASD_3990_ERP_CLEANUP
+ * DASD_3990_ERP_CLEANUP
*
* DESCRIPTION
* Removes the already build but not necessary ERP request and sets
@@ -197,10 +197,10 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
*
* PARAMETER
* erp request to be blocked
- * final_status either DASD_CQR_DONE or DASD_CQR_FAILED
+ * final_status either DASD_CQR_DONE or DASD_CQR_FAILED
*
* RETURN VALUES
- * cqr original cqr
+ * cqr original cqr
*/
static struct dasd_ccw_req *
dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
@@ -214,7 +214,7 @@ dasd_3990_erp_cleanup(struct dasd_ccw_req * erp, char final_status)
} /* end dasd_3990_erp_cleanup */
/*
- * DASD_3990_ERP_BLOCK_QUEUE
+ * DASD_3990_ERP_BLOCK_QUEUE
*
* DESCRIPTION
* Block the given device request queue to prevent from further
@@ -237,7 +237,7 @@ dasd_3990_erp_block_queue(struct dasd_ccw_req * erp, int expires)
}
/*
- * DASD_3990_ERP_INT_REQ
+ * DASD_3990_ERP_INT_REQ
*
* DESCRIPTION
* Handles 'Intervention Required' error.
@@ -277,7 +277,7 @@ dasd_3990_erp_int_req(struct dasd_ccw_req * erp)
} /* end dasd_3990_erp_int_req */
/*
- * DASD_3990_ERP_ALTERNATE_PATH
+ * DASD_3990_ERP_ALTERNATE_PATH
*
* DESCRIPTION
* Repeat the operation on a different channel path.
@@ -330,15 +330,15 @@ dasd_3990_erp_alternate_path(struct dasd_ccw_req * erp)
* DASD_3990_ERP_DCTL
*
* DESCRIPTION
- * Setup cqr to do the Diagnostic Control (DCTL) command with an
+ * Setup cqr to do the Diagnostic Control (DCTL) command with an
* Inhibit Write subcommand (0x20) and the given modifier.
*
* PARAMETER
* erp pointer to the current (failed) ERP
* modifier subcommand modifier
- *
+ *
* RETURN VALUES
- * dctl_cqr pointer to NEW dctl_cqr
+ * dctl_cqr pointer to NEW dctl_cqr
*
*/
static struct dasd_ccw_req *
@@ -386,7 +386,7 @@ dasd_3990_erp_DCTL(struct dasd_ccw_req * erp, char modifier)
} /* end dasd_3990_erp_DCTL */
/*
- * DASD_3990_ERP_ACTION_1
+ * DASD_3990_ERP_ACTION_1
*
* DESCRIPTION
* Setup ERP to do the ERP action 1 (see Reference manual).
@@ -415,7 +415,7 @@ dasd_3990_erp_action_1(struct dasd_ccw_req * erp)
} /* end dasd_3990_erp_action_1 */
/*
- * DASD_3990_ERP_ACTION_4
+ * DASD_3990_ERP_ACTION_4
*
* DESCRIPTION
* Setup ERP to do the ERP action 4 (see Reference manual).
@@ -453,11 +453,11 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
if (sense[25] == 0x1D) { /* state change pending */
- DEV_MESSAGE(KERN_INFO, device,
+ DEV_MESSAGE(KERN_INFO, device,
"waiting for state change pending "
"interrupt, %d retries left",
erp->retries);
-
+
dasd_3990_erp_block_queue(erp, 30*HZ);
} else if (sense[25] == 0x1E) { /* busy */
@@ -469,9 +469,9 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
} else {
/* no state change pending - retry */
- DEV_MESSAGE (KERN_INFO, device,
+ DEV_MESSAGE (KERN_INFO, device,
"redriving request immediately, "
- "%d retries left",
+ "%d retries left",
erp->retries);
erp->status = DASD_CQR_QUEUED;
}
@@ -482,13 +482,13 @@ dasd_3990_erp_action_4(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_action_4 */
/*
- *****************************************************************************
+ *****************************************************************************
* 24 byte sense ERP functions (only)
- *****************************************************************************
+ *****************************************************************************
*/
/*
- * DASD_3990_ERP_ACTION_5
+ * DASD_3990_ERP_ACTION_5
*
* DESCRIPTION
* Setup ERP to do the ERP action 5 (see Reference manual).
@@ -523,7 +523,7 @@ dasd_3990_erp_action_5(struct dasd_ccw_req * erp)
*
* PARAMETER
* sense current sense data
- *
+ *
* RETURN VALUES
* void
*/
@@ -1150,9 +1150,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
* PARAMETER
* erp current erp_head
* sense current sense data
- *
+ *
* RETURN VALUES
- * erp 'new' erp_head - pointer to new ERP
+ * erp 'new' erp_head - pointer to new ERP
*/
static struct dasd_ccw_req *
dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
@@ -1185,7 +1185,7 @@ dasd_3990_erp_com_rej(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_com_rej */
/*
- * DASD_3990_ERP_BUS_OUT
+ * DASD_3990_ERP_BUS_OUT
*
* DESCRIPTION
* Handles 24 byte 'Bus Out Parity Check' error.
@@ -1483,7 +1483,7 @@ dasd_3990_erp_env_data(struct dasd_ccw_req * erp, char *sense)
*
* PARAMETER
* erp already added default ERP
- *
+ *
* RETURN VALUES
* erp new erp_head - pointer to new ERP
*/
@@ -1527,11 +1527,11 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
} /* end dasd_3990_erp_file_prot */
/*
- * DASD_3990_ERP_INSPECT_24
+ * DASD_3990_ERP_INSPECT_24
*
* DESCRIPTION
* Does a detailed inspection of the 24 byte sense data
- * and sets up a related error recovery action.
+ * and sets up a related error recovery action.
*
* PARAMETER
* sense sense data of the actual error
@@ -1602,13 +1602,13 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
} /* END dasd_3990_erp_inspect_24 */
/*
- *****************************************************************************
+ *****************************************************************************
* 32 byte sense ERP functions (only)
- *****************************************************************************
+ *****************************************************************************
*/
/*
- * DASD_3990_ERPACTION_10_32
+ * DASD_3990_ERPACTION_10_32
*
* DESCRIPTION
* Handles 32 byte 'Action 10' of Single Program Action Codes.
@@ -1616,7 +1616,7 @@ dasd_3990_erp_inspect_24(struct dasd_ccw_req * erp, char *sense)
*
* PARAMETER
* erp current erp_head
- * sense current sense data
+ * sense current sense data
* RETURN VALUES
* erp modified erp_head
*/
@@ -1640,18 +1640,18 @@ dasd_3990_erp_action_10_32(struct dasd_ccw_req * erp, char *sense)
*
* DESCRIPTION
* Handles 32 byte 'Action 1B' of Single Program Action Codes.
- * A write operation could not be finished because of an unexpected
+ * A write operation could not be finished because of an unexpected
* condition.
- * The already created 'default erp' is used to get the link to
- * the erp chain, but it can not be used for this recovery
+ * The already created 'default erp' is used to get the link to
+ * the erp chain, but it can not be used for this recovery
* action because it contains no DE/LO data space.
*
* PARAMETER
* default_erp already added default erp.
- * sense current sense data
+ * sense current sense data
*
* RETURN VALUES
- * erp new erp or
+ * erp new erp or
* default_erp in case of imprecise ending or error
*/
static struct dasd_ccw_req *
@@ -1789,16 +1789,16 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense)
* DASD_3990_UPDATE_1B
*
* DESCRIPTION
- * Handles the update to the 32 byte 'Action 1B' of Single Program
+ * Handles the update to the 32 byte 'Action 1B' of Single Program
* Action Codes in case the first action was not successful.
* The already created 'previous_erp' is the currently not successful
- * ERP.
+ * ERP.
*
* PARAMETER
* previous_erp already created previous erp.
- * sense current sense data
+ * sense current sense data
* RETURN VALUES
- * erp modified erp
+ * erp modified erp
*/
static struct dasd_ccw_req *
dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
@@ -1897,7 +1897,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense)
} /* end dasd_3990_update_1B */
/*
- * DASD_3990_ERP_COMPOUND_RETRY
+ * DASD_3990_ERP_COMPOUND_RETRY
*
* DESCRIPTION
* Handles the compound ERP action retry code.
@@ -1943,7 +1943,7 @@ dasd_3990_erp_compound_retry(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_compound_retry */
/*
- * DASD_3990_ERP_COMPOUND_PATH
+ * DASD_3990_ERP_COMPOUND_PATH
*
* DESCRIPTION
* Handles the compound ERP action for retry on alternate
@@ -1965,7 +1965,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
dasd_3990_erp_alternate_path(erp);
if (erp->status == DASD_CQR_FAILED) {
- /* reset the lpm and the status to be able to
+ /* reset the lpm and the status to be able to
* try further actions. */
erp->lpm = 0;
@@ -1980,7 +1980,7 @@ dasd_3990_erp_compound_path(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_compound_path */
/*
- * DASD_3990_ERP_COMPOUND_CODE
+ * DASD_3990_ERP_COMPOUND_CODE
*
* DESCRIPTION
* Handles the compound ERP action for retry code.
@@ -2001,18 +2001,18 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
switch (sense[28]) {
case 0x17:
- /* issue a Diagnostic Control command with an
+ /* issue a Diagnostic Control command with an
* Inhibit Write subcommand and controler modifier */
erp = dasd_3990_erp_DCTL(erp, 0x20);
break;
-
+
case 0x25:
/* wait for 5 seconds and retry again */
erp->retries = 1;
-
+
dasd_3990_erp_block_queue (erp, 5*HZ);
break;
-
+
default:
/* should not happen - continue */
break;
@@ -2026,7 +2026,7 @@ dasd_3990_erp_compound_code(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_compound_code */
/*
- * DASD_3990_ERP_COMPOUND_CONFIG
+ * DASD_3990_ERP_COMPOUND_CONFIG
*
* DESCRIPTION
* Handles the compound ERP action for configruation
@@ -2063,10 +2063,10 @@ dasd_3990_erp_compound_config(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_compound_config */
/*
- * DASD_3990_ERP_COMPOUND
+ * DASD_3990_ERP_COMPOUND
*
* DESCRIPTION
- * Does the further compound program action if
+ * Does the further compound program action if
* compound retry was not successful.
*
* PARAMETER
@@ -2110,11 +2110,11 @@ dasd_3990_erp_compound(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_compound */
/*
- * DASD_3990_ERP_INSPECT_32
+ * DASD_3990_ERP_INSPECT_32
*
* DESCRIPTION
* Does a detailed inspection of the 32 byte sense data
- * and sets up a related error recovery action.
+ * and sets up a related error recovery action.
*
* PARAMETER
* sense sense data of the actual error
@@ -2228,9 +2228,9 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
} /* end dasd_3990_erp_inspect_32 */
/*
- *****************************************************************************
+ *****************************************************************************
* main ERP control fuctions (24 and 32 byte sense)
- *****************************************************************************
+ *****************************************************************************
*/
/*
@@ -2243,7 +2243,7 @@ dasd_3990_erp_inspect_32(struct dasd_ccw_req * erp, char *sense)
* PARAMETER
* erp pointer to the currently created default ERP
* RETURN VALUES
- * erp_new contens was possibly modified
+ * erp_new contens was possibly modified
*/
static struct dasd_ccw_req *
dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
@@ -2272,14 +2272,14 @@ dasd_3990_erp_inspect(struct dasd_ccw_req * erp)
/*
* DASD_3990_ERP_ADD_ERP
- *
+ *
* DESCRIPTION
* This funtion adds an additional request block (ERP) to the head of
* the given cqr (or erp).
* This erp is initialized as an default erp (retry TIC)
*
* PARAMETER
- * cqr head of the current ERP-chain (or single cqr if
+ * cqr head of the current ERP-chain (or single cqr if
* first error)
* RETURN VALUES
* erp pointer to new ERP-chain head
@@ -2332,15 +2332,15 @@ dasd_3990_erp_add_erp(struct dasd_ccw_req * cqr)
}
/*
- * DASD_3990_ERP_ADDITIONAL_ERP
- *
+ * DASD_3990_ERP_ADDITIONAL_ERP
+ *
* DESCRIPTION
* An additional ERP is needed to handle the current error.
* Add ERP to the head of the ERP-chain containing the ERP processing
* determined based on the sense data.
*
* PARAMETER
- * cqr head of the current ERP-chain (or single cqr if
+ * cqr head of the current ERP-chain (or single cqr if
* first error)
*
* RETURN VALUES
@@ -2376,7 +2376,7 @@ dasd_3990_erp_additional_erp(struct dasd_ccw_req * cqr)
* 24 byte sense byte 25 and 27 is set as well.
*
* PARAMETER
- * cqr1 first cqr, which will be compared with the
+ * cqr1 first cqr, which will be compared with the
* cqr2 second cqr.
*
* RETURN VALUES
@@ -2415,7 +2415,7 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2)
* cqr failed cqr (either original cqr or already an erp)
*
* RETURN VALUES
- * erp erp-pointer to the already defined error
+ * erp erp-pointer to the already defined error
* recovery procedure OR
* NULL if a 'new' error occurred.
*/
@@ -2451,10 +2451,10 @@ dasd_3990_erp_in_erp(struct dasd_ccw_req *cqr)
* DASD_3990_ERP_FURTHER_ERP (24 & 32 byte sense)
*
* DESCRIPTION
- * No retry is left for the current ERP. Check what has to be done
+ * No retry is left for the current ERP. Check what has to be done
* with the ERP.
* - do further defined ERP action or
- * - wait for interrupt or
+ * - wait for interrupt or
* - exit with permanent error
*
* PARAMETER
@@ -2485,7 +2485,7 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
if (!(sense[2] & DASD_SENSE_BIT_0)) {
- /* issue a Diagnostic Control command with an
+ /* issue a Diagnostic Control command with an
* Inhibit Write subcommand */
switch (sense[25]) {
@@ -2535,14 +2535,14 @@ dasd_3990_erp_further_erp(struct dasd_ccw_req *erp)
} /* end dasd_3990_erp_further_erp */
/*
- * DASD_3990_ERP_HANDLE_MATCH_ERP
+ * DASD_3990_ERP_HANDLE_MATCH_ERP
*
* DESCRIPTION
* An error occurred again and an ERP has been detected which is already
- * used to handle this error (e.g. retries).
+ * used to handle this error (e.g. retries).
* All prior ERP's are asumed to be successful and therefore removed
* from queue.
- * If retry counter of matching erp is already 0, it is checked if further
+ * If retry counter of matching erp is already 0, it is checked if further
* action is needed (besides retry) or if the ERP has failed.
*
* PARAMETER
@@ -2631,7 +2631,7 @@ dasd_3990_erp_handle_match_erp(struct dasd_ccw_req *erp_head,
* erp erp-pointer to the head of the ERP action chain.
* This means:
* - either a ptr to an additional ERP cqr or
- * - the original given cqr (which's status might
+ * - the original given cqr (which's status might
* be modified)
*/
struct dasd_ccw_req *
@@ -2723,22 +2723,3 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
return erp;
} /* end dasd_3990_erp_action */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_9336_erp.c b/drivers/s390/block/dasd_9336_erp.c
index dc861446d05..6e082688475 100644
--- a/drivers/s390/block/dasd_9336_erp.c
+++ b/drivers/s390/block/dasd_9336_erp.c
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_9336_erp.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
@@ -12,10 +12,10 @@
/*
- * DASD_9336_ERP_EXAMINE
+ * DASD_9336_ERP_EXAMINE
*
* DESCRIPTION
- * Checks only for fatal/no/recover error.
+ * Checks only for fatal/no/recover error.
* A detailed examination of the sense data is done later outside
* the interrupt handler.
*
@@ -23,7 +23,7 @@
* 'Chapter 7. 9336 Sense Data'.
*
* RETURN VALUES
- * dasd_era_none no error
+ * dasd_era_none no error
* dasd_era_fatal for all fatal (unrecoverable errors)
* dasd_era_recover for all others.
*/
@@ -39,22 +39,3 @@ dasd_9336_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
return dasd_era_recover;
} /* END dasd_9336_erp_examine */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_9343_erp.c b/drivers/s390/block/dasd_9343_erp.c
index 4a5b79569aa..ddecb9808ed 100644
--- a/drivers/s390/block/dasd_9343_erp.c
+++ b/drivers/s390/block/dasd_9343_erp.c
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_9345_erp.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c
index 216bc4fba19..91cf971f065 100644
--- a/drivers/s390/block/dasd_devmap.c
+++ b/drivers/s390/block/dasd_devmap.c
@@ -13,7 +13,6 @@
*
*/
-#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -27,7 +26,7 @@
#include "dasd_int.h"
kmem_cache_t *dasd_page_cache;
-EXPORT_SYMBOL(dasd_page_cache);
+EXPORT_SYMBOL_GPL(dasd_page_cache);
/*
* dasd_devmap_t is used to store the features and the relation
@@ -49,6 +48,22 @@ struct dasd_devmap {
};
/*
+ * dasd_server_ssid_map contains a globally unique storage server subsystem ID.
+ * dasd_server_ssid_list contains the list of all subsystem IDs accessed by
+ * the DASD device driver.
+ */
+struct dasd_server_ssid_map {
+ struct list_head list;
+ struct system_id {
+ char vendor[4];
+ char serial[15];
+ __u16 ssid;
+ } sid;
+};
+
+static struct list_head dasd_server_ssid_list;
+
+/*
* Parameter parsing functions for dasd= parameter. The syntax is:
* <devno> : (0x)?[0-9a-fA-F]+
* <busid> : [0-0a-f]\.[0-9a-f]\.(0x)?[0-9a-fA-F]+
@@ -64,6 +79,8 @@ struct dasd_devmap {
int dasd_probeonly = 0; /* is true, when probeonly mode is active */
int dasd_autodetect = 0; /* is true, when autodetection is active */
+int dasd_nopav = 0; /* is true, when PAV is disabled */
+EXPORT_SYMBOL_GPL(dasd_nopav);
/*
* char *dasd[] is intended to hold the ranges supplied by the dasd= statement
@@ -74,7 +91,7 @@ static char *dasd[256];
module_param_array(dasd, charp, NULL, 0);
/*
- * Single spinlock to protect devmap structures and lists.
+ * Single spinlock to protect devmap and servermap structures and lists.
*/
static DEFINE_SPINLOCK(dasd_devmap_lock);
@@ -123,7 +140,7 @@ static inline int
dasd_busid(char **str, int *id0, int *id1, int *devno)
{
int val, old_style;
-
+
/* check for leading '0x' */
old_style = 0;
if ((*str)[0] == '0' && (*str)[1] == 'x') {
@@ -179,7 +196,7 @@ dasd_feature_list(char *str, char **endp)
features = 0;
while (1) {
- for (len = 0;
+ for (len = 0;
str[len] && str[len] != ':' && str[len] != ')'; len++);
if (len == 2 && !strncmp(str, "ro", 2))
features |= DASD_FEATURE_READONLY;
@@ -228,24 +245,34 @@ dasd_parse_keyword( char *parsestring ) {
length = strlen(parsestring);
residual_str = parsestring + length;
}
- if (strncmp ("autodetect", parsestring, length) == 0) {
+ if (strncmp("autodetect", parsestring, length) == 0) {
dasd_autodetect = 1;
MESSAGE (KERN_INFO, "%s",
"turning to autodetection mode");
return residual_str;
}
- if (strncmp ("probeonly", parsestring, length) == 0) {
+ if (strncmp("probeonly", parsestring, length) == 0) {
dasd_probeonly = 1;
MESSAGE(KERN_INFO, "%s",
"turning to probeonly mode");
return residual_str;
}
- if (strncmp ("fixedbuffers", parsestring, length) == 0) {
+ if (strncmp("nopav", parsestring, length) == 0) {
+ if (MACHINE_IS_VM)
+ MESSAGE(KERN_INFO, "%s", "'nopav' not supported on VM");
+ else {
+ dasd_nopav = 1;
+ MESSAGE(KERN_INFO, "%s", "disable PAV mode");
+ }
+ return residual_str;
+ }
+ if (strncmp("fixedbuffers", parsestring, length) == 0) {
if (dasd_page_cache)
return residual_str;
dasd_page_cache =
- kmem_cache_create("dasd_page_cache", PAGE_SIZE, 0,
- SLAB_CACHE_DMA, NULL, NULL );
+ kmem_cache_create("dasd_page_cache", PAGE_SIZE,
+ PAGE_SIZE, SLAB_CACHE_DMA,
+ NULL, NULL );
if (!dasd_page_cache)
MESSAGE(KERN_WARNING, "%s", "Failed to create slab, "
"fixed buffer mode disabled.");
@@ -294,6 +321,8 @@ dasd_parse_range( char *parsestring ) {
features = dasd_feature_list(str, &str);
if (features < 0)
return ERR_PTR(-EINVAL);
+ /* each device in dasd= parameter should be set initially online */
+ features |= DASD_FEATURE_INITIAL_ONLINE;
while (from <= to) {
sprintf(bus_id, "%01x.%01x.%04x",
from_id0, from_id1, from++);
@@ -359,7 +388,7 @@ dasd_parse(void)
* Add a devmap for the device specified by busid. It is possible that
* the devmap already exists (dasd= parameter). The order of the devices
* added through this function will define the kdevs for the individual
- * devices.
+ * devices.
*/
static struct dasd_devmap *
dasd_add_busid(char *bus_id, int features)
@@ -368,11 +397,11 @@ dasd_add_busid(char *bus_id, int features)
int hash;
new = (struct dasd_devmap *)
- kmalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
+ kzalloc(sizeof(struct dasd_devmap), GFP_KERNEL);
if (!new)
return ERR_PTR(-ENOMEM);
spin_lock(&dasd_devmap_lock);
- devmap = 0;
+ devmap = NULL;
hash = dasd_hash_busid(bus_id);
list_for_each_entry(tmp, &dasd_hashlists[hash], list)
if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) {
@@ -384,10 +413,10 @@ dasd_add_busid(char *bus_id, int features)
new->devindex = dasd_max_devindex++;
strncpy(new->bus_id, bus_id, BUS_ID_SIZE);
new->features = features;
- new->device = 0;
+ new->device = NULL;
list_add(&new->list, &dasd_hashlists[hash]);
devmap = new;
- new = 0;
+ new = NULL;
}
spin_unlock(&dasd_devmap_lock);
kfree(new);
@@ -457,7 +486,7 @@ dasd_device_from_devindex(int devindex)
int i;
spin_lock(&dasd_devmap_lock);
- devmap = 0;
+ devmap = NULL;
for (i = 0; (i < 256) && !devmap; i++)
list_for_each_entry(tmp, &dasd_hashlists[i], list)
if (tmp->devindex == devindex) {
@@ -498,17 +527,17 @@ dasd_create_device(struct ccw_device *cdev)
{
struct dasd_devmap *devmap;
struct dasd_device *device;
+ unsigned long flags;
int rc;
devmap = dasd_devmap_from_cdev(cdev);
if (IS_ERR(devmap))
return (void *) devmap;
- cdev->dev.driver_data = devmap;
device = dasd_alloc_device();
if (IS_ERR(device))
return device;
- atomic_set(&device->ref_count, 2);
+ atomic_set(&device->ref_count, 3);
spin_lock(&dasd_devmap_lock);
if (!devmap->device) {
@@ -527,6 +556,11 @@ dasd_create_device(struct ccw_device *cdev)
dasd_free_device(device);
return ERR_PTR(rc);
}
+
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ cdev->dev.driver_data = device;
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
+
return device;
}
@@ -544,6 +578,7 @@ dasd_delete_device(struct dasd_device *device)
{
struct ccw_device *cdev;
struct dasd_devmap *devmap;
+ unsigned long flags;
/* First remove device pointer from devmap. */
devmap = dasd_find_busid(device->cdev->dev.bus_id);
@@ -557,9 +592,16 @@ dasd_delete_device(struct dasd_device *device)
devmap->device = NULL;
spin_unlock(&dasd_devmap_lock);
- /* Drop ref_count by 2, one for the devmap reference and
- * one for the passed reference. */
- atomic_sub(2, &device->ref_count);
+ /* Disconnect dasd_device structure from ccw_device structure. */
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ device->cdev->dev.driver_data = NULL;
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
+
+ /*
+ * Drop ref_count by 3, one for the devmap reference, one for
+ * the cdev reference and one for the passed reference.
+ */
+ atomic_sub(3, &device->ref_count);
/* Wait for reference counter to drop to zero. */
wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);
@@ -568,9 +610,6 @@ dasd_delete_device(struct dasd_device *device)
cdev = device->cdev;
device->cdev = NULL;
- /* Disconnect dasd_devmap structure from ccw_device structure. */
- cdev->dev.driver_data = NULL;
-
/* Put ccw_device structure. */
put_device(&cdev->dev);
@@ -590,21 +629,32 @@ dasd_put_device_wake(struct dasd_device *device)
/*
* Return dasd_device structure associated with cdev.
+ * This function needs to be called with the ccw device
+ * lock held. It can be used from interrupt context.
+ */
+struct dasd_device *
+dasd_device_from_cdev_locked(struct ccw_device *cdev)
+{
+ struct dasd_device *device = cdev->dev.driver_data;
+
+ if (!device)
+ return ERR_PTR(-ENODEV);
+ dasd_get_device(device);
+ return device;
+}
+
+/*
+ * Return dasd_device structure associated with cdev.
*/
struct dasd_device *
dasd_device_from_cdev(struct ccw_device *cdev)
{
- struct dasd_devmap *devmap;
struct dasd_device *device;
+ unsigned long flags;
- device = ERR_PTR(-ENODEV);
- spin_lock(&dasd_devmap_lock);
- devmap = cdev->dev.driver_data;
- if (devmap && devmap->device) {
- device = devmap->device;
- dasd_get_device(device);
- }
- spin_unlock(&dasd_devmap_lock);
+ spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
+ device = dasd_device_from_cdev_locked(cdev);
+ spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
return device;
}
@@ -630,7 +680,8 @@ dasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
-dasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_ro_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct dasd_devmap *devmap;
int ro_flag;
@@ -658,7 +709,7 @@ static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);
* use_diag controls whether the driver should use diag rather than ssch
* to talk to the device
*/
-static ssize_t
+static ssize_t
dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct dasd_devmap *devmap;
@@ -673,7 +724,8 @@ dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static ssize_t
-dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+dasd_use_diag_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct dasd_devmap *devmap;
ssize_t rc;
@@ -697,22 +749,23 @@ dasd_use_diag_store(struct device *dev, struct device_attribute *attr, const cha
return rc;
}
-static
-DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
+static DEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);
static ssize_t
-dasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf)
+dasd_discipline_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct dasd_devmap *devmap;
- char *dname;
+ struct dasd_device *device;
+ ssize_t len;
- spin_lock(&dasd_devmap_lock);
- dname = "none";
- devmap = dev->driver_data;
- if (devmap && devmap->device && devmap->device->discipline)
- dname = devmap->device->discipline->name;
- spin_unlock(&dasd_devmap_lock);
- return snprintf(buf, PAGE_SIZE, "%s\n", dname);
+ device = dasd_device_from_cdev(to_ccwdev(dev));
+ if (!IS_ERR(device) && device->discipline) {
+ len = snprintf(buf, PAGE_SIZE, "%s\n",
+ device->discipline->name);
+ dasd_put_device(device);
+ } else
+ len = snprintf(buf, PAGE_SIZE, "none\n");
+ return len;
}
static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);
@@ -834,7 +887,6 @@ static struct attribute_group dasd_attr_group = {
.attrs = dasd_attrs,
};
-
/*
* Return copy of the device unique identifier.
*/
@@ -854,21 +906,52 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid)
/*
* Register the given device unique identifier into devmap struct.
+ * In addition check if the related storage server subsystem ID is already
+ * contained in the dasd_server_ssid_list. If subsystem ID is not contained,
+ * create new entry.
+ * Return 0 if server was already in serverlist,
+ * 1 if the server was added successful
+ * <0 in case of error.
*/
int
dasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid)
{
struct dasd_devmap *devmap;
+ struct dasd_server_ssid_map *srv, *tmp;
devmap = dasd_find_busid(cdev->dev.bus_id);
if (IS_ERR(devmap))
return PTR_ERR(devmap);
+
+ /* generate entry for server_ssid_map */
+ srv = (struct dasd_server_ssid_map *)
+ kzalloc(sizeof(struct dasd_server_ssid_map), GFP_KERNEL);
+ if (!srv)
+ return -ENOMEM;
+ strncpy(srv->sid.vendor, uid->vendor, sizeof(srv->sid.vendor) - 1);
+ strncpy(srv->sid.serial, uid->serial, sizeof(srv->sid.serial) - 1);
+ srv->sid.ssid = uid->ssid;
+
+ /* server is already contained ? */
spin_lock(&dasd_devmap_lock);
devmap->uid = *uid;
+ list_for_each_entry(tmp, &dasd_server_ssid_list, list) {
+ if (!memcmp(&srv->sid, &tmp->sid,
+ sizeof(struct system_id))) {
+ kfree(srv);
+ srv = NULL;
+ break;
+ }
+ }
+
+ /* add servermap to serverlist */
+ if (srv)
+ list_add(&srv->list, &dasd_server_ssid_list);
spin_unlock(&dasd_devmap_lock);
- return 0;
+
+ return (srv ? 1 : 0);
}
-EXPORT_SYMBOL(dasd_set_uid);
+EXPORT_SYMBOL_GPL(dasd_set_uid);
/*
* Return value of the specified feature.
@@ -880,7 +963,7 @@ dasd_get_feature(struct ccw_device *cdev, int feature)
devmap = dasd_find_busid(cdev->dev.bus_id);
if (IS_ERR(devmap))
- return (int) PTR_ERR(devmap);
+ return PTR_ERR(devmap);
return ((devmap->features & feature) != 0);
}
@@ -896,7 +979,7 @@ dasd_set_feature(struct ccw_device *cdev, int feature, int flag)
devmap = dasd_find_busid(cdev->dev.bus_id);
if (IS_ERR(devmap))
- return (int) PTR_ERR(devmap);
+ return PTR_ERR(devmap);
spin_lock(&dasd_devmap_lock);
if (flag)
@@ -932,8 +1015,10 @@ dasd_devmap_init(void)
dasd_max_devindex = 0;
for (i = 0; i < 256; i++)
INIT_LIST_HEAD(&dasd_hashlists[i]);
- return 0;
+ /* Initialize servermap structure. */
+ INIT_LIST_HEAD(&dasd_server_ssid_list);
+ return 0;
}
void
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 3f9d704d265..9d051e5687e 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_diag.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Based on.......: linux/drivers/s390/block/mdisk.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -64,44 +63,26 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
* and function code cmd.
* In case of an exception return 3. Otherwise return result of bitwise OR of
* resulting condition code and DIAG return code. */
-static __inline__ int
-dia250(void *iob, int cmd)
+static inline int dia250(void *iob, int cmd)
{
+ register unsigned long reg0 asm ("0") = (unsigned long) iob;
typedef union {
struct dasd_diag_init_io init_io;
struct dasd_diag_rw_io rw_io;
} addr_type;
int rc;
- __asm__ __volatile__(
-#ifdef CONFIG_64BIT
- " lghi %0,3\n"
- " lgr 0,%3\n"
+ rc = 3;
+ asm volatile(
" diag 0,%2,0x250\n"
"0: ipm %0\n"
" srl %0,28\n"
" or %0,1\n"
"1:\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous\n"
-#else
- " lhi %0,3\n"
- " lr 0,%3\n"
- " diag 0,%2,0x250\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- " or %0,1\n"
- "1:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous\n"
-#endif
- : "=&d" (rc), "=m" (*(addr_type *) iob)
- : "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
- : "0", "1", "cc");
+ EX_TABLE(0b,1b)
+ : "+d" (rc), "=m" (*(addr_type *) iob)
+ : "d" (cmd), "d" (reg0), "m" (*(addr_type *) iob)
+ : "1", "cc");
return rc;
}
@@ -336,7 +317,7 @@ dasd_diag_check_device(struct dasd_device *device)
private = (struct dasd_diag_private *) device->private;
if (private == NULL) {
- private = kmalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
+ private = kzalloc(sizeof(struct dasd_diag_private),GFP_KERNEL);
if (private == NULL) {
DEV_MESSAGE(KERN_WARNING, device, "%s",
"memory allocation failed for private data");
@@ -527,7 +508,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
datasize, device);
if (IS_ERR(cqr))
return cqr;
-
+
dreq = (struct dasd_diag_req *) cqr->data;
dreq->block_count = count;
dbio = dreq->bio;
diff --git a/drivers/s390/block/dasd_diag.h b/drivers/s390/block/dasd_diag.h
index 38a4e55f895..b8c78267ff3 100644
--- a/drivers/s390/block/dasd_diag.h
+++ b/drivers/s390/block/dasd_diag.h
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_diag.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Based on.......: linux/drivers/s390/block/mdisk.h
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 7d5a6cee4bd..b7a7fac3f7c 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1,7 +1,7 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_eckd.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Horst Hummel <Horst.Hummel@de.ibm.com>
+ * Horst Hummel <Horst.Hummel@de.ibm.com>
* Carsten Otte <Cotte@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -24,6 +23,7 @@
#include <asm/io.h>
#include <asm/todclk.h>
#include <asm/uaccess.h>
+#include <asm/cio.h>
#include <asm/ccwdev.h>
#include "dasd_int.h"
@@ -65,16 +65,16 @@ struct dasd_eckd_private {
/* The ccw bus type uses this table to find devices that it sends to
* dasd_eckd_probe */
static struct ccw_device_id dasd_eckd_ids[] = {
- { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), driver_info: 0x1},
- { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), driver_info: 0x2},
- { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), driver_info: 0x3},
- { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), driver_info: 0x4},
- { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), driver_info: 0x5},
- { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), driver_info: 0x6},
- { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), driver_info: 0x7},
- { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), driver_info: 0x8},
- { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), driver_info: 0x9},
- { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), driver_info: 0xa},
+ { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3390, 0), .driver_info = 0x1},
+ { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3390, 0), .driver_info = 0x2},
+ { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3390, 0), .driver_info = 0x3},
+ { CCW_DEVICE_DEVTYPE (0x3990, 0, 0x3380, 0), .driver_info = 0x4},
+ { CCW_DEVICE_DEVTYPE (0x2105, 0, 0x3380, 0), .driver_info = 0x5},
+ { CCW_DEVICE_DEVTYPE (0x9343, 0, 0x9345, 0), .driver_info = 0x6},
+ { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3390, 0), .driver_info = 0x7},
+ { CCW_DEVICE_DEVTYPE (0x2107, 0, 0x3380, 0), .driver_info = 0x8},
+ { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3390, 0), .driver_info = 0x9},
+ { CCW_DEVICE_DEVTYPE (0x1750, 0, 0x3380, 0), .driver_info = 0xa},
{ /* end of list */ },
};
@@ -89,17 +89,22 @@ dasd_eckd_probe (struct ccw_device *cdev)
{
int ret;
- ret = dasd_generic_probe (cdev, &dasd_eckd_discipline);
- if (ret)
+ /* set ECKD specific ccw-device options */
+ ret = ccw_device_set_options(cdev, CCWDEV_ALLOW_FORCE);
+ if (ret) {
+ printk(KERN_WARNING
+ "dasd_eckd_probe: could not set ccw-device options "
+ "for %s\n", cdev->dev.bus_id);
return ret;
- ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP | CCWDEV_ALLOW_FORCE);
- return 0;
+ }
+ ret = dasd_generic_probe(cdev, &dasd_eckd_discipline);
+ return ret;
}
static int
dasd_eckd_set_online(struct ccw_device *cdev)
{
- return dasd_generic_set_online (cdev, &dasd_eckd_discipline);
+ return dasd_generic_set_online(cdev, &dasd_eckd_discipline);
}
static struct ccw_driver dasd_eckd_driver = {
@@ -210,14 +215,14 @@ check_XRC (struct ccw1 *de_ccw,
/* switch on System Time Stamp - needed for XRC Support */
if (private->rdc_data.facilities.XRC_supported) {
-
+
data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */
data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
+
data->ep_sys_time = get_clock ();
-
+
de_ccw->count = sizeof (struct DE_eckd_data);
- de_ccw->flags |= CCW_FLAG_SLI;
+ de_ccw->flags |= CCW_FLAG_SLI;
}
return;
@@ -296,8 +301,8 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
/* check for sequential prestage - enhance cylinder range */
if (data->attributes.operation == DASD_SEQ_PRESTAGE ||
data->attributes.operation == DASD_SEQ_ACCESS) {
-
- if (end.cyl + private->attrib.nr_cyl < geo.cyl)
+
+ if (end.cyl + private->attrib.nr_cyl < geo.cyl)
end.cyl += private->attrib.nr_cyl;
else
end.cyl = (geo.cyl - 1);
@@ -317,7 +322,7 @@ locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
struct dasd_eckd_private *private;
int sector;
int dn, d;
-
+
private = (struct dasd_eckd_private *) device->private;
DBF_DEV_EVENT(DBF_INFO, device,
@@ -463,11 +468,11 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid)
return -ENODEV;
memset(uid, 0, sizeof(struct dasd_uid));
- strncpy(uid->vendor, confdata->ned1.HDA_manufacturer,
- sizeof(uid->vendor) - 1);
+ memcpy(uid->vendor, confdata->ned1.HDA_manufacturer,
+ sizeof(uid->vendor) - 1);
EBCASC(uid->vendor, sizeof(uid->vendor) - 1);
- strncpy(uid->serial, confdata->ned1.HDA_location,
- sizeof(uid->serial) - 1);
+ memcpy(uid->serial, confdata->ned1.HDA_location,
+ sizeof(uid->serial) - 1);
EBCASC(uid->serial, sizeof(uid->serial) - 1);
uid->ssid = confdata->neq.subsystemID;
if (confdata->ned2.sneq.flags == 0x40) {
@@ -541,6 +546,86 @@ dasd_eckd_read_conf(struct dasd_device *device)
}
/*
+ * Build CP for Perform Subsystem Function - SSC.
+ */
+struct dasd_ccw_req *
+dasd_eckd_build_psf_ssc(struct dasd_device *device)
+{
+ struct dasd_ccw_req *cqr;
+ struct dasd_psf_ssc_data *psf_ssc_data;
+ struct ccw1 *ccw;
+
+ cqr = dasd_smalloc_request("ECKD", 1 /* PSF */ ,
+ sizeof(struct dasd_psf_ssc_data),
+ device);
+
+ if (IS_ERR(cqr)) {
+ DEV_MESSAGE(KERN_WARNING, device, "%s",
+ "Could not allocate PSF-SSC request");
+ return cqr;
+ }
+ psf_ssc_data = (struct dasd_psf_ssc_data *)cqr->data;
+ psf_ssc_data->order = PSF_ORDER_SSC;
+ psf_ssc_data->suborder = 0x08;
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = DASD_ECKD_CCW_PSF;
+ ccw->cda = (__u32)(addr_t)psf_ssc_data;
+ ccw->count = 66;
+
+ cqr->device = device;
+ cqr->expires = 10*HZ;
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+ return cqr;
+}
+
+/*
+ * Perform Subsystem Function.
+ * It is necessary to trigger CIO for channel revalidation since this
+ * call might change behaviour of DASD devices.
+ */
+static int
+dasd_eckd_psf_ssc(struct dasd_device *device)
+{
+ struct dasd_ccw_req *cqr;
+ int rc;
+
+ cqr = dasd_eckd_build_psf_ssc(device);
+ if (IS_ERR(cqr))
+ return PTR_ERR(cqr);
+
+ rc = dasd_sleep_on(cqr);
+ if (!rc)
+ /* trigger CIO to reprobe devices */
+ css_schedule_reprobe();
+ dasd_sfree_request(cqr, cqr->device);
+ return rc;
+}
+
+/*
+ * Valide storage server of current device.
+ */
+static int
+dasd_eckd_validate_server(struct dasd_device *device, struct dasd_uid *uid)
+{
+ int rc;
+
+ /* Currently PAV is the only reason to 'validate' server on LPAR */
+ if (dasd_nopav || MACHINE_IS_VM)
+ return 0;
+
+ rc = dasd_eckd_psf_ssc(device);
+ /* may be requested feature is not available on server,
+ * therefore just report error and go ahead */
+ DEV_MESSAGE(KERN_INFO, device,
+ "PSF-SSC on storage subsystem %s.%s.%04x returned rc=%d",
+ uid->vendor, uid->serial, uid->ssid, rc);
+ /* RE-Read Configuration Data */
+ return dasd_eckd_read_conf(device);
+}
+
+/*
* Check device characteristics.
* If the device is accessible using ECKD discipline, the device is enabled.
*/
@@ -554,7 +639,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
private = (struct dasd_eckd_private *) device->private;
if (private == NULL) {
- private = kmalloc(sizeof(struct dasd_eckd_private),
+ private = kzalloc(sizeof(struct dasd_eckd_private),
GFP_KERNEL | GFP_DMA);
if (private == NULL) {
DEV_MESSAGE(KERN_WARNING, device, "%s",
@@ -562,7 +647,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
"data");
return -ENOMEM;
}
- memset(private, 0, sizeof(struct dasd_eckd_private));
device->private = (void *) private;
}
/* Invalidate status of initial analysis. */
@@ -571,16 +655,29 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
private->attrib.operation = DASD_NORMAL_CACHE;
private->attrib.nr_cyl = 0;
+ /* Read Configuration Data */
+ rc = dasd_eckd_read_conf(device);
+ if (rc)
+ return rc;
+
+ /* Generate device unique id and register in devmap */
+ rc = dasd_eckd_generate_uid(device, &uid);
+ if (rc)
+ return rc;
+ rc = dasd_set_uid(device->cdev, &uid);
+ if (rc == 1) /* new server found */
+ rc = dasd_eckd_validate_server(device, &uid);
+ if (rc)
+ return rc;
+
/* Read Device Characteristics */
rdc_data = (void *) &(private->rdc_data);
memset(rdc_data, 0, sizeof(rdc_data));
rc = read_dev_chars(device->cdev, &rdc_data, 64);
- if (rc) {
+ if (rc)
DEV_MESSAGE(KERN_WARNING, device,
- "Read device characteristics returned error %d",
- rc);
- return rc;
- }
+ "Read device characteristics returned "
+ "rc=%d", rc);
DEV_MESSAGE(KERN_INFO, device,
"%04X/%02X(CU:%04X/%02X) Cyl:%d Head:%d Sec:%d",
@@ -591,19 +688,6 @@ dasd_eckd_check_characteristics(struct dasd_device *device)
private->rdc_data.no_cyl,
private->rdc_data.trk_per_cyl,
private->rdc_data.sec_per_trk);
-
- /* Read Configuration Data */
- rc = dasd_eckd_read_conf (device);
- if (rc)
- return rc;
-
- /* Generate device unique id and register in devmap */
- rc = dasd_eckd_generate_uid(device, &uid);
- if (rc)
- return rc;
-
- rc = dasd_set_uid(device->cdev, &uid);
-
return rc;
}
@@ -773,7 +857,7 @@ dasd_eckd_end_analysis(struct dasd_device *device)
((private->rdc_data.no_cyl *
private->rdc_data.trk_per_cyl *
blk_per_trk * (device->bp_block >> 9)) >> 1),
- ((blk_per_trk * device->bp_block) >> 10),
+ ((blk_per_trk * device->bp_block) >> 10),
private->uses_cdl ?
"compatible disk layout" : "linux disk layout");
@@ -970,7 +1054,7 @@ dasd_eckd_format_device(struct dasd_device * device,
if (i < 3) {
ect->kl = 4;
ect->dl = sizes_trk0[i] - 4;
- }
+ }
}
if ((fdata->intensity & 0x08) &&
fdata->start_unit == 1) {
@@ -1270,7 +1354,7 @@ dasd_eckd_fill_info(struct dasd_device * device,
/*
* Release device ioctl.
- * Buils a channel programm to releases a prior reserved
+ * Buils a channel programm to releases a prior reserved
* (see dasd_eckd_reserve) device.
*/
static int
@@ -1310,8 +1394,8 @@ dasd_eckd_release(struct dasd_device *device)
/*
* Reserve device ioctl.
* Options are set to 'synchronous wait for interrupt' and
- * 'timeout the request'. This leads to a terminate IO if
- * the interrupt is outstanding for a certain time.
+ * 'timeout the request'. This leads to a terminate IO if
+ * the interrupt is outstanding for a certain time.
*/
static int
dasd_eckd_reserve(struct dasd_device *device)
@@ -1349,7 +1433,7 @@ dasd_eckd_reserve(struct dasd_device *device)
/*
* Steal lock ioctl - unconditional reserve device.
- * Buils a channel programm to break a device's reservation.
+ * Buils a channel programm to break a device's reservation.
* (unconditional reserve)
*/
static int
@@ -1522,6 +1606,40 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
}
/*
+ * Dump the range of CCWs into 'page' buffer
+ * and return number of printed chars.
+ */
+static inline int
+dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
+{
+ int len, count;
+ char *datap;
+
+ len = 0;
+ while (from <= to) {
+ len += sprintf(page + len, KERN_ERR PRINTK_HEADER
+ " CCW %p: %08X %08X DAT:",
+ from, ((int *) from)[0], ((int *) from)[1]);
+
+ /* get pointer to data (consider IDALs) */
+ if (from->flags & CCW_FLAG_IDA)
+ datap = (char *) *((addr_t *) (addr_t) from->cda);
+ else
+ datap = (char *) ((addr_t) from->cda);
+
+ /* dump data (max 32 bytes) */
+ for (count = 0; count < from->count && count < 32; count++) {
+ if (count % 8 == 0) len += sprintf(page + len, " ");
+ if (count % 4 == 0) len += sprintf(page + len, " ");
+ len += sprintf(page + len, "%02x", datap[count]);
+ }
+ len += sprintf(page + len, "\n");
+ from++;
+ }
+ return len;
+}
+
+/*
* Print sense data and related channel program.
* Parts are printed because printk buffer is only 1024 bytes.
*/
@@ -1530,8 +1648,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
struct irb *irb)
{
char *page;
- struct ccw1 *act, *end, *last;
- int len, sl, sct, count;
+ struct ccw1 *first, *last, *fail, *from, *to;
+ int len, sl, sct;
page = (char *) get_zeroed_page(GFP_ATOMIC);
if (page == NULL) {
@@ -1539,7 +1657,8 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
"No memory to dump sense data");
return;
}
- len = sprintf(page, KERN_ERR PRINTK_HEADER
+ /* dump the sense data */
+ len = sprintf(page, KERN_ERR PRINTK_HEADER
" I/O status report for device %s:\n",
device->cdev->dev.bus_id);
len += sprintf(page + len, KERN_ERR PRINTK_HEADER
@@ -1564,87 +1683,55 @@ dasd_eckd_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
if (irb->ecw[27] & DASD_SENSE_BIT_0) {
/* 24 Byte Sense Data */
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " 24 Byte: %x MSG %x, "
- "%s MSGb to SYSOP\n",
- irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
- irb->ecw[1] & 0x10 ? "" : "no");
+ sprintf(page + len, KERN_ERR PRINTK_HEADER
+ " 24 Byte: %x MSG %x, "
+ "%s MSGb to SYSOP\n",
+ irb->ecw[7] >> 4, irb->ecw[7] & 0x0f,
+ irb->ecw[1] & 0x10 ? "" : "no");
} else {
/* 32 Byte Sense Data */
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " 32 Byte: Format: %x "
- "Exception class %x\n",
- irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
+ sprintf(page + len, KERN_ERR PRINTK_HEADER
+ " 32 Byte: Format: %x "
+ "Exception class %x\n",
+ irb->ecw[6] & 0x0f, irb->ecw[22] >> 4);
}
} else {
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " SORRY - NO VALID SENSE AVAILABLE\n");
+ sprintf(page + len, KERN_ERR PRINTK_HEADER
+ " SORRY - NO VALID SENSE AVAILABLE\n");
}
- MESSAGE_LOG(KERN_ERR, "%s",
- page + sizeof(KERN_ERR PRINTK_HEADER));
-
- /* dump the Channel Program */
- /* print first CCWs (maximum 8) */
- act = req->cpaddr;
- for (last = act; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
- end = min(act + 8, last);
- len = sprintf(page, KERN_ERR PRINTK_HEADER
+ printk("%s", page);
+
+ /* dump the Channel Program (max 140 Bytes per line) */
+ /* Count CCW and print first CCWs (maximum 1024 % 140 = 7) */
+ first = req->cpaddr;
+ for (last = first; last->flags & (CCW_FLAG_CC | CCW_FLAG_DC); last++);
+ to = min(first + 6, last);
+ len = sprintf(page, KERN_ERR PRINTK_HEADER
" Related CP in req: %p\n", req);
- while (act <= end) {
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " CCW %p: %08X %08X DAT:",
- act, ((int *) act)[0], ((int *) act)[1]);
- for (count = 0; count < 32 && count < act->count;
- count += sizeof(int))
- len += sprintf(page + len, " %08X",
- ((int *) (addr_t) act->cda)
- [(count>>2)]);
- len += sprintf(page + len, "\n");
- act++;
- }
- MESSAGE_LOG(KERN_ERR, "%s",
- page + sizeof(KERN_ERR PRINTK_HEADER));
+ dasd_eckd_dump_ccw_range(first, to, page + len);
+ printk("%s", page);
- /* print failing CCW area */
+ /* print failing CCW area (maximum 4) */
+ /* scsw->cda is either valid or zero */
len = 0;
- if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) {
- act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2;
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
- }
- end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last);
- while (act <= end) {
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " CCW %p: %08X %08X DAT:",
- act, ((int *) act)[0], ((int *) act)[1]);
- for (count = 0; count < 32 && count < act->count;
- count += sizeof(int))
- len += sprintf(page + len, " %08X",
- ((int *) (addr_t) act->cda)
- [(count>>2)]);
- len += sprintf(page + len, "\n");
- act++;
+ from = ++to;
+ fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */
+ if (from < fail - 2) {
+ from = fail - 2; /* there is a gap - print header */
+ len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n");
}
+ to = min(fail + 1, last);
+ len += dasd_eckd_dump_ccw_range(from, to, page + len);
- /* print last CCWs */
- if (act < last - 2) {
- act = last - 2;
+ /* print last CCWs (maximum 2) */
+ from = max(from, ++to);
+ if (from < last - 1) {
+ from = last - 1; /* there is a gap - print header */
len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n");
}
- while (act <= last) {
- len += sprintf(page + len, KERN_ERR PRINTK_HEADER
- " CCW %p: %08X %08X DAT:",
- act, ((int *) act)[0], ((int *) act)[1]);
- for (count = 0; count < 32 && count < act->count;
- count += sizeof(int))
- len += sprintf(page + len, " %08X",
- ((int *) (addr_t) act->cda)
- [(count>>2)]);
- len += sprintf(page + len, "\n");
- act++;
- }
+ len += dasd_eckd_dump_ccw_range(from, last, page + len);
if (len > 0)
- MESSAGE_LOG(KERN_ERR, "%s",
- page + sizeof(KERN_ERR PRINTK_HEADER));
+ printk("%s", page);
free_page((unsigned long) page);
}
@@ -1685,14 +1772,8 @@ static struct dasd_discipline dasd_eckd_discipline = {
static int __init
dasd_eckd_init(void)
{
- int ret;
-
ASCEBC(dasd_eckd_discipline.ebcname, 4);
-
- ret = ccw_driver_register(&dasd_eckd_driver);
- if (!ret)
- dasd_generic_auto_online(&dasd_eckd_driver);
- return ret;
+ return ccw_driver_register(&dasd_eckd_driver);
}
static void __exit
@@ -1703,22 +1784,3 @@ dasd_eckd_cleanup(void)
module_init(dasd_eckd_init);
module_exit(dasd_eckd_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index d5734e976e1..712ff165013 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -1,7 +1,7 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_eckd.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Horst Hummel <Horst.Hummel@de.ibm.com>
+ * Horst Hummel <Horst.Hummel@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
*
@@ -41,9 +41,10 @@
#define DASD_ECKD_CCW_RESERVE 0xB4
/*
- *Perform Subsystem Function / Sub-Orders
+ * Perform Subsystem Function / Sub-Orders
*/
-#define PSF_ORDER_PRSSD 0x18
+#define PSF_ORDER_PRSSD 0x18
+#define PSF_ORDER_SSC 0x1D
/*****************************************************************************
* SECTION: Type Definitions
@@ -155,7 +156,7 @@ struct dasd_eckd_characteristics {
unsigned char reserved2:4;
unsigned char reserved3:8;
unsigned char defect_wr:1;
- unsigned char XRC_supported:1;
+ unsigned char XRC_supported:1;
unsigned char reserved4:1;
unsigned char striping:1;
unsigned char reserved5:4;
@@ -343,7 +344,7 @@ struct dasd_eckd_path {
};
/*
- * Perform Subsystem Function - Prepare for Read Subsystem Data
+ * Perform Subsystem Function - Prepare for Read Subsystem Data
*/
struct dasd_psf_prssd_data {
unsigned char order;
@@ -353,4 +354,15 @@ struct dasd_psf_prssd_data {
unsigned char varies[9];
} __attribute__ ((packed));
+/*
+ * Perform Subsystem Function - Set Subsystem Characteristics
+ */
+struct dasd_psf_ssc_data {
+ unsigned char order;
+ unsigned char flags;
+ unsigned char cu_type[4];
+ unsigned char suborder;
+ unsigned char reserved[59];
+} __attribute__((packed));
+
#endif /* DASD_ECKD_H */
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
index 2d946b6ca07..e0bf30ebb21 100644
--- a/drivers/s390/block/dasd_eer.c
+++ b/drivers/s390/block/dasd_eer.c
@@ -89,7 +89,7 @@ struct eerbuffer {
};
static LIST_HEAD(bufferlist);
-static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bufferlock);
static DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
/*
@@ -276,7 +276,7 @@ struct dasd_eer_header {
__u64 tv_sec;
__u64 tv_usec;
char busid[DASD_EER_BUSID_SIZE];
-};
+} __attribute__ ((packed));
/*
* The following function can be used for those triggers that have
@@ -521,6 +521,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp)
unsigned long flags;
eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+ if (!eerb)
+ return -ENOMEM;
eerb->buffer_page_count = eer_pages;
if (eerb->buffer_page_count < 1 ||
eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {
@@ -676,7 +678,7 @@ int __init dasd_eer_init(void)
return 0;
}
-void __exit dasd_eer_exit(void)
+void dasd_eer_exit(void)
{
WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
}
diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c
index b842377cb0c..58a65097922 100644
--- a/drivers/s390/block/dasd_erp.c
+++ b/drivers/s390/block/dasd_erp.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/init.h>
@@ -90,7 +89,7 @@ dasd_default_erp_action(struct dasd_ccw_req * cqr)
/* just retry - there is nothing to save ... I got no sense data.... */
if (cqr->retries > 0) {
- DEV_MESSAGE (KERN_DEBUG, device,
+ DEV_MESSAGE (KERN_DEBUG, device,
"default ERP called (%i retries left)",
cqr->retries);
cqr->lpm = LPM_ANYPATH;
@@ -155,7 +154,7 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
/*
* Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
+ * all error recovery ccws that have been chained in from of the
* real request.
*/
static inline void
@@ -227,12 +226,12 @@ dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
/*
* Log bytes arround failed CCW but only if we did
* not log the whole CP of the CCW is outside the
- * logged CP.
+ * logged CP.
*/
if (cplength > 40 ||
((addr_t) cpa < (addr_t) lcqr->cpaddr &&
(addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
+
DEV_MESSAGE(KERN_ERR, device,
"Failed CCW (%p) (area):",
(void *) (long) cpa);
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index 91145698f8e..e85015be109 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_fba.c
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
@@ -6,7 +6,6 @@
*
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <asm/debug.h>
@@ -45,8 +44,8 @@ struct dasd_fba_private {
};
static struct ccw_device_id dasd_fba_ids[] = {
- { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), driver_info: 0x1},
- { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), driver_info: 0x2},
+ { CCW_DEVICE_DEVTYPE (0x6310, 0, 0x9336, 0), .driver_info = 0x1},
+ { CCW_DEVICE_DEVTYPE (0x3880, 0, 0x3370, 0), .driver_info = 0x2},
{ /* end of list */ },
};
@@ -56,19 +55,13 @@ static struct ccw_driver dasd_fba_driver; /* see below */
static int
dasd_fba_probe(struct ccw_device *cdev)
{
- int ret;
-
- ret = dasd_generic_probe (cdev, &dasd_fba_discipline);
- if (ret)
- return ret;
- ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
- return 0;
+ return dasd_generic_probe(cdev, &dasd_fba_discipline);
}
static int
dasd_fba_set_online(struct ccw_device *cdev)
{
- return dasd_generic_set_online (cdev, &dasd_fba_discipline);
+ return dasd_generic_set_online(cdev, &dasd_fba_discipline);
}
static struct ccw_driver dasd_fba_driver = {
@@ -125,13 +118,13 @@ static int
dasd_fba_check_characteristics(struct dasd_device *device)
{
struct dasd_fba_private *private;
- struct ccw_device *cdev = device->cdev;
+ struct ccw_device *cdev = device->cdev;
void *rdc_data;
int rc;
private = (struct dasd_fba_private *) device->private;
if (private == NULL) {
- private = kmalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
+ private = kzalloc(sizeof(struct dasd_fba_private), GFP_KERNEL);
if (private == NULL) {
DEV_MESSAGE(KERN_WARNING, device, "%s",
"memory allocation failed for private "
@@ -204,7 +197,7 @@ dasd_fba_examine_error(struct dasd_ccw_req * cqr, struct irb * irb)
if (irb->scsw.cstat == 0x00 &&
irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))
return dasd_era_none;
-
+
cdev = device->cdev;
switch (cdev->id.dev_type) {
case 0x3370:
@@ -539,7 +532,7 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
* 8192 bytes (=2 pages). For 64 bit one dasd_mchunkt_t structure has
* 24 bytes, the struct dasd_ccw_req has 136 bytes and each block can use
* up to 16 bytes (8 for the ccw and 8 for the idal pointer). In
- * addition we have one define extent ccw + 16 bytes of data and a
+ * addition we have one define extent ccw + 16 bytes of data and a
* locate record ccw for each block (stupid devices!) + 16 bytes of data.
* That makes:
* (8192 - 24 - 136 - 8 - 16) / 40 = 200.2 blocks at maximum.
@@ -569,16 +562,8 @@ static struct dasd_discipline dasd_fba_discipline = {
static int __init
dasd_fba_init(void)
{
- int ret;
-
ASCEBC(dasd_fba_discipline.ebcname, 4);
-
- ret = ccw_driver_register(&dasd_fba_driver);
- if (ret)
- return ret;
-
- dasd_generic_auto_online(&dasd_fba_driver);
- return 0;
+ return ccw_driver_register(&dasd_fba_driver);
}
static void __exit
@@ -589,22 +574,3 @@ dasd_fba_cleanup(void)
module_init(dasd_fba_init);
module_exit(dasd_fba_cleanup);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_fba.h b/drivers/s390/block/dasd_fba.h
index da1fa91fc01..14c910baa5f 100644
--- a/drivers/s390/block/dasd_fba.h
+++ b/drivers/s390/block/dasd_fba.h
@@ -1,4 +1,4 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_fba.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index fce2835e7d1..d163632101d 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/blkpg.h>
@@ -68,8 +67,6 @@ dasd_gendisk_alloc(struct dasd_device *device)
}
len += sprintf(gdp->disk_name + len, "%c", 'a'+(device->devindex%26));
- sprintf(gdp->devfs_name, "dasd/%s", device->cdev->dev.bus_id);
-
if (device->features & DASD_FEATURE_READONLY)
set_disk_ro(gdp, 1);
gdp->private_data = device;
@@ -86,10 +83,12 @@ dasd_gendisk_alloc(struct dasd_device *device)
void
dasd_gendisk_free(struct dasd_device *device)
{
- del_gendisk(device->gdp);
- device->gdp->queue = 0;
- put_disk(device->gdp);
- device->gdp = 0;
+ if (device->gdp) {
+ del_gendisk(device->gdp);
+ device->gdp->queue = NULL;
+ put_disk(device->gdp);
+ device->gdp = NULL;
+ }
}
/*
@@ -139,7 +138,7 @@ dasd_destroy_partitions(struct dasd_device * device)
* device->bdev to lower the offline open_count limit again.
*/
bdev = device->bdev;
- device->bdev = 0;
+ device->bdev = NULL;
/*
* See fs/partition/check.c:delete_partition
@@ -148,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
*/
memset(&bpart, 0, sizeof(struct blkpg_partition));
memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
- barg.data = &bpart;
+ barg.data = (void __user *) &bpart;
barg.op = BLKPG_DEL_PARTITION;
for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index d4b13e300a7..9f52004f6fc 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -1,7 +1,7 @@
-/*
+/*
* File...........: linux/drivers/s390/block/dasd_int.h
* Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Horst Hummel <Horst.Hummel@de.ibm.com>
+ * Horst Hummel <Horst.Hummel@de.ibm.com>
* Martin Schwidefsky <schwidefsky@de.ibm.com>
* Bugreports.to..: <Linux390@de.ibm.com>
* (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000
@@ -54,7 +54,6 @@
#include <linux/module.h>
#include <linux/wait.h>
#include <linux/blkdev.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
@@ -186,7 +185,7 @@ struct dasd_ccw_req {
void *callback_data;
};
-/*
+/*
* dasd_ccw_req -> status can be:
*/
#define DASD_CQR_FILLED 0x00 /* request is ready to be processed */
@@ -248,7 +247,7 @@ struct dasd_discipline {
/*
* Error recovery functions. examine_error() returns a value that
* indicates what to do for an error condition. If examine_error()
- * returns 'dasd_era_recover' erp_action() is called to create a
+ * returns 'dasd_era_recover' erp_action() is called to create a
* special error recovery ccw. erp_postaction() is called after
* an error recovery ccw has finished its execution. dump_sense
* is called for every error condition to print the sense data
@@ -302,11 +301,11 @@ struct dasd_device {
spinlock_t request_queue_lock;
struct block_device *bdev;
unsigned int devindex;
- unsigned long blocks; /* size of volume in blocks */
- unsigned int bp_block; /* bytes per block */
- unsigned int s2b_shift; /* log2 (bp_block/512) */
- unsigned long flags; /* per device flags */
- unsigned short features; /* copy of devmap-features (read-only!) */
+ unsigned long blocks; /* size of volume in blocks */
+ unsigned int bp_block; /* bytes per block */
+ unsigned int s2b_shift; /* log2 (bp_block/512) */
+ unsigned long flags; /* per device flags */
+ unsigned short features; /* copy of devmap-features (read-only!) */
/* extended error reporting stuff (eer) */
struct dasd_ccw_req *eer_cqr;
@@ -513,12 +512,12 @@ void dasd_generic_remove (struct ccw_device *cdev);
int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
-void dasd_generic_auto_online (struct ccw_driver *);
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
extern int dasd_probeonly;
extern int dasd_autodetect;
+extern int dasd_nopav;
int dasd_devmap_init(void);
void dasd_devmap_exit(void);
@@ -535,6 +534,7 @@ int dasd_add_sysfs_files(struct ccw_device *);
void dasd_remove_sysfs_files(struct ccw_device *);
struct dasd_device *dasd_device_from_cdev(struct ccw_device *);
+struct dasd_device *dasd_device_from_cdev_locked(struct ccw_device *);
struct dasd_device *dasd_device_from_devindex(int);
int dasd_parse(void);
@@ -606,22 +606,3 @@ static inline int dasd_eer_enabled(struct dasd_device *device)
#endif /* __KERNEL__ */
#endif /* DASD_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: 1
- * tab-width: 8
- * End:
- */
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index b8c80d28df4..8fed3603e9e 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -9,7 +9,6 @@
*
* i/o controls for the dasd driver.
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <linux/fs.h>
@@ -90,10 +89,10 @@ static int
dasd_ioctl_quiesce(struct dasd_device *device)
{
unsigned long flags;
-
+
if (!capable (CAP_SYS_ADMIN))
return -EACCES;
-
+
DEV_MESSAGE (KERN_DEBUG, device, "%s",
"Quiesce IO on device");
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
@@ -110,13 +109,13 @@ static int
dasd_ioctl_resume(struct dasd_device *device)
{
unsigned long flags;
-
- if (!capable (CAP_SYS_ADMIN))
+
+ if (!capable (CAP_SYS_ADMIN))
return -EACCES;
DEV_MESSAGE (KERN_DEBUG, device, "%s",
"resume IO on device");
-
+
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
device->stopped &= ~DASD_STOPPED_QUIESCE;
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
@@ -287,7 +286,7 @@ dasd_ioctl_information(struct dasd_device *device,
dasd_info->open_count = atomic_read(&device->open_count);
if (!device->bdev)
dasd_info->open_count++;
-
+
/*
* check if device is really formatted
* LDL / CDL was returned by 'fill_info'
@@ -346,7 +345,7 @@ dasd_ioctl_set_ro(struct block_device *bdev, void __user *argp)
if (bdev != bdev->bd_contains)
// ro setting is not allowed for partitions
return -EINVAL;
- if (get_user(intval, (int *)argp))
+ if (get_user(intval, (int __user *)argp))
return -EFAULT;
set_disk_ro(bdev->bd_disk, intval);
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index ad23aede356..bfa010f6dab 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 54ecd548c31..a04d9120cef 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -36,7 +36,6 @@
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/sysdev.h>
#include <linux/bio.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#define XPRAM_NAME "xpram"
@@ -49,15 +48,6 @@
#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x)
-static struct sysdev_class xpram_sysclass = {
- set_kset_name("xpram"),
-};
-
-static struct sys_device xpram_sys_device = {
- .id = 0,
- .cls = &xpram_sysclass,
-};
-
typedef struct {
unsigned int size; /* size of xpram segment in pages */
unsigned int offset; /* start page of xpram segment */
@@ -72,11 +62,11 @@ static int xpram_devs;
/*
* Parameter parsing functions.
*/
-static int devs = XPRAM_DEVS;
-static unsigned int sizes[XPRAM_MAX_DEVS];
+static int __initdata devs = XPRAM_DEVS;
+static char __initdata *sizes[XPRAM_MAX_DEVS];
module_param(devs, int, 0);
-module_param_array(sizes, int, NULL, 0);
+module_param_array(sizes, charp, NULL, 0);
MODULE_PARM_DESC(devs, "number of devices (\"partitions\"), " \
"the default is " __MODULE_STRING(XPRAM_DEVS) "\n");
@@ -87,59 +77,6 @@ MODULE_PARM_DESC(sizes, "list of device (partition) sizes " \
"claimed by explicit sizes\n");
MODULE_LICENSE("GPL");
-#ifndef MODULE
-/*
- * Parses the kernel parameters given in the kernel parameter line.
- * The expected format is
- * <number_of_partitions>[","<partition_size>]*
- * where
- * devices is a positive integer that initializes xpram_devs
- * each size is a non-negative integer possibly followed by a
- * magnitude (k,K,m,M,g,G), the list of sizes initialises
- * xpram_sizes
- *
- * Arguments
- * str: substring of kernel parameter line that contains xprams
- * kernel parameters.
- *
- * Result 0 on success, -EINVAL else -- only for Version > 2.3
- *
- * Side effects
- * the global variabls devs is set to the value of
- * <number_of_partitions> and sizes[i] is set to the i-th
- * partition size (if provided). A parsing error of a value
- * results in this value being set to -EINVAL.
- */
-static int __init xpram_setup (char *str)
-{
- char *cp;
- int i;
-
- devs = simple_strtoul(str, &cp, 10);
- if (cp <= str || devs > XPRAM_MAX_DEVS)
- return 0;
- for (i = 0; (i < devs) && (*cp++ == ','); i++) {
- sizes[i] = simple_strtoul(cp, &cp, 10);
- if (*cp == 'g' || *cp == 'G') {
- sizes[i] <<= 20;
- cp++;
- } else if (*cp == 'm' || *cp == 'M') {
- sizes[i] <<= 10;
- cp++;
- } else if (*cp == 'k' || *cp == 'K')
- cp++;
- while (isspace(*cp)) cp++;
- }
- if (*cp == ',' && i >= devs)
- PRINT_WARN("partition sizes list has too many entries.\n");
- else if (*cp != 0)
- PRINT_WARN("ignored '%s' at end of parameter string.\n", cp);
- return 1;
-}
-
-__setup("xpram_parts=", xpram_setup);
-#endif
-
/*
* Copy expanded memory page (4kB) into main memory
* Arguments
@@ -152,28 +89,15 @@ __setup("xpram_parts=", xpram_setup);
*/
static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
{
- int cc;
+ int cc = 2; /* return unused cc 2 if pgin traps */
- __asm__ __volatile__ (
- " lhi %0,2\n" /* return unused cc 2 if pgin traps */
- " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifndef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (cc)
- : "a" (__pa(page_addr)), "a" (xpage_index)
- : "cc" );
+ EX_TABLE(0b,1b)
+ : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
if (cc == 3)
return -ENXIO;
if (cc == 2) {
@@ -200,28 +124,15 @@ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
*/
static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
{
- int cc;
+ int cc = 2; /* return unused cc 2 if pgin traps */
- __asm__ __volatile__ (
- " lhi %0,2\n" /* return unused cc 2 if pgout traps */
- " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifndef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (cc)
- : "a" (__pa(page_addr)), "a" (xpage_index)
- : "cc" );
+ EX_TABLE(0b,1b)
+ : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
if (cc == 3)
return -ENXIO;
if (cc == 2) {
@@ -358,6 +269,7 @@ static int __init xpram_setup_sizes(unsigned long pages)
{
unsigned long mem_needed;
unsigned long mem_auto;
+ unsigned long long size;
int mem_auto_no;
int i;
@@ -375,7 +287,19 @@ static int __init xpram_setup_sizes(unsigned long pages)
mem_needed = 0;
mem_auto_no = 0;
for (i = 0; i < xpram_devs; i++) {
- xpram_sizes[i] = (sizes[i] + 3) & -4UL;
+ if (sizes[i]) {
+ size = simple_strtoull(sizes[i], &sizes[i], 0);
+ switch (sizes[i][0]) {
+ case 'g':
+ case 'G':
+ size <<= 20;
+ break;
+ case 'm':
+ case 'M':
+ size <<= 10;
+ }
+ xpram_sizes[i] = (size + 3) & -4UL;
+ }
if (xpram_sizes[i])
mem_needed += xpram_sizes[i];
else
@@ -439,8 +363,6 @@ static int __init xpram_setup_blkdev(void)
if (rc < 0)
goto out;
- devfs_mk_dir("slram");
-
/*
* Assign the other needed values: make request function, sizes and
* hardsect size. All the minor devices feature the same value.
@@ -469,14 +391,12 @@ static int __init xpram_setup_blkdev(void)
disk->private_data = &xpram_devices[i];
disk->queue = xpram_queue;
sprintf(disk->disk_name, "slram%d", i);
- sprintf(disk->devfs_name, "slram/%d", i);
set_capacity(disk, xpram_sizes[i] << 1);
add_disk(disk);
}
return 0;
out_unreg:
- devfs_remove("slram");
unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
out:
while (i--)
@@ -495,10 +415,7 @@ static void __exit xpram_exit(void)
put_disk(xpram_disks[i]);
}
unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME);
- devfs_remove("slram");
blk_cleanup_queue(xpram_queue);
- sysdev_unregister(&xpram_sys_device);
- sysdev_class_unregister(&xpram_sysclass);
}
static int __init xpram_init(void)
@@ -510,25 +427,13 @@ static int __init xpram_init(void)
PRINT_WARN("No expanded memory available\n");
return -ENODEV;
}
- xpram_pages = xpram_highest_page_index();
+ xpram_pages = xpram_highest_page_index() + 1;
PRINT_INFO(" %u pages expanded memory found (%lu KB).\n",
xpram_pages, (unsigned long) xpram_pages*4);
rc = xpram_setup_sizes(xpram_pages);
if (rc)
return rc;
- rc = sysdev_class_register(&xpram_sysclass);
- if (rc)
- return rc;
-
- rc = sysdev_register(&xpram_sys_device);
- if (rc) {
- sysdev_class_unregister(&xpram_sysclass);
- return rc;
- }
- rc = xpram_setup_blkdev();
- if (rc)
- sysdev_unregister(&xpram_sys_device);
- return rc;
+ return xpram_setup_blkdev();
}
module_init(xpram_init);
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 0c0162ff6c0..c3e97b4fc18 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_S390_TAPE) += tape.o tape_class.o
obj-$(CONFIG_S390_TAPE_34XX) += tape_34xx.o
obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
obj-$(CONFIG_MONREADER) += monreader.o
+obj-$(CONFIG_MONWRITER) += monwriter.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 606f6ad285a..2fa566fa6da 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -11,7 +11,6 @@
* Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
@@ -694,7 +693,7 @@ raw3215_probe (struct ccw_device *cdev)
GFP_KERNEL|GFP_DMA);
if (raw->buffer == NULL) {
spin_lock(&raw3215_device_lock);
- raw3215[line] = 0;
+ raw3215[line] = NULL;
spin_unlock(&raw3215_device_lock);
kfree(raw);
return -ENOMEM;
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index ef607a1de55..7566be89068 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -8,7 +8,6 @@
* -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
*/
-#include <linux/config.h>
#include <linux/bootmem.h>
#include <linux/console.h>
#include <linux/init.h>
diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c
index be463242cf0..d83eb6358ba 100644
--- a/drivers/s390/char/ctrlchar.c
+++ b/drivers/s390/char/ctrlchar.c
@@ -7,7 +7,6 @@
*
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <asm/errno.h>
#include <linux/sysrq.h>
@@ -24,7 +23,7 @@ ctrlchar_handle_sysrq(void *tty)
handle_sysrq(ctrlchar_sysrq_key, NULL, (struct tty_struct *) tty);
}
-static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, 0);
+static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
#endif
diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c
index ca15adb140d..17027d918cf 100644
--- a/drivers/s390/char/defkeymap.c
+++ b/drivers/s390/char/defkeymap.c
@@ -83,8 +83,8 @@ static u_short shift_ctrl_map[NR_KEYS] = {
};
ushort *key_maps[MAX_NR_KEYMAPS] = {
- plain_map, shift_map, 0, 0,
- ctrl_map, shift_ctrl_map, 0
+ plain_map, shift_map, NULL, NULL,
+ ctrl_map, shift_ctrl_map, NULL,
};
unsigned int keymap_count = 4;
@@ -145,7 +145,7 @@ char *func_table[MAX_NR_FUNC] = {
func_buf + 97,
func_buf + 103,
func_buf + 109,
- 0,
+ NULL,
};
struct kbdiacr accent_table[MAX_DIACR] = {
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index a6415377bc7..b4557fa3085 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -8,7 +8,6 @@
* -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
*/
-#include <linux/config.h>
#include <linux/bootmem.h>
#include <linux/console.h>
#include <linux/init.h>
@@ -18,7 +17,6 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
-#include <asm/cpcmd.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>
@@ -237,7 +235,7 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
* Process reads from fullscreen 3270.
*/
static ssize_t
-fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
+fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
@@ -282,7 +280,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
* Process writes to fullscreen 3270.
*/
static ssize_t
-fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
+fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
{
struct fs3270 *fp;
struct raw3270_request *rq;
@@ -339,10 +337,10 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
fp->write_command = arg;
break;
case TUBGETI:
- rc = put_user(fp->read_command, (char *) arg);
+ rc = put_user(fp->read_command, (char __user *) arg);
break;
case TUBGETO:
- rc = put_user(fp->write_command,(char *) arg);
+ rc = put_user(fp->write_command,(char __user *) arg);
break;
case TUBGETMOD:
iocb.model = fp->view.model;
@@ -351,7 +349,7 @@ fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
iocb.pf_cnt = 24;
iocb.re_cnt = 20;
iocb.map = 0;
- if (copy_to_user((char *) arg, &iocb,
+ if (copy_to_user((char __user *) arg, &iocb,
sizeof(struct raw3270_iocb)))
rc = -EFAULT;
break;
@@ -480,7 +478,7 @@ fs3270_close(struct inode *inode, struct file *filp)
struct fs3270 *fp;
fp = filp->private_data;
- filp->private_data = 0;
+ filp->private_data = NULL;
if (fp) {
fp->fs_pid = 0;
raw3270_reset(&fp->view);
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index d4d2ff0a9da..3be06569180 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -7,7 +7,6 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/sysrq.h>
@@ -104,7 +103,7 @@ out_maps:
out_kbd:
kfree(kbd);
out:
- return 0;
+ return NULL;
}
void
@@ -305,7 +304,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
if (kbd->sysrq) {
if (kbd->sysrq == K(KT_LATIN, '-')) {
kbd->sysrq = 0;
- handle_sysrq(value, 0, kbd->tty);
+ handle_sysrq(value, NULL, kbd->tty);
return;
}
if (value == '-') {
@@ -364,7 +363,7 @@ do_kdsk_ioctl(struct kbd_data *kbd, struct kbentry __user *user_kbe,
/* disallocate map */
key_map = kbd->key_maps[tmp.kb_table];
if (key_map) {
- kbd->key_maps[tmp.kb_table] = 0;
+ kbd->key_maps[tmp.kb_table] = NULL;
kfree(key_map);
}
break;
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c
index fb7bc9e5eeb..a138b151009 100644
--- a/drivers/s390/char/monreader.c
+++ b/drivers/s390/char/monreader.c
@@ -586,7 +586,6 @@ static struct file_operations mon_fops = {
static struct miscdevice mon_dev = {
.name = "monreader",
- .devfs_name = "monreader",
.fops = &mon_fops,
.minor = MISC_DYNAMIC_MINOR,
};
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
new file mode 100644
index 00000000000..1e3939aeb8a
--- /dev/null
+++ b/drivers/s390/char/monwriter.c
@@ -0,0 +1,292 @@
+/*
+ * drivers/s390/char/monwriter.c
+ *
+ * Character device driver for writing z/VM *MONITOR service records.
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/ctype.h>
+#include <linux/poll.h>
+#include <asm/uaccess.h>
+#include <asm/ebcdic.h>
+#include <asm/io.h>
+#include <asm/appldata.h>
+#include <asm/monwriter.h>
+
+#define MONWRITE_MAX_DATALEN 4024
+
+static int mon_max_bufs = 255;
+
+struct mon_buf {
+ struct list_head list;
+ struct monwrite_hdr hdr;
+ int diag_done;
+ char *data;
+};
+
+struct mon_private {
+ struct list_head list;
+ struct monwrite_hdr hdr;
+ size_t hdr_to_read;
+ size_t data_to_read;
+ struct mon_buf *current_buf;
+ int mon_buf_count;
+};
+
+/*
+ * helper functions
+ */
+
+static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
+{
+ struct appldata_product_id id;
+ int rc;
+
+ strcpy(id.prod_nr, "LNXAPPL");
+ id.prod_fn = myhdr->applid;
+ id.record_nr = myhdr->record_num;
+ id.version_nr = myhdr->version;
+ id.release_nr = myhdr->release;
+ id.mod_lvl = myhdr->mod_level;
+ rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
+ if (rc <= 0)
+ return rc;
+ if (rc == 5)
+ return -EPERM;
+ printk("DIAG X'DC' error with return code: %i\n", rc);
+ return -EINVAL;
+}
+
+static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+ struct monwrite_hdr *monhdr)
+{
+ struct mon_buf *entry, *next;
+
+ list_for_each_entry_safe(entry, next, &monpriv->list, list)
+ if (entry->hdr.applid == monhdr->applid &&
+ entry->hdr.record_num == monhdr->record_num &&
+ entry->hdr.version == monhdr->version &&
+ entry->hdr.release == monhdr->release &&
+ entry->hdr.mod_level == monhdr->mod_level)
+ return entry;
+ return NULL;
+}
+
+static int monwrite_new_hdr(struct mon_private *monpriv)
+{
+ struct monwrite_hdr *monhdr = &monpriv->hdr;
+ struct mon_buf *monbuf;
+ int rc;
+
+ if (monhdr->datalen > MONWRITE_MAX_DATALEN ||
+ monhdr->mon_function > MONWRITE_START_CONFIG ||
+ monhdr->hdrlen != sizeof(struct monwrite_hdr))
+ return -EINVAL;
+ monbuf = monwrite_find_hdr(monpriv, monhdr);
+ if (monbuf) {
+ if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
+ monhdr->datalen = monbuf->hdr.datalen;
+ rc = monwrite_diag(monhdr, monbuf->data,
+ APPLDATA_STOP_REC);
+ list_del(&monbuf->list);
+ monpriv->mon_buf_count--;
+ kfree(monbuf->data);
+ kfree(monbuf);
+ monbuf = NULL;
+ }
+ } else {
+ if (monpriv->mon_buf_count >= mon_max_bufs)
+ return -ENOSPC;
+ monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
+ if (!monbuf)
+ return -ENOMEM;
+ monbuf->data = kzalloc(monbuf->hdr.datalen,
+ GFP_KERNEL | GFP_DMA);
+ if (!monbuf->data) {
+ kfree(monbuf);
+ return -ENOMEM;
+ }
+ monbuf->hdr = *monhdr;
+ list_add_tail(&monbuf->list, &monpriv->list);
+ monpriv->mon_buf_count++;
+ }
+ monpriv->current_buf = monbuf;
+ return 0;
+}
+
+static int monwrite_new_data(struct mon_private *monpriv)
+{
+ struct monwrite_hdr *monhdr = &monpriv->hdr;
+ struct mon_buf *monbuf = monpriv->current_buf;
+ int rc = 0;
+
+ switch (monhdr->mon_function) {
+ case MONWRITE_START_INTERVAL:
+ if (!monbuf->diag_done) {
+ rc = monwrite_diag(monhdr, monbuf->data,
+ APPLDATA_START_INTERVAL_REC);
+ monbuf->diag_done = 1;
+ }
+ break;
+ case MONWRITE_START_CONFIG:
+ if (!monbuf->diag_done) {
+ rc = monwrite_diag(monhdr, monbuf->data,
+ APPLDATA_START_CONFIG_REC);
+ monbuf->diag_done = 1;
+ }
+ break;
+ case MONWRITE_GEN_EVENT:
+ rc = monwrite_diag(monhdr, monbuf->data,
+ APPLDATA_GEN_EVENT_REC);
+ list_del(&monpriv->current_buf->list);
+ kfree(monpriv->current_buf->data);
+ kfree(monpriv->current_buf);
+ monpriv->current_buf = NULL;
+ break;
+ default:
+ /* monhdr->mon_function is checked in monwrite_new_hdr */
+ BUG();
+ }
+ return rc;
+}
+
+/*
+ * file operations
+ */
+
+static int monwrite_open(struct inode *inode, struct file *filp)
+{
+ struct mon_private *monpriv;
+
+ monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL);
+ if (!monpriv)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&monpriv->list);
+ monpriv->hdr_to_read = sizeof(monpriv->hdr);
+ filp->private_data = monpriv;
+ return nonseekable_open(inode, filp);
+}
+
+static int monwrite_close(struct inode *inode, struct file *filp)
+{
+ struct mon_private *monpriv = filp->private_data;
+ struct mon_buf *entry, *next;
+
+ list_for_each_entry_safe(entry, next, &monpriv->list, list) {
+ if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
+ monwrite_diag(&entry->hdr, entry->data,
+ APPLDATA_STOP_REC);
+ monpriv->mon_buf_count--;
+ list_del(&entry->list);
+ kfree(entry->data);
+ kfree(entry);
+ }
+ kfree(monpriv);
+ return 0;
+}
+
+static ssize_t monwrite_write(struct file *filp, const char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct mon_private *monpriv = filp->private_data;
+ size_t len, written;
+ void *to;
+ int rc;
+
+ for (written = 0; written < count; ) {
+ if (monpriv->hdr_to_read) {
+ len = min(count - written, monpriv->hdr_to_read);
+ to = (char *) &monpriv->hdr +
+ sizeof(monpriv->hdr) - monpriv->hdr_to_read;
+ if (copy_from_user(to, data + written, len)) {
+ rc = -EFAULT;
+ goto out_error;
+ }
+ monpriv->hdr_to_read -= len;
+ written += len;
+ if (monpriv->hdr_to_read > 0)
+ continue;
+ rc = monwrite_new_hdr(monpriv);
+ if (rc)
+ goto out_error;
+ monpriv->data_to_read = monpriv->current_buf ?
+ monpriv->current_buf->hdr.datalen : 0;
+ }
+
+ if (monpriv->data_to_read) {
+ len = min(count - written, monpriv->data_to_read);
+ to = monpriv->current_buf->data +
+ monpriv->hdr.datalen - monpriv->data_to_read;
+ if (copy_from_user(to, data + written, len)) {
+ rc = -EFAULT;
+ goto out_error;
+ }
+ monpriv->data_to_read -= len;
+ written += len;
+ if (monpriv->data_to_read > 0)
+ continue;
+ rc = monwrite_new_data(monpriv);
+ if (rc)
+ goto out_error;
+ }
+ monpriv->hdr_to_read = sizeof(monpriv->hdr);
+ }
+ return written;
+
+out_error:
+ monpriv->data_to_read = 0;
+ monpriv->hdr_to_read = sizeof(struct monwrite_hdr);
+ return rc;
+}
+
+static struct file_operations monwrite_fops = {
+ .owner = THIS_MODULE,
+ .open = &monwrite_open,
+ .release = &monwrite_close,
+ .write = &monwrite_write,
+};
+
+static struct miscdevice mon_dev = {
+ .name = "monwriter",
+ .fops = &monwrite_fops,
+ .minor = MISC_DYNAMIC_MINOR,
+};
+
+/*
+ * module init/exit
+ */
+
+static int __init mon_init(void)
+{
+ if (MACHINE_IS_VM)
+ return misc_register(&mon_dev);
+ else
+ return -ENODEV;
+}
+
+static void __exit mon_exit(void)
+{
+ WARN_ON(misc_deregister(&mon_dev) != 0);
+}
+
+module_init(mon_init);
+module_exit(mon_exit);
+
+module_param_named(max_bufs, mon_max_bufs, int, 0644);
+MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers"
+ "that can be active at one time");
+
+MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>");
+MODULE_DESCRIPTION("Character device driver for writing z/VM "
+ "APPLDATA monitor records.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index eecb2afad5c..7a84014f203 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -8,7 +8,6 @@
* -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
*/
-#include <linux/config.h>
#include <linux/bootmem.h>
#include <linux/module.h>
#include <linux/err.h>
@@ -50,6 +49,9 @@ struct raw3270 {
unsigned char *ascebc; /* ascii -> ebcdic table */
struct class_device *clttydev; /* 3270-class tty device ptr */
struct class_device *cltubdev; /* 3270-class tub device ptr */
+
+ struct raw3270_request init_request;
+ unsigned char init_data[256];
};
/* raw3270->flags */
@@ -484,8 +486,6 @@ struct raw3270_ua { /* Query Reply structure for Usable Area */
} __attribute__ ((packed)) aua;
} __attribute__ ((packed));
-static unsigned char raw3270_init_data[256];
-static struct raw3270_request raw3270_init_request;
static struct diag210 raw3270_init_diag210;
static DECLARE_MUTEX(raw3270_init_sem);
@@ -555,7 +555,7 @@ raw3270_start_init(struct raw3270 *rp, struct raw3270_view *view,
#ifdef CONFIG_TN3270_CONSOLE
if (raw3270_registered == 0) {
spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags);
- rq->callback = 0;
+ rq->callback = NULL;
rc = __raw3270_start(rp, view, rq);
if (rc == 0)
while (!raw3270_request_final(rq)) {
@@ -644,17 +644,17 @@ __raw3270_size_device(struct raw3270 *rp)
* required (3270 device switched to 'stand-by') and command
* rejects (old devices that can't do 'read partition').
*/
- memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
- memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
- /* Store 'read partition' data stream to raw3270_init_data */
- memcpy(raw3270_init_data, wbuf, sizeof(wbuf));
- INIT_LIST_HEAD(&raw3270_init_request.list);
- raw3270_init_request.ccw.cmd_code = TC_WRITESF;
- raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
- raw3270_init_request.ccw.count = sizeof(wbuf);
- raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
-
- rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+ memset(&rp->init_request, 0, sizeof(rp->init_request));
+ memset(&rp->init_data, 0, 256);
+ /* Store 'read partition' data stream to init_data */
+ memcpy(&rp->init_data, wbuf, sizeof(wbuf));
+ INIT_LIST_HEAD(&rp->init_request.list);
+ rp->init_request.ccw.cmd_code = TC_WRITESF;
+ rp->init_request.ccw.flags = CCW_FLAG_SLI;
+ rp->init_request.ccw.count = sizeof(wbuf);
+ rp->init_request.ccw.cda = (__u32) __pa(&rp->init_data);
+
+ rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
if (rc)
/* Check error cases: -ERESTARTSYS, -EIO and -EOPNOTSUPP */
return rc;
@@ -679,18 +679,18 @@ __raw3270_size_device(struct raw3270 *rp)
* The device accepted the 'read partition' command. Now
* set up a read ccw and issue it.
*/
- raw3270_init_request.ccw.cmd_code = TC_READMOD;
- raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
- raw3270_init_request.ccw.count = sizeof(raw3270_init_data);
- raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
- rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
+ rp->init_request.ccw.cmd_code = TC_READMOD;
+ rp->init_request.ccw.flags = CCW_FLAG_SLI;
+ rp->init_request.ccw.count = sizeof(rp->init_data);
+ rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
+ rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
if (rc)
return rc;
/* Got a Query Reply */
- count = sizeof(raw3270_init_data) - raw3270_init_request.rescnt;
- uap = (struct raw3270_ua *) (raw3270_init_data + 1);
+ count = sizeof(rp->init_data) - rp->init_request.rescnt;
+ uap = (struct raw3270_ua *) (rp->init_data + 1);
/* Paranoia check. */
- if (raw3270_init_data[0] != 0x88 || uap->uab.qcode != 0x81)
+ if (rp->init_data[0] != 0x88 || uap->uab.qcode != 0x81)
return -EOPNOTSUPP;
/* Copy rows/columns of default Usable Area */
rp->rows = uap->uab.h;
@@ -719,8 +719,8 @@ raw3270_size_device(struct raw3270 *rp)
rc = __raw3270_size_device_vm(rp);
else
rc = __raw3270_size_device(rp);
- raw3270_init_view.dev = 0;
- rp->view = 0;
+ raw3270_init_view.dev = NULL;
+ rp->view = NULL;
up(&raw3270_init_sem);
if (rc == 0) { /* Found something. */
/* Try to find a model. */
@@ -749,20 +749,20 @@ raw3270_reset_device(struct raw3270 *rp)
int rc;
down(&raw3270_init_sem);
- memset(&raw3270_init_request, 0, sizeof(raw3270_init_request));
- memset(raw3270_init_data, 0, sizeof(raw3270_init_data));
- /* Store reset data stream to raw3270_init_data/raw3270_init_request */
- raw3270_init_data[0] = TW_KR;
- INIT_LIST_HEAD(&raw3270_init_request.list);
- raw3270_init_request.ccw.cmd_code = TC_EWRITEA;
- raw3270_init_request.ccw.flags = CCW_FLAG_SLI;
- raw3270_init_request.ccw.count = 1;
- raw3270_init_request.ccw.cda = (__u32) __pa(raw3270_init_data);
+ memset(&rp->init_request, 0, sizeof(rp->init_request));
+ memset(&rp->init_data, 0, sizeof(rp->init_data));
+ /* Store reset data stream to init_data/init_request */
+ rp->init_data[0] = TW_KR;
+ INIT_LIST_HEAD(&rp->init_request.list);
+ rp->init_request.ccw.cmd_code = TC_EWRITEA;
+ rp->init_request.ccw.flags = CCW_FLAG_SLI;
+ rp->init_request.ccw.count = 1;
+ rp->init_request.ccw.cda = (__u32) __pa(rp->init_data);
rp->view = &raw3270_init_view;
raw3270_init_view.dev = rp;
- rc = raw3270_start_init(rp, &raw3270_init_view, &raw3270_init_request);
- raw3270_init_view.dev = 0;
- rp->view = 0;
+ rc = raw3270_start_init(rp, &raw3270_init_view, &rp->init_request);
+ raw3270_init_view.dev = NULL;
+ rp->view = NULL;
up(&raw3270_init_sem);
return rc;
}
@@ -854,7 +854,7 @@ raw3270_setup_console(struct ccw_device *cdev)
char *ascebc;
int rc;
- rp = (struct raw3270 *) alloc_bootmem(sizeof(struct raw3270));
+ rp = (struct raw3270 *) alloc_bootmem_low(sizeof(struct raw3270));
ascebc = (char *) alloc_bootmem(256);
rc = raw3270_setup_device(cdev, rp, ascebc);
if (rc)
@@ -895,7 +895,7 @@ raw3270_create_device(struct ccw_device *cdev)
char *ascebc;
int rc;
- rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL);
+ rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
if (!rp)
return ERR_PTR(-ENOMEM);
ascebc = kmalloc(256, GFP_KERNEL);
@@ -934,7 +934,7 @@ raw3270_activate_view(struct raw3270_view *view)
else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
rc = -ENODEV;
else {
- oldview = 0;
+ oldview = NULL;
if (rp->view) {
oldview = rp->view;
oldview->fn->deactivate(oldview);
@@ -951,7 +951,7 @@ raw3270_activate_view(struct raw3270_view *view)
rp->view = nv;
if (nv->fn->activate(nv) == 0)
break;
- rp->view = 0;
+ rp->view = NULL;
}
}
}
@@ -975,7 +975,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rp->view == view) {
view->fn->deactivate(view);
- rp->view = 0;
+ rp->view = NULL;
/* Move deactivated view to end of list. */
list_del_init(&view->list);
list_add_tail(&view->list, &rp->view_list);
@@ -985,7 +985,7 @@ raw3270_deactivate_view(struct raw3270_view *view)
rp->view = view;
if (view->fn->activate(view) == 0)
break;
- rp->view = 0;
+ rp->view = NULL;
}
}
}
@@ -1076,7 +1076,7 @@ raw3270_del_view(struct raw3270_view *view)
spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags);
if (rp->view == view) {
view->fn->deactivate(view);
- rp->view = 0;
+ rp->view = NULL;
}
list_del_init(&view->list);
if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
@@ -1106,10 +1106,10 @@ raw3270_delete_device(struct raw3270 *rp)
/* Remove from device chain. */
mutex_lock(&raw3270_mutex);
- if (rp->clttydev)
+ if (rp->clttydev && !IS_ERR(rp->clttydev))
class_device_destroy(class3270,
MKDEV(IBM_TTY3270_MAJOR, rp->minor));
- if (rp->cltubdev)
+ if (rp->cltubdev && !IS_ERR(rp->cltubdev))
class_device_destroy(class3270,
MKDEV(IBM_FS3270_MAJOR, rp->minor));
list_del_init(&rp->list);
@@ -1117,9 +1117,9 @@ raw3270_delete_device(struct raw3270 *rp)
/* Disconnect from ccw_device. */
cdev = rp->cdev;
- rp->cdev = 0;
- cdev->dev.driver_data = 0;
- cdev->handler = 0;
+ rp->cdev = NULL;
+ cdev->dev.driver_data = NULL;
+ cdev->handler = NULL;
/* Put ccw_device structure. */
put_device(&cdev->dev);
@@ -1144,7 +1144,7 @@ raw3270_model_show(struct device *dev, struct device_attribute *attr, char *buf)
return snprintf(buf, PAGE_SIZE, "%i\n",
((struct raw3270 *) dev->driver_data)->model);
}
-static DEVICE_ATTR(model, 0444, raw3270_model_show, 0);
+static DEVICE_ATTR(model, 0444, raw3270_model_show, NULL);
static ssize_t
raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1152,7 +1152,7 @@ raw3270_rows_show(struct device *dev, struct device_attribute *attr, char *buf)
return snprintf(buf, PAGE_SIZE, "%i\n",
((struct raw3270 *) dev->driver_data)->rows);
}
-static DEVICE_ATTR(rows, 0444, raw3270_rows_show, 0);
+static DEVICE_ATTR(rows, 0444, raw3270_rows_show, NULL);
static ssize_t
raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *buf)
@@ -1160,7 +1160,7 @@ raw3270_columns_show(struct device *dev, struct device_attribute *attr, char *bu
return snprintf(buf, PAGE_SIZE, "%i\n",
((struct raw3270 *) dev->driver_data)->cols);
}
-static DEVICE_ATTR(columns, 0444, raw3270_columns_show, 0);
+static DEVICE_ATTR(columns, 0444, raw3270_columns_show, NULL);
static struct attribute * raw3270_attrs[] = {
&dev_attr_model.attr,
@@ -1173,21 +1173,37 @@ static struct attribute_group raw3270_attr_group = {
.attrs = raw3270_attrs,
};
-static void
-raw3270_create_attributes(struct raw3270 *rp)
+static int raw3270_create_attributes(struct raw3270 *rp)
{
- //FIXME: check return code
- sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
- rp->clttydev =
- class_device_create(class3270, NULL,
- MKDEV(IBM_TTY3270_MAJOR, rp->minor),
- &rp->cdev->dev, "tty%s",
- rp->cdev->dev.bus_id);
- rp->cltubdev =
- class_device_create(class3270, NULL,
- MKDEV(IBM_FS3270_MAJOR, rp->minor),
- &rp->cdev->dev, "tub%s",
- rp->cdev->dev.bus_id);
+ int rc;
+
+ rc = sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
+ if (rc)
+ goto out;
+
+ rp->clttydev = class_device_create(class3270, NULL,
+ MKDEV(IBM_TTY3270_MAJOR, rp->minor),
+ &rp->cdev->dev, "tty%s",
+ rp->cdev->dev.bus_id);
+ if (IS_ERR(rp->clttydev)) {
+ rc = PTR_ERR(rp->clttydev);
+ goto out_ttydev;
+ }
+
+ rp->cltubdev = class_device_create(class3270, NULL,
+ MKDEV(IBM_FS3270_MAJOR, rp->minor),
+ &rp->cdev->dev, "tub%s",
+ rp->cdev->dev.bus_id);
+ if (!IS_ERR(rp->cltubdev))
+ goto out;
+
+ rc = PTR_ERR(rp->cltubdev);
+ class_device_destroy(class3270, MKDEV(IBM_TTY3270_MAJOR, rp->minor));
+
+out_ttydev:
+ sysfs_remove_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
+out:
+ return rc;
}
/*
@@ -1255,7 +1271,9 @@ raw3270_set_online (struct ccw_device *cdev)
rc = raw3270_reset_device(rp);
if (rc)
goto failure;
- raw3270_create_attributes(rp);
+ rc = raw3270_create_attributes(rp);
+ if (rc)
+ goto failure;
set_bit(RAW3270_FLAGS_READY, &rp->flags);
mutex_lock(&raw3270_mutex);
list_for_each_entry(np, &raw3270_notifier, list)
@@ -1296,7 +1314,7 @@ raw3270_remove (struct ccw_device *cdev)
spin_lock_irqsave(get_ccwdev_lock(cdev), flags);
if (rp->view) {
rp->view->fn->deactivate(rp->view);
- rp->view = 0;
+ rp->view = NULL;
}
while (!list_empty(&rp->view_list)) {
v = list_entry(rp->view_list.next, struct raw3270_view, list);
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index b635bf8e777..90beaa80a78 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -231,7 +231,7 @@ alloc_string(struct list_head *free_list, unsigned long len)
INIT_LIST_HEAD(&cs->update);
return cs;
}
- return 0;
+ return NULL;
}
static inline unsigned long
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 4138564402b..31e335751d6 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -100,13 +100,12 @@ service_call(sclp_cmdw_t command, void *sccb)
{
int cc;
- __asm__ __volatile__(
- " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
- " ipm %0\n"
- " srl %0,28"
- : "=&d" (cc)
- : "d" (command), "a" (__pa(sccb))
- : "cc", "memory" );
+ asm volatile(
+ " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
+ " ipm %0\n"
+ " srl %0,28"
+ : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
+ : "cc", "memory");
if (cc == 3)
return -EIO;
if (cc == 2)
@@ -360,16 +359,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
sclp_process_queue();
}
-/* Return current Time-Of-Day clock. */
-static inline u64
-sclp_get_clock(void)
-{
- u64 result;
-
- asm volatile ("STCK 0(%1)" : "=m" (result) : "a" (&(result)) : "cc");
- return result;
-}
-
/* Convert interval in jiffies to TOD ticks. */
static inline u64
sclp_tod_from_jiffies(unsigned long jiffies)
@@ -382,7 +371,7 @@ sclp_tod_from_jiffies(unsigned long jiffies)
void
sclp_sync_wait(void)
{
- unsigned long psw_mask;
+ unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
@@ -391,35 +380,35 @@ sclp_sync_wait(void)
timeout = 0;
if (timer_pending(&sclp_request_timer)) {
/* Get timeout TOD value */
- timeout = sclp_get_clock() +
+ timeout = get_clock() +
sclp_tod_from_jiffies(sclp_request_timer.expires -
jiffies);
}
+ local_irq_save(flags);
/* Prevent bottom half from executing once we force interrupts open */
local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */
+ trace_hardirqs_on();
__ctl_store(cr0, 0, 0);
cr0_sync = cr0;
cr0_sync |= 0x00000200;
cr0_sync &= 0xFFFFF3AC;
__ctl_load(cr0_sync, 0, 0);
- asm volatile ("STOSM 0(%1),0x01"
- : "=m" (psw_mask) : "a" (&psw_mask) : "memory");
+ __raw_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */
while (sclp_running_state != sclp_running_state_idle) {
/* Check for expired request timer */
if (timer_pending(&sclp_request_timer) &&
- sclp_get_clock() > timeout &&
+ get_clock() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data);
barrier();
cpu_relax();
}
- /* Restore interrupt settings */
- asm volatile ("SSM 0(%0)"
- : : "a" (&psw_mask) : "memory");
+ local_irq_disable();
__ctl_load(cr0, 0, 0);
- __local_bh_enable();
+ _local_bh_enable();
+ local_irq_restore(flags);
}
EXPORT_SYMBOL(sclp_sync_wait);
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c
index 10ef22f1354..86864f64171 100644
--- a/drivers/s390/char/sclp_con.c
+++ b/drivers/s390/char/sclp_con.c
@@ -8,7 +8,6 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/kmod.h>
#include <linux/console.h>
#include <linux/init.h>
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c
index 80f7f31310e..732dfbdb85c 100644
--- a/drivers/s390/char/sclp_cpi.c
+++ b/drivers/s390/char/sclp_cpi.c
@@ -5,7 +5,6 @@
* SCLP Control-Program Identification.
*/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/kmod.h>
#include <linux/module.h>
diff --git a/drivers/s390/char/sclp_quiesce.c b/drivers/s390/char/sclp_quiesce.c
index 56fa6916889..32004aae95c 100644
--- a/drivers/s390/char/sclp_quiesce.c
+++ b/drivers/s390/char/sclp_quiesce.c
@@ -7,12 +7,12 @@
* Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/cpumask.h>
#include <linux/smp.h>
#include <linux/init.h>
+#include <linux/reboot.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/sigp.h>
@@ -66,8 +66,6 @@ do_machine_quiesce(void)
}
#endif
-extern void ctrl_alt_del(void);
-
/* Handler for quiesce event. Start shutdown procedure. */
static void
sclp_quiesce_handler(struct evbuf_header *evbuf)
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c
index 91e93c78f57..0c92d3909cc 100644
--- a/drivers/s390/char/sclp_rw.c
+++ b/drivers/s390/char/sclp_rw.c
@@ -8,7 +8,6 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/kmod.h>
#include <linux/types.h>
#include <linux/err.h>
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index 6cbf067f1a8..f6cf9023039 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -8,7 +8,6 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/tty.h>
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 9e02625c82c..54fba6f1718 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -7,7 +7,6 @@
* Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/list.h>
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h
index cd51ace8b61..1f4c89967be 100644
--- a/drivers/s390/char/tape.h
+++ b/drivers/s390/char/tape.h
@@ -16,7 +16,6 @@
#include <asm/ccwdev.h>
#include <asm/debug.h>
#include <asm/idals.h>
-#include <linux/config.h>
#include <linux/blkdev.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index d4f2da73807..7b95dab913d 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -8,7 +8,6 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bio.h>
@@ -1310,9 +1309,9 @@ static struct tape_discipline tape_discipline_34xx = {
};
static struct ccw_device_id tape_34xx_ids[] = {
- { CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), driver_info: tape_3480},
- { CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), driver_info: tape_3490},
- { /* end of list */ }
+ { CCW_DEVICE_DEVTYPE(0x3480, 0, 0x3480, 0), .driver_info = tape_3480},
+ { CCW_DEVICE_DEVTYPE(0x3490, 0, 0x3490, 0), .driver_info = tape_3490},
+ { /* end of list */ },
};
static int
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c
index d71ef1adea5..928cbefc49d 100644
--- a/drivers/s390/char/tape_3590.c
+++ b/drivers/s390/char/tape_3590.c
@@ -8,7 +8,6 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/bio.h>
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index b70d9269024..3225fcd1dcb 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -11,7 +11,6 @@
*/
#include <linux/fs.h>
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c
index 5ce7ca38ace..97f75237bed 100644
--- a/drivers/s390/char/tape_char.c
+++ b/drivers/s390/char/tape_char.c
@@ -10,7 +10,6 @@
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
diff --git a/drivers/s390/char/tape_class.c b/drivers/s390/char/tape_class.c
index a5c68e60fcf..56b87618b10 100644
--- a/drivers/s390/char/tape_class.c
+++ b/drivers/s390/char/tape_class.c
@@ -76,14 +76,22 @@ struct tape_class_device *register_tape_dev(
device,
"%s", tcd->device_name
);
- sysfs_create_link(
+ rc = IS_ERR(tcd->class_device) ? PTR_ERR(tcd->class_device) : 0;
+ if (rc)
+ goto fail_with_cdev;
+ rc = sysfs_create_link(
&device->kobj,
&tcd->class_device->kobj,
tcd->mode_name
);
+ if (rc)
+ goto fail_with_class_device;
return tcd;
+fail_with_class_device:
+ class_device_destroy(tape_class, tcd->char_device->dev);
+
fail_with_cdev:
cdev_del(tcd->char_device);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index e6e4086d322..2826aed9104 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -11,7 +11,6 @@
* Stefan Bader <shbader@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h> // for kernel parameters
#include <linux/kmod.h> // for requesting modules
@@ -544,20 +543,24 @@ int
tape_generic_probe(struct ccw_device *cdev)
{
struct tape_device *device;
+ int ret;
device = tape_alloc_device();
if (IS_ERR(device))
return -ENODEV;
- PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
+ ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
+ ret = sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
+ if (ret) {
+ tape_put_device(device);
+ PRINT_ERR("probe failed for tape device %s\n", cdev->dev.bus_id);
+ return ret;
+ }
cdev->dev.driver_data = device;
+ cdev->handler = __tape_do_irq;
device->cdev = cdev;
device->cdev_id = busid_to_int(cdev->dev.bus_id);
- cdev->handler = __tape_do_irq;
-
- ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP);
- sysfs_create_group(&cdev->dev.kobj, &tape_attr_group);
-
- return 0;
+ PRINT_INFO("tape device %s found\n", cdev->dev.bus_id);
+ return ret;
}
static inline void
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index 5fec0a10cc3..655d375ab22 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -11,7 +11,6 @@
* PROCFS Functions
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/seq_file.h>
diff --git a/drivers/s390/char/tape_std.c b/drivers/s390/char/tape_std.c
index 99cf881f41d..7a76ec413a3 100644
--- a/drivers/s390/char/tape_std.c
+++ b/drivers/s390/char/tape_std.c
@@ -11,7 +11,6 @@
* Stefan Bader <shbader@de.ibm.com>
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/bio.h>
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 9a141776873..06e2eeec847 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -8,7 +8,6 @@
* -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
@@ -438,7 +437,7 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
{
struct string *s;
- tp->rcl_walk = 0;
+ tp->rcl_walk = NULL;
if (len <= 0)
return;
if (tp->rcl_nr >= tp->rcl_max) {
@@ -467,12 +466,12 @@ tty3270_rcl_backward(struct kbd_data *kbd)
else if (!list_empty(&tp->rcl_lines))
tp->rcl_walk = tp->rcl_lines.prev;
s = tp->rcl_walk ?
- list_entry(tp->rcl_walk, struct string, list) : 0;
+ list_entry(tp->rcl_walk, struct string, list) : NULL;
if (tp->rcl_walk) {
s = list_entry(tp->rcl_walk, struct string, list);
tty3270_update_prompt(tp, s->string, s->len);
} else
- tty3270_update_prompt(tp, 0, 0);
+ tty3270_update_prompt(tp, NULL, 0);
tty3270_set_timer(tp, 1);
}
spin_unlock_bh(&tp->view.lock);
@@ -554,7 +553,7 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
* has to be emitted to the tty and for 0x6d the screen
* needs to be redrawn.
*/
- input = 0;
+ input = NULL;
len = 0;
if (tp->input->string[0] == 0x7d) {
/* Enter: write input to tty. */
@@ -568,7 +567,7 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
tty3270_update_status(tp);
}
/* Clear input area. */
- tty3270_update_prompt(tp, 0, 0);
+ tty3270_update_prompt(tp, NULL, 0);
tty3270_set_timer(tp, 1);
} else if (tp->input->string[0] == 0x6d) {
/* Display has been cleared. Redraw. */
@@ -699,7 +698,6 @@ tty3270_alloc_view(void)
if (!tp->freemem_pages)
goto out_tp;
INIT_LIST_HEAD(&tp->freemem);
- init_timer(&tp->timer);
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
tp->freemem_pages[pages] = (void *)
__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
@@ -809,8 +807,8 @@ tty3270_release(struct raw3270_view *view)
tp = (struct tty3270 *) view;
tty = tp->tty;
if (tty) {
- tty->driver_data = 0;
- tp->tty = tp->kbd->tty = 0;
+ tty->driver_data = NULL;
+ tp->tty = tp->kbd->tty = NULL;
tty_hangup(tty);
raw3270_put_view(&tp->view);
}
@@ -949,8 +947,8 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
return;
tp = (struct tty3270 *) tty->driver_data;
if (tp) {
- tty->driver_data = 0;
- tp->tty = tp->kbd->tty = 0;
+ tty->driver_data = NULL;
+ tp->tty = tp->kbd->tty = NULL;
raw3270_put_view(&tp->view);
}
}
@@ -1674,7 +1672,7 @@ tty3270_set_termios(struct tty_struct *tty, struct termios *old)
new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
if (new != tp->inattr) {
tp->inattr = new;
- tty3270_update_prompt(tp, 0, 0);
+ tty3270_update_prompt(tp, NULL, 0);
tty3270_set_timer(tp, 1);
}
}
@@ -1760,7 +1758,7 @@ void
tty3270_notifier(int index, int active)
{
if (active)
- tty_register_device(tty3270_driver, index, 0);
+ tty_register_device(tty3270_driver, index, NULL);
else
tty_unregister_device(tty3270_driver, index);
}
@@ -1785,7 +1783,6 @@ tty3270_init(void)
* proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
*/
driver->owner = THIS_MODULE;
- driver->devfs_name = "ttyTUB/";
driver->driver_name = "ttyTUB";
driver->name = "ttyTUB";
driver->major = IBM_TTY3270_MAJOR;
@@ -1793,7 +1790,7 @@ tty3270_init(void)
driver->type = TTY_DRIVER_TYPE_SYSTEM;
driver->subtype = SYSTEM_TYPE_TTY;
driver->init_termios = tty_std_termios;
- driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
+ driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(driver, &tty3270_ops);
ret = tty_register_driver(driver);
if (ret) {
@@ -1820,7 +1817,7 @@ tty3270_exit(void)
raw3270_unregister_notifier(tty3270_notifier);
driver = tty3270_driver;
- tty3270_driver = 0;
+ tty3270_driver = NULL;
tty_unregister_driver(driver);
tty3270_del_views();
}
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 19762f3476a..1678b6c757e 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004,2005 IBM Corporation
- * Interface implementation for communication with the v/VM control program
+ * Interface implementation for communication with the z/VM control program
* Author(s): Christian Borntraeger <cborntra@de.ibm.com>
*
*
diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h
index 87389e73046..8a5975f3dad 100644
--- a/drivers/s390/char/vmcp.h
+++ b/drivers/s390/char/vmcp.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2004, 2005 IBM Corporation
- * Interface implementation for communication with the v/VM control program
+ * Interface implementation for communication with the z/VM control program
* Version 1.0
* Author(s): Christian Borntraeger <cborntra@de.ibm.com>
*
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index c625b69ebd1..6cb23040954 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -86,8 +86,8 @@ struct vmlogrdr_priv_t {
*/
static int vmlogrdr_open(struct inode *, struct file *);
static int vmlogrdr_release(struct inode *, struct file *);
-static ssize_t vmlogrdr_read (struct file *filp, char *data, size_t count,
- loff_t * ppos);
+static ssize_t vmlogrdr_read (struct file *filp, char __user *data,
+ size_t count, loff_t * ppos);
static struct file_operations vmlogrdr_fops = {
.owner = THIS_MODULE,
@@ -515,7 +515,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
static ssize_t
-vmlogrdr_read (struct file *filp, char *data, size_t count, loff_t * ppos)
+vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos)
{
int rc;
struct vmlogrdr_priv_t * priv = filp->private_data;
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 5acc0ace3d7..4b868f72fe8 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -54,48 +54,20 @@ enum vmwdt_func {
static int __diag288(enum vmwdt_func func, unsigned int timeout,
char *cmd, size_t len)
{
- register unsigned long __func asm("2");
- register unsigned long __timeout asm("3");
- register unsigned long __cmdp asm("4");
- register unsigned long __cmdl asm("5");
+ register unsigned long __func asm("2") = func;
+ register unsigned long __timeout asm("3") = timeout;
+ register unsigned long __cmdp asm("4") = virt_to_phys(cmd);
+ register unsigned long __cmdl asm("5") = len;
int err;
- __func = func;
- __timeout = timeout;
- __cmdp = virt_to_phys(cmd);
- __cmdl = len;
- err = 0;
- asm volatile (
-#ifdef CONFIG_64BIT
- "diag %2,%4,0x288\n"
- "1: \n"
- ".section .fixup,\"ax\"\n"
- "2: lghi %0,%1\n"
- " jg 1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,2b\n"
- ".previous\n"
-#else
- "diag %2,%4,0x288\n"
- "1: \n"
- ".section .fixup,\"ax\"\n"
- "2: lhi %0,%1\n"
- " bras 1,3f\n"
- " .long 1b\n"
- "3: l 1,0(1)\n"
- " br 1\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,2b\n"
- ".previous\n"
-#endif
- : "+&d"(err)
- : "i"(-EINVAL), "d"(__func), "d"(__timeout),
- "d"(__cmdp), "d"(__cmdl)
- : "1", "cc");
+ err = -EINVAL;
+ asm volatile(
+ " diag %1,%3,0x288\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (err) : "d"(__func), "d"(__timeout),
+ "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
return err;
}
@@ -193,7 +165,7 @@ static int vmwdt_ioctl(struct inode *i, struct file *f,
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
- return put_user(0, (int *)arg);
+ return put_user(0, (int __user *)arg);
case WDIOC_GETTEMP:
return -EINVAL;
case WDIOC_SETOPTIONS:
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 0960bef7b19..12c2d6b746e 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -9,7 +9,6 @@
* Arnd Bergmann (arndb@de.ibm.com)
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>
@@ -224,39 +223,6 @@ is_blacklisted (int ssid, int devno)
}
#ifdef CONFIG_PROC_FS
-static int
-__s390_redo_validation(struct subchannel_id schid, void *data)
-{
- int ret;
- struct subchannel *sch;
-
- sch = get_subchannel_by_schid(schid);
- if (sch) {
- /* Already known. */
- put_device(&sch->dev);
- return 0;
- }
- ret = css_probe_device(schid);
- if (ret == -ENXIO)
- return ret; /* We're through. */
- if (ret == -ENOMEM)
- /* Stop validation for now. Bad, but no need for a panic. */
- return ret;
- return 0;
-}
-
-/*
- * Function: s390_redo_validation
- * Look for no longer blacklisted devices
- * FIXME: there must be a better way to do this */
-static inline void
-s390_redo_validation (void)
-{
- CIO_TRACE_EVENT (0, "redoval");
-
- for_each_subchannel(__s390_redo_validation, NULL);
-}
-
/*
* Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore
@@ -281,7 +247,7 @@ blacklist_parse_proc_parameters (char *buf)
return;
}
- s390_redo_validation ();
+ css_schedule_reprobe();
}
/* Iterator struct for all devices. */
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index bdfee7fbaa2..38954f5cd14 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -152,7 +152,6 @@ ccwgroup_create(struct device *root,
struct ccwgroup_device *gdev;
int i;
int rc;
- int del_drvdata;
if (argc > 256) /* disallow dumb users */
return -EINVAL;
@@ -163,7 +162,6 @@ ccwgroup_create(struct device *root,
atomic_set(&gdev->onoff, 0);
- del_drvdata = 0;
for (i = 0; i < argc; i++) {
gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
@@ -180,18 +178,14 @@ ccwgroup_create(struct device *root,
rc = -EINVAL;
goto free_dev;
}
- }
- for (i = 0; i < argc; i++)
gdev->cdev[i]->dev.driver_data = gdev;
- del_drvdata = 1;
+ }
gdev->creator_id = creator_id;
gdev->count = argc;
- gdev->dev = (struct device ) {
- .bus = &ccwgroup_bus_type,
- .parent = root,
- .release = ccwgroup_release,
- };
+ gdev->dev.bus = &ccwgroup_bus_type;
+ gdev->dev.parent = root;
+ gdev->dev.release = ccwgroup_release;
snprintf (gdev->dev.bus_id, BUS_ID_SIZE, "%s",
gdev->cdev[0]->dev.bus_id);
@@ -226,9 +220,9 @@ error:
free_dev:
for (i = 0; i < argc; i++)
if (gdev->cdev[i]) {
- put_device(&gdev->cdev[i]->dev);
- if (del_drvdata)
+ if (gdev->cdev[i]->dev.driver_data == gdev)
gdev->cdev[i]->dev.driver_data = NULL;
+ put_device(&gdev->cdev[i]->dev);
}
kfree(gdev);
return rc;
@@ -319,7 +313,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const
if (!try_module_get(gdrv->owner))
return -EINVAL;
- value = simple_strtoul(buf, 0, 0);
+ value = simple_strtoul(buf, NULL, 0);
ret = count;
if (value == 1)
ccwgroup_set_online(gdev);
@@ -395,30 +389,31 @@ int
ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
{
/* register our new driver with the core */
- cdriver->driver = (struct device_driver) {
- .bus = &ccwgroup_bus_type,
- .name = cdriver->name,
- };
+ cdriver->driver.bus = &ccwgroup_bus_type;
+ cdriver->driver.name = cdriver->name;
return driver_register(&cdriver->driver);
}
static int
-__ccwgroup_driver_unregister_device(struct device *dev, void *data)
+__ccwgroup_match_all(struct device *dev, void *data)
{
- __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
- device_unregister(dev);
- put_device(dev);
- return 0;
+ return 1;
}
void
ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
{
+ struct device *dev;
+
/* We don't want ccwgroup devices to live longer than their driver. */
get_driver(&cdriver->driver);
- driver_for_each_device(&cdriver->driver, NULL, NULL,
- __ccwgroup_driver_unregister_device);
+ while ((dev = driver_find_device(&cdriver->driver, NULL, NULL,
+ __ccwgroup_match_all))) {
+ __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+ device_unregister(dev);
+ put_device(dev);
+ }
put_driver(&cdriver->driver);
driver_unregister(&cdriver->driver);
}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 72187e54dca..3bb4e472d73 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h>
@@ -239,13 +238,10 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
/* Check for single path devices. */
if (sch->schib.pmcw.pim == 0x80)
goto out_unreg;
- if (sch->vpm == mask)
- goto out_unreg;
if ((sch->schib.scsw.actl & SCSW_ACTL_DEVACT) &&
(sch->schib.scsw.actl & SCSW_ACTL_SCHACT) &&
- (sch->schib.pmcw.lpum == mask) &&
- (sch->vpm == 0)) {
+ (sch->schib.pmcw.lpum == mask)) {
int cc;
cc = cio_clear(sch);
@@ -260,6 +256,8 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
/* trigger path verification. */
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
+ else if (sch->lpm == mask)
+ goto out_unreg;
out_unlock:
spin_unlock_irq(&sch->lock);
return 0;
@@ -380,6 +378,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
if (chp_mask == 0) {
spin_unlock_irq(&sch->lock);
+ put_device(&sch->dev);
return 0;
}
old_lpm = sch->lpm;
@@ -394,7 +393,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
spin_unlock_irq(&sch->lock);
put_device(&sch->dev);
- return (res_data->fla_mask == 0xffff) ? -ENODEV : 0;
+ return 0;
}
@@ -918,12 +917,13 @@ chp_measurement_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
chp = to_channelpath(container_of(kobj, struct device, kobj));
css = to_css(chp->dev.parent);
- size = sizeof(struct cmg_chars);
+ size = sizeof(struct cmg_entry);
/* Only allow single reads. */
if (off || count < size)
return 0;
chp_measurement_copy_block((struct cmg_entry *)buf, css, chp->id);
+ count = size;
return count;
}
@@ -1392,10 +1392,8 @@ new_channel_path(int chpid)
/* fill in status, etc. */
chp->id = chpid;
chp->state = 1;
- chp->dev = (struct device) {
- .parent = &css[0]->device,
- .release = chp_release,
- };
+ chp->dev.parent = &css[0]->device;
+ chp->dev.release = chp_release;
snprintf(chp->dev.bus_id, BUS_ID_SIZE, "chp0.%x", chpid);
/* Obtain channel path description and fill it in. */
@@ -1465,6 +1463,40 @@ chsc_get_chp_desc(struct subchannel *sch, int chp_no)
return desc;
}
+static int reset_channel_path(struct channel_path *chp)
+{
+ int cc;
+
+ cc = rchp(chp->id);
+ switch (cc) {
+ case 0:
+ return 0;
+ case 2:
+ return -EBUSY;
+ default:
+ return -ENODEV;
+ }
+}
+
+static void reset_channel_paths_css(struct channel_subsystem *css)
+{
+ int i;
+
+ for (i = 0; i <= __MAX_CHPID; i++) {
+ if (css->chps[i])
+ reset_channel_path(css->chps[i]);
+ }
+}
+
+void cio_reset_channel_paths(void)
+{
+ int i;
+
+ for (i = 0; i <= __MAX_CSSID; i++) {
+ if (css[i] && css[i]->valid)
+ reset_channel_paths_css(css[i]);
+ }
+}
static int __init
chsc_alloc_sei_area(void)
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 5b20d8c9c02..2e2882daefb 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -11,17 +11,15 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
-
#include <asm/cio.h>
#include <asm/delay.h>
#include <asm/irq.h>
-
+#include <asm/setup.h>
#include "airq.h"
#include "cio.h"
#include "css.h"
@@ -148,7 +146,7 @@ cio_tpi(void)
sch->driver->irq(&sch->dev);
spin_unlock(&sch->lock);
irq_exit ();
- __local_bh_enable();
+ _local_bh_enable();
return 1;
}
@@ -193,7 +191,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
sch->orb.pfch = sch->options.prefetch == 0;
sch->orb.spnd = sch->options.suspend;
sch->orb.ssic = sch->options.suspend && sch->options.inter;
- sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm;
+ sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_64BIT
/*
* for 64 bit we always support 64 bit IDAWs with 4k page size only
@@ -520,6 +518,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
memset(sch, 0, sizeof(struct subchannel));
spin_lock_init(&sch->lock);
+ mutex_init(&sch->reg_mutex);
/* Set a name for the subchannel */
snprintf (sch->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x", schid.ssid,
@@ -570,10 +569,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->opm = 0xff;
if (!cio_is_console(sch->schid))
chsc_validate_chpids(sch);
- sch->lpm = sch->schib.pmcw.pim &
- sch->schib.pmcw.pam &
- sch->schib.pmcw.pom &
- sch->opm;
+ sch->lpm = sch->schib.pmcw.pam & sch->opm;
CIO_DEBUG(KERN_INFO, 0,
"Detected device %04x on subchannel 0.%x.%04X"
@@ -798,7 +794,7 @@ struct subchannel *
cio_get_console_subchannel(void)
{
if (!console_subchannel_in_use)
- return 0;
+ return NULL;
return &console_subchannel;
}
@@ -841,14 +837,26 @@ __clear_subchannel_easy(struct subchannel_id schid)
return -EBUSY;
}
-extern void do_reipl(unsigned long devno);
-static int
-__shutdown_subchannel_easy(struct subchannel_id schid, void *data)
+struct sch_match_id {
+ struct subchannel_id schid;
+ struct ccw_dev_id devid;
+ int rc;
+};
+
+static int __shutdown_subchannel_easy_and_match(struct subchannel_id schid,
+ void *data)
{
struct schib schib;
+ struct sch_match_id *match_id = data;
if (stsch_err(schid, &schib))
return -ENXIO;
+ if (match_id && schib.pmcw.dnv &&
+ (schib.pmcw.dev == match_id->devid.devno) &&
+ (schid.ssid == match_id->devid.ssid)) {
+ match_id->schid = schid;
+ match_id->rc = 0;
+ }
if (!schib.pmcw.ena)
return 0;
switch(__disable_subchannel_easy(schid, &schib)) {
@@ -864,17 +872,71 @@ __shutdown_subchannel_easy(struct subchannel_id schid, void *data)
return 0;
}
-void
-clear_all_subchannels(void)
+static int clear_all_subchannels_and_match(struct ccw_dev_id *devid,
+ struct subchannel_id *schid)
{
+ struct sch_match_id match_id;
+
+ match_id.devid = *devid;
+ match_id.rc = -ENODEV;
local_irq_disable();
- for_each_subchannel(__shutdown_subchannel_easy, NULL);
+ for_each_subchannel(__shutdown_subchannel_easy_and_match, &match_id);
+ if (match_id.rc == 0)
+ *schid = match_id.schid;
+ return match_id.rc;
}
+
+void clear_all_subchannels(void)
+{
+ local_irq_disable();
+ for_each_subchannel(__shutdown_subchannel_easy_and_match, NULL);
+}
+
+extern void do_reipl_asm(__u32 schid);
+
/* Make sure all subchannels are quiet before we re-ipl an lpar. */
-void
-reipl(unsigned long devno)
+void reipl_ccw_dev(struct ccw_dev_id *devid)
{
- clear_all_subchannels();
- do_reipl(devno);
+ struct subchannel_id schid;
+
+ if (clear_all_subchannels_and_match(devid, &schid))
+ panic("IPL Device not found\n");
+ cio_reset_channel_paths();
+ do_reipl_asm(*((__u32*)&schid));
+}
+
+extern struct schib ipl_schib;
+
+/*
+ * ipl_save_parameters gets called very early. It is not allowed to access
+ * anything in the bss section at all. The bss section is not cleared yet,
+ * but may contain some ipl parameters written by the firmware.
+ * These parameters (if present) are copied to 0x2000.
+ * To avoid corruption of the ipl parameters, all variables used by this
+ * function must reside on the stack or in the data section.
+ */
+void ipl_save_parameters(void)
+{
+ struct subchannel_id schid;
+ unsigned int *ipl_ptr;
+ void *src, *dst;
+
+ schid = *(struct subchannel_id *)__LC_SUBCHANNEL_ID;
+ if (!schid.one)
+ return;
+ if (stsch(schid, &ipl_schib))
+ return;
+ if (!ipl_schib.pmcw.dnv)
+ return;
+ ipl_devno = ipl_schib.pmcw.dev;
+ ipl_flags |= IPL_DEVNO_VALID;
+ if (!ipl_schib.pmcw.qf)
+ return;
+ ipl_flags |= IPL_PARMBLOCK_VALID;
+ ipl_ptr = (unsigned int *)__LC_IPL_PARMBLOCK_PTR;
+ src = (void *)(unsigned long)*ipl_ptr;
+ dst = (void *)IPL_PARMBLOCK_ORIGIN;
+ memmove(dst, src, PAGE_SIZE);
+ *ipl_ptr = IPL_PARMBLOCK_ORIGIN;
}
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 0ca987344e0..4541c1af4b6 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -2,6 +2,7 @@
#define S390_CIO_H
#include "schid.h"
+#include <linux/mutex.h>
/*
* where we put the ssd info
@@ -87,7 +88,7 @@ struct orb {
struct subchannel {
struct subchannel_id schid;
spinlock_t lock; /* subchannel lock */
-
+ struct mutex reg_mutex;
enum {
SUBCHANNEL_TYPE_IO = 0,
SUBCHANNEL_TYPE_CHSC = 1,
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index 07ef3f640f4..828b2d334f0 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -3,9 +3,10 @@
*
* Linux on zSeries Channel Measurement Facility support
*
- * Copyright 2000,2003 IBM Corporation
+ * Copyright 2000,2006 IBM Corporation
*
- * Author: Arnd Bergmann <arndb@de.ibm.com>
+ * Authors: Arnd Bergmann <arndb@de.ibm.com>
+ * Cornelia Huck <cornelia.huck@de.ibm.com>
*
* original idea from Natarajan Krishnaswami <nkrishna@us.ibm.com>
*
@@ -96,9 +97,9 @@ module_param(format, bool, 0444);
/**
* struct cmb_operations - functions to use depending on cmb_format
*
- * all these functions operate on a struct cmf_device. There is only
- * one instance of struct cmb_operations because all cmf_device
- * objects are guaranteed to be of the same type.
+ * Most of these functions operate on a struct ccw_device. There is only
+ * one instance of struct cmb_operations because the format of the measurement
+ * data is guaranteed to be the same for every ccw_device.
*
* @alloc: allocate memory for a channel measurement block,
* either with the help of a special pool or with kmalloc
@@ -107,6 +108,7 @@ module_param(format, bool, 0444);
* @readall: read a measurement block in a common format
* @reset: clear the data in the associated measurement block and
* reset its time stamp
+ * @align: align an allocated block so that the hardware can use it
*/
struct cmb_operations {
int (*alloc) (struct ccw_device*);
@@ -115,11 +117,19 @@ struct cmb_operations {
u64 (*read) (struct ccw_device*, int);
int (*readall)(struct ccw_device*, struct cmbdata *);
void (*reset) (struct ccw_device*);
+ void * (*align) (void *);
struct attribute_group *attr_group;
};
static struct cmb_operations *cmbops;
+struct cmb_data {
+ void *hw_block; /* Pointer to block updated by hardware */
+ void *last_block; /* Last changed block copied from hardware block */
+ int size; /* Size of hw_block and last_block */
+ unsigned long long last_update; /* when last_block was updated */
+};
+
/* our user interface is designed in terms of nanoseconds,
* while the hardware measures total times in its own
* unit.*/
@@ -226,63 +236,229 @@ struct set_schib_struct {
unsigned long address;
wait_queue_head_t wait;
int ret;
+ struct kref kref;
};
+static void cmf_set_schib_release(struct kref *kref)
+{
+ struct set_schib_struct *set_data;
+
+ set_data = container_of(kref, struct set_schib_struct, kref);
+ kfree(set_data);
+}
+
+#define CMF_PENDING 1
+
static int set_schib_wait(struct ccw_device *cdev, u32 mme,
int mbfc, unsigned long address)
{
- struct set_schib_struct s = {
- .mme = mme,
- .mbfc = mbfc,
- .address = address,
- .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s.wait),
- };
+ struct set_schib_struct *set_data;
+ int ret;
spin_lock_irq(cdev->ccwlock);
- s.ret = set_schib(cdev, mme, mbfc, address);
- if (s.ret != -EBUSY) {
- goto out_nowait;
+ if (!cdev->private->cmb) {
+ ret = -ENODEV;
+ goto out;
}
+ set_data = kzalloc(sizeof(struct set_schib_struct), GFP_ATOMIC);
+ if (!set_data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ init_waitqueue_head(&set_data->wait);
+ kref_init(&set_data->kref);
+ set_data->mme = mme;
+ set_data->mbfc = mbfc;
+ set_data->address = address;
+
+ ret = set_schib(cdev, mme, mbfc, address);
+ if (ret != -EBUSY)
+ goto out_put;
if (cdev->private->state != DEV_STATE_ONLINE) {
- s.ret = -EBUSY;
/* if the device is not online, don't even try again */
- goto out_nowait;
+ ret = -EBUSY;
+ goto out_put;
}
+
cdev->private->state = DEV_STATE_CMFCHANGE;
- cdev->private->cmb_wait = &s;
- s.ret = 1;
+ set_data->ret = CMF_PENDING;
+ cdev->private->cmb_wait = set_data;
spin_unlock_irq(cdev->ccwlock);
- if (wait_event_interruptible(s.wait, s.ret != 1)) {
+ if (wait_event_interruptible(set_data->wait,
+ set_data->ret != CMF_PENDING)) {
spin_lock_irq(cdev->ccwlock);
- if (s.ret == 1) {
- s.ret = -ERESTARTSYS;
- cdev->private->cmb_wait = 0;
+ if (set_data->ret == CMF_PENDING) {
+ set_data->ret = -ERESTARTSYS;
if (cdev->private->state == DEV_STATE_CMFCHANGE)
cdev->private->state = DEV_STATE_ONLINE;
}
spin_unlock_irq(cdev->ccwlock);
}
- return s.ret;
-
-out_nowait:
+ spin_lock_irq(cdev->ccwlock);
+ cdev->private->cmb_wait = NULL;
+ ret = set_data->ret;
+out_put:
+ kref_put(&set_data->kref, cmf_set_schib_release);
+out:
spin_unlock_irq(cdev->ccwlock);
- return s.ret;
+ return ret;
}
void retry_set_schib(struct ccw_device *cdev)
{
- struct set_schib_struct *s;
+ struct set_schib_struct *set_data;
+
+ set_data = cdev->private->cmb_wait;
+ if (!set_data) {
+ WARN_ON(1);
+ return;
+ }
+ kref_get(&set_data->kref);
+ set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
+ set_data->address);
+ wake_up(&set_data->wait);
+ kref_put(&set_data->kref, cmf_set_schib_release);
+}
+
+static int cmf_copy_block(struct ccw_device *cdev)
+{
+ struct subchannel *sch;
+ void *reference_buf;
+ void *hw_block;
+ struct cmb_data *cmb_data;
+
+ sch = to_subchannel(cdev->dev.parent);
+
+ if (stsch(sch->schid, &sch->schib))
+ return -ENODEV;
+
+ if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
+ /* Don't copy if a start function is in progress. */
+ if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) &&
+ (sch->schib.scsw.actl &
+ (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
+ (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))
+ return -EBUSY;
+ }
+ cmb_data = cdev->private->cmb;
+ hw_block = cmbops->align(cmb_data->hw_block);
+ if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
+ /* No need to copy. */
+ return 0;
+ reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
+ if (!reference_buf)
+ return -ENOMEM;
+ /* Ensure consistency of block copied from hardware. */
+ do {
+ memcpy(cmb_data->last_block, hw_block, cmb_data->size);
+ memcpy(reference_buf, hw_block, cmb_data->size);
+ } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
+ cmb_data->last_update = get_clock();
+ kfree(reference_buf);
+ return 0;
+}
+
+struct copy_block_struct {
+ wait_queue_head_t wait;
+ int ret;
+ struct kref kref;
+};
+
+static void cmf_copy_block_release(struct kref *kref)
+{
+ struct copy_block_struct *copy_block;
+
+ copy_block = container_of(kref, struct copy_block_struct, kref);
+ kfree(copy_block);
+}
+
+static int cmf_cmb_copy_wait(struct ccw_device *cdev)
+{
+ struct copy_block_struct *copy_block;
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ if (!cdev->private->cmb) {
+ ret = -ENODEV;
+ goto out;
+ }
+ copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
+ if (!copy_block) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ init_waitqueue_head(&copy_block->wait);
+ kref_init(&copy_block->kref);
+
+ ret = cmf_copy_block(cdev);
+ if (ret != -EBUSY)
+ goto out_put;
+
+ if (cdev->private->state != DEV_STATE_ONLINE) {
+ ret = -EBUSY;
+ goto out_put;
+ }
+
+ cdev->private->state = DEV_STATE_CMFUPDATE;
+ copy_block->ret = CMF_PENDING;
+ cdev->private->cmb_wait = copy_block;
+
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ if (wait_event_interruptible(copy_block->wait,
+ copy_block->ret != CMF_PENDING)) {
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ if (copy_block->ret == CMF_PENDING) {
+ copy_block->ret = -ERESTARTSYS;
+ if (cdev->private->state == DEV_STATE_CMFUPDATE)
+ cdev->private->state = DEV_STATE_ONLINE;
+ }
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ }
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ cdev->private->cmb_wait = NULL;
+ ret = copy_block->ret;
+out_put:
+ kref_put(&copy_block->kref, cmf_copy_block_release);
+out:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ return ret;
+}
+
+void cmf_retry_copy_block(struct ccw_device *cdev)
+{
+ struct copy_block_struct *copy_block;
- s = cdev->private->cmb_wait;
- cdev->private->cmb_wait = 0;
- if (!s) {
+ copy_block = cdev->private->cmb_wait;
+ if (!copy_block) {
WARN_ON(1);
return;
}
- s->ret = set_schib(cdev, s->mme, s->mbfc, s->address);
- wake_up(&s->wait);
+ kref_get(&copy_block->kref);
+ copy_block->ret = cmf_copy_block(cdev);
+ wake_up(&copy_block->wait);
+ kref_put(&copy_block->kref, cmf_copy_block_release);
+}
+
+static void cmf_generic_reset(struct ccw_device *cdev)
+{
+ struct cmb_data *cmb_data;
+
+ spin_lock_irq(cdev->ccwlock);
+ cmb_data = cdev->private->cmb;
+ if (cmb_data) {
+ memset(cmb_data->last_block, 0, cmb_data->size);
+ /*
+ * Need to reset hw block as well to make the hardware start
+ * from 0 again.
+ */
+ memset(cmbops->align(cmb_data->hw_block), 0, cmb_data->size);
+ cmb_data->last_update = 0;
+ }
+ cdev->private->cmb_start_time = get_clock();
+ spin_unlock_irq(cdev->ccwlock);
}
/**
@@ -343,8 +519,8 @@ struct cmb {
/* insert a single device into the cmb_area list
* called with cmb_area.lock held from alloc_cmb
*/
-static inline int
-alloc_cmb_single (struct ccw_device *cdev)
+static inline int alloc_cmb_single (struct ccw_device *cdev,
+ struct cmb_data *cmb_data)
{
struct cmb *cmb;
struct ccw_device_private *node;
@@ -358,10 +534,12 @@ alloc_cmb_single (struct ccw_device *cdev)
/* find first unused cmb in cmb_area.mem.
* this is a little tricky: cmb_area.list
- * remains sorted by ->cmb pointers */
+ * remains sorted by ->cmb->hw_data pointers */
cmb = cmb_area.mem;
list_for_each_entry(node, &cmb_area.list, cmb_list) {
- if ((struct cmb*)node->cmb > cmb)
+ struct cmb_data *data;
+ data = node->cmb;
+ if ((struct cmb*)data->hw_block > cmb)
break;
cmb++;
}
@@ -372,7 +550,8 @@ alloc_cmb_single (struct ccw_device *cdev)
/* insert new cmb */
list_add_tail(&cdev->private->cmb_list, &node->cmb_list);
- cdev->private->cmb = cmb;
+ cmb_data->hw_block = cmb;
+ cdev->private->cmb = cmb_data;
ret = 0;
out:
spin_unlock_irq(cdev->ccwlock);
@@ -385,7 +564,19 @@ alloc_cmb (struct ccw_device *cdev)
int ret;
struct cmb *mem;
ssize_t size;
+ struct cmb_data *cmb_data;
+
+ /* Allocate private cmb_data. */
+ cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+ if (!cmb_data)
+ return -ENOMEM;
+ cmb_data->last_block = kzalloc(sizeof(struct cmb), GFP_KERNEL);
+ if (!cmb_data->last_block) {
+ kfree(cmb_data);
+ return -ENOMEM;
+ }
+ cmb_data->size = sizeof(struct cmb);
spin_lock(&cmb_area.lock);
if (!cmb_area.mem) {
@@ -414,29 +605,36 @@ alloc_cmb (struct ccw_device *cdev)
}
/* do the actual allocation */
- ret = alloc_cmb_single(cdev);
+ ret = alloc_cmb_single(cdev, cmb_data);
out:
spin_unlock(&cmb_area.lock);
-
+ if (ret) {
+ kfree(cmb_data->last_block);
+ kfree(cmb_data);
+ }
return ret;
}
-static void
-free_cmb(struct ccw_device *cdev)
+static void free_cmb(struct ccw_device *cdev)
{
struct ccw_device_private *priv;
-
- priv = cdev->private;
+ struct cmb_data *cmb_data;
spin_lock(&cmb_area.lock);
spin_lock_irq(cdev->ccwlock);
+ priv = cdev->private;
+
if (list_empty(&priv->cmb_list)) {
/* already freed */
goto out;
}
+ cmb_data = priv->cmb;
priv->cmb = NULL;
+ if (cmb_data)
+ kfree(cmb_data->last_block);
+ kfree(cmb_data);
list_del_init(&priv->cmb_list);
if (list_empty(&cmb_area.list)) {
@@ -451,83 +649,97 @@ out:
spin_unlock(&cmb_area.lock);
}
-static int
-set_cmb(struct ccw_device *cdev, u32 mme)
+static int set_cmb(struct ccw_device *cdev, u32 mme)
{
u16 offset;
+ struct cmb_data *cmb_data;
+ unsigned long flags;
- if (!cdev->private->cmb)
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ if (!cdev->private->cmb) {
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
return -EINVAL;
-
- offset = mme ? (struct cmb *)cdev->private->cmb - cmb_area.mem : 0;
+ }
+ cmb_data = cdev->private->cmb;
+ offset = mme ? (struct cmb *)cmb_data->hw_block - cmb_area.mem : 0;
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
return set_schib_wait(cdev, mme, 0, offset);
}
-static u64
-read_cmb (struct ccw_device *cdev, int index)
+static u64 read_cmb (struct ccw_device *cdev, int index)
{
- /* yes, we have to put it on the stack
- * because the cmb must only be accessed
- * atomically, e.g. with mvc */
- struct cmb cmb;
- unsigned long flags;
+ struct cmb *cmb;
u32 val;
+ int ret;
+ unsigned long flags;
+
+ ret = cmf_cmb_copy_wait(cdev);
+ if (ret < 0)
+ return 0;
spin_lock_irqsave(cdev->ccwlock, flags);
if (!cdev->private->cmb) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- return 0;
+ ret = 0;
+ goto out;
}
-
- cmb = *(struct cmb*)cdev->private->cmb;
- spin_unlock_irqrestore(cdev->ccwlock, flags);
+ cmb = ((struct cmb_data *)cdev->private->cmb)->last_block;
switch (index) {
case cmb_ssch_rsch_count:
- return cmb.ssch_rsch_count;
+ ret = cmb->ssch_rsch_count;
+ goto out;
case cmb_sample_count:
- return cmb.sample_count;
+ ret = cmb->sample_count;
+ goto out;
case cmb_device_connect_time:
- val = cmb.device_connect_time;
+ val = cmb->device_connect_time;
break;
case cmb_function_pending_time:
- val = cmb.function_pending_time;
+ val = cmb->function_pending_time;
break;
case cmb_device_disconnect_time:
- val = cmb.device_disconnect_time;
+ val = cmb->device_disconnect_time;
break;
case cmb_control_unit_queuing_time:
- val = cmb.control_unit_queuing_time;
+ val = cmb->control_unit_queuing_time;
break;
case cmb_device_active_only_time:
- val = cmb.device_active_only_time;
+ val = cmb->device_active_only_time;
break;
default:
- return 0;
+ ret = 0;
+ goto out;
}
- return time_to_avg_nsec(val, cmb.sample_count);
+ ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ return ret;
}
-static int
-readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
{
- /* yes, we have to put it on the stack
- * because the cmb must only be accessed
- * atomically, e.g. with mvc */
- struct cmb cmb;
- unsigned long flags;
+ struct cmb *cmb;
+ struct cmb_data *cmb_data;
u64 time;
+ unsigned long flags;
+ int ret;
+ ret = cmf_cmb_copy_wait(cdev);
+ if (ret < 0)
+ return ret;
spin_lock_irqsave(cdev->ccwlock, flags);
- if (!cdev->private->cmb) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- return -ENODEV;
+ cmb_data = cdev->private->cmb;
+ if (!cmb_data) {
+ ret = -ENODEV;
+ goto out;
}
-
- cmb = *(struct cmb*)cdev->private->cmb;
- time = get_clock() - cdev->private->cmb_start_time;
- spin_unlock_irqrestore(cdev->ccwlock, flags);
+ if (cmb_data->last_update == 0) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ cmb = cmb_data->last_block;
+ time = cmb_data->last_update - cdev->private->cmb_start_time;
memset(data, 0, sizeof(struct cmbdata));
@@ -538,31 +750,32 @@ readall_cmb (struct ccw_device *cdev, struct cmbdata *data)
data->elapsed_time = (time * 1000) >> 12;
/* copy data to new structure */
- data->ssch_rsch_count = cmb.ssch_rsch_count;
- data->sample_count = cmb.sample_count;
+ data->ssch_rsch_count = cmb->ssch_rsch_count;
+ data->sample_count = cmb->sample_count;
/* time fields are converted to nanoseconds while copying */
- data->device_connect_time = time_to_nsec(cmb.device_connect_time);
- data->function_pending_time = time_to_nsec(cmb.function_pending_time);
- data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+ data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+ data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+ data->device_disconnect_time =
+ time_to_nsec(cmb->device_disconnect_time);
data->control_unit_queuing_time
- = time_to_nsec(cmb.control_unit_queuing_time);
+ = time_to_nsec(cmb->control_unit_queuing_time);
data->device_active_only_time
- = time_to_nsec(cmb.device_active_only_time);
+ = time_to_nsec(cmb->device_active_only_time);
+ ret = 0;
+out:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ return ret;
+}
- return 0;
+static void reset_cmb(struct ccw_device *cdev)
+{
+ cmf_generic_reset(cdev);
}
-static void
-reset_cmb(struct ccw_device *cdev)
+static void * align_cmb(void *area)
{
- struct cmb *cmb;
- spin_lock_irq(cdev->ccwlock);
- cmb = cdev->private->cmb;
- if (cmb)
- memset (cmb, 0, sizeof (*cmb));
- cdev->private->cmb_start_time = get_clock();
- spin_unlock_irq(cdev->ccwlock);
+ return area;
}
static struct attribute_group cmf_attr_group;
@@ -574,6 +787,7 @@ static struct cmb_operations cmbops_basic = {
.read = read_cmb,
.readall = readall_cmb,
.reset = reset_cmb,
+ .align = align_cmb,
.attr_group = &cmf_attr_group,
};
@@ -610,22 +824,34 @@ static inline struct cmbe* cmbe_align(struct cmbe *c)
return (struct cmbe*)addr;
}
-static int
-alloc_cmbe (struct ccw_device *cdev)
+static int alloc_cmbe (struct ccw_device *cdev)
{
struct cmbe *cmbe;
- cmbe = kmalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
+ struct cmb_data *cmb_data;
+ int ret;
+
+ cmbe = kzalloc (sizeof (*cmbe) * 2, GFP_KERNEL);
if (!cmbe)
return -ENOMEM;
-
+ cmb_data = kzalloc(sizeof(struct cmb_data), GFP_KERNEL);
+ if (!cmb_data) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ cmb_data->last_block = kzalloc(sizeof(struct cmbe), GFP_KERNEL);
+ if (!cmb_data->last_block) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+ cmb_data->size = sizeof(struct cmbe);
spin_lock_irq(cdev->ccwlock);
if (cdev->private->cmb) {
- kfree(cmbe);
spin_unlock_irq(cdev->ccwlock);
- return -EBUSY;
+ ret = -EBUSY;
+ goto out_free;
}
-
- cdev->private->cmb = cmbe;
+ cmb_data->hw_block = cmbe;
+ cdev->private->cmb = cmb_data;
spin_unlock_irq(cdev->ccwlock);
/* activate global measurement if this is the first channel */
@@ -636,14 +862,24 @@ alloc_cmbe (struct ccw_device *cdev)
spin_unlock(&cmb_area.lock);
return 0;
+out_free:
+ if (cmb_data)
+ kfree(cmb_data->last_block);
+ kfree(cmb_data);
+ kfree(cmbe);
+ return ret;
}
-static void
-free_cmbe (struct ccw_device *cdev)
+static void free_cmbe (struct ccw_device *cdev)
{
+ struct cmb_data *cmb_data;
+
spin_lock_irq(cdev->ccwlock);
- kfree(cdev->private->cmb);
+ cmb_data = cdev->private->cmb;
cdev->private->cmb = NULL;
+ if (cmb_data)
+ kfree(cmb_data->last_block);
+ kfree(cmb_data);
spin_unlock_irq(cdev->ccwlock);
/* deactivate global measurement if this is the last channel */
@@ -654,89 +890,105 @@ free_cmbe (struct ccw_device *cdev)
spin_unlock(&cmb_area.lock);
}
-static int
-set_cmbe(struct ccw_device *cdev, u32 mme)
+static int set_cmbe(struct ccw_device *cdev, u32 mme)
{
unsigned long mba;
+ struct cmb_data *cmb_data;
+ unsigned long flags;
- if (!cdev->private->cmb)
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ if (!cdev->private->cmb) {
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
return -EINVAL;
- mba = mme ? (unsigned long) cmbe_align(cdev->private->cmb) : 0;
+ }
+ cmb_data = cdev->private->cmb;
+ mba = mme ? (unsigned long) cmbe_align(cmb_data->hw_block) : 0;
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
return set_schib_wait(cdev, mme, 1, mba);
}
-u64
-read_cmbe (struct ccw_device *cdev, int index)
+static u64 read_cmbe (struct ccw_device *cdev, int index)
{
- /* yes, we have to put it on the stack
- * because the cmb must only be accessed
- * atomically, e.g. with mvc */
- struct cmbe cmb;
- unsigned long flags;
+ struct cmbe *cmb;
+ struct cmb_data *cmb_data;
u32 val;
+ int ret;
+ unsigned long flags;
- spin_lock_irqsave(cdev->ccwlock, flags);
- if (!cdev->private->cmb) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
+ ret = cmf_cmb_copy_wait(cdev);
+ if (ret < 0)
return 0;
- }
- cmb = *cmbe_align(cdev->private->cmb);
- spin_unlock_irqrestore(cdev->ccwlock, flags);
+ spin_lock_irqsave(cdev->ccwlock, flags);
+ cmb_data = cdev->private->cmb;
+ if (!cmb_data) {
+ ret = 0;
+ goto out;
+ }
+ cmb = cmb_data->last_block;
switch (index) {
case cmb_ssch_rsch_count:
- return cmb.ssch_rsch_count;
+ ret = cmb->ssch_rsch_count;
+ goto out;
case cmb_sample_count:
- return cmb.sample_count;
+ ret = cmb->sample_count;
+ goto out;
case cmb_device_connect_time:
- val = cmb.device_connect_time;
+ val = cmb->device_connect_time;
break;
case cmb_function_pending_time:
- val = cmb.function_pending_time;
+ val = cmb->function_pending_time;
break;
case cmb_device_disconnect_time:
- val = cmb.device_disconnect_time;
+ val = cmb->device_disconnect_time;
break;
case cmb_control_unit_queuing_time:
- val = cmb.control_unit_queuing_time;
+ val = cmb->control_unit_queuing_time;
break;
case cmb_device_active_only_time:
- val = cmb.device_active_only_time;
+ val = cmb->device_active_only_time;
break;
case cmb_device_busy_time:
- val = cmb.device_busy_time;
+ val = cmb->device_busy_time;
break;
case cmb_initial_command_response_time:
- val = cmb.initial_command_response_time;
+ val = cmb->initial_command_response_time;
break;
default:
- return 0;
+ ret = 0;
+ goto out;
}
- return time_to_avg_nsec(val, cmb.sample_count);
+ ret = time_to_avg_nsec(val, cmb->sample_count);
+out:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ return ret;
}
-static int
-readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
+static int readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
{
- /* yes, we have to put it on the stack
- * because the cmb must only be accessed
- * atomically, e.g. with mvc */
- struct cmbe cmb;
- unsigned long flags;
+ struct cmbe *cmb;
+ struct cmb_data *cmb_data;
u64 time;
+ unsigned long flags;
+ int ret;
+ ret = cmf_cmb_copy_wait(cdev);
+ if (ret < 0)
+ return ret;
spin_lock_irqsave(cdev->ccwlock, flags);
- if (!cdev->private->cmb) {
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- return -ENODEV;
+ cmb_data = cdev->private->cmb;
+ if (!cmb_data) {
+ ret = -ENODEV;
+ goto out;
}
-
- cmb = *cmbe_align(cdev->private->cmb);
- time = get_clock() - cdev->private->cmb_start_time;
- spin_unlock_irqrestore(cdev->ccwlock, flags);
+ if (cmb_data->last_update == 0) {
+ ret = -EAGAIN;
+ goto out;
+ }
+ time = cmb_data->last_update - cdev->private->cmb_start_time;
memset (data, 0, sizeof(struct cmbdata));
@@ -746,35 +998,38 @@ readall_cmbe (struct ccw_device *cdev, struct cmbdata *data)
/* conver to nanoseconds */
data->elapsed_time = (time * 1000) >> 12;
+ cmb = cmb_data->last_block;
/* copy data to new structure */
- data->ssch_rsch_count = cmb.ssch_rsch_count;
- data->sample_count = cmb.sample_count;
+ data->ssch_rsch_count = cmb->ssch_rsch_count;
+ data->sample_count = cmb->sample_count;
/* time fields are converted to nanoseconds while copying */
- data->device_connect_time = time_to_nsec(cmb.device_connect_time);
- data->function_pending_time = time_to_nsec(cmb.function_pending_time);
- data->device_disconnect_time = time_to_nsec(cmb.device_disconnect_time);
+ data->device_connect_time = time_to_nsec(cmb->device_connect_time);
+ data->function_pending_time = time_to_nsec(cmb->function_pending_time);
+ data->device_disconnect_time =
+ time_to_nsec(cmb->device_disconnect_time);
data->control_unit_queuing_time
- = time_to_nsec(cmb.control_unit_queuing_time);
+ = time_to_nsec(cmb->control_unit_queuing_time);
data->device_active_only_time
- = time_to_nsec(cmb.device_active_only_time);
- data->device_busy_time = time_to_nsec(cmb.device_busy_time);
+ = time_to_nsec(cmb->device_active_only_time);
+ data->device_busy_time = time_to_nsec(cmb->device_busy_time);
data->initial_command_response_time
- = time_to_nsec(cmb.initial_command_response_time);
+ = time_to_nsec(cmb->initial_command_response_time);
- return 0;
+ ret = 0;
+out:
+ spin_unlock_irqrestore(cdev->ccwlock, flags);
+ return ret;
}
-static void
-reset_cmbe(struct ccw_device *cdev)
+static void reset_cmbe(struct ccw_device *cdev)
{
- struct cmbe *cmb;
- spin_lock_irq(cdev->ccwlock);
- cmb = cmbe_align(cdev->private->cmb);
- if (cmb)
- memset (cmb, 0, sizeof (*cmb));
- cdev->private->cmb_start_time = get_clock();
- spin_unlock_irq(cdev->ccwlock);
+ cmf_generic_reset(cdev);
+}
+
+static void * align_cmbe(void *area)
+{
+ return cmbe_align(area);
}
static struct attribute_group cmf_attr_group_ext;
@@ -786,6 +1041,7 @@ static struct cmb_operations cmbops_extended = {
.read = read_cmbe,
.readall = readall_cmbe,
.reset = reset_cmbe,
+ .align = align_cmbe,
.attr_group = &cmf_attr_group_ext,
};
@@ -803,14 +1059,20 @@ cmb_show_avg_sample_interval(struct device *dev, struct device_attribute *attr,
struct ccw_device *cdev;
long interval;
unsigned long count;
+ struct cmb_data *cmb_data;
cdev = to_ccwdev(dev);
- interval = get_clock() - cdev->private->cmb_start_time;
count = cmf_read(cdev, cmb_sample_count);
- if (count)
+ spin_lock_irq(cdev->ccwlock);
+ cmb_data = cdev->private->cmb;
+ if (count) {
+ interval = cmb_data->last_update -
+ cdev->private->cmb_start_time;
+ interval = (interval * 1000) >> 12;
interval /= count;
- else
+ } else
interval = -1;
+ spin_unlock_irq(cdev->ccwlock);
return sprintf(buf, "%ld\n", interval);
}
@@ -823,7 +1085,10 @@ cmb_show_avg_utilization(struct device *dev, struct device_attribute *attr, char
int ret;
ret = cmf_readall(to_ccwdev(dev), &data);
- if (ret)
+ if (ret == -EAGAIN || ret == -ENODEV)
+ /* No data (yet/currently) available to use for calculation. */
+ return sprintf(buf, "n/a\n");
+ else if (ret)
return ret;
utilization = data.device_connect_time +
@@ -876,7 +1141,7 @@ static struct attribute *cmf_attributes[] = {
&dev_attr_avg_device_disconnect_time.attr,
&dev_attr_avg_control_unit_queuing_time.attr,
&dev_attr_avg_device_active_only_time.attr,
- 0,
+ NULL,
};
static struct attribute_group cmf_attr_group = {
@@ -896,7 +1161,7 @@ static struct attribute *cmf_attributes_ext[] = {
&dev_attr_avg_device_active_only_time.attr,
&dev_attr_avg_device_busy_time.attr,
&dev_attr_avg_initial_command_response_time.attr,
- 0,
+ NULL,
};
static struct attribute_group cmf_attr_group_ext = {
@@ -982,6 +1247,13 @@ cmf_readall(struct ccw_device *cdev, struct cmbdata *data)
return cmbops->readall(cdev, data);
}
+/* Reenable cmf when a disconnected device becomes available again. */
+int cmf_reenable(struct ccw_device *cdev)
+{
+ cmbops->reset(cdev);
+ return cmbops->set(cdev, 2);
+}
+
static int __init
init_cmf(void)
{
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 74ea8aac4b7..7086a74e987 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -19,9 +19,11 @@
#include "cio_debug.h"
#include "ioasm.h"
#include "chsc.h"
+#include "device.h"
int need_rescan = 0;
int css_init_done = 0;
+static int need_reprobe = 0;
static int max_ssid = 0;
struct channel_subsystem *css[__MAX_CSSID + 1];
@@ -106,6 +108,24 @@ css_subchannel_release(struct device *dev)
extern int css_get_ssd_info(struct subchannel *sch);
+
+int css_sch_device_register(struct subchannel *sch)
+{
+ int ret;
+
+ mutex_lock(&sch->reg_mutex);
+ ret = device_register(&sch->dev);
+ mutex_unlock(&sch->reg_mutex);
+ return ret;
+}
+
+void css_sch_device_unregister(struct subchannel *sch)
+{
+ mutex_lock(&sch->reg_mutex);
+ device_unregister(&sch->dev);
+ mutex_unlock(&sch->reg_mutex);
+}
+
static int
css_register_subchannel(struct subchannel *sch)
{
@@ -117,7 +137,7 @@ css_register_subchannel(struct subchannel *sch)
sch->dev.release = &css_subchannel_release;
/* make it known to the system */
- ret = device_register(&sch->dev);
+ ret = css_sch_device_register(sch);
if (ret)
printk (KERN_WARNING "%s: could not register %s\n",
__func__, sch->dev.bus_id);
@@ -162,136 +182,141 @@ get_subchannel_by_schid(struct subchannel_id schid)
return dev ? to_subchannel(dev) : NULL;
}
-
-static inline int
-css_get_subchannel_status(struct subchannel *sch, struct subchannel_id schid)
+static inline int css_get_subchannel_status(struct subchannel *sch)
{
struct schib schib;
- int cc;
- cc = stsch(schid, &schib);
- if (cc)
- return CIO_GONE;
- if (!schib.pmcw.dnv)
+ if (stsch(sch->schid, &schib) || !schib.pmcw.dnv)
return CIO_GONE;
- if (sch && sch->schib.pmcw.dnv &&
- (schib.pmcw.dev != sch->schib.pmcw.dev))
+ if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev))
return CIO_REVALIDATE;
- if (sch && !sch->lpm)
+ if (!sch->lpm)
return CIO_NO_PATH;
return CIO_OPER;
}
-
-static int
-css_evaluate_subchannel(struct subchannel_id schid, int slow)
+
+static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
{
int event, ret, disc;
- struct subchannel *sch;
unsigned long flags;
+ enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action;
- sch = get_subchannel_by_schid(schid);
- disc = sch ? device_is_disconnected(sch) : 0;
+ spin_lock_irqsave(&sch->lock, flags);
+ disc = device_is_disconnected(sch);
if (disc && slow) {
- if (sch)
- put_device(&sch->dev);
- return 0; /* Already processed. */
+ /* Disconnected devices are evaluated directly only.*/
+ spin_unlock_irqrestore(&sch->lock, flags);
+ return 0;
}
- /*
- * We've got a machine check, so running I/O won't get an interrupt.
- * Kill any pending timers.
- */
- if (sch)
- device_kill_pending_timer(sch);
+ /* No interrupt after machine check - kill pending timers. */
+ device_kill_pending_timer(sch);
if (!disc && !slow) {
- if (sch)
- put_device(&sch->dev);
- return -EAGAIN; /* Will be done on the slow path. */
+ /* Non-disconnected devices are evaluated on the slow path. */
+ spin_unlock_irqrestore(&sch->lock, flags);
+ return -EAGAIN;
}
- event = css_get_subchannel_status(sch, schid);
+ event = css_get_subchannel_status(sch);
CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n",
- schid.ssid, schid.sch_no, event,
- sch?(disc?"disconnected":"normal"):"unknown",
- slow?"slow":"fast");
+ sch->schid.ssid, sch->schid.sch_no, event,
+ disc ? "disconnected" : "normal",
+ slow ? "slow" : "fast");
+ /* Analyze subchannel status. */
+ action = NONE;
switch (event) {
case CIO_NO_PATH:
- case CIO_GONE:
- if (!sch) {
- /* Never used this subchannel. Ignore. */
- ret = 0;
+ if (disc) {
+ /* Check if paths have become available. */
+ action = REPROBE;
break;
}
- if (disc && (event == CIO_NO_PATH)) {
- /*
- * Uargh, hack again. Because we don't get a machine
- * check on configure on, our path bookkeeping can
- * be out of date here (it's fine while we only do
- * logical varying or get chsc machine checks). We
- * need to force reprobing or we might miss devices
- * coming operational again. It won't do harm in real
- * no path situations.
- */
- spin_lock_irqsave(&sch->lock, flags);
- device_trigger_reprobe(sch);
+ /* fall through */
+ case CIO_GONE:
+ /* Prevent unwanted effects when opening lock. */
+ cio_disable_subchannel(sch);
+ device_set_disconnected(sch);
+ /* Ask driver what to do with device. */
+ action = UNREGISTER;
+ if (sch->driver && sch->driver->notify) {
spin_unlock_irqrestore(&sch->lock, flags);
- ret = 0;
- break;
- }
- if (sch->driver && sch->driver->notify &&
- sch->driver->notify(&sch->dev, event)) {
- cio_disable_subchannel(sch);
- device_set_disconnected(sch);
- ret = 0;
- break;
+ ret = sch->driver->notify(&sch->dev, event);
+ spin_lock_irqsave(&sch->lock, flags);
+ if (ret)
+ action = NONE;
}
- /*
- * Unregister subchannel.
- * The device will be killed automatically.
- */
- cio_disable_subchannel(sch);
- device_unregister(&sch->dev);
- /* Reset intparm to zeroes. */
- sch->schib.pmcw.intparm = 0;
- cio_modify(sch);
- put_device(&sch->dev);
- ret = 0;
break;
case CIO_REVALIDATE:
- /*
- * Revalidation machine check. Sick.
- * We don't notify the driver since we have to throw the device
- * away in any case.
- */
- if (!disc) {
- device_unregister(&sch->dev);
- /* Reset intparm to zeroes. */
- sch->schib.pmcw.intparm = 0;
- cio_modify(sch);
- put_device(&sch->dev);
- ret = css_probe_device(schid);
- } else {
- /*
- * We can't immediately deregister the disconnected
- * device since it might block.
- */
- spin_lock_irqsave(&sch->lock, flags);
- device_trigger_reprobe(sch);
- spin_unlock_irqrestore(&sch->lock, flags);
- ret = 0;
- }
+ /* Device will be removed, so no notify necessary. */
+ if (disc)
+ /* Reprobe because immediate unregister might block. */
+ action = REPROBE;
+ else
+ action = UNREGISTER_PROBE;
break;
case CIO_OPER:
- if (disc) {
- spin_lock_irqsave(&sch->lock, flags);
+ if (disc)
/* Get device operational again. */
- device_trigger_reprobe(sch);
- spin_unlock_irqrestore(&sch->lock, flags);
- }
- ret = sch ? 0 : css_probe_device(schid);
+ action = REPROBE;
+ break;
+ }
+ /* Perform action. */
+ ret = 0;
+ switch (action) {
+ case UNREGISTER:
+ case UNREGISTER_PROBE:
+ /* Unregister device (will use subchannel lock). */
+ spin_unlock_irqrestore(&sch->lock, flags);
+ css_sch_device_unregister(sch);
+ spin_lock_irqsave(&sch->lock, flags);
+
+ /* Reset intparm to zeroes. */
+ sch->schib.pmcw.intparm = 0;
+ cio_modify(sch);
+
+ /* Probe if necessary. */
+ if (action == UNREGISTER_PROBE)
+ ret = css_probe_device(sch->schid);
+ break;
+ case REPROBE:
+ device_trigger_reprobe(sch);
break;
default:
- BUG();
- ret = 0;
+ break;
}
+ spin_unlock_irqrestore(&sch->lock, flags);
+
+ return ret;
+}
+
+static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
+{
+ struct schib schib;
+
+ if (!slow) {
+ /* Will be done on the slow path. */
+ return -EAGAIN;
+ }
+ if (stsch(schid, &schib) || !schib.pmcw.dnv) {
+ /* Unusable - ignore. */
+ return 0;
+ }
+ CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, unknown, "
+ "slow path.\n", schid.ssid, schid.sch_no, CIO_OPER);
+
+ return css_probe_device(schid);
+}
+
+static int css_evaluate_subchannel(struct subchannel_id schid, int slow)
+{
+ struct subchannel *sch;
+ int ret;
+
+ sch = get_subchannel_by_schid(schid);
+ if (sch) {
+ ret = css_evaluate_known_subchannel(sch, slow);
+ put_device(&sch->dev);
+ } else
+ ret = css_evaluate_new_subchannel(schid, slow);
+
return ret;
}
@@ -339,6 +364,67 @@ typedef void (*workfunc)(void *);
DECLARE_WORK(slow_path_work, (workfunc)css_trigger_slow_path, NULL);
struct workqueue_struct *slow_path_wq;
+/* Reprobe subchannel if unregistered. */
+static int reprobe_subchannel(struct subchannel_id schid, void *data)
+{
+ struct subchannel *sch;
+ int ret;
+
+ CIO_DEBUG(KERN_INFO, 6, "cio: reprobe 0.%x.%04x\n",
+ schid.ssid, schid.sch_no);
+ if (need_reprobe)
+ return -EAGAIN;
+
+ sch = get_subchannel_by_schid(schid);
+ if (sch) {
+ /* Already known. */
+ put_device(&sch->dev);
+ return 0;
+ }
+
+ ret = css_probe_device(schid);
+ switch (ret) {
+ case 0:
+ break;
+ case -ENXIO:
+ case -ENOMEM:
+ /* These should abort looping */
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/* Work function used to reprobe all unregistered subchannels. */
+static void reprobe_all(void *data)
+{
+ int ret;
+
+ CIO_MSG_EVENT(2, "reprobe start\n");
+
+ need_reprobe = 0;
+ /* Make sure initial subchannel scan is done. */
+ wait_event(ccw_device_init_wq,
+ atomic_read(&ccw_device_init_count) == 0);
+ ret = for_each_subchannel(reprobe_subchannel, NULL);
+
+ CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+ need_reprobe);
+}
+
+DECLARE_WORK(css_reprobe_work, reprobe_all, NULL);
+
+/* Schedule reprobing of all unregistered subchannels. */
+void css_schedule_reprobe(void)
+{
+ need_reprobe = 1;
+ queue_work(ccw_device_work, &css_reprobe_work);
+}
+
+EXPORT_SYMBOL_GPL(css_schedule_reprobe);
+
/*
* Rescan for new devices. FIXME: This is slow.
* This function is called when we have lost CRWs due to overflows and we have
@@ -542,9 +628,13 @@ init_channel_subsystem (void)
ret = device_register(&css[i]->device);
if (ret)
goto out_free;
- if (css_characteristics_avail && css_chsc_characteristics.secm)
- device_create_file(&css[i]->device,
- &dev_attr_cm_enable);
+ if (css_characteristics_avail &&
+ css_chsc_characteristics.secm) {
+ ret = device_create_file(&css[i]->device,
+ &dev_attr_cm_enable);
+ if (ret)
+ goto out_device;
+ }
}
css_init_done = 1;
@@ -552,6 +642,8 @@ init_channel_subsystem (void)
for_each_subchannel(__init_channel_subsystem, NULL);
return 0;
+out_device:
+ device_unregister(&css[i]->device);
out_free:
kfree(css[i]);
out_unregister:
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index e210f89a244..8aabb4adeb5 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -100,7 +100,7 @@ struct ccw_device_private {
struct qdio_irq *qdio_data;
struct irb irb; /* device status */
struct senseid senseid; /* SenseID info */
- struct pgid pgid; /* path group ID */
+ struct pgid pgid[8]; /* path group IDs per chpid*/
struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */
struct work_struct kick_work;
wait_queue_head_t wait_q;
@@ -136,6 +136,8 @@ extern struct bus_type css_bus_type;
extern struct css_driver io_subchannel_driver;
extern int css_probe_device(struct subchannel_id);
+extern int css_sch_device_register(struct subchannel *);
+extern void css_sch_device_unregister(struct subchannel *);
extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 8e3053c2a45..688945662c1 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -8,7 +8,6 @@
* Cornelia Huck (cornelia.huck@de.ibm.com)
* Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
@@ -53,55 +52,83 @@ ccw_bus_match (struct device * dev, struct device_driver * drv)
return 1;
}
-/*
- * Hotplugging interface for ccw devices.
- * Heavily modeled on pci and usb hotplug.
- */
-static int
-ccw_uevent (struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+/* Store modalias string delimited by prefix/suffix string into buffer with
+ * specified size. Return length of resulting string (excluding trailing '\0')
+ * even if string doesn't fit buffer (snprintf semantics). */
+static int snprint_alias(char *buf, size_t size, const char *prefix,
+ struct ccw_device_id *id, const char *suffix)
{
- struct ccw_device *cdev = to_ccwdev(dev);
- int i = 0;
- int length = 0;
+ int len;
- if (!cdev)
- return -ENODEV;
+ len = snprintf(buf, size, "%sccw:t%04Xm%02X", prefix, id->cu_type,
+ id->cu_model);
+ if (len > size)
+ return len;
+ buf += len;
+ size -= len;
+
+ if (id->dev_type != 0)
+ len += snprintf(buf, size, "dt%04Xdm%02X%s", id->dev_type,
+ id->dev_model, suffix);
+ else
+ len += snprintf(buf, size, "dtdm%s", suffix);
- /* what we want to pass to /sbin/hotplug */
+ return len;
+}
- envp[i++] = buffer;
- length += scnprintf(buffer, buffer_size - length, "CU_TYPE=%04X",
- cdev->id.cu_type);
- if ((buffer_size - length <= 0) || (i >= num_envp))
- return -ENOMEM;
- ++length;
- buffer += length;
+/* Set up environment variables for ccw device uevent. Return 0 on success,
+ * non-zero otherwise. */
+static int ccw_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct ccw_device *cdev = to_ccwdev(dev);
+ struct ccw_device_id *id = &(cdev->id);
+ int i = 0;
+ int len;
+ /* CU_TYPE= */
+ len = snprintf(buffer, buffer_size, "CU_TYPE=%04X", id->cu_type) + 1;
+ if (len > buffer_size || i >= num_envp)
+ return -ENOMEM;
envp[i++] = buffer;
- length += scnprintf(buffer, buffer_size - length, "CU_MODEL=%02X",
- cdev->id.cu_model);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ buffer += len;
+ buffer_size -= len;
+
+ /* CU_MODEL= */
+ len = snprintf(buffer, buffer_size, "CU_MODEL=%02X", id->cu_model) + 1;
+ if (len > buffer_size || i >= num_envp)
return -ENOMEM;
- ++length;
- buffer += length;
+ envp[i++] = buffer;
+ buffer += len;
+ buffer_size -= len;
/* The next two can be zero, that's ok for us */
- envp[i++] = buffer;
- length += scnprintf(buffer, buffer_size - length, "DEV_TYPE=%04X",
- cdev->id.dev_type);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ /* DEV_TYPE= */
+ len = snprintf(buffer, buffer_size, "DEV_TYPE=%04X", id->dev_type) + 1;
+ if (len > buffer_size || i >= num_envp)
return -ENOMEM;
- ++length;
- buffer += length;
+ envp[i++] = buffer;
+ buffer += len;
+ buffer_size -= len;
+ /* DEV_MODEL= */
+ len = snprintf(buffer, buffer_size, "DEV_MODEL=%02X",
+ (unsigned char) id->dev_model) + 1;
+ if (len > buffer_size || i >= num_envp)
+ return -ENOMEM;
envp[i++] = buffer;
- length += scnprintf(buffer, buffer_size - length, "DEV_MODEL=%02X",
- cdev->id.dev_model);
- if ((buffer_size - length <= 0) || (i >= num_envp))
+ buffer += len;
+ buffer_size -= len;
+
+ /* MODALIAS= */
+ len = snprint_alias(buffer, buffer_size, "MODALIAS=", id, "") + 1;
+ if (len > buffer_size || i >= num_envp)
return -ENOMEM;
+ envp[i++] = buffer;
+ buffer += len;
+ buffer_size -= len;
- envp[i] = 0;
+ envp[i] = NULL;
return 0;
}
@@ -133,8 +160,8 @@ struct css_driver io_subchannel_driver = {
struct workqueue_struct *ccw_device_work;
struct workqueue_struct *ccw_device_notify_work;
-static wait_queue_head_t ccw_device_init_wq;
-static atomic_t ccw_device_init_count;
+wait_queue_head_t ccw_device_init_wq;
+atomic_t ccw_device_init_count;
static int __init
init_ccw_bus_type (void)
@@ -252,16 +279,11 @@ modalias_show (struct device *dev, struct device_attribute *attr, char *buf)
{
struct ccw_device *cdev = to_ccwdev(dev);
struct ccw_device_id *id = &(cdev->id);
- int ret;
+ int len;
- ret = sprintf(buf, "ccw:t%04Xm%02X",
- id->cu_type, id->cu_model);
- if (id->dev_type != 0)
- ret += sprintf(buf + ret, "dt%04Xdm%02X\n",
- id->dev_type, id->dev_model);
- else
- ret += sprintf(buf + ret, "dtdm\n");
- return ret;
+ len = snprint_alias(buf, PAGE_SIZE, "", id, "\n") + 1;
+
+ return len > PAGE_SIZE ? PAGE_SIZE : len;
}
static ssize_t
@@ -281,7 +303,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
* 'throw away device'.
*/
sch = to_subchannel(cdev->dev.parent);
- device_unregister(&sch->dev);
+ css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
@@ -557,12 +579,11 @@ get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid,
struct ccw_device *sibling)
{
struct device *dev;
- struct match_data data = {
- .devno = devno,
- .ssid = ssid,
- .sibling = sibling,
- };
+ struct match_data data;
+ data.devno = devno;
+ data.ssid = ssid;
+ data.sibling = sibling;
dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno);
return dev ? to_ccwdev(dev) : NULL;
@@ -626,7 +647,7 @@ ccw_device_do_unreg_rereg(void *data)
other_sch->schib.pmcw.intparm = 0;
cio_modify(other_sch);
}
- device_unregister(&other_sch->dev);
+ css_sch_device_unregister(other_sch);
}
}
/* Update ssd info here. */
@@ -710,7 +731,7 @@ ccw_device_call_sch_unregister(void *data)
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
- device_unregister(&sch->dev);
+ css_sch_device_unregister(sch);
/* Reset intparm to zeroes. */
sch->schib.pmcw.intparm = 0;
cio_modify(sch);
@@ -836,10 +857,8 @@ io_subchannel_probe (struct subchannel *sch)
return -ENOMEM;
}
atomic_set(&cdev->private->onoff, 0);
- cdev->dev = (struct device) {
- .parent = &sch->dev,
- .release = ccw_device_release,
- };
+ cdev->dev.parent = &sch->dev;
+ cdev->dev.release = ccw_device_release;
INIT_LIST_HEAD(&cdev->private->kick_work.entry);
/* Do first half of device_register. */
device_initialize(&cdev->dev);
@@ -978,9 +997,7 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
int rc;
/* Initialize the ccw_device structure. */
- cdev->dev = (struct device) {
- .parent = &sch->dev,
- };
+ cdev->dev.parent= &sch->dev;
rc = io_subchannel_recog(cdev, sch);
if (rc)
return rc;
@@ -1058,7 +1075,7 @@ get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
__ccwdev_check_busid);
put_driver(drv);
- return dev ? to_ccwdev(dev) : 0;
+ return dev ? to_ccwdev(dev) : NULL;
}
/************************** device driver handling ************************/
@@ -1083,7 +1100,7 @@ ccw_device_probe (struct device *dev)
ret = cdrv->probe ? cdrv->probe(cdev) : -ENODEV;
if (ret) {
- cdev->drv = 0;
+ cdev->drv = NULL;
return ret;
}
@@ -1114,7 +1131,7 @@ ccw_device_remove (struct device *dev)
ret, cdev->dev.bus_id);
}
ccw_device_set_timeout(cdev, 0);
- cdev->drv = 0;
+ cdev->drv = NULL;
return 0;
}
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 11587ebb728..00be9a5b4ac 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -1,6 +1,10 @@
#ifndef S390_DEVICE_H
#define S390_DEVICE_H
+#include <asm/ccwdev.h>
+#include <asm/atomic.h>
+#include <linux/wait.h>
+
/*
* states of the device statemachine
*/
@@ -23,6 +27,7 @@ enum dev_state {
DEV_STATE_DISCONNECTED,
DEV_STATE_DISCONNECTED_SENSE_ID,
DEV_STATE_CMFCHANGE,
+ DEV_STATE_CMFUPDATE,
/* last element! */
NR_DEV_STATES
};
@@ -67,6 +72,8 @@ dev_fsm_final_state(struct ccw_device *cdev)
extern struct workqueue_struct *ccw_device_work;
extern struct workqueue_struct *ccw_device_notify_work;
+extern wait_queue_head_t ccw_device_init_wq;
+extern atomic_t ccw_device_init_count;
void io_subchannel_recog_done(struct ccw_device *cdev);
@@ -112,5 +119,8 @@ int ccw_device_stlck(struct ccw_device *);
void ccw_device_set_timeout(struct ccw_device *, int);
extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
+/* Channel measurement facility related */
void retry_set_schib(struct ccw_device *cdev);
+void cmf_retry_copy_block(struct ccw_device *);
+int cmf_reenable(struct ccw_device *);
#endif
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 49ec562d7f6..dace46fc32e 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -9,7 +9,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/string.h>
@@ -153,7 +152,8 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev)
if (cdev->private->iretry) {
cdev->private->iretry--;
ret = cio_halt(sch);
- return (ret == 0) ? -EBUSY : ret;
+ if (ret != -EBUSY)
+ return (ret == 0) ? -EBUSY : ret;
}
/* halt io unsuccessful. */
cdev->private->iretry = 255; /* 255 clear retries. */
@@ -232,10 +232,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
*/
old_lpm = sch->lpm;
stsch(sch->schid, &sch->schib);
- sch->lpm = sch->schib.pmcw.pim &
- sch->schib.pmcw.pam &
- sch->schib.pmcw.pom &
- sch->opm;
+ sch->lpm = sch->schib.pmcw.pam & sch->opm;
/* Check since device may again have become not operational. */
if (!sch->schib.pmcw.dnv)
state = DEV_STATE_NOT_OPER;
@@ -267,12 +264,11 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
notify = 1;
}
/* fill out sense information */
- cdev->id = (struct ccw_device_id) {
- .cu_type = cdev->private->senseid.cu_type,
- .cu_model = cdev->private->senseid.cu_model,
- .dev_type = cdev->private->senseid.dev_type,
- .dev_model = cdev->private->senseid.dev_model,
- };
+ memset(&cdev->id, 0, sizeof(cdev->id));
+ cdev->id.cu_type = cdev->private->senseid.cu_type;
+ cdev->id.cu_model = cdev->private->senseid.cu_model;
+ cdev->id.dev_type = cdev->private->senseid.dev_type;
+ cdev->id.dev_model = cdev->private->senseid.dev_model;
if (notify) {
cdev->private->state = DEV_STATE_OFFLINE;
if (same_dev) {
@@ -336,8 +332,11 @@ ccw_device_oper_notify(void *data)
if (!ret)
/* Driver doesn't want device back. */
ccw_device_do_unreg_rereg((void *)cdev);
- else
+ else {
+ /* Reenable channel measurements, if needed. */
+ cmf_reenable(cdev);
wake_up(&cdev->private->wait_q);
+ }
}
/*
@@ -376,6 +375,56 @@ ccw_device_done(struct ccw_device *cdev, int state)
put_device (&cdev->dev);
}
+static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+{
+ char *c1;
+ char *c2;
+
+ c1 = (char *)p1;
+ c2 = (char *)p2;
+
+ return memcmp(c1 + 1, c2 + 1, sizeof(struct pgid) - 1);
+}
+
+static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
+{
+ int i;
+ int last;
+
+ last = 0;
+ for (i = 0; i < 8; i++) {
+ if (cdev->private->pgid[i].inf.ps.state1 == SNID_STATE1_RESET)
+ /* No PGID yet */
+ continue;
+ if (cdev->private->pgid[last].inf.ps.state1 ==
+ SNID_STATE1_RESET) {
+ /* First non-zero PGID */
+ last = i;
+ continue;
+ }
+ if (cmp_pgid(&cdev->private->pgid[i],
+ &cdev->private->pgid[last]) == 0)
+ /* Non-conflicting PGIDs */
+ continue;
+
+ /* PGID mismatch, can't pathgroup. */
+ CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
+ "0.%x.%04x, can't pathgroup\n",
+ cdev->private->ssid, cdev->private->devno);
+ cdev->private->options.pgroup = 0;
+ return;
+ }
+ if (cdev->private->pgid[last].inf.ps.state1 ==
+ SNID_STATE1_RESET)
+ /* No previous pgid found */
+ memcpy(&cdev->private->pgid[0], &css[0]->global_pgid,
+ sizeof(struct pgid));
+ else
+ /* Use existing pgid */
+ memcpy(&cdev->private->pgid[0], &cdev->private->pgid[last],
+ sizeof(struct pgid));
+}
+
/*
* Function called from device_pgid.c after sense path ground has completed.
*/
@@ -386,24 +435,26 @@ ccw_device_sense_pgid_done(struct ccw_device *cdev, int err)
sch = to_subchannel(cdev->dev.parent);
switch (err) {
- case 0:
- /* Start Path Group verification. */
- sch->vpm = 0; /* Start with no path groups set. */
- cdev->private->state = DEV_STATE_VERIFY;
- ccw_device_verify_start(cdev);
+ case -EOPNOTSUPP: /* path grouping not supported, use nop instead. */
+ cdev->private->options.pgroup = 0;
+ break;
+ case 0: /* success */
+ case -EACCES: /* partial success, some paths not operational */
+ /* Check if all pgids are equal or 0. */
+ __ccw_device_get_common_pgid(cdev);
break;
case -ETIME: /* Sense path group id stopped by timeout. */
case -EUSERS: /* device is reserved for someone else. */
ccw_device_done(cdev, DEV_STATE_BOXED);
- break;
- case -EOPNOTSUPP: /* path grouping not supported, just set online. */
- cdev->private->options.pgroup = 0;
- ccw_device_done(cdev, DEV_STATE_ONLINE);
- break;
+ return;
default:
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
- break;
+ return;
}
+ /* Start Path Group verification. */
+ cdev->private->state = DEV_STATE_VERIFY;
+ cdev->private->flags.doverify = 0;
+ ccw_device_verify_start(cdev);
}
/*
@@ -502,7 +553,19 @@ ccw_device_nopath_notify(void *data)
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
- cdev->private->flags.doverify = 0;
+ struct subchannel *sch;
+
+ sch = to_subchannel(cdev->dev.parent);
+ /* Update schib - pom may have changed. */
+ stsch(sch->schid, &sch->schib);
+ /* Update lpm with verified path mask. */
+ sch->lpm = sch->vpm;
+ /* Repeat path verification? */
+ if (cdev->private->flags.doverify) {
+ cdev->private->flags.doverify = 0;
+ ccw_device_verify_start(cdev);
+ return;
+ }
switch (err) {
case -EOPNOTSUPP: /* path grouping not supported, just set online. */
cdev->private->options.pgroup = 0;
@@ -511,12 +574,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
/* Deliver fake irb to device driver, if needed. */
if (cdev->private->flags.fake_irb) {
memset(&cdev->private->irb, 0, sizeof(struct irb));
- cdev->private->irb.scsw = (struct scsw) {
- .cc = 1,
- .fctl = SCSW_FCTL_START_FUNC,
- .actl = SCSW_ACTL_START_PEND,
- .stctl = SCSW_STCTL_STATUS_PEND,
- };
+ cdev->private->irb.scsw.cc = 1;
+ cdev->private->irb.scsw.fctl = SCSW_FCTL_START_FUNC;
+ cdev->private->irb.scsw.actl = SCSW_ACTL_START_PEND;
+ cdev->private->irb.scsw.stctl = SCSW_STCTL_STATUS_PEND;
cdev->private->flags.fake_irb = 0;
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
@@ -560,8 +621,10 @@ ccw_device_online(struct ccw_device *cdev)
}
/* Do we want to do path grouping? */
if (!cdev->private->options.pgroup) {
- /* No, set state online immediately. */
- ccw_device_done(cdev, DEV_STATE_ONLINE);
+ /* Start initial path verification. */
+ cdev->private->state = DEV_STATE_VERIFY;
+ cdev->private->flags.doverify = 0;
+ ccw_device_verify_start(cdev);
return 0;
}
/* Do a SensePGID first. */
@@ -703,8 +766,6 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
{
struct subchannel *sch;
- if (!cdev->private->options.pgroup)
- return;
if (cdev->private->state == DEV_STATE_W4SENSE) {
cdev->private->flags.doverify = 1;
return;
@@ -717,6 +778,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
stsch(sch->schid, &sch->schib);
if (sch->schib.scsw.actl != 0 ||
+ (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) ||
(cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
/*
* No final status yet or final status not yet delivered
@@ -728,6 +790,7 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
}
/* Device is idle, we can do the path verification. */
cdev->private->state = DEV_STATE_VERIFY;
+ cdev->private->flags.doverify = 0;
ccw_device_verify_start(cdev);
}
@@ -861,6 +924,8 @@ ccw_device_clear_verify(struct ccw_device *cdev, enum dev_event dev_event)
irb = (struct irb *) __LC_IRB;
/* Accumulate status. We don't do basic sense. */
ccw_device_accumulate_irb(cdev, irb);
+ /* Remember to clear irb to avoid residuals. */
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
/* Try to start delayed device verification. */
ccw_device_online_verify(cdev, 0);
/* Note: Don't call handler for cio initiated clear! */
@@ -988,11 +1053,10 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
}
static void
-ccw_device_wait4io_verify(struct ccw_device *cdev, enum dev_event dev_event)
+ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event)
{
- /* When the I/O has terminated, we have to start verification. */
- if (cdev->private->options.pgroup)
- cdev->private->flags.doverify = 1;
+ /* Start verification after current task finished. */
+ cdev->private->flags.doverify = 1;
}
static void
@@ -1057,10 +1121,7 @@ device_trigger_reprobe(struct subchannel *sch)
* The pim, pam, pom values may not be accurate, but they are the best
* we have before performing device selection :/
*/
- sch->lpm = sch->schib.pmcw.pim &
- sch->schib.pmcw.pam &
- sch->schib.pmcw.pom &
- sch->opm;
+ sch->lpm = sch->schib.pmcw.pam & sch->opm;
/* Re-set some bits in the pmcw that were lost. */
sch->schib.pmcw.isc = 3;
sch->schib.pmcw.csense = 1;
@@ -1093,6 +1154,13 @@ ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
dev_fsm_event(cdev, dev_event);
}
+static void ccw_device_update_cmfblock(struct ccw_device *cdev,
+ enum dev_event dev_event)
+{
+ cmf_retry_copy_block(cdev);
+ cdev->private->state = DEV_STATE_ONLINE;
+ dev_fsm_event(cdev, dev_event);
+}
static void
ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
@@ -1177,7 +1245,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
- [DEV_EVENT_VERIFY] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_ONLINE] = {
[DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
@@ -1220,7 +1288,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
[DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq,
[DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout,
- [DEV_EVENT_VERIFY] = ccw_device_wait4io_verify,
+ [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
},
[DEV_STATE_QUIESCE] = {
[DEV_EVENT_NOTOPER] = ccw_device_quiesce_done,
@@ -1233,7 +1301,7 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_NOTOPER] = ccw_device_nop,
[DEV_EVENT_INTERRUPT] = ccw_device_start_id,
[DEV_EVENT_TIMEOUT] = ccw_device_bug,
- [DEV_EVENT_VERIFY] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_start_id,
},
[DEV_STATE_DISCONNECTED_SENSE_ID] = {
[DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
@@ -1247,6 +1315,12 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_TIMEOUT] = ccw_device_change_cmfstate,
[DEV_EVENT_VERIFY] = ccw_device_change_cmfstate,
},
+ [DEV_STATE_CMFUPDATE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_update_cmfblock,
+ [DEV_EVENT_INTERRUPT] = ccw_device_update_cmfblock,
+ [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock,
+ [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock,
+ },
};
/*
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index e60b2d8103b..1398367b5f6 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <asm/ccwdev.h>
@@ -43,18 +42,15 @@ diag210(struct diag210 * addr)
spin_lock_irqsave(&diag210_lock, flags);
diag210_tmp = *addr;
- asm volatile (
- " lhi %0,-1\n"
- " sam31\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1: sam64\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
- : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory" );
+ asm volatile(
+ " lhi %0,-1\n"
+ " sam31\n"
+ " diag %1,0,0x210\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1: sam64\n"
+ EX_TABLE(0b,1b)
+ : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory");
*addr = diag210_tmp;
spin_unlock_irqrestore(&diag210_lock, flags);
@@ -67,17 +63,14 @@ diag210(struct diag210 * addr)
{
int ccode;
- asm volatile (
- " lhi %0,-1\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " lhi %0,-1\n"
+ " diag %1,0,0x210\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
- : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory" );
+ EX_TABLE(0b,1b)
+ : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory");
return ccode;
}
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 795abb5a65b..93a897eebff 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -6,7 +6,6 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
* Cornelia Huck (cornelia.huck@de.ibm.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -78,7 +77,8 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
return -ENODEV;
if (cdev->private->state == DEV_STATE_NOT_OPER)
return -ENODEV;
- if (cdev->private->state == DEV_STATE_VERIFY) {
+ if (cdev->private->state == DEV_STATE_VERIFY ||
+ cdev->private->state == DEV_STATE_CLEAR_VERIFY) {
/* Remember to fake irb when finished. */
if (!cdev->private->flags.fake_irb) {
cdev->private->flags.fake_irb = 1;
@@ -96,6 +96,12 @@ ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa,
ret = cio_set_options (sch, flags);
if (ret)
return ret;
+ /* Adjust requested path mask to excluded varied off paths. */
+ if (lpm) {
+ lpm &= sch->opm;
+ if (lpm == 0)
+ return -EACCES;
+ }
ret = cio_start_key (sch, cpa, lpm, key);
if (ret == 0)
cdev->private->intparm = intparm;
@@ -250,7 +256,7 @@ ccw_device_get_path_mask(struct ccw_device *cdev)
if (!sch)
return 0;
else
- return sch->vpm;
+ return sch->lpm;
}
static void
@@ -263,6 +269,9 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
/* Abuse intparm for error reporting. */
if (IS_ERR(irb))
cdev->private->intparm = -EIO;
+ else if (irb->scsw.cc == 1)
+ /* Retry for deferred condition code. */
+ cdev->private->intparm = -EAGAIN;
else if ((irb->scsw.dstat !=
(DEV_STAT_CHN_END|DEV_STAT_DEV_END)) ||
(irb->scsw.cstat != 0)) {
@@ -270,7 +279,8 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
* We didn't get channel end / device end. Check if path
* verification has been started; we can retry after it has
* finished. We also retry unit checks except for command reject
- * or intervention required.
+ * or intervention required. Also check for long busy
+ * conditions.
*/
if (cdev->private->flags.doverify ||
cdev->private->state == DEV_STATE_VERIFY)
@@ -279,6 +289,10 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
!(irb->ecw[0] &
(SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
cdev->private->intparm = -EAGAIN;
+ else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
+ (irb->scsw.dstat & DEV_STAT_DEV_END) &&
+ (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
+ cdev->private->intparm = -EAGAIN;
else
cdev->private->intparm = -EIO;
@@ -296,7 +310,7 @@ __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, _
sch = to_subchannel(cdev->dev.parent);
do {
ret = cio_start (sch, ccw, lpm);
- if ((ret == -EBUSY) || (ret == -EACCES)) {
+ if (ret == -EBUSY) {
/* Try again later. */
spin_unlock_irq(&sch->lock);
msleep(10);
@@ -425,6 +439,13 @@ read_conf_data_lpm (struct ccw_device *cdev, void **buffer, int *length, __u8 lp
if (!ciw || ciw->cmd == 0)
return -EOPNOTSUPP;
+ /* Adjust requested path mask to excluded varied off paths. */
+ if (lpm) {
+ lpm &= sch->opm;
+ if (lpm == 0)
+ return -EACCES;
+ }
+
rcd_ccw = kzalloc(sizeof(struct ccw1), GFP_KERNEL | GFP_DMA);
if (!rcd_ccw)
return -ENOMEM;
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 85b1020a1fc..8ca2d078848 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -9,7 +9,6 @@
* Path Group ID functions.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -25,6 +24,21 @@
#include "ioasm.h"
/*
+ * Helper function called from interrupt context to decide whether an
+ * operation should be tried again.
+ */
+static int __ccw_device_should_retry(struct scsw *scsw)
+{
+ /* CC is only valid if start function bit is set. */
+ if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1)
+ return 1;
+ /* No more activity. For sense and set PGID we stubbornly try again. */
+ if (!scsw->actl)
+ return 1;
+ return 0;
+}
+
+/*
* Start Sense Path Group ID helper function. Used in ccw_device_recog
* and ccw_device_sense_pgid.
*/
@@ -34,12 +48,17 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
struct subchannel *sch;
struct ccw1 *ccw;
int ret;
+ int i;
sch = to_subchannel(cdev->dev.parent);
+ /* Return if we already checked on all paths. */
+ if (cdev->private->imask == 0)
+ return (sch->lpm == 0) ? -ENODEV : -EACCES;
+ i = 8 - ffs(cdev->private->imask);
+
/* Setup sense path group id channel program. */
ccw = cdev->private->iccws;
ccw->cmd_code = CCW_CMD_SENSE_PGID;
- ccw->cda = (__u32) __pa (&cdev->private->pgid);
ccw->count = sizeof (struct pgid);
ccw->flags = CCW_FLAG_SLI;
@@ -49,6 +68,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
ret = -ENODEV;
while (cdev->private->imask != 0) {
/* Try every path multiple times. */
+ ccw->cda = (__u32) __pa (&cdev->private->pgid[i]);
if (cdev->private->iretry > 0) {
cdev->private->iretry--;
ret = cio_start (sch, cdev->private->iccws,
@@ -65,7 +85,9 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
}
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
+ i++;
}
+
return ret;
}
@@ -77,7 +99,7 @@ ccw_device_sense_pgid_start(struct ccw_device *cdev)
cdev->private->state = DEV_STATE_SENSE_PGID;
cdev->private->imask = 0x80;
cdev->private->iretry = 5;
- memset (&cdev->private->pgid, 0, sizeof (struct pgid));
+ memset (&cdev->private->pgid, 0, sizeof (cdev->private->pgid));
ret = __ccw_device_sense_pgid_start(cdev);
if (ret && ret != -EBUSY)
ccw_device_sense_pgid_done(cdev, ret);
@@ -92,6 +114,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
{
struct subchannel *sch;
struct irb *irb;
+ int i;
sch = to_subchannel(cdev->dev.parent);
irb = &cdev->private->irb;
@@ -125,7 +148,8 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
sch->schid.sch_no, sch->orb.lpm);
return -EACCES;
}
- if (cdev->private->pgid.inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
+ i = 8 - ffs(cdev->private->imask);
+ if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
"is reserved by someone else\n",
cdev->private->devno, sch->schid.ssid,
@@ -146,10 +170,10 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
int ret;
irb = (struct irb *) __LC_IRB;
- /* Retry sense pgid for cc=1. */
+
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (irb->scsw.cc == 1) {
+ if (__ccw_device_should_retry(&irb->scsw)) {
ret = __ccw_device_sense_pgid_start(cdev);
if (ret && ret != -EBUSY)
ccw_device_sense_pgid_done(cdev, ret);
@@ -163,12 +187,6 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
memset(&cdev->private->irb, 0, sizeof(struct irb));
switch (ret) {
/* 0, -ETIME, -EOPNOTSUPP, -EAGAIN, -EACCES or -EUSERS */
- case 0: /* Sense Path Group ID successful. */
- if (cdev->private->pgid.inf.ps.state1 == SNID_STATE1_RESET)
- memcpy(&cdev->private->pgid, &css[0]->global_pgid,
- sizeof(struct pgid));
- ccw_device_sense_pgid_done(cdev, 0);
- break;
case -EOPNOTSUPP: /* Sense Path Group ID not supported */
ccw_device_sense_pgid_done(cdev, -EOPNOTSUPP);
break;
@@ -177,13 +195,15 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event)
break;
case -EACCES: /* channel is not operational. */
sch->lpm &= ~cdev->private->imask;
+ /* Fall through. */
+ case 0: /* Sense Path Group ID successful. */
cdev->private->imask >>= 1;
cdev->private->iretry = 5;
/* Fall through. */
case -EAGAIN: /* Try again. */
ret = __ccw_device_sense_pgid_start(cdev);
if (ret != 0 && ret != -EBUSY)
- ccw_device_sense_pgid_done(cdev, -ENODEV);
+ ccw_device_sense_pgid_done(cdev, ret);
break;
case -EUSERS: /* device is reserved for someone else. */
ccw_device_sense_pgid_done(cdev, -EUSERS);
@@ -204,20 +224,20 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
sch = to_subchannel(cdev->dev.parent);
/* Setup sense path group id channel program. */
- cdev->private->pgid.inf.fc = func;
+ cdev->private->pgid[0].inf.fc = func;
ccw = cdev->private->iccws;
if (!cdev->private->flags.pgid_single) {
- cdev->private->pgid.inf.fc |= SPID_FUNC_MULTI_PATH;
+ cdev->private->pgid[0].inf.fc |= SPID_FUNC_MULTI_PATH;
ccw->cmd_code = CCW_CMD_SUSPEND_RECONN;
ccw->cda = 0;
ccw->count = 0;
ccw->flags = CCW_FLAG_SLI | CCW_FLAG_CC;
ccw++;
} else
- cdev->private->pgid.inf.fc |= SPID_FUNC_SINGLE_PATH;
+ cdev->private->pgid[0].inf.fc |= SPID_FUNC_SINGLE_PATH;
ccw->cmd_code = CCW_CMD_SET_PGID;
- ccw->cda = (__u32) __pa (&cdev->private->pgid);
+ ccw->cda = (__u32) __pa (&cdev->private->pgid[0]);
ccw->count = sizeof (struct pgid);
ccw->flags = CCW_FLAG_SLI;
@@ -225,18 +245,17 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
memset(&cdev->private->irb, 0, sizeof(struct irb));
/* Try multiple times. */
- ret = -ENODEV;
+ ret = -EACCES;
if (cdev->private->iretry > 0) {
cdev->private->iretry--;
ret = cio_start (sch, cdev->private->iccws,
cdev->private->imask);
- /* ret is 0, -EBUSY, -EACCES or -ENODEV */
- if ((ret != -EACCES) && (ret != -ENODEV))
+ /* We expect an interrupt in case of success or busy
+ * indication. */
+ if ((ret == 0) || (ret == -EBUSY))
return ret;
}
- /* PGID command failed on this path. Switch it off. */
- sch->lpm &= ~cdev->private->imask;
- sch->vpm &= ~cdev->private->imask;
+ /* PGID command failed on this path. */
CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
cdev->private->devno, sch->schid.ssid,
@@ -245,6 +264,47 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
}
/*
+ * Helper function to send a nop ccw down a path.
+ */
+static int __ccw_device_do_nop(struct ccw_device *cdev)
+{
+ struct subchannel *sch;
+ struct ccw1 *ccw;
+ int ret;
+
+ sch = to_subchannel(cdev->dev.parent);
+
+ /* Setup nop channel program. */
+ ccw = cdev->private->iccws;
+ ccw->cmd_code = CCW_CMD_NOOP;
+ ccw->cda = 0;
+ ccw->count = 0;
+ ccw->flags = CCW_FLAG_SLI;
+
+ /* Reset device status. */
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+
+ /* Try multiple times. */
+ ret = -EACCES;
+ if (cdev->private->iretry > 0) {
+ cdev->private->iretry--;
+ ret = cio_start (sch, cdev->private->iccws,
+ cdev->private->imask);
+ /* We expect an interrupt in case of success or busy
+ * indication. */
+ if ((ret == 0) || (ret == -EBUSY))
+ return ret;
+ }
+ /* nop command failed on this path. */
+ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
+ "0.%x.%04x, lpm %02X, became 'not operational'\n",
+ cdev->private->devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return ret;
+}
+
+
+/*
* Called from interrupt context to check if a valid answer
* to Set Path Group ID was received.
*/
@@ -283,28 +343,59 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
return 0;
}
+/*
+ * Called from interrupt context to check the path status after a nop has
+ * been send.
+ */
+static int __ccw_device_check_nop(struct ccw_device *cdev)
+{
+ struct subchannel *sch;
+ struct irb *irb;
+
+ sch = to_subchannel(cdev->dev.parent);
+ irb = &cdev->private->irb;
+ if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC))
+ return -ETIME;
+ if (irb->scsw.cc == 3) {
+ CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
+ " lpm %02X, became 'not operational'\n",
+ cdev->private->devno, sch->schid.ssid,
+ sch->schid.sch_no, cdev->private->imask);
+ return -EACCES;
+ }
+ return 0;
+}
+
static void
__ccw_device_verify_start(struct ccw_device *cdev)
{
struct subchannel *sch;
- __u8 imask, func;
+ __u8 func;
int ret;
sch = to_subchannel(cdev->dev.parent);
- while (sch->vpm != sch->lpm) {
- /* Find first unequal bit in vpm vs. lpm */
- for (imask = 0x80; imask != 0; imask >>= 1)
- if ((sch->vpm & imask) != (sch->lpm & imask))
- break;
- cdev->private->imask = imask;
- func = (sch->vpm & imask) ?
- SPID_FUNC_RESIGN : SPID_FUNC_ESTABLISH;
- ret = __ccw_device_do_pgid(cdev, func);
+ /* Repeat for all paths. */
+ for (; cdev->private->imask; cdev->private->imask >>= 1,
+ cdev->private->iretry = 5) {
+ if ((cdev->private->imask & sch->schib.pmcw.pam) == 0)
+ /* Path not available, try next. */
+ continue;
+ if (cdev->private->options.pgroup) {
+ if (sch->opm & cdev->private->imask)
+ func = SPID_FUNC_ESTABLISH;
+ else
+ func = SPID_FUNC_RESIGN;
+ ret = __ccw_device_do_pgid(cdev, func);
+ } else
+ ret = __ccw_device_do_nop(cdev);
+ /* We expect an interrupt in case of success or busy
+ * indication. */
if (ret == 0 || ret == -EBUSY)
return;
- cdev->private->iretry = 5;
+ /* Permanent path failure, try next. */
}
- ccw_device_verify_done(cdev, (sch->lpm != 0) ? 0 : -ENODEV);
+ /* Done with all paths. */
+ ccw_device_verify_done(cdev, (sch->vpm != 0) ? 0 : -ENODEV);
}
/*
@@ -318,26 +409,29 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
int ret;
irb = (struct irb *) __LC_IRB;
- /* Retry set pgid for cc=1. */
+
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (irb->scsw.cc == 1)
+ if (__ccw_device_should_retry(&irb->scsw))
__ccw_device_verify_start(cdev);
return;
}
if (ccw_device_accumulate_and_sense(cdev, irb) != 0)
return;
sch = to_subchannel(cdev->dev.parent);
- ret = __ccw_device_check_pgid(cdev);
+ if (cdev->private->options.pgroup)
+ ret = __ccw_device_check_pgid(cdev);
+ else
+ ret = __ccw_device_check_nop(cdev);
memset(&cdev->private->irb, 0, sizeof(struct irb));
+
switch (ret) {
/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
case 0:
- /* Establish or Resign Path Group done. Update vpm. */
- if ((sch->lpm & cdev->private->imask) != 0)
- sch->vpm |= cdev->private->imask;
- else
- sch->vpm &= ~cdev->private->imask;
+ /* Path verification ccw finished successfully, update lpm. */
+ sch->vpm |= sch->opm & cdev->private->imask;
+ /* Go on with next path. */
+ cdev->private->imask >>= 1;
cdev->private->iretry = 5;
__ccw_device_verify_start(cdev);
break;
@@ -346,11 +440,14 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
* One of those strange devices which claim to be able
* to do multipathing but not for Set Path Group ID.
*/
- if (cdev->private->flags.pgid_single) {
- ccw_device_verify_done(cdev, -EOPNOTSUPP);
- break;
- }
- cdev->private->flags.pgid_single = 1;
+ if (cdev->private->flags.pgid_single)
+ cdev->private->options.pgroup = 0;
+ else
+ cdev->private->flags.pgid_single = 1;
+ /* Retry */
+ sch->vpm = 0;
+ cdev->private->imask = 0x80;
+ cdev->private->iretry = 5;
/* fall through. */
case -EAGAIN: /* Try again. */
__ccw_device_verify_start(cdev);
@@ -359,8 +456,7 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event)
ccw_device_verify_done(cdev, -ETIME);
break;
case -EACCES: /* channel is not operational. */
- sch->lpm &= ~cdev->private->imask;
- sch->vpm &= ~cdev->private->imask;
+ cdev->private->imask >>= 1;
cdev->private->iretry = 5;
__ccw_device_verify_start(cdev);
break;
@@ -373,19 +469,17 @@ ccw_device_verify_start(struct ccw_device *cdev)
struct subchannel *sch = to_subchannel(cdev->dev.parent);
cdev->private->flags.pgid_single = 0;
+ cdev->private->imask = 0x80;
cdev->private->iretry = 5;
- /*
- * Update sch->lpm with current values to catch paths becoming
- * available again.
- */
+
+ /* Start with empty vpm. */
+ sch->vpm = 0;
+
+ /* Get current pam. */
if (stsch(sch->schid, &sch->schib)) {
ccw_device_verify_done(cdev, -ENODEV);
return;
}
- sch->lpm = sch->schib.pmcw.pim &
- sch->schib.pmcw.pam &
- sch->schib.pmcw.pom &
- sch->opm;
__ccw_device_verify_start(cdev);
}
@@ -419,10 +513,10 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
int ret;
irb = (struct irb *) __LC_IRB;
- /* Retry set pgid for cc=1. */
+
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (irb->scsw.cc == 1)
+ if (__ccw_device_should_retry(&irb->scsw))
__ccw_device_disband_start(cdev);
return;
}
@@ -434,7 +528,6 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
switch (ret) {
/* 0, -ETIME, -EAGAIN, -EOPNOTSUPP or -EACCES */
case 0: /* disband successful. */
- sch->vpm = 0;
ccw_device_disband_done(cdev, ret);
break;
case -EOPNOTSUPP:
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index 6c762b43f92..caf148d5caa 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -9,7 +9,6 @@
* Status accumulation and basic sense functions.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -68,8 +67,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
sch->schib.pmcw.pnom);
sch->lpm &= ~sch->schib.pmcw.pnom;
- if (cdev->private->options.pgroup)
- cdev->private->flags.doverify = 1;
+ cdev->private->flags.doverify = 1;
}
/*
@@ -181,7 +179,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
cdev_irb->esw.esw0.erw.auth = irb->esw.esw0.erw.auth;
/* Copy path verification required flag. */
cdev_irb->esw.esw0.erw.pvrf = irb->esw.esw0.erw.pvrf;
- if (irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
+ if (irb->esw.esw0.erw.pvrf)
cdev->private->flags.doverify = 1;
/* Copy concurrent sense bit. */
cdev_irb->esw.esw0.erw.cons = irb->esw.esw0.erw.cons;
@@ -355,7 +353,7 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb)
}
/* Check if path verification is required. */
if (ccw_device_accumulate_esw_valid(irb) &&
- irb->esw.esw0.erw.pvrf && cdev->private->options.pgroup)
+ irb->esw.esw0.erw.pvrf)
cdev->private->flags.doverify = 1;
}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 95a9462f9a9..ad6d8294006 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -25,106 +25,74 @@ struct tpi_info {
static inline int stsch(struct subchannel_id schid,
volatile struct schib *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " stsch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " stsch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int stsch_err(struct subchannel_id schid,
volatile struct schib *addr)
{
- int ccode;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
- __asm__ __volatile__(
- " lhi %0,%3\n"
- " lr 1,%1\n"
- " stsch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " stsch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifdef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (ccode)
- : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
- : "cc", "1" );
+ EX_TABLE(0b,1b)
+ : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int msch(struct subchannel_id schid,
volatile struct schib *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " msch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " msch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int msch_err(struct subchannel_id schid,
volatile struct schib *addr)
{
- int ccode;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
- __asm__ __volatile__(
- " lhi %0,%3\n"
- " lr 1,%1\n"
- " msch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " msch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifdef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (ccode)
- : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
- : "cc", "1" );
+ EX_TABLE(0b,1b)
+ : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int tsch(struct subchannel_id schid,
volatile struct irb *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " tsch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " tsch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
@@ -132,89 +100,77 @@ static inline int tpi( volatile struct tpi_info *addr)
{
int ccode;
- __asm__ __volatile__(
- " tpi 0(%1)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " tpi 0(%1)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int ssch(struct subchannel_id schid,
volatile struct orb *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " ssch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " ssch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int rsch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " rsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " rsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
static inline int csch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " csch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " csch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
static inline int hsch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " hsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " hsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
static inline int xsch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " .insn rre,0xb2760000,%1,0\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " .insn rre,0xb2760000,%1,0\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
@@ -223,41 +179,27 @@ static inline int chsc(void *chsc_area)
typedef struct { char _[4096]; } addr_type;
int cc;
- __asm__ __volatile__ (
- ".insn rre,0xb25f0000,%2,0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
+ asm volatile(
+ " .insn rre,0xb25f0000,%2,0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (cc), "=m" (*(addr_type *) chsc_area)
: "d" (chsc_area), "m" (*(addr_type *) chsc_area)
- : "cc" );
-
+ : "cc");
return cc;
}
-static inline int iac( void)
-{
- int ccode;
-
- __asm__ __volatile__(
- " iac 1\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode) : : "cc", "1" );
- return ccode;
-}
-
static inline int rchp(int chpid)
{
+ register unsigned int reg1 asm ("1") = chpid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " rchp\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (chpid)
- : "cc", "1" );
+ asm volatile(
+ " lr 1,%1\n"
+ " rchp\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 96f519281d9..cde822d8b5c 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -30,7 +30,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -116,7 +115,7 @@ qdio_min(int a,int b)
static inline __u64
qdio_get_micros(void)
{
- return (get_clock() >> 10); /* time>>12 is microseconds */
+ return (get_clock() >> 12); /* time>>12 is microseconds */
}
/*
@@ -1130,7 +1129,7 @@ out:
#ifdef QDIO_USE_PROCESSING_STATE
if (last_position>=0)
- set_slsb(q, &last_position, SLSB_P_INPUT_NOT_INIT, &count);
+ set_slsb(q, &last_position, SLSB_P_INPUT_PROCESSING, &count);
#endif /* QDIO_USE_PROCESSING_STATE */
QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
@@ -2736,7 +2735,7 @@ qdio_free(struct ccw_device *cdev)
QDIO_DBF_TEXT1(0,trace,dbf_text);
QDIO_DBF_TEXT0(0,setup,dbf_text);
- cdev->private->qdio_data = 0;
+ cdev->private->qdio_data = NULL;
up(&irq_ptr->setting_up_sema);
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index ceb3ab31ee0..49bb9e371c3 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -191,49 +191,49 @@ enum qdio_irq_states {
#if QDIO_VERBOSE_LEVEL>8
#define QDIO_PRINT_STUPID(x...) printk( KERN_DEBUG QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_STUPID(x...)
+#define QDIO_PRINT_STUPID(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>7
#define QDIO_PRINT_ALL(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_ALL(x...)
+#define QDIO_PRINT_ALL(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>6
#define QDIO_PRINT_INFO(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_INFO(x...)
+#define QDIO_PRINT_INFO(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>5
#define QDIO_PRINT_WARN(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_WARN(x...)
+#define QDIO_PRINT_WARN(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>4
#define QDIO_PRINT_ERR(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_ERR(x...)
+#define QDIO_PRINT_ERR(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>3
#define QDIO_PRINT_CRIT(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_CRIT(x...)
+#define QDIO_PRINT_CRIT(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>2
#define QDIO_PRINT_ALERT(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_ALERT(x...)
+#define QDIO_PRINT_ALERT(x...) do { } while (0)
#endif
#if QDIO_VERBOSE_LEVEL>1
#define QDIO_PRINT_EMERG(x...) printk( QDIO_PRINTK_HEADER x)
#else
-#define QDIO_PRINT_EMERG(x...)
+#define QDIO_PRINT_EMERG(x...) do { } while (0)
#endif
#define HEXDUMP16(importance,header,ptr) \
@@ -274,12 +274,11 @@ do_sqbs(unsigned long sch, unsigned char state, int queue,
register unsigned long _sch asm ("1") = sch;
unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
- asm volatile (
- " .insn rsy,0xeb000000008A,%1,0,0(%2)\n\t"
- : "+d" (_ccq), "+d" (_queuestart)
- : "d" ((unsigned long)state), "d" (_sch)
- : "memory", "cc"
- );
+ asm volatile(
+ " .insn rsy,0xeb000000008A,%1,0,0(%2)"
+ : "+d" (_ccq), "+d" (_queuestart)
+ : "d" ((unsigned long)state), "d" (_sch)
+ : "memory", "cc");
*count = _ccq & 0xff;
*start = _queuestart & 0xff;
@@ -299,12 +298,11 @@ do_eqbs(unsigned long sch, unsigned char *state, int queue,
unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
unsigned long _state = 0;
- asm volatile (
- " .insn rrf,0xB99c0000,%1,%2,0,0 \n\t"
- : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
- : "d" (_sch)
- : "memory", "cc"
- );
+ asm volatile(
+ " .insn rrf,0xB99c0000,%1,%2,0,0"
+ : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
+ : "d" (_sch)
+ : "memory", "cc" );
*count = _ccq & 0xff;
*start = _queuestart & 0xff;
*state = _state & 0xff;
@@ -319,69 +317,35 @@ do_eqbs(unsigned long sch, unsigned char *state, int queue,
static inline int
do_siga_sync(struct subchannel_id schid, unsigned int mask1, unsigned int mask2)
{
+ register unsigned long reg0 asm ("0") = 2;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ register unsigned long reg2 asm ("2") = mask1;
+ register unsigned long reg3 asm ("3") = mask2;
int cc;
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 0,2 \n\t"
- "lr 1,%1 \n\t"
- "lr 2,%2 \n\t"
- "lr 3,%3 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
+ asm volatile(
+ " siga 0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (cc)
- : "d" (schid), "d" (mask1), "d" (mask2)
- : "cc", "0", "1", "2", "3"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "lghi 0,2 \n\t"
- "llgfr 1,%1 \n\t"
- "llgfr 2,%2 \n\t"
- "llgfr 3,%3 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- : "=d" (cc)
- : "d" (schid), "d" (mask1), "d" (mask2)
- : "cc", "0", "1", "2", "3"
- );
-#endif /* CONFIG_64BIT */
+ : "d" (reg0), "d" (reg1), "d" (reg2), "d" (reg3) : "cc");
return cc;
}
static inline int
do_siga_input(struct subchannel_id schid, unsigned int mask)
{
+ register unsigned long reg0 asm ("0") = 1;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ register unsigned long reg2 asm ("2") = mask;
int cc;
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 0,1 \n\t"
- "lr 1,%1 \n\t"
- "lr 2,%2 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- : "=d" (cc)
- : "d" (schid), "d" (mask)
- : "cc", "0", "1", "2", "memory"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "lghi 0,1 \n\t"
- "llgfr 1,%1 \n\t"
- "llgfr 2,%2 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
+ asm volatile(
+ " siga 0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (cc)
- : "d" (schid), "d" (mask)
- : "cc", "0", "1", "2", "memory"
- );
-#endif /* CONFIG_64BIT */
-
+ : "d" (reg0), "d" (reg1), "d" (reg2) : "cc", "memory");
return cc;
}
@@ -389,93 +353,35 @@ static inline int
do_siga_output(unsigned long schid, unsigned long mask, __u32 *bb,
unsigned int fc)
{
+ register unsigned long __fc asm("0") = fc;
+ register unsigned long __schid asm("1") = schid;
+ register unsigned long __mask asm("2") = mask;
int cc;
- __u32 busy_bit;
-
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 0,0 \n\t"
- "lr 1,%2 \n\t"
- "lr 2,%3 \n\t"
- "siga 0 \n\t"
- "0:"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- "srl 0,31 \n\t"
- "lr %1,0 \n\t"
- "1: \n\t"
- ".section .fixup,\"ax\"\n\t"
- "2: \n\t"
- "lhi %0,%4 \n\t"
- "bras 1,3f \n\t"
- ".long 1b \n\t"
- "3: \n\t"
- "l 1,0(1) \n\t"
- "br 1 \n\t"
- ".previous \n\t"
- ".section __ex_table,\"a\"\n\t"
- ".align 4 \n\t"
- ".long 0b,2b \n\t"
- ".previous \n\t"
- : "=d" (cc), "=d" (busy_bit)
- : "d" (schid), "d" (mask),
- "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
- : "cc", "0", "1", "2", "memory"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "llgfr 0,%5 \n\t"
- "lgr 1,%2 \n\t"
- "llgfr 2,%3 \n\t"
- "siga 0 \n\t"
- "0:"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- "srl 0,31 \n\t"
- "llgfr %1,0 \n\t"
- "1: \n\t"
- ".section .fixup,\"ax\"\n\t"
- "lghi %0,%4 \n\t"
- "jg 1b \n\t"
- ".previous\n\t"
- ".section __ex_table,\"a\"\n\t"
- ".align 8 \n\t"
- ".quad 0b,1b \n\t"
- ".previous \n\t"
- : "=d" (cc), "=d" (busy_bit)
- : "d" (schid), "d" (mask),
- "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc)
- : "cc", "0", "1", "2", "memory"
- );
-#endif /* CONFIG_64BIT */
-
- (*bb) = busy_bit;
+
+ asm volatile(
+ " siga 0\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask)
+ : "0" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
+ : "cc", "memory");
+ (*bb) = ((unsigned int) __fc) >> 31;
return cc;
}
static inline unsigned long
do_clear_global_summary(void)
{
-
- unsigned long time;
-
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 1,3 \n\t"
- ".insn rre,0xb2650000,2,0 \n\t"
- "lr %0,3 \n\t"
- : "=d" (time) : : "cc", "1", "2", "3"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "lghi 1,3 \n\t"
- ".insn rre,0xb2650000,2,0 \n\t"
- "lgr %0,3 \n\t"
- : "=d" (time) : : "cc", "1", "2", "3"
- );
-#endif /* CONFIG_64BIT */
-
- return time;
+ register unsigned long __fn asm("1") = 3;
+ register unsigned long __tmp asm("2");
+ register unsigned long __time asm("3");
+
+ asm volatile(
+ " .insn rre,0xb2650000,2,0"
+ : "+d" (__fn), "=d" (__tmp), "=d" (__time));
+ return __time;
}
/*
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
index 15edebbead7..f0a12d2eb78 100644
--- a/drivers/s390/crypto/Makefile
+++ b/drivers/s390/crypto/Makefile
@@ -2,5 +2,16 @@
# S/390 crypto devices
#
-z90crypt-objs := z90main.o z90hardware.o
-obj-$(CONFIG_Z90CRYPT) += z90crypt.o
+ifdef CONFIG_ZCRYPT_MONOLITHIC
+
+z90crypt-objs := zcrypt_mono.o ap_bus.o zcrypt_api.o \
+ zcrypt_pcica.o zcrypt_pcicc.o zcrypt_pcixcc.o zcrypt_cex2a.o
+obj-$(CONFIG_ZCRYPT) += z90crypt.o
+
+else
+
+ap-objs := ap_bus.o
+obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcicc.o zcrypt_pcixcc.o
+obj-$(CONFIG_ZCRYPT) += zcrypt_pcica.o zcrypt_cex2a.o
+
+endif
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
new file mode 100644
index 00000000000..6ed0985c0c9
--- /dev/null
+++ b/drivers/s390/crypto/ap_bus.c
@@ -0,0 +1,1221 @@
+/*
+ * linux/drivers/s390/crypto/ap_bus.c
+ *
+ * Copyright (C) 2006 IBM Corporation
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * Adjunct processor bus.
+ *
+ * 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, 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/err.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/notifier.h>
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <asm/s390_rdev.h>
+
+#include "ap_bus.h"
+
+/* Some prototypes. */
+static void ap_scan_bus(void *);
+static void ap_poll_all(unsigned long);
+static void ap_poll_timeout(unsigned long);
+static int ap_poll_thread_start(void);
+static void ap_poll_thread_stop(void);
+
+/**
+ * Module description.
+ */
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("Adjunct Processor Bus driver, "
+ "Copyright 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+
+/**
+ * Module parameter
+ */
+int ap_domain_index = -1; /* Adjunct Processor Domain Index */
+module_param_named(domain, ap_domain_index, int, 0000);
+MODULE_PARM_DESC(domain, "domain index for ap devices");
+EXPORT_SYMBOL(ap_domain_index);
+
+static int ap_thread_flag = 1;
+module_param_named(poll_thread, ap_thread_flag, int, 0000);
+MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 1 (on).");
+
+static struct device *ap_root_device = NULL;
+
+/**
+ * Workqueue & timer for bus rescan.
+ */
+static struct workqueue_struct *ap_work_queue;
+static struct timer_list ap_config_timer;
+static int ap_config_time = AP_CONFIG_TIME;
+static DECLARE_WORK(ap_config_work, ap_scan_bus, NULL);
+
+/**
+ * Tasklet & timer for AP request polling.
+ */
+static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0);
+static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0);
+static atomic_t ap_poll_requests = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait);
+static struct task_struct *ap_poll_kthread = NULL;
+static DEFINE_MUTEX(ap_poll_thread_mutex);
+
+/**
+ * Test if ap instructions are available.
+ *
+ * Returns 0 if the ap instructions are installed.
+ */
+static inline int ap_instructions_available(void)
+{
+ register unsigned long reg0 asm ("0") = AP_MKQID(0,0);
+ register unsigned long reg1 asm ("1") = -ENODEV;
+ register unsigned long reg2 asm ("2") = 0UL;
+
+ asm volatile(
+ " .long 0xb2af0000\n" /* PQAP(TAPQ) */
+ "0: la %1,0\n"
+ "1:\n"
+ EX_TABLE(0b, 1b)
+ : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" );
+ return reg1;
+}
+
+/**
+ * Test adjunct processor queue.
+ * @qid: the ap queue number
+ * @queue_depth: pointer to queue depth value
+ * @device_type: pointer to device type value
+ *
+ * Returns ap queue status structure.
+ */
+static inline struct ap_queue_status
+ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
+{
+ register unsigned long reg0 asm ("0") = qid;
+ register struct ap_queue_status reg1 asm ("1");
+ register unsigned long reg2 asm ("2") = 0UL;
+
+ asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
+ : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
+ *device_type = (int) (reg2 >> 24);
+ *queue_depth = (int) (reg2 & 0xff);
+ return reg1;
+}
+
+/**
+ * Reset adjunct processor queue.
+ * @qid: the ap queue number
+ *
+ * Returns ap queue status structure.
+ */
+static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid)
+{
+ register unsigned long reg0 asm ("0") = qid | 0x01000000UL;
+ register struct ap_queue_status reg1 asm ("1");
+ register unsigned long reg2 asm ("2") = 0UL;
+
+ asm volatile(
+ ".long 0xb2af0000" /* PQAP(RAPQ) */
+ : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
+ return reg1;
+}
+
+/**
+ * Send message to adjunct processor queue.
+ * @qid: the ap queue number
+ * @psmid: the program supplied message identifier
+ * @msg: the message text
+ * @length: the message length
+ *
+ * Returns ap queue status structure.
+ *
+ * Condition code 1 on NQAP can't happen because the L bit is 1.
+ *
+ * Condition code 2 on NQAP also means the send is incomplete,
+ * because a segment boundary was reached. The NQAP is repeated.
+ */
+static inline struct ap_queue_status
+__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+{
+ typedef struct { char _[length]; } msgblock;
+ register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
+ register struct ap_queue_status reg1 asm ("1");
+ register unsigned long reg2 asm ("2") = (unsigned long) msg;
+ register unsigned long reg3 asm ("3") = (unsigned long) length;
+ register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
+ register unsigned long reg5 asm ("5") = (unsigned int) psmid;
+
+ asm volatile (
+ "0: .long 0xb2ad0042\n" /* DQAP */
+ " brc 2,0b"
+ : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3)
+ : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg)
+ : "cc" );
+ return reg1;
+}
+
+int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
+{
+ struct ap_queue_status status;
+
+ status = __ap_send(qid, psmid, msg, length);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ return 0;
+ case AP_RESPONSE_Q_FULL:
+ return -EBUSY;
+ default: /* Device is gone. */
+ return -ENODEV;
+ }
+}
+EXPORT_SYMBOL(ap_send);
+
+/*
+ * Receive message from adjunct processor queue.
+ * @qid: the ap queue number
+ * @psmid: pointer to program supplied message identifier
+ * @msg: the message text
+ * @length: the message length
+ *
+ * Returns ap queue status structure.
+ *
+ * Condition code 1 on DQAP means the receive has taken place
+ * but only partially. The response is incomplete, hence the
+ * DQAP is repeated.
+ *
+ * Condition code 2 on DQAP also means the receive is incomplete,
+ * this time because a segment boundary was reached. Again, the
+ * DQAP is repeated.
+ *
+ * Note that gpr2 is used by the DQAP instruction to keep track of
+ * any 'residual' length, in case the instruction gets interrupted.
+ * Hence it gets zeroed before the instruction.
+ */
+static inline struct ap_queue_status
+__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
+{
+ typedef struct { char _[length]; } msgblock;
+ register unsigned long reg0 asm("0") = qid | 0x80000000UL;
+ register struct ap_queue_status reg1 asm ("1");
+ register unsigned long reg2 asm("2") = 0UL;
+ register unsigned long reg4 asm("4") = (unsigned long) msg;
+ register unsigned long reg5 asm("5") = (unsigned long) length;
+ register unsigned long reg6 asm("6") = 0UL;
+ register unsigned long reg7 asm("7") = 0UL;
+
+
+ asm volatile(
+ "0: .long 0xb2ae0064\n"
+ " brc 6,0b\n"
+ : "+d" (reg0), "=d" (reg1), "+d" (reg2),
+ "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7),
+ "=m" (*(msgblock *) msg) : : "cc" );
+ *psmid = (((unsigned long long) reg6) << 32) + reg7;
+ return reg1;
+}
+
+int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length)
+{
+ struct ap_queue_status status;
+
+ status = __ap_recv(qid, psmid, msg, length);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ return 0;
+ case AP_RESPONSE_NO_PENDING_REPLY:
+ if (status.queue_empty)
+ return -ENOENT;
+ return -EBUSY;
+ default:
+ return -ENODEV;
+ }
+}
+EXPORT_SYMBOL(ap_recv);
+
+/**
+ * Check if an AP queue is available. The test is repeated for
+ * AP_MAX_RESET times.
+ * @qid: the ap queue number
+ * @queue_depth: pointer to queue depth value
+ * @device_type: pointer to device type value
+ */
+static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type)
+{
+ struct ap_queue_status status;
+ int t_depth, t_device_type, rc, i;
+
+ rc = -EBUSY;
+ for (i = 0; i < AP_MAX_RESET; i++) {
+ status = ap_test_queue(qid, &t_depth, &t_device_type);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ *queue_depth = t_depth + 1;
+ *device_type = t_device_type;
+ rc = 0;
+ break;
+ case AP_RESPONSE_Q_NOT_AVAIL:
+ rc = -ENODEV;
+ break;
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ break;
+ case AP_RESPONSE_DECONFIGURED:
+ rc = -ENODEV;
+ break;
+ case AP_RESPONSE_CHECKSTOPPED:
+ rc = -ENODEV;
+ break;
+ case AP_RESPONSE_BUSY:
+ break;
+ default:
+ BUG();
+ }
+ if (rc != -EBUSY)
+ break;
+ if (i < AP_MAX_RESET - 1)
+ udelay(5);
+ }
+ return rc;
+}
+
+/**
+ * Reset an AP queue and wait for it to become available again.
+ * @qid: the ap queue number
+ */
+static int ap_init_queue(ap_qid_t qid)
+{
+ struct ap_queue_status status;
+ int rc, dummy, i;
+
+ rc = -ENODEV;
+ status = ap_reset_queue(qid);
+ for (i = 0; i < AP_MAX_RESET; i++) {
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ if (status.queue_empty)
+ rc = 0;
+ break;
+ case AP_RESPONSE_Q_NOT_AVAIL:
+ case AP_RESPONSE_DECONFIGURED:
+ case AP_RESPONSE_CHECKSTOPPED:
+ i = AP_MAX_RESET; /* return with -ENODEV */
+ break;
+ case AP_RESPONSE_RESET_IN_PROGRESS:
+ case AP_RESPONSE_BUSY:
+ default:
+ break;
+ }
+ if (rc != -ENODEV)
+ break;
+ if (i < AP_MAX_RESET - 1) {
+ udelay(5);
+ status = ap_test_queue(qid, &dummy, &dummy);
+ }
+ }
+ return rc;
+}
+
+/**
+ * AP device related attributes.
+ */
+static ssize_t ap_hwtype_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type);
+}
+static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL);
+
+static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth);
+}
+static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL);
+
+static ssize_t ap_request_count_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ int rc;
+
+ spin_lock_bh(&ap_dev->lock);
+ rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count);
+ spin_unlock_bh(&ap_dev->lock);
+ return rc;
+}
+
+static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL);
+
+static ssize_t ap_modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "ap:t%02X", to_ap_dev(dev)->device_type);
+}
+
+static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL);
+
+static struct attribute *ap_dev_attrs[] = {
+ &dev_attr_hwtype.attr,
+ &dev_attr_depth.attr,
+ &dev_attr_request_count.attr,
+ &dev_attr_modalias.attr,
+ NULL
+};
+static struct attribute_group ap_dev_attr_group = {
+ .attrs = ap_dev_attrs
+};
+
+/**
+ * AP bus driver registration/unregistration.
+ */
+static int ap_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ struct ap_driver *ap_drv = to_ap_drv(drv);
+ struct ap_device_id *id;
+
+ /**
+ * Compare device type of the device with the list of
+ * supported types of the device_driver.
+ */
+ for (id = ap_drv->ids; id->match_flags; id++) {
+ if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) &&
+ (id->dev_type != ap_dev->device_type))
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * uevent function for AP devices. It sets up a single environment
+ * variable DEV_TYPE which contains the hardware device type.
+ */
+static int ap_uevent (struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ int length;
+
+ if (!ap_dev)
+ return -ENODEV;
+
+ /* Set up DEV_TYPE environment variable. */
+ envp[0] = buffer;
+ length = scnprintf(buffer, buffer_size, "DEV_TYPE=%04X",
+ ap_dev->device_type);
+ if (buffer_size - length <= 0)
+ return -ENOMEM;
+ envp[1] = 0;
+ return 0;
+}
+
+static struct bus_type ap_bus_type = {
+ .name = "ap",
+ .match = &ap_bus_match,
+ .uevent = &ap_uevent,
+};
+
+static int ap_device_probe(struct device *dev)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ struct ap_driver *ap_drv = to_ap_drv(dev->driver);
+ int rc;
+
+ ap_dev->drv = ap_drv;
+ rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
+ if (rc)
+ ap_dev->unregistered = 1;
+ return rc;
+}
+
+/**
+ * Flush all requests from the request/pending queue of an AP device.
+ * @ap_dev: pointer to the AP device.
+ */
+static inline void __ap_flush_queue(struct ap_device *ap_dev)
+{
+ struct ap_message *ap_msg, *next;
+
+ list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) {
+ list_del_init(&ap_msg->list);
+ ap_dev->pendingq_count--;
+ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ }
+ list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) {
+ list_del_init(&ap_msg->list);
+ ap_dev->requestq_count--;
+ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ }
+}
+
+void ap_flush_queue(struct ap_device *ap_dev)
+{
+ spin_lock_bh(&ap_dev->lock);
+ __ap_flush_queue(ap_dev);
+ spin_unlock_bh(&ap_dev->lock);
+}
+EXPORT_SYMBOL(ap_flush_queue);
+
+static int ap_device_remove(struct device *dev)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ struct ap_driver *ap_drv = ap_dev->drv;
+
+ spin_lock_bh(&ap_dev->lock);
+ __ap_flush_queue(ap_dev);
+ /**
+ * set ->unregistered to 1 while holding the lock. This prevents
+ * new messages to be put on the queue from now on.
+ */
+ ap_dev->unregistered = 1;
+ spin_unlock_bh(&ap_dev->lock);
+ if (ap_drv->remove)
+ ap_drv->remove(ap_dev);
+ return 0;
+}
+
+int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
+ char *name)
+{
+ struct device_driver *drv = &ap_drv->driver;
+
+ drv->bus = &ap_bus_type;
+ drv->probe = ap_device_probe;
+ drv->remove = ap_device_remove;
+ drv->owner = owner;
+ drv->name = name;
+ return driver_register(drv);
+}
+EXPORT_SYMBOL(ap_driver_register);
+
+void ap_driver_unregister(struct ap_driver *ap_drv)
+{
+ driver_unregister(&ap_drv->driver);
+}
+EXPORT_SYMBOL(ap_driver_unregister);
+
+/**
+ * AP bus attributes.
+ */
+static ssize_t ap_domain_show(struct bus_type *bus, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index);
+}
+
+static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL);
+
+static ssize_t ap_config_time_show(struct bus_type *bus, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time);
+}
+
+static ssize_t ap_config_time_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ int time;
+
+ if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120)
+ return -EINVAL;
+ ap_config_time = time;
+ if (!timer_pending(&ap_config_timer) ||
+ !mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ)) {
+ ap_config_timer.expires = jiffies + ap_config_time * HZ;
+ add_timer(&ap_config_timer);
+ }
+ return count;
+}
+
+static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store);
+
+static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0);
+}
+
+static ssize_t ap_poll_thread_store(struct bus_type *bus,
+ const char *buf, size_t count)
+{
+ int flag, rc;
+
+ if (sscanf(buf, "%d\n", &flag) != 1)
+ return -EINVAL;
+ if (flag) {
+ rc = ap_poll_thread_start();
+ if (rc)
+ return rc;
+ }
+ else
+ ap_poll_thread_stop();
+ return count;
+}
+
+static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store);
+
+static struct bus_attribute *const ap_bus_attrs[] = {
+ &bus_attr_ap_domain,
+ &bus_attr_config_time,
+ &bus_attr_poll_thread,
+ NULL
+};
+
+/**
+ * Pick one of the 16 ap domains.
+ */
+static inline int ap_select_domain(void)
+{
+ int queue_depth, device_type, count, max_count, best_domain;
+ int rc, i, j;
+
+ /**
+ * We want to use a single domain. Either the one specified with
+ * the "domain=" parameter or the domain with the maximum number
+ * of devices.
+ */
+ if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS)
+ /* Domain has already been selected. */
+ return 0;
+ best_domain = -1;
+ max_count = 0;
+ for (i = 0; i < AP_DOMAINS; i++) {
+ count = 0;
+ for (j = 0; j < AP_DEVICES; j++) {
+ ap_qid_t qid = AP_MKQID(j, i);
+ rc = ap_query_queue(qid, &queue_depth, &device_type);
+ if (rc)
+ continue;
+ count++;
+ }
+ if (count > max_count) {
+ max_count = count;
+ best_domain = i;
+ }
+ }
+ if (best_domain >= 0){
+ ap_domain_index = best_domain;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+/**
+ * Find the device type if query queue returned a device type of 0.
+ * @ap_dev: pointer to the AP device.
+ */
+static int ap_probe_device_type(struct ap_device *ap_dev)
+{
+ static unsigned char msg[] = {
+ 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x01,0x00,0x43,0x43,0x41,0x2d,0x41,0x50,
+ 0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,
+ 0x00,0x00,0x00,0x00,0x50,0x4b,0x00,0x00,
+ 0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x54,0x32,0x01,0x00,0xa0,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0xb8,0x05,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,
+ 0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20,
+ 0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,
+ 0x2d,0x31,0x2e,0x32,0x37,0x00,0x11,0x22,
+ 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
+ 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,
+ 0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
+ 0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
+ 0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,
+ 0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
+ 0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,
+ 0x88,0x1e,0x00,0x00,0x57,0x00,0x00,0x00,
+ 0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,
+ 0x03,0x02,0x00,0x00,0x40,0x01,0x00,0x01,
+ 0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,
+ 0xf6,0xd2,0x7b,0x58,0x4b,0xf9,0x28,0x68,
+ 0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,
+ 0x63,0x42,0xef,0xf8,0xfd,0xa4,0xf8,0xb0,
+ 0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,
+ 0x53,0x8c,0x6f,0x4e,0x72,0x8f,0x6c,0x04,
+ 0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,
+ 0xf7,0xdd,0xfd,0x4f,0x11,0x36,0x95,0x5d,
+ };
+ struct ap_queue_status status;
+ unsigned long long psmid;
+ char *reply;
+ int rc, i;
+
+ reply = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!reply) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
+ msg, sizeof(msg));
+ if (status.response_code != AP_RESPONSE_NORMAL) {
+ rc = -ENODEV;
+ goto out_free;
+ }
+
+ /* Wait for the test message to complete. */
+ for (i = 0; i < 6; i++) {
+ mdelay(300);
+ status = __ap_recv(ap_dev->qid, &psmid, reply, 4096);
+ if (status.response_code == AP_RESPONSE_NORMAL &&
+ psmid == 0x0102030405060708ULL)
+ break;
+ }
+ if (i < 6) {
+ /* Got an answer. */
+ if (reply[0] == 0x00 && reply[1] == 0x86)
+ ap_dev->device_type = AP_DEVICE_TYPE_PCICC;
+ else
+ ap_dev->device_type = AP_DEVICE_TYPE_PCICA;
+ rc = 0;
+ } else
+ rc = -ENODEV;
+
+out_free:
+ free_page((unsigned long) reply);
+out:
+ return rc;
+}
+
+/**
+ * Scan the ap bus for new devices.
+ */
+static int __ap_scan_bus(struct device *dev, void *data)
+{
+ return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data;
+}
+
+static void ap_device_release(struct device *dev)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+
+ kfree(ap_dev);
+}
+
+static void ap_scan_bus(void *data)
+{
+ struct ap_device *ap_dev;
+ struct device *dev;
+ ap_qid_t qid;
+ int queue_depth, device_type;
+ int rc, i;
+
+ if (ap_select_domain() != 0)
+ return;
+ for (i = 0; i < AP_DEVICES; i++) {
+ qid = AP_MKQID(i, ap_domain_index);
+ dev = bus_find_device(&ap_bus_type, NULL,
+ (void *)(unsigned long)qid,
+ __ap_scan_bus);
+ if (dev) {
+ put_device(dev);
+ continue;
+ }
+ rc = ap_query_queue(qid, &queue_depth, &device_type);
+ if (rc)
+ continue;
+ rc = ap_init_queue(qid);
+ if (rc)
+ continue;
+ ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL);
+ if (!ap_dev)
+ break;
+ ap_dev->qid = qid;
+ ap_dev->queue_depth = queue_depth;
+ spin_lock_init(&ap_dev->lock);
+ INIT_LIST_HEAD(&ap_dev->pendingq);
+ INIT_LIST_HEAD(&ap_dev->requestq);
+ if (device_type == 0)
+ ap_probe_device_type(ap_dev);
+ else
+ ap_dev->device_type = device_type;
+
+ ap_dev->device.bus = &ap_bus_type;
+ ap_dev->device.parent = ap_root_device;
+ snprintf(ap_dev->device.bus_id, BUS_ID_SIZE, "card%02x",
+ AP_QID_DEVICE(ap_dev->qid));
+ ap_dev->device.release = ap_device_release;
+ rc = device_register(&ap_dev->device);
+ if (rc) {
+ kfree(ap_dev);
+ continue;
+ }
+ /* Add device attributes. */
+ rc = sysfs_create_group(&ap_dev->device.kobj,
+ &ap_dev_attr_group);
+ if (rc)
+ device_unregister(&ap_dev->device);
+ }
+}
+
+static void
+ap_config_timeout(unsigned long ptr)
+{
+ queue_work(ap_work_queue, &ap_config_work);
+ ap_config_timer.expires = jiffies + ap_config_time * HZ;
+ add_timer(&ap_config_timer);
+}
+
+/**
+ * Set up the timer to run the poll tasklet
+ */
+static inline void ap_schedule_poll_timer(void)
+{
+ if (timer_pending(&ap_poll_timer))
+ return;
+ mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME);
+}
+
+/**
+ * Receive pending reply messages from an AP device.
+ * @ap_dev: pointer to the AP device
+ * @flags: pointer to control flags, bit 2^0 is set if another poll is
+ * required, bit 2^1 is set if the poll timer needs to get armed
+ * Returns 0 if the device is still present, -ENODEV if not.
+ */
+static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+{
+ struct ap_queue_status status;
+ struct ap_message *ap_msg;
+
+ if (ap_dev->queue_count <= 0)
+ return 0;
+ status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid,
+ ap_dev->reply->message, ap_dev->reply->length);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ atomic_dec(&ap_poll_requests);
+ ap_dev->queue_count--;
+ list_for_each_entry(ap_msg, &ap_dev->pendingq, list) {
+ if (ap_msg->psmid != ap_dev->reply->psmid)
+ continue;
+ list_del_init(&ap_msg->list);
+ ap_dev->pendingq_count--;
+ ap_dev->drv->receive(ap_dev, ap_msg, ap_dev->reply);
+ break;
+ }
+ if (ap_dev->queue_count > 0)
+ *flags |= 1;
+ break;
+ case AP_RESPONSE_NO_PENDING_REPLY:
+ if (status.queue_empty) {
+ /* The card shouldn't forget requests but who knows. */
+ ap_dev->queue_count = 0;
+ list_splice_init(&ap_dev->pendingq, &ap_dev->requestq);
+ ap_dev->requestq_count += ap_dev->pendingq_count;
+ ap_dev->pendingq_count = 0;
+ } else
+ *flags |= 2;
+ break;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * Send messages from the request queue to an AP device.
+ * @ap_dev: pointer to the AP device
+ * @flags: pointer to control flags, bit 2^0 is set if another poll is
+ * required, bit 2^1 is set if the poll timer needs to get armed
+ * Returns 0 if the device is still present, -ENODEV if not.
+ */
+static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+{
+ struct ap_queue_status status;
+ struct ap_message *ap_msg;
+
+ if (ap_dev->requestq_count <= 0 ||
+ ap_dev->queue_count >= ap_dev->queue_depth)
+ return 0;
+ /* Start the next request on the queue. */
+ ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
+ status = __ap_send(ap_dev->qid, ap_msg->psmid,
+ ap_msg->message, ap_msg->length);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ atomic_inc(&ap_poll_requests);
+ ap_dev->queue_count++;
+ list_move_tail(&ap_msg->list, &ap_dev->pendingq);
+ ap_dev->requestq_count--;
+ ap_dev->pendingq_count++;
+ if (ap_dev->queue_count < ap_dev->queue_depth &&
+ ap_dev->requestq_count > 0)
+ *flags |= 1;
+ *flags |= 2;
+ break;
+ case AP_RESPONSE_Q_FULL:
+ *flags |= 2;
+ break;
+ case AP_RESPONSE_MESSAGE_TOO_BIG:
+ return -EINVAL;
+ default:
+ return -ENODEV;
+ }
+ return 0;
+}
+
+/**
+ * Poll AP device for pending replies and send new messages. If either
+ * ap_poll_read or ap_poll_write returns -ENODEV unregister the device.
+ * @ap_dev: pointer to the bus device
+ * @flags: pointer to control flags, bit 2^0 is set if another poll is
+ * required, bit 2^1 is set if the poll timer needs to get armed
+ * Returns 0.
+ */
+static inline int ap_poll_queue(struct ap_device *ap_dev, unsigned long *flags)
+{
+ int rc;
+
+ rc = ap_poll_read(ap_dev, flags);
+ if (rc)
+ return rc;
+ return ap_poll_write(ap_dev, flags);
+}
+
+/**
+ * Queue a message to a device.
+ * @ap_dev: pointer to the AP device
+ * @ap_msg: the message to be queued
+ */
+static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
+{
+ struct ap_queue_status status;
+
+ if (list_empty(&ap_dev->requestq) &&
+ ap_dev->queue_count < ap_dev->queue_depth) {
+ status = __ap_send(ap_dev->qid, ap_msg->psmid,
+ ap_msg->message, ap_msg->length);
+ switch (status.response_code) {
+ case AP_RESPONSE_NORMAL:
+ list_add_tail(&ap_msg->list, &ap_dev->pendingq);
+ atomic_inc(&ap_poll_requests);
+ ap_dev->pendingq_count++;
+ ap_dev->queue_count++;
+ ap_dev->total_request_count++;
+ break;
+ case AP_RESPONSE_Q_FULL:
+ list_add_tail(&ap_msg->list, &ap_dev->requestq);
+ ap_dev->requestq_count++;
+ ap_dev->total_request_count++;
+ return -EBUSY;
+ case AP_RESPONSE_MESSAGE_TOO_BIG:
+ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
+ return -EINVAL;
+ default: /* Device is gone. */
+ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ return -ENODEV;
+ }
+ } else {
+ list_add_tail(&ap_msg->list, &ap_dev->requestq);
+ ap_dev->requestq_count++;
+ ap_dev->total_request_count++;
+ return -EBUSY;
+ }
+ ap_schedule_poll_timer();
+ return 0;
+}
+
+void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
+{
+ unsigned long flags;
+ int rc;
+
+ spin_lock_bh(&ap_dev->lock);
+ if (!ap_dev->unregistered) {
+ /* Make room on the queue by polling for finished requests. */
+ rc = ap_poll_queue(ap_dev, &flags);
+ if (!rc)
+ rc = __ap_queue_message(ap_dev, ap_msg);
+ if (!rc)
+ wake_up(&ap_poll_wait);
+ } else {
+ ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
+ rc = 0;
+ }
+ spin_unlock_bh(&ap_dev->lock);
+ if (rc == -ENODEV)
+ device_unregister(&ap_dev->device);
+}
+EXPORT_SYMBOL(ap_queue_message);
+
+/**
+ * Cancel a crypto request. This is done by removing the request
+ * from the devive pendingq or requestq queue. Note that the
+ * request stays on the AP queue. When it finishes the message
+ * reply will be discarded because the psmid can't be found.
+ * @ap_dev: AP device that has the message queued
+ * @ap_msg: the message that is to be removed
+ */
+void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
+{
+ struct ap_message *tmp;
+
+ spin_lock_bh(&ap_dev->lock);
+ if (!list_empty(&ap_msg->list)) {
+ list_for_each_entry(tmp, &ap_dev->pendingq, list)
+ if (tmp->psmid == ap_msg->psmid) {
+ ap_dev->pendingq_count--;
+ goto found;
+ }
+ ap_dev->requestq_count--;
+ found:
+ list_del_init(&ap_msg->list);
+ }
+ spin_unlock_bh(&ap_dev->lock);
+}
+EXPORT_SYMBOL(ap_cancel_message);
+
+/**
+ * AP receive polling for finished AP requests
+ */
+static void ap_poll_timeout(unsigned long unused)
+{
+ tasklet_schedule(&ap_tasklet);
+}
+
+/**
+ * Poll all AP devices on the bus in a round robin fashion. Continue
+ * polling until bit 2^0 of the control flags is not set. If bit 2^1
+ * of the control flags has been set arm the poll timer.
+ */
+static int __ap_poll_all(struct device *dev, void *data)
+{
+ struct ap_device *ap_dev = to_ap_dev(dev);
+ int rc;
+
+ spin_lock(&ap_dev->lock);
+ if (!ap_dev->unregistered) {
+ rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data);
+ } else
+ rc = 0;
+ spin_unlock(&ap_dev->lock);
+ if (rc)
+ device_unregister(&ap_dev->device);
+ return 0;
+}
+
+static void ap_poll_all(unsigned long dummy)
+{
+ unsigned long flags;
+
+ do {
+ flags = 0;
+ bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
+ } while (flags & 1);
+ if (flags & 2)
+ ap_schedule_poll_timer();
+}
+
+/**
+ * AP bus poll thread. The purpose of this thread is to poll for
+ * finished requests in a loop if there is a "free" cpu - that is
+ * a cpu that doesn't have anything better to do. The polling stops
+ * as soon as there is another task or if all messages have been
+ * delivered.
+ */
+static int ap_poll_thread(void *data)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ unsigned long flags;
+ int requests;
+
+ set_user_nice(current, -20);
+ while (1) {
+ if (need_resched()) {
+ schedule();
+ continue;
+ }
+ add_wait_queue(&ap_poll_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (kthread_should_stop())
+ break;
+ requests = atomic_read(&ap_poll_requests);
+ if (requests <= 0)
+ schedule();
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ap_poll_wait, &wait);
+
+ local_bh_disable();
+ flags = 0;
+ bus_for_each_dev(&ap_bus_type, NULL, &flags, __ap_poll_all);
+ local_bh_enable();
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ap_poll_wait, &wait);
+ return 0;
+}
+
+static int ap_poll_thread_start(void)
+{
+ int rc;
+
+ mutex_lock(&ap_poll_thread_mutex);
+ if (!ap_poll_kthread) {
+ ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll");
+ rc = IS_ERR(ap_poll_kthread) ? PTR_ERR(ap_poll_kthread) : 0;
+ if (rc)
+ ap_poll_kthread = NULL;
+ }
+ else
+ rc = 0;
+ mutex_unlock(&ap_poll_thread_mutex);
+ return rc;
+}
+
+static void ap_poll_thread_stop(void)
+{
+ mutex_lock(&ap_poll_thread_mutex);
+ if (ap_poll_kthread) {
+ kthread_stop(ap_poll_kthread);
+ ap_poll_kthread = NULL;
+ }
+ mutex_unlock(&ap_poll_thread_mutex);
+}
+
+/**
+ * The module initialization code.
+ */
+int __init ap_module_init(void)
+{
+ int rc, i;
+
+ if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) {
+ printk(KERN_WARNING "Invalid param: domain = %d. "
+ " Not loading.\n", ap_domain_index);
+ return -EINVAL;
+ }
+ if (ap_instructions_available() != 0) {
+ printk(KERN_WARNING "AP instructions not installed.\n");
+ return -ENODEV;
+ }
+
+ /* Create /sys/bus/ap. */
+ rc = bus_register(&ap_bus_type);
+ if (rc)
+ goto out;
+ for (i = 0; ap_bus_attrs[i]; i++) {
+ rc = bus_create_file(&ap_bus_type, ap_bus_attrs[i]);
+ if (rc)
+ goto out_bus;
+ }
+
+ /* Create /sys/devices/ap. */
+ ap_root_device = s390_root_dev_register("ap");
+ rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0;
+ if (rc)
+ goto out_bus;
+
+ ap_work_queue = create_singlethread_workqueue("kapwork");
+ if (!ap_work_queue) {
+ rc = -ENOMEM;
+ goto out_root;
+ }
+
+ if (ap_select_domain() == 0)
+ ap_scan_bus(NULL);
+
+ /* Setup the ap bus rescan timer. */
+ init_timer(&ap_config_timer);
+ ap_config_timer.function = ap_config_timeout;
+ ap_config_timer.data = 0;
+ ap_config_timer.expires = jiffies + ap_config_time * HZ;
+ add_timer(&ap_config_timer);
+
+ /* Start the low priority AP bus poll thread. */
+ if (ap_thread_flag) {
+ rc = ap_poll_thread_start();
+ if (rc)
+ goto out_work;
+ }
+
+ return 0;
+
+out_work:
+ del_timer_sync(&ap_config_timer);
+ del_timer_sync(&ap_poll_timer);
+ destroy_workqueue(ap_work_queue);
+out_root:
+ s390_root_dev_unregister(ap_root_device);
+out_bus:
+ while (i--)
+ bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
+ bus_unregister(&ap_bus_type);
+out:
+ return rc;
+}
+
+static int __ap_match_all(struct device *dev, void *data)
+{
+ return 1;
+}
+
+/**
+ * The module termination code
+ */
+void ap_module_exit(void)
+{
+ int i;
+ struct device *dev;
+
+ ap_poll_thread_stop();
+ del_timer_sync(&ap_config_timer);
+ del_timer_sync(&ap_poll_timer);
+ destroy_workqueue(ap_work_queue);
+ s390_root_dev_unregister(ap_root_device);
+ while ((dev = bus_find_device(&ap_bus_type, NULL, NULL,
+ __ap_match_all)))
+ {
+ device_unregister(dev);
+ put_device(dev);
+ }
+ for (i = 0; ap_bus_attrs[i]; i++)
+ bus_remove_file(&ap_bus_type, ap_bus_attrs[i]);
+ bus_unregister(&ap_bus_type);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(ap_module_init);
+module_exit(ap_module_exit);
+#endif
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
new file mode 100644
index 00000000000..83b69c01cd6
--- /dev/null
+++ b/drivers/s390/crypto/ap_bus.h
@@ -0,0 +1,158 @@
+/*
+ * linux/drivers/s390/crypto/ap_bus.h
+ *
+ * Copyright (C) 2006 IBM Corporation
+ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
+ * Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * Adjunct processor bus header file.
+ *
+ * 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, 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 _AP_BUS_H_
+#define _AP_BUS_H_
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/types.h>
+
+#define AP_DEVICES 64 /* Number of AP devices. */
+#define AP_DOMAINS 16 /* Number of AP domains. */
+#define AP_MAX_RESET 90 /* Maximum number of resets. */
+#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
+#define AP_POLL_TIME 1 /* Time in ticks between receive polls. */
+
+extern int ap_domain_index;
+
+/**
+ * The ap_qid_t identifier of an ap queue. It contains a
+ * 6 bit device index and a 4 bit queue index (domain).
+ */
+typedef unsigned int ap_qid_t;
+
+#define AP_MKQID(_device,_queue) (((_device) & 63) << 8 | ((_queue) & 15))
+#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63)
+#define AP_QID_QUEUE(_qid) ((_qid) & 15)
+
+/**
+ * The ap queue status word is returned by all three AP functions
+ * (PQAP, NQAP and DQAP). There's a set of flags in the first
+ * byte, followed by a 1 byte response code.
+ */
+struct ap_queue_status {
+ unsigned int queue_empty : 1;
+ unsigned int replies_waiting : 1;
+ unsigned int queue_full : 1;
+ unsigned int pad1 : 5;
+ unsigned int response_code : 8;
+ unsigned int pad2 : 16;
+};
+
+#define AP_RESPONSE_NORMAL 0x00
+#define AP_RESPONSE_Q_NOT_AVAIL 0x01
+#define AP_RESPONSE_RESET_IN_PROGRESS 0x02
+#define AP_RESPONSE_DECONFIGURED 0x03
+#define AP_RESPONSE_CHECKSTOPPED 0x04
+#define AP_RESPONSE_BUSY 0x05
+#define AP_RESPONSE_Q_FULL 0x10
+#define AP_RESPONSE_NO_PENDING_REPLY 0x10
+#define AP_RESPONSE_INDEX_TOO_BIG 0x11
+#define AP_RESPONSE_NO_FIRST_PART 0x13
+#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
+
+/**
+ * Known device types
+ */
+#define AP_DEVICE_TYPE_PCICC 3
+#define AP_DEVICE_TYPE_PCICA 4
+#define AP_DEVICE_TYPE_PCIXCC 5
+#define AP_DEVICE_TYPE_CEX2A 6
+#define AP_DEVICE_TYPE_CEX2C 7
+
+struct ap_device;
+struct ap_message;
+
+struct ap_driver {
+ struct device_driver driver;
+ struct ap_device_id *ids;
+
+ int (*probe)(struct ap_device *);
+ void (*remove)(struct ap_device *);
+ /* receive is called from tasklet context */
+ void (*receive)(struct ap_device *, struct ap_message *,
+ struct ap_message *);
+};
+
+#define to_ap_drv(x) container_of((x), struct ap_driver, driver)
+
+int ap_driver_register(struct ap_driver *, struct module *, char *);
+void ap_driver_unregister(struct ap_driver *);
+
+struct ap_device {
+ struct device device;
+ struct ap_driver *drv; /* Pointer to AP device driver. */
+ spinlock_t lock; /* Per device lock. */
+
+ ap_qid_t qid; /* AP queue id. */
+ int queue_depth; /* AP queue depth.*/
+ int device_type; /* AP device type. */
+ int unregistered; /* marks AP device as unregistered */
+
+ int queue_count; /* # messages currently on AP queue. */
+
+ struct list_head pendingq; /* List of message sent to AP queue. */
+ int pendingq_count; /* # requests on pendingq list. */
+ struct list_head requestq; /* List of message yet to be sent. */
+ int requestq_count; /* # requests on requestq list. */
+ int total_request_count; /* # requests ever for this AP device. */
+
+ struct ap_message *reply; /* Per device reply message. */
+
+ void *private; /* ap driver private pointer. */
+};
+
+#define to_ap_dev(x) container_of((x), struct ap_device, device)
+
+struct ap_message {
+ struct list_head list; /* Request queueing. */
+ unsigned long long psmid; /* Message id. */
+ void *message; /* Pointer to message buffer. */
+ size_t length; /* Message length. */
+
+ void *private; /* ap driver private pointer. */
+};
+
+#define AP_DEVICE(dt) \
+ .dev_type=(dt), \
+ .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,
+
+/**
+ * Note: don't use ap_send/ap_recv after using ap_queue_message
+ * for the first time. Otherwise the ap message queue will get
+ * confused.
+ */
+int ap_send(ap_qid_t, unsigned long long, void *, size_t);
+int ap_recv(ap_qid_t, unsigned long long *, void *, size_t);
+
+void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
+void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg);
+void ap_flush_queue(struct ap_device *ap_dev);
+
+int ap_module_init(void);
+void ap_module_exit(void);
+
+#endif /* _AP_BUS_H_ */
diff --git a/drivers/s390/crypto/z90common.h b/drivers/s390/crypto/z90common.h
deleted file mode 100644
index dbbcda3c846..00000000000
--- a/drivers/s390/crypto/z90common.h
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * linux/drivers/s390/crypto/z90common.h
- *
- * z90crypt 1.3.3
- *
- * Copyright (C) 2001, 2005 IBM Corporation
- * Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 _Z90COMMON_H_
-#define _Z90COMMON_H_
-
-
-#define RESPBUFFSIZE 256
-#define PCI_FUNC_KEY_DECRYPT 0x5044
-#define PCI_FUNC_KEY_ENCRYPT 0x504B
-extern int ext_bitlens;
-
-enum devstat {
- DEV_GONE,
- DEV_ONLINE,
- DEV_QUEUE_FULL,
- DEV_EMPTY,
- DEV_NO_WORK,
- DEV_BAD_MESSAGE,
- DEV_TSQ_EXCEPTION,
- DEV_RSQ_EXCEPTION,
- DEV_SEN_EXCEPTION,
- DEV_REC_EXCEPTION
-};
-
-enum hdstat {
- HD_NOT_THERE,
- HD_BUSY,
- HD_DECONFIGURED,
- HD_CHECKSTOPPED,
- HD_ONLINE,
- HD_TSQ_EXCEPTION
-};
-
-#define Z90C_NO_DEVICES 1
-#define Z90C_AMBIGUOUS_DOMAIN 2
-#define Z90C_INCORRECT_DOMAIN 3
-#define ENOTINIT 4
-
-#define SEN_BUSY 7
-#define SEN_USER_ERROR 8
-#define SEN_QUEUE_FULL 11
-#define SEN_NOT_AVAIL 16
-#define SEN_PAD_ERROR 17
-#define SEN_RETRY 18
-#define SEN_RELEASED 24
-
-#define REC_EMPTY 4
-#define REC_BUSY 6
-#define REC_OPERAND_INV 8
-#define REC_OPERAND_SIZE 9
-#define REC_EVEN_MOD 10
-#define REC_NO_WORK 11
-#define REC_HARDWAR_ERR 12
-#define REC_NO_RESPONSE 13
-#define REC_RETRY_DEV 14
-#define REC_USER_GONE 15
-#define REC_BAD_MESSAGE 16
-#define REC_INVALID_PAD 17
-#define REC_USE_PCICA 18
-
-#define WRONG_DEVICE_TYPE 20
-
-#define REC_FATAL_ERROR 32
-#define SEN_FATAL_ERROR 33
-#define TSQ_FATAL_ERROR 34
-#define RSQ_FATAL_ERROR 35
-
-#define Z90CRYPT_NUM_TYPES 6
-#define PCICA 0
-#define PCICC 1
-#define PCIXCC_MCL2 2
-#define PCIXCC_MCL3 3
-#define CEX2C 4
-#define CEX2A 5
-#define NILDEV -1
-#define ANYDEV -1
-#define PCIXCC_UNK -2
-
-enum hdevice_type {
- PCICC_HW = 3,
- PCICA_HW = 4,
- PCIXCC_HW = 5,
- CEX2A_HW = 6,
- CEX2C_HW = 7
-};
-
-struct CPRBX {
- unsigned short cprb_len;
- unsigned char cprb_ver_id;
- unsigned char pad_000[3];
- unsigned char func_id[2];
- unsigned char cprb_flags[4];
- unsigned int req_parml;
- unsigned int req_datal;
- unsigned int rpl_msgbl;
- unsigned int rpld_parml;
- unsigned int rpl_datal;
- unsigned int rpld_datal;
- unsigned int req_extbl;
- unsigned char pad_001[4];
- unsigned int rpld_extbl;
- unsigned char req_parmb[16];
- unsigned char req_datab[16];
- unsigned char rpl_parmb[16];
- unsigned char rpl_datab[16];
- unsigned char req_extb[16];
- unsigned char rpl_extb[16];
- unsigned short ccp_rtcode;
- unsigned short ccp_rscode;
- unsigned int mac_data_len;
- unsigned char logon_id[8];
- unsigned char mac_value[8];
- unsigned char mac_content_flgs;
- unsigned char pad_002;
- unsigned short domain;
- unsigned char pad_003[12];
- unsigned char pad_004[36];
-};
-
-#ifndef DEV_NAME
-#define DEV_NAME "z90crypt"
-#endif
-#define PRINTK(fmt, args...) \
- printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
-#define PRINTKN(fmt, args...) \
- printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
-#define PRINTKW(fmt, args...) \
- printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
-#define PRINTKC(fmt, args...) \
- printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
-
-#ifdef Z90CRYPT_DEBUG
-#define PDEBUG(fmt, args...) \
- printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
-#else
-#define PDEBUG(fmt, args...) do {} while (0)
-#endif
-
-#define UMIN(a,b) ((a) < (b) ? (a) : (b))
-#define IS_EVEN(x) ((x) == (2 * ((x) / 2)))
-
-#endif
diff --git a/drivers/s390/crypto/z90crypt.h b/drivers/s390/crypto/z90crypt.h
deleted file mode 100644
index 0ca1d126ccb..00000000000
--- a/drivers/s390/crypto/z90crypt.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * linux/drivers/s390/crypto/z90crypt.h
- *
- * z90crypt 1.3.3 (kernel-private header)
- *
- * Copyright (C) 2001, 2005 IBM Corporation
- * Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 _Z90CRYPT_H_
-#define _Z90CRYPT_H_
-
-#include <asm/z90crypt.h>
-
-/**
- * local errno definitions
- */
-#define ENOBUFF 129 // filp->private_data->...>work_elem_p->buffer is NULL
-#define EWORKPEND 130 // user issues ioctl while another pending
-#define ERELEASED 131 // user released while ioctl pending
-#define EQUIESCE 132 // z90crypt quiescing (no more work allowed)
-#define ETIMEOUT 133 // request timed out
-#define EUNKNOWN 134 // some unrecognized error occured (retry may succeed)
-#define EGETBUFF 135 // Error getting buffer or hardware lacks capability
- // (retry in software)
-
-/**
- * DEPRECATED STRUCTURES
- */
-
-/**
- * This structure is DEPRECATED and the corresponding ioctl() has been
- * replaced with individual ioctl()s for each piece of data!
- * This structure will NOT survive past version 1.3.1, so switch to the
- * new ioctl()s.
- */
-#define MASK_LENGTH 64 // mask length
-struct ica_z90_status {
- int totalcount;
- int leedslitecount; // PCICA
- int leeds2count; // PCICC
- // int PCIXCCCount; is not in struct for backward compatibility
- int requestqWaitCount;
- int pendingqWaitCount;
- int totalOpenCount;
- int cryptoDomain;
- // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3,
- // 5=CEX2C
- unsigned char status[MASK_LENGTH];
- // qdepth: # work elements waiting for each device
- unsigned char qdepth[MASK_LENGTH];
-};
-
-#endif /* _Z90CRYPT_H_ */
diff --git a/drivers/s390/crypto/z90hardware.c b/drivers/s390/crypto/z90hardware.c
deleted file mode 100644
index be60795f4a7..00000000000
--- a/drivers/s390/crypto/z90hardware.c
+++ /dev/null
@@ -1,2531 +0,0 @@
-/*
- * linux/drivers/s390/crypto/z90hardware.c
- *
- * z90crypt 1.3.3
- *
- * Copyright (C) 2001, 2005 IBM Corporation
- * Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 <asm/uaccess.h>
-#include <linux/compiler.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include "z90crypt.h"
-#include "z90common.h"
-
-struct cca_token_hdr {
- unsigned char token_identifier;
- unsigned char version;
- unsigned short token_length;
- unsigned char reserved[4];
-};
-
-#define CCA_TKN_HDR_ID_EXT 0x1E
-
-struct cca_private_ext_ME_sec {
- unsigned char section_identifier;
- unsigned char version;
- unsigned short section_length;
- unsigned char private_key_hash[20];
- unsigned char reserved1[4];
- unsigned char key_format;
- unsigned char reserved2;
- unsigned char key_name_hash[20];
- unsigned char key_use_flags[4];
- unsigned char reserved3[6];
- unsigned char reserved4[24];
- unsigned char confounder[24];
- unsigned char exponent[128];
- unsigned char modulus[128];
-};
-
-#define CCA_PVT_USAGE_ALL 0x80
-
-struct cca_public_sec {
- unsigned char section_identifier;
- unsigned char version;
- unsigned short section_length;
- unsigned char reserved[2];
- unsigned short exponent_len;
- unsigned short modulus_bit_len;
- unsigned short modulus_byte_len;
- unsigned char exponent[3];
-};
-
-struct cca_private_ext_ME {
- struct cca_token_hdr pvtMEHdr;
- struct cca_private_ext_ME_sec pvtMESec;
- struct cca_public_sec pubMESec;
-};
-
-struct cca_public_key {
- struct cca_token_hdr pubHdr;
- struct cca_public_sec pubSec;
-};
-
-struct cca_pvt_ext_CRT_sec {
- unsigned char section_identifier;
- unsigned char version;
- unsigned short section_length;
- unsigned char private_key_hash[20];
- unsigned char reserved1[4];
- unsigned char key_format;
- unsigned char reserved2;
- unsigned char key_name_hash[20];
- unsigned char key_use_flags[4];
- unsigned short p_len;
- unsigned short q_len;
- unsigned short dp_len;
- unsigned short dq_len;
- unsigned short u_len;
- unsigned short mod_len;
- unsigned char reserved3[4];
- unsigned short pad_len;
- unsigned char reserved4[52];
- unsigned char confounder[8];
-};
-
-#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
-#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
-
-struct cca_private_ext_CRT {
- struct cca_token_hdr pvtCrtHdr;
- struct cca_pvt_ext_CRT_sec pvtCrtSec;
- struct cca_public_sec pubCrtSec;
-};
-
-struct ap_status_word {
- unsigned char q_stat_flags;
- unsigned char response_code;
- unsigned char reserved[2];
-};
-
-#define AP_Q_STATUS_EMPTY 0x80
-#define AP_Q_STATUS_REPLIES_WAITING 0x40
-#define AP_Q_STATUS_ARRAY_FULL 0x20
-
-#define AP_RESPONSE_NORMAL 0x00
-#define AP_RESPONSE_Q_NOT_AVAIL 0x01
-#define AP_RESPONSE_RESET_IN_PROGRESS 0x02
-#define AP_RESPONSE_DECONFIGURED 0x03
-#define AP_RESPONSE_CHECKSTOPPED 0x04
-#define AP_RESPONSE_BUSY 0x05
-#define AP_RESPONSE_Q_FULL 0x10
-#define AP_RESPONSE_NO_PENDING_REPLY 0x10
-#define AP_RESPONSE_INDEX_TOO_BIG 0x11
-#define AP_RESPONSE_NO_FIRST_PART 0x13
-#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
-
-#define AP_MAX_CDX_BITL 4
-#define AP_RQID_RESERVED_BITL 4
-#define SKIP_BITL (AP_MAX_CDX_BITL + AP_RQID_RESERVED_BITL)
-
-struct type4_hdr {
- unsigned char reserved1;
- unsigned char msg_type_code;
- unsigned short msg_len;
- unsigned char request_code;
- unsigned char msg_fmt;
- unsigned short reserved2;
-};
-
-#define TYPE4_TYPE_CODE 0x04
-#define TYPE4_REQU_CODE 0x40
-
-#define TYPE4_SME_LEN 0x0188
-#define TYPE4_LME_LEN 0x0308
-#define TYPE4_SCR_LEN 0x01E0
-#define TYPE4_LCR_LEN 0x03A0
-
-#define TYPE4_SME_FMT 0x00
-#define TYPE4_LME_FMT 0x10
-#define TYPE4_SCR_FMT 0x40
-#define TYPE4_LCR_FMT 0x50
-
-struct type4_sme {
- struct type4_hdr header;
- unsigned char message[128];
- unsigned char exponent[128];
- unsigned char modulus[128];
-};
-
-struct type4_lme {
- struct type4_hdr header;
- unsigned char message[256];
- unsigned char exponent[256];
- unsigned char modulus[256];
-};
-
-struct type4_scr {
- struct type4_hdr header;
- unsigned char message[128];
- unsigned char dp[72];
- unsigned char dq[64];
- unsigned char p[72];
- unsigned char q[64];
- unsigned char u[72];
-};
-
-struct type4_lcr {
- struct type4_hdr header;
- unsigned char message[256];
- unsigned char dp[136];
- unsigned char dq[128];
- unsigned char p[136];
- unsigned char q[128];
- unsigned char u[136];
-};
-
-union type4_msg {
- struct type4_sme sme;
- struct type4_lme lme;
- struct type4_scr scr;
- struct type4_lcr lcr;
-};
-
-struct type84_hdr {
- unsigned char reserved1;
- unsigned char code;
- unsigned short len;
- unsigned char reserved2[4];
-};
-
-#define TYPE84_RSP_CODE 0x84
-
-struct type6_hdr {
- unsigned char reserved1;
- unsigned char type;
- unsigned char reserved2[2];
- unsigned char right[4];
- unsigned char reserved3[2];
- unsigned char reserved4[2];
- unsigned char apfs[4];
- unsigned int offset1;
- unsigned int offset2;
- unsigned int offset3;
- unsigned int offset4;
- unsigned char agent_id[16];
- unsigned char rqid[2];
- unsigned char reserved5[2];
- unsigned char function_code[2];
- unsigned char reserved6[2];
- unsigned int ToCardLen1;
- unsigned int ToCardLen2;
- unsigned int ToCardLen3;
- unsigned int ToCardLen4;
- unsigned int FromCardLen1;
- unsigned int FromCardLen2;
- unsigned int FromCardLen3;
- unsigned int FromCardLen4;
-};
-
-struct CPRB {
- unsigned char cprb_len[2];
- unsigned char cprb_ver_id;
- unsigned char pad_000;
- unsigned char srpi_rtcode[4];
- unsigned char srpi_verb;
- unsigned char flags;
- unsigned char func_id[2];
- unsigned char checkpoint_flag;
- unsigned char resv2;
- unsigned char req_parml[2];
- unsigned char req_parmp[4];
- unsigned char req_datal[4];
- unsigned char req_datap[4];
- unsigned char rpl_parml[2];
- unsigned char pad_001[2];
- unsigned char rpl_parmp[4];
- unsigned char rpl_datal[4];
- unsigned char rpl_datap[4];
- unsigned char ccp_rscode[2];
- unsigned char ccp_rtcode[2];
- unsigned char repd_parml[2];
- unsigned char mac_data_len[2];
- unsigned char repd_datal[4];
- unsigned char req_pc[2];
- unsigned char res_origin[8];
- unsigned char mac_value[8];
- unsigned char logon_id[8];
- unsigned char usage_domain[2];
- unsigned char resv3[18];
- unsigned char svr_namel[2];
- unsigned char svr_name[8];
-};
-
-struct type6_msg {
- struct type6_hdr header;
- struct CPRB CPRB;
-};
-
-struct type86_hdr {
- unsigned char reserved1;
- unsigned char type;
- unsigned char format;
- unsigned char reserved2;
- unsigned char reply_code;
- unsigned char reserved3[3];
-};
-
-#define TYPE86_RSP_CODE 0x86
-#define TYPE86_FMT2 0x02
-
-struct type86_fmt2_msg {
- struct type86_hdr header;
- unsigned char reserved[4];
- unsigned char apfs[4];
- unsigned int count1;
- unsigned int offset1;
- unsigned int count2;
- unsigned int offset2;
- unsigned int count3;
- unsigned int offset3;
- unsigned int count4;
- unsigned int offset4;
-};
-
-static struct type6_hdr static_type6_hdr = {
- 0x00,
- 0x06,
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- 0x00000058,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
- 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
- {0x00,0x00},
- {0x00,0x00},
- {0x50,0x44},
- {0x00,0x00},
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000
-};
-
-static struct type6_hdr static_type6_hdrX = {
- 0x00,
- 0x06,
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- 0x00000058,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- {0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x50,0x44},
- {0x00,0x00},
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000
-};
-
-static struct CPRB static_cprb = {
- {0x70,0x00},
- 0x41,
- 0x00,
- {0x00,0x00,0x00,0x00},
- 0x00,
- 0x00,
- {0x54,0x32},
- 0x01,
- 0x00,
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x00,0x00},
- {0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00},
- {0x08,0x00},
- {0x49,0x43,0x53,0x46,0x20,0x20,0x20,0x20}
-};
-
-struct function_and_rules_block {
- unsigned char function_code[2];
- unsigned char ulen[2];
- unsigned char only_rule[8];
-};
-
-static struct function_and_rules_block static_pkd_function_and_rules = {
- {0x50,0x44},
- {0x0A,0x00},
- {'P','K','C','S','-','1','.','2'}
-};
-
-static struct function_and_rules_block static_pke_function_and_rules = {
- {0x50,0x4B},
- {0x0A,0x00},
- {'P','K','C','S','-','1','.','2'}
-};
-
-struct T6_keyBlock_hdr {
- unsigned char blen[2];
- unsigned char ulen[2];
- unsigned char flags[2];
-};
-
-static struct T6_keyBlock_hdr static_T6_keyBlock_hdr = {
- {0x89,0x01},
- {0x87,0x01},
- {0x00}
-};
-
-static struct CPRBX static_cprbx = {
- 0x00DC,
- 0x02,
- {0x00,0x00,0x00},
- {0x54,0x32},
- {0x00,0x00,0x00,0x00},
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- {0x00,0x00,0x00,0x00},
- 0x00000000,
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- 0x0000,
- 0x0000,
- 0x00000000,
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- 0x00,
- 0x00,
- 0x0000,
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
-};
-
-static struct function_and_rules_block static_pkd_function_and_rulesX_MCL2 = {
- {0x50,0x44},
- {0x00,0x0A},
- {'P','K','C','S','-','1','.','2'}
-};
-
-static struct function_and_rules_block static_pke_function_and_rulesX_MCL2 = {
- {0x50,0x4B},
- {0x00,0x0A},
- {'Z','E','R','O','-','P','A','D'}
-};
-
-static struct function_and_rules_block static_pkd_function_and_rulesX = {
- {0x50,0x44},
- {0x00,0x0A},
- {'Z','E','R','O','-','P','A','D'}
-};
-
-static struct function_and_rules_block static_pke_function_and_rulesX = {
- {0x50,0x4B},
- {0x00,0x0A},
- {'M','R','P',' ',' ',' ',' ',' '}
-};
-
-static unsigned char static_PKE_function_code[2] = {0x50, 0x4B};
-
-struct T6_keyBlock_hdrX {
- unsigned short blen;
- unsigned short ulen;
- unsigned char flags[2];
-};
-
-static unsigned char static_pad[256] = {
-0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
-0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
-0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
-0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
-0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
-0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
-0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
-0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
-0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
-0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
-0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
-0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
-0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
-0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
-0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
-0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
-};
-
-static struct cca_private_ext_ME static_pvt_me_key = {
- {
- 0x1E,
- 0x00,
- 0x0183,
- {0x00,0x00,0x00,0x00}
- },
-
- {
- 0x02,
- 0x00,
- 0x016C,
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00},
- 0x00,
- 0x00,
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00},
- {0x80,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
- {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
- },
-
- {
- 0x04,
- 0x00,
- 0x000F,
- {0x00,0x00},
- 0x0003,
- 0x0000,
- 0x0000,
- {0x01,0x00,0x01}
- }
-};
-
-static struct cca_public_key static_public_key = {
- {
- 0x1E,
- 0x00,
- 0x0000,
- {0x00,0x00,0x00,0x00}
- },
-
- {
- 0x04,
- 0x00,
- 0x0000,
- {0x00,0x00},
- 0x0000,
- 0x0000,
- 0x0000,
- {0x01,0x00,0x01}
- }
-};
-
-#define FIXED_TYPE6_ME_LEN 0x0000025F
-
-#define FIXED_TYPE6_ME_EN_LEN 0x000000F0
-
-#define FIXED_TYPE6_ME_LENX 0x000002CB
-
-#define FIXED_TYPE6_ME_EN_LENX 0x0000015C
-
-static struct cca_public_sec static_cca_pub_sec = {
- 0x04,
- 0x00,
- 0x000f,
- {0x00,0x00},
- 0x0003,
- 0x0000,
- 0x0000,
- {0x01,0x00,0x01}
-};
-
-#define FIXED_TYPE6_CR_LEN 0x00000177
-
-#define FIXED_TYPE6_CR_LENX 0x000001E3
-
-#define MAX_RESPONSE_SIZE 0x00000710
-
-#define MAX_RESPONSEX_SIZE 0x0000077C
-
-#define RESPONSE_CPRB_SIZE 0x000006B8
-#define RESPONSE_CPRBX_SIZE 0x00000724
-
-struct type50_hdr {
- u8 reserved1;
- u8 msg_type_code;
- u16 msg_len;
- u8 reserved2;
- u8 ignored;
- u16 reserved3;
-};
-
-#define TYPE50_TYPE_CODE 0x50
-
-#define TYPE50_MEB1_LEN (sizeof(struct type50_meb1_msg))
-#define TYPE50_MEB2_LEN (sizeof(struct type50_meb2_msg))
-#define TYPE50_CRB1_LEN (sizeof(struct type50_crb1_msg))
-#define TYPE50_CRB2_LEN (sizeof(struct type50_crb2_msg))
-
-#define TYPE50_MEB1_FMT 0x0001
-#define TYPE50_MEB2_FMT 0x0002
-#define TYPE50_CRB1_FMT 0x0011
-#define TYPE50_CRB2_FMT 0x0012
-
-struct type50_meb1_msg {
- struct type50_hdr header;
- u16 keyblock_type;
- u8 reserved[6];
- u8 exponent[128];
- u8 modulus[128];
- u8 message[128];
-};
-
-struct type50_meb2_msg {
- struct type50_hdr header;
- u16 keyblock_type;
- u8 reserved[6];
- u8 exponent[256];
- u8 modulus[256];
- u8 message[256];
-};
-
-struct type50_crb1_msg {
- struct type50_hdr header;
- u16 keyblock_type;
- u8 reserved[6];
- u8 p[64];
- u8 q[64];
- u8 dp[64];
- u8 dq[64];
- u8 u[64];
- u8 message[128];
-};
-
-struct type50_crb2_msg {
- struct type50_hdr header;
- u16 keyblock_type;
- u8 reserved[6];
- u8 p[128];
- u8 q[128];
- u8 dp[128];
- u8 dq[128];
- u8 u[128];
- u8 message[256];
-};
-
-union type50_msg {
- struct type50_meb1_msg meb1;
- struct type50_meb2_msg meb2;
- struct type50_crb1_msg crb1;
- struct type50_crb2_msg crb2;
-};
-
-struct type80_hdr {
- u8 reserved1;
- u8 type;
- u16 len;
- u8 code;
- u8 reserved2[3];
- u8 reserved3[8];
-};
-
-#define TYPE80_RSP_CODE 0x80
-
-struct error_hdr {
- unsigned char reserved1;
- unsigned char type;
- unsigned char reserved2[2];
- unsigned char reply_code;
- unsigned char reserved3[3];
-};
-
-#define TYPE82_RSP_CODE 0x82
-#define TYPE88_RSP_CODE 0x88
-
-#define REP82_ERROR_MACHINE_FAILURE 0x10
-#define REP82_ERROR_PREEMPT_FAILURE 0x12
-#define REP82_ERROR_CHECKPT_FAILURE 0x14
-#define REP82_ERROR_MESSAGE_TYPE 0x20
-#define REP82_ERROR_INVALID_COMM_CD 0x21
-#define REP82_ERROR_INVALID_MSG_LEN 0x23
-#define REP82_ERROR_RESERVD_FIELD 0x24
-#define REP82_ERROR_FORMAT_FIELD 0x29
-#define REP82_ERROR_INVALID_COMMAND 0x30
-#define REP82_ERROR_MALFORMED_MSG 0x40
-#define REP82_ERROR_RESERVED_FIELDO 0x50
-#define REP82_ERROR_WORD_ALIGNMENT 0x60
-#define REP82_ERROR_MESSAGE_LENGTH 0x80
-#define REP82_ERROR_OPERAND_INVALID 0x82
-#define REP82_ERROR_OPERAND_SIZE 0x84
-#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
-#define REP82_ERROR_RESERVED_FIELD 0x88
-#define REP82_ERROR_TRANSPORT_FAIL 0x90
-#define REP82_ERROR_PACKET_TRUNCATED 0xA0
-#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
-
-#define REP88_ERROR_MODULE_FAILURE 0x10
-#define REP88_ERROR_MODULE_TIMEOUT 0x11
-#define REP88_ERROR_MODULE_NOTINIT 0x13
-#define REP88_ERROR_MODULE_NOTAVAIL 0x14
-#define REP88_ERROR_MODULE_DISABLED 0x15
-#define REP88_ERROR_MODULE_IN_DIAGN 0x17
-#define REP88_ERROR_FASTPATH_DISABLD 0x19
-#define REP88_ERROR_MESSAGE_TYPE 0x20
-#define REP88_ERROR_MESSAGE_MALFORMD 0x22
-#define REP88_ERROR_MESSAGE_LENGTH 0x23
-#define REP88_ERROR_RESERVED_FIELD 0x24
-#define REP88_ERROR_KEY_TYPE 0x34
-#define REP88_ERROR_INVALID_KEY 0x82
-#define REP88_ERROR_OPERAND 0x84
-#define REP88_ERROR_OPERAND_EVEN_MOD 0x85
-
-#define CALLER_HEADER 12
-
-static inline int
-testq(int q_nr, int *q_depth, int *dev_type, struct ap_status_word *stat)
-{
- int ccode;
-
- asm volatile
-#ifdef CONFIG_64BIT
- (" llgfr 0,%4 \n"
- " slgr 1,1 \n"
- " lgr 2,1 \n"
- "0: .long 0xb2af0000 \n"
- "1: ipm %0 \n"
- " srl %0,28 \n"
- " iihh %0,0 \n"
- " iihl %0,0 \n"
- " lgr %1,1 \n"
- " lgr %3,2 \n"
- " srl %3,24 \n"
- " sll 2,24 \n"
- " srl 2,24 \n"
- " lgr %2,2 \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h5 \n"
- " jg 2b \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 8 \n"
- " .quad 0b,3b \n"
- " .quad 1b,3b \n"
- ".previous"
- :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
- :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
- :"cc","0","1","2","memory");
-#else
- (" lr 0,%4 \n"
- " slr 1,1 \n"
- " lr 2,1 \n"
- "0: .long 0xb2af0000 \n"
- "1: ipm %0 \n"
- " srl %0,28 \n"
- " lr %1,1 \n"
- " lr %3,2 \n"
- " srl %3,24 \n"
- " sll 2,24 \n"
- " srl 2,24 \n"
- " lr %2,2 \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h5 \n"
- " bras 1,4f \n"
- " .long 2b \n"
- "4: \n"
- " l 1,0(1) \n"
- " br 1 \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 4 \n"
- " .long 0b,3b \n"
- " .long 1b,3b \n"
- ".previous"
- :"=d" (ccode),"=d" (*stat),"=d" (*q_depth), "=d" (*dev_type)
- :"d" (q_nr), "K" (DEV_TSQ_EXCEPTION)
- :"cc","0","1","2","memory");
-#endif
- return ccode;
-}
-
-static inline int
-resetq(int q_nr, struct ap_status_word *stat_p)
-{
- int ccode;
-
- asm volatile
-#ifdef CONFIG_64BIT
- (" llgfr 0,%2 \n"
- " lghi 1,1 \n"
- " sll 1,24 \n"
- " or 0,1 \n"
- " slgr 1,1 \n"
- " lgr 2,1 \n"
- "0: .long 0xb2af0000 \n"
- "1: ipm %0 \n"
- " srl %0,28 \n"
- " iihh %0,0 \n"
- " iihl %0,0 \n"
- " lgr %1,1 \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h3 \n"
- " jg 2b \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 8 \n"
- " .quad 0b,3b \n"
- " .quad 1b,3b \n"
- ".previous"
- :"=d" (ccode),"=d" (*stat_p)
- :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
- :"cc","0","1","2","memory");
-#else
- (" lr 0,%2 \n"
- " lhi 1,1 \n"
- " sll 1,24 \n"
- " or 0,1 \n"
- " slr 1,1 \n"
- " lr 2,1 \n"
- "0: .long 0xb2af0000 \n"
- "1: ipm %0 \n"
- " srl %0,28 \n"
- " lr %1,1 \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h3 \n"
- " bras 1,4f \n"
- " .long 2b \n"
- "4: \n"
- " l 1,0(1) \n"
- " br 1 \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 4 \n"
- " .long 0b,3b \n"
- " .long 1b,3b \n"
- ".previous"
- :"=d" (ccode),"=d" (*stat_p)
- :"d" (q_nr), "K" (DEV_RSQ_EXCEPTION)
- :"cc","0","1","2","memory");
-#endif
- return ccode;
-}
-
-static inline int
-sen(int msg_len, unsigned char *msg_ext, struct ap_status_word *stat)
-{
- int ccode;
-
- asm volatile
-#ifdef CONFIG_64BIT
- (" lgr 6,%3 \n"
- " llgfr 7,%2 \n"
- " llgt 0,0(6) \n"
- " lghi 1,64 \n"
- " sll 1,24 \n"
- " or 0,1 \n"
- " la 6,4(6) \n"
- " llgt 2,0(6) \n"
- " llgt 3,4(6) \n"
- " la 6,8(6) \n"
- " slr 1,1 \n"
- "0: .long 0xb2ad0026 \n"
- "1: brc 2,0b \n"
- " ipm %0 \n"
- " srl %0,28 \n"
- " iihh %0,0 \n"
- " iihl %0,0 \n"
- " lgr %1,1 \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h4 \n"
- " jg 2b \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 8 \n"
- " .quad 0b,3b \n"
- " .quad 1b,3b \n"
- ".previous"
- :"=d" (ccode),"=d" (*stat)
- :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
- :"cc","0","1","2","3","6","7","memory");
-#else
- (" lr 6,%3 \n"
- " lr 7,%2 \n"
- " l 0,0(6) \n"
- " lhi 1,64 \n"
- " sll 1,24 \n"
- " or 0,1 \n"
- " la 6,4(6) \n"
- " l 2,0(6) \n"
- " l 3,4(6) \n"
- " la 6,8(6) \n"
- " slr 1,1 \n"
- "0: .long 0xb2ad0026 \n"
- "1: brc 2,0b \n"
- " ipm %0 \n"
- " srl %0,28 \n"
- " lr %1,1 \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h4 \n"
- " bras 1,4f \n"
- " .long 2b \n"
- "4: \n"
- " l 1,0(1) \n"
- " br 1 \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 4 \n"
- " .long 0b,3b \n"
- " .long 1b,3b \n"
- ".previous"
- :"=d" (ccode),"=d" (*stat)
- :"d" (msg_len),"a" (msg_ext), "K" (DEV_SEN_EXCEPTION)
- :"cc","0","1","2","3","6","7","memory");
-#endif
- return ccode;
-}
-
-static inline int
-rec(int q_nr, int buff_l, unsigned char *rsp, unsigned char *id,
- struct ap_status_word *st)
-{
- int ccode;
-
- asm volatile
-#ifdef CONFIG_64BIT
- (" llgfr 0,%2 \n"
- " lgr 3,%4 \n"
- " lgr 6,%3 \n"
- " llgfr 7,%5 \n"
- " lghi 1,128 \n"
- " sll 1,24 \n"
- " or 0,1 \n"
- " slgr 1,1 \n"
- " lgr 2,1 \n"
- " lgr 4,1 \n"
- " lgr 5,1 \n"
- "0: .long 0xb2ae0046 \n"
- "1: brc 2,0b \n"
- " brc 4,0b \n"
- " ipm %0 \n"
- " srl %0,28 \n"
- " iihh %0,0 \n"
- " iihl %0,0 \n"
- " lgr %1,1 \n"
- " st 4,0(3) \n"
- " st 5,4(3) \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h6 \n"
- " jg 2b \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 8 \n"
- " .quad 0b,3b \n"
- " .quad 1b,3b \n"
- ".previous"
- :"=d"(ccode),"=d"(*st)
- :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
- :"cc","0","1","2","3","4","5","6","7","memory");
-#else
- (" lr 0,%2 \n"
- " lr 3,%4 \n"
- " lr 6,%3 \n"
- " lr 7,%5 \n"
- " lhi 1,128 \n"
- " sll 1,24 \n"
- " or 0,1 \n"
- " slr 1,1 \n"
- " lr 2,1 \n"
- " lr 4,1 \n"
- " lr 5,1 \n"
- "0: .long 0xb2ae0046 \n"
- "1: brc 2,0b \n"
- " brc 4,0b \n"
- " ipm %0 \n"
- " srl %0,28 \n"
- " lr %1,1 \n"
- " st 4,0(3) \n"
- " st 5,4(3) \n"
- "2: \n"
- ".section .fixup,\"ax\" \n"
- "3: \n"
- " lhi %0,%h6 \n"
- " bras 1,4f \n"
- " .long 2b \n"
- "4: \n"
- " l 1,0(1) \n"
- " br 1 \n"
- ".previous \n"
- ".section __ex_table,\"a\" \n"
- " .align 4 \n"
- " .long 0b,3b \n"
- " .long 1b,3b \n"
- ".previous"
- :"=d"(ccode),"=d"(*st)
- :"d" (q_nr), "d" (rsp), "d" (id), "d" (buff_l), "K" (DEV_REC_EXCEPTION)
- :"cc","0","1","2","3","4","5","6","7","memory");
-#endif
- return ccode;
-}
-
-static inline void
-itoLe2(int *i_p, unsigned char *lechars)
-{
- *lechars = *((unsigned char *) i_p + sizeof(int) - 1);
- *(lechars + 1) = *((unsigned char *) i_p + sizeof(int) - 2);
-}
-
-static inline void
-le2toI(unsigned char *lechars, int *i_p)
-{
- unsigned char *ic_p;
- *i_p = 0;
- ic_p = (unsigned char *) i_p;
- *(ic_p + 2) = *(lechars + 1);
- *(ic_p + 3) = *(lechars);
-}
-
-static inline int
-is_empty(unsigned char *ptr, int len)
-{
- return !memcmp(ptr, (unsigned char *) &static_pvt_me_key+60, len);
-}
-
-enum hdstat
-query_online(int deviceNr, int cdx, int resetNr, int *q_depth, int *dev_type)
-{
- int q_nr, i, t_depth, t_dev_type;
- enum devstat ccode;
- struct ap_status_word stat_word;
- enum hdstat stat;
- int break_out;
-
- q_nr = (deviceNr << SKIP_BITL) + cdx;
- stat = HD_BUSY;
- ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
- PDEBUG("ccode %d response_code %02X\n", ccode, stat_word.response_code);
- break_out = 0;
- for (i = 0; i < resetNr; i++) {
- if (ccode > 3) {
- PRINTKC("Exception testing device %d\n", i);
- return HD_TSQ_EXCEPTION;
- }
- switch (ccode) {
- case 0:
- PDEBUG("t_dev_type %d\n", t_dev_type);
- break_out = 1;
- stat = HD_ONLINE;
- *q_depth = t_depth + 1;
- switch (t_dev_type) {
- case PCICA_HW:
- *dev_type = PCICA;
- break;
- case PCICC_HW:
- *dev_type = PCICC;
- break;
- case PCIXCC_HW:
- *dev_type = PCIXCC_UNK;
- break;
- case CEX2C_HW:
- *dev_type = CEX2C;
- break;
- case CEX2A_HW:
- *dev_type = CEX2A;
- break;
- default:
- *dev_type = NILDEV;
- break;
- }
- PDEBUG("available device %d: Q depth = %d, dev "
- "type = %d, stat = %02X%02X%02X%02X\n",
- deviceNr, *q_depth, *dev_type,
- stat_word.q_stat_flags,
- stat_word.response_code,
- stat_word.reserved[0],
- stat_word.reserved[1]);
- break;
- case 3:
- switch (stat_word.response_code) {
- case AP_RESPONSE_NORMAL:
- stat = HD_ONLINE;
- break_out = 1;
- *q_depth = t_depth + 1;
- *dev_type = t_dev_type;
- PDEBUG("cc3, available device "
- "%d: Q depth = %d, dev "
- "type = %d, stat = "
- "%02X%02X%02X%02X\n",
- deviceNr, *q_depth,
- *dev_type,
- stat_word.q_stat_flags,
- stat_word.response_code,
- stat_word.reserved[0],
- stat_word.reserved[1]);
- break;
- case AP_RESPONSE_Q_NOT_AVAIL:
- stat = HD_NOT_THERE;
- break_out = 1;
- break;
- case AP_RESPONSE_RESET_IN_PROGRESS:
- PDEBUG("device %d in reset\n",
- deviceNr);
- break;
- case AP_RESPONSE_DECONFIGURED:
- stat = HD_DECONFIGURED;
- break_out = 1;
- break;
- case AP_RESPONSE_CHECKSTOPPED:
- stat = HD_CHECKSTOPPED;
- break_out = 1;
- break;
- case AP_RESPONSE_BUSY:
- PDEBUG("device %d busy\n",
- deviceNr);
- break;
- default:
- break;
- }
- break;
- default:
- stat = HD_NOT_THERE;
- break_out = 1;
- break;
- }
- if (break_out)
- break;
-
- udelay(5);
-
- ccode = testq(q_nr, &t_depth, &t_dev_type, &stat_word);
- }
- return stat;
-}
-
-enum devstat
-reset_device(int deviceNr, int cdx, int resetNr)
-{
- int q_nr, ccode = 0, dummy_qdepth, dummy_devType, i;
- struct ap_status_word stat_word;
- enum devstat stat;
- int break_out;
-
- q_nr = (deviceNr << SKIP_BITL) + cdx;
- stat = DEV_GONE;
- ccode = resetq(q_nr, &stat_word);
- if (ccode > 3)
- return DEV_RSQ_EXCEPTION;
-
- break_out = 0;
- for (i = 0; i < resetNr; i++) {
- switch (ccode) {
- case 0:
- stat = DEV_ONLINE;
- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
- break_out = 1;
- break;
- case 3:
- switch (stat_word.response_code) {
- case AP_RESPONSE_NORMAL:
- stat = DEV_ONLINE;
- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
- break_out = 1;
- break;
- case AP_RESPONSE_Q_NOT_AVAIL:
- case AP_RESPONSE_DECONFIGURED:
- case AP_RESPONSE_CHECKSTOPPED:
- stat = DEV_GONE;
- break_out = 1;
- break;
- case AP_RESPONSE_RESET_IN_PROGRESS:
- case AP_RESPONSE_BUSY:
- default:
- break;
- }
- break;
- default:
- stat = DEV_GONE;
- break_out = 1;
- break;
- }
- if (break_out == 1)
- break;
- udelay(5);
-
- ccode = testq(q_nr, &dummy_qdepth, &dummy_devType, &stat_word);
- if (ccode > 3) {
- stat = DEV_TSQ_EXCEPTION;
- break;
- }
- }
- PDEBUG("Number of testq's needed for reset: %d\n", i);
-
- if (i >= resetNr) {
- stat = DEV_GONE;
- }
-
- return stat;
-}
-
-#ifdef DEBUG_HYDRA_MSGS
-static inline void
-print_buffer(unsigned char *buffer, int bufflen)
-{
- int i;
- for (i = 0; i < bufflen; i += 16) {
- PRINTK("%04X: %02X%02X%02X%02X %02X%02X%02X%02X "
- "%02X%02X%02X%02X %02X%02X%02X%02X\n", i,
- buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3],
- buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7],
- buffer[i+8], buffer[i+9], buffer[i+10], buffer[i+11],
- buffer[i+12], buffer[i+13], buffer[i+14], buffer[i+15]);
- }
-}
-#endif
-
-enum devstat
-send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext)
-{
- struct ap_status_word stat_word;
- enum devstat stat;
- int ccode;
- u32 *q_nr_p = (u32 *)msg_ext;
-
- *q_nr_p = (dev_nr << SKIP_BITL) + cdx;
- PDEBUG("msg_len passed to sen: %d\n", msg_len);
- PDEBUG("q number passed to sen: %02x%02x%02x%02x\n",
- msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3]);
- stat = DEV_GONE;
-
-#ifdef DEBUG_HYDRA_MSGS
- PRINTK("Request header: %02X%02X%02X%02X %02X%02X%02X%02X "
- "%02X%02X%02X%02X\n",
- msg_ext[0], msg_ext[1], msg_ext[2], msg_ext[3],
- msg_ext[4], msg_ext[5], msg_ext[6], msg_ext[7],
- msg_ext[8], msg_ext[9], msg_ext[10], msg_ext[11]);
- print_buffer(msg_ext+CALLER_HEADER, msg_len);
-#endif
-
- ccode = sen(msg_len, msg_ext, &stat_word);
- if (ccode > 3)
- return DEV_SEN_EXCEPTION;
-
- PDEBUG("nq cc: %u, st: %02x%02x%02x%02x\n",
- ccode, stat_word.q_stat_flags, stat_word.response_code,
- stat_word.reserved[0], stat_word.reserved[1]);
- switch (ccode) {
- case 0:
- stat = DEV_ONLINE;
- break;
- case 1:
- stat = DEV_GONE;
- break;
- case 3:
- switch (stat_word.response_code) {
- case AP_RESPONSE_NORMAL:
- stat = DEV_ONLINE;
- break;
- case AP_RESPONSE_Q_FULL:
- stat = DEV_QUEUE_FULL;
- break;
- default:
- stat = DEV_GONE;
- break;
- }
- break;
- default:
- stat = DEV_GONE;
- break;
- }
-
- return stat;
-}
-
-enum devstat
-receive_from_AP(int dev_nr, int cdx, int resplen, unsigned char *resp,
- unsigned char *psmid)
-{
- int ccode;
- struct ap_status_word stat_word;
- enum devstat stat;
-
- memset(resp, 0x00, 8);
-
- ccode = rec((dev_nr << SKIP_BITL) + cdx, resplen, resp, psmid,
- &stat_word);
- if (ccode > 3)
- return DEV_REC_EXCEPTION;
-
- PDEBUG("dq cc: %u, st: %02x%02x%02x%02x\n",
- ccode, stat_word.q_stat_flags, stat_word.response_code,
- stat_word.reserved[0], stat_word.reserved[1]);
-
- stat = DEV_GONE;
- switch (ccode) {
- case 0:
- stat = DEV_ONLINE;
-#ifdef DEBUG_HYDRA_MSGS
- print_buffer(resp, resplen);
-#endif
- break;
- case 3:
- switch (stat_word.response_code) {
- case AP_RESPONSE_NORMAL:
- stat = DEV_ONLINE;
- break;
- case AP_RESPONSE_NO_PENDING_REPLY:
- if (stat_word.q_stat_flags & AP_Q_STATUS_EMPTY)
- stat = DEV_EMPTY;
- else
- stat = DEV_NO_WORK;
- break;
- case AP_RESPONSE_INDEX_TOO_BIG:
- case AP_RESPONSE_NO_FIRST_PART:
- case AP_RESPONSE_MESSAGE_TOO_BIG:
- stat = DEV_BAD_MESSAGE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- return stat;
-}
-
-static inline int
-pad_msg(unsigned char *buffer, int totalLength, int msgLength)
-{
- int pad_len;
-
- for (pad_len = 0; pad_len < (totalLength - msgLength); pad_len++)
- if (buffer[pad_len] != 0x00)
- break;
- pad_len -= 3;
- if (pad_len < 8)
- return SEN_PAD_ERROR;
-
- buffer[0] = 0x00;
- buffer[1] = 0x02;
-
- memcpy(buffer+2, static_pad, pad_len);
-
- buffer[pad_len + 2] = 0x00;
-
- return 0;
-}
-
-static inline int
-is_common_public_key(unsigned char *key, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- if (key[i])
- break;
- key += i;
- len -= i;
- if (((len == 1) && (key[0] == 3)) ||
- ((len == 3) && (key[0] == 1) && (key[1] == 0) && (key[2] == 1)))
- return 1;
-
- return 0;
-}
-
-static int
-ICAMEX_msg_to_type4MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
- union type4_msg *z90cMsg_p)
-{
- int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
- unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
- union type4_msg *tmp_type4_msg;
-
- mod_len = icaMex_p->inputdatalength;
-
- msg_size = ((mod_len <= 128) ? TYPE4_SME_LEN : TYPE4_LME_LEN) +
- CALLER_HEADER;
-
- memset(z90cMsg_p, 0, msg_size);
-
- tmp_type4_msg = (union type4_msg *)
- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
-
- tmp_type4_msg->sme.header.msg_type_code = TYPE4_TYPE_CODE;
- tmp_type4_msg->sme.header.request_code = TYPE4_REQU_CODE;
-
- if (mod_len <= 128) {
- tmp_type4_msg->sme.header.msg_fmt = TYPE4_SME_FMT;
- tmp_type4_msg->sme.header.msg_len = TYPE4_SME_LEN;
- mod_tgt = tmp_type4_msg->sme.modulus;
- mod_tgt_len = sizeof(tmp_type4_msg->sme.modulus);
- exp_tgt = tmp_type4_msg->sme.exponent;
- exp_tgt_len = sizeof(tmp_type4_msg->sme.exponent);
- inp_tgt = tmp_type4_msg->sme.message;
- inp_tgt_len = sizeof(tmp_type4_msg->sme.message);
- } else {
- tmp_type4_msg->lme.header.msg_fmt = TYPE4_LME_FMT;
- tmp_type4_msg->lme.header.msg_len = TYPE4_LME_LEN;
- mod_tgt = tmp_type4_msg->lme.modulus;
- mod_tgt_len = sizeof(tmp_type4_msg->lme.modulus);
- exp_tgt = tmp_type4_msg->lme.exponent;
- exp_tgt_len = sizeof(tmp_type4_msg->lme.exponent);
- inp_tgt = tmp_type4_msg->lme.message;
- inp_tgt_len = sizeof(tmp_type4_msg->lme.message);
- }
-
- mod_tgt += (mod_tgt_len - mod_len);
- if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
- return SEN_RELEASED;
- if (is_empty(mod_tgt, mod_len))
- return SEN_USER_ERROR;
- exp_tgt += (exp_tgt_len - mod_len);
- if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
- return SEN_RELEASED;
- if (is_empty(exp_tgt, mod_len))
- return SEN_USER_ERROR;
- inp_tgt += (inp_tgt_len - mod_len);
- if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(inp_tgt, mod_len))
- return SEN_USER_ERROR;
-
- *z90cMsg_l_p = msg_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICACRT_msg_to_type4CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
- int *z90cMsg_l_p, union type4_msg *z90cMsg_p)
-{
- int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
- dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len;
- unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt;
- union type4_msg *tmp_type4_msg;
-
- mod_len = icaMsg_p->inputdatalength;
- short_len = mod_len / 2;
- long_len = mod_len / 2 + 8;
-
- tmp_size = ((mod_len <= 128) ? TYPE4_SCR_LEN : TYPE4_LCR_LEN) +
- CALLER_HEADER;
-
- memset(z90cMsg_p, 0, tmp_size);
-
- tmp_type4_msg = (union type4_msg *)
- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
-
- tmp_type4_msg->scr.header.msg_type_code = TYPE4_TYPE_CODE;
- tmp_type4_msg->scr.header.request_code = TYPE4_REQU_CODE;
- if (mod_len <= 128) {
- tmp_type4_msg->scr.header.msg_fmt = TYPE4_SCR_FMT;
- tmp_type4_msg->scr.header.msg_len = TYPE4_SCR_LEN;
- p_tgt = tmp_type4_msg->scr.p;
- p_tgt_len = sizeof(tmp_type4_msg->scr.p);
- q_tgt = tmp_type4_msg->scr.q;
- q_tgt_len = sizeof(tmp_type4_msg->scr.q);
- dp_tgt = tmp_type4_msg->scr.dp;
- dp_tgt_len = sizeof(tmp_type4_msg->scr.dp);
- dq_tgt = tmp_type4_msg->scr.dq;
- dq_tgt_len = sizeof(tmp_type4_msg->scr.dq);
- u_tgt = tmp_type4_msg->scr.u;
- u_tgt_len = sizeof(tmp_type4_msg->scr.u);
- inp_tgt = tmp_type4_msg->scr.message;
- inp_tgt_len = sizeof(tmp_type4_msg->scr.message);
- } else {
- tmp_type4_msg->lcr.header.msg_fmt = TYPE4_LCR_FMT;
- tmp_type4_msg->lcr.header.msg_len = TYPE4_LCR_LEN;
- p_tgt = tmp_type4_msg->lcr.p;
- p_tgt_len = sizeof(tmp_type4_msg->lcr.p);
- q_tgt = tmp_type4_msg->lcr.q;
- q_tgt_len = sizeof(tmp_type4_msg->lcr.q);
- dp_tgt = tmp_type4_msg->lcr.dp;
- dp_tgt_len = sizeof(tmp_type4_msg->lcr.dp);
- dq_tgt = tmp_type4_msg->lcr.dq;
- dq_tgt_len = sizeof(tmp_type4_msg->lcr.dq);
- u_tgt = tmp_type4_msg->lcr.u;
- u_tgt_len = sizeof(tmp_type4_msg->lcr.u);
- inp_tgt = tmp_type4_msg->lcr.message;
- inp_tgt_len = sizeof(tmp_type4_msg->lcr.message);
- }
-
- p_tgt += (p_tgt_len - long_len);
- if (copy_from_user(p_tgt, icaMsg_p->np_prime, long_len))
- return SEN_RELEASED;
- if (is_empty(p_tgt, long_len))
- return SEN_USER_ERROR;
- q_tgt += (q_tgt_len - short_len);
- if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
- return SEN_RELEASED;
- if (is_empty(q_tgt, short_len))
- return SEN_USER_ERROR;
- dp_tgt += (dp_tgt_len - long_len);
- if (copy_from_user(dp_tgt, icaMsg_p->bp_key, long_len))
- return SEN_RELEASED;
- if (is_empty(dp_tgt, long_len))
- return SEN_USER_ERROR;
- dq_tgt += (dq_tgt_len - short_len);
- if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
- return SEN_RELEASED;
- if (is_empty(dq_tgt, short_len))
- return SEN_USER_ERROR;
- u_tgt += (u_tgt_len - long_len);
- if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv, long_len))
- return SEN_RELEASED;
- if (is_empty(u_tgt, long_len))
- return SEN_USER_ERROR;
- inp_tgt += (inp_tgt_len - mod_len);
- if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(inp_tgt, mod_len))
- return SEN_USER_ERROR;
-
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICAMEX_msg_to_type6MEX_de_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
-{
- int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
- unsigned char *temp;
- struct type6_hdr *tp6Hdr_p;
- struct CPRB *cprb_p;
- struct cca_private_ext_ME *key_p;
- static int deprecated_msg_count = 0;
-
- mod_len = icaMsg_p->inputdatalength;
- tmp_size = FIXED_TYPE6_ME_LEN + mod_len;
- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
- parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
- tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
-
- memset(z90cMsg_p, 0, tmp_size);
-
- temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
- memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
- tp6Hdr_p = (struct type6_hdr *)temp;
- tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
-
- temp += sizeof(struct type6_hdr);
- memcpy(temp, &static_cprb, sizeof(struct CPRB));
- cprb_p = (struct CPRB *) temp;
- cprb_p->usage_domain[0]= (unsigned char)cdx;
- itoLe2(&parmBlock_l, cprb_p->req_parml);
- itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
-
- temp += sizeof(struct CPRB);
- memcpy(temp, &static_pkd_function_and_rules,
- sizeof(struct function_and_rules_block));
-
- temp += sizeof(struct function_and_rules_block);
- vud_len = 2 + icaMsg_p->inputdatalength;
- itoLe2(&vud_len, temp);
-
- temp += 2;
- if (copy_from_user(temp, icaMsg_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
-
- temp += mod_len;
- memcpy(temp, &static_T6_keyBlock_hdr, sizeof(struct T6_keyBlock_hdr));
-
- temp += sizeof(struct T6_keyBlock_hdr);
- memcpy(temp, &static_pvt_me_key, sizeof(struct cca_private_ext_ME));
- key_p = (struct cca_private_ext_ME *)temp;
- temp = key_p->pvtMESec.exponent + sizeof(key_p->pvtMESec.exponent)
- - mod_len;
- if (copy_from_user(temp, icaMsg_p->b_key, mod_len))
- return SEN_RELEASED;
- if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
-
- if (is_common_public_key(temp, mod_len)) {
- if (deprecated_msg_count < 20) {
- PRINTK("Common public key used for modex decrypt\n");
- deprecated_msg_count++;
- if (deprecated_msg_count == 20)
- PRINTK("No longer issuing messages about common"
- " public key for modex decrypt.\n");
- }
- return SEN_NOT_AVAIL;
- }
-
- temp = key_p->pvtMESec.modulus + sizeof(key_p->pvtMESec.modulus)
- - mod_len;
- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
- return SEN_RELEASED;
- if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
-
- key_p->pubMESec.modulus_bit_len = 8 * mod_len;
-
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICAMEX_msg_to_type6MEX_en_msg(struct ica_rsa_modexpo *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
-{
- int mod_len, vud_len, exp_len, key_len;
- int pad_len, tmp_size, total_CPRB_len, parmBlock_l, i;
- unsigned char *temp_exp, *exp_p, *temp;
- struct type6_hdr *tp6Hdr_p;
- struct CPRB *cprb_p;
- struct cca_public_key *key_p;
- struct T6_keyBlock_hdr *keyb_p;
-
- temp_exp = kmalloc(256, GFP_KERNEL);
- if (!temp_exp)
- return EGETBUFF;
- mod_len = icaMsg_p->inputdatalength;
- if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
- kfree(temp_exp);
- return SEN_RELEASED;
- }
- if (is_empty(temp_exp, mod_len)) {
- kfree(temp_exp);
- return SEN_USER_ERROR;
- }
-
- exp_p = temp_exp;
- for (i = 0; i < mod_len; i++)
- if (exp_p[i])
- break;
- if (i >= mod_len) {
- kfree(temp_exp);
- return SEN_USER_ERROR;
- }
-
- exp_len = mod_len - i;
- exp_p += i;
-
- PDEBUG("exp_len after computation: %08x\n", exp_len);
- tmp_size = FIXED_TYPE6_ME_EN_LEN + 2 * mod_len + exp_len;
- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
- parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
- tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
-
- vud_len = 2 + mod_len;
- memset(z90cMsg_p, 0, tmp_size);
-
- temp = (unsigned char *)z90cMsg_p + CALLER_HEADER;
- memcpy(temp, &static_type6_hdr, sizeof(struct type6_hdr));
- tp6Hdr_p = (struct type6_hdr *)temp;
- tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
- memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
- sizeof(static_PKE_function_code));
- temp += sizeof(struct type6_hdr);
- memcpy(temp, &static_cprb, sizeof(struct CPRB));
- cprb_p = (struct CPRB *) temp;
- cprb_p->usage_domain[0]= (unsigned char)cdx;
- itoLe2((int *)&(tp6Hdr_p->FromCardLen1), cprb_p->rpl_parml);
- temp += sizeof(struct CPRB);
- memcpy(temp, &static_pke_function_and_rules,
- sizeof(struct function_and_rules_block));
- temp += sizeof(struct function_and_rules_block);
- temp += 2;
- if (copy_from_user(temp, icaMsg_p->inputdata, mod_len)) {
- kfree(temp_exp);
- return SEN_RELEASED;
- }
- if (is_empty(temp, mod_len)) {
- kfree(temp_exp);
- return SEN_USER_ERROR;
- }
- if ((temp[0] != 0x00) || (temp[1] != 0x02)) {
- kfree(temp_exp);
- return SEN_NOT_AVAIL;
- }
- for (i = 2; i < mod_len; i++)
- if (temp[i] == 0x00)
- break;
- if ((i < 9) || (i > (mod_len - 2))) {
- kfree(temp_exp);
- return SEN_NOT_AVAIL;
- }
- pad_len = i + 1;
- vud_len = mod_len - pad_len;
- memmove(temp, temp+pad_len, vud_len);
- temp -= 2;
- vud_len += 2;
- itoLe2(&vud_len, temp);
- temp += (vud_len);
- keyb_p = (struct T6_keyBlock_hdr *)temp;
- temp += sizeof(struct T6_keyBlock_hdr);
- memcpy(temp, &static_public_key, sizeof(static_public_key));
- key_p = (struct cca_public_key *)temp;
- temp = key_p->pubSec.exponent;
- memcpy(temp, exp_p, exp_len);
- kfree(temp_exp);
- temp += exp_len;
- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
- return SEN_RELEASED;
- if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
- key_p->pubSec.modulus_bit_len = 8 * mod_len;
- key_p->pubSec.modulus_byte_len = mod_len;
- key_p->pubSec.exponent_len = exp_len;
- key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
- key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
- key_p->pubHdr.token_length = key_len;
- key_len += 4;
- itoLe2(&key_len, keyb_p->ulen);
- key_len += 2;
- itoLe2(&key_len, keyb_p->blen);
- parmBlock_l -= pad_len;
- itoLe2(&parmBlock_l, cprb_p->req_parml);
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICACRT_msg_to_type6CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p)
-{
- int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
- int long_len, pad_len, keyPartsLen, tmp_l;
- unsigned char *tgt_p, *temp;
- struct type6_hdr *tp6Hdr_p;
- struct CPRB *cprb_p;
- struct cca_token_hdr *keyHdr_p;
- struct cca_pvt_ext_CRT_sec *pvtSec_p;
- struct cca_public_sec *pubSec_p;
-
- mod_len = icaMsg_p->inputdatalength;
- short_len = mod_len / 2;
- long_len = 8 + short_len;
- keyPartsLen = 3 * long_len + 2 * short_len;
- pad_len = (8 - (keyPartsLen % 8)) % 8;
- keyPartsLen += pad_len + mod_len;
- tmp_size = FIXED_TYPE6_CR_LEN + keyPartsLen + mod_len;
- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
- parmBlock_l = total_CPRB_len - sizeof(struct CPRB);
- vud_len = 2 + mod_len;
- tmp_size = 4*((tmp_size + 3)/4) + CALLER_HEADER;
-
- memset(z90cMsg_p, 0, tmp_size);
- tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
- memcpy(tgt_p, &static_type6_hdr, sizeof(struct type6_hdr));
- tp6Hdr_p = (struct type6_hdr *)tgt_p;
- tp6Hdr_p->ToCardLen1 = 4*((total_CPRB_len+3)/4);
- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRB_SIZE;
- tgt_p += sizeof(struct type6_hdr);
- cprb_p = (struct CPRB *) tgt_p;
- memcpy(tgt_p, &static_cprb, sizeof(struct CPRB));
- cprb_p->usage_domain[0]= *((unsigned char *)(&(cdx))+3);
- itoLe2(&parmBlock_l, cprb_p->req_parml);
- memcpy(cprb_p->rpl_parml, cprb_p->req_parml,
- sizeof(cprb_p->req_parml));
- tgt_p += sizeof(struct CPRB);
- memcpy(tgt_p, &static_pkd_function_and_rules,
- sizeof(struct function_and_rules_block));
- tgt_p += sizeof(struct function_and_rules_block);
- itoLe2(&vud_len, tgt_p);
- tgt_p += 2;
- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, mod_len))
- return SEN_USER_ERROR;
- tgt_p += mod_len;
- tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
- sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
- itoLe2(&tmp_l, tgt_p);
- temp = tgt_p + 2;
- tmp_l -= 2;
- itoLe2(&tmp_l, temp);
- tgt_p += sizeof(struct T6_keyBlock_hdr);
- keyHdr_p = (struct cca_token_hdr *)tgt_p;
- keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
- tmp_l -= 4;
- keyHdr_p->token_length = tmp_l;
- tgt_p += sizeof(struct cca_token_hdr);
- pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
- pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
- pvtSec_p->section_length =
- sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
- pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
- pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
- pvtSec_p->p_len = long_len;
- pvtSec_p->q_len = short_len;
- pvtSec_p->dp_len = long_len;
- pvtSec_p->dq_len = short_len;
- pvtSec_p->u_len = long_len;
- pvtSec_p->mod_len = mod_len;
- pvtSec_p->pad_len = pad_len;
- tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
- if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, long_len))
- return SEN_USER_ERROR;
- tgt_p += long_len;
- if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, short_len))
- return SEN_USER_ERROR;
- tgt_p += short_len;
- if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, long_len))
- return SEN_USER_ERROR;
- tgt_p += long_len;
- if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, short_len))
- return SEN_USER_ERROR;
- tgt_p += short_len;
- if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, long_len))
- return SEN_USER_ERROR;
- tgt_p += long_len;
- tgt_p += pad_len;
- memset(tgt_p, 0xFF, mod_len);
- tgt_p += mod_len;
- memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
- pubSec_p = (struct cca_public_sec *) tgt_p;
- pubSec_p->modulus_bit_len = 8 * mod_len;
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICAMEX_msg_to_type6MEX_msgX(struct ica_rsa_modexpo *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
- int dev_type)
-{
- int mod_len, exp_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l;
- int key_len, i;
- unsigned char *temp_exp, *tgt_p, *temp, *exp_p;
- struct type6_hdr *tp6Hdr_p;
- struct CPRBX *cprbx_p;
- struct cca_public_key *key_p;
- struct T6_keyBlock_hdrX *keyb_p;
-
- temp_exp = kmalloc(256, GFP_KERNEL);
- if (!temp_exp)
- return EGETBUFF;
- mod_len = icaMsg_p->inputdatalength;
- if (copy_from_user(temp_exp, icaMsg_p->b_key, mod_len)) {
- kfree(temp_exp);
- return SEN_RELEASED;
- }
- if (is_empty(temp_exp, mod_len)) {
- kfree(temp_exp);
- return SEN_USER_ERROR;
- }
- exp_p = temp_exp;
- for (i = 0; i < mod_len; i++)
- if (exp_p[i])
- break;
- if (i >= mod_len) {
- kfree(temp_exp);
- return SEN_USER_ERROR;
- }
- exp_len = mod_len - i;
- exp_p += i;
- PDEBUG("exp_len after computation: %08x\n", exp_len);
- tmp_size = FIXED_TYPE6_ME_EN_LENX + 2 * mod_len + exp_len;
- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
- parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
- tmp_size = tmp_size + CALLER_HEADER;
- vud_len = 2 + mod_len;
- memset(z90cMsg_p, 0, tmp_size);
- tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
- memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
- tp6Hdr_p = (struct type6_hdr *)tgt_p;
- tp6Hdr_p->ToCardLen1 = total_CPRB_len;
- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
- memcpy(tp6Hdr_p->function_code, static_PKE_function_code,
- sizeof(static_PKE_function_code));
- tgt_p += sizeof(struct type6_hdr);
- memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
- cprbx_p = (struct CPRBX *) tgt_p;
- cprbx_p->domain = (unsigned short)cdx;
- cprbx_p->rpl_msgbl = RESPONSE_CPRBX_SIZE;
- tgt_p += sizeof(struct CPRBX);
- if (dev_type == PCIXCC_MCL2)
- memcpy(tgt_p, &static_pke_function_and_rulesX_MCL2,
- sizeof(struct function_and_rules_block));
- else
- memcpy(tgt_p, &static_pke_function_and_rulesX,
- sizeof(struct function_and_rules_block));
- tgt_p += sizeof(struct function_and_rules_block);
-
- tgt_p += 2;
- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len)) {
- kfree(temp_exp);
- return SEN_RELEASED;
- }
- if (is_empty(tgt_p, mod_len)) {
- kfree(temp_exp);
- return SEN_USER_ERROR;
- }
- tgt_p -= 2;
- *((short *)tgt_p) = (short) vud_len;
- tgt_p += vud_len;
- keyb_p = (struct T6_keyBlock_hdrX *)tgt_p;
- tgt_p += sizeof(struct T6_keyBlock_hdrX);
- memcpy(tgt_p, &static_public_key, sizeof(static_public_key));
- key_p = (struct cca_public_key *)tgt_p;
- temp = key_p->pubSec.exponent;
- memcpy(temp, exp_p, exp_len);
- kfree(temp_exp);
- temp += exp_len;
- if (copy_from_user(temp, icaMsg_p->n_modulus, mod_len))
- return SEN_RELEASED;
- if (is_empty(temp, mod_len))
- return SEN_USER_ERROR;
- key_p->pubSec.modulus_bit_len = 8 * mod_len;
- key_p->pubSec.modulus_byte_len = mod_len;
- key_p->pubSec.exponent_len = exp_len;
- key_p->pubSec.section_length = CALLER_HEADER + mod_len + exp_len;
- key_len = key_p->pubSec.section_length + sizeof(struct cca_token_hdr);
- key_p->pubHdr.token_length = key_len;
- key_len += 4;
- keyb_p->ulen = (unsigned short)key_len;
- key_len += 2;
- keyb_p->blen = (unsigned short)key_len;
- cprbx_p->req_parml = parmBlock_l;
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICACRT_msg_to_type6CRT_msgX(struct ica_rsa_modexpo_crt *icaMsg_p, int cdx,
- int *z90cMsg_l_p, struct type6_msg *z90cMsg_p,
- int dev_type)
-{
- int mod_len, vud_len, tmp_size, total_CPRB_len, parmBlock_l, short_len;
- int long_len, pad_len, keyPartsLen, tmp_l;
- unsigned char *tgt_p, *temp;
- struct type6_hdr *tp6Hdr_p;
- struct CPRBX *cprbx_p;
- struct cca_token_hdr *keyHdr_p;
- struct cca_pvt_ext_CRT_sec *pvtSec_p;
- struct cca_public_sec *pubSec_p;
-
- mod_len = icaMsg_p->inputdatalength;
- short_len = mod_len / 2;
- long_len = 8 + short_len;
- keyPartsLen = 3 * long_len + 2 * short_len;
- pad_len = (8 - (keyPartsLen % 8)) % 8;
- keyPartsLen += pad_len + mod_len;
- tmp_size = FIXED_TYPE6_CR_LENX + keyPartsLen + mod_len;
- total_CPRB_len = tmp_size - sizeof(struct type6_hdr);
- parmBlock_l = total_CPRB_len - sizeof(struct CPRBX);
- vud_len = 2 + mod_len;
- tmp_size = tmp_size + CALLER_HEADER;
- memset(z90cMsg_p, 0, tmp_size);
- tgt_p = (unsigned char *)z90cMsg_p + CALLER_HEADER;
- memcpy(tgt_p, &static_type6_hdrX, sizeof(struct type6_hdr));
- tp6Hdr_p = (struct type6_hdr *)tgt_p;
- tp6Hdr_p->ToCardLen1 = total_CPRB_len;
- tp6Hdr_p->FromCardLen1 = RESPONSE_CPRBX_SIZE;
- tgt_p += sizeof(struct type6_hdr);
- cprbx_p = (struct CPRBX *) tgt_p;
- memcpy(tgt_p, &static_cprbx, sizeof(struct CPRBX));
- cprbx_p->domain = (unsigned short)cdx;
- cprbx_p->req_parml = parmBlock_l;
- cprbx_p->rpl_msgbl = parmBlock_l;
- tgt_p += sizeof(struct CPRBX);
- if (dev_type == PCIXCC_MCL2)
- memcpy(tgt_p, &static_pkd_function_and_rulesX_MCL2,
- sizeof(struct function_and_rules_block));
- else
- memcpy(tgt_p, &static_pkd_function_and_rulesX,
- sizeof(struct function_and_rules_block));
- tgt_p += sizeof(struct function_and_rules_block);
- *((short *)tgt_p) = (short) vud_len;
- tgt_p += 2;
- if (copy_from_user(tgt_p, icaMsg_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, mod_len))
- return SEN_USER_ERROR;
- tgt_p += mod_len;
- tmp_l = sizeof(struct T6_keyBlock_hdr) + sizeof(struct cca_token_hdr) +
- sizeof(struct cca_pvt_ext_CRT_sec) + 0x0F + keyPartsLen;
- *((short *)tgt_p) = (short) tmp_l;
- temp = tgt_p + 2;
- tmp_l -= 2;
- *((short *)temp) = (short) tmp_l;
- tgt_p += sizeof(struct T6_keyBlock_hdr);
- keyHdr_p = (struct cca_token_hdr *)tgt_p;
- keyHdr_p->token_identifier = CCA_TKN_HDR_ID_EXT;
- tmp_l -= 4;
- keyHdr_p->token_length = tmp_l;
- tgt_p += sizeof(struct cca_token_hdr);
- pvtSec_p = (struct cca_pvt_ext_CRT_sec *)tgt_p;
- pvtSec_p->section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
- pvtSec_p->section_length =
- sizeof(struct cca_pvt_ext_CRT_sec) + keyPartsLen;
- pvtSec_p->key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
- pvtSec_p->key_use_flags[0] = CCA_PVT_USAGE_ALL;
- pvtSec_p->p_len = long_len;
- pvtSec_p->q_len = short_len;
- pvtSec_p->dp_len = long_len;
- pvtSec_p->dq_len = short_len;
- pvtSec_p->u_len = long_len;
- pvtSec_p->mod_len = mod_len;
- pvtSec_p->pad_len = pad_len;
- tgt_p += sizeof(struct cca_pvt_ext_CRT_sec);
- if (copy_from_user(tgt_p, icaMsg_p->np_prime, long_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, long_len))
- return SEN_USER_ERROR;
- tgt_p += long_len;
- if (copy_from_user(tgt_p, icaMsg_p->nq_prime, short_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, short_len))
- return SEN_USER_ERROR;
- tgt_p += short_len;
- if (copy_from_user(tgt_p, icaMsg_p->bp_key, long_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, long_len))
- return SEN_USER_ERROR;
- tgt_p += long_len;
- if (copy_from_user(tgt_p, icaMsg_p->bq_key, short_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, short_len))
- return SEN_USER_ERROR;
- tgt_p += short_len;
- if (copy_from_user(tgt_p, icaMsg_p->u_mult_inv, long_len))
- return SEN_RELEASED;
- if (is_empty(tgt_p, long_len))
- return SEN_USER_ERROR;
- tgt_p += long_len;
- tgt_p += pad_len;
- memset(tgt_p, 0xFF, mod_len);
- tgt_p += mod_len;
- memcpy(tgt_p, &static_cca_pub_sec, sizeof(struct cca_public_sec));
- pubSec_p = (struct cca_public_sec *) tgt_p;
- pubSec_p->modulus_bit_len = 8 * mod_len;
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICAMEX_msg_to_type50MEX_msg(struct ica_rsa_modexpo *icaMex_p, int *z90cMsg_l_p,
- union type50_msg *z90cMsg_p)
-{
- int mod_len, msg_size, mod_tgt_len, exp_tgt_len, inp_tgt_len;
- unsigned char *mod_tgt, *exp_tgt, *inp_tgt;
- union type50_msg *tmp_type50_msg;
-
- mod_len = icaMex_p->inputdatalength;
-
- msg_size = ((mod_len <= 128) ? TYPE50_MEB1_LEN : TYPE50_MEB2_LEN) +
- CALLER_HEADER;
-
- memset(z90cMsg_p, 0, msg_size);
-
- tmp_type50_msg = (union type50_msg *)
- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
-
- tmp_type50_msg->meb1.header.msg_type_code = TYPE50_TYPE_CODE;
-
- if (mod_len <= 128) {
- tmp_type50_msg->meb1.header.msg_len = TYPE50_MEB1_LEN;
- tmp_type50_msg->meb1.keyblock_type = TYPE50_MEB1_FMT;
- mod_tgt = tmp_type50_msg->meb1.modulus;
- mod_tgt_len = sizeof(tmp_type50_msg->meb1.modulus);
- exp_tgt = tmp_type50_msg->meb1.exponent;
- exp_tgt_len = sizeof(tmp_type50_msg->meb1.exponent);
- inp_tgt = tmp_type50_msg->meb1.message;
- inp_tgt_len = sizeof(tmp_type50_msg->meb1.message);
- } else {
- tmp_type50_msg->meb2.header.msg_len = TYPE50_MEB2_LEN;
- tmp_type50_msg->meb2.keyblock_type = TYPE50_MEB2_FMT;
- mod_tgt = tmp_type50_msg->meb2.modulus;
- mod_tgt_len = sizeof(tmp_type50_msg->meb2.modulus);
- exp_tgt = tmp_type50_msg->meb2.exponent;
- exp_tgt_len = sizeof(tmp_type50_msg->meb2.exponent);
- inp_tgt = tmp_type50_msg->meb2.message;
- inp_tgt_len = sizeof(tmp_type50_msg->meb2.message);
- }
-
- mod_tgt += (mod_tgt_len - mod_len);
- if (copy_from_user(mod_tgt, icaMex_p->n_modulus, mod_len))
- return SEN_RELEASED;
- if (is_empty(mod_tgt, mod_len))
- return SEN_USER_ERROR;
- exp_tgt += (exp_tgt_len - mod_len);
- if (copy_from_user(exp_tgt, icaMex_p->b_key, mod_len))
- return SEN_RELEASED;
- if (is_empty(exp_tgt, mod_len))
- return SEN_USER_ERROR;
- inp_tgt += (inp_tgt_len - mod_len);
- if (copy_from_user(inp_tgt, icaMex_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(inp_tgt, mod_len))
- return SEN_USER_ERROR;
-
- *z90cMsg_l_p = msg_size - CALLER_HEADER;
-
- return 0;
-}
-
-static int
-ICACRT_msg_to_type50CRT_msg(struct ica_rsa_modexpo_crt *icaMsg_p,
- int *z90cMsg_l_p, union type50_msg *z90cMsg_p)
-{
- int mod_len, short_len, long_len, tmp_size, p_tgt_len, q_tgt_len,
- dp_tgt_len, dq_tgt_len, u_tgt_len, inp_tgt_len, long_offset;
- unsigned char *p_tgt, *q_tgt, *dp_tgt, *dq_tgt, *u_tgt, *inp_tgt,
- temp[8];
- union type50_msg *tmp_type50_msg;
-
- mod_len = icaMsg_p->inputdatalength;
- short_len = mod_len / 2;
- long_len = mod_len / 2 + 8;
- long_offset = 0;
-
- if (long_len > 128) {
- memset(temp, 0x00, sizeof(temp));
- if (copy_from_user(temp, icaMsg_p->np_prime, long_len-128))
- return SEN_RELEASED;
- if (!is_empty(temp, 8))
- return SEN_NOT_AVAIL;
- if (copy_from_user(temp, icaMsg_p->bp_key, long_len-128))
- return SEN_RELEASED;
- if (!is_empty(temp, 8))
- return SEN_NOT_AVAIL;
- if (copy_from_user(temp, icaMsg_p->u_mult_inv, long_len-128))
- return SEN_RELEASED;
- if (!is_empty(temp, 8))
- return SEN_NOT_AVAIL;
- long_offset = long_len - 128;
- long_len = 128;
- }
-
- tmp_size = ((long_len <= 64) ? TYPE50_CRB1_LEN : TYPE50_CRB2_LEN) +
- CALLER_HEADER;
-
- memset(z90cMsg_p, 0, tmp_size);
-
- tmp_type50_msg = (union type50_msg *)
- ((unsigned char *) z90cMsg_p + CALLER_HEADER);
-
- tmp_type50_msg->crb1.header.msg_type_code = TYPE50_TYPE_CODE;
- if (long_len <= 64) {
- tmp_type50_msg->crb1.header.msg_len = TYPE50_CRB1_LEN;
- tmp_type50_msg->crb1.keyblock_type = TYPE50_CRB1_FMT;
- p_tgt = tmp_type50_msg->crb1.p;
- p_tgt_len = sizeof(tmp_type50_msg->crb1.p);
- q_tgt = tmp_type50_msg->crb1.q;
- q_tgt_len = sizeof(tmp_type50_msg->crb1.q);
- dp_tgt = tmp_type50_msg->crb1.dp;
- dp_tgt_len = sizeof(tmp_type50_msg->crb1.dp);
- dq_tgt = tmp_type50_msg->crb1.dq;
- dq_tgt_len = sizeof(tmp_type50_msg->crb1.dq);
- u_tgt = tmp_type50_msg->crb1.u;
- u_tgt_len = sizeof(tmp_type50_msg->crb1.u);
- inp_tgt = tmp_type50_msg->crb1.message;
- inp_tgt_len = sizeof(tmp_type50_msg->crb1.message);
- } else {
- tmp_type50_msg->crb2.header.msg_len = TYPE50_CRB2_LEN;
- tmp_type50_msg->crb2.keyblock_type = TYPE50_CRB2_FMT;
- p_tgt = tmp_type50_msg->crb2.p;
- p_tgt_len = sizeof(tmp_type50_msg->crb2.p);
- q_tgt = tmp_type50_msg->crb2.q;
- q_tgt_len = sizeof(tmp_type50_msg->crb2.q);
- dp_tgt = tmp_type50_msg->crb2.dp;
- dp_tgt_len = sizeof(tmp_type50_msg->crb2.dp);
- dq_tgt = tmp_type50_msg->crb2.dq;
- dq_tgt_len = sizeof(tmp_type50_msg->crb2.dq);
- u_tgt = tmp_type50_msg->crb2.u;
- u_tgt_len = sizeof(tmp_type50_msg->crb2.u);
- inp_tgt = tmp_type50_msg->crb2.message;
- inp_tgt_len = sizeof(tmp_type50_msg->crb2.message);
- }
-
- p_tgt += (p_tgt_len - long_len);
- if (copy_from_user(p_tgt, icaMsg_p->np_prime + long_offset, long_len))
- return SEN_RELEASED;
- if (is_empty(p_tgt, long_len))
- return SEN_USER_ERROR;
- q_tgt += (q_tgt_len - short_len);
- if (copy_from_user(q_tgt, icaMsg_p->nq_prime, short_len))
- return SEN_RELEASED;
- if (is_empty(q_tgt, short_len))
- return SEN_USER_ERROR;
- dp_tgt += (dp_tgt_len - long_len);
- if (copy_from_user(dp_tgt, icaMsg_p->bp_key + long_offset, long_len))
- return SEN_RELEASED;
- if (is_empty(dp_tgt, long_len))
- return SEN_USER_ERROR;
- dq_tgt += (dq_tgt_len - short_len);
- if (copy_from_user(dq_tgt, icaMsg_p->bq_key, short_len))
- return SEN_RELEASED;
- if (is_empty(dq_tgt, short_len))
- return SEN_USER_ERROR;
- u_tgt += (u_tgt_len - long_len);
- if (copy_from_user(u_tgt, icaMsg_p->u_mult_inv + long_offset, long_len))
- return SEN_RELEASED;
- if (is_empty(u_tgt, long_len))
- return SEN_USER_ERROR;
- inp_tgt += (inp_tgt_len - mod_len);
- if (copy_from_user(inp_tgt, icaMsg_p->inputdata, mod_len))
- return SEN_RELEASED;
- if (is_empty(inp_tgt, mod_len))
- return SEN_USER_ERROR;
-
- *z90cMsg_l_p = tmp_size - CALLER_HEADER;
-
- return 0;
-}
-
-int
-convert_request(unsigned char *buffer, int func, unsigned short function,
- int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p)
-{
- if (dev_type == PCICA) {
- if (func == ICARSACRT)
- return ICACRT_msg_to_type4CRT_msg(
- (struct ica_rsa_modexpo_crt *) buffer,
- msg_l_p, (union type4_msg *) msg_p);
- else
- return ICAMEX_msg_to_type4MEX_msg(
- (struct ica_rsa_modexpo *) buffer,
- msg_l_p, (union type4_msg *) msg_p);
- }
- if (dev_type == PCICC) {
- if (func == ICARSACRT)
- return ICACRT_msg_to_type6CRT_msg(
- (struct ica_rsa_modexpo_crt *) buffer,
- cdx, msg_l_p, (struct type6_msg *)msg_p);
- if (function == PCI_FUNC_KEY_ENCRYPT)
- return ICAMEX_msg_to_type6MEX_en_msg(
- (struct ica_rsa_modexpo *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p);
- else
- return ICAMEX_msg_to_type6MEX_de_msg(
- (struct ica_rsa_modexpo *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p);
- }
- if ((dev_type == PCIXCC_MCL2) ||
- (dev_type == PCIXCC_MCL3) ||
- (dev_type == CEX2C)) {
- if (func == ICARSACRT)
- return ICACRT_msg_to_type6CRT_msgX(
- (struct ica_rsa_modexpo_crt *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p,
- dev_type);
- else
- return ICAMEX_msg_to_type6MEX_msgX(
- (struct ica_rsa_modexpo *) buffer,
- cdx, msg_l_p, (struct type6_msg *) msg_p,
- dev_type);
- }
- if (dev_type == CEX2A) {
- if (func == ICARSACRT)
- return ICACRT_msg_to_type50CRT_msg(
- (struct ica_rsa_modexpo_crt *) buffer,
- msg_l_p, (union type50_msg *) msg_p);
- else
- return ICAMEX_msg_to_type50MEX_msg(
- (struct ica_rsa_modexpo *) buffer,
- msg_l_p, (union type50_msg *) msg_p);
- }
-
- return 0;
-}
-
-int ext_bitlens_msg_count = 0;
-static inline void
-unset_ext_bitlens(void)
-{
- if (!ext_bitlens_msg_count) {
- PRINTK("Unable to use coprocessors for extended bitlengths. "
- "Using PCICAs/CEX2As (if present) for extended "
- "bitlengths. This is not an error.\n");
- ext_bitlens_msg_count++;
- }
- ext_bitlens = 0;
-}
-
-int
-convert_response(unsigned char *response, unsigned char *buffer,
- int *respbufflen_p, unsigned char *resp_buff)
-{
- struct ica_rsa_modexpo *icaMsg_p = (struct ica_rsa_modexpo *) buffer;
- struct error_hdr *errh_p = (struct error_hdr *) response;
- struct type80_hdr *t80h_p = (struct type80_hdr *) response;
- struct type84_hdr *t84h_p = (struct type84_hdr *) response;
- struct type86_fmt2_msg *t86m_p = (struct type86_fmt2_msg *) response;
- int reply_code, service_rc, service_rs, src_l;
- unsigned char *src_p, *tgt_p;
- struct CPRB *cprb_p;
- struct CPRBX *cprbx_p;
-
- src_p = 0;
- reply_code = 0;
- service_rc = 0;
- service_rs = 0;
- src_l = 0;
- switch (errh_p->type) {
- case TYPE82_RSP_CODE:
- case TYPE88_RSP_CODE:
- reply_code = errh_p->reply_code;
- src_p = (unsigned char *)errh_p;
- PRINTK("Hardware error: Type %02X Message Header: "
- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
- errh_p->type,
- src_p[0], src_p[1], src_p[2], src_p[3],
- src_p[4], src_p[5], src_p[6], src_p[7]);
- break;
- case TYPE80_RSP_CODE:
- src_l = icaMsg_p->outputdatalength;
- src_p = response + (int)t80h_p->len - src_l;
- break;
- case TYPE84_RSP_CODE:
- src_l = icaMsg_p->outputdatalength;
- src_p = response + (int)t84h_p->len - src_l;
- break;
- case TYPE86_RSP_CODE:
- reply_code = t86m_p->header.reply_code;
- if (reply_code != 0)
- break;
- cprb_p = (struct CPRB *)
- (response + sizeof(struct type86_fmt2_msg));
- cprbx_p = (struct CPRBX *) cprb_p;
- if (cprb_p->cprb_ver_id != 0x02) {
- le2toI(cprb_p->ccp_rtcode, &service_rc);
- if (service_rc != 0) {
- le2toI(cprb_p->ccp_rscode, &service_rs);
- if ((service_rc == 8) && (service_rs == 66))
- PDEBUG("Bad block format on PCICC\n");
- else if ((service_rc == 8) && (service_rs == 65))
- PDEBUG("Probably an even modulus on "
- "PCICC\n");
- else if ((service_rc == 8) && (service_rs == 770)) {
- PDEBUG("Invalid key length on PCICC\n");
- unset_ext_bitlens();
- return REC_USE_PCICA;
- }
- else if ((service_rc == 8) && (service_rs == 783)) {
- PDEBUG("Extended bitlengths not enabled"
- "on PCICC\n");
- unset_ext_bitlens();
- return REC_USE_PCICA;
- }
- else
- PRINTK("service rc/rs (PCICC): %d/%d\n",
- service_rc, service_rs);
- return REC_OPERAND_INV;
- }
- src_p = (unsigned char *)cprb_p + sizeof(struct CPRB);
- src_p += 4;
- le2toI(src_p, &src_l);
- src_l -= 2;
- src_p += 2;
- } else {
- service_rc = (int)cprbx_p->ccp_rtcode;
- if (service_rc != 0) {
- service_rs = (int) cprbx_p->ccp_rscode;
- if ((service_rc == 8) && (service_rs == 66))
- PDEBUG("Bad block format on PCIXCC\n");
- else if ((service_rc == 8) && (service_rs == 65))
- PDEBUG("Probably an even modulus on "
- "PCIXCC\n");
- else if ((service_rc == 8) && (service_rs == 770)) {
- PDEBUG("Invalid key length on PCIXCC\n");
- unset_ext_bitlens();
- return REC_USE_PCICA;
- }
- else if ((service_rc == 8) && (service_rs == 783)) {
- PDEBUG("Extended bitlengths not enabled"
- "on PCIXCC\n");
- unset_ext_bitlens();
- return REC_USE_PCICA;
- }
- else
- PRINTK("service rc/rs (PCIXCC): %d/%d\n",
- service_rc, service_rs);
- return REC_OPERAND_INV;
- }
- src_p = (unsigned char *)
- cprbx_p + sizeof(struct CPRBX);
- src_p += 4;
- src_l = (int)(*((short *) src_p));
- src_l -= 2;
- src_p += 2;
- }
- break;
- default:
- src_p = (unsigned char *)errh_p;
- PRINTK("Unrecognized Message Header: "
- "%02x%02x%02x%02x%02x%02x%02x%02x\n",
- src_p[0], src_p[1], src_p[2], src_p[3],
- src_p[4], src_p[5], src_p[6], src_p[7]);
- return REC_BAD_MESSAGE;
- }
-
- if (reply_code)
- switch (reply_code) {
- case REP82_ERROR_MACHINE_FAILURE:
- if (errh_p->type == TYPE82_RSP_CODE)
- PRINTKW("Machine check failure\n");
- else
- PRINTKW("Module failure\n");
- return REC_HARDWAR_ERR;
- case REP82_ERROR_OPERAND_INVALID:
- return REC_OPERAND_INV;
- case REP88_ERROR_MESSAGE_MALFORMD:
- PRINTKW("Message malformed\n");
- return REC_OPERAND_INV;
- case REP82_ERROR_OPERAND_SIZE:
- return REC_OPERAND_SIZE;
- case REP82_ERROR_EVEN_MOD_IN_OPND:
- return REC_EVEN_MOD;
- case REP82_ERROR_MESSAGE_TYPE:
- return WRONG_DEVICE_TYPE;
- case REP82_ERROR_TRANSPORT_FAIL:
- PRINTKW("Transport failed (APFS = %02X%02X%02X%02X)\n",
- t86m_p->apfs[0], t86m_p->apfs[1],
- t86m_p->apfs[2], t86m_p->apfs[3]);
- return REC_HARDWAR_ERR;
- default:
- PRINTKW("reply code = %d\n", reply_code);
- return REC_HARDWAR_ERR;
- }
-
- if (service_rc != 0)
- return REC_OPERAND_INV;
-
- if ((src_l > icaMsg_p->outputdatalength) ||
- (src_l > RESPBUFFSIZE) ||
- (src_l <= 0))
- return REC_OPERAND_SIZE;
-
- PDEBUG("Length returned = %d\n", src_l);
- tgt_p = resp_buff + icaMsg_p->outputdatalength - src_l;
- memcpy(tgt_p, src_p, src_l);
- if ((errh_p->type == TYPE86_RSP_CODE) && (resp_buff < tgt_p)) {
- memset(resp_buff, 0, icaMsg_p->outputdatalength - src_l);
- if (pad_msg(resp_buff, icaMsg_p->outputdatalength, src_l))
- return REC_INVALID_PAD;
- }
- *respbufflen_p = icaMsg_p->outputdatalength;
- if (*respbufflen_p == 0)
- PRINTK("Zero *respbufflen_p\n");
-
- return 0;
-}
-
diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c
deleted file mode 100644
index 982acc7303e..00000000000
--- a/drivers/s390/crypto/z90main.c
+++ /dev/null
@@ -1,3380 +0,0 @@
-/*
- * linux/drivers/s390/crypto/z90main.c
- *
- * z90crypt 1.3.3
- *
- * Copyright (C) 2001, 2005 IBM Corporation
- * Author(s): Robert Burroughs (burrough@us.ibm.com)
- * Eric Rossman (edrossma@us.ibm.com)
- *
- * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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 <asm/uaccess.h> // copy_(from|to)_user
-#include <linux/compat.h>
-#include <linux/compiler.h>
-#include <linux/delay.h> // mdelay
-#include <linux/init.h>
-#include <linux/interrupt.h> // for tasklets
-#include <linux/miscdevice.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/proc_fs.h>
-#include <linux/syscalls.h>
-#include "z90crypt.h"
-#include "z90common.h"
-
-/**
- * Defaults that may be modified.
- */
-
-/**
- * You can specify a different minor at compile time.
- */
-#ifndef Z90CRYPT_MINOR
-#define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR
-#endif
-
-/**
- * You can specify a different domain at compile time or on the insmod
- * command line.
- */
-#ifndef DOMAIN_INDEX
-#define DOMAIN_INDEX -1
-#endif
-
-/**
- * This is the name under which the device is registered in /proc/modules.
- */
-#define REG_NAME "z90crypt"
-
-/**
- * Cleanup should run every CLEANUPTIME seconds and should clean up requests
- * older than CLEANUPTIME seconds in the past.
- */
-#ifndef CLEANUPTIME
-#define CLEANUPTIME 15
-#endif
-
-/**
- * Config should run every CONFIGTIME seconds
- */
-#ifndef CONFIGTIME
-#define CONFIGTIME 30
-#endif
-
-/**
- * The first execution of the config task should take place
- * immediately after initialization
- */
-#ifndef INITIAL_CONFIGTIME
-#define INITIAL_CONFIGTIME 1
-#endif
-
-/**
- * Reader should run every READERTIME milliseconds
- * With the 100Hz patch for s390, z90crypt can lock the system solid while
- * under heavy load. We'll try to avoid that.
- */
-#ifndef READERTIME
-#if HZ > 1000
-#define READERTIME 2
-#else
-#define READERTIME 10
-#endif
-#endif
-
-/**
- * turn long device array index into device pointer
- */
-#define LONG2DEVPTR(ndx) (z90crypt.device_p[(ndx)])
-
-/**
- * turn short device array index into long device array index
- */
-#define SHRT2LONG(ndx) (z90crypt.overall_device_x.device_index[(ndx)])
-
-/**
- * turn short device array index into device pointer
- */
-#define SHRT2DEVPTR(ndx) LONG2DEVPTR(SHRT2LONG(ndx))
-
-/**
- * Status for a work-element
- */
-#define STAT_DEFAULT 0x00 // request has not been processed
-
-#define STAT_ROUTED 0x80 // bit 7: requests get routed to specific device
- // else, device is determined each write
-#define STAT_FAILED 0x40 // bit 6: this bit is set if the request failed
- // before being sent to the hardware.
-#define STAT_WRITTEN 0x30 // bits 5-4: work to be done, not sent to device
-// 0x20 // UNUSED state
-#define STAT_READPEND 0x10 // bits 5-4: work done, we're returning data now
-#define STAT_NOWORK 0x00 // bits off: no work on any queue
-#define STAT_RDWRMASK 0x30 // mask for bits 5-4
-
-/**
- * Macros to check the status RDWRMASK
- */
-#define CHK_RDWRMASK(statbyte) ((statbyte) & STAT_RDWRMASK)
-#define SET_RDWRMASK(statbyte, newval) \
- {(statbyte) &= ~STAT_RDWRMASK; (statbyte) |= newval;}
-
-/**
- * Audit Trail. Progress of a Work element
- * audit[0]: Unless noted otherwise, these bits are all set by the process
- */
-#define FP_COPYFROM 0x80 // Caller's buffer has been copied to work element
-#define FP_BUFFREQ 0x40 // Low Level buffer requested
-#define FP_BUFFGOT 0x20 // Low Level buffer obtained
-#define FP_SENT 0x10 // Work element sent to a crypto device
- // (may be set by process or by reader task)
-#define FP_PENDING 0x08 // Work element placed on pending queue
- // (may be set by process or by reader task)
-#define FP_REQUEST 0x04 // Work element placed on request queue
-#define FP_ASLEEP 0x02 // Work element about to sleep
-#define FP_AWAKE 0x01 // Work element has been awakened
-
-/**
- * audit[1]: These bits are set by the reader task and/or the cleanup task
- */
-#define FP_NOTPENDING 0x80 // Work element removed from pending queue
-#define FP_AWAKENING 0x40 // Caller about to be awakened
-#define FP_TIMEDOUT 0x20 // Caller timed out
-#define FP_RESPSIZESET 0x10 // Response size copied to work element
-#define FP_RESPADDRCOPIED 0x08 // Response address copied to work element
-#define FP_RESPBUFFCOPIED 0x04 // Response buffer copied to work element
-#define FP_REMREQUEST 0x02 // Work element removed from request queue
-#define FP_SIGNALED 0x01 // Work element was awakened by a signal
-
-/**
- * audit[2]: unused
- */
-
-/**
- * state of the file handle in private_data.status
- */
-#define STAT_OPEN 0
-#define STAT_CLOSED 1
-
-/**
- * PID() expands to the process ID of the current process
- */
-#define PID() (current->pid)
-
-/**
- * Selected Constants. The number of APs and the number of devices
- */
-#ifndef Z90CRYPT_NUM_APS
-#define Z90CRYPT_NUM_APS 64
-#endif
-#ifndef Z90CRYPT_NUM_DEVS
-#define Z90CRYPT_NUM_DEVS Z90CRYPT_NUM_APS
-#endif
-
-/**
- * Buffer size for receiving responses. The maximum Response Size
- * is actually the maximum request size, since in an error condition
- * the request itself may be returned unchanged.
- */
-#define MAX_RESPONSE_SIZE 0x0000077C
-
-/**
- * A count and status-byte mask
- */
-struct status {
- int st_count; // # of enabled devices
- int disabled_count; // # of disabled devices
- int user_disabled_count; // # of devices disabled via proc fs
- unsigned char st_mask[Z90CRYPT_NUM_APS]; // current status mask
-};
-
-/**
- * The array of device indexes is a mechanism for fast indexing into
- * a long (and sparse) array. For instance, if APs 3, 9 and 47 are
- * installed, z90CDeviceIndex[0] is 3, z90CDeviceIndex[1] is 9, and
- * z90CDeviceIndex[2] is 47.
- */
-struct device_x {
- int device_index[Z90CRYPT_NUM_DEVS];
-};
-
-/**
- * All devices are arranged in a single array: 64 APs
- */
-struct device {
- int dev_type; // PCICA, PCICC, PCIXCC_MCL2,
- // PCIXCC_MCL3, CEX2C, CEX2A
- enum devstat dev_stat; // current device status
- int dev_self_x; // Index in array
- int disabled; // Set when device is in error
- int user_disabled; // Set when device is disabled by user
- int dev_q_depth; // q depth
- unsigned char * dev_resp_p; // Response buffer address
- int dev_resp_l; // Response Buffer length
- int dev_caller_count; // Number of callers
- int dev_total_req_cnt; // # requests for device since load
- struct list_head dev_caller_list; // List of callers
-};
-
-/**
- * There's a struct status and a struct device_x for each device type.
- */
-struct hdware_block {
- struct status hdware_mask;
- struct status type_mask[Z90CRYPT_NUM_TYPES];
- struct device_x type_x_addr[Z90CRYPT_NUM_TYPES];
- unsigned char device_type_array[Z90CRYPT_NUM_APS];
-};
-
-/**
- * z90crypt is the topmost data structure in the hierarchy.
- */
-struct z90crypt {
- int max_count; // Nr of possible crypto devices
- struct status mask;
- int q_depth_array[Z90CRYPT_NUM_DEVS];
- int dev_type_array[Z90CRYPT_NUM_DEVS];
- struct device_x overall_device_x; // array device indexes
- struct device * device_p[Z90CRYPT_NUM_DEVS];
- int terminating;
- int domain_established;// TRUE: domain has been found
- int cdx; // Crypto Domain Index
- int len; // Length of this data structure
- struct hdware_block *hdware_info;
-};
-
-/**
- * An array of these structures is pointed to from dev_caller
- * The length of the array depends on the device type. For APs,
- * there are 8.
- *
- * The caller buffer is allocated to the user at OPEN. At WRITE,
- * it contains the request; at READ, the response. The function
- * send_to_crypto_device converts the request to device-dependent
- * form and use the caller's OPEN-allocated buffer for the response.
- *
- * For the contents of caller_dev_dep_req and caller_dev_dep_req_p
- * because that points to it, see the discussion in z90hardware.c.
- * Search for "extended request message block".
- */
-struct caller {
- int caller_buf_l; // length of original request
- unsigned char * caller_buf_p; // Original request on WRITE
- int caller_dev_dep_req_l; // len device dependent request
- unsigned char * caller_dev_dep_req_p; // Device dependent form
- unsigned char caller_id[8]; // caller-supplied message id
- struct list_head caller_liste;
- unsigned char caller_dev_dep_req[MAX_RESPONSE_SIZE];
-};
-
-/**
- * Function prototypes from z90hardware.c
- */
-enum hdstat query_online(int deviceNr, int cdx, int resetNr, int *q_depth,
- int *dev_type);
-enum devstat reset_device(int deviceNr, int cdx, int resetNr);
-enum devstat send_to_AP(int dev_nr, int cdx, int msg_len, unsigned char *msg_ext);
-enum devstat receive_from_AP(int dev_nr, int cdx, int resplen,
- unsigned char *resp, unsigned char *psmid);
-int convert_request(unsigned char *buffer, int func, unsigned short function,
- int cdx, int dev_type, int *msg_l_p, unsigned char *msg_p);
-int convert_response(unsigned char *response, unsigned char *buffer,
- int *respbufflen_p, unsigned char *resp_buff);
-
-/**
- * Low level function prototypes
- */
-static int create_z90crypt(int *cdx_p);
-static int refresh_z90crypt(int *cdx_p);
-static int find_crypto_devices(struct status *deviceMask);
-static int create_crypto_device(int index);
-static int destroy_crypto_device(int index);
-static void destroy_z90crypt(void);
-static int refresh_index_array(struct status *status_str,
- struct device_x *index_array);
-static int probe_device_type(struct device *devPtr);
-static int probe_PCIXCC_type(struct device *devPtr);
-
-/**
- * proc fs definitions
- */
-static struct proc_dir_entry *z90crypt_entry;
-
-/**
- * data structures
- */
-
-/**
- * work_element.opener points back to this structure
- */
-struct priv_data {
- pid_t opener_pid;
- unsigned char status; // 0: open 1: closed
-};
-
-/**
- * A work element is allocated for each request
- */
-struct work_element {
- struct priv_data *priv_data;
- pid_t pid;
- int devindex; // index of device processing this w_e
- // (If request did not specify device,
- // -1 until placed onto a queue)
- int devtype;
- struct list_head liste; // used for requestq and pendingq
- char buffer[128]; // local copy of user request
- int buff_size; // size of the buffer for the request
- char resp_buff[RESPBUFFSIZE];
- int resp_buff_size;
- char __user * resp_addr; // address of response in user space
- unsigned int funccode; // function code of request
- wait_queue_head_t waitq;
- unsigned long requestsent; // time at which the request was sent
- atomic_t alarmrung; // wake-up signal
- unsigned char caller_id[8]; // pid + counter, for this w_e
- unsigned char status[1]; // bits to mark status of the request
- unsigned char audit[3]; // record of work element's progress
- unsigned char * requestptr; // address of request buffer
- int retcode; // return code of request
-};
-
-/**
- * High level function prototypes
- */
-static int z90crypt_open(struct inode *, struct file *);
-static int z90crypt_release(struct inode *, struct file *);
-static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *);
-static ssize_t z90crypt_write(struct file *, const char __user *,
- size_t, loff_t *);
-static long z90crypt_unlocked_ioctl(struct file *, unsigned int, unsigned long);
-static long z90crypt_compat_ioctl(struct file *, unsigned int, unsigned long);
-
-static void z90crypt_reader_task(unsigned long);
-static void z90crypt_schedule_reader_task(unsigned long);
-static void z90crypt_config_task(unsigned long);
-static void z90crypt_cleanup_task(unsigned long);
-
-static int z90crypt_status(char *, char **, off_t, int, int *, void *);
-static int z90crypt_status_write(struct file *, const char __user *,
- unsigned long, void *);
-
-/**
- * Storage allocated at initialization and used throughout the life of
- * this insmod
- */
-static int domain = DOMAIN_INDEX;
-static struct z90crypt z90crypt;
-static int quiesce_z90crypt;
-static spinlock_t queuespinlock;
-static struct list_head request_list;
-static int requestq_count;
-static struct list_head pending_list;
-static int pendingq_count;
-
-static struct tasklet_struct reader_tasklet;
-static struct timer_list reader_timer;
-static struct timer_list config_timer;
-static struct timer_list cleanup_timer;
-static atomic_t total_open;
-static atomic_t z90crypt_step;
-
-static struct file_operations z90crypt_fops = {
- .owner = THIS_MODULE,
- .read = z90crypt_read,
- .write = z90crypt_write,
- .unlocked_ioctl = z90crypt_unlocked_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = z90crypt_compat_ioctl,
-#endif
- .open = z90crypt_open,
- .release = z90crypt_release
-};
-
-static struct miscdevice z90crypt_misc_device = {
- .minor = Z90CRYPT_MINOR,
- .name = DEV_NAME,
- .fops = &z90crypt_fops,
- .devfs_name = DEV_NAME
-};
-
-/**
- * Documentation values.
- */
-MODULE_AUTHOR("zSeries Linux Crypto Team: Robert H. Burroughs, Eric D. Rossman"
- "and Jochen Roehrig");
-MODULE_DESCRIPTION("zSeries Linux Cryptographic Coprocessor device driver, "
- "Copyright 2001, 2005 IBM Corporation");
-MODULE_LICENSE("GPL");
-module_param(domain, int, 0);
-MODULE_PARM_DESC(domain, "domain index for device");
-
-#ifdef CONFIG_COMPAT
-/**
- * ioctl32 conversion routines
- */
-struct ica_rsa_modexpo_32 { // For 32-bit callers
- compat_uptr_t inputdata;
- unsigned int inputdatalength;
- compat_uptr_t outputdata;
- unsigned int outputdatalength;
- compat_uptr_t b_key;
- compat_uptr_t n_modulus;
-};
-
-static long
-trans_modexpo32(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg);
- struct ica_rsa_modexpo_32 mex32k;
- struct ica_rsa_modexpo __user *mex64;
- long ret = 0;
- unsigned int i;
-
- if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32)))
- return -EFAULT;
- mex64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo));
- if (!access_ok(VERIFY_WRITE, mex64, sizeof(struct ica_rsa_modexpo)))
- return -EFAULT;
- if (copy_from_user(&mex32k, mex32u, sizeof(struct ica_rsa_modexpo_32)))
- return -EFAULT;
- if (__put_user(compat_ptr(mex32k.inputdata), &mex64->inputdata) ||
- __put_user(mex32k.inputdatalength, &mex64->inputdatalength) ||
- __put_user(compat_ptr(mex32k.outputdata), &mex64->outputdata) ||
- __put_user(mex32k.outputdatalength, &mex64->outputdatalength) ||
- __put_user(compat_ptr(mex32k.b_key), &mex64->b_key) ||
- __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus))
- return -EFAULT;
- ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)mex64);
- if (!ret)
- if (__get_user(i, &mex64->outputdatalength) ||
- __put_user(i, &mex32u->outputdatalength))
- ret = -EFAULT;
- return ret;
-}
-
-struct ica_rsa_modexpo_crt_32 { // For 32-bit callers
- compat_uptr_t inputdata;
- unsigned int inputdatalength;
- compat_uptr_t outputdata;
- unsigned int outputdatalength;
- compat_uptr_t bp_key;
- compat_uptr_t bq_key;
- compat_uptr_t np_prime;
- compat_uptr_t nq_prime;
- compat_uptr_t u_mult_inv;
-};
-
-static long
-trans_modexpo_crt32(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct ica_rsa_modexpo_crt_32 __user *crt32u = compat_ptr(arg);
- struct ica_rsa_modexpo_crt_32 crt32k;
- struct ica_rsa_modexpo_crt __user *crt64;
- long ret = 0;
- unsigned int i;
-
- if (!access_ok(VERIFY_WRITE, crt32u,
- sizeof(struct ica_rsa_modexpo_crt_32)))
- return -EFAULT;
- crt64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo_crt));
- if (!access_ok(VERIFY_WRITE, crt64, sizeof(struct ica_rsa_modexpo_crt)))
- return -EFAULT;
- if (copy_from_user(&crt32k, crt32u,
- sizeof(struct ica_rsa_modexpo_crt_32)))
- return -EFAULT;
- if (__put_user(compat_ptr(crt32k.inputdata), &crt64->inputdata) ||
- __put_user(crt32k.inputdatalength, &crt64->inputdatalength) ||
- __put_user(compat_ptr(crt32k.outputdata), &crt64->outputdata) ||
- __put_user(crt32k.outputdatalength, &crt64->outputdatalength) ||
- __put_user(compat_ptr(crt32k.bp_key), &crt64->bp_key) ||
- __put_user(compat_ptr(crt32k.bq_key), &crt64->bq_key) ||
- __put_user(compat_ptr(crt32k.np_prime), &crt64->np_prime) ||
- __put_user(compat_ptr(crt32k.nq_prime), &crt64->nq_prime) ||
- __put_user(compat_ptr(crt32k.u_mult_inv), &crt64->u_mult_inv))
- return -EFAULT;
- ret = z90crypt_unlocked_ioctl(filp, cmd, (unsigned long)crt64);
- if (!ret)
- if (__get_user(i, &crt64->outputdatalength) ||
- __put_user(i, &crt32u->outputdatalength))
- ret = -EFAULT;
- return ret;
-}
-
-static long
-z90crypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case ICAZ90STATUS:
- case Z90QUIESCE:
- case Z90STAT_TOTALCOUNT:
- case Z90STAT_PCICACOUNT:
- case Z90STAT_PCICCCOUNT:
- case Z90STAT_PCIXCCCOUNT:
- case Z90STAT_PCIXCCMCL2COUNT:
- case Z90STAT_PCIXCCMCL3COUNT:
- case Z90STAT_CEX2CCOUNT:
- case Z90STAT_REQUESTQ_COUNT:
- case Z90STAT_PENDINGQ_COUNT:
- case Z90STAT_TOTALOPEN_COUNT:
- case Z90STAT_DOMAIN_INDEX:
- case Z90STAT_STATUS_MASK:
- case Z90STAT_QDEPTH_MASK:
- case Z90STAT_PERDEV_REQCNT:
- return z90crypt_unlocked_ioctl(filp, cmd, arg);
- case ICARSAMODEXPO:
- return trans_modexpo32(filp, cmd, arg);
- case ICARSACRT:
- return trans_modexpo_crt32(filp, cmd, arg);
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif
-
-/**
- * The module initialization code.
- */
-static int __init
-z90crypt_init_module(void)
-{
- int result, nresult;
- struct proc_dir_entry *entry;
-
- PDEBUG("PID %d\n", PID());
-
- if ((domain < -1) || (domain > 15)) {
- PRINTKW("Invalid param: domain = %d. Not loading.\n", domain);
- return -EINVAL;
- }
-
- /* Register as misc device with given minor (or get a dynamic one). */
- result = misc_register(&z90crypt_misc_device);
- if (result < 0) {
- PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
- z90crypt_misc_device.minor, result);
- return result;
- }
-
- PDEBUG("Registered " DEV_NAME " with result %d\n", result);
-
- result = create_z90crypt(&domain);
- if (result != 0) {
- PRINTKW("create_z90crypt (domain index %d) failed with %d.\n",
- domain, result);
- result = -ENOMEM;
- goto init_module_cleanup;
- }
-
- if (result == 0) {
- PRINTKN("Version %d.%d.%d loaded, built on %s %s\n",
- z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT,
- __DATE__, __TIME__);
- PDEBUG("create_z90crypt (domain index %d) successful.\n",
- domain);
- } else
- PRINTK("No devices at startup\n");
-
- /* Initialize globals. */
- spin_lock_init(&queuespinlock);
-
- INIT_LIST_HEAD(&pending_list);
- pendingq_count = 0;
-
- INIT_LIST_HEAD(&request_list);
- requestq_count = 0;
-
- quiesce_z90crypt = 0;
-
- atomic_set(&total_open, 0);
- atomic_set(&z90crypt_step, 0);
-
- /* Set up the cleanup task. */
- init_timer(&cleanup_timer);
- cleanup_timer.function = z90crypt_cleanup_task;
- cleanup_timer.data = 0;
- cleanup_timer.expires = jiffies + (CLEANUPTIME * HZ);
- add_timer(&cleanup_timer);
-
- /* Set up the proc file system */
- entry = create_proc_entry("driver/z90crypt", 0644, 0);
- if (entry) {
- entry->nlink = 1;
- entry->data = 0;
- entry->read_proc = z90crypt_status;
- entry->write_proc = z90crypt_status_write;
- }
- else
- PRINTK("Couldn't create z90crypt proc entry\n");
- z90crypt_entry = entry;
-
- /* Set up the configuration task. */
- init_timer(&config_timer);
- config_timer.function = z90crypt_config_task;
- config_timer.data = 0;
- config_timer.expires = jiffies + (INITIAL_CONFIGTIME * HZ);
- add_timer(&config_timer);
-
- /* Set up the reader task */
- tasklet_init(&reader_tasklet, z90crypt_reader_task, 0);
- init_timer(&reader_timer);
- reader_timer.function = z90crypt_schedule_reader_task;
- reader_timer.data = 0;
- reader_timer.expires = jiffies + (READERTIME * HZ / 1000);
- add_timer(&reader_timer);
-
- return 0; // success
-
-init_module_cleanup:
- if ((nresult = misc_deregister(&z90crypt_misc_device)))
- PRINTK("misc_deregister failed with %d.\n", nresult);
- else
- PDEBUG("misc_deregister successful.\n");
-
- return result; // failure
-}
-
-/**
- * The module termination code
- */
-static void __exit
-z90crypt_cleanup_module(void)
-{
- int nresult;
-
- PDEBUG("PID %d\n", PID());
-
- remove_proc_entry("driver/z90crypt", 0);
-
- if ((nresult = misc_deregister(&z90crypt_misc_device)))
- PRINTK("misc_deregister failed with %d.\n", nresult);
- else
- PDEBUG("misc_deregister successful.\n");
-
- /* Remove the tasks */
- tasklet_kill(&reader_tasklet);
- del_timer(&reader_timer);
- del_timer(&config_timer);
- del_timer(&cleanup_timer);
-
- destroy_z90crypt();
-
- PRINTKN("Unloaded.\n");
-}
-
-/**
- * Functions running under a process id
- *
- * The I/O functions:
- * z90crypt_open
- * z90crypt_release
- * z90crypt_read
- * z90crypt_write
- * z90crypt_unlocked_ioctl
- * z90crypt_status
- * z90crypt_status_write
- * disable_card
- * enable_card
- *
- * Helper functions:
- * z90crypt_rsa
- * z90crypt_prepare
- * z90crypt_send
- * z90crypt_process_results
- *
- */
-static int
-z90crypt_open(struct inode *inode, struct file *filp)
-{
- struct priv_data *private_data_p;
-
- if (quiesce_z90crypt)
- return -EQUIESCE;
-
- private_data_p = kzalloc(sizeof(struct priv_data), GFP_KERNEL);
- if (!private_data_p) {
- PRINTK("Memory allocate failed\n");
- return -ENOMEM;
- }
-
- private_data_p->status = STAT_OPEN;
- private_data_p->opener_pid = PID();
- filp->private_data = private_data_p;
- atomic_inc(&total_open);
-
- return 0;
-}
-
-static int
-z90crypt_release(struct inode *inode, struct file *filp)
-{
- struct priv_data *private_data_p = filp->private_data;
-
- PDEBUG("PID %d (filp %p)\n", PID(), filp);
-
- private_data_p->status = STAT_CLOSED;
- memset(private_data_p, 0, sizeof(struct priv_data));
- kfree(private_data_p);
- atomic_dec(&total_open);
-
- return 0;
-}
-
-/*
- * there are two read functions, of which compile options will choose one
- * without USE_GET_RANDOM_BYTES
- * => read() always returns -EPERM;
- * otherwise
- * => read() uses get_random_bytes() kernel function
- */
-#ifndef USE_GET_RANDOM_BYTES
-/**
- * z90crypt_read will not be supported beyond z90crypt 1.3.1
- */
-static ssize_t
-z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
- PDEBUG("filp %p (PID %d)\n", filp, PID());
- return -EPERM;
-}
-#else // we want to use get_random_bytes
-/**
- * read() just returns a string of random bytes. Since we have no way
- * to generate these cryptographically, we just execute get_random_bytes
- * for the length specified.
- */
-#include <linux/random.h>
-static ssize_t
-z90crypt_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
-{
- unsigned char *temp_buff;
-
- PDEBUG("filp %p (PID %d)\n", filp, PID());
-
- if (quiesce_z90crypt)
- return -EQUIESCE;
- if (count < 0) {
- PRINTK("Requested random byte count negative: %ld\n", count);
- return -EINVAL;
- }
- if (count > RESPBUFFSIZE) {
- PDEBUG("count[%d] > RESPBUFFSIZE", count);
- return -EINVAL;
- }
- if (count == 0)
- return 0;
- temp_buff = kmalloc(RESPBUFFSIZE, GFP_KERNEL);
- if (!temp_buff) {
- PRINTK("Memory allocate failed\n");
- return -ENOMEM;
- }
- get_random_bytes(temp_buff, count);
-
- if (copy_to_user(buf, temp_buff, count) != 0) {
- kfree(temp_buff);
- return -EFAULT;
- }
- kfree(temp_buff);
- return count;
-}
-#endif
-
-/**
- * Write is is not allowed
- */
-static ssize_t
-z90crypt_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
-{
- PDEBUG("filp %p (PID %d)\n", filp, PID());
- return -EPERM;
-}
-
-/**
- * New status functions
- */
-static inline int
-get_status_totalcount(void)
-{
- return z90crypt.hdware_info->hdware_mask.st_count;
-}
-
-static inline int
-get_status_PCICAcount(void)
-{
- return z90crypt.hdware_info->type_mask[PCICA].st_count;
-}
-
-static inline int
-get_status_PCICCcount(void)
-{
- return z90crypt.hdware_info->type_mask[PCICC].st_count;
-}
-
-static inline int
-get_status_PCIXCCcount(void)
-{
- return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count +
- z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
-}
-
-static inline int
-get_status_PCIXCCMCL2count(void)
-{
- return z90crypt.hdware_info->type_mask[PCIXCC_MCL2].st_count;
-}
-
-static inline int
-get_status_PCIXCCMCL3count(void)
-{
- return z90crypt.hdware_info->type_mask[PCIXCC_MCL3].st_count;
-}
-
-static inline int
-get_status_CEX2Ccount(void)
-{
- return z90crypt.hdware_info->type_mask[CEX2C].st_count;
-}
-
-static inline int
-get_status_CEX2Acount(void)
-{
- return z90crypt.hdware_info->type_mask[CEX2A].st_count;
-}
-
-static inline int
-get_status_requestq_count(void)
-{
- return requestq_count;
-}
-
-static inline int
-get_status_pendingq_count(void)
-{
- return pendingq_count;
-}
-
-static inline int
-get_status_totalopen_count(void)
-{
- return atomic_read(&total_open);
-}
-
-static inline int
-get_status_domain_index(void)
-{
- return z90crypt.cdx;
-}
-
-static inline unsigned char *
-get_status_status_mask(unsigned char status[Z90CRYPT_NUM_APS])
-{
- int i, ix;
-
- memcpy(status, z90crypt.hdware_info->device_type_array,
- Z90CRYPT_NUM_APS);
-
- for (i = 0; i < get_status_totalcount(); i++) {
- ix = SHRT2LONG(i);
- if (LONG2DEVPTR(ix)->user_disabled)
- status[ix] = 0x0d;
- }
-
- return status;
-}
-
-static inline unsigned char *
-get_status_qdepth_mask(unsigned char qdepth[Z90CRYPT_NUM_APS])
-{
- int i, ix;
-
- memset(qdepth, 0, Z90CRYPT_NUM_APS);
-
- for (i = 0; i < get_status_totalcount(); i++) {
- ix = SHRT2LONG(i);
- qdepth[ix] = LONG2DEVPTR(ix)->dev_caller_count;
- }
-
- return qdepth;
-}
-
-static inline unsigned int *
-get_status_perdevice_reqcnt(unsigned int reqcnt[Z90CRYPT_NUM_APS])
-{
- int i, ix;
-
- memset(reqcnt, 0, Z90CRYPT_NUM_APS * sizeof(int));
-
- for (i = 0; i < get_status_totalcount(); i++) {
- ix = SHRT2LONG(i);
- reqcnt[ix] = LONG2DEVPTR(ix)->dev_total_req_cnt;
- }
-
- return reqcnt;
-}
-
-static inline void
-init_work_element(struct work_element *we_p,
- struct priv_data *priv_data, pid_t pid)
-{
- int step;
-
- we_p->requestptr = (unsigned char *)we_p + sizeof(struct work_element);
- /* Come up with a unique id for this caller. */
- step = atomic_inc_return(&z90crypt_step);
- memcpy(we_p->caller_id+0, (void *) &pid, sizeof(pid));
- memcpy(we_p->caller_id+4, (void *) &step, sizeof(step));
- we_p->pid = pid;
- we_p->priv_data = priv_data;
- we_p->status[0] = STAT_DEFAULT;
- we_p->audit[0] = 0x00;
- we_p->audit[1] = 0x00;
- we_p->audit[2] = 0x00;
- we_p->resp_buff_size = 0;
- we_p->retcode = 0;
- we_p->devindex = -1;
- we_p->devtype = -1;
- atomic_set(&we_p->alarmrung, 0);
- init_waitqueue_head(&we_p->waitq);
- INIT_LIST_HEAD(&(we_p->liste));
-}
-
-static inline int
-allocate_work_element(struct work_element **we_pp,
- struct priv_data *priv_data_p, pid_t pid)
-{
- struct work_element *we_p;
-
- we_p = (struct work_element *) get_zeroed_page(GFP_KERNEL);
- if (!we_p)
- return -ENOMEM;
- init_work_element(we_p, priv_data_p, pid);
- *we_pp = we_p;
- return 0;
-}
-
-static inline void
-remove_device(struct device *device_p)
-{
- if (!device_p || (device_p->disabled != 0))
- return;
- device_p->disabled = 1;
- z90crypt.hdware_info->type_mask[device_p->dev_type].disabled_count++;
- z90crypt.hdware_info->hdware_mask.disabled_count++;
-}
-
-/**
- * Bitlength limits for each card
- *
- * There are new MCLs which allow more bitlengths. See the table for details.
- * The MCL must be applied and the newer bitlengths enabled for these to work.
- *
- * Card Type Old limit New limit
- * PCICA ??-2048 same (the lower limit is less than 128 bit...)
- * PCICC 512-1024 512-2048
- * PCIXCC_MCL2 512-2048 ----- (applying any GA LIC will make an MCL3 card)
- * PCIXCC_MCL3 ----- 128-2048
- * CEX2C 512-2048 128-2048
- * CEX2A ??-2048 same (the lower limit is less than 128 bit...)
- *
- * ext_bitlens (extended bitlengths) is a global, since you should not apply an
- * MCL to just one card in a machine. We assume, at first, that all cards have
- * these capabilities.
- */
-int ext_bitlens = 1; // This is global
-#define PCIXCC_MIN_MOD_SIZE 16 // 128 bits
-#define OLD_PCIXCC_MIN_MOD_SIZE 64 // 512 bits
-#define PCICC_MIN_MOD_SIZE 64 // 512 bits
-#define OLD_PCICC_MAX_MOD_SIZE 128 // 1024 bits
-#define MAX_MOD_SIZE 256 // 2048 bits
-
-static inline int
-select_device_type(int *dev_type_p, int bytelength)
-{
- static int count = 0;
- int PCICA_avail, PCIXCC_MCL3_avail, CEX2C_avail, CEX2A_avail,
- index_to_use;
- struct status *stat;
- if ((*dev_type_p != PCICC) && (*dev_type_p != PCICA) &&
- (*dev_type_p != PCIXCC_MCL2) && (*dev_type_p != PCIXCC_MCL3) &&
- (*dev_type_p != CEX2C) && (*dev_type_p != CEX2A) &&
- (*dev_type_p != ANYDEV))
- return -1;
- if (*dev_type_p != ANYDEV) {
- stat = &z90crypt.hdware_info->type_mask[*dev_type_p];
- if (stat->st_count >
- (stat->disabled_count + stat->user_disabled_count))
- return 0;
- return -1;
- }
-
- /**
- * Assumption: PCICA, PCIXCC_MCL3, CEX2C, and CEX2A are all similar in
- * speed.
- *
- * PCICA and CEX2A do NOT co-exist, so it would be either one or the
- * other present.
- */
- stat = &z90crypt.hdware_info->type_mask[PCICA];
- PCICA_avail = stat->st_count -
- (stat->disabled_count + stat->user_disabled_count);
- stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL3];
- PCIXCC_MCL3_avail = stat->st_count -
- (stat->disabled_count + stat->user_disabled_count);
- stat = &z90crypt.hdware_info->type_mask[CEX2C];
- CEX2C_avail = stat->st_count -
- (stat->disabled_count + stat->user_disabled_count);
- stat = &z90crypt.hdware_info->type_mask[CEX2A];
- CEX2A_avail = stat->st_count -
- (stat->disabled_count + stat->user_disabled_count);
- if (PCICA_avail || PCIXCC_MCL3_avail || CEX2C_avail || CEX2A_avail) {
- /**
- * bitlength is a factor, PCICA or CEX2A are the most capable,
- * even with the new MCL for PCIXCC.
- */
- if ((bytelength < PCIXCC_MIN_MOD_SIZE) ||
- (!ext_bitlens && (bytelength < OLD_PCIXCC_MIN_MOD_SIZE))) {
- if (PCICA_avail) {
- *dev_type_p = PCICA;
- return 0;
- }
- if (CEX2A_avail) {
- *dev_type_p = CEX2A;
- return 0;
- }
- return -1;
- }
-
- index_to_use = count % (PCICA_avail + PCIXCC_MCL3_avail +
- CEX2C_avail + CEX2A_avail);
- if (index_to_use < PCICA_avail)
- *dev_type_p = PCICA;
- else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail))
- *dev_type_p = PCIXCC_MCL3;
- else if (index_to_use < (PCICA_avail + PCIXCC_MCL3_avail +
- CEX2C_avail))
- *dev_type_p = CEX2C;
- else
- *dev_type_p = CEX2A;
- count++;
- return 0;
- }
-
- /* Less than OLD_PCIXCC_MIN_MOD_SIZE cannot go to a PCIXCC_MCL2 */
- if (bytelength < OLD_PCIXCC_MIN_MOD_SIZE)
- return -1;
- stat = &z90crypt.hdware_info->type_mask[PCIXCC_MCL2];
- if (stat->st_count >
- (stat->disabled_count + stat->user_disabled_count)) {
- *dev_type_p = PCIXCC_MCL2;
- return 0;
- }
-
- /**
- * Less than PCICC_MIN_MOD_SIZE or more than OLD_PCICC_MAX_MOD_SIZE
- * (if we don't have the MCL applied and the newer bitlengths enabled)
- * cannot go to a PCICC
- */
- if ((bytelength < PCICC_MIN_MOD_SIZE) ||
- (!ext_bitlens && (bytelength > OLD_PCICC_MAX_MOD_SIZE))) {
- return -1;
- }
- stat = &z90crypt.hdware_info->type_mask[PCICC];
- if (stat->st_count >
- (stat->disabled_count + stat->user_disabled_count)) {
- *dev_type_p = PCICC;
- return 0;
- }
-
- return -1;
-}
-
-/**
- * Try the selected number, then the selected type (can be ANYDEV)
- */
-static inline int
-select_device(int *dev_type_p, int *device_nr_p, int bytelength)
-{
- int i, indx, devTp, low_count, low_indx;
- struct device_x *index_p;
- struct device *dev_ptr;
-
- PDEBUG("device type = %d, index = %d\n", *dev_type_p, *device_nr_p);
- if ((*device_nr_p >= 0) && (*device_nr_p < Z90CRYPT_NUM_DEVS)) {
- PDEBUG("trying index = %d\n", *device_nr_p);
- dev_ptr = z90crypt.device_p[*device_nr_p];
-
- if (dev_ptr &&
- (dev_ptr->dev_stat != DEV_GONE) &&
- (dev_ptr->disabled == 0) &&
- (dev_ptr->user_disabled == 0)) {
- PDEBUG("selected by number, index = %d\n",
- *device_nr_p);
- *dev_type_p = dev_ptr->dev_type;
- return *device_nr_p;
- }
- }
- *device_nr_p = -1;
- PDEBUG("trying type = %d\n", *dev_type_p);
- devTp = *dev_type_p;
- if (select_device_type(&devTp, bytelength) == -1) {
- PDEBUG("failed to select by type\n");
- return -1;
- }
- PDEBUG("selected type = %d\n", devTp);
- index_p = &z90crypt.hdware_info->type_x_addr[devTp];
- low_count = 0x0000FFFF;
- low_indx = -1;
- for (i = 0; i < z90crypt.hdware_info->type_mask[devTp].st_count; i++) {
- indx = index_p->device_index[i];
- dev_ptr = z90crypt.device_p[indx];
- if (dev_ptr &&
- (dev_ptr->dev_stat != DEV_GONE) &&
- (dev_ptr->disabled == 0) &&
- (dev_ptr->user_disabled == 0) &&
- (devTp == dev_ptr->dev_type) &&
- (low_count > dev_ptr->dev_caller_count)) {
- low_count = dev_ptr->dev_caller_count;
- low_indx = indx;
- }
- }
- *device_nr_p = low_indx;
- return low_indx;
-}
-
-static inline int
-send_to_crypto_device(struct work_element *we_p)
-{
- struct caller *caller_p;
- struct device *device_p;
- int dev_nr;
- int bytelen = ((struct ica_rsa_modexpo *)we_p->buffer)->inputdatalength;
-
- if (!we_p->requestptr)
- return SEN_FATAL_ERROR;
- caller_p = (struct caller *)we_p->requestptr;
- dev_nr = we_p->devindex;
- if (select_device(&we_p->devtype, &dev_nr, bytelen) == -1) {
- if (z90crypt.hdware_info->hdware_mask.st_count != 0)
- return SEN_RETRY;
- else
- return SEN_NOT_AVAIL;
- }
- we_p->devindex = dev_nr;
- device_p = z90crypt.device_p[dev_nr];
- if (!device_p)
- return SEN_NOT_AVAIL;
- if (device_p->dev_type != we_p->devtype)
- return SEN_RETRY;
- if (device_p->dev_caller_count >= device_p->dev_q_depth)
- return SEN_QUEUE_FULL;
- PDEBUG("device number prior to send: %d\n", dev_nr);
- switch (send_to_AP(dev_nr, z90crypt.cdx,
- caller_p->caller_dev_dep_req_l,
- caller_p->caller_dev_dep_req_p)) {
- case DEV_SEN_EXCEPTION:
- PRINTKC("Exception during send to device %d\n", dev_nr);
- z90crypt.terminating = 1;
- return SEN_FATAL_ERROR;
- case DEV_GONE:
- PRINTK("Device %d not available\n", dev_nr);
- remove_device(device_p);
- return SEN_NOT_AVAIL;
- case DEV_EMPTY:
- return SEN_NOT_AVAIL;
- case DEV_NO_WORK:
- return SEN_FATAL_ERROR;
- case DEV_BAD_MESSAGE:
- return SEN_USER_ERROR;
- case DEV_QUEUE_FULL:
- return SEN_QUEUE_FULL;
- default:
- case DEV_ONLINE:
- break;
- }
- list_add_tail(&(caller_p->caller_liste), &(device_p->dev_caller_list));
- device_p->dev_caller_count++;
- return 0;
-}
-
-/**
- * Send puts the user's work on one of two queues:
- * the pending queue if the send was successful
- * the request queue if the send failed because device full or busy
- */
-static inline int
-z90crypt_send(struct work_element *we_p, const char *buf)
-{
- int rv;
-
- PDEBUG("PID %d\n", PID());
-
- if (CHK_RDWRMASK(we_p->status[0]) != STAT_NOWORK) {
- PDEBUG("PID %d tried to send more work but has outstanding "
- "work.\n", PID());
- return -EWORKPEND;
- }
- we_p->devindex = -1; // Reset device number
- spin_lock_irq(&queuespinlock);
- rv = send_to_crypto_device(we_p);
- switch (rv) {
- case 0:
- we_p->requestsent = jiffies;
- we_p->audit[0] |= FP_SENT;
- list_add_tail(&we_p->liste, &pending_list);
- ++pendingq_count;
- we_p->audit[0] |= FP_PENDING;
- break;
- case SEN_BUSY:
- case SEN_QUEUE_FULL:
- rv = 0;
- we_p->devindex = -1; // any device will do
- we_p->requestsent = jiffies;
- list_add_tail(&we_p->liste, &request_list);
- ++requestq_count;
- we_p->audit[0] |= FP_REQUEST;
- break;
- case SEN_RETRY:
- rv = -ERESTARTSYS;
- break;
- case SEN_NOT_AVAIL:
- PRINTK("*** No devices available.\n");
- rv = we_p->retcode = -ENODEV;
- we_p->status[0] |= STAT_FAILED;
- break;
- case REC_OPERAND_INV:
- case REC_OPERAND_SIZE:
- case REC_EVEN_MOD:
- case REC_INVALID_PAD:
- rv = we_p->retcode = -EINVAL;
- we_p->status[0] |= STAT_FAILED;
- break;
- default:
- we_p->retcode = rv;
- we_p->status[0] |= STAT_FAILED;
- break;
- }
- if (rv != -ERESTARTSYS)
- SET_RDWRMASK(we_p->status[0], STAT_WRITTEN);
- spin_unlock_irq(&queuespinlock);
- if (rv == 0)
- tasklet_schedule(&reader_tasklet);
- return rv;
-}
-
-/**
- * process_results copies the user's work from kernel space.
- */
-static inline int
-z90crypt_process_results(struct work_element *we_p, char __user *buf)
-{
- int rv;
-
- PDEBUG("we_p %p (PID %d)\n", we_p, PID());
-
- LONG2DEVPTR(we_p->devindex)->dev_total_req_cnt++;
- SET_RDWRMASK(we_p->status[0], STAT_READPEND);
-
- rv = 0;
- if (!we_p->buffer) {
- PRINTK("we_p %p PID %d in STAT_READPEND: buffer NULL.\n",
- we_p, PID());
- rv = -ENOBUFF;
- }
-
- if (!rv)
- if ((rv = copy_to_user(buf, we_p->buffer, we_p->buff_size))) {
- PDEBUG("copy_to_user failed: rv = %d\n", rv);
- rv = -EFAULT;
- }
-
- if (!rv)
- rv = we_p->retcode;
- if (!rv)
- if (we_p->resp_buff_size
- && copy_to_user(we_p->resp_addr, we_p->resp_buff,
- we_p->resp_buff_size))
- rv = -EFAULT;
-
- SET_RDWRMASK(we_p->status[0], STAT_NOWORK);
- return rv;
-}
-
-static unsigned char NULL_psmid[8] =
-{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-/**
- * Used in device configuration functions
- */
-#define MAX_RESET 90
-
-/**
- * This is used only for PCICC support
- */
-static inline int
-is_PKCS11_padded(unsigned char *buffer, int length)
-{
- int i;
- if ((buffer[0] != 0x00) || (buffer[1] != 0x01))
- return 0;
- for (i = 2; i < length; i++)
- if (buffer[i] != 0xFF)
- break;
- if ((i < 10) || (i == length))
- return 0;
- if (buffer[i] != 0x00)
- return 0;
- return 1;
-}
-
-/**
- * This is used only for PCICC support
- */
-static inline int
-is_PKCS12_padded(unsigned char *buffer, int length)
-{
- int i;
- if ((buffer[0] != 0x00) || (buffer[1] != 0x02))
- return 0;
- for (i = 2; i < length; i++)
- if (buffer[i] == 0x00)
- break;
- if ((i < 10) || (i == length))
- return 0;
- if (buffer[i] != 0x00)
- return 0;
- return 1;
-}
-
-/**
- * builds struct caller and converts message from generic format to
- * device-dependent format
- * func is ICARSAMODEXPO or ICARSACRT
- * function is PCI_FUNC_KEY_ENCRYPT or PCI_FUNC_KEY_DECRYPT
- */
-static inline int
-build_caller(struct work_element *we_p, short function)
-{
- int rv;
- struct caller *caller_p = (struct caller *)we_p->requestptr;
-
- if ((we_p->devtype != PCICC) && (we_p->devtype != PCICA) &&
- (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
- (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A))
- return SEN_NOT_AVAIL;
-
- memcpy(caller_p->caller_id, we_p->caller_id,
- sizeof(caller_p->caller_id));
- caller_p->caller_dev_dep_req_p = caller_p->caller_dev_dep_req;
- caller_p->caller_dev_dep_req_l = MAX_RESPONSE_SIZE;
- caller_p->caller_buf_p = we_p->buffer;
- INIT_LIST_HEAD(&(caller_p->caller_liste));
-
- rv = convert_request(we_p->buffer, we_p->funccode, function,
- z90crypt.cdx, we_p->devtype,
- &caller_p->caller_dev_dep_req_l,
- caller_p->caller_dev_dep_req_p);
- if (rv) {
- if (rv == SEN_NOT_AVAIL)
- PDEBUG("request can't be processed on hdwr avail\n");
- else
- PRINTK("Error from convert_request: %d\n", rv);
- }
- else
- memcpy(&(caller_p->caller_dev_dep_req_p[4]), we_p->caller_id,8);
- return rv;
-}
-
-static inline void
-unbuild_caller(struct device *device_p, struct caller *caller_p)
-{
- if (!caller_p)
- return;
- if (caller_p->caller_liste.next && caller_p->caller_liste.prev)
- if (!list_empty(&caller_p->caller_liste)) {
- list_del_init(&caller_p->caller_liste);
- device_p->dev_caller_count--;
- }
- memset(caller_p->caller_id, 0, sizeof(caller_p->caller_id));
-}
-
-static inline int
-get_crypto_request_buffer(struct work_element *we_p)
-{
- struct ica_rsa_modexpo *mex_p;
- struct ica_rsa_modexpo_crt *crt_p;
- unsigned char *temp_buffer;
- short function;
- int rv;
-
- mex_p = (struct ica_rsa_modexpo *) we_p->buffer;
- crt_p = (struct ica_rsa_modexpo_crt *) we_p->buffer;
-
- PDEBUG("device type input = %d\n", we_p->devtype);
-
- if (z90crypt.terminating)
- return REC_NO_RESPONSE;
- if (memcmp(we_p->caller_id, NULL_psmid, 8) == 0) {
- PRINTK("psmid zeroes\n");
- return SEN_FATAL_ERROR;
- }
- if (!we_p->buffer) {
- PRINTK("buffer pointer NULL\n");
- return SEN_USER_ERROR;
- }
- if (!we_p->requestptr) {
- PRINTK("caller pointer NULL\n");
- return SEN_USER_ERROR;
- }
-
- if ((we_p->devtype != PCICA) && (we_p->devtype != PCICC) &&
- (we_p->devtype != PCIXCC_MCL2) && (we_p->devtype != PCIXCC_MCL3) &&
- (we_p->devtype != CEX2C) && (we_p->devtype != CEX2A) &&
- (we_p->devtype != ANYDEV)) {
- PRINTK("invalid device type\n");
- return SEN_USER_ERROR;
- }
-
- if ((mex_p->inputdatalength < 1) ||
- (mex_p->inputdatalength > MAX_MOD_SIZE)) {
- PRINTK("inputdatalength[%d] is not valid\n",
- mex_p->inputdatalength);
- return SEN_USER_ERROR;
- }
-
- if (mex_p->outputdatalength < mex_p->inputdatalength) {
- PRINTK("outputdatalength[%d] < inputdatalength[%d]\n",
- mex_p->outputdatalength, mex_p->inputdatalength);
- return SEN_USER_ERROR;
- }
-
- if (!mex_p->inputdata || !mex_p->outputdata) {
- PRINTK("inputdata[%p] or outputdata[%p] is NULL\n",
- mex_p->outputdata, mex_p->inputdata);
- return SEN_USER_ERROR;
- }
-
- /**
- * As long as outputdatalength is big enough, we can set the
- * outputdatalength equal to the inputdatalength, since that is the
- * number of bytes we will copy in any case
- */
- mex_p->outputdatalength = mex_p->inputdatalength;
-
- rv = 0;
- switch (we_p->funccode) {
- case ICARSAMODEXPO:
- if (!mex_p->b_key || !mex_p->n_modulus)
- rv = SEN_USER_ERROR;
- break;
- case ICARSACRT:
- if (!IS_EVEN(crt_p->inputdatalength)) {
- PRINTK("inputdatalength[%d] is odd, CRT form\n",
- crt_p->inputdatalength);
- rv = SEN_USER_ERROR;
- break;
- }
- if (!crt_p->bp_key ||
- !crt_p->bq_key ||
- !crt_p->np_prime ||
- !crt_p->nq_prime ||
- !crt_p->u_mult_inv) {
- PRINTK("CRT form, bad data: %p/%p/%p/%p/%p\n",
- crt_p->bp_key, crt_p->bq_key,
- crt_p->np_prime, crt_p->nq_prime,
- crt_p->u_mult_inv);
- rv = SEN_USER_ERROR;
- }
- break;
- default:
- PRINTK("bad func = %d\n", we_p->funccode);
- rv = SEN_USER_ERROR;
- break;
- }
- if (rv != 0)
- return rv;
-
- if (select_device_type(&we_p->devtype, mex_p->inputdatalength) < 0)
- return SEN_NOT_AVAIL;
-
- temp_buffer = (unsigned char *)we_p + sizeof(struct work_element) +
- sizeof(struct caller);
- if (copy_from_user(temp_buffer, mex_p->inputdata,
- mex_p->inputdatalength) != 0)
- return SEN_RELEASED;
-
- function = PCI_FUNC_KEY_ENCRYPT;
- switch (we_p->devtype) {
- /* PCICA and CEX2A do everything with a simple RSA mod-expo operation */
- case PCICA:
- case CEX2A:
- function = PCI_FUNC_KEY_ENCRYPT;
- break;
- /**
- * PCIXCC_MCL2 does all Mod-Expo form with a simple RSA mod-expo
- * operation, and all CRT forms with a PKCS-1.2 format decrypt.
- * PCIXCC_MCL3 and CEX2C do all Mod-Expo and CRT forms with a simple RSA
- * mod-expo operation
- */
- case PCIXCC_MCL2:
- if (we_p->funccode == ICARSAMODEXPO)
- function = PCI_FUNC_KEY_ENCRYPT;
- else
- function = PCI_FUNC_KEY_DECRYPT;
- break;
- case PCIXCC_MCL3:
- case CEX2C:
- if (we_p->funccode == ICARSAMODEXPO)
- function = PCI_FUNC_KEY_ENCRYPT;
- else
- function = PCI_FUNC_KEY_DECRYPT;
- break;
- /**
- * PCICC does everything as a PKCS-1.2 format request
- */
- case PCICC:
- /* PCICC cannot handle input that is is PKCS#1.1 padded */
- if (is_PKCS11_padded(temp_buffer, mex_p->inputdatalength)) {
- return SEN_NOT_AVAIL;
- }
- if (we_p->funccode == ICARSAMODEXPO) {
- if (is_PKCS12_padded(temp_buffer,
- mex_p->inputdatalength))
- function = PCI_FUNC_KEY_ENCRYPT;
- else
- function = PCI_FUNC_KEY_DECRYPT;
- } else
- /* all CRT forms are decrypts */
- function = PCI_FUNC_KEY_DECRYPT;
- break;
- }
- PDEBUG("function: %04x\n", function);
- rv = build_caller(we_p, function);
- PDEBUG("rv from build_caller = %d\n", rv);
- return rv;
-}
-
-static inline int
-z90crypt_prepare(struct work_element *we_p, unsigned int funccode,
- const char __user *buffer)
-{
- int rv;
-
- we_p->devindex = -1;
- if (funccode == ICARSAMODEXPO)
- we_p->buff_size = sizeof(struct ica_rsa_modexpo);
- else
- we_p->buff_size = sizeof(struct ica_rsa_modexpo_crt);
-
- if (copy_from_user(we_p->buffer, buffer, we_p->buff_size))
- return -EFAULT;
-
- we_p->audit[0] |= FP_COPYFROM;
- SET_RDWRMASK(we_p->status[0], STAT_WRITTEN);
- we_p->funccode = funccode;
- we_p->devtype = -1;
- we_p->audit[0] |= FP_BUFFREQ;
- rv = get_crypto_request_buffer(we_p);
- switch (rv) {
- case 0:
- we_p->audit[0] |= FP_BUFFGOT;
- break;
- case SEN_USER_ERROR:
- rv = -EINVAL;
- break;
- case SEN_QUEUE_FULL:
- rv = 0;
- break;
- case SEN_RELEASED:
- rv = -EFAULT;
- break;
- case REC_NO_RESPONSE:
- rv = -ENODEV;
- break;
- case SEN_NOT_AVAIL:
- case EGETBUFF:
- rv = -EGETBUFF;
- break;
- default:
- PRINTK("rv = %d\n", rv);
- rv = -EGETBUFF;
- break;
- }
- if (CHK_RDWRMASK(we_p->status[0]) == STAT_WRITTEN)
- SET_RDWRMASK(we_p->status[0], STAT_DEFAULT);
- return rv;
-}
-
-static inline void
-purge_work_element(struct work_element *we_p)
-{
- struct list_head *lptr;
-
- spin_lock_irq(&queuespinlock);
- list_for_each(lptr, &request_list) {
- if (lptr == &we_p->liste) {
- list_del_init(lptr);
- requestq_count--;
- break;
- }
- }
- list_for_each(lptr, &pending_list) {
- if (lptr == &we_p->liste) {
- list_del_init(lptr);
- pendingq_count--;
- break;
- }
- }
- spin_unlock_irq(&queuespinlock);
-}
-
-/**
- * Build the request and send it.
- */
-static inline int
-z90crypt_rsa(struct priv_data *private_data_p, pid_t pid,
- unsigned int cmd, unsigned long arg)
-{
- struct work_element *we_p;
- int rv;
-
- if ((rv = allocate_work_element(&we_p, private_data_p, pid))) {
- PDEBUG("PID %d: allocate_work_element returned ENOMEM\n", pid);
- return rv;
- }
- if ((rv = z90crypt_prepare(we_p, cmd, (const char __user *)arg)))
- PDEBUG("PID %d: rv = %d from z90crypt_prepare\n", pid, rv);
- if (!rv)
- if ((rv = z90crypt_send(we_p, (const char *)arg)))
- PDEBUG("PID %d: rv %d from z90crypt_send.\n", pid, rv);
- if (!rv) {
- we_p->audit[0] |= FP_ASLEEP;
- wait_event(we_p->waitq, atomic_read(&we_p->alarmrung));
- we_p->audit[0] |= FP_AWAKE;
- rv = we_p->retcode;
- }
- if (!rv)
- rv = z90crypt_process_results(we_p, (char __user *)arg);
-
- if ((we_p->status[0] & STAT_FAILED)) {
- switch (rv) {
- /**
- * EINVAL *after* receive is almost always a padding error or
- * length error issued by a coprocessor (not an accelerator).
- * We convert this return value to -EGETBUFF which should
- * trigger a fallback to software.
- */
- case -EINVAL:
- if ((we_p->devtype != PCICA) &&
- (we_p->devtype != CEX2A))
- rv = -EGETBUFF;
- break;
- case -ETIMEOUT:
- if (z90crypt.mask.st_count > 0)
- rv = -ERESTARTSYS; // retry with another
- else
- rv = -ENODEV; // no cards left
- /* fall through to clean up request queue */
- case -ERESTARTSYS:
- case -ERELEASED:
- switch (CHK_RDWRMASK(we_p->status[0])) {
- case STAT_WRITTEN:
- purge_work_element(we_p);
- break;
- case STAT_READPEND:
- case STAT_NOWORK:
- default:
- break;
- }
- break;
- default:
- we_p->status[0] ^= STAT_FAILED;
- break;
- }
- }
- free_page((long)we_p);
- return rv;
-}
-
-/**
- * This function is a little long, but it's really just one large switch
- * statement.
- */
-static long
-z90crypt_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
-{
- struct priv_data *private_data_p = filp->private_data;
- unsigned char *status;
- unsigned char *qdepth;
- unsigned int *reqcnt;
- struct ica_z90_status *pstat;
- int ret, i, loopLim, tempstat;
- static int deprecated_msg_count1 = 0;
- static int deprecated_msg_count2 = 0;
-
- PDEBUG("filp %p (PID %d), cmd 0x%08X\n", filp, PID(), cmd);
- PDEBUG("cmd 0x%08X: dir %s, size 0x%04X, type 0x%02X, nr 0x%02X\n",
- cmd,
- !_IOC_DIR(cmd) ? "NO"
- : ((_IOC_DIR(cmd) == (_IOC_READ|_IOC_WRITE)) ? "RW"
- : ((_IOC_DIR(cmd) == _IOC_READ) ? "RD"
- : "WR")),
- _IOC_SIZE(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd));
-
- if (_IOC_TYPE(cmd) != Z90_IOCTL_MAGIC) {
- PRINTK("cmd 0x%08X contains bad magic\n", cmd);
- return -ENOTTY;
- }
-
- ret = 0;
- switch (cmd) {
- case ICARSAMODEXPO:
- case ICARSACRT:
- if (quiesce_z90crypt) {
- ret = -EQUIESCE;
- break;
- }
- ret = -ENODEV; // Default if no devices
- loopLim = z90crypt.hdware_info->hdware_mask.st_count -
- (z90crypt.hdware_info->hdware_mask.disabled_count +
- z90crypt.hdware_info->hdware_mask.user_disabled_count);
- for (i = 0; i < loopLim; i++) {
- ret = z90crypt_rsa(private_data_p, PID(), cmd, arg);
- if (ret != -ERESTARTSYS)
- break;
- }
- if (ret == -ERESTARTSYS)
- ret = -ENODEV;
- break;
-
- case Z90STAT_TOTALCOUNT:
- tempstat = get_status_totalcount();
- if (copy_to_user((int __user *)arg, &tempstat,sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_PCICACOUNT:
- tempstat = get_status_PCICAcount();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_PCICCCOUNT:
- tempstat = get_status_PCICCcount();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_PCIXCCMCL2COUNT:
- tempstat = get_status_PCIXCCMCL2count();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_PCIXCCMCL3COUNT:
- tempstat = get_status_PCIXCCMCL3count();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_CEX2CCOUNT:
- tempstat = get_status_CEX2Ccount();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_CEX2ACOUNT:
- tempstat = get_status_CEX2Acount();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_REQUESTQ_COUNT:
- tempstat = get_status_requestq_count();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_PENDINGQ_COUNT:
- tempstat = get_status_pendingq_count();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_TOTALOPEN_COUNT:
- tempstat = get_status_totalopen_count();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_DOMAIN_INDEX:
- tempstat = get_status_domain_index();
- if (copy_to_user((int __user *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90STAT_STATUS_MASK:
- status = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
- if (!status) {
- PRINTK("kmalloc for status failed!\n");
- ret = -ENOMEM;
- break;
- }
- get_status_status_mask(status);
- if (copy_to_user((char __user *) arg, status, Z90CRYPT_NUM_APS)
- != 0)
- ret = -EFAULT;
- kfree(status);
- break;
-
- case Z90STAT_QDEPTH_MASK:
- qdepth = kmalloc(Z90CRYPT_NUM_APS, GFP_KERNEL);
- if (!qdepth) {
- PRINTK("kmalloc for qdepth failed!\n");
- ret = -ENOMEM;
- break;
- }
- get_status_qdepth_mask(qdepth);
- if (copy_to_user((char __user *) arg, qdepth, Z90CRYPT_NUM_APS) != 0)
- ret = -EFAULT;
- kfree(qdepth);
- break;
-
- case Z90STAT_PERDEV_REQCNT:
- reqcnt = kmalloc(sizeof(int) * Z90CRYPT_NUM_APS, GFP_KERNEL);
- if (!reqcnt) {
- PRINTK("kmalloc for reqcnt failed!\n");
- ret = -ENOMEM;
- break;
- }
- get_status_perdevice_reqcnt(reqcnt);
- if (copy_to_user((char __user *) arg, reqcnt,
- Z90CRYPT_NUM_APS * sizeof(int)) != 0)
- ret = -EFAULT;
- kfree(reqcnt);
- break;
-
- /* THIS IS DEPRECATED. USE THE NEW STATUS CALLS */
- case ICAZ90STATUS:
- if (deprecated_msg_count1 < 20) {
- PRINTK("deprecated call to ioctl (ICAZ90STATUS)!\n");
- deprecated_msg_count1++;
- if (deprecated_msg_count1 == 20)
- PRINTK("No longer issuing messages related to "
- "deprecated call to ICAZ90STATUS.\n");
- }
-
- pstat = kmalloc(sizeof(struct ica_z90_status), GFP_KERNEL);
- if (!pstat) {
- PRINTK("kmalloc for pstat failed!\n");
- ret = -ENOMEM;
- break;
- }
-
- pstat->totalcount = get_status_totalcount();
- pstat->leedslitecount = get_status_PCICAcount();
- pstat->leeds2count = get_status_PCICCcount();
- pstat->requestqWaitCount = get_status_requestq_count();
- pstat->pendingqWaitCount = get_status_pendingq_count();
- pstat->totalOpenCount = get_status_totalopen_count();
- pstat->cryptoDomain = get_status_domain_index();
- get_status_status_mask(pstat->status);
- get_status_qdepth_mask(pstat->qdepth);
-
- if (copy_to_user((struct ica_z90_status __user *) arg, pstat,
- sizeof(struct ica_z90_status)) != 0)
- ret = -EFAULT;
- kfree(pstat);
- break;
-
- /* THIS IS DEPRECATED. USE THE NEW STATUS CALLS */
- case Z90STAT_PCIXCCCOUNT:
- if (deprecated_msg_count2 < 20) {
- PRINTK("deprecated ioctl (Z90STAT_PCIXCCCOUNT)!\n");
- deprecated_msg_count2++;
- if (deprecated_msg_count2 == 20)
- PRINTK("No longer issuing messages about depre"
- "cated ioctl Z90STAT_PCIXCCCOUNT.\n");
- }
-
- tempstat = get_status_PCIXCCcount();
- if (copy_to_user((int *)arg, &tempstat, sizeof(int)) != 0)
- ret = -EFAULT;
- break;
-
- case Z90QUIESCE:
- if (current->euid != 0) {
- PRINTK("QUIESCE fails: euid %d\n",
- current->euid);
- ret = -EACCES;
- } else {
- PRINTK("QUIESCE device from PID %d\n", PID());
- quiesce_z90crypt = 1;
- }
- break;
-
- default:
- /* user passed an invalid IOCTL number */
- PDEBUG("cmd 0x%08X contains invalid ioctl code\n", cmd);
- ret = -ENOTTY;
- break;
- }
-
- return ret;
-}
-
-static inline int
-sprintcl(unsigned char *outaddr, unsigned char *addr, unsigned int len)
-{
- int hl, i;
-
- hl = 0;
- for (i = 0; i < len; i++)
- hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
- hl += sprintf(outaddr+hl, " ");
-
- return hl;
-}
-
-static inline int
-sprintrw(unsigned char *outaddr, unsigned char *addr, unsigned int len)
-{
- int hl, inl, c, cx;
-
- hl = sprintf(outaddr, " ");
- inl = 0;
- for (c = 0; c < (len / 16); c++) {
- hl += sprintcl(outaddr+hl, addr+inl, 16);
- inl += 16;
- }
-
- cx = len%16;
- if (cx) {
- hl += sprintcl(outaddr+hl, addr+inl, cx);
- inl += cx;
- }
-
- hl += sprintf(outaddr+hl, "\n");
-
- return hl;
-}
-
-static inline int
-sprinthx(unsigned char *title, unsigned char *outaddr,
- unsigned char *addr, unsigned int len)
-{
- int hl, inl, r, rx;
-
- hl = sprintf(outaddr, "\n%s\n", title);
- inl = 0;
- for (r = 0; r < (len / 64); r++) {
- hl += sprintrw(outaddr+hl, addr+inl, 64);
- inl += 64;
- }
- rx = len % 64;
- if (rx) {
- hl += sprintrw(outaddr+hl, addr+inl, rx);
- inl += rx;
- }
-
- hl += sprintf(outaddr+hl, "\n");
-
- return hl;
-}
-
-static inline int
-sprinthx4(unsigned char *title, unsigned char *outaddr,
- unsigned int *array, unsigned int len)
-{
- int hl, r;
-
- hl = sprintf(outaddr, "\n%s\n", title);
-
- for (r = 0; r < len; r++) {
- if ((r % 8) == 0)
- hl += sprintf(outaddr+hl, " ");
- hl += sprintf(outaddr+hl, "%08X ", array[r]);
- if ((r % 8) == 7)
- hl += sprintf(outaddr+hl, "\n");
- }
-
- hl += sprintf(outaddr+hl, "\n");
-
- return hl;
-}
-
-static int
-z90crypt_status(char *resp_buff, char **start, off_t offset,
- int count, int *eof, void *data)
-{
- unsigned char *workarea;
- int len;
-
- /* resp_buff is a page. Use the right half for a work area */
- workarea = resp_buff+2000;
- len = 0;
- len += sprintf(resp_buff+len, "\nz90crypt version: %d.%d.%d\n",
- z90crypt_VERSION, z90crypt_RELEASE, z90crypt_VARIANT);
- len += sprintf(resp_buff+len, "Cryptographic domain: %d\n",
- get_status_domain_index());
- len += sprintf(resp_buff+len, "Total device count: %d\n",
- get_status_totalcount());
- len += sprintf(resp_buff+len, "PCICA count: %d\n",
- get_status_PCICAcount());
- len += sprintf(resp_buff+len, "PCICC count: %d\n",
- get_status_PCICCcount());
- len += sprintf(resp_buff+len, "PCIXCC MCL2 count: %d\n",
- get_status_PCIXCCMCL2count());
- len += sprintf(resp_buff+len, "PCIXCC MCL3 count: %d\n",
- get_status_PCIXCCMCL3count());
- len += sprintf(resp_buff+len, "CEX2C count: %d\n",
- get_status_CEX2Ccount());
- len += sprintf(resp_buff+len, "CEX2A count: %d\n",
- get_status_CEX2Acount());
- len += sprintf(resp_buff+len, "requestq count: %d\n",
- get_status_requestq_count());
- len += sprintf(resp_buff+len, "pendingq count: %d\n",
- get_status_pendingq_count());
- len += sprintf(resp_buff+len, "Total open handles: %d\n\n",
- get_status_totalopen_count());
- len += sprinthx(
- "Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
- "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
- resp_buff+len,
- get_status_status_mask(workarea),
- Z90CRYPT_NUM_APS);
- len += sprinthx("Waiting work element counts",
- resp_buff+len,
- get_status_qdepth_mask(workarea),
- Z90CRYPT_NUM_APS);
- len += sprinthx4(
- "Per-device successfully completed request counts",
- resp_buff+len,
- get_status_perdevice_reqcnt((unsigned int *)workarea),
- Z90CRYPT_NUM_APS);
- *eof = 1;
- memset(workarea, 0, Z90CRYPT_NUM_APS * sizeof(unsigned int));
- return len;
-}
-
-static inline void
-disable_card(int card_index)
-{
- struct device *devp;
-
- devp = LONG2DEVPTR(card_index);
- if (!devp || devp->user_disabled)
- return;
- devp->user_disabled = 1;
- z90crypt.hdware_info->hdware_mask.user_disabled_count++;
- if (devp->dev_type == -1)
- return;
- z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count++;
-}
-
-static inline void
-enable_card(int card_index)
-{
- struct device *devp;
-
- devp = LONG2DEVPTR(card_index);
- if (!devp || !devp->user_disabled)
- return;
- devp->user_disabled = 0;
- z90crypt.hdware_info->hdware_mask.user_disabled_count--;
- if (devp->dev_type == -1)
- return;
- z90crypt.hdware_info->type_mask[devp->dev_type].user_disabled_count--;
-}
-
-static int
-z90crypt_status_write(struct file *file, const char __user *buffer,
- unsigned long count, void *data)
-{
- int j, eol;
- unsigned char *lbuf, *ptr;
- unsigned int local_count;
-
-#define LBUFSIZE 1200
- lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
- if (!lbuf) {
- PRINTK("kmalloc failed!\n");
- return 0;
- }
-
- if (count <= 0)
- return 0;
-
- local_count = UMIN((unsigned int)count, LBUFSIZE-1);
-
- if (copy_from_user(lbuf, buffer, local_count) != 0) {
- kfree(lbuf);
- return -EFAULT;
- }
-
- lbuf[local_count] = '\0';
-
- ptr = strstr(lbuf, "Online devices");
- if (ptr == 0) {
- PRINTK("Unable to parse data (missing \"Online devices\")\n");
- kfree(lbuf);
- return count;
- }
-
- ptr = strstr(ptr, "\n");
- if (ptr == 0) {
- PRINTK("Unable to parse data (missing newline after \"Online devices\")\n");
- kfree(lbuf);
- return count;
- }
- ptr++;
-
- if (strstr(ptr, "Waiting work element counts") == NULL) {
- PRINTK("Unable to parse data (missing \"Waiting work element counts\")\n");
- kfree(lbuf);
- return count;
- }
-
- j = 0;
- eol = 0;
- while ((j < 64) && (*ptr != '\0')) {
- switch (*ptr) {
- case '\t':
- case ' ':
- break;
- case '\n':
- default:
- eol = 1;
- break;
- case '0': // no device
- case '1': // PCICA
- case '2': // PCICC
- case '3': // PCIXCC_MCL2
- case '4': // PCIXCC_MCL3
- case '5': // CEX2C
- case '6': // CEX2A
- j++;
- break;
- case 'd':
- case 'D':
- disable_card(j);
- j++;
- break;
- case 'e':
- case 'E':
- enable_card(j);
- j++;
- break;
- }
- if (eol)
- break;
- ptr++;
- }
-
- kfree(lbuf);
- return count;
-}
-
-/**
- * Functions that run under a timer, with no process id
- *
- * The task functions:
- * z90crypt_reader_task
- * helper_send_work
- * helper_handle_work_element
- * helper_receive_rc
- * z90crypt_config_task
- * z90crypt_cleanup_task
- *
- * Helper functions:
- * z90crypt_schedule_reader_timer
- * z90crypt_schedule_reader_task
- * z90crypt_schedule_config_task
- * z90crypt_schedule_cleanup_task
- */
-static inline int
-receive_from_crypto_device(int index, unsigned char *psmid, int *buff_len_p,
- unsigned char *buff, unsigned char __user **dest_p_p)
-{
- int dv, rv;
- struct device *dev_ptr;
- struct caller *caller_p;
- struct ica_rsa_modexpo *icaMsg_p;
- struct list_head *ptr, *tptr;
-
- memcpy(psmid, NULL_psmid, sizeof(NULL_psmid));
-
- if (z90crypt.terminating)
- return REC_FATAL_ERROR;
-
- caller_p = 0;
- dev_ptr = z90crypt.device_p[index];
- rv = 0;
- do {
- if (!dev_ptr || dev_ptr->disabled) {
- rv = REC_NO_WORK; // a disabled device can't return work
- break;
- }
- if (dev_ptr->dev_self_x != index) {
- PRINTKC("Corrupt dev ptr\n");
- z90crypt.terminating = 1;
- rv = REC_FATAL_ERROR;
- break;
- }
- if (!dev_ptr->dev_resp_l || !dev_ptr->dev_resp_p) {
- dv = DEV_REC_EXCEPTION;
- PRINTK("dev_resp_l = %d, dev_resp_p = %p\n",
- dev_ptr->dev_resp_l, dev_ptr->dev_resp_p);
- } else {
- PDEBUG("Dequeue called for device %d\n", index);
- dv = receive_from_AP(index, z90crypt.cdx,
- dev_ptr->dev_resp_l,
- dev_ptr->dev_resp_p, psmid);
- }
- switch (dv) {
- case DEV_REC_EXCEPTION:
- rv = REC_FATAL_ERROR;
- z90crypt.terminating = 1;
- PRINTKC("Exception in receive from device %d\n",
- index);
- break;
- case DEV_ONLINE:
- rv = 0;
- break;
- case DEV_EMPTY:
- rv = REC_EMPTY;
- break;
- case DEV_NO_WORK:
- rv = REC_NO_WORK;
- break;
- case DEV_BAD_MESSAGE:
- case DEV_GONE:
- case REC_HARDWAR_ERR:
- default:
- rv = REC_NO_RESPONSE;
- break;
- }
- if (rv)
- break;
- if (dev_ptr->dev_caller_count <= 0) {
- rv = REC_USER_GONE;
- break;
- }
-
- list_for_each_safe(ptr, tptr, &dev_ptr->dev_caller_list) {
- caller_p = list_entry(ptr, struct caller, caller_liste);
- if (!memcmp(caller_p->caller_id, psmid,
- sizeof(caller_p->caller_id))) {
- if (!list_empty(&caller_p->caller_liste)) {
- list_del_init(ptr);
- dev_ptr->dev_caller_count--;
- break;
- }
- }
- caller_p = 0;
- }
- if (!caller_p) {
- PRINTKW("Unable to locate PSMID %02X%02X%02X%02X%02X"
- "%02X%02X%02X in device list\n",
- psmid[0], psmid[1], psmid[2], psmid[3],
- psmid[4], psmid[5], psmid[6], psmid[7]);
- rv = REC_USER_GONE;
- break;
- }
-
- PDEBUG("caller_p after successful receive: %p\n", caller_p);
- rv = convert_response(dev_ptr->dev_resp_p,
- caller_p->caller_buf_p, buff_len_p, buff);
- switch (rv) {
- case REC_USE_PCICA:
- break;
- case REC_OPERAND_INV:
- case REC_OPERAND_SIZE:
- case REC_EVEN_MOD:
- case REC_INVALID_PAD:
- PDEBUG("device %d: 'user error' %d\n", index, rv);
- break;
- case WRONG_DEVICE_TYPE:
- case REC_HARDWAR_ERR:
- case REC_BAD_MESSAGE:
- PRINTKW("device %d: hardware error %d\n", index, rv);
- rv = REC_NO_RESPONSE;
- break;
- default:
- PDEBUG("device %d: rv = %d\n", index, rv);
- break;
- }
- } while (0);
-
- switch (rv) {
- case 0:
- PDEBUG("Successful receive from device %d\n", index);
- icaMsg_p = (struct ica_rsa_modexpo *)caller_p->caller_buf_p;
- *dest_p_p = icaMsg_p->outputdata;
- if (*buff_len_p == 0)
- PRINTK("Zero *buff_len_p\n");
- break;
- case REC_NO_RESPONSE:
- PRINTKW("Removing device %d from availability\n", index);
- remove_device(dev_ptr);
- break;
- }
-
- if (caller_p)
- unbuild_caller(dev_ptr, caller_p);
-
- return rv;
-}
-
-static inline void
-helper_send_work(int index)
-{
- struct work_element *rq_p;
- int rv;
-
- if (list_empty(&request_list))
- return;
- requestq_count--;
- rq_p = list_entry(request_list.next, struct work_element, liste);
- list_del_init(&rq_p->liste);
- rq_p->audit[1] |= FP_REMREQUEST;
- if (rq_p->devtype == SHRT2DEVPTR(index)->dev_type) {
- rq_p->devindex = SHRT2LONG(index);
- rv = send_to_crypto_device(rq_p);
- if (rv == 0) {
- rq_p->requestsent = jiffies;
- rq_p->audit[0] |= FP_SENT;
- list_add_tail(&rq_p->liste, &pending_list);
- ++pendingq_count;
- rq_p->audit[0] |= FP_PENDING;
- } else {
- switch (rv) {
- case REC_OPERAND_INV:
- case REC_OPERAND_SIZE:
- case REC_EVEN_MOD:
- case REC_INVALID_PAD:
- rq_p->retcode = -EINVAL;
- break;
- case SEN_NOT_AVAIL:
- case SEN_RETRY:
- case REC_NO_RESPONSE:
- default:
- if (z90crypt.mask.st_count > 1)
- rq_p->retcode =
- -ERESTARTSYS;
- else
- rq_p->retcode = -ENODEV;
- break;
- }
- rq_p->status[0] |= STAT_FAILED;
- rq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&rq_p->alarmrung, 1);
- wake_up(&rq_p->waitq);
- }
- } else {
- if (z90crypt.mask.st_count > 1)
- rq_p->retcode = -ERESTARTSYS;
- else
- rq_p->retcode = -ENODEV;
- rq_p->status[0] |= STAT_FAILED;
- rq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&rq_p->alarmrung, 1);
- wake_up(&rq_p->waitq);
- }
-}
-
-static inline void
-helper_handle_work_element(int index, unsigned char psmid[8], int rc,
- int buff_len, unsigned char *buff,
- unsigned char __user *resp_addr)
-{
- struct work_element *pq_p;
- struct list_head *lptr, *tptr;
-
- pq_p = 0;
- list_for_each_safe(lptr, tptr, &pending_list) {
- pq_p = list_entry(lptr, struct work_element, liste);
- if (!memcmp(pq_p->caller_id, psmid, sizeof(pq_p->caller_id))) {
- list_del_init(lptr);
- pendingq_count--;
- pq_p->audit[1] |= FP_NOTPENDING;
- break;
- }
- pq_p = 0;
- }
-
- if (!pq_p) {
- PRINTK("device %d has work but no caller exists on pending Q\n",
- SHRT2LONG(index));
- return;
- }
-
- switch (rc) {
- case 0:
- pq_p->resp_buff_size = buff_len;
- pq_p->audit[1] |= FP_RESPSIZESET;
- if (buff_len) {
- pq_p->resp_addr = resp_addr;
- pq_p->audit[1] |= FP_RESPADDRCOPIED;
- memcpy(pq_p->resp_buff, buff, buff_len);
- pq_p->audit[1] |= FP_RESPBUFFCOPIED;
- }
- break;
- case REC_OPERAND_INV:
- case REC_OPERAND_SIZE:
- case REC_EVEN_MOD:
- case REC_INVALID_PAD:
- PDEBUG("-EINVAL after application error %d\n", rc);
- pq_p->retcode = -EINVAL;
- pq_p->status[0] |= STAT_FAILED;
- break;
- case REC_USE_PCICA:
- pq_p->retcode = -ERESTARTSYS;
- pq_p->status[0] |= STAT_FAILED;
- break;
- case REC_NO_RESPONSE:
- default:
- if (z90crypt.mask.st_count > 1)
- pq_p->retcode = -ERESTARTSYS;
- else
- pq_p->retcode = -ENODEV;
- pq_p->status[0] |= STAT_FAILED;
- break;
- }
- if ((pq_p->status[0] != STAT_FAILED) || (pq_p->retcode != -ERELEASED)) {
- pq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&pq_p->alarmrung, 1);
- wake_up(&pq_p->waitq);
- }
-}
-
-/**
- * return TRUE if the work element should be removed from the queue
- */
-static inline int
-helper_receive_rc(int index, int *rc_p)
-{
- switch (*rc_p) {
- case 0:
- case REC_OPERAND_INV:
- case REC_OPERAND_SIZE:
- case REC_EVEN_MOD:
- case REC_INVALID_PAD:
- case REC_USE_PCICA:
- break;
-
- case REC_BUSY:
- case REC_NO_WORK:
- case REC_EMPTY:
- case REC_RETRY_DEV:
- case REC_FATAL_ERROR:
- return 0;
-
- case REC_NO_RESPONSE:
- break;
-
- default:
- PRINTK("rc %d, device %d converted to REC_NO_RESPONSE\n",
- *rc_p, SHRT2LONG(index));
- *rc_p = REC_NO_RESPONSE;
- break;
- }
- return 1;
-}
-
-static inline void
-z90crypt_schedule_reader_timer(void)
-{
- if (timer_pending(&reader_timer))
- return;
- if (mod_timer(&reader_timer, jiffies+(READERTIME*HZ/1000)) != 0)
- PRINTK("Timer pending while modifying reader timer\n");
-}
-
-static void
-z90crypt_reader_task(unsigned long ptr)
-{
- int workavail, index, rc, buff_len;
- unsigned char psmid[8];
- unsigned char __user *resp_addr;
- static unsigned char buff[1024];
-
- /**
- * we use workavail = 2 to ensure 2 passes with nothing dequeued before
- * exiting the loop. If (pendingq_count+requestq_count) == 0 after the
- * loop, there is no work remaining on the queues.
- */
- resp_addr = 0;
- workavail = 2;
- buff_len = 0;
- while (workavail) {
- workavail--;
- rc = 0;
- spin_lock_irq(&queuespinlock);
- memset(buff, 0x00, sizeof(buff));
-
- /* Dequeue once from each device in round robin. */
- for (index = 0; index < z90crypt.mask.st_count; index++) {
- PDEBUG("About to receive.\n");
- rc = receive_from_crypto_device(SHRT2LONG(index),
- psmid,
- &buff_len,
- buff,
- &resp_addr);
- PDEBUG("Dequeued: rc = %d.\n", rc);
-
- if (helper_receive_rc(index, &rc)) {
- if (rc != REC_NO_RESPONSE) {
- helper_send_work(index);
- workavail = 2;
- }
-
- helper_handle_work_element(index, psmid, rc,
- buff_len, buff,
- resp_addr);
- }
-
- if (rc == REC_FATAL_ERROR)
- PRINTKW("REC_FATAL_ERROR from device %d!\n",
- SHRT2LONG(index));
- }
- spin_unlock_irq(&queuespinlock);
- }
-
- if (pendingq_count + requestq_count)
- z90crypt_schedule_reader_timer();
-}
-
-static inline void
-z90crypt_schedule_config_task(unsigned int expiration)
-{
- if (timer_pending(&config_timer))
- return;
- if (mod_timer(&config_timer, jiffies+(expiration*HZ)) != 0)
- PRINTK("Timer pending while modifying config timer\n");
-}
-
-static void
-z90crypt_config_task(unsigned long ptr)
-{
- int rc;
-
- PDEBUG("jiffies %ld\n", jiffies);
-
- if ((rc = refresh_z90crypt(&z90crypt.cdx)))
- PRINTK("Error %d detected in refresh_z90crypt.\n", rc);
- /* If return was fatal, don't bother reconfiguring */
- if ((rc != TSQ_FATAL_ERROR) && (rc != RSQ_FATAL_ERROR))
- z90crypt_schedule_config_task(CONFIGTIME);
-}
-
-static inline void
-z90crypt_schedule_cleanup_task(void)
-{
- if (timer_pending(&cleanup_timer))
- return;
- if (mod_timer(&cleanup_timer, jiffies+(CLEANUPTIME*HZ)) != 0)
- PRINTK("Timer pending while modifying cleanup timer\n");
-}
-
-static inline void
-helper_drain_queues(void)
-{
- struct work_element *pq_p;
- struct list_head *lptr, *tptr;
-
- list_for_each_safe(lptr, tptr, &pending_list) {
- pq_p = list_entry(lptr, struct work_element, liste);
- pq_p->retcode = -ENODEV;
- pq_p->status[0] |= STAT_FAILED;
- unbuild_caller(LONG2DEVPTR(pq_p->devindex),
- (struct caller *)pq_p->requestptr);
- list_del_init(lptr);
- pendingq_count--;
- pq_p->audit[1] |= FP_NOTPENDING;
- pq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&pq_p->alarmrung, 1);
- wake_up(&pq_p->waitq);
- }
-
- list_for_each_safe(lptr, tptr, &request_list) {
- pq_p = list_entry(lptr, struct work_element, liste);
- pq_p->retcode = -ENODEV;
- pq_p->status[0] |= STAT_FAILED;
- list_del_init(lptr);
- requestq_count--;
- pq_p->audit[1] |= FP_REMREQUEST;
- pq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&pq_p->alarmrung, 1);
- wake_up(&pq_p->waitq);
- }
-}
-
-static inline void
-helper_timeout_requests(void)
-{
- struct work_element *pq_p;
- struct list_head *lptr, *tptr;
- long timelimit;
-
- timelimit = jiffies - (CLEANUPTIME * HZ);
- /* The list is in strict chronological order */
- list_for_each_safe(lptr, tptr, &pending_list) {
- pq_p = list_entry(lptr, struct work_element, liste);
- if (pq_p->requestsent >= timelimit)
- break;
- PRINTKW("Purging(PQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
- ((struct caller *)pq_p->requestptr)->caller_id[0],
- ((struct caller *)pq_p->requestptr)->caller_id[1],
- ((struct caller *)pq_p->requestptr)->caller_id[2],
- ((struct caller *)pq_p->requestptr)->caller_id[3],
- ((struct caller *)pq_p->requestptr)->caller_id[4],
- ((struct caller *)pq_p->requestptr)->caller_id[5],
- ((struct caller *)pq_p->requestptr)->caller_id[6],
- ((struct caller *)pq_p->requestptr)->caller_id[7]);
- pq_p->retcode = -ETIMEOUT;
- pq_p->status[0] |= STAT_FAILED;
- /* get this off any caller queue it may be on */
- unbuild_caller(LONG2DEVPTR(pq_p->devindex),
- (struct caller *) pq_p->requestptr);
- list_del_init(lptr);
- pendingq_count--;
- pq_p->audit[1] |= FP_TIMEDOUT;
- pq_p->audit[1] |= FP_NOTPENDING;
- pq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&pq_p->alarmrung, 1);
- wake_up(&pq_p->waitq);
- }
-
- /**
- * If pending count is zero, items left on the request queue may
- * never be processed.
- */
- if (pendingq_count <= 0) {
- list_for_each_safe(lptr, tptr, &request_list) {
- pq_p = list_entry(lptr, struct work_element, liste);
- if (pq_p->requestsent >= timelimit)
- break;
- PRINTKW("Purging(RQ) PSMID %02X%02X%02X%02X%02X%02X%02X%02X\n",
- ((struct caller *)pq_p->requestptr)->caller_id[0],
- ((struct caller *)pq_p->requestptr)->caller_id[1],
- ((struct caller *)pq_p->requestptr)->caller_id[2],
- ((struct caller *)pq_p->requestptr)->caller_id[3],
- ((struct caller *)pq_p->requestptr)->caller_id[4],
- ((struct caller *)pq_p->requestptr)->caller_id[5],
- ((struct caller *)pq_p->requestptr)->caller_id[6],
- ((struct caller *)pq_p->requestptr)->caller_id[7]);
- pq_p->retcode = -ETIMEOUT;
- pq_p->status[0] |= STAT_FAILED;
- list_del_init(lptr);
- requestq_count--;
- pq_p->audit[1] |= FP_TIMEDOUT;
- pq_p->audit[1] |= FP_REMREQUEST;
- pq_p->audit[1] |= FP_AWAKENING;
- atomic_set(&pq_p->alarmrung, 1);
- wake_up(&pq_p->waitq);
- }
- }
-}
-
-static void
-z90crypt_cleanup_task(unsigned long ptr)
-{
- PDEBUG("jiffies %ld\n", jiffies);
- spin_lock_irq(&queuespinlock);
- if (z90crypt.mask.st_count <= 0) // no devices!
- helper_drain_queues();
- else
- helper_timeout_requests();
- spin_unlock_irq(&queuespinlock);
- z90crypt_schedule_cleanup_task();
-}
-
-static void
-z90crypt_schedule_reader_task(unsigned long ptr)
-{
- tasklet_schedule(&reader_tasklet);
-}
-
-/**
- * Lowlevel Functions:
- *
- * create_z90crypt: creates and initializes basic data structures
- * refresh_z90crypt: re-initializes basic data structures
- * find_crypto_devices: returns a count and mask of hardware status
- * create_crypto_device: builds the descriptor for a device
- * destroy_crypto_device: unallocates the descriptor for a device
- * destroy_z90crypt: drains all work, unallocates structs
- */
-
-/**
- * build the z90crypt root structure using the given domain index
- */
-static int
-create_z90crypt(int *cdx_p)
-{
- struct hdware_block *hdware_blk_p;
-
- memset(&z90crypt, 0x00, sizeof(struct z90crypt));
- z90crypt.domain_established = 0;
- z90crypt.len = sizeof(struct z90crypt);
- z90crypt.max_count = Z90CRYPT_NUM_DEVS;
- z90crypt.cdx = *cdx_p;
-
- hdware_blk_p = kzalloc(sizeof(struct hdware_block), GFP_ATOMIC);
- if (!hdware_blk_p) {
- PDEBUG("kmalloc for hardware block failed\n");
- return ENOMEM;
- }
- z90crypt.hdware_info = hdware_blk_p;
-
- return 0;
-}
-
-static inline int
-helper_scan_devices(int cdx_array[16], int *cdx_p, int *correct_cdx_found)
-{
- enum hdstat hd_stat;
- int q_depth, dev_type;
- int indx, chkdom, numdomains;
-
- q_depth = dev_type = numdomains = 0;
- for (chkdom = 0; chkdom <= 15; cdx_array[chkdom++] = -1);
- for (indx = 0; indx < z90crypt.max_count; indx++) {
- hd_stat = HD_NOT_THERE;
- numdomains = 0;
- for (chkdom = 0; chkdom <= 15; chkdom++) {
- hd_stat = query_online(indx, chkdom, MAX_RESET,
- &q_depth, &dev_type);
- if (hd_stat == HD_TSQ_EXCEPTION) {
- z90crypt.terminating = 1;
- PRINTKC("exception taken!\n");
- break;
- }
- if (hd_stat == HD_ONLINE) {
- cdx_array[numdomains++] = chkdom;
- if (*cdx_p == chkdom) {
- *correct_cdx_found = 1;
- break;
- }
- }
- }
- if ((*correct_cdx_found == 1) || (numdomains != 0))
- break;
- if (z90crypt.terminating)
- break;
- }
- return numdomains;
-}
-
-static inline int
-probe_crypto_domain(int *cdx_p)
-{
- int cdx_array[16];
- char cdx_array_text[53], temp[5];
- int correct_cdx_found, numdomains;
-
- correct_cdx_found = 0;
- numdomains = helper_scan_devices(cdx_array, cdx_p, &correct_cdx_found);
-
- if (z90crypt.terminating)
- return TSQ_FATAL_ERROR;
-
- if (correct_cdx_found)
- return 0;
-
- if (numdomains == 0) {
- PRINTKW("Unable to find crypto domain: No devices found\n");
- return Z90C_NO_DEVICES;
- }
-
- if (numdomains == 1) {
- if (*cdx_p == -1) {
- *cdx_p = cdx_array[0];
- return 0;
- }
- PRINTKW("incorrect domain: specified = %d, found = %d\n",
- *cdx_p, cdx_array[0]);
- return Z90C_INCORRECT_DOMAIN;
- }
-
- numdomains--;
- sprintf(cdx_array_text, "%d", cdx_array[numdomains]);
- while (numdomains) {
- numdomains--;
- sprintf(temp, ", %d", cdx_array[numdomains]);
- strcat(cdx_array_text, temp);
- }
-
- PRINTKW("ambiguous domain detected: specified = %d, found array = %s\n",
- *cdx_p, cdx_array_text);
- return Z90C_AMBIGUOUS_DOMAIN;
-}
-
-static int
-refresh_z90crypt(int *cdx_p)
-{
- int i, j, indx, rv;
- static struct status local_mask;
- struct device *devPtr;
- unsigned char oldStat, newStat;
- int return_unchanged;
-
- if (z90crypt.len != sizeof(z90crypt))
- return ENOTINIT;
- if (z90crypt.terminating)
- return TSQ_FATAL_ERROR;
- rv = 0;
- if (!z90crypt.hdware_info->hdware_mask.st_count &&
- !z90crypt.domain_established) {
- rv = probe_crypto_domain(cdx_p);
- if (z90crypt.terminating)
- return TSQ_FATAL_ERROR;
- if (rv == Z90C_NO_DEVICES)
- return 0; // try later
- if (rv)
- return rv;
- z90crypt.cdx = *cdx_p;
- z90crypt.domain_established = 1;
- }
- rv = find_crypto_devices(&local_mask);
- if (rv) {
- PRINTK("find crypto devices returned %d\n", rv);
- return rv;
- }
- if (!memcmp(&local_mask, &z90crypt.hdware_info->hdware_mask,
- sizeof(struct status))) {
- return_unchanged = 1;
- for (i = 0; i < Z90CRYPT_NUM_TYPES; i++) {
- /**
- * Check for disabled cards. If any device is marked
- * disabled, destroy it.
- */
- for (j = 0;
- j < z90crypt.hdware_info->type_mask[i].st_count;
- j++) {
- indx = z90crypt.hdware_info->type_x_addr[i].
- device_index[j];
- devPtr = z90crypt.device_p[indx];
- if (devPtr && devPtr->disabled) {
- local_mask.st_mask[indx] = HD_NOT_THERE;
- return_unchanged = 0;
- }
- }
- }
- if (return_unchanged == 1)
- return 0;
- }
-
- spin_lock_irq(&queuespinlock);
- for (i = 0; i < z90crypt.max_count; i++) {
- oldStat = z90crypt.hdware_info->hdware_mask.st_mask[i];
- newStat = local_mask.st_mask[i];
- if ((oldStat == HD_ONLINE) && (newStat != HD_ONLINE))
- destroy_crypto_device(i);
- else if ((oldStat != HD_ONLINE) && (newStat == HD_ONLINE)) {
- rv = create_crypto_device(i);
- if (rv >= REC_FATAL_ERROR)
- return rv;
- if (rv != 0) {
- local_mask.st_mask[i] = HD_NOT_THERE;
- local_mask.st_count--;
- }
- }
- }
- memcpy(z90crypt.hdware_info->hdware_mask.st_mask, local_mask.st_mask,
- sizeof(local_mask.st_mask));
- z90crypt.hdware_info->hdware_mask.st_count = local_mask.st_count;
- z90crypt.hdware_info->hdware_mask.disabled_count =
- local_mask.disabled_count;
- refresh_index_array(&z90crypt.mask, &z90crypt.overall_device_x);
- for (i = 0; i < Z90CRYPT_NUM_TYPES; i++)
- refresh_index_array(&(z90crypt.hdware_info->type_mask[i]),
- &(z90crypt.hdware_info->type_x_addr[i]));
- spin_unlock_irq(&queuespinlock);
-
- return rv;
-}
-
-static int
-find_crypto_devices(struct status *deviceMask)
-{
- int i, q_depth, dev_type;
- enum hdstat hd_stat;
-
- deviceMask->st_count = 0;
- deviceMask->disabled_count = 0;
- deviceMask->user_disabled_count = 0;
-
- for (i = 0; i < z90crypt.max_count; i++) {
- hd_stat = query_online(i, z90crypt.cdx, MAX_RESET, &q_depth,
- &dev_type);
- if (hd_stat == HD_TSQ_EXCEPTION) {
- z90crypt.terminating = 1;
- PRINTKC("Exception during probe for crypto devices\n");
- return TSQ_FATAL_ERROR;
- }
- deviceMask->st_mask[i] = hd_stat;
- if (hd_stat == HD_ONLINE) {
- PDEBUG("Got an online crypto!: %d\n", i);
- PDEBUG("Got a queue depth of %d\n", q_depth);
- PDEBUG("Got a device type of %d\n", dev_type);
- if (q_depth <= 0)
- return TSQ_FATAL_ERROR;
- deviceMask->st_count++;
- z90crypt.q_depth_array[i] = q_depth;
- z90crypt.dev_type_array[i] = dev_type;
- }
- }
-
- return 0;
-}
-
-static int
-refresh_index_array(struct status *status_str, struct device_x *index_array)
-{
- int i, count;
- enum devstat stat;
-
- i = -1;
- count = 0;
- do {
- stat = status_str->st_mask[++i];
- if (stat == DEV_ONLINE)
- index_array->device_index[count++] = i;
- } while ((i < Z90CRYPT_NUM_DEVS) && (count < status_str->st_count));
-
- return count;
-}
-
-static int
-create_crypto_device(int index)
-{
- int rv, devstat, total_size;
- struct device *dev_ptr;
- struct status *type_str_p;
- int deviceType;
-
- dev_ptr = z90crypt.device_p[index];
- if (!dev_ptr) {
- total_size = sizeof(struct device) +
- z90crypt.q_depth_array[index] * sizeof(int);
-
- dev_ptr = kzalloc(total_size, GFP_ATOMIC);
- if (!dev_ptr) {
- PRINTK("kmalloc device %d failed\n", index);
- return ENOMEM;
- }
- dev_ptr->dev_resp_p = kmalloc(MAX_RESPONSE_SIZE, GFP_ATOMIC);
- if (!dev_ptr->dev_resp_p) {
- kfree(dev_ptr);
- PRINTK("kmalloc device %d rec buffer failed\n", index);
- return ENOMEM;
- }
- dev_ptr->dev_resp_l = MAX_RESPONSE_SIZE;
- INIT_LIST_HEAD(&(dev_ptr->dev_caller_list));
- }
-
- devstat = reset_device(index, z90crypt.cdx, MAX_RESET);
- if (devstat == DEV_RSQ_EXCEPTION) {
- PRINTK("exception during reset device %d\n", index);
- kfree(dev_ptr->dev_resp_p);
- kfree(dev_ptr);
- return RSQ_FATAL_ERROR;
- }
- if (devstat == DEV_ONLINE) {
- dev_ptr->dev_self_x = index;
- dev_ptr->dev_type = z90crypt.dev_type_array[index];
- if (dev_ptr->dev_type == NILDEV) {
- rv = probe_device_type(dev_ptr);
- if (rv) {
- PRINTK("rv = %d from probe_device_type %d\n",
- rv, index);
- kfree(dev_ptr->dev_resp_p);
- kfree(dev_ptr);
- return rv;
- }
- }
- if (dev_ptr->dev_type == PCIXCC_UNK) {
- rv = probe_PCIXCC_type(dev_ptr);
- if (rv) {
- PRINTK("rv = %d from probe_PCIXCC_type %d\n",
- rv, index);
- kfree(dev_ptr->dev_resp_p);
- kfree(dev_ptr);
- return rv;
- }
- }
- deviceType = dev_ptr->dev_type;
- z90crypt.dev_type_array[index] = deviceType;
- if (deviceType == PCICA)
- z90crypt.hdware_info->device_type_array[index] = 1;
- else if (deviceType == PCICC)
- z90crypt.hdware_info->device_type_array[index] = 2;
- else if (deviceType == PCIXCC_MCL2)
- z90crypt.hdware_info->device_type_array[index] = 3;
- else if (deviceType == PCIXCC_MCL3)
- z90crypt.hdware_info->device_type_array[index] = 4;
- else if (deviceType == CEX2C)
- z90crypt.hdware_info->device_type_array[index] = 5;
- else if (deviceType == CEX2A)
- z90crypt.hdware_info->device_type_array[index] = 6;
- else // No idea how this would happen.
- z90crypt.hdware_info->device_type_array[index] = -1;
- }
-
- /**
- * 'q_depth' returned by the hardware is one less than
- * the actual depth
- */
- dev_ptr->dev_q_depth = z90crypt.q_depth_array[index];
- dev_ptr->dev_type = z90crypt.dev_type_array[index];
- dev_ptr->dev_stat = devstat;
- dev_ptr->disabled = 0;
- z90crypt.device_p[index] = dev_ptr;
-
- if (devstat == DEV_ONLINE) {
- if (z90crypt.mask.st_mask[index] != DEV_ONLINE) {
- z90crypt.mask.st_mask[index] = DEV_ONLINE;
- z90crypt.mask.st_count++;
- }
- deviceType = dev_ptr->dev_type;
- type_str_p = &z90crypt.hdware_info->type_mask[deviceType];
- if (type_str_p->st_mask[index] != DEV_ONLINE) {
- type_str_p->st_mask[index] = DEV_ONLINE;
- type_str_p->st_count++;
- }
- }
-
- return 0;
-}
-
-static int
-destroy_crypto_device(int index)
-{
- struct device *dev_ptr;
- int t, disabledFlag;
-
- dev_ptr = z90crypt.device_p[index];
-
- /* remember device type; get rid of device struct */
- if (dev_ptr) {
- disabledFlag = dev_ptr->disabled;
- t = dev_ptr->dev_type;
- kfree(dev_ptr->dev_resp_p);
- kfree(dev_ptr);
- } else {
- disabledFlag = 0;
- t = -1;
- }
- z90crypt.device_p[index] = 0;
-
- /* if the type is valid, remove the device from the type_mask */
- if ((t != -1) && z90crypt.hdware_info->type_mask[t].st_mask[index]) {
- z90crypt.hdware_info->type_mask[t].st_mask[index] = 0x00;
- z90crypt.hdware_info->type_mask[t].st_count--;
- if (disabledFlag == 1)
- z90crypt.hdware_info->type_mask[t].disabled_count--;
- }
- if (z90crypt.mask.st_mask[index] != DEV_GONE) {
- z90crypt.mask.st_mask[index] = DEV_GONE;
- z90crypt.mask.st_count--;
- }
- z90crypt.hdware_info->device_type_array[index] = 0;
-
- return 0;
-}
-
-static void
-destroy_z90crypt(void)
-{
- int i;
-
- for (i = 0; i < z90crypt.max_count; i++)
- if (z90crypt.device_p[i])
- destroy_crypto_device(i);
- kfree(z90crypt.hdware_info);
- memset((void *)&z90crypt, 0, sizeof(z90crypt));
-}
-
-static unsigned char static_testmsg[384] = {
-0x00,0x00,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x00,0x06,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x58,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x43,0x43,
-0x41,0x2d,0x41,0x50,0x50,0x4c,0x20,0x20,0x20,0x01,0x01,0x01,0x00,0x00,0x00,0x00,
-0x50,0x4b,0x00,0x00,0x00,0x00,0x01,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x05,0xb8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x70,0x00,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x54,0x32,
-0x01,0x00,0xa0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0xb8,0x05,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x00,0x49,0x43,0x53,0x46,
-0x20,0x20,0x20,0x20,0x50,0x4b,0x0a,0x00,0x50,0x4b,0x43,0x53,0x2d,0x31,0x2e,0x32,
-0x37,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,
-0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,
-0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x44,0x55,0x66,
-0x77,0x88,0x99,0x00,0x11,0x22,0x33,0x5d,0x00,0x5b,0x00,0x77,0x88,0x1e,0x00,0x00,
-0x57,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x4f,0x00,0x00,0x00,0x03,0x02,0x00,0x00,
-0x40,0x01,0x00,0x01,0xce,0x02,0x68,0x2d,0x5f,0xa9,0xde,0x0c,0xf6,0xd2,0x7b,0x58,
-0x4b,0xf9,0x28,0x68,0x3d,0xb4,0xf4,0xef,0x78,0xd5,0xbe,0x66,0x63,0x42,0xef,0xf8,
-0xfd,0xa4,0xf8,0xb0,0x8e,0x29,0xc2,0xc9,0x2e,0xd8,0x45,0xb8,0x53,0x8c,0x6f,0x4e,
-0x72,0x8f,0x6c,0x04,0x9c,0x88,0xfc,0x1e,0xc5,0x83,0x55,0x57,0xf7,0xdd,0xfd,0x4f,
-0x11,0x36,0x95,0x5d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
-};
-
-static int
-probe_device_type(struct device *devPtr)
-{
- int rv, dv, i, index, length;
- unsigned char psmid[8];
- static unsigned char loc_testmsg[sizeof(static_testmsg)];
-
- index = devPtr->dev_self_x;
- rv = 0;
- do {
- memcpy(loc_testmsg, static_testmsg, sizeof(static_testmsg));
- length = sizeof(static_testmsg) - 24;
- /* the -24 allows for the header */
- dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
- if (dv) {
- PDEBUG("dv returned by send during probe: %d\n", dv);
- if (dv == DEV_SEN_EXCEPTION) {
- rv = SEN_FATAL_ERROR;
- PRINTKC("exception in send to AP %d\n", index);
- break;
- }
- PDEBUG("return value from send_to_AP: %d\n", rv);
- switch (dv) {
- case DEV_GONE:
- PDEBUG("dev %d not available\n", index);
- rv = SEN_NOT_AVAIL;
- break;
- case DEV_ONLINE:
- rv = 0;
- break;
- case DEV_EMPTY:
- rv = SEN_NOT_AVAIL;
- break;
- case DEV_NO_WORK:
- rv = SEN_FATAL_ERROR;
- break;
- case DEV_BAD_MESSAGE:
- rv = SEN_USER_ERROR;
- break;
- case DEV_QUEUE_FULL:
- rv = SEN_QUEUE_FULL;
- break;
- default:
- PRINTK("unknown dv=%d for dev %d\n", dv, index);
- rv = SEN_NOT_AVAIL;
- break;
- }
- }
-
- if (rv)
- break;
-
- for (i = 0; i < 6; i++) {
- mdelay(300);
- dv = receive_from_AP(index, z90crypt.cdx,
- devPtr->dev_resp_l,
- devPtr->dev_resp_p, psmid);
- PDEBUG("dv returned by DQ = %d\n", dv);
- if (dv == DEV_REC_EXCEPTION) {
- rv = REC_FATAL_ERROR;
- PRINTKC("exception in dequeue %d\n",
- index);
- break;
- }
- switch (dv) {
- case DEV_ONLINE:
- rv = 0;
- break;
- case DEV_EMPTY:
- rv = REC_EMPTY;
- break;
- case DEV_NO_WORK:
- rv = REC_NO_WORK;
- break;
- case DEV_BAD_MESSAGE:
- case DEV_GONE:
- default:
- rv = REC_NO_RESPONSE;
- break;
- }
- if ((rv != 0) && (rv != REC_NO_WORK))
- break;
- if (rv == 0)
- break;
- }
- if (rv)
- break;
- rv = (devPtr->dev_resp_p[0] == 0x00) &&
- (devPtr->dev_resp_p[1] == 0x86);
- if (rv)
- devPtr->dev_type = PCICC;
- else
- devPtr->dev_type = PCICA;
- rv = 0;
- } while (0);
- /* In a general error case, the card is not marked online */
- return rv;
-}
-
-static unsigned char MCL3_testmsg[] = {
-0x00,0x00,0x00,0x00,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
-0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
-0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
-0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
-0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
-0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
-0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
-0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
-0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
-0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
-0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
-0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
-0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
-0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
-0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
-0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,0xF1,0x3D,0x93,0x53
-};
-
-static int
-probe_PCIXCC_type(struct device *devPtr)
-{
- int rv, dv, i, index, length;
- unsigned char psmid[8];
- static unsigned char loc_testmsg[548];
- struct CPRBX *cprbx_p;
-
- index = devPtr->dev_self_x;
- rv = 0;
- do {
- memcpy(loc_testmsg, MCL3_testmsg, sizeof(MCL3_testmsg));
- length = sizeof(MCL3_testmsg) - 0x0C;
- dv = send_to_AP(index, z90crypt.cdx, length, loc_testmsg);
- if (dv) {
- PDEBUG("dv returned = %d\n", dv);
- if (dv == DEV_SEN_EXCEPTION) {
- rv = SEN_FATAL_ERROR;
- PRINTKC("exception in send to AP %d\n", index);
- break;
- }
- PDEBUG("return value from send_to_AP: %d\n", rv);
- switch (dv) {
- case DEV_GONE:
- PDEBUG("dev %d not available\n", index);
- rv = SEN_NOT_AVAIL;
- break;
- case DEV_ONLINE:
- rv = 0;
- break;
- case DEV_EMPTY:
- rv = SEN_NOT_AVAIL;
- break;
- case DEV_NO_WORK:
- rv = SEN_FATAL_ERROR;
- break;
- case DEV_BAD_MESSAGE:
- rv = SEN_USER_ERROR;
- break;
- case DEV_QUEUE_FULL:
- rv = SEN_QUEUE_FULL;
- break;
- default:
- PRINTK("unknown dv=%d for dev %d\n", dv, index);
- rv = SEN_NOT_AVAIL;
- break;
- }
- }
-
- if (rv)
- break;
-
- for (i = 0; i < 6; i++) {
- mdelay(300);
- dv = receive_from_AP(index, z90crypt.cdx,
- devPtr->dev_resp_l,
- devPtr->dev_resp_p, psmid);
- PDEBUG("dv returned by DQ = %d\n", dv);
- if (dv == DEV_REC_EXCEPTION) {
- rv = REC_FATAL_ERROR;
- PRINTKC("exception in dequeue %d\n",
- index);
- break;
- }
- switch (dv) {
- case DEV_ONLINE:
- rv = 0;
- break;
- case DEV_EMPTY:
- rv = REC_EMPTY;
- break;
- case DEV_NO_WORK:
- rv = REC_NO_WORK;
- break;
- case DEV_BAD_MESSAGE:
- case DEV_GONE:
- default:
- rv = REC_NO_RESPONSE;
- break;
- }
- if ((rv != 0) && (rv != REC_NO_WORK))
- break;
- if (rv == 0)
- break;
- }
- if (rv)
- break;
- cprbx_p = (struct CPRBX *) (devPtr->dev_resp_p + 48);
- if ((cprbx_p->ccp_rtcode == 8) && (cprbx_p->ccp_rscode == 33)) {
- devPtr->dev_type = PCIXCC_MCL2;
- PDEBUG("device %d is MCL2\n", index);
- } else {
- devPtr->dev_type = PCIXCC_MCL3;
- PDEBUG("device %d is MCL3\n", index);
- }
- } while (0);
- /* In a general error case, the card is not marked online */
- return rv;
-}
-
-module_init(z90crypt_init_module);
-module_exit(z90crypt_cleanup_module);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
new file mode 100644
index 00000000000..1edc10a7a6f
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -0,0 +1,1091 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_api.c
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ * Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/compat.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "zcrypt_api.h"
+
+/**
+ * Module description.
+ */
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("Cryptographic Coprocessor interface, "
+ "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+
+static DEFINE_SPINLOCK(zcrypt_device_lock);
+static LIST_HEAD(zcrypt_device_list);
+static int zcrypt_device_count = 0;
+static atomic_t zcrypt_open_count = ATOMIC_INIT(0);
+
+/**
+ * Device attributes common for all crypto devices.
+ */
+static ssize_t zcrypt_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zcrypt_device *zdev = to_ap_dev(dev)->private;
+ return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string);
+}
+
+static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL);
+
+static ssize_t zcrypt_online_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct zcrypt_device *zdev = to_ap_dev(dev)->private;
+ return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online);
+}
+
+static ssize_t zcrypt_online_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct zcrypt_device *zdev = to_ap_dev(dev)->private;
+ int online;
+
+ if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1)
+ return -EINVAL;
+ zdev->online = online;
+ if (!online)
+ ap_flush_queue(zdev->ap_dev);
+ return count;
+}
+
+static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store);
+
+static struct attribute * zcrypt_device_attrs[] = {
+ &dev_attr_type.attr,
+ &dev_attr_online.attr,
+ NULL,
+};
+
+static struct attribute_group zcrypt_device_attr_group = {
+ .attrs = zcrypt_device_attrs,
+};
+
+/**
+ * Move the device towards the head of the device list.
+ * Need to be called while holding the zcrypt device list lock.
+ * Note: cards with speed_rating of 0 are kept at the end of the list.
+ */
+static void __zcrypt_increase_preference(struct zcrypt_device *zdev)
+{
+ struct zcrypt_device *tmp;
+ struct list_head *l;
+
+ if (zdev->speed_rating == 0)
+ return;
+ for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) {
+ tmp = list_entry(l, struct zcrypt_device, list);
+ if ((tmp->request_count + 1) * tmp->speed_rating <=
+ (zdev->request_count + 1) * zdev->speed_rating &&
+ tmp->speed_rating != 0)
+ break;
+ }
+ if (l == zdev->list.prev)
+ return;
+ /* Move zdev behind l */
+ list_del(&zdev->list);
+ list_add(&zdev->list, l);
+}
+
+/**
+ * Move the device towards the tail of the device list.
+ * Need to be called while holding the zcrypt device list lock.
+ * Note: cards with speed_rating of 0 are kept at the end of the list.
+ */
+static void __zcrypt_decrease_preference(struct zcrypt_device *zdev)
+{
+ struct zcrypt_device *tmp;
+ struct list_head *l;
+
+ if (zdev->speed_rating == 0)
+ return;
+ for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) {
+ tmp = list_entry(l, struct zcrypt_device, list);
+ if ((tmp->request_count + 1) * tmp->speed_rating >
+ (zdev->request_count + 1) * zdev->speed_rating ||
+ tmp->speed_rating == 0)
+ break;
+ }
+ if (l == zdev->list.next)
+ return;
+ /* Move zdev before l */
+ list_del(&zdev->list);
+ list_add_tail(&zdev->list, l);
+}
+
+static void zcrypt_device_release(struct kref *kref)
+{
+ struct zcrypt_device *zdev =
+ container_of(kref, struct zcrypt_device, refcount);
+ zcrypt_device_free(zdev);
+}
+
+void zcrypt_device_get(struct zcrypt_device *zdev)
+{
+ kref_get(&zdev->refcount);
+}
+EXPORT_SYMBOL(zcrypt_device_get);
+
+int zcrypt_device_put(struct zcrypt_device *zdev)
+{
+ return kref_put(&zdev->refcount, zcrypt_device_release);
+}
+EXPORT_SYMBOL(zcrypt_device_put);
+
+struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size)
+{
+ struct zcrypt_device *zdev;
+
+ zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL);
+ if (!zdev)
+ return NULL;
+ zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL);
+ if (!zdev->reply.message)
+ goto out_free;
+ zdev->reply.length = max_response_size;
+ spin_lock_init(&zdev->lock);
+ INIT_LIST_HEAD(&zdev->list);
+ return zdev;
+
+out_free:
+ kfree(zdev);
+ return NULL;
+}
+EXPORT_SYMBOL(zcrypt_device_alloc);
+
+void zcrypt_device_free(struct zcrypt_device *zdev)
+{
+ kfree(zdev->reply.message);
+ kfree(zdev);
+}
+EXPORT_SYMBOL(zcrypt_device_free);
+
+/**
+ * Register a crypto device.
+ */
+int zcrypt_device_register(struct zcrypt_device *zdev)
+{
+ int rc;
+
+ rc = sysfs_create_group(&zdev->ap_dev->device.kobj,
+ &zcrypt_device_attr_group);
+ if (rc)
+ goto out;
+ get_device(&zdev->ap_dev->device);
+ kref_init(&zdev->refcount);
+ spin_lock_bh(&zcrypt_device_lock);
+ zdev->online = 1; /* New devices are online by default. */
+ list_add_tail(&zdev->list, &zcrypt_device_list);
+ __zcrypt_increase_preference(zdev);
+ zcrypt_device_count++;
+ spin_unlock_bh(&zcrypt_device_lock);
+out:
+ return rc;
+}
+EXPORT_SYMBOL(zcrypt_device_register);
+
+/**
+ * Unregister a crypto device.
+ */
+void zcrypt_device_unregister(struct zcrypt_device *zdev)
+{
+ spin_lock_bh(&zcrypt_device_lock);
+ zcrypt_device_count--;
+ list_del_init(&zdev->list);
+ spin_unlock_bh(&zcrypt_device_lock);
+ sysfs_remove_group(&zdev->ap_dev->device.kobj,
+ &zcrypt_device_attr_group);
+ put_device(&zdev->ap_dev->device);
+ zcrypt_device_put(zdev);
+}
+EXPORT_SYMBOL(zcrypt_device_unregister);
+
+/**
+ * zcrypt_read is not be supported beyond zcrypt 1.3.1
+ */
+static ssize_t zcrypt_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ return -EPERM;
+}
+
+/**
+ * Write is is not allowed
+ */
+static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ return -EPERM;
+}
+
+/**
+ * Device open/close functions to count number of users.
+ */
+static int zcrypt_open(struct inode *inode, struct file *filp)
+{
+ atomic_inc(&zcrypt_open_count);
+ return 0;
+}
+
+static int zcrypt_release(struct inode *inode, struct file *filp)
+{
+ atomic_dec(&zcrypt_open_count);
+ return 0;
+}
+
+/**
+ * zcrypt ioctls.
+ */
+static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
+{
+ struct zcrypt_device *zdev;
+ int rc;
+
+ if (mex->outputdatalength < mex->inputdatalength)
+ return -EINVAL;
+ /**
+ * As long as outputdatalength is big enough, we can set the
+ * outputdatalength equal to the inputdatalength, since that is the
+ * number of bytes we will copy in any case
+ */
+ mex->outputdatalength = mex->inputdatalength;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ if (!zdev->online ||
+ !zdev->ops->rsa_modexpo ||
+ zdev->min_mod_size > mex->inputdatalength ||
+ zdev->max_mod_size < mex->inputdatalength)
+ continue;
+ zcrypt_device_get(zdev);
+ get_device(&zdev->ap_dev->device);
+ zdev->request_count++;
+ __zcrypt_decrease_preference(zdev);
+ spin_unlock_bh(&zcrypt_device_lock);
+ if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
+ rc = zdev->ops->rsa_modexpo(zdev, mex);
+ module_put(zdev->ap_dev->drv->driver.owner);
+ }
+ else
+ rc = -EAGAIN;
+ spin_lock_bh(&zcrypt_device_lock);
+ zdev->request_count--;
+ __zcrypt_increase_preference(zdev);
+ put_device(&zdev->ap_dev->device);
+ zcrypt_device_put(zdev);
+ spin_unlock_bh(&zcrypt_device_lock);
+ return rc;
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+ return -ENODEV;
+}
+
+static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
+{
+ struct zcrypt_device *zdev;
+ unsigned long long z1, z2, z3;
+ int rc, copied;
+
+ if (crt->outputdatalength < crt->inputdatalength ||
+ (crt->inputdatalength & 1))
+ return -EINVAL;
+ /**
+ * As long as outputdatalength is big enough, we can set the
+ * outputdatalength equal to the inputdatalength, since that is the
+ * number of bytes we will copy in any case
+ */
+ crt->outputdatalength = crt->inputdatalength;
+
+ copied = 0;
+ restart:
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ if (!zdev->online ||
+ !zdev->ops->rsa_modexpo_crt ||
+ zdev->min_mod_size > crt->inputdatalength ||
+ zdev->max_mod_size < crt->inputdatalength)
+ continue;
+ if (zdev->short_crt && crt->inputdatalength > 240) {
+ /**
+ * Check inputdata for leading zeros for cards
+ * that can't handle np_prime, bp_key, or
+ * u_mult_inv > 128 bytes.
+ */
+ if (copied == 0) {
+ int len;
+ spin_unlock_bh(&zcrypt_device_lock);
+ /* len is max 256 / 2 - 120 = 8 */
+ len = crt->inputdatalength / 2 - 120;
+ z1 = z2 = z3 = 0;
+ if (copy_from_user(&z1, crt->np_prime, len) ||
+ copy_from_user(&z2, crt->bp_key, len) ||
+ copy_from_user(&z3, crt->u_mult_inv, len))
+ return -EFAULT;
+ copied = 1;
+ /**
+ * We have to restart device lookup -
+ * the device list may have changed by now.
+ */
+ goto restart;
+ }
+ if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL)
+ /* The device can't handle this request. */
+ continue;
+ }
+ zcrypt_device_get(zdev);
+ get_device(&zdev->ap_dev->device);
+ zdev->request_count++;
+ __zcrypt_decrease_preference(zdev);
+ spin_unlock_bh(&zcrypt_device_lock);
+ if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
+ rc = zdev->ops->rsa_modexpo_crt(zdev, crt);
+ module_put(zdev->ap_dev->drv->driver.owner);
+ }
+ else
+ rc = -EAGAIN;
+ spin_lock_bh(&zcrypt_device_lock);
+ zdev->request_count--;
+ __zcrypt_increase_preference(zdev);
+ put_device(&zdev->ap_dev->device);
+ zcrypt_device_put(zdev);
+ spin_unlock_bh(&zcrypt_device_lock);
+ return rc;
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+ return -ENODEV;
+}
+
+static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
+{
+ struct zcrypt_device *zdev;
+ int rc;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ if (!zdev->online || !zdev->ops->send_cprb ||
+ (xcRB->user_defined != AUTOSELECT &&
+ AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)
+ )
+ continue;
+ zcrypt_device_get(zdev);
+ get_device(&zdev->ap_dev->device);
+ zdev->request_count++;
+ __zcrypt_decrease_preference(zdev);
+ spin_unlock_bh(&zcrypt_device_lock);
+ if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
+ rc = zdev->ops->send_cprb(zdev, xcRB);
+ module_put(zdev->ap_dev->drv->driver.owner);
+ }
+ else
+ rc = -EAGAIN;
+ spin_lock_bh(&zcrypt_device_lock);
+ zdev->request_count--;
+ __zcrypt_increase_preference(zdev);
+ put_device(&zdev->ap_dev->device);
+ zcrypt_device_put(zdev);
+ spin_unlock_bh(&zcrypt_device_lock);
+ return rc;
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+ return -ENODEV;
+}
+
+static void zcrypt_status_mask(char status[AP_DEVICES])
+{
+ struct zcrypt_device *zdev;
+
+ memset(status, 0, sizeof(char) * AP_DEVICES);
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list)
+ status[AP_QID_DEVICE(zdev->ap_dev->qid)] =
+ zdev->online ? zdev->user_space_type : 0x0d;
+ spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES])
+{
+ struct zcrypt_device *zdev;
+
+ memset(qdepth, 0, sizeof(char) * AP_DEVICES);
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ spin_lock(&zdev->ap_dev->lock);
+ qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] =
+ zdev->ap_dev->pendingq_count +
+ zdev->ap_dev->requestq_count;
+ spin_unlock(&zdev->ap_dev->lock);
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES])
+{
+ struct zcrypt_device *zdev;
+
+ memset(reqcnt, 0, sizeof(int) * AP_DEVICES);
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ spin_lock(&zdev->ap_dev->lock);
+ reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] =
+ zdev->ap_dev->total_request_count;
+ spin_unlock(&zdev->ap_dev->lock);
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static int zcrypt_pendingq_count(void)
+{
+ struct zcrypt_device *zdev;
+ int pendingq_count = 0;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ spin_lock(&zdev->ap_dev->lock);
+ pendingq_count += zdev->ap_dev->pendingq_count;
+ spin_unlock(&zdev->ap_dev->lock);
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+ return pendingq_count;
+}
+
+static int zcrypt_requestq_count(void)
+{
+ struct zcrypt_device *zdev;
+ int requestq_count = 0;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list) {
+ spin_lock(&zdev->ap_dev->lock);
+ requestq_count += zdev->ap_dev->requestq_count;
+ spin_unlock(&zdev->ap_dev->lock);
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+ return requestq_count;
+}
+
+static int zcrypt_count_type(int type)
+{
+ struct zcrypt_device *zdev;
+ int device_count = 0;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list)
+ if (zdev->user_space_type == type)
+ device_count++;
+ spin_unlock_bh(&zcrypt_device_lock);
+ return device_count;
+}
+
+/**
+ * Old, deprecated combi status call.
+ */
+static long zcrypt_ica_status(struct file *filp, unsigned long arg)
+{
+ struct ica_z90_status *pstat;
+ int ret;
+
+ pstat = kzalloc(sizeof(*pstat), GFP_KERNEL);
+ if (!pstat)
+ return -ENOMEM;
+ pstat->totalcount = zcrypt_device_count;
+ pstat->leedslitecount = zcrypt_count_type(ZCRYPT_PCICA);
+ pstat->leeds2count = zcrypt_count_type(ZCRYPT_PCICC);
+ pstat->requestqWaitCount = zcrypt_requestq_count();
+ pstat->pendingqWaitCount = zcrypt_pendingq_count();
+ pstat->totalOpenCount = atomic_read(&zcrypt_open_count);
+ pstat->cryptoDomain = ap_domain_index;
+ zcrypt_status_mask(pstat->status);
+ zcrypt_qdepth_mask(pstat->qdepth);
+ ret = 0;
+ if (copy_to_user((void __user *) arg, pstat, sizeof(*pstat)))
+ ret = -EFAULT;
+ kfree(pstat);
+ return ret;
+}
+
+static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+
+ switch (cmd) {
+ case ICARSAMODEXPO: {
+ struct ica_rsa_modexpo __user *umex = (void __user *) arg;
+ struct ica_rsa_modexpo mex;
+ if (copy_from_user(&mex, umex, sizeof(mex)))
+ return -EFAULT;
+ do {
+ rc = zcrypt_rsa_modexpo(&mex);
+ } while (rc == -EAGAIN);
+ if (rc)
+ return rc;
+ return put_user(mex.outputdatalength, &umex->outputdatalength);
+ }
+ case ICARSACRT: {
+ struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg;
+ struct ica_rsa_modexpo_crt crt;
+ if (copy_from_user(&crt, ucrt, sizeof(crt)))
+ return -EFAULT;
+ do {
+ rc = zcrypt_rsa_crt(&crt);
+ } while (rc == -EAGAIN);
+ if (rc)
+ return rc;
+ return put_user(crt.outputdatalength, &ucrt->outputdatalength);
+ }
+ case ZSECSENDCPRB: {
+ struct ica_xcRB __user *uxcRB = (void __user *) arg;
+ struct ica_xcRB xcRB;
+ if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
+ return -EFAULT;
+ do {
+ rc = zcrypt_send_cprb(&xcRB);
+ } while (rc == -EAGAIN);
+ if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
+ return -EFAULT;
+ return rc;
+ }
+ case Z90STAT_STATUS_MASK: {
+ char status[AP_DEVICES];
+ zcrypt_status_mask(status);
+ if (copy_to_user((char __user *) arg, status,
+ sizeof(char) * AP_DEVICES))
+ return -EFAULT;
+ return 0;
+ }
+ case Z90STAT_QDEPTH_MASK: {
+ char qdepth[AP_DEVICES];
+ zcrypt_qdepth_mask(qdepth);
+ if (copy_to_user((char __user *) arg, qdepth,
+ sizeof(char) * AP_DEVICES))
+ return -EFAULT;
+ return 0;
+ }
+ case Z90STAT_PERDEV_REQCNT: {
+ int reqcnt[AP_DEVICES];
+ zcrypt_perdev_reqcnt(reqcnt);
+ if (copy_to_user((int __user *) arg, reqcnt,
+ sizeof(int) * AP_DEVICES))
+ return -EFAULT;
+ return 0;
+ }
+ case Z90STAT_REQUESTQ_COUNT:
+ return put_user(zcrypt_requestq_count(), (int __user *) arg);
+ case Z90STAT_PENDINGQ_COUNT:
+ return put_user(zcrypt_pendingq_count(), (int __user *) arg);
+ case Z90STAT_TOTALOPEN_COUNT:
+ return put_user(atomic_read(&zcrypt_open_count),
+ (int __user *) arg);
+ case Z90STAT_DOMAIN_INDEX:
+ return put_user(ap_domain_index, (int __user *) arg);
+ /**
+ * Deprecated ioctls. Don't add another device count ioctl,
+ * you can count them yourself in the user space with the
+ * output of the Z90STAT_STATUS_MASK ioctl.
+ */
+ case ICAZ90STATUS:
+ return zcrypt_ica_status(filp, arg);
+ case Z90STAT_TOTALCOUNT:
+ return put_user(zcrypt_device_count, (int __user *) arg);
+ case Z90STAT_PCICACOUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_PCICA),
+ (int __user *) arg);
+ case Z90STAT_PCICCCOUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_PCICC),
+ (int __user *) arg);
+ case Z90STAT_PCIXCCMCL2COUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2),
+ (int __user *) arg);
+ case Z90STAT_PCIXCCMCL3COUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL3),
+ (int __user *) arg);
+ case Z90STAT_PCIXCCCOUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_PCIXCC_MCL2) +
+ zcrypt_count_type(ZCRYPT_PCIXCC_MCL3),
+ (int __user *) arg);
+ case Z90STAT_CEX2CCOUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_CEX2C),
+ (int __user *) arg);
+ case Z90STAT_CEX2ACOUNT:
+ return put_user(zcrypt_count_type(ZCRYPT_CEX2A),
+ (int __user *) arg);
+ default:
+ /* unknown ioctl number */
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+/**
+ * ioctl32 conversion routines
+ */
+struct compat_ica_rsa_modexpo {
+ compat_uptr_t inputdata;
+ unsigned int inputdatalength;
+ compat_uptr_t outputdata;
+ unsigned int outputdatalength;
+ compat_uptr_t b_key;
+ compat_uptr_t n_modulus;
+};
+
+static long trans_modexpo32(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
+ struct compat_ica_rsa_modexpo mex32;
+ struct ica_rsa_modexpo mex64;
+ long rc;
+
+ if (copy_from_user(&mex32, umex32, sizeof(mex32)))
+ return -EFAULT;
+ mex64.inputdata = compat_ptr(mex32.inputdata);
+ mex64.inputdatalength = mex32.inputdatalength;
+ mex64.outputdata = compat_ptr(mex32.outputdata);
+ mex64.outputdatalength = mex32.outputdatalength;
+ mex64.b_key = compat_ptr(mex32.b_key);
+ mex64.n_modulus = compat_ptr(mex32.n_modulus);
+ do {
+ rc = zcrypt_rsa_modexpo(&mex64);
+ } while (rc == -EAGAIN);
+ if (!rc)
+ rc = put_user(mex64.outputdatalength,
+ &umex32->outputdatalength);
+ return rc;
+}
+
+struct compat_ica_rsa_modexpo_crt {
+ compat_uptr_t inputdata;
+ unsigned int inputdatalength;
+ compat_uptr_t outputdata;
+ unsigned int outputdatalength;
+ compat_uptr_t bp_key;
+ compat_uptr_t bq_key;
+ compat_uptr_t np_prime;
+ compat_uptr_t nq_prime;
+ compat_uptr_t u_mult_inv;
+};
+
+static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
+ struct compat_ica_rsa_modexpo_crt crt32;
+ struct ica_rsa_modexpo_crt crt64;
+ long rc;
+
+ if (copy_from_user(&crt32, ucrt32, sizeof(crt32)))
+ return -EFAULT;
+ crt64.inputdata = compat_ptr(crt32.inputdata);
+ crt64.inputdatalength = crt32.inputdatalength;
+ crt64.outputdata= compat_ptr(crt32.outputdata);
+ crt64.outputdatalength = crt32.outputdatalength;
+ crt64.bp_key = compat_ptr(crt32.bp_key);
+ crt64.bq_key = compat_ptr(crt32.bq_key);
+ crt64.np_prime = compat_ptr(crt32.np_prime);
+ crt64.nq_prime = compat_ptr(crt32.nq_prime);
+ crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
+ do {
+ rc = zcrypt_rsa_crt(&crt64);
+ } while (rc == -EAGAIN);
+ if (!rc)
+ rc = put_user(crt64.outputdatalength,
+ &ucrt32->outputdatalength);
+ return rc;
+}
+
+struct compat_ica_xcRB {
+ unsigned short agent_ID;
+ unsigned int user_defined;
+ unsigned short request_ID;
+ unsigned int request_control_blk_length;
+ unsigned char padding1[16 - sizeof (compat_uptr_t)];
+ compat_uptr_t request_control_blk_addr;
+ unsigned int request_data_length;
+ char padding2[16 - sizeof (compat_uptr_t)];
+ compat_uptr_t request_data_address;
+ unsigned int reply_control_blk_length;
+ char padding3[16 - sizeof (compat_uptr_t)];
+ compat_uptr_t reply_control_blk_addr;
+ unsigned int reply_data_length;
+ char padding4[16 - sizeof (compat_uptr_t)];
+ compat_uptr_t reply_data_addr;
+ unsigned short priority_window;
+ unsigned int status;
+} __attribute__((packed));
+
+static long trans_xcRB32(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
+ struct compat_ica_xcRB xcRB32;
+ struct ica_xcRB xcRB64;
+ long rc;
+
+ if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32)))
+ return -EFAULT;
+ xcRB64.agent_ID = xcRB32.agent_ID;
+ xcRB64.user_defined = xcRB32.user_defined;
+ xcRB64.request_ID = xcRB32.request_ID;
+ xcRB64.request_control_blk_length =
+ xcRB32.request_control_blk_length;
+ xcRB64.request_control_blk_addr =
+ compat_ptr(xcRB32.request_control_blk_addr);
+ xcRB64.request_data_length =
+ xcRB32.request_data_length;
+ xcRB64.request_data_address =
+ compat_ptr(xcRB32.request_data_address);
+ xcRB64.reply_control_blk_length =
+ xcRB32.reply_control_blk_length;
+ xcRB64.reply_control_blk_addr =
+ compat_ptr(xcRB32.reply_control_blk_addr);
+ xcRB64.reply_data_length = xcRB32.reply_data_length;
+ xcRB64.reply_data_addr =
+ compat_ptr(xcRB32.reply_data_addr);
+ xcRB64.priority_window = xcRB32.priority_window;
+ xcRB64.status = xcRB32.status;
+ do {
+ rc = zcrypt_send_cprb(&xcRB64);
+ } while (rc == -EAGAIN);
+ xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
+ xcRB32.reply_data_length = xcRB64.reply_data_length;
+ xcRB32.status = xcRB64.status;
+ if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32)))
+ return -EFAULT;
+ return rc;
+}
+
+long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ if (cmd == ICARSAMODEXPO)
+ return trans_modexpo32(filp, cmd, arg);
+ if (cmd == ICARSACRT)
+ return trans_modexpo_crt32(filp, cmd, arg);
+ if (cmd == ZSECSENDCPRB)
+ return trans_xcRB32(filp, cmd, arg);
+ return zcrypt_unlocked_ioctl(filp, cmd, arg);
+}
+#endif
+
+/**
+ * Misc device file operations.
+ */
+static struct file_operations zcrypt_fops = {
+ .owner = THIS_MODULE,
+ .read = zcrypt_read,
+ .write = zcrypt_write,
+ .unlocked_ioctl = zcrypt_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = zcrypt_compat_ioctl,
+#endif
+ .open = zcrypt_open,
+ .release = zcrypt_release
+};
+
+/**
+ * Misc device.
+ */
+static struct miscdevice zcrypt_misc_device = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "z90crypt",
+ .fops = &zcrypt_fops,
+};
+
+/**
+ * Deprecated /proc entry support.
+ */
+static struct proc_dir_entry *zcrypt_entry;
+
+static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
+{
+ int hl, i;
+
+ hl = 0;
+ for (i = 0; i < len; i++)
+ hl += sprintf(outaddr+hl, "%01x", (unsigned int) addr[i]);
+ hl += sprintf(outaddr+hl, " ");
+ return hl;
+}
+
+static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
+ unsigned int len)
+{
+ int hl, inl, c, cx;
+
+ hl = sprintf(outaddr, " ");
+ inl = 0;
+ for (c = 0; c < (len / 16); c++) {
+ hl += sprintcl(outaddr+hl, addr+inl, 16);
+ inl += 16;
+ }
+ cx = len%16;
+ if (cx) {
+ hl += sprintcl(outaddr+hl, addr+inl, cx);
+ inl += cx;
+ }
+ hl += sprintf(outaddr+hl, "\n");
+ return hl;
+}
+
+static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
+ unsigned char *addr, unsigned int len)
+{
+ int hl, inl, r, rx;
+
+ hl = sprintf(outaddr, "\n%s\n", title);
+ inl = 0;
+ for (r = 0; r < (len / 64); r++) {
+ hl += sprintrw(outaddr+hl, addr+inl, 64);
+ inl += 64;
+ }
+ rx = len % 64;
+ if (rx) {
+ hl += sprintrw(outaddr+hl, addr+inl, rx);
+ inl += rx;
+ }
+ hl += sprintf(outaddr+hl, "\n");
+ return hl;
+}
+
+static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
+ unsigned int *array, unsigned int len)
+{
+ int hl, r;
+
+ hl = sprintf(outaddr, "\n%s\n", title);
+ for (r = 0; r < len; r++) {
+ if ((r % 8) == 0)
+ hl += sprintf(outaddr+hl, " ");
+ hl += sprintf(outaddr+hl, "%08X ", array[r]);
+ if ((r % 8) == 7)
+ hl += sprintf(outaddr+hl, "\n");
+ }
+ hl += sprintf(outaddr+hl, "\n");
+ return hl;
+}
+
+static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ unsigned char *workarea;
+ int len;
+
+ len = 0;
+
+ /* resp_buff is a page. Use the right half for a work area */
+ workarea = resp_buff + 2000;
+ len += sprintf(resp_buff + len, "\nzcrypt version: %d.%d.%d\n",
+ ZCRYPT_VERSION, ZCRYPT_RELEASE, ZCRYPT_VARIANT);
+ len += sprintf(resp_buff + len, "Cryptographic domain: %d\n",
+ ap_domain_index);
+ len += sprintf(resp_buff + len, "Total device count: %d\n",
+ zcrypt_device_count);
+ len += sprintf(resp_buff + len, "PCICA count: %d\n",
+ zcrypt_count_type(ZCRYPT_PCICA));
+ len += sprintf(resp_buff + len, "PCICC count: %d\n",
+ zcrypt_count_type(ZCRYPT_PCICC));
+ len += sprintf(resp_buff + len, "PCIXCC MCL2 count: %d\n",
+ zcrypt_count_type(ZCRYPT_PCIXCC_MCL2));
+ len += sprintf(resp_buff + len, "PCIXCC MCL3 count: %d\n",
+ zcrypt_count_type(ZCRYPT_PCIXCC_MCL3));
+ len += sprintf(resp_buff + len, "CEX2C count: %d\n",
+ zcrypt_count_type(ZCRYPT_CEX2C));
+ len += sprintf(resp_buff + len, "CEX2A count: %d\n",
+ zcrypt_count_type(ZCRYPT_CEX2A));
+ len += sprintf(resp_buff + len, "requestq count: %d\n",
+ zcrypt_requestq_count());
+ len += sprintf(resp_buff + len, "pendingq count: %d\n",
+ zcrypt_pendingq_count());
+ len += sprintf(resp_buff + len, "Total open handles: %d\n\n",
+ atomic_read(&zcrypt_open_count));
+ zcrypt_status_mask(workarea);
+ len += sprinthx("Online devices: 1=PCICA 2=PCICC 3=PCIXCC(MCL2) "
+ "4=PCIXCC(MCL3) 5=CEX2C 6=CEX2A",
+ resp_buff+len, workarea, AP_DEVICES);
+ zcrypt_qdepth_mask(workarea);
+ len += sprinthx("Waiting work element counts",
+ resp_buff+len, workarea, AP_DEVICES);
+ zcrypt_perdev_reqcnt((unsigned int *) workarea);
+ len += sprinthx4("Per-device successfully completed request counts",
+ resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
+ *eof = 1;
+ memset((void *) workarea, 0x00, AP_DEVICES * sizeof(unsigned int));
+ return len;
+}
+
+static void zcrypt_disable_card(int index)
+{
+ struct zcrypt_device *zdev;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list)
+ if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
+ zdev->online = 0;
+ ap_flush_queue(zdev->ap_dev);
+ break;
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static void zcrypt_enable_card(int index)
+{
+ struct zcrypt_device *zdev;
+
+ spin_lock_bh(&zcrypt_device_lock);
+ list_for_each_entry(zdev, &zcrypt_device_list, list)
+ if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) {
+ zdev->online = 1;
+ break;
+ }
+ spin_unlock_bh(&zcrypt_device_lock);
+}
+
+static int zcrypt_status_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ unsigned char *lbuf, *ptr;
+ unsigned long local_count;
+ int j;
+
+ if (count <= 0)
+ return 0;
+
+#define LBUFSIZE 1200UL
+ lbuf = kmalloc(LBUFSIZE, GFP_KERNEL);
+ if (!lbuf) {
+ PRINTK("kmalloc failed!\n");
+ return 0;
+ }
+
+ local_count = min(LBUFSIZE - 1, count);
+ if (copy_from_user(lbuf, buffer, local_count) != 0) {
+ kfree(lbuf);
+ return -EFAULT;
+ }
+ lbuf[local_count] = '\0';
+
+ ptr = strstr(lbuf, "Online devices");
+ if (!ptr) {
+ PRINTK("Unable to parse data (missing \"Online devices\")\n");
+ goto out;
+ }
+ ptr = strstr(ptr, "\n");
+ if (!ptr) {
+ PRINTK("Unable to parse data (missing newline "
+ "after \"Online devices\")\n");
+ goto out;
+ }
+ ptr++;
+
+ if (strstr(ptr, "Waiting work element counts") == NULL) {
+ PRINTK("Unable to parse data (missing "
+ "\"Waiting work element counts\")\n");
+ goto out;
+ }
+
+ for (j = 0; j < 64 && *ptr; ptr++) {
+ /**
+ * '0' for no device, '1' for PCICA, '2' for PCICC,
+ * '3' for PCIXCC_MCL2, '4' for PCIXCC_MCL3,
+ * '5' for CEX2C and '6' for CEX2A'
+ */
+ if (*ptr >= '0' && *ptr <= '6')
+ j++;
+ else if (*ptr == 'd' || *ptr == 'D')
+ zcrypt_disable_card(j++);
+ else if (*ptr == 'e' || *ptr == 'E')
+ zcrypt_enable_card(j++);
+ else if (*ptr != ' ' && *ptr != '\t')
+ break;
+ }
+out:
+ kfree(lbuf);
+ return count;
+}
+
+/**
+ * The module initialization code.
+ */
+int __init zcrypt_api_init(void)
+{
+ int rc;
+
+ /* Register the request sprayer. */
+ rc = misc_register(&zcrypt_misc_device);
+ if (rc < 0) {
+ PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n",
+ zcrypt_misc_device.minor, rc);
+ goto out;
+ }
+
+ /* Set up the proc file system */
+ zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL);
+ if (!zcrypt_entry) {
+ PRINTK("Couldn't create z90crypt proc entry\n");
+ rc = -ENOMEM;
+ goto out_misc;
+ }
+ zcrypt_entry->nlink = 1;
+ zcrypt_entry->data = NULL;
+ zcrypt_entry->read_proc = zcrypt_status_read;
+ zcrypt_entry->write_proc = zcrypt_status_write;
+
+ return 0;
+
+out_misc:
+ misc_deregister(&zcrypt_misc_device);
+out:
+ return rc;
+}
+
+/**
+ * The module termination code.
+ */
+void zcrypt_api_exit(void)
+{
+ remove_proc_entry("driver/z90crypt", NULL);
+ misc_deregister(&zcrypt_misc_device);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_api_init);
+module_exit(zcrypt_api_exit);
+#endif
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
new file mode 100644
index 00000000000..de4877ee618
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -0,0 +1,141 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_api.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ * Cornelia Huck <cornelia.huck@de.ibm.com>
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_API_H_
+#define _ZCRYPT_API_H_
+
+/**
+ * Macro definitions
+ *
+ * PDEBUG debugs in the form "zcrypt: function_name -> message"
+ *
+ * PRINTK is like PDEBUG, except that it is always enabled
+ * PRINTKN is like PRINTK, except that it does not include the function name
+ * PRINTKW is like PRINTK, except that it uses KERN_WARNING
+ * PRINTKC is like PRINTK, except that it uses KERN_CRIT
+ */
+#define DEV_NAME "zcrypt"
+
+#define PRINTK(fmt, args...) \
+ printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#define PRINTKN(fmt, args...) \
+ printk(KERN_DEBUG DEV_NAME ": " fmt, ## args)
+#define PRINTKW(fmt, args...) \
+ printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#define PRINTKC(fmt, args...) \
+ printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+
+#ifdef ZCRYPT_DEBUG
+#define PDEBUG(fmt, args...) \
+ printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __FUNCTION__ , ## args)
+#else
+#define PDEBUG(fmt, args...) do {} while (0)
+#endif
+
+#include "ap_bus.h"
+#include <asm/zcrypt.h>
+
+/* deprecated status calls */
+#define ICAZ90STATUS _IOR(ZCRYPT_IOCTL_MAGIC, 0x10, struct ica_z90_status)
+#define Z90STAT_PCIXCCCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x43, int)
+
+/**
+ * This structure is deprecated and the corresponding ioctl() has been
+ * replaced with individual ioctl()s for each piece of data!
+ */
+struct ica_z90_status {
+ int totalcount;
+ int leedslitecount; // PCICA
+ int leeds2count; // PCICC
+ // int PCIXCCCount; is not in struct for backward compatibility
+ int requestqWaitCount;
+ int pendingqWaitCount;
+ int totalOpenCount;
+ int cryptoDomain;
+ // status: 0=not there, 1=PCICA, 2=PCICC, 3=PCIXCC_MCL2, 4=PCIXCC_MCL3,
+ // 5=CEX2C
+ unsigned char status[64];
+ // qdepth: # work elements waiting for each device
+ unsigned char qdepth[64];
+};
+
+/**
+ * device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2,
+ * PCIXCC_MCL3, CEX2C, or CEX2A
+ *
+ * NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed
+ * Internal Code (LIC) (EC J12220 level 29).
+ * PCIXCC_MCL2 refers to any LIC before this level.
+ */
+#define ZCRYPT_PCICA 1
+#define ZCRYPT_PCICC 2
+#define ZCRYPT_PCIXCC_MCL2 3
+#define ZCRYPT_PCIXCC_MCL3 4
+#define ZCRYPT_CEX2C 5
+#define ZCRYPT_CEX2A 6
+
+struct zcrypt_device;
+
+struct zcrypt_ops {
+ long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
+ long (*rsa_modexpo_crt)(struct zcrypt_device *,
+ struct ica_rsa_modexpo_crt *);
+ long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *);
+};
+
+struct zcrypt_device {
+ struct list_head list; /* Device list. */
+ spinlock_t lock; /* Per device lock. */
+ struct kref refcount; /* device refcounting */
+ struct ap_device *ap_dev; /* The "real" ap device. */
+ struct zcrypt_ops *ops; /* Crypto operations. */
+ int online; /* User online/offline */
+
+ int user_space_type; /* User space device id. */
+ char *type_string; /* User space device name. */
+ int min_mod_size; /* Min number of bits. */
+ int max_mod_size; /* Max number of bits. */
+ int short_crt; /* Card has crt length restriction. */
+ int speed_rating; /* Speed of the crypto device. */
+
+ int request_count; /* # current requests. */
+
+ struct ap_message reply; /* Per-device reply structure. */
+};
+
+struct zcrypt_device *zcrypt_device_alloc(size_t);
+void zcrypt_device_free(struct zcrypt_device *);
+void zcrypt_device_get(struct zcrypt_device *);
+int zcrypt_device_put(struct zcrypt_device *);
+int zcrypt_device_register(struct zcrypt_device *);
+void zcrypt_device_unregister(struct zcrypt_device *);
+int zcrypt_api_init(void);
+void zcrypt_api_exit(void);
+
+#endif /* _ZCRYPT_API_H_ */
diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h
new file mode 100644
index 00000000000..8dbcf0eef3e
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_cca_key.h
@@ -0,0 +1,350 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_cca_key.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_CCA_KEY_H_
+#define _ZCRYPT_CCA_KEY_H_
+
+struct T6_keyBlock_hdr {
+ unsigned short blen;
+ unsigned short ulen;
+ unsigned short flags;
+};
+
+/**
+ * mapping for the cca private ME key token.
+ * Three parts of interest here: the header, the private section and
+ * the public section.
+ *
+ * mapping for the cca key token header
+ */
+struct cca_token_hdr {
+ unsigned char token_identifier;
+ unsigned char version;
+ unsigned short token_length;
+ unsigned char reserved[4];
+} __attribute__((packed));
+
+#define CCA_TKN_HDR_ID_EXT 0x1E
+
+/**
+ * mapping for the cca private ME section
+ */
+struct cca_private_ext_ME_sec {
+ unsigned char section_identifier;
+ unsigned char version;
+ unsigned short section_length;
+ unsigned char private_key_hash[20];
+ unsigned char reserved1[4];
+ unsigned char key_format;
+ unsigned char reserved2;
+ unsigned char key_name_hash[20];
+ unsigned char key_use_flags[4];
+ unsigned char reserved3[6];
+ unsigned char reserved4[24];
+ unsigned char confounder[24];
+ unsigned char exponent[128];
+ unsigned char modulus[128];
+} __attribute__((packed));
+
+#define CCA_PVT_USAGE_ALL 0x80
+
+/**
+ * mapping for the cca public section
+ * In a private key, the modulus doesn't appear in the public
+ * section. So, an arbitrary public exponent of 0x010001 will be
+ * used, for a section length of 0x0F always.
+ */
+struct cca_public_sec {
+ unsigned char section_identifier;
+ unsigned char version;
+ unsigned short section_length;
+ unsigned char reserved[2];
+ unsigned short exponent_len;
+ unsigned short modulus_bit_len;
+ unsigned short modulus_byte_len; /* In a private key, this is 0 */
+} __attribute__((packed));
+
+/**
+ * mapping for the cca private CRT key 'token'
+ * The first three parts (the only parts considered in this release)
+ * are: the header, the private section and the public section.
+ * The header and public section are the same as for the
+ * struct cca_private_ext_ME
+ *
+ * Following the structure are the quantities p, q, dp, dq, u, pad,
+ * and modulus, in that order, where pad_len is the modulo 8
+ * complement of the residue modulo 8 of the sum of
+ * (p_len + q_len + dp_len + dq_len + u_len).
+ */
+struct cca_pvt_ext_CRT_sec {
+ unsigned char section_identifier;
+ unsigned char version;
+ unsigned short section_length;
+ unsigned char private_key_hash[20];
+ unsigned char reserved1[4];
+ unsigned char key_format;
+ unsigned char reserved2;
+ unsigned char key_name_hash[20];
+ unsigned char key_use_flags[4];
+ unsigned short p_len;
+ unsigned short q_len;
+ unsigned short dp_len;
+ unsigned short dq_len;
+ unsigned short u_len;
+ unsigned short mod_len;
+ unsigned char reserved3[4];
+ unsigned short pad_len;
+ unsigned char reserved4[52];
+ unsigned char confounder[8];
+} __attribute__((packed));
+
+#define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08
+#define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40
+
+/**
+ * Set up private key fields of a type6 MEX message.
+ * Note that all numerics in the key token are big-endian,
+ * while the entries in the key block header are little-endian.
+ *
+ * @mex: pointer to user input data
+ * @p: pointer to memory area for the key
+ *
+ * Returns the size of the key area or -EFAULT
+ */
+static inline int zcrypt_type6_mex_key_de(struct ica_rsa_modexpo *mex,
+ void *p, int big_endian)
+{
+ static struct cca_token_hdr static_pvt_me_hdr = {
+ .token_identifier = 0x1E,
+ .token_length = 0x0183,
+ };
+ static struct cca_private_ext_ME_sec static_pvt_me_sec = {
+ .section_identifier = 0x02,
+ .section_length = 0x016C,
+ .key_use_flags = {0x80,0x00,0x00,0x00},
+ };
+ static struct cca_public_sec static_pub_me_sec = {
+ .section_identifier = 0x04,
+ .section_length = 0x000F,
+ .exponent_len = 0x0003,
+ };
+ static char pk_exponent[3] = { 0x01, 0x00, 0x01 };
+ struct {
+ struct T6_keyBlock_hdr t6_hdr;
+ struct cca_token_hdr pvtMeHdr;
+ struct cca_private_ext_ME_sec pvtMeSec;
+ struct cca_public_sec pubMeSec;
+ char exponent[3];
+ } __attribute__((packed)) *key = p;
+ unsigned char *temp;
+
+ memset(key, 0, sizeof(*key));
+
+ if (big_endian) {
+ key->t6_hdr.blen = cpu_to_be16(0x189);
+ key->t6_hdr.ulen = cpu_to_be16(0x189 - 2);
+ } else {
+ key->t6_hdr.blen = cpu_to_le16(0x189);
+ key->t6_hdr.ulen = cpu_to_le16(0x189 - 2);
+ }
+ key->pvtMeHdr = static_pvt_me_hdr;
+ key->pvtMeSec = static_pvt_me_sec;
+ key->pubMeSec = static_pub_me_sec;
+ /**
+ * In a private key, the modulus doesn't appear in the public
+ * section. So, an arbitrary public exponent of 0x010001 will be
+ * used.
+ */
+ memcpy(key->exponent, pk_exponent, 3);
+
+ /* key parameter block */
+ temp = key->pvtMeSec.exponent +
+ sizeof(key->pvtMeSec.exponent) - mex->inputdatalength;
+ if (copy_from_user(temp, mex->b_key, mex->inputdatalength))
+ return -EFAULT;
+
+ /* modulus */
+ temp = key->pvtMeSec.modulus +
+ sizeof(key->pvtMeSec.modulus) - mex->inputdatalength;
+ if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength))
+ return -EFAULT;
+ key->pubMeSec.modulus_bit_len = 8 * mex->inputdatalength;
+ return sizeof(*key);
+}
+
+/**
+ * Set up private key fields of a type6 MEX message. The _pad variant
+ * strips leading zeroes from the b_key.
+ * Note that all numerics in the key token are big-endian,
+ * while the entries in the key block header are little-endian.
+ *
+ * @mex: pointer to user input data
+ * @p: pointer to memory area for the key
+ *
+ * Returns the size of the key area or -EFAULT
+ */
+static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex,
+ void *p, int big_endian)
+{
+ static struct cca_token_hdr static_pub_hdr = {
+ .token_identifier = 0x1E,
+ };
+ static struct cca_public_sec static_pub_sec = {
+ .section_identifier = 0x04,
+ };
+ struct {
+ struct T6_keyBlock_hdr t6_hdr;
+ struct cca_token_hdr pubHdr;
+ struct cca_public_sec pubSec;
+ char exponent[0];
+ } __attribute__((packed)) *key = p;
+ unsigned char *temp;
+ int i;
+
+ memset(key, 0, sizeof(*key));
+
+ key->pubHdr = static_pub_hdr;
+ key->pubSec = static_pub_sec;
+
+ /* key parameter block */
+ temp = key->exponent;
+ if (copy_from_user(temp, mex->b_key, mex->inputdatalength))
+ return -EFAULT;
+ /* Strip leading zeroes from b_key. */
+ for (i = 0; i < mex->inputdatalength; i++)
+ if (temp[i])
+ break;
+ if (i >= mex->inputdatalength)
+ return -EINVAL;
+ memmove(temp, temp + i, mex->inputdatalength - i);
+ temp += mex->inputdatalength - i;
+ /* modulus */
+ if (copy_from_user(temp, mex->n_modulus, mex->inputdatalength))
+ return -EFAULT;
+
+ key->pubSec.modulus_bit_len = 8 * mex->inputdatalength;
+ key->pubSec.modulus_byte_len = mex->inputdatalength;
+ key->pubSec.exponent_len = mex->inputdatalength - i;
+ key->pubSec.section_length = sizeof(key->pubSec) +
+ 2*mex->inputdatalength - i;
+ key->pubHdr.token_length =
+ key->pubSec.section_length + sizeof(key->pubHdr);
+ if (big_endian) {
+ key->t6_hdr.ulen = cpu_to_be16(key->pubHdr.token_length + 4);
+ key->t6_hdr.blen = cpu_to_be16(key->pubHdr.token_length + 6);
+ } else {
+ key->t6_hdr.ulen = cpu_to_le16(key->pubHdr.token_length + 4);
+ key->t6_hdr.blen = cpu_to_le16(key->pubHdr.token_length + 6);
+ }
+ return sizeof(*key) + 2*mex->inputdatalength - i;
+}
+
+/**
+ * Set up private key fields of a type6 CRT message.
+ * Note that all numerics in the key token are big-endian,
+ * while the entries in the key block header are little-endian.
+ *
+ * @mex: pointer to user input data
+ * @p: pointer to memory area for the key
+ *
+ * Returns the size of the key area or -EFAULT
+ */
+static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt,
+ void *p, int big_endian)
+{
+ static struct cca_public_sec static_cca_pub_sec = {
+ .section_identifier = 4,
+ .section_length = 0x000f,
+ .exponent_len = 0x0003,
+ };
+ static char pk_exponent[3] = { 0x01, 0x00, 0x01 };
+ struct {
+ struct T6_keyBlock_hdr t6_hdr;
+ struct cca_token_hdr token;
+ struct cca_pvt_ext_CRT_sec pvt;
+ char key_parts[0];
+ } __attribute__((packed)) *key = p;
+ struct cca_public_sec *pub;
+ int short_len, long_len, pad_len, key_len, size;
+
+ memset(key, 0, sizeof(*key));
+
+ short_len = crt->inputdatalength / 2;
+ long_len = short_len + 8;
+ pad_len = -(3*long_len + 2*short_len) & 7;
+ key_len = 3*long_len + 2*short_len + pad_len + crt->inputdatalength;
+ size = sizeof(*key) + key_len + sizeof(*pub) + 3;
+
+ /* parameter block.key block */
+ if (big_endian) {
+ key->t6_hdr.blen = cpu_to_be16(size);
+ key->t6_hdr.ulen = cpu_to_be16(size - 2);
+ } else {
+ key->t6_hdr.blen = cpu_to_le16(size);
+ key->t6_hdr.ulen = cpu_to_le16(size - 2);
+ }
+
+ /* key token header */
+ key->token.token_identifier = CCA_TKN_HDR_ID_EXT;
+ key->token.token_length = size - 6;
+
+ /* private section */
+ key->pvt.section_identifier = CCA_PVT_EXT_CRT_SEC_ID_PVT;
+ key->pvt.section_length = sizeof(key->pvt) + key_len;
+ key->pvt.key_format = CCA_PVT_EXT_CRT_SEC_FMT_CL;
+ key->pvt.key_use_flags[0] = CCA_PVT_USAGE_ALL;
+ key->pvt.p_len = key->pvt.dp_len = key->pvt.u_len = long_len;
+ key->pvt.q_len = key->pvt.dq_len = short_len;
+ key->pvt.mod_len = crt->inputdatalength;
+ key->pvt.pad_len = pad_len;
+
+ /* key parts */
+ if (copy_from_user(key->key_parts, crt->np_prime, long_len) ||
+ copy_from_user(key->key_parts + long_len,
+ crt->nq_prime, short_len) ||
+ copy_from_user(key->key_parts + long_len + short_len,
+ crt->bp_key, long_len) ||
+ copy_from_user(key->key_parts + 2*long_len + short_len,
+ crt->bq_key, short_len) ||
+ copy_from_user(key->key_parts + 2*long_len + 2*short_len,
+ crt->u_mult_inv, long_len))
+ return -EFAULT;
+ memset(key->key_parts + 3*long_len + 2*short_len + pad_len,
+ 0xff, crt->inputdatalength);
+ pub = (struct cca_public_sec *)(key->key_parts + key_len);
+ *pub = static_cca_pub_sec;
+ pub->modulus_bit_len = 8 * crt->inputdatalength;
+ /**
+ * In a private key, the modulus doesn't appear in the public
+ * section. So, an arbitrary public exponent of 0x010001 will be
+ * used.
+ */
+ memcpy((char *) (pub + 1), pk_exponent, 3);
+ return size;
+}
+
+#endif /* _ZCRYPT_CCA_KEY_H_ */
diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c
new file mode 100644
index 00000000000..a62b00083d0
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_cex2a.c
@@ -0,0 +1,435 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_cex2a.c
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/err.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_cex2a.h"
+
+#define CEX2A_MIN_MOD_SIZE 1 /* 8 bits */
+#define CEX2A_MAX_MOD_SIZE 256 /* 2048 bits */
+
+#define CEX2A_SPEED_RATING 970
+
+#define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */
+#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
+
+#define CEX2A_CLEANUP_TIME (15*HZ)
+
+static struct ap_device_id zcrypt_cex2a_ids[] = {
+ { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) },
+ { /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, "
+ "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_cex2a_probe(struct ap_device *ap_dev);
+static void zcrypt_cex2a_remove(struct ap_device *ap_dev);
+static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *,
+ struct ap_message *);
+
+static struct ap_driver zcrypt_cex2a_driver = {
+ .probe = zcrypt_cex2a_probe,
+ .remove = zcrypt_cex2a_remove,
+ .receive = zcrypt_cex2a_receive,
+ .ids = zcrypt_cex2a_ids,
+};
+
+/**
+ * Convert a ICAMEX message to a type50 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo *mex)
+{
+ unsigned char *mod, *exp, *inp;
+ int mod_len;
+
+ mod_len = mex->inputdatalength;
+
+ if (mod_len <= 128) {
+ struct type50_meb1_msg *meb1 = ap_msg->message;
+ memset(meb1, 0, sizeof(*meb1));
+ ap_msg->length = sizeof(*meb1);
+ meb1->header.msg_type_code = TYPE50_TYPE_CODE;
+ meb1->header.msg_len = sizeof(*meb1);
+ meb1->keyblock_type = TYPE50_MEB1_FMT;
+ mod = meb1->modulus + sizeof(meb1->modulus) - mod_len;
+ exp = meb1->exponent + sizeof(meb1->exponent) - mod_len;
+ inp = meb1->message + sizeof(meb1->message) - mod_len;
+ } else {
+ struct type50_meb2_msg *meb2 = ap_msg->message;
+ memset(meb2, 0, sizeof(*meb2));
+ ap_msg->length = sizeof(*meb2);
+ meb2->header.msg_type_code = TYPE50_TYPE_CODE;
+ meb2->header.msg_len = sizeof(*meb2);
+ meb2->keyblock_type = TYPE50_MEB2_FMT;
+ mod = meb2->modulus + sizeof(meb2->modulus) - mod_len;
+ exp = meb2->exponent + sizeof(meb2->exponent) - mod_len;
+ inp = meb2->message + sizeof(meb2->message) - mod_len;
+ }
+
+ if (copy_from_user(mod, mex->n_modulus, mod_len) ||
+ copy_from_user(exp, mex->b_key, mod_len) ||
+ copy_from_user(inp, mex->inputdata, mod_len))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type50 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ int mod_len, short_len, long_len, long_offset;
+ unsigned char *p, *q, *dp, *dq, *u, *inp;
+
+ mod_len = crt->inputdatalength;
+ short_len = mod_len / 2;
+ long_len = mod_len / 2 + 8;
+
+ /*
+ * CEX2A cannot handle p, dp, or U > 128 bytes.
+ * If we have one of these, we need to do extra checking.
+ */
+ if (long_len > 128) {
+ /*
+ * zcrypt_rsa_crt already checked for the leading
+ * zeroes of np_prime, bp_key and u_mult_inc.
+ */
+ long_offset = long_len - 128;
+ long_len = 128;
+ } else
+ long_offset = 0;
+
+ /*
+ * Instead of doing extra work for p, dp, U > 64 bytes, we'll just use
+ * the larger message structure.
+ */
+ if (long_len <= 64) {
+ struct type50_crb1_msg *crb1 = ap_msg->message;
+ memset(crb1, 0, sizeof(*crb1));
+ ap_msg->length = sizeof(*crb1);
+ crb1->header.msg_type_code = TYPE50_TYPE_CODE;
+ crb1->header.msg_len = sizeof(*crb1);
+ crb1->keyblock_type = TYPE50_CRB1_FMT;
+ p = crb1->p + sizeof(crb1->p) - long_len;
+ q = crb1->q + sizeof(crb1->q) - short_len;
+ dp = crb1->dp + sizeof(crb1->dp) - long_len;
+ dq = crb1->dq + sizeof(crb1->dq) - short_len;
+ u = crb1->u + sizeof(crb1->u) - long_len;
+ inp = crb1->message + sizeof(crb1->message) - mod_len;
+ } else {
+ struct type50_crb2_msg *crb2 = ap_msg->message;
+ memset(crb2, 0, sizeof(*crb2));
+ ap_msg->length = sizeof(*crb2);
+ crb2->header.msg_type_code = TYPE50_TYPE_CODE;
+ crb2->header.msg_len = sizeof(*crb2);
+ crb2->keyblock_type = TYPE50_CRB2_FMT;
+ p = crb2->p + sizeof(crb2->p) - long_len;
+ q = crb2->q + sizeof(crb2->q) - short_len;
+ dp = crb2->dp + sizeof(crb2->dp) - long_len;
+ dq = crb2->dq + sizeof(crb2->dq) - short_len;
+ u = crb2->u + sizeof(crb2->u) - long_len;
+ inp = crb2->message + sizeof(crb2->message) - mod_len;
+ }
+
+ if (copy_from_user(p, crt->np_prime + long_offset, long_len) ||
+ copy_from_user(q, crt->nq_prime, short_len) ||
+ copy_from_user(dp, crt->bp_key + long_offset, long_len) ||
+ copy_from_user(dq, crt->bq_key, short_len) ||
+ copy_from_user(u, crt->u_mult_inv + long_offset, long_len) ||
+ copy_from_user(inp, crt->inputdata, mod_len))
+ return -EFAULT;
+
+
+ return 0;
+}
+
+/**
+ * Copy results from a type 80 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int convert_type80(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ struct type80_hdr *t80h = reply->message;
+ unsigned char *data;
+
+ if (t80h->len < sizeof(*t80h) + outputdatalength) {
+ /* The result is too short, the CEX2A card may not do that.. */
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+ BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE);
+ data = reply->message + t80h->len - outputdatalength;
+ if (copy_to_user(outputdata, data, outputdatalength))
+ return -EFAULT;
+ return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ /* Response type byte is the second byte in the response. */
+ switch (((unsigned char *) reply->message)[1]) {
+ case TYPE82_RSP_CODE:
+ case TYPE88_RSP_CODE:
+ return convert_error(zdev, reply);
+ case TYPE80_RSP_CODE:
+ return convert_type80(zdev, reply,
+ outputdata, outputdatalength);
+ default: /* Unknown response type, this should NEVER EVER happen */
+ PRINTK("Unrecognized Message Header: %08x%08x\n",
+ *(unsigned int *) reply->message,
+ *(unsigned int *) (reply->message+4));
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_cex2a_receive(struct ap_device *ap_dev,
+ struct ap_message *msg,
+ struct ap_message *reply)
+{
+ static struct error_hdr error_reply = {
+ .type = TYPE82_RSP_CODE,
+ .reply_code = REP82_ERROR_MACHINE_FAILURE,
+ };
+ struct type80_hdr *t80h = reply->message;
+ int length;
+
+ /* Copy the reply message to the request message buffer. */
+ if (IS_ERR(reply))
+ memcpy(msg->message, &error_reply, sizeof(error_reply));
+ else if (t80h->type == TYPE80_RSP_CODE) {
+ length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len);
+ memcpy(msg->message, reply->message, length);
+ } else
+ memcpy(msg->message, reply->message, sizeof error_reply);
+ complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the CEX2A
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * CEX2A device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo *mex)
+{
+ struct ap_message ap_msg;
+ struct completion work;
+ int rc;
+
+ ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &work;
+ rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex);
+ if (rc)
+ goto out_free;
+ init_completion(&work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &work, CEX2A_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response(zdev, &ap_msg, mex->outputdata,
+ mex->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ kfree(ap_msg.message);
+ return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the CEX2A
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * CEX2A device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ struct ap_message ap_msg;
+ struct completion work;
+ int rc;
+
+ ap_msg.message = (void *) kmalloc(CEX2A_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &work;
+ rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt);
+ if (rc)
+ goto out_free;
+ init_completion(&work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &work, CEX2A_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response(zdev, &ap_msg, crt->outputdata,
+ crt->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ kfree(ap_msg.message);
+ return rc;
+}
+
+/**
+ * The crypto operations for a CEX2A card.
+ */
+static struct zcrypt_ops zcrypt_cex2a_ops = {
+ .rsa_modexpo = zcrypt_cex2a_modexpo,
+ .rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
+};
+
+/**
+ * Probe function for CEX2A cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_cex2a_probe(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev;
+ int rc;
+
+ zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE);
+ if (!zdev)
+ return -ENOMEM;
+ zdev->ap_dev = ap_dev;
+ zdev->ops = &zcrypt_cex2a_ops;
+ zdev->online = 1;
+ zdev->user_space_type = ZCRYPT_CEX2A;
+ zdev->type_string = "CEX2A";
+ zdev->min_mod_size = CEX2A_MIN_MOD_SIZE;
+ zdev->max_mod_size = CEX2A_MAX_MOD_SIZE;
+ zdev->short_crt = 1;
+ zdev->speed_rating = CEX2A_SPEED_RATING;
+ ap_dev->reply = &zdev->reply;
+ ap_dev->private = zdev;
+ rc = zcrypt_device_register(zdev);
+ if (rc)
+ goto out_free;
+ return 0;
+
+out_free:
+ ap_dev->private = NULL;
+ zcrypt_device_free(zdev);
+ return rc;
+}
+
+/**
+ * This is called to remove the extended CEX2A driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_cex2a_remove(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev = ap_dev->private;
+
+ zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_cex2a_init(void)
+{
+ return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a");
+}
+
+void __exit zcrypt_cex2a_exit(void)
+{
+ ap_driver_unregister(&zcrypt_cex2a_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_cex2a_init);
+module_exit(zcrypt_cex2a_exit);
+#endif
diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h
new file mode 100644
index 00000000000..8f69d1dacab
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_cex2a.h
@@ -0,0 +1,126 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_cex2a.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_CEX2A_H_
+#define _ZCRYPT_CEX2A_H_
+
+/**
+ * The type 50 message family is associated with a CEX2A card.
+ *
+ * The four members of the family are described below.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type50_hdr {
+ unsigned char reserved1;
+ unsigned char msg_type_code; /* 0x50 */
+ unsigned short msg_len;
+ unsigned char reserved2;
+ unsigned char ignored;
+ unsigned short reserved3;
+} __attribute__((packed));
+
+#define TYPE50_TYPE_CODE 0x50
+
+#define TYPE50_MEB1_FMT 0x0001
+#define TYPE50_MEB2_FMT 0x0002
+#define TYPE50_CRB1_FMT 0x0011
+#define TYPE50_CRB2_FMT 0x0012
+
+/* Mod-Exp, with a small modulus */
+struct type50_meb1_msg {
+ struct type50_hdr header;
+ unsigned short keyblock_type; /* 0x0001 */
+ unsigned char reserved[6];
+ unsigned char exponent[128];
+ unsigned char modulus[128];
+ unsigned char message[128];
+} __attribute__((packed));
+
+/* Mod-Exp, with a large modulus */
+struct type50_meb2_msg {
+ struct type50_hdr header;
+ unsigned short keyblock_type; /* 0x0002 */
+ unsigned char reserved[6];
+ unsigned char exponent[256];
+ unsigned char modulus[256];
+ unsigned char message[256];
+} __attribute__((packed));
+
+/* CRT, with a small modulus */
+struct type50_crb1_msg {
+ struct type50_hdr header;
+ unsigned short keyblock_type; /* 0x0011 */
+ unsigned char reserved[6];
+ unsigned char p[64];
+ unsigned char q[64];
+ unsigned char dp[64];
+ unsigned char dq[64];
+ unsigned char u[64];
+ unsigned char message[128];
+} __attribute__((packed));
+
+/* CRT, with a large modulus */
+struct type50_crb2_msg {
+ struct type50_hdr header;
+ unsigned short keyblock_type; /* 0x0012 */
+ unsigned char reserved[6];
+ unsigned char p[128];
+ unsigned char q[128];
+ unsigned char dp[128];
+ unsigned char dq[128];
+ unsigned char u[128];
+ unsigned char message[256];
+} __attribute__((packed));
+
+/**
+ * The type 80 response family is associated with a CEX2A card.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+
+#define TYPE80_RSP_CODE 0x80
+
+struct type80_hdr {
+ unsigned char reserved1;
+ unsigned char type; /* 0x80 */
+ unsigned short len;
+ unsigned char code; /* 0x00 */
+ unsigned char reserved2[3];
+ unsigned char reserved3[8];
+} __attribute__((packed));
+
+int zcrypt_cex2a_init(void);
+void zcrypt_cex2a_exit(void);
+
+#endif /* _ZCRYPT_CEX2A_H_ */
diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h
new file mode 100644
index 00000000000..2cb616ba8be
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_error.h
@@ -0,0 +1,133 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_error.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_ERROR_H_
+#define _ZCRYPT_ERROR_H_
+
+#include "zcrypt_api.h"
+
+/**
+ * Reply Messages
+ *
+ * Error reply messages are of two types:
+ * 82: Error (see below)
+ * 88: Error (see below)
+ * Both type 82 and type 88 have the same structure in the header.
+ *
+ * Request reply messages are of three known types:
+ * 80: Reply from a Type 50 Request (see CEX2A-RELATED STRUCTS)
+ * 84: Reply from a Type 4 Request (see PCICA-RELATED STRUCTS)
+ * 86: Reply from a Type 6 Request (see PCICC/PCIXCC/CEX2C-RELATED STRUCTS)
+ *
+ */
+struct error_hdr {
+ unsigned char reserved1; /* 0x00 */
+ unsigned char type; /* 0x82 or 0x88 */
+ unsigned char reserved2[2]; /* 0x0000 */
+ unsigned char reply_code; /* reply code */
+ unsigned char reserved3[3]; /* 0x000000 */
+};
+
+#define TYPE82_RSP_CODE 0x82
+#define TYPE88_RSP_CODE 0x88
+
+#define REP82_ERROR_MACHINE_FAILURE 0x10
+#define REP82_ERROR_PREEMPT_FAILURE 0x12
+#define REP82_ERROR_CHECKPT_FAILURE 0x14
+#define REP82_ERROR_MESSAGE_TYPE 0x20
+#define REP82_ERROR_INVALID_COMM_CD 0x21 /* Type 84 */
+#define REP82_ERROR_INVALID_MSG_LEN 0x23
+#define REP82_ERROR_RESERVD_FIELD 0x24 /* was 0x50 */
+#define REP82_ERROR_FORMAT_FIELD 0x29
+#define REP82_ERROR_INVALID_COMMAND 0x30
+#define REP82_ERROR_MALFORMED_MSG 0x40
+#define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */
+#define REP82_ERROR_WORD_ALIGNMENT 0x60
+#define REP82_ERROR_MESSAGE_LENGTH 0x80
+#define REP82_ERROR_OPERAND_INVALID 0x82
+#define REP82_ERROR_OPERAND_SIZE 0x84
+#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85
+#define REP82_ERROR_RESERVED_FIELD 0x88
+#define REP82_ERROR_TRANSPORT_FAIL 0x90
+#define REP82_ERROR_PACKET_TRUNCATED 0xA0
+#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0
+
+#define REP88_ERROR_MODULE_FAILURE 0x10
+
+#define REP88_ERROR_MESSAGE_TYPE 0x20
+#define REP88_ERROR_MESSAGE_MALFORMD 0x22
+#define REP88_ERROR_MESSAGE_LENGTH 0x23
+#define REP88_ERROR_RESERVED_FIELD 0x24
+#define REP88_ERROR_KEY_TYPE 0x34
+#define REP88_ERROR_INVALID_KEY 0x82 /* CEX2A */
+#define REP88_ERROR_OPERAND 0x84 /* CEX2A */
+#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */
+
+static inline int convert_error(struct zcrypt_device *zdev,
+ struct ap_message *reply)
+{
+ struct error_hdr *ehdr = reply->message;
+
+ PRINTK("Hardware error : Type %02x Message Header: %08x%08x\n",
+ ehdr->type, *(unsigned int *) reply->message,
+ *(unsigned int *) (reply->message + 4));
+
+ switch (ehdr->reply_code) {
+ case REP82_ERROR_OPERAND_INVALID:
+ case REP82_ERROR_OPERAND_SIZE:
+ case REP82_ERROR_EVEN_MOD_IN_OPND:
+ case REP88_ERROR_MESSAGE_MALFORMD:
+ // REP88_ERROR_INVALID_KEY // '82' CEX2A
+ // REP88_ERROR_OPERAND // '84' CEX2A
+ // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A
+ /* Invalid input data. */
+ return -EINVAL;
+ case REP82_ERROR_MESSAGE_TYPE:
+ // REP88_ERROR_MESSAGE_TYPE // '20' CEX2A
+ /**
+ * To sent a message of the wrong type is a bug in the
+ * device driver. Warn about it, disable the device
+ * and then repeat the request.
+ */
+ WARN_ON(1);
+ zdev->online = 0;
+ return -EAGAIN;
+ case REP82_ERROR_TRANSPORT_FAIL:
+ case REP82_ERROR_MACHINE_FAILURE:
+ // REP88_ERROR_MODULE_FAILURE // '10' CEX2A
+ /* If a card fails disable it and repeat the request. */
+ zdev->online = 0;
+ return -EAGAIN;
+ default:
+ PRINTKW("unknown type %02x reply code = %d\n",
+ ehdr->type, ehdr->reply_code);
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+}
+
+#endif /* _ZCRYPT_ERROR_H_ */
diff --git a/drivers/s390/crypto/zcrypt_mono.c b/drivers/s390/crypto/zcrypt_mono.c
new file mode 100644
index 00000000000..2a9349ad68b
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_mono.c
@@ -0,0 +1,100 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_mono.c
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/interrupt.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/compat.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_pcica.h"
+#include "zcrypt_pcicc.h"
+#include "zcrypt_pcixcc.h"
+#include "zcrypt_cex2a.h"
+
+/**
+ * The module initialization code.
+ */
+int __init zcrypt_init(void)
+{
+ int rc;
+
+ rc = ap_module_init();
+ if (rc)
+ goto out;
+ rc = zcrypt_api_init();
+ if (rc)
+ goto out_ap;
+ rc = zcrypt_pcica_init();
+ if (rc)
+ goto out_api;
+ rc = zcrypt_pcicc_init();
+ if (rc)
+ goto out_pcica;
+ rc = zcrypt_pcixcc_init();
+ if (rc)
+ goto out_pcicc;
+ rc = zcrypt_cex2a_init();
+ if (rc)
+ goto out_pcixcc;
+ return 0;
+
+out_pcixcc:
+ zcrypt_pcixcc_exit();
+out_pcicc:
+ zcrypt_pcicc_exit();
+out_pcica:
+ zcrypt_pcica_exit();
+out_api:
+ zcrypt_api_exit();
+out_ap:
+ ap_module_exit();
+out:
+ return rc;
+}
+
+/**
+ * The module termination code.
+ */
+void __exit zcrypt_exit(void)
+{
+ zcrypt_cex2a_exit();
+ zcrypt_pcixcc_exit();
+ zcrypt_pcicc_exit();
+ zcrypt_pcica_exit();
+ zcrypt_api_exit();
+ ap_module_exit();
+}
+
+module_init(zcrypt_init);
+module_exit(zcrypt_exit);
diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c
new file mode 100644
index 00000000000..b6a4ecdc802
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcica.c
@@ -0,0 +1,418 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_pcica.c
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/err.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_pcica.h"
+
+#define PCICA_MIN_MOD_SIZE 1 /* 8 bits */
+#define PCICA_MAX_MOD_SIZE 256 /* 2048 bits */
+
+#define PCICA_SPEED_RATING 2800
+
+#define PCICA_MAX_MESSAGE_SIZE 0x3a0 /* sizeof(struct type4_lcr) */
+#define PCICA_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */
+
+#define PCICA_CLEANUP_TIME (15*HZ)
+
+static struct ap_device_id zcrypt_pcica_ids[] = {
+ { AP_DEVICE(AP_DEVICE_TYPE_PCICA) },
+ { /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_pcica_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("PCICA Cryptographic Coprocessor device driver, "
+ "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_pcica_probe(struct ap_device *ap_dev);
+static void zcrypt_pcica_remove(struct ap_device *ap_dev);
+static void zcrypt_pcica_receive(struct ap_device *, struct ap_message *,
+ struct ap_message *);
+
+static struct ap_driver zcrypt_pcica_driver = {
+ .probe = zcrypt_pcica_probe,
+ .remove = zcrypt_pcica_remove,
+ .receive = zcrypt_pcica_receive,
+ .ids = zcrypt_pcica_ids,
+};
+
+/**
+ * Convert a ICAMEX message to a type4 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type4MEX_msg(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo *mex)
+{
+ unsigned char *modulus, *exponent, *message;
+ int mod_len;
+
+ mod_len = mex->inputdatalength;
+
+ if (mod_len <= 128) {
+ struct type4_sme *sme = ap_msg->message;
+ memset(sme, 0, sizeof(*sme));
+ ap_msg->length = sizeof(*sme);
+ sme->header.msg_fmt = TYPE4_SME_FMT;
+ sme->header.msg_len = sizeof(*sme);
+ sme->header.msg_type_code = TYPE4_TYPE_CODE;
+ sme->header.request_code = TYPE4_REQU_CODE;
+ modulus = sme->modulus + sizeof(sme->modulus) - mod_len;
+ exponent = sme->exponent + sizeof(sme->exponent) - mod_len;
+ message = sme->message + sizeof(sme->message) - mod_len;
+ } else {
+ struct type4_lme *lme = ap_msg->message;
+ memset(lme, 0, sizeof(*lme));
+ ap_msg->length = sizeof(*lme);
+ lme->header.msg_fmt = TYPE4_LME_FMT;
+ lme->header.msg_len = sizeof(*lme);
+ lme->header.msg_type_code = TYPE4_TYPE_CODE;
+ lme->header.request_code = TYPE4_REQU_CODE;
+ modulus = lme->modulus + sizeof(lme->modulus) - mod_len;
+ exponent = lme->exponent + sizeof(lme->exponent) - mod_len;
+ message = lme->message + sizeof(lme->message) - mod_len;
+ }
+
+ if (copy_from_user(modulus, mex->n_modulus, mod_len) ||
+ copy_from_user(exponent, mex->b_key, mod_len) ||
+ copy_from_user(message, mex->inputdata, mod_len))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type4 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ unsigned char *p, *q, *dp, *dq, *u, *inp;
+ int mod_len, short_len, long_len;
+
+ mod_len = crt->inputdatalength;
+ short_len = mod_len / 2;
+ long_len = mod_len / 2 + 8;
+
+ if (mod_len <= 128) {
+ struct type4_scr *scr = ap_msg->message;
+ memset(scr, 0, sizeof(*scr));
+ ap_msg->length = sizeof(*scr);
+ scr->header.msg_type_code = TYPE4_TYPE_CODE;
+ scr->header.request_code = TYPE4_REQU_CODE;
+ scr->header.msg_fmt = TYPE4_SCR_FMT;
+ scr->header.msg_len = sizeof(*scr);
+ p = scr->p + sizeof(scr->p) - long_len;
+ q = scr->q + sizeof(scr->q) - short_len;
+ dp = scr->dp + sizeof(scr->dp) - long_len;
+ dq = scr->dq + sizeof(scr->dq) - short_len;
+ u = scr->u + sizeof(scr->u) - long_len;
+ inp = scr->message + sizeof(scr->message) - mod_len;
+ } else {
+ struct type4_lcr *lcr = ap_msg->message;
+ memset(lcr, 0, sizeof(*lcr));
+ ap_msg->length = sizeof(*lcr);
+ lcr->header.msg_type_code = TYPE4_TYPE_CODE;
+ lcr->header.request_code = TYPE4_REQU_CODE;
+ lcr->header.msg_fmt = TYPE4_LCR_FMT;
+ lcr->header.msg_len = sizeof(*lcr);
+ p = lcr->p + sizeof(lcr->p) - long_len;
+ q = lcr->q + sizeof(lcr->q) - short_len;
+ dp = lcr->dp + sizeof(lcr->dp) - long_len;
+ dq = lcr->dq + sizeof(lcr->dq) - short_len;
+ u = lcr->u + sizeof(lcr->u) - long_len;
+ inp = lcr->message + sizeof(lcr->message) - mod_len;
+ }
+
+ if (copy_from_user(p, crt->np_prime, long_len) ||
+ copy_from_user(q, crt->nq_prime, short_len) ||
+ copy_from_user(dp, crt->bp_key, long_len) ||
+ copy_from_user(dq, crt->bq_key, short_len) ||
+ copy_from_user(u, crt->u_mult_inv, long_len) ||
+ copy_from_user(inp, crt->inputdata, mod_len))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * Copy results from a type 84 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static inline int convert_type84(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ struct type84_hdr *t84h = reply->message;
+ char *data;
+
+ if (t84h->len < sizeof(*t84h) + outputdatalength) {
+ /* The result is too short, the PCICA card may not do that.. */
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+ BUG_ON(t84h->len > PCICA_MAX_RESPONSE_SIZE);
+ data = reply->message + t84h->len - outputdatalength;
+ if (copy_to_user(outputdata, data, outputdatalength))
+ return -EFAULT;
+ return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ /* Response type byte is the second byte in the response. */
+ switch (((unsigned char *) reply->message)[1]) {
+ case TYPE82_RSP_CODE:
+ case TYPE88_RSP_CODE:
+ return convert_error(zdev, reply);
+ case TYPE84_RSP_CODE:
+ return convert_type84(zdev, reply,
+ outputdata, outputdatalength);
+ default: /* Unknown response type, this should NEVER EVER happen */
+ PRINTK("Unrecognized Message Header: %08x%08x\n",
+ *(unsigned int *) reply->message,
+ *(unsigned int *) (reply->message+4));
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_pcica_receive(struct ap_device *ap_dev,
+ struct ap_message *msg,
+ struct ap_message *reply)
+{
+ static struct error_hdr error_reply = {
+ .type = TYPE82_RSP_CODE,
+ .reply_code = REP82_ERROR_MACHINE_FAILURE,
+ };
+ struct type84_hdr *t84h = reply->message;
+ int length;
+
+ /* Copy the reply message to the request message buffer. */
+ if (IS_ERR(reply))
+ memcpy(msg->message, &error_reply, sizeof(error_reply));
+ else if (t84h->code == TYPE84_RSP_CODE) {
+ length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len);
+ memcpy(msg->message, reply->message, length);
+ } else
+ memcpy(msg->message, reply->message, sizeof error_reply);
+ complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCICA
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCICA device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_pcica_modexpo(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo *mex)
+{
+ struct ap_message ap_msg;
+ struct completion work;
+ int rc;
+
+ ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &work;
+ rc = ICAMEX_msg_to_type4MEX_msg(zdev, &ap_msg, mex);
+ if (rc)
+ goto out_free;
+ init_completion(&work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &work, PCICA_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response(zdev, &ap_msg, mex->outputdata,
+ mex->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ kfree(ap_msg.message);
+ return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCICA
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCICA device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_pcica_modexpo_crt(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ struct ap_message ap_msg;
+ struct completion work;
+ int rc;
+
+ ap_msg.message = (void *) kmalloc(PCICA_MAX_MESSAGE_SIZE, GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &work;
+ rc = ICACRT_msg_to_type4CRT_msg(zdev, &ap_msg, crt);
+ if (rc)
+ goto out_free;
+ init_completion(&work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &work, PCICA_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response(zdev, &ap_msg, crt->outputdata,
+ crt->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ kfree(ap_msg.message);
+ return rc;
+}
+
+/**
+ * The crypto operations for a PCICA card.
+ */
+static struct zcrypt_ops zcrypt_pcica_ops = {
+ .rsa_modexpo = zcrypt_pcica_modexpo,
+ .rsa_modexpo_crt = zcrypt_pcica_modexpo_crt,
+};
+
+/**
+ * Probe function for PCICA cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcica_probe(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev;
+ int rc;
+
+ zdev = zcrypt_device_alloc(PCICA_MAX_RESPONSE_SIZE);
+ if (!zdev)
+ return -ENOMEM;
+ zdev->ap_dev = ap_dev;
+ zdev->ops = &zcrypt_pcica_ops;
+ zdev->online = 1;
+ zdev->user_space_type = ZCRYPT_PCICA;
+ zdev->type_string = "PCICA";
+ zdev->min_mod_size = PCICA_MIN_MOD_SIZE;
+ zdev->max_mod_size = PCICA_MAX_MOD_SIZE;
+ zdev->speed_rating = PCICA_SPEED_RATING;
+ ap_dev->reply = &zdev->reply;
+ ap_dev->private = zdev;
+ rc = zcrypt_device_register(zdev);
+ if (rc)
+ goto out_free;
+ return 0;
+
+out_free:
+ ap_dev->private = NULL;
+ zcrypt_device_free(zdev);
+ return rc;
+}
+
+/**
+ * This is called to remove the extended PCICA driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_pcica_remove(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev = ap_dev->private;
+
+ zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_pcica_init(void)
+{
+ return ap_driver_register(&zcrypt_pcica_driver, THIS_MODULE, "pcica");
+}
+
+void zcrypt_pcica_exit(void)
+{
+ ap_driver_unregister(&zcrypt_pcica_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_pcica_init);
+module_exit(zcrypt_pcica_exit);
+#endif
diff --git a/drivers/s390/crypto/zcrypt_pcica.h b/drivers/s390/crypto/zcrypt_pcica.h
new file mode 100644
index 00000000000..3be11187f6d
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcica.h
@@ -0,0 +1,117 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_pcica.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_PCICA_H_
+#define _ZCRYPT_PCICA_H_
+
+/**
+ * The type 4 message family is associated with a PCICA card.
+ *
+ * The four members of the family are described below.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type4_hdr {
+ unsigned char reserved1;
+ unsigned char msg_type_code; /* 0x04 */
+ unsigned short msg_len;
+ unsigned char request_code; /* 0x40 */
+ unsigned char msg_fmt;
+ unsigned short reserved2;
+} __attribute__((packed));
+
+#define TYPE4_TYPE_CODE 0x04
+#define TYPE4_REQU_CODE 0x40
+
+#define TYPE4_SME_FMT 0x00
+#define TYPE4_LME_FMT 0x10
+#define TYPE4_SCR_FMT 0x40
+#define TYPE4_LCR_FMT 0x50
+
+/* Mod-Exp, with a small modulus */
+struct type4_sme {
+ struct type4_hdr header;
+ unsigned char message[128];
+ unsigned char exponent[128];
+ unsigned char modulus[128];
+} __attribute__((packed));
+
+/* Mod-Exp, with a large modulus */
+struct type4_lme {
+ struct type4_hdr header;
+ unsigned char message[256];
+ unsigned char exponent[256];
+ unsigned char modulus[256];
+} __attribute__((packed));
+
+/* CRT, with a small modulus */
+struct type4_scr {
+ struct type4_hdr header;
+ unsigned char message[128];
+ unsigned char dp[72];
+ unsigned char dq[64];
+ unsigned char p[72];
+ unsigned char q[64];
+ unsigned char u[72];
+} __attribute__((packed));
+
+/* CRT, with a large modulus */
+struct type4_lcr {
+ struct type4_hdr header;
+ unsigned char message[256];
+ unsigned char dp[136];
+ unsigned char dq[128];
+ unsigned char p[136];
+ unsigned char q[128];
+ unsigned char u[136];
+} __attribute__((packed));
+
+/**
+ * The type 84 response family is associated with a PCICA card.
+ *
+ * Note that all unsigned char arrays are right-justified and left-padded
+ * with zeroes.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+
+struct type84_hdr {
+ unsigned char reserved1;
+ unsigned char code;
+ unsigned short len;
+ unsigned char reserved2[4];
+} __attribute__((packed));
+
+#define TYPE84_RSP_CODE 0x84
+
+int zcrypt_pcica_init(void);
+void zcrypt_pcica_exit(void);
+
+#endif /* _ZCRYPT_PCICA_H_ */
diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c
new file mode 100644
index 00000000000..f295a403b29
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcicc.c
@@ -0,0 +1,630 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_pcicc.c
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/err.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_pcicc.h"
+#include "zcrypt_cca_key.h"
+
+#define PCICC_MIN_MOD_SIZE 64 /* 512 bits */
+#define PCICC_MAX_MOD_SIZE_OLD 128 /* 1024 bits */
+#define PCICC_MAX_MOD_SIZE 256 /* 2048 bits */
+
+/**
+ * PCICC cards need a speed rating of 0. This keeps them at the end of
+ * the zcrypt device list (see zcrypt_api.c). PCICC cards are only
+ * used if no other cards are present because they are slow and can only
+ * cope with PKCS12 padded requests. The logic is queer. PKCS11 padded
+ * requests are rejected. The modexpo function encrypts PKCS12 padded data
+ * and decrypts any non-PKCS12 padded data (except PKCS11) in the assumption
+ * that it's encrypted PKCS12 data. The modexpo_crt function always decrypts
+ * the data in the assumption that its PKCS12 encrypted data.
+ */
+#define PCICC_SPEED_RATING 0
+
+#define PCICC_MAX_MESSAGE_SIZE 0x710 /* max size type6 v1 crt message */
+#define PCICC_MAX_RESPONSE_SIZE 0x710 /* max size type86 v1 reply */
+
+#define PCICC_CLEANUP_TIME (15*HZ)
+
+static struct ap_device_id zcrypt_pcicc_ids[] = {
+ { AP_DEVICE(AP_DEVICE_TYPE_PCICC) },
+ { /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_pcicc_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("PCICC Cryptographic Coprocessor device driver, "
+ "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_pcicc_probe(struct ap_device *ap_dev);
+static void zcrypt_pcicc_remove(struct ap_device *ap_dev);
+static void zcrypt_pcicc_receive(struct ap_device *, struct ap_message *,
+ struct ap_message *);
+
+static struct ap_driver zcrypt_pcicc_driver = {
+ .probe = zcrypt_pcicc_probe,
+ .remove = zcrypt_pcicc_remove,
+ .receive = zcrypt_pcicc_receive,
+ .ids = zcrypt_pcicc_ids,
+};
+
+/**
+ * The following is used to initialize the CPRB passed to the PCICC card
+ * in a type6 message. The 3 fields that must be filled in at execution
+ * time are req_parml, rpl_parml and usage_domain. Note that all three
+ * fields are *little*-endian. Actually, everything about this interface
+ * is ascii/little-endian, since the device has 'Intel inside'.
+ *
+ * The CPRB is followed immediately by the parm block.
+ * The parm block contains:
+ * - function code ('PD' 0x5044 or 'PK' 0x504B)
+ * - rule block (0x0A00 'PKCS-1.2' or 0x0A00 'ZERO-PAD')
+ * - VUD block
+ */
+static struct CPRB static_cprb = {
+ .cprb_len = __constant_cpu_to_le16(0x0070),
+ .cprb_ver_id = 0x41,
+ .func_id = {0x54,0x32},
+ .checkpoint_flag= 0x01,
+ .svr_namel = __constant_cpu_to_le16(0x0008),
+ .svr_name = {'I','C','S','F',' ',' ',' ',' '}
+};
+
+/**
+ * Check the message for PKCS11 padding.
+ */
+static inline int is_PKCS11_padded(unsigned char *buffer, int length)
+{
+ int i;
+ if ((buffer[0] != 0x00) || (buffer[1] != 0x01))
+ return 0;
+ for (i = 2; i < length; i++)
+ if (buffer[i] != 0xFF)
+ break;
+ if (i < 10 || i == length)
+ return 0;
+ if (buffer[i] != 0x00)
+ return 0;
+ return 1;
+}
+
+/**
+ * Check the message for PKCS12 padding.
+ */
+static inline int is_PKCS12_padded(unsigned char *buffer, int length)
+{
+ int i;
+ if ((buffer[0] != 0x00) || (buffer[1] != 0x02))
+ return 0;
+ for (i = 2; i < length; i++)
+ if (buffer[i] == 0x00)
+ break;
+ if ((i < 10) || (i == length))
+ return 0;
+ if (buffer[i] != 0x00)
+ return 0;
+ return 1;
+}
+
+/**
+ * Convert a ICAMEX message to a type6 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type6MEX_msg(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo *mex)
+{
+ static struct type6_hdr static_type6_hdr = {
+ .type = 0x06,
+ .offset1 = 0x00000058,
+ .agent_id = {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
+ 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
+ .function_code = {'P','K'},
+ };
+ static struct function_and_rules_block static_pke_function_and_rules ={
+ .function_code = {'P','K'},
+ .ulen = __constant_cpu_to_le16(10),
+ .only_rule = {'P','K','C','S','-','1','.','2'}
+ };
+ struct {
+ struct type6_hdr hdr;
+ struct CPRB cprb;
+ struct function_and_rules_block fr;
+ unsigned short length;
+ char text[0];
+ } __attribute__((packed)) *msg = ap_msg->message;
+ int vud_len, pad_len, size;
+
+ /* VUD.ciphertext */
+ if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
+ return -EFAULT;
+
+ if (is_PKCS11_padded(msg->text, mex->inputdatalength))
+ return -EINVAL;
+
+ /* static message header and f&r */
+ msg->hdr = static_type6_hdr;
+ msg->fr = static_pke_function_and_rules;
+
+ if (is_PKCS12_padded(msg->text, mex->inputdatalength)) {
+ /* strip the padding and adjust the data length */
+ pad_len = strnlen(msg->text + 2, mex->inputdatalength - 2) + 3;
+ if (pad_len <= 9 || pad_len >= mex->inputdatalength)
+ return -ENODEV;
+ vud_len = mex->inputdatalength - pad_len;
+ memmove(msg->text, msg->text + pad_len, vud_len);
+ msg->length = cpu_to_le16(vud_len + 2);
+
+ /* Set up key after the variable length text. */
+ size = zcrypt_type6_mex_key_en(mex, msg->text + vud_len, 0);
+ if (size < 0)
+ return size;
+ size += sizeof(*msg) + vud_len; /* total size of msg */
+ } else {
+ vud_len = mex->inputdatalength;
+ msg->length = cpu_to_le16(2 + vud_len);
+
+ msg->hdr.function_code[1] = 'D';
+ msg->fr.function_code[1] = 'D';
+
+ /* Set up key after the variable length text. */
+ size = zcrypt_type6_mex_key_de(mex, msg->text + vud_len, 0);
+ if (size < 0)
+ return size;
+ size += sizeof(*msg) + vud_len; /* total size of msg */
+ }
+
+ /* message header, cprb and f&r */
+ msg->hdr.ToCardLen1 = (size - sizeof(msg->hdr) + 3) & -4;
+ msg->hdr.FromCardLen1 = PCICC_MAX_RESPONSE_SIZE - sizeof(msg->hdr);
+
+ msg->cprb = static_cprb;
+ msg->cprb.usage_domain[0]= AP_QID_QUEUE(zdev->ap_dev->qid);
+ msg->cprb.req_parml = cpu_to_le16(size - sizeof(msg->hdr) -
+ sizeof(msg->cprb));
+ msg->cprb.rpl_parml = cpu_to_le16(msg->hdr.FromCardLen1);
+
+ ap_msg->length = (size + 3) & -4;
+ return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type6 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @zreq: crypto request pointer
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type6CRT_msg(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ static struct type6_hdr static_type6_hdr = {
+ .type = 0x06,
+ .offset1 = 0x00000058,
+ .agent_id = {0x01,0x00,0x43,0x43,0x41,0x2D,0x41,0x50,
+ 0x50,0x4C,0x20,0x20,0x20,0x01,0x01,0x01},
+ .function_code = {'P','D'},
+ };
+ static struct function_and_rules_block static_pkd_function_and_rules ={
+ .function_code = {'P','D'},
+ .ulen = __constant_cpu_to_le16(10),
+ .only_rule = {'P','K','C','S','-','1','.','2'}
+ };
+ struct {
+ struct type6_hdr hdr;
+ struct CPRB cprb;
+ struct function_and_rules_block fr;
+ unsigned short length;
+ char text[0];
+ } __attribute__((packed)) *msg = ap_msg->message;
+ int size;
+
+ /* VUD.ciphertext */
+ msg->length = cpu_to_le16(2 + crt->inputdatalength);
+ if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
+ return -EFAULT;
+
+ if (is_PKCS11_padded(msg->text, crt->inputdatalength))
+ return -EINVAL;
+
+ /* Set up key after the variable length text. */
+ size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 0);
+ if (size < 0)
+ return size;
+ size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
+
+ /* message header, cprb and f&r */
+ msg->hdr = static_type6_hdr;
+ msg->hdr.ToCardLen1 = (size - sizeof(msg->hdr) + 3) & -4;
+ msg->hdr.FromCardLen1 = PCICC_MAX_RESPONSE_SIZE - sizeof(msg->hdr);
+
+ msg->cprb = static_cprb;
+ msg->cprb.usage_domain[0] = AP_QID_QUEUE(zdev->ap_dev->qid);
+ msg->cprb.req_parml = msg->cprb.rpl_parml =
+ cpu_to_le16(size - sizeof(msg->hdr) - sizeof(msg->cprb));
+
+ msg->fr = static_pkd_function_and_rules;
+
+ ap_msg->length = (size + 3) & -4;
+ return 0;
+}
+
+/**
+ * Copy results from a type 86 reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+struct type86_reply {
+ struct type86_hdr hdr;
+ struct type86_fmt2_ext fmt2;
+ struct CPRB cprb;
+ unsigned char pad[4]; /* 4 byte function code/rules block ? */
+ unsigned short length;
+ char text[0];
+} __attribute__((packed));
+
+static int convert_type86(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ static unsigned char static_pad[] = {
+ 0x00,0x02,
+ 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
+ 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
+ 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
+ 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
+ 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
+ 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
+ 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
+ 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
+ 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
+ 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
+ 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
+ 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
+ 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
+ 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
+ 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
+ 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
+ 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
+ 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
+ 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
+ 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
+ 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
+ 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
+ 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
+ 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
+ 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
+ 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
+ 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
+ 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
+ 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
+ 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
+ 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
+ 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
+ };
+ struct type86_reply *msg = reply->message;
+ unsigned short service_rc, service_rs;
+ unsigned int reply_len, pad_len;
+ char *data;
+
+ service_rc = le16_to_cpu(msg->cprb.ccp_rtcode);
+ if (unlikely(service_rc != 0)) {
+ service_rs = le16_to_cpu(msg->cprb.ccp_rscode);
+ if (service_rc == 8 && service_rs == 66) {
+ PDEBUG("Bad block format on PCICC\n");
+ return -EINVAL;
+ }
+ if (service_rc == 8 && service_rs == 65) {
+ PDEBUG("Probably an even modulus on PCICC\n");
+ return -EINVAL;
+ }
+ if (service_rc == 8 && service_rs == 770) {
+ PDEBUG("Invalid key length on PCICC\n");
+ zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
+ return -EAGAIN;
+ }
+ if (service_rc == 8 && service_rs == 783) {
+ PDEBUG("Extended bitlengths not enabled on PCICC\n");
+ zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD;
+ return -EAGAIN;
+ }
+ PRINTK("Unknown service rc/rs (PCICC): %d/%d\n",
+ service_rc, service_rs);
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+ data = msg->text;
+ reply_len = le16_to_cpu(msg->length) - 2;
+ if (reply_len > outputdatalength)
+ return -EINVAL;
+ /**
+ * For all encipher requests, the length of the ciphertext (reply_len)
+ * will always equal the modulus length. For MEX decipher requests
+ * the output needs to get padded. Minimum pad size is 10.
+ *
+ * Currently, the cases where padding will be added is for:
+ * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
+ * ZERO-PAD and CRT is only supported for PKD requests)
+ * - PCICC, always
+ */
+ pad_len = outputdatalength - reply_len;
+ if (pad_len > 0) {
+ if (pad_len < 10)
+ return -EINVAL;
+ /* 'restore' padding left in the PCICC/PCIXCC card. */
+ if (copy_to_user(outputdata, static_pad, pad_len - 1))
+ return -EFAULT;
+ if (put_user(0, outputdata + pad_len - 1))
+ return -EFAULT;
+ }
+ /* Copy the crypto response to user space. */
+ if (copy_to_user(outputdata + pad_len, data, reply_len))
+ return -EFAULT;
+ return 0;
+}
+
+static int convert_response(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ struct type86_reply *msg = reply->message;
+
+ /* Response type byte is the second byte in the response. */
+ switch (msg->hdr.type) {
+ case TYPE82_RSP_CODE:
+ case TYPE88_RSP_CODE:
+ return convert_error(zdev, reply);
+ case TYPE86_RSP_CODE:
+ if (msg->hdr.reply_code)
+ return convert_error(zdev, reply);
+ if (msg->cprb.cprb_ver_id == 0x01)
+ return convert_type86(zdev, reply,
+ outputdata, outputdatalength);
+ /* no break, incorrect cprb version is an unknown response */
+ default: /* Unknown response type, this should NEVER EVER happen */
+ PRINTK("Unrecognized Message Header: %08x%08x\n",
+ *(unsigned int *) reply->message,
+ *(unsigned int *) (reply->message+4));
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_pcicc_receive(struct ap_device *ap_dev,
+ struct ap_message *msg,
+ struct ap_message *reply)
+{
+ static struct error_hdr error_reply = {
+ .type = TYPE82_RSP_CODE,
+ .reply_code = REP82_ERROR_MACHINE_FAILURE,
+ };
+ struct type86_reply *t86r = reply->message;
+ int length;
+
+ /* Copy the reply message to the request message buffer. */
+ if (IS_ERR(reply))
+ memcpy(msg->message, &error_reply, sizeof(error_reply));
+ else if (t86r->hdr.type == TYPE86_RSP_CODE &&
+ t86r->cprb.cprb_ver_id == 0x01) {
+ length = sizeof(struct type86_reply) + t86r->length - 2;
+ length = min(PCICC_MAX_RESPONSE_SIZE, length);
+ memcpy(msg->message, reply->message, length);
+ } else
+ memcpy(msg->message, reply->message, sizeof error_reply);
+ complete((struct completion *) msg->private);
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCICC
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCICC device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_pcicc_modexpo(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo *mex)
+{
+ struct ap_message ap_msg;
+ struct completion work;
+ int rc;
+
+ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.length = PAGE_SIZE;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &work;
+ rc = ICAMEX_msg_to_type6MEX_msg(zdev, &ap_msg, mex);
+ if (rc)
+ goto out_free;
+ init_completion(&work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &work, PCICC_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response(zdev, &ap_msg, mex->outputdata,
+ mex->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ free_page((unsigned long) ap_msg.message);
+ return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCICC
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCICC device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_pcicc_modexpo_crt(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ struct ap_message ap_msg;
+ struct completion work;
+ int rc;
+
+ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.length = PAGE_SIZE;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &work;
+ rc = ICACRT_msg_to_type6CRT_msg(zdev, &ap_msg, crt);
+ if (rc)
+ goto out_free;
+ init_completion(&work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &work, PCICC_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response(zdev, &ap_msg, crt->outputdata,
+ crt->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ free_page((unsigned long) ap_msg.message);
+ return rc;
+}
+
+/**
+ * The crypto operations for a PCICC card.
+ */
+static struct zcrypt_ops zcrypt_pcicc_ops = {
+ .rsa_modexpo = zcrypt_pcicc_modexpo,
+ .rsa_modexpo_crt = zcrypt_pcicc_modexpo_crt,
+};
+
+/**
+ * Probe function for PCICC cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcicc_probe(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev;
+ int rc;
+
+ zdev = zcrypt_device_alloc(PCICC_MAX_RESPONSE_SIZE);
+ if (!zdev)
+ return -ENOMEM;
+ zdev->ap_dev = ap_dev;
+ zdev->ops = &zcrypt_pcicc_ops;
+ zdev->online = 1;
+ zdev->user_space_type = ZCRYPT_PCICC;
+ zdev->type_string = "PCICC";
+ zdev->min_mod_size = PCICC_MIN_MOD_SIZE;
+ zdev->max_mod_size = PCICC_MAX_MOD_SIZE;
+ zdev->speed_rating = PCICC_SPEED_RATING;
+ ap_dev->reply = &zdev->reply;
+ ap_dev->private = zdev;
+ rc = zcrypt_device_register(zdev);
+ if (rc)
+ goto out_free;
+ return 0;
+
+ out_free:
+ ap_dev->private = NULL;
+ zcrypt_device_free(zdev);
+ return rc;
+}
+
+/**
+ * This is called to remove the extended PCICC driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_pcicc_remove(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev = ap_dev->private;
+
+ zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_pcicc_init(void)
+{
+ return ap_driver_register(&zcrypt_pcicc_driver, THIS_MODULE, "pcicc");
+}
+
+void zcrypt_pcicc_exit(void)
+{
+ ap_driver_unregister(&zcrypt_pcicc_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_pcicc_init);
+module_exit(zcrypt_pcicc_exit);
+#endif
diff --git a/drivers/s390/crypto/zcrypt_pcicc.h b/drivers/s390/crypto/zcrypt_pcicc.h
new file mode 100644
index 00000000000..6d4454846c8
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcicc.h
@@ -0,0 +1,176 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_pcicc.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_PCICC_H_
+#define _ZCRYPT_PCICC_H_
+
+/**
+ * The type 6 message family is associated with PCICC or PCIXCC cards.
+ *
+ * It contains a message header followed by a CPRB, both of which
+ * are described below.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type6_hdr {
+ unsigned char reserved1; /* 0x00 */
+ unsigned char type; /* 0x06 */
+ unsigned char reserved2[2]; /* 0x0000 */
+ unsigned char right[4]; /* 0x00000000 */
+ unsigned char reserved3[2]; /* 0x0000 */
+ unsigned char reserved4[2]; /* 0x0000 */
+ unsigned char apfs[4]; /* 0x00000000 */
+ unsigned int offset1; /* 0x00000058 (offset to CPRB) */
+ unsigned int offset2; /* 0x00000000 */
+ unsigned int offset3; /* 0x00000000 */
+ unsigned int offset4; /* 0x00000000 */
+ unsigned char agent_id[16]; /* PCICC: */
+ /* 0x0100 */
+ /* 0x4343412d4150504c202020 */
+ /* 0x010101 */
+ /* PCIXCC: */
+ /* 0x4341000000000000 */
+ /* 0x0000000000000000 */
+ unsigned char rqid[2]; /* rqid. internal to 603 */
+ unsigned char reserved5[2]; /* 0x0000 */
+ unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */
+ unsigned char reserved6[2]; /* 0x0000 */
+ unsigned int ToCardLen1; /* (request CPRB len + 3) & -4 */
+ unsigned int ToCardLen2; /* db len 0x00000000 for PKD */
+ unsigned int ToCardLen3; /* 0x00000000 */
+ unsigned int ToCardLen4; /* 0x00000000 */
+ unsigned int FromCardLen1; /* response buffer length */
+ unsigned int FromCardLen2; /* db len 0x00000000 for PKD */
+ unsigned int FromCardLen3; /* 0x00000000 */
+ unsigned int FromCardLen4; /* 0x00000000 */
+} __attribute__((packed));
+
+/**
+ * CPRB
+ * Note that all shorts, ints and longs are little-endian.
+ * All pointer fields are 32-bits long, and mean nothing
+ *
+ * A request CPRB is followed by a request_parameter_block.
+ *
+ * The request (or reply) parameter block is organized thus:
+ * function code
+ * VUD block
+ * key block
+ */
+struct CPRB {
+ unsigned short cprb_len; /* CPRB length */
+ unsigned char cprb_ver_id; /* CPRB version id. */
+ unsigned char pad_000; /* Alignment pad byte. */
+ unsigned char srpi_rtcode[4]; /* SRPI return code LELONG */
+ unsigned char srpi_verb; /* SRPI verb type */
+ unsigned char flags; /* flags */
+ unsigned char func_id[2]; /* function id */
+ unsigned char checkpoint_flag; /* */
+ unsigned char resv2; /* reserved */
+ unsigned short req_parml; /* request parameter buffer */
+ /* length 16-bit little endian */
+ unsigned char req_parmp[4]; /* request parameter buffer *
+ * pointer (means nothing: the *
+ * parameter buffer follows *
+ * the CPRB). */
+ unsigned char req_datal[4]; /* request data buffer */
+ /* length ULELONG */
+ unsigned char req_datap[4]; /* request data buffer */
+ /* pointer */
+ unsigned short rpl_parml; /* reply parameter buffer */
+ /* length 16-bit little endian */
+ unsigned char pad_001[2]; /* Alignment pad bytes. ULESHORT */
+ unsigned char rpl_parmp[4]; /* reply parameter buffer *
+ * pointer (means nothing: the *
+ * parameter buffer follows *
+ * the CPRB). */
+ unsigned char rpl_datal[4]; /* reply data buffer len ULELONG */
+ unsigned char rpl_datap[4]; /* reply data buffer */
+ /* pointer */
+ unsigned short ccp_rscode; /* server reason code ULESHORT */
+ unsigned short ccp_rtcode; /* server return code ULESHORT */
+ unsigned char repd_parml[2]; /* replied parameter len ULESHORT*/
+ unsigned char mac_data_len[2]; /* Mac Data Length ULESHORT */
+ unsigned char repd_datal[4]; /* replied data length ULELONG */
+ unsigned char req_pc[2]; /* PC identifier */
+ unsigned char res_origin[8]; /* resource origin */
+ unsigned char mac_value[8]; /* Mac Value */
+ unsigned char logon_id[8]; /* Logon Identifier */
+ unsigned char usage_domain[2]; /* cdx */
+ unsigned char resv3[18]; /* reserved for requestor */
+ unsigned short svr_namel; /* server name length ULESHORT */
+ unsigned char svr_name[8]; /* server name */
+} __attribute__((packed));
+
+/**
+ * The type 86 message family is associated with PCICC and PCIXCC cards.
+ *
+ * It contains a message header followed by a CPRB. The CPRB is
+ * the same as the request CPRB, which is described above.
+ *
+ * If format is 1, an error condition exists and no data beyond
+ * the 8-byte message header is of interest.
+ *
+ * The non-error message is shown below.
+ *
+ * Note that all reserved fields must be zeroes.
+ */
+struct type86_hdr {
+ unsigned char reserved1; /* 0x00 */
+ unsigned char type; /* 0x86 */
+ unsigned char format; /* 0x01 (error) or 0x02 (ok) */
+ unsigned char reserved2; /* 0x00 */
+ unsigned char reply_code; /* reply code (see above) */
+ unsigned char reserved3[3]; /* 0x000000 */
+} __attribute__((packed));
+
+#define TYPE86_RSP_CODE 0x86
+#define TYPE86_FMT2 0x02
+
+struct type86_fmt2_ext {
+ unsigned char reserved[4]; /* 0x00000000 */
+ unsigned char apfs[4]; /* final status */
+ unsigned int count1; /* length of CPRB + parameters */
+ unsigned int offset1; /* offset to CPRB */
+ unsigned int count2; /* 0x00000000 */
+ unsigned int offset2; /* db offset 0x00000000 for PKD */
+ unsigned int count3; /* 0x00000000 */
+ unsigned int offset3; /* 0x00000000 */
+ unsigned int count4; /* 0x00000000 */
+ unsigned int offset4; /* 0x00000000 */
+} __attribute__((packed));
+
+struct function_and_rules_block {
+ unsigned char function_code[2];
+ unsigned short ulen;
+ unsigned char only_rule[8];
+} __attribute__((packed));
+
+int zcrypt_pcicc_init(void);
+void zcrypt_pcicc_exit(void);
+
+#endif /* _ZCRYPT_PCICC_H_ */
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
new file mode 100644
index 00000000000..2da8b938140
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -0,0 +1,951 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_pcixcc.c
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ * Ralph Wuerthner <rwuerthn@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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/err.h>
+#include <linux/delay.h>
+#include <asm/atomic.h>
+#include <asm/uaccess.h>
+
+#include "ap_bus.h"
+#include "zcrypt_api.h"
+#include "zcrypt_error.h"
+#include "zcrypt_pcicc.h"
+#include "zcrypt_pcixcc.h"
+#include "zcrypt_cca_key.h"
+
+#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
+#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
+#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
+
+#define PCIXCC_MCL2_SPEED_RATING 7870 /* FIXME: needs finetuning */
+#define PCIXCC_MCL3_SPEED_RATING 7870
+#define CEX2C_SPEED_RATING 8540
+
+#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
+#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
+
+#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
+#define PCIXCC_MAX_XCRB_RESPONSE_SIZE PCIXCC_MAX_XCRB_MESSAGE_SIZE
+#define PCIXCC_MAX_XCRB_DATA_SIZE (11*1024)
+#define PCIXCC_MAX_XCRB_REPLY_SIZE (5*1024)
+
+#define PCIXCC_MAX_RESPONSE_SIZE PCIXCC_MAX_XCRB_RESPONSE_SIZE
+
+#define PCIXCC_CLEANUP_TIME (15*HZ)
+
+#define CEIL4(x) ((((x)+3)/4)*4)
+
+struct response_type {
+ struct completion work;
+ int type;
+};
+#define PCIXCC_RESPONSE_TYPE_ICA 0
+#define PCIXCC_RESPONSE_TYPE_XCRB 1
+
+static struct ap_device_id zcrypt_pcixcc_ids[] = {
+ { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
+ { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
+ { /* end of list */ },
+};
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids);
+MODULE_AUTHOR("IBM Corporation");
+MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, "
+ "Copyright 2001, 2006 IBM Corporation");
+MODULE_LICENSE("GPL");
+#endif
+
+static int zcrypt_pcixcc_probe(struct ap_device *ap_dev);
+static void zcrypt_pcixcc_remove(struct ap_device *ap_dev);
+static void zcrypt_pcixcc_receive(struct ap_device *, struct ap_message *,
+ struct ap_message *);
+
+static struct ap_driver zcrypt_pcixcc_driver = {
+ .probe = zcrypt_pcixcc_probe,
+ .remove = zcrypt_pcixcc_remove,
+ .receive = zcrypt_pcixcc_receive,
+ .ids = zcrypt_pcixcc_ids,
+};
+
+/**
+ * The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
+ * card in a type6 message. The 3 fields that must be filled in at execution
+ * time are req_parml, rpl_parml and usage_domain.
+ * Everything about this interface is ascii/big-endian, since the
+ * device does *not* have 'Intel inside'.
+ *
+ * The CPRBX is followed immediately by the parm block.
+ * The parm block contains:
+ * - function code ('PD' 0x5044 or 'PK' 0x504B)
+ * - rule block (one of:)
+ * + 0x000A 'PKCS-1.2' (MCL2 'PD')
+ * + 0x000A 'ZERO-PAD' (MCL2 'PK')
+ * + 0x000A 'ZERO-PAD' (MCL3 'PD' or CEX2C 'PD')
+ * + 0x000A 'MRP ' (MCL3 'PK' or CEX2C 'PK')
+ * - VUD block
+ */
+static struct CPRBX static_cprbx = {
+ .cprb_len = 0x00DC,
+ .cprb_ver_id = 0x02,
+ .func_id = {0x54,0x32},
+};
+
+/**
+ * Convert a ICAMEX message to a type6 MEX message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @mex: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo *mex)
+{
+ static struct type6_hdr static_type6_hdrX = {
+ .type = 0x06,
+ .offset1 = 0x00000058,
+ .agent_id = {'C','A',},
+ .function_code = {'P','K'},
+ };
+ static struct function_and_rules_block static_pke_fnr = {
+ .function_code = {'P','K'},
+ .ulen = 10,
+ .only_rule = {'M','R','P',' ',' ',' ',' ',' '}
+ };
+ static struct function_and_rules_block static_pke_fnr_MCL2 = {
+ .function_code = {'P','K'},
+ .ulen = 10,
+ .only_rule = {'Z','E','R','O','-','P','A','D'}
+ };
+ struct {
+ struct type6_hdr hdr;
+ struct CPRBX cprbx;
+ struct function_and_rules_block fr;
+ unsigned short length;
+ char text[0];
+ } __attribute__((packed)) *msg = ap_msg->message;
+ int size;
+
+ /* VUD.ciphertext */
+ msg->length = mex->inputdatalength + 2;
+ if (copy_from_user(msg->text, mex->inputdata, mex->inputdatalength))
+ return -EFAULT;
+
+ /* Set up key which is located after the variable length text. */
+ size = zcrypt_type6_mex_key_en(mex, msg->text+mex->inputdatalength, 1);
+ if (size < 0)
+ return size;
+ size += sizeof(*msg) + mex->inputdatalength;
+
+ /* message header, cprbx and f&r */
+ msg->hdr = static_type6_hdrX;
+ msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
+ msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+
+ msg->cprbx = static_cprbx;
+ msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+ msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1;
+
+ msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
+ static_pke_fnr_MCL2 : static_pke_fnr;
+
+ msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx);
+
+ ap_msg->length = size;
+ return 0;
+}
+
+/**
+ * Convert a ICACRT message to a type6 CRT message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @crt: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ static struct type6_hdr static_type6_hdrX = {
+ .type = 0x06,
+ .offset1 = 0x00000058,
+ .agent_id = {'C','A',},
+ .function_code = {'P','D'},
+ };
+ static struct function_and_rules_block static_pkd_fnr = {
+ .function_code = {'P','D'},
+ .ulen = 10,
+ .only_rule = {'Z','E','R','O','-','P','A','D'}
+ };
+
+ static struct function_and_rules_block static_pkd_fnr_MCL2 = {
+ .function_code = {'P','D'},
+ .ulen = 10,
+ .only_rule = {'P','K','C','S','-','1','.','2'}
+ };
+ struct {
+ struct type6_hdr hdr;
+ struct CPRBX cprbx;
+ struct function_and_rules_block fr;
+ unsigned short length;
+ char text[0];
+ } __attribute__((packed)) *msg = ap_msg->message;
+ int size;
+
+ /* VUD.ciphertext */
+ msg->length = crt->inputdatalength + 2;
+ if (copy_from_user(msg->text, crt->inputdata, crt->inputdatalength))
+ return -EFAULT;
+
+ /* Set up key which is located after the variable length text. */
+ size = zcrypt_type6_crt_key(crt, msg->text + crt->inputdatalength, 1);
+ if (size < 0)
+ return size;
+ size += sizeof(*msg) + crt->inputdatalength; /* total size of msg */
+
+ /* message header, cprbx and f&r */
+ msg->hdr = static_type6_hdrX;
+ msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
+ msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
+
+ msg->cprbx = static_cprbx;
+ msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid);
+ msg->cprbx.req_parml = msg->cprbx.rpl_msgbl =
+ size - sizeof(msg->hdr) - sizeof(msg->cprbx);
+
+ msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ?
+ static_pkd_fnr_MCL2 : static_pkd_fnr;
+
+ ap_msg->length = size;
+ return 0;
+}
+
+/**
+ * Convert a XCRB message to a type6 CPRB message.
+ *
+ * @zdev: crypto device pointer
+ * @ap_msg: pointer to AP message
+ * @xcRB: pointer to user input data
+ *
+ * Returns 0 on success or -EFAULT.
+ */
+struct type86_fmt2_msg {
+ struct type86_hdr hdr;
+ struct type86_fmt2_ext fmt2;
+} __attribute__((packed));
+
+static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
+ struct ap_message *ap_msg,
+ struct ica_xcRB *xcRB)
+{
+ static struct type6_hdr static_type6_hdrX = {
+ .type = 0x06,
+ .offset1 = 0x00000058,
+ };
+ struct {
+ struct type6_hdr hdr;
+ struct ica_CPRBX cprbx;
+ } __attribute__((packed)) *msg = ap_msg->message;
+
+ int rcblen = CEIL4(xcRB->request_control_blk_length);
+ int replylen;
+ char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
+ char *function_code;
+
+ /* length checks */
+ ap_msg->length = sizeof(struct type6_hdr) +
+ CEIL4(xcRB->request_control_blk_length) +
+ xcRB->request_data_length;
+ if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) {
+ PRINTK("Combined message is too large (%ld/%d/%d).\n",
+ sizeof(struct type6_hdr),
+ xcRB->request_control_blk_length,
+ xcRB->request_data_length);
+ return -EFAULT;
+ }
+ if (CEIL4(xcRB->reply_control_blk_length) >
+ PCIXCC_MAX_XCRB_REPLY_SIZE) {
+ PDEBUG("Reply CPRB length is too large (%d).\n",
+ xcRB->request_control_blk_length);
+ return -EFAULT;
+ }
+ if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) {
+ PDEBUG("Reply data block length is too large (%d).\n",
+ xcRB->reply_data_length);
+ return -EFAULT;
+ }
+ replylen = CEIL4(xcRB->reply_control_blk_length) +
+ CEIL4(xcRB->reply_data_length) +
+ sizeof(struct type86_fmt2_msg);
+ if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
+ PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE"
+ " (%d/%d/%d).\n",
+ sizeof(struct type86_fmt2_msg),
+ xcRB->reply_control_blk_length,
+ xcRB->reply_data_length);
+ xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
+ (sizeof(struct type86_fmt2_msg) +
+ CEIL4(xcRB->reply_data_length));
+ PDEBUG("Capping Reply CPRB length at %d\n",
+ xcRB->reply_control_blk_length);
+ }
+
+ /* prepare type6 header */
+ msg->hdr = static_type6_hdrX;
+ memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
+ msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
+ if (xcRB->request_data_length) {
+ msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
+ msg->hdr.ToCardLen2 = xcRB->request_data_length;
+ }
+ msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
+ msg->hdr.FromCardLen2 = xcRB->reply_data_length;
+
+ /* prepare CPRB */
+ if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
+ xcRB->request_control_blk_length))
+ return -EFAULT;
+ if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
+ xcRB->request_control_blk_length) {
+ PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len,
+ xcRB->request_control_blk_length);
+ return -EFAULT;
+ }
+ function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
+ memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
+
+ /* copy data block */
+ if (xcRB->request_data_length &&
+ copy_from_user(req_data, xcRB->request_data_address,
+ xcRB->request_data_length))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * Copy results from a type 86 ICA reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @data: pointer to user output data
+ * @length: size of user output data
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+struct type86x_reply {
+ struct type86_hdr hdr;
+ struct type86_fmt2_ext fmt2;
+ struct CPRBX cprbx;
+ unsigned char pad[4]; /* 4 byte function code/rules block ? */
+ unsigned short length;
+ char text[0];
+} __attribute__((packed));
+
+static int convert_type86_ica(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ static unsigned char static_pad[] = {
+ 0x00,0x02,
+ 0x1B,0x7B,0x5D,0xB5,0x75,0x01,0x3D,0xFD,
+ 0x8D,0xD1,0xC7,0x03,0x2D,0x09,0x23,0x57,
+ 0x89,0x49,0xB9,0x3F,0xBB,0x99,0x41,0x5B,
+ 0x75,0x21,0x7B,0x9D,0x3B,0x6B,0x51,0x39,
+ 0xBB,0x0D,0x35,0xB9,0x89,0x0F,0x93,0xA5,
+ 0x0B,0x47,0xF1,0xD3,0xBB,0xCB,0xF1,0x9D,
+ 0x23,0x73,0x71,0xFF,0xF3,0xF5,0x45,0xFB,
+ 0x61,0x29,0x23,0xFD,0xF1,0x29,0x3F,0x7F,
+ 0x17,0xB7,0x1B,0xA9,0x19,0xBD,0x57,0xA9,
+ 0xD7,0x95,0xA3,0xCB,0xED,0x1D,0xDB,0x45,
+ 0x7D,0x11,0xD1,0x51,0x1B,0xED,0x71,0xE9,
+ 0xB1,0xD1,0xAB,0xAB,0x21,0x2B,0x1B,0x9F,
+ 0x3B,0x9F,0xF7,0xF7,0xBD,0x63,0xEB,0xAD,
+ 0xDF,0xB3,0x6F,0x5B,0xDB,0x8D,0xA9,0x5D,
+ 0xE3,0x7D,0x77,0x49,0x47,0xF5,0xA7,0xFD,
+ 0xAB,0x2F,0x27,0x35,0x77,0xD3,0x49,0xC9,
+ 0x09,0xEB,0xB1,0xF9,0xBF,0x4B,0xCB,0x2B,
+ 0xEB,0xEB,0x05,0xFF,0x7D,0xC7,0x91,0x8B,
+ 0x09,0x83,0xB9,0xB9,0x69,0x33,0x39,0x6B,
+ 0x79,0x75,0x19,0xBF,0xBB,0x07,0x1D,0xBD,
+ 0x29,0xBF,0x39,0x95,0x93,0x1D,0x35,0xC7,
+ 0xC9,0x4D,0xE5,0x97,0x0B,0x43,0x9B,0xF1,
+ 0x16,0x93,0x03,0x1F,0xA5,0xFB,0xDB,0xF3,
+ 0x27,0x4F,0x27,0x61,0x05,0x1F,0xB9,0x23,
+ 0x2F,0xC3,0x81,0xA9,0x23,0x71,0x55,0x55,
+ 0xEB,0xED,0x41,0xE5,0xF3,0x11,0xF1,0x43,
+ 0x69,0x03,0xBD,0x0B,0x37,0x0F,0x51,0x8F,
+ 0x0B,0xB5,0x89,0x5B,0x67,0xA9,0xD9,0x4F,
+ 0x01,0xF9,0x21,0x77,0x37,0x73,0x79,0xC5,
+ 0x7F,0x51,0xC1,0xCF,0x97,0xA1,0x75,0xAD,
+ 0x35,0x9D,0xD3,0xD3,0xA7,0x9D,0x5D,0x41,
+ 0x6F,0x65,0x1B,0xCF,0xA9,0x87,0x91,0x09
+ };
+ struct type86x_reply *msg = reply->message;
+ unsigned short service_rc, service_rs;
+ unsigned int reply_len, pad_len;
+ char *data;
+
+ service_rc = msg->cprbx.ccp_rtcode;
+ if (unlikely(service_rc != 0)) {
+ service_rs = msg->cprbx.ccp_rscode;
+ if (service_rc == 8 && service_rs == 66) {
+ PDEBUG("Bad block format on PCIXCC/CEX2C\n");
+ return -EINVAL;
+ }
+ if (service_rc == 8 && service_rs == 65) {
+ PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n");
+ return -EINVAL;
+ }
+ if (service_rc == 8 && service_rs == 770) {
+ PDEBUG("Invalid key length on PCIXCC/CEX2C\n");
+ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+ return -EAGAIN;
+ }
+ if (service_rc == 8 && service_rs == 783) {
+ PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n");
+ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+ return -EAGAIN;
+ }
+ PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n",
+ service_rc, service_rs);
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+ data = msg->text;
+ reply_len = msg->length - 2;
+ if (reply_len > outputdatalength)
+ return -EINVAL;
+ /**
+ * For all encipher requests, the length of the ciphertext (reply_len)
+ * will always equal the modulus length. For MEX decipher requests
+ * the output needs to get padded. Minimum pad size is 10.
+ *
+ * Currently, the cases where padding will be added is for:
+ * - PCIXCC_MCL2 using a CRT form token (since PKD didn't support
+ * ZERO-PAD and CRT is only supported for PKD requests)
+ * - PCICC, always
+ */
+ pad_len = outputdatalength - reply_len;
+ if (pad_len > 0) {
+ if (pad_len < 10)
+ return -EINVAL;
+ /* 'restore' padding left in the PCICC/PCIXCC card. */
+ if (copy_to_user(outputdata, static_pad, pad_len - 1))
+ return -EFAULT;
+ if (put_user(0, outputdata + pad_len - 1))
+ return -EFAULT;
+ }
+ /* Copy the crypto response to user space. */
+ if (copy_to_user(outputdata + pad_len, data, reply_len))
+ return -EFAULT;
+ return 0;
+}
+
+/**
+ * Copy results from a type 86 XCRB reply message back to user space.
+ *
+ * @zdev: crypto device pointer
+ * @reply: reply AP message.
+ * @xcRB: pointer to XCRB
+ *
+ * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
+ */
+static int convert_type86_xcrb(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ struct ica_xcRB *xcRB)
+{
+ struct type86_fmt2_msg *msg = reply->message;
+ char *data = reply->message;
+
+ /* Copy CPRB to user */
+ if (copy_to_user(xcRB->reply_control_blk_addr,
+ data + msg->fmt2.offset1, msg->fmt2.count1))
+ return -EFAULT;
+ xcRB->reply_control_blk_length = msg->fmt2.count1;
+
+ /* Copy data buffer to user */
+ if (msg->fmt2.count2)
+ if (copy_to_user(xcRB->reply_data_addr,
+ data + msg->fmt2.offset2, msg->fmt2.count2))
+ return -EFAULT;
+ xcRB->reply_data_length = msg->fmt2.count2;
+ return 0;
+}
+
+static int convert_response_ica(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ char __user *outputdata,
+ unsigned int outputdatalength)
+{
+ struct type86x_reply *msg = reply->message;
+
+ /* Response type byte is the second byte in the response. */
+ switch (((unsigned char *) reply->message)[1]) {
+ case TYPE82_RSP_CODE:
+ case TYPE88_RSP_CODE:
+ return convert_error(zdev, reply);
+ case TYPE86_RSP_CODE:
+ if (msg->hdr.reply_code)
+ return convert_error(zdev, reply);
+ if (msg->cprbx.cprb_ver_id == 0x02)
+ return convert_type86_ica(zdev, reply,
+ outputdata, outputdatalength);
+ /* no break, incorrect cprb version is an unknown response */
+ default: /* Unknown response type, this should NEVER EVER happen */
+ PRINTK("Unrecognized Message Header: %08x%08x\n",
+ *(unsigned int *) reply->message,
+ *(unsigned int *) (reply->message+4));
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+}
+
+static int convert_response_xcrb(struct zcrypt_device *zdev,
+ struct ap_message *reply,
+ struct ica_xcRB *xcRB)
+{
+ struct type86x_reply *msg = reply->message;
+
+ /* Response type byte is the second byte in the response. */
+ switch (((unsigned char *) reply->message)[1]) {
+ case TYPE82_RSP_CODE:
+ case TYPE88_RSP_CODE:
+ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
+ return convert_error(zdev, reply);
+ case TYPE86_RSP_CODE:
+ if (msg->hdr.reply_code) {
+ memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
+ return convert_error(zdev, reply);
+ }
+ if (msg->cprbx.cprb_ver_id == 0x02)
+ return convert_type86_xcrb(zdev, reply, xcRB);
+ /* no break, incorrect cprb version is an unknown response */
+ default: /* Unknown response type, this should NEVER EVER happen */
+ PRINTK("Unrecognized Message Header: %08x%08x\n",
+ *(unsigned int *) reply->message,
+ *(unsigned int *) (reply->message+4));
+ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
+ zdev->online = 0;
+ return -EAGAIN; /* repeat the request on a different device. */
+ }
+}
+
+/**
+ * This function is called from the AP bus code after a crypto request
+ * "msg" has finished with the reply message "reply".
+ * It is called from tasklet context.
+ * @ap_dev: pointer to the AP device
+ * @msg: pointer to the AP message
+ * @reply: pointer to the AP reply message
+ */
+static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
+ struct ap_message *msg,
+ struct ap_message *reply)
+{
+ static struct error_hdr error_reply = {
+ .type = TYPE82_RSP_CODE,
+ .reply_code = REP82_ERROR_MACHINE_FAILURE,
+ };
+ struct response_type *resp_type =
+ (struct response_type *) msg->private;
+ struct type86x_reply *t86r = reply->message;
+ int length;
+
+ /* Copy the reply message to the request message buffer. */
+ if (IS_ERR(reply))
+ memcpy(msg->message, &error_reply, sizeof(error_reply));
+ else if (t86r->hdr.type == TYPE86_RSP_CODE &&
+ t86r->cprbx.cprb_ver_id == 0x02) {
+ switch (resp_type->type) {
+ case PCIXCC_RESPONSE_TYPE_ICA:
+ length = sizeof(struct type86x_reply)
+ + t86r->length - 2;
+ length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
+ memcpy(msg->message, reply->message, length);
+ break;
+ case PCIXCC_RESPONSE_TYPE_XCRB:
+ length = t86r->fmt2.offset2 + t86r->fmt2.count2;
+ length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length);
+ memcpy(msg->message, reply->message, length);
+ break;
+ default:
+ PRINTK("Invalid internal response type: %i\n",
+ resp_type->type);
+ memcpy(msg->message, &error_reply,
+ sizeof error_reply);
+ }
+ } else
+ memcpy(msg->message, reply->message, sizeof error_reply);
+ complete(&(resp_type->work));
+}
+
+static atomic_t zcrypt_step = ATOMIC_INIT(0);
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a modexpo request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCIXCC/CEX2C device to the request distributor
+ * @mex: pointer to the modexpo request buffer
+ */
+static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo *mex)
+{
+ struct ap_message ap_msg;
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_ICA,
+ };
+ int rc;
+
+ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &resp_type;
+ rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
+ if (rc)
+ goto out_free;
+ init_completion(&resp_type.work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &resp_type.work, PCIXCC_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
+ mex->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ free_page((unsigned long) ap_msg.message);
+ return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a modexpo_crt request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCIXCC/CEX2C device to the request distributor
+ * @crt: pointer to the modexpoc_crt request buffer
+ */
+static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
+ struct ica_rsa_modexpo_crt *crt)
+{
+ struct ap_message ap_msg;
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_ICA,
+ };
+ int rc;
+
+ ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &resp_type;
+ rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
+ if (rc)
+ goto out_free;
+ init_completion(&resp_type.work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &resp_type.work, PCIXCC_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
+ crt->outputdatalength);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ free_page((unsigned long) ap_msg.message);
+ return rc;
+}
+
+/**
+ * The request distributor calls this function if it picked the PCIXCC/CEX2C
+ * device to handle a send_cprb request.
+ * @zdev: pointer to zcrypt_device structure that identifies the
+ * PCIXCC/CEX2C device to the request distributor
+ * @xcRB: pointer to the send_cprb request buffer
+ */
+long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+{
+ struct ap_message ap_msg;
+ struct response_type resp_type = {
+ .type = PCIXCC_RESPONSE_TYPE_XCRB,
+ };
+ int rc;
+
+ ap_msg.message = (void *) kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
+ if (!ap_msg.message)
+ return -ENOMEM;
+ ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
+ atomic_inc_return(&zcrypt_step);
+ ap_msg.private = &resp_type;
+ rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB);
+ if (rc)
+ goto out_free;
+ init_completion(&resp_type.work);
+ ap_queue_message(zdev->ap_dev, &ap_msg);
+ rc = wait_for_completion_interruptible_timeout(
+ &resp_type.work, PCIXCC_CLEANUP_TIME);
+ if (rc > 0)
+ rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
+ else {
+ /* Signal pending or message timed out. */
+ ap_cancel_message(zdev->ap_dev, &ap_msg);
+ if (rc == 0)
+ /* Message timed out. */
+ rc = -ETIME;
+ }
+out_free:
+ memset(ap_msg.message, 0x0, ap_msg.length);
+ kfree(ap_msg.message);
+ return rc;
+}
+
+/**
+ * The crypto operations for a PCIXCC/CEX2C card.
+ */
+static struct zcrypt_ops zcrypt_pcixcc_ops = {
+ .rsa_modexpo = zcrypt_pcixcc_modexpo,
+ .rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
+ .send_cprb = zcrypt_pcixcc_send_cprb,
+};
+
+/**
+ * Micro-code detection function. Its sends a message to a pcixcc card
+ * to find out the microcode level.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev)
+{
+ static unsigned char msg[] = {
+ 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,
+ 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,
+ 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,
+ 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,
+ 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,
+ 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,
+ 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,
+ 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,
+ 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,
+ 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,
+ 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,
+ 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,
+ 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,
+ 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,
+ 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,
+ 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,
+ 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,
+ 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,
+ 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,
+ 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,
+ 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,
+ 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,
+ 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,
+ 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,
+ 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,
+ 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,
+ 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,
+ 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,
+ 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,
+ 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,
+ 0xF1,0x3D,0x93,0x53
+ };
+ unsigned long long psmid;
+ struct CPRBX *cprbx;
+ char *reply;
+ int rc, i;
+
+ reply = (void *) get_zeroed_page(GFP_KERNEL);
+ if (!reply)
+ return -ENOMEM;
+
+ rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));
+ if (rc)
+ goto out_free;
+
+ /* Wait for the test message to complete. */
+ for (i = 0; i < 6; i++) {
+ mdelay(300);
+ rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);
+ if (rc == 0 && psmid == 0x0102030405060708ULL)
+ break;
+ }
+
+ if (i >= 6) {
+ /* Got no answer. */
+ rc = -ENODEV;
+ goto out_free;
+ }
+
+ cprbx = (struct CPRBX *) (reply + 48);
+ if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)
+ rc = ZCRYPT_PCIXCC_MCL2;
+ else
+ rc = ZCRYPT_PCIXCC_MCL3;
+out_free:
+ free_page((unsigned long) reply);
+ return rc;
+}
+
+/**
+ * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device
+ * since the bus_match already checked the hardware type. The PCIXCC
+ * cards come in two flavours: micro code level 2 and micro code level 3.
+ * This is checked by sending a test message to the device.
+ * @ap_dev: pointer to the AP device.
+ */
+static int zcrypt_pcixcc_probe(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev;
+ int rc;
+
+ zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);
+ if (!zdev)
+ return -ENOMEM;
+ zdev->ap_dev = ap_dev;
+ zdev->ops = &zcrypt_pcixcc_ops;
+ zdev->online = 1;
+ if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {
+ rc = zcrypt_pcixcc_mcl(ap_dev);
+ if (rc < 0) {
+ zcrypt_device_free(zdev);
+ return rc;
+ }
+ zdev->user_space_type = rc;
+ if (rc == ZCRYPT_PCIXCC_MCL2) {
+ zdev->type_string = "PCIXCC_MCL2";
+ zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;
+ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;
+ zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ } else {
+ zdev->type_string = "PCIXCC_MCL3";
+ zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;
+ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
+ zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ }
+ } else {
+ zdev->user_space_type = ZCRYPT_CEX2C;
+ zdev->type_string = "CEX2C";
+ zdev->speed_rating = CEX2C_SPEED_RATING;
+ zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;
+ zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;
+ }
+ ap_dev->reply = &zdev->reply;
+ ap_dev->private = zdev;
+ rc = zcrypt_device_register(zdev);
+ if (rc)
+ goto out_free;
+ return 0;
+
+ out_free:
+ ap_dev->private = NULL;
+ zcrypt_device_free(zdev);
+ return rc;
+}
+
+/**
+ * This is called to remove the extended PCIXCC/CEX2C driver information
+ * if an AP device is removed.
+ */
+static void zcrypt_pcixcc_remove(struct ap_device *ap_dev)
+{
+ struct zcrypt_device *zdev = ap_dev->private;
+
+ zcrypt_device_unregister(zdev);
+}
+
+int __init zcrypt_pcixcc_init(void)
+{
+ return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");
+}
+
+void zcrypt_pcixcc_exit(void)
+{
+ ap_driver_unregister(&zcrypt_pcixcc_driver);
+}
+
+#ifndef CONFIG_ZCRYPT_MONOLITHIC
+module_init(zcrypt_pcixcc_init);
+module_exit(zcrypt_pcixcc_exit);
+#endif
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h
new file mode 100644
index 00000000000..a78ff307fd1
--- /dev/null
+++ b/drivers/s390/crypto/zcrypt_pcixcc.h
@@ -0,0 +1,79 @@
+/*
+ * linux/drivers/s390/crypto/zcrypt_pcixcc.h
+ *
+ * zcrypt 2.1.0
+ *
+ * Copyright (C) 2001, 2006 IBM Corporation
+ * Author(s): Robert Burroughs
+ * Eric Rossman (edrossma@us.ibm.com)
+ *
+ * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com)
+ * Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, 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 _ZCRYPT_PCIXCC_H_
+#define _ZCRYPT_PCIXCC_H_
+
+/**
+ * CPRBX
+ * Note that all shorts and ints are big-endian.
+ * All pointer fields are 16 bytes long, and mean nothing.
+ *
+ * A request CPRB is followed by a request_parameter_block.
+ *
+ * The request (or reply) parameter block is organized thus:
+ * function code
+ * VUD block
+ * key block
+ */
+struct CPRBX {
+ unsigned short cprb_len; /* CPRB length 220 */
+ unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
+ unsigned char pad_000[3]; /* Alignment pad bytes */
+ unsigned char func_id[2]; /* function id 0x5432 */
+ unsigned char cprb_flags[4]; /* Flags */
+ unsigned int req_parml; /* request parameter buffer len */
+ unsigned int req_datal; /* request data buffer */
+ unsigned int rpl_msgbl; /* reply message block length */
+ unsigned int rpld_parml; /* replied parameter block len */
+ unsigned int rpl_datal; /* reply data block len */
+ unsigned int rpld_datal; /* replied data block len */
+ unsigned int req_extbl; /* request extension block len */
+ unsigned char pad_001[4]; /* reserved */
+ unsigned int rpld_extbl; /* replied extension block len */
+ unsigned char req_parmb[16]; /* request parm block 'address' */
+ unsigned char req_datab[16]; /* request data block 'address' */
+ unsigned char rpl_parmb[16]; /* reply parm block 'address' */
+ unsigned char rpl_datab[16]; /* reply data block 'address' */
+ unsigned char req_extb[16]; /* request extension block 'addr'*/
+ unsigned char rpl_extb[16]; /* reply extension block 'addres'*/
+ unsigned short ccp_rtcode; /* server return code */
+ unsigned short ccp_rscode; /* server reason code */
+ unsigned int mac_data_len; /* Mac Data Length */
+ unsigned char logon_id[8]; /* Logon Identifier */
+ unsigned char mac_value[8]; /* Mac Value */
+ unsigned char mac_content_flgs;/* Mac content flag byte */
+ unsigned char pad_002; /* Alignment */
+ unsigned short domain; /* Domain */
+ unsigned char pad_003[12]; /* Domain masks */
+ unsigned char pad_004[36]; /* reserved */
+} __attribute__((packed));
+
+int zcrypt_pcixcc_init(void);
+void zcrypt_pcixcc_exit(void);
+
+#endif /* _ZCRYPT_PCIXCC_H_ */
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig
index 54885475492..1a93fa684e9 100644
--- a/drivers/s390/net/Kconfig
+++ b/drivers/s390/net/Kconfig
@@ -92,15 +92,6 @@ config QETH_VLAN
If CONFIG_QETH is switched on, this option will include IEEE
802.1q VLAN support in the qeth device driver.
-config QETH_PERF_STATS
- bool "Performance statistics in /proc"
- depends on QETH
- help
- When switched on, this option will add a file in the proc-fs
- (/proc/qeth_perf_stats) containing performance statistics. It
- may slightly impact performance, so this is only recommended for
- internal tuning of the device driver.
-
config CCWGROUP
tristate
default (LCS || CTC || QETH)
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile
index 6775a837d64..4777e36a922 100644
--- a/drivers/s390/net/Makefile
+++ b/drivers/s390/net/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_SMSGIUCV) += smsgiucv.o
obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o
obj-$(CONFIG_LCS) += lcs.o cu3088.o
obj-$(CONFIG_CLAW) += claw.o cu3088.o
-obj-$(CONFIG_MPC) += ctcmpc.o fsm.o cu3088.o
qeth-y := qeth_main.o qeth_mpc.o qeth_sys.o qeth_eddp.o
qeth-$(CONFIG_PROC_FS) += qeth_proc.o
obj-$(CONFIG_QETH) += qeth.o
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 23d53bf9daf..95f4e105cb9 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -529,7 +529,7 @@ claw_open(struct net_device *dev)
printk(KERN_INFO "%s:%s Enter \n",dev->name,__FUNCTION__);
#endif
CLAW_DBF_TEXT(4,trace,"open");
- if (!dev | (dev->name[0] == 0x00)) {
+ if (!dev || (dev->name[0] == 0x00)) {
CLAW_DBF_TEXT(2,trace,"BadDev");
printk(KERN_WARNING "claw: Bad device at open failing \n");
return -ENODEV;
diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c
index 20c8eb16f46..3257c22dd79 100644
--- a/drivers/s390/net/ctcmain.c
+++ b/drivers/s390/net/ctcmain.c
@@ -1714,6 +1714,9 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
kfree(ch);
return 0;
}
+
+ spin_lock_init(&ch->collect_lock);
+
fsm_settimer(ch->fsm, &ch->timer);
skb_queue_head_init(&ch->io_queue);
skb_queue_head_init(&ch->collect_queue);
@@ -2686,9 +2689,17 @@ static struct attribute_group ctc_attr_group = {
static int
ctc_add_attributes(struct device *dev)
{
- device_create_file(dev, &dev_attr_loglevel);
- device_create_file(dev, &dev_attr_stats);
- return 0;
+ int rc;
+
+ rc = device_create_file(dev, &dev_attr_loglevel);
+ if (rc)
+ goto out;
+ rc = device_create_file(dev, &dev_attr_stats);
+ if (!rc)
+ goto out;
+ device_remove_file(dev, &dev_attr_loglevel);
+out:
+ return rc;
}
static void
@@ -2901,7 +2912,12 @@ ctc_new_device(struct ccwgroup_device *cgdev)
goto out;
}
- ctc_add_attributes(&cgdev->dev);
+ if (ctc_add_attributes(&cgdev->dev)) {
+ ctc_netdev_unregister(dev);
+ dev->priv = NULL;
+ ctc_free_netdevice(dev, 1);
+ goto out;
+ }
strlcpy(privptr->fsm->name, dev->name, sizeof (privptr->fsm->name));
diff --git a/drivers/s390/net/fsm.c b/drivers/s390/net/fsm.c
index 7145e2134cf..2c1db8036b7 100644
--- a/drivers/s390/net/fsm.c
+++ b/drivers/s390/net/fsm.c
@@ -4,7 +4,6 @@
*/
#include "fsm.h"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/timer.h>
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
index e0c7deb9883..809dd8d7f47 100644
--- a/drivers/s390/net/iucv.c
+++ b/drivers/s390/net/iucv.c
@@ -33,7 +33,6 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
@@ -336,8 +335,8 @@ do { \
#else
-#define iucv_debug(lvl, fmt, args...)
-#define iucv_dumpit(title, buf, len)
+#define iucv_debug(lvl, fmt, args...) do { } while (0)
+#define iucv_dumpit(title, buf, len) do { } while (0)
#endif
@@ -535,19 +534,15 @@ iucv_add_handler (handler *new)
*
* Returns: return code from CP's IUCV call
*/
-static __inline__ ulong
-b2f0(__u32 code, void *parm)
+static inline ulong b2f0(__u32 code, void *parm)
{
+ register unsigned long reg0 asm ("0");
+ register unsigned long reg1 asm ("1");
iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
- asm volatile (
- "LRA 1,0(%1)\n\t"
- "LR 0,%0\n\t"
- ".long 0xb2f01000"
- :
- : "d" (code), "a" (parm)
- : "0", "1"
- );
+ reg0 = code;
+ reg1 = virt_to_phys(parm);
+ asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
@@ -693,7 +688,7 @@ iucv_retrieve_buffer (void)
iucv_debug(1, "entering");
if (iucv_cpuid != -1) {
smp_call_function_on(iucv_retrieve_buffer_cpuid,
- 0, 0, 1, iucv_cpuid);
+ NULL, 0, 1, iucv_cpuid);
/* Release the cpu reserved by iucv_declare_buffer. */
smp_put_cpu(iucv_cpuid);
iucv_cpuid = -1;
@@ -1249,6 +1244,8 @@ iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
static int
iucv_query_generic(int want_maxconn)
{
+ register unsigned long reg0 asm ("0");
+ register unsigned long reg1 asm ("1");
iparml_purge *parm = (iparml_purge *)grab_param();
int bufsize, maxconn;
int ccode;
@@ -1257,18 +1254,15 @@ iucv_query_generic(int want_maxconn)
* Call b2f0 and store R0 (max buffer size),
* R1 (max connections) and CC.
*/
- asm volatile (
- "LRA 1,0(%4)\n\t"
- "LR 0,%3\n\t"
- ".long 0xb2f01000\n\t"
- "IPM %0\n\t"
- "SRL %0,28\n\t"
- "ST 0,%1\n\t"
- "ST 1,%2\n\t"
- : "=d" (ccode), "=m" (bufsize), "=m" (maxconn)
- : "d" (QUERY), "a" (parm)
- : "0", "1", "cc"
- );
+ reg0 = QUERY;
+ reg1 = virt_to_phys(parm);
+ asm volatile(
+ " .long 0xb2f01000\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
+ bufsize = reg0;
+ maxconn = reg1;
release_param(parm);
if (ccode)
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index f94419b334f..16ac68c27a2 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -670,9 +670,8 @@ lcs_ready_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, rc;
LCS_DBF_TEXT(5, trace, "rdybuff");
- if (buffer->state != BUF_STATE_LOCKED &&
- buffer->state != BUF_STATE_PROCESSED)
- BUG();
+ BUG_ON(buffer->state != BUF_STATE_LOCKED &&
+ buffer->state != BUF_STATE_PROCESSED);
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_READY;
index = buffer - channel->iob;
@@ -696,8 +695,7 @@ __lcs_processed_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
int index, prev, next;
LCS_DBF_TEXT(5, trace, "prcsbuff");
- if (buffer->state != BUF_STATE_READY)
- BUG();
+ BUG_ON(buffer->state != BUF_STATE_READY);
buffer->state = BUF_STATE_PROCESSED;
index = buffer - channel->iob;
prev = (index - 1) & (LCS_NUM_BUFFS - 1);
@@ -729,9 +727,8 @@ lcs_release_buffer(struct lcs_channel *channel, struct lcs_buffer *buffer)
unsigned long flags;
LCS_DBF_TEXT(5, trace, "relbuff");
- if (buffer->state != BUF_STATE_LOCKED &&
- buffer->state != BUF_STATE_PROCESSED)
- BUG();
+ BUG_ON(buffer->state != BUF_STATE_LOCKED &&
+ buffer->state != BUF_STATE_PROCESSED);
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
buffer->state = BUF_STATE_EMPTY;
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
@@ -1140,10 +1137,9 @@ list_modified:
}
}
/* re-insert all entries from the failed_list into ipm_list */
- list_for_each_entry_safe(ipm, tmp, &failed_list, list) {
- list_del_init(&ipm->list);
- list_add_tail(&ipm->list, &card->ipm_list);
- }
+ list_for_each_entry_safe(ipm, tmp, &failed_list, list)
+ list_move_tail(&ipm->list, &card->ipm_list);
+
spin_unlock_irqrestore(&card->ipm_lock, flags);
}
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index b452cc1afd5..d7d1cc0a5c8 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -112,7 +112,12 @@ struct iucv_connection {
/**
* Linked list of all connection structs.
*/
-static struct iucv_connection *iucv_connections;
+struct iucv_connection_struct {
+ struct iucv_connection *iucv_connections;
+ rwlock_t iucv_rwlock;
+};
+
+static struct iucv_connection_struct iucv_conns;
/**
* Representation of event-data for the
@@ -1368,8 +1373,10 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
struct net_device *ndev = priv->conn->netdev;
char *p;
char *tmp;
- char username[10];
+ char username[9];
int i;
+ struct iucv_connection **clist = &iucv_conns.iucv_connections;
+ unsigned long flags;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
@@ -1382,7 +1389,7 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
tmp = strsep((char **) &buf, "\n");
for (i=0, p=tmp; i<8 && *p; i++, p++) {
if (isalnum(*p) || (*p == '$'))
- username[i]= *p;
+ username[i]= toupper(*p);
else if (*p == '\n') {
/* trailing lf, grr */
break;
@@ -1395,11 +1402,11 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
return -EINVAL;
}
}
- while (i<9)
+ while (i<8)
username[i++] = ' ';
- username[9] = '\0';
+ username[8] = '\0';
- if (memcmp(username, priv->conn->userid, 8)) {
+ if (memcmp(username, priv->conn->userid, 9)) {
/* username changed */
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
PRINT_WARN(
@@ -1410,6 +1417,19 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf,
return -EBUSY;
}
}
+ read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
+ while (*clist) {
+ if (!strncmp(username, (*clist)->userid, 9) ||
+ ((*clist)->netdev != ndev))
+ break;
+ clist = &((*clist)->next);
+ }
+ read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ if (*clist) {
+ PRINT_WARN("netiucv: Connection to %s already exists\n",
+ username);
+ return -EEXIST;
+ }
memcpy(priv->conn->userid, username, 9);
return count;
@@ -1781,13 +1801,15 @@ netiucv_unregister_device(struct device *dev)
static struct iucv_connection *
netiucv_new_connection(struct net_device *dev, char *username)
{
- struct iucv_connection **clist = &iucv_connections;
+ unsigned long flags;
+ struct iucv_connection **clist = &iucv_conns.iucv_connections;
struct iucv_connection *conn =
kzalloc(sizeof(struct iucv_connection), GFP_KERNEL);
if (conn) {
skb_queue_head_init(&conn->collect_queue);
skb_queue_head_init(&conn->commit_queue);
+ spin_lock_init(&conn->collect_lock);
conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT;
conn->netdev = dev;
@@ -1822,8 +1844,10 @@ netiucv_new_connection(struct net_device *dev, char *username)
fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
}
+ write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
conn->next = *clist;
*clist = conn;
+ write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
}
return conn;
}
@@ -1835,14 +1859,17 @@ netiucv_new_connection(struct net_device *dev, char *username)
static void
netiucv_remove_connection(struct iucv_connection *conn)
{
- struct iucv_connection **clist = &iucv_connections;
+ struct iucv_connection **clist = &iucv_conns.iucv_connections;
+ unsigned long flags;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (conn == NULL)
return;
+ write_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
while (*clist) {
if (*clist == conn) {
*clist = conn->next;
+ write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
if (conn->handle) {
iucv_unregister_program(conn->handle);
conn->handle = NULL;
@@ -1855,6 +1882,7 @@ netiucv_remove_connection(struct iucv_connection *conn)
}
clist = &((*clist)->next);
}
+ write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
}
/**
@@ -1947,9 +1975,11 @@ static ssize_t
conn_write(struct device_driver *drv, const char *buf, size_t count)
{
char *p;
- char username[10];
+ char username[9];
int i, ret;
struct net_device *dev;
+ struct iucv_connection **clist = &iucv_conns.iucv_connections;
+ unsigned long flags;
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count>9) {
@@ -1960,7 +1990,7 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
for (i=0, p=(char *)buf; i<8 && *p; i++, p++) {
if (isalnum(*p) || (*p == '$'))
- username[i]= *p;
+ username[i]= toupper(*p);
else if (*p == '\n') {
/* trailing lf, grr */
break;
@@ -1971,9 +2001,22 @@ conn_write(struct device_driver *drv, const char *buf, size_t count)
return -EINVAL;
}
}
- while (i<9)
+ while (i<8)
username[i++] = ' ';
- username[9] = '\0';
+ username[8] = '\0';
+
+ read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
+ while (*clist) {
+ if (!strncmp(username, (*clist)->userid, 9))
+ break;
+ clist = &((*clist)->next);
+ }
+ read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
+ if (*clist) {
+ PRINT_WARN("netiucv: Connection to %s already exists\n",
+ username);
+ return -EEXIST;
+ }
dev = netiucv_init_netdevice(username);
if (!dev) {
PRINT_WARN(
@@ -2015,7 +2058,8 @@ DRIVER_ATTR(connection, 0200, NULL, conn_write);
static ssize_t
remove_write (struct device_driver *drv, const char *buf, size_t count)
{
- struct iucv_connection **clist = &iucv_connections;
+ struct iucv_connection **clist = &iucv_conns.iucv_connections;
+ unsigned long flags;
struct net_device *ndev;
struct netiucv_priv *priv;
struct device *dev;
@@ -2026,10 +2070,10 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
if (count >= IFNAMSIZ)
- count = IFNAMSIZ-1;
+ count = IFNAMSIZ - 1;;
for (i=0, p=(char *)buf; i<count && *p; i++, p++) {
- if ((*p == '\n') | (*p == ' ')) {
+ if ((*p == '\n') || (*p == ' ')) {
/* trailing lf, grr */
break;
} else {
@@ -2038,6 +2082,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
}
name[i] = '\0';
+ read_lock_irqsave(&iucv_conns.iucv_rwlock, flags);
while (*clist) {
ndev = (*clist)->netdev;
priv = (struct netiucv_priv*)ndev->priv;
@@ -2047,6 +2092,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
clist = &((*clist)->next);
continue;
}
+ read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
if (ndev->flags & (IFF_UP | IFF_RUNNING)) {
PRINT_WARN(
"netiucv: net device %s active with peer %s\n",
@@ -2060,6 +2106,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
netiucv_unregister_device(dev);
return count;
}
+ read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags);
PRINT_WARN("netiucv: net device %s unknown\n", name);
IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n");
return -EINVAL;
@@ -2077,8 +2124,8 @@ static void __exit
netiucv_exit(void)
{
IUCV_DBF_TEXT(trace, 3, __FUNCTION__);
- while (iucv_connections) {
- struct net_device *ndev = iucv_connections->netdev;
+ while (iucv_conns.iucv_connections) {
+ struct net_device *ndev = iucv_conns.iucv_connections->netdev;
struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv;
struct device *dev = priv->dev;
@@ -2120,6 +2167,7 @@ netiucv_init(void)
if (!ret) {
ret = driver_create_file(&netiucv_driver, &driver_attr_remove);
netiucv_banner();
+ rwlock_init(&iucv_conns.iucv_rwlock);
} else {
PRINT_ERR("NETIUCV: failed to add driver attribute.\n");
IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret);
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index 619f4a0c716..821383d8cbe 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -176,7 +176,6 @@ extern struct ccwgroup_driver qeth_ccwgroup_driver;
/**
* card stuff
*/
-#ifdef CONFIG_QETH_PERF_STATS
struct qeth_perf_stats {
unsigned int bufs_rec;
unsigned int bufs_sent;
@@ -211,8 +210,10 @@ struct qeth_perf_stats {
unsigned int large_send_cnt;
unsigned int sg_skbs_sent;
unsigned int sg_frags_sent;
+ /* initial values when measuring starts */
+ unsigned long initial_rx_packets;
+ unsigned long initial_tx_packets;
};
-#endif /* CONFIG_QETH_PERF_STATS */
/* Routing stuff */
struct qeth_routing_info {
@@ -462,6 +463,7 @@ enum qeth_qdio_info_states {
QETH_QDIO_UNINITIALIZED,
QETH_QDIO_ALLOCATED,
QETH_QDIO_ESTABLISHED,
+ QETH_QDIO_CLEANING
};
struct qeth_buffer_pool_entry {
@@ -536,7 +538,7 @@ struct qeth_qdio_out_q {
} __attribute__ ((aligned(256)));
struct qeth_qdio_info {
- volatile enum qeth_qdio_info_states state;
+ atomic_t state;
/* input */
struct qeth_qdio_q *in_q;
struct qeth_qdio_buffer_pool in_buf_pool;
@@ -767,6 +769,7 @@ struct qeth_card_options {
int fake_ll;
int layer2;
enum qeth_large_send_types large_send;
+ int performance_stats;
};
/*
@@ -819,9 +822,7 @@ struct qeth_card {
struct list_head cmd_waiter_list;
/* QDIO buffer handling */
struct qeth_qdio_info qdio;
-#ifdef CONFIG_QETH_PERF_STATS
struct qeth_perf_stats perf_stats;
-#endif /* CONFIG_QETH_PERF_STATS */
int use_hard_stop;
int (*orig_hard_header)(struct sk_buff *,struct net_device *,
unsigned short,void *,void *,unsigned);
@@ -859,23 +860,18 @@ qeth_get_ipa_adp_type(enum qeth_link_types link_type)
}
}
-static inline int
-qeth_realloc_headroom(struct qeth_card *card, struct sk_buff **skb, int size)
+static inline struct sk_buff *
+qeth_realloc_headroom(struct qeth_card *card, struct sk_buff *skb, int size)
{
- struct sk_buff *new_skb = NULL;
-
- if (skb_headroom(*skb) < size){
- new_skb = skb_realloc_headroom(*skb, size);
- if (!new_skb) {
- PRINT_ERR("qeth_prepare_skb: could "
- "not realloc headroom for qeth_hdr "
- "on interface %s", QETH_CARD_IFNAME(card));
- return -ENOMEM;
- }
- kfree_skb(*skb);
- *skb = new_skb;
- }
- return 0;
+ struct sk_buff *new_skb = skb;
+
+ if (skb_headroom(skb) >= size)
+ return skb;
+ new_skb = skb_realloc_headroom(skb, size);
+ if (!new_skb)
+ PRINT_ERR("Could not realloc headroom for qeth_hdr "
+ "on interface %s", QETH_CARD_IFNAME(card));
+ return new_skb;
}
static inline struct sk_buff *
@@ -885,16 +881,15 @@ qeth_pskb_unshare(struct sk_buff *skb, int pri)
if (!skb_cloned(skb))
return skb;
nskb = skb_copy(skb, pri);
- kfree_skb(skb); /* free our shared copy */
return nskb;
}
static inline void *
-qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
+qeth_push_skb(struct qeth_card *card, struct sk_buff *skb, int size)
{
void *hdr;
- hdr = (void *) skb_push(*skb, size);
+ hdr = (void *) skb_push(skb, size);
/*
* sanity check, the Linux memory allocation scheme should
* never present us cases like this one (the qdio header size plus
@@ -903,8 +898,7 @@ qeth_push_skb(struct qeth_card *card, struct sk_buff **skb, int size)
if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
(((unsigned long) hdr + size +
QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
- PRINT_ERR("qeth_prepare_skb: misaligned "
- "packet on interface %s. Discarded.",
+ PRINT_ERR("Misaligned packet on interface %s. Discarded.",
QETH_CARD_IFNAME(card));
return NULL;
}
@@ -1056,13 +1050,11 @@ qeth_get_arphdr_type(int cardtype, int linktype)
}
}
-#ifdef CONFIG_QETH_PERF_STATS
static inline int
qeth_get_micros(void)
{
return (int) (get_clock() >> 12);
}
-#endif
static inline int
qeth_get_qdio_q_format(struct qeth_card *card)
@@ -1096,10 +1088,11 @@ qeth_string_to_ipaddr4(const char *buf, __u8 *addr)
{
int count = 0, rc = 0;
int in[4];
+ char c;
- rc = sscanf(buf, "%d.%d.%d.%d%n",
- &in[0], &in[1], &in[2], &in[3], &count);
- if (rc != 4 || count<=0)
+ rc = sscanf(buf, "%u.%u.%u.%u%c",
+ &in[0], &in[1], &in[2], &in[3], &c);
+ if (rc != 4 && (rc != 5 || c != '\n'))
return -EINVAL;
for (count = 0; count < 4; count++) {
if (in[count] > 255)
@@ -1123,24 +1116,28 @@ qeth_ipaddr6_to_string(const __u8 *addr, char *buf)
static inline int
qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
{
- char *end, *start;
+ const char *end, *end_tmp, *start;
__u16 *in;
char num[5];
int num2, cnt, out, found, save_cnt;
unsigned short in_tmp[8] = {0, };
cnt = out = found = save_cnt = num2 = 0;
- end = start = (char *) buf;
+ end = start = buf;
in = (__u16 *) addr;
memset(in, 0, 16);
- while (end) {
- end = strchr(end,':');
+ while (*end) {
+ end = strchr(start,':');
if (end == NULL) {
- end = (char *)buf + (strlen(buf));
- out = 1;
+ end = buf + strlen(buf);
+ if ((end_tmp = strchr(start, '\n')) != NULL)
+ end = end_tmp;
+ out = 1;
}
if ((end - start)) {
memset(num, 0, 5);
+ if ((end - start) > 4)
+ return -EINVAL;
memcpy(num, start, end - start);
if (!qeth_isxdigit(num))
return -EINVAL;
@@ -1158,6 +1155,8 @@ qeth_string_to_ipaddr6(const char *buf, __u8 *addr)
}
start = ++end;
}
+ if (cnt + save_cnt > 8)
+ return -EINVAL;
cnt = 7;
while (save_cnt)
in[cnt--] = in_tmp[--save_cnt];
diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
index 38aad832145..a363721cf28 100644
--- a/drivers/s390/net/qeth_eddp.c
+++ b/drivers/s390/net/qeth_eddp.c
@@ -8,7 +8,6 @@
* Author(s): Thomas Spatzier <tspat@de.ibm.com>
*
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/ip.h>
#include <linux/inetdevice.h>
@@ -180,9 +179,8 @@ out_check:
flush_cnt++;
}
} else {
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.skbs_sent_pack++;
-#endif
+ if (queue->card->options.performance_stats)
+ queue->card->perf_stats.skbs_sent_pack++;
QETH_DBF_TEXT(trace, 6, "fillbfpa");
if (buf->next_element_to_fill >=
QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 56009d76832..8364d5475ac 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -27,7 +27,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/string.h>
@@ -85,6 +84,8 @@ static debug_info_t *qeth_dbf_qerr = NULL;
DEFINE_PER_CPU(char[256], qeth_dbf_txt_buf);
+static struct lock_class_key qdio_out_skb_queue_key;
+
/**
* some more definitions and declarations
*/
@@ -1072,6 +1073,7 @@ qeth_set_intial_options(struct qeth_card *card)
card->options.layer2 = 1;
else
card->options.layer2 = 0;
+ card->options.performance_stats = 1;
}
/**
@@ -1707,6 +1709,7 @@ qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
"IP address reset.\n",
QETH_CARD_IFNAME(card),
card->info.chpid);
+ netif_carrier_on(card->dev);
qeth_schedule_recovery(card);
return NULL;
case IPA_CMD_MODCCID:
@@ -2463,24 +2466,6 @@ qeth_rebuild_skb_fake_ll(struct qeth_card *card, struct sk_buff *skb,
qeth_rebuild_skb_fake_ll_eth(card, skb, hdr);
}
-static inline void
-qeth_rebuild_skb_vlan(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_hdr *hdr)
-{
-#ifdef CONFIG_QETH_VLAN
- u16 *vlan_tag;
-
- if (hdr->hdr.l3.ext_flags &
- (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) {
- vlan_tag = (u16 *) skb_push(skb, VLAN_HLEN);
- *vlan_tag = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)?
- hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]);
- *(vlan_tag + 1) = skb->protocol;
- skb->protocol = __constant_htons(ETH_P_8021Q);
- }
-#endif /* CONFIG_QETH_VLAN */
-}
-
static inline __u16
qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
@@ -2509,15 +2494,16 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
return vlan_id;
}
-static inline void
+static inline __u16
qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
struct qeth_hdr *hdr)
{
+ unsigned short vlan_id = 0;
#ifdef CONFIG_QETH_IPV6
if (hdr->hdr.l3.flags & QETH_HDR_PASSTHRU) {
skb->pkt_type = PACKET_HOST;
skb->protocol = qeth_type_trans(skb, card->dev);
- return;
+ return 0;
}
#endif /* CONFIG_QETH_IPV6 */
skb->protocol = htons((hdr->hdr.l3.flags & QETH_HDR_IPV6)? ETH_P_IPV6 :
@@ -2539,7 +2525,13 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
default:
skb->pkt_type = PACKET_HOST;
}
- qeth_rebuild_skb_vlan(card, skb, hdr);
+
+ if (hdr->hdr.l3.ext_flags &
+ (QETH_HDR_EXT_VLAN_FRAME | QETH_HDR_EXT_INCLUDE_VLAN_TAG)) {
+ vlan_id = (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_VLAN_FRAME)?
+ hdr->hdr.l3.vlan_id : *((u16 *)&hdr->hdr.l3.dest_addr[12]);
+ }
+
if (card->options.fake_ll)
qeth_rebuild_skb_fake_ll(card, skb, hdr);
else
@@ -2555,6 +2547,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
else
skb->ip_summed = SW_CHECKSUMMING;
}
+ return vlan_id;
}
static inline void
@@ -2567,20 +2560,20 @@ qeth_process_inbound_buffer(struct qeth_card *card,
int offset;
int rxrc;
__u16 vlan_tag = 0;
+ __u16 *vlan_addr;
/* get first element of current buffer */
element = (struct qdio_buffer_element *)&buf->buffer->element[0];
offset = 0;
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.bufs_rec++;
-#endif
+ if (card->options.performance_stats)
+ card->perf_stats.bufs_rec++;
while((skb = qeth_get_next_skb(card, buf->buffer, &element,
&offset, &hdr))) {
skb->dev = card->dev;
if (hdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2)
vlan_tag = qeth_layer2_rebuild_skb(card, skb, hdr);
else if (hdr->hdr.l3.id == QETH_HEADER_TYPE_LAYER3)
- qeth_rebuild_skb(card, skb, hdr);
+ vlan_tag = qeth_rebuild_skb(card, skb, hdr);
else { /*in case of OSN*/
skb_push(skb, sizeof(struct qeth_hdr));
memcpy(skb->data, hdr, sizeof(struct qeth_hdr));
@@ -2590,14 +2583,19 @@ qeth_process_inbound_buffer(struct qeth_card *card,
dev_kfree_skb_any(skb);
continue;
}
+ if (card->info.type == QETH_CARD_TYPE_OSN)
+ rxrc = card->osn_info.data_cb(skb);
+ else
#ifdef CONFIG_QETH_VLAN
if (vlan_tag)
- vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag);
+ if (card->vlangrp)
+ vlan_hwaccel_rx(skb, card->vlangrp, vlan_tag);
+ else {
+ dev_kfree_skb_any(skb);
+ continue;
+ }
else
#endif
- if (card->info.type == QETH_CARD_TYPE_OSN)
- rxrc = card->osn_info.data_cb(skb);
- else
rxrc = netif_rx(skb);
card->dev->last_rx = jiffies;
card->stats.rx_packets++;
@@ -2625,7 +2623,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
{
struct qeth_buffer_pool_entry *pool_entry;
int i;
-
+
pool_entry = qeth_get_buffer_pool_entry(card);
/*
* since the buffer is accessed only from the input_tasklet
@@ -2699,17 +2697,18 @@ qeth_queue_input_buffer(struct qeth_card *card, int index)
* 'index') un-requeued -> this buffer is the first buffer that
* will be requeued the next time
*/
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.inbound_do_qdio_cnt++;
- card->perf_stats.inbound_do_qdio_start_time = qeth_get_micros();
-#endif
+ if (card->options.performance_stats) {
+ card->perf_stats.inbound_do_qdio_cnt++;
+ card->perf_stats.inbound_do_qdio_start_time =
+ qeth_get_micros();
+ }
rc = do_QDIO(CARD_DDEV(card),
QDIO_FLAG_SYNC_INPUT | QDIO_FLAG_UNDER_INTERRUPT,
0, queue->next_buf_to_init, count, NULL);
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.inbound_do_qdio_time += qeth_get_micros() -
- card->perf_stats.inbound_do_qdio_start_time;
-#endif
+ if (card->options.performance_stats)
+ card->perf_stats.inbound_do_qdio_time +=
+ qeth_get_micros() -
+ card->perf_stats.inbound_do_qdio_start_time;
if (rc){
PRINT_WARN("qeth_queue_input_buffer's do_QDIO "
"return %i (device %s).\n",
@@ -2745,10 +2744,10 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
QETH_DBF_TEXT(trace, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.inbound_cnt++;
- card->perf_stats.inbound_start_time = qeth_get_micros();
-#endif
+ if (card->options.performance_stats) {
+ card->perf_stats.inbound_cnt++;
+ card->perf_stats.inbound_start_time = qeth_get_micros();
+ }
if (status & QDIO_STATUS_LOOK_FOR_ERROR) {
if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){
QETH_DBF_TEXT(trace, 1,"qdinchk");
@@ -2770,10 +2769,9 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
qeth_put_buffer_pool_entry(card, buffer->pool_entry);
qeth_queue_input_buffer(card, index);
}
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.inbound_time += qeth_get_micros() -
- card->perf_stats.inbound_start_time;
-#endif
+ if (card->options.performance_stats)
+ card->perf_stats.inbound_time += qeth_get_micros() -
+ card->perf_stats.inbound_start_time;
}
static inline int
@@ -2863,10 +2861,11 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
}
queue->card->dev->trans_start = jiffies;
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.outbound_do_qdio_cnt++;
- queue->card->perf_stats.outbound_do_qdio_start_time = qeth_get_micros();
-#endif
+ if (queue->card->options.performance_stats) {
+ queue->card->perf_stats.outbound_do_qdio_cnt++;
+ queue->card->perf_stats.outbound_do_qdio_start_time =
+ qeth_get_micros();
+ }
if (under_int)
rc = do_QDIO(CARD_DDEV(queue->card),
QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT,
@@ -2874,10 +2873,10 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
else
rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT,
queue->queue_no, index, count, NULL);
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.outbound_do_qdio_time += qeth_get_micros() -
- queue->card->perf_stats.outbound_do_qdio_start_time;
-#endif
+ if (queue->card->options.performance_stats)
+ queue->card->perf_stats.outbound_do_qdio_time +=
+ qeth_get_micros() -
+ queue->card->perf_stats.outbound_do_qdio_start_time;
if (rc){
QETH_DBF_TEXT(trace, 2, "flushbuf");
QETH_DBF_TEXT_(trace, 2, " err%d", rc);
@@ -2889,9 +2888,8 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
return;
}
atomic_add(count, &queue->used_buffers);
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.bufs_sent += count;
-#endif
+ if (queue->card->options.performance_stats)
+ queue->card->perf_stats.bufs_sent += count;
}
/*
@@ -2906,9 +2904,8 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
>= QETH_HIGH_WATERMARK_PACK){
/* switch non-PACKING -> PACKING */
QETH_DBF_TEXT(trace, 6, "np->pack");
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.sc_dp_p++;
-#endif
+ if (queue->card->options.performance_stats)
+ queue->card->perf_stats.sc_dp_p++;
queue->do_pack = 1;
}
}
@@ -2931,9 +2928,8 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
<= QETH_LOW_WATERMARK_PACK) {
/* switch PACKING -> non-PACKING */
QETH_DBF_TEXT(trace, 6, "pack->np");
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.sc_p_dp++;
-#endif
+ if (queue->card->options.performance_stats)
+ queue->card->perf_stats.sc_p_dp++;
queue->do_pack = 0;
/* flush packing buffers */
buffer = &queue->bufs[queue->next_buf_to_fill];
@@ -2945,7 +2941,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
queue->next_buf_to_fill =
(queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
- }
+ }
}
}
return flush_count;
@@ -3001,11 +2997,10 @@ qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
!atomic_read(&queue->set_pci_flags_count))
flush_cnt +=
qeth_flush_buffers_on_no_pci(queue);
-#ifdef CONFIG_QETH_PERF_STATS
- if (q_was_packing)
+ if (queue->card->options.performance_stats &&
+ q_was_packing)
queue->card->perf_stats.bufs_sent_pack +=
flush_cnt;
-#endif
if (flush_cnt)
qeth_flush_buffers(queue, 1, index, flush_cnt);
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
@@ -3035,10 +3030,11 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
return;
}
}
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.outbound_handler_cnt++;
- card->perf_stats.outbound_handler_start_time = qeth_get_micros();
-#endif
+ if (card->options.performance_stats) {
+ card->perf_stats.outbound_handler_cnt++;
+ card->perf_stats.outbound_handler_start_time =
+ qeth_get_micros();
+ }
for(i = first_element; i < (first_element + count); ++i){
buffer = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
/*we only handle the KICK_IT error by doing a recovery */
@@ -3057,10 +3053,9 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status,
qeth_check_outbound_queue(queue);
netif_wake_queue(queue->card->dev);
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.outbound_handler_time += qeth_get_micros() -
- card->perf_stats.outbound_handler_start_time;
-#endif
+ if (card->options.performance_stats)
+ card->perf_stats.outbound_handler_time += qeth_get_micros() -
+ card->perf_stats.outbound_handler_start_time;
}
static void
@@ -3184,13 +3179,14 @@ qeth_alloc_qdio_buffers(struct qeth_card *card)
QETH_DBF_TEXT(setup, 2, "allcqdbf");
- if (card->qdio.state == QETH_QDIO_ALLOCATED)
+ if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_UNINITIALIZED,
+ QETH_QDIO_ALLOCATED) != QETH_QDIO_UNINITIALIZED)
return 0;
card->qdio.in_q = kmalloc(sizeof(struct qeth_qdio_q),
GFP_KERNEL|GFP_DMA);
if (!card->qdio.in_q)
- return - ENOMEM;
+ goto out_nomem;
QETH_DBF_TEXT(setup, 2, "inq");
QETH_DBF_HEX(setup, 2, &card->qdio.in_q, sizeof(void *));
memset(card->qdio.in_q, 0, sizeof(struct qeth_qdio_q));
@@ -3199,27 +3195,19 @@ qeth_alloc_qdio_buffers(struct qeth_card *card)
card->qdio.in_q->bufs[i].buffer =
&card->qdio.in_q->qdio_bufs[i];
/* inbound buffer pool */
- if (qeth_alloc_buffer_pool(card)){
- kfree(card->qdio.in_q);
- return -ENOMEM;
- }
+ if (qeth_alloc_buffer_pool(card))
+ goto out_freeinq;
/* outbound */
card->qdio.out_qs =
kmalloc(card->qdio.no_out_queues *
sizeof(struct qeth_qdio_out_q *), GFP_KERNEL);
- if (!card->qdio.out_qs){
- qeth_free_buffer_pool(card);
- return -ENOMEM;
- }
- for (i = 0; i < card->qdio.no_out_queues; ++i){
+ if (!card->qdio.out_qs)
+ goto out_freepool;
+ for (i = 0; i < card->qdio.no_out_queues; ++i) {
card->qdio.out_qs[i] = kmalloc(sizeof(struct qeth_qdio_out_q),
GFP_KERNEL|GFP_DMA);
- if (!card->qdio.out_qs[i]){
- while (i > 0)
- kfree(card->qdio.out_qs[--i]);
- kfree(card->qdio.out_qs);
- return -ENOMEM;
- }
+ if (!card->qdio.out_qs[i])
+ goto out_freeoutq;
QETH_DBF_TEXT_(setup, 2, "outq %i", i);
QETH_DBF_HEX(setup, 2, &card->qdio.out_qs[i], sizeof(void *));
memset(card->qdio.out_qs[i], 0, sizeof(struct qeth_qdio_out_q));
@@ -3230,11 +3218,25 @@ qeth_alloc_qdio_buffers(struct qeth_card *card)
&card->qdio.out_qs[i]->qdio_bufs[j];
skb_queue_head_init(&card->qdio.out_qs[i]->bufs[j].
skb_list);
+ lockdep_set_class(
+ &card->qdio.out_qs[i]->bufs[j].skb_list.lock,
+ &qdio_out_skb_queue_key);
INIT_LIST_HEAD(&card->qdio.out_qs[i]->bufs[j].ctx_list);
}
}
- card->qdio.state = QETH_QDIO_ALLOCATED;
return 0;
+
+out_freeoutq:
+ while (i > 0)
+ kfree(card->qdio.out_qs[--i]);
+ kfree(card->qdio.out_qs);
+out_freepool:
+ qeth_free_buffer_pool(card);
+out_freeinq:
+ kfree(card->qdio.in_q);
+out_nomem:
+ atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED);
+ return -ENOMEM;
}
static void
@@ -3243,7 +3245,8 @@ qeth_free_qdio_buffers(struct qeth_card *card)
int i, j;
QETH_DBF_TEXT(trace, 2, "freeqdbf");
- if (card->qdio.state == QETH_QDIO_UNINITIALIZED)
+ if (atomic_swap(&card->qdio.state, QETH_QDIO_UNINITIALIZED) ==
+ QETH_QDIO_UNINITIALIZED)
return;
kfree(card->qdio.in_q);
/* inbound buffer pool */
@@ -3256,7 +3259,6 @@ qeth_free_qdio_buffers(struct qeth_card *card)
kfree(card->qdio.out_qs[i]);
}
kfree(card->qdio.out_qs);
- card->qdio.state = QETH_QDIO_UNINITIALIZED;
}
static void
@@ -3278,7 +3280,7 @@ static void
qeth_init_qdio_info(struct qeth_card *card)
{
QETH_DBF_TEXT(setup, 4, "intqdinf");
- card->qdio.state = QETH_QDIO_UNINITIALIZED;
+ atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED);
/* inbound */
card->qdio.in_buf_size = QETH_IN_BUF_SIZE_DEFAULT;
card->qdio.init_pool.buf_count = QETH_IN_BUF_COUNT_DEFAULT;
@@ -3341,7 +3343,7 @@ qeth_qdio_establish(struct qeth_card *card)
struct qdio_buffer **in_sbal_ptrs;
struct qdio_buffer **out_sbal_ptrs;
int i, j, k;
- int rc;
+ int rc = 0;
QETH_DBF_TEXT(setup, 2, "qdioest");
@@ -3400,8 +3402,10 @@ qeth_qdio_establish(struct qeth_card *card)
init_data.input_sbal_addr_array = (void **) in_sbal_ptrs;
init_data.output_sbal_addr_array = (void **) out_sbal_ptrs;
- if (!(rc = qdio_initialize(&init_data)))
- card->qdio.state = QETH_QDIO_ESTABLISHED;
+ if (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ALLOCATED,
+ QETH_QDIO_ESTABLISHED) == QETH_QDIO_ALLOCATED)
+ if ((rc = qdio_initialize(&init_data)))
+ atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
kfree(out_sbal_ptrs);
kfree(in_sbal_ptrs);
@@ -3517,13 +3521,20 @@ qeth_qdio_clear_card(struct qeth_card *card, int use_halt)
int rc = 0;
QETH_DBF_TEXT(trace,3,"qdioclr");
- if (card->qdio.state == QETH_QDIO_ESTABLISHED){
+ switch (atomic_cmpxchg(&card->qdio.state, QETH_QDIO_ESTABLISHED,
+ QETH_QDIO_CLEANING)) {
+ case QETH_QDIO_ESTABLISHED:
if ((rc = qdio_cleanup(CARD_DDEV(card),
- (card->info.type == QETH_CARD_TYPE_IQD) ?
- QDIO_FLAG_CLEANUP_USING_HALT :
- QDIO_FLAG_CLEANUP_USING_CLEAR)))
+ (card->info.type == QETH_CARD_TYPE_IQD) ?
+ QDIO_FLAG_CLEANUP_USING_HALT :
+ QDIO_FLAG_CLEANUP_USING_CLEAR)))
QETH_DBF_TEXT_(trace, 3, "1err%d", rc);
- card->qdio.state = QETH_QDIO_ALLOCATED;
+ atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED);
+ break;
+ case QETH_QDIO_CLEANING:
+ return rc;
+ default:
+ break;
}
if ((rc = qeth_clear_halt_card(card, use_halt)))
QETH_DBF_TEXT_(trace, 3, "2err%d", rc);
@@ -3683,10 +3694,10 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* return OK; otherwise ksoftirqd goes to 100% */
return NETDEV_TX_OK;
}
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.outbound_cnt++;
- card->perf_stats.outbound_start_time = qeth_get_micros();
-#endif
+ if (card->options.performance_stats) {
+ card->perf_stats.outbound_cnt++;
+ card->perf_stats.outbound_start_time = qeth_get_micros();
+ }
netif_stop_queue(dev);
if ((rc = qeth_send_packet(card, skb))) {
if (rc == -EBUSY) {
@@ -3700,10 +3711,9 @@ qeth_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
}
netif_wake_queue(dev);
-#ifdef CONFIG_QETH_PERF_STATS
- card->perf_stats.outbound_time += qeth_get_micros() -
- card->perf_stats.outbound_start_time;
-#endif
+ if (card->options.performance_stats)
+ card->perf_stats.outbound_time += qeth_get_micros() -
+ card->perf_stats.outbound_start_time;
return rc;
}
@@ -3918,49 +3928,59 @@ qeth_get_ip_version(struct sk_buff *skb)
}
}
-static inline int
-qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb,
- struct qeth_hdr **hdr, int ipv)
+static inline struct qeth_hdr *
+__qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
{
- int rc = 0;
#ifdef CONFIG_QETH_VLAN
u16 *tag;
-#endif
-
- QETH_DBF_TEXT(trace, 6, "prepskb");
- if (card->info.type == QETH_CARD_TYPE_OSN) {
- *hdr = (struct qeth_hdr *)(*skb)->data;
- return rc;
- }
- rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
- if (rc)
- return rc;
-#ifdef CONFIG_QETH_VLAN
- if (card->vlangrp && vlan_tx_tag_present(*skb) &&
+ if (card->vlangrp && vlan_tx_tag_present(skb) &&
((ipv == 6) || card->options.layer2) ) {
/*
* Move the mac addresses (6 bytes src, 6 bytes dest)
* to the beginning of the new header. We are using three
* memcpys instead of one memmove to save cycles.
*/
- skb_push(*skb, VLAN_HLEN);
- memcpy((*skb)->data, (*skb)->data + 4, 4);
- memcpy((*skb)->data + 4, (*skb)->data + 8, 4);
- memcpy((*skb)->data + 8, (*skb)->data + 12, 4);
- tag = (u16 *)((*skb)->data + 12);
+ skb_push(skb, VLAN_HLEN);
+ memcpy(skb->data, skb->data + 4, 4);
+ memcpy(skb->data + 4, skb->data + 8, 4);
+ memcpy(skb->data + 8, skb->data + 12, 4);
+ tag = (u16 *)(skb->data + 12);
/*
* first two bytes = ETH_P_8021Q (0x8100)
* second two bytes = VLANID
*/
*tag = __constant_htons(ETH_P_8021Q);
- *(tag + 1) = htons(vlan_tx_tag_get(*skb));
+ *(tag + 1) = htons(vlan_tx_tag_get(skb));
}
#endif
- *hdr = (struct qeth_hdr *)
- qeth_push_skb(card, skb, sizeof(struct qeth_hdr));
- if (*hdr == NULL)
- return -EINVAL;
- return 0;
+ return ((struct qeth_hdr *)
+ qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
+}
+
+static inline void
+__qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
+{
+ if (orig_skb != new_skb)
+ dev_kfree_skb_any(new_skb);
+}
+
+static inline struct sk_buff *
+qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
+ struct qeth_hdr **hdr, int ipv)
+{
+ struct sk_buff *new_skb;
+
+ QETH_DBF_TEXT(trace, 6, "prepskb");
+
+ new_skb = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr));
+ if (new_skb == NULL)
+ return NULL;
+ *hdr = __qeth_prepare_skb(card, new_skb, ipv);
+ if (*hdr == NULL) {
+ __qeth_free_new_skb(skb, new_skb);
+ return NULL;
+ }
+ return new_skb;
}
static inline u8
@@ -4202,9 +4222,8 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
flush_cnt = 1;
} else {
QETH_DBF_TEXT(trace, 6, "fillbfpa");
-#ifdef CONFIG_QETH_PERF_STATS
- queue->card->perf_stats.skbs_sent_pack++;
-#endif
+ if (queue->card->options.performance_stats)
+ queue->card->perf_stats.skbs_sent_pack++;
if (buf->next_element_to_fill >=
QETH_MAX_BUFFER_ELEMENTS(queue->card)) {
/*
@@ -4241,21 +4260,15 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* check if buffer is empty to make sure that we do not 'overtake'
* ourselves and try to fill a buffer that is already primed
*/
- if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
- card->stats.tx_dropped++;
- atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
- return -EBUSY;
- }
+ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY)
+ goto out;
if (ctx == NULL)
queue->next_buf_to_fill = (queue->next_buf_to_fill + 1) %
QDIO_MAX_BUFFERS_PER_Q;
else {
buffers_needed = qeth_eddp_check_buffers_for_context(queue,ctx);
- if (buffers_needed < 0) {
- card->stats.tx_dropped++;
- atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
- return -EBUSY;
- }
+ if (buffers_needed < 0)
+ goto out;
queue->next_buf_to_fill =
(queue->next_buf_to_fill + buffers_needed) %
QDIO_MAX_BUFFERS_PER_Q;
@@ -4270,6 +4283,9 @@ qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
qeth_flush_buffers(queue, 0, index, flush_cnt);
}
return 0;
+out:
+ atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
+ return -EBUSY;
}
static inline int
@@ -4295,8 +4311,7 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* check if buffer is empty to make sure that we do not 'overtake'
* ourselves and try to fill a buffer that is already primed
*/
- if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY){
- card->stats.tx_dropped++;
+ if (atomic_read(&buffer->state) != QETH_QDIO_BUF_EMPTY) {
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY;
}
@@ -4319,7 +4334,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* again */
if (atomic_read(&buffer->state) !=
QETH_QDIO_BUF_EMPTY){
- card->stats.tx_dropped++;
qeth_flush_buffers(queue, 0, start_index, flush_count);
atomic_set(&queue->state, QETH_OUT_Q_UNLOCKED);
return -EBUSY;
@@ -4330,7 +4344,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
* free buffers) to handle eddp context */
if (qeth_eddp_check_buffers_for_context(queue,ctx) < 0){
printk("eddp tx_dropped 1\n");
- card->stats.tx_dropped++;
rc = -EBUSY;
goto out;
}
@@ -4342,7 +4355,6 @@ qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
tmp = qeth_eddp_fill_buffer(queue,ctx,queue->next_buf_to_fill);
if (tmp < 0) {
printk("eddp tx_dropped 2\n");
- card->stats.tx_dropped++;
rc = - EBUSY;
goto out;
}
@@ -4376,10 +4388,8 @@ out:
qeth_flush_buffers(queue, 0, start_index, flush_count);
}
/* at this point the queue is UNLOCKED again */
-#ifdef CONFIG_QETH_PERF_STATS
- if (do_pack)
+ if (queue->card->options.performance_stats && do_pack)
queue->card->perf_stats.bufs_sent_pack += flush_count;
-#endif /* CONFIG_QETH_PERF_STATS */
return rc;
}
@@ -4390,21 +4400,21 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
{
int elements_needed = 0;
- if (skb_shinfo(skb)->nr_frags > 0) {
+ if (skb_shinfo(skb)->nr_frags > 0)
elements_needed = (skb_shinfo(skb)->nr_frags + 1);
- }
- if (elements_needed == 0 )
+ if (elements_needed == 0)
elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE)
+ skb->len) >> PAGE_SHIFT);
if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){
- PRINT_ERR("qeth_do_send_packet: invalid size of "
- "IP packet (Number=%d / Length=%d). Discarded.\n",
+ PRINT_ERR("Invalid size of IP packet "
+ "(Number=%d / Length=%d). Discarded.\n",
(elements_needed+elems), skb->len);
return 0;
}
return elements_needed;
}
+
static inline int
qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
{
@@ -4418,108 +4428,110 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
int tx_bytes = skb->len;
unsigned short nr_frags = skb_shinfo(skb)->nr_frags;
unsigned short tso_size = skb_shinfo(skb)->gso_size;
+ struct sk_buff *new_skb, *new_skb2;
int rc;
QETH_DBF_TEXT(trace, 6, "sendpkt");
+ new_skb = skb;
+ if ((card->info.type == QETH_CARD_TYPE_OSN) &&
+ (skb->protocol == htons(ETH_P_IPV6)))
+ return -EPERM;
+ cast_type = qeth_get_cast_type(card, skb);
+ if ((cast_type == RTN_BROADCAST) &&
+ (card->info.broadcast_capable == 0))
+ return -EPERM;
+ queue = card->qdio.out_qs
+ [qeth_get_priority_queue(card, skb, ipv, cast_type)];
if (!card->options.layer2) {
ipv = qeth_get_ip_version(skb);
if ((card->dev->hard_header == qeth_fake_header) && ipv) {
- if ((skb = qeth_pskb_unshare(skb,GFP_ATOMIC)) == NULL) {
- card->stats.tx_dropped++;
- dev_kfree_skb_irq(skb);
- return 0;
- }
+ new_skb = qeth_pskb_unshare(skb, GFP_ATOMIC);
+ if (!new_skb)
+ return -ENOMEM;
if(card->dev->type == ARPHRD_IEEE802_TR){
- skb_pull(skb, QETH_FAKE_LL_LEN_TR);
+ skb_pull(new_skb, QETH_FAKE_LL_LEN_TR);
} else {
- skb_pull(skb, QETH_FAKE_LL_LEN_ETH);
+ skb_pull(new_skb, QETH_FAKE_LL_LEN_ETH);
}
}
}
- if ((card->info.type == QETH_CARD_TYPE_OSN) &&
- (skb->protocol == htons(ETH_P_IPV6))) {
- dev_kfree_skb_any(skb);
- return 0;
- }
- cast_type = qeth_get_cast_type(card, skb);
- if ((cast_type == RTN_BROADCAST) &&
- (card->info.broadcast_capable == 0)){
- card->stats.tx_dropped++;
- card->stats.tx_errors++;
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
- }
- queue = card->qdio.out_qs
- [qeth_get_priority_queue(card, skb, ipv, cast_type)];
-
- if (skb_shinfo(skb)->gso_size)
+ if (skb_is_gso(skb))
large_send = card->options.large_send;
-
- /*are we able to do TSO ? If so ,prepare and send it from here */
+ /* check on OSN device*/
+ if (card->info.type == QETH_CARD_TYPE_OSN)
+ hdr = (struct qeth_hdr *)new_skb->data;
+ /*are we able to do TSO ? */
if ((large_send == QETH_LARGE_SEND_TSO) &&
(cast_type == RTN_UNSPEC)) {
- rc = qeth_tso_prepare_packet(card, skb, ipv, cast_type);
+ rc = qeth_tso_prepare_packet(card, new_skb, ipv, cast_type);
if (rc) {
- card->stats.tx_dropped++;
- card->stats.tx_errors++;
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
+ __qeth_free_new_skb(skb, new_skb);
+ return rc;
}
elements_needed++;
- } else {
- if ((rc = qeth_prepare_skb(card, &skb, &hdr, ipv))) {
- QETH_DBF_TEXT_(trace, 4, "pskbe%d", rc);
- return rc;
+ } else if (card->info.type != QETH_CARD_TYPE_OSN) {
+ new_skb2 = qeth_prepare_skb(card, new_skb, &hdr, ipv);
+ if (!new_skb2) {
+ __qeth_free_new_skb(skb, new_skb);
+ return -EINVAL;
}
- if (card->info.type != QETH_CARD_TYPE_OSN)
- qeth_fill_header(card, hdr, skb, ipv, cast_type);
+ if (new_skb != skb)
+ __qeth_free_new_skb(new_skb2, new_skb);
+ new_skb = new_skb2;
+ qeth_fill_header(card, hdr, new_skb, ipv, cast_type);
}
-
if (large_send == QETH_LARGE_SEND_EDDP) {
- ctx = qeth_eddp_create_context(card, skb, hdr);
+ ctx = qeth_eddp_create_context(card, new_skb, hdr);
if (ctx == NULL) {
+ __qeth_free_new_skb(skb, new_skb);
PRINT_WARN("could not create eddp context\n");
return -EINVAL;
}
} else {
- int elems = qeth_get_elements_no(card,(void*) hdr, skb,
+ int elems = qeth_get_elements_no(card,(void*) hdr, new_skb,
elements_needed);
- if (!elems)
+ if (!elems) {
+ __qeth_free_new_skb(skb, new_skb);
return -EINVAL;
+ }
elements_needed += elems;
}
if (card->info.type != QETH_CARD_TYPE_IQD)
- rc = qeth_do_send_packet(card, queue, skb, hdr,
+ rc = qeth_do_send_packet(card, queue, new_skb, hdr,
elements_needed, ctx);
else
- rc = qeth_do_send_packet_fast(card, queue, skb, hdr,
+ rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr,
elements_needed, ctx);
- if (!rc){
+ if (!rc) {
card->stats.tx_packets++;
card->stats.tx_bytes += tx_bytes;
-#ifdef CONFIG_QETH_PERF_STATS
- if (tso_size &&
- !(large_send == QETH_LARGE_SEND_NO)) {
- card->perf_stats.large_send_bytes += tx_bytes;
- card->perf_stats.large_send_cnt++;
- }
- if (nr_frags > 0){
- card->perf_stats.sg_skbs_sent++;
- /* nr_frags + skb->data */
- card->perf_stats.sg_frags_sent +=
- nr_frags + 1;
+ if (new_skb != skb)
+ dev_kfree_skb_any(skb);
+ if (card->options.performance_stats) {
+ if (tso_size &&
+ !(large_send == QETH_LARGE_SEND_NO)) {
+ card->perf_stats.large_send_bytes += tx_bytes;
+ card->perf_stats.large_send_cnt++;
+ }
+ if (nr_frags > 0) {
+ card->perf_stats.sg_skbs_sent++;
+ /* nr_frags + skb->data */
+ card->perf_stats.sg_frags_sent +=
+ nr_frags + 1;
+ }
}
-#endif /* CONFIG_QETH_PERF_STATS */
+ } else {
+ card->stats.tx_dropped++;
+ __qeth_free_new_skb(skb, new_skb);
}
if (ctx != NULL) {
/* drop creator's reference */
qeth_eddp_put_context(ctx);
/* free skb; it's not referenced by a buffer */
- if (rc == 0)
- dev_kfree_skb_any(skb);
-
+ if (!rc)
+ dev_kfree_skb_any(new_skb);
}
return rc;
}
@@ -4798,7 +4810,7 @@ static struct qeth_cmd_buffer *
qeth_get_setassparms_cmd(struct qeth_card *, enum qeth_ipa_funcs,
__u16, __u16, enum qeth_prot_versions);
static int
-qeth_arp_query(struct qeth_card *card, char *udata)
+qeth_arp_query(struct qeth_card *card, char __user *udata)
{
struct qeth_cmd_buffer *iob;
struct qeth_arp_query_info qinfo = {0, };
@@ -4931,7 +4943,7 @@ qeth_get_adapter_cmd(struct qeth_card *card, __u32 command, __u32 cmdlen)
* function to send SNMP commands to OSA-E card
*/
static int
-qeth_snmp_command(struct qeth_card *card, char *udata)
+qeth_snmp_command(struct qeth_card *card, char __user *udata)
{
struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd;
@@ -5273,6 +5285,7 @@ qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
struct sk_buff_head tmp_list;
skb_queue_head_init(&tmp_list);
+ lockdep_set_class(&tmp_list.lock, &qdio_out_skb_queue_key);
for(i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i){
while ((skb = skb_dequeue(&buf->skb_list))){
if (vlan_tx_tag_present(skb) &&
@@ -7331,6 +7344,8 @@ qeth_setrouting_v6(struct qeth_card *card)
QETH_DBF_TEXT(trace,3,"setrtg6");
#ifdef CONFIG_QETH_IPV6
+ if (!qeth_is_supported(card, IPA_IPV6))
+ return 0;
qeth_correct_routing_type(card, &card->options.route6.type,
QETH_PROT_IPV6);
@@ -7869,12 +7884,12 @@ __qeth_set_online(struct ccwgroup_device *gdev, int recovery_mode)
QETH_DBF_TEXT_(setup, 2, "5err%d", rc);
goto out_remove;
}
- card->state = CARD_STATE_SOFTSETUP;
if ((rc = qeth_init_qdio_queues(card))){
QETH_DBF_TEXT_(setup, 2, "6err%d", rc);
goto out_remove;
}
+ card->state = CARD_STATE_SOFTSETUP;
netif_carrier_on(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
@@ -7902,9 +7917,9 @@ qeth_set_online(struct ccwgroup_device *gdev)
}
static struct ccw_device_id qeth_ids[] = {
- {CCW_DEVICE(0x1731, 0x01), driver_info:QETH_CARD_TYPE_OSAE},
- {CCW_DEVICE(0x1731, 0x05), driver_info:QETH_CARD_TYPE_IQD},
- {CCW_DEVICE(0x1731, 0x06), driver_info:QETH_CARD_TYPE_OSN},
+ {CCW_DEVICE(0x1731, 0x01), .driver_info = QETH_CARD_TYPE_OSAE},
+ {CCW_DEVICE(0x1731, 0x05), .driver_info = QETH_CARD_TYPE_IQD},
+ {CCW_DEVICE(0x1731, 0x06), .driver_info = QETH_CARD_TYPE_OSN},
{},
};
MODULE_DEVICE_TABLE(ccw, qeth_ids);
@@ -8052,7 +8067,7 @@ qeth_arp_constructor(struct neighbour *neigh)
neigh->parms = neigh_parms_clone(parms);
rcu_read_unlock();
- neigh->type = inet_addr_type(*(u32 *) neigh->primary_key);
+ neigh->type = inet_addr_type(*(__be32 *) neigh->primary_key);
neigh->nud_state = NUD_NOARP;
neigh->ops = arp_direct_ops;
neigh->output = neigh->ops->queue_xmit;
@@ -8373,7 +8388,7 @@ out:
static struct notifier_block qeth_ip_notifier = {
qeth_ip_event,
- 0
+ NULL,
};
#ifdef CONFIG_QETH_IPV6
@@ -8426,7 +8441,7 @@ out:
static struct notifier_block qeth_ip6_notifier = {
qeth_ip6_event,
- 0
+ NULL,
};
#endif
@@ -8444,16 +8459,17 @@ __qeth_reboot_event_card(struct device *dev, void *data)
static int
qeth_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
{
+ int ret;
- driver_for_each_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
- __qeth_reboot_event_card);
- return NOTIFY_DONE;
+ ret = driver_for_each_device(&qeth_ccwgroup_driver.driver, NULL, NULL,
+ __qeth_reboot_event_card);
+ return ret ? NOTIFY_BAD : NOTIFY_DONE;
}
static struct notifier_block qeth_reboot_notifier = {
qeth_reboot_event,
- 0
+ NULL,
};
static int
@@ -8502,9 +8518,9 @@ static int
qeth_ipv6_init(void)
{
qeth_old_arp_constructor = arp_tbl.constructor;
- write_lock(&arp_tbl.lock);
+ write_lock_bh(&arp_tbl.lock);
arp_tbl.constructor = qeth_arp_constructor;
- write_unlock(&arp_tbl.lock);
+ write_unlock_bh(&arp_tbl.lock);
arp_direct_ops = (struct neigh_ops*)
kmalloc(sizeof(struct neigh_ops), GFP_KERNEL);
@@ -8520,9 +8536,9 @@ qeth_ipv6_init(void)
static void
qeth_ipv6_uninit(void)
{
- write_lock(&arp_tbl.lock);
+ write_lock_bh(&arp_tbl.lock);
arp_tbl.constructor = qeth_old_arp_constructor;
- write_unlock(&arp_tbl.lock);
+ write_unlock_bh(&arp_tbl.lock);
kfree(arp_direct_ops);
}
#endif /* CONFIG_QETH_IPV6 */
@@ -8530,34 +8546,44 @@ qeth_ipv6_uninit(void)
static void
qeth_sysfs_unregister(void)
{
+ s390_root_dev_unregister(qeth_root_dev);
qeth_remove_driver_attributes();
ccw_driver_unregister(&qeth_ccw_driver);
ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
- s390_root_dev_unregister(qeth_root_dev);
}
+
/**
* register qeth at sysfs
*/
static int
qeth_sysfs_register(void)
{
- int rc=0;
+ int rc;
rc = ccwgroup_driver_register(&qeth_ccwgroup_driver);
if (rc)
- return rc;
+ goto out;
+
rc = ccw_driver_register(&qeth_ccw_driver);
if (rc)
- return rc;
+ goto out_ccw_driver;
+
rc = qeth_create_driver_attributes();
if (rc)
- return rc;
+ goto out_qeth_attr;
+
qeth_root_dev = s390_root_dev_register("qeth");
- if (IS_ERR(qeth_root_dev)) {
- rc = PTR_ERR(qeth_root_dev);
- return rc;
- }
- return 0;
+ rc = IS_ERR(qeth_root_dev) ? PTR_ERR(qeth_root_dev) : 0;
+ if (!rc)
+ goto out;
+
+ qeth_remove_driver_attributes();
+out_qeth_attr:
+ ccw_driver_unregister(&qeth_ccw_driver);
+out_ccw_driver:
+ ccwgroup_driver_unregister(&qeth_ccwgroup_driver);
+out:
+ return rc;
}
/***
@@ -8566,7 +8592,7 @@ qeth_sysfs_register(void)
static int __init
qeth_init(void)
{
- int rc=0;
+ int rc;
PRINT_INFO("loading %s\n", version);
@@ -8575,20 +8601,26 @@ qeth_init(void)
spin_lock_init(&qeth_notify_lock);
rwlock_init(&qeth_card_list.rwlock);
- if (qeth_register_dbf_views())
+ rc = qeth_register_dbf_views();
+ if (rc)
goto out_err;
- if (qeth_sysfs_register())
- goto out_sysfs;
+
+ rc = qeth_sysfs_register();
+ if (rc)
+ goto out_dbf;
#ifdef CONFIG_QETH_IPV6
- if (qeth_ipv6_init()) {
- PRINT_ERR("Out of memory during ipv6 init.\n");
+ rc = qeth_ipv6_init();
+ if (rc) {
+ PRINT_ERR("Out of memory during ipv6 init code = %d\n", rc);
goto out_sysfs;
}
#endif /* QETH_IPV6 */
- if (qeth_register_notifiers())
+ rc = qeth_register_notifiers();
+ if (rc)
goto out_ipv6;
- if (qeth_create_procfs_entries())
+ rc = qeth_create_procfs_entries();
+ if (rc)
goto out_notifiers;
return rc;
@@ -8598,12 +8630,13 @@ out_notifiers:
out_ipv6:
#ifdef CONFIG_QETH_IPV6
qeth_ipv6_uninit();
-#endif /* QETH_IPV6 */
out_sysfs:
+#endif /* QETH_IPV6 */
qeth_sysfs_unregister();
+out_dbf:
qeth_unregister_dbf_views();
out_err:
- PRINT_ERR("Initialization failed");
+ PRINT_ERR("Initialization failed with code %d\n", rc);
return rc;
}
diff --git a/drivers/s390/net/qeth_proc.c b/drivers/s390/net/qeth_proc.c
index 66f2da14e6e..faa768e5925 100644
--- a/drivers/s390/net/qeth_proc.c
+++ b/drivers/s390/net/qeth_proc.c
@@ -173,7 +173,6 @@ static struct file_operations qeth_procfile_fops = {
#define QETH_PERF_PROCFILE_NAME "qeth_perf"
static struct proc_dir_entry *qeth_perf_procfile;
-#ifdef CONFIG_QETH_PERF_STATS
static int
qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
{
@@ -192,14 +191,21 @@ qeth_perf_procfile_seq_show(struct seq_file *s, void *it)
CARD_DDEV_ID(card),
QETH_CARD_IFNAME(card)
);
+ if (!card->options.performance_stats)
+ seq_printf(s, "Performance statistics are deactivated.\n");
seq_printf(s, " Skb's/buffers received : %lu/%u\n"
" Skb's/buffers sent : %lu/%u\n\n",
- card->stats.rx_packets, card->perf_stats.bufs_rec,
- card->stats.tx_packets, card->perf_stats.bufs_sent
+ card->stats.rx_packets -
+ card->perf_stats.initial_rx_packets,
+ card->perf_stats.bufs_rec,
+ card->stats.tx_packets -
+ card->perf_stats.initial_tx_packets,
+ card->perf_stats.bufs_sent
);
seq_printf(s, " Skb's/buffers sent without packing : %lu/%u\n"
" Skb's/buffers sent with packing : %u/%u\n\n",
- card->stats.tx_packets - card->perf_stats.skbs_sent_pack,
+ card->stats.tx_packets - card->perf_stats.initial_tx_packets
+ - card->perf_stats.skbs_sent_pack,
card->perf_stats.bufs_sent - card->perf_stats.bufs_sent_pack,
card->perf_stats.skbs_sent_pack,
card->perf_stats.bufs_sent_pack
@@ -275,11 +281,6 @@ static struct file_operations qeth_perf_procfile_fops = {
.release = seq_release,
};
-#define qeth_perf_procfile_created qeth_perf_procfile
-#else
-#define qeth_perf_procfile_created 1
-#endif /* CONFIG_QETH_PERF_STATS */
-
int __init
qeth_create_procfs_entries(void)
{
@@ -288,15 +289,13 @@ qeth_create_procfs_entries(void)
if (qeth_procfile)
qeth_procfile->proc_fops = &qeth_procfile_fops;
-#ifdef CONFIG_QETH_PERF_STATS
qeth_perf_procfile = create_proc_entry(QETH_PERF_PROCFILE_NAME,
S_IFREG | 0444, NULL);
if (qeth_perf_procfile)
qeth_perf_procfile->proc_fops = &qeth_perf_procfile_fops;
-#endif /* CONFIG_QETH_PERF_STATS */
if (qeth_procfile &&
- qeth_perf_procfile_created)
+ qeth_perf_procfile)
return 0;
else
return -ENOMEM;
diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c
index 185a9cfbcbd..5836737ac58 100644
--- a/drivers/s390/net/qeth_sys.c
+++ b/drivers/s390/net/qeth_sys.c
@@ -743,6 +743,47 @@ static DEVICE_ATTR(layer2, 0644, qeth_dev_layer2_show,
qeth_dev_layer2_store);
static ssize_t
+qeth_dev_performance_stats_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct qeth_card *card = dev->driver_data;
+
+ if (!card)
+ return -EINVAL;
+
+ return sprintf(buf, "%i\n", card->options.performance_stats ? 1:0);
+}
+
+static ssize_t
+qeth_dev_performance_stats_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct qeth_card *card = dev->driver_data;
+ char *tmp;
+ int i;
+
+ if (!card)
+ return -EINVAL;
+
+ i = simple_strtoul(buf, &tmp, 16);
+ if ((i == 0) || (i == 1)) {
+ if (i == card->options.performance_stats)
+ return count;
+ card->options.performance_stats = i;
+ if (i == 0)
+ memset(&card->perf_stats, 0,
+ sizeof(struct qeth_perf_stats));
+ card->perf_stats.initial_rx_packets = card->stats.rx_packets;
+ card->perf_stats.initial_tx_packets = card->stats.tx_packets;
+ } else {
+ PRINT_WARN("performance_stats: write 0 or 1 to this file!\n");
+ return -EINVAL;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(performance_stats, 0644, qeth_dev_performance_stats_show,
+ qeth_dev_performance_stats_store);
+
+static ssize_t
qeth_dev_large_send_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct qeth_card *card = dev->driver_data;
@@ -928,6 +969,7 @@ static struct device_attribute * qeth_device_attrs[] = {
&dev_attr_canonical_macaddr,
&dev_attr_layer2,
&dev_attr_large_send,
+ &dev_attr_performance_stats,
NULL,
};
@@ -1110,12 +1152,12 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
{
const char *start, *end;
char *tmp;
- char buffer[49] = {0, };
+ char buffer[40] = {0, };
start = buf;
/* get address string */
end = strchr(start, '/');
- if (!end || (end-start >= 49)){
+ if (!end || (end - start >= 40)){
PRINT_WARN("Invalid format for ipato_addx/delx. "
"Use <ip addr>/<mask bits>\n");
return -EINVAL;
@@ -1127,7 +1169,12 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
}
start = end + 1;
*mask_bits = simple_strtoul(start, &tmp, 10);
-
+ if (!strlen(start) ||
+ (tmp == start) ||
+ (*mask_bits > ((proto == QETH_PROT_IPV4) ? 32 : 128))) {
+ PRINT_WARN("Invalid mask bits for ipato_addx/delx !\n");
+ return -EINVAL;
+ }
return 0;
}
@@ -1698,11 +1745,16 @@ qeth_create_device_attributes(struct device *dev)
sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
+ return ret;
}
- if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group)))
+ if ((ret = sysfs_create_group(&dev->kobj, &qeth_device_blkt_group))){
+ sysfs_remove_group(&dev->kobj, &qeth_device_attr_group);
+ sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group);
+ sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group);
+ sysfs_remove_group(&dev->kobj, &qeth_device_rxip_group);
return ret;
-
- return ret;
+ }
+ return 0;
}
void
@@ -1755,7 +1807,7 @@ qeth_driver_group_store(struct device_driver *ddrv, const char *buf,
}
-static DRIVER_ATTR(group, 0200, 0, qeth_driver_group_store);
+static DRIVER_ATTR(group, 0200, NULL, qeth_driver_group_store);
static ssize_t
qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf,
@@ -1783,7 +1835,7 @@ qeth_driver_notifier_register_store(struct device_driver *ddrv, const char *buf,
return count;
}
-static DRIVER_ATTR(notifier_register, 0200, 0,
+static DRIVER_ATTR(notifier_register, 0200, NULL,
qeth_driver_notifier_register_store);
int
diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
index 593f298142c..14504afb044 100644
--- a/drivers/s390/net/qeth_tso.h
+++ b/drivers/s390/net/qeth_tso.h
@@ -24,7 +24,7 @@ static inline struct qeth_hdr_tso *
qeth_tso_prepare_skb(struct qeth_card *card, struct sk_buff **skb)
{
QETH_DBF_TEXT(trace, 5, "tsoprsk");
- return qeth_push_skb(card, skb, sizeof(struct qeth_hdr_tso));
+ return qeth_push_skb(card, *skb, sizeof(struct qeth_hdr_tso));
}
/**
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 72118ee6895..b8179c27ceb 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -66,7 +66,7 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data)
return;
}
rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls,
- msg, len, 0, 0, 0);
+ msg, len, NULL, NULL, NULL);
if (rc == 0) {
msg[len] = 0;
EBCASC(msg, len);
@@ -122,7 +122,7 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str))
struct smsg_callback *cb, *tmp;
spin_lock(&smsg_list_lock);
- cb = 0;
+ cb = NULL;
list_for_each_entry(tmp, &smsg_list, list)
if (tmp->callback == callback &&
strcmp(tmp->prefix, prefix) == 0) {
@@ -139,7 +139,7 @@ smsg_exit(void)
{
if (smsg_handle > 0) {
cpcmd("SET SMSG OFF", NULL, 0, NULL);
- iucv_sever(smsg_pathid, 0);
+ iucv_sever(smsg_pathid, NULL);
iucv_unregister_program(smsg_handle);
driver_unregister(&smsg_driver);
}
@@ -162,19 +162,19 @@ smsg_init(void)
return rc;
}
smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ",
- pgmmask, &smsg_ops, 0);
+ pgmmask, &smsg_ops, NULL);
if (!smsg_handle) {
printk(KERN_ERR "SMSGIUCV: failed to register to iucv");
driver_unregister(&smsg_driver);
return -EIO; /* better errno ? */
}
- rc = iucv_connect (&smsg_pathid, 255, 0, "*MSG ", 0, 0, 0, 0,
- smsg_handle, 0);
+ rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0,
+ NULL, NULL, smsg_handle, NULL);
if (rc) {
printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG");
iucv_unregister_program(smsg_handle);
driver_unregister(&smsg_driver);
- smsg_handle = 0;
+ smsg_handle = NULL;
return -EIO;
}
cpcmd("SET SMSG IUCV", NULL, 0, NULL);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index f99e55308b3..479364d0332 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -8,20 +8,17 @@
* Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/workqueue.h>
#include <linux/time.h>
+#include <linux/kthread.h>
#include <asm/lowcore.h>
#include "s390mach.h"
-#define DBG printk
-// #define DBG(args,...) do {} while (0);
-
static struct semaphore m_sem;
extern int css_process_crw(int, int);
@@ -56,8 +53,6 @@ s390_collect_crw_info(void *param)
unsigned int chain;
sem = (struct semaphore *)param;
- /* Set a nice name. */
- daemonize("kmcheck");
repeat:
down_interruptible(sem);
slow = 0;
@@ -85,11 +80,11 @@ repeat:
ccode = stcrw(&crw[chain]);
if (ccode != 0)
break;
- DBG(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
- "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
- crw[chain].slct, crw[chain].oflw, crw[chain].chn,
- crw[chain].rsc, crw[chain].anc, crw[chain].erc,
- crw[chain].rsid);
+ printk(KERN_DEBUG "crw_info : CRW reports slct=%d, oflw=%d, "
+ "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n",
+ crw[chain].slct, crw[chain].oflw, crw[chain].chn,
+ crw[chain].rsc, crw[chain].anc, crw[chain].erc,
+ crw[chain].rsid);
/* Check for overflows. */
if (crw[chain].oflw) {
pr_debug("%s: crw overflow detected!\n", __FUNCTION__);
@@ -113,6 +108,16 @@ repeat:
break;
case CRW_RSC_CPATH:
pr_debug("source is channel path %02X\n", crw[0].rsid);
+ /*
+ * Check for solicited machine checks. These are
+ * created by reset channel path and need not be
+ * reported to the common I/O layer.
+ */
+ if (crw[chain].slct) {
+ pr_debug("solicited machine check for "
+ "channel path %02X\n", crw[0].rsid);
+ break;
+ }
switch (crw[0].erc) {
case CRW_ERC_IPARM: /* Path has come. */
ret = chp_process_crw(crw[0].rsid, 1);
@@ -248,11 +253,12 @@ s390_revalidate_registers(struct mci *mci)
kill_task = 1;
#ifndef CONFIG_64BIT
- asm volatile("ld 0,0(%0)\n"
- "ld 2,8(%0)\n"
- "ld 4,16(%0)\n"
- "ld 6,24(%0)"
- : : "a" (&S390_lowcore.floating_pt_save_area));
+ asm volatile(
+ " ld 0,0(%0)\n"
+ " ld 2,8(%0)\n"
+ " ld 4,16(%0)\n"
+ " ld 6,24(%0)"
+ : : "a" (&S390_lowcore.floating_pt_save_area));
#endif
if (MACHINE_HAS_IEEE) {
@@ -269,37 +275,36 @@ s390_revalidate_registers(struct mci *mci)
* Floating point control register can't be restored.
* Task will be terminated.
*/
- asm volatile ("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
+ asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
kill_task = 1;
- }
- else
- asm volatile (
- "lfpc 0(%0)"
- : : "a" (fpt_creg_save_area));
-
- asm volatile("ld 0,0(%0)\n"
- "ld 1,8(%0)\n"
- "ld 2,16(%0)\n"
- "ld 3,24(%0)\n"
- "ld 4,32(%0)\n"
- "ld 5,40(%0)\n"
- "ld 6,48(%0)\n"
- "ld 7,56(%0)\n"
- "ld 8,64(%0)\n"
- "ld 9,72(%0)\n"
- "ld 10,80(%0)\n"
- "ld 11,88(%0)\n"
- "ld 12,96(%0)\n"
- "ld 13,104(%0)\n"
- "ld 14,112(%0)\n"
- "ld 15,120(%0)\n"
- : : "a" (fpt_save_area));
+ } else
+ asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
+
+ asm volatile(
+ " ld 0,0(%0)\n"
+ " ld 1,8(%0)\n"
+ " ld 2,16(%0)\n"
+ " ld 3,24(%0)\n"
+ " ld 4,32(%0)\n"
+ " ld 5,40(%0)\n"
+ " ld 6,48(%0)\n"
+ " ld 7,56(%0)\n"
+ " ld 8,64(%0)\n"
+ " ld 9,72(%0)\n"
+ " ld 10,80(%0)\n"
+ " ld 11,88(%0)\n"
+ " ld 12,96(%0)\n"
+ " ld 13,104(%0)\n"
+ " ld 14,112(%0)\n"
+ " ld 15,120(%0)\n"
+ : : "a" (fpt_save_area));
}
/* Revalidate access registers */
- asm volatile("lam 0,15,0(%0)"
- : : "a" (&S390_lowcore.access_regs_save_area));
+ asm volatile(
+ " lam 0,15,0(%0)"
+ : : "a" (&S390_lowcore.access_regs_save_area));
if (!mci->ar)
/*
* Access registers have unknown contents.
@@ -316,11 +321,13 @@ s390_revalidate_registers(struct mci *mci)
s390_handle_damage("invalid control registers.");
else
#ifdef CONFIG_64BIT
- asm volatile("lctlg 0,15,0(%0)"
- : : "a" (&S390_lowcore.cregs_save_area));
+ asm volatile(
+ " lctlg 0,15,0(%0)"
+ : : "a" (&S390_lowcore.cregs_save_area));
#else
- asm volatile("lctl 0,15,0(%0)"
- : : "a" (&S390_lowcore.cregs_save_area));
+ asm volatile(
+ " lctl 0,15,0(%0)"
+ : : "a" (&S390_lowcore.cregs_save_area));
#endif
/*
@@ -334,20 +341,23 @@ s390_revalidate_registers(struct mci *mci)
* old contents (should be zero) otherwise set it to zero.
*/
if (!mci->pr)
- asm volatile("sr 0,0\n"
- "sckpf"
- : : : "0", "cc");
+ asm volatile(
+ " sr 0,0\n"
+ " sckpf"
+ : : : "0", "cc");
else
asm volatile(
- "l 0,0(%0)\n"
- "sckpf"
- : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc");
+ " l 0,0(%0)\n"
+ " sckpf"
+ : : "a" (&S390_lowcore.tod_progreg_save_area)
+ : "0", "cc");
#endif
/* Revalidate clock comparator register */
- asm volatile ("stck 0(%1)\n"
- "sckc 0(%1)"
- : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
+ asm volatile(
+ " stck 0(%1)\n"
+ " sckc 0(%1)"
+ : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
/* Check if old PSW is valid */
if (!mci->wp)
@@ -380,6 +390,8 @@ s390_do_machine_check(struct pt_regs *regs)
struct mcck_struct *mcck;
int umode;
+ lockdep_off();
+
mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
mcck = &__get_cpu_var(cpu_mcck);
umode = user_mode(regs);
@@ -484,6 +496,7 @@ s390_do_machine_check(struct pt_regs *regs)
mcck->warning = 1;
set_thread_flag(TIF_MCCK_PENDING);
}
+ lockdep_on();
}
/*
@@ -516,7 +529,7 @@ arch_initcall(machine_check_init);
static int __init
machine_check_crw_init (void)
{
- kernel_thread(s390_collect_crw_info, &m_sem, CLONE_FS|CLONE_FILES);
+ kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
ctl_set_bit(14, 28); /* enable channel report MCH */
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 9cd789b8acd..5d39b2df0cc 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -112,6 +112,109 @@ _zfcp_hex_dump(char *addr, int count)
printk("\n");
}
+
+/****************************************************************/
+/****** Functions to handle the request ID hash table ********/
+/****************************************************************/
+
+#define ZFCP_LOG_AREA ZFCP_LOG_AREA_FSF
+
+static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
+{
+ int i;
+
+ adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
+ GFP_KERNEL);
+
+ if (!adapter->req_list)
+ return -ENOMEM;
+
+ for (i=0; i<REQUEST_LIST_SIZE; i++)
+ INIT_LIST_HEAD(&adapter->req_list[i]);
+
+ return 0;
+}
+
+static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
+{
+ struct zfcp_fsf_req *request, *tmp;
+ unsigned int i;
+
+ for (i=0; i<REQUEST_LIST_SIZE; i++) {
+ if (list_empty(&adapter->req_list[i]))
+ continue;
+
+ list_for_each_entry_safe(request, tmp,
+ &adapter->req_list[i], list)
+ list_del(&request->list);
+ }
+
+ kfree(adapter->req_list);
+}
+
+void zfcp_reqlist_add(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *fsf_req)
+{
+ unsigned int i;
+
+ i = fsf_req->req_id % REQUEST_LIST_SIZE;
+ list_add_tail(&fsf_req->list, &adapter->req_list[i]);
+}
+
+void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
+{
+ struct zfcp_fsf_req *request, *tmp;
+ unsigned int i, counter;
+ u64 dbg_tmp[2];
+
+ i = req_id % REQUEST_LIST_SIZE;
+ BUG_ON(list_empty(&adapter->req_list[i]));
+
+ counter = 0;
+ list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
+ if (request->req_id == req_id) {
+ dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
+ dbg_tmp[1] = (u64) counter;
+ debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
+ list_del(&request->list);
+ break;
+ }
+ counter++;
+ }
+}
+
+struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
+ unsigned long req_id)
+{
+ struct zfcp_fsf_req *request, *tmp;
+ unsigned int i;
+
+ /* 0 is reserved as an invalid req_id */
+ if (req_id == 0)
+ return NULL;
+
+ i = req_id % REQUEST_LIST_SIZE;
+
+ list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
+ if (request->req_id == req_id)
+ return request;
+
+ return NULL;
+}
+
+int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
+{
+ unsigned int i;
+
+ for (i=0; i<REQUEST_LIST_SIZE; i++)
+ if (!list_empty(&adapter->req_list[i]))
+ return 0;
+
+ return 1;
+}
+
+#undef ZFCP_LOG_AREA
+
/****************************************************************/
/************** Uncategorised Functions *************************/
/****************************************************************/
@@ -200,11 +303,45 @@ zfcp_init_device_configure(void)
return;
}
+static int calc_alignment(int size)
+{
+ int align = 1;
+
+ if (!size)
+ return 0;
+
+ while ((size - align) > 0)
+ align <<= 1;
+
+ return align;
+}
+
static int __init
zfcp_module_init(void)
{
+ int retval = -ENOMEM;
+ int size, align;
+
+ size = sizeof(struct zfcp_fsf_req_qtcb);
+ align = calc_alignment(size);
+ zfcp_data.fsf_req_qtcb_cache =
+ kmem_cache_create("zfcp_fsf", size, align, 0, NULL, NULL);
+ if (!zfcp_data.fsf_req_qtcb_cache)
+ goto out;
- int retval = 0;
+ size = sizeof(struct fsf_status_read_buffer);
+ align = calc_alignment(size);
+ zfcp_data.sr_buffer_cache =
+ kmem_cache_create("zfcp_sr", size, align, 0, NULL, NULL);
+ if (!zfcp_data.sr_buffer_cache)
+ goto out_sr_cache;
+
+ size = sizeof(struct zfcp_gid_pn_data);
+ align = calc_alignment(size);
+ zfcp_data.gid_pn_cache =
+ kmem_cache_create("zfcp_gid", size, align, 0, NULL, NULL);
+ if (!zfcp_data.gid_pn_cache)
+ goto out_gid_cache;
atomic_set(&zfcp_data.loglevel, loglevel);
@@ -214,15 +351,16 @@ zfcp_module_init(void)
/* initialize adapters to be removed list head */
INIT_LIST_HEAD(&zfcp_data.adapter_remove_lh);
- zfcp_transport_template = fc_attach_transport(&zfcp_transport_functions);
- if (!zfcp_transport_template)
- return -ENODEV;
+ zfcp_data.scsi_transport_template =
+ fc_attach_transport(&zfcp_transport_functions);
+ if (!zfcp_data.scsi_transport_template)
+ goto out_transport;
retval = misc_register(&zfcp_cfdc_misc);
if (retval != 0) {
ZFCP_LOG_INFO("registration of misc device "
"zfcp_cfdc failed\n");
- goto out;
+ goto out_misc;
}
ZFCP_LOG_TRACE("major/minor for zfcp_cfdc: %d/%d\n",
@@ -234,9 +372,6 @@ zfcp_module_init(void)
/* initialise configuration rw lock */
rwlock_init(&zfcp_data.config_lock);
- /* save address of data structure managing the driver module */
- zfcp_data.scsi_host_template.module = THIS_MODULE;
-
/* setup dynamic I/O */
retval = zfcp_ccw_register();
if (retval) {
@@ -251,6 +386,14 @@ zfcp_module_init(void)
out_ccw_register:
misc_deregister(&zfcp_cfdc_misc);
+ out_misc:
+ fc_release_transport(zfcp_data.scsi_transport_template);
+ out_transport:
+ kmem_cache_destroy(zfcp_data.gid_pn_cache);
+ out_gid_cache:
+ kmem_cache_destroy(zfcp_data.sr_buffer_cache);
+ out_sr_cache:
+ kmem_cache_destroy(zfcp_data.fsf_req_qtcb_cache);
out:
return retval;
}
@@ -836,20 +979,20 @@ static int
zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
{
adapter->pool.fsf_req_erp =
- mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ERP_NR,
- sizeof(struct zfcp_fsf_req_pool_element));
+ mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ERP_NR,
+ zfcp_data.fsf_req_qtcb_cache);
if (!adapter->pool.fsf_req_erp)
return -ENOMEM;
adapter->pool.fsf_req_scsi =
- mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_SCSI_NR,
- sizeof(struct zfcp_fsf_req_pool_element));
+ mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_SCSI_NR,
+ zfcp_data.fsf_req_qtcb_cache);
if (!adapter->pool.fsf_req_scsi)
return -ENOMEM;
adapter->pool.fsf_req_abort =
- mempool_create_kmalloc_pool(ZFCP_POOL_FSF_REQ_ABORT_NR,
- sizeof(struct zfcp_fsf_req_pool_element));
+ mempool_create_slab_pool(ZFCP_POOL_FSF_REQ_ABORT_NR,
+ zfcp_data.fsf_req_qtcb_cache);
if (!adapter->pool.fsf_req_abort)
return -ENOMEM;
@@ -860,14 +1003,14 @@ zfcp_allocate_low_mem_buffers(struct zfcp_adapter *adapter)
return -ENOMEM;
adapter->pool.data_status_read =
- mempool_create_kmalloc_pool(ZFCP_POOL_STATUS_READ_NR,
- sizeof(struct fsf_status_read_buffer));
+ mempool_create_slab_pool(ZFCP_POOL_STATUS_READ_NR,
+ zfcp_data.sr_buffer_cache);
if (!adapter->pool.data_status_read)
return -ENOMEM;
adapter->pool.data_gid_pn =
- mempool_create_kmalloc_pool(ZFCP_POOL_DATA_GID_PN_NR,
- sizeof(struct zfcp_gid_pn_data));
+ mempool_create_slab_pool(ZFCP_POOL_DATA_GID_PN_NR,
+ zfcp_data.gid_pn_cache);
if (!adapter->pool.data_gid_pn)
return -ENOMEM;
@@ -961,8 +1104,12 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
INIT_LIST_HEAD(&adapter->port_remove_lh);
/* initialize list of fsf requests */
- spin_lock_init(&adapter->fsf_req_list_lock);
- INIT_LIST_HEAD(&adapter->fsf_req_list_head);
+ spin_lock_init(&adapter->req_list_lock);
+ retval = zfcp_reqlist_init(adapter);
+ if (retval) {
+ ZFCP_LOG_INFO("request list initialization failed\n");
+ goto failed_low_mem_buffers;
+ }
/* initialize debug locks */
@@ -988,9 +1135,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
/* initialize lock of associated request queue */
rwlock_init(&adapter->request_queue.queue_lock);
- /* intitialise SCSI ER timer */
- init_timer(&adapter->scsi_er_timer);
-
/* mark adapter unusable as long as sysfs registration is not complete */
atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status);
@@ -1041,8 +1185,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
* !0 - struct zfcp_adapter data structure could not be removed
* (e.g. still used)
* locks: adapter list write lock is assumed to be held by caller
- * adapter->fsf_req_list_lock is taken and released within this
- * function and must not be held on entry
*/
void
zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
@@ -1054,14 +1196,14 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
dev_set_drvdata(&adapter->ccw_device->dev, NULL);
/* sanity check: no pending FSF requests */
- spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
- retval = !list_empty(&adapter->fsf_req_list_head);
- spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
- if (retval) {
+ spin_lock_irqsave(&adapter->req_list_lock, flags);
+ retval = zfcp_reqlist_isempty(adapter);
+ spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+ if (!retval) {
ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, "
"%i requests outstanding\n",
zfcp_get_busid_by_adapter(adapter), adapter,
- atomic_read(&adapter->fsf_reqs_active));
+ atomic_read(&adapter->reqs_active));
retval = -EBUSY;
goto out;
}
@@ -1087,6 +1229,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
zfcp_free_low_mem_buffers(adapter);
/* free memory of adapter data structure and queues */
zfcp_qdio_free_queues(adapter);
+ zfcp_reqlist_free(adapter);
kfree(adapter->fc_stats);
kfree(adapter->stats_reset_data);
ZFCP_LOG_TRACE("freeing adapter structure\n");
@@ -1507,7 +1650,6 @@ zfcp_ns_gid_pn_request(struct zfcp_erp_action *erp_action)
gid_pn->ct.handler = zfcp_ns_gid_pn_handler;
gid_pn->ct.handler_data = (unsigned long) gid_pn;
gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT;
- gid_pn->ct.timer = &erp_action->timer;
gid_pn->port = erp_action->port;
ret = zfcp_fsf_send_ct(&gid_pn->ct, adapter->pool.fsf_req_erp,
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 57d8e4bfb8d..81680efa172 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -164,6 +164,11 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
retval = zfcp_adapter_scsi_register(adapter);
if (retval)
goto out_scsi_register;
+
+ /* initialize request counter */
+ BUG_ON(!zfcp_reqlist_isempty(adapter));
+ adapter->req_no = 0;
+
zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
ZFCP_SET);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
@@ -270,19 +275,6 @@ zfcp_ccw_register(void)
}
/**
- * zfcp_ccw_unregister - ccw unregister function
- *
- * Unregisters the driver from common i/o layer. Function will be called at
- * module unload/system shutdown.
- */
-void __exit
-zfcp_ccw_unregister(void)
-{
- zfcp_sysfs_driver_remove_files(&zfcp_ccw_driver.driver);
- ccw_driver_unregister(&zfcp_ccw_driver);
-}
-
-/**
* zfcp_ccw_shutdown - gets called on reboot/shutdown
*
* Makes sure that QDIO queues are down when the system gets stopped.
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index c033145d0f1..0aa3b1ac76a 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -707,7 +707,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
struct zfcp_fsf_req *fsf_req,
- struct zfcp_fsf_req *old_fsf_req)
+ unsigned long old_req_id)
{
struct zfcp_scsi_dbf_record *rec = &adapter->scsi_dbf_buf;
struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec;
@@ -768,8 +768,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
rec->fsf_seqno = fsf_req->seq_no;
rec->fsf_issued = fsf_req->issued;
}
- rec->type.old_fsf_reqid =
- (unsigned long) old_fsf_req;
+ rec->type.old_fsf_reqid = old_req_id;
} else {
strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE);
dump->total_size = buflen;
@@ -794,17 +793,17 @@ zfcp_scsi_dbf_event_result(const char *tag, int level,
struct zfcp_fsf_req *fsf_req)
{
_zfcp_scsi_dbf_event_common("rslt", tag, level,
- adapter, scsi_cmnd, fsf_req, NULL);
+ adapter, scsi_cmnd, fsf_req, 0);
}
inline void
zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
struct scsi_cmnd *scsi_cmnd,
struct zfcp_fsf_req *new_fsf_req,
- struct zfcp_fsf_req *old_fsf_req)
+ unsigned long old_req_id)
{
_zfcp_scsi_dbf_event_common("abrt", tag, 1,
- adapter, scsi_cmnd, new_fsf_req, old_fsf_req);
+ adapter, scsi_cmnd, new_fsf_req, old_req_id);
}
inline void
@@ -814,7 +813,7 @@ zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
struct zfcp_adapter *adapter = unit->port->adapter;
_zfcp_scsi_dbf_event_common(flag == FCP_TARGET_RESET ? "trst" : "lrst",
- tag, 1, adapter, scsi_cmnd, NULL, NULL);
+ tag, 1, adapter, scsi_cmnd, NULL, 0);
}
static int
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index 2df512a18e2..8f882690994 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -19,7 +19,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#ifndef ZFCP_DEF_H
#define ZFCP_DEF_H
@@ -32,6 +31,10 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/mempool.h>
+#include <linux/syscalls.h>
+#include <linux/ioctl.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_cmnd.h>
@@ -39,20 +42,17 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
-#include "zfcp_fsf.h"
#include <asm/ccwdev.h>
#include <asm/qdio.h>
#include <asm/debug.h>
#include <asm/ebcdic.h>
-#include <linux/mempool.h>
-#include <linux/syscalls.h>
-#include <linux/ioctl.h>
+#include "zfcp_fsf.h"
/********************* GENERAL DEFINES *********************************/
/* zfcp version number, it consists of major, minor, and patch-level number */
-#define ZFCP_VERSION "4.7.0"
+#define ZFCP_VERSION "4.8.0"
/**
* zfcp_sg_to_address - determine kernel address from struct scatterlist
@@ -80,7 +80,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
#define REQUEST_LIST_SIZE 128
/********************* SCSI SPECIFIC DEFINES *********************************/
-#define ZFCP_SCSI_ER_TIMEOUT (100*HZ)
+#define ZFCP_SCSI_ER_TIMEOUT (10*HZ)
/********************* CIO/QDIO SPECIFIC DEFINES *****************************/
@@ -137,7 +137,7 @@ zfcp_address_to_sg(void *address, struct scatterlist *list)
#define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7
/* timeout value for "default timer" for fsf requests */
-#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ);
+#define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ)
/*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/
@@ -543,7 +543,7 @@ do { \
} while (0)
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_NORMAL
-# define ZFCP_LOG_NORMAL(fmt, args...)
+# define ZFCP_LOG_NORMAL(fmt, args...) do { } while (0)
#else
# define ZFCP_LOG_NORMAL(fmt, args...) \
do { \
@@ -553,7 +553,7 @@ do { \
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_INFO
-# define ZFCP_LOG_INFO(fmt, args...)
+# define ZFCP_LOG_INFO(fmt, args...) do { } while (0)
#else
# define ZFCP_LOG_INFO(fmt, args...) \
do { \
@@ -563,14 +563,14 @@ do { \
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_DEBUG
-# define ZFCP_LOG_DEBUG(fmt, args...)
+# define ZFCP_LOG_DEBUG(fmt, args...) do { } while (0)
#else
# define ZFCP_LOG_DEBUG(fmt, args...) \
ZFCP_LOG(ZFCP_LOG_LEVEL_DEBUG, fmt , ##args)
#endif
#if ZFCP_LOG_LEVEL_LIMIT < ZFCP_LOG_LEVEL_TRACE
-# define ZFCP_LOG_TRACE(fmt, args...)
+# define ZFCP_LOG_TRACE(fmt, args...) do { } while (0)
#else
# define ZFCP_LOG_TRACE(fmt, args...) \
ZFCP_LOG(ZFCP_LOG_LEVEL_TRACE, fmt , ##args)
@@ -779,7 +779,6 @@ typedef void (*zfcp_send_ct_handler_t)(unsigned long);
* @handler_data: data passed to handler function
* @pool: pointer to memory pool for ct request structure
* @timeout: FSF timeout for this request
- * @timer: timer (e.g. for request initiated by erp)
* @completion: completion for synchronization purposes
* @status: used to pass error status to calling function
*/
@@ -793,7 +792,6 @@ struct zfcp_send_ct {
unsigned long handler_data;
mempool_t *pool;
int timeout;
- struct timer_list *timer;
struct completion *completion;
int status;
};
@@ -821,7 +819,6 @@ typedef void (*zfcp_send_els_handler_t)(unsigned long);
* @resp_count: number of elements in response scatter-gather list
* @handler: handler function (called for response to the request)
* @handler_data: data passed to handler function
- * @timer: timer (e.g. for request initiated by erp)
* @completion: completion for synchronization purposes
* @ls_code: hex code of ELS command
* @status: used to pass error status to calling function
@@ -836,7 +833,6 @@ struct zfcp_send_els {
unsigned int resp_count;
zfcp_send_els_handler_t handler;
unsigned long handler_data;
- struct timer_list *timer;
struct completion *completion;
int ls_code;
int status;
@@ -886,11 +882,10 @@ struct zfcp_adapter {
struct list_head port_remove_lh; /* head of ports to be
removed */
u32 ports; /* number of remote ports */
- struct timer_list scsi_er_timer; /* SCSI err recovery watch */
- struct list_head fsf_req_list_head; /* head of FSF req list */
- spinlock_t fsf_req_list_lock; /* lock for ops on list of
- FSF requests */
- atomic_t fsf_reqs_active; /* # active FSF reqs */
+ atomic_t reqs_active; /* # active FSF reqs */
+ unsigned long req_no; /* unique FSF req number */
+ struct list_head *req_list; /* list of pending reqs */
+ spinlock_t req_list_lock; /* request list lock */
struct zfcp_qdio_queue request_queue; /* request queue */
u32 fsf_req_seq_no; /* FSF cmnd seq number */
wait_queue_head_t request_wq; /* can be used to wait for
@@ -986,6 +981,7 @@ struct zfcp_unit {
/* FSF request */
struct zfcp_fsf_req {
struct list_head list; /* list of FSF requests */
+ unsigned long req_id; /* unique request ID */
struct zfcp_adapter *adapter; /* adapter request belongs to */
u8 sbal_number; /* nr of SBALs free for use */
u8 sbal_first; /* first SBAL for this request */
@@ -1002,6 +998,7 @@ struct zfcp_fsf_req {
struct fsf_qtcb *qtcb; /* address of associated QTCB */
u32 seq_no; /* Sequence number of request */
unsigned long data; /* private data of request */
+ struct timer_list timer; /* used for erp or scsi er */
struct zfcp_erp_action *erp_action; /* used if this request is
issued on behalf of erp */
mempool_t *pool; /* used if request was alloacted
@@ -1015,6 +1012,7 @@ typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*);
/* driver data */
struct zfcp_data {
struct scsi_host_template scsi_host_template;
+ struct scsi_transport_template *scsi_transport_template;
atomic_t status; /* Module status flags */
struct list_head adapter_list_head; /* head of adapter list */
struct list_head adapter_remove_lh; /* head of adapters to be
@@ -1030,6 +1028,9 @@ struct zfcp_data {
wwn_t init_wwpn;
fcp_lun_t init_fcp_lun;
char *driver_version;
+ kmem_cache_t *fsf_req_qtcb_cache;
+ kmem_cache_t *sr_buffer_cache;
+ kmem_cache_t *gid_pn_cache;
};
/**
@@ -1050,7 +1051,7 @@ struct zfcp_sg_list {
#define ZFCP_POOL_DATA_GID_PN_NR 1
/* struct used by memory pools for fsf_requests */
-struct zfcp_fsf_req_pool_element {
+struct zfcp_fsf_req_qtcb {
struct zfcp_fsf_req fsf_req;
struct fsf_qtcb qtcb;
};
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 4682c8b8bd2..862a411a4aa 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -64,8 +64,6 @@ static int zfcp_erp_strategy_check_action(struct zfcp_erp_action *, int);
static int zfcp_erp_adapter_strategy(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *, int);
static int zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *);
-static int zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *);
static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *);
@@ -93,10 +91,10 @@ static int zfcp_erp_unit_strategy_clearstati(struct zfcp_unit *);
static int zfcp_erp_unit_strategy_close(struct zfcp_erp_action *);
static int zfcp_erp_unit_strategy_open(struct zfcp_erp_action *);
-static int zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
-static int zfcp_erp_action_dismiss_port(struct zfcp_port *);
-static int zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
-static int zfcp_erp_action_dismiss(struct zfcp_erp_action *);
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *);
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *);
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *);
+static void zfcp_erp_action_dismiss(struct zfcp_erp_action *);
static int zfcp_erp_action_enqueue(int, struct zfcp_adapter *,
struct zfcp_port *, struct zfcp_unit *);
@@ -112,8 +110,62 @@ static inline void zfcp_erp_action_to_ready(struct zfcp_erp_action *);
static inline void zfcp_erp_action_to_running(struct zfcp_erp_action *);
static void zfcp_erp_memwait_handler(unsigned long);
-static void zfcp_erp_timeout_handler(unsigned long);
-static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *);
+
+/**
+ * zfcp_close_qdio - close qdio queues for an adapter
+ */
+static void zfcp_close_qdio(struct zfcp_adapter *adapter)
+{
+ struct zfcp_qdio_queue *req_queue;
+ int first, count;
+
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status))
+ return;
+
+ /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */
+ req_queue = &adapter->request_queue;
+ write_lock_irq(&req_queue->queue_lock);
+ atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
+ write_unlock_irq(&req_queue->queue_lock);
+
+ debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
+ while (qdio_shutdown(adapter->ccw_device,
+ QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
+ msleep(1000);
+ debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
+
+ /* cleanup used outbound sbals */
+ count = atomic_read(&req_queue->free_count);
+ if (count < QDIO_MAX_BUFFERS_PER_Q) {
+ first = (req_queue->free_index+count) % QDIO_MAX_BUFFERS_PER_Q;
+ count = QDIO_MAX_BUFFERS_PER_Q - count;
+ zfcp_qdio_zero_sbals(req_queue->buffer, first, count);
+ }
+ req_queue->free_index = 0;
+ atomic_set(&req_queue->free_count, 0);
+ req_queue->distance_from_int = 0;
+ adapter->response_queue.free_index = 0;
+ atomic_set(&adapter->response_queue.free_count, 0);
+}
+
+/**
+ * zfcp_close_fsf - stop FSF operations for an adapter
+ *
+ * Dismiss and cleanup all pending fsf_reqs (this wakes up all initiators of
+ * requests waiting for completion; especially this returns SCSI commands
+ * with error state).
+ */
+static void zfcp_close_fsf(struct zfcp_adapter *adapter)
+{
+ /* close queues to ensure that buffers are not accessed by adapter */
+ zfcp_close_qdio(adapter);
+ zfcp_fsf_req_dismiss_all(adapter);
+ /* reset FSF request sequence number */
+ adapter->fsf_req_seq_no = 0;
+ /* all ports and units are closed */
+ zfcp_erp_modify_adapter_status(adapter,
+ ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
+}
/**
* zfcp_fsf_request_timeout_handler - called if a request timed out
@@ -122,42 +174,20 @@ static inline void zfcp_erp_timeout_init(struct zfcp_erp_action *);
* This function needs to be called if requests (ELS, Generic Service,
* or SCSI commands) exceed a certain time limit. The assumption is
* that after the time limit the adapter get stuck. So we trigger a reopen of
- * the adapter. This should not be used for error recovery, SCSI abort
- * commands and SCSI requests from SCSI mid-layer.
+ * the adapter.
*/
-void
-zfcp_fsf_request_timeout_handler(unsigned long data)
+static void zfcp_fsf_request_timeout_handler(unsigned long data)
{
- struct zfcp_adapter *adapter;
-
- adapter = (struct zfcp_adapter *) data;
-
+ struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
zfcp_erp_adapter_reopen(adapter, 0);
}
-/*
- * function: zfcp_fsf_scsi_er_timeout_handler
- *
- * purpose: This function needs to be called whenever a SCSI error recovery
- * action (abort/reset) does not return.
- * Re-opening the adapter means that the command can be returned
- * by zfcp (it is guarranteed that it does not return via the
- * adapter anymore). The buffer can then be used again.
- *
- * returns: sod all
- */
-void
-zfcp_fsf_scsi_er_timeout_handler(unsigned long data)
+void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
{
- struct zfcp_adapter *adapter = (struct zfcp_adapter *) data;
-
- ZFCP_LOG_NORMAL("warning: SCSI error recovery timed out. "
- "Restarting all operations on the adapter %s\n",
- zfcp_get_busid_by_adapter(adapter));
- debug_text_event(adapter->erp_dbf, 1, "eh_lmem_tout");
- zfcp_erp_adapter_reopen(adapter, 0);
-
- return;
+ fsf_req->timer.function = zfcp_fsf_request_timeout_handler;
+ fsf_req->timer.data = (unsigned long) fsf_req->adapter;
+ fsf_req->timer.expires = timeout;
+ add_timer(&fsf_req->timer);
}
/*
@@ -167,7 +197,7 @@ zfcp_fsf_scsi_er_timeout_handler(unsigned long data)
* initiates adapter recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
@@ -203,7 +233,7 @@ zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
* purpose: Wrappper for zfcp_erp_adapter_reopen_internal
* used to ensure the correct locking
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
@@ -273,7 +303,6 @@ zfcp_erp_adisc(struct zfcp_port *port)
struct zfcp_ls_adisc *adisc;
void *address = NULL;
int retval = 0;
- struct timer_list *timer;
send_els = kzalloc(sizeof(struct zfcp_send_els), GFP_ATOMIC);
if (send_els == NULL)
@@ -320,22 +349,11 @@ zfcp_erp_adisc(struct zfcp_port *port)
(wwn_t) adisc->wwnn, adisc->hard_nport_id,
adisc->nport_id);
- timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
- if (!timer)
- goto nomem;
-
- init_timer(timer);
- timer->function = zfcp_fsf_request_timeout_handler;
- timer->data = (unsigned long) adapter;
- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
- send_els->timer = timer;
-
retval = zfcp_fsf_send_els(send_els);
if (retval != 0) {
ZFCP_LOG_NORMAL("error: initiation of Send ELS failed for port "
"0x%08x on adapter %s\n", send_els->d_id,
zfcp_get_busid_by_adapter(adapter));
- del_timer(send_els->timer);
goto freemem;
}
@@ -347,7 +365,6 @@ zfcp_erp_adisc(struct zfcp_port *port)
if (address != NULL)
__free_pages(send_els->req->page, 0);
if (send_els != NULL) {
- kfree(send_els->timer);
kfree(send_els->req);
kfree(send_els->resp);
kfree(send_els);
@@ -373,9 +390,6 @@ zfcp_erp_adisc_handler(unsigned long data)
struct zfcp_ls_adisc_acc *adisc;
send_els = (struct zfcp_send_els *) data;
-
- del_timer(send_els->timer);
-
adapter = send_els->adapter;
port = send_els->port;
d_id = send_els->d_id;
@@ -424,7 +438,6 @@ zfcp_erp_adisc_handler(unsigned long data)
out:
zfcp_port_put(port);
__free_pages(send_els->req->page, 0);
- kfree(send_els->timer);
kfree(send_els->req);
kfree(send_els->resp);
kfree(send_els);
@@ -469,7 +482,7 @@ zfcp_test_link(struct zfcp_port *port)
* initiates Forced Reopen recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
static int
@@ -509,7 +522,7 @@ zfcp_erp_port_forced_reopen_internal(struct zfcp_port *port, int clear_mask)
* purpose: Wrappper for zfcp_erp_port_forced_reopen_internal
* used to ensure the correct locking
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
@@ -536,7 +549,7 @@ zfcp_erp_port_forced_reopen(struct zfcp_port *port, int clear_mask)
* initiates Reopen recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
static int
@@ -605,7 +618,7 @@ zfcp_erp_port_reopen(struct zfcp_port *port, int clear_mask)
* initiates Reopen recovery which is done
* asynchronously
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
static int
@@ -670,17 +683,10 @@ zfcp_erp_unit_reopen(struct zfcp_unit *unit, int clear_mask)
return retval;
}
-/*
- * function:
- *
- * purpose: disable I/O,
- * return any open requests and clean them up,
- * aim: no pending and incoming I/O
- *
- * returns:
+/**
+ * zfcp_erp_adapter_block - mark adapter as blocked, block scsi requests
*/
-static void
-zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
+static void zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
{
debug_text_event(adapter->erp_dbf, 6, "a_bl");
zfcp_erp_modify_adapter_status(adapter,
@@ -688,15 +694,10 @@ zfcp_erp_adapter_block(struct zfcp_adapter *adapter, int clear_mask)
clear_mask, ZFCP_CLEAR);
}
-/*
- * function:
- *
- * purpose: enable I/O
- *
- * returns:
+/**
+ * zfcp_erp_adapter_unblock - mark adapter as unblocked, allow scsi requests
*/
-static void
-zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
+static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter)
{
debug_text_event(adapter->erp_dbf, 6, "a_ubl");
atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status);
@@ -848,18 +849,16 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
if (erp_action->fsf_req) {
- /* take lock to ensure that request is not being deleted meanwhile */
- spin_lock(&adapter->fsf_req_list_lock);
- /* check whether fsf req does still exist */
- list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
- if (fsf_req == erp_action->fsf_req)
- break;
- if (fsf_req && (fsf_req->erp_action == erp_action)) {
+ /* take lock to ensure that request is not deleted meanwhile */
+ spin_lock(&adapter->req_list_lock);
+ if ((!zfcp_reqlist_ismember(adapter,
+ erp_action->fsf_req->req_id)) &&
+ (fsf_req->erp_action == erp_action)) {
/* fsf_req still exists */
debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
debug_event(adapter->erp_dbf, 3, &fsf_req,
sizeof (unsigned long));
- /* dismiss fsf_req of timed out or dismissed erp_action */
+ /* dismiss fsf_req of timed out/dismissed erp_action */
if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED |
ZFCP_STATUS_ERP_TIMEDOUT)) {
debug_text_event(adapter->erp_dbf, 3,
@@ -892,77 +891,50 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
*/
erp_action->fsf_req = NULL;
}
- spin_unlock(&adapter->fsf_req_list_lock);
+ spin_unlock(&adapter->req_list_lock);
} else
debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq");
return retval;
}
-/*
- * purpose: generic handler for asynchronous events related to erp_action events
- * (normal completion, time-out, dismissing, retry after
- * low memory condition)
- *
- * note: deletion of timer is not required (e.g. in case of a time-out),
- * but a second try does no harm,
- * we leave it in here to allow for greater simplification
+/**
+ * zfcp_erp_async_handler_nolock - complete erp_action
*
- * returns: 0 - there was an action to handle
- * !0 - otherwise
+ * Used for normal completion, time-out, dismissal and failure after
+ * low memory condition.
*/
-static int
-zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
- unsigned long set_mask)
+static void zfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action,
+ unsigned long set_mask)
{
- int retval;
struct zfcp_adapter *adapter = erp_action->adapter;
if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) {
debug_text_event(adapter->erp_dbf, 2, "a_asyh_ex");
debug_event(adapter->erp_dbf, 2, &erp_action->action,
sizeof (int));
- if (!(set_mask & ZFCP_STATUS_ERP_TIMEDOUT))
- del_timer(&erp_action->timer);
erp_action->status |= set_mask;
zfcp_erp_action_ready(erp_action);
- retval = 0;
} else {
/* action is ready or gone - nothing to do */
debug_text_event(adapter->erp_dbf, 3, "a_asyh_gone");
debug_event(adapter->erp_dbf, 3, &erp_action->action,
sizeof (int));
- retval = 1;
}
-
- return retval;
}
-/*
- * purpose: generic handler for asynchronous events related to erp_action
- * events (normal completion, time-out, dismissing, retry after
- * low memory condition)
- *
- * note: deletion of timer is not required (e.g. in case of a time-out),
- * but a second try does no harm,
- * we leave it in here to allow for greater simplification
- *
- * returns: 0 - there was an action to handle
- * !0 - otherwise
+/**
+ * zfcp_erp_async_handler - wrapper for erp_async_handler_nolock w/ locking
*/
-int
-zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
- unsigned long set_mask)
+void zfcp_erp_async_handler(struct zfcp_erp_action *erp_action,
+ unsigned long set_mask)
{
struct zfcp_adapter *adapter = erp_action->adapter;
unsigned long flags;
- int retval;
write_lock_irqsave(&adapter->erp_lock, flags);
- retval = zfcp_erp_async_handler_nolock(erp_action, set_mask);
+ zfcp_erp_async_handler_nolock(erp_action, set_mask);
write_unlock_irqrestore(&adapter->erp_lock, flags);
-
- return retval;
}
/*
@@ -987,8 +959,7 @@ zfcp_erp_memwait_handler(unsigned long data)
* action gets an appropriate flag and will be processed
* accordingly
*/
-static void
-zfcp_erp_timeout_handler(unsigned long data)
+void zfcp_erp_timeout_handler(unsigned long data)
{
struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data;
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -999,17 +970,15 @@ zfcp_erp_timeout_handler(unsigned long data)
zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT);
}
-/*
- * purpose: is called for an erp_action which needs to be ended
- * though not being done,
- * this is usually required if an higher is generated,
- * action gets an appropriate flag and will be processed
- * accordingly
+/**
+ * zfcp_erp_action_dismiss - dismiss an erp_action
*
- * locks: erp_lock held (thus we need to call another handler variant)
+ * adapter->erp_lock must be held
+ *
+ * Dismissal of an erp_action is usually required if an erp_action of
+ * higher priority is generated.
*/
-static int
-zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
+static void zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
{
struct zfcp_adapter *adapter = erp_action->adapter;
@@ -1017,8 +986,6 @@ zfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action)
debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int));
zfcp_erp_async_handler_nolock(erp_action, ZFCP_STATUS_ERP_DISMISSED);
-
- return 0;
}
int
@@ -1805,7 +1772,7 @@ zfcp_erp_modify_unit_status(struct zfcp_unit *unit, u32 mask, int set_or_clear)
* purpose: Wrappper for zfcp_erp_port_reopen_all_internal
* used to ensure the correct locking
*
- * returns: 0 - initiated action succesfully
+ * returns: 0 - initiated action successfully
* <0 - failed to initiate action
*/
int
@@ -1968,8 +1935,7 @@ zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *erp_action, int close)
&erp_action->adapter->status);
failed_openfcp:
- zfcp_erp_adapter_strategy_close_qdio(erp_action);
- zfcp_erp_adapter_strategy_close_fsf(erp_action);
+ zfcp_close_fsf(erp_action->adapter);
failed_qdio:
out:
return retval;
@@ -2074,69 +2040,6 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
return retval;
}
-/*
- * function: zfcp_qdio_cleanup
- *
- * purpose: cleans up QDIO operation for the specified adapter
- *
- * returns: 0 - successful cleanup
- * !0 - failed cleanup
- */
-int
-zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action)
-{
- int retval = ZFCP_ERP_SUCCEEDED;
- int first_used;
- int used_count;
- struct zfcp_adapter *adapter = erp_action->adapter;
-
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status)) {
- ZFCP_LOG_DEBUG("error: attempt to shut down inactive QDIO "
- "queues on adapter %s\n",
- zfcp_get_busid_by_adapter(adapter));
- retval = ZFCP_ERP_FAILED;
- goto out;
- }
-
- /*
- * Get queue_lock and clear QDIOUP flag. Thus it's guaranteed that
- * do_QDIO won't be called while qdio_shutdown is in progress.
- */
-
- write_lock_irq(&adapter->request_queue.queue_lock);
- atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status);
- write_unlock_irq(&adapter->request_queue.queue_lock);
-
- debug_text_event(adapter->erp_dbf, 3, "qdio_down2a");
- while (qdio_shutdown(adapter->ccw_device,
- QDIO_FLAG_CLEANUP_USING_CLEAR) == -EINPROGRESS)
- msleep(1000);
- debug_text_event(adapter->erp_dbf, 3, "qdio_down2b");
-
- /*
- * First we had to stop QDIO operation.
- * Now it is safe to take the following actions.
- */
-
- /* Cleanup only necessary when there are unacknowledged buffers */
- if (atomic_read(&adapter->request_queue.free_count)
- < QDIO_MAX_BUFFERS_PER_Q) {
- first_used = (adapter->request_queue.free_index +
- atomic_read(&adapter->request_queue.free_count))
- % QDIO_MAX_BUFFERS_PER_Q;
- used_count = QDIO_MAX_BUFFERS_PER_Q -
- atomic_read(&adapter->request_queue.free_count);
- zfcp_qdio_zero_sbals(adapter->request_queue.buffer,
- first_used, used_count);
- }
- adapter->response_queue.free_index = 0;
- atomic_set(&adapter->response_queue.free_count, 0);
- adapter->request_queue.free_index = 0;
- atomic_set(&adapter->request_queue.free_count, 0);
- adapter->request_queue.distance_from_int = 0;
- out:
- return retval;
-}
static int
zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action)
@@ -2168,10 +2071,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
&adapter->status);
ZFCP_LOG_DEBUG("Doing exchange config data\n");
- write_lock(&adapter->erp_lock);
+ write_lock_irq(&adapter->erp_lock);
zfcp_erp_action_to_running(erp_action);
- write_unlock(&adapter->erp_lock);
- zfcp_erp_timeout_init(erp_action);
+ write_unlock_irq(&adapter->erp_lock);
if (zfcp_fsf_exchange_config_data(erp_action)) {
retval = ZFCP_ERP_FAILED;
debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf");
@@ -2236,11 +2138,10 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
adapter = erp_action->adapter;
atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status);
- write_lock(&adapter->erp_lock);
+ write_lock_irq(&adapter->erp_lock);
zfcp_erp_action_to_running(erp_action);
- write_unlock(&adapter->erp_lock);
+ write_unlock_irq(&adapter->erp_lock);
- zfcp_erp_timeout_init(erp_action);
ret = zfcp_fsf_exchange_port_data(erp_action, adapter, NULL);
if (ret == -EOPNOTSUPP) {
debug_text_event(adapter->erp_dbf, 3, "a_xport_notsupp");
@@ -2258,11 +2159,11 @@ zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action)
"%s)\n", zfcp_get_busid_by_adapter(adapter));
ret = ZFCP_ERP_FAILED;
}
- if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status)) {
- ZFCP_LOG_INFO("error: exchange port data failed (adapter "
+
+ /* don't treat as error for the sake of compatibility */
+ if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status))
+ ZFCP_LOG_INFO("warning: exchange port data failed (adapter "
"%s\n", zfcp_get_busid_by_adapter(adapter));
- ret = ZFCP_ERP_FAILED;
- }
return ret;
}
@@ -2293,35 +2194,6 @@ zfcp_erp_adapter_strategy_open_fsf_statusread(struct zfcp_erp_action
}
/*
- * function: zfcp_fsf_cleanup
- *
- * purpose: cleanup FSF operation for specified adapter
- *
- * returns: 0 - FSF operation successfully cleaned up
- * !0 - failed to cleanup FSF operation for this adapter
- */
-static int
-zfcp_erp_adapter_strategy_close_fsf(struct zfcp_erp_action *erp_action)
-{
- int retval = ZFCP_ERP_SUCCEEDED;
- struct zfcp_adapter *adapter = erp_action->adapter;
-
- /*
- * wake waiting initiators of requests,
- * return SCSI commands (with error status),
- * clean up all requests (synchronously)
- */
- zfcp_fsf_req_dismiss_all(adapter);
- /* reset FSF request sequence number */
- adapter->fsf_req_seq_no = 0;
- /* all ports and units are closed */
- zfcp_erp_modify_adapter_status(adapter,
- ZFCP_STATUS_COMMON_OPEN, ZFCP_CLEAR);
-
- return retval;
-}
-
-/*
* function:
*
* purpose: this routine executes the 'Reopen Physical Port' action
@@ -2657,7 +2529,6 @@ zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_close_physical_port(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "o_pfstc_nomem");
@@ -2714,7 +2585,6 @@ zfcp_erp_port_strategy_close(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_close_port(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstc_nomem");
@@ -2752,7 +2622,6 @@ zfcp_erp_port_strategy_open_port(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_open_port(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_psto_nomem");
@@ -2790,7 +2659,6 @@ zfcp_erp_port_strategy_open_common_lookup(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_port *port = erp_action->port;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_ns_gid_pn_request(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "p_pstn_nomem");
@@ -2916,7 +2784,6 @@ zfcp_erp_unit_strategy_close(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_unit *unit = erp_action->unit;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_close_unit(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "u_ustc_nomem");
@@ -2957,7 +2824,6 @@ zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
struct zfcp_adapter *adapter = erp_action->adapter;
struct zfcp_unit *unit = erp_action->unit;
- zfcp_erp_timeout_init(erp_action);
retval = zfcp_fsf_open_unit(erp_action);
if (retval == -ENOMEM) {
debug_text_event(adapter->erp_dbf, 5, "u_usto_nomem");
@@ -2982,14 +2848,13 @@ zfcp_erp_unit_strategy_open(struct zfcp_erp_action *erp_action)
return retval;
}
-static inline void
-zfcp_erp_timeout_init(struct zfcp_erp_action *erp_action)
+void zfcp_erp_start_timer(struct zfcp_fsf_req *fsf_req)
{
- init_timer(&erp_action->timer);
- erp_action->timer.function = zfcp_erp_timeout_handler;
- erp_action->timer.data = (unsigned long) erp_action;
- /* jiffies will be added in zfcp_fsf_req_send */
- erp_action->timer.expires = ZFCP_ERP_FSFREQ_TIMEOUT;
+ BUG_ON(!fsf_req->erp_action);
+ fsf_req->timer.function = zfcp_erp_timeout_handler;
+ fsf_req->timer.data = (unsigned long) fsf_req->erp_action;
+ fsf_req->timer.expires = jiffies + ZFCP_ERP_FSFREQ_TIMEOUT;
+ add_timer(&fsf_req->timer);
}
/*
@@ -3293,10 +3158,8 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
}
-static int
-zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
+static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
{
- int retval = 0;
struct zfcp_port *port;
debug_text_event(adapter->erp_dbf, 5, "a_actab");
@@ -3305,14 +3168,10 @@ zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter)
else
list_for_each_entry(port, &adapter->port_list_head, list)
zfcp_erp_action_dismiss_port(port);
-
- return retval;
}
-static int
-zfcp_erp_action_dismiss_port(struct zfcp_port *port)
+static void zfcp_erp_action_dismiss_port(struct zfcp_port *port)
{
- int retval = 0;
struct zfcp_unit *unit;
struct zfcp_adapter *adapter = port->adapter;
@@ -3323,22 +3182,16 @@ zfcp_erp_action_dismiss_port(struct zfcp_port *port)
else
list_for_each_entry(unit, &port->unit_list_head, list)
zfcp_erp_action_dismiss_unit(unit);
-
- return retval;
}
-static int
-zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
+static void zfcp_erp_action_dismiss_unit(struct zfcp_unit *unit)
{
- int retval = 0;
struct zfcp_adapter *adapter = unit->port->adapter;
debug_text_event(adapter->erp_dbf, 5, "u_actab");
debug_event(adapter->erp_dbf, 5, &unit->fcp_lun, sizeof (fcp_lun_t));
if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &unit->status))
zfcp_erp_action_dismiss(&unit->erp_action);
-
- return retval;
}
static inline void
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index d02366004cd..b8794d77285 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -55,7 +55,6 @@ extern void zfcp_unit_dequeue(struct zfcp_unit *);
/******************************* S/390 IO ************************************/
extern int zfcp_ccw_register(void);
-extern void zfcp_ccw_unregister(void);
extern void zfcp_qdio_zero_sbals(struct qdio_buffer **, int, int);
extern int zfcp_qdio_allocate(struct zfcp_adapter *);
@@ -63,7 +62,6 @@ extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *);
extern void zfcp_qdio_free_queues(struct zfcp_adapter *);
extern int zfcp_qdio_determine_pci(struct zfcp_qdio_queue *,
struct zfcp_fsf_req *);
-extern int zfcp_qdio_reqid_check(struct zfcp_adapter *, void *);
extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req
(struct zfcp_fsf_req *, int, int);
@@ -89,8 +87,8 @@ extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *,
struct fsf_qtcb_bottom_port *);
extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **,
u32, u32, struct zfcp_sg_list *);
-extern void zfcp_fsf_request_timeout_handler(unsigned long);
-extern void zfcp_fsf_scsi_er_timeout_handler(unsigned long);
+extern void zfcp_fsf_start_timer(struct zfcp_fsf_req *, unsigned long);
+extern void zfcp_erp_start_timer(struct zfcp_fsf_req *);
extern int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *);
extern int zfcp_fsf_status_read(struct zfcp_adapter *, int);
extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *,
@@ -100,8 +98,7 @@ extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *,
extern int zfcp_fsf_send_els(struct zfcp_send_els *);
extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *,
struct zfcp_unit *,
- struct scsi_cmnd *,
- struct timer_list*, int);
+ struct scsi_cmnd *, int, int);
extern int zfcp_fsf_req_complete(struct zfcp_fsf_req *);
extern void zfcp_fsf_incoming_els(struct zfcp_fsf_req *);
extern void zfcp_fsf_req_free(struct zfcp_fsf_req *);
@@ -125,14 +122,11 @@ extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
extern void set_host_byte(u32 *, char);
extern void set_driver_byte(u32 *, char);
extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
-extern void zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *);
extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
extern int zfcp_scsi_command_async(struct zfcp_adapter *,struct zfcp_unit *,
- struct scsi_cmnd *, struct timer_list *);
-extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *,
- struct timer_list *);
-extern struct scsi_transport_template *zfcp_transport_template;
+ struct scsi_cmnd *, int);
+extern int zfcp_scsi_command_sync(struct zfcp_unit *, struct scsi_cmnd *, int);
extern struct fc_function_template zfcp_transport_functions;
/******************************** ERP ****************************************/
@@ -156,7 +150,7 @@ extern void zfcp_erp_unit_failed(struct zfcp_unit *);
extern int zfcp_erp_thread_setup(struct zfcp_adapter *);
extern int zfcp_erp_thread_kill(struct zfcp_adapter *);
extern int zfcp_erp_wait(struct zfcp_adapter *);
-extern int zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long);
+extern void zfcp_erp_async_handler(struct zfcp_erp_action *, unsigned long);
extern int zfcp_test_link(struct zfcp_port *);
@@ -187,8 +181,13 @@ extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *,
struct zfcp_fsf_req *);
extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
struct scsi_cmnd *, struct zfcp_fsf_req *,
- struct zfcp_fsf_req *);
+ unsigned long);
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
struct scsi_cmnd *);
+extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
+extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
+extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
+ unsigned long);
+extern int zfcp_reqlist_isempty(struct zfcp_adapter *);
#endif /* ZFCP_EXT_H */
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 6335f922918..277826cdd0c 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -42,14 +42,13 @@ static inline int zfcp_fsf_req_sbal_check(
static inline int zfcp_use_one_sbal(
struct scatterlist *, int, struct scatterlist *, int);
static struct zfcp_fsf_req *zfcp_fsf_req_alloc(mempool_t *, int);
-static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *);
+static int zfcp_fsf_req_send(struct zfcp_fsf_req *);
static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *);
static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *);
static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *);
static void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *,
struct fsf_link_down_info *);
static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *);
-static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *);
/* association between FSF command and FSF QTCB type */
static u32 fsf_qtcb_type[] = {
@@ -101,14 +100,19 @@ zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
if (req_flags & ZFCP_REQ_NO_QTCB)
size = sizeof(struct zfcp_fsf_req);
else
- size = sizeof(struct zfcp_fsf_req_pool_element);
+ size = sizeof(struct zfcp_fsf_req_qtcb);
- if (likely(pool != NULL))
+ if (likely(pool))
ptr = mempool_alloc(pool, GFP_ATOMIC);
- else
- ptr = kmalloc(size, GFP_ATOMIC);
+ else {
+ if (req_flags & ZFCP_REQ_NO_QTCB)
+ ptr = kmalloc(size, GFP_ATOMIC);
+ else
+ ptr = kmem_cache_alloc(zfcp_data.fsf_req_qtcb_cache,
+ SLAB_ATOMIC);
+ }
- if (unlikely(NULL == ptr))
+ if (unlikely(!ptr))
goto out;
memset(ptr, 0, size);
@@ -116,9 +120,8 @@ zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
if (req_flags & ZFCP_REQ_NO_QTCB) {
fsf_req = (struct zfcp_fsf_req *) ptr;
} else {
- fsf_req = &((struct zfcp_fsf_req_pool_element *) ptr)->fsf_req;
- fsf_req->qtcb =
- &((struct zfcp_fsf_req_pool_element *) ptr)->qtcb;
+ fsf_req = &((struct zfcp_fsf_req_qtcb *) ptr)->fsf_req;
+ fsf_req->qtcb = &((struct zfcp_fsf_req_qtcb *) ptr)->qtcb;
}
fsf_req->pool = pool;
@@ -140,55 +143,63 @@ zfcp_fsf_req_alloc(mempool_t *pool, int req_flags)
void
zfcp_fsf_req_free(struct zfcp_fsf_req *fsf_req)
{
- if (likely(fsf_req->pool != NULL))
+ if (likely(fsf_req->pool)) {
mempool_free(fsf_req, fsf_req->pool);
- else
- kfree(fsf_req);
-}
-
-/*
- * function:
- *
- * purpose:
- *
- * returns:
- *
- * note: qdio queues shall be down (no ongoing inbound processing)
- */
-int
-zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
-{
- struct zfcp_fsf_req *fsf_req, *tmp;
- unsigned long flags;
- LIST_HEAD(remove_queue);
-
- spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
- list_splice_init(&adapter->fsf_req_list_head, &remove_queue);
- atomic_set(&adapter->fsf_reqs_active, 0);
- spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
+ return;
+ }
- list_for_each_entry_safe(fsf_req, tmp, &remove_queue, list) {
- list_del(&fsf_req->list);
- zfcp_fsf_req_dismiss(fsf_req);
+ if (fsf_req->qtcb) {
+ kmem_cache_free(zfcp_data.fsf_req_qtcb_cache, fsf_req);
+ return;
}
- return 0;
+ kfree(fsf_req);
}
-/*
- * function:
- *
- * purpose:
- *
- * returns:
+/**
+ * zfcp_fsf_req_dismiss - dismiss a single fsf request
*/
-static void
-zfcp_fsf_req_dismiss(struct zfcp_fsf_req *fsf_req)
+static void zfcp_fsf_req_dismiss(struct zfcp_adapter *adapter,
+ struct zfcp_fsf_req *fsf_req,
+ unsigned int counter)
{
+ u64 dbg_tmp[2];
+
+ dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
+ dbg_tmp[1] = (u64) counter;
+ debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
+ list_del(&fsf_req->list);
fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED;
zfcp_fsf_req_complete(fsf_req);
}
+/**
+ * zfcp_fsf_req_dismiss_all - dismiss all remaining fsf requests
+ */
+int zfcp_fsf_req_dismiss_all(struct zfcp_adapter *adapter)
+{
+ struct zfcp_fsf_req *request, *tmp;
+ unsigned long flags;
+ unsigned int i, counter;
+
+ spin_lock_irqsave(&adapter->req_list_lock, flags);
+ atomic_set(&adapter->reqs_active, 0);
+ for (i=0; i<REQUEST_LIST_SIZE; i++) {
+ if (list_empty(&adapter->req_list[i]))
+ continue;
+
+ counter = 0;
+ list_for_each_entry_safe(request, tmp,
+ &adapter->req_list[i], list) {
+ zfcp_fsf_req_dismiss(adapter, request, counter);
+ counter++;
+ }
+ }
+ spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+
+ return 0;
+}
+
/*
* function: zfcp_fsf_req_complete
*
@@ -214,8 +225,10 @@ zfcp_fsf_req_complete(struct zfcp_fsf_req *fsf_req)
*/
zfcp_fsf_status_read_handler(fsf_req);
goto out;
- } else
+ } else {
+ del_timer(&fsf_req->timer);
zfcp_fsf_protstatus_eval(fsf_req);
+ }
/*
* fsf_req may be deleted due to waking up functions, so
@@ -774,8 +787,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags)
sbale->addr = (void *) status_buffer;
sbale->length = sizeof(struct fsf_status_read_buffer);
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(fsf_req, NULL);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
ZFCP_LOG_DEBUG("error: Could not set-up unsolicited status "
"environment.\n");
@@ -1101,8 +1113,8 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
struct zfcp_unit *unit, int req_flags)
{
volatile struct qdio_buffer_element *sbale;
- unsigned long lock_flags;
struct zfcp_fsf_req *fsf_req = NULL;
+ unsigned long lock_flags;
int retval = 0;
/* setup new FSF request */
@@ -1132,12 +1144,9 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id,
/* set handle of request which should be aborted */
fsf_req->qtcb->bottom.support.req_handle = (u64) old_req_id;
- /* start QDIO request for this FSF request */
-
- zfcp_fsf_start_scsi_er_timer(adapter);
- retval = zfcp_fsf_req_send(fsf_req, NULL);
+ zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
- del_timer(&adapter->scsi_er_timer);
ZFCP_LOG_INFO("error: Failed to send abort command request "
"on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
zfcp_get_busid_by_adapter(adapter),
@@ -1173,8 +1182,6 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req)
unsigned char status_qual =
new_fsf_req->qtcb->header.fsf_status_qual.word[0];
- del_timer(&new_fsf_req->adapter->scsi_er_timer);
-
if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
/* do not set ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED */
goto skip_fsfstatus;
@@ -1380,11 +1387,6 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
goto failed_req;
}
- if (erp_action != NULL) {
- erp_action->fsf_req = fsf_req;
- fsf_req->erp_action = erp_action;
- }
-
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
if (zfcp_use_one_sbal(ct->req, ct->req_count,
ct->resp, ct->resp_count)){
@@ -1451,8 +1453,14 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool,
zfcp_san_dbf_event_ct_request(fsf_req);
- /* start QDIO request for this FSF request */
- ret = zfcp_fsf_req_send(fsf_req, ct->timer);
+ if (erp_action) {
+ erp_action->fsf_req = fsf_req;
+ fsf_req->erp_action = erp_action;
+ zfcp_erp_start_timer(fsf_req);
+ } else
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+
+ ret = zfcp_fsf_req_send(fsf_req);
if (ret) {
ZFCP_LOG_DEBUG("error: initiation of CT request failed "
"(adapter %s, port 0x%016Lx)\n",
@@ -1749,8 +1757,8 @@ zfcp_fsf_send_els(struct zfcp_send_els *els)
zfcp_san_dbf_event_els_request(fsf_req);
- /* start QDIO request for this FSF request */
- ret = zfcp_fsf_req_send(fsf_req, els->timer);
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ ret = zfcp_fsf_req_send(fsf_req);
if (ret) {
ZFCP_LOG_DEBUG("error: initiation of ELS request failed "
"(adapter %s, port d_id: 0x%08x)\n",
@@ -1947,6 +1955,7 @@ int
zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
unsigned long lock_flags;
int retval = 0;
@@ -1955,7 +1964,7 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
FSF_QTCB_EXCHANGE_CONFIG_DATA,
ZFCP_REQ_AUTO_CLEANUP,
erp_action->adapter->pool.fsf_req_erp,
- &lock_flags, &(erp_action->fsf_req));
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Could not create exchange configuration "
"data request for adapter %s.\n",
@@ -1963,26 +1972,26 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action)
goto out;
}
- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
- erp_action->fsf_req->sbal_curr, 0);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- erp_action->fsf_req->erp_action = erp_action;
- erp_action->fsf_req->qtcb->bottom.config.feature_selection =
+ fsf_req->qtcb->bottom.config.feature_selection =
FSF_FEATURE_CFDC |
FSF_FEATURE_LUN_SHARING |
FSF_FEATURE_NOTIFICATION_LOST |
FSF_FEATURE_UPDATE_ALERT;
+ fsf_req->erp_action = erp_action;
+ erp_action->fsf_req = fsf_req;
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ zfcp_erp_start_timer(fsf_req);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
ZFCP_LOG_INFO
("error: Could not send exchange configuration data "
"command on the adapter %s\n",
zfcp_get_busid_by_adapter(erp_action->adapter));
- zfcp_fsf_req_free(erp_action->fsf_req);
+ zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
goto out;
}
@@ -2212,10 +2221,9 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
struct fsf_qtcb_bottom_port *data)
{
volatile struct qdio_buffer_element *sbale;
- int retval = 0;
- unsigned long lock_flags;
struct zfcp_fsf_req *fsf_req;
- struct timer_list *timer;
+ unsigned long lock_flags;
+ int retval = 0;
if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) {
ZFCP_LOG_INFO("error: exchange port data "
@@ -2227,7 +2235,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
/* setup new FSF request */
retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_PORT_DATA,
erp_action ? ZFCP_REQ_AUTO_CLEANUP : 0,
- 0, &lock_flags, &fsf_req);
+ NULL, &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Out of resources. Could not create an "
"exchange port data request for"
@@ -2248,22 +2256,11 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
if (erp_action) {
erp_action->fsf_req = fsf_req;
fsf_req->erp_action = erp_action;
- timer = &erp_action->timer;
- } else {
- timer = kmalloc(sizeof(struct timer_list), GFP_ATOMIC);
- if (!timer) {
- write_unlock_irqrestore(&adapter->request_queue.queue_lock,
- lock_flags);
- zfcp_fsf_req_free(fsf_req);
- return -ENOMEM;
- }
- init_timer(timer);
- timer->function = zfcp_fsf_request_timeout_handler;
- timer->data = (unsigned long) adapter;
- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
- }
+ zfcp_erp_start_timer(fsf_req);
+ } else
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
- retval = zfcp_fsf_req_send(fsf_req, timer);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not send an exchange port data "
"command on the adapter %s\n",
@@ -2271,8 +2268,6 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
zfcp_fsf_req_free(fsf_req);
if (erp_action)
erp_action->fsf_req = NULL;
- else
- kfree(timer);
write_unlock_irqrestore(&adapter->request_queue.queue_lock,
lock_flags);
return retval;
@@ -2283,9 +2278,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action,
if (!erp_action) {
wait_event(fsf_req->completion_wq,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
- del_timer_sync(timer);
zfcp_fsf_req_free(fsf_req);
- kfree(timer);
}
return retval;
}
@@ -2367,6 +2360,7 @@ int
zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
unsigned long lock_flags;
int retval = 0;
@@ -2375,7 +2369,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
FSF_QTCB_OPEN_PORT_WITH_DID,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
erp_action->adapter->pool.fsf_req_erp,
- &lock_flags, &(erp_action->fsf_req));
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Could not create open port request "
"for port 0x%016Lx on adapter %s.\n",
@@ -2384,24 +2378,24 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action)
goto out;
}
- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
- erp_action->fsf_req->sbal_curr, 0);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
+ fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id;
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status);
- erp_action->fsf_req->data = (unsigned long) erp_action->port;
- erp_action->fsf_req->erp_action = erp_action;
+ fsf_req->data = (unsigned long) erp_action->port;
+ fsf_req->erp_action = erp_action;
+ erp_action->fsf_req = fsf_req;
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ zfcp_erp_start_timer(fsf_req);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not send open port request for "
"port 0x%016Lx on adapter %s.\n",
erp_action->port->wwpn,
zfcp_get_busid_by_adapter(erp_action->adapter));
- zfcp_fsf_req_free(erp_action->fsf_req);
+ zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
goto out;
}
@@ -2623,6 +2617,7 @@ int
zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
unsigned long lock_flags;
int retval = 0;
@@ -2631,7 +2626,7 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
FSF_QTCB_CLOSE_PORT,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
erp_action->adapter->pool.fsf_req_erp,
- &lock_flags, &(erp_action->fsf_req));
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Could not create a close port request "
"for port 0x%016Lx on adapter %s.\n",
@@ -2640,25 +2635,25 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action)
goto out;
}
- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
- erp_action->fsf_req->sbal_curr, 0);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status);
- erp_action->fsf_req->data = (unsigned long) erp_action->port;
- erp_action->fsf_req->erp_action = erp_action;
- erp_action->fsf_req->qtcb->header.port_handle =
- erp_action->port->handle;
-
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ fsf_req->data = (unsigned long) erp_action->port;
+ fsf_req->erp_action = erp_action;
+ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
+ fsf_req->erp_action = erp_action;
+ erp_action->fsf_req = fsf_req;
+
+ zfcp_erp_start_timer(fsf_req);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not send a close port request for "
"port 0x%016Lx on adapter %s.\n",
erp_action->port->wwpn,
zfcp_get_busid_by_adapter(erp_action->adapter));
- zfcp_fsf_req_free(erp_action->fsf_req);
+ zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
goto out;
}
@@ -2755,16 +2750,17 @@ zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req)
int
zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
{
- int retval = 0;
- unsigned long lock_flags;
volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long lock_flags;
+ int retval = 0;
/* setup new FSF request */
retval = zfcp_fsf_req_create(erp_action->adapter,
FSF_QTCB_CLOSE_PHYSICAL_PORT,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
erp_action->adapter->pool.fsf_req_erp,
- &lock_flags, &erp_action->fsf_req);
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Could not create close physical port "
"request (adapter %s, port 0x%016Lx)\n",
@@ -2774,8 +2770,7 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
goto out;
}
- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
- erp_action->fsf_req->sbal_curr, 0);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
@@ -2783,20 +2778,19 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action)
atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING,
&erp_action->port->status);
/* save a pointer to this port */
- erp_action->fsf_req->data = (unsigned long) erp_action->port;
- /* port to be closed */
- erp_action->fsf_req->qtcb->header.port_handle =
- erp_action->port->handle;
- erp_action->fsf_req->erp_action = erp_action;
-
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ fsf_req->data = (unsigned long) erp_action->port;
+ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
+ fsf_req->erp_action = erp_action;
+ erp_action->fsf_req = fsf_req;
+
+ zfcp_erp_start_timer(fsf_req);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not send close physical port "
"request (adapter %s, port 0x%016Lx)\n",
zfcp_get_busid_by_adapter(erp_action->adapter),
erp_action->port->wwpn);
- zfcp_fsf_req_free(erp_action->fsf_req);
+ zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
goto out;
}
@@ -2961,6 +2955,7 @@ int
zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
unsigned long lock_flags;
int retval = 0;
@@ -2969,7 +2964,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
FSF_QTCB_OPEN_LUN,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
erp_action->adapter->pool.fsf_req_erp,
- &lock_flags, &(erp_action->fsf_req));
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Could not create open unit request for "
"unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
@@ -2979,24 +2974,22 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
goto out;
}
- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
- erp_action->fsf_req->sbal_curr, 0);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- erp_action->fsf_req->qtcb->header.port_handle =
- erp_action->port->handle;
- erp_action->fsf_req->qtcb->bottom.support.fcp_lun =
- erp_action->unit->fcp_lun;
+ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
+ fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun;
if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE))
- erp_action->fsf_req->qtcb->bottom.support.option =
+ fsf_req->qtcb->bottom.support.option =
FSF_OPEN_LUN_SUPPRESS_BOXING;
atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status);
- erp_action->fsf_req->data = (unsigned long) erp_action->unit;
- erp_action->fsf_req->erp_action = erp_action;
+ fsf_req->data = (unsigned long) erp_action->unit;
+ fsf_req->erp_action = erp_action;
+ erp_action->fsf_req = fsf_req;
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ zfcp_erp_start_timer(fsf_req);
+ retval = zfcp_fsf_req_send(erp_action->fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not send an open unit request "
"on the adapter %s, port 0x%016Lx for "
@@ -3004,7 +2997,7 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action)
zfcp_get_busid_by_adapter(erp_action->adapter),
erp_action->port->wwpn,
erp_action->unit->fcp_lun);
- zfcp_fsf_req_free(erp_action->fsf_req);
+ zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
goto out;
}
@@ -3297,6 +3290,7 @@ int
zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
{
volatile struct qdio_buffer_element *sbale;
+ struct zfcp_fsf_req *fsf_req;
unsigned long lock_flags;
int retval = 0;
@@ -3305,7 +3299,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
FSF_QTCB_CLOSE_LUN,
ZFCP_WAIT_FOR_SBAL | ZFCP_REQ_AUTO_CLEANUP,
erp_action->adapter->pool.fsf_req_erp,
- &lock_flags, &(erp_action->fsf_req));
+ &lock_flags, &fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("error: Could not create close unit request for "
"unit 0x%016Lx on port 0x%016Lx on adapter %s.\n",
@@ -3315,27 +3309,26 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action)
goto out;
}
- sbale = zfcp_qdio_sbale_req(erp_action->fsf_req,
- erp_action->fsf_req->sbal_curr, 0);
+ sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
sbale[0].flags |= SBAL_FLAGS0_TYPE_READ;
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- erp_action->fsf_req->qtcb->header.port_handle =
- erp_action->port->handle;
- erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
+ fsf_req->qtcb->header.port_handle = erp_action->port->handle;
+ fsf_req->qtcb->header.lun_handle = erp_action->unit->handle;
atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status);
- erp_action->fsf_req->data = (unsigned long) erp_action->unit;
- erp_action->fsf_req->erp_action = erp_action;
+ fsf_req->data = (unsigned long) erp_action->unit;
+ fsf_req->erp_action = erp_action;
+ erp_action->fsf_req = fsf_req;
- /* start QDIO request for this FSF request */
- retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer);
+ zfcp_erp_start_timer(fsf_req);
+ retval = zfcp_fsf_req_send(erp_action->fsf_req);
if (retval) {
ZFCP_LOG_INFO("error: Could not send a close unit request for "
"unit 0x%016Lx on port 0x%016Lx onadapter %s.\n",
erp_action->unit->fcp_lun,
erp_action->port->wwpn,
zfcp_get_busid_by_adapter(erp_action->adapter));
- zfcp_fsf_req_free(erp_action->fsf_req);
+ zfcp_fsf_req_free(fsf_req);
erp_action->fsf_req = NULL;
goto out;
}
@@ -3488,7 +3481,7 @@ int
zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
struct zfcp_unit *unit,
struct scsi_cmnd * scsi_cmnd,
- struct timer_list *timer, int req_flags)
+ int use_timer, int req_flags)
{
struct zfcp_fsf_req *fsf_req = NULL;
struct fcp_cmnd_iu *fcp_cmnd_iu;
@@ -3516,7 +3509,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
fsf_req->unit = unit;
/* associate FSF request with SCSI request (for look up on abort) */
- scsi_cmnd->host_scribble = (char *) fsf_req;
+ scsi_cmnd->host_scribble = (unsigned char *) fsf_req->req_id;
/* associate SCSI command with FSF request */
fsf_req->data = (unsigned long) scsi_cmnd;
@@ -3629,11 +3622,10 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter,
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG,
(char *) scsi_cmnd->cmnd, scsi_cmnd->cmd_len);
- /*
- * start QDIO request for this FSF request
- * covered by an SBALE)
- */
- retval = zfcp_fsf_req_send(fsf_req, timer);
+ if (use_timer)
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+
+ retval = zfcp_fsf_req_send(fsf_req);
if (unlikely(retval < 0)) {
ZFCP_LOG_INFO("error: Could not send FCP command request "
"on adapter %s, port 0x%016Lx, unit 0x%016Lx\n",
@@ -3718,11 +3710,9 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter,
fcp_cmnd_iu->fcp_lun = unit->fcp_lun;
fcp_cmnd_iu->task_management_flags = tm_flags;
- /* start QDIO request for this FSF request */
- zfcp_fsf_start_scsi_er_timer(adapter);
- retval = zfcp_fsf_req_send(fsf_req, NULL);
+ zfcp_fsf_start_timer(fsf_req, ZFCP_SCSI_ER_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval) {
- del_timer(&adapter->scsi_er_timer);
ZFCP_LOG_INFO("error: Could not send an FCP-command (task "
"management) on adapter %s, port 0x%016Lx for "
"unit LUN 0x%016Lx\n",
@@ -4226,7 +4216,6 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req)
char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu);
struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data;
- del_timer(&fsf_req->adapter->scsi_er_timer);
if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) {
fsf_req->status |= ZFCP_STATUS_FSFREQ_TMFUNCFAILED;
goto skip_fsfstatus;
@@ -4295,7 +4284,6 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter,
struct zfcp_fsf_req *fsf_req;
struct fsf_qtcb_bottom_support *bottom;
volatile struct qdio_buffer_element *sbale;
- struct timer_list *timer;
unsigned long lock_flags;
int req_flags = 0;
int direction;
@@ -4327,12 +4315,6 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter,
goto out;
}
- timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
- if (!timer) {
- retval = -ENOMEM;
- goto out;
- }
-
retval = zfcp_fsf_req_create(adapter, fsf_command, req_flags,
NULL, &lock_flags, &fsf_req);
if (retval < 0) {
@@ -4367,12 +4349,8 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter,
} else
sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY;
- init_timer(timer);
- timer->function = zfcp_fsf_request_timeout_handler;
- timer->data = (unsigned long) adapter;
- timer->expires = ZFCP_FSF_REQUEST_TIMEOUT;
-
- retval = zfcp_fsf_req_send(fsf_req, timer);
+ zfcp_fsf_start_timer(fsf_req, ZFCP_FSF_REQUEST_TIMEOUT);
+ retval = zfcp_fsf_req_send(fsf_req);
if (retval < 0) {
ZFCP_LOG_INFO("initiation of cfdc up/download failed"
"(adapter %s)\n",
@@ -4392,15 +4370,12 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter,
fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
*fsf_req_ptr = fsf_req;
- del_timer_sync(timer);
- goto free_timer;
+ goto out;
free_fsf_req:
zfcp_fsf_req_free(fsf_req);
unlock_queue_lock:
write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags);
- free_timer:
- kfree(timer);
out:
return retval;
}
@@ -4592,12 +4567,14 @@ static inline void
zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
{
if (likely(fsf_req->qtcb != NULL)) {
- fsf_req->qtcb->prefix.req_seq_no = fsf_req->adapter->fsf_req_seq_no;
- fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req;
+ fsf_req->qtcb->prefix.req_seq_no =
+ fsf_req->adapter->fsf_req_seq_no;
+ fsf_req->qtcb->prefix.req_id = fsf_req->req_id;
fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION;
- fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_req->fsf_command];
+ fsf_req->qtcb->prefix.qtcb_type =
+ fsf_qtcb_type[fsf_req->fsf_command];
fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION;
- fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req;
+ fsf_req->qtcb->header.req_handle = fsf_req->req_id;
fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command;
}
}
@@ -4668,8 +4645,15 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
fsf_req->adapter = adapter;
fsf_req->fsf_command = fsf_cmd;
+ INIT_LIST_HEAD(&fsf_req->list);
+
+ /* this is serialized (we are holding req_queue-lock of adapter */
+ if (adapter->req_no == 0)
+ adapter->req_no++;
+ fsf_req->req_id = adapter->req_no++;
- zfcp_fsf_req_qtcb_init(fsf_req);
+ init_timer(&fsf_req->timer);
+ zfcp_fsf_req_qtcb_init(fsf_req);
/* initialize waitqueue which may be used to wait on
this request completion */
@@ -4707,7 +4691,7 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0);
/* setup common SBALE fields */
- sbale[0].addr = fsf_req;
+ sbale[0].addr = (void *) fsf_req->req_id;
sbale[0].flags |= SBAL_FLAGS0_COMMAND;
if (likely(fsf_req->qtcb != NULL)) {
sbale[1].addr = (void *) fsf_req->qtcb;
@@ -4739,15 +4723,14 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags,
* returns: 0 - request transfer succesfully started
* !0 - start of request transfer failed
*/
-static int
-zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
+static int zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req)
{
struct zfcp_adapter *adapter;
struct zfcp_qdio_queue *req_queue;
volatile struct qdio_buffer_element *sbale;
int inc_seq_no;
int new_distance_from_int;
- unsigned long flags;
+ u64 dbg_tmp[2];
int retval = 0;
adapter = fsf_req->adapter;
@@ -4761,19 +4744,13 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr,
sbale[1].length);
- /* put allocated FSF request at list tail */
- spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
- list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head);
- spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
+ /* put allocated FSF request into hash table */
+ spin_lock(&adapter->req_list_lock);
+ zfcp_reqlist_add(adapter, fsf_req);
+ spin_unlock(&adapter->req_list_lock);
inc_seq_no = (fsf_req->qtcb != NULL);
- /* figure out expiration time of timeout and start timeout */
- if (unlikely(timer)) {
- timer->expires += jiffies;
- add_timer(timer);
- }
-
ZFCP_LOG_TRACE("request queue of adapter %s: "
"next free SBAL is %i, %i free SBALs\n",
zfcp_get_busid_by_adapter(adapter),
@@ -4803,31 +4780,25 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
QDIO_FLAG_SYNC_OUTPUT,
0, fsf_req->sbal_first, fsf_req->sbal_number, NULL);
+ dbg_tmp[0] = (unsigned long) sbale[0].addr;
+ dbg_tmp[1] = (u64) retval;
+ debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
+
if (unlikely(retval)) {
/* Queues are down..... */
retval = -EIO;
- /*
- * FIXME(potential race):
- * timer might be expired (absolutely unlikely)
- */
- if (timer)
- del_timer(timer);
- spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
- list_del(&fsf_req->list);
- spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
- /*
- * adjust the number of free SBALs in request queue as well as
- * position of first one
- */
+ del_timer(&fsf_req->timer);
+ spin_lock(&adapter->req_list_lock);
+ zfcp_reqlist_remove(adapter, fsf_req->req_id);
+ spin_unlock(&adapter->req_list_lock);
+ /* undo changes in request queue made for this request */
zfcp_qdio_zero_sbals(req_queue->buffer,
fsf_req->sbal_first, fsf_req->sbal_number);
atomic_add(fsf_req->sbal_number, &req_queue->free_count);
- req_queue->free_index -= fsf_req->sbal_number; /* increase */
+ req_queue->free_index -= fsf_req->sbal_number;
req_queue->free_index += QDIO_MAX_BUFFERS_PER_Q;
req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */
- ZFCP_LOG_DEBUG
- ("error: do_QDIO failed. Buffers could not be enqueued "
- "to request queue.\n");
+ zfcp_erp_adapter_reopen(adapter, 0);
} else {
req_queue->distance_from_int = new_distance_from_int;
/*
@@ -4843,7 +4814,7 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer)
adapter->fsf_req_seq_no++;
/* count FSF requests pending */
- atomic_inc(&adapter->fsf_reqs_active);
+ atomic_inc(&adapter->reqs_active);
}
return retval;
}
diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c
index 345a191926a..dbd9f48e863 100644
--- a/drivers/s390/scsi/zfcp_qdio.c
+++ b/drivers/s390/scsi/zfcp_qdio.c
@@ -282,6 +282,37 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device,
return;
}
+/**
+ * zfcp_qdio_reqid_check - checks for valid reqids or unsolicited status
+ */
+static int zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
+ unsigned long req_id)
+{
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long flags;
+
+ debug_long_event(adapter->erp_dbf, 4, req_id);
+
+ spin_lock_irqsave(&adapter->req_list_lock, flags);
+ fsf_req = zfcp_reqlist_ismember(adapter, req_id);
+
+ if (!fsf_req) {
+ spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+ ZFCP_LOG_NORMAL("error: unknown request id (%ld).\n", req_id);
+ zfcp_erp_adapter_reopen(adapter, 0);
+ return -EINVAL;
+ }
+
+ zfcp_reqlist_remove(adapter, req_id);
+ atomic_dec(&adapter->reqs_active);
+ spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+
+ /* finish the FSF request */
+ zfcp_fsf_req_complete(fsf_req);
+
+ return 0;
+}
+
/*
* function: zfcp_qdio_response_handler
*
@@ -344,7 +375,7 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
/* look for QDIO request identifiers in SB */
buffere = &buffer->element[buffere_index];
retval = zfcp_qdio_reqid_check(adapter,
- (void *) buffere->addr);
+ (unsigned long) buffere->addr);
if (retval) {
ZFCP_LOG_NORMAL("bug: unexpected inbound "
@@ -415,51 +446,6 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device,
return;
}
-/*
- * function: zfcp_qdio_reqid_check
- *
- * purpose: checks for valid reqids or unsolicited status
- *
- * returns: 0 - valid request id or unsolicited status
- * !0 - otherwise
- */
-int
-zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
-{
- struct zfcp_fsf_req *fsf_req;
-
- /* invalid (per convention used in this driver) */
- if (unlikely(!sbale_addr)) {
- ZFCP_LOG_NORMAL("bug: invalid reqid\n");
- return -EINVAL;
- }
-
- /* valid request id and thus (hopefully :) valid fsf_req address */
- fsf_req = (struct zfcp_fsf_req *) sbale_addr;
-
- /* serialize with zfcp_fsf_req_dismiss_all */
- spin_lock(&adapter->fsf_req_list_lock);
- if (list_empty(&adapter->fsf_req_list_head)) {
- spin_unlock(&adapter->fsf_req_list_lock);
- return 0;
- }
- list_del(&fsf_req->list);
- atomic_dec(&adapter->fsf_reqs_active);
- spin_unlock(&adapter->fsf_req_list_lock);
-
- if (unlikely(adapter != fsf_req->adapter)) {
- ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, "
- "fsf_req->adapter=%p, adapter=%p)\n",
- fsf_req, fsf_req->adapter, adapter);
- return -EINVAL;
- }
-
- /* finish the FSF request */
- zfcp_fsf_req_complete(fsf_req);
-
- return 0;
-}
-
/**
* zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue
* @queue: queue from which SBALE should be returned
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 46e14f22ec1..7cafa34e4c7 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -30,7 +30,6 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *,
void (*done) (struct scsi_cmnd *));
static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *);
-static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *);
static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *);
static int zfcp_task_management_function(struct zfcp_unit *, u8,
struct scsi_cmnd *);
@@ -40,37 +39,27 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int,
static struct device_attribute *zfcp_sysfs_sdev_attrs[];
-struct scsi_transport_template *zfcp_transport_template;
-
struct zfcp_data zfcp_data = {
.scsi_host_template = {
- name: ZFCP_NAME,
- proc_name: "zfcp",
- proc_info: NULL,
- detect: NULL,
- slave_alloc: zfcp_scsi_slave_alloc,
- slave_configure: zfcp_scsi_slave_configure,
- slave_destroy: zfcp_scsi_slave_destroy,
- queuecommand: zfcp_scsi_queuecommand,
- eh_abort_handler: zfcp_scsi_eh_abort_handler,
- eh_device_reset_handler: zfcp_scsi_eh_device_reset_handler,
- eh_bus_reset_handler: zfcp_scsi_eh_bus_reset_handler,
- eh_host_reset_handler: zfcp_scsi_eh_host_reset_handler,
- /* FIXME(openfcp): Tune */
- can_queue: 4096,
- this_id: -1,
- /*
- * FIXME:
- * one less? can zfcp_create_sbale cope with it?
- */
- sg_tablesize: ZFCP_MAX_SBALES_PER_REQ,
- cmd_per_lun: 1,
- unchecked_isa_dma: 0,
- use_clustering: 1,
- sdev_attrs: zfcp_sysfs_sdev_attrs,
+ .name = ZFCP_NAME,
+ .module = THIS_MODULE,
+ .proc_name = "zfcp",
+ .slave_alloc = zfcp_scsi_slave_alloc,
+ .slave_configure = zfcp_scsi_slave_configure,
+ .slave_destroy = zfcp_scsi_slave_destroy,
+ .queuecommand = zfcp_scsi_queuecommand,
+ .eh_abort_handler = zfcp_scsi_eh_abort_handler,
+ .eh_device_reset_handler = zfcp_scsi_eh_device_reset_handler,
+ .eh_bus_reset_handler = zfcp_scsi_eh_host_reset_handler,
+ .eh_host_reset_handler = zfcp_scsi_eh_host_reset_handler,
+ .can_queue = 4096,
+ .this_id = -1,
+ .sg_tablesize = ZFCP_MAX_SBALES_PER_REQ,
+ .cmd_per_lun = 1,
+ .use_clustering = 1,
+ .sdev_attrs = zfcp_sysfs_sdev_attrs,
},
.driver_version = ZFCP_VERSION,
- /* rest initialised with zeros */
};
/* Find start of Response Information in FCP response unit*/
@@ -177,8 +166,14 @@ zfcp_scsi_slave_alloc(struct scsi_device *sdp)
return retval;
}
-static void
-zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
+/**
+ * zfcp_scsi_slave_destroy - called when scsi device is removed
+ *
+ * Remove reference to associated scsi device for an zfcp_unit.
+ * Mark zfcp_unit as failed. The scsi device might be deleted via sysfs
+ * or a scan for this device might have failed.
+ */
+static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
{
struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata;
@@ -186,6 +181,7 @@ zfcp_scsi_slave_destroy(struct scsi_device *sdpnt)
atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status);
sdpnt->hostdata = NULL;
unit->device = NULL;
+ zfcp_erp_unit_failed(unit);
zfcp_unit_put(unit);
} else {
ZFCP_LOG_NORMAL("bug: no unit associated with SCSI device at "
@@ -235,7 +231,7 @@ zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result)
*/
int
zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
- struct scsi_cmnd *scpnt, struct timer_list *timer)
+ struct scsi_cmnd *scpnt, int use_timer)
{
int tmp;
int retval;
@@ -271,7 +267,7 @@ zfcp_scsi_command_async(struct zfcp_adapter *adapter, struct zfcp_unit *unit,
goto out;
}
- tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, timer,
+ tmp = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, use_timer,
ZFCP_REQ_AUTO_CLEANUP);
if (unlikely(tmp < 0)) {
@@ -295,21 +291,22 @@ zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
* zfcp_scsi_command_sync - send a SCSI command and wait for completion
* @unit: unit where command is sent to
* @scpnt: scsi command to be sent
- * @timer: timer to be started if request is successfully initiated
+ * @use_timer: indicates whether timer should be setup or not
* Return: 0
*
* Errors are indicated in scpnt->result
*/
int
zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
- struct timer_list *timer)
+ int use_timer)
{
int ret;
DECLARE_COMPLETION(wait);
scpnt->SCp.ptr = (void *) &wait; /* silent re-use */
scpnt->scsi_done = zfcp_scsi_command_sync_handler;
- ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt, timer);
+ ret = zfcp_scsi_command_async(unit->port->adapter, unit, scpnt,
+ use_timer);
if (ret == 0)
wait_for_completion(&wait);
@@ -345,7 +342,7 @@ zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0];
unit = (struct zfcp_unit *) scpnt->device->hostdata;
- return zfcp_scsi_command_async(adapter, unit, scpnt, NULL);
+ return zfcp_scsi_command_async(adapter, unit, scpnt, 0);
}
static struct zfcp_unit *
@@ -382,16 +379,15 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
* will handle late commands. (Usually, the normal completion of late
* commands is ignored with respect to the running abort operation.)
*/
-int
-zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
{
struct Scsi_Host *scsi_host;
struct zfcp_adapter *adapter;
struct zfcp_unit *unit;
- int retval = SUCCESS;
- struct zfcp_fsf_req *new_fsf_req = NULL;
- struct zfcp_fsf_req *old_fsf_req;
+ struct zfcp_fsf_req *fsf_req;
unsigned long flags;
+ unsigned long old_req_id;
+ int retval = SUCCESS;
scsi_host = scpnt->device->host;
adapter = (struct zfcp_adapter *) scsi_host->hostdata[0];
@@ -403,55 +399,47 @@ zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
/* avoid race condition between late normal completion and abort */
write_lock_irqsave(&adapter->abort_lock, flags);
- /*
- * Check whether command has just completed and can not be aborted.
- * Even if the command has just been completed late, we can access
- * scpnt since the SCSI stack does not release it at least until
- * this routine returns. (scpnt is parameter passed to this routine
- * and must not disappear during abort even on late completion.)
- */
- old_fsf_req = (struct zfcp_fsf_req *) scpnt->host_scribble;
- if (!old_fsf_req) {
+ /* Check whether corresponding fsf_req is still pending */
+ spin_lock(&adapter->req_list_lock);
+ fsf_req = zfcp_reqlist_ismember(adapter, (unsigned long)
+ scpnt->host_scribble);
+ spin_unlock(&adapter->req_list_lock);
+ if (!fsf_req) {
write_unlock_irqrestore(&adapter->abort_lock, flags);
- zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, NULL);
+ zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, NULL, 0);
retval = SUCCESS;
goto out;
}
- old_fsf_req->data = 0;
- old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
+ fsf_req->data = 0;
+ fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING;
+ old_req_id = fsf_req->req_id;
- /* don't access old_fsf_req after releasing the abort_lock */
+ /* don't access old fsf_req after releasing the abort_lock */
write_unlock_irqrestore(&adapter->abort_lock, flags);
- /* call FSF routine which does the abort */
- new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req,
- adapter, unit, 0);
- if (!new_fsf_req) {
+
+ fsf_req = zfcp_fsf_abort_fcp_command(old_req_id, adapter, unit, 0);
+ if (!fsf_req) {
ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n");
zfcp_scsi_dbf_event_abort("nres", adapter, scpnt, NULL,
- old_fsf_req);
+ old_req_id);
retval = FAILED;
goto out;
}
- /* wait for completion of abort */
- __wait_event(new_fsf_req->completion_wq,
- new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
+ __wait_event(fsf_req->completion_wq,
+ fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED);
- /* status should be valid since signals were not permitted */
- if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
- zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, new_fsf_req,
- NULL);
+ if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) {
+ zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, fsf_req, 0);
retval = SUCCESS;
- } else if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
- zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, new_fsf_req,
- NULL);
+ } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) {
+ zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, fsf_req, 0);
retval = SUCCESS;
} else {
- zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, new_fsf_req,
- NULL);
+ zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, fsf_req, 0);
retval = FAILED;
}
- zfcp_fsf_req_free(new_fsf_req);
+ zfcp_fsf_req_free(fsf_req);
out:
return retval;
}
@@ -550,33 +538,19 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
}
/**
- * zfcp_scsi_eh_bus_reset_handler - reset bus (reopen adapter)
+ * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
*/
-int
-zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt)
+int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
{
- struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
- struct zfcp_adapter *adapter = unit->port->adapter;
-
- ZFCP_LOG_NORMAL("bus reset because of problems with "
- "unit 0x%016Lx\n", unit->fcp_lun);
- zfcp_erp_adapter_reopen(adapter, 0);
- zfcp_erp_wait(adapter);
-
- return SUCCESS;
-}
+ struct zfcp_unit *unit;
+ struct zfcp_adapter *adapter;
-/**
- * zfcp_scsi_eh_host_reset_handler - reset host (reopen adapter)
- */
-int
-zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
-{
- struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata;
- struct zfcp_adapter *adapter = unit->port->adapter;
+ unit = (struct zfcp_unit*) scpnt->device->hostdata;
+ adapter = unit->port->adapter;
- ZFCP_LOG_NORMAL("host reset because of problems with "
+ ZFCP_LOG_NORMAL("host/bus reset because of problems with "
"unit 0x%016Lx\n", unit->fcp_lun);
+
zfcp_erp_adapter_reopen(adapter, 0);
zfcp_erp_wait(adapter);
@@ -607,7 +581,7 @@ zfcp_adapter_scsi_register(struct zfcp_adapter *adapter)
adapter->scsi_host->max_channel = 0;
adapter->scsi_host->unique_id = unique_id++; /* FIXME */
adapter->scsi_host->max_cmd_len = ZFCP_MAX_SCSI_CMND_LENGTH;
- adapter->scsi_host->transportt = zfcp_transport_template;
+ adapter->scsi_host->transportt = zfcp_data.scsi_transport_template;
/*
* save a pointer to our own adapter data structure within
@@ -648,16 +622,6 @@ zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter)
return;
}
-
-void
-zfcp_fsf_start_scsi_er_timer(struct zfcp_adapter *adapter)
-{
- adapter->scsi_er_timer.function = zfcp_fsf_scsi_er_timeout_handler;
- adapter->scsi_er_timer.data = (unsigned long) adapter;
- adapter->scsi_er_timer.expires = jiffies + ZFCP_SCSI_ER_TIMEOUT;
- add_timer(&adapter->scsi_er_timer);
-}
-
/*
* Support functions for FC transport class
*/
diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c
index 66da840c931..1e788e815ce 100644
--- a/drivers/s390/sysinfo.c
+++ b/drivers/s390/sysinfo.c
@@ -5,26 +5,24 @@
* Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <asm/ebcdic.h>
-struct sysinfo_1_1_1
-{
+struct sysinfo_1_1_1 {
char reserved_0[32];
char manufacturer[16];
char type[4];
char reserved_1[12];
- char model[16];
+ char model_capacity[16];
char sequence[16];
char plant[4];
+ char model[16];
};
-struct sysinfo_1_2_1
-{
+struct sysinfo_1_2_1 {
char reserved_0[80];
char sequence[16];
char plant[4];
@@ -32,9 +30,12 @@ struct sysinfo_1_2_1
unsigned short cpu_address;
};
-struct sysinfo_1_2_2
-{
- char reserved_0[32];
+struct sysinfo_1_2_2 {
+ char format;
+ char reserved_0[1];
+ unsigned short acc_offset;
+ char reserved_1[24];
+ unsigned int secondary_capability;
unsigned int capability;
unsigned short cpus_total;
unsigned short cpus_configured;
@@ -43,8 +44,12 @@ struct sysinfo_1_2_2
unsigned short adjustment[0];
};
-struct sysinfo_2_2_1
-{
+struct sysinfo_1_2_2_extension {
+ unsigned int alt_capability;
+ unsigned short alt_adjustment[0];
+};
+
+struct sysinfo_2_2_1 {
char reserved_0[80];
char sequence[16];
char plant[4];
@@ -52,15 +57,11 @@ struct sysinfo_2_2_1
unsigned short cpu_address;
};
-struct sysinfo_2_2_2
-{
+struct sysinfo_2_2_2 {
char reserved_0[32];
unsigned short lpar_number;
char reserved_1;
unsigned char characteristics;
- #define LPAR_CHAR_DEDICATED (1 << 7)
- #define LPAR_CHAR_SHARED (1 << 6)
- #define LPAR_CHAR_LIMITED (1 << 5)
unsigned short cpus_total;
unsigned short cpus_configured;
unsigned short cpus_standby;
@@ -72,12 +73,14 @@ struct sysinfo_2_2_2
unsigned short cpus_shared;
};
-struct sysinfo_3_2_2
-{
+#define LPAR_CHAR_DEDICATED (1 << 7)
+#define LPAR_CHAR_SHARED (1 << 6)
+#define LPAR_CHAR_LIMITED (1 << 5)
+
+struct sysinfo_3_2_2 {
char reserved_0[31];
unsigned char count;
- struct
- {
+ struct {
char reserved_0[4];
unsigned short cpus_total;
unsigned short cpus_configured;
@@ -91,136 +94,223 @@ struct sysinfo_3_2_2
} vm[8];
};
-union s390_sysinfo
+static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
{
- struct sysinfo_1_1_1 sysinfo_1_1_1;
- struct sysinfo_1_2_1 sysinfo_1_2_1;
- struct sysinfo_1_2_2 sysinfo_1_2_2;
- struct sysinfo_2_2_1 sysinfo_2_2_1;
- struct sysinfo_2_2_2 sysinfo_2_2_2;
- struct sysinfo_3_2_2 sysinfo_3_2_2;
-};
-
-static inline int stsi (void *sysinfo,
- int fc, int sel1, int sel2)
-{
- int cc, retv;
-
-#ifndef CONFIG_64BIT
- __asm__ __volatile__ ( "lr\t0,%2\n"
- "\tlr\t1,%3\n"
- "\tstsi\t0(%4)\n"
- "0:\tipm\t%0\n"
- "\tsrl\t%0,28\n"
- "1:lr\t%1,0\n"
- ".section .fixup,\"ax\"\n"
- "2:\tlhi\t%0,3\n"
- "\tbras\t1,3f\n"
- "\t.long 1b\n"
- "3:\tl\t1,0(1)\n"
- "\tbr\t1\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- "\t.align 4\n"
- "\t.long 0b,2b\n"
- ".previous\n"
- : "=d" (cc), "=d" (retv)
- : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo)
- : "cc", "memory", "0", "1" );
-#else
- __asm__ __volatile__ ( "lr\t0,%2\n"
- "lr\t1,%3\n"
- "\tstsi\t0(%4)\n"
- "0:\tipm\t%0\n"
- "\tsrl\t%0,28\n"
- "1:lr\t%1,0\n"
- ".section .fixup,\"ax\"\n"
- "2:\tlhi\t%0,3\n"
- "\tjg\t1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- "\t.align 8\n"
- "\t.quad 0b,2b\n"
- ".previous\n"
- : "=d" (cc), "=d" (retv)
- : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo)
- : "cc", "memory", "0", "1" );
-#endif
-
- return cc? -1 : retv;
+ register int r0 asm("0") = (fc << 28) | sel1;
+ register int r1 asm("1") = sel2;
+
+ asm volatile(
+ " stsi 0(%2)\n"
+ "0: jz 2f\n"
+ "1: lhi %0,%3\n"
+ "2:\n"
+ EX_TABLE(0b,1b)
+ : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS)
+ : "cc", "memory" );
+ return r0;
}
-static inline int stsi_0 (void)
+static inline int stsi_0(void)
{
int rc = stsi (NULL, 0, 0, 0);
- return rc == -1 ? rc : (((unsigned int)rc) >> 28);
+ return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
}
-static inline int stsi_1_1_1 (struct sysinfo_1_1_1 *info)
+static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
{
- int rc = stsi (info, 1, 1, 1);
- if (rc != -1)
- {
- EBCASC (info->manufacturer, sizeof(info->manufacturer));
- EBCASC (info->type, sizeof(info->type));
- EBCASC (info->model, sizeof(info->model));
- EBCASC (info->sequence, sizeof(info->sequence));
- EBCASC (info->plant, sizeof(info->plant));
- }
- return rc == -1 ? rc : 0;
+ if (stsi(info, 1, 1, 1) == -ENOSYS)
+ return len;
+
+ EBCASC(info->manufacturer, sizeof(info->manufacturer));
+ EBCASC(info->type, sizeof(info->type));
+ EBCASC(info->model, sizeof(info->model));
+ EBCASC(info->sequence, sizeof(info->sequence));
+ EBCASC(info->plant, sizeof(info->plant));
+ EBCASC(info->model_capacity, sizeof(info->model_capacity));
+ len += sprintf(page + len, "Manufacturer: %-16.16s\n",
+ info->manufacturer);
+ len += sprintf(page + len, "Type: %-4.4s\n",
+ info->type);
+ if (info->model[0] != '\0')
+ /*
+ * Sigh: the model field has been renamed with System z9
+ * to model_capacity and a new model field has been added
+ * after the plant field. To avoid confusing older programs
+ * the "Model:" prints "model_capacity model" or just
+ * "model_capacity" if the model string is empty .
+ */
+ len += sprintf(page + len,
+ "Model: %-16.16s %-16.16s\n",
+ info->model_capacity, info->model);
+ else
+ len += sprintf(page + len, "Model: %-16.16s\n",
+ info->model_capacity);
+ len += sprintf(page + len, "Sequence Code: %-16.16s\n",
+ info->sequence);
+ len += sprintf(page + len, "Plant: %-4.4s\n",
+ info->plant);
+ len += sprintf(page + len, "Model Capacity: %-16.16s\n",
+ info->model_capacity);
+ return len;
}
-static inline int stsi_1_2_1 (struct sysinfo_1_2_1 *info)
+#if 0 /* Currently unused */
+static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len)
{
- int rc = stsi (info, 1, 2, 1);
- if (rc != -1)
- {
- EBCASC (info->sequence, sizeof(info->sequence));
- EBCASC (info->plant, sizeof(info->plant));
- }
- return rc == -1 ? rc : 0;
+ if (stsi(info, 1, 2, 1) == -ENOSYS)
+ return len;
+
+ len += sprintf(page + len, "\n");
+ EBCASC(info->sequence, sizeof(info->sequence));
+ EBCASC(info->plant, sizeof(info->plant));
+ len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n",
+ info->sequence);
+ len += sprintf(page + len, "Plant of CPU: %-16.16s\n",
+ info->plant);
+ return len;
}
+#endif
-static inline int stsi_1_2_2 (struct sysinfo_1_2_2 *info)
+static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
{
- int rc = stsi (info, 1, 2, 2);
- return rc == -1 ? rc : 0;
+ struct sysinfo_1_2_2_extension *ext;
+ int i;
+
+ if (stsi(info, 1, 2, 2) == -ENOSYS)
+ return len;
+ ext = (struct sysinfo_1_2_2_extension *)
+ ((unsigned long) info + info->acc_offset);
+
+ len += sprintf(page + len, "\n");
+ len += sprintf(page + len, "CPUs Total: %d\n",
+ info->cpus_total);
+ len += sprintf(page + len, "CPUs Configured: %d\n",
+ info->cpus_configured);
+ len += sprintf(page + len, "CPUs Standby: %d\n",
+ info->cpus_standby);
+ len += sprintf(page + len, "CPUs Reserved: %d\n",
+ info->cpus_reserved);
+
+ if (info->format == 1) {
+ /*
+ * Sigh 2. According to the specification the alternate
+ * capability field is a 32 bit floating point number
+ * if the higher order 8 bits are not zero. Printing
+ * a floating point number in the kernel is a no-no,
+ * always print the number as 32 bit unsigned integer.
+ * The user-space needs to know about the stange
+ * encoding of the alternate cpu capability.
+ */
+ len += sprintf(page + len, "Capability: %u %u\n",
+ info->capability, ext->alt_capability);
+ for (i = 2; i <= info->cpus_total; i++)
+ len += sprintf(page + len,
+ "Adjustment %02d-way: %u %u\n",
+ i, info->adjustment[i-2],
+ ext->alt_adjustment[i-2]);
+
+ } else {
+ len += sprintf(page + len, "Capability: %u\n",
+ info->capability);
+ for (i = 2; i <= info->cpus_total; i++)
+ len += sprintf(page + len,
+ "Adjustment %02d-way: %u\n",
+ i, info->adjustment[i-2]);
+ }
+
+ if (info->secondary_capability != 0)
+ len += sprintf(page + len, "Secondary Capability: %d\n",
+ info->secondary_capability);
+
+ return len;
}
-static inline int stsi_2_2_1 (struct sysinfo_2_2_1 *info)
+#if 0 /* Currently unused */
+static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len)
{
- int rc = stsi (info, 2, 2, 1);
- if (rc != -1)
- {
- EBCASC (info->sequence, sizeof(info->sequence));
- EBCASC (info->plant, sizeof(info->plant));
- }
- return rc == -1 ? rc : 0;
+ if (stsi(info, 2, 2, 1) == -ENOSYS)
+ return len;
+
+ len += sprintf(page + len, "\n");
+ EBCASC (info->sequence, sizeof(info->sequence));
+ EBCASC (info->plant, sizeof(info->plant));
+ len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n",
+ info->sequence);
+ len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n",
+ info->plant);
+ return len;
}
+#endif
-static inline int stsi_2_2_2 (struct sysinfo_2_2_2 *info)
+static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
{
- int rc = stsi (info, 2, 2, 2);
- if (rc != -1)
- {
- EBCASC (info->name, sizeof(info->name));
- }
- return rc == -1 ? rc : 0;
+ if (stsi(info, 2, 2, 2) == -ENOSYS)
+ return len;
+
+ EBCASC (info->name, sizeof(info->name));
+
+ len += sprintf(page + len, "\n");
+ len += sprintf(page + len, "LPAR Number: %d\n",
+ info->lpar_number);
+
+ len += sprintf(page + len, "LPAR Characteristics: ");
+ if (info->characteristics & LPAR_CHAR_DEDICATED)
+ len += sprintf(page + len, "Dedicated ");
+ if (info->characteristics & LPAR_CHAR_SHARED)
+ len += sprintf(page + len, "Shared ");
+ if (info->characteristics & LPAR_CHAR_LIMITED)
+ len += sprintf(page + len, "Limited ");
+ len += sprintf(page + len, "\n");
+
+ len += sprintf(page + len, "LPAR Name: %-8.8s\n",
+ info->name);
+
+ len += sprintf(page + len, "LPAR Adjustment: %d\n",
+ info->caf);
+
+ len += sprintf(page + len, "LPAR CPUs Total: %d\n",
+ info->cpus_total);
+ len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
+ info->cpus_configured);
+ len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
+ info->cpus_standby);
+ len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
+ info->cpus_reserved);
+ len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
+ info->cpus_dedicated);
+ len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
+ info->cpus_shared);
+ return len;
}
-static inline int stsi_3_2_2 (struct sysinfo_3_2_2 *info)
+static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
{
- int rc = stsi (info, 3, 2, 2);
- if (rc != -1)
- {
- int i;
- for (i = 0; i < info->count; i++)
- {
- EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
- EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
- }
+ int i;
+
+ if (stsi(info, 3, 2, 2) == -ENOSYS)
+ return len;
+ for (i = 0; i < info->count; i++) {
+ EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
+ EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
+ len += sprintf(page + len, "\n");
+ len += sprintf(page + len, "VM%02d Name: %-8.8s\n",
+ i, info->vm[i].name);
+ len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
+ i, info->vm[i].cpi);
+
+ len += sprintf(page + len, "VM%02d Adjustment: %d\n",
+ i, info->vm[i].caf);
+
+ len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
+ i, info->vm[i].cpus_total);
+ len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
+ i, info->vm[i].cpus_configured);
+ len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
+ i, info->vm[i].cpus_standby);
+ len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
+ i, info->vm[i].cpus_reserved);
}
- return rc == -1 ? rc : 0;
+ return len;
}
@@ -228,118 +318,34 @@ static int proc_read_sysinfo(char *page, char **start,
off_t off, int count,
int *eof, void *data)
{
- unsigned long info_page = get_zeroed_page (GFP_KERNEL);
- union s390_sysinfo *info = (union s390_sysinfo *) info_page;
- int len = 0;
- int level;
- int i;
+ unsigned long info = get_zeroed_page (GFP_KERNEL);
+ int level, len;
if (!info)
return 0;
- level = stsi_0 ();
-
- if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0)
- {
- len += sprintf (page+len, "Manufacturer: %-16.16s\n",
- info->sysinfo_1_1_1.manufacturer);
- len += sprintf (page+len, "Type: %-4.4s\n",
- info->sysinfo_1_1_1.type);
- len += sprintf (page+len, "Model: %-16.16s\n",
- info->sysinfo_1_1_1.model);
- len += sprintf (page+len, "Sequence Code: %-16.16s\n",
- info->sysinfo_1_1_1.sequence);
- len += sprintf (page+len, "Plant: %-4.4s\n",
- info->sysinfo_1_1_1.plant);
- }
-
- if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0)
- {
- len += sprintf (page+len, "\n");
- len += sprintf (page+len, "CPUs Total: %d\n",
- info->sysinfo_1_2_2.cpus_total);
- len += sprintf (page+len, "CPUs Configured: %d\n",
- info->sysinfo_1_2_2.cpus_configured);
- len += sprintf (page+len, "CPUs Standby: %d\n",
- info->sysinfo_1_2_2.cpus_standby);
- len += sprintf (page+len, "CPUs Reserved: %d\n",
- info->sysinfo_1_2_2.cpus_reserved);
-
- len += sprintf (page+len, "Capability: %d\n",
- info->sysinfo_1_2_2.capability);
+ len = 0;
+ level = stsi_0();
+ if (level >= 1)
+ len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
- for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++)
- len += sprintf (page+len, "Adjustment %02d-way: %d\n",
- i, info->sysinfo_1_2_2.adjustment[i-2]);
- }
+ if (level >= 1)
+ len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
- if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0)
- {
- len += sprintf (page+len, "\n");
- len += sprintf (page+len, "LPAR Number: %d\n",
- info->sysinfo_2_2_2.lpar_number);
-
- len += sprintf (page+len, "LPAR Characteristics: ");
- if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED)
- len += sprintf (page+len, "Dedicated ");
- if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED)
- len += sprintf (page+len, "Shared ");
- if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED)
- len += sprintf (page+len, "Limited ");
- len += sprintf (page+len, "\n");
-
- len += sprintf (page+len, "LPAR Name: %-8.8s\n",
- info->sysinfo_2_2_2.name);
-
- len += sprintf (page+len, "LPAR Adjustment: %d\n",
- info->sysinfo_2_2_2.caf);
-
- len += sprintf (page+len, "LPAR CPUs Total: %d\n",
- info->sysinfo_2_2_2.cpus_total);
- len += sprintf (page+len, "LPAR CPUs Configured: %d\n",
- info->sysinfo_2_2_2.cpus_configured);
- len += sprintf (page+len, "LPAR CPUs Standby: %d\n",
- info->sysinfo_2_2_2.cpus_standby);
- len += sprintf (page+len, "LPAR CPUs Reserved: %d\n",
- info->sysinfo_2_2_2.cpus_reserved);
- len += sprintf (page+len, "LPAR CPUs Dedicated: %d\n",
- info->sysinfo_2_2_2.cpus_dedicated);
- len += sprintf (page+len, "LPAR CPUs Shared: %d\n",
- info->sysinfo_2_2_2.cpus_shared);
- }
+ if (level >= 2)
+ len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
- if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0)
- {
- for (i = 0; i < info->sysinfo_3_2_2.count; i++)
- {
- len += sprintf (page+len, "\n");
- len += sprintf (page+len, "VM%02d Name: %-8.8s\n",
- i, info->sysinfo_3_2_2.vm[i].name);
- len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n",
- i, info->sysinfo_3_2_2.vm[i].cpi);
-
- len += sprintf (page+len, "VM%02d Adjustment: %d\n",
- i, info->sysinfo_3_2_2.vm[i].caf);
-
- len += sprintf (page+len, "VM%02d CPUs Total: %d\n",
- i, info->sysinfo_3_2_2.vm[i].cpus_total);
- len += sprintf (page+len, "VM%02d CPUs Configured: %d\n",
- i, info->sysinfo_3_2_2.vm[i].cpus_configured);
- len += sprintf (page+len, "VM%02d CPUs Standby: %d\n",
- i, info->sysinfo_3_2_2.vm[i].cpus_standby);
- len += sprintf (page+len, "VM%02d CPUs Reserved: %d\n",
- i, info->sysinfo_3_2_2.vm[i].cpus_reserved);
- }
- }
+ if (level >= 3)
+ len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
- free_page (info_page);
+ free_page (info);
return len;
}
static __init int create_proc_sysinfo(void)
{
- create_proc_read_entry ("sysinfo", 0444, NULL,
- proc_read_sysinfo, NULL);
+ create_proc_read_entry("sysinfo", 0444, NULL,
+ proc_read_sysinfo, NULL);
return 0;
}
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 015db40ad8a..4fdb2c93221 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -337,19 +337,19 @@ static int aurora_probe(void)
printk("intr pri %d\n", grrr);
#endif
if ((bp->irq=irqs[bn]) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+ !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
free_irq(bp->irq|0x30, bp);
} else
if ((bp->irq=prom_getint(sdev->prom_node, "bintr")) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+ !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
free_irq(bp->irq|0x30, bp);
} else
if ((bp->irq=prom_getint(sdev->prom_node, "intr")) && valid_irq(bp->irq) &&
- !request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+ !request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
free_irq(bp->irq|0x30, bp);
} else
for(grrr=0;grrr<TYPE_1_IRQS;grrr++) {
- if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ, "sio16", bp)) {
+ if ((bp->irq=type_1_irq[grrr])&&!request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED, "sio16", bp)) {
free_irq(bp->irq|0x30, bp);
break;
} else {
@@ -909,14 +909,14 @@ static int aurora_setup_board(struct Aurora_board * bp)
#ifdef AURORA_ALLIRQ
int i;
for (i = 0; i < AURORA_ALLIRQ; i++) {
- error = request_irq(allirq[i]|0x30, aurora_interrupt, SA_SHIRQ,
+ error = request_irq(allirq[i]|0x30, aurora_interrupt, IRQF_SHARED,
"sio16", bp);
if (error)
printk(KERN_ERR "IRQ%d request error %d\n",
allirq[i], error);
}
#else
- error = request_irq(bp->irq|0x30, aurora_interrupt, SA_SHIRQ,
+ error = request_irq(bp->irq|0x30, aurora_interrupt, IRQF_SHARED,
"sio16", bp);
if (error) {
printk(KERN_ERR "IRQ request error %d\n", error);
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index d89f83f769f..1cc706e1111 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -575,9 +575,9 @@ int bbc_envctrl_init(void)
int devidx = 0;
while ((echild = bbc_i2c_getdev(devidx++)) != NULL) {
- if (!strcmp(echild->prom_name, "temperature"))
+ if (!strcmp(echild->prom_node->name, "temperature"))
attach_one_temp(echild, temp_index++);
- if (!strcmp(echild->prom_name, "fan-control"))
+ if (!strcmp(echild->prom_node->name, "fan-control"))
attach_one_fan(echild, fan_index++);
}
if (temp_index != 0 && fan_index != 0) {
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 3e156e005f2..7186235594f 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -377,7 +377,7 @@ static int __init attach_one_i2c(struct linux_ebus_device *edev, int index)
bp->waiting = 0;
init_waitqueue_head(&bp->wq);
if (request_irq(edev->irqs[0], bbc_i2c_interrupt,
- SA_SHIRQ, "bbc_i2c", bp))
+ IRQF_SHARED, "bbc_i2c", bp))
goto fail;
bp->index = index;
@@ -423,7 +423,7 @@ static int __init bbc_present(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "bbc"))
+ if (!strcmp(edev->prom_node->name, "bbc"))
return 1;
}
}
@@ -446,7 +446,7 @@ static int __init bbc_i2c_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "i2c")) {
+ if (!strcmp(edev->prom_node->name, "i2c")) {
if (!attach_one_i2c(edev, index))
index++;
}
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index ccb20a6f5f3..385f4f76831 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -20,7 +20,6 @@
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/major.h>
-#include <linux/devfs_fs_kernel.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1031,11 +1030,6 @@ static int __init bpp_init(void)
instances[idx].opened = 0;
probeLptPort(idx);
}
- devfs_mk_dir("bpp");
- for (idx = 0; idx < BPP_NO; idx++) {
- devfs_mk_cdev(MKDEV(BPP_MAJOR, idx),
- S_IFCHR | S_IRUSR | S_IWUSR, "bpp/%d", idx);
- }
return 0;
}
@@ -1044,9 +1038,6 @@ static void __exit bpp_cleanup(void)
{
unsigned idx;
- for (idx = 0; idx < BPP_NO; idx++)
- devfs_remove("bpp/%d", idx);
- devfs_remove("bpp");
unregister_chrdev(BPP_MAJOR, dev_name);
for (idx = 0; idx < BPP_NO; idx++) {
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index 5bf3dd901b6..836a58bb030 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -301,7 +301,7 @@ static int wd_open(struct inode *inode, struct file *f)
{
if (request_irq(wd_dev.irq,
&wd_interrupt,
- SA_SHIRQ,
+ IRQF_SHARED,
WD_OBPNAME,
(void *)wd_dev.regs)) {
printk("%s: Cannot register IRQ %d\n",
@@ -755,7 +755,7 @@ static int __init wd_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, WD_OBPNAME))
+ if (!strcmp(edev->ofdev.node->name, WD_OBPNAME))
goto ebus_done;
}
}
diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c
index c3a51d1fae5..d92bc8827a9 100644
--- a/drivers/sbus/char/display7seg.c
+++ b/drivers/sbus/char/display7seg.c
@@ -184,7 +184,7 @@ static int __init d7s_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, D7S_OBPNAME))
+ if (!strcmp(edev->prom_node->name, D7S_OBPNAME))
goto ebus_done;
}
}
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 19e8eddf887..063e676a3ac 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -22,7 +22,6 @@
#define __KERNEL_SYSCALLS__
static int errno;
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kthread.h>
@@ -768,16 +767,14 @@ static void envctrl_set_mon(struct i2c_child_t *pchild,
* decoding tables, monitor type, optional properties.
* Return: None.
*/
-static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
+static void envctrl_init_adc(struct i2c_child_t *pchild, struct device_node *dp)
{
- char chnls_desc[CHANNEL_DESC_SZ];
int i = 0, len;
- char *pos = chnls_desc;
+ char *pos;
+ unsigned int *pval;
/* Firmware describe channels into a stream separated by a '\0'. */
- len = prom_getproperty(node, "channels-description", chnls_desc,
- CHANNEL_DESC_SZ);
- chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';
+ pos = of_get_property(dp, "channels-description", &len);
while (len > 0) {
int l = strlen(pos) + 1;
@@ -787,10 +784,13 @@ static void envctrl_init_adc(struct i2c_child_t *pchild, int node)
}
/* Get optional properties. */
- len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature,
- sizeof(warning_temperature));
- len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature,
- sizeof(shutdown_temperature));
+ pval = of_get_property(dp, "warning-temp", NULL);
+ if (pval)
+ warning_temperature = *pval;
+
+ pval = of_get_property(dp, "shutdown-temp", NULL);
+ if (pval)
+ shutdown_temperature = *pval;
}
/* Function Description: Initialize child device monitoring fan status.
@@ -864,21 +864,18 @@ static void envctrl_init_voltage_status(struct i2c_child_t *pchild)
static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
struct i2c_child_t *pchild)
{
- int node, len, i, tbls_size = 0;
-
- node = edev_child->prom_node;
+ int len, i, tbls_size = 0;
+ struct device_node *dp = edev_child->prom_node;
+ void *pval;
/* Get device address. */
- len = prom_getproperty(node, "reg",
- (char *) &(pchild->addr),
- sizeof(pchild->addr));
+ pval = of_get_property(dp, "reg", &len);
+ memcpy(&pchild->addr, pval, len);
/* Get tables property. Read firmware temperature tables. */
- len = prom_getproperty(node, "translation",
- (char *) pchild->tblprop_array,
- (PCF8584_MAX_CHANNELS *
- sizeof(struct pcf8584_tblprop)));
- if (len > 0) {
+ pval = of_get_property(dp, "translation", &len);
+ if (pval && len > 0) {
+ memcpy(pchild->tblprop_array, pval, len);
pchild->total_tbls = len / sizeof(struct pcf8584_tblprop);
for (i = 0; i < pchild->total_tbls; i++) {
if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) {
@@ -891,12 +888,12 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
printk("envctrl: Failed to allocate table.\n");
return;
}
- len = prom_getproperty(node, "tables",
- (char *) pchild->tables, tbls_size);
- if (len <= 0) {
+ pval = of_get_property(dp, "tables", &len);
+ if (!pval || len <= 0) {
printk("envctrl: Failed to get table.\n");
return;
}
+ memcpy(pchild->tables, pval, len);
}
/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)
@@ -907,12 +904,11 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
* 'NULL' monitor type.
*/
if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {
+ struct device_node *root_node;
int len;
- char prop[56];
- len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));
- if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))
- {
+ root_node = of_find_node_by_path("/");
+ if (!strcmp(root_node->name, "SUNW,UltraSPARC-IIi-cEngine")) {
for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {
pchild->mon_type[len] = ENVCTRL_NOMON;
}
@@ -921,16 +917,14 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
}
/* Get the monitor channels. */
- len = prom_getproperty(node, "channels-in-use",
- (char *) pchild->chnl_array,
- (PCF8584_MAX_CHANNELS *
- sizeof(struct pcf8584_channel)));
+ pval = of_get_property(dp, "channels-in-use", &len);
+ memcpy(pchild->chnl_array, pval, len);
pchild->total_chnls = len / sizeof(struct pcf8584_channel);
for (i = 0; i < pchild->total_chnls; i++) {
switch (pchild->chnl_array[i].type) {
case PCF8584_TEMP_TYPE:
- envctrl_init_adc(pchild, node);
+ envctrl_init_adc(pchild, dp);
break;
case PCF8584_GLOBALADDR_TYPE:
@@ -945,7 +939,7 @@ static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,
case PCF8584_VOLTAGE_TYPE:
if (pchild->i2ctype == I2C_ADC) {
- envctrl_init_adc(pchild,node);
+ envctrl_init_adc(pchild,dp);
} else {
envctrl_init_voltage_status(pchild);
}
@@ -1046,7 +1040,7 @@ static int __init envctrl_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "bbc")) {
+ if (!strcmp(edev->prom_node->name, "bbc")) {
/* If we find a boot-bus controller node,
* then this envctrl driver is not for us.
*/
@@ -1060,14 +1054,14 @@ static int __init envctrl_init(void)
*/
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "i2c")) {
+ if (!strcmp(edev->prom_node->name, "i2c")) {
i2c = ioremap(edev->resource[0].start, 0x2);
for_each_edevchild(edev, edev_child) {
- if (!strcmp("gpio", edev_child->prom_name)) {
+ if (!strcmp("gpio", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_GPIO;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}
- if (!strcmp("adc", edev_child->prom_name)) {
+ if (!strcmp("adc", edev_child->prom_node->name)) {
i2c_childlist[i].i2ctype = I2C_ADC;
envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));
}
diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c
index 2beb3dded08..fa2418f7ad3 100644
--- a/drivers/sbus/char/flash.c
+++ b/drivers/sbus/char/flash.c
@@ -4,7 +4,6 @@
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -71,7 +70,6 @@ flash_mmap(struct file *file, struct vm_area_struct *vma)
if (vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT)) > size)
size = vma->vm_end - (vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT));
- vma->vm_flags |= (VM_SHM | VM_LOCKED);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
if (io_remap_pfn_range(vma, vma->vm_start, addr, size, vma->vm_page_prot))
@@ -192,9 +190,11 @@ static int __init flash_init(void)
}
if (!sdev) {
#ifdef CONFIG_PCI
+ struct linux_prom_registers *ebus_regs;
+
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "flashprom"))
+ if (!strcmp(edev->prom_node->name, "flashprom"))
goto ebus_done;
}
}
@@ -202,23 +202,23 @@ static int __init flash_init(void)
if (!edev)
return -ENODEV;
- len = prom_getproperty(edev->prom_node, "reg", (void *)regs, sizeof(regs));
- if ((len % sizeof(regs[0])) != 0) {
+ ebus_regs = of_get_property(edev->prom_node, "reg", &len);
+ if (!ebus_regs || (len % sizeof(regs[0])) != 0) {
printk("flash: Strange reg property size %d\n", len);
return -ENODEV;
}
- nregs = len / sizeof(regs[0]);
+ nregs = len / sizeof(ebus_regs[0]);
flash.read_base = edev->resource[0].start;
- flash.read_size = regs[0].reg_size;
+ flash.read_size = ebus_regs[0].reg_size;
if (nregs == 1) {
flash.write_base = edev->resource[0].start;
- flash.write_size = regs[0].reg_size;
+ flash.write_size = ebus_regs[0].reg_size;
} else if (nregs == 2) {
flash.write_base = edev->resource[1].start;
- flash.write_size = regs[1].reg_size;
+ flash.write_size = ebus_regs[1].reg_size;
} else {
printk("flash: Strange number of regs %d\n", nregs);
return -ENODEV;
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 239e108b8ed..2f698763ba5 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -29,9 +29,6 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define PROMLIB_INTERNAL
-
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -39,10 +36,10 @@
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/miscdevice.h>
-#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/openpromio.h>
@@ -51,15 +48,20 @@
#include <asm/pbm.h>
#endif
+MODULE_AUTHOR("Thomas K. Dyas (tdyas@noc.rutgers.edu) and Eddie C. Dost (ecd@skynet.be)");
+MODULE_DESCRIPTION("OPENPROM Configuration Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("1.0");
+
/* Private data kept by the driver for each descriptor. */
typedef struct openprom_private_data
{
- int current_node; /* Current node for SunOS ioctls. */
- int lastnode; /* Last valid node used by BSD ioctls. */
+ struct device_node *current_node; /* Current node for SunOS ioctls. */
+ struct device_node *lastnode; /* Last valid node used by BSD ioctls. */
} DATA;
/* ID of the PROM node containing all of the EEPROM options. */
-static int options_node = 0;
+static struct device_node *options_node;
/*
* Copy an openpromio structure into kernel space from user space.
@@ -87,9 +89,8 @@ static int copyin(struct openpromio __user *info, struct openpromio **opp_p)
if (bufsize > OPROMMAXPARAM)
bufsize = OPROMMAXPARAM;
- if (!(*opp_p = kmalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
+ if (!(*opp_p = kzalloc(sizeof(int) + bufsize + 1, GFP_KERNEL)))
return -ENOMEM;
- memset(*opp_p, 0, sizeof(int) + bufsize + 1);
if (copy_from_user(&(*opp_p)->oprom_array,
&info->oprom_array, bufsize)) {
@@ -107,10 +108,9 @@ static int getstrings(struct openpromio __user *info, struct openpromio **opp_p)
if (!info || !opp_p)
return -EFAULT;
- if (!(*opp_p = kmalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
+ if (!(*opp_p = kzalloc(sizeof(int) + OPROMMAXPARAM + 1, GFP_KERNEL)))
return -ENOMEM;
- memset(*opp_p, 0, sizeof(int) + OPROMMAXPARAM + 1);
(*opp_p)->oprom_size = 0;
n = bufsize = 0;
@@ -140,16 +140,171 @@ static int copyout(void __user *info, struct openpromio *opp, int len)
return 0;
}
+static int opromgetprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
+{
+ void *pval;
+ int len;
+
+ if (!dp ||
+ !(pval = of_get_property(dp, op->oprom_array, &len)) ||
+ len <= 0 || len > bufsize)
+ return copyout(argp, op, sizeof(int));
+
+ memcpy(op->oprom_array, pval, len);
+ op->oprom_array[len] = '\0';
+ op->oprom_size = len;
+
+ return copyout(argp, op, sizeof(int) + bufsize);
+}
+
+static int opromnxtprop(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize)
+{
+ struct property *prop;
+ int len;
+
+ if (!dp)
+ return copyout(argp, op, sizeof(int));
+ if (op->oprom_array[0] == '\0') {
+ prop = dp->properties;
+ if (!prop)
+ return copyout(argp, op, sizeof(int));
+ len = strlen(prop->name);
+ } else {
+ prop = of_find_property(dp, op->oprom_array, NULL);
+
+ if (!prop ||
+ !prop->next ||
+ (len = strlen(prop->next->name)) + 1 > bufsize)
+ return copyout(argp, op, sizeof(int));
+
+ prop = prop->next;
+ }
+
+ memcpy(op->oprom_array, prop->name, len);
+ op->oprom_array[len] = '\0';
+ op->oprom_size = ++len;
+
+ return copyout(argp, op, sizeof(int) + bufsize);
+}
+
+static int opromsetopt(struct device_node *dp, struct openpromio *op, int bufsize)
+{
+ char *buf = op->oprom_array + strlen(op->oprom_array) + 1;
+ int len = op->oprom_array + bufsize - buf;
+
+ return of_set_property(options_node, op->oprom_array, buf, len);
+}
+
+static int opromnext(void __user *argp, unsigned int cmd, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+ phandle ph;
+
+ BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
+
+ if (bufsize < sizeof(phandle))
+ return -EINVAL;
+
+ ph = *((int *) op->oprom_array);
+ if (ph) {
+ dp = of_find_node_by_phandle(ph);
+ if (!dp)
+ return -EINVAL;
+
+ switch (cmd) {
+ case OPROMNEXT:
+ dp = dp->sibling;
+ break;
+
+ case OPROMCHILD:
+ dp = dp->child;
+ break;
+
+ case OPROMSETCUR:
+ default:
+ break;
+ };
+ } else {
+ /* Sibling of node zero is the root node. */
+ if (cmd != OPROMNEXT)
+ return -EINVAL;
+
+ dp = of_find_node_by_path("/");
+ }
+
+ ph = 0;
+ if (dp)
+ ph = dp->node;
+
+ data->current_node = dp;
+ *((int *) op->oprom_array) = ph;
+ op->oprom_size = sizeof(phandle);
+
+ return copyout(argp, op, bufsize + sizeof(int));
+}
+
+static int oprompci2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+ int err = -EINVAL;
+
+ if (bufsize >= 2*sizeof(int)) {
+#ifdef CONFIG_PCI
+ struct pci_dev *pdev;
+ struct pcidev_cookie *pcp;
+ pdev = pci_find_slot (((int *) op->oprom_array)[0],
+ ((int *) op->oprom_array)[1]);
+
+ pcp = pdev->sysdata;
+ if (pcp != NULL) {
+ dp = pcp->prom_node;
+ data->current_node = dp;
+ *((int *)op->oprom_array) = dp->node;
+ op->oprom_size = sizeof(int);
+ err = copyout(argp, op, bufsize + sizeof(int));
+ }
+#endif
+ }
+
+ return err;
+}
+
+static int oprompath2node(void __user *argp, struct device_node *dp, struct openpromio *op, int bufsize, DATA *data)
+{
+ phandle ph = 0;
+
+ dp = of_find_node_by_path(op->oprom_array);
+ if (dp)
+ ph = dp->node;
+ data->current_node = dp;
+ *((int *)op->oprom_array) = ph;
+ op->oprom_size = sizeof(int);
+
+ return copyout(argp, op, bufsize + sizeof(int));
+}
+
+static int opromgetbootargs(void __user *argp, struct openpromio *op, int bufsize)
+{
+ char *buf = saved_command_line;
+ int len = strlen(buf);
+
+ if (len > bufsize)
+ return -EINVAL;
+
+ strcpy(op->oprom_array, buf);
+ op->oprom_size = len;
+
+ return copyout(argp, op, bufsize + sizeof(int));
+}
+
/*
* SunOS and Solaris /dev/openprom ioctl calls.
*/
static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg, int node)
+ unsigned int cmd, unsigned long arg,
+ struct device_node *dp)
{
- DATA *data = (DATA *) file->private_data;
- char buffer[OPROMMAXPARAM+1], *buf;
+ DATA *data = file->private_data;
struct openpromio *opp;
- int bufsize, len, error = 0;
+ int bufsize, error = 0;
static int cnt;
void __user *argp = (void __user *)arg;
@@ -164,119 +319,35 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
switch (cmd) {
case OPROMGETOPT:
case OPROMGETPROP:
- len = prom_getproplen(node, opp->oprom_array);
-
- if (len <= 0 || len > bufsize) {
- error = copyout(argp, opp, sizeof(int));
- break;
- }
-
- len = prom_getproperty(node, opp->oprom_array, buffer, bufsize);
-
- memcpy(opp->oprom_array, buffer, len);
- opp->oprom_array[len] = '\0';
- opp->oprom_size = len;
-
- error = copyout(argp, opp, sizeof(int) + bufsize);
+ error = opromgetprop(argp, dp, opp, bufsize);
break;
case OPROMNXTOPT:
case OPROMNXTPROP:
- buf = prom_nextprop(node, opp->oprom_array, buffer);
-
- len = strlen(buf);
- if (len == 0 || len + 1 > bufsize) {
- error = copyout(argp, opp, sizeof(int));
- break;
- }
-
- memcpy(opp->oprom_array, buf, len);
- opp->oprom_array[len] = '\0';
- opp->oprom_size = ++len;
-
- error = copyout(argp, opp, sizeof(int) + bufsize);
+ error = opromnxtprop(argp, dp, opp, bufsize);
break;
case OPROMSETOPT:
case OPROMSETOPT2:
- buf = opp->oprom_array + strlen(opp->oprom_array) + 1;
- len = opp->oprom_array + bufsize - buf;
-
- error = prom_setprop(options_node, opp->oprom_array,
- buf, len);
-
- if (error < 0)
- error = -EINVAL;
+ error = opromsetopt(dp, opp, bufsize);
break;
case OPROMNEXT:
case OPROMCHILD:
case OPROMSETCUR:
- if (bufsize < sizeof(int)) {
- error = -EINVAL;
- break;
- }
-
- node = *((int *) opp->oprom_array);
-
- switch (cmd) {
- case OPROMNEXT: node = __prom_getsibling(node); break;
- case OPROMCHILD: node = __prom_getchild(node); break;
- case OPROMSETCUR: break;
- }
-
- data->current_node = node;
- *((int *)opp->oprom_array) = node;
- opp->oprom_size = sizeof(int);
-
- error = copyout(argp, opp, bufsize + sizeof(int));
+ error = opromnext(argp, cmd, dp, opp, bufsize, data);
break;
case OPROMPCI2NODE:
- error = -EINVAL;
-
- if (bufsize >= 2*sizeof(int)) {
-#ifdef CONFIG_PCI
- struct pci_dev *pdev;
- struct pcidev_cookie *pcp;
- pdev = pci_find_slot (((int *) opp->oprom_array)[0],
- ((int *) opp->oprom_array)[1]);
-
- pcp = pdev->sysdata;
- if (pcp != NULL && pcp->prom_node != -1 && pcp->prom_node) {
- node = pcp->prom_node;
- data->current_node = node;
- *((int *)opp->oprom_array) = node;
- opp->oprom_size = sizeof(int);
- error = copyout(argp, opp, bufsize + sizeof(int));
- }
-#endif
- }
+ error = oprompci2node(argp, dp, opp, bufsize, data);
break;
case OPROMPATH2NODE:
- node = prom_finddevice(opp->oprom_array);
- data->current_node = node;
- *((int *)opp->oprom_array) = node;
- opp->oprom_size = sizeof(int);
-
- error = copyout(argp, opp, bufsize + sizeof(int));
+ error = oprompath2node(argp, dp, opp, bufsize, data);
break;
case OPROMGETBOOTARGS:
- buf = saved_command_line;
-
- len = strlen(buf);
-
- if (len > bufsize) {
- error = -EINVAL;
- break;
- }
-
- strcpy(opp->oprom_array, buf);
- opp->oprom_size = len;
-
- error = copyout(argp, opp, bufsize + sizeof(int));
+ error = opromgetbootargs(argp, opp, bufsize);
break;
case OPROMU2P:
@@ -297,25 +368,14 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file,
return error;
}
-
-/* Return nonzero if a specific node is in the PROM device tree. */
-static int intree(int root, int node)
+static struct device_node *get_node(phandle n, DATA *data)
{
- for (; root != 0; root = prom_getsibling(root))
- if (root == node || intree(prom_getchild(root),node))
- return 1;
- return 0;
-}
+ struct device_node *dp = of_find_node_by_phandle(n);
-/* Return nonzero if a specific node is "valid". */
-static int goodnode(int n, DATA *data)
-{
- if (n == data->lastnode || n == prom_root_node || n == options_node)
- return 1;
- if (n == 0 || n == -1 || !intree(prom_root_node,n))
- return 0;
- data->lastnode = n;
- return 1;
+ if (dp)
+ data->lastnode = dp;
+
+ return dp;
}
/* Copy in a whole string from userspace into kernelspace. */
@@ -330,7 +390,7 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
if (!tmp)
return -ENOMEM;
- if(copy_from_user(tmp, user, len)) {
+ if (copy_from_user(tmp, user, len)) {
kfree(tmp);
return -EFAULT;
}
@@ -345,162 +405,187 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
/*
* NetBSD /dev/openprom ioctl calls.
*/
-static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int opiocget(void __user *argp, DATA *data)
{
- DATA *data = (DATA *) file->private_data;
- void __user *argp = (void __user *)arg;
struct opiocdesc op;
- int error, node, len;
- char *str, *tmp;
- char buffer[64];
- static int cnt;
-
- switch (cmd) {
- case OPIOCGET:
- if (copy_from_user(&op, argp, sizeof(op)))
- return -EFAULT;
+ struct device_node *dp;
+ char *str;
+ void *pval;
+ int err, len;
- if (!goodnode(op.op_nodeid,data))
- return -EINVAL;
-
- error = copyin_string(op.op_name, op.op_namelen, &str);
- if (error)
- return error;
+ if (copy_from_user(&op, argp, sizeof(op)))
+ return -EFAULT;
- len = prom_getproplen(op.op_nodeid,str);
+ dp = get_node(op.op_nodeid, data);
- if (len > op.op_buflen) {
- kfree(str);
- return -ENOMEM;
- }
+ err = copyin_string(op.op_name, op.op_namelen, &str);
+ if (err)
+ return err;
+ pval = of_get_property(dp, str, &len);
+ err = 0;
+ if (!pval || len > op.op_buflen) {
+ err = -EINVAL;
+ } else {
op.op_buflen = len;
+ if (copy_to_user(argp, &op, sizeof(op)) ||
+ copy_to_user(op.op_buf, pval, len))
+ err = -EFAULT;
+ }
+ kfree(str);
- if (len <= 0) {
- kfree(str);
- /* Verified by the above copy_from_user */
- if (__copy_to_user(argp, &op,
- sizeof(op)))
- return -EFAULT;
- return 0;
- }
+ return err;
+}
- tmp = kmalloc(len + 1, GFP_KERNEL);
- if (!tmp) {
- kfree(str);
- return -ENOMEM;
- }
+static int opiocnextprop(void __user *argp, DATA *data)
+{
+ struct opiocdesc op;
+ struct device_node *dp;
+ struct property *prop;
+ char *str;
+ int err, len;
- cnt = prom_getproperty(op.op_nodeid, str, tmp, len);
- if (cnt <= 0) {
- error = -EINVAL;
- } else {
- tmp[len] = '\0';
+ if (copy_from_user(&op, argp, sizeof(op)))
+ return -EFAULT;
- if (__copy_to_user(argp, &op, sizeof(op)) != 0 ||
- copy_to_user(op.op_buf, tmp, len) != 0)
- error = -EFAULT;
- }
+ dp = get_node(op.op_nodeid, data);
+ if (!dp)
+ return -EINVAL;
- kfree(tmp);
- kfree(str);
+ err = copyin_string(op.op_name, op.op_namelen, &str);
+ if (err)
+ return err;
- return error;
+ if (str[0] == '\0') {
+ prop = dp->properties;
+ } else {
+ prop = of_find_property(dp, str, NULL);
+ if (prop)
+ prop = prop->next;
+ }
+ kfree(str);
- case OPIOCNEXTPROP:
- if (copy_from_user(&op, argp, sizeof(op)))
- return -EFAULT;
+ if (!prop)
+ len = 0;
+ else
+ len = prop->length;
- if (!goodnode(op.op_nodeid,data))
- return -EINVAL;
+ if (len > op.op_buflen)
+ len = op.op_buflen;
- error = copyin_string(op.op_name, op.op_namelen, &str);
- if (error)
- return error;
+ if (copy_to_user(argp, &op, sizeof(op)))
+ return -EFAULT;
- tmp = prom_nextprop(op.op_nodeid,str,buffer);
+ if (len &&
+ copy_to_user(op.op_buf, prop->value, len))
+ return -EFAULT;
- if (tmp) {
- len = strlen(tmp);
- if (len > op.op_buflen)
- len = op.op_buflen;
- else
- op.op_buflen = len;
- } else {
- len = op.op_buflen = 0;
- }
+ return 0;
+}
- if (!access_ok(VERIFY_WRITE, argp, sizeof(op))) {
- kfree(str);
- return -EFAULT;
- }
+static int opiocset(void __user *argp, DATA *data)
+{
+ struct opiocdesc op;
+ struct device_node *dp;
+ char *str, *tmp;
+ int err;
- if (!access_ok(VERIFY_WRITE, op.op_buf, len)) {
- kfree(str);
- return -EFAULT;
- }
+ if (copy_from_user(&op, argp, sizeof(op)))
+ return -EFAULT;
+
+ dp = get_node(op.op_nodeid, data);
+ if (!dp)
+ return -EINVAL;
- error = __copy_to_user(argp, &op, sizeof(op));
- if (!error) error = __copy_to_user(op.op_buf, tmp, len);
+ err = copyin_string(op.op_name, op.op_namelen, &str);
+ if (err)
+ return err;
+ err = copyin_string(op.op_buf, op.op_buflen, &tmp);
+ if (err) {
kfree(str);
+ return err;
+ }
- return error;
+ err = of_set_property(dp, str, tmp, op.op_buflen);
- case OPIOCSET:
- if (copy_from_user(&op, argp, sizeof(op)))
- return -EFAULT;
+ kfree(str);
+ kfree(tmp);
- if (!goodnode(op.op_nodeid,data))
- return -EINVAL;
+ return err;
+}
- error = copyin_string(op.op_name, op.op_namelen, &str);
- if (error)
- return error;
+static int opiocgetnext(unsigned int cmd, void __user *argp)
+{
+ struct device_node *dp;
+ phandle nd;
- error = copyin_string(op.op_buf, op.op_buflen, &tmp);
- if (error) {
- kfree(str);
- return error;
- }
+ BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
- len = prom_setprop(op.op_nodeid,str,tmp,op.op_buflen+1);
+ if (copy_from_user(&nd, argp, sizeof(phandle)))
+ return -EFAULT;
- if (len != op.op_buflen)
+ if (nd == 0) {
+ if (cmd != OPIOCGETNEXT)
return -EINVAL;
+ dp = of_find_node_by_path("/");
+ } else {
+ dp = of_find_node_by_phandle(nd);
+ nd = 0;
+ if (dp) {
+ if (cmd == OPIOCGETNEXT)
+ dp = dp->sibling;
+ else
+ dp = dp->child;
+ }
+ }
+ if (dp)
+ nd = dp->node;
+ if (copy_to_user(argp, &nd, sizeof(phandle)))
+ return -EFAULT;
- kfree(str);
- kfree(tmp);
+ return 0;
+}
- return 0;
+static int openprom_bsd_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ DATA *data = (DATA *) file->private_data;
+ void __user *argp = (void __user *)arg;
+ int err;
- case OPIOCGETOPTNODE:
- if (copy_to_user(argp, &options_node, sizeof(int)))
- return -EFAULT;
- return 0;
+ switch (cmd) {
+ case OPIOCGET:
+ err = opiocget(argp, data);
+ break;
- case OPIOCGETNEXT:
- case OPIOCGETCHILD:
- if (copy_from_user(&node, argp, sizeof(int)))
- return -EFAULT;
+ case OPIOCNEXTPROP:
+ err = opiocnextprop(argp, data);
+ break;
- if (cmd == OPIOCGETNEXT)
- node = __prom_getsibling(node);
- else
- node = __prom_getchild(node);
+ case OPIOCSET:
+ err = opiocset(argp, data);
+ break;
+
+ case OPIOCGETOPTNODE:
+ BUILD_BUG_ON(sizeof(phandle) != sizeof(int));
- if (__copy_to_user(argp, &node, sizeof(int)))
+ if (copy_to_user(argp, &options_node->node, sizeof(phandle)))
return -EFAULT;
return 0;
+ case OPIOCGETNEXT:
+ case OPIOCGETCHILD:
+ err = opiocgetnext(cmd, argp);
+ break;
+
default:
- if (cnt++ < 10)
- printk(KERN_INFO "openprom_bsd_ioctl: cmd 0x%X\n", cmd);
return -EINVAL;
- }
+ };
+
+ return err;
}
@@ -511,7 +596,6 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
unsigned int cmd, unsigned long arg)
{
DATA *data = (DATA *) file->private_data;
- static int cnt;
switch (cmd) {
case OPROMGETOPT:
@@ -563,10 +647,8 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
return openprom_bsd_ioctl(inode,file,cmd,arg);
default:
- if (cnt++ < 10)
- printk("openprom_ioctl: cmd 0x%X, arg 0x%lX\n", cmd, arg);
return -EINVAL;
- }
+ };
}
static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
@@ -594,9 +676,7 @@ static long openprom_compat_ioctl(struct file *file, unsigned int cmd,
case OPROMSETCUR:
case OPROMPCI2NODE:
case OPROMPATH2NODE:
- lock_kernel();
rval = openprom_ioctl(file->f_dentry->d_inode, file, cmd, arg);
- lock_kernel();
break;
}
@@ -607,13 +687,13 @@ static int openprom_open(struct inode * inode, struct file * file)
{
DATA *data;
- data = (DATA *) kmalloc(sizeof(DATA), GFP_KERNEL);
+ data = kmalloc(sizeof(DATA), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->current_node = prom_root_node;
- data->lastnode = prom_root_node;
- file->private_data = (void *)data;
+ data->current_node = of_find_node_by_path("/");
+ data->lastnode = data->current_node;
+ file->private_data = (void *) data;
return 0;
}
@@ -634,24 +714,30 @@ static struct file_operations openprom_fops = {
};
static struct miscdevice openprom_dev = {
- SUN_OPENPROM_MINOR, "openprom", &openprom_fops
+ .minor = SUN_OPENPROM_MINOR,
+ .name = "openprom",
+ .fops = &openprom_fops,
};
static int __init openprom_init(void)
{
- int error;
+ struct device_node *dp;
+ int err;
- error = misc_register(&openprom_dev);
- if (error) {
- printk(KERN_ERR "openprom: unable to get misc minor\n");
- return error;
- }
+ err = misc_register(&openprom_dev);
+ if (err)
+ return err;
- options_node = prom_getchild(prom_root_node);
- options_node = prom_searchsiblings(options_node,"options");
+ dp = of_find_node_by_path("/");
+ dp = dp->child;
+ while (dp) {
+ if (!strcmp(dp->name, "options"))
+ break;
+ dp = dp->sibling;
+ }
+ options_node = dp;
- if (options_node == 0 || options_node == -1) {
- printk(KERN_ERR "openprom: unable to find options node\n");
+ if (!options_node) {
misc_deregister(&openprom_dev);
return -EIO;
}
@@ -666,4 +752,3 @@ static void __exit openprom_cleanup(void)
module_init(openprom_init);
module_exit(openprom_cleanup);
-MODULE_LICENSE("GPL");
diff --git a/drivers/sbus/char/riowatchdog.c b/drivers/sbus/char/riowatchdog.c
index d1babff6a53..2a9cc820442 100644
--- a/drivers/sbus/char/riowatchdog.c
+++ b/drivers/sbus/char/riowatchdog.c
@@ -211,7 +211,7 @@ static int __init riowd_bbc_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "bbc"))
+ if (!strcmp(edev->ofdev.node->name, "bbc"))
goto found_bbc;
}
}
@@ -238,7 +238,7 @@ static int __init riowd_init(void)
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, RIOWD_NAME))
+ if (!strcmp(edev->ofdev.node->name, RIOWD_NAME))
goto ebus_done;
}
}
diff --git a/drivers/sbus/char/vfc.h b/drivers/sbus/char/vfc.h
index 8045cd5e7cb..63941a259b9 100644
--- a/drivers/sbus/char/vfc.h
+++ b/drivers/sbus/char/vfc.h
@@ -1,8 +1,6 @@
#ifndef _LINUX_VFC_H_
#define _LINUX_VFC_H_
-#include <linux/devfs_fs_kernel.h>
-
/*
* The control register for the vfc is at offset 0x4000
* The first field ram bank is located at offset 0x5000
diff --git a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
index dfdd6be551f..55b2b31bd7a 100644
--- a/drivers/sbus/char/vfc_dev.c
+++ b/drivers/sbus/char/vfc_dev.c
@@ -164,10 +164,6 @@ int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
return -EINVAL;
if (init_vfc_hw(dev))
return -EIO;
-
- devfs_mk_cdev(MKDEV(VFC_MAJOR, instance),
- S_IFCHR | S_IRUSR | S_IWUSR,
- "vfc/%d", instance);
return 0;
}
@@ -623,7 +619,7 @@ static int vfc_mmap(struct file *file, struct vm_area_struct *vma)
map_size = sizeof(struct vfc_regs);
vma->vm_flags |=
- (VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
+ (VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE);
map_offset = (unsigned int) (long)dev->phys_regs;
ret = io_remap_pfn_range(vma, vma->vm_start,
MK_IOSPACE_PFN(dev->which_io,
@@ -677,7 +673,6 @@ static int vfc_probe(void)
kfree(vfc_dev_lst);
return -EIO;
}
- devfs_mk_dir("vfc");
instance = 0;
for_all_sbusdev(sdev, sbus) {
if (strcmp(sdev->prom_name, "vfc") == 0) {
@@ -717,7 +712,6 @@ static void deinit_vfc_device(struct vfc_dev *dev)
{
if(dev == NULL)
return;
- devfs_remove("vfc/%d", dev->instance);
sbus_iounmap(dev->regs, sizeof(struct vfc_regs));
kfree(dev);
}
@@ -731,7 +725,6 @@ void cleanup_module(void)
for (devp = vfc_dev_lst; *devp; devp++)
deinit_vfc_device(*devp);
- devfs_remove("vfc");
kfree(vfc_dev_lst);
return;
}
diff --git a/drivers/sbus/dvma.c b/drivers/sbus/dvma.c
index 378a1d68024..57e1526746a 100644
--- a/drivers/sbus/dvma.c
+++ b/drivers/sbus/dvma.c
@@ -3,7 +3,6 @@
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/slab.h>
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 5d30a3ebfcc..935952ef88f 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -1,12 +1,10 @@
-/* $Id: sbus.c,v 1.100 2002/01/24 15:36:24 davem Exp $
- * sbus.c: SBus support routines.
+/* sbus.c: SBus support routines.
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 2006 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/pci.h>
@@ -14,237 +12,76 @@
#include <asm/sbus.h>
#include <asm/dma.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/bpp.h>
#include <asm/irq.h>
-struct sbus_bus *sbus_root = NULL;
+struct sbus_bus *sbus_root;
-static struct linux_prom_irqs irqs[PROMINTR_MAX] __initdata = { { 0 } };
-#ifdef CONFIG_SPARC32
-static int interrupts[PROMINTR_MAX] __initdata = { 0 };
-#endif
-
-#ifdef CONFIG_PCI
-extern int pcic_present(void);
-#endif
-
-/* Perhaps when I figure out more about the iommu we'll put a
- * device registration routine here that probe_sbus() calls to
- * setup the iommu for each Sbus.
- */
-
-/* We call this for each SBus device, and fill the structure based
- * upon the prom device tree. We return the start of memory after
- * the things we have allocated.
- */
-
-/* #define DEBUG_FILL */
-
-static void __init fill_sbus_device(int prom_node, struct sbus_dev *sdev)
+static void __init fill_sbus_device(struct device_node *dp, struct sbus_dev *sdev)
{
- unsigned long address, base;
+ unsigned long base;
+ void *pval;
int len;
- sdev->prom_node = prom_node;
- prom_getstring(prom_node, "name",
- sdev->prom_name, sizeof(sdev->prom_name));
- address = prom_getint(prom_node, "address");
- len = prom_getproperty(prom_node, "reg",
- (char *) sdev->reg_addrs,
- sizeof(sdev->reg_addrs));
- if (len == -1) {
- sdev->num_registers = 0;
- goto no_regs;
- }
+ sdev->prom_node = dp->node;
+ strcpy(sdev->prom_name, dp->name);
- if (len % sizeof(struct linux_prom_registers)) {
- prom_printf("fill_sbus_device: proplen for regs of %s "
- " was %d, need multiple of %d\n",
- sdev->prom_name, len,
- (int) sizeof(struct linux_prom_registers));
- prom_halt();
- }
- if (len > (sizeof(struct linux_prom_registers) * PROMREG_MAX)) {
- prom_printf("fill_sbus_device: Too many register properties "
- "for device %s, len=%d\n",
- sdev->prom_name, len);
- prom_halt();
- }
- sdev->num_registers = len / sizeof(struct linux_prom_registers);
- sdev->ranges_applied = 0;
+ pval = of_get_property(dp, "reg", &len);
+ sdev->num_registers = 0;
+ if (pval) {
+ memcpy(sdev->reg_addrs, pval, len);
- base = (unsigned long) sdev->reg_addrs[0].phys_addr;
+ sdev->num_registers =
+ len / sizeof(struct linux_prom_registers);
- /* Compute the slot number. */
- if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m) {
- sdev->slot = sbus_dev_slot(base);
- } else {
- sdev->slot = sdev->reg_addrs[0].which_io;
- }
+ base = (unsigned long) sdev->reg_addrs[0].phys_addr;
-no_regs:
- len = prom_getproperty(prom_node, "ranges",
- (char *)sdev->device_ranges,
- sizeof(sdev->device_ranges));
- if (len == -1) {
- sdev->num_device_ranges = 0;
- goto no_ranges;
- }
- if (len % sizeof(struct linux_prom_ranges)) {
- prom_printf("fill_sbus_device: proplen for ranges of %s "
- " was %d, need multiple of %d\n",
- sdev->prom_name, len,
- (int) sizeof(struct linux_prom_ranges));
- prom_halt();
- }
- if (len > (sizeof(struct linux_prom_ranges) * PROMREG_MAX)) {
- prom_printf("fill_sbus_device: Too many range properties "
- "for device %s, len=%d\n",
- sdev->prom_name, len);
- prom_halt();
+ /* Compute the slot number. */
+ if (base >= SUN_SBUS_BVADDR && sparc_cpu_model == sun4m)
+ sdev->slot = sbus_dev_slot(base);
+ else
+ sdev->slot = sdev->reg_addrs[0].which_io;
}
- sdev->num_device_ranges =
- len / sizeof(struct linux_prom_ranges);
-
-no_ranges:
- /* XXX Unfortunately, IRQ issues are very arch specific.
- * XXX Pull this crud out into an arch specific area
- * XXX at some point. -DaveM
- */
-#ifdef CONFIG_SPARC64
- len = prom_getproperty(prom_node, "interrupts",
- (char *) irqs, sizeof(irqs));
- if (len == -1 || len == 0) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- unsigned int pri = irqs[0].pri;
-
- sdev->num_irqs = 1;
- if (pri < 0x20)
- pri += sdev->slot * 8;
-
- sdev->irqs[0] = sbus_build_irq(sdev->bus, pri);
+
+ pval = of_get_property(dp, "ranges", &len);
+ sdev->num_device_ranges = 0;
+ if (pval) {
+ memcpy(sdev->device_ranges, pval, len);
+ sdev->num_device_ranges =
+ len / sizeof(struct linux_prom_ranges);
}
-#endif /* CONFIG_SPARC64 */
-
-#ifdef CONFIG_SPARC32
- len = prom_getproperty(prom_node, "intr",
- (char *)irqs, sizeof(irqs));
- if (len != -1) {
- sdev->num_irqs = len / 8;
- if (sdev->num_irqs == 0) {
- sdev->irqs[0] = 0;
- } else if (sparc_cpu_model == sun4d) {
- extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq);
-
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] = sun4d_build_irq(sdev, irqs[len].pri);
- } else {
- for (len = 0; len < sdev->num_irqs; len++)
- sdev->irqs[len] = irqs[len].pri;
- }
- } else {
- /* No "intr" node found-- check for "interrupts" node.
- * This node contains SBus interrupt levels, not IPLs
- * as in "intr", and no vector values. We convert
- * SBus interrupt levels to PILs (platform specific).
- */
- len = prom_getproperty(prom_node, "interrupts",
- (char *)interrupts, sizeof(interrupts));
- if (len == -1) {
- sdev->irqs[0] = 0;
- sdev->num_irqs = 0;
- } else {
- sdev->num_irqs = len / sizeof(int);
- for (len = 0; len < sdev->num_irqs; len++) {
- sdev->irqs[len] = sbint_to_irq(sdev, interrupts[len]);
- }
- }
- }
-#endif /* CONFIG_SPARC32 */
-}
-/* This routine gets called from whoever needs the sbus first, to scan
- * the SBus device tree. Currently it just prints out the devices
- * found on the bus and builds trees of SBUS structs and attached
- * devices.
- */
+ sbus_fill_device_irq(sdev);
-extern void iommu_init(int iommu_node, struct sbus_bus *sbus);
-extern void iounit_init(int sbi_node, int iounit_node, struct sbus_bus *sbus);
-void sun4_init(void);
-#ifdef CONFIG_SUN_AUXIO
-extern void auxio_probe(void);
-#endif
-
-static void __init sbus_do_child_siblings(int start_node,
- struct sbus_dev *child,
- struct sbus_dev *parent,
- struct sbus_bus *sbus)
-{
- struct sbus_dev *this_dev = child;
- int this_node = start_node;
-
- /* Child already filled in, just need to traverse siblings. */
- child->child = NULL;
- child->parent = parent;
- while((this_node = prom_getsibling(this_node)) != 0) {
- this_dev->next = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
- this_dev = this_dev->next;
- this_dev->next = NULL;
- this_dev->parent = parent;
-
- this_dev->bus = sbus;
- fill_sbus_device(this_node, this_dev);
-
- if(prom_getchild(this_node)) {
- this_dev->child = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- this_dev->child->bus = sbus;
- this_dev->child->next = NULL;
- fill_sbus_device(prom_getchild(this_node), this_dev->child);
- sbus_do_child_siblings(prom_getchild(this_node),
- this_dev->child, this_dev, sbus);
- } else {
- this_dev->child = NULL;
- }
- }
-}
+ sdev->ofdev.node = dp;
+ if (sdev->parent)
+ sdev->ofdev.dev.parent = &sdev->parent->ofdev.dev;
+ else
+ sdev->ofdev.dev.parent = &sdev->bus->ofdev.dev;
+ sdev->ofdev.dev.bus = &sbus_bus_type;
+ strcpy(sdev->ofdev.dev.bus_id, dp->path_component_name);
-/*
- * XXX This functions appears to be a distorted version of
- * prom_sbus_ranges_init(), with all sun4d stuff cut away.
- * Ask DaveM what is going on here, how is sun4d supposed to work... XXX
- */
-/* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */
+ if (of_device_register(&sdev->ofdev) != 0)
+ printk(KERN_DEBUG "sbus: device registration error for %s!\n",
+ sdev->ofdev.dev.bus_id);
+}
-static void __init sbus_bus_ranges_init(int parent_node, struct sbus_bus *sbus)
+static void __init sbus_bus_ranges_init(struct device_node *dp, struct sbus_bus *sbus)
{
+ void *pval;
int len;
- len = prom_getproperty(sbus->prom_node, "ranges",
- (char *) sbus->sbus_ranges,
- sizeof(sbus->sbus_ranges));
- if (len == -1 || len == 0) {
- sbus->num_sbus_ranges = 0;
- return;
- }
- sbus->num_sbus_ranges = len / sizeof(struct linux_prom_ranges);
-#ifdef CONFIG_SPARC32
- if (sparc_cpu_model == sun4d) {
- struct linux_prom_ranges iounit_ranges[PROMREG_MAX];
- int num_iounit_ranges;
-
- len = prom_getproperty(parent_node, "ranges",
- (char *) iounit_ranges,
- sizeof (iounit_ranges));
- if (len != -1) {
- num_iounit_ranges = (len/sizeof(struct linux_prom_ranges));
- prom_adjust_ranges (sbus->sbus_ranges, sbus->num_sbus_ranges, iounit_ranges, num_iounit_ranges);
- }
+ pval = of_get_property(dp, "ranges", &len);
+ sbus->num_sbus_ranges = 0;
+ if (pval) {
+ memcpy(sbus->sbus_ranges, pval, len);
+ sbus->num_sbus_ranges =
+ len / sizeof(struct linux_prom_ranges);
+
+ sbus_arch_bus_ranges_init(dp->parent, sbus);
}
-#endif
}
static void __init __apply_ranges_to_regs(struct linux_prom_ranges *ranges,
@@ -322,241 +159,127 @@ static void __init sbus_fixup_all_regs(struct sbus_dev *first_sdev)
}
}
-extern void register_proc_sparc_ioport(void);
-extern void firetruck_init(void);
+/* We preserve the "probe order" of these bus and device lists to give
+ * the same ordering as the old code.
+ */
+static void __init sbus_insert(struct sbus_bus *sbus, struct sbus_bus **root)
+{
+ while (*root)
+ root = &(*root)->next;
+ *root = sbus;
+ sbus->next = NULL;
+}
-#ifdef CONFIG_SUN4
-extern void sun4_dvma_init(void);
-#endif
+static void __init sdev_insert(struct sbus_dev *sdev, struct sbus_dev **root)
+{
+ while (*root)
+ root = &(*root)->next;
+ *root = sdev;
+ sdev->next = NULL;
+}
-static int __init sbus_init(void)
+static void __init walk_children(struct device_node *dp, struct sbus_dev *parent, struct sbus_bus *sbus)
{
- int nd, this_sbus, sbus_devs, topnd, iommund;
- unsigned int sbus_clock;
- struct sbus_bus *sbus;
- struct sbus_dev *this_dev;
- int num_sbus = 0; /* How many did we find? */
+ dp = dp->child;
+ while (dp) {
+ struct sbus_dev *sdev;
-#ifdef CONFIG_SPARC32
- register_proc_sparc_ioport();
-#endif
+ sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
+ if (sdev) {
+ sdev_insert(sdev, &parent->child);
-#ifdef CONFIG_SUN4
- sun4_dvma_init();
- return 0;
-#endif
-
- topnd = prom_getchild(prom_root_node);
-
- /* Finding the first sbus is a special case... */
- iommund = 0;
- if(sparc_cpu_model == sun4u) {
- nd = prom_searchsiblings(topnd, "sbus");
- if(nd == 0) {
-#ifdef CONFIG_PCI
- if (!pcic_present()) {
- prom_printf("Neither SBUS nor PCI found.\n");
- prom_halt();
- } else {
-#ifdef CONFIG_SPARC64
- firetruck_init();
-#endif
- }
- return 0;
-#else
- prom_printf("YEEE, UltraSparc sbus not found\n");
- prom_halt();
-#endif
- }
- } else if(sparc_cpu_model == sun4d) {
- if((iommund = prom_searchsiblings(topnd, "io-unit")) == 0 ||
- (nd = prom_getchild(iommund)) == 0 ||
- (nd = prom_searchsiblings(nd, "sbi")) == 0) {
- panic("sbi not found");
- }
- } else if((nd = prom_searchsiblings(topnd, "sbus")) == 0) {
- if((iommund = prom_searchsiblings(topnd, "iommu")) == 0 ||
- (nd = prom_getchild(iommund)) == 0 ||
- (nd = prom_searchsiblings(nd, "sbus")) == 0) {
-#ifdef CONFIG_PCI
- if (!pcic_present()) {
- prom_printf("Neither SBUS nor PCI found.\n");
- prom_halt();
- }
- return 0;
-#else
- /* No reason to run further - the data access trap will occur. */
- panic("sbus not found");
-#endif
+ sdev->bus = sbus;
+ sdev->parent = parent;
+
+ fill_sbus_device(dp, sdev);
+
+ walk_children(dp, sdev, sbus);
}
+ dp = dp->sibling;
}
+}
- /* Ok, we've found the first one, allocate first SBus struct
- * and place in chain.
- */
- sbus = sbus_root = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
- sbus->next = NULL;
- sbus->prom_node = nd;
- this_sbus = nd;
+static void __init build_one_sbus(struct device_node *dp, int num_sbus)
+{
+ struct sbus_bus *sbus;
+ unsigned int sbus_clock;
+ struct device_node *dev_dp;
- if(iommund && sparc_cpu_model != sun4u && sparc_cpu_model != sun4d)
- iommu_init(iommund, sbus);
+ sbus = kzalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
+ if (!sbus)
+ return;
- /* Loop until we find no more SBUS's */
- while(this_sbus) {
-#ifdef CONFIG_SPARC64
- /* IOMMU hides inside SBUS/SYSIO prom node on Ultra. */
- if(sparc_cpu_model == sun4u) {
- extern void sbus_iommu_init(int prom_node, struct sbus_bus *sbus);
+ sbus_insert(sbus, &sbus_root);
+ sbus->prom_node = dp->node;
- sbus_iommu_init(this_sbus, sbus);
- }
-#endif /* CONFIG_SPARC64 */
-
-#ifdef CONFIG_SPARC32
- if (sparc_cpu_model == sun4d)
- iounit_init(this_sbus, iommund, sbus);
-#endif /* CONFIG_SPARC32 */
- printk("sbus%d: ", num_sbus);
- sbus_clock = prom_getint(this_sbus, "clock-frequency");
- if(sbus_clock == -1)
- sbus_clock = (25*1000*1000);
- printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
- (int) (((sbus_clock/1000)%1000 != 0) ?
- (((sbus_clock/1000)%1000) + 1000) : 0));
-
- prom_getstring(this_sbus, "name",
- sbus->prom_name, sizeof(sbus->prom_name));
- sbus->clock_freq = sbus_clock;
-#ifdef CONFIG_SPARC32
- if (sparc_cpu_model == sun4d) {
- sbus->devid = prom_getint(iommund, "device-id");
- sbus->board = prom_getint(iommund, "board#");
- }
-#endif
-
- sbus_bus_ranges_init(iommund, sbus);
-
- sbus_devs = prom_getchild(this_sbus);
- if (!sbus_devs) {
- sbus->devices = NULL;
- goto next_bus;
- }
+ sbus_setup_iommu(sbus, dp);
- sbus->devices = kmalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
-
- this_dev = sbus->devices;
- this_dev->next = NULL;
-
- this_dev->bus = sbus;
- this_dev->parent = NULL;
- fill_sbus_device(sbus_devs, this_dev);
-
- /* Should we traverse for children? */
- if(prom_getchild(sbus_devs)) {
- /* Allocate device node */
- this_dev->child = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- /* Fill it */
- this_dev->child->bus = sbus;
- this_dev->child->next = NULL;
- fill_sbus_device(prom_getchild(sbus_devs),
- this_dev->child);
- sbus_do_child_siblings(prom_getchild(sbus_devs),
- this_dev->child,
- this_dev,
- sbus);
- } else {
- this_dev->child = NULL;
- }
+ printk("sbus%d: ", num_sbus);
- while((sbus_devs = prom_getsibling(sbus_devs)) != 0) {
- /* Allocate device node */
- this_dev->next = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- this_dev = this_dev->next;
- this_dev->next = NULL;
-
- /* Fill it */
- this_dev->bus = sbus;
- this_dev->parent = NULL;
- fill_sbus_device(sbus_devs, this_dev);
-
- /* Is there a child node hanging off of us? */
- if(prom_getchild(sbus_devs)) {
- /* Get new device struct */
- this_dev->child = kmalloc(sizeof(struct sbus_dev),
- GFP_ATOMIC);
- /* Fill it */
- this_dev->child->bus = sbus;
- this_dev->child->next = NULL;
- fill_sbus_device(prom_getchild(sbus_devs),
- this_dev->child);
- sbus_do_child_siblings(prom_getchild(sbus_devs),
- this_dev->child,
- this_dev,
- sbus);
- } else {
- this_dev->child = NULL;
- }
+ sbus_clock = of_getintprop_default(dp, "clock-frequency",
+ (25*1000*1000));
+ sbus->clock_freq = sbus_clock;
+
+ printk("Clock %d.%d MHz\n", (int) ((sbus_clock/1000)/1000),
+ (int) (((sbus_clock/1000)%1000 != 0) ?
+ (((sbus_clock/1000)%1000) + 1000) : 0));
+
+ strcpy(sbus->prom_name, dp->name);
+
+ sbus_setup_arch_props(sbus, dp);
+
+ sbus_bus_ranges_init(dp, sbus);
+
+ sbus->ofdev.node = dp;
+ sbus->ofdev.dev.parent = NULL;
+ sbus->ofdev.dev.bus = &sbus_bus_type;
+ sprintf(sbus->ofdev.dev.bus_id, "sbus%d", num_sbus);
+
+ if (of_device_register(&sbus->ofdev) != 0)
+ printk(KERN_DEBUG "sbus: device registration error for %s!\n",
+ sbus->ofdev.dev.bus_id);
+
+ dev_dp = dp->child;
+ while (dev_dp) {
+ struct sbus_dev *sdev;
+
+ sdev = kzalloc(sizeof(struct sbus_dev), GFP_ATOMIC);
+ if (sdev) {
+ sdev_insert(sdev, &sbus->devices);
+
+ sdev->bus = sbus;
+ sdev->parent = NULL;
+ fill_sbus_device(dev_dp, sdev);
+
+ walk_children(dev_dp, sdev, sbus);
}
+ dev_dp = dev_dp->sibling;
+ }
- /* Walk all devices and apply parent ranges. */
- sbus_fixup_all_regs(sbus->devices);
+ sbus_fixup_all_regs(sbus->devices);
- dvma_init(sbus);
- next_bus:
+ dvma_init(sbus);
+}
+
+static int __init sbus_init(void)
+{
+ struct device_node *dp;
+ const char *sbus_name = "sbus";
+ int num_sbus = 0;
+
+ if (sbus_arch_preinit())
+ return 0;
+
+ if (sparc_cpu_model == sun4d)
+ sbus_name = "sbi";
+
+ for_each_node_by_name(dp, sbus_name) {
+ build_one_sbus(dp, num_sbus);
num_sbus++;
- if(sparc_cpu_model == sun4u) {
- this_sbus = prom_getsibling(this_sbus);
- if(!this_sbus)
- break;
- this_sbus = prom_searchsiblings(this_sbus, "sbus");
- } else if(sparc_cpu_model == sun4d) {
- iommund = prom_getsibling(iommund);
- if(!iommund)
- break;
- iommund = prom_searchsiblings(iommund, "io-unit");
- if(!iommund)
- break;
- this_sbus = prom_searchsiblings(prom_getchild(iommund), "sbi");
- } else {
- this_sbus = prom_getsibling(this_sbus);
- if(!this_sbus)
- break;
- this_sbus = prom_searchsiblings(this_sbus, "sbus");
- }
- if(this_sbus) {
- sbus->next = kmalloc(sizeof(struct sbus_bus), GFP_ATOMIC);
- sbus = sbus->next;
- sbus->next = NULL;
- sbus->prom_node = this_sbus;
- } else {
- break;
- }
- } /* while(this_sbus) */
- if (sparc_cpu_model == sun4d) {
- extern void sun4d_init_sbi_irq(void);
- sun4d_init_sbi_irq();
- }
-
-#ifdef CONFIG_SPARC64
- if (sparc_cpu_model == sun4u) {
- firetruck_init();
}
-#endif
-#ifdef CONFIG_SUN_AUXIO
- if (sparc_cpu_model == sun4u)
- auxio_probe ();
-#endif
-#ifdef CONFIG_SPARC64
- if (sparc_cpu_model == sun4u) {
- extern void clock_probe(void);
-
- clock_probe();
- }
-#endif
+
+ sbus_arch_postinit();
return 0;
}
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index b003baf8d40..5a9475e56d0 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -2122,7 +2122,7 @@ static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id
TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH)));
/* Now setup the interrupt handler */
- retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev);
+ retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev);
if (retval) {
TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
goto out_remove_host;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 17dbd4ac869..f3a5f422a8e 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2397,7 +2397,7 @@ static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *
printk(KERN_WARNING "3w-xxxx: scsi%d: Found a 3ware Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, tw_dev->base_addr, pdev->irq);
/* Now setup the interrupt handler */
- retval = request_irq(pdev->irq, tw_interrupt, SA_SHIRQ, "3w-xxxx", tw_dev);
+ retval = request_irq(pdev->irq, tw_interrupt, IRQF_SHARED, "3w-xxxx", tw_dev);
if (retval) {
printk(KERN_WARNING "3w-xxxx: Error requesting IRQ.");
goto out_remove_host;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 3c683dc2354..657a3ab7539 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -114,7 +114,6 @@
* */
#define NCR_700_VERSION "2.8"
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -174,6 +173,7 @@ STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
+STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt);
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
@@ -183,10 +183,6 @@ STATIC struct device_attribute *NCR_700_dev_attrs[];
STATIC struct scsi_transport_template *NCR_700_transport_template = NULL;
-struct NCR_700_sense {
- unsigned char cmnd[MAX_COMMAND_SIZE];
-};
-
static char *NCR_700_phase[] = {
"",
"after selection",
@@ -334,6 +330,7 @@ NCR_700_detect(struct scsi_host_template *tpnt,
tpnt->use_clustering = ENABLE_CLUSTERING;
tpnt->slave_configure = NCR_700_slave_configure;
tpnt->slave_destroy = NCR_700_slave_destroy;
+ tpnt->slave_alloc = NCR_700_slave_alloc;
tpnt->change_queue_depth = NCR_700_change_queue_depth;
tpnt->change_queue_type = NCR_700_change_queue_type;
@@ -612,9 +609,10 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
- NCR_700_unmap(hostdata, SCp, slot);
+ dma_unmap_single(hostdata->dev, slot->pCmd,
+ sizeof(SCp->cmnd), DMA_TO_DEVICE);
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
- struct NCR_700_sense *sense = SCp->device->hostdata;
+ char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_700_DEBUG
printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
SCp, SCp->cmnd[7], result);
@@ -625,10 +623,9 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
/* restore the old result if the request sense was
* successful */
if(result == 0)
- result = sense->cmnd[7];
+ result = cmnd[7];
} else
- dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ NCR_700_unmap(hostdata, SCp, slot);
free_slot(slot, hostdata);
#ifdef NCR_700_DEBUG
@@ -970,14 +967,15 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
status_byte(hostdata->status[0]) == COMMAND_TERMINATED) {
struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
- if(SCp->cmnd[0] == REQUEST_SENSE) {
+ if(slot->flags == NCR_700_FLAG_AUTOSENSE) {
/* OOPS: bad device, returning another
* contingent allegiance condition */
scmd_printk(KERN_ERR, SCp,
"broken device is looping in contingent allegiance: ignoring\n");
NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
} else {
- struct NCR_700_sense *sense = SCp->device->hostdata;
+ char *cmnd =
+ NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_DEBUG
scsi_print_command(SCp);
printk(" cmd %p has status %d, requesting sense\n",
@@ -995,21 +993,21 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
sizeof(SCp->cmnd),
DMA_TO_DEVICE);
- sense->cmnd[0] = REQUEST_SENSE;
- sense->cmnd[1] = (SCp->device->lun & 0x7) << 5;
- sense->cmnd[2] = 0;
- sense->cmnd[3] = 0;
- sense->cmnd[4] = sizeof(SCp->sense_buffer);
- sense->cmnd[5] = 0;
+ cmnd[0] = REQUEST_SENSE;
+ cmnd[1] = (SCp->device->lun & 0x7) << 5;
+ cmnd[2] = 0;
+ cmnd[3] = 0;
+ cmnd[4] = sizeof(SCp->sense_buffer);
+ cmnd[5] = 0;
/* Here's a quiet hack: the
* REQUEST_SENSE command is six bytes,
* so store a flag indicating that
* this was an internal sense request
* and the original status at the end
* of the command */
- sense->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
- sense->cmnd[7] = hostdata->status[0];
- slot->pCmd = dma_map_single(hostdata->dev, sense->cmnd, sizeof(sense->cmnd), DMA_TO_DEVICE);
+ cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
+ cmnd[7] = hostdata->status[0];
+ slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE);
slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
@@ -1531,7 +1529,7 @@ NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
/* clear all the negotiated parameters */
__shost_for_each_device(SDp, host)
- SDp->hostdata = NULL;
+ NCR_700_clear_flag(SDp, ~0);
/* clear all the slots and their pending commands */
for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
@@ -2036,7 +2034,17 @@ NCR_700_set_offset(struct scsi_target *STp, int offset)
spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
}
+STATIC int
+NCR_700_slave_alloc(struct scsi_device *SDp)
+{
+ SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters),
+ GFP_KERNEL);
+ if (!SDp->hostdata)
+ return -ENOMEM;
+
+ return 0;
+}
STATIC int
NCR_700_slave_configure(struct scsi_device *SDp)
@@ -2044,11 +2052,6 @@ NCR_700_slave_configure(struct scsi_device *SDp)
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
- SDp->hostdata = kmalloc(GFP_KERNEL, sizeof(struct NCR_700_sense));
-
- if (!SDp->hostdata)
- return -ENOMEM;
-
/* to do here: allocate memory; build a queue_full list */
if(SDp->tagged_supported) {
scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 7f22a06fe5e..97ebe71b701 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -12,7 +12,7 @@
#include <asm/io.h>
#include <scsi/scsi_device.h>
-
+#include <scsi/scsi_cmnd.h>
/* Turn on for general debugging---too verbose for normal use */
#undef NCR_700_DEBUG
@@ -76,11 +76,16 @@ struct NCR_700_SG_List {
#define SCRIPT_RETURN 0x90080000
};
-/* We use device->hostdata to store negotiated parameters. This is
- * supposed to be a pointer to a device private area, but we cannot
- * really use it as such since it will never be freed, so just use the
- * 32 bits to cram the information. The SYNC negotiation sequence looks
- * like:
+struct NCR_700_Device_Parameters {
+ /* space for creating a request sense command. Really, except
+ * for the annoying SCSI-2 requirement for LUN information in
+ * cmnd[1], this could be in static storage */
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ __u8 depth;
+};
+
+
+/* The SYNC negotiation sequence looks like:
*
* If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the
* initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION
@@ -98,19 +103,26 @@ struct NCR_700_SG_List {
#define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17)
#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19)
+static inline char *NCR_700_get_sense_cmnd(struct scsi_device *SDp)
+{
+ struct NCR_700_Device_Parameters *hostdata = SDp->hostdata;
+
+ return hostdata->cmnd;
+}
+
static inline void
NCR_700_set_depth(struct scsi_device *SDp, __u8 depth)
{
- long l = (long)SDp->hostdata;
+ struct NCR_700_Device_Parameters *hostdata = SDp->hostdata;
- l &= 0xffff00ff;
- l |= 0xff00 & (depth << 8);
- SDp->hostdata = (void *)l;
+ hostdata->depth = depth;
}
static inline __u8
NCR_700_get_depth(struct scsi_device *SDp)
{
- return ((((unsigned long)SDp->hostdata) & 0xff00)>>8);
+ struct NCR_700_Device_Parameters *hostdata = SDp->hostdata;
+
+ return hostdata->depth;
}
static inline int
NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag)
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index 765769a629e..acf292736b4 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -232,7 +232,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <asm/setup.h>
@@ -1071,7 +1070,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
NCR53c7x0_driver_init (host);
- if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7xx", host))
+ if (request_irq(host->irq, NCR53c7x0_intr, IRQF_SHARED, "53c7xx", host))
{
printk("scsi%d : IRQ%d not free, detaching\n",
host->host_no, host->irq);
@@ -3452,12 +3451,12 @@ create_cmd (Scsi_Cmnd *cmd) {
for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4,
cmd_dataout += 4, ++i) {
u32 vbuf = cmd->use_sg
- ? (u32)page_address(((struct scatterlist *)cmd->buffer)[i].page)+
- ((struct scatterlist *)cmd->buffer)[i].offset
+ ? (u32)page_address(((struct scatterlist *)cmd->request_buffer)[i].page)+
+ ((struct scatterlist *)cmd->request_buffer)[i].offset
: (u32)(cmd->request_buffer);
u32 bbuf = virt_to_bus((void *)vbuf);
u32 count = cmd->use_sg ?
- ((struct scatterlist *)cmd->buffer)[i].length :
+ ((struct scatterlist *)cmd->request_buffer)[i].length :
cmd->request_bufflen;
/*
@@ -4233,7 +4232,7 @@ restart:
* Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
* the same IRQ line.
*
- * Inputs : Since we're using the SA_INTERRUPT interrupt handler
+ * Inputs : Since we're using the IRQF_DISABLED interrupt handler
* semantics, irq indicates the interrupt which invoked
* this handler.
*
@@ -5418,7 +5417,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
if ((buffers = cmd->use_sg)) {
for (offset = 0,
- segment = (struct scatterlist *) cmd->buffer;
+ segment = (struct scatterlist *) cmd->request_buffer;
buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) &&
(ptr < ((char *)page_address(segment->page)+segment->offset+segment->length)))));
--buffers, offset += segment->length, ++segment)
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index bde3d5834ad..4ea49fd7965 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -29,7 +29,6 @@
#define BusLogic_DriverVersion "2.1.16"
#define BusLogic_DriverDate "18 July 2002"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -663,7 +662,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
particular standard ISA I/O Address need not be probed.
*/
PrimaryProbeInfo->IO_Address = 0;
- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
+ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter;
struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation;
enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest;
@@ -763,7 +762,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
PrimaryProbeInfo->Bus = Bus;
PrimaryProbeInfo->Device = Device;
PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
- PrimaryProbeInfo->PCI_Device = PCI_Device;
+ PrimaryProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
PCIMultiMasterCount++;
} else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) {
struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
@@ -774,7 +773,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
- ProbeInfo->PCI_Device = PCI_Device;
+ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
NonPrimaryPCIMultiMasterCount++;
PCIMultiMasterCount++;
} else
@@ -824,7 +823,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
noting the PCI bus location and assigned IRQ Channel.
*/
PCI_Device = NULL;
- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
+ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
unsigned char Bus;
unsigned char Device;
unsigned int IRQ_Channel;
@@ -851,7 +850,7 @@ static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAd
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
- ProbeInfo->PCI_Device = PCI_Device;
+ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
break;
}
}
@@ -875,7 +874,7 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAda
/*
Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
*/
- while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
+ while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
unsigned char Bus;
unsigned char Device;
unsigned int IRQ_Channel;
@@ -924,7 +923,7 @@ static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAda
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
- ProbeInfo->PCI_Device = PCI_Device;
+ ProbeInfo->PCI_Device = pci_dev_get(PCI_Device);
FlashPointCount++;
} else
BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL);
@@ -1845,7 +1844,7 @@ static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *Hos
/*
Acquire shared access to the IRQ Channel.
*/
- if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) {
+ if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, IRQF_SHARED, HostAdapter->FullModelName, HostAdapter) < 0) {
BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->IRQ_Channel);
return false;
}
@@ -1891,6 +1890,7 @@ static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter)
*/
if (HostAdapter->MailboxSpace)
pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle);
+ pci_dev_put(HostAdapter->PCI_Device);
HostAdapter->MailboxSpace = NULL;
HostAdapter->MailboxSpaceHandle = 0;
HostAdapter->MailboxSize = 0;
@@ -2177,6 +2177,7 @@ static int __init BusLogic_init(void)
{
int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
struct BusLogic_HostAdapter *PrototypeHostAdapter;
+ int ret = 0;
#ifdef MODULE
if (BusLogic)
@@ -2283,25 +2284,49 @@ static int __init BusLogic_init(void)
perform Target Device Inquiry.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
- BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) {
+ BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
+ BusLogic_AcquireResources(HostAdapter) &&
+ BusLogic_CreateInitialCCBs(HostAdapter) &&
+ BusLogic_InitializeHostAdapter(HostAdapter) &&
+ BusLogic_TargetDeviceInquiry(HostAdapter)) {
/*
Initialization has been completed successfully. Release and
re-register usage of the I/O Address range so that the Model
Name of the Host Adapter will appear, and initialize the SCSI
Host structure.
*/
- release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
- if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) {
- printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address);
+ release_region(HostAdapter->IO_Address,
+ HostAdapter->AddressCount);
+ if (!request_region(HostAdapter->IO_Address,
+ HostAdapter->AddressCount,
+ HostAdapter->FullModelName)) {
+ printk(KERN_WARNING
+ "BusLogic: Release and re-register of "
+ "port 0x%04lx failed \n",
+ (unsigned long)HostAdapter->IO_Address);
BusLogic_DestroyCCBs(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
+ ret = -ENOMEM;
} else {
- BusLogic_InitializeHostStructure(HostAdapter, Host);
- scsi_add_host(Host, HostAdapter->PCI_Device ? &HostAdapter->PCI_Device->dev : NULL);
- scsi_scan_host(Host);
- BusLogicHostAdapterCount++;
+ BusLogic_InitializeHostStructure(HostAdapter,
+ Host);
+ if (scsi_add_host(Host, HostAdapter->PCI_Device
+ ? &HostAdapter->PCI_Device->dev
+ : NULL)) {
+ printk(KERN_WARNING
+ "BusLogic: scsi_add_host()"
+ "failed!\n");
+ BusLogic_DestroyCCBs(HostAdapter);
+ BusLogic_ReleaseResources(HostAdapter);
+ list_del(&HostAdapter->host_list);
+ scsi_host_put(Host);
+ ret = -ENODEV;
+ } else {
+ scsi_scan_host(Host);
+ BusLogicHostAdapterCount++;
+ }
}
} else {
/*
@@ -2316,12 +2341,13 @@ static int __init BusLogic_init(void)
BusLogic_ReleaseResources(HostAdapter);
list_del(&HostAdapter->host_list);
scsi_host_put(Host);
+ ret = -ENODEV;
}
}
kfree(PrototypeHostAdapter);
kfree(BusLogic_ProbeInfoList);
BusLogic_ProbeInfoList = NULL;
- return 0;
+ return ret;
}
@@ -2955,6 +2981,7 @@ static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRou
}
+#if 0
/*
BusLogic_AbortCommand aborts Command if possible.
*/
@@ -3025,6 +3052,7 @@ static int BusLogic_AbortCommand(struct scsi_cmnd *Command)
return SUCCESS;
}
+#endif
/*
BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all
currently executing SCSI Commands as having been Reset.
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 1aaa6569eda..9792e5af525 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -28,7 +28,6 @@
#ifndef _BUSLOGIC_H
#define _BUSLOGIC_H
-#include <linux/config.h>
#ifndef PACKED
#define PACKED __attribute__((packed))
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 8e3d949b711..7c006804958 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -15,7 +15,6 @@
*/
-#include <linux/config.h>
#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 44728ae3fe7..c4dfcc91ddd 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -27,6 +27,11 @@ config SCSI
However, do not compile this as a module if your root file system
(the one containing the directory /) is located on a SCSI device.
+config SCSI_NETLINK
+ bool
+ default n
+ select NET
+
config SCSI_PROC_FS
bool "legacy /proc/scsi/ support"
depends on SCSI && PROC_FS
@@ -209,7 +214,7 @@ config SCSI_LOGGING
there should be no noticeable performance impact as long as you have
logging turned off.
-menu "SCSI Transport Attributes"
+menu "SCSI Transports"
depends on SCSI
config SCSI_SPI_ATTRS
@@ -222,6 +227,7 @@ config SCSI_SPI_ATTRS
config SCSI_FC_ATTRS
tristate "FiberChannel Transport Attributes"
depends on SCSI
+ select SCSI_NETLINK
help
If you wish to export transport-specific information about
each attached FiberChannel device to sysfs, say Y.
@@ -242,6 +248,8 @@ config SCSI_SAS_ATTRS
If you wish to export transport-specific information about
each attached SAS device to sysfs, say Y.
+source "drivers/scsi/libsas/Kconfig"
+
endmenu
menu "SCSI low-level drivers"
@@ -431,6 +439,7 @@ config SCSI_AIC7XXX_OLD
module will be called aic7xxx_old.
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
+source "drivers/scsi/aic94xx/Kconfig"
# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
@@ -469,68 +478,21 @@ config SCSI_IN2000
To compile this driver as a module, choose M here: the
module will be called in2000.
-source "drivers/scsi/megaraid/Kconfig.megaraid"
-
-config SCSI_SATA
- tristate "Serial ATA (SATA) support"
- depends on SCSI
- help
- This driver family supports Serial ATA host controllers
- and devices.
-
- If unsure, say N.
-
-config SCSI_SATA_AHCI
- tristate "AHCI SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for AHCI Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_SVW
- tristate "ServerWorks Frodo / Apple K2 SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Broadcom/Serverworks/Apple K2
- SATA support.
-
- If unsure, say N.
-
-config SCSI_ATA_PIIX
- tristate "Intel PIIX/ICH SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for ICH5 Serial ATA.
- If PATA support was enabled previously, this enables
- support for select Intel PIIX/ICH PATA host controllers.
-
- If unsure, say N.
-
-config SCSI_SATA_MV
- tristate "Marvell SATA support (HIGHLY EXPERIMENTAL)"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for the Marvell Serial ATA family.
- Currently supports 88SX[56]0[48][01] chips.
-
- If unsure, say N.
-
-config SCSI_SATA_NV
- tristate "NVIDIA SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
+config SCSI_ARCMSR
+ tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support"
+ depends on PCI && SCSI
help
- This option enables support for NVIDIA Serial ATA.
+ This driver supports all of ARECA's SATA RAID controller cards.
+ This is an ARECA-maintained driver by Erich Chen.
+ If you have any problems, please mail to: < erich@areca.com.tw >
+ Areca supports Linux RAID config tools.
- If unsure, say N.
+ < http://www.areca.com.tw >
-config SCSI_PDC_ADMA
- tristate "Pacific Digital ADMA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Pacific Digital ADMA controllers
+ To compile this driver as a module, choose M here: the
+ module will be called arcmsr (modprobe arcmsr).
- If unsure, say N.
+source "drivers/scsi/megaraid/Kconfig.megaraid"
config SCSI_HPTIOP
tristate "HighPoint RocketRAID 3xxx Controller support"
@@ -542,83 +504,6 @@ config SCSI_HPTIOP
To compile this driver as a module, choose M here; the module
will be called hptiop. If unsure, say N.
-config SCSI_SATA_QSTOR
- tristate "Pacific Digital SATA QStor support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Pacific Digital Serial ATA QStor.
-
- If unsure, say N.
-
-config SCSI_SATA_PROMISE
- tristate "Promise SATA TX2/TX4 support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Promise Serial ATA TX2/TX4.
-
- If unsure, say N.
-
-config SCSI_SATA_SX4
- tristate "Promise SATA SX4 support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for Promise Serial ATA SX4.
-
- If unsure, say N.
-
-config SCSI_SATA_SIL
- tristate "Silicon Image SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for Silicon Image Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_SIL24
- tristate "Silicon Image 3124/3132 SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for Silicon Image 3124/3132 Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_SIS
- tristate "SiS 964/180 SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for SiS Serial ATA 964/180.
-
- If unsure, say N.
-
-config SCSI_SATA_ULI
- tristate "ULi Electronics SATA support"
- depends on SCSI_SATA && PCI && EXPERIMENTAL
- help
- This option enables support for ULi Electronics SATA.
-
- If unsure, say N.
-
-config SCSI_SATA_VIA
- tristate "VIA SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for VIA Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_VITESSE
- tristate "VITESSE VSC-7174 / INTEL 31244 SATA support"
- depends on SCSI_SATA && PCI
- help
- This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA.
-
- If unsure, say N.
-
-config SCSI_SATA_INTEL_COMBINED
- bool
- depends on IDE=y && !BLK_DEV_IDE_SATA && (SCSI_SATA_AHCI || SCSI_ATA_PIIX)
- default y
-
config SCSI_BUSLOGIC
tristate "BusLogic SCSI support"
depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
@@ -1053,6 +938,13 @@ config 53C700_LE_ON_BE
depends on SCSI_LASI700
default y
+config SCSI_STEX
+ tristate "Promise SuperTrak EX Series support"
+ depends on PCI && SCSI
+ ---help---
+ This driver supports Promise SuperTrak EX8350/8300/16350/16300
+ Storage controllers.
+
config SCSI_SYM53C8XX_2
tristate "SYM53C8XX Version 2 SCSI support"
depends on PCI && SCSI
@@ -1169,7 +1061,7 @@ config SCSI_NCR_Q720
you do not have this SCSI card, so say N.
config SCSI_NCR53C8XX_DEFAULT_TAGS
- int " default tagged command queue depth"
+ int "default tagged command queue depth"
depends on SCSI_ZALON || SCSI_NCR_Q720
default "8"
---help---
@@ -1195,7 +1087,7 @@ config SCSI_NCR53C8XX_DEFAULT_TAGS
There is no safe option other than using good SCSI devices.
config SCSI_NCR53C8XX_MAX_TAGS
- int " maximum number of queued commands"
+ int "maximum number of queued commands"
depends on SCSI_ZALON || SCSI_NCR_Q720
default "32"
---help---
@@ -1212,7 +1104,7 @@ config SCSI_NCR53C8XX_MAX_TAGS
There is no safe option and the default answer is recommended.
config SCSI_NCR53C8XX_SYNC
- int " synchronous transfers frequency in MHz"
+ int "synchronous transfers frequency in MHz"
depends on SCSI_ZALON || SCSI_NCR_Q720
default "20"
---help---
@@ -1246,7 +1138,7 @@ config SCSI_NCR53C8XX_SYNC
terminations and SCSI conformant devices.
config SCSI_NCR53C8XX_PROFILE
- bool " enable profiling"
+ bool "enable profiling"
depends on SCSI_ZALON || SCSI_NCR_Q720
help
This option allows you to enable profiling information gathering.
@@ -1257,7 +1149,7 @@ config SCSI_NCR53C8XX_PROFILE
The normal answer therefore is N.
config SCSI_NCR53C8XX_NO_DISCONNECT
- bool " not allow targets to disconnect"
+ bool "not allow targets to disconnect"
depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
help
This option is only provided for safety if you suspect some SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 84d546323dc..1ef951be7a5 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -32,8 +32,10 @@ obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o
obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o
obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o
obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o
+obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/
obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o
+obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o
obj-$(CONFIG_SCSI_AMIGA7XX) += amiga7xx.o 53c7xx.o
obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o
obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o
@@ -58,6 +60,7 @@ obj-$(CONFIG_SCSI_PSI240I) += psi240i.o
obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o
obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o
obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o
+obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/
obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o
obj-$(CONFIG_SCSI_AHA152X) += aha152x.o
obj-$(CONFIG_SCSI_AHA1542) += aha1542.o
@@ -66,6 +69,7 @@ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/
obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/
obj-$(CONFIG_SCSI_AACRAID) += aacraid/
obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o
+obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/
obj-$(CONFIG_SCSI_IPS) += ips.o
obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o
obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
@@ -121,22 +125,8 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_NSP32) += nsp32.o
obj-$(CONFIG_SCSI_IPR) += ipr.o
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/
-obj-$(CONFIG_SCSI_SATA_AHCI) += libata.o ahci.o
-obj-$(CONFIG_SCSI_SATA_SVW) += libata.o sata_svw.o
-obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
-obj-$(CONFIG_SCSI_SATA_PROMISE) += libata.o sata_promise.o
-obj-$(CONFIG_SCSI_SATA_QSTOR) += libata.o sata_qstor.o
-obj-$(CONFIG_SCSI_SATA_SIL) += libata.o sata_sil.o
-obj-$(CONFIG_SCSI_SATA_SIL24) += libata.o sata_sil24.o
-obj-$(CONFIG_SCSI_SATA_VIA) += libata.o sata_via.o
-obj-$(CONFIG_SCSI_SATA_VITESSE) += libata.o sata_vsc.o
-obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o
-obj-$(CONFIG_SCSI_SATA_SX4) += libata.o sata_sx4.o
-obj-$(CONFIG_SCSI_SATA_NV) += libata.o sata_nv.o
-obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o
-obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o
-obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o
obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o
+obj-$(CONFIG_SCSI_STEX) += stex.o
obj-$(CONFIG_ARM) += arm/
@@ -154,6 +144,7 @@ scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
scsicam.o scsi_error.o scsi_lib.o \
scsi_scan.o scsi_sysfs.o \
scsi_devinfo.o
+scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
@@ -165,7 +156,6 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
zalon7xx-objs := zalon.o ncr53c8xx.o
NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o
-libata-objs := libata-core.o libata-scsi.o libata-bmdma.o libata-eh.o
oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index fa57e0b4a5f..616810ad17d 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -500,7 +500,7 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
/*
* Function : int should_disconnect (unsigned char cmd)
*
- * Purpose : decide weather a command would normally disconnect or
+ * Purpose : decide whether a command would normally disconnect or
* not, since if it won't disconnect we should go to sleep.
*
* Input : cmd - opcode of SCSI command
@@ -585,7 +585,7 @@ static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
NCR5380_setup(instance);
for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
- if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0))
+ if ((mask & possible) && (request_irq(i, &probe_intr, IRQF_DISABLED, "NCR-probe", NULL) == 0))
trying_irqs |= mask;
timeout = jiffies + (250 * HZ / 1000);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index c7dd0154d01..bdc6bb262bc 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -23,7 +23,6 @@
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
@@ -912,7 +911,7 @@ static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
sp->SCp.ptr =
(char *) virt_to_phys(sp->request_buffer);
} else {
- sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = sp->use_sg - 1;
sp->SCp.this_residual = sp->SCp.buffer->length;
if (esp->dma_mmu_get_scsi_sgl)
@@ -2153,29 +2152,23 @@ static int esp_do_data_finale(struct NCR_ESP *esp,
*/
static int esp_should_clear_sync(Scsi_Cmnd *sp)
{
- unchar cmd1 = sp->cmnd[0];
- unchar cmd2 = sp->data_cmnd[0];
+ unchar cmd = sp->cmnd[0];
/* These cases are for spinning up a disk and
* waiting for that spinup to complete.
*/
- if(cmd1 == START_STOP ||
- cmd2 == START_STOP)
+ if(cmd == START_STOP)
return 0;
- if(cmd1 == TEST_UNIT_READY ||
- cmd2 == TEST_UNIT_READY)
+ if(cmd == TEST_UNIT_READY)
return 0;
/* One more special case for SCSI tape drives,
* this is what is used to probe the device for
* completion of a rewind or tape load operation.
*/
- if(sp->device->type == TYPE_TAPE) {
- if(cmd1 == MODE_SENSE ||
- cmd2 == MODE_SENSE)
- return 0;
- }
+ if(sp->device->type == TYPE_TAPE && cmd == MODE_SENSE)
+ return 0;
return 1;
}
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 65a9b377a41..481653c977c 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -13,7 +13,6 @@
#ifndef NCR53C9X_H
#define NCR53C9X_H
-#include <linux/config.h>
#include <linux/interrupt.h>
/* djweis for mac driver */
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index 577e6349977..d05681f9d81 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -114,7 +114,7 @@ MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
MODULE_LICENSE("GPL");
module_param(NCR_D700, charp, 0);
-static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
+static __u8 __devinitdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
{ [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 };
#ifdef MODULE
@@ -173,7 +173,7 @@ struct NCR_D700_private {
char pad;
};
-static int
+static int __devinit
NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
int slot, u32 region, int differential)
{
@@ -243,7 +243,7 @@ NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
* essentially connectecd to the MCA bus independently, it is easier
* to set them up as two separate host adapters, rather than one
* adapter with two channels */
-static int
+static int __devinit
NCR_D700_probe(struct device *dev)
{
struct NCR_D700_private *p;
@@ -320,7 +320,7 @@ NCR_D700_probe(struct device *dev)
memset(p, '\0', sizeof(*p));
p->dev = dev;
snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
- if (request_irq(irq, NCR_D700_intr, SA_SHIRQ, p->name, p)) {
+ if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) {
printk(KERN_ERR "D700: request_irq failed\n");
kfree(p);
return -EBUSY;
@@ -329,7 +329,7 @@ NCR_D700_probe(struct device *dev)
for (i = 0; i < 2; i++) {
int err;
- if ((err = NCR_D700_probe_one(p, i, slot, irq,
+ if ((err = NCR_D700_probe_one(p, i, irq, slot,
offset_addr + (0x80 * i),
differential)) != 0)
printk("D700: SIOP%d: probe failed, error = %d\n",
@@ -349,7 +349,7 @@ NCR_D700_probe(struct device *dev)
return 0;
}
-static void
+static void __devexit
NCR_D700_remove_one(struct Scsi_Host *host)
{
scsi_remove_host(host);
@@ -359,7 +359,7 @@ NCR_D700_remove_one(struct Scsi_Host *host)
release_region(host->base, 64);
}
-static int
+static int __devexit
NCR_D700_remove(struct device *dev)
{
struct NCR_D700_private *p = dev_get_drvdata(dev);
@@ -380,7 +380,7 @@ static struct mca_driver NCR_D700_driver = {
.name = "NCR_D700",
.bus = &mca_bus_type,
.probe = NCR_D700_probe,
- .remove = NCR_D700_remove,
+ .remove = __devexit_p(NCR_D700_remove),
},
};
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index 9d18ec90510..c39ffbb86e3 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -265,7 +265,7 @@ NCR_Q720_probe(struct device *dev)
p->irq = irq;
p->siops = siops;
- if (request_irq(irq, NCR_Q720_intr, SA_SHIRQ, "NCR_Q720", p)) {
+ if (request_irq(irq, NCR_Q720_intr, IRQF_SHARED, "NCR_Q720", p)) {
printk(KERN_ERR "NCR_Q720: request irq %d failed\n", irq);
goto out_release;
}
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 3dce21c7873..d7e9fab54c6 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1120,7 +1120,7 @@ static int __devinit inia100_probe_one(struct pci_dev *pdev,
shost->sg_tablesize = TOTAL_SG_ENTRY;
/* Initial orc chip */
- error = request_irq(pdev->irq, inia100_intr, SA_SHIRQ,
+ error = request_irq(pdev->irq, inia100_intr, IRQF_SHARED,
"inia100", shost);
if (error < 0) {
printk(KERN_WARNING "inia100: unable to get irq %d\n",
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 54996eaae97..08540692860 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -40,7 +40,7 @@ static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
return IRQ_HANDLED;
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -115,7 +115,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
/* disable SCSI interrupts */
@@ -208,7 +208,7 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
regs.SASR = &(DMA(instance)->SASR);
regs.SCMD = &(DMA(instance)->SCMD);
wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
- request_irq(IRQ_AMIGA_PORTS, a2091_intr, SA_SHIRQ, "A2091 SCSI",
+ request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI",
instance);
DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
num_a2091++;
@@ -217,7 +217,7 @@ int __init a2091_detect(struct scsi_host_template *tpnt)
return num_a2091;
}
-static int a2091_bus_reset(Scsi_Cmnd *cmd)
+static int a2091_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
index 22d6a13dd8b..fe809bc88d7 100644
--- a/drivers/scsi/a2091.h
+++ b/drivers/scsi/a2091.h
@@ -13,10 +13,6 @@
int a2091_detect(struct scsi_host_template *);
int a2091_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index f425d424bf0..7bf46d40b56 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -44,7 +44,7 @@ static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
return IRQ_NONE;
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -110,8 +110,8 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
- int status)
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
{
/* disable SCSI interrupts */
unsigned short cntr = CNTR_PDMD;
@@ -190,7 +190,7 @@ int __init a3000_detect(struct scsi_host_template *tpnt)
regs.SASR = &(DMA(a3000_host)->SASR);
regs.SCMD = &(DMA(a3000_host)->SCMD);
wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
- if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, SA_SHIRQ, "A3000 SCSI",
+ if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, "A3000 SCSI",
a3000_intr))
goto fail_irq;
DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
@@ -205,7 +205,7 @@ fail_register:
return 0;
}
-static int a3000_bus_reset(Scsi_Cmnd *cmd)
+static int a3000_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
index 5535a65150a..44a4ec7b465 100644
--- a/drivers/scsi/a3000.h
+++ b/drivers/scsi/a3000.h
@@ -13,10 +13,6 @@
int a3000_detect(struct scsi_host_template *);
int a3000_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 83b5c7d085f..ac108f9e267 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -169,13 +169,17 @@ MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control block
int acbsize = -1;
module_param(acbsize, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware.");
+
+int expose_physicals = 0;
+module_param(expose_physicals, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. 0=off, 1=on");
/**
* aac_get_config_status - check the adapter configuration
* @common: adapter to query
*
* Query config status, and commit the configuration if needed.
*/
-int aac_get_config_status(struct aac_dev *dev)
+int aac_get_config_status(struct aac_dev *dev, int commit_flag)
{
int status = 0;
struct fib * fibptr;
@@ -219,7 +223,7 @@ int aac_get_config_status(struct aac_dev *dev)
aac_fib_complete(fibptr);
/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
if (status >= 0) {
- if (commit == 1) {
+ if ((commit == 1) || commit_flag) {
struct aac_commit_config * dinfo;
aac_fib_init(fibptr);
dinfo = (struct aac_commit_config *) fib_data(fibptr);
@@ -489,6 +493,8 @@ int aac_probe_container(struct aac_dev *dev, int cid)
unsigned instance;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -ENOMEM;
instance = dev->scsi_host_ptr->unique_id;
if (!(fibptr = aac_fib_alloc(dev)))
@@ -782,8 +788,9 @@ int aac_get_adapter_info(struct aac_dev* dev)
dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount);
}
- tmp = le32_to_cpu(dev->adapter_info.kernelrev);
- printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
+ if (!dev->in_reset) {
+ tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+ printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n",
dev->name,
dev->id,
tmp>>24,
@@ -792,20 +799,21 @@ int aac_get_adapter_info(struct aac_dev* dev)
le32_to_cpu(dev->adapter_info.kernelbuild),
(int)sizeof(dev->supplement_adapter_info.BuildDate),
dev->supplement_adapter_info.BuildDate);
- tmp = le32_to_cpu(dev->adapter_info.monitorrev);
- printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
+ tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+ printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n",
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.monitorbuild));
- tmp = le32_to_cpu(dev->adapter_info.biosrev);
- printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
+ tmp = le32_to_cpu(dev->adapter_info.biosrev);
+ printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n",
dev->name, dev->id,
tmp>>24,(tmp>>16)&0xff,tmp&0xff,
le32_to_cpu(dev->adapter_info.biosbuild));
- if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
- printk(KERN_INFO "%s%d: serial %x\n",
- dev->name, dev->id,
- le32_to_cpu(dev->adapter_info.serial[0]));
+ if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+ printk(KERN_INFO "%s%d: serial %x\n",
+ dev->name, dev->id,
+ le32_to_cpu(dev->adapter_info.serial[0]));
+ }
dev->nondasd_support = 0;
dev->raid_scsi_mode = 0;
@@ -1392,6 +1400,7 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
struct scsi_cmnd *cmd;
struct scsi_device *sdev = scsicmd->device;
int active = 0;
+ struct aac_dev *aac;
unsigned long flags;
/*
@@ -1413,11 +1422,14 @@ static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
if (active)
return SCSI_MLQUEUE_DEVICE_BUSY;
+ aac = (struct aac_dev *)scsicmd->device->host->hostdata;
+ if (aac->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
/*
* Allocate and initialize a Fib
*/
- if (!(cmd_fibcontext =
- aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata)))
+ if (!(cmd_fibcontext = aac_fib_alloc(aac)))
return SCSI_MLQUEUE_HOST_BUSY;
aac_fib_init(cmd_fibcontext);
@@ -1470,6 +1482,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
struct aac_dev *dev = (struct aac_dev *)host->hostdata;
struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
+ if (fsa_dev_ptr == NULL)
+ return -1;
/*
* If the bus, id or lun is out of range, return fail
* Test does not apply to ID 16, the pseudo id for the controller
@@ -1499,6 +1513,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case INQUIRY:
case READ_CAPACITY:
case TEST_UNIT_READY:
+ if (dev->in_reset)
+ return -1;
spin_unlock_irq(host->host_lock);
aac_probe_container(dev, cid);
if ((fsa_dev_ptr[cid].valid & 1) == 0)
@@ -1523,7 +1539,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
return 0;
}
} else { /* check for physical non-dasd devices */
- if(dev->nondasd_support == 1){
+ if ((dev->nondasd_support == 1) || expose_physicals) {
+ if (dev->in_reset)
+ return -1;
return aac_send_srb_fib(scsicmd);
} else {
scsicmd->result = DID_NO_CONNECT << 16;
@@ -1579,6 +1597,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsicmd->scsi_done(scsicmd);
return 0;
}
+ if (dev->in_reset)
+ return -1;
setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type);
inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */
aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
@@ -1734,6 +1754,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case READ_10:
case READ_12:
case READ_16:
+ if (dev->in_reset)
+ return -1;
/*
* Hack to keep track of ordinal number of the device that
* corresponds to a container. Needed to convert
@@ -1752,6 +1774,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
case WRITE_10:
case WRITE_12:
case WRITE_16:
+ if (dev->in_reset)
+ return -1;
return aac_write(scsicmd, cid);
case SYNCHRONIZE_CACHE:
@@ -1782,6 +1806,8 @@ static int query_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -EBUSY;
if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
return -EFAULT;
if (qd.cnum == -1)
@@ -1820,6 +1846,8 @@ static int force_delete_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -EBUSY;
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
return -EFAULT;
@@ -1843,6 +1871,8 @@ static int delete_disk(struct aac_dev *dev, void __user *arg)
struct fsa_dev_info *fsa_dev_ptr;
fsa_dev_ptr = dev->fsa_dev;
+ if (!fsa_dev_ptr)
+ return -EBUSY;
if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
return -EFAULT;
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index d0eecd4bec8..eb3ed91bac7 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -494,6 +494,7 @@ struct adapter_ops
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
int (*adapter_send)(struct fib * fib);
+ int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
};
/*
@@ -682,14 +683,6 @@ struct rx_inbound {
__le32 Mailbox[8];
};
-#define InboundMailbox0 IndexRegs.Mailbox[0]
-#define InboundMailbox1 IndexRegs.Mailbox[1]
-#define InboundMailbox2 IndexRegs.Mailbox[2]
-#define InboundMailbox3 IndexRegs.Mailbox[3]
-#define InboundMailbox4 IndexRegs.Mailbox[4]
-#define InboundMailbox5 IndexRegs.Mailbox[5]
-#define InboundMailbox6 IndexRegs.Mailbox[6]
-
#define INBOUNDDOORBELL_0 0x00000001
#define INBOUNDDOORBELL_1 0x00000002
#define INBOUNDDOORBELL_2 0x00000004
@@ -1010,6 +1003,8 @@ struct aac_dev
struct rx_registers __iomem *rx;
struct rkt_registers __iomem *rkt;
} regs;
+ volatile void __iomem *base;
+ volatile struct rx_inbound __iomem *IndexRegs;
u32 OIMR; /* Mask Register Cache */
/*
* AIF thread states
@@ -1029,6 +1024,7 @@ struct aac_dev
init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
u8 raw_io_64;
u8 printf_enabled;
+ u8 in_reset;
};
#define aac_adapter_interrupt(dev) \
@@ -1049,6 +1045,9 @@ struct aac_dev
#define aac_adapter_send(fib) \
((fib)->dev)->a_ops.adapter_send(fib)
+#define aac_adapter_ioremap(dev, size) \
+ (dev)->a_ops.adapter_ioremap(dev, size)
+
#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001)
/*
@@ -1524,7 +1523,6 @@ struct aac_get_name {
__le32 count; /* sizeof(((struct aac_get_name_resp *)NULL)->data) */
};
-#define CT_OK 218
struct aac_get_name_resp {
__le32 dummy0;
__le32 dummy1;
@@ -1670,6 +1668,7 @@ extern struct aac_common aac_config;
#define RCV_TEMP_READINGS 0x00000025
#define GET_COMM_PREFERRED_SETTINGS 0x00000026
#define IOP_RESET 0x00001000
+#define IOP_RESET_ALWAYS 0x00001001
#define RE_INIT_ADAPTER 0x000000ee
/*
@@ -1788,7 +1787,7 @@ void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
int aac_fib_complete(struct fib * context);
#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
struct aac_dev *aac_init_adapter(struct aac_dev *dev);
-int aac_get_config_status(struct aac_dev *dev);
+int aac_get_config_status(struct aac_dev *dev, int commit_flag);
int aac_get_containers(struct aac_dev *dev);
int aac_scsi_cmd(struct scsi_cmnd *cmd);
int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
@@ -1799,6 +1798,7 @@ int aac_sa_init(struct aac_dev *dev);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
+int aac_check_health(struct aac_dev * dev);
int aac_command_thread(void *data);
int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size);
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 255421de9d1..da1d3a9212f 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -38,7 +38,7 @@
#include <linux/completion.h>
#include <linux/dma-mapping.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
+#include <linux/delay.h> /* ssleep prototype */
#include <linux/kthread.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -140,7 +140,8 @@ cleanup:
fibptr->hw_fib_pa = hw_fib_pa;
fibptr->hw_fib = hw_fib;
}
- aac_fib_free(fibptr);
+ if (retval != -EINTR)
+ aac_fib_free(fibptr);
return retval;
}
@@ -297,7 +298,7 @@ return_fib:
spin_unlock_irqrestore(&dev->fib_lock, flags);
/* If someone killed the AIF aacraid thread, restart it */
status = !dev->aif_thread;
- if (status && dev->queues && dev->fsa_dev) {
+ if (status && !dev->in_reset && dev->queues && dev->fsa_dev) {
/* Be paranoid, be very paranoid! */
kthread_stop(dev->thread);
ssleep(1);
@@ -621,7 +622,13 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
actual_fibsize = sizeof (struct aac_srb) + (((user_srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
if(actual_fibsize != fibsize){ // User made a mistake - should not continue
- dprintk((KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n"));
+ dprintk((KERN_DEBUG"aacraid: Bad Size specified in "
+ "Raw SRB command calculated fibsize=%d "
+ "user_srbcmd->sg.count=%d aac_srb=%d sgentry=%d "
+ "issued fibsize=%d\n",
+ actual_fibsize, user_srbcmd->sg.count,
+ sizeof(struct aac_srb), sizeof(struct sgentry),
+ fibsize));
rcode = -EINVAL;
goto cleanup;
}
@@ -663,6 +670,10 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
psg->count = cpu_to_le32(sg_indx+1);
status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
}
+ if (status == -EINTR) {
+ rcode = -EINTR;
+ goto cleanup;
+ }
if (status != 0){
dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"));
@@ -696,8 +707,10 @@ cleanup:
for(i=0; i <= sg_indx; i++){
kfree(sg_list[i]);
}
- aac_fib_complete(srbfib);
- aac_fib_free(srbfib);
+ if (rcode != -EINTR) {
+ aac_fib_complete(srbfib);
+ aac_fib_free(srbfib);
+ }
return rcode;
}
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 35b0a6ebd3f..d5cf8b91a0e 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -92,28 +92,7 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
init->AdapterFibsSize = cpu_to_le32(fibsize);
init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
- /*
- * number of 4k pages of host physical memory. The aacraid fw needs
- * this number to be less than 4gb worth of pages. num_physpages is in
- * system page units. New firmware doesn't have any issues with the
- * mapping system, but older Firmware did, and had *troubles* dealing
- * with the math overloading past 32 bits, thus we must limit this
- * field.
- *
- * This assumes the memory is mapped zero->n, which isnt
- * always true on real computers. It also has some slight problems
- * with the GART on x86-64. I've btw never tried DMA from PCI space
- * on this platform but don't be surprised if its problematic.
- */
-#ifndef CONFIG_GART_IOMMU
- if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) {
- init->HostPhysMemPages =
- cpu_to_le32(num_physpages << (PAGE_SHIFT-12));
- } else
-#endif
- {
- init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
- }
+ init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
init->InitFlags = 0;
if (dev->new_comm_interface) {
@@ -201,7 +180,7 @@ int aac_send_shutdown(struct aac_dev * dev)
-2 /* Timeout silently */, 1,
NULL, NULL);
- if (status == 0)
+ if (status >= 0)
aac_fib_complete(fibctx);
aac_fib_free(fibctx);
return status;
@@ -328,17 +307,12 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
if (status[1] & AAC_OPT_NEW_COMM)
dev->new_comm_interface = dev->a_ops.adapter_send != 0;
if (dev->new_comm_interface && (status[2] > dev->base_size)) {
- iounmap(dev->regs.sa);
+ aac_adapter_ioremap(dev, 0);
dev->base_size = status[2];
- dprintk((KERN_DEBUG "ioremap(%lx,%d)\n",
- host->base, status[2]));
- dev->regs.sa = ioremap(host->base, status[2]);
- if (dev->regs.sa == NULL) {
+ if (aac_adapter_ioremap(dev, status[2])) {
/* remap failed, go back ... */
dev->new_comm_interface = 0;
- dev->regs.sa = ioremap(host->base,
- AAC_MIN_FOOTPRINT_SIZE);
- if (dev->regs.sa == NULL) {
+ if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) {
printk(KERN_WARNING
"aacraid: unable to map adapter.\n");
return NULL;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 3f27419c66a..19e42ac07cb 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -40,8 +40,11 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/kthread.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
#include <asm/semaphore.h>
#include "aacraid.h"
@@ -464,6 +467,8 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr));
+ if (!dev->queues)
+ return -EBUSY;
q = &dev->queues->queue[AdapNormCmdQueue];
if(wait)
@@ -527,8 +532,15 @@ int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size,
}
udelay(5);
}
- } else
- down(&fibptr->event_wait);
+ } else if (down_interruptible(&fibptr->event_wait)) {
+ spin_lock_irqsave(&fibptr->event_lock, flags);
+ if (fibptr->done == 0) {
+ fibptr->done = 2; /* Tell interrupt we aborted */
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ return -EINTR;
+ }
+ spin_unlock_irqrestore(&fibptr->event_lock, flags);
+ }
BUG_ON(fibptr->done == 0);
if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
@@ -795,7 +807,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
/* Sniff for container changes */
- if (!dev)
+ if (!dev || !dev->fsa_dev)
return;
container = (u32)-1;
@@ -1022,13 +1034,7 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
if (device) {
switch (device_config_needed) {
case DELETE:
- scsi_remove_device(device);
- break;
case CHANGE:
- if (!dev->fsa_dev[container].valid) {
- scsi_remove_device(device);
- break;
- }
scsi_rescan_device(&device->sdev_gendev);
default:
@@ -1045,6 +1051,262 @@ static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
}
+static int _aac_reset_adapter(struct aac_dev *aac)
+{
+ int index, quirks;
+ u32 ret;
+ int retval;
+ struct Scsi_Host *host;
+ struct scsi_device *dev;
+ struct scsi_cmnd *command;
+ struct scsi_cmnd *command_list;
+
+ /*
+ * Assumptions:
+ * - host is locked.
+ * - in_reset is asserted, so no new i/o is getting to the
+ * card.
+ * - The card is dead.
+ */
+ host = aac->scsi_host_ptr;
+ scsi_block_requests(host);
+ aac_adapter_disable_int(aac);
+ spin_unlock_irq(host->host_lock);
+ kthread_stop(aac->thread);
+
+ /*
+ * If a positive health, means in a known DEAD PANIC
+ * state and the adapter could be reset to `try again'.
+ */
+ retval = aac_adapter_check_health(aac);
+ if (retval == 0)
+ retval = aac_adapter_sync_cmd(aac, IOP_RESET_ALWAYS,
+ 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+ if (retval)
+ retval = aac_adapter_sync_cmd(aac, IOP_RESET,
+ 0, 0, 0, 0, 0, 0, &ret, NULL, NULL, NULL, NULL);
+
+ if (retval)
+ goto out;
+ if (ret != 0x00000001) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ index = aac->cardtype;
+
+ /*
+ * Re-initialize the adapter, first free resources, then carefully
+ * apply the initialization sequence to come back again. Only risk
+ * is a change in Firmware dropping cache, it is assumed the caller
+ * will ensure that i/o is queisced and the card is flushed in that
+ * case.
+ */
+ aac_fib_map_free(aac);
+ aac->hw_fib_va = NULL;
+ aac->hw_fib_pa = 0;
+ pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+ aac->comm_addr = NULL;
+ aac->comm_phys = 0;
+ kfree(aac->queues);
+ aac->queues = NULL;
+ free_irq(aac->pdev->irq, aac);
+ kfree(aac->fsa_dev);
+ aac->fsa_dev = NULL;
+ if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT) {
+ if (((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_32BIT_MASK))))
+ goto out;
+ } else {
+ if (((retval = pci_set_dma_mask(aac->pdev, 0x7FFFFFFFULL))) ||
+ ((retval = pci_set_consistent_dma_mask(aac->pdev, 0x7FFFFFFFULL))))
+ goto out;
+ }
+ if ((retval = (*(aac_get_driver_ident(index)->init))(aac)))
+ goto out;
+ if (aac_get_driver_ident(index)->quirks & AAC_QUIRK_31BIT)
+ if ((retval = pci_set_dma_mask(aac->pdev, DMA_32BIT_MASK)))
+ goto out;
+ aac->thread = kthread_run(aac_command_thread, aac, aac->name);
+ if (IS_ERR(aac->thread)) {
+ retval = PTR_ERR(aac->thread);
+ goto out;
+ }
+ (void)aac_get_adapter_info(aac);
+ quirks = aac_get_driver_ident(index)->quirks;
+ if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) {
+ host->sg_tablesize = 34;
+ host->max_sectors = (host->sg_tablesize * 8) + 112;
+ }
+ if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) {
+ host->sg_tablesize = 17;
+ host->max_sectors = (host->sg_tablesize * 8) + 112;
+ }
+ aac_get_config_status(aac, 1);
+ aac_get_containers(aac);
+ /*
+ * This is where the assumption that the Adapter is quiesced
+ * is important.
+ */
+ command_list = NULL;
+ __shost_for_each_device(dev, host) {
+ unsigned long flags;
+ spin_lock_irqsave(&dev->list_lock, flags);
+ list_for_each_entry(command, &dev->cmd_list, list)
+ if (command->SCp.phase == AAC_OWNER_FIRMWARE) {
+ command->SCp.buffer = (struct scatterlist *)command_list;
+ command_list = command;
+ }
+ spin_unlock_irqrestore(&dev->list_lock, flags);
+ }
+ while ((command = command_list)) {
+ command_list = (struct scsi_cmnd *)command->SCp.buffer;
+ command->SCp.buffer = NULL;
+ command->result = DID_OK << 16
+ | COMMAND_COMPLETE << 8
+ | SAM_STAT_TASK_SET_FULL;
+ command->SCp.phase = AAC_OWNER_ERROR_HANDLER;
+ command->scsi_done(command);
+ }
+ retval = 0;
+
+out:
+ aac->in_reset = 0;
+ scsi_unblock_requests(host);
+ spin_lock_irq(host->host_lock);
+ return retval;
+}
+
+int aac_check_health(struct aac_dev * aac)
+{
+ int BlinkLED;
+ unsigned long time_now, flagv = 0;
+ struct list_head * entry;
+ struct Scsi_Host * host;
+
+ /* Extending the scope of fib_lock slightly to protect aac->in_reset */
+ if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0)
+ return 0;
+
+ if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) {
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+ return 0; /* OK */
+ }
+
+ aac->in_reset = 1;
+
+ /* Fake up an AIF:
+ * aac_aifcmd.command = AifCmdEventNotify = 1
+ * aac_aifcmd.seqnum = 0xFFFFFFFF
+ * aac_aifcmd.data[0] = AifEnExpEvent = 23
+ * aac_aifcmd.data[1] = AifExeFirmwarePanic = 3
+ * aac.aifcmd.data[2] = AifHighPriority = 3
+ * aac.aifcmd.data[3] = BlinkLED
+ */
+
+ time_now = jiffies/HZ;
+ entry = aac->fib_list.next;
+
+ /*
+ * For each Context that is on the
+ * fibctxList, make a copy of the
+ * fib, and then set the event to wake up the
+ * thread that is waiting for it.
+ */
+ while (entry != &aac->fib_list) {
+ /*
+ * Extract the fibctx
+ */
+ struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next);
+ struct hw_fib * hw_fib;
+ struct fib * fib;
+ /*
+ * Check if the queue is getting
+ * backlogged
+ */
+ if (fibctx->count > 20) {
+ /*
+ * It's *not* jiffies folks,
+ * but jiffies / HZ, so do not
+ * panic ...
+ */
+ u32 time_last = fibctx->jiffies;
+ /*
+ * Has it been > 2 minutes
+ * since the last read off
+ * the queue?
+ */
+ if ((time_now - time_last) > aif_timeout) {
+ entry = entry->next;
+ aac_close_fib_context(aac, fibctx);
+ continue;
+ }
+ }
+ /*
+ * Warning: no sleep allowed while
+ * holding spinlock
+ */
+ hw_fib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+ fib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+ if (fib && hw_fib) {
+ struct aac_aifcmd * aif;
+
+ memset(hw_fib, 0, sizeof(struct hw_fib));
+ memset(fib, 0, sizeof(struct fib));
+ fib->hw_fib = hw_fib;
+ fib->dev = aac;
+ aac_fib_init(fib);
+ fib->type = FSAFS_NTC_FIB_CONTEXT;
+ fib->size = sizeof (struct fib);
+ fib->data = hw_fib->data;
+ aif = (struct aac_aifcmd *)hw_fib->data;
+ aif->command = cpu_to_le32(AifCmdEventNotify);
+ aif->seqnum = cpu_to_le32(0xFFFFFFFF);
+ aif->data[0] = cpu_to_le32(AifEnExpEvent);
+ aif->data[1] = cpu_to_le32(AifExeFirmwarePanic);
+ aif->data[2] = cpu_to_le32(AifHighPriority);
+ aif->data[3] = cpu_to_le32(BlinkLED);
+
+ /*
+ * Put the FIB onto the
+ * fibctx's fibs
+ */
+ list_add_tail(&fib->fiblink, &fibctx->fib_list);
+ fibctx->count++;
+ /*
+ * Set the event to wake up the
+ * thread that will waiting.
+ */
+ up(&fibctx->wait_sem);
+ } else {
+ printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
+ kfree(fib);
+ kfree(hw_fib);
+ }
+ entry = entry->next;
+ }
+
+ spin_unlock_irqrestore(&aac->fib_lock, flagv);
+
+ if (BlinkLED < 0) {
+ printk(KERN_ERR "%s: Host adapter dead %d\n", aac->name, BlinkLED);
+ goto out;
+ }
+
+ printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED);
+
+ host = aac->scsi_host_ptr;
+ spin_lock_irqsave(host->host_lock, flagv);
+ BlinkLED = _aac_reset_adapter(aac);
+ spin_unlock_irqrestore(host->host_lock, flagv);
+ return BlinkLED;
+
+out:
+ aac->in_reset = 0;
+ return BlinkLED;
+}
+
+
/**
* aac_command_thread - command processing thread
* @dev: Adapter to monitor
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
index b2a5c7262f3..8335f07b772 100644
--- a/drivers/scsi/aacraid/dpcsup.c
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -124,10 +124,15 @@ unsigned int aac_response_normal(struct aac_queue * q)
} else {
unsigned long flagv;
spin_lock_irqsave(&fib->event_lock, flagv);
- fib->done = 1;
+ if (!fib->done)
+ fib->done = 1;
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+ if (fib->done == 2) {
+ aac_fib_complete(fib);
+ aac_fib_free(fib);
+ }
}
consumed++;
spin_lock_irqsave(q->lock, flags);
@@ -316,7 +321,8 @@ unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index)
unsigned long flagv;
dprintk((KERN_INFO "event_wait up\n"));
spin_lock_irqsave(&fib->event_lock, flagv);
- fib->done = 1;
+ if (!fib->done)
+ fib->done = 1;
up(&fib->event_wait);
spin_unlock_irqrestore(&fib->event_lock, flagv);
FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index e42a479ce64..359e7ddfdb4 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -82,6 +82,8 @@ static LIST_HEAD(aac_devices);
static int aac_cfg_major = -1;
char aac_driver_version[] = AAC_DRIVER_FULL_VERSION;
+extern int expose_physicals;
+
/*
* Because of the way Linux names scsi devices, the order in this table has
* become important. Check for on-board Raid first, add-in cards second.
@@ -394,6 +396,7 @@ static int aac_slave_configure(struct scsi_device *sdev)
sdev->skip_ms_page_3f = 1;
}
if ((sdev->type == TYPE_DISK) &&
+ !expose_physicals &&
(sdev_channel(sdev) != CONTAINER_CHANNEL)) {
struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
if (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))
@@ -454,17 +457,17 @@ static int aac_eh_reset(struct scsi_cmnd* cmd)
printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n",
AAC_DRIVERNAME);
aac = (struct aac_dev *)host->hostdata;
- if (aac_adapter_check_health(aac)) {
- printk(KERN_ERR "%s: Host adapter appears dead\n",
- AAC_DRIVERNAME);
- return -ENODEV;
- }
+
+ if ((count = aac_check_health(aac)))
+ return count;
/*
* Wait for all commands to complete to this specific
* target (block maximum 60 seconds).
*/
for (count = 60; count; --count) {
- int active = 0;
+ int active = aac->in_reset;
+
+ if (active == 0)
__shost_for_each_device(dev, host) {
spin_lock_irqsave(&dev->list_lock, flags);
list_for_each_entry(command, &dev->cmd_list, list) {
@@ -864,13 +867,6 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* Map in the registers from the adapter.
*/
aac->base_size = AAC_MIN_FOOTPRINT_SIZE;
- if ((aac->regs.sa = ioremap(
- (unsigned long)aac->scsi_host_ptr->base, AAC_MIN_FOOTPRINT_SIZE))
- == NULL) {
- printk(KERN_WARNING "%s: unable to map adapter.\n",
- AAC_DRIVERNAME);
- goto out_free_fibs;
- }
if ((*aac_drivers[index].init)(aac))
goto out_unmap;
@@ -928,12 +924,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
* all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
* physical channels are address by their actual physical number+1
*/
- if (aac->nondasd_support == 1)
+ if ((aac->nondasd_support == 1) || expose_physicals)
shost->max_channel = aac->maximum_num_channels;
else
shost->max_channel = 0;
- aac_get_config_status(aac);
+ aac_get_config_status(aac, 0);
aac_get_containers(aac);
list_add(&aac->entry, insert);
@@ -969,8 +965,7 @@ static int __devinit aac_probe_one(struct pci_dev *pdev,
aac_fib_map_free(aac);
pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
kfree(aac->queues);
- iounmap(aac->regs.sa);
- out_free_fibs:
+ aac_adapter_ioremap(aac, 0);
kfree(aac->fibs);
kfree(aac->fsa_dev);
out_free_host:
@@ -1005,7 +1000,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
kfree(aac->queues);
free_irq(pdev->irq, aac);
- iounmap(aac->regs.sa);
+ aac_adapter_ioremap(aac, 0);
kfree(aac->fibs);
kfree(aac->fsa_dev);
@@ -1013,6 +1008,10 @@ static void __devexit aac_remove_one(struct pci_dev *pdev)
list_del(&aac->entry);
scsi_host_put(shost);
pci_disable_device(pdev);
+ if (list_empty(&aac_devices)) {
+ unregister_chrdev(aac_cfg_major, "aac");
+ aac_cfg_major = -1;
+ }
}
static struct pci_driver aac_pci_driver = {
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
index 5b52966bbbf..643f23b5ded 100644
--- a/drivers/scsi/aacraid/rkt.c
+++ b/drivers/scsi/aacraid/rkt.c
@@ -28,370 +28,27 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/completion.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <asm/semaphore.h>
#include <scsi/scsi_host.h>
#include "aacraid.h"
-static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct aac_dev *dev = dev_id;
-
- if (dev->new_comm_interface) {
- u32 Index = rkt_readl(dev, MUnit.OutboundQueue);
- if (Index == 0xFFFFFFFFL)
- Index = rkt_readl(dev, MUnit.OutboundQueue);
- if (Index != 0xFFFFFFFFL) {
- do {
- if (aac_intr_normal(dev, Index)) {
- rkt_writel(dev, MUnit.OutboundQueue, Index);
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespReady);
- }
- Index = rkt_readl(dev, MUnit.OutboundQueue);
- } while (Index != 0xFFFFFFFFL);
- return IRQ_HANDLED;
- }
- } else {
- unsigned long bellbits;
- u8 intstat;
- intstat = rkt_readb(dev, MUnit.OISR);
- /*
- * Read mask and invert because drawbridge is reversed.
- * This allows us to only service interrupts that have
- * been enabled.
- * Check to see if this is our interrupt. If it isn't just return
- */
- if (intstat & ~(dev->OIMR))
- {
- bellbits = rkt_readl(dev, OutboundDoorbellReg);
- if (bellbits & DoorBellPrintfReady) {
- aac_printf(dev, rkt_readl (dev, IndexRegs.Mailbox[5]));
- rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
- rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
- }
- else if (bellbits & DoorBellAdapterNormCmdReady) {
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
- aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
-// rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
- }
- else if (bellbits & DoorBellAdapterNormRespReady) {
- rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
- aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
- }
- else if (bellbits & DoorBellAdapterNormCmdNotFull) {
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
- }
- else if (bellbits & DoorBellAdapterNormRespNotFull) {
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
- rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
- }
- return IRQ_HANDLED;
- }
- }
- return IRQ_NONE;
-}
-
-/**
- * aac_rkt_disable_interrupt - Disable interrupts
- * @dev: Adapter
- */
-
-static void aac_rkt_disable_interrupt(struct aac_dev *dev)
-{
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
-}
-
/**
- * rkt_sync_cmd - send a command and wait
- * @dev: Adapter
- * @command: Command to execute
- * @p1: first parameter
- * @ret: adapter status
+ * aac_rkt_ioremap
+ * @size: mapping resize request
*
- * This routine will send a synchronous command to the adapter and wait
- * for its completion.
*/
-
-static int rkt_sync_cmd(struct aac_dev *dev, u32 command,
- u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6,
- u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4)
+static int aac_rkt_ioremap(struct aac_dev * dev, u32 size)
{
- unsigned long start;
- int ok;
- /*
- * Write the command into Mailbox 0
- */
- rkt_writel(dev, InboundMailbox0, command);
- /*
- * Write the parameters into Mailboxes 1 - 6
- */
- rkt_writel(dev, InboundMailbox1, p1);
- rkt_writel(dev, InboundMailbox2, p2);
- rkt_writel(dev, InboundMailbox3, p3);
- rkt_writel(dev, InboundMailbox4, p4);
- /*
- * Clear the synch command doorbell to start on a clean slate.
- */
- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
- /*
- * Disable doorbell interrupts
- */
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
- /*
- * Force the completion of the mask register write before issuing
- * the interrupt.
- */
- rkt_readb (dev, MUnit.OIMR);
- /*
- * Signal that there is a new synch command
- */
- rkt_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
-
- ok = 0;
- start = jiffies;
-
- /*
- * Wait up to 30 seconds
- */
- while (time_before(jiffies, start+30*HZ))
- {
- udelay(5); /* Delay 5 microseconds to let Mon960 get info. */
- /*
- * Mon960 will set doorbell0 bit when it has completed the command.
- */
- if (rkt_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
- /*
- * Clear the doorbell.
- */
- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
- ok = 1;
- break;
- }
- /*
- * Yield the processor in case we are slow
- */
- msleep(1);
+ if (!size) {
+ iounmap(dev->regs.rkt);
+ return 0;
}
- if (ok != 1) {
- /*
- * Restore interrupt mask even though we timed out
- */
- if (dev->new_comm_interface)
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- else
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
- return -ETIMEDOUT;
- }
- /*
- * Pull the synch status from Mailbox 0.
- */
- if (status)
- *status = rkt_readl(dev, IndexRegs.Mailbox[0]);
- if (r1)
- *r1 = rkt_readl(dev, IndexRegs.Mailbox[1]);
- if (r2)
- *r2 = rkt_readl(dev, IndexRegs.Mailbox[2]);
- if (r3)
- *r3 = rkt_readl(dev, IndexRegs.Mailbox[3]);
- if (r4)
- *r4 = rkt_readl(dev, IndexRegs.Mailbox[4]);
- /*
- * Clear the synch command doorbell.
- */
- rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
- /*
- * Restore interrupt mask
- */
- if (dev->new_comm_interface)
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- else
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
- return 0;
-
-}
-
-/**
- * aac_rkt_interrupt_adapter - interrupt adapter
- * @dev: Adapter
- *
- * Send an interrupt to the i960 and breakpoint it.
- */
-
-static void aac_rkt_interrupt_adapter(struct aac_dev *dev)
-{
- rkt_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0,
- NULL, NULL, NULL, NULL, NULL);
-}
-
-/**
- * aac_rkt_notify_adapter - send an event to the adapter
- * @dev: Adapter
- * @event: Event to send
- *
- * Notify the i960 that something it probably cares about has
- * happened.
- */
-
-static void aac_rkt_notify_adapter(struct aac_dev *dev, u32 event)
-{
- switch (event) {
-
- case AdapNormCmdQue:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
- break;
- case HostNormRespNotFull:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
- break;
- case AdapNormRespQue:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
- break;
- case HostNormCmdNotFull:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
- break;
- case HostShutdown:
-// rkt_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
-// NULL, NULL, NULL, NULL, NULL);
- break;
- case FastIo:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
- break;
- case AdapPrintfDone:
- rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
- break;
- default:
- BUG();
- break;
- }
-}
-
-/**
- * aac_rkt_start_adapter - activate adapter
- * @dev: Adapter
- *
- * Start up processing on an i960 based AAC adapter
- */
-
-static void aac_rkt_start_adapter(struct aac_dev *dev)
-{
- struct aac_init *init;
-
- init = dev->init;
- init->HostElapsedSeconds = cpu_to_le32(get_seconds());
- // We can only use a 32 bit address here
- rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa,
- 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL);
-}
-
-/**
- * aac_rkt_check_health
- * @dev: device to check if healthy
- *
- * Will attempt to determine if the specified adapter is alive and
- * capable of handling requests, returning 0 if alive.
- */
-static int aac_rkt_check_health(struct aac_dev *dev)
-{
- u32 status = rkt_readl(dev, MUnit.OMRx[0]);
-
- /*
- * Check to see if the board failed any self tests.
- */
- if (status & SELF_TEST_FAILED)
+ dev->base = dev->regs.rkt = ioremap(dev->scsi_host_ptr->base, size);
+ if (dev->base == NULL)
return -1;
- /*
- * Check to see if the board panic'd.
- */
- if (status & KERNEL_PANIC) {
- char * buffer;
- struct POSTSTATUS {
- __le32 Post_Command;
- __le32 Post_Address;
- } * post;
- dma_addr_t paddr, baddr;
- int ret;
-
- if ((status & 0xFF000000L) == 0xBC000000L)
- return (status >> 16) & 0xFF;
- buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
- ret = -2;
- if (buffer == NULL)
- return ret;
- post = pci_alloc_consistent(dev->pdev,
- sizeof(struct POSTSTATUS), &paddr);
- if (post == NULL) {
- pci_free_consistent(dev->pdev, 512, buffer, baddr);
- return ret;
- }
- memset(buffer, 0, 512);
- post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
- post->Post_Address = cpu_to_le32(baddr);
- rkt_writel(dev, MUnit.IMRx[0], paddr);
- rkt_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0,
- NULL, NULL, NULL, NULL, NULL);
- pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
- post, paddr);
- if ((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X'))) {
- ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
- ret <<= 4;
- ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
- }
- pci_free_consistent(dev->pdev, 512, buffer, baddr);
- return ret;
- }
- /*
- * Wait for the adapter to be up and running.
- */
- if (!(status & KERNEL_UP_AND_RUNNING))
- return -3;
- /*
- * Everything is OK
- */
- return 0;
-}
-
-/**
- * aac_rkt_send
- * @fib: fib to issue
- *
- * Will send a fib, returning 0 if successful.
- */
-static int aac_rkt_send(struct fib * fib)
-{
- u64 addr = fib->hw_fib_pa;
- struct aac_dev *dev = fib->dev;
- volatile void __iomem *device = dev->regs.rkt;
- u32 Index;
-
- dprintk((KERN_DEBUG "%p->aac_rkt_send(%p->%llx)\n", dev, fib, addr));
- Index = rkt_readl(dev, MUnit.InboundQueue);
- if (Index == 0xFFFFFFFFL)
- Index = rkt_readl(dev, MUnit.InboundQueue);
- dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
- if (Index == 0xFFFFFFFFL)
- return Index;
- device += Index;
- dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
- (u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
- writel((u32)(addr & 0xffffffff), device);
- device += sizeof(u32);
- writel((u32)(addr >> 32), device);
- device += sizeof(u32);
- writel(le16_to_cpu(fib->hw_fib->header.Size), device);
- rkt_writel(dev, MUnit.InboundQueue, Index);
- dprintk((KERN_DEBUG "aac_rkt_send - return 0\n"));
+ dev->IndexRegs = &dev->regs.rkt->IndexRegs;
return 0;
}
@@ -406,78 +63,18 @@ static int aac_rkt_send(struct fib * fib)
int aac_rkt_init(struct aac_dev *dev)
{
- unsigned long start;
- unsigned long status;
- int instance;
- const char * name;
-
- instance = dev->id;
- name = dev->name;
+ int retval;
+ extern int _aac_rx_init(struct aac_dev *dev);
+ extern void aac_rx_start_adapter(struct aac_dev *dev);
/*
- * Check to see if the board panic'd while booting.
- */
- /*
- * Check to see if the board failed any self tests.
- */
- if (rkt_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
- printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
- goto error_iounmap;
- }
- /*
- * Check to see if the monitor panic'd while booting.
- */
- if (rkt_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
- printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
- goto error_iounmap;
- }
- /*
- * Check to see if the board panic'd while booting.
- */
- if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
- printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
- goto error_iounmap;
- }
- start = jiffies;
- /*
- * Wait for the adapter to be up and running. Wait up to 3 minutes
- */
- while (!(rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING))
- {
- if(time_after(jiffies, start+startup_timeout*HZ))
- {
- status = rkt_readl(dev, MUnit.OMRx[0]);
- printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
- dev->name, instance, status);
- goto error_iounmap;
- }
- msleep(1);
- }
- if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0)
- {
- printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
- goto error_iounmap;
- }
- /*
* Fill in the function dispatch table.
*/
- dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
- dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt;
- dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
- dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
- dev->a_ops.adapter_check_health = aac_rkt_check_health;
- dev->a_ops.adapter_send = aac_rkt_send;
-
- /*
- * First clear out all interrupts. Then enable the one's that we
- * can handle.
- */
- rkt_writeb(dev, MUnit.OIMR, 0xff);
- rkt_writel(dev, MUnit.ODR, 0xffffffff);
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+ dev->a_ops.adapter_ioremap = aac_rkt_ioremap;
- if (aac_init_adapter(dev) == NULL)
- goto error_irq;
+ retval = _aac_rx_init(dev);
+ if (retval)
+ return retval;
if (dev->new_comm_interface) {
/*
* FIB Setup has already been done, but we can minimize the
@@ -494,20 +91,11 @@ int aac_rkt_init(struct aac_dev *dev)
dev->init->MaxIoCommands = cpu_to_le32(246);
dev->scsi_host_ptr->can_queue = 246 - AAC_NUM_MGT_FIB;
}
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
}
/*
* Tell the adapter that all is configured, and it can start
* accepting requests
*/
- aac_rkt_start_adapter(dev);
+ aac_rx_start_adapter(dev);
return 0;
-
-error_irq:
- rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
- free_irq(dev->scsi_host_ptr->irq, (void *)dev);
-
-error_iounmap:
-
- return -1;
}
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 9dadfb28b3f..a1d214d770e 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -79,7 +79,7 @@ static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
{
bellbits = rx_readl(dev, OutboundDoorbellReg);
if (bellbits & DoorBellPrintfReady) {
- aac_printf(dev, rx_readl (dev, IndexRegs.Mailbox[5]));
+ aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5]));
rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
}
@@ -134,14 +134,14 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
/*
* Write the command into Mailbox 0
*/
- rx_writel(dev, InboundMailbox0, command);
+ writel(command, &dev->IndexRegs->Mailbox[0]);
/*
* Write the parameters into Mailboxes 1 - 6
*/
- rx_writel(dev, InboundMailbox1, p1);
- rx_writel(dev, InboundMailbox2, p2);
- rx_writel(dev, InboundMailbox3, p3);
- rx_writel(dev, InboundMailbox4, p4);
+ writel(p1, &dev->IndexRegs->Mailbox[1]);
+ writel(p2, &dev->IndexRegs->Mailbox[2]);
+ writel(p3, &dev->IndexRegs->Mailbox[3]);
+ writel(p4, &dev->IndexRegs->Mailbox[4]);
/*
* Clear the synch command doorbell to start on a clean slate.
*/
@@ -199,15 +199,15 @@ static int rx_sync_cmd(struct aac_dev *dev, u32 command,
* Pull the synch status from Mailbox 0.
*/
if (status)
- *status = rx_readl(dev, IndexRegs.Mailbox[0]);
+ *status = readl(&dev->IndexRegs->Mailbox[0]);
if (r1)
- *r1 = rx_readl(dev, IndexRegs.Mailbox[1]);
+ *r1 = readl(&dev->IndexRegs->Mailbox[1]);
if (r2)
- *r2 = rx_readl(dev, IndexRegs.Mailbox[2]);
+ *r2 = readl(&dev->IndexRegs->Mailbox[2]);
if (r3)
- *r3 = rx_readl(dev, IndexRegs.Mailbox[3]);
+ *r3 = readl(&dev->IndexRegs->Mailbox[3]);
if (r4)
- *r4 = rx_readl(dev, IndexRegs.Mailbox[4]);
+ *r4 = readl(&dev->IndexRegs->Mailbox[4]);
/*
* Clear the synch command doorbell.
*/
@@ -261,8 +261,6 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
break;
case HostShutdown:
-// rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0,
-// NULL, NULL, NULL, NULL, NULL);
break;
case FastIo:
rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
@@ -283,7 +281,7 @@ static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
* Start up processing on an i960 based AAC adapter
*/
-static void aac_rx_start_adapter(struct aac_dev *dev)
+void aac_rx_start_adapter(struct aac_dev *dev)
{
struct aac_init *init;
@@ -381,7 +379,7 @@ static int aac_rx_send(struct fib * fib)
dprintk((KERN_DEBUG "Index = 0x%x\n", Index));
if (Index == 0xFFFFFFFFL)
return Index;
- device += Index;
+ device = dev->base + Index;
dprintk((KERN_DEBUG "entry = %x %x %u\n", (u32)(addr & 0xffffffff),
(u32)(addr >> 32), (u32)le16_to_cpu(fib->hw_fib->header.Size)));
writel((u32)(addr & 0xffffffff), device);
@@ -395,6 +393,43 @@ static int aac_rx_send(struct fib * fib)
}
/**
+ * aac_rx_ioremap
+ * @size: mapping resize request
+ *
+ */
+static int aac_rx_ioremap(struct aac_dev * dev, u32 size)
+{
+ if (!size) {
+ iounmap(dev->regs.rx);
+ return 0;
+ }
+ dev->base = dev->regs.rx = ioremap(dev->scsi_host_ptr->base, size);
+ if (dev->base == NULL)
+ return -1;
+ dev->IndexRegs = &dev->regs.rx->IndexRegs;
+ return 0;
+}
+
+static int aac_rx_restart_adapter(struct aac_dev *dev)
+{
+ u32 var;
+
+ printk(KERN_ERR "%s%d: adapter kernel panic'd.\n",
+ dev->name, dev->id);
+
+ if (aac_rx_check_health(dev) <= 0)
+ return 1;
+ if (rx_sync_cmd(dev, IOP_RESET, 0, 0, 0, 0, 0, 0,
+ &var, NULL, NULL, NULL, NULL))
+ return 1;
+ if (var != 0x00000001)
+ return 1;
+ if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC)
+ return 1;
+ return 0;
+}
+
+/**
* aac_rx_init - initialize an i960 based AAC card
* @dev: device to configure
*
@@ -403,7 +438,7 @@ static int aac_rx_send(struct fib * fib)
* to the comm region.
*/
-int aac_rx_init(struct aac_dev *dev)
+int _aac_rx_init(struct aac_dev *dev)
{
unsigned long start;
unsigned long status;
@@ -413,27 +448,30 @@ int aac_rx_init(struct aac_dev *dev)
instance = dev->id;
name = dev->name;
+ if (aac_adapter_ioremap(dev, dev->base_size)) {
+ printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+ goto error_iounmap;
+ }
+
/*
* Check to see if the board panic'd while booting.
*/
+ status = rx_readl(dev, MUnit.OMRx[0]);
+ if (status & KERNEL_PANIC)
+ if (aac_rx_restart_adapter(dev))
+ goto error_iounmap;
/*
* Check to see if the board failed any self tests.
*/
- if (rx_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
+ status = rx_readl(dev, MUnit.OMRx[0]);
+ if (status & SELF_TEST_FAILED) {
printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
goto error_iounmap;
}
/*
- * Check to see if the board panic'd while booting.
- */
- if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
- printk(KERN_ERR "%s%d: adapter kernel panic.\n", dev->name, instance);
- goto error_iounmap;
- }
- /*
* Check to see if the monitor panic'd while booting.
*/
- if (rx_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
+ if (status & MONITOR_PANIC) {
printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
goto error_iounmap;
}
@@ -441,19 +479,17 @@ int aac_rx_init(struct aac_dev *dev)
/*
* Wait for the adapter to be up and running. Wait up to 3 minutes
*/
- while ((!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING))
- || (!(rx_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING)))
+ while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING))
{
if(time_after(jiffies, start+startup_timeout*HZ))
{
- status = rx_readl(dev, IndexRegs.Mailbox[7]);
printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n",
dev->name, instance, status);
goto error_iounmap;
}
msleep(1);
}
- if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0)
+ if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev)<0)
{
printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
goto error_iounmap;
@@ -481,11 +517,6 @@ int aac_rx_init(struct aac_dev *dev)
if (dev->new_comm_interface)
rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7);
- /*
- * Tell the adapter that all is configured, and it can start
- * accepting requests
- */
- aac_rx_start_adapter(dev);
return 0;
error_irq:
@@ -496,3 +527,23 @@ error_iounmap:
return -1;
}
+
+int aac_rx_init(struct aac_dev *dev)
+{
+ int retval;
+
+ /*
+ * Fill in the function dispatch table.
+ */
+ dev->a_ops.adapter_ioremap = aac_rx_ioremap;
+
+ retval = _aac_rx_init(dev);
+ if (!retval) {
+ /*
+ * Tell the adapter that all is configured, and it can
+ * start accepting requests
+ */
+ aac_rx_start_adapter(dev);
+ }
+ return retval;
+}
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index 88d400fccc9..f906ead239d 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -281,6 +281,21 @@ static int aac_sa_check_health(struct aac_dev *dev)
}
/**
+ * aac_sa_ioremap
+ * @size: mapping resize request
+ *
+ */
+static int aac_sa_ioremap(struct aac_dev * dev, u32 size)
+{
+ if (!size) {
+ iounmap(dev->regs.sa);
+ return 0;
+ }
+ dev->base = dev->regs.sa = ioremap(dev->scsi_host_ptr->base, size);
+ return (dev->base == NULL) ? -1 : 0;
+}
+
+/**
* aac_sa_init - initialize an ARM based AAC card
* @dev: device to configure
*
@@ -299,6 +314,11 @@ int aac_sa_init(struct aac_dev *dev)
instance = dev->id;
name = dev->name;
+ if (aac_sa_ioremap(dev, dev->base_size)) {
+ printk(KERN_WARNING "%s: unable to map adapter.\n", name);
+ goto error_iounmap;
+ }
+
/*
* Check to see if the board failed any self tests.
*/
@@ -327,7 +347,7 @@ int aac_sa_init(struct aac_dev *dev)
msleep(1);
}
- if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
+ if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev ) < 0) {
printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
goto error_iounmap;
}
@@ -341,6 +361,7 @@ int aac_sa_init(struct aac_dev *dev)
dev->a_ops.adapter_notify = aac_sa_notify_adapter;
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health;
+ dev->a_ops.adapter_ioremap = aac_sa_ioremap;
/*
* First clear out all interrupts. Then enable the one's that
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2a419634b25..773f02e3b10 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -371,7 +371,7 @@
1.5 (8/8/96):
1. Add support for ABP-940U (PCI Ultra) adapter.
- 2. Add support for IRQ sharing by setting the SA_SHIRQ flag for
+ 2. Add support for IRQ sharing by setting the IRQF_SHARED flag for
request_irq and supplying a dev_id pointer to both request_irq()
and free_irq().
3. In AscSearchIOPortAddr11() restore a call to check_region() which
@@ -504,9 +504,9 @@
3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
access functions.
4. Update board serial number printing.
- 5. Try allocating an IRQ both with and without the SA_INTERRUPT
+ 5. Try allocating an IRQ both with and without the IRQF_DISABLED
flag set to allow IRQ sharing with drivers that do not set
- the SA_INTERRUPT flag. Also display a more descriptive error
+ the IRQF_DISABLED flag. Also display a more descriptive error
message if request_irq() fails.
6. Update to latest Asc and Adv Libraries.
@@ -754,7 +754,6 @@
* --- Linux Include Files
*/
-#include <linux/config.h>
#include <linux/module.h>
#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
@@ -889,10 +888,6 @@ typedef unsigned char uchar;
#define ASC_PCI_ID2DEV(id) (((id) >> 11) & 0x1F)
#define ASC_PCI_ID2FUNC(id) (((id) >> 8) & 0x7)
#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
-#define ASC_PCI_VENDORID 0x10CD
-#define ASC_PCI_DEVICEID_1200A 0x1100
-#define ASC_PCI_DEVICEID_1200B 0x1200
-#define ASC_PCI_DEVICEID_ULTRA 0x1300
#define ASC_PCI_REVISION_3150 0x02
#define ASC_PCI_REVISION_3050 0x03
@@ -900,6 +895,14 @@ typedef unsigned char uchar;
#define ASC_DVCLIB_CALL_FAILED (0)
#define ASC_DVCLIB_CALL_ERROR (-1)
+#define PCI_VENDOR_ID_ASP 0x10cd
+#define PCI_DEVICE_ID_ASP_1200A 0x1100
+#define PCI_DEVICE_ID_ASP_ABP940 0x1200
+#define PCI_DEVICE_ID_ASP_ABP940U 0x1300
+#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300
+#define PCI_DEVICE_ID_38C0800_REV1 0x2500
+#define PCI_DEVICE_ID_38C1600_REV1 0x2700
+
/*
* Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
* The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
@@ -1493,8 +1496,6 @@ typedef struct asc_dvc_cfg {
#define ASC_INIT_STATE_END_INQUIRY 0x0080
#define ASC_INIT_RESET_SCSI_DONE 0x0100
#define ASC_INIT_STATE_WITHOUT_EEP 0x8000
-#define ASC_PCI_DEVICE_ID_REV_A 0x1100
-#define ASC_PCI_DEVICE_ID_REV_B 0x1200
#define ASC_BUG_FIX_IF_NOT_DWB 0x0001
#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002
#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
@@ -2101,12 +2102,6 @@ STATIC ASC_DCNT AscGetMaxDmaCount(ushort);
#define ADV_NUM_PAGE_CROSSING \
((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
-/* a_condor.h */
-#define ADV_PCI_VENDOR_ID 0x10CD
-#define ADV_PCI_DEVICE_ID_REV_A 0x2300
-#define ADV_PCI_DEVID_38C0800_REV1 0x2500
-#define ADV_PCI_DEVID_38C1600_REV1 0x2700
-
#define ADV_EEP_DVC_CFG_BEGIN (0x00)
#define ADV_EEP_DVC_CFG_END (0x15)
#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
@@ -3570,14 +3565,7 @@ typedef struct scsi_cmnd REQ, *REQP;
#define PCI_MAX_SLOT 0x1F
#define PCI_MAX_BUS 0xFF
#define PCI_IOADDRESS_MASK 0xFFFE
-#define ASC_PCI_VENDORID 0x10CD
#define ASC_PCI_DEVICE_ID_CNT 6 /* PCI Device ID count. */
-#define ASC_PCI_DEVICE_ID_1100 0x1100
-#define ASC_PCI_DEVICE_ID_1200 0x1200
-#define ASC_PCI_DEVICE_ID_1300 0x1300
-#define ASC_PCI_DEVICE_ID_2300 0x2300 /* ASC-3550 */
-#define ASC_PCI_DEVICE_ID_2500 0x2500 /* ASC-38C0800 */
-#define ASC_PCI_DEVICE_ID_2700 0x2700 /* ASC-38C1600 */
#ifndef ADVANSYS_STATS
#define ASC_STATS(shp, counter)
@@ -4331,12 +4319,12 @@ advansys_detect(struct scsi_host_template *tpnt)
struct pci_dev *pci_devp = NULL;
int pci_device_id_cnt = 0;
unsigned int pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
- ASC_PCI_DEVICE_ID_1100,
- ASC_PCI_DEVICE_ID_1200,
- ASC_PCI_DEVICE_ID_1300,
- ASC_PCI_DEVICE_ID_2300,
- ASC_PCI_DEVICE_ID_2500,
- ASC_PCI_DEVICE_ID_2700
+ PCI_DEVICE_ID_ASP_1200A,
+ PCI_DEVICE_ID_ASP_ABP940,
+ PCI_DEVICE_ID_ASP_ABP940U,
+ PCI_DEVICE_ID_ASP_ABP940UW,
+ PCI_DEVICE_ID_38C0800_REV1,
+ PCI_DEVICE_ID_38C1600_REV1
};
ADV_PADDR pci_memory_address;
#endif /* CONFIG_PCI */
@@ -4472,7 +4460,7 @@ advansys_detect(struct scsi_host_template *tpnt)
/* Find all PCI cards. */
while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
- if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
+ if ((pci_devp = pci_find_device(PCI_VENDOR_ID_ASP,
pci_device_id[pci_device_id_cnt], pci_devp)) ==
NULL) {
pci_device_id_cnt++;
@@ -4576,9 +4564,9 @@ advansys_detect(struct scsi_host_template *tpnt)
*/
#ifdef CONFIG_PCI
if (asc_bus[bus] == ASC_IS_PCI &&
- (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
- pci_devp->device == ASC_PCI_DEVICE_ID_2500 ||
- pci_devp->device == ASC_PCI_DEVICE_ID_2700))
+ (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW ||
+ pci_devp->device == PCI_DEVICE_ID_38C0800_REV1 ||
+ pci_devp->device == PCI_DEVICE_ID_38C1600_REV1))
{
boardp->flags |= ASC_IS_WIDE_BOARD;
}
@@ -4601,11 +4589,11 @@ advansys_detect(struct scsi_host_template *tpnt)
adv_dvc_varp->isr_callback = adv_isr_callback;
adv_dvc_varp->async_callback = adv_async_callback;
#ifdef CONFIG_PCI
- if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
+ if (pci_devp->device == PCI_DEVICE_ID_ASP_ABP940UW)
{
ASC_DBG(1, "advansys_detect: ASC-3550\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
- } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500)
+ } else if (pci_devp->device == PCI_DEVICE_ID_38C0800_REV1)
{
ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
@@ -5203,19 +5191,19 @@ advansys_detect(struct scsi_host_template *tpnt)
/* Register IRQ Number. */
ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
/*
- * If request_irq() fails with the SA_INTERRUPT flag set,
- * then try again without the SA_INTERRUPT flag set. This
+ * If request_irq() fails with the IRQF_DISABLED flag set,
+ * then try again without the IRQF_DISABLED flag set. This
* allows IRQ sharing to work even with other drivers that
- * do not set the SA_INTERRUPT flag.
+ * do not set the IRQF_DISABLED flag.
*
- * If SA_INTERRUPT is not set, then interrupts are enabled
+ * If IRQF_DISABLED is not set, then interrupts are enabled
* before the driver interrupt function is called.
*/
if (((ret = request_irq(shp->irq, advansys_interrupt,
- SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+ IRQF_DISABLED | (share_irq == TRUE ? IRQF_SHARED : 0),
"advansys", boardp)) != 0) &&
((ret = request_irq(shp->irq, advansys_interrupt,
- (share_irq == TRUE ? SA_SHIRQ : 0),
+ (share_irq == TRUE ? IRQF_SHARED : 0),
"advansys", boardp)) != 0))
{
if (ret == -EBUSY) {
@@ -11923,7 +11911,7 @@ AscInitGetConfig(
PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
AscPCIConfigRevisionIDRegister);
- if (PCIVendorID != ASC_PCI_VENDORID) {
+ if (PCIVendorID != PCI_VENDOR_ID_ASP) {
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
@@ -11943,15 +11931,15 @@ AscInitGetConfig(
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
}
- if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) ||
- (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) {
+ if ((PCIDeviceID == PCI_DEVICE_ID_ASP_1200A) ||
+ (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940)) {
DvcWritePCIConfigByte(asc_dvc,
AscPCIConfigLatencyTimer, 0x00);
if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
!= 0x00) {
warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
}
- } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) {
+ } else if (PCIDeviceID == PCI_DEVICE_ID_ASP_ABP940U) {
if (DvcReadPCIConfigByte(asc_dvc,
AscPCIConfigLatencyTimer) < 0x20) {
DvcWritePCIConfigByte(asc_dvc,
@@ -12038,8 +12026,8 @@ AscInitFromAscDvcVar(
AscSetChipCfgMsw(iop_base, cfg_msw);
if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
} else {
- if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
- (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
+ if ((pci_device_id == PCI_DEVICE_ID_ASP_1200A) ||
+ (pci_device_id == PCI_DEVICE_ID_ASP_ABP940)) {
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
}
@@ -12374,7 +12362,7 @@ AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
ASC_PRINT1(
"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
} else {
- ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM.");
+ ASC_PRINT("AscInitFromEEP: Successfully re-wrote EEPROM.\n");
}
}
return (warn_code);
@@ -14276,8 +14264,8 @@ Default_38C0800_EEPROM_Config __initdata = {
0, /* 55 reserved */
0, /* 56 cisptr_lsw */
0, /* 57 cisprt_msw */
- ADV_PCI_VENDOR_ID, /* 58 subsysvid */
- ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
+ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
+ PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */
0, /* 60 reserved */
0, /* 61 reserved */
0, /* 62 reserved */
@@ -14406,8 +14394,8 @@ Default_38C1600_EEPROM_Config __initdata = {
0, /* 55 reserved */
0, /* 56 cisptr_lsw */
0, /* 57 cisprt_msw */
- ADV_PCI_VENDOR_ID, /* 58 subsysvid */
- ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */
+ PCI_VENDOR_ID_ASP, /* 58 subsysvid */
+ PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */
0, /* 60 reserved */
0, /* 61 reserved */
0, /* 62 reserved */
@@ -17316,7 +17304,7 @@ AdvWaitEEPCmd(AdvPortAddr iop_base)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
{
ushort *wbuf;
@@ -17383,7 +17371,7 @@ AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
ADVEEP_38C0800_CONFIG *cfg_buf)
{
@@ -17451,7 +17439,7 @@ AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
/*
* Write the EEPROM from 'cfg_buf'.
*/
-void
+void __init
AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
ADVEEP_38C1600_CONFIG *cfg_buf)
{
@@ -18226,3 +18214,22 @@ AdvInquiryHandling(
}
}
MODULE_LICENSE("Dual BSD/GPL");
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id advansys_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, advansys_pci_tbl);
+
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index de80cdfb5b9..fb6a476eb87 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -253,6 +253,7 @@
#include <linux/isapnp.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
+#include <linux/list.h>
#include <asm/semaphore.h>
#include <scsi/scsicam.h>
@@ -262,6 +263,8 @@
#include <scsi/scsi_transport_spi.h>
#include "aha152x.h"
+static LIST_HEAD(aha152x_host_list);
+
/* DEFINES */
@@ -423,8 +426,6 @@ MODULE_DEVICE_TABLE(isapnp, id_table);
#endif /* !PCMCIA */
-static int registered_count=0;
-static struct Scsi_Host *aha152x_host[2];
static struct scsi_host_template aha152x_driver_template;
/*
@@ -541,6 +542,7 @@ struct aha152x_hostdata {
#ifdef __ISAPNP__
struct pnp_dev *pnpdev;
#endif
+ struct list_head host_list;
};
@@ -551,6 +553,11 @@ struct aha152x_hostdata {
struct aha152x_scdata {
Scsi_Cmnd *next; /* next sc in queue */
struct semaphore *sem; /* semaphore to block on */
+ unsigned char cmd_len;
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned short use_sg;
+ unsigned request_bufflen;
+ void *request_buffer;
};
@@ -750,20 +757,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
return ptr;
}
-static inline struct Scsi_Host *lookup_irq(int irqno)
-{
- int i;
-
- for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
- if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
- return aha152x_host[i];
-
- return NULL;
-}
-
static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
{
- struct Scsi_Host *shpnt = lookup_irq(irqno);
+ struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
if (!shpnt) {
printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
@@ -786,10 +782,11 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
return NULL;
}
- /* need to have host registered before triggering any interrupt */
- aha152x_host[registered_count] = shpnt;
-
memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
+ INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
+
+ /* need to have host registered before triggering any interrupt */
+ list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
shpnt->io_port = setup->io_port;
shpnt->n_io_port = IO_RANGE;
@@ -855,7 +852,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, 0);
- if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+ if( request_irq(shpnt->irq, swintr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
@@ -889,7 +886,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
SETPORT(SSTAT0, 0x7f);
SETPORT(SSTAT1, 0xef);
- if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+ if ( request_irq(shpnt->irq, intr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
goto out_host_put;
}
@@ -902,12 +899,10 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
scsi_scan_host(shpnt);
- registered_count++;
-
return shpnt;
out_host_put:
- aha152x_host[registered_count]=NULL;
+ list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
return NULL;
@@ -932,6 +927,7 @@ void aha152x_release(struct Scsi_Host *shpnt)
#endif
scsi_remove_host(shpnt);
+ list_del(&HOSTDATA(shpnt)->host_list);
scsi_host_put(shpnt);
}
@@ -1006,11 +1002,20 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p
return FAILED;
}
} else {
+ struct aha152x_scdata *sc;
+
SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
if(SCpnt->host_scribble==0) {
printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
return FAILED;
}
+
+ sc = SCDATA(SCpnt);
+ memcpy(sc->cmnd, SCpnt->cmnd, sizeof(sc->cmnd));
+ sc->request_buffer = SCpnt->request_buffer;
+ sc->request_bufflen = SCpnt->request_bufflen;
+ sc->use_sg = SCpnt->use_sg;
+ sc->cmd_len = SCpnt->cmd_len;
}
SCNEXT(SCpnt) = NULL;
@@ -1165,6 +1170,10 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
DECLARE_MUTEX_LOCKED(sem);
struct timer_list timer;
int ret, issued, disconnected;
+ unsigned char old_cmd_len = SCpnt->cmd_len;
+ unsigned short old_use_sg = SCpnt->use_sg;
+ void *old_buffer = SCpnt->request_buffer;
+ unsigned old_bufflen = SCpnt->request_bufflen;
unsigned long flags;
#if defined(AHA152X_DEBUG)
@@ -1198,11 +1207,11 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
add_timer(&timer);
down(&sem);
del_timer(&timer);
-
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->request_buffer = SCpnt->buffer;
- SCpnt->request_bufflen = SCpnt->bufflen;
+
+ SCpnt->cmd_len = old_cmd_len;
+ SCpnt->use_sg = old_use_sg;
+ SCpnt->request_buffer = old_buffer;
+ SCpnt->request_bufflen = old_bufflen;
DO_LOCK(flags);
@@ -1441,9 +1450,12 @@ static struct work_struct aha152x_tq;
*/
static void run(void)
{
- int i;
- for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
- is_complete(aha152x_host[i]);
+ struct aha152x_hostdata *hd;
+
+ list_for_each_entry(hd, &aha152x_host_list, host_list) {
+ struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
+
+ is_complete(shost);
}
}
@@ -1453,7 +1465,7 @@ static void run(void)
*/
static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
{
- struct Scsi_Host *shpnt = lookup_irq(irqno);
+ struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
unsigned long flags;
unsigned char rev, dmacntrl0;
@@ -1565,6 +1577,9 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
if(DONE_SC->SCp.phase & check_condition) {
+ struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
+ struct aha152x_scdata *sc = SCDATA(cmd);
+
#if 0
if(HOSTDATA(shpnt)->debug & debug_eh) {
printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
@@ -1573,13 +1588,13 @@ static void busfree_run(struct Scsi_Host *shpnt)
#endif
/* restore old command */
- memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd));
- DONE_SC->request_buffer = DONE_SC->buffer;
- DONE_SC->request_bufflen = DONE_SC->bufflen;
- DONE_SC->use_sg = DONE_SC->old_use_sg;
- DONE_SC->cmd_len = DONE_SC->old_cmd_len;
+ memcpy(cmd->cmnd, sc->cmnd, sizeof(sc->cmnd));
+ cmd->request_buffer = sc->request_buffer;
+ cmd->request_bufflen = sc->request_bufflen;
+ cmd->use_sg = sc->use_sg;
+ cmd->cmd_len = sc->cmd_len;
- DONE_SC->SCp.Status = 0x02;
+ cmd->SCp.Status = 0x02;
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
@@ -3932,16 +3947,17 @@ static int __init aha152x_init(void)
#endif
}
- return registered_count>0;
+ return 1;
}
static void __exit aha152x_exit(void)
{
- int i;
+ struct aha152x_hostdata *hd;
+
+ list_for_each_entry(hd, &aha152x_host_list, host_list) {
+ struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
- for(i=0; i<ARRAY_SIZE(setup); i++) {
- aha152x_release(aha152x_host[i]);
- aha152x_host[i]=NULL;
+ aha152x_release(shost);
}
}
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 86c6bd23459..24f0f546179 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -25,7 +25,6 @@
* Added proper detection of the AHA-1640 (MCA version of AHA-1540)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 4b8c6a54392..6b35ed8301e 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -634,7 +634,7 @@ static int aha1740_probe (struct device *dev)
}
DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
- if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : SA_SHIRQ,
+ if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED,
"aha1740",shpnt)) {
printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
irq_level);
@@ -681,6 +681,7 @@ static struct eisa_device_id aha1740_ids[] = {
{ "ADP0400" }, /* 1744 */
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, aha1740_ids);
static struct eisa_driver aha1740_driver = {
.id_table = aha1740_ids,
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index d754b326786..1ac119733ba 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -65,7 +65,7 @@ aic7770_map_int(struct ahc_softc *ahc, u_int irq)
shared = 0;
if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0)
- shared = SA_SHIRQ;
+ shared = IRQF_SHARED;
error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc);
if (error == 0)
@@ -132,7 +132,8 @@ static struct eisa_device_id aic7770_ids[] = {
{ "ADP7770", 5 }, /* AIC7770 generic */
{ "" }
};
-
+MODULE_DEVICE_TABLE(eisa, aic7770_ids);
+
static struct eisa_driver aic7770_driver = {
.id_table = aic7770_ids,
.driver = {
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index eb774569268..df3346b5caf 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -1487,6 +1487,7 @@ typedef enum {
} ahd_queue_alg;
void ahd_set_tags(struct ahd_softc *ahd,
+ struct scsi_cmnd *cmd,
struct ahd_devinfo *devinfo,
ahd_queue_alg alg);
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 801fc81d0b2..653818d2f80 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -1090,7 +1090,7 @@ ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
/* Notify XPT */
ahd_send_async(ahd, devinfo.channel, devinfo.target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ CAM_LUN_WILDCARD, AC_SENT_BDR);
/*
* Allow the sequencer to continue with
@@ -3062,7 +3062,7 @@ ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
tinfo->curr.ppr_options = ppr_options;
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
if (offset != 0) {
int options;
@@ -3184,7 +3184,7 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
tinfo->curr.width = width;
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+ CAM_LUN_WILDCARD, AC_TRANSFER_NEG);
if (bootverbose) {
printf("%s: target %d using %dbit transfers\n",
ahd_name(ahd), devinfo->target,
@@ -3211,12 +3211,14 @@ ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
* Update the current state of tagged queuing for a given target.
*/
void
-ahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
- ahd_queue_alg alg)
+ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+ struct ahd_devinfo *devinfo, ahd_queue_alg alg)
{
- ahd_platform_set_tags(ahd, devinfo, alg);
+ struct scsi_device *sdev = cmd->device;
+
+ ahd_platform_set_tags(ahd, sdev, devinfo, alg);
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- devinfo->lun, AC_TRANSFER_NEG, &alg);
+ devinfo->lun, AC_TRANSFER_NEG);
}
static void
@@ -4746,7 +4748,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
printf("(%s:%c:%d:%d): refuses tagged commands. "
"Performing non-tagged I/O\n", ahd_name(ahd),
devinfo->channel, devinfo->target, devinfo->lun);
- ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE);
+ ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE);
mask = ~0x23;
} else {
printf("(%s:%c:%d:%d): refuses %s tagged commands. "
@@ -4754,7 +4756,7 @@ ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
ahd_name(ahd), devinfo->channel, devinfo->target,
devinfo->lun, tag_type == MSG_ORDERED_TASK
? "ordered" : "head of queue");
- ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC);
+ ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC);
mask = ~0x03;
}
@@ -5098,7 +5100,7 @@ ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
if (status != CAM_SEL_TIMEOUT)
ahd_send_async(ahd, devinfo->channel, devinfo->target,
- CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+ CAM_LUN_WILDCARD, AC_SENT_BDR);
if (message != NULL && bootverbose)
printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
@@ -7287,7 +7289,7 @@ ahd_reset_cmds_pending(struct ahd_softc *ahd)
ahd->flags &= ~AHD_UPDATE_PEND_CMDS;
}
-void
+static void
ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status)
{
cam_status ostat;
@@ -7952,7 +7954,7 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
#endif
/* Notify the XPT that a bus reset occurred */
ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
- CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
+ CAM_LUN_WILDCARD, AC_BUS_RESET);
/*
* Revert to async/narrow transfers until we renegotiate.
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index e0ccdf36220..c7eeaced324 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -243,25 +243,6 @@ ahd_print_path(struct ahd_softc *ahd, struct scb *scb)
static uint32_t aic79xx_no_reset;
/*
- * Certain PCI motherboards will scan PCI devices from highest to lowest,
- * others scan from lowest to highest, and they tend to do all kinds of
- * strange things when they come into contact with PCI bridge chips. The
- * net result of all this is that the PCI card that is actually used to boot
- * the machine is very hard to detect. Most motherboards go from lowest
- * PCI slot number to highest, and the first SCSI controller found is the
- * one you boot from. The only exceptions to this are when a controller
- * has its BIOS disabled. So, we by default sort all of our SCSI controllers
- * from lowest PCI slot number to highest PCI slot number. We also force
- * all controllers with their BIOS disabled to the end of the list. This
- * works on *almost* all computers. Where it doesn't work, we have this
- * option. Setting this option to non-0 will reverse the order of the sort
- * to highest first, then lowest, but will still leave cards with their BIOS
- * disabled at the very end. That should fix everyone up unless there are
- * really strange cirumstances.
- */
-static uint32_t aic79xx_reverse_scan;
-
-/*
* Should we force EXTENDED translation on a controller.
* 0 == Use whatever is in the SEEPROM or default to off
* 1 == Use whatever is in the SEEPROM or default to on
@@ -340,7 +321,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC79XX_DRIVER_VERSION);
module_param(aic79xx, charp, 0444);
MODULE_PARM_DESC(aic79xx,
-"period delimited, options string.\n"
+"period-delimited options string:\n"
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
@@ -350,7 +331,6 @@ MODULE_PARM_DESC(aic79xx,
" periodically to prevent tag starvation.\n"
" This may be required by some older disk\n"
" or drives/RAID arrays.\n"
-" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for all targets on all buses\n"
" slewrate:<slewrate_list>Set the signal slew rate (0-15).\n"
@@ -366,7 +346,7 @@ MODULE_PARM_DESC(aic79xx,
" Shorten the selection timeout to 128ms\n"
"\n"
" options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
-"\n");
+);
static void ahd_linux_handle_scsi_status(struct ahd_softc *,
struct scsi_device *,
@@ -484,7 +464,6 @@ ahd_linux_target_alloc(struct scsi_target *starget)
struct seeprom_config *sc = ahd->seep_config;
unsigned long flags;
struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget);
- struct ahd_linux_target *targ = scsi_transport_target_data(starget);
struct ahd_devinfo devinfo;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
@@ -495,7 +474,6 @@ ahd_linux_target_alloc(struct scsi_target *starget)
BUG_ON(*ahd_targp != NULL);
*ahd_targp = starget;
- memset(targ, 0, sizeof(*targ));
if (sc) {
int flags = sc->device_flags[starget->id];
@@ -551,15 +529,11 @@ ahd_linux_slave_alloc(struct scsi_device *sdev)
{
struct ahd_softc *ahd =
*((struct ahd_softc **)sdev->host->hostdata);
- struct scsi_target *starget = sdev->sdev_target;
- struct ahd_linux_target *targ = scsi_transport_target_data(starget);
struct ahd_linux_device *dev;
if (bootverbose)
printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id);
- BUG_ON(targ->sdev[sdev->lun] != NULL);
-
dev = scsi_transport_device_data(sdev);
memset(dev, 0, sizeof(*dev));
@@ -576,8 +550,6 @@ ahd_linux_slave_alloc(struct scsi_device *sdev)
*/
dev->maxtags = 0;
- targ->sdev[sdev->lun] = sdev;
-
return (0);
}
@@ -599,23 +571,6 @@ ahd_linux_slave_configure(struct scsi_device *sdev)
return 0;
}
-static void
-ahd_linux_slave_destroy(struct scsi_device *sdev)
-{
- struct ahd_softc *ahd;
- struct ahd_linux_device *dev = scsi_transport_device_data(sdev);
- struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target);
-
- ahd = *((struct ahd_softc **)sdev->host->hostdata);
- if (bootverbose)
- printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id);
-
- BUG_ON(dev->active);
-
- targ->sdev[sdev->lun] = NULL;
-
-}
-
#if defined(__i386__)
/*
* Return the disk geometry for the given SCSI device.
@@ -822,7 +777,6 @@ struct scsi_host_template aic79xx_driver_template = {
.use_clustering = ENABLE_CLUSTERING,
.slave_alloc = ahd_linux_slave_alloc,
.slave_configure = ahd_linux_slave_configure,
- .slave_destroy = ahd_linux_slave_destroy,
.target_alloc = ahd_linux_target_alloc,
.target_destroy = ahd_linux_target_destroy,
};
@@ -1057,7 +1011,6 @@ aic79xx_setup(char *s)
#ifdef AHD_DEBUG
{ "debug", &ahd_debug },
#endif
- { "reverse_scan", &aic79xx_reverse_scan },
{ "periodic_otag", &aic79xx_periodic_otag },
{ "pci_parity", &aic79xx_pci_parity },
{ "seltime", &aic79xx_seltime },
@@ -1249,20 +1202,13 @@ void
ahd_platform_free(struct ahd_softc *ahd)
{
struct scsi_target *starget;
- int i, j;
+ int i;
if (ahd->platform_data != NULL) {
/* destroy all of the device and target objects */
for (i = 0; i < AHD_NUM_TARGETS; i++) {
starget = ahd->platform_data->starget[i];
if (starget != NULL) {
- for (j = 0; j < AHD_NUM_LUNS; j++) {
- struct ahd_linux_target *targ =
- scsi_transport_target_data(starget);
- if (targ->sdev[j] == NULL)
- continue;
- targ->sdev[j] = NULL;
- }
ahd->platform_data->starget[i] = NULL;
}
}
@@ -1318,20 +1264,13 @@ ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
}
void
-ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
- ahd_queue_alg alg)
+ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
+ struct ahd_devinfo *devinfo, ahd_queue_alg alg)
{
- struct scsi_target *starget;
- struct ahd_linux_target *targ;
struct ahd_linux_device *dev;
- struct scsi_device *sdev;
int was_queuing;
int now_queuing;
- starget = ahd->platform_data->starget[devinfo->target];
- targ = scsi_transport_target_data(starget);
- BUG_ON(targ == NULL);
- sdev = targ->sdev[devinfo->lun];
if (sdev == NULL)
return;
@@ -1467,11 +1406,15 @@ ahd_linux_device_queue_depth(struct scsi_device *sdev)
tags = ahd_linux_user_tagdepth(ahd, &devinfo);
if (tags != 0 && sdev->tagged_supported != 0) {
- ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
+ ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_TAGGED);
+ ahd_send_async(ahd, devinfo.channel, devinfo.target,
+ devinfo.lun, AC_TRANSFER_NEG);
ahd_print_devinfo(ahd, &devinfo);
printf("Tagged Queuing enabled. Depth %d\n", tags);
} else {
- ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
+ ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE);
+ ahd_send_async(ahd, devinfo.channel, devinfo.target,
+ devinfo.lun, AC_TRANSFER_NEG);
}
}
@@ -1629,7 +1572,7 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
void
ahd_send_async(struct ahd_softc *ahd, char channel,
- u_int target, u_int lun, ac_code code, void *arg)
+ u_int target, u_int lun, ac_code code)
{
switch (code) {
case AC_TRANSFER_NEG:
@@ -1956,7 +1899,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
}
ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
ahd_set_scsi_status(scb, SCSI_STATUS_OK);
- ahd_platform_set_tags(ahd, &devinfo,
+ ahd_platform_set_tags(ahd, sdev, &devinfo,
(dev->flags & AHD_DEV_Q_BASIC)
? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
break;
@@ -1966,7 +1909,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
* as if the target returned BUSY SCSI status.
*/
dev->openings = 1;
- ahd_platform_set_tags(ahd, &devinfo,
+ ahd_platform_set_tags(ahd, sdev, &devinfo,
(dev->flags & AHD_DEV_Q_BASIC)
? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
@@ -2778,8 +2721,6 @@ ahd_linux_init(void)
if (!ahd_linux_transport_template)
return -ENODEV;
- scsi_transport_reserve_target(ahd_linux_transport_template,
- sizeof(struct ahd_linux_target));
scsi_transport_reserve_device(ahd_linux_transport_template,
sizeof(struct ahd_linux_device));
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 2b8331649ee..601340d8441 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -42,7 +42,6 @@
#ifndef _AIC79XX_LINUX_H_
#define _AIC79XX_LINUX_H_
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
@@ -94,7 +93,6 @@
#endif
/********************************** Misc Macros *******************************/
-#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
#define powerof2(x) ((((x)-1)&(x))==0)
/************************* Forward Declarations *******************************/
@@ -263,7 +261,6 @@ typedef enum {
AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */
} ahd_linux_dev_flags;
-struct ahd_linux_target;
struct ahd_linux_device {
TAILQ_ENTRY(ahd_linux_device) links;
@@ -343,12 +340,6 @@ struct ahd_linux_device {
#define AHD_OTAG_THRESH 500
};
-struct ahd_linux_target {
- struct scsi_device *sdev[AHD_NUM_LUNS];
- struct ahd_transinfo last_tinfo;
- struct ahd_softc *ahd;
-};
-
/********************* Definitions Required by the Core ***********************/
/*
* Number of SG segments we require. So long as the S/G segments for
@@ -865,7 +856,7 @@ ahd_freeze_scb(struct scb *scb)
}
}
-void ahd_platform_set_tags(struct ahd_softc *ahd,
+void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
struct ahd_devinfo *devinfo, ahd_queue_alg);
int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
@@ -874,7 +865,7 @@ irqreturn_t
ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
void ahd_done(struct ahd_softc*, struct scb*);
void ahd_send_async(struct ahd_softc *, char channel,
- u_int target, u_int lun, ac_code, void *);
+ u_int target, u_int lun, ac_code);
void ahd_print_path(struct ahd_softc *, struct scb *);
#ifdef CONFIG_PCI
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index ebbf7e4ff4c..50a41eda580 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -342,7 +342,7 @@ ahd_pci_map_int(struct ahd_softc *ahd)
int error;
error = request_irq(ahd->dev_softc->irq, ahd_linux_isr,
- SA_SHIRQ, "aic79xx", ahd);
+ IRQF_SHARED, "aic79xx", ahd);
if (!error)
ahd->platform_data->irq = ahd->dev_softc->irq;
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 24fd59a230b..c5f0ee59150 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -47,7 +47,7 @@ static int copy_info(struct info_str *info, char *fmt, ...);
static void ahd_dump_target_state(struct ahd_softc *ahd,
struct info_str *info,
u_int our_id, char channel,
- u_int target_id, u_int target_offset);
+ u_int target_id);
static void ahd_dump_device_state(struct info_str *info,
struct scsi_device *sdev);
static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
@@ -204,10 +204,8 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
static void
ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
- u_int our_id, char channel, u_int target_id,
- u_int target_offset)
+ u_int our_id, char channel, u_int target_id)
{
- struct ahd_linux_target *targ;
struct scsi_target *starget;
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
@@ -218,10 +216,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
copy_info(info, "Target %d Negotiation Settings\n", target_id);
copy_info(info, "\tUser: ");
ahd_format_transinfo(info, &tinfo->user);
- starget = ahd->platform_data->starget[target_offset];
+ starget = ahd->platform_data->starget[target_id];
if (starget == NULL)
return;
- targ = scsi_transport_target_data(starget);
copy_info(info, "\tGoal: ");
ahd_format_transinfo(info, &tinfo->goal);
@@ -231,7 +228,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
struct scsi_device *dev;
- dev = targ->sdev[lun];
+ dev = scsi_device_lookup_by_target(starget, lun);
if (dev == NULL)
continue;
@@ -355,7 +352,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
ahd->scb_data.numscbs, AHD_NSEG);
- max_targ = 15;
+ max_targ = 16;
if (ahd->seep_config == NULL)
copy_info(&info, "No Serial EEPROM\n");
@@ -373,12 +370,12 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
copy_info(&info, "\n");
if ((ahd->features & AHD_WIDE) == 0)
- max_targ = 7;
+ max_targ = 8;
- for (i = 0; i <= max_targ; i++) {
+ for (i = 0; i < max_targ; i++) {
ahd_dump_target_state(ahd, &info, ahd->our_id, 'A',
- /*target_id*/i, /*target_offset*/i);
+ /*target_id*/i);
}
retval = info.pos > info.offset ? info.pos - info.offset : 0;
done:
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index debf3e2a079..64c8b88a429 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -341,7 +341,7 @@ MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
module_param(aic7xxx, charp, 0444);
MODULE_PARM_DESC(aic7xxx,
-"period delimited, options string.\n"
+"period-delimited options string:\n"
" verbose Enable verbose/diagnostic logging\n"
" allow_memio Allow device registers to be memory mapped\n"
" debug Bitmask of debug values to enable\n"
@@ -353,7 +353,6 @@ MODULE_PARM_DESC(aic7xxx,
" periodically to prevent tag starvation.\n"
" This may be required by some older disk\n"
" drives or RAID arrays.\n"
-" reverse_scan Sort PCI devices highest Bus/Slot to lowest\n"
" tag_info:<tag_str> Set per-target tag depth\n"
" global_tag_depth:<int> Global tag depth for every target\n"
" on every bus\n"
@@ -2540,15 +2539,28 @@ static void ahc_linux_set_iu(struct scsi_target *starget, int iu)
static void ahc_linux_get_signalling(struct Scsi_Host *shost)
{
struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata;
- u8 mode = ahc_inb(ahc, SBLKCTL);
+ unsigned long flags;
+ u8 mode;
- if (mode & ENAB40)
- spi_signalling(shost) = SPI_SIGNAL_LVD;
- else if (mode & ENAB20)
+ if (!(ahc->features & AHC_ULTRA2)) {
+ /* non-LVD chipset, may not have SBLKCTL reg */
spi_signalling(shost) =
ahc->features & AHC_HVD ?
SPI_SIGNAL_HVD :
SPI_SIGNAL_SE;
+ return;
+ }
+
+ ahc_lock(ahc, &flags);
+ ahc_pause(ahc);
+ mode = ahc_inb(ahc, SBLKCTL);
+ ahc_unpause(ahc);
+ ahc_unlock(ahc, &flags);
+
+ if (mode & ENAB40)
+ spi_signalling(shost) = SPI_SIGNAL_LVD;
+ else if (mode & ENAB20)
+ spi_signalling(shost) = SPI_SIGNAL_SE;
else
spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index a20b08c9ff1..d42a71ee076 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -59,7 +59,6 @@
#ifndef _AIC7XXX_LINUX_H_
#define _AIC7XXX_LINUX_H_
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 0c9c2f400bf..7e42f07a27f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -375,7 +375,7 @@ ahc_pci_map_int(struct ahc_softc *ahc)
int error;
error = request_irq(ahc->dev_softc->irq, ahc_linux_isr,
- SA_SHIRQ, "aic7xxx", ahc);
+ IRQF_SHARED, "aic7xxx", ahc);
if (error == 0)
ahc->platform_data->irq = ahc->dev_softc->irq;
diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile
index 8c91fda6482..b98c5c1056c 100644
--- a/drivers/scsi/aic7xxx/aicasm/Makefile
+++ b/drivers/scsi/aic7xxx/aicasm/Makefile
@@ -14,6 +14,8 @@ LIBS= -ldb
clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG)
# Override default kernel CFLAGS. This is a userland app.
AICASM_CFLAGS:= -I/usr/include -I.
+LEX= flex
+YACC= bison
YFLAGS= -d
NOMAN= noman
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 5dba1c63122..5dcef48d414 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -249,8 +249,6 @@
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
-#include <linux/config.h> /* for CONFIG_PCI */
-
#define AIC7XXX_C_VERSION "5.2.6"
#define ALL_TARGETS -1
@@ -8322,11 +8320,11 @@ aic7xxx_register(struct scsi_host_template *template, struct aic7xxx_host *p,
}
else
{
- result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+ result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_SHARED,
"aic7xxx", p));
if (result < 0)
{
- result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+ result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_DISABLED | IRQF_SHARED,
"aic7xxx", p));
}
}
@@ -9196,7 +9194,7 @@ aic7xxx_detect(struct scsi_host_template *template)
for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++)
{
pdev = NULL;
- while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
+ while ((pdev = pci_get_device(aic_pdevs[i].vendor_id,
aic_pdevs[i].device_id,
pdev))) {
if (pci_enable_device(pdev))
@@ -9653,6 +9651,9 @@ aic7xxx_detect(struct scsi_host_template *template)
*/
aic7xxx_configure_bugs(temp_p);
+ /* Hold a pci device reference */
+ pci_dev_get(temp_p->pdev);
+
if ( list_p == NULL )
{
list_p = current_p = temp_p;
@@ -10989,8 +10990,10 @@ aic7xxx_release(struct Scsi_Host *host)
if(!p->pdev)
release_region(p->base, MAXREG - MINREG);
#ifdef CONFIG_PCI
- else
+ else {
pci_release_regions(p->pdev);
+ pci_dev_put(p->pdev);
+ }
#endif
prev = NULL;
next = first_aic7xxx;
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
index 3bf334931a8..b07e4f04fd0 100644
--- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
@@ -29,7 +29,6 @@
* $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
-#include <linux/config.h>
#define BLS (&aic7xxx_buffer[size])
#define HDRB \
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
new file mode 100644
index 00000000000..0ed391d8ee8
--- /dev/null
+++ b/drivers/scsi/aic94xx/Kconfig
@@ -0,0 +1,41 @@
+#
+# Kernel configuration file for aic94xx SAS/SATA driver.
+#
+# Copyright (c) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the aic94xx driver.
+#
+# The aic94xx driver 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 of the
+# License.
+#
+# The aic94xx driver 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 Aic94xx Driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#
+#
+
+config SCSI_AIC94XX
+ tristate "Adaptec AIC94xx SAS/SATA support"
+ depends on PCI
+ select SCSI_SAS_LIBSAS
+ help
+ This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
+ AIC94xx chip based host adapters.
+
+config AIC94XX_DEBUG
+ bool "Compile in debug mode"
+ default y
+ depends on SCSI_AIC94XX
+ help
+ Compiles the aic94xx driver in debug mode. In debug mode,
+ the driver prints some messages to the console.
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile
new file mode 100644
index 00000000000..e6b70123940
--- /dev/null
+++ b/drivers/scsi/aic94xx/Makefile
@@ -0,0 +1,39 @@
+#
+# Makefile for Adaptec aic94xx SAS/SATA driver.
+#
+# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# This file is part of the the aic94xx driver.
+#
+# The aic94xx driver 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 of the
+# License.
+#
+# The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ifeq ($(CONFIG_AIC94XX_DEBUG),y)
+ EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT
+endif
+
+obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o
+aic94xx-y += aic94xx_init.o \
+ aic94xx_hwi.o \
+ aic94xx_reg.o \
+ aic94xx_sds.o \
+ aic94xx_seq.o \
+ aic94xx_dump.o \
+ aic94xx_scb.o \
+ aic94xx_dev.o \
+ aic94xx_tmf.o \
+ aic94xx_task.o
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
new file mode 100644
index 00000000000..71a031df7a3
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -0,0 +1,114 @@
+/*
+ * Aic94xx SAS/SATA driver header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id: //depot/aic94xx/aic94xx.h#31 $
+ */
+
+#ifndef _AIC94XX_H_
+#define _AIC94XX_H_
+
+#include <linux/slab.h>
+#include <linux/ctype.h>
+#include <scsi/libsas.h>
+
+#define ASD_DRIVER_NAME "aic94xx"
+#define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver"
+
+#define asd_printk(fmt, ...) printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__)
+
+#ifdef ASD_ENTER_EXIT
+#define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \
+ __FUNCTION__)
+#define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \
+ __FUNCTION__)
+#else
+#define ENTER
+#define EXIT
+#endif
+
+#ifdef ASD_DEBUG
+#define ASD_DPRINTK asd_printk
+#else
+#define ASD_DPRINTK(fmt, ...)
+#endif
+
+/* 2*ITNL timeout + 1 second */
+#define AIC94XX_SCB_TIMEOUT (5*HZ)
+
+extern kmem_cache_t *asd_dma_token_cache;
+extern kmem_cache_t *asd_ascb_cache;
+extern char sas_addr_str[2*SAS_ADDR_SIZE + 1];
+
+static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr)
+{
+ int i;
+ for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2)
+ snprintf(p, 3, "%02X", sas_addr[i]);
+ *p = '\0';
+}
+
+static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p)
+{
+ int i;
+ for (i = 0; i < SAS_ADDR_SIZE; i++) {
+ u8 h, l;
+ if (!*p)
+ break;
+ h = isdigit(*p) ? *p-'0' : *p-'A'+10;
+ p++;
+ l = isdigit(*p) ? *p-'0' : *p-'A'+10;
+ p++;
+ sas_addr[i] = (h<<4) | l;
+ }
+}
+
+struct asd_ha_struct;
+struct asd_ascb;
+
+int asd_read_ocm(struct asd_ha_struct *asd_ha);
+int asd_read_flash(struct asd_ha_struct *asd_ha);
+
+int asd_dev_found(struct domain_device *dev);
+void asd_dev_gone(struct domain_device *dev);
+
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
+
+int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
+
+/* ---------- TMFs ---------- */
+int asd_abort_task(struct sas_task *);
+int asd_abort_task_set(struct domain_device *, u8 *lun);
+int asd_clear_aca(struct domain_device *, u8 *lun);
+int asd_clear_task_set(struct domain_device *, u8 *lun);
+int asd_lu_reset(struct domain_device *, u8 *lun);
+int asd_query_task(struct sas_task *);
+
+/* ---------- Adapter and Port management ---------- */
+int asd_clear_nexus_port(struct asd_sas_port *port);
+int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha);
+
+/* ---------- Phy Management ---------- */
+int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg);
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c
new file mode 100644
index 00000000000..6f8901b748f
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_dev.c
@@ -0,0 +1,353 @@
+/*
+ * Aic94xx SAS/SATA DDB management
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_dev.c#21 $
+ */
+
+#include "aic94xx.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_sas.h"
+
+#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \
+ (_ha)->hw_prof.max_ddbs)
+#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap)
+
+static inline int asd_get_ddb(struct asd_ha_struct *asd_ha)
+{
+ unsigned long flags;
+ int ddb, i;
+
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+ ddb = FIND_FREE_DDB(asd_ha);
+ if (ddb >= asd_ha->hw_prof.max_ddbs) {
+ ddb = -ENOMEM;
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+ goto out;
+ }
+ SET_DDB(ddb, asd_ha);
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+
+ for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4)
+ asd_ddbsite_write_dword(asd_ha, ddb, i, 0);
+out:
+ return ddb;
+}
+
+#define INIT_CONN_TAG offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag)
+#define DEST_SAS_ADDR offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr)
+#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head)
+#define DDB_TYPE offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type)
+#define CONN_MASK offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask)
+#define DDB_TARG_FLAGS offsetof(struct asd_ddb_ssp_smp_target_port, flags)
+#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2)
+#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail)
+#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail)
+#define SISTER_DDB offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb)
+#define MAX_CCONN offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn)
+#define NUM_CTX offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts)
+#define ATA_CMD_SCBPTR offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr)
+#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask)
+#define NUM_SATA_TAGS offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags)
+#define SATA_STATUS offsetof(struct asd_ddb_stp_sata_target_port, sata_status)
+#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr)
+#define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout)
+
+static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb)
+{
+ unsigned long flags;
+
+ if (!ddb || ddb >= 0xFFFF)
+ return;
+ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED);
+ spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags);
+ CLEAR_DDB(ddb, asd_ha);
+ spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags);
+}
+
+static inline void asd_set_ddb_type(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb = (int) (unsigned long) dev->lldd_dev;
+
+ if (dev->dev_type == SATA_PM_PORT)
+ asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT);
+ else if (dev->tproto)
+ asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET);
+ else
+ asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR);
+}
+
+static int asd_init_sata_tag_ddb(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb, i;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2)
+ asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+ asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+ SISTER_DDB, ddb);
+ return 0;
+}
+
+static inline int asd_init_sata(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb = (int) (unsigned long) dev->lldd_dev;
+ u32 qdepth = 0;
+ int res = 0;
+
+ asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+ if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) &&
+ dev->sata_dev.identify_device &&
+ dev->sata_dev.identify_device[10] != 0) {
+ u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]);
+ u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]);
+
+ if (w76 & 0x100) /* NCQ? */
+ qdepth = (w75 & 0x1F) + 1;
+ asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK,
+ (1<<qdepth)-1);
+ asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth);
+ }
+ if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM ||
+ dev->dev_type == SATA_PM_PORT) {
+ struct dev_to_host_fis *fis = (struct dev_to_host_fis *)
+ dev->frame_rcvd;
+ asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status);
+ }
+ asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF);
+ if (qdepth > 0)
+ res = asd_init_sata_tag_ddb(dev);
+ return res;
+}
+
+static int asd_init_target_ddb(struct domain_device *dev)
+{
+ int ddb, i;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ u8 flags = 0;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ dev->lldd_dev = (void *) (unsigned long) ddb;
+
+ asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE);
+ asd_ddbsite_write_byte(asd_ha, ddb, 1, 0);
+ asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF);
+ for (i = 0; i < SAS_ADDR_SIZE; i++)
+ asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i,
+ dev->sas_addr[i]);
+ asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF);
+ asd_set_ddb_type(dev);
+ asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask);
+ if (dev->port->oob_mode != SATA_OOB_MODE) {
+ flags |= OPEN_REQUIRED;
+ if ((dev->dev_type == SATA_DEV) ||
+ (dev->tproto & SAS_PROTO_STP)) {
+ struct smp_resp *rps_resp = &dev->sata_dev.rps_resp;
+ if (rps_resp->frame_type == SMP_RESPONSE &&
+ rps_resp->function == SMP_REPORT_PHY_SATA &&
+ rps_resp->result == SMP_RESP_FUNC_ACC) {
+ if (rps_resp->rps.affil_valid)
+ flags |= STP_AFFIL_POL;
+ if (rps_resp->rps.affil_supp)
+ flags |= SUPPORTS_AFFIL;
+ }
+ } else {
+ flags |= CONCURRENT_CONN_SUPP;
+ if (!dev->parent &&
+ (dev->dev_type == EDGE_DEV ||
+ dev->dev_type == FANOUT_DEV))
+ asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+ 4);
+ else
+ asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN,
+ dev->pathways);
+ asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1);
+ }
+ }
+ if (dev->dev_type == SATA_PM)
+ flags |= SATA_MULTIPORT;
+ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags);
+
+ flags = 0;
+ if (dev->tproto & SAS_PROTO_STP)
+ flags |= STP_CL_POL_NO_TX;
+ asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags);
+
+ asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+
+ if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) {
+ i = asd_init_sata(dev);
+ if (i < 0) {
+ asd_free_ddb(asd_ha, ddb);
+ return i;
+ }
+ }
+
+ if (dev->dev_type == SAS_END_DEV) {
+ struct sas_end_device *rdev = rphy_to_end_device(dev->rphy);
+ if (rdev->I_T_nexus_loss_timeout > 0)
+ asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+ min(rdev->I_T_nexus_loss_timeout,
+ (u16)ITNL_TIMEOUT_CONST));
+ else
+ asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT,
+ (u16)ITNL_TIMEOUT_CONST);
+ }
+ return 0;
+}
+
+static int asd_init_sata_pm_table_ddb(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ int ddb, i;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ for (i = 0; i < 32; i += 2)
+ asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF);
+
+ asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev,
+ SISTER_DDB, ddb);
+
+ return 0;
+}
+
+#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags)
+#define PARENT_DDB offsetof(struct asd_ddb_sata_pm_port, parent_ddb)
+
+/**
+ * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port
+ * dev: pointer to domain device
+ *
+ * For SATA Port Multiplier Ports we need to allocate one SATA Port
+ * Multiplier Port DDB and depending on whether the target on it
+ * supports SATA II NCQ, one SATA Tag DDB.
+ */
+static int asd_init_sata_pm_port_ddb(struct domain_device *dev)
+{
+ int ddb, i, parent_ddb, pmtable_ddb;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ u8 flags;
+
+ ddb = asd_get_ddb(asd_ha);
+ if (ddb < 0)
+ return ddb;
+
+ asd_set_ddb_type(dev);
+ flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET;
+ asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags);
+ asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF);
+ asd_init_sata(dev);
+
+ parent_ddb = (int) (unsigned long) dev->parent->lldd_dev;
+ asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb);
+ pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB);
+ asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb);
+
+ if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) {
+ i = asd_init_sata_tag_ddb(dev);
+ if (i < 0) {
+ asd_free_ddb(asd_ha, ddb);
+ return i;
+ }
+ }
+ return 0;
+}
+
+static int asd_init_initiator_ddb(struct domain_device *dev)
+{
+ return -ENODEV;
+}
+
+/**
+ * asd_init_sata_pm_ddb -- SATA Port Multiplier
+ * dev: pointer to domain device
+ *
+ * For STP and direct-attached SATA Port Multipliers we need
+ * one target port DDB entry and one SATA PM table DDB entry.
+ */
+static int asd_init_sata_pm_ddb(struct domain_device *dev)
+{
+ int res = 0;
+
+ res = asd_init_target_ddb(dev);
+ if (res)
+ goto out;
+ res = asd_init_sata_pm_table_ddb(dev);
+ if (res)
+ asd_free_ddb(dev->port->ha->lldd_ha,
+ (int) (unsigned long) dev->lldd_dev);
+out:
+ return res;
+}
+
+int asd_dev_found(struct domain_device *dev)
+{
+ int res = 0;
+
+ switch (dev->dev_type) {
+ case SATA_PM:
+ res = asd_init_sata_pm_ddb(dev);
+ break;
+ case SATA_PM_PORT:
+ res = asd_init_sata_pm_port_ddb(dev);
+ break;
+ default:
+ if (dev->tproto)
+ res = asd_init_target_ddb(dev);
+ else
+ res = asd_init_initiator_ddb(dev);
+ }
+ return res;
+}
+
+void asd_dev_gone(struct domain_device *dev)
+{
+ int ddb, sister_ddb;
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+
+ ddb = (int) (unsigned long) dev->lldd_dev;
+ sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB);
+
+ if (sister_ddb != 0xFFFF)
+ asd_free_ddb(asd_ha, sister_ddb);
+ asd_free_ddb(asd_ha, ddb);
+ dev->lldd_dev = NULL;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c
new file mode 100644
index 00000000000..e6ade5996d9
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_dump.c
@@ -0,0 +1,959 @@
+/*
+ * Aic94xx SAS/SATA driver dump interface.
+ *
+ * Copyright (C) 2004 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * 2005/07/14/LT Complete overhaul of this file. Update pages, register
+ * locations, names, etc. Make use of macros. Print more information.
+ * Print all cseq and lseq mip and mdp.
+ *
+ */
+
+#include "linux/pci.h"
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_reg_def.h"
+#include "aic94xx_sas.h"
+
+#include "aic94xx_dump.h"
+
+#ifdef ASD_DEBUG
+
+#define MD(x) (1 << (x))
+#define MODE_COMMON (1 << 31)
+#define MODE_0_7 (0xFF)
+
+static const struct lseq_cio_regs {
+ char *name;
+ u32 offs;
+ u8 width;
+ u32 mode;
+} LSEQmCIOREGS[] = {
+ {"LmMnSCBPTR", 0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+ {"LmMnDDBPTR", 0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) },
+ {"LmREQMBX", 0x30, 32, MODE_COMMON },
+ {"LmRSPMBX", 0x34, 32, MODE_COMMON },
+ {"LmMnINT", 0x38, 32, MODE_0_7 },
+ {"LmMnINTEN", 0x3C, 32, MODE_0_7 },
+ {"LmXMTPRIMD", 0x40, 32, MODE_COMMON },
+ {"LmXMTPRIMCS", 0x44, 8, MODE_COMMON },
+ {"LmCONSTAT", 0x45, 8, MODE_COMMON },
+ {"LmMnDMAERRS", 0x46, 8, MD(0)|MD(1) },
+ {"LmMnSGDMAERRS", 0x47, 8, MD(0)|MD(1) },
+ {"LmMnEXPHDRP", 0x48, 8, MD(0) },
+ {"LmMnSASAALIGN", 0x48, 8, MD(1) },
+ {"LmMnMSKHDRP", 0x49, 8, MD(0) },
+ {"LmMnSTPALIGN", 0x49, 8, MD(1) },
+ {"LmMnRCVHDRP", 0x4A, 8, MD(0) },
+ {"LmMnXMTHDRP", 0x4A, 8, MD(1) },
+ {"LmALIGNMODE", 0x4B, 8, MD(1) },
+ {"LmMnEXPRCVCNT", 0x4C, 32, MD(0) },
+ {"LmMnXMTCNT", 0x4C, 32, MD(1) },
+ {"LmMnCURRTAG", 0x54, 16, MD(0) },
+ {"LmMnPREVTAG", 0x56, 16, MD(0) },
+ {"LmMnACKOFS", 0x58, 8, MD(1) },
+ {"LmMnXFRLVL", 0x59, 8, MD(0)|MD(1) },
+ {"LmMnSGDMACTL", 0x5A, 8, MD(0)|MD(1) },
+ {"LmMnSGDMASTAT", 0x5B, 8, MD(0)|MD(1) },
+ {"LmMnDDMACTL", 0x5C, 8, MD(0)|MD(1) },
+ {"LmMnDDMASTAT", 0x5D, 8, MD(0)|MD(1) },
+ {"LmMnDDMAMODE", 0x5E, 16, MD(0)|MD(1) },
+ {"LmMnPIPECTL", 0x61, 8, MD(0)|MD(1) },
+ {"LmMnACTSCB", 0x62, 16, MD(0)|MD(1) },
+ {"LmMnSGBHADR", 0x64, 8, MD(0)|MD(1) },
+ {"LmMnSGBADR", 0x65, 8, MD(0)|MD(1) },
+ {"LmMnSGDCNT", 0x66, 8, MD(0)|MD(1) },
+ {"LmMnSGDMADR", 0x68, 32, MD(0)|MD(1) },
+ {"LmMnSGDMADR", 0x6C, 32, MD(0)|MD(1) },
+ {"LmMnXFRCNT", 0x70, 32, MD(0)|MD(1) },
+ {"LmMnXMTCRC", 0x74, 32, MD(1) },
+ {"LmCURRTAG", 0x74, 16, MD(0) },
+ {"LmPREVTAG", 0x76, 16, MD(0) },
+ {"LmMnDPSEL", 0x7B, 8, MD(0)|MD(1) },
+ {"LmDPTHSTAT", 0x7C, 8, MODE_COMMON },
+ {"LmMnHOLDLVL", 0x7D, 8, MD(0) },
+ {"LmMnSATAFS", 0x7E, 8, MD(1) },
+ {"LmMnCMPLTSTAT", 0x7F, 8, MD(0)|MD(1) },
+ {"LmPRMSTAT0", 0x80, 32, MODE_COMMON },
+ {"LmPRMSTAT1", 0x84, 32, MODE_COMMON },
+ {"LmGPRMINT", 0x88, 8, MODE_COMMON },
+ {"LmMnCURRSCB", 0x8A, 16, MD(0) },
+ {"LmPRMICODE", 0x8C, 32, MODE_COMMON },
+ {"LmMnRCVCNT", 0x90, 16, MD(0) },
+ {"LmMnBUFSTAT", 0x92, 16, MD(0) },
+ {"LmMnXMTHDRSIZE",0x92, 8, MD(1) },
+ {"LmMnXMTSIZE", 0x93, 8, MD(1) },
+ {"LmMnTGTXFRCNT", 0x94, 32, MD(0) },
+ {"LmMnEXPROFS", 0x98, 32, MD(0) },
+ {"LmMnXMTROFS", 0x98, 32, MD(1) },
+ {"LmMnRCVROFS", 0x9C, 32, MD(0) },
+ {"LmCONCTL", 0xA0, 16, MODE_COMMON },
+ {"LmBITLTIMER", 0xA2, 16, MODE_COMMON },
+ {"LmWWNLOW", 0xA8, 32, MODE_COMMON },
+ {"LmWWNHIGH", 0xAC, 32, MODE_COMMON },
+ {"LmMnFRMERR", 0xB0, 32, MD(0) },
+ {"LmMnFRMERREN", 0xB4, 32, MD(0) },
+ {"LmAWTIMER", 0xB8, 16, MODE_COMMON },
+ {"LmAWTCTL", 0xBA, 8, MODE_COMMON },
+ {"LmMnHDRCMPS", 0xC0, 32, MD(0) },
+ {"LmMnXMTSTAT", 0xC4, 8, MD(1) },
+ {"LmHWTSTATEN", 0xC5, 8, MODE_COMMON },
+ {"LmMnRRDYRC", 0xC6, 8, MD(0) },
+ {"LmMnRRDYTC", 0xC6, 8, MD(1) },
+ {"LmHWTSTAT", 0xC7, 8, MODE_COMMON },
+ {"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) },
+ {"LmDWSSTATUS", 0xCB, 8, MODE_COMMON },
+ {"LmMnACTSTAT", 0xCE, 16, MD(0)|MD(1) },
+ {"LmMnREQSCB", 0xD2, 16, MD(0)|MD(1) },
+ {"LmXXXPRIM", 0xD4, 32, MODE_COMMON },
+ {"LmRCVASTAT", 0xD9, 8, MODE_COMMON },
+ {"LmINTDIS1", 0xDA, 8, MODE_COMMON },
+ {"LmPSTORESEL", 0xDB, 8, MODE_COMMON },
+ {"LmPSTORE", 0xDC, 32, MODE_COMMON },
+ {"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON },
+ {"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON },
+ {"LmDONETCTL", 0xF2, 16, MODE_COMMON },
+ {NULL, 0, 0, 0 }
+};
+/*
+static struct lseq_cio_regs LSEQmOOBREGS[] = {
+ {"OOB_BFLTR" ,0x100, 8, MD(5)},
+ {"OOB_INIT_MIN" ,0x102,16, MD(5)},
+ {"OOB_INIT_MAX" ,0x104,16, MD(5)},
+ {"OOB_INIT_NEG" ,0x106,16, MD(5)},
+ {"OOB_SAS_MIN" ,0x108,16, MD(5)},
+ {"OOB_SAS_MAX" ,0x10A,16, MD(5)},
+ {"OOB_SAS_NEG" ,0x10C,16, MD(5)},
+ {"OOB_WAKE_MIN" ,0x10E,16, MD(5)},
+ {"OOB_WAKE_MAX" ,0x110,16, MD(5)},
+ {"OOB_WAKE_NEG" ,0x112,16, MD(5)},
+ {"OOB_IDLE_MAX" ,0x114,16, MD(5)},
+ {"OOB_BURST_MAX" ,0x116,16, MD(5)},
+ {"OOB_XMIT_BURST" ,0x118, 8, MD(5)},
+ {"OOB_SEND_PAIRS" ,0x119, 8, MD(5)},
+ {"OOB_INIT_IDLE" ,0x11A, 8, MD(5)},
+ {"OOB_INIT_NEGO" ,0x11C, 8, MD(5)},
+ {"OOB_SAS_IDLE" ,0x11E, 8, MD(5)},
+ {"OOB_SAS_NEGO" ,0x120, 8, MD(5)},
+ {"OOB_WAKE_IDLE" ,0x122, 8, MD(5)},
+ {"OOB_WAKE_NEGO" ,0x124, 8, MD(5)},
+ {"OOB_DATA_KBITS" ,0x126, 8, MD(5)},
+ {"OOB_BURST_DATA" ,0x128,32, MD(5)},
+ {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)},
+ {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)},
+ {"OOB_SYNC_DATA" ,0x134,32, MD(5)},
+ {"OOB_D10_2_DATA" ,0x138,32, MD(5)},
+ {"OOB_PHY_RST_CNT" ,0x13C,32, MD(5)},
+ {"OOB_SIG_GEN" ,0x140, 8, MD(5)},
+ {"OOB_XMIT" ,0x141, 8, MD(5)},
+ {"FUNCTION_MAKS" ,0x142, 8, MD(5)},
+ {"OOB_MODE" ,0x143, 8, MD(5)},
+ {"CURRENT_STATUS" ,0x144, 8, MD(5)},
+ {"SPEED_MASK" ,0x145, 8, MD(5)},
+ {"PRIM_COUNT" ,0x146, 8, MD(5)},
+ {"OOB_SIGNALS" ,0x148, 8, MD(5)},
+ {"OOB_DATA_DET" ,0x149, 8, MD(5)},
+ {"OOB_TIME_OUT" ,0x14C, 8, MD(5)},
+ {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)},
+ {"OOB_STATUS" ,0x14E, 8, MD(5)},
+ {"HOT_PLUG_DELAY" ,0x150, 8, MD(5)},
+ {"RCD_DELAY" ,0x151, 8, MD(5)},
+ {"COMSAS_TIMER" ,0x152, 8, MD(5)},
+ {"SNTT_DELAY" ,0x153, 8, MD(5)},
+ {"SPD_CHNG_DELAY" ,0x154, 8, MD(5)},
+ {"SNLT_DELAY" ,0x155, 8, MD(5)},
+ {"SNWT_DELAY" ,0x156, 8, MD(5)},
+ {"ALIGN_DELAY" ,0x157, 8, MD(5)},
+ {"INT_ENABLE_0" ,0x158, 8, MD(5)},
+ {"INT_ENABLE_1" ,0x159, 8, MD(5)},
+ {"INT_ENABLE_2" ,0x15A, 8, MD(5)},
+ {"INT_ENABLE_3" ,0x15B, 8, MD(5)},
+ {"OOB_TEST_REG" ,0x15C, 8, MD(5)},
+ {"PHY_CONTROL_0" ,0x160, 8, MD(5)},
+ {"PHY_CONTROL_1" ,0x161, 8, MD(5)},
+ {"PHY_CONTROL_2" ,0x162, 8, MD(5)},
+ {"PHY_CONTROL_3" ,0x163, 8, MD(5)},
+ {"PHY_OOB_CAL_TX" ,0x164, 8, MD(5)},
+ {"PHY_OOB_CAL_RX" ,0x165, 8, MD(5)},
+ {"OOB_PHY_CAL_TX" ,0x166, 8, MD(5)},
+ {"OOB_PHY_CAL_RX" ,0x167, 8, MD(5)},
+ {"PHY_CONTROL_4" ,0x168, 8, MD(5)},
+ {"PHY_TEST" ,0x169, 8, MD(5)},
+ {"PHY_PWR_CTL" ,0x16A, 8, MD(5)},
+ {"PHY_PWR_DELAY" ,0x16B, 8, MD(5)},
+ {"OOB_SM_CON" ,0x16C, 8, MD(5)},
+ {"ADDR_TRAP_1" ,0x16D, 8, MD(5)},
+ {"ADDR_NEXT_1" ,0x16E, 8, MD(5)},
+ {"NEXT_ST_1" ,0x16F, 8, MD(5)},
+ {"OOB_SM_STATE" ,0x170, 8, MD(5)},
+ {"ADDR_TRAP_2" ,0x171, 8, MD(5)},
+ {"ADDR_NEXT_2" ,0x172, 8, MD(5)},
+ {"NEXT_ST_2" ,0x173, 8, MD(5)},
+ {NULL, 0, 0, 0 }
+};
+*/
+#define STR_8BIT " %30s[0x%04x]:0x%02x\n"
+#define STR_16BIT " %30s[0x%04x]:0x%04x\n"
+#define STR_32BIT " %30s[0x%04x]:0x%08x\n"
+#define STR_64BIT " %30s[0x%04x]:0x%llx\n"
+
+#define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n, \
+ asd_read_reg_byte(_ha, _r))
+#define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n, \
+ asd_read_reg_word(_ha, _r))
+#define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n, \
+ asd_read_reg_dword(_ha, _r))
+
+#define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n, \
+ asd_read_reg_byte(_ha, C##_n))
+#define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n, \
+ asd_read_reg_word(_ha, C##_n))
+#define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n, \
+ asd_read_reg_dword(_ha, C##_n))
+
+#define MSTR_8BIT " Mode:%02d %30s[0x%04x]:0x%02x\n"
+#define MSTR_16BIT " Mode:%02d %30s[0x%04x]:0x%04x\n"
+#define MSTR_32BIT " Mode:%02d %30s[0x%04x]:0x%08x\n"
+
+#define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n, \
+ asd_read_reg_byte(_ha, _r))
+#define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \
+ asd_read_reg_word(_ha, _r))
+#define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \
+ asd_read_reg_dword(_ha, _r))
+
+/* can also be used for MD when the register is mode aware already */
+#define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\
+ asd_read_reg_byte(_ha, CSEQ_##_n))
+#define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+ asd_read_reg_word(_ha, CSEQ_##_n))
+#define PRINT_MIS_dword(_ha, _n) \
+ asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\
+ asd_read_reg_dword(_ha, CSEQ_##_n))
+#define PRINT_MIS_qword(_ha, _n) \
+ asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR, \
+ (unsigned long long)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n)) \
+ | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32)))
+
+#define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n)
+#define PRINT_CMDP_word(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+ #_n, \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \
+ asd_read_reg_word(_ha, CMDP_REG(_n, 7)))
+
+#define PRINT_CMDP_byte(_ha, _n) \
+asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \
+ #_n, \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \
+ asd_read_reg_byte(_ha, CMDP_REG(_n, 7)))
+
+static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha)
+{
+ int mode;
+
+ asd_printk("CSEQ STATE\n");
+
+ asd_printk("ARP2 REGISTERS\n");
+
+ PRINT_CREG_32bit(asd_ha, ARP2CTL);
+ PRINT_CREG_32bit(asd_ha, ARP2INT);
+ PRINT_CREG_32bit(asd_ha, ARP2INTEN);
+ PRINT_CREG_8bit(asd_ha, MODEPTR);
+ PRINT_CREG_8bit(asd_ha, ALTMODE);
+ PRINT_CREG_8bit(asd_ha, FLAG);
+ PRINT_CREG_8bit(asd_ha, ARP2INTCTL);
+ PRINT_CREG_16bit(asd_ha, STACK);
+ PRINT_CREG_16bit(asd_ha, PRGMCNT);
+ PRINT_CREG_16bit(asd_ha, ACCUM);
+ PRINT_CREG_16bit(asd_ha, SINDEX);
+ PRINT_CREG_16bit(asd_ha, DINDEX);
+ PRINT_CREG_8bit(asd_ha, SINDIR);
+ PRINT_CREG_8bit(asd_ha, DINDIR);
+ PRINT_CREG_8bit(asd_ha, JUMLDIR);
+ PRINT_CREG_8bit(asd_ha, ARP2HALTCODE);
+ PRINT_CREG_16bit(asd_ha, CURRADDR);
+ PRINT_CREG_16bit(asd_ha, LASTADDR);
+ PRINT_CREG_16bit(asd_ha, NXTLADDR);
+
+ asd_printk("IOP REGISTERS\n");
+
+ PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL);
+ PRINT_CREG_32bit(asd_ha, MAPPEDSCR);
+
+ asd_printk("CIO REGISTERS\n");
+
+ for (mode = 0; mode < 9; mode++)
+ PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode));
+ PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15));
+
+ for (mode = 0; mode < 9; mode++)
+ PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode));
+ PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15));
+
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode));
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode));
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode));
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode));
+
+ PRINT_CREG_8bit(asd_ha, SCRATCHPAGE);
+ for (mode = 0; mode < 8; mode++)
+ PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE,
+ CMnSCRATCHPAGE(mode));
+
+ PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON);
+ PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK);
+ PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST);
+ PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE);
+ PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC);
+ PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS);
+
+ asd_printk("SCRATCH MEMORY\n");
+
+ asd_printk("MIP 4 >>>>>\n");
+ PRINT_MIS_word(asd_ha, Q_EXE_HEAD);
+ PRINT_MIS_word(asd_ha, Q_EXE_TAIL);
+ PRINT_MIS_word(asd_ha, Q_DONE_HEAD);
+ PRINT_MIS_word(asd_ha, Q_DONE_TAIL);
+ PRINT_MIS_word(asd_ha, Q_SEND_HEAD);
+ PRINT_MIS_word(asd_ha, Q_SEND_TAIL);
+ PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD);
+ PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL);
+ PRINT_MIS_word(asd_ha, Q_COPY_HEAD);
+ PRINT_MIS_word(asd_ha, Q_COPY_TAIL);
+ PRINT_MIS_word(asd_ha, REG0);
+ PRINT_MIS_word(asd_ha, REG1);
+ PRINT_MIS_dword(asd_ha, REG2);
+ PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP);
+ PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE);
+ PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT);
+
+ asd_printk("MIP 5 >>>>\n");
+ PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE);
+ PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT);
+ PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD);
+ PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL);
+ PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB);
+ PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD);
+ PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL);
+ PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET);
+
+ asd_printk("MIP 6 >>>>\n");
+ PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0);
+ PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1);
+ PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR);
+ PRINT_MIS_byte(asd_ha, INT_ROUT_MODE);
+ PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS);
+ PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX);
+ PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX);
+ PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD);
+ PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL);
+ PRINT_MIS_byte(asd_ha, FREE_SCB_MASK);
+ PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD);
+ PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL);
+ PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD);
+ PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL);
+
+ asd_printk("MIP 7 >>>>\n");
+ PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE);
+ PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT);
+ PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD);
+ PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL);
+ PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB);
+ PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD);
+ PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL);
+ PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET);
+ PRINT_MIS_word(asd_ha, PRIMITIVE_DATA);
+ PRINT_MIS_dword(asd_ha, TIMEOUT_CONST);
+
+ asd_printk("MDP 0 >>>>\n");
+ asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n",
+ "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7");
+ PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX);
+ PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR);
+ PRINT_CMDP_word(asd_ha, Q_LINK_HEAD);
+ PRINT_CMDP_word(asd_ha, Q_LINK_TAIL);
+ PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE);
+
+ asd_printk("MDP 0 Mode 8 >>>>\n");
+ PRINT_MIS_word(asd_ha, RET_ADDR);
+ PRINT_MIS_word(asd_ha, RET_SCBPTR);
+ PRINT_MIS_word(asd_ha, SAVE_SCBPTR);
+ PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX);
+ PRINT_MIS_word(asd_ha, RESP_LEN);
+ PRINT_MIS_word(asd_ha, TMF_SCBPTR);
+ PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB);
+ PRINT_MIS_word(asd_ha, GLOBAL_HEAD);
+ PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD);
+ PRINT_MIS_byte(asd_ha, TMF_OPCODE);
+ PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS);
+ PRINT_MIS_word(asd_ha, HSB_SITE);
+ PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE);
+ PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE);
+
+ asd_printk("MDP 1 Mode 8 >>>>\n");
+ PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR);
+ PRINT_MIS_qword(asd_ha, LUN_TO_CHECK);
+
+ asd_printk("MDP 2 Mode 8 >>>>\n");
+ PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER);
+ PRINT_MIS_qword(asd_ha, HQ_DONE_BASE);
+ PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER);
+ PRINT_MIS_byte(asd_ha, HQ_DONE_PASS);
+}
+
+#define PRINT_LREG_8bit(_h, _lseq, _n) \
+ asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_16bit(_h, _lseq, _n) \
+ asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq)))
+#define PRINT_LREG_32bit(_h, _lseq, _n) \
+ asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq)))
+
+#define PRINT_LMIP_byte(_h, _lseq, _n) \
+ asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ asd_read_reg_byte(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_word(_h, _lseq, _n) \
+ asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ asd_read_reg_word(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_dword(_h, _lseq, _n) \
+ asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)))
+#define PRINT_LMIP_qword(_h, _lseq, _n) \
+ asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \
+ (unsigned long long)(((unsigned long long) \
+ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) \
+ | (((unsigned long long) \
+ asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32)))
+
+static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha,
+ u32 lseq_cio_addr, int i)
+{
+ switch (LSEQmCIOREGS[i].width) {
+ case 8:
+ asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name,
+ LSEQmCIOREGS[i].offs,
+ asd_read_reg_byte(asd_ha, lseq_cio_addr +
+ LSEQmCIOREGS[i].offs));
+
+ break;
+ case 16:
+ asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name,
+ LSEQmCIOREGS[i].offs,
+ asd_read_reg_word(asd_ha, lseq_cio_addr +
+ LSEQmCIOREGS[i].offs));
+
+ break;
+ case 32:
+ asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name,
+ LSEQmCIOREGS[i].offs,
+ asd_read_reg_dword(asd_ha, lseq_cio_addr +
+ LSEQmCIOREGS[i].offs));
+ break;
+ }
+}
+
+static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u32 moffs;
+ int mode;
+
+ asd_printk("LSEQ %d STATE\n", lseq);
+
+ asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq);
+ PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL);
+ PRINT_LREG_32bit(asd_ha, lseq, ARP2INT);
+ PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN);
+ PRINT_LREG_8bit(asd_ha, lseq, MODEPTR);
+ PRINT_LREG_8bit(asd_ha, lseq, ALTMODE);
+ PRINT_LREG_8bit(asd_ha, lseq, FLAG);
+ PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL);
+ PRINT_LREG_16bit(asd_ha, lseq, STACK);
+ PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT);
+ PRINT_LREG_16bit(asd_ha, lseq, ACCUM);
+ PRINT_LREG_16bit(asd_ha, lseq, SINDEX);
+ PRINT_LREG_16bit(asd_ha, lseq, DINDEX);
+ PRINT_LREG_8bit(asd_ha, lseq, SINDIR);
+ PRINT_LREG_8bit(asd_ha, lseq, DINDIR);
+ PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR);
+ PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE);
+ PRINT_LREG_16bit(asd_ha, lseq, CURRADDR);
+ PRINT_LREG_16bit(asd_ha, lseq, LASTADDR);
+ PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR);
+
+ asd_printk("LSEQ%d: IOP REGISTERS\n", lseq);
+
+ PRINT_LREG_32bit(asd_ha, lseq, MODECTL);
+ PRINT_LREG_32bit(asd_ha, lseq, DBGMODE);
+ PRINT_LREG_32bit(asd_ha, lseq, CONTROL);
+ PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq));
+ PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq));
+
+ asd_printk("LSEQ%d: CIO REGISTERS\n", lseq);
+ asd_printk("Mode common:\n");
+
+ for (mode = 0; mode < 8; mode++) {
+ u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+ int i;
+
+ for (i = 0; LSEQmCIOREGS[i].name; i++)
+ if (LSEQmCIOREGS[i].mode == MODE_COMMON)
+ asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i);
+ }
+
+ asd_printk("Mode unique:\n");
+ for (mode = 0; mode < 8; mode++) {
+ u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq);
+ int i;
+
+ asd_printk("Mode %d\n", mode);
+ for (i = 0; LSEQmCIOREGS[i].name; i++) {
+ if (!(LSEQmCIOREGS[i].mode & (1 << mode)))
+ continue;
+ asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i);
+ }
+ }
+
+ asd_printk("SCRATCH MEMORY\n");
+
+ asd_printk("LSEQ%d MIP 0 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD);
+ PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER);
+ PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS);
+ PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE);
+ PRINT_LMIP_word(asd_ha, lseq, CONCTL);
+ PRINT_LMIP_byte(asd_ha, lseq, CONSTAT);
+ PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES);
+ PRINT_LMIP_word(asd_ha, lseq, REG1_ISR);
+ PRINT_LMIP_word(asd_ha, lseq, REG2_ISR);
+ PRINT_LMIP_word(asd_ha, lseq, REG3_ISR);
+ PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR);
+
+ asd_printk("LSEQ%d MIP 1 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2);
+ PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL);
+ PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL);
+ PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST);
+ PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX);
+ PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX);
+
+ asd_printk("LSEQ%d MIP 2 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL);
+ PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL);
+
+ asd_printk("LSEQ%d MIP 3 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST);
+ PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT);
+ PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT);
+
+ for (mode = 0; mode < 3; mode++) {
+ asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode);
+ moffs = mode * LSEQ_MODE_SCRATCH_SIZE;
+
+ asd_printk(STR_16BIT, "RET_ADDR", 0,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "REG0_MODE", 2,
+ asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+ asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)
+ + moffs));
+ asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+ asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)
+ + moffs));
+ asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+ asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)
+ + moffs));
+ }
+
+ asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq);
+ moffs = LSEQ_MODE5_PAGE0_OFFSET;
+ asd_printk(STR_16BIT, "RET_ADDR", 0,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs));
+ asd_printk(STR_16BIT, "REG0_MODE", 2,
+ asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs));
+ asd_printk(STR_16BIT, "MODE_FLAGS", 4,
+ asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR2", 0x6,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs));
+ asd_printk(STR_16BIT, "RET_ADDR1", 0x8,
+ asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs));
+ asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB,
+ asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs));
+ asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC,
+ asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs));
+
+ asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE);
+ PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX);
+ PRINT_LMIP_word(asd_ha, lseq, RESP_LEN);
+ PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE);
+ PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL);
+ PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR);
+
+ asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD);
+ PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX);
+ PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG);
+ PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE);
+ PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE);
+ PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR);
+
+ asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq);
+ PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER);
+ PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR);
+ PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE);
+ PRINT_LMIP_word(asd_ha, lseq, IP_BITL);
+ PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG);
+ PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH);
+
+ asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE);
+ PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR);
+ PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS);
+ PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE);
+ PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT);
+ PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES);
+ PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES);
+ PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT);
+ PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT);
+
+ asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq);
+ PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0);
+ PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1);
+
+ asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq);
+ PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0);
+ PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1);
+
+ asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT);
+ PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT);
+ PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT);
+
+ asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK);
+ PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT);
+ PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK);
+ PRINT_LMIP_word(asd_ha, lseq, TAG_MASK);
+ PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG);
+ PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET);
+
+ asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS);
+ PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS);
+ PRINT_LMIP_word(asd_ha, lseq, SDB_DDB);
+ PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS);
+ PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG);
+
+ asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq);
+ PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME);
+ PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL);
+
+ asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS);
+
+ asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq);
+ PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS);
+ PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS);
+}
+
+/**
+ * asd_dump_ddb_site -- dump a CSEQ DDB site
+ * @asd_ha: pointer to host adapter structure
+ * @site_no: site number of interest
+ */
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+ if (site_no >= asd_ha->hw_prof.max_ddbs)
+ return;
+
+#define DDB_FIELDB(__name) \
+ asd_ddbsite_read_byte(asd_ha, site_no, \
+ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+#define DDB2_FIELDB(__name) \
+ asd_ddbsite_read_byte(asd_ha, site_no, \
+ offsetof(struct asd_ddb_stp_sata_target_port, __name))
+#define DDB_FIELDW(__name) \
+ asd_ddbsite_read_word(asd_ha, site_no, \
+ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+#define DDB_FIELDD(__name) \
+ asd_ddbsite_read_dword(asd_ha, site_no, \
+ offsetof(struct asd_ddb_ssp_smp_target_port, __name))
+
+ asd_printk("DDB: 0x%02x\n", site_no);
+ asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type));
+ asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate));
+ asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag)));
+ asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head)));
+ asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended));
+ asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type));
+ asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def));
+ asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features));
+ asd_printk("Pathway Blocked Count: 0x%02x\n",
+ DDB_FIELDB(pathway_blocked_count));
+ asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time));
+ asd_printk("more_compat_features: 0x%08x\n",
+ DDB_FIELDD(more_compat_features));
+ asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask));
+ asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags));
+ asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2));
+ asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail));
+ asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail));
+ asd_printk("Active Task Count: 0x%04x\n",
+ DDB_FIELDW(active_task_count));
+ asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason));
+ asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout));
+ asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp));
+}
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha)
+{
+#define DDB0_FIELDB(__name) \
+ asd_ddbsite_read_byte(asd_ha, 0, \
+ offsetof(struct asd_ddb_seq_shared, __name))
+#define DDB0_FIELDW(__name) \
+ asd_ddbsite_read_word(asd_ha, 0, \
+ offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDD(__name) \
+ asd_ddbsite_read_dword(asd_ha,0 , \
+ offsetof(struct asd_ddb_seq_shared, __name))
+
+#define DDB0_FIELDA(__name, _o) \
+ asd_ddbsite_read_byte(asd_ha, 0, \
+ offsetof(struct asd_ddb_seq_shared, __name)+_o)
+
+
+ asd_printk("DDB: 0\n");
+ asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head));
+ asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail));
+ asd_printk("q_free_ddb_cnt:%04x\n", DDB0_FIELDW(q_free_ddb_cnt));
+ asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head));
+ asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail));
+ asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock));
+ asd_printk("smp_conn_tag:%04x\n", DDB0_FIELDW(smp_conn_tag));
+ asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt));
+ asd_printk("est_nexus_buf_thresh:%04x\n",
+ DDB0_FIELDW(est_nexus_buf_thresh));
+ asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active));
+ asd_printk("phy_is_up:%02x\n", DDB0_FIELDB(phy_is_up));
+ asd_printk("port_map_by_links:%02x %02x %02x %02x "
+ "%02x %02x %02x %02x\n",
+ DDB0_FIELDA(port_map_by_links, 0),
+ DDB0_FIELDA(port_map_by_links, 1),
+ DDB0_FIELDA(port_map_by_links, 2),
+ DDB0_FIELDA(port_map_by_links, 3),
+ DDB0_FIELDA(port_map_by_links, 4),
+ DDB0_FIELDA(port_map_by_links, 5),
+ DDB0_FIELDA(port_map_by_links, 6),
+ DDB0_FIELDA(port_map_by_links, 7));
+}
+
+static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no)
+{
+
+#define SCB_FIELDB(__name) \
+ asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header) \
+ + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDW(__name) \
+ asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header) \
+ + offsetof(struct initiate_ssp_task, __name))
+#define SCB_FIELDD(__name) \
+ asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header) \
+ + offsetof(struct initiate_ssp_task, __name))
+
+ asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len));
+ asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type));
+ asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag));
+ asd_printk("Target Port Xfer Tag: 0x%04x.\n",
+ SCB_FIELDW(ssp_frame.tptt));
+ asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs));
+ asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count));
+}
+
+/**
+ * asd_dump_scb_sites -- dump currently used CSEQ SCB sites
+ * @asd_ha: pointer to host adapter struct
+ */
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha)
+{
+ u16 site_no;
+
+ for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) {
+ u8 opcode;
+
+ if (!SCB_SITE_VALID(site_no))
+ continue;
+
+ /* We are only interested in SCB sites currently used.
+ */
+ opcode = asd_scbsite_read_byte(asd_ha, site_no,
+ offsetof(struct scb_header,
+ opcode));
+ if (opcode == 0xFF)
+ continue;
+
+ asd_printk("\nSCB: 0x%x\n", site_no);
+ asd_dump_scb_site(asd_ha, site_no);
+ }
+}
+
+/**
+ * ads_dump_seq_state -- dump CSEQ and LSEQ states
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of LSEQs of interest
+ */
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+ int lseq;
+
+ asd_dump_cseq_state(asd_ha);
+
+ if (lseq_mask != 0)
+ for_each_sequencer(lseq_mask, lseq_mask, lseq)
+ asd_dump_lseq_state(asd_ha, lseq);
+}
+
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+ struct done_list_struct *dl)
+{
+ unsigned long flags;
+ int i;
+
+ switch ((dl->status_block[1] & 0x70) >> 3) {
+ case SAS_PROTO_STP:
+ ASD_DPRINTK("STP proto device-to-host FIS:\n");
+ break;
+ default:
+ case SAS_PROTO_SSP:
+ ASD_DPRINTK("SAS proto IDENTIFY:\n");
+ break;
+ }
+ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+ for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4)
+ ASD_DPRINTK("%02x: %02x %02x %02x %02x\n",
+ i,
+ phy->frame_rcvd[i],
+ phy->frame_rcvd[i+1],
+ phy->frame_rcvd[i+2],
+ phy->frame_rcvd[i+3]);
+ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+}
+
+static inline void asd_dump_scb(struct asd_ascb *ascb, int ind)
+{
+ asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, "
+ "index:%d, opcode:0x%02x\n",
+ ind, ascb->dma_scb.vaddr,
+ (unsigned long long)ascb->dma_scb.dma_handle,
+ (unsigned long long)
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+}
+
+void asd_dump_scb_list(struct asd_ascb *ascb, int num)
+{
+ int i = 0;
+
+ asd_printk("dumping %d scbs:\n", num);
+
+ asd_dump_scb(ascb, i++);
+ --num;
+
+ if (num > 0 && !list_empty(&ascb->list)) {
+ struct list_head *el;
+
+ list_for_each(el, &ascb->list) {
+ struct asd_ascb *s = list_entry(el, struct asd_ascb,
+ list);
+ asd_dump_scb(s, i++);
+ if (--num <= 0)
+ break;
+ }
+ }
+}
+
+#endif /* ASD_DEBUG */
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h
new file mode 100644
index 00000000000..0c388e7da6b
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_dump.h
@@ -0,0 +1,52 @@
+/*
+ * Aic94xx SAS/SATA driver dump header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_DUMP_H_
+#define _AIC94XX_DUMP_H_
+
+#ifdef ASD_DEBUG
+
+void asd_dump_ddb_0(struct asd_ha_struct *asd_ha);
+void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no);
+void asd_dump_scb_sites(struct asd_ha_struct *asd_ha);
+void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+void asd_dump_frame_rcvd(struct asd_phy *phy,
+ struct done_list_struct *dl);
+void asd_dump_scb_list(struct asd_ascb *ascb, int num);
+#else /* ASD_DEBUG */
+
+static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha,
+ u16 site_no) { }
+static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { }
+static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha,
+ u8 lseq_mask) { }
+static inline void asd_dump_frame_rcvd(struct asd_phy *phy,
+ struct done_list_struct *dl) { }
+static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { }
+#endif /* ASD_DEBUG */
+
+#endif /* _AIC94XX_DUMP_H_ */
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
new file mode 100644
index 00000000000..1d8c5e5f442
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -0,0 +1,1376 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+u32 MBAR0_SWB_SIZE;
+
+/* ---------- Initialization ---------- */
+
+static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha)
+{
+ extern char sas_addr_str[];
+ /* If the user has specified a WWN it overrides other settings
+ */
+ if (sas_addr_str[0] != '\0')
+ asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr,
+ sas_addr_str);
+ else if (asd_ha->hw_prof.sas_addr[0] != 0)
+ asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr);
+}
+
+static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0)
+ continue;
+ /* Set a phy's address only if it has none.
+ */
+ ASD_DPRINTK("setting phy%d addr to %llx\n", i,
+ SAS_ADDR(asd_ha->hw_prof.sas_addr));
+ memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr,
+ asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+ }
+}
+
+/* ---------- PHY initialization ---------- */
+
+static void asd_init_phy_identify(struct asd_phy *phy)
+{
+ phy->identify_frame = phy->id_frm_tok->vaddr;
+
+ memset(phy->identify_frame, 0, sizeof(*phy->identify_frame));
+
+ phy->identify_frame->dev_type = SAS_END_DEV;
+ if (phy->sas_phy.role & PHY_ROLE_INITIATOR)
+ phy->identify_frame->initiator_bits = phy->sas_phy.iproto;
+ if (phy->sas_phy.role & PHY_ROLE_TARGET)
+ phy->identify_frame->target_bits = phy->sas_phy.tproto;
+ memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr,
+ SAS_ADDR_SIZE);
+ phy->identify_frame->phy_id = phy->sas_phy.id;
+}
+
+static int asd_init_phy(struct asd_phy *phy)
+{
+ struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ sas_phy->enabled = 1;
+ sas_phy->class = SAS;
+ sas_phy->iproto = SAS_PROTO_ALL;
+ sas_phy->tproto = 0;
+ sas_phy->type = PHY_TYPE_PHYSICAL;
+ sas_phy->role = PHY_ROLE_INITIATOR;
+ sas_phy->oob_mode = OOB_NOT_CONNECTED;
+ sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ phy->id_frm_tok = asd_alloc_coherent(asd_ha,
+ sizeof(*phy->identify_frame),
+ GFP_KERNEL);
+ if (!phy->id_frm_tok) {
+ asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id);
+ return -ENOMEM;
+ } else
+ asd_init_phy_identify(phy);
+
+ memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd));
+
+ return 0;
+}
+
+static int asd_init_phys(struct asd_ha_struct *asd_ha)
+{
+ u8 i;
+ u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ struct asd_phy *phy = &asd_ha->phys[i];
+
+ phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
+
+ phy->sas_phy.enabled = 0;
+ phy->sas_phy.id = i;
+ phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0];
+ phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0];
+ phy->sas_phy.ha = &asd_ha->sas_ha;
+ phy->sas_phy.lldd_phy = phy;
+ }
+
+ /* Now enable and initialize only the enabled phys. */
+ for_each_phy(phy_mask, phy_mask, i) {
+ int err = asd_init_phy(&asd_ha->phys[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* ---------- Sliding windows ---------- */
+
+static int asd_init_sw(struct asd_ha_struct *asd_ha)
+{
+ struct pci_dev *pcidev = asd_ha->pcidev;
+ int err;
+ u32 v;
+
+ /* Unlock MBARs */
+ err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v);
+ if (err) {
+ asd_printk("couldn't access conf. space of %s\n",
+ pci_name(pcidev));
+ goto Err;
+ }
+ if (v)
+ err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v);
+ if (err) {
+ asd_printk("couldn't write to MBAR_KEY of %s\n",
+ pci_name(pcidev));
+ goto Err;
+ }
+
+ /* Set sliding windows A, B and C to point to proper internal
+ * memory regions.
+ */
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR);
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB,
+ REG_BASE_ADDR_CSEQCIO);
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI);
+ asd_ha->io_handle[0].swa_base = REG_BASE_ADDR;
+ asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO;
+ asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI;
+ MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80;
+ if (!asd_ha->iospace) {
+ /* MBAR1 will point to OCM (On Chip Memory) */
+ pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR);
+ asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR;
+ }
+ spin_lock_init(&asd_ha->iolock);
+Err:
+ return err;
+}
+
+/* ---------- SCB initialization ---------- */
+
+/**
+ * asd_init_scbs - manually allocate the first SCB.
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This allocates the very first SCB which would be sent to the
+ * sequencer for execution. Its bus address is written to
+ * CSEQ_Q_NEW_POINTER, mode page 2, mode 8. Since the bus address of
+ * the _next_ scb to be DMA-ed to the host adapter is read from the last
+ * SCB DMA-ed to the host adapter, we have to always stay one step
+ * ahead of the sequencer and keep one SCB already allocated.
+ */
+static int asd_init_scbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int bitmap_bytes;
+
+ /* allocate the index array and bitmap */
+ asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs;
+ asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits*
+ sizeof(void *), GFP_KERNEL);
+ if (!asd_ha->seq.tc_index_array)
+ return -ENOMEM;
+
+ bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8;
+ bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+ asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+ if (!asd_ha->seq.tc_index_bitmap)
+ return -ENOMEM;
+
+ spin_lock_init(&seq->tc_index_lock);
+
+ seq->next_scb.size = sizeof(struct scb);
+ seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL,
+ &seq->next_scb.dma_handle);
+ if (!seq->next_scb.vaddr) {
+ kfree(asd_ha->seq.tc_index_bitmap);
+ kfree(asd_ha->seq.tc_index_array);
+ asd_ha->seq.tc_index_bitmap = NULL;
+ asd_ha->seq.tc_index_array = NULL;
+ return -ENOMEM;
+ }
+
+ seq->pending = 0;
+ spin_lock_init(&seq->pend_q_lock);
+ INIT_LIST_HEAD(&seq->pend_q);
+
+ return 0;
+}
+
+static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha)
+{
+ asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE;
+ asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE;
+ ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n",
+ asd_ha->hw_prof.max_scbs,
+ asd_ha->hw_prof.max_ddbs);
+}
+
+/* ---------- Done List initialization ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long);
+
+static int asd_init_dl(struct asd_ha_struct *asd_ha)
+{
+ asd_ha->seq.actual_dl
+ = asd_alloc_coherent(asd_ha,
+ ASD_DL_SIZE * sizeof(struct done_list_struct),
+ GFP_KERNEL);
+ if (!asd_ha->seq.actual_dl)
+ return -ENOMEM;
+ asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr;
+ asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE;
+ asd_ha->seq.dl_next = 0;
+ tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler,
+ (unsigned long) asd_ha);
+
+ return 0;
+}
+
+/* ---------- EDB and ESCB init ---------- */
+
+static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags);
+ if (!seq->edb_arr)
+ return -ENOMEM;
+
+ for (i = 0; i < seq->num_edbs; i++) {
+ seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE,
+ gfp_flags);
+ if (!seq->edb_arr[i])
+ goto Err_unroll;
+ memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE);
+ }
+
+ ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs);
+
+ return 0;
+
+Err_unroll:
+ for (i-- ; i >= 0; i--)
+ asd_free_coherent(asd_ha, seq->edb_arr[i]);
+ kfree(seq->edb_arr);
+ seq->edb_arr = NULL;
+
+ return -ENOMEM;
+}
+
+static int asd_alloc_escbs(struct asd_ha_struct *asd_ha,
+ gfp_t gfp_flags)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ struct asd_ascb *escb;
+ int i, escbs;
+
+ seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr),
+ gfp_flags);
+ if (!seq->escb_arr)
+ return -ENOMEM;
+
+ escbs = seq->num_escbs;
+ escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags);
+ if (!escb) {
+ asd_printk("couldn't allocate list of escbs\n");
+ goto Err;
+ }
+ seq->num_escbs -= escbs; /* subtract what was not allocated */
+ ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs);
+
+ for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next,
+ struct asd_ascb,
+ list)) {
+ seq->escb_arr[i] = escb;
+ escb->scb->header.opcode = EMPTY_SCB;
+ }
+
+ return 0;
+Err:
+ kfree(seq->escb_arr);
+ seq->escb_arr = NULL;
+ return -ENOMEM;
+
+}
+
+static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i, k, z = 0;
+
+ for (i = 0; i < seq->num_escbs; i++) {
+ struct asd_ascb *ascb = seq->escb_arr[i];
+ struct empty_scb *escb = &ascb->scb->escb;
+
+ ascb->edb_index = z;
+
+ escb->num_valid = ASD_EDBS_PER_SCB;
+
+ for (k = 0; k < ASD_EDBS_PER_SCB; k++) {
+ struct sg_el *eb = &escb->eb[k];
+ struct asd_dma_tok *edb = seq->edb_arr[z++];
+
+ memset(eb, 0, sizeof(*eb));
+ eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle));
+ eb->size = cpu_to_le32(((u32) edb->size));
+ }
+ }
+}
+
+/**
+ * asd_init_escbs -- allocate and initialize empty scbs
+ * @asd_ha: pointer to host adapter structure
+ *
+ * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers.
+ * They transport sense data, etc.
+ */
+static int asd_init_escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int err = 0;
+
+ /* Allocate two empty data buffers (edb) per sequencer. */
+ int edbs = 2*(1+asd_ha->hw_prof.num_phys);
+
+ seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB;
+ seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB;
+
+ err = asd_alloc_edbs(asd_ha, GFP_KERNEL);
+ if (err) {
+ asd_printk("couldn't allocate edbs\n");
+ return err;
+ }
+
+ err = asd_alloc_escbs(asd_ha, GFP_KERNEL);
+ if (err) {
+ asd_printk("couldn't allocate escbs\n");
+ return err;
+ }
+
+ asd_assign_edbs2escbs(asd_ha);
+ /* In order to insure that normal SCBs do not overfill sequencer
+ * memory and leave no space for escbs (halting condition),
+ * we increment pending here by the number of escbs. However,
+ * escbs are never pending.
+ */
+ seq->pending = seq->num_escbs;
+ seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2;
+
+ return 0;
+}
+
+/* ---------- HW initialization ---------- */
+
+/**
+ * asd_chip_hardrst -- hard reset the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This takes 16 cycles and is synchronous to CFCLK, which runs
+ * at 200 MHz, so this should take at most 80 nanoseconds.
+ */
+int asd_chip_hardrst(struct asd_ha_struct *asd_ha)
+{
+ int i;
+ int count = 100;
+ u32 reg;
+
+ for (i = 0 ; i < 4 ; i++) {
+ asd_write_reg_dword(asd_ha, COMBIST, HARDRST);
+ }
+
+ do {
+ udelay(1);
+ reg = asd_read_reg_dword(asd_ha, CHIMINT);
+ if (reg & HARDRSTDET) {
+ asd_write_reg_dword(asd_ha, CHIMINT,
+ HARDRSTDET|PORRSTDET);
+ return 0;
+ }
+ } while (--count > 0);
+
+ return -ENODEV;
+}
+
+/**
+ * asd_init_chip -- initialize the chip
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Hard resets the chip, disables HA interrupts, downloads the sequnecer
+ * microcode and starts the sequencers. The caller has to explicitly
+ * enable HA interrupts with asd_enable_ints(asd_ha).
+ */
+static int asd_init_chip(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = asd_chip_hardrst(asd_ha);
+ if (err) {
+ asd_printk("couldn't hard reset %s\n",
+ pci_name(asd_ha->pcidev));
+ goto out;
+ }
+
+ asd_disable_ints(asd_ha);
+
+ err = asd_init_seqs(asd_ha);
+ if (err) {
+ asd_printk("couldn't init seqs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto out;
+ }
+
+ err = asd_start_seqs(asd_ha);
+ if (err) {
+ asd_printk("coudln't start seqs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto out;
+ }
+out:
+ return err;
+}
+
+#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE))
+
+static int max_devs = 0;
+module_param_named(max_devs, max_devs, int, S_IRUGO);
+MODULE_PARM_DESC(max_devs, "\n"
+ "\tMaximum number of SAS devices to support (not LUs).\n"
+ "\tDefault: 2176, Maximum: 65663.\n");
+
+static int max_cmnds = 0;
+module_param_named(max_cmnds, max_cmnds, int, S_IRUGO);
+MODULE_PARM_DESC(max_cmnds, "\n"
+ "\tMaximum number of commands queuable.\n"
+ "\tDefault: 512, Maximum: 66047.\n");
+
+static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha)
+{
+ unsigned long dma_addr = OCM_BASE_ADDR;
+ u32 d;
+
+ dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+ asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr);
+ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+ d |= 4;
+ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+ asd_ha->hw_prof.max_ddbs += MAX_DEVS;
+}
+
+static int asd_extend_devctx(struct asd_ha_struct *asd_ha)
+{
+ dma_addr_t dma_handle;
+ unsigned long dma_addr;
+ u32 d;
+ int size;
+
+ asd_extend_devctx_ocm(asd_ha);
+
+ asd_ha->hw_prof.ddb_ext = NULL;
+ if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) {
+ max_devs = asd_ha->hw_prof.max_ddbs;
+ return 0;
+ }
+
+ size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE;
+
+ asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+ if (!asd_ha->hw_prof.ddb_ext) {
+ asd_printk("couldn't allocate memory for %d devices\n",
+ max_devs);
+ max_devs = asd_ha->hw_prof.max_ddbs;
+ return -ENOMEM;
+ }
+ dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle;
+ dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE);
+ dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE;
+ dma_handle = (dma_addr_t) dma_addr;
+ asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle);
+ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+ d &= ~4;
+ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+ asd_ha->hw_prof.max_ddbs = max_devs;
+
+ return 0;
+}
+
+static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha)
+{
+ dma_addr_t dma_handle;
+ unsigned long dma_addr;
+ u32 d;
+ int size;
+
+ asd_ha->hw_prof.scb_ext = NULL;
+ if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) {
+ max_cmnds = asd_ha->hw_prof.max_scbs;
+ return 0;
+ }
+
+ size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE;
+
+ asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL);
+ if (!asd_ha->hw_prof.scb_ext) {
+ asd_printk("couldn't allocate memory for %d commands\n",
+ max_cmnds);
+ max_cmnds = asd_ha->hw_prof.max_scbs;
+ return -ENOMEM;
+ }
+ dma_handle = asd_ha->hw_prof.scb_ext->dma_handle;
+ dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE);
+ dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE;
+ dma_handle = (dma_addr_t) dma_addr;
+ asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle);
+ d = asd_read_reg_dword(asd_ha, CTXDOMAIN);
+ d &= ~1;
+ asd_write_reg_dword(asd_ha, CTXDOMAIN, d);
+
+ asd_ha->hw_prof.max_scbs = max_cmnds;
+
+ return 0;
+}
+
+/**
+ * asd_init_ctxmem -- initialize context memory
+ * asd_ha: pointer to host adapter structure
+ *
+ * This function sets the maximum number of SCBs and
+ * DDBs which can be used by the sequencer. This is normally
+ * 512 and 128 respectively. If support for more SCBs or more DDBs
+ * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are
+ * initialized here to extend context memory to point to host memory,
+ * thus allowing unlimited support for SCBs and DDBs -- only limited
+ * by host memory.
+ */
+static int asd_init_ctxmem(struct asd_ha_struct *asd_ha)
+{
+ int bitmap_bytes;
+
+ asd_get_max_scb_ddb(asd_ha);
+ asd_extend_devctx(asd_ha);
+ asd_extend_cmdctx(asd_ha);
+
+ /* The kernel wants bitmaps to be unsigned long sized. */
+ bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8;
+ bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long);
+ asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL);
+ if (!asd_ha->hw_prof.ddb_bitmap)
+ return -ENOMEM;
+ spin_lock_init(&asd_ha->hw_prof.ddb_lock);
+
+ return 0;
+}
+
+int asd_init_hw(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ u32 v;
+
+ err = asd_init_sw(asd_ha);
+ if (err)
+ return err;
+
+ err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v);
+ if (err) {
+ asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+ pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL,
+ v | SC_TMR_DIS);
+ if (err) {
+ asd_printk("couldn't disable split completion timer of %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+
+ err = asd_read_ocm(asd_ha);
+ if (err) {
+ asd_printk("couldn't read ocm(%d)\n", err);
+ /* While suspicios, it is not an error that we
+ * couldn't read the OCM. */
+ }
+
+ err = asd_read_flash(asd_ha);
+ if (err) {
+ asd_printk("couldn't read flash(%d)\n", err);
+ /* While suspicios, it is not an error that we
+ * couldn't read FLASH memory.
+ */
+ }
+
+ asd_init_ctxmem(asd_ha);
+
+ asd_get_user_sas_addr(asd_ha);
+ if (!asd_ha->hw_prof.sas_addr[0]) {
+ asd_printk("No SAS Address provided for %s\n",
+ pci_name(asd_ha->pcidev));
+ err = -ENODEV;
+ goto Out;
+ }
+
+ asd_propagate_sas_addr(asd_ha);
+
+ err = asd_init_phys(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize phys for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Out;
+ }
+
+ err = asd_init_scbs(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize scbs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Out;
+ }
+
+ err = asd_init_dl(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize the done list:%d\n",
+ err);
+ goto Out;
+ }
+
+ err = asd_init_escbs(asd_ha);
+ if (err) {
+ asd_printk("couldn't initialize escbs\n");
+ goto Out;
+ }
+
+ err = asd_init_chip(asd_ha);
+ if (err) {
+ asd_printk("couldn't init the chip\n");
+ goto Out;
+ }
+Out:
+ return err;
+}
+
+/* ---------- Chip reset ---------- */
+
+/**
+ * asd_chip_reset -- reset the host adapter, etc
+ * @asd_ha: pointer to host adapter structure of interest
+ *
+ * Called from the ISR. Hard reset the chip. Let everything
+ * timeout. This should be no different than hot-unplugging the
+ * host adapter. Once everything times out we'll init the chip with
+ * a call to asd_init_chip() and enable interrupts with asd_enable_ints().
+ * XXX finish.
+ */
+static void asd_chip_reset(struct asd_ha_struct *asd_ha)
+{
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+
+ ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev));
+ asd_chip_hardrst(asd_ha);
+ sas_ha->notify_ha_event(sas_ha, HAE_RESET);
+}
+
+/* ---------- Done List Routines ---------- */
+
+static void asd_dl_tasklet_handler(unsigned long data)
+{
+ struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data;
+ struct asd_seq_data *seq = &asd_ha->seq;
+ unsigned long flags;
+
+ while (1) {
+ struct done_list_struct *dl = &seq->dl[seq->dl_next];
+ struct asd_ascb *ascb;
+
+ if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle)
+ break;
+
+ /* find the aSCB */
+ spin_lock_irqsave(&seq->tc_index_lock, flags);
+ ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index));
+ spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+ if (unlikely(!ascb)) {
+ ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n");
+ goto next_1;
+ } else if (ascb->scb->header.opcode == EMPTY_SCB) {
+ goto out;
+ } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) {
+ goto next_1;
+ }
+ spin_lock_irqsave(&seq->pend_q_lock, flags);
+ list_del_init(&ascb->list);
+ seq->pending--;
+ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+ out:
+ ascb->tasklet_complete(ascb, dl);
+
+ next_1:
+ seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1);
+ if (!seq->dl_next)
+ seq->dl_toggle ^= DL_TOGGLE_MASK;
+ }
+}
+
+/* ---------- Interrupt Service Routines ---------- */
+
+/**
+ * asd_process_donelist_isr -- schedule processing of done list entries
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha)
+{
+ tasklet_schedule(&asd_ha->seq.dl_tasklet);
+}
+
+/**
+ * asd_com_sas_isr -- process device communication interrupt (COMINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha)
+{
+ u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT);
+
+ /* clear COMSTAT int */
+ asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF);
+
+ if (comstat & CSBUFPERR) {
+ asd_printk("%s: command/status buffer dma parity error\n",
+ pci_name(asd_ha->pcidev));
+ } else if (comstat & CSERR) {
+ int i;
+ u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+ dmaerr &= 0xFF;
+ asd_printk("%s: command/status dma error, DMAERR: 0x%02x, "
+ "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n",
+ pci_name(asd_ha->pcidev),
+ dmaerr,
+ asd_read_reg_dword(asd_ha, CSDMAADR),
+ asd_read_reg_dword(asd_ha, CSDMAADR+4));
+ asd_printk("CSBUFFER:\n");
+ for (i = 0; i < 8; i++) {
+ asd_printk("%08x %08x %08x %08x\n",
+ asd_read_reg_dword(asd_ha, CSBUFFER),
+ asd_read_reg_dword(asd_ha, CSBUFFER+4),
+ asd_read_reg_dword(asd_ha, CSBUFFER+8),
+ asd_read_reg_dword(asd_ha, CSBUFFER+12));
+ }
+ asd_dump_seq_state(asd_ha, 0);
+ } else if (comstat & OVLYERR) {
+ u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR);
+ dmaerr = (dmaerr >> 8) & 0xFF;
+ asd_printk("%s: overlay dma error:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ dmaerr);
+ }
+ asd_chip_reset(asd_ha);
+}
+
+static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus)
+{
+ static const char *halt_code[256] = {
+ "UNEXPECTED_INTERRUPT0",
+ "UNEXPECTED_INTERRUPT1",
+ "UNEXPECTED_INTERRUPT2",
+ "UNEXPECTED_INTERRUPT3",
+ "UNEXPECTED_INTERRUPT4",
+ "UNEXPECTED_INTERRUPT5",
+ "UNEXPECTED_INTERRUPT6",
+ "UNEXPECTED_INTERRUPT7",
+ "UNEXPECTED_INTERRUPT8",
+ "UNEXPECTED_INTERRUPT9",
+ "UNEXPECTED_INTERRUPT10",
+ [11 ... 19] = "unknown[11,19]",
+ "NO_FREE_SCB_AVAILABLE",
+ "INVALID_SCB_OPCODE",
+ "INVALID_MBX_OPCODE",
+ "INVALID_ATA_STATE",
+ "ATA_QUEUE_FULL",
+ "ATA_TAG_TABLE_FAULT",
+ "ATA_TAG_MASK_FAULT",
+ "BAD_LINK_QUEUE_STATE",
+ "DMA2CHIM_QUEUE_ERROR",
+ "EMPTY_SCB_LIST_FULL",
+ "unknown[30]",
+ "IN_USE_SCB_ON_FREE_LIST",
+ "BAD_OPEN_WAIT_STATE",
+ "INVALID_STP_AFFILIATION",
+ "unknown[34]",
+ "EXEC_QUEUE_ERROR",
+ "TOO_MANY_EMPTIES_NEEDED",
+ "EMPTY_REQ_QUEUE_ERROR",
+ "Q_MONIRTT_MGMT_ERROR",
+ "TARGET_MODE_FLOW_ERROR",
+ "DEVICE_QUEUE_NOT_FOUND",
+ "START_IRTT_TIMER_ERROR",
+ "ABORT_TASK_ILLEGAL_REQ",
+ [43 ... 255] = "unknown[43,255]"
+ };
+
+ if (dchstatus & CSEQINT) {
+ u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT);
+
+ if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) {
+ asd_printk("%s: CSEQ arp2int:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ arp2int);
+ } else if (arp2int & ARP2HALTC)
+ asd_printk("%s: CSEQ halted: %s\n",
+ pci_name(asd_ha->pcidev),
+ halt_code[(arp2int>>16)&0xFF]);
+ else
+ asd_printk("%s: CARP2INT:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ arp2int);
+ }
+ if (dchstatus & LSEQINT_MASK) {
+ int lseq;
+ u8 lseq_mask = dchstatus & LSEQINT_MASK;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ u32 arp2int = asd_read_reg_dword(asd_ha,
+ LmARP2INT(lseq));
+ if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR
+ | ARP2CIOPERR)) {
+ asd_printk("%s: LSEQ%d arp2int:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ lseq, arp2int);
+ /* XXX we should only do lseq reset */
+ } else if (arp2int & ARP2HALTC)
+ asd_printk("%s: LSEQ%d halted: %s\n",
+ pci_name(asd_ha->pcidev),
+ lseq,halt_code[(arp2int>>16)&0xFF]);
+ else
+ asd_printk("%s: LSEQ%d ARP2INT:0x%x\n",
+ pci_name(asd_ha->pcidev), lseq,
+ arp2int);
+ }
+ }
+ asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_dch_sas_isr -- process device channel interrupt (DEVINT)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha)
+{
+ u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS);
+
+ if (dchstatus & CFIFTOERR) {
+ asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev));
+ asd_chip_reset(asd_ha);
+ } else
+ asd_arp2_err(asd_ha, dchstatus);
+}
+
+/**
+ * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR)
+ * @asd_ha: pointer to host adapter structure
+ */
+static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha)
+{
+ u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R);
+
+ if (!(stat0r & ASIERR)) {
+ asd_printk("hmm, EXSI interrupted but no error?\n");
+ return;
+ }
+
+ if (stat0r & ASIFMTERR) {
+ asd_printk("ASI SEEPROM format error for %s\n",
+ pci_name(asd_ha->pcidev));
+ } else if (stat0r & ASISEECHKERR) {
+ u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R);
+ asd_printk("ASI SEEPROM checksum 0x%x error for %s\n",
+ stat1r & CHECKSUM_MASK,
+ pci_name(asd_ha->pcidev));
+ } else {
+ u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR);
+
+ if (!(statr & CPI2ASIMSTERR_MASK)) {
+ ASD_DPRINTK("hmm, ASIERR?\n");
+ return;
+ } else {
+ u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR);
+ u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR);
+
+ asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, "
+ "count: 0x%x, byteen: 0x%x, targerr: 0x%x "
+ "master id: 0x%x, master err: 0x%x\n",
+ pci_name(asd_ha->pcidev),
+ addr, data,
+ (statr & CPI2ASIBYTECNT_MASK) >> 16,
+ (statr & CPI2ASIBYTEEN_MASK) >> 12,
+ (statr & CPI2ASITARGERR_MASK) >> 8,
+ (statr & CPI2ASITARGMID_MASK) >> 4,
+ (statr & CPI2ASIMSTERR_MASK));
+ }
+ }
+ asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hst_pcix_isr -- process host interface interrupts
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Asserted on PCIX errors: target abort, etc.
+ */
+static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
+{
+ u16 status;
+ u32 pcix_status;
+ u32 ecc_status;
+
+ pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status);
+ pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status);
+ pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status);
+
+ if (status & PCI_STATUS_DETECTED_PARITY)
+ asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev));
+ else if (status & PCI_STATUS_REC_MASTER_ABORT)
+ asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev));
+ else if (status & PCI_STATUS_REC_TARGET_ABORT)
+ asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev));
+ else if (status & PCI_STATUS_PARITY)
+ asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev));
+ else if (pcix_status & RCV_SCE) {
+ asd_printk("received split completion error for %s\n",
+ pci_name(asd_ha->pcidev));
+ pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+ /* XXX: Abort task? */
+ return;
+ } else if (pcix_status & UNEXP_SC) {
+ asd_printk("unexpected split completion for %s\n",
+ pci_name(asd_ha->pcidev));
+ pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status);
+ /* ignore */
+ return;
+ } else if (pcix_status & SC_DISCARD)
+ asd_printk("split completion discarded for %s\n",
+ pci_name(asd_ha->pcidev));
+ else if (ecc_status & UNCOR_ECCERR)
+ asd_printk("uncorrectable ECC error for %s\n",
+ pci_name(asd_ha->pcidev));
+ asd_chip_reset(asd_ha);
+}
+
+/**
+ * asd_hw_isr -- host adapter interrupt service routine
+ * @irq: ignored
+ * @dev_id: pointer to host adapter structure
+ * @regs: ignored
+ *
+ * The ISR processes done list entries and level 3 error handling.
+ */
+irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct asd_ha_struct *asd_ha = dev_id;
+ u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
+
+ if (!chimint)
+ return IRQ_NONE;
+
+ asd_write_reg_dword(asd_ha, CHIMINT, chimint);
+ (void) asd_read_reg_dword(asd_ha, CHIMINT);
+
+ if (chimint & DLAVAIL)
+ asd_process_donelist_isr(asd_ha);
+ if (chimint & COMINT)
+ asd_com_sas_isr(asd_ha);
+ if (chimint & DEVINT)
+ asd_dch_sas_isr(asd_ha);
+ if (chimint & INITERR)
+ asd_rbi_exsi_isr(asd_ha);
+ if (chimint & HOSTERR)
+ asd_hst_pcix_isr(asd_ha);
+
+ return IRQ_HANDLED;
+}
+
+/* ---------- SCB handling ---------- */
+
+static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha,
+ gfp_t gfp_flags)
+{
+ extern kmem_cache_t *asd_ascb_cache;
+ struct asd_seq_data *seq = &asd_ha->seq;
+ struct asd_ascb *ascb;
+ unsigned long flags;
+
+ ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags);
+
+ if (ascb) {
+ memset(ascb, 0, sizeof(*ascb));
+ ascb->dma_scb.size = sizeof(struct scb);
+ ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool,
+ gfp_flags,
+ &ascb->dma_scb.dma_handle);
+ if (!ascb->dma_scb.vaddr) {
+ kmem_cache_free(asd_ascb_cache, ascb);
+ return NULL;
+ }
+ memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb));
+ asd_init_ascb(asd_ha, ascb);
+
+ spin_lock_irqsave(&seq->tc_index_lock, flags);
+ ascb->tc_index = asd_tc_index_get(seq, ascb);
+ spin_unlock_irqrestore(&seq->tc_index_lock, flags);
+ if (ascb->tc_index == -1)
+ goto undo;
+
+ ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index);
+ }
+
+ return ascb;
+undo:
+ dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+ ascb->dma_scb.dma_handle);
+ kmem_cache_free(asd_ascb_cache, ascb);
+ ASD_DPRINTK("no index for ascb\n");
+ return NULL;
+}
+
+/**
+ * asd_ascb_alloc_list -- allocate a list of aSCBs
+ * @asd_ha: pointer to host adapter structure
+ * @num: pointer to integer number of aSCBs
+ * @gfp_flags: GFP_ flags.
+ *
+ * This is the only function which is used to allocate aSCBs.
+ * It can allocate one or many. If more than one, then they form
+ * a linked list in two ways: by their list field of the ascb struct
+ * and by the next_scb field of the scb_header.
+ *
+ * Returns NULL if no memory was available, else pointer to a list
+ * of ascbs. When this function returns, @num would be the number
+ * of SCBs which were not able to be allocated, 0 if all requested
+ * were able to be allocated.
+ */
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+ *asd_ha, int *num,
+ gfp_t gfp_flags)
+{
+ struct asd_ascb *first = NULL;
+
+ for ( ; *num > 0; --*num) {
+ struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags);
+
+ if (!ascb)
+ break;
+ else if (!first)
+ first = ascb;
+ else {
+ struct asd_ascb *last = list_entry(first->list.prev,
+ struct asd_ascb,
+ list);
+ list_add_tail(&ascb->list, &first->list);
+ last->scb->header.next_scb =
+ cpu_to_le64(((u64)ascb->dma_scb.dma_handle));
+ }
+ }
+
+ return first;
+}
+
+/**
+ * asd_swap_head_scb -- swap the head scb
+ * @asd_ha: pointer to host adapter structure
+ * @ascb: pointer to the head of an ascb list
+ *
+ * The sequencer knows the DMA address of the next SCB to be DMAed to
+ * the host adapter, from initialization or from the last list DMAed.
+ * seq->next_scb keeps the address of this SCB. The sequencer will
+ * DMA to the host adapter this list of SCBs. But the head (first
+ * element) of this list is not known to the sequencer. Here we swap
+ * the head of the list with the known SCB (memcpy()).
+ * Only one memcpy() is required per list so it is in our interest
+ * to keep the list of SCB as long as possible so that the ratio
+ * of number of memcpy calls to the number of SCB DMA-ed is as small
+ * as possible.
+ *
+ * LOCKING: called with the pending list lock held.
+ */
+static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha,
+ struct asd_ascb *ascb)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ struct asd_ascb *last = list_entry(ascb->list.prev,
+ struct asd_ascb,
+ list);
+ struct asd_dma_tok t = ascb->dma_scb;
+
+ memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb));
+ ascb->dma_scb = seq->next_scb;
+ ascb->scb = ascb->dma_scb.vaddr;
+ seq->next_scb = t;
+ last->scb->header.next_scb =
+ cpu_to_le64(((u64)seq->next_scb.dma_handle));
+}
+
+/**
+ * asd_start_timers -- (add and) start timers of SCBs
+ * @list: pointer to struct list_head of the scbs
+ * @to: timeout in jiffies
+ *
+ * If an SCB in the @list has no timer function, assign the default
+ * one, then start the timer of the SCB. This function is
+ * intended to be called from asd_post_ascb_list(), just prior to
+ * posting the SCBs to the sequencer.
+ */
+static inline void asd_start_scb_timers(struct list_head *list)
+{
+ struct asd_ascb *ascb;
+ list_for_each_entry(ascb, list, list) {
+ if (!ascb->uldd_timer) {
+ ascb->timer.data = (unsigned long) ascb;
+ ascb->timer.function = asd_ascb_timedout;
+ ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+ add_timer(&ascb->timer);
+ }
+ }
+}
+
+/**
+ * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first aSCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * See queueing comment in asd_post_escb_list().
+ *
+ * Additional note on queuing: In order to minimize the ratio of memcpy()
+ * to the number of ascbs sent, we try to batch-send as many ascbs as possible
+ * in one go.
+ * Two cases are possible:
+ * A) can_queue >= num,
+ * B) can_queue < num.
+ * Case A: we can send the whole batch at once. Increment "pending"
+ * in the beginning of this function, when it is checked, in order to
+ * eliminate races when this function is called by multiple processes.
+ * Case B: should never happen if the managing layer considers
+ * lldd_queue_size.
+ */
+int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num)
+{
+ unsigned long flags;
+ LIST_HEAD(list);
+ int can_queue;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending;
+ if (can_queue >= num)
+ asd_ha->seq.pending += num;
+ else
+ can_queue = 0;
+
+ if (!can_queue) {
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+ asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev));
+ return -SAS_QUEUE_FULL;
+ }
+
+ asd_swap_head_scb(asd_ha, ascb);
+
+ __list_add(&list, ascb->list.prev, &ascb->list);
+
+ asd_start_scb_timers(&list);
+
+ asd_ha->seq.scbpro += num;
+ list_splice_init(&list, asd_ha->seq.pend_q.prev);
+ asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ return 0;
+}
+
+/**
+ * asd_post_escb_list -- post a list of 1 or more empty scb
+ * @asd_ha: pointer to a host adapter structure
+ * @ascb: pointer to the first empty SCB in the list
+ * @num: number of aSCBs in the list (to be posted)
+ *
+ * This is essentially the same as asd_post_ascb_list, but we do not
+ * increment pending, add those to the pending list or get indexes.
+ * See asd_init_escbs() and asd_init_post_escbs().
+ *
+ * Since sending a list of ascbs is a superset of sending a single
+ * ascb, this function exists to generalize this. More specifically,
+ * when sending a list of those, we want to do only a _single_
+ * memcpy() at swap head, as opposed to for each ascb sent (in the
+ * case of sending them one by one). That is, we want to minimize the
+ * ratio of memcpy() operations to the number of ascbs sent. The same
+ * logic applies to asd_post_ascb_list().
+ */
+int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ asd_swap_head_scb(asd_ha, ascb);
+ asd_ha->seq.scbpro += num;
+ asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro);
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ return 0;
+}
+
+/* ---------- LED ---------- */
+
+/**
+ * asd_turn_led -- turn on/off an LED
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: the PHY id whose LED we want to manupulate
+ * @op: 1 to turn on, 0 to turn off
+ */
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+ if (phy_id < ASD_MAX_PHYS) {
+ u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id));
+ if (op)
+ v |= LEDPOL;
+ else
+ v &= ~LEDPOL;
+ asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v);
+ }
+}
+
+/**
+ * asd_control_led -- enable/disable an LED on the board
+ * @asd_ha: pointer to host adapter structure
+ * @phy_id: integer, the phy id
+ * @op: integer, 1 to enable, 0 to disable the LED
+ *
+ * First we output enable the LED, then we set the source
+ * to be an external module.
+ */
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op)
+{
+ if (phy_id < ASD_MAX_PHYS) {
+ u32 v;
+
+ v = asd_read_reg_dword(asd_ha, GPIOOER);
+ if (op)
+ v |= (1 << phy_id);
+ else
+ v &= ~(1 << phy_id);
+ asd_write_reg_dword(asd_ha, GPIOOER, v);
+
+ v = asd_read_reg_dword(asd_ha, GPIOCNFGR);
+ if (op)
+ v |= (1 << phy_id);
+ else
+ v &= ~(1 << phy_id);
+ asd_write_reg_dword(asd_ha, GPIOCNFGR, v);
+ }
+}
+
+/* ---------- PHY enable ---------- */
+
+static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id)
+{
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY),
+ HOTPLUG_DELAY_TIMEOUT);
+
+ /* Get defaults from manuf. sector */
+ /* XXX we need defaults for those in case MS is broken. */
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0),
+ phy->phy_desc->phy_control_0);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1),
+ phy->phy_desc->phy_control_1);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2),
+ phy->phy_desc->phy_control_2);
+ asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3),
+ phy->phy_desc->phy_control_3);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id),
+ ASD_COMINIT_TIMEOUT);
+
+ asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id),
+ phy->id_frm_tok->dma_handle);
+
+ asd_control_led(asd_ha, phy_id, 1);
+
+ return 0;
+}
+
+int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask)
+{
+ u8 phy_m;
+ u8 i;
+ int num = 0, k;
+ struct asd_ascb *ascb;
+ struct asd_ascb *ascb_list;
+
+ if (!phy_mask) {
+ asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__);
+ return 0;
+ }
+
+ for_each_phy(phy_mask, phy_m, i) {
+ num++;
+ asd_enable_phy(asd_ha, i);
+ }
+
+ k = num;
+ ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL);
+ if (!ascb_list) {
+ asd_printk("no memory for control phy ascb list\n");
+ return -ENOMEM;
+ }
+ num -= k;
+
+ ascb = ascb_list;
+ for_each_phy(phy_mask, phy_m, i) {
+ asd_build_control_phy(ascb, i, ENABLE_PHY);
+ ascb = list_entry(ascb->list.next, struct asd_ascb, list);
+ }
+ ASD_DPRINTK("posting %d control phy scbs\n", num);
+ k = asd_post_ascb_list(asd_ha, ascb_list, num);
+ if (k)
+ asd_ascb_free_list(ascb_list);
+
+ return k;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
new file mode 100644
index 00000000000..8498144aa5e
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -0,0 +1,397 @@
+/*
+ * Aic94xx SAS/SATA driver hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_HWI_H_
+#define _AIC94XX_HWI_H_
+
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include <scsi/libsas.h>
+
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+
+/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
+#define ASD_MAX_PHYS 8
+#define ASD_PCBA_SN_SIZE 12
+
+/* Those are to be further named properly, the "RAZORx" part, and
+ * subsequently included in include/linux/pci_ids.h.
+ */
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E
+#define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F
+
+struct asd_ha_addrspace {
+ void __iomem *addr;
+ unsigned long start; /* pci resource start */
+ unsigned long len; /* pci resource len */
+ unsigned long flags; /* pci resource flags */
+
+ /* addresses internal to the host adapter */
+ u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
+ u32 swb_base;
+ u32 swc_base;
+};
+
+struct bios_struct {
+ int present;
+ u8 maj;
+ u8 min;
+ u32 bld;
+};
+
+struct unit_element_struct {
+ u16 num;
+ u16 size;
+ void *area;
+};
+
+struct flash_struct {
+ u32 bar;
+ int present;
+ int wide;
+ u8 manuf;
+ u8 dev_id;
+ u8 sec_prot;
+
+ u32 dir_offs;
+};
+
+struct asd_phy_desc {
+ /* From CTRL-A settings, then set to what is appropriate */
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 max_sas_lrate;
+ u8 min_sas_lrate;
+ u8 max_sata_lrate;
+ u8 min_sata_lrate;
+ u8 flags;
+#define ASD_CRC_DIS 1
+#define ASD_SATA_SPINUP_HOLD 2
+
+ u8 phy_control_0; /* mode 5 reg 0x160 */
+ u8 phy_control_1; /* mode 5 reg 0x161 */
+ u8 phy_control_2; /* mode 5 reg 0x162 */
+ u8 phy_control_3; /* mode 5 reg 0x163 */
+};
+
+struct asd_dma_tok {
+ void *vaddr;
+ dma_addr_t dma_handle;
+ size_t size;
+};
+
+struct hw_profile {
+ struct bios_struct bios;
+ struct unit_element_struct ue;
+ struct flash_struct flash;
+
+ u8 sas_addr[SAS_ADDR_SIZE];
+ char pcba_sn[ASD_PCBA_SN_SIZE+1];
+
+ u8 enabled_phys; /* mask of enabled phys */
+ struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
+ u32 max_scbs; /* absolute sequencer scb queue size */
+ struct asd_dma_tok *scb_ext;
+ u32 max_ddbs;
+ struct asd_dma_tok *ddb_ext;
+
+ spinlock_t ddb_lock;
+ void *ddb_bitmap;
+
+ int num_phys; /* ENABLEABLE */
+ int max_phys; /* REPORTED + ENABLEABLE */
+
+ unsigned addr_range; /* max # of addrs; max # of possible ports */
+ unsigned port_name_base;
+ unsigned dev_name_base;
+ unsigned sata_name_base;
+};
+
+struct asd_ascb {
+ struct list_head list;
+ struct asd_ha_struct *ha;
+
+ struct scb *scb; /* equals dma_scb->vaddr */
+ struct asd_dma_tok dma_scb;
+ struct asd_dma_tok *sg_arr;
+
+ void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
+ u8 uldd_timer:1;
+
+ /* internally generated command */
+ struct timer_list timer;
+ struct completion completion;
+ u8 tag_valid:1;
+ __be16 tag; /* error recovery only */
+
+ /* If this is an Empty SCB, index of first edb in seq->edb_arr. */
+ int edb_index;
+
+ /* Used by the timer timeout function. */
+ int tc_index;
+
+ void *uldd_task;
+};
+
+#define ASD_DL_SIZE_BITS 0x8
+#define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS))
+#define ASD_DEF_DL_TOGGLE 0x01
+
+struct asd_seq_data {
+ spinlock_t pend_q_lock;
+ u16 scbpro;
+ int pending;
+ struct list_head pend_q;
+ int can_queue; /* per adapter */
+ struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
+
+ spinlock_t tc_index_lock;
+ void **tc_index_array;
+ void *tc_index_bitmap;
+ int tc_index_bitmap_bits;
+
+ struct tasklet_struct dl_tasklet;
+ struct done_list_struct *dl; /* array of done list entries, equals */
+ struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
+ int dl_toggle;
+ int dl_next;
+
+ int num_edbs;
+ struct asd_dma_tok **edb_arr;
+ int num_escbs;
+ struct asd_ascb **escb_arr; /* array of pointers to escbs */
+};
+
+/* This is the Host Adapter structure. It describes the hardware
+ * SAS adapter.
+ */
+struct asd_ha_struct {
+ struct pci_dev *pcidev;
+ const char *name;
+
+ struct sas_ha_struct sas_ha;
+
+ u8 revision_id;
+
+ int iospace;
+ spinlock_t iolock;
+ struct asd_ha_addrspace io_handle[2];
+
+ struct hw_profile hw_prof;
+
+ struct asd_phy phys[ASD_MAX_PHYS];
+ struct asd_sas_port ports[ASD_MAX_PHYS];
+
+ struct dma_pool *scb_pool;
+
+ struct asd_seq_data seq; /* sequencer related */
+};
+
+/* ---------- Common macros ---------- */
+
+#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
+#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \
+ ? ((u32)((__dma_handle) >> 32)) \
+ : ((u32)0))
+
+#define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev))
+#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \
+ && ((__site_no) & 0xF0FF) > 0x001F)
+/* For each bit set in __lseq_mask, set __lseq to equal the bit
+ * position of the set bit and execute the statement following.
+ * __mc is the temporary mask, used as a mask "counter".
+ */
+#define for_each_sequencer(__lseq_mask, __mc, __lseq) \
+ for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+ if (((__mc) & 1))
+#define for_each_phy(__lseq_mask, __mc, __lseq) \
+ for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
+ if (((__mc) & 1))
+
+#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
+
+/* ---------- DMA allocs ---------- */
+
+static inline struct asd_dma_tok *asd_dmatok_alloc(gfp_t flags)
+{
+ return kmem_cache_alloc(asd_dma_token_cache, flags);
+}
+
+static inline void asd_dmatok_free(struct asd_dma_tok *token)
+{
+ kmem_cache_free(asd_dma_token_cache, token);
+}
+
+static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
+ asd_ha, size_t size,
+ gfp_t flags)
+{
+ struct asd_dma_tok *token = asd_dmatok_alloc(flags);
+ if (token) {
+ token->size = size;
+ token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
+ token->size,
+ &token->dma_handle,
+ flags);
+ if (!token->vaddr) {
+ asd_dmatok_free(token);
+ token = NULL;
+ }
+ }
+ return token;
+}
+
+static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
+ struct asd_dma_tok *token)
+{
+ if (token) {
+ dma_free_coherent(&asd_ha->pcidev->dev, token->size,
+ token->vaddr, token->dma_handle);
+ asd_dmatok_free(token);
+ }
+}
+
+static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
+ struct asd_ascb *ascb)
+{
+ INIT_LIST_HEAD(&ascb->list);
+ ascb->scb = ascb->dma_scb.vaddr;
+ ascb->ha = asd_ha;
+ ascb->timer.function = NULL;
+ init_timer(&ascb->timer);
+ ascb->tc_index = -1;
+ init_completion(&ascb->completion);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
+{
+ seq->tc_index_array[index] = NULL;
+ clear_bit(index, seq->tc_index_bitmap);
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
+{
+ int index;
+
+ index = find_first_zero_bit(seq->tc_index_bitmap,
+ seq->tc_index_bitmap_bits);
+ if (index == seq->tc_index_bitmap_bits)
+ return -1;
+
+ seq->tc_index_array[index] = ptr;
+ set_bit(index, seq->tc_index_bitmap);
+
+ return index;
+}
+
+/* Must be called with the tc_index_lock held!
+ */
+static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
+{
+ return seq->tc_index_array[index];
+}
+
+/**
+ * asd_ascb_free -- free a single aSCB after is has completed
+ * @ascb: pointer to the aSCB of interest
+ *
+ * This frees an aSCB after it has been executed/completed by
+ * the sequencer.
+ */
+static inline void asd_ascb_free(struct asd_ascb *ascb)
+{
+ if (ascb) {
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ unsigned long flags;
+
+ BUG_ON(!list_empty(&ascb->list));
+ spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
+ asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
+ spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
+ dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
+ ascb->dma_scb.dma_handle);
+ kmem_cache_free(asd_ascb_cache, ascb);
+ }
+}
+
+/**
+ * asd_ascb_list_free -- free a list of ascbs
+ * @ascb_list: a list of ascbs
+ *
+ * This function will free a list of ascbs allocated by asd_ascb_alloc_list.
+ * It is used when say the scb queueing function returned QUEUE_FULL,
+ * and we do not need the ascbs any more.
+ */
+static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
+{
+ LIST_HEAD(list);
+ struct list_head *n, *pos;
+
+ __list_add(&list, ascb_list->list.prev, &ascb_list->list);
+ list_for_each_safe(pos, n, &list) {
+ list_del_init(pos);
+ asd_ascb_free(list_entry(pos, struct asd_ascb, list));
+ }
+}
+
+/* ---------- Function declarations ---------- */
+
+int asd_init_hw(struct asd_ha_struct *asd_ha);
+irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs);
+
+
+struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
+ *asd_ha, int *num,
+ gfp_t gfp_mask);
+
+int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num);
+int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
+ int num);
+
+int asd_init_post_escbs(struct asd_ha_struct *asd_ha);
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
+void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
+int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+ u8 subfunc);
+
+void asd_ascb_timedout(unsigned long data);
+int asd_chip_hardrst(struct asd_ha_struct *asd_ha);
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
new file mode 100644
index 00000000000..ee2ccad7048
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -0,0 +1,866 @@
+/*
+ * Aic94xx SAS/SATA driver initialization.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+/* The format is "version.release.patchlevel" */
+#define ASD_DRIVER_VERSION "1.0.2"
+
+static int use_msi = 0;
+module_param_named(use_msi, use_msi, int, S_IRUGO);
+MODULE_PARM_DESC(use_msi, "\n"
+ "\tEnable(1) or disable(0) using PCI MSI.\n"
+ "\tDefault: 0");
+
+static int lldd_max_execute_num = 0;
+module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
+MODULE_PARM_DESC(collector, "\n"
+ "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
+ "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
+ "\tThe aic94xx SAS LLDD supports both modes.\n"
+ "\tDefault: 0 (Direct Mode).\n");
+
+char sas_addr_str[2*SAS_ADDR_SIZE + 1] = "";
+
+static struct scsi_transport_template *aic94xx_transport_template;
+
+static struct scsi_host_template aic94xx_sht = {
+ .module = THIS_MODULE,
+ /* .name is initialized */
+ .name = "aic94xx",
+ .queuecommand = sas_queuecommand,
+ .target_alloc = sas_target_alloc,
+ .slave_configure = sas_slave_configure,
+ .slave_destroy = sas_slave_destroy,
+ .change_queue_depth = sas_change_queue_depth,
+ .change_queue_type = sas_change_queue_type,
+ .bios_param = sas_bios_param,
+ .can_queue = 1,
+ .cmd_per_lun = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha)
+{
+ int err, i;
+ struct asd_ha_addrspace *io_handle;
+
+ asd_ha->iospace = 0;
+ for (i = 0; i < 3; i += 2) {
+ io_handle = &asd_ha->io_handle[i==0?0:1];
+ io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+ io_handle->len = pci_resource_len(asd_ha->pcidev, i);
+ io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+ err = -ENODEV;
+ if (!io_handle->start || !io_handle->len) {
+ asd_printk("MBAR%d start or length for %s is 0.\n",
+ i==0?0:1, pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+ err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+ if (err) {
+ asd_printk("couldn't reserve memory region for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+ if (io_handle->flags & IORESOURCE_CACHEABLE)
+ io_handle->addr = ioremap(io_handle->start,
+ io_handle->len);
+ else
+ io_handle->addr = ioremap_nocache(io_handle->start,
+ io_handle->len);
+ if (!io_handle->addr) {
+ asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1,
+ pci_name(asd_ha->pcidev));
+ goto Err_unreq;
+ }
+ }
+
+ return 0;
+Err_unreq:
+ pci_release_region(asd_ha->pcidev, i);
+Err:
+ if (i > 0) {
+ io_handle = &asd_ha->io_handle[0];
+ iounmap(io_handle->addr);
+ pci_release_region(asd_ha->pcidev, 0);
+ }
+ return err;
+}
+
+static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha)
+{
+ struct asd_ha_addrspace *io_handle;
+
+ io_handle = &asd_ha->io_handle[1];
+ iounmap(io_handle->addr);
+ pci_release_region(asd_ha->pcidev, 2);
+
+ io_handle = &asd_ha->io_handle[0];
+ iounmap(io_handle->addr);
+ pci_release_region(asd_ha->pcidev, 0);
+}
+
+static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha)
+{
+ int i = PCI_IOBAR_OFFSET, err;
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];
+
+ asd_ha->iospace = 1;
+ io_handle->start = pci_resource_start(asd_ha->pcidev, i);
+ io_handle->len = pci_resource_len(asd_ha->pcidev, i);
+ io_handle->flags = pci_resource_flags(asd_ha->pcidev, i);
+ io_handle->addr = (void __iomem *) io_handle->start;
+ if (!io_handle->start || !io_handle->len) {
+ asd_printk("couldn't get IO ports for %s\n",
+ pci_name(asd_ha->pcidev));
+ return -ENODEV;
+ }
+ err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME);
+ if (err) {
+ asd_printk("couldn't reserve io space for %s\n",
+ pci_name(asd_ha->pcidev));
+ }
+
+ return err;
+}
+
+static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha)
+{
+ pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET);
+}
+
+static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ u16 cmd_reg;
+
+ err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg);
+ if (err) {
+ asd_printk("couldn't read command register of %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+
+ err = -ENODEV;
+ if (cmd_reg & PCI_COMMAND_MEMORY) {
+ if ((err = asd_map_memio(asd_ha)))
+ goto Err;
+ } else if (cmd_reg & PCI_COMMAND_IO) {
+ if ((err = asd_map_ioport(asd_ha)))
+ goto Err;
+ asd_printk("%s ioport mapped -- upgrade your hardware\n",
+ pci_name(asd_ha->pcidev));
+ } else {
+ asd_printk("no proper device access to %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+
+ return 0;
+Err:
+ return err;
+}
+
+static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha)
+{
+ if (asd_ha->iospace)
+ asd_unmap_ioport(asd_ha);
+ else
+ asd_unmap_memio(asd_ha);
+}
+
+static const char *asd_dev_rev[30] = {
+ [0] = "A0",
+ [1] = "A1",
+ [8] = "B0",
+};
+
+static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha)
+{
+ int err, i;
+
+ err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID,
+ &asd_ha->revision_id);
+ if (err) {
+ asd_printk("couldn't read REVISION ID register of %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err;
+ }
+ err = -ENODEV;
+ if (asd_ha->revision_id < AIC9410_DEV_REV_B0) {
+ asd_printk("%s is revision %s (%X), which is not supported\n",
+ pci_name(asd_ha->pcidev),
+ asd_dev_rev[asd_ha->revision_id],
+ asd_ha->revision_id);
+ goto Err;
+ }
+ /* Provide some sane default values. */
+ asd_ha->hw_prof.max_scbs = 512;
+ asd_ha->hw_prof.max_ddbs = 128;
+ asd_ha->hw_prof.num_phys = ASD_MAX_PHYS;
+ /* All phys are enabled, by default. */
+ asd_ha->hw_prof.enabled_phys = 0xFF;
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
+ SAS_LINK_RATE_3_0_GBPS;
+ asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
+ SAS_LINK_RATE_1_5_GBPS;
+ asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
+ SAS_LINK_RATE_1_5_GBPS;
+ asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
+ SAS_LINK_RATE_1_5_GBPS;
+ }
+
+ return 0;
+Err:
+ return err;
+}
+
+static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha)
+{
+ int err = asd_common_setup(asd_ha);
+
+ if (err)
+ return err;
+
+ asd_ha->hw_prof.addr_range = 8;
+ asd_ha->hw_prof.port_name_base = 0;
+ asd_ha->hw_prof.dev_name_base = 8;
+ asd_ha->hw_prof.sata_name_base = 16;
+
+ return 0;
+}
+
+static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha)
+{
+ int err = asd_common_setup(asd_ha);
+
+ if (err)
+ return err;
+
+ asd_ha->hw_prof.addr_range = 4;
+ asd_ha->hw_prof.port_name_base = 0;
+ asd_ha->hw_prof.dev_name_base = 4;
+ asd_ha->hw_prof.sata_name_base = 8;
+
+ return 0;
+}
+
+static ssize_t asd_show_dev_rev(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ asd_dev_rev[asd_ha->revision_id]);
+}
+static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL);
+
+static ssize_t asd_show_dev_bios_build(struct device *dev,
+ struct device_attribute *attr,char *buf)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld);
+}
+static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL);
+
+static ssize_t asd_show_dev_pcba_sn(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev);
+ return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn);
+}
+static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
+
+static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+ device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
+{
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+}
+
+/* The first entry, 0, is used for dynamic ids, the rest for devices
+ * we know about.
+ */
+static struct asd_pcidev_struct {
+ const char * name;
+ int (*setup)(struct asd_ha_struct *asd_ha);
+} asd_pcidev_data[] = {
+ /* Id 0 is used for dynamic ids. */
+ { .name = "Adaptec AIC-94xx SAS/SATA Host Adapter",
+ .setup = asd_aic9410_setup
+ },
+ { .name = "Adaptec AIC-9410W SAS/SATA Host Adapter",
+ .setup = asd_aic9410_setup
+ },
+ { .name = "Adaptec AIC-9405W SAS/SATA Host Adapter",
+ .setup = asd_aic9405_setup
+ },
+};
+
+static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha)
+{
+ asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool",
+ &asd_ha->pcidev->dev,
+ sizeof(struct scb),
+ 8, 0);
+ if (!asd_ha->scb_pool) {
+ asd_printk("couldn't create scb pool\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/**
+ * asd_free_edbs -- free empty data buffers
+ * asd_ha: pointer to host adapter structure
+ */
+static inline void asd_free_edbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ for (i = 0; i < seq->num_edbs; i++)
+ asd_free_coherent(asd_ha, seq->edb_arr[i]);
+ kfree(seq->edb_arr);
+ seq->edb_arr = NULL;
+}
+
+static inline void asd_free_escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ for (i = 0; i < seq->num_escbs; i++) {
+ if (!list_empty(&seq->escb_arr[i]->list))
+ list_del_init(&seq->escb_arr[i]->list);
+
+ asd_ascb_free(seq->escb_arr[i]);
+ }
+ kfree(seq->escb_arr);
+ seq->escb_arr = NULL;
+}
+
+static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ if (asd_ha->hw_prof.ddb_ext)
+ asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext);
+ if (asd_ha->hw_prof.scb_ext)
+ asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext);
+
+ if (asd_ha->hw_prof.ddb_bitmap)
+ kfree(asd_ha->hw_prof.ddb_bitmap);
+ asd_ha->hw_prof.ddb_bitmap = NULL;
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ struct asd_phy *phy = &asd_ha->phys[i];
+
+ asd_free_coherent(asd_ha, phy->id_frm_tok);
+ }
+ if (asd_ha->seq.escb_arr)
+ asd_free_escbs(asd_ha);
+ if (asd_ha->seq.edb_arr)
+ asd_free_edbs(asd_ha);
+ if (asd_ha->hw_prof.ue.area) {
+ kfree(asd_ha->hw_prof.ue.area);
+ asd_ha->hw_prof.ue.area = NULL;
+ }
+ if (asd_ha->seq.tc_index_array) {
+ kfree(asd_ha->seq.tc_index_array);
+ kfree(asd_ha->seq.tc_index_bitmap);
+ asd_ha->seq.tc_index_array = NULL;
+ asd_ha->seq.tc_index_bitmap = NULL;
+ }
+ if (asd_ha->seq.actual_dl) {
+ asd_free_coherent(asd_ha, asd_ha->seq.actual_dl);
+ asd_ha->seq.actual_dl = NULL;
+ asd_ha->seq.dl = NULL;
+ }
+ if (asd_ha->seq.next_scb.vaddr) {
+ dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr,
+ asd_ha->seq.next_scb.dma_handle);
+ asd_ha->seq.next_scb.vaddr = NULL;
+ }
+ dma_pool_destroy(asd_ha->scb_pool);
+ asd_ha->scb_pool = NULL;
+}
+
+kmem_cache_t *asd_dma_token_cache;
+kmem_cache_t *asd_ascb_cache;
+
+static int asd_create_global_caches(void)
+{
+ if (!asd_dma_token_cache) {
+ asd_dma_token_cache
+ = kmem_cache_create(ASD_DRIVER_NAME "_dma_token",
+ sizeof(struct asd_dma_tok),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!asd_dma_token_cache) {
+ asd_printk("couldn't create dma token cache\n");
+ return -ENOMEM;
+ }
+ }
+
+ if (!asd_ascb_cache) {
+ asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb",
+ sizeof(struct asd_ascb),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (!asd_ascb_cache) {
+ asd_printk("couldn't create ascb cache\n");
+ goto Err;
+ }
+ }
+
+ return 0;
+Err:
+ kmem_cache_destroy(asd_dma_token_cache);
+ asd_dma_token_cache = NULL;
+ return -ENOMEM;
+}
+
+static void asd_destroy_global_caches(void)
+{
+ if (asd_dma_token_cache)
+ kmem_cache_destroy(asd_dma_token_cache);
+ asd_dma_token_cache = NULL;
+
+ if (asd_ascb_cache)
+ kmem_cache_destroy(asd_ascb_cache);
+ asd_ascb_cache = NULL;
+}
+
+static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
+{
+ int i;
+ struct asd_sas_phy **sas_phys =
+ kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL);
+ struct asd_sas_port **sas_ports =
+ kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL);
+
+ if (!sas_phys || !sas_ports) {
+ kfree(sas_phys);
+ kfree(sas_ports);
+ return -ENOMEM;
+ }
+
+ asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name;
+ asd_ha->sas_ha.lldd_module = THIS_MODULE;
+ asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0];
+
+ for (i = 0; i < ASD_MAX_PHYS; i++) {
+ sas_phys[i] = &asd_ha->phys[i].sas_phy;
+ sas_ports[i] = &asd_ha->ports[i];
+ }
+
+ asd_ha->sas_ha.sas_phy = sas_phys;
+ asd_ha->sas_ha.sas_port= sas_ports;
+ asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
+
+ asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
+
+ return sas_register_ha(&asd_ha->sas_ha);
+}
+
+static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = sas_unregister_ha(&asd_ha->sas_ha);
+
+ sas_remove_host(asd_ha->sas_ha.core.shost);
+ scsi_remove_host(asd_ha->sas_ha.core.shost);
+ scsi_host_put(asd_ha->sas_ha.core.shost);
+
+ kfree(asd_ha->sas_ha.sas_phy);
+ kfree(asd_ha->sas_ha.sas_port);
+
+ return err;
+}
+
+static int __devinit asd_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct asd_pcidev_struct *asd_dev;
+ unsigned asd_id = (unsigned) id->driver_data;
+ struct asd_ha_struct *asd_ha;
+ struct Scsi_Host *shost;
+ int err;
+
+ if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) {
+ asd_printk("wrong driver_data in PCI table\n");
+ return -ENODEV;
+ }
+
+ if ((err = pci_enable_device(dev))) {
+ asd_printk("couldn't enable device %s\n", pci_name(dev));
+ return err;
+ }
+
+ pci_set_master(dev);
+
+ err = -ENOMEM;
+
+ shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *));
+ if (!shost)
+ goto Err;
+
+ asd_dev = &asd_pcidev_data[asd_id];
+
+ asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL);
+ if (!asd_ha) {
+ asd_printk("out of memory\n");
+ goto Err;
+ }
+ asd_ha->pcidev = dev;
+ asd_ha->sas_ha.pcidev = asd_ha->pcidev;
+ asd_ha->sas_ha.lldd_ha = asd_ha;
+
+ asd_ha->name = asd_dev->name;
+ asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev));
+
+ SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha;
+ asd_ha->sas_ha.core.shost = shost;
+ shost->transportt = aic94xx_transport_template;
+ shost->max_id = ~0;
+ shost->max_lun = ~0;
+ shost->max_cmd_len = 16;
+
+ err = scsi_add_host(shost, &dev->dev);
+ if (err) {
+ scsi_host_put(shost);
+ goto Err_free;
+ }
+
+
+
+ err = asd_dev->setup(asd_ha);
+ if (err)
+ goto Err_free;
+
+ err = -ENODEV;
+ if (!pci_set_dma_mask(dev, DMA_64BIT_MASK)
+ && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK))
+ ;
+ else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK)
+ && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK))
+ ;
+ else {
+ asd_printk("no suitable DMA mask for %s\n", pci_name(dev));
+ goto Err_free;
+ }
+
+ pci_set_drvdata(dev, asd_ha);
+
+ err = asd_map_ha(asd_ha);
+ if (err)
+ goto Err_free;
+
+ err = asd_create_ha_caches(asd_ha);
+ if (err)
+ goto Err_unmap;
+
+ err = asd_init_hw(asd_ha);
+ if (err)
+ goto Err_free_cache;
+
+ asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled "
+ "phys, flash %s, BIOS %s%d\n",
+ pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr),
+ asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys,
+ asd_ha->hw_prof.num_phys,
+ asd_ha->hw_prof.flash.present ? "present" : "not present",
+ asd_ha->hw_prof.bios.present ? "build " : "not present",
+ asd_ha->hw_prof.bios.bld);
+
+ shost->can_queue = asd_ha->seq.can_queue;
+
+ if (use_msi)
+ pci_enable_msi(asd_ha->pcidev);
+
+ err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ,
+ ASD_DRIVER_NAME, asd_ha);
+ if (err) {
+ asd_printk("couldn't get irq %d for %s\n",
+ asd_ha->pcidev->irq, pci_name(asd_ha->pcidev));
+ goto Err_irq;
+ }
+ asd_enable_ints(asd_ha);
+
+ err = asd_init_post_escbs(asd_ha);
+ if (err) {
+ asd_printk("couldn't post escbs for %s\n",
+ pci_name(asd_ha->pcidev));
+ goto Err_escbs;
+ }
+ ASD_DPRINTK("escbs posted\n");
+
+ asd_create_dev_attrs(asd_ha);
+
+ err = asd_register_sas_ha(asd_ha);
+ if (err)
+ goto Err_reg_sas;
+
+ err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys);
+ if (err) {
+ asd_printk("coudln't enable phys, err:%d\n", err);
+ goto Err_en_phys;
+ }
+ ASD_DPRINTK("enabled phys\n");
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ ssleep(1);
+ /* Wait for discovery to finish */
+ scsi_flush_work(asd_ha->sas_ha.core.shost);
+
+ return 0;
+Err_en_phys:
+ asd_unregister_sas_ha(asd_ha);
+Err_reg_sas:
+ asd_remove_dev_attrs(asd_ha);
+Err_escbs:
+ asd_disable_ints(asd_ha);
+ free_irq(dev->irq, asd_ha);
+Err_irq:
+ if (use_msi)
+ pci_disable_msi(dev);
+ asd_chip_hardrst(asd_ha);
+Err_free_cache:
+ asd_destroy_ha_caches(asd_ha);
+Err_unmap:
+ asd_unmap_ha(asd_ha);
+Err_free:
+ kfree(asd_ha);
+ scsi_remove_host(shost);
+Err:
+ pci_disable_device(dev);
+ return err;
+}
+
+static void asd_free_queues(struct asd_ha_struct *asd_ha)
+{
+ unsigned long flags;
+ LIST_HEAD(pending);
+ struct list_head *n, *pos;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ asd_ha->seq.pending = 0;
+ list_splice_init(&asd_ha->seq.pend_q, &pending);
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ if (!list_empty(&pending))
+ ASD_DPRINTK("Uh-oh! Pending is not empty!\n");
+
+ list_for_each_safe(pos, n, &pending) {
+ struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list);
+ list_del_init(pos);
+ ASD_DPRINTK("freeing from pending\n");
+ asd_ascb_free(ascb);
+ }
+}
+
+static void asd_turn_off_leds(struct asd_ha_struct *asd_ha)
+{
+ u8 phy_mask = asd_ha->hw_prof.enabled_phys;
+ u8 i;
+
+ for_each_phy(phy_mask, phy_mask, i) {
+ asd_turn_led(asd_ha, i, 0);
+ asd_control_led(asd_ha, i, 0);
+ }
+}
+
+static void __devexit asd_pci_remove(struct pci_dev *dev)
+{
+ struct asd_ha_struct *asd_ha = pci_get_drvdata(dev);
+
+ if (!asd_ha)
+ return;
+
+ asd_unregister_sas_ha(asd_ha);
+
+ asd_disable_ints(asd_ha);
+
+ asd_remove_dev_attrs(asd_ha);
+
+ /* XXX more here as needed */
+
+ free_irq(dev->irq, asd_ha);
+ if (use_msi)
+ pci_disable_msi(asd_ha->pcidev);
+ asd_turn_off_leds(asd_ha);
+ asd_chip_hardrst(asd_ha);
+ asd_free_queues(asd_ha);
+ asd_destroy_ha_caches(asd_ha);
+ asd_unmap_ha(asd_ha);
+ kfree(asd_ha);
+ pci_disable_device(dev);
+ return;
+}
+
+static ssize_t asd_version_show(struct device_driver *driver, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION);
+}
+static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
+
+static void asd_create_driver_attrs(struct device_driver *driver)
+{
+ driver_create_file(driver, &driver_attr_version);
+}
+
+static void asd_remove_driver_attrs(struct device_driver *driver)
+{
+ driver_remove_file(driver, &driver_attr_version);
+}
+
+static struct sas_domain_function_template aic94xx_transport_functions = {
+ .lldd_port_formed = asd_update_port_links,
+
+ .lldd_dev_found = asd_dev_found,
+ .lldd_dev_gone = asd_dev_gone,
+
+ .lldd_execute_task = asd_execute_task,
+
+ .lldd_abort_task = asd_abort_task,
+ .lldd_abort_task_set = asd_abort_task_set,
+ .lldd_clear_aca = asd_clear_aca,
+ .lldd_clear_task_set = asd_clear_task_set,
+ .lldd_I_T_nexus_reset = NULL,
+ .lldd_lu_reset = asd_lu_reset,
+ .lldd_query_task = asd_query_task,
+
+ .lldd_clear_nexus_port = asd_clear_nexus_port,
+ .lldd_clear_nexus_ha = asd_clear_nexus_ha,
+
+ .lldd_control_phy = asd_control_phy,
+};
+
+static const struct pci_device_id aic94xx_pci_table[] __devinitdata = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10),
+ 0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12),
+ 0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E),
+ 0, 0, 1},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30),
+ 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32),
+ 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E),
+ 0, 0, 2},
+ {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F),
+ 0, 0, 2},
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, aic94xx_pci_table);
+
+static struct pci_driver aic94xx_pci_driver = {
+ .name = ASD_DRIVER_NAME,
+ .id_table = aic94xx_pci_table,
+ .probe = asd_pci_probe,
+ .remove = __devexit_p(asd_pci_remove),
+};
+
+static int __init aic94xx_init(void)
+{
+ int err;
+
+
+ asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION,
+ ASD_DRIVER_VERSION);
+
+ err = asd_create_global_caches();
+ if (err)
+ return err;
+
+ aic94xx_transport_template =
+ sas_domain_attach_transport(&aic94xx_transport_functions);
+ if (!aic94xx_transport_template)
+ goto out_destroy_caches;
+
+ err = pci_register_driver(&aic94xx_pci_driver);
+ if (err)
+ goto out_release_transport;
+
+ asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+
+ return err;
+
+ out_release_transport:
+ sas_release_transport(aic94xx_transport_template);
+ out_destroy_caches:
+ asd_destroy_global_caches();
+
+ return err;
+}
+
+static void __exit aic94xx_exit(void)
+{
+ asd_remove_driver_attrs(&aic94xx_pci_driver.driver);
+ pci_unregister_driver(&aic94xx_pci_driver);
+ sas_release_transport(aic94xx_transport_template);
+ asd_destroy_global_caches();
+ asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION,
+ ASD_DRIVER_VERSION);
+}
+
+module_init(aic94xx_init);
+module_exit(aic94xx_exit);
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(ASD_DRIVER_VERSION);
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c
new file mode 100644
index 00000000000..f210dac3203
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_reg.c
@@ -0,0 +1,332 @@
+/*
+ * Aic94xx SAS/SATA driver register access.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include "aic94xx_reg.h"
+#include "aic94xx.h"
+
+/* Writing to device address space.
+ * Offset comes before value to remind that the operation of
+ * this function is *offs = val.
+ */
+static inline void asd_write_byte(struct asd_ha_struct *asd_ha,
+ unsigned long offs, u8 val)
+{
+ if (unlikely(asd_ha->iospace))
+ outb(val,
+ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+ else
+ writeb(val, asd_ha->io_handle[0].addr + offs);
+ wmb();
+}
+
+static inline void asd_write_word(struct asd_ha_struct *asd_ha,
+ unsigned long offs, u16 val)
+{
+ if (unlikely(asd_ha->iospace))
+ outw(val,
+ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+ else
+ writew(val, asd_ha->io_handle[0].addr + offs);
+ wmb();
+}
+
+static inline void asd_write_dword(struct asd_ha_struct *asd_ha,
+ unsigned long offs, u32 val)
+{
+ if (unlikely(asd_ha->iospace))
+ outl(val,
+ (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
+ else
+ writel(val, asd_ha->io_handle[0].addr + offs);
+ wmb();
+}
+
+/* Reading from device address space.
+ */
+static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha,
+ unsigned long offs)
+{
+ u8 val;
+ if (unlikely(asd_ha->iospace))
+ val = inb((unsigned long) asd_ha->io_handle[0].addr
+ + (offs & 0xFF));
+ else
+ val = readb(asd_ha->io_handle[0].addr + offs);
+ rmb();
+ return val;
+}
+
+static inline u16 asd_read_word(struct asd_ha_struct *asd_ha,
+ unsigned long offs)
+{
+ u16 val;
+ if (unlikely(asd_ha->iospace))
+ val = inw((unsigned long)asd_ha->io_handle[0].addr
+ + (offs & 0xFF));
+ else
+ val = readw(asd_ha->io_handle[0].addr + offs);
+ rmb();
+ return val;
+}
+
+static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha,
+ unsigned long offs)
+{
+ u32 val;
+ if (unlikely(asd_ha->iospace))
+ val = inl((unsigned long) asd_ha->io_handle[0].addr
+ + (offs & 0xFF));
+ else
+ val = readl(asd_ha->io_handle[0].addr + offs);
+ rmb();
+ return val;
+}
+
+static inline u32 asd_mem_offs_swa(void)
+{
+ return 0;
+}
+
+static inline u32 asd_mem_offs_swc(void)
+{
+ return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
+}
+
+static inline u32 asd_mem_offs_swb(void)
+{
+ return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
+}
+
+/* We know that the register wanted is in the range
+ * of the sliding window.
+ */
+#define ASD_READ_SW(ww, type, ord) \
+static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+ u32 reg) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
+ u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+ return asd_read_##ord (asd_ha, (unsigned long) map_offs); \
+}
+
+#define ASD_WRITE_SW(ww, type, ord) \
+static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\
+ u32 reg, type val) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \
+ u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\
+ asd_write_##ord (asd_ha, (unsigned long) map_offs, val); \
+}
+
+ASD_READ_SW(swa, u8, byte);
+ASD_READ_SW(swa, u16, word);
+ASD_READ_SW(swa, u32, dword);
+
+ASD_READ_SW(swb, u8, byte);
+ASD_READ_SW(swb, u16, word);
+ASD_READ_SW(swb, u32, dword);
+
+ASD_READ_SW(swc, u8, byte);
+ASD_READ_SW(swc, u16, word);
+ASD_READ_SW(swc, u32, dword);
+
+ASD_WRITE_SW(swa, u8, byte);
+ASD_WRITE_SW(swa, u16, word);
+ASD_WRITE_SW(swa, u32, dword);
+
+ASD_WRITE_SW(swb, u8, byte);
+ASD_WRITE_SW(swb, u16, word);
+ASD_WRITE_SW(swb, u32, dword);
+
+ASD_WRITE_SW(swc, u8, byte);
+ASD_WRITE_SW(swc, u16, word);
+ASD_WRITE_SW(swc, u32, dword);
+
+/*
+ * A word about sliding windows:
+ * MBAR0 is divided into sliding windows A, C and B, in that order.
+ * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
+ * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
+ * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
+ * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
+ * See asd_init_sw() in aic94xx_hwi.c
+ *
+ * We map the most common registers we'd access of the internal 4GB
+ * host adapter memory space. If a register/internal memory location
+ * is wanted which is not mapped, we slide SWB, by paging it,
+ * see asd_move_swb() in aic94xx_reg.c.
+ */
+
+/**
+ * asd_move_swb -- move sliding window B
+ * @asd_ha: pointer to host adapter structure
+ * @reg: register desired to be within range of the new window
+ */
+static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
+{
+ u32 base = reg & ~(MBAR0_SWB_SIZE-1);
+ pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
+ asd_ha->io_handle[0].swb_base = base;
+}
+
+static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
+{
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+ if (io_handle->swa_base <= reg
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+ asd_write_swa_byte (asd_ha, reg,val);
+ else if (io_handle->swb_base <= reg
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+ asd_write_swb_byte (asd_ha, reg, val);
+ else if (io_handle->swc_base <= reg
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+ asd_write_swc_byte (asd_ha, reg, val);
+ else {
+ /* Ok, we have to move SWB */
+ asd_move_swb(asd_ha, reg);
+ asd_write_swb_byte (asd_ha, reg, val);
+ }
+}
+
+#define ASD_WRITE_REG(type, ord) \
+void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
+{ \
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+ unsigned long flags; \
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
+ spin_lock_irqsave(&asd_ha->iolock, flags); \
+ if (io_handle->swa_base <= reg \
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
+ asd_write_swa_##ord (asd_ha, reg,val); \
+ else if (io_handle->swb_base <= reg \
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
+ asd_write_swb_##ord (asd_ha, reg, val); \
+ else if (io_handle->swc_base <= reg \
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
+ asd_write_swc_##ord (asd_ha, reg, val); \
+ else { \
+ /* Ok, we have to move SWB */ \
+ asd_move_swb(asd_ha, reg); \
+ asd_write_swb_##ord (asd_ha, reg, val); \
+ } \
+ spin_unlock_irqrestore(&asd_ha->iolock, flags); \
+}
+
+ASD_WRITE_REG(u8, byte);
+ASD_WRITE_REG(u16,word);
+ASD_WRITE_REG(u32,dword);
+
+static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
+{
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
+ u8 val;
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
+ if (io_handle->swa_base <= reg
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
+ val = asd_read_swa_byte (asd_ha, reg);
+ else if (io_handle->swb_base <= reg
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
+ val = asd_read_swb_byte (asd_ha, reg);
+ else if (io_handle->swc_base <= reg
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
+ val = asd_read_swc_byte (asd_ha, reg);
+ else {
+ /* Ok, we have to move SWB */
+ asd_move_swb(asd_ha, reg);
+ val = asd_read_swb_byte (asd_ha, reg);
+ }
+ return val;
+}
+
+#define ASD_READ_REG(type, ord) \
+type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \
+{ \
+ struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
+ type val; \
+ unsigned long flags; \
+ BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \
+ spin_lock_irqsave(&asd_ha->iolock, flags); \
+ if (io_handle->swa_base <= reg \
+ && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \
+ val = asd_read_swa_##ord (asd_ha, reg); \
+ else if (io_handle->swb_base <= reg \
+ && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \
+ val = asd_read_swb_##ord (asd_ha, reg); \
+ else if (io_handle->swc_base <= reg \
+ && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \
+ val = asd_read_swc_##ord (asd_ha, reg); \
+ else { \
+ /* Ok, we have to move SWB */ \
+ asd_move_swb(asd_ha, reg); \
+ val = asd_read_swb_##ord (asd_ha, reg); \
+ } \
+ spin_unlock_irqrestore(&asd_ha->iolock, flags); \
+ return val; \
+}
+
+ASD_READ_REG(u8, byte);
+ASD_READ_REG(u16,word);
+ASD_READ_REG(u32,dword);
+
+/**
+ * asd_read_reg_string -- read a string of bytes from io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @dst: pointer to a destination buffer where data will be written to
+ * @offs: start offset (register) to read from
+ * @count: number of bytes to read
+ */
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+ u32 offs, int count)
+{
+ u8 *p = dst;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->iolock, flags);
+ for ( ; count > 0; count--, offs++, p++)
+ *p = __asd_read_reg_byte(asd_ha, offs);
+ spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
+
+/**
+ * asd_write_reg_string -- write a string of bytes to io space memory
+ * @asd_ha: pointer to host adapter structure
+ * @src: pointer to source buffer where data will be read from
+ * @offs: start offset (register) to write to
+ * @count: number of bytes to write
+ */
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+ u32 offs, int count)
+{
+ u8 *p = src;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->iolock, flags);
+ for ( ; count > 0; count--, offs++, p++)
+ __asd_write_reg_byte(asd_ha, offs, *p);
+ spin_unlock_irqrestore(&asd_ha->iolock, flags);
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h
new file mode 100644
index 00000000000..2279307fd27
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_reg.h
@@ -0,0 +1,302 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers definitions.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_REG_H_
+#define _AIC94XX_REG_H_
+
+#include <asm/io.h>
+#include "aic94xx_hwi.h"
+
+/* Values */
+#define AIC9410_DEV_REV_B0 0x8
+
+/* MBAR0, SWA, SWB, SWC, internal memory space addresses */
+#define REG_BASE_ADDR 0xB8000000
+#define REG_BASE_ADDR_CSEQCIO 0xB8002000
+#define REG_BASE_ADDR_EXSI 0xB8042800
+
+#define MBAR0_SWA_SIZE 0x58
+extern u32 MBAR0_SWB_SIZE;
+#define MBAR0_SWC_SIZE 0x8
+
+/* MBAR1, points to On Chip Memory */
+#define OCM_BASE_ADDR 0xA0000000
+#define OCM_MAX_SIZE 0x20000
+
+/* Smallest address possible to reference */
+#define ALL_BASE_ADDR OCM_BASE_ADDR
+
+/* PCI configuration space registers */
+#define PCI_IOBAR_OFFSET 4
+
+#define PCI_CONF_MBAR1 0x6C
+#define PCI_CONF_MBAR0_SWA 0x70
+#define PCI_CONF_MBAR0_SWB 0x74
+#define PCI_CONF_MBAR0_SWC 0x78
+#define PCI_CONF_MBAR_KEY 0x7C
+#define PCI_CONF_FLSH_BAR 0xB8
+
+#include "aic94xx_reg_def.h"
+
+u8 asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg);
+u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg);
+u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg);
+
+void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val);
+void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val);
+void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val);
+
+void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
+ u32 offs, int count);
+void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
+ u32 offs, int count);
+
+#define ASD_READ_OCM(type, ord, S) \
+static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha, \
+ u32 offs) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \
+ type val = read##S (io_handle->addr + (unsigned long) offs); \
+ rmb(); \
+ return val; \
+}
+
+ASD_READ_OCM(u8, byte, b);
+ASD_READ_OCM(u16,word, w);
+ASD_READ_OCM(u32,dword,l);
+
+#define ASD_WRITE_OCM(type, ord, S) \
+static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha, \
+ u32 offs, type val) \
+{ \
+ struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \
+ write##S (val, io_handle->addr + (unsigned long) offs); \
+ return; \
+}
+
+ASD_WRITE_OCM(u8, byte, b);
+ASD_WRITE_OCM(u16,word, w);
+ASD_WRITE_OCM(u32,dword,l);
+
+#define ASD_DDBSITE_READ(type, ord) \
+static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha, \
+ u16 ddb_site_no, \
+ u16 offs) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \
+ return asd_read_reg_##ord (asd_ha, CTXACCESS); \
+}
+
+ASD_DDBSITE_READ(u32, dword);
+ASD_DDBSITE_READ(u16, word);
+
+static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no,
+ u16 offs)
+{
+ if (offs & 1)
+ return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+ offs & ~1) >> 8;
+ else
+ return asd_ddbsite_read_word(asd_ha, ddb_site_no,
+ offs) & 0xFF;
+}
+
+
+#define ASD_DDBSITE_WRITE(type, ord) \
+static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha, \
+ u16 ddb_site_no, \
+ u16 offs, type val) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \
+ asd_write_reg_##ord (asd_ha, CTXACCESS, val); \
+}
+
+ASD_DDBSITE_WRITE(u32, dword);
+ASD_DDBSITE_WRITE(u16, word);
+
+static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no,
+ u16 offs, u8 val)
+{
+ u16 base = offs & ~1;
+ u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+ if (offs & 1)
+ rval = (val << 8) | (rval & 0xFF);
+ else
+ rval = (rval & 0xFF00) | val;
+ asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval);
+}
+
+
+#define ASD_SCBSITE_READ(type, ord) \
+static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha, \
+ u16 scb_site_no, \
+ u16 offs) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \
+ return asd_read_reg_##ord (asd_ha, CTXACCESS); \
+}
+
+ASD_SCBSITE_READ(u32, dword);
+ASD_SCBSITE_READ(u16, word);
+
+static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha,
+ u16 scb_site_no,
+ u16 offs)
+{
+ if (offs & 1)
+ return asd_scbsite_read_word(asd_ha, scb_site_no,
+ offs & ~1) >> 8;
+ else
+ return asd_scbsite_read_word(asd_ha, scb_site_no,
+ offs) & 0xFF;
+}
+
+
+#define ASD_SCBSITE_WRITE(type, ord) \
+static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha, \
+ u16 scb_site_no, \
+ u16 offs, type val) \
+{ \
+ asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \
+ asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \
+ asd_write_reg_##ord (asd_ha, CTXACCESS, val); \
+}
+
+ASD_SCBSITE_WRITE(u32, dword);
+ASD_SCBSITE_WRITE(u16, word);
+
+static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha,
+ u16 scb_site_no,
+ u16 offs, u8 val)
+{
+ u16 base = offs & ~1;
+ u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base);
+ if (offs & 1)
+ rval = (val << 8) | (rval & 0xFF);
+ else
+ rval = (rval & 0xFF00) | val;
+ asd_scbsite_write_word(asd_ha, scb_site_no, base, rval);
+}
+
+/**
+ * asd_ddbsite_update_word -- atomically update a word in a ddb site
+ * @asd_ha: pointer to host adapter structure
+ * @ddb_site_no: the DDB site number
+ * @offs: the offset into the DDB
+ * @oldval: old value found in that offset
+ * @newval: the new value to replace it
+ *
+ * This function is used when the sequencers are running and we need to
+ * update a DDB site atomically without expensive pausing and upausing
+ * of the sequencers and accessing the DDB site through the CIO bus.
+ *
+ * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value
+ * is different than the current value at that offset.
+ */
+static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no, u16 offs,
+ u16 oldval, u16 newval)
+{
+ u8 done;
+ u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs);
+ if (oval != oldval)
+ return -EAGAIN;
+ asd_write_reg_word(asd_ha, AOLDDATA, oldval);
+ asd_write_reg_word(asd_ha, ANEWDATA, newval);
+ do {
+ done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL);
+ } while (!(done & ATOMICDONE));
+ if (done & ATOMICERR)
+ return -EFAULT; /* parity error */
+ else if (done & ATOMICWIN)
+ return 0; /* success */
+ else
+ return -EAGAIN; /* oldval different than current value */
+}
+
+static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha,
+ u16 ddb_site_no, u16 offs,
+ u8 _oldval, u8 _newval)
+{
+ u16 base = offs & ~1;
+ u16 oval;
+ u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base);
+ if (offs & 1) {
+ if ((nval >> 8) != _oldval)
+ return -EAGAIN;
+ nval = (_newval << 8) | (nval & 0xFF);
+ oval = (_oldval << 8) | (nval & 0xFF);
+ } else {
+ if ((nval & 0xFF) != _oldval)
+ return -EAGAIN;
+ nval = (nval & 0xFF00) | _newval;
+ oval = (nval & 0xFF00) | _oldval;
+ }
+ return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval);
+}
+
+static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg,
+ dma_addr_t dma_handle)
+{
+ asd_write_reg_dword(asd_ha, reg, ASD_BUSADDR_LO(dma_handle));
+ asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle));
+}
+
+static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha)
+{
+ /* DCHREVISION returns 0, possibly broken */
+ u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+ return ctxmemsize ? 65536 : 32768;
+}
+
+static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha)
+{
+ u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE;
+ return ctxmemsize ? 8192 : 4096;
+}
+
+static inline void asd_disable_ints(struct asd_ha_struct *asd_ha)
+{
+ asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+}
+
+static inline void asd_enable_ints(struct asd_ha_struct *asd_ha)
+{
+ /* Enable COM SAS interrupt on errors, COMSTAT */
+ asd_write_reg_dword(asd_ha, COMSTATEN,
+ EN_CSBUFPERR | EN_CSERR | EN_OVLYERR);
+ /* Enable DCH SAS CFIFTOERR */
+ asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR);
+ /* Enable Host Device interrupts */
+ asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN);
+}
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h
new file mode 100644
index 00000000000..b79f45f3ad4
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h
@@ -0,0 +1,2398 @@
+/*
+ * Aic94xx SAS/SATA driver hardware registers defintions.
+ *
+ * Copyright (C) 2004 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com>
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Luben Tuikov: Some register value updates to make it work with the window
+ * agnostic register r/w functions. Some register corrections, sizes,
+ * etc.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $
+ *
+ */
+
+#ifndef _ADP94XX_REG_DEF_H_
+#define _ADP94XX_REG_DEF_H_
+
+/*
+ * Common definitions.
+ */
+#define CSEQ_MODE_PAGE_SIZE 0x200 /* CSEQ mode page size */
+#define LmSEQ_MODE_PAGE_SIZE 0x200 /* LmSEQ mode page size */
+#define LmSEQ_HOST_REG_SIZE 0x4000 /* LmSEQ Host Register size */
+
+/********************* COM_SAS registers definition *************************/
+
+/* The base is REG_BASE_ADDR, defined in aic94xx_reg.h.
+ */
+
+/*
+ * CHIM Registers, Address Range : (0x00-0xFF)
+ */
+#define COMBIST (REG_BASE_ADDR + 0x00)
+
+/* bits 31:24 */
+#define L7BLKRST 0x80000000
+#define L6BLKRST 0x40000000
+#define L5BLKRST 0x20000000
+#define L4BLKRST 0x10000000
+#define L3BLKRST 0x08000000
+#define L2BLKRST 0x04000000
+#define L1BLKRST 0x02000000
+#define L0BLKRST 0x01000000
+#define LmBLKRST 0xFF000000
+#define LmBLKRST_COMBIST(phyid) (1 << (24 + phyid))
+
+#define OCMBLKRST 0x00400000
+#define CTXMEMBLKRST 0x00200000
+#define CSEQBLKRST 0x00100000
+#define EXSIBLKRST 0x00040000
+#define DPIBLKRST 0x00020000
+#define DFIFBLKRST 0x00010000
+#define HARDRST 0x00000200
+#define COMBLKRST 0x00000100
+#define FRCDFPERR 0x00000080
+#define FRCCIOPERR 0x00000020
+#define FRCBISTERR 0x00000010
+#define COMBISTEN 0x00000004
+#define COMBISTDONE 0x00000002 /* ro */
+#define COMBISTFAIL 0x00000001 /* ro */
+
+#define COMSTAT (REG_BASE_ADDR + 0x04)
+
+#define REQMBXREAD 0x00000040
+#define RSPMBXAVAIL 0x00000020
+#define CSBUFPERR 0x00000008
+#define OVLYERR 0x00000004
+#define CSERR 0x00000002
+#define OVLYDMADONE 0x00000001
+
+#define COMSTAT_MASK (REQMBXREAD | RSPMBXAVAIL | \
+ CSBUFPERR | OVLYERR | CSERR |\
+ OVLYDMADONE)
+
+#define COMSTATEN (REG_BASE_ADDR + 0x08)
+
+#define EN_REQMBXREAD 0x00000040
+#define EN_RSPMBXAVAIL 0x00000020
+#define EN_CSBUFPERR 0x00000008
+#define EN_OVLYERR 0x00000004
+#define EN_CSERR 0x00000002
+#define EN_OVLYDONE 0x00000001
+
+#define SCBPRO (REG_BASE_ADDR + 0x0C)
+
+#define SCBCONS_MASK 0xFFFF0000
+#define SCBPRO_MASK 0x0000FFFF
+
+#define CHIMREQMBX (REG_BASE_ADDR + 0x10)
+
+#define CHIMRSPMBX (REG_BASE_ADDR + 0x14)
+
+#define CHIMINT (REG_BASE_ADDR + 0x18)
+
+#define EXT_INT0 0x00000800
+#define EXT_INT1 0x00000400
+#define PORRSTDET 0x00000200
+#define HARDRSTDET 0x00000100
+#define DLAVAILQ 0x00000080 /* ro */
+#define HOSTERR 0x00000040
+#define INITERR 0x00000020
+#define DEVINT 0x00000010
+#define COMINT 0x00000008
+#define DEVTIMER2 0x00000004
+#define DEVTIMER1 0x00000002
+#define DLAVAIL 0x00000001
+
+#define CHIMINT_MASK (HOSTERR | INITERR | DEVINT | COMINT |\
+ DEVTIMER2 | DEVTIMER1 | DLAVAIL)
+
+#define DEVEXCEPT_MASK (HOSTERR | INITERR | DEVINT | COMINT)
+
+#define CHIMINTEN (REG_BASE_ADDR + 0x1C)
+
+#define RST_EN_EXT_INT1 0x01000000
+#define RST_EN_EXT_INT0 0x00800000
+#define RST_EN_HOSTERR 0x00400000
+#define RST_EN_INITERR 0x00200000
+#define RST_EN_DEVINT 0x00100000
+#define RST_EN_COMINT 0x00080000
+#define RST_EN_DEVTIMER2 0x00040000
+#define RST_EN_DEVTIMER1 0x00020000
+#define RST_EN_DLAVAIL 0x00010000
+#define SET_EN_EXT_INT1 0x00000100
+#define SET_EN_EXT_INT0 0x00000080
+#define SET_EN_HOSTERR 0x00000040
+#define SET_EN_INITERR 0x00000020
+#define SET_EN_DEVINT 0x00000010
+#define SET_EN_COMINT 0x00000008
+#define SET_EN_DEVTIMER2 0x00000004
+#define SET_EN_DEVTIMER1 0x00000002
+#define SET_EN_DLAVAIL 0x00000001
+
+#define RST_CHIMINTEN (RST_EN_HOSTERR | RST_EN_INITERR | \
+ RST_EN_DEVINT | RST_EN_COMINT | \
+ RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\
+ RST_EN_DLAVAIL)
+
+#define SET_CHIMINTEN (SET_EN_HOSTERR | SET_EN_INITERR |\
+ SET_EN_DEVINT | SET_EN_COMINT |\
+ SET_EN_DLAVAIL)
+
+#define OVLYDMACTL (REG_BASE_ADDR + 0x20)
+
+#define OVLYADR_MASK 0x07FF0000
+#define OVLYLSEQ_MASK 0x0000FF00
+#define OVLYCSEQ 0x00000080
+#define OVLYHALTERR 0x00000040
+#define PIOCMODE 0x00000020
+#define RESETOVLYDMA 0x00000008 /* wo */
+#define STARTOVLYDMA 0x00000004
+#define STOPOVLYDMA 0x00000002 /* wo */
+#define OVLYDMAACT 0x00000001 /* ro */
+
+#define OVLYDMACNT (REG_BASE_ADDR + 0x24)
+
+#define OVLYDOMAIN1 0x20000000 /* ro */
+#define OVLYDOMAIN0 0x10000000
+#define OVLYBUFADR_MASK 0x007F0000
+#define OVLYDMACNT_MASK 0x00003FFF
+
+#define OVLYDMAADR (REG_BASE_ADDR + 0x28)
+
+#define DMAERR (REG_BASE_ADDR + 0x30)
+
+#define OVLYERRSTAT_MASK 0x0000FF00 /* ro */
+#define CSERRSTAT_MASK 0x000000FF /* ro */
+
+#define SPIODATA (REG_BASE_ADDR + 0x34)
+
+/* 0x38 - 0x3C are reserved */
+
+#define T1CNTRLR (REG_BASE_ADDR + 0x40)
+
+#define T1DONE 0x00010000 /* ro */
+#define TIMER64 0x00000400
+#define T1ENABLE 0x00000200
+#define T1RELOAD 0x00000100
+#define T1PRESCALER_MASK 0x00000003
+
+#define T1CMPR (REG_BASE_ADDR + 0x44)
+
+#define T1CNTR (REG_BASE_ADDR + 0x48)
+
+#define T2CNTRLR (REG_BASE_ADDR + 0x4C)
+
+#define T2DONE 0x00010000 /* ro */
+#define T2ENABLE 0x00000200
+#define T2RELOAD 0x00000100
+#define T2PRESCALER_MASK 0x00000003
+
+#define T2CMPR (REG_BASE_ADDR + 0x50)
+
+#define T2CNTR (REG_BASE_ADDR + 0x54)
+
+/* 0x58h - 0xFCh are reserved */
+
+/*
+ * DCH_SAS Registers, Address Range : (0x800-0xFFF)
+ */
+#define CMDCTXBASE (REG_BASE_ADDR + 0x800)
+
+#define DEVCTXBASE (REG_BASE_ADDR + 0x808)
+
+#define CTXDOMAIN (REG_BASE_ADDR + 0x810)
+
+#define DEVCTXDOMAIN1 0x00000008 /* ro */
+#define DEVCTXDOMAIN0 0x00000004
+#define CMDCTXDOMAIN1 0x00000002 /* ro */
+#define CMDCTXDOMAIN0 0x00000001
+
+#define DCHCTL (REG_BASE_ADDR + 0x814)
+
+#define OCMBISTREPAIR 0x00080000
+#define OCMBISTEN 0x00040000
+#define OCMBISTDN 0x00020000 /* ro */
+#define OCMBISTFAIL 0x00010000 /* ro */
+#define DDBBISTEN 0x00004000
+#define DDBBISTDN 0x00002000 /* ro */
+#define DDBBISTFAIL 0x00001000 /* ro */
+#define SCBBISTEN 0x00000400
+#define SCBBISTDN 0x00000200 /* ro */
+#define SCBBISTFAIL 0x00000100 /* ro */
+
+#define MEMSEL_MASK 0x000000E0
+#define MEMSEL_CCM_LSEQ 0x00000000
+#define MEMSEL_CCM_IOP 0x00000020
+#define MEMSEL_CCM_SASCTL 0x00000040
+#define MEMSEL_DCM_LSEQ 0x00000060
+#define MEMSEL_DCM_IOP 0x00000080
+#define MEMSEL_OCM 0x000000A0
+
+#define FRCERR 0x00000010
+#define AUTORLS 0x00000001
+
+#define DCHREVISION (REG_BASE_ADDR + 0x818)
+
+#define DCHREVISION_MASK 0x000000FF
+
+#define DCHSTATUS (REG_BASE_ADDR + 0x81C)
+
+#define EN_CFIFTOERR 0x00020000
+#define CFIFTOERR 0x00000200
+#define CSEQINT 0x00000100 /* ro */
+#define LSEQ7INT 0x00000080 /* ro */
+#define LSEQ6INT 0x00000040 /* ro */
+#define LSEQ5INT 0x00000020 /* ro */
+#define LSEQ4INT 0x00000010 /* ro */
+#define LSEQ3INT 0x00000008 /* ro */
+#define LSEQ2INT 0x00000004 /* ro */
+#define LSEQ1INT 0x00000002 /* ro */
+#define LSEQ0INT 0x00000001 /* ro */
+
+#define LSEQINT_MASK (LSEQ7INT | LSEQ6INT | LSEQ5INT |\
+ LSEQ4INT | LSEQ3INT | LSEQ2INT |\
+ LSEQ1INT | LSEQ0INT)
+
+#define DCHDFIFDEBUG (REG_BASE_ADDR + 0x820)
+#define ENFAIRMST 0x00FF0000
+#define DISWRMST9 0x00000200
+#define DISWRMST8 0x00000100
+#define DISRDMST 0x000000FF
+
+#define ATOMICSTATCTL (REG_BASE_ADDR + 0x824)
+/* 8 bit wide */
+#define AUTOINC 0x80
+#define ATOMICERR 0x04
+#define ATOMICWIN 0x02
+#define ATOMICDONE 0x01
+
+
+#define ALTCIOADR (REG_BASE_ADDR + 0x828)
+/* 16 bit; bits 8:0 define CIO addr space of CSEQ */
+
+#define ASCBPTR (REG_BASE_ADDR + 0x82C)
+/* 16 bit wide */
+
+#define ADDBPTR (REG_BASE_ADDR + 0x82E)
+/* 16 bit wide */
+
+#define ANEWDATA (REG_BASE_ADDR + 0x830)
+/* 16 bit */
+
+#define AOLDDATA (REG_BASE_ADDR + 0x834)
+/* 16 bit */
+
+#define CTXACCESS (REG_BASE_ADDR + 0x838)
+/* 32 bit */
+
+/* 0x83Ch - 0xFFCh are reserved */
+
+/*
+ * ARP2 External Processor Registers, Address Range : (0x00-0x1F)
+ */
+#define ARP2CTL 0x00
+
+#define FRCSCRPERR 0x00040000
+#define FRCARP2PERR 0x00020000
+#define FRCARP2ILLOPC 0x00010000
+#define ENWAITTO 0x00008000
+#define PERRORDIS 0x00004000
+#define FAILDIS 0x00002000
+#define CIOPERRDIS 0x00001000
+#define BREAKEN3 0x00000800
+#define BREAKEN2 0x00000400
+#define BREAKEN1 0x00000200
+#define BREAKEN0 0x00000100
+#define EPAUSE 0x00000008
+#define PAUSED 0x00000004 /* ro */
+#define STEP 0x00000002
+#define ARP2RESET 0x00000001 /* wo */
+
+#define ARP2INT 0x04
+
+#define HALTCODE_MASK 0x00FF0000 /* ro */
+#define ARP2WAITTO 0x00000100
+#define ARP2HALTC 0x00000080
+#define ARP2ILLOPC 0x00000040
+#define ARP2PERR 0x00000020
+#define ARP2CIOPERR 0x00000010
+#define ARP2BREAK3 0x00000008
+#define ARP2BREAK2 0x00000004
+#define ARP2BREAK1 0x00000002
+#define ARP2BREAK0 0x00000001
+
+#define ARP2INTEN 0x08
+
+#define EN_ARP2WAITTO 0x00000100
+#define EN_ARP2HALTC 0x00000080
+#define EN_ARP2ILLOPC 0x00000040
+#define EN_ARP2PERR 0x00000020
+#define EN_ARP2CIOPERR 0x00000010
+#define EN_ARP2BREAK3 0x00000008
+#define EN_ARP2BREAK2 0x00000004
+#define EN_ARP2BREAK1 0x00000002
+#define EN_ARP2BREAK0 0x00000001
+
+#define ARP2BREAKADR01 0x0C
+
+#define BREAKADR1_MASK 0x0FFF0000
+#define BREAKADR0_MASK 0x00000FFF
+
+#define ARP2BREAKADR23 0x10
+
+#define BREAKADR3_MASK 0x0FFF0000
+#define BREAKADR2_MASK 0x00000FFF
+
+/* 0x14h - 0x1Ch are reserved */
+
+/*
+ * ARP2 Registers, Address Range : (0x00-0x1F)
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MODEPTR 0x00
+
+#define DSTMODE 0xF0
+#define SRCMODE 0x0F
+
+#define ALTMODE 0x01
+
+#define ALTDMODE 0xF0
+#define ALTSMODE 0x0F
+
+#define ATOMICXCHG 0x02
+
+#define FLAG 0x04
+
+#define INTCODE_MASK 0xF0
+#define ALTMODEV2 0x04
+#define CARRY_INT 0x02
+#define CARRY 0x01
+
+#define ARP2INTCTL 0x05
+
+#define PAUSEDIS 0x80
+#define RSTINTCTL 0x40
+#define POPALTMODE 0x08
+#define ALTMODEV 0x04
+#define INTMASK 0x02
+#define IRET 0x01
+
+#define STACK 0x06
+
+#define FUNCTION1 0x07
+
+#define PRGMCNT 0x08
+
+#define ACCUM 0x0A
+
+#define SINDEX 0x0C
+
+#define DINDEX 0x0E
+
+#define ALLONES 0x10
+
+#define ALLZEROS 0x11
+
+#define SINDIR 0x12
+
+#define DINDIR 0x13
+
+#define JUMLDIR 0x14
+
+#define ARP2HALTCODE 0x15
+
+#define CURRADDR 0x16
+
+#define LASTADDR 0x18
+
+#define NXTLADDR 0x1A
+
+#define DBGPORTPTR 0x1C
+
+#define DBGPORT 0x1D
+
+/*
+ * CIO Registers.
+ * The definitions have the same address offset for CSEQ and LmSEQ
+ * CIO Bus Registers.
+ */
+#define MnSCBPTR 0x20
+
+#define MnDDBPTR 0x22
+
+#define SCRATCHPAGE 0x24
+
+#define MnSCRATCHPAGE 0x25
+
+#define SCRATCHPAGESV 0x26
+
+#define MnSCRATCHPAGESV 0x27
+
+#define MnDMAERRS 0x46
+
+#define MnSGDMAERRS 0x47
+
+#define MnSGBUF 0x53
+
+#define MnSGDMASTAT 0x5b
+
+#define MnDDMACTL 0x5c /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMASTAT 0x5d /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDDMAMODE 0x5e /* RAZOR.rspec.fm rev 1.5 is wrong */
+
+#define MnDMAENG 0x60
+
+#define MnPIPECTL 0x61
+
+#define MnSGBADR 0x65
+
+#define MnSCB_SITE 0x100
+
+#define MnDDB_SITE 0x180
+
+/*
+ * The common definitions below have the same address offset for both
+ * CSEQ and LmSEQ.
+ */
+#define BISTCTL0 0x4C
+
+#define BISTCTL1 0x50
+
+#define MAPPEDSCR 0x800
+
+/*
+ * CSEQ Host Register, Address Range : (0x000-0xFFC)
+ */
+#define CSEQ_HOST_REG_BASE_ADR 0xB8001000
+
+#define CARP2CTL (CSEQ_HOST_REG_BASE_ADR + ARP2CTL)
+
+#define CARP2INT (CSEQ_HOST_REG_BASE_ADR + ARP2INT)
+
+#define CARP2INTEN (CSEQ_HOST_REG_BASE_ADR + ARP2INTEN)
+
+#define CARP2BREAKADR01 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01)
+
+#define CARP2BREAKADR23 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23)
+
+#define CBISTCTL (CSEQ_HOST_REG_BASE_ADR + BISTCTL1)
+
+#define CSEQRAMBISTEN 0x00000040
+#define CSEQRAMBISTDN 0x00000020 /* ro */
+#define CSEQRAMBISTFAIL 0x00000010 /* ro */
+#define CSEQSCRBISTEN 0x00000004
+#define CSEQSCRBISTDN 0x00000002 /* ro */
+#define CSEQSCRBISTFAIL 0x00000001 /* ro */
+
+#define CMAPPEDSCR (CSEQ_HOST_REG_BASE_ADR + MAPPEDSCR)
+
+/*
+ * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC)
+ * 16 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define CSEQ_CIO_REG_BASE_ADR REG_BASE_ADDR_CSEQCIO
+
+#define CSEQm_CIO_REG(Mode, Reg) \
+ (CSEQ_CIO_REG_BASE_ADR + \
+ ((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg))
+
+#define CMODEPTR (CSEQ_CIO_REG_BASE_ADR + MODEPTR)
+
+#define CALTMODE (CSEQ_CIO_REG_BASE_ADR + ALTMODE)
+
+#define CATOMICXCHG (CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG)
+
+#define CFLAG (CSEQ_CIO_REG_BASE_ADR + FLAG)
+
+#define CARP2INTCTL (CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL)
+
+#define CSTACK (CSEQ_CIO_REG_BASE_ADR + STACK)
+
+#define CFUNCTION1 (CSEQ_CIO_REG_BASE_ADR + FUNCTION1)
+
+#define CPRGMCNT (CSEQ_CIO_REG_BASE_ADR + PRGMCNT)
+
+#define CACCUM (CSEQ_CIO_REG_BASE_ADR + ACCUM)
+
+#define CSINDEX (CSEQ_CIO_REG_BASE_ADR + SINDEX)
+
+#define CDINDEX (CSEQ_CIO_REG_BASE_ADR + DINDEX)
+
+#define CALLONES (CSEQ_CIO_REG_BASE_ADR + ALLONES)
+
+#define CALLZEROS (CSEQ_CIO_REG_BASE_ADR + ALLZEROS)
+
+#define CSINDIR (CSEQ_CIO_REG_BASE_ADR + SINDIR)
+
+#define CDINDIR (CSEQ_CIO_REG_BASE_ADR + DINDIR)
+
+#define CJUMLDIR (CSEQ_CIO_REG_BASE_ADR + JUMLDIR)
+
+#define CARP2HALTCODE (CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE)
+
+#define CCURRADDR (CSEQ_CIO_REG_BASE_ADR + CURRADDR)
+
+#define CLASTADDR (CSEQ_CIO_REG_BASE_ADR + LASTADDR)
+
+#define CNXTLADDR (CSEQ_CIO_REG_BASE_ADR + NXTLADDR)
+
+#define CDBGPORTPTR (CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR)
+
+#define CDBGPORT (CSEQ_CIO_REG_BASE_ADR + DBGPORT)
+
+#define CSCRATCHPAGE (CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE)
+
+#define CMnSCBPTR(Mode) CSEQm_CIO_REG(Mode, MnSCBPTR)
+
+#define CMnDDBPTR(Mode) CSEQm_CIO_REG(Mode, MnDDBPTR)
+
+#define CMnSCRATCHPAGE(Mode) CSEQm_CIO_REG(Mode, MnSCRATCHPAGE)
+
+#define CLINKCON (CSEQ_CIO_REG_BASE_ADR + 0x28)
+
+#define CCIOAACESS (CSEQ_CIO_REG_BASE_ADR + 0x2C)
+
+/* mode 0-7 */
+#define MnREQMBX 0x30
+#define CMnREQMBX(Mode) CSEQm_CIO_REG(Mode, 0x30)
+
+/* mode 8 */
+#define CSEQCON CSEQm_CIO_REG(8, 0x30)
+
+/* mode 0-7 */
+#define MnRSPMBX 0x34
+#define CMnRSPMBX(Mode) CSEQm_CIO_REG(Mode, 0x34)
+
+/* mode 8 */
+#define CSEQCOMCTL CSEQm_CIO_REG(8, 0x34)
+
+/* mode 8 */
+#define CSEQCOMSTAT CSEQm_CIO_REG(8, 0x35)
+
+/* mode 8 */
+#define CSEQCOMINTEN CSEQm_CIO_REG(8, 0x36)
+
+/* mode 8 */
+#define CSEQCOMDMACTL CSEQm_CIO_REG(8, 0x37)
+
+#define CSHALTERR 0x10
+#define RESETCSDMA 0x08 /* wo */
+#define STARTCSDMA 0x04
+#define STOPCSDMA 0x02 /* wo */
+#define CSDMAACT 0x01 /* ro */
+
+/* mode 0-7 */
+#define MnINT 0x38
+#define CMnINT(Mode) CSEQm_CIO_REG(Mode, 0x38)
+
+#define CMnREQMBXE 0x02
+#define CMnRSPMBXF 0x01
+#define CMnINT_MASK 0x00000003
+
+/* mode 8 */
+#define CSEQREQMBX CSEQm_CIO_REG(8, 0x38)
+
+/* mode 0-7 */
+#define MnINTEN 0x3C
+#define CMnINTEN(Mode) CSEQm_CIO_REG(Mode, 0x3C)
+
+#define EN_CMnRSPMBXF 0x01
+
+/* mode 8 */
+#define CSEQRSPMBX CSEQm_CIO_REG(8, 0x3C)
+
+/* mode 8 */
+#define CSDMAADR CSEQm_CIO_REG(8, 0x40)
+
+/* mode 8 */
+#define CSDMACNT CSEQm_CIO_REG(8, 0x48)
+
+/* mode 8 */
+#define CSEQDLCTL CSEQm_CIO_REG(8, 0x4D)
+
+#define DONELISTEND 0x10
+#define DONELISTSIZE_MASK 0x0F
+#define DONELISTSIZE_8ELEM 0x01
+#define DONELISTSIZE_16ELEM 0x02
+#define DONELISTSIZE_32ELEM 0x03
+#define DONELISTSIZE_64ELEM 0x04
+#define DONELISTSIZE_128ELEM 0x05
+#define DONELISTSIZE_256ELEM 0x06
+#define DONELISTSIZE_512ELEM 0x07
+#define DONELISTSIZE_1024ELEM 0x08
+#define DONELISTSIZE_2048ELEM 0x09
+#define DONELISTSIZE_4096ELEM 0x0A
+#define DONELISTSIZE_8192ELEM 0x0B
+#define DONELISTSIZE_16384ELEM 0x0C
+
+/* mode 8 */
+#define CSEQDLOFFS CSEQm_CIO_REG(8, 0x4E)
+
+/* mode 11 */
+#define CM11INTVEC0 CSEQm_CIO_REG(11, 0x50)
+
+/* mode 11 */
+#define CM11INTVEC1 CSEQm_CIO_REG(11, 0x52)
+
+/* mode 11 */
+#define CM11INTVEC2 CSEQm_CIO_REG(11, 0x54)
+
+#define CCONMSK (CSEQ_CIO_REG_BASE_ADR + 0x60)
+
+#define CCONEXIST (CSEQ_CIO_REG_BASE_ADR + 0x61)
+
+#define CCONMODE (CSEQ_CIO_REG_BASE_ADR + 0x62)
+
+#define CTIMERCALC (CSEQ_CIO_REG_BASE_ADR + 0x64)
+
+#define CINTDIS (CSEQ_CIO_REG_BASE_ADR + 0x68)
+
+/* mode 8, 32x32 bits, 128 bytes of mapped buffer */
+#define CSBUFFER CSEQm_CIO_REG(8, 0x80)
+
+#define CSCRATCH (CSEQ_CIO_REG_BASE_ADR + 0x1C0)
+
+/* mode 0-8 */
+#define CMnSCRATCH(Mode) CSEQm_CIO_REG(Mode, 0x1E0)
+
+/*
+ * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC)
+ */
+#define CSEQ_RAM_REG_BASE_ADR 0xB8004000
+
+/*
+ * The common definitions below have the same address offset for all the Link
+ * sequencers.
+ */
+#define MODECTL 0x40
+
+#define DBGMODE 0x44
+
+#define CONTROL 0x48
+#define LEDTIMER 0x00010000
+#define LEDTIMERS_10us 0x00000000
+#define LEDTIMERS_1ms 0x00000800
+#define LEDTIMERS_100ms 0x00001000
+#define LEDMODE_TXRX 0x00000000
+#define LEDMODE_CONNECTED 0x00000200
+#define LEDPOL 0x00000100
+
+#define LSEQRAM 0x1000
+
+/*
+ * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC)
+ */
+#define LSEQ0_HOST_REG_BASE_ADR 0xB8020000
+#define LSEQ1_HOST_REG_BASE_ADR 0xB8024000
+#define LSEQ2_HOST_REG_BASE_ADR 0xB8028000
+#define LSEQ3_HOST_REG_BASE_ADR 0xB802C000
+#define LSEQ4_HOST_REG_BASE_ADR 0xB8030000
+#define LSEQ5_HOST_REG_BASE_ADR 0xB8034000
+#define LSEQ6_HOST_REG_BASE_ADR 0xB8038000
+#define LSEQ7_HOST_REG_BASE_ADR 0xB803C000
+
+#define LmARP2CTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2CTL)
+
+#define LmARP2INT(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2INT)
+
+#define LmARP2INTEN(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2INTEN)
+
+#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ DBGMODE)
+
+#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ CONTROL)
+
+#define LmARP2BREAKADR01(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2BREAKADR01)
+
+#define LmARP2BREAKADR23(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ ARP2BREAKADR23)
+
+#define LmMODECTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ MODECTL)
+
+#define LmAUTODISCI 0x08000000
+#define LmDSBLBITLT 0x04000000
+#define LmDSBLANTT 0x02000000
+#define LmDSBLCRTT 0x01000000
+#define LmDSBLCONT 0x00000100
+#define LmPRIMODE 0x00000080
+#define LmDSBLHOLD 0x00000040
+#define LmDISACK 0x00000020
+#define LmBLIND48 0x00000010
+#define LmRCVMODE_MASK 0x0000000C
+#define LmRCVMODE_PLD 0x00000000
+#define LmRCVMODE_HPC 0x00000004
+
+#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ DBGMODE)
+
+#define LmFRCPERR 0x80000000
+#define LmMEMSEL_MASK 0x30000000
+#define LmFRCRBPERR 0x00000000
+#define LmFRCTBPERR 0x10000000
+#define LmFRCSGBPERR 0x20000000
+#define LmFRCARBPERR 0x30000000
+#define LmRCVIDW 0x00080000
+#define LmINVDWERR 0x00040000
+#define LmRCVDISP 0x00004000
+#define LmDISPERR 0x00002000
+#define LmDSBLDSCR 0x00000800
+#define LmDSBLSCR 0x00000400
+#define LmFRCNAK 0x00000200
+#define LmFRCROFS 0x00000100
+#define LmFRCCRC 0x00000080
+#define LmFRMTYPE_MASK 0x00000070
+#define LmSG_DATA 0x00000000
+#define LmSG_COMMAND 0x00000010
+#define LmSG_TASK 0x00000020
+#define LmSG_TGTXFER 0x00000030
+#define LmSG_RESPONSE 0x00000040
+#define LmSG_IDENADDR 0x00000050
+#define LmSG_OPENADDR 0x00000060
+#define LmDISCRCGEN 0x00000008
+#define LmDISCRCCHK 0x00000004
+#define LmSSXMTFRM 0x00000002
+#define LmSSRCVFRM 0x00000001
+
+#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ CONTROL)
+
+#define LmSTEPXMTFRM 0x00000002
+#define LmSTEPRCVFRM 0x00000001
+
+#define LmBISTCTL0(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \
+ BISTCTL0)
+
+#define ARBBISTEN 0x40000000
+#define ARBBISTDN 0x20000000 /* ro */
+#define ARBBISTFAIL 0x10000000 /* ro */
+#define TBBISTEN 0x00000400
+#define TBBISTDN 0x00000200 /* ro */
+#define TBBISTFAIL 0x00000100 /* ro */
+#define RBBISTEN 0x00000040
+#define RBBISTDN 0x00000020 /* ro */
+#define RBBISTFAIL 0x00000010 /* ro */
+#define SGBISTEN 0x00000004
+#define SGBISTDN 0x00000002 /* ro */
+#define SGBISTFAIL 0x00000001 /* ro */
+
+#define LmBISTCTL1(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum)*LmSEQ_HOST_REG_SIZE) +\
+ BISTCTL1)
+
+#define LmRAMPAGE1 0x00000200
+#define LmRAMPAGE0 0x00000100
+#define LmIMEMBISTEN 0x00000040
+#define LmIMEMBISTDN 0x00000020 /* ro */
+#define LmIMEMBISTFAIL 0x00000010 /* ro */
+#define LmSCRBISTEN 0x00000004
+#define LmSCRBISTDN 0x00000002 /* ro */
+#define LmSCRBISTFAIL 0x00000001 /* ro */
+#define LmRAMPAGE (LmRAMPAGE1 + LmRAMPAGE0)
+#define LmRAMPAGE_LSHIFT 0x8
+
+#define LmSCRATCH(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+ MAPPEDSCR)
+
+#define LmSEQRAM(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \
+ ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\
+ LSEQRAM)
+
+/*
+ * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC)
+ * 8 modes, each mode is 512 bytes.
+ * Unless specified, the register should valid for all modes.
+ */
+#define LmSEQ_CIOBUS_REG_BASE 0x2000
+
+#define LmSEQ_PHY_BASE(Mode, LinkNum) \
+ (LSEQ0_HOST_REG_BASE_ADR + \
+ (LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \
+ LmSEQ_CIOBUS_REG_BASE + \
+ ((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE))
+
+#define LmSEQ_PHY_REG(Mode, LinkNum, Reg) \
+ (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg))
+
+#define LmMODEPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, MODEPTR)
+
+#define LmALTMODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALTMODE)
+
+#define LmATOMICXCHG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG)
+
+#define LmFLAG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FLAG)
+
+#define LmARP2INTCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL)
+
+#define LmSTACK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, STACK)
+
+#define LmFUNCTION1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FUNCTION1)
+
+#define LmPRGMCNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, PRGMCNT)
+
+#define LmACCUM(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ACCUM)
+
+#define LmSINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDEX)
+
+#define LmDINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDEX)
+
+#define LmALLONES(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLONES)
+
+#define LmALLZEROS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLZEROS)
+
+#define LmSINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDIR)
+
+#define LmDINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDIR)
+
+#define LmJUMLDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, JUMLDIR)
+
+#define LmARP2HALTCODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE)
+
+#define LmCURRADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, CURRADDR)
+
+#define LmLASTADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, LASTADDR)
+
+#define LmNXTLADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, NXTLADDR)
+
+#define LmDBGPORTPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR)
+
+#define LmDBGPORT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORT)
+
+#define LmSCRATCHPAGE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE)
+
+#define LmMnSCRATCHPAGE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, \
+ MnSCRATCHPAGE)
+
+#define LmTIMERCALC(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x28)
+
+#define LmREQMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x30)
+
+#define LmRSPMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x34)
+
+#define LmMnINT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x38)
+
+#define CTXMEMSIZE 0x80000000 /* ro */
+#define LmACKREQ 0x08000000
+#define LmNAKREQ 0x04000000
+#define LmMnXMTERR 0x02000000
+#define LmM5OOBSVC 0x01000000
+#define LmHWTINT 0x00800000
+#define LmMnCTXDONE 0x00100000
+#define LmM2REQMBXF 0x00080000
+#define LmM2RSPMBXE 0x00040000
+#define LmMnDMAERR 0x00020000
+#define LmRCVPRIM 0x00010000
+#define LmRCVERR 0x00008000
+#define LmADDRRCV 0x00004000
+#define LmMnHDRMISS 0x00002000
+#define LmMnWAITSCB 0x00001000
+#define LmMnRLSSCB 0x00000800
+#define LmMnSAVECTX 0x00000400
+#define LmMnFETCHSG 0x00000200
+#define LmMnLOADCTX 0x00000100
+#define LmMnCFGICL 0x00000080
+#define LmMnCFGSATA 0x00000040
+#define LmMnCFGEXPSATA 0x00000020
+#define LmMnCFGCMPLT 0x00000010
+#define LmMnCFGRBUF 0x00000008
+#define LmMnSAVETTR 0x00000004
+#define LmMnCFGRDAT 0x00000002
+#define LmMnCFGHDR 0x00000001
+
+#define LmMnINTEN(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x3C)
+
+#define EN_LmACKREQ 0x08000000
+#define EN_LmNAKREQ 0x04000000
+#define EN_LmMnXMTERR 0x02000000
+#define EN_LmM5OOBSVC 0x01000000
+#define EN_LmHWTINT 0x00800000
+#define EN_LmMnCTXDONE 0x00100000
+#define EN_LmM2REQMBXF 0x00080000
+#define EN_LmM2RSPMBXE 0x00040000
+#define EN_LmMnDMAERR 0x00020000
+#define EN_LmRCVPRIM 0x00010000
+#define EN_LmRCVERR 0x00008000
+#define EN_LmADDRRCV 0x00004000
+#define EN_LmMnHDRMISS 0x00002000
+#define EN_LmMnWAITSCB 0x00001000
+#define EN_LmMnRLSSCB 0x00000800
+#define EN_LmMnSAVECTX 0x00000400
+#define EN_LmMnFETCHSG 0x00000200
+#define EN_LmMnLOADCTX 0x00000100
+#define EN_LmMnCFGICL 0x00000080
+#define EN_LmMnCFGSATA 0x00000040
+#define EN_LmMnCFGEXPSATA 0x00000020
+#define EN_LmMnCFGCMPLT 0x00000010
+#define EN_LmMnCFGRBUF 0x00000008
+#define EN_LmMnSAVETTR 0x00000004
+#define EN_LmMnCFGRDAT 0x00000002
+#define EN_LmMnCFGHDR 0x00000001
+
+#define LmM0INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \
+ EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \
+ EN_LmMnCFGHDR | EN_LmRCVERR | \
+ EN_LmADDRRCV | EN_LmMnHDRMISS | \
+ EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+ EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+ EN_LmHWTINT | EN_LmMnCTXDONE | \
+ EN_LmRCVPRIM | EN_LmMnCFGSATA | \
+ EN_LmMnCFGEXPSATA | EN_LmMnDMAERR)
+
+#define LmM1INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmADDRRCV | \
+ EN_LmMnRLSSCB | EN_LmMnSAVECTX | \
+ EN_LmMnFETCHSG | EN_LmMnLOADCTX | \
+ EN_LmMnXMTERR | EN_LmHWTINT | \
+ EN_LmMnCTXDONE | EN_LmRCVPRIM | \
+ EN_LmRCVERR | EN_LmMnDMAERR)
+
+#define LmM2INTEN_MASK (EN_LmADDRRCV | EN_LmHWTINT | \
+ EN_LmM2REQMBXF | EN_LmRCVPRIM | \
+ EN_LmRCVERR)
+
+#define LmM5INTEN_MASK (EN_LmADDRRCV | EN_LmM5OOBSVC | \
+ EN_LmHWTINT | EN_LmRCVPRIM | \
+ EN_LmRCVERR)
+
+#define LmXMTPRIMD(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x40)
+
+#define LmXMTPRIMCS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x44)
+
+#define LmCONSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x45)
+
+#define LmMnDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x46)
+
+#define LmMnSGDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x47)
+
+#define LmM0EXPHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x48)
+
+#define LmM1SASALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x48)
+#define SAS_ALIGN_DEFAULT 0xFF
+
+#define LmM0MSKHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x49)
+
+#define LmM1STPALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x49)
+#define STP_ALIGN_DEFAULT 0x1F
+
+#define LmM0RCVHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4A)
+
+#define LmM1XMTHDRP(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4A)
+
+#define LmM0ICLADR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4B)
+
+#define LmM1ALIGNMODE(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4B)
+
+#define LmDISALIGN 0x20
+#define LmROTSTPALIGN 0x10
+#define LmSTPALIGN 0x08
+#define LmROTNOTIFY 0x04
+#define LmDUALALIGN 0x02
+#define LmROTALIGN 0x01
+
+#define LmM0EXPRCVNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4C)
+
+#define LmM1XMTCNT(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4C)
+
+#define LmMnBUFSTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x4E)
+
+#define LmMnBUFPERR 0x01
+
+/* mode 0-1 */
+#define LmMnXFRLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x59)
+
+#define LmMnXFRLVL_128 0x05
+#define LmMnXFRLVL_256 0x04
+#define LmMnXFRLVL_512 0x03
+#define LmMnXFRLVL_1024 0x02
+#define LmMnXFRLVL_1536 0x01
+#define LmMnXFRLVL_2048 0x00
+
+ /* mode 0-1 */
+#define LmMnSGDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5A)
+
+#define LmMnRESETSG 0x04
+#define LmMnSTOPSG 0x02
+#define LmMnSTARTSG 0x01
+
+/* mode 0-1 */
+#define LmMnSGDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5B)
+
+/* mode 0-1 */
+#define LmMnDDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5C)
+
+#define LmMnFLUSH 0x40 /* wo */
+#define LmMnRLSRTRY 0x20 /* wo */
+#define LmMnDISCARD 0x10 /* wo */
+#define LmMnRESETDAT 0x08 /* wo */
+#define LmMnSUSDAT 0x04 /* wo */
+#define LmMnSTOPDAT 0x02 /* wo */
+#define LmMnSTARTDAT 0x01 /* wo */
+
+/* mode 0-1 */
+#define LmMnDDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5D)
+
+#define LmMnDPEMPTY 0x80
+#define LmMnFLUSHING 0x40
+#define LmMnDDMAREQ 0x20
+#define LmMnHDMAREQ 0x10
+#define LmMnDATFREE 0x08
+#define LmMnDATSUS 0x04
+#define LmMnDATACT 0x02
+#define LmMnDATEN 0x01
+
+/* mode 0-1 */
+#define LmMnDDMAMODE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5E)
+
+#define LmMnDMATYPE_NORMAL 0x0000
+#define LmMnDMATYPE_HOST_ONLY_TX 0x0001
+#define LmMnDMATYPE_DEVICE_ONLY_TX 0x0002
+#define LmMnDMATYPE_INVALID 0x0003
+#define LmMnDMATYPE_MASK 0x0003
+
+#define LmMnDMAWRAP 0x0004
+#define LmMnBITBUCKET 0x0008
+#define LmMnDISHDR 0x0010
+#define LmMnSTPCRC 0x0020
+#define LmXTEST 0x0040
+#define LmMnDISCRC 0x0080
+#define LmMnENINTLK 0x0100
+#define LmMnADDRFRM 0x0400
+#define LmMnENXMTCRC 0x0800
+
+/* mode 0-1 */
+#define LmMnXFRCNT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x70)
+
+/* mode 0-1 */
+#define LmMnDPSEL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7B)
+#define LmMnDPSEL_MASK 0x07
+#define LmMnEOLPRE 0x40
+#define LmMnEOSPRE 0x80
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Receive Mode n = 0 */
+#define LmMnHRADDR 0x00
+#define LmMnHBYTECNT 0x01
+#define LmMnHREWIND 0x02
+#define LmMnDWADDR 0x03
+#define LmMnDSPACECNT 0x04
+#define LmMnDFRMSIZE 0x05
+
+/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */
+/* Transmit Mode n = 1 */
+#define LmMnHWADDR 0x00
+#define LmMnHSPACECNT 0x01
+/* #define LmMnHREWIND 0x02 */
+#define LmMnDRADDR 0x03
+#define LmMnDBYTECNT 0x04
+/* #define LmMnDFRMSIZE 0x05 */
+
+/* mode 0-1 */
+#define LmMnDPACC(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x78)
+#define LmMnDPACC_MASK 0x00FFFFFF
+
+/* mode 0-1 */
+#define LmMnHOLDLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7D)
+
+#define LmPRMSTAT0(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x80)
+#define LmPRMSTAT0BYTE0 0x80
+#define LmPRMSTAT0BYTE1 0x81
+#define LmPRMSTAT0BYTE2 0x82
+#define LmPRMSTAT0BYTE3 0x83
+
+#define LmFRAMERCVD 0x80000000
+#define LmXFRRDYRCVD 0x40000000
+#define LmUNKNOWNP 0x20000000
+#define LmBREAK 0x10000000
+#define LmDONE 0x08000000
+#define LmOPENACPT 0x04000000
+#define LmOPENRJCT 0x02000000
+#define LmOPENRTRY 0x01000000
+#define LmCLOSERV1 0x00800000
+#define LmCLOSERV0 0x00400000
+#define LmCLOSENORM 0x00200000
+#define LmCLOSECLAF 0x00100000
+#define LmNOTIFYRV2 0x00080000
+#define LmNOTIFYRV1 0x00040000
+#define LmNOTIFYRV0 0x00020000
+#define LmNOTIFYSPIN 0x00010000
+#define LmBROADRV4 0x00008000
+#define LmBROADRV3 0x00004000
+#define LmBROADRV2 0x00002000
+#define LmBROADRV1 0x00001000
+#define LmBROADSES 0x00000800
+#define LmBROADRVCH1 0x00000400
+#define LmBROADRVCH0 0x00000200
+#define LmBROADCH 0x00000100
+#define LmAIPRVWP 0x00000080
+#define LmAIPWP 0x00000040
+#define LmAIPWD 0x00000020
+#define LmAIPWC 0x00000010
+#define LmAIPRV2 0x00000008
+#define LmAIPRV1 0x00000004
+#define LmAIPRV0 0x00000002
+#define LmAIPNRML 0x00000001
+
+#define LmBROADCAST_MASK (LmBROADCH | LmBROADRVCH0 | \
+ LmBROADRVCH1)
+
+#define LmPRMSTAT1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x84)
+#define LmPRMSTAT1BYTE0 0x84
+#define LmPRMSTAT1BYTE1 0x85
+#define LmPRMSTAT1BYTE2 0x86
+#define LmPRMSTAT1BYTE3 0x87
+
+#define LmFRMRCVDSTAT 0x80000000
+#define LmBREAK_DET 0x04000000
+#define LmCLOSE_DET 0x02000000
+#define LmDONE_DET 0x01000000
+#define LmXRDY 0x00040000
+#define LmSYNCSRST 0x00020000
+#define LmSYNC 0x00010000
+#define LmXHOLD 0x00008000
+#define LmRRDY 0x00004000
+#define LmHOLD 0x00002000
+#define LmROK 0x00001000
+#define LmRIP 0x00000800
+#define LmCRBLK 0x00000400
+#define LmACK 0x00000200
+#define LmNAK 0x00000100
+#define LmHARDRST 0x00000080
+#define LmERROR 0x00000040
+#define LmRERR 0x00000020
+#define LmPMREQP 0x00000010
+#define LmPMREQS 0x00000008
+#define LmPMACK 0x00000004
+#define LmPMNAK 0x00000002
+#define LmDMAT 0x00000001
+
+/* mode 1 */
+#define LmMnSATAFS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7E)
+#define LmMnXMTSIZE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x93)
+
+/* mode 0 */
+#define LmMnFRMERR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xB0)
+
+#define LmACRCERR 0x00000800
+#define LmPHYOVRN 0x00000400
+#define LmOBOVRN 0x00000200
+#define LmMnZERODATA 0x00000100
+#define LmSATAINTLK 0x00000080
+#define LmMnCRCERR 0x00000020
+#define LmRRDYOVRN 0x00000010
+#define LmMISSSOAF 0x00000008
+#define LmMISSSOF 0x00000004
+#define LmMISSEOAF 0x00000002
+#define LmMISSEOF 0x00000001
+
+#define LmFRMERREN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xB4)
+
+#define EN_LmACRCERR 0x00000800
+#define EN_LmPHYOVRN 0x00000400
+#define EN_LmOBOVRN 0x00000200
+#define EN_LmMnZERODATA 0x00000100
+#define EN_LmSATAINTLK 0x00000080
+#define EN_LmFRMBAD 0x00000040
+#define EN_LmMnCRCERR 0x00000020
+#define EN_LmRRDYOVRN 0x00000010
+#define EN_LmMISSSOAF 0x00000008
+#define EN_LmMISSSOF 0x00000004
+#define EN_LmMISSEOAF 0x00000002
+#define EN_LmMISSEOF 0x00000001
+
+#define LmFRMERREN_MASK (EN_LmSATAINTLK | EN_LmMnCRCERR | \
+ EN_LmRRDYOVRN | EN_LmMISSSOF | \
+ EN_LmMISSEOAF | EN_LmMISSEOF | \
+ EN_LmACRCERR | LmPHYOVRN | \
+ EN_LmOBOVRN | EN_LmMnZERODATA)
+
+#define LmHWTSTATEN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC5)
+
+#define EN_LmDONETO 0x80
+#define EN_LmINVDISP 0x40
+#define EN_LmINVDW 0x20
+#define EN_LmDWSEVENT 0x08
+#define EN_LmCRTTTO 0x04
+#define EN_LmANTTTO 0x02
+#define EN_LmBITLTTO 0x01
+
+#define LmHWTSTATEN_MASK (EN_LmINVDISP | EN_LmINVDW | \
+ EN_LmDWSEVENT | EN_LmCRTTTO | \
+ EN_LmANTTTO | EN_LmDONETO | \
+ EN_LmBITLTTO)
+
+#define LmHWTSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC7)
+
+#define LmDONETO 0x80
+#define LmINVDISP 0x40
+#define LmINVDW 0x20
+#define LmDWSEVENT 0x08
+#define LmCRTTTO 0x04
+#define LmANTTTO 0x02
+#define LmBITLTTO 0x01
+
+#define LmMnDATABUFADR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xC8)
+#define LmDATABUFADR_MASK 0x0FFF
+
+#define LmMnDATABUF(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xCA)
+
+#define LmPRIMSTAT0EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE0)
+
+#define EN_LmUNKNOWNP 0x20000000
+#define EN_LmBREAK 0x10000000
+#define EN_LmDONE 0x08000000
+#define EN_LmOPENACPT 0x04000000
+#define EN_LmOPENRJCT 0x02000000
+#define EN_LmOPENRTRY 0x01000000
+#define EN_LmCLOSERV1 0x00800000
+#define EN_LmCLOSERV0 0x00400000
+#define EN_LmCLOSENORM 0x00200000
+#define EN_LmCLOSECLAF 0x00100000
+#define EN_LmNOTIFYRV2 0x00080000
+#define EN_LmNOTIFYRV1 0x00040000
+#define EN_LmNOTIFYRV0 0x00020000
+#define EN_LmNOTIFYSPIN 0x00010000
+#define EN_LmBROADRV4 0x00008000
+#define EN_LmBROADRV3 0x00004000
+#define EN_LmBROADRV2 0x00002000
+#define EN_LmBROADRV1 0x00001000
+#define EN_LmBROADRV0 0x00000800
+#define EN_LmBROADRVCH1 0x00000400
+#define EN_LmBROADRVCH0 0x00000200
+#define EN_LmBROADCH 0x00000100
+#define EN_LmAIPRVWP 0x00000080
+#define EN_LmAIPWP 0x00000040
+#define EN_LmAIPWD 0x00000020
+#define EN_LmAIPWC 0x00000010
+#define EN_LmAIPRV2 0x00000008
+#define EN_LmAIPRV1 0x00000004
+#define EN_LmAIPRV0 0x00000002
+#define EN_LmAIPNRML 0x00000001
+
+#define LmPRIMSTAT0EN_MASK (EN_LmBREAK | \
+ EN_LmDONE | EN_LmOPENACPT | \
+ EN_LmOPENRJCT | EN_LmOPENRTRY | \
+ EN_LmCLOSERV1 | EN_LmCLOSERV0 | \
+ EN_LmCLOSENORM | EN_LmCLOSECLAF | \
+ EN_LmBROADRV4 | EN_LmBROADRV3 | \
+ EN_LmBROADRV2 | EN_LmBROADRV1 | \
+ EN_LmBROADRV0 | EN_LmBROADRVCH1 | \
+ EN_LmBROADRVCH0 | EN_LmBROADCH | \
+ EN_LmAIPRVWP | EN_LmAIPWP | \
+ EN_LmAIPWD | EN_LmAIPWC | \
+ EN_LmAIPRV2 | EN_LmAIPRV1 | \
+ EN_LmAIPRV0 | EN_LmAIPNRML)
+
+#define LmPRIMSTAT1EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE4)
+
+#define EN_LmXRDY 0x00040000
+#define EN_LmSYNCSRST 0x00020000
+#define EN_LmSYNC 0x00010000
+#define EN_LmXHOLD 0x00008000
+#define EN_LmRRDY 0x00004000
+#define EN_LmHOLD 0x00002000
+#define EN_LmROK 0x00001000
+#define EN_LmRIP 0x00000800
+#define EN_LmCRBLK 0x00000400
+#define EN_LmACK 0x00000200
+#define EN_LmNAK 0x00000100
+#define EN_LmHARDRST 0x00000080
+#define EN_LmERROR 0x00000040
+#define EN_LmRERR 0x00000020
+#define EN_LmPMREQP 0x00000010
+#define EN_LmPMREQS 0x00000008
+#define EN_LmPMACK 0x00000004
+#define EN_LmPMNAK 0x00000002
+#define EN_LmDMAT 0x00000001
+
+#define LmPRIMSTAT1EN_MASK (EN_LmHARDRST | \
+ EN_LmSYNCSRST | \
+ EN_LmPMREQP | EN_LmPMREQS | \
+ EN_LmPMACK | EN_LmPMNAK)
+
+#define LmSMSTATE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE8)
+
+#define LmSMSTATEBRK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xEC)
+
+#define LmSMDBGCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xF0)
+
+
+/*
+ * LmSEQ CIO Bus Mode 3 Register.
+ * Mode 3: Configuration and Setup, IOP Context SCB.
+ */
+#define LmM3SATATIMER(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x48)
+
+#define LmM3INTVEC0(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x90)
+
+#define LmM3INTVEC1(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x92)
+
+#define LmM3INTVEC2(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x94)
+
+#define LmM3INTVEC3(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x96)
+
+#define LmM3INTVEC4(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x98)
+
+#define LmM3INTVEC5(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9A)
+
+#define LmM3INTVEC6(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9C)
+
+#define LmM3INTVEC7(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9E)
+
+#define LmM3INTVEC8(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA4)
+
+#define LmM3INTVEC9(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA6)
+
+#define LmM3INTVEC10(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB0)
+
+#define LmM3FRMGAP(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB4)
+
+#define LmBITL_TIMER(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA2)
+
+#define LmWWN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA8)
+
+
+/*
+ * LmSEQ CIO Bus Mode 5 Registers.
+ * Mode 5: Phy/OOB Control and Status.
+ */
+#define LmSEQ_OOB_REG(phy_id, reg) LmSEQ_PHY_REG(5, (phy_id), (reg))
+
+#define OOB_BFLTR 0x100
+
+#define BFLTR_THR_MASK 0xF0
+#define BFLTR_TC_MASK 0x0F
+
+#define OOB_INIT_MIN 0x102
+
+#define OOB_INIT_MAX 0x104
+
+#define OOB_INIT_NEG 0x106
+
+#define OOB_SAS_MIN 0x108
+
+#define OOB_SAS_MAX 0x10A
+
+#define OOB_SAS_NEG 0x10C
+
+#define OOB_WAKE_MIN 0x10E
+
+#define OOB_WAKE_MAX 0x110
+
+#define OOB_WAKE_NEG 0x112
+
+#define OOB_IDLE_MAX 0x114
+
+#define OOB_BURST_MAX 0x116
+
+#define OOB_DATA_KBITS 0x126
+
+#define OOB_ALIGN_0_DATA 0x12C
+
+#define OOB_ALIGN_1_DATA 0x130
+
+#define D10_2_DATA_k 0x00
+#define SYNC_DATA_k 0x02
+#define ALIGN_1_DATA_k 0x04
+#define ALIGN_0_DATA_k 0x08
+#define BURST_DATA_k 0x10
+
+#define OOB_PHY_RESET_COUNT 0x13C
+
+#define OOB_SIG_GEN 0x140
+
+#define START_OOB 0x80
+#define START_DWS 0x40
+#define ALIGN_CNT3 0x30
+#define ALIGN_CNT2 0x20
+#define ALIGN_CNT1 0x10
+#define ALIGN_CNT4 0x00
+#define STOP_DWS 0x08
+#define SEND_COMSAS 0x04
+#define SEND_COMINIT 0x02
+#define SEND_COMWAKE 0x01
+
+#define OOB_XMIT 0x141
+
+#define TX_ENABLE 0x80
+#define XMIT_OOB_BURST 0x10
+#define XMIT_D10_2 0x08
+#define XMIT_SYNC 0x04
+#define XMIT_ALIGN_1 0x02
+#define XMIT_ALIGN_0 0x01
+
+#define FUNCTION_MASK 0x142
+
+#define SAS_MODE_DIS 0x80
+#define SATA_MODE_DIS 0x40
+#define SPINUP_HOLD_DIS 0x20
+#define HOT_PLUG_DIS 0x10
+#define SATA_PS_DIS 0x08
+#define FUNCTION_MASK_DEFAULT (SPINUP_HOLD_DIS | SATA_PS_DIS)
+
+#define OOB_MODE 0x143
+
+#define SAS_MODE 0x80
+#define SATA_MODE 0x40
+#define SLOW_CLK 0x20
+#define FORCE_XMIT_15 0x08
+#define PHY_SPEED_60 0x04
+#define PHY_SPEED_30 0x02
+#define PHY_SPEED_15 0x01
+
+#define CURRENT_STATUS 0x144
+
+#define CURRENT_OOB_DONE 0x80
+#define CURRENT_LOSS_OF_SIGNAL 0x40
+#define CURRENT_SPINUP_HOLD 0x20
+#define CURRENT_HOT_PLUG_CNCT 0x10
+#define CURRENT_GTO_TIMEOUT 0x08
+#define CURRENT_OOB_TIMEOUT 0x04
+#define CURRENT_DEVICE_PRESENT 0x02
+#define CURRENT_OOB_ERROR 0x01
+
+#define CURRENT_OOB1_ERROR (CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_GTO_TIMEOUT)
+
+#define CURRENT_OOB2_ERROR (CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_OOB_ERROR)
+
+#define DEVICE_ADDED_W_CNT (CURRENT_OOB_DONE | \
+ CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_DEVICE_PRESENT)
+
+#define DEVICE_ADDED_WO_CNT (CURRENT_OOB_DONE | \
+ CURRENT_DEVICE_PRESENT)
+
+#define DEVICE_REMOVED CURRENT_LOSS_OF_SIGNAL
+
+#define CURRENT_PHY_MASK (CURRENT_OOB_DONE | \
+ CURRENT_LOSS_OF_SIGNAL | \
+ CURRENT_SPINUP_HOLD | \
+ CURRENT_HOT_PLUG_CNCT | \
+ CURRENT_GTO_TIMEOUT | \
+ CURRENT_DEVICE_PRESENT | \
+ CURRENT_OOB_ERROR )
+
+#define CURRENT_ERR_MASK (CURRENT_LOSS_OF_SIGNAL | \
+ CURRENT_GTO_TIMEOUT | \
+ CURRENT_OOB_TIMEOUT | \
+ CURRENT_OOB_ERROR )
+
+#define SPEED_MASK 0x145
+
+#define SATA_SPEED_30_DIS 0x10
+#define SATA_SPEED_15_DIS 0x08
+#define SAS_SPEED_60_DIS 0x04
+#define SAS_SPEED_30_DIS 0x02
+#define SAS_SPEED_15_DIS 0x01
+#define SAS_SPEED_MASK_DEFAULT 0x00
+
+#define OOB_TIMER_ENABLE 0x14D
+
+#define HOT_PLUG_EN 0x80
+#define RCD_EN 0x40
+#define COMTIMER_EN 0x20
+#define SNTT_EN 0x10
+#define SNLT_EN 0x04
+#define SNWT_EN 0x02
+#define ALIGN_EN 0x01
+
+#define OOB_STATUS 0x14E
+
+#define OOB_DONE 0x80
+#define LOSS_OF_SIGNAL 0x40 /* ro */
+#define SPINUP_HOLD 0x20
+#define HOT_PLUG_CNCT 0x10 /* ro */
+#define GTO_TIMEOUT 0x08 /* ro */
+#define OOB_TIMEOUT 0x04 /* ro */
+#define DEVICE_PRESENT 0x02 /* ro */
+#define OOB_ERROR 0x01 /* ro */
+
+#define OOB_STATUS_ERROR_MASK (LOSS_OF_SIGNAL | GTO_TIMEOUT | \
+ OOB_TIMEOUT | OOB_ERROR)
+
+#define OOB_STATUS_CLEAR 0x14F
+
+#define OOB_DONE_CLR 0x80
+#define LOSS_OF_SIGNAL_CLR 0x40
+#define SPINUP_HOLD_CLR 0x20
+#define HOT_PLUG_CNCT_CLR 0x10
+#define GTO_TIMEOUT_CLR 0x08
+#define OOB_TIMEOUT_CLR 0x04
+#define OOB_ERROR_CLR 0x01
+
+#define HOT_PLUG_DELAY 0x150
+/* In 5 ms units. 20 = 100 ms. */
+#define HOTPLUG_DELAY_TIMEOUT 20
+
+
+#define INT_ENABLE_2 0x15A
+
+#define OOB_DONE_EN 0x80
+#define LOSS_OF_SIGNAL_EN 0x40
+#define SPINUP_HOLD_EN 0x20
+#define HOT_PLUG_CNCT_EN 0x10
+#define GTO_TIMEOUT_EN 0x08
+#define OOB_TIMEOUT_EN 0x04
+#define DEVICE_PRESENT_EN 0x02
+#define OOB_ERROR_EN 0x01
+
+#define PHY_CONTROL_0 0x160
+
+#define PHY_LOWPWREN_TX 0x80
+#define PHY_LOWPWREN_RX 0x40
+#define SPARE_REG_160_B5 0x20
+#define OFFSET_CANCEL_RX 0x10
+
+/* bits 3:2 */
+#define PHY_RXCOMCENTER_60V 0x00
+#define PHY_RXCOMCENTER_70V 0x04
+#define PHY_RXCOMCENTER_80V 0x08
+#define PHY_RXCOMCENTER_90V 0x0C
+#define PHY_RXCOMCENTER_MASK 0x0C
+
+#define PHY_RESET 0x02
+#define SAS_DEFAULT_SEL 0x01
+
+#define PHY_CONTROL_1 0x161
+
+/* bits 2:0 */
+#define SATA_PHY_DETLEVEL_50mv 0x00
+#define SATA_PHY_DETLEVEL_75mv 0x01
+#define SATA_PHY_DETLEVEL_100mv 0x02
+#define SATA_PHY_DETLEVEL_125mv 0x03
+#define SATA_PHY_DETLEVEL_150mv 0x04
+#define SATA_PHY_DETLEVEL_175mv 0x05
+#define SATA_PHY_DETLEVEL_200mv 0x06
+#define SATA_PHY_DETLEVEL_225mv 0x07
+#define SATA_PHY_DETLEVEL_MASK 0x07
+
+/* bits 5:3 */
+#define SAS_PHY_DETLEVEL_50mv 0x00
+#define SAS_PHY_DETLEVEL_75mv 0x08
+#define SAS_PHY_DETLEVEL_100mv 0x10
+#define SAS_PHY_DETLEVEL_125mv 0x11
+#define SAS_PHY_DETLEVEL_150mv 0x20
+#define SAS_PHY_DETLEVEL_175mv 0x21
+#define SAS_PHY_DETLEVEL_200mv 0x30
+#define SAS_PHY_DETLEVEL_225mv 0x31
+#define SAS_PHY_DETLEVEL_MASK 0x38
+
+#define PHY_CONTROL_2 0x162
+
+/* bits 7:5 */
+#define SATA_PHY_DRV_400mv 0x00
+#define SATA_PHY_DRV_450mv 0x20
+#define SATA_PHY_DRV_500mv 0x40
+#define SATA_PHY_DRV_550mv 0x60
+#define SATA_PHY_DRV_600mv 0x80
+#define SATA_PHY_DRV_650mv 0xA0
+#define SATA_PHY_DRV_725mv 0xC0
+#define SATA_PHY_DRV_800mv 0xE0
+#define SATA_PHY_DRV_MASK 0xE0
+
+/* bits 4:3 */
+#define SATA_PREEMP_0 0x00
+#define SATA_PREEMP_1 0x08
+#define SATA_PREEMP_2 0x10
+#define SATA_PREEMP_3 0x18
+#define SATA_PREEMP_MASK 0x18
+
+#define SATA_CMSH1P5 0x04
+
+/* bits 1:0 */
+#define SATA_SLEW_0 0x00
+#define SATA_SLEW_1 0x01
+#define SATA_SLEW_2 0x02
+#define SATA_SLEW_3 0x03
+#define SATA_SLEW_MASK 0x03
+
+#define PHY_CONTROL_3 0x163
+
+/* bits 7:5 */
+#define SAS_PHY_DRV_400mv 0x00
+#define SAS_PHY_DRV_450mv 0x20
+#define SAS_PHY_DRV_500mv 0x40
+#define SAS_PHY_DRV_550mv 0x60
+#define SAS_PHY_DRV_600mv 0x80
+#define SAS_PHY_DRV_650mv 0xA0
+#define SAS_PHY_DRV_725mv 0xC0
+#define SAS_PHY_DRV_800mv 0xE0
+#define SAS_PHY_DRV_MASK 0xE0
+
+/* bits 4:3 */
+#define SAS_PREEMP_0 0x00
+#define SAS_PREEMP_1 0x08
+#define SAS_PREEMP_2 0x10
+#define SAS_PREEMP_3 0x18
+#define SAS_PREEMP_MASK 0x18
+
+#define SAS_CMSH1P5 0x04
+
+/* bits 1:0 */
+#define SAS_SLEW_0 0x00
+#define SAS_SLEW_1 0x01
+#define SAS_SLEW_2 0x02
+#define SAS_SLEW_3 0x03
+#define SAS_SLEW_MASK 0x03
+
+#define PHY_CONTROL_4 0x168
+
+#define PHY_DONE_CAL_TX 0x80
+#define PHY_DONE_CAL_RX 0x40
+#define RX_TERM_LOAD_DIS 0x20
+#define TX_TERM_LOAD_DIS 0x10
+#define AUTO_TERM_CAL_DIS 0x08
+#define PHY_SIGDET_FLTR_EN 0x04
+#define OSC_FREQ 0x02
+#define PHY_START_CAL 0x01
+
+/*
+ * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC)
+ */
+#define PCIX_REG_BASE_ADR 0xB8040000
+
+#define PCIC_VENDOR_ID 0x00
+
+#define PCIC_DEVICE_ID 0x02
+
+#define PCIC_COMMAND 0x04
+
+#define INT_DIS 0x0400
+#define FBB_EN 0x0200 /* ro */
+#define SERR_EN 0x0100
+#define STEP_EN 0x0080 /* ro */
+#define PERR_EN 0x0040
+#define VGA_EN 0x0020 /* ro */
+#define MWI_EN 0x0010
+#define SPC_EN 0x0008
+#define MST_EN 0x0004
+#define MEM_EN 0x0002
+#define IO_EN 0x0001
+
+#define PCIC_STATUS 0x06
+
+#define PERR_DET 0x8000
+#define SERR_GEN 0x4000
+#define MABT_DET 0x2000
+#define TABT_DET 0x1000
+#define TABT_GEN 0x0800
+#define DPERR_DET 0x0100
+#define CAP_LIST 0x0010
+#define INT_STAT 0x0008
+
+#define PCIC_DEVREV_ID 0x08
+
+#define PCIC_CLASS_CODE 0x09
+
+#define PCIC_CACHELINE_SIZE 0x0C
+
+#define PCIC_MBAR0 0x10
+
+#define PCIC_MBAR0_OFFSET 0
+
+#define PCIC_MBAR1 0x18
+
+#define PCIC_MBAR1_OFFSET 2
+
+#define PCIC_IOBAR 0x20
+
+#define PCIC_IOBAR_OFFSET 4
+
+#define PCIC_SUBVENDOR_ID 0x2C
+
+#define PCIC_SUBSYTEM_ID 0x2E
+
+#define PCIX_STATUS 0x44
+#define RCV_SCE 0x20000000
+#define UNEXP_SC 0x00080000
+#define SC_DISCARD 0x00040000
+
+#define ECC_CTRL_STAT 0x48
+#define UNCOR_ECCERR 0x00000008
+
+#define PCIC_PM_CSR 0x5C
+
+#define PWR_STATE_D0 0
+#define PWR_STATE_D1 1 /* not supported */
+#define PWR_STATE_D2 2 /* not supported */
+#define PWR_STATE_D3 3
+
+#define PCIC_BASE1 0x6C /* internal use only */
+
+#define BASE1_RSVD 0xFFFFFFF8
+
+#define PCIC_BASEA 0x70 /* internal use only */
+
+#define BASEA_RSVD 0xFFFFFFC0
+#define BASEA_START 0
+
+#define PCIC_BASEB 0x74 /* internal use only */
+
+#define BASEB_RSVD 0xFFFFFF80
+#define BASEB_IOMAP_MASK 0x7F
+#define BASEB_START 0x80
+
+#define PCIC_BASEC 0x78 /* internal use only */
+
+#define BASEC_RSVD 0xFFFFFFFC
+#define BASEC_MASK 0x03
+#define BASEC_START 0x58
+
+#define PCIC_MBAR_KEY 0x7C /* internal use only */
+
+#define MBAR_KEY_MASK 0xFFFFFFFF
+
+#define PCIC_HSTPCIX_CNTRL 0xA0
+
+#define REWIND_DIS 0x0800
+#define SC_TMR_DIS 0x04000000
+
+#define PCIC_MBAR0_MASK 0xA8
+#define PCIC_MBAR0_SIZE_MASK 0x1FFFE000
+#define PCIC_MBAR0_SIZE_SHIFT 13
+#define PCIC_MBAR0_SIZE(val) \
+ (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT)
+
+#define PCIC_FLASH_MBAR 0xB8
+
+#define PCIC_INTRPT_STAT 0xD4
+
+#define PCIC_TP_CTRL 0xFC
+
+/*
+ * EXSI Registers, Addresss Range: (0x00-0xFC)
+ */
+#define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI
+
+#define EXSICNFGR (EXSI_REG_BASE_ADR + 0x00)
+
+#define OCMINITIALIZED 0x80000000
+#define ASIEN 0x00400000
+#define HCMODE 0x00200000
+#define PCIDEF 0x00100000
+#define COMSTOCK 0x00080000
+#define SEEPROMEND 0x00040000
+#define MSTTIMEN 0x00020000
+#define XREGEX 0x00000200
+#define NVRAMW 0x00000100
+#define NVRAMEX 0x00000080
+#define SRAMW 0x00000040
+#define SRAMEX 0x00000020
+#define FLASHW 0x00000010
+#define FLASHEX 0x00000008
+#define SEEPROMCFG 0x00000004
+#define SEEPROMTYP 0x00000002
+#define SEEPROMEX 0x00000001
+
+
+#define EXSICNTRLR (EXSI_REG_BASE_ADR + 0x04)
+
+#define MODINT_EN 0x00000001
+
+
+#define PMSTATR (EXSI_REG_BASE_ADR + 0x10)
+
+#define FLASHRST 0x00000002
+#define FLASHRDY 0x00000001
+
+
+#define FLCNFGR (EXSI_REG_BASE_ADR + 0x14)
+
+#define FLWEH_MASK 0x30000000
+#define FLWESU_MASK 0x0C000000
+#define FLWEPW_MASK 0x03F00000
+#define FLOEH_MASK 0x000C0000
+#define FLOESU_MASK 0x00030000
+#define FLOEPW_MASK 0x0000FC00
+#define FLCSH_MASK 0x00000300
+#define FLCSSU_MASK 0x000000C0
+#define FLCSPW_MASK 0x0000003F
+
+#define SRCNFGR (EXSI_REG_BASE_ADR + 0x18)
+
+#define SRWEH_MASK 0x30000000
+#define SRWESU_MASK 0x0C000000
+#define SRWEPW_MASK 0x03F00000
+
+#define SROEH_MASK 0x000C0000
+#define SROESU_MASK 0x00030000
+#define SROEPW_MASK 0x0000FC00
+#define SRCSH_MASK 0x00000300
+#define SRCSSU_MASK 0x000000C0
+#define SRCSPW_MASK 0x0000003F
+
+#define NVCNFGR (EXSI_REG_BASE_ADR + 0x1C)
+
+#define NVWEH_MASK 0x30000000
+#define NVWESU_MASK 0x0C000000
+#define NVWEPW_MASK 0x03F00000
+#define NVOEH_MASK 0x000C0000
+#define NVOESU_MASK 0x00030000
+#define NVOEPW_MASK 0x0000FC00
+#define NVCSH_MASK 0x00000300
+#define NVCSSU_MASK 0x000000C0
+#define NVCSPW_MASK 0x0000003F
+
+#define XRCNFGR (EXSI_REG_BASE_ADR + 0x20)
+
+#define XRWEH_MASK 0x30000000
+#define XRWESU_MASK 0x0C000000
+#define XRWEPW_MASK 0x03F00000
+#define XROEH_MASK 0x000C0000
+#define XROESU_MASK 0x00030000
+#define XROEPW_MASK 0x0000FC00
+#define XRCSH_MASK 0x00000300
+#define XRCSSU_MASK 0x000000C0
+#define XRCSPW_MASK 0x0000003F
+
+#define XREGADDR (EXSI_REG_BASE_ADR + 0x24)
+
+#define XRADDRINCEN 0x80000000
+#define XREGADD_MASK 0x007FFFFF
+
+
+#define XREGDATAR (EXSI_REG_BASE_ADR + 0x28)
+
+#define XREGDATA_MASK 0x0000FFFF
+
+#define GPIOOER (EXSI_REG_BASE_ADR + 0x40)
+
+#define GPIOODENR (EXSI_REG_BASE_ADR + 0x44)
+
+#define GPIOINVR (EXSI_REG_BASE_ADR + 0x48)
+
+#define GPIODATAOR (EXSI_REG_BASE_ADR + 0x4C)
+
+#define GPIODATAIR (EXSI_REG_BASE_ADR + 0x50)
+
+#define GPIOCNFGR (EXSI_REG_BASE_ADR + 0x54)
+
+#define GPIO_EXTSRC 0x00000001
+
+#define SCNTRLR (EXSI_REG_BASE_ADR + 0xA0)
+
+#define SXFERDONE 0x00000100
+#define SXFERCNT_MASK 0x000000E0
+#define SCMDTYP_MASK 0x0000001C
+#define SXFERSTART 0x00000002
+#define SXFEREN 0x00000001
+
+#define SRATER (EXSI_REG_BASE_ADR + 0xA4)
+
+#define SADDRR (EXSI_REG_BASE_ADR + 0xA8)
+
+#define SADDR_MASK 0x0000FFFF
+
+#define SDATAOR (EXSI_REG_BASE_ADR + 0xAC)
+
+#define SDATAOR0 (EXSI_REG_BASE_ADR + 0xAC)
+#define SDATAOR1 (EXSI_REG_BASE_ADR + 0xAD)
+#define SDATAOR2 (EXSI_REG_BASE_ADR + 0xAE)
+#define SDATAOR3 (EXSI_REG_BASE_ADR + 0xAF)
+
+#define SDATAIR (EXSI_REG_BASE_ADR + 0xB0)
+
+#define SDATAIR0 (EXSI_REG_BASE_ADR + 0xB0)
+#define SDATAIR1 (EXSI_REG_BASE_ADR + 0xB1)
+#define SDATAIR2 (EXSI_REG_BASE_ADR + 0xB2)
+#define SDATAIR3 (EXSI_REG_BASE_ADR + 0xB3)
+
+#define ASISTAT0R (EXSI_REG_BASE_ADR + 0xD0)
+#define ASIFMTERR 0x00000400
+#define ASISEECHKERR 0x00000200
+#define ASIERR 0x00000100
+
+#define ASISTAT1R (EXSI_REG_BASE_ADR + 0xD4)
+#define CHECKSUM_MASK 0x0000FFFF
+
+#define ASIERRADDR (EXSI_REG_BASE_ADR + 0xD8)
+#define ASIERRDATAR (EXSI_REG_BASE_ADR + 0xDC)
+#define ASIERRSTATR (EXSI_REG_BASE_ADR + 0xE0)
+#define CPI2ASIBYTECNT_MASK 0x00070000
+#define CPI2ASIBYTEEN_MASK 0x0000F000
+#define CPI2ASITARGERR_MASK 0x00000F00
+#define CPI2ASITARGMID_MASK 0x000000F0
+#define CPI2ASIMSTERR_MASK 0x0000000F
+
+/*
+ * XSRAM, External SRAM (DWord and any BE pattern accessible)
+ */
+#define XSRAM_REG_BASE_ADDR 0xB8100000
+#define XSRAM_SIZE 0x100000
+
+/*
+ * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF).
+ */
+#define NVRAM_REG_BASE_ADR 0xBF800000
+#define NVRAM_MAX_BASE_ADR 0x003FFFFF
+
+/* OCM base address */
+#define OCM_BASE_ADDR 0xA0000000
+#define OCM_MAX_SIZE 0x20000
+
+/*
+ * Sequencers (Central and Link) Scratch RAM page definitions.
+ */
+
+/*
+ * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024
+ * byte memory. It is dword accessible and has byte parity
+ * protection. The CSEQ accesses it in 32 byte windows, either as mode
+ * dependent or mode independent memory. Each mode has 96 bytes,
+ * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of
+ * Mode Independent memory (four 32 byte pages 3-7). Note that mode
+ * dependent scratch memory, Mode 8, page 0-3 overlaps mode
+ * independent scratch memory, pages 0-3.
+ * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and
+ * 128 bytes in mode 8,
+ * - 259 bytes of mode independent scratch, common to modes 0-15.
+ *
+ * Sequencer scratch RAM is 1024 bytes. This scratch memory is
+ * divided into mode dependent and mode independent scratch with this
+ * memory further subdivided into pages of size 32 bytes. There are 5
+ * pages (160 bytes) of mode independent scratch and 3 pages of
+ * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages
+ * 0-2 dependent scratch overlap with pages 0-2 of mode independent
+ * scratch memory.
+ *
+ * The host accesses this scratch in a different manner from the
+ * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE
+ * and CMnSCRPAGE to access the scratch memory. A flat mapping of the
+ * scratch memory is avaliable for software convenience and to prevent
+ * corruption while the sequencer is running. This memory is mapped
+ * onto addresses 800h - BFFh, total of 400h bytes.
+ *
+ * These addresses are mapped as follows:
+ *
+ * 800h-83Fh Mode Dependent Scratch Mode 0 Pages 0-1
+ * 840h-87Fh Mode Dependent Scratch Mode 1 Pages 0-1
+ * 880h-8BFh Mode Dependent Scratch Mode 2 Pages 0-1
+ * 8C0h-8FFh Mode Dependent Scratch Mode 3 Pages 0-1
+ * 900h-93Fh Mode Dependent Scratch Mode 4 Pages 0-1
+ * 940h-97Fh Mode Dependent Scratch Mode 5 Pages 0-1
+ * 980h-9BFh Mode Dependent Scratch Mode 6 Pages 0-1
+ * 9C0h-9FFh Mode Dependent Scratch Mode 7 Pages 0-1
+ * A00h-A5Fh Mode Dependent Scratch Mode 8 Pages 0-2
+ * Mode Independent Scratch Pages 0-2
+ * A60h-A7Fh Mode Dependent Scratch Mode 8 Page 3
+ * Mode Independent Scratch Page 3
+ * A80h-AFFh Mode Independent Scratch Pages 4-7
+ * B00h-B1Fh Mode Dependent Scratch Mode 0 Page 2
+ * B20h-B3Fh Mode Dependent Scratch Mode 1 Page 2
+ * B40h-B5Fh Mode Dependent Scratch Mode 2 Page 2
+ * B60h-B7Fh Mode Dependent Scratch Mode 3 Page 2
+ * B80h-B9Fh Mode Dependent Scratch Mode 4 Page 2
+ * BA0h-BBFh Mode Dependent Scratch Mode 5 Page 2
+ * BC0h-BDFh Mode Dependent Scratch Mode 6 Page 2
+ * BE0h-BFFh Mode Dependent Scratch Mode 7 Page 2
+ */
+
+/* General macros */
+#define CSEQ_PAGE_SIZE 32 /* Scratch page size (in bytes) */
+
+/* All macros start with offsets from base + 0x800 (CMAPPEDSCR).
+ * Mode dependent scratch page 0, mode 0.
+ * For modes 1-7 you have to do arithmetic. */
+#define CSEQ_LRM_SAVE_SINDEX (CMAPPEDSCR + 0x0000)
+#define CSEQ_LRM_SAVE_SCBPTR (CMAPPEDSCR + 0x0002)
+#define CSEQ_Q_LINK_HEAD (CMAPPEDSCR + 0x0004)
+#define CSEQ_Q_LINK_TAIL (CMAPPEDSCR + 0x0006)
+#define CSEQ_LRM_SAVE_SCRPAGE (CMAPPEDSCR + 0x0008)
+
+/* Mode dependent scratch page 0 mode 8 macros. */
+#define CSEQ_RET_ADDR (CMAPPEDSCR + 0x0200)
+#define CSEQ_RET_SCBPTR (CMAPPEDSCR + 0x0202)
+#define CSEQ_SAVE_SCBPTR (CMAPPEDSCR + 0x0204)
+#define CSEQ_EMPTY_TRANS_CTX (CMAPPEDSCR + 0x0206)
+#define CSEQ_RESP_LEN (CMAPPEDSCR + 0x0208)
+#define CSEQ_TMF_SCBPTR (CMAPPEDSCR + 0x020A)
+#define CSEQ_GLOBAL_PREV_SCB (CMAPPEDSCR + 0x020C)
+#define CSEQ_GLOBAL_HEAD (CMAPPEDSCR + 0x020E)
+#define CSEQ_CLEAR_LU_HEAD (CMAPPEDSCR + 0x0210)
+#define CSEQ_TMF_OPCODE (CMAPPEDSCR + 0x0212)
+#define CSEQ_SCRATCH_FLAGS (CMAPPEDSCR + 0x0213)
+#define CSEQ_HSB_SITE (CMAPPEDSCR + 0x021A)
+#define CSEQ_FIRST_INV_SCB_SITE (CMAPPEDSCR + 0x021C)
+#define CSEQ_FIRST_INV_DDB_SITE (CMAPPEDSCR + 0x021E)
+
+/* Mode dependent scratch page 1 mode 8 macros. */
+#define CSEQ_LUN_TO_CLEAR (CMAPPEDSCR + 0x0220)
+#define CSEQ_LUN_TO_CHECK (CMAPPEDSCR + 0x0228)
+
+/* Mode dependent scratch page 2 mode 8 macros */
+#define CSEQ_HQ_NEW_POINTER (CMAPPEDSCR + 0x0240)
+#define CSEQ_HQ_DONE_BASE (CMAPPEDSCR + 0x0248)
+#define CSEQ_HQ_DONE_POINTER (CMAPPEDSCR + 0x0250)
+#define CSEQ_HQ_DONE_PASS (CMAPPEDSCR + 0x0254)
+
+/* Mode independent scratch page 4 macros. */
+#define CSEQ_Q_EXE_HEAD (CMAPPEDSCR + 0x0280)
+#define CSEQ_Q_EXE_TAIL (CMAPPEDSCR + 0x0282)
+#define CSEQ_Q_DONE_HEAD (CMAPPEDSCR + 0x0284)
+#define CSEQ_Q_DONE_TAIL (CMAPPEDSCR + 0x0286)
+#define CSEQ_Q_SEND_HEAD (CMAPPEDSCR + 0x0288)
+#define CSEQ_Q_SEND_TAIL (CMAPPEDSCR + 0x028A)
+#define CSEQ_Q_DMA2CHIM_HEAD (CMAPPEDSCR + 0x028C)
+#define CSEQ_Q_DMA2CHIM_TAIL (CMAPPEDSCR + 0x028E)
+#define CSEQ_Q_COPY_HEAD (CMAPPEDSCR + 0x0290)
+#define CSEQ_Q_COPY_TAIL (CMAPPEDSCR + 0x0292)
+#define CSEQ_REG0 (CMAPPEDSCR + 0x0294)
+#define CSEQ_REG1 (CMAPPEDSCR + 0x0296)
+#define CSEQ_REG2 (CMAPPEDSCR + 0x0298)
+#define CSEQ_LINK_CTL_Q_MAP (CMAPPEDSCR + 0x029C)
+#define CSEQ_MAX_CSEQ_MODE (CMAPPEDSCR + 0x029D)
+#define CSEQ_FREE_LIST_HACK_COUNT (CMAPPEDSCR + 0x029E)
+
+/* Mode independent scratch page 5 macros. */
+#define CSEQ_EST_NEXUS_REQ_QUEUE (CMAPPEDSCR + 0x02A0)
+#define CSEQ_EST_NEXUS_REQ_COUNT (CMAPPEDSCR + 0x02A8)
+#define CSEQ_Q_EST_NEXUS_HEAD (CMAPPEDSCR + 0x02B0)
+#define CSEQ_Q_EST_NEXUS_TAIL (CMAPPEDSCR + 0x02B2)
+#define CSEQ_NEED_EST_NEXUS_SCB (CMAPPEDSCR + 0x02B4)
+#define CSEQ_EST_NEXUS_REQ_HEAD (CMAPPEDSCR + 0x02B6)
+#define CSEQ_EST_NEXUS_REQ_TAIL (CMAPPEDSCR + 0x02B7)
+#define CSEQ_EST_NEXUS_SCB_OFFSET (CMAPPEDSCR + 0x02B8)
+
+/* Mode independent scratch page 6 macros. */
+#define CSEQ_INT_ROUT_RET_ADDR0 (CMAPPEDSCR + 0x02C0)
+#define CSEQ_INT_ROUT_RET_ADDR1 (CMAPPEDSCR + 0x02C2)
+#define CSEQ_INT_ROUT_SCBPTR (CMAPPEDSCR + 0x02C4)
+#define CSEQ_INT_ROUT_MODE (CMAPPEDSCR + 0x02C6)
+#define CSEQ_ISR_SCRATCH_FLAGS (CMAPPEDSCR + 0x02C7)
+#define CSEQ_ISR_SAVE_SINDEX (CMAPPEDSCR + 0x02C8)
+#define CSEQ_ISR_SAVE_DINDEX (CMAPPEDSCR + 0x02CA)
+#define CSEQ_Q_MONIRTT_HEAD (CMAPPEDSCR + 0x02D0)
+#define CSEQ_Q_MONIRTT_TAIL (CMAPPEDSCR + 0x02D2)
+#define CSEQ_FREE_SCB_MASK (CMAPPEDSCR + 0x02D5)
+#define CSEQ_BUILTIN_FREE_SCB_HEAD (CMAPPEDSCR + 0x02D6)
+#define CSEQ_BUILTIN_FREE_SCB_TAIL (CMAPPEDSCR + 0x02D8)
+#define CSEQ_EXTENDED_FREE_SCB_HEAD (CMAPPEDSCR + 0x02DA)
+#define CSEQ_EXTENDED_FREE_SCB_TAIL (CMAPPEDSCR + 0x02DC)
+
+/* Mode independent scratch page 7 macros. */
+#define CSEQ_EMPTY_REQ_QUEUE (CMAPPEDSCR + 0x02E0)
+#define CSEQ_EMPTY_REQ_COUNT (CMAPPEDSCR + 0x02E8)
+#define CSEQ_Q_EMPTY_HEAD (CMAPPEDSCR + 0x02F0)
+#define CSEQ_Q_EMPTY_TAIL (CMAPPEDSCR + 0x02F2)
+#define CSEQ_NEED_EMPTY_SCB (CMAPPEDSCR + 0x02F4)
+#define CSEQ_EMPTY_REQ_HEAD (CMAPPEDSCR + 0x02F6)
+#define CSEQ_EMPTY_REQ_TAIL (CMAPPEDSCR + 0x02F7)
+#define CSEQ_EMPTY_SCB_OFFSET (CMAPPEDSCR + 0x02F8)
+#define CSEQ_PRIMITIVE_DATA (CMAPPEDSCR + 0x02FA)
+#define CSEQ_TIMEOUT_CONST (CMAPPEDSCR + 0x02FC)
+
+/***************************************************************************
+* Link m Sequencer scratch RAM is 512 bytes.
+* This scratch memory is divided into mode dependent and mode
+* independent scratch with this memory further subdivided into
+* pages of size 32 bytes. There are 4 pages (128 bytes) of
+* mode independent scratch and 4 pages of dependent scratch
+* memory for modes 0-2 (384 bytes).
+*
+* The host accesses this scratch in a different manner from the
+* link sequencer. The sequencer has to use LSEQ registers
+* LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat
+* mapping of the scratch memory is avaliable for software
+* convenience and to prevent corruption while the sequencer is
+* running. This memory is mapped onto addresses 800h - 9FFh.
+*
+* These addresses are mapped as follows:
+*
+* 800h-85Fh Mode Dependent Scratch Mode 0 Pages 0-2
+* 860h-87Fh Mode Dependent Scratch Mode 0 Page 3
+* Mode Dependent Scratch Mode 5 Page 0
+* 880h-8DFh Mode Dependent Scratch Mode 1 Pages 0-2
+* 8E0h-8FFh Mode Dependent Scratch Mode 1 Page 3
+* Mode Dependent Scratch Mode 5 Page 1
+* 900h-95Fh Mode Dependent Scratch Mode 2 Pages 0-2
+* 960h-97Fh Mode Dependent Scratch Mode 2 Page 3
+* Mode Dependent Scratch Mode 5 Page 2
+* 980h-9DFh Mode Independent Scratch Pages 0-3
+* 9E0h-9FFh Mode Independent Scratch Page 3
+* Mode Dependent Scratch Mode 5 Page 3
+*
+****************************************************************************/
+/* General macros */
+#define LSEQ_MODE_SCRATCH_SIZE 0x80 /* Size of scratch RAM per mode */
+#define LSEQ_PAGE_SIZE 0x20 /* Scratch page size (in bytes) */
+#define LSEQ_MODE5_PAGE0_OFFSET 0x60
+
+/* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */
+/* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */
+#define LmSEQ_RET_ADDR(LinkNum) (LmSCRATCH(LinkNum) + 0x0000)
+#define LmSEQ_REG0_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0002)
+#define LmSEQ_MODE_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0004)
+
+/* Mode flag macros (byte 0) */
+#define SAS_SAVECTX_OCCURRED 0x80
+#define SAS_OOBSVC_OCCURRED 0x40
+#define SAS_OOB_DEVICE_PRESENT 0x20
+#define SAS_CFGHDR_OCCURRED 0x10
+#define SAS_RCV_INTS_ARE_DISABLED 0x08
+#define SAS_OOB_HOT_PLUG_CNCT 0x04
+#define SAS_AWAIT_OPEN_CONNECTION 0x02
+#define SAS_CFGCMPLT_OCCURRED 0x01
+
+/* Mode flag macros (byte 1) */
+#define SAS_RLSSCB_OCCURRED 0x80
+#define SAS_FORCED_HEADER_MISS 0x40
+
+#define LmSEQ_RET_ADDR2(LinkNum) (LmSCRATCH(LinkNum) + 0x0006)
+#define LmSEQ_RET_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0008)
+#define LmSEQ_OPCODE_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000B)
+#define LmSEQ_DATA_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000C)
+
+/* Mode dependent scratch page 0 macros for mode 0 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_FIRST_INV_DDB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x000E)
+#define LmSEQ_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0010)
+#define LmSEQ_RESP_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x0012)
+#define LmSEQ_FIRST_INV_SCB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x0014)
+#define LmSEQ_INTEN_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0016)
+#define LmSEQ_LINK_RST_FRM_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x001A)
+#define LmSEQ_LINK_RST_PROTOCOL(LinkNum) (LmSCRATCH(LinkNum) + 0x001B)
+#define LmSEQ_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x001C)
+#define LmSEQ_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x001D)
+#define LmSEQ_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x001E)
+
+/* Mode dependent scratch page 0 macros for mode 1 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_Q_XMIT_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x008E)
+#define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0090)
+#define LmSEQ_INI_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0092)
+#define LmSEQ_FAILED_OPEN_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009A)
+#define LmSEQ_XMIT_REQUEST_TYPE(LinkNum) (LmSCRATCH(LinkNum) + 0x009B)
+#define LmSEQ_M1_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009C)
+#define LmSEQ_M1_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x009D)
+#define LmSEQ_M1_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x009E)
+
+/* Mode dependent scratch page 0 macros for mode 2 (non-common) */
+#define LmSEQ_PORT_COUNTER(LinkNum) (LmSCRATCH(LinkNum) + 0x010E)
+#define LmSEQ_PM_TABLE_PTR(LinkNum) (LmSCRATCH(LinkNum) + 0x0110)
+#define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0112)
+#define LmSEQ_IP_BITL(LinkNum) (LmSCRATCH(LinkNum) + 0x0114)
+#define LmSEQ_COPY_SMP_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0116)
+#define LmSEQ_P0M2_OFFS1AH(LinkNum) (LmSCRATCH(LinkNum) + 0x011A)
+
+/* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */
+/* Absolute offsets */
+#define LmSEQ_SAVED_OOB_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x006E)
+#define LmSEQ_SAVED_OOB_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x006F)
+#define LmSEQ_Q_LINK_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0070)
+#define LmSEQ_LINK_RST_ERR(LinkNum) (LmSCRATCH(LinkNum) + 0x0072)
+#define LmSEQ_SAVED_OOB_SIGNALS(LinkNum) (LmSCRATCH(LinkNum) + 0x0073)
+#define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074)
+#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075)
+#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076)
+#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A)
+#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C)
+#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E)
+
+/* Mode dependent scratch page 1, mode 0 and mode 1 */
+#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020)
+#define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0030)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x00A0)
+#define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x00B0)
+
+/* Mode dependent scratch page 1 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_INVALID_DWORD_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0120)
+#define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0124)
+#define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0128)
+
+/* Mode dependent scratch page 1 macros for mode 4/5 */
+#define LmSEQ_FRAME_TYPE_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E0)
+#define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E1)
+#define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4)
+#define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E5)
+#define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00EB)
+#define LmSEQ_TAG_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00F0)
+#define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x00F2)
+#define LmSEQ_DATA_OFFSET(LinkNum) (LmSCRATCH(LinkNum) + 0x00F4)
+
+/* Mode dependent scratch page 2 macros for mode 0 */
+/* Absolute offsets */
+#define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0040)
+#define LmSEQ_DEVICE_BITS(LinkNum) (LmSCRATCH(LinkNum) + 0x005B)
+#define LmSEQ_SDB_DDB(LinkNum) (LmSCRATCH(LinkNum) + 0x005C)
+#define LmSEQ_SDB_NUM_TAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x005E)
+#define LmSEQ_SDB_CURR_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x005F)
+
+/* Mode dependent scratch page 2 macros for mode 1 */
+/* Absolute offsets */
+/* byte 0 bits 1-0 are domain select. */
+#define LmSEQ_TX_ID_ADDR_FRAME(LinkNum) (LmSCRATCH(LinkNum) + 0x00C0)
+#define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00C8)
+#define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00CC)
+#define LmSEQ_LAST_LOADED_SG_EL(LinkNum) (LmSCRATCH(LinkNum) + 0x00D4)
+
+/* Mode dependent scratch page 2 macros for mode 2 */
+/* Absolute offsets */
+#define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140)
+#define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0144)
+#define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0148)
+#define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x014C)
+#define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \
+ (LmSCRATCH(LinkNum) + 0x0150)
+#define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0154)
+
+/* Mode dependent scratch page 2 macros for mode 5 */
+#define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0160)
+#define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0164)
+#define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0168)
+#define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x016C)
+
+/* Mode dependent scratch page 3 macros for modes 0 and 1 */
+/* None defined */
+
+/* Mode dependent scratch page 3 macros for modes 2 and 5 */
+/* None defined */
+
+/* Mode Independent Scratch page 0 macros. */
+#define LmSEQ_Q_TGTXFR_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0180)
+#define LmSEQ_Q_TGTXFR_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x0182)
+#define LmSEQ_LINK_NUMBER(LinkNum) (LmSCRATCH(LinkNum) + 0x0186)
+#define LmSEQ_SCRATCH_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0187)
+/*
+ * Currently only bit 0, SAS_DWSAQD, is used.
+ */
+#define SAS_DWSAQD 0x01 /*
+ * DWSSTATUS: DWSAQD
+ * bit las read in ISR.
+ */
+#define LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188)
+/* Connection states (byte 0) */
+#define SAS_WE_OPENED_CS 0x01
+#define SAS_DEVICE_OPENED_CS 0x02
+#define SAS_WE_SENT_DONE_CS 0x04
+#define SAS_DEVICE_SENT_DONE_CS 0x08
+#define SAS_WE_SENT_CLOSE_CS 0x10
+#define SAS_DEVICE_SENT_CLOSE_CS 0x20
+#define SAS_WE_SENT_BREAK_CS 0x40
+#define SAS_DEVICE_SENT_BREAK_CS 0x80
+/* Connection states (byte 1) */
+#define SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS 0x01
+#define SAS_AIP_RECEIVED_CS 0x02
+#define SAS_CREDIT_TIMEOUT_OCCURRED_CS 0x04
+#define SAS_ACKNAK_TIMEOUT_OCCURRED_CS 0x08
+#define SAS_SMPRSP_TIMEOUT_OCCURRED_CS 0x10
+#define SAS_DONE_TIMEOUT_OCCURRED_CS 0x20
+/* Connection states (byte 2) */
+#define SAS_SMP_RESPONSE_RECEIVED_CS 0x01
+#define SAS_INTLK_TIMEOUT_OCCURRED_CS 0x02
+#define SAS_DEVICE_SENT_DMAT_CS 0x04
+#define SAS_DEVICE_SENT_SYNCSRST_CS 0x08
+#define SAS_CLEARING_AFFILIATION_CS 0x20
+#define SAS_RXTASK_ACTIVE_CS 0x40
+#define SAS_TXTASK_ACTIVE_CS 0x80
+/* Connection states (byte 3) */
+#define SAS_PHY_LOSS_OF_SIGNAL_CS 0x01
+#define SAS_DWS_TIMER_EXPIRED_CS 0x02
+#define SAS_LINK_RESET_NOT_COMPLETE_CS 0x04
+#define SAS_PHY_DISABLED_CS 0x08
+#define SAS_LINK_CTL_TASK_ACTIVE_CS 0x10
+#define SAS_PHY_EVENT_TASK_ACTIVE_CS 0x20
+#define SAS_DEVICE_SENT_ID_FRAME_CS 0x40
+#define SAS_DEVICE_SENT_REG_FIS_CS 0x40
+#define SAS_DEVICE_SENT_HARD_RESET_CS 0x80
+#define SAS_PHY_IS_DOWN_FLAGS (SAS_PHY_LOSS_OF_SIGNAL_CS|\
+ SAS_DWS_TIMER_EXPIRED_CS |\
+ SAS_LINK_RESET_NOT_COMPLETE_CS|\
+ SAS_PHY_DISABLED_CS)
+
+#define SAS_LINK_CTL_PHY_EVENT_FLAGS (SAS_LINK_CTL_TASK_ACTIVE_CS |\
+ SAS_PHY_EVENT_TASK_ACTIVE_CS |\
+ SAS_DEVICE_SENT_ID_FRAME_CS |\
+ SAS_DEVICE_SENT_HARD_RESET_CS)
+
+#define LmSEQ_CONCTL(LinkNum) (LmSCRATCH(LinkNum) + 0x018C)
+#define LmSEQ_CONSTAT(LinkNum) (LmSCRATCH(LinkNum) + 0x018E)
+#define LmSEQ_CONNECTION_MODES(LinkNum) (LmSCRATCH(LinkNum) + 0x018F)
+#define LmSEQ_REG1_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0192)
+#define LmSEQ_REG2_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0194)
+#define LmSEQ_REG3_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0196)
+#define LmSEQ_REG0_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0198)
+
+/* Mode independent scratch page 1 macros. */
+#define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A0)
+#define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A2)
+#define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01A4)
+#define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01A6)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A8)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A9)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum) (LmSCRATCH(LinkNum) + 0x01AA)
+#define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum) (LmSCRATCH(LinkNum) + 0x01AB)
+#define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01AC)
+#define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AD)
+#define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AE)
+#define LmSEQ_TIMEOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01B8)
+#define LmSEQ_ISR_SAVE_SINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BC)
+#define LmSEQ_ISR_SAVE_DINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BE)
+
+/* Mode independent scratch page 2 macros. */
+#define LmSEQ_EMPTY_SCB_PTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C0)
+#define LmSEQ_EMPTY_SCB_PTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C2)
+#define LmSEQ_EMPTY_SCB_PTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01C4)
+#define LmSEQ_EMPTY_SCB_PTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01C6)
+#define LmSEQ_EMPTY_SCB_OPCD0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C8)
+#define LmSEQ_EMPTY_SCB_OPCD1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C9)
+#define LmSEQ_EMPTY_SCB_OPCD2(LinkNum) (LmSCRATCH(LinkNum) + 0x01CA)
+#define LmSEQ_EMPTY_SCB_OPCD3(LinkNum) (LmSCRATCH(LinkNum) + 0x01CB)
+#define LmSEQ_EMPTY_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01CC)
+#define LmSEQ_EMPTY_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CD)
+#define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CE)
+#define LmSEQ_ATA_SCR_REGS(LinkNum) (LmSCRATCH(LinkNum) + 0x01D4)
+
+/* Mode independent scratch page 3 macros. */
+#define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01E0)
+#define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E4)
+#define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E8)
+#define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01EC)
+#define LmSEQ_RCV_FIS_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F0)
+#define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F4)
+#define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F8)
+#define LmSEQ_SMP_RCV_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01FC)
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h
new file mode 100644
index 00000000000..64d23171234
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_sas.h
@@ -0,0 +1,785 @@
+/*
+ * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_SAS_H_
+#define _AIC94XX_SAS_H_
+
+#include <scsi/libsas.h>
+
+/* ---------- DDBs ---------- */
+/* DDBs are device descriptor blocks which describe a device in the
+ * domain that this sequencer can maintain low-level connections for
+ * us. They are be 64 bytes.
+ */
+
+struct asd_ddb_ssp_smp_target_port {
+ u8 conn_type; /* byte 0 */
+#define DDB_TP_CONN_TYPE 0x81 /* Initiator port and addr frame type 0x01 */
+
+ u8 conn_rate;
+ __be16 init_conn_tag;
+ u8 dest_sas_addr[8]; /* bytes 4-11 */
+
+ __le16 send_queue_head;
+ u8 sq_suspended;
+ u8 ddb_type; /* DDB_TYPE_TARGET */
+#define DDB_TYPE_UNUSED 0xFF
+#define DDB_TYPE_TARGET 0xFE
+#define DDB_TYPE_INITIATOR 0xFD
+#define DDB_TYPE_PM_PORT 0xFC
+
+ __le16 _r_a;
+ __be16 awt_def;
+
+ u8 compat_features; /* byte 20 */
+ u8 pathway_blocked_count;
+ __be16 arb_wait_time;
+ __be32 more_compat_features; /* byte 24 */
+
+ u8 conn_mask;
+ u8 flags; /* concurrent conn:2,2 and open:0(1) */
+#define CONCURRENT_CONN_SUPP 0x04
+#define OPEN_REQUIRED 0x01
+
+ u16 _r_b;
+ __le16 exec_queue_tail;
+ __le16 send_queue_tail;
+ __le16 sister_ddb;
+
+ __le16 _r_c;
+
+ u8 max_concurrent_conn;
+ u8 num_concurrent_conn;
+ u8 num_contexts;
+
+ u8 _r_d;
+
+ __le16 active_task_count;
+
+ u8 _r_e[9];
+
+ u8 itnl_reason; /* I_T nexus loss reason */
+
+ __le16 _r_f;
+
+ __le16 itnl_timeout;
+#define ITNL_TIMEOUT_CONST 0x7D0 /* 2 seconds */
+
+ __le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+struct asd_ddb_stp_sata_target_port {
+ u8 conn_type; /* byte 0 */
+ u8 conn_rate;
+ __be16 init_conn_tag;
+ u8 dest_sas_addr[8]; /* bytes 4-11 */
+
+ __le16 send_queue_head;
+ u8 sq_suspended;
+ u8 ddb_type; /* DDB_TYPE_TARGET */
+
+ __le16 _r_a;
+
+ __be16 awt_def;
+ u8 compat_features; /* byte 20 */
+ u8 pathway_blocked_count;
+ __be16 arb_wait_time;
+ __be32 more_compat_features; /* byte 24 */
+
+ u8 conn_mask;
+ u8 flags; /* concurrent conn:2,2 and open:0(1) */
+#define SATA_MULTIPORT 0x80
+#define SUPPORTS_AFFIL 0x40
+#define STP_AFFIL_POL 0x20
+
+ u8 _r_b;
+ u8 flags2; /* STP close policy:0 */
+#define STP_CL_POL_NO_TX 0x00
+#define STP_CL_POL_BTW_CMDS 0x01
+
+ __le16 exec_queue_tail;
+ __le16 send_queue_tail;
+ __le16 sister_ddb;
+ __le16 ata_cmd_scbptr;
+ __le32 sata_tag_alloc_mask;
+ __le16 active_task_count;
+ __le16 _r_c;
+ __le32 sata_sactive;
+ u8 num_sata_tags;
+ u8 sata_status;
+ u8 sata_ending_status;
+ u8 itnl_reason; /* I_T nexus loss reason */
+ __le16 ncq_data_scb_ptr;
+ __le16 itnl_timeout;
+ __le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_init_port, describes the device descriptor block
+ * of an initiator port (when the sequencer is operating in target mode).
+ * Bytes [0,11] and [20,27] are from the OPEN address frame.
+ * The sequencer allocates an initiator port DDB entry.
+ */
+struct asd_ddb_init_port {
+ u8 conn_type; /* byte 0 */
+ u8 conn_rate;
+ __be16 init_conn_tag; /* BE */
+ u8 dest_sas_addr[8];
+ __le16 send_queue_head; /* LE, byte 12 */
+ u8 sq_suspended;
+ u8 ddb_type; /* DDB_TYPE_INITIATOR */
+ __le16 _r_a;
+ __be16 awt_def; /* BE */
+ u8 compat_features;
+ u8 pathway_blocked_count;
+ __be16 arb_wait_time; /* BE */
+ __be32 more_compat_features; /* BE */
+ u8 conn_mask;
+ u8 flags; /* == 5 */
+ u16 _r_b;
+ __le16 exec_queue_tail; /* execution queue tail */
+ __le16 send_queue_tail;
+ __le16 sister_ddb;
+ __le16 init_resp_timeout; /* initiator response timeout */
+ __le32 _r_c;
+ __le16 active_tasks; /* active task count */
+ __le16 init_list; /* initiator list link pointer */
+ __le32 _r_d;
+ u8 max_conn_to[3]; /* from Conn-Disc mode page, in us, LE */
+ u8 itnl_reason; /* I_T nexus loss reason */
+ __le16 bus_inact_to; /* from Conn-Disc mode page, in 100 us, LE */
+ __le16 itnl_to; /* from the Protocol Specific Port Ctrl MP */
+ __le32 itnl_timestamp;
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_tag, describes a look-up table to be used
+ * by the sequencers. SATA II, IDENTIFY DEVICE data, word 76, bit 8:
+ * NCQ support. This table is used by the sequencers to find the
+ * corresponding SCB, given a SATA II tag value.
+ */
+struct asd_ddb_sata_tag {
+ __le16 scb_pointer[32];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_pm_table, describes a port number to
+ * connection handle look-up table. SATA targets attached to a port
+ * multiplier require a 4-bit port number value. There is one DDB
+ * entry of this type for each SATA port multiplier (sister DDB).
+ * Given a SATA PM port number, this table gives us the SATA PM Port
+ * DDB of the SATA port multiplier port (i.e. the SATA target
+ * discovered on the port).
+ */
+struct asd_ddb_sata_pm_table {
+ __le16 ddb_pointer[16];
+ __le16 _r_a[16];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_sata_pm_port, describes the SATA port multiplier
+ * port format DDB.
+ */
+struct asd_ddb_sata_pm_port {
+ u8 _r_a[15];
+ u8 ddb_type;
+ u8 _r_b[13];
+ u8 pm_port_flags;
+#define PM_PORT_MASK 0xF0
+#define PM_PORT_SET 0x02
+ u8 _r_c[6];
+ __le16 sister_ddb;
+ __le16 ata_cmd_scbptr;
+ __le32 sata_tag_alloc_mask;
+ __le16 active_task_count;
+ __le16 parent_ddb;
+ __le32 sata_sactive;
+ u8 num_sata_tags;
+ u8 sata_status;
+ u8 sata_ending_status;
+ u8 _r_d[9];
+} __attribute__ ((packed));
+
+/* This struct asd_ddb_seq_shared, describes a DDB shared by the
+ * central and link sequencers. port_map_by_links is indexed phy
+ * number [0,7]; each byte is a bit mask of all the phys that are in
+ * the same port as the indexed phy.
+ */
+struct asd_ddb_seq_shared {
+ __le16 q_free_ddb_head;
+ __le16 q_free_ddb_tail;
+ __le16 q_free_ddb_cnt;
+ __le16 q_used_ddb_head;
+ __le16 q_used_ddb_tail;
+ __le16 shared_mem_lock;
+ __le16 smp_conn_tag;
+ __le16 est_nexus_buf_cnt;
+ __le16 est_nexus_buf_thresh;
+ u32 _r_a;
+ u8 settable_max_contexts;
+ u8 _r_b[23];
+ u8 conn_not_active;
+ u8 phy_is_up;
+ u8 _r_c[8];
+ u8 port_map_by_links[8];
+} __attribute__ ((packed));
+
+/* ---------- SG Element ---------- */
+
+/* This struct sg_el, describes the hardware scatter gather buffer
+ * element. All entries are little endian. In an SCB, there are 2 of
+ * this, plus one more, called a link element of this indicating a
+ * sublist if needed.
+ *
+ * A link element has only the bus address set and the flags (DS) bit
+ * valid. The bus address points to the start of the sublist.
+ *
+ * If a sublist is needed, then that sublist should also include the 2
+ * sg_el embedded in the SCB, in which case next_sg_offset is 32,
+ * since sizeof(sg_el) = 16; EOS should be 1 and EOL 0 in this case.
+ */
+struct sg_el {
+ __le64 bus_addr;
+ __le32 size;
+ __le16 _r;
+ u8 next_sg_offs;
+ u8 flags;
+#define ASD_SG_EL_DS_MASK 0x30
+#define ASD_SG_EL_DS_OCM 0x10
+#define ASD_SG_EL_DS_HM 0x00
+#define ASD_SG_EL_LIST_MASK 0xC0
+#define ASD_SG_EL_LIST_EOL 0x40
+#define ASD_SG_EL_LIST_EOS 0x80
+} __attribute__ ((packed));
+
+/* ---------- SCBs ---------- */
+
+/* An SCB (sequencer control block) is comprised of a common header
+ * and a task part, for a total of 128 bytes. All fields are in LE
+ * order, unless otherwise noted.
+ */
+
+/* This struct scb_header, defines the SCB header format.
+ */
+struct scb_header {
+ __le64 next_scb;
+ __le16 index; /* transaction context */
+ u8 opcode;
+} __attribute__ ((packed));
+
+/* SCB opcodes: Execution queue
+ */
+#define INITIATE_SSP_TASK 0x00
+#define INITIATE_LONG_SSP_TASK 0x01
+#define INITIATE_BIDIR_SSP_TASK 0x02
+#define ABORT_TASK 0x03
+#define INITIATE_SSP_TMF 0x04
+#define SSP_TARG_GET_DATA 0x05
+#define SSP_TARG_GET_DATA_GOOD 0x06
+#define SSP_TARG_SEND_RESP 0x07
+#define QUERY_SSP_TASK 0x08
+#define INITIATE_ATA_TASK 0x09
+#define INITIATE_ATAPI_TASK 0x0a
+#define CONTROL_ATA_DEV 0x0b
+#define INITIATE_SMP_TASK 0x0c
+#define SMP_TARG_SEND_RESP 0x0f
+
+/* SCB opcodes: Send Queue
+ */
+#define SSP_TARG_SEND_DATA 0x40
+#define SSP_TARG_SEND_DATA_GOOD 0x41
+
+/* SCB opcodes: Link Queue
+ */
+#define CONTROL_PHY 0x80
+#define SEND_PRIMITIVE 0x81
+#define INITIATE_LINK_ADM_TASK 0x82
+
+/* SCB opcodes: other
+ */
+#define EMPTY_SCB 0xc0
+#define INITIATE_SEQ_ADM_TASK 0xc1
+#define EST_ICL_TARG_WINDOW 0xc2
+#define COPY_MEM 0xc3
+#define CLEAR_NEXUS 0xc4
+#define INITIATE_DDB_ADM_TASK 0xc6
+#define ESTABLISH_NEXUS_ESCB 0xd0
+
+#define LUN_SIZE 8
+
+/* See SAS spec, task IU
+ */
+struct ssp_task_iu {
+ u8 lun[LUN_SIZE]; /* BE */
+ u16 _r_a;
+ u8 tmf;
+ u8 _r_b;
+ __be16 tag; /* BE */
+ u8 _r_c[14];
+} __attribute__ ((packed));
+
+/* See SAS spec, command IU
+ */
+struct ssp_command_iu {
+ u8 lun[LUN_SIZE];
+ u8 _r_a;
+ u8 efb_prio_attr; /* enable first burst, task prio & attr */
+#define EFB_MASK 0x80
+#define TASK_PRIO_MASK 0x78
+#define TASK_ATTR_MASK 0x07
+
+ u8 _r_b;
+ u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */
+ union {
+ u8 cdb[16];
+ struct {
+ __le64 long_cdb_addr; /* bus address, LE */
+ __le32 long_cdb_size; /* LE */
+ u8 _r_c[3];
+ u8 eol_ds; /* eol:6,6, ds:5,4 */
+ } long_cdb; /* sequencer extension */
+ };
+} __attribute__ ((packed));
+
+struct xfer_rdy_iu {
+ __be32 requested_offset; /* BE */
+ __be32 write_data_len; /* BE */
+ __be32 _r_a;
+} __attribute__ ((packed));
+
+/* ---------- SCB tasks ---------- */
+
+/* This is both ssp_task and long_ssp_task
+ */
+struct initiate_ssp_task {
+ u8 proto_conn_rate; /* proto:6,4, conn_rate:3,0 */
+ __le32 total_xfer_len;
+ struct ssp_frame_hdr ssp_frame;
+ struct ssp_command_iu ssp_cmd;
+ __le16 sister_scb; /* 0xFFFF */
+ __le16 conn_handle; /* index to DDB for the intended target */
+ u8 data_dir; /* :1,0 */
+#define DATA_DIR_NONE 0x00
+#define DATA_DIR_IN 0x01
+#define DATA_DIR_OUT 0x02
+#define DATA_DIR_BYRECIPIENT 0x03
+
+ u8 _r_a;
+ u8 retry_count;
+ u8 _r_b[5];
+ struct sg_el sg_element[3]; /* 2 real and 1 link */
+} __attribute__ ((packed));
+
+/* This defines both ata_task and atapi_task.
+ * ata: C bit of FIS should be 1,
+ * atapi: C bit of FIS should be 1, and command register should be 0xA0,
+ * to indicate a packet command.
+ */
+struct initiate_ata_task {
+ u8 proto_conn_rate;
+ __le32 total_xfer_len;
+ struct host_to_dev_fis fis;
+ __le32 data_offs;
+ u8 atapi_packet[16];
+ u8 _r_a[12];
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 ata_flags; /* CSMI:6,6, DTM:4,4, QT:3,3, data dir:1,0 */
+#define CSMI_TASK 0x40
+#define DATA_XFER_MODE_DMA 0x10
+#define ATA_Q_TYPE_MASK 0x08
+#define ATA_Q_TYPE_UNTAGGED 0x00
+#define ATA_Q_TYPE_NCQ 0x08
+
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c;
+ u8 flags;
+#define STP_AFFIL_POLICY 0x20
+#define SET_AFFIL_POLICY 0x10
+#define RET_PARTIAL_SGLIST 0x02
+
+ u8 _r_d[3];
+ struct sg_el sg_element[3];
+} __attribute__ ((packed));
+
+struct initiate_smp_task {
+ u8 proto_conn_rate;
+ u8 _r_a[40];
+ struct sg_el smp_req;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 _r_c[8];
+ struct sg_el smp_resp;
+ u8 _r_d[32];
+} __attribute__ ((packed));
+
+struct control_phy {
+ u8 phy_id;
+ u8 sub_func;
+#define DISABLE_PHY 0x00
+#define ENABLE_PHY 0x01
+#define RELEASE_SPINUP_HOLD 0x02
+#define ENABLE_PHY_NO_SAS_OOB 0x03
+#define ENABLE_PHY_NO_SATA_OOB 0x04
+#define PHY_NO_OP 0x05
+#define EXECUTE_HARD_RESET 0x81
+
+ u8 func_mask;
+ u8 speed_mask;
+ u8 hot_plug_delay;
+ u8 port_type;
+ u8 flags;
+#define DEV_PRES_TIMER_OVERRIDE_ENABLE 0x01
+#define DISABLE_PHY_IF_OOB_FAILS 0x02
+
+ __le32 timeout_override;
+ u8 link_reset_retries;
+ u8 _r_a[47];
+ __le16 conn_handle;
+ u8 _r_b[56];
+} __attribute__ ((packed));
+
+struct control_ata_dev {
+ u8 proto_conn_rate;
+ __le32 _r_a;
+ struct host_to_dev_fis fis;
+ u8 _r_b[32];
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 ata_flags; /* 0 */
+ u8 _r_c[55];
+} __attribute__ ((packed));
+
+struct empty_scb {
+ u8 num_valid;
+ __le32 _r_a;
+#define ASD_EDBS_PER_SCB 7
+/* header+data+CRC+DMA suffix data */
+#define ASD_EDB_SIZE (24+1024+4+16)
+ struct sg_el eb[ASD_EDBS_PER_SCB];
+#define ELEMENT_NOT_VALID 0xC0
+} __attribute__ ((packed));
+
+struct initiate_link_adm {
+ u8 phy_id;
+ u8 sub_func;
+#define GET_LINK_ERROR_COUNT 0x00
+#define RESET_LINK_ERROR_COUNT 0x01
+#define ENABLE_NOTIFY_SPINUP_INTS 0x02
+
+ u8 _r_a[57];
+ __le16 conn_handle;
+ u8 _r_b[56];
+} __attribute__ ((packed));
+
+struct copy_memory {
+ u8 _r_a;
+ __le16 xfer_len;
+ __le16 _r_b;
+ __le64 src_busaddr;
+ u8 src_ds; /* See definition of sg_el */
+ u8 _r_c[45];
+ __le16 conn_handle;
+ __le64 _r_d;
+ __le64 dest_busaddr;
+ u8 dest_ds; /* See definition of sg_el */
+ u8 _r_e[39];
+} __attribute__ ((packed));
+
+struct abort_task {
+ u8 proto_conn_rate;
+ __le32 _r_a;
+ struct ssp_frame_hdr ssp_frame;
+ struct ssp_task_iu ssp_task;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */
+#define SUSPEND_DATA_TRANS 0x04
+
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c[5];
+ __le16 index; /* Transaction context of task to be queried */
+ __le16 itnl_to;
+ u8 _r_d[44];
+} __attribute__ ((packed));
+
+struct clear_nexus {
+ u8 nexus;
+#define NEXUS_ADAPTER 0x00
+#define NEXUS_PORT 0x01
+#define NEXUS_I_T 0x02
+#define NEXUS_I_T_L 0x03
+#define NEXUS_TAG 0x04
+#define NEXUS_TRANS_CX 0x05
+#define NEXUS_SATA_TAG 0x06
+#define NEXUS_T_L 0x07
+#define NEXUS_L 0x08
+#define NEXUS_T_TAG 0x09
+
+ __le32 _r_a;
+ u8 flags;
+#define SUSPEND_TX 0x80
+#define RESUME_TX 0x40
+#define SEND_Q 0x04
+#define EXEC_Q 0x02
+#define NOTINQ 0x01
+
+ u8 _r_b[3];
+ u8 conn_mask;
+ u8 _r_c[19];
+ struct ssp_task_iu ssp_task; /* LUN and TAG */
+ __le16 _r_d;
+ __le16 conn_handle;
+ __le64 _r_e;
+ __le16 index; /* Transaction context of task to be cleared */
+ __le16 context; /* Clear nexus context */
+ u8 _r_f[44];
+} __attribute__ ((packed));
+
+struct initiate_ssp_tmf {
+ u8 proto_conn_rate;
+ __le32 _r_a;
+ struct ssp_frame_hdr ssp_frame;
+ struct ssp_task_iu ssp_task;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 flags; /* itnl override and suspend data tx */
+#define OVERRIDE_ITNL_TIMER 8
+
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c[5];
+ __le16 index; /* Transaction context of task to be queried */
+ __le16 itnl_to;
+ u8 _r_d[44];
+} __attribute__ ((packed));
+
+/* Transmits an arbitrary primitive on the link.
+ * Used for NOTIFY and BROADCAST.
+ */
+struct send_prim {
+ u8 phy_id;
+ u8 wait_transmit; /* :0,0 */
+ u8 xmit_flags;
+#define XMTPSIZE_MASK 0xF0
+#define XMTPSIZE_SINGLE 0x10
+#define XMTPSIZE_REPEATED 0x20
+#define XMTPSIZE_CONT 0x20
+#define XMTPSIZE_TRIPLE 0x30
+#define XMTPSIZE_REDUNDANT 0x60
+#define XMTPSIZE_INF 0
+
+#define XMTCONTEN 0x04
+#define XMTPFRM 0x02 /* Transmit at the next frame boundary */
+#define XMTPIMM 0x01 /* Transmit immediately */
+
+ __le16 _r_a;
+ u8 prim[4]; /* K, D0, D1, D2 */
+ u8 _r_b[50];
+ __le16 conn_handle;
+ u8 _r_c[56];
+} __attribute__ ((packed));
+
+/* This describes both SSP Target Get Data and SSP Target Get Data And
+ * Send Good Response SCBs. Used when the sequencer is operating in
+ * target mode...
+ */
+struct ssp_targ_get_data {
+ u8 proto_conn_rate;
+ __le32 total_xfer_len;
+ struct ssp_frame_hdr ssp_frame;
+ struct xfer_rdy_iu xfer_rdy;
+ u8 lun[LUN_SIZE];
+ __le64 _r_a;
+ __le16 sister_scb;
+ __le16 conn_handle;
+ u8 data_dir; /* 01b */
+ u8 _r_b;
+ u8 retry_count;
+ u8 _r_c[5];
+ struct sg_el sg_element[3];
+} __attribute__ ((packed));
+
+/* ---------- The actual SCB struct ---------- */
+
+struct scb {
+ struct scb_header header;
+ union {
+ struct initiate_ssp_task ssp_task;
+ struct initiate_ata_task ata_task;
+ struct initiate_smp_task smp_task;
+ struct control_phy control_phy;
+ struct control_ata_dev control_ata_dev;
+ struct empty_scb escb;
+ struct initiate_link_adm link_adm;
+ struct copy_memory cp_mem;
+ struct abort_task abort_task;
+ struct clear_nexus clear_nexus;
+ struct initiate_ssp_tmf ssp_tmf;
+ };
+} __attribute__ ((packed));
+
+/* ---------- Done List ---------- */
+/* The done list entry opcode field is defined below.
+ * The mnemonic encoding and meaning is as follows:
+ * TC - Task Complete, status was received and acknowledged
+ * TF - Task Failed, indicates an error prior to receiving acknowledgment
+ * for the command:
+ * - no conn,
+ * - NACK or R_ERR received in response to this command,
+ * - credit blocked or not available, or in the case of SMP request,
+ * - no SMP response was received.
+ * In these four cases it is known that the target didn't receive the
+ * command.
+ * TI - Task Interrupted, error after the command was acknowledged. It is
+ * known that the command was received by the target.
+ * TU - Task Unacked, command was transmitted but neither ACK (R_OK) nor NAK
+ * (R_ERR) was received due to loss of signal, broken connection, loss of
+ * dword sync or other reason. The application client should send the
+ * appropriate task query.
+ * TA - Task Aborted, see TF.
+ * _RESP - The completion includes an empty buffer containing status.
+ * TO - Timeout.
+ */
+#define TC_NO_ERROR 0x00
+#define TC_UNDERRUN 0x01
+#define TC_OVERRUN 0x02
+#define TF_OPEN_TO 0x03
+#define TF_OPEN_REJECT 0x04
+#define TI_BREAK 0x05
+#define TI_PROTO_ERR 0x06
+#define TC_SSP_RESP 0x07
+#define TI_PHY_DOWN 0x08
+#define TF_PHY_DOWN 0x09
+#define TC_LINK_ADM_RESP 0x0a
+#define TC_CSMI 0x0b
+#define TC_ATA_RESP 0x0c
+#define TU_PHY_DOWN 0x0d
+#define TU_BREAK 0x0e
+#define TI_SATA_TO 0x0f
+#define TI_NAK 0x10
+#define TC_CONTROL_PHY 0x11
+#define TF_BREAK 0x12
+#define TC_RESUME 0x13
+#define TI_ACK_NAK_TO 0x14
+#define TF_SMPRSP_TO 0x15
+#define TF_SMP_XMIT_RCV_ERR 0x16
+#define TC_PARTIAL_SG_LIST 0x17
+#define TU_ACK_NAK_TO 0x18
+#define TU_SATA_TO 0x19
+#define TF_NAK_RECV 0x1a
+#define TA_I_T_NEXUS_LOSS 0x1b
+#define TC_ATA_R_ERR_RECV 0x1c
+#define TF_TMF_NO_CTX 0x1d
+#define TA_ON_REQ 0x1e
+#define TF_TMF_NO_TAG 0x1f
+#define TF_TMF_TAG_FREE 0x20
+#define TF_TMF_TASK_DONE 0x21
+#define TF_TMF_NO_CONN_HANDLE 0x22
+#define TC_TASK_CLEARED 0x23
+#define TI_SYNCS_RECV 0x24
+#define TU_SYNCS_RECV 0x25
+#define TF_IRTT_TO 0x26
+#define TF_NO_SMP_CONN 0x27
+#define TF_IU_SHORT 0x28
+#define TF_DATA_OFFS_ERR 0x29
+#define TF_INV_CONN_HANDLE 0x2a
+#define TF_REQUESTED_N_PENDING 0x2b
+
+/* 0xc1 - 0xc7: empty buffer received,
+ 0xd1 - 0xd7: establish nexus empty buffer received
+*/
+/* This is the ESCB mask */
+#define ESCB_RECVD 0xC0
+
+
+/* This struct done_list_struct defines the done list entry.
+ * All fields are LE.
+ */
+struct done_list_struct {
+ __le16 index; /* aka transaction context */
+ u8 opcode;
+ u8 status_block[4];
+ u8 toggle; /* bit 0 */
+#define DL_TOGGLE_MASK 0x01
+} __attribute__ ((packed));
+
+/* ---------- PHYS ---------- */
+
+struct asd_phy {
+ struct asd_sas_phy sas_phy;
+ struct asd_phy_desc *phy_desc; /* hw profile */
+
+ struct sas_identify_frame *identify_frame;
+ struct asd_dma_tok *id_frm_tok;
+
+ u8 frame_rcvd[ASD_EDB_SIZE];
+};
+
+
+#define ASD_SCB_SIZE sizeof(struct scb)
+#define ASD_DDB_SIZE sizeof(struct asd_ddb_ssp_smp_target_port)
+
+/* Define this to 0 if you do not want NOTIFY (ENABLE SPINIP) sent.
+ * Default: 0x10 (it's a mask)
+ */
+#define ASD_NOTIFY_ENABLE_SPINUP 0x10
+
+/* If enabled, set this to the interval between transmission
+ * of NOTIFY (ENABLE SPINUP). In units of 200 us.
+ */
+#define ASD_NOTIFY_TIMEOUT 2500
+
+/* Initial delay after OOB, before we transmit NOTIFY (ENABLE SPINUP).
+ * If 0, transmit immediately. In milliseconds.
+ */
+#define ASD_NOTIFY_DOWN_COUNT 0
+
+/* Device present timer timeout constant, 10 ms. */
+#define ASD_DEV_PRESENT_TIMEOUT 0x2710
+
+#define ASD_SATA_INTERLOCK_TIMEOUT 0
+
+/* How long to wait before shutting down an STP connection, unless
+ * an STP target sent frame(s). 50 usec.
+ * IGNORED by the sequencer (i.e. value 0 always).
+ */
+#define ASD_STP_SHUTDOWN_TIMEOUT 0x0
+
+/* ATA soft reset timer timeout. 5 usec. */
+#define ASD_SRST_ASSERT_TIMEOUT 0x05
+
+/* 31 sec */
+#define ASD_RCV_FIS_TIMEOUT 0x01D905C0
+
+#define ASD_ONE_MILLISEC_TIMEOUT 0x03e8
+
+/* COMINIT timer */
+#define ASD_TEN_MILLISEC_TIMEOUT 0x2710
+#define ASD_COMINIT_TIMEOUT ASD_TEN_MILLISEC_TIMEOUT
+
+/* 1 sec */
+#define ASD_SMP_RCV_TIMEOUT 0x000F4240
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c
new file mode 100644
index 00000000000..7ee49b51b72
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -0,0 +1,758 @@
+/*
+ * Aic94xx SAS/SATA driver SCB management.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+#include "aic94xx_seq.h"
+
+#include "aic94xx_dump.h"
+
+/* ---------- EMPTY SCB ---------- */
+
+#define DL_PHY_MASK 7
+#define BYTES_DMAED 0
+#define PRIMITIVE_RECVD 0x08
+#define PHY_EVENT 0x10
+#define LINK_RESET_ERROR 0x18
+#define TIMER_EVENT 0x20
+#define REQ_TASK_ABORT 0xF0
+#define REQ_DEVICE_RESET 0xF1
+#define SIGNAL_NCQ_ERROR 0xF2
+#define CLEAR_NCQ_ERROR 0xF3
+
+#define PHY_EVENTS_STATUS (CURRENT_LOSS_OF_SIGNAL | CURRENT_OOB_DONE \
+ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
+ | CURRENT_OOB_ERROR)
+
+static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode)
+{
+ struct sas_phy *sas_phy = phy->sas_phy.phy;
+
+ switch (oob_mode & 7) {
+ case PHY_SPEED_60:
+ /* FIXME: sas transport class doesn't have this */
+ phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
+ break;
+ case PHY_SPEED_30:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
+ break;
+ case PHY_SPEED_15:
+ phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
+ phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
+ break;
+ }
+ sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
+ sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
+ sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
+ sas_phy->maximum_linkrate = phy->phy_desc->max_sas_lrate;
+ sas_phy->minimum_linkrate = phy->phy_desc->min_sas_lrate;
+
+ if (oob_mode & SAS_MODE)
+ phy->sas_phy.oob_mode = SAS_OOB_MODE;
+ else if (oob_mode & SATA_MODE)
+ phy->sas_phy.oob_mode = SATA_OOB_MODE;
+}
+
+static inline void asd_phy_event_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+ int phy_id = dl->status_block[0] & DL_PHY_MASK;
+ struct asd_phy *phy = &asd_ha->phys[phy_id];
+
+ u8 oob_status = dl->status_block[1] & PHY_EVENTS_STATUS;
+ u8 oob_mode = dl->status_block[2];
+
+ switch (oob_status) {
+ case CURRENT_LOSS_OF_SIGNAL:
+ /* directly attached device was removed */
+ ASD_DPRINTK("phy%d: device unplugged\n", phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ sas_phy_disconnected(&phy->sas_phy);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL);
+ break;
+ case CURRENT_OOB_DONE:
+ /* hot plugged device */
+ asd_turn_led(asd_ha, phy_id, 1);
+ get_lrate_mode(phy, oob_mode);
+ ASD_DPRINTK("phy%d device plugged: lrate:0x%x, proto:0x%x\n",
+ phy_id, phy->sas_phy.linkrate, phy->sas_phy.iproto);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE);
+ break;
+ case CURRENT_SPINUP_HOLD:
+ /* hot plug SATA, no COMWAKE sent */
+ asd_turn_led(asd_ha, phy_id, 1);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD);
+ break;
+ case CURRENT_GTO_TIMEOUT:
+ case CURRENT_OOB_ERROR:
+ ASD_DPRINTK("phy%d error while OOB: oob status:0x%x\n", phy_id,
+ dl->status_block[1]);
+ asd_turn_led(asd_ha, phy_id, 0);
+ sas_phy_disconnected(&phy->sas_phy);
+ sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR);
+ break;
+ }
+}
+
+/* If phys are enabled sparsely, this will do the right thing. */
+static inline unsigned ord_phy(struct asd_ha_struct *asd_ha,
+ struct asd_phy *phy)
+{
+ u8 enabled_mask = asd_ha->hw_prof.enabled_phys;
+ int i, k = 0;
+
+ for_each_phy(enabled_mask, enabled_mask, i) {
+ if (&asd_ha->phys[i] == phy)
+ return k;
+ k++;
+ }
+ return 0;
+}
+
+/**
+ * asd_get_attached_sas_addr -- extract/generate attached SAS address
+ * phy: pointer to asd_phy
+ * sas_addr: pointer to buffer where the SAS address is to be written
+ *
+ * This function extracts the SAS address from an IDENTIFY frame
+ * received. If OOB is SATA, then a SAS address is generated from the
+ * HA tables.
+ *
+ * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
+ * buffer.
+ */
+static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
+{
+ if (phy->sas_phy.frame_rcvd[0] == 0x34
+ && phy->sas_phy.oob_mode == SATA_OOB_MODE) {
+ struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha;
+ /* FIS device-to-host */
+ u64 addr = be64_to_cpu(*(__be64 *)phy->phy_desc->sas_addr);
+
+ addr += asd_ha->hw_prof.sata_name_base + ord_phy(asd_ha, phy);
+ *(__be64 *)sas_addr = cpu_to_be64(addr);
+ } else {
+ struct sas_identify_frame *idframe =
+ (void *) phy->sas_phy.frame_rcvd;
+ memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
+ }
+}
+
+static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int edb_id, int phy_id)
+{
+ unsigned long flags;
+ int edb_el = edb_id + ascb->edb_index;
+ struct asd_dma_tok *edb = ascb->ha->seq.edb_arr[edb_el];
+ struct asd_phy *phy = &ascb->ha->phys[phy_id];
+ struct sas_ha_struct *sas_ha = phy->sas_phy.ha;
+ u16 size = ((dl->status_block[3] & 7) << 8) | dl->status_block[2];
+
+ size = min(size, (u16) sizeof(phy->frame_rcvd));
+
+ spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
+ memcpy(phy->sas_phy.frame_rcvd, edb->vaddr, size);
+ phy->sas_phy.frame_rcvd_size = size;
+ asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
+ spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
+ asd_dump_frame_rcvd(phy, dl);
+ sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
+}
+
+static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int phy_id)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+ u8 lr_error = dl->status_block[1];
+ u8 retries_left = dl->status_block[2];
+
+ switch (lr_error) {
+ case 0:
+ ASD_DPRINTK("phy%d: Receive ID timer expired\n", phy_id);
+ break;
+ case 1:
+ ASD_DPRINTK("phy%d: Loss of signal\n", phy_id);
+ break;
+ case 2:
+ ASD_DPRINTK("phy%d: Loss of dword sync\n", phy_id);
+ break;
+ case 3:
+ ASD_DPRINTK("phy%d: Receive FIS timeout\n", phy_id);
+ break;
+ default:
+ ASD_DPRINTK("phy%d: unknown link reset error code: 0x%x\n",
+ phy_id, lr_error);
+ break;
+ }
+
+ asd_turn_led(asd_ha, phy_id, 0);
+ sas_phy_disconnected(sas_phy);
+ sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
+
+ if (retries_left == 0) {
+ int num = 1;
+ struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num,
+ GFP_ATOMIC);
+ if (!cp) {
+ asd_printk("%s: out of memory\n", __FUNCTION__);
+ goto out;
+ }
+ ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n",
+ phy_id);
+ asd_build_control_phy(cp, phy_id, ENABLE_PHY);
+ if (asd_post_ascb_list(ascb->ha, cp, 1) != 0)
+ asd_ascb_free(cp);
+ }
+out:
+ ;
+}
+
+static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl,
+ int phy_id)
+{
+ unsigned long flags;
+ struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
+ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+ u8 reg = dl->status_block[1];
+ u32 cont = dl->status_block[2] << ((reg & 3)*8);
+
+ reg &= ~3;
+ switch (reg) {
+ case LmPRMSTAT0BYTE0:
+ switch (cont) {
+ case LmBROADCH:
+ case LmBROADRVCH0:
+ case LmBROADRVCH1:
+ case LmBROADSES:
+ ASD_DPRINTK("phy%d: BROADCAST change received:%d\n",
+ phy_id, cont);
+ spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
+ sas_phy->sas_prim = ffs(cont);
+ spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
+ sas_ha->notify_port_event(sas_phy,PORTE_BROADCAST_RCVD);
+ break;
+
+ case LmUNKNOWNP:
+ ASD_DPRINTK("phy%d: unknown BREAK\n", phy_id);
+ break;
+
+ default:
+ ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
+ phy_id, reg, cont);
+ break;
+ }
+ break;
+ case LmPRMSTAT1BYTE0:
+ switch (cont) {
+ case LmHARDRST:
+ ASD_DPRINTK("phy%d: HARD_RESET primitive rcvd\n",
+ phy_id);
+ /* The sequencer disables all phys on that port.
+ * We have to re-enable the phys ourselves. */
+ sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
+ break;
+
+ default:
+ ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n",
+ phy_id, reg, cont);
+ break;
+ }
+ break;
+ default:
+ ASD_DPRINTK("unknown primitive register:0x%x\n",
+ dl->status_block[1]);
+ break;
+ }
+}
+
+/**
+ * asd_invalidate_edb -- invalidate an EDB and if necessary post the ESCB
+ * @ascb: pointer to Empty SCB
+ * @edb_id: index [0,6] to the empty data buffer which is to be invalidated
+ *
+ * After an EDB has been invalidated, if all EDBs in this ESCB have been
+ * invalidated, the ESCB is posted back to the sequencer.
+ * Context is tasklet/IRQ.
+ */
+void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id)
+{
+ struct asd_seq_data *seq = &ascb->ha->seq;
+ struct empty_scb *escb = &ascb->scb->escb;
+ struct sg_el *eb = &escb->eb[edb_id];
+ struct asd_dma_tok *edb = seq->edb_arr[ascb->edb_index + edb_id];
+
+ memset(edb->vaddr, 0, ASD_EDB_SIZE);
+ eb->flags |= ELEMENT_NOT_VALID;
+ escb->num_valid--;
+
+ if (escb->num_valid == 0) {
+ int i;
+ /* ASD_DPRINTK("reposting escb: vaddr: 0x%p, "
+ "dma_handle: 0x%08llx, next: 0x%08llx, "
+ "index:%d, opcode:0x%02x\n",
+ ascb->dma_scb.vaddr,
+ (u64)ascb->dma_scb.dma_handle,
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+ */
+ escb->num_valid = ASD_EDBS_PER_SCB;
+ for (i = 0; i < ASD_EDBS_PER_SCB; i++)
+ escb->eb[i].flags = 0;
+ if (!list_empty(&ascb->list))
+ list_del_init(&ascb->list);
+ i = asd_post_escb_list(ascb->ha, ascb, 1);
+ if (i)
+ asd_printk("couldn't post escb, err:%d\n", i);
+ }
+}
+
+static void escb_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
+ int edb = (dl->opcode & DL_PHY_MASK) - 1; /* [0xc1,0xc7] -> [0,6] */
+ u8 sb_opcode = dl->status_block[0];
+ int phy_id = sb_opcode & DL_PHY_MASK;
+ struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
+
+ if (edb > 6 || edb < 0) {
+ ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
+ edb, dl->opcode);
+ ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
+ sb_opcode, phy_id);
+ ASD_DPRINTK("escb: vaddr: 0x%p, "
+ "dma_handle: 0x%llx, next: 0x%llx, "
+ "index:%d, opcode:0x%02x\n",
+ ascb->dma_scb.vaddr,
+ (unsigned long long)ascb->dma_scb.dma_handle,
+ (unsigned long long)
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+ }
+
+ sb_opcode &= ~DL_PHY_MASK;
+
+ switch (sb_opcode) {
+ case BYTES_DMAED:
+ ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id);
+ asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id);
+ break;
+ case PRIMITIVE_RECVD:
+ ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__,
+ phy_id);
+ asd_primitive_rcvd_tasklet(ascb, dl, phy_id);
+ break;
+ case PHY_EVENT:
+ ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id);
+ asd_phy_event_tasklet(ascb, dl);
+ break;
+ case LINK_RESET_ERROR:
+ ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__,
+ phy_id);
+ asd_link_reset_err_tasklet(ascb, dl, phy_id);
+ break;
+ case TIMER_EVENT:
+ ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n",
+ __FUNCTION__, phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ /* the device is gone */
+ sas_phy_disconnected(sas_phy);
+ sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
+ break;
+ case REQ_TASK_ABORT:
+ ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__,
+ phy_id);
+ break;
+ case REQ_DEVICE_RESET:
+ ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__,
+ phy_id);
+ break;
+ case SIGNAL_NCQ_ERROR:
+ ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__,
+ phy_id);
+ break;
+ case CLEAR_NCQ_ERROR:
+ ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__,
+ phy_id);
+ break;
+ default:
+ ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__,
+ phy_id, sb_opcode);
+ ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
+ edb, dl->opcode);
+ ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n",
+ sb_opcode, phy_id);
+ ASD_DPRINTK("escb: vaddr: 0x%p, "
+ "dma_handle: 0x%llx, next: 0x%llx, "
+ "index:%d, opcode:0x%02x\n",
+ ascb->dma_scb.vaddr,
+ (unsigned long long)ascb->dma_scb.dma_handle,
+ (unsigned long long)
+ le64_to_cpu(ascb->scb->header.next_scb),
+ le16_to_cpu(ascb->scb->header.index),
+ ascb->scb->header.opcode);
+
+ break;
+ }
+
+ asd_invalidate_edb(ascb, edb);
+}
+
+int asd_init_post_escbs(struct asd_ha_struct *asd_ha)
+{
+ struct asd_seq_data *seq = &asd_ha->seq;
+ int i;
+
+ for (i = 0; i < seq->num_escbs; i++)
+ seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete;
+
+ ASD_DPRINTK("posting %d escbs\n", i);
+ return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs);
+}
+
+/* ---------- CONTROL PHY ---------- */
+
+#define CONTROL_PHY_STATUS (CURRENT_DEVICE_PRESENT | CURRENT_OOB_DONE \
+ | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \
+ | CURRENT_OOB_ERROR)
+
+/**
+ * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb
+ * @ascb: pointer to an ascb
+ * @dl: pointer to the done list entry
+ *
+ * This function completes a CONTROL PHY scb and frees the ascb.
+ * A note on LEDs:
+ * - an LED blinks if there is IO though it,
+ * - if a device is connected to the LED, it is lit,
+ * - if no device is connected to the LED, is is dimmed (off).
+ */
+static void control_phy_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct scb *scb = ascb->scb;
+ struct control_phy *control_phy = &scb->control_phy;
+ u8 phy_id = control_phy->phy_id;
+ struct asd_phy *phy = &ascb->ha->phys[phy_id];
+
+ u8 status = dl->status_block[0];
+ u8 oob_status = dl->status_block[1];
+ u8 oob_mode = dl->status_block[2];
+ /* u8 oob_signals= dl->status_block[3]; */
+
+ if (status != 0) {
+ ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n",
+ __FUNCTION__, phy_id, status);
+ goto out;
+ }
+
+ switch (control_phy->sub_func) {
+ case DISABLE_PHY:
+ asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ asd_control_led(asd_ha, phy_id, 0);
+ ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id);
+ break;
+
+ case ENABLE_PHY:
+ asd_control_led(asd_ha, phy_id, 1);
+ if (oob_status & CURRENT_OOB_DONE) {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ get_lrate_mode(phy, oob_mode);
+ asd_turn_led(asd_ha, phy_id, 1);
+ ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n",
+ __FUNCTION__, phy_id,phy->sas_phy.linkrate,
+ phy->sas_phy.iproto);
+ } else if (oob_status & CURRENT_SPINUP_HOLD) {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 1);
+ ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__,
+ phy_id);
+ } else if (oob_status & CURRENT_ERR_MASK) {
+ asd_turn_led(asd_ha, phy_id, 0);
+ ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n",
+ __FUNCTION__, phy_id, oob_status);
+ } else if (oob_status & (CURRENT_HOT_PLUG_CNCT
+ | CURRENT_DEVICE_PRESENT)) {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 1);
+ ASD_DPRINTK("%s: phy%d: hot plug or device present\n",
+ __FUNCTION__, phy_id);
+ } else {
+ asd_ha->hw_prof.enabled_phys |= (1 << phy_id);
+ asd_turn_led(asd_ha, phy_id, 0);
+ ASD_DPRINTK("%s: phy%d: no device present: "
+ "oob_status:0x%x\n",
+ __FUNCTION__, phy_id, oob_status);
+ }
+ break;
+ case RELEASE_SPINUP_HOLD:
+ case PHY_NO_OP:
+ case EXECUTE_HARD_RESET:
+ ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__,
+ phy_id, control_phy->sub_func);
+ /* XXX finish */
+ break;
+ default:
+ ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__,
+ phy_id, control_phy->sub_func);
+ break;
+ }
+out:
+ asd_ascb_free(ascb);
+}
+
+static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd)
+{
+ /* disable all speeds, then enable defaults */
+ *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS
+ | SATA_SPEED_30_DIS | SATA_SPEED_15_DIS;
+
+ switch (pd->max_sas_lrate) {
+ case SAS_LINK_RATE_6_0_GBPS:
+ *speed_mask &= ~SAS_SPEED_60_DIS;
+ default:
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask &= ~SAS_SPEED_30_DIS;
+ case SAS_LINK_RATE_1_5_GBPS:
+ *speed_mask &= ~SAS_SPEED_15_DIS;
+ }
+
+ switch (pd->min_sas_lrate) {
+ case SAS_LINK_RATE_6_0_GBPS:
+ *speed_mask |= SAS_SPEED_30_DIS;
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask |= SAS_SPEED_15_DIS;
+ default:
+ case SAS_LINK_RATE_1_5_GBPS:
+ /* nothing to do */
+ ;
+ }
+
+ switch (pd->max_sata_lrate) {
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask &= ~SATA_SPEED_30_DIS;
+ default:
+ case SAS_LINK_RATE_1_5_GBPS:
+ *speed_mask &= ~SATA_SPEED_15_DIS;
+ }
+
+ switch (pd->min_sata_lrate) {
+ case SAS_LINK_RATE_3_0_GBPS:
+ *speed_mask |= SATA_SPEED_15_DIS;
+ default:
+ case SAS_LINK_RATE_1_5_GBPS:
+ /* nothing to do */
+ ;
+ }
+}
+
+/**
+ * asd_build_control_phy -- build a CONTROL PHY SCB
+ * @ascb: pointer to an ascb
+ * @phy_id: phy id to control, integer
+ * @subfunc: subfunction, what to actually to do the phy
+ *
+ * This function builds a CONTROL PHY scb. No allocation of any kind
+ * is performed. @ascb is allocated with the list function.
+ * The caller can override the ascb->tasklet_complete to point
+ * to its own callback function. It must call asd_ascb_free()
+ * at its tasklet complete function.
+ * See the default implementation.
+ */
+void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc)
+{
+ struct asd_phy *phy = &ascb->ha->phys[phy_id];
+ struct scb *scb = ascb->scb;
+ struct control_phy *control_phy = &scb->control_phy;
+
+ scb->header.opcode = CONTROL_PHY;
+ control_phy->phy_id = (u8) phy_id;
+ control_phy->sub_func = subfunc;
+
+ switch (subfunc) {
+ case EXECUTE_HARD_RESET: /* 0x81 */
+ case ENABLE_PHY: /* 0x01 */
+ /* decide hot plug delay */
+ control_phy->hot_plug_delay = HOTPLUG_DELAY_TIMEOUT;
+
+ /* decide speed mask */
+ set_speed_mask(&control_phy->speed_mask, phy->phy_desc);
+
+ /* initiator port settings are in the hi nibble */
+ if (phy->sas_phy.role == PHY_ROLE_INITIATOR)
+ control_phy->port_type = SAS_PROTO_ALL << 4;
+ else if (phy->sas_phy.role == PHY_ROLE_TARGET)
+ control_phy->port_type = SAS_PROTO_ALL;
+ else
+ control_phy->port_type =
+ (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL;
+
+ /* link reset retries, this should be nominal */
+ control_phy->link_reset_retries = 10;
+
+ case RELEASE_SPINUP_HOLD: /* 0x02 */
+ /* decide the func_mask */
+ control_phy->func_mask = FUNCTION_MASK_DEFAULT;
+ if (phy->phy_desc->flags & ASD_SATA_SPINUP_HOLD)
+ control_phy->func_mask &= ~SPINUP_HOLD_DIS;
+ else
+ control_phy->func_mask |= SPINUP_HOLD_DIS;
+ }
+
+ control_phy->conn_handle = cpu_to_le16(0xFFFF);
+
+ ascb->tasklet_complete = control_phy_tasklet_complete;
+}
+
+/* ---------- INITIATE LINK ADM TASK ---------- */
+
+static void link_adm_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ u8 opcode = dl->opcode;
+ struct initiate_link_adm *link_adm = &ascb->scb->link_adm;
+ u8 phy_id = link_adm->phy_id;
+
+ if (opcode != TC_NO_ERROR) {
+ asd_printk("phy%d: link adm task 0x%x completed with error "
+ "0x%x\n", phy_id, link_adm->sub_func, opcode);
+ }
+ ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n",
+ phy_id, link_adm->sub_func, opcode);
+
+ asd_ascb_free(ascb);
+}
+
+void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id,
+ u8 subfunc)
+{
+ struct scb *scb = ascb->scb;
+ struct initiate_link_adm *link_adm = &scb->link_adm;
+
+ scb->header.opcode = INITIATE_LINK_ADM_TASK;
+
+ link_adm->phy_id = phy_id;
+ link_adm->sub_func = subfunc;
+ link_adm->conn_handle = cpu_to_le16(0xFFFF);
+
+ ascb->tasklet_complete = link_adm_tasklet_complete;
+}
+
+/* ---------- SCB timer ---------- */
+
+/**
+ * asd_ascb_timedout -- called when a pending SCB's timer has expired
+ * @data: unsigned long, a pointer to the ascb in question
+ *
+ * This is the default timeout function which does the most necessary.
+ * Upper layers can implement their own timeout function, say to free
+ * resources they have with this SCB, and then call this one at the
+ * end of their timeout function. To do this, one should initialize
+ * the ascb->timer.{function, data, expires} prior to calling the post
+ * funcion. The timer is started by the post function.
+ */
+void asd_ascb_timedout(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+ struct asd_seq_data *seq = &ascb->ha->seq;
+ unsigned long flags;
+
+ ASD_DPRINTK("scb:0x%x timed out\n", ascb->scb->header.opcode);
+
+ spin_lock_irqsave(&seq->pend_q_lock, flags);
+ seq->pending--;
+ list_del_init(&ascb->list);
+ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+
+ asd_ascb_free(ascb);
+}
+
+/* ---------- CONTROL PHY ---------- */
+
+/* Given the spec value, return a driver value. */
+static const int phy_func_table[] = {
+ [PHY_FUNC_NOP] = PHY_NO_OP,
+ [PHY_FUNC_LINK_RESET] = ENABLE_PHY,
+ [PHY_FUNC_HARD_RESET] = EXECUTE_HARD_RESET,
+ [PHY_FUNC_DISABLE] = DISABLE_PHY,
+ [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD,
+};
+
+int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg)
+{
+ struct asd_ha_struct *asd_ha = phy->ha->lldd_ha;
+ struct asd_phy_desc *pd = asd_ha->phys[phy->id].phy_desc;
+ struct asd_ascb *ascb;
+ struct sas_phy_linkrates *rates;
+ int res = 1;
+
+ switch (func) {
+ case PHY_FUNC_CLEAR_ERROR_LOG:
+ return -ENOSYS;
+ case PHY_FUNC_SET_LINK_RATE:
+ rates = arg;
+ if (rates->minimum_linkrate) {
+ pd->min_sas_lrate = rates->minimum_linkrate;
+ pd->min_sata_lrate = rates->minimum_linkrate;
+ }
+ if (rates->maximum_linkrate) {
+ pd->max_sas_lrate = rates->maximum_linkrate;
+ pd->max_sata_lrate = rates->maximum_linkrate;
+ }
+ func = PHY_FUNC_LINK_RESET;
+ break;
+ default:
+ break;
+ }
+
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+ if (!ascb)
+ return -ENOMEM;
+
+ asd_build_control_phy(ascb, phy->id, phy_func_table[func]);
+ res = asd_post_ascb_list(asd_ha, ascb , 1);
+ if (res)
+ asd_ascb_free(ascb);
+
+ return res;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c
new file mode 100644
index 00000000000..83574b5b4e6
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_sds.c
@@ -0,0 +1,1089 @@
+/*
+ * Aic94xx SAS/SATA driver access to shared data structures and memory
+ * maps.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "aic94xx.h"
+#include "aic94xx_reg.h"
+
+/* ---------- OCM stuff ---------- */
+
+struct asd_ocm_dir_ent {
+ u8 type;
+ u8 offs[3];
+ u8 _r1;
+ u8 size[3];
+} __attribute__ ((packed));
+
+struct asd_ocm_dir {
+ char sig[2];
+ u8 _r1[2];
+ u8 major; /* 0 */
+ u8 minor; /* 0 */
+ u8 _r2;
+ u8 num_de;
+ struct asd_ocm_dir_ent entry[15];
+} __attribute__ ((packed));
+
+#define OCM_DE_OCM_DIR 0x00
+#define OCM_DE_WIN_DRVR 0x01
+#define OCM_DE_BIOS_CHIM 0x02
+#define OCM_DE_RAID_ENGN 0x03
+#define OCM_DE_BIOS_INTL 0x04
+#define OCM_DE_BIOS_CHIM_OSM 0x05
+#define OCM_DE_BIOS_CHIM_DYNAMIC 0x06
+#define OCM_DE_ADDC2C_RES0 0x07
+#define OCM_DE_ADDC2C_RES1 0x08
+#define OCM_DE_ADDC2C_RES2 0x09
+#define OCM_DE_ADDC2C_RES3 0x0A
+
+#define OCM_INIT_DIR_ENTRIES 5
+/***************************************************************************
+* OCM dircetory default
+***************************************************************************/
+static struct asd_ocm_dir OCMDirInit =
+{
+ .sig = {0x4D, 0x4F}, /* signature */
+ .num_de = OCM_INIT_DIR_ENTRIES, /* no. of directory entries */
+};
+
+/***************************************************************************
+* OCM dircetory Entries default
+***************************************************************************/
+static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] =
+{
+ {
+ .type = (OCM_DE_ADDC2C_RES0), /* Entry type */
+ .offs = {128}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_ADDC2C_RES1), /* Entry type */
+ .offs = {128, 4}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_ADDC2C_RES2), /* Entry type */
+ .offs = {128, 8}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_ADDC2C_RES3), /* Entry type */
+ .offs = {128, 12}, /* Offset */
+ .size = {0, 4}, /* size */
+ },
+ {
+ .type = (OCM_DE_WIN_DRVR), /* Entry type */
+ .offs = {128, 16}, /* Offset */
+ .size = {128, 235, 1}, /* size */
+ },
+};
+
+struct asd_bios_chim_struct {
+ char sig[4];
+ u8 major; /* 1 */
+ u8 minor; /* 0 */
+ u8 bios_major;
+ u8 bios_minor;
+ __le32 bios_build;
+ u8 flags;
+ u8 pci_slot;
+ __le16 ue_num;
+ __le16 ue_size;
+ u8 _r[14];
+ /* The unit element array is right here.
+ */
+} __attribute__ ((packed));
+
+/**
+ * asd_read_ocm_seg - read an on chip memory (OCM) segment
+ * @asd_ha: pointer to the host adapter structure
+ * @buffer: where to write the read data
+ * @offs: offset into OCM where to read from
+ * @size: how many bytes to read
+ *
+ * Return the number of bytes not read. Return 0 on success.
+ */
+static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
+ u32 offs, int size)
+{
+ u8 *p = buffer;
+ if (unlikely(asd_ha->iospace))
+ asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
+ else {
+ for ( ; size > 0; size--, offs++, p++)
+ *p = asd_read_ocm_byte(asd_ha, offs);
+ }
+ return size;
+}
+
+static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha,
+ struct asd_ocm_dir *dir, u32 offs)
+{
+ int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir));
+ if (err) {
+ ASD_DPRINTK("couldn't read ocm segment\n");
+ return err;
+ }
+
+ if (dir->sig[0] != 'M' || dir->sig[1] != 'O') {
+ ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n",
+ dir->sig[0], dir->sig[1]);
+ return -ENOENT;
+ }
+ if (dir->major != 0) {
+ asd_printk("unsupported major version of ocm dir:0x%x\n",
+ dir->major);
+ return -ENOENT;
+ }
+ dir->num_de &= 0xf;
+ return 0;
+}
+
+/**
+ * asd_write_ocm_seg - write an on chip memory (OCM) segment
+ * @asd_ha: pointer to the host adapter structure
+ * @buffer: where to read the write data
+ * @offs: offset into OCM to write to
+ * @size: how many bytes to write
+ *
+ * Return the number of bytes not written. Return 0 on success.
+ */
+static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer,
+ u32 offs, int size)
+{
+ u8 *p = buffer;
+ if (unlikely(asd_ha->iospace))
+ asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size);
+ else {
+ for ( ; size > 0; size--, offs++, p++)
+ asd_write_ocm_byte(asd_ha, offs, *p);
+ }
+ return;
+}
+
+#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16))
+
+static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type,
+ u32 *offs, u32 *size)
+{
+ int i;
+ struct asd_ocm_dir_ent *ent;
+
+ for (i = 0; i < dir->num_de; i++) {
+ if (dir->entry[i].type == type)
+ break;
+ }
+ if (i >= dir->num_de)
+ return -ENOENT;
+ ent = &dir->entry[i];
+ *offs = (u32) THREE_TO_NUM(ent->offs);
+ *size = (u32) THREE_TO_NUM(ent->size);
+ return 0;
+}
+
+#define OCM_BIOS_CHIM_DE 2
+#define BC_BIOS_PRESENT 1
+
+static int asd_get_bios_chim(struct asd_ha_struct *asd_ha,
+ struct asd_ocm_dir *dir)
+{
+ int err;
+ struct asd_bios_chim_struct *bc_struct;
+ u32 offs, size;
+
+ err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size);
+ if (err) {
+ ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n");
+ goto out;
+ }
+ err = -ENOMEM;
+ bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL);
+ if (!bc_struct) {
+ asd_printk("no memory for bios_chim struct\n");
+ goto out;
+ }
+ err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs,
+ sizeof(*bc_struct));
+ if (err) {
+ ASD_DPRINTK("couldn't read ocm segment\n");
+ goto out2;
+ }
+ if (strncmp(bc_struct->sig, "SOIB", 4)
+ && strncmp(bc_struct->sig, "IPSA", 4)) {
+ ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n",
+ bc_struct->sig[0], bc_struct->sig[1],
+ bc_struct->sig[2], bc_struct->sig[3]);
+ err = -ENOENT;
+ goto out2;
+ }
+ if (bc_struct->major != 1) {
+ asd_printk("BIOS_CHIM unsupported major version:0x%x\n",
+ bc_struct->major);
+ err = -ENOENT;
+ goto out2;
+ }
+ if (bc_struct->flags & BC_BIOS_PRESENT) {
+ asd_ha->hw_prof.bios.present = 1;
+ asd_ha->hw_prof.bios.maj = bc_struct->bios_major;
+ asd_ha->hw_prof.bios.min = bc_struct->bios_minor;
+ asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build);
+ ASD_DPRINTK("BIOS present (%d,%d), %d\n",
+ asd_ha->hw_prof.bios.maj,
+ asd_ha->hw_prof.bios.min,
+ asd_ha->hw_prof.bios.bld);
+ }
+ asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num);
+ asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size);
+ ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num,
+ asd_ha->hw_prof.ue.size);
+ size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size;
+ if (size > 0) {
+ err = -ENOMEM;
+ asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL);
+ if (!asd_ha->hw_prof.ue.area)
+ goto out2;
+ err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area,
+ offs + sizeof(*bc_struct), size);
+ if (err) {
+ kfree(asd_ha->hw_prof.ue.area);
+ asd_ha->hw_prof.ue.area = NULL;
+ asd_ha->hw_prof.ue.num = 0;
+ asd_ha->hw_prof.ue.size = 0;
+ ASD_DPRINTK("couldn't read ue entries(%d)\n", err);
+ }
+ }
+out2:
+ kfree(bc_struct);
+out:
+ return err;
+}
+
+static void
+asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ /* Zero OCM */
+ for (i = 0; i < OCM_MAX_SIZE; i += 4)
+ asd_write_ocm_dword(asd_ha, i, 0);
+
+ /* Write Dir */
+ asd_write_ocm_seg(asd_ha, &OCMDirInit, 0,
+ sizeof(struct asd_ocm_dir));
+
+ /* Write Dir Entries */
+ for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++)
+ asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i],
+ sizeof(struct asd_ocm_dir) +
+ (i * sizeof(struct asd_ocm_dir_ent))
+ , sizeof(struct asd_ocm_dir_ent));
+
+}
+
+static int
+asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha)
+{
+ struct pci_dev *pcidev = asd_ha->pcidev;
+ u32 reg;
+ int err = 0;
+ u32 v;
+
+ /* check if OCM has been initialized by BIOS */
+ reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
+
+ if (!(reg & OCMINITIALIZED)) {
+ err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v);
+ if (err) {
+ asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n",
+ pci_name(pcidev));
+ goto out;
+ }
+
+ printk(KERN_INFO "OCM is not initialized by BIOS,"
+ "reinitialize it and ignore it, current IntrptStatus"
+ "is 0x%x\n", v);
+
+ if (v)
+ err = pci_write_config_dword(pcidev,
+ PCIC_INTRPT_STAT, v);
+ if (err) {
+ asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n",
+ pci_name(pcidev));
+ goto out;
+ }
+
+ asd_hwi_initialize_ocm_dir(asd_ha);
+
+ }
+out:
+ return err;
+}
+
+/**
+ * asd_read_ocm - read on chip memory (OCM)
+ * @asd_ha: pointer to the host adapter structure
+ */
+int asd_read_ocm(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ struct asd_ocm_dir *dir;
+
+ if (asd_hwi_check_ocm_access(asd_ha))
+ return -1;
+
+ dir = kmalloc(sizeof(*dir), GFP_KERNEL);
+ if (!dir) {
+ asd_printk("no memory for ocm dir\n");
+ return -ENOMEM;
+ }
+
+ err = asd_read_ocm_dir(asd_ha, dir, 0);
+ if (err)
+ goto out;
+
+ err = asd_get_bios_chim(asd_ha, dir);
+out:
+ kfree(dir);
+ return err;
+}
+
+/* ---------- FLASH stuff ---------- */
+
+#define FLASH_RESET 0xF0
+
+#define FLASH_SIZE 0x200000
+#define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** "
+#define FLASH_NEXT_ENTRY_OFFS 0x2000
+#define FLASH_MAX_DIR_ENTRIES 32
+
+#define FLASH_DE_TYPE_MASK 0x3FFFFFFF
+#define FLASH_DE_MS 0x120
+#define FLASH_DE_CTRL_A_USER 0xE0
+
+struct asd_flash_de {
+ __le32 type;
+ __le32 offs;
+ __le32 pad_size;
+ __le32 image_size;
+ __le32 chksum;
+ u8 _r[12];
+ u8 version[32];
+} __attribute__ ((packed));
+
+struct asd_flash_dir {
+ u8 cookie[32];
+ __le32 rev; /* 2 */
+ __le32 chksum;
+ __le32 chksum_antidote;
+ __le32 bld;
+ u8 bld_id[32]; /* build id data */
+ u8 ver_data[32]; /* date and time of build */
+ __le32 ae_mask;
+ __le32 v_mask;
+ __le32 oc_mask;
+ u8 _r[20];
+ struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES];
+} __attribute__ ((packed));
+
+struct asd_manuf_sec {
+ char sig[2]; /* 'S', 'M' */
+ u16 offs_next;
+ u8 maj; /* 0 */
+ u8 min; /* 0 */
+ u16 chksum;
+ u16 size;
+ u8 _r[6];
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 pcba_sn[ASD_PCBA_SN_SIZE];
+ /* Here start the other segments */
+ u8 linked_list[0];
+} __attribute__ ((packed));
+
+struct asd_manuf_phy_desc {
+ u8 state; /* low 4 bits */
+#define MS_PHY_STATE_ENABLEABLE 0
+#define MS_PHY_STATE_REPORTED 1
+#define MS_PHY_STATE_HIDDEN 2
+ u8 phy_id;
+ u16 _r;
+ u8 phy_control_0; /* mode 5 reg 0x160 */
+ u8 phy_control_1; /* mode 5 reg 0x161 */
+ u8 phy_control_2; /* mode 5 reg 0x162 */
+ u8 phy_control_3; /* mode 5 reg 0x163 */
+} __attribute__ ((packed));
+
+struct asd_manuf_phy_param {
+ char sig[2]; /* 'P', 'M' */
+ u16 next;
+ u8 maj; /* 0 */
+ u8 min; /* 2 */
+ u8 num_phy_desc; /* 8 */
+ u8 phy_desc_size; /* 8 */
+ u8 _r[3];
+ u8 usage_model_id;
+ u32 _r2;
+ struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_sb_type[] = {
+ "unknown",
+ "SGPIO",
+ [2 ... 0x7F] = "unknown",
+ [0x80] = "ADPT_I2C",
+ [0x81 ... 0xFF] = "VENDOR_UNIQUExx"
+};
+#endif
+
+struct asd_ms_sb_desc {
+ u8 type;
+ u8 node_desc_index;
+ u8 conn_desc_index;
+ u8 _recvd[0];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_conn_type[] = {
+ [0 ... 7] = "unknown",
+ "SFF8470",
+ "SFF8482",
+ "SFF8484",
+ [0x80] = "PCIX_DAUGHTER0",
+ [0x81] = "SAS_DAUGHTER0",
+ [0x82 ... 0xFF] = "VENDOR_UNIQUExx"
+};
+
+static const char *asd_conn_location[] = {
+ "unknown",
+ "internal",
+ "external",
+ "board_to_board",
+};
+#endif
+
+struct asd_ms_conn_desc {
+ u8 type;
+ u8 location;
+ u8 num_sideband_desc;
+ u8 size_sideband_desc;
+ u32 _resvd;
+ u8 name[16];
+ struct asd_ms_sb_desc sb_desc[0];
+} __attribute__ ((packed));
+
+struct asd_nd_phy_desc {
+ u8 vp_attch_type;
+ u8 attch_specific[0];
+} __attribute__ ((packed));
+
+#if 0
+static const char *asd_node_type[] = {
+ "IOP",
+ "IO_CONTROLLER",
+ "EXPANDER",
+ "PORT_MULTIPLIER",
+ "PORT_MULTIPLEXER",
+ "MULTI_DROP_I2C_BUS",
+};
+#endif
+
+struct asd_ms_node_desc {
+ u8 type;
+ u8 num_phy_desc;
+ u8 size_phy_desc;
+ u8 _resvd;
+ u8 name[16];
+ struct asd_nd_phy_desc phy_desc[0];
+} __attribute__ ((packed));
+
+struct asd_ms_conn_map {
+ char sig[2]; /* 'M', 'C' */
+ __le16 next;
+ u8 maj; /* 0 */
+ u8 min; /* 0 */
+ __le16 cm_size; /* size of this struct */
+ u8 num_conn;
+ u8 conn_size;
+ u8 num_nodes;
+ u8 usage_model_id;
+ u32 _resvd;
+ struct asd_ms_conn_desc conn_desc[0];
+ struct asd_ms_node_desc node_desc[0];
+} __attribute__ ((packed));
+
+struct asd_ctrla_phy_entry {
+ u8 sas_addr[SAS_ADDR_SIZE];
+ u8 sas_link_rates; /* max in hi bits, min in low bits */
+ u8 flags;
+ u8 sata_link_rates;
+ u8 _r[5];
+} __attribute__ ((packed));
+
+struct asd_ctrla_phy_settings {
+ u8 id0; /* P'h'y */
+ u8 _r;
+ u16 next;
+ u8 num_phys; /* number of PHYs in the PCI function */
+ u8 _r2[3];
+ struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS];
+} __attribute__ ((packed));
+
+struct asd_ll_el {
+ u8 id0;
+ u8 id1;
+ __le16 next;
+ u8 something_here[0];
+} __attribute__ ((packed));
+
+static int asd_poll_flash(struct asd_ha_struct *asd_ha)
+{
+ int c;
+ u8 d;
+
+ for (c = 5000; c > 0; c--) {
+ d = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
+ d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar);
+ if (!d)
+ return 0;
+ udelay(5);
+ }
+ return -ENOENT;
+}
+
+static int asd_reset_flash(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = asd_poll_flash(asd_ha);
+ if (err)
+ return err;
+ asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET);
+ err = asd_poll_flash(asd_ha);
+
+ return err;
+}
+
+static inline int asd_read_flash_seg(struct asd_ha_struct *asd_ha,
+ void *buffer, u32 offs, int size)
+{
+ asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs,
+ size);
+ return 0;
+}
+
+/**
+ * asd_find_flash_dir - finds and reads the flash directory
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to flash directory structure
+ *
+ * If found, the flash directory segment will be copied to
+ * @flash_dir. Return 1 if found, 0 if not.
+ */
+static int asd_find_flash_dir(struct asd_ha_struct *asd_ha,
+ struct asd_flash_dir *flash_dir)
+{
+ u32 v;
+ for (v = 0; v < FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) {
+ asd_read_flash_seg(asd_ha, flash_dir, v,
+ sizeof(FLASH_DIR_COOKIE)-1);
+ if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE,
+ sizeof(FLASH_DIR_COOKIE)-1) == 0) {
+ asd_ha->hw_prof.flash.dir_offs = v;
+ asd_read_flash_seg(asd_ha, flash_dir, v,
+ sizeof(*flash_dir));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int asd_flash_getid(struct asd_ha_struct *asd_ha)
+{
+ int err = 0;
+ u32 reg;
+
+ reg = asd_read_reg_dword(asd_ha, EXSICNFGR);
+
+ if (!(reg & FLASHEX)) {
+ ASD_DPRINTK("flash doesn't exist\n");
+ return -ENOENT;
+ }
+ if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR,
+ &asd_ha->hw_prof.flash.bar)) {
+ asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n",
+ pci_name(asd_ha->pcidev));
+ return -ENOENT;
+ }
+ asd_ha->hw_prof.flash.present = 1;
+ asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0;
+ err = asd_reset_flash(asd_ha);
+ if (err) {
+ ASD_DPRINTK("couldn't reset flash(%d)\n", err);
+ return err;
+ }
+ return 0;
+}
+
+static u16 asd_calc_flash_chksum(u16 *p, int size)
+{
+ u16 chksum = 0;
+
+ while (size-- > 0)
+ chksum += *p++;
+
+ return chksum;
+}
+
+
+static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type,
+ u32 *offs, u32 *size)
+{
+ int i;
+ struct asd_flash_de *de;
+
+ for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) {
+ u32 type = le32_to_cpu(flash_dir->dir_entry[i].type);
+
+ type &= FLASH_DE_TYPE_MASK;
+ if (type == entry_type)
+ break;
+ }
+ if (i >= FLASH_MAX_DIR_ENTRIES)
+ return -ENOENT;
+ de = &flash_dir->dir_entry[i];
+ *offs = le32_to_cpu(de->offs);
+ *size = le32_to_cpu(de->pad_size);
+ return 0;
+}
+
+static int asd_validate_ms(struct asd_manuf_sec *ms)
+{
+ if (ms->sig[0] != 'S' || ms->sig[1] != 'M') {
+ ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n",
+ ms->sig[0], ms->sig[1]);
+ return -ENOENT;
+ }
+ if (ms->maj != 0) {
+ asd_printk("unsupported manuf. sector. major version:%x\n",
+ ms->maj);
+ return -ENOENT;
+ }
+ ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next);
+ ms->chksum = le16_to_cpu((__force __le16) ms->chksum);
+ ms->size = le16_to_cpu((__force __le16) ms->size);
+
+ if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) {
+ asd_printk("failed manuf sector checksum\n");
+ }
+
+ return 0;
+}
+
+static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *ms)
+{
+ memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE);
+ return 0;
+}
+
+static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *ms)
+{
+ memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE);
+ asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0';
+ return 0;
+}
+
+/**
+ * asd_find_ll_by_id - find a linked list entry by its id
+ * @start: void pointer to the first element in the linked list
+ * @id0: the first byte of the id (offs 0)
+ * @id1: the second byte of the id (offs 1)
+ *
+ * @start has to be the _base_ element start, since the
+ * linked list entries's offset is from this pointer.
+ * Some linked list entries use only the first id, in which case
+ * you can pass 0xFF for the second.
+ */
+static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1)
+{
+ struct asd_ll_el *el = start;
+
+ do {
+ switch (id1) {
+ default:
+ if (el->id1 == id1)
+ case 0xFF:
+ if (el->id0 == id0)
+ return el;
+ }
+ el = start + le16_to_cpu(el->next);
+ } while (el != start);
+
+ return NULL;
+}
+
+/**
+ * asd_ms_get_phy_params - get phy parameters from the manufacturing sector
+ * @asd_ha: pointer to the host adapter structure
+ * @manuf_sec: pointer to the manufacturing sector
+ *
+ * The manufacturing sector contans also the linked list of sub-segments,
+ * since when it was read, its size was taken from the flash directory,
+ * not from the structure size.
+ *
+ * HIDDEN phys do not count in the total count. REPORTED phys cannot
+ * be enabled but are reported and counted towards the total.
+ * ENEBLEABLE phys are enabled by default and count towards the total.
+ * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys
+ * merely specifies the number of phys the host adapter decided to
+ * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN,
+ * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE.
+ * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2
+ * are actually enabled (enabled by default, max number of phys
+ * enableable in this case).
+ */
+static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *manuf_sec)
+{
+ int i;
+ int en_phys = 0;
+ int rep_phys = 0;
+ struct asd_manuf_phy_param *phy_param;
+ struct asd_manuf_phy_param dflt_phy_param;
+
+ phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M');
+ if (!phy_param) {
+ ASD_DPRINTK("ms: no phy parameters found\n");
+ ASD_DPRINTK("ms: Creating default phy parameters\n");
+ dflt_phy_param.sig[0] = 'P';
+ dflt_phy_param.sig[1] = 'M';
+ dflt_phy_param.maj = 0;
+ dflt_phy_param.min = 2;
+ dflt_phy_param.num_phy_desc = 8;
+ dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc);
+ for (i =0; i < ASD_MAX_PHYS; i++) {
+ dflt_phy_param.phy_desc[i].state = 0;
+ dflt_phy_param.phy_desc[i].phy_id = i;
+ dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6;
+ dflt_phy_param.phy_desc[i].phy_control_1 = 0x10;
+ dflt_phy_param.phy_desc[i].phy_control_2 = 0x43;
+ dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb;
+ }
+
+ phy_param = &dflt_phy_param;
+
+ }
+
+ if (phy_param->maj != 0) {
+ asd_printk("unsupported manuf. phy param major version:0x%x\n",
+ phy_param->maj);
+ return -ENOENT;
+ }
+
+ ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc);
+ asd_ha->hw_prof.enabled_phys = 0;
+ for (i = 0; i < phy_param->num_phy_desc; i++) {
+ struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i];
+ switch (pd->state & 0xF) {
+ case MS_PHY_STATE_HIDDEN:
+ ASD_DPRINTK("ms: phy%d: HIDDEN\n", i);
+ continue;
+ case MS_PHY_STATE_REPORTED:
+ ASD_DPRINTK("ms: phy%d: REPORTED\n", i);
+ asd_ha->hw_prof.enabled_phys &= ~(1 << i);
+ rep_phys++;
+ continue;
+ case MS_PHY_STATE_ENABLEABLE:
+ ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i);
+ asd_ha->hw_prof.enabled_phys |= (1 << i);
+ en_phys++;
+ break;
+ }
+ asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0;
+ asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1;
+ asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2;
+ asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3;
+ }
+ asd_ha->hw_prof.max_phys = rep_phys + en_phys;
+ asd_ha->hw_prof.num_phys = en_phys;
+ ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n",
+ asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys);
+ ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys);
+ return 0;
+}
+
+static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha,
+ struct asd_manuf_sec *manuf_sec)
+{
+ struct asd_ms_conn_map *cm;
+
+ cm = asd_find_ll_by_id(manuf_sec, 'M', 'C');
+ if (!cm) {
+ ASD_DPRINTK("ms: no connector map found\n");
+ return 0;
+ }
+
+ if (cm->maj != 0) {
+ ASD_DPRINTK("ms: unsupported: connector map major version 0x%x"
+ "\n", cm->maj);
+ return -ENOENT;
+ }
+
+ /* XXX */
+
+ return 0;
+}
+
+
+/**
+ * asd_process_ms - find and extract information from the manufacturing sector
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to the flash directory
+ */
+static int asd_process_ms(struct asd_ha_struct *asd_ha,
+ struct asd_flash_dir *flash_dir)
+{
+ int err;
+ struct asd_manuf_sec *manuf_sec;
+ u32 offs, size;
+
+ err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size);
+ if (err) {
+ ASD_DPRINTK("Couldn't find the manuf. sector\n");
+ goto out;
+ }
+
+ if (size == 0)
+ goto out;
+
+ err = -ENOMEM;
+ manuf_sec = kmalloc(size, GFP_KERNEL);
+ if (!manuf_sec) {
+ ASD_DPRINTK("no mem for manuf sector\n");
+ goto out;
+ }
+
+ err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size);
+ if (err) {
+ ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n",
+ offs, size);
+ goto out2;
+ }
+
+ err = asd_validate_ms(manuf_sec);
+ if (err) {
+ ASD_DPRINTK("couldn't validate manuf sector\n");
+ goto out2;
+ }
+
+ err = asd_ms_get_sas_addr(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("couldn't read the SAS_ADDR\n");
+ goto out2;
+ }
+ ASD_DPRINTK("manuf sect SAS_ADDR %llx\n",
+ SAS_ADDR(asd_ha->hw_prof.sas_addr));
+
+ err = asd_ms_get_pcba_sn(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("couldn't read the PCBA SN\n");
+ goto out2;
+ }
+ ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn);
+
+ err = asd_ms_get_phy_params(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("ms: couldn't get phy parameters\n");
+ goto out2;
+ }
+
+ err = asd_ms_get_connector_map(asd_ha, manuf_sec);
+ if (err) {
+ ASD_DPRINTK("ms: couldn't get connector map\n");
+ goto out2;
+ }
+
+out2:
+ kfree(manuf_sec);
+out:
+ return err;
+}
+
+static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha,
+ struct asd_ctrla_phy_settings *ps)
+{
+ int i;
+ for (i = 0; i < ps->num_phys; i++) {
+ struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i];
+
+ if (!PHY_ENABLED(asd_ha, i))
+ continue;
+ if (*(u64 *)pe->sas_addr == 0) {
+ asd_ha->hw_prof.enabled_phys &= ~(1 << i);
+ continue;
+ }
+ /* This is the SAS address which should be sent in IDENTIFY. */
+ memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr,
+ SAS_ADDR_SIZE);
+ asd_ha->hw_prof.phy_desc[i].max_sas_lrate =
+ (pe->sas_link_rates & 0xF0) >> 4;
+ asd_ha->hw_prof.phy_desc[i].min_sas_lrate =
+ (pe->sas_link_rates & 0x0F);
+ asd_ha->hw_prof.phy_desc[i].max_sata_lrate =
+ (pe->sata_link_rates & 0xF0) >> 4;
+ asd_ha->hw_prof.phy_desc[i].min_sata_lrate =
+ (pe->sata_link_rates & 0x0F);
+ asd_ha->hw_prof.phy_desc[i].flags = pe->flags;
+ ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x,"
+ " sata rate:0x%x-0x%x, flags:0x%x\n",
+ i,
+ SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr),
+ asd_ha->hw_prof.phy_desc[i].max_sas_lrate,
+ asd_ha->hw_prof.phy_desc[i].min_sas_lrate,
+ asd_ha->hw_prof.phy_desc[i].max_sata_lrate,
+ asd_ha->hw_prof.phy_desc[i].min_sata_lrate,
+ asd_ha->hw_prof.phy_desc[i].flags);
+ }
+
+ return 0;
+}
+
+/**
+ * asd_process_ctrl_a_user - process CTRL-A user settings
+ * @asd_ha: pointer to the host adapter structure
+ * @flash_dir: pointer to the flash directory
+ */
+static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha,
+ struct asd_flash_dir *flash_dir)
+{
+ int err, i;
+ u32 offs, size;
+ struct asd_ll_el *el;
+ struct asd_ctrla_phy_settings *ps;
+ struct asd_ctrla_phy_settings dflt_ps;
+
+ err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size);
+ if (err) {
+ ASD_DPRINTK("couldn't find CTRL-A user settings section\n");
+ ASD_DPRINTK("Creating default CTRL-A user settings section\n");
+
+ dflt_ps.id0 = 'h';
+ dflt_ps.num_phys = 8;
+ for (i =0; i < ASD_MAX_PHYS; i++) {
+ memcpy(dflt_ps.phy_ent[i].sas_addr,
+ asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE);
+ dflt_ps.phy_ent[i].sas_link_rates = 0x98;
+ dflt_ps.phy_ent[i].flags = 0x0;
+ dflt_ps.phy_ent[i].sata_link_rates = 0x0;
+ }
+
+ size = sizeof(struct asd_ctrla_phy_settings);
+ ps = &dflt_ps;
+ }
+
+ if (size == 0)
+ goto out;
+
+ err = -ENOMEM;
+ el = kmalloc(size, GFP_KERNEL);
+ if (!el) {
+ ASD_DPRINTK("no mem for ctrla user settings section\n");
+ goto out;
+ }
+
+ err = asd_read_flash_seg(asd_ha, (void *)el, offs, size);
+ if (err) {
+ ASD_DPRINTK("couldn't read ctrla phy settings section\n");
+ goto out2;
+ }
+
+ err = -ENOENT;
+ ps = asd_find_ll_by_id(el, 'h', 0xFF);
+ if (!ps) {
+ ASD_DPRINTK("couldn't find ctrla phy settings struct\n");
+ goto out2;
+ }
+
+ err = asd_process_ctrla_phy_settings(asd_ha, ps);
+ if (err) {
+ ASD_DPRINTK("couldn't process ctrla phy settings\n");
+ goto out2;
+ }
+out2:
+ kfree(el);
+out:
+ return err;
+}
+
+/**
+ * asd_read_flash - read flash memory
+ * @asd_ha: pointer to the host adapter structure
+ */
+int asd_read_flash(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ struct asd_flash_dir *flash_dir;
+
+ err = asd_flash_getid(asd_ha);
+ if (err)
+ return err;
+
+ flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL);
+ if (!flash_dir)
+ return -ENOMEM;
+
+ err = -ENOENT;
+ if (!asd_find_flash_dir(asd_ha, flash_dir)) {
+ ASD_DPRINTK("couldn't find flash directory\n");
+ goto out;
+ }
+
+ if (le32_to_cpu(flash_dir->rev) != 2) {
+ asd_printk("unsupported flash dir version:0x%x\n",
+ le32_to_cpu(flash_dir->rev));
+ goto out;
+ }
+
+ err = asd_process_ms(asd_ha, flash_dir);
+ if (err) {
+ ASD_DPRINTK("couldn't process manuf sector settings\n");
+ goto out;
+ }
+
+ err = asd_process_ctrl_a_user(asd_ha, flash_dir);
+ if (err) {
+ ASD_DPRINTK("couldn't process CTRL-A user settings\n");
+ goto out;
+ }
+
+out:
+ kfree(flash_dir);
+ return err;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c
new file mode 100644
index 00000000000..56e4b3ba6a0
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_seq.c
@@ -0,0 +1,1404 @@
+/*
+ * Aic94xx SAS/SATA driver sequencer interface.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * Parts of this code adapted from David Chaw's adp94xx_seq.c.
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include "aic94xx_reg.h"
+#include "aic94xx_hwi.h"
+
+#include "aic94xx_seq.h"
+#include "aic94xx_dump.h"
+
+/* It takes no more than 0.05 us for an instruction
+ * to complete. So waiting for 1 us should be more than
+ * plenty.
+ */
+#define PAUSE_DELAY 1
+#define PAUSE_TRIES 1000
+
+static const struct firmware *sequencer_fw;
+static const char *sequencer_version;
+static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task,
+ cseq_idle_loop, lseq_idle_loop;
+static u8 *cseq_code, *lseq_code;
+static u32 cseq_code_size, lseq_code_size;
+
+static u16 first_scb_site_no = 0xFFFF;
+static u16 last_scb_site_no;
+
+/* ---------- Pause/Unpause CSEQ/LSEQ ---------- */
+
+/**
+ * asd_pause_cseq - pause the central sequencer
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_pause_cseq(struct asd_ha_struct *asd_ha)
+{
+ int count = PAUSE_TRIES;
+ u32 arp2ctl;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (arp2ctl & PAUSED)
+ return 0;
+
+ asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (arp2ctl & PAUSED)
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't pause CSEQ\n");
+ return -1;
+}
+
+/**
+ * asd_unpause_cseq - unpause the central sequencer.
+ * @asd_ha: pointer to host adapter structure.
+ *
+ * Return 0 on success, negative on error.
+ */
+int asd_unpause_cseq(struct asd_ha_struct *asd_ha)
+{
+ u32 arp2ctl;
+ int count = PAUSE_TRIES;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (!(arp2ctl & PAUSED))
+ return 0;
+
+ asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL);
+ if (!(arp2ctl & PAUSED))
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't unpause the CSEQ\n");
+ return -1;
+}
+
+/**
+ * asd_seq_pause_lseq - pause a link sequencer
+ * @asd_ha: pointer to a host adapter structure
+ * @lseq: link sequencer of interest
+ *
+ * Return 0 on success, negative on error.
+ */
+static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u32 arp2ctl;
+ int count = PAUSE_TRIES;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (arp2ctl & PAUSED)
+ return 0;
+
+ asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (arp2ctl & PAUSED)
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq);
+ return -1;
+}
+
+/**
+ * asd_pause_lseq - pause the link sequencer(s)
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of link sequencers of interest
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+ int lseq;
+ int err = 0;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_seq_pause_lseq(asd_ha, lseq);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+/**
+ * asd_seq_unpause_lseq - unpause a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @lseq: link sequencer of interest
+ *
+ * Return 0 on success, negative on error.
+ */
+static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u32 arp2ctl;
+ int count = PAUSE_TRIES;
+
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (!(arp2ctl & PAUSED))
+ return 0;
+
+ asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE);
+ do {
+ arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq));
+ if (!(arp2ctl & PAUSED))
+ return 0;
+ udelay(PAUSE_DELAY);
+ } while (--count > 0);
+
+ ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq);
+ return 0;
+}
+
+
+/**
+ * asd_unpause_lseq - unpause the link sequencer(s)
+ * @asd_ha: pointer to host adapter structure
+ * @lseq_mask: mask of link sequencers of interest
+ *
+ * Return 0 on success, negative on failure.
+ */
+int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask)
+{
+ int lseq;
+ int err = 0;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_seq_unpause_lseq(asd_ha, lseq);
+ if (err)
+ return err;
+ }
+
+ return err;
+}
+
+/* ---------- Downloading CSEQ/LSEQ microcode ---------- */
+
+static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+ u32 size)
+{
+ u32 addr = CSEQ_RAM_REG_BASE_ADR;
+ const u32 *prog = (u32 *) _prog;
+ u32 i;
+
+ for (i = 0; i < size; i += 4, prog++, addr += 4) {
+ u32 val = asd_read_reg_dword(asd_ha, addr);
+
+ if (le32_to_cpu(*prog) != val) {
+ asd_printk("%s: cseq verify failed at %u "
+ "read:0x%x, wanted:0x%x\n",
+ pci_name(asd_ha->pcidev),
+ i, val, le32_to_cpu(*prog));
+ return -1;
+ }
+ }
+ ASD_DPRINTK("verified %d bytes, passed\n", size);
+ return 0;
+}
+
+/**
+ * asd_verify_lseq - verify the microcode of a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @_prog: pointer to the microcode
+ * @size: size of the microcode in bytes
+ * @lseq: link sequencer of interest
+ *
+ * The link sequencer code is accessed in 4 KB pages, which are selected
+ * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register.
+ * The 10 KB LSEQm instruction code is mapped, page at a time, at
+ * LmSEQRAM address.
+ */
+static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+ u32 size, int lseq)
+{
+#define LSEQ_CODEPAGE_SIZE 4096
+ int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE;
+ u32 page;
+ const u32 *prog = (u32 *) _prog;
+
+ for (page = 0; page < pages; page++) {
+ u32 i;
+
+ asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq),
+ page << LmRAMPAGE_LSHIFT);
+ for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE;
+ i += 4, prog++, size-=4) {
+
+ u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i);
+
+ if (le32_to_cpu(*prog) != val) {
+ asd_printk("%s: LSEQ%d verify failed "
+ "page:%d, offs:%d\n",
+ pci_name(asd_ha->pcidev),
+ lseq, page, i);
+ return -1;
+ }
+ }
+ }
+ ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq,
+ (int)((u8 *)prog-_prog));
+ return 0;
+}
+
+/**
+ * asd_verify_seq -- verify CSEQ/LSEQ microcode
+ * @asd_ha: pointer to host adapter structure
+ * @prog: pointer to microcode
+ * @size: size of the microcode
+ * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest
+ *
+ * Return 0 if microcode is correct, negative on mismatch.
+ */
+static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog,
+ u32 size, u8 lseq_mask)
+{
+ if (lseq_mask == 0)
+ return asd_verify_cseq(asd_ha, prog, size);
+ else {
+ int lseq, err;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_verify_lseq(asd_ha, prog, size, lseq);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+#define ASD_DMA_MODE_DOWNLOAD
+#ifdef ASD_DMA_MODE_DOWNLOAD
+/* This is the size of the CSEQ Mapped instruction page */
+#define MAX_DMA_OVLY_COUNT ((1U << 14)-1)
+static int asd_download_seq(struct asd_ha_struct *asd_ha,
+ const u8 * const prog, u32 size, u8 lseq_mask)
+{
+ u32 comstaten;
+ u32 reg;
+ int page;
+ const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT;
+ struct asd_dma_tok *token;
+ int err = 0;
+
+ if (size % 4) {
+ asd_printk("sequencer program not multiple of 4\n");
+ return -1;
+ }
+
+ asd_pause_cseq(asd_ha);
+ asd_pause_lseq(asd_ha, 0xFF);
+
+ /* save, disable and clear interrupts */
+ comstaten = asd_read_reg_dword(asd_ha, COMSTATEN);
+ asd_write_reg_dword(asd_ha, COMSTATEN, 0);
+ asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK);
+
+ asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN);
+ asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK);
+
+ token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL);
+ if (!token) {
+ asd_printk("out of memory for dma SEQ download\n");
+ err = -ENOMEM;
+ goto out;
+ }
+ ASD_DPRINTK("dma-ing %d bytes\n", size);
+
+ for (page = 0; page < pages; page++) {
+ int i;
+ u32 left = min(size-page*MAX_DMA_OVLY_COUNT,
+ (u32)MAX_DMA_OVLY_COUNT);
+
+ memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left);
+ asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle);
+ asd_write_reg_dword(asd_ha, OVLYDMACNT, left);
+ reg = !page ? RESETOVLYDMA : 0;
+ reg |= (STARTOVLYDMA | OVLYHALTERR);
+ reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
+ /* Start DMA. */
+ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+ for (i = PAUSE_TRIES*100; i > 0; i--) {
+ u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL);
+ if (!(dmadone & OVLYDMAACT))
+ break;
+ udelay(PAUSE_DELAY);
+ }
+ }
+
+ reg = asd_read_reg_dword(asd_ha, COMSTAT);
+ if (!(reg & OVLYDMADONE) || (reg & OVLYERR)
+ || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){
+ asd_printk("%s: error DMA-ing sequencer code\n",
+ pci_name(asd_ha->pcidev));
+ err = -ENODEV;
+ }
+
+ asd_free_coherent(asd_ha, token);
+ out:
+ asd_write_reg_dword(asd_ha, COMSTATEN, comstaten);
+
+ return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask);
+}
+#else /* ASD_DMA_MODE_DOWNLOAD */
+static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog,
+ u32 size, u8 lseq_mask)
+{
+ int i;
+ u32 reg = 0;
+ const u32 *prog = (u32 *) _prog;
+
+ if (size % 4) {
+ asd_printk("sequencer program not multiple of 4\n");
+ return -1;
+ }
+
+ asd_pause_cseq(asd_ha);
+ asd_pause_lseq(asd_ha, 0xFF);
+
+ reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ);
+ reg |= PIOCMODE;
+
+ asd_write_reg_dword(asd_ha, OVLYDMACNT, size);
+ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+ ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n",
+ lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : "");
+
+ for (i = 0; i < size; i += 4, prog++)
+ asd_write_reg_dword(asd_ha, SPIODATA, *prog);
+
+ reg = (reg & ~PIOCMODE) | OVLYHALTERR;
+ asd_write_reg_dword(asd_ha, OVLYDMACTL, reg);
+
+ return asd_verify_seq(asd_ha, _prog, size, lseq_mask);
+}
+#endif /* ASD_DMA_MODE_DOWNLOAD */
+
+/**
+ * asd_seq_download_seqs - download the sequencer microcode
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Download the central and link sequencer microcode.
+ */
+static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ if (!asd_ha->hw_prof.enabled_phys) {
+ asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev));
+ return -ENODEV;
+ }
+
+ /* Download the CSEQ */
+ ASD_DPRINTK("downloading CSEQ...\n");
+ err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0);
+ if (err) {
+ asd_printk("CSEQ download failed:%d\n", err);
+ return err;
+ }
+
+ /* Download the Link Sequencers code. All of the Link Sequencers
+ * microcode can be downloaded at the same time.
+ */
+ ASD_DPRINTK("downloading LSEQs...\n");
+ err = asd_download_seq(asd_ha, lseq_code, lseq_code_size,
+ asd_ha->hw_prof.enabled_phys);
+ if (err) {
+ /* Try it one at a time */
+ u8 lseq;
+ u8 lseq_mask = asd_ha->hw_prof.enabled_phys;
+
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_download_seq(asd_ha, lseq_code,
+ lseq_code_size, 1<<lseq);
+ if (err)
+ break;
+ }
+ }
+ if (err)
+ asd_printk("LSEQs download failed:%d\n", err);
+
+ return err;
+}
+
+/* ---------- Initializing the chip, chip memory, etc. ---------- */
+
+/**
+ * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha)
+{
+ /* CSEQ Mode Independent, page 4 setup. */
+ asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_REG0, 0);
+ asd_write_reg_word(asd_ha, CSEQ_REG1, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_REG2, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0);
+ {
+ u8 con = asd_read_reg_byte(asd_ha, CCONEXIST);
+ u8 val = hweight8(con);
+ asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val);
+ }
+ asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0);
+
+ /* CSEQ Mode independent, page 5 setup. */
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0);
+
+ /* CSEQ Mode independent, page 6 setup. */
+ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0);
+ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0);
+ asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0);
+ asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0);
+ asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0);
+ asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF);
+ /* Calculate the free scb mask. */
+ {
+ u16 cmdctx = asd_get_cmdctx_size(asd_ha);
+ cmdctx = (~((cmdctx/128)-1)) >> 8;
+ asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx);
+ }
+ asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD,
+ first_scb_site_no);
+ asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL,
+ last_scb_site_no);
+ asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF);
+
+ /* CSEQ Mode independent, page 7 setup. */
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0);
+ asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0);
+}
+
+/**
+ * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha)
+{
+ int i;
+ int moffs;
+
+ moffs = CSEQ_PAGE_SIZE * 2;
+
+ /* CSEQ Mode dependent, modes 0-7, page 0 setup. */
+ for (i = 0; i < 8; i++) {
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0);
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF);
+ asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF);
+ asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0);
+ }
+
+ /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */
+
+ /* CSEQ Mode dependent, mode 8, page 0 setup. */
+ asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF);
+ asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0);
+ asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0);
+ asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0);
+ asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0);
+ asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0);
+ asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0);
+ asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0);
+ asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0);
+ asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE,
+ (u16)last_scb_site_no+1);
+ asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE,
+ (u16)asd_ha->hw_prof.max_ddbs);
+
+ /* CSEQ Mode dependent, mode 8, page 1 setup. */
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0);
+ asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0);
+
+ /* CSEQ Mode dependent, mode 8, page 2 setup. */
+ /* Tell the sequencer the bus address of the first SCB. */
+ asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER,
+ asd_ha->seq.next_scb.dma_handle);
+ ASD_DPRINTK("First SCB dma_handle: 0x%llx\n",
+ (unsigned long long)asd_ha->seq.next_scb.dma_handle);
+
+ /* Tell the sequencer the first Done List entry address. */
+ asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE,
+ asd_ha->seq.actual_dl->dma_handle);
+
+ /* Initialize the Q_DONE_POINTER with the least significant
+ * 4 bytes of the first Done List address. */
+ asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER,
+ ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle));
+
+ asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE);
+
+ /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */
+}
+
+/**
+ * asd_init_cseq_scratch -- setup and init CSEQ
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Setup and initialize Central sequencers. Initialiaze the mode
+ * independent and dependent scratch page to the default settings.
+ */
+static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha)
+{
+ asd_init_cseq_mip(asd_ha);
+ asd_init_cseq_mdp(asd_ha);
+}
+
+/**
+ * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq)
+{
+ int i;
+
+ /* LSEQ Mode independent page 0 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq);
+ asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq),
+ ASD_NOTIFY_ENABLE_SPINUP);
+ asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000);
+ asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0);
+
+ /* LSEQ Mode independent page 1 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0);
+
+ /* LSEQ Mode Independent page 2 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0);
+ for (i = 0; i < 12; i += 4)
+ asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0);
+
+ /* LSEQ Mode Independent page 3 setup. */
+
+ /* Device present timer timeout */
+ asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq),
+ ASD_DEV_PRESENT_TIMEOUT);
+
+ /* SATA interlock timer disabled */
+ asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq),
+ ASD_SATA_INTERLOCK_TIMEOUT);
+
+ /* STP shutdown timer timeout constant, IGNORED by the sequencer,
+ * always 0. */
+ asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq),
+ ASD_STP_SHUTDOWN_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq),
+ ASD_SRST_ASSERT_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq),
+ ASD_RCV_FIS_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq),
+ ASD_ONE_MILLISEC_TIMEOUT);
+
+ /* COM_INIT timer */
+ asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq),
+ ASD_TEN_MILLISEC_TIMEOUT);
+
+ asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq),
+ ASD_SMP_RCV_TIMEOUT);
+}
+
+/**
+ * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages.
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq)
+{
+ int i;
+ u32 moffs;
+ u16 ret_addr[] = {
+ 0xFFFF, /* mode 0 */
+ 0xFFFF, /* mode 1 */
+ mode2_task, /* mode 2 */
+ 0,
+ 0xFFFF, /* mode 4/5 */
+ 0xFFFF, /* mode 4/5 */
+ };
+
+ /*
+ * Mode 0,1,2 and 4/5 have common field on page 0 for the first
+ * 14 bytes.
+ */
+ for (i = 0; i < 3; i++) {
+ moffs = i * LSEQ_MODE_SCRATCH_SIZE;
+ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs,
+ ret_addr[i]);
+ asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0);
+ asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0);
+ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0);
+ asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0);
+ }
+ /*
+ * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3.
+ */
+ asd_write_reg_word(asd_ha,
+ LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET,
+ ret_addr[5]);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF);
+ asd_write_reg_byte(asd_ha,
+ LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0);
+ asd_write_reg_word(asd_ha,
+ LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0);
+
+ /* LSEQ Mode dependent 0, page 0 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq),
+ (u16)asd_ha->hw_prof.max_ddbs);
+ asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq),
+ (u16)last_scb_site_no+1);
+ asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq),
+ (u16) ((LmM0INTEN_MASK & 0xFFFF0000) >> 16));
+ asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2,
+ (u16) LmM0INTEN_MASK & 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0);
+
+ /* LSEQ mode dependent, mode 1, page 0 setup. */
+ asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF);
+ asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0);
+
+ /* LSEQ Mode dependent mode 2, page 0 setup */
+ asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0);
+
+ /* LSEQ Mode dependent, mode 4/5, page 0 setup. */
+ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0);
+ /*
+ * Set the desired interval between transmissions of the NOTIFY
+ * (ENABLE SPINUP) primitive. Must be initilized to val - 1.
+ */
+ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq),
+ ASD_NOTIFY_TIMEOUT - 1);
+ /* No delay for the first NOTIFY to be sent to the attached target. */
+ asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq),
+ ASD_NOTIFY_DOWN_COUNT);
+
+ /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */
+ for (i = 0; i < 2; i++) {
+ int j;
+ /* Start from Page 1 of Mode 0 and 1. */
+ moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE;
+ /* All the fields of page 1 can be intialized to 0. */
+ for (j = 0; j < LSEQ_PAGE_SIZE; j += 4)
+ asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0);
+ }
+
+ /* LSEQ Mode dependent, mode 2, page 1 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0);
+
+ /* LSEQ Mode dependent, mode 4/5, page 1. */
+ for (i = 0; i < LSEQ_PAGE_SIZE; i+=4)
+ asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF);
+ asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF);
+ asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF);
+
+ /* LSEQ Mode dependent, mode 0, page 2 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0);
+ asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0);
+ asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0);
+
+ /* LSEQ Mode Dependent 1, page 2 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0);
+
+ /* LSEQ Mode Dependent 2, page 2 setup. */
+ /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer,
+ * i.e. always 0. */
+ asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0);
+ asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0);
+ asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0);
+
+ /* LSEQ Mode Dependent 4/5, page 2 setup. */
+ asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0);
+ asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0);
+}
+
+/**
+ * asd_init_lseq_scratch -- setup and init link sequencers
+ * @asd_ha: pointer to host adapter struct
+ */
+static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha)
+{
+ u8 lseq;
+ u8 lseq_mask;
+
+ lseq_mask = asd_ha->hw_prof.enabled_phys;
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ asd_init_lseq_mip(asd_ha, lseq);
+ asd_init_lseq_mdp(asd_ha, lseq);
+ }
+}
+
+/**
+ * asd_init_scb_sites -- initialize sequencer SCB sites (memory).
+ * @asd_ha: pointer to host adapter structure
+ *
+ * This should be done before initializing common CSEQ and LSEQ
+ * scratch since those areas depend on some computed values here,
+ * last_scb_site_no, etc.
+ */
+static void asd_init_scb_sites(struct asd_ha_struct *asd_ha)
+{
+ u16 site_no;
+ u16 max_scbs = 0;
+
+ for (site_no = asd_ha->hw_prof.max_scbs-1;
+ site_no != (u16) -1;
+ site_no--) {
+ u16 i;
+
+ /* Initialize all fields in the SCB site to 0. */
+ for (i = 0; i < ASD_SCB_SIZE; i += 4)
+ asd_scbsite_write_dword(asd_ha, site_no, i, 0);
+
+ /* Workaround needed by SEQ to fix a SATA issue is to exclude
+ * certain SCB sites from the free list. */
+ if (!SCB_SITE_VALID(site_no))
+ continue;
+
+ if (last_scb_site_no == 0)
+ last_scb_site_no = site_no;
+
+ /* For every SCB site, we need to initialize the
+ * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS,
+ * and SG Element Flag. */
+
+ /* Q_NEXT field of the last SCB is invalidated. */
+ asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no);
+
+ /* Initialize SCB Site Opcode field to invalid. */
+ asd_scbsite_write_byte(asd_ha, site_no,
+ offsetof(struct scb_header, opcode),
+ 0xFF);
+
+ /* Initialize SCB Site Flags field to mean a response
+ * frame has been received. This means inadvertent
+ * frames received to be dropped. */
+ asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01);
+
+ first_scb_site_no = site_no;
+ max_scbs++;
+ }
+ asd_ha->hw_prof.max_scbs = max_scbs;
+ ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs);
+ ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no);
+ ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no);
+}
+
+/**
+ * asd_init_cseq_cio - initialize CSEQ CIO registers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0);
+ asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS);
+ asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0);
+ asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0);
+ asd_ha->seq.scbpro = 0;
+ asd_write_reg_dword(asd_ha, SCBPRO, 0);
+ asd_write_reg_dword(asd_ha, CSEQCON, 0);
+
+ /* Intialize CSEQ Mode 11 Interrupt Vectors.
+ * The addresses are 16 bit wide and in dword units.
+ * The values of their macros are in byte units.
+ * Thus we have to divide by 4. */
+ asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]);
+ asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]);
+ asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]);
+
+ /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
+ asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC);
+
+ /* Initialize CSEQ Scratch Page to 0x04. */
+ asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04);
+
+ /* Initialize CSEQ Mode[0-8] Dependent registers. */
+ /* Initialize Scratch Page to 0. */
+ for (i = 0; i < 9; i++)
+ asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0);
+
+ /* Reset the ARP2 Program Count. */
+ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
+
+ for (i = 0; i < 8; i++) {
+ /* Intialize Mode n Link m Interrupt Enable. */
+ asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF);
+ /* Initialize Mode n Request Mailbox. */
+ asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0);
+ }
+}
+
+/**
+ * asd_init_lseq_cio -- initialize LmSEQ CIO registers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq)
+{
+ u8 *sas_addr;
+ int i;
+
+ /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */
+ asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC);
+
+ asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0);
+
+ /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */
+ for (i = 0; i < 3; i++)
+ asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0);
+
+ /* Initialize Mode 5 SCRATCHPAGE to 0. */
+ asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0);
+
+ asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0);
+ /* Initialize Mode 0,1,2 and 5 Interrupt Enable and
+ * Interrupt registers. */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF);
+ /* Mode 1 */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF);
+ /* Mode 2 */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF);
+ /* Mode 5 */
+ asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK);
+ asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF);
+
+ /* Enable HW Timer status. */
+ asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK);
+
+ /* Enable Primitive Status 0 and 1. */
+ asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK);
+ asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK);
+
+ /* Enable Frame Error. */
+ asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK);
+ asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50);
+
+ /* Initialize Mode 0 Transfer Level to 512. */
+ asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512);
+ /* Initialize Mode 1 Transfer Level to 256. */
+ asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256);
+
+ /* Initialize Program Count. */
+ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop);
+
+ /* Enable Blind SG Move. */
+ asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48);
+ asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq),
+ ASD_SATA_INTERLOCK_TIMEOUT);
+
+ (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq));
+
+ /* Clear Primitive Status 0 and 1. */
+ asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF);
+ asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF);
+
+ /* Clear HW Timer status. */
+ asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF);
+
+ /* Clear DMA Errors for Mode 0 and 1. */
+ asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF);
+ asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF);
+
+ /* Clear SG DMA Errors for Mode 0 and 1. */
+ asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF);
+ asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF);
+
+ /* Clear Mode 0 Buffer Parity Error. */
+ asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR);
+
+ /* Clear Mode 0 Frame Error register. */
+ asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF);
+
+ /* Reset LSEQ external interrupt arbiter. */
+ asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL);
+
+ /* Set the Phy SAS for the LmSEQ WWN. */
+ sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr;
+ for (i = 0; i < SAS_ADDR_SIZE; i++)
+ asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]);
+
+ /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */
+ asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0);
+
+ /* Set the Bus Inactivity Time Limit Timer. */
+ asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9);
+
+ /* Enable SATA Port Multiplier. */
+ asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80);
+
+ /* Initialize Interrupt Vector[0-10] address in Mode 3.
+ * See the comment on CSEQ_INT_* */
+ asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]);
+ asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]);
+ /*
+ * Program the Link LED control, applicable only for
+ * Chip Rev. B or later.
+ */
+ asd_write_reg_dword(asd_ha, LmCONTROL(lseq),
+ (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms));
+
+ /* Set the Align Rate for SAS and STP mode. */
+ asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT);
+ asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT);
+}
+
+
+/**
+ * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox
+ * @asd_ha: pointer to host adapter struct
+ */
+static void asd_post_init_cseq(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF);
+ for (i = 0; i < 8; i++)
+ asd_read_reg_dword(asd_ha, CMnRSPMBX(i));
+ /* Reset the external interrupt arbiter. */
+ asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL);
+}
+
+/**
+ * asd_init_ddb_0 -- initialize DDB 0
+ * @asd_ha: pointer to host adapter structure
+ *
+ * Initialize DDB site 0 which is used internally by the sequencer.
+ */
+static void asd_init_ddb_0(struct asd_ha_struct *asd_ha)
+{
+ int i;
+
+ /* Zero out the DDB explicitly */
+ for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4)
+ asd_ddbsite_write_dword(asd_ha, 0, i, 0);
+
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail),
+ asd_ha->hw_prof.max_ddbs-1);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0);
+ asd_ddbsite_write_word(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh),
+ asd_ha->hw_prof.num_phys * 2);
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0);
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF);
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00);
+ /* DDB 0 is reserved */
+ set_bit(0, asd_ha->hw_prof.ddb_bitmap);
+}
+
+/**
+ * asd_seq_setup_seqs -- setup and initialize central and link sequencers
+ * @asd_ha: pointer to host adapter structure
+ */
+static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha)
+{
+ int lseq;
+ u8 lseq_mask;
+
+ /* Initialize SCB sites. Done first to compute some values which
+ * the rest of the init code depends on. */
+ asd_init_scb_sites(asd_ha);
+
+ /* Initialize CSEQ Scratch RAM registers. */
+ asd_init_cseq_scratch(asd_ha);
+
+ /* Initialize LmSEQ Scratch RAM registers. */
+ asd_init_lseq_scratch(asd_ha);
+
+ /* Initialize CSEQ CIO registers. */
+ asd_init_cseq_cio(asd_ha);
+
+ asd_init_ddb_0(asd_ha);
+
+ /* Initialize LmSEQ CIO registers. */
+ lseq_mask = asd_ha->hw_prof.enabled_phys;
+ for_each_sequencer(lseq_mask, lseq_mask, lseq)
+ asd_init_lseq_cio(asd_ha, lseq);
+ asd_post_init_cseq(asd_ha);
+}
+
+
+/**
+ * asd_seq_start_cseq -- start the central sequencer, CSEQ
+ * @asd_ha: pointer to host adapter structure
+ */
+static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha)
+{
+ /* Reset the ARP2 instruction to location zero. */
+ asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop);
+
+ /* Unpause the CSEQ */
+ return asd_unpause_cseq(asd_ha);
+}
+
+/**
+ * asd_seq_start_lseq -- start a link sequencer
+ * @asd_ha: pointer to host adapter structure
+ * @lseq: the link sequencer of interest
+ */
+static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq)
+{
+ /* Reset the ARP2 instruction to location zero. */
+ asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop);
+
+ /* Unpause the LmSEQ */
+ return asd_seq_unpause_lseq(asd_ha, lseq);
+}
+
+static int asd_request_firmware(struct asd_ha_struct *asd_ha)
+{
+ int err, i;
+ struct sequencer_file_header header, *hdr_ptr;
+ u32 csum = 0;
+ u16 *ptr_cseq_vecs, *ptr_lseq_vecs;
+
+ if (sequencer_fw)
+ /* already loaded */
+ return 0;
+
+ err = request_firmware(&sequencer_fw,
+ SAS_RAZOR_SEQUENCER_FW_FILE,
+ &asd_ha->pcidev->dev);
+ if (err)
+ return err;
+
+ hdr_ptr = (struct sequencer_file_header *)sequencer_fw->data;
+
+ header.csum = le32_to_cpu(hdr_ptr->csum);
+ header.major = le32_to_cpu(hdr_ptr->major);
+ header.minor = le32_to_cpu(hdr_ptr->minor);
+ sequencer_version = hdr_ptr->version;
+ header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset);
+ header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size);
+ header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset);
+ header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size);
+ header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset);
+ header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size);
+ header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset);
+ header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size);
+ header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task);
+ header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop);
+ header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop);
+
+ for (i = sizeof(header.csum); i < sequencer_fw->size; i++)
+ csum += sequencer_fw->data[i];
+
+ if (csum != header.csum) {
+ asd_printk("Firmware file checksum mismatch\n");
+ return -EINVAL;
+ }
+
+ if (header.cseq_table_size != CSEQ_NUM_VECS ||
+ header.lseq_table_size != LSEQ_NUM_VECS) {
+ asd_printk("Firmware file table size mismatch\n");
+ return -EINVAL;
+ }
+
+ ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset];
+ ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset];
+ mode2_task = header.mode2_task;
+ cseq_idle_loop = header.cseq_idle_loop;
+ lseq_idle_loop = header.lseq_idle_loop;
+
+ for (i = 0; i < CSEQ_NUM_VECS; i++)
+ cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]);
+
+ for (i = 0; i < LSEQ_NUM_VECS; i++)
+ lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]);
+
+ cseq_code = &sequencer_fw->data[header.cseq_code_offset];
+ cseq_code_size = header.cseq_code_size;
+ lseq_code = &sequencer_fw->data[header.lseq_code_offset];
+ lseq_code_size = header.lseq_code_size;
+
+ return 0;
+}
+
+int asd_init_seqs(struct asd_ha_struct *asd_ha)
+{
+ int err;
+
+ err = asd_request_firmware(asd_ha);
+
+ if (err) {
+ asd_printk("Failed to load sequencer firmware file %s, error %d\n",
+ SAS_RAZOR_SEQUENCER_FW_FILE, err);
+ return err;
+ }
+
+ asd_printk("using sequencer %s\n", sequencer_version);
+ err = asd_seq_download_seqs(asd_ha);
+ if (err) {
+ asd_printk("couldn't download sequencers for %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+
+ asd_seq_setup_seqs(asd_ha);
+
+ return 0;
+}
+
+int asd_start_seqs(struct asd_ha_struct *asd_ha)
+{
+ int err;
+ u8 lseq_mask;
+ int lseq;
+
+ err = asd_seq_start_cseq(asd_ha);
+ if (err) {
+ asd_printk("couldn't start CSEQ for %s\n",
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+
+ lseq_mask = asd_ha->hw_prof.enabled_phys;
+ for_each_sequencer(lseq_mask, lseq_mask, lseq) {
+ err = asd_seq_start_lseq(asd_ha, lseq);
+ if (err) {
+ asd_printk("coudln't start LSEQ %d for %s\n", lseq,
+ pci_name(asd_ha->pcidev));
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * asd_update_port_links -- update port_map_by_links and phy_is_up
+ * @sas_phy: pointer to the phy which has been added to a port
+ *
+ * 1) When a link reset has completed and we got BYTES DMAED with a
+ * valid frame we call this function for that phy, to indicate that
+ * the phy is up, i.e. we update the phy_is_up in DDB 0. The
+ * sequencer checks phy_is_up when pending SCBs are to be sent, and
+ * when an open address frame has been received.
+ *
+ * 2) When we know of ports, we call this function to update the map
+ * of phys participaing in that port, i.e. we update the
+ * port_map_by_links in DDB 0. When a HARD_RESET primitive has been
+ * received, the sequencer disables all phys in that port.
+ * port_map_by_links is also used as the conn_mask byte in the
+ * initiator/target port DDB.
+ */
+void asd_update_port_links(struct asd_sas_phy *sas_phy)
+{
+ struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha;
+ const u8 phy_mask = (u8) sas_phy->port->phy_mask;
+ u8 phy_is_up;
+ u8 mask;
+ int i, err;
+
+ for_each_phy(phy_mask, mask, i)
+ asd_ddbsite_write_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared,
+ port_map_by_links)+i,phy_mask);
+
+ for (i = 0; i < 12; i++) {
+ phy_is_up = asd_ddbsite_read_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, phy_is_up));
+ err = asd_ddbsite_update_byte(asd_ha, 0,
+ offsetof(struct asd_ddb_seq_shared, phy_is_up),
+ phy_is_up,
+ phy_is_up | phy_mask);
+ if (!err)
+ break;
+ else if (err == -EFAULT) {
+ asd_printk("phy_is_up: parity error in DDB 0\n");
+ break;
+ }
+ }
+
+ if (err)
+ asd_printk("couldn't update DDB 0:error:%d\n", err);
+}
+
+MODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE);
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h
new file mode 100644
index 00000000000..42281c36153
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_seq.h
@@ -0,0 +1,70 @@
+/*
+ * Aic94xx SAS/SATA driver sequencer interface header file.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AIC94XX_SEQ_H_
+#define _AIC94XX_SEQ_H_
+
+#define CSEQ_NUM_VECS 3
+#define LSEQ_NUM_VECS 11
+
+#define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw"
+
+/* Note: All quantites in the sequencer file are little endian */
+struct sequencer_file_header {
+ /* Checksum of the entire contents of the sequencer excluding
+ * these four bytes */
+ u32 csum;
+ /* numeric major version */
+ u32 major;
+ /* numeric minor version */
+ u32 minor;
+ /* version string printed by driver */
+ char version[16];
+ u32 cseq_table_offset;
+ u32 cseq_table_size;
+ u32 lseq_table_offset;
+ u32 lseq_table_size;
+ u32 cseq_code_offset;
+ u32 cseq_code_size;
+ u32 lseq_code_offset;
+ u32 lseq_code_size;
+ u16 mode2_task;
+ u16 cseq_idle_loop;
+ u16 lseq_idle_loop;
+} __attribute__((packed));
+
+#ifdef __KERNEL__
+int asd_pause_cseq(struct asd_ha_struct *asd_ha);
+int asd_unpause_cseq(struct asd_ha_struct *asd_ha);
+int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
+int asd_init_seqs(struct asd_ha_struct *asd_ha);
+int asd_start_seqs(struct asd_ha_struct *asd_ha);
+
+void asd_update_port_links(struct asd_sas_phy *phy);
+#endif
+
+#endif
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
new file mode 100644
index 00000000000..d202ed5a670
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -0,0 +1,642 @@
+/*
+ * Aic94xx SAS/SATA Tasks
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/spinlock.h>
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+#include "aic94xx_hwi.h"
+
+static void asd_unbuild_ata_ascb(struct asd_ascb *a);
+static void asd_unbuild_smp_ascb(struct asd_ascb *a);
+static void asd_unbuild_ssp_ascb(struct asd_ascb *a);
+
+static inline void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ asd_ha->seq.can_queue += num;
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+}
+
+/* PCI_DMA_... to our direction translation.
+ */
+static const u8 data_dir_flags[] = {
+ [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */
+ [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */
+ [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */
+ [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */
+};
+
+static inline int asd_map_scatterlist(struct sas_task *task,
+ struct sg_el *sg_arr,
+ gfp_t gfp_flags)
+{
+ struct asd_ascb *ascb = task->lldd_task;
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct scatterlist *sc;
+ int num_sg, res;
+
+ if (task->data_dir == PCI_DMA_NONE)
+ return 0;
+
+ if (task->num_scatter == 0) {
+ void *p = task->scatter;
+ dma_addr_t dma = pci_map_single(asd_ha->pcidev, p,
+ task->total_xfer_len,
+ task->data_dir);
+ sg_arr[0].bus_addr = cpu_to_le64((u64)dma);
+ sg_arr[0].size = cpu_to_le32(task->total_xfer_len);
+ sg_arr[0].flags |= ASD_SG_EL_LIST_EOL;
+ return 0;
+ }
+
+ num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
+ if (num_sg == 0)
+ return -ENOMEM;
+
+ if (num_sg > 3) {
+ int i;
+
+ ascb->sg_arr = asd_alloc_coherent(asd_ha,
+ num_sg*sizeof(struct sg_el),
+ gfp_flags);
+ if (!ascb->sg_arr) {
+ res = -ENOMEM;
+ goto err_unmap;
+ }
+ for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+ struct sg_el *sg =
+ &((struct sg_el *)ascb->sg_arr->vaddr)[i];
+ sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc));
+ sg->size = cpu_to_le32((u32)sg_dma_len(sc));
+ if (i == num_sg-1)
+ sg->flags |= ASD_SG_EL_LIST_EOL;
+ }
+
+ for (sc = task->scatter, i = 0; i < 2; i++, sc++) {
+ sg_arr[i].bus_addr =
+ cpu_to_le64((u64)sg_dma_address(sc));
+ sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
+ }
+ sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr);
+ sg_arr[1].flags |= ASD_SG_EL_LIST_EOS;
+
+ memset(&sg_arr[2], 0, sizeof(*sg_arr));
+ sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle);
+ } else {
+ int i;
+ for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) {
+ sg_arr[i].bus_addr =
+ cpu_to_le64((u64)sg_dma_address(sc));
+ sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc));
+ }
+ sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL;
+ }
+
+ return 0;
+err_unmap:
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
+ return res;
+}
+
+static inline void asd_unmap_scatterlist(struct asd_ascb *ascb)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_task *task = ascb->uldd_task;
+
+ if (task->data_dir == PCI_DMA_NONE)
+ return;
+
+ if (task->num_scatter == 0) {
+ dma_addr_t dma = (dma_addr_t)
+ le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr);
+ pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len,
+ task->data_dir);
+ return;
+ }
+
+ asd_free_coherent(asd_ha, ascb->sg_arr);
+ pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter,
+ task->data_dir);
+}
+
+/* ---------- Task complete tasklet ---------- */
+
+static void asd_get_response_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct sas_task *task = ascb->uldd_task;
+ struct task_status_struct *ts = &task->task_status;
+ unsigned long flags;
+ struct tc_resp_sb_struct {
+ __le16 index_escb;
+ u8 len_lsb;
+ u8 flags;
+ } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
+
+/* int size = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */
+ int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
+ struct asd_ascb *escb;
+ struct asd_dma_tok *edb;
+ void *r;
+
+ spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
+ escb = asd_tc_index_find(&asd_ha->seq,
+ (int)le16_to_cpu(resp_sb->index_escb));
+ spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
+
+ if (!escb) {
+ ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
+ return;
+ }
+
+ ts->buf_valid_size = 0;
+ edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+ r = edb->vaddr;
+ if (task->task_proto == SAS_PROTO_SSP) {
+ struct ssp_response_iu *iu =
+ r + 16 + sizeof(struct ssp_frame_hdr);
+
+ ts->residual = le32_to_cpu(*(__le32 *)r);
+ ts->resp = SAS_TASK_COMPLETE;
+ if (iu->datapres == 0)
+ ts->stat = iu->status;
+ else if (iu->datapres == 1)
+ ts->stat = iu->resp_data[3];
+ else if (iu->datapres == 2) {
+ ts->stat = SAM_CHECK_COND;
+ ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE,
+ be32_to_cpu(iu->sense_data_len));
+ memcpy(ts->buf, iu->sense_data, ts->buf_valid_size);
+ if (iu->status != SAM_CHECK_COND) {
+ ASD_DPRINTK("device %llx sent sense data, but "
+ "stat(0x%x) is not CHECK_CONDITION"
+ "\n",
+ SAS_ADDR(task->dev->sas_addr),
+ ts->stat);
+ }
+ }
+ } else {
+ struct ata_task_resp *resp = (void *) &ts->buf[0];
+
+ ts->residual = le32_to_cpu(*(__le32 *)r);
+
+ if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
+ resp->frame_len = le16_to_cpu(*(__le16 *)(r+6));
+ memcpy(&resp->ending_fis[0], r+16, 24);
+ ts->buf_valid_size = sizeof(*resp);
+ }
+ }
+
+ asd_invalidate_edb(escb, edb_id);
+}
+
+static void asd_task_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct sas_task *task = ascb->uldd_task;
+ struct task_status_struct *ts = &task->task_status;
+ unsigned long flags;
+ u8 opcode = dl->opcode;
+
+ asd_can_dequeue(ascb->ha, 1);
+
+Again:
+ switch (opcode) {
+ case TC_NO_ERROR:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAM_GOOD;
+ break;
+ case TC_UNDERRUN:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_UNDERRUN;
+ ts->residual = le32_to_cpu(*(__le32 *)dl->status_block);
+ break;
+ case TC_OVERRUN:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_DATA_OVERRUN;
+ ts->residual = 0;
+ break;
+ case TC_SSP_RESP:
+ case TC_ATA_RESP:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PROTO_RESPONSE;
+ asd_get_response_tasklet(ascb, dl);
+ break;
+ case TF_OPEN_REJECT:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_REJECT;
+ if (dl->status_block[1] & 2)
+ ts->open_rej_reason = 1 + dl->status_block[2];
+ else if (dl->status_block[1] & 1)
+ ts->open_rej_reason = (dl->status_block[2] >> 4)+10;
+ else
+ ts->open_rej_reason = SAS_OREJ_UNKNOWN;
+ break;
+ case TF_OPEN_TO:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_OPEN_TO;
+ break;
+ case TF_PHY_DOWN:
+ case TU_PHY_DOWN:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case TI_PHY_DOWN:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_PHY_DOWN;
+ break;
+ case TI_BREAK:
+ case TI_PROTO_ERR:
+ case TI_NAK:
+ case TI_ACK_NAK_TO:
+ case TF_SMP_XMIT_RCV_ERR:
+ case TC_ATA_R_ERR_RECV:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_INTERRUPTED;
+ break;
+ case TF_BREAK:
+ case TU_BREAK:
+ case TU_ACK_NAK_TO:
+ case TF_SMPRSP_TO:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+ case TF_NAK_RECV:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_NAK_R_ERR;
+ break;
+ case TA_I_T_NEXUS_LOSS:
+ opcode = dl->status_block[0];
+ goto Again;
+ break;
+ case TF_INV_CONN_HANDLE:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEVICE_UNKNOWN;
+ break;
+ case TF_REQUESTED_N_PENDING:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_PENDING;
+ break;
+ case TC_TASK_CLEARED:
+ case TA_ON_REQ:
+ ts->resp = SAS_TASK_COMPLETE;
+ ts->stat = SAS_ABORTED_TASK;
+ break;
+
+ case TF_NO_SMP_CONN:
+ case TF_TMF_NO_CTX:
+ case TF_TMF_NO_TAG:
+ case TF_TMF_TAG_FREE:
+ case TF_TMF_TASK_DONE:
+ case TF_TMF_NO_CONN_HANDLE:
+ case TF_IRTT_TO:
+ case TF_IU_SHORT:
+ case TF_DATA_OFFS_ERR:
+ ts->resp = SAS_TASK_UNDELIVERED;
+ ts->stat = SAS_DEV_NO_RESPONSE;
+ break;
+
+ case TC_LINK_ADM_RESP:
+ case TC_CONTROL_PHY:
+ case TC_RESUME:
+ case TC_PARTIAL_SG_LIST:
+ default:
+ ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode);
+ break;
+ }
+
+ switch (task->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ asd_unbuild_ata_ascb(ascb);
+ break;
+ case SAS_PROTO_SMP:
+ asd_unbuild_smp_ascb(ascb);
+ break;
+ case SAS_PROTO_SSP:
+ asd_unbuild_ssp_ascb(ascb);
+ default:
+ break;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
+ task->task_state_flags |= SAS_TASK_STATE_DONE;
+ if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x "
+ "stat 0x%x but aborted by upper layer!\n",
+ task, opcode, ts->resp, ts->stat);
+ complete(&ascb->completion);
+ } else {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ task->lldd_task = NULL;
+ asd_ascb_free(ascb);
+ mb();
+ task->task_done(task);
+ }
+}
+
+/* ---------- ATA ---------- */
+
+static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task,
+ gfp_t gfp_flags)
+{
+ struct domain_device *dev = task->dev;
+ struct scb *scb;
+ u8 flags;
+ int res = 0;
+
+ scb = ascb->scb;
+
+ if (unlikely(task->ata_task.device_control_reg_update))
+ scb->header.opcode = CONTROL_ATA_DEV;
+ else if (dev->sata_dev.command_set == ATA_COMMAND_SET)
+ scb->header.opcode = INITIATE_ATA_TASK;
+ else
+ scb->header.opcode = INITIATE_ATAPI_TASK;
+
+ scb->ata_task.proto_conn_rate = (1 << 5); /* STP */
+ if (dev->port->oob_mode == SAS_OOB_MODE)
+ scb->ata_task.proto_conn_rate |= dev->linkrate;
+
+ scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
+ scb->ata_task.fis = task->ata_task.fis;
+ scb->ata_task.fis.fis_type = 0x27;
+ if (likely(!task->ata_task.device_control_reg_update))
+ scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
+ scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+ memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet,
+ 16);
+ scb->ata_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->ata_task.conn_handle = cpu_to_le16(
+ (u16)(unsigned long)dev->lldd_dev);
+
+ if (likely(!task->ata_task.device_control_reg_update)) {
+ flags = 0;
+ if (task->ata_task.dma_xfer)
+ flags |= DATA_XFER_MODE_DMA;
+ if (task->ata_task.use_ncq &&
+ dev->sata_dev.command_set != ATAPI_COMMAND_SET)
+ flags |= ATA_Q_TYPE_NCQ;
+ flags |= data_dir_flags[task->data_dir];
+ scb->ata_task.ata_flags = flags;
+
+ scb->ata_task.retry_count = task->ata_task.retry_count;
+
+ flags = 0;
+ if (task->ata_task.set_affil_pol)
+ flags |= SET_AFFIL_POLICY;
+ if (task->ata_task.stp_affil_pol)
+ flags |= STP_AFFIL_POLICY;
+ scb->ata_task.flags = flags;
+ }
+ ascb->tasklet_complete = asd_task_tasklet_complete;
+
+ if (likely(!task->ata_task.device_control_reg_update))
+ res = asd_map_scatterlist(task, scb->ata_task.sg_element,
+ gfp_flags);
+
+ return res;
+}
+
+static void asd_unbuild_ata_ascb(struct asd_ascb *a)
+{
+ asd_unmap_scatterlist(a);
+}
+
+/* ---------- SMP ---------- */
+
+static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task,
+ gfp_t gfp_flags)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ struct domain_device *dev = task->dev;
+ struct scb *scb;
+
+ pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1,
+ PCI_DMA_FROMDEVICE);
+ pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+
+ scb = ascb->scb;
+
+ scb->header.opcode = INITIATE_SMP_TASK;
+
+ scb->smp_task.proto_conn_rate = dev->linkrate;
+
+ scb->smp_task.smp_req.bus_addr =
+ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
+ scb->smp_task.smp_req.size =
+ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
+
+ scb->smp_task.smp_resp.bus_addr =
+ cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
+ scb->smp_task.smp_resp.size =
+ cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
+
+ scb->smp_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->smp_task.conn_handle = cpu_to_le16((u16)
+ (unsigned long)dev->lldd_dev);
+
+ ascb->tasklet_complete = asd_task_tasklet_complete;
+
+ return 0;
+}
+
+static void asd_unbuild_smp_ascb(struct asd_ascb *a)
+{
+ struct sas_task *task = a->uldd_task;
+
+ BUG_ON(!task);
+ pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1,
+ PCI_DMA_FROMDEVICE);
+ pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1,
+ PCI_DMA_FROMDEVICE);
+}
+
+/* ---------- SSP ---------- */
+
+static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task,
+ gfp_t gfp_flags)
+{
+ struct domain_device *dev = task->dev;
+ struct scb *scb;
+ int res = 0;
+
+ scb = ascb->scb;
+
+ scb->header.opcode = INITIATE_SSP_TASK;
+
+ scb->ssp_task.proto_conn_rate = (1 << 4); /* SSP */
+ scb->ssp_task.proto_conn_rate |= dev->linkrate;
+ scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len);
+ scb->ssp_task.ssp_frame.frame_type = SSP_DATA;
+ memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr,
+ HASHED_SAS_ADDR_SIZE);
+ memcpy(scb->ssp_task.ssp_frame.hashed_src_addr,
+ dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+
+ memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8);
+ if (task->ssp_task.enable_first_burst)
+ scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK;
+ scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3);
+ scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7);
+ memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16);
+
+ scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->ssp_task.conn_handle = cpu_to_le16(
+ (u16)(unsigned long)dev->lldd_dev);
+ scb->ssp_task.data_dir = data_dir_flags[task->data_dir];
+ scb->ssp_task.retry_count = scb->ssp_task.retry_count;
+
+ ascb->tasklet_complete = asd_task_tasklet_complete;
+
+ res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags);
+
+ return res;
+}
+
+static void asd_unbuild_ssp_ascb(struct asd_ascb *a)
+{
+ asd_unmap_scatterlist(a);
+}
+
+/* ---------- Execute Task ---------- */
+
+static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
+{
+ int res = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags);
+ if ((asd_ha->seq.can_queue - num) < 0)
+ res = -SAS_QUEUE_FULL;
+ else
+ asd_ha->seq.can_queue -= num;
+ spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags);
+
+ return res;
+}
+
+int asd_execute_task(struct sas_task *task, const int num,
+ gfp_t gfp_flags)
+{
+ int res = 0;
+ LIST_HEAD(alist);
+ struct sas_task *t = task;
+ struct asd_ascb *ascb = NULL, *a;
+ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+
+ res = asd_can_queue(asd_ha, num);
+ if (res)
+ return res;
+
+ res = num;
+ ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);
+ if (res) {
+ res = -ENOMEM;
+ goto out_err;
+ }
+
+ __list_add(&alist, ascb->list.prev, &ascb->list);
+ list_for_each_entry(a, &alist, list) {
+ a->uldd_task = t;
+ t->lldd_task = a;
+ t = list_entry(t->list.next, struct sas_task, list);
+ }
+ list_for_each_entry(a, &alist, list) {
+ t = a->uldd_task;
+ a->uldd_timer = 1;
+ if (t->task_proto & SAS_PROTO_STP)
+ t->task_proto = SAS_PROTO_STP;
+ switch (t->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ res = asd_build_ata_ascb(a, t, gfp_flags);
+ break;
+ case SAS_PROTO_SMP:
+ res = asd_build_smp_ascb(a, t, gfp_flags);
+ break;
+ case SAS_PROTO_SSP:
+ res = asd_build_ssp_ascb(a, t, gfp_flags);
+ break;
+ default:
+ asd_printk("unknown sas_task proto: 0x%x\n",
+ t->task_proto);
+ res = -ENOMEM;
+ break;
+ }
+ if (res)
+ goto out_err_unmap;
+ }
+ list_del_init(&alist);
+
+ res = asd_post_ascb_list(asd_ha, ascb, num);
+ if (unlikely(res)) {
+ a = NULL;
+ __list_add(&alist, ascb->list.prev, &ascb->list);
+ goto out_err_unmap;
+ }
+
+ return 0;
+out_err_unmap:
+ {
+ struct asd_ascb *b = a;
+ list_for_each_entry(a, &alist, list) {
+ if (a == b)
+ break;
+ t = a->uldd_task;
+ switch (t->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ asd_unbuild_ata_ascb(a);
+ break;
+ case SAS_PROTO_SMP:
+ asd_unbuild_smp_ascb(a);
+ break;
+ case SAS_PROTO_SSP:
+ asd_unbuild_ssp_ascb(a);
+ default:
+ break;
+ }
+ t->lldd_task = NULL;
+ }
+ }
+ list_del_init(&alist);
+out_err:
+ if (ascb)
+ asd_ascb_free_list(ascb);
+ asd_can_dequeue(asd_ha, num);
+ return res;
+}
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c
new file mode 100644
index 00000000000..61234384503
--- /dev/null
+++ b/drivers/scsi/aic94xx/aic94xx_tmf.c
@@ -0,0 +1,636 @@
+/*
+ * Aic94xx Task Management Functions
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file is part of the aic94xx driver.
+ *
+ * The aic94xx driver 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 of the
+ * License.
+ *
+ * The aic94xx driver 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 the aic94xx driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/spinlock.h>
+#include "aic94xx.h"
+#include "aic94xx_sas.h"
+#include "aic94xx_hwi.h"
+
+/* ---------- Internal enqueue ---------- */
+
+static int asd_enqueue_internal(struct asd_ascb *ascb,
+ void (*tasklet_complete)(struct asd_ascb *,
+ struct done_list_struct *),
+ void (*timed_out)(unsigned long))
+{
+ int res;
+
+ ascb->tasklet_complete = tasklet_complete;
+ ascb->uldd_timer = 1;
+
+ ascb->timer.data = (unsigned long) ascb;
+ ascb->timer.function = timed_out;
+ ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT;
+
+ add_timer(&ascb->timer);
+
+ res = asd_post_ascb_list(ascb->ha, ascb, 1);
+ if (unlikely(res))
+ del_timer(&ascb->timer);
+ return res;
+}
+
+static inline void asd_timedout_common(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+ struct asd_seq_data *seq = &ascb->ha->seq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&seq->pend_q_lock, flags);
+ seq->pending--;
+ list_del_init(&ascb->list);
+ spin_unlock_irqrestore(&seq->pend_q_lock, flags);
+}
+
+/* ---------- CLEAR NEXUS ---------- */
+
+static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ ASD_DPRINTK("%s: here\n", __FUNCTION__);
+ if (!del_timer(&ascb->timer)) {
+ ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__);
+ return;
+ }
+ ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode);
+ ascb->uldd_task = (void *) (unsigned long) dl->opcode;
+ complete(&ascb->completion);
+}
+
+static void asd_clear_nexus_timedout(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+
+ ASD_DPRINTK("%s: here\n", __FUNCTION__);
+ asd_timedout_common(data);
+ ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
+ complete(&ascb->completion);
+}
+
+#define CLEAR_NEXUS_PRE \
+ ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \
+ res = 1; \
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \
+ if (!ascb) \
+ return -ENOMEM; \
+ \
+ scb = ascb->scb; \
+ scb->header.opcode = CLEAR_NEXUS
+
+#define CLEAR_NEXUS_POST \
+ ASD_DPRINTK("%s: POST\n", __FUNCTION__); \
+ res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \
+ asd_clear_nexus_timedout); \
+ if (res) \
+ goto out_err; \
+ ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \
+ wait_for_completion(&ascb->completion); \
+ res = (int) (unsigned long) ascb->uldd_task; \
+ if (res == TC_NO_ERROR) \
+ res = TMF_RESP_FUNC_COMPLETE; \
+out_err: \
+ asd_ascb_free(ascb); \
+ return res
+
+int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha)
+{
+ struct asd_ha_struct *asd_ha = sas_ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_ADAPTER;
+ CLEAR_NEXUS_POST;
+}
+
+int asd_clear_nexus_port(struct asd_sas_port *port)
+{
+ struct asd_ha_struct *asd_ha = port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_PORT;
+ scb->clear_nexus.conn_mask = port->phy_mask;
+ CLEAR_NEXUS_POST;
+}
+
+#if 0
+static int asd_clear_nexus_I_T(struct domain_device *dev)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_I_T;
+ scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+ if (dev->tproto)
+ scb->clear_nexus.flags |= SUSPEND_TX;
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ dev->lldd_dev);
+ CLEAR_NEXUS_POST;
+}
+#endif
+
+static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_I_T_L;
+ scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ;
+ if (dev->tproto)
+ scb->clear_nexus.flags |= SUSPEND_TX;
+ memcpy(scb->clear_nexus.ssp_task.lun, lun, 8);
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ dev->lldd_dev);
+ CLEAR_NEXUS_POST;
+}
+
+static int asd_clear_nexus_tag(struct sas_task *task)
+{
+ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+ struct asd_ascb *tascb = task->lldd_task;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_TAG;
+ memcpy(scb->clear_nexus.ssp_task.lun, task->ssp_task.LUN, 8);
+ scb->clear_nexus.ssp_task.tag = tascb->tag;
+ if (task->dev->tproto)
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ task->dev->lldd_dev);
+ CLEAR_NEXUS_POST;
+}
+
+static int asd_clear_nexus_index(struct sas_task *task)
+{
+ struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
+ struct asd_ascb *tascb = task->lldd_task;
+ struct asd_ascb *ascb;
+ struct scb *scb;
+ int res;
+
+ CLEAR_NEXUS_PRE;
+ scb->clear_nexus.nexus = NEXUS_TRANS_CX;
+ if (task->dev->tproto)
+ scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long)
+ task->dev->lldd_dev);
+ scb->clear_nexus.index = cpu_to_le16(tascb->tc_index);
+ CLEAR_NEXUS_POST;
+}
+
+/* ---------- TMFs ---------- */
+
+static void asd_tmf_timedout(unsigned long data)
+{
+ struct asd_ascb *ascb = (void *) data;
+
+ ASD_DPRINTK("tmf timed out\n");
+ asd_timedout_common(data);
+ ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED;
+ complete(&ascb->completion);
+}
+
+static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ struct asd_ha_struct *asd_ha = ascb->ha;
+ unsigned long flags;
+ struct tc_resp_sb_struct {
+ __le16 index_escb;
+ u8 len_lsb;
+ u8 flags;
+ } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block;
+
+ int edb_id = ((resp_sb->flags & 0x70) >> 4)-1;
+ struct asd_ascb *escb;
+ struct asd_dma_tok *edb;
+ struct ssp_frame_hdr *fh;
+ struct ssp_response_iu *ru;
+ int res = TMF_RESP_FUNC_FAILED;
+
+ ASD_DPRINTK("tmf resp tasklet\n");
+
+ spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags);
+ escb = asd_tc_index_find(&asd_ha->seq,
+ (int)le16_to_cpu(resp_sb->index_escb));
+ spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags);
+
+ if (!escb) {
+ ASD_DPRINTK("Uh-oh! No escb for this dl?!\n");
+ return res;
+ }
+
+ edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index];
+ ascb->tag = *(__be16 *)(edb->vaddr+4);
+ fh = edb->vaddr + 16;
+ ru = edb->vaddr + 16 + sizeof(*fh);
+ res = ru->status;
+ if (ru->datapres == 1) /* Response data present */
+ res = ru->resp_data[3];
+#if 0
+ ascb->tag = fh->tag;
+#endif
+ ascb->tag_valid = 1;
+
+ asd_invalidate_edb(escb, edb_id);
+ return res;
+}
+
+static void asd_tmf_tasklet_complete(struct asd_ascb *ascb,
+ struct done_list_struct *dl)
+{
+ if (!del_timer(&ascb->timer))
+ return;
+
+ ASD_DPRINTK("tmf tasklet complete\n");
+
+ if (dl->opcode == TC_SSP_RESP)
+ ascb->uldd_task = (void *) (unsigned long)
+ asd_get_tmf_resp_tasklet(ascb, dl);
+ else
+ ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode;
+
+ complete(&ascb->completion);
+}
+
+static inline int asd_clear_nexus(struct sas_task *task)
+{
+ int res = TMF_RESP_FUNC_FAILED;
+ struct asd_ascb *tascb = task->lldd_task;
+ unsigned long flags;
+
+ ASD_DPRINTK("task not done, clearing nexus\n");
+ if (tascb->tag_valid)
+ res = asd_clear_nexus_tag(task);
+ else
+ res = asd_clear_nexus_index(task);
+ wait_for_completion_timeout(&tascb->completion,
+ AIC94XX_SCB_TIMEOUT);
+ ASD_DPRINTK("came back from clear nexus\n");
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE)
+ res = TMF_RESP_FUNC_COMPLETE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ return res;
+}
+
+/**
+ * asd_abort_task -- ABORT TASK TMF
+ * @task: the task to be aborted
+ *
+ * Before calling ABORT TASK the task state flags should be ORed with
+ * SAS_TASK_STATE_ABORTED (unless SAS_TASK_STATE_DONE is set) under
+ * the task_state_lock IRQ spinlock, then ABORT TASK *must* be called.
+ *
+ * Implements the ABORT TASK TMF, I_T_L_Q nexus.
+ * Returns: SAS TMF responses (see sas_task.h),
+ * -ENOMEM,
+ * -SAS_QUEUE_FULL.
+ *
+ * When ABORT TASK returns, the caller of ABORT TASK checks first the
+ * task->task_state_flags, and then the return value of ABORT TASK.
+ *
+ * If the task has task state bit SAS_TASK_STATE_DONE set, then the
+ * task was completed successfully prior to it being aborted. The
+ * caller of ABORT TASK has responsibility to call task->task_done()
+ * xor free the task, depending on their framework. The return code
+ * is TMF_RESP_FUNC_FAILED in this case.
+ *
+ * Else the SAS_TASK_STATE_DONE bit is not set,
+ * If the return code is TMF_RESP_FUNC_COMPLETE, then
+ * the task was aborted successfully. The caller of
+ * ABORT TASK has responsibility to call task->task_done()
+ * to finish the task, xor free the task depending on their
+ * framework.
+ * else
+ * the ABORT TASK returned some kind of error. The task
+ * was _not_ cancelled. Nothing can be assumed.
+ * The caller of ABORT TASK may wish to retry.
+ */
+int asd_abort_task(struct sas_task *task)
+{
+ struct asd_ascb *tascb = task->lldd_task;
+ struct asd_ha_struct *asd_ha = tascb->ha;
+ int res = 1;
+ unsigned long flags;
+ struct asd_ascb *ascb = NULL;
+ struct scb *scb;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ res = TMF_RESP_FUNC_COMPLETE;
+ ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+ if (!ascb)
+ return -ENOMEM;
+ scb = ascb->scb;
+
+ scb->header.opcode = ABORT_TASK;
+
+ switch (task->task_proto) {
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ scb->abort_task.proto_conn_rate = (1 << 5); /* STP */
+ break;
+ case SAS_PROTO_SSP:
+ scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */
+ scb->abort_task.proto_conn_rate |= task->dev->linkrate;
+ break;
+ case SAS_PROTO_SMP:
+ break;
+ default:
+ break;
+ }
+
+ if (task->task_proto == SAS_PROTO_SSP) {
+ scb->abort_task.ssp_frame.frame_type = SSP_TASK;
+ memcpy(scb->abort_task.ssp_frame.hashed_dest_addr,
+ task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ memcpy(scb->abort_task.ssp_frame.hashed_src_addr,
+ task->dev->port->ha->hashed_sas_addr,
+ HASHED_SAS_ADDR_SIZE);
+ scb->abort_task.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+
+ memcpy(scb->abort_task.ssp_task.lun, task->ssp_task.LUN, 8);
+ scb->abort_task.ssp_task.tmf = TMF_ABORT_TASK;
+ scb->abort_task.ssp_task.tag = cpu_to_be16(0xFFFF);
+ }
+
+ scb->abort_task.sister_scb = cpu_to_le16(0xFFFF);
+ scb->abort_task.conn_handle = cpu_to_le16(
+ (u16)(unsigned long)task->dev->lldd_dev);
+ scb->abort_task.retry_count = 1;
+ scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index);
+ scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
+
+ res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+ asd_tmf_timedout);
+ if (res)
+ goto out;
+ wait_for_completion(&ascb->completion);
+ ASD_DPRINTK("tmf came back\n");
+
+ res = (int) (unsigned long) ascb->uldd_task;
+ tascb->tag = ascb->tag;
+ tascb->tag_valid = ascb->tag_valid;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ res = TMF_RESP_FUNC_COMPLETE;
+ ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task);
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ switch (res) {
+ /* The task to be aborted has been sent to the device.
+ * We got a Response IU for the ABORT TASK TMF. */
+ case TC_NO_ERROR + 0xFF00:
+ case TMF_RESP_FUNC_COMPLETE:
+ case TMF_RESP_FUNC_FAILED:
+ res = asd_clear_nexus(task);
+ break;
+ case TMF_RESP_INVALID_FRAME:
+ case TMF_RESP_OVERLAPPED_TAG:
+ case TMF_RESP_FUNC_ESUPP:
+ case TMF_RESP_NO_LUN:
+ goto out_done; break;
+ }
+ /* In the following we assume that the managing layer
+ * will _never_ make a mistake, when issuing ABORT TASK.
+ */
+ switch (res) {
+ default:
+ res = asd_clear_nexus(task);
+ /* fallthrough */
+ case TC_NO_ERROR + 0xFF00:
+ case TMF_RESP_FUNC_COMPLETE:
+ break;
+ /* The task hasn't been sent to the device xor we never got
+ * a (sane) Response IU for the ABORT TASK TMF.
+ */
+ case TF_NAK_RECV + 0xFF00:
+ res = TMF_RESP_INVALID_FRAME;
+ break;
+ case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */
+ res = TMF_RESP_FUNC_FAILED;
+ wait_for_completion_timeout(&tascb->completion,
+ AIC94XX_SCB_TIMEOUT);
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE)
+ res = TMF_RESP_FUNC_COMPLETE;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ goto out_done;
+ case TF_TMF_NO_TAG + 0xFF00:
+ case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
+ case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
+ res = TMF_RESP_FUNC_COMPLETE;
+ goto out_done;
+ case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
+ res = TMF_RESP_FUNC_ESUPP;
+ goto out;
+ }
+out_done:
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ task->lldd_task = NULL;
+ mb();
+ asd_ascb_free(tascb);
+ }
+out:
+ asd_ascb_free(ascb);
+ ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res);
+ return res;
+}
+
+/**
+ * asd_initiate_ssp_tmf -- send a TMF to an I_T_L or I_T_L_Q nexus
+ * @dev: pointer to struct domain_device of interest
+ * @lun: pointer to u8[8] which is the LUN
+ * @tmf: the TMF to be performed (see sas_task.h or the SAS spec)
+ * @index: the transaction context of the task to be queried if QT TMF
+ *
+ * This function is used to send ABORT TASK SET, CLEAR ACA,
+ * CLEAR TASK SET, LU RESET and QUERY TASK TMFs.
+ *
+ * No SCBs should be queued to the I_T_L nexus when this SCB is
+ * pending.
+ *
+ * Returns: TMF response code (see sas_task.h or the SAS spec)
+ */
+static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun,
+ int tmf, int index)
+{
+ struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha;
+ struct asd_ascb *ascb;
+ int res = 1;
+ struct scb *scb;
+
+ if (!(dev->tproto & SAS_PROTO_SSP))
+ return TMF_RESP_FUNC_ESUPP;
+
+ ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL);
+ if (!ascb)
+ return -ENOMEM;
+ scb = ascb->scb;
+
+ if (tmf == TMF_QUERY_TASK)
+ scb->header.opcode = QUERY_SSP_TASK;
+ else
+ scb->header.opcode = INITIATE_SSP_TMF;
+
+ scb->ssp_tmf.proto_conn_rate = (1 << 4); /* SSP */
+ scb->ssp_tmf.proto_conn_rate |= dev->linkrate;
+ /* SSP frame header */
+ scb->ssp_tmf.ssp_frame.frame_type = SSP_TASK;
+ memcpy(scb->ssp_tmf.ssp_frame.hashed_dest_addr,
+ dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ memcpy(scb->ssp_tmf.ssp_frame.hashed_src_addr,
+ dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE);
+ scb->ssp_tmf.ssp_frame.tptt = cpu_to_be16(0xFFFF);
+ /* SSP Task IU */
+ memcpy(scb->ssp_tmf.ssp_task.lun, lun, 8);
+ scb->ssp_tmf.ssp_task.tmf = tmf;
+
+ scb->ssp_tmf.sister_scb = cpu_to_le16(0xFFFF);
+ scb->ssp_tmf.conn_handle= cpu_to_le16((u16)(unsigned long)
+ dev->lldd_dev);
+ scb->ssp_tmf.retry_count = 1;
+ scb->ssp_tmf.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST);
+ if (tmf == TMF_QUERY_TASK)
+ scb->ssp_tmf.index = cpu_to_le16(index);
+
+ res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete,
+ asd_tmf_timedout);
+ if (res)
+ goto out_err;
+ wait_for_completion(&ascb->completion);
+ res = (int) (unsigned long) ascb->uldd_task;
+
+ switch (res) {
+ case TC_NO_ERROR + 0xFF00:
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ case TF_NAK_RECV + 0xFF00:
+ res = TMF_RESP_INVALID_FRAME;
+ break;
+ case TF_TMF_TASK_DONE + 0xFF00:
+ res = TMF_RESP_FUNC_FAILED;
+ break;
+ case TF_TMF_NO_TAG + 0xFF00:
+ case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */
+ case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */
+ res = TMF_RESP_FUNC_COMPLETE;
+ break;
+ case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */
+ res = TMF_RESP_FUNC_ESUPP;
+ break;
+ default:
+ ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n",
+ __FUNCTION__, res);
+ res = TMF_RESP_FUNC_FAILED;
+ break;
+ }
+out_err:
+ asd_ascb_free(ascb);
+ return res;
+}
+
+int asd_abort_task_set(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_ABORT_TASK_SET, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+int asd_clear_aca(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+int asd_clear_task_set(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+int asd_lu_reset(struct domain_device *dev, u8 *lun)
+{
+ int res = asd_initiate_ssp_tmf(dev, lun, TMF_LU_RESET, 0);
+
+ if (res == TMF_RESP_FUNC_COMPLETE)
+ asd_clear_nexus_I_T_L(dev, lun);
+ return res;
+}
+
+/**
+ * asd_query_task -- send a QUERY TASK TMF to an I_T_L_Q nexus
+ * task: pointer to sas_task struct of interest
+ *
+ * Returns: TMF_RESP_FUNC_COMPLETE if the task is not in the task set,
+ * or TMF_RESP_FUNC_SUCC if the task is in the task set.
+ *
+ * Normally the management layer sets the task to aborted state,
+ * and then calls query task and then abort task.
+ */
+int asd_query_task(struct sas_task *task)
+{
+ struct asd_ascb *ascb = task->lldd_task;
+ int index;
+
+ if (ascb) {
+ index = ascb->tc_index;
+ return asd_initiate_ssp_tmf(task->dev, task->ssp_task.LUN,
+ TMF_QUERY_TASK, index);
+ }
+ return TMF_RESP_FUNC_COMPLETE;
+}
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
index c0844fa32c5..9099d531d5a 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/config.h>
#include <linux/zorro.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/arcmsr/Makefile b/drivers/scsi/arcmsr/Makefile
new file mode 100644
index 00000000000..721aced3916
--- /dev/null
+++ b/drivers/scsi/arcmsr/Makefile
@@ -0,0 +1,6 @@
+# File: drivers/arcmsr/Makefile
+# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver.
+
+arcmsr-objs := arcmsr_attr.o arcmsr_hba.o
+
+obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
new file mode 100644
index 00000000000..aff96db9ccf
--- /dev/null
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -0,0 +1,472 @@
+/*
+*******************************************************************************
+** O.S : Linux
+** FILE NAME : arcmsr.h
+** BY : Erich Chen
+** Description: SCSI RAID Device Driver for
+** ARECA RAID Host adapter
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
+**
+** Web site: www.areca.com.tw
+** E-mail: erich@areca.com.tw
+**
+** 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.
+** 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.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+**(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+*/
+#include <linux/interrupt.h>
+
+struct class_device_attribute;
+
+#define ARCMSR_MAX_OUTSTANDING_CMD 256
+#define ARCMSR_MAX_FREECCB_NUM 288
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.13"
+#define ARCMSR_SCSI_INITIATOR_ID 255
+#define ARCMSR_MAX_XFER_SECTORS 512
+#define ARCMSR_MAX_TARGETID 17
+#define ARCMSR_MAX_TARGETLUN 8
+#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER 4096
+#define ARCMSR_MAX_SG_ENTRIES 38
+
+/*
+*******************************************************************************
+** split 64bits dma addressing
+*******************************************************************************
+*/
+#define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16)
+#define dma_addr_lo32(addr) (uint32_t) (addr & 0xffffffff)
+/*
+*******************************************************************************
+** MESSAGE CONTROL CODE
+*******************************************************************************
+*/
+struct CMD_MESSAGE
+{
+ uint32_t HeaderLength;
+ uint8_t Signature[8];
+ uint32_t Timeout;
+ uint32_t ControlCode;
+ uint32_t ReturnCode;
+ uint32_t Length;
+};
+/*
+*******************************************************************************
+** IOP Message Transfer Data for user space
+*******************************************************************************
+*/
+struct CMD_MESSAGE_FIELD
+{
+ struct CMD_MESSAGE cmdmessage;
+ uint8_t messagedatabuffer[1032];
+};
+/* IOP message transfer */
+#define ARCMSR_MESSAGE_FAIL 0x0001
+/* DeviceType */
+#define ARECA_SATA_RAID 0x90000000
+/* FunctionCode */
+#define FUNCTION_READ_RQBUFFER 0x0801
+#define FUNCTION_WRITE_WQBUFFER 0x0802
+#define FUNCTION_CLEAR_RQBUFFER 0x0803
+#define FUNCTION_CLEAR_WQBUFFER 0x0804
+#define FUNCTION_CLEAR_ALLQBUFFER 0x0805
+#define FUNCTION_RETURN_CODE_3F 0x0806
+#define FUNCTION_SAY_HELLO 0x0807
+#define FUNCTION_SAY_GOODBYE 0x0808
+#define FUNCTION_FLUSH_ADAPTER_CACHE 0x0809
+/* ARECA IO CONTROL CODE*/
+#define ARCMSR_MESSAGE_READ_RQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
+#define ARCMSR_MESSAGE_WRITE_WQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_RQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_WQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
+#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER \
+ ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
+#define ARCMSR_MESSAGE_RETURN_CODE_3F \
+ ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
+#define ARCMSR_MESSAGE_SAY_HELLO \
+ ARECA_SATA_RAID | FUNCTION_SAY_HELLO
+#define ARCMSR_MESSAGE_SAY_GOODBYE \
+ ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
+#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
+ ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
+/* ARECA IOCTL ReturnCode */
+#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006
+#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F
+/*
+*************************************************************
+** structure for holding DMA address data
+*************************************************************
+*/
+#define IS_SG64_ADDR 0x01000000 /* bit24 */
+struct SG32ENTRY
+{
+ uint32_t length;
+ uint32_t address;
+};
+struct SG64ENTRY
+{
+ uint32_t length;
+ uint32_t address;
+ uint32_t addresshigh;
+};
+struct SGENTRY_UNION
+{
+ union
+ {
+ struct SG32ENTRY sg32entry;
+ struct SG64ENTRY sg64entry;
+ }u;
+};
+/*
+********************************************************************
+** Q Buffer of IOP Message Transfer
+********************************************************************
+*/
+struct QBUFFER
+{
+ uint32_t data_len;
+ uint8_t data[124];
+};
+/*
+*******************************************************************************
+** FIRMWARE INFO
+*******************************************************************************
+*/
+struct FIRMWARE_INFO
+{
+ uint32_t signature; /*0, 00-03*/
+ uint32_t request_len; /*1, 04-07*/
+ uint32_t numbers_queue; /*2, 08-11*/
+ uint32_t sdram_size; /*3, 12-15*/
+ uint32_t ide_channels; /*4, 16-19*/
+ char vendor[40]; /*5, 20-59*/
+ char model[8]; /*15, 60-67*/
+ char firmware_ver[16]; /*17, 68-83*/
+ char device_map[16]; /*21, 84-99*/
+};
+/* signature of set and get firmware config */
+#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
+/* message code of inbound message register */
+#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
+#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002
+#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003
+#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004
+#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE 0x00000005
+#define ARCMSR_INBOUND_MESG0_START_BGRB 0x00000006
+#define ARCMSR_INBOUND_MESG0_CHK331PENDING 0x00000007
+#define ARCMSR_INBOUND_MESG0_SYNC_TIMER 0x00000008
+/* doorbell interrupt generator */
+#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK 0x00000001
+#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK 0x00000002
+#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK 0x00000001
+#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK 0x00000002
+/* ccb areca cdb flag */
+#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000
+#define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000
+#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
+/* outbound firmware ok */
+#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+/*
+*******************************************************************************
+** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
+*******************************************************************************
+*/
+struct ARCMSR_CDB
+{
+ uint8_t Bus;
+ uint8_t TargetID;
+ uint8_t LUN;
+ uint8_t Function;
+
+ uint8_t CdbLength;
+ uint8_t sgcount;
+ uint8_t Flags;
+#define ARCMSR_CDB_FLAG_SGL_BSIZE 0x01
+#define ARCMSR_CDB_FLAG_BIOS 0x02
+#define ARCMSR_CDB_FLAG_WRITE 0x04
+#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00
+#define ARCMSR_CDB_FLAG_HEADQ 0x08
+#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
+ uint8_t Reserved1;
+
+ uint32_t Context;
+ uint32_t DataLength;
+
+ uint8_t Cdb[16];
+
+ uint8_t DeviceStatus;
+#define ARCMSR_DEV_CHECK_CONDITION 0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
+#define ARCMSR_DEV_ABORTED 0xF1
+#define ARCMSR_DEV_INIT_FAIL 0xF2
+ uint8_t SenseData[15];
+
+ union
+ {
+ struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
+ struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES];
+ } u;
+};
+/*
+*******************************************************************************
+** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+*******************************************************************************
+*/
+struct MessageUnit
+{
+ uint32_t resrved0[4]; /*0000 000F*/
+ uint32_t inbound_msgaddr0; /*0010 0013*/
+ uint32_t inbound_msgaddr1; /*0014 0017*/
+ uint32_t outbound_msgaddr0; /*0018 001B*/
+ uint32_t outbound_msgaddr1; /*001C 001F*/
+ uint32_t inbound_doorbell; /*0020 0023*/
+ uint32_t inbound_intstatus; /*0024 0027*/
+ uint32_t inbound_intmask; /*0028 002B*/
+ uint32_t outbound_doorbell; /*002C 002F*/
+ uint32_t outbound_intstatus; /*0030 0033*/
+ uint32_t outbound_intmask; /*0034 0037*/
+ uint32_t reserved1[2]; /*0038 003F*/
+ uint32_t inbound_queueport; /*0040 0043*/
+ uint32_t outbound_queueport; /*0044 0047*/
+ uint32_t reserved2[2]; /*0048 004F*/
+ uint32_t reserved3[492]; /*0050 07FF 492*/
+ uint32_t reserved4[128]; /*0800 09FF 128*/
+ uint32_t message_rwbuffer[256]; /*0a00 0DFF 256*/
+ uint32_t message_wbuffer[32]; /*0E00 0E7F 32*/
+ uint32_t reserved5[32]; /*0E80 0EFF 32*/
+ uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/
+ uint32_t reserved6[32]; /*0F80 0FFF 32*/
+};
+/*
+*******************************************************************************
+** Adapter Control Block
+*******************************************************************************
+*/
+struct AdapterControlBlock
+{
+ struct pci_dev * pdev;
+ struct Scsi_Host * host;
+ unsigned long vir2phy_offset;
+ /* Offset is used in making arc cdb physical to virtual calculations */
+ uint32_t outbound_int_enable;
+
+ struct MessageUnit __iomem * pmu;
+ /* message unit ATU inbound base address0 */
+
+ uint32_t acb_flags;
+#define ACB_F_SCSISTOPADAPTER 0x0001
+#define ACB_F_MSG_STOP_BGRB 0x0002
+ /* stop RAID background rebuild */
+#define ACB_F_MSG_START_BGRB 0x0004
+ /* stop RAID background rebuild */
+#define ACB_F_IOPDATA_OVERFLOW 0x0008
+ /* iop message data rqbuffer overflow */
+#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
+ /* message clear wqbuffer */
+#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
+ /* message clear rqbuffer */
+#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
+#define ACB_F_BUS_RESET 0x0080
+#define ACB_F_IOP_INITED 0x0100
+ /* iop init */
+
+ struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
+ /* used for memory free */
+ struct list_head ccb_free_list;
+ /* head of free ccb list */
+ atomic_t ccboutstandingcount;
+
+ void * dma_coherent;
+ /* dma_coherent used for memory free */
+ dma_addr_t dma_coherent_handle;
+ /* dma_coherent_handle used for memory free */
+
+ uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
+ /* data collection buffer for read from 80331 */
+ int32_t rqbuf_firstindex;
+ /* first of read buffer */
+ int32_t rqbuf_lastindex;
+ /* last of read buffer */
+ uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
+ /* data collection buffer for write to 80331 */
+ int32_t wqbuf_firstindex;
+ /* first of write buffer */
+ int32_t wqbuf_lastindex;
+ /* last of write buffer */
+ uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
+ /* id0 ..... id15, lun0...lun7 */
+#define ARECA_RAID_GONE 0x55
+#define ARECA_RAID_GOOD 0xaa
+ uint32_t num_resets;
+ uint32_t num_aborts;
+ uint32_t firm_request_len;
+ uint32_t firm_numbers_queue;
+ uint32_t firm_sdram_size;
+ uint32_t firm_hd_channels;
+ char firm_model[12];
+ char firm_version[20];
+};/* HW_DEVICE_EXTENSION */
+/*
+*******************************************************************************
+** Command Control Block
+** this CCB length must be 32 bytes boundary
+*******************************************************************************
+*/
+struct CommandControlBlock
+{
+ struct ARCMSR_CDB arcmsr_cdb;
+ /*
+ ** 0-503 (size of CDB=504):
+ ** arcmsr messenger scsi command descriptor size 504 bytes
+ */
+ uint32_t cdb_shifted_phyaddr;
+ /* 504-507 */
+ uint32_t reserved1;
+ /* 508-511 */
+#if BITS_PER_LONG == 64
+ /* ======================512+64 bytes======================== */
+ struct list_head list;
+ /* 512-527 16 bytes next/prev ptrs for ccb lists */
+ struct scsi_cmnd * pcmd;
+ /* 528-535 8 bytes pointer of linux scsi command */
+ struct AdapterControlBlock * acb;
+ /* 536-543 8 bytes pointer of acb */
+
+ uint16_t ccb_flags;
+ /* 544-545 */
+ #define CCB_FLAG_READ 0x0000
+ #define CCB_FLAG_WRITE 0x0001
+ #define CCB_FLAG_ERROR 0x0002
+ #define CCB_FLAG_FLUSHCACHE 0x0004
+ #define CCB_FLAG_MASTER_ABORTED 0x0008
+ uint16_t startdone;
+ /* 546-547 */
+ #define ARCMSR_CCB_DONE 0x0000
+ #define ARCMSR_CCB_START 0x55AA
+ #define ARCMSR_CCB_ABORTED 0xAA55
+ #define ARCMSR_CCB_ILLEGAL 0xFFFF
+ uint32_t reserved2[7];
+ /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */
+#else
+ /* ======================512+32 bytes======================== */
+ struct list_head list;
+ /* 512-519 8 bytes next/prev ptrs for ccb lists */
+ struct scsi_cmnd * pcmd;
+ /* 520-523 4 bytes pointer of linux scsi command */
+ struct AdapterControlBlock * acb;
+ /* 524-527 4 bytes pointer of acb */
+
+ uint16_t ccb_flags;
+ /* 528-529 */
+ #define CCB_FLAG_READ 0x0000
+ #define CCB_FLAG_WRITE 0x0001
+ #define CCB_FLAG_ERROR 0x0002
+ #define CCB_FLAG_FLUSHCACHE 0x0004
+ #define CCB_FLAG_MASTER_ABORTED 0x0008
+ uint16_t startdone;
+ /* 530-531 */
+ #define ARCMSR_CCB_DONE 0x0000
+ #define ARCMSR_CCB_START 0x55AA
+ #define ARCMSR_CCB_ABORTED 0xAA55
+ #define ARCMSR_CCB_ILLEGAL 0xFFFF
+ uint32_t reserved2[3];
+ /* 532-535 536-539 540-543 */
+#endif
+ /* ========================================================== */
+};
+/*
+*******************************************************************************
+** ARECA SCSI sense data
+*******************************************************************************
+*/
+struct SENSE_DATA
+{
+ uint8_t ErrorCode:7;
+#define SCSI_SENSE_CURRENT_ERRORS 0x70
+#define SCSI_SENSE_DEFERRED_ERRORS 0x71
+ uint8_t Valid:1;
+ uint8_t SegmentNumber;
+ uint8_t SenseKey:4;
+ uint8_t Reserved:1;
+ uint8_t IncorrectLength:1;
+ uint8_t EndOfMedia:1;
+ uint8_t FileMark:1;
+ uint8_t Information[4];
+ uint8_t AdditionalSenseLength;
+ uint8_t CommandSpecificInformation[4];
+ uint8_t AdditionalSenseCode;
+ uint8_t AdditionalSenseCodeQualifier;
+ uint8_t FieldReplaceableUnitCode;
+ uint8_t SenseKeySpecific[3];
+};
+/*
+*******************************************************************************
+** Outbound Interrupt Status Register - OISR
+*******************************************************************************
+*/
+#define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG 0x30
+#define ARCMSR_MU_OUTBOUND_PCI_INT 0x10
+#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT 0x08
+#define ARCMSR_MU_OUTBOUND_DOORBELL_INT 0x04
+#define ARCMSR_MU_OUTBOUND_MESSAGE1_INT 0x02
+#define ARCMSR_MU_OUTBOUND_MESSAGE0_INT 0x01
+#define ARCMSR_MU_OUTBOUND_HANDLE_INT \
+ (ARCMSR_MU_OUTBOUND_MESSAGE0_INT \
+ |ARCMSR_MU_OUTBOUND_MESSAGE1_INT \
+ |ARCMSR_MU_OUTBOUND_DOORBELL_INT \
+ |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT \
+ |ARCMSR_MU_OUTBOUND_PCI_INT)
+/*
+*******************************************************************************
+** Outbound Interrupt Mask Register - OIMR
+*******************************************************************************
+*/
+#define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG 0x34
+#define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE 0x10
+#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE 0x08
+#define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE 0x04
+#define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE 0x02
+#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
+#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
+
+extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
+extern struct class_device_attribute *arcmsr_host_attrs[];
+extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
+void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
+
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
new file mode 100644
index 00000000000..12497da5529
--- /dev/null
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -0,0 +1,381 @@
+/*
+*******************************************************************************
+** O.S : Linux
+** FILE NAME : arcmsr_attr.c
+** BY : Erich Chen
+** Description: attributes exported to sysfs and device host
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
+**
+** Web site: www.areca.com.tw
+** E-mail: erich@areca.com.tw
+**
+** 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.
+** 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.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
+** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include "arcmsr.h"
+
+struct class_device_attribute *arcmsr_host_attrs[];
+
+static ssize_t
+arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint8_t *pQbuffer,*ptmpQbuffer;
+ int32_t allxfer_len = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ /* do message unit read. */
+ ptmpQbuffer = (uint8_t *)buf;
+ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+ && (allxfer_len < 1031)) {
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+ memcpy(ptmpQbuffer, pQbuffer, 1);
+ acb->rqbuf_firstindex++;
+ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ ptmpQbuffer++;
+ allxfer_len++;
+ }
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
+ &reg->message_rbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ int32_t iop_len;
+
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ iop_len = readl(&prbuffer->data_len);
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ }
+ return (allxfer_len);
+}
+
+static ssize_t
+arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (count > 1032)
+ return -EINVAL;
+ /* do message unit write. */
+ ptmpuserbuffer = (uint8_t *)buf;
+ user_len = (int32_t)count;
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ if (wqbuf_lastindex != wqbuf_firstindex) {
+ arcmsr_post_Qbuffer(acb);
+ return 0; /*need retry*/
+ } else {
+ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= user_len) {
+ while (user_len > 0) {
+ pQbuffer =
+ &acb->wqbuffer[acb->wqbuf_lastindex];
+ memcpy(pQbuffer, ptmpuserbuffer, 1);
+ acb->wqbuf_lastindex++;
+ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ ptmpuserbuffer++;
+ user_len--;
+ }
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+ acb->acb_flags &=
+ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ arcmsr_post_Qbuffer(acb);
+ }
+ return count;
+ } else {
+ return 0; /*need retry*/
+ }
+ }
+}
+
+static ssize_t
+arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint8_t *pQbuffer;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+ , &reg->inbound_doorbell);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED
+ | ACB_F_MESSAGE_RQBUFFER_CLEARED
+ | ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ pQbuffer = acb->rqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ pQbuffer = acb->wqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ return 1;
+}
+
+static struct bin_attribute arcmsr_sysfs_message_read_attr = {
+ .attr = {
+ .name = "mu_read",
+ .mode = S_IRUSR ,
+ .owner = THIS_MODULE,
+ },
+ .size = 1032,
+ .read = arcmsr_sysfs_iop_message_read,
+};
+
+static struct bin_attribute arcmsr_sysfs_message_write_attr = {
+ .attr = {
+ .name = "mu_write",
+ .mode = S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = 1032,
+ .write = arcmsr_sysfs_iop_message_write,
+};
+
+static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
+ .attr = {
+ .name = "mu_clear",
+ .mode = S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = 1,
+ .write = arcmsr_sysfs_iop_message_clear,
+};
+
+int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
+{
+ struct Scsi_Host *host = acb->host;
+ int error;
+
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_read_attr);
+ if (error) {
+ printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
+ goto error_bin_file_message_read;
+ }
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_write_attr);
+ if (error) {
+ printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
+ goto error_bin_file_message_write;
+ }
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_clear_attr);
+ if (error) {
+ printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
+ goto error_bin_file_message_clear;
+ }
+ return 0;
+error_bin_file_message_clear:
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_write_attr);
+error_bin_file_message_write:
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_read_attr);
+error_bin_file_message_read:
+ return error;
+}
+
+void
+arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
+ struct Scsi_Host *host = acb->host;
+
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_clear_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj,
+ &arcmsr_sysfs_message_read_attr);
+}
+
+
+static ssize_t
+arcmsr_attr_host_driver_version(struct class_device *cdev, char *buf) {
+ return snprintf(buf, PAGE_SIZE,
+ "%s\n",
+ ARCMSR_DRIVER_VERSION);
+}
+
+static ssize_t
+arcmsr_attr_host_driver_posted_cmd(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ atomic_read(&acb->ccboutstandingcount));
+}
+
+static ssize_t
+arcmsr_attr_host_driver_reset(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->num_resets);
+}
+
+static ssize_t
+arcmsr_attr_host_driver_abort(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->num_aborts);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_model(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+ return snprintf(buf, PAGE_SIZE,
+ "%s\n",
+ acb->firm_model);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_version(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%s\n",
+ acb->firm_version);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_request_len(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_request_len);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_numbers_queue(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_numbers_queue);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_sdram_size(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_sdram_size);
+}
+
+static ssize_t
+arcmsr_attr_host_fw_hd_channels(struct class_device *cdev, char *buf) {
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+
+ return snprintf(buf, PAGE_SIZE,
+ "%4d\n",
+ acb->firm_hd_channels);
+}
+
+static CLASS_DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
+static CLASS_DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL);
+static CLASS_DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL);
+static CLASS_DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL);
+static CLASS_DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
+static CLASS_DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
+static CLASS_DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
+static CLASS_DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
+static CLASS_DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
+static CLASS_DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
+
+struct class_device_attribute *arcmsr_host_attrs[] = {
+ &class_device_attr_host_driver_version,
+ &class_device_attr_host_driver_posted_cmd,
+ &class_device_attr_host_driver_reset,
+ &class_device_attr_host_driver_abort,
+ &class_device_attr_host_fw_model,
+ &class_device_attr_host_fw_version,
+ &class_device_attr_host_fw_request_len,
+ &class_device_attr_host_fw_numbers_queue,
+ &class_device_attr_host_fw_sdram_size,
+ &class_device_attr_host_fw_hd_channels,
+ NULL,
+};
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
new file mode 100644
index 00000000000..475f978ff8f
--- /dev/null
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -0,0 +1,1496 @@
+/*
+*******************************************************************************
+** O.S : Linux
+** FILE NAME : arcmsr_hba.c
+** BY : Erich Chen
+** Description: SCSI RAID Device Driver for
+** ARECA RAID Host adapter
+*******************************************************************************
+** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
+**
+** Web site: www.areca.com.tw
+** E-mail: erich@areca.com.tw
+**
+** 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.
+** 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.
+*******************************************************************************
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+** 1. Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** 2. Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+** 3. The name of the author may not be used to endorse or promote products
+** derived from this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT
+** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF
+** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*******************************************************************************
+** For history of changes, see Documentation/scsi/ChangeLog.arcmsr
+** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt
+*******************************************************************************
+*/
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/pci_ids.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsicam.h>
+#include "arcmsr.h"
+
+MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx) SATA RAID HOST Adapter");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(ARCMSR_DRIVER_VERSION);
+
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
+static int arcmsr_abort(struct scsi_cmnd *);
+static int arcmsr_bus_reset(struct scsi_cmnd *);
+static int arcmsr_bios_param(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int *info);
+static int arcmsr_queue_command(struct scsi_cmnd * cmd,
+ void (*done) (struct scsi_cmnd *));
+static int arcmsr_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id);
+static void arcmsr_remove(struct pci_dev *pdev);
+static void arcmsr_shutdown(struct pci_dev *pdev);
+static void arcmsr_iop_init(struct AdapterControlBlock *acb);
+static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
+static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
+static const char *arcmsr_info(struct Scsi_Host *);
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
+
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+ if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
+ queue_depth = ARCMSR_MAX_CMD_PERLUN;
+ scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+ return queue_depth;
+}
+
+static struct scsi_host_template arcmsr_scsi_host_template = {
+ .module = THIS_MODULE,
+ .name = "ARCMSR ARECA SATA RAID HOST Adapter" ARCMSR_DRIVER_VERSION,
+ .info = arcmsr_info,
+ .queuecommand = arcmsr_queue_command,
+ .eh_abort_handler = arcmsr_abort,
+ .eh_bus_reset_handler = arcmsr_bus_reset,
+ .bios_param = arcmsr_bios_param,
+ .change_queue_depth = arcmsr_adjust_disk_queue_depth,
+ .can_queue = ARCMSR_MAX_OUTSTANDING_CMD,
+ .this_id = ARCMSR_SCSI_INITIATOR_ID,
+ .sg_tablesize = ARCMSR_MAX_SG_ENTRIES,
+ .max_sectors = ARCMSR_MAX_XFER_SECTORS,
+ .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = arcmsr_host_attrs,
+};
+
+static struct pci_device_id arcmsr_device_id_table[] = {
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
+ {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
+ {0, 0}, /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
+static struct pci_driver arcmsr_pci_driver = {
+ .name = "arcmsr",
+ .id_table = arcmsr_device_id_table,
+ .probe = arcmsr_probe,
+ .remove = arcmsr_remove,
+ .shutdown = arcmsr_shutdown
+};
+
+static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ irqreturn_t handle_state;
+ struct AdapterControlBlock *acb;
+ unsigned long flags;
+
+ acb = (struct AdapterControlBlock *)dev_id;
+
+ spin_lock_irqsave(acb->host->host_lock, flags);
+ handle_state = arcmsr_interrupt(acb);
+ spin_unlock_irqrestore(acb->host->host_lock, flags);
+ return handle_state;
+}
+
+static int arcmsr_bios_param(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int *geom)
+{
+ int ret, heads, sectors, cylinders, total_capacity;
+ unsigned char *buffer;/* return copy of block device's partition table */
+
+ buffer = scsi_bios_ptable(bdev);
+ if (buffer) {
+ ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
+ kfree(buffer);
+ if (ret != -1)
+ return ret;
+ }
+ total_capacity = capacity;
+ heads = 64;
+ sectors = 32;
+ cylinders = total_capacity / (heads * sectors);
+ if (cylinders > 1024) {
+ heads = 255;
+ sectors = 63;
+ cylinders = total_capacity / (heads * sectors);
+ }
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+ return 0;
+}
+
+static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+{
+ struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ u32 ccb_phyaddr_hi32;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ struct CommandControlBlock *ccb_tmp;
+ int i, j;
+
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
+ ARCMSR_MAX_FREECCB_NUM *
+ sizeof (struct CommandControlBlock) + 0x20,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent)
+ return -ENOMEM;
+
+ acb->dma_coherent = dma_coherent;
+ acb->dma_coherent_handle = dma_coherent_handle;
+
+ if (((unsigned long)dma_coherent & 0x1F)) {
+ dma_coherent = dma_coherent +
+ (0x20 - ((unsigned long)dma_coherent & 0x1F));
+ dma_coherent_handle = dma_coherent_handle +
+ (0x20 - ((unsigned long)dma_coherent_handle & 0x1F));
+ }
+
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+ dma_addr = dma_addr + sizeof (struct CommandControlBlock);
+ ccb_tmp++;
+ }
+
+ acb->vir2phy_offset = (unsigned long)ccb_tmp -
+ (unsigned long)dma_addr;
+ for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+ for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+ acb->devstate[i][j] = ARECA_RAID_GOOD;
+
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
+ if (ccb_phyaddr_hi32 != 0) {
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
+ writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE "arcmsr%d: "
+ "'set ccb high part physical address' timeout\n",
+ acb->host->host_no);
+ }
+
+ writel(readl(&reg->outbound_intmask) |
+ ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+ &reg->outbound_intmask);
+ return 0;
+}
+
+static int arcmsr_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct Scsi_Host *host;
+ struct AdapterControlBlock *acb;
+ uint8_t bus, dev_fun;
+ int error;
+
+ error = pci_enable_device(pdev);
+ if (error)
+ goto out;
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&arcmsr_scsi_host_template,
+ sizeof(struct AdapterControlBlock));
+ if (!host) {
+ error = -ENOMEM;
+ goto out_disable_device;
+ }
+ acb = (struct AdapterControlBlock *)host->hostdata;
+ memset(acb, 0, sizeof (struct AdapterControlBlock));
+
+ error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+ if (error) {
+ error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (error) {
+ printk(KERN_WARNING
+ "scsi%d: No suitable DMA mask available\n",
+ host->host_no);
+ goto out_host_put;
+ }
+ }
+ bus = pdev->bus->number;
+ dev_fun = pdev->devfn;
+ acb->host = host;
+ acb->pdev = pdev;
+ host->max_sectors = ARCMSR_MAX_XFER_SECTORS;
+ host->max_lun = ARCMSR_MAX_TARGETLUN;
+ host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/
+ host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/
+ host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES;
+ host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */
+ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
+ host->this_id = ARCMSR_SCSI_INITIATOR_ID;
+ host->unique_id = (bus << 8) | dev_fun;
+ host->irq = pdev->irq;
+ error = pci_request_regions(pdev, "arcmsr");
+ if (error)
+ goto out_host_put;
+
+ acb->pmu = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if (!acb->pmu) {
+ printk(KERN_NOTICE "arcmsr%d: memory"
+ " mapping region fail \n", acb->host->host_no);
+ goto out_release_regions;
+ }
+ acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_RQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
+ INIT_LIST_HEAD(&acb->ccb_free_list);
+
+ error = arcmsr_alloc_ccb_pool(acb);
+ if (error)
+ goto out_iounmap;
+
+ error = request_irq(pdev->irq, arcmsr_do_interrupt,
+ SA_INTERRUPT | SA_SHIRQ, "arcmsr", acb);
+ if (error)
+ goto out_free_ccb_pool;
+
+ arcmsr_iop_init(acb);
+ pci_set_drvdata(pdev, host);
+
+ error = scsi_add_host(host, &pdev->dev);
+ if (error)
+ goto out_free_irq;
+
+ error = arcmsr_alloc_sysfs_attr(acb);
+ if (error)
+ goto out_free_sysfs;
+
+ scsi_scan_host(host);
+ return 0;
+ out_free_sysfs:
+ out_free_irq:
+ free_irq(pdev->irq, acb);
+ out_free_ccb_pool:
+ arcmsr_free_ccb_pool(acb);
+ out_iounmap:
+ iounmap(acb->pmu);
+ out_release_regions:
+ pci_release_regions(pdev);
+ out_host_put:
+ scsi_host_put(host);
+ out_disable_device:
+ pci_disable_device(pdev);
+ out:
+ return error;
+}
+
+static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+
+ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'abort all outstanding command' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
+{
+ struct AdapterControlBlock *acb = ccb->acb;
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+
+ if (pcmd->use_sg != 0) {
+ struct scatterlist *sl;
+
+ sl = (struct scatterlist *)pcmd->request_buffer;
+ pci_unmap_sg(acb->pdev, sl, pcmd->use_sg, pcmd->sc_data_direction);
+ }
+ else if (pcmd->request_bufflen != 0)
+ pci_unmap_single(acb->pdev,
+ pcmd->SCp.dma_handle,
+ pcmd->request_bufflen, pcmd->sc_data_direction);
+}
+
+static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag)
+{
+ struct AdapterControlBlock *acb = ccb->acb;
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+
+ arcmsr_pci_unmap_dma(ccb);
+ if (stand_flag == 1)
+ atomic_dec(&acb->ccboutstandingcount);
+ ccb->startdone = ARCMSR_CCB_DONE;
+ ccb->ccb_flags = 0;
+ list_add_tail(&ccb->list, &acb->ccb_free_list);
+ pcmd->scsi_done(pcmd);
+}
+
+static void arcmsr_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ struct MessageUnit __iomem *reg = acb->pmu;
+ int poll_count = 0;
+
+ arcmsr_free_sysfs_attr(acb);
+ scsi_remove_host(host);
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
+ writel(readl(&reg->outbound_intmask) |
+ ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+ &reg->outbound_intmask);
+ acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
+ acb->acb_flags &= ~ACB_F_IOP_INITED;
+
+ for (poll_count = 0; poll_count < 256; poll_count++) {
+ if (!atomic_read(&acb->ccboutstandingcount))
+ break;
+ arcmsr_interrupt(acb);
+ msleep(25);
+ }
+
+ if (atomic_read(&acb->ccboutstandingcount)) {
+ int i;
+
+ arcmsr_abort_allcmd(acb);
+ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
+ readl(&reg->outbound_queueport);
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ struct CommandControlBlock *ccb = acb->pccb_pool[i];
+ if (ccb->startdone == ARCMSR_CCB_START) {
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ }
+ }
+
+ free_irq(pdev->irq, acb);
+ iounmap(acb->pmu);
+ arcmsr_free_ccb_pool(acb);
+ pci_release_regions(pdev);
+
+ scsi_host_put(host);
+
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+static void arcmsr_shutdown(struct pci_dev *pdev)
+{
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *)host->hostdata;
+
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
+}
+
+static int arcmsr_module_init(void)
+{
+ int error = 0;
+
+ error = pci_register_driver(&arcmsr_pci_driver);
+ return error;
+}
+
+static void arcmsr_module_exit(void)
+{
+ pci_unregister_driver(&arcmsr_pci_driver);
+}
+module_init(arcmsr_module_init);
+module_exit(arcmsr_module_exit);
+
+static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ u32 orig_mask = readl(&reg->outbound_intmask);
+
+ writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+ &reg->outbound_intmask);
+ return orig_mask;
+}
+
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
+ u32 orig_mask)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ u32 mask;
+
+ mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
+ ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+ writel(mask, &reg->outbound_intmask);
+}
+
+static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg=acb->pmu;
+
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'flush adapter cache' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+{
+ struct scsi_cmnd *pcmd = ccb->pcmd;
+ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
+
+ pcmd->result = DID_OK << 16;
+ if (sensebuffer) {
+ int sense_data_length =
+ sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer)
+ ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer);
+ memset(sensebuffer, 0, sizeof (pcmd->sense_buffer));
+ memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+ sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
+ sensebuffer->Valid = 1;
+ }
+}
+
+static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus)
+ & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT
+ , &reg->outbound_intstatus);
+ return 0x00;
+ }
+ msleep_interruptible(10);
+ }/*max 1 seconds*/
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static void arcmsr_build_ccb(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
+{
+ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+ int8_t *psge = (int8_t *)&arcmsr_cdb->u;
+ uint32_t address_lo, address_hi;
+ int arccdbsize = 0x30;
+
+ ccb->pcmd = pcmd;
+ memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB));
+ arcmsr_cdb->Bus = 0;
+ arcmsr_cdb->TargetID = pcmd->device->id;
+ arcmsr_cdb->LUN = pcmd->device->lun;
+ arcmsr_cdb->Function = 1;
+ arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
+ arcmsr_cdb->Context = (unsigned long)arcmsr_cdb;
+ memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
+ if (pcmd->use_sg) {
+ int length, sgcount, i, cdb_sgcount = 0;
+ struct scatterlist *sl;
+
+ /* Get Scatter Gather List from scsiport. */
+ sl = (struct scatterlist *) pcmd->request_buffer;
+ sgcount = pci_map_sg(acb->pdev, sl, pcmd->use_sg,
+ pcmd->sc_data_direction);
+ /* map stor port SG list to our iop SG List. */
+ for (i = 0; i < sgcount; i++) {
+ /* Get the physical address of the current data pointer */
+ length = cpu_to_le32(sg_dma_len(sl));
+ address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sl)));
+ address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sl)));
+ if (address_hi == 0) {
+ struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
+
+ pdma_sg->address = address_lo;
+ pdma_sg->length = length;
+ psge += sizeof (struct SG32ENTRY);
+ arccdbsize += sizeof (struct SG32ENTRY);
+ } else {
+ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+
+ pdma_sg->addresshigh = address_hi;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = length|IS_SG64_ADDR;
+ psge += sizeof (struct SG64ENTRY);
+ arccdbsize += sizeof (struct SG64ENTRY);
+ }
+ sl++;
+ cdb_sgcount++;
+ }
+ arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
+ arcmsr_cdb->DataLength = pcmd->request_bufflen;
+ if ( arccdbsize > 256)
+ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
+ } else if (pcmd->request_bufflen) {
+ dma_addr_t dma_addr;
+ dma_addr = pci_map_single(acb->pdev, pcmd->request_buffer,
+ pcmd->request_bufflen, pcmd->sc_data_direction);
+ pcmd->SCp.dma_handle = dma_addr;
+ address_lo = cpu_to_le32(dma_addr_lo32(dma_addr));
+ address_hi = cpu_to_le32(dma_addr_hi32(dma_addr));
+ if (address_hi == 0) {
+ struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = pcmd->request_bufflen;
+ } else {
+ struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
+ pdma_sg->addresshigh = address_hi;
+ pdma_sg->address = address_lo;
+ pdma_sg->length = pcmd->request_bufflen|IS_SG64_ADDR;
+ }
+ arcmsr_cdb->sgcount = 1;
+ arcmsr_cdb->DataLength = pcmd->request_bufflen;
+ }
+ if (pcmd->sc_data_direction == DMA_TO_DEVICE ) {
+ arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
+ ccb->ccb_flags |= CCB_FLAG_WRITE;
+ }
+}
+
+static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr;
+ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+
+ atomic_inc(&acb->ccboutstandingcount);
+ ccb->startdone = ARCMSR_CCB_START;
+ if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
+ writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ &reg->inbound_queueport);
+ else
+ writel(cdb_shifted_phyaddr, &reg->inbound_queueport);
+}
+
+void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
+ uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data;
+ int32_t allxfer_len = 0;
+
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
+ && (allxfer_len < 124)) {
+ writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
+ acb->wqbuf_firstindex++;
+ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ writel(allxfer_len, &pwbuffer->data_len);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK
+ , &reg->inbound_doorbell);
+ }
+}
+
+static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+
+ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
+ , acb->host->host_no);
+}
+
+static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
+{
+ dma_free_coherent(&acb->pdev->dev,
+ ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20,
+ acb->dma_coherent,
+ acb->dma_coherent_handle);
+}
+
+static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, outbound_intstatus, outbound_doorbell;
+
+ outbound_intstatus = readl(&reg->outbound_intstatus)
+ & acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) {
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+ struct QBUFFER __iomem * prbuffer =
+ (struct QBUFFER __iomem *) &reg->message_rbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+
+ rqbuf_lastindex = acb->rqbuf_lastindex;
+ rqbuf_firstindex = acb->rqbuf_firstindex;
+ iop_len = readl(&prbuffer->data_len);
+ my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= iop_len) {
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ } else
+ acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
+ }
+ if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
+ if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
+ struct QBUFFER __iomem * pwbuffer =
+ (struct QBUFFER __iomem *) &reg->message_wbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data;
+ int32_t allxfer_len = 0;
+
+ acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+ while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex)
+ && (allxfer_len < 124)) {
+ writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data);
+ acb->wqbuf_firstindex++;
+ acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ allxfer_len++;
+ }
+ writel(allxfer_len, &pwbuffer->data_len);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
+ &reg->inbound_doorbell);
+ }
+ if (acb->wqbuf_firstindex == acb->wqbuf_lastindex)
+ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ }
+ }
+ if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
+ int id, lun;
+ /*
+ ****************************************************************
+ ** areca cdb command done
+ ****************************************************************
+ */
+ while (1) {
+ if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF)
+ break;/*chip FIFO no ccb for completion already*/
+ /* check if command done with no error*/
+ ccb = (struct CommandControlBlock *)(acb->vir2phy_offset +
+ (flag_ccb << 5));
+ if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
+ if (ccb->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd=ccb->pcmd;
+ if (abortcmd) {
+ abortcmd->result |= DID_ABORT >> 16;
+ arcmsr_ccb_complete(ccb, 1);
+ printk(KERN_NOTICE
+ "arcmsr%d: ccb='0x%p' isr got aborted command \n"
+ , acb->host->host_no, ccb);
+ }
+ continue;
+ }
+ printk(KERN_NOTICE
+ "arcmsr%d: isr get an illegal ccb command done acb='0x%p'"
+ "ccb='0x%p' ccbacb='0x%p' startdone = 0x%x"
+ " ccboutstandingcount=%d \n"
+ , acb->host->host_no
+ , acb
+ , ccb
+ , ccb->acb
+ , ccb->startdone
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ } else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_TIME_OUT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_ABORTED:
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id=%d lun=%d"
+ " isr get command error done,"
+ "but got unknown DeviceStatus = 0x%x \n"
+ , acb->host->host_no
+ , id
+ , lun
+ , ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_NO_CONNECT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ }/*drain reply FIFO*/
+ }
+ if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))
+ return IRQ_NONE;
+ return IRQ_HANDLED;
+}
+
+static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
+{
+ if (acb) {
+ /* stop adapter background rebuild */
+ if (acb->acb_flags & ACB_F_MSG_START_BGRB) {
+ acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ arcmsr_stop_adapter_bgrb(acb);
+ arcmsr_flush_adapter_cache(acb);
+ }
+ }
+}
+
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CMD_MESSAGE_FIELD *pcmdmessagefld;
+ int retvalue = 0, transfer_len = 0;
+ char *buffer;
+ uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
+ (uint32_t ) cmd->cmnd[6] << 16 |
+ (uint32_t ) cmd->cmnd[7] << 8 |
+ (uint32_t ) cmd->cmnd[8];
+ /* 4 bytes: Areca io control code */
+ if (cmd->use_sg) {
+ struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
+
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ if (cmd->use_sg > 1) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ transfer_len += sg->length;
+ } else {
+ buffer = cmd->request_buffer;
+ transfer_len = cmd->request_bufflen;
+ }
+ if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
+ switch(controlcode) {
+ case ARCMSR_MESSAGE_READ_RQBUFFER: {
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ uint8_t *pQbuffer, *ptmpQbuffer;
+ int32_t allxfer_len = 0;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpQbuffer = (uint8_t *) ver_addr;
+ while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
+ && (allxfer_len < 1031)) {
+ pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
+ memcpy(ptmpQbuffer, pQbuffer, 1);
+ acb->rqbuf_firstindex++;
+ acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
+ ptmpQbuffer++;
+ allxfer_len++;
+ }
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
+ &reg->message_rbuffer;
+ uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ int32_t iop_len;
+
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ iop_len = readl(&prbuffer->data_len);
+ while (iop_len > 0) {
+ acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
+ acb->rqbuf_lastindex++;
+ acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ iop_data++;
+ iop_len--;
+ }
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ }
+ memcpy(pcmdmessagefld->messagedatabuffer,
+ (uint8_t *)ver_addr, allxfer_len);
+ pcmdmessagefld->cmdmessage.Length = allxfer_len;
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ }
+ break;
+ case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
+ unsigned long *ver_addr;
+ dma_addr_t buf_handle;
+ int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+ uint8_t *pQbuffer, *ptmpuserbuffer;
+
+ ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle);
+ if (!ver_addr) {
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ goto message_out;
+ }
+ ptmpuserbuffer = (uint8_t *)ver_addr;
+ user_len = pcmdmessagefld->cmdmessage.Length;
+ memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+ wqbuf_lastindex = acb->wqbuf_lastindex;
+ wqbuf_firstindex = acb->wqbuf_firstindex;
+ if (wqbuf_lastindex != wqbuf_firstindex) {
+ struct SENSE_DATA *sensebuffer =
+ (struct SENSE_DATA *)cmd->sense_buffer;
+ arcmsr_post_Qbuffer(acb);
+ /* has error report sensedata */
+ sensebuffer->ErrorCode = 0x70;
+ sensebuffer->SenseKey = ILLEGAL_REQUEST;
+ sensebuffer->AdditionalSenseLength = 0x0A;
+ sensebuffer->AdditionalSenseCode = 0x20;
+ sensebuffer->Valid = 1;
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ } else {
+ my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
+ &(ARCMSR_MAX_QBUFFER - 1);
+ if (my_empty_len >= user_len) {
+ while (user_len > 0) {
+ pQbuffer =
+ &acb->wqbuffer[acb->wqbuf_lastindex];
+ memcpy(pQbuffer, ptmpuserbuffer, 1);
+ acb->wqbuf_lastindex++;
+ acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+ ptmpuserbuffer++;
+ user_len--;
+ }
+ if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+ acb->acb_flags &=
+ ~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+ arcmsr_post_Qbuffer(acb);
+ }
+ } else {
+ /* has error report sensedata */
+ struct SENSE_DATA *sensebuffer =
+ (struct SENSE_DATA *)cmd->sense_buffer;
+ sensebuffer->ErrorCode = 0x70;
+ sensebuffer->SenseKey = ILLEGAL_REQUEST;
+ sensebuffer->AdditionalSenseLength = 0x0A;
+ sensebuffer->AdditionalSenseCode = 0x20;
+ sensebuffer->Valid = 1;
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ }
+ }
+ pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle);
+ }
+ break;
+ case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
+ uint8_t *pQbuffer = acb->rqbuffer;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+ &reg->inbound_doorbell);
+ }
+ acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
+ uint8_t *pQbuffer = acb->wqbuffer;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+ , &reg->inbound_doorbell);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+ ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
+ pcmdmessagefld->cmdmessage.ReturnCode =
+ ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
+ uint8_t *pQbuffer;
+
+ if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
+ acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
+ , &reg->inbound_doorbell);
+ }
+ acb->acb_flags |=
+ (ACB_F_MESSAGE_WQBUFFER_CLEARED
+ | ACB_F_MESSAGE_RQBUFFER_CLEARED
+ | ACB_F_MESSAGE_WQBUFFER_READED);
+ acb->rqbuf_firstindex = 0;
+ acb->rqbuf_lastindex = 0;
+ acb->wqbuf_firstindex = 0;
+ acb->wqbuf_lastindex = 0;
+ pQbuffer = acb->rqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ pQbuffer = acb->wqbuffer;
+ memset(pQbuffer, 0, sizeof (struct QBUFFER));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_RETURN_CODE_3F: {
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
+ }
+ break;
+ case ARCMSR_MESSAGE_SAY_HELLO: {
+ int8_t * hello_string = "Hello! I am ARCMSR";
+
+ memcpy(pcmdmessagefld->messagedatabuffer, hello_string
+ , (int16_t)strlen(hello_string));
+ pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+ }
+ break;
+ case ARCMSR_MESSAGE_SAY_GOODBYE:
+ arcmsr_iop_parking(acb);
+ break;
+ case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
+ arcmsr_flush_adapter_cache(acb);
+ break;
+ default:
+ retvalue = ARCMSR_MESSAGE_FAIL;
+ }
+ message_out:
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ }
+ return retvalue;
+}
+
+static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb)
+{
+ struct list_head *head = &acb->ccb_free_list;
+ struct CommandControlBlock *ccb = NULL;
+
+ if (!list_empty(head)) {
+ ccb = list_entry(head->next, struct CommandControlBlock, list);
+ list_del(head->next);
+ }
+ return ccb;
+}
+
+static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
+ struct scsi_cmnd *cmd)
+{
+ switch (cmd->cmnd[0]) {
+ case INQUIRY: {
+ unsigned char inqdata[36];
+ char *buffer;
+
+ if (cmd->device->lun) {
+ cmd->result = (DID_TIME_OUT << 16);
+ cmd->scsi_done(cmd);
+ return;
+ }
+ inqdata[0] = TYPE_PROCESSOR;
+ /* Periph Qualifier & Periph Dev Type */
+ inqdata[1] = 0;
+ /* rem media bit & Dev Type Modifier */
+ inqdata[2] = 0;
+ /* ISO,ECMA,& ANSI versions */
+ inqdata[4] = 31;
+ /* length of additional data */
+ strncpy(&inqdata[8], "Areca ", 8);
+ /* Vendor Identification */
+ strncpy(&inqdata[16], "RAID controller ", 16);
+ /* Product Identification */
+ strncpy(&inqdata[32], "R001", 4); /* Product Revision */
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset;
+ } else {
+ buffer = cmd->request_buffer;
+ }
+ memcpy(buffer, inqdata, sizeof(inqdata));
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+
+ sg = (struct scatterlist *) cmd->request_buffer;
+ kunmap_atomic(buffer - sg->offset, KM_IRQ0);
+ }
+ cmd->scsi_done(cmd);
+ }
+ break;
+ case WRITE_BUFFER:
+ case READ_BUFFER: {
+ if (arcmsr_iop_message_xfer(acb, cmd))
+ cmd->result = (DID_ERROR << 16);
+ cmd->scsi_done(cmd);
+ }
+ break;
+ default:
+ cmd->scsi_done(cmd);
+ }
+}
+
+static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+ void (* done)(struct scsi_cmnd *))
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ struct CommandControlBlock *ccb;
+ int target = cmd->device->id;
+ int lun = cmd->device->lun;
+
+ cmd->scsi_done = done;
+ cmd->host_scribble = NULL;
+ cmd->result = 0;
+ if (acb->acb_flags & ACB_F_BUS_RESET) {
+ printk(KERN_NOTICE "arcmsr%d: bus reset"
+ " and return busy \n"
+ , acb->host->host_no);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ if(target == 16) {
+ /* virtual device for iop message transfer */
+ arcmsr_handle_virtual_command(acb, cmd);
+ return 0;
+ }
+ if (acb->devstate[target][lun] == ARECA_RAID_GONE) {
+ uint8_t block_cmd;
+
+ block_cmd = cmd->cmnd[0] & 0x0f;
+ if (block_cmd == 0x08 || block_cmd == 0x0a) {
+ printk(KERN_NOTICE
+ "arcmsr%d: block 'read/write'"
+ "command with gone raid volume"
+ " Cmd=%2x, TargetId=%d, Lun=%d \n"
+ , acb->host->host_no
+ , cmd->cmnd[0]
+ , target, lun);
+ cmd->result = (DID_NO_CONNECT << 16);
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ }
+ if (atomic_read(&acb->ccboutstandingcount) >=
+ ARCMSR_MAX_OUTSTANDING_CMD)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ ccb = arcmsr_get_freeccb(acb);
+ if (!ccb)
+ return SCSI_MLQUEUE_HOST_BUSY;
+ arcmsr_build_ccb(acb, ccb, cmd);
+ arcmsr_post_ccb(acb, ccb);
+ return 0;
+}
+
+static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ char *acb_firm_model = acb->firm_model;
+ char *acb_firm_version = acb->firm_version;
+ char __iomem *iop_firm_model = (char __iomem *) &reg->message_rwbuffer[15];
+ char __iomem *iop_firm_version = (char __iomem *) &reg->message_rwbuffer[17];
+ int count;
+
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait "
+ "'get adapter firmware miscellaneous data' timeout \n"
+ , acb->host->host_no);
+ count = 8;
+ while (count) {
+ *acb_firm_model = readb(iop_firm_model);
+ acb_firm_model++;
+ iop_firm_model++;
+ count--;
+ }
+ count = 16;
+ while (count) {
+ *acb_firm_version = readb(iop_firm_version);
+ acb_firm_version++;
+ iop_firm_version++;
+ count--;
+ }
+ printk(KERN_INFO
+ "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
+ , acb->host->host_no
+ , acb->firm_version);
+ acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
+ acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
+ acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
+ acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
+}
+
+static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
+ int id, lun;
+
+ polling_ccb_retry:
+ poll_count++;
+ outbound_intstatus = readl(&reg->outbound_intstatus)
+ & acb->outbound_int_enable;
+ writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+ while (1) {
+ if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
+ if (poll_ccb_done)
+ break;
+ else {
+ msleep(25);
+ if (poll_count > 100)
+ break;
+ goto polling_ccb_retry;
+ }
+ }
+ ccb = (struct CommandControlBlock *)
+ (acb->vir2phy_offset + (flag_ccb << 5));
+ if ((ccb->acb != acb) ||
+ (ccb->startdone != ARCMSR_CCB_START)) {
+ if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
+ (ccb == poll_ccb)) {
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id=%d lun=%d ccb='0x%p'"
+ " poll command abort successfully \n"
+ , acb->host->host_no
+ , ccb->pcmd->device->id
+ , ccb->pcmd->device->lun
+ , ccb);
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ poll_ccb_done = 1;
+ continue;
+ }
+ printk(KERN_NOTICE
+ "arcmsr%d: polling get an illegal ccb"
+ " command done ccb='0x%p'"
+ "ccboutstandingcount=%d \n"
+ , acb->host->host_no
+ , ccb
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ id = ccb->pcmd->device->id;
+ lun = ccb->pcmd->device->lun;
+ if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (acb->devstate[id][lun] == ARECA_RAID_GONE)
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ ccb->pcmd->result = DID_OK << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ } else {
+ switch(ccb->arcmsr_cdb.DeviceStatus) {
+ case ARCMSR_DEV_SELECT_TIMEOUT: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_TIME_OUT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_ABORTED:
+ case ARCMSR_DEV_INIT_FAIL: {
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ case ARCMSR_DEV_CHECK_CONDITION: {
+ acb->devstate[id][lun] = ARECA_RAID_GOOD;
+ arcmsr_report_sense_info(ccb);
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ break;
+ default:
+ printk(KERN_NOTICE
+ "arcmsr%d: scsi id=%d lun=%d"
+ " polling and getting command error done"
+ "but got unknown DeviceStatus = 0x%x \n"
+ , acb->host->host_no
+ , id
+ , lun
+ , ccb->arcmsr_cdb.DeviceStatus);
+ acb->devstate[id][lun] = ARECA_RAID_GONE;
+ ccb->pcmd->result = DID_BAD_TARGET << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ break;
+ }
+ }
+ }
+}
+
+static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0;
+
+ do {
+ firmware_state = readl(&reg->outbound_msgaddr1);
+ } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK));
+ intmask_org = readl(&reg->outbound_intmask)
+ | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+ arcmsr_get_firmware_spec(acb);
+
+ acb->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
+ if (arcmsr_wait_msgint_ready(acb)) {
+ printk(KERN_NOTICE "arcmsr%d: "
+ "wait 'start adapter background rebulid' timeout\n",
+ acb->host->host_no);
+ }
+
+ outbound_doorbell = readl(&reg->outbound_doorbell);
+ writel(outbound_doorbell, &reg->outbound_doorbell);
+ writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+ mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE
+ | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+ writel(intmask_org & mask, &reg->outbound_intmask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+ acb->acb_flags |= ACB_F_IOP_INITED;
+}
+
+static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit __iomem *reg = acb->pmu;
+ struct CommandControlBlock *ccb;
+ uint32_t intmask_org;
+ int i = 0;
+
+ if (atomic_read(&acb->ccboutstandingcount) != 0) {
+ /* talk to iop 331 outstanding command aborted */
+ arcmsr_abort_allcmd(acb);
+ /* wait for 3 sec for all command aborted*/
+ msleep_interruptible(3000);
+ /* disable all outbound interrupt */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ /* clear all outbound posted Q */
+ for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++)
+ readl(&reg->outbound_queueport);
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb = acb->pccb_pool[i];
+ if ((ccb->startdone == ARCMSR_CCB_START) ||
+ (ccb->startdone == ARCMSR_CCB_ABORTED)) {
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+ ccb->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(ccb, 1);
+ }
+ }
+ /* enable all outbound interrupt */
+ arcmsr_enable_outbound_ints(acb, intmask_org);
+ }
+ atomic_set(&acb->ccboutstandingcount, 0);
+}
+
+static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
+{
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *)cmd->device->host->hostdata;
+ int i;
+
+ acb->num_resets++;
+ acb->acb_flags |= ACB_F_BUS_RESET;
+ for (i = 0; i < 400; i++) {
+ if (!atomic_read(&acb->ccboutstandingcount))
+ break;
+ arcmsr_interrupt(acb);
+ msleep(25);
+ }
+ arcmsr_iop_reset(acb);
+ acb->acb_flags &= ~ACB_F_BUS_RESET;
+ return SUCCESS;
+}
+
+static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
+ struct CommandControlBlock *ccb)
+{
+ u32 intmask;
+
+ ccb->startdone = ARCMSR_CCB_ABORTED;
+
+ /*
+ ** Wait for 3 sec for all command done.
+ */
+ msleep_interruptible(3000);
+
+ intmask = arcmsr_disable_outbound_ints(acb);
+ arcmsr_polling_ccbdone(acb, ccb);
+ arcmsr_enable_outbound_ints(acb, intmask);
+}
+
+static int arcmsr_abort(struct scsi_cmnd *cmd)
+{
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *)cmd->device->host->hostdata;
+ int i = 0;
+
+ printk(KERN_NOTICE
+ "arcmsr%d: abort device command of scsi id=%d lun=%d \n",
+ acb->host->host_no, cmd->device->id, cmd->device->lun);
+ acb->num_aborts++;
+
+ /*
+ ************************************************
+ ** the all interrupt service routine is locked
+ ** we need to handle it as soon as possible and exit
+ ************************************************
+ */
+ if (!atomic_read(&acb->ccboutstandingcount))
+ return SUCCESS;
+
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ struct CommandControlBlock *ccb = acb->pccb_pool[i];
+ if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
+ arcmsr_abort_one_cmd(acb, ccb);
+ break;
+ }
+ }
+
+ return SUCCESS;
+}
+
+static const char *arcmsr_info(struct Scsi_Host *host)
+{
+ struct AdapterControlBlock *acb =
+ (struct AdapterControlBlock *) host->hostdata;
+ static char buf[256];
+ char *type;
+ int raid6 = 1;
+
+ switch (acb->pdev->device) {
+ case PCI_DEVICE_ID_ARECA_1110:
+ case PCI_DEVICE_ID_ARECA_1210:
+ raid6 = 0;
+ /*FALLTHRU*/
+ case PCI_DEVICE_ID_ARECA_1120:
+ case PCI_DEVICE_ID_ARECA_1130:
+ case PCI_DEVICE_ID_ARECA_1160:
+ case PCI_DEVICE_ID_ARECA_1170:
+ case PCI_DEVICE_ID_ARECA_1220:
+ case PCI_DEVICE_ID_ARECA_1230:
+ case PCI_DEVICE_ID_ARECA_1260:
+ case PCI_DEVICE_ID_ARECA_1270:
+ case PCI_DEVICE_ID_ARECA_1280:
+ type = "SATA";
+ break;
+ case PCI_DEVICE_ID_ARECA_1380:
+ case PCI_DEVICE_ID_ARECA_1381:
+ case PCI_DEVICE_ID_ARECA_1680:
+ case PCI_DEVICE_ID_ARECA_1681:
+ type = "SAS";
+ break;
+ default:
+ type = "X-TYPE";
+ break;
+ }
+ sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",
+ type, raid6 ? "( RAID6 capable)" : "",
+ ARCMSR_DRIVER_VERSION);
+ return buf;
+}
+
+
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
index 06d7601cdf5..d006a8cb4a7 100644
--- a/drivers/scsi/arm/Kconfig
+++ b/drivers/scsi/arm/Kconfig
@@ -69,6 +69,7 @@ comment "The following drivers are not fully supported"
config SCSI_CUMANA_1
tristate "CumanaSCSI I support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+ select SCSI_SPI_ATTRS
help
This enables support for the Cumana SCSI I card. If you have an
Acorn system with one of these, say Y. If unsure, say N.
@@ -76,6 +77,7 @@ config SCSI_CUMANA_1
config SCSI_ECOSCSI
tristate "EcoScsi support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
+ select SCSI_SPI_ATTRS
help
This enables support for the EcoSCSI card -- a small card that sits
in the Econet socket. If you have an Acorn system with one of these,
@@ -84,6 +86,7 @@ config SCSI_ECOSCSI
config SCSI_OAK1
tristate "Oak SCSI support (EXPERIMENTAL)"
depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+ select SCSI_SPI_ATTRS
help
This enables support for the Oak SCSI card. If you have an Acorn
system with one of these, say Y. If unsure, say N.
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index dda5a5f79c5..7621e3fa37b 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -129,7 +129,6 @@
#define STRx(x) STRINGIFY(x)
#define NO_WRITE_STR STRx(NO_WRITE)
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -3031,7 +3030,7 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
if (!request_region(host->io_port, 2048, "acornscsi(ram)"))
goto err_5;
- ret = request_irq(host->irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", ashost);
+ ret = request_irq(host->irq, acornscsi_intr, IRQF_DISABLED, "acornscsi", ashost);
if (ret) {
printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
host->host_no, ashost->scsi.irq, ret);
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index e6c9491dc5c..3bdfc36481a 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -277,7 +277,7 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
outb(0x00, host->io_port - 577);
- ret = request_irq(host->irq, cumanascsi_intr, SA_INTERRUPT,
+ ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED,
"CumanaSCSI-1", host);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index fad2109268b..719af0dcc0e 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -460,7 +460,7 @@ cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
goto out_free;
ret = request_irq(ec->irq, cumanascsi_2_intr,
- SA_INTERRUPT, "cumanascsi2", info);
+ IRQF_DISABLED, "cumanascsi2", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 3e1053f111d..4cf7afc31cc 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2427,7 +2427,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
info->stats.aborts += 1;
printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
- __scsi_print_command(SCpnt->data_cmnd);
+ __scsi_print_command(SCpnt->cmnd);
print_debug_list();
fas216_dumpstate(info);
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index 3d69f6c45a6..b2c346a4705 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -373,7 +373,7 @@ powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
goto out_free;
ret = request_irq(ec->irq, powertecscsi_intr,
- SA_INTERRUPT, "powertec", info);
+ IRQF_DISABLED, "powertec", info);
if (ret) {
printk("scsi%d: IRQ%d not free: %d\n",
host->host_no, ec->irq, ret);
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 6dd544a5eb5..8c2600ffc6a 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -74,7 +74,7 @@ static inline void init_SCp(Scsi_Cmnd *SCpnt)
unsigned long len = 0;
int buf;
- SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
+ SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer;
SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
SCpnt->SCp.ptr = (char *)
(page_address(SCpnt->SCp.buffer->page) +
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 57295bcea3e..e397129c90d 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -507,7 +507,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
cmd->SCp.buffer->offset;
@@ -524,7 +524,6 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
}
}
-#include <linux/config.h>
#include <linux/delay.h>
#if NDEBUG
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index f677c5a32a6..e1be4a4387c 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -65,7 +65,6 @@
-#include <linux/config.h>
#include <linux/module.h>
#define NDEBUG (0)
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 3ee4d4d3f44..0ec41f34f46 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -2625,29 +2625,32 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
unsigned int base_io, tmport, error,n;
unsigned char host_id;
struct Scsi_Host *shpnt = NULL;
- struct atp_unit atp_dev, *p;
+ struct atp_unit *atpdev, *p;
unsigned char setupdata[2][16];
int count = 0;
-
+
+ atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL);
+ if (!atpdev)
+ return -ENOMEM;
+
if (pci_enable_device(pdev))
- return -EIO;
+ goto err_eio;
if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
} else {
printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
- return -EIO;
+ goto err_eio;
}
- memset(&atp_dev, 0, sizeof atp_dev);
/*
* It's probably easier to weed out some revisions like
* this than via the PCI device table
*/
if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
- error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
- if (atp_dev.chip_ver < 2)
- return -EIO;
+ error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver);
+ if (atpdev->chip_ver < 2)
+ goto err_eio;
}
switch (ent->device) {
@@ -2656,15 +2659,15 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
case ATP880_DEVID1:
case ATP880_DEVID2:
case ATP885_DEVID:
- atp_dev.chip_ver = 0x04;
+ atpdev->chip_ver = 0x04;
default:
break;
}
base_io = pci_resource_start(pdev, 0);
base_io &= 0xfffffff8;
-
+
if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
- error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
+ error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atpdev->chip_ver);
pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
host_id = inb(base_io + 0x39);
@@ -2672,17 +2675,17 @@ static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
" IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atp_dev.ioport[0] = base_io + 0x40;
- atp_dev.pciport[0] = base_io + 0x28;
- atp_dev.dev_id = ent->device;
- atp_dev.host_id[0] = host_id;
+ atpdev->ioport[0] = base_io + 0x40;
+ atpdev->pciport[0] = base_io + 0x28;
+ atpdev->dev_id = ent->device;
+ atpdev->host_id[0] = host_id;
tmport = base_io + 0x22;
- atp_dev.scam_on = inb(tmport);
+ atpdev->scam_on = inb(tmport);
tmport += 0x13;
- atp_dev.global_map[0] = inb(tmport);
+ atpdev->global_map[0] = inb(tmport);
tmport += 0x07;
- atp_dev.ultra_map[0] = inw(tmport);
+ atpdev->ultra_map[0] = inw(tmport);
n = 0x3f09;
next_fblk_880:
@@ -2695,63 +2698,63 @@ next_fblk_880:
if (inb(base_io + 0x30) == 0xff)
goto flash_ok_880;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
outw(n, base_io + 0x34);
n += 0x0002;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
outw(n, base_io + 0x34);
n += 0x0002;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
outw(n, base_io + 0x34);
n += 0x0002;
- atp_dev.sp[0][m++] = inb(base_io + 0x30);
- atp_dev.sp[0][m++] = inb(base_io + 0x31);
- atp_dev.sp[0][m++] = inb(base_io + 0x32);
- atp_dev.sp[0][m++] = inb(base_io + 0x33);
+ atpdev->sp[0][m++] = inb(base_io + 0x30);
+ atpdev->sp[0][m++] = inb(base_io + 0x31);
+ atpdev->sp[0][m++] = inb(base_io + 0x32);
+ atpdev->sp[0][m++] = inb(base_io + 0x33);
n += 0x0018;
goto next_fblk_880;
flash_ok_880:
outw(0, base_io + 0x34);
- atp_dev.ultra_map[0] = 0;
- atp_dev.async[0] = 0;
+ atpdev->ultra_map[0] = 0;
+ atpdev->async[0] = 0;
for (k = 0; k < 16; k++) {
n = 1;
n = n << k;
- if (atp_dev.sp[0][k] > 1) {
- atp_dev.ultra_map[0] |= n;
+ if (atpdev->sp[0][k] > 1) {
+ atpdev->ultra_map[0] |= n;
} else {
- if (atp_dev.sp[0][k] == 0)
- atp_dev.async[0] |= n;
+ if (atpdev->sp[0][k] == 0)
+ atpdev->async[0] |= n;
}
}
- atp_dev.async[0] = ~(atp_dev.async[0]);
- outb(atp_dev.global_map[0], base_io + 0x35);
+ atpdev->async[0] = ~(atpdev->async[0]);
+ outb(atpdev->global_map[0], base_io + 0x35);
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
if (!shpnt)
- return -ENOMEM;
+ goto err_nomem;
p = (struct atp_unit *)&shpnt->hostdata;
- atp_dev.host = shpnt;
- atp_dev.pdev = pdev;
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
pci_set_drvdata(pdev, p);
- memcpy(p, &atp_dev, sizeof atp_dev);
+ memcpy(p, atpdev, sizeof(*atpdev));
if (atp870u_init_tables(shpnt) < 0) {
printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
goto unregister;
}
- if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp880i", shpnt)) {
+ if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
goto free_tables;
}
@@ -2798,31 +2801,31 @@ flash_ok_880:
printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n"
, base_io, pdev->irq);
- atp_dev.pdev = pdev;
- atp_dev.dev_id = ent->device;
- atp_dev.baseport = base_io;
- atp_dev.ioport[0] = base_io + 0x80;
- atp_dev.ioport[1] = base_io + 0xc0;
- atp_dev.pciport[0] = base_io + 0x40;
- atp_dev.pciport[1] = base_io + 0x50;
+ atpdev->pdev = pdev;
+ atpdev->dev_id = ent->device;
+ atpdev->baseport = base_io;
+ atpdev->ioport[0] = base_io + 0x80;
+ atpdev->ioport[1] = base_io + 0xc0;
+ atpdev->pciport[0] = base_io + 0x40;
+ atpdev->pciport[1] = base_io + 0x50;
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
if (!shpnt)
- return -ENOMEM;
+ goto err_nomem;
p = (struct atp_unit *)&shpnt->hostdata;
- atp_dev.host = shpnt;
- atp_dev.pdev = pdev;
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
pci_set_drvdata(pdev, p);
- memcpy(p, &atp_dev, sizeof(struct atp_unit));
+ memcpy(p, atpdev, sizeof(struct atp_unit));
if (atp870u_init_tables(shpnt) < 0)
goto unregister;
#ifdef ED_DBGP
printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
#endif
- if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) {
+ if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
goto free_tables;
}
@@ -2974,43 +2977,43 @@ flash_ok_885:
printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
"IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
- atp_dev.ioport[0] = base_io;
- atp_dev.pciport[0] = base_io + 0x20;
- atp_dev.dev_id = ent->device;
+ atpdev->ioport[0] = base_io;
+ atpdev->pciport[0] = base_io + 0x20;
+ atpdev->dev_id = ent->device;
host_id &= 0x07;
- atp_dev.host_id[0] = host_id;
+ atpdev->host_id[0] = host_id;
tmport = base_io + 0x22;
- atp_dev.scam_on = inb(tmport);
+ atpdev->scam_on = inb(tmport);
tmport += 0x0b;
- atp_dev.global_map[0] = inb(tmport++);
- atp_dev.ultra_map[0] = inw(tmport);
+ atpdev->global_map[0] = inb(tmport++);
+ atpdev->ultra_map[0] = inw(tmport);
- if (atp_dev.ultra_map[0] == 0) {
- atp_dev.scam_on = 0x00;
- atp_dev.global_map[0] = 0x20;
- atp_dev.ultra_map[0] = 0xffff;
+ if (atpdev->ultra_map[0] == 0) {
+ atpdev->scam_on = 0x00;
+ atpdev->global_map[0] = 0x20;
+ atpdev->ultra_map[0] = 0xffff;
}
shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
if (!shpnt)
- return -ENOMEM;
+ goto err_nomem;
p = (struct atp_unit *)&shpnt->hostdata;
- atp_dev.host = shpnt;
- atp_dev.pdev = pdev;
+ atpdev->host = shpnt;
+ atpdev->pdev = pdev;
pci_set_drvdata(pdev, p);
- memcpy(p, &atp_dev, sizeof atp_dev);
+ memcpy(p, atpdev, sizeof(*atpdev));
if (atp870u_init_tables(shpnt) < 0)
goto unregister;
- if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870i", shpnt)) {
+ if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) {
printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
goto free_tables;
}
spin_lock_irqsave(shpnt->host_lock, flags);
- if (atp_dev.chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
+ if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */
tmport = base_io + 0x3e;
outb(0x00, tmport);
}
@@ -3044,7 +3047,7 @@ flash_ok_885:
outb((inb(tmport) & 0xef), tmport);
tmport++;
outb((inb(tmport) | 0x20), tmport);
- if (atp_dev.chip_ver == 4)
+ if (atpdev->chip_ver == 4)
shpnt->max_id = 16;
else
shpnt->max_id = 8;
@@ -3093,6 +3096,12 @@ unregister:
printk("atp870u_prob:unregister\n");
scsi_host_put(shpnt);
return -1;
+err_eio:
+ kfree(atpdev);
+ return -EIO;
+err_nomem:
+ kfree(atpdev);
+ return -ENOMEM;
}
/* The abort command does not leave the device in a clean state where
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
index 3867ac2de4c..329a8f297b3 100644
--- a/drivers/scsi/blz1230.c
+++ b/drivers/scsi/blz1230.c
@@ -172,7 +172,7 @@ int __init blz1230_esp_detect(struct scsi_host_template *tpnt)
esp->irq = IRQ_AMIGA_PORTS;
esp->slot = board+REAL_BLZ1230_ESP_ADDR;
- if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"Blizzard 1230 SCSI IV", esp->ehost))
goto err_out;
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
index 4ebe69e3275..b6c137b9735 100644
--- a/drivers/scsi/blz2060.c
+++ b/drivers/scsi/blz2060.c
@@ -146,7 +146,7 @@ int __init blz2060_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"Blizzard 2060 SCSI", esp->ehost);
/* Figure out our scsi ID on the bus */
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index d9abd1645d1..f6caa430776 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -7,7 +7,6 @@
#define VERSION "0.25"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index d92d5040a9f..61f6024b61b 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -5,9 +5,9 @@
* Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
* by D. Gilbert and aeb (20020609)
* Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
+ * Update to SPC-4 T10/1713-D Rev 5a, 14 June 2006, D. Gilbert 20060702
*/
-#include <linux/config.h>
#include <linux/blkdev.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -37,55 +37,56 @@ static const char * cdb_byte0_names[] = {
/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
"Reasssign Blocks",
-/* 08-0d */ "Read (6)", NULL, "Write (6)", "Seek (6)", NULL, NULL,
+/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL,
/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",
-/* 13-16 */ "Verify (6)", "Recover Buffered Data", "Mode Select (6)",
- "Reserve (6)",
-/* 17-1a */ "Release (6)", "Copy", "Erase", "Mode Sense (6)",
+/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)",
+ "Reserve(6)",
+/* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)",
/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic",
/* 1e-1f */ "Prevent/Allow Medium Removal", NULL,
/* 20-22 */ NULL, NULL, NULL,
/* 23-28 */ "Read Format Capacities", "Set Window",
- "Read Capacity (10)", NULL, NULL, "Read (10)",
-/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase (10)",
- "Read updated block",
-/* 2e-31 */ "Write Verify (10)", "Verify (10)", "Search High", "Search Equal",
+ "Read Capacity(10)", NULL, NULL, "Read(10)",
+/* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)",
+ "Read updated block",
+/* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal",
/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position",
-/* 35-37 */ "Synchronize Cache (10)", "Lock/Unlock Cache (10)",
+/* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)",
"Read Defect Data(10)",
/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer",
"Read Buffer",
-/* 3d-3f */ "Update Block", "Read Long (10)", "Write Long (10)",
-/* 40-41 */ "Change Definition", "Write Same (10)",
+/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)",
+/* 40-41 */ "Change Definition", "Write Same(10)",
/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support",
- "Play audio (10)", "Get configuration", "Play audio msf",
+ "Play audio(10)", "Get configuration", "Play audio msf",
"Play audio track/index",
-/* 49-4f */ "Play track relative (10)", "Get event status notification",
+/* 49-4f */ "Play track relative(10)", "Get event status notification",
"Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
NULL,
/* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info",
- "Reserve track", "Send OPC info", "Mode Select (10)",
-/* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", "Read master cue",
- "Mode Sense (10)", "Close track/session",
+ "Reserve track", "Send OPC info", "Mode Select(10)",
+/* 56-5b */ "Reserve(10)", "Release(10)", "Repair track", "Read master cue",
+ "Mode Sense(10)", "Close track/session",
/* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in",
"Persistent reserve out",
/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length",
-/* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", "Extended copy",
+/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy",
"Receive copy results",
-/* 85-89 */ "Memory Export In (16)", "Access control in", "Access control out",
- "Read (16)", "Memory Export Out (16)",
-/* 8a-8f */ "Write (16)", NULL, "Read attributes", "Write attributes",
- "Write and verify (16)", "Verify (16)",
-/* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)",
- "Lock/unlock cache (16)", "Write same (16)", NULL,
+/* 85-89 */ "ATA command pass through(16)", "Access control in",
+ "Access control out", "Read(16)", "Memory Export Out(16)",
+/* 8a-8f */ "Write(16)", NULL, "Read attributes", "Write attributes",
+ "Write and verify(16)", "Verify(16)",
+/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)",
+ "Lock/unlock cache(16)", "Write same(16)", NULL,
/* 95-99 */ NULL, NULL, NULL, NULL, NULL,
-/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in (16)",
- "Service action out (16)",
-/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance in",
- "Maintenance out", "Move medium/play audio(12)",
+/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)",
+ "Service action out(16)",
+/* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank",
+ "Security protocol in", "Maintenance in", "Maintenance out",
+ "Move medium/play audio(12)",
/* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)",
"Play track relative(12)",
/* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance",
@@ -93,12 +94,12 @@ static const char * cdb_byte0_names[] = {
/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
/* b2-b4 */ "Search data low(12)", "Set limits(12)",
"Read element status attached",
-/* b5-b6 */ "Request volume element address", "Send volume tag, set streaming",
+/* b5-b6 */ "Security protocol out", "Send volume tag, set streaming",
/* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf",
/* ba-bc */ "Redundancy group (in), Scan",
- "Redundancy group (out), Set cd-rom speed", "Spare in, Play cd",
-/* bd-bf */ "Spare out, Mechanism status", "Volume set in, Read cd",
- "Volume set out, Send DVD structure",
+ "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd",
+/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd",
+ "Volume set (out), Send DVD structure",
};
struct value_name_pair {
@@ -113,6 +114,7 @@ static const struct value_name_pair maint_in_arr[] = {
{0xc, "Report supported operation codes"},
{0xd, "Report supported task management functions"},
{0xe, "Report priority"},
+ {0xf, "Report timestamp"},
};
#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr)
@@ -121,6 +123,7 @@ static const struct value_name_pair maint_out_arr[] = {
{0xa, "Set target port groups"},
{0xb, "Change aliases"},
{0xe, "Set priority"},
+ {0xe, "Set timestamp"},
};
#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr)
@@ -428,6 +431,7 @@ static struct error_info additional[] =
{0x001A, "Rewind operation in progress"},
{0x001B, "Set capacity operation in progress"},
{0x001C, "Verify operation in progress"},
+ {0x001D, "ATA pass through information available"},
{0x0100, "No index/sector signal"},
@@ -439,7 +443,7 @@ static struct error_info additional[] =
{0x0400, "Logical unit not ready, cause not reportable"},
{0x0401, "Logical unit is in process of becoming ready"},
- {0x0402, "Logical unit not ready, initializing cmd. required"},
+ {0x0402, "Logical unit not ready, initializing command required"},
{0x0403, "Logical unit not ready, manual intervention required"},
{0x0404, "Logical unit not ready, format in progress"},
{0x0405, "Logical unit not ready, rebuild in progress"},
@@ -479,6 +483,9 @@ static struct error_info additional[] =
{0x0B00, "Warning"},
{0x0B01, "Warning - specified temperature exceeded"},
{0x0B02, "Warning - enclosure degraded"},
+ {0x0B03, "Warning - background self-test failed"},
+ {0x0B04, "Warning - background pre-scan detected medium error"},
+ {0x0B05, "Warning - background medium scan detected medium error"},
{0x0C00, "Write error"},
{0x0C01, "Write error - recovered with auto reallocation"},
@@ -494,6 +501,7 @@ static struct error_info additional[] =
{0x0C0B, "Auxiliary memory write error"},
{0x0C0C, "Write error - unexpected unsolicited data"},
{0x0C0D, "Write error - not enough unsolicited data"},
+ {0x0C0F, "Defects in error window"},
{0x0D00, "Error detected by third party temporary initiator"},
{0x0D01, "Third party device failure"},
@@ -505,11 +513,12 @@ static struct error_info additional[] =
{0x0E00, "Invalid information unit"},
{0x0E01, "Information unit too short"},
{0x0E02, "Information unit too long"},
+ {0x0E03, "Invalid field in command information unit"},
{0x1000, "Id CRC or ECC error"},
- {0x1001, "Data block guard check failed"},
- {0x1002, "Data block application tag check failed"},
- {0x1003, "Data block reference tag check failed"},
+ {0x1001, "Logical block guard check failed"},
+ {0x1002, "Logical block application tag check failed"},
+ {0x1003, "Logical block reference tag check failed"},
{0x1100, "Unrecovered read error"},
{0x1101, "Read retries exhausted"},
@@ -531,6 +540,7 @@ static struct error_info additional[] =
{0x1111, "Read error - loss of streaming"},
{0x1112, "Auxiliary memory read error"},
{0x1113, "Read error - failed retransmission request"},
+ {0x1114, "Read error - lba marked bad by application client"},
{0x1200, "Address mark not found for id field"},
@@ -611,11 +621,14 @@ static struct error_info additional[] =
{0x2100, "Logical block address out of range"},
{0x2101, "Invalid element address"},
{0x2102, "Invalid address for write"},
+ {0x2103, "Invalid write crossing layer jump"},
{0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
{0x2400, "Invalid field in cdb"},
{0x2401, "CDB decryption error"},
+ {0x2402, "Obsolete"},
+ {0x2403, "Obsolete"},
{0x2404, "Security audit value frozen"},
{0x2405, "Security working key frozen"},
{0x2406, "Nonce not unique"},
@@ -638,7 +651,10 @@ static struct error_info additional[] =
{0x260C, "Invalid operation for copy source or destination"},
{0x260D, "Copy segment granularity violation"},
{0x260E, "Invalid parameter while port is enabled"},
- {0x260F, "Invalid data-out buffer integrity"},
+ {0x260F, "Invalid data-out buffer integrity check value"},
+ {0x2610, "Data decryption key fail limit reached"},
+ {0x2611, "Incomplete key-associated data set"},
+ {0x2612, "Vendor specific key reference not found"},
{0x2700, "Write protected"},
{0x2701, "Hardware write protected"},
@@ -650,6 +666,7 @@ static struct error_info additional[] =
{0x2800, "Not ready to ready change, medium may have changed"},
{0x2801, "Import or export element accessed"},
+ {0x2802, "Format-layer may have changed"},
{0x2900, "Power on, reset, or bus device reset occurred"},
{0x2901, "Power on occurred"},
@@ -670,6 +687,11 @@ static struct error_info additional[] =
{0x2A07, "Implicit asymmetric access state transition failed"},
{0x2A08, "Priority changed"},
{0x2A09, "Capacity data has changed"},
+ {0x2A10, "Timestamp changed"},
+ {0x2A11, "Data encryption parameters changed by another i_t nexus"},
+ {0x2A12, "Data encryption parameters changed by vendor specific "
+ "event"},
+ {0x2A13, "Data encryption key instance counter has changed"},
{0x2B00, "Copy cannot execute since host cannot disconnect"},
@@ -691,6 +713,7 @@ static struct error_info additional[] =
{0x2E00, "Insufficient time for operation"},
{0x2F00, "Commands cleared by another initiator"},
+ {0x2F01, "Commands cleared by power loss notification"},
{0x3000, "Incompatible medium installed"},
{0x3001, "Cannot read medium - unknown format"},
@@ -703,7 +726,8 @@ static struct error_info additional[] =
{0x3008, "Cannot write - application code mismatch"},
{0x3009, "Current session not fixated for append"},
{0x300A, "Cleaning request rejected"},
- {0x300C, "WORM medium, overwrite attempted"},
+ {0x300C, "WORM medium - overwrite attempted"},
+ {0x300D, "WORM medium - integrity check"},
{0x3010, "Medium not formatted"},
{0x3100, "Medium format corrupted"},
@@ -791,6 +815,9 @@ static struct error_info additional[] =
{0x3F0F, "Echo buffer overwritten"},
{0x3F10, "Medium loadable"},
{0x3F11, "Medium auxiliary memory accessible"},
+ {0x3F12, "iSCSI IP address added"},
+ {0x3F13, "iSCSI IP address removed"},
+ {0x3F14, "iSCSI IP address changed"},
/*
* {0x40NN, "Ram failure"},
* {0x40NN, "Diagnostic failure on component nn"},
@@ -800,6 +827,7 @@ static struct error_info additional[] =
{0x4300, "Message error"},
{0x4400, "Internal target failure"},
+ {0x4471, "ATA device failed set features"},
{0x4500, "Select or reselect failure"},
@@ -808,9 +836,10 @@ static struct error_info additional[] =
{0x4700, "Scsi parity error"},
{0x4701, "Data phase CRC error detected"},
{0x4702, "Scsi parity error detected during st data phase"},
- {0x4703, "Information unit CRC error detected"},
+ {0x4703, "Information unit iuCRC error detected"},
{0x4704, "Asynchronous information protection error detected"},
{0x4705, "Protocol service CRC error"},
+ {0x4706, "Phy test function in progress"},
{0x477f, "Some commands cleared by iSCSI Protocol event"},
{0x4800, "Initiator detected error message received"},
@@ -845,6 +874,8 @@ static struct error_info additional[] =
{0x5300, "Media load or eject failed"},
{0x5301, "Unload tape failure"},
{0x5302, "Medium removal prevented"},
+ {0x5303, "Medium removal prevented by data transfer element"},
+ {0x5304, "Medium thread or unthread failure"},
{0x5400, "Scsi to host system interface failure"},
@@ -856,6 +887,7 @@ static struct error_info additional[] =
{0x5505, "Insufficient access control resources"},
{0x5506, "Auxiliary memory out of space"},
{0x5507, "Quota error"},
+ {0x5508, "Maximum number of supplemental decryption keys exceeded"},
{0x5700, "Unable to recover table-of-contents"},
@@ -1005,6 +1037,7 @@ static struct error_info additional[] =
{0x6708, "Assign failure occurred"},
{0x6709, "Multiply assigned logical unit"},
{0x670A, "Set target port groups command failed"},
+ {0x670B, "ATA device feature not enabled"},
{0x6800, "Logical unit not configured"},
@@ -1031,6 +1064,8 @@ static struct error_info additional[] =
{0x6F03, "Read of scrambled sector without authentication"},
{0x6F04, "Media region code is mismatched to logical unit region"},
{0x6F05, "Drive region must be permanent/region reset count error"},
+ {0x6F06, "Insufficient block count for binding nonce recording"},
+ {0x6F07, "Conflict in binding nonce recording"},
/*
* {0x70NN, "Decompression exception short algorithm id of nn"},
*/
@@ -1042,6 +1077,8 @@ static struct error_info additional[] =
{0x7203, "Session fixation error - incomplete track in session"},
{0x7204, "Empty or partially written reserved track"},
{0x7205, "No more track reservations allowed"},
+ {0x7206, "RMZ extension is not allowed"},
+ {0x7207, "No more test zone extensions are allowed"},
{0x7300, "Cd control error"},
{0x7301, "Power calibration area almost full"},
@@ -1050,6 +1087,18 @@ static struct error_info additional[] =
{0x7304, "Program memory area update failure"},
{0x7305, "Program memory area is full"},
{0x7306, "RMA/PMA is almost full"},
+ {0x7310, "Current power calibration area almost full"},
+ {0x7311, "Current power calibration area is full"},
+ {0x7317, "RDZ is full"},
+
+ {0x7400, "Security error"},
+ {0x7401, "Unable to decrypt data"},
+ {0x7402, "Unencrypted data encountered while decrypting"},
+ {0x7403, "Incorrect data encryption key"},
+ {0x7404, "Cryptographic integrity validation failed"},
+ {0x7405, "Error decrypting data"},
+ {0x7471, "Logical unit access not authorized"},
+
{0, NULL}
};
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
index a4a4fac5c0a..7c7cfb54e89 100644
--- a/drivers/scsi/cyberstorm.c
+++ b/drivers/scsi/cyberstorm.c
@@ -172,7 +172,7 @@ int __init cyber_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"CyberStorm SCSI", esp->ehost);
/* Figure out our scsi ID on the bus */
/* The DMA cond flag contains a hardcoded jumper bit
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
index 3a803d73bc5..d88cb9cf091 100644
--- a/drivers/scsi/cyberstormII.c
+++ b/drivers/scsi/cyberstormII.c
@@ -153,7 +153,7 @@ int __init cyberII_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"CyberStorm SCSI Mk II", esp->ehost);
/* Figure out our scsi ID on the bus */
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 18324525493..ff2b1796fa3 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -3771,7 +3771,7 @@ static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
* @target: The target for the new device.
* @lun: The lun for the new device.
*
- * Return the new device if succesfull or NULL on failure.
+ * Return the new device if successful or NULL on failure.
**/
static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
u8 target, u8 lun)
@@ -4562,7 +4562,7 @@ static int __devinit adapter_init(struct AdapterCtlBlk *acb,
acb->io_port_base = io_port;
acb->io_port_len = io_port_len;
- if (request_irq(irq, dc395x_interrupt, SA_SHIRQ, DC395X_NAME, acb)) {
+ if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) {
/* release the region we just claimed */
dprintkl(KERN_INFO, "Failed to register IRQ\n");
goto failed;
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index a35ee43a48d..eb32062f7e6 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -202,19 +202,19 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
esp_initialize(esp);
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
"ncr53c94", esp->ehost))
goto err_dealloc;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
- scsi_dma_merr_int, SA_INTERRUPT,
+ scsi_dma_merr_int, IRQF_DISABLED,
"ncr53c94 error", esp->ehost))
goto err_free_irq;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
- scsi_dma_err_int, SA_INTERRUPT,
+ scsi_dma_err_int, IRQF_DISABLED,
"ncr53c94 overrun", esp->ehost))
goto err_free_irq_merr;
if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
- scsi_dma_int, SA_INTERRUPT,
+ scsi_dma_int, IRQF_DISABLED,
"ncr53c94 dma", esp->ehost))
goto err_free_irq_err;
@@ -276,7 +276,7 @@ static int dec_esp_detect(struct scsi_host_template * tpnt)
esp->dma_mmu_release_scsi_sgl = 0;
esp->dma_advance_sg = 0;
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
"PMAZ_AA", esp->ehost)) {
esp_deallocate(esp);
release_tc_card(slot);
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 38e4010eff9..879a2665767 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -94,7 +94,7 @@ static int __devinit dmx3191d_probe_one(struct pci_dev *pdev,
NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
- if (request_irq(pdev->irq, NCR5380_intr, SA_SHIRQ,
+ if (request_irq(pdev->irq, NCR5380_intr, IRQF_SHARED,
DMX3191D_DRIVER_NAME, shost)) {
/*
* Steam powered scsi controllers run without an IRQ anyway
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index a9585f5235d..d84a281ad94 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -23,7 +23,6 @@
#include <asm/semaphore.h> /* Needed for MUTEX init macros */
#include <linux/version.h>
-#include <linux/config.h>
#include <linux/notifier.h>
#include <asm/atomic.h>
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index b1b704a42ef..7b3bd34faf4 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -46,7 +46,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
#include <linux/stat.h>
#include <linux/slab.h> /* for kmalloc() */
-#include <linux/config.h> /* for CONFIG_PCI */
#include <linux/pci.h> /* for PCI support */
#include <linux/proc_fs.h>
#include <linux/blkdev.h>
@@ -185,7 +184,7 @@ static int adpt_detect(struct scsi_host_template* sht)
PINFO("Detecting Adaptec I2O RAID controllers...\n");
/* search for all Adatpec I2O RAID cards */
- while ((pDev = pci_find_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
+ while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
if(pDev->device == PCI_DPT_DEVICE_ID ||
pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
if(adpt_install_hba(sht, pDev) ){
@@ -193,8 +192,11 @@ static int adpt_detect(struct scsi_host_template* sht)
PERROR("Will not try to detect others.\n");
return hba_count-1;
}
+ pci_dev_get(pDev);
}
}
+ if (pDev)
+ pci_dev_put(pDev);
/* In INIT state, Activate IOPs */
for (pHba = hba_chain; pHba; pHba = pHba->next) {
@@ -1009,7 +1011,7 @@ static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev
printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
}
- if (request_irq (pDev->irq, adpt_isr, SA_SHIRQ, pHba->name, pHba)) {
+ if (request_irq (pDev->irq, adpt_isr, IRQF_SHARED, pHba->name, pHba)) {
printk(KERN_ERR"%s: Couldn't register IRQ %d\n", pHba->name, pDev->irq);
adpt_i2o_delete_hba(pHba);
return -EINVAL;
@@ -1076,6 +1078,7 @@ static void adpt_i2o_delete_hba(adpt_hba* pHba)
}
}
}
+ pci_dev_put(pHba->pDev);
kfree(pHba);
if(hba_count <= 0){
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index c5108c8c887..0d5713dfa20 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -280,7 +280,7 @@ found:
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc", instance)) {
+ if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED, "dtc", instance)) {
printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
}
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 059eeee4b55..a5ff43b1b26 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -477,7 +477,6 @@
* the driver sets host->wish_block = 1 for all ISA boards.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -1222,7 +1221,7 @@ static int port_detect(unsigned long port_base, unsigned int j,
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+ IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
driver_name, (void *)&sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name,
irq);
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
index 34bce2c9e92..635c14861f8 100644
--- a/drivers/scsi/eata_generic.h
+++ b/drivers/scsi/eata_generic.h
@@ -364,6 +364,7 @@ typedef struct hstd {
__u8 moresupport; /* HBA supports MORE flag */
struct Scsi_Host *next;
struct Scsi_Host *prev;
+ struct pci_dev *pdev; /* PCI device or NULL for non PCI */
struct eata_sp sp; /* status packet */
struct eata_ccb ccb[0]; /* ccb array begins here */
}hostdata;
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 23beb48c79c..d312633db92 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -46,7 +46,6 @@
* last change: 2002/11/02 OS: Linux 2.5.45 *
************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -72,11 +71,11 @@
#include "eata_pio.h"
-static uint ISAbases[MAXISA] = {
+static unsigned int ISAbases[MAXISA] = {
0x1F0, 0x170, 0x330, 0x230
};
-static uint ISAirqs[MAXISA] = {
+static unsigned int ISAirqs[MAXISA] = {
14, 12, 15, 11
};
@@ -85,7 +84,7 @@ static unsigned char EISAbases[] = {
1, 1, 1, 1, 1, 1, 1, 1
};
-static uint registered_HBAs;
+static unsigned int registered_HBAs;
static struct Scsi_Host *last_HBA;
static struct Scsi_Host *first_HBA;
static unsigned char reg_IRQ[16];
@@ -166,6 +165,7 @@ static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **star
static int eata_pio_release(struct Scsi_Host *sh)
{
+ hostdata *hd = SD(sh);
if (sh->irq && reg_IRQ[sh->irq] == 1)
free_irq(sh->irq, NULL);
else
@@ -174,10 +174,13 @@ static int eata_pio_release(struct Scsi_Host *sh)
if (sh->io_port && sh->n_io_port)
release_region(sh->io_port, sh->n_io_port);
}
+ /* At this point the PCI reference can go */
+ if (hd->pdev)
+ pci_dev_put(hd->pdev);
return 1;
}
-static void IncStat(struct scsi_pointer *SCp, uint Increment)
+static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
{
SCp->ptr += Increment;
if ((SCp->this_residual -= Increment) == 0) {
@@ -191,46 +194,49 @@ static void IncStat(struct scsi_pointer *SCp, uint Increment)
}
}
-static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id,
struct pt_regs *regs)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
+ irqreturn_t ret;
spin_lock_irqsave(dev->host_lock, flags);
- eata_pio_int_handler(irq, dev_id, regs);
+ ret = eata_pio_int_handler(irq, dev_id, regs);
spin_unlock_irqrestore(dev->host_lock, flags);
- return IRQ_HANDLED;
+ return ret;
}
-static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- uint eata_stat = 0xfffff;
+ unsigned int eata_stat = 0xfffff;
struct scsi_cmnd *cmd;
hostdata *hd;
struct eata_ccb *cp;
- uint base;
- uint x, z;
+ unsigned long base;
+ unsigned int x, z;
struct Scsi_Host *sh;
unsigned short zwickel = 0;
unsigned char stat, odd;
+ irqreturn_t ret = IRQ_NONE;
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev)
{
if (sh->irq != irq)
continue;
- if (inb((uint) sh->base + HA_RSTATUS) & HA_SBUSY)
+ if (inb(sh->base + HA_RSTATUS) & HA_SBUSY)
continue;
int_counter++;
+ ret = IRQ_HANDLED;
hd = SD(sh);
cp = &hd->ccb[0];
cmd = cp->cmd;
- base = (uint) cmd->device->host->base;
+ base = cmd->device->host->base;
do {
stat = inb(base + HA_RSTATUS);
@@ -305,7 +311,7 @@ static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {
cmd->result = (DID_OK << 16);
hd->devflags |= (1 << cp->cp_id);
- } else if (hd->devflags & 1 << cp->cp_id)
+ } else if (hd->devflags & (1 << cp->cp_id))
cmd->result = (DID_OK << 16) + 0x02;
else
cmd->result = (DID_NO_CONNECT << 16);
@@ -314,7 +320,7 @@ static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
cp->status = FREE;
eata_stat = inb(base + HA_RSTATUS);
printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n");
- return;
+ return ret;
}
#if DBG_INTR2
if (stat != 0x50)
@@ -326,12 +332,12 @@ static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
cmd->scsi_done(cmd);
}
- return;
+ return ret;
}
-static inline uint eata_pio_send_command(uint base, unsigned char command)
+static inline unsigned int eata_pio_send_command(unsigned long base, unsigned char command)
{
- uint loop = HZ / 2;
+ unsigned int loop = 50;
while (inb(base + HA_RSTATUS) & HA_SBUSY)
if (--loop == 0)
@@ -350,8 +356,8 @@ static inline uint eata_pio_send_command(uint base, unsigned char command)
static int eata_pio_queue(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
- uint x, y;
- uint base;
+ unsigned int x, y;
+ unsigned long base;
hostdata *hd;
struct Scsi_Host *sh;
@@ -361,7 +367,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
hd = HD(cmd);
sh = cmd->device->host;
- base = (uint) sh->base;
+ base = sh->base;
/* use only slot 0, as 2001 can handle only one cmd at a time */
@@ -396,9 +402,9 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
cp->DataIn = 0; /* Input mode */
cp->Interpret = (cmd->device->id == hd->hostid);
- cp->cp_datalen = htonl((unsigned long) cmd->request_bufflen);
+ cp->cp_datalen = cpu_to_be32(cmd->request_bufflen);
cp->Auto_Req_Sen = 0;
- cp->cp_reqDMA = htonl(0);
+ cp->cp_reqDMA = 0;
cp->reqlen = 0;
cp->cp_id = cmd->device->id;
@@ -407,7 +413,7 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
cp->cp_identify = 1;
memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
- cp->cp_statDMA = htonl(0);
+ cp->cp_statDMA = 0;
cp->cp_viraddr = cp;
cp->cmd = cmd;
@@ -446,14 +452,14 @@ static int eata_pio_queue(struct scsi_cmnd *cmd,
DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd,
"Queued base %#.4lx pid: %ld "
- "slot %d irq %d\n", (long) sh->base, cmd->pid, y, sh->irq));
+ "slot %d irq %d\n", sh->base, cmd->pid, y, sh->irq));
return (0);
}
static int eata_pio_abort(struct scsi_cmnd *cmd)
{
- uint loop = HZ;
+ unsigned int loop = 100;
DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd,
"eata_pio_abort called pid: %ld\n",
@@ -486,7 +492,7 @@ static int eata_pio_abort(struct scsi_cmnd *cmd)
static int eata_pio_host_reset(struct scsi_cmnd *cmd)
{
- uint x, limit = 0;
+ unsigned int x, limit = 0;
unsigned char success = 0;
struct scsi_cmnd *sp;
struct Scsi_Host *host = cmd->device->host;
@@ -519,7 +525,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
}
/* hard reset the HBA */
- outb(EATA_CMD_RESET, (uint) cmd->device->host->base + HA_WCOMMAND);
+ outb(EATA_CMD_RESET, cmd->device->host->base + HA_WCOMMAND);
DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
HD(cmd)->state = RESET;
@@ -559,7 +565,7 @@ static int eata_pio_host_reset(struct scsi_cmnd *cmd)
}
}
-static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned long cplen, unsigned short cppadlen)
+static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned int id, unsigned long cplen, unsigned short cppadlen)
{
struct eata_ccb cp;
static char buff[256];
@@ -571,8 +577,8 @@ static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned
cp.DataIn = 1;
cp.Interpret = 1; /* Interpret command */
- cp.cp_datalen = htonl(254);
- cp.cp_dataDMA = htonl(0);
+ cp.cp_datalen = cpu_to_be32(254);
+ cp.cp_dataDMA = cpu_to_be32(0);
cp.cp_id = id;
cp.cp_lun = 0;
@@ -584,7 +590,7 @@ static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned
cp.cp_cdb[4] = 254;
cp.cp_cdb[5] = 0;
- if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP))
+ if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
return (NULL);
while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
outsw(base + HA_RDATA, &cp, cplen);
@@ -605,7 +611,7 @@ static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned
}
}
-static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
+static int get_pio_conf_PIO(unsigned long base, struct get_conf *buf)
{
unsigned long loop = HZ / 2;
int z;
@@ -620,30 +626,30 @@ static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
if (--loop == 0)
goto fail;
- DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
+ DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#lx\n", base));
eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
- loop = HZ / 2;
+ loop = 50;
for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
if (--loop == 0)
goto fail;
- loop = HZ / 2;
+ loop = 50;
*p = inw(base + HA_RDATA);
}
if (inb(base + HA_RSTATUS) & HA_SERROR) {
DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during "
- "transfer for HBA at %x\n", base));
+ "transfer for HBA at %lx\n", base));
goto fail;
}
- if (htonl(EATA_SIGNATURE) != buf->signature)
+ if (cpu_to_be32(EATA_SIGNATURE) != buf->signature)
goto fail;
DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
- "at %#4x EATA Level: %x\n",
- base, (uint) (buf->version)));
+ "at %#4lx EATA Level: %x\n",
+ base, (unsigned int) (buf->version)));
while (inb(base + HA_RSTATUS) & HA_SDRQ)
inw(base + HA_RDATA);
@@ -666,12 +672,12 @@ static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
static void print_pio_config(struct get_conf *gc)
{
printk("Please check values: (read config data)\n");
- printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", (uint) ntohl(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
- printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+ printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", be32_to_cpu(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+ printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], be16_to_cpu(gc->queuesiz), be16_to_cpu(gc->SGsiz), gc->SECOND);
printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest);
}
-static uint print_selftest(uint base)
+static unsigned int print_selftest(unsigned int base)
{
unsigned char buffer[512];
#ifdef VERBOSE_SETUP
@@ -698,7 +704,7 @@ static uint print_selftest(uint base)
return (!(inb(base + HA_RSTATUS) & HA_SERROR));
}
-static int register_pio_HBA(long base, struct get_conf *gc)
+static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev)
{
unsigned long size = 0;
char *buff;
@@ -715,24 +721,24 @@ static int register_pio_HBA(long base, struct get_conf *gc)
return 0;
}
- if ((buff = get_pio_board_data((uint) base, gc->IRQ, gc->scsi_id[3], cplen = (htonl(gc->cplen) + 1) / 2, cppadlen = (htons(gc->cppadlen) + 1) / 2)) == NULL) {
- printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (unsigned long) base);
+ if ((buff = get_pio_board_data(base, gc->IRQ, gc->scsi_id[3], cplen = (cpu_to_be32(gc->cplen) + 1) / 2, cppadlen = (cpu_to_be16(gc->cppadlen) + 1) / 2)) == NULL) {
+ printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", base);
return 0;
}
if (!print_selftest(base) && !ALLOW_DMA_BOARDS) {
- printk("HBA at %#lx failed while performing self test & setup.\n", (unsigned long) base);
+ printk("HBA at %#lx failed while performing self test & setup.\n", base);
return 0;
}
- size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+ size = sizeof(hostdata) + (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz));
sh = scsi_register(&driver_template, size);
if (sh == NULL)
return 0;
if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
- if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", sh)) {
+ if (!request_irq(gc->IRQ, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", sh)) {
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */
@@ -750,8 +756,8 @@ static int register_pio_HBA(long base, struct get_conf *gc)
hd = SD(sh);
- memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
- memset(hd->reads, 0, sizeof(unsigned long) * 26);
+ memset(hd->ccb, 0, (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz)));
+ memset(hd->reads, 0, sizeof(hd->reads));
strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor));
strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name));
@@ -762,7 +768,7 @@ static int register_pio_HBA(long base, struct get_conf *gc)
SD(sh)->revision[4] = buff[35];
SD(sh)->revision[5] = 0;
- switch (ntohl(gc->len)) {
+ switch (be32_to_cpu(gc->len)) {
case 0x1c:
SD(sh)->EATA_revision = 'a';
break;
@@ -778,7 +784,7 @@ static int register_pio_HBA(long base, struct get_conf *gc)
SD(sh)->EATA_revision = '?';
}
- if (ntohl(gc->len) >= 0x22) {
+ if (be32_to_cpu(gc->len) >= 0x22) {
if (gc->is_PCI)
hd->bustype = IS_PCI;
else if (gc->is_EISA)
@@ -812,6 +818,8 @@ static int register_pio_HBA(long base, struct get_conf *gc)
hd->channel = 0;
+ hd->pdev = pci_dev_get(pdev); /* Keep a PCI reference */
+
sh->max_id = 8;
sh->max_lun = 8;
@@ -842,7 +850,7 @@ static void find_pio_ISA(struct get_conf *buf)
continue;
if (!get_pio_conf_PIO(ISAbases[i], buf))
continue;
- if (!register_pio_HBA(ISAbases[i], buf))
+ if (!register_pio_HBA(ISAbases[i], buf, NULL))
release_region(ISAbases[i], 9);
else
ISAbases[i] = 0;
@@ -874,7 +882,7 @@ static void find_pio_EISA(struct get_conf *buf)
if (get_pio_conf_PIO(base, buf)) {
DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
if (buf->IRQ) {
- if (!register_pio_HBA(base, buf))
+ if (!register_pio_HBA(base, buf, NULL))
release_region(base, 9);
} else {
printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
@@ -897,9 +905,9 @@ static void find_pio_PCI(struct get_conf *buf)
printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
#else
struct pci_dev *dev = NULL;
- u32 base, x;
+ unsigned long base, x;
- while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
+ while ((dev = pci_get_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev)));
if (pci_enable_device(dev))
continue;
@@ -927,7 +935,7 @@ static void find_pio_PCI(struct get_conf *buf)
* eventually remove it from the EISA and ISA list
*/
- if (!register_pio_HBA(base, buf)) {
+ if (!register_pio_HBA(base, buf, dev)) {
release_region(base, 9);
continue;
}
@@ -966,7 +974,7 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
for (i = 0; i <= MAXIRQ; i++)
if (reg_IRQ[i])
- request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+ request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL);
HBA_ptr = first_HBA;
@@ -977,12 +985,12 @@ static int eata_pio_detect(struct scsi_host_template *tpnt)
printk("Registered HBAs:\n");
printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n");
for (i = 1; i <= registered_HBAs; i++) {
- printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %d %d %c"
+ printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d %d %d %c"
" %2d %2d %2d\n",
HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ?
"PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ",
- (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
+ HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue,
HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
HBA_ptr = SD(HBA_ptr)->next;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 0a3e45d7a97..5630868c1b2 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1,7 +1,6 @@
-/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
- * esp.c: EnhancedScsiProcessor Sun SCSI driver code.
+/* esp.c: ESP Sun SCSI driver.
*
- * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995, 1998, 2006 David S. Miller (davem@davemloft.net)
*/
/* TODO:
@@ -13,7 +12,6 @@
* 3) Add tagged queueing.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/types.h>
@@ -185,11 +183,6 @@ enum {
/*5*/ do_intr_end
};
-/* The master ring of all esp hosts we are managing in this driver. */
-static struct esp *espchain;
-static DEFINE_SPINLOCK(espchain_lock);
-static int esps_running = 0;
-
/* Forward declarations. */
static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@@ -694,36 +687,6 @@ static void __init esp_bootup_reset(struct esp *esp)
sbus_readb(esp->eregs + ESP_INTRPT);
}
-static void esp_chain_add(struct esp *esp)
-{
- spin_lock_irq(&espchain_lock);
- if (espchain) {
- struct esp *elink = espchain;
- while (elink->next)
- elink = elink->next;
- elink->next = esp;
- } else {
- espchain = esp;
- }
- esp->next = NULL;
- spin_unlock_irq(&espchain_lock);
-}
-
-static void esp_chain_del(struct esp *esp)
-{
- spin_lock_irq(&espchain_lock);
- if (espchain == esp) {
- espchain = esp->next;
- } else {
- struct esp *elink = espchain;
- while (elink->next != esp)
- elink = elink->next;
- elink->next = esp->next;
- }
- esp->next = NULL;
- spin_unlock_irq(&espchain_lock);
-}
-
static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
{
struct sbus_dev *sdev = esp->sdev;
@@ -815,7 +778,7 @@ static int __init esp_register_irq(struct esp *esp)
* sanely maintain.
*/
if (request_irq(esp->ehost->irq, esp_intr,
- SA_SHIRQ, "ESP SCSI", esp)) {
+ IRQF_SHARED, "ESP SCSI", esp)) {
printk("esp%d: Cannot acquire irq line\n",
esp->esp_id);
return -1;
@@ -830,19 +793,20 @@ static int __init esp_register_irq(struct esp *esp)
static void __init esp_get_scsi_id(struct esp *esp)
{
struct sbus_dev *sdev = esp->sdev;
+ struct device_node *dp = sdev->ofdev.node;
- esp->scsi_id = prom_getintdefault(esp->prom_node,
- "initiator-id",
- -1);
+ esp->scsi_id = of_getintprop_default(dp,
+ "initiator-id",
+ -1);
if (esp->scsi_id == -1)
- esp->scsi_id = prom_getintdefault(esp->prom_node,
- "scsi-initiator-id",
- -1);
+ esp->scsi_id = of_getintprop_default(dp,
+ "scsi-initiator-id",
+ -1);
if (esp->scsi_id == -1)
esp->scsi_id = (sdev->bus == NULL) ? 7 :
- prom_getintdefault(sdev->bus->prom_node,
- "scsi-initiator-id",
- 7);
+ of_getintprop_default(sdev->bus->ofdev.node,
+ "scsi-initiator-id",
+ 7);
esp->ehost->this_id = esp->scsi_id;
esp->scsi_id_mask = (1 << esp->scsi_id);
@@ -1067,28 +1031,30 @@ static void __init esp_init_swstate(struct esp *esp)
esp->prev_hme_dmacsr = 0xffffffff;
}
-static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
- struct sbus_dev *espdma, struct sbus_bus *sbus,
- int id, int hme)
+static int __init detect_one_esp(struct scsi_host_template *tpnt,
+ struct device *dev,
+ struct sbus_dev *esp_dev,
+ struct sbus_dev *espdma,
+ struct sbus_bus *sbus,
+ int hme)
{
- struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
+ static int instance;
+ struct Scsi_Host *esp_host = scsi_host_alloc(tpnt, sizeof(struct esp));
struct esp *esp;
- if (!esp_host) {
- printk("ESP: Cannot register SCSI host\n");
- return -1;
- }
+ if (!esp_host)
+ return -ENOMEM;
+
if (hme)
esp_host->max_id = 16;
esp = (struct esp *) esp_host->hostdata;
esp->ehost = esp_host;
esp->sdev = esp_dev;
- esp->esp_id = id;
+ esp->esp_id = instance;
esp->prom_node = esp_dev->prom_node;
prom_getstring(esp->prom_node, "name", esp->prom_name,
sizeof(esp->prom_name));
- esp_chain_add(esp);
if (esp_find_dvma(esp, espdma) < 0)
goto fail_unlink;
if (esp_map_regs(esp, hme) < 0) {
@@ -1115,8 +1081,19 @@ static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_de
esp_bootup_reset(esp);
+ if (scsi_add_host(esp_host, dev))
+ goto fail_free_irq;
+
+ dev_set_drvdata(&esp_dev->ofdev.dev, esp);
+
+ scsi_scan_host(esp_host);
+ instance++;
+
return 0;
+fail_free_irq:
+ free_irq(esp->ehost->irq, esp);
+
fail_unmap_cmdarea:
sbus_free_consistent(esp->sdev, 16,
(void *) esp->esp_command,
@@ -1129,119 +1106,99 @@ fail_dvma_release:
esp->dma->allocated = 0;
fail_unlink:
- esp_chain_del(esp);
- scsi_unregister(esp_host);
+ scsi_host_put(esp_host);
return -1;
}
/* Detecting ESP chips on the machine. This is the simple and easy
* version.
*/
+static int __devexit esp_remove_common(struct esp *esp)
+{
+ unsigned int irq = esp->ehost->irq;
+
+ scsi_remove_host(esp->ehost);
+
+ ESP_INTSOFF(esp->dregs);
+#if 0
+ esp_reset_dma(esp);
+ esp_reset_esp(esp);
+#endif
+
+ free_irq(irq, esp);
+ sbus_free_consistent(esp->sdev, 16,
+ (void *) esp->esp_command, esp->esp_command_dvma);
+ sbus_iounmap(esp->eregs, ESP_REG_SIZE);
+ esp->dma->allocated = 0;
+
+ scsi_host_put(esp->ehost);
+
+ return 0;
+}
+
#ifdef CONFIG_SUN4
#include <asm/sun4paddr.h>
-static int __init esp_detect(struct scsi_host_template *tpnt)
-{
- static struct sbus_dev esp_dev;
- int esps_in_use = 0;
-
- espchain = NULL;
+static struct sbus_dev sun4_esp_dev;
+static int __init esp_sun4_probe(struct scsi_host_template *tpnt)
+{
if (sun4_esp_physaddr) {
- memset (&esp_dev, 0, sizeof(esp_dev));
- esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
- esp_dev.irqs[0] = 4;
- esp_dev.resource[0].start = sun4_esp_physaddr;
- esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
- esp_dev.resource[0].flags = IORESOURCE_IO;
-
- if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
- esps_in_use++;
- printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
- esps_running = esps_in_use;
+ memset(&sun4_esp_dev, 0, sizeof(sun4_esp_dev));
+ sun4_esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
+ sun4_esp_dev.irqs[0] = 4;
+ sun4_esp_dev.resource[0].start = sun4_esp_physaddr;
+ sun4_esp_dev.resource[0].end =
+ sun4_esp_physaddr + ESP_REG_SIZE - 1;
+ sun4_esp_dev.resource[0].flags = IORESOURCE_IO;
+
+ return detect_one_esp(tpnt, NULL,
+ &sun4_esp_dev, NULL, NULL, 0);
}
- return esps_in_use;
+ return 0;
}
-#else /* !CONFIG_SUN4 */
-
-static int __init esp_detect(struct scsi_host_template *tpnt)
+static int __devexit esp_sun4_remove(void)
{
- struct sbus_bus *sbus;
- struct sbus_dev *esp_dev, *sbdev_iter;
- int nesps = 0, esps_in_use = 0;
+ struct of_device *dev = &sun4_esp_dev.ofdev;
+ struct esp *esp = dev_get_drvdata(&dev->dev);
- espchain = 0;
- if (!sbus_root) {
-#ifdef CONFIG_PCI
- return 0;
-#else
- panic("No SBUS in esp_detect()");
-#endif
- }
- for_each_sbus(sbus) {
- for_each_sbusdev(sbdev_iter, sbus) {
- struct sbus_dev *espdma = NULL;
- int hme = 0;
-
- /* Is it an esp sbus device? */
- esp_dev = sbdev_iter;
- if (strcmp(esp_dev->prom_name, "esp") &&
- strcmp(esp_dev->prom_name, "SUNW,esp")) {
- if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
- hme = 1;
- espdma = esp_dev;
- } else {
- if (!esp_dev->child ||
- (strcmp(esp_dev->prom_name, "espdma") &&
- strcmp(esp_dev->prom_name, "dma")))
- continue; /* nope... */
- espdma = esp_dev;
- esp_dev = esp_dev->child;
- if (strcmp(esp_dev->prom_name, "esp") &&
- strcmp(esp_dev->prom_name, "SUNW,esp"))
- continue; /* how can this happen? */
- }
- }
-
- if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
- continue;
-
- esps_in_use++;
- } /* for each sbusdev */
- } /* for each sbus */
- printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
- esps_in_use);
- esps_running = esps_in_use;
- return esps_in_use;
+ return esp_remove_common(esp);
}
-#endif /* !CONFIG_SUN4 */
+#else /* !CONFIG_SUN4 */
-/*
- */
-static int esp_release(struct Scsi_Host *host)
+static int __devinit esp_sbus_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct esp *esp = (struct esp *) host->hostdata;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct sbus_dev *dma_sdev = NULL;
+ int hme = 0;
+
+ if (dp->parent &&
+ (!strcmp(dp->parent->name, "espdma") ||
+ !strcmp(dp->parent->name, "dma")))
+ dma_sdev = sdev->parent;
+ else if (!strcmp(dp->name, "SUNW,fas")) {
+ dma_sdev = sdev;
+ hme = 1;
+ }
- ESP_INTSOFF(esp->dregs);
-#if 0
- esp_reset_dma(esp);
- esp_reset_esp(esp);
-#endif
+ return detect_one_esp(match->data, &dev->dev,
+ sdev, dma_sdev, sdev->bus, hme);
+}
- free_irq(esp->ehost->irq, esp);
- sbus_free_consistent(esp->sdev, 16,
- (void *) esp->esp_command, esp->esp_command_dvma);
- sbus_iounmap(esp->eregs, ESP_REG_SIZE);
- esp->dma->allocated = 0;
- esp_chain_del(esp);
+static int __devexit esp_sbus_remove(struct of_device *dev)
+{
+ struct esp *esp = dev_get_drvdata(&dev->dev);
- return 0;
+ return esp_remove_common(esp);
}
+#endif /* !CONFIG_SUN4 */
+
/* The info function will return whatever useful
* information the developer sees fit. If not provided, then
* the name field will be used instead.
@@ -1415,18 +1372,11 @@ static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
int length, int inout)
{
- struct esp *esp;
+ struct esp *esp = (struct esp *) host->hostdata;
if (inout)
return -EINVAL; /* not yet */
- for_each_esp(esp) {
- if (esp->ehost == host)
- break;
- }
- if (!esp)
- return -EINVAL;
-
if (start)
*start = buffer;
@@ -1448,7 +1398,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
sp->SCp.ptr = NULL;
}
} else {
- sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+ sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
sp->SCp.buffer,
sp->use_sg,
@@ -1461,7 +1411,7 @@ static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
{
if (sp->use_sg) {
- sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+ sbus_unmap_sg(esp->sdev, sp->request_buffer, sp->use_sg,
sp->sc_data_direction);
} else if (sp->request_bufflen) {
sbus_unmap_single(esp->sdev,
@@ -2805,18 +2755,15 @@ static int esp_do_data_finale(struct esp *esp)
*/
static int esp_should_clear_sync(struct scsi_cmnd *sp)
{
- u8 cmd1 = sp->cmnd[0];
- u8 cmd2 = sp->data_cmnd[0];
+ u8 cmd = sp->cmnd[0];
/* These cases are for spinning up a disk and
* waiting for that spinup to complete.
*/
- if (cmd1 == START_STOP ||
- cmd2 == START_STOP)
+ if (cmd == START_STOP)
return 0;
- if (cmd1 == TEST_UNIT_READY ||
- cmd2 == TEST_UNIT_READY)
+ if (cmd == TEST_UNIT_READY)
return 0;
/* One more special case for SCSI tape drives,
@@ -2824,8 +2771,7 @@ static int esp_should_clear_sync(struct scsi_cmnd *sp)
* completion of a rewind or tape load operation.
*/
if (sp->device->type == TYPE_TAPE) {
- if (cmd1 == MODE_SENSE ||
- cmd2 == MODE_SENSE)
+ if (cmd == MODE_SENSE)
return 0;
}
@@ -4377,15 +4323,12 @@ static void esp_slave_destroy(struct scsi_device *SDptr)
SDptr->hostdata = NULL;
}
-static struct scsi_host_template driver_template = {
- .proc_name = "esp",
- .proc_info = esp_proc_info,
- .name = "Sun ESP 100/100a/200",
- .detect = esp_detect,
+static struct scsi_host_template esp_template = {
+ .module = THIS_MODULE,
+ .name = "esp",
+ .info = esp_info,
.slave_alloc = esp_slave_alloc,
.slave_destroy = esp_slave_destroy,
- .release = esp_release,
- .info = esp_info,
.queuecommand = esp_queue,
.eh_abort_handler = esp_abort,
.eh_bus_reset_handler = esp_reset,
@@ -4394,12 +4337,58 @@ static struct scsi_host_template driver_template = {
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
+ .proc_name = "esp",
+ .proc_info = esp_proc_info,
+};
+
+#ifndef CONFIG_SUN4
+static struct of_device_id esp_match[] = {
+ {
+ .name = "SUNW,esp",
+ .data = &esp_template,
+ },
+ {
+ .name = "SUNW,fas",
+ .data = &esp_template,
+ },
+ {
+ .name = "esp",
+ .data = &esp_template,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, esp_match);
+
+static struct of_platform_driver esp_sbus_driver = {
+ .name = "esp",
+ .match_table = esp_match,
+ .probe = esp_sbus_probe,
+ .remove = __devexit_p(esp_sbus_remove),
};
+#endif
+
+static int __init esp_init(void)
+{
+#ifdef CONFIG_SUN4
+ return esp_sun4_probe(&esp_template);
+#else
+ return of_register_driver(&esp_sbus_driver, &sbus_bus_type);
+#endif
+}
-#include "scsi_module.c"
+static void __exit esp_exit(void)
+{
+#ifdef CONFIG_SUN4
+ esp_sun4_remove();
+#else
+ of_unregister_driver(&esp_sbus_driver);
+#endif
+}
-MODULE_DESCRIPTION("EnhancedScsiProcessor Sun SCSI driver");
-MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("ESP Sun SCSI driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
+module_init(esp_init);
+module_exit(esp_exit);
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
index 73f7d6968ab..a98cda9121f 100644
--- a/drivers/scsi/esp.h
+++ b/drivers/scsi/esp.h
@@ -403,8 +403,4 @@ struct esp {
#define ESP_MHZ_TO_CYCLE(mhertz) ((1000000000) / ((mhertz) / 1000))
#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000))
-/* For our interrupt engine. */
-#define for_each_esp(esp) \
- for((esp) = espchain; (esp); (esp) = (esp)->next)
-
#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
index 8ae9c406a83..2a1c5c22b9e 100644
--- a/drivers/scsi/fastlane.c
+++ b/drivers/scsi/fastlane.c
@@ -210,7 +210,7 @@ int __init fastlane_esp_detect(struct scsi_host_template *tpnt)
esp->irq = IRQ_AMIGA_PORTS;
esp->slot = board+FASTLANE_ESP_ADDR;
- if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ if (request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"Fastlane SCSI", esp->ehost)) {
printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
goto err_unmap;
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
index 03416548f20..c4e16c0775d 100644
--- a/drivers/scsi/fcal.c
+++ b/drivers/scsi/fcal.c
@@ -13,7 +13,6 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-#include <linux/config.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
@@ -249,8 +248,7 @@ int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t of
if (scd->id == target) {
SPRINTF (" [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x] ",
alpa, target, u1[0], u1[1], u2[0], u2[1]);
- SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
- scsi_device_types[(short) scd->type] : "Unknown device");
+ SPRINTF ("%s ", scsi_device_type(scd->type));
for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
SPRINTF ("%c", scd->vendor[j]);
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index 70a1606bd58..dde3edf35c0 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -400,7 +400,7 @@ static int fd_mcs_detect(struct scsi_host_template * tpnt)
mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
/* check irq/region */
- if (request_irq(irq, fd_mcs_intr, SA_SHIRQ, "fd_mcs", hosts)) {
+ if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) {
printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
continue;
}
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index e16013f0ad6..b0694dcce24 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -266,7 +266,6 @@
**************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -950,7 +949,7 @@ struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
/* Register the IRQ with the kernel */
retcode = request_irq( interrupt_level,
- do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt);
+ do_fdomain_16x0_intr, pdev?IRQF_SHARED:0, "fdomain", shpnt);
if (retcode < 0) {
if (retcode == -EINVAL) {
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 5f313c93b7a..cdd893bb4e2 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -91,7 +91,6 @@
#define AUTOPROBE_IRQ
#define AUTOSENSE
-#include <linux/config.h>
#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define NCR53C400_PSEUDO_DMA 1
@@ -462,7 +461,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
instance->irq = NCR5380_probe_irq(instance, 0xffff);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", instance)) {
+ if (request_irq(instance->irq, generic_NCR5380_intr, IRQF_DISABLED, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
}
@@ -812,7 +811,6 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
struct NCR5380_hostdata *hostdata;
#ifdef NCR5380_STATS
struct scsi_device *dev;
- extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
#endif
NCR5380_setup(scsi_ptr);
@@ -852,7 +850,7 @@ static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, c
long tr = hostdata->time_read[dev->id] / HZ;
long tw = hostdata->time_write[dev->id] / HZ;
- PRINTP(" T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
+ PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
for (i = 0; i < 8; i++)
if (dev->vendor[i] >= 0x20)
*(buffer + (len++)) = dev->vendor[i];
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index d60a89cb805..df0b3f69ef6 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -32,7 +32,6 @@
#ifndef GENERIC_NCR5380_H
#define GENERIC_NCR5380_H
-#include <linux/config.h>
#define GENERIC_NCR5380_PUBLIC_RELEASE 1
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 76071a15830..43afd476e60 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4350,7 +4350,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
isa_bios,ha->irq,ha->drq);
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+ if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
printk("GDT-ISA: Unable to allocate IRQ\n");
scsi_unregister(shp);
continue;
@@ -4476,7 +4476,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
eisa_slot>>12,ha->irq);
- if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+ if (request_irq(ha->irq,gdth_interrupt,IRQF_DISABLED,"gdth",ha)) {
printk("GDT-EISA: Unable to allocate IRQ\n");
scsi_unregister(shp);
continue;
@@ -4603,7 +4603,7 @@ static int __init gdth_detect(Scsi_Host_Template *shtp)
pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
if (request_irq(ha->irq, gdth_interrupt,
- SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
+ IRQF_DISABLED|IRQF_SHARED, "gdth", ha))
{
printk("GDT-PCI: Unable to allocate IRQ\n");
scsi_unregister(shp);
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 5b154498056..18dbe5c27da 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -47,7 +47,7 @@ void gvp11_setup (char *str, int *ints)
gvp11_xfer_mask = ints[1];
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned short cntr = GVP11_DMAC_INT_ENABLE;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -142,8 +142,8 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
- int status)
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
+ int status)
{
/* stop DMA */
DMA(instance)->SP_DMA = 1;
@@ -328,7 +328,7 @@ int __init gvp11_detect(struct scsi_host_template *tpnt)
(epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
: WD33C93_FS_12_15);
- request_irq(IRQ_AMIGA_PORTS, gvp11_intr, SA_SHIRQ, "GVP11 SCSI",
+ request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI",
instance);
DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
num_gvp11++;
@@ -341,7 +341,7 @@ release:
return num_gvp11;
}
-static int gvp11_bus_reset(Scsi_Cmnd *cmd)
+static int gvp11_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
index 575d219d14b..bf22859a503 100644
--- a/drivers/scsi/gvp11.h
+++ b/drivers/scsi/gvp11.h
@@ -13,10 +13,6 @@
int gvp11_detect(struct scsi_host_template *);
int gvp11_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index dfcb96f3e60..68ef1636678 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -265,6 +265,9 @@ static void scsi_host_dev_release(struct device *dev)
destroy_workqueue(shost->work_q);
scsi_destroy_command_freelist(shost);
+ if (shost->bqt)
+ blk_free_tags(shost->bqt);
+
kfree(shost->shost_data);
if (parent)
@@ -487,7 +490,9 @@ EXPORT_SYMBOL(scsi_is_host_device);
* @work: Work to queue for execution.
*
* Return value:
- * 0 on success / != 0 for error
+ * 1 - work queued for execution
+ * 0 - work is already queued
+ * -EINVAL - work queue doesn't exist
**/
int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
{
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index f77808329e7..28bfb8f9f81 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -15,7 +15,6 @@
*
* For more information, visit http://www.highpoint-tech.com
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -45,10 +44,6 @@ static char driver_name[] = "hptiop";
static const char driver_name_long[] = "RocketRAID 3xxx SATA Controller driver";
static const char driver_ver[] = "v1.0 (060426)";
-static DEFINE_SPINLOCK(hptiop_hba_list_lock);
-static LIST_HEAD(hptiop_hba_list);
-static int hptiop_cdev_major = -1;
-
static void hptiop_host_request_callback(struct hptiop_hba *hba, u32 tag);
static void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag);
static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg);
@@ -577,7 +572,7 @@ static int hptiop_reset_hba(struct hptiop_hba *hba)
if (atomic_xchg(&hba->resetting, 1) == 0) {
atomic_inc(&hba->reset_count);
writel(IOPMU_INBOUND_MSG0_RESET,
- &hba->iop->outbound_msgaddr0);
+ &hba->iop->inbound_msgaddr0);
hptiop_pci_posting_flush(hba->iop);
}
@@ -620,532 +615,11 @@ static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
return queue_depth;
}
-struct hptiop_getinfo {
- char __user *buffer;
- loff_t buflength;
- loff_t bufoffset;
- loff_t buffillen;
- loff_t filpos;
-};
-
-static void hptiop_copy_mem_info(struct hptiop_getinfo *pinfo,
- char *data, int datalen)
-{
- if (pinfo->filpos < pinfo->bufoffset) {
- if (pinfo->filpos + datalen <= pinfo->bufoffset) {
- pinfo->filpos += datalen;
- return;
- } else {
- data += (pinfo->bufoffset - pinfo->filpos);
- datalen -= (pinfo->bufoffset - pinfo->filpos);
- pinfo->filpos = pinfo->bufoffset;
- }
- }
-
- pinfo->filpos += datalen;
- if (pinfo->buffillen == pinfo->buflength)
- return;
-
- if (pinfo->buflength - pinfo->buffillen < datalen)
- datalen = pinfo->buflength - pinfo->buffillen;
-
- if (copy_to_user(pinfo->buffer + pinfo->buffillen, data, datalen))
- return;
-
- pinfo->buffillen += datalen;
-}
-
-static int hptiop_copy_info(struct hptiop_getinfo *pinfo, char *fmt, ...)
-{
- va_list args;
- char buf[128];
- int len;
-
- va_start(args, fmt);
- len = vsnprintf(buf, sizeof(buf), fmt, args);
- va_end(args);
- hptiop_copy_mem_info(pinfo, buf, len);
- return len;
-}
-
-static void hptiop_ioctl_done(struct hpt_ioctl_k *arg)
-{
- arg->done = NULL;
- wake_up(&arg->hba->ioctl_wq);
-}
-
-static void hptiop_do_ioctl(struct hpt_ioctl_k *arg)
-{
- struct hptiop_hba *hba = arg->hba;
- u32 val;
- struct hpt_iop_request_ioctl_command __iomem *req;
- int ioctl_retry = 0;
-
- dprintk("scsi%d: hptiop_do_ioctl\n", hba->host->host_no);
-
- /*
- * check (in + out) buff size from application.
- * outbuf must be dword aligned.
- */
- if (((arg->inbuf_size + 3) & ~3) + arg->outbuf_size >
- hba->max_request_size
- - sizeof(struct hpt_iop_request_header)
- - 4 * sizeof(u32)) {
- dprintk("scsi%d: ioctl buf size (%d/%d) is too large\n",
- hba->host->host_no,
- arg->inbuf_size, arg->outbuf_size);
- arg->result = HPT_IOCTL_RESULT_FAILED;
- return;
- }
-
-retry:
- spin_lock_irq(hba->host->host_lock);
-
- val = readl(&hba->iop->inbound_queue);
- if (val == IOPMU_QUEUE_EMPTY) {
- spin_unlock_irq(hba->host->host_lock);
- dprintk("scsi%d: no free req for ioctl\n", hba->host->host_no);
- arg->result = -1;
- return;
- }
-
- req = (struct hpt_iop_request_ioctl_command __iomem *)
- ((unsigned long)hba->iop + val);
-
- writel(HPT_CTL_CODE_LINUX_TO_IOP(arg->ioctl_code),
- &req->ioctl_code);
- writel(arg->inbuf_size, &req->inbuf_size);
- writel(arg->outbuf_size, &req->outbuf_size);
-
- /*
- * use the buffer on the IOP local memory first, then copy it
- * back to host.
- * the caller's request buffer shoudl be little-endian.
- */
- if (arg->inbuf_size)
- memcpy_toio(req->buf, arg->inbuf, arg->inbuf_size);
-
- /* correct the controller ID for IOP */
- if ((arg->ioctl_code == HPT_IOCTL_GET_CHANNEL_INFO ||
- arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO_V2 ||
- arg->ioctl_code == HPT_IOCTL_GET_CONTROLLER_INFO)
- && arg->inbuf_size >= sizeof(u32))
- writel(0, req->buf);
-
- writel(IOP_REQUEST_TYPE_IOCTL_COMMAND, &req->header.type);
- writel(0, &req->header.flags);
- writel(offsetof(struct hpt_iop_request_ioctl_command, buf)
- + arg->inbuf_size, &req->header.size);
- writel((u32)(unsigned long)arg, &req->header.context);
- writel(BITS_PER_LONG > 32 ? (u32)((unsigned long)arg>>32) : 0,
- &req->header.context_hi32);
- writel(IOP_RESULT_PENDING, &req->header.result);
-
- arg->result = HPT_IOCTL_RESULT_FAILED;
- arg->done = hptiop_ioctl_done;
-
- writel(val, &hba->iop->inbound_queue);
- hptiop_pci_posting_flush(hba->iop);
-
- spin_unlock_irq(hba->host->host_lock);
-
- wait_event_timeout(hba->ioctl_wq, arg->done == NULL, 60 * HZ);
-
- if (arg->done != NULL) {
- hptiop_reset_hba(hba);
- if (ioctl_retry++ < 3)
- goto retry;
- }
-
- dprintk("hpt_iop_ioctl %x result %d\n",
- arg->ioctl_code, arg->result);
-}
-
-static int __hpt_do_ioctl(struct hptiop_hba *hba, u32 code, void *inbuf,
- u32 insize, void *outbuf, u32 outsize)
-{
- struct hpt_ioctl_k arg;
- arg.hba = hba;
- arg.ioctl_code = code;
- arg.inbuf = inbuf;
- arg.outbuf = outbuf;
- arg.inbuf_size = insize;
- arg.outbuf_size = outsize;
- arg.bytes_returned = NULL;
- hptiop_do_ioctl(&arg);
- return arg.result;
-}
-
-static inline int hpt_id_valid(__le32 id)
-{
- return id != 0 && id != cpu_to_le32(0xffffffff);
-}
-
-static int hptiop_get_controller_info(struct hptiop_hba *hba,
- struct hpt_controller_info *pinfo)
-{
- int id = 0;
-
- return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CONTROLLER_INFO,
- &id, sizeof(int), pinfo, sizeof(*pinfo));
-}
-
-
-static int hptiop_get_channel_info(struct hptiop_hba *hba, int bus,
- struct hpt_channel_info *pinfo)
-{
- u32 ids[2];
-
- ids[0] = 0;
- ids[1] = bus;
- return __hpt_do_ioctl(hba, HPT_IOCTL_GET_CHANNEL_INFO,
- ids, sizeof(ids), pinfo, sizeof(*pinfo));
-
-}
-
-static int hptiop_get_logical_devices(struct hptiop_hba *hba,
- __le32 *pids, int maxcount)
-{
- int i;
- u32 count = maxcount - 1;
-
- if (__hpt_do_ioctl(hba, HPT_IOCTL_GET_LOGICAL_DEVICES,
- &count, sizeof(u32),
- pids, sizeof(u32) * maxcount))
- return -1;
-
- maxcount = le32_to_cpu(pids[0]);
- for (i = 0; i < maxcount; i++)
- pids[i] = pids[i+1];
-
- return maxcount;
-}
-
-static int hptiop_get_device_info_v3(struct hptiop_hba *hba, __le32 id,
- struct hpt_logical_device_info_v3 *pinfo)
-{
- return __hpt_do_ioctl(hba, HPT_IOCTL_GET_DEVICE_INFO_V3,
- &id, sizeof(u32),
- pinfo, sizeof(*pinfo));
-}
-
-static const char *get_array_status(struct hpt_logical_device_info_v3 *devinfo)
-{
- static char s[64];
- u32 flags = le32_to_cpu(devinfo->u.array.flags);
- u32 trans_prog = le32_to_cpu(devinfo->u.array.transforming_progress);
- u32 reb_prog = le32_to_cpu(devinfo->u.array.rebuilding_progress);
-
- if (flags & ARRAY_FLAG_DISABLED)
- return "Disabled";
- else if (flags & ARRAY_FLAG_TRANSFORMING)
- sprintf(s, "Expanding/Migrating %d.%d%%%s%s",
- trans_prog / 100,
- trans_prog % 100,
- (flags & (ARRAY_FLAG_NEEDBUILDING|ARRAY_FLAG_BROKEN))?
- ", Critical" : "",
- ((flags & ARRAY_FLAG_NEEDINITIALIZING) &&
- !(flags & ARRAY_FLAG_REBUILDING) &&
- !(flags & ARRAY_FLAG_INITIALIZING))?
- ", Unintialized" : "");
- else if ((flags & ARRAY_FLAG_BROKEN) &&
- devinfo->u.array.array_type != AT_RAID6)
- return "Critical";
- else if (flags & ARRAY_FLAG_REBUILDING)
- sprintf(s,
- (flags & ARRAY_FLAG_NEEDINITIALIZING)?
- "%sBackground initializing %d.%d%%" :
- "%sRebuilding %d.%d%%",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- reb_prog / 100,
- reb_prog % 100);
- else if (flags & ARRAY_FLAG_VERIFYING)
- sprintf(s, "%sVerifying %d.%d%%",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- reb_prog / 100,
- reb_prog % 100);
- else if (flags & ARRAY_FLAG_INITIALIZING)
- sprintf(s, "%sForground initializing %d.%d%%",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- reb_prog / 100,
- reb_prog % 100);
- else if (flags & ARRAY_FLAG_NEEDTRANSFORM)
- sprintf(s,"%s%s%s", "Need Expanding/Migrating",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "",
- ((flags & ARRAY_FLAG_NEEDINITIALIZING) &&
- !(flags & ARRAY_FLAG_REBUILDING) &&
- !(flags & ARRAY_FLAG_INITIALIZING))?
- ", Unintialized" : "");
- else if (flags & ARRAY_FLAG_NEEDINITIALIZING &&
- !(flags & ARRAY_FLAG_REBUILDING) &&
- !(flags & ARRAY_FLAG_INITIALIZING))
- sprintf(s,"%sUninitialized",
- (flags & ARRAY_FLAG_BROKEN)? "Critical, " : "");
- else if ((flags & ARRAY_FLAG_NEEDBUILDING) ||
- (flags & ARRAY_FLAG_BROKEN))
- return "Critical";
- else
- return "Normal";
- return s;
-}
-
-static void hptiop_dump_devinfo(struct hptiop_hba *hba,
- struct hptiop_getinfo *pinfo, __le32 id, int indent)
-{
- struct hpt_logical_device_info_v3 devinfo;
- int i;
- u64 capacity;
-
- for (i = 0; i < indent; i++)
- hptiop_copy_info(pinfo, "\t");
-
- if (hptiop_get_device_info_v3(hba, id, &devinfo)) {
- hptiop_copy_info(pinfo, "unknown\n");
- return;
- }
-
- switch (devinfo.type) {
-
- case LDT_DEVICE: {
- struct hd_driveid *driveid;
- u32 flags = le32_to_cpu(devinfo.u.device.flags);
-
- driveid = (struct hd_driveid *)devinfo.u.device.ident;
- /* model[] is 40 chars long, but we just want 20 chars here */
- driveid->model[20] = 0;
-
- if (indent)
- if (flags & DEVICE_FLAG_DISABLED)
- hptiop_copy_info(pinfo,"Missing\n");
- else
- hptiop_copy_info(pinfo, "CH%d %s\n",
- devinfo.u.device.path_id + 1,
- driveid->model);
- else {
- capacity = le64_to_cpu(devinfo.capacity) * 512;
- do_div(capacity, 1000000);
- hptiop_copy_info(pinfo,
- "CH%d %s, %lluMB, %s %s%s%s%s\n",
- devinfo.u.device.path_id + 1,
- driveid->model,
- capacity,
- (flags & DEVICE_FLAG_DISABLED)?
- "Disabled" : "Normal",
- devinfo.u.device.read_ahead_enabled?
- "[RA]" : "",
- devinfo.u.device.write_cache_enabled?
- "[WC]" : "",
- devinfo.u.device.TCQ_enabled?
- "[TCQ]" : "",
- devinfo.u.device.NCQ_enabled?
- "[NCQ]" : ""
- );
- }
- break;
- }
-
- case LDT_ARRAY:
- if (devinfo.target_id != INVALID_TARGET_ID)
- hptiop_copy_info(pinfo, "[DISK %d_%d] ",
- devinfo.vbus_id, devinfo.target_id);
-
- capacity = le64_to_cpu(devinfo.capacity) * 512;
- do_div(capacity, 1000000);
- hptiop_copy_info(pinfo, "%s (%s), %lluMB, %s\n",
- devinfo.u.array.name,
- devinfo.u.array.array_type==AT_RAID0? "RAID0" :
- devinfo.u.array.array_type==AT_RAID1? "RAID1" :
- devinfo.u.array.array_type==AT_RAID5? "RAID5" :
- devinfo.u.array.array_type==AT_RAID6? "RAID6" :
- devinfo.u.array.array_type==AT_JBOD? "JBOD" :
- "unknown",
- capacity,
- get_array_status(&devinfo));
- for (i = 0; i < devinfo.u.array.ndisk; i++) {
- if (hpt_id_valid(devinfo.u.array.members[i])) {
- if (cpu_to_le16(1<<i) &
- devinfo.u.array.critical_members)
- hptiop_copy_info(pinfo, "\t*");
- hptiop_dump_devinfo(hba, pinfo,
- devinfo.u.array.members[i], indent+1);
- }
- else
- hptiop_copy_info(pinfo, "\tMissing\n");
- }
- if (id == devinfo.u.array.transform_source) {
- hptiop_copy_info(pinfo, "\tExpanding/Migrating to:\n");
- hptiop_dump_devinfo(hba, pinfo,
- devinfo.u.array.transform_target, indent+1);
- }
- break;
- }
-}
-
static ssize_t hptiop_show_version(struct class_device *class_dev, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver);
}
-static ssize_t hptiop_cdev_read(struct file *filp, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct hptiop_hba *hba = filp->private_data;
- struct hptiop_getinfo info;
- int i, j, ndev;
- struct hpt_controller_info con_info;
- struct hpt_channel_info chan_info;
- __le32 ids[32];
-
- info.buffer = buf;
- info.buflength = count;
- info.bufoffset = ppos ? *ppos : 0;
- info.filpos = 0;
- info.buffillen = 0;
-
- if (hptiop_get_controller_info(hba, &con_info))
- return -EIO;
-
- for (i = 0; i < con_info.num_buses; i++) {
- if (hptiop_get_channel_info(hba, i, &chan_info) == 0) {
- if (hpt_id_valid(chan_info.devices[0]))
- hptiop_dump_devinfo(hba, &info,
- chan_info.devices[0], 0);
- if (hpt_id_valid(chan_info.devices[1]))
- hptiop_dump_devinfo(hba, &info,
- chan_info.devices[1], 0);
- }
- }
-
- ndev = hptiop_get_logical_devices(hba, ids,
- sizeof(ids) / sizeof(ids[0]));
-
- /*
- * if hptiop_get_logical_devices fails, ndev==-1 and it just
- * output nothing here
- */
- for (j = 0; j < ndev; j++)
- hptiop_dump_devinfo(hba, &info, ids[j], 0);
-
- if (ppos)
- *ppos += info.buffillen;
-
- return info.buffillen;
-}
-
-static int hptiop_cdev_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct hptiop_hba *hba = file->private_data;
- struct hpt_ioctl_u ioctl_u;
- struct hpt_ioctl_k ioctl_k;
- u32 bytes_returned;
- int err = -EINVAL;
-
- if (copy_from_user(&ioctl_u,
- (void __user *)arg, sizeof(struct hpt_ioctl_u)))
- return -EINVAL;
-
- if (ioctl_u.magic != HPT_IOCTL_MAGIC)
- return -EINVAL;
-
- ioctl_k.ioctl_code = ioctl_u.ioctl_code;
- ioctl_k.inbuf = NULL;
- ioctl_k.inbuf_size = ioctl_u.inbuf_size;
- ioctl_k.outbuf = NULL;
- ioctl_k.outbuf_size = ioctl_u.outbuf_size;
- ioctl_k.hba = hba;
- ioctl_k.bytes_returned = &bytes_returned;
-
- /* verify user buffer */
- if ((ioctl_k.inbuf_size && !access_ok(VERIFY_READ,
- ioctl_u.inbuf, ioctl_k.inbuf_size)) ||
- (ioctl_k.outbuf_size && !access_ok(VERIFY_WRITE,
- ioctl_u.outbuf, ioctl_k.outbuf_size)) ||
- (ioctl_u.bytes_returned && !access_ok(VERIFY_WRITE,
- ioctl_u.bytes_returned, sizeof(u32))) ||
- ioctl_k.inbuf_size + ioctl_k.outbuf_size > 0x10000) {
-
- dprintk("scsi%d: got bad user address\n", hba->host->host_no);
- return -EINVAL;
- }
-
- /* map buffer to kernel. */
- if (ioctl_k.inbuf_size) {
- ioctl_k.inbuf = kmalloc(ioctl_k.inbuf_size, GFP_KERNEL);
- if (!ioctl_k.inbuf) {
- dprintk("scsi%d: fail to alloc inbuf\n",
- hba->host->host_no);
- err = -ENOMEM;
- goto err_exit;
- }
-
- if (copy_from_user(ioctl_k.inbuf,
- ioctl_u.inbuf, ioctl_k.inbuf_size)) {
- goto err_exit;
- }
- }
-
- if (ioctl_k.outbuf_size) {
- ioctl_k.outbuf = kmalloc(ioctl_k.outbuf_size, GFP_KERNEL);
- if (!ioctl_k.outbuf) {
- dprintk("scsi%d: fail to alloc outbuf\n",
- hba->host->host_no);
- err = -ENOMEM;
- goto err_exit;
- }
- }
-
- hptiop_do_ioctl(&ioctl_k);
-
- if (ioctl_k.result == HPT_IOCTL_RESULT_OK) {
- if (ioctl_k.outbuf_size &&
- copy_to_user(ioctl_u.outbuf,
- ioctl_k.outbuf, ioctl_k.outbuf_size))
- goto err_exit;
-
- if (ioctl_u.bytes_returned &&
- copy_to_user(ioctl_u.bytes_returned,
- &bytes_returned, sizeof(u32)))
- goto err_exit;
-
- err = 0;
- }
-
-err_exit:
- kfree(ioctl_k.inbuf);
- kfree(ioctl_k.outbuf);
-
- return err;
-}
-
-static int hptiop_cdev_open(struct inode *inode, struct file *file)
-{
- struct hptiop_hba *hba;
- unsigned i = 0, minor = iminor(inode);
- int ret = -ENODEV;
-
- spin_lock(&hptiop_hba_list_lock);
- list_for_each_entry(hba, &hptiop_hba_list, link) {
- if (i == minor) {
- file->private_data = hba;
- ret = 0;
- goto out;
- }
- i++;
- }
-
-out:
- spin_unlock(&hptiop_hba_list_lock);
- return ret;
-}
-
-static struct file_operations hptiop_cdev_fops = {
- .owner = THIS_MODULE,
- .read = hptiop_cdev_read,
- .ioctl = hptiop_cdev_ioctl,
- .open = hptiop_cdev_open,
-};
-
static ssize_t hptiop_show_fw_version(struct class_device *class_dev, char *buf)
{
struct Scsi_Host *host = class_to_shost(class_dev);
@@ -1296,19 +770,13 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
goto unmap_pci_bar;
}
- if (scsi_add_host(host, &pcidev->dev)) {
- printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
- hba->host->host_no);
- goto unmap_pci_bar;
- }
-
pci_set_drvdata(pcidev, host);
- if (request_irq(pcidev->irq, hptiop_intr, SA_SHIRQ,
+ if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED,
driver_name, hba)) {
printk(KERN_ERR "scsi%d: request irq %d failed\n",
hba->host->host_no, pcidev->irq);
- goto remove_scsi_host;
+ goto unmap_pci_bar;
}
/* Allocate request mem */
@@ -1355,9 +823,12 @@ static int __devinit hptiop_probe(struct pci_dev *pcidev,
if (hptiop_initialize_iop(hba))
goto free_request_mem;
- spin_lock(&hptiop_hba_list_lock);
- list_add_tail(&hba->link, &hptiop_hba_list);
- spin_unlock(&hptiop_hba_list_lock);
+ if (scsi_add_host(host, &pcidev->dev)) {
+ printk(KERN_ERR "scsi%d: scsi_add_host failed\n",
+ hba->host->host_no);
+ goto free_request_mem;
+ }
+
scsi_scan_host(host);
@@ -1372,9 +843,6 @@ free_request_mem:
free_request_irq:
free_irq(hba->pcidev->irq, hba);
-remove_scsi_host:
- scsi_remove_host(host);
-
unmap_pci_bar:
iounmap(hba->iop);
@@ -1422,10 +890,6 @@ static void hptiop_remove(struct pci_dev *pcidev)
scsi_remove_host(host);
- spin_lock(&hptiop_hba_list_lock);
- list_del_init(&hba->link);
- spin_unlock(&hptiop_hba_list_lock);
-
hptiop_shutdown(pcidev);
free_irq(hba->pcidev->irq, hba);
@@ -1462,27 +926,12 @@ static struct pci_driver hptiop_pci_driver = {
static int __init hptiop_module_init(void)
{
- int error;
-
printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver);
-
- error = pci_register_driver(&hptiop_pci_driver);
- if (error < 0)
- return error;
-
- hptiop_cdev_major = register_chrdev(0, "hptiop", &hptiop_cdev_fops);
- if (hptiop_cdev_major < 0) {
- printk(KERN_WARNING "unable to register hptiop device.\n");
- return hptiop_cdev_major;
- }
-
- return 0;
+ return pci_register_driver(&hptiop_pci_driver);
}
static void __exit hptiop_module_exit(void)
{
- dprintk("hptiop_module_exit\n");
- unregister_chrdev(hptiop_cdev_major, "hptiop");
pci_unregister_driver(&hptiop_pci_driver);
}
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 115f55471ed..2be1dc5d852 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -17,7 +17,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
@@ -760,7 +759,7 @@ static int device_inquiry(int host_index, int ldn)
while (!got_interrupt(host_index))
barrier();
- /*if command succesful, break */
+ /*if command successful, break */
if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
return 1;
}
@@ -885,7 +884,7 @@ static int immediate_assign(int host_index, unsigned int pun, unsigned int lun,
while (!got_interrupt(host_index))
barrier();
- /*if command succesful, break */
+ /*if command successful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
@@ -921,7 +920,7 @@ static int immediate_feature(int host_index, unsigned int speed, unsigned int ti
return 2;
} else
global_command_error_excuse = 0;
- /*if command succesful, break */
+ /*if command successful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
@@ -959,7 +958,7 @@ static int immediate_reset(int host_index, unsigned int ldn)
/* did not work, finish */
return 1;
}
- /*if command succesful, break */
+ /*if command successful, break */
if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
return 1;
}
@@ -1511,7 +1510,7 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
#endif
/* get interrupt request level */
- if (request_irq(IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+ if (request_irq(IM_IRQ, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
return 0;
} else
@@ -1636,7 +1635,7 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
/* IRQ11 is used by SCSI-2 F/W Adapter/A */
printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
/* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+ if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts)) {
printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
} else
IRQ11_registered++;
@@ -1697,7 +1696,7 @@ int ibmmca_detect(struct scsi_host_template * scsi_template)
/* IRQ11 is used by SCSI-2 F/W Adapter/A */
printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
/* get interrupt request level */
- if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts))
+ if (request_irq(IM_IRQ_FW, interrupt_handler, IRQF_SHARED, "ibmmcascsi", hosts))
printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
else
IRQ11_registered++;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 944fc1203eb..669ea4fff16 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -535,6 +535,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
struct ibmvscsi_host_data *hostdata)
{
u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
+ int request_status;
int rc;
/* If we have exhausted our request limit, just fail this request.
@@ -542,9 +543,18 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
* (such as task management requests) that the mid layer may think we
* can handle more requests (can_queue) when we actually can't
*/
- if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
- (atomic_dec_if_positive(&hostdata->request_limit) < 0))
- goto send_error;
+ if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) {
+ request_status =
+ atomic_dec_if_positive(&hostdata->request_limit);
+ /* If request limit was -1 when we started, it is now even
+ * less than that
+ */
+ if (request_status < -1)
+ goto send_error;
+ /* Otherwise, if we have run out of requests */
+ else if (request_status < 0)
+ goto send_busy;
+ }
/* Copy the IU into the transfer area */
*evt_struct->xfer_iu = evt_struct->iu;
@@ -567,11 +577,23 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
return 0;
- send_error:
+ send_busy:
unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
free_event_struct(&hostdata->pool, evt_struct);
return SCSI_MLQUEUE_HOST_BUSY;
+
+ send_error:
+ unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev);
+
+ if (evt_struct->cmnd != NULL) {
+ evt_struct->cmnd->result = DID_ERROR << 16;
+ evt_struct->cmnd_done(evt_struct->cmnd);
+ } else if (evt_struct->done)
+ evt_struct->done(evt_struct);
+
+ free_event_struct(&hostdata->pool, evt_struct);
+ return 0;
}
/**
@@ -1184,27 +1206,37 @@ void ibmvscsi_handle_crq(struct viosrp_crq *crq,
return;
case 0xFF: /* Hypervisor telling us the connection is closed */
scsi_block_requests(hostdata->host);
+ atomic_set(&hostdata->request_limit, 0);
if (crq->format == 0x06) {
/* We need to re-setup the interpartition connection */
printk(KERN_INFO
"ibmvscsi: Re-enabling adapter!\n");
- atomic_set(&hostdata->request_limit, -1);
purge_requests(hostdata, DID_REQUEUE);
- if (ibmvscsi_reenable_crq_queue(&hostdata->queue,
- hostdata) == 0)
- if (ibmvscsi_send_crq(hostdata,
- 0xC001000000000000LL, 0))
+ if ((ibmvscsi_reenable_crq_queue(&hostdata->queue,
+ hostdata) == 0) ||
+ (ibmvscsi_send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
+ atomic_set(&hostdata->request_limit,
+ -1);
printk(KERN_ERR
- "ibmvscsi: transmit error after"
+ "ibmvscsi: error after"
" enable\n");
+ }
} else {
printk(KERN_INFO
"ibmvscsi: Virtual adapter failed rc %d!\n",
crq->format);
- atomic_set(&hostdata->request_limit, -1);
purge_requests(hostdata, DID_ERROR);
- ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+ if ((ibmvscsi_reset_crq_queue(&hostdata->queue,
+ hostdata)) ||
+ (ibmvscsi_send_crq(hostdata,
+ 0xC001000000000000LL, 0))) {
+ atomic_set(&hostdata->request_limit,
+ -1);
+ printk(KERN_ERR
+ "ibmvscsi: error after reset\n");
+ }
}
scsi_unblock_requests(hostdata->host);
return;
@@ -1467,6 +1499,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
struct Scsi_Host *host;
struct device *dev = &vdev->dev;
unsigned long wait_switch = 0;
+ int rc;
vdev->dev.driver_data = NULL;
@@ -1484,8 +1517,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
atomic_set(&hostdata->request_limit, -1);
hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
- if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata,
- max_requests) != 0) {
+ rc = ibmvscsi_init_crq_queue(&hostdata->queue, hostdata, max_requests);
+ if (rc != 0 && rc != H_RESOURCE) {
printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
goto init_crq_failed;
}
@@ -1505,7 +1538,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
* to fail if the other end is not acive. In that case we don't
* want to scan
*/
- if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) {
+ if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0
+ || rc == H_RESOURCE) {
/*
* Wait around max init_timeout secs for the adapter to finish
* initializing. When we are done initializing, we will have a
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
index 7eed0b09817..6aeb5f003c3 100644
--- a/drivers/scsi/ibmvscsi/iseries_vscsi.c
+++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c
@@ -81,7 +81,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
int rc;
single_host_data = hostdata;
- rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0);
+ rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests);
if (rc < 0) {
printk("viopath_open failed with rc %d in open_event_path\n",
rc);
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 1a9992bdfef..01b8ac641eb 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -156,8 +156,8 @@ static void gather_partition_info(void)
{
struct device_node *rootdn;
- char *ppartition_name;
- unsigned int *p_number_ptr;
+ const char *ppartition_name;
+ const unsigned int *p_number_ptr;
/* Retrieve information about this partition */
rootdn = find_path_device("/");
@@ -165,14 +165,11 @@ static void gather_partition_info(void)
return;
}
- ppartition_name =
- get_property(rootdn, "ibm,partition-name", NULL);
+ ppartition_name = get_property(rootdn, "ibm,partition-name", NULL);
if (ppartition_name)
strncpy(partition_name, ppartition_name,
sizeof(partition_name));
- p_number_ptr =
- (unsigned int *)get_property(rootdn, "ibm,partition-no",
- NULL);
+ p_number_ptr = get_property(rootdn, "ibm,partition-no", NULL);
if (p_number_ptr)
partition_number = *p_number_ptr;
}
@@ -208,6 +205,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
int max_requests)
{
int rc;
+ int retrc;
struct vio_dev *vdev = to_vio_dev(hostdata->dev);
queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
@@ -226,7 +224,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
gather_partition_info();
set_adapter_info(hostdata);
- rc = plpar_hcall_norets(H_REG_CRQ,
+ retrc = rc = plpar_hcall_norets(H_REG_CRQ,
vdev->unit_address,
queue->msg_token, PAGE_SIZE);
if (rc == H_RESOURCE)
@@ -237,6 +235,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
if (rc == 2) {
/* Adapter is good, but other end is not ready */
printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+ retrc = 0;
} else if (rc != 0) {
printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
goto reg_crq_failed;
@@ -263,7 +262,7 @@ int ibmvscsi_init_crq_queue(struct crq_queue *queue,
tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
(unsigned long)hostdata);
- return 0;
+ return retrc;
req_irq_failed:
do {
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 988e6f7af01..94d1de55607 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -34,7 +34,6 @@
#define IDESCSI_VERSION "0.92"
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -518,7 +517,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
/* No more interrupts */
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
- local_irq_enable();
+ local_irq_enable_in_hardirq();
if (status.b.check)
rq->errors++;
idescsi_end_request (drive, 1, 0);
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
index cd2dffdab77..2d95ac9c32c 100644
--- a/drivers/scsi/imm.c
+++ b/drivers/scsi/imm.c
@@ -3,15 +3,11 @@
*
* (The IMM is the embedded controller in the ZIP Plus drive.)
*
- * Current Maintainer: David Campbell (Perth, Western Australia)
- * campbell@torque.net
- *
* My unoffical company acronym list is 21 pages long:
* FLA: Four letter acronym with built in facility for
* future expansion to five letters.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index dc3aebf0e36..ece936ac29c 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -2,7 +2,7 @@
/* Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in
* the Iomega ZIP Plus drive
*
- * (c) 1998 David Campbell campbell@torque.net
+ * (c) 1998 David Campbell
*
* Please note that I live in Perth, Western Australia. GMT+0800
*/
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 883bc92b4d9..59a4097f125 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2015,7 +2015,7 @@ static int __init in2000_detect(struct scsi_host_template * tpnt)
write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */
write1_io(0, IO_INTR_MASK); /* allow all ints */
x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
- if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", instance)) {
+ if (request_irq(x, in2000_intr, IRQF_DISABLED, "in2000", instance)) {
printk("in2000_detect: Unable to allocate IRQ.\n");
detect_count--;
continue;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 913ba95f85b..9e10dac61cf 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -118,7 +118,6 @@
#include <linux/blkdev.h>
#include <linux/spinlock.h>
#include <linux/stat.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
@@ -2868,7 +2867,7 @@ static int i91u_detect(struct scsi_host_template * tpnt)
hreg->sg_tablesize = TOTAL_SG_ENTRY; /* Maximun support is 32 */
/* Initial tulip chip */
- ok = request_irq(pHCB->HCS_Intr, i91u_intr, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
+ ok = request_irq(pHCB->HCS_Intr, i91u_intr, IRQF_DISABLED | IRQF_SHARED, "i91u", hreg);
if (ok < 0) {
printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
return 0;
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
index 3efb1184fc3..acb67a4af2c 100644
--- a/drivers/scsi/initio.h
+++ b/drivers/scsi/initio.h
@@ -54,7 +54,6 @@
**************************************************************************/
-#include <linux/config.h>
#include <linux/types.h>
#define ULONG unsigned long
@@ -193,13 +192,13 @@ typedef struct {
#define TSC_SEL_ATN_DIRECT_OUT 0x15 /* Select With ATN Sequence */
#define TSC_SEL_ATN3_DIRECT_IN 0xB5 /* Select With ATN3 Sequence */
#define TSC_SEL_ATN3_DIRECT_OUT 0x35 /* Select With ATN3 Sequence */
-#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Infomation out */
-#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Infomation in */
+#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Information out */
+#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Information in */
-#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Infomation out */
-#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Infomation in */
-#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Infomation out */
-#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Infomation in */
+#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Information out */
+#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Information in */
+#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Information out */
+#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Information in */
#define TSC_MSG_ACCEPT 0x0F /* Message Accept */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 96b65b307dd..7ed4eef8347 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -54,7 +54,6 @@
*
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -176,6 +175,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"Qualified success"},
{0x01080000, 1, 1,
"FFFE: Soft device bus error recovered by the IOA"},
+ {0x01088100, 0, 1,
+ "4101: Soft device bus fabric error"},
{0x01170600, 0, 1,
"FFF9: Device sector reassign successful"},
{0x01170900, 0, 1,
@@ -226,6 +227,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"3109: IOA timed out a device command"},
{0x04088000, 0, 0,
"3120: SCSI bus is not operational"},
+ {0x04088100, 0, 1,
+ "4100: Hard device bus fabric error"},
{0x04118000, 0, 1,
"9000: IOA reserved area data check"},
{0x04118100, 0, 1,
@@ -274,6 +277,14 @@ struct ipr_error_table_t ipr_error_table[] = {
"9091: Incorrect hardware configuration change has been detected"},
{0x04678000, 0, 1,
"9073: Invalid multi-adapter configuration"},
+ {0x04678100, 0, 1,
+ "4010: Incorrect connection between cascaded expanders"},
+ {0x04678200, 0, 1,
+ "4020: Connections exceed IOA design limits"},
+ {0x04678300, 0, 1,
+ "4030: Incorrect multipath connection"},
+ {0x04679000, 0, 1,
+ "4110: Unsupported enclosure function"},
{0x046E0000, 0, 1,
"FFF4: Command to logical unit failed"},
{0x05240000, 1, 0,
@@ -298,6 +309,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"9031: Array protection temporarily suspended, protection resuming"},
{0x06040600, 0, 1,
"9040: Array protection temporarily suspended, protection resuming"},
+ {0x06288000, 0, 1,
+ "3140: Device bus not ready to ready transition"},
{0x06290000, 0, 1,
"FFFB: SCSI bus was reset"},
{0x06290500, 0, 0,
@@ -320,6 +333,16 @@ struct ipr_error_table_t ipr_error_table[] = {
"3150: SCSI bus configuration error"},
{0x06678100, 0, 1,
"9074: Asymmetric advanced function disk configuration"},
+ {0x06678300, 0, 1,
+ "4040: Incomplete multipath connection between IOA and enclosure"},
+ {0x06678400, 0, 1,
+ "4041: Incomplete multipath connection between enclosure and device"},
+ {0x06678500, 0, 1,
+ "9075: Incomplete multipath connection between IOA and remote IOA"},
+ {0x06678600, 0, 1,
+ "9076: Configuration error, missing remote IOA"},
+ {0x06679100, 0, 1,
+ "4050: Enclosure does not support a required multipath function"},
{0x06690200, 0, 1,
"9041: Array protection temporarily suspended"},
{0x06698200, 0, 1,
@@ -332,6 +355,10 @@ struct ipr_error_table_t ipr_error_table[] = {
"9072: Link not operational transition"},
{0x066B8200, 0, 1,
"9032: Array exposed but still protected"},
+ {0x066B9100, 0, 1,
+ "4061: Multipath redundancy level got better"},
+ {0x066B9200, 0, 1,
+ "4060: Multipath redundancy level got worse"},
{0x07270000, 0, 0,
"Failure due to other device"},
{0x07278000, 0, 1,
@@ -4100,8 +4127,7 @@ static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
- if ((be32_to_cpu(ioasa->ioasc_specific) &
- (IPR_ADDITIONAL_STATUS_FMT | IPR_AUTOSENSE_VALID)) == 0)
+ if ((be32_to_cpu(ioasa->ioasc_specific) & IPR_AUTOSENSE_VALID) == 0)
return 0;
memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data,
@@ -4191,7 +4217,8 @@ static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
case IPR_IOASC_NR_INIT_CMD_REQUIRED:
break;
default:
- scsi_cmd->result |= (DID_ERROR << 16);
+ if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
+ scsi_cmd->result |= (DID_ERROR << 16);
if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res))
res->needs_sync_complete = 1;
break;
@@ -6429,7 +6456,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
ioa_cfg->needs_hard_reset = 1;
ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
- rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg);
+ rc = request_irq(pdev->irq, ipr_isr, IRQF_SHARED, IPR_NAME, ioa_cfg);
if (rc) {
dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n",
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 1ad24df69d7..11eaff52432 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -36,8 +36,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.1.3"
-#define IPR_DRIVER_DATE "(March 29, 2006)"
+#define IPR_DRIVER_VERSION "2.1.4"
+#define IPR_DRIVER_DATE "(August 2, 2006)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -45,6 +45,7 @@
* This can be adjusted at runtime through sysfs device attributes.
*/
#define IPR_MAX_CMD_PER_LUN 6
+#define IPR_MAX_CMD_PER_ATA_LUN 1
/*
* IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of
@@ -106,7 +107,7 @@
#define IPR_IOA_BUS 0xff
#define IPR_IOA_TARGET 0xff
#define IPR_IOA_LUN 0xff
-#define IPR_MAX_NUM_BUSES 8
+#define IPR_MAX_NUM_BUSES 16
#define IPR_MAX_BUS_TO_SCAN IPR_MAX_NUM_BUSES
#define IPR_NUM_RESET_RELOAD_RETRIES 3
@@ -145,6 +146,7 @@
#define IPR_LUN_RESET 0x40
#define IPR_TARGET_RESET 0x20
#define IPR_BUS_RESET 0x10
+#define IPR_ATA_PHY_RESET 0x80
#define IPR_ID_HOST_RR_Q 0xC4
#define IPR_QUERY_IOA_CONFIG 0xC5
#define IPR_CANCEL_ALL_REQUESTS 0xCE
@@ -295,7 +297,11 @@ struct ipr_std_inq_data {
}__attribute__ ((packed));
struct ipr_config_table_entry {
- u8 service_level;
+ u8 proto;
+#define IPR_PROTO_SATA 0x02
+#define IPR_PROTO_SATA_ATAPI 0x03
+#define IPR_PROTO_SAS_STP 0x06
+#define IPR_PROTO_SAS_STP_ATAPI 0x07
u8 array_id;
u8 flags;
#define IPR_IS_IOA_RESOURCE 0x80
@@ -307,6 +313,7 @@ struct ipr_config_table_entry {
#define IPR_SUBTYPE_AF_DASD 0
#define IPR_SUBTYPE_GENERIC_SCSI 1
#define IPR_SUBTYPE_VOLUME_SET 2
+#define IPR_SUBTYPE_GENERIC_ATA 4
#define IPR_QUEUEING_MODEL(res) ((((res)->cfgte.flags) & 0x70) >> 4)
#define IPR_QUEUE_FROZEN_MODEL 0
@@ -350,6 +357,7 @@ struct ipr_cmd_pkt {
#define IPR_RQTYPE_SCSICDB 0x00
#define IPR_RQTYPE_IOACMD 0x01
#define IPR_RQTYPE_HCAM 0x02
+#define IPR_RQTYPE_ATA_PASSTHRU 0x04
u8 luntar_luntrn;
@@ -373,6 +381,37 @@ struct ipr_cmd_pkt {
__be16 timeout;
}__attribute__ ((packed, aligned(4)));
+struct ipr_ioarcb_ata_regs {
+ u8 flags;
+#define IPR_ATA_FLAG_PACKET_CMD 0x80
+#define IPR_ATA_FLAG_XFER_TYPE_DMA 0x40
+#define IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION 0x20
+ u8 reserved[3];
+
+ __be16 data;
+ u8 feature;
+ u8 nsect;
+ u8 lbal;
+ u8 lbam;
+ u8 lbah;
+ u8 device;
+ u8 command;
+ u8 reserved2[3];
+ u8 hob_feature;
+ u8 hob_nsect;
+ u8 hob_lbal;
+ u8 hob_lbam;
+ u8 hob_lbah;
+ u8 ctl;
+}__attribute__ ((packed, aligned(4)));
+
+struct ipr_ioarcb_add_data {
+ union {
+ struct ipr_ioarcb_ata_regs regs;
+ __be32 add_cmd_parms[10];
+ }u;
+}__attribute__ ((packed, aligned(4)));
+
/* IOA Request Control Block 128 bytes */
struct ipr_ioarcb {
__be32 ioarcb_host_pci_addr;
@@ -397,7 +436,7 @@ struct ipr_ioarcb {
struct ipr_cmd_pkt cmd_pkt;
__be32 add_cmd_parms_len;
- __be32 add_cmd_parms[10];
+ struct ipr_ioarcb_add_data add_data;
}__attribute__((packed, aligned (4)));
struct ipr_ioadl_desc {
@@ -433,6 +472,21 @@ struct ipr_ioasa_gpdd {
__be32 ioa_data[2];
}__attribute__((packed, aligned (4)));
+struct ipr_ioasa_gata {
+ u8 error;
+ u8 nsect; /* Interrupt reason */
+ u8 lbal;
+ u8 lbam;
+ u8 lbah;
+ u8 device;
+ u8 status;
+ u8 alt_status; /* ATA CTL */
+ u8 hob_nsect;
+ u8 hob_lbal;
+ u8 hob_lbam;
+ u8 hob_lbah;
+}__attribute__((packed, aligned (4)));
+
struct ipr_auto_sense {
__be16 auto_sense_len;
__be16 ioa_data_len;
@@ -466,6 +520,7 @@ struct ipr_ioasa {
__be32 ioasc_specific; /* status code specific field */
#define IPR_ADDITIONAL_STATUS_FMT 0x80000000
#define IPR_AUTOSENSE_VALID 0x40000000
+#define IPR_ATA_DEVICE_WAS_RESET 0x20000000
#define IPR_IOASC_SPECIFIC_MASK 0x00ffffff
#define IPR_FIELD_POINTER_VALID (0x80000000 >> 8)
#define IPR_FIELD_POINTER_MASK 0x0000ffff
@@ -474,6 +529,7 @@ struct ipr_ioasa {
struct ipr_ioasa_vset vset;
struct ipr_ioasa_af_dasd dasd;
struct ipr_ioasa_gpdd gpdd;
+ struct ipr_ioasa_gata gata;
} u;
struct ipr_auto_sense auto_sense;
@@ -1308,6 +1364,22 @@ static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res)
}
/**
+ * ipr_is_gata - Determine if a resource is a generic ATA resource
+ * @res: resource entry struct
+ *
+ * Return value:
+ * 1 if GATA / 0 if not GATA
+ **/
+static inline int ipr_is_gata(struct ipr_resource_entry *res)
+{
+ if (!ipr_is_ioa_resource(res) &&
+ IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_ATA)
+ return 1;
+ else
+ return 0;
+}
+
+/**
* ipr_is_naca_model - Determine if a resource is using NACA queueing model
* @res: resource entry struct
*
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 5353b28b293..3c639286ec1 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -196,7 +196,6 @@
#include <linux/module.h>
#include <linux/stat.h>
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/init.h>
@@ -6438,7 +6437,7 @@ ips_erase_bios(ips_ha_t * ha)
/* VPP failure */
return (1);
- /* check for succesful flash */
+ /* check for successful flash */
if (status & 0x30)
/* sequence error */
return (1);
@@ -6550,7 +6549,7 @@ ips_erase_bios_memio(ips_ha_t * ha)
/* VPP failure */
return (1);
- /* check for succesful flash */
+ /* check for successful flash */
if (status & 0x30)
/* sequence error */
return (1);
@@ -7008,7 +7007,7 @@ ips_register_scsi(int index)
memcpy(ha, oldha, sizeof (ips_ha_t));
free_irq(oldha->irq, oldha);
/* Install the interrupt handler with the new ha */
- if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+ if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
IPS_PRINTK(KERN_WARNING, ha->pcidev,
"Unable to install interrupt handler\n");
scsi_host_put(sh);
@@ -7420,7 +7419,7 @@ ips_init_phase2(int index)
}
/* Install the interrupt handler */
- if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+ if (request_irq(ha->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) {
IPS_PRINTK(KERN_WARNING, ha->pcidev,
"Unable to install interrupt handler\n");
return ips_abort_init(ha, index);
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index b4743a9ecc8..0a9dbc59663 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -43,13 +43,10 @@
#include "iscsi_tcp.h"
-#define ISCSI_TCP_VERSION "1.0-595"
-
MODULE_AUTHOR("Dmitry Yusupov <dmitry_yus@yahoo.com>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI/TCP data-path");
MODULE_LICENSE("GPL");
-MODULE_VERSION(ISCSI_TCP_VERSION);
/* #define DEBUG_TCP */
#define DEBUG_ASSERT
@@ -111,8 +108,8 @@ iscsi_hdr_digest(struct iscsi_conn *conn, struct iscsi_buf *buf,
{
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- crypto_digest_digest(tcp_conn->tx_tfm, &buf->sg, 1, crc);
- buf->sg.length += sizeof(uint32_t);
+ crypto_hash_digest(&tcp_conn->tx_hash, &buf->sg, buf->sg.length, crc);
+ buf->sg.length = tcp_conn->hdr_size;
}
static inline int
@@ -185,11 +182,19 @@ iscsi_hdr_extract(struct iscsi_tcp_conn *tcp_conn)
* must be called with session lock
*/
static void
-__iscsi_ctask_cleanup(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ struct iscsi_r2t_info *r2t;
struct scsi_cmnd *sc;
+ /* flush ctask's r2t queues */
+ while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
+ __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ sizeof(void*));
+ debug_scsi("iscsi_tcp_cleanup_ctask pending r2t dropped\n");
+ }
+
sc = ctask->sc;
if (unlikely(!sc))
return;
@@ -276,7 +281,6 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
{
struct iscsi_data *hdr;
struct scsi_cmnd *sc = ctask->sc;
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
hdr = &r2t->dtask.hdr;
memset(hdr, 0, sizeof(struct iscsi_data));
@@ -331,10 +335,12 @@ iscsi_solicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
sg_count += sg->length;
}
BUG_ON(r2t->sg == NULL);
- } else
- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
+ } else {
+ iscsi_buf_init_iov(&r2t->sendbuf,
(char*)sc->request_buffer + r2t->data_offset,
r2t->data_count);
+ r2t->sg = NULL;
+ }
}
/**
@@ -353,8 +359,11 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
int r2tsn = be32_to_cpu(rhdr->r2tsn);
int rc;
- if (tcp_conn->in.datalen)
+ if (tcp_conn->in.datalen) {
+ printk(KERN_ERR "iscsi_tcp: invalid R2t with datalen %d\n",
+ tcp_conn->in.datalen);
return ISCSI_ERR_DATALEN;
+ }
if (tcp_ctask->exp_r2tsn && tcp_ctask->exp_r2tsn != r2tsn)
return ISCSI_ERR_R2TSN;
@@ -374,20 +383,29 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
spin_unlock(&session->lock);
return 0;
}
+
rc = __kfifo_get(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
BUG_ON(!rc);
r2t->exp_statsn = rhdr->statsn;
r2t->data_length = be32_to_cpu(rhdr->data_length);
- if (r2t->data_length == 0 ||
- r2t->data_length > session->max_burst) {
+ if (r2t->data_length == 0) {
+ printk(KERN_ERR "iscsi_tcp: invalid R2T with zero data len\n");
spin_unlock(&session->lock);
return ISCSI_ERR_DATALEN;
}
+ if (r2t->data_length > session->max_burst)
+ debug_scsi("invalid R2T with data len %u and max burst %u."
+ "Attempting to execute request.\n",
+ r2t->data_length, session->max_burst);
+
r2t->data_offset = be32_to_cpu(rhdr->data_offset);
if (r2t->data_offset + r2t->data_length > ctask->total_length) {
spin_unlock(&session->lock);
+ printk(KERN_ERR "iscsi_tcp: invalid R2T with data len %u at "
+ "offset %u and total length %d\n", r2t->data_length,
+ r2t->data_offset, ctask->total_length);
return ISCSI_ERR_DATALEN;
}
@@ -399,7 +417,7 @@ iscsi_r2t_rsp(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
tcp_ctask->exp_r2tsn = r2tsn + 1;
tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
__kfifo_put(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*));
- __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
+ list_move_tail(&ctask->running, &conn->xmitqueue);
scsi_queue_work(session->host, &conn->xmitwork);
conn->r2t_pdus_cnt++;
@@ -450,7 +468,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
sg_init_one(&sg, (u8 *)hdr,
sizeof(struct iscsi_hdr) + ahslen);
- crypto_digest_digest(tcp_conn->rx_tfm, &sg, 1, (u8 *)&cdgst);
+ crypto_hash_digest(&tcp_conn->rx_hash, &sg, sg.length,
+ (u8 *)&cdgst);
rdgst = *(uint32_t*)((char*)hdr + sizeof(struct iscsi_hdr) +
ahslen);
if (cdgst != rdgst) {
@@ -477,6 +496,8 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
case ISCSI_OP_SCSI_DATA_IN:
tcp_conn->in.ctask = session->cmds[itt];
rc = iscsi_data_rsp(conn, tcp_conn->in.ctask);
+ if (rc)
+ return rc;
/* fall through */
case ISCSI_OP_SCSI_CMD_RSP:
tcp_conn->in.ctask = session->cmds[itt];
@@ -484,7 +505,6 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
goto copy_hdr;
spin_lock(&session->lock);
- __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask);
rc = __iscsi_complete_pdu(conn, hdr, NULL, 0);
spin_unlock(&session->lock);
break;
@@ -500,13 +520,28 @@ iscsi_tcp_hdr_recv(struct iscsi_conn *conn)
break;
case ISCSI_OP_LOGIN_RSP:
case ISCSI_OP_TEXT_RSP:
- case ISCSI_OP_LOGOUT_RSP:
- case ISCSI_OP_NOOP_IN:
case ISCSI_OP_REJECT:
case ISCSI_OP_ASYNC_EVENT:
+ /*
+ * It is possible that we could get a PDU with a buffer larger
+ * than 8K, but there are no targets that currently do this.
+ * For now we fail until we find a vendor that needs it
+ */
+ if (DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH <
+ tcp_conn->in.datalen) {
+ printk(KERN_ERR "iscsi_tcp: received buffer of len %u "
+ "but conn buffer is only %u (opcode %0x)\n",
+ tcp_conn->in.datalen,
+ DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, opcode);
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
+
if (tcp_conn->in.datalen)
goto copy_hdr;
/* fall through */
+ case ISCSI_OP_LOGOUT_RSP:
+ case ISCSI_OP_NOOP_IN:
case ISCSI_OP_SCSI_TMFUNC_RSP:
rc = iscsi_complete_pdu(conn, hdr, NULL, 0);
break;
@@ -523,7 +558,7 @@ copy_hdr:
* skbs to complete the command then we have to copy the header
* for later use
*/
- if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <
+ if (tcp_conn->in.zero_copy_hdr && tcp_conn->in.copy <=
(tcp_conn->in.datalen + tcp_conn->in.padding +
(conn->datadgst_en ? 4 : 0))) {
debug_tcp("Copying header for later use. in.copy %d in.datalen"
@@ -614,10 +649,9 @@ iscsi_ctask_copy(struct iscsi_tcp_conn *tcp_conn, struct iscsi_cmd_task *ctask,
* byte counters.
**/
static inline int
-iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
+iscsi_tcp_copy(struct iscsi_conn *conn, int buf_size)
{
- void *buf = tcp_conn->data;
- int buf_size = tcp_conn->in.datalen;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
int buf_left = buf_size - tcp_conn->data_copied;
int size = min(tcp_conn->in.copy, buf_left);
int rc;
@@ -627,7 +661,7 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
BUG_ON(size <= 0);
rc = skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
- (char*)buf + tcp_conn->data_copied, size);
+ (char*)conn->data + tcp_conn->data_copied, size);
BUG_ON(rc);
tcp_conn->in.offset += size;
@@ -642,15 +676,15 @@ iscsi_tcp_copy(struct iscsi_tcp_conn *tcp_conn)
}
static inline void
-partial_sg_digest_update(struct iscsi_tcp_conn *tcp_conn,
- struct scatterlist *sg, int offset, int length)
+partial_sg_digest_update(struct hash_desc *desc, struct scatterlist *sg,
+ int offset, int length)
{
struct scatterlist temp;
memcpy(&temp, sg, sizeof(struct scatterlist));
temp.offset = offset;
temp.length = length;
- crypto_digest_update(tcp_conn->data_rx_tfm, &temp, 1);
+ crypto_hash_update(desc, &temp, length);
}
static void
@@ -659,7 +693,7 @@ iscsi_recv_digest_update(struct iscsi_tcp_conn *tcp_conn, char* buf, int len)
struct scatterlist tmp;
sg_init_one(&tmp, buf, len);
- crypto_digest_update(tcp_conn->data_rx_tfm, &tmp, 1);
+ crypto_hash_update(&tcp_conn->rx_hash, &tmp, len);
}
static int iscsi_scsi_data_in(struct iscsi_conn *conn)
@@ -713,11 +747,12 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
if (!rc) {
if (conn->datadgst_en) {
if (!offset)
- crypto_digest_update(
- tcp_conn->data_rx_tfm,
+ crypto_hash_update(
+ &tcp_conn->rx_hash,
&sg[i], 1);
else
- partial_sg_digest_update(tcp_conn,
+ partial_sg_digest_update(
+ &tcp_conn->rx_hash,
&sg[i],
sg[i].offset + offset,
sg[i].length - offset);
@@ -731,8 +766,10 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
/*
* data-in is complete, but buffer not...
*/
- partial_sg_digest_update(tcp_conn, &sg[i],
- sg[i].offset, sg[i].length-rc);
+ partial_sg_digest_update(&tcp_conn->rx_hash,
+ &sg[i],
+ sg[i].offset,
+ sg[i].length-rc);
rc = 0;
break;
}
@@ -745,10 +782,10 @@ static int iscsi_scsi_data_in(struct iscsi_conn *conn)
done:
/* check for non-exceptional status */
if (tcp_conn->in.hdr->flags & ISCSI_FLAG_DATA_STATUS) {
- debug_scsi("done [sc %lx res %d itt 0x%x]\n",
- (long)sc, sc->result, ctask->itt);
+ debug_scsi("done [sc %lx res %d itt 0x%x flags 0x%x]\n",
+ (long)sc, sc->result, ctask->itt,
+ tcp_conn->in.hdr->flags);
spin_lock(&conn->session->lock);
- __iscsi_ctask_cleanup(conn, ctask);
__iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0);
spin_unlock(&conn->session->lock);
}
@@ -768,27 +805,23 @@ iscsi_data_recv(struct iscsi_conn *conn)
rc = iscsi_scsi_data_in(conn);
break;
case ISCSI_OP_SCSI_CMD_RSP:
- spin_lock(&conn->session->lock);
- __iscsi_ctask_cleanup(conn, tcp_conn->in.ctask);
- spin_unlock(&conn->session->lock);
case ISCSI_OP_TEXT_RSP:
case ISCSI_OP_LOGIN_RSP:
- case ISCSI_OP_NOOP_IN:
case ISCSI_OP_ASYNC_EVENT:
case ISCSI_OP_REJECT:
/*
* Collect data segment to the connection's data
* placeholder
*/
- if (iscsi_tcp_copy(tcp_conn)) {
+ if (iscsi_tcp_copy(conn, tcp_conn->in.datalen)) {
rc = -EAGAIN;
goto exit;
}
- rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, tcp_conn->data,
+ rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, conn->data,
tcp_conn->in.datalen);
if (!rc && conn->datadgst_en && opcode != ISCSI_OP_LOGIN_RSP)
- iscsi_recv_digest_update(tcp_conn, tcp_conn->data,
+ iscsi_recv_digest_update(tcp_conn, conn->data,
tcp_conn->in.datalen);
break;
default:
@@ -843,7 +876,7 @@ more:
if (rc == -EAGAIN)
goto nomore;
else {
- iscsi_conn_failure(conn, rc);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return 0;
}
}
@@ -853,10 +886,8 @@ more:
*/
rc = iscsi_tcp_hdr_recv(conn);
if (!rc && tcp_conn->in.datalen) {
- if (conn->datadgst_en) {
- BUG_ON(!tcp_conn->data_rx_tfm);
- crypto_digest_init(tcp_conn->data_rx_tfm);
- }
+ if (conn->datadgst_en)
+ crypto_hash_init(&tcp_conn->rx_hash);
tcp_conn->in_progress = IN_PROGRESS_DATA_RECV;
} else if (rc) {
iscsi_conn_failure(conn, rc);
@@ -869,10 +900,15 @@ more:
debug_tcp("extra data_recv offset %d copy %d\n",
tcp_conn->in.offset, tcp_conn->in.copy);
- skb_copy_bits(tcp_conn->in.skb, tcp_conn->in.offset,
- &recv_digest, 4);
- tcp_conn->in.offset += 4;
- tcp_conn->in.copy -= 4;
+ rc = iscsi_tcp_copy(conn, sizeof(uint32_t));
+ if (rc) {
+ if (rc == -EAGAIN)
+ goto again;
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+ return 0;
+ }
+
+ memcpy(&recv_digest, conn->data, sizeof(uint32_t));
if (recv_digest != tcp_conn->in.datadgst) {
debug_tcp("iscsi_tcp: data digest error!"
"0x%x != 0x%x\n", recv_digest,
@@ -897,7 +933,7 @@ more:
if (rc) {
if (rc == -EAGAIN)
goto again;
- iscsi_conn_failure(conn, rc);
+ iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
return 0;
}
tcp_conn->in.copy -= tcp_conn->in.padding;
@@ -908,13 +944,14 @@ more:
tcp_conn->in.padding);
memset(pad, 0, tcp_conn->in.padding);
sg_init_one(&sg, pad, tcp_conn->in.padding);
- crypto_digest_update(tcp_conn->data_rx_tfm,
- &sg, 1);
+ crypto_hash_update(&tcp_conn->rx_hash,
+ &sg, sg.length);
}
- crypto_digest_final(tcp_conn->data_rx_tfm,
- (u8 *) & tcp_conn->in.datadgst);
+ crypto_hash_final(&tcp_conn->rx_hash,
+ (u8 *) &tcp_conn->in.datadgst);
debug_tcp("rx digest 0x%x\n", tcp_conn->in.datadgst);
tcp_conn->in_progress = IN_PROGRESS_DDIGEST_RECV;
+ tcp_conn->data_copied = 0;
} else
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
}
@@ -1028,9 +1065,8 @@ iscsi_conn_set_callbacks(struct iscsi_conn *conn)
}
static void
-iscsi_conn_restore_callbacks(struct iscsi_conn *conn)
+iscsi_conn_restore_callbacks(struct iscsi_tcp_conn *tcp_conn)
{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct sock *sk = tcp_conn->sock->sk;
/* restore socket callbacks, see also: iscsi_conn_set_callbacks() */
@@ -1155,37 +1191,12 @@ iscsi_sendpage(struct iscsi_conn *conn, struct iscsi_buf *buf,
static inline void
iscsi_data_digest_init(struct iscsi_tcp_conn *tcp_conn,
- struct iscsi_cmd_task *ctask)
+ struct iscsi_tcp_cmd_task *tcp_ctask)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
-
- BUG_ON(!tcp_conn->data_tx_tfm);
- crypto_digest_init(tcp_conn->data_tx_tfm);
+ crypto_hash_init(&tcp_conn->tx_hash);
tcp_ctask->digest_count = 4;
}
-static int
-iscsi_digest_final_send(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
- struct iscsi_buf *buf, uint32_t *digest, int final)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- int rc = 0;
- int sent = 0;
-
- if (final)
- crypto_digest_final(tcp_conn->data_tx_tfm, (u8*)digest);
-
- iscsi_buf_init_iov(buf, (char*)digest, 4);
- rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
- if (rc) {
- tcp_ctask->datadigest = *digest;
- tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
- } else
- tcp_ctask->digest_count = 4;
- return rc;
-}
-
/**
* iscsi_solicit_data_cont - initialize next Data-Out
* @conn: iscsi connection
@@ -1203,7 +1214,6 @@ static void
iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
struct iscsi_r2t_info *r2t, int left)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data *hdr;
struct scsi_cmnd *sc = ctask->sc;
int new_offset;
@@ -1232,27 +1242,30 @@ iscsi_solicit_data_cont(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
iscsi_buf_init_iov(&r2t->headbuf, (char*)hdr,
sizeof(struct iscsi_hdr));
- if (sc->use_sg && !iscsi_buf_left(&r2t->sendbuf)) {
- BUG_ON(tcp_ctask->bad_sg == r2t->sg);
+ if (iscsi_buf_left(&r2t->sendbuf))
+ return;
+
+ if (sc->use_sg) {
iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
r2t->sg += 1;
- } else
- iscsi_buf_init_iov(&tcp_ctask->sendbuf,
+ } else {
+ iscsi_buf_init_iov(&r2t->sendbuf,
(char*)sc->request_buffer + new_offset,
r2t->data_count);
+ r2t->sg = NULL;
+ }
}
-static void
-iscsi_unsolicit_data_init(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static void iscsi_set_padding(struct iscsi_tcp_cmd_task *tcp_ctask,
+ unsigned long len)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_data_task *dtask;
+ tcp_ctask->pad_count = len & (ISCSI_PAD_LEN - 1);
+ if (!tcp_ctask->pad_count)
+ return;
- dtask = tcp_ctask->dtask = &tcp_ctask->unsol_dtask;
- iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr,
- tcp_ctask->r2t_data_count);
- iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
- sizeof(struct iscsi_hdr));
+ tcp_ctask->pad_count = ISCSI_PAD_LEN - tcp_ctask->pad_count;
+ debug_scsi("write padding %d bytes\n", tcp_ctask->pad_count);
+ tcp_ctask->xmstate |= XMSTATE_W_PAD;
}
/**
@@ -1280,38 +1293,20 @@ iscsi_tcp_cmd_init(struct iscsi_cmd_task *ctask)
if (sc->use_sg) {
struct scatterlist *sg = sc->request_buffer;
- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
- &sg[tcp_ctask->sg_count++]);
- tcp_ctask->sg = sg;
+ iscsi_buf_init_sg(&tcp_ctask->sendbuf, sg);
+ tcp_ctask->sg = sg + 1;
tcp_ctask->bad_sg = sg + sc->use_sg;
- } else
+ } else {
iscsi_buf_init_iov(&tcp_ctask->sendbuf,
sc->request_buffer,
sc->request_bufflen);
-
- if (ctask->imm_count)
- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
-
- tcp_ctask->pad_count = ctask->total_length & (ISCSI_PAD_LEN-1);
- if (tcp_ctask->pad_count) {
- tcp_ctask->pad_count = ISCSI_PAD_LEN -
- tcp_ctask->pad_count;
- debug_scsi("write padding %d bytes\n",
- tcp_ctask->pad_count);
- tcp_ctask->xmstate |= XMSTATE_W_PAD;
+ tcp_ctask->sg = NULL;
+ tcp_ctask->bad_sg = NULL;
}
-
- if (ctask->unsol_count)
- tcp_ctask->xmstate |= XMSTATE_UNS_HDR |
- XMSTATE_UNS_INIT;
- tcp_ctask->r2t_data_count = ctask->total_length -
- ctask->imm_count -
- ctask->unsol_count;
-
- debug_scsi("cmd [itt %x total %d imm %d imm_data %d "
- "r2t_data %d]\n",
+ debug_scsi("cmd [itt 0x%x total %d imm_data %d "
+ "unsol count %d, unsol offset %d]\n",
ctask->itt, ctask->total_length, ctask->imm_count,
- ctask->unsol_count, tcp_ctask->r2t_data_count);
+ ctask->unsol_count, ctask->unsol_offset);
} else
tcp_ctask->xmstate = XMSTATE_R_HDR;
@@ -1393,8 +1388,8 @@ iscsi_tcp_mtask_xmit(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask)
}
static inline int
-handle_xmstate_r_hdr(struct iscsi_conn *conn,
- struct iscsi_tcp_cmd_task *tcp_ctask)
+iscsi_send_read_hdr(struct iscsi_conn *conn,
+ struct iscsi_tcp_cmd_task *tcp_ctask)
{
int rc;
@@ -1412,7 +1407,7 @@ handle_xmstate_r_hdr(struct iscsi_conn *conn,
}
static inline int
-handle_xmstate_w_hdr(struct iscsi_conn *conn,
+iscsi_send_write_hdr(struct iscsi_conn *conn,
struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
@@ -1423,85 +1418,126 @@ handle_xmstate_w_hdr(struct iscsi_conn *conn,
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)tcp_ctask->hdrext);
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->imm_count);
- if (rc)
+ if (rc) {
tcp_ctask->xmstate |= XMSTATE_W_HDR;
- return rc;
+ return rc;
+ }
+
+ if (ctask->imm_count) {
+ tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
+ iscsi_set_padding(tcp_ctask, ctask->imm_count);
+
+ if (ctask->conn->datadgst_en) {
+ iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
+ tcp_ctask->immdigest = 0;
+ }
+ }
+
+ if (ctask->unsol_count)
+ tcp_ctask->xmstate |= XMSTATE_UNS_HDR | XMSTATE_UNS_INIT;
+ return 0;
}
-static inline int
-handle_xmstate_data_digest(struct iscsi_conn *conn,
- struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_padding(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- int rc;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int sent = 0, rc;
- tcp_ctask->xmstate &= ~XMSTATE_DATA_DIGEST;
- debug_tcp("resent data digest 0x%x\n", tcp_ctask->datadigest);
- rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
- &tcp_ctask->datadigest, 0);
+ if (tcp_ctask->xmstate & XMSTATE_W_PAD) {
+ iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
+ tcp_ctask->pad_count);
+ if (conn->datadgst_en)
+ crypto_hash_update(&tcp_conn->tx_hash,
+ &tcp_ctask->sendbuf.sg,
+ tcp_ctask->sendbuf.sg.length);
+ } else if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_PAD))
+ return 0;
+
+ tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
+ tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_PAD;
+ debug_scsi("sending %d pad bytes for itt 0x%x\n",
+ tcp_ctask->pad_count, ctask->itt);
+ rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
+ &sent);
if (rc) {
- tcp_ctask->xmstate |= XMSTATE_DATA_DIGEST;
- debug_tcp("resent data digest 0x%x fail!\n",
- tcp_ctask->datadigest);
+ debug_scsi("padding send failed %d\n", rc);
+ tcp_ctask->xmstate |= XMSTATE_W_RESEND_PAD;
}
-
return rc;
}
-static inline int
-handle_xmstate_imm_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_digest(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
+ struct iscsi_buf *buf, uint32_t *digest)
{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- int rc;
+ struct iscsi_tcp_cmd_task *tcp_ctask;
+ struct iscsi_tcp_conn *tcp_conn;
+ int rc, sent = 0;
- BUG_ON(!ctask->imm_count);
- tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
+ if (!conn->datadgst_en)
+ return 0;
- if (conn->datadgst_en) {
- iscsi_data_digest_init(tcp_conn, ctask);
- tcp_ctask->immdigest = 0;
- }
+ tcp_ctask = ctask->dd_data;
+ tcp_conn = conn->dd_data;
- for (;;) {
- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
- &ctask->imm_count, &tcp_ctask->sent);
- if (rc) {
- tcp_ctask->xmstate |= XMSTATE_IMM_DATA;
- if (conn->datadgst_en) {
- crypto_digest_final(tcp_conn->data_tx_tfm,
- (u8*)&tcp_ctask->immdigest);
- debug_tcp("tx imm sendpage fail 0x%x\n",
- tcp_ctask->datadigest);
- }
- return rc;
- }
- if (conn->datadgst_en)
- crypto_digest_update(tcp_conn->data_tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
+ if (!(tcp_ctask->xmstate & XMSTATE_W_RESEND_DATA_DIGEST)) {
+ crypto_hash_final(&tcp_conn->tx_hash, (u8*)digest);
+ iscsi_buf_init_iov(buf, (char*)digest, 4);
+ }
+ tcp_ctask->xmstate &= ~XMSTATE_W_RESEND_DATA_DIGEST;
- if (!ctask->imm_count)
- break;
- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
- &tcp_ctask->sg[tcp_ctask->sg_count++]);
+ rc = iscsi_sendpage(conn, buf, &tcp_ctask->digest_count, &sent);
+ if (!rc)
+ debug_scsi("sent digest 0x%x for itt 0x%x\n", *digest,
+ ctask->itt);
+ else {
+ debug_scsi("sending digest 0x%x failed for itt 0x%x!\n",
+ *digest, ctask->itt);
+ tcp_ctask->xmstate |= XMSTATE_W_RESEND_DATA_DIGEST;
}
+ return rc;
+}
- if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
- rc = iscsi_digest_final_send(conn, ctask, &tcp_ctask->immbuf,
- &tcp_ctask->immdigest, 1);
- if (rc) {
- debug_tcp("sending imm digest 0x%x fail!\n",
- tcp_ctask->immdigest);
- return rc;
+static int
+iscsi_send_data(struct iscsi_cmd_task *ctask, struct iscsi_buf *sendbuf,
+ struct scatterlist **sg, int *sent, int *count,
+ struct iscsi_buf *digestbuf, uint32_t *digest)
+{
+ struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
+ struct iscsi_conn *conn = ctask->conn;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int rc, buf_sent, offset;
+
+ while (*count) {
+ buf_sent = 0;
+ offset = sendbuf->sent;
+
+ rc = iscsi_sendpage(conn, sendbuf, count, &buf_sent);
+ *sent = *sent + buf_sent;
+ if (buf_sent && conn->datadgst_en)
+ partial_sg_digest_update(&tcp_conn->tx_hash,
+ &sendbuf->sg, sendbuf->sg.offset + offset,
+ buf_sent);
+ if (!iscsi_buf_left(sendbuf) && *sg != tcp_ctask->bad_sg) {
+ iscsi_buf_init_sg(sendbuf, *sg);
+ *sg = *sg + 1;
}
- debug_tcp("sending imm digest 0x%x\n", tcp_ctask->immdigest);
+
+ if (rc)
+ return rc;
}
- return 0;
+ rc = iscsi_send_padding(conn, ctask);
+ if (rc)
+ return rc;
+
+ return iscsi_send_digest(conn, ctask, digestbuf, digest);
}
-static inline int
-handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_unsol_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
struct iscsi_data_task *dtask;
@@ -1509,12 +1545,17 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
if (tcp_ctask->xmstate & XMSTATE_UNS_INIT) {
- iscsi_unsolicit_data_init(conn, ctask);
- dtask = tcp_ctask->dtask;
+ dtask = &tcp_ctask->unsol_dtask;
+
+ iscsi_prep_unsolicit_data_pdu(ctask, &dtask->hdr);
+ iscsi_buf_init_iov(&tcp_ctask->headbuf, (char*)&dtask->hdr,
+ sizeof(struct iscsi_hdr));
if (conn->hdrdgst_en)
iscsi_hdr_digest(conn, &tcp_ctask->headbuf,
(u8*)dtask->hdrext);
+
tcp_ctask->xmstate &= ~XMSTATE_UNS_INIT;
+ iscsi_set_padding(tcp_ctask, ctask->data_count);
}
rc = iscsi_sendhdr(conn, &tcp_ctask->headbuf, ctask->data_count);
@@ -1524,254 +1565,138 @@ handle_xmstate_uns_hdr(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
return rc;
}
+ if (conn->datadgst_en) {
+ dtask = &tcp_ctask->unsol_dtask;
+ iscsi_data_digest_init(ctask->conn->dd_data, tcp_ctask);
+ dtask->digest = 0;
+ }
+
debug_scsi("uns dout [itt 0x%x dlen %d sent %d]\n",
ctask->itt, ctask->unsol_count, tcp_ctask->sent);
return 0;
}
-static inline int
-handle_xmstate_uns_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int
+iscsi_send_unsol_pdu(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
{
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_data_task *dtask = tcp_ctask->dtask;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
int rc;
- BUG_ON(!ctask->data_count);
- tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
-
- if (conn->datadgst_en) {
- iscsi_data_digest_init(tcp_conn, ctask);
- dtask->digest = 0;
+ if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
+ BUG_ON(!ctask->unsol_count);
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
+send_hdr:
+ rc = iscsi_send_unsol_hdr(conn, ctask);
+ if (rc)
+ return rc;
}
- for (;;) {
+ if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
+ struct iscsi_data_task *dtask = &tcp_ctask->unsol_dtask;
int start = tcp_ctask->sent;
- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf,
- &ctask->data_count, &tcp_ctask->sent);
- if (rc) {
- ctask->unsol_count -= tcp_ctask->sent - start;
- tcp_ctask->xmstate |= XMSTATE_UNS_DATA;
- /* will continue with this ctask later.. */
- if (conn->datadgst_en) {
- crypto_digest_final(tcp_conn->data_tx_tfm,
- (u8 *)&dtask->digest);
- debug_tcp("tx uns data fail 0x%x\n",
- dtask->digest);
- }
- return rc;
- }
-
- BUG_ON(tcp_ctask->sent > ctask->total_length);
+ rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
+ &tcp_ctask->sent, &ctask->data_count,
+ &dtask->digestbuf, &dtask->digest);
ctask->unsol_count -= tcp_ctask->sent - start;
-
+ if (rc)
+ return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_UNS_DATA;
/*
- * XXX:we may run here with un-initial sendbuf.
- * so pass it
+ * Done with the Data-Out. Next, check if we need
+ * to send another unsolicited Data-Out.
*/
- if (conn->datadgst_en && tcp_ctask->sent - start > 0)
- crypto_digest_update(tcp_conn->data_tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
-
- if (!ctask->data_count)
- break;
- iscsi_buf_init_sg(&tcp_ctask->sendbuf,
- &tcp_ctask->sg[tcp_ctask->sg_count++]);
- }
- BUG_ON(ctask->unsol_count < 0);
-
- /*
- * Done with the Data-Out. Next, check if we need
- * to send another unsolicited Data-Out.
- */
- if (ctask->unsol_count) {
- if (conn->datadgst_en) {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send uns digest 0x%x fail\n",
- dtask->digest);
- return rc;
- }
- debug_tcp("sending uns digest 0x%x, more uns\n",
- dtask->digest);
+ if (ctask->unsol_count) {
+ debug_scsi("sending more uns\n");
+ tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
+ goto send_hdr;
}
- tcp_ctask->xmstate |= XMSTATE_UNS_INIT;
- return 1;
}
-
- if (conn->datadgst_en && !(tcp_ctask->xmstate & XMSTATE_W_PAD)) {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send last uns digest 0x%x fail\n",
- dtask->digest);
- return rc;
- }
- debug_tcp("sending uns digest 0x%x\n",dtask->digest);
- }
-
return 0;
}
-static inline int
-handle_xmstate_sol_data(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
+static int iscsi_send_sol_pdu(struct iscsi_conn *conn,
+ struct iscsi_cmd_task *ctask)
{
- struct iscsi_session *session = conn->session;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_r2t_info *r2t = tcp_ctask->r2t;
- struct iscsi_data_task *dtask = &r2t->dtask;
+ struct iscsi_session *session = conn->session;
+ struct iscsi_r2t_info *r2t;
+ struct iscsi_data_task *dtask;
int left, rc;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->dtask = dtask;
-
- if (conn->datadgst_en) {
- iscsi_data_digest_init(tcp_conn, ctask);
- dtask->digest = 0;
- }
-solicit_again:
- /*
- * send Data-Out whitnin this R2T sequence.
- */
- if (!r2t->data_count)
- goto data_out_done;
-
- rc = iscsi_sendpage(conn, &r2t->sendbuf, &r2t->data_count, &r2t->sent);
- if (rc) {
+ if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- /* will continue with this ctask later.. */
- if (conn->datadgst_en) {
- crypto_digest_final(tcp_conn->data_tx_tfm,
- (u8 *)&dtask->digest);
- debug_tcp("r2t data send fail 0x%x\n", dtask->digest);
- }
- return rc;
- }
+ if (!tcp_ctask->r2t)
+ __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
+ sizeof(void*));
+send_hdr:
+ r2t = tcp_ctask->r2t;
+ dtask = &r2t->dtask;
- BUG_ON(r2t->data_count < 0);
- if (conn->datadgst_en)
- crypto_digest_update(tcp_conn->data_tx_tfm, &r2t->sendbuf.sg,
- 1);
-
- if (r2t->data_count) {
- BUG_ON(ctask->sc->use_sg == 0);
- if (!iscsi_buf_left(&r2t->sendbuf)) {
- BUG_ON(tcp_ctask->bad_sg == r2t->sg);
- iscsi_buf_init_sg(&r2t->sendbuf, r2t->sg);
- r2t->sg += 1;
+ if (conn->hdrdgst_en)
+ iscsi_hdr_digest(conn, &r2t->headbuf,
+ (u8*)dtask->hdrext);
+ rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
+ if (rc) {
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
+ tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
+ return rc;
}
- goto solicit_again;
- }
-data_out_done:
- /*
- * Done with this Data-Out. Next, check if we have
- * to send another Data-Out for this R2T.
- */
- BUG_ON(r2t->data_length - r2t->sent < 0);
- left = r2t->data_length - r2t->sent;
- if (left) {
if (conn->datadgst_en) {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send r2t data digest 0x%x"
- "fail\n", dtask->digest);
- return rc;
- }
- debug_tcp("r2t data send digest 0x%x\n",
- dtask->digest);
+ iscsi_data_digest_init(conn->dd_data, tcp_ctask);
+ dtask->digest = 0;
}
- iscsi_solicit_data_cont(conn, ctask, r2t, left);
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- return 1;
- }
-
- /*
- * Done with this R2T. Check if there are more
- * outstanding R2Ts ready to be processed.
- */
- BUG_ON(tcp_ctask->r2t_data_count - r2t->data_length < 0);
- if (conn->datadgst_en) {
- rc = iscsi_digest_final_send(conn, ctask, &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send last r2t data digest 0x%x"
- "fail\n", dtask->digest);
- return rc;
- }
- debug_tcp("r2t done dout digest 0x%x\n", dtask->digest);
- }
- tcp_ctask->r2t_data_count -= r2t->data_length;
- tcp_ctask->r2t = NULL;
- spin_lock_bh(&session->lock);
- __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t, sizeof(void*));
- spin_unlock_bh(&session->lock);
- if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*))) {
- tcp_ctask->r2t = r2t;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- return 1;
+ iscsi_set_padding(tcp_ctask, r2t->data_count);
+ debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
+ r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
+ r2t->sent);
}
- return 0;
-}
+ if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
+ r2t = tcp_ctask->r2t;
+ dtask = &r2t->dtask;
-static inline int
-handle_xmstate_w_pad(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct iscsi_data_task *dtask = tcp_ctask->dtask;
- int sent, rc;
+ rc = iscsi_send_data(ctask, &r2t->sendbuf, &r2t->sg,
+ &r2t->sent, &r2t->data_count,
+ &dtask->digestbuf, &dtask->digest);
+ if (rc)
+ return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->xmstate &= ~XMSTATE_W_PAD;
- iscsi_buf_init_iov(&tcp_ctask->sendbuf, (char*)&tcp_ctask->pad,
- tcp_ctask->pad_count);
- rc = iscsi_sendpage(conn, &tcp_ctask->sendbuf, &tcp_ctask->pad_count,
- &sent);
- if (rc) {
- tcp_ctask->xmstate |= XMSTATE_W_PAD;
- return rc;
- }
+ /*
+ * Done with this Data-Out. Next, check if we have
+ * to send another Data-Out for this R2T.
+ */
+ BUG_ON(r2t->data_length - r2t->sent < 0);
+ left = r2t->data_length - r2t->sent;
+ if (left) {
+ iscsi_solicit_data_cont(conn, ctask, r2t, left);
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ goto send_hdr;
+ }
- if (conn->datadgst_en) {
- crypto_digest_update(tcp_conn->data_tx_tfm,
- &tcp_ctask->sendbuf.sg, 1);
- /* imm data? */
- if (!dtask) {
- rc = iscsi_digest_final_send(conn, ctask,
- &tcp_ctask->immbuf,
- &tcp_ctask->immdigest, 1);
- if (rc) {
- debug_tcp("send padding digest 0x%x"
- "fail!\n", tcp_ctask->immdigest);
- return rc;
- }
- debug_tcp("done with padding, digest 0x%x\n",
- tcp_ctask->datadigest);
- } else {
- rc = iscsi_digest_final_send(conn, ctask,
- &dtask->digestbuf,
- &dtask->digest, 1);
- if (rc) {
- debug_tcp("send padding digest 0x%x"
- "fail\n", dtask->digest);
- return rc;
- }
- debug_tcp("done with padding, digest 0x%x\n",
- dtask->digest);
+ /*
+ * Done with this R2T. Check if there are more
+ * outstanding R2Ts ready to be processed.
+ */
+ spin_lock_bh(&session->lock);
+ tcp_ctask->r2t = NULL;
+ __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
+ sizeof(void*));
+ if (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t,
+ sizeof(void*))) {
+ tcp_ctask->r2t = r2t;
+ tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
+ tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
+ spin_unlock_bh(&session->lock);
+ goto send_hdr;
}
+ spin_unlock_bh(&session->lock);
}
-
return 0;
}
@@ -1791,85 +1716,30 @@ iscsi_tcp_ctask_xmit(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
return rc;
if (tcp_ctask->xmstate & XMSTATE_R_HDR)
- return handle_xmstate_r_hdr(conn, tcp_ctask);
+ return iscsi_send_read_hdr(conn, tcp_ctask);
if (tcp_ctask->xmstate & XMSTATE_W_HDR) {
- rc = handle_xmstate_w_hdr(conn, ctask);
- if (rc)
- return rc;
- }
-
- /* XXX: for data digest xmit recover */
- if (tcp_ctask->xmstate & XMSTATE_DATA_DIGEST) {
- rc = handle_xmstate_data_digest(conn, ctask);
+ rc = iscsi_send_write_hdr(conn, ctask);
if (rc)
return rc;
}
if (tcp_ctask->xmstate & XMSTATE_IMM_DATA) {
- rc = handle_xmstate_imm_data(conn, ctask);
+ rc = iscsi_send_data(ctask, &tcp_ctask->sendbuf, &tcp_ctask->sg,
+ &tcp_ctask->sent, &ctask->imm_count,
+ &tcp_ctask->immbuf, &tcp_ctask->immdigest);
if (rc)
return rc;
+ tcp_ctask->xmstate &= ~XMSTATE_IMM_DATA;
}
- if (tcp_ctask->xmstate & XMSTATE_UNS_HDR) {
- BUG_ON(!ctask->unsol_count);
- tcp_ctask->xmstate &= ~XMSTATE_UNS_HDR;
-unsolicit_head_again:
- rc = handle_xmstate_uns_hdr(conn, ctask);
- if (rc)
- return rc;
- }
-
- if (tcp_ctask->xmstate & XMSTATE_UNS_DATA) {
- rc = handle_xmstate_uns_data(conn, ctask);
- if (rc == 1)
- goto unsolicit_head_again;
- else if (rc)
- return rc;
- goto done;
- }
-
- if (tcp_ctask->xmstate & XMSTATE_SOL_HDR) {
- struct iscsi_r2t_info *r2t;
-
- tcp_ctask->xmstate &= ~XMSTATE_SOL_HDR;
- tcp_ctask->xmstate |= XMSTATE_SOL_DATA;
- if (!tcp_ctask->r2t)
- __kfifo_get(tcp_ctask->r2tqueue, (void*)&tcp_ctask->r2t,
- sizeof(void*));
-solicit_head_again:
- r2t = tcp_ctask->r2t;
- if (conn->hdrdgst_en)
- iscsi_hdr_digest(conn, &r2t->headbuf,
- (u8*)r2t->dtask.hdrext);
- rc = iscsi_sendhdr(conn, &r2t->headbuf, r2t->data_count);
- if (rc) {
- tcp_ctask->xmstate &= ~XMSTATE_SOL_DATA;
- tcp_ctask->xmstate |= XMSTATE_SOL_HDR;
- return rc;
- }
-
- debug_scsi("sol dout [dsn %d itt 0x%x dlen %d sent %d]\n",
- r2t->solicit_datasn - 1, ctask->itt, r2t->data_count,
- r2t->sent);
- }
-
- if (tcp_ctask->xmstate & XMSTATE_SOL_DATA) {
- rc = handle_xmstate_sol_data(conn, ctask);
- if (rc == 1)
- goto solicit_head_again;
- if (rc)
- return rc;
- }
+ rc = iscsi_send_unsol_pdu(conn, ctask);
+ if (rc)
+ return rc;
-done:
- /*
- * Last thing to check is whether we need to send write
- * padding. Note that we check for xmstate equality, not just the bit.
- */
- if (tcp_ctask->xmstate == XMSTATE_W_PAD)
- rc = handle_xmstate_w_pad(conn, ctask);
+ rc = iscsi_send_sol_pdu(conn, ctask);
+ if (rc)
+ return rc;
return rc;
}
@@ -1900,20 +1770,24 @@ iscsi_tcp_conn_create(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
tcp_conn->in_progress = IN_PROGRESS_WAIT_HEADER;
/* initial operational parameters */
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
- tcp_conn->data_size = DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH;
- /* allocate initial PDU receive place holder */
- if (tcp_conn->data_size <= PAGE_SIZE)
- tcp_conn->data = kmalloc(tcp_conn->data_size, GFP_KERNEL);
- else
- tcp_conn->data = (void*)__get_free_pages(GFP_KERNEL,
- get_order(tcp_conn->data_size));
- if (!tcp_conn->data)
- goto max_recv_dlenght_alloc_fail;
+ tcp_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ CRYPTO_ALG_ASYNC);
+ tcp_conn->tx_hash.flags = 0;
+ if (!tcp_conn->tx_hash.tfm)
+ goto free_tcp_conn;
+
+ tcp_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0,
+ CRYPTO_ALG_ASYNC);
+ tcp_conn->rx_hash.flags = 0;
+ if (!tcp_conn->rx_hash.tfm)
+ goto free_tx_tfm;
return cls_conn;
-max_recv_dlenght_alloc_fail:
+free_tx_tfm:
+ crypto_free_hash(tcp_conn->tx_hash.tfm);
+free_tcp_conn:
kfree(tcp_conn);
tcp_conn_alloc_fail:
iscsi_conn_teardown(cls_conn);
@@ -1921,6 +1795,23 @@ tcp_conn_alloc_fail:
}
static void
+iscsi_tcp_release_conn(struct iscsi_conn *conn)
+{
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+ if (!tcp_conn->sock)
+ return;
+
+ sock_hold(tcp_conn->sock->sk);
+ iscsi_conn_restore_callbacks(tcp_conn);
+ sock_put(tcp_conn->sock->sk);
+
+ sock_release(tcp_conn->sock);
+ tcp_conn->sock = NULL;
+ conn->recv_lock = NULL;
+}
+
+static void
iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
{
struct iscsi_conn *conn = cls_conn->dd_data;
@@ -1930,29 +1821,31 @@ iscsi_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn)
if (conn->hdrdgst_en || conn->datadgst_en)
digest = 1;
+ iscsi_tcp_release_conn(conn);
iscsi_conn_teardown(cls_conn);
/* now free tcp_conn */
if (digest) {
- if (tcp_conn->tx_tfm)
- crypto_free_tfm(tcp_conn->tx_tfm);
- if (tcp_conn->rx_tfm)
- crypto_free_tfm(tcp_conn->rx_tfm);
- if (tcp_conn->data_tx_tfm)
- crypto_free_tfm(tcp_conn->data_tx_tfm);
- if (tcp_conn->data_rx_tfm)
- crypto_free_tfm(tcp_conn->data_rx_tfm);
+ if (tcp_conn->tx_hash.tfm)
+ crypto_free_hash(tcp_conn->tx_hash.tfm);
+ if (tcp_conn->rx_hash.tfm)
+ crypto_free_hash(tcp_conn->rx_hash.tfm);
}
- /* free conn->data, size = MaxRecvDataSegmentLength */
- if (tcp_conn->data_size <= PAGE_SIZE)
- kfree(tcp_conn->data);
- else
- free_pages((unsigned long)tcp_conn->data,
- get_order(tcp_conn->data_size));
kfree(tcp_conn);
}
+static void
+iscsi_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+
+ iscsi_conn_stop(cls_conn, flag);
+ iscsi_tcp_release_conn(conn);
+ tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
+}
+
static int
iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
struct iscsi_cls_conn *cls_conn, uint64_t transport_eph,
@@ -2001,52 +1894,6 @@ iscsi_tcp_conn_bind(struct iscsi_cls_session *cls_session,
return 0;
}
-static void
-iscsi_tcp_cleanup_ctask(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask)
-{
- struct iscsi_tcp_cmd_task *tcp_ctask = ctask->dd_data;
- struct iscsi_r2t_info *r2t;
-
- /* flush ctask's r2t queues */
- while (__kfifo_get(tcp_ctask->r2tqueue, (void*)&r2t, sizeof(void*)))
- __kfifo_put(tcp_ctask->r2tpool.queue, (void*)&r2t,
- sizeof(void*));
-
- __iscsi_ctask_cleanup(conn, ctask);
-}
-
-static void
-iscsi_tcp_suspend_conn_rx(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct sock *sk;
-
- if (!tcp_conn->sock)
- return;
-
- sk = tcp_conn->sock->sk;
- write_lock_bh(&sk->sk_callback_lock);
- set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
- write_unlock_bh(&sk->sk_callback_lock);
-}
-
-static void
-iscsi_tcp_terminate_conn(struct iscsi_conn *conn)
-{
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
-
- if (!tcp_conn->sock)
- return;
-
- sock_hold(tcp_conn->sock->sk);
- iscsi_conn_restore_callbacks(conn);
- sock_put(tcp_conn->sock->sk);
-
- sock_release(tcp_conn->sock);
- tcp_conn->sock = NULL;
- conn->recv_lock = NULL;
-}
-
/* called with host lock */
static void
iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
@@ -2057,6 +1904,7 @@ iscsi_tcp_mgmt_init(struct iscsi_conn *conn, struct iscsi_mgmt_task *mtask,
iscsi_buf_init_iov(&tcp_mtask->headbuf, (char*)mtask->hdr,
sizeof(struct iscsi_hdr));
tcp_mtask->xmstate = XMSTATE_IMM_HDR;
+ tcp_mtask->sent = 0;
if (mtask->data_count)
iscsi_buf_init_iov(&tcp_mtask->sendbuf, (char*)mtask->data,
@@ -2130,211 +1978,55 @@ iscsi_r2tpool_free(struct iscsi_session *session)
static int
iscsi_conn_set_param(struct iscsi_cls_conn *cls_conn, enum iscsi_param param,
- uint32_t value)
+ char *buf, int buflen)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
+ int value;
switch(param) {
- case ISCSI_PARAM_MAX_RECV_DLENGTH: {
- char *saveptr = tcp_conn->data;
- gfp_t flags = GFP_KERNEL;
-
- if (tcp_conn->data_size >= value) {
- conn->max_recv_dlength = value;
- break;
- }
-
- spin_lock_bh(&session->lock);
- if (conn->stop_stage == STOP_CONN_RECOVER)
- flags = GFP_ATOMIC;
- spin_unlock_bh(&session->lock);
-
- if (value <= PAGE_SIZE)
- tcp_conn->data = kmalloc(value, flags);
- else
- tcp_conn->data = (void*)__get_free_pages(flags,
- get_order(value));
- if (tcp_conn->data == NULL) {
- tcp_conn->data = saveptr;
- return -ENOMEM;
- }
- if (tcp_conn->data_size <= PAGE_SIZE)
- kfree(saveptr);
- else
- free_pages((unsigned long)saveptr,
- get_order(tcp_conn->data_size));
- conn->max_recv_dlength = value;
- tcp_conn->data_size = value;
- }
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- conn->max_xmit_dlength = value;
- break;
case ISCSI_PARAM_HDRDGST_EN:
- conn->hdrdgst_en = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->hdr_size = sizeof(struct iscsi_hdr);
- if (conn->hdrdgst_en) {
+ if (conn->hdrdgst_en)
tcp_conn->hdr_size += sizeof(__u32);
- if (!tcp_conn->tx_tfm)
- tcp_conn->tx_tfm = crypto_alloc_tfm("crc32c",
- 0);
- if (!tcp_conn->tx_tfm)
- return -ENOMEM;
- if (!tcp_conn->rx_tfm)
- tcp_conn->rx_tfm = crypto_alloc_tfm("crc32c",
- 0);
- if (!tcp_conn->rx_tfm) {
- crypto_free_tfm(tcp_conn->tx_tfm);
- return -ENOMEM;
- }
- } else {
- if (tcp_conn->tx_tfm)
- crypto_free_tfm(tcp_conn->tx_tfm);
- if (tcp_conn->rx_tfm)
- crypto_free_tfm(tcp_conn->rx_tfm);
- }
break;
case ISCSI_PARAM_DATADGST_EN:
- conn->datadgst_en = value;
- if (conn->datadgst_en) {
- if (!tcp_conn->data_tx_tfm)
- tcp_conn->data_tx_tfm =
- crypto_alloc_tfm("crc32c", 0);
- if (!tcp_conn->data_tx_tfm)
- return -ENOMEM;
- if (!tcp_conn->data_rx_tfm)
- tcp_conn->data_rx_tfm =
- crypto_alloc_tfm("crc32c", 0);
- if (!tcp_conn->data_rx_tfm) {
- crypto_free_tfm(tcp_conn->data_tx_tfm);
- return -ENOMEM;
- }
- } else {
- if (tcp_conn->data_tx_tfm)
- crypto_free_tfm(tcp_conn->data_tx_tfm);
- if (tcp_conn->data_rx_tfm)
- crypto_free_tfm(tcp_conn->data_rx_tfm);
- }
+ iscsi_set_param(cls_conn, param, buf, buflen);
tcp_conn->sendpage = conn->datadgst_en ?
sock_no_sendpage : tcp_conn->sock->ops->sendpage;
break;
- case ISCSI_PARAM_INITIAL_R2T_EN:
- session->initial_r2t_en = value;
- break;
case ISCSI_PARAM_MAX_R2T:
+ sscanf(buf, "%d", &value);
if (session->max_r2t == roundup_pow_of_two(value))
break;
iscsi_r2tpool_free(session);
- session->max_r2t = value;
+ iscsi_set_param(cls_conn, param, buf, buflen);
if (session->max_r2t & (session->max_r2t - 1))
session->max_r2t = roundup_pow_of_two(session->max_r2t);
if (iscsi_r2tpool_alloc(session))
return -ENOMEM;
break;
- case ISCSI_PARAM_IMM_DATA_EN:
- session->imm_data_en = value;
- break;
- case ISCSI_PARAM_FIRST_BURST:
- session->first_burst = value;
- break;
- case ISCSI_PARAM_MAX_BURST:
- session->max_burst = value;
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- session->pdu_inorder_en = value;
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- session->dataseq_inorder_en = value;
- break;
- case ISCSI_PARAM_ERL:
- session->erl = value;
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- BUG_ON(value);
- session->ifmarker_en = value;
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- BUG_ON(value);
- session->ofmarker_en = value;
- break;
- case ISCSI_PARAM_EXP_STATSN:
- conn->exp_statsn = value;
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int
-iscsi_session_get_param(struct iscsi_cls_session *cls_session,
- enum iscsi_param param, uint32_t *value)
-{
- struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
- struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
-
- switch(param) {
- case ISCSI_PARAM_INITIAL_R2T_EN:
- *value = session->initial_r2t_en;
- break;
- case ISCSI_PARAM_MAX_R2T:
- *value = session->max_r2t;
- break;
- case ISCSI_PARAM_IMM_DATA_EN:
- *value = session->imm_data_en;
- break;
- case ISCSI_PARAM_FIRST_BURST:
- *value = session->first_burst;
- break;
- case ISCSI_PARAM_MAX_BURST:
- *value = session->max_burst;
- break;
- case ISCSI_PARAM_PDU_INORDER_EN:
- *value = session->pdu_inorder_en;
- break;
- case ISCSI_PARAM_DATASEQ_INORDER_EN:
- *value = session->dataseq_inorder_en;
- break;
- case ISCSI_PARAM_ERL:
- *value = session->erl;
- break;
- case ISCSI_PARAM_IFMARKER_EN:
- *value = session->ifmarker_en;
- break;
- case ISCSI_PARAM_OFMARKER_EN:
- *value = session->ofmarker_en;
- break;
default:
- return -EINVAL;
+ return iscsi_set_param(cls_conn, param, buf, buflen);
}
return 0;
}
static int
-iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, uint32_t *value)
+iscsi_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
{
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct inet_sock *inet;
+ struct ipv6_pinfo *np;
+ struct sock *sk;
+ int len;
switch(param) {
- case ISCSI_PARAM_MAX_RECV_DLENGTH:
- *value = conn->max_recv_dlength;
- break;
- case ISCSI_PARAM_MAX_XMIT_DLENGTH:
- *value = conn->max_xmit_dlength;
- break;
- case ISCSI_PARAM_HDRDGST_EN:
- *value = conn->hdrdgst_en;
- break;
- case ISCSI_PARAM_DATADGST_EN:
- *value = conn->datadgst_en;
- break;
case ISCSI_PARAM_CONN_PORT:
mutex_lock(&conn->xmitmutex);
if (!tcp_conn->sock) {
@@ -2343,30 +2035,9 @@ iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
}
inet = inet_sk(tcp_conn->sock->sk);
- *value = be16_to_cpu(inet->dport);
+ len = sprintf(buf, "%hu\n", be16_to_cpu(inet->dport));
mutex_unlock(&conn->xmitmutex);
- case ISCSI_PARAM_EXP_STATSN:
- *value = conn->exp_statsn;
break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int
-iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
- enum iscsi_param param, char *buf)
-{
- struct iscsi_conn *conn = cls_conn->dd_data;
- struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
- struct sock *sk;
- struct inet_sock *inet;
- struct ipv6_pinfo *np;
- int len = 0;
-
- switch (param) {
case ISCSI_PARAM_CONN_ADDRESS:
mutex_lock(&conn->xmitmutex);
if (!tcp_conn->sock) {
@@ -2388,7 +2059,7 @@ iscsi_conn_get_str_param(struct iscsi_cls_conn *cls_conn,
mutex_unlock(&conn->xmitmutex);
break;
default:
- return -EINVAL;
+ return iscsi_conn_get_param(cls_conn, param, buf);
}
return len;
@@ -2468,8 +2139,7 @@ static void iscsi_tcp_session_destroy(struct iscsi_cls_session *cls_session)
}
static struct scsi_host_template iscsi_sht = {
- .name = "iSCSI Initiator over TCP/IP, v"
- ISCSI_TCP_VERSION,
+ .name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
.change_queue_depth = iscsi_change_queue_depth,
.can_queue = ISCSI_XMIT_CMDS_MAX - 1,
@@ -2501,7 +2171,11 @@ static struct iscsi_transport iscsi_tcp_transport = {
ISCSI_ERL |
ISCSI_CONN_PORT |
ISCSI_CONN_ADDRESS |
- ISCSI_EXP_STATSN,
+ ISCSI_EXP_STATSN |
+ ISCSI_PERSISTENT_PORT |
+ ISCSI_PERSISTENT_ADDRESS |
+ ISCSI_TARGET_NAME |
+ ISCSI_TPGT,
.host_template = &iscsi_sht,
.conndata_size = sizeof(struct iscsi_conn),
.max_conn = 1,
@@ -2514,14 +2188,10 @@ static struct iscsi_transport iscsi_tcp_transport = {
.bind_conn = iscsi_tcp_conn_bind,
.destroy_conn = iscsi_tcp_conn_destroy,
.set_param = iscsi_conn_set_param,
- .get_conn_param = iscsi_conn_get_param,
- .get_conn_str_param = iscsi_conn_get_str_param,
+ .get_conn_param = iscsi_tcp_conn_get_param,
.get_session_param = iscsi_session_get_param,
.start_conn = iscsi_conn_start,
- .stop_conn = iscsi_conn_stop,
- /* these are called as part of conn recovery */
- .suspend_conn_recv = iscsi_tcp_suspend_conn_rx,
- .terminate_conn = iscsi_tcp_terminate_conn,
+ .stop_conn = iscsi_tcp_conn_stop,
/* IO */
.send_pdu = iscsi_conn_send_pdu,
.get_stats = iscsi_conn_get_stats,
diff --git a/drivers/scsi/iscsi_tcp.h b/drivers/scsi/iscsi_tcp.h
index 808302832e6..32736831790 100644
--- a/drivers/scsi/iscsi_tcp.h
+++ b/drivers/scsi/iscsi_tcp.h
@@ -31,26 +31,25 @@
#define IN_PROGRESS_DDIGEST_RECV 0x3
/* xmit state machine */
-#define XMSTATE_IDLE 0x0
-#define XMSTATE_R_HDR 0x1
-#define XMSTATE_W_HDR 0x2
-#define XMSTATE_IMM_HDR 0x4
-#define XMSTATE_IMM_DATA 0x8
-#define XMSTATE_UNS_INIT 0x10
-#define XMSTATE_UNS_HDR 0x20
-#define XMSTATE_UNS_DATA 0x40
-#define XMSTATE_SOL_HDR 0x80
-#define XMSTATE_SOL_DATA 0x100
-#define XMSTATE_W_PAD 0x200
-#define XMSTATE_DATA_DIGEST 0x400
-
-#define ISCSI_CONN_RCVBUF_MIN 262144
-#define ISCSI_CONN_SNDBUF_MIN 262144
+#define XMSTATE_IDLE 0x0
+#define XMSTATE_R_HDR 0x1
+#define XMSTATE_W_HDR 0x2
+#define XMSTATE_IMM_HDR 0x4
+#define XMSTATE_IMM_DATA 0x8
+#define XMSTATE_UNS_INIT 0x10
+#define XMSTATE_UNS_HDR 0x20
+#define XMSTATE_UNS_DATA 0x40
+#define XMSTATE_SOL_HDR 0x80
+#define XMSTATE_SOL_DATA 0x100
+#define XMSTATE_W_PAD 0x200
+#define XMSTATE_W_RESEND_PAD 0x400
+#define XMSTATE_W_RESEND_DATA_DIGEST 0x800
+
#define ISCSI_PAD_LEN 4
-#define ISCSI_R2T_MAX 16
#define ISCSI_SG_TABLESIZE SG_ALL
#define ISCSI_TCP_MAX_CMD_LEN 16
+struct crypto_hash;
struct socket;
/* Socket connection recieve helper */
@@ -78,17 +77,12 @@ struct iscsi_tcp_conn {
char hdrext[4*sizeof(__u16) +
sizeof(__u32)];
int data_copied;
- char *data; /* data placeholder */
- int data_size; /* actual recv_dlength */
int stop_stage; /* conn_stop() flag: *
* stop to recover, *
* stop to terminate */
/* iSCSI connection-wide sequencing */
int hdr_size; /* PDU header size */
- struct crypto_tfm *rx_tfm; /* CRC32C (Rx) */
- struct crypto_tfm *data_rx_tfm; /* CRC32C (Rx) for data */
-
/* control data */
struct iscsi_tcp_recv in; /* TCP receive context */
int in_progress; /* connection state machine */
@@ -98,9 +92,9 @@ struct iscsi_tcp_conn {
void (*old_state_change)(struct sock *);
void (*old_write_space)(struct sock *);
- /* xmit */
- struct crypto_tfm *tx_tfm; /* CRC32C (Tx) */
- struct crypto_tfm *data_tx_tfm; /* CRC32C (Tx) for data */
+ /* data and header digests */
+ struct hash_desc tx_hash; /* CRC32C (Tx) */
+ struct hash_desc rx_hash; /* CRC32C (Rx) */
/* MIB custom statistics */
uint32_t sendpage_failures_cnt;
@@ -159,19 +153,15 @@ struct iscsi_tcp_cmd_task {
struct scatterlist *bad_sg; /* assert statement */
int sg_count; /* SG's to process */
uint32_t exp_r2tsn;
- int r2t_data_count; /* R2T Data-Out bytes */
int data_offset;
struct iscsi_r2t_info *r2t; /* in progress R2T */
struct iscsi_queue r2tpool;
struct kfifo *r2tqueue;
struct iscsi_r2t_info **r2ts;
- uint32_t datadigest; /* for recover digest */
int digest_count;
uint32_t immdigest; /* for imm data */
struct iscsi_buf immbuf; /* for imm data digest */
- struct iscsi_data_task *dtask; /* data task in progress*/
struct iscsi_data_task unsol_dtask; /* unsol data task */
- int digest_offset; /* for partial buff digest */
};
#endif /* ISCSI_H */
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
index fc031c76dad..bfac4441d89 100644
--- a/drivers/scsi/jazz_esp.c
+++ b/drivers/scsi/jazz_esp.c
@@ -131,7 +131,7 @@ static int jazz_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = vdma_alloc(CPHYSADDR(cmd_buffer), sizeof (cmd_buffer));
esp->irq = JAZZ_SCSI_IRQ;
- request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI",
+ request_irq(JAZZ_SCSI_IRQ, esp_intr, IRQF_DISABLED, "JAZZ SCSI",
esp->ehost);
/*
@@ -257,7 +257,7 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp)
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp)
{
int sz = sp->use_sg - 1;
- struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+ struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
while(sz >= 0) {
vdma_free(sg[sz].dma_address);
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index eb7bd310cc8..f0871c3ac3d 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -131,7 +131,7 @@ lasi700_probe(struct parisc_device *dev)
host->this_id = 7;
host->base = base;
host->irq = dev->irq;
- if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, "lasi700", host)) {
+ if(request_irq(dev->irq, NCR_700_intr, IRQF_SHARED, "lasi700", host)) {
printk(KERN_ERR "lasi700: request_irq failed!\n");
goto out_put_host;
}
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 2673a11a949..c542d0e95e6 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -68,8 +68,7 @@ iscsi_check_assign_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr)
EXPORT_SYMBOL_GPL(iscsi_check_assign_cmdsn);
void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
- struct iscsi_data *hdr,
- int transport_data_cnt)
+ struct iscsi_data *hdr)
{
struct iscsi_conn *conn = ctask->conn;
@@ -82,14 +81,12 @@ void iscsi_prep_unsolicit_data_pdu(struct iscsi_cmd_task *ctask,
hdr->itt = ctask->hdr->itt;
hdr->exp_statsn = cpu_to_be32(conn->exp_statsn);
-
- hdr->offset = cpu_to_be32(ctask->total_length -
- transport_data_cnt -
- ctask->unsol_count);
+ hdr->offset = cpu_to_be32(ctask->unsol_offset);
if (ctask->unsol_count > conn->max_xmit_dlength) {
hton24(hdr->dlength, conn->max_xmit_dlength);
ctask->data_count = conn->max_xmit_dlength;
+ ctask->unsol_offset += ctask->data_count;
hdr->flags = 0;
} else {
hton24(hdr->dlength, ctask->unsol_count);
@@ -125,6 +122,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
memcpy(hdr->cdb, sc->cmnd, sc->cmd_len);
memset(&hdr->cdb[sc->cmd_len], 0, MAX_COMMAND_SIZE - sc->cmd_len);
+ ctask->data_count = 0;
if (sc->sc_data_direction == DMA_TO_DEVICE) {
hdr->flags |= ISCSI_FLAG_CMD_WRITE;
/*
@@ -143,6 +141,7 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
*/
ctask->imm_count = 0;
ctask->unsol_count = 0;
+ ctask->unsol_offset = 0;
ctask->unsol_datasn = 0;
if (session->imm_data_en) {
@@ -156,9 +155,12 @@ static void iscsi_prep_scsi_cmd_pdu(struct iscsi_cmd_task *ctask)
} else
zero_data(ctask->hdr->dlength);
- if (!session->initial_r2t_en)
+ if (!session->initial_r2t_en) {
ctask->unsol_count = min(session->first_burst,
ctask->total_length) - ctask->imm_count;
+ ctask->unsol_offset = ctask->imm_count;
+ }
+
if (!ctask->unsol_count)
/* No unsolicit Data-Out's */
ctask->hdr->flags |= ISCSI_FLAG_CMD_FINAL;
@@ -177,24 +179,51 @@ EXPORT_SYMBOL_GPL(iscsi_prep_scsi_cmd_pdu);
/**
* iscsi_complete_command - return command back to scsi-ml
- * @session: iscsi session
* @ctask: iscsi cmd task
*
* Must be called with session lock.
* This function returns the scsi command to scsi-ml and returns
* the cmd task to the pool of available cmd tasks.
*/
-static void iscsi_complete_command(struct iscsi_session *session,
- struct iscsi_cmd_task *ctask)
+static void iscsi_complete_command(struct iscsi_cmd_task *ctask)
{
+ struct iscsi_session *session = ctask->conn->session;
struct scsi_cmnd *sc = ctask->sc;
+ ctask->state = ISCSI_TASK_COMPLETED;
ctask->sc = NULL;
+ /* SCSI eh reuses commands to verify us */
+ sc->SCp.ptr = NULL;
list_del_init(&ctask->running);
__kfifo_put(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
sc->scsi_done(sc);
}
+static void __iscsi_get_ctask(struct iscsi_cmd_task *ctask)
+{
+ atomic_inc(&ctask->refcount);
+}
+
+static void iscsi_get_ctask(struct iscsi_cmd_task *ctask)
+{
+ spin_lock_bh(&ctask->conn->session->lock);
+ __iscsi_get_ctask(ctask);
+ spin_unlock_bh(&ctask->conn->session->lock);
+}
+
+static void __iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+{
+ if (atomic_dec_and_test(&ctask->refcount))
+ iscsi_complete_command(ctask);
+}
+
+static void iscsi_put_ctask(struct iscsi_cmd_task *ctask)
+{
+ spin_lock_bh(&ctask->conn->session->lock);
+ __iscsi_put_ctask(ctask);
+ spin_unlock_bh(&ctask->conn->session->lock);
+}
+
/**
* iscsi_cmd_rsp - SCSI Command Response processing
* @conn: iscsi connection
@@ -271,10 +300,53 @@ out:
(long)sc, sc->result, ctask->itt);
conn->scsirsp_pdus_cnt++;
- iscsi_complete_command(conn->session, ctask);
+ __iscsi_put_ctask(ctask);
return rc;
}
+static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
+{
+ struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
+
+ conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
+ conn->tmfrsp_pdus_cnt++;
+
+ if (conn->tmabort_state != TMABORT_INITIAL)
+ return;
+
+ if (tmf->response == ISCSI_TMF_RSP_COMPLETE)
+ conn->tmabort_state = TMABORT_SUCCESS;
+ else if (tmf->response == ISCSI_TMF_RSP_NO_TASK)
+ conn->tmabort_state = TMABORT_NOT_FOUND;
+ else
+ conn->tmabort_state = TMABORT_FAILED;
+ wake_up(&conn->ehwait);
+}
+
+static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
+ char *data, int datalen)
+{
+ struct iscsi_reject *reject = (struct iscsi_reject *)hdr;
+ struct iscsi_hdr rejected_pdu;
+ uint32_t itt;
+
+ conn->exp_statsn = be32_to_cpu(reject->statsn) + 1;
+
+ if (reject->reason == ISCSI_REASON_DATA_DIGEST_ERROR) {
+ if (ntoh24(reject->dlength) > datalen)
+ return ISCSI_ERR_PROTO;
+
+ if (ntoh24(reject->dlength) >= sizeof(struct iscsi_hdr)) {
+ memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr));
+ itt = rejected_pdu.itt & ISCSI_ITT_MASK;
+ printk(KERN_ERR "itt 0x%x had pdu (op 0x%x) rejected "
+ "due to DataDigest error.\n", itt,
+ rejected_pdu.opcode);
+ }
+ }
+ return 0;
+}
+
/**
* __iscsi_complete_pdu - complete pdu
* @conn: iscsi conn
@@ -316,7 +388,7 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
BUG_ON((void*)ctask != ctask->sc->SCp.ptr);
if (hdr->flags & ISCSI_FLAG_DATA_STATUS) {
conn->scsirsp_pdus_cnt++;
- iscsi_complete_command(session, ctask);
+ __iscsi_put_ctask(ctask);
}
break;
case ISCSI_OP_R2T:
@@ -340,6 +412,10 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
switch(opcode) {
case ISCSI_OP_LOGOUT_RSP:
+ if (datalen) {
+ rc = ISCSI_ERR_PROTO;
+ break;
+ }
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
/* fall through */
case ISCSI_OP_LOGIN_RSP:
@@ -348,7 +424,8 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
* login related PDU's exp_statsn is handled in
* userspace
*/
- rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ rc = ISCSI_ERR_CONN_FAILED;
list_del(&mtask->running);
if (conn->login_mtask != mtask)
__kfifo_put(session->mgmtpool.queue,
@@ -360,25 +437,17 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
- conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- conn->tmfrsp_pdus_cnt++;
- if (conn->tmabort_state == TMABORT_INITIAL) {
- conn->tmabort_state =
- ((struct iscsi_tm_rsp *)hdr)->
- response == ISCSI_TMF_RSP_COMPLETE ?
- TMABORT_SUCCESS:TMABORT_FAILED;
- /* unblock eh_abort() */
- wake_up(&conn->ehwait);
- }
+ iscsi_tmf_rsp(conn, hdr);
break;
case ISCSI_OP_NOOP_IN:
- if (hdr->ttt != ISCSI_RESERVED_TAG) {
+ if (hdr->ttt != ISCSI_RESERVED_TAG || datalen) {
rc = ISCSI_ERR_PROTO;
break;
}
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
- rc = iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen);
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen))
+ rc = ISCSI_ERR_CONN_FAILED;
list_del(&mtask->running);
if (conn->login_mtask != mtask)
__kfifo_put(session->mgmtpool.queue,
@@ -389,19 +458,27 @@ int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
break;
}
} else if (itt == ISCSI_RESERVED_TAG) {
+ rc = iscsi_check_assign_cmdsn(session,
+ (struct iscsi_nopin*)hdr);
+ if (rc)
+ goto done;
+
switch(opcode) {
case ISCSI_OP_NOOP_IN:
- if (!datalen) {
- rc = iscsi_check_assign_cmdsn(session,
- (struct iscsi_nopin*)hdr);
- if (!rc && hdr->ttt != ISCSI_RESERVED_TAG)
- rc = iscsi_recv_pdu(conn->cls_conn,
- hdr, NULL, 0);
- } else
+ if (datalen) {
rc = ISCSI_ERR_PROTO;
+ break;
+ }
+
+ if (hdr->ttt == ISCSI_RESERVED_TAG)
+ break;
+
+ if (iscsi_recv_pdu(conn->cls_conn, hdr, NULL, 0))
+ rc = ISCSI_ERR_CONN_FAILED;
break;
case ISCSI_OP_REJECT:
- /* we need sth like iscsi_reject_rsp()*/
+ rc = iscsi_handle_reject(conn, hdr, data, datalen);
+ break;
case ISCSI_OP_ASYNC_EVENT:
conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
/* we need sth like iscsi_async_event_rsp() */
@@ -537,7 +614,9 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
BUG_ON(conn->ctask && conn->mtask);
if (conn->ctask) {
+ iscsi_get_ctask(conn->ctask);
rc = tt->xmit_cmd_task(conn, conn->ctask);
+ iscsi_put_ctask(conn->ctask);
if (rc)
goto again;
/* done with this in-progress ctask */
@@ -568,20 +647,31 @@ static int iscsi_data_xmit(struct iscsi_conn *conn)
}
/* process command queue */
- while (__kfifo_get(conn->xmitqueue, (void*)&conn->ctask,
- sizeof(void*))) {
+ spin_lock_bh(&conn->session->lock);
+ while (!list_empty(&conn->xmitqueue)) {
/*
* iscsi tcp may readd the task to the xmitqueue to send
* write data
*/
- spin_lock_bh(&conn->session->lock);
- if (list_empty(&conn->ctask->running))
- list_add_tail(&conn->ctask->running, &conn->run_list);
+ conn->ctask = list_entry(conn->xmitqueue.next,
+ struct iscsi_cmd_task, running);
+ conn->ctask->state = ISCSI_TASK_RUNNING;
+ list_move_tail(conn->xmitqueue.next, &conn->run_list);
+ __iscsi_get_ctask(conn->ctask);
spin_unlock_bh(&conn->session->lock);
+
rc = tt->xmit_cmd_task(conn, conn->ctask);
if (rc)
goto again;
+
+ spin_lock_bh(&conn->session->lock);
+ __iscsi_put_ctask(conn->ctask);
+ if (rc) {
+ spin_unlock_bh(&conn->session->lock);
+ goto again;
+ }
}
+ spin_unlock_bh(&conn->session->lock);
/* done with this ctask */
conn->ctask = NULL;
@@ -629,6 +719,7 @@ enum {
FAILURE_SESSION_FAILED,
FAILURE_SESSION_FREED,
FAILURE_WINDOW_CLOSED,
+ FAILURE_OOM,
FAILURE_SESSION_TERMINATE,
FAILURE_SESSION_IN_RECOVERY,
FAILURE_SESSION_RECOVERY_TIMEOUT,
@@ -644,6 +735,7 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
sc->scsi_done = done;
sc->result = 0;
+ sc->SCp.ptr = NULL;
host = sc->device->host;
session = iscsi_hostdata(host->hostdata);
@@ -687,10 +779,16 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
conn = session->leadconn;
- __kfifo_get(session->cmdpool.queue, (void*)&ctask, sizeof(void*));
+ if (!__kfifo_get(session->cmdpool.queue, (void*)&ctask,
+ sizeof(void*))) {
+ reason = FAILURE_OOM;
+ goto reject;
+ }
sc->SCp.phase = session->age;
sc->SCp.ptr = (char *)ctask;
+ atomic_set(&ctask->refcount, 1);
+ ctask->state = ISCSI_TASK_PENDING;
ctask->mtask = NULL;
ctask->conn = conn;
ctask->sc = sc;
@@ -700,11 +798,12 @@ int iscsi_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *))
session->tt->init_cmd_task(ctask);
- __kfifo_put(conn->xmitqueue, (void*)&ctask, sizeof(void*));
+ list_add_tail(&ctask->running, &conn->xmitqueue);
debug_scsi(
- "ctask enq [%s cid %d sc %lx itt 0x%x len %d cmdsn %d win %d]\n",
+ "ctask enq [%s cid %d sc %p cdb 0x%x itt 0x%x len %d cmdsn %d "
+ "win %d]\n",
sc->sc_data_direction == DMA_TO_DEVICE ? "write" : "read",
- conn->id, (long)sc, ctask->itt, sc->request_bufflen,
+ conn->id, sc, sc->cmnd[0], ctask->itt, sc->request_bufflen,
session->cmdsn, session->max_cmdsn - session->exp_cmdsn + 1);
spin_unlock(&session->lock);
@@ -977,31 +1076,27 @@ static int iscsi_exec_abort_task(struct scsi_cmnd *sc,
/*
* xmit mutex and session lock must be held
*/
-#define iscsi_remove_task(tasktype) \
-static struct iscsi_##tasktype * \
-iscsi_remove_##tasktype(struct kfifo *fifo, uint32_t itt) \
-{ \
- int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*); \
- struct iscsi_##tasktype *task; \
- \
- debug_scsi("searching %d tasks\n", nr_tasks); \
- \
- for (i = 0; i < nr_tasks; i++) { \
- __kfifo_get(fifo, (void*)&task, sizeof(void*)); \
- debug_scsi("check task %u\n", task->itt); \
- \
- if (task->itt == itt) { \
- debug_scsi("matched task\n"); \
- return task; \
- } \
- \
- __kfifo_put(fifo, (void*)&task, sizeof(void*)); \
- } \
- return NULL; \
-}
+static struct iscsi_mgmt_task *
+iscsi_remove_mgmt_task(struct kfifo *fifo, uint32_t itt)
+{
+ int i, nr_tasks = __kfifo_len(fifo) / sizeof(void*);
+ struct iscsi_mgmt_task *task;
+
+ debug_scsi("searching %d tasks\n", nr_tasks);
+
+ for (i = 0; i < nr_tasks; i++) {
+ __kfifo_get(fifo, (void*)&task, sizeof(void*));
+ debug_scsi("check task %u\n", task->itt);
+
+ if (task->itt == itt) {
+ debug_scsi("matched task\n");
+ return task;
+ }
-iscsi_remove_task(mgmt_task);
-iscsi_remove_task(cmd_task);
+ __kfifo_put(fifo, (void*)&task, sizeof(void*));
+ }
+ return NULL;
+}
static int iscsi_ctask_mtask_cleanup(struct iscsi_cmd_task *ctask)
{
@@ -1027,25 +1122,39 @@ static void fail_command(struct iscsi_conn *conn, struct iscsi_cmd_task *ctask,
{
struct scsi_cmnd *sc;
- conn->session->tt->cleanup_cmd_task(conn, ctask);
- iscsi_ctask_mtask_cleanup(ctask);
-
sc = ctask->sc;
if (!sc)
return;
+
+ conn->session->tt->cleanup_cmd_task(conn, ctask);
+ iscsi_ctask_mtask_cleanup(ctask);
+
sc->result = err;
sc->resid = sc->request_bufflen;
- iscsi_complete_command(conn->session, ctask);
+ /* release ref from queuecommand */
+ __iscsi_put_ctask(ctask);
}
int iscsi_eh_abort(struct scsi_cmnd *sc)
{
- struct iscsi_cmd_task *ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
- struct iscsi_conn *conn = ctask->conn;
- struct iscsi_session *session = conn->session;
- struct iscsi_cmd_task *pending_ctask;
+ struct iscsi_cmd_task *ctask;
+ struct iscsi_conn *conn;
+ struct iscsi_session *session;
int rc;
+ /*
+ * if session was ISCSI_STATE_IN_RECOVERY then we may not have
+ * got the command.
+ */
+ if (!sc->SCp.ptr) {
+ debug_scsi("sc never reached iscsi layer or it completed.\n");
+ return SUCCESS;
+ }
+
+ ctask = (struct iscsi_cmd_task *)sc->SCp.ptr;
+ conn = ctask->conn;
+ session = conn->session;
+
conn->eh_abort_cnt++;
debug_scsi("aborting [sc %p itt 0x%x]\n", sc, ctask->itt);
@@ -1061,8 +1170,11 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
goto failed;
/* ctask completed before time out */
- if (!ctask->sc)
- goto success;
+ if (!ctask->sc) {
+ spin_unlock_bh(&session->lock);
+ debug_scsi("sc completed while abort in progress\n");
+ goto success_rel_mutex;
+ }
/* what should we do here ? */
if (conn->ctask == ctask) {
@@ -1071,17 +1183,8 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
goto failed;
}
- /* check for the easy pending cmd abort */
- pending_ctask = iscsi_remove_cmd_task(conn->xmitqueue, ctask->itt);
- if (pending_ctask) {
- /* iscsi_tcp queues write transfers on the xmitqueue */
- if (list_empty(&pending_ctask->running)) {
- debug_scsi("found pending task\n");
- goto success;
- } else
- __kfifo_put(conn->xmitqueue, (void*)&pending_ctask,
- sizeof(void*));
- }
+ if (ctask->state == ISCSI_TASK_PENDING)
+ goto success_cleanup;
conn->tmabort_state = TMABORT_INITIAL;
@@ -1089,25 +1192,31 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
rc = iscsi_exec_abort_task(sc, ctask);
spin_lock_bh(&session->lock);
- iscsi_ctask_mtask_cleanup(ctask);
if (rc || sc->SCp.phase != session->age ||
session->state != ISCSI_STATE_LOGGED_IN)
goto failed;
+ iscsi_ctask_mtask_cleanup(ctask);
- /* ctask completed before tmf abort response */
- if (!ctask->sc) {
- debug_scsi("sc completed while abort in progress\n");
- goto success;
- }
-
- if (conn->tmabort_state != TMABORT_SUCCESS) {
+ switch (conn->tmabort_state) {
+ case TMABORT_SUCCESS:
+ goto success_cleanup;
+ case TMABORT_NOT_FOUND:
+ if (!ctask->sc) {
+ /* ctask completed before tmf abort response */
+ spin_unlock_bh(&session->lock);
+ debug_scsi("sc completed while abort in progress\n");
+ goto success_rel_mutex;
+ }
+ /* fall through */
+ default:
+ /* timedout or failed */
spin_unlock_bh(&session->lock);
iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
spin_lock_bh(&session->lock);
goto failed;
}
-success:
+success_cleanup:
debug_scsi("abort success [sc %lx itt 0x%x]\n", (long)sc, ctask->itt);
spin_unlock_bh(&session->lock);
@@ -1121,6 +1230,7 @@ success:
spin_unlock(&session->lock);
write_unlock_bh(conn->recv_lock);
+success_rel_mutex:
mutex_unlock(&conn->xmitmutex);
return SUCCESS;
@@ -1263,6 +1373,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
if (cmd_task_size)
ctask->dd_data = &ctask[1];
ctask->itt = cmd_i;
+ INIT_LIST_HEAD(&ctask->running);
}
spin_lock_init(&session->lock);
@@ -1282,18 +1393,24 @@ iscsi_session_setup(struct iscsi_transport *iscsit,
if (mgmt_task_size)
mtask->dd_data = &mtask[1];
mtask->itt = ISCSI_MGMT_ITT_OFFSET + cmd_i;
+ INIT_LIST_HEAD(&mtask->running);
}
if (scsi_add_host(shost, NULL))
goto add_host_fail;
+ if (!try_module_get(iscsit->owner))
+ goto cls_session_fail;
+
cls_session = iscsi_create_session(shost, iscsit, 0);
if (!cls_session)
- goto cls_session_fail;
+ goto module_put;
*(unsigned long*)shost->hostdata = (unsigned long)cls_session;
return cls_session;
+module_put:
+ module_put(iscsit->owner);
cls_session_fail:
scsi_remove_host(shost);
add_host_fail:
@@ -1317,14 +1434,18 @@ void iscsi_session_teardown(struct iscsi_cls_session *cls_session)
{
struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ struct module *owner = cls_session->transport->owner;
scsi_remove_host(shost);
iscsi_pool_free(&session->mgmtpool, (void**)session->mgmt_cmds);
iscsi_pool_free(&session->cmdpool, (void**)session->cmds);
+ kfree(session->targetname);
+
iscsi_destroy_session(cls_session);
scsi_host_put(shost);
+ module_put(owner);
}
EXPORT_SYMBOL_GPL(iscsi_session_teardown);
@@ -1355,12 +1476,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
conn->tmabort_state = TMABORT_INITIAL;
INIT_LIST_HEAD(&conn->run_list);
INIT_LIST_HEAD(&conn->mgmt_run_list);
-
- /* initialize general xmit PDU commands queue */
- conn->xmitqueue = kfifo_alloc(session->cmds_max * sizeof(void*),
- GFP_KERNEL, NULL);
- if (conn->xmitqueue == ERR_PTR(-ENOMEM))
- goto xmitqueue_alloc_fail;
+ INIT_LIST_HEAD(&conn->xmitqueue);
/* initialize general immediate & non-immediate PDU commands queue */
conn->immqueue = kfifo_alloc(session->mgmtpool_max * sizeof(void*),
@@ -1388,7 +1504,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, uint32_t conn_idx)
data = kmalloc(DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH, GFP_KERNEL);
if (!data)
goto login_mtask_data_alloc_fail;
- conn->login_mtask->data = data;
+ conn->login_mtask->data = conn->data = data;
init_timer(&conn->tmabort_timer);
mutex_init(&conn->xmitmutex);
@@ -1404,8 +1520,6 @@ login_mtask_alloc_fail:
mgmtqueue_alloc_fail:
kfifo_free(conn->immqueue);
immqueue_alloc_fail:
- kfifo_free(conn->xmitqueue);
-xmitqueue_alloc_fail:
iscsi_destroy_conn(cls_conn);
return NULL;
}
@@ -1426,12 +1540,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
mutex_lock(&conn->xmitmutex);
- if (conn->c_stage == ISCSI_CONN_INITIAL_STAGE) {
- if (session->tt->suspend_conn_recv)
- session->tt->suspend_conn_recv(conn);
-
- session->tt->terminate_conn(conn);
- }
spin_lock_bh(&session->lock);
conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
@@ -1468,7 +1576,8 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
}
spin_lock_bh(&session->lock);
- kfree(conn->login_mtask->data);
+ kfree(conn->data);
+ kfree(conn->persistent_address);
__kfifo_put(session->mgmtpool.queue, (void*)&conn->login_mtask,
sizeof(void*));
list_del(&conn->item);
@@ -1483,7 +1592,6 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
session->cmdsn = session->max_cmdsn = session->exp_cmdsn = 1;
spin_unlock_bh(&session->lock);
- kfifo_free(conn->xmitqueue);
kfifo_free(conn->immqueue);
kfifo_free(conn->mgmtqueue);
@@ -1496,11 +1604,19 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
struct iscsi_conn *conn = cls_conn->dd_data;
struct iscsi_session *session = conn->session;
- if (session == NULL) {
+ if (!session) {
printk(KERN_ERR "iscsi: can't start unbound connection\n");
return -EPERM;
}
+ if ((session->imm_data_en || !session->initial_r2t_en) &&
+ session->first_burst > session->max_burst) {
+ printk("iscsi: invalid burst lengths: "
+ "first_burst %d max_burst %d\n",
+ session->first_burst, session->max_burst);
+ return -EINVAL;
+ }
+
spin_lock_bh(&session->lock);
conn->c_stage = ISCSI_CONN_STARTED;
session->state = ISCSI_STATE_LOGGED_IN;
@@ -1566,7 +1682,7 @@ static void fail_all_commands(struct iscsi_conn *conn)
struct iscsi_cmd_task *ctask, *tmp;
/* flush pending */
- while (__kfifo_get(conn->xmitqueue, (void*)&ctask, sizeof(void*))) {
+ list_for_each_entry_safe(ctask, tmp, &conn->xmitqueue, running) {
debug_scsi("failing pending sc %p itt 0x%x\n", ctask->sc,
ctask->itt);
fail_command(conn, ctask, DID_BUS_BUSY << 16);
@@ -1609,8 +1725,9 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx);
spin_unlock_bh(&session->lock);
- if (session->tt->suspend_conn_recv)
- session->tt->suspend_conn_recv(conn);
+ write_lock_bh(conn->recv_lock);
+ set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx);
+ write_unlock_bh(conn->recv_lock);
mutex_lock(&conn->xmitmutex);
/*
@@ -1629,7 +1746,6 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
}
}
- session->tt->terminate_conn(conn);
/*
* flush queues.
*/
@@ -1697,6 +1813,185 @@ int iscsi_conn_bind(struct iscsi_cls_session *cls_session,
}
EXPORT_SYMBOL_GPL(iscsi_conn_bind);
+
+int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
+ uint32_t value;
+
+ switch(param) {
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ sscanf(buf, "%d", &conn->max_recv_dlength);
+ break;
+ case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+ sscanf(buf, "%d", &conn->max_xmit_dlength);
+ break;
+ case ISCSI_PARAM_HDRDGST_EN:
+ sscanf(buf, "%d", &conn->hdrdgst_en);
+ break;
+ case ISCSI_PARAM_DATADGST_EN:
+ sscanf(buf, "%d", &conn->datadgst_en);
+ break;
+ case ISCSI_PARAM_INITIAL_R2T_EN:
+ sscanf(buf, "%d", &session->initial_r2t_en);
+ break;
+ case ISCSI_PARAM_MAX_R2T:
+ sscanf(buf, "%d", &session->max_r2t);
+ break;
+ case ISCSI_PARAM_IMM_DATA_EN:
+ sscanf(buf, "%d", &session->imm_data_en);
+ break;
+ case ISCSI_PARAM_FIRST_BURST:
+ sscanf(buf, "%d", &session->first_burst);
+ break;
+ case ISCSI_PARAM_MAX_BURST:
+ sscanf(buf, "%d", &session->max_burst);
+ break;
+ case ISCSI_PARAM_PDU_INORDER_EN:
+ sscanf(buf, "%d", &session->pdu_inorder_en);
+ break;
+ case ISCSI_PARAM_DATASEQ_INORDER_EN:
+ sscanf(buf, "%d", &session->dataseq_inorder_en);
+ break;
+ case ISCSI_PARAM_ERL:
+ sscanf(buf, "%d", &session->erl);
+ break;
+ case ISCSI_PARAM_IFMARKER_EN:
+ sscanf(buf, "%d", &value);
+ BUG_ON(value);
+ break;
+ case ISCSI_PARAM_OFMARKER_EN:
+ sscanf(buf, "%d", &value);
+ BUG_ON(value);
+ break;
+ case ISCSI_PARAM_EXP_STATSN:
+ sscanf(buf, "%u", &conn->exp_statsn);
+ break;
+ case ISCSI_PARAM_TARGET_NAME:
+ /* this should not change between logins */
+ if (session->targetname)
+ break;
+
+ session->targetname = kstrdup(buf, GFP_KERNEL);
+ if (!session->targetname)
+ return -ENOMEM;
+ break;
+ case ISCSI_PARAM_TPGT:
+ sscanf(buf, "%d", &session->tpgt);
+ break;
+ case ISCSI_PARAM_PERSISTENT_PORT:
+ sscanf(buf, "%d", &conn->persistent_port);
+ break;
+ case ISCSI_PARAM_PERSISTENT_ADDRESS:
+ /*
+ * this is the address returned in discovery so it should
+ * not change between logins.
+ */
+ if (conn->persistent_address)
+ break;
+
+ conn->persistent_address = kstrdup(buf, GFP_KERNEL);
+ if (!conn->persistent_address)
+ return -ENOMEM;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iscsi_set_param);
+
+int iscsi_session_get_param(struct iscsi_cls_session *cls_session,
+ enum iscsi_param param, char *buf)
+{
+ struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
+ struct iscsi_session *session = iscsi_hostdata(shost->hostdata);
+ int len;
+
+ switch(param) {
+ case ISCSI_PARAM_INITIAL_R2T_EN:
+ len = sprintf(buf, "%d\n", session->initial_r2t_en);
+ break;
+ case ISCSI_PARAM_MAX_R2T:
+ len = sprintf(buf, "%hu\n", session->max_r2t);
+ break;
+ case ISCSI_PARAM_IMM_DATA_EN:
+ len = sprintf(buf, "%d\n", session->imm_data_en);
+ break;
+ case ISCSI_PARAM_FIRST_BURST:
+ len = sprintf(buf, "%u\n", session->first_burst);
+ break;
+ case ISCSI_PARAM_MAX_BURST:
+ len = sprintf(buf, "%u\n", session->max_burst);
+ break;
+ case ISCSI_PARAM_PDU_INORDER_EN:
+ len = sprintf(buf, "%d\n", session->pdu_inorder_en);
+ break;
+ case ISCSI_PARAM_DATASEQ_INORDER_EN:
+ len = sprintf(buf, "%d\n", session->dataseq_inorder_en);
+ break;
+ case ISCSI_PARAM_ERL:
+ len = sprintf(buf, "%d\n", session->erl);
+ break;
+ case ISCSI_PARAM_TARGET_NAME:
+ len = sprintf(buf, "%s\n", session->targetname);
+ break;
+ case ISCSI_PARAM_TPGT:
+ len = sprintf(buf, "%d\n", session->tpgt);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_session_get_param);
+
+int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ int len;
+
+ switch(param) {
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ len = sprintf(buf, "%u\n", conn->max_recv_dlength);
+ break;
+ case ISCSI_PARAM_MAX_XMIT_DLENGTH:
+ len = sprintf(buf, "%u\n", conn->max_xmit_dlength);
+ break;
+ case ISCSI_PARAM_HDRDGST_EN:
+ len = sprintf(buf, "%d\n", conn->hdrdgst_en);
+ break;
+ case ISCSI_PARAM_DATADGST_EN:
+ len = sprintf(buf, "%d\n", conn->datadgst_en);
+ break;
+ case ISCSI_PARAM_IFMARKER_EN:
+ len = sprintf(buf, "%d\n", conn->ifmarker_en);
+ break;
+ case ISCSI_PARAM_OFMARKER_EN:
+ len = sprintf(buf, "%d\n", conn->ofmarker_en);
+ break;
+ case ISCSI_PARAM_EXP_STATSN:
+ len = sprintf(buf, "%u\n", conn->exp_statsn);
+ break;
+ case ISCSI_PARAM_PERSISTENT_PORT:
+ len = sprintf(buf, "%d\n", conn->persistent_port);
+ break;
+ case ISCSI_PARAM_PERSISTENT_ADDRESS:
+ len = sprintf(buf, "%s\n", conn->persistent_address);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(iscsi_conn_get_param);
+
MODULE_AUTHOR("Mike Christie");
MODULE_DESCRIPTION("iSCSI library functions");
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig
new file mode 100644
index 00000000000..aafdc92f831
--- /dev/null
+++ b/drivers/scsi/libsas/Kconfig
@@ -0,0 +1,39 @@
+#
+# Kernel configuration file for the SAS Class
+#
+# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# 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 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+#
+
+config SCSI_SAS_LIBSAS
+ tristate "SAS Domain Transport Attributes"
+ depends on SCSI
+ select SCSI_SAS_ATTRS
+ help
+ This provides transport specific helpers for SAS drivers which
+ use the domain device construct (like the aic94xxx).
+
+config SCSI_SAS_LIBSAS_DEBUG
+ bool "Compile the SAS Domain Transport Attributes in debug mode"
+ default y
+ depends on SCSI_SAS_LIBSAS
+ help
+ Compiles the SAS Layer in debug mode. In debug mode, the
+ SAS Layer prints diagnostic and debug messages.
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile
new file mode 100644
index 00000000000..44d972a3b4b
--- /dev/null
+++ b/drivers/scsi/libsas/Makefile
@@ -0,0 +1,36 @@
+#
+# Kernel Makefile for the libsas helpers
+#
+# Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+# Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+#
+# This file is licensed under GPLv2.
+#
+# 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 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+# USA
+
+ifeq ($(CONFIG_SCSI_SAS_LIBSAS_DEBUG),y)
+ EXTRA_CFLAGS += -DSAS_DEBUG
+endif
+
+obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o
+libsas-y += sas_init.o \
+ sas_phy.o \
+ sas_port.o \
+ sas_event.o \
+ sas_dump.o \
+ sas_discover.o \
+ sas_expander.o \
+ sas_scsi_host.o
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c
new file mode 100644
index 00000000000..d977bd492d8
--- /dev/null
+++ b/drivers/scsi/libsas/sas_discover.c
@@ -0,0 +1,749 @@
+/*
+ * Serial Attached SCSI (SAS) Discover process
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_eh.h>
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+/* ---------- Basic task processing for discovery purposes ---------- */
+
+void sas_init_dev(struct domain_device *dev)
+{
+ INIT_LIST_HEAD(&dev->siblings);
+ INIT_LIST_HEAD(&dev->dev_list_node);
+ switch (dev->dev_type) {
+ case SAS_END_DEV:
+ break;
+ case EDGE_DEV:
+ case FANOUT_DEV:
+ INIT_LIST_HEAD(&dev->ex_dev.children);
+ break;
+ case SATA_DEV:
+ case SATA_PM:
+ case SATA_PM_PORT:
+ INIT_LIST_HEAD(&dev->sata_dev.children);
+ break;
+ default:
+ break;
+ }
+}
+
+static void sas_task_timedout(unsigned long _task)
+{
+ struct sas_task *task = (void *) _task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ complete(&task->completion);
+}
+
+static void sas_disc_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+#define SAS_DEV_TIMEOUT 10
+
+/**
+ * sas_execute_task -- Basic task processing for discovery
+ * @task: the task to be executed
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_execute_task(struct sas_task *task, void *buffer, int size,
+ int pci_dma_dir)
+{
+ int res = 0;
+ struct scatterlist *scatter = NULL;
+ struct task_status_struct *ts = &task->task_status;
+ int num_scatter = 0;
+ int retries = 0;
+ struct sas_internal *i =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+ if (pci_dma_dir != PCI_DMA_NONE) {
+ scatter = kzalloc(sizeof(*scatter), GFP_KERNEL);
+ if (!scatter)
+ goto out;
+
+ sg_init_one(scatter, buffer, size);
+ num_scatter = 1;
+ }
+
+ task->task_proto = task->dev->tproto;
+ task->scatter = scatter;
+ task->num_scatter = num_scatter;
+ task->total_xfer_len = size;
+ task->data_dir = pci_dma_dir;
+ task->task_done = sas_disc_task_done;
+
+ for (retries = 0; retries < 5; retries++) {
+ task->task_state_flags = SAS_TASK_STATE_PENDING;
+ init_completion(&task->completion);
+
+ task->timer.data = (unsigned long) task;
+ task->timer.function = sas_task_timedout;
+ task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+ if (res) {
+ del_timer(&task->timer);
+ SAS_DPRINTK("executing SAS discovery task failed:%d\n",
+ res);
+ goto ex_err;
+ }
+ wait_for_completion(&task->completion);
+ res = -ETASK;
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ int res2;
+ SAS_DPRINTK("task aborted, flags:0x%x\n",
+ task->task_state_flags);
+ res2 = i->dft->lldd_abort_task(task);
+ SAS_DPRINTK("came back from abort task\n");
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ if (res2 == TMF_RESP_FUNC_COMPLETE)
+ continue; /* Retry the task */
+ else
+ goto ex_err;
+ }
+ }
+ if (task->task_status.stat == SAM_BUSY ||
+ task->task_status.stat == SAM_TASK_SET_FULL ||
+ task->task_status.stat == SAS_QUEUE_FULL) {
+ SAS_DPRINTK("task: q busy, sleeping...\n");
+ schedule_timeout_interruptible(HZ);
+ } else if (task->task_status.stat == SAM_CHECK_COND) {
+ struct scsi_sense_hdr shdr;
+
+ if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size,
+ &shdr)) {
+ SAS_DPRINTK("couldn't normalize sense\n");
+ continue;
+ }
+ if ((shdr.sense_key == 6 && shdr.asc == 0x29) ||
+ (shdr.sense_key == 2 && shdr.asc == 4 &&
+ shdr.ascq == 1)) {
+ SAS_DPRINTK("device %016llx LUN: %016llx "
+ "powering up or not ready yet, "
+ "sleeping...\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN));
+
+ schedule_timeout_interruptible(5*HZ);
+ } else if (shdr.sense_key == 1) {
+ res = 0;
+ break;
+ } else if (shdr.sense_key == 5) {
+ break;
+ } else {
+ SAS_DPRINTK("dev %016llx LUN: %016llx "
+ "sense key:0x%x ASC:0x%x ASCQ:0x%x"
+ "\n",
+ SAS_ADDR(task->dev->sas_addr),
+ SAS_ADDR(task->ssp_task.LUN),
+ shdr.sense_key,
+ shdr.asc, shdr.ascq);
+ }
+ } else if (task->task_status.resp != SAS_TASK_COMPLETE ||
+ task->task_status.stat != SAM_GOOD) {
+ SAS_DPRINTK("task finished with resp:0x%x, "
+ "stat:0x%x\n",
+ task->task_status.resp,
+ task->task_status.stat);
+ goto ex_err;
+ } else {
+ res = 0;
+ break;
+ }
+ }
+ex_err:
+ if (pci_dma_dir != PCI_DMA_NONE)
+ kfree(scatter);
+out:
+ return res;
+}
+
+/* ---------- Domain device discovery ---------- */
+
+/**
+ * sas_get_port_device -- Discover devices which caused port creation
+ * @port: pointer to struct sas_port of interest
+ *
+ * Devices directly attached to a HA port, have no parent. This is
+ * how we know they are (domain) "root" devices. All other devices
+ * do, and should have their "parent" pointer set appropriately as
+ * soon as a child device is discovered.
+ */
+static int sas_get_port_device(struct asd_sas_port *port)
+{
+ unsigned long flags;
+ struct asd_sas_phy *phy;
+ struct sas_rphy *rphy;
+ struct domain_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&port->phy_list_lock, flags);
+ if (list_empty(&port->phy_list)) {
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+ kfree(dev);
+ return -ENODEV;
+ }
+ phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el);
+ spin_lock(&phy->frame_rcvd_lock);
+ memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd),
+ (size_t)phy->frame_rcvd_size));
+ spin_unlock(&phy->frame_rcvd_lock);
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+
+ if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) {
+ struct dev_to_host_fis *fis =
+ (struct dev_to_host_fis *) dev->frame_rcvd;
+ if (fis->interrupt_reason == 1 && fis->lbal == 1 &&
+ fis->byte_count_low==0x69 && fis->byte_count_high == 0x96
+ && (fis->device & ~0x10) == 0)
+ dev->dev_type = SATA_PM;
+ else
+ dev->dev_type = SATA_DEV;
+ dev->tproto = SATA_PROTO;
+ } else {
+ struct sas_identify_frame *id =
+ (struct sas_identify_frame *) dev->frame_rcvd;
+ dev->dev_type = id->dev_type;
+ dev->iproto = id->initiator_bits;
+ dev->tproto = id->target_bits;
+ }
+
+ sas_init_dev(dev);
+
+ switch (dev->dev_type) {
+ case SAS_END_DEV:
+ rphy = sas_end_device_alloc(port->port);
+ break;
+ case EDGE_DEV:
+ rphy = sas_expander_alloc(port->port,
+ SAS_EDGE_EXPANDER_DEVICE);
+ break;
+ case FANOUT_DEV:
+ rphy = sas_expander_alloc(port->port,
+ SAS_FANOUT_EXPANDER_DEVICE);
+ break;
+ case SATA_DEV:
+ default:
+ printk("ERROR: Unidentified device type %d\n", dev->dev_type);
+ rphy = NULL;
+ break;
+ }
+
+ if (!rphy) {
+ kfree(dev);
+ return -ENODEV;
+ }
+ rphy->identify.phy_identifier = phy->phy->identify.phy_identifier;
+ memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE);
+ sas_fill_in_rphy(dev, rphy);
+ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+ port->port_dev = dev;
+ dev->port = port;
+ dev->linkrate = port->linkrate;
+ dev->min_linkrate = port->linkrate;
+ dev->max_linkrate = port->linkrate;
+ dev->pathways = port->num_phys;
+ memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE);
+ memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE);
+ memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE);
+ port->disc.max_level = 0;
+
+ dev->rphy = rphy;
+ spin_lock(&port->dev_list_lock);
+ list_add_tail(&dev->dev_list_node, &port->dev_list);
+ spin_unlock(&port->dev_list_lock);
+
+ return 0;
+}
+
+/* ---------- Discover and Revalidate ---------- */
+
+/* ---------- SATA ---------- */
+
+static void sas_get_ata_command_set(struct domain_device *dev)
+{
+ struct dev_to_host_fis *fis =
+ (struct dev_to_host_fis *) dev->frame_rcvd;
+
+ if ((fis->sector_count == 1 && /* ATA */
+ fis->lbal == 1 &&
+ fis->lbam == 0 &&
+ fis->lbah == 0 &&
+ fis->device == 0)
+ ||
+ (fis->sector_count == 0 && /* CE-ATA (mATA) */
+ fis->lbal == 0 &&
+ fis->lbam == 0xCE &&
+ fis->lbah == 0xAA &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATA_COMMAND_SET;
+
+ else if ((fis->interrupt_reason == 1 && /* ATAPI */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x14 &&
+ fis->byte_count_high == 0xEB &&
+ (fis->device & ~0x10) == 0))
+
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+
+ else if ((fis->sector_count == 1 && /* SEMB */
+ fis->lbal == 1 &&
+ fis->lbam == 0x3C &&
+ fis->lbah == 0xC3 &&
+ fis->device == 0)
+ ||
+ (fis->interrupt_reason == 1 && /* SATA PM */
+ fis->lbal == 1 &&
+ fis->byte_count_low == 0x69 &&
+ fis->byte_count_high == 0x96 &&
+ (fis->device & ~0x10) == 0))
+
+ /* Treat it as a superset? */
+ dev->sata_dev.command_set = ATAPI_COMMAND_SET;
+}
+
+/**
+ * sas_issue_ata_cmd -- Basic SATA command processing for discovery
+ * @dev: the device to send the command to
+ * @command: the command register
+ * @features: the features register
+ * @buffer: pointer to buffer to do I/O
+ * @size: size of @buffer
+ * @pci_dma_dir: PCI_DMA_...
+ */
+static int sas_issue_ata_cmd(struct domain_device *dev, u8 command,
+ u8 features, void *buffer, int size,
+ int pci_dma_dir)
+{
+ int res = 0;
+ struct sas_task *task;
+ struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *)
+ &dev->frame_rcvd[0];
+
+ res = -ENOMEM;
+ task = sas_alloc_task(GFP_KERNEL);
+ if (!task)
+ goto out;
+
+ task->dev = dev;
+
+ task->ata_task.fis.command = command;
+ task->ata_task.fis.features = features;
+ task->ata_task.fis.device = d2h_fis->device;
+ task->ata_task.retry_count = 1;
+
+ res = sas_execute_task(task, buffer, size, pci_dma_dir);
+
+ sas_free_task(task);
+out:
+ return res;
+}
+
+static void sas_sata_propagate_sas_addr(struct domain_device *dev)
+{
+ unsigned long flags;
+ struct asd_sas_port *port = dev->port;
+ struct asd_sas_phy *phy;
+
+ BUG_ON(dev->parent);
+
+ memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_lock_irqsave(&port->phy_list_lock, flags);
+ list_for_each_entry(phy, &port->phy_list, port_phy_el)
+ memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE);
+ spin_unlock_irqrestore(&port->phy_list_lock, flags);
+}
+
+#define ATA_IDENTIFY_DEV 0xEC
+#define ATA_IDENTIFY_PACKET_DEV 0xA1
+#define ATA_SET_FEATURES 0xEF
+#define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07
+
+/**
+ * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV)
+ * @dev: STP/SATA device of interest (ATA/ATAPI)
+ *
+ * The LLDD has already been notified of this device, so that we can
+ * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY
+ * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its
+ * performance for this device.
+ */
+static int sas_discover_sata_dev(struct domain_device *dev)
+{
+ int res;
+ __le16 *identify_x;
+ u8 command;
+
+ identify_x = kzalloc(512, GFP_KERNEL);
+ if (!identify_x)
+ return -ENOMEM;
+
+ if (dev->sata_dev.command_set == ATA_COMMAND_SET) {
+ dev->sata_dev.identify_device = identify_x;
+ command = ATA_IDENTIFY_DEV;
+ } else {
+ dev->sata_dev.identify_packet_device = identify_x;
+ command = ATA_IDENTIFY_PACKET_DEV;
+ }
+
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ PCI_DMA_FROMDEVICE);
+ if (res)
+ goto out_err;
+
+ /* lives on the media? */
+ if (le16_to_cpu(identify_x[0]) & 4) {
+ /* incomplete response */
+ SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to "
+ "dev %llx\n", SAS_ADDR(dev->sas_addr));
+ if (!le16_to_cpu(identify_x[83] & (1<<6)))
+ goto cont1;
+ res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES,
+ ATA_FEATURE_PUP_STBY_SPIN_UP,
+ NULL, 0, PCI_DMA_NONE);
+ if (res)
+ goto cont1;
+
+ schedule_timeout_interruptible(5*HZ); /* More time? */
+ res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512,
+ PCI_DMA_FROMDEVICE);
+ if (res)
+ goto out_err;
+ }
+cont1:
+ /* Get WWN */
+ if (dev->port->oob_mode != SATA_OOB_MODE) {
+ memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr,
+ SAS_ADDR_SIZE);
+ } else if (dev->sata_dev.command_set == ATA_COMMAND_SET &&
+ (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000)
+ == 0x5000) {
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ dev->sas_addr[2*i] =
+ (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8;
+ dev->sas_addr[2*i+1] =
+ le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF;
+ }
+ }
+ sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr);
+ if (!dev->parent)
+ sas_sata_propagate_sas_addr(dev);
+
+ /* XXX Hint: register this SATA device with SATL.
+ When this returns, dev->sata_dev->lu is alive and
+ present.
+ sas_satl_register_dev(dev);
+ */
+ return 0;
+out_err:
+ dev->sata_dev.identify_packet_device = NULL;
+ dev->sata_dev.identify_device = NULL;
+ kfree(identify_x);
+ return res;
+}
+
+static int sas_discover_sata_pm(struct domain_device *dev)
+{
+ return -ENODEV;
+}
+
+int sas_notify_lldd_dev_found(struct domain_device *dev)
+{
+ int res = 0;
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct Scsi_Host *shost = sas_ha->core.shost;
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+
+ if (i->dft->lldd_dev_found) {
+ res = i->dft->lldd_dev_found(dev);
+ if (res) {
+ printk("sas: driver on pcidev %s cannot handle "
+ "device %llx, error:%d\n",
+ pci_name(sas_ha->pcidev),
+ SAS_ADDR(dev->sas_addr), res);
+ }
+ }
+ return res;
+}
+
+
+void sas_notify_lldd_dev_gone(struct domain_device *dev)
+{
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct Scsi_Host *shost = sas_ha->core.shost;
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+
+ if (i->dft->lldd_dev_gone)
+ i->dft->lldd_dev_gone(dev);
+}
+
+/* ---------- Common/dispatchers ---------- */
+
+/**
+ * sas_discover_sata -- discover an STP/SATA domain device
+ * @dev: pointer to struct domain_device of interest
+ *
+ * First we notify the LLDD of this device, so we can send frames to
+ * it. Then depending on the type of device we call the appropriate
+ * discover functions. Once device discover is done, we notify the
+ * LLDD so that it can fine-tune its parameters for the device, by
+ * removing it and then adding it. That is, the second time around,
+ * the driver would have certain fields, that it is looking at, set.
+ * Finally we initialize the kobj so that the device can be added to
+ * the system at registration time. Devices directly attached to a HA
+ * port, have no parents. All other devices do, and should have their
+ * "parent" pointer set appropriately before calling this function.
+ */
+int sas_discover_sata(struct domain_device *dev)
+{
+ int res;
+
+ sas_get_ata_command_set(dev);
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ switch (dev->dev_type) {
+ case SATA_DEV:
+ res = sas_discover_sata_dev(dev);
+ break;
+ case SATA_PM:
+ res = sas_discover_sata_pm(dev);
+ break;
+ default:
+ break;
+ }
+
+ sas_notify_lldd_dev_gone(dev);
+ if (!res) {
+ sas_notify_lldd_dev_found(dev);
+ }
+ return res;
+}
+
+/**
+ * sas_discover_end_dev -- discover an end device (SSP, etc)
+ * @end: pointer to domain device of interest
+ *
+ * See comment in sas_discover_sata().
+ */
+int sas_discover_end_dev(struct domain_device *dev)
+{
+ int res;
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ res = sas_rphy_add(dev->rphy);
+ if (res)
+ goto out_err;
+
+ /* do this to get the end device port attributes which will have
+ * been scanned in sas_rphy_add */
+ sas_notify_lldd_dev_gone(dev);
+ sas_notify_lldd_dev_found(dev);
+
+ return 0;
+
+out_err:
+ sas_notify_lldd_dev_gone(dev);
+ return res;
+}
+
+/* ---------- Device registration and unregistration ---------- */
+
+static inline void sas_unregister_common_dev(struct domain_device *dev)
+{
+ sas_notify_lldd_dev_gone(dev);
+ if (!dev->parent)
+ dev->port->port_dev = NULL;
+ else
+ list_del_init(&dev->siblings);
+ list_del_init(&dev->dev_list_node);
+}
+
+void sas_unregister_dev(struct domain_device *dev)
+{
+ if (dev->rphy) {
+ sas_remove_children(&dev->rphy->dev);
+ sas_rphy_delete(dev->rphy);
+ dev->rphy = NULL;
+ }
+ if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
+ /* remove the phys and ports, everything else should be gone */
+ kfree(dev->ex_dev.ex_phy);
+ dev->ex_dev.ex_phy = NULL;
+ }
+ sas_unregister_common_dev(dev);
+}
+
+void sas_unregister_domain_devices(struct asd_sas_port *port)
+{
+ struct domain_device *dev, *n;
+
+ list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node)
+ sas_unregister_dev(dev);
+
+ port->port->rphy = NULL;
+
+}
+
+/* ---------- Discovery and Revalidation ---------- */
+
+/**
+ * sas_discover_domain -- discover the domain
+ * @port: port to the domain of interest
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered. Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.
+ */
+static void sas_discover_domain(void *data)
+{
+ int error = 0;
+ struct asd_sas_port *port = data;
+
+ sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock,
+ &port->disc.pending);
+
+ if (port->port_dev)
+ return ;
+ else {
+ error = sas_get_port_device(port);
+ if (error)
+ return;
+ }
+
+ SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id,
+ current->pid);
+
+ switch (port->port_dev->dev_type) {
+ case SAS_END_DEV:
+ error = sas_discover_end_dev(port->port_dev);
+ break;
+ case EDGE_DEV:
+ case FANOUT_DEV:
+ error = sas_discover_root_expander(port->port_dev);
+ break;
+ case SATA_DEV:
+ case SATA_PM:
+ error = sas_discover_sata(port->port_dev);
+ break;
+ default:
+ SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type);
+ break;
+ }
+
+ if (error) {
+ kfree(port->port_dev); /* not kobject_register-ed yet */
+ port->port_dev = NULL;
+ }
+
+ SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id,
+ current->pid, error);
+}
+
+static void sas_revalidate_domain(void *data)
+{
+ int res = 0;
+ struct asd_sas_port *port = data;
+
+ sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock,
+ &port->disc.pending);
+
+ SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id,
+ current->pid);
+ if (port->port_dev)
+ res = sas_ex_revalidate_domain(port->port_dev);
+
+ SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n",
+ port->id, current->pid, res);
+}
+
+/* ---------- Events ---------- */
+
+int sas_discover_event(struct asd_sas_port *port, enum discover_event ev)
+{
+ struct sas_discovery *disc;
+
+ if (!port)
+ return 0;
+ disc = &port->disc;
+
+ BUG_ON(ev >= DISC_NUM_EVENTS);
+
+ sas_queue_event(ev, &disc->disc_event_lock, &disc->pending,
+ &disc->disc_work[ev], port->ha->core.shost);
+
+ return 0;
+}
+
+/**
+ * sas_init_disc -- initialize the discovery struct in the port
+ * @port: pointer to struct port
+ *
+ * Called when the ports are being initialized.
+ */
+void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
+{
+ int i;
+
+ static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = {
+ [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
+ [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
+ };
+
+ spin_lock_init(&disc->disc_event_lock);
+ disc->pending = 0;
+ for (i = 0; i < DISC_NUM_EVENTS; i++)
+ INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port);
+}
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c
new file mode 100644
index 00000000000..f1246d2c9be
--- /dev/null
+++ b/drivers/scsi/libsas/sas_dump.c
@@ -0,0 +1,76 @@
+/*
+ * Serial Attached SCSI (SAS) Dump/Debugging routines
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sas_dump.h"
+
+#ifdef SAS_DEBUG
+
+static const char *sas_hae_str[] = {
+ [0] = "HAE_RESET",
+};
+
+static const char *sas_porte_str[] = {
+ [0] = "PORTE_BYTES_DMAED",
+ [1] = "PORTE_BROADCAST_RCVD",
+ [2] = "PORTE_LINK_RESET_ERR",
+ [3] = "PORTE_TIMER_EVENT",
+ [4] = "PORTE_HARD_RESET",
+};
+
+static const char *sas_phye_str[] = {
+ [0] = "PHYE_LOSS_OF_SIGNAL",
+ [1] = "PHYE_OOB_DONE",
+ [2] = "PHYE_OOB_ERROR",
+ [3] = "PHYE_SPINUP_HOLD",
+};
+
+void sas_dprint_porte(int phyid, enum port_event pe)
+{
+ SAS_DPRINTK("phy%d: port event: %s\n", phyid, sas_porte_str[pe]);
+}
+void sas_dprint_phye(int phyid, enum phy_event pe)
+{
+ SAS_DPRINTK("phy%d: phy event: %s\n", phyid, sas_phye_str[pe]);
+}
+
+void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he)
+{
+ SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev),
+ sas_hae_str[he]);
+}
+
+void sas_dump_port(struct asd_sas_port *port)
+{
+ SAS_DPRINTK("port%d: class:0x%x\n", port->id, port->class);
+ SAS_DPRINTK("port%d: sas_addr:%llx\n", port->id,
+ SAS_ADDR(port->sas_addr));
+ SAS_DPRINTK("port%d: attached_sas_addr:%llx\n", port->id,
+ SAS_ADDR(port->attached_sas_addr));
+ SAS_DPRINTK("port%d: iproto:0x%x\n", port->id, port->iproto);
+ SAS_DPRINTK("port%d: tproto:0x%x\n", port->id, port->tproto);
+ SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode);
+ SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys);
+}
+
+#endif /* SAS_DEBUG */
diff --git a/drivers/scsi/libsas/sas_dump.h b/drivers/scsi/libsas/sas_dump.h
new file mode 100644
index 00000000000..47b45d4f525
--- /dev/null
+++ b/drivers/scsi/libsas/sas_dump.h
@@ -0,0 +1,42 @@
+/*
+ * Serial Attached SCSI (SAS) Dump/Debugging routines header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sas_internal.h"
+
+#ifdef SAS_DEBUG
+
+void sas_dprint_porte(int phyid, enum port_event pe);
+void sas_dprint_phye(int phyid, enum phy_event pe);
+void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he);
+void sas_dump_port(struct asd_sas_port *port);
+
+#else /* SAS_DEBUG */
+
+static inline void sas_dprint_porte(int phyid, enum port_event pe) { }
+static inline void sas_dprint_phye(int phyid, enum phy_event pe) { }
+static inline void sas_dprint_hae(struct sas_ha_struct *sas_ha,
+ enum ha_event he) { }
+static inline void sas_dump_port(struct asd_sas_port *port) { }
+
+#endif /* SAS_DEBUG */
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c
new file mode 100644
index 00000000000..19110ed1c89
--- /dev/null
+++ b/drivers/scsi/libsas/sas_event.c
@@ -0,0 +1,75 @@
+/*
+ * Serial Attached SCSI (SAS) Event processing
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <scsi/scsi_host.h>
+#include "sas_internal.h"
+#include "sas_dump.h"
+
+static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event)
+{
+ BUG_ON(event >= HA_NUM_EVENTS);
+
+ sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending,
+ &sas_ha->ha_events[event], sas_ha->core.shost);
+}
+
+static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
+{
+ struct sas_ha_struct *ha = phy->ha;
+
+ BUG_ON(event >= PORT_NUM_EVENTS);
+
+ sas_queue_event(event, &ha->event_lock, &phy->port_events_pending,
+ &phy->port_events[event], ha->core.shost);
+}
+
+static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+{
+ struct sas_ha_struct *ha = phy->ha;
+
+ BUG_ON(event >= PHY_NUM_EVENTS);
+
+ sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending,
+ &phy->phy_events[event], ha->core.shost);
+}
+
+int sas_init_events(struct sas_ha_struct *sas_ha)
+{
+ static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = {
+ [HAE_RESET] = sas_hae_reset,
+ };
+
+ int i;
+
+ spin_lock_init(&sas_ha->event_lock);
+
+ for (i = 0; i < HA_NUM_EVENTS; i++)
+ INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha);
+
+ sas_ha->notify_ha_event = notify_ha_event;
+ sas_ha->notify_port_event = notify_port_event;
+ sas_ha->notify_phy_event = notify_phy_event;
+
+ return 0;
+}
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
new file mode 100644
index 00000000000..30b8014bcc7
--- /dev/null
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -0,0 +1,1855 @@
+/*
+ * Serial Attached SCSI (SAS) Expander discovery and configuration
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+static int sas_discover_expander(struct domain_device *dev);
+static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr);
+static int sas_configure_phy(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int include);
+static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr);
+
+#if 0
+/* FIXME: smp needs to migrate into the sas class */
+static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t);
+static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t);
+#endif
+
+/* ---------- SMP task management ---------- */
+
+static void smp_task_timedout(unsigned long _task)
+{
+ struct sas_task *task = (void *) _task;
+ unsigned long flags;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE))
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ complete(&task->completion);
+}
+
+static void smp_task_done(struct sas_task *task)
+{
+ if (!del_timer(&task->timer))
+ return;
+ complete(&task->completion);
+}
+
+/* Give it some long enough timeout. In seconds. */
+#define SMP_TIMEOUT 10
+
+static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
+ void *resp, int resp_size)
+{
+ int res;
+ struct sas_task *task = sas_alloc_task(GFP_KERNEL);
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+
+ if (!task)
+ return -ENOMEM;
+
+ task->dev = dev;
+ task->task_proto = dev->tproto;
+ sg_init_one(&task->smp_task.smp_req, req, req_size);
+ sg_init_one(&task->smp_task.smp_resp, resp, resp_size);
+
+ task->task_done = smp_task_done;
+
+ task->timer.data = (unsigned long) task;
+ task->timer.function = smp_task_timedout;
+ task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
+ add_timer(&task->timer);
+
+ res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+
+ if (res) {
+ del_timer(&task->timer);
+ SAS_DPRINTK("executing SMP task failed:%d\n", res);
+ goto ex_err;
+ }
+
+ wait_for_completion(&task->completion);
+ res = -ETASK;
+ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
+ SAS_DPRINTK("smp task timed out or aborted\n");
+ i->dft->lldd_abort_task(task);
+ if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
+ SAS_DPRINTK("SMP task aborted and not done\n");
+ goto ex_err;
+ }
+ }
+ if (task->task_status.resp == SAS_TASK_COMPLETE &&
+ task->task_status.stat == SAM_GOOD)
+ res = 0;
+ else
+ SAS_DPRINTK("%s: task to dev %016llx response: 0x%x "
+ "status 0x%x\n", __FUNCTION__,
+ SAS_ADDR(dev->sas_addr),
+ task->task_status.resp,
+ task->task_status.stat);
+ex_err:
+ sas_free_task(task);
+ return res;
+}
+
+/* ---------- Allocations ---------- */
+
+static inline void *alloc_smp_req(int size)
+{
+ u8 *p = kzalloc(size, GFP_KERNEL);
+ if (p)
+ p[0] = SMP_REQUEST;
+ return p;
+}
+
+static inline void *alloc_smp_resp(int size)
+{
+ return kzalloc(size, GFP_KERNEL);
+}
+
+/* ---------- Expander configuration ---------- */
+
+static void sas_set_ex_phy(struct domain_device *dev, int phy_id,
+ void *disc_resp)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ struct smp_resp *resp = disc_resp;
+ struct discover_resp *dr = &resp->disc;
+ struct sas_rphy *rphy = dev->rphy;
+ int rediscover = (phy->phy != NULL);
+
+ if (!rediscover) {
+ phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
+
+ /* FIXME: error_handling */
+ BUG_ON(!phy->phy);
+ }
+
+ switch (resp->result) {
+ case SMP_RESP_PHY_VACANT:
+ phy->phy_state = PHY_VACANT;
+ return;
+ default:
+ phy->phy_state = PHY_NOT_PRESENT;
+ return;
+ case SMP_RESP_FUNC_ACC:
+ phy->phy_state = PHY_EMPTY; /* do not know yet */
+ break;
+ }
+
+ phy->phy_id = phy_id;
+ phy->attached_dev_type = dr->attached_dev_type;
+ phy->linkrate = dr->linkrate;
+ phy->attached_sata_host = dr->attached_sata_host;
+ phy->attached_sata_dev = dr->attached_sata_dev;
+ phy->attached_sata_ps = dr->attached_sata_ps;
+ phy->attached_iproto = dr->iproto << 1;
+ phy->attached_tproto = dr->tproto << 1;
+ memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);
+ phy->attached_phy_id = dr->attached_phy_id;
+ phy->phy_change_count = dr->change_count;
+ phy->routing_attr = dr->routing_attr;
+ phy->virtual = dr->virtual;
+ phy->last_da_index = -1;
+
+ phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
+ phy->phy->identify.target_port_protocols = phy->attached_tproto;
+ phy->phy->identify.phy_identifier = phy_id;
+ phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
+ phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
+ phy->phy->minimum_linkrate = dr->pmin_linkrate;
+ phy->phy->maximum_linkrate = dr->pmax_linkrate;
+ phy->phy->negotiated_linkrate = phy->linkrate;
+
+ if (!rediscover)
+ sas_phy_add(phy->phy);
+
+ SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n",
+ SAS_ADDR(dev->sas_addr), phy->phy_id,
+ phy->routing_attr == TABLE_ROUTING ? 'T' :
+ phy->routing_attr == DIRECT_ROUTING ? 'D' :
+ phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?',
+ SAS_ADDR(phy->attached_sas_addr));
+
+ return;
+}
+
+#define DISCOVER_REQ_SIZE 16
+#define DISCOVER_RESP_SIZE 56
+
+static int sas_ex_phy_discover(struct domain_device *dev, int single)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int res = 0;
+ u8 *disc_req;
+ u8 *disc_resp;
+
+ disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
+ if (!disc_req)
+ return -ENOMEM;
+
+ disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE);
+ if (!disc_resp) {
+ kfree(disc_req);
+ return -ENOMEM;
+ }
+
+ disc_req[1] = SMP_DISCOVER;
+
+ if (0 <= single && single < ex->num_phys) {
+ disc_req[9] = single;
+ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+ disc_resp, DISCOVER_RESP_SIZE);
+ if (res)
+ goto out_err;
+ sas_set_ex_phy(dev, single, disc_resp);
+ } else {
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ disc_req[9] = i;
+ res = smp_execute_task(dev, disc_req,
+ DISCOVER_REQ_SIZE, disc_resp,
+ DISCOVER_RESP_SIZE);
+ if (res)
+ goto out_err;
+ sas_set_ex_phy(dev, i, disc_resp);
+ }
+ }
+out_err:
+ kfree(disc_resp);
+ kfree(disc_req);
+ return res;
+}
+
+static int sas_expander_discover(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int res = -ENOMEM;
+
+ ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL);
+ if (!ex->ex_phy)
+ return -ENOMEM;
+
+ res = sas_ex_phy_discover(dev, -1);
+ if (res)
+ goto out_err;
+
+ return 0;
+ out_err:
+ kfree(ex->ex_phy);
+ ex->ex_phy = NULL;
+ return res;
+}
+
+#define MAX_EXPANDER_PHYS 128
+
+static void ex_assign_report_general(struct domain_device *dev,
+ struct smp_resp *resp)
+{
+ struct report_general_resp *rg = &resp->rg;
+
+ dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count);
+ dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes);
+ dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS);
+ dev->ex_dev.conf_route_table = rg->conf_route_table;
+ dev->ex_dev.configuring = rg->configuring;
+ memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8);
+}
+
+#define RG_REQ_SIZE 8
+#define RG_RESP_SIZE 32
+
+static int sas_ex_general(struct domain_device *dev)
+{
+ u8 *rg_req;
+ struct smp_resp *rg_resp;
+ int res;
+ int i;
+
+ rg_req = alloc_smp_req(RG_REQ_SIZE);
+ if (!rg_req)
+ return -ENOMEM;
+
+ rg_resp = alloc_smp_resp(RG_RESP_SIZE);
+ if (!rg_resp) {
+ kfree(rg_req);
+ return -ENOMEM;
+ }
+
+ rg_req[1] = SMP_REPORT_GENERAL;
+
+ for (i = 0; i < 5; i++) {
+ res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
+ RG_RESP_SIZE);
+
+ if (res) {
+ SAS_DPRINTK("RG to ex %016llx failed:0x%x\n",
+ SAS_ADDR(dev->sas_addr), res);
+ goto out;
+ } else if (rg_resp->result != SMP_RESP_FUNC_ACC) {
+ SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n",
+ SAS_ADDR(dev->sas_addr), rg_resp->result);
+ res = rg_resp->result;
+ goto out;
+ }
+
+ ex_assign_report_general(dev, rg_resp);
+
+ if (dev->ex_dev.configuring) {
+ SAS_DPRINTK("RG: ex %llx self-configuring...\n",
+ SAS_ADDR(dev->sas_addr));
+ schedule_timeout_interruptible(5*HZ);
+ } else
+ break;
+ }
+out:
+ kfree(rg_req);
+ kfree(rg_resp);
+ return res;
+}
+
+static void ex_assign_manuf_info(struct domain_device *dev, void
+ *_mi_resp)
+{
+ u8 *mi_resp = _mi_resp;
+ struct sas_rphy *rphy = dev->rphy;
+ struct sas_expander_device *edev = rphy_to_expander_device(rphy);
+
+ memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN);
+ memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN);
+ memcpy(edev->product_rev, mi_resp + 36,
+ SAS_EXPANDER_PRODUCT_REV_LEN);
+
+ if (mi_resp[8] & 1) {
+ memcpy(edev->component_vendor_id, mi_resp + 40,
+ SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
+ edev->component_id = mi_resp[48] << 8 | mi_resp[49];
+ edev->component_revision_id = mi_resp[50];
+ }
+}
+
+#define MI_REQ_SIZE 8
+#define MI_RESP_SIZE 64
+
+static int sas_ex_manuf_info(struct domain_device *dev)
+{
+ u8 *mi_req;
+ u8 *mi_resp;
+ int res;
+
+ mi_req = alloc_smp_req(MI_REQ_SIZE);
+ if (!mi_req)
+ return -ENOMEM;
+
+ mi_resp = alloc_smp_resp(MI_RESP_SIZE);
+ if (!mi_resp) {
+ kfree(mi_req);
+ return -ENOMEM;
+ }
+
+ mi_req[1] = SMP_REPORT_MANUF_INFO;
+
+ res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE);
+ if (res) {
+ SAS_DPRINTK("MI: ex %016llx failed:0x%x\n",
+ SAS_ADDR(dev->sas_addr), res);
+ goto out;
+ } else if (mi_resp[2] != SMP_RESP_FUNC_ACC) {
+ SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n",
+ SAS_ADDR(dev->sas_addr), mi_resp[2]);
+ goto out;
+ }
+
+ ex_assign_manuf_info(dev, mi_resp);
+out:
+ kfree(mi_req);
+ kfree(mi_resp);
+ return res;
+}
+
+#define PC_REQ_SIZE 44
+#define PC_RESP_SIZE 8
+
+int sas_smp_phy_control(struct domain_device *dev, int phy_id,
+ enum phy_func phy_func,
+ struct sas_phy_linkrates *rates)
+{
+ u8 *pc_req;
+ u8 *pc_resp;
+ int res;
+
+ pc_req = alloc_smp_req(PC_REQ_SIZE);
+ if (!pc_req)
+ return -ENOMEM;
+
+ pc_resp = alloc_smp_resp(PC_RESP_SIZE);
+ if (!pc_resp) {
+ kfree(pc_req);
+ return -ENOMEM;
+ }
+
+ pc_req[1] = SMP_PHY_CONTROL;
+ pc_req[9] = phy_id;
+ pc_req[10]= phy_func;
+ if (rates) {
+ pc_req[32] = rates->minimum_linkrate << 4;
+ pc_req[33] = rates->maximum_linkrate << 4;
+ }
+
+ res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
+
+ kfree(pc_resp);
+ kfree(pc_req);
+ return res;
+}
+
+static void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+
+ sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL);
+ phy->linkrate = SAS_PHY_DISABLED;
+}
+
+static void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr))
+ sas_ex_disable_phy(dev, i);
+ }
+}
+
+static int sas_dev_present_in_domain(struct asd_sas_port *port,
+ u8 *sas_addr)
+{
+ struct domain_device *dev;
+
+ if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr))
+ return 1;
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr))
+ return 1;
+ }
+ return 0;
+}
+
+#define RPEL_REQ_SIZE 16
+#define RPEL_RESP_SIZE 32
+int sas_smp_get_phy_events(struct sas_phy *phy)
+{
+ int res;
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *dev = sas_find_dev_by_rphy(rphy);
+ u8 *req = alloc_smp_req(RPEL_REQ_SIZE);
+ u8 *resp = kzalloc(RPEL_RESP_SIZE, GFP_KERNEL);
+
+ if (!resp)
+ return -ENOMEM;
+
+ req[1] = SMP_REPORT_PHY_ERR_LOG;
+ req[9] = phy->number;
+
+ res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
+ resp, RPEL_RESP_SIZE);
+
+ if (!res)
+ goto out;
+
+ phy->invalid_dword_count = scsi_to_u32(&resp[12]);
+ phy->running_disparity_error_count = scsi_to_u32(&resp[16]);
+ phy->loss_of_dword_sync_count = scsi_to_u32(&resp[20]);
+ phy->phy_reset_problem_count = scsi_to_u32(&resp[24]);
+
+ out:
+ kfree(resp);
+ return res;
+
+}
+
+#define RPS_REQ_SIZE 16
+#define RPS_RESP_SIZE 60
+
+static int sas_get_report_phy_sata(struct domain_device *dev,
+ int phy_id,
+ struct smp_resp *rps_resp)
+{
+ int res;
+ u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
+
+ if (!rps_req)
+ return -ENOMEM;
+
+ rps_req[1] = SMP_REPORT_PHY_SATA;
+ rps_req[9] = phy_id;
+
+ res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
+ rps_resp, RPS_RESP_SIZE);
+
+ kfree(rps_req);
+ return 0;
+}
+
+static void sas_ex_get_linkrate(struct domain_device *parent,
+ struct domain_device *child,
+ struct ex_phy *parent_phy)
+{
+ struct expander_device *parent_ex = &parent->ex_dev;
+ struct sas_port *port;
+ int i;
+
+ child->pathways = 0;
+
+ port = parent_phy->port;
+
+ for (i = 0; i < parent_ex->num_phys; i++) {
+ struct ex_phy *phy = &parent_ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(child->sas_addr)) {
+
+ child->min_linkrate = min(parent->min_linkrate,
+ phy->linkrate);
+ child->max_linkrate = max(parent->max_linkrate,
+ phy->linkrate);
+ child->pathways++;
+ sas_port_add_phy(port, phy->phy);
+ }
+ }
+ child->linkrate = min(parent_phy->linkrate, child->max_linkrate);
+ child->pathways = min(child->pathways, parent->pathways);
+}
+
+static struct domain_device *sas_ex_discover_end_dev(
+ struct domain_device *parent, int phy_id)
+{
+ struct expander_device *parent_ex = &parent->ex_dev;
+ struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
+ struct domain_device *child = NULL;
+ struct sas_rphy *rphy;
+ int res;
+
+ if (phy->attached_sata_host || phy->attached_sata_ps)
+ return NULL;
+
+ child = kzalloc(sizeof(*child), GFP_KERNEL);
+ if (!child)
+ return NULL;
+
+ child->parent = parent;
+ child->port = parent->port;
+ child->iproto = phy->attached_iproto;
+ memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+ sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
+ phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
+ BUG_ON(!phy->port);
+ /* FIXME: better error handling*/
+ BUG_ON(sas_port_add(phy->port) != 0);
+ sas_ex_get_linkrate(parent, child, phy);
+
+ if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) {
+ child->dev_type = SATA_DEV;
+ if (phy->attached_tproto & SAS_PROTO_STP)
+ child->tproto = phy->attached_tproto;
+ if (phy->attached_sata_dev)
+ child->tproto |= SATA_DEV;
+ res = sas_get_report_phy_sata(parent, phy_id,
+ &child->sata_dev.rps_resp);
+ if (res) {
+ SAS_DPRINTK("report phy sata to %016llx:0x%x returned "
+ "0x%x\n", SAS_ADDR(parent->sas_addr),
+ phy_id, res);
+ kfree(child);
+ return NULL;
+ }
+ memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis,
+ sizeof(struct dev_to_host_fis));
+ sas_init_dev(child);
+ res = sas_discover_sata(child);
+ if (res) {
+ SAS_DPRINTK("sas_discover_sata() for device %16llx at "
+ "%016llx:0x%x returned 0x%x\n",
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(parent->sas_addr), phy_id, res);
+ kfree(child);
+ return NULL;
+ }
+ } else if (phy->attached_tproto & SAS_PROTO_SSP) {
+ child->dev_type = SAS_END_DEV;
+ rphy = sas_end_device_alloc(phy->port);
+ /* FIXME: error handling */
+ BUG_ON(!rphy);
+ child->tproto = phy->attached_tproto;
+ sas_init_dev(child);
+
+ child->rphy = rphy;
+ sas_fill_in_rphy(child, rphy);
+
+ spin_lock(&parent->port->dev_list_lock);
+ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+ spin_unlock(&parent->port->dev_list_lock);
+
+ res = sas_discover_end_dev(child);
+ if (res) {
+ SAS_DPRINTK("sas_discover_end_dev() for device %16llx "
+ "at %016llx:0x%x returned 0x%x\n",
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(parent->sas_addr), phy_id, res);
+ /* FIXME: this kfrees list elements without removing them */
+ //kfree(child);
+ return NULL;
+ }
+ } else {
+ SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n",
+ phy->attached_tproto, SAS_ADDR(parent->sas_addr),
+ phy_id);
+ }
+
+ list_add_tail(&child->siblings, &parent_ex->children);
+ return child;
+}
+
+static struct domain_device *sas_ex_discover_expander(
+ struct domain_device *parent, int phy_id)
+{
+ struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy);
+ struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
+ struct domain_device *child = NULL;
+ struct sas_rphy *rphy;
+ struct sas_expander_device *edev;
+ struct asd_sas_port *port;
+ int res;
+
+ if (phy->routing_attr == DIRECT_ROUTING) {
+ SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not "
+ "allowed\n",
+ SAS_ADDR(parent->sas_addr), phy_id,
+ SAS_ADDR(phy->attached_sas_addr),
+ phy->attached_phy_id);
+ return NULL;
+ }
+ child = kzalloc(sizeof(*child), GFP_KERNEL);
+ if (!child)
+ return NULL;
+
+ phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
+ /* FIXME: better error handling */
+ BUG_ON(sas_port_add(phy->port) != 0);
+
+
+ switch (phy->attached_dev_type) {
+ case EDGE_DEV:
+ rphy = sas_expander_alloc(phy->port,
+ SAS_EDGE_EXPANDER_DEVICE);
+ break;
+ case FANOUT_DEV:
+ rphy = sas_expander_alloc(phy->port,
+ SAS_FANOUT_EXPANDER_DEVICE);
+ break;
+ default:
+ rphy = NULL; /* shut gcc up */
+ BUG();
+ }
+ port = parent->port;
+ child->rphy = rphy;
+ edev = rphy_to_expander_device(rphy);
+ child->dev_type = phy->attached_dev_type;
+ child->parent = parent;
+ child->port = port;
+ child->iproto = phy->attached_iproto;
+ child->tproto = phy->attached_tproto;
+ memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
+ sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
+ sas_ex_get_linkrate(parent, child, phy);
+ edev->level = parent_ex->level + 1;
+ parent->port->disc.max_level = max(parent->port->disc.max_level,
+ edev->level);
+ sas_init_dev(child);
+ sas_fill_in_rphy(child, rphy);
+ sas_rphy_add(rphy);
+
+ spin_lock(&parent->port->dev_list_lock);
+ list_add_tail(&child->dev_list_node, &parent->port->dev_list);
+ spin_unlock(&parent->port->dev_list_lock);
+
+ res = sas_discover_expander(child);
+ if (res) {
+ kfree(child);
+ return NULL;
+ }
+ list_add_tail(&child->siblings, &parent->ex_dev.children);
+ return child;
+}
+
+static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
+ struct domain_device *child = NULL;
+ int res = 0;
+
+ /* Phy state */
+ if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) {
+ if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL))
+ res = sas_ex_phy_discover(dev, phy_id);
+ if (res)
+ return res;
+ }
+
+ /* Parent and domain coherency */
+ if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
+ SAS_ADDR(dev->port->sas_addr))) {
+ sas_add_parent_port(dev, phy_id);
+ return 0;
+ }
+ if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
+ SAS_ADDR(dev->parent->sas_addr))) {
+ sas_add_parent_port(dev, phy_id);
+ if (ex_phy->routing_attr == TABLE_ROUTING)
+ sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1);
+ return 0;
+ }
+
+ if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr))
+ sas_ex_disable_port(dev, ex_phy->attached_sas_addr);
+
+ if (ex_phy->attached_dev_type == NO_DEVICE) {
+ if (ex_phy->routing_attr == DIRECT_ROUTING) {
+ memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ sas_configure_routing(dev, ex_phy->attached_sas_addr);
+ }
+ return 0;
+ } else if (ex_phy->linkrate == SAS_LINK_RATE_UNKNOWN)
+ return 0;
+
+ if (ex_phy->attached_dev_type != SAS_END_DEV &&
+ ex_phy->attached_dev_type != FANOUT_DEV &&
+ ex_phy->attached_dev_type != EDGE_DEV) {
+ SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx "
+ "phy 0x%x\n", ex_phy->attached_dev_type,
+ SAS_ADDR(dev->sas_addr),
+ phy_id);
+ return 0;
+ }
+
+ res = sas_configure_routing(dev, ex_phy->attached_sas_addr);
+ if (res) {
+ SAS_DPRINTK("configure routing for dev %016llx "
+ "reported 0x%x. Forgotten\n",
+ SAS_ADDR(ex_phy->attached_sas_addr), res);
+ sas_disable_routing(dev, ex_phy->attached_sas_addr);
+ return res;
+ }
+
+ switch (ex_phy->attached_dev_type) {
+ case SAS_END_DEV:
+ child = sas_ex_discover_end_dev(dev, phy_id);
+ break;
+ case FANOUT_DEV:
+ if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
+ SAS_DPRINTK("second fanout expander %016llx phy 0x%x "
+ "attached to ex %016llx phy 0x%x\n",
+ SAS_ADDR(ex_phy->attached_sas_addr),
+ ex_phy->attached_phy_id,
+ SAS_ADDR(dev->sas_addr),
+ phy_id);
+ sas_ex_disable_phy(dev, phy_id);
+ break;
+ } else
+ memcpy(dev->port->disc.fanout_sas_addr,
+ ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
+ /* fallthrough */
+ case EDGE_DEV:
+ child = sas_ex_discover_expander(dev, phy_id);
+ break;
+ default:
+ break;
+ }
+
+ if (child) {
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ if (ex->ex_phy[i].phy_state == PHY_VACANT ||
+ ex->ex_phy[i].phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) ==
+ SAS_ADDR(child->sas_addr))
+ ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED;
+ }
+ }
+
+ return res;
+}
+
+static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if ((phy->attached_dev_type == EDGE_DEV ||
+ phy->attached_dev_type == FANOUT_DEV) &&
+ phy->routing_attr == SUBTRACTIVE_ROUTING) {
+
+ memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE);
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int sas_check_level_subtractive_boundary(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct domain_device *child;
+ u8 sub_addr[8] = {0, };
+
+ list_for_each_entry(child, &ex->children, siblings) {
+ if (child->dev_type != EDGE_DEV &&
+ child->dev_type != FANOUT_DEV)
+ continue;
+ if (sub_addr[0] == 0) {
+ sas_find_sub_addr(child, sub_addr);
+ continue;
+ } else {
+ u8 s2[8];
+
+ if (sas_find_sub_addr(child, s2) &&
+ (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
+
+ SAS_DPRINTK("ex %016llx->%016llx-?->%016llx "
+ "diverges from subtractive "
+ "boundary %016llx\n",
+ SAS_ADDR(dev->sas_addr),
+ SAS_ADDR(child->sas_addr),
+ SAS_ADDR(s2),
+ SAS_ADDR(sub_addr));
+
+ sas_ex_disable_port(child, s2);
+ }
+ }
+ }
+ return 0;
+}
+/**
+ * sas_ex_discover_devices -- discover devices attached to this expander
+ * dev: pointer to the expander domain device
+ * single: if you want to do a single phy, else set to -1;
+ *
+ * Configure this expander for use with its devices and register the
+ * devices of this expander.
+ */
+static int sas_ex_discover_devices(struct domain_device *dev, int single)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i = 0, end = ex->num_phys;
+ int res = 0;
+
+ if (0 <= single && single < end) {
+ i = single;
+ end = i+1;
+ }
+
+ for ( ; i < end; i++) {
+ struct ex_phy *ex_phy = &ex->ex_phy[i];
+
+ if (ex_phy->phy_state == PHY_VACANT ||
+ ex_phy->phy_state == PHY_NOT_PRESENT ||
+ ex_phy->phy_state == PHY_DEVICE_DISCOVERED)
+ continue;
+
+ switch (ex_phy->linkrate) {
+ case SAS_PHY_DISABLED:
+ case SAS_PHY_RESET_PROBLEM:
+ case SAS_SATA_PORT_SELECTOR:
+ continue;
+ default:
+ res = sas_ex_discover_dev(dev, i);
+ if (res)
+ break;
+ continue;
+ }
+ }
+
+ if (!res)
+ sas_check_level_subtractive_boundary(dev);
+
+ return res;
+}
+
+static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int i;
+ u8 *sub_sas_addr = NULL;
+
+ if (dev->dev_type != EDGE_DEV)
+ return 0;
+
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (phy->phy_state == PHY_VACANT ||
+ phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if ((phy->attached_dev_type == FANOUT_DEV ||
+ phy->attached_dev_type == EDGE_DEV) &&
+ phy->routing_attr == SUBTRACTIVE_ROUTING) {
+
+ if (!sub_sas_addr)
+ sub_sas_addr = &phy->attached_sas_addr[0];
+ else if (SAS_ADDR(sub_sas_addr) !=
+ SAS_ADDR(phy->attached_sas_addr)) {
+
+ SAS_DPRINTK("ex %016llx phy 0x%x "
+ "diverges(%016llx) on subtractive "
+ "boundary(%016llx). Disabled\n",
+ SAS_ADDR(dev->sas_addr), i,
+ SAS_ADDR(phy->attached_sas_addr),
+ SAS_ADDR(sub_sas_addr));
+ sas_ex_disable_phy(dev, i);
+ }
+ }
+ }
+ return 0;
+}
+
+static void sas_print_parent_topology_bug(struct domain_device *child,
+ struct ex_phy *parent_phy,
+ struct ex_phy *child_phy)
+{
+ static const char ra_char[] = {
+ [DIRECT_ROUTING] = 'D',
+ [SUBTRACTIVE_ROUTING] = 'S',
+ [TABLE_ROUTING] = 'T',
+ };
+ static const char *ex_type[] = {
+ [EDGE_DEV] = "edge",
+ [FANOUT_DEV] = "fanout",
+ };
+ struct domain_device *parent = child->parent;
+
+ sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x "
+ "has %c:%c routing link!\n",
+
+ ex_type[parent->dev_type],
+ SAS_ADDR(parent->sas_addr),
+ parent_phy->phy_id,
+
+ ex_type[child->dev_type],
+ SAS_ADDR(child->sas_addr),
+ child_phy->phy_id,
+
+ ra_char[parent_phy->routing_attr],
+ ra_char[child_phy->routing_attr]);
+}
+
+static int sas_check_eeds(struct domain_device *child,
+ struct ex_phy *parent_phy,
+ struct ex_phy *child_phy)
+{
+ int res = 0;
+ struct domain_device *parent = child->parent;
+
+ if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
+ res = -ENODEV;
+ SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx "
+ "phy S:0x%x, while there is a fanout ex %016llx\n",
+ SAS_ADDR(parent->sas_addr),
+ parent_phy->phy_id,
+ SAS_ADDR(child->sas_addr),
+ child_phy->phy_id,
+ SAS_ADDR(parent->port->disc.fanout_sas_addr));
+ } else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
+ memcpy(parent->port->disc.eeds_a, parent->sas_addr,
+ SAS_ADDR_SIZE);
+ memcpy(parent->port->disc.eeds_b, child->sas_addr,
+ SAS_ADDR_SIZE);
+ } else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
+ SAS_ADDR(parent->sas_addr)) ||
+ (SAS_ADDR(parent->port->disc.eeds_a) ==
+ SAS_ADDR(child->sas_addr)))
+ &&
+ ((SAS_ADDR(parent->port->disc.eeds_b) ==
+ SAS_ADDR(parent->sas_addr)) ||
+ (SAS_ADDR(parent->port->disc.eeds_b) ==
+ SAS_ADDR(child->sas_addr))))
+ ;
+ else {
+ res = -ENODEV;
+ SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx "
+ "phy 0x%x link forms a third EEDS!\n",
+ SAS_ADDR(parent->sas_addr),
+ parent_phy->phy_id,
+ SAS_ADDR(child->sas_addr),
+ child_phy->phy_id);
+ }
+
+ return res;
+}
+
+/* Here we spill over 80 columns. It is intentional.
+ */
+static int sas_check_parent_topology(struct domain_device *child)
+{
+ struct expander_device *child_ex = &child->ex_dev;
+ struct expander_device *parent_ex;
+ int i;
+ int res = 0;
+
+ if (!child->parent)
+ return 0;
+
+ if (child->parent->dev_type != EDGE_DEV &&
+ child->parent->dev_type != FANOUT_DEV)
+ return 0;
+
+ parent_ex = &child->parent->ex_dev;
+
+ for (i = 0; i < parent_ex->num_phys; i++) {
+ struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
+ struct ex_phy *child_phy;
+
+ if (parent_phy->phy_state == PHY_VACANT ||
+ parent_phy->phy_state == PHY_NOT_PRESENT)
+ continue;
+
+ if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr))
+ continue;
+
+ child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
+
+ switch (child->parent->dev_type) {
+ case EDGE_DEV:
+ if (child->dev_type == FANOUT_DEV) {
+ if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
+ child_phy->routing_attr != TABLE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ } else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
+ if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
+ res = sas_check_eeds(child, parent_phy, child_phy);
+ } else if (child_phy->routing_attr != TABLE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ } else if (parent_phy->routing_attr == TABLE_ROUTING &&
+ child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ break;
+ case FANOUT_DEV:
+ if (parent_phy->routing_attr != TABLE_ROUTING ||
+ child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
+ sas_print_parent_topology_bug(child, parent_phy, child_phy);
+ res = -ENODEV;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return res;
+}
+
+#define RRI_REQ_SIZE 16
+#define RRI_RESP_SIZE 44
+
+static int sas_configure_present(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int *index, int *present)
+{
+ int i, res = 0;
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ u8 *rri_req;
+ u8 *rri_resp;
+
+ *present = 0;
+ *index = 0;
+
+ rri_req = alloc_smp_req(RRI_REQ_SIZE);
+ if (!rri_req)
+ return -ENOMEM;
+
+ rri_resp = alloc_smp_resp(RRI_RESP_SIZE);
+ if (!rri_resp) {
+ kfree(rri_req);
+ return -ENOMEM;
+ }
+
+ rri_req[1] = SMP_REPORT_ROUTE_INFO;
+ rri_req[9] = phy_id;
+
+ for (i = 0; i < ex->max_route_indexes ; i++) {
+ *(__be16 *)(rri_req+6) = cpu_to_be16(i);
+ res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp,
+ RRI_RESP_SIZE);
+ if (res)
+ goto out;
+ res = rri_resp[2];
+ if (res == SMP_RESP_NO_INDEX) {
+ SAS_DPRINTK("overflow of indexes: dev %016llx "
+ "phy 0x%x index 0x%x\n",
+ SAS_ADDR(dev->sas_addr), phy_id, i);
+ goto out;
+ } else if (res != SMP_RESP_FUNC_ACC) {
+ SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x "
+ "result 0x%x\n", __FUNCTION__,
+ SAS_ADDR(dev->sas_addr), phy_id, i, res);
+ goto out;
+ }
+ if (SAS_ADDR(sas_addr) != 0) {
+ if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) {
+ *index = i;
+ if ((rri_resp[12] & 0x80) == 0x80)
+ *present = 0;
+ else
+ *present = 1;
+ goto out;
+ } else if (SAS_ADDR(rri_resp+16) == 0) {
+ *index = i;
+ *present = 0;
+ goto out;
+ }
+ } else if (SAS_ADDR(rri_resp+16) == 0 &&
+ phy->last_da_index < i) {
+ phy->last_da_index = i;
+ *index = i;
+ *present = 0;
+ goto out;
+ }
+ }
+ res = -1;
+out:
+ kfree(rri_req);
+ kfree(rri_resp);
+ return res;
+}
+
+#define CRI_REQ_SIZE 44
+#define CRI_RESP_SIZE 8
+
+static int sas_configure_set(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int index, int include)
+{
+ int res;
+ u8 *cri_req;
+ u8 *cri_resp;
+
+ cri_req = alloc_smp_req(CRI_REQ_SIZE);
+ if (!cri_req)
+ return -ENOMEM;
+
+ cri_resp = alloc_smp_resp(CRI_RESP_SIZE);
+ if (!cri_resp) {
+ kfree(cri_req);
+ return -ENOMEM;
+ }
+
+ cri_req[1] = SMP_CONF_ROUTE_INFO;
+ *(__be16 *)(cri_req+6) = cpu_to_be16(index);
+ cri_req[9] = phy_id;
+ if (SAS_ADDR(sas_addr) == 0 || !include)
+ cri_req[12] |= 0x80;
+ memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE);
+
+ res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp,
+ CRI_RESP_SIZE);
+ if (res)
+ goto out;
+ res = cri_resp[2];
+ if (res == SMP_RESP_NO_INDEX) {
+ SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x "
+ "index 0x%x\n",
+ SAS_ADDR(dev->sas_addr), phy_id, index);
+ }
+out:
+ kfree(cri_req);
+ kfree(cri_resp);
+ return res;
+}
+
+static int sas_configure_phy(struct domain_device *dev, int phy_id,
+ u8 *sas_addr, int include)
+{
+ int index;
+ int present;
+ int res;
+
+ res = sas_configure_present(dev, phy_id, sas_addr, &index, &present);
+ if (res)
+ return res;
+ if (include ^ present)
+ return sas_configure_set(dev, phy_id, sas_addr, index,include);
+
+ return res;
+}
+
+/**
+ * sas_configure_parent -- configure routing table of parent
+ * parent: parent expander
+ * child: child expander
+ * sas_addr: SAS port identifier of device directly attached to child
+ */
+static int sas_configure_parent(struct domain_device *parent,
+ struct domain_device *child,
+ u8 *sas_addr, int include)
+{
+ struct expander_device *ex_parent = &parent->ex_dev;
+ int res = 0;
+ int i;
+
+ if (parent->parent) {
+ res = sas_configure_parent(parent->parent, parent, sas_addr,
+ include);
+ if (res)
+ return res;
+ }
+
+ if (ex_parent->conf_route_table == 0) {
+ SAS_DPRINTK("ex %016llx has self-configuring routing table\n",
+ SAS_ADDR(parent->sas_addr));
+ return 0;
+ }
+
+ for (i = 0; i < ex_parent->num_phys; i++) {
+ struct ex_phy *phy = &ex_parent->ex_phy[i];
+
+ if ((phy->routing_attr == TABLE_ROUTING) &&
+ (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(child->sas_addr))) {
+ res = sas_configure_phy(parent, i, sas_addr, include);
+ if (res)
+ return res;
+ }
+ }
+
+ return res;
+}
+
+/**
+ * sas_configure_routing -- configure routing
+ * dev: expander device
+ * sas_addr: port identifier of device directly attached to the expander device
+ */
+static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
+{
+ if (dev->parent)
+ return sas_configure_parent(dev->parent, dev, sas_addr, 1);
+ return 0;
+}
+
+static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr)
+{
+ if (dev->parent)
+ return sas_configure_parent(dev->parent, dev, sas_addr, 0);
+ return 0;
+}
+
+#if 0
+#define SMP_BIN_ATTR_NAME "smp_portal"
+
+static void sas_ex_smp_hook(struct domain_device *dev)
+{
+ struct expander_device *ex_dev = &dev->ex_dev;
+ struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr;
+
+ memset(bin_attr, 0, sizeof(*bin_attr));
+
+ bin_attr->attr.name = SMP_BIN_ATTR_NAME;
+ bin_attr->attr.owner = THIS_MODULE;
+ bin_attr->attr.mode = 0600;
+
+ bin_attr->size = 0;
+ bin_attr->private = NULL;
+ bin_attr->read = smp_portal_read;
+ bin_attr->write= smp_portal_write;
+ bin_attr->mmap = NULL;
+
+ ex_dev->smp_portal_pid = -1;
+ init_MUTEX(&ex_dev->smp_sema);
+}
+#endif
+
+/**
+ * sas_discover_expander -- expander discovery
+ * @ex: pointer to expander domain device
+ *
+ * See comment in sas_discover_sata().
+ */
+static int sas_discover_expander(struct domain_device *dev)
+{
+ int res;
+
+ res = sas_notify_lldd_dev_found(dev);
+ if (res)
+ return res;
+
+ res = sas_ex_general(dev);
+ if (res)
+ goto out_err;
+ res = sas_ex_manuf_info(dev);
+ if (res)
+ goto out_err;
+
+ res = sas_expander_discover(dev);
+ if (res) {
+ SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n",
+ SAS_ADDR(dev->sas_addr), res);
+ goto out_err;
+ }
+
+ sas_check_ex_subtractive_boundary(dev);
+ res = sas_check_parent_topology(dev);
+ if (res)
+ goto out_err;
+ return 0;
+out_err:
+ sas_notify_lldd_dev_gone(dev);
+ return res;
+}
+
+static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
+{
+ int res = 0;
+ struct domain_device *dev;
+
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ if (dev->dev_type == EDGE_DEV ||
+ dev->dev_type == FANOUT_DEV) {
+ struct sas_expander_device *ex =
+ rphy_to_expander_device(dev->rphy);
+
+ if (level == ex->level)
+ res = sas_ex_discover_devices(dev, -1);
+ else if (level > 0)
+ res = sas_ex_discover_devices(port->port_dev, -1);
+
+ }
+ }
+
+ return res;
+}
+
+static int sas_ex_bfs_disc(struct asd_sas_port *port)
+{
+ int res;
+ int level;
+
+ do {
+ level = port->disc.max_level;
+ res = sas_ex_level_discovery(port, level);
+ mb();
+ } while (level < port->disc.max_level);
+
+ return res;
+}
+
+int sas_discover_root_expander(struct domain_device *dev)
+{
+ int res;
+ struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
+
+ sas_rphy_add(dev->rphy);
+
+ ex->level = dev->port->disc.max_level; /* 0 */
+ res = sas_discover_expander(dev);
+ if (!res)
+ sas_ex_bfs_disc(dev->port);
+
+ return res;
+}
+
+/* ---------- Domain revalidation ---------- */
+
+static int sas_get_phy_discover(struct domain_device *dev,
+ int phy_id, struct smp_resp *disc_resp)
+{
+ int res;
+ u8 *disc_req;
+
+ disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
+ if (!disc_req)
+ return -ENOMEM;
+
+ disc_req[1] = SMP_DISCOVER;
+ disc_req[9] = phy_id;
+
+ res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
+ disc_resp, DISCOVER_RESP_SIZE);
+ if (res)
+ goto out;
+ else if (disc_resp->result != SMP_RESP_FUNC_ACC) {
+ res = disc_resp->result;
+ goto out;
+ }
+out:
+ kfree(disc_req);
+ return res;
+}
+
+static int sas_get_phy_change_count(struct domain_device *dev,
+ int phy_id, int *pcc)
+{
+ int res;
+ struct smp_resp *disc_resp;
+
+ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
+ if (!disc_resp)
+ return -ENOMEM;
+
+ res = sas_get_phy_discover(dev, phy_id, disc_resp);
+ if (!res)
+ *pcc = disc_resp->disc.change_count;
+
+ kfree(disc_resp);
+ return res;
+}
+
+static int sas_get_phy_attached_sas_addr(struct domain_device *dev,
+ int phy_id, u8 *attached_sas_addr)
+{
+ int res;
+ struct smp_resp *disc_resp;
+ struct discover_resp *dr;
+
+ disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
+ if (!disc_resp)
+ return -ENOMEM;
+ dr = &disc_resp->disc;
+
+ res = sas_get_phy_discover(dev, phy_id, disc_resp);
+ if (!res) {
+ memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8);
+ if (dr->attached_dev_type == 0)
+ memset(attached_sas_addr, 0, 8);
+ }
+ kfree(disc_resp);
+ return res;
+}
+
+static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
+ int from_phy)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int res = 0;
+ int i;
+
+ for (i = from_phy; i < ex->num_phys; i++) {
+ int phy_change_count = 0;
+
+ res = sas_get_phy_change_count(dev, i, &phy_change_count);
+ if (res)
+ goto out;
+ else if (phy_change_count != ex->ex_phy[i].phy_change_count) {
+ ex->ex_phy[i].phy_change_count = phy_change_count;
+ *phy_id = i;
+ return 0;
+ }
+ }
+out:
+ return res;
+}
+
+static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
+{
+ int res;
+ u8 *rg_req;
+ struct smp_resp *rg_resp;
+
+ rg_req = alloc_smp_req(RG_REQ_SIZE);
+ if (!rg_req)
+ return -ENOMEM;
+
+ rg_resp = alloc_smp_resp(RG_RESP_SIZE);
+ if (!rg_resp) {
+ kfree(rg_req);
+ return -ENOMEM;
+ }
+
+ rg_req[1] = SMP_REPORT_GENERAL;
+
+ res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
+ RG_RESP_SIZE);
+ if (res)
+ goto out;
+ if (rg_resp->result != SMP_RESP_FUNC_ACC) {
+ res = rg_resp->result;
+ goto out;
+ }
+
+ *ecc = be16_to_cpu(rg_resp->rg.change_count);
+out:
+ kfree(rg_resp);
+ kfree(rg_req);
+ return res;
+}
+
+static int sas_find_bcast_dev(struct domain_device *dev,
+ struct domain_device **src_dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ int ex_change_count = -1;
+ int res;
+
+ res = sas_get_ex_change_count(dev, &ex_change_count);
+ if (res)
+ goto out;
+ if (ex_change_count != -1 &&
+ ex_change_count != ex->ex_change_count) {
+ *src_dev = dev;
+ ex->ex_change_count = ex_change_count;
+ } else {
+ struct domain_device *ch;
+
+ list_for_each_entry(ch, &ex->children, siblings) {
+ if (ch->dev_type == EDGE_DEV ||
+ ch->dev_type == FANOUT_DEV) {
+ res = sas_find_bcast_dev(ch, src_dev);
+ if (src_dev)
+ return res;
+ }
+ }
+ }
+out:
+ return res;
+}
+
+static void sas_unregister_ex_tree(struct domain_device *dev)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct domain_device *child, *n;
+
+ list_for_each_entry_safe(child, n, &ex->children, siblings) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ sas_unregister_ex_tree(child);
+ else
+ sas_unregister_dev(child);
+ }
+ sas_unregister_dev(dev);
+}
+
+static void sas_unregister_devs_sas_addr(struct domain_device *parent,
+ int phy_id)
+{
+ struct expander_device *ex_dev = &parent->ex_dev;
+ struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
+ struct domain_device *child, *n;
+
+ list_for_each_entry_safe(child, n, &ex_dev->children, siblings) {
+ if (SAS_ADDR(child->sas_addr) ==
+ SAS_ADDR(phy->attached_sas_addr)) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ sas_unregister_ex_tree(child);
+ else
+ sas_unregister_dev(child);
+ break;
+ }
+ }
+ sas_disable_routing(parent, phy->attached_sas_addr);
+ memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ sas_port_delete_phy(phy->port, phy->phy);
+ if (phy->port->num_phys == 0)
+ sas_port_delete(phy->port);
+ phy->port = NULL;
+}
+
+static int sas_discover_bfs_by_root_level(struct domain_device *root,
+ const int level)
+{
+ struct expander_device *ex_root = &root->ex_dev;
+ struct domain_device *child;
+ int res = 0;
+
+ list_for_each_entry(child, &ex_root->children, siblings) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV) {
+ struct sas_expander_device *ex =
+ rphy_to_expander_device(child->rphy);
+
+ if (level > ex->level)
+ res = sas_discover_bfs_by_root_level(child,
+ level);
+ else if (level == ex->level)
+ res = sas_ex_discover_devices(child, -1);
+ }
+ }
+ return res;
+}
+
+static int sas_discover_bfs_by_root(struct domain_device *dev)
+{
+ int res;
+ struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
+ int level = ex->level+1;
+
+ res = sas_ex_discover_devices(dev, -1);
+ if (res)
+ goto out;
+ do {
+ res = sas_discover_bfs_by_root_level(dev, level);
+ mb();
+ level += 1;
+ } while (level <= dev->port->disc.max_level);
+out:
+ return res;
+}
+
+static int sas_discover_new(struct domain_device *dev, int phy_id)
+{
+ struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
+ struct domain_device *child;
+ int res;
+
+ SAS_DPRINTK("ex %016llx phy%d new device attached\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
+ res = sas_ex_phy_discover(dev, phy_id);
+ if (res)
+ goto out;
+ res = sas_ex_discover_devices(dev, phy_id);
+ if (res)
+ goto out;
+ list_for_each_entry(child, &dev->ex_dev.children, siblings) {
+ if (SAS_ADDR(child->sas_addr) ==
+ SAS_ADDR(ex_phy->attached_sas_addr)) {
+ if (child->dev_type == EDGE_DEV ||
+ child->dev_type == FANOUT_DEV)
+ res = sas_discover_bfs_by_root(child);
+ break;
+ }
+ }
+out:
+ return res;
+}
+
+static int sas_rediscover_dev(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *phy = &ex->ex_phy[phy_id];
+ u8 attached_sas_addr[8];
+ int res;
+
+ res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr);
+ switch (res) {
+ case SMP_RESP_NO_PHY:
+ phy->phy_state = PHY_NOT_PRESENT;
+ sas_unregister_devs_sas_addr(dev, phy_id);
+ goto out; break;
+ case SMP_RESP_PHY_VACANT:
+ phy->phy_state = PHY_VACANT;
+ sas_unregister_devs_sas_addr(dev, phy_id);
+ goto out; break;
+ case SMP_RESP_FUNC_ACC:
+ break;
+ }
+
+ if (SAS_ADDR(attached_sas_addr) == 0) {
+ phy->phy_state = PHY_EMPTY;
+ sas_unregister_devs_sas_addr(dev, phy_id);
+ } else if (SAS_ADDR(attached_sas_addr) ==
+ SAS_ADDR(phy->attached_sas_addr)) {
+ SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
+ sas_ex_phy_discover(dev, phy_id);
+ } else
+ res = sas_discover_new(dev, phy_id);
+out:
+ return res;
+}
+
+static int sas_rediscover(struct domain_device *dev, const int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
+ int res = 0;
+ int i;
+
+ SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n",
+ SAS_ADDR(dev->sas_addr), phy_id);
+
+ if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
+ for (i = 0; i < ex->num_phys; i++) {
+ struct ex_phy *phy = &ex->ex_phy[i];
+
+ if (i == phy_id)
+ continue;
+ if (SAS_ADDR(phy->attached_sas_addr) ==
+ SAS_ADDR(changed_phy->attached_sas_addr)) {
+ SAS_DPRINTK("phy%d part of wide port with "
+ "phy%d\n", phy_id, i);
+ goto out;
+ }
+ }
+ res = sas_rediscover_dev(dev, phy_id);
+ } else
+ res = sas_discover_new(dev, phy_id);
+out:
+ return res;
+}
+
+/**
+ * sas_revalidate_domain -- revalidate the domain
+ * @port: port to the domain of interest
+ *
+ * NOTE: this process _must_ quit (return) as soon as any connection
+ * errors are encountered. Connection recovery is done elsewhere.
+ * Discover process only interrogates devices in order to discover the
+ * domain.
+ */
+int sas_ex_revalidate_domain(struct domain_device *port_dev)
+{
+ int res;
+ struct domain_device *dev = NULL;
+
+ res = sas_find_bcast_dev(port_dev, &dev);
+ if (res)
+ goto out;
+ if (dev) {
+ struct expander_device *ex = &dev->ex_dev;
+ int i = 0, phy_id;
+
+ do {
+ phy_id = -1;
+ res = sas_find_bcast_phy(dev, &phy_id, i);
+ if (phy_id == -1)
+ break;
+ res = sas_rediscover(dev, phy_id);
+ i = phy_id + 1;
+ } while (i < ex->num_phys);
+ }
+out:
+ return res;
+}
+
+#if 0
+/* ---------- SMP portal ---------- */
+
+static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs,
+ size_t size)
+{
+ struct domain_device *dev = to_dom_device(kobj);
+ struct expander_device *ex = &dev->ex_dev;
+
+ if (offs != 0)
+ return -EFBIG;
+ else if (size == 0)
+ return 0;
+
+ down_interruptible(&ex->smp_sema);
+ if (ex->smp_req)
+ kfree(ex->smp_req);
+ ex->smp_req = kzalloc(size, GFP_USER);
+ if (!ex->smp_req) {
+ up(&ex->smp_sema);
+ return -ENOMEM;
+ }
+ memcpy(ex->smp_req, buf, size);
+ ex->smp_req_size = size;
+ ex->smp_portal_pid = current->pid;
+ up(&ex->smp_sema);
+
+ return size;
+}
+
+static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs,
+ size_t size)
+{
+ struct domain_device *dev = to_dom_device(kobj);
+ struct expander_device *ex = &dev->ex_dev;
+ u8 *smp_resp;
+ int res = -EINVAL;
+
+ /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact
+ * it should be 0.
+ */
+
+ down_interruptible(&ex->smp_sema);
+ if (!ex->smp_req || ex->smp_portal_pid != current->pid)
+ goto out;
+
+ res = 0;
+ if (size == 0)
+ goto out;
+
+ res = -ENOMEM;
+ smp_resp = alloc_smp_resp(size);
+ if (!smp_resp)
+ goto out;
+ res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size,
+ smp_resp, size);
+ if (!res) {
+ memcpy(buf, smp_resp, size);
+ res = size;
+ }
+
+ kfree(smp_resp);
+out:
+ kfree(ex->smp_req);
+ ex->smp_req = NULL;
+ ex->smp_req_size = 0;
+ ex->smp_portal_pid = -1;
+ up(&ex->smp_sema);
+ return res;
+}
+#endif
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
new file mode 100644
index 00000000000..c836a237fb7
--- /dev/null
+++ b/drivers/scsi/libsas/sas_init.c
@@ -0,0 +1,267 @@
+/*
+ * Serial Attached SCSI (SAS) Transport Layer initialization
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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/init.h>
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+
+#include "sas_internal.h"
+
+#include "../scsi_sas_internal.h"
+
+kmem_cache_t *sas_task_cache;
+
+/*------------ SAS addr hash -----------*/
+void sas_hash_addr(u8 *hashed, const u8 *sas_addr)
+{
+ const u32 poly = 0x00DB2777;
+ u32 r = 0;
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ int b;
+ for (b = 7; b >= 0; b--) {
+ r <<= 1;
+ if ((1 << b) & sas_addr[i]) {
+ if (!(r & 0x01000000))
+ r ^= poly;
+ } else if (r & 0x01000000)
+ r ^= poly;
+ }
+ }
+
+ hashed[0] = (r >> 16) & 0xFF;
+ hashed[1] = (r >> 8) & 0xFF ;
+ hashed[2] = r & 0xFF;
+}
+
+
+/* ---------- HA events ---------- */
+
+void sas_hae_reset(void *data)
+{
+ struct sas_ha_struct *ha = data;
+
+ sas_begin_event(HAE_RESET, &ha->event_lock,
+ &ha->pending);
+}
+
+int sas_register_ha(struct sas_ha_struct *sas_ha)
+{
+ int error = 0;
+
+ spin_lock_init(&sas_ha->phy_port_lock);
+ sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
+
+ if (sas_ha->lldd_queue_size == 0)
+ sas_ha->lldd_queue_size = 1;
+ else if (sas_ha->lldd_queue_size == -1)
+ sas_ha->lldd_queue_size = 128; /* Sanity */
+
+ error = sas_register_phys(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't register sas phys:%d\n", error);
+ return error;
+ }
+
+ error = sas_register_ports(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't register sas ports:%d\n", error);
+ goto Undo_phys;
+ }
+
+ error = sas_init_events(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't start event thread:%d\n", error);
+ goto Undo_ports;
+ }
+
+ if (sas_ha->lldd_max_execute_num > 1) {
+ error = sas_init_queue(sas_ha);
+ if (error) {
+ printk(KERN_NOTICE "couldn't start queue thread:%d, "
+ "running in direct mode\n", error);
+ sas_ha->lldd_max_execute_num = 1;
+ }
+ }
+
+ return 0;
+
+Undo_ports:
+ sas_unregister_ports(sas_ha);
+Undo_phys:
+
+ return error;
+}
+
+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+{
+ if (sas_ha->lldd_max_execute_num > 1) {
+ sas_shutdown_queue(sas_ha);
+ }
+
+ sas_unregister_ports(sas_ha);
+
+ return 0;
+}
+
+static int sas_get_linkerrors(struct sas_phy *phy)
+{
+ if (scsi_is_sas_phy_local(phy))
+ /* FIXME: we have no local phy stats
+ * gathering at this time */
+ return -EINVAL;
+
+ return sas_smp_get_phy_events(phy);
+}
+
+static int sas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+ int ret;
+ enum phy_func reset_type;
+
+ if (hard_reset)
+ reset_type = PHY_FUNC_HARD_RESET;
+ else
+ reset_type = PHY_FUNC_LINK_RESET;
+
+ if (scsi_is_sas_phy_local(phy)) {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL);
+ } else {
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
+ ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL);
+ }
+ return ret;
+}
+
+static int sas_set_phy_speed(struct sas_phy *phy,
+ struct sas_phy_linkrates *rates)
+{
+ int ret;
+
+ if ((rates->minimum_linkrate &&
+ rates->minimum_linkrate > phy->maximum_linkrate) ||
+ (rates->maximum_linkrate &&
+ rates->maximum_linkrate < phy->minimum_linkrate))
+ return -EINVAL;
+
+ if (rates->minimum_linkrate &&
+ rates->minimum_linkrate < phy->minimum_linkrate_hw)
+ rates->minimum_linkrate = phy->minimum_linkrate_hw;
+
+ if (rates->maximum_linkrate &&
+ rates->maximum_linkrate > phy->maximum_linkrate_hw)
+ rates->maximum_linkrate = phy->maximum_linkrate_hw;
+
+ if (scsi_is_sas_phy_local(phy)) {
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
+ struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
+ struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number];
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE,
+ rates);
+ } else {
+ struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
+ struct domain_device *ddev = sas_find_dev_by_rphy(rphy);
+ ret = sas_smp_phy_control(ddev, phy->number,
+ PHY_FUNC_LINK_RESET, rates);
+
+ }
+
+ return ret;
+}
+
+static struct sas_function_template sft = {
+ .phy_reset = sas_phy_reset,
+ .set_phy_speed = sas_set_phy_speed,
+ .get_linkerrors = sas_get_linkerrors,
+};
+
+struct scsi_transport_template *
+sas_domain_attach_transport(struct sas_domain_function_template *dft)
+{
+ struct scsi_transport_template *stt = sas_attach_transport(&sft);
+ struct sas_internal *i;
+
+ if (!stt)
+ return stt;
+
+ i = to_sas_internal(stt);
+ i->dft = dft;
+ stt->create_work_queue = 1;
+ stt->eh_timed_out = sas_scsi_timed_out;
+ stt->eh_strategy_handler = sas_scsi_recover_host;
+
+ return stt;
+}
+EXPORT_SYMBOL_GPL(sas_domain_attach_transport);
+
+
+void sas_domain_release_transport(struct scsi_transport_template *stt)
+{
+ sas_release_transport(stt);
+}
+EXPORT_SYMBOL_GPL(sas_domain_release_transport);
+
+/* ---------- SAS Class register/unregister ---------- */
+
+static int __init sas_class_init(void)
+{
+ sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (!sas_task_cache)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __exit sas_class_exit(void)
+{
+ kmem_cache_destroy(sas_task_cache);
+}
+
+MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>");
+MODULE_DESCRIPTION("SAS Transport Layer");
+MODULE_LICENSE("GPL v2");
+
+module_init(sas_class_init);
+module_exit(sas_class_exit);
+
+EXPORT_SYMBOL_GPL(sas_register_ha);
+EXPORT_SYMBOL_GPL(sas_unregister_ha);
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
new file mode 100644
index 00000000000..bffcee47492
--- /dev/null
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -0,0 +1,146 @@
+/*
+ * Serial Attached SCSI (SAS) class internal header file
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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
+ *
+ */
+
+#ifndef _SAS_INTERNAL_H_
+#define _SAS_INTERNAL_H_
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_sas.h>
+#include <scsi/libsas.h>
+
+#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
+
+#ifdef SAS_DEBUG
+#define SAS_DPRINTK(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__)
+#else
+#define SAS_DPRINTK(fmt, ...)
+#endif
+
+void sas_scsi_recover_host(struct Scsi_Host *shost);
+
+int sas_show_class(enum sas_class class, char *buf);
+int sas_show_proto(enum sas_proto proto, char *buf);
+int sas_show_linkrate(enum sas_linkrate linkrate, char *buf);
+int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf);
+
+int sas_register_phys(struct sas_ha_struct *sas_ha);
+void sas_unregister_phys(struct sas_ha_struct *sas_ha);
+
+int sas_register_ports(struct sas_ha_struct *sas_ha);
+void sas_unregister_ports(struct sas_ha_struct *sas_ha);
+
+enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
+
+int sas_init_queue(struct sas_ha_struct *sas_ha);
+int sas_init_events(struct sas_ha_struct *sas_ha);
+void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
+
+void sas_deform_port(struct asd_sas_phy *phy);
+
+void sas_porte_bytes_dmaed(void *);
+void sas_porte_broadcast_rcvd(void *);
+void sas_porte_link_reset_err(void *);
+void sas_porte_timer_event(void *);
+void sas_porte_hard_reset(void *);
+
+int sas_notify_lldd_dev_found(struct domain_device *);
+void sas_notify_lldd_dev_gone(struct domain_device *);
+
+int sas_smp_phy_control(struct domain_device *dev, int phy_id,
+ enum phy_func phy_func, struct sas_phy_linkrates *);
+int sas_smp_get_phy_events(struct sas_phy *phy);
+
+struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
+
+void sas_hae_reset(void *);
+
+static inline void sas_queue_event(int event, spinlock_t *lock,
+ unsigned long *pending,
+ struct work_struct *work,
+ struct Scsi_Host *shost)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ if (test_bit(event, pending)) {
+ spin_unlock_irqrestore(lock, flags);
+ return;
+ }
+ __set_bit(event, pending);
+ spin_unlock_irqrestore(lock, flags);
+ scsi_queue_work(shost, work);
+}
+
+static inline void sas_begin_event(int event, spinlock_t *lock,
+ unsigned long *pending)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ __clear_bit(event, pending);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static inline void sas_fill_in_rphy(struct domain_device *dev,
+ struct sas_rphy *rphy)
+{
+ rphy->identify.sas_address = SAS_ADDR(dev->sas_addr);
+ rphy->identify.initiator_port_protocols = dev->iproto;
+ rphy->identify.target_port_protocols = dev->tproto;
+ switch (dev->dev_type) {
+ case SATA_DEV:
+ /* FIXME: need sata device type */
+ case SAS_END_DEV:
+ rphy->identify.device_type = SAS_END_DEVICE;
+ break;
+ case EDGE_DEV:
+ rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE;
+ break;
+ case FANOUT_DEV:
+ rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE;
+ break;
+ default:
+ rphy->identify.device_type = SAS_PHY_UNUSED;
+ break;
+ }
+}
+
+static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
+{
+ struct expander_device *ex = &dev->ex_dev;
+ struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
+
+ if (!ex->parent_port) {
+ ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id);
+ /* FIXME: error handling */
+ BUG_ON(!ex->parent_port);
+ BUG_ON(sas_port_add(ex->parent_port));
+ sas_port_mark_backlink(ex->parent_port);
+ }
+ sas_port_add_phy(ex->parent_port, ex_phy->phy);
+}
+
+#endif /* _SAS_INTERNAL_H_ */
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c
new file mode 100644
index 00000000000..9340cdbae4a
--- /dev/null
+++ b/drivers/scsi/libsas/sas_phy.c
@@ -0,0 +1,158 @@
+/*
+ * Serial Attached SCSI (SAS) Phy class
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sas_internal.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+/* ---------- Phy events ---------- */
+
+static void sas_phye_loss_of_signal(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+ phy->error = 0;
+ sas_deform_port(phy);
+}
+
+static void sas_phye_oob_done(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+ phy->error = 0;
+}
+
+static void sas_phye_oob_error(void *data)
+{
+ struct asd_sas_phy *phy = data;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct asd_sas_port *port = phy->port;
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+
+ sas_deform_port(phy);
+
+ if (!port && phy->enabled && i->dft->lldd_control_phy) {
+ phy->error++;
+ switch (phy->error) {
+ case 1:
+ case 2:
+ i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
+ NULL);
+ break;
+ case 3:
+ default:
+ phy->error = 0;
+ phy->enabled = 0;
+ i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
+ break;
+ }
+ }
+}
+
+static void sas_phye_spinup_hold(void *data)
+{
+ struct asd_sas_phy *phy = data;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct sas_internal *i =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock,
+ &phy->phy_events_pending);
+
+ phy->error = 0;
+ i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
+}
+
+/* ---------- Phy class registration ---------- */
+
+int sas_register_phys(struct sas_ha_struct *sas_ha)
+{
+ int i;
+
+ static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = {
+ [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
+ [PHYE_OOB_DONE] = sas_phye_oob_done,
+ [PHYE_OOB_ERROR] = sas_phye_oob_error,
+ [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
+ };
+
+ static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = {
+ [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
+ [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
+ [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
+ [PORTE_TIMER_EVENT] = sas_porte_timer_event,
+ [PORTE_HARD_RESET] = sas_porte_hard_reset,
+ };
+
+ /* Now register the phys. */
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ int k;
+ struct asd_sas_phy *phy = sas_ha->sas_phy[i];
+
+ phy->error = 0;
+ INIT_LIST_HEAD(&phy->port_phy_el);
+ for (k = 0; k < PORT_NUM_EVENTS; k++)
+ INIT_WORK(&phy->port_events[k], sas_port_event_fns[k],
+ phy);
+
+ for (k = 0; k < PHY_NUM_EVENTS; k++)
+ INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k],
+ phy);
+ phy->port = NULL;
+ phy->ha = sas_ha;
+ spin_lock_init(&phy->frame_rcvd_lock);
+ spin_lock_init(&phy->sas_prim_lock);
+ phy->frame_rcvd_size = 0;
+
+ phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev,
+ i);
+ if (!phy->phy)
+ return -ENOMEM;
+
+ phy->phy->identify.initiator_port_protocols =
+ phy->iproto;
+ phy->phy->identify.target_port_protocols = phy->tproto;
+ phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
+ phy->phy->identify.phy_identifier = i;
+ phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ sas_phy_add(phy->phy);
+ }
+
+ return 0;
+}
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c
new file mode 100644
index 00000000000..253cdcf306a
--- /dev/null
+++ b/drivers/scsi/libsas/sas_port.c
@@ -0,0 +1,279 @@
+/*
+ * Serial Attached SCSI (SAS) Port class
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "sas_internal.h"
+
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+/**
+ * sas_form_port -- add this phy to a port
+ * @phy: the phy of interest
+ *
+ * This function adds this phy to an existing port, thus creating a wide
+ * port, or it creates a port and adds the phy to the port.
+ */
+static void sas_form_port(struct asd_sas_phy *phy)
+{
+ int i;
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct asd_sas_port *port = phy->port;
+ struct sas_internal *si =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ if (port) {
+ if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
+ SAS_ADDR_SIZE) == 0)
+ sas_deform_port(phy);
+ else {
+ SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
+ __FUNCTION__, phy->id, phy->port->id,
+ phy->port->num_phys);
+ return;
+ }
+ }
+
+ /* find a port */
+ spin_lock(&sas_ha->phy_port_lock);
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ port = sas_ha->sas_port[i];
+ spin_lock(&port->phy_list_lock);
+ if (*(u64 *) port->sas_addr &&
+ memcmp(port->attached_sas_addr,
+ phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 &&
+ port->num_phys > 0) {
+ /* wide port */
+ SAS_DPRINTK("phy%d matched wide port%d\n", phy->id,
+ port->id);
+ break;
+ } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) {
+ memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
+ break;
+ }
+ spin_unlock(&port->phy_list_lock);
+ }
+
+ if (i >= sas_ha->num_phys) {
+ printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n",
+ __FUNCTION__);
+ spin_unlock(&sas_ha->phy_port_lock);
+ return;
+ }
+
+ /* add the phy to the port */
+ list_add_tail(&phy->port_phy_el, &port->phy_list);
+ phy->port = port;
+ port->num_phys++;
+ port->phy_mask |= (1U << phy->id);
+
+ if (!port->phy)
+ port->phy = phy->phy;
+
+ SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id,
+ port->id, port->phy_mask);
+
+ if (*(u64 *)port->attached_sas_addr == 0) {
+ port->class = phy->class;
+ memcpy(port->attached_sas_addr, phy->attached_sas_addr,
+ SAS_ADDR_SIZE);
+ port->iproto = phy->iproto;
+ port->tproto = phy->tproto;
+ port->oob_mode = phy->oob_mode;
+ port->linkrate = phy->linkrate;
+ } else
+ port->linkrate = max(port->linkrate, phy->linkrate);
+ spin_unlock(&port->phy_list_lock);
+ spin_unlock(&sas_ha->phy_port_lock);
+
+ if (!port->port) {
+ port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
+ BUG_ON(!port->port);
+ sas_port_add(port->port);
+ }
+ sas_port_add_phy(port->port, phy->phy);
+
+ if (port->port_dev)
+ port->port_dev->pathways = port->num_phys;
+
+ /* Tell the LLDD about this port formation. */
+ if (si->dft->lldd_port_formed)
+ si->dft->lldd_port_formed(phy);
+
+ sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
+}
+
+/**
+ * sas_deform_port -- remove this phy from the port it belongs to
+ * @phy: the phy of interest
+ *
+ * This is called when the physical link to the other phy has been
+ * lost (on this phy), in Event thread context. We cannot delay here.
+ */
+void sas_deform_port(struct asd_sas_phy *phy)
+{
+ struct sas_ha_struct *sas_ha = phy->ha;
+ struct asd_sas_port *port = phy->port;
+ struct sas_internal *si =
+ to_sas_internal(sas_ha->core.shost->transportt);
+
+ if (!port)
+ return; /* done by a phy event */
+
+ if (port->port_dev)
+ port->port_dev->pathways--;
+
+ if (port->num_phys == 1) {
+ sas_unregister_domain_devices(port);
+ sas_port_delete(port->port);
+ port->port = NULL;
+ } else
+ sas_port_delete_phy(port->port, phy->phy);
+
+
+ if (si->dft->lldd_port_deformed)
+ si->dft->lldd_port_deformed(phy);
+
+ spin_lock(&sas_ha->phy_port_lock);
+ spin_lock(&port->phy_list_lock);
+
+ list_del_init(&phy->port_phy_el);
+ phy->port = NULL;
+ port->num_phys--;
+ port->phy_mask &= ~(1U << phy->id);
+
+ if (port->num_phys == 0) {
+ INIT_LIST_HEAD(&port->phy_list);
+ memset(port->sas_addr, 0, SAS_ADDR_SIZE);
+ memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE);
+ port->class = 0;
+ port->iproto = 0;
+ port->tproto = 0;
+ port->oob_mode = 0;
+ port->phy_mask = 0;
+ }
+ spin_unlock(&port->phy_list_lock);
+ spin_unlock(&sas_ha->phy_port_lock);
+
+ return;
+}
+
+/* ---------- SAS port events ---------- */
+
+void sas_porte_bytes_dmaed(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_form_port(phy);
+}
+
+void sas_porte_broadcast_rcvd(void *data)
+{
+ unsigned long flags;
+ u32 prim;
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ spin_lock_irqsave(&phy->sas_prim_lock, flags);
+ prim = phy->sas_prim;
+ spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
+
+ SAS_DPRINTK("broadcast received: %d\n", prim);
+ sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
+}
+
+void sas_porte_link_reset_err(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_deform_port(phy);
+}
+
+void sas_porte_timer_event(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_deform_port(phy);
+}
+
+void sas_porte_hard_reset(void *data)
+{
+ struct asd_sas_phy *phy = data;
+
+ sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock,
+ &phy->port_events_pending);
+
+ sas_deform_port(phy);
+}
+
+/* ---------- SAS port registration ---------- */
+
+static void sas_init_port(struct asd_sas_port *port,
+ struct sas_ha_struct *sas_ha, int i)
+{
+ port->id = i;
+ INIT_LIST_HEAD(&port->dev_list);
+ spin_lock_init(&port->phy_list_lock);
+ INIT_LIST_HEAD(&port->phy_list);
+ port->num_phys = 0;
+ port->phy_mask = 0;
+ port->ha = sas_ha;
+
+ spin_lock_init(&port->dev_list_lock);
+}
+
+int sas_register_ports(struct sas_ha_struct *sas_ha)
+{
+ int i;
+
+ /* initialize the ports and discovery */
+ for (i = 0; i < sas_ha->num_phys; i++) {
+ struct asd_sas_port *port = sas_ha->sas_port[i];
+
+ sas_init_port(port, sas_ha, i);
+ sas_init_disc(&port->disc, port);
+ }
+ return 0;
+}
+
+void sas_unregister_ports(struct sas_ha_struct *sas_ha)
+{
+ int i;
+
+ for (i = 0; i < sas_ha->num_phys; i++)
+ if (sas_ha->sas_phy[i]->port)
+ sas_deform_port(sas_ha->sas_phy[i]);
+
+}
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
new file mode 100644
index 00000000000..7f9e89bcac7
--- /dev/null
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -0,0 +1,786 @@
+/*
+ * Serial Attached SCSI (SAS) class SCSI Host glue.
+ *
+ * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
+ * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * 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 "sas_internal.h"
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_sas.h>
+#include "../scsi_sas_internal.h"
+
+#include <linux/err.h>
+#include <linux/blkdev.h>
+#include <linux/scatterlist.h>
+
+/* ---------- SCSI Host glue ---------- */
+
+#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)
+#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
+
+static void sas_scsi_task_done(struct sas_task *task)
+{
+ struct task_status_struct *ts = &task->task_status;
+ struct scsi_cmnd *sc = task->uldd_task;
+ unsigned ts_flags = task->task_state_flags;
+ int hs = 0, stat = 0;
+
+ if (unlikely(!sc)) {
+ SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
+ list_del_init(&task->list);
+ sas_free_task(task);
+ return;
+ }
+
+ if (ts->resp == SAS_TASK_UNDELIVERED) {
+ /* transport error */
+ hs = DID_NO_CONNECT;
+ } else { /* ts->resp == SAS_TASK_COMPLETE */
+ /* task delivered, what happened afterwards? */
+ switch (ts->stat) {
+ case SAS_DEV_NO_RESPONSE:
+ case SAS_INTERRUPTED:
+ case SAS_PHY_DOWN:
+ case SAS_NAK_R_ERR:
+ case SAS_OPEN_TO:
+ hs = DID_NO_CONNECT;
+ break;
+ case SAS_DATA_UNDERRUN:
+ sc->resid = ts->residual;
+ if (sc->request_bufflen - sc->resid < sc->underflow)
+ hs = DID_ERROR;
+ break;
+ case SAS_DATA_OVERRUN:
+ hs = DID_ERROR;
+ break;
+ case SAS_QUEUE_FULL:
+ hs = DID_SOFT_ERROR; /* retry */
+ break;
+ case SAS_DEVICE_UNKNOWN:
+ hs = DID_BAD_TARGET;
+ break;
+ case SAS_SG_ERR:
+ hs = DID_PARITY;
+ break;
+ case SAS_OPEN_REJECT:
+ if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY)
+ hs = DID_SOFT_ERROR; /* retry */
+ else
+ hs = DID_ERROR;
+ break;
+ case SAS_PROTO_RESPONSE:
+ SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP "
+ "task; please report this\n",
+ task->dev->port->ha->sas_ha_name);
+ break;
+ case SAS_ABORTED_TASK:
+ hs = DID_ABORT;
+ break;
+ case SAM_CHECK_COND:
+ memcpy(sc->sense_buffer, ts->buf,
+ max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size));
+ stat = SAM_CHECK_COND;
+ break;
+ default:
+ stat = ts->stat;
+ break;
+ }
+ }
+ ASSIGN_SAS_TASK(sc, NULL);
+ sc->result = (hs << 16) | stat;
+ list_del_init(&task->list);
+ sas_free_task(task);
+ /* This is very ugly but this is how SCSI Core works. */
+ if (ts_flags & SAS_TASK_STATE_ABORTED)
+ scsi_finish_command(sc);
+ else
+ sc->scsi_done(sc);
+}
+
+static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
+{
+ enum task_attribute ta = TASK_ATTR_SIMPLE;
+ if (cmd->request && blk_rq_tagged(cmd->request)) {
+ if (cmd->device->ordered_tags &&
+ (cmd->request->flags & REQ_HARDBARRIER))
+ ta = TASK_ATTR_HOQ;
+ }
+ return ta;
+}
+
+static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
+ struct domain_device *dev,
+ gfp_t gfp_flags)
+{
+ struct sas_task *task = sas_alloc_task(gfp_flags);
+ struct scsi_lun lun;
+
+ if (!task)
+ return NULL;
+
+ *(u32 *)cmd->sense_buffer = 0;
+ task->uldd_task = cmd;
+ ASSIGN_SAS_TASK(cmd, task);
+
+ task->dev = dev;
+ task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */
+
+ task->ssp_task.retry_count = 1;
+ int_to_scsilun(cmd->device->lun, &lun);
+ memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8);
+ task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd);
+ memcpy(task->ssp_task.cdb, cmd->cmnd, 16);
+
+ task->scatter = cmd->request_buffer;
+ task->num_scatter = cmd->use_sg;
+ task->total_xfer_len = cmd->request_bufflen;
+ task->data_dir = cmd->sc_data_direction;
+
+ task->task_done = sas_scsi_task_done;
+
+ return task;
+}
+
+static int sas_queue_up(struct sas_task *task)
+{
+ struct sas_ha_struct *sas_ha = task->dev->port->ha;
+ struct scsi_core *core = &sas_ha->core;
+ unsigned long flags;
+ LIST_HEAD(list);
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ if (sas_ha->lldd_queue_size < core->task_queue_size + 1) {
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ return -SAS_QUEUE_FULL;
+ }
+ list_add_tail(&task->list, &core->task_queue);
+ core->task_queue_size += 1;
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ up(&core->queue_thread_sema);
+
+ return 0;
+}
+
+/**
+ * sas_queuecommand -- Enqueue a command for processing
+ * @parameters: See SCSI Core documentation
+ *
+ * Note: XXX: Remove the host unlock/lock pair when SCSI Core can
+ * call us without holding an IRQ spinlock...
+ */
+int sas_queuecommand(struct scsi_cmnd *cmd,
+ void (*scsi_done)(struct scsi_cmnd *))
+{
+ int res = 0;
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+ struct Scsi_Host *host = cmd->device->host;
+ struct sas_internal *i = to_sas_internal(host->transportt);
+
+ spin_unlock_irq(host->host_lock);
+
+ {
+ struct sas_ha_struct *sas_ha = dev->port->ha;
+ struct sas_task *task;
+
+ res = -ENOMEM;
+ task = sas_create_task(cmd, dev, GFP_ATOMIC);
+ if (!task)
+ goto out;
+
+ cmd->scsi_done = scsi_done;
+ /* Queue up, Direct Mode or Task Collector Mode. */
+ if (sas_ha->lldd_max_execute_num < 2)
+ res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
+ else
+ res = sas_queue_up(task);
+
+ /* Examine */
+ if (res) {
+ SAS_DPRINTK("lldd_execute_task returned: %d\n", res);
+ ASSIGN_SAS_TASK(cmd, NULL);
+ sas_free_task(task);
+ if (res == -SAS_QUEUE_FULL) {
+ cmd->result = DID_SOFT_ERROR << 16; /* retry */
+ res = 0;
+ scsi_done(cmd);
+ }
+ goto out;
+ }
+ }
+out:
+ spin_lock_irq(host->host_lock);
+ return res;
+}
+
+static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd)
+{
+ struct scsi_cmnd *cmd, *n;
+
+ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+ if (cmd == my_cmd)
+ list_del_init(&cmd->eh_entry);
+ }
+}
+
+static void sas_scsi_clear_queue_I_T(struct list_head *error_q,
+ struct domain_device *dev)
+{
+ struct scsi_cmnd *cmd, *n;
+
+ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+ struct domain_device *x = cmd_to_domain_dev(cmd);
+
+ if (x == dev)
+ list_del_init(&cmd->eh_entry);
+ }
+}
+
+static void sas_scsi_clear_queue_port(struct list_head *error_q,
+ struct asd_sas_port *port)
+{
+ struct scsi_cmnd *cmd, *n;
+
+ list_for_each_entry_safe(cmd, n, error_q, eh_entry) {
+ struct domain_device *dev = cmd_to_domain_dev(cmd);
+ struct asd_sas_port *x = dev->port;
+
+ if (x == port)
+ list_del_init(&cmd->eh_entry);
+ }
+}
+
+enum task_disposition {
+ TASK_IS_DONE,
+ TASK_IS_ABORTED,
+ TASK_IS_AT_LU,
+ TASK_IS_NOT_AT_LU,
+};
+
+static enum task_disposition sas_scsi_find_task(struct sas_task *task)
+{
+ struct sas_ha_struct *ha = task->dev->port->ha;
+ unsigned long flags;
+ int i, res;
+ struct sas_internal *si =
+ to_sas_internal(task->dev->port->ha->core.shost->transportt);
+
+ if (ha->lldd_max_execute_num > 1) {
+ struct scsi_core *core = &ha->core;
+ struct sas_task *t, *n;
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ list_for_each_entry_safe(t, n, &core->task_queue, list) {
+ if (task == t) {
+ list_del_init(&t->list);
+ spin_unlock_irqrestore(&core->task_queue_lock,
+ flags);
+ SAS_DPRINTK("%s: task 0x%p aborted from "
+ "task_queue\n",
+ __FUNCTION__, task);
+ return TASK_IS_ABORTED;
+ }
+ }
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ }
+
+ for (i = 0; i < 5; i++) {
+ SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
+ res = si->dft->lldd_abort_task(task);
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+ task);
+ return TASK_IS_DONE;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("%s: task 0x%p is aborted\n",
+ __FUNCTION__, task);
+ return TASK_IS_ABORTED;
+ } else if (si->dft->lldd_query_task) {
+ SAS_DPRINTK("%s: querying task 0x%p\n",
+ __FUNCTION__, task);
+ res = si->dft->lldd_query_task(task);
+ if (res == TMF_RESP_FUNC_SUCC) {
+ SAS_DPRINTK("%s: task 0x%p at LU\n",
+ __FUNCTION__, task);
+ return TASK_IS_AT_LU;
+ } else if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("%s: task 0x%p not at LU\n",
+ __FUNCTION__, task);
+ return TASK_IS_NOT_AT_LU;
+ }
+ }
+ }
+ return res;
+}
+
+static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd)
+{
+ int res = TMF_RESP_FUNC_FAILED;
+ struct scsi_lun lun;
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+
+ int_to_scsilun(cmd->device->lun, &lun);
+
+ SAS_DPRINTK("eh: device %llx LUN %x has the task\n",
+ SAS_ADDR(dev->sas_addr),
+ cmd->device->lun);
+
+ if (i->dft->lldd_abort_task_set)
+ res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun);
+
+ if (res == TMF_RESP_FUNC_FAILED) {
+ if (i->dft->lldd_clear_task_set)
+ res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun);
+ }
+
+ if (res == TMF_RESP_FUNC_FAILED) {
+ if (i->dft->lldd_lu_reset)
+ res = i->dft->lldd_lu_reset(dev, lun.scsi_lun);
+ }
+
+ return res;
+}
+
+static int sas_recover_I_T(struct domain_device *dev)
+{
+ int res = TMF_RESP_FUNC_FAILED;
+ struct sas_internal *i =
+ to_sas_internal(dev->port->ha->core.shost->transportt);
+
+ SAS_DPRINTK("I_T nexus reset for dev %016llx\n",
+ SAS_ADDR(dev->sas_addr));
+
+ if (i->dft->lldd_I_T_nexus_reset)
+ res = i->dft->lldd_I_T_nexus_reset(dev);
+
+ return res;
+}
+
+void sas_scsi_recover_host(struct Scsi_Host *shost)
+{
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ unsigned long flags;
+ LIST_HEAD(error_q);
+ struct scsi_cmnd *cmd, *n;
+ enum task_disposition res = TASK_IS_DONE;
+ int tmf_resp;
+ struct sas_internal *i = to_sas_internal(shost->transportt);
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ list_splice_init(&shost->eh_cmd_q, &error_q);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+
+ /* All tasks on this list were marked SAS_TASK_STATE_ABORTED
+ * by sas_scsi_timed_out() callback.
+ */
+Again:
+ SAS_DPRINTK("going over list...\n");
+ list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
+ struct sas_task *task = TO_SAS_TASK(cmd);
+
+ SAS_DPRINTK("trying to find task 0x%p\n", task);
+ list_del_init(&cmd->eh_entry);
+ res = sas_scsi_find_task(task);
+
+ cmd->eh_eflags = 0;
+ shost->host_failed--;
+
+ switch (res) {
+ case TASK_IS_DONE:
+ SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+ task);
+ task->task_done(task);
+ continue;
+ case TASK_IS_ABORTED:
+ SAS_DPRINTK("%s: task 0x%p is aborted\n",
+ __FUNCTION__, task);
+ task->task_done(task);
+ continue;
+ case TASK_IS_AT_LU:
+ SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
+ tmf_resp = sas_recover_lu(task->dev, cmd);
+ if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("dev %016llx LU %x is "
+ "recovered\n",
+ SAS_ADDR(task->dev),
+ cmd->device->lun);
+ task->task_done(task);
+ sas_scsi_clear_queue_lu(&error_q, cmd);
+ goto Again;
+ }
+ /* fallthrough */
+ case TASK_IS_NOT_AT_LU:
+ SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n",
+ task);
+ tmf_resp = sas_recover_I_T(task->dev);
+ if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("I_T %016llx recovered\n",
+ SAS_ADDR(task->dev->sas_addr));
+ task->task_done(task);
+ sas_scsi_clear_queue_I_T(&error_q, task->dev);
+ goto Again;
+ }
+ /* Hammer time :-) */
+ if (i->dft->lldd_clear_nexus_port) {
+ struct asd_sas_port *port = task->dev->port;
+ SAS_DPRINTK("clearing nexus for port:%d\n",
+ port->id);
+ res = i->dft->lldd_clear_nexus_port(port);
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("clear nexus port:%d "
+ "succeeded\n", port->id);
+ task->task_done(task);
+ sas_scsi_clear_queue_port(&error_q,
+ port);
+ goto Again;
+ }
+ }
+ if (i->dft->lldd_clear_nexus_ha) {
+ SAS_DPRINTK("clear nexus ha\n");
+ res = i->dft->lldd_clear_nexus_ha(ha);
+ if (res == TMF_RESP_FUNC_COMPLETE) {
+ SAS_DPRINTK("clear nexus ha "
+ "succeeded\n");
+ task->task_done(task);
+ goto out;
+ }
+ }
+ /* If we are here -- this means that no amount
+ * of effort could recover from errors. Quite
+ * possibly the HA just disappeared.
+ */
+ SAS_DPRINTK("error from device %llx, LUN %x "
+ "couldn't be recovered in any way\n",
+ SAS_ADDR(task->dev->sas_addr),
+ cmd->device->lun);
+
+ task->task_done(task);
+ goto clear_q;
+ }
+ }
+out:
+ SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+ return;
+clear_q:
+ SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
+ list_for_each_entry_safe(cmd, n, &error_q, eh_entry) {
+ struct sas_task *task = TO_SAS_TASK(cmd);
+ list_del_init(&cmd->eh_entry);
+ task->task_done(task);
+ }
+}
+
+enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+{
+ struct sas_task *task = TO_SAS_TASK(cmd);
+ unsigned long flags;
+
+ if (!task) {
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+ cmd, task);
+ return EH_HANDLED;
+ }
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
+ cmd, task);
+ return EH_HANDLED;
+ }
+ task->task_state_flags |= SAS_TASK_STATE_ABORTED;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+ cmd, task);
+
+ return EH_NOT_HANDLED;
+}
+
+struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy)
+{
+ struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent);
+ struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost);
+ struct domain_device *found_dev = NULL;
+ int i;
+
+ spin_lock(&ha->phy_port_lock);
+ for (i = 0; i < ha->num_phys; i++) {
+ struct asd_sas_port *port = ha->sas_port[i];
+ struct domain_device *dev;
+
+ spin_lock(&port->dev_list_lock);
+ list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+ if (rphy == dev->rphy) {
+ found_dev = dev;
+ spin_unlock(&port->dev_list_lock);
+ goto found;
+ }
+ }
+ spin_unlock(&port->dev_list_lock);
+ }
+ found:
+ spin_unlock(&ha->phy_port_lock);
+
+ return found_dev;
+}
+
+static inline struct domain_device *sas_find_target(struct scsi_target *starget)
+{
+ struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent);
+
+ return sas_find_dev_by_rphy(rphy);
+}
+
+int sas_target_alloc(struct scsi_target *starget)
+{
+ struct domain_device *found_dev = sas_find_target(starget);
+
+ if (!found_dev)
+ return -ENODEV;
+
+ starget->hostdata = found_dev;
+ return 0;
+}
+
+#define SAS_DEF_QD 32
+#define SAS_MAX_QD 64
+
+int sas_slave_configure(struct scsi_device *scsi_dev)
+{
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+ struct sas_ha_struct *sas_ha;
+
+ BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE);
+
+ sas_ha = dev->port->ha;
+
+ sas_read_port_mode_page(scsi_dev);
+
+ if (scsi_dev->tagged_supported) {
+ scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG);
+ scsi_activate_tcq(scsi_dev, SAS_DEF_QD);
+ } else {
+ SAS_DPRINTK("device %llx, LUN %x doesn't support "
+ "TCQ\n", SAS_ADDR(dev->sas_addr),
+ scsi_dev->lun);
+ scsi_dev->tagged_supported = 0;
+ scsi_set_tag_type(scsi_dev, 0);
+ scsi_deactivate_tcq(scsi_dev, 1);
+ }
+
+ return 0;
+}
+
+void sas_slave_destroy(struct scsi_device *scsi_dev)
+{
+}
+
+int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth)
+{
+ int res = min(new_depth, SAS_MAX_QD);
+
+ if (scsi_dev->tagged_supported)
+ scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev),
+ res);
+ else {
+ struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
+ sas_printk("device %llx LUN %x queue depth changed to 1\n",
+ SAS_ADDR(dev->sas_addr),
+ scsi_dev->lun);
+ scsi_adjust_queue_depth(scsi_dev, 0, 1);
+ res = 1;
+ }
+
+ return res;
+}
+
+int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
+{
+ if (!scsi_dev->tagged_supported)
+ return 0;
+
+ scsi_deactivate_tcq(scsi_dev, 1);
+
+ scsi_set_tag_type(scsi_dev, qt);
+ scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
+
+ return qt;
+}
+
+int sas_bios_param(struct scsi_device *scsi_dev,
+ struct block_device *bdev,
+ sector_t capacity, int *hsc)
+{
+ hsc[0] = 255;
+ hsc[1] = 63;
+ sector_div(capacity, 255*63);
+ hsc[2] = capacity;
+
+ return 0;
+}
+
+/* ---------- Task Collector Thread implementation ---------- */
+
+static void sas_queue(struct sas_ha_struct *sas_ha)
+{
+ struct scsi_core *core = &sas_ha->core;
+ unsigned long flags;
+ LIST_HEAD(q);
+ int can_queue;
+ int res;
+ struct sas_internal *i = to_sas_internal(core->shost->transportt);
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ while (!core->queue_thread_kill &&
+ !list_empty(&core->task_queue)) {
+
+ can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
+ if (can_queue >= 0) {
+ can_queue = core->task_queue_size;
+ list_splice_init(&core->task_queue, &q);
+ } else {
+ struct list_head *a, *n;
+
+ can_queue = sas_ha->lldd_queue_size;
+ list_for_each_safe(a, n, &core->task_queue) {
+ list_move_tail(a, &q);
+ if (--can_queue == 0)
+ break;
+ }
+ can_queue = sas_ha->lldd_queue_size;
+ }
+ core->task_queue_size -= can_queue;
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+ {
+ struct sas_task *task = list_entry(q.next,
+ struct sas_task,
+ list);
+ list_del_init(&q);
+ res = i->dft->lldd_execute_task(task, can_queue,
+ GFP_KERNEL);
+ if (unlikely(res))
+ __list_add(&q, task->list.prev, &task->list);
+ }
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ if (res) {
+ list_splice_init(&q, &core->task_queue); /*at head*/
+ core->task_queue_size += can_queue;
+ }
+ }
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+}
+
+static DECLARE_COMPLETION(queue_th_comp);
+
+/**
+ * sas_queue_thread -- The Task Collector thread
+ * @_sas_ha: pointer to struct sas_ha
+ */
+static int sas_queue_thread(void *_sas_ha)
+{
+ struct sas_ha_struct *sas_ha = _sas_ha;
+ struct scsi_core *core = &sas_ha->core;
+
+ daemonize("sas_queue_%d", core->shost->host_no);
+ current->flags |= PF_NOFREEZE;
+
+ complete(&queue_th_comp);
+
+ while (1) {
+ down_interruptible(&core->queue_thread_sema);
+ sas_queue(sas_ha);
+ if (core->queue_thread_kill)
+ break;
+ }
+
+ complete(&queue_th_comp);
+
+ return 0;
+}
+
+int sas_init_queue(struct sas_ha_struct *sas_ha)
+{
+ int res;
+ struct scsi_core *core = &sas_ha->core;
+
+ spin_lock_init(&core->task_queue_lock);
+ core->task_queue_size = 0;
+ INIT_LIST_HEAD(&core->task_queue);
+ init_MUTEX_LOCKED(&core->queue_thread_sema);
+
+ res = kernel_thread(sas_queue_thread, sas_ha, 0);
+ if (res >= 0)
+ wait_for_completion(&queue_th_comp);
+
+ return res < 0 ? res : 0;
+}
+
+void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
+{
+ unsigned long flags;
+ struct scsi_core *core = &sas_ha->core;
+ struct sas_task *task, *n;
+
+ init_completion(&queue_th_comp);
+ core->queue_thread_kill = 1;
+ up(&core->queue_thread_sema);
+ wait_for_completion(&queue_th_comp);
+
+ if (!list_empty(&core->task_queue))
+ SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
+ SAS_ADDR(sas_ha->sas_addr));
+
+ spin_lock_irqsave(&core->task_queue_lock, flags);
+ list_for_each_entry_safe(task, n, &core->task_queue, list) {
+ struct scsi_cmnd *cmd = task->uldd_task;
+
+ list_del_init(&task->list);
+
+ ASSIGN_SAS_TASK(cmd, NULL);
+ sas_free_task(task);
+ cmd->result = DID_ABORT << 16;
+ cmd->scsi_done(cmd);
+ }
+ spin_unlock_irqrestore(&core->task_queue_lock, flags);
+}
+
+EXPORT_SYMBOL_GPL(sas_queuecommand);
+EXPORT_SYMBOL_GPL(sas_target_alloc);
+EXPORT_SYMBOL_GPL(sas_slave_configure);
+EXPORT_SYMBOL_GPL(sas_slave_destroy);
+EXPORT_SYMBOL_GPL(sas_change_queue_depth);
+EXPORT_SYMBOL_GPL(sas_change_queue_type);
+EXPORT_SYMBOL_GPL(sas_bios_param);
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h
index 087c44539a1..3f7f5f8abd7 100644
--- a/drivers/scsi/lpfc/lpfc.h
+++ b/drivers/scsi/lpfc/lpfc.h
@@ -21,10 +21,12 @@
struct lpfc_sli2_slim;
-#define LPFC_MAX_TARGET 256 /* max targets supported */
-#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els req */
-#define LPFC_MAX_NS_RETRY 3 /* max NameServer retries */
+#define LPFC_MAX_TARGET 256 /* max number of targets supported */
+#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els
+ requests */
+#define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact
+ the NameServer before giving up. */
#define LPFC_DFT_HBA_Q_DEPTH 2048 /* max cmds per hba */
#define LPFC_LC_HBA_Q_DEPTH 1024 /* max cmds per low cost hba */
#define LPFC_LP101_HBA_Q_DEPTH 128 /* max cmds per low cost hba */
@@ -41,7 +43,6 @@ struct lpfc_sli2_slim;
(( (u64)(high)<<16 ) << 16)|( (u64)(low))))
/* Provide maximum configuration definitions. */
#define LPFC_DRVR_TIMEOUT 16 /* driver iocb timeout value in sec */
-#define MAX_FCP_TARGET 256 /* max num of FCP targets supported */
#define FC_MAX_ADPTMSG 64
#define MAX_HBAEVT 32
@@ -174,7 +175,6 @@ struct lpfc_hba {
dma_addr_t slim2p_mapping;
uint16_t pci_cfg_value;
- struct semaphore hba_can_block;
int32_t hba_state;
#define LPFC_STATE_UNKNOWN 0 /* HBA state is unknown */
@@ -285,6 +285,7 @@ struct lpfc_hba {
uint32_t cfg_log_verbose;
uint32_t cfg_lun_queue_depth;
uint32_t cfg_nodev_tmo;
+ uint32_t cfg_devloss_tmo;
uint32_t cfg_hba_queue_depth;
uint32_t cfg_fcp_class;
uint32_t cfg_use_adisc;
@@ -302,6 +303,9 @@ struct lpfc_hba {
uint32_t cfg_poll_tmo;
uint32_t cfg_sg_seg_cnt;
uint32_t cfg_sg_dma_buf_size;
+ uint64_t cfg_soft_wwpn;
+
+ uint32_t dev_loss_tmo_changed;
lpfc_vpd_t vpd; /* vital product data */
@@ -351,6 +355,8 @@ struct lpfc_hba {
#define VPD_PORT 0x8 /* valid vpd port data */
#define VPD_MASK 0xf /* mask for any vpd data */
+ uint8_t soft_wwpn_enable;
+
struct timer_list fcp_poll_timer;
struct timer_list els_tmofunc;
@@ -391,3 +397,5 @@ struct rnidrsp {
struct list_head list;
uint32_t data;
};
+
+#define FC_REG_DUMP_EVENT 0x10 /* Register for Dump events */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index b62a72dfab2..9496e87c135 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -39,6 +39,9 @@
#include "lpfc_compat.h"
#include "lpfc_crtn.h"
+#define LPFC_DEF_DEVLOSS_TMO 30
+#define LPFC_MIN_DEVLOSS_TMO 1
+#define LPFC_MAX_DEVLOSS_TMO 255
static void
lpfc_jedec_to_ascii(int incr, char hdw[])
@@ -219,8 +222,18 @@ lpfc_issue_lip(struct Scsi_Host *host)
return -ENOMEM;
memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
- lpfc_init_link(phba, pmboxq, phba->cfg_topology, phba->cfg_link_speed);
- mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+ pmboxq->mb.mbxCommand = MBX_DOWN_LINK;
+ pmboxq->mb.mbxOwner = OWN_HOST;
+
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2);
+
+ if ((mbxstatus == MBX_SUCCESS) && (pmboxq->mb.mbxStatus == 0)) {
+ memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t));
+ lpfc_init_link(phba, pmboxq, phba->cfg_topology,
+ phba->cfg_link_speed);
+ mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq,
+ phba->fc_ratov * 2);
+ }
if (mbxstatus == MBX_TIMEOUT)
pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
@@ -233,51 +246,53 @@ lpfc_issue_lip(struct Scsi_Host *host)
return 0;
}
-static ssize_t
-lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
+static int
+lpfc_selective_reset(struct lpfc_hba *phba)
{
- struct Scsi_Host *host = class_to_shost(cdev);
- struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
+ struct completion online_compl;
+ int status = 0;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &status, &online_compl,
+ LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+
+ if (status != 0)
+ return -EIO;
+
+ return 0;
}
static ssize_t
-lpfc_board_online_show(struct class_device *cdev, char *buf)
+lpfc_issue_reset(struct class_device *cdev, const char *buf, size_t count)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int status = -EINVAL;
- if (phba->fc_flag & FC_OFFLINE_MODE)
- return snprintf(buf, PAGE_SIZE, "0\n");
+ if (strncmp(buf, "selective", sizeof("selective") - 1) == 0)
+ status = lpfc_selective_reset(phba);
+
+ if (status == 0)
+ return strlen(buf);
else
- return snprintf(buf, PAGE_SIZE, "1\n");
+ return status;
}
static ssize_t
-lpfc_board_online_store(struct class_device *cdev, const char *buf,
- size_t count)
+lpfc_nport_evt_cnt_show(struct class_device *cdev, char *buf)
{
struct Scsi_Host *host = class_to_shost(cdev);
struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
- struct completion online_compl;
- int val=0, status=0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- init_completion(&online_compl);
-
- if (val)
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_ONLINE);
- else
- lpfc_workq_post_event(phba, &status, &online_compl,
- LPFC_EVT_OFFLINE);
- wait_for_completion(&online_compl);
- if (!status)
- return strlen(buf);
- else
- return -EIO;
+ return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt);
}
static ssize_t
@@ -532,10 +547,122 @@ static CLASS_DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show,
NULL);
static CLASS_DEVICE_ATTR(management_version, S_IRUGO, management_version_show,
NULL);
-static CLASS_DEVICE_ATTR(board_online, S_IRUGO | S_IWUSR,
- lpfc_board_online_show, lpfc_board_online_store);
static CLASS_DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR,
lpfc_board_mode_show, lpfc_board_mode_store);
+static CLASS_DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset);
+
+
+static char *lpfc_soft_wwpn_key = "C99G71SL8032A";
+
+static ssize_t
+lpfc_soft_wwpn_enable_store(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ unsigned int cnt = count;
+
+ /*
+ * We're doing a simple sanity check for soft_wwpn setting.
+ * We require that the user write a specific key to enable
+ * the soft_wwpn attribute to be settable. Once the attribute
+ * is written, the enable key resets. If further updates are
+ * desired, the key must be written again to re-enable the
+ * attribute.
+ *
+ * The "key" is not secret - it is a hardcoded string shown
+ * here. The intent is to protect against the random user or
+ * application that is just writing attributes.
+ */
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ if ((cnt != strlen(lpfc_soft_wwpn_key)) ||
+ (strncmp(buf, lpfc_soft_wwpn_key, strlen(lpfc_soft_wwpn_key)) != 0))
+ return -EINVAL;
+
+ phba->soft_wwpn_enable = 1;
+ return count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwpn_enable, S_IWUSR, NULL,
+ lpfc_soft_wwpn_enable_store);
+
+static ssize_t
+lpfc_soft_wwpn_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n", phba->cfg_soft_wwpn);
+}
+
+
+static ssize_t
+lpfc_soft_wwpn_store(struct class_device *cdev, const char *buf, size_t count)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ struct completion online_compl;
+ int stat1=0, stat2=0;
+ unsigned int i, j, cnt=count;
+ u8 wwpn[8];
+
+ /* count may include a LF at end of string */
+ if (buf[cnt-1] == '\n')
+ cnt--;
+
+ if (!phba->soft_wwpn_enable || (cnt < 16) || (cnt > 18) ||
+ ((cnt == 17) && (*buf++ != 'x')) ||
+ ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x'))))
+ return -EINVAL;
+
+ phba->soft_wwpn_enable = 0;
+
+ memset(wwpn, 0, sizeof(wwpn));
+
+ /* Validate and store the new name */
+ for (i=0, j=0; i < 16; i++) {
+ if ((*buf >= 'a') && (*buf <= 'f'))
+ j = ((j << 4) | ((*buf++ -'a') + 10));
+ else if ((*buf >= 'A') && (*buf <= 'F'))
+ j = ((j << 4) | ((*buf++ -'A') + 10));
+ else if ((*buf >= '0') && (*buf <= '9'))
+ j = ((j << 4) | (*buf++ -'0'));
+ else
+ return -EINVAL;
+ if (i % 2) {
+ wwpn[i/2] = j & 0xff;
+ j = 0;
+ }
+ }
+ phba->cfg_soft_wwpn = wwn_to_u64(wwpn);
+ fc_host_port_name(host) = phba->cfg_soft_wwpn;
+
+ dev_printk(KERN_NOTICE, &phba->pcidev->dev,
+ "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no);
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &stat1, &online_compl, LPFC_EVT_OFFLINE);
+ wait_for_completion(&online_compl);
+ if (stat1)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0463 lpfc_soft_wwpn attribute set failed to reinit "
+ "adapter - %d\n", phba->brd_no, stat1);
+
+ init_completion(&online_compl);
+ lpfc_workq_post_event(phba, &stat2, &online_compl, LPFC_EVT_ONLINE);
+ wait_for_completion(&online_compl);
+ if (stat2)
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0464 lpfc_soft_wwpn attribute set failed to reinit "
+ "adapter - %d\n", phba->brd_no, stat2);
+
+ return (stat1 || stat2) ? -EIO : count;
+}
+static CLASS_DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\
+ lpfc_soft_wwpn_show, lpfc_soft_wwpn_store);
+
static int lpfc_poll = 0;
module_param(lpfc_poll, int, 0);
@@ -548,6 +675,123 @@ static CLASS_DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR,
lpfc_poll_show, lpfc_poll_store);
/*
+# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
+# until the timer expires. Value range is [0,255]. Default value is 30.
+*/
+static int lpfc_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+static int lpfc_devloss_tmo = LPFC_DEF_DEVLOSS_TMO;
+module_param(lpfc_nodev_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_nodev_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+static ssize_t
+lpfc_nodev_tmo_show(struct class_device *cdev, char *buf)
+{
+ struct Scsi_Host *host = class_to_shost(cdev);
+ struct lpfc_hba *phba = (struct lpfc_hba*)host->hostdata;
+ int val = 0;
+ val = phba->cfg_devloss_tmo;
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ phba->cfg_devloss_tmo);
+}
+
+static int
+lpfc_nodev_tmo_init(struct lpfc_hba *phba, int val)
+{
+ static int warned;
+ if (phba->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = phba->cfg_devloss_tmo;
+ if (!warned && val != LPFC_DEF_DEVLOSS_TMO) {
+ warned = 1;
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0402 Ignoring nodev_tmo module "
+ "parameter because devloss_tmo is"
+ " set.\n",
+ phba->brd_no);
+ }
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0400 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO);
+ phba->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO;
+ return -EINVAL;
+}
+
+static int
+lpfc_nodev_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (phba->dev_loss_tmo_changed ||
+ (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) {
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0401 Ignoring change to nodev_tmo "
+ "because devloss_tmo is set.\n",
+ phba->brd_no);
+ return 0;
+ }
+
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0403 lpfc_nodev_tmo attribute cannot be set to %d, "
+ "allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(nodev_tmo)
+
+static CLASS_DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR,
+ lpfc_nodev_tmo_show, lpfc_nodev_tmo_store);
+
+/*
+# lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that
+# disappear until the timer expires. Value range is [0,255]. Default
+# value is 30.
+*/
+module_param(lpfc_devloss_tmo, int, 0);
+MODULE_PARM_DESC(lpfc_devloss_tmo,
+ "Seconds driver will hold I/O waiting "
+ "for a device to come back");
+lpfc_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO,
+ LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO)
+lpfc_param_show(devloss_tmo)
+static int
+lpfc_devloss_tmo_set(struct lpfc_hba *phba, int val)
+{
+ if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) {
+ phba->cfg_nodev_tmo = val;
+ phba->cfg_devloss_tmo = val;
+ phba->dev_loss_tmo_changed = 1;
+ return 0;
+ }
+
+ lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
+ "%d:0404 lpfc_devloss_tmo attribute cannot be set to"
+ " %d, allowed range is [%d, %d]\n",
+ phba->brd_no, val, LPFC_MIN_DEVLOSS_TMO,
+ LPFC_MAX_DEVLOSS_TMO);
+ return -EINVAL;
+}
+
+lpfc_param_store(devloss_tmo)
+static CLASS_DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR,
+ lpfc_devloss_tmo_show, lpfc_devloss_tmo_store);
+
+/*
# lpfc_log_verbose: Only turn this flag on if you are willing to risk being
# deluged with LOTS of information.
# You can set a bit mask to record specific types of verbose messages:
@@ -606,14 +850,6 @@ LPFC_ATTR_R(scan_down, 1, 0, 1,
"Start scanning for devices from highest ALPA to lowest");
/*
-# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear
-# until the timer expires. Value range is [0,255]. Default value is 30.
-# NOTE: this MUST be less then the SCSI Layer command timeout - 1.
-*/
-LPFC_ATTR_RW(nodev_tmo, 30, 0, 255,
- "Seconds driver will hold I/O waiting for a device to come back");
-
-/*
# lpfc_topology: link topology for init link
# 0x0 = attempt loop mode then point-to-point
# 0x01 = internal loopback mode
@@ -695,12 +931,12 @@ LPFC_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands "
"during discovery");
/*
-# lpfc_max_luns: maximum number of LUNs per target driver will support
-# Value range is [1,32768]. Default value is 256.
-# NOTE: The SCSI layer will scan each target for this many luns
+# lpfc_max_luns: maximum allowed LUN.
+# Value range is [0,65535]. Default value is 255.
+# NOTE: The SCSI layer might probe all allowed LUN on some old targets.
*/
-LPFC_ATTR_R(max_luns, 256, 1, 32768,
- "Maximum number of LUNs per target driver will support");
+LPFC_ATTR_R(max_luns, 255, 0, 65535,
+ "Maximum allowed LUN");
/*
# lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring.
@@ -709,6 +945,7 @@ LPFC_ATTR_R(max_luns, 256, 1, 32768,
LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
"Milliseconds driver will wait between polling FCP ring");
+
struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_info,
&class_device_attr_serialnum,
@@ -726,6 +963,7 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_lun_queue_depth,
&class_device_attr_lpfc_hba_queue_depth,
&class_device_attr_lpfc_nodev_tmo,
+ &class_device_attr_lpfc_devloss_tmo,
&class_device_attr_lpfc_fcp_class,
&class_device_attr_lpfc_use_adisc,
&class_device_attr_lpfc_ack0,
@@ -739,10 +977,12 @@ struct class_device_attribute *lpfc_host_attrs[] = {
&class_device_attr_lpfc_max_luns,
&class_device_attr_nport_evt_cnt,
&class_device_attr_management_version,
- &class_device_attr_board_online,
&class_device_attr_board_mode,
+ &class_device_attr_issue_reset,
&class_device_attr_lpfc_poll,
&class_device_attr_lpfc_poll_tmo,
+ &class_device_attr_lpfc_soft_wwpn,
+ &class_device_attr_lpfc_soft_wwpn_enable,
NULL,
};
@@ -873,7 +1113,7 @@ sysfs_mbox_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
phba->sysfs_mbox.mbox == NULL ) {
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -EINVAL;
+ return -EAGAIN;
}
}
@@ -989,14 +1229,15 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
spin_unlock_irq(phba->host->host_lock);
rc = lpfc_sli_issue_mbox_wait (phba,
phba->sysfs_mbox.mbox,
- phba->fc_ratov * 2);
+ lpfc_mbox_tmo_val(phba,
+ phba->sysfs_mbox.mbox->mb.mbxCommand) * HZ);
spin_lock_irq(phba->host->host_lock);
}
if (rc != MBX_SUCCESS) {
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -ENODEV;
+ return (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV;
}
phba->sysfs_mbox.state = SMBOX_READING;
}
@@ -1005,7 +1246,7 @@ sysfs_mbox_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
printk(KERN_WARNING "mbox_read: Bad State\n");
sysfs_mbox_idle(phba);
spin_unlock_irq(host->host_lock);
- return -EINVAL;
+ return -EAGAIN;
}
memcpy(buf, (uint8_t *) & phba->sysfs_mbox.mbox->mb + off, count);
@@ -1192,6 +1433,15 @@ lpfc_get_host_fabric_name (struct Scsi_Host *shost)
fc_host_fabric_name(shost) = node_name;
}
+static void
+lpfc_get_host_symbolic_name (struct Scsi_Host *shost)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba*)shost->hostdata;
+
+ spin_lock_irq(shost->host_lock);
+ lpfc_get_hba_sym_node_name(phba, fc_host_symbolic_name(shost));
+ spin_unlock_irq(shost->host_lock);
+}
static struct fc_host_statistics *
lpfc_get_stats(struct Scsi_Host *shost)
@@ -1199,8 +1449,10 @@ lpfc_get_stats(struct Scsi_Host *shost)
struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
struct lpfc_sli *psli = &phba->sli;
struct fc_host_statistics *hs = &phba->link_stats;
+ struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
LPFC_MBOXQ_t *pmboxq;
MAILBOX_t *pmb;
+ unsigned long seconds;
int rc = 0;
pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
@@ -1261,22 +1513,103 @@ lpfc_get_stats(struct Scsi_Host *shost)
hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
hs->error_frames = pmb->un.varRdLnk.crcCnt;
+ hs->link_failure_count -= lso->link_failure_count;
+ hs->loss_of_sync_count -= lso->loss_of_sync_count;
+ hs->loss_of_signal_count -= lso->loss_of_signal_count;
+ hs->prim_seq_protocol_err_count -= lso->prim_seq_protocol_err_count;
+ hs->invalid_tx_word_count -= lso->invalid_tx_word_count;
+ hs->invalid_crc_count -= lso->invalid_crc_count;
+ hs->error_frames -= lso->error_frames;
+
if (phba->fc_topology == TOPOLOGY_LOOP) {
hs->lip_count = (phba->fc_eventTag >> 1);
+ hs->lip_count -= lso->link_events;
hs->nos_count = -1;
} else {
hs->lip_count = -1;
hs->nos_count = (phba->fc_eventTag >> 1);
+ hs->nos_count -= lso->link_events;
}
hs->dumped_frames = -1;
-/* FIX ME */
- /*hs->SecondsSinceLastReset = (jiffies - lpfc_loadtime) / HZ;*/
+ seconds = get_seconds();
+ if (seconds < psli->stats_start)
+ hs->seconds_since_last_reset = seconds +
+ ((unsigned long)-1 - psli->stats_start);
+ else
+ hs->seconds_since_last_reset = seconds - psli->stats_start;
return hs;
}
+static void
+lpfc_reset_stats(struct Scsi_Host *shost)
+{
+ struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata;
+ struct lpfc_sli *psli = &phba->sli;
+ struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets;
+ LPFC_MBOXQ_t *pmboxq;
+ MAILBOX_t *pmb;
+ int rc = 0;
+
+ pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+ if (!pmboxq)
+ return;
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+
+ pmb = &pmboxq->mb;
+ pmb->mbxCommand = MBX_READ_STATUS;
+ pmb->mbxOwner = OWN_HOST;
+ pmb->un.varWords[0] = 0x1; /* reset request */
+ pmboxq->context1 = NULL;
+
+ if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT)
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ else
+ mempool_free(pmboxq, phba->mbox_mem_pool);
+ return;
+ }
+
+ memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t));
+ pmb->mbxCommand = MBX_READ_LNK_STAT;
+ pmb->mbxOwner = OWN_HOST;
+ pmboxq->context1 = NULL;
+
+ if ((phba->fc_flag & FC_OFFLINE_MODE) ||
+ (!(psli->sli_flag & LPFC_SLI2_ACTIVE)))
+ rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL);
+ else
+ rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2);
+
+ if (rc != MBX_SUCCESS) {
+ if (rc == MBX_TIMEOUT)
+ pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+ else
+ mempool_free( pmboxq, phba->mbox_mem_pool);
+ return;
+ }
+
+ lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt;
+ lso->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt;
+ lso->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt;
+ lso->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt;
+ lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord;
+ lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt;
+ lso->error_frames = pmb->un.varRdLnk.crcCnt;
+ lso->link_events = (phba->fc_eventTag >> 1);
+
+ psli->stats_start = get_seconds();
+
+ return;
+}
/*
* The LPFC driver treats linkdown handling as target loss events so there
@@ -1346,27 +1679,12 @@ lpfc_get_starget_port_name(struct scsi_target *starget)
}
static void
-lpfc_get_rport_loss_tmo(struct fc_rport *rport)
-{
- /*
- * Return the driver's global value for device loss timeout plus
- * five seconds to allow the driver's nodev timer to run.
- */
- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
-}
-
-static void
lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
- /*
- * The driver doesn't have a per-target timeout setting. Set
- * this value globally. lpfc_nodev_tmo should be greater then 0.
- */
if (timeout)
- lpfc_nodev_tmo = timeout;
+ rport->dev_loss_tmo = timeout;
else
- lpfc_nodev_tmo = 1;
- rport->dev_loss_tmo = lpfc_nodev_tmo + 5;
+ rport->dev_loss_tmo = 1;
}
@@ -1391,7 +1709,6 @@ struct fc_function_template lpfc_transport_functions = {
.show_host_port_name = 1,
.show_host_supported_classes = 1,
.show_host_supported_fc4s = 1,
- .show_host_symbolic_name = 1,
.show_host_supported_speeds = 1,
.show_host_maxframe_size = 1,
@@ -1414,20 +1731,21 @@ struct fc_function_template lpfc_transport_functions = {
.get_host_fabric_name = lpfc_get_host_fabric_name,
.show_host_fabric_name = 1,
+ .get_host_symbolic_name = lpfc_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+
/*
* The LPFC driver treats linkdown handling as target loss events
* so there are no sysfs handlers for link_down_tmo.
*/
.get_fc_host_stats = lpfc_get_stats,
-
- /* the LPFC driver doesn't support resetting stats yet */
+ .reset_fc_host_stats = lpfc_reset_stats,
.dd_fcrport_size = sizeof(struct lpfc_rport_data),
.show_rport_maxframe_size = 1,
.show_rport_supported_classes = 1,
- .get_rport_dev_loss_tmo = lpfc_get_rport_loss_tmo,
.set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo,
.show_rport_dev_loss_tmo = 1,
@@ -1441,6 +1759,8 @@ struct fc_function_template lpfc_transport_functions = {
.show_starget_port_name = 1,
.issue_fc_host_lip = lpfc_issue_lip,
+ .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk,
+ .terminate_rport_io = lpfc_terminate_rport_io,
};
void
@@ -1456,14 +1776,15 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
lpfc_ack0_init(phba, lpfc_ack0);
lpfc_topology_init(phba, lpfc_topology);
lpfc_scan_down_init(phba, lpfc_scan_down);
- lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
lpfc_link_speed_init(phba, lpfc_link_speed);
lpfc_fdmi_on_init(phba, lpfc_fdmi_on);
lpfc_discovery_threads_init(phba, lpfc_discovery_threads);
lpfc_max_luns_init(phba, lpfc_max_luns);
lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
-
+ lpfc_devloss_tmo_init(phba, lpfc_devloss_tmo);
+ lpfc_nodev_tmo_init(phba, lpfc_nodev_tmo);
phba->cfg_poll = lpfc_poll;
+ phba->cfg_soft_wwpn = 0L;
/*
* The total number of segments is the configuration value plus 2
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index ee22173fce4..3d684496acd 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -18,6 +18,7 @@
* included with this package. *
*******************************************************************/
+struct fc_rport;
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
@@ -127,6 +128,7 @@ void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
+int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
int lpfc_mem_alloc(struct lpfc_hba *);
void lpfc_mem_free(struct lpfc_hba *);
@@ -147,6 +149,7 @@ int lpfc_sli_hba_setup(struct lpfc_hba *);
int lpfc_sli_hba_down(struct lpfc_hba *);
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
+int lpfc_sli_flush_mbox_queue(struct lpfc_hba *);
int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
struct lpfc_sli_ring *, uint32_t);
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
@@ -198,6 +201,8 @@ extern struct scsi_host_template lpfc_template;
extern struct fc_function_template lpfc_transport_functions;
void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
+void lpfc_terminate_rport_io(struct fc_rport *);
+void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
#define HBA_EVENT_RSCN 5
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index b65ee57af53..ae410645899 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -131,6 +131,7 @@ lpfc_ct_unsol_event(struct lpfc_hba * phba,
}
ct_unsol_event_exit_piocbq:
+ list_del(&head);
if (pmbuf) {
list_for_each_entry_safe(matp, next_matp, &pmbuf->list, list) {
lpfc_mbuf_free(phba, matp->virt, matp->phys);
@@ -323,7 +324,6 @@ lpfc_ns_rsp(struct lpfc_hba * phba, struct lpfc_dmabuf * mp, uint32_t Size)
struct lpfc_sli_ct_request *Response =
(struct lpfc_sli_ct_request *) mp->virt;
struct lpfc_nodelist *ndlp = NULL;
- struct lpfc_nodelist *next_ndlp;
struct lpfc_dmabuf *mlast, *next_mp;
uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType;
uint32_t Did;
@@ -398,30 +398,6 @@ nsout1:
* current driver state.
*/
if (phba->hba_state == LPFC_HBA_READY) {
-
- /*
- * Switch ports that connect a loop of multiple targets need
- * special consideration. The driver wants to unregister the
- * rpi only on the target that was pulled from the loop. On
- * RSCN, the driver wants to rediscover an NPort only if the
- * driver flagged it as NLP_NPR_2B_DISC. Provided adisc is
- * not enabled and the NPort is not capable of retransmissions
- * (FC Tape) prevent timing races with the scsi error handler by
- * unregistering the Nport's RPI. This action causes all
- * outstanding IO to flush back to the midlayer.
- */
- list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list,
- nlp_listp) {
- if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC) &&
- (lpfc_rscn_payload_check(phba, ndlp->nlp_DID))) {
- if ((phba->cfg_use_adisc == 0) &&
- !(ndlp->nlp_fcp_info &
- NLP_FCP_2_DEVICE)) {
- lpfc_unreg_rpi(phba, ndlp);
- ndlp->nlp_flag &= ~NLP_NPR_ADISC;
- }
- }
- }
lpfc_els_flush_rscn(phba);
spin_lock_irq(phba->host->host_lock);
phba->fc_flag |= FC_RSCN_MODE; /* we are still in RSCN mode */
@@ -481,7 +457,7 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
if (CTrsp->CommandResponse.bits.CmdRsp ==
be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0239 NameServer Rsp "
+ "%d:0208 NameServer Rsp "
"Data: x%x\n",
phba->brd_no,
phba->fc_flag);
@@ -588,13 +564,9 @@ lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp)
lpfc_decode_firmware_rev(phba, fwrev, 0);
- if (phba->Port[0]) {
- sprintf(symbp, "Emulex %s Port %s FV%s DV%s", phba->ModelName,
- phba->Port, fwrev, lpfc_release_version);
- } else {
- sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
- fwrev, lpfc_release_version);
- }
+ sprintf(symbp, "Emulex %s FV%s DV%s", phba->ModelName,
+ fwrev, lpfc_release_version);
+ return;
}
/*
diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h
index 41cf5d3ea6c..9766f909c9c 100644
--- a/drivers/scsi/lpfc/lpfc_disc.h
+++ b/drivers/scsi/lpfc/lpfc_disc.h
@@ -30,7 +30,6 @@
/* worker thread events */
enum lpfc_work_type {
- LPFC_EVT_NODEV_TMO,
LPFC_EVT_ONLINE,
LPFC_EVT_OFFLINE,
LPFC_EVT_WARM_START,
@@ -74,11 +73,9 @@ struct lpfc_nodelist {
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */
- struct timer_list nlp_tmofunc; /* Used for nodev tmo */
struct fc_rport *rport; /* Corresponding FC transport
port structure */
struct lpfc_hba *nlp_phba;
- struct lpfc_work_evt nodev_timeout_evt;
struct lpfc_work_evt els_retry_evt;
unsigned long last_ramp_up_time; /* jiffy of last ramp up */
unsigned long last_q_full_time; /* jiffy of last queue full */
@@ -102,7 +99,6 @@ struct lpfc_nodelist {
#define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */
#define NLP_RNID_SND 0x400 /* sent RNID request for this entry */
#define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */
-#define NLP_NODEV_TMO 0x10000 /* nodev timeout is running for node */
#define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */
#define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */
#define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */
@@ -169,7 +165,7 @@ struct lpfc_nodelist {
*/
/*
* For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
- * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
+ * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
* expire, all effected nodes will receive a DEVICE_RM event.
*/
/*
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 283b7d824c3..71864cdc6c7 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -648,33 +648,32 @@ lpfc_more_plogi(struct lpfc_hba * phba)
}
static struct lpfc_nodelist *
-lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
+lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_dmabuf *prsp,
struct lpfc_nodelist *ndlp)
{
struct lpfc_nodelist *new_ndlp;
- struct lpfc_dmabuf *pcmd, *prsp;
uint32_t *lp;
struct serv_parm *sp;
uint8_t name[sizeof (struct lpfc_name)];
uint32_t rc;
- pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
- prsp = (struct lpfc_dmabuf *) pcmd->list.next;
lp = (uint32_t *) prsp->virt;
sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t));
+ memset(name, 0, sizeof (struct lpfc_name));
/* Now we to find out if the NPort we are logging into, matches the WWPN
* we have for that ndlp. If not, we have some work to do.
*/
new_ndlp = lpfc_findnode_wwpn(phba, NLP_SEARCH_ALL, &sp->portName);
- memset(name, 0, sizeof (struct lpfc_name));
- rc = memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
- if (!rc || (new_ndlp == ndlp)) {
+ if (new_ndlp == ndlp)
return ndlp;
- }
if (!new_ndlp) {
+ rc =
+ memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name));
+ if (!rc)
+ return ndlp;
new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC);
if (!new_ndlp)
return ndlp;
@@ -683,17 +682,21 @@ lpfc_plogi_confirm_nport(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
lpfc_unreg_rpi(phba, new_ndlp);
- new_ndlp->nlp_prev_state = ndlp->nlp_state;
new_ndlp->nlp_DID = ndlp->nlp_DID;
- new_ndlp->nlp_state = NLP_STE_PLOGI_ISSUE;
- lpfc_nlp_list(phba, new_ndlp, NLP_PLOGI_LIST);
+ new_ndlp->nlp_prev_state = ndlp->nlp_prev_state;
+ new_ndlp->nlp_state = ndlp->nlp_state;
+ lpfc_nlp_list(phba, new_ndlp, ndlp->nlp_flag & NLP_LIST_MASK);
/* Move this back to NPR list */
- lpfc_unreg_rpi(phba, ndlp);
- ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
- ndlp->nlp_state = NLP_STE_NPR_NODE;
- lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
-
+ if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ }
+ else {
+ lpfc_unreg_rpi(phba, ndlp);
+ ndlp->nlp_DID = 0; /* Two ndlps cannot have the same did */
+ ndlp->nlp_state = NLP_STE_NPR_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST);
+ }
return new_ndlp;
}
@@ -703,6 +706,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
{
IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
+ struct lpfc_dmabuf *prsp;
int disc, rc, did, type;
@@ -769,7 +773,10 @@ lpfc_cmpl_els_plogi(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
}
} else {
/* Good status, call state machine */
- ndlp = lpfc_plogi_confirm_nport(phba, cmdiocb, ndlp);
+ prsp = list_entry(((struct lpfc_dmabuf *)
+ cmdiocb->context2)->list.next,
+ struct lpfc_dmabuf, list);
+ ndlp = lpfc_plogi_confirm_nport(phba, prsp, ndlp);
rc = lpfc_disc_state_machine(phba, ndlp, cmdiocb,
NLP_EVT_CMPL_PLOGI);
}
@@ -821,7 +828,7 @@ lpfc_issue_els_plogi(struct lpfc_hba * phba, uint32_t did, uint8_t retry)
pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */
cmdsize = (sizeof (uint32_t) + sizeof (struct serv_parm));
- elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, 0, did,
+ elsiocb = lpfc_prep_els_iocb(phba, 1, cmdsize, retry, NULL, did,
ELS_CMD_PLOGI);
if (!elsiocb)
return 1;
@@ -1841,9 +1848,12 @@ static void
lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
struct lpfc_iocbq * rspiocb)
{
+ IOCB_t *irsp;
struct lpfc_nodelist *ndlp;
LPFC_MBOXQ_t *mbox = NULL;
+ irsp = &rspiocb->iocb;
+
ndlp = (struct lpfc_nodelist *) cmdiocb->context1;
if (cmdiocb->context_un.mbox)
mbox = cmdiocb->context_un.mbox;
@@ -1886,9 +1896,15 @@ lpfc_cmpl_els_acc(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
mempool_free( mbox, phba->mbox_mem_pool);
} else {
mempool_free( mbox, phba->mbox_mem_pool);
- if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
- lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
- ndlp = NULL;
+ /* Do not call NO_LIST for lpfc_els_abort'ed ELS cmds */
+ if (!((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) &&
+ ((irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) ||
+ (irsp->un.ulpWord[4] == IOERR_LINK_DOWN) ||
+ (irsp->un.ulpWord[4] == IOERR_SLI_DOWN)))) {
+ if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) {
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
+ ndlp = NULL;
+ }
}
}
}
@@ -2490,6 +2506,7 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
uint32_t *lp;
IOCB_t *icmd;
uint32_t payload_len, cmd;
+ int i;
icmd = &cmdiocb->iocb;
pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -2508,6 +2525,10 @@ lpfc_els_rcv_rscn(struct lpfc_hba * phba,
phba->brd_no,
phba->fc_flag, payload_len, *lp, phba->fc_rscn_id_cnt);
+ for (i = 0; i < payload_len/sizeof(uint32_t); i++)
+ fc_host_post_event(phba->host, fc_get_event_number(),
+ FCH_EVT_RSCN, lp[i]);
+
/* If we are about to begin discovery, just ACC the RSCN.
* Discovery processing will satisfy it.
*/
@@ -2791,8 +2812,8 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
ndlp = (struct lpfc_nodelist *) pmb->context2;
xri = (uint16_t) ((unsigned long)(pmb->context1));
- pmb->context1 = 0;
- pmb->context2 = 0;
+ pmb->context1 = NULL;
+ pmb->context2 = NULL;
if (mb->mbxStatus) {
mempool_free( pmb, phba->mbox_mem_pool);
@@ -2832,7 +2853,7 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
/* Xmit ELS RPS ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS RPS ACC response tag x%x "
+ "%d:0118 Xmit ELS RPS ACC response tag x%x "
"Data: x%x x%x x%x x%x x%x\n",
phba->brd_no,
elsiocb->iocb.ulpIoTag,
@@ -2941,7 +2962,7 @@ lpfc_els_rsp_rpl_acc(struct lpfc_hba * phba, uint16_t cmdsize,
/* Xmit ELS RPL ACC response tag <ulpIoTag> */
lpfc_printf_log(phba, KERN_INFO, LOG_ELS,
- "%d:0128 Xmit ELS RPL ACC response tag x%x "
+ "%d:0120 Xmit ELS RPL ACC response tag x%x "
"Data: x%x x%x x%x x%x x%x\n",
phba->brd_no,
elsiocb->iocb.ulpIoTag,
@@ -3102,7 +3123,7 @@ lpfc_els_rcv_fan(struct lpfc_hba * phba, struct lpfc_iocbq * cmdiocb,
struct lpfc_nodelist *ndlp, *next_ndlp;
/* FAN received */
- lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:265 FAN received\n",
+ lpfc_printf_log(phba, KERN_INFO, LOG_ELS, "%d:0265 FAN received\n",
phba->brd_no);
icmd = &cmdiocb->iocb;
@@ -3282,10 +3303,9 @@ lpfc_els_timeout_handler(struct lpfc_hba *phba)
} else
lpfc_sli_release_iocbq(phba, piocb);
}
- if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) {
- phba->els_tmofunc.expires = jiffies + HZ * timeout;
- add_timer(&phba->els_tmofunc);
- }
+ if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt)
+ mod_timer(&phba->els_tmofunc, jiffies + HZ * timeout);
+
spin_unlock_irq(phba->host->host_lock);
}
@@ -3442,6 +3462,8 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) {
ndlp->nlp_type |= NLP_FABRIC;
}
+ ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
}
phba->fc_stat.elsRcvFrame++;
@@ -3463,13 +3485,14 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
rjt_err = 1;
break;
}
+ ndlp = lpfc_plogi_confirm_nport(phba, mp, ndlp);
lpfc_disc_state_machine(phba, ndlp, elsiocb, NLP_EVT_RCV_PLOGI);
break;
case ELS_CMD_FLOGI:
phba->fc_stat.elsRcvFLOGI++;
lpfc_els_rcv_flogi(phba, elsiocb, ndlp, newnode);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_LOGO:
@@ -3492,7 +3515,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
phba->fc_stat.elsRcvRSCN++;
lpfc_els_rcv_rscn(phba, elsiocb, ndlp, newnode);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_ADISC:
@@ -3535,28 +3558,28 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
phba->fc_stat.elsRcvLIRR++;
lpfc_els_rcv_lirr(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RPS:
phba->fc_stat.elsRcvRPS++;
lpfc_els_rcv_rps(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RPL:
phba->fc_stat.elsRcvRPL++;
lpfc_els_rcv_rpl(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
case ELS_CMD_RNID:
phba->fc_stat.elsRcvRNID++;
lpfc_els_rcv_rnid(phba, elsiocb, ndlp);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
default:
@@ -3568,7 +3591,7 @@ lpfc_els_unsol_event(struct lpfc_hba * phba,
"%d:0115 Unknown ELS command x%x received from "
"NPORT x%x\n", phba->brd_no, cmd, did);
if (newnode) {
- mempool_free( ndlp, phba->nlp_mem_pool);
+ lpfc_nlp_list(phba, ndlp, NLP_NO_LIST);
}
break;
}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index adb086009ae..d586c3d3b0d 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -56,28 +56,63 @@ static uint8_t lpfcAlpaArray[] = {
static void lpfc_disc_timeout_handler(struct lpfc_hba *);
-static void
-lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
+void
+lpfc_terminate_rport_io(struct fc_rport *rport)
{
- uint8_t *name = (uint8_t *)&ndlp->nlp_portname;
- int warn_on = 0;
+ struct lpfc_rport_data *rdata;
+ struct lpfc_nodelist * ndlp;
+ struct lpfc_hba *phba;
- spin_lock_irq(phba->host->host_lock);
- if (!(ndlp->nlp_flag & NLP_NODEV_TMO)) {
- spin_unlock_irq(phba->host->host_lock);
+ rdata = rport->dd_data;
+ ndlp = rdata->pnode;
+
+ if (!ndlp) {
+ if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ printk(KERN_ERR "Cannot find remote node"
+ " to terminate I/O Data x%x\n",
+ rport->port_id);
return;
}
- /*
- * If a discovery event readded nodev_timer after timer
- * firing and before processing the timer, cancel the
- * nlp_tmofunc.
- */
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&ndlp->nlp_tmofunc);
+ phba = ndlp->nlp_phba;
+
spin_lock_irq(phba->host->host_lock);
+ if (ndlp->nlp_sid != NLP_NO_SID) {
+ lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
+ ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
+ }
+ spin_unlock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NODEV_TMO;
+ return;
+}
+
+/*
+ * This function will be called when dev_loss_tmo fire.
+ */
+void
+lpfc_dev_loss_tmo_callbk(struct fc_rport *rport)
+{
+ struct lpfc_rport_data *rdata;
+ struct lpfc_nodelist * ndlp;
+ uint8_t *name;
+ int warn_on = 0;
+ struct lpfc_hba *phba;
+
+ rdata = rport->dd_data;
+ ndlp = rdata->pnode;
+
+ if (!ndlp) {
+ if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+ printk(KERN_ERR "Cannot find remote node"
+ " for rport in dev_loss_tmo_callbk x%x\n",
+ rport->port_id);
+ return;
+ }
+
+ name = (uint8_t *)&ndlp->nlp_portname;
+ phba = ndlp->nlp_phba;
+
+ spin_lock_irq(phba->host->host_lock);
if (ndlp->nlp_sid != NLP_NO_SID) {
warn_on = 1;
@@ -85,11 +120,14 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring],
ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT);
}
+ if (phba->fc_flag & FC_UNLOADING)
+ warn_on = 0;
+
spin_unlock_irq(phba->host->host_lock);
if (warn_on) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0203 Nodev timeout on "
+ "%d:0203 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
phba->brd_no,
@@ -99,7 +137,7 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
ndlp->nlp_state, ndlp->nlp_rpi);
} else {
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0204 Nodev timeout on "
+ "%d:0204 Devloss timeout on "
"WWPN %x:%x:%x:%x:%x:%x:%x:%x "
"NPort x%x Data: x%x x%x x%x\n",
phba->brd_no,
@@ -109,7 +147,12 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
ndlp->nlp_state, ndlp->nlp_rpi);
}
- lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+ ndlp->rport = NULL;
+ rdata->pnode = NULL;
+
+ if (!(phba->fc_flag & FC_UNLOADING))
+ lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM);
+
return;
}
@@ -127,11 +170,6 @@ lpfc_work_list_done(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
free_evt = 1;
switch (evtp->evt) {
- case LPFC_EVT_NODEV_TMO:
- ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
- lpfc_process_nodev_timeout(phba, ndlp);
- free_evt = 0;
- break;
case LPFC_EVT_ELS_RETRY:
ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1);
lpfc_els_retry_delay_handler(ndlp);
@@ -340,6 +378,9 @@ lpfc_linkdown(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
}
+ fc_host_post_event(phba->host, fc_get_event_number(),
+ FCH_EVT_LINKDOWN, 0);
+
/* Clean up any firmware default rpi's */
if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) {
lpfc_unreg_did(phba, 0xffffffff, mb);
@@ -374,16 +415,6 @@ lpfc_linkdown(struct lpfc_hba * phba)
rc = lpfc_disc_state_machine(phba, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
- /* Check config parameter use-adisc or FCP-2 */
- if ((rc != NLP_STE_FREED_NODE) &&
- (phba->cfg_use_adisc == 0) &&
- !(ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE)) {
- /* We know we will have to relogin, so
- * unreglogin the rpi right now to fail
- * any outstanding I/Os quickly.
- */
- lpfc_unreg_rpi(phba, ndlp);
- }
}
}
@@ -427,6 +458,9 @@ lpfc_linkup(struct lpfc_hba * phba)
struct list_head *listp, *node_list[7];
int i;
+ fc_host_post_event(phba->host, fc_get_event_number(),
+ FCH_EVT_LINKUP, 0);
+
spin_lock_irq(phba->host->host_lock);
phba->hba_state = LPFC_LINK_UP;
phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY |
@@ -638,6 +672,8 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb)
memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt,
sizeof (struct serv_parm));
+ if (phba->cfg_soft_wwpn)
+ u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
memcpy((uint8_t *) & phba->fc_nodename,
(uint8_t *) & phba->fc_sparam.nodeName,
sizeof (struct lpfc_name));
@@ -1084,7 +1120,7 @@ lpfc_register_remote_port(struct lpfc_hba * phba,
fc_remote_port_rolechg(rport, rport_ids.roles);
if ((rport->scsi_target_id != -1) &&
- (rport->scsi_target_id < MAX_FCP_TARGET)) {
+ (rport->scsi_target_id < LPFC_MAX_TARGET)) {
ndlp->nlp_sid = rport->scsi_target_id;
}
@@ -1098,8 +1134,11 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba,
struct fc_rport *rport = ndlp->rport;
struct lpfc_rport_data *rdata = rport->dd_data;
- ndlp->rport = NULL;
- rdata->pnode = NULL;
+ if (rport->scsi_target_id == -1) {
+ ndlp->rport = NULL;
+ rdata->pnode = NULL;
+ }
+
fc_remote_port_delete(rport);
return;
@@ -1227,17 +1266,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list);
phba->fc_unmap_cnt++;
phba->nport_event_cnt++;
- /* stop nodev tmo if running */
- if (nlp->nlp_flag & NLP_NODEV_TMO) {
- nlp->nlp_flag &= ~NLP_NODEV_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&nlp->nlp_tmofunc);
- spin_lock_irq(phba->host->host_lock);
- if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
- list_del_init(&nlp->nodev_timeout_evt.
- evt_listp);
-
- }
nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
nlp->nlp_type |= NLP_FC_NODE;
break;
@@ -1248,17 +1276,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list);
phba->fc_map_cnt++;
phba->nport_event_cnt++;
- /* stop nodev tmo if running */
- if (nlp->nlp_flag & NLP_NODEV_TMO) {
- nlp->nlp_flag &= ~NLP_NODEV_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&nlp->nlp_tmofunc);
- spin_lock_irq(phba->host->host_lock);
- if (!list_empty(&nlp->nodev_timeout_evt.evt_listp))
- list_del_init(&nlp->nodev_timeout_evt.
- evt_listp);
-
- }
nlp->nlp_flag &= ~NLP_NODEV_REMOVE;
break;
case NLP_NPR_LIST:
@@ -1267,11 +1284,6 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list);
phba->fc_npr_cnt++;
- if (!(nlp->nlp_flag & NLP_NODEV_TMO))
- mod_timer(&nlp->nlp_tmofunc,
- jiffies + HZ * phba->cfg_nodev_tmo);
-
- nlp->nlp_flag |= NLP_NODEV_TMO;
nlp->nlp_flag &= ~NLP_RCV_PLOGI;
break;
case NLP_JUST_DQ:
@@ -1301,7 +1313,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
* already. If we have, and it's a scsi entity, be
* sure to unblock any attached scsi devices
*/
- if (!nlp->rport)
+ if ((!nlp->rport) || (nlp->rport->port_state ==
+ FC_PORTSTATE_BLOCKED))
lpfc_register_remote_port(phba, nlp);
/*
@@ -1313,7 +1326,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list)
if ((rport_add == mapped) &&
((!nlp->rport) ||
(nlp->rport->scsi_target_id == -1) ||
- (nlp->rport->scsi_target_id >= MAX_FCP_TARGET))) {
+ (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) {
nlp->nlp_state = NLP_STE_UNMAPPED_NODE;
spin_lock_irq(phba->host->host_lock);
nlp->nlp_flag |= NLP_TGT_NO_SCSIID;
@@ -1557,6 +1570,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
}
}
+
+ spin_lock_irq(phba->host->host_lock);
list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) &&
(ndlp == (struct lpfc_nodelist *) mb->context2)) {
@@ -1569,18 +1584,16 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
mempool_free(mb, phba->mbox_mem_pool);
}
}
+ spin_unlock_irq(phba->host->host_lock);
lpfc_els_abort(phba,ndlp,0);
spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~(NLP_NODEV_TMO|NLP_DELAY_TMO);
+ ndlp->nlp_flag &= ~NLP_DELAY_TMO;
spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&ndlp->nlp_tmofunc);
ndlp->nlp_last_elscmd = 0;
del_timer_sync(&ndlp->nlp_delayfunc);
- if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
- list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
if (!list_empty(&ndlp->els_retry_evt.evt_listp))
list_del_init(&ndlp->els_retry_evt.evt_listp);
@@ -1597,16 +1610,6 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
int
lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp)
{
- if (ndlp->nlp_flag & NLP_NODEV_TMO) {
- spin_lock_irq(phba->host->host_lock);
- ndlp->nlp_flag &= ~NLP_NODEV_TMO;
- spin_unlock_irq(phba->host->host_lock);
- del_timer_sync(&ndlp->nlp_tmofunc);
- if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp))
- list_del_init(&ndlp->nodev_timeout_evt.evt_listp);
-
- }
-
if (ndlp->nlp_flag & NLP_DELAY_TMO) {
lpfc_cancel_retry_delay_tmo(phba, ndlp);
@@ -1782,7 +1785,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to REGLOGIN */
/* FIND node DID reglogin */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID reglogin"
+ "%d:0901 FIND node DID reglogin"
" Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1805,7 +1808,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to PRLI */
/* FIND node DID prli */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID prli "
+ "%d:0902 FIND node DID prli "
"Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1828,7 +1831,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to NPR */
/* FIND node DID npr */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID npr "
+ "%d:0903 FIND node DID npr "
"Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -1851,7 +1854,7 @@ lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did)
/* LOG change to UNUSED */
/* FIND node DID unused */
lpfc_printf_log(phba, KERN_INFO, LOG_NODE,
- "%d:0931 FIND node DID unused "
+ "%d:0905 FIND node DID unused "
"Data: x%p x%x x%x x%x\n",
phba->brd_no,
ndlp, ndlp->nlp_DID,
@@ -2335,7 +2338,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!initlinkmbox) {
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0226 Device Discovery "
+ "%d:0206 Device Discovery "
"completion error\n",
phba->brd_no);
phba->hba_state = LPFC_HBA_ERROR;
@@ -2365,7 +2368,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
if (!clearlambox) {
clrlaerr = 1;
lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
- "%d:0226 Device Discovery "
+ "%d:0207 Device Discovery "
"completion error\n",
phba->brd_no);
phba->hba_state = LPFC_HBA_ERROR;
@@ -2421,34 +2424,6 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba)
return;
}
-static void
-lpfc_nodev_timeout(unsigned long ptr)
-{
- struct lpfc_hba *phba;
- struct lpfc_nodelist *ndlp;
- unsigned long iflag;
- struct lpfc_work_evt *evtp;
-
- ndlp = (struct lpfc_nodelist *)ptr;
- phba = ndlp->nlp_phba;
- evtp = &ndlp->nodev_timeout_evt;
- spin_lock_irqsave(phba->host->host_lock, iflag);
-
- if (!list_empty(&evtp->evt_listp)) {
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
- return;
- }
- evtp->evt_arg1 = ndlp;
- evtp->evt = LPFC_EVT_NODEV_TMO;
- list_add_tail(&evtp->evt_listp, &phba->work_list);
- if (phba->work_wait)
- wake_up(phba->work_wait);
-
- spin_unlock_irqrestore(phba->host->host_lock, iflag);
- return;
-}
-
-
/*
* This routine handles processing a NameServer REG_LOGIN mailbox
* command upon completion. It is setup in the LPFC_MBOXQ
@@ -2572,11 +2547,7 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
uint32_t did)
{
memset(ndlp, 0, sizeof (struct lpfc_nodelist));
- INIT_LIST_HEAD(&ndlp->nodev_timeout_evt.evt_listp);
INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp);
- init_timer(&ndlp->nlp_tmofunc);
- ndlp->nlp_tmofunc.function = lpfc_nodev_timeout;
- ndlp->nlp_tmofunc.data = (unsigned long)ndlp;
init_timer(&ndlp->nlp_delayfunc);
ndlp->nlp_delayfunc.function = lpfc_els_retry_delay;
ndlp->nlp_delayfunc.data = (unsigned long)ndlp;
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 908d0f27706..4cdf3464267 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -71,6 +71,7 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
uint16_t offset = 0;
static char licensed[56] =
"key unlock for use with gnu public licensed code only\0";
+ static int init_key = 1;
pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (!pmb) {
@@ -82,10 +83,13 @@ lpfc_config_port_prep(struct lpfc_hba * phba)
phba->hba_state = LPFC_INIT_MBX_CMDS;
if (lpfc_is_LC_HBA(phba->pcidev->device)) {
- uint32_t *ptext = (uint32_t *) licensed;
+ if (init_key) {
+ uint32_t *ptext = (uint32_t *) licensed;
- for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
- *ptext = cpu_to_be32(*ptext);
+ for (i = 0; i < 56; i += sizeof (uint32_t), ptext++)
+ *ptext = cpu_to_be32(*ptext);
+ init_key = 0;
+ }
lpfc_read_nv(phba, pmb);
memset((char*)mb->un.varRDnvp.rsvd3, 0,
@@ -264,6 +268,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
kfree(mp);
pmb->context1 = NULL;
+ if (phba->cfg_soft_wwpn)
+ u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn);
memcpy(&phba->fc_nodename, &phba->fc_sparam.nodeName,
sizeof (struct lpfc_name));
memcpy(&phba->fc_portname, &phba->fc_sparam.portName,
@@ -405,19 +411,26 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
/* MBOX buffer will be freed in mbox compl */
- i = 0;
+ return (0);
+}
+
+static int
+lpfc_discovery_wait(struct lpfc_hba *phba)
+{
+ int i = 0;
+
while ((phba->hba_state != LPFC_HBA_READY) ||
(phba->num_disc_nodes) || (phba->fc_prli_sent) ||
((phba->fc_map_cnt == 0) && (i<2)) ||
- (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
+ (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE)) {
/* Check every second for 30 retries. */
i++;
if (i > 30) {
- break;
+ return -ETIMEDOUT;
}
if ((i >= 15) && (phba->hba_state <= LPFC_LINK_DOWN)) {
/* The link is down. Set linkdown timeout */
- break;
+ return -ETIMEDOUT;
}
/* Delay for 1 second to give discovery time to complete. */
@@ -425,12 +438,7 @@ lpfc_config_port_post(struct lpfc_hba * phba)
}
- /* Since num_disc_nodes keys off of PLOGI, delay a bit to let
- * any potential PRLIs to flush thru the SLI sub-system.
- */
- msleep(50);
-
- return (0);
+ return 0;
}
/************************************************************************/
@@ -505,6 +513,7 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
{
struct lpfc_sli *psli = &phba->sli;
struct lpfc_sli_ring *pring;
+ uint32_t event_data;
if (phba->work_hs & HS_FFER6) {
/* Re-establishing Link */
@@ -549,6 +558,11 @@ lpfc_handle_eratt(struct lpfc_hba * phba)
phba->brd_no, phba->work_hs,
phba->work_status[0], phba->work_status[1]);
+ event_data = FC_REG_DUMP_EVENT;
+ fc_host_post_vendor_event(phba->host, fc_get_event_number(),
+ sizeof(event_data), (char *) &event_data,
+ SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX);
+
psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
lpfc_offline(phba);
phba->hba_state = LPFC_HBA_ERROR;
@@ -939,12 +953,12 @@ lpfc_get_hba_model_desc(struct lpfc_hba * phba, uint8_t * mdp, uint8_t * descp)
"10-port ", "PCIe"};
break;
default:
- m = (typeof(m)){ 0 };
+ m = (typeof(m)){ NULL };
break;
}
break;
default:
- m = (typeof(m)){ 0 };
+ m = (typeof(m)){ NULL };
break;
}
@@ -1339,7 +1353,8 @@ lpfc_offline(struct lpfc_hba * phba)
struct lpfc_sli_ring *pring;
struct lpfc_sli *psli;
unsigned long iflag;
- int i = 0;
+ int i;
+ int cnt = 0;
if (!phba)
return 0;
@@ -1348,20 +1363,31 @@ lpfc_offline(struct lpfc_hba * phba)
return 0;
psli = &phba->sli;
- pring = &psli->ring[psli->fcp_ring];
lpfc_linkdown(phba);
+ lpfc_sli_flush_mbox_queue(phba);
- /* The linkdown event takes 30 seconds to timeout. */
- while (pring->txcmplq_cnt) {
- mdelay(10);
- if (i++ > 3000)
- break;
+ for (i = 0; i < psli->num_rings; i++) {
+ pring = &psli->ring[i];
+ /* The linkdown event takes 30 seconds to timeout. */
+ while (pring->txcmplq_cnt) {
+ mdelay(10);
+ if (cnt++ > 3000) {
+ lpfc_printf_log(phba,
+ KERN_WARNING, LOG_INIT,
+ "%d:0466 Outstanding IO when "
+ "bringing Adapter offline\n",
+ phba->brd_no);
+ break;
+ }
+ }
}
+
/* stop all timers associated with this hba */
lpfc_stop_timer(phba);
phba->work_hba_events = 0;
+ phba->work_ha = 0;
lpfc_printf_log(phba,
KERN_WARNING,
@@ -1451,7 +1477,6 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_put_host;
host->unique_id = phba->brd_no;
- init_MUTEX(&phba->hba_can_block);
INIT_LIST_HEAD(&phba->ctrspbuflist);
INIT_LIST_HEAD(&phba->rnidrspbuflist);
INIT_LIST_HEAD(&phba->freebufList);
@@ -1600,7 +1625,11 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_iocbq;
}
- /* We can rely on a queue depth attribute only after SLI HBA setup */
+ /*
+ * Set initial can_queue value since 0 is no longer supported and
+ * scsi_add_host will fail. This will be adjusted later based on the
+ * max xri value determined in hba setup.
+ */
host->can_queue = phba->cfg_hba_queue_depth - 10;
/* Tell the midlayer we support 16 byte commands */
@@ -1620,7 +1649,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
if (error)
goto out_remove_host;
- error = request_irq(phba->pcidev->irq, lpfc_intr_handler, SA_SHIRQ,
+ error = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED,
LPFC_DRIVER_NAME, phba);
if (error) {
lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
@@ -1640,6 +1669,14 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
goto out_free_irq;
}
+ /*
+ * hba setup may have changed the hba_queue_depth so we need to adjust
+ * the value of can_queue.
+ */
+ host->can_queue = phba->cfg_hba_queue_depth - 10;
+
+ lpfc_discovery_wait(phba);
+
if (phba->cfg_poll & DISABLE_FCP_RING_INT) {
spin_lock_irq(phba->host->host_lock);
lpfc_poll_start_timer(phba);
diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c
index e42f22aaf71..4d016c2a1b2 100644
--- a/drivers/scsi/lpfc/lpfc_mbox.c
+++ b/drivers/scsi/lpfc/lpfc_mbox.c
@@ -651,3 +651,19 @@ lpfc_mbox_get(struct lpfc_hba * phba)
return mbq;
}
+
+int
+lpfc_mbox_tmo_val(struct lpfc_hba *phba, int cmd)
+{
+ switch (cmd) {
+ case MBX_WRITE_NV: /* 0x03 */
+ case MBX_UPDATE_CFG: /* 0x1B */
+ case MBX_DOWN_LOAD: /* 0x1C */
+ case MBX_DEL_LD_ENTRY: /* 0x1D */
+ case MBX_LOAD_AREA: /* 0x81 */
+ case MBX_FLASH_WR_ULA: /* 0x98 */
+ case MBX_LOAD_EXP_ROM: /* 0x9C */
+ return LPFC_MBOX_TMO_FLASH_CMD;
+ }
+ return LPFC_MBOX_TMO;
+}
diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c
index 07017658ac5..066292d3995 100644
--- a/drivers/scsi/lpfc/lpfc_mem.c
+++ b/drivers/scsi/lpfc/lpfc_mem.c
@@ -133,6 +133,11 @@ lpfc_mem_free(struct lpfc_hba * phba)
pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool);
pci_pool_destroy(phba->lpfc_mbuf_pool);
+
+ /* Free the iocb lookup array */
+ kfree(psli->iocbq_lookup);
+ psli->iocbq_lookup = NULL;
+
}
void *
diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c
index 27d60ad897c..d5f415007db 100644
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -179,7 +179,7 @@ lpfc_els_abort(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp,
/* Abort outstanding I/O on NPort <nlp_DID> */
lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY,
- "%d:0201 Abort outstanding I/O on NPort x%x "
+ "%d:0205 Abort outstanding I/O on NPort x%x "
"Data: x%x x%x x%x\n",
phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag,
ndlp->nlp_state, ndlp->nlp_rpi);
@@ -393,6 +393,20 @@ lpfc_rcv_plogi(struct lpfc_hba * phba,
mbox->context2 = ndlp;
ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
+ /*
+ * If there is an outstanding PLOGI issued, abort it before
+ * sending ACC rsp for received PLOGI. If pending plogi
+ * is not canceled here, the plogi will be rejected by
+ * remote port and will be retried. On a configuration with
+ * single discovery thread, this will cause a huge delay in
+ * discovery. Also this will cause multiple state machines
+ * running in parallel for this node.
+ */
+ if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+ /* software abort outstanding PLOGI */
+ lpfc_els_abort(phba, ndlp, 1);
+ }
+
lpfc_els_rsp_acc(phba, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox, 0);
return 1;
@@ -1110,6 +1124,17 @@ lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_hba * phba,
phba->brd_no,
did, mb->mbxStatus, phba->hba_state);
+ /*
+ * If RegLogin failed due to lack of HBA resources do not
+ * retry discovery.
+ */
+ if (mb->mbxStatus == MBXERR_RPI_FULL) {
+ ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE;
+ ndlp->nlp_state = NLP_STE_UNUSED_NODE;
+ lpfc_nlp_list(phba, ndlp, NLP_UNUSED_LIST);
+ return ndlp->nlp_state;
+ }
+
/* Put ndlp in npr list set plogi timer for 1 sec */
mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1);
spin_lock_irq(phba->host->host_lock);
@@ -1590,7 +1615,13 @@ lpfc_rcv_padisc_npr_node(struct lpfc_hba * phba,
lpfc_rcv_padisc(phba, ndlp, cmdiocb);
- if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) {
+ /*
+ * Do not start discovery if discovery is about to start
+ * or discovery in progress for this node. Starting discovery
+ * here will affect the counting of discovery threads.
+ */
+ if ((!(ndlp->nlp_flag & NLP_DELAY_TMO)) &&
+ (ndlp->nlp_flag & NLP_NPR_2B_DISC)){
if (ndlp->nlp_flag & NLP_NPR_ADISC) {
ndlp->nlp_prev_state = NLP_STE_NPR_NODE;
ndlp->nlp_state = NLP_STE_ADISC_ISSUE;
@@ -1782,7 +1813,7 @@ lpfc_device_recov_npr_node(struct lpfc_hba * phba,
*/
/*
* For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped
- * lists will receive a DEVICE_RECOVERY event. If the linkdown or nodev timers
+ * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers
* expire, all effected nodes will receive a DEVICE_RM event.
*/
/*
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 7dc4c2e6bed..97ae98dc95d 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -21,6 +21,7 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
#include <scsi/scsi.h>
#include <scsi/scsi_device.h>
@@ -41,20 +42,6 @@
#define LPFC_ABORT_WAIT 2
-static inline void
-lpfc_block_requests(struct lpfc_hba * phba)
-{
- down(&phba->hba_can_block);
- scsi_block_requests(phba->host);
-}
-
-static inline void
-lpfc_unblock_requests(struct lpfc_hba * phba)
-{
- scsi_unblock_requests(phba->host);
- up(&phba->hba_can_block);
-}
-
/*
* This routine allocates a scsi buffer, which contains all the necessary
* information needed to initiate a SCSI I/O. The non-DMAable buffer region
@@ -167,22 +154,6 @@ static void
lpfc_release_scsi_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
{
unsigned long iflag = 0;
- /*
- * There are only two special cases to consider. (1) the scsi command
- * requested scatter-gather usage or (2) the scsi command allocated
- * a request buffer, but did not request use_sg. There is a third
- * case, but it does not require resource deallocation.
- */
- if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
- dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
- psb->seg_cnt, psb->pCmd->sc_data_direction);
- } else {
- if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
- dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
- psb->pCmd->request_bufflen,
- psb->pCmd->sc_data_direction);
- }
- }
spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag);
psb->pCmd = NULL;
@@ -296,6 +267,27 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd)
}
static void
+lpfc_scsi_unprep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * psb)
+{
+ /*
+ * There are only two special cases to consider. (1) the scsi command
+ * requested scatter-gather usage or (2) the scsi command allocated
+ * a request buffer, but did not request use_sg. There is a third
+ * case, but it does not require resource deallocation.
+ */
+ if ((psb->seg_cnt > 0) && (psb->pCmd->use_sg)) {
+ dma_unmap_sg(&phba->pcidev->dev, psb->pCmd->request_buffer,
+ psb->seg_cnt, psb->pCmd->sc_data_direction);
+ } else {
+ if ((psb->nonsg_phys) && (psb->pCmd->request_bufflen)) {
+ dma_unmap_single(&phba->pcidev->dev, psb->nonsg_phys,
+ psb->pCmd->request_bufflen,
+ psb->pCmd->sc_data_direction);
+ }
+ }
+}
+
+static void
lpfc_handle_fcp_err(struct lpfc_scsi_buf *lpfc_cmd)
{
struct scsi_cmnd *cmnd = lpfc_cmd->pCmd;
@@ -468,6 +460,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
cmd->scsi_done(cmd);
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
return;
}
@@ -525,6 +518,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn,
}
}
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
}
@@ -623,6 +617,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd,
static int
lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
struct lpfc_scsi_buf *lpfc_cmd,
+ unsigned int lun,
uint8_t task_mgmt_cmd)
{
struct lpfc_sli *psli;
@@ -641,8 +636,7 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
piocb = &piocbq->iocb;
fcp_cmnd = lpfc_cmd->fcp_cmnd;
- int_to_scsilun(lpfc_cmd->pCmd->device->lun,
- &lpfc_cmd->fcp_cmnd->fcp_lun);
+ int_to_scsilun(lun, &lpfc_cmd->fcp_cmnd->fcp_lun);
fcp_cmnd->fcpCntl2 = task_mgmt_cmd;
piocb->ulpCommand = CMD_FCP_ICMND64_CR;
@@ -669,14 +663,16 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba,
static int
lpfc_scsi_tgt_reset(struct lpfc_scsi_buf * lpfc_cmd, struct lpfc_hba * phba,
- unsigned tgt_id, struct lpfc_rport_data *rdata)
+ unsigned tgt_id, unsigned int lun,
+ struct lpfc_rport_data *rdata)
{
struct lpfc_iocbq *iocbq;
struct lpfc_iocbq *iocbqrsp;
int ret;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_TARGET_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, lun,
+ FCP_TARGET_RESET);
if (!ret)
return FAILED;
@@ -836,6 +832,7 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0;
out_host_busy_free_buf:
+ lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd);
lpfc_release_scsi_buf(phba, lpfc_cmd);
out_host_busy:
return SCSI_MLQUEUE_HOST_BUSY;
@@ -845,6 +842,21 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
return 0;
}
+static void
+lpfc_block_error_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+
+ spin_lock_irq(shost->host_lock);
+ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+ spin_unlock_irq(shost->host_lock);
+ msleep(1000);
+ spin_lock_irq(shost->host_lock);
+ }
+ spin_unlock_irq(shost->host_lock);
+ return;
+}
static int
lpfc_abort_handler(struct scsi_cmnd *cmnd)
@@ -859,7 +871,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
unsigned int loop_count = 0;
int ret = SUCCESS;
- lpfc_block_requests(phba);
+ lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble;
@@ -923,7 +935,7 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
schedule_timeout_uninterruptible(LPFC_ABORT_WAIT*HZ);
spin_lock_irq(phba->host->host_lock);
if (++loop_count
- > (2 * phba->cfg_nodev_tmo)/LPFC_ABORT_WAIT)
+ > (2 * phba->cfg_devloss_tmo)/LPFC_ABORT_WAIT)
break;
}
@@ -945,7 +957,6 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
cmnd->device->lun, cmnd->serial_number);
spin_unlock_irq(shost->host_lock);
- lpfc_unblock_requests(phba);
return ret;
}
@@ -963,11 +974,11 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
int ret = FAILED;
int cnt, loopcnt;
- lpfc_block_requests(phba);
+ lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
/*
* If target is not in a MAPPED state, delay the reset until
- * target is rediscovered or nodev timeout expires.
+ * target is rediscovered or devloss timeout expires.
*/
while ( 1 ) {
if (!pnode)
@@ -986,12 +997,12 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
if (lpfc_cmd == NULL)
goto out;
- lpfc_cmd->pCmd = cmnd;
lpfc_cmd->timeout = 60;
lpfc_cmd->scsi_hba = phba;
lpfc_cmd->rdata = rdata;
- ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, FCP_LUN_RESET);
+ ret = lpfc_scsi_prep_task_mgmt_cmd(phba, lpfc_cmd, cmnd->device->lun,
+ FCP_LUN_RESET);
if (!ret)
goto out_free_scsi_buf;
@@ -1018,7 +1029,6 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
cmd_status = iocbqrsp->iocb.ulpStatus;
lpfc_sli_release_iocbq(phba, iocbqrsp);
- lpfc_release_scsi_buf(phba, lpfc_cmd);
/*
* All outstanding txcmplq I/Os should have been aborted by the device.
@@ -1040,7 +1050,7 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
spin_lock_irq(phba->host->host_lock);
if (++loopcnt
- > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
+ > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
break;
cnt = lpfc_sli_sum_iocb(phba,
@@ -1057,6 +1067,8 @@ lpfc_reset_lun_handler(struct scsi_cmnd *cmnd)
}
out_free_scsi_buf:
+ lpfc_release_scsi_buf(phba, lpfc_cmd);
+
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
"%d:0713 SCSI layer issued LUN reset (%d, %d) "
"Data: x%x x%x x%x\n",
@@ -1065,7 +1077,6 @@ out_free_scsi_buf:
out:
spin_unlock_irq(shost->host_lock);
- lpfc_unblock_requests(phba);
return ret;
}
@@ -1080,7 +1091,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
int cnt, loopcnt;
struct lpfc_scsi_buf * lpfc_cmd;
- lpfc_block_requests(phba);
+ lpfc_block_error_handler(cmnd);
spin_lock_irq(shost->host_lock);
lpfc_cmd = lpfc_get_scsi_buf(phba);
@@ -1089,7 +1100,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
/* The lpfc_cmd storage is reused. Set all loop invariants. */
lpfc_cmd->timeout = 60;
- lpfc_cmd->pCmd = cmnd;
lpfc_cmd->scsi_hba = phba;
/*
@@ -1097,7 +1107,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
* targets known to the driver. Should any target reset
* fail, this routine returns failure to the midlayer.
*/
- for (i = 0; i < MAX_FCP_TARGET; i++) {
+ for (i = 0; i < LPFC_MAX_TARGET; i++) {
/* Search the mapped list for this target ID */
match = 0;
list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
@@ -1109,11 +1119,11 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
if (!match)
continue;
- ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba,
- i, ndlp->rport->dd_data);
+ ret = lpfc_scsi_tgt_reset(lpfc_cmd, phba, i, cmnd->device->lun,
+ ndlp->rport->dd_data);
if (ret != SUCCESS) {
lpfc_printf_log(phba, KERN_ERR, LOG_FCP,
- "%d:0713 Bus Reset on target %d failed\n",
+ "%d:0700 Bus Reset on target %d failed\n",
phba->brd_no, i);
err_count++;
}
@@ -1141,7 +1151,7 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
spin_lock_irq(phba->host->host_lock);
if (++loopcnt
- > (2 * phba->cfg_nodev_tmo)/LPFC_RESET_WAIT)
+ > (2 * phba->cfg_devloss_tmo)/LPFC_RESET_WAIT)
break;
cnt = lpfc_sli_sum_iocb(phba,
@@ -1163,7 +1173,6 @@ lpfc_reset_bus_handler(struct scsi_cmnd *cmnd)
phba->brd_no, ret);
out:
spin_unlock_irq(shost->host_lock);
- lpfc_unblock_requests(phba);
return ret;
}
@@ -1240,7 +1249,7 @@ lpfc_slave_configure(struct scsi_device *sdev)
* target pointer is stored in the starget_data for the
* driver's sysfs entry point functions.
*/
- rport->dev_loss_tmo = phba->cfg_nodev_tmo + 5;
+ rport->dev_loss_tmo = phba->cfg_devloss_tmo;
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_poll_fcp_ring(phba);
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index bb69a7a1ec5..70f4d5a1348 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -191,35 +191,12 @@ static int
lpfc_sli_ringtxcmpl_put(struct lpfc_hba * phba,
struct lpfc_sli_ring * pring, struct lpfc_iocbq * piocb)
{
- uint16_t iotag;
-
list_add_tail(&piocb->list, &pring->txcmplq);
pring->txcmplq_cnt++;
if (unlikely(pring->ringno == LPFC_ELS_RING))
mod_timer(&phba->els_tmofunc,
jiffies + HZ * (phba->fc_ratov << 1));
- if (pring->fast_lookup) {
- /* Setup fast lookup based on iotag for completion */
- iotag = piocb->iocb.ulpIoTag;
- if (iotag && (iotag < pring->fast_iotag))
- *(pring->fast_lookup + iotag) = piocb;
- else {
-
- /* Cmd ring <ringno> put: iotag <iotag> greater then
- configured max <fast_iotag> wd0 <icmd> */
- lpfc_printf_log(phba,
- KERN_ERR,
- LOG_SLI,
- "%d:0316 Cmd ring %d put: iotag x%x "
- "greater then configured max x%x "
- "wd0 x%x\n",
- phba->brd_no,
- pring->ringno, iotag,
- pring->fast_iotag,
- *(((uint32_t *)(&piocb->iocb)) + 7));
- }
- }
return (0);
}
@@ -343,7 +320,8 @@ lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocbq)
kfree(old_arr);
return iotag;
}
- }
+ } else
+ spin_unlock_irq(phba->host->host_lock);
lpfc_printf_log(phba, KERN_ERR,LOG_SLI,
"%d:0318 Failed to allocate IOTAG.last IOTAG is %d\n",
@@ -601,7 +579,7 @@ lpfc_sli_handle_mb_event(struct lpfc_hba * phba)
/* Stray Mailbox Interrupt, mbxCommand <cmd> mbxStatus
<status> */
lpfc_printf_log(phba,
- KERN_ERR,
+ KERN_WARNING,
LOG_MBOX | LOG_SLI,
"%d:0304 Stray Mailbox Interrupt "
"mbxCommand x%x mbxStatus x%x\n",
@@ -992,9 +970,11 @@ void lpfc_sli_poll_fcp_ring(struct lpfc_hba * phba)
* resources need to be recovered.
*/
if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
- printk(KERN_INFO "%s: IOCB cmd 0x%x processed."
- " Skipping completion\n", __FUNCTION__,
- irsp->ulpCommand);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0314 IOCB cmd 0x%x"
+ " processed. Skipping"
+ " completion", phba->brd_no,
+ irsp->ulpCommand);
break;
}
@@ -1127,7 +1107,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
if (unlikely(irsp->ulpStatus)) {
/* Rsp ring <ringno> error: IOCB */
lpfc_printf_log(phba, KERN_WARNING, LOG_SLI,
- "%d:0326 Rsp Ring %d error: IOCB Data: "
+ "%d:0336 Rsp Ring %d error: IOCB Data: "
"x%x x%x x%x x%x x%x x%x x%x x%x\n",
phba->brd_no, pring->ringno,
irsp->un.ulpWord[0], irsp->un.ulpWord[1],
@@ -1145,9 +1125,11 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
* resources need to be recovered.
*/
if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) {
- printk(KERN_INFO "%s: IOCB cmd 0x%x processed. "
- "Skipping completion\n", __FUNCTION__,
- irsp->ulpCommand);
+ lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
+ "%d:0333 IOCB cmd 0x%x"
+ " processed. Skipping"
+ " completion\n", phba->brd_no,
+ irsp->ulpCommand);
break;
}
@@ -1178,7 +1160,7 @@ lpfc_sli_handle_fast_ring_event(struct lpfc_hba * phba,
} else {
/* Unknown IOCB command */
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0321 Unknown IOCB command "
+ "%d:0334 Unknown IOCB command "
"Data: x%x, x%x x%x x%x x%x\n",
phba->brd_no, type, irsp->ulpCommand,
irsp->ulpStatus, irsp->ulpIoTag,
@@ -1261,7 +1243,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
- "%d:0312 Ring %d handler: portRspPut %d "
+ "%d:0303 Ring %d handler: portRspPut %d "
"is bigger then rsp ring %d\n",
phba->brd_no,
pring->ringno, portRspPut, portRspMax);
@@ -1406,7 +1388,7 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
lpfc_printf_log(phba,
KERN_ERR,
LOG_SLI,
- "%d:0321 Unknown IOCB command "
+ "%d:0335 Unknown IOCB command "
"Data: x%x x%x x%x x%x\n",
phba->brd_no,
irsp->ulpCommand,
@@ -1422,11 +1404,11 @@ lpfc_sli_handle_slow_ring_event(struct lpfc_hba * phba,
next_iocb,
&saveq->list,
list) {
+ list_del(&rspiocbp->list);
lpfc_sli_release_iocbq(phba,
rspiocbp);
}
}
-
lpfc_sli_release_iocbq(phba, saveq);
}
}
@@ -1570,8 +1552,8 @@ lpfc_sli_brdready(struct lpfc_hba * phba, uint32_t mask)
void lpfc_reset_barrier(struct lpfc_hba * phba)
{
- uint32_t * resp_buf;
- uint32_t * mbox_buf;
+ uint32_t __iomem *resp_buf;
+ uint32_t __iomem *mbox_buf;
volatile uint32_t mbox;
uint32_t hc_copy;
int i;
@@ -1587,7 +1569,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
* Tell the other part of the chip to suspend temporarily all
* its DMA activity.
*/
- resp_buf = (uint32_t *)phba->MBslimaddr;
+ resp_buf = phba->MBslimaddr;
/* Disable the error attention */
hc_copy = readl(phba->HCregaddr);
@@ -1605,7 +1587,7 @@ void lpfc_reset_barrier(struct lpfc_hba * phba)
((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP;
writel(BARRIER_TEST_PATTERN, (resp_buf + 1));
- mbox_buf = (uint32_t *)phba->MBslimaddr;
+ mbox_buf = phba->MBslimaddr;
writel(mbox, mbox_buf);
for (i = 0;
@@ -1734,15 +1716,13 @@ lpfc_sli_brdreset(struct lpfc_hba * phba)
phba->fc_myDID = 0;
phba->fc_prevDID = 0;
- psli->sli_flag = 0;
-
/* Turn off parity checking and serr during the physical reset */
pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value);
pci_write_config_word(phba->pcidev, PCI_COMMAND,
(cfg_value &
~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR)));
- psli->sli_flag &= ~LPFC_SLI2_ACTIVE;
+ psli->sli_flag &= ~(LPFC_SLI2_ACTIVE | LPFC_PROCESS_LA);
/* Now toggle INITFF bit in the Host Control Register */
writel(HC_INITFF, phba->HCregaddr);
mdelay(1);
@@ -1783,7 +1763,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
/* Restart HBA */
lpfc_printf_log(phba, KERN_INFO, LOG_SLI,
- "%d:0328 Restart HBA Data: x%x x%x\n", phba->brd_no,
+ "%d:0337 Restart HBA Data: x%x x%x\n", phba->brd_no,
phba->hba_state, psli->sli_flag);
word0 = 0;
@@ -1805,7 +1785,7 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
skip_post = 0;
word0 = 0; /* This is really setting up word1 */
}
- to_slim = (uint8_t *) phba->MBslimaddr + sizeof (uint32_t);
+ to_slim = phba->MBslimaddr + sizeof (uint32_t);
writel(*(uint32_t *) mb, to_slim);
readl(to_slim); /* flush */
@@ -1815,6 +1795,9 @@ lpfc_sli_brdrestart(struct lpfc_hba * phba)
spin_unlock_irq(phba->host->host_lock);
+ memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets));
+ psli->stats_start = get_seconds();
+
if (skip_post)
mdelay(100);
else
@@ -1925,6 +1908,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba)
}
while (resetcount < 2 && !done) {
+ spin_lock_irq(phba->host->host_lock);
+ phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE;
+ spin_unlock_irq(phba->host->host_lock);
phba->hba_state = LPFC_STATE_UNKNOWN;
lpfc_sli_brdrestart(phba);
msleep(2500);
@@ -1932,6 +1918,9 @@ lpfc_sli_hba_setup(struct lpfc_hba * phba)
if (rc)
break;
+ spin_lock_irq(phba->host->host_lock);
+ phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
+ spin_unlock_irq(phba->host->host_lock);
resetcount++;
/* Call pre CONFIG_PORT mailbox command initialization. A value of 0
@@ -2217,7 +2206,8 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
return (MBX_NOT_FINISHED);
}
/* timeout active mbox command */
- mod_timer(&psli->mbox_tmo, jiffies + HZ * LPFC_MBOX_TMO);
+ mod_timer(&psli->mbox_tmo, (jiffies +
+ (HZ * lpfc_mbox_tmo_val(phba, mb->mbxCommand))));
}
/* Mailbox cmd <cmd> issue */
@@ -2277,7 +2267,6 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
break;
case MBX_POLL:
- i = 0;
psli->mbox_active = NULL;
if (psli->sli_flag & LPFC_SLI2_ACTIVE) {
/* First read mbox status word */
@@ -2291,11 +2280,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
/* Read the HBA Host Attention Register */
ha_copy = readl(phba->HAregaddr);
+ i = lpfc_mbox_tmo_val(phba, mb->mbxCommand);
+ i *= 1000; /* Convert to ms */
+
/* Wait for command to complete */
while (((word0 & OWN_CHIP) == OWN_CHIP) ||
(!(ha_copy & HA_MBATT) &&
(phba->hba_state > LPFC_WARM_START))) {
- if (i++ >= 100) {
+ if (i-- <= 0) {
psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
spin_unlock_irqrestore(phba->host->host_lock,
drvr_flag);
@@ -2313,7 +2305,7 @@ lpfc_sli_issue_mbox(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmbox, uint32_t flag)
/* Can be in interrupt context, do not sleep */
/* (or might be called with interrupts disabled) */
- mdelay(i);
+ mdelay(1);
spin_lock_irqsave(phba->host->host_lock, drvr_flag);
@@ -2659,8 +2651,6 @@ lpfc_sli_hba_down(struct lpfc_hba * phba)
INIT_LIST_HEAD(&(pring->txq));
- kfree(pring->fast_lookup);
- pring->fast_lookup = NULL;
}
spin_unlock_irqrestore(phba->host->host_lock, flags);
@@ -3030,7 +3020,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
if (timeleft == 0) {
lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
- "%d:0329 IOCB wait timeout error - no "
+ "%d:0338 IOCB wait timeout error - no "
"wake response Data x%x\n",
phba->brd_no, timeout);
retval = IOCB_TIMEDOUT;
@@ -3110,6 +3100,24 @@ lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
return retval;
}
+int
+lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
+{
+ int i = 0;
+
+ while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE && !phba->stopped) {
+ if (i++ > LPFC_MBOX_TMO * 1000)
+ return 1;
+
+ if (lpfc_sli_handle_mb_event(phba) == 0)
+ i = 0;
+
+ msleep(1);
+ }
+
+ return (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) ? 1 : 0;
+}
+
irqreturn_t
lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
{
diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h
index a52d6c6cf08..e26de680935 100644
--- a/drivers/scsi/lpfc/lpfc_sli.h
+++ b/drivers/scsi/lpfc/lpfc_sli.h
@@ -135,8 +135,6 @@ struct lpfc_sli_ring {
uint32_t fast_iotag; /* max fastlookup based iotag */
uint32_t iotag_ctr; /* keeps track of the next iotag to use */
uint32_t iotag_max; /* max iotag value to use */
- struct lpfc_iocbq ** fast_lookup; /* array of IOCB ptrs indexed by
- iotag */
struct list_head txq;
uint16_t txq_cnt; /* current length of queue */
uint16_t txq_max; /* max length */
@@ -174,6 +172,18 @@ struct lpfc_sli_stat {
uint32_t mbox_busy; /* Mailbox cmd busy */
};
+/* Structure to store link status values when port stats are reset */
+struct lpfc_lnk_stat {
+ uint32_t link_failure_count;
+ uint32_t loss_of_sync_count;
+ uint32_t loss_of_signal_count;
+ uint32_t prim_seq_protocol_err_count;
+ uint32_t invalid_tx_word_count;
+ uint32_t invalid_crc_count;
+ uint32_t error_frames;
+ uint32_t link_events;
+};
+
/* Structure used to hold SLI information */
struct lpfc_sli {
uint32_t num_rings;
@@ -203,6 +213,8 @@ struct lpfc_sli {
struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */
size_t iocbq_lookup_len; /* current lengs of the array */
uint16_t last_iotag; /* last allocated IOTAG */
+ unsigned long stats_start; /* in seconds */
+ struct lpfc_lnk_stat lnk_stat_offsets;
};
/* Given a pointer to the start of the ring, and the slot number of
@@ -213,3 +225,9 @@ struct lpfc_sli {
#define LPFC_MBOX_TMO 30 /* Sec tmo for outstanding mbox
command */
+#define LPFC_MBOX_TMO_FLASH_CMD 300 /* Sec tmo for outstanding FLASH write
+ * or erase cmds. This is especially
+ * long because of the potential of
+ * multiple flash erases that can be
+ * spawned.
+ */
diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h
index 6b737568b83..ac417908b40 100644
--- a/drivers/scsi/lpfc/lpfc_version.h
+++ b/drivers/scsi/lpfc/lpfc_version.h
@@ -18,7 +18,7 @@
* included with this package. *
*******************************************************************/
-#define LPFC_DRIVER_VERSION "8.1.6"
+#define LPFC_DRIVER_VERSION "8.1.10"
#define LPFC_DRIVER_NAME "lpfc"
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 93edaa8696c..6422de72bf4 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -378,7 +378,7 @@ static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
for (i = 0; i < nseg; ++i) {
@@ -431,7 +431,7 @@ static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *mat
struct fsc_state *state;
struct Scsi_Host *host;
void *dma_cmd_space;
- unsigned char *clkprop;
+ const unsigned char *clkprop;
int proplen, rc = -ENODEV;
if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index e31fadd6190..118206d68c6 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -43,9 +43,6 @@
/* #define DEBUG_MAC_ESP */
-#define mac_turnon_irq(x) mac_enable_irq(x)
-#define mac_turnoff_irq(x) mac_disable_irq(x)
-
extern void esp_handle(struct NCR_ESP *esp);
extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
@@ -639,13 +636,13 @@ static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
static void dma_ints_off(struct NCR_ESP * esp)
{
- mac_turnoff_irq(esp->irq);
+ disable_irq(esp->irq);
}
static void dma_ints_on(struct NCR_ESP * esp)
{
- mac_turnon_irq(esp->irq);
+ enable_irq(esp->irq);
}
/*
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 777f9bcd117..a942a21dd87 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -65,9 +65,6 @@
#define RESET_BOOT
#define DRIVER_SETUP
-#define ENABLE_IRQ() mac_enable_irq( IRQ_MAC_SCSI );
-#define DISABLE_IRQ() mac_disable_irq( IRQ_MAC_SCSI );
-
extern void via_scsi_clear(void);
#ifdef RESET_BOOT
@@ -351,7 +348,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
- mac_disable_irq(IRQ_MAC_SCSI);
+ disable_irq(IRQ_MAC_SCSI);
/* get in phase */
NCR5380_write( TARGET_COMMAND_REG,
@@ -369,7 +366,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
barrier();
/* switch on SCSI IRQ again */
- mac_enable_irq(IRQ_MAC_SCSI);
+ enable_irq(IRQ_MAC_SCSI);
printk(KERN_INFO " done\n" );
}
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 5d2cefb5e52..b87bef69ba0 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -2822,9 +2822,7 @@ mega_print_inquiry(char *page, char *scsi_inq)
i = scsi_inq[0] & 0x1f;
- len += sprintf(page+len, " Type: %s ",
- i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
- "Unknown ");
+ len += sprintf(page+len, " Type: %s ", scsi_device_type(i));
len += sprintf(page+len,
" ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
@@ -3658,8 +3656,9 @@ megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
* Send the request sense data also, irrespective of
* whether the user has asked for it or not.
*/
- copy_to_user(upthru->reqsensearea,
- pthru->reqsensearea, 14);
+ if (copy_to_user(upthru->reqsensearea,
+ pthru->reqsensearea, 14))
+ rval = -EFAULT;
freemem_and_return:
if( pthru->dataxferlen ) {
@@ -4714,7 +4713,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ?
megaraid_isr_memmapped : megaraid_isr_iomapped,
- SA_SHIRQ, "megaraid", adapter)) {
+ IRQF_SHARED, "megaraid", adapter)) {
printk(KERN_WARNING
"megaraid: Couldn't register IRQ %d!\n", irq);
goto out_free_scb_list;
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 4675343228a..8cd0bd1d0f7 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -37,6 +37,12 @@
#define LSI_MAX_CHANNELS 16
#define LSI_MAX_LOGICAL_DRIVES_64LD (64+1)
+#define HBA_SIGNATURE_64_BIT 0x299
+#define PCI_CONF_AMISIG64 0xa4
+
+#define MEGA_SCSI_INQ_EVPD 1
+#define MEGA_INVALID_FIELD_IN_CDB 0x24
+
/**
* scb_t - scsi command control block
diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h
index bdaee144a1c..b8aa34202ec 100644
--- a/drivers/scsi/megaraid/megaraid_ioctl.h
+++ b/drivers/scsi/megaraid/megaraid_ioctl.h
@@ -132,6 +132,10 @@ typedef struct uioc {
/* Driver Data: */
void __user * user_data;
uint32_t user_data_len;
+
+ /* 64bit alignment */
+ uint32_t pad_for_64bit_align;
+
mraid_passthru_t __user *user_pthru;
mraid_passthru_t *pthru32;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index bec1424eda8..266b3910846 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mbox.c
- * Version : v2.20.4.8 (Apr 11 2006)
+ * Version : v2.20.4.9 (Jul 16 2006)
*
* Authors:
* Atul Mukker <Atul.Mukker@lsil.com>
@@ -330,6 +330,21 @@ static struct device_attribute *megaraid_sdev_attrs[] = {
NULL,
};
+/**
+ * megaraid_change_queue_depth - Change the device's queue depth
+ * @sdev: scsi device struct
+ * @qdepth: depth to set
+ *
+ * Return value:
+ * actual depth set
+ **/
+static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+ if (qdepth > MBOX_MAX_SCSI_CMDS)
+ qdepth = MBOX_MAX_SCSI_CMDS;
+ scsi_adjust_queue_depth(sdev, 0, qdepth);
+ return sdev->queue_depth;
+}
/*
* Scsi host template for megaraid unified driver
@@ -343,6 +358,7 @@ static struct scsi_host_template megaraid_template_g = {
.eh_device_reset_handler = megaraid_reset_handler,
.eh_bus_reset_handler = megaraid_reset_handler,
.eh_host_reset_handler = megaraid_reset_handler,
+ .change_queue_depth = megaraid_change_queue_depth,
.use_clustering = ENABLE_CLUSTERING,
.sdev_attrs = megaraid_sdev_attrs,
.shost_attrs = megaraid_shost_attrs,
@@ -714,12 +730,13 @@ megaraid_io_detach(adapter_t *adapter)
* . Allocate memory required for all the commands
* . Use internal library of FW routines, build up complete soft state
*/
-static int __init
+static int __devinit
megaraid_init_mbox(adapter_t *adapter)
{
struct pci_dev *pdev;
mraid_device_t *raid_dev;
int i;
+ uint32_t magic64;
adapter->ito = MBOX_TIMEOUT;
@@ -767,7 +784,7 @@ megaraid_init_mbox(adapter_t *adapter)
//
// request IRQ and register the interrupt service routine
- if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid",
+ if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid",
adapter)) {
con_log(CL_ANN, (KERN_WARNING
@@ -863,12 +880,33 @@ megaraid_init_mbox(adapter_t *adapter)
// Set the DMA mask to 64-bit. All supported controllers as capable of
// DMA in this range
- if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK) != 0) {
-
- con_log(CL_ANN, (KERN_WARNING
- "megaraid: could not set DMA mask for 64-bit.\n"));
+ pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64);
+
+ if (((magic64 == HBA_SIGNATURE_64_BIT) &&
+ ((adapter->pdev->subsystem_device !=
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_6) ||
+ (adapter->pdev->subsystem_device !=
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_VERDE) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_DOBSON) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
+ adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) ||
+ (adapter->pdev->vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) {
+ if (pci_set_dma_mask(adapter->pdev, DMA_64BIT_MASK)) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: DMA mask for 64-bit failed\n"));
- goto out_free_sysfs_res;
+ if (pci_set_dma_mask (adapter->pdev, DMA_32BIT_MASK)) {
+ con_log(CL_ANN, (KERN_WARNING
+ "megaraid: 32-bit DMA mask failed\n"));
+ goto out_free_sysfs_res;
+ }
+ }
}
// setup tasklet for DPC
@@ -1622,6 +1660,14 @@ megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
rdev->last_disp |= (1L << SCP2CHANNEL(scp));
}
+ if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) {
+ scp->sense_buffer[0] = 0x70;
+ scp->sense_buffer[2] = ILLEGAL_REQUEST;
+ scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB;
+ scp->result = CHECK_CONDITION << 1;
+ return NULL;
+ }
+
/* Fall through */
case READ_CAPACITY:
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 868fb0ec93e..2b5a3285f79 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -21,8 +21,8 @@
#include "megaraid_ioctl.h"
-#define MEGARAID_VERSION "2.20.4.8"
-#define MEGARAID_EXT_VERSION "(Release Date: Mon Apr 11 12:27:22 EST 2006)"
+#define MEGARAID_VERSION "2.20.4.9"
+#define MEGARAID_EXT_VERSION "(Release Date: Sun Jul 16 12:27:22 EST 2006)"
/*
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
index e8f534fb336..d85b9a8f1b8 100644
--- a/drivers/scsi/megaraid/megaraid_mm.c
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_mm.c
- * Version : v2.20.2.6 (Mar 7 2005)
+ * Version : v2.20.2.7 (Jul 16 2006)
*
* Common management module
*/
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
index 3d9e67d6849..c8762b2b8ed 100644
--- a/drivers/scsi/megaraid/megaraid_mm.h
+++ b/drivers/scsi/megaraid/megaraid_mm.h
@@ -27,9 +27,9 @@
#include "megaraid_ioctl.h"
-#define LSI_COMMON_MOD_VERSION "2.20.2.6"
+#define LSI_COMMON_MOD_VERSION "2.20.2.7"
#define LSI_COMMON_MOD_EXT_VERSION \
- "(Release Date: Mon Mar 7 00:01:03 EST 2005)"
+ "(Release Date: Sun Jul 16 00:01:03 EST 2006)"
#define LSI_DBGLVL dbglevel
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 0c9516ff636..4cab5b534b2 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.02.04
+ * Version : v00.00.03.01
*
* Authors:
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
@@ -53,25 +53,15 @@ MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
*/
static struct pci_device_id megasas_pci_table[] = {
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_LSI_SAS1064R, // xscale IOP
- PCI_ANY_ID,
- PCI_ANY_ID,
- },
- {
- PCI_VENDOR_ID_LSI_LOGIC,
- PCI_DEVICE_ID_LSI_SAS1078R, // ppc IOP
- PCI_ANY_ID,
- PCI_ANY_ID,
- },
- {
- PCI_VENDOR_ID_DELL,
- PCI_DEVICE_ID_DELL_PERC5, // xscale IOP
- PCI_ANY_ID,
- PCI_ANY_ID,
- },
- {0} /* Terminating entry */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
+ /* xscale IOP */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
+ /* ppc IOP */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
+ /* xscale IOP, vega */
+ {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
+ /* xscale IOP */
+ {}
};
MODULE_DEVICE_TABLE(pci, megasas_pci_table);
@@ -289,9 +279,14 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
* @regs: MFI register set
*/
static inline void
-megasas_disable_intr(struct megasas_register_set __iomem * regs)
+megasas_disable_intr(struct megasas_instance *instance)
{
u32 mask = 0x1f;
+ struct megasas_register_set __iomem *regs = instance->reg_set;
+
+ if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
+ mask = 0xffffffff;
+
writel(mask, &regs->outbound_intr_mask);
/* Dummy readl to force pci flush */
@@ -1260,7 +1255,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Bring it to READY state; assuming max wait 2 secs
*/
- megasas_disable_intr(instance->reg_set);
+ megasas_disable_intr(instance);
writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
max_wait = 10;
@@ -1757,6 +1752,11 @@ static int megasas_init_mfi(struct megasas_instance *instance)
init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
/*
+ * disable the intr before firing the init frame to FW
+ */
+ megasas_disable_intr(instance);
+
+ /*
* Issue the init frame in polled mode
*/
if (megasas_issue_polled(instance, cmd)) {
@@ -2191,7 +2191,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/*
* Register IRQ
*/
- if (request_irq(pdev->irq, megasas_isr, SA_SHIRQ, "megasas", instance)) {
+ if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED, "megasas", instance)) {
printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
goto fail_irq;
}
@@ -2234,7 +2234,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
megasas_mgmt_info.max_index--;
pci_set_drvdata(pdev, NULL);
- megasas_disable_intr(instance->reg_set);
+ megasas_disable_intr(instance);
free_irq(instance->pdev->irq, instance);
megasas_release_mfi(instance);
@@ -2364,7 +2364,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_set_drvdata(instance->pdev, NULL);
- megasas_disable_intr(instance->reg_set);
+ megasas_disable_intr(instance);
free_irq(instance->pdev->irq, instance);
@@ -2838,7 +2838,7 @@ static int __init megasas_init(void)
/*
* Register ourselves as PCI hotplug module
*/
- rval = pci_module_init(&megasas_pci_driver);
+ rval = pci_register_driver(&megasas_pci_driver);
if (rval) {
printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 927d6ffef05..3531a14222a 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,16 @@
/**
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.02.04"
-#define MEGASAS_RELDATE "Feb 03, 2006"
-#define MEGASAS_EXT_VERSION "Fri Feb 03 14:31:44 PST 2006"
+#define MEGASAS_VERSION "00.00.03.01"
+#define MEGASAS_RELDATE "May 14, 2006"
+#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006"
+
+/*
+ * Device IDs
+ */
+#define PCI_DEVICE_ID_LSI_SAS1078R 0x0060
+#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413
+
/*
* =====================================
* MegaRAID SAS MFI firmware definitions
@@ -554,7 +561,11 @@ struct megasas_ctrl_info {
#define MFI_POLL_TIMEOUT_SECS 10
#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000
-#define PCI_DEVICE_ID_LSI_SAS1078R 0x00000060
+
+/*
+* register set for both 1068 and 1078 controllers
+* structure extended for 1078 registers
+*/
struct megasas_register_set {
u32 reserved_0[4]; /*0000h*/
@@ -1150,10 +1161,10 @@ struct compat_megasas_iocpacket {
struct compat_iovec sgl[MAX_IOCTL_SGE];
} __attribute__ ((packed));
+#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket)
#endif
#define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket)
-#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket)
#define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen)
struct megasas_mgmt_info {
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index f852421002e..683fc7ae4b8 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -18,7 +18,6 @@
* - retry arbitration if lost (unless higher levels do this for us)
* - power down the chip when no device is detected
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -1269,7 +1268,7 @@ static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
if (cmd->use_sg > 0) {
int nseg;
total = 0;
- scl = (struct scatterlist *) cmd->buffer;
+ scl = (struct scatterlist *) cmd->request_buffer;
off = ms->data_ptr;
nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
cmd->sc_data_direction);
@@ -1757,16 +1756,23 @@ static void set_mesh_power(struct mesh_state *ms, int state)
pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
msleep(10);
}
-}
+}
#ifdef CONFIG_PM
-static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
+static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg)
{
struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
unsigned long flags;
- if (state.event == mdev->ofdev.dev.power.power_state.event || state.event < 2)
+ switch (mesg.event) {
+ case PM_EVENT_SUSPEND:
+ case PM_EVENT_FREEZE:
+ break;
+ default:
+ return 0;
+ }
+ if (mesg.event == mdev->ofdev.dev.power.power_state.event)
return 0;
scsi_block_requests(ms->host);
@@ -1781,7 +1787,7 @@ static int mesh_suspend(struct macio_dev *mdev, pm_message_t state)
disable_irq(ms->meshintr);
set_mesh_power(ms, 0);
- mdev->ofdev.dev.power.power_state = state;
+ mdev->ofdev.dev.power.power_state = mesg;
return 0;
}
@@ -1851,7 +1857,8 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mesh = macio_get_of_node(mdev);
struct pci_dev* pdev = macio_get_pci_dev(mdev);
- int tgt, *cfp, minper;
+ int tgt, minper;
+ const int *cfp;
struct mesh_state *ms;
struct Scsi_Host *mesh_host;
void *dma_cmd_space;
@@ -1940,7 +1947,7 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
ms->tgts[tgt].current_req = NULL;
}
- if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
+ if ((cfp = get_property(mesh, "clock-frequency", NULL)))
ms->clk_freq = *cfp;
else {
printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index cb367c2c5c7..9b991b746d1 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -29,7 +29,7 @@ static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
return IRQ_HANDLED;
}
-static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+static int dma_setup(struct scsi_cmnd *cmd, int dir_in)
{
unsigned char flags = 0x01;
unsigned long addr = virt_to_bus(cmd->SCp.ptr);
@@ -57,7 +57,7 @@ static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
return 0;
}
-static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
m147_pcc->dma_cntrl = 0;
@@ -112,7 +112,7 @@ int mvme147_detect(struct scsi_host_template *tpnt)
return 0;
}
-static int mvme147_bus_reset(Scsi_Cmnd *cmd)
+static int mvme147_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h
index 2f56d69bd18..32aee85434d 100644
--- a/drivers/scsi/mvme147.h
+++ b/drivers/scsi/mvme147.h
@@ -12,10 +12,6 @@
int mvme147_detect(struct scsi_host_template *);
int mvme147_release(struct Scsi_Host *);
-const char *wd33c93_info(void);
-int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int wd33c93_abort(Scsi_Cmnd *);
-int wd33c93_reset(Scsi_Cmnd *, unsigned int);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 6ab035590ee..b28712df0b7 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -5118,8 +5118,7 @@ static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp)
cp->host_status &= ~HS_SKIPMASK;
cp->start.schedule.l_paddr =
cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
- list_del(&cp->link_ccbq);
- list_add_tail(&cp->link_ccbq, &lp->skip_ccbq);
+ list_move_tail(&cp->link_ccbq, &lp->skip_ccbq);
if (cp->queued) {
--lp->queuedccbs;
}
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 0e4e46a0133..78818b6684f 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -53,10 +53,8 @@
#ifndef NCR53C8XX_H
#define NCR53C8XX_H
-#include <linux/config.h>
#include <scsi/scsi_host.h>
-#include <linux/config.h>
/*
** If you want a driver as small as possible, donnot define the
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 5c55e152e71..bfb4f49e125 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -2866,8 +2866,7 @@ static int nsp32_detect(struct scsi_host_template *sht)
*/
nsp32_do_bus_reset(data);
- ret = request_irq(host->irq, do_nsp32_isr,
- SA_SHIRQ | SA_SAMPLE_RANDOM, "nsp32", data);
+ ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data);
if (ret < 0) {
nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 "
"SCSI PCI controller. Interrupt: %d", host->irq);
@@ -2886,12 +2885,19 @@ static int nsp32_detect(struct scsi_host_template *sht)
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
- scsi_add_host (host, &PCIDEV->dev);
+ ret = scsi_add_host(host, &PCIDEV->dev);
+ if (ret) {
+ nsp32_msg(KERN_ERR, "failed to add scsi host");
+ goto free_region;
+ }
scsi_scan_host(host);
#endif
pci_set_drvdata(PCIDEV, host);
return DETECT_OK;
+ free_region:
+ release_region(host->io_port, host->n_io_port);
+
free_irq:
free_irq(host->irq, data);
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
index dee426f8c07..dd67a68c5c2 100644
--- a/drivers/scsi/oktagon_esp.c
+++ b/drivers/scsi/oktagon_esp.c
@@ -6,7 +6,6 @@
* Based on cyber_esp.c
*/
-#include <linux/config.h>
#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS)
#define USE_BOTTOM_HALF
@@ -198,7 +197,7 @@ int oktagon_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = (__u32) cmd_buffer;
esp->irq = IRQ_AMIGA_PORTS;
- request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+ request_irq(IRQ_AMIGA_PORTS, esp_intr, IRQF_SHARED,
"BSC Oktagon SCSI", esp->ehost);
/* Figure out our scsi ID on the bus */
diff --git a/drivers/scsi/oktagon_io.S b/drivers/scsi/oktagon_io.S
index 08ce8d80d8f..8a7340b0270 100644
--- a/drivers/scsi/oktagon_io.S
+++ b/drivers/scsi/oktagon_io.S
@@ -23,7 +23,6 @@ int oktag_from_io(long *addr,long *paddr,long len)
* is moved to/from the IO register.
*/
-#include <linux/config.h>
#ifdef CONFIG_APUS
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
index 011d4d6ca9f..1e426f5d0ed 100644
--- a/drivers/scsi/osst.h
+++ b/drivers/scsi/osst.h
@@ -3,7 +3,6 @@
*/
#include <asm/byteorder.h>
-#include <linux/config.h>
#include <linux/completion.h>
/* FIXME - rename and use the following two types or delete them!
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 1bf96ed8f93..1434209a8ac 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -454,7 +454,7 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", instance)) {
+ if (request_irq(instance->irq, pas16_intr, IRQF_DISABLED, "pas16", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 231f9c311c6..0d4c04e1f3d 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1623,7 +1623,7 @@ static int nsp_cs_probe(struct pcmcia_device *link)
/* Interrupt handler */
link->irq.Handler = &nspintr;
link->irq.Instance = info;
- link->irq.Attributes |= (SA_SHIRQ | SA_SAMPLE_RANDOM);
+ link->irq.Attributes |= IRQF_SHARED;
/* General socket configuration */
link->conf.Attributes = CONF_ENABLE_IRQ;
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 9f59827707f..0b65099acb1 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -799,7 +799,7 @@ next_entry:
data = (struct sym53c500_data *)host->hostdata;
if (irq_level > 0) {
- if (request_irq(irq_level, SYM53C500_intr, SA_SHIRQ, "SYM53C500", host)) {
+ if (request_irq(irq_level, SYM53C500_intr, IRQF_SHARED, "SYM53C500", host)) {
printk("SYM53C500: unable to allocate IRQ %d\n", irq_level);
goto err_free_scsi;
}
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 83a67179993..0bd9c60e645 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -13,7 +13,6 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/init.h>
-#include <linux/config.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
@@ -170,8 +169,6 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt->request->rq_status = RQ_SCSI_BUSY;
SCpnt->done = pluto_detect_done;
- SCpnt->bufflen = 256;
- SCpnt->buffer = fcs[i].inquiry;
SCpnt->request_bufflen = 256;
SCpnt->request_buffer = fcs[i].inquiry;
PLD(("set up %d %08lx\n", i, (long)SCpnt))
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index 108910f512e..b0eba39f208 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -6,11 +6,8 @@
* (c) 1995,1996 Grant R. Guenther, grant@torque.net,
* under the terms of the GNU General Public License.
*
- * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
- * campbell@torque.net
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index f6e1a1574bb..7511df3588e 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -2,7 +2,7 @@
* the Iomega ZIP drive
*
* (c) 1996 Grant R. Guenther grant@torque.net
- * David Campbell campbell@torque.net
+ * David Campbell
*
* All comments to David.
*/
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 680f6063954..8953991462d 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -192,7 +192,7 @@
- Don't walk the entire list in qla1280_putq_t() just to directly
grab the pointer to the last element afterwards
Rev 3.23.5 Beta August 9, 2001, Jes Sorensen
- - Don't use SA_INTERRUPT, it's use is deprecated for this kinda driver
+ - Don't use IRQF_DISABLED, it's use is deprecated for this kinda driver
Rev 3.23.4 Beta August 8, 2001, Jes Sorensen
- Set dev->max_sectors to 1024
Rev 3.23.3 Beta August 6, 2001, Jes Sorensen
@@ -331,7 +331,6 @@
*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
@@ -4210,7 +4209,7 @@ qla1280_setup(char *s)
}
-static int
+static int __init
qla1280_get_token(char *str)
{
char *sep;
@@ -4370,7 +4369,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
/* Disable ISP interrupts. */
qla1280_disable_intrs(ha);
- if (request_irq(pdev->irq, qla1280_intr_handler, SA_SHIRQ,
+ if (request_irq(pdev->irq, qla1280_intr_handler, IRQF_SHARED,
"qla1280", ha)) {
printk("qla1280 : Failed to reserve interrupt %d already "
"in use\n", pdev->irq);
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index e96d58ded57..87f90c4f08e 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -16,15 +16,16 @@ qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf, loff_t off,
{
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
+ char *rbuf = (char *)ha->fw_dump;
if (ha->fw_dump_reading == 0)
return 0;
- if (off > ha->fw_dump_buffer_len)
- return 0;
- if (off + count > ha->fw_dump_buffer_len)
- count = ha->fw_dump_buffer_len - off;
+ if (off > ha->fw_dump_len)
+ return 0;
+ if (off + count > ha->fw_dump_len)
+ count = ha->fw_dump_len - off;
- memcpy(buf, &ha->fw_dump_buffer[off], count);
+ memcpy(buf, &rbuf[off], count);
return (count);
}
@@ -36,7 +37,6 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
struct device, kobj)));
int reading;
- uint32_t dump_size;
if (off != 0)
return (0);
@@ -44,46 +44,27 @@ qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf, loff_t off,
reading = simple_strtol(buf, NULL, 10);
switch (reading) {
case 0:
- if (ha->fw_dump_reading == 1) {
- qla_printk(KERN_INFO, ha,
- "Firmware dump cleared on (%ld).\n", ha->host_no);
+ if (!ha->fw_dump_reading)
+ break;
- vfree(ha->fw_dump_buffer);
- ha->fw_dump_buffer = NULL;
- ha->fw_dump_reading = 0;
- ha->fw_dumped = 0;
- }
+ qla_printk(KERN_INFO, ha,
+ "Firmware dump cleared on (%ld).\n", ha->host_no);
+
+ ha->fw_dump_reading = 0;
+ ha->fw_dumped = 0;
break;
case 1:
if (ha->fw_dumped && !ha->fw_dump_reading) {
ha->fw_dump_reading = 1;
- if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
- dump_size = FW_DUMP_SIZE_24XX;
- else {
- dump_size = FW_DUMP_SIZE_1M;
- if (ha->fw_memory_size < 0x20000)
- dump_size = FW_DUMP_SIZE_128K;
- else if (ha->fw_memory_size < 0x80000)
- dump_size = FW_DUMP_SIZE_512K;
- }
- ha->fw_dump_buffer = (char *)vmalloc(dump_size);
- if (ha->fw_dump_buffer == NULL) {
- qla_printk(KERN_WARNING, ha,
- "Unable to allocate memory for firmware "
- "dump buffer (%d).\n", dump_size);
-
- ha->fw_dump_reading = 0;
- return (count);
- }
qla_printk(KERN_INFO, ha,
- "Firmware dump ready for read on (%ld).\n",
+ "Raw firmware dump ready for read on (%ld).\n",
ha->host_no);
- memset(ha->fw_dump_buffer, 0, dump_size);
- ha->isp_ops.ascii_fw_dump(ha);
- ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);
}
break;
+ case 2:
+ qla2x00_alloc_fw_dump(ha);
+ break;
}
return (count);
}
@@ -313,9 +294,6 @@ qla2x00_sysfs_read_vpd(struct kobject *kobj, char *buf, loff_t off,
if (!capable(CAP_SYS_ADMIN) || off != 0)
return 0;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
- return -ENOTSUPP;
-
/* Read NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->vpd_base, ha->vpd_size);
@@ -335,9 +313,6 @@ qla2x00_sysfs_write_vpd(struct kobject *kobj, char *buf, loff_t off,
if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size)
return 0;
- if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
- return -ENOTSUPP;
-
/* Write NVRAM. */
spin_lock_irqsave(&ha->hardware_lock, flags);
ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
@@ -357,6 +332,53 @@ static struct bin_attribute sysfs_vpd_attr = {
.write = qla2x00_sysfs_write_vpd,
};
+static ssize_t
+qla2x00_sysfs_read_sfp(struct kobject *kobj, char *buf, loff_t off,
+ size_t count)
+{
+ struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+ struct device, kobj)));
+ uint16_t iter, addr, offset;
+ int rval;
+
+ if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2)
+ return 0;
+
+ addr = 0xa0;
+ for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE;
+ iter++, offset += SFP_BLOCK_SIZE) {
+ if (iter == 4) {
+ /* Skip to next device address. */
+ addr = 0xa2;
+ offset = 0;
+ }
+
+ rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset,
+ SFP_BLOCK_SIZE);
+ if (rval != QLA_SUCCESS) {
+ qla_printk(KERN_WARNING, ha,
+ "Unable to read SFP data (%x/%x/%x).\n", rval,
+ addr, offset);
+ count = 0;
+ break;
+ }
+ memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE);
+ buf += SFP_BLOCK_SIZE;
+ }
+
+ return count;
+}
+
+static struct bin_attribute sysfs_sfp_attr = {
+ .attr = {
+ .name = "sfp",
+ .mode = S_IRUSR | S_IWUSR,
+ .owner = THIS_MODULE,
+ },
+ .size = SFP_DEV_SIZE * 2,
+ .read = qla2x00_sysfs_read_sfp,
+};
+
void
qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
{
@@ -367,7 +389,12 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
sysfs_create_bin_file(&host->shost_gendev.kobj,
&sysfs_optrom_ctl_attr);
- sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr);
+ if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ sysfs_create_bin_file(&host->shost_gendev.kobj,
+ &sysfs_vpd_attr);
+ sysfs_create_bin_file(&host->shost_gendev.kobj,
+ &sysfs_sfp_attr);
+ }
}
void
@@ -380,7 +407,12 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_optrom_attr);
sysfs_remove_bin_file(&host->shost_gendev.kobj,
&sysfs_optrom_ctl_attr);
- sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_vpd_attr);
+ if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ sysfs_remove_bin_file(&host->shost_gendev.kobj,
+ &sysfs_vpd_attr);
+ sysfs_remove_bin_file(&host->shost_gendev.kobj,
+ &sysfs_sfp_attr);
+ }
if (ha->beacon_blink_led == 1)
ha->isp_ops.beacon_off(ha);
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
index 74e54713aa7..f6ed6962bc2 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.c
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -8,7 +8,34 @@
#include <linux/delay.h>
-static int qla_uprintf(char **, char *, ...);
+static inline void
+qla2xxx_prep_dump(scsi_qla_host_t *ha, struct qla2xxx_fw_dump *fw_dump)
+{
+ fw_dump->fw_major_version = htonl(ha->fw_major_version);
+ fw_dump->fw_minor_version = htonl(ha->fw_minor_version);
+ fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version);
+ fw_dump->fw_attributes = htonl(ha->fw_attributes);
+
+ fw_dump->vendor = htonl(ha->pdev->vendor);
+ fw_dump->device = htonl(ha->pdev->device);
+ fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor);
+ fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device);
+}
+
+static inline void *
+qla2xxx_copy_queues(scsi_qla_host_t *ha, void *ptr)
+{
+ /* Request queue. */
+ memcpy(ptr, ha->request_ring, ha->request_q_length *
+ sizeof(request_t));
+
+ /* Response queue. */
+ ptr += ha->request_q_length * sizeof(request_t);
+ memcpy(ptr, ha->response_ring, ha->response_q_length *
+ sizeof(response_t));
+
+ return ptr + (ha->response_q_length * sizeof(response_t));
+}
/**
* qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
@@ -49,10 +76,11 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
"request...\n", ha->fw_dump);
goto qla2300_fw_dump_failed;
}
- fw = ha->fw_dump;
+ fw = &ha->fw_dump->isp.isp23;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
rval = QLA_SUCCESS;
- fw->hccr = RD_REG_WORD(&reg->hccr);
+ fw->hccr = htons(RD_REG_WORD(&reg->hccr));
/* Pause RISC. */
WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
@@ -73,85 +101,86 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (rval == QLA_SUCCESS) {
dmp_reg = (uint16_t __iomem *)(reg + 0);
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++)
- fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40);
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x40);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++)
- fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->resp_dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x50);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2200);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2400);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2600);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2800);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2A00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2C00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2E00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x10);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->frame_buf_hdw_reg[cnt] =
+ htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x20);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x30);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
/* Reset RISC. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -226,7 +255,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->risc_ram[cnt] = mb2;
+ fw->risc_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -285,7 +314,7 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->stack_ram[cnt] = mb2;
+ fw->stack_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -345,12 +374,15 @@ qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->data_ram[cnt] = mb2;
+ fw->data_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
+ if (rval == QLA_SUCCESS)
+ qla2xxx_copy_queues(ha, &fw->data_ram[cnt]);
+
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -369,193 +401,6 @@ qla2300_fw_dump_failed:
}
/**
- * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII.
- * @ha: HA context
- */
-void
-qla2300_ascii_fw_dump(scsi_qla_host_t *ha)
-{
- uint32_t cnt;
- char *uiter;
- char fw_info[30];
- struct qla2300_fw_dump *fw;
- uint32_t data_ram_cnt;
-
- uiter = ha->fw_dump_buffer;
- fw = ha->fw_dump;
-
- qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number,
- ha->isp_ops.fw_version_str(ha, fw_info));
-
- qla_uprintf(&uiter, "\n[==>BEG]\n");
-
- qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr);
-
- qla_uprintf(&uiter, "PBIU Registers:");
- for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nMailbox Registers:");
- for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:");
- for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nDMA Registers:");
- for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP2 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP3 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP4 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP5 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP6 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP7 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nCode RAM Dump:");
- for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800);
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nStack RAM Dump:");
- for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000);
- }
- qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nData RAM Dump:");
- data_ram_cnt = ha->fw_memory_size - 0x11000 + 1;
- for (cnt = 0; cnt < data_ram_cnt; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000);
- }
- qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump.");
-}
-
-/**
* qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware.
* @ha: HA context
* @hardware_locked: Called with the hardware_lock
@@ -591,10 +436,11 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
"request...\n", ha->fw_dump);
goto qla2100_fw_dump_failed;
}
- fw = ha->fw_dump;
+ fw = &ha->fw_dump->isp.isp21;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
rval = QLA_SUCCESS;
- fw->hccr = RD_REG_WORD(&reg->hccr);
+ fw->hccr = htons(RD_REG_WORD(&reg->hccr));
/* Pause RISC. */
WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
@@ -608,79 +454,81 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (rval == QLA_SUCCESS) {
dmp_reg = (uint16_t __iomem *)(reg + 0);
for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++)
- fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
for (cnt = 0; cnt < ha->mbx_count; cnt++) {
if (cnt == 8) {
- dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0);
+ dmp_reg = (uint16_t __iomem *)
+ ((uint8_t __iomem *)reg + 0xe0);
}
- fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
}
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20);
for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++)
- fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x00);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++)
- fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2000);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++)
- fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2100);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++)
- fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2200);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++)
- fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp2_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2300);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++)
- fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp3_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2400);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++)
- fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp4_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2500);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++)
- fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp5_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2600);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++)
- fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp6_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->pcr, 0x2700);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++)
- fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->risc_gp7_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x10);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++)
- fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->frame_buf_hdw_reg[cnt] =
+ htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x20);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++)
- fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b0_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
WRT_REG_WORD(&reg->ctrl_status, 0x30);
dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++)
- fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+ fw->fpm_b1_reg[cnt] = htons(RD_REG_WORD(dmp_reg++));
/* Reset the ISP. */
WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
@@ -755,12 +603,15 @@ qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb0 & MBS_MASK;
- fw->risc_ram[cnt] = mb2;
+ fw->risc_ram[cnt] = htons(mb2);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
+ if (rval == QLA_SUCCESS)
+ qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]);
+
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -778,179 +629,6 @@ qla2100_fw_dump_failed:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-/**
- * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII.
- * @ha: HA context
- */
-void
-qla2100_ascii_fw_dump(scsi_qla_host_t *ha)
-{
- uint32_t cnt;
- char *uiter;
- char fw_info[30];
- struct qla2100_fw_dump *fw;
-
- uiter = ha->fw_dump_buffer;
- fw = ha->fw_dump;
-
- qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number,
- ha->isp_ops.fw_version_str(ha, fw_info));
-
- qla_uprintf(&uiter, "\n[==>BEG]\n");
-
- qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr);
-
- qla_uprintf(&uiter, "PBIU Registers:");
- for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nMailbox Registers:");
- for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nDMA Registers:");
- for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP2 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP3 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP4 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP5 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP6 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP7 Registers:");
- for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:");
- for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B0 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM B1 Registers:");
- for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n");
- }
- qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC SRAM:");
- for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000);
- }
- qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump.");
-
- return;
-}
-
-static int
-qla_uprintf(char **uiter, char *fmt, ...)
-{
- int iter, len;
- char buf[128];
- va_list args;
-
- va_start(args, fmt);
- len = vsprintf(buf, fmt, args);
- va_end(args);
-
- for (iter = 0; iter < len; iter++, *uiter += 1)
- *uiter[0] = buf[iter];
-
- return (len);
-}
-
-
void
qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
{
@@ -967,6 +645,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
unsigned long flags;
struct qla24xx_fw_dump *fw;
uint32_t ext_mem_cnt;
+ void *eft;
risc_address = ext_mem_cnt = 0;
memset(mb, 0, sizeof(mb));
@@ -987,10 +666,11 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
"request...\n", ha->fw_dump);
goto qla24xx_fw_dump_failed;
}
- fw = ha->fw_dump;
+ fw = &ha->fw_dump->isp.isp24;
+ qla2xxx_prep_dump(ha, ha->fw_dump);
rval = QLA_SUCCESS;
- fw->host_status = RD_REG_DWORD(&reg->host_status);
+ fw->host_status = htonl(RD_REG_DWORD(&reg->host_status));
/* Pause RISC. */
if ((RD_REG_DWORD(&reg->hccr) & HCCRX_RISC_PAUSE) == 0) {
@@ -1012,7 +692,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
/* Host interface registers. */
dmp_reg = (uint32_t __iomem *)(reg + 0);
for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++)
- fw->host_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Disable interrupts. */
WRT_REG_DWORD(&reg->ictrl, 0);
@@ -1024,470 +704,471 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0000000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[0] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[0] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0100000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[1] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[1] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0200000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[2] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[2] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0300000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[3] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[3] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0400000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[4] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[4] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0500000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[5] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[5] = htonl(RD_REG_DWORD(dmp_reg));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xF0);
WRT_REG_DWORD(dmp_reg, 0xB0600000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xFC);
- fw->shadow_reg[6] = RD_REG_DWORD(dmp_reg);
+ fw->shadow_reg[6] = htonl(RD_REG_DWORD(dmp_reg));
/* Mailbox registers. */
mbx_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++)
- fw->mailbox_reg[cnt] = RD_REG_WORD(mbx_reg++);
+ fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++));
/* Transfer sequence registers. */
iter_reg = fw->xseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xBF00);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF10);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF20);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF30);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF40);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF50);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF60);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBF70);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFE0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++)
- fw->xseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->xseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xBFF0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++)
- fw->xseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->xseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Receive sequence registers. */
iter_reg = fw->rseq_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0xFF00);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF10);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF20);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF30);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF40);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF50);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF60);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFF70);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFD0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++)
- fw->rseq_0_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->rseq_0_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFE0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++)
- fw->rseq_1_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->rseq_1_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0xFFF0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++)
- fw->rseq_2_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->rseq_2_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Command DMA registers. */
WRT_REG_DWORD(&reg->iobase_addr, 0x7100);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++)
- fw->cmd_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->cmd_dma_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++));
/* Queues. */
iter_reg = fw->req0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7200);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->resp0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7300);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->req1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7400);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 8; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xE4);
for (cnt = 0; cnt < 7; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Transmit DMA registers. */
iter_reg = fw->xmt0_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7600);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7610);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt1_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7620);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7630);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt2_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7640);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7650);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt3_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7660);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7670);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->xmt4_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7680);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7690);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x76A0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++)
- fw->xmt_data_dma_reg[cnt] = RD_REG_DWORD(dmp_reg++);
+ fw->xmt_data_dma_reg[cnt] =
+ htonl(RD_REG_DWORD(dmp_reg++));
/* Receive DMA registers. */
iter_reg = fw->rcvt0_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7700);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7710);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
iter_reg = fw->rcvt1_data_dma_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x7720);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x7730);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* RISC registers. */
iter_reg = fw->risc_gp_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x0F00);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F10);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F20);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F30);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F40);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F50);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F60);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x0F70);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Local memory controller registers. */
iter_reg = fw->lmc_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x3000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3010);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3020);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3030);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3040);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3050);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x3060);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Fibre Protocol Module registers. */
iter_reg = fw->fpm_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x4000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4010);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4020);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4030);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4040);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4050);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4060);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4070);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4080);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x4090);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40A0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x40B0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Frame Buffer registers. */
iter_reg = fw->fb_hdw_reg;
WRT_REG_DWORD(&reg->iobase_addr, 0x6000);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6010);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6020);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6030);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6040);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6100);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6130);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6150);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6170);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x6190);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
WRT_REG_DWORD(&reg->iobase_addr, 0x61B0);
dmp_reg = (uint32_t __iomem *)((uint8_t __iomem *)reg + 0xC0);
for (cnt = 0; cnt < 16; cnt++)
- *iter_reg++ = RD_REG_DWORD(dmp_reg++);
+ *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++));
/* Reset RISC. */
WRT_REG_DWORD(&reg->ctrl_status,
@@ -1577,7 +1258,7 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb[0] & MBS_MASK;
- fw->code_ram[cnt] = (mb[3] << 16) | mb[2];
+ fw->code_ram[cnt] = htonl((mb[3] << 16) | mb[2]);
} else {
rval = QLA_FUNCTION_FAILED;
}
@@ -1627,12 +1308,18 @@ qla24xx_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
rval = mb[0] & MBS_MASK;
- fw->ext_mem[cnt] = (mb[3] << 16) | mb[2];
+ fw->ext_mem[cnt] = htonl((mb[3] << 16) | mb[2]);
} else {
rval = QLA_FUNCTION_FAILED;
}
}
+ if (rval == QLA_SUCCESS) {
+ eft = qla2xxx_copy_queues(ha, &fw->ext_mem[cnt]);
+ if (ha->eft)
+ memcpy(eft, ha->eft, ntohl(ha->fw_dump->eft_size));
+ }
+
if (rval != QLA_SUCCESS) {
qla_printk(KERN_WARNING, ha,
"Failed to dump firmware (%x)!!!\n", rval);
@@ -1650,252 +1337,6 @@ qla24xx_fw_dump_failed:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
}
-void
-qla24xx_ascii_fw_dump(scsi_qla_host_t *ha)
-{
- uint32_t cnt;
- char *uiter;
- struct qla24xx_fw_dump *fw;
- uint32_t ext_mem_cnt;
-
- uiter = ha->fw_dump_buffer;
- fw = ha->fw_dump;
-
- qla_uprintf(&uiter, "ISP FW Version %d.%02d.%02d Attributes %04x\n",
- ha->fw_major_version, ha->fw_minor_version,
- ha->fw_subminor_version, ha->fw_attributes);
-
- qla_uprintf(&uiter, "\nR2H Status Register\n%04x\n", fw->host_status);
-
- qla_uprintf(&uiter, "\nHost Interface Registers");
- for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->host_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nShadow Registers");
- for (cnt = 0; cnt < sizeof(fw->shadow_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->shadow_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nMailbox Registers");
- for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->mailbox_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXSEQ GP Registers");
- for (cnt = 0; cnt < sizeof(fw->xseq_gp_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xseq_gp_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXSEQ-0 Registers");
- for (cnt = 0; cnt < sizeof(fw->xseq_0_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xseq_0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXSEQ-1 Registers");
- for (cnt = 0; cnt < sizeof(fw->xseq_1_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xseq_1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ GP Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_gp_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_gp_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ-0 Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_0_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_0_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ-1 Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_1_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_1_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRSEQ-2 Registers");
- for (cnt = 0; cnt < sizeof(fw->rseq_2_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rseq_2_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nCommand DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->cmd_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->cmd_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRequest0 Queue DMA Channel Registers");
- for (cnt = 0; cnt < sizeof(fw->req0_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->req0_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nResponse0 Queue DMA Channel Registers");
- for (cnt = 0; cnt < sizeof(fw->resp0_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->resp0_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRequest1 Queue DMA Channel Registers");
- for (cnt = 0; cnt < sizeof(fw->req1_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->req1_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT0 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt0_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt0_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT1 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt1_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt1_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT2 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt2_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt2_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT3 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt3_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt3_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT4 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt4_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt4_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nXMT Data DMA Common Registers");
- for (cnt = 0; cnt < sizeof(fw->xmt_data_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->xmt_data_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRCV Thread 0 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->rcvt0_data_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rcvt0_data_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRCV Thread 1 Data DMA Registers");
- for (cnt = 0; cnt < sizeof(fw->rcvt1_data_dma_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->rcvt1_data_dma_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nRISC GP Registers");
- for (cnt = 0; cnt < sizeof(fw->risc_gp_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->risc_gp_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nLMC Registers");
- for (cnt = 0; cnt < sizeof(fw->lmc_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->lmc_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFPM Hardware Registers");
- for (cnt = 0; cnt < sizeof(fw->fpm_hdw_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->fpm_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nFB Hardware Registers");
- for (cnt = 0; cnt < sizeof(fw->fb_hdw_reg) / 4; cnt++) {
- if (cnt % 8 == 0)
- qla_uprintf(&uiter, "\n");
-
- qla_uprintf(&uiter, "%08x ", fw->fb_hdw_reg[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nCode RAM");
- for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%08x: ", cnt + 0x20000);
- }
- qla_uprintf(&uiter, "%08x ", fw->code_ram[cnt]);
- }
-
- qla_uprintf(&uiter, "\n\nExternal Memory");
- ext_mem_cnt = ha->fw_memory_size - 0x100000 + 1;
- for (cnt = 0; cnt < ext_mem_cnt; cnt++) {
- if (cnt % 8 == 0) {
- qla_uprintf(&uiter, "\n%08x: ", cnt + 0x100000);
- }
- qla_uprintf(&uiter, "%08x ", fw->ext_mem[cnt]);
- }
-
- qla_uprintf(&uiter, "\n[<==END] ISP Debug Dump");
-}
-
-
/****************************************************************************/
/* Driver Debug Functions. */
/****************************************************************************/
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index ab6afeaa2f2..533425338e0 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -37,134 +37,86 @@
/*
* Macros use for debugging the driver.
*/
-#undef ENTER_TRACE
-#if defined(ENTER_TRACE)
-#define ENTER(x) do { printk("qla2100 : Entering %s()\n", x); } while (0)
-#define LEAVE(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0)
-#define ENTER_INTR(x) do { printk("qla2100 : Entering %s()\n", x); } while (0)
-#define LEAVE_INTR(x) do { printk("qla2100 : Leaving %s()\n", x); } while (0)
-#else
-#define ENTER(x) do {} while (0)
-#define LEAVE(x) do {} while (0)
-#define ENTER_INTR(x) do {} while (0)
-#define LEAVE_INTR(x) do {} while (0)
-#endif
-#if DEBUG_QLA2100
-#define DEBUG(x) do {x;} while (0);
-#else
-#define DEBUG(x) do {} while (0);
-#endif
+#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_1)
-#define DEBUG1(x) do {x;} while (0);
+#define DEBUG1(x) do {x;} while (0)
#else
-#define DEBUG1(x) do {} while (0);
+#define DEBUG1(x) do {} while (0)
#endif
-#if defined(QL_DEBUG_LEVEL_2)
-#define DEBUG2(x) do {x;} while (0);
-#define DEBUG2_3(x) do {x;} while (0);
-#define DEBUG2_3_11(x) do {x;} while (0);
-#define DEBUG2_9_10(x) do {x;} while (0);
-#define DEBUG2_11(x) do {x;} while (0);
-#define DEBUG2_13(x) do {x;} while (0);
-#else
-#define DEBUG2(x) do {} while (0);
-#endif
+#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_3)
-#define DEBUG3(x) do {x;} while (0);
-#define DEBUG2_3(x) do {x;} while (0);
-#define DEBUG2_3_11(x) do {x;} while (0);
-#define DEBUG3_11(x) do {x;} while (0);
+#define DEBUG3(x) do {x;} while (0)
+#define DEBUG3_11(x) do {x;} while (0)
#else
-#define DEBUG3(x) do {} while (0);
- #if !defined(QL_DEBUG_LEVEL_2)
- #define DEBUG2_3(x) do {} while (0);
- #endif
+#define DEBUG3(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_4)
-#define DEBUG4(x) do {x;} while (0);
+#define DEBUG4(x) do {x;} while (0)
#else
-#define DEBUG4(x) do {} while (0);
+#define DEBUG4(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_5)
-#define DEBUG5(x) do {x;} while (0);
+#define DEBUG5(x) do {x;} while (0)
#else
-#define DEBUG5(x) do {} while (0);
+#define DEBUG5(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_7)
-#define DEBUG7(x) do {x;} while (0);
+#define DEBUG7(x) do {x;} while (0)
#else
-#define DEBUG7(x) do {} while (0);
+#define DEBUG7(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_9)
-#define DEBUG9(x) do {x;} while (0);
-#define DEBUG9_10(x) do {x;} while (0);
-#define DEBUG2_9_10(x) do {x;} while (0);
+#define DEBUG9(x) do {x;} while (0)
+#define DEBUG9_10(x) do {x;} while (0)
#else
-#define DEBUG9(x) do {} while (0);
+#define DEBUG9(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_10)
-#define DEBUG10(x) do {x;} while (0);
-#define DEBUG2_9_10(x) do {x;} while (0);
-#define DEBUG9_10(x) do {x;} while (0);
+#define DEBUG10(x) do {x;} while (0)
+#define DEBUG9_10(x) do {x;} while (0)
#else
-#define DEBUG10(x) do {} while (0);
- #if !defined(DEBUG2_9_10)
- #define DEBUG2_9_10(x) do {} while (0);
- #endif
+#define DEBUG10(x) do {} while (0)
#if !defined(DEBUG9_10)
- #define DEBUG9_10(x) do {} while (0);
+ #define DEBUG9_10(x) do {} while (0)
#endif
#endif
#if defined(QL_DEBUG_LEVEL_11)
-#define DEBUG11(x) do{x;} while(0);
-#if !defined(DEBUG2_11)
-#define DEBUG2_11(x) do{x;} while(0);
-#endif
-#if !defined(DEBUG2_3_11)
-#define DEBUG2_3_11(x) do{x;} while(0);
-#endif
+#define DEBUG11(x) do{x;} while(0)
#if !defined(DEBUG3_11)
-#define DEBUG3_11(x) do{x;} while(0);
+#define DEBUG3_11(x) do{x;} while(0)
#endif
#else
-#define DEBUG11(x) do{} while(0);
- #if !defined(QL_DEBUG_LEVEL_2)
- #define DEBUG2_11(x) do{} while(0);
- #if !defined(QL_DEBUG_LEVEL_3)
- #define DEBUG2_3_11(x) do{} while(0);
- #endif
- #endif
+#define DEBUG11(x) do{} while(0)
#if !defined(QL_DEBUG_LEVEL_3)
- #define DEBUG3_11(x) do{} while(0);
+ #define DEBUG3_11(x) do{} while(0)
#endif
#endif
#if defined(QL_DEBUG_LEVEL_12)
-#define DEBUG12(x) do {x;} while (0);
+#define DEBUG12(x) do {x;} while (0)
#else
-#define DEBUG12(x) do {} while (0);
+#define DEBUG12(x) do {} while (0)
#endif
#if defined(QL_DEBUG_LEVEL_13)
#define DEBUG13(x) do {x;} while (0)
-#if !defined(DEBUG2_13)
-#define DEBUG2_13(x) do {x;} while(0)
-#endif
#else
#define DEBUG13(x) do {} while (0)
-#if !defined(QL_DEBUG_LEVEL_2)
-#define DEBUG2_13(x) do {} while(0)
-#endif
#endif
#if defined(QL_DEBUG_LEVEL_14)
@@ -176,9 +128,6 @@
/*
* Firmware Dump structure definition
*/
-#define FW_DUMP_SIZE_128K 0xBC000
-#define FW_DUMP_SIZE_512K 0x2FC000
-#define FW_DUMP_SIZE_1M 0x5FC000
struct qla2300_fw_dump {
uint16_t hccr;
@@ -224,8 +173,6 @@ struct qla2100_fw_dump {
uint16_t risc_ram[0xf000];
};
-#define FW_DUMP_SIZE_24XX 0x2B0000
-
struct qla24xx_fw_dump {
uint32_t host_status;
uint32_t host_reg[32];
@@ -257,3 +204,39 @@ struct qla24xx_fw_dump {
uint32_t code_ram[0x2000];
uint32_t ext_mem[1];
};
+
+#define EFT_NUM_BUFFERS 4
+#define EFT_BYTES_PER_BUFFER 0x4000
+#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS))
+
+struct qla2xxx_fw_dump {
+ uint8_t signature[4];
+ uint32_t version;
+
+ uint32_t fw_major_version;
+ uint32_t fw_minor_version;
+ uint32_t fw_subminor_version;
+ uint32_t fw_attributes;
+
+ uint32_t vendor;
+ uint32_t device;
+ uint32_t subsystem_vendor;
+ uint32_t subsystem_device;
+
+ uint32_t fixed_size;
+ uint32_t mem_size;
+ uint32_t req_q_size;
+ uint32_t rsp_q_size;
+
+ uint32_t eft_size;
+ uint32_t eft_addr_l;
+ uint32_t eft_addr_h;
+
+ uint32_t header_size;
+
+ union {
+ struct qla2100_fw_dump isp21;
+ struct qla2300_fw_dump isp23;
+ struct qla24xx_fw_dump isp24;
+ } isp;
+};
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index d6f6579cfd2..0930260aec2 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -487,6 +487,7 @@ typedef struct {
#define MBA_IP_RCV_BUFFER_EMPTY 0x8026 /* IP receive buffer queue empty. */
#define MBA_IP_HDR_DATA_SPLIT 0x8027 /* IP header/data splitting feature */
/* used. */
+#define MBA_TRACE_NOTIFICATION 0x8028 /* Trace/Diagnostic notification. */
#define MBA_POINT_TO_POINT 0x8030 /* Point to point mode. */
#define MBA_CMPLT_1_16BIT 0x8031 /* Completion 1 16bit IOSB. */
#define MBA_CMPLT_2_16BIT 0x8032 /* Completion 2 16bit IOSB. */
@@ -608,7 +609,9 @@ typedef struct {
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
#define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */
+#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */
#define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */
+#define MBC_READ_SFP 0x31 /* Read SFP Data. */
#define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */
#define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */
#define MBC_MID_GET_VP_DATABASE 0x49 /* MID Get VP Database. */
@@ -618,6 +621,9 @@ typedef struct {
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
+#define TC_ENABLE 4
+#define TC_DISABLE 5
+
/* Firmware return data sizes */
#define FCAL_MAP_SIZE 128
@@ -1997,7 +2003,6 @@ struct isp_operations {
uint32_t);
void (*fw_dump) (struct scsi_qla_host *, int);
- void (*ascii_fw_dump) (struct scsi_qla_host *);
int (*beacon_on) (struct scsi_qla_host *);
int (*beacon_off) (struct scsi_qla_host *);
@@ -2041,6 +2046,7 @@ typedef struct scsi_qla_host {
uint32_t enable_led_scheme :1;
uint32_t msi_enabled :1;
uint32_t msix_enabled :1;
+ uint32_t disable_serdes :1;
} flags;
atomic_t loop_state;
@@ -2134,7 +2140,7 @@ typedef struct scsi_qla_host {
mempool_t *srb_mempool;
/* This spinlock is used to protect "io transactions", you must
- * aquire it before doing any IO to the card, eg with RD_REG*() and
+ * acquire it before doing any IO to the card, eg with RD_REG*() and
* WRT_REG*() for the duration of your entire commandtransaction.
*
* This spinlock is of lower priority than the io request lock.
@@ -2238,6 +2244,11 @@ typedef struct scsi_qla_host {
struct sns_cmd_pkt *sns_cmd;
dma_addr_t sns_cmd_dma;
+#define SFP_DEV_SIZE 256
+#define SFP_BLOCK_SIZE 64
+ void *sfp_data;
+ dma_addr_t sfp_data_dma;
+
struct task_struct *dpc_thread;
uint8_t dpc_active; /* DPC routine is active */
@@ -2303,11 +2314,12 @@ typedef struct scsi_qla_host {
uint16_t fw_seriallink_options24[4];
/* Firmware dump information. */
- void *fw_dump;
+ struct qla2xxx_fw_dump *fw_dump;
+ uint32_t fw_dump_len;
int fw_dumped;
int fw_dump_reading;
- char *fw_dump_buffer;
- int fw_dump_buffer_len;
+ dma_addr_t eft_dma;
+ void *eft;
uint8_t host_str[16];
uint32_t pci_attr;
diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h
index a8fc0ffc7fc..dd435410dfa 100644
--- a/drivers/scsi/qla2xxx/qla_devtbl.h
+++ b/drivers/scsi/qla2xxx/qla_devtbl.h
@@ -1,4 +1,4 @@
-#define QLA_MODEL_NAMES 0x4A
+#define QLA_MODEL_NAMES 0x57
/*
* Adapter model names and descriptions.
@@ -76,6 +76,19 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = {
"QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */
"QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */
"QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */
- " ", " ", /* 0x148 */
+ "HP AE369A", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x148 */
"QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */
+ " ", " ", /* 0x14a */
+ " ", " ", /* 0x14b */
+ "QMC2432M", "IBM eServer BC 4Gb FC Expansion Card CFFE", /* 0x14c */
+ "QMC2422M", "IBM eServer BC 4Gb FC Expansion Card CFFX", /* 0x14d */
+ "QLE220", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x14e */
+ " ", " ", /* 0x14f */
+ " ", " ", /* 0x150 */
+ " ", " ", /* 0x151 */
+ "QME2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x152 */
+ "QMH2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x153 */
+ " ", " ", /* 0x154 */
+ "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */
+ "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */
};
diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h
index 3af478663be..a0a722cf423 100644
--- a/drivers/scsi/qla2xxx/qla_fw.h
+++ b/drivers/scsi/qla2xxx/qla_fw.h
@@ -141,7 +141,7 @@ struct nvram_24xx {
* BIT 2 = Enable Memory Map BIOS
* BIT 3 = Enable Selectable Boot
* BIT 4 = Disable RISC code load
- * BIT 5 =
+ * BIT 5 = Disable Serdes
* BIT 6 =
* BIT 7 =
*
@@ -278,7 +278,7 @@ struct init_cb_24xx {
uint16_t response_q_length;
uint16_t request_q_length;
- uint16_t link_down_timeout; /* Milliseconds. */
+ uint16_t link_down_on_nos; /* Milliseconds. */
uint16_t prio_request_q_length;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 164d53ccbfd..8311ac2b93a 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -31,13 +31,9 @@ extern void qla2x00_update_fw_options(struct scsi_qla_host *);
extern void qla24xx_update_fw_options(scsi_qla_host_t *);
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
-extern int qla24xx_load_risc_flash(scsi_qla_host_t *, uint32_t *);
-
-extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t);
extern int qla2x00_loop_resync(scsi_qla_host_t *);
-extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
@@ -51,6 +47,8 @@ extern int qla2x00_abort_isp(scsi_qla_host_t *);
extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
extern void qla2x00_reg_remote_port(scsi_qla_host_t *, fc_port_t *);
+extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
+
/*
* Global Data in qla_os.c source file.
*/
@@ -61,6 +59,8 @@ extern int qlport_down_retry;
extern int ql2xplogiabsentdevice;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
+extern int ql2xallocfwdump;
+extern int extended_error_logging;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -80,8 +80,6 @@ extern void qla2xxx_wake_dpc(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_iocb.c source file.
*/
-extern void qla2x00_isp_cmd(scsi_qla_host_t *);
-
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
@@ -204,6 +202,12 @@ qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
extern int
qla2x00_stop_firmware(scsi_qla_host_t *);
+extern int
+qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
+
+extern int
+qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
@@ -254,9 +258,6 @@ extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *,
extern void qla2100_fw_dump(scsi_qla_host_t *, int);
extern void qla2300_fw_dump(scsi_qla_host_t *, int);
extern void qla24xx_fw_dump(scsi_qla_host_t *, int);
-extern void qla2100_ascii_fw_dump(scsi_qla_host_t *);
-extern void qla2300_ascii_fw_dump(scsi_qla_host_t *);
-extern void qla24xx_ascii_fw_dump(scsi_qla_host_t *);
extern void qla2x00_dump_regs(scsi_qla_host_t *);
extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
@@ -280,13 +281,6 @@ extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
/*
- * Global Function Prototypes in qla_xioctl.c source file.
- */
-#define qla2x00_enqueue_aen(ha, cmd, mode) do { } while (0)
-#define qla2x00_alloc_ioctl_mem(ha) (0)
-#define qla2x00_free_ioctl_mem(ha) do { } while (0)
-
-/*
* Global Function Prototypes in qla_attr.c source file.
*/
struct class_device_attribute;
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index aef093db597..859649160ca 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -39,6 +39,8 @@ static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
static int qla2x00_restart_isp(scsi_qla_host_t *);
+static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev);
+
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
@@ -89,6 +91,17 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha)
ha->isp_ops.nvram_config(ha);
+ if (ha->flags.disable_serdes) {
+ /* Mask HBA via NVRAM settings? */
+ qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
+ "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
+ ha->port_name[0], ha->port_name[1],
+ ha->port_name[2], ha->port_name[3],
+ ha->port_name[4], ha->port_name[5],
+ ha->port_name[6], ha->port_name[7]);
+ return QLA_FUNCTION_FAILED;
+ }
+
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
retry = 10;
@@ -770,29 +783,104 @@ qla24xx_chip_diag(scsi_qla_host_t *ha)
return rval;
}
-static void
+void
qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
{
- uint32_t dump_size = 0;
+ int rval;
+ uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
+ eft_size;
+ dma_addr_t eft_dma;
+ void *eft;
+
+ if (ha->fw_dump) {
+ qla_printk(KERN_WARNING, ha,
+ "Firmware dump previously allocated.\n");
+ return;
+ }
ha->fw_dumped = 0;
+ fixed_size = mem_size = eft_size = 0;
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
- dump_size = sizeof(struct qla2100_fw_dump);
+ fixed_size = sizeof(struct qla2100_fw_dump);
} else if (IS_QLA23XX(ha)) {
- dump_size = sizeof(struct qla2300_fw_dump);
- dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t);
- } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
- dump_size = sizeof(struct qla24xx_fw_dump);
- dump_size += (ha->fw_memory_size - 0x100000) * sizeof(uint32_t);
+ fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
+ mem_size = (ha->fw_memory_size - 0x11000 + 1) *
+ sizeof(uint16_t);
+ } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
+ mem_size = (ha->fw_memory_size - 0x100000 + 1) *
+ sizeof(uint32_t);
+
+ /* Allocate memory for Extended Trace Buffer. */
+ eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
+ GFP_KERNEL);
+ if (!eft) {
+ qla_printk(KERN_WARNING, ha, "Unable to allocate "
+ "(%d KB) for EFT.\n", EFT_SIZE / 1024);
+ goto cont_alloc;
+ }
+
+ rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
+ EFT_NUM_BUFFERS);
+ if (rval) {
+ qla_printk(KERN_WARNING, ha, "Unable to initialize "
+ "EFT (%d).\n", rval);
+ dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
+ eft_dma);
+ goto cont_alloc;
+ }
+
+ qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
+ EFT_SIZE / 1024);
+
+ eft_size = EFT_SIZE;
+ memset(eft, 0, eft_size);
+ ha->eft_dma = eft_dma;
+ ha->eft = eft;
}
+cont_alloc:
+ req_q_size = ha->request_q_length * sizeof(request_t);
+ rsp_q_size = ha->response_q_length * sizeof(response_t);
+
+ dump_size = offsetof(struct qla2xxx_fw_dump, isp);
+ dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
+ eft_size;
ha->fw_dump = vmalloc(dump_size);
- if (ha->fw_dump)
- qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware "
- "dump...\n", dump_size / 1024);
- else
+ if (!ha->fw_dump) {
qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
"firmware dump!!!\n", dump_size / 1024);
+
+ if (ha->eft) {
+ dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
+ ha->eft_dma);
+ ha->eft = NULL;
+ ha->eft_dma = 0;
+ }
+ return;
+ }
+
+ qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
+ dump_size / 1024);
+
+ ha->fw_dump_len = dump_size;
+ ha->fw_dump->signature[0] = 'Q';
+ ha->fw_dump->signature[1] = 'L';
+ ha->fw_dump->signature[2] = 'G';
+ ha->fw_dump->signature[3] = 'C';
+ ha->fw_dump->version = __constant_htonl(1);
+
+ ha->fw_dump->fixed_size = htonl(fixed_size);
+ ha->fw_dump->mem_size = htonl(mem_size);
+ ha->fw_dump->req_q_size = htonl(req_q_size);
+ ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
+
+ ha->fw_dump->eft_size = htonl(eft_size);
+ ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
+ ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
+
+ ha->fw_dump->header_size =
+ htonl(offsetof(struct qla2xxx_fw_dump, isp));
}
/**
@@ -810,8 +898,6 @@ qla2x00_resize_request_q(scsi_qla_host_t *ha)
dma_addr_t request_dma;
request_t *request_ring;
- qla2x00_alloc_fw_dump(ha);
-
/* Valid only on recent ISPs. */
if (IS_QLA2100(ha) || IS_QLA2200(ha))
return;
@@ -883,6 +969,9 @@ qla2x00_setup_chip(scsi_qla_host_t *ha)
&ha->fw_subminor_version,
&ha->fw_attributes, &ha->fw_memory_size);
qla2x00_resize_request_q(ha);
+
+ if (ql2xallocfwdump)
+ qla2x00_alloc_fw_dump(ha);
}
} else {
DEBUG2(printk(KERN_INFO
@@ -1186,8 +1275,7 @@ qla2x00_fw_ready(scsi_qla_host_t *ha)
rval = QLA_FUNCTION_FAILED;
if (atomic_read(&ha->loop_down_timer) &&
- (fw_state >= FSTATE_LOSS_OF_SYNC ||
- fw_state == FSTATE_WAIT_AL_PA)) {
+ fw_state != FSTATE_READY) {
/* Loop down. Timeout on min_wait for states
* other than Wait for Login.
*/
@@ -1555,6 +1643,8 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
/*
* Set host adapter parameters.
*/
+ if (nv->host_p[0] & BIT_7)
+ extended_error_logging = 1;
ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
/* Always load RISC code on non ISP2[12]00 chips. */
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
@@ -1563,6 +1653,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
+ ha->flags.disable_serdes = 0;
ha->operating_mode =
(icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -1701,7 +1792,7 @@ qla2x00_rport_del(void *data)
*
* Returns a pointer to the allocated fcport, or NULL, if none available.
*/
-fc_port_t *
+static fc_port_t *
qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
{
fc_port_t *fcport;
@@ -2258,8 +2349,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
}
/* Remove device from the new list and add it to DB */
- list_del(&fcport->list);
- list_add_tail(&fcport->list, &ha->fcports);
+ list_move_tail(&fcport->list, &ha->fcports);
/* Login and update database */
qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
@@ -2498,7 +2588,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
* Context:
* Kernel context.
*/
-int
+static int
qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
{
int rval;
@@ -2973,6 +3063,7 @@ qla2x00_update_fcports(scsi_qla_host_t *ha)
int
qla2x00_abort_isp(scsi_qla_host_t *ha)
{
+ int rval;
unsigned long flags = 0;
uint16_t cnt;
srb_t *sp;
@@ -3029,6 +3120,16 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->isp_abort_cnt = 0;
clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+
+ if (ha->eft) {
+ rval = qla2x00_trace_control(ha, TC_ENABLE,
+ ha->eft_dma, EFT_NUM_BUFFERS);
+ if (rval) {
+ qla_printk(KERN_WARNING, ha,
+ "Unable to reinitialize EFT "
+ "(%d).\n", rval);
+ }
+ }
} else { /* failed the ISP abort */
ha->flags.online = 1;
if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
@@ -3049,14 +3150,14 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
ha->isp_abort_cnt--;
DEBUG(printk("qla%ld: ISP abort - "
"retry remaining %d\n",
- ha->host_no, ha->isp_abort_cnt);)
+ ha->host_no, ha->isp_abort_cnt));
status = 1;
}
} else {
ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
DEBUG(printk("qla2x00(%ld): ISP error recovery "
"- retrying (%d) more times\n",
- ha->host_no, ha->isp_abort_cnt);)
+ ha->host_no, ha->isp_abort_cnt));
set_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
status = 1;
}
@@ -3070,7 +3171,7 @@ qla2x00_abort_isp(scsi_qla_host_t *ha)
} else {
DEBUG(printk(KERN_INFO
"qla2x00_abort_isp(%ld): exiting.\n",
- ha->host_no);)
+ ha->host_no));
}
return(status);
@@ -3146,7 +3247,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
if (!(status = qla2x00_fw_ready(ha))) {
DEBUG(printk("%s(): Start configure loop, "
- "status = %d\n", __func__, status);)
+ "status = %d\n", __func__, status));
/* Issue a marker after FW becomes ready. */
qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
@@ -3170,7 +3271,7 @@ qla2x00_restart_isp(scsi_qla_host_t *ha)
DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
__func__,
- status);)
+ status));
}
return (status);
}
@@ -3290,7 +3391,6 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
nv->node_name[6] = 0x55;
nv->node_name[7] = 0x86;
nv->login_retry_count = __constant_cpu_to_le16(8);
- nv->link_down_timeout = __constant_cpu_to_le16(200);
nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
nv->login_timeout = __constant_cpu_to_le16(0);
nv->firmware_options_1 =
@@ -3319,7 +3419,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
*dptr1++ = *dptr2++;
icb->login_retry_count = nv->login_retry_count;
- icb->link_down_timeout = nv->link_down_timeout;
+ icb->link_down_on_nos = nv->link_down_on_nos;
/* Copy 2nd segment. */
dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
@@ -3374,6 +3474,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
ha->flags.enable_lip_full_login = 1;
ha->flags.enable_target_reset = 1;
ha->flags.enable_led_scheme = 0;
+ ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
(BIT_6 | BIT_5 | BIT_4)) >> 4;
@@ -3473,7 +3574,7 @@ qla24xx_nvram_config(scsi_qla_host_t *ha)
return (rval);
}
-int
+static int
qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
{
int rval;
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 8c769cfaa14..c5b3c610a32 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -15,6 +15,7 @@ static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd);
static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *);
static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *);
static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha);
+static void qla2x00_isp_cmd(scsi_qla_host_t *ha);
/**
* qla2x00_get_cmd_direction() - Determine control_flag data direction.
@@ -470,6 +471,7 @@ __qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
mrk24->nport_handle = cpu_to_le16(loop_id);
mrk24->lun[1] = LSB(lun);
mrk24->lun[2] = MSB(lun);
+ host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun));
} else {
SET_TARGET_ID(ha, mrk->target, loop_id);
mrk->lun = cpu_to_le16(lun);
@@ -574,7 +576,7 @@ qla2x00_req_pkt(scsi_qla_host_t *ha)
*
* Note: The caller must hold the hardware lock before calling this routine.
*/
-void
+static void
qla2x00_isp_cmd(scsi_qla_host_t *ha)
{
device_reg_t __iomem *reg = ha->iobase;
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index b28ac0a27e2..de0613135f7 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -395,10 +395,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
ha->flags.management_server_logged_in = 0;
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL);
-
break;
case MBA_LOOP_UP: /* Loop Up Event */
@@ -418,9 +414,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
link_speed);
ha->flags.management_server_logged_in = 0;
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL);
break;
case MBA_LOOP_DOWN: /* Loop Down Event */
@@ -439,9 +432,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->link_data_rate = LDR_UNKNOWN;
if (ql2xfdmienable)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL);
break;
case MBA_LIP_RESET: /* LIP reset occurred */
@@ -460,10 +450,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
ha->operating_mode = LOOP;
ha->flags.management_server_logged_in = 0;
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL);
-
break;
case MBA_POINT_TO_POINT: /* Point-to-Point */
@@ -545,9 +531,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL);
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
@@ -584,9 +567,6 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
set_bit(RSCN_UPDATE, &ha->dpc_flags);
-
- /* Update AEN queue. */
- qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]);
break;
/* case MBA_RIO_RESPONSE: */
@@ -607,6 +587,11 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
"%04x.\n", ha->host_no, mb[1], mb[2], mb[3]));
break;
+
+ case MBA_TRACE_NOTIFICATION:
+ DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
+ ha->host_no, mb[1], mb[2]));
+ break;
}
}
@@ -1452,8 +1437,8 @@ qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt)
DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
__func__, ha->host_no, pkt, pkt->handle));
- DEBUG9(printk("%s: ct pkt dump:\n", __func__);)
- DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx));)
+ DEBUG9(printk("%s: ct pkt dump:\n", __func__));
+ DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx)));
/* Validate handle. */
if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index d6cb3bd1a29..879f281e2ea 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -13,13 +13,13 @@ qla2x00_mbx_sem_timeout(unsigned long data)
{
struct semaphore *sem_ptr = (struct semaphore *)data;
- DEBUG11(printk("qla2x00_sem_timeout: entered.\n");)
+ DEBUG11(printk("qla2x00_sem_timeout: entered.\n"));
if (sem_ptr != NULL) {
up(sem_ptr);
}
- DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");)
+ DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n"));
}
/*
@@ -61,7 +61,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
rval = QLA_SUCCESS;
abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
/*
* Wait for active mailbox commands to finish by waiting at most tov
@@ -72,7 +72,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
/* Timeout occurred. Return error. */
DEBUG2_3_11(printk("%s(%ld): cmd access timeout. "
- "Exiting.\n", __func__, ha->host_no);)
+ "Exiting.\n", __func__, ha->host_no));
return QLA_FUNCTION_TIMEOUT;
}
}
@@ -86,7 +86,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
DEBUG11(printk("scsi(%ld): prepare to issue mbox cmd=0x%x.\n",
- ha->host_no, mcp->mb[0]);)
+ ha->host_no, mcp->mb[0]));
spin_lock_irqsave(&ha->hardware_lock, flags);
@@ -131,14 +131,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
/* Unlock mbx registers and wait for interrupt */
DEBUG11(printk("%s(%ld): going to unlock irq & waiting for interrupt. "
- "jiffies=%lx.\n", __func__, ha->host_no, jiffies);)
+ "jiffies=%lx.\n", __func__, ha->host_no, jiffies));
/* Wait for mbx cmd completion until timeout */
if (!abort_active && io_lock_on) {
/* sleep on completion semaphore */
DEBUG11(printk("%s(%ld): INTERRUPT MODE. Initializing timer.\n",
- __func__, ha->host_no);)
+ __func__, ha->host_no));
init_timer(&tmp_intr_timer);
tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
@@ -147,11 +147,11 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
(void (*)(unsigned long))qla2x00_mbx_sem_timeout;
DEBUG11(printk("%s(%ld): Adding timer.\n", __func__,
- ha->host_no);)
+ ha->host_no));
add_timer(&tmp_intr_timer);
DEBUG11(printk("%s(%ld): going to unlock & sleep. "
- "time=0x%lx.\n", __func__, ha->host_no, jiffies);)
+ "time=0x%lx.\n", __func__, ha->host_no, jiffies));
set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
@@ -170,14 +170,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
down(&ha->mbx_intr_sem);
DEBUG11(printk("%s(%ld): waking up. time=0x%lx\n", __func__,
- ha->host_no, jiffies);)
+ ha->host_no, jiffies));
clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
/* delete the timer */
del_timer(&tmp_intr_timer);
} else {
DEBUG3_11(printk("%s(%ld): cmd=%x POLLING MODE.\n", __func__,
- ha->host_no, command);)
+ ha->host_no, command));
if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_SET_HOST_INT);
@@ -209,7 +209,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
uint16_t *iptr2;
DEBUG3_11(printk("%s(%ld): cmd %x completed.\n", __func__,
- ha->host_no, command);)
+ ha->host_no, command));
/* Got interrupt. Clear the flag. */
ha->flags.mbox_int = 0;
@@ -266,7 +266,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (!abort_active) {
DEBUG11(printk("%s(%ld): checking for additional resp "
- "interrupt.\n", __func__, ha->host_no);)
+ "interrupt.\n", __func__, ha->host_no));
/* polling mode for non isp_abort commands. */
qla2x00_poll(ha);
@@ -277,9 +277,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (!io_lock_on || (mcp->flags & IOCTL_CMD)) {
/* not in dpc. schedule it for dpc to take over. */
DEBUG(printk("%s(%ld): timeout schedule "
- "isp_abort_needed.\n", __func__, ha->host_no);)
+ "isp_abort_needed.\n", __func__, ha->host_no));
DEBUG2_3_11(printk("%s(%ld): timeout schedule "
- "isp_abort_needed.\n", __func__, ha->host_no);)
+ "isp_abort_needed.\n", __func__, ha->host_no));
qla_printk(KERN_WARNING, ha,
"Mailbox command timeout occured. Scheduling ISP "
"abort.\n");
@@ -288,9 +288,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
} else if (!abort_active) {
/* call abort directly since we are in the DPC thread */
DEBUG(printk("%s(%ld): timeout calling abort_isp\n",
- __func__, ha->host_no);)
+ __func__, ha->host_no));
DEBUG2_3_11(printk("%s(%ld): timeout calling "
- "abort_isp\n", __func__, ha->host_no);)
+ "abort_isp\n", __func__, ha->host_no));
qla_printk(KERN_WARNING, ha,
"Mailbox command timeout occured. Issuing ISP "
"abort.\n");
@@ -303,9 +303,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
}
clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
DEBUG(printk("%s(%ld): finished abort_isp\n", __func__,
- ha->host_no);)
+ ha->host_no));
DEBUG2_3_11(printk("%s(%ld): finished abort_isp\n",
- __func__, ha->host_no);)
+ __func__, ha->host_no));
}
}
@@ -316,9 +316,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
if (rval) {
DEBUG2_3_11(printk("%s(%ld): **** FAILED. mbx0=%x, mbx1=%x, "
"mbx2=%x, cmd=%x ****\n", __func__, ha->host_no,
- mcp->mb[0], mcp->mb[1], mcp->mb[2], command);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[2], command));
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
@@ -394,7 +394,7 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
mcp->out_mb = MBX_0;
@@ -424,10 +424,10 @@ qla2x00_execute_fw(scsi_qla_host_t *ha, uint32_t risc_addr)
} else {
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
DEBUG11(printk("%s(%ld): done exchanges=%x.\n",
- __func__, ha->host_no, mcp->mb[1]);)
+ __func__, ha->host_no, mcp->mb[1]));
} else {
DEBUG11(printk("%s(%ld): done.\n", __func__,
- ha->host_no);)
+ ha->host_no));
}
}
@@ -611,7 +611,7 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no));
mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
mcp->mb[1] = 0xAAAA;
@@ -639,11 +639,11 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *ha)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -671,7 +671,7 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_VERIFY_CHECKSUM;
mcp->out_mb = MBX_0;
@@ -694,9 +694,9 @@ qla2x00_verify_checksum(scsi_qla_host_t *ha, uint32_t risc_addr)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed=%x chk sum=%x.\n", __func__,
ha->host_no, rval, (IS_QLA24XX(ha) || IS_QLA54XX(ha) ?
- (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1]));)
+ (mcp->mb[2] << 16) | mcp->mb[1]: mcp->mb[1])));
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
@@ -743,9 +743,9 @@ qla2x00_issue_iocb(scsi_qla_host_t *ha, void* buffer, dma_addr_t phys_addr,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
sts_entry_t *sts_entry = (sts_entry_t *) buffer;
@@ -781,7 +781,7 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no));
fcport = sp->fcport;
@@ -813,11 +813,11 @@ qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
sp->flags |= SRB_ABORT_PENDING;
DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -848,7 +848,7 @@ qla2x00_abort_target(fc_port_t *fcport)
if (fcport == NULL)
return 0;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
mcp->mb[0] = MBC_ABORT_TARGET;
@@ -872,11 +872,11 @@ qla2x00_abort_target(fc_port_t *fcport)
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_abort_target(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -912,7 +912,7 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
mcp->out_mb = MBX_0;
@@ -933,11 +933,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -968,7 +968,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_RETRY_COUNT;
mcp->out_mb = MBX_0;
@@ -980,7 +980,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n",
- ha->host_no, mcp->mb[0]);)
+ ha->host_no, mcp->mb[0]));
} else {
/* Convert returned data and check our values. */
*r_a_tov = mcp->mb[3] / 2;
@@ -992,7 +992,7 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
}
DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d "
- "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);)
+ "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov));
}
return rval;
@@ -1023,7 +1023,7 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
mcp->mb[2] = MSW(ha->init_cb_dma);
@@ -1043,11 +1043,11 @@ qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x "
"mb0=%x.\n",
- ha->host_no, rval, mcp->mb[0]);)
+ ha->host_no, rval, mcp->mb[0]));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1079,7 +1079,7 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
struct port_database_24xx *pd24;
dma_addr_t pd_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
pd24 = NULL;
pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma);
@@ -1220,7 +1220,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
mcp->out_mb = MBX_0;
@@ -1235,11 +1235,11 @@ qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): "
- "failed=%x.\n", ha->host_no, rval);)
+ "failed=%x.\n", ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1272,7 +1272,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_GET_PORT_NAME;
mcp->out_mb = MBX_1|MBX_0;
@@ -1292,7 +1292,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
if (name != NULL) {
/* This function returns name in big endian. */
@@ -1307,7 +1307,7 @@ qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
}
DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1335,7 +1335,7 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
@@ -1364,10 +1364,10 @@ qla2x00_lip_reset(scsi_qla_host_t *ha)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n",
- __func__, ha->host_no, rval);)
+ __func__, ha->host_no, rval));
} else {
/*EMPTY*/
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return rval;
@@ -1400,10 +1400,10 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total "
- "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);)
+ "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov));
mcp->mb[0] = MBC_SEND_SNS_COMMAND;
mcp->mb[1] = cmd_size;
@@ -1421,12 +1421,12 @@ qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
- "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);)
+ "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
- "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);)
+ "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
} else {
/*EMPTY*/
- DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no));
}
return rval;
@@ -1442,7 +1442,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
dma_addr_t lg_dma;
uint32_t iop[2];
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
if (lg == NULL) {
@@ -1458,13 +1458,15 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI);
if (opt & BIT_0)
lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI);
+ if (opt & BIT_1)
+ lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI);
lg->port_id[0] = al_pa;
lg->port_id[1] = area;
lg->port_id[2] = domain;
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Login IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
} else if (lg->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
@@ -1505,7 +1507,7 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
break;
}
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
iop[0] = le32_to_cpu(lg->io_parameter[0]);
@@ -1559,7 +1561,7 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
- DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);)
+ DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no));
mcp->mb[0] = MBC_LOGIN_FABRIC_PORT;
mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
@@ -1604,11 +1606,11 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x "
"mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval,
- mcp->mb[0], mcp->mb[1], mcp->mb[2]);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[2]));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1643,7 +1645,7 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport,
fcport->d_id.b.domain, fcport->d_id.b.area,
fcport->d_id.b.al_pa, mb_ret, opt);
- DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no));
mcp->mb[0] = MBC_LOGIN_LOOP_PORT;
if (HAS_EXTENDED_IDS(ha))
@@ -1677,13 +1679,13 @@ qla2x00_login_local_device(scsi_qla_host_t *ha, fc_port_t *fcport,
DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
"mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval,
- mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
"mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval,
- mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);)
+ mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]));
} else {
/*EMPTY*/
- DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
return (rval);
@@ -1697,7 +1699,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
struct logio_entry_24xx *lg;
dma_addr_t lg_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
if (lg == NULL) {
@@ -1718,7 +1720,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
rval = qla2x00_issue_iocb(ha, lg, lg_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Logout IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
} else if (lg->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
@@ -1729,10 +1731,10 @@ qla24xx_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
"-- completion status (%x) ioparam=%x/%x.\n", __func__,
ha->host_no, le16_to_cpu(lg->comp_status),
le32_to_cpu(lg->io_parameter[0]),
- le32_to_cpu(lg->io_parameter[1]));)
+ le32_to_cpu(lg->io_parameter[1])));
} else {
/*EMPTY*/
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
@@ -1765,7 +1767,7 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT;
mcp->out_mb = MBX_1|MBX_0;
@@ -1785,11 +1787,11 @@ qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x "
- "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);)
+ "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1818,7 +1820,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
mcp->mb[0] = MBC_LIP_FULL_LOGIN;
mcp->mb[1] = 0;
@@ -1833,11 +1835,11 @@ qla2x00_full_login_lip(scsi_qla_host_t *ha)
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
/*EMPTY*/
DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1864,7 +1866,7 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
mbx_cmd_t *mcp = &mc;
DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n",
- ha->host_no);)
+ ha->host_no));
if (id_list == NULL)
return QLA_FUNCTION_FAILED;
@@ -1893,11 +1895,11 @@ qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n",
- ha->host_no, rval);)
+ ha->host_no, rval));
} else {
*entries = mcp->mb[1];
DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n",
- ha->host_no);)
+ ha->host_no));
}
return rval;
@@ -1936,7 +1938,7 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
if (rval != QLA_SUCCESS) {
/*EMPTY*/
DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__,
- ha->host_no, mcp->mb[0]);)
+ ha->host_no, mcp->mb[0]));
} else {
DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
"mb7=%x mb10=%x.\n", __func__, ha->host_no,
@@ -2045,7 +2047,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
link_stat_t *stat_buf;
dma_addr_t stat_buf_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
stat_buf = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &stat_buf_dma);
if (stat_buf == NULL) {
@@ -2083,7 +2085,7 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
if (rval == QLA_SUCCESS) {
if (mcp->mb[0] != MBS_COMMAND_COMPLETE) {
DEBUG2_3_11(printk("%s(%ld): cmd failed. mbx0=%x.\n",
- __func__, ha->host_no, mcp->mb[0]);)
+ __func__, ha->host_no, mcp->mb[0]));
status[0] = mcp->mb[0];
rval = BIT_1;
} else {
@@ -2108,12 +2110,12 @@ qla2x00_get_link_status(scsi_qla_host_t *ha, uint16_t loop_id,
stat_buf->loss_sync_cnt, stat_buf->loss_sig_cnt,
stat_buf->prim_seq_err_cnt,
stat_buf->inval_xmit_word_cnt,
- stat_buf->inval_crc_cnt);)
+ stat_buf->inval_crc_cnt));
}
} else {
/* Failed. */
DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
- ha->host_no, rval);)
+ ha->host_no, rval));
rval = BIT_1;
}
@@ -2132,7 +2134,7 @@ qla24xx_get_isp_stats(scsi_qla_host_t *ha, uint32_t *dwbuf, uint32_t dwords,
uint32_t *sbuf, *siter;
dma_addr_t sbuf_dma;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
if (dwords > (DMA_POOL_SIZE / 4)) {
DEBUG2_3_11(printk("%s(%ld): Unabled to retrieve %d DWORDs "
@@ -2196,7 +2198,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
dma_addr_t abt_dma;
uint32_t handle;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
fcport = sp->fcport;
@@ -2229,7 +2231,7 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
rval = qla2x00_issue_iocb(ha, abt, abt_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue IOCB (%x).\n",
- __func__, ha->host_no, rval);)
+ __func__, ha->host_no, rval));
} else if (abt->entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- error status (%x).\n", __func__, ha->host_no,
@@ -2238,10 +2240,10 @@ qla24xx_abort_command(scsi_qla_host_t *ha, srb_t *sp)
} else if (abt->nport_handle != __constant_cpu_to_le16(0)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__, ha->host_no,
- le16_to_cpu(abt->nport_handle));)
+ le16_to_cpu(abt->nport_handle)));
rval = QLA_FUNCTION_FAILED;
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
sp->flags |= SRB_ABORT_PENDING;
}
@@ -2268,7 +2270,7 @@ qla24xx_abort_target(fc_port_t *fcport)
if (fcport == NULL)
return 0;
- DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no);)
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, fcport->ha->host_no));
ha = fcport->ha;
tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma);
@@ -2290,7 +2292,7 @@ qla24xx_abort_target(fc_port_t *fcport)
rval = qla2x00_issue_iocb(ha, tsk, tsk_dma, 0);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Target Reset IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
goto atarget_done;
} else if (tsk->p.sts.entry_status != 0) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
@@ -2302,7 +2304,7 @@ qla24xx_abort_target(fc_port_t *fcport)
__constant_cpu_to_le16(CS_COMPLETE)) {
DEBUG2_3_11(printk("%s(%ld): failed to complete IOCB "
"-- completion status (%x).\n", __func__,
- ha->host_no, le16_to_cpu(tsk->p.sts.comp_status));)
+ ha->host_no, le16_to_cpu(tsk->p.sts.comp_status)));
rval = QLA_FUNCTION_FAILED;
goto atarget_done;
}
@@ -2311,9 +2313,9 @@ qla24xx_abort_target(fc_port_t *fcport)
rval = qla2x00_marker(ha, fcport->loop_id, 0, MK_SYNC_ID);
if (rval != QLA_SUCCESS) {
DEBUG2_3_11(printk("%s(%ld): failed to issue Marker IOCB "
- "(%x).\n", __func__, ha->host_no, rval);)
+ "(%x).\n", __func__, ha->host_no, rval));
} else {
- DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
}
atarget_done:
@@ -2460,3 +2462,81 @@ qla2x00_stop_firmware(scsi_qla_host_t *ha)
return rval;
}
+
+int
+qla2x00_trace_control(scsi_qla_host_t *ha, uint16_t ctrl, dma_addr_t eft_dma,
+ uint16_t buffers)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_TRACE_CONTROL;
+ mcp->mb[1] = ctrl;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_1|MBX_0;
+ if (ctrl == TC_ENABLE) {
+ mcp->mb[2] = LSW(eft_dma);
+ mcp->mb[3] = MSW(eft_dma);
+ mcp->mb[4] = LSW(MSD(eft_dma));
+ mcp->mb[5] = MSW(MSD(eft_dma));
+ mcp->mb[6] = buffers;
+ mcp->mb[7] = buffers;
+ mcp->out_mb |= MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2;
+ }
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x.\n",
+ __func__, ha->host_no, rval, mcp->mb[0], mcp->mb[1]));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
+
+int
+qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
+ uint16_t off, uint16_t count)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_READ_SFP;
+ mcp->mb[1] = addr;
+ mcp->mb[2] = MSW(sfp_dma);
+ mcp->mb[3] = LSW(sfp_dma);
+ mcp->mb[6] = MSW(MSD(sfp_dma));
+ mcp->mb[7] = LSW(MSD(sfp_dma));
+ mcp->mb[8] = count;
+ mcp->mb[9] = off;
+ mcp->mb[10] = 0;
+ mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+ ha->host_no, rval, mcp->mb[0]));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index ccaad0b08d3..65cbe2f5eea 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -39,14 +39,14 @@ MODULE_PARM_DESC(ql2xlogintimeout,
int qlport_down_retry = 30;
module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(qlport_down_retry,
- "Maximum number of command retries to a port that returns"
+ "Maximum number of command retries to a port that returns "
"a PORT-DOWN status.");
int ql2xplogiabsentdevice;
module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xplogiabsentdevice,
"Option to enable PLOGI to devices that are not present after "
- "a Fabric scan. This is needed for several broken switches."
+ "a Fabric scan. This is needed for several broken switches. "
"Default is 0 - no PLOGI. 1 - perfom PLOGI.");
int ql2xloginretrycount = 0;
@@ -54,6 +54,19 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xloginretrycount,
"Specify an alternate value for the NVRAM login retry count.");
+int ql2xallocfwdump = 1;
+module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xallocfwdump,
+ "Option to enable allocation of memory for a firmware dump "
+ "during HBA initialization. Memory allocation requirements "
+ "vary by ISP type. Default is 1 - allocate memory.");
+
+int extended_error_logging;
+module_param(extended_error_logging, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(extended_error_logging,
+ "Option to enable extended error logging, "
+ "Default is 0 - no logging. 1 - log errors.");
+
static void qla2x00_free_device(scsi_qla_host_t *);
static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
@@ -624,7 +637,7 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n",
__func__, ha->host_no, sp, serial));
- DEBUG3(qla2x00_print_scsi_cmd(cmd);)
+ DEBUG3(qla2x00_print_scsi_cmd(cmd));
spin_unlock_irqrestore(&ha->hardware_lock, flags);
if (ha->isp_ops.abort_command(ha, sp)) {
@@ -731,7 +744,6 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
@@ -742,8 +754,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
@@ -766,7 +777,7 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
#endif
} else {
DEBUG2(printk(KERN_INFO
- "%s failed: loop not ready\n",__func__);)
+ "%s failed: loop not ready\n",__func__));
}
if (ret == FAILED) {
@@ -862,7 +873,6 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
@@ -873,8 +883,7 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
@@ -923,7 +932,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
scsi_qla_host_t *ha = to_qla_host(cmd->device->host);
fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
- srb_t *sp;
int ret;
unsigned int id, lun;
unsigned long serial;
@@ -934,8 +942,7 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
lun = cmd->device->lun;
serial = cmd->serial_number;
- sp = (srb_t *) CMD_SP(cmd);
- if (!sp || !fcport)
+ if (!fcport)
return ret;
qla_printk(KERN_INFO, ha,
@@ -1021,12 +1028,12 @@ qla2x00_loop_reset(scsi_qla_host_t *ha)
/* Empty */
DEBUG2_3(printk("%s(%ld): **** FAILED ****\n",
__func__,
- ha->host_no);)
+ ha->host_no));
} else {
/* Empty */
DEBUG3(printk("%s(%ld): exiting normally.\n",
__func__,
- ha->host_no);)
+ ha->host_no));
}
return(status);
@@ -1324,7 +1331,8 @@ qla24xx_disable_intrs(scsi_qla_host_t *ha)
/*
* PCI driver interface
*/
-static int qla2x00_probe_one(struct pci_dev *pdev)
+static int __devinit
+qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret = -ENODEV;
device_reg_t __iomem *reg;
@@ -1405,7 +1413,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
ha->isp_ops.read_nvram = qla2x00_read_nvram_data;
ha->isp_ops.write_nvram = qla2x00_write_nvram_data;
ha->isp_ops.fw_dump = qla2100_fw_dump;
- ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump;
ha->isp_ops.read_optrom = qla2x00_read_optrom_data;
ha->isp_ops.write_optrom = qla2x00_write_optrom_data;
if (IS_QLA2100(ha)) {
@@ -1432,7 +1439,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
ha->isp_ops.pci_config = qla2300_pci_config;
ha->isp_ops.intr_handler = qla2300_intr_handler;
ha->isp_ops.fw_dump = qla2300_fw_dump;
- ha->isp_ops.ascii_fw_dump = qla2300_ascii_fw_dump;
ha->isp_ops.beacon_on = qla2x00_beacon_on;
ha->isp_ops.beacon_off = qla2x00_beacon_off;
ha->isp_ops.beacon_blink = qla2x00_beacon_blink;
@@ -1469,7 +1475,6 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
ha->isp_ops.read_nvram = qla24xx_read_nvram_data;
ha->isp_ops.write_nvram = qla24xx_write_nvram_data;
ha->isp_ops.fw_dump = qla24xx_fw_dump;
- ha->isp_ops.ascii_fw_dump = qla24xx_ascii_fw_dump;
ha->isp_ops.read_optrom = qla24xx_read_optrom_data;
ha->isp_ops.write_optrom = qla24xx_write_optrom_data;
ha->isp_ops.beacon_on = qla24xx_beacon_on;
@@ -1541,7 +1546,7 @@ static int qla2x00_probe_one(struct pci_dev *pdev)
host->transportt = qla2xxx_transport_template;
ret = request_irq(pdev->irq, ha->isp_ops.intr_handler,
- SA_INTERRUPT|SA_SHIRQ, QLA2XXX_DRIVER_NAME, ha);
+ IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, ha);
if (ret) {
qla_printk(KERN_WARNING, ha,
"Failed to reserve interrupt %d already in use.\n",
@@ -1640,7 +1645,8 @@ probe_out:
return ret;
}
-static void qla2x00_remove_one(struct pci_dev *pdev)
+static void __devexit
+qla2x00_remove_one(struct pci_dev *pdev)
{
scsi_qla_host_t *ha;
@@ -1678,6 +1684,9 @@ qla2x00_free_device(scsi_qla_host_t *ha)
kthread_stop(t);
}
+ if (ha->eft)
+ qla2x00_trace_control(ha, TC_DISABLE, 0, 0);
+
/* Stop currently executing firmware. */
qla2x00_stop_firmware(ha);
@@ -1899,17 +1908,6 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
}
memset(ha->init_cb, 0, ha->init_cb_size);
- /* Allocate ioctl related memory. */
- if (qla2x00_alloc_ioctl_mem(ha)) {
- qla_printk(KERN_WARNING, ha,
- "Memory Allocation failed - ioctl_mem\n");
-
- qla2x00_mem_free(ha);
- msleep(100);
-
- continue;
- }
-
if (qla2x00_allocate_sp_pool(ha)) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - "
@@ -1972,6 +1970,26 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
continue;
}
memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
+
+ if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
+ /*
+ * Get consistent memory allocated for SFP
+ * block.
+ */
+ ha->sfp_data = dma_pool_alloc(ha->s_dma_pool,
+ GFP_KERNEL, &ha->sfp_data_dma);
+ if (ha->sfp_data == NULL) {
+ qla_printk(KERN_WARNING, ha,
+ "Memory Allocation failed - "
+ "sfp_data\n");
+
+ qla2x00_mem_free(ha);
+ msleep(100);
+
+ continue;
+ }
+ memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
+ }
}
/* Done all allocations without any error. */
@@ -2006,12 +2024,16 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
return;
}
- /* free ioctl memory */
- qla2x00_free_ioctl_mem(ha);
-
/* free sp pool */
qla2x00_free_sp_pool(ha);
+ if (ha->fw_dump) {
+ if (ha->eft)
+ dma_free_coherent(&ha->pdev->dev,
+ ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma);
+ vfree(ha->fw_dump);
+ }
+
if (ha->sns_cmd)
dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
ha->sns_cmd, ha->sns_cmd_dma);
@@ -2020,6 +2042,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
ha->ct_sns, ha->ct_sns_dma);
+ if (ha->sfp_data)
+ dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma);
+
if (ha->ms_iocb)
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
@@ -2043,6 +2068,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
(ha->request_q_length + 1) * sizeof(request_t),
ha->request_ring, ha->request_dma);
+ ha->eft = NULL;
+ ha->eft_dma = 0;
ha->sns_cmd = NULL;
ha->sns_cmd_dma = 0;
ha->ct_sns = NULL;
@@ -2071,13 +2098,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
}
INIT_LIST_HEAD(&ha->fcports);
- vfree(ha->fw_dump);
- vfree(ha->fw_dump_buffer);
-
ha->fw_dump = NULL;
ha->fw_dumped = 0;
ha->fw_dump_reading = 0;
- ha->fw_dump_buffer = NULL;
vfree(ha->optrom_buffer);
}
@@ -2215,9 +2238,6 @@ qla2x00_do_dpc(void *data)
next_loopid = 0;
list_for_each_entry(fcport, &ha->fcports, list) {
- if (fcport->port_type != FCT_TARGET)
- continue;
-
/*
* If the port is not ONLINE then try to login
* to it if we haven't run out of retries.
@@ -2617,40 +2637,16 @@ static struct pci_device_id qla2xxx_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
-static int __devinit
-qla2xxx_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- return qla2x00_probe_one(pdev);
-}
-
-static void __devexit
-qla2xxx_remove_one(struct pci_dev *pdev)
-{
- qla2x00_remove_one(pdev);
-}
-
static struct pci_driver qla2xxx_pci_driver = {
.name = QLA2XXX_DRIVER_NAME,
.driver = {
.owner = THIS_MODULE,
},
.id_table = qla2xxx_pci_tbl,
- .probe = qla2xxx_probe_one,
- .remove = __devexit_p(qla2xxx_remove_one),
+ .probe = qla2x00_probe_one,
+ .remove = __devexit_p(qla2x00_remove_one),
};
-static inline int
-qla2x00_pci_module_init(void)
-{
- return pci_module_init(&qla2xxx_pci_driver);
-}
-
-static inline void
-qla2x00_pci_module_exit(void)
-{
- pci_unregister_driver(&qla2xxx_pci_driver);
-}
-
/**
* qla2x00_module_init - Module initialization.
**/
@@ -2670,16 +2666,16 @@ qla2x00_module_init(void)
/* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
-#if DEBUG_QLA2100
- strcat(qla2x00_version_str, "-debug");
-#endif
+ if (extended_error_logging)
+ strcat(qla2x00_version_str, "-debug");
+
qla2xxx_transport_template =
fc_attach_transport(&qla2xxx_transport_functions);
if (!qla2xxx_transport_template)
return -ENODEV;
printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
- ret = qla2x00_pci_module_init();
+ ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
@@ -2693,7 +2689,7 @@ qla2x00_module_init(void)
static void __exit
qla2x00_module_exit(void)
{
- qla2x00_pci_module_exit();
+ pci_unregister_driver(&qla2xxx_pci_driver);
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
fc_release_transport(qla2xxx_transport_template);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 6b315521bd8..971259032ef 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,9 +7,9 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.05-k2"
+#define QLA2XXX_VERSION "8.01.07-k1"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
-#define QLA_DRIVER_PATCH_VER 5
+#define QLA_DRIVER_PATCH_VER 7
#define QLA_DRIVER_BETA_VER 0
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 2203103adce..5b2f0741a55 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -1,6 +1,6 @@
/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
*
- * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ * Copyright (C) 1996, 2006 David S. Miller (davem@davemloft.net)
*
* A lot of this driver was directly stolen from Erik H. Moe's PCI
* Qlogic ISP driver. Mucho kudos to him for this code.
@@ -46,8 +46,6 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_host.h>
-
-
#define MAX_TARGETS 16
#define MAX_LUNS 8 /* 32 for 1.31 F/W */
@@ -57,7 +55,6 @@
static struct qlogicpti *qptichain = NULL;
static DEFINE_SPINLOCK(qptichain_lock);
-static int qptis_running = 0;
#define PACKB(a, b) (((a)<<4)|(b))
@@ -721,7 +718,7 @@ static int __init qpti_register_irq(struct qlogicpti *qpti)
* sanely maintain.
*/
if (request_irq(qpti->irq, qpti_intr,
- SA_SHIRQ, "Qlogic/PTI", qpti))
+ IRQF_SHARED, "Qlogic/PTI", qpti))
goto fail;
printk("qpti%d: IRQ %d ", qpti->qpti_id, qpti->irq);
@@ -815,173 +812,6 @@ static int __init qpti_map_queues(struct qlogicpti *qpti)
return 0;
}
-/* Detect all PTI Qlogic ISP's in the machine. */
-static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
-{
- struct qlogicpti *qpti;
- struct Scsi_Host *qpti_host;
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
- int nqptis = 0, nqptis_in_use = 0;
-
- tpnt->proc_name = "qlogicpti";
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- /* Is this a red snapper? */
- if (strcmp(sdev->prom_name, "ptisp") &&
- strcmp(sdev->prom_name, "PTI,ptisp") &&
- strcmp(sdev->prom_name, "QLGC,isp") &&
- strcmp(sdev->prom_name, "SUNW,isp"))
- continue;
-
- /* Sometimes Antares cards come up not completely
- * setup, and we get a report of a zero IRQ.
- * Skip over them in such cases so we survive.
- */
- if (sdev->irqs[0] == 0) {
- printk("qpti%d: Adapter reports no interrupt, "
- "skipping over this card.", nqptis);
- continue;
- }
-
- /* Yep, register and allocate software state. */
- qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
- if (!qpti_host) {
- printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
- continue;
- }
- qpti = (struct qlogicpti *) qpti_host->hostdata;
-
- /* We are wide capable, 16 targets. */
- qpti_host->max_id = MAX_TARGETS;
-
- /* Setup back pointers and misc. state. */
- qpti->qhost = qpti_host;
- qpti->sdev = sdev;
- qpti->qpti_id = nqptis++;
- qpti->prom_node = sdev->prom_node;
- prom_getstring(qpti->prom_node, "name",
- qpti->prom_name,
- sizeof(qpti->prom_name));
-
- /* This is not correct, actually. There's a switch
- * on the PTI cards that put them into "emulation"
- * mode- i.e., report themselves as QLGC,isp
- * instead of PTI,ptisp. The only real substantive
- * difference between non-pti and pti cards is
- * the tmon register. Which is possibly even
- * there for Qlogic cards, but non-functional.
- */
- qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
-
- qpti_chain_add(qpti);
- if (qpti_map_regs(qpti) < 0)
- goto fail_unlink;
-
- if (qpti_register_irq(qpti) < 0)
- goto fail_unmap_regs;
-
- qpti_get_scsi_id(qpti);
- qpti_get_bursts(qpti);
- qpti_get_clock(qpti);
-
- /* Clear out scsi_cmnd array. */
- memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
-
- if (qpti_map_queues(qpti) < 0)
- goto fail_free_irq;
-
- /* Load the firmware. */
- if (qlogicpti_load_firmware(qpti))
- goto fail_unmap_queues;
- if (qpti->is_pti) {
- /* Check the PTI status reg. */
- if (qlogicpti_verify_tmon(qpti))
- goto fail_unmap_queues;
- }
-
- /* Reset the ISP and init res/req queues. */
- if (qlogicpti_reset_hardware(qpti_host))
- goto fail_unmap_queues;
-
- printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
- qpti->fware_minrev, qpti->fware_micrev);
- {
- char buffer[60];
-
- prom_getstring (qpti->prom_node,
- "isp-fcode", buffer, 60);
- if (buffer[0])
- printk("(Firmware %s)", buffer);
- if (prom_getbool(qpti->prom_node, "differential"))
- qpti->differential = 1;
- }
-
- printk (" [%s Wide, using %s interface]\n",
- (qpti->ultra ? "Ultra" : "Fast"),
- (qpti->differential ? "differential" : "single ended"));
-
- nqptis_in_use++;
- continue;
-
- fail_unmap_queues:
-#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
-#undef QSIZE
- fail_free_irq:
- free_irq(qpti->irq, qpti);
-
- fail_unmap_regs:
- sbus_iounmap(qpti->qregs,
- qpti->sdev->reg_addrs[0].reg_size);
- if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
- fail_unlink:
- qpti_chain_del(qpti);
- scsi_unregister(qpti->qhost);
- }
- }
- if (nqptis)
- printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
- nqptis, nqptis_in_use);
- qptis_running = nqptis_in_use;
- return nqptis;
-}
-
-static int qlogicpti_release(struct Scsi_Host *host)
-{
- struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
-
- /* Remove visibility from IRQ handlers. */
- qpti_chain_del(qpti);
-
- /* Shut up the card. */
- sbus_writew(0, qpti->qregs + SBUS_CTRL);
-
- /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
- free_irq(qpti->irq, qpti);
-
-#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
- sbus_free_consistent(qpti->sdev,
- QSIZE(RES_QUEUE_LEN),
- qpti->res_cpu, qpti->res_dvma);
- sbus_free_consistent(qpti->sdev,
- QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
- qpti->req_cpu, qpti->req_dvma);
-#undef QSIZE
-
- sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
- if (qpti->is_pti)
- sbus_iounmap(qpti->sreg, sizeof(unsigned char));
-
- return 0;
-}
-
const char *qlogicpti_info(struct Scsi_Host *host)
{
static char buf[80];
@@ -1044,7 +874,7 @@ static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
if (Cmnd->use_sg) {
int sg_count;
- sg = (struct scatterlist *) Cmnd->buffer;
+ sg = (struct scatterlist *) Cmnd->request_buffer;
sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
ds = cmd->dataseg;
@@ -1448,7 +1278,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
if (Cmnd->use_sg) {
sbus_unmap_sg(qpti->sdev,
- (struct scatterlist *)Cmnd->buffer,
+ (struct scatterlist *)Cmnd->request_buffer,
Cmnd->use_sg,
Cmnd->sc_data_direction);
} else {
@@ -1551,9 +1381,9 @@ static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
return return_status;
}
-static struct scsi_host_template driver_template = {
- .detect = qlogicpti_detect,
- .release = qlogicpti_release,
+static struct scsi_host_template qpti_template = {
+ .module = THIS_MODULE,
+ .name = "qlogicpti",
.info = qlogicpti_info,
.queuecommand = qlogicpti_queuecommand_slow,
.eh_abort_handler = qlogicpti_abort,
@@ -1565,8 +1395,189 @@ static struct scsi_host_template driver_template = {
.use_clustering = ENABLE_CLUSTERING,
};
+static int __devinit qpti_sbus_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ static int nqptis;
+ struct sbus_dev *sdev = to_sbus_device(&dev->dev);
+ struct device_node *dp = dev->node;
+ struct scsi_host_template *tpnt = match->data;
+ struct Scsi_Host *host;
+ struct qlogicpti *qpti;
+ char *fcode;
+
+ /* Sometimes Antares cards come up not completely
+ * setup, and we get a report of a zero IRQ.
+ */
+ if (sdev->irqs[0] == 0)
+ return -ENODEV;
+
+ host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti));
+ if (!host)
+ return -ENOMEM;
+
+ qpti = (struct qlogicpti *) host->hostdata;
+
+ host->max_id = MAX_TARGETS;
+ qpti->qhost = host;
+ qpti->sdev = sdev;
+ qpti->qpti_id = nqptis;
+ qpti->prom_node = sdev->prom_node;
+ strcpy(qpti->prom_name, sdev->ofdev.node->name);
+ qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp");
+
+ if (qpti_map_regs(qpti) < 0)
+ goto fail_unlink;
+
+ if (qpti_register_irq(qpti) < 0)
+ goto fail_unmap_regs;
+
+ qpti_get_scsi_id(qpti);
+ qpti_get_bursts(qpti);
+ qpti_get_clock(qpti);
+
+ /* Clear out scsi_cmnd array. */
+ memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
+
+ if (qpti_map_queues(qpti) < 0)
+ goto fail_free_irq;
+
+ /* Load the firmware. */
+ if (qlogicpti_load_firmware(qpti))
+ goto fail_unmap_queues;
+ if (qpti->is_pti) {
+ /* Check the PTI status reg. */
+ if (qlogicpti_verify_tmon(qpti))
+ goto fail_unmap_queues;
+ }
+
+ /* Reset the ISP and init res/req queues. */
+ if (qlogicpti_reset_hardware(host))
+ goto fail_unmap_queues;
+
+ if (scsi_add_host(host, &dev->dev))
+ goto fail_unmap_queues;
+
+ printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
+ qpti->fware_minrev, qpti->fware_micrev);
+
+ fcode = of_get_property(dp, "isp-fcode", NULL);
+ if (fcode && fcode[0])
+ printk("(Firmware %s)", fcode);
+ if (of_find_property(dp, "differential", NULL) != NULL)
+ qpti->differential = 1;
+
+ printk (" [%s Wide, using %s interface]\n",
+ (qpti->ultra ? "Ultra" : "Fast"),
+ (qpti->differential ? "differential" : "single ended"));
+
+ dev_set_drvdata(&sdev->ofdev.dev, qpti);
+
+ qpti_chain_add(qpti);
+
+ scsi_scan_host(host);
+ nqptis++;
+
+ return 0;
+
+fail_unmap_queues:
+#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+fail_unmap_regs:
+ sbus_iounmap(qpti->qregs,
+ qpti->sdev->reg_addrs[0].reg_size);
+ if (qpti->is_pti)
+ sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+fail_free_irq:
+ free_irq(qpti->irq, qpti);
+
+fail_unlink:
+ scsi_host_put(host);
+
+ return -ENODEV;
+}
+
+static int __devexit qpti_sbus_remove(struct of_device *dev)
+{
+ struct qlogicpti *qpti = dev_get_drvdata(&dev->dev);
+
+ qpti_chain_del(qpti);
+
+ scsi_remove_host(qpti->qhost);
+
+ /* Shut up the card. */
+ sbus_writew(0, qpti->qregs + SBUS_CTRL);
+
+ /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
+ free_irq(qpti->irq, qpti);
+
+#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN)
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(RES_QUEUE_LEN),
+ qpti->res_cpu, qpti->res_dvma);
+ sbus_free_consistent(qpti->sdev,
+ QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+ qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+ sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+ if (qpti->is_pti)
+ sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+ scsi_host_put(qpti->qhost);
+
+ return 0;
+}
+
+static struct of_device_id qpti_match[] = {
+ {
+ .name = "ptisp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "PTI,ptisp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "QLGC,isp",
+ .data = &qpti_template,
+ },
+ {
+ .name = "SUNW,isp",
+ .data = &qpti_template,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, qpti_match);
+
+static struct of_platform_driver qpti_sbus_driver = {
+ .name = "qpti",
+ .match_table = qpti_match,
+ .probe = qpti_sbus_probe,
+ .remove = __devexit_p(qpti_sbus_remove),
+};
-#include "scsi_module.c"
+static int __init qpti_init(void)
+{
+ return of_register_driver(&qpti_sbus_driver, &sbus_bus_type);
+}
+
+static void __exit qpti_exit(void)
+{
+ of_unregister_driver(&qpti_sbus_driver);
+}
+MODULE_DESCRIPTION("QlogicISP SBUS driver");
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
MODULE_LICENSE("GPL");
+MODULE_VERSION("2.0");
+module_init(qpti_init);
+module_exit(qpti_exit);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 2ab7df0dcfe..7a054f9d1ee 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -96,7 +96,11 @@ unsigned int scsi_logging_level;
EXPORT_SYMBOL(scsi_logging_level);
#endif
-const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
+/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI.
+ * You may not alter any existing entry (although adding new ones is
+ * encouraged once assigned by ANSI/INCITS T10
+ */
+static const char *const scsi_device_types[] = {
"Direct-Access ",
"Sequential-Access",
"Printer ",
@@ -107,13 +111,29 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
"Optical Device ",
"Medium Changer ",
"Communications ",
- "Unknown ",
- "Unknown ",
+ "ASC IT8 ",
+ "ASC IT8 ",
"RAID ",
"Enclosure ",
"Direct-Access-RBC",
+ "Optical card ",
+ "Bridge controller",
+ "Object storage ",
+ "Automation/Drive ",
};
-EXPORT_SYMBOL(scsi_device_types);
+
+const char * scsi_device_type(unsigned type)
+{
+ if (type == 0x1e)
+ return "Well-known LUN ";
+ if (type == 0x1f)
+ return "No Device ";
+ if (type > ARRAY_SIZE(scsi_device_types))
+ return "Unknown ";
+ return scsi_device_types[type];
+}
+
+EXPORT_SYMBOL(scsi_device_type);
struct scsi_host_cmd_pool {
kmem_cache_t *slab;
@@ -346,7 +366,7 @@ void scsi_log_send(struct scsi_cmnd *cmd)
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
" done = 0x%p, queuecommand 0x%p\n",
- cmd->buffer, cmd->bufflen,
+ cmd->request_buffer, cmd->request_bufflen,
cmd->done,
sdev->host->hostt->queuecommand);
@@ -661,11 +681,6 @@ void __scsi_done(struct scsi_cmnd *cmd)
*/
int scsi_retry_command(struct scsi_cmnd *cmd)
{
- /*
- * Restore the SCSI command state.
- */
- scsi_setup_cmd_retry(cmd);
-
/*
* Zero the sense information from the last time we tried
* this command.
@@ -711,10 +726,6 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
"Notifying upper driver of completion "
"(result %x)\n", cmd->result));
- /*
- * We can get here with use_sg=0, causing a panic in the upper level
- */
- cmd->use_sg = cmd->old_use_sg;
cmd->done(cmd);
}
EXPORT_SYMBOL(scsi_finish_command);
@@ -844,14 +855,14 @@ EXPORT_SYMBOL(scsi_track_queue_full);
*/
int scsi_device_get(struct scsi_device *sdev)
{
- if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
+ if (sdev->sdev_state == SDEV_DEL)
return -ENXIO;
if (!get_device(&sdev->sdev_gendev))
return -ENXIO;
- if (!try_module_get(sdev->host->hostt->module)) {
- put_device(&sdev->sdev_gendev);
- return -ENXIO;
- }
+ /* We can fail this if we're doing SCSI operations
+ * from module exit (like cache flush) */
+ try_module_get(sdev->host->hostt->module);
+
return 0;
}
EXPORT_SYMBOL(scsi_device_get);
@@ -866,7 +877,14 @@ EXPORT_SYMBOL(scsi_device_get);
*/
void scsi_device_put(struct scsi_device *sdev)
{
- module_put(sdev->host->hostt->module);
+ struct module *module = sdev->host->hostt->module;
+
+#ifdef CONFIG_MODULE_UNLOAD
+ /* The module refcount will be zero if scsi_device_get()
+ * was called from a module removal routine */
+ if (module && module_refcount(module) != 0)
+ module_put(module);
+#endif
put_device(&sdev->sdev_gendev);
}
EXPORT_SYMBOL(scsi_device_put);
@@ -1108,6 +1126,8 @@ static int __init init_scsi(void)
for_each_possible_cpu(i)
INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
+ scsi_netlink_init();
+
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
@@ -1128,6 +1148,7 @@ cleanup_queue:
static void __exit exit_scsi(void)
{
+ scsi_netlink_exit();
scsi_sysfs_unregister();
scsi_exit_sysctl();
scsi_exit_hosts();
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index f51e466893e..d5a55fae60e 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -20,8 +20,6 @@
#ifndef _SCSI_H
#define _SCSI_H
-#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
-
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_eh.h>
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 5a5d2af8ee4..9c0f35820e3 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1,5 +1,4 @@
/*
- * linux/kernel/scsi_debug.c
* vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
* Copyright (C) 1992 Eric Youngdale
* Simulate a host adapter with 2 disks attached. Do a lot of checking
@@ -8,7 +7,9 @@
* ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
* This version is more generic, simulating a variable number of disk
- * (or disk like devices) sharing a common amount of RAM
+ * (or disk like devices) sharing a common amount of RAM. To be more
+ * realistic, the simulated devices have the transport attributes of
+ * SAS disks.
*
*
* For documentation see http://www.torque.net/sg/sdebug26.html
@@ -24,7 +25,6 @@
* module options to "modprobe scsi_debug num_tgts=2" [20021221]
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -51,18 +51,22 @@
#include "scsi_logging.h"
#include "scsi_debug.h"
-#define SCSI_DEBUG_VERSION "1.75"
-static const char * scsi_debug_version_date = "20050113";
+#define SCSI_DEBUG_VERSION "1.80"
+static const char * scsi_debug_version_date = "20060914";
/* Additional Sense Code (ASC) used */
-#define NO_ADDED_SENSE 0x0
+#define NO_ADDITIONAL_SENSE 0x0
+#define LOGICAL_UNIT_NOT_READY 0x4
#define UNRECOVERED_READ_ERR 0x11
+#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
#define ADDR_OUT_OF_RANGE 0x21
#define INVALID_FIELD_IN_CDB 0x24
+#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define POWERON_RESET 0x29
#define SAVING_PARAMS_UNSUP 0x39
-#define THRESHHOLD_EXCEEDED 0x5d
+#define THRESHOLD_EXCEEDED 0x5d
+#define LOW_POWER_COND_ON 0x5e
#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
@@ -81,6 +85,10 @@ static const char * scsi_debug_version_date = "20050113";
#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */
#define DEF_PTYPE 0
#define DEF_D_SENSE 0
+#define DEF_NO_LUN_0 0
+#define DEF_VIRTUAL_GB 0
+#define DEF_FAKE_RW 0
+#define DEF_VPD_USE_HOSTNO 1
/* bit mask values for scsi_debug_opts */
#define SCSI_DEBUG_OPT_NOISE 1
@@ -107,6 +115,7 @@ static const char * scsi_debug_version_date = "20050113";
/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
* or "peripheral device" addressing (value 0) */
#define SAM2_LUN_ADDRESS_METHOD 0
+#define SAM2_WLUN_REPORT_LUNS 0xc101
static int scsi_debug_add_host = DEF_NUM_HOST;
static int scsi_debug_delay = DEF_DELAY;
@@ -119,13 +128,18 @@ static int scsi_debug_opts = DEF_OPTS;
static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
static int scsi_debug_dsense = DEF_D_SENSE;
+static int scsi_debug_no_lun_0 = DEF_NO_LUN_0;
+static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB;
+static int scsi_debug_fake_rw = DEF_FAKE_RW;
+static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
static int scsi_debug_cmnd_count = 0;
#define DEV_READONLY(TGT) (0)
#define DEV_REMOVEABLE(TGT) (0)
-static unsigned long sdebug_store_size; /* in bytes */
+static unsigned int sdebug_store_size; /* in bytes */
+static unsigned int sdebug_store_sectors;
static sector_t sdebug_capacity; /* in sectors */
/* old BIOS stuff, kernel may get rid of them but some mode sense pages
@@ -150,7 +164,9 @@ struct sdebug_dev_info {
unsigned int target;
unsigned int lun;
struct sdebug_host_info *sdbg_host;
+ unsigned int wlun;
char reset;
+ char stopped;
char used;
};
@@ -194,11 +210,11 @@ static struct scsi_host_template sdebug_driver_template = {
.bios_param = scsi_debug_biosparam,
.can_queue = SCSI_DEBUG_CANQUEUE,
.this_id = 7,
- .sg_tablesize = 64,
- .cmd_per_lun = 3,
- .max_sectors = 4096,
+ .sg_tablesize = 256,
+ .cmd_per_lun = 16,
+ .max_sectors = 0xffff,
.unchecked_isa_dma = 0,
- .use_clustering = DISABLE_CLUSTERING,
+ .use_clustering = ENABLE_CLUSTERING,
.module = THIS_MODULE,
};
@@ -226,19 +242,32 @@ static struct device_driver sdebug_driverfs_driver = {
static const int check_condition_result =
(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
+ 0, 0, 0x2, 0x4b};
+static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
+ 0, 0, 0x0, 0x0};
+
/* function declarations */
static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
struct sdebug_dev_info * devip);
static int resp_requests(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
+static int resp_start_stop(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip);
static int resp_readcap(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
-static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target,
+static int resp_readcap16(struct scsi_cmnd * SCpnt,
+ struct sdebug_dev_info * devip);
+static int resp_mode_sense(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip);
-static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip);
-static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip);
+static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
+ struct sdebug_dev_info * devip);
+static int resp_log_sense(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip);
+static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip);
+static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip);
static int resp_report_luns(struct scsi_cmnd * SCpnt,
struct sdebug_dev_info * devip);
static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
@@ -249,8 +278,8 @@ static void timer_intr_handler(unsigned long);
static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
int asc, int asq);
-static int check_reset(struct scsi_cmnd * SCpnt,
- struct sdebug_dev_info * devip);
+static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
+ struct sdebug_dev_info * devip);
static int schedule_resp(struct scsi_cmnd * cmnd,
struct sdebug_dev_info * devip,
done_funct_t done, int scsi_result, int delta_jiff);
@@ -258,9 +287,11 @@ static void __init sdebug_build_parts(unsigned char * ramp);
static void __init init_all_queued(void);
static void stop_all_queued(void);
static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
-static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
- const char * dev_id_str, int dev_id_str_len);
-static void do_create_driverfs_files(void);
+static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
+ int dev_id_num, const char * dev_id_str,
+ int dev_id_str_len);
+static int inquiry_evpd_88(unsigned char * arr, int target_dev_id);
+static int do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
static int sdebug_add_adapter(void);
@@ -275,18 +306,22 @@ static
int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
{
unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
- int block, upper_blk, num, k;
+ int len, k, j;
+ unsigned int num;
+ unsigned long long lba;
int errsts = 0;
- int target = scmd_id(SCpnt);
+ int target = SCpnt->device->id;
struct sdebug_dev_info * devip = NULL;
int inj_recovered = 0;
+ int delay_override = 0;
if (done == NULL)
return 0; /* assume mid level reprocessing command */
+ SCpnt->resid = 0;
if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
printk(KERN_INFO "scsi_debug: cmd ");
- for (k = 0, num = SCpnt->cmd_len; k < num; ++k)
+ for (k = 0, len = SCpnt->cmd_len; k < len; ++k)
printk("%02x ", (int)cmd[k]);
printk("\n");
}
@@ -297,7 +332,8 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
DID_NO_CONNECT << 16, 0);
}
- if (SCpnt->device->lun >= scsi_debug_max_luns)
+ if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
+ (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
return schedule_resp(SCpnt, NULL, done,
DID_NO_CONNECT << 16, 0);
devip = devInfoReg(SCpnt->device);
@@ -316,118 +352,154 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
inj_recovered = 1; /* to reads and writes below */
}
+ if (devip->wlun) {
+ switch (*cmd) {
+ case INQUIRY:
+ case REQUEST_SENSE:
+ case TEST_UNIT_READY:
+ case REPORT_LUNS:
+ break; /* only allowable wlun commands */
+ default:
+ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+ printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
+ "not supported for wlun\n", *cmd);
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_OPCODE, 0);
+ errsts = check_condition_result;
+ return schedule_resp(SCpnt, devip, done, errsts,
+ 0);
+ }
+ }
+
switch (*cmd) {
case INQUIRY: /* mandatory, ignore unit attention */
+ delay_override = 1;
errsts = resp_inquiry(SCpnt, target, devip);
break;
case REQUEST_SENSE: /* mandatory, ignore unit attention */
+ delay_override = 1;
errsts = resp_requests(SCpnt, devip);
break;
case REZERO_UNIT: /* actually this is REWIND for SSC */
case START_STOP:
- errsts = check_reset(SCpnt, devip);
+ errsts = resp_start_stop(SCpnt, devip);
break;
case ALLOW_MEDIUM_REMOVAL:
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 1, devip)))
break;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Medium removal %s\n",
cmd[4] ? "inhibited" : "enabled");
break;
case SEND_DIAGNOSTIC: /* mandatory */
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case TEST_UNIT_READY: /* mandatory */
- errsts = check_reset(SCpnt, devip);
+ delay_override = 1;
+ errsts = check_readiness(SCpnt, 0, devip);
break;
case RESERVE:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case RESERVE_10:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case RELEASE:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case RELEASE_10:
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 1, devip);
break;
case READ_CAPACITY:
errsts = resp_readcap(SCpnt, devip);
break;
+ case SERVICE_ACTION_IN:
+ if (SAI_READ_CAPACITY_16 != cmd[1]) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+ errsts = resp_readcap16(SCpnt, devip);
+ break;
case READ_16:
case READ_12:
case READ_10:
case READ_6:
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 0, devip)))
+ break;
+ if (scsi_debug_fake_rw)
break;
- upper_blk = 0;
if ((*cmd) == READ_16) {
- upper_blk = cmd[5] + (cmd[4] << 8) +
- (cmd[3] << 16) + (cmd[2] << 24);
- block = cmd[9] + (cmd[8] << 8) +
- (cmd[7] << 16) + (cmd[6] << 24);
+ for (lba = 0, j = 0; j < 8; ++j) {
+ if (j > 0)
+ lba <<= 8;
+ lba += cmd[2 + j];
+ }
num = cmd[13] + (cmd[12] << 8) +
(cmd[11] << 16) + (cmd[10] << 24);
} else if ((*cmd) == READ_12) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[9] + (cmd[8] << 8) +
(cmd[7] << 16) + (cmd[6] << 24);
} else if ((*cmd) == READ_10) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[8] + (cmd[7] << 8);
- } else {
- block = cmd[3] + (cmd[2] << 8) +
+ } else { /* READ (6) */
+ lba = cmd[3] + (cmd[2] << 8) +
((cmd[1] & 0x1f) << 16);
- num = cmd[4];
+ num = (0 == cmd[4]) ? 256 : cmd[4];
}
- errsts = resp_read(SCpnt, upper_blk, block, num, devip);
+ errsts = resp_read(SCpnt, lba, num, devip);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
- THRESHHOLD_EXCEEDED, 0);
+ THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
}
break;
case REPORT_LUNS: /* mandatory, ignore unit attention */
+ delay_override = 1;
errsts = resp_report_luns(SCpnt, devip);
break;
case VERIFY: /* 10 byte SBC-2 command */
- errsts = check_reset(SCpnt, devip);
+ errsts = check_readiness(SCpnt, 0, devip);
break;
case WRITE_16:
case WRITE_12:
case WRITE_10:
case WRITE_6:
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 0, devip)))
+ break;
+ if (scsi_debug_fake_rw)
break;
- upper_blk = 0;
if ((*cmd) == WRITE_16) {
- upper_blk = cmd[5] + (cmd[4] << 8) +
- (cmd[3] << 16) + (cmd[2] << 24);
- block = cmd[9] + (cmd[8] << 8) +
- (cmd[7] << 16) + (cmd[6] << 24);
+ for (lba = 0, j = 0; j < 8; ++j) {
+ if (j > 0)
+ lba <<= 8;
+ lba += cmd[2 + j];
+ }
num = cmd[13] + (cmd[12] << 8) +
(cmd[11] << 16) + (cmd[10] << 24);
} else if ((*cmd) == WRITE_12) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[9] + (cmd[8] << 8) +
(cmd[7] << 16) + (cmd[6] << 24);
} else if ((*cmd) == WRITE_10) {
- block = cmd[5] + (cmd[4] << 8) +
+ lba = cmd[5] + (cmd[4] << 8) +
(cmd[3] << 16) + (cmd[2] << 24);
num = cmd[8] + (cmd[7] << 8);
- } else {
- block = cmd[3] + (cmd[2] << 8) +
+ } else { /* WRITE (6) */
+ lba = cmd[3] + (cmd[2] << 8) +
((cmd[1] & 0x1f) << 16);
- num = cmd[4];
+ num = (0 == cmd[4]) ? 256 : cmd[4];
}
- errsts = resp_write(SCpnt, upper_blk, block, num, devip);
+ errsts = resp_write(SCpnt, lba, num, devip);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
- THRESHHOLD_EXCEEDED, 0);
+ THRESHOLD_EXCEEDED, 0);
errsts = check_condition_result;
}
break;
@@ -435,20 +507,31 @@ int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
case MODE_SENSE_10:
errsts = resp_mode_sense(SCpnt, target, devip);
break;
+ case MODE_SELECT:
+ errsts = resp_mode_select(SCpnt, 1, devip);
+ break;
+ case MODE_SELECT_10:
+ errsts = resp_mode_select(SCpnt, 0, devip);
+ break;
+ case LOG_SENSE:
+ errsts = resp_log_sense(SCpnt, devip);
+ break;
case SYNCHRONIZE_CACHE:
- errsts = check_reset(SCpnt, devip);
+ delay_override = 1;
+ errsts = check_readiness(SCpnt, 0, devip);
break;
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
"supported\n", *cmd);
- if ((errsts = check_reset(SCpnt, devip)))
+ if ((errsts = check_readiness(SCpnt, 1, devip)))
break; /* Unit attention takes precedence */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
errsts = check_condition_result;
break;
}
- return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
+ return schedule_resp(SCpnt, devip, done, errsts,
+ (delay_override ? 0 : scsi_debug_delay));
}
static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
@@ -460,7 +543,8 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
/* return -ENOTTY; // correct return but upsets fdisk */
}
-static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
+static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only,
+ struct sdebug_dev_info * devip)
{
if (devip->reset) {
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
@@ -470,6 +554,14 @@ static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
return check_condition_result;
}
+ if ((0 == reset_only) && devip->stopped) {
+ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+ printk(KERN_INFO "scsi_debug: Reporting Not "
+ "ready: initializing command required\n");
+ mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY,
+ 0x2);
+ return check_condition_result;
+ }
return 0;
}
@@ -493,7 +585,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
req_len = scp->request_bufflen;
act_len = (req_len < arr_len) ? req_len : arr_len;
memcpy(scp->request_buffer, arr, act_len);
- scp->resid = req_len - act_len;
+ if (scp->resid)
+ scp->resid -= act_len;
+ else
+ scp->resid = req_len - act_len;
return 0;
}
sgpnt = (struct scatterlist *)scp->request_buffer;
@@ -516,7 +611,10 @@ static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
}
req_len += sgpnt->length;
}
- scp->resid = req_len - act_len;
+ if (scp->resid)
+ scp->resid -= act_len;
+ else
+ scp->resid = req_len - act_len;
return 0;
}
@@ -567,12 +665,14 @@ static const char * inq_vendor_id = "Linux ";
static const char * inq_product_id = "scsi_debug ";
static const char * inq_product_rev = "0004";
-static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
- const char * dev_id_str, int dev_id_str_len)
+static int inquiry_evpd_83(unsigned char * arr, int target_dev_id,
+ int dev_id_num, const char * dev_id_str,
+ int dev_id_str_len)
{
- int num;
+ int num, port_a;
+ char b[32];
- /* Two identification descriptors: */
+ port_a = target_dev_id + 1;
/* T10 vendor identifier field format (faked) */
arr[0] = 0x2; /* ASCII */
arr[1] = 0x1;
@@ -583,25 +683,246 @@ static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
num = 8 + 16 + dev_id_str_len;
arr[3] = num;
num += 4;
- /* NAA IEEE registered identifier (faked) */
- arr[num] = 0x1; /* binary */
- arr[num + 1] = 0x3;
- arr[num + 2] = 0x0;
- arr[num + 3] = 0x8;
- arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */
- arr[num + 5] = 0x23;
- arr[num + 6] = 0x45;
- arr[num + 7] = 0x60;
- arr[num + 8] = (dev_id_num >> 24);
- arr[num + 9] = (dev_id_num >> 16) & 0xff;
- arr[num + 10] = (dev_id_num >> 8) & 0xff;
- arr[num + 11] = dev_id_num & 0xff;
- return num + 12;
+ if (dev_id_num >= 0) {
+ /* NAA-5, Logical unit identifier (binary) */
+ arr[num++] = 0x1; /* binary (not necessarily sas) */
+ arr[num++] = 0x3; /* PIV=0, lu, naa */
+ arr[num++] = 0x0;
+ arr[num++] = 0x8;
+ arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */
+ arr[num++] = 0x33;
+ arr[num++] = 0x33;
+ arr[num++] = 0x30;
+ arr[num++] = (dev_id_num >> 24);
+ arr[num++] = (dev_id_num >> 16) & 0xff;
+ arr[num++] = (dev_id_num >> 8) & 0xff;
+ arr[num++] = dev_id_num & 0xff;
+ /* Target relative port number */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x94; /* PIV=1, target port, rel port */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x4; /* length */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ arr[num++] = 0x1; /* relative port A */
+ }
+ /* NAA-5, Target port identifier */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x93; /* piv=1, target port, naa */
+ arr[num++] = 0x0;
+ arr[num++] = 0x8;
+ arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (port_a >> 24);
+ arr[num++] = (port_a >> 16) & 0xff;
+ arr[num++] = (port_a >> 8) & 0xff;
+ arr[num++] = port_a & 0xff;
+ /* NAA-5, Target device identifier */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0xa3; /* piv=1, target device, naa */
+ arr[num++] = 0x0;
+ arr[num++] = 0x8;
+ arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (target_dev_id >> 24);
+ arr[num++] = (target_dev_id >> 16) & 0xff;
+ arr[num++] = (target_dev_id >> 8) & 0xff;
+ arr[num++] = target_dev_id & 0xff;
+ /* SCSI name string: Target device identifier */
+ arr[num++] = 0x63; /* proto=sas, UTF-8 */
+ arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
+ arr[num++] = 0x0;
+ arr[num++] = 24;
+ memcpy(arr + num, "naa.52222220", 12);
+ num += 12;
+ snprintf(b, sizeof(b), "%08X", target_dev_id);
+ memcpy(arr + num, b, 8);
+ num += 8;
+ memset(arr + num, 0, 4);
+ num += 4;
+ return num;
+}
+
+
+static unsigned char vpd84_data[] = {
+/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
+ 0x22,0x22,0x22,0x0,0xbb,0x1,
+ 0x22,0x22,0x22,0x0,0xbb,0x2,
+};
+
+static int inquiry_evpd_84(unsigned char * arr)
+{
+ memcpy(arr, vpd84_data, sizeof(vpd84_data));
+ return sizeof(vpd84_data);
+}
+
+static int inquiry_evpd_85(unsigned char * arr)
+{
+ int num = 0;
+ const char * na1 = "https://www.kernel.org/config";
+ const char * na2 = "http://www.kernel.org/log";
+ int plen, olen;
+
+ arr[num++] = 0x1; /* lu, storage config */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ olen = strlen(na1);
+ plen = olen + 1;
+ if (plen % 4)
+ plen = ((plen / 4) + 1) * 4;
+ arr[num++] = plen; /* length, null termianted, padded */
+ memcpy(arr + num, na1, olen);
+ memset(arr + num + olen, 0, plen - olen);
+ num += plen;
+
+ arr[num++] = 0x4; /* lu, logging */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ olen = strlen(na2);
+ plen = olen + 1;
+ if (plen % 4)
+ plen = ((plen / 4) + 1) * 4;
+ arr[num++] = plen; /* length, null terminated, padded */
+ memcpy(arr + num, na2, olen);
+ memset(arr + num + olen, 0, plen - olen);
+ num += plen;
+
+ return num;
+}
+
+/* SCSI ports VPD page */
+static int inquiry_evpd_88(unsigned char * arr, int target_dev_id)
+{
+ int num = 0;
+ int port_a, port_b;
+
+ port_a = target_dev_id + 1;
+ port_b = port_a + 1;
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ arr[num++] = 0x1; /* relative port 1 (primary) */
+ memset(arr + num, 0, 6);
+ num += 6;
+ arr[num++] = 0x0;
+ arr[num++] = 12; /* length tp descriptor */
+ /* naa-5 target port identifier (A) */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x93; /* PIV=1, target port, NAA */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x8; /* length */
+ arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (port_a >> 24);
+ arr[num++] = (port_a >> 16) & 0xff;
+ arr[num++] = (port_a >> 8) & 0xff;
+ arr[num++] = port_a & 0xff;
+
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x0;
+ arr[num++] = 0x2; /* relative port 2 (secondary) */
+ memset(arr + num, 0, 6);
+ num += 6;
+ arr[num++] = 0x0;
+ arr[num++] = 12; /* length tp descriptor */
+ /* naa-5 target port identifier (B) */
+ arr[num++] = 0x61; /* proto=sas, binary */
+ arr[num++] = 0x93; /* PIV=1, target port, NAA */
+ arr[num++] = 0x0; /* reserved */
+ arr[num++] = 0x8; /* length */
+ arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */
+ arr[num++] = 0x22;
+ arr[num++] = 0x22;
+ arr[num++] = 0x20;
+ arr[num++] = (port_b >> 24);
+ arr[num++] = (port_b >> 16) & 0xff;
+ arr[num++] = (port_b >> 8) & 0xff;
+ arr[num++] = port_b & 0xff;
+
+ return num;
+}
+
+
+static unsigned char vpd89_data[] = {
+/* from 4th byte */ 0,0,0,0,
+'l','i','n','u','x',' ',' ',' ',
+'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
+'1','2','3','4',
+0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
+0xec,0,0,0,
+0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
+0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
+0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
+0x53,0x41,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x20,0x20,
+0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+0x10,0x80,
+0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
+0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
+0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
+0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
+0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
+0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
+0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
+0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
+0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
+};
+
+static int inquiry_evpd_89(unsigned char * arr)
+{
+ memcpy(arr, vpd89_data, sizeof(vpd89_data));
+ return sizeof(vpd89_data);
+}
+
+
+static unsigned char vpdb0_data[] = {
+ /* from 4th byte */ 0,0,0,4,
+ 0,0,0x4,0,
+ 0,0,0,64,
+};
+
+static int inquiry_evpd_b0(unsigned char * arr)
+{
+ memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
+ if (sdebug_store_sectors > 0x400) {
+ arr[4] = (sdebug_store_sectors >> 24) & 0xff;
+ arr[5] = (sdebug_store_sectors >> 16) & 0xff;
+ arr[6] = (sdebug_store_sectors >> 8) & 0xff;
+ arr[7] = sdebug_store_sectors & 0xff;
+ }
+ return sizeof(vpdb0_data);
}
#define SDEBUG_LONG_INQ_SZ 96
-#define SDEBUG_MAX_INQ_ARR_SZ 128
+#define SDEBUG_MAX_INQ_ARR_SZ 584
static int resp_inquiry(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip)
@@ -609,64 +930,115 @@ static int resp_inquiry(struct scsi_cmnd * scp, int target,
unsigned char pq_pdt;
unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
unsigned char *cmd = (unsigned char *)scp->cmnd;
- int alloc_len;
+ int alloc_len, n;
alloc_len = (cmd[3] << 8) + cmd[4];
memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
- pq_pdt = (scsi_debug_ptype & 0x1f);
+ if (devip->wlun)
+ pq_pdt = 0x1e; /* present, wlun */
+ else if (scsi_debug_no_lun_0 && (0 == devip->lun))
+ pq_pdt = 0x7f; /* not present, no device type */
+ else
+ pq_pdt = (scsi_debug_ptype & 0x1f);
arr[0] = pq_pdt;
if (0x2 & cmd[1]) { /* CMDDT bit set */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
return check_condition_result;
} else if (0x1 & cmd[1]) { /* EVPD bit set */
- int dev_id_num, len;
- char dev_id_str[6];
+ int lu_id_num, target_dev_id, len;
+ char lu_id_str[6];
+ int host_no = devip->sdbg_host->shost->host_no;
- dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
- (devip->target * 1000) + devip->lun;
- len = scnprintf(dev_id_str, 6, "%d", dev_id_num);
+ if (0 == scsi_debug_vpd_use_hostno)
+ host_no = 0;
+ lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
+ (devip->target * 1000) + devip->lun);
+ target_dev_id = ((host_no + 1) * 2000) +
+ (devip->target * 1000) - 3;
+ len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
if (0 == cmd[2]) { /* supported vital product data pages */
- arr[3] = 3;
- arr[4] = 0x0; /* this page */
- arr[5] = 0x80; /* unit serial number */
- arr[6] = 0x83; /* device identification */
+ arr[1] = cmd[2]; /*sanity */
+ n = 4;
+ arr[n++] = 0x0; /* this page */
+ arr[n++] = 0x80; /* unit serial number */
+ arr[n++] = 0x83; /* device identification */
+ arr[n++] = 0x84; /* software interface ident. */
+ arr[n++] = 0x85; /* management network addresses */
+ arr[n++] = 0x86; /* extended inquiry */
+ arr[n++] = 0x87; /* mode page policy */
+ arr[n++] = 0x88; /* SCSI ports */
+ arr[n++] = 0x89; /* ATA information */
+ arr[n++] = 0xb0; /* Block limits (SBC) */
+ arr[3] = n - 4; /* number of supported VPD pages */
} else if (0x80 == cmd[2]) { /* unit serial number */
- arr[1] = 0x80;
+ arr[1] = cmd[2]; /*sanity */
arr[3] = len;
- memcpy(&arr[4], dev_id_str, len);
+ memcpy(&arr[4], lu_id_str, len);
} else if (0x83 == cmd[2]) { /* device identification */
- arr[1] = 0x83;
- arr[3] = inquiry_evpd_83(&arr[4], dev_id_num,
- dev_id_str, len);
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_83(&arr[4], target_dev_id,
+ lu_id_num, lu_id_str, len);
+ } else if (0x84 == cmd[2]) { /* Software interface ident. */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_84(&arr[4]);
+ } else if (0x85 == cmd[2]) { /* Management network addresses */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_85(&arr[4]);
+ } else if (0x86 == cmd[2]) { /* extended inquiry */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = 0x3c; /* number of following entries */
+ arr[4] = 0x0; /* no protection stuff */
+ arr[5] = 0x7; /* head of q, ordered + simple q's */
+ } else if (0x87 == cmd[2]) { /* mode page policy */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = 0x8; /* number of following entries */
+ arr[4] = 0x2; /* disconnect-reconnect mp */
+ arr[6] = 0x80; /* mlus, shared */
+ arr[8] = 0x18; /* protocol specific lu */
+ arr[10] = 0x82; /* mlus, per initiator port */
+ } else if (0x88 == cmd[2]) { /* SCSI Ports */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_88(&arr[4], target_dev_id);
+ } else if (0x89 == cmd[2]) { /* ATA information */
+ arr[1] = cmd[2]; /*sanity */
+ n = inquiry_evpd_89(&arr[4]);
+ arr[2] = (n >> 8);
+ arr[3] = (n & 0xff);
+ } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */
+ arr[1] = cmd[2]; /*sanity */
+ arr[3] = inquiry_evpd_b0(&arr[4]);
} else {
/* Illegal request, invalid field in cdb */
mk_sense_buffer(devip, ILLEGAL_REQUEST,
INVALID_FIELD_IN_CDB, 0);
return check_condition_result;
}
+ len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
return fill_from_dev_buffer(scp, arr,
- min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ));
+ min(len, SDEBUG_MAX_INQ_ARR_SZ));
}
/* drops through here for a standard inquiry */
arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
arr[2] = scsi_debug_scsi_level;
arr[3] = 2; /* response_data_format==2 */
arr[4] = SDEBUG_LONG_INQ_SZ - 5;
- arr[6] = 0x1; /* claim: ADDR16 */
+ arr[6] = 0x10; /* claim: MultiP */
/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
- arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
+ arr[7] = 0xa; /* claim: LINKED + CMDQUE */
memcpy(&arr[8], inq_vendor_id, 8);
memcpy(&arr[16], inq_product_id, 16);
memcpy(&arr[32], inq_product_rev, 4);
/* version descriptors (2 bytes each) follow */
- arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */
- arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */
+ arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */
+ arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */
+ n = 62;
if (scsi_debug_ptype == 0) {
- arr[62] = 0x1; arr[63] = 0x80; /* SBC */
+ arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */
} else if (scsi_debug_ptype == 1) {
- arr[62] = 0x2; arr[63] = 0x00; /* SSC */
+ arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */
}
+ arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */
return fill_from_dev_buffer(scp, arr,
min(alloc_len, SDEBUG_LONG_INQ_SZ));
}
@@ -677,46 +1049,128 @@ static int resp_requests(struct scsi_cmnd * scp,
unsigned char * sbuff;
unsigned char *cmd = (unsigned char *)scp->cmnd;
unsigned char arr[SDEBUG_SENSE_LEN];
+ int want_dsense;
int len = 18;
- memset(arr, 0, SDEBUG_SENSE_LEN);
+ memset(arr, 0, sizeof(arr));
if (devip->reset == 1)
- mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+ mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
+ want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
sbuff = devip->sense_buff;
- if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
- /* DESC bit set and sense_buff in fixed format */
- arr[0] = 0x72;
- arr[1] = sbuff[2]; /* sense key */
- arr[2] = sbuff[12]; /* asc */
- arr[3] = sbuff[13]; /* ascq */
- len = 8;
- } else
+ if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
+ if (want_dsense) {
+ arr[0] = 0x72;
+ arr[1] = 0x0; /* NO_SENSE in sense_key */
+ arr[2] = THRESHOLD_EXCEEDED;
+ arr[3] = 0xff; /* TEST set and MRIE==6 */
+ } else {
+ arr[0] = 0x70;
+ arr[2] = 0x0; /* NO_SENSE in sense_key */
+ arr[7] = 0xa; /* 18 byte sense buffer */
+ arr[12] = THRESHOLD_EXCEEDED;
+ arr[13] = 0xff; /* TEST set and MRIE==6 */
+ }
+ } else {
memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
- mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+ if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
+ /* DESC bit set and sense_buff in fixed format */
+ memset(arr, 0, sizeof(arr));
+ arr[0] = 0x72;
+ arr[1] = sbuff[2]; /* sense key */
+ arr[2] = sbuff[12]; /* asc */
+ arr[3] = sbuff[13]; /* ascq */
+ len = 8;
+ }
+ }
+ mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0);
return fill_from_dev_buffer(scp, arr, len);
}
+static int resp_start_stop(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+ int power_cond, errsts, start;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ power_cond = (cmd[4] & 0xf0) >> 4;
+ if (power_cond) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
+ start = cmd[4] & 1;
+ if (start == devip->stopped)
+ devip->stopped = !start;
+ return 0;
+}
+
#define SDEBUG_READCAP_ARR_SZ 8
static int resp_readcap(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
unsigned char arr[SDEBUG_READCAP_ARR_SZ];
- unsigned long capac;
+ unsigned int capac;
int errsts;
- if ((errsts = check_reset(scp, devip)))
+ if ((errsts = check_readiness(scp, 1, devip)))
return errsts;
+ /* following just in case virtual_gb changed */
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
- capac = (unsigned long)sdebug_capacity - 1;
- arr[0] = (capac >> 24);
- arr[1] = (capac >> 16) & 0xff;
- arr[2] = (capac >> 8) & 0xff;
- arr[3] = capac & 0xff;
+ if (sdebug_capacity < 0xffffffff) {
+ capac = (unsigned int)sdebug_capacity - 1;
+ arr[0] = (capac >> 24);
+ arr[1] = (capac >> 16) & 0xff;
+ arr[2] = (capac >> 8) & 0xff;
+ arr[3] = capac & 0xff;
+ } else {
+ arr[0] = 0xff;
+ arr[1] = 0xff;
+ arr[2] = 0xff;
+ arr[3] = 0xff;
+ }
arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
arr[7] = SECT_SIZE_PER(target) & 0xff;
return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
}
+#define SDEBUG_READCAP16_ARR_SZ 32
+static int resp_readcap16(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+ unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
+ unsigned long long capac;
+ int errsts, k, alloc_len;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
+ + cmd[13]);
+ /* following just in case virtual_gb changed */
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
+ memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
+ capac = sdebug_capacity - 1;
+ for (k = 0; k < 8; ++k, capac >>= 8)
+ arr[7 - k] = capac & 0xff;
+ arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff;
+ arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff;
+ arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ arr[11] = SECT_SIZE_PER(target) & 0xff;
+ return fill_from_dev_buffer(scp, arr,
+ min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
+}
+
/* <<Following mode page info copied from ST318451LW>> */
static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
@@ -772,47 +1226,123 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
{ /* Control mode page for mode_sense */
- unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
+ unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0};
+ unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
0, 0, 0x2, 0x4b};
if (scsi_debug_dsense)
ctrl_m_pg[2] |= 0x4;
+ else
+ ctrl_m_pg[2] &= ~0x4;
memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
if (1 == pcontrol)
- memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
+ memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
+ else if (2 == pcontrol)
+ memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
return sizeof(ctrl_m_pg);
}
+
static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
{ /* Informational Exceptions control mode page for mode_sense */
- unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
- 0, 0, 0x0, 0x0};
+ unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
+ 0, 0, 0x0, 0x0};
+ unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
+ 0, 0, 0x0, 0x0};
+
memcpy(p, iec_m_pg, sizeof(iec_m_pg));
if (1 == pcontrol)
- memset(p + 2, 0, sizeof(iec_m_pg) - 2);
+ memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
+ else if (2 == pcontrol)
+ memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
return sizeof(iec_m_pg);
}
+static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
+{ /* SAS SSP mode page - short format for mode_sense */
+ unsigned char sas_sf_m_pg[] = {0x19, 0x6,
+ 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
+
+ memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
+ if (1 == pcontrol)
+ memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
+ return sizeof(sas_sf_m_pg);
+}
+
+
+static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
+ int target_dev_id)
+{ /* SAS phy control and discover mode page for mode_sense */
+ unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
+ 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
+ 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
+ 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
+ 0x2, 0, 0, 0, 0, 0, 0, 0,
+ 0x88, 0x99, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
+ 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0,
+ 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1,
+ 0x3, 0, 0, 0, 0, 0, 0, 0,
+ 0x88, 0x99, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+ int port_a, port_b;
+
+ port_a = target_dev_id + 1;
+ port_b = port_a + 1;
+ memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
+ p[20] = (port_a >> 24);
+ p[21] = (port_a >> 16) & 0xff;
+ p[22] = (port_a >> 8) & 0xff;
+ p[23] = port_a & 0xff;
+ p[48 + 20] = (port_b >> 24);
+ p[48 + 21] = (port_b >> 16) & 0xff;
+ p[48 + 22] = (port_b >> 8) & 0xff;
+ p[48 + 23] = port_b & 0xff;
+ if (1 == pcontrol)
+ memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
+ return sizeof(sas_pcd_m_pg);
+}
+
+static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
+{ /* SAS SSP shared protocol specific port mode subpage */
+ unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ };
+
+ memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
+ if (1 == pcontrol)
+ memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
+ return sizeof(sas_sha_m_pg);
+}
+
#define SDEBUG_MAX_MSENSE_SZ 256
static int resp_mode_sense(struct scsi_cmnd * scp, int target,
struct sdebug_dev_info * devip)
{
- unsigned char dbd;
- int pcontrol, pcode, subpcode;
+ unsigned char dbd, llbaa;
+ int pcontrol, pcode, subpcode, bd_len;
unsigned char dev_spec;
- int alloc_len, msense_6, offset, len, errsts;
+ int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
unsigned char * ap;
unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
unsigned char *cmd = (unsigned char *)scp->cmnd;
- if ((errsts = check_reset(scp, devip)))
+ if ((errsts = check_readiness(scp, 1, devip)))
return errsts;
- dbd = cmd[1] & 0x8;
+ dbd = !!(cmd[1] & 0x8);
pcontrol = (cmd[2] & 0xc0) >> 6;
pcode = cmd[2] & 0x3f;
subpcode = cmd[3];
msense_6 = (MODE_SENSE == cmd[0]);
+ llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10);
+ if ((0 == scsi_debug_ptype) && (0 == dbd))
+ bd_len = llbaa ? 16 : 8;
+ else
+ bd_len = 0;
alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
if (0x3 == pcontrol) { /* Saving values not supported */
@@ -820,17 +1350,63 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
0);
return check_condition_result;
}
- dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
+ target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
+ (devip->target * 1000) - 3;
+ /* set DPOFUA bit for disks */
+ if (0 == scsi_debug_ptype)
+ dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10;
+ else
+ dev_spec = 0x0;
if (msense_6) {
arr[2] = dev_spec;
+ arr[3] = bd_len;
offset = 4;
} else {
arr[3] = dev_spec;
+ if (16 == bd_len)
+ arr[4] = 0x1; /* set LONGLBA bit */
+ arr[7] = bd_len; /* assume 255 or less */
offset = 8;
}
ap = arr + offset;
+ if ((bd_len > 0) && (0 == sdebug_capacity)) {
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
+ }
+ if (8 == bd_len) {
+ if (sdebug_capacity > 0xfffffffe) {
+ ap[0] = 0xff;
+ ap[1] = 0xff;
+ ap[2] = 0xff;
+ ap[3] = 0xff;
+ } else {
+ ap[0] = (sdebug_capacity >> 24) & 0xff;
+ ap[1] = (sdebug_capacity >> 16) & 0xff;
+ ap[2] = (sdebug_capacity >> 8) & 0xff;
+ ap[3] = sdebug_capacity & 0xff;
+ }
+ ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ ap[7] = SECT_SIZE_PER(target) & 0xff;
+ offset += bd_len;
+ ap = arr + offset;
+ } else if (16 == bd_len) {
+ unsigned long long capac = sdebug_capacity;
+
+ for (k = 0; k < 8; ++k, capac >>= 8)
+ ap[7 - k] = capac & 0xff;
+ ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff;
+ ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff;
+ ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+ ap[15] = SECT_SIZE_PER(target) & 0xff;
+ offset += bd_len;
+ ap = arr + offset;
+ }
- if (0 != subpcode) { /* TODO: Control Extension page */
+ if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
+ /* TODO: Control Extension page */
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
return check_condition_result;
@@ -856,17 +1432,45 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
len = resp_ctrl_m_pg(ap, pcontrol, target);
offset += len;
break;
+ case 0x19: /* if spc==1 then sas phy, control+discover */
+ if ((subpcode > 0x2) && (subpcode < 0xff)) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ len = 0;
+ if ((0x0 == subpcode) || (0xff == subpcode))
+ len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
+ if ((0x1 == subpcode) || (0xff == subpcode))
+ len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
+ target_dev_id);
+ if ((0x2 == subpcode) || (0xff == subpcode))
+ len += resp_sas_sha_m_spg(ap + len, pcontrol);
+ offset += len;
+ break;
case 0x1c: /* Informational Exceptions Mode page, all devices */
len = resp_iec_m_pg(ap, pcontrol, target);
offset += len;
break;
case 0x3f: /* Read all Mode pages */
- len = resp_err_recov_pg(ap, pcontrol, target);
- len += resp_disconnect_pg(ap + len, pcontrol, target);
- len += resp_format_pg(ap + len, pcontrol, target);
- len += resp_caching_pg(ap + len, pcontrol, target);
- len += resp_ctrl_m_pg(ap + len, pcontrol, target);
- len += resp_iec_m_pg(ap + len, pcontrol, target);
+ if ((0 == subpcode) || (0xff == subpcode)) {
+ len = resp_err_recov_pg(ap, pcontrol, target);
+ len += resp_disconnect_pg(ap + len, pcontrol, target);
+ len += resp_format_pg(ap + len, pcontrol, target);
+ len += resp_caching_pg(ap + len, pcontrol, target);
+ len += resp_ctrl_m_pg(ap + len, pcontrol, target);
+ len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
+ if (0xff == subpcode) {
+ len += resp_sas_pcd_m_spg(ap + len, pcontrol,
+ target, target_dev_id);
+ len += resp_sas_sha_m_spg(ap + len, pcontrol);
+ }
+ len += resp_iec_m_pg(ap + len, pcontrol, target);
+ } else {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
offset += len;
break;
default:
@@ -883,71 +1487,314 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
}
-static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip)
+#define SDEBUG_MAX_MSELECT_SZ 512
+
+static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
+ struct sdebug_dev_info * devip)
+{
+ int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
+ int param_len, res, errsts, mpage;
+ unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ memset(arr, 0, sizeof(arr));
+ pf = cmd[1] & 0x10;
+ sp = cmd[1] & 0x1;
+ param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
+ if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ res = fetch_to_dev_buffer(scp, arr, param_len);
+ if (-1 == res)
+ return (DID_ERROR << 16);
+ else if ((res < param_len) &&
+ (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
+ printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, "
+ " IO sent=%d bytes\n", param_len, res);
+ md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
+ bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
+ if (md_len > 2) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+ }
+ off = bd_len + (mselect6 ? 4 : 8);
+ mpage = arr[off] & 0x3f;
+ ps = !!(arr[off] & 0x80);
+ if (ps) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+ }
+ spf = !!(arr[off] & 0x40);
+ pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) :
+ (arr[off + 1] + 2);
+ if ((pg_len + off) > param_len) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ PARAMETER_LIST_LENGTH_ERR, 0);
+ return check_condition_result;
+ }
+ switch (mpage) {
+ case 0xa: /* Control Mode page */
+ if (ctrl_m_pg[1] == arr[off + 1]) {
+ memcpy(ctrl_m_pg + 2, arr + off + 2,
+ sizeof(ctrl_m_pg) - 2);
+ scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4);
+ return 0;
+ }
+ break;
+ case 0x1c: /* Informational Exceptions Mode page */
+ if (iec_m_pg[1] == arr[off + 1]) {
+ memcpy(iec_m_pg + 2, arr + off + 2,
+ sizeof(iec_m_pg) - 2);
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_PARAM_LIST, 0);
+ return check_condition_result;
+}
+
+static int resp_temp_l_pg(unsigned char * arr)
+{
+ unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
+ 0x0, 0x1, 0x3, 0x2, 0x0, 65,
+ };
+
+ memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
+ return sizeof(temp_l_pg);
+}
+
+static int resp_ie_l_pg(unsigned char * arr)
+{
+ unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
+ };
+
+ memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
+ if (iec_m_pg[2] & 0x4) { /* TEST bit set */
+ arr[4] = THRESHOLD_EXCEEDED;
+ arr[5] = 0xff;
+ }
+ return sizeof(ie_l_pg);
+}
+
+#define SDEBUG_MAX_LSENSE_SZ 512
+
+static int resp_log_sense(struct scsi_cmnd * scp,
+ struct sdebug_dev_info * devip)
+{
+ int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
+ unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
+ unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+ if ((errsts = check_readiness(scp, 1, devip)))
+ return errsts;
+ memset(arr, 0, sizeof(arr));
+ ppc = cmd[1] & 0x2;
+ sp = cmd[1] & 0x1;
+ if (ppc || sp) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ pcontrol = (cmd[2] & 0xc0) >> 6;
+ pcode = cmd[2] & 0x3f;
+ subpcode = cmd[3] & 0xff;
+ alloc_len = (cmd[7] << 8) + cmd[8];
+ arr[0] = pcode;
+ if (0 == subpcode) {
+ switch (pcode) {
+ case 0x0: /* Supported log pages log page */
+ n = 4;
+ arr[n++] = 0x0; /* this page */
+ arr[n++] = 0xd; /* Temperature */
+ arr[n++] = 0x2f; /* Informational exceptions */
+ arr[3] = n - 4;
+ break;
+ case 0xd: /* Temperature log page */
+ arr[3] = resp_temp_l_pg(arr + 4);
+ break;
+ case 0x2f: /* Informational exceptions log page */
+ arr[3] = resp_ie_l_pg(arr + 4);
+ break;
+ default:
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ } else if (0xff == subpcode) {
+ arr[0] |= 0x40;
+ arr[1] = subpcode;
+ switch (pcode) {
+ case 0x0: /* Supported log pages and subpages log page */
+ n = 4;
+ arr[n++] = 0x0;
+ arr[n++] = 0x0; /* 0,0 page */
+ arr[n++] = 0x0;
+ arr[n++] = 0xff; /* this page */
+ arr[n++] = 0xd;
+ arr[n++] = 0x0; /* Temperature */
+ arr[n++] = 0x2f;
+ arr[n++] = 0x0; /* Informational exceptions */
+ arr[3] = n - 4;
+ break;
+ case 0xd: /* Temperature subpages */
+ n = 4;
+ arr[n++] = 0xd;
+ arr[n++] = 0x0; /* Temperature */
+ arr[3] = n - 4;
+ break;
+ case 0x2f: /* Informational exceptions subpages */
+ n = 4;
+ arr[n++] = 0x2f;
+ arr[n++] = 0x0; /* Informational exceptions */
+ arr[3] = n - 4;
+ break;
+ default:
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ } else {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+ len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
+ return fill_from_dev_buffer(scp, arr,
+ min(len, SDEBUG_MAX_INQ_ARR_SZ));
+}
+
+static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip)
{
unsigned long iflags;
+ unsigned int block, from_bottom;
+ unsigned long long u;
int ret;
- if (upper_blk || (block + num > sdebug_capacity)) {
+ if (lba + num > sdebug_capacity) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
0);
return check_condition_result;
}
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
- (block <= OPT_MEDIUM_ERR_ADDR) &&
- ((block + num) > OPT_MEDIUM_ERR_ADDR)) {
+ (lba <= OPT_MEDIUM_ERR_ADDR) &&
+ ((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
+ /* claim unrecoverable read error */
mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
0);
- /* claim unrecoverable read error */
+ /* set info field and valid bit for fixed descriptor */
+ if (0x70 == (devip->sense_buff[0] & 0x7f)) {
+ devip->sense_buff[0] |= 0x80; /* Valid bit */
+ ret = OPT_MEDIUM_ERR_ADDR;
+ devip->sense_buff[3] = (ret >> 24) & 0xff;
+ devip->sense_buff[4] = (ret >> 16) & 0xff;
+ devip->sense_buff[5] = (ret >> 8) & 0xff;
+ devip->sense_buff[6] = ret & 0xff;
+ }
return check_condition_result;
}
read_lock_irqsave(&atomic_rw, iflags);
- ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
- num * SECT_SIZE);
+ if ((lba + num) <= sdebug_store_sectors)
+ ret = fill_from_dev_buffer(SCpnt,
+ fake_storep + (lba * SECT_SIZE),
+ num * SECT_SIZE);
+ else {
+ /* modulo when one arg is 64 bits needs do_div() */
+ u = lba;
+ block = do_div(u, sdebug_store_sectors);
+ from_bottom = 0;
+ if ((block + num) > sdebug_store_sectors)
+ from_bottom = (block + num) - sdebug_store_sectors;
+ ret = fill_from_dev_buffer(SCpnt,
+ fake_storep + (block * SECT_SIZE),
+ (num - from_bottom) * SECT_SIZE);
+ if ((0 == ret) && (from_bottom > 0))
+ ret = fill_from_dev_buffer(SCpnt, fake_storep,
+ from_bottom * SECT_SIZE);
+ }
read_unlock_irqrestore(&atomic_rw, iflags);
return ret;
}
-static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
- int num, struct sdebug_dev_info * devip)
+static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba,
+ unsigned int num, struct sdebug_dev_info * devip)
{
unsigned long iflags;
+ unsigned int block, to_bottom;
+ unsigned long long u;
int res;
- if (upper_blk || (block + num > sdebug_capacity)) {
+ if (lba + num > sdebug_capacity) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
0);
return check_condition_result;
}
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+ 0);
+ return check_condition_result;
+ }
write_lock_irqsave(&atomic_rw, iflags);
- res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
- num * SECT_SIZE);
+ if ((lba + num) <= sdebug_store_sectors)
+ res = fetch_to_dev_buffer(SCpnt,
+ fake_storep + (lba * SECT_SIZE),
+ num * SECT_SIZE);
+ else {
+ /* modulo when one arg is 64 bits needs do_div() */
+ u = lba;
+ block = do_div(u, sdebug_store_sectors);
+ to_bottom = 0;
+ if ((block + num) > sdebug_store_sectors)
+ to_bottom = (block + num) - sdebug_store_sectors;
+ res = fetch_to_dev_buffer(SCpnt,
+ fake_storep + (block * SECT_SIZE),
+ (num - to_bottom) * SECT_SIZE);
+ if ((0 == res) && (to_bottom > 0))
+ res = fetch_to_dev_buffer(SCpnt, fake_storep,
+ to_bottom * SECT_SIZE);
+ }
write_unlock_irqrestore(&atomic_rw, iflags);
if (-1 == res)
return (DID_ERROR << 16);
else if ((res < (num * SECT_SIZE)) &&
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
- printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, "
+ printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, "
" IO sent=%d bytes\n", num * SECT_SIZE, res);
return 0;
}
-#define SDEBUG_RLUN_ARR_SZ 128
+#define SDEBUG_RLUN_ARR_SZ 256
static int resp_report_luns(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
unsigned int alloc_len;
- int lun_cnt, i, upper;
+ int lun_cnt, i, upper, num, n, wlun, lun;
unsigned char *cmd = (unsigned char *)scp->cmnd;
int select_report = (int)cmd[2];
struct scsi_lun *one_lun;
unsigned char arr[SDEBUG_RLUN_ARR_SZ];
+ unsigned char * max_addr;
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
- if ((alloc_len < 16) || (select_report > 2)) {
+ if ((alloc_len < 4) || (select_report > 2)) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
0);
return check_condition_result;
@@ -955,18 +1802,37 @@ static int resp_report_luns(struct scsi_cmnd * scp,
/* can produce response with up to 16k luns (lun 0 to lun 16383) */
memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
lun_cnt = scsi_debug_max_luns;
- arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
- arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
- lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
- sizeof(struct scsi_lun)), lun_cnt);
+ if (1 == select_report)
+ lun_cnt = 0;
+ else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
+ --lun_cnt;
+ wlun = (select_report > 0) ? 1 : 0;
+ num = lun_cnt + wlun;
+ arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
+ arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
+ n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
+ sizeof(struct scsi_lun)), num);
+ if (n < num) {
+ wlun = 0;
+ lun_cnt = n;
+ }
one_lun = (struct scsi_lun *) &arr[8];
- for (i = 0; i < lun_cnt; i++) {
- upper = (i >> 8) & 0x3f;
+ max_addr = arr + SDEBUG_RLUN_ARR_SZ;
+ for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0);
+ ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr));
+ i++, lun++) {
+ upper = (lun >> 8) & 0x3f;
if (upper)
one_lun[i].scsi_lun[0] =
(upper | (SAM2_LUN_ADDRESS_METHOD << 6));
- one_lun[i].scsi_lun[1] = i & 0xff;
+ one_lun[i].scsi_lun[1] = lun & 0xff;
}
+ if (wlun) {
+ one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
+ one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
+ i++;
+ }
+ alloc_len = (unsigned char *)(one_lun + i) - arr;
return fill_from_dev_buffer(scp, arr,
min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
}
@@ -1002,7 +1868,8 @@ static void timer_intr_handler(unsigned long indx)
static int scsi_debug_slave_alloc(struct scsi_device * sdp)
{
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_alloc\n");
+ printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
+ sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
return 0;
}
@@ -1011,7 +1878,8 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
struct sdebug_dev_info * devip;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_configure\n");
+ printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
+ sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
devip = devInfoReg(sdp);
@@ -1019,6 +1887,7 @@ static int scsi_debug_slave_configure(struct scsi_device * sdp)
if (sdp->host->cmd_per_lun)
scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
sdp->host->cmd_per_lun);
+ blk_queue_max_segment_size(sdp->request_queue, 256 * 1024);
return 0;
}
@@ -1028,7 +1897,8 @@ static void scsi_debug_slave_destroy(struct scsi_device * sdp)
(struct sdebug_dev_info *)sdp->hostdata;
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, sdp, "scsi_debug: slave_destroy\n");
+ printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
+ sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (devip) {
/* make this slot avaliable for re-use */
devip->used = 0;
@@ -1085,6 +1955,8 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
open_devip->sense_buff[0] = 0x70;
open_devip->sense_buff[7] = 0xa;
}
+ if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
+ open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
return open_devip;
}
return NULL;
@@ -1273,7 +2145,7 @@ static void __init sdebug_build_parts(unsigned char * ramp)
printk(KERN_WARNING "scsi_debug:build_parts: reducing "
"partitions to %d\n", SDEBUG_MAX_PARTS);
}
- num_sectors = (int)(sdebug_store_size / SECT_SIZE);
+ num_sectors = (int)sdebug_store_sectors;
sectors_per_part = (num_sectors - sdebug_sectors_per)
/ scsi_debug_num_parts;
heads_by_sects = sdebug_heads * sdebug_sectors_per;
@@ -1316,9 +2188,9 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
if (scsi_result) {
struct scsi_device * sdp = cmnd->device;
- sdev_printk(KERN_INFO, sdp,
- "non-zero result=0x%x\n",
- scsi_result);
+ printk(KERN_INFO "scsi_debug: <%u %u %u %u> "
+ "non-zero result=0x%x\n", sdp->host->host_no,
+ sdp->channel, sdp->id, sdp->lun, scsi_result);
}
}
if (cmnd && devip) {
@@ -1365,21 +2237,28 @@ static int schedule_resp(struct scsi_cmnd * cmnd,
}
}
-/* Set 'perm' (4th argument) to 0 to disable module_param's definition
- * of sysfs parameters (which module_param doesn't yet support).
- * Sysfs parameters defined explicitly below.
+/* Note: The following macros create attribute files in the
+ /sys/module/scsi_debug/parameters directory. Unfortunately this
+ driver is unaware of a change and cannot trigger auxiliary actions
+ as it can when the corresponding attribute in the
+ /sys/bus/pseudo/drivers/scsi_debug directory is changed.
*/
-module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */
-module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */
-module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0);
-module_param_named(dsense, scsi_debug_dsense, int, 0);
-module_param_named(every_nth, scsi_debug_every_nth, int, 0);
-module_param_named(max_luns, scsi_debug_max_luns, int, 0);
-module_param_named(num_parts, scsi_debug_num_parts, int, 0);
-module_param_named(num_tgts, scsi_debug_num_tgts, int, 0);
-module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */
-module_param_named(ptype, scsi_debug_ptype, int, 0);
-module_param_named(scsi_level, scsi_debug_scsi_level, int, 0);
+module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR);
+module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR);
+module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO);
+module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR);
+module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR);
+module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR);
+module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR);
+module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR);
+module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO);
+module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR);
+module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR);
+module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
+module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
+module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR);
+module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int,
+ S_IRUGO | S_IWUSR);
MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
MODULE_DESCRIPTION("SCSI debug adapter driver");
@@ -1388,15 +2267,19 @@ MODULE_VERSION(SCSI_DEBUG_VERSION);
MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
-MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs");
-MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)");
+MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
+MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
-MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate");
+MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
+MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
+MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
-MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");
-MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->...");
+MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
+MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->... (def=0)");
MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
+MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
+MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
static char sdebug_info[256];
@@ -1548,6 +2431,42 @@ static ssize_t sdebug_dsense_store(struct device_driver * ddp,
DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
sdebug_dsense_store);
+static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw);
+}
+static ssize_t sdebug_fake_rw_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_fake_rw = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show,
+ sdebug_fake_rw_store);
+
+static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0);
+}
+static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_no_lun_0 = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show,
+ sdebug_no_lun_0_store);
+
static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
@@ -1623,6 +2542,29 @@ static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
}
DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
+static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb);
+}
+static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_virtual_gb = n;
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show,
+ sdebug_virtual_gb_store);
+
static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
{
return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
@@ -1660,29 +2602,65 @@ static ssize_t sdebug_add_host_store(struct device_driver * ddp,
DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show,
sdebug_add_host_store);
-static void do_create_driverfs_files(void)
+static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp,
+ char * buf)
{
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
- driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno);
+}
+static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp,
+ const char * buf, size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_vpd_use_hostno = n;
+ return count;
+ }
+ return -EINVAL;
+}
+DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show,
+ sdebug_vpd_use_hostno_store);
+
+/* Note: The following function creates attribute files in the
+ /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
+ files (over those found in the /sys/module/scsi_debug/parameters
+ directory) is that auxiliary actions can be triggered when an attribute
+ is changed. For example see: sdebug_add_host_store() above.
+ */
+static int do_create_driverfs_files(void)
+{
+ int ret;
+
+ ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
+ ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
+ return ret;
}
static void do_remove_driverfs_files(void)
{
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
- driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
@@ -1692,14 +2670,20 @@ static void do_remove_driverfs_files(void)
static int __init scsi_debug_init(void)
{
- unsigned long sz;
+ unsigned int sz;
int host_to_add;
int k;
+ int ret;
if (scsi_debug_dev_size_mb < 1)
scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
- sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576;
- sdebug_capacity = sdebug_store_size / SECT_SIZE;
+ sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576;
+ sdebug_store_sectors = sdebug_store_size / SECT_SIZE;
+ if (scsi_debug_virtual_gb > 0) {
+ sdebug_capacity = 2048 * 1024;
+ sdebug_capacity *= scsi_debug_virtual_gb;
+ } else
+ sdebug_capacity = sdebug_store_sectors;
/* play around with geometry, don't waste too much on track 0 */
sdebug_heads = 8;
@@ -1728,12 +2712,32 @@ static int __init scsi_debug_init(void)
if (scsi_debug_num_parts > 0)
sdebug_build_parts(fake_storep);
- init_all_queued();
+ ret = device_register(&pseudo_primary);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: device_register error: %d\n",
+ ret);
+ goto free_vm;
+ }
+ ret = bus_register(&pseudo_lld_bus);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: bus_register error: %d\n",
+ ret);
+ goto dev_unreg;
+ }
+ ret = driver_register(&sdebug_driverfs_driver);
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: driver_register error: %d\n",
+ ret);
+ goto bus_unreg;
+ }
+ ret = do_create_driverfs_files();
+ if (ret < 0) {
+ printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n",
+ ret);
+ goto del_files;
+ }
- device_register(&pseudo_primary);
- bus_register(&pseudo_lld_bus);
- driver_register(&sdebug_driverfs_driver);
- do_create_driverfs_files();
+ init_all_queued();
sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
@@ -1753,6 +2757,18 @@ static int __init scsi_debug_init(void)
scsi_debug_add_host);
}
return 0;
+
+del_files:
+ do_remove_driverfs_files();
+ driver_unregister(&sdebug_driverfs_driver);
+bus_unreg:
+ bus_unregister(&pseudo_lld_bus);
+dev_unreg:
+ device_unregister(&pseudo_primary);
+free_vm:
+ vfree(fake_storep);
+
+ return ret;
}
static void __exit scsi_debug_exit(void)
@@ -1813,7 +2829,7 @@ static int sdebug_add_adapter(void)
struct sdebug_dev_info *sdbg_devinfo;
struct list_head *lh, *lh_sf;
- sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
+ sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL);
if (NULL == sdbg_host) {
printk(KERN_ERR "%s: out of memory at line %d\n",
@@ -1825,7 +2841,7 @@ static int sdebug_add_adapter(void)
devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
for (k = 0; k < devs_per_host; k++) {
- sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo), GFP_KERNEL);
+ sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
if (NULL == sdbg_devinfo) {
printk(KERN_ERR "%s: out of memory at line %d\n",
__FUNCTION__, __LINE__);
@@ -1906,7 +2922,7 @@ static int sdebug_driver_probe(struct device * dev)
hpnt->max_id = scsi_debug_num_tgts + 1;
else
hpnt->max_id = scsi_debug_num_tgts;
- hpnt->max_lun = scsi_debug_max_luns;
+ hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */
error = scsi_add_host(hpnt, &sdbg_host->dev);
if (error) {
@@ -1960,7 +2976,7 @@ static void sdebug_max_tgts_luns(void)
hpnt->max_id = scsi_debug_num_tgts + 1;
else
hpnt->max_id = scsi_debug_num_tgts;
- hpnt->max_lun = scsi_debug_max_luns;
+ hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */
}
spin_unlock(&sdebug_host_list_lock);
}
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index fb5cb4c9ac6..3d0429bc14a 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -162,7 +162,7 @@ static struct {
{"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
{"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
- {"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */
+ {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
{"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
{"HP", "C1557A", NULL, BLIST_FORCELUN},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 6a7a60fc0a4..3d355d05461 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -460,19 +460,71 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
* Return value:
* SUCCESS or FAILED or NEEDS_RETRY
**/
-static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
+ int cmnd_size, int timeout, int copy_sense)
{
struct scsi_device *sdev = scmd->device;
struct Scsi_Host *shost = sdev->host;
- DECLARE_COMPLETION(done);
+ int old_result = scmd->result;
+ DECLARE_COMPLETION_ONSTACK(done);
unsigned long timeleft;
unsigned long flags;
+ unsigned char old_cmnd[MAX_COMMAND_SIZE];
+ enum dma_data_direction old_data_direction;
+ unsigned short old_use_sg;
+ unsigned char old_cmd_len;
+ unsigned old_bufflen;
+ void *old_buffer;
int rtn;
+ /*
+ * We need saved copies of a number of fields - this is because
+ * error handling may need to overwrite these with different values
+ * to run different commands, and once error handling is complete,
+ * we will need to restore these values prior to running the actual
+ * command.
+ */
+ old_buffer = scmd->request_buffer;
+ old_bufflen = scmd->request_bufflen;
+ memcpy(old_cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ old_data_direction = scmd->sc_data_direction;
+ old_cmd_len = scmd->cmd_len;
+ old_use_sg = scmd->use_sg;
+
+ memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ memcpy(scmd->cmnd, cmnd, cmnd_size);
+
+ if (copy_sense) {
+ int gfp_mask = GFP_ATOMIC;
+
+ if (shost->hostt->unchecked_isa_dma)
+ gfp_mask |= __GFP_DMA;
+
+ scmd->sc_data_direction = DMA_FROM_DEVICE;
+ scmd->request_bufflen = 252;
+ scmd->request_buffer = kzalloc(scmd->request_bufflen, gfp_mask);
+ if (!scmd->request_buffer)
+ return FAILED;
+ } else {
+ scmd->request_buffer = NULL;
+ scmd->request_bufflen = 0;
+ scmd->sc_data_direction = DMA_NONE;
+ }
+
+ scmd->underflow = 0;
+ scmd->use_sg = 0;
+ scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+
if (sdev->scsi_level <= SCSI_2)
scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
(sdev->lun << 5 & 0xe0);
+ /*
+ * Zero the sense buffer. The scsi spec mandates that any
+ * untransferred sense data should be interpreted as being zero.
+ */
+ memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
shost->eh_action = &done;
spin_lock_irqsave(shost->host_lock, flags);
@@ -522,6 +574,29 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
rtn = FAILED;
}
+
+ /*
+ * Last chance to have valid sense data.
+ */
+ if (copy_sense) {
+ if (!SCSI_SENSE_VALID(scmd)) {
+ memcpy(scmd->sense_buffer, scmd->request_buffer,
+ sizeof(scmd->sense_buffer));
+ }
+ kfree(scmd->request_buffer);
+ }
+
+
+ /*
+ * Restore original data
+ */
+ scmd->request_buffer = old_buffer;
+ scmd->request_bufflen = old_bufflen;
+ memcpy(scmd->cmnd, old_cmnd, sizeof(scmd->cmnd));
+ scmd->sc_data_direction = old_data_direction;
+ scmd->cmd_len = old_cmd_len;
+ scmd->use_sg = old_use_sg;
+ scmd->result = old_result;
return rtn;
}
@@ -537,56 +612,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
static int scsi_request_sense(struct scsi_cmnd *scmd)
{
static unsigned char generic_sense[6] =
- {REQUEST_SENSE, 0, 0, 0, 252, 0};
- unsigned char *scsi_result;
- int saved_result;
- int rtn;
-
- memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense));
-
- scsi_result = kmalloc(252, GFP_ATOMIC | ((scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0));
+ {REQUEST_SENSE, 0, 0, 0, 252, 0};
-
- if (unlikely(!scsi_result)) {
- printk(KERN_ERR "%s: cannot allocate scsi_result.\n",
- __FUNCTION__);
- return FAILED;
- }
-
- /*
- * zero the sense buffer. some host adapters automatically always
- * request sense, so it is not a good idea that
- * scmd->request_buffer and scmd->sense_buffer point to the same
- * address (db). 0 is not a valid sense code.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
- memset(scsi_result, 0, 252);
-
- saved_result = scmd->result;
- scmd->request_buffer = scsi_result;
- scmd->request_bufflen = 252;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->sc_data_direction = DMA_FROM_DEVICE;
- scmd->underflow = 0;
-
- rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
-
- /* last chance to have valid sense data */
- if(!SCSI_SENSE_VALID(scmd)) {
- memcpy(scmd->sense_buffer, scmd->request_buffer,
- sizeof(scmd->sense_buffer));
- }
-
- kfree(scsi_result);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
- return rtn;
+ return scsi_send_eh_cmnd(scmd, generic_sense, 6, SENSE_TIMEOUT, 1);
}
/**
@@ -605,12 +633,6 @@ void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q)
{
scmd->device->host->host_failed--;
scmd->eh_eflags = 0;
-
- /*
- * set this back so that the upper level can correctly free up
- * things.
- */
- scsi_setup_cmd_retry(scmd);
list_move_tail(&scmd->eh_entry, done_q);
}
EXPORT_SYMBOL(scsi_eh_finish_cmd);
@@ -715,47 +737,23 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd)
{
static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
int retry_cnt = 1, rtn;
- int saved_result;
retry_tur:
- memcpy(scmd->cmnd, tur_command, sizeof(tur_command));
-
- /*
- * zero the sense buffer. the scsi spec mandates that any
- * untransferred sense data should be interpreted as being zero.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+ rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0);
- saved_result = scmd->result;
- scmd->request_buffer = NULL;
- scmd->request_bufflen = 0;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->underflow = 0;
- scmd->sc_data_direction = DMA_NONE;
-
- rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
-
- /*
- * hey, we are done. let's look to see what happened.
- */
SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
__FUNCTION__, scmd, rtn));
- if (rtn == SUCCESS)
- return 0;
- else if (rtn == NEEDS_RETRY) {
+
+ switch (rtn) {
+ case NEEDS_RETRY:
if (retry_cnt--)
goto retry_tur;
+ /*FALLTHRU*/
+ case SUCCESS:
return 0;
+ default:
+ return 1;
}
- return 1;
}
/**
@@ -837,44 +835,16 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
{
static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
- int rtn;
- int saved_result;
-
- if (!scmd->device->allow_restart)
- return 1;
- memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
-
- /*
- * zero the sense buffer. the scsi spec mandates that any
- * untransferred sense data should be interpreted as being zero.
- */
- memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
-
- saved_result = scmd->result;
- scmd->request_buffer = NULL;
- scmd->request_bufflen = 0;
- scmd->use_sg = 0;
- scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
- scmd->underflow = 0;
- scmd->sc_data_direction = DMA_NONE;
+ if (scmd->device->allow_restart) {
+ int rtn;
- rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT);
-
- /*
- * when we eventually call scsi_finish, we really wish to complete
- * the original request, so let's restore the original data. (db)
- */
- scsi_setup_cmd_retry(scmd);
- scmd->result = saved_result;
+ rtn = scsi_send_eh_cmnd(scmd, stu_command, 6,
+ START_UNIT_TIMEOUT, 0);
+ if (rtn == SUCCESS)
+ return 0;
+ }
- /*
- * hey, we are done. let's look to see what happened.
- */
- SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
- __FUNCTION__, scmd, rtn));
- if (rtn == SUCCESS)
- return 0;
return 1;
}
@@ -1672,7 +1642,9 @@ int
scsi_reset_provider(struct scsi_device *dev, int flag)
{
struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+ struct Scsi_Host *shost = dev->host;
struct request req;
+ unsigned long flags;
int rtn;
scmd->request = &req;
@@ -1682,8 +1654,6 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
scmd->scsi_done = scsi_reset_provider_done_command;
scmd->done = NULL;
- scmd->buffer = NULL;
- scmd->bufflen = 0;
scmd->request_buffer = NULL;
scmd->request_bufflen = 0;
@@ -1699,6 +1669,10 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
*/
scmd->pid = 0;
+ spin_lock_irqsave(shost->host_lock, flags);
+ shost->tmf_in_progress = 1;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
switch (flag) {
case SCSI_TRY_RESET_DEVICE:
rtn = scsi_try_bus_device_reset(scmd);
@@ -1717,6 +1691,22 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
rtn = FAILED;
}
+ spin_lock_irqsave(shost->host_lock, flags);
+ shost->tmf_in_progress = 0;
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ /*
+ * be sure to wake up anyone who was sleeping or had their queue
+ * suspended while we performed the TMF.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,
+ printk("%s: waking up host to restart after TMF\n",
+ __FUNCTION__));
+
+ wake_up(&shost->host_wait);
+
+ scsi_run_host_queues(shost);
+
scsi_next_command(scmd);
return rtn;
}
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index a89c4115cfb..32293f45166 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -110,11 +110,8 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
sshdr.asc, sshdr.ascq);
break;
case NOT_READY: /* This happens if there is no disc in drive */
- if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) {
- printk(KERN_INFO "Device not ready. Make sure"
- " there is a disc in the drive.\n");
+ if (sdev->removable)
break;
- }
case UNIT_ATTENTION:
if (sdev->removable) {
sdev->changed = 1;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 3d04a9f386a..d6743b959a7 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -436,60 +436,16 @@ EXPORT_SYMBOL_GPL(scsi_execute_async);
*
* Arguments: cmd - command that is ready to be queued.
*
- * Returns: Nothing
- *
* Notes: This function has the job of initializing a number of
* fields related to error handling. Typically this will
* be called once for each command, as required.
*/
-static int scsi_init_cmd_errh(struct scsi_cmnd *cmd)
+static void scsi_init_cmd_errh(struct scsi_cmnd *cmd)
{
cmd->serial_number = 0;
-
memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
-
if (cmd->cmd_len == 0)
cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- /*
- * We need saved copies of a number of fields - this is because
- * error handling may need to overwrite these with different values
- * to run different commands, and once error handling is complete,
- * we will need to restore these values prior to running the actual
- * command.
- */
- cmd->old_use_sg = cmd->use_sg;
- cmd->old_cmd_len = cmd->cmd_len;
- cmd->sc_old_data_direction = cmd->sc_data_direction;
- cmd->old_underflow = cmd->underflow;
- memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd));
- cmd->buffer = cmd->request_buffer;
- cmd->bufflen = cmd->request_bufflen;
-
- return 1;
-}
-
-/*
- * Function: scsi_setup_cmd_retry()
- *
- * Purpose: Restore the command state for a retry
- *
- * Arguments: cmd - command to be restored
- *
- * Returns: Nothing
- *
- * Notes: Immediately prior to retrying a command, we need
- * to restore certain fields that we saved above.
- */
-void scsi_setup_cmd_retry(struct scsi_cmnd *cmd)
-{
- memcpy(cmd->cmnd, cmd->data_cmnd, sizeof(cmd->data_cmnd));
- cmd->request_buffer = cmd->buffer;
- cmd->request_bufflen = cmd->bufflen;
- cmd->use_sg = cmd->old_use_sg;
- cmd->cmd_len = cmd->old_cmd_len;
- cmd->sc_data_direction = cmd->sc_old_data_direction;
- cmd->underflow = cmd->old_underflow;
}
void scsi_device_unbusy(struct scsi_device *sdev)
@@ -595,7 +551,15 @@ static void scsi_run_queue(struct request_queue *q)
list_del_init(&sdev->starved_entry);
spin_unlock_irqrestore(shost->host_lock, flags);
- blk_run_queue(sdev->request_queue);
+
+ if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
+ !test_and_set_bit(QUEUE_FLAG_REENTER,
+ &sdev->request_queue->queue_flags)) {
+ blk_run_queue(sdev->request_queue);
+ clear_bit(QUEUE_FLAG_REENTER,
+ &sdev->request_queue->queue_flags);
+ } else
+ blk_run_queue(sdev->request_queue);
spin_lock_irqsave(shost->host_lock, flags);
if (unlikely(!list_empty(&sdev->starved_entry)))
@@ -807,22 +771,13 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
*/
static void scsi_release_buffers(struct scsi_cmnd *cmd)
{
- struct request *req = cmd->request;
-
- /*
- * Free up any indirection buffers we allocated for DMA purposes.
- */
if (cmd->use_sg)
scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
- else if (cmd->request_buffer != req->buffer)
- kfree(cmd->request_buffer);
/*
* Zero these out. They now point to freed memory, and it is
* dangerous to hang onto the pointers.
*/
- cmd->buffer = NULL;
- cmd->bufflen = 0;
cmd->request_buffer = NULL;
cmd->request_bufflen = 0;
}
@@ -855,11 +810,10 @@ static void scsi_release_buffers(struct scsi_cmnd *cmd)
* b) We can just use scsi_requeue_command() here. This would
* be used if we just wanted to retry, for example.
*/
-void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
- unsigned int block_bytes)
+void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
{
int result = cmd->result;
- int this_count = cmd->bufflen;
+ int this_count = cmd->request_bufflen;
request_queue_t *q = cmd->device->request_queue;
struct request *req = cmd->request;
int clear_errors = 1;
@@ -867,28 +821,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
int sense_valid = 0;
int sense_deferred = 0;
- /*
- * Free up any indirection buffers we allocated for DMA purposes.
- * For the case of a READ, we need to copy the data out of the
- * bounce buffer and into the real buffer.
- */
- if (cmd->use_sg)
- scsi_free_sgtable(cmd->buffer, cmd->sglist_len);
- else if (cmd->buffer != req->buffer) {
- if (rq_data_dir(req) == READ) {
- unsigned long flags;
- char *to = bio_kmap_irq(req->bio, &flags);
- memcpy(to, cmd->buffer, cmd->bufflen);
- bio_kunmap_irq(to, &flags);
- }
- kfree(cmd->buffer);
- }
+ scsi_release_buffers(cmd);
if (result) {
sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
+
if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
req->errors = result;
if (result) {
@@ -909,99 +849,73 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
}
/*
- * Zero these out. They now point to freed memory, and it is
- * dangerous to hang onto the pointers.
- */
- cmd->buffer = NULL;
- cmd->bufflen = 0;
- cmd->request_buffer = NULL;
- cmd->request_bufflen = 0;
-
- /*
* Next deal with any sectors which we were able to correctly
* handle.
*/
- if (good_bytes >= 0) {
- SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n",
- req->nr_sectors, good_bytes));
- SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
+ SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, "
+ "%d bytes done.\n",
+ req->nr_sectors, good_bytes));
+ SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
- if (clear_errors)
- req->errors = 0;
- /*
- * If multiple sectors are requested in one buffer, then
- * they will have been finished off by the first command.
- * If not, then we have a multi-buffer command.
- *
- * If block_bytes != 0, it means we had a medium error
- * of some sort, and that we want to mark some number of
- * sectors as not uptodate. Thus we want to inhibit
- * requeueing right here - we will requeue down below
- * when we handle the bad sectors.
- */
+ if (clear_errors)
+ req->errors = 0;
- /*
- * If the command completed without error, then either
- * finish off the rest of the command, or start a new one.
- */
- if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
- return;
- }
- /*
- * Now, if we were good little boys and girls, Santa left us a request
- * sense buffer. We can extract information from this, so we
- * can choose a block to remap, etc.
+ /* A number of bytes were successfully read. If there
+ * are leftovers and there is some kind of error
+ * (result != 0), retry the rest.
+ */
+ if (scsi_end_request(cmd, 1, good_bytes, result == 0) == NULL)
+ return;
+
+ /* good_bytes = 0, or (inclusive) there were leftovers and
+ * result = 0, so scsi_end_request couldn't retry.
*/
if (sense_valid && !sense_deferred) {
switch (sshdr.sense_key) {
case UNIT_ATTENTION:
if (cmd->device->removable) {
- /* detected disc change. set a bit
+ /* Detected disc change. Set a bit
* and quietly refuse further access.
*/
cmd->device->changed = 1;
- scsi_end_request(cmd, 0,
- this_count, 1);
+ scsi_end_request(cmd, 0, this_count, 1);
return;
} else {
- /*
- * Must have been a power glitch, or a
- * bus reset. Could not have been a
- * media change, so we just retry the
- * request and see what happens.
- */
+ /* Must have been a power glitch, or a
+ * bus reset. Could not have been a
+ * media change, so we just retry the
+ * request and see what happens.
+ */
scsi_requeue_command(q, cmd);
return;
}
break;
case ILLEGAL_REQUEST:
- /*
- * If we had an ILLEGAL REQUEST returned, then we may
- * have performed an unsupported command. The only
- * thing this should be would be a ten byte read where
- * only a six byte read was supported. Also, on a
- * system where READ CAPACITY failed, we may have read
- * past the end of the disk.
- */
+ /* If we had an ILLEGAL REQUEST returned, then
+ * we may have performed an unsupported
+ * command. The only thing this should be
+ * would be a ten byte read where only a six
+ * byte read was supported. Also, on a system
+ * where READ CAPACITY failed, we may have
+ * read past the end of the disk.
+ */
if ((cmd->device->use_10_for_rw &&
sshdr.asc == 0x20 && sshdr.ascq == 0x00) &&
(cmd->cmnd[0] == READ_10 ||
cmd->cmnd[0] == WRITE_10)) {
cmd->device->use_10_for_rw = 0;
- /*
- * This will cause a retry with a 6-byte
- * command.
+ /* This will cause a retry with a
+ * 6-byte command.
*/
scsi_requeue_command(q, cmd);
- result = 0;
+ return;
} else {
scsi_end_request(cmd, 0, this_count, 1);
return;
}
break;
case NOT_READY:
- /*
- * If the device is in the process of becoming
+ /* If the device is in the process of becoming
* ready, or has a temporary blockage, retry.
*/
if (sshdr.asc == 0x04) {
@@ -1021,7 +935,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
}
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "Device not ready: ");
+ "Device not ready: ");
scsi_print_sense_hdr("", &sshdr);
}
scsi_end_request(cmd, 0, this_count, 1);
@@ -1029,21 +943,21 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
case VOLUME_OVERFLOW:
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "Volume overflow, CDB: ");
- __scsi_print_command(cmd->data_cmnd);
+ "Volume overflow, CDB: ");
+ __scsi_print_command(cmd->cmnd);
scsi_print_sense("", cmd);
}
- scsi_end_request(cmd, 0, block_bytes, 1);
+ /* See SSC3rXX or current. */
+ scsi_end_request(cmd, 0, this_count, 1);
return;
default:
break;
}
- } /* driver byte != 0 */
+ }
if (host_byte(result) == DID_RESET) {
- /*
- * Third party bus reset or reset for error
- * recovery reasons. Just retry the request
- * and see what happens.
+ /* Third party bus reset or reset for error recovery
+ * reasons. Just retry the request and see what
+ * happens.
*/
scsi_requeue_command(q, cmd);
return;
@@ -1051,21 +965,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
if (result) {
if (!(req->flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
- "SCSI error: return code = 0x%x\n", result);
-
+ "SCSI error: return code = 0x%08x\n",
+ result);
if (driver_byte(result) & DRIVER_SENSE)
scsi_print_sense("", cmd);
}
- /*
- * Mark a single buffer as not uptodate. Queue the remainder.
- * We sometimes get this cruft in the event that a medium error
- * isn't properly reported.
- */
- block_bytes = req->hard_cur_sectors << 9;
- if (!block_bytes)
- block_bytes = req->data_len;
- scsi_end_request(cmd, 0, block_bytes, 1);
}
+ scsi_end_request(cmd, 0, this_count, !result);
}
EXPORT_SYMBOL(scsi_io_completion);
@@ -1169,7 +1075,7 @@ static void scsi_blk_pc_done(struct scsi_cmnd *cmd)
* successfully. Since this is a REQ_BLOCK_PC command the
* caller should check the request's errors value
*/
- scsi_io_completion(cmd, cmd->bufflen, 0);
+ scsi_io_completion(cmd, cmd->request_bufflen);
}
static void scsi_setup_blk_pc_cmnd(struct scsi_cmnd *cmd)
@@ -2050,6 +1956,7 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
switch (oldstate) {
case SDEV_CREATED:
case SDEV_RUNNING:
+ case SDEV_QUIESCE:
case SDEV_OFFLINE:
case SDEV_BLOCK:
break;
@@ -2060,6 +1967,9 @@ scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
case SDEV_DEL:
switch (oldstate) {
+ case SDEV_CREATED:
+ case SDEV_RUNNING:
+ case SDEV_OFFLINE:
case SDEV_CANCEL:
break;
default:
diff --git a/drivers/scsi/scsi_logging.h b/drivers/scsi/scsi_logging.h
index a3e2af6a846..1f65139e14f 100644
--- a/drivers/scsi/scsi_logging.h
+++ b/drivers/scsi/scsi_logging.h
@@ -1,7 +1,6 @@
#ifndef _SCSI_LOGGING_H
#define _SCSI_LOGGING_H
-#include <linux/config.h>
/*
* This defines the scsi logging feature. It is a means by which the user
diff --git a/drivers/scsi/scsi_netlink.c b/drivers/scsi/scsi_netlink.c
new file mode 100644
index 00000000000..1b59b27e887
--- /dev/null
+++ b/drivers/scsi/scsi_netlink.c
@@ -0,0 +1,199 @@
+/*
+ * scsi_netlink.c - SCSI Transport Netlink Interface
+ *
+ * Copyright (C) 2006 James Smart, Emulex Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/time.h>
+#include <linux/jiffies.h>
+#include <linux/security.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+
+#include <scsi/scsi_netlink.h>
+#include "scsi_priv.h"
+
+struct sock *scsi_nl_sock = NULL;
+EXPORT_SYMBOL_GPL(scsi_nl_sock);
+
+
+/**
+ * scsi_nl_rcv_msg -
+ * Receive message handler. Extracts message from a receive buffer.
+ * Validates message header and calls appropriate transport message handler
+ *
+ * @skb: socket receive buffer
+ *
+ **/
+static void
+scsi_nl_rcv_msg(struct sk_buff *skb)
+{
+ struct nlmsghdr *nlh;
+ struct scsi_nl_hdr *hdr;
+ uint32_t rlen;
+ int err;
+
+ while (skb->len >= NLMSG_SPACE(0)) {
+ err = 0;
+
+ nlh = (struct nlmsghdr *) skb->data;
+ if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) ||
+ (skb->len < nlh->nlmsg_len)) {
+ printk(KERN_WARNING "%s: discarding partial skb\n",
+ __FUNCTION__);
+ return;
+ }
+
+ rlen = NLMSG_ALIGN(nlh->nlmsg_len);
+ if (rlen > skb->len)
+ rlen = skb->len;
+
+ if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) {
+ err = -EBADMSG;
+ goto next_msg;
+ }
+
+ hdr = NLMSG_DATA(nlh);
+ if ((hdr->version != SCSI_NL_VERSION) ||
+ (hdr->magic != SCSI_NL_MAGIC)) {
+ err = -EPROTOTYPE;
+ goto next_msg;
+ }
+
+ if (security_netlink_recv(skb, CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto next_msg;
+ }
+
+ if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) {
+ printk(KERN_WARNING "%s: discarding partial message\n",
+ __FUNCTION__);
+ return;
+ }
+
+ /*
+ * We currently don't support anyone sending us a message
+ */
+
+next_msg:
+ if ((err) || (nlh->nlmsg_flags & NLM_F_ACK))
+ netlink_ack(skb, nlh, err);
+
+ skb_pull(skb, rlen);
+ }
+}
+
+
+/**
+ * scsi_nl_rcv_msg -
+ * Receive handler for a socket. Extracts a received message buffer from
+ * the socket, and starts message processing.
+ *
+ * @sk: socket
+ * @len: unused
+ *
+ **/
+static void
+scsi_nl_rcv(struct sock *sk, int len)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+ scsi_nl_rcv_msg(skb);
+ kfree_skb(skb);
+ }
+}
+
+
+/**
+ * scsi_nl_rcv_event -
+ * Event handler for a netlink socket.
+ *
+ * @this: event notifier block
+ * @event: event type
+ * @ptr: event payload
+ *
+ **/
+static int
+scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct netlink_notify *n = ptr;
+
+ if (n->protocol != NETLINK_SCSITRANSPORT)
+ return NOTIFY_DONE;
+
+ /*
+ * Currently, we are not tracking PID's, etc. There is nothing
+ * to handle.
+ */
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block scsi_netlink_notifier = {
+ .notifier_call = scsi_nl_rcv_event,
+};
+
+
+/**
+ * scsi_netlink_init -
+ * Called by SCSI subsystem to intialize the SCSI transport netlink
+ * interface
+ *
+ **/
+void
+scsi_netlink_init(void)
+{
+ int error;
+
+ error = netlink_register_notifier(&scsi_netlink_notifier);
+ if (error) {
+ printk(KERN_ERR "%s: register of event handler failed - %d\n",
+ __FUNCTION__, error);
+ return;
+ }
+
+ scsi_nl_sock = netlink_kernel_create(NETLINK_SCSITRANSPORT,
+ SCSI_NL_GRP_CNT, scsi_nl_rcv, THIS_MODULE);
+ if (!scsi_nl_sock) {
+ printk(KERN_ERR "%s: register of recieve handler failed\n",
+ __FUNCTION__);
+ netlink_unregister_notifier(&scsi_netlink_notifier);
+ }
+
+ return;
+}
+
+
+/**
+ * scsi_netlink_exit -
+ * Called by SCSI subsystem to disable the SCSI transport netlink
+ * interface
+ *
+ **/
+void
+scsi_netlink_exit(void)
+{
+ if (scsi_nl_sock) {
+ sock_release(scsi_nl_sock->sk_socket);
+ netlink_unregister_notifier(&scsi_netlink_notifier);
+ }
+
+ return;
+}
+
+
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index a1727a0e1bd..5d023d44e5e 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -1,7 +1,6 @@
#ifndef _SCSI_PRIV_H
#define _SCSI_PRIV_H
-#include <linux/config.h>
#include <linux/device.h>
struct request_queue;
@@ -9,6 +8,7 @@ struct scsi_cmnd;
struct scsi_device;
struct scsi_host_template;
struct Scsi_Host;
+struct scsi_nl_hdr;
/*
@@ -58,7 +58,6 @@ extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
/* scsi_lib.c */
extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
-extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
extern void scsi_next_command(struct scsi_cmnd *cmd);
@@ -112,12 +111,22 @@ extern void __scsi_remove_device(struct scsi_device *);
extern struct bus_type scsi_bus_type;
+/* scsi_netlink.c */
+#ifdef CONFIG_SCSI_NETLINK
+extern void scsi_netlink_init(void);
+extern void scsi_netlink_exit(void);
+extern struct sock *scsi_nl_sock;
+#else
+static inline void scsi_netlink_init(void) {}
+static inline void scsi_netlink_exit(void) {}
+#endif
+
/*
* internal scsi timeout functions: for use by mid-layer and transport
* classes.
*/
-#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT (HZ*60)
+#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT 600 /* units in seconds */
extern int scsi_internal_device_block(struct scsi_device *sdev);
extern int scsi_internal_device_unblock(struct scsi_device *sdev);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 55200e4fdf1..524a5f7a519 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -178,9 +178,7 @@ static int proc_print_scsidevice(struct device *dev, void *data)
seq_printf(s, "\n");
- seq_printf(s, " Type: %s ",
- sdev->type < MAX_SCSI_DEVICE_CODE ?
- scsi_device_types[(int) sdev->type] : "Unknown ");
+ seq_printf(s, " Type: %s ", scsi_device_type(sdev->type));
seq_printf(s, " ANSI"
" SCSI revision: %02x", (sdev->scsi_level - 1) ?
sdev->scsi_level - 1 : 1);
diff --git a/drivers/scsi/scsi_sas_internal.h b/drivers/scsi/scsi_sas_internal.h
index d76e6e3d8ca..e1edab45a37 100644
--- a/drivers/scsi/scsi_sas_internal.h
+++ b/drivers/scsi/scsi_sas_internal.h
@@ -2,7 +2,8 @@
#define _SCSI_SAS_INTERNAL_H
#define SAS_HOST_ATTRS 0
-#define SAS_PORT_ATTRS 17
+#define SAS_PHY_ATTRS 17
+#define SAS_PORT_ATTRS 1
#define SAS_RPORT_ATTRS 7
#define SAS_END_DEV_ATTRS 3
#define SAS_EXPANDER_ATTRS 7
@@ -13,12 +14,14 @@ struct sas_internal {
struct sas_domain_function_template *dft;
struct class_device_attribute private_host_attrs[SAS_HOST_ATTRS];
- struct class_device_attribute private_phy_attrs[SAS_PORT_ATTRS];
+ struct class_device_attribute private_phy_attrs[SAS_PHY_ATTRS];
+ struct class_device_attribute private_port_attrs[SAS_PORT_ATTRS];
struct class_device_attribute private_rphy_attrs[SAS_RPORT_ATTRS];
struct class_device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS];
struct class_device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS];
struct transport_container phy_attr_cont;
+ struct transport_container port_attr_cont;
struct transport_container rphy_attr_cont;
struct transport_container end_dev_attr_cont;
struct transport_container expander_attr_cont;
@@ -28,7 +31,8 @@ struct sas_internal {
* needed by scsi_sysfs.c
*/
struct class_device_attribute *host_attrs[SAS_HOST_ATTRS + 1];
- struct class_device_attribute *phy_attrs[SAS_PORT_ATTRS + 1];
+ struct class_device_attribute *phy_attrs[SAS_PHY_ATTRS + 1];
+ struct class_device_attribute *port_attrs[SAS_PORT_ATTRS + 1];
struct class_device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1];
struct class_device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1];
struct class_device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1];
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0f7e6f94d66..fd9e281c3bf 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -25,7 +25,6 @@
* or a LUN is seen that cannot have a device attached to it.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -135,59 +134,6 @@ static void scsi_unlock_floptical(struct scsi_device *sdev,
}
/**
- * print_inquiry - printk the inquiry information
- * @inq_result: printk this SCSI INQUIRY
- *
- * Description:
- * printk the vendor, model, and other information found in the
- * INQUIRY data in @inq_result.
- *
- * Notes:
- * Remove this, and replace with a hotplug event that logs any
- * relevant information.
- **/
-static void print_inquiry(unsigned char *inq_result)
-{
- int i;
-
- printk(KERN_NOTICE " Vendor: ");
- for (i = 8; i < 16; i++)
- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
- printk("%c", inq_result[i]);
- else
- printk(" ");
-
- printk(" Model: ");
- for (i = 16; i < 32; i++)
- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
- printk("%c", inq_result[i]);
- else
- printk(" ");
-
- printk(" Rev: ");
- for (i = 32; i < 36; i++)
- if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
- printk("%c", inq_result[i]);
- else
- printk(" ");
-
- printk("\n");
-
- i = inq_result[0] & 0x1f;
-
- printk(KERN_NOTICE " Type: %s ",
- i <
- MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
- "Unknown ");
- printk(" ANSI SCSI revision: %02x",
- inq_result[2] & 0x07);
- if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)
- printk(" CCS\n");
- else
- printk("\n");
-}
-
-/**
* scsi_alloc_sdev - allocate and setup a scsi_Device
*
* Description:
@@ -320,6 +266,18 @@ static struct scsi_target *__scsi_find_target(struct device *parent,
return found_starget;
}
+/**
+ * scsi_alloc_target - allocate a new or find an existing target
+ * @parent: parent of the target (need not be a scsi host)
+ * @channel: target channel number (zero if no channels)
+ * @id: target id number
+ *
+ * Return an existing target if one exists, provided it hasn't already
+ * gone into STARGET_DEL state, otherwise allocate a new target.
+ *
+ * The target is returned with an incremented reference, so the caller
+ * is responsible for both reaping and doing a last put
+ */
static struct scsi_target *scsi_alloc_target(struct device *parent,
int channel, uint id)
{
@@ -385,14 +343,15 @@ static struct scsi_target *scsi_alloc_target(struct device *parent,
return NULL;
}
}
+ get_device(dev);
return starget;
found:
found_target->reap_ref++;
spin_unlock_irqrestore(shost->host_lock, flags);
- put_device(parent);
if (found_target->state != STARGET_DEL) {
+ put_device(parent);
kfree(starget);
return found_target;
}
@@ -451,6 +410,32 @@ void scsi_target_reap(struct scsi_target *starget)
}
/**
+ * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string
+ * @s: INQUIRY result string to sanitize
+ * @len: length of the string
+ *
+ * Description:
+ * The SCSI spec says that INQUIRY vendor, product, and revision
+ * strings must consist entirely of graphic ASCII characters,
+ * padded on the right with spaces. Since not all devices obey
+ * this rule, we will replace non-graphic or non-ASCII characters
+ * with spaces. Exception: a NUL character is interpreted as a
+ * string terminator, so all the following characters are set to
+ * spaces.
+ **/
+static void sanitize_inquiry_string(unsigned char *s, int len)
+{
+ int terminated = 0;
+
+ for (; len > 0; (--len, ++s)) {
+ if (*s == 0)
+ terminated = 1;
+ if (terminated || *s < 0x20 || *s > 0x7e)
+ *s = ' ';
+ }
+}
+
+/**
* scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
* @sdev: scsi_device to probe
* @inq_result: area to store the INQUIRY result
@@ -464,7 +449,7 @@ void scsi_target_reap(struct scsi_target *starget)
* INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
* are copied to the scsi_device any flags value is stored in *@bflags.
**/
-static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
+static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
int result_len, int *bflags)
{
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
@@ -523,7 +508,11 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
}
if (result == 0) {
- response_len = (unsigned char) inq_result[4] + 5;
+ sanitize_inquiry_string(&inq_result[8], 8);
+ sanitize_inquiry_string(&inq_result[16], 16);
+ sanitize_inquiry_string(&inq_result[32], 4);
+
+ response_len = inq_result[4] + 5;
if (response_len > 255)
response_len = first_inquiry_len; /* sanity */
@@ -629,7 +618,8 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result,
* SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device
* SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized
**/
-static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
+static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
+ int *bflags)
{
/*
* XXX do not save the inquiry, since it can change underneath us,
@@ -654,9 +644,8 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
if (*bflags & BLIST_ISROM) {
/*
* It would be better to modify sdev->type, and set
- * sdev->removable, but then the print_inquiry() output
- * would not show TYPE_ROM; if print_inquiry() is removed
- * the issue goes away.
+ * sdev->removable; this can now be done since
+ * print_inquiry has gone away.
*/
inq_result[0] = TYPE_ROM;
inq_result[1] |= 0x80; /* removable */
@@ -685,8 +674,6 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
}
- print_inquiry(inq_result);
-
/*
* For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
* spec says: The device server is capable of supporting the
@@ -716,6 +703,12 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
if (inq_result[7] & 0x10)
sdev->sdtr = 1;
+ sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d "
+ "ANSI: %d%s\n", scsi_device_type(sdev->type),
+ sdev->vendor, sdev->model, sdev->rev,
+ sdev->inq_periph_qual, inq_result[2] & 0x07,
+ (inq_result[3] & 0x0f) == 1 ? " CCS" : "");
+
/*
* End sysfs code.
*/
@@ -810,6 +803,7 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
static inline void scsi_destroy_sdev(struct scsi_device *sdev)
{
+ scsi_device_set_state(sdev, SDEV_DEL);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
transport_destroy_device(&sdev->sdev_gendev);
@@ -943,11 +937,26 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget,
}
/*
- * Non-standard SCSI targets may set the PDT to 0x1f (unknown or
- * no device type) instead of using the Peripheral Qualifier to
- * indicate that no LUN is present. For example, USB UFI does this.
+ * Some targets may set slight variations of PQ and PDT to signal
+ * that no LUN is present, so don't add sdev in these cases.
+ * Two specific examples are:
+ * 1) NetApp targets: return PQ=1, PDT=0x1f
+ * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved"
+ * in the UFI 1.0 spec (we cannot rely on reserved bits).
+ *
+ * References:
+ * 1) SCSI SPC-3, pp. 145-146
+ * PQ=1: "A peripheral device having the specified peripheral
+ * device type is not connected to this logical unit. However, the
+ * device server is capable of supporting the specified peripheral
+ * device type on this logical unit."
+ * PDT=0x1f: "Unknown or no device type"
+ * 2) USB UFI 1.0, p. 20
+ * PDT=00h Direct-access device (floppy)
+ * PDT=1Fh none (no FDD connected to the requested logical unit)
*/
- if (starget->pdt_1f_for_no_lun && (result[0] & 0x1f) == 0x1f) {
+ if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) &&
+ (result[0] & 0x1f) == 0x1f) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: peripheral device type"
" of 31, no device added\n"));
@@ -1345,7 +1354,6 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (!starget)
return ERR_PTR(-ENOMEM);
- get_device(&starget->dev);
mutex_lock(&shost->scan_mutex);
if (scsi_host_scan_allowed(shost))
scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
@@ -1404,7 +1412,6 @@ static void __scsi_scan_target(struct device *parent, unsigned int channel,
if (!starget)
return;
- get_device(&starget->dev);
if (lun != SCAN_WILD_CARD) {
/*
* Scan for a specific host/chan/id/lun.
@@ -1586,7 +1593,8 @@ struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
if (sdev) {
sdev->sdev_gendev.parent = get_device(&starget->dev);
sdev->borken = 0;
- }
+ } else
+ scsi_target_reap(starget);
put_device(&starget->dev);
out:
mutex_unlock(&shost->scan_mutex);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5ec7a4fb014..e7fe565b96d 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -6,7 +6,6 @@
* Created to pull SCSI mid layer sysfs routines into one file.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/blkdev.h>
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index f2db7a41cf1..38c215a78f6 100644
--- a/drivers/scsi/scsi_transport_fc.c
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -32,6 +32,9 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include <scsi/scsi_cmnd.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <scsi/scsi_netlink_fc.h>
#include "scsi_priv.h"
static int fc_queue_work(struct Scsi_Host *, struct work_struct *);
@@ -93,6 +96,29 @@ fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
#define FC_PORTTYPE_MAX_NAMELEN 50
+/* Convert fc_host_event_code values to ascii string name */
+static const struct {
+ enum fc_host_event_code value;
+ char *name;
+} fc_host_event_code_names[] = {
+ { FCH_EVT_LIP, "lip" },
+ { FCH_EVT_LINKUP, "link_up" },
+ { FCH_EVT_LINKDOWN, "link_down" },
+ { FCH_EVT_LIPRESET, "lip_reset" },
+ { FCH_EVT_RSCN, "rscn" },
+ { FCH_EVT_ADAPTER_CHANGE, "adapter_chg" },
+ { FCH_EVT_PORT_UNKNOWN, "port_unknown" },
+ { FCH_EVT_PORT_ONLINE, "port_online" },
+ { FCH_EVT_PORT_OFFLINE, "port_offline" },
+ { FCH_EVT_PORT_FABRIC, "port_fabric" },
+ { FCH_EVT_LINK_UNKNOWN, "link_unknown" },
+ { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" },
+};
+fc_enum_name_search(host_event_code, fc_host_event_code,
+ fc_host_event_code_names)
+#define FC_HOST_EVENT_CODE_MAX_NAMELEN 30
+
+
/* Convert fc_port_state values to ascii string name */
static struct {
enum fc_port_state value;
@@ -216,6 +242,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
static void fc_timeout_deleted_rport(void *data);
+static void fc_timeout_fail_rport_io(void *data);
static void fc_scsi_scan_rport(void *data);
/*
@@ -223,7 +250,7 @@ static void fc_scsi_scan_rport(void *data);
* Increase these values if you add attributes
*/
#define FC_STARGET_NUM_ATTRS 3
-#define FC_RPORT_NUM_ATTRS 9
+#define FC_RPORT_NUM_ATTRS 10
#define FC_HOST_NUM_ATTRS 17
struct fc_internal {
@@ -301,8 +328,6 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
fc_host->supported_classes = FC_COS_UNSPECIFIED;
memset(fc_host->supported_fc4s, 0,
sizeof(fc_host->supported_fc4s));
- memset(fc_host->symbolic_name, 0,
- sizeof(fc_host->symbolic_name));
fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN;
fc_host->maxframe_size = -1;
memset(fc_host->serial_number, 0,
@@ -315,6 +340,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev,
sizeof(fc_host->active_fc4s));
fc_host->speed = FC_PORTSPEED_UNKNOWN;
fc_host->fabric_name = -1;
+ memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name));
+ memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname));
fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN;
@@ -368,7 +395,7 @@ static DECLARE_TRANSPORT_CLASS(fc_rport_class,
* should insulate the loss of a remote port.
* The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
*/
-static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT;
+static unsigned int fc_dev_loss_tmo = 60; /* seconds */
module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(dev_loss_tmo,
@@ -377,10 +404,184 @@ MODULE_PARM_DESC(dev_loss_tmo,
" exceeded, the scsi target is removed. Value should be"
" between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+/**
+ * Netlink Infrastructure
+ **/
+
+static atomic_t fc_event_seq;
+
+/**
+ * fc_get_event_number - Obtain the next sequential FC event number
+ *
+ * Notes:
+ * We could have inline'd this, but it would have required fc_event_seq to
+ * be exposed. For now, live with the subroutine call.
+ * Atomic used to avoid lock/unlock...
+ **/
+u32
+fc_get_event_number(void)
+{
+ return atomic_add_return(1, &fc_event_seq);
+}
+EXPORT_SYMBOL(fc_get_event_number);
+
+
+/**
+ * fc_host_post_event - called to post an even on an fc_host.
+ *
+ * @shost: host the event occurred on
+ * @event_number: fc event number obtained from get_fc_event_number()
+ * @event_code: fc_host event being posted
+ * @event_data: 32bits of data for the event being posted
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void
+fc_host_post_event(struct Scsi_Host *shost, u32 event_number,
+ enum fc_host_event_code event_code, u32 event_data)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct fc_nl_event *event;
+ const char *name;
+ u32 len, skblen;
+ int err;
+
+ if (!scsi_nl_sock) {
+ err = -ENOENT;
+ goto send_fail;
+ }
+
+ len = FC_NL_MSGALIGN(sizeof(*event));
+ skblen = NLMSG_SPACE(len);
+
+ skb = alloc_skb(skblen, GFP_KERNEL);
+ if (!skb) {
+ err = -ENOBUFS;
+ goto send_fail;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+ skblen - sizeof(*nlh), 0);
+ if (!nlh) {
+ err = -ENOBUFS;
+ goto send_fail_skb;
+ }
+ event = NLMSG_DATA(nlh);
+
+ INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
+ FC_NL_ASYNC_EVENT, len);
+ event->seconds = get_seconds();
+ event->vendor_id = 0;
+ event->host_no = shost->host_no;
+ event->event_datalen = sizeof(u32); /* bytes */
+ event->event_num = event_number;
+ event->event_code = event_code;
+ event->event_data = event_data;
+
+ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
+ GFP_KERNEL);
+ if (err && (err != -ESRCH)) /* filter no recipient errors */
+ /* nlmsg_multicast already kfree_skb'd */
+ goto send_fail;
+
+ return;
+
+send_fail_skb:
+ kfree_skb(skb);
+send_fail:
+ name = get_fc_host_event_code_name(event_code);
+ printk(KERN_WARNING
+ "%s: Dropped Event : host %d %s data 0x%08x - err %d\n",
+ __FUNCTION__, shost->host_no,
+ (name) ? name : "<unknown>", event_data, err);
+ return;
+}
+EXPORT_SYMBOL(fc_host_post_event);
+
+
+/**
+ * fc_host_post_vendor_event - called to post a vendor unique event on
+ * a fc_host
+ *
+ * @shost: host the event occurred on
+ * @event_number: fc event number obtained from get_fc_event_number()
+ * @data_len: amount, in bytes, of vendor unique data
+ * @data_buf: pointer to vendor unique data
+ *
+ * Notes:
+ * This routine assumes no locks are held on entry.
+ **/
+void
+fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number,
+ u32 data_len, char * data_buf, u64 vendor_id)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ struct fc_nl_event *event;
+ u32 len, skblen;
+ int err;
+
+ if (!scsi_nl_sock) {
+ err = -ENOENT;
+ goto send_vendor_fail;
+ }
+
+ len = FC_NL_MSGALIGN(sizeof(*event) + data_len);
+ skblen = NLMSG_SPACE(len);
+
+ skb = alloc_skb(skblen, GFP_KERNEL);
+ if (!skb) {
+ err = -ENOBUFS;
+ goto send_vendor_fail;
+ }
+
+ nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG,
+ skblen - sizeof(*nlh), 0);
+ if (!nlh) {
+ err = -ENOBUFS;
+ goto send_vendor_fail_skb;
+ }
+ event = NLMSG_DATA(nlh);
+
+ INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC,
+ FC_NL_ASYNC_EVENT, len);
+ event->seconds = get_seconds();
+ event->vendor_id = vendor_id;
+ event->host_no = shost->host_no;
+ event->event_datalen = data_len; /* bytes */
+ event->event_num = event_number;
+ event->event_code = FCH_EVT_VENDOR_UNIQUE;
+ memcpy(&event->event_data, data_buf, data_len);
+
+ err = nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS,
+ GFP_KERNEL);
+ if (err && (err != -ESRCH)) /* filter no recipient errors */
+ /* nlmsg_multicast already kfree_skb'd */
+ goto send_vendor_fail;
+
+ return;
+
+send_vendor_fail_skb:
+ kfree_skb(skb);
+send_vendor_fail:
+ printk(KERN_WARNING
+ "%s: Dropped Event : host %d vendor_unique - err %d\n",
+ __FUNCTION__, shost->host_no, err);
+ return;
+}
+EXPORT_SYMBOL(fc_host_post_vendor_event);
+
+
static __init int fc_transport_init(void)
{
- int error = transport_class_register(&fc_host_class);
+ int error;
+
+ atomic_set(&fc_event_seq, 0);
+
+ error = transport_class_register(&fc_host_class);
if (error)
return error;
error = transport_class_register(&fc_rport_class);
@@ -424,11 +625,14 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \
struct fc_rport *rport = transport_class_to_rport(cdev); \
struct Scsi_Host *shost = rport_to_shost(rport); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
+ char *cp; \
if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \
(rport->port_state == FC_PORTSTATE_DELETED) || \
(rport->port_state == FC_PORTSTATE_NOTPRESENT)) \
return -EBUSY; \
- val = simple_strtoul(buf, NULL, 0); \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
i->f->set_rport_##field(rport, val); \
return count; \
}
@@ -510,6 +714,13 @@ static FC_CLASS_DEVICE_ATTR(rport, title, S_IRUGO, \
if (i->f->show_rport_##field) \
count++
+#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \
+{ \
+ i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+ i->rport_attrs[count] = &i->private_rport_attrs[count]; \
+ count++; \
+}
+
/* The FC Transport Remote Port Attributes: */
@@ -542,12 +753,14 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf,
struct fc_rport *rport = transport_class_to_rport(cdev);
struct Scsi_Host *shost = rport_to_shost(rport);
struct fc_internal *i = to_fc_internal(shost->transportt);
+ char *cp;
if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
(rport->port_state == FC_PORTSTATE_DELETED) ||
(rport->port_state == FC_PORTSTATE_NOTPRESENT))
return -EBUSY;
- val = simple_strtoul(buf, NULL, 0);
- if ((val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
+ val = simple_strtoul(buf, &cp, 0);
+ if ((*cp && (*cp != '\n')) ||
+ (val < 0) || (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT))
return -EINVAL;
i->f->set_rport_dev_loss_tmo(rport, val);
return count;
@@ -597,6 +810,44 @@ static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20);
+/*
+ * fast_io_fail_tmo attribute
+ */
+static ssize_t
+show_fc_rport_fast_io_fail_tmo (struct class_device *cdev, char *buf)
+{
+ struct fc_rport *rport = transport_class_to_rport(cdev);
+
+ if (rport->fast_io_fail_tmo == -1)
+ return snprintf(buf, 5, "off\n");
+ return snprintf(buf, 20, "%d\n", rport->fast_io_fail_tmo);
+}
+
+static ssize_t
+store_fc_rport_fast_io_fail_tmo(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ int val;
+ char *cp;
+ struct fc_rport *rport = transport_class_to_rport(cdev);
+
+ if ((rport->port_state == FC_PORTSTATE_BLOCKED) ||
+ (rport->port_state == FC_PORTSTATE_DELETED) ||
+ (rport->port_state == FC_PORTSTATE_NOTPRESENT))
+ return -EBUSY;
+ if (strncmp(buf, "off", 3) == 0)
+ rport->fast_io_fail_tmo = -1;
+ else {
+ val = simple_strtoul(buf, &cp, 0);
+ if ((*cp && (*cp != '\n')) ||
+ (val < 0) || (val >= rport->dev_loss_tmo))
+ return -EINVAL;
+ rport->fast_io_fail_tmo = val;
+ }
+ return count;
+}
+static FC_CLASS_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR,
+ show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo);
/*
@@ -682,12 +933,34 @@ store_fc_host_##field(struct class_device *cdev, const char *buf, \
int val; \
struct Scsi_Host *shost = transport_class_to_shost(cdev); \
struct fc_internal *i = to_fc_internal(shost->transportt); \
+ char *cp; \
\
- val = simple_strtoul(buf, NULL, 0); \
+ val = simple_strtoul(buf, &cp, 0); \
+ if (*cp && (*cp != '\n')) \
+ return -EINVAL; \
i->f->set_host_##field(shost, val); \
return count; \
}
+#define fc_host_store_str_function(field, slen) \
+static ssize_t \
+store_fc_host_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct Scsi_Host *shost = transport_class_to_shost(cdev); \
+ struct fc_internal *i = to_fc_internal(shost->transportt); \
+ unsigned int cnt=count; \
+ \
+ /* count may include a LF at end of string */ \
+ if (buf[cnt-1] == '\n') \
+ cnt--; \
+ if (cnt > ((slen) - 1)) \
+ return -EINVAL; \
+ memcpy(fc_host_##field(shost), buf, cnt); \
+ i->f->set_host_##field(shost); \
+ return count; \
+}
+
#define fc_host_rd_attr(field, format_string, sz) \
fc_host_show_function(field, format_string, sz, ) \
static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO, \
@@ -815,7 +1088,6 @@ fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20,
unsigned long long);
-fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
@@ -858,6 +1130,13 @@ fc_host_rd_attr(port_id, "0x%06x\n", 20);
fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN);
fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
+fc_host_rd_attr(symbolic_name, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1);
+
+fc_private_host_show_function(system_hostname, "%s\n",
+ FC_SYMBOLIC_NAME_SIZE + 1, )
+fc_host_store_str_function(system_hostname, FC_SYMBOLIC_NAME_SIZE)
+static FC_CLASS_DEVICE_ATTR(host, system_hostname, S_IRUGO | S_IWUSR,
+ show_fc_host_system_hostname, store_fc_host_system_hostname);
/* Private Host Attributes */
@@ -1223,7 +1502,6 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_HOST_ATTRIBUTE_RD(permanent_port_name);
SETUP_HOST_ATTRIBUTE_RD(supported_classes);
SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
- SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
SETUP_HOST_ATTRIBUTE_RD(serial_number);
@@ -1234,6 +1512,8 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_HOST_ATTRIBUTE_RD(active_fc4s);
SETUP_HOST_ATTRIBUTE_RD(speed);
SETUP_HOST_ATTRIBUTE_RD(fabric_name);
+ SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
+ SETUP_HOST_ATTRIBUTE_RW(system_hostname);
/* Transport-managed attributes */
SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
@@ -1257,6 +1537,8 @@ fc_attach_transport(struct fc_function_template *ft)
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
+ if (ft->terminate_rport_io)
+ SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo);
BUG_ON(count > FC_RPORT_NUM_ATTRS);
@@ -1284,7 +1566,9 @@ EXPORT_SYMBOL(fc_release_transport);
* @work: Work to queue for execution.
*
* Return value:
- * 0 on success / != 0 for error
+ * 1 - work queued for execution
+ * 0 - work is already queued
+ * -EINVAL - work queue doesn't exist
**/
static int
fc_queue_work(struct Scsi_Host *shost, struct work_struct *work)
@@ -1326,7 +1610,7 @@ fc_flush_work(struct Scsi_Host *shost)
* @delay: jiffies to delay the work queuing
*
* Return value:
- * 0 on success / != 0 for error
+ * 1 on success / 0 already queued / < 0 for error
**/
static int
fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
@@ -1341,6 +1625,9 @@ fc_queue_devloss_work(struct Scsi_Host *shost, struct work_struct *work,
return -EINVAL;
}
+ if (delay == 0)
+ return queue_work(fc_host_devloss_work_q(shost), work);
+
return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay);
}
@@ -1433,12 +1720,23 @@ fc_starget_delete(void *data)
struct fc_rport *rport = (struct fc_rport *)data;
struct Scsi_Host *shost = rport_to_shost(rport);
unsigned long flags;
+ struct fc_internal *i = to_fc_internal(shost->transportt);
- scsi_target_unblock(&rport->dev);
+ /*
+ * Involve the LLDD if possible. All io on the rport is to
+ * be terminated, either as part of the dev_loss_tmo callback
+ * processing, or via the terminate_rport_io function.
+ */
+ if (i->f->dev_loss_tmo_callbk)
+ i->f->dev_loss_tmo_callbk(rport);
+ else if (i->f->terminate_rport_io)
+ i->f->terminate_rport_io(rport);
spin_lock_irqsave(shost->host_lock, flags);
if (rport->flags & FC_RPORT_DEVLOSS_PENDING) {
spin_unlock_irqrestore(shost->host_lock, flags);
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);
spin_lock_irqsave(shost->host_lock, flags);
@@ -1461,10 +1759,7 @@ fc_rport_final_delete(void *data)
struct fc_rport *rport = (struct fc_rport *)data;
struct device *dev = &rport->dev;
struct Scsi_Host *shost = rport_to_shost(rport);
-
- /* Delete SCSI target and sdevs */
- if (rport->scsi_target_id != -1)
- fc_starget_delete(data);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
/*
* if a scan is pending, flush the SCSI Host work_q so that
@@ -1473,10 +1768,19 @@ fc_rport_final_delete(void *data)
if (rport->flags & FC_RPORT_SCAN_PENDING)
scsi_flush_work(shost);
+ /* Delete SCSI target and sdevs */
+ if (rport->scsi_target_id != -1)
+ fc_starget_delete(data);
+ else if (i->f->dev_loss_tmo_callbk)
+ i->f->dev_loss_tmo_callbk(rport);
+ else if (i->f->terminate_rport_io)
+ i->f->terminate_rport_io(rport);
+
transport_remove_device(dev);
device_del(dev);
transport_destroy_device(dev);
- put_device(&shost->shost_gendev);
+ put_device(&shost->shost_gendev); /* for fc_host->rport list */
+ put_device(dev); /* for self-reference */
}
@@ -1523,8 +1827,10 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
if (fci->f->dd_fcrport_size)
rport->dd_data = &rport[1];
rport->channel = channel;
+ rport->fast_io_fail_tmo = -1;
INIT_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport, rport);
+ INIT_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io, rport);
INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
INIT_WORK(&rport->stgt_delete_work, fc_starget_delete, rport);
INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete, rport);
@@ -1537,13 +1843,13 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
else
rport->scsi_target_id = -1;
list_add_tail(&rport->peers, &fc_host->rports);
- get_device(&shost->shost_gendev);
+ get_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
dev = &rport->dev;
- device_initialize(dev);
- dev->parent = get_device(&shost->shost_gendev);
+ device_initialize(dev); /* takes self reference */
+ dev->parent = get_device(&shost->shost_gendev); /* parent reference */
dev->release = fc_rport_dev_release;
sprintf(dev->bus_id, "rport-%d:%d-%d",
shost->host_no, channel, rport->number);
@@ -1567,10 +1873,9 @@ fc_rport_create(struct Scsi_Host *shost, int channel,
delete_rport:
transport_destroy_device(dev);
- put_device(dev->parent);
spin_lock_irqsave(shost->host_lock, flags);
list_del(&rport->peers);
- put_device(&shost->shost_gendev);
+ put_device(&shost->shost_gendev); /* for fc_host->rport list */
spin_unlock_irqrestore(shost->host_lock, flags);
put_device(dev->parent);
kfree(rport);
@@ -1689,11 +1994,13 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
/* restart the target */
/*
- * Stop the target timer first. Take no action
+ * Stop the target timers first. Take no action
* on the del_timer failure as the state
* machine state change will validate the
* transaction.
*/
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
if (!cancel_delayed_work(work))
fc_flush_devloss(shost);
@@ -1707,6 +2014,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
+
return rport;
}
}
@@ -1762,9 +2071,10 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel,
/* initiate a scan of the target */
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
- }
-
- spin_unlock_irqrestore(shost->host_lock, flags);
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
+ } else
+ spin_unlock_irqrestore(shost->host_lock, flags);
return rport;
}
@@ -1834,6 +2144,7 @@ void
fc_remote_port_delete(struct fc_rport *rport)
{
struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
int timeout = rport->dev_loss_tmo;
unsigned long flags;
@@ -1864,6 +2175,12 @@ fc_remote_port_delete(struct fc_rport *rport)
scsi_target_block(&rport->dev);
+ /* see if we need to kill io faster than waiting for device loss */
+ if ((rport->fast_io_fail_tmo != -1) &&
+ (rport->fast_io_fail_tmo < timeout) && (i->f->terminate_rport_io))
+ fc_queue_devloss_work(shost, &rport->fail_io_work,
+ rport->fast_io_fail_tmo * HZ);
+
/* cap the length the devices can be blocked until they are deleted */
fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ);
}
@@ -1923,6 +2240,8 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
* machine state change will validate the
* transaction.
*/
+ if (!cancel_delayed_work(&rport->fail_io_work))
+ fc_flush_devloss(shost);
if (!cancel_delayed_work(&rport->dev_loss_work))
fc_flush_devloss(shost);
@@ -1938,6 +2257,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles)
rport->flags |= FC_RPORT_SCAN_PENDING;
scsi_queue_work(shost, &rport->scan_work);
spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
}
}
EXPORT_SYMBOL(fc_remote_port_rolechg);
@@ -1970,8 +2290,9 @@ fc_timeout_deleted_rport(void *data)
dev_printk(KERN_ERR, &rport->dev,
"blocked FC remote port time out: no longer"
" a FCP target, removing starget\n");
- fc_queue_work(shost, &rport->stgt_delete_work);
spin_unlock_irqrestore(shost->host_lock, flags);
+ scsi_target_unblock(&rport->dev);
+ fc_queue_work(shost, &rport->stgt_delete_work);
return;
}
@@ -2035,17 +2356,37 @@ fc_timeout_deleted_rport(void *data)
* went away and didn't come back - we'll remove
* all attached scsi devices.
*/
+ spin_unlock_irqrestore(shost->host_lock, flags);
+
+ scsi_target_unblock(&rport->dev);
fc_queue_work(shost, &rport->stgt_delete_work);
+}
- spin_unlock_irqrestore(shost->host_lock, flags);
+/**
+ * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a
+ * disconnected SCSI target.
+ *
+ * @data: rport to terminate io on.
+ *
+ * Notes: Only requests the failure of the io, not that all are flushed
+ * prior to returning.
+ **/
+static void
+fc_timeout_fail_rport_io(void *data)
+{
+ struct fc_rport *rport = (struct fc_rport *)data;
+ struct Scsi_Host *shost = rport_to_shost(rport);
+ struct fc_internal *i = to_fc_internal(shost->transportt);
+
+ if (rport->port_state != FC_PORTSTATE_BLOCKED)
+ return;
+
+ i->f->terminate_rport_io(rport);
}
/**
* fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
*
- * Will unblock the target (in case it went away and has now come back),
- * then invoke a scan.
- *
* @data: remote port to be scanned.
**/
static void
@@ -2057,7 +2398,6 @@ fc_scsi_scan_rport(void *data)
if ((rport->port_state == FC_PORTSTATE_ONLINE) &&
(rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
- scsi_target_unblock(&rport->dev);
scsi_scan_target(&rport->dev, rport->channel,
rport->scsi_target_id, SCAN_WILD_CARD, 1);
}
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 5569fdcfd62..7b0019cccce 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -34,6 +34,7 @@
#define ISCSI_SESSION_ATTRS 11
#define ISCSI_CONN_ATTRS 11
#define ISCSI_HOST_ATTRS 0
+#define ISCSI_TRANSPORT_VERSION "2.0-685"
struct iscsi_internal {
int daemon_pid;
@@ -228,14 +229,11 @@ static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid)
static void iscsi_session_release(struct device *dev)
{
struct iscsi_cls_session *session = iscsi_dev_to_session(dev);
- struct iscsi_transport *transport = session->transport;
struct Scsi_Host *shost;
shost = iscsi_session_to_shost(session);
scsi_host_put(shost);
- kfree(session->targetname);
kfree(session);
- module_put(transport->owner);
}
static int iscsi_is_session_dev(const struct device *dev)
@@ -251,10 +249,9 @@ static int iscsi_user_scan(struct Scsi_Host *shost, uint channel,
mutex_lock(&ihost->mutex);
list_for_each_entry(session, &ihost->sessions, host_list) {
- if ((channel == SCAN_WILD_CARD ||
- channel == session->channel) &&
+ if ((channel == SCAN_WILD_CARD || channel == 0) &&
(id == SCAN_WILD_CARD || id == session->target_id))
- scsi_scan_target(&session->dev, session->channel,
+ scsi_scan_target(&session->dev, 0,
session->target_id, lun, 1);
}
mutex_unlock(&ihost->mutex);
@@ -291,80 +288,92 @@ void iscsi_block_session(struct iscsi_cls_session *session)
}
EXPORT_SYMBOL_GPL(iscsi_block_session);
-/**
- * iscsi_create_session - create iscsi class session
- * @shost: scsi host
- * @transport: iscsi transport
- *
- * This can be called from a LLD or iscsi_transport.
- **/
struct iscsi_cls_session *
-iscsi_create_session(struct Scsi_Host *shost,
- struct iscsi_transport *transport, int channel)
+iscsi_alloc_session(struct Scsi_Host *shost,
+ struct iscsi_transport *transport)
{
- struct iscsi_host *ihost;
struct iscsi_cls_session *session;
- int err;
-
- if (!try_module_get(transport->owner))
- return NULL;
session = kzalloc(sizeof(*session) + transport->sessiondata_size,
GFP_KERNEL);
if (!session)
- goto module_put;
+ return NULL;
+
session->transport = transport;
session->recovery_tmo = 120;
INIT_WORK(&session->recovery_work, session_recovery_timedout, session);
INIT_LIST_HEAD(&session->host_list);
INIT_LIST_HEAD(&session->sess_list);
+ /* this is released in the dev's release function */
+ scsi_host_get(shost);
+ session->dev.parent = &shost->shost_gendev;
+ session->dev.release = iscsi_session_release;
+ device_initialize(&session->dev);
if (transport->sessiondata_size)
session->dd_data = &session[1];
+ return session;
+}
+EXPORT_SYMBOL_GPL(iscsi_alloc_session);
- /* this is released in the dev's release function */
- scsi_host_get(shost);
- ihost = shost->shost_data;
+int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id)
+{
+ struct Scsi_Host *shost = iscsi_session_to_shost(session);
+ struct iscsi_host *ihost;
+ int err;
+ ihost = shost->shost_data;
session->sid = iscsi_session_nr++;
- session->channel = channel;
- session->target_id = ihost->next_target_id++;
+ session->target_id = target_id;
snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u",
session->sid);
- session->dev.parent = &shost->shost_gendev;
- session->dev.release = iscsi_session_release;
- err = device_register(&session->dev);
+ err = device_add(&session->dev);
if (err) {
dev_printk(KERN_ERR, &session->dev, "iscsi: could not "
"register session's dev\n");
- goto free_session;
+ goto release_host;
}
transport_register_device(&session->dev);
mutex_lock(&ihost->mutex);
list_add(&session->host_list, &ihost->sessions);
mutex_unlock(&ihost->mutex);
+ return 0;
- return session;
-
-free_session:
- kfree(session);
-module_put:
- module_put(transport->owner);
- return NULL;
+release_host:
+ scsi_host_put(shost);
+ return err;
}
-
-EXPORT_SYMBOL_GPL(iscsi_create_session);
+EXPORT_SYMBOL_GPL(iscsi_add_session);
/**
- * iscsi_destroy_session - destroy iscsi session
- * @session: iscsi_session
+ * iscsi_create_session - create iscsi class session
+ * @shost: scsi host
+ * @transport: iscsi transport
*
- * Can be called by a LLD or iscsi_transport. There must not be
- * any running connections.
+ * This can be called from a LLD or iscsi_transport.
**/
-int iscsi_destroy_session(struct iscsi_cls_session *session)
+struct iscsi_cls_session *
+iscsi_create_session(struct Scsi_Host *shost,
+ struct iscsi_transport *transport,
+ unsigned int target_id)
+{
+ struct iscsi_cls_session *session;
+
+ session = iscsi_alloc_session(shost, transport);
+ if (!session)
+ return NULL;
+
+ if (iscsi_add_session(session, target_id)) {
+ iscsi_free_session(session);
+ return NULL;
+ }
+ return session;
+}
+EXPORT_SYMBOL_GPL(iscsi_create_session);
+
+void iscsi_remove_session(struct iscsi_cls_session *session)
{
struct Scsi_Host *shost = iscsi_session_to_shost(session);
struct iscsi_host *ihost = shost->shost_data;
@@ -376,19 +385,88 @@ int iscsi_destroy_session(struct iscsi_cls_session *session)
list_del(&session->host_list);
mutex_unlock(&ihost->mutex);
+ scsi_remove_target(&session->dev);
+
transport_unregister_device(&session->dev);
- device_unregister(&session->dev);
- return 0;
+ device_del(&session->dev);
+}
+EXPORT_SYMBOL_GPL(iscsi_remove_session);
+
+void iscsi_free_session(struct iscsi_cls_session *session)
+{
+ put_device(&session->dev);
}
+EXPORT_SYMBOL_GPL(iscsi_free_session);
+
+/**
+ * iscsi_destroy_session - destroy iscsi session
+ * @session: iscsi_session
+ *
+ * Can be called by a LLD or iscsi_transport. There must not be
+ * any running connections.
+ **/
+int iscsi_destroy_session(struct iscsi_cls_session *session)
+{
+ iscsi_remove_session(session);
+ iscsi_free_session(session);
+ return 0;
+}
EXPORT_SYMBOL_GPL(iscsi_destroy_session);
+static void mempool_zone_destroy(struct mempool_zone *zp)
+{
+ mempool_destroy(zp->pool);
+ kfree(zp);
+}
+
+static void*
+mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
+{
+ struct mempool_zone *zone = pool_data;
+
+ return alloc_skb(zone->size, gfp_mask);
+}
+
+static void
+mempool_zone_free_skb(void *element, void *pool_data)
+{
+ kfree_skb(element);
+}
+
+static struct mempool_zone *
+mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
+{
+ struct mempool_zone *zp;
+
+ zp = kzalloc(sizeof(*zp), GFP_KERNEL);
+ if (!zp)
+ return NULL;
+
+ zp->size = size;
+ zp->hiwat = hiwat;
+ INIT_LIST_HEAD(&zp->freequeue);
+ spin_lock_init(&zp->freelock);
+ atomic_set(&zp->allocated, 0);
+
+ zp->pool = mempool_create(max, mempool_zone_alloc_skb,
+ mempool_zone_free_skb, zp);
+ if (!zp->pool) {
+ kfree(zp);
+ return NULL;
+ }
+
+ return zp;
+}
+
static void iscsi_conn_release(struct device *dev)
{
struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev);
struct device *parent = conn->dev.parent;
- kfree(conn->persistent_address);
+ mempool_zone_destroy(conn->z_pdu);
+ mempool_zone_destroy(conn->z_error);
+
kfree(conn);
put_device(parent);
}
@@ -398,6 +476,31 @@ static int iscsi_is_conn_dev(const struct device *dev)
return dev->release == iscsi_conn_release;
}
+static int iscsi_create_event_pools(struct iscsi_cls_conn *conn)
+{
+ conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
+ NLMSG_SPACE(sizeof(struct iscsi_uevent) +
+ sizeof(struct iscsi_hdr) +
+ DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
+ Z_HIWAT_PDU);
+ if (!conn->z_pdu) {
+ dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+ "pdu zone for new conn\n");
+ return -ENOMEM;
+ }
+
+ conn->z_error = mempool_zone_init(Z_MAX_ERROR,
+ NLMSG_SPACE(sizeof(struct iscsi_uevent)),
+ Z_HIWAT_ERROR);
+ if (!conn->z_error) {
+ dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
+ "error zone for new conn\n");
+ mempool_zone_destroy(conn->z_pdu);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
/**
* iscsi_create_conn - create iscsi class connection
* @session: iscsi cls session
@@ -430,9 +533,12 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
conn->transport = transport;
conn->cid = cid;
+ if (iscsi_create_event_pools(conn))
+ goto free_conn;
+
/* this is released in the dev's release function */
if (!get_device(&session->dev))
- goto free_conn;
+ goto free_conn_pools;
snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u",
session->sid, cid);
@@ -449,6 +555,8 @@ iscsi_create_conn(struct iscsi_cls_session *session, uint32_t cid)
release_parent_ref:
put_device(&session->dev);
+free_conn_pools:
+
free_conn:
kfree(conn);
return NULL;
@@ -496,20 +604,6 @@ static inline struct list_head *skb_to_lh(struct sk_buff *skb)
return (struct list_head *)&skb->cb;
}
-static void*
-mempool_zone_alloc_skb(gfp_t gfp_mask, void *pool_data)
-{
- struct mempool_zone *zone = pool_data;
-
- return alloc_skb(zone->size, gfp_mask);
-}
-
-static void
-mempool_zone_free_skb(void *element, void *pool_data)
-{
- kfree_skb(element);
-}
-
static void
mempool_zone_complete(struct mempool_zone *zone)
{
@@ -529,37 +623,6 @@ mempool_zone_complete(struct mempool_zone *zone)
spin_unlock_irqrestore(&zone->freelock, flags);
}
-static struct mempool_zone *
-mempool_zone_init(unsigned max, unsigned size, unsigned hiwat)
-{
- struct mempool_zone *zp;
-
- zp = kzalloc(sizeof(*zp), GFP_KERNEL);
- if (!zp)
- return NULL;
-
- zp->size = size;
- zp->hiwat = hiwat;
- INIT_LIST_HEAD(&zp->freequeue);
- spin_lock_init(&zp->freelock);
- atomic_set(&zp->allocated, 0);
-
- zp->pool = mempool_create(max, mempool_zone_alloc_skb,
- mempool_zone_free_skb, zp);
- if (!zp->pool) {
- kfree(zp);
- return NULL;
- }
-
- return zp;
-}
-
-static void mempool_zone_destroy(struct mempool_zone *zp)
-{
- mempool_destroy(zp->pool);
- kfree(zp);
-}
-
static struct sk_buff*
mempool_zone_get_skb(struct mempool_zone *zone)
{
@@ -572,6 +635,27 @@ mempool_zone_get_skb(struct mempool_zone *zone)
}
static int
+iscsi_broadcast_skb(struct mempool_zone *zone, struct sk_buff *skb, gfp_t gfp)
+{
+ unsigned long flags;
+ int rc;
+
+ skb_get(skb);
+ rc = netlink_broadcast(nls, skb, 0, 1, gfp);
+ if (rc < 0) {
+ mempool_free(skb, zone->pool);
+ printk(KERN_ERR "iscsi: can not broadcast skb (%d)\n", rc);
+ return rc;
+ }
+
+ spin_lock_irqsave(&zone->freelock, flags);
+ INIT_LIST_HEAD(skb_to_lh(skb));
+ list_add(skb_to_lh(skb), &zone->freequeue);
+ spin_unlock_irqrestore(&zone->freelock, flags);
+ return 0;
+}
+
+static int
iscsi_unicast_skb(struct mempool_zone *zone, struct sk_buff *skb, int pid)
{
unsigned long flags;
@@ -666,7 +750,7 @@ void iscsi_conn_error(struct iscsi_cls_conn *conn, enum iscsi_err error)
ev->r.connerror.cid = conn->cid;
ev->r.connerror.sid = iscsi_conn_get_sid(conn);
- iscsi_unicast_skb(conn->z_error, skb, priv->daemon_pid);
+ iscsi_broadcast_skb(conn->z_error, skb, GFP_ATOMIC);
dev_printk(KERN_INFO, &conn->dev, "iscsi: detected conn error (%d)\n",
error);
@@ -767,6 +851,131 @@ iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh)
return err;
}
+/**
+ * iscsi_if_destroy_session_done - send session destr. completion event
+ * @conn: last connection for session
+ *
+ * This is called by HW iscsi LLDs to notify userpsace that its HW has
+ * removed a session.
+ **/
+int iscsi_if_destroy_session_done(struct iscsi_cls_conn *conn)
+{
+ struct iscsi_internal *priv;
+ struct iscsi_cls_session *session;
+ struct Scsi_Host *shost;
+ struct iscsi_uevent *ev;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ unsigned long flags;
+ int rc, len = NLMSG_SPACE(sizeof(*ev));
+
+ priv = iscsi_if_transport_lookup(conn->transport);
+ if (!priv)
+ return -EINVAL;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ shost = iscsi_session_to_shost(session);
+
+ mempool_zone_complete(conn->z_pdu);
+
+ skb = mempool_zone_get_skb(conn->z_pdu);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event\n");
+ return -ENOMEM;
+ }
+
+ nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+ ev = NLMSG_DATA(nlh);
+ ev->transport_handle = iscsi_handle(conn->transport);
+ ev->type = ISCSI_KEVENT_DESTROY_SESSION;
+ ev->r.d_session.host_no = shost->host_no;
+ ev->r.d_session.sid = session->sid;
+
+ /*
+ * this will occur if the daemon is not up, so we just warn
+ * the user and when the daemon is restarted it will handle it
+ */
+ rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL);
+ if (rc < 0)
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session destruction event. Check iscsi daemon\n");
+
+ spin_lock_irqsave(&sesslock, flags);
+ list_del(&session->sess_list);
+ spin_unlock_irqrestore(&sesslock, flags);
+
+ spin_lock_irqsave(&connlock, flags);
+ conn->active = 0;
+ list_del(&conn->conn_list);
+ spin_unlock_irqrestore(&connlock, flags);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_if_destroy_session_done);
+
+/**
+ * iscsi_if_create_session_done - send session creation completion event
+ * @conn: leading connection for session
+ *
+ * This is called by HW iscsi LLDs to notify userpsace that its HW has
+ * created a session or a existing session is back in the logged in state.
+ **/
+int iscsi_if_create_session_done(struct iscsi_cls_conn *conn)
+{
+ struct iscsi_internal *priv;
+ struct iscsi_cls_session *session;
+ struct Scsi_Host *shost;
+ struct iscsi_uevent *ev;
+ struct sk_buff *skb;
+ struct nlmsghdr *nlh;
+ unsigned long flags;
+ int rc, len = NLMSG_SPACE(sizeof(*ev));
+
+ priv = iscsi_if_transport_lookup(conn->transport);
+ if (!priv)
+ return -EINVAL;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ shost = iscsi_session_to_shost(session);
+
+ mempool_zone_complete(conn->z_pdu);
+
+ skb = mempool_zone_get_skb(conn->z_pdu);
+ if (!skb) {
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event\n");
+ return -ENOMEM;
+ }
+
+ nlh = __nlmsg_put(skb, priv->daemon_pid, 0, 0, (len - sizeof(*nlh)), 0);
+ ev = NLMSG_DATA(nlh);
+ ev->transport_handle = iscsi_handle(conn->transport);
+ ev->type = ISCSI_UEVENT_CREATE_SESSION;
+ ev->r.c_session_ret.host_no = shost->host_no;
+ ev->r.c_session_ret.sid = session->sid;
+
+ /*
+ * this will occur if the daemon is not up, so we just warn
+ * the user and when the daemon is restarted it will handle it
+ */
+ rc = iscsi_broadcast_skb(conn->z_pdu, skb, GFP_KERNEL);
+ if (rc < 0)
+ dev_printk(KERN_ERR, &conn->dev, "Cannot notify userspace of "
+ "session creation event. Check iscsi daemon\n");
+
+ spin_lock_irqsave(&sesslock, flags);
+ list_add(&session->sess_list, &sesslist);
+ spin_unlock_irqrestore(&sesslock, flags);
+
+ spin_lock_irqsave(&connlock, flags);
+ list_add(&conn->conn_list, &connlist);
+ conn->active = 1;
+ spin_unlock_irqrestore(&connlock, flags);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(iscsi_if_create_session_done);
+
static int
iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_uevent *ev)
{
@@ -812,26 +1021,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
return -ENOMEM;
}
- conn->z_pdu = mempool_zone_init(Z_MAX_PDU,
- NLMSG_SPACE(sizeof(struct iscsi_uevent) +
- sizeof(struct iscsi_hdr) +
- DEFAULT_MAX_RECV_DATA_SEGMENT_LENGTH),
- Z_HIWAT_PDU);
- if (!conn->z_pdu) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
- "pdu zone for new conn\n");
- goto destroy_conn;
- }
-
- conn->z_error = mempool_zone_init(Z_MAX_ERROR,
- NLMSG_SPACE(sizeof(struct iscsi_uevent)),
- Z_HIWAT_ERROR);
- if (!conn->z_error) {
- dev_printk(KERN_ERR, &conn->dev, "iscsi: can not allocate "
- "error zone for new conn\n");
- goto free_pdu_pool;
- }
-
ev->r.c_conn_ret.sid = session->sid;
ev->r.c_conn_ret.cid = conn->cid;
@@ -841,13 +1030,6 @@ iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev)
spin_unlock_irqrestore(&connlock, flags);
return 0;
-
-free_pdu_pool:
- mempool_zone_destroy(conn->z_pdu);
-destroy_conn:
- if (transport->destroy_conn)
- transport->destroy_conn(conn->dd_data);
- return -ENOMEM;
}
static int
@@ -855,7 +1037,6 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
{
unsigned long flags;
struct iscsi_cls_conn *conn;
- struct mempool_zone *z_error, *z_pdu;
conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid);
if (!conn)
@@ -865,35 +1046,18 @@ iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev
list_del(&conn->conn_list);
spin_unlock_irqrestore(&connlock, flags);
- z_pdu = conn->z_pdu;
- z_error = conn->z_error;
-
if (transport->destroy_conn)
transport->destroy_conn(conn);
-
- mempool_zone_destroy(z_pdu);
- mempool_zone_destroy(z_error);
-
return 0;
}
-static void
-iscsi_copy_param(struct iscsi_uevent *ev, uint32_t *value, char *data)
-{
- if (ev->u.set_param.len != sizeof(uint32_t))
- BUG();
- memcpy(value, data, min_t(uint32_t, sizeof(uint32_t),
- ev->u.set_param.len));
-}
-
static int
iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
{
char *data = (char*)ev + sizeof(*ev);
struct iscsi_cls_conn *conn;
struct iscsi_cls_session *session;
- int err = 0;
- uint32_t value = 0;
+ int err = 0, value = 0;
session = iscsi_session_lookup(ev->u.set_param.sid);
conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid);
@@ -902,42 +1066,13 @@ iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev)
switch (ev->u.set_param.param) {
case ISCSI_PARAM_SESS_RECOVERY_TMO:
- iscsi_copy_param(ev, &value, data);
+ sscanf(data, "%d", &value);
if (value != 0)
session->recovery_tmo = value;
break;
- case ISCSI_PARAM_TARGET_NAME:
- /* this should not change between logins */
- if (session->targetname)
- return 0;
-
- session->targetname = kstrdup(data, GFP_KERNEL);
- if (!session->targetname)
- return -ENOMEM;
- break;
- case ISCSI_PARAM_TPGT:
- iscsi_copy_param(ev, &value, data);
- session->tpgt = value;
- break;
- case ISCSI_PARAM_PERSISTENT_PORT:
- iscsi_copy_param(ev, &value, data);
- conn->persistent_port = value;
- break;
- case ISCSI_PARAM_PERSISTENT_ADDRESS:
- /*
- * this is the address returned in discovery so it should
- * not change between logins.
- */
- if (conn->persistent_address)
- return 0;
-
- conn->persistent_address = kstrdup(data, GFP_KERNEL);
- if (!conn->persistent_address)
- return -ENOMEM;
- break;
default:
- iscsi_copy_param(ev, &value, data);
- err = transport->set_param(conn, ev->u.set_param.param, value);
+ err = transport->set_param(conn, ev->u.set_param.param,
+ data, ev->u.set_param.len);
}
return err;
@@ -978,6 +1113,21 @@ iscsi_if_transport_ep(struct iscsi_transport *transport,
}
static int
+iscsi_tgt_dscvr(struct iscsi_transport *transport,
+ struct iscsi_uevent *ev)
+{
+ struct sockaddr *dst_addr;
+
+ if (!transport->tgt_dscvr)
+ return -EINVAL;
+
+ dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev));
+ return transport->tgt_dscvr(ev->u.tgt_dscvr.type,
+ ev->u.tgt_dscvr.host_no,
+ ev->u.tgt_dscvr.enable, dst_addr);
+}
+
+static int
iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
{
int err = 0;
@@ -1065,6 +1215,9 @@ iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT:
err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type);
break;
+ case ISCSI_UEVENT_TGT_DSCVR:
+ err = iscsi_tgt_dscvr(transport, ev);
+ break;
default:
err = -EINVAL;
break;
@@ -1147,49 +1300,31 @@ struct class_device_attribute class_device_attr_##_prefix##_##_name = \
/*
* iSCSI connection attrs
*/
-#define iscsi_conn_int_attr_show(param, format) \
-static ssize_t \
-show_conn_int_param_##param(struct class_device *cdev, char *buf) \
-{ \
- uint32_t value = 0; \
- struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- struct iscsi_transport *t = conn->transport; \
- \
- t->get_conn_param(conn, param, &value); \
- return snprintf(buf, 20, format"\n", value); \
-}
-
-#define iscsi_conn_int_attr(field, param, format) \
- iscsi_conn_int_attr_show(param, format) \
-static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_int_param_##param, \
- NULL);
-
-iscsi_conn_int_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH, "%u");
-iscsi_conn_int_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH, "%u");
-iscsi_conn_int_attr(header_digest, ISCSI_PARAM_HDRDGST_EN, "%d");
-iscsi_conn_int_attr(data_digest, ISCSI_PARAM_DATADGST_EN, "%d");
-iscsi_conn_int_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN, "%d");
-iscsi_conn_int_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN, "%d");
-iscsi_conn_int_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT, "%d");
-iscsi_conn_int_attr(port, ISCSI_PARAM_CONN_PORT, "%d");
-iscsi_conn_int_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN, "%u");
-
-#define iscsi_conn_str_attr_show(param) \
+#define iscsi_conn_attr_show(param) \
static ssize_t \
-show_conn_str_param_##param(struct class_device *cdev, char *buf) \
+show_conn_param_##param(struct class_device *cdev, char *buf) \
{ \
struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
struct iscsi_transport *t = conn->transport; \
- return t->get_conn_str_param(conn, param, buf); \
+ return t->get_conn_param(conn, param, buf); \
}
-#define iscsi_conn_str_attr(field, param) \
- iscsi_conn_str_attr_show(param) \
-static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_str_param_##param, \
+#define iscsi_conn_attr(field, param) \
+ iscsi_conn_attr_show(param) \
+static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \
NULL);
-iscsi_conn_str_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
-iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS);
+iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH);
+iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH);
+iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN);
+iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN);
+iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN);
+iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN);
+iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT);
+iscsi_conn_attr(port, ISCSI_PARAM_CONN_PORT);
+iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN);
+iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS);
+iscsi_conn_attr(address, ISCSI_PARAM_CONN_ADDRESS);
#define iscsi_cdev_to_session(_cdev) \
iscsi_dev_to_session(_cdev->dev)
@@ -1197,61 +1332,36 @@ iscsi_conn_str_attr(address, ISCSI_PARAM_CONN_ADDRESS);
/*
* iSCSI session attrs
*/
-#define iscsi_session_int_attr_show(param, format) \
-static ssize_t \
-show_session_int_param_##param(struct class_device *cdev, char *buf) \
-{ \
- uint32_t value = 0; \
- struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
- struct iscsi_transport *t = session->transport; \
- \
- t->get_session_param(session, param, &value); \
- return snprintf(buf, 20, format"\n", value); \
-}
-
-#define iscsi_session_int_attr(field, param, format) \
- iscsi_session_int_attr_show(param, format) \
-static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_int_param_##param, \
- NULL);
-
-iscsi_session_int_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, "%d");
-iscsi_session_int_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, "%hu");
-iscsi_session_int_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, "%d");
-iscsi_session_int_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, "%u");
-iscsi_session_int_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, "%u");
-iscsi_session_int_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, "%d");
-iscsi_session_int_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, "%d");
-iscsi_session_int_attr(erl, ISCSI_PARAM_ERL, "%d");
-iscsi_session_int_attr(tpgt, ISCSI_PARAM_TPGT, "%d");
-
-#define iscsi_session_str_attr_show(param) \
+#define iscsi_session_attr_show(param) \
static ssize_t \
-show_session_str_param_##param(struct class_device *cdev, char *buf) \
+show_session_param_##param(struct class_device *cdev, char *buf) \
{ \
struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
struct iscsi_transport *t = session->transport; \
- return t->get_session_str_param(session, param, buf); \
+ return t->get_session_param(session, param, buf); \
}
-#define iscsi_session_str_attr(field, param) \
- iscsi_session_str_attr_show(param) \
-static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_str_param_##param, \
+#define iscsi_session_attr(field, param) \
+ iscsi_session_attr_show(param) \
+static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \
NULL);
-iscsi_session_str_attr(targetname, ISCSI_PARAM_TARGET_NAME);
+iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME);
+iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN);
+iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T);
+iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN);
+iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST);
+iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST);
+iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN);
+iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN);
+iscsi_session_attr(erl, ISCSI_PARAM_ERL);
+iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT);
-/*
- * Private session and conn attrs. userspace uses several iscsi values
- * to identify each session between reboots. Some of these values may not
- * be present in the iscsi_transport/LLD driver becuase userspace handles
- * login (and failback for login redirect) so for these type of drivers
- * the class manages the attrs and values for the iscsi_transport/LLD
- */
#define iscsi_priv_session_attr_show(field, format) \
static ssize_t \
-show_priv_session_##field(struct class_device *cdev, char *buf) \
+show_priv_session_##field(struct class_device *cdev, char *buf) \
{ \
- struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev); \
+ struct iscsi_cls_session *session = iscsi_cdev_to_session(cdev);\
return sprintf(buf, format"\n", session->field); \
}
@@ -1259,31 +1369,15 @@ show_priv_session_##field(struct class_device *cdev, char *buf) \
iscsi_priv_session_attr_show(field, format) \
static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO, show_priv_session_##field, \
NULL)
-iscsi_priv_session_attr(targetname, "%s");
-iscsi_priv_session_attr(tpgt, "%d");
iscsi_priv_session_attr(recovery_tmo, "%d");
-#define iscsi_priv_conn_attr_show(field, format) \
-static ssize_t \
-show_priv_conn_##field(struct class_device *cdev, char *buf) \
-{ \
- struct iscsi_cls_conn *conn = iscsi_cdev_to_conn(cdev); \
- return sprintf(buf, format"\n", conn->field); \
-}
-
-#define iscsi_priv_conn_attr(field, format) \
- iscsi_priv_conn_attr_show(field, format) \
-static ISCSI_CLASS_ATTR(priv_conn, field, S_IRUGO, show_priv_conn_##field, \
- NULL)
-iscsi_priv_conn_attr(persistent_address, "%s");
-iscsi_priv_conn_attr(persistent_port, "%d");
-
#define SETUP_PRIV_SESSION_RD_ATTR(field) \
do { \
priv->session_attrs[count] = &class_device_attr_priv_sess_##field; \
count++; \
} while (0)
+
#define SETUP_SESSION_RD_ATTR(field, param_flag) \
do { \
if (tt->param_mask & param_flag) { \
@@ -1292,12 +1386,6 @@ do { \
} \
} while (0)
-#define SETUP_PRIV_CONN_RD_ATTR(field) \
-do { \
- priv->conn_attrs[count] = &class_device_attr_priv_conn_##field; \
- count++; \
-} while (0)
-
#define SETUP_CONN_RD_ATTR(field, param_flag) \
do { \
if (tt->param_mask & param_flag) { \
@@ -1388,6 +1476,7 @@ iscsi_register_transport(struct iscsi_transport *tt)
if (!priv)
return NULL;
INIT_LIST_HEAD(&priv->list);
+ priv->daemon_pid = -1;
priv->iscsi_transport = tt;
priv->t.user_scan = iscsi_user_scan;
@@ -1424,16 +1513,8 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_CONN_RD_ATTR(address, ISCSI_CONN_ADDRESS);
SETUP_CONN_RD_ATTR(port, ISCSI_CONN_PORT);
SETUP_CONN_RD_ATTR(exp_statsn, ISCSI_EXP_STATSN);
-
- if (tt->param_mask & ISCSI_PERSISTENT_ADDRESS)
- SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
- else
- SETUP_PRIV_CONN_RD_ATTR(persistent_address);
-
- if (tt->param_mask & ISCSI_PERSISTENT_PORT)
- SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
- else
- SETUP_PRIV_CONN_RD_ATTR(persistent_port);
+ SETUP_CONN_RD_ATTR(persistent_address, ISCSI_PERSISTENT_ADDRESS);
+ SETUP_CONN_RD_ATTR(persistent_port, ISCSI_PERSISTENT_PORT);
BUG_ON(count > ISCSI_CONN_ATTRS);
priv->conn_attrs[count] = NULL;
@@ -1453,18 +1534,10 @@ iscsi_register_transport(struct iscsi_transport *tt)
SETUP_SESSION_RD_ATTR(data_pdu_in_order, ISCSI_PDU_INORDER_EN);
SETUP_SESSION_RD_ATTR(data_seq_in_order, ISCSI_DATASEQ_INORDER_EN);
SETUP_SESSION_RD_ATTR(erl, ISCSI_ERL);
+ SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
+ SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
SETUP_PRIV_SESSION_RD_ATTR(recovery_tmo);
- if (tt->param_mask & ISCSI_TARGET_NAME)
- SETUP_SESSION_RD_ATTR(targetname, ISCSI_TARGET_NAME);
- else
- SETUP_PRIV_SESSION_RD_ATTR(targetname);
-
- if (tt->param_mask & ISCSI_TPGT)
- SETUP_SESSION_RD_ATTR(tpgt, ISCSI_TPGT);
- else
- SETUP_PRIV_SESSION_RD_ATTR(tpgt);
-
BUG_ON(count > ISCSI_SESSION_ATTRS);
priv->session_attrs[count] = NULL;
@@ -1541,6 +1614,9 @@ static __init int iscsi_transport_init(void)
{
int err;
+ printk(KERN_INFO "Loading iSCSI transport class v%s.",
+ ISCSI_TRANSPORT_VERSION);
+
err = class_register(&iscsi_transport_class);
if (err)
return err;
@@ -1606,3 +1682,4 @@ MODULE_AUTHOR("Mike Christie <michaelc@cs.wisc.edu>, "
"Alex Aizman <itn780@yahoo.com>");
MODULE_DESCRIPTION("iSCSI Transport Interface");
MODULE_LICENSE("GPL");
+MODULE_VERSION(ISCSI_TRANSPORT_VERSION);
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 1fe6b2d0185..b5b0c2cba96 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -41,6 +41,7 @@ struct sas_host_attrs {
struct mutex lock;
u32 next_target_id;
u32 next_expander_id;
+ int next_port_id;
};
#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data)
@@ -76,6 +77,24 @@ get_sas_##title##_names(u32 table_key, char *buf) \
return len; \
}
+#define sas_bitfield_name_set(title, table) \
+static ssize_t \
+set_sas_##title##_names(u32 *table_key, const char *buf) \
+{ \
+ ssize_t len = 0; \
+ int i; \
+ \
+ for (i = 0; i < ARRAY_SIZE(table); i++) { \
+ len = strlen(table[i].name); \
+ if (strncmp(buf, table[i].name, len) == 0 && \
+ (buf[len] == '\n' || buf[len] == '\0')) { \
+ *table_key = table[i].value; \
+ return 0; \
+ } \
+ } \
+ return -EINVAL; \
+}
+
#define sas_bitfield_name_search(title, table) \
static ssize_t \
get_sas_##title##_names(u32 table_key, char *buf) \
@@ -130,7 +149,7 @@ static struct {
{ SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
};
sas_bitfield_name_search(linkspeed, sas_linkspeed_names)
-
+sas_bitfield_name_set(linkspeed, sas_linkspeed_names)
/*
* SAS host attributes
@@ -146,6 +165,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,
mutex_init(&sas_host->lock);
sas_host->next_target_id = 0;
sas_host->next_expander_id = 0;
+ sas_host->next_port_id = 0;
return 0;
}
@@ -174,12 +194,29 @@ static int sas_host_match(struct attribute_container *cont,
static int do_sas_phy_delete(struct device *dev, void *data)
{
- if (scsi_is_sas_phy(dev))
+ int pass = (int)(unsigned long)data;
+
+ if (pass == 0 && scsi_is_sas_port(dev))
+ sas_port_delete(dev_to_sas_port(dev));
+ else if (pass == 1 && scsi_is_sas_phy(dev))
sas_phy_delete(dev_to_phy(dev));
return 0;
}
/**
+ * sas_remove_children -- tear down a devices SAS data structures
+ * @dev: device belonging to the sas object
+ *
+ * Removes all SAS PHYs and remote PHYs for a given object
+ */
+void sas_remove_children(struct device *dev)
+{
+ device_for_each_child(dev, (void *)0, do_sas_phy_delete);
+ device_for_each_child(dev, (void *)1, do_sas_phy_delete);
+}
+EXPORT_SYMBOL(sas_remove_children);
+
+/**
* sas_remove_host -- tear down a Scsi_Host's SAS data structures
* @shost: Scsi Host that is torn down
*
@@ -188,13 +225,13 @@ static int do_sas_phy_delete(struct device *dev, void *data)
*/
void sas_remove_host(struct Scsi_Host *shost)
{
- device_for_each_child(&shost->shost_gendev, NULL, do_sas_phy_delete);
+ sas_remove_children(&shost->shost_gendev);
}
EXPORT_SYMBOL(sas_remove_host);
/*
- * SAS Port attributes
+ * SAS Phy attributes
*/
#define sas_phy_show_simple(field, name, format_string, cast) \
@@ -234,10 +271,39 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \
return get_sas_linkspeed_names(phy->field, buf); \
}
+/* Fudge to tell if we're minimum or maximum */
+#define sas_phy_store_linkspeed(field) \
+static ssize_t \
+store_sas_phy_##field(struct class_device *cdev, const char *buf, \
+ size_t count) \
+{ \
+ struct sas_phy *phy = transport_class_to_phy(cdev); \
+ struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \
+ struct sas_internal *i = to_sas_internal(shost->transportt); \
+ u32 value; \
+ struct sas_phy_linkrates rates = {0}; \
+ int error; \
+ \
+ error = set_sas_linkspeed_names(&value, buf); \
+ if (error) \
+ return error; \
+ rates.field = value; \
+ error = i->f->set_phy_speed(phy, &rates); \
+ \
+ return error ? error : count; \
+}
+
+#define sas_phy_linkspeed_rw_attr(field) \
+ sas_phy_show_linkspeed(field) \
+ sas_phy_store_linkspeed(field) \
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \
+ store_sas_phy_##field)
+
#define sas_phy_linkspeed_attr(field) \
sas_phy_show_linkspeed(field) \
static CLASS_DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL)
+
#define sas_phy_show_linkerror(field) \
static ssize_t \
show_sas_phy_##field(struct class_device *cdev, char *buf) \
@@ -247,9 +313,6 @@ show_sas_phy_##field(struct class_device *cdev, char *buf) \
struct sas_internal *i = to_sas_internal(shost->transportt); \
int error; \
\
- if (!phy->local_attached) \
- return -EINVAL; \
- \
error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \
if (error) \
return error; \
@@ -280,9 +343,6 @@ static ssize_t do_sas_phy_reset(struct class_device *cdev,
struct sas_internal *i = to_sas_internal(shost->transportt);
int error;
- if (!phy->local_attached)
- return -EINVAL;
-
error = i->f->phy_reset(phy, hard_reset);
if (error)
return error;
@@ -310,12 +370,12 @@ sas_phy_protocol_attr(identify.target_port_protocols,
sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n",
unsigned long long);
sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8);
-sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", u8);
+//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int);
sas_phy_linkspeed_attr(negotiated_linkrate);
sas_phy_linkspeed_attr(minimum_linkrate_hw);
-sas_phy_linkspeed_attr(minimum_linkrate);
+sas_phy_linkspeed_rw_attr(minimum_linkrate);
sas_phy_linkspeed_attr(maximum_linkrate_hw);
-sas_phy_linkspeed_attr(maximum_linkrate);
+sas_phy_linkspeed_rw_attr(maximum_linkrate);
sas_phy_linkerror_attr(invalid_dword_count);
sas_phy_linkerror_attr(running_disparity_error_count);
sas_phy_linkerror_attr(loss_of_dword_sync_count);
@@ -378,9 +438,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number)
device_initialize(&phy->dev);
phy->dev.parent = get_device(parent);
phy->dev.release = sas_phy_release;
+ INIT_LIST_HEAD(&phy->port_siblings);
if (scsi_is_sas_expander_device(parent)) {
struct sas_rphy *rphy = dev_to_rphy(parent);
- sprintf(phy->dev.bus_id, "phy-%d-%d:%d", shost->host_no,
+ sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no,
rphy->scsi_target_id, number);
} else
sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number);
@@ -440,8 +501,8 @@ sas_phy_delete(struct sas_phy *phy)
{
struct device *dev = &phy->dev;
- if (phy->rphy)
- sas_rphy_delete(phy->rphy);
+ /* this happens if the phy is still part of a port when deleted */
+ BUG_ON(!list_empty(&phy->port_siblings));
transport_remove_device(dev);
device_del(dev);
@@ -464,6 +525,310 @@ int scsi_is_sas_phy(const struct device *dev)
EXPORT_SYMBOL(scsi_is_sas_phy);
/*
+ * SAS Port attributes
+ */
+#define sas_port_show_simple(field, name, format_string, cast) \
+static ssize_t \
+show_sas_port_##name(struct class_device *cdev, char *buf) \
+{ \
+ struct sas_port *port = transport_class_to_sas_port(cdev); \
+ \
+ return snprintf(buf, 20, format_string, cast port->field); \
+}
+
+#define sas_port_simple_attr(field, name, format_string, type) \
+ sas_port_show_simple(field, name, format_string, (type)) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL)
+
+sas_port_simple_attr(num_phys, num_phys, "%d\n", int);
+
+static DECLARE_TRANSPORT_CLASS(sas_port_class,
+ "sas_port", NULL, NULL, NULL);
+
+static int sas_port_match(struct attribute_container *cont, struct device *dev)
+{
+ struct Scsi_Host *shost;
+ struct sas_internal *i;
+
+ if (!scsi_is_sas_port(dev))
+ return 0;
+ shost = dev_to_shost(dev->parent);
+
+ if (!shost->transportt)
+ return 0;
+ if (shost->transportt->host_attrs.ac.class !=
+ &sas_host_class.class)
+ return 0;
+
+ i = to_sas_internal(shost->transportt);
+ return &i->port_attr_cont.ac == cont;
+}
+
+
+static void sas_port_release(struct device *dev)
+{
+ struct sas_port *port = dev_to_sas_port(dev);
+
+ BUG_ON(!list_empty(&port->phy_list));
+
+ put_device(dev->parent);
+ kfree(port);
+}
+
+static void sas_port_create_link(struct sas_port *port,
+ struct sas_phy *phy)
+{
+ sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, phy->dev.bus_id);
+ sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port");
+}
+
+static void sas_port_delete_link(struct sas_port *port,
+ struct sas_phy *phy)
+{
+ sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id);
+ sysfs_remove_link(&phy->dev.kobj, "port");
+}
+
+/** sas_port_alloc - allocate and initialize a SAS port structure
+ *
+ * @parent: parent device
+ * @port_id: port number
+ *
+ * Allocates a SAS port structure. It will be added to the device tree
+ * below the device specified by @parent which must be either a Scsi_Host
+ * or a sas_expander_device.
+ *
+ * Returns %NULL on error
+ */
+struct sas_port *sas_port_alloc(struct device *parent, int port_id)
+{
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_port *port;
+
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
+ return NULL;
+
+ port->port_identifier = port_id;
+
+ device_initialize(&port->dev);
+
+ port->dev.parent = get_device(parent);
+ port->dev.release = sas_port_release;
+
+ mutex_init(&port->phy_list_mutex);
+ INIT_LIST_HEAD(&port->phy_list);
+
+ if (scsi_is_sas_expander_device(parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent);
+ sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no,
+ rphy->scsi_target_id, port->port_identifier);
+ } else
+ sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no,
+ port->port_identifier);
+
+ transport_setup_device(&port->dev);
+
+ return port;
+}
+EXPORT_SYMBOL(sas_port_alloc);
+
+/** sas_port_alloc_num - allocate and initialize a SAS port structure
+ *
+ * @parent: parent device
+ *
+ * Allocates a SAS port structure and a number to go with it. This
+ * interface is really for adapters where the port number has no
+ * meansing, so the sas class should manage them. It will be added to
+ * the device tree below the device specified by @parent which must be
+ * either a Scsi_Host or a sas_expander_device.
+ *
+ * Returns %NULL on error
+ */
+struct sas_port *sas_port_alloc_num(struct device *parent)
+{
+ int index;
+ struct Scsi_Host *shost = dev_to_shost(parent);
+ struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
+
+ /* FIXME: use idr for this eventually */
+ mutex_lock(&sas_host->lock);
+ if (scsi_is_sas_expander_device(parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent);
+ struct sas_expander_device *exp = rphy_to_expander_device(rphy);
+
+ index = exp->next_port_id++;
+ } else
+ index = sas_host->next_port_id++;
+ mutex_unlock(&sas_host->lock);
+ return sas_port_alloc(parent, index);
+}
+EXPORT_SYMBOL(sas_port_alloc_num);
+
+/**
+ * sas_port_add - add a SAS port to the device hierarchy
+ *
+ * @port: port to be added
+ *
+ * publishes a port to the rest of the system
+ */
+int sas_port_add(struct sas_port *port)
+{
+ int error;
+
+ /* No phys should be added until this is made visible */
+ BUG_ON(!list_empty(&port->phy_list));
+
+ error = device_add(&port->dev);
+
+ if (error)
+ return error;
+
+ transport_add_device(&port->dev);
+ transport_configure_device(&port->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL(sas_port_add);
+
+/**
+ * sas_port_free -- free a SAS PORT
+ * @port: SAS PORT to free
+ *
+ * Frees the specified SAS PORT.
+ *
+ * Note:
+ * This function must only be called on a PORT that has not
+ * sucessfully been added using sas_port_add().
+ */
+void sas_port_free(struct sas_port *port)
+{
+ transport_destroy_device(&port->dev);
+ put_device(&port->dev);
+}
+EXPORT_SYMBOL(sas_port_free);
+
+/**
+ * sas_port_delete -- remove SAS PORT
+ * @port: SAS PORT to remove
+ *
+ * Removes the specified SAS PORT. If the SAS PORT has an
+ * associated phys, unlink them from the port as well.
+ */
+void sas_port_delete(struct sas_port *port)
+{
+ struct device *dev = &port->dev;
+ struct sas_phy *phy, *tmp_phy;
+
+ if (port->rphy) {
+ sas_rphy_delete(port->rphy);
+ port->rphy = NULL;
+ }
+
+ mutex_lock(&port->phy_list_mutex);
+ list_for_each_entry_safe(phy, tmp_phy, &port->phy_list,
+ port_siblings) {
+ sas_port_delete_link(port, phy);
+ list_del_init(&phy->port_siblings);
+ }
+ mutex_unlock(&port->phy_list_mutex);
+
+ if (port->is_backlink) {
+ struct device *parent = port->dev.parent;
+
+ sysfs_remove_link(&port->dev.kobj, parent->bus_id);
+ port->is_backlink = 0;
+ }
+
+ transport_remove_device(dev);
+ device_del(dev);
+ transport_destroy_device(dev);
+ put_device(dev);
+}
+EXPORT_SYMBOL(sas_port_delete);
+
+/**
+ * scsi_is_sas_port -- check if a struct device represents a SAS port
+ * @dev: device to check
+ *
+ * Returns:
+ * %1 if the device represents a SAS Port, %0 else
+ */
+int scsi_is_sas_port(const struct device *dev)
+{
+ return dev->release == sas_port_release;
+}
+EXPORT_SYMBOL(scsi_is_sas_port);
+
+/**
+ * sas_port_add_phy - add another phy to a port to form a wide port
+ * @port: port to add the phy to
+ * @phy: phy to add
+ *
+ * When a port is initially created, it is empty (has no phys). All
+ * ports must have at least one phy to operated, and all wide ports
+ * must have at least two. The current code makes no difference
+ * between ports and wide ports, but the only object that can be
+ * connected to a remote device is a port, so ports must be formed on
+ * all devices with phys if they're connected to anything.
+ */
+void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy)
+{
+ mutex_lock(&port->phy_list_mutex);
+ if (unlikely(!list_empty(&phy->port_siblings))) {
+ /* make sure we're already on this port */
+ struct sas_phy *tmp;
+
+ list_for_each_entry(tmp, &port->phy_list, port_siblings)
+ if (tmp == phy)
+ break;
+ /* If this trips, you added a phy that was already
+ * part of a different port */
+ if (unlikely(tmp != phy)) {
+ dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id);
+ BUG();
+ }
+ } else {
+ sas_port_create_link(port, phy);
+ list_add_tail(&phy->port_siblings, &port->phy_list);
+ port->num_phys++;
+ }
+ mutex_unlock(&port->phy_list_mutex);
+}
+EXPORT_SYMBOL(sas_port_add_phy);
+
+/**
+ * sas_port_delete_phy - remove a phy from a port or wide port
+ * @port: port to remove the phy from
+ * @phy: phy to remove
+ *
+ * This operation is used for tearing down ports again. It must be
+ * done to every port or wide port before calling sas_port_delete.
+ */
+void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy)
+{
+ mutex_lock(&port->phy_list_mutex);
+ sas_port_delete_link(port, phy);
+ list_del_init(&phy->port_siblings);
+ port->num_phys--;
+ mutex_unlock(&port->phy_list_mutex);
+}
+EXPORT_SYMBOL(sas_port_delete_phy);
+
+void sas_port_mark_backlink(struct sas_port *port)
+{
+ struct device *parent = port->dev.parent->parent->parent;
+
+ if (port->is_backlink)
+ return;
+ port->is_backlink = 1;
+ sysfs_create_link(&port->dev.kobj, &parent->kobj,
+ parent->bus_id);
+
+}
+EXPORT_SYMBOL(sas_port_mark_backlink);
+
+/*
* SAS remote PHY attributes.
*/
@@ -525,7 +890,7 @@ show_sas_rphy_enclosure_identifier(struct class_device *cdev, char *buf)
* Only devices behind an expander are supported, because the
* enclosure identifier is a SMP feature.
*/
- if (phy->local_attached)
+ if (scsi_is_sas_phy_local(phy))
return -EINVAL;
error = i->f->get_enclosure_identifier(rphy, &identifier);
@@ -546,7 +911,7 @@ show_sas_rphy_bay_identifier(struct class_device *cdev, char *buf)
struct sas_internal *i = to_sas_internal(shost->transportt);
int val;
- if (phy->local_attached)
+ if (scsi_is_sas_phy_local(phy))
return -EINVAL;
val = i->f->get_bay_identifier(rphy);
@@ -767,7 +1132,7 @@ static void sas_rphy_initialize(struct sas_rphy *rphy)
* Returns:
* SAS PHY allocated or %NULL if the allocation failed.
*/
-struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
+struct sas_rphy *sas_end_device_alloc(struct sas_port *parent)
{
struct Scsi_Host *shost = dev_to_shost(&parent->dev);
struct sas_end_device *rdev;
@@ -780,8 +1145,13 @@ struct sas_rphy *sas_end_device_alloc(struct sas_phy *parent)
device_initialize(&rdev->rphy.dev);
rdev->rphy.dev.parent = get_device(&parent->dev);
rdev->rphy.dev.release = sas_end_device_release;
- sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d-%d",
- shost->host_no, parent->port_identifier, parent->number);
+ if (scsi_is_sas_expander_device(parent->dev.parent)) {
+ struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent);
+ sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d",
+ shost->host_no, rphy->scsi_target_id, parent->port_identifier);
+ } else
+ sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d",
+ shost->host_no, parent->port_identifier);
rdev->rphy.identify.device_type = SAS_END_DEVICE;
sas_rphy_initialize(&rdev->rphy);
transport_setup_device(&rdev->rphy.dev);
@@ -798,7 +1168,7 @@ EXPORT_SYMBOL(sas_end_device_alloc);
* Returns:
* SAS PHY allocated or %NULL if the allocation failed.
*/
-struct sas_rphy *sas_expander_alloc(struct sas_phy *parent,
+struct sas_rphy *sas_expander_alloc(struct sas_port *parent,
enum sas_device_type type)
{
struct Scsi_Host *shost = dev_to_shost(&parent->dev);
@@ -837,7 +1207,7 @@ EXPORT_SYMBOL(sas_expander_alloc);
*/
int sas_rphy_add(struct sas_rphy *rphy)
{
- struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
+ struct sas_port *parent = dev_to_sas_port(rphy->dev.parent);
struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
struct sas_identify *identify = &rphy->identify;
@@ -865,7 +1235,7 @@ int sas_rphy_add(struct sas_rphy *rphy)
if (identify->device_type == SAS_END_DEVICE &&
rphy->scsi_target_id != -1) {
- scsi_scan_target(&rphy->dev, parent->port_identifier,
+ scsi_scan_target(&rphy->dev, 0,
rphy->scsi_target_id, ~0, 0);
}
@@ -910,7 +1280,7 @@ void
sas_rphy_delete(struct sas_rphy *rphy)
{
struct device *dev = &rphy->dev;
- struct sas_phy *parent = dev_to_phy(dev->parent);
+ struct sas_port *parent = dev_to_sas_port(dev->parent);
struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
@@ -920,7 +1290,7 @@ sas_rphy_delete(struct sas_rphy *rphy)
break;
case SAS_EDGE_EXPANDER_DEVICE:
case SAS_FANOUT_EXPANDER_DEVICE:
- device_for_each_child(dev, NULL, do_sas_phy_delete);
+ sas_remove_children(dev);
break;
default:
break;
@@ -967,15 +1337,13 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
mutex_lock(&sas_host->lock);
list_for_each_entry(rphy, &sas_host->rphy_list, list) {
- struct sas_phy *parent = dev_to_phy(rphy->dev.parent);
-
if (rphy->identify.device_type != SAS_END_DEVICE ||
rphy->scsi_target_id == -1)
continue;
- if ((channel == SCAN_WILD_CARD || channel == parent->port_identifier) &&
+ if ((channel == SCAN_WILD_CARD || channel == 0) &&
(id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) {
- scsi_scan_target(&rphy->dev, parent->port_identifier,
+ scsi_scan_target(&rphy->dev, 0,
rphy->scsi_target_id, lun, 1);
}
}
@@ -989,13 +1357,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
* Setup / Teardown code
*/
-#define SETUP_TEMPLATE(attrb, field, perm, test) \
+#define SETUP_TEMPLATE(attrb, field, perm, test) \
i->private_##attrb[count] = class_device_attr_##field; \
i->private_##attrb[count].attr.mode = perm; \
i->attrb[count] = &i->private_##attrb[count]; \
if (test) \
count++
+#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \
+ i->private_##attrb[count] = class_device_attr_##field; \
+ i->private_##attrb[count].attr.mode = perm; \
+ if (ro_test) { \
+ i->private_##attrb[count].attr.mode = ro_perm; \
+ i->private_##attrb[count].store = NULL; \
+ } \
+ i->attrb[count] = &i->private_##attrb[count]; \
+ if (test) \
+ count++
#define SETUP_RPORT_ATTRIBUTE(field) \
SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1)
@@ -1003,16 +1381,23 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel,
#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \
SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func)
-#define SETUP_PORT_ATTRIBUTE(field) \
+#define SETUP_PHY_ATTRIBUTE(field) \
SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1)
-#define SETUP_OPTIONAL_PORT_ATTRIBUTE(field, func) \
+#define SETUP_PHY_ATTRIBUTE_RW(field) \
+ SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \
+ !i->f->set_phy_speed, S_IRUGO)
+
+#define SETUP_PORT_ATTRIBUTE(field) \
+ SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+
+#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \
SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func)
-#define SETUP_PORT_ATTRIBUTE_WRONLY(field) \
+#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \
SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, 1)
-#define SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(field, func) \
+#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \
SETUP_TEMPLATE(phy_attrs, field, S_IWUGO, i->f->func)
#define SETUP_END_DEV_ATTRIBUTE(field) \
@@ -1048,6 +1433,11 @@ sas_attach_transport(struct sas_function_template *ft)
i->phy_attr_cont.ac.match = sas_phy_match;
transport_container_register(&i->phy_attr_cont);
+ i->port_attr_cont.ac.class = &sas_port_class.class;
+ i->port_attr_cont.ac.attrs = &i->port_attrs[0];
+ i->port_attr_cont.ac.match = sas_port_match;
+ transport_container_register(&i->port_attr_cont);
+
i->rphy_attr_cont.ac.class = &sas_rphy_class.class;
i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0];
i->rphy_attr_cont.ac.match = sas_rphy_match;
@@ -1066,30 +1456,35 @@ sas_attach_transport(struct sas_function_template *ft)
i->f = ft;
count = 0;
+ SETUP_PORT_ATTRIBUTE(num_phys);
i->host_attrs[count] = NULL;
count = 0;
- SETUP_PORT_ATTRIBUTE(initiator_port_protocols);
- SETUP_PORT_ATTRIBUTE(target_port_protocols);
- SETUP_PORT_ATTRIBUTE(device_type);
- SETUP_PORT_ATTRIBUTE(sas_address);
- SETUP_PORT_ATTRIBUTE(phy_identifier);
- SETUP_PORT_ATTRIBUTE(port_identifier);
- SETUP_PORT_ATTRIBUTE(negotiated_linkrate);
- SETUP_PORT_ATTRIBUTE(minimum_linkrate_hw);
- SETUP_PORT_ATTRIBUTE(minimum_linkrate);
- SETUP_PORT_ATTRIBUTE(maximum_linkrate_hw);
- SETUP_PORT_ATTRIBUTE(maximum_linkrate);
-
- SETUP_PORT_ATTRIBUTE(invalid_dword_count);
- SETUP_PORT_ATTRIBUTE(running_disparity_error_count);
- SETUP_PORT_ATTRIBUTE(loss_of_dword_sync_count);
- SETUP_PORT_ATTRIBUTE(phy_reset_problem_count);
- SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(link_reset, phy_reset);
- SETUP_OPTIONAL_PORT_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
+ SETUP_PHY_ATTRIBUTE(initiator_port_protocols);
+ SETUP_PHY_ATTRIBUTE(target_port_protocols);
+ SETUP_PHY_ATTRIBUTE(device_type);
+ SETUP_PHY_ATTRIBUTE(sas_address);
+ SETUP_PHY_ATTRIBUTE(phy_identifier);
+ //SETUP_PHY_ATTRIBUTE(port_identifier);
+ SETUP_PHY_ATTRIBUTE(negotiated_linkrate);
+ SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw);
+ SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate);
+ SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw);
+ SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate);
+
+ SETUP_PHY_ATTRIBUTE(invalid_dword_count);
+ SETUP_PHY_ATTRIBUTE(running_disparity_error_count);
+ SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count);
+ SETUP_PHY_ATTRIBUTE(phy_reset_problem_count);
+ SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset);
+ SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset);
i->phy_attrs[count] = NULL;
count = 0;
+ SETUP_PORT_ATTRIBUTE(num_phys);
+ i->port_attrs[count] = NULL;
+
+ count = 0;
SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols);
SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols);
SETUP_RPORT_ATTRIBUTE(rphy_device_type);
@@ -1131,6 +1526,7 @@ void sas_release_transport(struct scsi_transport_template *t)
transport_container_unregister(&i->t.host_attrs);
transport_container_unregister(&i->phy_attr_cont);
+ transport_container_unregister(&i->port_attr_cont);
transport_container_unregister(&i->rphy_attr_cont);
transport_container_unregister(&i->end_dev_attr_cont);
transport_container_unregister(&i->expander_attr_cont);
@@ -1149,9 +1545,12 @@ static __init int sas_transport_init(void)
error = transport_class_register(&sas_phy_class);
if (error)
goto out_unregister_transport;
- error = transport_class_register(&sas_rphy_class);
+ error = transport_class_register(&sas_port_class);
if (error)
goto out_unregister_phy;
+ error = transport_class_register(&sas_rphy_class);
+ if (error)
+ goto out_unregister_port;
error = transport_class_register(&sas_end_dev_class);
if (error)
goto out_unregister_rphy;
@@ -1165,6 +1564,8 @@ static __init int sas_transport_init(void)
transport_class_unregister(&sas_end_dev_class);
out_unregister_rphy:
transport_class_unregister(&sas_rphy_class);
+ out_unregister_port:
+ transport_class_unregister(&sas_port_class);
out_unregister_phy:
transport_class_unregister(&sas_phy_class);
out_unregister_transport:
@@ -1178,6 +1579,7 @@ static void __exit sas_transport_exit(void)
{
transport_class_unregister(&sas_host_class);
transport_class_unregister(&sas_phy_class);
+ transport_class_unregister(&sas_port_class);
transport_class_unregister(&sas_rphy_class);
transport_class_unregister(&sas_end_dev_class);
transport_class_unregister(&sas_expander_class);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index ace49d5bd9c..9f070f0d0f2 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -18,7 +18,6 @@
* 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/config.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -48,6 +47,7 @@
/* Private data accessors (keep these out of the header file) */
#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
+#define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress)
#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex)
struct spi_internal {
@@ -241,6 +241,7 @@ static int spi_setup_transport_attrs(struct transport_container *tc,
spi_pcomp_en(starget) = 0;
spi_hold_mcs(starget) = 0;
spi_dv_pending(starget) = 0;
+ spi_dv_in_progress(starget) = 0;
spi_initial_dv(starget) = 0;
mutex_init(&spi_dv_mutex(starget));
@@ -831,28 +832,37 @@ spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer)
DV_SET(period, spi_min_period(starget));
/* try QAS requests; this should be harmless to set if the
* target supports it */
- if (scsi_device_qas(sdev))
+ if (scsi_device_qas(sdev)) {
DV_SET(qas, 1);
- /* Also try IU transfers */
- if (scsi_device_ius(sdev))
+ } else {
+ DV_SET(qas, 0);
+ }
+
+ if (scsi_device_ius(sdev) && spi_min_period(starget) < 9) {
+ /* This u320 (or u640). Set IU transfers */
DV_SET(iu, 1);
- if (spi_min_period(starget) < 9) {
- /* This u320 (or u640). Ignore the coupled parameters
- * like DT and IU, but set the optional ones */
+ /* Then set the optional parameters */
DV_SET(rd_strm, 1);
DV_SET(wr_flow, 1);
DV_SET(rti, 1);
if (spi_min_period(starget) == 8)
DV_SET(pcomp_en, 1);
+ } else {
+ DV_SET(iu, 0);
}
+
/* now that we've done all this, actually check the bus
* signal type (if known). Some devices are stupid on
* a SE bus and still claim they can try LVD only settings */
if (i->f->get_signalling)
i->f->get_signalling(shost);
if (spi_signalling(shost) == SPI_SIGNAL_SE ||
- spi_signalling(shost) == SPI_SIGNAL_HVD)
+ spi_signalling(shost) == SPI_SIGNAL_HVD ||
+ !scsi_device_dt(sdev)) {
DV_SET(dt, 0);
+ } else {
+ DV_SET(dt, 1);
+ }
/* Do the read only INQUIRY tests */
spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len,
spi_dv_device_compare_inquiry);
@@ -908,6 +918,10 @@ spi_dv_device(struct scsi_device *sdev)
if (unlikely(scsi_device_get(sdev)))
return;
+ if (unlikely(spi_dv_in_progress(starget)))
+ return;
+ spi_dv_in_progress(starget) = 1;
+
buffer = kzalloc(len, GFP_KERNEL);
if (unlikely(!buffer))
@@ -939,6 +953,7 @@ spi_dv_device(struct scsi_device *sdev)
out_free:
kfree(buffer);
out_put:
+ spi_dv_in_progress(starget) = 0;
scsi_device_put(sdev);
}
EXPORT_SYMBOL(spi_dv_device);
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index b78354fc4b1..cd68a66c7bb 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -57,6 +57,7 @@ EXPORT_SYMBOL(scsi_bios_ptable);
int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
{
unsigned char *p;
+ u64 capacity64 = capacity; /* Suppress gcc warning */
int ret;
p = scsi_bios_ptable(bdev);
@@ -68,7 +69,7 @@ int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
(unsigned int *)ip + 0, (unsigned int *)ip + 1);
kfree(p);
- if (ret == -1) {
+ if (ret == -1 && capacity64 < (1ULL << 32)) {
/* pick some standard mapping with at most 1024 cylinders,
and at most 62 sectors per track - this works up to
7905 MB */
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 35419901124..638cff41d43 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -32,7 +32,6 @@
* than the level indicated above to trigger output.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -208,6 +207,23 @@ static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
return count;
}
+static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,
+ size_t count)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+ struct scsi_device *sdp = sdkp->device;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (sdp->type != TYPE_DISK)
+ return -EINVAL;
+
+ sdp->allow_restart = simple_strtoul(buf, NULL, 10);
+
+ return count;
+}
+
static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf)
{
struct scsi_disk *sdkp = to_scsi_disk(cdev);
@@ -223,10 +239,19 @@ static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
}
+static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf)
+{
+ struct scsi_disk *sdkp = to_scsi_disk(cdev);
+
+ return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);
+}
+
static struct class_device_attribute sd_disk_attrs[] = {
__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
sd_store_cache_type),
__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
+ __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,
+ sd_store_allow_restart),
__ATTR_NULL,
};
@@ -477,8 +502,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[4] = (unsigned char) this_count;
SCpnt->cmnd[5] = 0;
}
- SCpnt->request_bufflen = SCpnt->bufflen =
- this_count * sdp->sector_size;
+ SCpnt->request_bufflen = this_count * sdp->sector_size;
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
@@ -891,11 +915,10 @@ static struct block_device_operations sd_fops = {
static void sd_rw_intr(struct scsi_cmnd * SCpnt)
{
int result = SCpnt->result;
- int this_count = SCpnt->request_bufflen;
- int good_bytes = (result == 0 ? this_count : 0);
- sector_t block_sectors = 1;
- u64 first_err_block;
- sector_t error_sector;
+ unsigned int xfer_size = SCpnt->request_bufflen;
+ unsigned int good_bytes = result ? 0 : xfer_size;
+ u64 start_lba = SCpnt->request->sector;
+ u64 bad_lba;
struct scsi_sense_hdr sshdr;
int sense_valid = 0;
int sense_deferred = 0;
@@ -906,7 +929,6 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
-
#ifdef CONFIG_SCSI_LOGGING
SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n",
SCpnt->request->rq_disk->disk_name, result));
@@ -916,89 +938,72 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt)
sshdr.sense_key, sshdr.asc, sshdr.ascq));
}
#endif
- /*
- Handle MEDIUM ERRORs that indicate partial success. Since this is a
- relatively rare error condition, no care is taken to avoid
- unnecessary additional work such as memcpy's that could be avoided.
- */
- if (driver_byte(result) != 0 &&
- sense_valid && !sense_deferred) {
- switch (sshdr.sense_key) {
- case MEDIUM_ERROR:
- if (!blk_fs_request(SCpnt->request))
- break;
- info_valid = scsi_get_sense_info_fld(
- SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
- &first_err_block);
- /*
- * May want to warn and skip if following cast results
- * in actual truncation (if sector_t < 64 bits)
- */
- error_sector = (sector_t)first_err_block;
- if (SCpnt->request->bio != NULL)
- block_sectors = bio_sectors(SCpnt->request->bio);
- switch (SCpnt->device->sector_size) {
- case 1024:
- error_sector <<= 1;
- if (block_sectors < 2)
- block_sectors = 2;
- break;
- case 2048:
- error_sector <<= 2;
- if (block_sectors < 4)
- block_sectors = 4;
- break;
- case 4096:
- error_sector <<=3;
- if (block_sectors < 8)
- block_sectors = 8;
- break;
- case 256:
- error_sector >>= 1;
- break;
- default:
- break;
- }
+ if (driver_byte(result) != DRIVER_SENSE &&
+ (!sense_valid || sense_deferred))
+ goto out;
- error_sector &= ~(block_sectors - 1);
- good_bytes = (error_sector - SCpnt->request->sector) << 9;
- if (good_bytes < 0 || good_bytes >= this_count)
- good_bytes = 0;
+ switch (sshdr.sense_key) {
+ case HARDWARE_ERROR:
+ case MEDIUM_ERROR:
+ if (!blk_fs_request(SCpnt->request))
+ goto out;
+ info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE,
+ &bad_lba);
+ if (!info_valid)
+ goto out;
+ if (xfer_size <= SCpnt->device->sector_size)
+ goto out;
+ switch (SCpnt->device->sector_size) {
+ case 256:
+ start_lba <<= 1;
break;
-
- case RECOVERED_ERROR: /* an error occurred, but it recovered */
- case NO_SENSE: /* LLDD got sense data */
- /*
- * Inform the user, but make sure that it's not treated
- * as a hard error.
- */
- scsi_print_sense("sd", SCpnt);
- SCpnt->result = 0;
- memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
- good_bytes = this_count;
+ case 512:
break;
-
- case ILLEGAL_REQUEST:
- if (SCpnt->device->use_10_for_rw &&
- (SCpnt->cmnd[0] == READ_10 ||
- SCpnt->cmnd[0] == WRITE_10))
- SCpnt->device->use_10_for_rw = 0;
- if (SCpnt->device->use_10_for_ms &&
- (SCpnt->cmnd[0] == MODE_SENSE_10 ||
- SCpnt->cmnd[0] == MODE_SELECT_10))
- SCpnt->device->use_10_for_ms = 0;
+ case 1024:
+ start_lba >>= 1;
+ break;
+ case 2048:
+ start_lba >>= 2;
+ break;
+ case 4096:
+ start_lba >>= 3;
break;
-
default:
+ /* Print something here with limiting frequency. */
+ goto out;
break;
}
+ /* This computation should always be done in terms of
+ * the resolution of the device's medium.
+ */
+ good_bytes = (bad_lba - start_lba)*SCpnt->device->sector_size;
+ break;
+ case RECOVERED_ERROR:
+ case NO_SENSE:
+ /* Inform the user, but make sure that it's not treated
+ * as a hard error.
+ */
+ scsi_print_sense("sd", SCpnt);
+ SCpnt->result = 0;
+ memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+ good_bytes = xfer_size;
+ break;
+ case ILLEGAL_REQUEST:
+ if (SCpnt->device->use_10_for_rw &&
+ (SCpnt->cmnd[0] == READ_10 ||
+ SCpnt->cmnd[0] == WRITE_10))
+ SCpnt->device->use_10_for_rw = 0;
+ if (SCpnt->device->use_10_for_ms &&
+ (SCpnt->cmnd[0] == MODE_SENSE_10 ||
+ SCpnt->cmnd[0] == MODE_SELECT_10))
+ SCpnt->device->use_10_for_ms = 0;
+ break;
+ default:
+ break;
}
- /*
- * This calls the generic completion function, now that we know
- * how many actual sectors finished, and how many sectors we need
- * to say have failed.
- */
- scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+ out:
+ scsi_io_completion(SCpnt, good_bytes);
}
static int media_not_present(struct scsi_disk *sdkp,
@@ -1210,7 +1215,7 @@ repeat:
/* Either no media are present but the drive didn't tell us,
or they are present but the read capacity command fails */
/* sdkp->media_present = 0; -- not always correct */
- sdkp->capacity = 0x200000; /* 1 GB - random */
+ sdkp->capacity = 0; /* unknown mapped to zero - as usual */
return;
} else if (the_result && longrc) {
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 7fa4da4ea64..2679ea8bff1 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -497,7 +497,7 @@ int __init seagate_st0x_detect (struct scsi_host_template * tpnt)
return 0;
hostno = instance->host_no;
- if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
+ if (request_irq (irq, do_seagate_reconnect_intr, IRQF_DISABLED, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
return 0;
}
@@ -1002,7 +1002,7 @@ connect_loop:
}
#endif
- buffer = (struct scatterlist *) SCint->buffer;
+ buffer = (struct scatterlist *) SCint->request_buffer;
len = buffer->length;
data = page_address(buffer->page) + buffer->offset;
} else {
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 98b9312ba8d..34f9343ed0a 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -18,8 +18,8 @@
*
*/
-static int sg_version_num = 30533; /* 2 digits for each component */
-#define SG_VERSION_STR "3.5.33"
+static int sg_version_num = 30534; /* 2 digits for each component */
+#define SG_VERSION_STR "3.5.34"
/*
* D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
@@ -28,7 +28,6 @@ static int sg_version_num = 30533; /* 2 digits for each component */
* (otherwise the macros compile to empty statements).
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
@@ -61,7 +60,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */
#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
-static char *sg_version_date = "20050908";
+static char *sg_version_date = "20060818";
static int sg_proc_init(void);
static void sg_proc_cleanup(void);
@@ -1165,7 +1164,7 @@ sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
len = vma->vm_end - sa;
len = (len < sg->length) ? len : sg->length;
if (offset < len) {
- page = sg->page;
+ page = virt_to_page(page_address(sg->page) + offset);
get_page(page); /* increment page count */
break;
}
@@ -1402,6 +1401,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
Sg_device *sdp = NULL;
struct cdev * cdev = NULL;
int error, k;
+ unsigned long iflags;
disk = alloc_disk(1);
if (!disk) {
@@ -1429,7 +1429,7 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
if (error)
- goto out;
+ goto cdev_add_err;
sdp->cdev = cdev;
if (sg_sysfs_valid) {
@@ -1456,6 +1456,13 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf)
return 0;
+cdev_add_err:
+ write_lock_irqsave(&sg_dev_arr_lock, iflags);
+ kfree(sg_dev_arr[k]);
+ sg_dev_arr[k] = NULL;
+ sg_nr_dev--;
+ write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+
out:
put_disk(disk);
if (cdev)
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 7cd366fcc57..4f1db6f2aae 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -97,7 +97,7 @@ static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
}
static inline
-void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp)
+void fill_hpc_entries(struct hpc_chunk *hcp, struct scsi_cmnd *cmd, int datainp)
{
unsigned long len = cmd->SCp.this_residual;
void *addr = cmd->SCp.ptr;
@@ -129,7 +129,7 @@ void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp)
hcp->desc.cntinfo = HPCDMA_EOX;
}
-static int dma_setup(Scsi_Cmnd *cmd, int datainp)
+static int dma_setup(struct scsi_cmnd *cmd, int datainp)
{
struct ip22_hostdata *hdata = HDATA(cmd->device->host);
struct hpc3_scsiregs *hregs =
@@ -163,7 +163,7 @@ static int dma_setup(Scsi_Cmnd *cmd, int datainp)
return 0;
}
-static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt,
int status)
{
struct ip22_hostdata *hdata = HDATA(instance);
@@ -305,7 +305,7 @@ static int sgiwd93_release(struct Scsi_Host *instance)
return 1;
}
-static int sgiwd93_bus_reset(Scsi_Cmnd *cmd)
+static int sgiwd93_bus_reset(struct scsi_cmnd *cmd)
{
/* FIXME perform bus-specific reset */
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index 255886a9ac5..551baccec52 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -26,7 +26,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/blkdev.h>
@@ -134,7 +133,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
host->this_id = scsi_id;
host->base = base_addr;
host->irq = irq;
- if (request_irq(irq, NCR_700_intr, SA_SHIRQ, "sim710", host)) {
+ if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) {
printk(KERN_ERR "sim710: request_irq failed\n");
goto out_put_host;
}
@@ -283,6 +282,7 @@ static struct eisa_device_id sim710_eisa_ids[] = {
{ "HWP0C80" },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
static __init int
sim710_eisa_probe(struct device *dev)
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index ebf6579ed69..fae6e95a629 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -292,7 +292,7 @@ static void rw_intr(struct scsi_cmnd * SCpnt)
* how many actual sectors finished, and how many sectors we need
* to say have failed.
*/
- scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+ scsi_io_completion(SCpnt, good_bytes);
}
static int sr_init_command(struct scsi_cmnd * SCpnt)
@@ -360,7 +360,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
"mismatch count %d, bytes %d\n",
size, SCpnt->request_bufflen);
if (SCpnt->request_bufflen > size)
- SCpnt->request_bufflen = SCpnt->bufflen = size;
+ SCpnt->request_bufflen = size;
}
}
@@ -387,8 +387,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
if (this_count > 0xffff) {
this_count = 0xffff;
- SCpnt->request_bufflen = SCpnt->bufflen =
- this_count * s_size;
+ SCpnt->request_bufflen = this_count * s_size;
}
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index 9dde8df2f5c..a3e9d0f2eb5 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -34,7 +34,6 @@
* HP 6020 writers now supported.
*/
-#include <linux/config.h>
#include <linux/cdrom.h>
#include <linux/errno.h>
#include <linux/string.h>
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 1272dd249af..7f669b60067 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -368,7 +368,7 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
if (cmdstatp->have_sense)
- __scsi_print_sense("st", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
} ) /* end DEB */
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
@@ -384,9 +384,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
scode != VOLUME_OVERFLOW &&
SRpnt->cmd[0] != MODE_SENSE &&
SRpnt->cmd[0] != TEST_UNIT_READY) {
- printk(KERN_WARNING "%s: Error with sense data: ", name);
- __scsi_print_sense("st", SRpnt->sense,
- SCSI_SENSE_BUFFERSIZE);
+
+ __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
}
@@ -2818,7 +2817,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
(cmdstatp->sense_hdr.sense_key == NO_SENSE ||
cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
undone == 0) {
- ioctl_result = 0; /* EOF written succesfully at EOM */
+ ioctl_result = 0; /* EOF written successfully at EOM */
if (fileno >= 0)
fileno++;
STps->drv_file = fileno;
@@ -3599,7 +3598,6 @@ static struct st_buffer *
tb->use_sg = max_sg;
tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
- tb->in_use = 1;
tb->dma = need_dma;
tb->buffer_size = got;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 411209048d7..05a5cae126e 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -31,7 +31,6 @@ struct st_request {
/* The tape buffer descriptor. */
struct st_buffer {
- unsigned char in_use;
unsigned char dma; /* DMA-able buffer */
unsigned char do_dio; /* direct i/o set up? */
int buffer_size;
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
new file mode 100644
index 00000000000..3cf3106a29b
--- /dev/null
+++ b/drivers/scsi/stex.c
@@ -0,0 +1,1252 @@
+/*
+ * SuperTrak EX Series Storage Controller driver for Linux
+ *
+ * Copyright (C) 2005, 2006 Promise Technology Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Written By:
+ * Ed Lin <promise_linux@promise.com>
+ *
+ * Version: 2.9.0.13
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#define DRV_NAME "stex"
+#define ST_DRIVER_VERSION "2.9.0.13"
+#define ST_VER_MAJOR 2
+#define ST_VER_MINOR 9
+#define ST_OEM 0
+#define ST_BUILD_VER 13
+
+enum {
+ /* MU register offset */
+ IMR0 = 0x10, /* MU_INBOUND_MESSAGE_REG0 */
+ IMR1 = 0x14, /* MU_INBOUND_MESSAGE_REG1 */
+ OMR0 = 0x18, /* MU_OUTBOUND_MESSAGE_REG0 */
+ OMR1 = 0x1c, /* MU_OUTBOUND_MESSAGE_REG1 */
+ IDBL = 0x20, /* MU_INBOUND_DOORBELL */
+ IIS = 0x24, /* MU_INBOUND_INTERRUPT_STATUS */
+ IIM = 0x28, /* MU_INBOUND_INTERRUPT_MASK */
+ ODBL = 0x2c, /* MU_OUTBOUND_DOORBELL */
+ OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */
+ OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */
+
+ /* MU register value */
+ MU_INBOUND_DOORBELL_HANDSHAKE = 1,
+ MU_INBOUND_DOORBELL_REQHEADCHANGED = 2,
+ MU_INBOUND_DOORBELL_STATUSTAILCHANGED = 4,
+ MU_INBOUND_DOORBELL_HMUSTOPPED = 8,
+ MU_INBOUND_DOORBELL_RESET = 16,
+
+ MU_OUTBOUND_DOORBELL_HANDSHAKE = 1,
+ MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = 2,
+ MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = 4,
+ MU_OUTBOUND_DOORBELL_BUSCHANGE = 8,
+ MU_OUTBOUND_DOORBELL_HASEVENT = 16,
+
+ /* MU status code */
+ MU_STATE_STARTING = 1,
+ MU_STATE_FMU_READY_FOR_HANDSHAKE = 2,
+ MU_STATE_SEND_HANDSHAKE_FRAME = 3,
+ MU_STATE_STARTED = 4,
+ MU_STATE_RESETTING = 5,
+
+ MU_MAX_DELAY_TIME = 240000,
+ MU_HANDSHAKE_SIGNATURE = 0x55aaaa55,
+ HMU_PARTNER_TYPE = 2,
+
+ /* firmware returned values */
+ SRB_STATUS_SUCCESS = 0x01,
+ SRB_STATUS_ERROR = 0x04,
+ SRB_STATUS_BUSY = 0x05,
+ SRB_STATUS_INVALID_REQUEST = 0x06,
+ SRB_STATUS_SELECTION_TIMEOUT = 0x0A,
+ SRB_SEE_SENSE = 0x80,
+
+ /* task attribute */
+ TASK_ATTRIBUTE_SIMPLE = 0x0,
+ TASK_ATTRIBUTE_HEADOFQUEUE = 0x1,
+ TASK_ATTRIBUTE_ORDERED = 0x2,
+ TASK_ATTRIBUTE_ACA = 0x4,
+
+ /* request count, etc. */
+ MU_MAX_REQUEST = 32,
+
+ /* one message wasted, use MU_MAX_REQUEST+1
+ to handle MU_MAX_REQUEST messages */
+ MU_REQ_COUNT = (MU_MAX_REQUEST + 1),
+ MU_STATUS_COUNT = (MU_MAX_REQUEST + 1),
+
+ STEX_CDB_LENGTH = MAX_COMMAND_SIZE,
+ REQ_VARIABLE_LEN = 1024,
+ STATUS_VAR_LEN = 128,
+ ST_CAN_QUEUE = MU_MAX_REQUEST,
+ ST_CMD_PER_LUN = MU_MAX_REQUEST,
+ ST_MAX_SG = 32,
+
+ /* sg flags */
+ SG_CF_EOT = 0x80, /* end of table */
+ SG_CF_64B = 0x40, /* 64 bit item */
+ SG_CF_HOST = 0x20, /* sg in host memory */
+
+ ST_MAX_ARRAY_SUPPORTED = 16,
+ ST_MAX_TARGET_NUM = (ST_MAX_ARRAY_SUPPORTED+1),
+ ST_MAX_LUN_PER_TARGET = 16,
+
+ st_shasta = 0,
+ st_vsc = 1,
+
+ PASSTHRU_REQ_TYPE = 0x00000001,
+ PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
+ ST_INTERNAL_TIMEOUT = 30,
+
+ /* vendor specific commands of Promise */
+ ARRAY_CMD = 0xe0,
+ CONTROLLER_CMD = 0xe1,
+ DEBUGGING_CMD = 0xe2,
+ PASSTHRU_CMD = 0xe3,
+
+ PASSTHRU_GET_ADAPTER = 0x05,
+ PASSTHRU_GET_DRVVER = 0x10,
+ CTLR_POWER_STATE_CHANGE = 0x0e,
+ CTLR_POWER_SAVING = 0x01,
+
+ PASSTHRU_SIGNATURE = 0x4e415041,
+
+ INQUIRY_EVPD = 0x01,
+};
+
+struct st_sgitem {
+ u8 ctrl; /* SG_CF_xxx */
+ u8 reserved[3];
+ __le32 count;
+ __le32 addr;
+ __le32 addr_hi;
+};
+
+struct st_sgtable {
+ __le16 sg_count;
+ __le16 max_sg_count;
+ __le32 sz_in_byte;
+ struct st_sgitem table[ST_MAX_SG];
+};
+
+struct handshake_frame {
+ __le32 rb_phy; /* request payload queue physical address */
+ __le32 rb_phy_hi;
+ __le16 req_sz; /* size of each request payload */
+ __le16 req_cnt; /* count of reqs the buffer can hold */
+ __le16 status_sz; /* size of each status payload */
+ __le16 status_cnt; /* count of status the buffer can hold */
+ __le32 hosttime; /* seconds from Jan 1, 1970 (GMT) */
+ __le32 hosttime_hi;
+ u8 partner_type; /* who sends this frame */
+ u8 reserved0[7];
+ __le32 partner_ver_major;
+ __le32 partner_ver_minor;
+ __le32 partner_ver_oem;
+ __le32 partner_ver_build;
+ u32 reserved1[4];
+};
+
+struct req_msg {
+ __le16 tag;
+ u8 lun;
+ u8 target;
+ u8 task_attr;
+ u8 task_manage;
+ u8 prd_entry;
+ u8 payload_sz; /* payload size in 4-byte */
+ u8 cdb[STEX_CDB_LENGTH];
+ u8 variable[REQ_VARIABLE_LEN];
+};
+
+struct status_msg {
+ __le16 tag;
+ u8 lun;
+ u8 target;
+ u8 srb_status;
+ u8 scsi_status;
+ u8 reserved;
+ u8 payload_sz; /* payload size in 4-byte */
+ u8 variable[STATUS_VAR_LEN];
+};
+
+struct ver_info {
+ u32 major;
+ u32 minor;
+ u32 oem;
+ u32 build;
+ u32 reserved[2];
+};
+
+struct st_frame {
+ u32 base[6];
+ u32 rom_addr;
+
+ struct ver_info drv_ver;
+ struct ver_info bios_ver;
+
+ u32 bus;
+ u32 slot;
+ u32 irq_level;
+ u32 irq_vec;
+ u32 id;
+ u32 subid;
+
+ u32 dimm_size;
+ u8 dimm_type;
+ u8 reserved[3];
+
+ u32 channel;
+ u32 reserved1;
+};
+
+struct st_drvver {
+ u32 major;
+ u32 minor;
+ u32 oem;
+ u32 build;
+ u32 signature[2];
+ u8 console_id;
+ u8 host_no;
+ u8 reserved0[2];
+ u32 reserved[3];
+};
+
+#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg))
+#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg))
+#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
+#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + sizeof(struct st_frame))
+
+struct st_ccb {
+ struct req_msg *req;
+ struct scsi_cmnd *cmd;
+
+ void *sense_buffer;
+ unsigned int sense_bufflen;
+ int sg_count;
+
+ u32 req_type;
+ u8 srb_status;
+ u8 scsi_status;
+};
+
+struct st_hba {
+ void __iomem *mmio_base; /* iomapped PCI memory space */
+ void *dma_mem;
+ dma_addr_t dma_handle;
+
+ struct Scsi_Host *host;
+ struct pci_dev *pdev;
+
+ u32 req_head;
+ u32 req_tail;
+ u32 status_head;
+ u32 status_tail;
+
+ struct status_msg *status_buffer;
+ void *copy_buffer; /* temp buffer for driver-handled commands */
+ struct st_ccb ccb[MU_MAX_REQUEST];
+ struct st_ccb *wait_ccb;
+ wait_queue_head_t waitq;
+
+ unsigned int mu_status;
+ int out_req_cnt;
+
+ unsigned int cardtype;
+};
+
+static const char console_inq_page[] =
+{
+ 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30,
+ 0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20, /* "Promise " */
+ 0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E, /* "RAID Con" */
+ 0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20, /* "sole " */
+ 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20, /* "1.00 " */
+ 0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D, /* "SX/RSAF-" */
+ 0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20, /* "TE1.00 " */
+ 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20
+};
+
+MODULE_AUTHOR("Ed Lin");
+MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ST_DRIVER_VERSION);
+
+static void stex_gettime(__le32 *time)
+{
+ struct timeval tv;
+ do_gettimeofday(&tv);
+
+ *time = cpu_to_le32(tv.tv_sec & 0xffffffff);
+ *(time + 1) = cpu_to_le32((tv.tv_sec >> 16) >> 16);
+}
+
+static struct status_msg *stex_get_status(struct st_hba *hba)
+{
+ struct status_msg *status =
+ hba->status_buffer + hba->status_tail;
+
+ ++hba->status_tail;
+ hba->status_tail %= MU_STATUS_COUNT;
+
+ return status;
+}
+
+static void stex_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ cmd->sense_buffer[0] = 0x70; /* fixed format, current */
+ cmd->sense_buffer[2] = sk;
+ cmd->sense_buffer[7] = 18 - 8; /* additional sense length */
+ cmd->sense_buffer[12] = asc;
+ cmd->sense_buffer[13] = ascq;
+}
+
+static void stex_invalid_field(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ /* "Invalid field in cbd" */
+ stex_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+ done(cmd);
+}
+
+static struct req_msg *stex_alloc_req(struct st_hba *hba)
+{
+ struct req_msg *req = ((struct req_msg *)hba->dma_mem) +
+ hba->req_head;
+
+ ++hba->req_head;
+ hba->req_head %= MU_REQ_COUNT;
+
+ return req;
+}
+
+static int stex_map_sg(struct st_hba *hba,
+ struct req_msg *req, struct st_ccb *ccb)
+{
+ struct pci_dev *pdev = hba->pdev;
+ struct scsi_cmnd *cmd;
+ dma_addr_t dma_handle;
+ struct scatterlist *src;
+ struct st_sgtable *dst;
+ int i;
+
+ cmd = ccb->cmd;
+ dst = (struct st_sgtable *)req->variable;
+ dst->max_sg_count = cpu_to_le16(ST_MAX_SG);
+ dst->sz_in_byte = cpu_to_le32(cmd->request_bufflen);
+
+ if (cmd->use_sg) {
+ int n_elem;
+
+ src = (struct scatterlist *) cmd->request_buffer;
+ n_elem = pci_map_sg(pdev, src,
+ cmd->use_sg, cmd->sc_data_direction);
+ if (n_elem <= 0)
+ return -EIO;
+
+ ccb->sg_count = n_elem;
+ dst->sg_count = cpu_to_le16((u16)n_elem);
+
+ for (i = 0; i < n_elem; i++, src++) {
+ dst->table[i].count = cpu_to_le32((u32)sg_dma_len(src));
+ dst->table[i].addr =
+ cpu_to_le32(sg_dma_address(src) & 0xffffffff);
+ dst->table[i].addr_hi =
+ cpu_to_le32((sg_dma_address(src) >> 16) >> 16);
+ dst->table[i].ctrl = SG_CF_64B | SG_CF_HOST;
+ }
+ dst->table[--i].ctrl |= SG_CF_EOT;
+ return 0;
+ }
+
+ dma_handle = pci_map_single(pdev, cmd->request_buffer,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ cmd->SCp.dma_handle = dma_handle;
+
+ ccb->sg_count = 1;
+ dst->sg_count = cpu_to_le16(1);
+ dst->table[0].addr = cpu_to_le32(dma_handle & 0xffffffff);
+ dst->table[0].addr_hi = cpu_to_le32((dma_handle >> 16) >> 16);
+ dst->table[0].count = cpu_to_le32((u32)cmd->request_bufflen);
+ dst->table[0].ctrl = SG_CF_EOT | SG_CF_64B | SG_CF_HOST;
+
+ return 0;
+}
+
+static void stex_internal_copy(struct scsi_cmnd *cmd,
+ const void *src, size_t *count, int sg_count)
+{
+ size_t lcount;
+ size_t len;
+ void *s, *d, *base = NULL;
+ if (*count > cmd->request_bufflen)
+ *count = cmd->request_bufflen;
+ lcount = *count;
+ while (lcount) {
+ len = lcount;
+ s = (void *)src;
+ if (cmd->use_sg) {
+ size_t offset = *count - lcount;
+ s += offset;
+ base = scsi_kmap_atomic_sg(cmd->request_buffer,
+ sg_count, &offset, &len);
+ if (base == NULL) {
+ *count -= lcount;
+ return;
+ }
+ d = base + offset;
+ } else
+ d = cmd->request_buffer;
+
+ memcpy(d, s, len);
+
+ lcount -= len;
+ if (cmd->use_sg)
+ scsi_kunmap_atomic_sg(base);
+ }
+}
+
+static int stex_direct_copy(struct scsi_cmnd *cmd,
+ const void *src, size_t count)
+{
+ struct st_hba *hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+ size_t cp_len = count;
+ int n_elem = 0;
+
+ if (cmd->use_sg) {
+ n_elem = pci_map_sg(hba->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ if (n_elem <= 0)
+ return 0;
+ }
+
+ stex_internal_copy(cmd, src, &cp_len, n_elem);
+
+ if (cmd->use_sg)
+ pci_unmap_sg(hba->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ return cp_len == count;
+}
+
+static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
+{
+ struct st_frame *p;
+ size_t count = sizeof(struct st_frame);
+
+ p = hba->copy_buffer;
+ memset(p->base, 0, sizeof(u32)*6);
+ *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0);
+ p->rom_addr = 0;
+
+ p->drv_ver.major = ST_VER_MAJOR;
+ p->drv_ver.minor = ST_VER_MINOR;
+ p->drv_ver.oem = ST_OEM;
+ p->drv_ver.build = ST_BUILD_VER;
+
+ p->bus = hba->pdev->bus->number;
+ p->slot = hba->pdev->devfn;
+ p->irq_level = 0;
+ p->irq_vec = hba->pdev->irq;
+ p->id = hba->pdev->vendor << 16 | hba->pdev->device;
+ p->subid =
+ hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
+
+ stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
+}
+
+static void
+stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
+{
+ req->tag = cpu_to_le16(tag);
+ req->task_attr = TASK_ATTRIBUTE_SIMPLE;
+ req->task_manage = 0; /* not supported yet */
+ req->payload_sz = (u8)(sizeof(struct req_msg)/sizeof(u32));
+
+ hba->ccb[tag].req = req;
+ hba->out_req_cnt++;
+
+ writel(hba->req_head, hba->mmio_base + IMR0);
+ writel(MU_INBOUND_DOORBELL_REQHEADCHANGED, hba->mmio_base + IDBL);
+ readl(hba->mmio_base + IDBL); /* flush */
+}
+
+static int
+stex_slave_alloc(struct scsi_device *sdev)
+{
+ /* Cheat: usually extracted from Inquiry data */
+ sdev->tagged_supported = 1;
+
+ scsi_activate_tcq(sdev, sdev->host->can_queue);
+
+ return 0;
+}
+
+static int
+stex_slave_config(struct scsi_device *sdev)
+{
+ sdev->use_10_for_rw = 1;
+ sdev->use_10_for_ms = 1;
+ sdev->timeout = 60 * HZ;
+ sdev->tagged_supported = 1;
+
+ return 0;
+}
+
+static void
+stex_slave_destroy(struct scsi_device *sdev)
+{
+ scsi_deactivate_tcq(sdev, 1);
+}
+
+static int
+stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+{
+ struct st_hba *hba;
+ struct Scsi_Host *host;
+ unsigned int id,lun;
+ struct req_msg *req;
+ u16 tag;
+ host = cmd->device->host;
+ id = cmd->device->id;
+ lun = cmd->device->channel; /* firmware lun issue work around */
+ hba = (struct st_hba *) &host->hostdata[0];
+
+ switch (cmd->cmnd[0]) {
+ case MODE_SENSE_10:
+ {
+ static char ms10_caching_page[12] =
+ { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 };
+ unsigned char page;
+ page = cmd->cmnd[2] & 0x3f;
+ if (page == 0x8 || page == 0x3f) {
+ stex_direct_copy(cmd, ms10_caching_page,
+ sizeof(ms10_caching_page));
+ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ } else
+ stex_invalid_field(cmd, done);
+ return 0;
+ }
+ case INQUIRY:
+ if (id != ST_MAX_ARRAY_SUPPORTED)
+ break;
+ if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) {
+ stex_direct_copy(cmd, console_inq_page,
+ sizeof(console_inq_page));
+ cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ } else
+ stex_invalid_field(cmd, done);
+ return 0;
+ case PASSTHRU_CMD:
+ if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) {
+ struct st_drvver ver;
+ ver.major = ST_VER_MAJOR;
+ ver.minor = ST_VER_MINOR;
+ ver.oem = ST_OEM;
+ ver.build = ST_BUILD_VER;
+ ver.signature[0] = PASSTHRU_SIGNATURE;
+ ver.console_id = ST_MAX_ARRAY_SUPPORTED;
+ ver.host_no = hba->host->host_no;
+ cmd->result = stex_direct_copy(cmd, &ver, sizeof(ver)) ?
+ DID_OK << 16 | COMMAND_COMPLETE << 8 :
+ DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ done(cmd);
+ return 0;
+ }
+ default:
+ break;
+ }
+
+ cmd->scsi_done = done;
+
+ tag = cmd->request->tag;
+
+ if (unlikely(tag >= host->can_queue))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ req = stex_alloc_req(hba);
+ req->lun = lun;
+ req->target = id;
+
+ /* cdb */
+ memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
+
+ hba->ccb[tag].cmd = cmd;
+ hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE;
+ hba->ccb[tag].sense_buffer = cmd->sense_buffer;
+ hba->ccb[tag].req_type = 0;
+
+ if (cmd->sc_data_direction != DMA_NONE)
+ stex_map_sg(hba, req, &hba->ccb[tag]);
+
+ stex_send_cmd(hba, req, tag);
+ return 0;
+}
+
+static void stex_unmap_sg(struct st_hba *hba, struct scsi_cmnd *cmd)
+{
+ if (cmd->sc_data_direction != DMA_NONE) {
+ if (cmd->use_sg)
+ pci_unmap_sg(hba->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ else
+ pci_unmap_single(hba->pdev, cmd->SCp.dma_handle,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ }
+}
+
+static void stex_scsi_done(struct st_ccb *ccb)
+{
+ struct scsi_cmnd *cmd = ccb->cmd;
+ int result;
+
+ if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) {
+ result = ccb->scsi_status;
+ switch (ccb->scsi_status) {
+ case SAM_STAT_GOOD:
+ result |= DID_OK << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SAM_STAT_CHECK_CONDITION:
+ result |= DRIVER_SENSE << 24;
+ break;
+ case SAM_STAT_BUSY:
+ result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
+ break;
+ default:
+ result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ break;
+ }
+ }
+ else if (ccb->srb_status & SRB_SEE_SENSE)
+ result = DRIVER_SENSE << 24 | SAM_STAT_CHECK_CONDITION;
+ else switch (ccb->srb_status) {
+ case SRB_STATUS_SELECTION_TIMEOUT:
+ result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SRB_STATUS_BUSY:
+ result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SRB_STATUS_INVALID_REQUEST:
+ case SRB_STATUS_ERROR:
+ default:
+ result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+ break;
+ }
+
+ cmd->result = result;
+ cmd->scsi_done(cmd);
+}
+
+static void stex_copy_data(struct st_ccb *ccb,
+ struct status_msg *resp, unsigned int variable)
+{
+ size_t count = variable;
+ if (resp->scsi_status != SAM_STAT_GOOD) {
+ if (ccb->sense_buffer != NULL)
+ memcpy(ccb->sense_buffer, resp->variable,
+ min(variable, ccb->sense_bufflen));
+ return;
+ }
+
+ if (ccb->cmd == NULL)
+ return;
+ stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
+}
+
+static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
+{
+ void __iomem *base = hba->mmio_base;
+ struct status_msg *resp;
+ struct st_ccb *ccb;
+ unsigned int size;
+ u16 tag;
+
+ if (!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))
+ return;
+
+ /* status payloads */
+ hba->status_head = readl(base + OMR1);
+ if (unlikely(hba->status_head >= MU_STATUS_COUNT)) {
+ printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n",
+ pci_name(hba->pdev));
+ return;
+ }
+
+ if (unlikely(hba->mu_status != MU_STATE_STARTED ||
+ hba->out_req_cnt <= 0)) {
+ hba->status_tail = hba->status_head;
+ goto update_status;
+ }
+
+ while (hba->status_tail != hba->status_head) {
+ resp = stex_get_status(hba);
+ tag = le16_to_cpu(resp->tag);
+ if (unlikely(tag >= hba->host->can_queue)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): invalid tag\n", pci_name(hba->pdev));
+ continue;
+ }
+
+ ccb = &hba->ccb[tag];
+ if (hba->wait_ccb == ccb)
+ hba->wait_ccb = NULL;
+ if (unlikely(ccb->req == NULL)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): lagging req\n", pci_name(hba->pdev));
+ continue;
+ }
+
+ size = resp->payload_sz * sizeof(u32); /* payload size */
+ if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN ||
+ size > sizeof(*resp))) {
+ printk(KERN_WARNING DRV_NAME "(%s): bad status size\n",
+ pci_name(hba->pdev));
+ } else {
+ size -= sizeof(*resp) - STATUS_VAR_LEN; /* copy size */
+ if (size)
+ stex_copy_data(ccb, resp, size);
+ }
+
+ ccb->srb_status = resp->srb_status;
+ ccb->scsi_status = resp->scsi_status;
+
+ if (likely(ccb->cmd != NULL)) {
+ if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
+ ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
+ stex_controller_info(hba, ccb);
+ stex_unmap_sg(hba, ccb->cmd);
+ stex_scsi_done(ccb);
+ hba->out_req_cnt--;
+ } else if (ccb->req_type & PASSTHRU_REQ_TYPE) {
+ hba->out_req_cnt--;
+ if (ccb->req_type & PASSTHRU_REQ_NO_WAKEUP) {
+ ccb->req_type = 0;
+ continue;
+ }
+ ccb->req_type = 0;
+ if (waitqueue_active(&hba->waitq))
+ wake_up(&hba->waitq);
+ }
+ }
+
+update_status:
+ writel(hba->status_head, base + IMR1);
+ readl(base + IMR1); /* flush */
+}
+
+static irqreturn_t stex_intr(int irq, void *__hba, struct pt_regs *regs)
+{
+ struct st_hba *hba = __hba;
+ void __iomem *base = hba->mmio_base;
+ u32 data;
+ unsigned long flags;
+ int handled = 0;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+
+ data = readl(base + ODBL);
+
+ if (data && data != 0xffffffff) {
+ /* clear the interrupt */
+ writel(data, base + ODBL);
+ readl(base + ODBL); /* flush */
+ stex_mu_intr(hba, data);
+ handled = 1;
+ }
+
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+static int stex_handshake(struct st_hba *hba)
+{
+ void __iomem *base = hba->mmio_base;
+ struct handshake_frame *h;
+ dma_addr_t status_phys;
+ int i;
+
+ if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) {
+ writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
+ readl(base + IDBL);
+ for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
+ && i < MU_MAX_DELAY_TIME; i++) {
+ rmb();
+ msleep(1);
+ }
+
+ if (i == MU_MAX_DELAY_TIME) {
+ printk(KERN_ERR DRV_NAME
+ "(%s): no handshake signature\n",
+ pci_name(hba->pdev));
+ return -1;
+ }
+ }
+
+ udelay(10);
+
+ h = (struct handshake_frame *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
+ h->rb_phy = cpu_to_le32(hba->dma_handle);
+ h->rb_phy_hi = cpu_to_le32((hba->dma_handle >> 16) >> 16);
+ h->req_sz = cpu_to_le16(sizeof(struct req_msg));
+ h->req_cnt = cpu_to_le16(MU_REQ_COUNT);
+ h->status_sz = cpu_to_le16(sizeof(struct status_msg));
+ h->status_cnt = cpu_to_le16(MU_STATUS_COUNT);
+ stex_gettime(&h->hosttime);
+ h->partner_type = HMU_PARTNER_TYPE;
+
+ status_phys = hba->dma_handle + MU_REQ_BUFFER_SIZE;
+ writel(status_phys, base + IMR0);
+ readl(base + IMR0);
+ writel((status_phys >> 16) >> 16, base + IMR1);
+ readl(base + IMR1);
+
+ writel((status_phys >> 16) >> 16, base + OMR0); /* old fw compatible */
+ readl(base + OMR0);
+ writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL);
+ readl(base + IDBL); /* flush */
+
+ udelay(10);
+ for (i = 0; readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE
+ && i < MU_MAX_DELAY_TIME; i++) {
+ rmb();
+ msleep(1);
+ }
+
+ if (i == MU_MAX_DELAY_TIME) {
+ printk(KERN_ERR DRV_NAME
+ "(%s): no signature after handshake frame\n",
+ pci_name(hba->pdev));
+ return -1;
+ }
+
+ writel(0, base + IMR0);
+ readl(base + IMR0);
+ writel(0, base + OMR0);
+ readl(base + OMR0);
+ writel(0, base + IMR1);
+ readl(base + IMR1);
+ writel(0, base + OMR1);
+ readl(base + OMR1); /* flush */
+ hba->mu_status = MU_STATE_STARTED;
+ return 0;
+}
+
+static int stex_abort(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ struct st_hba *hba = (struct st_hba *)host->hostdata;
+ u16 tag = cmd->request->tag;
+ void __iomem *base;
+ u32 data;
+ int result = SUCCESS;
+ unsigned long flags;
+ base = hba->mmio_base;
+ spin_lock_irqsave(host->host_lock, flags);
+ if (tag < host->can_queue && hba->ccb[tag].cmd == cmd)
+ hba->wait_ccb = &hba->ccb[tag];
+ else {
+ for (tag = 0; tag < host->can_queue; tag++)
+ if (hba->ccb[tag].cmd == cmd) {
+ hba->wait_ccb = &hba->ccb[tag];
+ break;
+ }
+ if (tag >= host->can_queue)
+ goto out;
+ }
+
+ data = readl(base + ODBL);
+ if (data == 0 || data == 0xffffffff)
+ goto fail_out;
+
+ writel(data, base + ODBL);
+ readl(base + ODBL); /* flush */
+
+ stex_mu_intr(hba, data);
+
+ if (hba->wait_ccb == NULL) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): lost interrupt\n", pci_name(hba->pdev));
+ goto out;
+ }
+
+fail_out:
+ stex_unmap_sg(hba, cmd);
+ hba->wait_ccb->req = NULL; /* nullify the req's future return */
+ hba->wait_ccb = NULL;
+ result = FAILED;
+out:
+ spin_unlock_irqrestore(host->host_lock, flags);
+ return result;
+}
+
+static void stex_hard_reset(struct st_hba *hba)
+{
+ struct pci_bus *bus;
+ int i;
+ u16 pci_cmd;
+ u8 pci_bctl;
+
+ for (i = 0; i < 16; i++)
+ pci_read_config_dword(hba->pdev, i * 4,
+ &hba->pdev->saved_config_space[i]);
+
+ /* Reset secondary bus. Our controller(MU/ATU) is the only device on
+ secondary bus. Consult Intel 80331/3 developer's manual for detail */
+ bus = hba->pdev->bus;
+ pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl);
+ pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
+ msleep(1);
+ pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET;
+ pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl);
+
+ for (i = 0; i < MU_MAX_DELAY_TIME; i++) {
+ pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd);
+ if (pci_cmd & PCI_COMMAND_MASTER)
+ break;
+ msleep(1);
+ }
+
+ ssleep(5);
+ for (i = 0; i < 16; i++)
+ pci_write_config_dword(hba->pdev, i * 4,
+ hba->pdev->saved_config_space[i]);
+}
+
+static int stex_reset(struct scsi_cmnd *cmd)
+{
+ struct st_hba *hba;
+ unsigned long flags;
+ hba = (struct st_hba *) &cmd->device->host->hostdata[0];
+
+ hba->mu_status = MU_STATE_RESETTING;
+
+ if (hba->cardtype == st_shasta)
+ stex_hard_reset(hba);
+
+ if (stex_handshake(hba)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): resetting: handshake failed\n",
+ pci_name(hba->pdev));
+ return FAILED;
+ }
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->req_head = 0;
+ hba->req_tail = 0;
+ hba->status_head = 0;
+ hba->status_tail = 0;
+ hba->out_req_cnt = 0;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ return SUCCESS;
+}
+
+static int stex_biosparam(struct scsi_device *sdev,
+ struct block_device *bdev, sector_t capacity, int geom[])
+{
+ int heads = 255, sectors = 63, cylinders;
+
+ if (capacity < 0x200000) {
+ heads = 64;
+ sectors = 32;
+ }
+
+ cylinders = sector_div(capacity, heads * sectors);
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+
+ return 0;
+}
+
+static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
+ .name = DRV_NAME,
+ .proc_name = DRV_NAME,
+ .bios_param = stex_biosparam,
+ .queuecommand = stex_queuecommand,
+ .slave_alloc = stex_slave_alloc,
+ .slave_configure = stex_slave_config,
+ .slave_destroy = stex_slave_destroy,
+ .eh_abort_handler = stex_abort,
+ .eh_host_reset_handler = stex_reset,
+ .can_queue = ST_CAN_QUEUE,
+ .this_id = -1,
+ .sg_tablesize = ST_MAX_SG,
+ .cmd_per_lun = ST_CMD_PER_LUN,
+};
+
+static int stex_set_dma_mask(struct pci_dev * pdev)
+{
+ int ret;
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)
+ && !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+ return 0;
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (!ret)
+ ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+ return ret;
+}
+
+static int __devinit
+stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct st_hba *hba;
+ struct Scsi_Host *host;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+
+ pci_set_master(pdev);
+
+ host = scsi_host_alloc(&driver_template, sizeof(struct st_hba));
+
+ if (!host) {
+ printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto out_disable;
+ }
+
+ hba = (struct st_hba *)host->hostdata;
+ memset(hba, 0, sizeof(struct st_hba));
+
+ err = pci_request_regions(pdev, DRV_NAME);
+ if (err < 0) {
+ printk(KERN_ERR DRV_NAME "(%s): request regions failed\n",
+ pci_name(pdev));
+ goto out_scsi_host_put;
+ }
+
+ hba->mmio_base = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ if ( !hba->mmio_base) {
+ printk(KERN_ERR DRV_NAME "(%s): memory map failed\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ err = stex_set_dma_mask(pdev);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n",
+ pci_name(pdev));
+ goto out_iounmap;
+ }
+
+ hba->dma_mem = dma_alloc_coherent(&pdev->dev,
+ STEX_BUFFER_SIZE, &hba->dma_handle, GFP_KERNEL);
+ if (!hba->dma_mem) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n",
+ pci_name(pdev));
+ goto out_iounmap;
+ }
+
+ hba->status_buffer =
+ (struct status_msg *)(hba->dma_mem + MU_REQ_BUFFER_SIZE);
+ hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE;
+ hba->mu_status = MU_STATE_STARTING;
+
+ hba->cardtype = (unsigned int) id->driver_data;
+
+ /* firmware uses id/lun pair for a logical drive, but lun would be
+ always 0 if CONFIG_SCSI_MULTI_LUN not configured, so we use
+ channel to map lun here */
+ host->max_channel = ST_MAX_LUN_PER_TARGET - 1;
+ host->max_id = ST_MAX_TARGET_NUM;
+ host->max_lun = 1;
+ host->unique_id = host->host_no;
+ host->max_cmd_len = STEX_CDB_LENGTH;
+
+ hba->host = host;
+ hba->pdev = pdev;
+ init_waitqueue_head(&hba->waitq);
+
+ err = request_irq(pdev->irq, stex_intr, IRQF_SHARED, DRV_NAME, hba);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): request irq failed\n",
+ pci_name(pdev));
+ goto out_pci_free;
+ }
+
+ err = stex_handshake(hba);
+ if (err)
+ goto out_free_irq;
+
+ err = scsi_init_shared_tag_map(host, ST_CAN_QUEUE);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
+ pci_name(pdev));
+ goto out_free_irq;
+ }
+
+ pci_set_drvdata(pdev, hba);
+
+ err = scsi_add_host(host, &pdev->dev);
+ if (err) {
+ printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n",
+ pci_name(pdev));
+ goto out_free_irq;
+ }
+
+ scsi_scan_host(host);
+
+ return 0;
+
+out_free_irq:
+ free_irq(pdev->irq, hba);
+out_pci_free:
+ dma_free_coherent(&pdev->dev, STEX_BUFFER_SIZE,
+ hba->dma_mem, hba->dma_handle);
+out_iounmap:
+ iounmap(hba->mmio_base);
+out_release_regions:
+ pci_release_regions(pdev);
+out_scsi_host_put:
+ scsi_host_put(host);
+out_disable:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void stex_hba_stop(struct st_hba *hba)
+{
+ struct req_msg *req;
+ unsigned long flags;
+ unsigned long before;
+ u16 tag = 0;
+
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ req = stex_alloc_req(hba);
+ memset(req->cdb, 0, STEX_CDB_LENGTH);
+
+ req->cdb[0] = CONTROLLER_CMD;
+ req->cdb[1] = CTLR_POWER_STATE_CHANGE;
+ req->cdb[2] = CTLR_POWER_SAVING;
+
+ hba->ccb[tag].cmd = NULL;
+ hba->ccb[tag].sg_count = 0;
+ hba->ccb[tag].sense_bufflen = 0;
+ hba->ccb[tag].sense_buffer = NULL;
+ hba->ccb[tag].req_type |= PASSTHRU_REQ_TYPE;
+
+ stex_send_cmd(hba, req, tag);
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+
+ before = jiffies;
+ while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ))
+ return;
+ msleep(10);
+ }
+}
+
+static void stex_hba_free(struct st_hba *hba)
+{
+ free_irq(hba->pdev->irq, hba);
+
+ iounmap(hba->mmio_base);
+
+ pci_release_regions(hba->pdev);
+
+ dma_free_coherent(&hba->pdev->dev, STEX_BUFFER_SIZE,
+ hba->dma_mem, hba->dma_handle);
+}
+
+static void stex_remove(struct pci_dev *pdev)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ scsi_remove_host(hba->host);
+
+ pci_set_drvdata(pdev, NULL);
+
+ stex_hba_stop(hba);
+
+ stex_hba_free(hba);
+
+ scsi_host_put(hba->host);
+
+ pci_disable_device(pdev);
+}
+
+static void stex_shutdown(struct pci_dev *pdev)
+{
+ struct st_hba *hba = pci_get_drvdata(pdev);
+
+ stex_hba_stop(hba);
+}
+
+static struct pci_device_id stex_pci_tbl[] = {
+ { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x105a, 0xf350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x105a, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
+ { 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
+ { } /* terminate list */
+};
+MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
+
+static struct pci_driver stex_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = stex_pci_tbl,
+ .probe = stex_probe,
+ .remove = __devexit_p(stex_remove),
+ .shutdown = stex_shutdown,
+};
+
+static int __init stex_init(void)
+{
+ printk(KERN_INFO DRV_NAME
+ ": Promise SuperTrak EX Driver version: %s\n",
+ ST_DRIVER_VERSION);
+
+ return pci_register_driver(&stex_pci_driver);
+}
+
+static void __exit stex_exit(void)
+{
+ pci_unregister_driver(&stex_pci_driver);
+}
+
+module_init(stex_init);
+module_exit(stex_exit);
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 25cced91c8a..2f8073b73bf 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -517,7 +517,7 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
cmd->SCp.this_residual = cmd->SCp.buffer->length;
@@ -535,7 +535,6 @@ static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
}
-#include <linux/config.h>
#include <linux/delay.h>
#if 1
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
index cc990bed968..6b60536ac92 100644
--- a/drivers/scsi/sun3x_esp.c
+++ b/drivers/scsi/sun3x_esp.c
@@ -97,7 +97,7 @@ int sun3x_esp_detect(struct scsi_host_template *tpnt)
esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command);
esp->irq = 2;
- if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ if (request_irq(esp->irq, esp_intr, IRQF_DISABLED,
"SUN3X SCSI", esp->ehost)) {
esp_deallocate(esp);
return 0;
@@ -332,11 +332,11 @@ static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
struct scatterlist *sg = sp->SCp.buffer;
while (sz >= 0) {
- sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
+ sg[sz].dma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
sg[sz].offset, sg[sz].length);
sz--;
}
- sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+ sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dma_address);
}
static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
@@ -347,17 +347,17 @@ static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
{
int sz = sp->use_sg - 1;
- struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+ struct scatterlist *sg = (struct scatterlist *)sp->request_buffer;
while(sz >= 0) {
- dvma_unmap((char *)sg[sz].dvma_address);
+ dvma_unmap((char *)sg[sz].dma_address);
sz--;
}
}
static void dma_advance_sg (Scsi_Cmnd *sp)
{
- sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+ sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dma_address);
}
static int sun3x_esp_release(struct Scsi_Host *instance)
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
index 48110376972..7519728dfc3 100644
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -40,7 +40,6 @@
#ifndef SYM53C8XX_H
#define SYM53C8XX_H
-#include <linux/config.h>
/*
* DMA addressing mode.
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index ea82d3df63a..739d3ef46a4 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1547,7 +1547,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
* If we synchonize the C code with SCRIPTS on interrupt,
* we do not want to share the INTR line at all.
*/
- if (request_irq(pdev->irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) {
+ if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX, np)) {
printf_err("%s: request irq %d failure\n",
sym_name(np), pdev->irq);
goto attach_failed;
@@ -2084,7 +2084,7 @@ static struct pci_device_id sym2_id_table[] __devinitdata = {
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895,
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
index a446cda3f64..e022d3c71b5 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.h
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -40,7 +40,6 @@
#ifndef SYM_GLUE_H
#define SYM_GLUE_H
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/pci.h>
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index a24f661b027..2df6747cb76 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -260,7 +260,7 @@ found:
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, t128_intr, SA_INTERRUPT, "t128", instance)) {
+ if (request_irq(instance->irq, t128_intr, IRQF_DISABLED, "t128", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
instance->irq = SCSI_IRQ_NONE;
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 91322aff241..9404ff3d4c7 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -218,7 +218,6 @@
#endif
#define DCBDEBUG1(x) C_NOP
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/signal.h>
@@ -2585,7 +2584,7 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev,
/* Reset Pending INT */
DC390_read8_(INT_Status, io_port);
- if (request_irq(pdev->irq, do_DC390_Interrupt, SA_SHIRQ,
+ if (request_irq(pdev->irq, do_DC390_Interrupt, IRQF_SHARED,
"tmscsim", pACB)) {
printk(KERN_ERR "DC390: register IRQ error!\n");
goto out_release_region;
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index d4495272fb4..9b66fa8d38d 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -9,7 +9,6 @@
#define _TMSCSIM_H
#include <linux/types.h>
-#include <linux/config.h>
#define SCSI_IRQ_NONE 255
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 33cd90fc657..57449611e71 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -405,7 +405,6 @@
* the driver sets host->wish_block = TRUE for all ISA boards.
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -873,7 +872,7 @@ static int port_detect \
/* Board detected, allocate its IRQ */
if (request_irq(irq, do_interrupt_handler,
- SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+ IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0),
driver_name, (void *) &sha[j])) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
goto freelock;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index e681681ab7a..0372aa9fa19 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -196,8 +196,8 @@ struct mscp {
u32 sense_data PACKED;
/* The following fields are for software only. They are included in
the MSCP structure because they are associated with SCSI requests. */
- void (*done)(Scsi_Cmnd *);
- Scsi_Cmnd *SCint;
+ void (*done) (struct scsi_cmnd *);
+ struct scsi_cmnd *SCint;
ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */
};
@@ -289,7 +289,7 @@ static const unsigned short ultrastor_ports_14f[] = {
static void ultrastor_interrupt(int, void *, struct pt_regs *);
static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *);
-static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
+static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt);
/* Always called with host lock held */
@@ -673,7 +673,7 @@ static const char *ultrastor_info(struct Scsi_Host * shpnt)
return buf;
}
-static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
+static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt)
{
struct scatterlist *sl;
long transfer_length = 0;
@@ -694,7 +694,8 @@ static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
mscp->transfer_data_length = transfer_length;
}
-static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int ultrastor_queuecommand(struct scsi_cmnd *SCpnt,
+ void (*done) (struct scsi_cmnd *))
{
struct mscp *my_mscp;
#if ULTRASTOR_MAX_CMDS > 1
@@ -833,7 +834,7 @@ retry:
*/
-static int ultrastor_abort(Scsi_Cmnd *SCpnt)
+static int ultrastor_abort(struct scsi_cmnd *SCpnt)
{
#if ULTRASTOR_DEBUG & UD_ABORT
char out[108];
@@ -843,7 +844,7 @@ static int ultrastor_abort(Scsi_Cmnd *SCpnt)
unsigned int mscp_index;
unsigned char old_aborted;
unsigned long flags;
- void (*done)(Scsi_Cmnd *);
+ void (*done)(struct scsi_cmnd *);
struct Scsi_Host *host = SCpnt->device->host;
if(config.slot)
@@ -960,7 +961,7 @@ static int ultrastor_abort(Scsi_Cmnd *SCpnt)
return SUCCESS;
}
-static int ultrastor_host_reset(Scsi_Cmnd * SCpnt)
+static int ultrastor_host_reset(struct scsi_cmnd * SCpnt)
{
unsigned long flags;
int i;
@@ -1045,8 +1046,8 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned int mscp_index;
#endif
struct mscp *mscp;
- void (*done)(Scsi_Cmnd *);
- Scsi_Cmnd *SCtmp;
+ void (*done) (struct scsi_cmnd *);
+ struct scsi_cmnd *SCtmp;
#if ULTRASTOR_MAX_CMDS == 1
mscp = &config.mscp[0];
@@ -1079,7 +1080,7 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return;
}
if (icm_status == 3) {
- void (*done)(Scsi_Cmnd *) = mscp->done;
+ void (*done)(struct scsi_cmnd *) = mscp->done;
if (done) {
mscp->done = NULL;
mscp->SCint->result = DID_ABORT << 16;
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index da759a11def..a692905f95f 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -14,11 +14,13 @@
#define _ULTRASTOR_H
static int ultrastor_detect(struct scsi_host_template *);
-static const char *ultrastor_info(struct Scsi_Host * shpnt);
-static int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-static int ultrastor_abort(Scsi_Cmnd *);
-static int ultrastor_host_reset(Scsi_Cmnd *);
-static int ultrastor_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
+static const char *ultrastor_info(struct Scsi_Host *shpnt);
+static int ultrastor_queuecommand(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
+static int ultrastor_abort(struct scsi_cmnd *);
+static int ultrastor_host_reset(struct scsi_cmnd *);
+static int ultrastor_biosparam(struct scsi_device *, struct block_device *,
+ sector_t, int *);
#define ULTRASTOR_14F_MAX_SG 16
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index 27307fe5a4c..2083454db51 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -71,7 +71,6 @@
* Richard Hirst <richard@sleepie.demon.co.uk> August 2000
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -374,7 +373,7 @@ wd33c93_queuecommand(struct scsi_cmnd *cmd,
*/
if (cmd->use_sg) {
- cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
cmd->SCp.buffers_residual = cmd->use_sg - 1;
cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
cmd->SCp.buffer->offset;
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
index 193ec517d25..edcb0365cf0 100644
--- a/drivers/scsi/wd33c93.h
+++ b/drivers/scsi/wd33c93.h
@@ -22,7 +22,6 @@
#ifndef WD33C93_H
#define WD33C93_H
-#include <linux/config.h>
#define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */
#ifdef PROC_INTERFACE
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index e55f0ee7e7e..a0b61af48f1 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1250,7 +1250,7 @@ static int wd7000_init(Adapter * host)
return 0;
- if (request_irq(host->irq, wd7000_intr, SA_INTERRUPT, "wd7000", host)) {
+ if (request_irq(host->irq, wd7000_intr, IRQF_DISABLED, "wd7000", host)) {
printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return (0);
}
@@ -1391,7 +1391,7 @@ static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start,
*
*/
-static int wd7000_detect(struct scsi_host_template *tpnt)
+static __init int wd7000_detect(struct scsi_host_template *tpnt)
{
short present = 0, biosaddr_ptr, sig_ptr, i, pass;
short biosptr[NUM_CONFIGS];
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index a6cfbb3b361..4b5f908d35c 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -136,7 +136,7 @@ zalon_probe(struct parisc_device *dev)
if (!host)
goto fail;
- if (request_irq(dev->irq, ncr53c8xx_intr, SA_SHIRQ, "zalon", host)) {
+ if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) {
printk(KERN_ERR "%s: irq problem with %d, detaching\n ",
dev->dev.bus_id, dev->irq);
goto fail;
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index 7572665a885..57438326b07 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -7,7 +7,6 @@
*
* $Id: 21285.c,v 1.37 2002/07/28 10:03:27 rmk Exp $
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
@@ -479,7 +478,6 @@ static struct uart_driver serial21285_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyFB",
.dev_name = "ttyFB",
- .devfs_name = "ttyFB",
.major = SERIAL_21285_MAJOR,
.minor = SERIAL_21285_MINOR,
.nr = 1,
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index b88a7c1158a..993a702422e 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -23,7 +23,6 @@
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
-#include <linux/config.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
@@ -131,17 +130,6 @@ static int m68328_console_baud = CONSOLE_BAUD_RATE;
static int m68328_console_cbaud = DEFAULT_CBAUD;
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the memcpy_fromfs blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */
-
static inline int serial_paranoia_check(struct m68k_serial *info,
char *name, const char *routine)
{
@@ -211,16 +199,16 @@ static void rs_stop(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_stop"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
uart->ustcnt &= ~USTCNT_TXEN;
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void rs_put_char(char ch)
{
int flags, loops = 0;
- save_flags(flags); cli();
+ local_irq_save(flags);
while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
loops++;
@@ -229,7 +217,7 @@ static void rs_put_char(char ch)
UTX_TXDATA = ch;
udelay(5);
- restore_flags(flags);
+ local_irq_restore(flags);
}
static void rs_start(struct tty_struct *tty)
@@ -241,7 +229,7 @@ static void rs_start(struct tty_struct *tty)
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
#ifdef USE_INTS
uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
@@ -249,7 +237,7 @@ static void rs_start(struct tty_struct *tty)
uart->ustcnt |= USTCNT_TXEN;
#endif
}
- restore_flags(flags);
+ local_irq_restore(flags);
}
/* Drop into either the boot monitor or kadb upon receiving a break
@@ -327,14 +315,6 @@ static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
if(!tty)
goto clear_and_exit;
- /*
- * Make sure that we do not overflow the buffer
- */
- if (tty_request_buffer_room(tty, 1) == 0) {
- tty_schedule_flip(tty);
- return;
- }
-
flag = TTY_NORMAL;
if(rx & URX_PARITY_ERROR) {
@@ -473,7 +453,7 @@ static int startup(struct m68k_serial * info)
return -ENOMEM;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
/*
* Clear the FIFO buffers and disable them
@@ -506,7 +486,7 @@ static int startup(struct m68k_serial * info)
change_speed(info);
info->flags |= S_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
@@ -523,7 +503,7 @@ static void shutdown(struct m68k_serial * info)
if (!(info->flags & S_INITIALIZED))
return;
- save_flags(flags); cli(); /* Disable interrupts */
+ local_irq_save(flags);
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
@@ -534,7 +514,7 @@ static void shutdown(struct m68k_serial * info)
set_bit(TTY_IO_ERROR, &info->tty->flags);
info->flags &= ~S_INITIALIZED;
- restore_flags(flags);
+ local_irq_restore(flags);
}
struct {
@@ -655,24 +635,24 @@ static void rs_fair_output(void)
if (info == 0) return;
if (info->xmit_buf == 0) return;
- save_flags(flags); cli();
+ local_irq_save(flags);
left = info->xmit_cnt;
while (left != 0) {
c = info->xmit_buf[info->xmit_tail];
info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt--;
- restore_flags(flags);
+ local_irq_restore(flags);
rs_put_char(c);
- save_flags(flags); cli();
+ local_irq_save(flags);
left = min(info->xmit_cnt, left-1);
}
/* Last character is being transmitted now (hopefully). */
udelay(5);
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -720,11 +700,11 @@ static void rs_flush_chars(struct tty_struct *tty)
#endif
/* Enable transmitter */
- save_flags(flags); cli();
+ local_irq_save(flags);
if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
!info->xmit_buf) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -749,7 +729,7 @@ static void rs_flush_chars(struct tty_struct *tty)
while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
}
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}
extern void console_printn(const char * b, int count);
@@ -768,18 +748,22 @@ static int rs_write(struct tty_struct * tty,
if (!tty || !info->xmit_buf)
return 0;
- save_flags(flags);
+ local_save_flags(flags);
while (1) {
- cli();
+ local_irq_disable();
c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
+ local_irq_restore(flags);
+
if (c <= 0)
break;
memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+ local_irq_disable();
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c;
- restore_flags(flags);
+ local_irq_restore(flags);
buf += c;
count -= c;
total += c;
@@ -787,7 +771,7 @@ static int rs_write(struct tty_struct * tty,
if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
/* Enable transmitter */
- cli();
+ local_irq_disable();
#ifndef USE_INTS
while(info->xmit_cnt) {
#endif
@@ -807,9 +791,9 @@ static int rs_write(struct tty_struct * tty,
#ifndef USE_INTS
}
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}
- restore_flags(flags);
+
return total;
}
@@ -838,12 +822,13 @@ static int rs_chars_in_buffer(struct tty_struct *tty)
static void rs_flush_buffer(struct tty_struct *tty)
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+ unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
- cli();
+ local_irq_save(flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- sti();
+ local_irq_restore(flags);
tty_wakeup(tty);
}
@@ -973,14 +958,15 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
m68328_uart *uart = &uart_addr[info->line];
#endif
unsigned char status;
+ unsigned long flags;
- cli();
+ local_irq_save(flags);
#ifdef CONFIG_SERIAL_68328_RTS_CTS
status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
#else
status = 0;
#endif
- sti();
+ local_irq_restore(flags);
put_user(status,value);
return 0;
}
@@ -994,14 +980,13 @@ static void send_break(struct m68k_serial * info, unsigned int duration)
unsigned long flags;
if (!info->port)
return;
- save_flags(flags);
- cli();
+ local_irq_save(flags);
#ifdef USE_INTS
uart->utx.w |= UTX_SEND_BREAK;
msleep_interruptible(duration);
uart->utx.w &= ~UTX_SEND_BREAK;
#endif
- restore_flags(flags);
+ local_irq_restore(flags);
}
static int rs_ioctl(struct tty_struct *tty, struct file * file,
@@ -1060,7 +1045,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */
if (access_ok(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
+ sizeof(unsigned int)))
return get_lsr_info(info, (unsigned int *) arg);
return -EFAULT;
case TIOCSERGSTRUCT:
@@ -1113,10 +1098,10 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
- save_flags(flags); cli();
+ local_irq_save(flags);
if (tty_hung_up_p(filp)) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
@@ -1138,7 +1123,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
info->count = 0;
}
if (info->count) {
- restore_flags(flags);
+ local_irq_restore(flags);
return;
}
info->flags |= S_CLOSING;
@@ -1186,7 +1171,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
}
info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING);
wake_up_interruptible(&info->close_wait);
- restore_flags(flags);
+ local_irq_restore(flags);
}
/*
@@ -1262,9 +1247,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
info->count--;
info->blocked_open++;
while (1) {
- cli();
+ local_irq_disable();
m68k_rtsdtr(info, 1);
- sti();
+ local_irq_enable();
current->state = TASK_INTERRUPTIBLE;
if (tty_hung_up_p(filp) ||
!(info->flags & S_INITIALIZED)) {
@@ -1444,7 +1429,7 @@ rs68328_init(void)
return -ENOMEM;
}
- save_flags(flags); cli();
+ local_irq_save(flags);
for(i=0;i<NR_PORTS;i++) {
@@ -1489,7 +1474,7 @@ rs68328_init(void)
serial_pm[i]->data = info;
#endif
}
- restore_flags(flags);
+ local_irq_restore(flags);
return 0;
}
diff --git a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
index 978f8a609f3..58aa2154655 100644
--- a/drivers/serial/68328serial.h
+++ b/drivers/serial/68328serial.h
@@ -11,7 +11,6 @@
#ifndef _MC683XX_SERIAL_H
#define _MC683XX_SERIAL_H
-#include <linux/config.h>
struct serial_struct {
int type;
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index 9843ae3d420..e80e70e9b12 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -20,7 +20,6 @@
* int rs_360_init(void);
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index bbf78aaf9e0..0ae9ced00ed 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -19,7 +19,6 @@
* mapbase is the physical address of the IO port.
* membase is an 'ioremapped' cookie.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -49,7 +48,7 @@
/*
* Configuration:
- * share_irqs - whether we pass SA_SHIRQ to request_irq(). This option
+ * share_irqs - whether we pass IRQF_SHARED to request_irq(). This option
* is unsafe when used on edge-triggered interrupts.
*/
static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
@@ -300,6 +299,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset)
static unsigned int serial_in(struct uart_8250_port *up, int offset)
{
+ unsigned int tmp;
offset = map_8250_in_reg(up, offset) << up->port.regshift;
switch (up->port.iotype) {
@@ -318,6 +318,13 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset)
return __raw_readl(up->port.membase + offset);
#endif
+ case UPIO_TSI:
+ if (offset == UART_IIR) {
+ tmp = readl((u32 *)(up->port.membase + UART_RX));
+ return (cpu_to_le32(tmp) >> 8) & 0xff;
+ } else
+ return readb(up->port.membase + offset);
+
default:
return inb(up->port.iobase + offset);
}
@@ -347,6 +354,10 @@ serial_out(struct uart_8250_port *up, int offset, int value)
__raw_writel(value, up->port.membase + offset);
break;
#endif
+ case UPIO_TSI:
+ if (!((offset == UART_IER) && (value & UART_IER_UUE)))
+ writeb(value, up->port.membase + offset);
+ break;
default:
outb(value, up->port.iobase + offset);
@@ -1401,7 +1412,7 @@ static void serial_do_unlink(struct irq_info *i, struct uart_8250_port *up)
static int serial_link_irq_chain(struct uart_8250_port *up)
{
struct irq_info *i = irq_lists + up->port.irq;
- int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
+ int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
spin_lock_irq(&i->lock);
@@ -2241,10 +2252,14 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
touch_nmi_watchdog();
- if (oops_in_progress) {
- locked = spin_trylock_irqsave(&up->port.lock, flags);
+ local_irq_save(flags);
+ if (up->port.sysrq) {
+ /* serial8250_handle_port() already took the lock */
+ locked = 0;
+ } else if (oops_in_progress) {
+ locked = spin_trylock(&up->port.lock);
} else
- spin_lock_irqsave(&up->port.lock, flags);
+ spin_lock(&up->port.lock);
/*
* First save the IER then disable the interrupts
@@ -2266,7 +2281,8 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
serial_out(up, UART_IER, ier);
if (locked)
- spin_unlock_irqrestore(&up->port.lock, flags);
+ spin_unlock(&up->port.lock);
+ local_irq_restore(flags);
}
static int serial8250_console_setup(struct console *co, char *options)
@@ -2354,7 +2370,6 @@ int __init serial8250_start_console(struct uart_port *port, char *options)
static struct uart_driver serial8250_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 490606b8709..91bd28f2bb4 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -15,7 +15,6 @@
* $Id: 8250.h,v 1.8 2002/07/21 21:32:30 rmk Exp $
*/
-#include <linux/config.h>
#include <linux/serial_8250.h>
struct old_serial_port {
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
index ac205256d5f..d10be944ad4 100644
--- a/drivers/serial/8250_mca.c
+++ b/drivers/serial/8250_mca.c
@@ -8,7 +8,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mca.h>
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 94886c000d2..851e4839d6d 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -134,7 +134,7 @@ afavlab_setup(struct serial_private *priv, struct pciserial_board *board,
* and Keystone have one Diva chip with 3 UARTs. Some later machines have
* one Diva chip, but it has been expanded to 5 UARTs.
*/
-static int __devinit pci_hp_diva_init(struct pci_dev *dev)
+static int pci_hp_diva_init(struct pci_dev *dev)
{
int rc = 0;
@@ -194,7 +194,7 @@ pci_hp_diva_setup(struct serial_private *priv, struct pciserial_board *board,
/*
* Added for EKF Intel i960 serial boards
*/
-static int __devinit pci_inteli960ni_init(struct pci_dev *dev)
+static int pci_inteli960ni_init(struct pci_dev *dev)
{
unsigned long oldval;
@@ -216,7 +216,7 @@ static int __devinit pci_inteli960ni_init(struct pci_dev *dev)
* seems to be mainly needed on card using the PLX which also use I/O
* mapped memory.
*/
-static int __devinit pci_plx9050_init(struct pci_dev *dev)
+static int pci_plx9050_init(struct pci_dev *dev)
{
u8 irq_config;
void __iomem *p;
@@ -314,7 +314,7 @@ sbs_setup(struct serial_private *priv, struct pciserial_board *board,
/* global control register offset for SBS PMC-OctalPro */
#define OCT_REG_CR_OFF 0x500
-static int __devinit sbs_init(struct pci_dev *dev)
+static int sbs_init(struct pci_dev *dev)
{
u8 __iomem *p;
@@ -458,11 +458,11 @@ static int pci_siig_setup(struct serial_private *priv,
* growing *huge*, we use this function to collapse some 70 entries
* in the PCI table into one, for sanity's and compactness's sake.
*/
-static unsigned short timedia_single_port[] = {
+static const unsigned short timedia_single_port[] = {
0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0
};
-static unsigned short timedia_dual_port[] = {
+static const unsigned short timedia_dual_port[] = {
0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085,
0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079,
0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079,
@@ -470,35 +470,34 @@ static unsigned short timedia_dual_port[] = {
0xD079, 0
};
-static unsigned short timedia_quad_port[] = {
+static const unsigned short timedia_quad_port[] = {
0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157,
0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159,
0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056,
0xB157, 0
};
-static unsigned short timedia_eight_port[] = {
+static const unsigned short timedia_eight_port[] = {
0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166,
0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0
};
static const struct timedia_struct {
int num;
- unsigned short *ids;
+ const unsigned short *ids;
} timedia_data[] = {
{ 1, timedia_single_port },
{ 2, timedia_dual_port },
{ 4, timedia_quad_port },
- { 8, timedia_eight_port },
- { 0, NULL }
+ { 8, timedia_eight_port }
};
-static int __devinit pci_timedia_init(struct pci_dev *dev)
+static int pci_timedia_init(struct pci_dev *dev)
{
- unsigned short *ids;
+ const unsigned short *ids;
int i, j;
- for (i = 0; timedia_data[i].num; i++) {
+ for (i = 0; i < ARRAY_SIZE(timedia_data); i++) {
ids = timedia_data[i].ids;
for (j = 0; ids[j]; j++)
if (dev->subsystem_device == ids[j])
@@ -566,13 +565,13 @@ titan_400l_800l_setup(struct serial_private *priv,
return setup_port(priv, port, bar, offset, board->reg_shift);
}
-static int __devinit pci_xircom_init(struct pci_dev *dev)
+static int pci_xircom_init(struct pci_dev *dev)
{
msleep(100);
return 0;
}
-static int __devinit pci_netmos_init(struct pci_dev *dev)
+static int pci_netmos_init(struct pci_dev *dev)
{
/* subdevice 0x00PS means <P> parallel, <S> serial */
unsigned int num_serial = dev->subsystem_device & 0xf;
@@ -594,8 +593,8 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
else
offset += idx * board->uart_offset;
- maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) /
- (8 << board->reg_shift);
+ maxnr = (pci_resource_len(priv->dev, bar) - board->first_offset) >>
+ (board->reg_shift + 3);
if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr)
return 1;
@@ -622,7 +621,7 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board,
*/
static struct pci_serial_quirk pci_serial_quirks[] = {
/*
- * AFAVLAB cards.
+ * AFAVLAB cards - these may be called via parport_serial
* It is not clear whether this applies to all products.
*/
{
@@ -754,7 +753,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.exit = __devexit_p(sbs_exit),
},
/*
- * SIIG cards.
+ * SIIG cards - these may be called via parport_serial
*/
{
.vendor = PCI_VENDOR_ID_SIIG,
@@ -811,7 +810,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.setup = pci_default_setup,
},
/*
- * Netmos cards
+ * Netmos cards - these may be called via parport_serial
*/
{
.vendor = PCI_VENDOR_ID_NETMOS,
@@ -936,6 +935,7 @@ enum pci_board_num_t {
pbn_b1_8_1382400,
pbn_b2_1_115200,
+ pbn_b2_2_115200,
pbn_b2_8_115200,
pbn_b2_1_460800,
@@ -1243,6 +1243,12 @@ static struct pciserial_board pci_boards[] __devinitdata = {
.base_baud = 115200,
.uart_offset = 8,
},
+ [pbn_b2_2_115200] = {
+ .flags = FL_BASE2,
+ .num_ports = 2,
+ .base_baud = 115200,
+ .uart_offset = 8,
+ },
[pbn_b2_8_115200] = {
.flags = FL_BASE2,
.num_ports = 8,
@@ -2340,6 +2346,13 @@ static struct pci_device_id serial_pci_tbl[] = {
pbn_b0_1_115200 },
/*
+ * IntaShield IS-200
+ */
+ { PCI_VENDOR_ID_INTASHIELD, PCI_DEVICE_ID_INTASHIELD_IS200,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, /* 135a.0811 */
+ pbn_b2_2_115200 },
+
+ /*
* These entries match devices with class COMMUNICATION_SERIAL,
* COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
*/
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index b79ed0665d5..632f62d6ec7 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -323,8 +323,10 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "USR9180", 0 },
/* U.S. Robotics 56K Voice INT PnP*/
{ "USR9190", 0 },
- /* HP Compaq Tablet PC tc1100 Wacom tablet */
+ /* Wacom tablets */
+ { "WACF004", 0 },
{ "WACF005", 0 },
+ { "WACF006", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
/* Unkown PnP modems */
@@ -429,6 +431,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
#endif
port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+ if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
+ port.flags |= UPF_SHARE_IRQ;
port.uartclk = 1843200;
port.dev = &dev->dev;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index bef4a9622ed..d926272a40d 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -295,7 +295,7 @@ config SERIAL_AMBA_PL011_CONSOLE
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
- "console=ttyAM0". (Try "man bootparam" or see the documentation of
+ "console=ttyAMA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
@@ -354,21 +354,24 @@ config SERIAL_CLPS711X_CONSOLE
kernel at boot time.)
config SERIAL_S3C2410
- tristate "Samsung S3C2410 Serial port support"
+ tristate "Samsung S3C2410/S3C2440/S3C2442/S3C2412 Serial port support"
depends on ARM && ARCH_S3C2410
select SERIAL_CORE
help
- Support for the on-chip UARTs on the Samsung S3C2410X CPU,
+ Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
provide all of these ports, depending on how the serial port
pins are configured.
+ Currently this driver supports the UARTS on the S3C2410, S3C2440,
+ S3C2442, S3C2412 and S3C2413 CPUs.
+
config SERIAL_S3C2410_CONSOLE
bool "Support for console on S3C2410 serial port"
depends on SERIAL_S3C2410=y
select SERIAL_CORE_CONSOLE
help
- Allow selection of the S3C2410 on-board serial ports for use as
+ Allow selection of the S3C24XX on-board serial ports for use as
an virtual console.
Even if you say Y here, the currently visible virtual console
@@ -639,12 +642,17 @@ config V850E_UART_CONSOLE
select SERIAL_CORE_CONSOLE
config SERIAL_SH_SCI
- tristate "SH SCI(F) serial port support"
+ tristate "SuperH SCI(F) serial port support"
depends on SUPERH || H8300
select SERIAL_CORE
+config SERIAL_SH_SCI_NR_UARTS
+ int "Maximum number of SCI(F) serial ports"
+ depends on SERIAL_SH_SCI
+ default "2"
+
config SERIAL_SH_SCI_CONSOLE
- bool "Support for console on SH SCI(F)"
+ bool "Support for console on SuperH SCI(F)"
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index e920d196d0b..7311d8487c9 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -31,7 +31,6 @@
* required, these have to be supplied via some other means (eg, GPIO)
* and hooked into this driver.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_AMBA_PL010_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index 3d966cfc9a3..a8d7124e84a 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -31,7 +31,6 @@
* required, these have to be supplied via some other means (eg, GPIO)
* and hooked into this driver.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c
index db5b25fafed..bf4bf103e5a 100644
--- a/drivers/serial/at91_serial.c
+++ b/drivers/serial/at91_serial.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
@@ -42,6 +41,7 @@
#include <asm/mach/serial_at91.h>
#include <asm/arch/board.h>
#include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -139,11 +139,11 @@ static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
* AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
* We need to drive the pin manually.
*/
- if (port->mapbase == AT91_BASE_US0) {
+ if (port->mapbase == AT91RM9200_BASE_US0) {
if (mctrl & TIOCM_RTS)
- at91_sys_write(AT91_PIOA + PIO_CODR, AT91_PA21_RTS0);
+ at91_set_gpio_value(AT91_PIN_PA21, 0);
else
- at91_sys_write(AT91_PIOA + PIO_SODR, AT91_PA21_RTS0);
+ at91_set_gpio_value(AT91_PIN_PA21, 1);
}
}
@@ -388,7 +388,7 @@ static int at91_startup(struct uart_port *port)
/*
* Allocate the IRQ
*/
- retval = request_irq(port->irq, at91_interrupt, SA_SHIRQ, "at91_serial", port);
+ retval = request_irq(port->irq, at91_interrupt, IRQF_SHARED, "at91_serial", port);
if (retval) {
printk("at91_serial: at91_startup - Can't get irq\n");
return retval;
@@ -863,7 +863,6 @@ static struct uart_driver at91_uart = {
.owner = THIS_MODULE,
.driver_name = "at91_serial",
.dev_name = AT91_DEVICENAME,
- .devfs_name = AT91_DEVICENAME,
.major = SERIAL_AT91_MAJOR,
.minor = MINOR_START,
.nr = AT91_NR_UART,
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
index 2691112c84a..f27d852ce50 100644
--- a/drivers/serial/clps711x.c
+++ b/drivers/serial/clps711x.c
@@ -25,7 +25,6 @@
* $Id: clps711x.c,v 1.42 2002/07/28 10:03:28 rmk Exp $
*
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 5cba59ad7dc..90ff96e3339 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -31,7 +31,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 17406a05ce1..95afc37297a 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index cdba128250a..ef3bb476c43 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 89700141f87..cabd048c863 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -415,7 +415,7 @@
* Fixed DEF_TX value that caused the serial transmitter pin (txd) to go to 0 when
* closing the last filehandle, NASTY!.
* Added break generation, not tested though!
- * Use SA_SHIRQ when request_irq() for ser2 and ser3 (shared with) par0 and par1.
+ * Use IRQF_SHARED when request_irq() for ser2 and ser3 (shared with) par0 and par1.
* You can't use them at the same time (yet..), but you can hopefully switch
* between ser2/par0, ser3/par1 with the same kernel config.
* Replaced some magic constants with defines
@@ -425,7 +425,6 @@
static char *serial_version = "$Revision: 1.25 $";
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -2573,12 +2572,6 @@ static void flush_to_flip_buffer(struct e100_serial *info)
DFLIP(
if (1) {
-
- if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
- DEBUG_LOG(info->line, "*** TTY_DONT_FLIP set flip.count %i ***\n", tty->flip.count);
- DEBUG_LOG(info->line, "*** recv_cnt %i\n", info->recv_cnt);
- } else {
- }
DEBUG_LOG(info->line, "*** rxtot %i\n", info->icount.rx);
DEBUG_LOG(info->line, "ldisc %lu\n", tty->ldisc.chars_in_buffer(tty));
DEBUG_LOG(info->line, "room %lu\n", tty->ldisc.receive_room(tty));
@@ -4884,7 +4877,7 @@ rs_init(void)
driver->init_termios = tty_std_termios;
driver->init_termios.c_cflag =
B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
- driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
driver->termios = serial_termios;
driver->termios_locked = serial_termios_locked;
@@ -4949,55 +4942,55 @@ rs_init(void)
/* Not needed in simulator. May only complicate stuff. */
/* hook the irq's for DMA channel 6 and 7, serial output and input, and some more... */
- if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial ", NULL))
+ if (request_irq(SERIAL_IRQ_NBR, ser_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial ", NULL))
panic("irq8");
#ifdef CONFIG_ETRAX_SERIAL_PORT0
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA6_OUT
- if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 0 dma tr", NULL))
+ if (request_irq(SER0_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_DISABLED, "serial 0 dma tr", NULL))
panic("irq22");
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT0_DMA7_IN
- if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 0 dma rec", NULL))
+ if (request_irq(SER0_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_DISABLED, "serial 0 dma rec", NULL))
panic("irq23");
#endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA8_OUT
- if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, SA_INTERRUPT, "serial 1 dma tr", NULL))
+ if (request_irq(SER1_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_DISABLED, "serial 1 dma tr", NULL))
panic("irq24");
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT1_DMA9_IN
- if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, SA_INTERRUPT, "serial 1 dma rec", NULL))
+ if (request_irq(SER1_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_DISABLED, "serial 1 dma rec", NULL))
panic("irq25");
#endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2
/* DMA Shared with par0 (and SCSI0 and ATA) */
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA2_OUT
- if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma tr", NULL))
+ if (request_irq(SER2_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 2 dma tr", NULL))
panic("irq18");
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2_DMA3_IN
- if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 2 dma rec", NULL))
+ if (request_irq(SER2_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 2 dma rec", NULL))
panic("irq19");
#endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3
/* DMA Shared with par1 (and SCSI1 and Extern DMA 0) */
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA4_OUT
- if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma tr", NULL))
+ if (request_irq(SER3_DMA_TX_IRQ_NBR, tr_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 3 dma tr", NULL))
panic("irq20");
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT3_DMA5_IN
- if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, SA_SHIRQ | SA_INTERRUPT, "serial 3 dma rec", NULL))
+ if (request_irq(SER3_DMA_RX_IRQ_NBR, rec_interrupt, IRQF_SHARED | IRQF_DISABLED, "serial 3 dma rec", NULL))
panic("irq21");
#endif
#endif
#ifdef CONFIG_ETRAX_SERIAL_FLUSH_DMA_FAST
- if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, SA_SHIRQ | SA_INTERRUPT,
+ if (request_irq(TIMER1_IRQ_NBR, timeout_interrupt, IRQF_SHARED | IRQF_DISABLED,
"fast serial dma timeout", NULL)) {
printk(KERN_CRIT "err: timer1 irq\n");
}
diff --git a/drivers/serial/crisv10.h b/drivers/serial/crisv10.h
index 1800c0e7531..f30b93d6ef7 100644
--- a/drivers/serial/crisv10.h
+++ b/drivers/serial/crisv10.h
@@ -7,7 +7,6 @@
#ifndef _ETRAX_SERIAL_H
#define _ETRAX_SERIAL_H
-#include <linux/config.h>
#include <linux/circ_buf.h>
#include <asm/termios.h>
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index bf71bad5c34..8a98aae80e2 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -26,7 +26,6 @@
#undef DEBUG_DZ
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/init.h>
@@ -674,7 +673,7 @@ static void dz_reset(struct dz_port *dport)
}
#ifdef CONFIG_SERIAL_DZ_CONSOLE
-static void dz_console_putchar(struct uart_port *port, int ch)
+static void dz_console_putchar(struct uart_port *uport, int ch)
{
struct dz_port *dport = (struct dz_port *)uport;
unsigned long flags;
@@ -768,11 +767,7 @@ void __init dz_serial_console_init(void)
static struct uart_driver dz_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
-#ifdef CONFIG_DEVFS
- .dev_name = "tts/%d",
-#else
.dev_name = "ttyS%d",
-#endif
.major = TTY_MAJOR,
.minor = 64,
.nr = DZ_NB_PORT,
@@ -802,7 +797,7 @@ int __init dz_init(void)
restore_flags(flags);
if (request_irq(dz_ports[0].port.irq, dz_interrupt,
- SA_INTERRUPT, "DZ", &dz_ports[0]))
+ IRQF_DISABLED, "DZ", &dz_ports[0]))
panic("Unable to register DZ interrupt");
ret = uart_register_driver(&dz_reg);
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index 144a7a352b2..a3c00a25214 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -24,7 +24,6 @@
*/
#define SERIAL_DO_RESTART
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -1564,7 +1563,7 @@ static int __devinit icom_probe(struct pci_dev *dev,
/* save off irq and request irq line */
if ( (retval = request_irq(dev->irq, icom_interrupt,
- SA_INTERRUPT | SA_SHIRQ, ICOM_DRIVER_NAME,
+ IRQF_DISABLED | IRQF_SHARED, ICOM_DRIVER_NAME,
(void *) icom_adapter))) {
goto probe_exit2;
}
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index d202eb4f384..4a142d6b8f3 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -25,7 +25,6 @@
* [29-Mar-2005] Mike Lee
* Added hardware handshake
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -405,7 +404,7 @@ static int imx_startup(struct uart_port *port)
if (retval) goto error_out2;
retval = request_irq(sport->rtsirq, imx_rtsint,
- SA_TRIGGER_FALLING | SA_TRIGGER_RISING,
+ IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
DRIVER_NAME, sport);
if (retval) goto error_out3;
@@ -888,7 +887,6 @@ static struct uart_driver imx_reg = {
.owner = THIS_MODULE,
.driver_name = DRIVER_NAME,
.dev_name = "ttySMX",
- .devfs_name = "ttsmx/",
.major = SERIAL_IMX_MAJOR,
.minor = MINOR_START,
.nr = ARRAY_SIZE(imx_ports),
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 717e47bbd78..576ca1eaa2b 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -2855,7 +2855,7 @@ ioc4_serial_attach_one(struct ioc4_driver_data *idd)
control->ic_soft = soft;
/* Hook up interrupt handler */
- if (!request_irq(idd->idd_pdev->irq, ioc4_intr, SA_SHIRQ,
+ if (!request_irq(idd->idd_pdev->irq, ioc4_intr, IRQF_SHARED,
"sgi-ioc4serial", soft)) {
control->ic_irq = idd->idd_pdev->irq;
} else {
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index 651772474ac..5ff269fb604 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -12,7 +12,6 @@
* Copyright (C) 2002 Ralf Baechle (ralf@linux-mips.org)
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -1085,7 +1084,6 @@ static struct console ip22zilog_console = {
static struct uart_driver ip22zilog_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
@@ -1145,9 +1143,8 @@ static void __init ip22zilog_prepare(void)
up[(chip * 2) + 1].port.fifosize = 1;
up[(chip * 2) + 1].port.ops = &ip22zilog_pops;
up[(chip * 2) + 1].port.type = PORT_IP22ZILOG;
- up[(chip * 2) + 1].port.flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
up[(chip * 2) + 1].port.line = (chip * 2) + 1;
- up[(chip * 2) + 1].flags = 0;
+ up[(chip * 2) + 1].flags |= IP22ZILOG_FLAG_IS_CHANNEL_A;
}
}
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index b3e1f71be4d..244f63be3a0 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -121,7 +121,7 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
}
rc = request_irq(brd->irq, brd->bd_ops->intr,
- SA_INTERRUPT|SA_SHIRQ, "JSM", brd);
+ IRQF_DISABLED|IRQF_SHARED, "JSM", brd);
if (rc) {
printk(KERN_WARNING "Failed to hook IRQ %d\n",brd->irq);
goto out_iounmap;
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 7d823705193..f8262e6ad8d 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -589,13 +589,6 @@ void jsm_input(struct jsm_channel *ch)
ld = tty_ldisc_ref(tp);
/*
- * If the DONT_FLIP flag is on, don't flush our buffer, and act
- * like the ld doesn't have any space to put the data right now.
- */
- if (test_bit(TTY_DONT_FLIP, &tp->flags))
- len = 0;
-
- /*
* If we were unable to get a reference to the ld,
* don't flush our buffer, and act like the ld doesn't
* have any space to put the data right now.
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 321a40f33b5..e7fe4bb46ec 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -25,7 +25,6 @@
* membase is an 'ioremapped' cookie. This is compatible with the old
* serial.c driver, and is currently the preferred form.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_M32R_SIO_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -543,7 +542,7 @@ static void serial_do_unlink(struct irq_info *i, struct uart_sio_port *up)
static int serial_link_irq_chain(struct uart_sio_port *up)
{
struct irq_info *i = irq_lists + up->port.irq;
- int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? SA_SHIRQ : 0;
+ int ret, irq_flags = up->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0;
spin_lock_irq(&i->lock);
@@ -1131,7 +1130,6 @@ console_initcall(m32r_sio_console_init);
static struct uart_driver m32r_sio_reg = {
.owner = THIS_MODULE,
.driver_name = "sio",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
diff --git a/drivers/serial/m32r_sio.h b/drivers/serial/m32r_sio.h
index 7c3ec24f7e5..849f1b2c253 100644
--- a/drivers/serial/m32r_sio.h
+++ b/drivers/serial/m32r_sio.h
@@ -15,7 +15,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
struct m32r_sio_probe {
struct module *owner;
diff --git a/drivers/serial/m32r_sio_reg.h b/drivers/serial/m32r_sio_reg.h
index 9c864529451..4671473793e 100644
--- a/drivers/serial/m32r_sio_reg.h
+++ b/drivers/serial/m32r_sio_reg.h
@@ -15,7 +15,6 @@
#ifndef _M32R_SIO_REG_H
#define _M32R_SIO_REG_H
-#include <linux/config.h>
#ifdef CONFIG_SERIAL_M32R_PLDSIO
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 8cbbb954df2..832abd3c470 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -60,11 +60,11 @@ struct timer_list mcfrs_timer_struct;
#if defined(CONFIG_HW_FEITH)
#define CONSOLE_BAUD_RATE 38400
#define DEFAULT_CBAUD B38400
-#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB)
+#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || defined(CONFIG_M5329EVB)
#define CONSOLE_BAUD_RATE 115200
#define DEFAULT_CBAUD B115200
#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
- defined(CONFIG_senTec) || defined(CONFIG_SNEHA)
+ defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
#define CONSOLE_BAUD_RATE 19200
#define DEFAULT_CBAUD B19200
#endif
@@ -93,7 +93,7 @@ static struct tty_driver *mcfrs_serial_driver;
#undef SERIAL_DEBUG_FLOW
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
- defined(CONFIG_M520x)
+ defined(CONFIG_M520x) || defined(CONFIG_M532x)
#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
#else
#define IRQBASE 73
@@ -1545,6 +1545,28 @@ static void mcfrs_irqinit(struct mcf_serial *info)
*feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
| MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
}
+#elif defined(CONFIG_M532x)
+ volatile unsigned char *uartp;
+ uartp = info->addr;
+ switch (info->line) {
+ case 0:
+ MCF_INTC0_ICR26 = 0x3;
+ MCF_INTC0_CIMR = 26;
+ /* GPIO initialization */
+ MCF_GPIO_PAR_UART |= 0x000F;
+ break;
+ case 1:
+ MCF_INTC0_ICR27 = 0x3;
+ MCF_INTC0_CIMR = 27;
+ /* GPIO initialization */
+ MCF_GPIO_PAR_UART |= 0x0FF0;
+ break;
+ case 2:
+ MCF_INTC0_ICR28 = 0x3;
+ MCF_INTC0_CIMR = 28;
+ /* GPIOs also must be initalized, depends on board */
+ break;
+ }
#else
volatile unsigned char *icrp, *uartp;
@@ -1574,7 +1596,7 @@ static void mcfrs_irqinit(struct mcf_serial *info)
/* Clear mask, so no surprise interrupts. */
uartp[MCFUART_UIMR] = 0;
- if (request_irq(info->irq, mcfrs_interrupt, SA_INTERRUPT,
+ if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
"ColdFire UART", NULL)) {
printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
"vector=%d\n", info->line, info->irq);
@@ -1691,7 +1713,6 @@ mcfrs_init(void)
/* Initialize the tty_driver structure */
mcfrs_serial_driver->owner = THIS_MODULE;
mcfrs_serial_driver->name = "ttyS";
- mcfrs_serial_driver->devfs_name = "ttys/";
mcfrs_serial_driver->driver_name = "serial";
mcfrs_serial_driver->major = TTY_MAJOR;
mcfrs_serial_driver->minor_start = 64;
diff --git a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
index a2b28e8629f..56420e2cb11 100644
--- a/drivers/serial/mcfserial.h
+++ b/drivers/serial/mcfserial.h
@@ -14,7 +14,6 @@
#ifndef _MCF_SERIAL_H
#define _MCF_SERIAL_H
-#include <linux/config.h>
#include <linux/serial.h>
#ifdef __KERNEL__
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 6459edc7f5c..7708e5dd365 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -44,7 +44,6 @@
* will be mapped to.
*/
-#include <linux/config.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/tty.h>
@@ -191,7 +190,7 @@ mpc52xx_uart_startup(struct uart_port *port)
/* Request IRQ */
ret = request_irq(port->irq, mpc52xx_uart_int,
- SA_INTERRUPT | SA_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
if (ret)
return ret;
@@ -693,7 +692,6 @@ static struct uart_driver mpc52xx_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "mpc52xx_psc_uart",
.dev_name = "ttyPSC",
- .devfs_name = "ttyPSC",
.major = SERIAL_PSC_MAJOR,
.minor = SERIAL_PSC_MINOR,
.nr = MPC52xx_PSC_MAXNUM,
@@ -728,8 +726,7 @@ mpc52xx_uart_probe(struct platform_device *dev)
spin_lock_init(&port->lock);
port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
- port->fifosize = 255; /* Should be 512 ! But it can't be */
- /* stored in a unsigned char */
+ port->fifosize = 512;
port->iotype = UPIO_MEM;
port->flags = UPF_BOOT_AUTOCONF |
( uart_console(port) ? 0 : UPF_IOREMAP );
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 94681922ea0..63d2a66e563 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -50,7 +50,6 @@
* 4) AFAICT, hardware flow control isn't supported by the controller --MAG.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_MPSC_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -315,7 +314,6 @@ struct mpsc_port_info *mpsc_device_remove(int index);
#define MPSC_MAJOR 204
#define MPSC_MINOR_START 44
#define MPSC_DRIVER_NAME "MPSC"
-#define MPSC_DEVFS_NAME "ttymm/"
#define MPSC_DEV_NAME "ttyMM"
#define MPSC_VERSION "1.00"
@@ -1414,7 +1412,7 @@ mpsc_startup(struct uart_port *port)
/* If irq's are shared, need to set flag */
if (mpsc_ports[0].port.irq == mpsc_ports[1].port.irq)
- flag = SA_SHIRQ;
+ flag = IRQF_SHARED;
if (request_irq(pi->port.irq, mpsc_sdma_intr, flag,
"mpsc-sdma", pi))
@@ -1863,7 +1861,6 @@ static struct platform_driver mpsc_shared_driver = {
static struct uart_driver mpsc_reg = {
.owner = THIS_MODULE,
.driver_name = MPSC_DRIVER_NAME,
- .devfs_name = MPSC_DEVFS_NAME,
.dev_name = MPSC_DEV_NAME,
.major = MPSC_MAJOR,
.minor = MPSC_MINOR_START,
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index 64c0e89124c..4a1c9983f38 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -16,7 +16,6 @@
**
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/ioport.h>
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 513ff859770..a3b99caf80e 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -42,7 +42,6 @@
#undef DEBUG_HARD
#undef USE_CTRL_O_SYSRQ
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/tty.h>
@@ -101,7 +100,6 @@ static DEFINE_MUTEX(pmz_irq_mutex);
static struct uart_driver pmz_uart_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyS",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
@@ -936,7 +934,7 @@ static int pmz_startup(struct uart_port *port)
}
pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
- if (request_irq(uap->port.irq, pmz_interrupt, SA_SHIRQ, "PowerMac Zilog", uap)) {
+ if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
dev_err(&uap->dev->ofdev.dev,
"Unable to register zs interrupt handler.\n");
pmz_set_scc_power(uap, 0);
@@ -1402,8 +1400,8 @@ static struct uart_ops pmz_pops = {
static int __init pmz_init_port(struct uart_pmac_port *uap)
{
struct device_node *np = uap->node;
- char *conn;
- struct slot_names_prop {
+ const char *conn;
+ const struct slot_names_prop {
int count;
char name[1];
} *slots;
@@ -1445,8 +1443,8 @@ static int __init pmz_init_port(struct uart_pmac_port *uap)
uap->flags &= ~PMACZILOG_FLAG_HAS_DMA;
goto no_dma;
}
- uap->tx_dma_irq = np->intrs[1].line;
- uap->rx_dma_irq = np->intrs[2].line;
+ uap->tx_dma_irq = irq_of_parse_and_map(np, 1);
+ uap->rx_dma_irq = irq_of_parse_and_map(np, 2);
}
no_dma:
@@ -1460,7 +1458,7 @@ no_dma:
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
uap->port_type = PMAC_SCC_ASYNC;
/* 1999 Powerbook G3 has slot-names property instead */
- slots = (struct slot_names_prop *)get_property(np, "slot-names", &len);
+ slots = get_property(np, "slot-names", &len);
if (slots && slots->count > 0) {
if (strcmp(slots->name, "IrDA") == 0)
uap->flags |= PMACZILOG_FLAG_IS_IRDA;
@@ -1472,7 +1470,8 @@ no_dma:
if (ZS_IS_INTMODEM(uap)) {
struct device_node* i2c_modem = find_devices("i2c-modem");
if (i2c_modem) {
- char* mid = get_property(i2c_modem, "modem-id", NULL);
+ const char* mid =
+ get_property(i2c_modem, "modem-id", NULL);
if (mid) switch(*mid) {
case 0x04 :
case 0x05 :
@@ -1493,7 +1492,7 @@ no_dma:
* Init remaining bits of "port" structure
*/
uap->port.iotype = UPIO_MEM;
- uap->port.irq = np->intrs[0].line;
+ uap->port.irq = irq_of_parse_and_map(np, 0);
uap->port.uartclk = ZS_CLOCK;
uap->port.fifosize = 1;
uap->port.ops = &pmz_pops;
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index ae364956854..a720953a404 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -24,7 +24,6 @@
* with the serial core maintainer satisfaction to appear soon.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_PXA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -390,7 +389,7 @@ static int serial_pxa_startup(struct uart_port *port)
/*
* Finally, enable interrupts. Note: Modem status interrupts
- * are set via set_termios(), which will be occuring imminently
+ * are set via set_termios(), which will be occurring imminently
* anyway, so we don't enable them here.
*/
up->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE;
@@ -780,7 +779,6 @@ static struct uart_pxa_port serial_pxa_ports[] = {
static struct uart_driver serial_pxa_reg = {
.owner = THIS_MODULE,
.driver_name = "PXA serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = 64,
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 53c2465bad2..95738a19cde 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -55,7 +55,6 @@
* BJD, 04-Nov-2004
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_S3C2410_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -149,7 +148,6 @@ s3c24xx_serial_dbg(const char *fmt, ...)
/* UART name and device definitions */
#define S3C24XX_SERIAL_NAME "ttySAC"
-#define S3C24XX_SERIAL_DEVFS "tts/"
#define S3C24XX_SERIAL_MAJOR 204
#define S3C24XX_SERIAL_MINOR 64
@@ -872,6 +870,8 @@ static const char *s3c24xx_serial_type(struct uart_port *port)
return "S3C2410";
case PORT_S3C2440:
return "S3C2440";
+ case PORT_S3C2412:
+ return "S3C2412";
default:
return NULL;
}
@@ -950,7 +950,6 @@ static struct uart_driver s3c24xx_uart_drv = {
.nr = 3,
.cons = S3C24XX_SERIAL_CONSOLE,
.driver_name = S3C24XX_SERIAL_NAME,
- .devfs_name = S3C24XX_SERIAL_DEVFS,
.major = S3C24XX_SERIAL_MAJOR,
.minor = S3C24XX_SERIAL_MINOR,
};
@@ -1528,6 +1527,141 @@ static inline void s3c2440_serial_exit(void)
#define s3c2440_uart_inf_at NULL
#endif /* CONFIG_CPU_S3C2440 */
+#if defined(CONFIG_CPU_S3C2412) || defined(CONFIG_CPU_S3C2413)
+
+static int s3c2412_serial_setsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ ucon &= ~S3C2412_UCON_CLKMASK;
+
+ if (strcmp(clk->name, "uclk") == 0)
+ ucon |= S3C2440_UCON_UCLK;
+ else if (strcmp(clk->name, "pclk") == 0)
+ ucon |= S3C2440_UCON_PCLK;
+ else if (strcmp(clk->name, "usysclk") == 0)
+ ucon |= S3C2412_UCON_USYSCLK;
+ else {
+ printk(KERN_ERR "unknown clock source %s\n", clk->name);
+ return -EINVAL;
+ }
+
+ wr_regl(port, S3C2410_UCON, ucon);
+ return 0;
+}
+
+
+static int s3c2412_serial_getsource(struct uart_port *port,
+ struct s3c24xx_uart_clksrc *clk)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ switch (ucon & S3C2412_UCON_CLKMASK) {
+ case S3C2412_UCON_UCLK:
+ clk->divisor = 1;
+ clk->name = "uclk";
+ break;
+
+ case S3C2412_UCON_PCLK:
+ case S3C2412_UCON_PCLK2:
+ clk->divisor = 1;
+ clk->name = "pclk";
+ break;
+
+ case S3C2412_UCON_USYSCLK:
+ clk->divisor = 1;
+ clk->name = "usysclk";
+ break;
+ }
+
+ return 0;
+}
+
+static int s3c2412_serial_resetport(struct uart_port *port,
+ struct s3c2410_uartcfg *cfg)
+{
+ unsigned long ucon = rd_regl(port, S3C2410_UCON);
+
+ dbg("%s: port=%p (%08lx), cfg=%p\n",
+ __FUNCTION__, port, port->mapbase, cfg);
+
+ /* ensure we don't change the clock settings... */
+
+ ucon &= S3C2412_UCON_CLKMASK;
+
+ wr_regl(port, S3C2410_UCON, ucon | cfg->ucon);
+ wr_regl(port, S3C2410_ULCON, cfg->ulcon);
+
+ /* reset both fifos */
+
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
+ wr_regl(port, S3C2410_UFCON, cfg->ufcon);
+
+ return 0;
+}
+
+static struct s3c24xx_uart_info s3c2412_uart_inf = {
+ .name = "Samsung S3C2412 UART",
+ .type = PORT_S3C2412,
+ .fifosize = 64,
+ .rx_fifomask = S3C2440_UFSTAT_RXMASK,
+ .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
+ .rx_fifofull = S3C2440_UFSTAT_RXFULL,
+ .tx_fifofull = S3C2440_UFSTAT_TXFULL,
+ .tx_fifomask = S3C2440_UFSTAT_TXMASK,
+ .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
+ .get_clksrc = s3c2412_serial_getsource,
+ .set_clksrc = s3c2412_serial_setsource,
+ .reset_port = s3c2412_serial_resetport,
+};
+
+/* device management */
+
+static int s3c2412_serial_probe(struct platform_device *dev)
+{
+ dbg("s3c2440_serial_probe: dev=%p\n", dev);
+ return s3c24xx_serial_probe(dev, &s3c2412_uart_inf);
+}
+
+static struct platform_driver s3c2412_serial_drv = {
+ .probe = s3c2412_serial_probe,
+ .remove = s3c24xx_serial_remove,
+ .suspend = s3c24xx_serial_suspend,
+ .resume = s3c24xx_serial_resume,
+ .driver = {
+ .name = "s3c2412-uart",
+ .owner = THIS_MODULE,
+ },
+};
+
+
+static inline int s3c2412_serial_init(void)
+{
+ return s3c24xx_serial_init(&s3c2412_serial_drv, &s3c2412_uart_inf);
+}
+
+static inline void s3c2412_serial_exit(void)
+{
+ platform_driver_unregister(&s3c2412_serial_drv);
+}
+
+#define s3c2412_uart_inf_at &s3c2412_uart_inf
+#else
+
+static inline int s3c2412_serial_init(void)
+{
+ return 0;
+}
+
+static inline void s3c2412_serial_exit(void)
+{
+}
+
+#define s3c2412_uart_inf_at NULL
+#endif /* CONFIG_CPU_S3C2440 */
+
+
/* module initialisation code */
static int __init s3c24xx_serial_modinit(void)
@@ -1542,6 +1676,7 @@ static int __init s3c24xx_serial_modinit(void)
s3c2400_serial_init();
s3c2410_serial_init();
+ s3c2412_serial_init();
s3c2440_serial_init();
return 0;
@@ -1551,6 +1686,7 @@ static void __exit s3c24xx_serial_modexit(void)
{
s3c2400_serial_exit();
s3c2410_serial_exit();
+ s3c2412_serial_exit();
s3c2440_serial_exit();
uart_unregister_driver(&s3c24xx_uart_drv);
@@ -1773,6 +1909,8 @@ static int s3c24xx_serial_initconsole(void)
info = s3c2410_uart_inf_at;
} else if (strcmp(dev->name, "s3c2440-uart") == 0) {
info = s3c2440_uart_inf_at;
+ } else if (strcmp(dev->name, "s3c2412-uart") == 0) {
+ info = s3c2412_uart_inf_at;
} else {
printk(KERN_ERR "s3c24xx: no driver for %s\n", dev->name);
return 0;
@@ -1796,4 +1934,4 @@ console_initcall(s3c24xx_serial_initconsole);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("Samsung S3C2410/S3C2440 Serial port driver");
+MODULE_DESCRIPTION("Samsung S3C2410/S3C2440/S3C2412 Serial port driver");
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index c2d9068b491..db3486d3387 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -24,7 +24,6 @@
* $Id: sa1100.c,v 1.50 2002/07/29 14:41:04 rmk Exp $
*
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -816,7 +815,6 @@ static struct uart_driver sa1100_reg = {
.owner = THIS_MODULE,
.driver_name = "ttySA",
.dev_name = "ttySA",
- .devfs_name = "ttySA",
.major = SERIAL_SA1100_MAJOR,
.minor = MINOR_START,
.nr = NR_PORTS,
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 17839e753e4..5f7ba1adb30 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -22,7 +22,6 @@
* 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/config.h>
#include <linux/module.h>
#include <linux/tty.h>
#include <linux/slab.h>
@@ -50,6 +49,12 @@
*/
static DEFINE_MUTEX(port_mutex);
+/*
+ * lockdep: port->lock is initialized in two places, but we
+ * want only one lock-class:
+ */
+static struct lock_class_key port_lock_key;
+
#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0))
@@ -691,7 +696,8 @@ static int uart_set_info(struct uart_state *state,
(new_serial.baud_base != port->uartclk / 16) ||
(close_delay != state->close_delay) ||
(closing_wait != state->closing_wait) ||
- (new_serial.xmit_fifo_size != port->fifosize) ||
+ (new_serial.xmit_fifo_size &&
+ new_serial.xmit_fifo_size != port->fifosize) ||
(((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0))
goto exit;
port->flags = ((port->flags & ~UPF_USR_MASK) |
@@ -796,7 +802,8 @@ static int uart_set_info(struct uart_state *state,
port->custom_divisor = new_serial.custom_divisor;
state->close_delay = close_delay;
state->closing_wait = closing_wait;
- port->fifosize = new_serial.xmit_fifo_size;
+ if (new_serial.xmit_fifo_size)
+ port->fifosize = new_serial.xmit_fifo_size;
if (state->info->tty)
state->info->tty->low_latency =
(port->flags & UPF_LOW_LATENCY) ? 1 : 0;
@@ -1866,6 +1873,7 @@ uart_set_options(struct uart_port *port, struct console *co,
* early.
*/
spin_lock_init(&port->lock);
+ lockdep_set_class(&port->lock, &port_lock_key);
memset(&termios, 0, sizeof(struct termios));
@@ -1921,6 +1929,13 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
mutex_lock(&state->mutex);
+#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
+ if (uart_console(port)) {
+ mutex_unlock(&state->mutex);
+ return 0;
+ }
+#endif
+
if (state->info && state->info->flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
@@ -1959,6 +1974,13 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
mutex_lock(&state->mutex);
+#ifdef CONFIG_DISABLE_CONSOLE_SUSPEND
+ if (uart_console(port)) {
+ mutex_unlock(&state->mutex);
+ return 0;
+ }
+#endif
+
uart_change_pm(state, 0);
/*
@@ -2028,6 +2050,7 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port)
case UPIO_MEM:
case UPIO_MEM32:
case UPIO_AU:
+ case UPIO_TSI:
snprintf(address, sizeof(address),
"MMIO 0x%lx", port->mapbase);
break;
@@ -2153,7 +2176,6 @@ int uart_register_driver(struct uart_driver *drv)
normal->owner = drv->owner;
normal->driver_name = drv->driver_name;
- normal->devfs_name = drv->devfs_name;
normal->name = drv->dev_name;
normal->major = drv->major;
normal->minor_start = drv->minor;
@@ -2161,7 +2183,7 @@ int uart_register_driver(struct uart_driver *drv)
normal->subtype = SERIAL_TYPE_NORMAL;
normal->init_termios = tty_std_termios;
normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
normal->driver_state = drv;
tty_set_operations(normal, &uart_ops);
@@ -2249,8 +2271,10 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
* If this port is a console, then the spinlock is already
* initialised.
*/
- if (!(uart_console(port) && (port->cons->flags & CON_ENABLED)))
+ if (!(uart_console(port) && (port->cons->flags & CON_ENABLED))) {
spin_lock_init(&port->lock);
+ lockdep_set_class(&port->lock, &port_lock_key);
+ }
uart_configure_port(drv, state, port);
@@ -2312,7 +2336,7 @@ int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port)
mutex_unlock(&state->mutex);
/*
- * Remove the devices from devfs
+ * Remove the devices from the tty layer
*/
tty_unregister_device(drv->tty_driver, port->line);
@@ -2367,6 +2391,9 @@ int uart_match_port(struct uart_port *port1, struct uart_port *port2)
return (port1->iobase == port2->iobase) &&
(port1->hub6 == port2->hub6);
case UPIO_MEM:
+ case UPIO_MEM32:
+ case UPIO_AU:
+ case UPIO_TSI:
return (port1->mapbase == port2->mapbase);
}
return 0;
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 2c70773543e..cbf260bc225 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -786,6 +786,7 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
+ PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "GLOBETROTTER.cis"),
/* too generic */
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
/* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index 776d4ff0608..23ddedbaec0 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_LH7A40X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 3bdee64d1a9..b361669f85a 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -38,7 +38,6 @@
* Fix some spin_locks.
* Do not call uart_add_one_port for absent ports.
*/
-#include <linux/config.h>
#if defined(CONFIG_SERIAL_TXX9_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -69,12 +68,10 @@ static char *serial_name = "TX39/49 Serial driver";
#if !defined(CONFIG_SERIAL_TXX9_STDSERIAL)
/* "ttyS" is used for standard serial driver */
#define TXX9_TTY_NAME "ttyTX"
-#define TXX9_TTY_DEVFS_NAME "tttx/"
#define TXX9_TTY_MINOR_START (64 + 64) /* ttyTX0(128), ttyTX1(129) */
#else
/* acts like standard serial driver */
#define TXX9_TTY_NAME "ttyS"
-#define TXX9_TTY_DEVFS_NAME "tts/"
#define TXX9_TTY_MINOR_START 64
#endif
#define TXX9_TTY_MAJOR TTY_MAJOR
@@ -498,7 +495,7 @@ static int serial_txx9_startup(struct uart_port *port)
sio_out(up, TXX9_SIDISR, 0);
retval = request_irq(up->port.irq, serial_txx9_interrupt,
- SA_SHIRQ, "serial_txx9", up);
+ IRQF_SHARED, "serial_txx9", up);
if (retval)
return retval;
@@ -971,7 +968,6 @@ console_initcall(serial_txx9_console_init);
static struct uart_driver serial_txx9_reg = {
.owner = THIS_MODULE,
.driver_name = "serial_txx9",
- .devfs_name = TXX9_TTY_DEVFS_NAME,
.dev_name = TXX9_TTY_NAME,
.major = TXX9_TTY_MAJOR,
.minor = TXX9_TTY_MINOR_START,
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index 44f6bf79bbe..f336ba6778d 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -3,7 +3,7 @@
*
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
- * Copyright (C) 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2002 - 2006 Paul Mundt
*
* based off of the old drivers/char/sh-sci.c by:
*
@@ -23,8 +23,6 @@
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -33,71 +31,77 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/sysrq.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/console.h>
-#include <linux/bitops.h>
-#include <linux/generic_serial.h>
+#include <linux/platform_device.h>
#ifdef CONFIG_CPU_FREQ
#include <linux/notifier.h>
#include <linux/cpufreq.h>
#endif
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
#include <asm/clock.h>
-#endif
-
-#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
+#include <asm/kgdb.h>
#endif
+#include <asm/sci.h>
+
#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include "sh-sci.h"
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
+struct sci_port {
+ struct uart_port port;
+
+ /* Port type */
+ unsigned int type;
+
+ /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
+ unsigned int irqs[SCIx_NR_IRQS];
+
+ /* Port pin configuration */
+ void (*init_pins)(struct uart_port *port,
+ unsigned int cflag);
-static int kgdb_get_char(struct sci_port *port);
-static void kgdb_put_char(struct sci_port *port, char c);
-static void kgdb_handle_error(struct sci_port *port);
+ /* Port enable callback */
+ void (*enable)(struct uart_port *port);
+
+ /* Port disable callback */
+ void (*disable)(struct uart_port *port);
+
+ /* Break timer */
+ struct timer_list break_timer;
+ int break_flag;
+};
+
+#ifdef CONFIG_SH_KGDB
static struct sci_port *kgdb_sci_port;
-#endif /* CONFIG_SH_KGDB */
+#endif
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-static struct sci_port *serial_console_port = 0;
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+static struct sci_port *serial_console_port;
+#endif
/* Function prototypes */
static void sci_stop_tx(struct uart_port *port);
-static void sci_start_tx(struct uart_port *port);
-static void sci_start_rx(struct uart_port *port, unsigned int tty_start);
-static void sci_stop_rx(struct uart_port *port);
-static int sci_request_irq(struct sci_port *port);
-static void sci_free_irq(struct sci_port *port);
-
-static struct sci_port sci_ports[];
-static struct uart_driver sci_uart_driver;
-#define SCI_NPORTS sci_uart_driver.nr
+#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+static struct sci_port sci_ports[SCI_NPORTS];
+static struct uart_driver sci_uart_driver;
-static void handle_error(struct uart_port *port)
-{ /* Clear error flags */
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \
+ defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+static inline void handle_error(struct uart_port *port)
+{
+ /* Clear error flags */
sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
}
@@ -107,8 +111,8 @@ static int get_char(struct uart_port *port)
unsigned short status;
int c;
- local_irq_save(flags);
- do {
+ spin_lock_irqsave(&port->lock, flags);
+ do {
status = sci_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
handle_error(port);
@@ -118,38 +122,19 @@ static int get_char(struct uart_port *port)
c = sci_in(port, SCxRDR);
sci_in(port, SCxSR); /* Dummy read */
sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
return c;
}
-
-/* Taken from sh-stub.c of GDB 4.18 */
-static const char hexchars[] = "0123456789abcdef";
-
-static __inline__ char highhex(int x)
-{
- return hexchars[(x >> 4) & 0xf];
-}
-
-static __inline__ char lowhex(int x)
-{
- return hexchars[x & 0xf];
-}
-
#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
-/*
- * Send the packet in buffer. The host gets one chance to read it.
- * This routine does not wait for a positive acknowledge.
- */
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB)
static void put_char(struct uart_port *port, char c)
{
unsigned long flags;
unsigned short status;
- local_irq_save(flags);
+ spin_lock_irqsave(&port->lock, flags);
do {
status = sci_in(port, SCxSR);
@@ -159,9 +144,11 @@ static void put_char(struct uart_port *port, char c)
sci_in(port, SCxSR); /* Dummy read */
sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
+#endif
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
static void put_string(struct sci_port *sci_port, const char *buffer, int count)
{
struct uart_port *port = &sci_port->port;
@@ -214,96 +201,28 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
}
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-
#ifdef CONFIG_SH_KGDB
-
-/* Is the SCI ready, ie is there a char waiting? */
-static int kgdb_is_char_ready(struct sci_port *port)
-{
- unsigned short status = sci_in(port, SCxSR);
-
- if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
- kgdb_handle_error(port);
-
- return (status & SCxSR_RDxF(port));
-}
-
-/* Write a char */
-static void kgdb_put_char(struct sci_port *port, char c)
-{
- unsigned short status;
-
- do
- status = sci_in(port, SCxSR);
- while (!(status & SCxSR_TDxE(port)));
-
- sci_out(port, SCxTDR, c);
- sci_in(port, SCxSR); /* Dummy read */
- sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
-}
-
-/* Get a char if there is one, else ret -1 */
-static int kgdb_get_char(struct sci_port *port)
-{
- int c;
-
- if (kgdb_is_char_ready(port) == 0)
- c = -1;
- else {
- c = sci_in(port, SCxRDR);
- sci_in(port, SCxSR); /* Dummy read */
- sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
- }
-
- return c;
-}
-
-/* Called from kgdbstub.c to get a character, i.e. is blocking */
static int kgdb_sci_getchar(void)
{
- volatile int c;
+ int c;
/* Keep trying to read a character, this could be neater */
- while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
+ while ((c = get_char(kgdb_sci_port)) < 0)
+ cpu_relax();
return c;
}
-/* Called from kgdbstub.c to put a character, just a wrapper */
-static void kgdb_sci_putchar(int c)
-{
-
- kgdb_put_char(kgdb_sci_port, c);
-}
-
-/* Clear any errors on the SCI */
-static void kgdb_handle_error(struct sci_port *port)
+static inline void kgdb_sci_putchar(int c)
{
- sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Clear error flags */
+ put_char(kgdb_sci_port, c);
}
-
-/* Breakpoint if there's a break sent on the serial port */
-static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
-{
- struct sci_port *port = ptr;
- unsigned short status = sci_in(port, SCxSR);
-
- if (status & SCxSR_BRK(port)) {
-
- /* Break into the debugger if a break is detected */
- BREAKPOINT();
-
- /* Clear */
- sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
- }
-}
-
#endif /* CONFIG_SH_KGDB */
#if defined(__H8300S__)
enum { sci_disable, sci_enable };
-static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl)
+static void h8300_sci_config(struct uart_port* port, unsigned int ctrl)
{
volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
int ch = (port->mapbase - SMR0) >> 3;
@@ -315,32 +234,66 @@ static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl)
*mstpcrl &= ~mask;
}
}
+
+static inline void h8300_sci_enable(struct uart_port *port)
+{
+ h8300_sci_config(port, sci_enable);
+}
+
+static inline void h8300_sci_disable(struct uart_port *port)
+{
+ h8300_sci_config(port, sci_disable);
+}
#endif
-#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
-#if defined(__H8300H__) || defined(__H8300S__)
+#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) && \
+ defined(__H8300H__) || defined(__H8300S__)
static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag)
{
int ch = (port->mapbase - SMR0) >> 3;
/* set DDR regs */
- H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT);
- H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT);
+ H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+ h8300_sci_pins[ch].rx,
+ H8300_GPIO_INPUT);
+ H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+ h8300_sci_pins[ch].tx,
+ H8300_GPIO_OUTPUT);
+
/* tx mark output*/
H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
}
+#else
+#define sci_init_pins_sci NULL
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+
+ if (cflag & CRTSCTS)
+ fcr_val |= SCFCR_MCE;
+
+ sci_out(port, SCFCR, fcr_val);
+}
+#else
+#define sci_init_pins_irda NULL
#endif
+
+#ifdef SCI_ONLY
+#define sci_init_pins_scif NULL
#endif
#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
/* SH7300 doesn't use RTS/CTS */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
sci_out(port, SCFCR, 0);
}
#elif defined(CONFIG_CPU_SH3)
-/* For SH7705, SH7707, SH7709, SH7709A, SH7729 */
+/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
unsigned int fcr_val = 0;
@@ -367,20 +320,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
sci_out(port, SCFCR, fcr_val);
}
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
-static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
-{
- unsigned int fcr_val = 0;
-
- if (cflag & CRTSCTS)
- fcr_val |= SCFCR_MCE;
-
- sci_out(port, SCFCR, fcr_val);
-}
-#endif
#else
-
/* For SH7750 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
@@ -389,7 +329,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
if (cflag & CRTSCTS) {
fcr_val |= SCFCR_MCE;
} else {
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#ifdef CONFIG_CPU_SUBTYPE_SH7343
+ /* Nothing */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
#else
ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
@@ -397,10 +339,41 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
}
sci_out(port, SCFCR, fcr_val);
}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+static inline int scif_txroom(struct uart_port *port)
+{
+ return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
+}
+
+static inline int scif_rxroom(struct uart_port *port)
+{
+ return sci_in(port, SCRFDR) & 0x7f;
+}
+#else
+static inline int scif_txroom(struct uart_port *port)
+{
+ return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8);
+}
+static inline int scif_rxroom(struct uart_port *port)
+{
+ return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+}
#endif
#endif /* SCIF_ONLY || SCI_AND_SCIF */
+static inline int sci_txroom(struct uart_port *port)
+{
+ return ((sci_in(port, SCxSR) & SCI_TDRE) != 0);
+}
+
+static inline int sci_rxroom(struct uart_port *port)
+{
+ return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0);
+}
+
/* ********************************************************************** *
* the interrupt related routines *
* ********************************************************************** */
@@ -409,14 +382,12 @@ static void sci_transmit_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
unsigned int stopped = uart_tx_stopped(port);
- unsigned long flags;
unsigned short status;
unsigned short ctrl;
- int count, txroom;
+ int count;
status = sci_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) {
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
if (uart_circ_empty(xmit)) {
ctrl &= ~SCI_CTRL_FLAGS_TIE;
@@ -424,25 +395,15 @@ static void sci_transmit_chars(struct uart_port *port)
ctrl |= SCI_CTRL_FLAGS_TIE;
}
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
return;
}
-#if !defined(SCI_ONLY)
- if (port->type == PORT_SCIF) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
- txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
-#else
- txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8);
-#endif
- } else {
- txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
- }
-#else
- txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
+#ifndef SCI_ONLY
+ if (port->type == PORT_SCIF)
+ count = scif_txroom(port);
+ else
#endif
-
- count = txroom;
+ count = sci_txroom(port);
do {
unsigned char c;
@@ -469,7 +430,6 @@ static void sci_transmit_chars(struct uart_port *port)
if (uart_circ_empty(xmit)) {
sci_stop_tx(port);
} else {
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
#if !defined(SCI_ONLY)
@@ -481,7 +441,6 @@ static void sci_transmit_chars(struct uart_port *port)
ctrl |= SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
}
@@ -491,6 +450,7 @@ static void sci_transmit_chars(struct uart_port *port)
static inline void sci_receive_chars(struct uart_port *port,
struct pt_regs *regs)
{
+ struct sci_port *sci_port = (struct sci_port *)port;
struct tty_struct *tty = port->info->tty;
int i, count, copied = 0;
unsigned short status;
@@ -502,18 +462,11 @@ static inline void sci_receive_chars(struct uart_port *port,
while (1) {
#if !defined(SCI_ONLY)
- if (port->type == PORT_SCIF) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
- count = sci_in(port, SCRFDR) & 0x7f;
-#else
- count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ;
-#endif
- } else {
- count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
- }
-#else
- count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
+ if (port->type == PORT_SCIF)
+ count = scif_rxroom(port);
+ else
#endif
+ count = sci_rxroom(port);
/* Don't copy more bytes than there is room for in the buffer */
count = tty_buffer_request_room(tty, count);
@@ -524,11 +477,10 @@ static inline void sci_receive_chars(struct uart_port *port,
if (port->type == PORT_SCI) {
char c = sci_in(port, SCxRDR);
- if(((struct sci_port *)port)->break_flag
- || uart_handle_sysrq_char(port, c, regs)) {
+ if (uart_handle_sysrq_char(port, c, regs) || sci_port->break_flag)
count = 0;
- } else {
- tty_insert_flip_char(tty, c, TTY_NORMAL);
+ else {
+ tty_insert_flip_char(tty, c, TTY_NORMAL);
}
} else {
for (i=0; i<count; i++) {
@@ -536,15 +488,17 @@ static inline void sci_receive_chars(struct uart_port *port,
status = sci_in(port, SCxSR);
#if defined(CONFIG_CPU_SH3)
/* Skip "chars" during break */
- if (((struct sci_port *)port)->break_flag) {
+ if (sci_port->break_flag) {
if ((c == 0) &&
(status & SCxSR_FER(port))) {
count--; i--;
continue;
}
+
/* Nonzero => end-of-break */
pr_debug("scif: debounce<%02x>\n", c);
- ((struct sci_port *)port)->break_flag = 0;
+ sci_port->break_flag = 0;
+
if (STEPFN(c)) {
count--; i--;
continue;
@@ -601,15 +555,17 @@ static void sci_schedule_break_timer(struct sci_port *port)
/* Ensure that two consecutive samples find the break over. */
static void sci_break_timer(unsigned long data)
{
- struct sci_port * port = (struct sci_port *)data;
- if(sci_rxd_in(&port->port) == 0) {
+ struct sci_port *port = (struct sci_port *)data;
+
+ if (sci_rxd_in(&port->port) == 0) {
port->break_flag = 1;
- sci_schedule_break_timer(port);
- } else if(port->break_flag == 1){
+ sci_schedule_break_timer(port);
+ } else if (port->break_flag == 1) {
/* break is over. */
port->break_flag = 2;
- sci_schedule_break_timer(port);
- } else port->break_flag = 0;
+ sci_schedule_break_timer(port);
+ } else
+ port->break_flag = 0;
}
static inline int sci_handle_errors(struct uart_port *port)
@@ -618,40 +574,41 @@ static inline int sci_handle_errors(struct uart_port *port)
unsigned short status = sci_in(port, SCxSR);
struct tty_struct *tty = port->info->tty;
- if (status&SCxSR_ORER(port)) {
+ if (status & SCxSR_ORER(port)) {
/* overrun error */
- if(tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
copied++;
pr_debug("sci: overrun error\n");
}
- if (status&SCxSR_FER(port)) {
+ if (status & SCxSR_FER(port)) {
if (sci_rxd_in(port) == 0) {
/* Notify of BREAK */
- struct sci_port * sci_port = (struct sci_port *)port;
- if(!sci_port->break_flag) {
- sci_port->break_flag = 1;
- sci_schedule_break_timer((struct sci_port *)port);
+ struct sci_port *sci_port = (struct sci_port *)port;
+
+ if (!sci_port->break_flag) {
+ sci_port->break_flag = 1;
+ sci_schedule_break_timer(sci_port);
+
/* Do sysrq handling. */
- if(uart_handle_break(port))
+ if (uart_handle_break(port))
return 0;
pr_debug("sci: BREAK detected\n");
- if(tty_insert_flip_char(tty, 0, TTY_BREAK))
+ if (tty_insert_flip_char(tty, 0, TTY_BREAK))
copied++;
}
- }
- else {
+ } else {
/* frame error */
- if(tty_insert_flip_char(tty, 0, TTY_FRAME))
+ if (tty_insert_flip_char(tty, 0, TTY_FRAME))
copied++;
pr_debug("sci: frame error\n");
}
}
- if (status&SCxSR_PER(port)) {
- if(tty_insert_flip_char(tty, 0, TTY_PARITY))
- copied++;
+ if (status & SCxSR_PER(port)) {
/* parity error */
+ if (tty_insert_flip_char(tty, 0, TTY_PARITY))
+ copied++;
pr_debug("sci: parity error\n");
}
@@ -674,7 +631,7 @@ static inline int sci_handle_breaks(struct uart_port *port)
s->break_flag = 1;
#endif
/* Notify of BREAK */
- if(tty_insert_flip_char(tty, 0, TTY_BREAK))
+ if (tty_insert_flip_char(tty, 0, TTY_BREAK))
copied++;
pr_debug("sci: BREAK detected\n");
}
@@ -683,7 +640,7 @@ static inline int sci_handle_breaks(struct uart_port *port)
/* XXX: Handle SCIF overrun error */
if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
sci_out(port, SCLSR, 0);
- if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
+ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
copied++;
pr_debug("sci: overrun error\n");
}
@@ -692,13 +649,12 @@ static inline int sci_handle_breaks(struct uart_port *port)
if (copied)
tty_flip_buffer_push(tty);
+
return copied;
}
-static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sci_rx_interrupt(int irq, void *port, struct pt_regs *regs)
{
- struct uart_port *port = ptr;
-
/* I think sci_receive_chars has to be called irrespective
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
@@ -712,7 +668,9 @@ static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
struct uart_port *port = ptr;
+ spin_lock_irq(&port->lock);
sci_transmit_chars(port);
+ spin_unlock_irq(&port->lock);
return IRQ_HANDLED;
}
@@ -756,6 +714,12 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
/* Handle BREAKs */
sci_handle_breaks(port);
+
+#ifdef CONFIG_SH_KGDB
+ /* Break into the debugger if a break is detected */
+ BREAKPOINT();
+#endif
+
sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
@@ -770,16 +734,16 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
scr_status = sci_in(port,SCSCR);
/* Tx Interrupt */
- if ((ssr_status&0x0020) && (scr_status&0x0080))
+ if ((ssr_status & 0x0020) && (scr_status & 0x0080))
sci_tx_interrupt(irq, ptr, regs);
/* Rx Interrupt */
- if ((ssr_status&0x0002) && (scr_status&0x0040))
+ if ((ssr_status & 0x0002) && (scr_status & 0x0040))
sci_rx_interrupt(irq, ptr, regs);
/* Error Interrupt */
- if ((ssr_status&0x0080) && (scr_status&0x0400))
+ if ((ssr_status & 0x0080) && (scr_status & 0x0400))
sci_er_interrupt(irq, ptr, regs);
/* Break Interrupt */
- if ((ssr_status&0x0010) && (scr_status&0x0200))
+ if ((ssr_status & 0x0010) && (scr_status & 0x0200))
sci_br_interrupt(irq, ptr, regs);
return IRQ_HANDLED;
@@ -790,7 +754,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
* Here we define a transistion notifier so that we can update all of our
* ports' baud rate when the peripheral clock changes.
*/
-static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p)
+static int sci_notifier(struct notifier_block *self,
+ unsigned long phase, void *p)
{
struct cpufreq_freqs *freqs = p;
int i;
@@ -817,8 +782,9 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void *
clk_put(clk);
}
- printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n",
- __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+ printk(KERN_INFO "%s: got a postchange notification "
+ "for cpu %d (old %d, new %d)\n",
+ __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
}
return NOTIFY_OK;
@@ -842,8 +808,9 @@ static int sci_request_irq(struct sci_port *port)
printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n");
return -ENODEV;
}
- if (request_irq(port->irqs[0], sci_mpxed_interrupt, SA_INTERRUPT,
- "sci", port)) {
+
+ if (request_irq(port->irqs[0], sci_mpxed_interrupt,
+ SA_INTERRUPT, "sci", port)) {
printk(KERN_ERR "sci: Cannot allocate irq.\n");
return -ENODEV;
}
@@ -851,8 +818,8 @@ static int sci_request_irq(struct sci_port *port)
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
if (!port->irqs[i])
continue;
- if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
- desc[i], port)) {
+ if (request_irq(port->irqs[i], handlers[i],
+ SA_INTERRUPT, desc[i], port)) {
printk(KERN_ERR "sci: Cannot allocate irq.\n");
return -ENODEV;
}
@@ -904,50 +871,42 @@ static unsigned int sci_get_mctrl(struct uart_port *port)
static void sci_start_tx(struct uart_port *port)
{
- struct sci_port *s = &sci_ports[port->line];
+ unsigned short ctrl;
- disable_irq(s->irqs[SCIx_TXI_IRQ]);
- sci_transmit_chars(port);
- enable_irq(s->irqs[SCIx_TXI_IRQ]);
+ /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+ ctrl = sci_in(port, SCSCR);
+ ctrl |= SCI_CTRL_FLAGS_TIE;
+ sci_out(port, SCSCR, ctrl);
}
static void sci_stop_tx(struct uart_port *port)
{
- unsigned long flags;
unsigned short ctrl;
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
ctrl &= ~SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
static void sci_start_rx(struct uart_port *port, unsigned int tty_start)
{
- unsigned long flags;
unsigned short ctrl;
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
static void sci_stop_rx(struct uart_port *port)
{
- unsigned long flags;
unsigned short ctrl;
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
static void sci_enable_ms(struct uart_port *port)
@@ -964,9 +923,8 @@ static int sci_startup(struct uart_port *port)
{
struct sci_port *s = &sci_ports[port->line];
-#if defined(__H8300S__)
- h8300_sci_enable(port, sci_enable);
-#endif
+ if (s->enable)
+ s->enable(port);
sci_request_irq(s);
sci_start_tx(port);
@@ -983,9 +941,8 @@ static void sci_shutdown(struct uart_port *port)
sci_stop_tx(port);
sci_free_irq(s);
-#if defined(__H8300S__)
- h8300_sci_enable(port, sci_disable);
-#endif
+ if (s->disable)
+ s->disable(port);
}
static void sci_set_termios(struct uart_port *port, struct termios *termios,
@@ -998,6 +955,23 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ switch (baud) {
+ case 0:
+ t = -1;
+ break;
+ default:
+ {
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ struct clk *clk = clk_get("module_clk");
+ t = SCBRR_VALUE(baud, clk_get_rate(clk));
+ clk_put(clk);
+#else
+ t = SCBRR_VALUE(baud);
+#endif
+ }
+ break;
+ }
+
spin_lock_irqsave(&port->lock, flags);
do {
@@ -1007,9 +981,8 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
#if !defined(SCI_ONLY)
- if (port->type == PORT_SCIF) {
+ if (port->type == PORT_SCIF)
sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
- }
#endif
smr_val = sci_in(port, SCSMR) & 3;
@@ -1026,23 +999,6 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
sci_out(port, SCSMR, smr_val);
- switch (baud) {
- case 0:
- t = -1;
- break;
- default:
- {
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
- struct clk *clk = clk_get("module_clk");
- t = SCBRR_VALUE(baud, clk_get_rate(clk));
- clk_put(clk);
-#else
- t = SCBRR_VALUE(baud);
-#endif
- }
- break;
- }
-
if (t > 0) {
if(t >= 256) {
sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
@@ -1093,11 +1049,23 @@ static void sci_config_port(struct uart_port *port, int flags)
port->type = s->type;
+ switch (port->type) {
+ case PORT_SCI:
+ s->init_pins = sci_init_pins_sci;
+ break;
+ case PORT_SCIF:
+ s->init_pins = sci_init_pins_scif;
+ break;
+ case PORT_IRDA:
+ s->init_pins = sci_init_pins_irda;
+ break;
+ }
+
#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
if (port->mapbase == 0)
port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
- port->membase = (void *)port->mapbase;
+ port->membase = (void __iomem *)port->mapbase;
#endif
}
@@ -1133,412 +1101,61 @@ static struct uart_ops sci_uart_ops = {
.verify_port = sci_verify_port,
};
-static struct sci_port sci_ports[] = {
-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
- {
- .port = {
- .membase = (void *)0xfffffe80,
- .mapbase = 0xfffffe80,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = SCI_IRQS,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
- {
- .port = {
- .membase = (void *)SCIF0,
- .mapbase = SCIF0,
- .iotype = UPIO_MEM,
- .irq = 55,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH3_IRDA_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)SCIF2,
- .mapbase = SCIF2,
- .iotype = UPIO_MEM,
- .irq = 59,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH3_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
- {
- .port = {
- .membase = (void *)0xfffffe80,
- .mapbase = 0xfffffe80,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = SCI_IRQS,
- },
- {
- .port = {
- .membase = (void *)0xa4000150,
- .mapbase = 0xa4000150,
- .iotype = UPIO_MEM,
- .irq = 59,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH3_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xa4000140,
- .mapbase = 0xa4000140,
- .iotype = UPIO_MEM,
- .irq = 55,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_IRDA,
- .irqs = SH3_IRDA_IRQS,
- .init_pins = sci_init_pins_irda,
- }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
- {
- .port = {
- .membase = (void *)0xA4430000,
- .mapbase = 0xA4430000,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7300_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH73180_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
- {
- .port = {
- .membase = (void *)0xffe80000,
- .mapbase = 0xffe80000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH4_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = SCI_IRQS,
- },
- {
- .port = {
- .membase = (void *)0xffe80000,
- .mapbase = 0xffe80000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH4_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
- {
- .port = {
- .membase = (void *)0xfe600000,
- .mapbase = 0xfe600000,
- .iotype = UPIO_MEM,
- .irq = 55,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7760_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xfe610000,
- .mapbase = 0xfe610000,
- .iotype = UPIO_MEM,
- .irq = 75,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH7760_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xfe620000,
- .mapbase = 0xfe620000,
- .iotype = UPIO_MEM,
- .irq = 79,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCIF,
- .irqs = SH7760_SCIF2_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 26,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = STB1_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xffe80000,
- .mapbase = 0xffe80000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH4_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
- {
- .port = {
- .iotype = UPIO_MEM,
- .irq = 42,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH5_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
- {
- .port = {
- .membase = (void *)0x00ffffb0,
- .mapbase = 0x00ffffb0,
- .iotype = UPIO_MEM,
- .irq = 54,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = H8300H_SCI_IRQS0,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffffb8,
- .mapbase = 0x00ffffb8,
- .iotype = UPIO_MEM,
- .irq = 58,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCI,
- .irqs = H8300H_SCI_IRQS1,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffffc0,
- .mapbase = 0x00ffffc0,
- .iotype = UPIO_MEM,
- .irq = 62,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCI,
- .irqs = H8300H_SCI_IRQS2,
- .init_pins = sci_init_pins_sci,
- },
-#elif defined(CONFIG_H8S2678)
- {
- .port = {
- .membase = (void *)0x00ffff78,
- .mapbase = 0x00ffff78,
- .iotype = UPIO_MEM,
- .irq = 90,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = H8S_SCI_IRQS0,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffff80,
- .mapbase = 0x00ffff80,
- .iotype = UPIO_MEM,
- .irq = 94,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCI,
- .irqs = H8S_SCI_IRQS1,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffff88,
- .mapbase = 0x00ffff88,
- .iotype = UPIO_MEM,
- .irq = 98,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCI,
- .irqs = H8S_SCI_IRQS2,
- .init_pins = sci_init_pins_sci,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
- {
- .port = {
- .membase = (void *)0xff923000,
- .mapbase = 0xff923000,
- .iotype = UPIO_MEM,
- .irq = 61,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7770_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xff924000,
- .mapbase = 0xff924000,
- .iotype = UPIO_MEM,
- .irq = 62,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH7770_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xff925000,
- .mapbase = 0xff925000,
- .iotype = UPIO_MEM,
- .irq = 63,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCIF,
- .irqs = SH7770_SCIF2_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7780_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xffe10000,
- .mapbase = 0xffe10000,
- .iotype = UPIO_MEM,
- .irq = 79,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH7780_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
+static void __init sci_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+
+ first = 0;
+
+ for (i = 0; i < SCI_NPORTS; i++) {
+ sci_ports[i].port.ops = &sci_uart_ops;
+ sci_ports[i].port.iotype = UPIO_MEM;
+ sci_ports[i].port.line = i;
+ sci_ports[i].port.fifosize = 1;
+
+#if defined(__H8300H__) || defined(__H8300S__)
+#ifdef __H8300S__
+ sci_ports[i].enable = h8300_sci_enable;
+ sci_ports[i].disable = h8300_sci_disable;
+#endif
+ sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK;
+#elif defined(CONFIG_SUPERH64)
+ sci_ports[i].port.uartclk = current_cpu_data.module_clock * 16;
#else
-#error "CPU subtype not defined"
+ /*
+ * XXX: We should use a proper SCI/SCIF clock
+ */
+ {
+ struct clk *clk = clk_get("module_clk");
+ sci_ports[i].port.uartclk = clk_get_rate(clk) * 16;
+ clk_put(clk);
+ }
#endif
-};
+
+ sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i];
+ sci_ports[i].break_timer.function = sci_break_timer;
+
+ init_timer(&sci_ports[i].break_timer);
+ }
+}
+
+int __init early_sci_setup(struct uart_port *port)
+{
+ if (unlikely(port->line > SCI_NPORTS))
+ return -ENODEV;
+
+ sci_init_ports();
+
+ sci_ports[port->line].port.membase = port->membase;
+ sci_ports[port->line].port.mapbase = port->mapbase;
+ sci_ports[port->line].port.type = port->type;
+
+ return 0;
+}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
/*
@@ -1560,34 +1177,38 @@ static int __init serial_console_setup(struct console *co, char *options)
int flow = 'n';
int ret;
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= SCI_NPORTS)
+ co->index = 0;
+
serial_console_port = &sci_ports[co->index];
port = &serial_console_port->port;
- port->type = serial_console_port->type;
-
-#ifdef CONFIG_SUPERH64
- /* This is especially needed on sh64 to remap the SCIF */
- sci_config_port(port, 0);
-#endif
/*
- * We need to set the initial uartclk here, since otherwise it will
- * only ever be setup at sci_init() time.
+ * Also need to check port->type, we don't actually have any
+ * UPIO_PORT ports, but uart_report_port() handily misreports
+ * it anyways if we don't have a port available by the time this is
+ * called.
*/
-#if defined(__H8300H__) || defined(__H8300S__)
- port->uartclk = CONFIG_CPU_CLOCK;
+ if (!port->type)
+ return -ENODEV;
+ if (!port->membase || !port->mapbase)
+ return -ENODEV;
+
+ spin_lock_init(&port->lock);
+
+ port->type = serial_console_port->type;
+
+ if (port->flags & UPF_IOREMAP)
+ sci_config_port(port, 0);
+
+ if (serial_console_port->enable)
+ serial_console_port->enable(port);
-#if defined(__H8300S__)
- h8300_sci_enable(port, sci_enable);
-#endif
-#elif defined(CONFIG_SUPERH64)
- port->uartclk = current_cpu_info.module_clock * 16;
-#else
- {
- struct clk *clk = clk_get("module_clk");
- port->uartclk = clk_get_rate(clk) * 16;
- clk_put(clk);
- }
-#endif
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1605,17 +1226,17 @@ static struct console serial_console = {
.device = uart_console_device,
.write = serial_console_write,
.setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER,
.index = -1,
.data = &sci_uart_driver,
};
static int __init sci_console_init(void)
{
+ sci_init_ports();
register_console(&serial_console);
return 0;
}
-
console_initcall(sci_console_init);
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
@@ -1650,6 +1271,8 @@ int __init kgdb_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
+ spin_lock_init(&port->lock);
+
if (co->index != kgdb_portnum)
co->index = kgdb_portnum;
@@ -1678,10 +1301,10 @@ static struct console kgdb_console = {
/* Register the KGDB console so we get messages (d'oh!) */
static int __init kgdb_console_init(void)
{
+ sci_init_ports();
register_console(&kgdb_console);
return 0;
}
-
console_initcall(kgdb_console_init);
#endif /* CONFIG_SH_KGDB_CONSOLE */
@@ -1699,66 +1322,135 @@ static char banner[] __initdata =
static struct uart_driver sci_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "sci",
-#ifdef CONFIG_DEVFS_FS
- .devfs_name = "ttsc/",
-#endif
.dev_name = "ttySC",
.major = SCI_MAJOR,
.minor = SCI_MINOR_START,
+ .nr = SCI_NPORTS,
.cons = SCI_CONSOLE,
};
-static int __init sci_init(void)
+/*
+ * Register a set of serial devices attached to a platform device. The
+ * list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
+ * remapping (such as sh64) should also set UPF_IOREMAP.
+ */
+static int __devinit sci_probe(struct platform_device *dev)
{
- int chan, ret;
+ struct plat_sci_port *p = dev->dev.platform_data;
+ int i;
- printk("%s", banner);
+ for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) {
+ struct sci_port *sciport = &sci_ports[i];
- sci_uart_driver.nr = ARRAY_SIZE(sci_ports);
+ sciport->port.mapbase = p->mapbase;
- ret = uart_register_driver(&sci_uart_driver);
- if (ret == 0) {
- for (chan = 0; chan < SCI_NPORTS; chan++) {
- struct sci_port *sciport = &sci_ports[chan];
+ /*
+ * For the simple (and majority of) cases where we don't need
+ * to do any remapping, just cast the cookie directly.
+ */
+ if (p->mapbase && !p->membase && !(p->flags & UPF_IOREMAP))
+ p->membase = (void __iomem *)p->mapbase;
-#if defined(__H8300H__) || defined(__H8300S__)
- sciport->port.uartclk = CONFIG_CPU_CLOCK;
-#elif defined(CONFIG_SUPERH64)
- sciport->port.uartclk = current_cpu_info.module_clock * 16;
-#else
- struct clk *clk = clk_get("module_clk");
- sciport->port.uartclk = clk_get_rate(clk) * 16;
- clk_put(clk);
-#endif
- uart_add_one_port(&sci_uart_driver, &sciport->port);
- sciport->break_timer.data = (unsigned long)sciport;
- sciport->break_timer.function = sci_break_timer;
- init_timer(&sciport->break_timer);
- }
+ sciport->port.membase = p->membase;
+
+ sciport->port.irq = p->irqs[SCIx_TXI_IRQ];
+ sciport->port.flags = p->flags;
+ sciport->port.dev = &dev->dev;
+
+ sciport->type = sciport->port.type = p->type;
+
+ memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs));
+
+ uart_add_one_port(&sci_uart_driver, &sciport->port);
}
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
- printk("sci: CPU frequency notifier registered\n");
+ dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
#endif
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_gdb_detach();
#endif
- return ret;
+ return 0;
}
-static void __exit sci_exit(void)
+static int __devexit sci_remove(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < SCI_NPORTS; i++)
+ uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
+
+ return 0;
+}
+
+static int sci_suspend(struct platform_device *dev, pm_message_t state)
+{
+ int i;
+
+ for (i = 0; i < SCI_NPORTS; i++) {
+ struct sci_port *p = &sci_ports[i];
+
+ if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
+ uart_suspend_port(&sci_uart_driver, &p->port);
+ }
+
+ return 0;
+}
+
+static int sci_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < SCI_NPORTS; i++) {
+ struct sci_port *p = &sci_ports[i];
+
+ if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
+ uart_resume_port(&sci_uart_driver, &p->port);
+ }
+
+ return 0;
+}
+
+static struct platform_driver sci_driver = {
+ .probe = sci_probe,
+ .remove = __devexit_p(sci_remove),
+ .suspend = sci_suspend,
+ .resume = sci_resume,
+ .driver = {
+ .name = "sh-sci",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sci_init(void)
{
- int chan;
+ int ret;
+
+ printk(banner);
- for (chan = 0; chan < SCI_NPORTS; chan++)
- uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port);
+ sci_init_ports();
+
+ ret = uart_register_driver(&sci_uart_driver);
+ if (likely(ret == 0)) {
+ ret = platform_driver_register(&sci_driver);
+ if (unlikely(ret))
+ uart_unregister_driver(&sci_uart_driver);
+ }
+ return ret;
+}
+
+static void __exit sci_exit(void)
+{
+ platform_driver_unregister(&sci_driver);
uart_unregister_driver(&sci_uart_driver);
}
module_init(sci_init);
module_exit(sci_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index 1f14bb4382f..28643c4dc85 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -12,6 +12,7 @@
*/
#include <linux/config.h>
#include <linux/serial_core.h>
+#include <asm/io.h>
#if defined(__H8300H__) || defined(__H8300S__)
#include <asm/gpio.h>
@@ -23,40 +24,13 @@
#endif
#endif
-/* Offsets into the sci_port->irqs array */
-#define SCIx_ERI_IRQ 0
-#define SCIx_RXI_IRQ 1
-#define SCIx_TXI_IRQ 2
-
-/* ERI, RXI, TXI, BRI */
-#define SCI_IRQS { 23, 24, 25, 0 }
-#define SH3_SCIF_IRQS { 56, 57, 59, 58 }
-#define SH3_IRDA_IRQS { 52, 53, 55, 54 }
-#define SH4_SCIF_IRQS { 40, 41, 43, 42 }
-#define STB1_SCIF1_IRQS {23, 24, 26, 25 }
-#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
-#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
-#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
-#define SH7300_SCIF0_IRQS {80, 80, 80, 80 }
-#define SH73180_SCIF_IRQS {80, 81, 83, 82 }
-#define H8300H_SCI_IRQS0 {52, 53, 54, 0 }
-#define H8300H_SCI_IRQS1 {56, 57, 58, 0 }
-#define H8300H_SCI_IRQS2 {60, 61, 62, 0 }
-#define H8S_SCI_IRQS0 {88, 89, 90, 0 }
-#define H8S_SCI_IRQS1 {92, 93, 94, 0 }
-#define H8S_SCI_IRQS2 {96, 97, 98, 0 }
-#define SH5_SCIF_IRQS {39, 40, 42, 0 }
-#define SH7770_SCIF0_IRQS {61, 61, 61, 61 }
-#define SH7770_SCIF1_IRQS {62, 62, 62, 62 }
-#define SH7770_SCIF2_IRQS {63, 63, 63, 63 }
-#define SH7780_SCIF0_IRQS {40, 41, 43, 42 }
-#define SH7780_SCIF1_IRQS {76, 77, 79, 78 }
-
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCSPTR 0xffffff7c /* 8 bit */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706)
# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
@@ -100,12 +74,23 @@
# define SCPDR 0xA4050136 /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
+# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
# define SCPDR 0xA4050138 /* 16 bit SCIF */
# define SCSPTR2 SCPDR
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+# define SCSPTR0 0xffe00010 /* 16 bit SCIF */
+# define SCSPTR1 0xffe10010 /* 16 bit SCIF */
+# define SCSPTR2 0xffe20010 /* 16 bit SCIF */
+# define SCSPTR3 0xffe30010 /* 16 bit SCIF */
+# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
+# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -146,7 +131,7 @@
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
-# define SCIF_OPER 0x0001 /* Overrun error bit */
+# define SCIF_ORER 0x0001 /* Overrun error bit */
# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#else
@@ -274,15 +259,6 @@
*/
#define SCI_EVENT_WRITE_WAKEUP 0
-struct sci_port {
- struct uart_port port;
- int type;
- unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */
- void (*init_pins)(struct uart_port *port, unsigned int cflag);
- int break_flag;
- struct timer_list break_timer;
-};
-
#define SCI_IN(size, offset) \
unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
@@ -337,7 +313,9 @@ struct sci_port {
}
#ifdef CONFIG_CPU_SH3
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -363,7 +341,9 @@ struct sci_port {
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
SCIF_FNS(SCSCR, 0x08, 16)
@@ -448,7 +428,9 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
@@ -468,6 +450,13 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
return 1;
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == SCSPTR0)
+ return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0;
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH4_202)
@@ -505,6 +494,19 @@ static inline int sci_rxd_in(struct uart_port *port)
{
return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xffe00000)
+ return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffe10000)
+ return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffe20000)
+ return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffe30000)
+ return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -588,4 +590,3 @@ static inline int sci_rxd_in(struct uart_port *port)
#else /* Generic SH */
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
#endif
-
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 60ea4a3f071..2f148e5b925 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -37,7 +37,6 @@
* http://oss.sgi.com/projects/GenInfo/NoticeExplan
*/
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/serial.h>
@@ -649,7 +648,7 @@ static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static int sn_sal_connect_interrupt(struct sn_cons_port *port)
{
if (request_irq(SGI_UART_VECTOR, sn_sal_interrupt,
- SA_INTERRUPT | SA_SHIRQ,
+ IRQF_DISABLED | IRQF_SHARED,
"SAL console driver", port) >= 0) {
return SGI_UART_VECTOR;
}
diff --git a/drivers/serial/suncore.c b/drivers/serial/suncore.c
index fa4ae94243c..e35d9ab359f 100644
--- a/drivers/serial/suncore.c
+++ b/drivers/serial/suncore.c
@@ -10,7 +10,6 @@
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/console.h>
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index f137804b313..f851f0f44f9 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -20,8 +20,8 @@
#include <asm/hypervisor.h>
#include <asm/spitfire.h>
-#include <asm/vdev.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/irq.h>
#if defined(CONFIG_MAGIC_SYSRQ)
@@ -353,7 +353,6 @@ static struct uart_ops sunhv_pops = {
static struct uart_driver sunhv_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
@@ -408,143 +407,120 @@ static inline struct console *SUNHV_CONSOLE(void)
return &sunhv_console;
}
-static int __init hv_console_compatible(char *buf, int len)
-{
- while (len) {
- int this_len;
-
- if (!strcmp(buf, "qcn"))
- return 1;
-
- this_len = strlen(buf) + 1;
-
- buf += this_len;
- len -= this_len;
- }
-
- return 0;
-}
-
-static unsigned int __init get_interrupt(void)
-{
- const char *cons_str = "console";
- const char *compat_str = "compatible";
- int node = prom_getchild(sun4v_vdev_root);
- char buf[64];
- int err, len;
-
- node = prom_searchsiblings(node, cons_str);
- if (!node)
- return 0;
-
- len = prom_getproplen(node, compat_str);
- if (len == 0 || len == -1)
- return 0;
-
- err = prom_getproperty(node, compat_str, buf, 64);
- if (err == -1)
- return 0;
-
- if (!hv_console_compatible(buf, len))
- return 0;
-
- /* Ok, the this is the OBP node for the sun4v hypervisor
- * console device. Decode the interrupt.
- */
- return sun4v_vdev_device_interrupt(node);
-}
-
-static int __init sunhv_init(void)
+static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
{
struct uart_port *port;
- int ret;
+ int err;
- if (tlb_type != hypervisor)
+ if (op->irqs[0] == 0xffffffff)
return -ENODEV;
- port = kmalloc(sizeof(struct uart_port), GFP_KERNEL);
+ port = kzalloc(sizeof(struct uart_port), GFP_KERNEL);
if (unlikely(!port))
return -ENOMEM;
- memset(port, 0, sizeof(struct uart_port));
+ sunhv_port = port;
port->line = 0;
port->ops = &sunhv_pops;
port->type = PORT_SUNHV;
port->uartclk = ( 29491200 / 16 ); /* arbitrary */
- /* Set this just to make uart_configure_port() happy. */
port->membase = (unsigned char __iomem *) __pa(port);
- port->irq = get_interrupt();
- if (!port->irq) {
- kfree(port);
- return -ENODEV;
- }
+ port->irq = op->irqs[0];
+
+ port->dev = &op->dev;
sunhv_reg.minor = sunserial_current_minor;
sunhv_reg.nr = 1;
- ret = uart_register_driver(&sunhv_reg);
- if (ret < 0) {
- printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n",
- ret);
- kfree(port);
-
- return ret;
- }
+ err = uart_register_driver(&sunhv_reg);
+ if (err)
+ goto out_free_port;
sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
sunserial_current_minor += 1;
sunhv_reg.cons = SUNHV_CONSOLE();
- sunhv_port = port;
+ err = uart_add_one_port(&sunhv_reg, port);
+ if (err)
+ goto out_unregister_driver;
- ret = uart_add_one_port(&sunhv_reg, port);
- if (ret < 0) {
- printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret);
- sunserial_current_minor -= 1;
- uart_unregister_driver(&sunhv_reg);
- kfree(port);
- sunhv_port = NULL;
- return -ENODEV;
- }
+ err = request_irq(port->irq, sunhv_interrupt, 0, "hvcons", port);
+ if (err)
+ goto out_remove_port;
- if (request_irq(port->irq, sunhv_interrupt,
- SA_SHIRQ, "serial(sunhv)", port)) {
- printk(KERN_ERR "sunhv: Cannot register IRQ\n");
- uart_remove_one_port(&sunhv_reg, port);
- sunserial_current_minor -= 1;
- uart_unregister_driver(&sunhv_reg);
- kfree(port);
- sunhv_port = NULL;
- return -ENODEV;
- }
+ dev_set_drvdata(&op->dev, port);
return 0;
+
+out_remove_port:
+ uart_remove_one_port(&sunhv_reg, port);
+
+out_unregister_driver:
+ sunserial_current_minor -= 1;
+ uart_unregister_driver(&sunhv_reg);
+
+out_free_port:
+ kfree(port);
+ sunhv_port = NULL;
+ return err;
}
-static void __exit sunhv_exit(void)
+static int __devexit hv_remove(struct of_device *dev)
{
- struct uart_port *port = sunhv_port;
-
- BUG_ON(!port);
+ struct uart_port *port = dev_get_drvdata(&dev->dev);
free_irq(port->irq, port);
uart_remove_one_port(&sunhv_reg, port);
- sunserial_current_minor -= 1;
+ sunserial_current_minor -= 1;
uart_unregister_driver(&sunhv_reg);
- kfree(sunhv_port);
+ kfree(port);
sunhv_port = NULL;
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ return 0;
+}
+
+static struct of_device_id hv_match[] = {
+ {
+ .name = "console",
+ .compatible = "qcn",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hv_match);
+
+static struct of_platform_driver hv_driver = {
+ .name = "hv",
+ .match_table = hv_match,
+ .probe = hv_probe,
+ .remove = __devexit_p(hv_remove),
+};
+
+static int __init sunhv_init(void)
+{
+ if (tlb_type != hypervisor)
+ return -ENODEV;
+
+ return of_register_driver(&hv_driver, &of_bus_type);
+}
+
+static void __exit sunhv_exit(void)
+{
+ of_unregister_driver(&hv_driver);
}
module_init(sunhv_init);
module_exit(sunhv_exit);
MODULE_AUTHOR("David S. Miller");
-MODULE_DESCRIPTION("SUN4V Hypervisor console driver")
+MODULE_DESCRIPTION("SUN4V Hypervisor console driver");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index bfbe9dc90cc..cfe20f73043 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -1,7 +1,7 @@
/* sunsab.c: ASYNC Driver for the SIEMENS SAB82532 DUSCC.
*
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net)
*
* Rewrote buffer handling to use CIRC(Circular Buffer) macros.
* Maxim Krasnyanskiy <maxk@qualcomm.com>
@@ -12,10 +12,9 @@
* Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
*
* Ported to new 2.5.x UART layer.
- * David S. Miller <davem@redhat.com>
+ * David S. Miller <davem@davemloft.net>
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -37,8 +36,8 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -851,7 +850,6 @@ static struct uart_ops sunsab_pops = {
static struct uart_driver sunsab_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
@@ -888,6 +886,15 @@ static int sunsab_console_setup(struct console *con, char *options)
unsigned long flags;
unsigned int baud, quot;
+ /*
+ * The console framework calls us for each and every port
+ * registered. Defer the console setup until the requested
+ * port has been properly discovered. A bit of a hack,
+ * though...
+ */
+ if (up->port.type != PORT_SUNSAB)
+ return -1;
+
printk("Console: ttyS%d (SAB82532)\n",
(sunsab_reg.minor - 64) + con->index);
@@ -977,199 +984,189 @@ static inline struct console *SUNSAB_CONSOLE(void)
#define sunsab_console_init() do { } while (0)
#endif
-static void __init for_each_sab_edev(void (*callback)(struct linux_ebus_device *, void *), void *arg)
+static int __devinit sunsab_init_one(struct uart_sunsab_port *up,
+ struct of_device *op,
+ unsigned long offset,
+ int line)
{
- struct linux_ebus *ebus;
- struct linux_ebus_device *edev = NULL;
-
- for_each_ebus(ebus) {
- for_each_ebusdev(edev, ebus) {
- if (!strcmp(edev->prom_name, "se")) {
- callback(edev, arg);
- continue;
- } else if (!strcmp(edev->prom_name, "serial")) {
- char compat[32];
- int clen;
-
- /* On RIO this can be an SE, check it. We could
- * just check ebus->is_rio, but this is more portable.
- */
- clen = prom_getproperty(edev->prom_node, "compatible",
- compat, sizeof(compat));
- if (clen > 0) {
- if (strncmp(compat, "sab82532", 8) == 0) {
- callback(edev, arg);
- continue;
- }
- }
- }
- }
- }
-}
+ up->port.line = line;
+ up->port.dev = &op->dev;
+
+ up->port.mapbase = op->resource[0].start + offset;
+ up->port.membase = of_ioremap(&op->resource[0], offset,
+ sizeof(union sab82532_async_regs),
+ "sab");
+ if (!up->port.membase)
+ return -ENOMEM;
+ up->regs = (union sab82532_async_regs __iomem *) up->port.membase;
-static void __init sab_count_callback(struct linux_ebus_device *edev, void *arg)
-{
- int *count_p = arg;
+ up->port.irq = op->irqs[0];
- (*count_p)++;
-}
+ up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
+ up->port.iotype = UPIO_MEM;
-static void __init sab_attach_callback(struct linux_ebus_device *edev, void *arg)
-{
- int *instance_p = arg;
- struct uart_sunsab_port *up;
- unsigned long regs, offset;
- int i;
+ writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc);
- /* Note: ports are located in reverse order */
- regs = edev->resource[0].start;
- offset = sizeof(union sab82532_async_regs);
- for (i = 0; i < 2; i++) {
- up = &sunsab_ports[(*instance_p * 2) + 1 - i];
+ up->port.ops = &sunsab_pops;
+ up->port.type = PORT_SUNSAB;
+ up->port.uartclk = SAB_BASE_BAUD;
- memset(up, 0, sizeof(*up));
- up->regs = ioremap(regs + offset, sizeof(union sab82532_async_regs));
- up->port.irq = edev->irqs[0];
- up->port.fifosize = SAB82532_XMIT_FIFO_SIZE;
- up->port.mapbase = (unsigned long)up->regs;
- up->port.iotype = UPIO_MEM;
+ up->type = readb(&up->regs->r.vstr) & 0x0f;
+ writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr);
+ writeb(0xff, &up->regs->w.pim);
+ if ((up->port.line & 0x1) == 0) {
+ up->pvr_dsr_bit = (1 << 0);
+ up->pvr_dtr_bit = (1 << 1);
+ } else {
+ up->pvr_dsr_bit = (1 << 3);
+ up->pvr_dtr_bit = (1 << 2);
+ }
+ up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
+ writeb(up->cached_pvr, &up->regs->w.pvr);
+ up->cached_mode = readb(&up->regs->rw.mode);
+ up->cached_mode |= SAB82532_MODE_FRTS;
+ writeb(up->cached_mode, &up->regs->rw.mode);
+ up->cached_mode |= SAB82532_MODE_RTS;
+ writeb(up->cached_mode, &up->regs->rw.mode);
- writeb(SAB82532_IPC_IC_ACT_LOW, &up->regs->w.ipc);
+ up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
+ up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
- offset -= sizeof(union sab82532_async_regs);
+ if (!(up->port.line & 0x01)) {
+ int err;
+
+ err = request_irq(up->port.irq, sunsab_interrupt,
+ IRQF_SHARED, "sab", up);
+ if (err) {
+ of_iounmap(up->port.membase,
+ sizeof(union sab82532_async_regs));
+ return err;
+ }
}
-
- (*instance_p)++;
+
+ return 0;
}
-static int __init probe_for_sabs(void)
+static int __devinit sab_probe(struct of_device *op, const struct of_device_id *match)
{
- int this_sab = 0;
+ static int inst;
+ struct uart_sunsab_port *up;
+ int err;
+
+ up = &sunsab_ports[inst * 2];
+
+ err = sunsab_init_one(&up[0], op,
+ 0,
+ (inst * 2) + 0);
+ if (err)
+ return err;
+
+ err = sunsab_init_one(&up[1], op,
+ sizeof(union sab82532_async_regs),
+ (inst * 2) + 1);
+ if (err) {
+ of_iounmap(up[0].port.membase,
+ sizeof(union sab82532_async_regs));
+ free_irq(up[0].port.irq, &up[0]);
+ return err;
+ }
- /* Find device instances. */
- for_each_sab_edev(&sab_count_callback, &this_sab);
- if (!this_sab)
- return -ENODEV;
+ uart_add_one_port(&sunsab_reg, &up[0].port);
+ uart_add_one_port(&sunsab_reg, &up[1].port);
- /* Allocate tables. */
- sunsab_ports = kmalloc(sizeof(struct uart_sunsab_port) * this_sab * 2,
- GFP_KERNEL);
- if (!sunsab_ports)
- return -ENOMEM;
+ dev_set_drvdata(&op->dev, &up[0]);
- num_channels = this_sab * 2;
+ inst++;
- this_sab = 0;
- for_each_sab_edev(&sab_attach_callback, &this_sab);
return 0;
}
-static void __init sunsab_init_hw(void)
+static void __devexit sab_remove_one(struct uart_sunsab_port *up)
{
- int i;
-
- for (i = 0; i < num_channels; i++) {
- struct uart_sunsab_port *up = &sunsab_ports[i];
-
- up->port.line = i;
- up->port.ops = &sunsab_pops;
- up->port.type = PORT_SUNSAB;
- up->port.uartclk = SAB_BASE_BAUD;
-
- up->type = readb(&up->regs->r.vstr) & 0x0f;
- writeb(~((1 << 1) | (1 << 2) | (1 << 4)), &up->regs->w.pcr);
- writeb(0xff, &up->regs->w.pim);
- if (up->port.line == 0) {
- up->pvr_dsr_bit = (1 << 0);
- up->pvr_dtr_bit = (1 << 1);
- } else {
- up->pvr_dsr_bit = (1 << 3);
- up->pvr_dtr_bit = (1 << 2);
- }
- up->cached_pvr = (1 << 1) | (1 << 2) | (1 << 4);
- writeb(up->cached_pvr, &up->regs->w.pvr);
- up->cached_mode = readb(&up->regs->rw.mode);
- up->cached_mode |= SAB82532_MODE_FRTS;
- writeb(up->cached_mode, &up->regs->rw.mode);
- up->cached_mode |= SAB82532_MODE_RTS;
- writeb(up->cached_mode, &up->regs->rw.mode);
-
- up->tec_timeout = SAB82532_MAX_TEC_TIMEOUT;
- up->cec_timeout = SAB82532_MAX_CEC_TIMEOUT;
-
- if (!(up->port.line & 0x01)) {
- if (request_irq(up->port.irq, sunsab_interrupt,
- SA_SHIRQ, "serial(sab82532)", up)) {
- printk("sunsab%d: can't get IRQ %x\n",
- i, up->port.irq);
- continue;
- }
- }
- }
+ uart_remove_one_port(&sunsab_reg, &up->port);
+ if (!(up->port.line & 1))
+ free_irq(up->port.irq, up);
+ of_iounmap(up->port.membase,
+ sizeof(union sab82532_async_regs));
}
-static int __init sunsab_init(void)
+static int __devexit sab_remove(struct of_device *op)
{
- int ret = probe_for_sabs();
- int i;
+ struct uart_sunsab_port *up = dev_get_drvdata(&op->dev);
- if (ret < 0)
- return ret;
+ sab_remove_one(&up[0]);
+ sab_remove_one(&up[1]);
- sunsab_init_hw();
+ dev_set_drvdata(&op->dev, NULL);
- sunsab_reg.minor = sunserial_current_minor;
- sunsab_reg.nr = num_channels;
-
- ret = uart_register_driver(&sunsab_reg);
- if (ret < 0) {
- int i;
+ return 0;
+}
- for (i = 0; i < num_channels; i++) {
- struct uart_sunsab_port *up = &sunsab_ports[i];
+static struct of_device_id sab_match[] = {
+ {
+ .name = "se",
+ },
+ {
+ .name = "serial",
+ .compatible = "sab82532",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sab_match);
- if (!(up->port.line & 0x01))
- free_irq(up->port.irq, up);
- iounmap(up->regs);
- }
- kfree(sunsab_ports);
- sunsab_ports = NULL;
+static struct of_platform_driver sab_driver = {
+ .name = "sab",
+ .match_table = sab_match,
+ .probe = sab_probe,
+ .remove = __devexit_p(sab_remove),
+};
- return ret;
+static int __init sunsab_init(void)
+{
+ struct device_node *dp;
+ int err;
+
+ num_channels = 0;
+ for_each_node_by_name(dp, "se")
+ num_channels += 2;
+ for_each_node_by_name(dp, "serial") {
+ if (of_device_is_compatible(dp, "sab82532"))
+ num_channels += 2;
}
- sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
+ if (num_channels) {
+ sunsab_ports = kzalloc(sizeof(struct uart_sunsab_port) *
+ num_channels, GFP_KERNEL);
+ if (!sunsab_ports)
+ return -ENOMEM;
- sunsab_reg.cons = SUNSAB_CONSOLE();
+ sunsab_reg.minor = sunserial_current_minor;
+ sunsab_reg.nr = num_channels;
- sunserial_current_minor += num_channels;
-
- for (i = 0; i < num_channels; i++) {
- struct uart_sunsab_port *up = &sunsab_ports[i];
+ err = uart_register_driver(&sunsab_reg);
+ if (err) {
+ kfree(sunsab_ports);
+ sunsab_ports = NULL;
+
+ return err;
+ }
- uart_add_one_port(&sunsab_reg, &up->port);
+ sunsab_reg.tty_driver->name_base = sunsab_reg.minor - 64;
+ sunsab_reg.cons = SUNSAB_CONSOLE();
+ sunserial_current_minor += num_channels;
}
- return 0;
+ return of_register_driver(&sab_driver, &of_bus_type);
}
static void __exit sunsab_exit(void)
{
- int i;
-
- for (i = 0; i < num_channels; i++) {
- struct uart_sunsab_port *up = &sunsab_ports[i];
-
- uart_remove_one_port(&sunsab_reg, &up->port);
-
- if (!(up->port.line & 0x01))
- free_irq(up->port.irq, up);
- iounmap(up->regs);
+ of_unregister_driver(&sab_driver);
+ if (num_channels) {
+ sunserial_current_minor -= num_channels;
+ uart_unregister_driver(&sunsab_reg);
}
- sunserial_current_minor -= num_channels;
- uart_unregister_driver(&sunsab_reg);
-
kfree(sunsab_ports);
sunsab_ports = NULL;
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index 4cdb610cdd3..d3a5aeee73a 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -12,10 +12,9 @@
* Theodore Ts'o <tytso@mit.edu>, 2001-Oct-12
*
* Converted to new 2.5.x UART layer.
- * David S. Miller (davem@redhat.com), 2002-Jul-29
+ * David S. Miller (davem@davemloft.net), 2002-Jul-29
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -40,11 +39,8 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/oplib.h>
-#include <asm/ebus.h>
-#ifdef CONFIG_SPARC64
-#include <asm/isa.h>
-#endif
+#include <asm/prom.h>
+#include <asm/of_device.h>
#if defined(CONFIG_SERIAL_SUNSU_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -94,10 +90,10 @@ struct uart_sunsu_port {
/* Probing information. */
enum su_type su_type;
unsigned int type_probed; /* XXX Stupid */
- int port_node;
+ unsigned long reg_size;
#ifdef CONFIG_SERIO
- struct serio *serio;
+ struct serio serio;
int serio_open;
#endif
};
@@ -509,7 +505,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
/* Stop-A is handled by drivers/char/keyboard.c now. */
if (up->su_type == SU_PORT_KBD) {
#ifdef CONFIG_SERIO
- serio_interrupt(up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0, regs);
#endif
} else if (up->su_type == SU_PORT_MS) {
int ret = suncore_mouse_baud_detection(ch, is_break);
@@ -523,7 +519,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
case 0:
#ifdef CONFIG_SERIO
- serio_interrupt(up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0, regs);
#endif
break;
};
@@ -671,10 +667,10 @@ static int sunsu_startup(struct uart_port *port)
if (up->su_type != SU_PORT_PORT) {
retval = request_irq(up->port.irq, sunsu_kbd_ms_interrupt,
- SA_SHIRQ, su_typev[up->su_type], up);
+ IRQF_SHARED, su_typev[up->su_type], up);
} else {
retval = request_irq(up->port.irq, sunsu_serial_interrupt,
- SA_SHIRQ, su_typev[up->su_type], up);
+ IRQF_SHARED, su_typev[up->su_type], up);
}
if (retval) {
printk("su: Cannot register IRQ %d\n", up->port.irq);
@@ -1031,99 +1027,14 @@ static void sunsu_autoconfig(struct uart_sunsu_port *up)
{
unsigned char status1, status2, scratch, scratch2, scratch3;
unsigned char save_lcr, save_mcr;
- struct linux_ebus_device *dev = NULL;
- struct linux_ebus *ebus;
-#ifdef CONFIG_SPARC64
- struct sparc_isa_bridge *isa_br;
- struct sparc_isa_device *isa_dev;
-#endif
-#ifndef CONFIG_SPARC64
- struct linux_prom_registers reg0;
-#endif
unsigned long flags;
- if (!up->port_node || !up->su_type)
+ if (up->su_type == SU_PORT_NONE)
return;
up->type_probed = PORT_UNKNOWN;
up->port.iotype = UPIO_MEM;
- /*
- * First we look for Ebus-bases su's
- */
- for_each_ebus(ebus) {
- for_each_ebusdev(dev, ebus) {
- if (dev->prom_node == up->port_node) {
- /*
- * The EBus is broken on sparc; it delivers
- * virtual addresses in resources. Oh well...
- * This is correct on sparc64, though.
- */
- up->port.membase = (char *) dev->resource[0].start;
- /*
- * This is correct on both architectures.
- */
- up->port.mapbase = dev->resource[0].start;
- up->port.irq = dev->irqs[0];
- goto ebus_done;
- }
- }
- }
-
-#ifdef CONFIG_SPARC64
- for_each_isa(isa_br) {
- for_each_isadev(isa_dev, isa_br) {
- if (isa_dev->prom_node == up->port_node) {
- /* Same on sparc64. Cool architecure... */
- up->port.membase = (char *) isa_dev->resource.start;
- up->port.mapbase = isa_dev->resource.start;
- up->port.irq = isa_dev->irq;
- goto ebus_done;
- }
- }
- }
-#endif
-
-#ifdef CONFIG_SPARC64
- /*
- * Not on Ebus, bailing.
- */
- return;
-#else
- /*
- * Not on Ebus, must be OBIO.
- */
- if (prom_getproperty(up->port_node, "reg",
- (char *)&reg0, sizeof(reg0)) == -1) {
- prom_printf("sunsu: no \"reg\" property\n");
- return;
- }
- prom_apply_obio_ranges(&reg0, 1);
- if (reg0.which_io != 0) { /* Just in case... */
- prom_printf("sunsu: bus number nonzero: 0x%x:%x\n",
- reg0.which_io, reg0.phys_addr);
- return;
- }
- up->port.mapbase = reg0.phys_addr;
- if ((up->port.membase = ioremap(reg0.phys_addr, reg0.reg_size)) == 0) {
- prom_printf("sunsu: Cannot map registers.\n");
- return;
- }
-
- /*
- * 0x20 is sun4m thing, Dave Redman heritage.
- * See arch/sparc/kernel/irq.c.
- */
-#define IRQ_4M(n) ((n)|0x20)
-
- /*
- * There is no intr property on MrCoffee, so hardwire it.
- */
- up->port.irq = IRQ_4M(13);
-#endif
-
-ebus_done:
-
spin_lock_irqsave(&up->port.lock, flags);
if (!(up->port.flags & UPF_BUGGY_UART)) {
@@ -1265,23 +1176,17 @@ out:
static struct uart_driver sunsu_reg = {
.owner = THIS_MODULE,
.driver_name = "serial",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
-static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel)
+static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up)
{
int quot, baud;
#ifdef CONFIG_SERIO
struct serio *serio;
#endif
- spin_lock_init(&up->port.lock);
- up->port.line = channel;
- up->port.type = PORT_UNKNOWN;
- up->port.uartclk = (SU_BASE_BAUD * 16);
-
if (up->su_type == SU_PORT_KBD) {
up->cflag = B1200 | CS8 | CLOCAL | CREAD;
baud = 1200;
@@ -1293,41 +1198,36 @@ static int __init sunsu_kbd_ms_init(struct uart_sunsu_port *up, int channel)
sunsu_autoconfig(up);
if (up->port.type == PORT_UNKNOWN)
- return -1;
+ return -ENODEV;
- printk(KERN_INFO "su%d at 0x%p (irq = %d) is a %s\n",
- channel,
- up->port.membase, up->port.irq,
- sunsu_type(&up->port));
+ printk("%s: %s port at %lx, irq %u\n",
+ to_of_device(up->port.dev)->node->full_name,
+ (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse",
+ up->port.mapbase, up->port.irq);
#ifdef CONFIG_SERIO
- up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
- if (serio) {
- memset(serio, 0, sizeof(*serio));
-
- serio->port_data = up;
-
- serio->id.type = SERIO_RS232;
- if (up->su_type == SU_PORT_KBD) {
- serio->id.proto = SERIO_SUNKBD;
- strlcpy(serio->name, "sukbd", sizeof(serio->name));
- } else {
- serio->id.proto = SERIO_SUN;
- serio->id.extra = 1;
- strlcpy(serio->name, "sums", sizeof(serio->name));
- }
- strlcpy(serio->phys, (channel == 0 ? "su/serio0" : "su/serio1"),
- sizeof(serio->phys));
+ serio = &up->serio;
+ serio->port_data = up;
- serio->write = sunsu_serio_write;
- serio->open = sunsu_serio_open;
- serio->close = sunsu_serio_close;
-
- serio_register_port(serio);
+ serio->id.type = SERIO_RS232;
+ if (up->su_type == SU_PORT_KBD) {
+ serio->id.proto = SERIO_SUNKBD;
+ strlcpy(serio->name, "sukbd", sizeof(serio->name));
} else {
- printk(KERN_WARNING "su%d: not enough memory for serio port\n",
- channel);
+ serio->id.proto = SERIO_SUN;
+ serio->id.extra = 1;
+ strlcpy(serio->name, "sums", sizeof(serio->name));
}
+ strlcpy(serio->phys,
+ (!(up->port.line & 1) ? "su/serio0" : "su/serio1"),
+ sizeof(serio->phys));
+
+ serio->write = sunsu_serio_write;
+ serio->open = sunsu_serio_open;
+ serio->close = sunsu_serio_close;
+ serio->dev.parent = up->port.dev;
+
+ serio_register_port(serio);
#endif
sunsu_change_speed(&up->port, up->cflag, 0, quot);
@@ -1459,22 +1359,20 @@ static struct console sunsu_cons = {
* Register console.
*/
-static inline struct console *SUNSU_CONSOLE(void)
+static inline struct console *SUNSU_CONSOLE(int num_uart)
{
int i;
if (con_is_present())
return NULL;
- for (i = 0; i < UART_NR; i++) {
+ for (i = 0; i < num_uart; i++) {
int this_minor = sunsu_reg.minor + i;
if ((this_minor - 64) == (serial_console - 1))
break;
}
- if (i == UART_NR)
- return NULL;
- if (sunsu_ports[i].port_node == 0)
+ if (i == num_uart)
return NULL;
sunsu_cons.index = i;
@@ -1482,252 +1380,203 @@ static inline struct console *SUNSU_CONSOLE(void)
return &sunsu_cons;
}
#else
-#define SUNSU_CONSOLE() (NULL)
+#define SUNSU_CONSOLE(num_uart) (NULL)
#define sunsu_serial_console_init() do { } while (0)
#endif
-static int __init sunsu_serial_init(void)
+static enum su_type __devinit su_get_type(struct device_node *dp)
{
- int instance, ret, i;
+ struct device_node *ap = of_find_node_by_path("/aliases");
- /* How many instances do we need? */
- instance = 0;
- for (i = 0; i < UART_NR; i++) {
- struct uart_sunsu_port *up = &sunsu_ports[i];
+ if (ap) {
+ char *keyb = of_get_property(ap, "keyboard", NULL);
+ char *ms = of_get_property(ap, "mouse", NULL);
- if (up->su_type == SU_PORT_MS ||
- up->su_type == SU_PORT_KBD)
- continue;
-
- spin_lock_init(&up->port.lock);
- up->port.flags |= UPF_BOOT_AUTOCONF;
- up->port.type = PORT_UNKNOWN;
- up->port.uartclk = (SU_BASE_BAUD * 16);
+ if (keyb) {
+ if (dp == of_find_node_by_path(keyb))
+ return SU_PORT_KBD;
+ }
+ if (ms) {
+ if (dp == of_find_node_by_path(ms))
+ return SU_PORT_MS;
+ }
+ }
- sunsu_autoconfig(up);
- if (up->port.type == PORT_UNKNOWN)
- continue;
+ return SU_PORT_PORT;
+}
- up->port.line = instance++;
- up->port.ops = &sunsu_pops;
+static int __devinit su_probe(struct of_device *op, const struct of_device_id *match)
+{
+ static int inst;
+ struct device_node *dp = op->node;
+ struct uart_sunsu_port *up;
+ struct resource *rp;
+ enum su_type type;
+ int err;
+
+ type = su_get_type(dp);
+ if (type == SU_PORT_PORT) {
+ if (inst >= UART_NR)
+ return -EINVAL;
+ up = &sunsu_ports[inst];
+ } else {
+ up = kzalloc(sizeof(*up), GFP_KERNEL);
+ if (!up)
+ return -ENOMEM;
}
- sunsu_reg.minor = sunserial_current_minor;
+ up->port.line = inst;
- sunsu_reg.nr = instance;
-
- ret = uart_register_driver(&sunsu_reg);
- if (ret < 0)
- return ret;
+ spin_lock_init(&up->port.lock);
- sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
+ up->su_type = type;
- sunserial_current_minor += instance;
+ rp = &op->resource[0];
+ up->port.mapbase = rp->start;
+ up->reg_size = (rp->end - rp->start) + 1;
+ up->port.membase = of_ioremap(rp, 0, up->reg_size, "su");
+ if (!up->port.membase) {
+ if (type != SU_PORT_PORT)
+ kfree(up);
+ return -ENOMEM;
+ }
- sunsu_reg.cons = SUNSU_CONSOLE();
+ up->port.irq = op->irqs[0];
- for (i = 0; i < UART_NR; i++) {
- struct uart_sunsu_port *up = &sunsu_ports[i];
+ up->port.dev = &op->dev;
- /* Do not register Keyboard/Mouse lines with UART
- * layer.
- */
- if (up->su_type == SU_PORT_MS ||
- up->su_type == SU_PORT_KBD)
- continue;
+ up->port.type = PORT_UNKNOWN;
+ up->port.uartclk = (SU_BASE_BAUD * 16);
- if (up->port.type == PORT_UNKNOWN)
- continue;
+ err = 0;
+ if (up->su_type == SU_PORT_KBD || up->su_type == SU_PORT_MS) {
+ err = sunsu_kbd_ms_init(up);
+ if (err) {
+ kfree(up);
+ goto out_unmap;
+ }
+ dev_set_drvdata(&op->dev, up);
- uart_add_one_port(&sunsu_reg, &up->port);
+ return 0;
}
- return 0;
-}
+ up->port.flags |= UPF_BOOT_AUTOCONF;
-static int su_node_ok(int node, char *name, int namelen)
-{
- if (strncmp(name, "su", namelen) == 0 ||
- strncmp(name, "su_pnp", namelen) == 0)
- return 1;
-
- if (strncmp(name, "serial", namelen) == 0) {
- char compat[32];
- int clen;
-
- /* Is it _really_ a 'su' device? */
- clen = prom_getproperty(node, "compatible", compat, sizeof(compat));
- if (clen > 0) {
- if (strncmp(compat, "sab82532", 8) == 0) {
- /* Nope, Siemens serial, not for us. */
- return 0;
- }
- }
- return 1;
- }
+ sunsu_autoconfig(up);
- return 0;
-}
+ err = -ENODEV;
+ if (up->port.type == PORT_UNKNOWN)
+ goto out_unmap;
-#define SU_PROPSIZE 128
+ up->port.ops = &sunsu_pops;
-/*
- * Scan status structure.
- * "prop" is a local variable but it eats stack to keep it in each
- * stack frame of a recursive procedure.
- */
-struct su_probe_scan {
- int msnode, kbnode; /* PROM nodes for mouse and keyboard */
- int msx, kbx; /* minors for mouse and keyboard */
- int devices; /* scan index */
- char prop[SU_PROPSIZE];
-};
+ err = uart_add_one_port(&sunsu_reg, &up->port);
+ if (err)
+ goto out_unmap;
-/*
- * We have several platforms which present 'su' in different parts
- * of the device tree. 'su' may be found under obio, ebus, isa and pci.
- * We walk over the tree and find them wherever PROM hides them.
- */
-static void __init su_probe_any(struct su_probe_scan *t, int sunode)
-{
- struct uart_sunsu_port *up;
- int len;
+ dev_set_drvdata(&op->dev, up);
- if (t->devices >= UART_NR)
- return;
+ inst++;
- for (; sunode != 0; sunode = prom_getsibling(sunode)) {
- len = prom_getproperty(sunode, "name", t->prop, SU_PROPSIZE);
- if (len <= 1)
- continue; /* Broken PROM node */
-
- if (su_node_ok(sunode, t->prop, len)) {
- up = &sunsu_ports[t->devices];
- if (t->kbnode != 0 && sunode == t->kbnode) {
- t->kbx = t->devices;
- up->su_type = SU_PORT_KBD;
- } else if (t->msnode != 0 && sunode == t->msnode) {
- t->msx = t->devices;
- up->su_type = SU_PORT_MS;
- } else {
-#ifdef CONFIG_SPARC64
- /*
- * Do not attempt to use the truncated
- * keyboard/mouse ports as serial ports
- * on Ultras with PC keyboard attached.
- */
- if (prom_getbool(sunode, "mouse"))
- continue;
- if (prom_getbool(sunode, "keyboard"))
- continue;
-#endif
- up->su_type = SU_PORT_PORT;
- }
- up->port_node = sunode;
- ++t->devices;
- } else {
- su_probe_any(t, prom_getchild(sunode));
- }
- }
+ return 0;
+
+out_unmap:
+ of_iounmap(up->port.membase, up->reg_size);
+ return err;
}
-static int __init sunsu_probe(void)
+static int __devexit su_remove(struct of_device *dev)
{
- int node;
- int len;
- struct su_probe_scan scan;
+ struct uart_sunsu_port *up = dev_get_drvdata(&dev->dev);;
- /*
- * First, we scan the tree.
- */
- scan.devices = 0;
- scan.msx = -1;
- scan.kbx = -1;
- scan.kbnode = 0;
- scan.msnode = 0;
+ if (up->su_type == SU_PORT_MS ||
+ up->su_type == SU_PORT_KBD) {
+#ifdef CONFIG_SERIO
+ serio_unregister_port(&up->serio);
+#endif
+ kfree(up);
+ } else if (up->port.type != PORT_UNKNOWN) {
+ uart_remove_one_port(&sunsu_reg, &up->port);
+ }
- /*
- * Get the nodes for keyboard and mouse from 'aliases'...
- */
- node = prom_getchild(prom_root_node);
- node = prom_searchsiblings(node, "aliases");
- if (node != 0) {
- len = prom_getproperty(node, "keyboard", scan.prop, SU_PROPSIZE);
- if (len > 0) {
- scan.prop[len] = 0;
- scan.kbnode = prom_finddevice(scan.prop);
- }
+ dev_set_drvdata(&dev->dev, NULL);
- len = prom_getproperty(node, "mouse", scan.prop, SU_PROPSIZE);
- if (len > 0) {
- scan.prop[len] = 0;
- scan.msnode = prom_finddevice(scan.prop);
- }
- }
+ return 0;
+}
- su_probe_any(&scan, prom_getchild(prom_root_node));
+static struct of_device_id su_match[] = {
+ {
+ .name = "su",
+ },
+ {
+ .name = "su_pnp",
+ },
+ {
+ .name = "serial",
+ .compatible = "su",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, su_match);
- /*
- * Second, we process the special case of keyboard and mouse.
- *
- * Currently if we got keyboard and mouse hooked to "su" ports
- * we do not use any possible remaining "su" as a serial port.
- * Thus, we ignore values of .msx and .kbx, then compact ports.
- */
- if (scan.msx != -1 && scan.kbx != -1) {
- sunsu_ports[0].su_type = SU_PORT_MS;
- sunsu_ports[0].port_node = scan.msnode;
- sunsu_kbd_ms_init(&sunsu_ports[0], 0);
+static struct of_platform_driver su_driver = {
+ .name = "su",
+ .match_table = su_match,
+ .probe = su_probe,
+ .remove = __devexit_p(su_remove),
+};
- sunsu_ports[1].su_type = SU_PORT_KBD;
- sunsu_ports[1].port_node = scan.kbnode;
- sunsu_kbd_ms_init(&sunsu_ports[1], 1);
+static int num_uart;
- return 0;
- }
+static int __init sunsu_init(void)
+{
+ struct device_node *dp;
+ int err;
- if (scan.msx != -1 || scan.kbx != -1) {
- printk("sunsu_probe: cannot match keyboard and mouse, confused\n");
- return -ENODEV;
+ num_uart = 0;
+ for_each_node_by_name(dp, "su") {
+ if (su_get_type(dp) == SU_PORT_PORT)
+ num_uart++;
+ }
+ for_each_node_by_name(dp, "su_pnp") {
+ if (su_get_type(dp) == SU_PORT_PORT)
+ num_uart++;
+ }
+ for_each_node_by_name(dp, "serial") {
+ if (of_device_is_compatible(dp, "su")) {
+ if (su_get_type(dp) == SU_PORT_PORT)
+ num_uart++;
+ }
}
- if (scan.devices == 0)
- return -ENODEV;
+ if (num_uart) {
+ sunsu_reg.minor = sunserial_current_minor;
+ sunsu_reg.nr = num_uart;
+ err = uart_register_driver(&sunsu_reg);
+ if (err)
+ return err;
+ sunsu_reg.tty_driver->name_base = sunsu_reg.minor - 64;
+ sunserial_current_minor += num_uart;
+ sunsu_reg.cons = SUNSU_CONSOLE(num_uart);
+ }
- /*
- * Console must be initiated after the generic initialization.
- */
- sunsu_serial_init();
+ err = of_register_driver(&su_driver, &of_bus_type);
+ if (err && num_uart)
+ uart_unregister_driver(&sunsu_reg);
- return 0;
+ return err;
}
static void __exit sunsu_exit(void)
{
- int i, saw_uart;
-
- saw_uart = 0;
- for (i = 0; i < UART_NR; i++) {
- struct uart_sunsu_port *up = &sunsu_ports[i];
-
- if (up->su_type == SU_PORT_MS ||
- up->su_type == SU_PORT_KBD) {
-#ifdef CONFIG_SERIO
- if (up->serio) {
- serio_unregister_port(up->serio);
- up->serio = NULL;
- }
-#endif
- } else if (up->port.type != PORT_UNKNOWN) {
- uart_remove_one_port(&sunsu_reg, &up->port);
- saw_uart++;
- }
- }
-
- if (saw_uart)
+ if (num_uart)
uart_unregister_driver(&sunsu_reg);
}
-module_init(sunsu_probe);
+module_init(sunsu_init);
module_exit(sunsu_exit);
+
+MODULE_AUTHOR("Eddie C. Dost, Peter Zaitcev, and David S. Miller");
+MODULE_DESCRIPTION("Sun SU serial port driver");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 5b6569728a9..0da3ebfff82 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -1,5 +1,4 @@
-/*
- * sunzilog.c
+/* sunzilog.c: Zilog serial driver for Sparc systems.
*
* Driver for Zilog serial chips found on Sun workstations and
* servers. This driver could actually be made more generic.
@@ -10,10 +9,9 @@
* C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
* work there.
*
- * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -38,10 +36,8 @@
#include <asm/io.h>
#include <asm/irq.h>
-#ifdef CONFIG_SPARC64
-#include <asm/fhc.h>
-#endif
-#include <asm/sbus.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#if defined(CONFIG_SERIAL_SUNZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -65,16 +61,13 @@
#define ZSDELAY()
#define ZSDELAY_LONG()
#define ZS_WSYNC(__channel) \
- sbus_readb(&((__channel)->control))
+ readb(&((__channel)->control))
#endif
static int num_sunzilog;
#define NUM_SUNZILOG num_sunzilog
#define NUM_CHANNELS (NUM_SUNZILOG * 2)
-#define KEYBOARD_LINE 0x2
-#define MOUSE_LINE 0x3
-
#define ZS_CLOCK 4915200 /* Zilog input clock rate. */
#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
@@ -107,7 +100,7 @@ struct uart_sunzilog_port {
unsigned char prev_status;
#ifdef CONFIG_SERIO
- struct serio *serio;
+ struct serio serio;
int serio_open;
#endif
};
@@ -138,9 +131,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
{
unsigned char retval;
- sbus_writeb(reg, &channel->control);
+ writeb(reg, &channel->control);
ZSDELAY();
- retval = sbus_readb(&channel->control);
+ retval = readb(&channel->control);
ZSDELAY();
return retval;
@@ -149,9 +142,9 @@ static unsigned char read_zsreg(struct zilog_channel __iomem *channel,
static void write_zsreg(struct zilog_channel __iomem *channel,
unsigned char reg, unsigned char value)
{
- sbus_writeb(reg, &channel->control);
+ writeb(reg, &channel->control);
ZSDELAY();
- sbus_writeb(value, &channel->control);
+ writeb(value, &channel->control);
ZSDELAY();
}
@@ -162,17 +155,17 @@ static void sunzilog_clear_fifo(struct zilog_channel __iomem *channel)
for (i = 0; i < 32; i++) {
unsigned char regval;
- regval = sbus_readb(&channel->control);
+ regval = readb(&channel->control);
ZSDELAY();
if (regval & Rx_CH_AV)
break;
regval = read_zsreg(channel, R1);
- sbus_readb(&channel->data);
+ readb(&channel->data);
ZSDELAY();
if (regval & (PAR_ERR | Rx_OVR | CRC_ERR)) {
- sbus_writeb(ERR_RES, &channel->control);
+ writeb(ERR_RES, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
}
@@ -194,7 +187,7 @@ static void __load_zsregs(struct zilog_channel __iomem *channel, unsigned char *
udelay(100);
}
- sbus_writeb(ERR_RES, &channel->control);
+ writeb(ERR_RES, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
@@ -291,7 +284,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
/* Stop-A is handled by drivers/char/keyboard.c now. */
#ifdef CONFIG_SERIO
if (up->serio_open)
- serio_interrupt(up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0, regs);
#endif
} else if (ZS_IS_MOUSE(up)) {
int ret = suncore_mouse_baud_detection(ch, is_break);
@@ -306,7 +299,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
case 0:
#ifdef CONFIG_SERIO
if (up->serio_open)
- serio_interrupt(up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0, regs);
#endif
break;
};
@@ -330,12 +323,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
r1 = read_zsreg(channel, R1);
if (r1 & (PAR_ERR | Rx_OVR | CRC_ERR)) {
- sbus_writeb(ERR_RES, &channel->control);
+ writeb(ERR_RES, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
}
- ch = sbus_readb(&channel->control);
+ ch = readb(&channel->control);
ZSDELAY();
/* This funny hack depends upon BRK_ABRT not interfering
@@ -347,7 +340,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
if (!(ch & Rx_CH_AV))
break;
- ch = sbus_readb(&channel->data);
+ ch = readb(&channel->data);
ZSDELAY();
ch &= up->parity_mask;
@@ -406,10 +399,10 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
{
unsigned char status;
- status = sbus_readb(&channel->control);
+ status = readb(&channel->control);
ZSDELAY();
- sbus_writeb(RES_EXT_INT, &channel->control);
+ writeb(RES_EXT_INT, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
@@ -421,7 +414,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
* confusing the PROM.
*/
while (1) {
- status = sbus_readb(&channel->control);
+ status = readb(&channel->control);
ZSDELAY();
if (!(status & BRK_ABRT))
break;
@@ -458,7 +451,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
struct circ_buf *xmit;
if (ZS_IS_CONS(up)) {
- unsigned char status = sbus_readb(&channel->control);
+ unsigned char status = readb(&channel->control);
ZSDELAY();
/* TX still busy? Just wait for the next TX done interrupt.
@@ -487,7 +480,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
if (up->port.x_char) {
up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
- sbus_writeb(up->port.x_char, &channel->data);
+ writeb(up->port.x_char, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
@@ -506,7 +499,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
goto ack_tx_int;
up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
- sbus_writeb(xmit->buf[xmit->tail], &channel->data);
+ writeb(xmit->buf[xmit->tail], &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
@@ -519,7 +512,7 @@ static void sunzilog_transmit_chars(struct uart_sunzilog_port *up,
return;
ack_tx_int:
- sbus_writeb(RES_Tx_P, &channel->control);
+ writeb(RES_Tx_P, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
}
@@ -540,7 +533,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
/* Channel A */
tty = NULL;
if (r3 & (CHAEXT | CHATxIP | CHARxIP)) {
- sbus_writeb(RES_H_IUS, &channel->control);
+ writeb(RES_H_IUS, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
@@ -563,7 +556,7 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
spin_lock(&up->port.lock);
tty = NULL;
if (r3 & (CHBEXT | CHBTxIP | CHBRxIP)) {
- sbus_writeb(RES_H_IUS, &channel->control);
+ writeb(RES_H_IUS, &channel->control);
ZSDELAY();
ZS_WSYNC(channel);
@@ -594,7 +587,7 @@ static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *p
unsigned char status;
channel = ZILOG_CHANNEL_FROM_PORT(port);
- status = sbus_readb(&channel->control);
+ status = readb(&channel->control);
ZSDELAY();
return status;
@@ -682,7 +675,7 @@ static void sunzilog_start_tx(struct uart_port *port)
up->flags |= SUNZILOG_FLAG_TX_ACTIVE;
up->flags &= ~SUNZILOG_FLAG_TX_STOPPED;
- status = sbus_readb(&channel->control);
+ status = readb(&channel->control);
ZSDELAY();
/* TX busy? Just wait for the TX done interrupt. */
@@ -693,7 +686,7 @@ static void sunzilog_start_tx(struct uart_port *port)
* IRQ sending engine.
*/
if (port->x_char) {
- sbus_writeb(port->x_char, &channel->data);
+ writeb(port->x_char, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
@@ -702,7 +695,7 @@ static void sunzilog_start_tx(struct uart_port *port)
} else {
struct circ_buf *xmit = &port->info->xmit;
- sbus_writeb(xmit->buf[xmit->tail], &channel->data);
+ writeb(xmit->buf[xmit->tail], &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
@@ -779,7 +772,7 @@ static void __sunzilog_startup(struct uart_sunzilog_port *up)
struct zilog_channel __iomem *channel;
channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
- up->prev_status = sbus_readb(&channel->control);
+ up->prev_status = readb(&channel->control);
/* Enable receiver and transmitter. */
up->curregs[R3] |= RxENAB;
@@ -963,7 +956,7 @@ sunzilog_set_termios(struct uart_port *port, struct termios *termios,
static const char *sunzilog_type(struct uart_port *port)
{
- return "SunZilog";
+ return "zs";
}
/* We do not request/release mappings of the registers here, this
@@ -1012,242 +1005,55 @@ static struct uart_sunzilog_port *sunzilog_port_table;
static struct zilog_layout __iomem **sunzilog_chip_regs;
static struct uart_sunzilog_port *sunzilog_irq_chain;
-static int zilog_irq = -1;
static struct uart_driver sunzilog_reg = {
.owner = THIS_MODULE,
.driver_name = "ttyS",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
};
-static void * __init alloc_one_table(unsigned long size)
-{
- void *ret;
-
- ret = kmalloc(size, GFP_KERNEL);
- if (ret != NULL)
- memset(ret, 0, size);
-
- return ret;
-}
-
-static void __init sunzilog_alloc_tables(void)
-{
- sunzilog_port_table =
- alloc_one_table(NUM_CHANNELS * sizeof(struct uart_sunzilog_port));
- sunzilog_chip_regs =
- alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *));
-
- if (sunzilog_port_table == NULL || sunzilog_chip_regs == NULL) {
- prom_printf("SunZilog: Cannot allocate tables.\n");
- prom_halt();
- }
-}
-
-#ifdef CONFIG_SPARC64
-
-/* We used to attempt to use the address property of the Zilog device node
- * but that totally is not necessary on sparc64.
- */
-static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
+static int __init sunzilog_alloc_tables(void)
{
- void __iomem *mapped_addr;
- unsigned int sun4u_ino;
- struct sbus_bus *sbus = NULL;
- struct sbus_dev *sdev = NULL;
- int err;
-
- if (central_bus == NULL) {
- for_each_sbus(sbus) {
- for_each_sbusdev(sdev, sbus) {
- if (sdev->prom_node == zsnode)
- goto found;
- }
- }
- }
- found:
- if (sdev == NULL && central_bus == NULL) {
- prom_printf("SunZilog: sdev&&central == NULL for "
- "Zilog %d in get_zs_sun4u.\n", chip);
- prom_halt();
- }
- if (central_bus == NULL) {
- mapped_addr =
- sbus_ioremap(&sdev->resource[0], 0,
- PAGE_SIZE,
- "Zilog Registers");
- } else {
- struct linux_prom_registers zsregs[1];
-
- err = prom_getproperty(zsnode, "reg",
- (char *) &zsregs[0],
- sizeof(zsregs));
- if (err == -1) {
- prom_printf("SunZilog: Cannot map "
- "Zilog %d regs on "
- "central bus.\n", chip);
- prom_halt();
- }
- apply_fhc_ranges(central_bus->child,
- &zsregs[0], 1);
- apply_central_ranges(central_bus, &zsregs[0], 1);
- mapped_addr = (void __iomem *)
- ((((u64)zsregs[0].which_io)<<32UL) |
- ((u64)zsregs[0].phys_addr));
- }
-
- if (zilog_irq == -1) {
- if (central_bus) {
- unsigned long iclr, imap;
-
- iclr = central_bus->child->fhc_regs.uregs
- + FHC_UREGS_ICLR;
- imap = central_bus->child->fhc_regs.uregs
- + FHC_UREGS_IMAP;
- zilog_irq = build_irq(12, 0, iclr, imap);
- } else {
- err = prom_getproperty(zsnode, "interrupts",
- (char *) &sun4u_ino,
- sizeof(sun4u_ino));
- zilog_irq = sbus_build_irq(sbus_root, sun4u_ino);
- }
- }
-
- return (struct zilog_layout __iomem *) mapped_addr;
-}
-#else /* CONFIG_SPARC64 */
-
-/*
- * XXX The sun4d case is utterly screwed: it tries to re-walk the tree
- * (for the 3rd time) in order to find bootbus and cpu. Streamline it.
- */
-static struct zilog_layout __iomem * __init get_zs_sun4cmd(int chip, int node)
-{
- struct linux_prom_irqs irq_info[2];
- void __iomem *mapped_addr = NULL;
- int zsnode, cpunode, bbnode;
- struct linux_prom_registers zsreg[4];
- struct resource res;
-
- if (sparc_cpu_model == sun4d) {
- int walk;
-
- zsnode = 0;
- bbnode = 0;
- cpunode = 0;
- for (walk = prom_getchild(prom_root_node);
- (walk = prom_searchsiblings(walk, "cpu-unit")) != 0;
- walk = prom_getsibling(walk)) {
- bbnode = prom_getchild(walk);
- if (bbnode &&
- (bbnode = prom_searchsiblings(bbnode, "bootbus"))) {
- if ((zsnode = prom_getchild(bbnode)) == node) {
- cpunode = walk;
- break;
- }
- }
- }
- if (!walk) {
- prom_printf("SunZilog: Cannot find the %d'th bootbus on sun4d.\n",
- (chip / 2));
- prom_halt();
- }
+ struct uart_sunzilog_port *up;
+ unsigned long size;
+ int i;
- if (prom_getproperty(zsnode, "reg",
- (char *) zsreg, sizeof(zsreg)) == -1) {
- prom_printf("SunZilog: Cannot map Zilog %d\n", chip);
- prom_halt();
- }
- /* XXX Looks like an off by one? */
- prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1);
- res.start = zsreg[0].phys_addr;
- res.end = res.start + (8 - 1);
- res.flags = zsreg[0].which_io | IORESOURCE_IO;
- mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial");
+ size = NUM_CHANNELS * sizeof(struct uart_sunzilog_port);
+ sunzilog_port_table = kzalloc(size, GFP_KERNEL);
+ if (!sunzilog_port_table)
+ return -ENOMEM;
- } else {
- zsnode = node;
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ up = &sunzilog_port_table[i];
-#if 0 /* XXX When was this used? */
- if (prom_getintdefault(zsnode, "slave", -1) != chipid) {
- zsnode = prom_getsibling(zsnode);
- continue;
- }
-#endif
+ spin_lock_init(&up->port.lock);
- /*
- * "address" is only present on ports that OBP opened
- * (from Mitch Bradley's "Hitchhiker's Guide to OBP").
- * We do not use it.
- */
+ if (i == 0)
+ sunzilog_irq_chain = up;
- if (prom_getproperty(zsnode, "reg",
- (char *) zsreg, sizeof(zsreg)) == -1) {
- prom_printf("SunZilog: Cannot map Zilog %d\n", chip);
- prom_halt();
- }
- if (sparc_cpu_model == sun4m) /* Crude. Pass parent. XXX */
- prom_apply_obio_ranges(zsreg, 1);
- res.start = zsreg[0].phys_addr;
- res.end = res.start + (8 - 1);
- res.flags = zsreg[0].which_io | IORESOURCE_IO;
- mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial");
+ if (i < NUM_CHANNELS - 1)
+ up->next = up + 1;
+ else
+ up->next = NULL;
}
- if (prom_getproperty(zsnode, "intr",
- (char *) irq_info, sizeof(irq_info))
- % sizeof(struct linux_prom_irqs)) {
- prom_printf("SunZilog: Cannot get IRQ property for Zilog %d.\n",
- chip);
- prom_halt();
- }
- if (zilog_irq == -1) {
- zilog_irq = irq_info[0].pri;
- } else if (zilog_irq != irq_info[0].pri) {
- /* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */
- prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n",
- chip);
- prom_halt();
+ size = NUM_SUNZILOG * sizeof(struct zilog_layout __iomem *);
+ sunzilog_chip_regs = kzalloc(size, GFP_KERNEL);
+ if (!sunzilog_chip_regs) {
+ kfree(sunzilog_port_table);
+ sunzilog_irq_chain = NULL;
+ return -ENOMEM;
}
- return (struct zilog_layout __iomem *) mapped_addr;
+ return 0;
}
-#endif /* !(CONFIG_SPARC64) */
-/* Get the address of the registers for SunZilog instance CHIP. */
-static struct zilog_layout __iomem * __init get_zs(int chip, int node)
+static void sunzilog_free_tables(void)
{
- if (chip < 0 || chip >= NUM_SUNZILOG) {
- prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip);
- prom_halt();
- }
-
-#ifdef CONFIG_SPARC64
- return get_zs_sun4u(chip, node);
-#else
-
- if (sparc_cpu_model == sun4) {
- struct resource res;
-
- /* Not probe-able, hard code it. */
- switch (chip) {
- case 0:
- res.start = 0xf1000000;
- break;
- case 1:
- res.start = 0xf0000000;
- break;
- };
- zilog_irq = 12;
- res.end = (res.start + (8 - 1));
- res.flags = IORESOURCE_IO;
- return sbus_ioremap(&res, 0, 8, "SunZilog");
- }
-
- return get_zs_sun4cmd(chip, node);
-#endif
+ kfree(sunzilog_port_table);
+ sunzilog_irq_chain = NULL;
+ kfree(sunzilog_chip_regs);
}
#define ZS_PUT_CHAR_MAX_DELAY 2000 /* 10 ms */
@@ -1261,7 +1067,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch)
* udelay with ZSDELAY as that is a NOP on some platforms. -DaveM
*/
do {
- unsigned char val = sbus_readb(&channel->control);
+ unsigned char val = readb(&channel->control);
if (val & Tx_BUF_EMP) {
ZSDELAY();
break;
@@ -1269,7 +1075,7 @@ static void sunzilog_putchar(struct uart_port *port, int ch)
udelay(5);
} while (--loops);
- sbus_writeb(ch, &channel->data);
+ writeb(ch, &channel->data);
ZSDELAY();
ZS_WSYNC(channel);
}
@@ -1340,6 +1146,9 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
unsigned long flags;
int baud, brg;
+ if (up->port.type != PORT_SUNZILOG)
+ return -1;
+
printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
(sunzilog_reg.minor - 64) + con->index, con->index);
@@ -1386,28 +1195,6 @@ static struct console sunzilog_console = {
.data = &sunzilog_reg,
};
-static int __init sunzilog_console_init(void)
-{
- int i;
-
- if (con_is_present())
- return 0;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- int this_minor = sunzilog_reg.minor + i;
-
- if ((this_minor - 64) == (serial_console - 1))
- break;
- }
- if (i == NUM_CHANNELS)
- return 0;
-
- sunzilog_console.index = i;
- sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
- register_console(&sunzilog_console);
- return 0;
-}
-
static inline struct console *SUNZILOG_CONSOLE(void)
{
int i;
@@ -1432,116 +1219,19 @@ static inline struct console *SUNZILOG_CONSOLE(void)
#else
#define SUNZILOG_CONSOLE() (NULL)
-#define sunzilog_console_init() do { } while (0)
#endif
-/*
- * We scan the PROM tree recursively. This is the most reliable way
- * to find Zilog nodes on various platforms. However, we face an extreme
- * shortage of kernel stack, so we must be very careful. To that end,
- * we scan only to a certain depth, and we use a common property buffer
- * in the scan structure.
- */
-#define ZS_PROPSIZE 128
-#define ZS_SCAN_DEPTH 5
-
-struct zs_probe_scan {
- int depth;
- void (*scanner)(struct zs_probe_scan *t, int node);
-
- int devices;
- char prop[ZS_PROPSIZE];
-};
-
-static int __inline__ sunzilog_node_ok(int node, const char *name, int len)
-{
- if (strncmp(name, "zs", len) == 0)
- return 1;
- /* Don't fold this procedure just yet. Compare to su_node_ok(). */
- return 0;
-}
-
-static void __init sunzilog_scan(struct zs_probe_scan *t, int node)
-{
- int len;
-
- for (; node != 0; node = prom_getsibling(node)) {
- len = prom_getproperty(node, "name", t->prop, ZS_PROPSIZE);
- if (len <= 1)
- continue; /* Broken PROM node */
- if (sunzilog_node_ok(node, t->prop, len)) {
- (*t->scanner)(t, node);
- } else {
- if (t->depth < ZS_SCAN_DEPTH) {
- t->depth++;
- sunzilog_scan(t, prom_getchild(node));
- --t->depth;
- }
- }
- }
-}
-
-static void __init sunzilog_prepare(void)
-{
- struct uart_sunzilog_port *up;
- struct zilog_layout __iomem *rp;
- int channel, chip;
-
- /*
- * Temporary fix.
- */
- for (channel = 0; channel < NUM_CHANNELS; channel++)
- spin_lock_init(&sunzilog_port_table[channel].port.lock);
-
- sunzilog_irq_chain = up = &sunzilog_port_table[0];
- for (channel = 0; channel < NUM_CHANNELS - 1; channel++)
- up[channel].next = &up[channel + 1];
- up[channel].next = NULL;
-
- for (chip = 0; chip < NUM_SUNZILOG; chip++) {
- rp = sunzilog_chip_regs[chip];
- up[(chip * 2) + 0].port.membase = (void __iomem *)&rp->channelA;
- up[(chip * 2) + 1].port.membase = (void __iomem *)&rp->channelB;
-
- /* Channel A */
- up[(chip * 2) + 0].port.iotype = UPIO_MEM;
- up[(chip * 2) + 0].port.irq = zilog_irq;
- up[(chip * 2) + 0].port.uartclk = ZS_CLOCK;
- up[(chip * 2) + 0].port.fifosize = 1;
- up[(chip * 2) + 0].port.ops = &sunzilog_pops;
- up[(chip * 2) + 0].port.type = PORT_SUNZILOG;
- up[(chip * 2) + 0].port.flags = 0;
- up[(chip * 2) + 0].port.line = (chip * 2) + 0;
- up[(chip * 2) + 0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
-
- /* Channel B */
- up[(chip * 2) + 1].port.iotype = UPIO_MEM;
- up[(chip * 2) + 1].port.irq = zilog_irq;
- up[(chip * 2) + 1].port.uartclk = ZS_CLOCK;
- up[(chip * 2) + 1].port.fifosize = 1;
- up[(chip * 2) + 1].port.ops = &sunzilog_pops;
- up[(chip * 2) + 1].port.type = PORT_SUNZILOG;
- up[(chip * 2) + 1].port.flags = 0;
- up[(chip * 2) + 1].port.line = (chip * 2) + 1;
- up[(chip * 2) + 1].flags |= 0;
- }
-}
-
static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channel)
{
int baud, brg;
- if (channel == KEYBOARD_LINE) {
- up->flags |= SUNZILOG_FLAG_CONS_KEYB;
+ if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
up->cflag = B1200 | CS8 | CLOCAL | CREAD;
baud = 1200;
} else {
- up->flags |= SUNZILOG_FLAG_CONS_MOUSE;
up->cflag = B4800 | CS8 | CLOCAL | CREAD;
baud = 4800;
}
- printk(KERN_INFO "zs%d at 0x%p (irq = %d) is a SunZilog\n",
- channel, up->port.membase, zilog_irq);
up->curregs[R15] = BRKIE;
brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
@@ -1551,218 +1241,290 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
}
#ifdef CONFIG_SERIO
-static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel)
+static void __init sunzilog_register_serio(struct uart_sunzilog_port *up)
{
- struct serio *serio;
-
- up->serio = serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
- if (serio) {
- memset(serio, 0, sizeof(*serio));
-
- serio->port_data = up;
-
- serio->id.type = SERIO_RS232;
- if (channel == KEYBOARD_LINE) {
- serio->id.proto = SERIO_SUNKBD;
- strlcpy(serio->name, "zskbd", sizeof(serio->name));
- } else {
- serio->id.proto = SERIO_SUN;
- serio->id.extra = 1;
- strlcpy(serio->name, "zsms", sizeof(serio->name));
- }
- strlcpy(serio->phys,
- (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"),
- sizeof(serio->phys));
+ struct serio *serio = &up->serio;
- serio->write = sunzilog_serio_write;
- serio->open = sunzilog_serio_open;
- serio->close = sunzilog_serio_close;
+ serio->port_data = up;
- serio_register_port(serio);
+ serio->id.type = SERIO_RS232;
+ if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
+ serio->id.proto = SERIO_SUNKBD;
+ strlcpy(serio->name, "zskbd", sizeof(serio->name));
} else {
- printk(KERN_WARNING "zs%d: not enough memory for serio port\n",
- channel);
+ serio->id.proto = SERIO_SUN;
+ serio->id.extra = 1;
+ strlcpy(serio->name, "zsms", sizeof(serio->name));
}
+ strlcpy(serio->phys,
+ ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
+ "zs/serio0" : "zs/serio1"),
+ sizeof(serio->phys));
+
+ serio->write = sunzilog_serio_write;
+ serio->open = sunzilog_serio_open;
+ serio->close = sunzilog_serio_close;
+ serio->dev.parent = up->port.dev;
+
+ serio_register_port(serio);
}
#endif
-static void __init sunzilog_init_hw(void)
+static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
{
- int i;
-
- for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_sunzilog_port *up = &sunzilog_port_table[i];
- struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
- unsigned long flags;
- int baud, brg;
+ struct zilog_channel __iomem *channel;
+ unsigned long flags;
+ int baud, brg;
- spin_lock_irqsave(&up->port.lock, flags);
+ channel = ZILOG_CHANNEL_FROM_PORT(&up->port);
- if (ZS_IS_CHANNEL_A(up)) {
- write_zsreg(channel, R9, FHWRES);
- ZSDELAY_LONG();
- (void) read_zsreg(channel, R0);
- }
+ spin_lock_irqsave(&up->port.lock, flags);
+ if (ZS_IS_CHANNEL_A(up)) {
+ write_zsreg(channel, R9, FHWRES);
+ ZSDELAY_LONG();
+ (void) read_zsreg(channel, R0);
+ }
- if (i == KEYBOARD_LINE || i == MOUSE_LINE) {
- sunzilog_init_kbdms(up, i);
- up->curregs[R9] |= (NV | MIE);
- write_zsreg(channel, R9, up->curregs[R9]);
- } else {
- /* Normal serial TTY. */
- up->parity_mask = 0xff;
- up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
- up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
- up->curregs[R3] = RxENAB | Rx8;
- up->curregs[R5] = TxENAB | Tx8;
- up->curregs[R9] = NV | MIE;
- up->curregs[R10] = NRZ;
- up->curregs[R11] = TCBR | RCBR;
- baud = 9600;
- brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
- up->curregs[R12] = (brg & 0xff);
- up->curregs[R13] = (brg >> 8) & 0xff;
- up->curregs[R14] = BRSRC | BRENAB;
- __load_zsregs(channel, up->curregs);
- write_zsreg(channel, R9, up->curregs[R9]);
- }
+ if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+ SUNZILOG_FLAG_CONS_MOUSE)) {
+ sunzilog_init_kbdms(up, up->port.line);
+ up->curregs[R9] |= (NV | MIE);
+ write_zsreg(channel, R9, up->curregs[R9]);
+ } else {
+ /* Normal serial TTY. */
+ up->parity_mask = 0xff;
+ up->curregs[R1] = EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB;
+ up->curregs[R4] = PAR_EVEN | X16CLK | SB1;
+ up->curregs[R3] = RxENAB | Rx8;
+ up->curregs[R5] = TxENAB | Tx8;
+ up->curregs[R9] = NV | MIE;
+ up->curregs[R10] = NRZ;
+ up->curregs[R11] = TCBR | RCBR;
+ baud = 9600;
+ brg = BPS_TO_BRG(baud, ZS_CLOCK / ZS_CLOCK_DIVISOR);
+ up->curregs[R12] = (brg & 0xff);
+ up->curregs[R13] = (brg >> 8) & 0xff;
+ up->curregs[R14] = BRSRC | BRENAB;
+ __load_zsregs(channel, up->curregs);
+ write_zsreg(channel, R9, up->curregs[R9]);
+ }
- spin_unlock_irqrestore(&up->port.lock, flags);
+ spin_unlock_irqrestore(&up->port.lock, flags);
#ifdef CONFIG_SERIO
- if (i == KEYBOARD_LINE || i == MOUSE_LINE)
- sunzilog_register_serio(up, i);
+ if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
+ SUNZILOG_FLAG_CONS_MOUSE))
+ sunzilog_register_serio(up);
#endif
- }
}
-static struct zilog_layout __iomem * __init get_zs(int chip, int node);
-
-static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node)
-{
- sunzilog_chip_regs[t->devices] = get_zs(t->devices, node);
- t->devices++;
-}
+static int zilog_irq = -1;
-static int __init sunzilog_ports_init(void)
+static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
{
- struct zs_probe_scan scan;
- int ret;
- int uart_count;
- int i;
+ static int inst;
+ struct uart_sunzilog_port *up;
+ struct zilog_layout __iomem *rp;
+ int keyboard_mouse;
+ int err;
- printk(KERN_DEBUG "SunZilog: %d chips.\n", NUM_SUNZILOG);
+ keyboard_mouse = 0;
+ if (of_find_property(op->node, "keyboard", NULL))
+ keyboard_mouse = 1;
+
+ sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
+ sizeof(struct zilog_layout),
+ "zs");
+ if (!sunzilog_chip_regs[inst])
+ return -ENOMEM;
+
+ rp = sunzilog_chip_regs[inst];
+
+ if (zilog_irq == -1)
+ zilog_irq = op->irqs[0];
+
+ up = &sunzilog_port_table[inst * 2];
+
+ /* Channel A */
+ up[0].port.mapbase = op->resource[0].start + 0x00;
+ up[0].port.membase = (void __iomem *) &rp->channelA;
+ up[0].port.iotype = UPIO_MEM;
+ up[0].port.irq = op->irqs[0];
+ up[0].port.uartclk = ZS_CLOCK;
+ up[0].port.fifosize = 1;
+ up[0].port.ops = &sunzilog_pops;
+ up[0].port.type = PORT_SUNZILOG;
+ up[0].port.flags = 0;
+ up[0].port.line = (inst * 2) + 0;
+ up[0].port.dev = &op->dev;
+ up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
+ if (keyboard_mouse)
+ up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
+ sunzilog_init_hw(&up[0]);
+
+ /* Channel B */
+ up[1].port.mapbase = op->resource[0].start + 0x04;
+ up[1].port.membase = (void __iomem *) &rp->channelB;
+ up[1].port.iotype = UPIO_MEM;
+ up[1].port.irq = op->irqs[0];
+ up[1].port.uartclk = ZS_CLOCK;
+ up[1].port.fifosize = 1;
+ up[1].port.ops = &sunzilog_pops;
+ up[1].port.type = PORT_SUNZILOG;
+ up[1].port.flags = 0;
+ up[1].port.line = (inst * 2) + 1;
+ up[1].port.dev = &op->dev;
+ up[1].flags |= 0;
+ if (keyboard_mouse)
+ up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
+ sunzilog_init_hw(&up[1]);
+
+ if (!keyboard_mouse) {
+ err = uart_add_one_port(&sunzilog_reg, &up[0].port);
+ if (err) {
+ of_iounmap(rp, sizeof(struct zilog_layout));
+ return err;
+ }
+ err = uart_add_one_port(&sunzilog_reg, &up[1].port);
+ if (err) {
+ uart_remove_one_port(&sunzilog_reg, &up[0].port);
+ of_iounmap(rp, sizeof(struct zilog_layout));
+ return err;
+ }
+ } else {
+ printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
+ "is a zs\n",
+ op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
+ printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
+ "is a zs\n",
+ op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
+ }
- scan.scanner = sunzilog_scan_probe;
- scan.depth = 0;
- scan.devices = 0;
- sunzilog_scan(&scan, prom_getchild(prom_root_node));
+ dev_set_drvdata(&op->dev, &up[0]);
- sunzilog_prepare();
+ inst++;
- if (request_irq(zilog_irq, sunzilog_interrupt, SA_SHIRQ,
- "SunZilog", sunzilog_irq_chain)) {
- prom_printf("SunZilog: Unable to register zs interrupt handler.\n");
- prom_halt();
- }
+ return 0;
+}
- sunzilog_init_hw();
+static void __devexit zs_remove_one(struct uart_sunzilog_port *up)
+{
+ if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
+#ifdef CONFIG_SERIO
+ serio_unregister_port(&up->serio);
+#endif
+ } else
+ uart_remove_one_port(&sunzilog_reg, &up->port);
+}
- /* We can only init this once we have probed the Zilogs
- * in the system. Do not count channels assigned to keyboards
- * or mice when we are deciding how many ports to register.
- */
- uart_count = 0;
- for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_sunzilog_port *up = &sunzilog_port_table[i];
+static int __devexit zs_remove(struct of_device *dev)
+{
+ struct uart_sunzilog_port *up = dev_get_drvdata(&dev->dev);
+ struct zilog_layout __iomem *regs;
- if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up))
- continue;
+ zs_remove_one(&up[0]);
+ zs_remove_one(&up[1]);
- uart_count++;
- }
-
- sunzilog_reg.nr = uart_count;
- sunzilog_reg.minor = sunserial_current_minor;
+ regs = sunzilog_chip_regs[up[0].port.line / 2];
+ of_iounmap(regs, sizeof(struct zilog_layout));
- ret = uart_register_driver(&sunzilog_reg);
- if (ret == 0) {
- sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
- sunzilog_reg.cons = SUNZILOG_CONSOLE();
+ dev_set_drvdata(&dev->dev, NULL);
- sunserial_current_minor += uart_count;
+ return 0;
+}
- for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_sunzilog_port *up = &sunzilog_port_table[i];
+static struct of_device_id zs_match[] = {
+ {
+ .name = "zs",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, zs_match);
- if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up))
- continue;
+static struct of_platform_driver zs_driver = {
+ .name = "zs",
+ .match_table = zs_match,
+ .probe = zs_probe,
+ .remove = __devexit_p(zs_remove),
+};
- if (uart_add_one_port(&sunzilog_reg, &up->port)) {
- printk(KERN_ERR
- "SunZilog: failed to add port zs%d\n", i);
- }
- }
+static int __init sunzilog_init(void)
+{
+ struct device_node *dp;
+ int err, uart_count;
+ int num_keybms;
+
+ NUM_SUNZILOG = 0;
+ num_keybms = 0;
+ for_each_node_by_name(dp, "zs") {
+ NUM_SUNZILOG++;
+ if (of_find_property(dp, "keyboard", NULL))
+ num_keybms++;
}
- return ret;
-}
+ uart_count = 0;
+ if (NUM_SUNZILOG) {
+ int uart_count;
-static void __init sunzilog_scan_count(struct zs_probe_scan *t, int node)
-{
- t->devices++;
-}
+ err = sunzilog_alloc_tables();
+ if (err)
+ goto out;
-static int __init sunzilog_ports_count(void)
-{
- struct zs_probe_scan scan;
+ uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms);
- /* Sun4 Zilog setup is hard coded, no probing to do. */
- if (sparc_cpu_model == sun4)
- return 2;
+ sunzilog_reg.nr = uart_count;
+ sunzilog_reg.minor = sunserial_current_minor;
+ err = uart_register_driver(&sunzilog_reg);
+ if (err)
+ goto out_free_tables;
- scan.scanner = sunzilog_scan_count;
- scan.depth = 0;
- scan.devices = 0;
+ sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
+ sunzilog_reg.cons = SUNZILOG_CONSOLE();
- sunzilog_scan(&scan, prom_getchild(prom_root_node));
+ sunserial_current_minor += uart_count;
+ }
- return scan.devices;
-}
+ err = of_register_driver(&zs_driver, &of_bus_type);
+ if (err)
+ goto out_unregister_uart;
-static int __init sunzilog_init(void)
-{
+ if (zilog_irq != -1) {
+ err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
+ "zs", sunzilog_irq_chain);
+ if (err)
+ goto out_unregister_driver;
+ }
- NUM_SUNZILOG = sunzilog_ports_count();
- if (NUM_SUNZILOG == 0)
- return -ENODEV;
+out:
+ return err;
- sunzilog_alloc_tables();
+out_unregister_driver:
+ of_unregister_driver(&zs_driver);
- sunzilog_ports_init();
+out_unregister_uart:
+ if (NUM_SUNZILOG) {
+ uart_unregister_driver(&sunzilog_reg);
+ sunzilog_reg.cons = NULL;
+ }
- return 0;
+out_free_tables:
+ sunzilog_free_tables();
+ goto out;
}
static void __exit sunzilog_exit(void)
{
- int i;
+ of_unregister_driver(&zs_driver);
- for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_sunzilog_port *up = &sunzilog_port_table[i];
-
- if (ZS_IS_KEYB(up) || ZS_IS_MOUSE(up)) {
-#ifdef CONFIG_SERIO
- if (up->serio) {
- serio_unregister_port(up->serio);
- up->serio = NULL;
- }
-#endif
- } else
- uart_remove_one_port(&sunzilog_reg, &up->port);
+ if (zilog_irq != -1) {
+ free_irq(zilog_irq, sunzilog_irq_chain);
+ zilog_irq = -1;
}
- uart_unregister_driver(&sunzilog_reg);
+ if (NUM_SUNZILOG) {
+ uart_unregister_driver(&sunzilog_reg);
+ sunzilog_free_tables();
+ }
}
module_init(sunzilog_init);
@@ -1770,4 +1532,5 @@ module_exit(sunzilog_exit);
MODULE_AUTHOR("David S. Miller");
MODULE_DESCRIPTION("Sun Zilog serial port driver");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
index df705fda424..f802867c95c 100644
--- a/drivers/serial/v850e_uart.c
+++ b/drivers/serial/v850e_uart.c
@@ -372,13 +372,13 @@ static int v850e_uart_startup (struct uart_port *port)
/* Alloc RX irq. */
err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq,
- SA_INTERRUPT, "v850e_uart", port);
+ IRQF_DISABLED, "v850e_uart", port);
if (err)
return err;
/* Alloc TX irq. */
err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq,
- SA_INTERRUPT, "v850e_uart", port);
+ IRQF_DISABLED, "v850e_uart", port);
if (err) {
free_irq (V850E_UART_RX_IRQ (port->line), port);
return err;
@@ -468,7 +468,6 @@ static struct uart_ops v850e_uart_ops = {
static struct uart_driver v850e_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "v850e_uart",
- .devfs_name = "tts/",
.dev_name = "ttyS",
.major = TTY_MAJOR,
.minor = V850E_UART_MINOR_BASE,
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index df5e8713fa3..6c8b0ea83c3 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -19,7 +19,6 @@
* 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/config.h>
#if defined(CONFIG_SERIAL_VR41XX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -39,6 +38,7 @@
#include <linux/tty_flip.h>
#include <asm/io.h>
+#include <asm/vr41xx/irq.h>
#include <asm/vr41xx/siu.h>
#include <asm/vr41xx/vr41xx.h>
@@ -911,7 +911,6 @@ static struct uart_driver siu_uart_driver = {
.owner = THIS_MODULE,
.driver_name = "SIU",
.dev_name = "ttyVR",
- .devfs_name = "ttvr/",
.major = SIU_MAJOR,
.minor = SIU_MINOR_BASE,
.cons = SERIAL_VR41XX_CONSOLE,
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 501316b198e..6c7e0352d56 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -7,7 +7,6 @@
* Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -26,7 +25,7 @@ static DECLARE_RWSEM(ioc3_devices_rwsem);
static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];
static struct ioc3_submodule *ioc3_ethernet;
-static rwlock_t ioc3_submodules_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(ioc3_submodules_lock);
/* NIC probing code */
@@ -707,7 +706,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
writel(~0, &idd->vma->eisr);
idd->dual_irq = 1;
- if (!request_irq(pdev->irq, ioc3_intr_eth, SA_SHIRQ,
+ if (!request_irq(pdev->irq, ioc3_intr_eth, IRQF_SHARED,
"ioc3-eth", (void *)idd)) {
idd->irq_eth = pdev->irq;
} else {
@@ -715,7 +714,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
"%s : request_irq fails for IRQ 0x%x\n ",
__FUNCTION__, pdev->irq);
}
- if (!request_irq(pdev->irq+2, ioc3_intr_io, SA_SHIRQ,
+ if (!request_irq(pdev->irq+2, ioc3_intr_io, IRQF_SHARED,
"ioc3-io", (void *)idd)) {
idd->irq_io = pdev->irq+2;
} else {
@@ -724,7 +723,7 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
__FUNCTION__, pdev->irq+2);
}
} else {
- if (!request_irq(pdev->irq, ioc3_intr_io, SA_SHIRQ,
+ if (!request_irq(pdev->irq, ioc3_intr_io, IRQF_SHARED,
"ioc3", (void *)idd)) {
idd->irq_io = pdev->irq;
} else {
diff --git a/drivers/sn/ioc4.c b/drivers/sn/ioc4.c
index 8256a97eb50..8562821e649 100644
--- a/drivers/sn/ioc4.c
+++ b/drivers/sn/ioc4.c
@@ -438,7 +438,7 @@ static struct pci_device_id ioc4_id_table[] = {
{0}
};
-static struct pci_driver __devinitdata ioc4_driver = {
+static struct pci_driver ioc4_driver = {
.name = "IOC4",
.id_table = ioc4_id_table,
.probe = ioc4_probe,
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 1cea4a6799f..146298ad737 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -210,6 +210,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip)
proxy->master = master;
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
+ proxy->mode = chip->mode;
proxy->irq = chip->irq;
proxy->modalias = chip->modalias;
@@ -509,7 +510,7 @@ static void spi_complete(void *arg)
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
int status;
message->complete = spi_complete;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index dd2f950b21a..a23862ef72b 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -16,7 +16,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
index a006a1ee27a..39d9b20f203 100644
--- a/drivers/spi/spi_butterfly.c
+++ b/drivers/spi/spi_butterfly.c
@@ -17,7 +17,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/tc/lk201.c b/drivers/tc/lk201.c
index cf10d5cdfb9..757dec9c7ee 100644
--- a/drivers/tc/lk201.c
+++ b/drivers/tc/lk201.c
@@ -8,7 +8,6 @@
* Copyright (C) 2001, 2002, 2003, 2004 Maciej W. Rozycki
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 2dffa8e303b..5e8a27620f6 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -39,7 +39,6 @@
* is shared with DSRS(DTE) at pin 23.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -1745,7 +1744,6 @@ int __init zs_init(void)
/* Not all of this is exactly right for us. */
serial_driver->owner = THIS_MODULE;
- serial_driver->devfs_name = "tts/";
serial_driver->name = "ttyS";
serial_driver->major = TTY_MAJOR;
serial_driver->minor_start = 64;
@@ -1754,7 +1752,7 @@ int __init zs_init(void)
serial_driver->init_termios = tty_std_termios;
serial_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(serial_driver, &serial_ops);
if (tty_register_driver(serial_driver))
@@ -1793,7 +1791,7 @@ int __init zs_init(void)
zs_soft[channel].clk_divisor = 16;
zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
- if (request_irq(zs_soft[channel].irq, rs_interrupt, SA_SHIRQ,
+ if (request_irq(zs_soft[channel].irq, rs_interrupt, IRQF_SHARED,
"scc", &zs_soft[channel]))
printk(KERN_ERR "decserial: can't get irq %d\n",
zs_soft[channel].irq);
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index 5578a9dd04e..f6b2948ab28 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -5712,7 +5712,7 @@ static int ixj_daa_write(IXJ *j)
return 1;
}
-int ixj_set_tone_off(unsigned short arg, IXJ *j)
+static int ixj_set_tone_off(unsigned short arg, IXJ *j)
{
j->tone_off_time = arg;
if (ixj_WriteDSPCommand(0x6E05, j)) /* Set Tone Off Period */
diff --git a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
index e166fffea86..e41f49afd0f 100644
--- a/drivers/telephony/phonedev.c
+++ b/drivers/telephony/phonedev.c
@@ -28,7 +28,6 @@
#include <linux/kmod.h>
#include <linux/sem.h>
-#include <linux/devfs_fs_kernel.h>
#include <linux/mutex.h>
#define PHONE_NUM_DEVICES 256
@@ -106,8 +105,6 @@ int phone_register_device(struct phone_device *p, int unit)
if (phone_device[i] == NULL) {
phone_device[i] = p;
p->minor = i;
- devfs_mk_cdev(MKDEV(PHONE_MAJOR,i),
- S_IFCHR|S_IRUSR|S_IWUSR, "phone/%d", i);
mutex_unlock(&phone_lock);
return 0;
}
@@ -125,7 +122,6 @@ void phone_unregister_device(struct phone_device *pfd)
mutex_lock(&phone_lock);
if (phone_device[pfd->minor] != pfd)
panic("phone: bad unregister");
- devfs_remove("phone/%d", pfd->minor);
phone_device[pfd->minor] = NULL;
mutex_unlock(&phone_lock);
}
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7fdbc5dad5f..f9b1719b9a3 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -23,7 +23,9 @@ config USB_ARCH_HAS_OHCI
default y if ARCH_LH7A404
default y if ARCH_S3C2410
default y if PXA27x
- default y if ARCH_AT91RM9200
+ default y if ARCH_EP93XX
+ default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
+ default y if ARCH_PNX4008
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index c7123bf71c5..97d57cfc343 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
+obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_ETRAX_USB_HOST) += host/
obj-$(CONFIG_USB_OHCI_AT91) += host/
@@ -23,6 +24,7 @@ obj-$(CONFIG_USB_PRINTER) += class/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-$(CONFIG_USB) += storage/
+obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_AIPTEK) += input/
obj-$(CONFIG_USB_ATI_REMOTE) += input/
obj-$(CONFIG_USB_HID) += input/
@@ -31,8 +33,8 @@ obj-$(CONFIG_USB_KBTAB) += input/
obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/
+obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/
obj-$(CONFIG_USB_WACOM) += input/
-obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_XPAD) += input/
obj-$(CONFIG_USB_CATC) += net/
@@ -47,22 +49,24 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
+obj-$(CONFIG_USB_ADUTUX) += misc/
+obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_AUERSWALD) += misc/
-obj-$(CONFIG_USB_CY7C63) += misc/
+obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
+obj-$(CONFIG_USB_FTDI_ELAN) += misc/
obj-$(CONFIG_USB_IDMOUSE) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
+obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
+obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_USS720) += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_SISUSBVGA) += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index b38990adf1c..465961a26e4 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1621,26 +1621,32 @@ static int claim_interface(struct usb_device *usb_dev,
return ret;
}
-static void create_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
+static struct attribute *attrs[] = {
+ &dev_attr_stat_status.attr,
+ &dev_attr_stat_mflags.attr,
+ &dev_attr_stat_human_status.attr,
+ &dev_attr_stat_delin.attr,
+ &dev_attr_stat_vidcpe.attr,
+ &dev_attr_stat_usrate.attr,
+ &dev_attr_stat_dsrate.attr,
+ &dev_attr_stat_usattenuation.attr,
+ &dev_attr_stat_dsattenuation.attr,
+ &dev_attr_stat_usmargin.attr,
+ &dev_attr_stat_dsmargin.attr,
+ &dev_attr_stat_txflow.attr,
+ &dev_attr_stat_rxflow.attr,
+ &dev_attr_stat_uscorr.attr,
+ &dev_attr_stat_dscorr.attr,
+ &dev_attr_stat_usunc.attr,
+ &dev_attr_stat_dsunc.attr,
+};
+static struct attribute_group attr_grp = {
+ .attrs = attrs,
+};
+
+static int create_fs_entries(struct usb_interface *intf)
{
- /* sysfs interface */
- device_create_file(&intf->dev, &dev_attr_stat_status);
- device_create_file(&intf->dev, &dev_attr_stat_mflags);
- device_create_file(&intf->dev, &dev_attr_stat_human_status);
- device_create_file(&intf->dev, &dev_attr_stat_delin);
- device_create_file(&intf->dev, &dev_attr_stat_vidcpe);
- device_create_file(&intf->dev, &dev_attr_stat_usrate);
- device_create_file(&intf->dev, &dev_attr_stat_dsrate);
- device_create_file(&intf->dev, &dev_attr_stat_usattenuation);
- device_create_file(&intf->dev, &dev_attr_stat_dsattenuation);
- device_create_file(&intf->dev, &dev_attr_stat_usmargin);
- device_create_file(&intf->dev, &dev_attr_stat_dsmargin);
- device_create_file(&intf->dev, &dev_attr_stat_txflow);
- device_create_file(&intf->dev, &dev_attr_stat_rxflow);
- device_create_file(&intf->dev, &dev_attr_stat_uscorr);
- device_create_file(&intf->dev, &dev_attr_stat_dscorr);
- device_create_file(&intf->dev, &dev_attr_stat_usunc);
- device_create_file(&intf->dev, &dev_attr_stat_dsunc);
+ return sysfs_create_group(&intf->dev.kobj, &attr_grp);
}
static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
@@ -1708,37 +1714,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
return ret;
}
- create_fs_entries(sc, intf);
+ ret = create_fs_entries(intf);
+ if (ret) {
+ uea_stop(sc);
+ kfree(sc);
+ return ret;
+ }
return 0;
}
-static void destroy_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
+static void destroy_fs_entries(struct usb_interface *intf)
{
- /* sysfs interface */
- device_remove_file(&intf->dev, &dev_attr_stat_status);
- device_remove_file(&intf->dev, &dev_attr_stat_mflags);
- device_remove_file(&intf->dev, &dev_attr_stat_human_status);
- device_remove_file(&intf->dev, &dev_attr_stat_delin);
- device_remove_file(&intf->dev, &dev_attr_stat_vidcpe);
- device_remove_file(&intf->dev, &dev_attr_stat_usrate);
- device_remove_file(&intf->dev, &dev_attr_stat_dsrate);
- device_remove_file(&intf->dev, &dev_attr_stat_usattenuation);
- device_remove_file(&intf->dev, &dev_attr_stat_dsattenuation);
- device_remove_file(&intf->dev, &dev_attr_stat_usmargin);
- device_remove_file(&intf->dev, &dev_attr_stat_dsmargin);
- device_remove_file(&intf->dev, &dev_attr_stat_txflow);
- device_remove_file(&intf->dev, &dev_attr_stat_rxflow);
- device_remove_file(&intf->dev, &dev_attr_stat_uscorr);
- device_remove_file(&intf->dev, &dev_attr_stat_dscorr);
- device_remove_file(&intf->dev, &dev_attr_stat_usunc);
- device_remove_file(&intf->dev, &dev_attr_stat_dsunc);
+ sysfs_remove_group(&intf->dev.kobj, &attr_grp);
}
static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
{
struct uea_softc *sc = usbatm->driver_data;
- destroy_fs_entries(sc, intf);
+ destroy_fs_entries(intf);
uea_stop(sc);
kfree(sc);
}
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index d41dc67ba4c..ca90326f2f5 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -291,13 +291,13 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
struct acm_ru *rcv = urb->context;
struct acm *acm = rcv->instance;
int status = urb->status;
- dbg("Entering acm_read_bulk with status %d\n", urb->status);
+ dbg("Entering acm_read_bulk with status %d", urb->status);
if (!ACM_READY(acm))
return;
if (status)
- dev_dbg(&acm->data->dev, "bulk rx status %d\n", status);
+ dev_dbg(&acm->data->dev, "bulk rx status %d", status);
buf = rcv->buffer;
buf->size = urb->actual_length;
@@ -343,7 +343,7 @@ next_buffer:
list_del(&buf->list);
spin_unlock(&acm->read_lock);
- dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size);
+ dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
tty_buffer_request_room(tty, buf->size);
if (!acm->throttle)
@@ -394,7 +394,7 @@ urbs:
rcv->urb->transfer_dma = buf->dma;
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf);
+ dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p", rcv->urb, rcv, buf);
/* This shouldn't kill the driver as unsuccessful URBs are returned to the
free-urbs-pool and resubmited ASAP */
@@ -413,7 +413,7 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = (struct acm *)urb->context;
- dbg("Entering acm_write_bulk with status %d\n", urb->status);
+ dbg("Entering acm_write_bulk with status %d", urb->status);
acm_write_done(acm);
acm_write_start(acm);
@@ -424,7 +424,7 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
static void acm_softint(void *private)
{
struct acm *acm = private;
- dbg("Entering acm_softint.\n");
+ dbg("Entering acm_softint.");
if (!ACM_READY(acm))
return;
@@ -440,7 +440,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
struct acm *acm;
int rv = -EINVAL;
int i;
- dbg("Entering acm_tty_open.\n");
+ dbg("Entering acm_tty_open.");
mutex_lock(&open_mutex);
@@ -541,7 +541,7 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
int wbn;
struct acm_wb *wb;
- dbg("Entering acm_tty_write to write %d bytes,\n", count);
+ dbg("Entering acm_tty_write to write %d bytes,", count);
if (!ACM_READY(acm))
return -EINVAL;
@@ -793,7 +793,7 @@ static int acm_probe (struct usb_interface *intf,
if (!buflen) {
if (intf->cur_altsetting->endpoint->extralen && intf->cur_altsetting->endpoint->extra) {
- dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint\n");
+ dev_dbg(&intf->dev,"Seeking extra descriptors on endpoint");
buflen = intf->cur_altsetting->endpoint->extralen;
buffer = intf->cur_altsetting->endpoint->extra;
} else {
@@ -842,24 +842,24 @@ next_desc:
if (!union_header) {
if (call_interface_num > 0) {
- dev_dbg(&intf->dev,"No union descriptor, using call management descriptor\n");
+ dev_dbg(&intf->dev,"No union descriptor, using call management descriptor");
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
control_interface = intf;
} else {
- dev_dbg(&intf->dev,"No union descriptor, giving up\n");
+ dev_dbg(&intf->dev,"No union descriptor, giving up");
return -ENODEV;
}
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
if (!control_interface || !data_interface) {
- dev_dbg(&intf->dev,"no interfaces\n");
+ dev_dbg(&intf->dev,"no interfaces");
return -ENODEV;
}
}
if (data_interface_num != call_interface_num)
- dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.\n");
+ dev_dbg(&intf->dev,"Seperate call control interface. That is not fully supported.");
skip_normal_probe:
@@ -867,7 +867,7 @@ skip_normal_probe:
if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
struct usb_interface *t;
- dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
+ dev_dbg(&intf->dev,"Your device has switched interfaces.");
t = control_interface;
control_interface = data_interface;
@@ -878,7 +878,7 @@ skip_normal_probe:
}
if (usb_interface_claimed(data_interface)) { /* valid in this context */
- dev_dbg(&intf->dev,"The data interface isn't available\n");
+ dev_dbg(&intf->dev,"The data interface isn't available");
return -EBUSY;
}
@@ -895,7 +895,7 @@ skip_normal_probe:
if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
/* descriptors are swapped */
struct usb_endpoint_descriptor *t;
- dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
+ dev_dbg(&intf->dev,"The data interface has switched endpoints");
t = epread;
epread = epwrite;
@@ -910,7 +910,7 @@ skip_normal_probe:
}
if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
- dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
+ dev_dbg(&intf->dev, "out of memory (acm kzalloc)");
goto alloc_fail;
}
@@ -936,26 +936,26 @@ skip_normal_probe:
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) {
- dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)\n");
+ dev_dbg(&intf->dev, "out of memory (ctrl buffer alloc)");
goto alloc_fail2;
}
acm->ctrl_buffer = buf;
if (acm_write_buffers_alloc(acm) < 0) {
- dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
+ dev_dbg(&intf->dev, "out of memory (write buffer alloc)");
goto alloc_fail4;
}
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
- dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
+ dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
goto alloc_fail5;
}
for (i = 0; i < num_rx_buf; i++) {
struct acm_ru *rcv = &(acm->ru[i]);
if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
+ dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
goto alloc_fail7;
}
@@ -966,13 +966,13 @@ skip_normal_probe:
struct acm_rb *buf = &(acm->rb[i]);
if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
- dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
+ dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)");
goto alloc_fail7;
}
}
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->writeurb) {
- dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)\n");
+ dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
goto alloc_fail7;
}
@@ -1086,6 +1086,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
.driver_info = SINGLE_RX_URB, /* firmware bug */
},
+ { USB_DEVICE(0x0ace, 0x1611), /* ZyDAS 56K USB MODEM - new version */
+ .driver_info = SINGLE_RX_URB, /* firmware bug */
+ },
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_ACM_PROTO_AT_V25TER) },
@@ -1145,12 +1148,11 @@ static int __init acm_init(void)
acm_tty_driver->owner = THIS_MODULE,
acm_tty_driver->driver_name = "acm",
acm_tty_driver->name = "ttyACM",
- acm_tty_driver->devfs_name = "usb/acm/",
acm_tty_driver->major = ACM_TTY_MAJOR,
acm_tty_driver->minor_start = 0,
acm_tty_driver->type = TTY_DRIVER_TYPE_SERIAL,
acm_tty_driver->subtype = SERIAL_TYPE_NORMAL,
- acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS,
+ acm_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
acm_tty_driver->init_termios = tty_std_termios;
acm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(acm_tty_driver, &acm_ops);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 48dee4b8d8e..9cac11ca1bb 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -813,7 +813,7 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product)
return 0;
}
-static struct file_operations usblp_fops = {
+static const struct file_operations usblp_fops = {
.owner = THIS_MODULE,
.read = usblp_read,
.write = usblp_write,
@@ -927,7 +927,9 @@ static int usblp_probe(struct usb_interface *intf,
/* Retrieve and store the device ID string. */
usblp_cache_device_id_string(usblp);
- device_create_file(&intf->dev, &dev_attr_ieee1284_id);
+ retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id);
+ if (retval)
+ goto abort_intfdata;
#ifdef DEBUG
usblp_check_status(usblp, 0);
@@ -1021,18 +1023,13 @@ static int usblp_select_alts(struct usblp *usblp)
for (e = 0; e < ifd->desc.bNumEndpoints; e++) {
epd = &ifd->endpoint[e].desc;
- if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
- USB_ENDPOINT_XFER_BULK)
- continue;
-
- if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
+ if (usb_endpoint_is_bulk_out(epd))
if (!epwrite)
epwrite = epd;
- } else {
+ if (usb_endpoint_is_bulk_in(epd))
if (!epread)
epread = epd;
- }
}
/* Ignore buggy hardware without the right endpoints. */
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a08787e253a..6e3b5358a76 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -31,9 +31,6 @@ config USB_DEVICEFS
For the format of the various /proc/bus/usb/ files, please read
<file:Documentation/usb/proc_usb_info.txt>.
- Please note that this code is completely unrelated to devfs, the
- "/dev file system support".
-
Most users want to say Y here.
config USB_BANDWIDTH
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index ec510922af6..34e9bac319b 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -4,7 +4,7 @@
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
- devio.o notify.o
+ devio.o notify.o generic.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index ad742cec94f..840442a25b6 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -5,7 +5,6 @@
* and should work with all USB controllers, regardles of bus type.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -105,7 +104,7 @@ void *hcd_buffer_alloc (
dma_addr_t *dma
)
{
- struct usb_hcd *hcd = bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
/* some USB hosts just use PIO */
@@ -128,7 +127,7 @@ void hcd_buffer_free (
dma_addr_t dma
)
{
- struct usb_hcd *hcd = bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
if (!addr)
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index a9d89c78cc2..bfb3731d42d 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/usb.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -476,7 +475,9 @@ int usb_get_configuration(struct usb_device *dev)
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "start");
- goto err;
+ dev_err(ddev, "chopping to %d config(s)\n", cfgno);
+ dev->descriptor.bNumConfigurations = cfgno;
+ break;
} else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno,
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index c0f37343a27..3538c2fdadf 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -593,7 +593,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
/* Kernel lock for "lastev" protection */
static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
{
- struct usb_device_status *st = (struct usb_device_status *)file->private_data;
+ struct usb_device_status *st = file->private_data;
unsigned int mask = 0;
lock_kernel();
@@ -603,7 +603,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
unlock_kernel();
return POLLIN;
}
-
+
/* we may have dropped BKL - need to check for having lost the race */
if (file->private_data) {
kfree(st);
@@ -667,7 +667,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
return ret;
}
-struct file_operations usbfs_devices_fops = {
+const struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 3f8e06279c9..a94c63bef63 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -47,6 +47,7 @@
#include <linux/usbdevice_fs.h>
#include <linux/cdev.h>
#include <linux/notifier.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
#include <linux/moduleparam.h>
@@ -58,6 +59,9 @@
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
+/* Mutual exclusion for removal, open, and release */
+DEFINE_MUTEX(usbfs_mutex);
+
struct async {
struct list_head asynclist;
struct dev_state *ps;
@@ -68,6 +72,7 @@ struct async {
void __user *userbuffer;
void __user *userurb;
struct urb *urb;
+ u32 secid;
};
static int usbfs_snoop = 0;
@@ -85,9 +90,10 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
#define MAX_USBFS_BUFFER_SIZE 16384
-static inline int connected (struct usb_device *dev)
+static inline int connected (struct dev_state *ps)
{
- return dev->state != USB_STATE_NOTATTACHED;
+ return (!list_empty(&ps->list) &&
+ ps->dev->state != USB_STATE_NOTATTACHED);
}
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -116,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
@@ -125,7 +131,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
pos = *ppos;
usb_lock_device(dev);
- if (!connected(dev)) {
+ if (!connected(ps)) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
@@ -299,7 +305,7 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
static void async_completed(struct urb *urb, struct pt_regs *regs)
{
- struct async *as = (struct async *)urb->context;
+ struct async *as = urb->context;
struct dev_state *ps = as->ps;
struct siginfo sinfo;
@@ -312,7 +318,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
- as->euid);
+ as->euid, as->secid);
}
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb, as->userurb);
@@ -515,19 +521,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
static struct usb_device *usbdev_lookup_minor(int minor)
{
- struct device *device;
- struct usb_device *udev = NULL;
+ struct class_device *class_dev;
+ struct usb_device *dev = NULL;
down(&usb_device_class->sem);
- list_for_each_entry(device, &usb_device_class->devices, node) {
- if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
- udev = device->platform_data;
+ list_for_each_entry(class_dev, &usb_device_class->children, node) {
+ if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+ dev = class_dev->class_data;
break;
}
}
up(&usb_device_class->sem);
- return udev;
+ return dev;
};
/*
@@ -539,25 +545,25 @@ static int usbdev_open(struct inode *inode, struct file *file)
struct dev_state *ps;
int ret;
- /*
- * no locking necessary here, as chrdev_open has the kernel lock
- * (still acquire the kernel lock for safety)
- */
+ /* Protect against simultaneous removal or release */
+ mutex_lock(&usbfs_mutex);
+
ret = -ENOMEM;
if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
- goto out_nolock;
+ goto out;
- lock_kernel();
ret = -ENOENT;
/* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
- dev = inode->u.generic_ip;
- if (!dev) {
- kfree(ps);
+ dev = inode->i_private;
+ if (!dev)
goto out;
- }
+ ret = usb_autoresume_device(dev, 1);
+ if (ret)
+ goto out;
+
usb_get_dev(dev);
ret = 0;
ps->dev = dev;
@@ -572,34 +578,41 @@ static int usbdev_open(struct inode *inode, struct file *file)
ps->disc_euid = current->euid;
ps->disccontext = NULL;
ps->ifclaimed = 0;
+ security_task_getsecid(current, &ps->secid);
wmb();
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
- unlock_kernel();
- out_nolock:
- return ret;
+ if (ret)
+ kfree(ps);
+ mutex_unlock(&usbfs_mutex);
+ return ret;
}
static int usbdev_release(struct inode *inode, struct file *file)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
unsigned int ifnum;
usb_lock_device(dev);
+
+ /* Protect against simultaneous open */
+ mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
+ mutex_unlock(&usbfs_mutex);
+
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
}
destroy_all_async(ps);
+ usb_autosuspend_device(dev, 1);
usb_unlock_device(dev);
usb_put_dev(dev);
- ps->dev = NULL;
kfree(ps);
- return 0;
+ return 0;
}
static int proc_control(struct dev_state *ps, void __user *arg)
@@ -1053,6 +1066,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->pid = current->pid;
as->uid = current->uid;
as->euid = current->euid;
+ security_task_getsecid(current, &as->secid);
if (!(uurb->endpoint & USB_DIR_IN)) {
if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
free_async(as);
@@ -1078,9 +1092,7 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg)
if (copy_from_user(&uurb, arg, sizeof(uurb)))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb,
- (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc,
- arg);
+ return proc_do_submiturb(ps, &uurb, (((struct usbdevfs_urb __user *)arg)->iso_frame_desc), arg);
}
static int proc_unlinkurb(struct dev_state *ps, void __user *arg)
@@ -1205,9 +1217,7 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
return -EFAULT;
- return proc_do_submiturb(ps, &uurb,
- (struct usbdevfs_iso_packet_desc __user *)uurb.iso_frame_desc,
- arg);
+ return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
}
static int processcompl_compat(struct async *as, void __user * __user *arg)
@@ -1322,7 +1332,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
- if (!connected(ps->dev)) {
+ if (!connected(ps)) {
kfree(buf);
return -ENODEV;
}
@@ -1349,7 +1359,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
usb_unlock_device(ps->dev);
- bus_rescan_devices(intf->dev.bus);
+ retval = bus_rescan_devices(intf->dev.bus);
usb_lock_device(ps->dev);
break;
@@ -1413,7 +1423,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
*/
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
void __user *p = (void __user *)arg;
int ret = -ENOTTY;
@@ -1421,7 +1431,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
- if (!connected(dev)) {
+ if (!connected(ps)) {
usb_unlock_device(dev);
return -ENODEV;
}
@@ -1556,18 +1566,18 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
- unsigned int mask = 0;
+ struct dev_state *ps = file->private_data;
+ unsigned int mask = 0;
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= POLLOUT | POLLWRNORM;
- if (!connected(ps->dev))
+ if (!connected(ps))
mask |= POLLERR | POLLHUP;
return mask;
}
-struct file_operations usbfs_device_file_operations = {
+const struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@ -1580,16 +1590,16 @@ static void usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
- dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
- MKDEV(USB_DEVICE_MAJOR, minor),
+ dev->class_dev = class_device_create(usb_device_class, NULL,
+ MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
- dev->usbfs_dev->platform_data = dev;
+ dev->class_dev->class_data = dev;
}
static void usbdev_remove(struct usb_device *dev)
{
- device_unregister(dev->usbfs_dev);
+ class_device_unregister(dev->class_dev);
}
static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index c196f384530..113e484c763 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -17,13 +17,14 @@
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
- * generic USB things that the real drivers can use..
+ * matching, probing, releasing, suspending and resuming for
+ * real drivers.
*
*/
-#include <linux/config.h>
#include <linux/device.h>
#include <linux/usb.h>
+#include <linux/workqueue.h>
#include "hcd.h"
#include "usb.h"
@@ -35,38 +36,6 @@ struct usb_dynid {
struct usb_device_id id;
};
-
-static int generic_probe(struct device *dev)
-{
- return 0;
-}
-static int generic_remove(struct device *dev)
-{
- struct usb_device *udev = to_usb_device(dev);
-
- /* if this is only an unbind, not a physical disconnect, then
- * unconfigure the device */
- if (udev->state == USB_STATE_CONFIGURED)
- usb_set_configuration(udev, 0);
-
- /* in case the call failed or the device was suspended */
- if (udev->state >= USB_STATE_CONFIGURED)
- usb_disable_device(udev, 0);
- return 0;
-}
-
-struct device_driver usb_generic_driver = {
- .owner = THIS_MODULE,
- .name = "usb",
- .bus = &usb_bus_type,
- .probe = generic_probe,
- .remove = generic_remove,
-};
-
-/* Fun hack to determine if the struct device is a
- * usb device or a usb interface. */
-int usb_generic_driver_data;
-
#ifdef CONFIG_HOTPLUG
/*
@@ -81,6 +50,7 @@ static ssize_t store_new_id(struct device_driver *driver,
u32 idVendor = 0;
u32 idProduct = 0;
int fields = 0;
+ int retval = 0;
fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
if (fields < 2)
@@ -100,10 +70,12 @@ static ssize_t store_new_id(struct device_driver *driver,
spin_unlock(&usb_drv->dynids.lock);
if (get_driver(driver)) {
- driver_attach(driver);
+ retval = driver_attach(driver);
put_driver(driver);
}
+ if (retval)
+ return retval;
return count;
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
@@ -116,7 +88,7 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
goto exit;
if (usb_drv->probe != NULL)
- error = sysfs_create_file(&usb_drv->driver.kobj,
+ error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
&driver_attr_new_id.attr);
exit:
return error;
@@ -128,7 +100,7 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
return;
if (usb_drv->probe != NULL)
- sysfs_remove_file(&usb_drv->driver.kobj,
+ sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
&driver_attr_new_id.attr);
}
@@ -175,21 +147,57 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
}
-/* called from driver core with usb_bus_type.subsys writelock */
+/* called from driver core with dev locked */
+static int usb_probe_device(struct device *dev)
+{
+ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
+ struct usb_device *udev;
+ int error = -ENODEV;
+
+ dev_dbg(dev, "%s\n", __FUNCTION__);
+
+ if (!is_usb_device(dev)) /* Sanity check */
+ return error;
+
+ udev = to_usb_device(dev);
+
+ /* TODO: Add real matching code */
+
+ /* The device should always appear to be in use
+ * unless the driver suports autosuspend.
+ */
+ udev->pm_usage_cnt = !(udriver->supports_autosuspend);
+
+ error = udriver->probe(udev);
+ return error;
+}
+
+/* called from driver core with dev locked */
+static int usb_unbind_device(struct device *dev)
+{
+ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
+
+ udriver->disconnect(to_usb_device(dev));
+ return 0;
+}
+
+
+/* called from driver core with dev locked */
static int usb_probe_interface(struct device *dev)
{
- struct usb_interface * intf = to_usb_interface(dev);
- struct usb_driver * driver = to_usb_driver(dev->driver);
+ struct usb_driver *driver = to_usb_driver(dev->driver);
+ struct usb_interface *intf;
+ struct usb_device *udev;
const struct usb_device_id *id;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __FUNCTION__);
- if (!driver->probe)
+ if (is_usb_device(dev)) /* Sanity check */
return error;
- /* FIXME we'd much prefer to just resume it ... */
- if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
id = usb_match_id(intf, driver->id_table);
if (!id)
@@ -197,48 +205,165 @@ static int usb_probe_interface(struct device *dev)
if (id) {
dev_dbg(dev, "%s - got id\n", __FUNCTION__);
+ error = usb_autoresume_device(udev, 1);
+ if (error)
+ return error;
+
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
intf->condition = USB_INTERFACE_BINDING;
+
+ /* The interface should always appear to be in use
+ * unless the driver suports autosuspend.
+ */
+ intf->pm_usage_cnt = !(driver->supports_autosuspend);
+
error = driver->probe(intf, id);
if (error) {
mark_quiesced(intf);
+ intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
} else
intf->condition = USB_INTERFACE_BOUND;
+
+ usb_autosuspend_device(udev, 1);
}
return error;
}
-/* called from driver core with usb_bus_type.subsys writelock */
+/* called from driver core with dev locked */
static int usb_unbind_interface(struct device *dev)
{
+ struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
- struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+ struct usb_device *udev;
+ int error;
intf->condition = USB_INTERFACE_UNBINDING;
+ /* Autoresume for set_interface call below */
+ udev = interface_to_usbdev(intf);
+ error = usb_autoresume_device(udev, 1);
+
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
- if (driver && driver->disconnect)
- driver->disconnect(intf);
+ driver->disconnect(intf);
/* reset other interface state */
usb_set_interface(interface_to_usbdev(intf),
intf->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(intf, NULL);
+
intf->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(intf);
+ intf->needs_remote_wakeup = 0;
+
+ if (!error)
+ usb_autosuspend_device(udev, 1);
return 0;
}
+/**
+ * usb_driver_claim_interface - bind a driver to an interface
+ * @driver: the driver to be bound
+ * @iface: the interface to which it will be bound; must be in the
+ * usb device's active configuration
+ * @priv: driver data associated with that interface
+ *
+ * This is used by usb device drivers that need to claim more than one
+ * interface on a device when probing (audio and acm are current examples).
+ * No device driver should directly modify internal usb_interface or
+ * usb_device structure members.
+ *
+ * Few drivers should need to use this routine, since the most natural
+ * way to bind to an interface is to return the private data from
+ * the driver's probe() method.
+ *
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock. So driver probe() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
+ */
+int usb_driver_claim_interface(struct usb_driver *driver,
+ struct usb_interface *iface, void* priv)
+{
+ struct device *dev = &iface->dev;
+ struct usb_device *udev = interface_to_usbdev(iface);
+ int retval = 0;
+
+ if (dev->driver)
+ return -EBUSY;
+
+ dev->driver = &driver->drvwrap.driver;
+ usb_set_intfdata(iface, priv);
+
+ usb_pm_lock(udev);
+ iface->condition = USB_INTERFACE_BOUND;
+ mark_active(iface);
+ iface->pm_usage_cnt = !(driver->supports_autosuspend);
+ usb_pm_unlock(udev);
+
+ /* if interface was already added, bind now; else let
+ * the future device_add() bind it, bypassing probe()
+ */
+ if (device_is_registered(dev))
+ retval = device_bind_driver(dev);
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_driver_claim_interface);
+
+/**
+ * usb_driver_release_interface - unbind a driver from an interface
+ * @driver: the driver to be unbound
+ * @iface: the interface from which it will be unbound
+ *
+ * This can be used by drivers to release an interface without waiting
+ * for their disconnect() methods to be called. In typical cases this
+ * also causes the driver disconnect() method to be called.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock. So driver disconnect() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
+ */
+void usb_driver_release_interface(struct usb_driver *driver,
+ struct usb_interface *iface)
+{
+ struct device *dev = &iface->dev;
+ struct usb_device *udev = interface_to_usbdev(iface);
+
+ /* this should never happen, don't release something that's not ours */
+ if (!dev->driver || dev->driver != &driver->drvwrap.driver)
+ return;
+
+ /* don't release from within disconnect() */
+ if (iface->condition != USB_INTERFACE_BOUND)
+ return;
+
+ /* don't release if the interface hasn't been added yet */
+ if (device_is_registered(dev)) {
+ iface->condition = USB_INTERFACE_UNBINDING;
+ device_release_driver(dev);
+ }
+
+ dev->driver = NULL;
+ usb_set_intfdata(iface, NULL);
+
+ usb_pm_lock(udev);
+ iface->condition = USB_INTERFACE_UNBOUND;
+ mark_quiesced(iface);
+ iface->needs_remote_wakeup = 0;
+ usb_pm_unlock(udev);
+}
+EXPORT_SYMBOL(usb_driver_release_interface);
+
/* returns 0 if no match, 1 if match */
static int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
@@ -382,35 +507,223 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
int usb_device_match(struct device *dev, struct device_driver *drv)
{
+ /* devices and interfaces are handled separately */
+ if (is_usb_device(dev)) {
+
+ /* interface drivers never match devices */
+ if (!is_usb_device_driver(drv))
+ return 0;
+
+ /* TODO: Add real matching code */
+ return 1;
+
+ } else {
+ struct usb_interface *intf;
+ struct usb_driver *usb_drv;
+ const struct usb_device_id *id;
+
+ /* device drivers never match interfaces */
+ if (is_usb_device_driver(drv))
+ return 0;
+
+ intf = to_usb_interface(dev);
+ usb_drv = to_usb_driver(drv);
+
+ id = usb_match_id(intf, usb_drv->id_table);
+ if (id)
+ return 1;
+
+ id = usb_match_dynamic_id(intf, usb_drv);
+ if (id)
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+
+/*
+ * This sends an uevent to userspace, typically helping to load driver
+ * or other modules, configure the device, and more. Drivers can provide
+ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
+ *
+ * We're called either from khubd (the typical case) or from root hub
+ * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
+ * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
+ * device (and this configuration!) are still present.
+ */
+static int usb_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
struct usb_interface *intf;
- struct usb_driver *usb_drv;
- const struct usb_device_id *id;
+ struct usb_device *usb_dev;
+ struct usb_host_interface *alt;
+ int i = 0;
+ int length = 0;
- /* check for generic driver, which we don't match any device with */
- if (drv == &usb_generic_driver)
- return 0;
+ if (!dev)
+ return -ENODEV;
- intf = to_usb_interface(dev);
- usb_drv = to_usb_driver(drv);
+ /* driver is often null here; dev_dbg() would oops */
+ pr_debug ("usb %s: uevent\n", dev->bus_id);
- id = usb_match_id(intf, usb_drv->id_table);
- if (id)
- return 1;
+ if (is_usb_device(dev)) {
+ usb_dev = to_usb_device(dev);
+ alt = NULL;
+ } else {
+ intf = to_usb_interface(dev);
+ usb_dev = interface_to_usbdev(intf);
+ alt = intf->cur_altsetting;
+ }
+
+ if (usb_dev->devnum < 0) {
+ pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+ return -ENODEV;
+ }
+ if (!usb_dev->bus) {
+ pr_debug ("usb %s: bus removed?\n", dev->bus_id);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_USB_DEVICEFS
+ /* If this is available, userspace programs can directly read
+ * all the device descriptors we don't tell them about. Or
+ * even act as usermode drivers.
+ *
+ * FIXME reduce hardwired intelligence here
+ */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "DEVICE=/proc/bus/usb/%03d/%03d",
+ usb_dev->bus->busnum, usb_dev->devnum))
+ return -ENOMEM;
+#endif
+
+ /* per-device configurations are common */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PRODUCT=%x/%x/%x",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+ return -ENOMEM;
+
+ /* class-based driver binding models */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "TYPE=%d/%d/%d",
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol))
+ return -ENOMEM;
+
+ if (!is_usb_device(dev)) {
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "INTERFACE=%d/%d/%d",
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice),
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol,
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;
+ }
+
+ envp[i] = NULL;
- id = usb_match_dynamic_id(intf, usb_drv);
- if (id)
- return 1;
return 0;
}
+#else
+
+static int usb_uevent(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_HOTPLUG */
+
+/**
+ * usb_register_device_driver - register a USB device (not interface) driver
+ * @new_udriver: USB operations for the device driver
+ * @owner: module owner of this driver.
+ *
+ * Registers a USB device driver with the USB core. The list of
+ * unattached devices will be rescanned whenever a new driver is
+ * added, allowing the new driver to attach to any recognized devices.
+ * Returns a negative error code on failure and 0 on success.
+ */
+int usb_register_device_driver(struct usb_device_driver *new_udriver,
+ struct module *owner)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ new_udriver->drvwrap.for_devices = 1;
+ new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
+ new_udriver->drvwrap.driver.bus = &usb_bus_type;
+ new_udriver->drvwrap.driver.probe = usb_probe_device;
+ new_udriver->drvwrap.driver.remove = usb_unbind_device;
+ new_udriver->drvwrap.driver.owner = owner;
+
+ retval = driver_register(&new_udriver->drvwrap.driver);
+
+ if (!retval) {
+ pr_info("%s: registered new device driver %s\n",
+ usbcore_name, new_udriver->name);
+ usbfs_update_special();
+ } else {
+ printk(KERN_ERR "%s: error %d registering device "
+ " driver %s\n",
+ usbcore_name, retval, new_udriver->name);
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_register_device_driver);
+
+/**
+ * usb_deregister_device_driver - unregister a USB device (not interface) driver
+ * @udriver: USB operations of the device driver to unregister
+ * Context: must be able to sleep
+ *
+ * Unlinks the specified driver from the internal USB driver list.
+ */
+void usb_deregister_device_driver(struct usb_device_driver *udriver)
+{
+ pr_info("%s: deregistering device driver %s\n",
+ usbcore_name, udriver->name);
+
+ driver_unregister(&udriver->drvwrap.driver);
+ usbfs_update_special();
+}
+EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
+
/**
- * usb_register_driver - register a USB driver
- * @new_driver: USB operations for the driver
+ * usb_register_driver - register a USB interface driver
+ * @new_driver: USB operations for the interface driver
* @owner: module owner of this driver.
*
- * Registers a USB driver with the USB core. The list of unattached
- * interfaces will be rescanned whenever a new driver is added, allowing
- * the new driver to attach to any recognized devices.
+ * Registers a USB interface driver with the USB core. The list of
+ * unattached interfaces will be rescanned whenever a new driver is
+ * added, allowing the new driver to attach to any recognized interfaces.
* Returns a negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
@@ -424,23 +737,25 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
if (usb_disabled())
return -ENODEV;
- new_driver->driver.name = (char *)new_driver->name;
- new_driver->driver.bus = &usb_bus_type;
- new_driver->driver.probe = usb_probe_interface;
- new_driver->driver.remove = usb_unbind_interface;
- new_driver->driver.owner = owner;
+ new_driver->drvwrap.for_devices = 0;
+ new_driver->drvwrap.driver.name = (char *) new_driver->name;
+ new_driver->drvwrap.driver.bus = &usb_bus_type;
+ new_driver->drvwrap.driver.probe = usb_probe_interface;
+ new_driver->drvwrap.driver.remove = usb_unbind_interface;
+ new_driver->drvwrap.driver.owner = owner;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
- retval = driver_register(&new_driver->driver);
+ retval = driver_register(&new_driver->drvwrap.driver);
if (!retval) {
- pr_info("%s: registered new driver %s\n",
+ pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);
usbfs_update_special();
usb_create_newid_file(new_driver);
} else {
- printk(KERN_ERR "%s: error %d registering driver %s\n",
+ printk(KERN_ERR "%s: error %d registering interface "
+ " driver %s\n",
usbcore_name, retval, new_driver->name);
}
@@ -449,8 +764,8 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
/**
- * usb_deregister - unregister a USB driver
- * @driver: USB operations of the driver to unregister
+ * usb_deregister - unregister a USB interface driver
+ * @driver: USB operations of the interface driver to unregister
* Context: must be able to sleep
*
* Unlinks the specified driver from the internal USB driver list.
@@ -461,12 +776,554 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
*/
void usb_deregister(struct usb_driver *driver)
{
- pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
+ pr_info("%s: deregistering interface driver %s\n",
+ usbcore_name, driver->name);
usb_remove_newid_file(driver);
usb_free_dynids(driver);
- driver_unregister(&driver->driver);
+ driver_unregister(&driver->drvwrap.driver);
usbfs_update_special();
}
EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
+
+#ifdef CONFIG_PM
+
+/* Caller has locked udev's pm_mutex */
+static int suspend_device(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_device_driver *udriver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state == USB_STATE_SUSPENDED)
+ goto done;
+
+ /* For devices that don't have a driver, we do a standard suspend. */
+ if (udev->dev.driver == NULL) {
+ udev->do_remote_wakeup = 0;
+ status = usb_port_suspend(udev);
+ goto done;
+ }
+
+ udriver = to_usb_device_driver(udev->dev.driver);
+ status = udriver->suspend(udev, msg);
+
+done:
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ udev->dev.power.power_state.event = msg.event;
+ return status;
+}
+
+/* Caller has locked udev's pm_mutex */
+static int resume_device(struct usb_device *udev)
+{
+ struct usb_device_driver *udriver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state != USB_STATE_SUSPENDED)
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+ if (udev->dev.driver == NULL) {
+ status = -ENOTCONN;
+ goto done;
+ }
+
+ udriver = to_usb_device_driver(udev->dev.driver);
+ status = udriver->resume(udev);
+
+done:
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ udev->dev.power.power_state.event = PM_EVENT_ON;
+ return status;
+}
+
+/* Caller has locked intf's usb_device's pm mutex */
+static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
+{
+ struct usb_driver *driver;
+ int status = 0;
+
+ /* with no hardware, USB interfaces only use FREEZE and ON states */
+ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+ !is_active(intf))
+ goto done;
+
+ if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */
+ goto done;
+ driver = to_usb_driver(intf->dev.driver);
+
+ if (driver->suspend && driver->resume) {
+ status = driver->suspend(intf, msg);
+ if (status == 0)
+ mark_quiesced(intf);
+ else if (!interface_to_usbdev(intf)->auto_pm)
+ dev_err(&intf->dev, "%s error %d\n",
+ "suspend", status);
+ } else {
+ // FIXME else if there's no suspend method, disconnect...
+ // Not possible if auto_pm is set...
+ dev_warn(&intf->dev, "no suspend for driver %s?\n",
+ driver->name);
+ mark_quiesced(intf);
+ }
+
+done:
+ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ intf->dev.power.power_state.event = msg.event;
+ return status;
+}
+
+/* Caller has locked intf's usb_device's pm_mutex */
+static int resume_interface(struct usb_interface *intf)
+{
+ struct usb_driver *driver;
+ int status = 0;
+
+ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+ is_active(intf))
+ goto done;
+
+ /* Don't let autoresume interfere with unbinding */
+ if (intf->condition == USB_INTERFACE_UNBINDING)
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+ if (intf->condition == USB_INTERFACE_UNBOUND) {
+ status = -ENOTCONN;
+ goto done;
+ }
+ driver = to_usb_driver(intf->dev.driver);
+
+ if (driver->resume) {
+ status = driver->resume(intf);
+ if (status)
+ dev_err(&intf->dev, "%s error %d\n",
+ "resume", status);
+ else
+ mark_active(intf);
+ } else {
+ dev_warn(&intf->dev, "no resume for driver %s?\n",
+ driver->name);
+ mark_active(intf);
+ }
+
+done:
+ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ intf->dev.power.power_state.event = PM_EVENT_ON;
+ return status;
+}
+
+/**
+ * usb_suspend_both - suspend a USB device and its interfaces
+ * @udev: the usb_device to suspend
+ * @msg: Power Management message describing this state transition
+ *
+ * This is the central routine for suspending USB devices. It calls the
+ * suspend methods for all the interface drivers in @udev and then calls
+ * the suspend method for @udev itself. If an error occurs at any stage,
+ * all the interfaces which were suspended are resumed so that they remain
+ * in the same state as the device.
+ *
+ * If an autosuspend is in progress (@udev->auto_pm is set), the routine
+ * checks first to make sure that neither the device itself or any of its
+ * active interfaces is in use (pm_usage_cnt is greater than 0). If they
+ * are, the autosuspend fails.
+ *
+ * If the suspend succeeds, the routine recursively queues an autosuspend
+ * request for @udev's parent device, thereby propagating the change up
+ * the device tree. If all of the parent's children are now suspended,
+ * the parent will autosuspend in turn.
+ *
+ * The suspend method calls are subject to mutual exclusion under control
+ * of @udev's pm_mutex. Many of these calls are also under the protection
+ * of @udev's device lock (including all requests originating outside the
+ * USB subsystem), but autosuspend requests generated by a child device or
+ * interface driver may not be. Usbcore will insure that the method calls
+ * do not arrive during bind, unbind, or reset operations. However, drivers
+ * must be prepared to handle suspend calls arriving at unpredictable times.
+ * The only way to block such calls is to do an autoresume (preventing
+ * autosuspends) while holding @udev's device lock (preventing outside
+ * suspends).
+ *
+ * The caller must hold @udev->pm_mutex.
+ *
+ * This routine can run only in process context.
+ */
+int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
+{
+ int status = 0;
+ int i = 0;
+ struct usb_interface *intf;
+ struct usb_device *parent = udev->parent;
+
+ cancel_delayed_work(&udev->autosuspend);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return 0;
+ if (udev->state == USB_STATE_SUSPENDED)
+ return 0;
+
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+
+ /* For autosuspend, fail fast if anything is in use.
+ * Also fail if any interfaces require remote wakeup but it
+ * isn't available. */
+ if (udev->auto_pm) {
+ if (udev->pm_usage_cnt > 0)
+ return -EBUSY;
+ if (udev->actconfig) {
+ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ if (!is_active(intf))
+ continue;
+ if (intf->pm_usage_cnt > 0)
+ return -EBUSY;
+ if (intf->needs_remote_wakeup &&
+ !udev->do_remote_wakeup) {
+ dev_dbg(&udev->dev,
+ "remote wakeup needed for autosuspend\n");
+ return -EOPNOTSUPP;
+ }
+ }
+ i = 0;
+ }
+ }
+
+ /* Suspend all the interfaces and then udev itself */
+ if (udev->actconfig) {
+ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ status = suspend_interface(intf, msg);
+ if (status != 0)
+ break;
+ }
+ }
+ if (status == 0)
+ status = suspend_device(udev, msg);
+
+ /* If the suspend failed, resume interfaces that did get suspended */
+ if (status != 0) {
+ while (--i >= 0) {
+ intf = udev->actconfig->interface[i];
+ resume_interface(intf);
+ }
+
+ /* If the suspend succeeded, propagate it up the tree */
+ } else if (parent)
+ usb_autosuspend_device(parent, 0);
+
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ return status;
+}
+
+/**
+ * usb_resume_both - resume a USB device and its interfaces
+ * @udev: the usb_device to resume
+ *
+ * This is the central routine for resuming USB devices. It calls the
+ * the resume method for @udev and then calls the resume methods for all
+ * the interface drivers in @udev.
+ *
+ * Before starting the resume, the routine calls itself recursively for
+ * the parent device of @udev, thereby propagating the change up the device
+ * tree and assuring that @udev will be able to resume. If the parent is
+ * unable to resume successfully, the routine fails.
+ *
+ * The resume method calls are subject to mutual exclusion under control
+ * of @udev's pm_mutex. Many of these calls are also under the protection
+ * of @udev's device lock (including all requests originating outside the
+ * USB subsystem), but autoresume requests generated by a child device or
+ * interface driver may not be. Usbcore will insure that the method calls
+ * do not arrive during bind, unbind, or reset operations. However, drivers
+ * must be prepared to handle resume calls arriving at unpredictable times.
+ * The only way to block such calls is to do an autoresume (preventing
+ * other autoresumes) while holding @udev's device lock (preventing outside
+ * resumes).
+ *
+ * The caller must hold @udev->pm_mutex.
+ *
+ * This routine can run only in process context.
+ */
+int usb_resume_both(struct usb_device *udev)
+{
+ int status = 0;
+ int i;
+ struct usb_interface *intf;
+ struct usb_device *parent = udev->parent;
+
+ cancel_delayed_work(&udev->autosuspend);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+
+ /* Propagate the resume up the tree, if necessary */
+ if (udev->state == USB_STATE_SUSPENDED) {
+ if (parent) {
+ usb_pm_lock(parent);
+ parent->auto_pm = 1;
+ status = usb_resume_both(parent);
+ } else {
+
+ /* We can't progagate beyond the USB subsystem,
+ * so if a root hub's controller is suspended
+ * then we're stuck. */
+ if (udev->dev.parent->power.power_state.event !=
+ PM_EVENT_ON)
+ status = -EHOSTUNREACH;
+ }
+ if (status == 0)
+ status = resume_device(udev);
+ if (parent)
+ usb_pm_unlock(parent);
+ } else {
+
+ /* Needed only for setting udev->dev.power.power_state.event
+ * and for possible debugging message. */
+ status = resume_device(udev);
+ }
+
+ /* Now the parent won't suspend until we are finished */
+
+ if (status == 0 && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ resume_interface(intf);
+ }
+ }
+
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ return status;
+}
+
+#ifdef CONFIG_USB_SUSPEND
+
+/**
+ * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
+ * @udev: the usb_device to autosuspend
+ * @dec_usage_cnt: flag to decrement @udev's PM-usage counter
+ *
+ * This routine should be called when a core subsystem is finished using
+ * @udev and wants to allow it to autosuspend. Examples would be when
+ * @udev's device file in usbfs is closed or after a configuration change.
+ *
+ * @dec_usage_cnt should be 1 if the subsystem previously incremented
+ * @udev's usage counter (such as by passing 1 to usb_autoresume_device);
+ * otherwise it should be 0.
+ *
+ * If the usage counter for @udev or any of its active interfaces is greater
+ * than 0, the autosuspend request will not be queued. (If an interface
+ * driver does not support autosuspend then its usage counter is permanently
+ * positive.) Likewise, if an interface driver requires remote-wakeup
+ * capability during autosuspend but remote wakeup is disabled, the
+ * autosuspend will fail.
+ *
+ * Often the caller will hold @udev's device lock, but this is not
+ * necessary.
+ *
+ * This routine can run only in process context.
+ */
+void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt)
+{
+ usb_pm_lock(udev);
+ udev->pm_usage_cnt -= dec_usage_cnt;
+ if (udev->pm_usage_cnt <= 0)
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ USB_AUTOSUSPEND_DELAY);
+ usb_pm_unlock(udev);
+ // dev_dbg(&udev->dev, "%s: cnt %d\n",
+ // __FUNCTION__, udev->pm_usage_cnt);
+}
+
+/**
+ * usb_autoresume_device - immediately autoresume a USB device and its interfaces
+ * @udev: the usb_device to autoresume
+ * @inc_usage_cnt: flag to increment @udev's PM-usage counter
+ *
+ * This routine should be called when a core subsystem wants to use @udev
+ * and needs to guarantee that it is not suspended. In addition, the
+ * caller can prevent @udev from being autosuspended subsequently. (Note
+ * that this will not prevent suspend events originating in the PM core.)
+ * Examples would be when @udev's device file in usbfs is opened (autosuspend
+ * should be prevented until the file is closed) or when a remote-wakeup
+ * request is received (later autosuspends should not be prevented).
+ *
+ * @inc_usage_cnt should be 1 to increment @udev's usage counter and prevent
+ * autosuspends. This prevention will persist until the usage counter is
+ * decremented again (such as by passing 1 to usb_autosuspend_device).
+ * Otherwise @inc_usage_cnt should be 0 to leave the usage counter unchanged.
+ * Regardless, if the autoresume fails then the usage counter is not
+ * incremented.
+ *
+ * Often the caller will hold @udev's device lock, but this is not
+ * necessary (and attempting it might cause deadlock).
+ *
+ * This routine can run only in process context.
+ */
+int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt)
+{
+ int status;
+
+ usb_pm_lock(udev);
+ udev->pm_usage_cnt += inc_usage_cnt;
+ udev->auto_pm = 1;
+ status = usb_resume_both(udev);
+ if (status != 0)
+ udev->pm_usage_cnt -= inc_usage_cnt;
+ usb_pm_unlock(udev);
+ // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
+ // __FUNCTION__, status, udev->pm_usage_cnt);
+ return status;
+}
+
+/**
+ * usb_autopm_put_interface - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine should be called by an interface driver when it is
+ * finished using @intf and wants to allow it to autosuspend. A typical
+ * example would be a character-device driver when its device file is
+ * closed.
+ *
+ * The routine decrements @intf's usage counter. When the counter reaches
+ * 0, a delayed autosuspend request for @intf's device is queued. When
+ * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all
+ * the other usage counters for the sibling interfaces and @intf's
+ * usb_device, the device and all its interfaces will be autosuspended.
+ *
+ * Note that @intf->pm_usage_cnt is owned by the interface driver. The
+ * core will not change its value other than the increment and decrement
+ * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
+ * may use this simple counter-oriented discipline or may set the value
+ * any way it likes.
+ *
+ * If the driver has set @intf->needs_remote_wakeup then autosuspend will
+ * take place only if the device's remote-wakeup facility is enabled.
+ *
+ * Suspend method calls queued by this routine can arrive at any time
+ * while @intf is resumed and its usage counter is equal to 0. They are
+ * not protected by the usb_device's lock but only by its pm_mutex.
+ * Drivers must provide their own synchronization.
+ *
+ * This routine can run only in process context.
+ */
+void usb_autopm_put_interface(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_pm_lock(udev);
+ if (intf->condition != USB_INTERFACE_UNBOUND &&
+ --intf->pm_usage_cnt <= 0) {
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ USB_AUTOSUSPEND_DELAY);
+ }
+ usb_pm_unlock(udev);
+ // dev_dbg(&intf->dev, "%s: cnt %d\n",
+ // __FUNCTION__, intf->pm_usage_cnt);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
+
+/**
+ * usb_autopm_get_interface - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine should be called by an interface driver when it wants to
+ * use @intf and needs to guarantee that it is not suspended. In addition,
+ * the routine prevents @intf from being autosuspended subsequently. (Note
+ * that this will not prevent suspend events originating in the PM core.)
+ * This prevention will persist until usb_autopm_put_interface() is called
+ * or @intf is unbound. A typical example would be a character-device
+ * driver when its device file is opened.
+ *
+ * The routine increments @intf's usage counter. So long as the counter
+ * is greater than 0, autosuspend will not be allowed for @intf or its
+ * usb_device. When the driver is finished using @intf it should call
+ * usb_autopm_put_interface() to decrement the usage counter and queue
+ * a delayed autosuspend request (if the counter is <= 0).
+ *
+ * Note that @intf->pm_usage_cnt is owned by the interface driver. The
+ * core will not change its value other than the increment and decrement
+ * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
+ * may use this simple counter-oriented discipline or may set the value
+ * any way it likes.
+ *
+ * Resume method calls generated by this routine can arrive at any time
+ * while @intf is suspended. They are not protected by the usb_device's
+ * lock but only by its pm_mutex. Drivers must provide their own
+ * synchronization.
+ *
+ * This routine can run only in process context.
+ */
+int usb_autopm_get_interface(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status;
+
+ usb_pm_lock(udev);
+ if (intf->condition == USB_INTERFACE_UNBOUND)
+ status = -ENODEV;
+ else {
+ ++intf->pm_usage_cnt;
+ udev->auto_pm = 1;
+ status = usb_resume_both(udev);
+ if (status != 0)
+ --intf->pm_usage_cnt;
+ }
+ usb_pm_unlock(udev);
+ // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
+ // __FUNCTION__, status, intf->pm_usage_cnt);
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
+
+#endif /* CONFIG_USB_SUSPEND */
+
+static int usb_suspend(struct device *dev, pm_message_t message)
+{
+ int status;
+
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ usb_pm_lock(udev);
+ udev->auto_pm = 0;
+ status = usb_suspend_both(udev, message);
+ usb_pm_unlock(udev);
+ } else
+ status = 0;
+ return status;
+}
+
+static int usb_resume(struct device *dev)
+{
+ int status;
+
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ usb_pm_lock(udev);
+ udev->auto_pm = 0;
+ status = usb_resume_both(udev);
+ usb_pm_unlock(udev);
+
+ /* Rebind drivers that had no suspend method? */
+ } else
+ status = 0;
+ return status;
+}
+
+#endif /* CONFIG_PM */
+
+struct bus_type usb_bus_type = {
+ .name = "usb",
+ .match = usb_device_match,
+ .uevent = usb_uevent,
+#ifdef CONFIG_PM
+ .suspend = usb_suspend,
+ .resume = usb_resume,
+#endif
+};
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 247b5a4913a..3ebb90149e9 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -207,9 +207,9 @@ static void ep_device_release(struct device *dev)
kfree(ep_dev);
}
-void usb_create_ep_files(struct device *parent,
- struct usb_host_endpoint *endpoint,
- struct usb_device *udev)
+int usb_create_ep_files(struct device *parent,
+ struct usb_host_endpoint *endpoint,
+ struct usb_device *udev)
{
char name[8];
struct ep_device *ep_dev;
@@ -242,19 +242,33 @@ void usb_create_ep_files(struct device *parent,
retval = device_register(&ep_dev->dev);
if (retval)
goto error;
- sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+ retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+ if (retval)
+ goto error_group;
endpoint->ep_dev = ep_dev;
/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
- sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name);
-
+ retval = sysfs_create_link(&parent->kobj,
+ &endpoint->ep_dev->dev.kobj, name);
+ if (retval)
+ goto error_link;
exit:
- return;
+ return retval;
+
+error_link:
+ sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+
+error_group:
+ device_unregister(&ep_dev->dev);
+ endpoint->ep_dev = NULL;
+ destroy_endpoint_class();
+ return retval;
error:
kfree(ep_dev);
- return;
+ destroy_endpoint_class();
+ return retval;
}
void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f65b193cde3..c376c655c5d 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -15,7 +15,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
@@ -56,7 +55,7 @@ static int usb_open(struct inode * inode, struct file * file)
return err;
}
-static struct file_operations usb_fops = {
+static const struct file_operations usb_fops = {
.owner = THIS_MODULE,
.open = usb_open,
};
@@ -195,13 +194,14 @@ int usb_register_dev(struct usb_interface *intf,
++temp;
else
temp = name;
- intf->usb_dev = device_create(usb_class->class, &intf->dev,
- MKDEV(USB_MAJOR, minor), "%s", temp);
- if (IS_ERR(intf->usb_dev)) {
+ intf->class_dev = class_device_create(usb_class->class, NULL,
+ MKDEV(USB_MAJOR, minor),
+ &intf->dev, "%s", temp);
+ if (IS_ERR(intf->class_dev)) {
spin_lock (&minor_lock);
usb_minors[intf->minor] = NULL;
spin_unlock (&minor_lock);
- retval = PTR_ERR(intf->usb_dev);
+ retval = PTR_ERR(intf->class_dev);
}
exit:
return retval;
@@ -242,8 +242,8 @@ void usb_deregister_dev(struct usb_interface *intf,
spin_unlock (&minor_lock);
snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
- device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
- intf->usb_dev = NULL;
+ class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+ intf->class_dev = NULL;
intf->minor = -1;
destroy_usb_class();
}
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
new file mode 100644
index 00000000000..16332cc5794
--- /dev/null
+++ b/drivers/usb/core/generic.c
@@ -0,0 +1,208 @@
+/*
+ * drivers/usb/generic.c - generic driver for USB devices (not interfaces)
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * based on drivers/usb/usb.c which had the following copyrights:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2004
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/usb.h>
+#include "usb.h"
+
+static inline const char *plural(int n)
+{
+ return (n == 1 ? "" : "s");
+}
+
+static int choose_configuration(struct usb_device *udev)
+{
+ int i;
+ int num_configs;
+ int insufficient_power = 0;
+ struct usb_host_config *c, *best;
+
+ best = NULL;
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+ struct usb_interface_descriptor *desc = NULL;
+
+ /* It's possible that a config has no interfaces! */
+ if (c->desc.bNumInterfaces > 0)
+ desc = &c->intf_cache[0]->altsetting->desc;
+
+ /*
+ * HP's USB bus-powered keyboard has only one configuration
+ * and it claims to be self-powered; other devices may have
+ * similar errors in their descriptors. If the next test
+ * were allowed to execute, such configurations would always
+ * be rejected and the devices would not work as expected.
+ * In the meantime, we run the risk of selecting a config
+ * that requires external power at a time when that power
+ * isn't available. It seems to be the lesser of two evils.
+ *
+ * Bugzilla #6448 reports a device that appears to crash
+ * when it receives a GET_DEVICE_STATUS request! We don't
+ * have any other way to tell whether a device is self-powered,
+ * but since we don't use that information anywhere but here,
+ * the call has been removed.
+ *
+ * Maybe the GET_DEVICE_STATUS call and the test below can
+ * be reinstated when device firmwares become more reliable.
+ * Don't hold your breath.
+ */
+#if 0
+ /* Rule out self-powered configs for a bus-powered device */
+ if (bus_powered && (c->desc.bmAttributes &
+ USB_CONFIG_ATT_SELFPOWER))
+ continue;
+#endif
+
+ /*
+ * The next test may not be as effective as it should be.
+ * Some hubs have errors in their descriptor, claiming
+ * to be self-powered when they are really bus-powered.
+ * We will overestimate the amount of current such hubs
+ * make available for each port.
+ *
+ * This is a fairly benign sort of failure. It won't
+ * cause us to reject configurations that we should have
+ * accepted.
+ */
+
+ /* Rule out configs that draw too much bus current */
+ if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+ insufficient_power++;
+ continue;
+ }
+
+ /* If the first config's first interface is COMM/2/0xff
+ * (MSFT RNDIS), rule it out unless Linux has host-side
+ * RNDIS support. */
+ if (i == 0 && desc
+ && desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff) {
+#ifndef CONFIG_USB_NET_RNDIS_HOST
+ continue;
+#else
+ best = c;
+#endif
+ }
+
+ /* From the remaining configs, choose the first one whose
+ * first interface is for a non-vendor-specific class.
+ * Reason: Linux is more likely to have a class driver
+ * than a vendor-specific driver. */
+ else if (udev->descriptor.bDeviceClass !=
+ USB_CLASS_VENDOR_SPEC &&
+ (!desc || desc->bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC)) {
+ best = c;
+ break;
+ }
+
+ /* If all the remaining configs are vendor-specific,
+ * choose the first one. */
+ else if (!best)
+ best = c;
+ }
+
+ if (insufficient_power > 0)
+ dev_info(&udev->dev, "rejected %d configuration%s "
+ "due to insufficient available bus power\n",
+ insufficient_power, plural(insufficient_power));
+
+ if (best) {
+ i = best->desc.bConfigurationValue;
+ dev_info(&udev->dev,
+ "configuration #%d chosen from %d choice%s\n",
+ i, num_configs, plural(num_configs));
+ } else {
+ i = -1;
+ dev_warn(&udev->dev,
+ "no configuration chosen from %d choice%s\n",
+ num_configs, plural(num_configs));
+ }
+ return i;
+}
+
+static int generic_probe(struct usb_device *udev)
+{
+ int err, c;
+
+ /* put device-specific files into sysfs */
+ usb_create_sysfs_dev_files(udev);
+
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ c = choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ c, err);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+
+ /* USB device state == configured ... usable */
+ usb_notify_add_device(udev);
+
+ return 0;
+}
+
+static void generic_disconnect(struct usb_device *udev)
+{
+ usb_notify_remove_device(udev);
+
+ /* if this is only an unbind, not a physical disconnect, then
+ * unconfigure the device */
+ if (udev->actconfig)
+ usb_set_configuration(udev, 0);
+
+ usb_remove_sysfs_dev_files(udev);
+}
+
+#ifdef CONFIG_PM
+
+static int generic_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ /* USB devices enter SUSPEND state through their hubs, but can be
+ * marked for FREEZE as soon as their children are already idled.
+ * But those semantics are useless, so we equate the two (sigh).
+ */
+ return usb_port_suspend(udev);
+}
+
+static int generic_resume(struct usb_device *udev)
+{
+ return usb_port_resume(udev);
+}
+
+#endif /* CONFIG_PM */
+
+struct usb_device_driver usb_generic_driver = {
+ .name = "usb",
+ .probe = generic_probe,
+ .disconnect = generic_disconnect,
+#ifdef CONFIG_PM
+ .suspend = generic_suspend,
+ .resume = generic_resume,
+#endif
+ .supports_autosuspend = 1,
+};
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 66b78404ab3..edf4300a3f7 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -16,7 +16,6 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -126,7 +125,7 @@ int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
pci_set_master (dev);
- retval = usb_add_hcd (hcd, dev->irq, SA_SHIRQ);
+ retval = usb_add_hcd (hcd, dev->irq, IRQF_SHARED);
if (retval != 0)
goto err4;
return retval;
@@ -282,7 +281,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
(void) usb_hcd_pci_resume (dev);
}
- } else {
+ } else if (hcd->state != HC_STATE_HALT) {
dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
hcd->state);
WARN_ON(1);
@@ -414,4 +413,20 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
#endif /* CONFIG_PM */
+/**
+ * usb_hcd_pci_shutdown - shutdown host controller
+ * @dev: USB Host Controller being shutdown
+ */
+void usb_hcd_pci_shutdown (struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+ if (!hcd)
+ return;
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_shutdown);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 4bf914d00a1..37f9f5e7425 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -22,7 +22,6 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/kernel.h>
@@ -37,6 +36,7 @@
#include <linux/mutex.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
+#include <linux/platform_device.h>
#include <linux/usb.h>
@@ -345,7 +345,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
- u8 tbuf [sizeof (struct usb_hub_descriptor)];
+ u8 tbuf [sizeof (struct usb_hub_descriptor)]
+ __attribute__((aligned(4)));
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
@@ -633,31 +634,20 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/*-------------------------------------------------------------------------*/
-/* Asynchronous unlinks of root-hub control URBs are legal, but they
- * don't do anything. Status URB unlinks must be made in process context
- * with interrupts enabled.
+/* Unlinks of root-hub control URBs are legal, but they don't do anything
+ * since these URBs always execute synchronously.
*/
static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
- if (in_interrupt())
- return 0; /* nothing to do */
-
- spin_lock_irq(&urb->lock); /* from usb_kill_urb */
- ++urb->reject;
- spin_unlock_irq(&urb->lock);
-
- wait_event(usb_kill_urb_queue,
- atomic_read(&urb->use_count) == 0);
+ unsigned long flags;
- spin_lock_irq(&urb->lock);
- --urb->reject;
- spin_unlock_irq(&urb->lock);
+ if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+ ; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
- del_timer_sync (&hcd->rh_timer);
- local_irq_disable ();
+ del_timer (&hcd->rh_timer);
+ local_irq_save (flags);
spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
@@ -667,7 +657,7 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
spin_unlock (&hcd_root_hub_lock);
if (urb)
usb_hcd_giveback_urb (hcd, urb, NULL);
- local_irq_enable ();
+ local_irq_restore (flags);
}
return 0;
@@ -675,31 +665,6 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
/*-------------------------------------------------------------------------*/
-/* exported only within usbcore */
-struct usb_bus *usb_bus_get(struct usb_bus *bus)
-{
- if (bus)
- kref_get(&bus->kref);
- return bus;
-}
-
-static void usb_host_release(struct kref *kref)
-{
- struct usb_bus *bus = container_of(kref, struct usb_bus, kref);
-
- if (bus->release)
- bus->release(bus);
-}
-
-/* exported only within usbcore */
-void usb_bus_put(struct usb_bus *bus)
-{
- if (bus)
- kref_put(&bus->kref, usb_host_release);
-}
-
-/*-------------------------------------------------------------------------*/
-
static struct class *usb_host_class;
int usb_host_init(void)
@@ -731,39 +696,12 @@ static void usb_bus_init (struct usb_bus *bus)
bus->devnum_next = 1;
bus->root_hub = NULL;
- bus->hcpriv = NULL;
bus->busnum = -1;
bus->bandwidth_allocated = 0;
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD (&bus->bus_list);
-
- kref_init(&bus->kref);
-}
-
-/**
- * usb_alloc_bus - creates a new USB host controller structure
- * @op: pointer to a struct usb_operations that this bus structure should use
- * Context: !in_interrupt()
- *
- * Creates a USB host controller bus structure with the specified
- * usb_operations and initializes all the necessary internal objects.
- *
- * If no memory is available, NULL is returned.
- *
- * The caller should call usb_put_bus() when it is finished with the structure.
- */
-struct usb_bus *usb_alloc_bus (struct usb_operations *op)
-{
- struct usb_bus *bus;
-
- bus = kzalloc (sizeof *bus, GFP_KERNEL);
- if (!bus)
- return NULL;
- usb_bus_init (bus);
- bus->op = op;
- return bus;
}
/*-------------------------------------------------------------------------*/
@@ -898,8 +836,7 @@ void usb_enable_root_hub_irq (struct usb_bus *bus)
struct usb_hcd *hcd;
hcd = container_of (bus, struct usb_hcd, self);
- if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
- hcd->state != HC_STATE_HALT)
+ if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
hcd->driver->hub_irq_enable (hcd);
}
@@ -1113,10 +1050,10 @@ static void urb_unlink (struct urb *urb)
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
-static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
- struct usb_hcd *hcd = urb->dev->bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
struct usb_host_endpoint *ep;
unsigned long flags;
@@ -1187,7 +1124,7 @@ doit:
/* lower level hcd code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.controller->dma_mask) {
+ if (hcd->self.uses_dma) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
@@ -1222,9 +1159,10 @@ done:
/*-------------------------------------------------------------------------*/
/* called in any context */
-static int hcd_get_frame_number (struct usb_device *udev)
+int usb_hcd_get_frame_number (struct usb_device *udev)
{
- struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
if (!HC_IS_RUNNING (hcd->state))
return -ESHUTDOWN;
return hcd->driver->get_frame_number (hcd);
@@ -1264,7 +1202,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
* caller guarantees urb won't be recycled till both unlink()
* and the urb's completion function return
*/
-static int hcd_unlink_urb (struct urb *urb, int status)
+int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_host_endpoint *ep;
struct usb_hcd *hcd = NULL;
@@ -1297,7 +1235,7 @@ static int hcd_unlink_urb (struct urb *urb, int status)
spin_lock (&hcd_data_lock);
sys = &urb->dev->dev;
- hcd = urb->dev->bus->hcpriv;
+ hcd = bus_to_hcd(urb->dev->bus);
if (hcd == NULL) {
retval = -ENODEV;
goto done;
@@ -1355,41 +1293,33 @@ done:
/*-------------------------------------------------------------------------*/
/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware. use for
+ * the hcd to make sure all endpoint state is gone from hardware, and then
+ * waits until the endpoint's queue is completely drained. use for
* set_configuration, set_interface, driver removal, physical disconnect.
*
* example: a qh stored in ep->hcpriv, holding state related to endpoint
* type, maxpacket size, toggle, halt status, and scheduling.
*/
-static void
-hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
+void usb_hcd_endpoint_disable (struct usb_device *udev,
+ struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
- hcd = udev->bus->hcpriv;
+ hcd = bus_to_hcd(udev->bus);
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
udev->state != USB_STATE_NOTATTACHED);
local_irq_disable ();
- /* FIXME move most of this into message.c as part of its
- * endpoint disable logic
- */
-
/* ep is already gone from udev->ep_{in,out}[]; no more submits */
rescan:
spin_lock (&hcd_data_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
int tmp;
- /* another cpu may be in hcd, spinning on hcd_data_lock
- * to giveback() this urb. the races here should be
- * small, but a full fix needs a new "can't submit"
- * urb state.
- * FIXME urb->reject should allow that...
- */
+ /* the urb may already have been unlinked */
if (urb->status != -EINPROGRESS)
continue;
usb_get_urb (urb);
@@ -1431,6 +1361,30 @@ rescan:
might_sleep ();
if (hcd->driver->endpoint_disable)
hcd->driver->endpoint_disable (hcd, ep);
+
+ /* Wait until the endpoint queue is completely empty. Most HCDs
+ * will have done this already in their endpoint_disable method,
+ * but some might not. And there could be root-hub control URBs
+ * still pending since they aren't affected by the HCDs'
+ * endpoint_disable methods.
+ */
+ while (!list_empty (&ep->urb_list)) {
+ spin_lock_irq (&hcd_data_lock);
+
+ /* The list may have changed while we acquired the spinlock */
+ urb = NULL;
+ if (!list_empty (&ep->urb_list)) {
+ urb = list_entry (ep->urb_list.prev, struct urb,
+ urb_list);
+ usb_get_urb (urb);
+ }
+ spin_unlock_irq (&hcd_data_lock);
+
+ if (urb) {
+ usb_kill_urb (urb);
+ usb_put_urb (urb);
+ }
+ }
}
/*-------------------------------------------------------------------------*/
@@ -1477,50 +1431,6 @@ int hcd_bus_resume (struct usb_bus *bus)
return status;
}
-/*
- * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
- * @hcd: host controller for this root hub
- *
- * This call arranges that usb_hcd_resume_root_hub() is safe to call later;
- * that the HCD's root hub polling is deactivated; and that the root's hub
- * driver is suspended. HCDs may call this to autosuspend when their root
- * hub's downstream ports are all inactive: unpowered, disconnected,
- * disabled, or suspended.
- *
- * The HCD will autoresume on device connect change detection (using SRP
- * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
- * from any ports that are suspended (if that is enabled). In most cases,
- * overcurrent signaling (on powered ports) will also start autoresume.
- *
- * Always called with IRQs blocked.
- */
-void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
-{
- struct urb *urb;
-
- spin_lock (&hcd_root_hub_lock);
- usb_suspend_root_hub (hcd->self.root_hub);
-
- /* force status urb to complete/unlink while suspended */
- if (hcd->status_urb) {
- urb = hcd->status_urb;
- urb->status = -ECONNRESET;
- urb->hcpriv = NULL;
- urb->actual_length = 0;
-
- del_timer (&hcd->rh_timer);
- hcd->poll_pending = 0;
- hcd->status_urb = NULL;
- } else
- urb = NULL;
- spin_unlock (&hcd_root_hub_lock);
- hcd->state = HC_STATE_SUSPENDED;
-
- if (urb)
- usb_hcd_giveback_urb (hcd, urb, NULL);
-}
-EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
-
/**
* usb_hcd_resume_root_hub - called by HCD to resume its root hub
* @hcd: host controller for this root hub
@@ -1584,20 +1494,6 @@ EXPORT_SYMBOL (usb_bus_start_enum);
/*-------------------------------------------------------------------------*/
-/*
- * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
- */
-static struct usb_operations usb_hcd_operations = {
- .get_frame_number = hcd_get_frame_number,
- .submit_urb = hcd_submit_urb,
- .unlink_urb = hcd_unlink_urb,
- .buffer_alloc = hcd_buffer_alloc,
- .buffer_free = hcd_buffer_free,
- .disable = hcd_endpoint_disable,
-};
-
-/*-------------------------------------------------------------------------*/
-
/**
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
@@ -1618,8 +1514,9 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
at_root_hub = (urb->dev == hcd->self.root_hub);
urb_unlink (urb);
- /* lower level hcd code should use *_dma exclusively */
- if (hcd->self.controller->dma_mask && !at_root_hub) {
+ /* lower level hcd code should use *_dma exclusively if the
+ * host controller does DMA */
+ if (hcd->self.uses_dma && !at_root_hub) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -1705,14 +1602,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
/*-------------------------------------------------------------------------*/
-static void hcd_release (struct usb_bus *bus)
-{
- struct usb_hcd *hcd;
-
- hcd = container_of(bus, struct usb_hcd, self);
- kfree(hcd);
-}
-
/**
* usb_create_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
@@ -1737,13 +1626,12 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
return NULL;
}
dev_set_drvdata(dev, hcd);
+ kref_init(&hcd->kref);
usb_bus_init(&hcd->self);
- hcd->self.op = &usb_hcd_operations;
- hcd->self.hcpriv = hcd;
- hcd->self.release = &hcd_release;
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
+ hcd->self.uses_dma = (dev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
@@ -1757,10 +1645,25 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
}
EXPORT_SYMBOL (usb_create_hcd);
+static void hcd_release (struct kref *kref)
+{
+ struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
+
+ kfree(hcd);
+}
+
+struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
+{
+ if (hcd)
+ kref_get (&hcd->kref);
+ return hcd;
+}
+EXPORT_SYMBOL (usb_get_hcd);
+
void usb_put_hcd (struct usb_hcd *hcd)
{
- dev_set_drvdata(hcd->self.controller, NULL);
- usb_bus_put(&hcd->self);
+ if (hcd)
+ kref_put (&hcd->kref, hcd_release);
}
EXPORT_SYMBOL (usb_put_hcd);
@@ -1916,6 +1819,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
}
EXPORT_SYMBOL (usb_remove_hcd);
+void
+usb_hcd_platform_shutdown(struct platform_device* dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL (usb_hcd_platform_shutdown);
+
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_MON)
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 7022aafb2ae..676877c15f8 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -55,12 +55,13 @@
/*-------------------------------------------------------------------------*/
-struct usb_hcd { /* usb_bus.hcpriv points to this */
+struct usb_hcd {
/*
* housekeeping
*/
struct usb_bus self; /* hcd is-a bus */
+ struct kref kref; /* reference counter */
const char *product_desc; /* product/vendor string */
char irq_descr[24]; /* driver + bus # */
@@ -85,6 +86,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned uses_new_polling:1;
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
+ unsigned wireless:1; /* Wireless USB HCD */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -128,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
return &hcd->self;
}
-
-// urb.hcpriv is really hardware-specific
+static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
+{
+ return container_of(bus, struct usb_hcd, self);
+}
struct hcd_timeout { /* timeouts we allocate */
struct list_head timeout_list;
@@ -138,28 +142,6 @@ struct hcd_timeout { /* timeouts we allocate */
/*-------------------------------------------------------------------------*/
-/*
- * FIXME usb_operations should vanish or become hc_driver,
- * when usb_bus and usb_hcd become the same thing.
- */
-
-struct usb_operations {
- int (*get_frame_number) (struct usb_device *usb_dev);
- int (*submit_urb) (struct urb *urb, gfp_t mem_flags);
- int (*unlink_urb) (struct urb *urb, int status);
-
- /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
- void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
- gfp_t mem_flags,
- dma_addr_t *dma);
- void (*buffer_free)(struct usb_bus *bus, size_t size,
- void *addr, dma_addr_t dma);
-
- void (*disable)(struct usb_device *udev,
- struct usb_host_endpoint *ep);
-};
-
-/* each driver provides one of these, and hardware init support */
struct pt_regs;
@@ -192,6 +174,9 @@ struct hc_driver {
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
+ /* shutdown HCD */
+ void (*shutdown) (struct usb_hcd *hcd);
+
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
@@ -218,15 +203,25 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
+extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
+extern int usb_hcd_unlink_urb (struct urb *urb, int status);
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb,
+ struct pt_regs *regs);
+extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+extern int usb_hcd_get_frame_number (struct usb_device *udev);
extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
struct device *dev, char *bus_name);
+extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
extern void usb_put_hcd (struct usb_hcd *hcd);
extern int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags);
extern void usb_remove_hcd(struct usb_hcd *hcd);
+struct platform_device;
+extern void usb_hcd_platform_shutdown(struct platform_device* dev);
+
#ifdef CONFIG_PCI
struct pci_dev;
struct pci_device_id;
@@ -239,6 +234,8 @@ extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
extern int usb_hcd_pci_resume (struct pci_dev *dev);
#endif /* CONFIG_PM */
+extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
+
#endif /* CONFIG_PCI */
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
@@ -352,8 +349,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
/*-------------------------------------------------------------------------*/
-extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
-
extern void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state);
@@ -365,9 +360,6 @@ extern struct list_head usb_bus_list;
extern struct mutex usb_bus_list_lock;
extern wait_queue_head_t usb_kill_urb_queue;
-extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
-extern void usb_bus_put (struct usb_bus *bus);
-
extern void usb_enable_root_hub_irq (struct usb_bus *bus);
extern int usb_find_interface_driver (struct usb_device *dev,
@@ -376,17 +368,11 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
-extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
extern int hcd_bus_suspend (struct usb_bus *bus);
extern int hcd_bus_resume (struct usb_bus *bus);
#else
-static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd)
-{
- return;
-}
-
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index e1731ff8af4..7676690a038 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/module.h>
@@ -294,7 +293,7 @@ void usb_kick_khubd(struct usb_device *hdev)
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb, struct pt_regs *regs)
{
- struct usb_hub *hub = (struct usb_hub *)urb->context;
+ struct usb_hub *hub = urb->context;
int status;
int i;
unsigned long bits;
@@ -312,7 +311,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
hub->error = urb->status;
/* FALL THROUGH */
-
+
/* let khubd handle things */
case 0: /* we got data: port status changed */
bits = 0;
@@ -453,18 +452,14 @@ static void hub_power_on(struct usb_hub *hub)
msleep(max(pgood_delay, (unsigned) 100));
}
-static inline void __hub_quiesce(struct usb_hub *hub)
+static void hub_quiesce(struct usb_hub *hub)
{
/* (nonblocking) khubd and related activity won't re-trigger */
hub->quiescing = 1;
hub->activating = 0;
hub->resume_root_hub = 0;
-}
-static void hub_quiesce(struct usb_hub *hub)
-{
/* (blocking) stop khubd and related activity */
- __hub_quiesce(hub);
usb_kill_urb(hub->urb);
if (hub->has_indicators)
cancel_delayed_work(&hub->leds);
@@ -869,13 +864,8 @@ descriptor_error:
endpoint = &desc->endpoint[0].desc;
- /* Output endpoint? Curiouser and curiouser.. */
- if (!(endpoint->bEndpointAddress & USB_DIR_IN))
- goto descriptor_error;
-
- /* If it's not an interrupt endpoint, we'd better punt! */
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_INT)
+ /* If it's not an interrupt in endpoint, we'd better punt! */
+ if (!usb_endpoint_is_int_in(endpoint))
goto descriptor_error;
/* We found a hub */
@@ -1023,26 +1013,29 @@ void usb_set_device_state(struct usb_device *udev,
if (udev->state == USB_STATE_NOTATTACHED)
; /* do nothing */
else if (new_state != USB_STATE_NOTATTACHED) {
- udev->state = new_state;
/* root hub wakeup capabilities are managed out-of-band
* and may involve silicon errata ... ignore them here.
*/
if (udev->parent) {
- if (new_state == USB_STATE_CONFIGURED)
+ if (udev->state == USB_STATE_SUSPENDED
+ || new_state == USB_STATE_SUSPENDED)
+ ; /* No change to wakeup settings */
+ else if (new_state == USB_STATE_CONFIGURED)
device_init_wakeup(&udev->dev,
(udev->actconfig->desc.bmAttributes
& USB_CONFIG_ATT_WAKEUP));
- else if (new_state != USB_STATE_SUSPENDED)
+ else
device_init_wakeup(&udev->dev, 0);
}
+ udev->state = new_state;
} else
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM
/**
* usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
@@ -1060,6 +1053,12 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
unsigned long flags;
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
+
+ /* Make sure no potential wakeup events get lost,
+ * by forcing the root hub to be resumed.
+ */
+ rhdev->dev.power.prev_state.event = PM_EVENT_ON;
+
spin_lock_irqsave(&device_state_lock, flags);
hub = hdev_to_hub(rhdev);
for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
@@ -1073,7 +1072,7 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
-#endif
+#endif /* CONFIG_PM */
static void choose_address(struct usb_device *udev)
{
@@ -1149,144 +1148,28 @@ void usb_disconnect(struct usb_device **pdev)
* cleaning up all state associated with the current configuration
* so that the hardware is now fully quiesced.
*/
+ dev_dbg (&udev->dev, "unregistering device\n");
usb_disable_device(udev, 0);
- usb_notify_remove_device(udev);
+ usb_unlock_device(udev);
- /* Free the device number, remove the /proc/bus/usb entry and
- * the sysfs attributes, and delete the parent's children[]
+ /* Unregister the device. The device driver is responsible
+ * for removing the device files from usbfs and sysfs and for
+ * de-configuring the device.
+ */
+ device_del(&udev->dev);
+
+ /* Free the device number and delete the parent's children[]
* (or root_hub) pointer.
*/
- dev_dbg (&udev->dev, "unregistering device\n");
release_address(udev);
- usb_remove_sysfs_dev_files(udev);
/* Avoid races with recursively_mark_NOTATTACHED() */
spin_lock_irq(&device_state_lock);
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
- usb_unlock_device(udev);
-
- device_unregister(&udev->dev);
-}
-
-static inline const char *plural(int n)
-{
- return (n == 1 ? "" : "s");
-}
-
-static int choose_configuration(struct usb_device *udev)
-{
- int i;
- int num_configs;
- int insufficient_power = 0;
- struct usb_host_config *c, *best;
-
- best = NULL;
- c = udev->config;
- num_configs = udev->descriptor.bNumConfigurations;
- for (i = 0; i < num_configs; (i++, c++)) {
- struct usb_interface_descriptor *desc = NULL;
-
- /* It's possible that a config has no interfaces! */
- if (c->desc.bNumInterfaces > 0)
- desc = &c->intf_cache[0]->altsetting->desc;
-
- /*
- * HP's USB bus-powered keyboard has only one configuration
- * and it claims to be self-powered; other devices may have
- * similar errors in their descriptors. If the next test
- * were allowed to execute, such configurations would always
- * be rejected and the devices would not work as expected.
- * In the meantime, we run the risk of selecting a config
- * that requires external power at a time when that power
- * isn't available. It seems to be the lesser of two evils.
- *
- * Bugzilla #6448 reports a device that appears to crash
- * when it receives a GET_DEVICE_STATUS request! We don't
- * have any other way to tell whether a device is self-powered,
- * but since we don't use that information anywhere but here,
- * the call has been removed.
- *
- * Maybe the GET_DEVICE_STATUS call and the test below can
- * be reinstated when device firmwares become more reliable.
- * Don't hold your breath.
- */
-#if 0
- /* Rule out self-powered configs for a bus-powered device */
- if (bus_powered && (c->desc.bmAttributes &
- USB_CONFIG_ATT_SELFPOWER))
- continue;
-#endif
-
- /*
- * The next test may not be as effective as it should be.
- * Some hubs have errors in their descriptor, claiming
- * to be self-powered when they are really bus-powered.
- * We will overestimate the amount of current such hubs
- * make available for each port.
- *
- * This is a fairly benign sort of failure. It won't
- * cause us to reject configurations that we should have
- * accepted.
- */
-
- /* Rule out configs that draw too much bus current */
- if (c->desc.bMaxPower * 2 > udev->bus_mA) {
- insufficient_power++;
- continue;
- }
-
- /* If the first config's first interface is COMM/2/0xff
- * (MSFT RNDIS), rule it out unless Linux has host-side
- * RNDIS support. */
- if (i == 0 && desc
- && desc->bInterfaceClass == USB_CLASS_COMM
- && desc->bInterfaceSubClass == 2
- && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
- continue;
-#else
- best = c;
-#endif
- }
-
- /* From the remaining configs, choose the first one whose
- * first interface is for a non-vendor-specific class.
- * Reason: Linux is more likely to have a class driver
- * than a vendor-specific driver. */
- else if (udev->descriptor.bDeviceClass !=
- USB_CLASS_VENDOR_SPEC &&
- (!desc || desc->bInterfaceClass !=
- USB_CLASS_VENDOR_SPEC)) {
- best = c;
- break;
- }
-
- /* If all the remaining configs are vendor-specific,
- * choose the first one. */
- else if (!best)
- best = c;
- }
-
- if (insufficient_power > 0)
- dev_info(&udev->dev, "rejected %d configuration%s "
- "due to insufficient available bus power\n",
- insufficient_power, plural(insufficient_power));
-
- if (best) {
- i = best->desc.bConfigurationValue;
- dev_info(&udev->dev,
- "configuration #%d chosen from %d choice%s\n",
- i, num_configs, plural(num_configs));
- } else {
- i = -1;
- dev_warn(&udev->dev,
- "no configuration chosen from %d choice%s\n",
- num_configs, plural(num_configs));
- }
- return i;
+ put_device(&udev->dev);
}
#ifdef DEBUG
@@ -1329,7 +1212,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
int usb_new_device(struct usb_device *udev)
{
int err;
- int c;
err = usb_get_configuration(udev);
if (err < 0) {
@@ -1372,8 +1254,7 @@ int usb_new_device(struct usb_device *udev)
USB_DT_OTG, (void **) &desc) == 0) {
if (desc->bmAttributes & USB_OTG_HNP) {
unsigned port1 = udev->portnum;
- struct usb_device *root = udev->parent;
-
+
dev_info(&udev->dev,
"Dual-Role OTG device on %sHNP port\n",
(port1 == bus->otg_port)
@@ -1408,9 +1289,9 @@ int usb_new_device(struct usb_device *udev)
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
- static int __usb_suspend_device(struct usb_device *,
+ static int __usb_port_suspend(struct usb_device *,
int port1);
- err = __usb_suspend_device(udev, udev->bus->otg_port);
+ err = __usb_port_suspend(udev, udev->bus->otg_port);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
@@ -1419,34 +1300,15 @@ int usb_new_device(struct usb_device *udev)
}
#endif
- /* put device-specific files into sysfs */
+ /* Register the device. The device driver is responsible
+ * for adding the device files to usbfs and sysfs and for
+ * configuring the device.
+ */
err = device_add (&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
- usb_create_sysfs_dev_files (udev);
-
- usb_lock_device(udev);
-
- /* choose and set the configuration. that registers the interfaces
- * with the driver core, and lets usb device drivers bind to them.
- */
- c = choose_configuration(udev);
- if (c >= 0) {
- err = usb_set_configuration(udev, c);
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",
- c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
- }
- }
-
- /* USB device state == configured ... usable */
- usb_notify_add_device(udev);
-
- usb_unlock_device(udev);
return 0;
@@ -1473,6 +1335,18 @@ static int hub_port_status(struct usb_hub *hub, int port1,
return ret;
}
+
+/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
+static unsigned hub_is_wusb(struct usb_hub *hub)
+{
+ struct usb_hcd *hcd;
+ if (hub->hdev->parent != NULL) /* not a root hub? */
+ return 0;
+ hcd = container_of(hub->hdev->bus, struct usb_hcd, self);
+ return hcd->wireless;
+}
+
+
#define PORT_RESET_TRIES 5
#define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
@@ -1513,7 +1387,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
/* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) {
- if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ if (hub_is_wusb(hub))
+ udev->speed = USB_SPEED_VARIABLE;
+ else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
udev->speed = USB_SPEED_LOW;
@@ -1608,6 +1484,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
kick_khubd(hub);
}
+#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
@@ -1634,7 +1511,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* NOTE: OTG devices may issue remote wakeup (or SRP) even when
* we don't explicitly enable it here.
*/
- if (device_may_wakeup(&udev->dev)) {
+ if (udev->do_remote_wakeup) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
@@ -1660,7 +1537,8 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
USB_CTRL_SET_TIMEOUT);
} else {
/* device has up to 10 msec to fully suspend */
- dev_dbg(&udev->dev, "usb suspend\n");
+ dev_dbg(&udev->dev, "usb %ssuspend\n",
+ udev->auto_pm ? "auto-" : "");
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
@@ -1685,7 +1563,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
*/
-static int __usb_suspend_device (struct usb_device *udev, int port1)
+static int __usb_port_suspend (struct usb_device *udev, int port1)
{
int status = 0;
@@ -1693,49 +1571,29 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
if (port1 < 0)
return port1;
- if (udev->state == USB_STATE_SUSPENDED
- || udev->state == USB_STATE_NOTATTACHED) {
- return 0;
- }
-
- /* all interfaces must already be suspended */
- if (udev->actconfig) {
- int i;
-
- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
- struct usb_interface *intf;
-
- intf = udev->actconfig->interface[i];
- if (is_active(intf)) {
- dev_dbg(&intf->dev, "nyet suspended\n");
- return -EBUSY;
- }
- }
- }
-
- /* we only change a device's upstream USB link.
- * root hubs have no upstream USB link.
+ /* we change the device's upstream USB link,
+ * but root hubs have no upstream USB link.
*/
if (udev->parent)
status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
udev);
-
- if (status == 0)
- udev->dev.power.power_state = PMSG_SUSPEND;
+ else {
+ dev_dbg(&udev->dev, "usb %ssuspend\n",
+ udev->auto_pm ? "auto-" : "");
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
+ }
return status;
}
-#endif
-
/*
- * usb_suspend_device - suspend a usb device
+ * usb_port_suspend - suspend a usb device's upstream port
* @udev: device that's no longer in active use
* Context: must be able to sleep; device not locked; pm locks held
*
* Suspends a USB device that isn't in active use, conserving power.
* Devices may wake out of a suspend, if anything important happens,
* using the remote wakeup mechanism. They may also be taken out of
- * suspend by the host, using usb_resume_device(). It's also routine
+ * suspend by the host, using usb_port_resume(). It's also routine
* to disconnect devices while they are suspended.
*
* This only affects the USB hardware for a device; its interfaces
@@ -1747,17 +1605,9 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
*
* Returns 0 on success, else negative errno.
*/
-int usb_suspend_device(struct usb_device *udev)
+int usb_port_suspend(struct usb_device *udev)
{
-#ifdef CONFIG_USB_SUSPEND
- if (udev->state == USB_STATE_NOTATTACHED)
- return -ENODEV;
- return __usb_suspend_device(udev, udev->portnum);
-#else
- /* NOTE: udev->state unchanged, it's not lying ... */
- udev->dev.power.power_state = PMSG_SUSPEND;
- return 0;
-#endif
+ return __usb_port_suspend(udev, udev->portnum);
}
/*
@@ -1768,7 +1618,7 @@ int usb_suspend_device(struct usb_device *udev)
* resume (by host) or remote wakeup (by device) ... now see what changed
* in the tree that's rooted at this device.
*/
-static int finish_device_resume(struct usb_device *udev)
+static int finish_port_resume(struct usb_device *udev)
{
int status;
u16 devstatus;
@@ -1784,21 +1634,20 @@ static int finish_device_resume(struct usb_device *udev)
usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
- udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
* and device drivers will know about any resume quirks.
*/
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
- if (status < 2)
+ if (status >= 0)
+ status = (status == 2 ? 0 : -ENODEV);
+
+ if (status)
dev_dbg(&udev->dev,
"gone after usb resume? status %d\n",
status);
else if (udev->actconfig) {
- unsigned i;
- int (*resume)(struct device *);
-
le16_to_cpus(&devstatus);
if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
&& udev->parent) {
@@ -1809,24 +1658,9 @@ static int finish_device_resume(struct usb_device *udev)
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
- if (status) {
+ if (status)
dev_dbg(&udev->dev, "disable remote "
"wakeup, status %d\n", status);
- status = 0;
- }
- }
-
- /* resume interface drivers; if this is a hub, it
- * may have a child resume event to deal with soon
- */
- resume = udev->dev.bus->resume;
- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
- struct device *dev =
- &udev->actconfig->interface[i]->dev;
-
- down(&dev->sem);
- (void) resume(dev);
- up(&dev->sem);
}
status = 0;
@@ -1837,8 +1671,6 @@ static int finish_device_resume(struct usb_device *udev)
return status;
}
-#ifdef CONFIG_USB_SUSPEND
-
static int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
{
@@ -1846,6 +1678,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
// dev_dbg(hub->intfdev, "resume port %d\n", port1);
+ set_bit(port1, hub->busy_bits);
+
/* see 7.1.7.7; affects power usage, but not budgeting */
status = clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_SUSPEND);
@@ -1859,7 +1693,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/* drive resume for at least 20 msec */
if (udev)
- dev_dbg(&udev->dev, "RESUME\n");
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ udev->auto_pm ? "auto-" : "");
msleep(25);
#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
@@ -1880,23 +1715,30 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
dev_dbg(hub->intfdev,
"port %d status %04x.%04x after resume, %d\n",
port1, portchange, devstatus, status);
+ if (status >= 0)
+ status = -ENODEV;
} else {
+ if (portchange & USB_PORT_STAT_C_SUSPEND)
+ clear_port_feature(hub->hdev, port1,
+ USB_PORT_FEAT_C_SUSPEND);
/* TRSMRCY = 10 msec */
msleep(10);
if (udev)
- status = finish_device_resume(udev);
+ status = finish_port_resume(udev);
}
}
if (status < 0)
hub_port_logical_disconnect(hub, port1);
+ clear_bit(port1, hub->busy_bits);
+ if (!hub->hdev->parent && !hub->busy_bits[0])
+ usb_enable_root_hub_irq(hub->hdev->bus);
+
return status;
}
-#endif
-
/*
- * usb_resume_device - re-activate a suspended usb device
+ * usb_port_resume - re-activate a suspended usb device's upstream port
* @udev: device to re-activate
* Context: must be able to sleep; device not locked; pm locks held
*
@@ -1908,36 +1750,24 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
*
* Returns 0 on success, else negative errno.
*/
-int usb_resume_device(struct usb_device *udev)
+int usb_port_resume(struct usb_device *udev)
{
int status;
- if (udev->state == USB_STATE_NOTATTACHED)
- return -ENODEV;
-
- /* selective resume of one downstream hub-to-device port */
+ /* we change the device's upstream USB link,
+ * but root hubs have no upstream USB link.
+ */
if (udev->parent) {
-#ifdef CONFIG_USB_SUSPEND
- if (udev->state == USB_STATE_SUSPENDED) {
- // NOTE swsusp may bork us, device state being wrong...
- // NOTE this fails if parent is also suspended...
- status = hub_port_resume(hdev_to_hub(udev->parent),
- udev->portnum, udev);
- } else
-#endif
- status = 0;
- } else
- status = finish_device_resume(udev);
- if (status < 0)
- dev_dbg(&udev->dev, "can't resume, status %d\n",
- status);
-
- /* rebind drivers that had no suspend() */
- if (status == 0) {
- usb_unlock_device(udev);
- bus_rescan_devices(&usb_bus_type);
- usb_lock_device(udev);
+ // NOTE this fails if parent is also suspended...
+ status = hub_port_resume(hdev_to_hub(udev->parent),
+ udev->portnum, udev);
+ } else {
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ udev->auto_pm ? "auto-" : "");
+ status = finish_port_resume(udev);
}
+ if (status < 0)
+ dev_dbg(&udev->dev, "can't resume, status %d\n", status);
return status;
}
@@ -1945,23 +1775,60 @@ static int remote_wakeup(struct usb_device *udev)
{
int status = 0;
-#ifdef CONFIG_USB_SUSPEND
+ /* All this just to avoid sending a port-resume message
+ * to the parent hub! */
- /* don't repeat RESUME sequence if this device
- * was already woken up by some other task
- */
usb_lock_device(udev);
+ usb_pm_lock(udev);
if (udev->state == USB_STATE_SUSPENDED) {
- dev_dbg(&udev->dev, "RESUME (wakeup)\n");
+ dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
/* TRSMRCY = 10 msec */
msleep(10);
- status = finish_device_resume(udev);
+ status = finish_port_resume(udev);
+ if (status == 0)
+ udev->dev.power.power_state.event = PM_EVENT_ON;
}
+ usb_pm_unlock(udev);
+
+ if (status == 0)
+ usb_autoresume_device(udev, 0);
usb_unlock_device(udev);
-#endif
return status;
}
+#else /* CONFIG_USB_SUSPEND */
+
+/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
+
+int usb_port_suspend(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int
+finish_port_resume(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int
+hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
+{
+ return 0;
+}
+
+int usb_port_resume(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int remote_wakeup(struct usb_device *udev)
+{
+ return 0;
+}
+
+#endif
+
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
{
struct usb_hub *hub = usb_get_intfdata (intf);
@@ -1973,13 +1840,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
- if (udev && (udev->dev.power.power_state.event
- == PM_EVENT_ON
+ if (udev && msg.event == PM_EVENT_SUSPEND &&
#ifdef CONFIG_USB_SUSPEND
- || udev->state != USB_STATE_SUSPENDED
+ udev->state != USB_STATE_SUSPENDED
+#else
+ udev->dev.power.power_state.event
+ == PM_EVENT_ON
#endif
- )) {
- dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
+ ) {
+ if (!hdev->auto_pm)
+ dev_dbg(&intf->dev, "port %d nyet suspended\n",
+ port1);
return -EBUSY;
}
}
@@ -2028,66 +1899,22 @@ static int hub_resume(struct usb_interface *intf)
}
}
+ /* tell khubd to look for changes on this hub */
hub_activate(hub);
-
- /* REVISIT: this recursion probably shouldn't exist. Remove
- * this code sometime, after retesting with different root and
- * external hubs.
- */
-#ifdef CONFIG_USB_SUSPEND
- {
- unsigned port1;
-
- for (port1 = 1; port1 <= hdev->maxchild; port1++) {
- struct usb_device *udev;
- u16 portstat, portchange;
-
- udev = hdev->children [port1-1];
- status = hub_port_status(hub, port1, &portstat, &portchange);
- if (status == 0) {
- if (portchange & USB_PORT_STAT_C_SUSPEND) {
- clear_port_feature(hdev, port1,
- USB_PORT_FEAT_C_SUSPEND);
- portchange &= ~USB_PORT_STAT_C_SUSPEND;
- }
-
- /* let khubd handle disconnects etc */
- if (portchange)
- continue;
- }
-
- if (!udev || status < 0)
- continue;
- usb_lock_device(udev);
- if (portstat & USB_PORT_STAT_SUSPEND)
- status = hub_port_resume(hub, port1, udev);
- else {
- status = finish_device_resume(udev);
- if (status < 0) {
- dev_dbg(&intf->dev, "resume port %d --> %d\n",
- port1, status);
- hub_port_logical_disconnect(hub, port1);
- }
- }
- usb_unlock_device(udev);
- }
- }
-#endif
return 0;
}
-void usb_suspend_root_hub(struct usb_device *hdev)
-{
- struct usb_hub *hub = hdev_to_hub(hdev);
+#else /* CONFIG_PM */
- /* This also makes any led blinker stop retriggering. We're called
- * from irq, so the blinker might still be scheduled. Caller promises
- * that the root hub status URB will be canceled.
- */
- __hub_quiesce(hub);
- mark_quiesced(to_usb_interface(hub->intfdev));
+static inline int remote_wakeup(struct usb_device *udev)
+{
+ return 0;
}
+#define hub_suspend NULL
+#define hub_resume NULL
+#endif
+
void usb_resume_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
@@ -2207,6 +2034,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
+ char *speed, *type;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -2239,8 +2067,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
+ * For Wireless USB devices, ep0 max packet is always 512 (tho
+ * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) {
+ case USB_SPEED_VARIABLE: /* fixed at 512 */
+ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
+ break;
case USB_SPEED_HIGH: /* fixed at 64 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
break;
@@ -2258,17 +2091,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
+ type = "";
+ switch (udev->speed) {
+ case USB_SPEED_LOW: speed = "low"; break;
+ case USB_SPEED_FULL: speed = "full"; break;
+ case USB_SPEED_HIGH: speed = "high"; break;
+ case USB_SPEED_VARIABLE:
+ speed = "variable";
+ type = "Wireless ";
+ break;
+ default: speed = "?"; break;
+ }
dev_info (&udev->dev,
- "%s %s speed USB device using %s and address %d\n",
- (udev->config) ? "reset" : "new",
- ({ char *speed; switch (udev->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
- }; speed;}),
- udev->bus->controller->driver->name,
- udev->devnum);
+ "%s %s speed %sUSB device using %s and address %d\n",
+ (udev->config) ? "reset" : "new", speed, type,
+ udev->bus->controller->driver->name, udev->devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -2310,6 +2147,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* down tremendously by NAKing the unexpectedly
* early status stage. Also, retry on all errors;
* some devices are flakey.
+ * 255 is for WUSB devices, we actually need to use 512.
+ * WUSB1.0[4.8.1].
*/
for (j = 0; j < 3; ++j) {
buf->bMaxPacketSize0 = 0;
@@ -2319,7 +2158,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
buf, GET_DESCRIPTOR_BUFSIZE,
(i ? USB_CTRL_GET_TIMEOUT : 1000));
switch (buf->bMaxPacketSize0) {
- case 8: case 16: case 32: case 64:
+ case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==
USB_DT_DEVICE) {
r = 0;
@@ -2393,7 +2232,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval)
goto fail;
- i = udev->descriptor.bMaxPacketSize0;
+ i = udev->descriptor.bMaxPacketSize0 == 0xff?
+ 512 : udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
@@ -2578,6 +2418,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
usb_set_device_state(udev, USB_STATE_POWERED);
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
+ udev->level = hdev->level + 1;
/* set the address */
choose_address(udev);
@@ -2729,17 +2570,6 @@ static void hub_events(void)
usb_get_intf(intf);
spin_unlock_irq(&hub_event_lock);
- /* Is this is a root hub wanting to reactivate the downstream
- * ports? If so, be sure the interface resumes even if its
- * stub "device" node was never suspended.
- */
- if (i) {
- dpm_runtime_resume(&hdev->dev);
- dpm_runtime_resume(&intf->dev);
- usb_put_intf(intf);
- continue;
- }
-
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
if (locktree(hdev) < 0) {
@@ -2756,6 +2586,13 @@ static void hub_events(void)
goto loop;
}
+ /* Is this is a root hub wanting to reactivate the downstream
+ * ports? If so, be sure the interface resumes even if its
+ * stub "device" node was never suspended.
+ */
+ if (i)
+ usb_autoresume_device(hdev, 0);
+
/* If this is an inactive or suspended hub, do nothing */
if (hub->quiescing)
goto loop;
@@ -2893,7 +2730,7 @@ static void hub_events(void)
/* If this is a root hub, tell the HCD it's okay to
* re-enable port-change interrupts now. */
- if (!hdev->parent)
+ if (!hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hdev->bus);
loop:
@@ -3068,6 +2905,9 @@ int usb_reset_device(struct usb_device *udev)
break;
}
clear_bit(port1, parent_hub->busy_bits);
+ if (!parent_hdev->parent && !parent_hub->busy_bits[0])
+ usb_enable_root_hub_irq(parent_hdev->bus);
+
if (ret < 0)
goto re_enumerate;
@@ -3121,6 +2961,7 @@ re_enumerate:
hub_port_logical_disconnect(parent_hub, port1);
return -ENODEV;
}
+EXPORT_SYMBOL(usb_reset_device);
/**
* usb_reset_composite_device - warn interface drivers and perform a USB port reset
@@ -3156,6 +2997,9 @@ int usb_reset_composite_device(struct usb_device *udev,
return -EINVAL;
}
+ /* Prevent autosuspend during the reset */
+ usb_autoresume_device(udev, 1);
+
if (iface && iface->condition != USB_INTERFACE_BINDING)
iface = NULL;
@@ -3197,5 +3041,7 @@ int usb_reset_composite_device(struct usb_device *udev,
}
}
+ usb_autosuspend_device(udev, 1);
return ret;
}
+EXPORT_SYMBOL(usb_reset_composite_device);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 29d5f45a845..0f8e82a4d48 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -212,7 +212,8 @@ struct usb_hub {
unsigned long event_bits[1]; /* status change bitmask */
unsigned long change_bits[1]; /* ports with logical connect
status change */
- unsigned long busy_bits[1]; /* ports being reset */
+ unsigned long busy_bits[1]; /* ports being reset or
+ resumed */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 95f5ad923b0..df3d152f049 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -27,7 +27,6 @@
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mount.h>
@@ -45,7 +44,7 @@
#include "hcd.h"
static struct super_operations usbfs_ops;
-static struct file_operations default_file_operations;
+static const struct file_operations default_file_operations;
static struct vfsmount *usbfs_mount;
static int usbfs_mount_count; /* = 0 */
static int ignore_mount = 0;
@@ -201,7 +200,7 @@ static void update_sb(struct super_block *sb)
if (!root)
return;
- mutex_lock(&root->d_inode->i_mutex);
+ mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT);
list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) {
if (bus->d_inode) {
@@ -250,7 +249,6 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
@@ -403,13 +401,13 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
static int default_open (struct inode *inode, struct file *file)
{
- if (inode->u.generic_ip)
- file->private_data = inode->u.generic_ip;
+ if (inode->i_private)
+ file->private_data = inode->i_private;
return 0;
}
-static struct file_operations default_file_operations = {
+static const struct file_operations default_file_operations = {
.read = default_read_file,
.write = default_write_file,
.open = default_open,
@@ -496,7 +494,7 @@ static int fs_create_by_name (const char *name, mode_t mode,
static struct dentry *fs_create_file (const char *name, mode_t mode,
struct dentry *parent, void *data,
- struct file_operations *fops,
+ const struct file_operations *fops,
uid_t uid, gid_t gid)
{
struct dentry *dentry;
@@ -510,7 +508,7 @@ static struct dentry *fs_create_file (const char *name, mode_t mode,
} else {
if (dentry->d_inode) {
if (data)
- dentry->d_inode->u.generic_ip = data;
+ dentry->d_inode->i_private = data;
if (fops)
dentry->d_inode->i_fop = fops;
dentry->d_inode->i_uid = uid;
@@ -528,7 +526,7 @@ static void fs_remove_file (struct dentry *dentry)
if (!parent || !parent->d_inode)
return;
- mutex_lock(&parent->d_inode->i_mutex);
+ mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT);
if (usbfs_positive(dentry)) {
if (dentry->d_inode) {
if (S_ISDIR(dentry->d_inode->i_mode))
@@ -569,7 +567,7 @@ static int create_special_files (void)
ignore_mount = 1;
/* create the devices special file */
- retval = simple_pin_fs("usbfs", &usbfs_mount, &usbfs_mount_count);
+ retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
if (retval) {
err ("Unable to get usbfs mount");
goto exit;
@@ -696,11 +694,11 @@ static void usbfs_remove_device(struct usb_device *dev)
wake_up_all(&ds->wait);
list_del_init(&ds->list);
if (ds->discsignr) {
- sinfo.si_signo = SIGPIPE;
+ sinfo.si_signo = ds->discsignr;
sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = ds->disccontext;
- kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid);
+ kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
}
}
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 8569600f313..85b1cd18336 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -2,7 +2,6 @@
* message.c - synchronous message handling
*/
-#include <linux/config.h>
#include <linux/pci.h> /* for scatterlist macros */
#include <linux/usb.h>
#include <linux/module.h>
@@ -24,59 +23,44 @@ static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
}
-static void timeout_kill(unsigned long data)
-{
- struct urb *urb = (struct urb *) data;
-
- usb_unlink_urb(urb);
-}
-
-// Starts urb and waits for completion or timeout
-// note that this call is NOT interruptible, while
-// many device driver i/o requests should be interruptible
-static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
+/*
+ * Starts urb and waits for completion or timeout. Note that this call
+ * is NOT interruptible. Many device driver i/o requests should be
+ * interruptible and therefore these drivers should implement their
+ * own interruptible routines.
+ */
+static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
- struct completion done;
- struct timer_list timer;
- int status;
+ struct completion done;
+ unsigned long expire;
+ int status;
init_completion(&done);
urb->context = &done;
urb->actual_length = 0;
status = usb_submit_urb(urb, GFP_NOIO);
-
- if (status == 0) {
- if (timeout > 0) {
- init_timer(&timer);
- timer.expires = jiffies + msecs_to_jiffies(timeout);
- timer.data = (unsigned long)urb;
- timer.function = timeout_kill;
- /* grr. timeout _should_ include submit delays. */
- add_timer(&timer);
- }
- wait_for_completion(&done);
+ if (unlikely(status))
+ goto out;
+
+ expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ if (!wait_for_completion_timeout(&done, expire)) {
+
+ dev_dbg(&urb->dev->dev,
+ "%s timed out on ep%d%s len=%d/%d\n",
+ current->comm,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->actual_length,
+ urb->transfer_buffer_length);
+
+ usb_kill_urb(urb);
+ status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+ } else
status = urb->status;
- /* note: HCDs return ETIMEDOUT for other reasons too */
- if (status == -ECONNRESET) {
- dev_dbg(&urb->dev->dev,
- "%s timed out on ep%d%s len=%d/%d\n",
- current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
- urb->actual_length,
- urb->transfer_buffer_length
- );
- if (urb->actual_length > 0)
- status = 0;
- else
- status = -ETIMEDOUT;
- }
- if (timeout > 0)
- del_timer_sync(&timer);
- }
-
+out:
if (actual_length)
*actual_length = urb->actual_length;
+
usb_free_urb(urb);
return status;
}
@@ -264,7 +248,7 @@ static void sg_clean (struct usb_sg_request *io)
static void sg_complete (struct urb *urb, struct pt_regs *regs)
{
- struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
+ struct usb_sg_request *io = urb->context;
spin_lock (&io->lock);
@@ -1000,8 +984,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
- if (ep && dev->bus && dev->bus->op && dev->bus->op->disable)
- dev->bus->op->disable(dev, ep);
+ if (ep && dev->bus)
+ usb_hcd_endpoint_disable(dev, ep);
}
/**
@@ -1382,9 +1366,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
- if (dev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
-
/* Allocate memory for new interfaces before doing anything else,
* so that if we run out then nothing will have changed. */
n = nintf = 0;
@@ -1419,6 +1400,11 @@ free_interfaces:
configuration, -i);
}
+ /* Wake up the device so we can send it the Set-Config request */
+ ret = usb_autoresume_device(dev, 1);
+ if (ret)
+ goto free_interfaces;
+
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
@@ -1438,6 +1424,7 @@ free_interfaces:
dev->actconfig = cp;
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
+ usb_autosuspend_device(dev, 1);
goto free_interfaces;
}
usb_set_device_state(dev, USB_STATE_CONFIGURED);
@@ -1506,8 +1493,68 @@ free_interfaces:
usb_create_sysfs_intf_files (intf);
}
+ usb_autosuspend_device(dev, 1);
+ return 0;
+}
+
+struct set_config_request {
+ struct usb_device *udev;
+ int config;
+ struct work_struct work;
+};
+
+/* Worker routine for usb_driver_set_configuration() */
+static void driver_set_config_work(void *_req)
+{
+ struct set_config_request *req = _req;
+
+ usb_lock_device(req->udev);
+ usb_set_configuration(req->udev, req->config);
+ usb_unlock_device(req->udev);
+ usb_put_dev(req->udev);
+ kfree(req);
+}
+
+/**
+ * usb_driver_set_configuration - Provide a way for drivers to change device configurations
+ * @udev: the device whose configuration is being updated
+ * @config: the configuration being chosen.
+ * Context: In process context, must be able to sleep
+ *
+ * Device interface drivers are not allowed to change device configurations.
+ * This is because changing configurations will destroy the interface the
+ * driver is bound to and create new ones; it would be like a floppy-disk
+ * driver telling the computer to replace the floppy-disk drive with a
+ * tape drive!
+ *
+ * Still, in certain specialized circumstances the need may arise. This
+ * routine gets around the normal restrictions by using a work thread to
+ * submit the change-config request.
+ *
+ * Returns 0 if the request was succesfully queued, error code otherwise.
+ * The caller has no way to know whether the queued request will eventually
+ * succeed.
+ */
+int usb_driver_set_configuration(struct usb_device *udev, int config)
+{
+ struct set_config_request *req;
+
+ req = kmalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ req->udev = udev;
+ req->config = config;
+ INIT_WORK(&req->work, driver_set_config_work, req);
+
+ usb_get_dev(udev);
+ if (!schedule_work(&req->work)) {
+ usb_put_dev(udev);
+ kfree(req);
+ return -EINVAL;
+ }
return 0;
}
+EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
// synchronous request completion model
EXPORT_SYMBOL(usb_control_msg);
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index fe0ed54fa0a..6b36897ca15 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -9,7 +9,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/usb.h>
@@ -51,8 +50,11 @@ void usb_notify_add_device(struct usb_device *udev)
void usb_notify_remove_device(struct usb_device *udev)
{
+ /* Protect against simultaneous usbfs open */
+ mutex_lock(&usbfs_mutex);
blocking_notifier_call_chain(&usb_notifier_list,
USB_DEVICE_REMOVE, udev);
+ mutex_unlock(&usbfs_mutex);
}
void usb_notify_add_bus(struct usb_bus *ubus)
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 3f49bf51cff..55d8f575206 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -10,7 +10,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/usb.h>
#include "usb.h"
@@ -61,7 +60,7 @@ static ssize_t
set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = udev = to_usb_device (dev);
+ struct usb_device *udev = to_usb_device (dev);
int config, value;
if (sscanf (buf, "%u", &config) != 1 || config > 255)
@@ -187,6 +186,7 @@ usb_descriptor_attr (bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
+ &dev_attr_configuration.attr,
&dev_attr_bNumInterfaces.attr,
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
@@ -210,20 +210,40 @@ static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
-void usb_create_sysfs_dev_files (struct usb_device *udev)
+int usb_create_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
+ int retval;
- sysfs_create_group(&dev->kobj, &dev_attr_grp);
+ retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
+ if (retval)
+ return retval;
- if (udev->manufacturer)
- device_create_file (dev, &dev_attr_manufacturer);
- if (udev->product)
- device_create_file (dev, &dev_attr_product);
- if (udev->serial)
- device_create_file (dev, &dev_attr_serial);
- device_create_file (dev, &dev_attr_configuration);
- usb_create_ep_files(dev, &udev->ep0, udev);
+ if (udev->manufacturer) {
+ retval = device_create_file (dev, &dev_attr_manufacturer);
+ if (retval)
+ goto error;
+ }
+ if (udev->product) {
+ retval = device_create_file (dev, &dev_attr_product);
+ if (retval)
+ goto error;
+ }
+ if (udev->serial) {
+ retval = device_create_file (dev, &dev_attr_serial);
+ if (retval)
+ goto error;
+ }
+ retval = usb_create_ep_files(dev, &udev->ep0, udev);
+ if (retval)
+ goto error;
+ return 0;
+error:
+ usb_remove_ep_files(&udev->ep0);
+ device_remove_file(dev, &dev_attr_manufacturer);
+ device_remove_file(dev, &dev_attr_product);
+ device_remove_file(dev, &dev_attr_serial);
+ return retval;
}
void usb_remove_sysfs_dev_files (struct usb_device *udev)
@@ -239,7 +259,6 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
device_remove_file(dev, &dev_attr_product);
if (udev->serial)
device_remove_file(dev, &dev_attr_serial);
- device_remove_file (dev, &dev_attr_configuration);
}
/* Interface fields */
@@ -341,18 +360,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
usb_remove_ep_files(&iface_desc->endpoint[i]);
}
-void usb_create_sysfs_intf_files (struct usb_interface *intf)
+int usb_create_sysfs_intf_files(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
+ int retval;
- sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+ retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+ if (retval)
+ goto error;
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
- device_create_file(&intf->dev, &dev_attr_interface);
+ retval = device_create_file(&intf->dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
+ return 0;
+error:
+ if (alt->string)
+ device_remove_file(&intf->dev, &dev_attr_interface);
+ sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
+ usb_remove_intf_ep_files(intf);
+ return retval;
}
void usb_remove_sysfs_intf_files (struct usb_interface *intf)
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index dad4d8fd818..9801d08edac 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
@@ -58,7 +57,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
- urb = (struct urb *)kmalloc(sizeof(struct urb) +
+ urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
@@ -222,7 +221,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int pipe, temp, max;
struct usb_device *dev;
- struct usb_operations *op;
int is_out;
if (!urb || urb->hcpriv || !urb->complete)
@@ -234,8 +232,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|| dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
- if (!(op = dev->bus->op) || !op->submit_urb)
- return -ENODEV;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
@@ -377,7 +373,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
- return op->submit_urb (urb, mem_flags);
+ return usb_hcd_submit_urb (urb, mem_flags);
}
/*-------------------------------------------------------------------*/
@@ -441,9 +437,9 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
- if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
+ if (!(urb->dev && urb->dev->bus))
return -ENODEV;
- return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);
+ return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
/**
@@ -469,13 +465,13 @@ int usb_unlink_urb(struct urb *urb)
void usb_kill_urb(struct urb *urb)
{
might_sleep();
- if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op))
+ if (!(urb && urb->dev && urb->dev->bus))
return;
spin_lock_irq(&urb->lock);
++urb->reject;
spin_unlock_irq(&urb->lock);
- urb->dev->bus->op->unlink_urb(urb, -ENOENT);
+ usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
spin_lock_irq(&urb->lock);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index fb488c8a860..e4df9edf1bc 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -21,7 +21,6 @@
* are evil.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/bitops.h>
@@ -34,6 +33,7 @@
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <asm/io.h>
#include <asm/scatterlist.h>
@@ -48,6 +48,8 @@ const char *usbcore_name = "usbcore";
static int nousb; /* Disable USB when built into kernel image */
+struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
+
/**
* usb_ifnum_to_if - get the interface object with a given interface number
@@ -68,7 +70,8 @@ static int nousb; /* Disable USB when built into kernel image */
* Don't call this function unless you are bound to one of the interfaces
* on this device or you have locked the device!
*/
-struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
+struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
+ unsigned ifnum)
{
struct usb_host_config *config = dev->actconfig;
int i;
@@ -101,8 +104,8 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
* Don't call this function unless you are bound to the intf interface
* or you have locked the device!
*/
-struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
- unsigned int altnum)
+struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
+ unsigned int altnum)
{
int i;
@@ -113,87 +116,6 @@ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
return NULL;
}
-/**
- * usb_driver_claim_interface - bind a driver to an interface
- * @driver: the driver to be bound
- * @iface: the interface to which it will be bound; must be in the
- * usb device's active configuration
- * @priv: driver data associated with that interface
- *
- * This is used by usb device drivers that need to claim more than one
- * interface on a device when probing (audio and acm are current examples).
- * No device driver should directly modify internal usb_interface or
- * usb_device structure members.
- *
- * Few drivers should need to use this routine, since the most natural
- * way to bind to an interface is to return the private data from
- * the driver's probe() method.
- *
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock. So driver probe() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
- */
-int usb_driver_claim_interface(struct usb_driver *driver,
- struct usb_interface *iface, void* priv)
-{
- struct device *dev = &iface->dev;
-
- if (dev->driver)
- return -EBUSY;
-
- dev->driver = &driver->driver;
- usb_set_intfdata(iface, priv);
- iface->condition = USB_INTERFACE_BOUND;
- mark_active(iface);
-
- /* if interface was already added, bind now; else let
- * the future device_add() bind it, bypassing probe()
- */
- if (device_is_registered(dev))
- device_bind_driver(dev);
-
- return 0;
-}
-
-/**
- * usb_driver_release_interface - unbind a driver from an interface
- * @driver: the driver to be unbound
- * @iface: the interface from which it will be unbound
- *
- * This can be used by drivers to release an interface without waiting
- * for their disconnect() methods to be called. In typical cases this
- * also causes the driver disconnect() method to be called.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock. So driver disconnect() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
- */
-void usb_driver_release_interface(struct usb_driver *driver,
- struct usb_interface *iface)
-{
- struct device *dev = &iface->dev;
-
- /* this should never happen, don't release something that's not ours */
- if (!dev->driver || dev->driver != &driver->driver)
- return;
-
- /* don't release from within disconnect() */
- if (iface->condition != USB_INTERFACE_BOUND)
- return;
-
- /* don't release if the interface hasn't been added yet */
- if (device_is_registered(dev)) {
- iface->condition = USB_INTERFACE_UNBINDING;
- device_release_driver(dev);
- }
-
- dev->driver = NULL;
- usb_set_intfdata(iface, NULL);
- iface->condition = USB_INTERFACE_UNBOUND;
- mark_quiesced(iface);
-}
-
struct find_interface_arg {
int minor;
struct usb_interface *interface;
@@ -205,7 +127,7 @@ static int __find_interface(struct device * dev, void * data)
struct usb_interface *intf;
/* can't look at usb devices, only interfaces */
- if (dev->driver == &usb_generic_driver)
+ if (is_usb_device(dev))
return 0;
intf = to_usb_interface(dev);
@@ -228,147 +150,82 @@ static int __find_interface(struct device * dev, void * data)
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct find_interface_arg argb;
+ int retval;
argb.minor = minor;
argb.interface = NULL;
- driver_for_each_device(&drv->driver, NULL, &argb, __find_interface);
+ /* eat the error, it will be in argb.interface */
+ retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb,
+ __find_interface);
return argb.interface;
}
-#ifdef CONFIG_HOTPLUG
-
-/*
- * This sends an uevent to userspace, typically helping to load driver
- * or other modules, configure the device, and more. Drivers can provide
- * a MODULE_DEVICE_TABLE to help with module loading subtasks.
+/**
+ * usb_release_dev - free a usb device structure when all users of it are finished.
+ * @dev: device that's been disconnected
*
- * We're called either from khubd (the typical case) or from root hub
- * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
- * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
- * device (and this configuration!) are still present.
+ * Will be called only by the device core when all users of this usb device are
+ * done.
*/
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static void usb_release_dev(struct device *dev)
{
- struct usb_interface *intf;
- struct usb_device *usb_dev;
- struct usb_host_interface *alt;
- int i = 0;
- int length = 0;
-
- if (!dev)
- return -ENODEV;
-
- /* driver is often null here; dev_dbg() would oops */
- pr_debug ("usb %s: uevent\n", dev->bus_id);
-
- /* Must check driver_data here, as on remove driver is always NULL */
- if ((dev->driver == &usb_generic_driver) ||
- (dev->driver_data == &usb_generic_driver_data))
- return 0;
-
- intf = to_usb_interface(dev);
- usb_dev = interface_to_usbdev (intf);
- alt = intf->cur_altsetting;
+ struct usb_device *udev;
- if (usb_dev->devnum < 0) {
- pr_debug ("usb %s: already deleted?\n", dev->bus_id);
- return -ENODEV;
- }
- if (!usb_dev->bus) {
- pr_debug ("usb %s: bus removed?\n", dev->bus_id);
- return -ENODEV;
- }
+ udev = to_usb_device(dev);
-#ifdef CONFIG_USB_DEVICEFS
- /* If this is available, userspace programs can directly read
- * all the device descriptors we don't tell them about. Or
- * even act as usermode drivers.
- *
- * FIXME reduce hardwired intelligence here
- */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
- usb_dev->bus->busnum, usb_dev->devnum))
- return -ENOMEM;
+#ifdef CONFIG_USB_SUSPEND
+ cancel_delayed_work(&udev->autosuspend);
+ flush_workqueue(ksuspend_usb_wq);
#endif
+ usb_destroy_configuration(udev);
+ usb_put_hcd(bus_to_hcd(udev->bus));
+ kfree(udev->product);
+ kfree(udev->manufacturer);
+ kfree(udev->serial);
+ kfree(udev);
+}
- /* per-device configurations are common */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
- le16_to_cpu(usb_dev->descriptor.idVendor),
- le16_to_cpu(usb_dev->descriptor.idProduct),
- le16_to_cpu(usb_dev->descriptor.bcdDevice)))
- return -ENOMEM;
+#ifdef CONFIG_PM
- /* class-based driver binding models */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
- usb_dev->descriptor.bDeviceClass,
- usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol))
+static int ksuspend_usb_init(void)
+{
+ ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
+ if (!ksuspend_usb_wq)
return -ENOMEM;
+ return 0;
+}
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "INTERFACE=%d/%d/%d",
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
- return -ENOMEM;
+static void ksuspend_usb_cleanup(void)
+{
+ destroy_workqueue(ksuspend_usb_wq);
+}
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
- le16_to_cpu(usb_dev->descriptor.idVendor),
- le16_to_cpu(usb_dev->descriptor.idProduct),
- le16_to_cpu(usb_dev->descriptor.bcdDevice),
- usb_dev->descriptor.bDeviceClass,
- usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol,
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
- return -ENOMEM;
+#else
- envp[i] = NULL;
+#define ksuspend_usb_init() 0
+#define ksuspend_usb_cleanup() do {} while (0)
- return 0;
-}
+#endif
-#else
+#ifdef CONFIG_USB_SUSPEND
-static int usb_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+/* usb_autosuspend_work - callback routine to autosuspend a USB device */
+static void usb_autosuspend_work(void *_udev)
{
- return -ENODEV;
-}
+ struct usb_device *udev = _udev;
-#endif /* CONFIG_HOTPLUG */
+ usb_pm_lock(udev);
+ udev->auto_pm = 1;
+ usb_suspend_both(udev, PMSG_SUSPEND);
+ usb_pm_unlock(udev);
+}
-/**
- * usb_release_dev - free a usb device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this usb device are
- * done.
- */
-static void usb_release_dev(struct device *dev)
-{
- struct usb_device *udev;
+#else
- udev = to_usb_device(dev);
+static void usb_autosuspend_work(void *_udev)
+{}
- usb_destroy_configuration(udev);
- usb_bus_put(udev->bus);
- kfree(udev->product);
- kfree(udev->manufacturer);
- kfree(udev->serial);
- kfree(udev);
-}
+#endif
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
@@ -391,8 +248,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
if (!dev)
return NULL;
- bus = usb_bus_get(bus);
- if (!bus) {
+ if (!usb_get_hcd(bus_to_hcd(bus))) {
kfree(dev);
return NULL;
}
@@ -400,11 +256,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.dma_mask = bus->controller->dma_mask;
- dev->dev.driver_data = &usb_generic_driver_data;
- dev->dev.driver = &usb_generic_driver;
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
+ /* This magic assignment distinguishes devices from interfaces */
+ dev->dev.platform_data = &usb_generic_driver;
+
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
@@ -445,6 +302,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
+#ifdef CONFIG_PM
+ mutex_init(&dev->pm_mutex);
+ INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev);
+#endif
return dev;
}
@@ -550,7 +411,7 @@ void usb_put_intf(struct usb_interface *intf)
* case the driver already owns the device lock.)
*/
int usb_lock_device_for_reset(struct usb_device *udev,
- struct usb_interface *iface)
+ const struct usb_interface *iface)
{
unsigned long jiffies_expire = jiffies + HZ;
@@ -673,7 +534,139 @@ exit:
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
- return dev->bus->op->get_frame_number (dev);
+ return usb_hcd_get_frame_number (dev);
+}
+
+/**
+ * usb_endpoint_dir_in - check if the endpoint has IN direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type IN, otherwise it returns false.
+ */
+int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
+}
+
+/**
+ * usb_endpoint_dir_out - check if the endpoint has OUT direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type OUT, otherwise it returns false.
+ */
+int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+}
+
+/**
+ * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type bulk, otherwise it returns false.
+ */
+int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK);
+}
+
+/**
+ * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type interrupt, otherwise it returns
+ * false.
+ */
+int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT);
+}
+
+/**
+ * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type isochronous, otherwise it returns
+ * false.
+ */
+int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_ISOC);
+}
+
+/**
+ * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has bulk transfer type and IN direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has bulk transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
+}
+
+/**
+ * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and IN direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
+}
+
+/**
+ * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has isochronous transfer type and IN direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has isochronous transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
}
/*-------------------------------------------------------------------*/
@@ -738,9 +731,9 @@ void *usb_buffer_alloc (
dma_addr_t *dma
)
{
- if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
+ if (!dev || !dev->bus)
return NULL;
- return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
+ return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
}
/**
@@ -761,9 +754,11 @@ void usb_buffer_free (
dma_addr_t dma
)
{
- if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
- return;
- dev->bus->op->buffer_free (dev->bus, size, addr, dma);
+ if (!dev || !dev->bus)
+ return;
+ if (!addr)
+ return;
+ hcd_buffer_free (dev->bus, size, addr, dma);
}
/**
@@ -912,8 +907,8 @@ void usb_buffer_unmap (struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int nents)
+int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
@@ -947,8 +942,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int n_hw_ents)
+void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
@@ -973,8 +968,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
*
* Reverses the effect of usb_buffer_map_sg().
*/
-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int n_hw_ents)
+void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
@@ -989,116 +984,6 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
-static int verify_suspended(struct device *dev, void *unused)
-{
- if (dev->driver == NULL)
- return 0;
- return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
-}
-
-static int usb_generic_suspend(struct device *dev, pm_message_t message)
-{
- struct usb_interface *intf;
- struct usb_driver *driver;
- int status;
-
- /* USB devices enter SUSPEND state through their hubs, but can be
- * marked for FREEZE as soon as their children are already idled.
- * But those semantics are useless, so we equate the two (sigh).
- */
- if (dev->driver == &usb_generic_driver) {
- if (dev->power.power_state.event == message.event)
- return 0;
- /* we need to rule out bogus requests through sysfs */
- status = device_for_each_child(dev, NULL, verify_suspended);
- if (status)
- return status;
- return usb_suspend_device (to_usb_device(dev));
- }
-
- if ((dev->driver == NULL) ||
- (dev->driver_data == &usb_generic_driver_data))
- return 0;
-
- intf = to_usb_interface(dev);
- driver = to_usb_driver(dev->driver);
-
- /* with no hardware, USB interfaces only use FREEZE and ON states */
- if (!is_active(intf))
- return 0;
-
- if (driver->suspend && driver->resume) {
- status = driver->suspend(intf, message);
- if (status)
- dev_err(dev, "%s error %d\n", "suspend", status);
- else
- mark_quiesced(intf);
- } else {
- // FIXME else if there's no suspend method, disconnect...
- dev_warn(dev, "no suspend for driver %s?\n", driver->name);
- mark_quiesced(intf);
- status = 0;
- }
- return status;
-}
-
-static int usb_generic_resume(struct device *dev)
-{
- struct usb_interface *intf;
- struct usb_driver *driver;
- struct usb_device *udev;
- int status;
-
- if (dev->power.power_state.event == PM_EVENT_ON)
- return 0;
-
- /* mark things as "on" immediately, no matter what errors crop up */
- dev->power.power_state.event = PM_EVENT_ON;
-
- /* devices resume through their hubs */
- if (dev->driver == &usb_generic_driver) {
- udev = to_usb_device(dev);
- if (udev->state == USB_STATE_NOTATTACHED)
- return 0;
- return usb_resume_device (to_usb_device(dev));
- }
-
- if ((dev->driver == NULL) ||
- (dev->driver_data == &usb_generic_driver_data)) {
- dev->power.power_state.event = PM_EVENT_FREEZE;
- return 0;
- }
-
- intf = to_usb_interface(dev);
- driver = to_usb_driver(dev->driver);
-
- udev = interface_to_usbdev(intf);
- if (udev->state == USB_STATE_NOTATTACHED)
- return 0;
-
- /* if driver was suspended, it has a resume method;
- * however, sysfs can wrongly mark things as suspended
- * (on the "no suspend method" FIXME path above)
- */
- if (driver->resume) {
- status = driver->resume(intf);
- if (status) {
- dev_err(dev, "%s error %d\n", "resume", status);
- mark_quiesced(intf);
- }
- } else
- dev_warn(dev, "no resume for driver %s?\n", driver->name);
- return 0;
-}
-
-struct bus_type usb_bus_type = {
- .name = "usb",
- .match = usb_device_match,
- .uevent = usb_uevent,
- .suspend = usb_generic_suspend,
- .resume = usb_generic_resume,
-};
-
/* format to disable USB on kernel command line is: nousb */
__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
@@ -1121,9 +1006,12 @@ static int __init usb_init(void)
return 0;
}
+ retval = ksuspend_usb_init();
+ if (retval)
+ goto out;
retval = bus_register(&usb_bus_type);
if (retval)
- goto out;
+ goto bus_register_failed;
retval = usb_host_init();
if (retval)
goto host_init_failed;
@@ -1142,7 +1030,7 @@ static int __init usb_init(void)
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
- retval = driver_register(&usb_generic_driver);
+ retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
if (!retval)
goto out;
@@ -1159,6 +1047,8 @@ major_init_failed:
usb_host_cleanup();
host_init_failed:
bus_unregister(&usb_bus_type);
+bus_register_failed:
+ ksuspend_usb_cleanup();
out:
return retval;
}
@@ -1172,7 +1062,7 @@ static void __exit usb_exit(void)
if (nousb)
return;
- driver_unregister(&usb_generic_driver);
+ usb_deregister_device_driver(&usb_generic_driver);
usb_major_cleanup();
usbfs_cleanup();
usb_deregister(&usbfs_driver);
@@ -1180,6 +1070,7 @@ static void __exit usb_exit(void)
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister(&usb_bus_type);
+ ksuspend_usb_cleanup();
}
subsys_initcall(usb_init);
@@ -1202,20 +1093,27 @@ EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
EXPORT_SYMBOL(usb_lock_device_for_reset);
-EXPORT_SYMBOL(usb_driver_claim_interface);
-EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
EXPORT_SYMBOL(usb_altnum_to_altsetting);
-EXPORT_SYMBOL(usb_reset_device);
-EXPORT_SYMBOL(usb_reset_composite_device);
-
EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
+EXPORT_SYMBOL_GPL(usb_endpoint_dir_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_dir_out);
+EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk);
+EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int);
+EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out);
+
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 7a650c763a6..f69df137ec0 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -1,10 +1,10 @@
/* Functions local to drivers/usb/core/ */
-extern void usb_create_sysfs_dev_files (struct usb_device *dev);
+extern int usb_create_sysfs_dev_files (struct usb_device *dev);
extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
-extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
+extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
-extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
+extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
@@ -20,7 +20,6 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_kick_khubd(struct usb_device *dev);
-extern void usb_suspend_root_hub(struct usb_device *hdev);
extern void usb_resume_root_hub(struct usb_device *dev);
extern int usb_hub_init(void);
@@ -30,28 +29,91 @@ extern void usb_major_cleanup(void);
extern int usb_host_init(void);
extern void usb_host_cleanup(void);
-extern int usb_suspend_device(struct usb_device *dev);
-extern int usb_resume_device(struct usb_device *dev);
+#ifdef CONFIG_PM
-extern struct device_driver usb_generic_driver;
-extern int usb_generic_driver_data;
-extern int usb_device_match(struct device *dev, struct device_driver *drv);
+extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
+extern int usb_resume_both(struct usb_device *udev);
+extern int usb_port_suspend(struct usb_device *dev);
+extern int usb_port_resume(struct usb_device *dev);
+
+static inline void usb_pm_lock(struct usb_device *udev)
+{
+ mutex_lock_nested(&udev->pm_mutex, udev->level);
+}
+
+static inline void usb_pm_unlock(struct usb_device *udev)
+{
+ mutex_unlock(&udev->pm_mutex);
+}
+
+#else
+
+#define usb_suspend_both(udev, msg) 0
+static inline int usb_resume_both(struct usb_device *udev)
+{
+ return 0;
+}
+#define usb_port_suspend(dev) 0
+#define usb_port_resume(dev) 0
+static inline void usb_pm_lock(struct usb_device *udev) {}
+static inline void usb_pm_unlock(struct usb_device *udev) {}
+
+#endif
+
+#ifdef CONFIG_USB_SUSPEND
+
+#define USB_AUTOSUSPEND_DELAY (HZ*2)
+
+extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt);
+extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt);
+
+#else
+
+#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0)
+static inline int usb_autoresume_device(struct usb_device *udev,
+ int inc_busy_cnt)
+{
+ return 0;
+}
+
+#endif
+
+extern struct workqueue_struct *ksuspend_usb_wq;
+extern struct bus_type usb_bus_type;
+extern struct usb_device_driver usb_generic_driver;
+
+/* Here's how we tell apart devices and interfaces. Luckily there's
+ * no such thing as a platform USB device, so we can steal the use
+ * of the platform_data field. */
+
+static inline int is_usb_device(const struct device *dev)
+{
+ return dev->platform_data == &usb_generic_driver;
+}
+
+/* Do the same for device drivers and interface drivers. */
+
+static inline int is_usb_device_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct usbdrv_wrap, driver)->
+ for_devices;
+}
/* Interfaces and their "power state" are owned by usbcore */
static inline void mark_active(struct usb_interface *f)
{
- f->dev.power.power_state.event = PM_EVENT_ON;
+ f->is_active = 1;
}
static inline void mark_quiesced(struct usb_interface *f)
{
- f->dev.power.power_state.event = PM_EVENT_FREEZE;
+ f->is_active = 0;
}
-static inline int is_active(struct usb_interface *f)
+static inline int is_active(const struct usb_interface *f)
{
- return f->dev.power.power_state.event == PM_EVENT_ON;
+ return f->is_active;
}
@@ -59,9 +121,10 @@ static inline int is_active(struct usb_interface *f)
extern const char *usbcore_name;
/* usbfs stuff */
+extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
-extern struct file_operations usbfs_devices_fops;
-extern struct file_operations usbfs_device_file_operations;
+extern const struct file_operations usbfs_devices_fops;
+extern const struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);
extern int usbdev_init(void);
@@ -80,6 +143,7 @@ struct dev_state {
uid_t disc_uid, disc_euid;
void __user *disccontext;
unsigned long ifclaimed;
+ u32 secid;
};
/* internal notify stuff */
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 363b2ad74ae..8e5dd6f29d0 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -26,7 +26,7 @@ config USB_GADGET
you need a low level bus controller driver, and some software
talking to it. Peripheral controllers are often discrete silicon,
or are integrated with the CPU in a microcontroller. The more
- familiar host side controllers have names like like "EHCI", "OHCI",
+ familiar host side controllers have names like "EHCI", "OHCI",
or "UHCI", and are usually integrated into southbridges on PC
motherboards.
@@ -207,7 +207,7 @@ config USB_AT91
config USB_GADGET_DUMMY_HCD
boolean "Dummy HCD (DEVELOPMENT)"
- depends on USB && EXPERIMENTAL
+ depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
select USB_GADGET_DUALSPEED
help
This host controller driver emulates USB, looping all data transfer
@@ -404,6 +404,20 @@ config USB_G_SERIAL
which includes instructions and a "driver info file" needed to
make MS-Windows work with this driver.
+config USB_MIDI_GADGET
+ tristate "MIDI Gadget (EXPERIMENTAL)"
+ depends on SND && EXPERIMENTAL
+ select SND_RAWMIDI
+ help
+ The MIDI Gadget acts as a USB Audio device, with one MIDI
+ input and one MIDI output. These MIDI jacks appear as
+ a sound "card" in the ALSA sound system. Other MIDI
+ connections can then be made on the gadget system, using
+ ALSA's aconnect utility etc.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_midi".
+
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5a28e61392e..e71e086a1cf 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o
g_zero-objs := zero.o usbstring.o config.o epautoconf.o
g_ether-objs := ether.o usbstring.o config.o epautoconf.o
g_serial-objs := serial.o usbstring.o config.o epautoconf.o
+g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o usbstring.o config.o \
epautoconf.o
@@ -28,4 +29,5 @@ obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index b8d0b7825bf..77beba485a8 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -25,7 +25,6 @@
#undef VERBOSE
#undef PACKET_TRACE
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
@@ -58,19 +57,23 @@
/*
* This controller is simple and PIO-only. It's used in many AT91-series
- * ARMv4T controllers, including the at91rm9200 (arm920T, with MMU),
- * at91sam9261 (arm926ejs, with MMU), and several no-mmu versions.
+ * full speed USB controllers, including the at91rm9200 (arm920T, with MMU),
+ * at91sam926x (arm926ejs, with MMU), and several no-mmu versions.
*
* This driver expects the board has been wired with two GPIOs suppporting
* a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the
- * testing hasn't covered such cases.) The pullup is most important; it
+ * testing hasn't covered such cases.)
+ *
+ * The pullup is most important (so it's integrated on sam926x parts). It
* provides software control over whether the host enumerates the device.
+ *
* The VBUS sensing helps during enumeration, and allows both USB clocks
* (and the transceiver) to stay gated off until they're necessary, saving
- * power. During USB suspend, the 48 MHz clock is gated off.
+ * power. During USB suspend, the 48 MHz clock is gated off in hardware;
+ * it may also be gated off by software during some Linux sleep states.
*/
-#define DRIVER_VERSION "8 March 2005"
+#define DRIVER_VERSION "3 May 2006"
static const char driver_name [] = "at91_udc";
static const char ep0name[] = "ep0";
@@ -244,7 +247,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
return single_open(file, proc_udc_show, PDE(inode)->data);
}
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -317,9 +320,15 @@ static void done(struct at91_ep *ep, struct at91_request *req, int status)
*
* There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE
* that shouldn't normally be changed.
+ *
+ * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains,
+ * implying a need to wait for one write to complete (test relevant bits)
+ * before starting the next write. This shouldn't be an issue given how
+ * infrequently we write, except maybe for write-then-read idioms.
*/
#define SET_FX (AT91_UDP_TXPKTRDY)
-#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
+#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \
+ | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)
/* pull OUT packet data from the endpoint's fifo */
static int read_fifo (struct at91_ep *ep, struct at91_request *req)
@@ -473,7 +482,8 @@ static void nuke(struct at91_ep *ep, int status)
/*-------------------------------------------------------------------------*/
-static int at91_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+static int at91_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
{
struct at91_ep *ep = container_of(_ep, struct at91_ep, ep);
struct at91_udc *dev = ep->udc;
@@ -583,11 +593,12 @@ static int at91_ep_disable (struct usb_ep * _ep)
* interesting for request or buffer allocation.
*/
-static struct usb_request *at91_ep_alloc_request (struct usb_ep *_ep, unsigned int gfp_flags)
+static struct usb_request *
+at91_ep_alloc_request(struct usb_ep *_ep, unsigned int gfp_flags)
{
struct at91_request *req;
- req = kcalloc(1, sizeof (struct at91_request), SLAB_KERNEL);
+ req = kcalloc(1, sizeof (struct at91_request), gfp_flags);
if (!req)
return NULL;
@@ -863,6 +874,7 @@ static void stop_activity(struct at91_udc *udc)
if (udc->gadget.speed == USB_SPEED_UNKNOWN)
driver = NULL;
udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->suspended = 0;
for (i = 0; i < NUM_ENDPOINTS; i++) {
struct at91_ep *ep = &udc->ep[i];
@@ -890,8 +902,8 @@ static void clk_off(struct at91_udc *udc)
return;
udc->clocked = 0;
udc->gadget.speed = USB_SPEED_UNKNOWN;
- clk_disable(udc->iclk);
clk_disable(udc->fclk);
+ clk_disable(udc->iclk);
}
/*
@@ -912,9 +924,6 @@ static void pullup(struct at91_udc *udc, int is_on)
at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_set_gpio_value(udc->board.pullup_pin, 0);
clk_off(udc);
-
- // REVISIT: with transceiver disabled, will D- float
- // so that a host would falsely detect a device?
}
}
@@ -1291,7 +1300,8 @@ static void handle_ep0(struct at91_udc *udc)
if (udc->wait_for_addr_ack) {
u32 tmp;
- at91_udp_write(AT91_UDP_FADDR, AT91_UDP_FEN | udc->addr);
+ at91_udp_write(AT91_UDP_FADDR,
+ AT91_UDP_FEN | udc->addr);
tmp = at91_udp_read(AT91_UDP_GLB_STAT);
tmp &= ~AT91_UDP_FADDEN;
if (udc->addr)
@@ -1362,9 +1372,10 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
u32 rescans = 5;
while (rescans--) {
- u32 status = at91_udp_read(AT91_UDP_ISR);
+ u32 status;
- status &= at91_udp_read(AT91_UDP_IMR);
+ status = at91_udp_read(AT91_UDP_ISR)
+ & at91_udp_read(AT91_UDP_IMR);
if (!status)
break;
@@ -1380,18 +1391,17 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
stop_activity(udc);
/* enable ep0 */
- at91_udp_write(AT91_UDP_CSR(0), AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
+ at91_udp_write(AT91_UDP_CSR(0),
+ AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL);
udc->gadget.speed = USB_SPEED_FULL;
udc->suspended = 0;
at91_udp_write(AT91_UDP_IER, AT91_UDP_EP(0));
/*
* NOTE: this driver keeps clocks off unless the
- * USB host is present. That saves power, and also
- * eliminates IRQs (reset, resume, suspend) that can
- * otherwise flood from the controller. If your
- * board doesn't support VBUS detection, suspend and
- * resume irq logic may need more attention...
+ * USB host is present. That saves power, but for
+ * boards that don't support VBUS detection, both
+ * clocks need to be active most of the time.
*/
/* host initiated suspend (3+ms bus idle) */
@@ -1453,13 +1463,19 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
/*-------------------------------------------------------------------------*/
+static void nop_release(struct device *dev)
+{
+ /* nothing to free */
+}
+
static struct at91_udc controller = {
.gadget = {
- .ops = &at91_udc_ops,
- .ep0 = &controller.ep[0].ep,
- .name = driver_name,
- .dev = {
- .bus_id = "gadget"
+ .ops = &at91_udc_ops,
+ .ep0 = &controller.ep[0].ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ .release = nop_release,
}
},
.ep[0] = {
@@ -1469,7 +1485,8 @@ static struct at91_udc controller = {
},
.udc = &controller,
.maxpacket = 8,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(0)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(0)),
.int_mask = 1 << 0,
},
.ep[1] = {
@@ -1480,7 +1497,8 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 64,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(1)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(1)),
.int_mask = 1 << 1,
},
.ep[2] = {
@@ -1491,7 +1509,8 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 64,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(2)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(2)),
.int_mask = 1 << 2,
},
.ep[3] = {
@@ -1502,7 +1521,8 @@ static struct at91_udc controller = {
},
.udc = &controller,
.maxpacket = 8,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(3)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(3)),
.int_mask = 1 << 3,
},
.ep[4] = {
@@ -1513,7 +1533,8 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 256,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(4)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(4)),
.int_mask = 1 << 4,
},
.ep[5] = {
@@ -1524,10 +1545,11 @@ static struct at91_udc controller = {
.udc = &controller,
.is_pingpong = 1,
.maxpacket = 256,
- .creg = (void __iomem *)(AT91_VA_BASE_UDP + AT91_UDP_CSR(5)),
+ .creg = (void __iomem *)(AT91_VA_BASE_UDP
+ + AT91_UDP_CSR(5)),
.int_mask = 1 << 5,
},
- /* ep6 and ep7 are also reserved */
+ /* ep6 and ep7 are also reserved (custom silicon might use them) */
};
static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
@@ -1594,6 +1616,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
local_irq_disable();
udc->enabled = 0;
+ at91_udp_write(AT91_UDP_IDR, ~0);
pullup(udc, 0);
local_irq_enable();
@@ -1625,7 +1648,17 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
+ if (pdev->num_resources != 2) {
+ DBG("invalid num_resources");
+ return -ENODEV;
+ }
+ if ((pdev->resource[0].flags != IORESOURCE_MEM)
+ || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+ DBG("invalid resource type");
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
DBG("someone's using UDC memory\n");
return -EBUSY;
}
@@ -1650,19 +1683,26 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
if (retval < 0)
goto fail0;
- /* disable everything until there's a gadget driver and vbus */
- pullup(udc, 0);
+ /* don't do anything until we have both gadget driver and VBUS */
+ clk_enable(udc->iclk);
+ at91_udp_write(AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
+ at91_udp_write(AT91_UDP_IDR, 0xffffffff);
+ clk_disable(udc->iclk);
/* request UDC and maybe VBUS irqs */
- if (request_irq(AT91_ID_UDP, at91_udc_irq, SA_INTERRUPT, driver_name, udc)) {
- DBG("request irq %d failed\n", AT91_ID_UDP);
+ udc->udp_irq = platform_get_irq(pdev, 0);
+ if (request_irq(udc->udp_irq, at91_udc_irq,
+ IRQF_DISABLED, driver_name, udc)) {
+ DBG("request irq %d failed\n", udc->udp_irq);
retval = -EBUSY;
goto fail1;
}
if (udc->board.vbus_pin > 0) {
- if (request_irq(udc->board.vbus_pin, at91_vbus_irq, SA_INTERRUPT, driver_name, udc)) {
- DBG("request vbus irq %d failed\n", udc->board.vbus_pin);
- free_irq(AT91_ID_UDP, udc);
+ if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
+ IRQF_DISABLED, driver_name, udc)) {
+ DBG("request vbus irq %d failed\n",
+ udc->board.vbus_pin);
+ free_irq(udc->udp_irq, udc);
retval = -EBUSY;
goto fail1;
}
@@ -1671,6 +1711,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
udc->vbus = 1;
}
dev_set_drvdata(dev, udc);
+ device_init_wakeup(dev, 1);
create_debug_file(udc);
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
@@ -1679,14 +1720,14 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
fail1:
device_unregister(&udc->gadget.dev);
fail0:
- release_mem_region(AT91_VA_BASE_UDP, SZ_16K);
+ release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
DBG("%s probe failed, %d\n", driver_name, retval);
return retval;
}
-static int __devexit at91udc_remove(struct platform_device *dev)
+static int __devexit at91udc_remove(struct platform_device *pdev)
{
- struct at91_udc *udc = platform_get_drvdata(dev);
+ struct at91_udc *udc = platform_get_drvdata(pdev);
DBG("remove\n");
@@ -1695,12 +1736,13 @@ static int __devexit at91udc_remove(struct platform_device *dev)
if (udc->driver != 0)
usb_gadget_unregister_driver(udc->driver);
+ device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
if (udc->board.vbus_pin > 0)
free_irq(udc->board.vbus_pin, udc);
- free_irq(AT91_ID_UDP, udc);
+ free_irq(udc->udp_irq, udc);
device_unregister(&udc->gadget.dev);
- release_mem_region(AT91_BASE_UDP, SZ_16K);
+ release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
clk_put(udc->iclk);
clk_put(udc->fclk);
@@ -1709,31 +1751,36 @@ static int __devexit at91udc_remove(struct platform_device *dev)
}
#ifdef CONFIG_PM
-static int at91udc_suspend(struct platform_device *dev, pm_message_t mesg)
+static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- struct at91_udc *udc = platform_get_drvdata(dev);
+ struct at91_udc *udc = platform_get_drvdata(pdev);
+ int wake = udc->driver && device_may_wakeup(&pdev->dev);
- /*
- * The "safe" suspend transitions are opportunistic ... e.g. when
- * the USB link is suspended (48MHz clock autogated off), or when
- * it's disconnected (programmatically gated off, elsewhere).
- * Then we can suspend, and the chip can enter slow clock mode.
- *
- * The problem case is some component (user mode?) suspending this
- * device while it's active, with the 48 MHz clock in use. There
- * are two basic approaches: (a) veto suspend levels involving slow
- * clock mode, (b) disconnect, so 48 MHz will no longer be in use
- * and we can enter slow clock mode. This uses (b) for now, since
- * it's simplest until AT91 PM exists and supports the other option.
+ /* Unless we can act normally to the host (letting it wake us up
+ * whenever it has work for us) force disconnect. Wakeup requires
+ * PLLB for USB events (signaling for reset, wakeup, or incoming
+ * tokens) and VBUS irqs (on systems which support them).
*/
- if (udc->vbus && !udc->suspended)
+ if ((!udc->suspended && udc->addr)
+ || !wake
+ || at91_suspend_entering_slow_clock()) {
pullup(udc, 0);
+ disable_irq_wake(udc->udp_irq);
+ } else
+ enable_irq_wake(udc->udp_irq);
+
+ if (udc->board.vbus_pin > 0) {
+ if (wake)
+ enable_irq_wake(udc->board.vbus_pin);
+ else
+ disable_irq_wake(udc->board.vbus_pin);
+ }
return 0;
}
-static int at91udc_resume(struct platform_device *dev)
+static int at91udc_resume(struct platform_device *pdev)
{
- struct at91_udc *udc = platform_get_drvdata(dev);
+ struct at91_udc *udc = platform_get_drvdata(pdev);
/* maybe reconnect to host; if so, clocks on */
pullup(udc, 1);
@@ -1749,7 +1796,7 @@ static struct platform_driver at91_udc = {
.remove = __devexit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
.suspend = at91udc_suspend,
- .resume = at91udc_resume,
+ .resume = at91udc_resume,
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
@@ -1768,6 +1815,6 @@ static void __devexit udc_exit_module(void)
}
module_exit(udc_exit_module);
-MODULE_DESCRIPTION("AT91RM9200 udc driver");
+MODULE_DESCRIPTION("AT91 udc driver");
MODULE_AUTHOR("Thomas Rathbone, David Brownell");
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 5a4799cedd1..882af42e86c 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -141,6 +141,7 @@ struct at91_udc {
struct clk *iclk, *fclk;
struct platform_device *pdev;
struct proc_dir_entry *pde;
+ int udp_irq;
};
static inline struct at91_udc *to_udc(struct usb_gadget *g)
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 42ce41d71b7..4d2946e540c 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -36,7 +36,6 @@
#define DEBUG
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -610,7 +609,8 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
if (!dum->driver)
return -ESHUTDOWN;
- spin_lock_irqsave (&dum->lock, flags);
+ local_irq_save (flags);
+ spin_lock (&dum->lock);
list_for_each_entry (req, &ep->queue, queue) {
if (&req->req == _req) {
list_del_init (&req->queue);
@@ -619,7 +619,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
break;
}
}
- spin_unlock_irqrestore (&dum->lock, flags);
+ spin_unlock (&dum->lock);
if (retval == 0) {
dev_dbg (udc_dev(dum),
@@ -627,6 +627,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
req, _ep->name, _req->length, _req->buf);
_req->complete (_ep, _req);
}
+ local_irq_restore (flags);
return retval;
}
@@ -815,15 +816,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
dum->gadget.dev.driver = &driver->driver;
dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
- if ((retval = driver->bind (&dum->gadget)) != 0) {
- dum->driver = NULL;
- dum->gadget.dev.driver = NULL;
- return retval;
- }
+ if ((retval = driver->bind (&dum->gadget)) != 0)
+ goto err_bind_gadget;
driver->driver.bus = dum->gadget.dev.parent->bus;
- driver_register (&driver->driver);
- device_bind_driver (&dum->gadget.dev);
+ if ((retval = driver_register (&driver->driver)) != 0)
+ goto err_register;
+ if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
+ goto err_bind_driver;
/* khubd will enumerate this in a while */
spin_lock_irq (&dum->lock);
@@ -833,6 +833,19 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
+
+err_bind_driver:
+ driver_unregister (&driver->driver);
+err_register:
+ driver->unbind (&dum->gadget);
+ spin_lock_irq (&dum->lock);
+ dum->pullup = 0;
+ set_link_state (dum);
+ spin_unlock_irq (&dum->lock);
+err_bind_gadget:
+ dum->driver = NULL;
+ dum->gadget.dev.driver = NULL;
+ return retval;
}
EXPORT_SYMBOL (usb_gadget_register_driver);
@@ -888,11 +901,9 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
static void
dummy_gadget_release (struct device *dev)
{
-#if 0 /* usb_bus_put isn't EXPORTed! */
struct dummy *dum = gadget_dev_to_dummy (dev);
- usb_bus_put (&dummy_to_hcd (dum)->self);
-#endif
+ usb_put_hcd (dummy_to_hcd (dum));
}
static int dummy_udc_probe (struct platform_device *pdev)
@@ -914,12 +925,12 @@ static int dummy_udc_probe (struct platform_device *pdev)
if (rc < 0)
return rc;
-#if 0 /* usb_bus_get isn't EXPORTed! */
- usb_bus_get (&dummy_to_hcd (dum)->self);
-#endif
+ usb_get_hcd (dummy_to_hcd (dum));
platform_set_drvdata (pdev, dum);
- device_create_file (&dum->gadget.dev, &dev_attr_function);
+ rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
+ if (rc < 0)
+ device_unregister (&dum->gadget.dev);
return rc;
}
@@ -1867,8 +1878,7 @@ static int dummy_start (struct usb_hcd *hcd)
#endif
/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
- device_create_file (dummy_dev(dum), &dev_attr_urbs);
- return 0;
+ return device_create_file (dummy_dev(dum), &dev_attr_urbs);
}
static void dummy_stop (struct usb_hcd *hcd)
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index f7c6d758e1b..53d584589c2 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -34,12 +34,12 @@
/* we must assign addresses for configurable endpoints (like net2280) */
-static __initdata unsigned epnum;
+static __devinitdata unsigned epnum;
// #define MANY_ENDPOINTS
#ifdef MANY_ENDPOINTS
/* more than 15 configurable endpoints */
-static __initdata unsigned in_epnum;
+static __devinitdata unsigned in_epnum;
#endif
@@ -59,7 +59,7 @@ static __initdata unsigned in_epnum;
* NOTE: each endpoint is unidirectional, as specified by its USB
* descriptor; and isn't specific to a configuration or altsetting.
*/
-static int __init
+static int __devinit
ep_matches (
struct usb_gadget *gadget,
struct usb_ep *ep,
@@ -73,7 +73,7 @@ ep_matches (
/* endpoint already claimed? */
if (0 != ep->driver_data)
return 0;
-
+
/* only support ep0 for portable CONTROL traffic */
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
if (USB_ENDPOINT_XFER_CONTROL == type)
@@ -186,7 +186,7 @@ ep_matches (
return 1;
}
-static struct usb_ep * __init
+static struct usb_ep * __devinit
find_ep (struct usb_gadget *gadget, const char *name)
{
struct usb_ep *ep;
@@ -228,7 +228,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
*
* On failure, this returns a null endpoint descriptor.
*/
-struct usb_ep * __init usb_ep_autoconfig (
+struct usb_ep * __devinit usb_ep_autoconfig (
struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc
)
@@ -276,7 +276,7 @@ struct usb_ep * __init usb_ep_autoconfig (
return ep;
}
- /* Second, look at endpoints until an unclaimed one looks usable */
+ /* Second, look at endpoints until an unclaimed one looks usable */
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
if (ep_matches (gadget, ep, desc))
return ep;
@@ -295,7 +295,7 @@ struct usb_ep * __init usb_ep_autoconfig (
* state such as ep->driver_data and the record of assigned endpoints
* used by usb_ep_autoconfig().
*/
-void __init usb_ep_autoconfig_reset (struct usb_gadget *gadget)
+void __devinit usb_ep_autoconfig_reset (struct usb_gadget *gadget)
{
struct usb_ep *ep;
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 078daa02671..366dc0a9e52 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -23,7 +23,6 @@
// #define DEBUG 1
// #define VERBOSE
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -118,6 +117,8 @@ struct eth_dev {
struct usb_ep *in_ep, *out_ep, *status_ep;
const struct usb_endpoint_descriptor
*in, *out, *status;
+
+ spinlock_t req_lock;
struct list_head tx_reqs, rx_reqs;
struct net_device *net;
@@ -261,7 +262,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define DEV_CONFIG_CDC
#endif
@@ -1067,21 +1068,31 @@ static void eth_reset_config (struct eth_dev *dev)
*/
if (dev->in) {
usb_ep_disable (dev->in_ep);
+ spin_lock(&dev->req_lock);
while (likely (!list_empty (&dev->tx_reqs))) {
req = container_of (dev->tx_reqs.next,
struct usb_request, list);
list_del (&req->list);
+
+ spin_unlock(&dev->req_lock);
usb_ep_free_request (dev->in_ep, req);
+ spin_lock(&dev->req_lock);
}
+ spin_unlock(&dev->req_lock);
}
if (dev->out) {
usb_ep_disable (dev->out_ep);
+ spin_lock(&dev->req_lock);
while (likely (!list_empty (&dev->rx_reqs))) {
req = container_of (dev->rx_reqs.next,
struct usb_request, list);
list_del (&req->list);
+
+ spin_unlock(&dev->req_lock);
usb_ep_free_request (dev->out_ep, req);
+ spin_lock(&dev->req_lock);
}
+ spin_unlock(&dev->req_lock);
}
if (dev->status) {
@@ -1660,9 +1671,9 @@ enomem:
if (retval) {
DEBUG (dev, "rx submit --> %d\n", retval);
dev_kfree_skb_any (skb);
- spin_lock (&dev->lock);
+ spin_lock(&dev->req_lock);
list_add (&req->list, &dev->rx_reqs);
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->req_lock);
}
return retval;
}
@@ -1731,8 +1742,9 @@ quiesce:
dev_kfree_skb_any (skb);
if (!netif_running (dev->net)) {
clean:
- /* nobody reading rx_reqs, so no dev->lock */
+ spin_lock(&dev->req_lock);
list_add (&req->list, &dev->rx_reqs);
+ spin_unlock(&dev->req_lock);
req = NULL;
}
if (req)
@@ -1783,15 +1795,18 @@ static int alloc_requests (struct eth_dev *dev, unsigned n, gfp_t gfp_flags)
{
int status;
+ spin_lock(&dev->req_lock);
status = prealloc (&dev->tx_reqs, dev->in_ep, n, gfp_flags);
if (status < 0)
goto fail;
status = prealloc (&dev->rx_reqs, dev->out_ep, n, gfp_flags);
if (status < 0)
goto fail;
- return 0;
+ goto done;
fail:
DEBUG (dev, "can't alloc requests\n");
+done:
+ spin_unlock(&dev->req_lock);
return status;
}
@@ -1801,21 +1816,21 @@ static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags)
unsigned long flags;
/* fill unused rxq slots with some skb */
- spin_lock_irqsave (&dev->lock, flags);
+ spin_lock_irqsave(&dev->req_lock, flags);
while (!list_empty (&dev->rx_reqs)) {
req = container_of (dev->rx_reqs.next,
struct usb_request, list);
list_del_init (&req->list);
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
if (rx_submit (dev, req, gfp_flags) < 0) {
defer_kevent (dev, WORK_RX_MEMORY);
return;
}
- spin_lock_irqsave (&dev->lock, flags);
+ spin_lock_irqsave(&dev->req_lock, flags);
}
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
}
static void eth_work (void *_dev)
@@ -1849,9 +1864,9 @@ static void tx_complete (struct usb_ep *ep, struct usb_request *req)
}
dev->stats.tx_packets++;
- spin_lock (&dev->lock);
+ spin_lock(&dev->req_lock);
list_add (&req->list, &dev->tx_reqs);
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->req_lock);
dev_kfree_skb_any (skb);
atomic_dec (&dev->tx_qlen);
@@ -1897,12 +1912,12 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
/* ignores USB_CDC_PACKET_TYPE_DIRECTED */
}
- spin_lock_irqsave (&dev->lock, flags);
+ spin_lock_irqsave(&dev->req_lock, flags);
req = container_of (dev->tx_reqs.next, struct usb_request, list);
list_del (&req->list);
if (list_empty (&dev->tx_reqs))
netif_stop_queue (net);
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
/* no buffer copies needed, unless the network stack did it
* or the hardware can't use skb buffers.
@@ -1956,11 +1971,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
drop:
dev->stats.tx_dropped++;
dev_kfree_skb_any (skb);
- spin_lock_irqsave (&dev->lock, flags);
+ spin_lock_irqsave(&dev->req_lock, flags);
if (list_empty (&dev->tx_reqs))
netif_start_queue (net);
list_add (&req->list, &dev->tx_reqs);
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->req_lock, flags);
}
return 0;
}
@@ -1999,7 +2014,7 @@ rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
static int rndis_control_ack (struct net_device *net)
{
struct eth_dev *dev = netdev_priv(net);
- u32 length;
+ int length;
struct usb_request *resp = dev->stat_req;
/* in case RNDIS calls this after disconnect */
@@ -2132,7 +2147,7 @@ eth_req_free (struct usb_ep *ep, struct usb_request *req)
}
-static void __exit
+static void /* __init_or_exit */
eth_unbind (struct usb_gadget *gadget)
{
struct eth_dev *dev = get_gadget_data (gadget);
@@ -2159,7 +2174,7 @@ eth_unbind (struct usb_gadget *gadget)
set_gadget_data (gadget, NULL);
}
-static u8 __init nibble (unsigned char c)
+static u8 __devinit nibble (unsigned char c)
{
if (likely (isdigit (c)))
return c - '0';
@@ -2169,7 +2184,7 @@ static u8 __init nibble (unsigned char c)
return 0;
}
-static int __init get_ether_addr(const char *str, u8 *dev_addr)
+static int __devinit get_ether_addr(const char *str, u8 *dev_addr)
{
if (str) {
unsigned i;
@@ -2190,7 +2205,7 @@ static int __init get_ether_addr(const char *str, u8 *dev_addr)
return 1;
}
-static int __init
+static int __devinit
eth_bind (struct usb_gadget *gadget)
{
struct eth_dev *dev;
@@ -2215,6 +2230,9 @@ eth_bind (struct usb_gadget *gadget)
if (gadget_is_pxa (gadget)) {
/* pxa doesn't support altsettings */
cdc = 0;
+ } else if (gadget_is_musbhdrc(gadget)) {
+ /* reduce tx dma overhead by avoiding special cases */
+ zlp = 0;
} else if (gadget_is_sh(gadget)) {
/* sh doesn't support multiple interfaces or configs */
cdc = 0;
@@ -2379,6 +2397,7 @@ autoconf_fail:
return status;
dev = netdev_priv(net);
spin_lock_init (&dev->lock);
+ spin_lock_init (&dev->req_lock);
INIT_WORK (&dev->work, eth_work, dev);
INIT_LIST_HEAD (&dev->tx_reqs);
INIT_LIST_HEAD (&dev->rx_reqs);
@@ -2548,7 +2567,7 @@ static struct usb_gadget_driver eth_driver = {
.function = (char *) driver_desc,
.bind = eth_bind,
- .unbind = __exit_p(eth_unbind),
+ .unbind = eth_unbind,
.setup = eth_setup,
.disconnect = eth_disconnect,
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index a43dc908ac5..c83d3b6c68f 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -221,7 +221,6 @@
#undef VERBOSE
#undef DUMP_MSGS
-#include <linux/config.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -568,6 +567,7 @@ struct lun {
unsigned int ro : 1;
unsigned int prevent_medium_removal : 1;
unsigned int registered : 1;
+ unsigned int info_valid : 1;
u32 sense_data;
u32 sense_data_info;
@@ -1657,6 +1657,7 @@ static int do_read(struct fsg_dev *fsg)
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
break;
@@ -1692,6 +1693,7 @@ static int do_read(struct fsg_dev *fsg)
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -1786,6 +1788,7 @@ static int do_write(struct fsg_dev *fsg)
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = usb_offset >> 9;
+ curlun->info_valid = 1;
continue;
}
amount -= (amount & 511);
@@ -1828,6 +1831,7 @@ static int do_write(struct fsg_dev *fsg)
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -1869,6 +1873,7 @@ static int do_write(struct fsg_dev *fsg)
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -2011,6 +2016,7 @@ static int do_verify(struct fsg_dev *fsg)
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -2037,6 +2043,7 @@ static int do_verify(struct fsg_dev *fsg)
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
file_offset += nread;
@@ -2080,6 +2087,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
struct lun *curlun = fsg->curlun;
u8 *buf = (u8 *) bh->buf;
u32 sd, sdinfo;
+ int valid;
/*
* From the SCSI-2 spec., section 7.9 (Unit attention condition):
@@ -2107,15 +2115,18 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
fsg->bad_lun_okay = 1;
sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
sdinfo = 0;
+ valid = 0;
} else {
sd = curlun->sense_data;
sdinfo = curlun->sense_data_info;
+ valid = curlun->info_valid << 7;
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
}
memset(buf, 0, 18);
- buf[0] = 0x80 | 0x70; // Valid, current error
+ buf[0] = valid | 0x70; // Valid, current error
buf[2] = SK(sd);
put_be32(&buf[3], sdinfo); // Sense information
buf[7] = 18 - 8; // Additional sense length
@@ -2704,6 +2715,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
}
} else {
fsg->curlun = curlun = NULL;
@@ -3333,6 +3345,7 @@ static void handle_exception(struct fsg_dev *fsg)
curlun->sense_data = curlun->unit_attention_data =
SS_NO_SENSE;
curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
}
fsg->state = FSG_STATE_IDLE;
}
@@ -3692,7 +3705,7 @@ static void lun_release(struct device *dev)
kref_put(&fsg->ref, fsg_release);
}
-static void __exit fsg_unbind(struct usb_gadget *gadget)
+static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
{
struct fsg_dev *fsg = get_gadget_data(gadget);
int i;
@@ -3874,21 +3887,26 @@ static int __init fsg_bind(struct usb_gadget *gadget)
for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i];
curlun->ro = mod_data.ro[i];
+ curlun->dev.release = lun_release;
curlun->dev.parent = &gadget->dev;
curlun->dev.driver = &fsg_driver.driver;
dev_set_drvdata(&curlun->dev, fsg);
snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
"%s-lun%d", gadget->dev.bus_id, i);
- if ((rc = device_register(&curlun->dev)) != 0)
+ if ((rc = device_register(&curlun->dev)) != 0) {
INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
- else {
- curlun->registered = 1;
- curlun->dev.release = lun_release;
- device_create_file(&curlun->dev, &dev_attr_ro);
- device_create_file(&curlun->dev, &dev_attr_file);
- kref_get(&fsg->ref);
+ goto out;
+ }
+ if ((rc = device_create_file(&curlun->dev,
+ &dev_attr_ro)) != 0 ||
+ (rc = device_create_file(&curlun->dev,
+ &dev_attr_file)) != 0) {
+ device_unregister(&curlun->dev);
+ goto out;
}
+ curlun->registered = 1;
+ kref_get(&fsg->ref);
if (mod_data.file[i] && *mod_data.file[i]) {
if ((rc = open_backing_file(curlun,
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
new file mode 100644
index 00000000000..b68cecd5741
--- /dev/null
+++ b/drivers/usb/gadget/gmidi.c
@@ -0,0 +1,1337 @@
+/*
+ * gmidi.c -- USB MIDI Gadget Driver
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * This code is based in part on:
+ *
+ * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell.
+ * USB Audio driver, Copyright (C) 2002 by Takashi Iwai.
+ * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch.
+ *
+ * Refer to the USB Device Class Definition for MIDI Devices:
+ * http://www.usb.org/developers/devclass_docs/midi10.pdf
+ */
+
+#define DEBUG 1
+// #define VERBOSE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
+
+#include "gadget_chips.h"
+
+MODULE_AUTHOR("Ben Williamson");
+MODULE_LICENSE("GPL v2");
+
+#define DRIVER_VERSION "25 Jul 2006"
+
+static const char shortname[] = "g_midi";
+static const char longname[] = "MIDI Gadget";
+
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
+
+/* Some systems will want different product identifers published in the
+ * device descriptor, either numbers or strings or both. These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort idVendor;
+module_param(idVendor, ushort, S_IRUGO);
+MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+
+static ushort idProduct;
+module_param(idProduct, ushort, S_IRUGO);
+MODULE_PARM_DESC(idProduct, "USB Product ID");
+
+static ushort bcdDevice;
+module_param(bcdDevice, ushort, S_IRUGO);
+MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+
+static char *iManufacturer;
+module_param(iManufacturer, charp, S_IRUGO);
+MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+
+static char *iProduct;
+module_param(iProduct, charp, S_IRUGO);
+MODULE_PARM_DESC(iProduct, "USB Product string");
+
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
+
+/*
+ * this version autoconfigures as much as possible,
+ * which is reasonable for most "bulk-only" drivers.
+ */
+static const char *EP_IN_NAME;
+static const char *EP_OUT_NAME;
+
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ 256
+
+
+/* This is a gadget, and the IN/OUT naming is from the host's perspective.
+ USB -> OUT endpoint -> rawmidi
+ USB <- IN endpoint <- rawmidi */
+struct gmidi_in_port {
+ struct gmidi_device* dev;
+ int active;
+ uint8_t cable; /* cable number << 4 */
+ uint8_t state;
+#define STATE_UNKNOWN 0
+#define STATE_1PARAM 1
+#define STATE_2PARAM_1 2
+#define STATE_2PARAM_2 3
+#define STATE_SYSEX_0 4
+#define STATE_SYSEX_1 5
+#define STATE_SYSEX_2 6
+ uint8_t data[2];
+};
+
+struct gmidi_device {
+ spinlock_t lock;
+ struct usb_gadget *gadget;
+ struct usb_request *req; /* for control responses */
+ u8 config;
+ struct usb_ep *in_ep, *out_ep;
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_substream *in_substream;
+ struct snd_rawmidi_substream *out_substream;
+
+ /* For the moment we only support one port in
+ each direction, but in_port is kept as a
+ separate struct so we can have more later. */
+ struct gmidi_in_port in_port;
+ unsigned long out_triggered;
+ struct tasklet_struct tasklet;
+};
+
+static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
+
+
+#define xprintk(d,level,fmt,args...) \
+ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#define DBG(dev,fmt,args...) \
+ xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DBG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* VERBOSE */
+
+#define ERROR(dev,fmt,args...) \
+ xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+ xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+ xprintk(dev , KERN_INFO , fmt , ## args)
+
+
+static unsigned buflen = 256;
+static unsigned qlen = 32;
+
+module_param(buflen, uint, S_IRUGO);
+module_param(qlen, uint, S_IRUGO);
+
+
+/* Thanks to Grey Innovation for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+#define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */
+#define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */
+
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full)
+ * configuration descriptors are built on demand.
+ */
+
+#define STRING_MANUFACTURER 25
+#define STRING_PRODUCT 42
+#define STRING_SERIAL 101
+#define STRING_MIDI_GADGET 250
+
+/* We only have the one configuration, it's number 1. */
+#define GMIDI_CONFIG 1
+
+/* We have two interfaces- AudioControl and MIDIStreaming */
+#define GMIDI_AC_INTERFACE 0
+#define GMIDI_MS_INTERFACE 1
+#define GMIDI_NUM_INTERFACES 2
+
+DECLARE_USB_AC_HEADER_DESCRIPTOR(1);
+DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
+DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
+
+/* B.1 Device Descriptor */
+static struct usb_device_descriptor device_desc = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .bNumConfigurations = 1,
+};
+
+/* B.2 Configuration Descriptor */
+static struct usb_config_descriptor config_desc = {
+ .bLength = USB_DT_CONFIG_SIZE,
+ .bDescriptorType = USB_DT_CONFIG,
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = GMIDI_NUM_INTERFACES,
+ .bConfigurationValue = GMIDI_CONFIG,
+ .iConfiguration = STRING_MIDI_GADGET,
+ /*
+ * FIXME: When embedding this driver in a device,
+ * these need to be set to reflect the actual
+ * power properties of the device. Is it selfpowered?
+ */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .bMaxPower = 1,
+};
+
+/* B.3.1 Standard AC Interface Descriptor */
+static const struct usb_interface_descriptor ac_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = GMIDI_AC_INTERFACE,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+ .iInterface = STRING_MIDI_GADGET,
+};
+
+/* B.3.2 Class-Specific AC Interface Descriptor */
+static const struct usb_ac_header_descriptor_1 ac_header_desc = {
+ .bLength = USB_DT_AC_HEADER_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_HEADER,
+ .bcdADC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = USB_DT_AC_HEADER_SIZE(1),
+ .bInCollection = 1,
+ .baInterfaceNr = {
+ [0] = GMIDI_MS_INTERFACE,
+ }
+};
+
+/* B.4.1 Standard MS Interface Descriptor */
+static const struct usb_interface_descriptor ms_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = GMIDI_MS_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
+ .iInterface = STRING_MIDI_GADGET,
+};
+
+/* B.4.2 Class-Specific MS Interface Descriptor */
+static const struct usb_ms_header_descriptor ms_header_desc = {
+ .bLength = USB_DT_MS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_HEADER,
+ .bcdMSC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = USB_DT_MS_HEADER_SIZE
+ + 2*USB_DT_MIDI_IN_SIZE
+ + 2*USB_DT_MIDI_OUT_SIZE(1),
+};
+
+#define JACK_IN_EMB 1
+#define JACK_IN_EXT 2
+#define JACK_OUT_EMB 3
+#define JACK_OUT_EXT 4
+
+/* B.4.3 MIDI IN Jack Descriptors */
+static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
+ .bLength = USB_DT_MIDI_IN_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
+ .bJackType = USB_MS_EMBEDDED,
+ .bJackID = JACK_IN_EMB,
+};
+
+static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = {
+ .bLength = USB_DT_MIDI_IN_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
+ .bJackType = USB_MS_EXTERNAL,
+ .bJackID = JACK_IN_EXT,
+};
+
+/* B.4.4 MIDI OUT Jack Descriptors */
+static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = {
+ .bLength = USB_DT_MIDI_OUT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
+ .bJackType = USB_MS_EMBEDDED,
+ .bJackID = JACK_OUT_EMB,
+ .bNrInputPins = 1,
+ .pins = {
+ [0] = {
+ .baSourceID = JACK_IN_EXT,
+ .baSourcePin = 1,
+ }
+ }
+};
+
+static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = {
+ .bLength = USB_DT_MIDI_OUT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
+ .bJackType = USB_MS_EXTERNAL,
+ .bJackID = JACK_OUT_EXT,
+ .bNrInputPins = 1,
+ .pins = {
+ [0] = {
+ .baSourceID = JACK_IN_EMB,
+ .baSourcePin = 1,
+ }
+ }
+};
+
+/* B.5.1 Standard Bulk OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
+static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = {
+ .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = USB_MS_GENERAL,
+ .bNumEmbMIDIJack = 1,
+ .baAssocJackID = {
+ [0] = JACK_IN_EMB,
+ }
+};
+
+/* B.6.1 Standard Bulk IN Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
+static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = {
+ .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = USB_MS_GENERAL,
+ .bNumEmbMIDIJack = 1,
+ .baAssocJackID = {
+ [0] = JACK_OUT_EMB,
+ }
+};
+
+static const struct usb_descriptor_header *gmidi_function [] = {
+ (struct usb_descriptor_header *)&ac_interface_desc,
+ (struct usb_descriptor_header *)&ac_header_desc,
+ (struct usb_descriptor_header *)&ms_interface_desc,
+
+ (struct usb_descriptor_header *)&ms_header_desc,
+ (struct usb_descriptor_header *)&jack_in_emb_desc,
+ (struct usb_descriptor_header *)&jack_in_ext_desc,
+ (struct usb_descriptor_header *)&jack_out_emb_desc,
+ (struct usb_descriptor_header *)&jack_out_ext_desc,
+ /* If you add more jacks, update ms_header_desc.wTotalLength */
+
+ (struct usb_descriptor_header *)&bulk_out_desc,
+ (struct usb_descriptor_header *)&ms_out_desc,
+ (struct usb_descriptor_header *)&bulk_in_desc,
+ (struct usb_descriptor_header *)&ms_in_desc,
+ NULL,
+};
+
+static char manufacturer[50];
+static char product_desc[40] = "MIDI Gadget";
+static char serial_number[20];
+
+/* static strings, in UTF-8 */
+static struct usb_string strings [] = {
+ { STRING_MANUFACTURER, manufacturer, },
+ { STRING_PRODUCT, product_desc, },
+ { STRING_SERIAL, serial_number, },
+ { STRING_MIDI_GADGET, longname, },
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+static int config_buf(struct usb_gadget *gadget,
+ u8 *buf, u8 type, unsigned index)
+{
+ int len;
+
+ /* only one configuration */
+ if (index != 0) {
+ return -EINVAL;
+ }
+ len = usb_gadget_config_buf(&config_desc,
+ buf, USB_BUFSIZ, gmidi_function);
+ if (len < 0) {
+ return len;
+ }
+ ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+ return len;
+}
+
+static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (req) {
+ req->length = length;
+ req->buf = kmalloc(length, GFP_ATOMIC);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ req = NULL;
+ }
+ }
+ return req;
+}
+
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+static const uint8_t gmidi_cin_length[] = {
+ 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
+};
+
+/*
+ * Receives a chunk of MIDI data.
+ */
+static void gmidi_read_data(struct usb_ep *ep, int cable,
+ uint8_t* data, int length)
+{
+ struct gmidi_device *dev = ep->driver_data;
+ /* cable is ignored, because for now we only have one. */
+
+ if (!dev->out_substream) {
+ /* Nobody is listening - throw it on the floor. */
+ return;
+ }
+ if (!test_bit(dev->out_substream->number, &dev->out_triggered)) {
+ return;
+ }
+ snd_rawmidi_receive(dev->out_substream, data, length);
+}
+
+static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
+{
+ unsigned i;
+ u8 *buf = req->buf;
+
+ for (i = 0; i + 3 < req->actual; i += 4) {
+ if (buf[i] != 0) {
+ int cable = buf[i] >> 4;
+ int length = gmidi_cin_length[buf[i] & 0x0f];
+ gmidi_read_data(ep, cable, &buf[i + 1], length);
+ }
+ }
+}
+
+static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct gmidi_device *dev = ep->driver_data;
+ int status = req->status;
+
+ switch (status) {
+ case 0: /* normal completion */
+ if (ep == dev->out_ep) {
+ /* we received stuff.
+ req is queued again, below */
+ gmidi_handle_out_data(ep, req);
+ } else if (ep == dev->in_ep) {
+ /* our transmit completed.
+ see if there's more to go.
+ gmidi_transmit eats req, don't queue it again. */
+ gmidi_transmit(dev, req);
+ return;
+ }
+ break;
+
+ /* this endpoint is normally active while we're configured */
+ case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNRESET: /* request dequeued */
+ case -ESHUTDOWN: /* disconnect from host */
+ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ req->actual, req->length);
+ if (ep == dev->out_ep) {
+ gmidi_handle_out_data(ep, req);
+ }
+ free_ep_req(ep, req);
+ return;
+
+ case -EOVERFLOW: /* buffer overrun on read means that
+ * we didn't provide a big enough
+ * buffer.
+ */
+ default:
+ DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
+ status, req->actual, req->length);
+ break;
+ case -EREMOTEIO: /* short read */
+ break;
+ }
+
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (status) {
+ ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
+ ep->name, req->length, status);
+ usb_ep_set_halt(ep);
+ /* FIXME recover later ... somehow */
+ }
+}
+
+static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
+{
+ int err = 0;
+ struct usb_request *req;
+ struct usb_ep* ep;
+ unsigned i;
+
+ err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+ if (err) {
+ ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
+ goto fail;
+ }
+ dev->in_ep->driver_data = dev;
+
+ err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+ if (err) {
+ ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
+ goto fail;
+ }
+ dev->out_ep->driver_data = dev;
+
+ /* allocate a bunch of read buffers and queue them all at once. */
+ ep = dev->out_ep;
+ for (i = 0; i < qlen && err == 0; i++) {
+ req = alloc_ep_req(ep, buflen);
+ if (req) {
+ req->complete = gmidi_complete;
+ err = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (err) {
+ DBG(dev, "%s queue req: %d\n", ep->name, err);
+ }
+ } else {
+ err = -ENOMEM;
+ }
+ }
+fail:
+ /* caller is responsible for cleanup on error */
+ return err;
+}
+
+
+static void gmidi_reset_config(struct gmidi_device *dev)
+{
+ if (dev->config == 0) {
+ return;
+ }
+
+ DBG(dev, "reset config\n");
+
+ /* just disable endpoints, forcing completion of pending i/o.
+ * all our completion handlers free their requests in this case.
+ */
+ usb_ep_disable(dev->in_ep);
+ usb_ep_disable(dev->out_ep);
+ dev->config = 0;
+}
+
+/* change our operational config. this code must agree with the code
+ * that returns config descriptors, and altsetting code.
+ *
+ * it's also responsible for power management interactions. some
+ * configurations might not work with our current power sources.
+ *
+ * note that some device controller hardware will constrain what this
+ * code can do, perhaps by disallowing more than one configuration or
+ * by limiting configuration choices (like the pxa2xx).
+ */
+static int
+gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+#if 0
+ /* FIXME */
+ /* Hacking this bit out fixes a bug where on receipt of two
+ USB_REQ_SET_CONFIGURATION messages, we end up with no
+ buffered OUT requests waiting for data. This is clearly
+ hiding a bug elsewhere, because if the config didn't
+ change then we really shouldn't do anything. */
+ /* Having said that, when we do "change" from config 1
+ to config 1, we at least gmidi_reset_config() which
+ clears out any requests on endpoints, so it's not like
+ we leak or anything. */
+ if (number == dev->config) {
+ return 0;
+ }
+#endif
+
+ if (gadget_is_sa1100(gadget) && dev->config) {
+ /* tx fifo is full, but we can't clear it...*/
+ INFO(dev, "can't change configurations\n");
+ return -ESPIPE;
+ }
+ gmidi_reset_config(dev);
+
+ switch (number) {
+ case GMIDI_CONFIG:
+ result = set_gmidi_config(dev, gfp_flags);
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ case 0:
+ return result;
+ }
+
+ if (!result && (!dev->in_ep || !dev->out_ep)) {
+ result = -ENODEV;
+ }
+ if (result) {
+ gmidi_reset_config(dev);
+ } else {
+ char *speed;
+
+ switch (gadget->speed) {
+ case USB_SPEED_LOW: speed = "low"; break;
+ case USB_SPEED_FULL: speed = "full"; break;
+ case USB_SPEED_HIGH: speed = "high"; break;
+ default: speed = "?"; break;
+ }
+
+ dev->config = number;
+ INFO(dev, "%s speed\n", speed);
+ }
+ return result;
+}
+
+
+static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->status || req->actual != req->length) {
+ DBG((struct gmidi_device *) ep->driver_data,
+ "setup complete --> %d, %d/%d\n",
+ req->status, req->actual, req->length);
+ }
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's
+ * not handled lower down, in hardware or the hardware driver (like
+ * device and endpoint feature flags, and their status). It's all
+ * housekeeping for the gadget function we're implementing. Most of
+ * the work is in config-specific setup.
+ */
+static int gmidi_setup(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+ struct usb_request *req = dev->req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* usually this stores reply data in the pre-allocated ep0 buffer,
+ * but config change events will reconfigure hardware.
+ */
+ req->zero = 0;
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrl->bRequestType != USB_DIR_IN) {
+ goto unknown;
+ }
+ switch (w_value >> 8) {
+
+ case USB_DT_DEVICE:
+ value = min(w_length, (u16) sizeof(device_desc));
+ memcpy(req->buf, &device_desc, value);
+ break;
+ case USB_DT_CONFIG:
+ value = config_buf(gadget, req->buf,
+ w_value >> 8,
+ w_value & 0xff);
+ if (value >= 0) {
+ value = min(w_length, (u16)value);
+ }
+ break;
+
+ case USB_DT_STRING:
+ /* wIndex == language code.
+ * this driver only handles one language, you can
+ * add string tables for other languages, using
+ * any UTF-8 characters
+ */
+ value = usb_gadget_get_string(&stringtab,
+ w_value & 0xff, req->buf);
+ if (value >= 0) {
+ value = min(w_length, (u16)value);
+ }
+ break;
+ }
+ break;
+
+ /* currently two configs, two speeds */
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl->bRequestType != 0) {
+ goto unknown;
+ }
+ if (gadget->a_hnp_support) {
+ DBG(dev, "HNP available\n");
+ } else if (gadget->a_alt_hnp_support) {
+ DBG(dev, "HNP needs a different root port\n");
+ } else {
+ VDBG(dev, "HNP inactive\n");
+ }
+ spin_lock(&dev->lock);
+ value = gmidi_set_config(dev, w_value, GFP_ATOMIC);
+ spin_unlock(&dev->lock);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ if (ctrl->bRequestType != USB_DIR_IN) {
+ goto unknown;
+ }
+ *(u8 *)req->buf = dev->config;
+ value = min(w_length, (u16)1);
+ break;
+
+ /* until we add altsetting support, or other interfaces,
+ * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
+ * and already killed pending endpoint I/O.
+ */
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE) {
+ goto unknown;
+ }
+ spin_lock(&dev->lock);
+ if (dev->config && w_index < GMIDI_NUM_INTERFACES
+ && w_value == 0)
+ {
+ u8 config = dev->config;
+
+ /* resets interface configuration, forgets about
+ * previous transaction state (queued bufs, etc)
+ * and re-inits endpoint state (toggle etc)
+ * no response queued, just zero status == success.
+ * if we had more than one interface we couldn't
+ * use this "reset the config" shortcut.
+ */
+ gmidi_reset_config(dev);
+ gmidi_set_config(dev, config, GFP_ATOMIC);
+ value = 0;
+ }
+ spin_unlock(&dev->lock);
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
+ goto unknown;
+ }
+ if (!dev->config) {
+ break;
+ }
+ if (w_index >= GMIDI_NUM_INTERFACES) {
+ value = -EDOM;
+ break;
+ }
+ *(u8 *)req->buf = 0;
+ value = min(w_length, (u16)1);
+ break;
+
+ default:
+unknown:
+ VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer before status phase? */
+ if (value >= 0) {
+ req->length = value;
+ req->zero = value < w_length;
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ DBG(dev, "ep_queue --> %d\n", value);
+ req->status = 0;
+ gmidi_setup_complete(gadget->ep0, req);
+ }
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static void gmidi_disconnect(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ gmidi_reset_config(dev);
+
+ /* a more significant application might have some non-usb
+ * activities to quiesce here, saving resources like power
+ * or pushing the notification up a network stack.
+ */
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* next we may get setup() calls to enumerate new connections;
+ * or an unbind() during shutdown (including removing module).
+ */
+}
+
+static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+ struct snd_card* card;
+
+ DBG(dev, "unbind\n");
+
+ card = dev->card;
+ dev->card = NULL;
+ if (card) {
+ snd_card_free(card);
+ }
+
+ /* we've already been disconnected ... no i/o is active */
+ if (dev->req) {
+ dev->req->length = USB_BUFSIZ;
+ free_ep_req(gadget->ep0, dev->req);
+ }
+ kfree(dev);
+ set_gadget_data(gadget, NULL);
+}
+
+static int gmidi_snd_free(struct snd_device *device)
+{
+ return 0;
+}
+
+static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+ uint8_t p1, uint8_t p2, uint8_t p3)
+{
+ unsigned length = req->length;
+
+ uint8_t* buf = (uint8_t*)req->buf + length;
+ buf[0] = p0;
+ buf[1] = p1;
+ buf[2] = p2;
+ buf[3] = p3;
+ req->length = length + 4;
+}
+
+/*
+ * Converts MIDI commands to USB MIDI packets.
+ */
+static void gmidi_transmit_byte(struct usb_request* req,
+ struct gmidi_in_port* port, uint8_t b)
+{
+ uint8_t p0 = port->cable;
+
+ if (b >= 0xf8) {
+ gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
+ } else if (b >= 0xf0) {
+ switch (b) {
+ case 0xf0:
+ port->data[0] = b;
+ port->state = STATE_SYSEX_1;
+ break;
+ case 0xf1:
+ case 0xf3:
+ port->data[0] = b;
+ port->state = STATE_1PARAM;
+ break;
+ case 0xf2:
+ port->data[0] = b;
+ port->state = STATE_2PARAM_1;
+ break;
+ case 0xf4:
+ case 0xf5:
+ port->state = STATE_UNKNOWN;
+ break;
+ case 0xf6:
+ gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
+ port->state = STATE_UNKNOWN;
+ break;
+ case 0xf7:
+ switch (port->state) {
+ case STATE_SYSEX_0:
+ gmidi_transmit_packet(req,
+ p0 | 0x05, 0xf7, 0, 0);
+ break;
+ case STATE_SYSEX_1:
+ gmidi_transmit_packet(req,
+ p0 | 0x06, port->data[0], 0xf7, 0);
+ break;
+ case STATE_SYSEX_2:
+ gmidi_transmit_packet(req,
+ p0 | 0x07, port->data[0],
+ port->data[1], 0xf7);
+ break;
+ }
+ port->state = STATE_UNKNOWN;
+ break;
+ }
+ } else if (b >= 0x80) {
+ port->data[0] = b;
+ if (b >= 0xc0 && b <= 0xdf)
+ port->state = STATE_1PARAM;
+ else
+ port->state = STATE_2PARAM_1;
+ } else { /* b < 0x80 */
+ switch (port->state) {
+ case STATE_1PARAM:
+ if (port->data[0] < 0xf0) {
+ p0 |= port->data[0] >> 4;
+ } else {
+ p0 |= 0x02;
+ port->state = STATE_UNKNOWN;
+ }
+ gmidi_transmit_packet(req, p0, port->data[0], b, 0);
+ break;
+ case STATE_2PARAM_1:
+ port->data[1] = b;
+ port->state = STATE_2PARAM_2;
+ break;
+ case STATE_2PARAM_2:
+ if (port->data[0] < 0xf0) {
+ p0 |= port->data[0] >> 4;
+ port->state = STATE_2PARAM_1;
+ } else {
+ p0 |= 0x03;
+ port->state = STATE_UNKNOWN;
+ }
+ gmidi_transmit_packet(req,
+ p0, port->data[0], port->data[1], b);
+ break;
+ case STATE_SYSEX_0:
+ port->data[0] = b;
+ port->state = STATE_SYSEX_1;
+ break;
+ case STATE_SYSEX_1:
+ port->data[1] = b;
+ port->state = STATE_SYSEX_2;
+ break;
+ case STATE_SYSEX_2:
+ gmidi_transmit_packet(req,
+ p0 | 0x04, port->data[0], port->data[1], b);
+ port->state = STATE_SYSEX_0;
+ break;
+ }
+ }
+}
+
+static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+{
+ struct usb_ep* ep = dev->in_ep;
+ struct gmidi_in_port* port = &dev->in_port;
+
+ if (!ep) {
+ return;
+ }
+ if (!req) {
+ req = alloc_ep_req(ep, buflen);
+ }
+ if (!req) {
+ ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n");
+ return;
+ }
+ req->length = 0;
+ req->complete = gmidi_complete;
+
+ if (port->active) {
+ while (req->length + 3 < buflen) {
+ uint8_t b;
+ if (snd_rawmidi_transmit(dev->in_substream, &b, 1)
+ != 1)
+ {
+ port->active = 0;
+ break;
+ }
+ gmidi_transmit_byte(req, port, b);
+ }
+ }
+ if (req->length > 0) {
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ } else {
+ free_ep_req(ep, req);
+ }
+}
+
+static void gmidi_in_tasklet(unsigned long data)
+{
+ struct gmidi_device* dev = (struct gmidi_device*)data;
+
+ gmidi_transmit(dev, NULL);
+}
+
+static int gmidi_in_open(struct snd_rawmidi_substream *substream)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_in_open\n");
+ dev->in_substream = substream;
+ dev->in_port.state = STATE_UNKNOWN;
+ return 0;
+}
+
+static int gmidi_in_close(struct snd_rawmidi_substream *substream)
+{
+ VDBG(dev, "gmidi_in_close\n");
+ return 0;
+}
+
+static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_in_trigger %d\n", up);
+ dev->in_port.active = up;
+ if (up) {
+ tasklet_hi_schedule(&dev->tasklet);
+ }
+}
+
+static int gmidi_out_open(struct snd_rawmidi_substream *substream)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_out_open\n");
+ dev->out_substream = substream;
+ return 0;
+}
+
+static int gmidi_out_close(struct snd_rawmidi_substream *substream)
+{
+ VDBG(dev, "gmidi_out_close\n");
+ return 0;
+}
+
+static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_out_trigger %d\n", up);
+ if (up) {
+ set_bit(substream->number, &dev->out_triggered);
+ } else {
+ clear_bit(substream->number, &dev->out_triggered);
+ }
+}
+
+static struct snd_rawmidi_ops gmidi_in_ops = {
+ .open = gmidi_in_open,
+ .close = gmidi_in_close,
+ .trigger = gmidi_in_trigger,
+};
+
+static struct snd_rawmidi_ops gmidi_out_ops = {
+ .open = gmidi_out_open,
+ .close = gmidi_out_close,
+ .trigger = gmidi_out_trigger
+};
+
+/* register as a sound "card" */
+static int gmidi_register_card(struct gmidi_device *dev)
+{
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ int err;
+ int out_ports = 1;
+ int in_ports = 1;
+ static struct snd_device_ops ops = {
+ .dev_free = gmidi_snd_free,
+ };
+
+ card = snd_card_new(index, id, THIS_MODULE, 0);
+ if (!card) {
+ ERROR(dev, "snd_card_new failed\n");
+ err = -ENOMEM;
+ goto fail;
+ }
+ dev->card = card;
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops);
+ if (err < 0) {
+ ERROR(dev, "snd_device_new failed: error %d\n", err);
+ goto fail;
+ }
+
+ strcpy(card->driver, longname);
+ strcpy(card->longname, longname);
+ strcpy(card->shortname, shortname);
+
+ /* Set up rawmidi */
+ dev->in_port.dev = dev;
+ dev->in_port.active = 0;
+ snd_component_add(card, "MIDI");
+ err = snd_rawmidi_new(card, "USB MIDI Gadget", 0,
+ out_ports, in_ports, &rmidi);
+ if (err < 0) {
+ ERROR(dev, "snd_rawmidi_new failed: error %d\n", err);
+ goto fail;
+ }
+ dev->rmidi = rmidi;
+ strcpy(rmidi->name, card->shortname);
+ rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ rmidi->private_data = dev;
+
+ /* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
+ It's an upside-down world being a gadget. */
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
+
+ snd_card_set_dev(card, &dev->gadget->dev);
+
+ /* register it - we're ready to go */
+ err = snd_card_register(card);
+ if (err < 0) {
+ ERROR(dev, "snd_card_register failed\n");
+ goto fail;
+ }
+
+ VDBG(dev, "gmidi_register_card finished ok\n");
+ return 0;
+
+fail:
+ if (dev->card) {
+ snd_card_free(dev->card);
+ dev->card = NULL;
+ }
+ return err;
+}
+
+/*
+ * Creates an output endpoint, and initializes output ports.
+ */
+static int __devinit gmidi_bind(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev;
+ struct usb_ep *in_ep, *out_ep;
+ int gcnum, err = 0;
+
+ /* support optional vendor/distro customization */
+ if (idVendor) {
+ if (!idProduct) {
+ printk(KERN_ERR "idVendor needs idProduct!\n");
+ return -ENODEV;
+ }
+ device_desc.idVendor = cpu_to_le16(idVendor);
+ device_desc.idProduct = cpu_to_le16(idProduct);
+ if (bcdDevice) {
+ device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+ }
+ }
+ if (iManufacturer) {
+ strlcpy(manufacturer, iManufacturer, sizeof(manufacturer));
+ } else {
+ snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+ system_utsname.sysname, system_utsname.release,
+ gadget->name);
+ }
+ if (iProduct) {
+ strlcpy(product_desc, iProduct, sizeof(product_desc));
+ }
+ if (iSerialNumber) {
+ device_desc.iSerialNumber = STRING_SERIAL,
+ strlcpy(serial_number, iSerialNumber, sizeof(serial_number));
+ }
+
+ /* Bulk-only drivers like this one SHOULD be able to
+ * autoconfigure on any sane usb controller driver,
+ * but there may also be important quirks to address.
+ */
+ usb_ep_autoconfig_reset(gadget);
+ in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
+ if (!in_ep) {
+autoconf_fail:
+ printk(KERN_ERR "%s: can't autoconfigure on %s\n",
+ shortname, gadget->name);
+ return -ENODEV;
+ }
+ EP_IN_NAME = in_ep->name;
+ in_ep->driver_data = in_ep; /* claim */
+
+ out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc);
+ if (!out_ep) {
+ goto autoconf_fail;
+ }
+ EP_OUT_NAME = out_ep->name;
+ out_ep->driver_data = out_ep; /* claim */
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0) {
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+ } else {
+ /* gmidi is so simple (no altsettings) that
+ * it SHOULD NOT have problems with bulk-capable hardware.
+ * so warn about unrecognized controllers, don't panic.
+ */
+ printk(KERN_WARNING "%s: controller '%s' not recognized\n",
+ shortname, gadget->name);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+ }
+
+
+ /* ok, we made sense of the hardware ... */
+ dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
+ if (!dev) {
+ return -ENOMEM;
+ }
+ spin_lock_init(&dev->lock);
+ dev->gadget = gadget;
+ dev->in_ep = in_ep;
+ dev->out_ep = out_ep;
+ set_gadget_data(gadget, dev);
+ tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
+
+ /* preallocate control response and buffer */
+ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+ if (!dev->req) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
+ &dev->req->dma, GFP_KERNEL);
+ if (!dev->req->buf) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ dev->req->complete = gmidi_setup_complete;
+
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+
+ gadget->ep0->driver_data = dev;
+
+ INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
+ EP_OUT_NAME, EP_IN_NAME);
+
+ /* register as an ALSA sound card */
+ err = gmidi_register_card(dev);
+ if (err < 0) {
+ goto fail;
+ }
+
+ VDBG(dev, "gmidi_bind finished ok\n");
+ return 0;
+
+fail:
+ gmidi_unbind(gadget);
+ return err;
+}
+
+
+static void gmidi_suspend(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+
+ if (gadget->speed == USB_SPEED_UNKNOWN) {
+ return;
+ }
+
+ DBG(dev, "suspend\n");
+}
+
+static void gmidi_resume(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+
+ DBG(dev, "resume\n");
+}
+
+
+static struct usb_gadget_driver gmidi_driver = {
+ .speed = USB_SPEED_FULL,
+ .function = (char *)longname,
+ .bind = gmidi_bind,
+ .unbind = __exit_p(gmidi_unbind),
+
+ .setup = gmidi_setup,
+ .disconnect = gmidi_disconnect,
+
+ .suspend = gmidi_suspend,
+ .resume = gmidi_resume,
+
+ .driver = {
+ .name = (char *)shortname,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gmidi_init(void)
+{
+ return usb_gadget_register_driver(&gmidi_driver);
+}
+module_init(gmidi_init);
+
+static void __exit gmidi_cleanup(void)
+{
+ usb_gadget_unregister_driver(&gmidi_driver);
+}
+module_exit(gmidi_cleanup);
+
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 5378c175729..7cf2999e861 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -24,7 +24,6 @@
// #define VERBOSE /* extra debug messages (success too) */
// #define USB_TRACE /* packet-level success messages */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -1917,7 +1916,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* init to known state, then setup irqs */
udc_reset(dev);
udc_reinit (dev);
- if (request_irq(pdev->irq, goku_irq, SA_SHIRQ/*|SA_SAMPLE_RANDOM*/,
+ if (request_irq(pdev->irq, goku_irq, IRQF_SHARED/*|IRQF_SAMPLE_RANDOM*/,
driver_name, dev) != 0) {
DBG(dev, "request interrupt %d failed\n", pdev->irq);
retval = -EBUSY;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3bdc5e3ba23..4655522a08d 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -32,6 +32,7 @@
#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
+#include <linux/poll.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
@@ -222,7 +223,6 @@ static void put_ep (struct ep_data *data)
/* needs no more cleanup */
BUG_ON (!list_empty (&data->epfiles));
BUG_ON (waitqueue_active (&data->wait));
- BUG_ON (down_trylock (&data->lock) != 0);
kfree (data);
}
@@ -477,6 +477,10 @@ static int
ep_release (struct inode *inode, struct file *fd)
{
struct ep_data *data = fd->private_data;
+ int value;
+
+ if ((value = down_interruptible(&data->lock)) < 0)
+ return value;
/* clean up if this can be reopened */
if (data->state != STATE_EP_UNBOUND) {
@@ -485,6 +489,7 @@ ep_release (struct inode *inode, struct file *fd)
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
+ up (&data->lock);
put_ep (data);
return 0;
}
@@ -709,7 +714,7 @@ ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
/*----------------------------------------------------------------------*/
/* used after endpoint configuration */
-static struct file_operations ep_io_operations = {
+static const struct file_operations ep_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -741,7 +746,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
struct ep_data *data = fd->private_data;
struct usb_ep *ep;
u32 tag;
- int value;
+ int value, length = len;
if ((value = down_interruptible (&data->lock)) < 0)
return value;
@@ -792,7 +797,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
goto fail0;
}
}
- value = len;
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND) {
@@ -822,8 +826,10 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
data->name);
data->state = STATE_EP_DEFER_ENABLE;
}
- if (value == 0)
+ if (value == 0) {
fd->f_op = &ep_io_operations;
+ value = length;
+ }
gone:
spin_unlock_irq (&data->dev->lock);
if (value < 0) {
@@ -844,7 +850,7 @@ fail1:
static int
ep_open (struct inode *inode, struct file *fd)
{
- struct ep_data *data = inode->u.generic_ip;
+ struct ep_data *data = inode->i_private;
int value = -EBUSY;
if (down_interruptible (&data->lock) != 0)
@@ -867,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd)
}
/* used before endpoint configuration */
-static struct file_operations ep_config_operations = {
+static const struct file_operations ep_config_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -1009,7 +1015,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
else {
len = min (len, (size_t)dev->req->actual);
// FIXME don't call this with the spinlock held ...
- if (copy_to_user (buf, &dev->req->buf, len))
+ if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */
@@ -1229,6 +1235,35 @@ dev_release (struct inode *inode, struct file *fd)
return 0;
}
+static unsigned int
+ep0_poll (struct file *fd, poll_table *wait)
+{
+ struct dev_data *dev = fd->private_data;
+ int mask = 0;
+
+ poll_wait(fd, &dev->wait, wait);
+
+ spin_lock_irq (&dev->lock);
+
+ /* report fd mode change before acting on it */
+ if (dev->setup_abort) {
+ dev->setup_abort = 0;
+ mask = POLLHUP;
+ goto out;
+ }
+
+ if (dev->state == STATE_SETUP) {
+ if (dev->setup_in || dev->setup_can_stall)
+ mask = POLLOUT;
+ } else {
+ if (dev->ev_next != 0)
+ mask = POLLIN;
+ }
+out:
+ spin_unlock_irq(&dev->lock);
+ return mask;
+}
+
static int dev_ioctl (struct inode *inode, struct file *fd,
unsigned code, unsigned long value)
{
@@ -1241,14 +1276,14 @@ static int dev_ioctl (struct inode *inode, struct file *fd,
}
/* used after device configuration */
-static struct file_operations ep0_io_operations = {
+static const struct file_operations ep0_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep0_read,
.write = ep0_write,
.fasync = ep0_fasync,
- // .poll = ep0_poll,
+ .poll = ep0_poll,
.ioctl = dev_ioctl,
.release = dev_release,
};
@@ -1696,16 +1731,17 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
{
struct dev_data *dev = get_gadget_data (gadget);
+ spin_lock (&dev->lock);
if (dev->state == STATE_UNCONNECTED) {
DBG (dev, "already unconnected\n");
- return;
+ goto exit;
}
dev->state = STATE_UNCONNECTED;
INFO (dev, "disconnected\n");
- spin_lock (&dev->lock);
next_event (dev, GADGETFS_DISCONNECT);
ep0_readable (dev);
+exit:
spin_unlock (&dev->lock);
}
@@ -1909,7 +1945,7 @@ fail:
static int
dev_open (struct inode *inode, struct file *fd)
{
- struct dev_data *dev = inode->u.generic_ip;
+ struct dev_data *dev = inode->i_private;
int value = -EBUSY;
if (dev->state == STATE_DEV_DISABLED) {
@@ -1922,7 +1958,7 @@ dev_open (struct inode *inode, struct file *fd)
return value;
}
-static struct file_operations dev_init_operations = {
+static const struct file_operations dev_init_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -1966,11 +2002,10 @@ gadgetfs_make_inode (struct super_block *sb,
inode->i_mode = mode;
inode->i_uid = default_uid;
inode->i_gid = default_gid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime
= CURRENT_TIME;
- inode->u.generic_ip = data;
+ inode->i_private = data;
inode->i_fop = fops;
}
return inode;
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 0d3424eda03..36db7257937 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -2107,7 +2107,7 @@ static int lh7a40x_udc_probe(struct platform_device *pdev)
/* irq setup after old hardware state is cleaned up */
retval =
- request_irq(IRQ_USBINTR, lh7a40x_udc_irq, SA_INTERRUPT, driver_name,
+ request_irq(IRQ_USBINTR, lh7a40x_udc_irq, IRQF_DISABLED, driver_name,
dev);
if (retval != 0) {
DEBUG(KERN_ERR "%s: can't get irq %i, err %d\n", driver_name,
@@ -2143,7 +2143,7 @@ static int lh7a40x_udc_remove(struct platform_device *pdev)
static struct platform_driver udc_driver = {
.probe = lh7a40x_udc_probe,
- .remove = lh7a40x_udc_remove
+ .remove = lh7a40x_udc_remove,
/* FIXME power management support */
/* .suspend = ... disable UDC */
/* .resume = ... re-enable UDC */
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index 9b2e6f7cbb8..e3bb78524c8 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -24,7 +24,6 @@
#ifndef __LH7A40X_H_
#define __LH7A40X_H_
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 1facdea56a8..3bda37f9a35 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2,7 +2,7 @@
* Driver for the PLX NET2280 USB device controller.
* Specs and errata are available from <http://www.plxtech.com>.
*
- * PLX Technology Inc. (formerly NetChip Technology) supported the
+ * PLX Technology Inc. (formerly NetChip Technology) supported the
* development of this driver.
*
*
@@ -26,7 +26,8 @@
* Copyright (C) 2003 David Brownell
* Copyright (C) 2003-2005 PLX Technology, Inc.
*
- * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
+ * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility
+ * with 2282 chip
*
* 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
@@ -46,7 +47,6 @@
#undef DEBUG /* messages on error and most fault paths */
#undef VERBOSE /* extra debug messages (success too) */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
@@ -86,7 +86,7 @@ static const char driver_name [] = "net2280";
static const char driver_desc [] = DRIVER_DESC;
static const char ep0name [] = "ep0";
-static const char *ep_name [] = {
+static const char *const ep_name [] = {
ep0name,
"ep-a", "ep-b", "ep-c", "ep-d",
"ep-e", "ep-f",
@@ -226,7 +226,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (!ep->is_in)
writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
else if (dev->pdev->device != 0x2280) {
- /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
+ /* Added for 2282, Don't use nak packets on an in endpoint,
+ * this was ignored on 2280
+ */
writel ((1 << CLEAR_NAK_OUT_PACKETS)
| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
}
@@ -289,7 +291,7 @@ static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
return -ETIMEDOUT;
}
-static struct usb_ep_ops net2280_ep_ops;
+static const struct usb_ep_ops net2280_ep_ops;
static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
{
@@ -450,34 +452,15 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-#undef USE_KMALLOC
-
-/* many common platforms have dma-coherent caches, which means that it's
- * safe to use kmalloc() memory for all i/o buffers without using any
- * cache flushing calls. (unless you're trying to share cache lines
- * between dma and non-dma activities, which is a slow idea in any case.)
+/*
+ * dma-coherent memory allocation (for dma-capable endpoints)
*
- * other platforms need more care, with 2.5 having a moderately general
- * solution (which falls down for allocations smaller than one page)
- * that improves significantly on the 2.4 PCI allocators by removing
- * the restriction that memory never be freed in_interrupt().
+ * NOTE: the dma_*_coherent() API calls suck. Most implementations are
+ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
+ * respect to calls with irqs disabled: alloc is safe, free is not.
+ * We currently work around (b), but not (a).
*/
-#if defined(CONFIG_X86)
-#define USE_KMALLOC
-
-#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
-#define USE_KMALLOC
-#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
-#define USE_KMALLOC
-
-/* FIXME there are other cases, including an x86-64 one ... */
-#endif
-
-/* allocating buffers this way eliminates dma mapping overhead, which
- * on some platforms will mean eliminating a per-io buffer copy. with
- * some kinds of system caches, further tweaks may still be needed.
- */
static void *
net2280_alloc_buffer (
struct usb_ep *_ep,
@@ -494,43 +477,71 @@ net2280_alloc_buffer (
return NULL;
*dma = DMA_ADDR_INVALID;
-#if defined(USE_KMALLOC)
- retval = kmalloc(bytes, gfp_flags);
- if (retval)
- *dma = virt_to_phys(retval);
-#else
- if (ep->dma) {
- /* the main problem with this call is that it wastes memory
- * on typical 1/N page allocations: it allocates 1-N pages.
- */
-#warning Using dma_alloc_coherent even with buffers smaller than a page.
+ if (ep->dma)
retval = dma_alloc_coherent(&ep->dev->pdev->dev,
bytes, dma, gfp_flags);
- } else
+ else
retval = kmalloc(bytes, gfp_flags);
-#endif
return retval;
}
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+ struct list_head list;
+ struct device *dev;
+ unsigned bytes;
+ dma_addr_t dma;
+};
+
+static void do_free(unsigned long ignored)
+{
+ spin_lock_irq(&buflock);
+ while (!list_empty(&buffers)) {
+ struct free_record *buf;
+
+ buf = list_entry(buffers.next, struct free_record, list);
+ list_del(&buf->list);
+ spin_unlock_irq(&buflock);
+
+ dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+ spin_lock_irq(&buflock);
+ }
+ spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
static void
net2280_free_buffer (
struct usb_ep *_ep,
- void *buf,
+ void *address,
dma_addr_t dma,
unsigned bytes
) {
/* free memory into the right allocator */
-#ifndef USE_KMALLOC
if (dma != DMA_ADDR_INVALID) {
struct net2280_ep *ep;
+ struct free_record *buf = address;
+ unsigned long flags;
ep = container_of(_ep, struct net2280_ep, ep);
if (!_ep)
return;
- dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ buf->dev = &ep->dev->pdev->dev;
+ buf->bytes = bytes;
+ buf->dma = dma;
+
+ spin_lock_irqsave(&buflock, flags);
+ list_add_tail(&buf->list, &buffers);
+ tasklet_schedule(&deferred_free);
+ spin_unlock_irqrestore(&buflock, flags);
} else
-#endif
- kfree (buf);
+ kfree (address);
}
/*-------------------------------------------------------------------------*/
@@ -738,7 +749,8 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
*/
if (ep->is_in)
dmacount |= (1 << DMA_DIRECTION);
- if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
+ if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0)
+ || ep->dev->pdev->device != 0x2280)
dmacount |= (1 << END_OF_CHAIN);
req->valid = valid;
@@ -813,7 +825,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
/* previous OUT packet might have been short */
if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
- & (1 << NAK_OUT_PACKETS)) != 0) {
+ & (1 << NAK_OUT_PACKETS)) != 0) {
writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
&ep->regs->ep_stat);
@@ -1374,7 +1386,7 @@ net2280_fifo_flush (struct usb_ep *_ep)
(void) readl (&ep->regs->ep_rsp);
}
-static struct usb_ep_ops net2280_ep_ops = {
+static const struct usb_ep_ops net2280_ep_ops = {
.enable = net2280_enable,
.disable = net2280_disable,
@@ -1632,7 +1644,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
}
/* Indexed Registers */
- // none yet
+ // none yet
/* Statistics */
t = scnprintf (next, size, "\nirqs: ");
@@ -1692,11 +1704,11 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
({ char *val;
switch (d->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
- val = "bulk"; break;
+ val = "bulk"; break;
case USB_ENDPOINT_XFER_INT:
- val = "intr"; break;
+ val = "intr"; break;
default:
- val = "iso"; break;
+ val = "iso"; break;
}; val; }),
le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
ep->dma ? "dma" : "pio", ep->fifo_size
@@ -1809,8 +1821,8 @@ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
* net2280_set_fifo_mode - change allocation of fifo buffers
* @gadget: access to the net2280 device that will be updated
* @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
- * 1 for two 2kB buffers (ep-a and ep-b only);
- * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
+ * 1 for two 2kB buffers (ep-a and ep-b only);
+ * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
*
* returns zero on success, else negative errno. when this succeeds,
* the contents of gadget->ep_list may have changed.
@@ -2242,7 +2254,8 @@ static void handle_ep_small (struct net2280_ep *ep)
req->td->dmacount = 0;
t = readl (&ep->regs->ep_avail);
dma_done (ep, req, count,
- (ep->out_overflow || t) ? -EOVERFLOW : 0);
+ (ep->out_overflow || t)
+ ? -EOVERFLOW : 0);
}
/* also flush to prevent erratum 0106 trouble */
@@ -2412,7 +2425,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
, &ep->regs->ep_stat);
u.raw [0] = readl (&dev->usb->setup0123);
u.raw [1] = readl (&dev->usb->setup4567);
-
+
cpu_to_le32s (&u.raw [0]);
cpu_to_le32s (&u.raw [1]);
@@ -2579,14 +2592,16 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
/* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
* Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
- * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
+ * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
* only indicates a change in the reset state).
*/
if (stat & tmp) {
writel (tmp, &dev->regs->irqstat1);
- if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
- ((readl (&dev->usb->usbstat) & mask) == 0))
- || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0)
+ if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
+ && ((readl (&dev->usb->usbstat) & mask)
+ == 0))
+ || ((readl (&dev->usb->usbctl)
+ & (1 << VBUS_PIN)) == 0)
) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
DEBUG (dev, "disconnect %s\n",
dev->driver->driver.name);
@@ -2853,7 +2868,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
/* now all the pci goodies ... */
if (pci_enable_device (pdev) < 0) {
- retval = -ENODEV;
+ retval = -ENODEV;
goto done;
}
dev->enabled = 1;
@@ -2871,6 +2886,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
}
dev->region = 1;
+ /* FIXME provide firmware download interface to put
+ * 8051 code into the chip, e.g. to turn on PCI PM.
+ */
+
base = ioremap_nocache (resource, len);
if (base == NULL) {
DEBUG (dev, "can't map memory\n");
@@ -2896,7 +2915,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
- if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev)
+ if (request_irq (pdev->irq, net2280_irq, IRQF_SHARED, driver_name, dev)
!= 0) {
ERROR (dev, "request interrupt %d failed\n", pdev->irq);
retval = -EBUSY;
@@ -2985,16 +3004,16 @@ static void net2280_shutdown (struct pci_dev *pdev)
/*-------------------------------------------------------------------------*/
-static struct pci_device_id pci_ids [] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
+static const struct pci_device_id pci_ids [] = { {
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2280,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2282,
.subvendor = PCI_ANY_ID,
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index fbea5144890..0a64504c254 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -22,7 +22,6 @@
#undef DEBUG
#undef VERBOSE
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -41,7 +40,7 @@
#include <linux/platform_device.h>
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <asm/byteorder.h>
@@ -773,7 +772,7 @@ static void dma_error(int lch, u16 ch_status, void *data)
struct omap_ep *ep = data;
/* if ch_status & OMAP_DMA_DROP_IRQ ... */
- /* if ch_status & OMAP_DMA_TOUT_IRQ ... */
+ /* if ch_status & OMAP1_DMA_TOUT_IRQ ... */
ERR("%s dma error, lch %d status %02x\n", ep->ep.name, lch, ch_status);
/* complete current transfer ... */
@@ -2438,7 +2437,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
return single_open(file, proc_udc_show, NULL);
}
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -2819,7 +2818,7 @@ bad_on_1710:
/* USB general purpose IRQ: ep0, state changes, dma, etc */
status = request_irq(pdev->resource[1].start, omap_udc_irq,
- SA_SAMPLE_RANDOM, driver_name, udc);
+ IRQF_SAMPLE_RANDOM, driver_name, udc);
if (status != 0) {
ERR( "can't get irq %ld, err %d\n",
pdev->resource[1].start, status);
@@ -2828,7 +2827,7 @@ bad_on_1710:
/* USB "non-iso" IRQ (PIO for all but ep0) */
status = request_irq(pdev->resource[2].start, omap_udc_pio_irq,
- SA_SAMPLE_RANDOM, "omap_udc pio", udc);
+ IRQF_SAMPLE_RANDOM, "omap_udc pio", udc);
if (status != 0) {
ERR( "can't get irq %ld, err %d\n",
pdev->resource[2].start, status);
@@ -2836,7 +2835,7 @@ bad_on_1710:
}
#ifdef USE_ISO
status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
- SA_INTERRUPT, "omap_udc iso", udc);
+ IRQF_DISABLED, "omap_udc iso", udc);
if (status != 0) {
ERR("can't get irq %ld, err %d\n",
pdev->resource[3].start, status);
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 269ce7f4ad6..f1adcf8b202 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -27,7 +27,6 @@
#undef DEBUG
// #define VERBOSE DBG_VERBOSE
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
@@ -60,7 +59,7 @@
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
-#include <asm/arch/hardware/intel_udc.h>
+#include <asm/arch/udc.h>
/*
@@ -151,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
static void nuke (struct pxa2xx_ep *, int status);
+/* one GPIO should be used to detect VBUS from the host */
+static int is_vbus_present(void)
+{
+ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+ if (mach->gpio_vbus)
+ return pxa_gpio_get(mach->gpio_vbus);
+ if (mach->udc_is_connected)
+ return mach->udc_is_connected();
+ return 1;
+}
+
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static void pullup_off(void)
+{
+ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+ if (mach->gpio_pullup)
+ pxa_gpio_set(mach->gpio_pullup, 0);
+ else if (mach->udc_command)
+ mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+static void pullup_on(void)
+{
+ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+ if (mach->gpio_pullup)
+ pxa_gpio_set(mach->gpio_pullup, 1);
+ else if (mach->udc_command)
+ mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
static void pio_irq_enable(int bEndpointAddress)
{
bEndpointAddress &= 0xf;
@@ -1722,6 +1754,16 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
#endif
+static irqreturn_t
+udc_vbus_irq(int irq, void *_dev, struct pt_regs *r)
+{
+ struct pxa2xx_udc *dev = _dev;
+ int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
+
+ pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+ return IRQ_HANDLED;
+}
+
/*-------------------------------------------------------------------------*/
@@ -2439,7 +2481,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
- int retval, out_dma = 1;
+ int retval, out_dma = 1, vbus_irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@@ -2503,6 +2545,16 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
/* other non-static parts of init */
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
+ if (dev->mach->gpio_vbus) {
+ vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
+ pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
+ | GPIO_IN);
+ set_irq_type(vbus_irq, IRQT_BOTHEDGE);
+ } else
+ vbus_irq = 0;
+ if (dev->mach->gpio_pullup)
+ pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
+ | GPIO_OUT | GPIO_DFLT_LOW);
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@@ -2522,7 +2574,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
- SA_INTERRUPT, driver_name, dev);
+ IRQF_DISABLED, driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
driver_name, IRQ_USB, retval);
@@ -2534,7 +2586,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
if (machine_is_lubbock()) {
retval = request_irq(LUBBOCK_USB_DISC_IRQ,
lubbock_vbus_irq,
- SA_INTERRUPT | SA_SAMPLE_RANDOM,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
@@ -2545,7 +2597,7 @@ lubbock_fail0:
}
retval = request_irq(LUBBOCK_USB_IRQ,
lubbock_vbus_irq,
- SA_INTERRUPT | SA_SAMPLE_RANDOM,
+ IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
driver_name, dev);
if (retval != 0) {
printk(KERN_ERR "%s: can't get irq %i, err %d\n",
@@ -2558,8 +2610,19 @@ lubbock_fail0:
HEX_DISPLAY(dev->stats.irqs);
LUB_DISC_BLNK_LED &= 0xff;
#endif
- }
+ } else
#endif
+ if (vbus_irq) {
+ retval = request_irq(vbus_irq, udc_vbus_irq,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM,
+ driver_name, dev);
+ if (retval != 0) {
+ printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+ driver_name, vbus_irq, retval);
+ free_irq(IRQ_USB, dev);
+ return -EBUSY;
+ }
+ }
create_proc_files();
return 0;
@@ -2588,6 +2651,8 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
+ if (dev->mach->gpio_vbus)
+ free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 19a883f7d1b..8e598c8bf4e 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,27 +177,19 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
-/* one GPIO should be used to detect VBUS from the host */
-static inline int is_vbus_present(void)
+static inline int pxa_gpio_get(unsigned gpio)
{
- if (!the_controller->mach->udc_is_connected)
- return 1;
- return the_controller->mach->udc_is_connected();
+ return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
}
-/* one GPIO should control a D+ pullup, so host sees this device (or not) */
-static inline void pullup_off(void)
+static inline void pxa_gpio_set(unsigned gpio, int is_on)
{
- if (!the_controller->mach->udc_command)
- return;
- the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
-}
+ int mask = GPIO_bit(gpio);
-static inline void pullup_on(void)
-{
- if (!the_controller->mach->udc_command)
- return;
- the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+ if (is_on)
+ GPSR(gpio) = mask;
+ else
+ GPCR(gpio) = mask;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 3ff6db7828a..408c3380d60 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -23,7 +23,6 @@
* updates to merge with Linux 2.6, better match RNDIS spec
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -1399,7 +1398,7 @@ static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
-int __init rndis_init (void)
+int __devinit rndis_init (void)
{
u8 i;
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 2956608be75..4c3c7259f01 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -264,7 +264,7 @@ int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);
extern void rndis_set_host_mac (int configNr, const u8 *addr);
-int __init rndis_init (void);
+int __devinit rndis_init (void);
void rndis_exit (void);
#endif /* _LINUX_RNDIS_H */
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 9d6e1d29552..b893e3118e1 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -588,12 +587,11 @@ static int __init gs_module_init(void)
gs_tty_driver->owner = THIS_MODULE;
gs_tty_driver->driver_name = GS_SHORT_NAME;
gs_tty_driver->name = "ttygs";
- gs_tty_driver->devfs_name = "usb/ttygs/";
gs_tty_driver->major = GS_MAJOR;
gs_tty_driver->minor_start = GS_MINOR_START;
gs_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
gs_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ gs_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
gs_tty_driver->init_termios = tty_std_termios;
gs_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(gs_tty_driver, &gs_tty_ops);
@@ -1122,12 +1120,15 @@ static int gs_send(struct gs_dev *dev)
gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
+ spin_unlock_irqrestore(&dev->dev_lock, flags);
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
printk(KERN_ERR
"gs_send: cannot queue read request, ret=%d\n",
ret);
+ spin_lock_irqsave(&dev->dev_lock, flags);
break;
}
+ spin_lock_irqsave(&dev->dev_lock, flags);
} else {
break;
}
@@ -1475,7 +1476,7 @@ autoconf_fail:
* Called on module unload. Frees the control request and device
* structure.
*/
-static void __exit gs_unbind(struct usb_gadget *gadget)
+static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
{
struct gs_dev *dev = get_gadget_data(gadget);
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 68e3d8f5da8..b7018ee487e 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -62,7 +62,6 @@
#define DEBUG 1
// #define VERBOSE
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
@@ -1122,7 +1121,7 @@ zero_autoresume (unsigned long _dev)
/*-------------------------------------------------------------------------*/
-static void __exit
+static void /* __init_or_exit */
zero_unbind (struct usb_gadget *gadget)
{
struct zero_dev *dev = get_gadget_data (gadget);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b93d71d28db..cf10cbc98f8 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -83,6 +83,7 @@ config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+ select I2C if ARCH_PNX4008
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's
@@ -141,6 +142,34 @@ config USB_UHCI_HCD
To compile this driver as a module, choose M here: the
module will be called uhci-hcd.
+config USB_U132_HCD
+ tristate "Elan U132 Adapter Host Controller"
+ depends on USB && USB_FTDI_ELAN
+ default M
+ help
+ The U132 adapter is a USB to CardBus adapter specifically designed
+ for PC cards that contain an OHCI host controller. Typical PC cards
+ are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132
+ adapter will *NOT* work with PC cards that do not contain an OHCI
+ controller.
+
+ For those PC cards that contain multiple OHCI controllers only ther
+ first one is used.
+
+ The driver consists of two modules, the "ftdi-elan" module is a
+ USB client driver that interfaces to the FTDI chip within ELAN's
+ USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host
+ controller driver that talks to the OHCI controller within the
+ CardBus cards that are inserted in the U132 adapter.
+
+ This driver has been tested with a CardBus OHCI USB adapter, and
+ worked with a USB PEN Drive inserted into the first USB port of
+ the PCCARD. A rather pointless thing to do, but useful for testing.
+
+ It is safe to say M here.
+
+ See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php>
+
config USB_SL811_HCD
tristate "SL811HS HCD support"
depends on USB
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index e3020f4b17b..a2e58c86849 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -14,4 +14,5 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
+obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 9b4697add31..5d1b12aad77 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -41,8 +41,6 @@
#endif
#define USBH_DISABLE (USB_MCFG_EBMEN | USB_MCFG_EMEMEN)
-#endif /* Au1200 */
-
extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/
@@ -107,9 +105,9 @@ int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
/* Au1200 AB USB does not support coherent memory */
if (!(read_c0_prid() & 0xff)) {
- pr_info("%s: this is chip revision AB!\n", dev->dev.name);
+ pr_info("%s: this is chip revision AB!\n", dev->name);
pr_info("%s: update your board or re-configure the kernel\n",
- dev->dev.name);
+ dev->name);
return -ENODEV;
}
#endif
@@ -148,7 +146,7 @@ int usb_ehci_au1xxx_probe(const struct hc_driver *driver,
/* ehci_hcd_init(hcd_to_ehci(hcd)); */
retval =
- usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
+ usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED);
if (retval == 0)
return retval;
@@ -202,6 +200,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -228,9 +227,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
/*-------------------------------------------------------------------------*/
-static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
+static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
struct usb_hcd *hcd = NULL;
int ret;
@@ -243,10 +241,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct device *dev)
return ret;
}
-static int ehci_hcd_au1xxx_drv_remove(struct device *dev)
+static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_ehci_au1xxx_remove(hcd, pdev);
return 0;
@@ -269,12 +266,14 @@ static int ehci_hcd_au1xxx_drv_resume(struct device *dev)
}
*/
MODULE_ALIAS("au1xxx-ehci");
-/* FIXME use "struct platform_driver" */
-static struct device_driver ehci_hcd_au1xxx_driver = {
- .name = "au1xxx-ehci",
- .bus = &platform_bus_type,
+static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ehci_hcd_au1xxx_drv_suspend, */
/*.resume = ehci_hcd_au1xxx_drv_resume, */
+ .driver = {
+ .name = "au1xxx-ehci",
+ .bus = &platform_bus_type
+ }
};
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 65ac9fef3a7..23b95b2bfe1 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2001-2002 by David Brownell
- *
+ *
* 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
@@ -65,7 +65,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
for (i = 0; i < HCS_N_PORTS (params); i++) {
// FIXME MIPS won't readb() ...
byte = readb (&ehci->caps->portroute[(i>>1)]);
- sprintf(tmp, "%d ",
+ sprintf(tmp, "%d ",
((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
strcat(buf, tmp);
}
@@ -141,12 +141,12 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
}
static void __attribute__((__unused__))
-dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
+dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
ehci_dbg (ehci,
- " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_transaction[0]),
le32_to_cpu(itd->hw_transaction[1]),
le32_to_cpu(itd->hw_transaction[2]),
@@ -156,7 +156,7 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
le32_to_cpu(itd->hw_transaction[6]),
le32_to_cpu(itd->hw_transaction[7]));
ehci_dbg (ehci,
- " buf: %08x %08x %08x %08x %08x %08x %08x\n",
+ " buf: %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_bufp[0]),
le32_to_cpu(itd->hw_bufp[1]),
le32_to_cpu(itd->hw_bufp[2]),
@@ -171,12 +171,12 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
}
static void __attribute__((__unused__))
-dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
ehci_dbg (ehci,
- " addr %08x sched %04x result %08x buf %08x %08x\n",
+ " addr %08x sched %04x result %08x buf %08x %08x\n",
le32_to_cpu(sitd->hw_fullspeed_ep),
le32_to_cpu(sitd->hw_uframe),
le32_to_cpu(sitd->hw_results),
@@ -451,7 +451,7 @@ show_async (struct class_device *class_dev, char *buf)
*buf = 0;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@@ -497,7 +497,7 @@ show_periodic (struct class_device *class_dev, char *buf)
seen_count = 0;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@@ -634,7 +634,7 @@ show_registers (struct class_device *class_dev, char *buf)
static char label [] = "";
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@@ -754,9 +754,7 @@ show_registers (struct class_device *class_dev, char *buf)
}
if (ehci->reclaim) {
- temp = scnprintf (next, size, "reclaim qh %p%s\n",
- ehci->reclaim,
- ehci->reclaim_ready ? " ready" : "");
+ temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim);
size -= temp;
next += temp;
}
@@ -785,10 +783,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ehci_hcd *ehci)
{
struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
+ int retval;
- class_device_create_file(cldev, &class_device_attr_async);
- class_device_create_file(cldev, &class_device_attr_periodic);
- class_device_create_file(cldev, &class_device_attr_registers);
+ retval = class_device_create_file(cldev, &class_device_attr_async);
+ retval = class_device_create_file(cldev, &class_device_attr_periodic);
+ retval = class_device_create_file(cldev, &class_device_attr_registers);
}
static inline void remove_debug_files (struct ehci_hcd *ehci)
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index a49a689bf42..1a915e982c1 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -121,7 +121,7 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
temp = in_le32(hcd->regs + 0x1a8);
out_le32(hcd->regs + 0x1a8, temp | 0x3);
- retval = usb_add_hcd(hcd, irq, SA_SHIRQ);
+ retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
if (retval != 0)
goto err4;
return retval;
@@ -285,6 +285,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.resume = ehci_bus_resume,
#endif
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -329,6 +330,7 @@ MODULE_ALIAS("fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
.probe = ehci_fsl_drv_probe,
.remove = ehci_fsl_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
},
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9b37e508ada..5ac91859113 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000-2004 by David Brownell
- *
+ *
* 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
@@ -16,7 +16,6 @@
* Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/dmapool.h>
@@ -71,7 +70,7 @@
* 2002-08-06 Handling for bulk and interrupt transfers is mostly shared;
* only scheduling is different, no arbitrary limitations.
* 2002-07-25 Sanity check PCI reads, mostly for better cardbus support,
- * clean up HC run state handshaking.
+ * clean up HC run state handshaking.
* 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts
* 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other
* missing pieces: enabling 64bit dma, handoff from BIOS/SMM.
@@ -112,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd";
#define EHCI_TUNE_MULT_TT 1
#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
-#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */
+#define EHCI_IAA_MSECS 10 /* arbitrary */
#define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */
#define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */
#define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */
@@ -255,6 +254,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
+static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs);
static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
#include "ehci-hub.c"
@@ -264,28 +264,39 @@ static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
/*-------------------------------------------------------------------------*/
-static void ehci_watchdog (unsigned long param)
+static void ehci_iaa_watchdog (unsigned long param)
{
struct ehci_hcd *ehci = (struct ehci_hcd *) param;
unsigned long flags;
+ u32 status;
spin_lock_irqsave (&ehci->lock, flags);
+ WARN_ON(!ehci->reclaim);
- /* lost IAA irqs wedge things badly; seen with a vt8235 */
+ /* lost IAA irqs wedge things badly; seen first with a vt8235 */
if (ehci->reclaim) {
- u32 status = readl (&ehci->regs->status);
-
+ status = readl (&ehci->regs->status);
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
writel (STS_IAA, &ehci->regs->status);
- ehci->reclaim_ready = 1;
+ end_unlink_async (ehci, NULL);
}
}
- /* stop async processing after it's idled a bit */
+ spin_unlock_irqrestore (&ehci->lock, flags);
+}
+
+static void ehci_watchdog (unsigned long param)
+{
+ struct ehci_hcd *ehci = (struct ehci_hcd *) param;
+ unsigned long flags;
+
+ spin_lock_irqsave (&ehci->lock, flags);
+
+ /* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
- start_unlink_async (ehci, ehci->async);
+ start_unlink_async (ehci, ehci->async);
/* ehci could run by timer, without IRQs ... */
ehci_work (ehci, NULL);
@@ -293,21 +304,20 @@ static void ehci_watchdog (unsigned long param)
spin_unlock_irqrestore (&ehci->lock, flags);
}
-/* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
+/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
* This forcibly disables dma and IRQs, helping kexec and other cases
* where the next system software may expect clean state.
*/
-static int
-ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
+static void
+ehci_shutdown (struct usb_hcd *hcd)
{
- struct ehci_hcd *ehci;
+ struct ehci_hcd *ehci;
- ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+ ehci = hcd_to_ehci (hcd);
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag);
- return 0;
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -335,8 +345,6 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
- if (ehci->reclaim_ready)
- end_unlink_async (ehci, regs);
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
@@ -371,6 +379,7 @@ static void ehci_stop (struct usb_hcd *hcd)
/* no more interrupts ... */
del_timer_sync (&ehci->watchdog);
+ del_timer_sync (&ehci->iaa_watchdog);
spin_lock_irq(&ehci->lock);
if (HC_IS_RUNNING (hcd->state))
@@ -382,7 +391,6 @@ static void ehci_stop (struct usb_hcd *hcd)
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
- unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
@@ -418,6 +426,10 @@ static int ehci_init(struct usb_hcd *hcd)
ehci->watchdog.function = ehci_watchdog;
ehci->watchdog.data = (unsigned long) ehci;
+ init_timer(&ehci->iaa_watchdog);
+ ehci->iaa_watchdog.function = ehci_iaa_watchdog;
+ ehci->iaa_watchdog.data = (unsigned long) ehci;
+
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -428,13 +440,12 @@ static int ehci_init(struct usb_hcd *hcd)
/* controllers may cache some of the periodic schedule ... */
hcc_params = readl(&ehci->caps->hcc_params);
- if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
+ if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
ehci->reclaim = NULL;
- ehci->reclaim_ready = 0;
ehci->next_uframe = -1;
/*
@@ -484,9 +495,6 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
- ehci->reboot_notifier.notifier_call = ehci_reboot;
- register_reboot_notifier(&ehci->reboot_notifier);
-
return 0;
}
@@ -500,7 +508,6 @@ static int ehci_run (struct usb_hcd *hcd)
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
- unregister_reboot_notifier(&ehci->reboot_notifier);
ehci_mem_cleanup(ehci);
return retval;
}
@@ -612,7 +619,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
/* complete the unlinking of some qh [4.15.2.3] */
if (status & STS_IAA) {
COUNT (ehci->stats.reclaim);
- ehci->reclaim_ready = 1;
+ end_unlink_async (ehci, regs);
bh = 1;
}
@@ -626,10 +633,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
writel (status | CMD_RUN, &ehci->regs->command);
while (i--) {
- status = readl (&ehci->regs->port_status [i]);
- if (status & PORT_OWNER)
+ int pstatus = readl (&ehci->regs->port_status [i]);
+
+ if (pstatus & PORT_OWNER)
continue;
- if (!(status & PORT_RESUME)
+ if (!(pstatus & PORT_RESUME)
|| ehci->reset_done [i] != 0)
continue;
@@ -715,10 +723,14 @@ static int ehci_urb_enqueue (
static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- /* if we need to use IAA and it's busy, defer */
- if (qh->qh_state == QH_STATE_LINKED
- && ehci->reclaim
- && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) {
+ // BUG_ON(qh->qh_state != QH_STATE_LINKED);
+
+ /* failfast */
+ if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+ end_unlink_async (ehci, NULL);
+
+ /* defer till later if busy */
+ else if (ehci->reclaim) {
struct ehci_qh *last;
for (last = ehci->reclaim;
@@ -728,12 +740,8 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
qh->qh_state = QH_STATE_UNLINK_WAIT;
last->reclaim = qh;
- /* bypass IAA if the hc can't care */
- } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
- end_unlink_async (ehci, NULL);
-
- /* something else might have unlinked the qh by now */
- if (qh->qh_state == QH_STATE_LINKED)
+ /* start IAA cycle */
+ } else
start_unlink_async (ehci, qh);
}
@@ -755,7 +763,19 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
- unlink_async (ehci, qh);
+ switch (qh->qh_state) {
+ case QH_STATE_LINKED:
+ case QH_STATE_COMPLETING:
+ unlink_async (ehci, qh);
+ break;
+ case QH_STATE_UNLINK:
+ case QH_STATE_UNLINK_WAIT:
+ /* already started */
+ break;
+ case QH_STATE_IDLE:
+ WARN_ON(1);
+ break;
+ }
break;
case PIPE_INTERRUPT:
@@ -847,6 +867,7 @@ rescan:
unlink_async (ehci, qh);
/* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
+ case QH_STATE_UNLINK_WAIT:
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
schedule_timeout_uninterruptible(1);
@@ -892,7 +913,7 @@ MODULE_LICENSE ("GPL");
#define PCI_DRIVER ehci_pci_driver
#endif
-#ifdef CONFIG_PPC_83xx
+#ifdef CONFIG_MPC834x
#include "ehci-fsl.c"
#define PLATFORM_DRIVER ehci_fsl_driver
#endif
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d03e3cad5ca..b2ee13c5851 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 by David Brownell
- *
+ *
* 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
@@ -48,7 +48,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
}
ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async (ehci, NULL);
ehci_work(ehci, NULL);
/* suspend any active/unsuspended ports, maybe allow wakeup */
@@ -103,10 +103,10 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) {
- /* at least some APM implementations will try to deliver
+ /* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
- */
- intr_enable = 1;
+ */
+ intr_enable = 1;
writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
@@ -232,7 +232,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [1] = 0;
retval++;
}
-
+
/* no hub change reports (bit 0) for now (power, ...) */
/* port N changes (bit N)? */
@@ -304,7 +304,7 @@ ehci_hub_descriptor (
/*-------------------------------------------------------------------------*/
-#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
static int ehci_hub_control (
struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 766061e0260..a8ba2e1497a 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2001 by David Brownell
- *
+ *
* 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
@@ -25,7 +25,7 @@
* - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these
* need to use dma_pool or dma_alloc_coherent
- * - driver buffers, read/written by HC ... single shot DMA mapped
+ * - driver buffers, read/written by HC ... single shot DMA mapped
*
* There's also PCI "register" data, which is memory mapped.
* No memory seen by this driver is pageable.
@@ -119,7 +119,7 @@ static inline void qh_put (struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-/* The queue heads and transfer descriptors are managed from pools tied
+/* The queue heads and transfer descriptors are managed from pools tied
* to each of the "per device" structures.
* This is the initialisation and cleanup code.
*/
@@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
int i;
/* QTDs for control/bulk/intr transfers */
- ehci->qtd_pool = dma_pool_create ("ehci_qtd",
+ ehci->qtd_pool = dma_pool_create ("ehci_qtd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qtd),
32 /* byte alignment (for hw parts) */,
@@ -175,7 +175,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* QHs for control/bulk/intr transfers */
- ehci->qh_pool = dma_pool_create ("ehci_qh",
+ ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qh),
32 /* byte alignment (for hw parts) */,
@@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* ITD for high speed ISO transfers */
- ehci->itd_pool = dma_pool_create ("ehci_itd",
+ ehci->itd_pool = dma_pool_create ("ehci_itd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_itd),
32 /* byte alignment (for hw parts) */,
@@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* SITD for full/low speed split ISO transfers */
- ehci->sitd_pool = dma_pool_create ("ehci_sitd",
+ ehci->sitd_pool = dma_pool_create ("ehci_sitd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_sitd),
32 /* byte alignment (for hw parts) */,
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index cadffacd945..08d0472d4f5 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -238,6 +238,12 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
writel (0, &ehci->regs->intr_enable);
(void)readl(&ehci->regs->intr_enable);
+ /* make sure snapshot being resumed re-enumerates everything */
+ if (message.event == PM_EVENT_PRETHAW) {
+ ehci_halt(ehci);
+ ehci_reset(ehci);
+ }
+
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
bail:
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -297,7 +303,7 @@ restart:
/* emptying the schedule aborts any urbs */
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
- ehci->reclaim_ready = 1;
+ end_unlink_async (ehci, NULL);
ehci_work(ehci, NULL);
spin_unlock_irq(&ehci->lock);
@@ -332,6 +338,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
.resume = ehci_pci_resume,
#endif
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -378,4 +385,5 @@ static struct pci_driver ehci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
+ .shutdown = usb_hcd_pci_shutdown,
};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index e469221e7ec..7fc25b6bd7d 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 by David Brownell
- *
+ *
* 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
@@ -31,7 +31,7 @@
* ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
* interrupts) needs careful scheduling. Performance improvements can be
* an ongoing challenge. That's in "ehci-sched.c".
- *
+ *
* USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
* or otherwise through transaction translators (TTs) in USB 2.0 hubs using
* (b) special fields in qh entries or (c) split iso entries. TTs will
@@ -199,7 +199,7 @@ static void qtd_copy_status (
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
&& (!ehci_is_TDI(ehci)
- || urb->dev->tt->hub !=
+ || urb->dev->tt->hub !=
ehci_to_hcd(ehci)->self.root_hub)) {
#ifdef DEBUG
struct usb_device *tt = urb->dev->tt->hub;
@@ -364,7 +364,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
*/
if (likely (urb->status == -EINPROGRESS))
continue;
-
+
/* issue status after short control reads */
if (unlikely (do_status != 0)
&& QTD_PID (token) == 0 /* OUT */) {
@@ -388,7 +388,7 @@ halt:
wmb ();
}
}
-
+
/* remove it from the queue */
spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token);
@@ -518,7 +518,7 @@ qh_urb_transaction (
/* for zero length DATA stages, STATUS is always IN */
if (len == 0)
token |= (1 /* "in" */ << 8);
- }
+ }
/*
* data transfer stage: buffer setup
@@ -759,7 +759,7 @@ qh_make (
}
break;
default:
- dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
qh_put (qh);
return NULL;
@@ -967,17 +967,16 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
- timer_action_done (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_done (ehci);
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
- qh_put (qh); // refcount from reclaim
+ qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
ehci->reclaim = next;
- ehci->reclaim_ready = 0;
qh->reclaim = NULL;
qh_completions (ehci, qh, regs);
@@ -1031,7 +1030,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
timer_action_done (ehci, TIMER_ASYNC_OFF);
}
return;
- }
+ }
qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_get (qh);
@@ -1046,17 +1045,16 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
/* if (unlikely (qh->reclaim != 0))
- * this will recurse, probably not much
+ * this will recurse, probably not much
*/
end_unlink_async (ehci, NULL);
return;
}
- ehci->reclaim_ready = 0;
cmd |= CMD_IAAD;
writel (cmd, &ehci->regs->command);
(void) readl (&ehci->regs->command);
- timer_action (ehci, TIMER_IAA_WATCHDOG);
+ iaa_watchdog_start (ehci);
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 4859900bd13..e5e9c653c90 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2001-2004 by David Brownell
* Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
- *
+ *
* 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
@@ -613,7 +613,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
static int check_period (
- struct ehci_hcd *ehci,
+ struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
unsigned period,
@@ -629,7 +629,7 @@ static int check_period (
/*
* 80% periodic == 100 usec/uframe available
- * convert "usecs we need" to "max already claimed"
+ * convert "usecs we need" to "max already claimed"
*/
usecs = 100 - usecs;
@@ -659,14 +659,14 @@ static int check_period (
}
static int check_intr_schedule (
- struct ehci_hcd *ehci,
+ struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
const struct ehci_qh *qh,
__le32 *c_maskp
)
{
- int retval = -ENOSPC;
+ int retval = -ENOSPC;
u8 mask = 0;
if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
@@ -701,7 +701,7 @@ static int check_intr_schedule (
/* Make sure this tt's buffer is also available for CSPLITs.
* We pessimize a bit; probably the typical full speed case
* doesn't need the second CSPLIT.
- *
+ *
* NOTE: both SPLIT and CSPLIT could be checked in just
* one smart pass...
*/
@@ -728,7 +728,7 @@ done:
*/
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int status;
+ int status;
unsigned uframe;
__le32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
@@ -784,7 +784,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
/* stuff into the periodic schedule */
- status = qh_link_periodic (ehci, qh);
+ status = qh_link_periodic (ehci, qh);
done:
return status;
}
@@ -1681,7 +1681,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
- if (likely (status == 0))
+ if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -1738,7 +1738,7 @@ sitd_sched_init (
if (packet->buf1 != (buf & ~(u64)0x0fff))
packet->cross = 1;
- /* OUT uses multiple start-splits */
+ /* OUT uses multiple start-splits */
if (stream->bEndpointAddress & USB_DIR_IN)
continue;
length = (length + 187) / 188;
@@ -1925,7 +1925,7 @@ sitd_link_urb (
/*-------------------------------------------------------------------------*/
#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
- | SITD_STS_XACT | SITD_STS_MMF)
+ | SITD_STS_XACT | SITD_STS_MMF)
static unsigned
sitd_complete (
@@ -2043,7 +2043,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
- if (status == 0)
+ if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -2226,5 +2226,5 @@ restart:
now_uframe++;
now_uframe %= mod;
}
- }
+ }
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 679c1cdcc91..6aac39f50e0 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2001-2002 by David Brownell
- *
+ *
* 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
@@ -58,7 +58,6 @@ struct ehci_hcd { /* one per controller */
/* async schedule support */
struct ehci_qh *async;
struct ehci_qh *reclaim;
- unsigned reclaim_ready : 1;
unsigned scanning : 1;
/* periodic schedule support */
@@ -81,8 +80,8 @@ struct ehci_hcd { /* one per controller */
struct dma_pool *itd_pool; /* itd per iso urb */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
+ struct timer_list iaa_watchdog;
struct timer_list watchdog;
- struct notifier_block reboot_notifier;
unsigned long actions;
unsigned stamp;
unsigned long next_statechange;
@@ -104,7 +103,7 @@ struct ehci_hcd { /* one per controller */
#endif
};
-/* convert between an HCD pointer and the corresponding EHCI_HCD */
+/* convert between an HCD pointer and the corresponding EHCI_HCD */
static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
{
return (struct ehci_hcd *) (hcd->hcd_priv);
@@ -115,9 +114,21 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci)
}
+static inline void
+iaa_watchdog_start (struct ehci_hcd *ehci)
+{
+ WARN_ON(timer_pending(&ehci->iaa_watchdog));
+ mod_timer (&ehci->iaa_watchdog,
+ jiffies + msecs_to_jiffies(EHCI_IAA_MSECS));
+}
+
+static inline void iaa_watchdog_done (struct ehci_hcd *ehci)
+{
+ del_timer (&ehci->iaa_watchdog);
+}
+
enum ehci_timer_action {
TIMER_IO_WATCHDOG,
- TIMER_IAA_WATCHDOG,
TIMER_ASYNC_SHRINK,
TIMER_ASYNC_OFF,
};
@@ -135,9 +146,6 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
unsigned long t;
switch (action) {
- case TIMER_IAA_WATCHDOG:
- t = EHCI_IAA_JIFFIES;
- break;
case TIMER_IO_WATCHDOG:
t = EHCI_IO_JIFFIES;
break;
@@ -154,8 +162,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
// async queue SHRINK often precedes IAA. while it's ready
// to go OFF neither can matter, and afterwards the IO
// watchdog stops unless there's still periodic traffic.
- if (action != TIMER_IAA_WATCHDOG
- && t > ehci->watchdog.expires
+ if (time_before_eq(t, ehci->watchdog.expires)
&& timer_pending (&ehci->watchdog))
return;
mod_timer (&ehci->watchdog, t);
@@ -179,8 +186,8 @@ struct ehci_caps {
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
u32 hcc_params; /* HCCPARAMS - offset 0x8 */
@@ -205,7 +212,7 @@ struct ehci_regs {
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
#define CMD_ASE (1<<5) /* async schedule enable */
-#define CMD_PSE (1<<4) /* periodic schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
/* 3:2 is periodic frame list size */
#define CMD_RESET (1<<1) /* reset HC not bus */
#define CMD_RUN (1<<0) /* start/stop HC */
@@ -231,9 +238,9 @@ struct ehci_regs {
/* FRINDEX: offset 0x0C */
u32 frame_index; /* current microframe number */
/* CTRLDSSEGMENT: offset 0x10 */
- u32 segment; /* address bits 63:32 if needed */
+ u32 segment; /* address bits 63:32 if needed */
/* PERIODICLISTBASE: offset 0x14 */
- u32 frame_list; /* points to periodic list */
+ u32 frame_list; /* points to periodic list */
/* ASYNCLISTADDR: offset 0x18 */
u32 async_next; /* address of next async queue head */
@@ -302,7 +309,7 @@ struct ehci_dbg_port {
/*
* EHCI Specification 0.95 Section 3.5
- * QTD: describe data transfer components (buffer, direction, ...)
+ * QTD: describe data transfer components (buffer, direction, ...)
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
*
* These are associated only with "QH" (Queue Head) structures,
@@ -312,7 +319,7 @@ struct ehci_qtd {
/* first part defined by EHCI spec */
__le32 hw_next; /* see EHCI 3.5.1 */
__le32 hw_alt_next; /* see EHCI 3.5.2 */
- __le32 hw_token; /* see EHCI 3.5.3 */
+ __le32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
@@ -349,8 +356,8 @@ struct ehci_qtd {
/* values for that type tag */
#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
-#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
-#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
+#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
@@ -367,7 +374,7 @@ struct ehci_qtd {
* For entries in the async schedule, the type tag always says "qh".
*/
union ehci_shadow {
- struct ehci_qh *qh; /* Q_TYPE_QH */
+ struct ehci_qh *qh; /* Q_TYPE_QH */
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
@@ -397,7 +404,7 @@ struct ehci_qh {
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
__le32 hw_current; /* qtd list - see EHCI 3.6.4 */
-
+
/* qtd overlay (hardware parts of a struct ehci_qtd) */
__le32 hw_qtd_next;
__le32 hw_alt_next;
@@ -472,7 +479,7 @@ struct ehci_iso_stream {
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
struct usb_device *udev;
- struct usb_host_endpoint *ep;
+ struct usb_host_endpoint *ep;
/* output of (re)scheduling */
unsigned long start; /* jiffies */
@@ -492,8 +499,8 @@ struct ehci_iso_stream {
unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */
- __le32 buf0;
- __le32 buf1;
+ __le32 buf0;
+ __le32 buf1;
__le32 buf2;
/* this is used to initialize sITD's tt info */
@@ -521,7 +528,7 @@ struct ehci_itd {
#define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
- __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
+ __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
__le32 hw_bufp_hi [7]; /* Appendix B */
/* the rest is HCD-private */
@@ -542,7 +549,7 @@ struct ehci_itd {
/*-------------------------------------------------------------------------*/
/*
- * EHCI Specification 0.95 Section 3.4
+ * EHCI Specification 0.95 Section 3.4
* siTD, aka split-transaction isochronous Transfer Descriptor
* ... describe full speed iso xfers through TT in hubs
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 2fe7fd19437..61e571782cf 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -4,7 +4,6 @@
* Copyright (c) 2002, 2003 Axis Communications AB.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
@@ -411,8 +410,7 @@ static inline void urb_list_move_last(struct urb *urb, int epid)
urb_entry_t *urb_entry = __urb_list_entry(urb, epid);
assert(urb_entry);
- list_del(&urb_entry->list);
- list_add_tail(&urb_entry->list, &urb_list[epid]);
+ list_move_tail(&urb_entry->list, &urb_list[epid]);
}
/* Get the next urb in the list. */
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 14386254c87..a72e041df8e 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -1204,10 +1204,10 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused)
static int isp116x_open_seq(struct inode *inode, struct file *file)
{
- return single_open(file, isp116x_show_dbg, inode->u.generic_ip);
+ return single_open(file, isp116x_show_dbg, inode->i_private);
}
-static struct file_operations isp116x_debug_fops = {
+static const struct file_operations isp116x_debug_fops = {
.open = isp116x_open_seq,
.read = seq_read,
.llseek = seq_lseek,
@@ -1653,7 +1653,7 @@ static int __init isp116x_probe(struct platform_device *pdev)
goto err6;
}
- ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (ret)
goto err6;
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
index a1b7c3813d3..b91e2edd9c5 100644
--- a/drivers/usb/host/isp116x.h
+++ b/drivers/usb/host/isp116x.h
@@ -233,7 +233,7 @@ static const int cc_to_error[16] = {
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
+ /* DevNotResp */ -ETIME,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 6b7350b5241..b466581beb4 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -4,7 +4,7 @@
* Copyright (C) 2004 SAN People (Pty) Ltd.
* Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
*
- * AT91RM9200 Bus Glue
+ * AT91 Bus Glue
*
* Based on fragments of 2.4 driver by Rick Bronson.
* Based on ohci-omap.c
@@ -19,12 +19,13 @@
#include <asm/hardware.h>
#include <asm/arch/board.h>
-#ifndef CONFIG_ARCH_AT91RM9200
-#error "CONFIG_ARCH_AT91RM9200 must be defined."
+#ifndef CONFIG_ARCH_AT91
+#error "CONFIG_ARCH_AT91 must be defined."
#endif
/* interface and function clocks */
static struct clk *iclk, *fclk;
+static int clocked;
extern int usb_disabled(void);
@@ -35,13 +36,14 @@ static void at91_start_hc(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd->regs;
- dev_dbg(&pdev->dev, "starting AT91RM9200 OHCI USB Controller\n");
+ dev_dbg(&pdev->dev, "start\n");
/*
* Start the USB clocks.
*/
clk_enable(iclk);
clk_enable(fclk);
+ clocked = 1;
/*
* The USB host controller must remain in reset.
@@ -54,7 +56,7 @@ static void at91_stop_hc(struct platform_device *pdev)
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd->regs;
- dev_dbg(&pdev->dev, "stopping AT91RM9200 OHCI USB Controller\n");
+ dev_dbg(&pdev->dev, "stop\n");
/*
* Put the USB host controller into reset.
@@ -66,6 +68,7 @@ static void at91_stop_hc(struct platform_device *pdev)
*/
clk_disable(fclk);
clk_disable(iclk);
+ clocked = 0;
}
@@ -78,14 +81,15 @@ static int usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
/**
- * usb_hcd_at91_probe - initialize AT91RM9200-based HCDs
+ * usb_hcd_at91_probe - initialize AT91-based HCDs
* Context: !in_interrupt()
*
* Allocates basic resources for this USB host controller, and
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *pdev)
+static int usb_hcd_at91_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
{
int retval;
struct usb_hcd *hcd = NULL;
@@ -95,12 +99,13 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *
return -ENODEV;
}
- if ((pdev->resource[0].flags != IORESOURCE_MEM) || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
+ if ((pdev->resource[0].flags != IORESOURCE_MEM)
+ || (pdev->resource[1].flags != IORESOURCE_IRQ)) {
pr_debug("hcd probe: invalid resource type\n");
return -ENODEV;
}
- hcd = usb_create_hcd(driver, &pdev->dev, "at91rm9200");
+ hcd = usb_create_hcd(driver, &pdev->dev, "at91");
if (!hcd)
return -ENOMEM;
hcd->rsrc_start = pdev->resource[0].start;
@@ -125,7 +130,7 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *
at91_start_hc(pdev);
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -149,21 +154,23 @@ int usb_hcd_at91_probe (const struct hc_driver *driver, struct platform_device *
/* may be called with controller, bus, and devices active */
/**
- * usb_hcd_at91_remove - shutdown processing for AT91RM9200-based HCDs
+ * usb_hcd_at91_remove - shutdown processing for AT91-based HCDs
* @dev: USB Host Controller being removed
* Context: !in_interrupt()
*
* Reverses the effect of usb_hcd_at91_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
+ * context, "rmmod" or something similar.
*
*/
-static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+static int usb_hcd_at91_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
{
usb_remove_hcd(hcd);
at91_stop_hc(pdev);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ disable_irq_wake(hcd->irq);
clk_put(fclk);
clk_put(iclk);
@@ -178,19 +185,21 @@ static int usb_hcd_at91_remove (struct usb_hcd *hcd, struct platform_device *pde
static int __devinit
ohci_at91_start (struct usb_hcd *hcd)
{
-// struct at91_ohci_data *board = hcd->self.controller->platform_data;
+ struct at91_usbh_data *board = hcd->self.controller->platform_data;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct usb_device *root = hcd->self.root_hub;
int ret;
if ((ret = ohci_init(ohci)) < 0)
return ret;
+ ohci->num_ports = board->ports;
+
if ((ret = ohci_run(ohci)) < 0) {
err("can't start %s", hcd->self.bus_name);
ohci_stop(hcd);
return ret;
}
-// hcd->self.root_hub->maxchild = board->ports;
return 0;
}
@@ -198,7 +207,7 @@ ohci_at91_start (struct usb_hcd *hcd)
static const struct hc_driver ohci_at91_hc_driver = {
.description = hcd_name,
- .product_desc = "AT91RM9200 OHCI",
+ .product_desc = "AT91 OHCI",
.hcd_priv_size = sizeof(struct ohci_hcd),
/*
@@ -212,6 +221,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.start = ohci_at91_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -230,7 +240,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
-
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -240,33 +250,55 @@ static const struct hc_driver ohci_at91_hc_driver = {
/*-------------------------------------------------------------------------*/
-static int ohci_hcd_at91_drv_probe(struct platform_device *dev)
+static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
{
- return usb_hcd_at91_probe(&ohci_at91_hc_driver, dev);
+ device_init_wakeup(&pdev->dev, 1);
+ return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
}
-static int ohci_hcd_at91_drv_remove(struct platform_device *dev)
+static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
{
- return usb_hcd_at91_remove(platform_get_drvdata(dev), dev);
+ device_init_wakeup(&pdev->dev, 0);
+ return usb_hcd_at91_remove(platform_get_drvdata(pdev), pdev);
}
#ifdef CONFIG_PM
-/* REVISIT suspend/resume look "too" simple here */
-
static int
-ohci_hcd_at91_drv_suspend(struct platform_device *dev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
{
- clk_disable(fclk);
- clk_disable(iclk);
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(hcd->irq);
+ else
+ disable_irq_wake(hcd->irq);
+
+ /*
+ * The integrated transceivers seem unable to notice disconnect,
+ * reconnect, or wakeup without the 48 MHz clock active. so for
+ * correctness, always discard connection state (using reset).
+ *
+ * REVISIT: some boards will be able to turn VBUS off...
+ */
+ if (at91_suspend_entering_slow_clock()) {
+ ohci_usb_reset (ohci);
+ clk_disable(fclk);
+ clk_disable(iclk);
+ clocked = 0;
+ }
return 0;
}
-static int ohci_hcd_at91_drv_resume(struct platform_device *dev)
+static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
{
- clk_enable(iclk);
- clk_enable(fclk);
+ if (!clocked) {
+ clk_enable(iclk);
+ clk_enable(fclk);
+ clocked = 1;
+ }
return 0;
}
@@ -275,15 +307,16 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *dev)
#define ohci_hcd_at91_drv_resume NULL
#endif
-MODULE_ALIAS("at91rm9200-ohci");
+MODULE_ALIAS("at91_ohci");
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {
- .name = "at91rm9200-ohci",
+ .name = "at91_ohci",
.owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index a1c8b3b2fcc..24e23c5783d 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -101,9 +101,11 @@ static void au1xxx_start_ohc(struct platform_device *dev)
#endif /* Au1200 */
+#ifndef CONFIG_SOC_AU1200
/* wait for reset complete (read register twice; see au1500 errata) */
while (au_readl(USB_HOST_CONFIG),
!(au_readl(USB_HOST_CONFIG) & USBH_ENABLE_RD))
+#endif
udelay(1000);
printk(KERN_DEBUG __FILE__
@@ -157,9 +159,9 @@ static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
/* Au1200 AB USB does not support coherent memory */
if (!(read_c0_prid() & 0xff)) {
pr_info("%s: this is chip revision AB !!\n",
- dev->dev.name);
+ dev->name);
pr_info("%s: update your board or re-configure the kernel\n",
- dev->dev.name);
+ dev->name);
return -ENODEV;
}
#endif
@@ -191,7 +193,7 @@ static int usb_ohci_au1xxx_probe(const struct hc_driver *driver,
au1xxx_start_ohc(dev);
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT | SA_SHIRQ);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED | IRQF_SHARED);
if (retval == 0)
return retval;
@@ -266,11 +268,8 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_au1xxx_start,
-#ifdef CONFIG_PM
- /* suspend: ohci_au1xxx_suspend, -- tbd */
- /* resume: ohci_au1xxx_resume, -- tbd */
-#endif /*CONFIG_PM*/
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -289,6 +288,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -336,6 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_au1xxx_driver = {
.probe = ohci_hcd_au1xxx_drv_probe,
.remove = ohci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_au1xxx_drv_suspend, */
/*.resume = ohci_hcd_au1xxx_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 7bfffcbbd22..8293c1d4be3 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -477,7 +477,7 @@ show_async (struct class_device *class_dev, char *buf)
unsigned long flags;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
/* display control and bulk lists together, for simplicity */
@@ -510,7 +510,7 @@ show_periodic (struct class_device *class_dev, char *buf)
seen_count = 0;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
next = buf;
size = PAGE_SIZE;
@@ -607,7 +607,7 @@ show_registers (struct class_device *class_dev, char *buf)
u32 rdata;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
regs = ohci->regs;
next = buf;
@@ -667,6 +667,11 @@ show_registers (struct class_device *class_dev, char *buf)
size -= temp;
next += temp;
+ temp = scnprintf (next, size, "hub poll timer %s\n",
+ ohci_to_hcd(ohci)->poll_rh ? "ON" : "off");
+ size -= temp;
+ next += temp;
+
/* roothub */
ohci_dump_roothub (ohci, 1, &next, &size);
@@ -680,10 +685,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ohci_hcd *ohci)
{
struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
+ int retval;
- class_device_create_file(cldev, &class_device_attr_async);
- class_device_create_file(cldev, &class_device_attr_periodic);
- class_device_create_file(cldev, &class_device_attr_registers);
+ retval = class_device_create_file(cldev, &class_device_attr_async);
+ retval = class_device_create_file(cldev, &class_device_attr_periodic);
+ retval = class_device_create_file(cldev, &class_device_attr_registers);
ohci_dbg (ohci, "created debug files\n");
}
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
new file mode 100644
index 00000000000..1bf5e7a4e73
--- /dev/null
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -0,0 +1,228 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ *
+ * Bus Glue for ep93xx.
+ *
+ * Written by Christopher Hoover <ch@hpl.hp.com>
+ * Based on fragments of previous driver by Russell King et al.
+ *
+ * Modified for LH7A404 from ohci-sa1111.c
+ * by Durgesh Pattamatta <pattamattad@sharpsec.com>
+ *
+ * Modified for pxa27x from ohci-lh7a404.c
+ * by Nick Bane <nick@cecomputing.co.uk> 26-8-2004
+ *
+ * Modified for ep93xx from ohci-pxa27x.c
+ * by Lennert Buytenhek <buytenh@wantstofly.org> 28-2-2006
+ * Based on an earlier driver by Ray Lehtiniemi
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/signal.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware.h>
+
+static struct clk *usb_host_clock;
+
+static void ep93xx_start_hc(struct device *dev)
+{
+ clk_enable(usb_host_clock);
+}
+
+static void ep93xx_stop_hc(struct device *dev)
+{
+ clk_disable(usb_host_clock);
+}
+
+static int usb_hcd_ep93xx_probe(const struct hc_driver *driver,
+ struct platform_device *pdev)
+{
+ int retval;
+ struct usb_hcd *hcd;
+
+ if (pdev->resource[1].flags != IORESOURCE_IRQ) {
+ pr_debug("resource[1] is not IORESOURCE_IRQ");
+ return -ENOMEM;
+ }
+
+ hcd = usb_create_hcd(driver, &pdev->dev, "ep93xx");
+ if (hcd == NULL)
+ return -ENOMEM;
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ usb_put_hcd(hcd);
+ retval = -EBUSY;
+ goto err1;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ pr_debug("ioremap failed");
+ retval = -ENOMEM;
+ goto err2;
+ }
+
+ usb_host_clock = clk_get(&pdev->dev, "usb_host");
+ ep93xx_start_hc(&pdev->dev);
+
+ ohci_hcd_init(hcd_to_ohci(hcd));
+
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+ if (retval == 0)
+ return retval;
+
+ ep93xx_stop_hc(&pdev->dev);
+ iounmap(hcd->regs);
+err2:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+ usb_put_hcd(hcd);
+
+ return retval;
+}
+
+static void usb_hcd_ep93xx_remove(struct usb_hcd *hcd,
+ struct platform_device *pdev)
+{
+ usb_remove_hcd(hcd);
+ ep93xx_stop_hc(&pdev->dev);
+ clk_put(usb_host_clock);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+}
+
+static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ err("can't start %s", hcd->self.bus_name);
+ ohci_stop(hcd);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct hc_driver ohci_ep93xx_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "EP93xx OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .start = ohci_ep93xx_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+ .get_frame_number = ohci_get_frame,
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+extern int usb_disabled(void);
+
+static int ohci_hcd_ep93xx_drv_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ ret = -ENODEV;
+ if (!usb_disabled())
+ ret = usb_hcd_ep93xx_probe(&ohci_ep93xx_hc_driver, pdev);
+
+ return ret;
+}
+
+static int ohci_hcd_ep93xx_drv_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_hcd_ep93xx_remove(hcd, pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ochi_hcd *ohci = hcd_to_ohci(hcd);
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ ep93xx_stop_hc(&pdev->dev);
+ hcd->state = HC_STATE_SUSPENDED;
+ pdev->dev.power.power_state = PMSG_SUSPEND;
+
+ return 0;
+}
+
+static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int status;
+
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+
+ ep93xx_start_hc(&pdev->dev);
+ pdev->dev.power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(hcd);
+
+ return 0;
+}
+#endif
+
+
+static struct platform_driver ohci_hcd_ep93xx_driver = {
+ .probe = ohci_hcd_ep93xx_drv_probe,
+ .remove = ohci_hcd_ep93xx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+#ifdef CONFIG_PM
+ .suspend = ohci_hcd_ep93xx_drv_suspend,
+ .resume = ohci_hcd_ep93xx_drv_resume,
+#endif
+ .driver = {
+ .name = "ep93xx-ohci",
+ },
+};
+
+static int __init ohci_hcd_ep93xx_init(void)
+{
+ return platform_driver_register(&ohci_hcd_ep93xx_driver);
+}
+
+static void __exit ohci_hcd_ep93xx_cleanup(void)
+{
+ platform_driver_unregister(&ohci_hcd_ep93xx_driver);
+}
+
+module_init(ohci_hcd_ep93xx_init);
+module_exit(ohci_hcd_ep93xx_cleanup);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 73f5a379d9b..d1d68c40225 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -74,7 +74,6 @@
* This file is licenced under the GPL.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
@@ -89,7 +88,7 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/usb.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/reboot.h>
@@ -102,7 +101,7 @@
#include "../core/hcd.h"
-#define DRIVER_VERSION "2005 April 22"
+#define DRIVER_VERSION "2006 August 04"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -111,9 +110,10 @@
#undef OHCI_VERBOSE_DEBUG /* not always helpful */
/* For initializing controller (mask in an HCFS mode too) */
-#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
+#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_INTR_INIT \
- (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
+ (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \
+ | OHCI_INTR_RD | OHCI_INTR_WDH)
#ifdef __hppa__
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
@@ -129,12 +129,13 @@
static const char hcd_name [] = "ohci_hcd";
+#define STATECHANGE_DELAY msecs_to_jiffies(300)
+
#include "ohci.h"
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
-static int ohci_reboot (struct notifier_block *, unsigned long , void *);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -417,21 +418,20 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
}
-/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
+/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
* other cases where the next software may expect clean state from the
* "firmware". this is bus-neutral, unlike shutdown() methods.
*/
-static int
-ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
+static void
+ohci_shutdown (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci;
- ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+ ohci = hcd_to_ohci (hcd);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
ohci_usb_reset (ohci);
/* flush the writes */
(void) ohci_readl (ohci, &ohci->regs->control);
- return 0;
}
/*-------------------------------------------------------------------------*
@@ -447,7 +447,6 @@ static int ohci_init (struct ohci_hcd *ohci)
disable (ohci);
ohci->regs = hcd->regs;
- ohci->next_statechange = jiffies;
/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
* was never needed for most non-PCI systems ... remove the code?
@@ -503,7 +502,6 @@ static int ohci_init (struct ohci_hcd *ohci)
if ((ret = ohci_mem_init (ohci)) < 0)
ohci_stop (hcd);
else {
- register_reboot_notifier (&ohci->reboot_notifier);
create_debug_files (ohci);
}
@@ -638,10 +636,14 @@ retry:
return -EOVERFLOW;
}
- /* start controller operations */
+ /* use rhsc irqs after khubd is fully initialized */
+ hcd->poll_rh = 1;
+ hcd->uses_new_polling = 1;
+
+ /* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC;
- ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
- ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
hcd->state = HC_STATE_RUNNING;
/* wake on ConnectStatusChange, matching external hubs */
@@ -649,7 +651,7 @@ retry:
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_INIT;
- ohci_writel (ohci, mask, &ohci->regs->intrstatus);
+ ohci_writel (ohci, ~0, &ohci->regs->intrstatus);
ohci_writel (ohci, mask, &ohci->regs->intrenable);
/* handle root hub init quirks ... */
@@ -673,6 +675,7 @@ retry:
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
+ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
spin_unlock_irq (&ohci->lock);
// POTPGT delay is bits 24-31, in 2 ms units.
@@ -710,7 +713,14 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
/* interrupt for some other device? */
} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
return IRQ_NOTMINE;
- }
+ }
+
+ if (ints & OHCI_INTR_RHSC) {
+ ohci_vdbg (ohci, "rhsc\n");
+ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
+ ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrstatus);
+ usb_hcd_poll_rh_status(hcd);
+ }
if (ints & OHCI_INTR_UE) {
disable (ohci);
@@ -724,13 +734,18 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (ints & OHCI_INTR_RD) {
ohci_vdbg (ohci, "resume detect\n");
ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
- if (hcd->state != HC_STATE_QUIESCING)
+ hcd->poll_rh = 1;
+ if (ohci->autostop) {
+ spin_lock (&ohci->lock);
+ ohci_rh_resume (ohci);
+ spin_unlock (&ohci->lock);
+ } else
usb_hcd_resume_root_hub(hcd);
}
if (ints & OHCI_INTR_WDH) {
if (HC_IS_RUNNING(hcd->state))
- ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
+ ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
spin_lock (&ohci->lock);
dl_done_list (ohci, ptregs);
spin_unlock (&ohci->lock);
@@ -776,9 +791,10 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_usb_reset (ohci);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
+ free_irq(hcd->irq, hcd);
+ hcd->irq = -1;
+
remove_debug_files (ohci);
- unregister_reboot_notifier (&ohci->reboot_notifier);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
dma_free_coherent (hcd->self.controller,
@@ -902,6 +918,10 @@ MODULE_LICENSE ("GPL");
#include "ohci-pxa27x.c"
#endif
+#ifdef CONFIG_ARCH_EP93XX
+#include "ohci-ep93xx.c"
+#endif
+
#ifdef CONFIG_SOC_AU1X00
#include "ohci-au1xxx.c"
#endif
@@ -910,19 +930,26 @@ MODULE_LICENSE ("GPL");
#include "ohci-ppc-soc.c"
#endif
-#ifdef CONFIG_ARCH_AT91RM9200
+#if defined(CONFIG_ARCH_AT91RM9200) || defined(CONFIG_ARCH_AT91SAM9261)
#include "ohci-at91.c"
#endif
+#ifdef CONFIG_ARCH_PNX4008
+#include "ohci-pnx4008.c"
+#endif
+
#if !(defined(CONFIG_PCI) \
|| defined(CONFIG_SA1111) \
|| defined(CONFIG_ARCH_S3C2410) \
|| defined(CONFIG_ARCH_OMAP) \
|| defined (CONFIG_ARCH_LH7A404) \
|| defined (CONFIG_PXA27x) \
+ || defined (CONFIG_ARCH_EP93XX) \
|| defined (CONFIG_SOC_AU1X00) \
|| defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
|| defined (CONFIG_ARCH_AT91RM9200) \
+ || defined (CONFIG_ARCH_AT91SAM9261) \
+ || defined (CONFIG_ARCH_PNX4008) \
)
#error "missing bus glue for ohci-hcd"
#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 0bb972b5833..ec75774abea 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,27 +36,25 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_PM
+/* hcd->hub_irq_enable() */
+static void ohci_rhsc_enable (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+}
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
-static int ohci_restart (struct ohci_hcd *ohci);
-static int ohci_bus_suspend (struct usb_hcd *hcd)
+static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
+__releases(ohci->lock)
+__acquires(ohci->lock)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int status = 0;
- unsigned long flags;
-
- spin_lock_irqsave (&ohci->lock, flags);
-
- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
- spin_unlock_irqrestore (&ohci->lock, flags);
- return -ESHUTDOWN;
- }
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
@@ -72,15 +70,16 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
ohci_dbg (ohci, "needs reinit!\n");
goto done;
case OHCI_USB_SUSPEND:
- ohci_dbg (ohci, "already suspended\n");
- goto done;
+ if (!ohci->autostop) {
+ ohci_dbg (ohci, "already suspended\n");
+ goto done;
+ }
}
- ohci_dbg (ohci, "suspend root hub\n");
+ ohci_dbg (ohci, "%s root hub\n",
+ autostop ? "auto-stop" : "suspend");
/* First stop any processing */
- if (ohci->hc_control & OHCI_SCHED_ENABLES) {
- int limit;
-
+ if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) {
ohci->hc_control &= ~OHCI_SCHED_ENABLES;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
@@ -90,27 +89,22 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
* then the last WDH could take 6+ msec
*/
ohci_dbg (ohci, "stopping schedules ...\n");
- limit = 2000;
- while (limit > 0) {
- udelay (250);
- limit =- 250;
- if (ohci_readl (ohci, &ohci->regs->intrstatus)
- & OHCI_INTR_SF)
- break;
- }
- dl_done_list (ohci, NULL);
- mdelay (7);
+ ohci->autostop = 0;
+ spin_unlock_irq (&ohci->lock);
+ msleep (8);
+ spin_lock_irq (&ohci->lock);
}
dl_done_list (ohci, NULL);
finish_unlinks (ohci, ohci_frame_no(ohci), NULL);
- ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
- &ohci->regs->intrstatus);
/* maybe resume can wake root hub */
- if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
+ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) ||
+ autostop)
ohci->hc_control |= OHCI_CTRL_RWE;
- else
+ else {
+ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
ohci->hc_control &= ~OHCI_CTRL_RWE;
+ }
/* Suspend hub ... this is the "global (to this bus) suspend" mode,
* which doesn't imply ports will first be individually suspended.
@@ -121,13 +115,12 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
/* no resumes until devices finish suspending */
- ohci->next_statechange = jiffies + msecs_to_jiffies (5);
+ if (!autostop) {
+ ohci->next_statechange = jiffies + msecs_to_jiffies (5);
+ ohci->autostop = 0;
+ }
done:
- /* external suspend vs self autosuspend ... same effect */
- if (status == 0)
- usb_hcd_suspend_root_hub(hcd);
- spin_unlock_irqrestore (&ohci->lock, flags);
return status;
}
@@ -139,25 +132,19 @@ static inline struct ed *find_head (struct ed *ed)
return ed;
}
+static int ohci_restart (struct ohci_hcd *ohci);
+
/* caller has locked the root hub */
-static int ohci_bus_resume (struct usb_hcd *hcd)
+static int ohci_rh_resume (struct ohci_hcd *ohci)
+__releases(ohci->lock)
+__acquires(ohci->lock)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct usb_hcd *hcd = ohci_to_hcd (ohci);
u32 temp, enables;
int status = -EINPROGRESS;
- unsigned long flags;
-
- if (time_before (jiffies, ohci->next_statechange))
- msleep(5);
-
- spin_lock_irqsave (&ohci->lock, flags);
-
- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
- spin_unlock_irqrestore (&ohci->lock, flags);
- return -ESHUTDOWN;
- }
-
+ int autostopped = ohci->autostop;
+ ohci->autostop = 0;
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
@@ -177,7 +164,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
ohci->hc_control |= OHCI_USB_RESUME;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
(void) ohci_readl (ohci, &ohci->regs->control);
- ohci_dbg (ohci, "resume root hub\n");
+ ohci_dbg (ohci, "%s root hub\n",
+ autostopped ? "auto-start" : "resume");
break;
case OHCI_USB_RESUME:
/* HCFS changes sometime after INTR_RD */
@@ -192,16 +180,24 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
ohci_dbg (ohci, "lost power\n");
status = -EBUSY;
}
- spin_unlock_irqrestore (&ohci->lock, flags);
+#ifdef CONFIG_PM
if (status == -EBUSY) {
- (void) ohci_init (ohci);
- return ohci_restart (ohci);
+ if (!autostopped) {
+ spin_unlock_irq (&ohci->lock);
+ (void) ohci_init (ohci);
+ status = ohci_restart (ohci);
+ spin_lock_irq (&ohci->lock);
+ }
+ return status;
}
+#endif
if (status != -EINPROGRESS)
return status;
+ if (autostopped)
+ goto skip_resume;
+ spin_unlock_irq (&ohci->lock);
temp = ohci->num_ports;
- enables = 0;
while (temp--) {
u32 stat = ohci_readl (ohci,
&ohci->regs->roothub.portstatus [temp]);
@@ -234,17 +230,21 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
/* Sometimes PCI D3 suspend trashes frame timings ... */
periodic_reinit (ohci);
+ /* the following code is executed with ohci->lock held and
+ * irqs disabled if and only if autostopped is true
+ */
+
+skip_resume:
/* interrupts might have been disabled */
ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable);
if (ohci->ed_rm_list)
ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable);
- ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
- &ohci->regs->intrstatus);
/* Then re-enable operations */
ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control);
(void) ohci_readl (ohci, &ohci->regs->control);
- msleep (3);
+ if (!autostopped)
+ msleep (3);
temp = ohci->hc_control;
temp &= OHCI_CTRL_RWC;
@@ -254,10 +254,14 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
/* TRSMRCY */
- msleep (10);
+ if (!autostopped) {
+ msleep (10);
+ spin_lock_irq (&ohci->lock);
+ }
+ /* now ohci->lock is always held and irqs are always disabled */
- /* keep it alive for ~5x suspend + resume costs */
- ohci->next_statechange = jiffies + msecs_to_jiffies (250);
+ /* keep it alive for more than ~5x suspend + resume costs */
+ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
/* maybe turn schedules back on */
enables = 0;
@@ -291,6 +295,45 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
return 0;
}
+#ifdef CONFIG_PM
+
+static int ohci_bus_suspend (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int rc;
+
+ spin_lock_irq (&ohci->lock);
+
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+ rc = -ESHUTDOWN;
+ else
+ rc = ohci_rh_suspend (ohci, 0);
+ spin_unlock_irq (&ohci->lock);
+ return rc;
+}
+
+static int ohci_bus_resume (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int rc;
+
+ if (time_before (jiffies, ohci->next_statechange))
+ msleep(5);
+
+ spin_lock_irq (&ohci->lock);
+
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+ rc = -ESHUTDOWN;
+ else
+ rc = ohci_rh_resume (ohci);
+ spin_unlock_irq (&ohci->lock);
+
+ /* poll until we know a device is connected or we autostop */
+ if (rc == 0)
+ usb_hcd_poll_rh_status(hcd);
+ return rc;
+}
+
#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -302,20 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int i, changed = 0, length = 1;
- int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
+ int any_connected = 0, rhsc_enabled = 1;
unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
- /* handle autosuspended root: finish resuming before
- * letting khubd or root hub timer see state changes.
- */
- if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
- || !HC_IS_RUNNING(hcd->state))) {
- can_suspend = 0;
- goto done;
- }
-
/* undocumented erratum seen on at least rev D */
if ((ohci->flags & OHCI_QUIRK_AMD756)
&& (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
@@ -339,6 +373,9 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ohci->num_ports; i++) {
u32 status = roothub_portstatus (ohci, i);
+ /* can't autostop if ports are connected */
+ any_connected |= (status & RH_PS_CCS);
+
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC)) {
changed = 1;
@@ -346,39 +383,72 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [0] |= 1 << (i + 1);
else
buf [1] |= 1 << (i - 7);
- continue;
}
-
- /* can suspend if no ports are enabled; or if all all
- * enabled ports are suspended AND remote wakeup is on.
- */
- if (!(status & RH_PS_CCS))
- continue;
- if ((status & RH_PS_PSS) && can_suspend)
- continue;
- can_suspend = 0;
}
-done:
- spin_unlock_irqrestore (&ohci->lock, flags);
-#ifdef CONFIG_PM
- /* save power by suspending idle root hubs;
- * INTR_RD wakes us when there's work
+ /* NOTE: vendors didn't always make the same implementation
+ * choices for RHSC. Sometimes it triggers on an edge (like
+ * setting and maybe clearing a port status change bit); and
+ * it's level-triggered on other silicon, active until khubd
+ * clears all active port status change bits. If it's still
+ * set (level-triggered) we must disable it and rely on
+ * polling until khubd re-enables it.
*/
- if (can_suspend
- && !changed
- && !ohci->ed_rm_list
- && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
- & ohci->hc_control)
- == OHCI_USB_OPER
- && time_after (jiffies, ohci->next_statechange)
- && usb_trylock_device (hcd->self.root_hub) == 0
- ) {
- ohci_vdbg (ohci, "autosuspend\n");
- (void) ohci_bus_suspend (hcd);
- usb_unlock_device (hcd->self.root_hub);
+ if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) {
+ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
+ (void) ohci_readl (ohci, &ohci->regs->intrdisable);
+ rhsc_enabled = 0;
}
-#endif
+ hcd->poll_rh = 1;
+
+ /* carry out appropriate state changes */
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+
+ case OHCI_USB_OPER:
+ /* keep on polling until we know a device is connected
+ * and RHSC is enabled */
+ if (!ohci->autostop) {
+ if (any_connected) {
+ if (rhsc_enabled)
+ hcd->poll_rh = 0;
+ } else {
+ ohci->autostop = 1;
+ ohci->next_statechange = jiffies + HZ;
+ }
+
+ /* if no devices have been attached for one second, autostop */
+ } else {
+ if (changed || any_connected) {
+ ohci->autostop = 0;
+ ohci->next_statechange = jiffies +
+ STATECHANGE_DELAY;
+ } else if (time_after_eq (jiffies,
+ ohci->next_statechange)
+ && !ohci->ed_rm_list
+ && !(ohci->hc_control &
+ OHCI_SCHED_ENABLES)) {
+ ohci_rh_suspend (ohci, 1);
+ }
+ }
+ break;
+
+ /* if there is a port change, autostart or ask to be resumed */
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ if (changed) {
+ if (ohci->autostop)
+ ohci_rh_resume (ohci);
+ else
+ usb_hcd_resume_root_hub (hcd);
+ } else {
+ /* everything is idle, no need for polling */
+ hcd->poll_rh = 0;
+ }
+ break;
+ }
+
+done:
+ spin_unlock_irqrestore (&ohci->lock, flags);
return changed ? length : 0;
}
@@ -550,9 +620,6 @@ static int ohci_hub_control (
break;
case USB_PORT_FEAT_SUSPEND:
temp = RH_PS_POCI;
- if ((ohci->hc_control & OHCI_CTRL_HCFS)
- != OHCI_USB_OPER)
- usb_hcd_resume_root_hub(hcd);
break;
case USB_PORT_FEAT_C_SUSPEND:
temp = RH_PS_PSSC;
@@ -581,14 +648,14 @@ static int ohci_hub_control (
break;
case GetHubStatus:
temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
- *(__le32 *) buf = cpu_to_le32 (temp);
+ put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
break;
case GetPortStatus:
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
temp = roothub_portstatus (ohci, wIndex);
- *(__le32 *) buf = cpu_to_le32 (temp);
+ put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
#ifndef OHCI_VERBOSE_DEBUG
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 0020ed7a39d..e121d97ed91 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -100,7 +100,7 @@ int usb_hcd_lh7a404_probe (const struct hc_driver *driver,
lh7a404_start_hc(dev);
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -173,11 +173,8 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_lh7a404_start,
-#ifdef CONFIG_PM
- /* suspend: ohci_lh7a404_suspend, -- tbd */
- /* resume: ohci_lh7a404_resume, -- tbd */
-#endif /*CONFIG_PM*/
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -196,6 +193,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -244,6 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_lh7a404_driver = {
.probe = ohci_hcd_lh7a404_drv_probe,
.remove = ohci_hcd_lh7a404_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_lh7a404_drv_suspend, */
/*.resume = ohci_hcd_lh7a404_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index bfbe328a478..d976614eebd 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
- ohci->reboot_notifier.notifier_call = ohci_reboot;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index ca19abe01c5..9c02177de50 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -4,7 +4,7 @@
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2005 David Brownell
* (C) Copyright 2002 Hewlett-Packard Company
- *
+ *
* OMAP Bus Glue
*
* Modified for OMAP by Tony Lindgren <tony@atomide.com>
@@ -14,7 +14,7 @@
* This file is licenced under the GPL.
*/
-#include <linux/signal.h> /* SA_INTERRUPT */
+#include <linux/signal.h> /* IRQF_DISABLED */
#include <linux/jiffies.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -66,15 +66,20 @@ extern int usb_disabled(void);
extern int ocpi_enable(void);
static struct clk *usb_host_ck;
+static struct clk *usb_dc_ck;
+static int host_enabled;
+static int host_initialized;
static void omap_ohci_clock_power(int on)
{
if (on) {
+ clk_enable(usb_dc_ck);
clk_enable(usb_host_ck);
/* guesstimate for T5 == 1x 32K clock + APLL lock time */
udelay(100);
} else {
clk_disable(usb_host_ck);
+ clk_disable(usb_dc_ck);
}
}
@@ -87,14 +92,14 @@ static int omap_ohci_transceiver_power(int on)
if (on) {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
- | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
+ | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (machine_is_omap_osk())
tps65010_set_gpio_out_value(GPIO1, LOW);
} else {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
- & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
+ & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (machine_is_omap_osk())
tps65010_set_gpio_out_value(GPIO1, HIGH);
@@ -103,6 +108,7 @@ static int omap_ohci_transceiver_power(int on)
return 0;
}
+#ifdef CONFIG_ARCH_OMAP15XX
/*
* OMAP-1510 specific Local Bus clock on/off
*/
@@ -121,8 +127,8 @@ static int omap_1510_local_bus_power(int on)
/*
* OMAP-1510 specific Local Bus initialization
* NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
- * See also arch/mach-omap/memory.h for __virt_to_dma() and
- * __dma_to_virt() which need to match with the physical
+ * See also arch/mach-omap/memory.h for __virt_to_dma() and
+ * __dma_to_virt() which need to match with the physical
* Local Bus address below.
*/
static int omap_1510_local_bus_init(void)
@@ -130,7 +136,7 @@ static int omap_1510_local_bus_init(void)
unsigned int tlb;
unsigned long lbaddr, physaddr;
- omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
+ omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
OMAP1510_LB_CLOCK_DIV);
/* Configure the Local Bus MMU table */
@@ -138,7 +144,7 @@ static int omap_1510_local_bus_init(void)
lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
physaddr = tlb * 0x00100000 + PHYS_OFFSET;
omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
- omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
+ omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
OMAP1510_LB_MMU_CAM_L);
omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
@@ -152,6 +158,10 @@ static int omap_1510_local_bus_init(void)
return 0;
}
+#else
+#define omap_1510_local_bus_power(x) {}
+#define omap_1510_local_bus_init() {}
+#endif
#ifdef CONFIG_USB_OTG
@@ -173,13 +183,14 @@ static void start_hnp(struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
-static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
+static int ohci_omap_init(struct usb_hcd *hcd)
{
- struct omap_usb_config *config = pdev->dev.platform_data;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct omap_usb_config *config = hcd->self.controller->platform_data;
int need_transceiver = (config->otg != 0);
int ret;
- dev_dbg(&pdev->dev, "starting USB Controller\n");
+ dev_dbg(hcd->self.controller, "starting USB Controller\n");
if (config->otg) {
ohci_to_hcd(ohci)->self.otg_port = config->otg;
@@ -200,7 +211,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
if (ohci->transceiver) {
int status = otg_set_host(ohci->transceiver,
&ohci_to_hcd(ohci)->self);
- dev_dbg(&pdev->dev, "init %s transceiver, status %d\n",
+ dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
ohci->transceiver->label, status);
if (status) {
if (ohci->transceiver)
@@ -208,7 +219,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
return status;
}
} else {
- dev_err(&pdev->dev, "can't find transceiver\n");
+ dev_err(hcd->self.controller, "can't find transceiver\n");
return -ENODEV;
}
}
@@ -247,6 +258,10 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
}
ohci_writel(ohci, rh, &ohci->regs->roothub.a);
distrust_firmware = 0;
+ } else if (machine_is_nokia770()) {
+ /* We require a self-powered hub, which should have
+ * plenty of power. */
+ ohci_to_hcd(ohci)->power_budget = 0;
}
/* FIXME khubd hub requests should manage power switching */
@@ -260,21 +275,15 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
return 0;
}
-static void omap_stop_hc(struct platform_device *pdev)
+static void ohci_omap_stop(struct usb_hcd *hcd)
{
- dev_dbg(&pdev->dev, "stopping USB Controller\n");
+ dev_dbg(hcd->self.controller, "stopping USB Controller\n");
omap_ohci_clock_power(0);
}
/*-------------------------------------------------------------------------*/
-void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
-
/**
* usb_hcd_omap_probe - initialize OMAP-based HCDs
* Context: !in_interrupt()
@@ -283,7 +292,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-int usb_hcd_omap_probe (const struct hc_driver *driver,
+static int usb_hcd_omap_probe (const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval, irq;
@@ -291,12 +300,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
struct ohci_hcd *ohci;
if (pdev->num_resources != 2) {
- printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
+ printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
pdev->num_resources);
return -ENODEV;
}
- if (pdev->resource[0].flags != IORESOURCE_MEM
+ if (pdev->resource[0].flags != IORESOURCE_MEM
|| pdev->resource[1].flags != IORESOURCE_IRQ) {
printk(KERN_ERR "hcd probe: invalid resource type\n");
return -ENODEV;
@@ -306,6 +315,17 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
+ if (!cpu_is_omap1510())
+ usb_dc_ck = clk_get(0, "usb_dc_ck");
+ else
+ usb_dc_ck = clk_get(0, "lb_ck");
+
+ if (IS_ERR(usb_dc_ck)) {
+ clk_put(usb_host_ck);
+ return PTR_ERR(usb_dc_ck);
+ }
+
+
hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
if (!hcd) {
retval = -ENOMEM;
@@ -325,25 +345,30 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
- retval = omap_start_hc(ohci, pdev);
- if (retval < 0)
- goto err2;
+ host_initialized = 0;
+ host_enabled = 1;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
retval = -ENXIO;
goto err2;
}
- retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
- if (retval == 0)
- return retval;
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+ if (retval)
+ goto err2;
+
+ host_initialized = 1;
+
+ if (!host_enabled)
+ omap_ohci_clock_power(0);
- omap_stop_hc(pdev);
+ return 0;
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
err0:
+ clk_put(usb_dc_ck);
clk_put(usb_host_ck);
return retval;
}
@@ -359,31 +384,41 @@ err0:
* Reverses the effect of usb_hcd_omap_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
- *
*/
-void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+static inline void
+usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
usb_remove_hcd(hcd);
+ if (ohci->transceiver) {
+ (void) otg_set_host(ohci->transceiver, 0);
+ put_device(ohci->transceiver->dev);
+ }
if (machine_is_omap_osk())
omap_free_gpio(9);
- omap_stop_hc(pdev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
+ clk_put(usb_dc_ck);
clk_put(usb_host_ck);
}
/*-------------------------------------------------------------------------*/
-static int __devinit
+static int
ohci_omap_start (struct usb_hcd *hcd)
{
struct omap_usb_config *config;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
+ if (!host_enabled)
+ return 0;
config = hcd->self.controller->platform_data;
- if (config->otg || config->rwc)
+ if (config->otg || config->rwc) {
+ ohci->hc_control = OHCI_CTRL_RWC;
writel(OHCI_CTRL_RWC, &ohci->regs->control);
+ }
if ((ret = ohci_run (ohci)) < 0) {
dev_err(hcd->self.controller, "can't start\n");
@@ -409,8 +444,10 @@ static const struct hc_driver ohci_omap_hc_driver = {
/*
* basic lifecycle operations
*/
+ .reset = ohci_omap_init,
.start = ohci_omap_start,
- .stop = ohci_stop,
+ .stop = ohci_omap_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -429,6 +466,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -446,13 +484,8 @@ static int ohci_hcd_omap_drv_probe(struct platform_device *dev)
static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
usb_hcd_omap_remove(hcd, dev);
- if (ohci->transceiver) {
- (void) otg_set_host(ohci->transceiver, 0);
- put_device(ohci->transceiver->dev);
- }
platform_set_drvdata(dev, NULL);
return 0;
@@ -472,7 +505,7 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
- dev->power.power_state = PMSG_SUSPEND;
+ dev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
@@ -485,8 +518,8 @@ static int ohci_omap_resume(struct platform_device *dev)
ohci->next_statechange = jiffies;
omap_ohci_clock_power(1);
- dev->power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(dev_get_drvdata(dev));
+ dev->dev.power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(platform_get_drvdata(dev));
return 0;
}
@@ -500,6 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_omap_driver = {
.probe = ohci_hcd_omap_drv_probe,
.remove = ohci_hcd_omap_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_omap_suspend,
.resume = ohci_omap_resume,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index b268537e389..87441855278 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -73,13 +73,14 @@ ohci_pci_start (struct usb_hcd *hcd)
else if (pdev->vendor == PCI_VENDOR_ID_NS) {
struct pci_dev *b;
- b = pci_find_slot (pdev->bus->number,
+ b = pci_get_slot (pdev->bus,
PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) {
ohci->flags |= OHCI_QUIRK_SUPERIO;
ohci_dbg (ohci, "Using NSC SuperIO setup\n");
}
+ pci_dev_put(b);
}
/* Check for Compaq's ZFMicro chipset, which needs short
@@ -135,6 +136,11 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
}
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
+
+ /* make sure snapshot being resumed re-enumerates everything */
+ if (message.event == PM_EVENT_PRETHAW)
+ ohci_usb_reset(ohci);
+
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
bail:
spin_unlock_irqrestore (&ohci->lock, flags);
@@ -171,11 +177,14 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.reset = ohci_pci_reset,
.start = ohci_pci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
#ifdef CONFIG_PM
+ /* these suspend/resume entries are for upstream PCI glue ONLY */
.suspend = ohci_pci_suspend,
.resume = ohci_pci_resume,
#endif
- .stop = ohci_stop,
/*
* managing i/o requests and associated device resources
@@ -194,6 +203,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -224,6 +234,8 @@ static struct pci_driver ohci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
+
+ .shutdown = usb_hcd_pci_shutdown,
};
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
new file mode 100644
index 00000000000..82cb22f002e
--- /dev/null
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -0,0 +1,476 @@
+/*
+ * drivers/usb/host/ohci-pnx4008.c
+ *
+ * driver for Philips PNX4008 USB Host
+ *
+ * Authors: Dmitry Chigirev <source@mvista.com>
+ * Vitaly Wool <vitalywool@gmail.com>
+ *
+ * register initialization is based on code examples provided by Philips
+ * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
+ *
+ * NOTE: This driver does not have suspend/resume functionality
+ * This driver is intended for engineering development purposes only
+ *
+ * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/platform.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/gpio.h>
+
+#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
+
+/* USB_CTRL bit defines */
+#define USB_SLAVE_HCLK_EN (1 << 24)
+#define USB_HOST_NEED_CLK_EN (1 << 21)
+
+#define USB_OTG_CLK_CTRL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4)
+#define USB_OTG_CLK_STAT IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8)
+
+/* USB_OTG_CLK_CTRL bit defines */
+#define AHB_M_CLOCK_ON (1 << 4)
+#define OTG_CLOCK_ON (1 << 3)
+#define I2C_CLOCK_ON (1 << 2)
+#define DEV_CLOCK_ON (1 << 1)
+#define HOST_CLOCK_ON (1 << 0)
+
+#define USB_OTG_STAT_CONTROL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110)
+
+/* USB_OTG_STAT_CONTROL bit defines */
+#define TRANSPARENT_I2C_EN (1 << 7)
+#define HOST_EN (1 << 0)
+
+/* ISP1301 USB transceiver I2C registers */
+#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
+
+#define MC1_SPEED_REG (1 << 0)
+#define MC1_SUSPEND_REG (1 << 1)
+#define MC1_DAT_SE0 (1 << 2)
+#define MC1_TRANSPARENT (1 << 3)
+#define MC1_BDIS_ACON_EN (1 << 4)
+#define MC1_OE_INT_EN (1 << 5)
+#define MC1_UART_EN (1 << 6)
+#define MC1_MASK 0x7f
+
+#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
+
+#define MC2_GLOBAL_PWR_DN (1 << 0)
+#define MC2_SPD_SUSP_CTRL (1 << 1)
+#define MC2_BI_DI (1 << 2)
+#define MC2_TRANSP_BDIR0 (1 << 3)
+#define MC2_TRANSP_BDIR1 (1 << 4)
+#define MC2_AUDIO_EN (1 << 5)
+#define MC2_PSW_EN (1 << 6)
+#define MC2_EN2V7 (1 << 7)
+
+#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
+# define OTG1_DP_PULLUP (1 << 0)
+# define OTG1_DM_PULLUP (1 << 1)
+# define OTG1_DP_PULLDOWN (1 << 2)
+# define OTG1_DM_PULLDOWN (1 << 3)
+# define OTG1_ID_PULLDOWN (1 << 4)
+# define OTG1_VBUS_DRV (1 << 5)
+# define OTG1_VBUS_DISCHRG (1 << 6)
+# define OTG1_VBUS_CHRG (1 << 7)
+#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */
+# define OTG_B_SESS_END (1 << 6)
+# define OTG_B_SESS_VLD (1 << 7)
+
+#define ISP1301_I2C_ADDR 0x2C
+
+#define ISP1301_I2C_MODE_CONTROL_1 0x4
+#define ISP1301_I2C_MODE_CONTROL_2 0x12
+#define ISP1301_I2C_OTG_CONTROL_1 0x6
+#define ISP1301_I2C_OTG_CONTROL_2 0x10
+#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
+#define ISP1301_I2C_INTERRUPT_LATCH 0xA
+#define ISP1301_I2C_INTERRUPT_FALLING 0xC
+#define ISP1301_I2C_INTERRUPT_RISING 0xE
+#define ISP1301_I2C_REG_CLEAR_ADDR 1
+
+struct i2c_driver isp1301_driver;
+struct i2c_client *isp1301_i2c_client;
+
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
+
+static struct clk *usb_clk;
+
+static int isp1301_probe(struct i2c_adapter *adap);
+static int isp1301_detach(struct i2c_client *client);
+static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+ void *arg);
+
+static unsigned short normal_i2c[] =
+ { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
+static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data = {
+ .normal_i2c = normal_i2c,
+ .probe = dummy_i2c_addrlist,
+ .ignore = dummy_i2c_addrlist,
+};
+
+struct i2c_driver isp1301_driver = {
+ .id = I2C_DRIVERID_I2CDEV, /* Fake Id */
+ .class = I2C_CLASS_HWMON,
+ .attach_adapter = isp1301_probe,
+ .detach_client = isp1301_detach,
+ .command = isp1301_command
+};
+
+static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct i2c_client *c;
+
+ c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL);
+
+ if (!c)
+ return -ENOMEM;
+
+ strcpy(c->name, "isp1301");
+ c->flags = 0;
+ c->addr = addr;
+ c->adapter = adap;
+ c->driver = &isp1301_driver;
+
+ isp1301_i2c_client = c;
+
+ return i2c_attach_client(c);
+}
+
+static int isp1301_probe(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, isp1301_attach);
+}
+
+static int isp1301_detach(struct i2c_client *client)
+{
+ i2c_detach_client(client);
+ kfree(isp1301_i2c_client);
+ return 0;
+}
+
+/* No commands defined */
+static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ return 0;
+}
+
+static void i2c_write(u8 buf, u8 subaddr)
+{
+ char tmpbuf[2];
+
+ tmpbuf[0] = subaddr; /*register number */
+ tmpbuf[1] = buf; /*register data */
+ i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2);
+}
+
+static void isp1301_configure(void)
+{
+ /* PNX4008 only supports DAT_SE0 USB mode */
+ /* PNX4008 R2A requires setting the MAX603 to output 3.6V */
+ /* Power up externel charge-pump */
+
+ i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1);
+ i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG),
+ ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL,
+ ISP1301_I2C_MODE_CONTROL_2);
+ i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL),
+ ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN,
+ ISP1301_I2C_OTG_CONTROL_1);
+ i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN),
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(0xFF,
+ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(0xFF,
+ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(0xFF,
+ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
+
+}
+
+static inline void isp1301_vbus_on(void)
+{
+ i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1);
+}
+
+static inline void isp1301_vbus_off(void)
+{
+ i2c_write(OTG1_VBUS_DRV,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+}
+
+static void pnx4008_start_hc(void)
+{
+ unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
+ __raw_writel(tmp, USB_OTG_STAT_CONTROL);
+ isp1301_vbus_on();
+}
+
+static void pnx4008_stop_hc(void)
+{
+ unsigned long tmp;
+ isp1301_vbus_off();
+ tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
+ __raw_writel(tmp, USB_OTG_STAT_CONTROL);
+}
+
+static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ dev_err(hcd->self.controller, "can't start\n");
+ ohci_stop(hcd);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct hc_driver ohci_pnx4008_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "pnx4008 OHCI",
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_pnx4008_start,
+ .stop = ohci_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+
+ .start_port_reset = ohci_start_port_reset,
+};
+
+#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
+
+static void pnx4008_set_usb_bits(void)
+{
+ start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
+ start_int_ack(SE_USB_OTG_ATX_INT_N);
+ start_int_umask(SE_USB_OTG_ATX_INT_N);
+
+ start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
+ start_int_ack(SE_USB_OTG_TIMER_INT);
+ start_int_umask(SE_USB_OTG_TIMER_INT);
+
+ start_int_set_rising_edge(SE_USB_I2C_INT);
+ start_int_ack(SE_USB_I2C_INT);
+ start_int_umask(SE_USB_I2C_INT);
+
+ start_int_set_rising_edge(SE_USB_INT);
+ start_int_ack(SE_USB_INT);
+ start_int_umask(SE_USB_INT);
+
+ start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
+ start_int_ack(SE_USB_NEED_CLK_INT);
+ start_int_umask(SE_USB_NEED_CLK_INT);
+
+ start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
+ start_int_ack(SE_USB_AHB_NEED_CLK_INT);
+ start_int_umask(SE_USB_AHB_NEED_CLK_INT);
+}
+
+static void pnx4008_unset_usb_bits(void)
+{
+ start_int_mask(SE_USB_OTG_ATX_INT_N);
+ start_int_mask(SE_USB_OTG_TIMER_INT);
+ start_int_mask(SE_USB_I2C_INT);
+ start_int_mask(SE_USB_INT);
+ start_int_mask(SE_USB_NEED_CLK_INT);
+ start_int_mask(SE_USB_AHB_NEED_CLK_INT);
+}
+
+static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = 0;
+ struct ohci_hcd *ohci;
+ const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
+
+ int ret = 0, irq;
+
+ dev_dbg(&pdev->dev, "%s: " DRIVER_INFO " (pnx4008)\n", hcd_name);
+ if (usb_disabled()) {
+ err("USB is disabled");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (pdev->num_resources != 2
+ || pdev->resource[0].flags != IORESOURCE_MEM
+ || pdev->resource[1].flags != IORESOURCE_IRQ) {
+ err("Invalid resource configuration");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Enable AHB slave USB clock, needed for further USB clock control */
+ __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+
+ ret = i2c_add_driver(&isp1301_driver);
+ if (ret < 0) {
+ err("failed to connect I2C to ISP1301 USB Transceiver");
+ goto out;
+ }
+
+ isp1301_configure();
+
+ /* Enable USB PLL */
+ usb_clk = clk_get(&pdev->dev, "ck_pll5");
+ if (IS_ERR(usb_clk)) {
+ err("failed to acquire USB PLL");
+ ret = PTR_ERR(usb_clk);
+ goto out1;
+ }
+
+ ret = clk_enable(usb_clk);
+ if (ret < 0) {
+ err("failed to start USB PLL");
+ goto out2;
+ }
+
+ ret = clk_set_rate(usb_clk, 48000);
+ if (ret < 0) {
+ err("failed to set USB clock rate");
+ goto out3;
+ }
+
+ __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
+
+ /* Set to enable all needed USB clocks */
+ __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
+
+ while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
+ USB_CLOCK_MASK) ;
+
+ hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ err("Failed to allocate HC buffer");
+ ret = -ENOMEM;
+ goto out3;
+ }
+
+ /* Set all USB bits in the Start Enable register */
+ pnx4008_set_usb_bits();
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ ret = -ENOMEM;
+ goto out4;
+ }
+ hcd->regs = (void __iomem *)pdev->resource[0].start;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENXIO;
+ goto out4;
+ }
+
+ hcd->self.hcpriv = (void *)hcd;
+
+ pnx4008_start_hc();
+ platform_set_drvdata(pdev, hcd);
+ ohci = hcd_to_ohci(hcd);
+ ohci_hcd_init(ohci);
+
+ dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
+ ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ if (ret == 0)
+ return ret;
+
+ pnx4008_stop_hc();
+out4:
+ pnx4008_unset_usb_bits();
+ usb_put_hcd(hcd);
+out3:
+ clk_disable(usb_clk);
+out2:
+ clk_put(usb_clk);
+out1:
+ i2c_del_driver(&isp1301_driver);
+out:
+ return ret;
+}
+
+static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ pnx4008_stop_hc();
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ pnx4008_unset_usb_bits();
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+ i2c_del_driver(&isp1301_driver);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver usb_hcd_pnx4008_driver = {
+ .driver = {
+ .name = "usb-ohci",
+ },
+ .probe = usb_hcd_pnx4008_probe,
+ .remove = usb_hcd_pnx4008_remove,
+};
+
+static int __init usb_hcd_pnx4008_init(void)
+{
+ return platform_driver_register(&usb_hcd_pnx4008_driver);
+}
+
+static void __exit usb_hcd_pnx4008_cleanup(void)
+{
+ return platform_driver_unregister(&usb_hcd_pnx4008_driver);
+}
+
+module_init(usb_hcd_pnx4008_init);
+module_exit(usb_hcd_pnx4008_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index b2a8dfa4887..d9d1ae236bd 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -75,7 +75,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
ohci->flags |= OHCI_BIG_ENDIAN;
ohci_hcd_init(ohci);
- retval = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -148,6 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.start = ohci_ppc_soc_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -166,6 +167,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -195,6 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ppc_soc_driver = {
.probe = ohci_hcd_ppc_soc_drv_probe,
.remove = ohci_hcd_ppc_soc_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index fafe7c1265b..e176b04d7ae 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -190,7 +190,7 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -270,6 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.start = ohci_pxa27x_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -288,6 +289,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -357,6 +359,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_drv_probe,
.remove = ohci_hcd_pxa27x_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_pxa27x_drv_suspend,
.resume = ohci_hcd_pxa27x_drv_resume,
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 1da5de573a6..59e436424d4 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -370,7 +370,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
goto err_mem;
}
- usb_clk = clk_get(&dev->dev, "upll");
+ usb_clk = clk_get(&dev->dev, "usb-bus-host");
if (IS_ERR(usb_clk)) {
dev_err(&dev->dev, "cannot get usb-host clock\n");
retval = -ENOENT;
@@ -388,7 +388,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
if (retval != 0)
goto err_ioremap;
@@ -447,6 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.start = ohci_s3c2410_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -465,6 +466,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -490,6 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index fb3221ebbb2..71371de32ad 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -143,7 +143,7 @@ int usb_hcd_sa1111_probe (const struct hc_driver *driver,
sa1111_start_hc(dev);
ohci_hcd_init(hcd_to_ohci(hcd));
- retval = usb_add_hcd(hcd, dev->irq[1], SA_INTERRUPT);
+ retval = usb_add_hcd(hcd, dev->irq[1], IRQF_DISABLED);
if (retval == 0)
return retval;
@@ -212,10 +212,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_sa1111_start,
-#ifdef CONFIG_PM
- /* suspend: ohci_sa1111_suspend, -- tbd */
- /* resume: ohci_sa1111_resume, -- tbd */
-#endif
.stop = ohci_stop,
/*
@@ -235,6 +231,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index caacf14371f..a2f42a2f47c 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -159,7 +159,7 @@ static const int cc_to_error [16] = {
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
+ /* DevNotResp */ -ETIME,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
@@ -388,8 +388,7 @@ struct ohci_hcd {
u32 hc_control; /* copy of hc control reg */
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */
-
- struct notifier_block reboot_notifier;
+ unsigned autostop:1; /* rh auto stopping/stopped */
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 1045f846fbe..20861650905 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -8,7 +8,6 @@
* (and others)
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -168,8 +167,6 @@ static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx)
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
{
void __iomem *base;
- int wait_time;
- u32 control;
if (!mmio_resource_enabled(pdev, 0))
return;
@@ -180,9 +177,10 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
#ifndef __hppa__
- control = readl(base + OHCI_CONTROL);
+{
+ u32 control = readl(base + OHCI_CONTROL);
if (control & OHCI_CTRL_IR) {
- wait_time = 500; /* arbitrary; 5 seconds */
+ int wait_time = 500; /* arbitrary; 5 seconds */
writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
writel(OHCI_OCR, base + OHCI_CMDSTATUS);
while (wait_time > 0 &&
@@ -199,6 +197,7 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
/* reset controller, preserving RWC */
writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL);
}
+}
#endif
/*
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 6b4bc3f2bd8..3a586aab393 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -31,7 +31,6 @@
#undef VERBOSE
#undef PACKET_TRACE
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -598,7 +597,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
/* error? retry, until "3 strikes" */
} else if (++ep->error_count >= 3) {
if (status & SL11H_STATMASK_TMOUT)
- urbstat = -ETIMEDOUT;
+ urbstat = -ETIME;
else if (status & SL11H_STATMASK_OVF)
urbstat = -EOVERFLOW;
else
@@ -1518,7 +1517,7 @@ static int proc_sl811h_open(struct inode *inode, struct file *file)
return single_open(file, proc_sl811h_show, PDE(inode)->data);
}
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
.open = proc_sl811h_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -1684,9 +1683,13 @@ sl811h_probe(struct platform_device *dev)
if (!addr || !data)
return -ENODEV;
ioaddr = 1;
-
- addr_reg = (void __iomem *) addr->start;
- data_reg = (void __iomem *) data->start;
+ /*
+ * NOTE: 64-bit resource->start is getting truncated
+ * to avoid compiler warning, assuming that ->start
+ * is always 32-bit for this case
+ */
+ addr_reg = (void __iomem *) (unsigned long) addr->start;
+ data_reg = (void __iomem *) (unsigned long) data->start;
} else {
addr_reg = ioremap(addr->start, 1);
if (addr_reg == NULL) {
@@ -1746,7 +1749,7 @@ sl811h_probe(struct platform_device *dev)
* was on a system with single edge triggering, so most sorts of
* triggering arrangement should work.
*/
- retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ);
+ retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
if (retval != 0)
goto err6;
@@ -1780,10 +1783,15 @@ sl811h_suspend(struct platform_device *dev, pm_message_t state)
struct sl811 *sl811 = hcd_to_sl811(hcd);
int retval = 0;
- if (state.event == PM_EVENT_FREEZE)
+ switch (state.event) {
+ case PM_EVENT_FREEZE:
retval = sl811h_bus_suspend(hcd);
- else if (state.event == PM_EVENT_SUSPEND)
+ break;
+ case PM_EVENT_SUSPEND:
+ case PM_EVENT_PRETHAW: /* explicitly discard hw state */
port_power(sl811, 0);
+ break;
+ }
if (retval == 0)
dev->dev.power.power_state = state;
return retval;
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
new file mode 100644
index 00000000000..cb2e2a604d1
--- /dev/null
+++ b/drivers/usb/host/u132-hcd.c
@@ -0,0 +1,3295 @@
+/*
+* Host Controller Driver for the Elan Digital Systems U132 adapter
+*
+* Copyright(C) 2006 Elan Digital Systems Limited
+* http://www.elandigitalsystems.com
+*
+* Author and Maintainer - Tony Olech - Elan Digital Systems
+* tony.olech@elandigitalsystems.com
+*
+* This program is free software;you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation, version 2.
+*
+*
+* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
+* based on various USB host drivers in the 2.6.15 linux kernel
+* with constant reference to the 3rd Edition of Linux Device Drivers
+* published by O'Reilly
+*
+* The U132 adapter is a USB to CardBus adapter specifically designed
+* for PC cards that contain an OHCI host controller. Typical PC cards
+* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
+*
+* The U132 adapter will *NOT *work with PC cards that do not contain
+* an OHCI controller. A simple way to test whether a PC card has an
+* OHCI controller as an interface is to insert the PC card directly
+* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
+* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
+* then there is a good chance that the U132 adapter will support the
+* PC card.(you also need the specific client driver for the PC card)
+*
+* Please inform the Author and Maintainer about any PC cards that
+* contain OHCI Host Controller and work when directly connected to
+* an embedded CardBus slot but do not work when they are connected
+* via an ELAN U132 adapter.
+*
+*/
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/pci_ids.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include "../core/hcd.h"
+#include "ohci.h"
+#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
+#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
+ OHCI_INTR_WDH)
+MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
+MODULE_DESCRIPTION("U132 USB Host Controller Driver");
+MODULE_LICENSE("GPL");
+#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
+INT_MODULE_PARM(testing, 0);
+/* Some boards misreport power switching/overcurrent*/
+static int distrust_firmware = 1;
+module_param(distrust_firmware, bool, 0);
+MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
+ "t setup");
+DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
+/*
+* u132_module_lock exists to protect access to global variables
+*
+*/
+static struct semaphore u132_module_lock;
+static int u132_exiting = 0;
+static int u132_instances = 0;
+static struct list_head u132_static_list;
+/*
+* end of the global variables protected by u132_module_lock
+*/
+static struct workqueue_struct *workqueue;
+#define MAX_U132_PORTS 7
+#define MAX_U132_ADDRS 128
+#define MAX_U132_UDEVS 4
+#define MAX_U132_ENDPS 100
+#define MAX_U132_RINGS 4
+static const char *cc_to_text[16] = {
+ "No Error ",
+ "CRC Error ",
+ "Bit Stuff ",
+ "Data Togg ",
+ "Stall ",
+ "DevNotResp ",
+ "PIDCheck ",
+ "UnExpPID ",
+ "DataOver ",
+ "DataUnder ",
+ "(for hw) ",
+ "(for hw) ",
+ "BufferOver ",
+ "BuffUnder ",
+ "(for HCD) ",
+ "(for HCD) "
+};
+struct u132_port {
+ struct u132 *u132;
+ int reset;
+ int enable;
+ int power;
+ int Status;
+};
+struct u132_addr {
+ u8 address;
+};
+struct u132_udev {
+ struct kref kref;
+ struct usb_device *usb_device;
+ u8 enumeration;
+ u8 udev_number;
+ u8 usb_addr;
+ u8 portnumber;
+ u8 endp_number_in[16];
+ u8 endp_number_out[16];
+};
+#define ENDP_QUEUE_SHIFT 3
+#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
+#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
+struct u132_urbq {
+ struct list_head urb_more;
+ struct urb *urb;
+};
+struct u132_spin {
+ spinlock_t slock;
+};
+struct u132_endp {
+ struct kref kref;
+ u8 udev_number;
+ u8 endp_number;
+ u8 usb_addr;
+ u8 usb_endp;
+ struct u132 *u132;
+ struct list_head endp_ring;
+ struct u132_ring *ring;
+ unsigned toggle_bits:2;
+ unsigned active:1;
+ unsigned delayed:1;
+ unsigned input:1;
+ unsigned output:1;
+ unsigned pipetype:2;
+ unsigned dequeueing:1;
+ unsigned edset_flush:1;
+ unsigned spare_bits:14;
+ unsigned long jiffies;
+ struct usb_host_endpoint *hep;
+ struct u132_spin queue_lock;
+ u16 queue_size;
+ u16 queue_last;
+ u16 queue_next;
+ struct urb *urb_list[ENDP_QUEUE_SIZE];
+ struct list_head urb_more;
+ struct work_struct scheduler;
+};
+struct u132_ring {
+ unsigned in_use:1;
+ unsigned length:7;
+ u8 number;
+ struct u132 *u132;
+ struct u132_endp *curr_endp;
+ struct work_struct scheduler;
+};
+#define OHCI_QUIRK_AMD756 0x01
+#define OHCI_QUIRK_SUPERIO 0x02
+#define OHCI_QUIRK_INITRESET 0x04
+#define OHCI_BIG_ENDIAN 0x08
+#define OHCI_QUIRK_ZFMICRO 0x10
+struct u132 {
+ struct kref kref;
+ struct list_head u132_list;
+ struct semaphore sw_lock;
+ struct semaphore scheduler_lock;
+ struct u132_platform_data *board;
+ struct platform_device *platform_dev;
+ struct u132_ring ring[MAX_U132_RINGS];
+ int sequence_num;
+ int going;
+ int power;
+ int reset;
+ int num_ports;
+ u32 hc_control;
+ u32 hc_fminterval;
+ u32 hc_roothub_status;
+ u32 hc_roothub_a;
+ u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
+ int flags;
+ unsigned long next_statechange;
+ struct work_struct monitor;
+ int num_endpoints;
+ struct u132_addr addr[MAX_U132_ADDRS];
+ struct u132_udev udev[MAX_U132_UDEVS];
+ struct u132_port port[MAX_U132_PORTS];
+ struct u132_endp *endp[MAX_U132_ENDPS];
+};
+int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data);
+int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs,
+ u8 width, u32 *data);
+int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs,
+ u8 width, u32 data);
+/*
+* these can not be inlines because we need the structure offset!!
+* Does anyone have a better way?????
+*/
+#define u132_read_pcimem(u132, member, data) \
+ usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0, data);
+#define u132_write_pcimem(u132, member, data) \
+ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0, data);
+#define u132_write_pcimem_byte(u132, member, data) \
+ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0x0e, data);
+static inline struct u132 *udev_to_u132(struct u132_udev *udev)
+{
+ u8 udev_number = udev->udev_number;
+ return container_of(udev, struct u132, udev[udev_number]);
+}
+
+static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
+{
+ return (struct u132 *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
+{
+ return container_of((void *)u132, struct usb_hcd, hcd_priv);
+}
+
+static inline void u132_disable(struct u132 *u132)
+{
+ u132_to_hcd(u132)->state = HC_STATE_HALT;
+}
+
+
+#define kref_to_u132(d) container_of(d, struct u132, kref)
+#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref)
+#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref)
+#include "../misc/usb_u132.h"
+static const char hcd_name[] = "u132_hcd";
+#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \
+ USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
+ USB_PORT_STAT_C_RESET) << 16)
+static void u132_hcd_delete(struct kref *kref)
+{
+ struct u132 *u132 = kref_to_u132(kref);
+ struct platform_device *pdev = u132->platform_dev;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ u132->going += 1;
+ down(&u132_module_lock);
+ list_del_init(&u132->u132_list);
+ u132_instances -= 1;
+ up(&u132_module_lock);
+ dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
+ "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
+ usb_put_hcd(hcd);
+}
+
+static inline void u132_u132_put_kref(struct u132 *u132)
+{
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static inline void u132_u132_init_kref(struct u132 *u132)
+{
+ kref_init(&u132->kref);
+}
+
+static void u132_udev_delete(struct kref *kref)
+{
+ struct u132_udev *udev = kref_to_u132_udev(kref);
+ udev->udev_number = 0;
+ udev->usb_device = NULL;
+ udev->usb_addr = 0;
+ udev->enumeration = 0;
+}
+
+static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
+{
+ kref_put(&udev->kref, u132_udev_delete);
+}
+
+static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
+{
+ kref_get(&udev->kref);
+}
+
+static inline void u132_udev_init_kref(struct u132 *u132,
+ struct u132_udev *udev)
+{
+ kref_init(&udev->kref);
+}
+
+static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
+{
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
+ unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &ring->scheduler, delta))
+ return;
+ } else if (queue_work(workqueue, &ring->scheduler))
+ return;
+ kref_put(&u132->kref, u132_hcd_delete);
+ return;
+}
+
+static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
+ unsigned int delta)
+{
+ kref_get(&u132->kref);
+ u132_ring_requeue_work(u132, ring, delta);
+ return;
+}
+
+static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
+{
+ if (cancel_delayed_work(&ring->scheduler)) {
+ kref_put(&u132->kref, u132_hcd_delete);
+ }
+}
+
+static void u132_endp_delete(struct kref *kref)
+{
+ struct u132_endp *endp = kref_to_u132_endp(kref);
+ struct u132 *u132 = endp->u132;
+ u8 usb_addr = endp->usb_addr;
+ u8 usb_endp = endp->usb_endp;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ u8 endp_number = endp->endp_number;
+ struct usb_host_endpoint *hep = endp->hep;
+ struct u132_ring *ring = endp->ring;
+ struct list_head *head = &endp->endp_ring;
+ ring->length -= 1;
+ if (endp == ring->curr_endp) {
+ if (list_empty(head)) {
+ ring->curr_endp = NULL;
+ list_del(head);
+ } else {
+ struct u132_endp *next_endp = list_entry(head->next,
+ struct u132_endp, endp_ring);
+ ring->curr_endp = next_endp;
+ list_del(head);
+ }} else
+ list_del(head);
+ if (endp->input) {
+ udev->endp_number_in[usb_endp] = 0;
+ u132_udev_put_kref(u132, udev);
+ }
+ if (endp->output) {
+ udev->endp_number_out[usb_endp] = 0;
+ u132_udev_put_kref(u132, udev);
+ }
+ u132->endp[endp_number - 1] = NULL;
+ hep->hcpriv = NULL;
+ kfree(endp);
+ u132_u132_put_kref(u132);
+}
+
+static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
+{
+ kref_put(&endp->kref, u132_endp_delete);
+}
+
+static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
+{
+ kref_get(&endp->kref);
+}
+
+static inline void u132_endp_init_kref(struct u132 *u132,
+ struct u132_endp *endp)
+{
+ kref_init(&endp->kref);
+ kref_get(&u132->kref);
+}
+
+static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
+ unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &endp->scheduler, delta))
+ kref_get(&endp->kref);
+ } else if (queue_work(workqueue, &endp->scheduler))
+ kref_get(&endp->kref);
+ return;
+}
+
+static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
+{
+ if (cancel_delayed_work(&endp->scheduler))
+ kref_put(&endp->kref, u132_endp_delete);
+}
+
+static inline void u132_monitor_put_kref(struct u132 *u132)
+{
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &u132->monitor, delta)) {
+ kref_get(&u132->kref);
+ }
+ } else if (queue_work(workqueue, &u132->monitor))
+ kref_get(&u132->kref);
+ return;
+}
+
+static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &u132->monitor, delta))
+ return;
+ } else if (queue_work(workqueue, &u132->monitor))
+ return;
+ kref_put(&u132->kref, u132_hcd_delete);
+ return;
+}
+
+static void u132_monitor_cancel_work(struct u132 *u132)
+{
+ if (cancel_delayed_work(&u132->monitor))
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static int read_roothub_info(struct u132 *u132)
+{
+ u32 revision;
+ int retval;
+ retval = u132_read_pcimem(u132, revision, &revision);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
+ "ntrol\n", retval);
+ return retval;
+ } else if ((revision & 0xFF) == 0x10) {
+ } else if ((revision & 0xFF) == 0x11) {
+ } else {
+ dev_err(&u132->platform_dev->dev, "device revision is not valid"
+ " %08X\n", revision);
+ return -ENODEV;
+ }
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
+ "ntrol\n", retval);
+ return retval;
+ }
+ retval = u132_read_pcimem(u132, roothub.status,
+ &u132->hc_roothub_status);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
+ "g roothub.status\n", retval);
+ return retval;
+ }
+ retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
+ "g roothub.a\n", retval);
+ return retval;
+ }
+ {
+ int I = u132->num_ports;
+ int i = 0;
+ while (I-- > 0) {
+ retval = u132_read_pcimem(u132, roothub.portstatus[i],
+ &u132->hc_roothub_portstatus[i]);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d acc"
+ "essing device roothub.portstatus[%d]\n"
+ , retval, i);
+ return retval;
+ } else
+ i += 1;
+ }
+ }
+ return 0;
+}
+
+static void u132_hcd_monitor_work(void *data)
+{
+ struct u132 *u132 = data;
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ u132_monitor_put_kref(u132);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ u132_monitor_put_kref(u132);
+ return;
+ } else {
+ int retval;
+ down(&u132->sw_lock);
+ retval = read_roothub_info(u132);
+ if (retval) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ u132_disable(u132);
+ u132->going = 1;
+ up(&u132->sw_lock);
+ usb_hc_died(hcd);
+ ftdi_elan_gone_away(u132->platform_dev);
+ u132_monitor_put_kref(u132);
+ return;
+ } else {
+ u132_monitor_requeue_work(u132, 500);
+ up(&u132->sw_lock);
+ return;
+ }
+ }
+}
+
+static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb, int status)
+{
+ struct u132_ring *ring;
+ unsigned long irqs;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ urb->error_count = 0;
+ urb->status = status;
+ urb->hcpriv = NULL;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_next += 1;
+ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
+ urb_more);
+ list_del(next);
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urbq->urb;
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(urbq);
+ } down(&u132->scheduler_lock);
+ ring = endp->ring;
+ ring->in_use = 0;
+ u132_ring_cancel_work(u132, ring);
+ u132_ring_queue_work(u132, ring, 0);
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ usb_hcd_giveback_urb(hcd, urb, NULL);
+ return;
+}
+
+static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb, int status)
+{
+ u132_endp_put_kref(u132, endp);
+}
+
+static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb, int status)
+{
+ unsigned long irqs;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ urb->error_count = 0;
+ urb->status = status;
+ urb->hcpriv = NULL;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_next += 1;
+ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
+ urb_more);
+ list_del(next);
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urbq->urb;
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(urbq);
+ } usb_hcd_giveback_urb(hcd, urb, NULL);
+ return;
+}
+
+static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
+ urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
+ urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
+ endp, urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
+ endp, urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+
+/*
+* must not LOCK sw_lock
+*
+*/
+static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer + urb->actual_length;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length += len;
+ if ((condition_code == TD_CC_NOERROR) &&
+ (urb->transfer_buffer_length > urb->actual_length)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ if (urb->actual_length > 0) {
+ int retval;
+ up(&u132->scheduler_lock);
+ retval = edset_single(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_interrupt_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ } else {
+ ring->in_use = 0;
+ endp->active = 0;
+ endp->jiffies = jiffies +
+ msecs_to_jiffies(urb->interval);
+ u132_ring_cancel_work(u132, ring);
+ u132_ring_queue_work(u132, ring, 0);
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ }
+ return;
+ } else if ((condition_code == TD_DATAUNDERRUN) &&
+ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ if (condition_code == TD_CC_NOERROR) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 1 & toggle_bits);
+ } else if (condition_code == TD_CC_STALL) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 0);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 0);
+ dev_err(&u132->platform_dev->dev, "urb=%p givin"
+ "g back INTERRUPT %s\n", urb,
+ cc_to_text[condition_code]);
+ }
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ urb->actual_length += len;
+ endp->toggle_bits = toggle_bits;
+ if (urb->transfer_buffer_length > urb->actual_length) {
+ int retval;
+ up(&u132->scheduler_lock);
+ retval = edset_output(u132, ring, endp, urb, address,
+ endp->toggle_bits, u132_hcd_bulk_output_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer + urb->actual_length;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length += len;
+ if ((condition_code == TD_CC_NOERROR) &&
+ (urb->transfer_buffer_length > urb->actual_length)) {
+ int retval;
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, endp->toggle_bits,
+ u132_hcd_bulk_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (condition_code == TD_CC_NOERROR) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else if ((condition_code == TD_DATAUNDERRUN) &&
+ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else if (condition_code == TD_DATAUNDERRUN) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
+ ") giving back BULK IN %s\n", urb,
+ cc_to_text[condition_code]);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else if (condition_code == TD_CC_STALL) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
+ dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
+ "ULK IN code=%d %s\n", urb, condition_code,
+ cc_to_text[condition_code]);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length = len;
+ if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
+ TD_DATAUNDERRUN) && ((urb->transfer_flags &
+ URB_SHORT_NOT_OK) == 0))) {
+ int retval;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0x3,
+ u132_hcd_configure_empty_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (condition_code == TD_CC_STALL) {
+ up(&u132->scheduler_lock);
+ dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
+ "NPUT STALL urb %p\n", urb);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else {
+ up(&u132->scheduler_lock);
+ dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
+ "PUT %s urb %p\n", cc_to_text[condition_code],
+ urb);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ if (usb_pipein(urb->pipe)) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0,
+ u132_hcd_configure_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0,
+ u132_hcd_configure_empty_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
+ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ u132->addr[0].address = 0;
+ endp->usb_addr = udev->usb_addr;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
+ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, 0, endp->usb_endp, 0,
+ u132_hcd_enumeration_empty_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length = len;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
+ ring->number, endp, urb, address, endp->usb_endp, 0x3,
+ u132_hcd_initial_empty_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address, endp->usb_endp, 0,
+ u132_hcd_initial_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_ring_work_scheduler(void *data);
+static void u132_hcd_endp_work_scheduler(void *data);
+/*
+* this work function is only executed from the work queue
+*
+*/
+static void u132_hcd_ring_work_scheduler(void *data)
+{
+ struct u132_ring *ring = data;
+ struct u132 *u132 = ring->u132;
+ down(&u132->scheduler_lock);
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else if (ring->curr_endp) {
+ struct u132_endp *last_endp = ring->curr_endp;
+ struct list_head *scan;
+ struct list_head *head = &last_endp->endp_ring;
+ unsigned long wakeup = 0;
+ list_for_each(scan, head) {
+ struct u132_endp *endp = list_entry(scan,
+ struct u132_endp, endp_ring);
+ if (endp->queue_next == endp->queue_last) {
+ } else if ((endp->delayed == 0)
+ || time_after_eq(jiffies, endp->jiffies)) {
+ ring->curr_endp = endp;
+ u132_endp_cancel_work(u132, last_endp);
+ u132_endp_queue_work(u132, last_endp, 0);
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else {
+ unsigned long delta = endp->jiffies - jiffies;
+ if (delta > wakeup)
+ wakeup = delta;
+ }
+ }
+ if (last_endp->queue_next == last_endp->queue_last) {
+ } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
+ last_endp->jiffies)) {
+ u132_endp_cancel_work(u132, last_endp);
+ u132_endp_queue_work(u132, last_endp, 0);
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else {
+ unsigned long delta = last_endp->jiffies - jiffies;
+ if (delta > wakeup)
+ wakeup = delta;
+ }
+ if (wakeup > 0) {
+ u132_ring_requeue_work(u132, ring, wakeup);
+ up(&u132->scheduler_lock);
+ return;
+ } else {
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ }
+ } else {
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ }
+}
+
+static void u132_hcd_endp_work_scheduler(void *data)
+{
+ struct u132_ring *ring;
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ ring = endp->ring;
+ if (endp->edset_flush) {
+ endp->edset_flush = 0;
+ if (endp->dequeueing)
+ usb_ftdi_elan_edset_flush(u132->platform_dev,
+ ring->number, endp);
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->active) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->queue_next == endp->queue_last) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->pipetype == PIPE_INTERRUPT) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_single(u132, ring, endp, urb, address,
+ endp->toggle_bits, u132_hcd_interrupt_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else if (endp->pipetype == PIPE_CONTROL) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (address == 0) {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, address,
+ 0x2, u132_hcd_initial_setup_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (endp->usb_addr == 0) {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
+ u132_hcd_enumeration_address_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ int retval;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, address,
+ 0x2, u132_hcd_configure_setup_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else {
+ if (endp->input) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[
+ ENDP_QUEUE_MASK & endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_input(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_bulk_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ return;
+ }
+ } else { /* output pipe */
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[
+ ENDP_QUEUE_MASK & endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_output(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_bulk_output_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ return;
+ }
+ }
+ }
+}
+
+static void port_power(struct u132 *u132, int pn, int is_on)
+{
+ u132->port[pn].power = is_on;
+}
+
+static void u132_power(struct u132 *u132, int is_on)
+{
+ struct usb_hcd *hcd = u132_to_hcd(u132)
+ ; /* hub is inactive unless the port is powered */
+ if (is_on) {
+ if (u132->power)
+ return;
+ u132->power = 1;
+ hcd->self.controller->power.power_state = PMSG_ON;
+ } else {
+ u132->power = 0;
+ hcd->state = HC_STATE_HALT;
+ hcd->self.controller->power.power_state = PMSG_SUSPEND;
+ }
+}
+
+static int u132_periodic_reinit(struct u132 *u132)
+{
+ int retval;
+ u32 fi = u132->hc_fminterval & 0x03fff;
+ u32 fit;
+ u32 fminterval;
+ retval = u132_read_pcimem(u132, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ fit = fminterval & FIT;
+ retval = u132_write_pcimem(u132, fminterval,
+ (fit ^ FIT) | u132->hc_fminterval);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, periodicstart,
+ ((9 *fi) / 10) & 0x3fff);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+static char *hcfs2string(int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET:
+ return "reset";
+ case OHCI_USB_RESUME:
+ return "resume";
+ case OHCI_USB_OPER:
+ return "operational";
+ case OHCI_USB_SUSPEND:
+ return "suspend";
+ }
+ return "?";
+}
+
+static int u132_usb_reset(struct u132 *u132)
+{
+ int retval;
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval)
+ return retval;
+ u132->hc_control &= OHCI_CTRL_RWC;
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+static int u132_init(struct u132 *u132)
+{
+ int retval;
+ u32 control;
+ u132_disable(u132);
+ u132->next_statechange =
+ jiffies; /* SMM owns the HC? not for long! */ {
+ u32 control;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ if (control & OHCI_CTRL_IR) {
+ u32 temp = 50;
+ retval = u132_write_pcimem(u132, intrenable,
+ OHCI_INTR_OC);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem_byte(u132, cmdstatus,
+ OHCI_OCR);
+ if (retval)
+ return retval;
+ check:{
+ retval = u132_read_pcimem(u132, control,
+ &control);
+ if (retval)
+ return retval;
+ }
+ if (control & OHCI_CTRL_IR) {
+ msleep(10);
+ if (--temp == 0) {
+ dev_err(&u132->platform_dev->dev, "USB "
+ "HC takeover failed!(BIOS/SMM b"
+ "ug) control=%08X\n", control);
+ return -EBUSY;
+ }
+ goto check;
+ }
+ u132_usb_reset(u132);
+ }
+ }
+ retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ if (u132->num_ports == 0) {
+ u32 rh_a = -1;
+ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ u132->num_ports = rh_a & RH_A_NDP;
+ retval = read_roothub_info(u132);
+ if (retval)
+ return retval;
+ }
+ if (u132->num_ports > MAX_U132_PORTS) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/* Start an OHCI controller, set the BUS operational
+* resets USB and controller
+* enable interrupts
+*/
+static int u132_run(struct u132 *u132)
+{
+ int retval;
+ u32 control;
+ u32 status;
+ u32 fminterval;
+ u32 periodicstart;
+ u32 cmdstatus;
+ u32 roothub_a;
+ int mask = OHCI_INTR_INIT;
+ int first = u132->hc_fminterval == 0;
+ int sleep_time = 0;
+ int reset_timeout = 30; /* ... allow extra time */
+ u132_disable(u132);
+ if (first) {
+ u32 temp;
+ retval = u132_read_pcimem(u132, fminterval, &temp);
+ if (retval)
+ return retval;
+ u132->hc_fminterval = temp & 0x3fff;
+ if (u132->hc_fminterval != FI) {
+ }
+ u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
+ }
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval)
+ return retval;
+ dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
+ "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
+ u132->hc_control);
+ switch (u132->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ sleep_time = 0;
+ break;
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_USB_RESUME;
+ sleep_time = 10;
+ break;
+ default:
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_USB_RESET;
+ sleep_time = 50;
+ break;
+ }
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ msleep(sleep_time);
+ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ if (!(roothub_a & RH_A_NPS)) {
+ int temp; /* power down each port */
+ for (temp = 0; temp < u132->num_ports; temp++) {
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[temp], RH_PS_LSDA);
+ if (retval)
+ return retval;
+ }
+ }
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ retry:retval = u132_read_pcimem(u132, cmdstatus, &status);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR);
+ if (retval)
+ return retval;
+ extra:{
+ retval = u132_read_pcimem(u132, cmdstatus, &status);
+ if (retval)
+ return retval;
+ if (0 != (status & OHCI_HCR)) {
+ if (--reset_timeout == 0) {
+ dev_err(&u132->platform_dev->dev, "USB HC reset"
+ " timed out!\n");
+ return -ENODEV;
+ } else {
+ msleep(5);
+ goto extra;
+ }
+ }
+ }
+ if (u132->flags & OHCI_QUIRK_INITRESET) {
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ }
+ retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, hcca, 0x00000000);
+ if (retval)
+ return retval;
+ retval = u132_periodic_reinit(u132);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
+ if (retval)
+ return retval;
+ if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
+ if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
+ u132->flags |= OHCI_QUIRK_INITRESET;
+ goto retry;
+ } else
+ dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
+ "\n", fminterval, periodicstart);
+ } /* start controller operations */
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
+ retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, intrstatus, mask);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, intrdisable,
+ OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
+ OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
+ OHCI_INTR_SO);
+ if (retval)
+ return retval; /* handle root hub init quirks ... */
+ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
+ if (u132->flags & OHCI_QUIRK_SUPERIO) {
+ roothub_a |= RH_A_NOCP;
+ roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
+ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
+ roothub_a |= RH_A_NPS;
+ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ }
+ retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, roothub.b,
+ (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ mdelay((roothub_a >> 23) & 0x1fe);
+ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
+ return 0;
+}
+
+static void u132_hcd_stop(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
+ "ed\n", hcd);
+ } else {
+ down(&u132->sw_lock);
+ msleep(100);
+ u132_power(u132, 0);
+ up(&u132->sw_lock);
+ }
+}
+
+static int u132_hcd_start(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else if (hcd->self.controller) {
+ int retval;
+ struct platform_device *pdev =
+ to_platform_device(hcd->self.controller);
+ u16 vendor = ((struct u132_platform_data *)
+ (pdev->dev.platform_data))->vendor;
+ u16 device = ((struct u132_platform_data *)
+ (pdev->dev.platform_data))->device;
+ down(&u132->sw_lock);
+ msleep(10);
+ if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
+ u132->flags = OHCI_QUIRK_AMD756;
+ } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
+ dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
+ "ounds unavailable\n");
+ } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
+ u132->flags |= OHCI_QUIRK_ZFMICRO;
+ retval = u132_run(u132);
+ if (retval) {
+ u132_disable(u132);
+ u132->going = 1;
+ }
+ msleep(100);
+ up(&u132->sw_lock);
+ return retval;
+ } else {
+ dev_err(&u132->platform_dev->dev, "platform_device missing\n");
+ return -ENODEV;
+ }
+}
+
+static int u132_hcd_reset(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval;
+ down(&u132->sw_lock);
+ retval = u132_init(u132);
+ if (retval) {
+ u132_disable(u132);
+ u132->going = 1;
+ }
+ up(&u132->sw_lock);
+ return retval;
+ }
+}
+
+static int create_endpoint_and_queue_int(struct u132 *u132,
+ struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
+ gfp_t mem_flags)
+{
+ struct u132_ring *ring;
+ unsigned long irqs;
+ u8 endp_number = ++u132->num_endpoints;
+ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
+ kmalloc(sizeof(struct u132_endp), mem_flags);
+ if (!endp) {
+ return -ENOMEM;
+ }
+ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
+ spin_lock_init(&endp->queue_lock.slock);
+ INIT_LIST_HEAD(&endp->urb_more);
+ ring = endp->ring = &u132->ring[0];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
+ endp->hep = hep;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_endp_init_kref(u132, endp);
+ if (usb_pipein(urb->pipe)) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
+ endp->input = 1;
+ endp->output = 0;
+ udev->endp_number_in[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
+ endp->input = 0;
+ endp->output = 1;
+ udev->endp_number_out[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ }
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->delayed = 1;
+ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
+ return 0;
+}
+
+static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp, u8 address)
+{
+ urb->hcpriv = u132;
+ endp->delayed = 1;
+ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+}
+
+static int create_endpoint_and_queue_bulk(struct u132 *u132,
+ struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
+ gfp_t mem_flags)
+{
+ int ring_number;
+ struct u132_ring *ring;
+ unsigned long irqs;
+ u8 endp_number = ++u132->num_endpoints;
+ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
+ kmalloc(sizeof(struct u132_endp), mem_flags);
+ if (!endp) {
+ return -ENOMEM;
+ }
+ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
+ spin_lock_init(&endp->queue_lock.slock);
+ INIT_LIST_HEAD(&endp->urb_more);
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
+ endp->hep = hep;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_endp_init_kref(u132, endp);
+ if (usb_pipein(urb->pipe)) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
+ ring_number = 3;
+ endp->input = 1;
+ endp->output = 0;
+ udev->endp_number_in[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
+ ring_number = 2;
+ endp->input = 0;
+ endp->output = 1;
+ udev->endp_number_out[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ }
+ ring = endp->ring = &u132->ring[ring_number - 1];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+}
+
+static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp, u8 address)
+{
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+}
+
+static int create_endpoint_and_queue_control(struct u132 *u132,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
+ gfp_t mem_flags)
+{
+ struct u132_ring *ring;
+ u8 endp_number = ++u132->num_endpoints;
+ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
+ kmalloc(sizeof(struct u132_endp), mem_flags);
+ if (!endp) {
+ return -ENOMEM;
+ }
+ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
+ spin_lock_init(&endp->queue_lock.slock);
+ INIT_LIST_HEAD(&endp->urb_more);
+ ring = endp->ring = &u132->ring[0];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
+ endp->hep = hep;
+ u132_endp_init_kref(u132, endp);
+ u132_endp_get_kref(u132, endp);
+ if (usb_addr == 0) {
+ unsigned long irqs;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->input = 1;
+ endp->output = 1;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_udev_init_kref(u132, udev);
+ u132_udev_get_kref(u132, udev);
+ udev->endp_number_in[usb_endp] = endp_number;
+ udev->endp_number_out[usb_endp] = endp_number;
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ } else { /*(usb_addr > 0) */
+ unsigned long irqs;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->input = 1;
+ endp->output = 1;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_udev_get_kref(u132, udev);
+ udev->enumeration = 2;
+ udev->endp_number_in[usb_endp] = endp_number;
+ udev->endp_number_out[usb_endp] = endp_number;
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+}
+
+static int queue_control_on_old_endpoint(struct u132 *u132,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp)
+{
+ if (usb_addr == 0) {
+ if (usb_pipein(urb->pipe)) {
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more,
+ &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ } else { /* usb_pipeout(urb->pipe) */
+ struct u132_addr *addr = &u132->addr[usb_dev->devnum];
+ int I = MAX_U132_UDEVS;
+ int i = 0;
+ while (--I > 0) {
+ struct u132_udev *udev = &u132->udev[++i];
+ if (udev->usb_device) {
+ continue;
+ } else {
+ udev->enumeration = 1;
+ u132->addr[0].address = i;
+ endp->udev_number = i;
+ udev->udev_number = i;
+ udev->usb_addr = usb_dev->devnum;
+ u132_udev_init_kref(u132, udev);
+ udev->endp_number_in[usb_endp] =
+ endp->endp_number;
+ u132_udev_get_kref(u132, udev);
+ udev->endp_number_out[usb_endp] =
+ endp->endp_number;
+ udev->usb_device = usb_dev;
+ ((u8 *) (urb->setup_packet))[2] =
+ addr->address = i;
+ u132_udev_get_kref(u132, udev);
+ break;
+ }
+ }
+ if (I == 0) {
+ dev_err(&u132->platform_dev->dev, "run out of d"
+ "evice space\n");
+ return -EINVAL;
+ }
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more,
+ &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ }
+ } else { /*(usb_addr > 0) */
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ urb->hcpriv = u132;
+ if (udev->enumeration == 2) {
+ } else
+ udev->enumeration = 2;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ }
+}
+
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
+ struct urb *urb, gfp_t mem_flags)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (irqs_disabled()) {
+ if (__GFP_WAIT & mem_flags) {
+ printk(KERN_ERR "invalid context for function that migh"
+ "t sleep\n");
+ return -EINVAL;
+ }
+ }
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ return -ESHUTDOWN;
+ } else {
+ u8 usb_addr = usb_pipedevice(urb->pipe);
+ u8 usb_endp = usb_pipeendpoint(urb->pipe);
+ struct usb_device *usb_dev = urb->dev;
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ struct u132_endp *endp = hep->hcpriv;
+ urb->actual_length = 0;
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
+ retval = queue_int_on_old_endpoint(u132, udev,
+ hep, urb, usb_dev, endp, usb_addr,
+ usb_endp, address);
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp,
+ msecs_to_jiffies(urb->interval))
+ ;
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else { /*(endp == NULL) */
+ return create_endpoint_and_queue_int(u132, udev,
+ hep, urb, usb_dev, usb_addr, usb_endp,
+ address, mem_flags);
+ }
+ } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ dev_err(&u132->platform_dev->dev, "the hardware does no"
+ "t support PIPE_ISOCHRONOUS\n");
+ return -EINVAL;
+ } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ struct u132_endp *endp = hep->hcpriv;
+ urb->actual_length = 0;
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
+ retval = queue_bulk_on_old_endpoint(u132, udev,
+ hep, urb, usb_dev, endp, usb_addr,
+ usb_endp, address);
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else
+ return create_endpoint_and_queue_bulk(u132,
+ udev, hep, urb, usb_dev, usb_addr,
+ usb_endp, address, mem_flags);
+ } else {
+ struct u132_endp *endp = hep->hcpriv;
+ u16 urb_size = 8;
+ u8 *b = urb->setup_packet;
+ int i = 0;
+ char data[30 *3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int l = 0;
+ data[0] = 0;
+ while (urb_size-- > 0) {
+ if (i > m) {
+ } else if (i++ < m) {
+ int w = sprintf(d, " %02X", *b++);
+ d += w;
+ l += w;
+ } else
+ d += sprintf(d, " ..");
+ }
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
+ retval = queue_control_on_old_endpoint(u132,
+ hep, urb, usb_dev, endp, usb_addr,
+ usb_endp);
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else
+ return create_endpoint_and_queue_control(u132,
+ hep, urb, usb_dev, usb_addr, usb_endp,
+ mem_flags);
+ }
+ }
+}
+
+static int dequeue_from_overflow_chain(struct u132 *u132,
+ struct u132_endp *endp, struct urb *urb)
+{
+ struct list_head *scan;
+ struct list_head *head = &endp->urb_more;
+ list_for_each(scan, head) {
+ struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
+ urb_more);
+ if (urbq->urb == urb) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ list_del(scan);
+ endp->queue_size -= 1;
+ urb->error_count = 0;
+ urb->hcpriv = NULL;
+ usb_hcd_giveback_urb(hcd, urb, NULL);
+ return 0;
+ } else
+ continue;
+ }
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
+ "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
+ "\n", urb, endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
+ endp->usb_endp, endp->usb_addr, endp->queue_size,
+ endp->queue_next, endp->queue_last);
+ return -EINVAL;
+}
+
+static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb)
+{
+ unsigned long irqs;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ if (endp->queue_size == 0) {
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
+ "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
+ endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
+ endp->usb_endp, endp->usb_addr);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return -EINVAL;
+ }
+ if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
+ if (endp->active) {
+ endp->dequeueing = 1;
+ endp->edset_flush = 1;
+ u132_endp_queue_work(u132, endp, 0);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ urb->hcpriv = NULL;
+ return 0;
+ } else {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+ return 0;
+ }
+ } else {
+ u16 queue_list = 0;
+ u16 queue_size = endp->queue_size;
+ u16 queue_scan = endp->queue_next;
+ struct urb **urb_slot = NULL;
+ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
+ if (urb == endp->urb_list[ENDP_QUEUE_MASK &
+ ++queue_scan]) {
+ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
+ queue_scan];
+ break;
+ } else
+ continue;
+ }
+ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
+ *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
+ ++queue_scan];
+ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
+ queue_scan];
+ }
+ if (urb_slot) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ endp->queue_size -= 1;
+ if (list_empty(&endp->urb_more)) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next,
+ struct u132_urbq, urb_more);
+ list_del(next);
+ *urb_slot = urbq->urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ kfree(urbq);
+ } urb->error_count = 0;
+ urb->hcpriv = NULL;
+ usb_hcd_giveback_urb(hcd, urb, NULL);
+ return 0;
+ } else if (list_empty(&endp->urb_more)) {
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in "
+ "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
+ "=%d size=%d next=%04X last=%04X\n", urb,
+ endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ',
+ endp->output ? 'O' : ' ', endp->usb_endp,
+ endp->usb_addr, endp->queue_size,
+ endp->queue_next, endp->queue_last);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return -EINVAL;
+ } else {
+ int retval = dequeue_from_overflow_chain(u132, endp,
+ urb);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return retval;
+ }
+ }
+}
+
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 2) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else {
+ u8 usb_addr = usb_pipedevice(urb->pipe);
+ u8 usb_endp = usb_pipeendpoint(urb->pipe);
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ if (usb_pipein(urb->pipe)) {
+ u8 endp_number = udev->endp_number_in[usb_endp];
+ struct u132_endp *endp = u132->endp[endp_number - 1];
+ return u132_endp_urb_dequeue(u132, endp, urb);
+ } else {
+ u8 endp_number = udev->endp_number_out[usb_endp];
+ struct u132_endp *endp = u132->endp[endp_number - 1];
+ return u132_endp_urb_dequeue(u132, endp, urb);
+ }
+ }
+}
+
+static void u132_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *hep)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 2) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else {
+ struct u132_endp *endp = hep->hcpriv;
+ if (endp)
+ u132_endp_put_kref(u132, endp);
+ }
+}
+
+static int u132_get_frame(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int frame = 0;
+ dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
+ msleep(100);
+ return frame;
+ }
+}
+
+static int u132_roothub_descriptor(struct u132 *u132,
+ struct usb_hub_descriptor *desc)
+{
+ int retval;
+ u16 temp;
+ u32 rh_a = -1;
+ u32 rh_b = -1;
+ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
+ desc->bHubContrCurrent = 0;
+ desc->bNbrPorts = u132->num_ports;
+ temp = 1 + (u132->num_ports / 8);
+ desc->bDescLength = 7 + 2 *temp;
+ temp = 0;
+ if (rh_a & RH_A_NPS)
+ temp |= 0x0002;
+ if (rh_a & RH_A_PSM)
+ temp |= 0x0001;
+ if (rh_a & RH_A_NOCP) {
+ temp |= 0x0010;
+ } else if (rh_a & RH_A_OCPM)
+ temp |= 0x0008;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+ retval = u132_read_pcimem(u132, roothub.b, &rh_b);
+ if (retval)
+ return retval;
+ memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
+ desc->bitmap[0] = rh_b & RH_B_DR;
+ if (u132->num_ports > 7) {
+ desc->bitmap[1] = (rh_b & RH_B_DR) >> 8;
+ desc->bitmap[2] = 0xff;
+ } else
+ desc->bitmap[1] = 0xff;
+ return 0;
+}
+
+static int u132_roothub_status(struct u132 *u132, __le32 *desc)
+{
+ u32 rh_status = -1;
+ int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
+ *desc = cpu_to_le32(rh_status);
+ return ret_status;
+}
+
+static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int port = wIndex - 1;
+ u32 rh_portstatus = -1;
+ int ret_portstatus = u132_read_pcimem(u132,
+ roothub.portstatus[port], &rh_portstatus);
+ *desc = cpu_to_le32(rh_portstatus);
+ if (*(u16 *) (desc + 2)) {
+ dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
+ "ge = %08X\n", port, *desc);
+ }
+ return ret_portstatus;
+ }
+}
+
+
+/* this timer value might be vendor-specific ... */
+#define PORT_RESET_HW_MSEC 10
+#define PORT_RESET_MSEC 10
+/* wrap-aware logic morphed from <linux/jiffies.h> */
+#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
+static int u132_roothub_portreset(struct u132 *u132, int port_index)
+{
+ int retval;
+ u32 fmnumber;
+ u16 now;
+ u16 reset_done;
+ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
+ if (retval)
+ return retval;
+ now = fmnumber;
+ reset_done = now + PORT_RESET_MSEC;
+ do {
+ u32 portstat;
+ do {
+ retval = u132_read_pcimem(u132,
+ roothub.portstatus[port_index], &portstat);
+ if (retval)
+ return retval;
+ if (RH_PS_PRS & portstat) {
+ continue;
+ } else
+ break;
+ } while (tick_before(now, reset_done));
+ if (RH_PS_PRS & portstat)
+ return -ENODEV;
+ if (RH_PS_CCS & portstat) {
+ if (RH_PS_PRSC & portstat) {
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index],
+ RH_PS_PRSC);
+ if (retval)
+ return retval;
+ }
+ } else
+ break; /* start the next reset,
+ sleep till it's probably done */
+ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
+ RH_PS_PRS);
+ if (retval)
+ return retval;
+ msleep(PORT_RESET_HW_MSEC);
+ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
+ if (retval)
+ return retval;
+ now = fmnumber;
+ } while (tick_before(now, reset_done));
+ return 0;
+}
+
+static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
+ u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int retval;
+ int port_index = wIndex - 1;
+ struct u132_port *port = &u132->port[port_index];
+ port->Status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index], RH_PS_PSS);
+ if (retval)
+ return retval;
+ return 0;
+ case USB_PORT_FEAT_POWER:
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index], RH_PS_PPS);
+ if (retval)
+ return retval;
+ return 0;
+ case USB_PORT_FEAT_RESET:
+ retval = u132_roothub_portreset(u132, port_index);
+ if (retval)
+ return retval;
+ return 0;
+ default:
+ return -EPIPE;
+ }
+ }
+}
+
+static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
+ u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int port_index = wIndex - 1;
+ u32 temp;
+ int retval;
+ struct u132_port *port = &u132->port[port_index];
+ port->Status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ temp = RH_PS_CCS;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ temp = RH_PS_PESC;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ temp = RH_PS_POCI;
+ if ((u132->hc_control & OHCI_CTRL_HCFS)
+ != OHCI_USB_OPER) {
+ dev_err(&u132->platform_dev->dev, "TODO resume_"
+ "root_hub\n");
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ temp = RH_PS_PSSC;
+ break;
+ case USB_PORT_FEAT_POWER:
+ temp = RH_PS_LSDA;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ temp = RH_PS_CSC;
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ temp = RH_PS_OCIC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ temp = RH_PS_PRSC;
+ break;
+ default:
+ return -EPIPE;
+ }
+ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
+ temp);
+ if (retval)
+ return retval;
+ return 0;
+ }
+}
+
+
+/* the virtual root hub timer IRQ checks for hub status*/
+static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
+ "ed %d\n", hcd, u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
+ "ed\n", hcd);
+ dump_stack();
+ return -ESHUTDOWN;
+ } else {
+ int i, changed = 0, length = 1;
+ if (u132->flags & OHCI_QUIRK_AMD756) {
+ if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
+ dev_err(&u132->platform_dev->dev, "bogus NDP, r"
+ "ereads as NDP=%d\n",
+ u132->hc_roothub_a & RH_A_NDP);
+ goto done;
+ }
+ }
+ if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) {
+ buf[0] = changed = 1;
+ } else
+ buf[0] = 0;
+ if (u132->num_ports > 7) {
+ buf[1] = 0;
+ length++;
+ }
+ for (i = 0; i < u132->num_ports; i++) {
+ if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
+ RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
+ RH_PS_PRSC)) {
+ changed = 1;
+ if (i < 7) {
+ buf[0] |= 1 << (i + 1);
+ } else
+ buf[1] |= 1 << (i - 7);
+ continue;
+ }
+ if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) {
+ continue;
+ }
+ if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) {
+ continue;
+ }
+ }
+ done:return changed ? length : 0;
+ }
+}
+
+static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ down(&u132->sw_lock);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto stall;
+ }
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto stall;
+ }
+ break;
+ case ClearPortFeature:{
+ retval = u132_roothub_clearportfeature(u132,
+ wValue, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetHubDescriptor:{
+ retval = u132_roothub_descriptor(u132,
+ (struct usb_hub_descriptor *)buf);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetHubStatus:{
+ retval = u132_roothub_status(u132,
+ (__le32 *) buf);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetPortStatus:{
+ retval = u132_roothub_portstatus(u132,
+ (__le32 *) buf, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ case SetPortFeature:{
+ retval = u132_roothub_setportfeature(u132,
+ wValue, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ default:
+ goto stall;
+ error:u132_disable(u132);
+ u132->going = 1;
+ break;
+ stall:retval = -EPIPE;
+ break;
+ }
+ up(&u132->sw_lock);
+ return retval;
+ }
+}
+
+static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static void u132_hub_irq_enable(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else if (u132->going > 0)
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+}
+
+
+#ifdef CONFIG_PM
+static int u132_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static int u132_hcd_resume(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static int u132_bus_suspend(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static int u132_bus_resume(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+#else
+#define u132_hcd_suspend NULL
+#define u132_hcd_resume NULL
+#define u132_bus_suspend NULL
+#define u132_bus_resume NULL
+#endif
+static struct hc_driver u132_hc_driver = {
+ .description = hcd_name,
+ .hcd_priv_size = sizeof(struct u132),
+ .irq = NULL,
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .reset = u132_hcd_reset,
+ .start = u132_hcd_start,
+ .suspend = u132_hcd_suspend,
+ .resume = u132_hcd_resume,
+ .stop = u132_hcd_stop,
+ .urb_enqueue = u132_urb_enqueue,
+ .urb_dequeue = u132_urb_dequeue,
+ .endpoint_disable = u132_endpoint_disable,
+ .get_frame_number = u132_get_frame,
+ .hub_status_data = u132_hub_status_data,
+ .hub_control = u132_hub_control,
+ .bus_suspend = u132_bus_suspend,
+ .bus_resume = u132_bus_resume,
+ .start_port_reset = u132_start_port_reset,
+ .hub_irq_enable = u132_hub_irq_enable,
+};
+
+/*
+* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
+* is held for writing, thus this module must not call usb_remove_hcd()
+* synchronously - but instead should immediately stop activity to the
+* device and ansynchronously call usb_remove_hcd()
+*/
+static int __devexit u132_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ if (hcd) {
+ struct u132 *u132 = hcd_to_u132(hcd);
+ dump_stack();
+ if (u132->going++ > 1) {
+ return -ENODEV;
+ } else {
+ int rings = MAX_U132_RINGS;
+ int endps = MAX_U132_ENDPS;
+ msleep(100);
+ down(&u132->sw_lock);
+ u132_monitor_cancel_work(u132);
+ while (rings-- > 0) {
+ struct u132_ring *ring = &u132->ring[rings];
+ u132_ring_cancel_work(u132, ring);
+ } while (endps-- > 0) {
+ struct u132_endp *endp = u132->endp[endps];
+ if (endp)
+ u132_endp_cancel_work(u132, endp);
+ }
+ u132->going += 1;
+ printk(KERN_INFO "removing device u132.%d\n",
+ u132->sequence_num);
+ up(&u132->sw_lock);
+ usb_remove_hcd(hcd);
+ u132_u132_put_kref(u132);
+ return 0;
+ }
+ } else
+ return 0;
+}
+
+static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
+{
+ int rings = MAX_U132_RINGS;
+ int ports = MAX_U132_PORTS;
+ int addrs = MAX_U132_ADDRS;
+ int udevs = MAX_U132_UDEVS;
+ int endps = MAX_U132_ENDPS;
+ u132->board = pdev->dev.platform_data;
+ u132->platform_dev = pdev;
+ u132->power = 0;
+ u132->reset = 0;
+ init_MUTEX(&u132->sw_lock);
+ init_MUTEX(&u132->scheduler_lock);
+ while (rings-- > 0) {
+ struct u132_ring *ring = &u132->ring[rings];
+ ring->u132 = u132;
+ ring->number = rings + 1;
+ ring->length = 0;
+ ring->curr_endp = NULL;
+ INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler,
+ (void *)ring);
+ } down(&u132->sw_lock);
+ INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132);
+ while (ports-- > 0) {
+ struct u132_port *port = &u132->port[ports];
+ port->u132 = u132;
+ port->reset = 0;
+ port->enable = 0;
+ port->power = 0;
+ port->Status = 0;
+ } while (addrs-- > 0) {
+ struct u132_addr *addr = &u132->addr[addrs];
+ addr->address = 0;
+ } while (udevs-- > 0) {
+ struct u132_udev *udev = &u132->udev[udevs];
+ int i = ARRAY_SIZE(udev->endp_number_in);
+ int o = ARRAY_SIZE(udev->endp_number_out);
+ udev->usb_device = NULL;
+ udev->udev_number = 0;
+ udev->usb_addr = 0;
+ udev->portnumber = 0;
+ while (i-- > 0) {
+ udev->endp_number_in[i] = 0;
+ }
+ while (o-- > 0) {
+ udev->endp_number_out[o] = 0;
+ }
+ }
+ while (endps-- > 0) {
+ u132->endp[endps] = NULL;
+ }
+ up(&u132->sw_lock);
+ return;
+}
+
+static int __devinit u132_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ msleep(100);
+ if (u132_exiting > 0) {
+ return -ENODEV;
+ } /* refuse to confuse usbcore */
+ if (pdev->dev.dma_mask) {
+ return -EINVAL;
+ }
+ hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
+ );
+ ftdi_elan_gone_away(pdev);
+ return -ENOMEM;
+ } else {
+ int retval = 0;
+ struct u132 *u132 = hcd_to_u132(hcd);
+ hcd->rsrc_start = 0;
+ down(&u132_module_lock);
+ list_add_tail(&u132->u132_list, &u132_static_list);
+ u132->sequence_num = ++u132_instances;
+ up(&u132_module_lock);
+ u132_u132_init_kref(u132);
+ u132_initialise(u132, pdev);
+ hcd->product_desc = "ELAN U132 Host Controller";
+ retval = usb_add_hcd(hcd, 0, 0);
+ if (retval != 0) {
+ dev_err(&u132->platform_dev->dev, "init error %d\n",
+ retval);
+ u132_u132_put_kref(u132);
+ return retval;
+ } else {
+ u132_monitor_queue_work(u132, 100);
+ return 0;
+ }
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* for this device there's no useful distinction between the controller
+* and its root hub, except that the root hub only gets direct PM calls
+* when CONFIG_USB_SUSPEND is enabled.
+*/
+static int u132_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ if (state.event == PM_EVENT_FREEZE) {
+ retval = u132_bus_suspend(hcd);
+ } else if (state.event == PM_EVENT_SUSPEND) {
+ int ports = MAX_U132_PORTS;
+ while (ports-- > 0) {
+ port_power(u132, ports, 0);
+ }
+ }
+ if (retval == 0)
+ pdev->dev.power.power_state = state;
+ return retval;
+ }
+}
+
+static int u132_resume(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ int ports = MAX_U132_PORTS;
+ while (ports-- > 0) {
+ port_power(u132, ports, 1);
+ }
+ retval = 0;
+ } else {
+ pdev->dev.power.power_state = PMSG_ON;
+ retval = u132_bus_resume(hcd);
+ }
+ return retval;
+ }
+}
+
+#else
+#define u132_suspend NULL
+#define u132_resume NULL
+#endif
+/*
+* this driver is loaded explicitely by ftdi_u132
+*
+* the platform_driver struct is static because it is per type of module
+*/
+static struct platform_driver u132_platform_driver = {
+ .probe = u132_probe,
+ .remove = __devexit_p(u132_remove),
+ .suspend = u132_suspend,
+ .resume = u132_resume,
+ .driver = {
+ .name = (char *)hcd_name,
+ .owner = THIS_MODULE,
+ },
+};
+static int __init u132_hcd_init(void)
+{
+ int retval;
+ INIT_LIST_HEAD(&u132_static_list);
+ u132_instances = 0;
+ u132_exiting = 0;
+ init_MUTEX(&u132_module_lock);
+ if (usb_disabled())
+ return -ENODEV;
+ printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
+ __DATE__);
+ workqueue = create_singlethread_workqueue("u132");
+ retval = platform_driver_register(&u132_platform_driver);
+ return retval;
+}
+
+
+module_init(u132_hcd_init);
+static void __exit u132_hcd_exit(void)
+{
+ struct u132 *u132;
+ struct u132 *temp;
+ down(&u132_module_lock);
+ u132_exiting += 1;
+ up(&u132_module_lock);
+ list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
+ platform_device_unregister(u132->platform_dev);
+ } platform_driver_unregister(&u132_platform_driver);
+ printk(KERN_INFO "u132-hcd driver deregistered\n");
+ wait_event(u132_hcd_wait, u132_instances == 0);
+ flush_workqueue(workqueue);
+ destroy_workqueue(workqueue);
+}
+
+
+module_exit(u132_hcd_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 6637a0e4997..e345f15b7d8 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -9,7 +9,6 @@
* (C) Copyright 1999-2001 Johannes Erdfelt
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/smp_lock.h>
@@ -17,7 +16,7 @@
#include "uhci-hcd.h"
-#define uhci_debug_operations (* (struct file_operations *) NULL)
+#define uhci_debug_operations (* (const struct file_operations *) NULL)
static struct dentry *uhci_debugfs_root;
#ifdef DEBUG
@@ -429,7 +428,7 @@ struct uhci_debug {
static int uhci_debug_open(struct inode *inode, struct file *file)
{
- struct uhci_hcd *uhci = inode->u.generic_ip;
+ struct uhci_hcd *uhci = inode->i_private;
struct uhci_debug *up;
int ret = -ENOMEM;
unsigned long flags;
@@ -501,7 +500,7 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
}
#undef uhci_debug_operations
-static struct file_operations uhci_debug_operations = {
+static const struct file_operations uhci_debug_operations = {
.owner = THIS_MODULE,
.open = uhci_debug_open,
.llseek = uhci_debug_lseek,
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 7b48567622e..eb4eab98e8b 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -735,6 +734,10 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
/* FIXME: Enable non-PME# remote wakeup? */
+ /* make sure snapshot being resumed re-enumerates everything */
+ if (message.event == PM_EVENT_PRETHAW)
+ uhci_hc_died(uhci);
+
done_okay:
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
done:
@@ -910,8 +913,7 @@ static int __init uhci_hcd_init(void)
return 0;
init_failed:
- if (kmem_cache_destroy(uhci_up_cachep))
- warn("not all urb_privs were freed!");
+ kmem_cache_destroy(uhci_up_cachep);
up_failed:
debugfs_remove(uhci_debugfs_root);
@@ -927,10 +929,7 @@ errbuf_failed:
static void __exit uhci_hcd_cleanup(void)
{
pci_unregister_driver(&uhci_pci_driver);
-
- if (kmem_cache_destroy(uhci_up_cachep))
- warn("not all urb_privs were freed!");
-
+ kmem_cache_destroy(uhci_up_cachep);
debugfs_remove(uhci_debugfs_root);
kfree(errbuf);
}
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index c545ef92fe2..16fb72eb6fc 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -84,6 +84,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
unsigned long port_addr)
{
int status;
+ int i;
if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) {
CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
@@ -92,9 +93,14 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
/* The controller won't actually turn off the RD bit until
* it has had a chance to send a low-speed EOP sequence,
- * which takes 3 bit times (= 2 microseconds). We'll delay
- * slightly longer for good luck. */
- udelay(4);
+ * which is supposed to take 3 bit times (= 2 microseconds).
+ * Experiments show that some controllers take longer, so
+ * we'll poll for completion. */
+ for (i = 0; i < 10; ++i) {
+ if (!(inw(port_addr) & USBPORTSC_RD))
+ break;
+ udelay(1);
+ }
}
clear_bit(port, &uhci->resuming_ports);
}
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index c9d72ac0a1d..431e8f31f1a 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -372,7 +372,7 @@ static void uhci_fixup_toggles(struct uhci_qh *qh, int skip_first)
* need to change any toggles in this URB */
td = list_entry(urbp->td_list.next, struct uhci_td, list);
if (toggle > 1 || uhci_toggle(td_token(td)) == toggle) {
- td = list_entry(urbp->td_list.next, struct uhci_td,
+ td = list_entry(urbp->td_list.prev, struct uhci_td,
list);
toggle = uhci_toggle(td_token(td)) ^ 1;
@@ -943,7 +943,9 @@ static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb)
/* We received a short packet */
if (urb->transfer_flags & URB_SHORT_NOT_OK)
ret = -EREMOTEIO;
- else if (ctrlstat & TD_CTRL_SPD)
+
+ /* Fixup needed only if this isn't the URB's last TD */
+ else if (&td->list != urbp->td_list.prev)
ret = 1;
}
@@ -1346,7 +1348,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
}
uhci_giveback_urb(uhci, qh, urb, regs);
- if (status < 0)
+ if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
break;
}
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 08daf400f98..ca6305c1d64 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -424,7 +424,7 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
***************************************************************************/
static struct usb_driver mdc800_usb_driver;
-static struct file_operations mdc800_device_ops;
+static const struct file_operations mdc800_device_ops;
static struct usb_class_driver mdc800_class = {
.name = "mdc800%d",
.fops = &mdc800_device_ops,
@@ -941,7 +941,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
****************************************************************************/
/* File Operations of this drivers */
-static struct file_operations mdc800_device_ops =
+static const struct file_operations mdc800_device_ops =
{
.owner = THIS_MODULE,
.read = mdc800_device_read,
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index b2bafc37c41..5f861331932 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -225,7 +225,7 @@ static inline void mts_debug_dump(struct mts_desc* desc) {
}
-static inline void mts_show_command(Scsi_Cmnd *srb)
+static inline void mts_show_command(struct scsi_cmnd *srb)
{
char *what = NULL;
@@ -309,7 +309,7 @@ static inline void mts_show_command(Scsi_Cmnd *srb)
#else
-static inline void mts_show_command(Scsi_Cmnd * dummy)
+static inline void mts_show_command(struct scsi_cmnd * dummy)
{
}
@@ -338,7 +338,7 @@ static int mts_slave_configure (struct scsi_device *s)
return 0;
}
-static int mts_scsi_abort (Scsi_Cmnd *srb)
+static int mts_scsi_abort(struct scsi_cmnd *srb)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
@@ -349,7 +349,7 @@ static int mts_scsi_abort (Scsi_Cmnd *srb)
return FAILED;
}
-static int mts_scsi_host_reset (Scsi_Cmnd *srb)
+static int mts_scsi_host_reset(struct scsi_cmnd *srb)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int result, rc;
@@ -366,8 +366,8 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb)
return result ? FAILED : SUCCESS;
}
-static
-int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
+static int
+mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
static void mts_transfer_cleanup( struct urb *transfer );
static void mts_do_sg(struct urb * transfer, struct pt_regs *regs);
@@ -537,7 +537,7 @@ static const unsigned char mts_direction[256/8] = {
#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
static void
-mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
+mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
{
int pipe;
struct scatterlist * sg;
@@ -588,8 +588,8 @@ mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
}
-static
-int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
+static int
+mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int err = 0;
diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
index 926d4bdc674..d5d62a93905 100644
--- a/drivers/usb/image/microtek.h
+++ b/drivers/usb/image/microtek.h
@@ -8,14 +8,14 @@
*
*/
-typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *);
+typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *);
struct mts_transfer_context
{
struct mts_desc* instance;
mts_scsi_cmnd_callback final_callback;
- Scsi_Cmnd *srb;
+ struct scsi_cmnd *srb;
void* data;
unsigned data_length;
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 650103bc961..a102a58fe36 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -205,10 +205,12 @@ config USB_TOUCHSCREEN
depends on USB && INPUT
---help---
USB Touchscreen driver for:
- - eGalax Touchkit USB
+ - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
- PanJit TouchSet USB
- - 3M MicroTouch USB
+ - 3M MicroTouch USB (EX II series)
- ITM
+ - some other eTurboTouch
+ - Gunze AHL61
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -218,7 +220,7 @@ config USB_TOUCHSCREEN
config USB_TOUCHSCREEN_EGALAX
default y
- bool "eGalax device support" if EMBEDDED
+ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_PANJIT
@@ -228,7 +230,7 @@ config USB_TOUCHSCREEN_PANJIT
config USB_TOUCHSCREEN_3M
default y
- bool "3M/Microtouch device support" if EMBEDDED
+ bool "3M/Microtouch EX II series device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_ITM
@@ -236,6 +238,16 @@ config USB_TOUCHSCREEN_ITM
bool "ITM device support" if EMBEDDED
depends on USB_TOUCHSCREEN
+config USB_TOUCHSCREEN_ETURBO
+ default y
+ bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
+config USB_TOUCHSCREEN_GUNZE
+ default y
+ bool "Gunze AHL61 device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
config USB_YEALINK
tristate "Yealink usb-p1k voip phone"
depends on USB && INPUT && EXPERIMENTAL
@@ -326,3 +338,13 @@ config USB_APPLETOUCH
To compile this driver as a module, choose M here: the
module will be called appletouch.
+
+config USB_TRANCEVIBRATOR
+ tristate "PlayStation 2 Trance Vibrator driver support"
+ depends on USB
+ help
+ Say Y here if you want to connect a PlayStation 2 Trance Vibrator
+ device to your computer's USB port.
+
+ To compile this driver as a module, choose M here: the
+ module will be called trancevibrator.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 764114529c5..48551be324a 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -3,6 +3,7 @@
#
# Multipart objects.
+wacom-objs := wacom_sys.o wacom_wac.o
usbhid-objs := hid-core.o
# Optional parts of multipart objects.
@@ -44,6 +45,7 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_YEALINK) += yealink.o
obj-$(CONFIG_USB_XPAD) += xpad.o
obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o
+obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
ifeq ($(CONFIG_USB_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
index 18c10e150ef..d83603ba40a 100644
--- a/drivers/usb/input/acecad.c
+++ b/drivers/usb/input/acecad.c
@@ -141,10 +141,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
endpoint = &interface->endpoint[0].desc;
- if (!(endpoint->bEndpointAddress & 0x80))
- return -ENODEV;
-
- if ((endpoint->bmAttributes & 3) != 3)
+ if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
index 36855062eac..0aa9cc2bfd6 100644
--- a/drivers/usb/input/appletouch.c
+++ b/drivers/usb/input/appletouch.c
@@ -27,7 +27,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -437,10 +436,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
iface_desc = iface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
- if (!int_in_endpointAddr &&
- (endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT)) {
+ if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
/* we found an interrupt in endpoint */
int_in_endpointAddr = endpoint->bEndpointAddress;
break;
@@ -598,9 +594,9 @@ static void atp_disconnect(struct usb_interface *iface)
if (dev) {
usb_kill_urb(dev->urb);
input_unregister_device(dev->input);
- usb_free_urb(dev->urb);
usb_buffer_free(dev->udev, dev->datalen,
dev->data, dev->urb->transfer_dma);
+ usb_free_urb(dev->urb);
kfree(dev);
}
printk(KERN_INFO "input: appletouch disconnected\n");
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 07c8c0e665d..3558d7ed99b 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -85,7 +85,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -112,14 +111,28 @@
#define NAME_BUFSIZE 80 /* size of product name, path buffers */
#define DATA_BUFSIZE 63 /* size of URB data buffers */
+/*
+ * Duplicate event filtering time.
+ * Sequential, identical KIND_FILTERED inputs with less than
+ * FILTER_TIME milliseconds between them are considered as repeat
+ * events. The hardware generates 5 events for the first keypress
+ * and we have to take this into account for an accurate repeat
+ * behaviour.
+ */
+#define FILTER_TIME 60 /* msec */
+
static unsigned long channel_mask;
-module_param(channel_mask, ulong, 0444);
+module_param(channel_mask, ulong, 0644);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
static int debug;
-module_param(debug, int, 0444);
+module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+static int repeat_filter = FILTER_TIME;
+module_param(repeat_filter, int, 0644);
+MODULE_PARM_DESC(repeat_filter, "Repeat filter time, default = 60 msec");
+
#define dbginfo(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
#undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg)
@@ -144,19 +157,6 @@ MODULE_DEVICE_TABLE(usb, ati_remote_table);
static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
-/* Acceleration curve for directional control pad */
-static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
-
-/* Duplicate event filtering time.
- * Sequential, identical KIND_FILTERED inputs with less than
- * FILTER_TIME jiffies between them are considered as repeat
- * events. The hardware generates 5 events for the first keypress
- * and we have to take this into account for an accurate repeat
- * behaviour.
- * (HZ / 20) == 50 ms and works well for me.
- */
-#define FILTER_TIME (HZ / 20)
-
struct ati_remote {
struct input_dev *idev;
struct usb_device *udev;
@@ -414,6 +414,43 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
}
/*
+ * ati_remote_compute_accel
+ *
+ * Implements acceleration curve for directional control pad
+ * If elapsed time since last event is > 1/4 second, user "stopped",
+ * so reset acceleration. Otherwise, user is probably holding the control
+ * pad down, so we increase acceleration, ramping up over two seconds to
+ * a maximum speed.
+ */
+static int ati_remote_compute_accel(struct ati_remote *ati_remote)
+{
+ static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
+ unsigned long now = jiffies;
+ int acc;
+
+ if (time_after(now, ati_remote->old_jiffies + msecs_to_jiffies(250))) {
+ acc = 1;
+ ati_remote->acc_jiffies = now;
+ }
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(125)))
+ acc = accel[0];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(250)))
+ acc = accel[1];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(500)))
+ acc = accel[2];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1000)))
+ acc = accel[3];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(1500)))
+ acc = accel[4];
+ else if (time_before(now, ati_remote->acc_jiffies + msecs_to_jiffies(2000)))
+ acc = accel[5];
+ else
+ acc = accel[6];
+
+ return acc;
+}
+
+/*
* ati_remote_report_input
*/
static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
@@ -466,9 +503,9 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
if (ati_remote_tbl[index].kind == KIND_FILTERED) {
/* Filter duplicate events which happen "too close" together. */
- if ((ati_remote->old_data[0] == data[1]) &&
- (ati_remote->old_data[1] == data[2]) &&
- time_before(jiffies, ati_remote->old_jiffies + FILTER_TIME)) {
+ if (ati_remote->old_data[0] == data[1] &&
+ ati_remote->old_data[1] == data[2] &&
+ time_before(jiffies, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) {
ati_remote->repeat_count++;
} else {
ati_remote->repeat_count = 0;
@@ -478,75 +515,61 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
ati_remote->old_data[1] = data[2];
ati_remote->old_jiffies = jiffies;
- if ((ati_remote->repeat_count > 0)
- && (ati_remote->repeat_count < 5))
+ if (ati_remote->repeat_count > 0 &&
+ ati_remote->repeat_count < 5)
return;
input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 1);
+ input_sync(dev);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 0);
input_sync(dev);
- return;
- }
+ } else {
- /*
- * Other event kinds are from the directional control pad, and have an
- * acceleration factor applied to them. Without this acceleration, the
- * control pad is mostly unusable.
- *
- * If elapsed time since last event is > 1/4 second, user "stopped",
- * so reset acceleration. Otherwise, user is probably holding the control
- * pad down, so we increase acceleration, ramping up over two seconds to
- * a maximum speed. The acceleration curve is #defined above.
- */
- if (time_after(jiffies, ati_remote->old_jiffies + (HZ >> 2))) {
- acc = 1;
- ati_remote->acc_jiffies = jiffies;
- }
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 3))) acc = accel[0];
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 2))) acc = accel[1];
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 1))) acc = accel[2];
- else if (time_before(jiffies, ati_remote->acc_jiffies + HZ)) acc = accel[3];
- else if (time_before(jiffies, ati_remote->acc_jiffies + HZ+(HZ>>1))) acc = accel[4];
- else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ << 1))) acc = accel[5];
- else acc = accel[6];
-
- input_regs(dev, regs);
- switch (ati_remote_tbl[index].kind) {
- case KIND_ACCEL:
- input_event(dev, ati_remote_tbl[index].type,
- ati_remote_tbl[index].code,
- ati_remote_tbl[index].value * acc);
- break;
- case KIND_LU:
- input_report_rel(dev, REL_X, -acc);
- input_report_rel(dev, REL_Y, -acc);
- break;
- case KIND_RU:
- input_report_rel(dev, REL_X, acc);
- input_report_rel(dev, REL_Y, -acc);
- break;
- case KIND_LD:
- input_report_rel(dev, REL_X, -acc);
- input_report_rel(dev, REL_Y, acc);
- break;
- case KIND_RD:
- input_report_rel(dev, REL_X, acc);
- input_report_rel(dev, REL_Y, acc);
- break;
- default:
- dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
- ati_remote_tbl[index].kind);
- }
- input_sync(dev);
+ /*
+ * Other event kinds are from the directional control pad, and have an
+ * acceleration factor applied to them. Without this acceleration, the
+ * control pad is mostly unusable.
+ */
+ acc = ati_remote_compute_accel(ati_remote);
+
+ input_regs(dev, regs);
+ switch (ati_remote_tbl[index].kind) {
+ case KIND_ACCEL:
+ input_event(dev, ati_remote_tbl[index].type,
+ ati_remote_tbl[index].code,
+ ati_remote_tbl[index].value * acc);
+ break;
+ case KIND_LU:
+ input_report_rel(dev, REL_X, -acc);
+ input_report_rel(dev, REL_Y, -acc);
+ break;
+ case KIND_RU:
+ input_report_rel(dev, REL_X, acc);
+ input_report_rel(dev, REL_Y, -acc);
+ break;
+ case KIND_LD:
+ input_report_rel(dev, REL_X, -acc);
+ input_report_rel(dev, REL_Y, acc);
+ break;
+ case KIND_RD:
+ input_report_rel(dev, REL_X, acc);
+ input_report_rel(dev, REL_Y, acc);
+ break;
+ default:
+ dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+ ati_remote_tbl[index].kind);
+ }
+ input_sync(dev);
- ati_remote->old_jiffies = jiffies;
- ati_remote->old_data[0] = data[1];
- ati_remote->old_data[1] = data[2];
+ ati_remote->old_jiffies = jiffies;
+ ati_remote->old_data[0] = data[1];
+ ati_remote->old_data[1] = data[2];
+ }
}
/*
@@ -709,12 +732,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
endpoint_in = &iface_host->endpoint[0].desc;
endpoint_out = &iface_host->endpoint[1].desc;
- if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) {
- err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
- return -ENODEV;
- }
- if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
- err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
+ if (!usb_endpoint_is_int_in(endpoint_in)) {
+ err("%s: Unexpected endpoint_in\n", __FUNCTION__);
return -ENODEV;
}
if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
diff --git a/drivers/usb/input/fixp-arith.h b/drivers/usb/input/fixp-arith.h
index b44d398de07..ed3d2da0c48 100644
--- a/drivers/usb/input/fixp-arith.h
+++ b/drivers/usb/input/fixp-arith.h
@@ -2,8 +2,6 @@
#define _FIXP_ARITH_H
/*
- * $$
- *
* Simplistic fixed-point arithmetics.
* Hmm, I'm probably duplicating some code :(
*
@@ -31,20 +29,20 @@
#include <linux/types.h>
-// The type representing fixed-point values
+/* The type representing fixed-point values */
typedef s16 fixp_t;
#define FRAC_N 8
#define FRAC_MASK ((1<<FRAC_N)-1)
-// Not to be used directly. Use fixp_{cos,sin}
-static const fixp_t cos_table[45] = {
+/* Not to be used directly. Use fixp_{cos,sin} */
+static const fixp_t cos_table[46] = {
0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8,
0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD,
0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1,
0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078,
0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035,
- 0x002C, 0x0023, 0x001A, 0x0011, 0x0008
+ 0x002C, 0x0023, 0x001A, 0x0011, 0x0008, 0x0000
};
@@ -68,9 +66,8 @@ static inline fixp_t fixp_cos(unsigned int degrees)
int quadrant = (degrees / 90) & 3;
unsigned int i = degrees % 90;
- if (quadrant == 1 || quadrant == 3) {
- i = 89 - i;
- }
+ if (quadrant == 1 || quadrant == 3)
+ i = 90 - i;
i >>= 1;
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index b9fb9687f92..81b1ea01a17 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1023,7 +1023,8 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
- case -ETIMEDOUT: /* NAK */
+ case -ETIME: /* protocol error or unplug */
+ case -ETIMEDOUT: /* Should never happen, but... */
clear_bit(HID_IN_RUNNING, &hid->iofl);
hid_io_error(hid);
return;
@@ -1411,17 +1412,54 @@ void hid_init_reports(struct hid_device *hid)
warn("timeout initializing reports");
}
+#define USB_VENDOR_ID_GTCO 0x078c
+#define USB_DEVICE_ID_GTCO_90 0x0090
+#define USB_DEVICE_ID_GTCO_100 0x0100
+#define USB_DEVICE_ID_GTCO_101 0x0101
+#define USB_DEVICE_ID_GTCO_103 0x0103
+#define USB_DEVICE_ID_GTCO_104 0x0104
+#define USB_DEVICE_ID_GTCO_105 0x0105
+#define USB_DEVICE_ID_GTCO_106 0x0106
+#define USB_DEVICE_ID_GTCO_107 0x0107
+#define USB_DEVICE_ID_GTCO_108 0x0108
+#define USB_DEVICE_ID_GTCO_200 0x0200
+#define USB_DEVICE_ID_GTCO_201 0x0201
+#define USB_DEVICE_ID_GTCO_202 0x0202
+#define USB_DEVICE_ID_GTCO_203 0x0203
+#define USB_DEVICE_ID_GTCO_204 0x0204
+#define USB_DEVICE_ID_GTCO_205 0x0205
+#define USB_DEVICE_ID_GTCO_206 0x0206
+#define USB_DEVICE_ID_GTCO_207 0x0207
+#define USB_DEVICE_ID_GTCO_300 0x0300
+#define USB_DEVICE_ID_GTCO_301 0x0301
+#define USB_DEVICE_ID_GTCO_302 0x0302
+#define USB_DEVICE_ID_GTCO_303 0x0303
+#define USB_DEVICE_ID_GTCO_304 0x0304
+#define USB_DEVICE_ID_GTCO_305 0x0305
+#define USB_DEVICE_ID_GTCO_306 0x0306
+#define USB_DEVICE_ID_GTCO_307 0x0307
+#define USB_DEVICE_ID_GTCO_308 0x0308
+#define USB_DEVICE_ID_GTCO_309 0x0309
+#define USB_DEVICE_ID_GTCO_400 0x0400
+#define USB_DEVICE_ID_GTCO_401 0x0401
+#define USB_DEVICE_ID_GTCO_402 0x0402
+#define USB_DEVICE_ID_GTCO_403 0x0403
+#define USB_DEVICE_ID_GTCO_404 0x0404
+#define USB_DEVICE_ID_GTCO_405 0x0405
+#define USB_DEVICE_ID_GTCO_500 0x0500
+#define USB_DEVICE_ID_GTCO_501 0x0501
+#define USB_DEVICE_ID_GTCO_502 0x0502
+#define USB_DEVICE_ID_GTCO_503 0x0503
+#define USB_DEVICE_ID_GTCO_504 0x0504
+#define USB_DEVICE_ID_GTCO_1000 0x1000
+#define USB_DEVICE_ID_GTCO_1001 0x1001
+#define USB_DEVICE_ID_GTCO_1002 0x1002
+#define USB_DEVICE_ID_GTCO_1003 0x1003
+#define USB_DEVICE_ID_GTCO_1004 0x1004
+#define USB_DEVICE_ID_GTCO_1005 0x1005
+#define USB_DEVICE_ID_GTCO_1006 0x1006
+
#define USB_VENDOR_ID_WACOM 0x056a
-#define USB_DEVICE_ID_WACOM_PENPARTNER 0x0000
-#define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS 0x0020
-#define USB_DEVICE_ID_WACOM_PL 0x0030
-#define USB_DEVICE_ID_WACOM_INTUOS2 0x0040
-#define USB_DEVICE_ID_WACOM_VOLITO 0x0060
-#define USB_DEVICE_ID_WACOM_PTU 0x0003
-#define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0
-#define USB_DEVICE_ID_WACOM_CINTIQ 0x003F
-#define USB_DEVICE_ID_WACOM_DTF 0x00C0
#define USB_VENDOR_ID_ACECAD 0x0460
#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
@@ -1498,15 +1536,22 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
-#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
+#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
#define USB_VENDOR_ID_CODEMERCS 0x07c0
#define USB_DEVICE_ID_CODEMERCS_IOW40 0x1500
#define USB_DEVICE_ID_CODEMERCS_IOW24 0x1501
@@ -1551,6 +1596,13 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+
+#define USB_VENDOR_ID_ALCOR 0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
+
+#define USB_VENDOR_ID_SUN 0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -1568,6 +1620,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
@@ -1580,11 +1633,59 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
@@ -1605,7 +1706,11 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
@@ -1614,51 +1719,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 7, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 8, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 9, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 7, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_VOLITO + 4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 6, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PTU, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS3 + 5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_CINTIQ, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_DTF + 3, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
@@ -1669,7 +1732,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
{ USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
@@ -1774,6 +1839,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
char *rdesc;
int n, len, insize = 0;
+ /* Ignore all Wacom devices */
+ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM)
+ return NULL;
+
for (n = 0; hid_blacklist[n].idVendor; n++)
if ((hid_blacklist[n].idVendor == le16_to_cpu(dev->descriptor.idVendor)) &&
(hid_blacklist[n].idProduct == le16_to_cpu(dev->descriptor.idProduct)))
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
index 702c48c2f81..f04d6d75c09 100644
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/usb/input/hid-debug.h
@@ -563,7 +563,7 @@ static char *keys[KEY_MAX + 1] = {
[KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power",
[KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus",
[KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma",
- [KEY_HANGUEL] = "Hanguel", [KEY_HANJA] = "Hanja",
+ [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja",
[KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta",
[KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose",
[KEY_STOP] = "Stop", [KEY_AGAIN] = "Again",
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 028e1ad89f5..7208839f2db 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -607,7 +607,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
- if (usage->hat_min < usage->hat_max || usage->hat_dir) {
+ if (usage->type == EV_ABS &&
+ (usage->hat_min < usage->hat_max || usage->hat_dir)) {
int i;
for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
input_set_abs_params(input, i, -1, 1, 0, 0);
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index c4670e1d465..a2b419d1374 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -25,7 +25,6 @@
* e-mail - mail your message to Paul Stewart <stewart@wetlogic.net>
*/
-#include <linux/config.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -50,7 +49,7 @@ struct hiddev {
int open;
wait_queue_head_t wait;
struct hid_device *hid;
- struct hiddev_list *list;
+ struct list_head list;
};
struct hiddev_list {
@@ -60,7 +59,7 @@ struct hiddev_list {
unsigned flags;
struct fasync_struct *fasync;
struct hiddev *hiddev;
- struct hiddev_list *next;
+ struct list_head node;
};
static struct hiddev *hiddev_table[HIDDEV_MINORS];
@@ -74,12 +73,15 @@ static struct hiddev *hiddev_table[HIDDEV_MINORS];
static struct hid_report *
hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
{
- unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
+ unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK;
+ unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK;
struct hid_report_enum *report_enum;
+ struct hid_report *report;
struct list_head *list;
if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
- rinfo->report_type > HID_REPORT_TYPE_MAX) return NULL;
+ rinfo->report_type > HID_REPORT_TYPE_MAX)
+ return NULL;
report_enum = hid->report_enum +
(rinfo->report_type - HID_REPORT_TYPE_MIN);
@@ -89,21 +91,25 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
break;
case HID_REPORT_ID_FIRST:
- list = report_enum->report_list.next;
- if (list == &report_enum->report_list)
+ if (list_empty(&report_enum->report_list))
return NULL;
- rinfo->report_id = ((struct hid_report *) list)->id;
+
+ list = report_enum->report_list.next;
+ report = list_entry(list, struct hid_report, list);
+ rinfo->report_id = report->id;
break;
case HID_REPORT_ID_NEXT:
- list = (struct list_head *)
- report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
- if (list == NULL)
+ report = report_enum->report_id_hash[rid];
+ if (!report)
return NULL;
- list = list->next;
+
+ list = report->list.next;
if (list == &report_enum->report_list)
return NULL;
- rinfo->report_id = ((struct hid_report *) list)->id;
+
+ report = list_entry(list, struct hid_report, list);
+ rinfo->report_id = report->id;
break;
default:
@@ -126,12 +132,13 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
struct hid_field *field;
if (uref->report_type < HID_REPORT_TYPE_MIN ||
- uref->report_type > HID_REPORT_TYPE_MAX) return NULL;
+ uref->report_type > HID_REPORT_TYPE_MAX)
+ return NULL;
report_enum = hid->report_enum +
(uref->report_type - HID_REPORT_TYPE_MIN);
- list_for_each_entry(report, &report_enum->report_list, list)
+ list_for_each_entry(report, &report_enum->report_list, list) {
for (i = 0; i < report->maxfield; i++) {
field = report->field[i];
for (j = 0; j < field->maxusage; j++) {
@@ -143,6 +150,7 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
}
}
}
+ }
return NULL;
}
@@ -151,9 +159,9 @@ static void hiddev_send_event(struct hid_device *hid,
struct hiddev_usage_ref *uref)
{
struct hiddev *hiddev = hid->hiddev;
- struct hiddev_list *list = hiddev->list;
+ struct hiddev_list *list;
- while (list) {
+ list_for_each_entry(list, &hiddev->list, node) {
if (uref->field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) {
list->buffer[list->head] = *uref;
@@ -161,8 +169,6 @@ static void hiddev_send_event(struct hid_device *hid,
(HIDDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
-
- list = list->next;
}
wake_up_interruptible(&hiddev->wait);
@@ -181,7 +187,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
- ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
+ ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
uref.report_id = field->report->id;
uref.field_index = field->index;
uref.usage_index = (usage - field->usage);
@@ -201,7 +207,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
- ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
+ ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0));
uref.report_id = report->id;
uref.field_index = HID_FIELD_INDEX_NONE;
@@ -214,7 +220,9 @@ static int hiddev_fasync(int fd, struct file *file, int on)
{
int retval;
struct hiddev_list *list = file->private_data;
+
retval = fasync_helper(fd, file, on, &list->fasync);
+
return retval < 0 ? retval : 0;
}
@@ -225,14 +233,9 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static int hiddev_release(struct inode * inode, struct file * file)
{
struct hiddev_list *list = file->private_data;
- struct hiddev_list **listptr;
- listptr = &list->hiddev->list;
hiddev_fasync(-1, file, 0);
-
- while (*listptr && (*listptr != list))
- listptr = &((*listptr)->next);
- *listptr = (*listptr)->next;
+ list_del(&list->node);
if (!--list->hiddev->open) {
if (list->hiddev->exist)
@@ -249,7 +252,8 @@ static int hiddev_release(struct inode * inode, struct file * file)
/*
* open file op
*/
-static int hiddev_open(struct inode * inode, struct file * file) {
+static int hiddev_open(struct inode *inode, struct file *file)
+{
struct hiddev_list *list;
int i = iminor(inode) - HIDDEV_MINOR_BASE;
@@ -261,9 +265,7 @@ static int hiddev_open(struct inode * inode, struct file * file) {
return -ENOMEM;
list->hiddev = hiddev_table[i];
- list->next = hiddev_table[i]->list;
- hiddev_table[i]->list = list;
-
+ list_add_tail(&list->node, &hiddev_table[i]->list);
file->private_data = list;
if (!list->hiddev->open++)
@@ -363,6 +365,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
static unsigned int hiddev_poll(struct file *file, poll_table *wait)
{
struct hiddev_list *list = file->private_data;
+
poll_wait(file, &list->hiddev->wait, wait);
if (list->head != list->tail)
return POLLIN | POLLRDNORM;
@@ -383,7 +386,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
- struct hiddev_usage_ref_multi *uref_multi=NULL;
+ struct hiddev_usage_ref_multi *uref_multi = NULL;
struct hiddev_usage_ref *uref;
struct hiddev_devinfo dinfo;
struct hid_report *report;
@@ -719,7 +722,7 @@ inval:
return -EINVAL;
}
-static struct file_operations hiddev_fops = {
+static const struct file_operations hiddev_fops = {
.owner = THIS_MODULE,
.read = hiddev_read,
.write = hiddev_write,
@@ -765,15 +768,15 @@ int hiddev_connect(struct hid_device *hid)
}
init_waitqueue_head(&hiddev->wait);
-
- hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
-
+ INIT_LIST_HEAD(&hiddev->list);
hiddev->hid = hid;
hiddev->exist = 1;
hid->minor = hid->intf->minor;
hid->hiddev = hiddev;
+ hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+
return 0;
}
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
index 5c570cc703f..61966d719ca 100644
--- a/drivers/usb/input/itmtouch.c
+++ b/drivers/usb/input/itmtouch.c
@@ -39,7 +39,6 @@
*
*****************************************************************************/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -88,7 +87,7 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c
index 70af985b5db..a9035955157 100644
--- a/drivers/usb/input/keyspan_remote.c
+++ b/drivers/usb/input/keyspan_remote.c
@@ -11,7 +11,6 @@
* and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -421,8 +420,7 @@ static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_i
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
endpoint = &iface->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ if (usb_endpoint_is_int_in(endpoint)) {
/* we found our interrupt in endpoint */
return endpoint;
}
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
index 4fdee4db072..5dce951f275 100644
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -39,7 +39,6 @@
*
*****************************************************************************/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -108,7 +107,7 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index b3c0d0c3eae..f0f8db6810a 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -313,9 +313,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
- if (!(endpoint->bEndpointAddress & 0x80))
- return -EIO;
- if ((endpoint->bmAttributes & 3) != 3)
+ if (!usb_endpoint_is_int_in(endpoint))
return -EIO;
usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index da7b0bf51af..30b9f820e7a 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -24,7 +24,6 @@
//#define DEBUG
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -202,7 +201,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
diff --git a/drivers/usb/input/trancevibrator.c b/drivers/usb/input/trancevibrator.c
new file mode 100644
index 00000000000..33cd91d11ec
--- /dev/null
+++ b/drivers/usb/input/trancevibrator.c
@@ -0,0 +1,159 @@
+/*
+ * PlayStation 2 Trance Vibrator driver
+ *
+ * Copyright (C) 2006 Sam Hocevar <sam@zoy.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Standard include files */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v1.1"
+#define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org"
+#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver"
+
+#define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */
+#define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
+ { },
+};
+MODULE_DEVICE_TABLE (usb, id_table);
+
+/* Driver-local specific stuff */
+struct trancevibrator {
+ struct usb_device *udev;
+ unsigned int speed;
+};
+
+static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct trancevibrator *tv = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d\n", tv->speed);
+}
+
+static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct trancevibrator *tv = usb_get_intfdata(intf);
+ int temp, retval;
+
+ temp = simple_strtoul(buf, NULL, 10);
+ if (temp > 255)
+ temp = 255;
+ else if (temp < 0)
+ temp = 0;
+ tv->speed = temp;
+
+ dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
+
+ /* Set speed */
+ retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
+ 0x01, /* vendor request: set speed */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ tv->speed, /* speed value */
+ 0, NULL, 0, USB_CTRL_GET_TIMEOUT);
+ if (retval) {
+ dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
+ return retval;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+
+static int tv_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct trancevibrator *dev;
+ int retval;
+
+ dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev->udev = usb_get_dev(udev);
+ usb_set_intfdata(interface, dev);
+ retval = device_create_file(&interface->dev, &dev_attr_speed);
+ if (retval)
+ goto error_create_file;
+
+ return 0;
+
+error_create_file:
+ usb_put_dev(udev);
+ usb_set_intfdata(interface, NULL);
+error:
+ kfree(dev);
+ return retval;
+}
+
+static void tv_disconnect(struct usb_interface *interface)
+{
+ struct trancevibrator *dev;
+
+ dev = usb_get_intfdata (interface);
+ usb_set_intfdata(interface, NULL);
+ device_remove_file(&interface->dev, &dev_attr_speed);
+ usb_put_dev(dev->udev);
+ kfree(dev);
+}
+
+/* USB subsystem object */
+static struct usb_driver tv_driver = {
+ .name = "trancevibrator",
+ .probe = tv_probe,
+ .disconnect = tv_disconnect,
+ .id_table = id_table,
+};
+
+static int __init tv_init(void)
+{
+ int retval = usb_register(&tv_driver);
+ if (retval) {
+ err("usb_register failed. Error number %d", retval);
+ return retval;
+ }
+
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+ return 0;
+}
+
+static void __exit tv_exit(void)
+{
+ usb_deregister(&tv_driver);
+}
+
+module_init (tv_init);
+module_exit (tv_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 446935b671d..0fb792be95e 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -218,7 +218,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(3, 1, 2) },
- { } /* Terminating entry */
+ { } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c
index 3b175aa482c..4640d1000d8 100644
--- a/drivers/usb/input/usbtouchscreen.c
+++ b/drivers/usb/input/usbtouchscreen.c
@@ -2,9 +2,12 @@
* usbtouchscreen.c
* Driver for USB Touchscreens, supporting those devices:
* - eGalax Touchkit
- * - 3M/Microtouch
+ * includes eTurboTouch CT-410/510/700
+ * - 3M/Microtouch EX II series
* - ITM
* - PanJit TouchSet
+ * - eTurboTouch
+ * - Gunze AHL61
*
* Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -42,7 +45,7 @@
#include <linux/usb/input.h>
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>"
#define DRIVER_DESC "USB Touchscreen Driver"
@@ -60,6 +63,7 @@ struct usbtouch_device_info {
int flags;
void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len);
+ int (*get_pkt_len) (unsigned char *pkt, int len);
int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press);
int (*init) (struct usbtouch_usb *usbtouch);
};
@@ -81,8 +85,16 @@ struct usbtouch_usb {
char phys[64];
};
-static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
- struct pt_regs *regs, unsigned char *pkt, int len);
+
+#if defined(CONFIG_USB_TOUCHSCREEN_EGALAX) || defined(CONFIG_USB_TOUCHSCREEN_ETURBO)
+#define MULTI_PACKET
+#endif
+
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+ struct pt_regs *regs,
+ unsigned char *pkt, int len);
+#endif
/* device types */
enum {
@@ -91,14 +103,19 @@ enum {
DEVTYPE_PANJIT,
DEVTYPE_3M,
DEVTYPE_ITM,
+ DEVTYPE_ETURBO,
+ DEVTYPE_GUNZE,
};
static struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
#endif
#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
@@ -116,6 +133,14 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
#endif
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+ {USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
+ {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
+#endif
+
{}
};
@@ -140,82 +165,23 @@ static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
*touch = pkt[0] & 0x01;
return 1;
-
}
-static int egalax_get_pkt_len(unsigned char *buf)
+static int egalax_get_pkt_len(unsigned char *buf, int len)
{
switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
case EGALAX_PKT_TYPE_REPT:
return 5;
case EGALAX_PKT_TYPE_DIAG:
+ if (len < 2)
+ return -1;
+
return buf[1] + 2;
}
return 0;
}
-
-static void egalax_process(struct usbtouch_usb *usbtouch, struct pt_regs *regs,
- unsigned char *pkt, int len)
-{
- unsigned char *buffer;
- int pkt_len, buf_len, pos;
-
- /* if the buffer contains data, append */
- if (unlikely(usbtouch->buf_len)) {
- int tmp;
-
- /* if only 1 byte in buffer, add another one to get length */
- if (usbtouch->buf_len == 1)
- usbtouch->buffer[1] = pkt[0];
-
- pkt_len = egalax_get_pkt_len(usbtouch->buffer);
-
- /* unknown packet: drop everything */
- if (!pkt_len)
- return;
-
- /* append, process */
- tmp = pkt_len - usbtouch->buf_len;
- memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
- usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len);
-
- buffer = pkt + tmp;
- buf_len = len - tmp;
- } else {
- buffer = pkt;
- buf_len = len;
- }
-
- /* only one byte left in buffer */
- if (unlikely(buf_len == 1)) {
- usbtouch->buffer[0] = buffer[0];
- usbtouch->buf_len = 1;
- return;
- }
-
- /* loop over the buffer */
- pos = 0;
- while (pos < buf_len) {
- /* get packet len */
- pkt_len = egalax_get_pkt_len(buffer + pos);
-
- /* unknown packet: drop everything */
- if (unlikely(!pkt_len))
- return;
-
- /* full packet: process */
- if (likely(pkt_len <= buf_len)) {
- usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len);
- } else {
- /* incomplete packet: save in buffer */
- memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
- usbtouch->buf_len = buf_len - pos;
- }
- pos += pkt_len;
- }
-}
#endif
@@ -254,7 +220,7 @@ static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
static int mtouch_init(struct usbtouch_usb *usbtouch)
{
- int ret;
+ int ret, i;
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
MTOUCHUSB_RESET,
@@ -264,15 +230,20 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
__FUNCTION__, ret);
if (ret < 0)
return ret;
-
- ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
- MTOUCHUSB_ASYNC_REPORT,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
- __FUNCTION__, ret);
- if (ret < 0)
- return ret;
+ msleep(150);
+
+ for (i = 0; i < 3; i++) {
+ ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ MTOUCHUSB_ASYNC_REPORT,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
+ __FUNCTION__, ret);
+ if (ret >= 0)
+ break;
+ if (ret != -EPIPE)
+ return ret;
+ }
return 0;
}
@@ -286,7 +257,7 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
{
*x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
- *x = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
+ *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
*press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F);
*touch = ~pkt[7] & 0x20;
@@ -296,6 +267,54 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr
/*****************************************************************************
+ * eTurboTouch part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+{
+ unsigned int shift;
+
+ /* packets should start with sync */
+ if (!(pkt[0] & 0x80))
+ return 0;
+
+ shift = (6 - (pkt[0] & 0x03));
+ *x = ((pkt[3] << 7) | pkt[4]) >> shift;
+ *y = ((pkt[1] << 7) | pkt[2]) >> shift;
+ *touch = (pkt[0] & 0x10) ? 1 : 0;
+
+ return 1;
+}
+
+static int eturbo_get_pkt_len(unsigned char *buf, int len)
+{
+ if (buf[0] & 0x80)
+ return 5;
+ if (buf[0] == 0x01)
+ return 3;
+ return 0;
+}
+#endif
+
+
+/*****************************************************************************
+ * Gunze part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
+static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+{
+ if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
+ return 0;
+
+ *x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
+ *y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
+ *touch = pkt[0] & 0x20;
+
+ return 1;
+}
+#endif
+
+/*****************************************************************************
* the different device descriptors
*/
static struct usbtouch_device_info usbtouch_dev_info[] = {
@@ -307,7 +326,8 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.max_yc = 0x07ff,
.rept_size = 16,
.flags = USBTOUCH_FLG_BUFFER,
- .process_pkt = egalax_process,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = egalax_get_pkt_len,
.read_data = egalax_read_data,
},
#endif
@@ -346,6 +366,31 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = itm_read_data,
},
#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+ [DEVTYPE_ETURBO] = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 8,
+ .flags = USBTOUCH_FLG_BUFFER,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = eturbo_get_pkt_len,
+ .read_data = eturbo_read_data,
+ },
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
+ [DEVTYPE_GUNZE] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = gunze_read_data,
+ },
+#endif
};
@@ -377,6 +422,83 @@ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
}
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+ struct pt_regs *regs,
+ unsigned char *pkt, int len)
+{
+ unsigned char *buffer;
+ int pkt_len, pos, buf_len, tmp;
+
+ /* process buffer */
+ if (unlikely(usbtouch->buf_len)) {
+ /* try to get size */
+ pkt_len = usbtouch->type->get_pkt_len(
+ usbtouch->buffer, usbtouch->buf_len);
+
+ /* drop? */
+ if (unlikely(!pkt_len))
+ goto out_flush_buf;
+
+ /* need to append -pkt_len bytes before able to get size */
+ if (unlikely(pkt_len < 0)) {
+ int append = -pkt_len;
+ if (unlikely(append > len))
+ append = len;
+ if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
+ goto out_flush_buf;
+ memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
+ usbtouch->buf_len += append;
+
+ pkt_len = usbtouch->type->get_pkt_len(
+ usbtouch->buffer, usbtouch->buf_len);
+ if (pkt_len < 0)
+ return;
+ }
+
+ /* append */
+ tmp = pkt_len - usbtouch->buf_len;
+ if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
+ goto out_flush_buf;
+ memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
+ usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len);
+
+ buffer = pkt + tmp;
+ buf_len = len - tmp;
+ } else {
+ buffer = pkt;
+ buf_len = len;
+ }
+
+ /* loop over the received packet, process */
+ pos = 0;
+ while (pos < buf_len) {
+ /* get packet len */
+ pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len);
+
+ /* unknown packet: drop everything */
+ if (unlikely(!pkt_len))
+ goto out_flush_buf;
+
+ /* full packet: process */
+ if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
+ usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len);
+ } else {
+ /* incomplete packet: save in buffer */
+ memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
+ usbtouch->buf_len = buf_len - pos;
+ return;
+ }
+ pos += pkt_len;
+ }
+
+out_flush_buf:
+ usbtouch->buf_len = 0;
+ return;
+}
+#endif
+
+
static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
{
struct usbtouch_usb *usbtouch = urb->context;
@@ -386,7 +508,7 @@ static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
@@ -452,7 +574,7 @@ static int usbtouch_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
struct usbtouch_device_info *type;
- int err;
+ int err = -ENOMEM;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
@@ -526,6 +648,7 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->data, type->rept_size,
usbtouch_irq, usbtouch, endpoint->bInterval);
+ usbtouch->irq->dev = usbtouch->udev;
usbtouch->irq->transfer_dma = usbtouch->data_dma;
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -553,7 +676,7 @@ out_free_buffers:
out_free:
input_free_device(input_dev);
kfree(usbtouch);
- return -ENOMEM;
+ return err;
}
static void usbtouch_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
deleted file mode 100644
index 369461a70b7..00000000000
--- a/drivers/usb/input/wacom.c
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * USB Wacom Graphire and Wacom Intuos tablet support
- *
- * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
- * Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
- * Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
- * Copyright (c) 2000 James E. Blair <corvus@gnu.org>
- * Copyright (c) 2000 Daniel Egger <egger@suse.de>
- * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
- * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
- * Copyright (c) 2002-2006 Ping Cheng <pingc@wacom.com>
- *
- * ChangeLog:
- * v0.1 (vp) - Initial release
- * v0.2 (aba) - Support for all buttons / combinations
- * v0.3 (vp) - Support for Intuos added
- * v0.4 (sm) - Support for more Intuos models, menustrip
- * relative mode, proximity.
- * v0.5 (vp) - Big cleanup, nifty features removed,
- * they belong in userspace
- * v1.8 (vp) - Submit URB only when operating, moved to CVS,
- * use input_report_key instead of report_btn and
- * other cleanups
- * v1.11 (vp) - Add URB ->dev setting for new kernels
- * v1.11 (jb) - Add support for the 4D Mouse & Lens
- * v1.12 (de) - Add support for two more inking pen IDs
- * v1.14 (vp) - Use new USB device id probing scheme.
- * Fix Wacom Graphire mouse wheel
- * v1.18 (vp) - Fix mouse wheel direction
- * Make mouse relative
- * v1.20 (fl) - Report tool id for Intuos devices
- * - Multi tools support
- * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
- * - Add PL models support
- * - Fix Wacom Graphire mouse wheel again
- * v1.21 (vp) - Removed protocol descriptions
- * - Added MISC_SERIAL for tool serial numbers
- * (gb) - Identify version on module load.
- * v1.21.1 (fl) - added Graphire2 support
- * v1.21.2 (fl) - added Intuos2 support
- * - added all the PL ids
- * v1.21.3 (fl) - added another eraser id from Neil Okamoto
- * - added smooth filter for Graphire from Peri Hankey
- * - added PenPartner support from Olaf van Es
- * - new tool ids from Ole Martin Bjoerndalen
- * v1.29 (pc) - Add support for more tablets
- * - Fix pressure reporting
- * v1.30 (vp) - Merge 2.4 and 2.5 drivers
- * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
- * - Cleanups here and there
- * v1.30.1 (pi) - Added Graphire3 support
- * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
- * v1.43 (pc) - Added support for Cintiq 21UX
- * - Fixed a Graphire bug
- * - Merged wacom_intuos3_irq into wacom_intuos_irq
- * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
- * - Report Device IDs
- * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
- * - Minor data report fix
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.45"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_WACOM 0x056a
-#define STYLUS_DEVICE_ID 0x02
-#define CURSOR_DEVICE_ID 0x06
-#define ERASER_DEVICE_ID 0x0A
-
-enum {
- PENPARTNER = 0,
- GRAPHIRE,
- WACOM_G4,
- PL,
- INTUOS,
- INTUOS3,
- INTUOS312,
- INTUOS319,
- CINTIQ,
- MAX_TYPE
-};
-
-struct wacom_features {
- char *name;
- int pktlen;
- int x_max;
- int y_max;
- int pressure_max;
- int distance_max;
- int type;
- usb_complete_t irq;
-};
-
-struct wacom {
- signed char *data;
- dma_addr_t data_dma;
- struct input_dev *dev;
- struct usb_device *usbdev;
- struct urb *irq;
- struct wacom_features *features;
- int tool[2];
- int id[2];
- __u32 serial[2];
- char phys[32];
-};
-
-#define USB_REQ_GET_REPORT 0x01
-#define USB_REQ_SET_REPORT 0x09
-
-static int usb_get_report(struct usb_interface *intf, unsigned char type,
- unsigned char id, void *buf, int size)
-{
- return usb_control_msg(interface_to_usbdev(intf),
- usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
- USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
- buf, size, 100);
-}
-
-static int usb_set_report(struct usb_interface *intf, unsigned char type,
- unsigned char id, void *buf, int size)
-{
- return usb_control_msg(interface_to_usbdev(intf),
- usb_sndctrlpipe(interface_to_usbdev(intf), 0),
- USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
- buf, size, 1000);
-}
-
-static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int prox, pressure, id;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2) {
- dbg("wacom_pl_irq: received unknown report #%d", data[0]);
- goto exit;
- }
-
- prox = data[1] & 0x40;
-
- input_regs(dev, regs);
-
- id = ERASER_DEVICE_ID;
- if (prox) {
-
- pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
- if (wacom->features->pressure_max > 255)
- pressure = (pressure << 1) | ((data[4] >> 6) & 1);
- pressure += (wacom->features->pressure_max + 1) / 2;
-
- /*
- * if going from out of proximity into proximity select between the eraser
- * and the pen based on the state of the stylus2 button, choose eraser if
- * pressed else choose pen. if not a proximity change from out to in, send
- * an out of proximity for previous tool then a in for new tool.
- */
- if (!wacom->tool[0]) {
- /* Eraser bit set for DTF */
- if (data[1] & 0x10)
- wacom->tool[1] = BTN_TOOL_RUBBER;
- else
- /* Going into proximity select tool */
- wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- } else {
- /* was entered with stylus2 pressed */
- if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
- /* report out proximity for previous tool */
- input_report_key(dev, wacom->tool[1], 0);
- input_sync(dev);
- wacom->tool[1] = BTN_TOOL_PEN;
- goto exit;
- }
- }
- if (wacom->tool[1] != BTN_TOOL_RUBBER) {
- /* Unknown tool selected default to pen tool */
- wacom->tool[1] = BTN_TOOL_PEN;
- id = STYLUS_DEVICE_ID;
- }
- input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
- input_report_abs(dev, ABS_MISC, id); /* report tool id */
- input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
- input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
- input_report_abs(dev, ABS_PRESSURE, pressure);
-
- input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
- input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
- /* Only allow the stylus2 button to be reported for the pen tool. */
- input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
- } else {
- /* report proximity-out of a (valid) tool */
- if (wacom->tool[1] != BTN_TOOL_RUBBER) {
- /* Unknown tool selected default to pen tool */
- wacom->tool[1] = BTN_TOOL_PEN;
- }
- input_report_key(dev, wacom->tool[1], prox);
- }
-
- wacom->tool[0] = prox; /* Save proximity state */
- input_sync(dev);
-
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int retval, id;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2) {
- printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
- if (data[1] & 0x04) {
- input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
- input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
- id = ERASER_DEVICE_ID;
- } else {
- input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
- input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
- id = STYLUS_DEVICE_ID;
- }
- input_report_abs(dev, ABS_MISC, id); /* report tool id */
- input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2]));
- input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4]));
- input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
- input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
-
- input_sync(dev);
-
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2) {
- printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
- input_report_key(dev, BTN_TOOL_PEN, 1);
- input_report_abs(dev, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
- input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1]));
- input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3]));
- input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
- input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
- input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
- input_sync(dev);
-
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int x, y, id, rw;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] == 99) return; /* for Volito tablets */
-
- if (data[0] != 2) {
- dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
-
- id = STYLUS_DEVICE_ID;
- if (data[1] & 0x10) { /* in prox */
-
- switch ((data[1] >> 5) & 3) {
-
- case 0: /* Pen */
- wacom->tool[0] = BTN_TOOL_PEN;
- break;
-
- case 1: /* Rubber */
- wacom->tool[0] = BTN_TOOL_RUBBER;
- id = ERASER_DEVICE_ID;
- break;
-
- case 2: /* Mouse with wheel */
- input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
- if (wacom->features->type == WACOM_G4) {
- rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
- input_report_rel(dev, REL_WHEEL, -rw);
- } else
- input_report_rel(dev, REL_WHEEL, -(signed char) data[6]);
- /* fall through */
-
- case 3: /* Mouse without wheel */
- wacom->tool[0] = BTN_TOOL_MOUSE;
- id = CURSOR_DEVICE_ID;
- input_report_key(dev, BTN_LEFT, data[1] & 0x01);
- input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
- if (wacom->features->type == WACOM_G4)
- input_report_abs(dev, ABS_DISTANCE, data[6]);
- else
- input_report_abs(dev, ABS_DISTANCE, data[7]);
- break;
- }
- }
-
- if (data[1] & 0x90) {
- x = le16_to_cpu(*(__le16 *) &data[2]);
- y = le16_to_cpu(*(__le16 *) &data[4]);
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
- if (wacom->tool[0] != BTN_TOOL_MOUSE) {
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
- input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
- }
- }
-
- if (data[1] & 0x10)
- input_report_abs(dev, ABS_MISC, id); /* report tool id */
- else
- input_report_abs(dev, ABS_MISC, 0); /* reset tool id */
- input_report_key(dev, wacom->tool[0], data[1] & 0x10);
- input_sync(dev);
-
- /* send pad data */
- if (wacom->features->type == WACOM_G4) {
- if ((wacom->serial[1] & 0xc0) != (data[7] & 0xf8)) {
- wacom->id[1] = 1;
- wacom->serial[1] = (data[7] & 0xf8);
- input_report_key(dev, BTN_0, (data[7] & 0x40));
- input_report_key(dev, BTN_4, (data[7] & 0x80));
- rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
- input_report_rel(dev, REL_WHEEL, rw);
- input_report_key(dev, BTN_TOOL_FINGER, 0xf0);
- input_event(dev, EV_MSC, MSC_SERIAL, 0xf0);
- } else if (wacom->id[1]) {
- wacom->id[1] = 0;
- input_report_key(dev, BTN_TOOL_FINGER, 0);
- input_event(dev, EV_MSC, MSC_SERIAL, 0xf0);
- }
- input_sync(dev);
- }
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static int wacom_intuos_inout(struct urb *urb)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int idx;
-
- /* tool number */
- idx = data[1] & 0x01;
-
- /* Enter report */
- if ((data[1] & 0xfc) == 0xc0) {
- /* serial number of the tool */
- wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
- (data[4] << 20) + (data[5] << 12) +
- (data[6] << 4) + (data[7] >> 4);
-
- wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
- switch (wacom->id[idx]) {
- case 0x812: /* Inking pen */
- case 0x801: /* Intuos3 Inking pen */
- case 0x012:
- wacom->tool[idx] = BTN_TOOL_PENCIL;
- break;
- case 0x822: /* Pen */
- case 0x842:
- case 0x852:
- case 0x823: /* Intuos3 Grip Pen */
- case 0x813: /* Intuos3 Classic Pen */
- case 0x885: /* Intuos3 Marker Pen */
- case 0x022:
- wacom->tool[idx] = BTN_TOOL_PEN;
- break;
- case 0x832: /* Stroke pen */
- case 0x032:
- wacom->tool[idx] = BTN_TOOL_BRUSH;
- break;
- case 0x007: /* Mouse 4D and 2D */
- case 0x09c:
- case 0x094:
- case 0x017: /* Intuos3 2D Mouse */
- wacom->tool[idx] = BTN_TOOL_MOUSE;
- break;
- case 0x096: /* Lens cursor */
- case 0x097: /* Intuos3 Lens cursor */
- wacom->tool[idx] = BTN_TOOL_LENS;
- break;
- case 0x82a: /* Eraser */
- case 0x85a:
- case 0x91a:
- case 0xd1a:
- case 0x0fa:
- case 0x82b: /* Intuos3 Grip Pen Eraser */
- case 0x81b: /* Intuos3 Classic Pen Eraser */
- case 0x91b: /* Intuos3 Airbrush Eraser */
- wacom->tool[idx] = BTN_TOOL_RUBBER;
- break;
- case 0xd12:
- case 0x912:
- case 0x112:
- case 0x913: /* Intuos3 Airbrush */
- wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
- break;
- default: /* Unknown tool */
- wacom->tool[idx] = BTN_TOOL_PEN;
- }
- if(!((wacom->tool[idx] == BTN_TOOL_LENS) &&
- ((wacom->features->type == INTUOS312)
- || (wacom->features->type == INTUOS319)))) {
- input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */
- input_report_key(dev, wacom->tool[idx], 1);
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
- }
- return 1;
- }
-
- /* Exit report */
- if ((data[1] & 0xfe) == 0x80) {
- input_report_key(dev, wacom->tool[idx], 0);
- input_report_abs(dev, ABS_MISC, 0); /* reset tool id */
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
- return 1;
- }
-
- if((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS312)
- || (wacom->features->type == INTUOS319)))
- return 1;
- else
- return 0;
-}
-
-static void wacom_intuos_general(struct urb *urb)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- unsigned int t;
-
- /* general pen packet */
- if ((data[1] & 0xb8) == 0xa0) {
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(dev, ABS_PRESSURE, t);
- input_report_abs(dev, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
- input_report_key(dev, BTN_STYLUS, data[1] & 2);
- input_report_key(dev, BTN_STYLUS2, data[1] & 4);
- input_report_key(dev, BTN_TOUCH, t > 10);
- }
-
- /* airbrush second packet */
- if ((data[1] & 0xbc) == 0xb4) {
- input_report_abs(dev, ABS_WHEEL,
- (data[6] << 2) | ((data[7] >> 6) & 3));
- input_report_abs(dev, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
- }
- return;
-}
-
-static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- unsigned int t;
- int idx;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
- dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
-
- /* tool number */
- idx = data[1] & 0x01;
-
- /* pad packets. Works as a second tool and is always in prox */
- if (data[0] == 12) {
- /* initiate the pad as a device */
- if (wacom->tool[1] != BTN_TOOL_FINGER)
- wacom->tool[1] = BTN_TOOL_FINGER;
-
- input_report_key(dev, BTN_0, (data[5] & 0x01));
- input_report_key(dev, BTN_1, (data[5] & 0x02));
- input_report_key(dev, BTN_2, (data[5] & 0x04));
- input_report_key(dev, BTN_3, (data[5] & 0x08));
- input_report_key(dev, BTN_4, (data[6] & 0x01));
- input_report_key(dev, BTN_5, (data[6] & 0x02));
- input_report_key(dev, BTN_6, (data[6] & 0x04));
- input_report_key(dev, BTN_7, (data[6] & 0x08));
- input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
- input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
- if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2])
- input_report_key(dev, wacom->tool[1], 1);
- else
- input_report_key(dev, wacom->tool[1], 0);
- input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff);
- input_sync(dev);
- goto exit;
- }
-
- /* process in/out prox events */
- if (wacom_intuos_inout(urb))
- goto exit;
-
- /* Cintiq doesn't send data when RDY bit isn't set */
- if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
- goto exit;
-
- if (wacom->features->type >= INTUOS3) {
- input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
- input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
- input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
- } else {
- input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
- input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
- input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
- }
-
- /* process general packets */
- wacom_intuos_general(urb);
-
- /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
- if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
-
- if (data[1] & 0x02) {
- /* Rotation packet */
- if (wacom->features->type >= INTUOS3) {
- /* I3 marker pen rotation reported as wheel
- * due to valuator limitation
- */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
- ((t-1) / 2 + 450)) : (450 - t / 2) ;
- input_report_abs(dev, ABS_WHEEL, t);
- } else {
- /* 4D mouse rotation packet */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
- ((t - 1) / 2) : -t / 2);
- }
-
- } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
- /* 4D mouse packet */
- input_report_key(dev, BTN_LEFT, data[8] & 0x01);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
-
- input_report_key(dev, BTN_SIDE, data[8] & 0x20);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
- } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
- /* 2D mouse packet */
- input_report_key(dev, BTN_LEFT, data[8] & 0x04);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
- input_report_rel(dev, REL_WHEEL, (data[8] & 0x01)
- - ((data[8] & 0x02) >> 1));
-
- /* I3 2D mouse side buttons */
- if (wacom->features->type == INTUOS3) {
- input_report_key(dev, BTN_SIDE, data[8] & 0x40);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x20);
- }
-
- } else if (wacom->features->type < INTUOS3) {
- /* Lens cursor packets */
- input_report_key(dev, BTN_LEFT, data[8] & 0x01);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
- input_report_key(dev, BTN_SIDE, data[8] & 0x10);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x08);
- }
- }
-
- input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */
- input_report_key(dev, wacom->tool[idx], 1);
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
-
-exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static struct wacom_features wacom_features[] = {
- { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq },
- { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_graphire_irq },
- { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_graphire_irq },
- { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq },
- { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq },
- { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_pl_irq },
- { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq },
- { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq },
- { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq },
- { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_pl_irq },
- { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq },
- { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS312, wacom_intuos_irq },
- { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS319, wacom_intuos_irq },
- { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
- { }
-};
-
-static struct usb_device_id wacom_ids[] = {
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC3) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, wacom_ids);
-
-static int wacom_open(struct input_dev *dev)
-{
- struct wacom *wacom = dev->private;
-
- wacom->irq->dev = wacom->usbdev;
- if (usb_submit_urb(wacom->irq, GFP_KERNEL))
- return -EIO;
-
- return 0;
-}
-
-static void wacom_close(struct input_dev *dev)
-{
- struct wacom *wacom = dev->private;
-
- usb_kill_urb(wacom->irq);
-}
-
-static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_endpoint_descriptor *endpoint;
- struct wacom *wacom;
- struct input_dev *input_dev;
- char rep_data[2], limit = 0;
-
- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!wacom || !input_dev)
- goto fail1;
-
- wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
- if (!wacom->data)
- goto fail1;
-
- wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!wacom->irq)
- goto fail2;
-
- wacom->usbdev = dev;
- wacom->dev = input_dev;
- usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
- strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
-
- wacom->features = wacom_features + (id - wacom_ids);
- if (wacom->features->pktlen > 10)
- BUG();
-
- input_dev->name = wacom->features->name;
- usb_to_input_id(dev, &input_dev->id);
-
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = wacom;
- input_dev->open = wacom_open;
- input_dev->close = wacom_close;
-
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
- input_set_abs_params(input_dev, ABS_X, 0, wacom->features->x_max, 4, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0);
- input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
-
- switch (wacom->features->type) {
- case WACOM_G4:
- input_dev->evbit[0] |= BIT(EV_MSC);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
- /* fall through */
-
- case GRAPHIRE:
- input_dev->evbit[0] |= BIT(EV_REL);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0);
- break;
-
- case INTUOS3:
- case INTUOS312:
- case INTUOS319:
- case CINTIQ:
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
- input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
- input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
- /* fall through */
-
- case INTUOS:
- input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
- | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0);
- input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
- input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
- input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
- break;
-
- case PL:
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
- break;
- }
-
- endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
- if (wacom->features->pktlen > 10)
- BUG();
-
- usb_fill_int_urb(wacom->irq, dev,
- usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, wacom->features->pktlen,
- wacom->features->irq, wacom, endpoint->bInterval);
- wacom->irq->transfer_dma = wacom->data_dma;
- wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- input_register_device(wacom->dev);
-
- /* Ask the tablet to report tablet data. Repeat until it succeeds */
- do {
- rep_data[0] = 2;
- rep_data[1] = 2;
- usb_set_report(intf, 3, 2, rep_data, 2);
- usb_get_report(intf, 3, 2, rep_data, 2);
- } while (rep_data[1] != 2 && limit++ < 5);
-
- usb_set_intfdata(intf, wacom);
- return 0;
-
-fail2: usb_buffer_free(dev, 10, wacom->data, wacom->data_dma);
-fail1: input_free_device(input_dev);
- kfree(wacom);
- return -ENOMEM;
-}
-
-static void wacom_disconnect(struct usb_interface *intf)
-{
- struct wacom *wacom = usb_get_intfdata (intf);
-
- usb_set_intfdata(intf, NULL);
- if (wacom) {
- usb_kill_urb(wacom->irq);
- input_unregister_device(wacom->dev);
- usb_free_urb(wacom->irq);
- usb_buffer_free(interface_to_usbdev(intf), 10, wacom->data, wacom->data_dma);
- kfree(wacom);
- }
-}
-
-static struct usb_driver wacom_driver = {
- .name = "wacom",
- .probe = wacom_probe,
- .disconnect = wacom_disconnect,
- .id_table = wacom_ids,
-};
-
-static int __init wacom_init(void)
-{
- int result = usb_register(&wacom_driver);
- if (result == 0)
- info(DRIVER_VERSION ":" DRIVER_DESC);
- return result;
-}
-
-static void __exit wacom_exit(void)
-{
- usb_deregister(&wacom_driver);
-}
-
-module_init(wacom_init);
-module_exit(wacom_exit);
diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h
new file mode 100644
index 00000000000..832737b658c
--- /dev/null
+++ b/drivers/usb/input/wacom.h
@@ -0,0 +1,132 @@
+/*
+ * drivers/usb/input/wacom.h
+ *
+ * USB Wacom Graphire and Wacom Intuos tablet support
+ *
+ * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
+ * Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
+ * Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
+ * Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
+ * Copyright (c) 2000 James E. Blair <corvus@gnu.org>
+ * Copyright (c) 2000 Daniel Egger <egger@suse.de>
+ * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
+ * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
+ * Copyright (c) 2002-2006 Ping Cheng <pingc@wacom.com>
+ *
+ * ChangeLog:
+ * v0.1 (vp) - Initial release
+ * v0.2 (aba) - Support for all buttons / combinations
+ * v0.3 (vp) - Support for Intuos added
+ * v0.4 (sm) - Support for more Intuos models, menustrip
+ * relative mode, proximity.
+ * v0.5 (vp) - Big cleanup, nifty features removed,
+ * they belong in userspace
+ * v1.8 (vp) - Submit URB only when operating, moved to CVS,
+ * use input_report_key instead of report_btn and
+ * other cleanups
+ * v1.11 (vp) - Add URB ->dev setting for new kernels
+ * v1.11 (jb) - Add support for the 4D Mouse & Lens
+ * v1.12 (de) - Add support for two more inking pen IDs
+ * v1.14 (vp) - Use new USB device id probing scheme.
+ * Fix Wacom Graphire mouse wheel
+ * v1.18 (vp) - Fix mouse wheel direction
+ * Make mouse relative
+ * v1.20 (fl) - Report tool id for Intuos devices
+ * - Multi tools support
+ * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
+ * - Add PL models support
+ * - Fix Wacom Graphire mouse wheel again
+ * v1.21 (vp) - Removed protocol descriptions
+ * - Added MISC_SERIAL for tool serial numbers
+ * (gb) - Identify version on module load.
+ * v1.21.1 (fl) - added Graphire2 support
+ * v1.21.2 (fl) - added Intuos2 support
+ * - added all the PL ids
+ * v1.21.3 (fl) - added another eraser id from Neil Okamoto
+ * - added smooth filter for Graphire from Peri Hankey
+ * - added PenPartner support from Olaf van Es
+ * - new tool ids from Ole Martin Bjoerndalen
+ * v1.29 (pc) - Add support for more tablets
+ * - Fix pressure reporting
+ * v1.30 (vp) - Merge 2.4 and 2.5 drivers
+ * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
+ * - Cleanups here and there
+ * v1.30.1 (pi) - Added Graphire3 support
+ * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ * v1.43 (pc) - Added support for Cintiq 21UX
+ * - Fixed a Graphire bug
+ * - Merged wacom_intuos3_irq into wacom_intuos_irq
+ * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
+ * - Report Device IDs
+ * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
+ * - Minor data report fix
+ * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
+ * - where wacom_sys.c deals with system specific code,
+ * - and wacom_wac.c deals with Wacom specific code
+ */
+
+/*
+ * 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.
+ */
+#ifndef WACOM_H
+#define WACOM_H
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.46"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_WACOM 0x056a
+
+struct wacom {
+ dma_addr_t data_dma;
+ struct input_dev *dev;
+ struct usb_device *usbdev;
+ struct urb *irq;
+ struct wacom_wac * wacom_wac;
+ char phys[32];
+};
+
+struct wacom_combo {
+ struct wacom * wacom;
+ struct urb * urb;
+ struct pt_regs *regs;
+};
+
+extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
+extern void wacom_sys_irq(struct urb *urb, struct pt_regs *regs);
+extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
+extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
+extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data);
+extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value);
+extern void wacom_input_regs(void *wcombo);
+extern void wacom_input_sync(void *wcombo);
+extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern __u16 wacom_le16_to_cpu(unsigned char *data);
+extern __u16 wacom_be16_to_cpu(unsigned char *data);
+extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
+extern const struct usb_device_id * get_device_table(void);
+
+#endif
diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c
new file mode 100644
index 00000000000..7c3b52bdd9d
--- /dev/null
+++ b/drivers/usb/input/wacom_sys.c
@@ -0,0 +1,315 @@
+/*
+ * drivers/usb/input/wacom_sys.c
+ *
+ * USB Wacom Graphire and Wacom Intuos tablet support - system specific code
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "wacom.h"
+#include "wacom_wac.h"
+
+#define USB_REQ_GET_REPORT 0x01
+#define USB_REQ_SET_REPORT 0x09
+
+static int usb_get_report(struct usb_interface *intf, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(interface_to_usbdev(intf),
+ usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
+ USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+ buf, size, 100);
+}
+
+static int usb_set_report(struct usb_interface *intf, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(interface_to_usbdev(intf),
+ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+ buf, size, 1000);
+}
+
+static struct input_dev * get_input_dev(struct wacom_combo *wcombo)
+{
+ return wcombo->wacom->dev;
+}
+
+void wacom_sys_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct wacom *wacom = urb->context;
+ struct wacom_combo wcombo;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ goto exit;
+ }
+
+ wcombo.wacom = wacom;
+ wcombo.urb = urb;
+ wcombo.regs = regs;
+
+ if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo))
+ input_sync(get_input_dev(&wcombo));
+
+ exit:
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, retval);
+}
+
+void wacom_report_key(void *wcombo, unsigned int key_type, int key_data)
+{
+ input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data);
+ return;
+}
+
+void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data)
+{
+ input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data);
+ return;
+}
+
+void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data)
+{
+ input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data);
+ return;
+}
+
+void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value)
+{
+ input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value);
+ return;
+}
+
+__u16 wacom_be16_to_cpu(unsigned char *data)
+{
+ __u16 value;
+ value = be16_to_cpu(*(__be16 *) data);
+ return value;
+}
+
+__u16 wacom_le16_to_cpu(unsigned char *data)
+{
+ __u16 value;
+ value = be16_to_cpu(*(__be16 *) data);
+ return value;
+}
+
+void wacom_input_regs(void *wcombo)
+{
+ input_regs(get_input_dev((struct wacom_combo *)wcombo), ((struct wacom_combo *)wcombo)->regs);
+ return;
+}
+
+void wacom_input_sync(void *wcombo)
+{
+ input_sync(get_input_dev((struct wacom_combo *)wcombo));
+ return;
+}
+
+static int wacom_open(struct input_dev *dev)
+{
+ struct wacom *wacom = dev->private;
+
+ wacom->irq->dev = wacom->usbdev;
+ if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void wacom_close(struct input_dev *dev)
+{
+ struct wacom *wacom = dev->private;
+
+ usb_kill_urb(wacom->irq);
+}
+
+void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->evbit[0] |= BIT(EV_MSC);
+ input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+}
+
+void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->evbit[0] |= BIT(EV_REL);
+ input_dev->relbit[0] |= BIT(REL_WHEEL);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+ input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+}
+
+void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+ input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
+ input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
+}
+
+void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
+ input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+ input_dev->relbit[0] |= BIT(REL_WHEEL);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
+ | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
+ input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+ input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
+ input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
+}
+
+void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+}
+
+void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER);
+}
+
+static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_endpoint_descriptor *endpoint;
+ struct wacom *wacom;
+ struct wacom_wac *wacom_wac;
+ struct input_dev *input_dev;
+ char rep_data[2], limit = 0;
+
+ wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!wacom || !input_dev || !wacom_wac)
+ goto fail1;
+
+ wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
+ if (!wacom_wac->data)
+ goto fail1;
+
+ wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!wacom->irq)
+ goto fail2;
+
+ wacom->usbdev = dev;
+ wacom->dev = input_dev;
+ usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
+ strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
+
+ wacom_wac->features = get_wacom_feature(id);
+ if (wacom_wac->features->pktlen > 10)
+ BUG();
+
+ input_dev->name = wacom_wac->features->name;
+ wacom->wacom_wac = wacom_wac;
+ usb_to_input_id(dev, &input_dev->id);
+
+ input_dev->cdev.dev = &intf->dev;
+ input_dev->private = wacom;
+ input_dev->open = wacom_open;
+ input_dev->close = wacom_close;
+
+ input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
+ input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
+ input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
+
+ wacom_init_input_dev(input_dev, wacom_wac);
+
+ endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+ usb_fill_int_urb(wacom->irq, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wacom_wac->data, wacom_wac->features->pktlen,
+ wacom_wac->features->irq, wacom, endpoint->bInterval);
+ wacom->irq->transfer_dma = wacom->data_dma;
+ wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ input_register_device(wacom->dev);
+
+ /* Ask the tablet to report tablet data. Repeat until it succeeds */
+ do {
+ rep_data[0] = 2;
+ rep_data[1] = 2;
+ usb_set_report(intf, 3, 2, rep_data, 2);
+ usb_get_report(intf, 3, 2, rep_data, 2);
+ } while (rep_data[1] != 2 && limit++ < 5);
+
+ usb_set_intfdata(intf, wacom);
+ return 0;
+
+fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
+fail1: input_free_device(input_dev);
+ kfree(wacom);
+ kfree(wacom_wac);
+ return -ENOMEM;
+}
+
+static void wacom_disconnect(struct usb_interface *intf)
+{
+ struct wacom *wacom = usb_get_intfdata (intf);
+
+ usb_set_intfdata(intf, NULL);
+ if (wacom) {
+ usb_kill_urb(wacom->irq);
+ input_unregister_device(wacom->dev);
+ usb_free_urb(wacom->irq);
+ usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
+ kfree(wacom);
+ kfree(wacom->wacom_wac);
+ }
+}
+
+static struct usb_driver wacom_driver = {
+ .name = "wacom",
+ .probe = wacom_probe,
+ .disconnect = wacom_disconnect,
+};
+
+static int __init wacom_init(void)
+{
+ int result;
+ wacom_driver.id_table = get_device_table();
+ result = usb_register(&wacom_driver);
+ if (result == 0)
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+ return result;
+}
+
+static void __exit wacom_exit(void)
+{
+ usb_deregister(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
new file mode 100644
index 00000000000..85d458c98b6
--- /dev/null
+++ b/drivers/usb/input/wacom_wac.c
@@ -0,0 +1,646 @@
+/*
+ * drivers/usb/input/wacom_wac.c
+ *
+ * USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include "wacom.h"
+#include "wacom_wac.h"
+
+static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+
+ switch (data[0]) {
+ case 1:
+ wacom_input_regs(wcombo);
+ if (data[5] & 0x80) {
+ wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
+ wacom_report_key(wcombo, wacom->tool[0], 1);
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
+ wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -127));
+ wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
+ } else {
+ wacom_report_key(wcombo, wacom->tool[0], 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* report tool id */
+ wacom_report_abs(wcombo, ABS_PRESSURE, -1);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
+ }
+ break;
+ case 2:
+ wacom_input_regs(wcombo);
+ wacom_report_key(wcombo, BTN_TOOL_PEN, 1);
+ wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
+ wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
+ wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
+ break;
+ default:
+ printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+ return 0;
+ }
+ return 1;
+}
+
+static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int prox, id, pressure;
+
+ if (data[0] != 2) {
+ dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+ return 0;
+ }
+
+ prox = data[1] & 0x40;
+
+ wacom_input_regs(wcombo);
+
+ id = ERASER_DEVICE_ID;
+ if (prox) {
+
+ pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+ if (wacom->features->pressure_max > 255)
+ pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+ pressure += (wacom->features->pressure_max + 1) / 2;
+
+ /*
+ * if going from out of proximity into proximity select between the eraser
+ * and the pen based on the state of the stylus2 button, choose eraser if
+ * pressed else choose pen. if not a proximity change from out to in, send
+ * an out of proximity for previous tool then a in for new tool.
+ */
+ if (!wacom->tool[0]) {
+ /* Eraser bit set for DTF */
+ if (data[1] & 0x10)
+ wacom->tool[1] = BTN_TOOL_RUBBER;
+ else
+ /* Going into proximity select tool */
+ wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ } else {
+ /* was entered with stylus2 pressed */
+ if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
+ /* report out proximity for previous tool */
+ wacom_report_key(wcombo, wacom->tool[1], 0);
+ wacom_input_sync(wcombo);
+ wacom->tool[1] = BTN_TOOL_PEN;
+ return 0;
+ }
+ }
+ if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+ /* Unknown tool selected default to pen tool */
+ wacom->tool[1] = BTN_TOOL_PEN;
+ id = STYLUS_DEVICE_ID;
+ }
+ wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */
+ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+ wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+ wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
+
+ wacom_report_key(wcombo, BTN_TOUCH, data[4] & 0x08);
+ wacom_report_key(wcombo, BTN_STYLUS, data[4] & 0x10);
+ /* Only allow the stylus2 button to be reported for the pen tool. */
+ wacom_report_key(wcombo, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
+ } else {
+ /* report proximity-out of a (valid) tool */
+ if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+ /* Unknown tool selected default to pen tool */
+ wacom->tool[1] = BTN_TOOL_PEN;
+ }
+ wacom_report_key(wcombo, wacom->tool[1], prox);
+ }
+
+ wacom->tool[0] = prox; /* Save proximity state */
+ return 1;
+}
+
+static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int id;
+
+ if (data[0] != 2) {
+ printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+ return 0;
+ }
+
+ wacom_input_regs(wcombo);
+ if (data[1] & 0x04) {
+ wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20);
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08);
+ id = ERASER_DEVICE_ID;
+ } else {
+ wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20);
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
+ id = STYLUS_DEVICE_ID;
+ }
+ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+ wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
+ return 1;
+}
+
+static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int x, y, id, rw;
+
+ if (data[0] != 2) {
+ dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+ return 0;
+ }
+
+ wacom_input_regs(wcombo);
+
+ id = STYLUS_DEVICE_ID;
+ if (data[1] & 0x10) { /* in prox */
+
+ switch ((data[1] >> 5) & 3) {
+
+ case 0: /* Pen */
+ wacom->tool[0] = BTN_TOOL_PEN;
+ break;
+
+ case 1: /* Rubber */
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ id = ERASER_DEVICE_ID;
+ break;
+
+ case 2: /* Mouse with wheel */
+ wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
+ if (wacom->features->type == WACOM_G4) {
+ rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
+ wacom_report_rel(wcombo, REL_WHEEL, -rw);
+ } else
+ wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
+ /* fall through */
+
+ case 3: /* Mouse without wheel */
+ wacom->tool[0] = BTN_TOOL_MOUSE;
+ id = CURSOR_DEVICE_ID;
+ wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
+ wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
+ if (wacom->features->type == WACOM_G4)
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[6]);
+ else
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[7]);
+ break;
+ }
+ }
+
+ if (data[1] & 0x90) {
+ x = wacom_le16_to_cpu(&data[2]);
+ y = wacom_le16_to_cpu(&data[4]);
+ wacom_report_abs(wcombo, ABS_X, x);
+ wacom_report_abs(wcombo, ABS_Y, y);
+ if (wacom->tool[0] != BTN_TOOL_MOUSE) {
+ wacom_report_abs(wcombo, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
+ }
+ }
+
+ if (data[1] & 0x10)
+ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+ else
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_report_key(wcombo, wacom->tool[0], data[1] & 0x10);
+ wacom_input_sync(wcombo);
+
+ /* send pad data */
+ if (wacom->features->type == WACOM_G4) {
+ if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) {
+ wacom->id[1] = 1;
+ wacom->serial[1] = (data[7] & 0xf8);
+ wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+ wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
+ rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
+ wacom_report_rel(wcombo, REL_WHEEL, rw);
+ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+ } else if (wacom->id[1]) {
+ wacom->id[1] = 0;
+ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+ }
+ }
+ return 1;
+}
+
+static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int idx;
+
+ /* tool number */
+ idx = data[1] & 0x01;
+
+ /* Enter report */
+ if ((data[1] & 0xfc) == 0xc0) {
+ /* serial number of the tool */
+ wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+ (data[4] << 20) + (data[5] << 12) +
+ (data[6] << 4) + (data[7] >> 4);
+
+ wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
+ switch (wacom->id[idx]) {
+ case 0x812: /* Inking pen */
+ case 0x801: /* Intuos3 Inking pen */
+ case 0x012:
+ wacom->tool[idx] = BTN_TOOL_PENCIL;
+ break;
+ case 0x822: /* Pen */
+ case 0x842:
+ case 0x852:
+ case 0x823: /* Intuos3 Grip Pen */
+ case 0x813: /* Intuos3 Classic Pen */
+ case 0x885: /* Intuos3 Marker Pen */
+ case 0x022:
+ wacom->tool[idx] = BTN_TOOL_PEN;
+ break;
+ case 0x832: /* Stroke pen */
+ case 0x032:
+ wacom->tool[idx] = BTN_TOOL_BRUSH;
+ break;
+ case 0x007: /* Mouse 4D and 2D */
+ case 0x09c:
+ case 0x094:
+ case 0x017: /* Intuos3 2D Mouse */
+ wacom->tool[idx] = BTN_TOOL_MOUSE;
+ break;
+ case 0x096: /* Lens cursor */
+ case 0x097: /* Intuos3 Lens cursor */
+ wacom->tool[idx] = BTN_TOOL_LENS;
+ break;
+ case 0x82a: /* Eraser */
+ case 0x85a:
+ case 0x91a:
+ case 0xd1a:
+ case 0x0fa:
+ case 0x82b: /* Intuos3 Grip Pen Eraser */
+ case 0x81b: /* Intuos3 Classic Pen Eraser */
+ case 0x91b: /* Intuos3 Airbrush Eraser */
+ wacom->tool[idx] = BTN_TOOL_RUBBER;
+ break;
+ case 0xd12:
+ case 0x912:
+ case 0x112:
+ case 0x913: /* Intuos3 Airbrush */
+ wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+ break;
+ default: /* Unknown tool */
+ wacom->tool[idx] = BTN_TOOL_PEN;
+ }
+ /* only large I3 support Lens Cursor */
+ if(!((wacom->tool[idx] == BTN_TOOL_LENS) &&
+ (wacom->features->type == INTUOS3))) {
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
+ wacom_report_key(wcombo, wacom->tool[idx], 1);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 2;
+ }
+ return 1;
+ }
+
+ /* Exit report */
+ if ((data[1] & 0xfe) == 0x80) {
+ wacom_report_key(wcombo, wacom->tool[idx], 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 2;
+ }
+ return 0;
+}
+
+static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ unsigned int t;
+
+ /* general pen packet */
+ if ((data[1] & 0xb8) == 0xa0) {
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ wacom_report_abs(wcombo, ABS_PRESSURE, t);
+ wacom_report_abs(wcombo, ABS_TILT_X,
+ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+ wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 2);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 4);
+ wacom_report_key(wcombo, BTN_TOUCH, t > 10);
+ }
+
+ /* airbrush second packet */
+ if ((data[1] & 0xbc) == 0xb4) {
+ wacom_report_abs(wcombo, ABS_WHEEL,
+ (data[6] << 2) | ((data[7] >> 6) & 3));
+ wacom_report_abs(wcombo, ABS_TILT_X,
+ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+ wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+ }
+ return;
+}
+
+static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ unsigned int t;
+ int idx, result;
+
+ if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
+ dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+ return 0;
+ }
+
+ wacom_input_regs(wcombo);
+
+ /* tool number */
+ idx = data[1] & 0x01;
+
+ /* pad packets. Works as a second tool and is always in prox */
+ if (data[0] == 12) {
+ /* initiate the pad as a device */
+ if (wacom->tool[1] != BTN_TOOL_FINGER)
+ wacom->tool[1] = BTN_TOOL_FINGER;
+
+ wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
+ wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
+ wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
+ wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
+ wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
+ wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
+ wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
+ wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
+ wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+ wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+
+ if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2])
+ wacom_report_key(wcombo, wacom->tool[1], 1);
+ else
+ wacom_report_key(wcombo, wacom->tool[1], 0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
+ return 1;
+ }
+
+ /* process in/out prox events */
+ result = wacom_intuos_inout(wacom, wcombo);
+ if (result)
+ return result-1;
+
+ /* Cintiq doesn't send data when RDY bit isn't set */
+ if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+ return 0;
+
+ if (wacom->features->type >= INTUOS3) {
+ wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+ wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+ wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+ } else {
+ wacom_report_abs(wcombo, ABS_X, wacom_be16_to_cpu(&data[2]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_be16_to_cpu(&data[4]));
+ wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
+ }
+
+ /* process general packets */
+ wacom_intuos_general(wacom, wcombo);
+
+ /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
+ if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+
+ if (data[1] & 0x02) {
+ /* Rotation packet */
+ if (wacom->features->type >= INTUOS3) {
+ /* I3 marker pen rotation reported as wheel
+ * due to valuator limitation
+ */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+ ((t-1) / 2 + 450)) : (450 - t / 2) ;
+ wacom_report_abs(wcombo, ABS_WHEEL, t);
+ } else {
+ /* 4D mouse rotation packet */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ wacom_report_abs(wcombo, ABS_RZ, (data[7] & 0x20) ?
+ ((t - 1) / 2) : -t / 2);
+ }
+
+ } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
+ /* 4D mouse packet */
+ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
+ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
+ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04);
+
+ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x20);
+ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x10);
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+ } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+ /* 2D mouse packet */
+ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04);
+ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
+ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10);
+ wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
+ - ((data[8] & 0x02) >> 1));
+
+ /* I3 2D mouse side buttons */
+ if (wacom->features->type == INTUOS3) {
+ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
+ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
+ }
+
+ } else if (wacom->features->type < INTUOS3) {
+ /* Lens cursor packets */
+ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
+ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
+ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04);
+ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x10);
+ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x08);
+ }
+ }
+
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
+ wacom_report_key(wcombo, wacom->tool[idx], 1);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 1;
+}
+
+int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
+{
+ switch (wacom_wac->features->type) {
+ case PENPARTNER:
+ return (wacom_penpartner_irq(wacom_wac, wcombo));
+ break;
+ case PL:
+ return (wacom_pl_irq(wacom_wac, wcombo));
+ break;
+ case WACOM_G4:
+ case GRAPHIRE:
+ return (wacom_graphire_irq(wacom_wac, wcombo));
+ break;
+ case PTU:
+ return (wacom_ptu_irq(wacom_wac, wcombo));
+ break;
+ case INTUOS:
+ case INTUOS3:
+ case INTUOS3L:
+ case CINTIQ:
+ return (wacom_intuos_irq(wacom_wac, wcombo));
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ switch (wacom_wac->features->type) {
+ case WACOM_G4:
+ input_dev_g4(input_dev, wacom_wac);
+ /* fall through */
+ case GRAPHIRE:
+ input_dev_g(input_dev, wacom_wac);
+ break;
+ case INTUOS3:
+ case INTUOS3L:
+ case CINTIQ:
+ input_dev_i3(input_dev, wacom_wac);
+ /* fall through */
+ case INTUOS:
+ input_dev_i(input_dev, wacom_wac);
+ break;
+ case PL:
+ case PTU:
+ input_dev_pl(input_dev, wacom_wac);
+ break;
+ case PENPARTNER:
+ input_dev_pt(input_dev, wacom_wac);
+ break;
+ }
+ return;
+}
+
+static struct wacom_features wacom_features[] = {
+ { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_sys_irq },
+ { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_sys_irq },
+ { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_sys_irq },
+ { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq },
+ { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq},
+ { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq},
+ { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_sys_irq },
+ { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_sys_irq },
+ { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_sys_irq },
+ { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_sys_irq },
+ { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_sys_irq },
+ { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_sys_irq },
+ { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_sys_irq },
+ { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq },
+ { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_sys_irq },
+ { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq },
+ { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_sys_irq },
+ { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PTU, wacom_sys_irq },
+ { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq },
+ { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_sys_irq },
+ { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_sys_irq },
+ { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_sys_irq },
+ { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L, wacom_sys_irq },
+ { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L, wacom_sys_irq },
+ { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_sys_irq },
+ { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_sys_irq },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq },
+ { }
+};
+
+static struct usb_device_id wacom_ids[] = {
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
+ { }
+};
+
+const struct usb_device_id * get_device_table(void) {
+ const struct usb_device_id * id_table = wacom_ids;
+ return id_table;
+}
+
+struct wacom_features * get_wacom_feature(const struct usb_device_id * id) {
+ int index = id - wacom_ids;
+ struct wacom_features *wf = &wacom_features[index];
+ return wf;
+}
+
+MODULE_DEVICE_TABLE(usb, wacom_ids);
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h
new file mode 100644
index 00000000000..ceae7bf59d9
--- /dev/null
+++ b/drivers/usb/input/wacom_wac.h
@@ -0,0 +1,48 @@
+/*
+ * drivers/usb/input/wacom_wac.h
+ *
+ * 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.
+ */
+#ifndef WACOM_WAC_H
+#define WACOM_WAC_H
+
+#define STYLUS_DEVICE_ID 0x02
+#define CURSOR_DEVICE_ID 0x06
+#define ERASER_DEVICE_ID 0x0A
+
+enum {
+ PENPARTNER = 0,
+ GRAPHIRE,
+ WACOM_G4,
+ PTU,
+ PL,
+ INTUOS,
+ INTUOS3,
+ INTUOS3L,
+ CINTIQ,
+ MAX_TYPE
+};
+
+struct wacom_features {
+ char *name;
+ int pktlen;
+ int x_max;
+ int y_max;
+ int pressure_max;
+ int distance_max;
+ int type;
+ usb_complete_t irq;
+};
+
+struct wacom_wac {
+ signed char *data;
+ int tool[2];
+ int id[2];
+ __u32 serial[2];
+ struct wacom_features *features;
+};
+
+#endif
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index cfd4a4e0433..9889b1cda05 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -54,7 +54,6 @@
* 2002-07-17 - 0.0.5 : simplified d-pad handling
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c
index 24aedbb20f0..7291e7a2717 100644
--- a/drivers/usb/input/yealink.c
+++ b/drivers/usb/input/yealink.c
@@ -46,7 +46,6 @@
* 20050816 henk Merge 2.6.13-rc6
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -811,12 +810,9 @@ static int usb_cleanup(struct yealink_dev *yld, int err)
if (yld == NULL)
return err;
- if (yld->urb_irq) {
- usb_kill_urb(yld->urb_irq);
- usb_free_urb(yld->urb_irq);
- }
- if (yld->urb_ctl)
- usb_free_urb(yld->urb_ctl);
+ usb_kill_urb(yld->urb_irq); /* parameter validation in core/urb */
+ usb_kill_urb(yld->urb_ctl); /* parameter validation in core/urb */
+
if (yld->idev) {
if (err)
input_free_device(yld->idev);
@@ -832,6 +828,9 @@ static int usb_cleanup(struct yealink_dev *yld, int err)
if (yld->irq_data)
usb_buffer_free(yld->udev, USB_PKT_LEN,
yld->irq_data, yld->irq_dma);
+
+ usb_free_urb(yld->urb_irq); /* parameter validation in core/urb */
+ usb_free_urb(yld->urb_ctl); /* parameter validation in core/urb */
kfree(yld);
return err;
}
@@ -972,7 +971,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
DRIVER_VERSION, sizeof(DRIVER_VERSION));
/* Register sysfs hooks (don't care about failure) */
- sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+ ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
return 0;
}
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index daa486dde8c..c29658f69e2 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -32,6 +32,16 @@ config USB_EMI26
To compile this driver as a module, choose M here: the
module will be called emi26.
+config USB_ADUTUX
+ tristate "ADU devices from Ontrak Control Systems (EXPERIMENTAL)"
+ depends on USB && EXPERIMENTAL
+ help
+ Say Y if you want to use an ADU device from Ontrak Control
+ Systems.
+
+ To compile this driver as a module, choose M here. The module
+ will be called adutux.
+
config USB_AUERSWALD
tristate "USB Auerswald ISDN support (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
@@ -88,19 +98,19 @@ config USB_LED
To compile this driver as a module, choose M here: the
module will be called usbled.
-config USB_CY7C63
+config USB_CYPRESS_CY7C63
tristate "Cypress CY7C63xxx USB driver support"
depends on USB
help
Say Y here if you want to connect a Cypress CY7C63xxx
- micro controller to your computer's USB port. This driver
- supports the pre-programmed devices (incl. firmware) by
- AK Modul-Bus Computer GmbH.
+ micro controller to your computer's USB port. Currently this
+ driver supports the pre-programmed devices (incl. firmware)
+ by AK Modul-Bus Computer GmbH.
Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html
To compile this driver as a module, choose M here: the
- module will be called cy7c63.
+ module will be called cypress_cy7c63.
config USB_CYTHERM
tristate "Cypress USB thermometer driver support"
@@ -115,19 +125,36 @@ config USB_CYTHERM
To compile this driver as a module, choose M here: the
module will be called cytherm.
-config USB_PHIDGETKIT
- tristate "USB PhidgetKit support"
+config USB_PHIDGET
+ tristate "USB Phidgets drivers"
depends on USB
help
- Say Y here if you want to connect a PhidgetKit USB device from
- Phidgets Inc.
+ Say Y here to enable the various drivers for devices from
+ Phidgets inc.
+
+config USB_PHIDGETKIT
+ tristate "USB PhidgetInterfaceKit support"
+ depends on USB_PHIDGET
+ help
+ Say Y here if you want to connect a PhidgetInterfaceKit USB device
+ from Phidgets Inc.
To compile this driver as a module, choose M here: the
module will be called phidgetkit.
+config USB_PHIDGETMOTORCONTROL
+ tristate "USB PhidgetMotorControl support"
+ depends on USB_PHIDGET
+ help
+ Say Y here if you want to connect a PhidgetMotorControl USB device
+ from Phidgets Inc.
+
+ To compile this driver as a module, choose M here: the
+ module will be called phidgetmotorcontrol.
+
config USB_PHIDGETSERVO
tristate "USB PhidgetServo support"
- depends on USB
+ depends on USB_PHIDGET
help
Say Y here if you want to connect an 1 or 4 Motor PhidgetServo
servo controller version 2.0 or 3.0.
@@ -151,6 +178,30 @@ config USB_IDMOUSE
See also <http://www.fs.tum.de/~echtler/idmouse/>.
+config USB_FTDI_ELAN
+ tristate "Elan PCMCIA CardBus Adapter USB Client"
+ depends on USB
+ default M
+ help
+ ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.
+ Currently only the U132 adapter is available.
+
+ The U132 is specifically designed for CardBus PC cards that contain
+ an OHCI host controller. Typical PC cards are the Orange Mobile 3G
+ Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work
+ with PC cards that do not contain an OHCI controller. To use a U132
+ adapter you will need this "ftdi-elan" module as well as the "u132-hcd"
+ module which is a USB host controller driver that talks to the OHCI
+ controller within CardBus card that are inserted in the U132 adapter.
+
+ This driver has been tested with a CardBus OHCI USB adapter, and
+ worked with a USB PEN Drive inserted into the first USB port of
+ the PCCARD. A rather pointless thing to do, but useful for testing.
+
+ See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller"
+
+ It is safe to say M here.
+
config USB_APPLEDISPLAY
tristate "Apple Cinema Display support"
depends on USB
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index f25a9722729..2be70fa259b 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -3,22 +3,25 @@
# (the ones that don't fit into any other categories)
#
+obj-$(CONFIG_USB_ADUTUX) += adutux.o
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
-obj-$(CONFIG_USB_CY7C63) += cy7c63.o
+obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_EMI62) += emi62.o
+obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
+obj-$(CONFIG_USB_PHIDGET) += phidget.o
obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o
+obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o
obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
obj-$(CONFIG_USB_USS720) += uss720.o
-obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
new file mode 100644
index 00000000000..d3963199b6e
--- /dev/null
+++ b/drivers/usb/misc/adutux.c
@@ -0,0 +1,900 @@
+/*
+ * adutux - driver for ADU devices from Ontrak Control Systems
+ * This is an experimental driver. Use at your own risk.
+ * This driver is not supported by Ontrak Control Systems.
+ *
+ * Copyright (c) 2003 John Homppi (SCO, leave this notice here)
+ *
+ * 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.
+ *
+ * derived from the Lego USB Tower driver 0.56:
+ * Copyright (c) 2003 David Glance <davidgsf@sourceforge.net>
+ * 2001 Juergen Stuber <stuber@loria.fr>
+ * that was derived from USB Skeleton driver - 0.5
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 5;
+#else
+static int debug = 1;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(lvl, format, arg...) \
+do { \
+ if (debug >= lvl) \
+ printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); \
+} while (0)
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.0.13"
+#define DRIVER_AUTHOR "John Homppi"
+#define DRIVER_DESC "adutux (see www.ontrak.net)"
+
+/* Module parameters */
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* Define these values to match your device */
+#define ADU_VENDOR_ID 0x0a07
+#define ADU_PRODUCT_ID 0x0064
+
+/* table of devices that work with this driver */
+static struct usb_device_id device_table [] = {
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) }, /* ADU100 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) }, /* ADU120 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) }, /* ADU130 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+100) }, /* ADU200 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+108) }, /* ADU208 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+118) }, /* ADU218 */
+ { }/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define ADU_MINOR_BASE 0
+#else
+#define ADU_MINOR_BASE 67
+#endif
+
+/* we can have up to this number of device plugged in at once */
+#define MAX_DEVICES 16
+
+#define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */
+
+/* Structure to hold all of our device specific stuff */
+struct adu_device {
+ struct semaphore sem; /* locks this structure */
+ struct usb_device* udev; /* save off the usb device pointer */
+ struct usb_interface* interface;
+ unsigned char minor; /* the starting minor number for this device */
+ char serial_number[8];
+
+ int open_count; /* number of times this port has been opened */
+
+ char* read_buffer_primary;
+ int read_buffer_length;
+ char* read_buffer_secondary;
+ int secondary_head;
+ int secondary_tail;
+ spinlock_t buflock;
+
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ char* interrupt_in_buffer;
+ struct usb_endpoint_descriptor* interrupt_in_endpoint;
+ struct urb* interrupt_in_urb;
+ int read_urb_finished;
+
+ char* interrupt_out_buffer;
+ struct usb_endpoint_descriptor* interrupt_out_endpoint;
+ struct urb* interrupt_out_urb;
+};
+
+/* prevent races between open() and disconnect */
+static DEFINE_MUTEX(disconnect_mutex);
+static struct usb_driver adu_driver;
+
+static void adu_debug_data(int level, const char *function, int size,
+ const unsigned char *data)
+{
+ int i;
+
+ if (debug < level)
+ return;
+
+ printk(KERN_DEBUG __FILE__": %s - length = %d, data = ",
+ function, size);
+ for (i = 0; i < size; ++i)
+ printk("%.2x ", data[i]);
+ printk("\n");
+}
+
+/**
+ * adu_abort_transfers
+ * aborts transfers and frees associated data structures
+ */
+static void adu_abort_transfers(struct adu_device *dev)
+{
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (dev == NULL) {
+ dbg(1," %s : dev is null", __FUNCTION__);
+ goto exit;
+ }
+
+ if (dev->udev == NULL) {
+ dbg(1," %s : udev is null", __FUNCTION__);
+ goto exit;
+ }
+
+ dbg(2," %s : udev state %d", __FUNCTION__, dev->udev->state);
+ if (dev->udev->state == USB_STATE_NOTATTACHED) {
+ dbg(1," %s : udev is not attached", __FUNCTION__);
+ goto exit;
+ }
+
+ /* shutdown transfer */
+ usb_unlink_urb(dev->interrupt_in_urb);
+ usb_unlink_urb(dev->interrupt_out_urb);
+
+exit:
+ dbg(2," %s : leave", __FUNCTION__);
+}
+
+static void adu_delete(struct adu_device *dev)
+{
+ dbg(2, "%s enter", __FUNCTION__);
+
+ adu_abort_transfers(dev);
+
+ /* free data structures */
+ usb_free_urb(dev->interrupt_in_urb);
+ usb_free_urb(dev->interrupt_out_urb);
+ kfree(dev->read_buffer_primary);
+ kfree(dev->read_buffer_secondary);
+ kfree(dev->interrupt_in_buffer);
+ kfree(dev->interrupt_out_buffer);
+ kfree(dev);
+
+ dbg(2, "%s : leave", __FUNCTION__);
+}
+
+static void adu_interrupt_in_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct adu_device *dev = urb->context;
+
+ dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ urb->transfer_buffer);
+
+ spin_lock(&dev->buflock);
+
+ if (urb->status != 0) {
+ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+ dbg(1," %s : nonzero status received: %d",
+ __FUNCTION__, urb->status);
+ }
+ goto exit;
+ }
+
+ if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
+ if (dev->read_buffer_length <
+ (4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) -
+ (urb->actual_length)) {
+ memcpy (dev->read_buffer_primary +
+ dev->read_buffer_length,
+ dev->interrupt_in_buffer, urb->actual_length);
+
+ dev->read_buffer_length += urb->actual_length;
+ dbg(2," %s reading %d ", __FUNCTION__,
+ urb->actual_length);
+ } else {
+ dbg(1," %s : read_buffer overflow", __FUNCTION__);
+ }
+ }
+
+exit:
+ dev->read_urb_finished = 1;
+ spin_unlock(&dev->buflock);
+ /* always wake up so we recover from errors */
+ wake_up_interruptible(&dev->read_wait);
+ adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ urb->transfer_buffer);
+ dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+}
+
+static void adu_interrupt_out_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct adu_device *dev = urb->context;
+
+ dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
+
+ if (urb->status != 0) {
+ if ((urb->status != -ENOENT) &&
+ (urb->status != -ECONNRESET)) {
+ dbg(1, " %s :nonzero status received: %d",
+ __FUNCTION__, urb->status);
+ }
+ goto exit;
+ }
+
+ wake_up_interruptible(&dev->write_wait);
+exit:
+
+ adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ urb->transfer_buffer);
+ dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+}
+
+static int adu_open(struct inode *inode, struct file *file)
+{
+ struct adu_device *dev = NULL;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+
+ dbg(2,"%s : enter", __FUNCTION__);
+
+ subminor = iminor(inode);
+
+ mutex_lock(&disconnect_mutex);
+
+ interface = usb_find_interface(&adu_driver, subminor);
+ if (!interface) {
+ err("%s - error, can't find device for minor %d",
+ __FUNCTION__, subminor);
+ retval = -ENODEV;
+ goto exit_no_device;
+ }
+
+ dev = usb_get_intfdata(interface);
+ if (!dev) {
+ retval = -ENODEV;
+ goto exit_no_device;
+ }
+
+ /* lock this device */
+ if ((retval = down_interruptible(&dev->sem))) {
+ dbg(2, "%s : sem down failed", __FUNCTION__);
+ goto exit_no_device;
+ }
+
+ /* increment our usage count for the device */
+ ++dev->open_count;
+ dbg(2,"%s : open count %d", __FUNCTION__, dev->open_count);
+
+ /* save device in the file's private structure */
+ file->private_data = dev;
+
+ /* initialize in direction */
+ dev->read_buffer_length = 0;
+
+ /* fixup first read by having urb waiting for it */
+ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ adu_interrupt_in_callback, dev,
+ dev->interrupt_in_endpoint->bInterval);
+ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
+ dev->read_urb_finished = 0;
+ usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ /* we ignore failure */
+ /* end of fixup for first read */
+
+ up(&dev->sem);
+
+exit_no_device:
+ mutex_unlock(&disconnect_mutex);
+ dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
+
+ return retval;
+}
+
+static int adu_release_internal(struct adu_device *dev)
+{
+ int retval = 0;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (dev->udev == NULL) {
+ /* the device was unplugged before the file was released */
+ adu_delete(dev);
+ goto exit;
+ }
+
+ /* decrement our usage count for the device */
+ --dev->open_count;
+ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
+ if (dev->open_count <= 0) {
+ adu_abort_transfers(dev);
+ dev->open_count = 0;
+ }
+
+exit:
+ dbg(2," %s : leave", __FUNCTION__);
+ return retval;
+}
+
+static int adu_release(struct inode *inode, struct file *file)
+{
+ struct adu_device *dev = NULL;
+ int retval = 0;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (file == NULL) {
+ dbg(1," %s : file is NULL", __FUNCTION__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ dev = file->private_data;
+
+ if (dev == NULL) {
+ dbg(1," %s : object is NULL", __FUNCTION__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* lock our device */
+ down(&dev->sem); /* not interruptible */
+
+ if (dev->open_count <= 0) {
+ dbg(1," %s : device not opened", __FUNCTION__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* do the work */
+ retval = adu_release_internal(dev);
+
+exit:
+ up(&dev->sem);
+ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ return retval;
+}
+
+static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct adu_device *dev;
+ size_t bytes_read = 0;
+ size_t bytes_to_read = count;
+ int i;
+ int retval = 0;
+ int timeout = 0;
+ int should_submit = 0;
+ unsigned long flags;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dbg(2," %s : enter, count = %Zd, file=%p", __FUNCTION__, count, file);
+
+ dev = file->private_data;
+ dbg(2," %s : dev=%p", __FUNCTION__, dev);
+ /* lock this object */
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* verify that the device wasn't unplugged */
+ if (dev->udev == NULL || dev->minor == 0) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d", retval);
+ goto exit;
+ }
+
+ /* verify that some data was requested */
+ if (count == 0) {
+ dbg(1," %s : read request of 0 bytes", __FUNCTION__);
+ goto exit;
+ }
+
+ timeout = COMMAND_TIMEOUT;
+ dbg(2," %s : about to start looping", __FUNCTION__);
+ while (bytes_to_read) {
+ int data_in_secondary = dev->secondary_tail - dev->secondary_head;
+ dbg(2," %s : while, data_in_secondary=%d, status=%d",
+ __FUNCTION__, data_in_secondary,
+ dev->interrupt_in_urb->status);
+
+ if (data_in_secondary) {
+ /* drain secondary buffer */
+ int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
+ i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
+ if (i < 0) {
+ retval = -EFAULT;
+ goto exit;
+ }
+ dev->secondary_head += (amount - i);
+ bytes_read += (amount - i);
+ bytes_to_read -= (amount - i);
+ if (i) {
+ retval = bytes_read ? bytes_read : -EFAULT;
+ goto exit;
+ }
+ } else {
+ /* we check the primary buffer */
+ spin_lock_irqsave (&dev->buflock, flags);
+ if (dev->read_buffer_length) {
+ /* we secure access to the primary */
+ char *tmp;
+ dbg(2," %s : swap, read_buffer_length = %d",
+ __FUNCTION__, dev->read_buffer_length);
+ tmp = dev->read_buffer_secondary;
+ dev->read_buffer_secondary = dev->read_buffer_primary;
+ dev->read_buffer_primary = tmp;
+ dev->secondary_head = 0;
+ dev->secondary_tail = dev->read_buffer_length;
+ dev->read_buffer_length = 0;
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ /* we have a free buffer so use it */
+ should_submit = 1;
+ } else {
+ /* even the primary was empty - we may need to do IO */
+ if (dev->interrupt_in_urb->status == -EINPROGRESS) {
+ /* somebody is doing IO */
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ dbg(2," %s : submitted already", __FUNCTION__);
+ } else {
+ /* we must initiate input */
+ dbg(2," %s : initiate input", __FUNCTION__);
+ dev->read_urb_finished = 0;
+
+ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ adu_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_endpoint->bInterval);
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ if (!retval) {
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ dbg(2," %s : submitted OK", __FUNCTION__);
+ } else {
+ if (retval == -ENOMEM) {
+ retval = bytes_read ? bytes_read : -ENOMEM;
+ }
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ dbg(2," %s : submit failed", __FUNCTION__);
+ goto exit;
+ }
+ }
+
+ /* we wait for I/O to complete */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&dev->read_wait, &wait);
+ if (!dev->read_urb_finished)
+ timeout = schedule_timeout(COMMAND_TIMEOUT);
+ else
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->read_wait, &wait);
+
+ if (timeout <= 0) {
+ dbg(2," %s : timeout", __FUNCTION__);
+ retval = bytes_read ? bytes_read : -ETIMEDOUT;
+ goto exit;
+ }
+
+ if (signal_pending(current)) {
+ dbg(2," %s : signal pending", __FUNCTION__);
+ retval = bytes_read ? bytes_read : -EINTR;
+ goto exit;
+ }
+ }
+ }
+ }
+
+ retval = bytes_read;
+ /* if the primary buffer is empty then use it */
+ if (should_submit && !dev->interrupt_in_urb->status==-EINPROGRESS) {
+ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ adu_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_endpoint->bInterval);
+ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
+ dev->read_urb_finished = 0;
+ usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ /* we ignore failure */
+ }
+
+exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ return retval;
+}
+
+static ssize_t adu_write(struct file *file, const __user char *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct adu_device *dev;
+ size_t bytes_written = 0;
+ size_t bytes_to_write;
+ size_t buffer_size;
+ int retval = 0;
+ int timeout = 0;
+
+ dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);
+
+ dev = file->private_data;
+
+ /* lock this object */
+ down_interruptible(&dev->sem);
+
+ /* verify that the device wasn't unplugged */
+ if (dev->udev == NULL || dev->minor == 0) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d", retval);
+ goto exit;
+ }
+
+ /* verify that we actually have some data to write */
+ if (count == 0) {
+ dbg(1," %s : write request of 0 bytes", __FUNCTION__);
+ goto exit;
+ }
+
+
+ while (count > 0) {
+ if (dev->interrupt_out_urb->status == -EINPROGRESS) {
+ timeout = COMMAND_TIMEOUT;
+
+ while (timeout > 0) {
+ if (signal_pending(current)) {
+ dbg(1," %s : interrupted", __FUNCTION__);
+ retval = -EINTR;
+ goto exit;
+ }
+ up(&dev->sem);
+ timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
+ down_interruptible(&dev->sem);
+ if (timeout > 0) {
+ break;
+ }
+ dbg(1," %s : interrupted timeout: %d", __FUNCTION__, timeout);
+ }
+
+
+ dbg(1," %s : final timeout: %d", __FUNCTION__, timeout);
+
+ if (timeout == 0) {
+ dbg(1, "%s - command timed out.", __FUNCTION__);
+ retval = -ETIMEDOUT;
+ goto exit;
+ }
+
+ dbg(4," %s : in progress, count = %Zd", __FUNCTION__, count);
+
+ } else {
+ dbg(4," %s : sending, count = %Zd", __FUNCTION__, count);
+
+ /* write the data into interrupt_out_buffer from userspace */
+ buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+ bytes_to_write = count > buffer_size ? buffer_size : count;
+ dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
+ __FUNCTION__, buffer_size, count, bytes_to_write);
+
+ if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ /* send off the urb */
+ usb_fill_int_urb(
+ dev->interrupt_out_urb,
+ dev->udev,
+ usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ adu_interrupt_out_callback,
+ dev,
+ dev->interrupt_in_endpoint->bInterval);
+ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
+ dev->interrupt_out_urb->actual_length = bytes_to_write;
+ retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
+ if (retval < 0) {
+ err("Couldn't submit interrupt_out_urb %d", retval);
+ goto exit;
+ }
+
+ buffer += bytes_to_write;
+ count -= bytes_to_write;
+
+ bytes_written += bytes_to_write;
+ }
+ }
+
+ retval = bytes_written;
+
+exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+
+ return retval;
+}
+
+/* file operations needed when we register this driver */
+static struct file_operations adu_fops = {
+ .owner = THIS_MODULE,
+ .read = adu_read,
+ .write = adu_write,
+ .open = adu_open,
+ .release = adu_release,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver adu_class = {
+ .name = "usb/adutux%d",
+ .fops = &adu_fops,
+ .minor_base = ADU_MINOR_BASE,
+};
+
+/**
+ * adu_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int adu_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct adu_device *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int retval = -ENODEV;
+ int in_end_size;
+ int out_end_size;
+ int i;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (udev == NULL) {
+ dev_err(&interface->dev, "udev is NULL.\n");
+ goto exit;
+ }
+
+ /* allocate memory for our device state and intialize it */
+ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ init_MUTEX(&dev->sem);
+ spin_lock_init(&dev->buflock);
+ dev->udev = udev;
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+
+ iface_desc = &interface->altsetting[0];
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint))
+ dev->interrupt_in_endpoint = endpoint;
+
+ if (usb_endpoint_is_int_out(endpoint))
+ dev->interrupt_out_endpoint = endpoint;
+ }
+ if (dev->interrupt_in_endpoint == NULL) {
+ dev_err(&interface->dev, "interrupt in endpoint not found\n");
+ goto error;
+ }
+ if (dev->interrupt_out_endpoint == NULL) {
+ dev_err(&interface->dev, "interrupt out endpoint not found\n");
+ goto error;
+ }
+
+ in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+ out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+
+ dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
+ if (!dev->read_buffer_primary) {
+ dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ /* debug code prime the buffer */
+ memset(dev->read_buffer_primary, 'a', in_end_size);
+ memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size);
+ memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size);
+ memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size);
+
+ dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL);
+ if (!dev->read_buffer_secondary) {
+ dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ /* debug code prime the buffer */
+ memset(dev->read_buffer_secondary, 'e', in_end_size);
+ memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size);
+ memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size);
+ memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size);
+
+ dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL);
+ if (!dev->interrupt_in_buffer) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
+ goto error;
+ }
+
+ /* debug code prime the buffer */
+ memset(dev->interrupt_in_buffer, 'i', in_end_size);
+
+ dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_in_urb) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL);
+ if (!dev->interrupt_out_buffer) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n");
+ goto error;
+ }
+ dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_out_urb) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_out_urb\n");
+ goto error;
+ }
+
+ if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number,
+ sizeof(dev->serial_number))) {
+ dev_err(&interface->dev, "Could not retrieve serial number\n");
+ goto error;
+ }
+ dbg(2," %s : serial_number=%s", __FUNCTION__, dev->serial_number);
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(interface, dev);
+
+ retval = usb_register_dev(interface, &adu_class);
+
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&interface->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(interface, NULL);
+ goto error;
+ }
+
+ dev->minor = interface->minor;
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d",
+ udev->descriptor.idProduct, dev->serial_number,
+ (dev->minor - ADU_MINOR_BASE));
+exit:
+ dbg(2," %s : leave, return value %p (dev)", __FUNCTION__, dev);
+
+ return retval;
+
+error:
+ adu_delete(dev);
+ return retval;
+}
+
+/**
+ * adu_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void adu_disconnect(struct usb_interface *interface)
+{
+ struct adu_device *dev;
+ int minor;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ mutex_lock(&disconnect_mutex); /* not interruptible */
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ down(&dev->sem); /* not interruptible */
+
+ minor = dev->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(interface, &adu_class);
+ dev->minor = 0;
+
+ /* if the device is not opened, then we clean up right now */
+ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
+ if (!dev->open_count) {
+ up(&dev->sem);
+ adu_delete(dev);
+ } else {
+ dev->udev = NULL;
+ up(&dev->sem);
+ }
+
+ mutex_unlock(&disconnect_mutex);
+
+ dev_info(&interface->dev, "ADU device adutux%d now disconnected",
+ (minor - ADU_MINOR_BASE));
+
+ dbg(2," %s : leave", __FUNCTION__);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver adu_driver = {
+ .name = "adutux",
+ .probe = adu_probe,
+ .disconnect = adu_disconnect,
+ .id_table = device_table,
+};
+
+static int __init adu_init(void)
+{
+ int result;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&adu_driver);
+ if (result < 0) {
+ err("usb_register failed for the "__FILE__" driver. "
+ "Error number %d", result);
+ goto exit;
+ }
+
+ info("adutux " DRIVER_DESC " " DRIVER_VERSION);
+ info("adutux is an experimental driver. Use at your own risk");
+
+exit:
+ dbg(2," %s : leave, return value %d", __FUNCTION__, result);
+
+ return result;
+}
+
+static void __exit adu_exit(void)
+{
+ dbg(2," %s : enter", __FUNCTION__);
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&adu_driver);
+ dbg(2," %s : leave", __FUNCTION__);
+}
+
+module_init(adu_init);
+module_exit(adu_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 1fef36e71c5..4fd2110b341 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -806,7 +806,7 @@ static void auerbuf_releasebuf( pauerbuf_t bp)
0 Initial, OK
-EINPROGRESS during submission until end
-ENOENT if urb is unlinked
--ETIMEDOUT Transfer timed out, NAK
+-ETIME Device did not respond
-ENOMEM Memory Overflow
-ENODEV Specified USB-device or bus doesn't exist
-ENXIO URB already queued
@@ -832,7 +832,7 @@ static int auerswald_status_retry (int status)
{
switch (status) {
case 0:
- case -ETIMEDOUT:
+ case -ETIME:
case -EOVERFLOW:
case -EAGAIN:
case -EPIPE:
@@ -1858,7 +1858,7 @@ static int auerchar_release (struct inode *inode, struct file *file)
/*----------------------------------------------------------------------*/
/* File operation structure */
-static struct file_operations auerswald_fops =
+static const struct file_operations auerswald_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/usb/misc/cy7c63.c b/drivers/usb/misc/cy7c63.c
deleted file mode 100644
index 8a1c10b89b7..00000000000
--- a/drivers/usb/misc/cy7c63.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-* cy7c63.c
-*
-* Copyright (c) 2006 Oliver Bock (bock@fh-wolfenbuettel.de)
-*
-* This driver is based on the Cypress Thermometer USB Driver by
-* Marcus Maul and the 2.0 version of Greg Kroah-Hartman's
-* USB Skeleton driver.
-*
-* Is is a generic driver for the Cypress CY7C63000 family.
-* For the time being it enables you to toggle the single I/O ports
-* of the device.
-*
-* Supported vendors: AK Modul-Bus Computer GmbH
-* Supported devices: CY7C63001A-PC (to be continued...)
-* Supported functions: Read/Write Ports (to be continued...)
-*
-* Chipsets families: CY7C63000, CY7C63001, CY7C63100, CY7C63101
-*
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License as
-* published by the Free Software Foundation, version 2.
-*/
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/usb.h>
-
-#define DRIVER_AUTHOR "Oliver Bock (bock@fh-wolfenbuettel.de)"
-#define DRIVER_DESC "Cypress CY7C63xxx USB driver"
-
-#define CY7C63_VENDOR_ID 0xa2c
-#define CY7C63_PRODUCT_ID 0x8
-
-#define CY7C63_READ_PORT 0x4
-#define CY7C63_WRITE_PORT 0x5
-#define CY7C63_READ_RAM 0x2
-#define CY7C63_WRITE_RAM 0x3
-#define CY7C63_READ_ROM 0x1
-
-#define CY7C63_READ_PORT_ID0 0
-#define CY7C63_WRITE_PORT_ID0 0
-#define CY7C63_READ_PORT_ID1 0x2
-#define CY7C63_WRITE_PORT_ID1 1
-
-#define CY7C63_MAX_REQSIZE 8
-
-
-/* table of devices that work with this driver */
-static struct usb_device_id cy7c63_table [] = {
- { USB_DEVICE(CY7C63_VENDOR_ID, CY7C63_PRODUCT_ID) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, cy7c63_table);
-
-/* structure to hold all of our device specific stuff */
-struct cy7c63 {
- struct usb_device * udev;
- char port0;
- char port1;
-};
-
-/* used to send usb control messages to device */
-int vendor_command(struct cy7c63 *dev, unsigned char request,
- unsigned char address, unsigned char data) {
-
- int retval = 0;
- unsigned int pipe;
- unsigned char *iobuf;
-
- /* allocate some memory for the i/o buffer*/
- iobuf = kzalloc(CY7C63_MAX_REQSIZE, GFP_KERNEL);
- if (!iobuf) {
- dev_err(&dev->udev->dev, "Out of memory!\n");
- retval = -ENOMEM;
- goto error;
- }
-
- dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
-
- /* prepare usb control message and send it upstream */
- pipe = usb_rcvctrlpipe(dev->udev, 0);
- retval = usb_control_msg(dev->udev, pipe, request,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
- address, data, iobuf, CY7C63_MAX_REQSIZE,
- USB_CTRL_GET_TIMEOUT);
-
- /* store returned data (more READs to be added!) */
- switch (request) {
- case CY7C63_READ_PORT:
- if (address == CY7C63_READ_PORT_ID0) {
- dev->port0 = iobuf[1];
- dev_dbg(&dev->udev->dev,
- "READ_PORT0 returned: %d\n",dev->port0);
- }
- else if (address == CY7C63_READ_PORT_ID1) {
- dev->port1 = iobuf[1];
- dev_dbg(&dev->udev->dev,
- "READ_PORT1 returned: %d\n",dev->port1);
- }
- break;
- }
-
- kfree(iobuf);
-error:
- return retval;
-}
-
-#define get_set_port(num,read_id,write_id) \
-static ssize_t set_port##num(struct device *dev, struct device_attribute *attr, \
- const char *buf, size_t count) { \
- \
- int value; \
- int result = 0; \
- \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct cy7c63 *cyp = usb_get_intfdata(intf); \
- \
- dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", num); \
- \
- /* validate input data */ \
- if (sscanf(buf, "%d", &value) < 1) { \
- result = -EINVAL; \
- goto error; \
- } \
- if (value>255 || value<0) { \
- result = -EINVAL; \
- goto error; \
- } \
- \
- result = vendor_command(cyp, CY7C63_WRITE_PORT, write_id, \
- (unsigned char)value); \
- \
- dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n",result); \
-error: \
- return result < 0 ? result : count; \
-} \
- \
-static ssize_t get_port##num(struct device *dev, \
- struct device_attribute *attr, char *buf) { \
- \
- int result = 0; \
- \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct cy7c63 *cyp = usb_get_intfdata(intf); \
- \
- dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", num); \
- \
- result = vendor_command(cyp, CY7C63_READ_PORT, read_id, 0); \
- \
- dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result); \
- \
- return sprintf(buf, "%d", cyp->port##num); \
-} \
-static DEVICE_ATTR(port##num, S_IWUGO | S_IRUGO, get_port##num, set_port##num);
-
-get_set_port(0, CY7C63_READ_PORT_ID0, CY7C63_WRITE_PORT_ID0);
-get_set_port(1, CY7C63_READ_PORT_ID1, CY7C63_WRITE_PORT_ID1);
-
-static int cy7c63_probe(struct usb_interface *interface,
- const struct usb_device_id *id) {
-
- struct cy7c63 *dev = NULL;
- int retval = -ENOMEM;
-
- /* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
- dev_err(&dev->udev->dev, "Out of memory!\n");
- goto error;
- }
-
- dev->udev = usb_get_dev(interface_to_usbdev(interface));
-
- /* save our data pointer in this interface device */
- usb_set_intfdata(interface, dev);
-
- /* create device attribute files */
- device_create_file(&interface->dev, &dev_attr_port0);
- device_create_file(&interface->dev, &dev_attr_port1);
-
- /* let the user know what node this device is now attached to */
- dev_info(&interface->dev,
- "Cypress CY7C63xxx device now attached\n");
-
- retval = 0;
-error:
- return retval;
-}
-
-static void cy7c63_disconnect(struct usb_interface *interface) {
-
- struct cy7c63 *dev;
-
- dev = usb_get_intfdata(interface);
- usb_set_intfdata(interface, NULL);
-
- /* remove device attribute files */
- device_remove_file(&interface->dev, &dev_attr_port0);
- device_remove_file(&interface->dev, &dev_attr_port1);
-
- usb_put_dev(dev->udev);
-
- dev_info(&interface->dev,
- "Cypress CY7C63xxx device now disconnected\n");
-
- kfree(dev);
-}
-
-static struct usb_driver cy7c63_driver = {
- .name = "cy7c63",
- .probe = cy7c63_probe,
- .disconnect = cy7c63_disconnect,
- .id_table = cy7c63_table,
-};
-
-static int __init cy7c63_init(void) {
-
- int result;
-
- /* register this driver with the USB subsystem */
- result = usb_register(&cy7c63_driver);
- if (result) {
- err("Function usb_register failed! Error number: %d\n", result);
- }
-
- return result;
-}
-
-static void __exit cy7c63_exit(void) {
-
- /* deregister this driver with the USB subsystem */
- usb_deregister(&cy7c63_driver);
-}
-
-module_init(cy7c63_init);
-module_exit(cy7c63_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
new file mode 100644
index 00000000000..b63b5f34b2a
--- /dev/null
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -0,0 +1,295 @@
+/*
+* cypress_cy7c63.c
+*
+* Copyright (c) 2006 Oliver Bock (o.bock@fh-wolfenbuettel.de)
+*
+* This driver is based on the Cypress USB Driver by Marcus Maul
+* (cyport) and the 2.0 version of Greg Kroah-Hartman's
+* USB Skeleton driver.
+*
+* This is a generic driver for the Cypress CY7C63xxx family.
+* For the time being it enables you to read from and write to
+* the single I/O ports of the device.
+*
+* Supported vendors: AK Modul-Bus Computer GmbH
+* (Firmware "Port-Chip")
+*
+* Supported devices: CY7C63001A-PC
+* CY7C63001C-PXC
+* CY7C63001C-SXC
+*
+* Supported functions: Read/Write Ports
+*
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation, version 2.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#define DRIVER_AUTHOR "Oliver Bock (o.bock@fh-wolfenbuettel.de)"
+#define DRIVER_DESC "Cypress CY7C63xxx USB driver"
+
+#define CYPRESS_VENDOR_ID 0xa2c
+#define CYPRESS_PRODUCT_ID 0x8
+
+#define CYPRESS_READ_PORT 0x4
+#define CYPRESS_WRITE_PORT 0x5
+
+#define CYPRESS_READ_RAM 0x2
+#define CYPRESS_WRITE_RAM 0x3
+#define CYPRESS_READ_ROM 0x1
+
+#define CYPRESS_READ_PORT_ID0 0
+#define CYPRESS_WRITE_PORT_ID0 0
+#define CYPRESS_READ_PORT_ID1 0x2
+#define CYPRESS_WRITE_PORT_ID1 1
+
+#define CYPRESS_MAX_REQSIZE 8
+
+
+/* table of devices that work with this driver */
+static struct usb_device_id cypress_table [] = {
+ { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, cypress_table);
+
+/* structure to hold all of our device specific stuff */
+struct cypress {
+ struct usb_device * udev;
+ unsigned char port[2];
+};
+
+/* used to send usb control messages to device */
+static int vendor_command(struct cypress *dev, unsigned char request,
+ unsigned char address, unsigned char data)
+{
+ int retval = 0;
+ unsigned int pipe;
+ unsigned char *iobuf;
+
+ /* allocate some memory for the i/o buffer*/
+ iobuf = kzalloc(CYPRESS_MAX_REQSIZE, GFP_KERNEL);
+ if (!iobuf) {
+ dev_err(&dev->udev->dev, "Out of memory!\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev_dbg(&dev->udev->dev, "Sending usb_control_msg (data: %d)\n", data);
+
+ /* prepare usb control message and send it upstream */
+ pipe = usb_rcvctrlpipe(dev->udev, 0);
+ retval = usb_control_msg(dev->udev, pipe, request,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ address, data, iobuf, CYPRESS_MAX_REQSIZE,
+ USB_CTRL_GET_TIMEOUT);
+
+ /* store returned data (more READs to be added) */
+ switch (request) {
+ case CYPRESS_READ_PORT:
+ if (address == CYPRESS_READ_PORT_ID0) {
+ dev->port[0] = iobuf[1];
+ dev_dbg(&dev->udev->dev,
+ "READ_PORT0 returned: %d\n",
+ dev->port[0]);
+ }
+ else if (address == CYPRESS_READ_PORT_ID1) {
+ dev->port[1] = iobuf[1];
+ dev_dbg(&dev->udev->dev,
+ "READ_PORT1 returned: %d\n",
+ dev->port[1]);
+ }
+ break;
+ }
+
+ kfree(iobuf);
+error:
+ return retval;
+}
+
+/* write port value */
+static ssize_t write_port(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count,
+ int port_num, int write_id)
+{
+ int value = -1;
+ int result = 0;
+
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct cypress *cyp = usb_get_intfdata(intf);
+
+ dev_dbg(&cyp->udev->dev, "WRITE_PORT%d called\n", port_num);
+
+ /* validate input data */
+ if (sscanf(buf, "%d", &value) < 1) {
+ result = -EINVAL;
+ goto error;
+ }
+ if (value < 0 || value > 255) {
+ result = -EINVAL;
+ goto error;
+ }
+
+ result = vendor_command(cyp, CYPRESS_WRITE_PORT, write_id,
+ (unsigned char)value);
+
+ dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
+error:
+ return result < 0 ? result : count;
+}
+
+/* attribute callback handler (write) */
+static ssize_t set_port0_handler(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return write_port(dev, attr, buf, count, 0, CYPRESS_WRITE_PORT_ID0);
+}
+
+/* attribute callback handler (write) */
+static ssize_t set_port1_handler(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ return write_port(dev, attr, buf, count, 1, CYPRESS_WRITE_PORT_ID1);
+}
+
+/* read port value */
+static ssize_t read_port(struct device *dev, struct device_attribute *attr,
+ char *buf, int port_num, int read_id)
+{
+ int result = 0;
+
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct cypress *cyp = usb_get_intfdata(intf);
+
+ dev_dbg(&cyp->udev->dev, "READ_PORT%d called\n", port_num);
+
+ result = vendor_command(cyp, CYPRESS_READ_PORT, read_id, 0);
+
+ dev_dbg(&cyp->udev->dev, "Result of vendor_command: %d\n\n", result);
+
+ return sprintf(buf, "%d", cyp->port[port_num]);
+}
+
+/* attribute callback handler (read) */
+static ssize_t get_port0_handler(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_port(dev, attr, buf, 0, CYPRESS_READ_PORT_ID0);
+}
+
+/* attribute callback handler (read) */
+static ssize_t get_port1_handler(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return read_port(dev, attr, buf, 1, CYPRESS_READ_PORT_ID1);
+}
+
+static DEVICE_ATTR(port0, S_IWUGO | S_IRUGO,
+ get_port0_handler, set_port0_handler);
+
+static DEVICE_ATTR(port1, S_IWUGO | S_IRUGO,
+ get_port1_handler, set_port1_handler);
+
+
+static int cypress_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct cypress *dev = NULL;
+ int retval = -ENOMEM;
+
+ /* allocate memory for our device state and initialize it */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory!\n");
+ goto error_mem;
+ }
+
+ dev->udev = usb_get_dev(interface_to_usbdev(interface));
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, dev);
+
+ /* create device attribute files */
+ retval = device_create_file(&interface->dev, &dev_attr_port0);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_port1);
+ if (retval)
+ goto error;
+
+ /* let the user know that the device is now attached */
+ dev_info(&interface->dev,
+ "Cypress CY7C63xxx device now attached\n");
+ return 0;
+
+error:
+ device_remove_file(&interface->dev, &dev_attr_port0);
+ device_remove_file(&interface->dev, &dev_attr_port1);
+ usb_set_intfdata(interface, NULL);
+ usb_put_dev(dev->udev);
+ kfree(dev);
+
+error_mem:
+ return retval;
+}
+
+static void cypress_disconnect(struct usb_interface *interface)
+{
+ struct cypress *dev;
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ /* remove device attribute files */
+ device_remove_file(&interface->dev, &dev_attr_port0);
+ device_remove_file(&interface->dev, &dev_attr_port1);
+
+ usb_put_dev(dev->udev);
+
+ dev_info(&interface->dev,
+ "Cypress CY7C63xxx device now disconnected\n");
+
+ kfree(dev);
+}
+
+static struct usb_driver cypress_driver = {
+ .name = "cypress_cy7c63",
+ .probe = cypress_probe,
+ .disconnect = cypress_disconnect,
+ .id_table = cypress_table,
+};
+
+static int __init cypress_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&cypress_driver);
+ if (result) {
+ err("Function usb_register failed! Error number: %d\n", result);
+ }
+
+ return result;
+}
+
+static void __exit cypress_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&cypress_driver);
+}
+
+module_init(cypress_init);
+module_exit(cypress_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index a04204292aa..04e87acd6e4 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -14,7 +14,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -354,7 +353,7 @@ static int cytherm_probe(struct usb_interface *interface,
dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
if (dev == NULL) {
dev_err (&interface->dev, "Out of memory\n");
- goto error;
+ goto error_mem;
}
dev->udev = usb_get_dev(udev);
@@ -363,18 +362,35 @@ static int cytherm_probe(struct usb_interface *interface,
dev->brightness = 0xFF;
- device_create_file(&interface->dev, &dev_attr_brightness);
- device_create_file(&interface->dev, &dev_attr_temp);
- device_create_file(&interface->dev, &dev_attr_button);
- device_create_file(&interface->dev, &dev_attr_port0);
- device_create_file(&interface->dev, &dev_attr_port1);
+ retval = device_create_file(&interface->dev, &dev_attr_brightness);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_temp);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_button);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_port0);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_port1);
+ if (retval)
+ goto error;
- dev_info (&interface->dev,
+ dev_info (&interface->dev,
"Cypress thermometer device now attached\n");
return 0;
-
- error:
+error:
+ device_remove_file(&interface->dev, &dev_attr_brightness);
+ device_remove_file(&interface->dev, &dev_attr_temp);
+ device_remove_file(&interface->dev, &dev_attr_button);
+ device_remove_file(&interface->dev, &dev_attr_port0);
+ device_remove_file(&interface->dev, &dev_attr_port1);
+ usb_set_intfdata (interface, NULL);
+ usb_put_dev(dev->udev);
kfree(dev);
+error_mem:
return retval;
}
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
new file mode 100644
index 00000000000..b88a09497c2
--- /dev/null
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -0,0 +1,2809 @@
+/*
+* USB FTDI client driver for Elan Digital Systems's Uxxx adapters
+*
+* Copyright(C) 2006 Elan Digital Systems Limited
+* http://www.elandigitalsystems.com
+*
+* Author and Maintainer - Tony Olech - Elan Digital Systems
+* tony.olech@elandigitalsystems.com
+*
+* This program is free software;you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation, version 2.
+*
+*
+* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
+* based on various USB client drivers in the 2.6.15 linux kernel
+* with constant reference to the 3rd Edition of Linux Device Drivers
+* published by O'Reilly
+*
+* The U132 adapter is a USB to CardBus adapter specifically designed
+* for PC cards that contain an OHCI host controller. Typical PC cards
+* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
+*
+* The U132 adapter will *NOT *work with PC cards that do not contain
+* an OHCI controller. A simple way to test whether a PC card has an
+* OHCI controller as an interface is to insert the PC card directly
+* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
+* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
+* then there is a good chance that the U132 adapter will support the
+* PC card.(you also need the specific client driver for the PC card)
+*
+* Please inform the Author and Maintainer about any PC cards that
+* contain OHCI Host Controller and work when directly connected to
+* an embedded CardBus slot but do not work when they are connected
+* via an ELAN U132 adapter.
+*
+*/
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+MODULE_AUTHOR("Tony Olech");
+MODULE_DESCRIPTION("FTDI ELAN driver");
+MODULE_LICENSE("GPL");
+#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
+extern struct platform_driver u132_platform_driver;
+static struct workqueue_struct *status_queue;
+static struct workqueue_struct *command_queue;
+static struct workqueue_struct *respond_queue;
+/*
+* ftdi_module_lock exists to protect access to global variables
+*
+*/
+static struct semaphore ftdi_module_lock;
+static int ftdi_instances = 0;
+static struct list_head ftdi_static_list;
+/*
+* end of the global variables protected by ftdi_module_lock
+*/
+#include "usb_u132.h"
+#define TD_DEVNOTRESP 5
+/* Define these values to match your devices*/
+#define USB_FTDI_ELAN_VENDOR_ID 0x0403
+#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
+/* table of devices that work with this driver*/
+static struct usb_device_id ftdi_elan_table[] = {
+ {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
+ { /* Terminating entry */ }
+};
+
+MODULE_DEVICE_TABLE(usb, ftdi_elan_table);
+/* only the jtag(firmware upgrade device) interface requires
+* a device file and corresponding minor number, but the
+* interface is created unconditionally - I suppose it could
+* be configured or not according to a module parameter.
+* But since we(now) require one interface per device,
+* and since it unlikely that a normal installation would
+* require more than a couple of elan-ftdi devices, 8 seems
+* like a reasonable limit to have here, and if someone
+* really requires more than 8 devices, then they can frig the
+* code and recompile
+*/
+#define USB_FTDI_ELAN_MINOR_BASE 192
+#define COMMAND_BITS 5
+#define COMMAND_SIZE (1<<COMMAND_BITS)
+#define COMMAND_MASK (COMMAND_SIZE-1)
+struct u132_command {
+ u8 header;
+ u16 length;
+ u8 address;
+ u8 width;
+ u32 value;
+ int follows;
+ void *buffer;
+};
+#define RESPOND_BITS 5
+#define RESPOND_SIZE (1<<RESPOND_BITS)
+#define RESPOND_MASK (RESPOND_SIZE-1)
+struct u132_respond {
+ u8 header;
+ u8 address;
+ u32 *value;
+ int *result;
+ struct completion wait_completion;
+};
+struct u132_target {
+ void *endp;
+ struct urb *urb;
+ int toggle_bits;
+ int error_count;
+ int condition_code;
+ int repeat_number;
+ int halted;
+ int skipped;
+ int actual;
+ int non_null;
+ int active;
+ int abandoning;
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual,
+ int non_null);
+};
+/* Structure to hold all of our device specific stuff*/
+struct usb_ftdi {
+ struct list_head ftdi_list;
+ struct semaphore u132_lock;
+ int command_next;
+ int command_head;
+ struct u132_command command[COMMAND_SIZE];
+ int respond_next;
+ int respond_head;
+ struct u132_respond respond[RESPOND_SIZE];
+ struct u132_target target[4];
+ char device_name[16];
+ unsigned synchronized:1;
+ unsigned enumerated:1;
+ unsigned registered:1;
+ unsigned initialized:1;
+ unsigned card_ejected:1;
+ int function;
+ int sequence_num;
+ int disconnected;
+ int gone_away;
+ int stuck_status;
+ int status_queue_delay;
+ struct semaphore sw_lock;
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ struct usb_class_driver *class;
+ struct work_struct status_work;
+ struct work_struct command_work;
+ struct work_struct respond_work;
+ struct u132_platform_data platform_data;
+ struct resource resources[0];
+ struct platform_device platform_dev;
+ unsigned char *bulk_in_buffer;
+ size_t bulk_in_size;
+ size_t bulk_in_last;
+ size_t bulk_in_left;
+ __u8 bulk_in_endpointAddr;
+ __u8 bulk_out_endpointAddr;
+ struct kref kref;
+ u32 controlreg;
+ u8 response[4 + 1024];
+ int expected;
+ int recieved;
+ int ed_found;
+};
+#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref)
+#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \
+ platform_dev)
+static struct usb_driver ftdi_elan_driver;
+static void ftdi_elan_delete(struct kref *kref)
+{
+ struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref);
+ dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
+ usb_put_dev(ftdi->udev);
+ ftdi->disconnected += 1;
+ down(&ftdi_module_lock);
+ list_del_init(&ftdi->ftdi_list);
+ ftdi_instances -= 1;
+ up(&ftdi_module_lock);
+ kfree(ftdi->bulk_in_buffer);
+ ftdi->bulk_in_buffer = NULL;
+}
+
+static void ftdi_elan_put_kref(struct usb_ftdi *ftdi)
+{
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+static void ftdi_elan_get_kref(struct usb_ftdi *ftdi)
+{
+ kref_get(&ftdi->kref);
+}
+
+static void ftdi_elan_init_kref(struct usb_ftdi *ftdi)
+{
+ kref_init(&ftdi->kref);
+}
+
+static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
+ return;
+ } else if (queue_work(status_queue, &ftdi->status_work))
+ return;
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+ return;
+}
+
+static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
+ kref_get(&ftdi->kref);
+ } else if (queue_work(status_queue, &ftdi->status_work))
+ kref_get(&ftdi->kref);
+ return;
+}
+
+static void ftdi_status_cancel_work(struct usb_ftdi *ftdi)
+{
+ if (cancel_delayed_work(&ftdi->status_work))
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(command_queue, &ftdi->command_work,
+ delta))
+ return;
+ } else if (queue_work(command_queue, &ftdi->command_work))
+ return;
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+ return;
+}
+
+static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(command_queue, &ftdi->command_work,
+ delta))
+ kref_get(&ftdi->kref);
+ } else if (queue_work(command_queue, &ftdi->command_work))
+ kref_get(&ftdi->kref);
+ return;
+}
+
+static void ftdi_command_cancel_work(struct usb_ftdi *ftdi)
+{
+ if (cancel_delayed_work(&ftdi->command_work))
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+static void ftdi_response_requeue_work(struct usb_ftdi *ftdi,
+ unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(respond_queue, &ftdi->respond_work,
+ delta))
+ return;
+ } else if (queue_work(respond_queue, &ftdi->respond_work))
+ return;
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+ return;
+}
+
+static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(respond_queue, &ftdi->respond_work,
+ delta))
+ kref_get(&ftdi->kref);
+ } else if (queue_work(respond_queue, &ftdi->respond_work))
+ kref_get(&ftdi->kref);
+ return;
+}
+
+static void ftdi_response_cancel_work(struct usb_ftdi *ftdi)
+{
+ if (cancel_delayed_work(&ftdi->respond_work))
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+void ftdi_elan_gone_away(struct platform_device *pdev)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ ftdi->gone_away += 1;
+ ftdi_elan_put_kref(ftdi);
+}
+
+
+EXPORT_SYMBOL_GPL(ftdi_elan_gone_away);
+void ftdi_release_platform_dev(struct device *dev)
+{
+ dev->parent = NULL;
+}
+
+static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
+ struct u132_target *target, u8 *buffer, int length);
+static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi);
+static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi);
+static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi);
+static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi);
+static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi);
+static int ftdi_elan_synchronize(struct usb_ftdi *ftdi);
+static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi);
+static int ftdi_elan_command_engine(struct usb_ftdi *ftdi);
+static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);
+static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)
+{
+ int result;
+ if (ftdi->platform_dev.dev.parent)
+ return -EBUSY;
+ ftdi_elan_get_kref(ftdi);
+ ftdi->platform_data.potpg = 100;
+ ftdi->platform_data.reset = NULL;
+ ftdi->platform_dev.id = ftdi->sequence_num;
+ ftdi->platform_dev.resource = ftdi->resources;
+ ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources);
+ ftdi->platform_dev.dev.platform_data = &ftdi->platform_data;
+ ftdi->platform_dev.dev.parent = NULL;
+ ftdi->platform_dev.dev.release = ftdi_release_platform_dev;
+ ftdi->platform_dev.dev.dma_mask = NULL;
+ snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd");
+ ftdi->platform_dev.name = ftdi->device_name;
+ dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd");
+ request_module("u132_hcd");
+ dev_info(&ftdi->udev->dev, "registering '%s'\n",
+ ftdi->platform_dev.name);
+ result = platform_device_register(&ftdi->platform_dev);
+ return result;
+}
+
+static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
+{
+ down(&ftdi->u132_lock);
+ while (ftdi->respond_next > ftdi->respond_head) {
+ struct u132_respond *respond = &ftdi->respond[RESPOND_MASK &
+ ftdi->respond_head++];
+ *respond->result = -ESHUTDOWN;
+ *respond->value = 0;
+ complete(&respond->wait_completion);
+ } up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
+{
+ int ed_number = 4;
+ down(&ftdi->u132_lock);
+ while (ed_number-- > 0) {
+ struct u132_target *target = &ftdi->target[ed_number];
+ if (target->active == 1) {
+ target->condition_code = TD_DEVNOTRESP;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, NULL, 0);
+ down(&ftdi->u132_lock);
+ }
+ }
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
+{
+ int ed_number = 4;
+ down(&ftdi->u132_lock);
+ while (ed_number-- > 0) {
+ struct u132_target *target = &ftdi->target[ed_number];
+ target->abandoning = 1;
+ wait_1:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x80 | (ed_number << 5) | 0x4;
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait_1;
+ }
+ }
+ wait_2:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x90 | (ed_number << 5);
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait_2;
+ }
+ }
+ }
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
+{
+ int ed_number = 4;
+ down(&ftdi->u132_lock);
+ while (ed_number-- > 0) {
+ struct u132_target *target = &ftdi->target[ed_number];
+ target->abandoning = 1;
+ wait:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x80 | (ed_number << 5) | 0x4;
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait;
+ }
+ }
+ }
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
+{
+ ftdi_command_queue_work(ftdi, 0);
+ return;
+}
+
+static void ftdi_elan_command_work(void *data)
+{
+ struct usb_ftdi *ftdi = data;
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else {
+ int retval = ftdi_elan_command_engine(ftdi);
+ if (retval == -ESHUTDOWN) {
+ ftdi->disconnected += 1;
+ } else if (retval == -ENODEV) {
+ ftdi->disconnected += 1;
+ } else if (retval)
+ dev_err(&ftdi->udev->dev, "command error %d\n", retval);
+ ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10));
+ return;
+ }
+}
+
+static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)
+{
+ ftdi_respond_queue_work(ftdi, 0);
+ return;
+}
+
+static void ftdi_elan_respond_work(void *data)
+{
+ struct usb_ftdi *ftdi = data;
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else {
+ int retval = ftdi_elan_respond_engine(ftdi);
+ if (retval == 0) {
+ } else if (retval == -ESHUTDOWN) {
+ ftdi->disconnected += 1;
+ } else if (retval == -ENODEV) {
+ ftdi->disconnected += 1;
+ } else if (retval == -ENODEV) {
+ ftdi->disconnected += 1;
+ } else if (retval == -EILSEQ) {
+ ftdi->disconnected += 1;
+ } else {
+ ftdi->disconnected += 1;
+ dev_err(&ftdi->udev->dev, "respond error %d\n", retval);
+ }
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_abandon_completions(ftdi);
+ ftdi_elan_abandon_targets(ftdi);
+ }
+ ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10));
+ return;
+ }
+}
+
+
+/*
+* the sw_lock is initially held and will be freed
+* after the FTDI has been synchronized
+*
+*/
+static void ftdi_elan_status_work(void *data)
+{
+ struct usb_ftdi *ftdi = data;
+ int work_delay_in_msec = 0;
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else if (ftdi->synchronized == 0) {
+ down(&ftdi->sw_lock);
+ if (ftdi_elan_synchronize(ftdi) == 0) {
+ ftdi->synchronized = 1;
+ ftdi_command_queue_work(ftdi, 1);
+ ftdi_respond_queue_work(ftdi, 1);
+ up(&ftdi->sw_lock);
+ work_delay_in_msec = 100;
+ } else {
+ dev_err(&ftdi->udev->dev, "synchronize failed\n");
+ up(&ftdi->sw_lock);
+ work_delay_in_msec = 10 *1000;
+ }
+ } else if (ftdi->stuck_status > 0) {
+ if (ftdi_elan_stuck_waiting(ftdi) == 0) {
+ ftdi->stuck_status = 0;
+ ftdi->synchronized = 0;
+ } else if ((ftdi->stuck_status++ % 60) == 1) {
+ dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
+ "- please remove\n");
+ } else
+ dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
+ "- checked %d times\n", ftdi->stuck_status);
+ work_delay_in_msec = 100;
+ } else if (ftdi->enumerated == 0) {
+ if (ftdi_elan_enumeratePCI(ftdi) == 0) {
+ ftdi->enumerated = 1;
+ work_delay_in_msec = 250;
+ } else
+ work_delay_in_msec = 1000;
+ } else if (ftdi->initialized == 0) {
+ if (ftdi_elan_setupOHCI(ftdi) == 0) {
+ ftdi->initialized = 1;
+ work_delay_in_msec = 500;
+ } else {
+ dev_err(&ftdi->udev->dev, "initialized failed - trying "
+ "again in 10 seconds\n");
+ work_delay_in_msec = 10 *1000;
+ }
+ } else if (ftdi->registered == 0) {
+ work_delay_in_msec = 10;
+ if (ftdi_elan_hcd_init(ftdi) == 0) {
+ ftdi->registered = 1;
+ } else
+ dev_err(&ftdi->udev->dev, "register failed\n");
+ work_delay_in_msec = 250;
+ } else {
+ if (ftdi_elan_checkingPCI(ftdi) == 0) {
+ work_delay_in_msec = 250;
+ } else if (ftdi->controlreg & 0x00400000) {
+ if (ftdi->gone_away > 0) {
+ dev_err(&ftdi->udev->dev, "PCI device eject con"
+ "firmed platform_dev.dev.parent=%p plat"
+ "form_dev.dev=%p\n",
+ ftdi->platform_dev.dev.parent,
+ &ftdi->platform_dev.dev);
+ platform_device_unregister(&ftdi->platform_dev);
+ ftdi->platform_dev.dev.parent = NULL;
+ ftdi->registered = 0;
+ ftdi->enumerated = 0;
+ ftdi->card_ejected = 0;
+ ftdi->initialized = 0;
+ ftdi->gone_away = 0;
+ } else
+ ftdi_elan_flush_targets(ftdi);
+ work_delay_in_msec = 250;
+ } else {
+ dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"
+ );
+ ftdi_elan_cancel_targets(ftdi);
+ work_delay_in_msec = 500;
+ ftdi->enumerated = 0;
+ ftdi->initialized = 0;
+ }
+ }
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else {
+ ftdi_status_requeue_work(ftdi,
+ msecs_to_jiffies(work_delay_in_msec));
+ return;
+ }
+}
+
+
+/*
+* file_operations for the jtag interface
+*
+* the usage count for the device is incremented on open()
+* and decremented on release()
+*/
+static int ftdi_elan_open(struct inode *inode, struct file *file)
+{
+ int subminor = iminor(inode);
+ struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver,
+ subminor);
+ if (!interface) {
+ printk(KERN_ERR "can't find device for minor %d\n", subminor);
+ return -ENODEV;
+ } else {
+ struct usb_ftdi *ftdi = usb_get_intfdata(interface);
+ if (!ftdi) {
+ return -ENODEV;
+ } else {
+ if (down_interruptible(&ftdi->sw_lock)) {
+ return -EINTR;
+ } else {
+ ftdi_elan_get_kref(ftdi);
+ file->private_data = ftdi;
+ return 0;
+ }
+ }
+ }
+}
+
+static int ftdi_elan_release(struct inode *inode, struct file *file)
+{
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
+ if (ftdi == NULL)
+ return -ENODEV;
+ up(&ftdi->sw_lock); /* decrement the count on our device */
+ ftdi_elan_put_kref(ftdi);
+ return 0;
+}
+
+
+#define FTDI_ELAN_IOC_MAGIC 0xA1
+#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132)
+static int ftdi_elan_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case FTDI_ELAN_IOCDEBUG:{
+ char line[132];
+ int size = strncpy_from_user(line,
+ (const char __user *)arg, sizeof(line));
+ if (size < 0) {
+ return -EINVAL;
+ } else {
+ printk(KERN_ERR "TODO: ioctl %s\n", line);
+ return 0;
+ }
+ }
+ default:
+ return -EFAULT;
+ }
+}
+
+
+/*
+*
+* blocking bulk reads are used to get data from the device
+*
+*/
+static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char data[30 *3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int bytes_read = 0;
+ int retry_on_empty = 10;
+ int retry_on_timeout = 5;
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
+ if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ }
+ data[0] = 0;
+ have:if (ftdi->bulk_in_left > 0) {
+ if (count-- > 0) {
+ char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer;
+ ftdi->bulk_in_left -= 1;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X", 0x000000FF & *p);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ if (copy_to_user(buffer++, p, 1)) {
+ return -EFAULT;
+ } else {
+ bytes_read += 1;
+ goto have;
+ }
+ } else
+ return bytes_read;
+ }
+ more:if (count > 0) {
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(50));
+ if (packet_bytes > 2) {
+ ftdi->bulk_in_left = packet_bytes - 2;
+ ftdi->bulk_in_last = 1;
+ goto have;
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto more;
+ } else if (bytes_read > 0) {
+ return bytes_read;
+ } else
+ return retval;
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return bytes_read;
+ } else
+ return retval;
+ } else
+ return bytes_read;
+}
+
+static void ftdi_elan_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
+ if (urb->status && !(urb->status == -ENOENT || urb->status ==
+ -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
+ "d\n", urb, urb->status);
+ }
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+}
+
+static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi,
+ char *buf, int command_size, int total_size)
+{
+ int ed_commands = 0;
+ int b = 0;
+ int I = command_size;
+ int i = ftdi->command_head;
+ while (I-- > 0) {
+ struct u132_command *command = &ftdi->command[COMMAND_MASK &
+ i++];
+ int F = command->follows;
+ u8 *f = command->buffer;
+ if (command->header & 0x80) {
+ ed_commands |= 1 << (0x3 & (command->header >> 5));
+ }
+ buf[b++] = command->header;
+ buf[b++] = (command->length >> 0) & 0x00FF;
+ buf[b++] = (command->length >> 8) & 0x00FF;
+ buf[b++] = command->address;
+ buf[b++] = command->width;
+ while (F-- > 0) {
+ buf[b++] = *f++;
+ }
+ }
+ return ed_commands;
+}
+
+static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)
+{
+ int total_size = 0;
+ int I = command_size;
+ int i = ftdi->command_head;
+ while (I-- > 0) {
+ struct u132_command *command = &ftdi->command[COMMAND_MASK &
+ i++];
+ total_size += 5 + command->follows;
+ } return total_size;
+}
+
+static int ftdi_elan_command_engine(struct usb_ftdi *ftdi)
+{
+ int retval;
+ char *buf;
+ int ed_commands;
+ int total_size;
+ struct urb *urb;
+ int command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size == 0)
+ return 0;
+ total_size = ftdi_elan_total_command_size(ftdi, command_size);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm"
+ "ands totaling %d bytes to the Uxxx\n", command_size,
+ total_size);
+ return -ENOMEM;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c"
+ "ommands totaling %d bytes to the Uxxx\n", command_size,
+ total_size);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf,
+ command_size, total_size);
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, total_size,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ if (ed_commands) {
+ char diag[40 *3 + 4];
+ char *d = diag;
+ int m = total_size;
+ u8 *c = buf;
+ int s = (sizeof(diag) - 1) / 3;
+ diag[0] = 0;
+ while (s-- > 0 && m-- > 0) {
+ if (s > 0 || m == 0) {
+ d += sprintf(d, " %02X", *c++);
+ } else
+ d += sprintf(d, " ..");
+ }
+ }
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write "
+ "%d commands totaling %d bytes to the Uxxx\n", retval,
+ urb, command_size, total_size);
+ usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ return retval;
+ }
+ usb_free_urb(urb); /* release our reference to this urb,
+ the USB core will eventually free it entirely */
+ ftdi->command_head += command_size;
+ ftdi_elan_kick_respond_queue(ftdi);
+ return 0;
+}
+
+static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
+ struct u132_target *target, u8 *buffer, int length)
+{
+ struct urb *urb = target->urb;
+ int halted = target->halted;
+ int skipped = target->skipped;
+ int actual = target->actual;
+ int non_null = target->non_null;
+ int toggle_bits = target->toggle_bits;
+ int error_count = target->error_count;
+ int condition_code = target->condition_code;
+ int repeat_number = target->repeat_number;
+ void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int,
+ int, int, int, int) = target->callback;
+ target->active -= 1;
+ target->callback = NULL;
+ (*callback) (target->endp, urb, buffer, length, toggle_bits,
+ error_count, condition_code, repeat_number, halted, skipped,
+ actual, non_null);
+}
+
+static char *have_ed_set_response(struct usb_ftdi *ftdi,
+ struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
+ char *b)
+{
+ int payload = (ed_length >> 0) & 0x07FF;
+ down(&ftdi->u132_lock);
+ target->actual = 0;
+ target->non_null = (ed_length >> 15) & 0x0001;
+ target->repeat_number = (ed_length >> 11) & 0x000F;
+ if (ed_type == 0x02) {
+ if (payload == 0 || target->abandoning > 0) {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ } else {
+ ftdi->expected = 4 + payload;
+ ftdi->ed_found = 1;
+ up(&ftdi->u132_lock);
+ return b;
+ }
+ } else if (ed_type == 0x03) {
+ if (payload == 0 || target->abandoning > 0) {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ } else {
+ ftdi->expected = 4 + payload;
+ ftdi->ed_found = 1;
+ up(&ftdi->u132_lock);
+ return b;
+ }
+ } else if (ed_type == 0x01) {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ } else {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ }
+}
+
+static char *have_ed_get_response(struct usb_ftdi *ftdi,
+ struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
+ char *b)
+{
+ down(&ftdi->u132_lock);
+ target->condition_code = TD_DEVNOTRESP;
+ target->actual = (ed_length >> 0) & 0x01FF;
+ target->non_null = (ed_length >> 15) & 0x0001;
+ target->repeat_number = (ed_length >> 11) & 0x000F;
+ up(&ftdi->u132_lock);
+ if (target->active)
+ ftdi_elan_do_callback(ftdi, target, NULL, 0);
+ target->abandoning = 0;
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+}
+
+
+/*
+* The engine tries to empty the FTDI fifo
+*
+* all responses found in the fifo data are dispatched thus
+* the response buffer can only ever hold a maximum sized
+* response from the Uxxx.
+*
+*/
+static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)
+{
+ u8 *b = ftdi->response + ftdi->recieved;
+ int bytes_read = 0;
+ int retry_on_empty = 1;
+ int retry_on_timeout = 3;
+ int empty_packets = 0;
+ read:{
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(500));
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = packet_bytes;
+ u8 *c = ftdi->bulk_in_buffer;
+ int s = (sizeof(diag) - 1) / 3;
+ diag[0] = 0;
+ while (s-- > 0 && m-- > 0) {
+ if (s > 0 || m == 0) {
+ d += sprintf(d, " %02X", *c++);
+ } else
+ d += sprintf(d, " ..");
+ }
+ if (packet_bytes > 2) {
+ ftdi->bulk_in_left = packet_bytes - 2;
+ ftdi->bulk_in_last = 1;
+ goto have;
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
+ "t_bytes = %d with total %d bytes%s\n",
+ packet_bytes, bytes_read, diag);
+ goto more;
+ } else if (bytes_read > 0) {
+ dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n",
+ bytes_read, diag);
+ return -ENOMEM;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
+ "t_bytes = %d with total %d bytes%s\n",
+ packet_bytes, bytes_read, diag);
+ return -ENOMEM;
+ }
+ } else if (retval == -EILSEQ) {
+ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
+ " = %d with total %d bytes%s\n", retval,
+ packet_bytes, bytes_read, diag);
+ return retval;
+ } else if (retval) {
+ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
+ " = %d with total %d bytes%s\n", retval,
+ packet_bytes, bytes_read, diag);
+ return retval;
+ } else if (packet_bytes == 2) {
+ unsigned char s0 = ftdi->bulk_in_buffer[0];
+ unsigned char s1 = ftdi->bulk_in_buffer[1];
+ empty_packets += 1;
+ if (s0 == 0x31 && s1 == 0x60) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ } else if (s0 == 0x31 && s1 == 0x00) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ } else {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ }
+ } else if (packet_bytes == 1) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ } else {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ }
+ }
+ more:{
+ goto read;
+ }
+ have:if (ftdi->bulk_in_left > 0) {
+ u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last];
+ bytes_read += 1;
+ ftdi->bulk_in_left -= 1;
+ if (ftdi->recieved == 0 && c == 0xFF) {
+ goto have;
+ } else
+ *b++ = c;
+ if (++ftdi->recieved < ftdi->expected) {
+ goto have;
+ } else if (ftdi->ed_found) {
+ int ed_number = (ftdi->response[0] >> 5) & 0x03;
+ u16 ed_length = (ftdi->response[2] << 8) |
+ ftdi->response[1];
+ struct u132_target *target = &ftdi->target[ed_number];
+ int payload = (ed_length >> 0) & 0x07FF;
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = payload;
+ u8 *c = 4 + ftdi->response;
+ int s = (sizeof(diag) - 1) / 3;
+ diag[0] = 0;
+ while (s-- > 0 && m-- > 0) {
+ if (s > 0 || m == 0) {
+ d += sprintf(d, " %02X", *c++);
+ } else
+ d += sprintf(d, " ..");
+ }
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ b = ftdi->response;
+ goto have;
+ } else if (ftdi->expected == 8) {
+ u8 buscmd;
+ int respond_head = ftdi->respond_head++;
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & respond_head];
+ u32 data = ftdi->response[7];
+ data <<= 8;
+ data |= ftdi->response[6];
+ data <<= 8;
+ data |= ftdi->response[5];
+ data <<= 8;
+ data |= ftdi->response[4];
+ *respond->value = data;
+ *respond->result = 0;
+ complete(&respond->wait_completion);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ b = ftdi->response;
+ buscmd = (ftdi->response[0] >> 0) & 0x0F;
+ if (buscmd == 0x00) {
+ } else if (buscmd == 0x02) {
+ } else if (buscmd == 0x06) {
+ } else if (buscmd == 0x0A) {
+ } else
+ dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va"
+ "lue = %08X\n", buscmd, data);
+ goto have;
+ } else {
+ if ((ftdi->response[0] & 0x80) == 0x00) {
+ ftdi->expected = 8;
+ goto have;
+ } else {
+ int ed_number = (ftdi->response[0] >> 5) & 0x03;
+ int ed_type = (ftdi->response[0] >> 0) & 0x03;
+ u16 ed_length = (ftdi->response[2] << 8) |
+ ftdi->response[1];
+ struct u132_target *target = &ftdi->target[
+ ed_number];
+ target->halted = (ftdi->response[0] >> 3) &
+ 0x01;
+ target->skipped = (ftdi->response[0] >> 2) &
+ 0x01;
+ target->toggle_bits = (ftdi->response[3] >> 6)
+ & 0x03;
+ target->error_count = (ftdi->response[3] >> 4)
+ & 0x03;
+ target->condition_code = (ftdi->response[
+ 3] >> 0) & 0x0F;
+ if ((ftdi->response[0] & 0x10) == 0x00) {
+ b = have_ed_set_response(ftdi, target,
+ ed_length, ed_number, ed_type,
+ b);
+ goto have;
+ } else {
+ b = have_ed_get_response(ftdi, target,
+ ed_length, ed_number, ed_type,
+ b);
+ goto have;
+ }
+ }
+ }
+ } else
+ goto more;
+}
+
+
+/*
+* create a urb, and a buffer for it, and copy the data to the urb
+*
+*/
+static ssize_t ftdi_elan_write(struct file *file,
+ const char __user *user_buffer, size_t count,
+ loff_t *ppos)
+{
+ int retval = 0;
+ struct urb *urb;
+ char *buf;
+ char data[30 *3 + 4];
+ char *d = data;
+ const char __user *s = user_buffer;
+ int m = (sizeof(data) - 1) / 3;
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
+ if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ }
+ if (count == 0) {
+ goto exit;
+ }
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ retval = -ENOMEM;
+ goto error_1;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ retval = -ENOMEM;
+ goto error_2;
+ }
+ if (copy_from_user(buf, user_buffer, count)) {
+ retval = -EFAULT;
+ goto error_3;
+ }
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, count,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed submitting write urb, error %"
+ "d\n", retval);
+ goto error_4;
+ }
+ usb_free_urb(urb);
+ exit:;
+ if (count > m) {
+ int I = m - 1;
+ while (I-- > 0) {
+ d += sprintf(d, " %02X", 0x000000FF & *s++);
+ }
+ d += sprintf(d, " ..");
+ } else {
+ int I = count;
+ while (I-- > 0) {
+ d += sprintf(d, " %02X", 0x000000FF & *s++);
+ }
+ }
+ return count;
+ error_4: error_3:usb_buffer_free(ftdi->udev, count, buf,
+ urb->transfer_dma);
+ error_2:usb_free_urb(urb);
+ error_1:return retval;
+}
+
+static struct file_operations ftdi_elan_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = ftdi_elan_ioctl,
+ .read = ftdi_elan_read,
+ .write = ftdi_elan_write,
+ .open = ftdi_elan_open,
+ .release = ftdi_elan_release,
+};
+
+/*
+* usb class driver info in order to get a minor number from the usb core,
+* and to have the device registered with the driver core
+*/
+static struct usb_class_driver ftdi_elan_jtag_class = {
+ .name = "ftdi-%d-jtag",
+ .fops = &ftdi_elan_fops,
+ .minor_base = USB_FTDI_ELAN_MINOR_BASE,
+};
+
+/*
+* the following definitions are for the
+* ELAN FPGA state machgine processor that
+* lies on the other side of the FTDI chip
+*/
+#define cPCIu132rd 0x0
+#define cPCIu132wr 0x1
+#define cPCIiord 0x2
+#define cPCIiowr 0x3
+#define cPCImemrd 0x6
+#define cPCImemwr 0x7
+#define cPCIcfgrd 0xA
+#define cPCIcfgwr 0xB
+#define cPCInull 0xF
+#define cU132cmd_status 0x0
+#define cU132flash 0x1
+#define cPIDsetup 0x0
+#define cPIDout 0x1
+#define cPIDin 0x2
+#define cPIDinonce 0x3
+#define cCCnoerror 0x0
+#define cCCcrc 0x1
+#define cCCbitstuff 0x2
+#define cCCtoggle 0x3
+#define cCCstall 0x4
+#define cCCnoresp 0x5
+#define cCCbadpid1 0x6
+#define cCCbadpid2 0x7
+#define cCCdataoverrun 0x8
+#define cCCdataunderrun 0x9
+#define cCCbuffoverrun 0xC
+#define cCCbuffunderrun 0xD
+#define cCCnotaccessed 0xF
+static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
+{
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x00 | cPCIu132wr;
+ command->length = 0x04;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 4;
+ command->value = data;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
+ u8 width, u32 data)
+{
+ u8 addressofs = config_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x00 | (cPCIcfgwr & 0x0F);
+ command->length = 0x04;
+ command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 4;
+ command->value = data;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
+ u8 width, u32 data)
+{
+ u8 addressofs = mem_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x00 | (cPCImemwr & 0x0F);
+ command->length = 0x04;
+ command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 4;
+ command->value = data;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset,
+ u8 width, u32 data)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem);
+static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
+{
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ int respond_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ respond_size = ftdi->respond_next - ftdi->respond_head;
+ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
+ {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & ftdi->respond_next];
+ int result = -ENODEV;
+ respond->result = &result;
+ respond->header = command->header = 0x00 | cPCIu132rd;
+ command->length = 0x04;
+ respond->address = command->address = cU132cmd_status;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ respond->value = data;
+ init_completion(&respond->wait_completion);
+ ftdi->command_next += 1;
+ ftdi->respond_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ wait_for_completion(&respond->wait_completion);
+ return result;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_read_reg(ftdi, data);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_reg);
+static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
+ u8 width, u32 *data)
+{
+ u8 addressofs = config_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ int respond_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ respond_size = ftdi->respond_next - ftdi->respond_head;
+ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
+ {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & ftdi->respond_next];
+ int result = -ENODEV;
+ respond->result = &result;
+ respond->header = command->header = 0x00 | (cPCIcfgrd &
+ 0x0F);
+ command->length = 0x04;
+ respond->address = command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ respond->value = data;
+ init_completion(&respond->wait_completion);
+ ftdi->command_next += 1;
+ ftdi->respond_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ wait_for_completion(&respond->wait_completion);
+ return result;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
+ u8 width, u32 *data)
+{
+ u8 addressofs = mem_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ int respond_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ respond_size = ftdi->respond_next - ftdi->respond_head;
+ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
+ {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & ftdi->respond_next];
+ int result = -ENODEV;
+ respond->result = &result;
+ respond->header = command->header = 0x00 | (cPCImemrd &
+ 0x0F);
+ command->length = 0x04;
+ respond->address = command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ respond->value = data;
+ init_completion(&respond->wait_completion);
+ ftdi->command_next += 1;
+ ftdi->respond_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ wait_for_completion(&respond->wait_completion);
+ return result;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset,
+ u8 width, u32 *data)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else
+ return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem);
+static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x80 | (ed << 5);
+ command->length = 0x8007;
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 8;
+ command->value = 0;
+ command->buffer = urb->setup_packet;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup);
+static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ int remaining_length = urb->transfer_buffer_length -
+ urb->actual_length;
+ command->header = 0x82 | (ed << 5);
+ if (remaining_length == 0) {
+ command->length = 0x0000;
+ } else if (remaining_length > 1024) {
+ command->length = 0x8000 | 1023;
+ } else
+ command->length = 0x8000 | (remaining_length -
+ 1);
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input);
+static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x81 | (ed << 5);
+ command->length = 0x0000;
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty);
+static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ u8 *b;
+ u16 urb_size;
+ int i = 0;
+ char data[30 *3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int l = 0;
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x81 | (ed << 5);
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = min(1024,
+ urb->transfer_buffer_length -
+ urb->actual_length);
+ command->value = 0;
+ command->buffer = urb->transfer_buffer +
+ urb->actual_length;
+ command->length = 0x8000 | (command->follows - 1);
+ b = command->buffer;
+ urb_size = command->follows;
+ data[0] = 0;
+ while (urb_size-- > 0) {
+ if (i > m) {
+ } else if (i++ < m) {
+ int w = sprintf(d, " %02X", *b++);
+ d += w;
+ l += w;
+ } else
+ d += sprintf(d, " ..");
+ }
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output);
+static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ int remaining_length = urb->transfer_buffer_length -
+ urb->actual_length;
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x83 | (ed << 5);
+ if (remaining_length == 0) {
+ command->length = 0x0000;
+ } else if (remaining_length > 1024) {
+ command->length = 0x8000 | 1023;
+ } else
+ command->length = 0x8000 | (remaining_length -
+ 1);
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single);
+static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp)
+{
+ u8 ed = ed_number - 1;
+ if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ struct u132_target *target = &ftdi->target[ed];
+ down(&ftdi->u132_lock);
+ if (target->abandoning > 0) {
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ target->abandoning = 1;
+ wait_1:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command =
+ &ftdi->command[COMMAND_MASK &
+ ftdi->command_next];
+ command->header = 0x80 | (ed << 5) |
+ 0x4;
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait_1;
+ }
+ }
+ up(&ftdi->u132_lock);
+ return 0;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
+ void *endp)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_flush(ftdi, ed_number, endp);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush);
+static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)
+{
+ int retry_on_empty = 10;
+ int retry_on_timeout = 5;
+ int retry_on_status = 20;
+ more:{
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(100));
+ if (packet_bytes > 2) {
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = (sizeof(diag) - 1) / 3;
+ char *b = ftdi->bulk_in_buffer;
+ int bytes_read = 0;
+ diag[0] = 0;
+ while (packet_bytes-- > 0) {
+ char c = *b++;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X",
+ 0x000000FF & c);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ bytes_read += 1;
+ continue;
+ }
+ goto more;
+ } else if (packet_bytes > 1) {
+ char s1 = ftdi->bulk_in_buffer[0];
+ char s2 = ftdi->bulk_in_buffer[1];
+ if (s1 == 0x31 && s2 == 0x60) {
+ return 0;
+ } else if (retry_on_status-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
+ "imit reached\n");
+ return -EFAULT;
+ }
+ } else if (packet_bytes > 0) {
+ char b1 = ftdi->bulk_in_buffer[0];
+ dev_err(&ftdi->udev->dev, "only one byte flushed from F"
+ "TDI = %02X\n", b1);
+ if (retry_on_status-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
+ "imit reached\n");
+ return -EFAULT;
+ }
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
+ "t reached\n");
+ return -ENOMEM;
+ }
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "empty packet retry l"
+ "imit reached\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(&ftdi->udev->dev, "error = %d\n", retval);
+ return retval;
+ }
+ }
+ return -1;
+}
+
+
+/*
+* send the long flush sequence
+*
+*/
+static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi)
+{
+ int retval;
+ struct urb *urb;
+ char *buf;
+ int I = 257;
+ int i = 0;
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ"
+ "ence\n");
+ return -ENOMEM;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
+ if (!buf) {
+ dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq"
+ "uence\n");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ while (I-- > 0)
+ buf[i++] = 0x55;
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, i,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
+ "flush sequence\n");
+ usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ usb_free_urb(urb);
+ return 0;
+}
+
+
+/*
+* send the reset sequence
+*
+*/
+static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi)
+{
+ int retval;
+ struct urb *urb;
+ char *buf;
+ int I = 4;
+ int i = 0;
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&ftdi->udev->dev, "could not get a urb for the reset se"
+ "quence\n");
+ return -ENOMEM;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
+ if (!buf) {
+ dev_err(&ftdi->udev->dev, "could not get a buffer for the reset"
+ " sequence\n");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ buf[i++] = 0x55;
+ buf[i++] = 0xAA;
+ buf[i++] = 0x5A;
+ buf[i++] = 0xA5;
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, i,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
+ "reset sequence\n");
+ usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ usb_free_urb(urb);
+ return 0;
+}
+
+static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
+{
+ int retval;
+ int long_stop = 10;
+ int retry_on_timeout = 5;
+ int retry_on_empty = 10;
+ int err_count = 0;
+ retval = ftdi_elan_flush_input_fifo(ftdi);
+ if (retval)
+ return retval;
+ ftdi->bulk_in_left = 0;
+ ftdi->bulk_in_last = -1;
+ while (long_stop-- > 0) {
+ int read_stop;
+ int read_stuck;
+ retval = ftdi_elan_synchronize_flush(ftdi);
+ if (retval)
+ return retval;
+ retval = ftdi_elan_flush_input_fifo(ftdi);
+ if (retval)
+ return retval;
+ reset:retval = ftdi_elan_synchronize_reset(ftdi);
+ if (retval)
+ return retval;
+ read_stop = 100;
+ read_stuck = 10;
+ read:{
+ int packet_bytes = 0;
+ retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev,
+ ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(500));
+ if (packet_bytes > 2) {
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = (sizeof(diag) - 1) / 3;
+ char *b = ftdi->bulk_in_buffer;
+ int bytes_read = 0;
+ unsigned char c = 0;
+ diag[0] = 0;
+ while (packet_bytes-- > 0) {
+ c = *b++;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X", c);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ bytes_read += 1;
+ continue;
+ }
+ if (c == 0x7E) {
+ return 0;
+ } else {
+ if (c == 0x55) {
+ goto read;
+ } else if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retr"
+ "y limit reached\n");
+ continue;
+ }
+ }
+ } else if (packet_bytes > 1) {
+ unsigned char s1 = ftdi->bulk_in_buffer[0];
+ unsigned char s2 = ftdi->bulk_in_buffer[1];
+ if (s1 == 0x31 && s2 == 0x00) {
+ if (read_stuck-- > 0) {
+ goto read;
+ } else
+ goto reset;
+ } else if (s1 == 0x31 && s2 == 0x60) {
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retr"
+ "y limit reached\n");
+ continue;
+ }
+ } else {
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retr"
+ "y limit reached\n");
+ continue;
+ }
+ }
+ } else if (packet_bytes > 0) {
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retry limit "
+ "reached\n");
+ continue;
+ }
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT re"
+ "try limit reached\n");
+ continue;
+ }
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "empty packet"
+ " retry limit reached\n");
+ continue;
+ }
+ } else {
+ err_count += 1;
+ dev_err(&ftdi->udev->dev, "error = %d\n",
+ retval);
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retry limit "
+ "reached\n");
+ continue;
+ }
+ }
+ }
+ }
+ dev_err(&ftdi->udev->dev, "failed to synchronize\n");
+ return -EFAULT;
+}
+
+static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)
+{
+ int retry_on_empty = 10;
+ int retry_on_timeout = 5;
+ int retry_on_status = 50;
+ more:{
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(1000));
+ if (packet_bytes > 2) {
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = (sizeof(diag) - 1) / 3;
+ char *b = ftdi->bulk_in_buffer;
+ int bytes_read = 0;
+ diag[0] = 0;
+ while (packet_bytes-- > 0) {
+ char c = *b++;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X",
+ 0x000000FF & c);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ bytes_read += 1;
+ continue;
+ }
+ goto more;
+ } else if (packet_bytes > 1) {
+ char s1 = ftdi->bulk_in_buffer[0];
+ char s2 = ftdi->bulk_in_buffer[1];
+ if (s1 == 0x31 && s2 == 0x60) {
+ return 0;
+ } else if (retry_on_status-- > 0) {
+ msleep(5);
+ goto more;
+ } else
+ return -EFAULT;
+ } else if (packet_bytes > 0) {
+ char b1 = ftdi->bulk_in_buffer[0];
+ dev_err(&ftdi->udev->dev, "only one byte flushed from F"
+ "TDI = %02X\n", b1);
+ if (retry_on_status-- > 0) {
+ msleep(5);
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
+ "imit reached\n");
+ return -EFAULT;
+ }
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
+ "t reached\n");
+ return -ENOMEM;
+ }
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "empty packet retry l"
+ "imit reached\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(&ftdi->udev->dev, "error = %d\n", retval);
+ return -ENOMEM;
+ }
+ }
+ return -1;
+}
+
+static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
+{
+ int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ if (ftdi->controlreg & 0x00400000) {
+ if (ftdi->card_ejected) {
+ } else {
+ ftdi->card_ejected = 1;
+ dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = "
+ "%08X\n", ftdi->controlreg);
+ }
+ return -ENODEV;
+ } else {
+ u8 fn = ftdi->function - 1;
+ int activePCIfn = fn << 8;
+ u32 pcidata;
+ u32 pciVID;
+ u32 pciPID;
+ int reg = 0;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ pciVID = pcidata & 0xFFFF;
+ pciPID = (pcidata >> 16) & 0xFFFF;
+ if (pciVID == ftdi->platform_data.vendor && pciPID ==
+ ftdi->platform_data.device) {
+ return 0;
+ } else {
+ dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi"
+ "ce=%04X pciPID=%04X\n",
+ ftdi->platform_data.vendor, pciVID,
+ ftdi->platform_data.device, pciPID);
+ return -ENODEV;
+ }
+ }
+}
+
+static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
+{
+ u32 latence_timer;
+ u32 controlreg;
+ int UxxxStatus;
+ u32 pcidata;
+ int reg = 0;
+ int foundOHCI = 0;
+ u8 fn;
+ int activePCIfn = 0;
+ u32 pciVID = 0;
+ u32 pciPID = 0;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
+ if (UxxxStatus)
+ return UxxxStatus;
+ msleep(750);
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ msleep(250);
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ msleep(1000);
+ for (fn = 0; (fn < 4) && (!foundOHCI); fn++) {
+ activePCIfn = fn << 8;
+ ftdi->function = fn + 1;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ pciVID = pcidata & 0xFFFF;
+ pciPID = (pcidata >> 16) & 0xFFFF;
+ if ((pciVID == 0x1045) && (pciPID == 0xc861)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) {
+ }
+ }
+ if (foundOHCI == 0) {
+ return -ENXIO;
+ }
+ ftdi->platform_data.vendor = pciVID;
+ ftdi->platform_data.device = pciPID;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
+ if (UxxxStatus)
+ return UxxxStatus;
+ reg = 16;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
+ 0xFFFFFFFF);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
+ 0xF0000000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ reg = 12;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &latence_timer);
+ if (UxxxStatus)
+ return UxxxStatus;
+ latence_timer &= 0xFFFF00FF;
+ latence_timer |= 0x00001600;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
+ latence_timer);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ reg = 4;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
+ 0x06);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ return 0;
+}
+
+static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
+{
+ u32 pcidata;
+ int U132Status;
+ int reg;
+ int reset_repeat = 0;
+ do_reset:reg = 8;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01);
+ if (U132Status)
+ return U132Status;
+ reset_check:{
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ if (pcidata & 1) {
+ msleep(500);
+ if (reset_repeat++ > 100) {
+ reset_repeat = 0;
+ goto do_reset;
+ } else
+ goto reset_check;
+ }
+ }
+ goto dump_regs;
+ msleep(500);
+ reg = 0x28;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x40;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x34;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 4;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ msleep(250);
+ reg = 8;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x28;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 8;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x48;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x58;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x34;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ msleep(100);
+ reg = 0x50;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ if (!(pcidata & 1)) {
+ msleep(500);
+ goto power_check;
+ }
+ msleep(3000);
+ reg = 0x54;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x58;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ msleep(750);
+ reg = 0x54;
+ if (0) {
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
+ if (U132Status)
+ return U132Status;
+ }
+ if (0) {
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ }
+ reg = 0x54;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x58;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ dump_regs:for (reg = 0; reg <= 0x54; reg += 4) {
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ }
+ return 0;
+}
+
+
+/*
+* we use only the first bulk-in and bulk-out endpoints
+*/
+static int ftdi_elan_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ size_t buffer_size;
+ int i;
+ int retval = -ENOMEM;
+ struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+ if (ftdi == NULL) {
+ printk(KERN_ERR "Out of memory\n");
+ return -ENOMEM;
+ }
+ memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+ down(&ftdi_module_lock);
+ list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
+ ftdi->sequence_num = ++ftdi_instances;
+ up(&ftdi_module_lock);
+ ftdi_elan_init_kref(ftdi);
+ init_MUTEX(&ftdi->sw_lock);
+ ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
+ ftdi->interface = interface;
+ init_MUTEX(&ftdi->u132_lock);
+ ftdi->expected = 4;
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!ftdi->bulk_in_endpointAddr &&
+ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) && ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
+ {
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ ftdi->bulk_in_size = buffer_size;
+ ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!ftdi->bulk_in_buffer) {
+ dev_err(&ftdi->udev->dev, "Could not allocate b"
+ "ulk_in_buffer\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+ }
+ if (!ftdi->bulk_out_endpointAddr &&
+ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_OUT) && ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
+ {
+ ftdi->bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ }
+ }
+ if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) {
+ dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk"
+ "-out endpoints\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n",
+ iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr,
+ ftdi->bulk_out_endpointAddr);
+ usb_set_intfdata(interface, ftdi);
+ if (iface_desc->desc.bInterfaceNumber == 0 &&
+ ftdi->bulk_in_endpointAddr == 0x81 &&
+ ftdi->bulk_out_endpointAddr == 0x02) {
+ retval = usb_register_dev(interface, &ftdi_elan_jtag_class);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "Not able to get a minor for "
+ "this device.\n");
+ usb_set_intfdata(interface, NULL);
+ retval = -ENOMEM;
+ goto error;
+ } else {
+ ftdi->class = &ftdi_elan_jtag_class;
+ dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface "
+ "%d now attached to ftdi%d\n", ftdi,
+ iface_desc->desc.bInterfaceNumber,
+ interface->minor);
+ return 0;
+ }
+ } else if (iface_desc->desc.bInterfaceNumber == 1 &&
+ ftdi->bulk_in_endpointAddr == 0x83 &&
+ ftdi->bulk_out_endpointAddr == 0x04) {
+ ftdi->class = NULL;
+ dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a"
+ "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber);
+ INIT_WORK(&ftdi->status_work, ftdi_elan_status_work,
+ (void *)ftdi);
+ INIT_WORK(&ftdi->command_work, ftdi_elan_command_work,
+ (void *)ftdi);
+ INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work,
+ (void *)ftdi);
+ ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000));
+ return 0;
+ } else {
+ dev_err(&ftdi->udev->dev,
+ "Could not find ELAN's U132 device\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ error:if (ftdi) {
+ ftdi_elan_put_kref(ftdi);
+ }
+ return retval;
+}
+
+static void ftdi_elan_disconnect(struct usb_interface *interface)
+{
+ struct usb_ftdi *ftdi = usb_get_intfdata(interface);
+ ftdi->disconnected += 1;
+ if (ftdi->class) {
+ int minor = interface->minor;
+ struct usb_class_driver *class = ftdi->class;
+ usb_set_intfdata(interface, NULL);
+ usb_deregister_dev(interface, class);
+ dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min"
+ "or %d now disconnected\n", minor);
+ } else {
+ ftdi_status_cancel_work(ftdi);
+ ftdi_command_cancel_work(ftdi);
+ ftdi_response_cancel_work(ftdi);
+ ftdi_elan_abandon_completions(ftdi);
+ ftdi_elan_abandon_targets(ftdi);
+ if (ftdi->registered) {
+ platform_device_unregister(&ftdi->platform_dev);
+ ftdi->synchronized = 0;
+ ftdi->enumerated = 0;
+ ftdi->registered = 0;
+ }
+ flush_workqueue(status_queue);
+ flush_workqueue(command_queue);
+ flush_workqueue(respond_queue);
+ ftdi->disconnected += 1;
+ usb_set_intfdata(interface, NULL);
+ dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter"
+ "face now disconnected\n");
+ }
+ ftdi_elan_put_kref(ftdi);
+}
+
+static struct usb_driver ftdi_elan_driver = {
+ .name = "ftdi-elan",
+ .probe = ftdi_elan_probe,
+ .disconnect = ftdi_elan_disconnect,
+ .id_table = ftdi_elan_table,
+};
+static int __init ftdi_elan_init(void)
+{
+ int result;
+ printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
+ __TIME__, __DATE__);
+ init_MUTEX(&ftdi_module_lock);
+ INIT_LIST_HEAD(&ftdi_static_list);
+ status_queue = create_singlethread_workqueue("ftdi-status-control");
+ command_queue = create_singlethread_workqueue("ftdi-command-engine");
+ respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
+ result = usb_register(&ftdi_elan_driver);
+ if (result)
+ printk(KERN_ERR "usb_register failed. Error number %d\n",
+ result);
+ return result;
+}
+
+static void __exit ftdi_elan_exit(void)
+{
+ struct usb_ftdi *ftdi;
+ struct usb_ftdi *temp;
+ usb_deregister(&ftdi_elan_driver);
+ printk(KERN_INFO "ftdi_u132 driver deregistered\n");
+ list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) {
+ ftdi_status_cancel_work(ftdi);
+ ftdi_command_cancel_work(ftdi);
+ ftdi_response_cancel_work(ftdi);
+ } flush_workqueue(status_queue);
+ destroy_workqueue(status_queue);
+ status_queue = NULL;
+ flush_workqueue(command_queue);
+ destroy_workqueue(command_queue);
+ command_queue = NULL;
+ flush_workqueue(respond_queue);
+ destroy_workqueue(respond_queue);
+ respond_queue = NULL;
+}
+
+
+module_init(ftdi_elan_init);
+module_exit(ftdi_elan_exit);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index d0b16725669..8e6e195a22b 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -16,7 +16,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/delay.h>
@@ -99,7 +98,7 @@ static int idmouse_probe(struct usb_interface *interface,
static void idmouse_disconnect(struct usb_interface *interface);
/* file operation pointers */
-static struct file_operations idmouse_fops = {
+static const struct file_operations idmouse_fops = {
.owner = THIS_MODULE,
.read = idmouse_read,
.open = idmouse_open,
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 966acb474f6..10b640339d8 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -27,7 +27,6 @@
* V0.13 (mh) Added support for LD X-Ray and Machine Test System
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -590,7 +589,7 @@ exit:
}
/* file operations needed when we register this driver */
-static struct file_operations ld_usb_fops = {
+static const struct file_operations ld_usb_fops = {
.owner = THIS_MODULE,
.read = ld_usb_read,
.write = ld_usb_write,
@@ -658,15 +657,11 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ if (usb_endpoint_is_int_in(endpoint))
dev->interrupt_in_endpoint = endpoint;
- }
- if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ if (usb_endpoint_is_int_out(endpoint))
dev->interrupt_out_endpoint = endpoint;
- }
}
if (dev->interrupt_in_endpoint == NULL) {
dev_err(&intf->dev, "Interrupt in endpoint not found\n");
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 779bcf0373a..77c36e63c7b 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -75,7 +75,6 @@
* - move reset into open to clean out spurious data
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -260,7 +259,7 @@ static void tower_disconnect (struct usb_interface *interface);
static DEFINE_MUTEX (disconnect_mutex);
/* file operations needed when we register this driver */
-static struct file_operations tower_fops = {
+static const struct file_operations tower_fops = {
.owner = THIS_MODULE,
.read = tower_read,
.write = tower_write,
diff --git a/drivers/usb/misc/phidget.c b/drivers/usb/misc/phidget.c
new file mode 100644
index 00000000000..735ed33f4f7
--- /dev/null
+++ b/drivers/usb/misc/phidget.c
@@ -0,0 +1,43 @@
+/*
+ * USB Phidgets class
+ *
+ * Copyright (C) 2006 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+struct class *phidget_class;
+
+static int __init init_phidget(void)
+{
+ phidget_class = class_create(THIS_MODULE, "phidget");
+
+ if (IS_ERR(phidget_class))
+ return PTR_ERR(phidget_class);
+
+ return 0;
+}
+
+static void __exit cleanup_phidget(void)
+{
+ class_destroy(phidget_class);
+}
+
+EXPORT_SYMBOL_GPL(phidget_class);
+
+module_init(init_phidget);
+module_exit(cleanup_phidget);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_DESCRIPTION("Container module for phidget class");
+
diff --git a/drivers/usb/misc/phidget.h b/drivers/usb/misc/phidget.h
new file mode 100644
index 00000000000..c4011907d43
--- /dev/null
+++ b/drivers/usb/misc/phidget.h
@@ -0,0 +1,12 @@
+/*
+ * USB Phidgets class
+ *
+ * Copyright (C) 2006 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+extern struct class *phidget_class;
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index 13aeea2026c..78e419904ab 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -13,7 +13,6 @@
* This is a driver for the USB PhidgetInterfaceKit.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -21,6 +20,8 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include "phidget.h"
+
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
#define DRIVER_DESC "USB PhidgetInterfaceKit Driver"
@@ -43,26 +44,35 @@ struct driver_interfacekit {
int inputs;
int outputs;
int has_lcd;
+ int amnesiac;
};
-#define ifkit(_sensors, _inputs, _outputs, _lcd) \
-static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \
+
+#define ifkit(_sensors, _inputs, _outputs, _lcd, _amnesiac) \
+{ \
.sensors = _sensors, \
.inputs = _inputs, \
.outputs = _outputs, \
.has_lcd = _lcd, \
+ .amnesiac = _amnesiac \
};
-ifkit(0, 0, 4, 0);
-ifkit(8, 8, 8, 0);
-ifkit(0, 4, 7, 1);
-ifkit(8, 8, 4, 0);
-ifkit(0, 8, 8, 1);
-ifkit(0, 16, 16, 0);
+
+static const struct driver_interfacekit ph_004 = ifkit(0, 0, 4, 0, 0);
+static const struct driver_interfacekit ph_888n = ifkit(8, 8, 8, 0, 1);
+static const struct driver_interfacekit ph_888o = ifkit(8, 8, 8, 0, 0);
+static const struct driver_interfacekit ph_047 = ifkit(0, 4, 7, 1, 0);
+static const struct driver_interfacekit ph_884 = ifkit(8, 8, 4, 0, 0);
+static const struct driver_interfacekit ph_088 = ifkit(0, 8, 8, 1, 0);
+static const struct driver_interfacekit ph_01616 = ifkit(0, 16, 16, 0, 0);
+
+static unsigned long device_no;
struct interfacekit {
struct usb_device *udev;
struct usb_interface *intf;
struct driver_interfacekit *ifkit;
+ struct device *dev;
unsigned long outputs;
+ int dev_no;
u8 inputs[MAX_INTERFACES];
u16 sensors[MAX_INTERFACES];
u8 lcd_files_on;
@@ -72,6 +82,7 @@ struct interfacekit {
dma_addr_t data_dma;
struct work_struct do_notify;
+ struct work_struct do_resubmit;
unsigned long input_events;
unsigned long sensor_events;
};
@@ -79,8 +90,10 @@ struct interfacekit {
static struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004),
.driver_info = (kernel_ulong_t)&ph_004},
- {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888),
- .driver_info = (kernel_ulong_t)&ph_888},
+ {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0, 0x814),
+ .driver_info = (kernel_ulong_t)&ph_888o},
+ {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0x0815, 0xffff),
+ .driver_info = (kernel_ulong_t)&ph_888n},
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047),
.driver_info = (kernel_ulong_t)&ph_047},
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
@@ -93,16 +106,11 @@ static struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static int change_outputs(struct interfacekit *kit, int output_num, int enable)
+static int set_outputs(struct interfacekit *kit)
{
u8 *buffer;
int retval;
- if (enable)
- set_bit(output_num, &kit->outputs);
- else
- clear_bit(output_num, &kit->outputs);
-
buffer = kzalloc(4, GFP_KERNEL);
if (!buffer) {
dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
@@ -122,6 +130,9 @@ static int change_outputs(struct interfacekit *kit, int output_num, int enable)
retval);
kfree(buffer);
+ if (kit->ifkit->amnesiac)
+ schedule_delayed_work(&kit->do_resubmit, HZ / 2);
+
return retval < 0 ? retval : 0;
}
@@ -181,21 +192,24 @@ exit:
}
#define set_lcd_line(number) \
-static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
- change_string(kit, buf, number - 1); \
- return count; \
-} \
-static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number);
+static ssize_t lcd_line_##number(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
+ change_string(kit, buf, number - 1); \
+ return count; \
+}
+
+#define lcd_line_attr(number) \
+ __ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number)
+
set_lcd_line(1);
set_lcd_line(2);
static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct interfacekit *kit = usb_get_intfdata(intf);
+ struct interfacekit *kit = dev_get_drvdata(dev);
int enabled;
unsigned char *buffer;
int retval = -ENOMEM;
@@ -227,23 +241,30 @@ exit:
kfree(buffer);
return retval;
}
-static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight);
+
+static struct device_attribute dev_lcd_line_attrs[] = {
+ lcd_line_attr(1),
+ lcd_line_attr(2),
+ __ATTR(backlight, S_IWUGO, NULL, set_backlight)
+};
static void remove_lcd_files(struct interfacekit *kit)
{
+ int i;
+
if (kit->lcd_files_on) {
dev_dbg(&kit->udev->dev, "Removing lcd files\n");
- device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1);
- device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2);
- device_remove_file(&kit->intf->dev, &dev_attr_backlight);
+
+ for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++)
+ device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
}
}
static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct interfacekit *kit = usb_get_intfdata(intf);
+ struct interfacekit *kit = dev_get_drvdata(dev);
int enable;
+ int i, rc;
if (kit->ifkit->has_lcd == 0)
return -ENODEV;
@@ -254,9 +275,12 @@ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *att
if (enable) {
if (!kit->lcd_files_on) {
dev_dbg(&kit->udev->dev, "Adding lcd files\n");
- device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1);
- device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2);
- device_create_file(&kit->intf->dev, &dev_attr_backlight);
+ for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++) {
+ rc = device_create_file(kit->dev,
+ &dev_lcd_line_attrs[i]);
+ if (rc)
+ goto out;
+ }
kit->lcd_files_on = 1;
}
} else {
@@ -267,7 +291,13 @@ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *att
}
return count;
+out:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
+
+ return rc;
}
+
static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
@@ -363,44 +393,58 @@ static void do_notify(void *data)
for (i=0; i<kit->ifkit->inputs; i++) {
if (test_and_clear_bit(i, &kit->input_events)) {
sprintf(sysfs_file, "input%d", i + 1);
- sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
+ sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
}
}
for (i=0; i<kit->ifkit->sensors; i++) {
if (test_and_clear_bit(i, &kit->sensor_events)) {
sprintf(sysfs_file, "sensor%d", i + 1);
- sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
+ sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
}
}
}
+static void do_resubmit(void *data)
+{
+ set_outputs(data);
+}
+
#define show_set_output(value) \
-static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
+static ssize_t set_output##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
- int enabled; \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
+ int enable; \
int retval; \
\
- if (sscanf(buf, "%d", &enabled) < 1) \
+ if (sscanf(buf, "%d", &enable) < 1) \
return -EINVAL; \
\
- retval = change_outputs(kit, value - 1, enabled); \
+ if (enable) \
+ set_bit(value - 1, &kit->outputs); \
+ else \
+ clear_bit(value - 1, &kit->outputs); \
+ \
+ retval = set_outputs(kit); \
\
return retval ? retval : count; \
} \
\
-static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_output##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
\
return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\
-} \
-static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \
- show_output##value, set_output##value);
+}
+
+#define output_attr(value) \
+ __ATTR(output##value, S_IWUGO | S_IRUGO, \
+ show_output##value, set_output##value)
+
show_set_output(1);
show_set_output(2);
show_set_output(3);
@@ -418,15 +462,24 @@ show_set_output(14);
show_set_output(15);
show_set_output(16);
+static struct device_attribute dev_output_attrs[] = {
+ output_attr(1), output_attr(2), output_attr(3), output_attr(4),
+ output_attr(5), output_attr(6), output_attr(7), output_attr(8),
+ output_attr(9), output_attr(10), output_attr(11), output_attr(12),
+ output_attr(13), output_attr(14), output_attr(15), output_attr(16)
+};
+
#define show_input(value) \
-static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_input##value(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
\
return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]); \
-} \
-static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL);
+}
+
+#define input_attr(value) \
+ __ATTR(input##value, S_IRUGO, show_input##value, NULL)
show_input(1);
show_input(2);
@@ -445,15 +498,25 @@ show_input(14);
show_input(15);
show_input(16);
+static struct device_attribute dev_input_attrs[] = {
+ input_attr(1), input_attr(2), input_attr(3), input_attr(4),
+ input_attr(5), input_attr(6), input_attr(7), input_attr(8),
+ input_attr(9), input_attr(10), input_attr(11), input_attr(12),
+ input_attr(13), input_attr(14), input_attr(15), input_attr(16)
+};
+
#define show_sensor(value) \
-static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_sensor##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
\
return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]); \
-} \
-static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL);
+}
+
+#define sensor_attr(value) \
+ __ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL)
show_sensor(1);
show_sensor(2);
@@ -464,6 +527,11 @@ show_sensor(6);
show_sensor(7);
show_sensor(8);
+static struct device_attribute dev_sensor_attrs[] = {
+ sensor_attr(1), sensor_attr(2), sensor_attr(3), sensor_attr(4),
+ sensor_attr(5), sensor_attr(6), sensor_attr(7), sensor_attr(8)
+};
+
static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -472,6 +540,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
struct interfacekit *kit;
struct driver_interfacekit *ifkit;
int pipe, maxp, rc = -ENOMEM;
+ int bit, value, i;
ifkit = (struct driver_interfacekit *)id->driver_info;
if (!ifkit)
@@ -494,6 +563,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
if (!kit)
goto out;
+ kit->dev_no = -1;
kit->ifkit = ifkit;
kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma);
if (!kit->data)
@@ -506,6 +576,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
kit->udev = usb_get_dev(dev);
kit->intf = intf;
INIT_WORK(&kit->do_notify, do_notify, kit);
+ INIT_WORK(&kit->do_resubmit, do_resubmit, kit);
usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
interfacekit_irq, kit, endpoint->bInterval);
@@ -514,85 +585,80 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
usb_set_intfdata(intf, kit);
+ do {
+ bit = find_first_zero_bit(&device_no, sizeof(device_no));
+ value = test_and_set_bit(bit, &device_no);
+ } while(value);
+ kit->dev_no = bit;
+
+ kit->dev = device_create(phidget_class, &kit->udev->dev, 0,
+ "interfacekit%d", kit->dev_no);
+ if (IS_ERR(kit->dev)) {
+ rc = PTR_ERR(kit->dev);
+ kit->dev = NULL;
+ goto out;
+ }
+ dev_set_drvdata(kit->dev, kit);
+
if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
rc = -EIO;
goto out;
}
- if (ifkit->outputs >= 4) {
- device_create_file(&intf->dev, &dev_attr_output1);
- device_create_file(&intf->dev, &dev_attr_output2);
- device_create_file(&intf->dev, &dev_attr_output3);
- device_create_file(&intf->dev, &dev_attr_output4);
- }
- if (ifkit->outputs >= 8) {
- device_create_file(&intf->dev, &dev_attr_output5);
- device_create_file(&intf->dev, &dev_attr_output6);
- device_create_file(&intf->dev, &dev_attr_output7);
- device_create_file(&intf->dev, &dev_attr_output8);
- }
- if (ifkit->outputs == 16) {
- device_create_file(&intf->dev, &dev_attr_output9);
- device_create_file(&intf->dev, &dev_attr_output10);
- device_create_file(&intf->dev, &dev_attr_output11);
- device_create_file(&intf->dev, &dev_attr_output12);
- device_create_file(&intf->dev, &dev_attr_output13);
- device_create_file(&intf->dev, &dev_attr_output14);
- device_create_file(&intf->dev, &dev_attr_output15);
- device_create_file(&intf->dev, &dev_attr_output16);
+ for (i=0; i<ifkit->outputs; i++ ) {
+ rc = device_create_file(kit->dev, &dev_output_attrs[i]);
+ if (rc)
+ goto out2;
}
- if (ifkit->inputs >= 4) {
- device_create_file(&intf->dev, &dev_attr_input1);
- device_create_file(&intf->dev, &dev_attr_input2);
- device_create_file(&intf->dev, &dev_attr_input3);
- device_create_file(&intf->dev, &dev_attr_input4);
- }
- if (ifkit->inputs >= 8) {
- device_create_file(&intf->dev, &dev_attr_input5);
- device_create_file(&intf->dev, &dev_attr_input6);
- device_create_file(&intf->dev, &dev_attr_input7);
- device_create_file(&intf->dev, &dev_attr_input8);
- }
- if (ifkit->inputs == 16) {
- device_create_file(&intf->dev, &dev_attr_input9);
- device_create_file(&intf->dev, &dev_attr_input10);
- device_create_file(&intf->dev, &dev_attr_input11);
- device_create_file(&intf->dev, &dev_attr_input12);
- device_create_file(&intf->dev, &dev_attr_input13);
- device_create_file(&intf->dev, &dev_attr_input14);
- device_create_file(&intf->dev, &dev_attr_input15);
- device_create_file(&intf->dev, &dev_attr_input16);
+ for (i=0; i<ifkit->inputs; i++ ) {
+ rc = device_create_file(kit->dev, &dev_input_attrs[i]);
+ if (rc)
+ goto out3;
}
- if (ifkit->sensors >= 4) {
- device_create_file(&intf->dev, &dev_attr_sensor1);
- device_create_file(&intf->dev, &dev_attr_sensor2);
- device_create_file(&intf->dev, &dev_attr_sensor3);
- device_create_file(&intf->dev, &dev_attr_sensor4);
+ for (i=0; i<ifkit->sensors; i++ ) {
+ rc = device_create_file(kit->dev, &dev_sensor_attrs[i]);
+ if (rc)
+ goto out4;
}
- if (ifkit->sensors >= 7) {
- device_create_file(&intf->dev, &dev_attr_sensor5);
- device_create_file(&intf->dev, &dev_attr_sensor6);
- device_create_file(&intf->dev, &dev_attr_sensor7);
- }
- if (ifkit->sensors == 8)
- device_create_file(&intf->dev, &dev_attr_sensor8);
- if (ifkit->has_lcd)
- device_create_file(&intf->dev, &dev_attr_lcd);
+ if (ifkit->has_lcd) {
+ rc = device_create_file(kit->dev, &dev_attr_lcd);
+ if (rc)
+ goto out4;
+
+ }
dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
ifkit->sensors, ifkit->inputs, ifkit->outputs);
return 0;
+out4:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_sensor_attrs[i]);
+
+ i = ifkit->inputs;
+out3:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_input_attrs[i]);
+
+ i = ifkit->outputs;
+out2:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_output_attrs[i]);
out:
if (kit) {
if (kit->irq)
usb_free_urb(kit->irq);
if (kit->data)
usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma);
+ if (kit->dev)
+ device_unregister(kit->dev);
+ if (kit->dev_no >= 0)
+ clear_bit(kit->dev_no, &device_no);
+
kfree(kit);
}
@@ -602,6 +668,7 @@ out:
static void interfacekit_disconnect(struct usb_interface *interface)
{
struct interfacekit *kit;
+ int i;
kit = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
@@ -613,74 +680,30 @@ static void interfacekit_disconnect(struct usb_interface *interface)
usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma);
cancel_delayed_work(&kit->do_notify);
+ cancel_delayed_work(&kit->do_resubmit);
- if (kit->ifkit->outputs >= 4) {
- device_remove_file(&interface->dev, &dev_attr_output1);
- device_remove_file(&interface->dev, &dev_attr_output2);
- device_remove_file(&interface->dev, &dev_attr_output3);
- device_remove_file(&interface->dev, &dev_attr_output4);
- }
- if (kit->ifkit->outputs >= 8) {
- device_remove_file(&interface->dev, &dev_attr_output5);
- device_remove_file(&interface->dev, &dev_attr_output6);
- device_remove_file(&interface->dev, &dev_attr_output7);
- device_remove_file(&interface->dev, &dev_attr_output8);
- }
- if (kit->ifkit->outputs == 16) {
- device_remove_file(&interface->dev, &dev_attr_output9);
- device_remove_file(&interface->dev, &dev_attr_output10);
- device_remove_file(&interface->dev, &dev_attr_output11);
- device_remove_file(&interface->dev, &dev_attr_output12);
- device_remove_file(&interface->dev, &dev_attr_output13);
- device_remove_file(&interface->dev, &dev_attr_output14);
- device_remove_file(&interface->dev, &dev_attr_output15);
- device_remove_file(&interface->dev, &dev_attr_output16);
- }
+ for (i=0; i<kit->ifkit->outputs; i++)
+ device_remove_file(kit->dev, &dev_output_attrs[i]);
- if (kit->ifkit->inputs >= 4) {
- device_remove_file(&interface->dev, &dev_attr_input1);
- device_remove_file(&interface->dev, &dev_attr_input2);
- device_remove_file(&interface->dev, &dev_attr_input3);
- device_remove_file(&interface->dev, &dev_attr_input4);
- }
- if (kit->ifkit->inputs >= 8) {
- device_remove_file(&interface->dev, &dev_attr_input5);
- device_remove_file(&interface->dev, &dev_attr_input6);
- device_remove_file(&interface->dev, &dev_attr_input7);
- device_remove_file(&interface->dev, &dev_attr_input8);
- }
- if (kit->ifkit->inputs == 16) {
- device_remove_file(&interface->dev, &dev_attr_input9);
- device_remove_file(&interface->dev, &dev_attr_input10);
- device_remove_file(&interface->dev, &dev_attr_input11);
- device_remove_file(&interface->dev, &dev_attr_input12);
- device_remove_file(&interface->dev, &dev_attr_input13);
- device_remove_file(&interface->dev, &dev_attr_input14);
- device_remove_file(&interface->dev, &dev_attr_input15);
- device_remove_file(&interface->dev, &dev_attr_input16);
- }
+ for (i=0; i<kit->ifkit->inputs; i++)
+ device_remove_file(kit->dev, &dev_input_attrs[i]);
- if (kit->ifkit->sensors >= 4) {
- device_remove_file(&interface->dev, &dev_attr_sensor1);
- device_remove_file(&interface->dev, &dev_attr_sensor2);
- device_remove_file(&interface->dev, &dev_attr_sensor3);
- device_remove_file(&interface->dev, &dev_attr_sensor4);
- }
- if (kit->ifkit->sensors >= 7) {
- device_remove_file(&interface->dev, &dev_attr_sensor5);
- device_remove_file(&interface->dev, &dev_attr_sensor6);
- device_remove_file(&interface->dev, &dev_attr_sensor7);
+ for (i=0; i<kit->ifkit->sensors; i++)
+ device_remove_file(kit->dev, &dev_sensor_attrs[i]);
+
+ if (kit->ifkit->has_lcd) {
+ device_remove_file(kit->dev, &dev_attr_lcd);
+ remove_lcd_files(kit);
}
- if (kit->ifkit->sensors == 8)
- device_remove_file(&interface->dev, &dev_attr_sensor8);
- if (kit->ifkit->has_lcd)
- device_remove_file(&interface->dev, &dev_attr_lcd);
+ device_unregister(kit->dev);
dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
usb_put_dev(kit->udev);
+ clear_bit(kit->dev_no, &device_no);
+
kfree(kit);
}
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
new file mode 100644
index 00000000000..6b59b620d61
--- /dev/null
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -0,0 +1,466 @@
+/*
+ * USB Phidget MotorControl driver
+ *
+ * Copyright (C) 2006 Sean Young <sean@mess.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "phidget.h"
+
+#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
+#define DRIVER_DESC "USB PhidgetMotorControl Driver"
+
+#define USB_VENDOR_ID_GLAB 0x06c2
+#define USB_DEVICE_ID_MOTORCONTROL 0x0058
+
+#define URB_INT_SIZE 8
+
+static unsigned long device_no;
+
+struct motorcontrol {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct device *dev;
+ int dev_no;
+ u8 inputs[4];
+ s8 desired_speed[2];
+ s8 speed[2];
+ s16 _current[2];
+ s8 acceleration[2];
+ struct urb *irq;
+ unsigned char *data;
+ dma_addr_t data_dma;
+
+ struct work_struct do_notify;
+ unsigned long input_events;
+ unsigned long speed_events;
+ unsigned long exceed_events;
+};
+
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_MOTORCONTROL) },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int set_motor(struct motorcontrol *mc, int motor)
+{
+ u8 *buffer;
+ int speed, speed2, acceleration;
+ int retval;
+
+ buffer = kzalloc(8, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&mc->intf->dev, "%s - out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ acceleration = mc->acceleration[motor] * 10;
+ /* -127 <= speed <= 127 */
+ speed = (mc->desired_speed[motor] * 127) / 100;
+ /* -0x7300 <= speed2 <= 0x7300 */
+ speed2 = (mc->desired_speed[motor] * 230 * 128) / 100;
+
+ buffer[0] = motor;
+ buffer[1] = speed;
+ buffer[2] = acceleration >> 8;
+ buffer[3] = acceleration;
+ buffer[4] = speed2 >> 8;
+ buffer[5] = speed2;
+
+ retval = usb_control_msg(mc->udev,
+ usb_sndctrlpipe(mc->udev, 0),
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
+
+ if (retval != 8)
+ dev_err(&mc->intf->dev, "usb_control_msg returned %d\n",
+ retval);
+ kfree(buffer);
+
+ return retval < 0 ? retval : 0;
+}
+
+static void motorcontrol_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct motorcontrol *mc = urb->context;
+ unsigned char *buffer = mc->data;
+ int i, level;
+ int status;
+
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ /* -EPIPE: should clear the halt */
+ default: /* error */
+ goto resubmit;
+ }
+
+ /* digital inputs */
+ for (i=0; i<4; i++) {
+ level = (buffer[0] >> i) & 1;
+ if (mc->inputs[i] != level) {
+ mc->inputs[i] = level;
+ set_bit(i, &mc->input_events);
+ }
+ }
+
+ /* motor speed */
+ if (buffer[2] == 0) {
+ for (i=0; i<2; i++) {
+ level = ((s8)buffer[4+i]) * 100 / 127;
+ if (mc->speed[i] != level) {
+ mc->speed[i] = level;
+ set_bit(i, &mc->speed_events);
+ }
+ }
+ } else {
+ int index = buffer[3] & 1;
+
+ level = ((s8)buffer[4] << 8) | buffer[5];
+ level = level * 100 / 29440;
+ if (mc->speed[index] != level) {
+ mc->speed[index] = level;
+ set_bit(index, &mc->speed_events);
+ }
+
+ level = ((s8)buffer[6] << 8) | buffer[7];
+ mc->_current[index] = level * 100 / 1572;
+ }
+
+ if (buffer[1] & 1)
+ set_bit(0, &mc->exceed_events);
+
+ if (buffer[1] & 2)
+ set_bit(1, &mc->exceed_events);
+
+ if (mc->input_events || mc->exceed_events || mc->speed_events)
+ schedule_work(&mc->do_notify);
+
+resubmit:
+ status = usb_submit_urb(urb, SLAB_ATOMIC);
+ if (status)
+ dev_err(&mc->intf->dev,
+ "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+ mc->udev->bus->bus_name,
+ mc->udev->devpath, status);
+}
+
+static void do_notify(void *data)
+{
+ struct motorcontrol *mc = data;
+ int i;
+ char sysfs_file[8];
+
+ for (i=0; i<4; i++) {
+ if (test_and_clear_bit(i, &mc->input_events)) {
+ sprintf(sysfs_file, "input%d", i);
+ sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
+ }
+ }
+
+ for (i=0; i<2; i++) {
+ if (test_and_clear_bit(i, &mc->speed_events)) {
+ sprintf(sysfs_file, "speed%d", i);
+ sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
+ }
+ }
+
+ for (i=0; i<2; i++) {
+ if (test_and_clear_bit(i, &mc->exceed_events))
+ dev_warn(&mc->intf->dev,
+ "motor #%d exceeds 1.5 Amp current limit\n", i);
+ }
+}
+
+#define show_set_speed(value) \
+static ssize_t set_speed##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ int speed; \
+ int retval; \
+ \
+ if (sscanf(buf, "%d", &speed) < 1) \
+ return -EINVAL; \
+ \
+ if (speed < -100 || speed > 100) \
+ return -EINVAL; \
+ \
+ mc->desired_speed[value] = speed; \
+ \
+ retval = set_motor(mc, value); \
+ \
+ return retval ? retval : count; \
+} \
+ \
+static ssize_t show_speed##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", mc->speed[value]); \
+}
+
+#define speed_attr(value) \
+ __ATTR(speed##value, S_IWUGO | S_IRUGO, \
+ show_speed##value, set_speed##value)
+
+show_set_speed(0);
+show_set_speed(1);
+
+#define show_set_acceleration(value) \
+static ssize_t set_acceleration##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ int acceleration; \
+ int retval; \
+ \
+ if (sscanf(buf, "%d", &acceleration) < 1) \
+ return -EINVAL; \
+ \
+ if (acceleration < 0 || acceleration > 100) \
+ return -EINVAL; \
+ \
+ mc->acceleration[value] = acceleration; \
+ \
+ retval = set_motor(mc, value); \
+ \
+ return retval ? retval : count; \
+} \
+ \
+static ssize_t show_acceleration##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", mc->acceleration[value]); \
+}
+
+#define acceleration_attr(value) \
+ __ATTR(acceleration##value, S_IWUGO | S_IRUGO, \
+ show_acceleration##value, set_acceleration##value)
+
+show_set_acceleration(0);
+show_set_acceleration(1);
+
+#define show_current(value) \
+static ssize_t show_current##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%dmA\n", (int)mc->_current[value]); \
+}
+
+#define current_attr(value) \
+ __ATTR(current##value, S_IRUGO, show_current##value, NULL)
+
+show_current(0);
+show_current(1);
+
+#define show_input(value) \
+static ssize_t show_input##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", (int)mc->inputs[value]); \
+}
+
+#define input_attr(value) \
+ __ATTR(input##value, S_IRUGO, show_input##value, NULL)
+
+show_input(0);
+show_input(1);
+show_input(2);
+show_input(3);
+
+static struct device_attribute dev_attrs[] = {
+ input_attr(0),
+ input_attr(1),
+ input_attr(2),
+ input_attr(3),
+ speed_attr(0),
+ speed_attr(1),
+ acceleration_attr(0),
+ acceleration_attr(1),
+ current_attr(0),
+ current_attr(1)
+};
+
+static int motorcontrol_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct motorcontrol *mc;
+ int pipe, maxp, rc = -ENOMEM;
+ int bit, value, i;
+
+ interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints != 1)
+ return -ENODEV;
+
+ endpoint = &interface->endpoint[0].desc;
+ if (!(endpoint->bEndpointAddress & 0x80))
+ return -ENODEV;
+
+ /*
+ * bmAttributes
+ */
+ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ mc = kzalloc(sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ goto out;
+
+ mc->dev_no = -1;
+ mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &mc->data_dma);
+ if (!mc->data)
+ goto out;
+
+ mc->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mc->irq)
+ goto out;
+
+ mc->udev = usb_get_dev(dev);
+ mc->intf = intf;
+ mc->acceleration[0] = mc->acceleration[1] = 10;
+ INIT_WORK(&mc->do_notify, do_notify, mc);
+ usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data,
+ maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
+ motorcontrol_irq, mc, endpoint->bInterval);
+ mc->irq->transfer_dma = mc->data_dma;
+ mc->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_set_intfdata(intf, mc);
+
+ do {
+ bit = find_first_zero_bit(&device_no, sizeof(device_no));
+ value = test_and_set_bit(bit, &device_no);
+ } while(value);
+ mc->dev_no = bit;
+
+ mc->dev = device_create(phidget_class, &mc->udev->dev, 0,
+ "motorcontrol%d", mc->dev_no);
+ if (IS_ERR(mc->dev)) {
+ rc = PTR_ERR(mc->dev);
+ mc->dev = NULL;
+ goto out;
+ }
+
+ dev_set_drvdata(mc->dev, mc);
+
+ if (usb_submit_urb(mc->irq, GFP_KERNEL)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ for (i=0; i<ARRAY_SIZE(dev_attrs); i++) {
+ rc = device_create_file(mc->dev, &dev_attrs[i]);
+ if (rc)
+ goto out2;
+ }
+
+ dev_info(&intf->dev, "USB PhidgetMotorControl attached\n");
+
+ return 0;
+out2:
+ while (i-- > 0)
+ device_remove_file(mc->dev, &dev_attrs[i]);
+out:
+ if (mc) {
+ if (mc->irq)
+ usb_free_urb(mc->irq);
+ if (mc->data)
+ usb_buffer_free(dev, URB_INT_SIZE, mc->data, mc->data_dma);
+ if (mc->dev)
+ device_unregister(mc->dev);
+ if (mc->dev_no >= 0)
+ clear_bit(mc->dev_no, &device_no);
+
+ kfree(mc);
+ }
+
+ return rc;
+}
+
+static void motorcontrol_disconnect(struct usb_interface *interface)
+{
+ struct motorcontrol *mc;
+ int i;
+
+ mc = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+ if (!mc)
+ return;
+
+ usb_kill_urb(mc->irq);
+ usb_free_urb(mc->irq);
+ usb_buffer_free(mc->udev, URB_INT_SIZE, mc->data, mc->data_dma);
+
+ cancel_delayed_work(&mc->do_notify);
+
+ for (i=0; i<ARRAY_SIZE(dev_attrs); i++)
+ device_remove_file(mc->dev, &dev_attrs[i]);
+
+ device_unregister(mc->dev);
+
+ usb_put_dev(mc->udev);
+ clear_bit(mc->dev_no, &device_no);
+ kfree(mc);
+
+ dev_info(&interface->dev, "USB PhidgetMotorControl detached\n");
+}
+
+static struct usb_driver motorcontrol_driver = {
+ .name = "phidgetmotorcontrol",
+ .probe = motorcontrol_probe,
+ .disconnect = motorcontrol_disconnect,
+ .id_table = id_table
+};
+
+static int __init motorcontrol_init(void)
+{
+ int retval = 0;
+
+ retval = usb_register(&motorcontrol_driver);
+ if (retval)
+ err("usb_register failed. Error number %d", retval);
+
+ return retval;
+}
+
+static void __exit motorcontrol_exit(void)
+{
+ usb_deregister(&motorcontrol_driver);
+}
+
+module_init(motorcontrol_init);
+module_exit(motorcontrol_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index 5a040c205ee..7163f05c5b2 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -1,7 +1,7 @@
/*
* USB PhidgetServo driver 1.0
*
- * Copyright (C) 2004 Sean Young <sean@mess.org>
+ * Copyright (C) 2004, 2006 Sean Young <sean@mess.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
@@ -15,17 +15,8 @@
*
* CAUTION: Generally you should use 0 < degrees < 180 as anything else
* is probably beyond the range of your servo and may damage it.
- *
- * Jun 16, 2004: Sean Young <sean@mess.org>
- * - cleanups
- * - was using memory after kfree()
- * Aug 8, 2004: Sean Young <sean@mess.org>
- * - set the highest angle as high as the hardware allows, there are
- * some odd servos out there
- *
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -33,6 +24,8 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include "phidget.h"
+
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
#define DRIVER_DESC "USB PhidgetServo Driver"
@@ -71,8 +64,12 @@ static struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
+static int unsigned long device_no;
+
struct phidget_servo {
struct usb_device *udev;
+ struct device *dev;
+ int dev_no;
ulong type;
int pulse[4];
int degrees[4];
@@ -204,16 +201,16 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
}
#define show_set(value) \
-static ssize_t set_servo##value (struct device *dev, struct device_attribute *attr, \
+static ssize_t set_servo##value (struct device *dev, \
+ struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
int degrees, minutes, retval; \
- struct usb_interface *intf = to_usb_interface (dev); \
- struct phidget_servo *servo = usb_get_intfdata (intf); \
+ struct phidget_servo *servo = dev_get_drvdata(dev); \
\
minutes = 0; \
/* must at least convert degrees */ \
- if (sscanf (buf, "%d.%d", &degrees, &minutes) < 1) { \
+ if (sscanf(buf, "%d.%d", &degrees, &minutes) < 1) { \
return -EINVAL; \
} \
\
@@ -221,86 +218,127 @@ static ssize_t set_servo##value (struct device *dev, struct device_attribute *at
return -EINVAL; \
\
if (servo->type & SERVO_VERSION_30) \
- retval = change_position_v30 (servo, value, degrees, \
+ retval = change_position_v30(servo, value, degrees, \
minutes); \
else \
- retval = change_position_v20 (servo, value, degrees, \
+ retval = change_position_v20(servo, value, degrees, \
minutes); \
\
return retval < 0 ? retval : count; \
} \
\
-static ssize_t show_servo##value (struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_servo##value (struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface (dev); \
- struct phidget_servo *servo = usb_get_intfdata (intf); \
+ struct phidget_servo *servo = dev_get_drvdata(dev); \
\
- return sprintf (buf, "%d.%02d\n", servo->degrees[value], \
+ return sprintf(buf, "%d.%02d\n", servo->degrees[value], \
servo->minutes[value]); \
-} \
-static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \
- show_servo##value, set_servo##value);
+}
+#define servo_attr(value) \
+ __ATTR(servo##value, S_IWUGO | S_IRUGO, \
+ show_servo##value, set_servo##value)
show_set(0);
show_set(1);
show_set(2);
show_set(3);
+static struct device_attribute dev_attrs[] = {
+ servo_attr(0), servo_attr(1), servo_attr(2), servo_attr(3)
+};
+
static int
servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct phidget_servo *dev;
+ int bit, value, rc;
+ int servo_count, i;
dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out;
}
dev->udev = usb_get_dev(udev);
dev->type = id->driver_info;
+ dev->dev_no = -1;
usb_set_intfdata(interface, dev);
- device_create_file(&interface->dev, &dev_attr_servo0);
- if (dev->type & SERVO_COUNT_QUAD) {
- device_create_file(&interface->dev, &dev_attr_servo1);
- device_create_file(&interface->dev, &dev_attr_servo2);
- device_create_file(&interface->dev, &dev_attr_servo3);
+ do {
+ bit = find_first_zero_bit(&device_no, sizeof(device_no));
+ value = test_and_set_bit(bit, &device_no);
+ } while (value);
+ dev->dev_no = bit;
+
+ dev->dev = device_create(phidget_class, &dev->udev->dev, 0,
+ "servo%d", dev->dev_no);
+ if (IS_ERR(dev->dev)) {
+ rc = PTR_ERR(dev->dev);
+ dev->dev = NULL;
+ goto out;
+ }
+
+ servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
+
+ for (i=0; i<servo_count; i++) {
+ rc = device_create_file(dev->dev, &dev_attrs[i]);
+ if (rc)
+ goto out2;
}
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
- dev->type & SERVO_COUNT_QUAD ? 4 : 1,
- dev->type & SERVO_VERSION_30 ? 3 : 2);
+ servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
- if(!(dev->type & SERVO_VERSION_30))
+ if (!(dev->type & SERVO_VERSION_30))
dev_info(&interface->dev,
"WARNING: v2.0 not tested! Please report if it works.\n");
return 0;
+out2:
+ while (i-- > 0)
+ device_remove_file(dev->dev, &dev_attrs[i]);
+out:
+ if (dev) {
+ if (dev->dev)
+ device_unregister(dev->dev);
+ if (dev->dev_no >= 0)
+ clear_bit(dev->dev_no, &device_no);
+
+ kfree(dev);
+ }
+
+ return rc;
}
static void
servo_disconnect(struct usb_interface *interface)
{
struct phidget_servo *dev;
+ int servo_count, i;
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
- device_remove_file(&interface->dev, &dev_attr_servo0);
- if (dev->type & SERVO_COUNT_QUAD) {
- device_remove_file(&interface->dev, &dev_attr_servo1);
- device_remove_file(&interface->dev, &dev_attr_servo2);
- device_remove_file(&interface->dev, &dev_attr_servo3);
- }
+ if (!dev)
+ return;
+
+ servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
+
+ for (i=0; i<servo_count; i++)
+ device_remove_file(dev->dev, &dev_attrs[i]);
+ device_unregister(dev->dev);
usb_put_dev(dev->udev);
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
- dev->type & SERVO_COUNT_QUAD ? 4 : 1,
- dev->type & SERVO_VERSION_30 ? 3 : 2);
+ servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
+ clear_bit(dev->dev_no, &device_no);
kfree(dev);
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 738bd7c7451..a44124c7e85 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -3179,7 +3179,7 @@ sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
}
#endif
-static struct file_operations usb_sisusb_fops = {
+static const struct file_operations usb_sisusb_fops = {
.owner = THIS_MODULE,
.open = sisusb_open,
.release = sisusb_release,
@@ -3435,6 +3435,8 @@ static void sisusb_disconnect(struct usb_interface *intf)
static struct usb_device_id sisusb_table [] = {
{ USB_DEVICE(0x0711, 0x0900) },
+ { USB_DEVICE(0x0711, 0x0901) },
+ { USB_DEVICE(0x0711, 0x0902) },
{ USB_DEVICE(0x182d, 0x021c) },
{ USB_DEVICE(0x182d, 0x0269) },
{ }
diff --git a/drivers/usb/misc/sisusbvga/sisusb_init.c b/drivers/usb/misc/sisusbvga/sisusb_init.c
index 968f0d38cff..9b30f896281 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_init.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_init.c
@@ -36,7 +36,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h
new file mode 100644
index 00000000000..551ba8906d6
--- /dev/null
+++ b/drivers/usb/misc/usb_u132.h
@@ -0,0 +1,97 @@
+/*
+* Common Header File for the Elan Digital Systems U132 adapter
+* this file should be included by both the "ftdi-u132" and
+* the "u132-hcd" modules.
+*
+* Copyright(C) 2006 Elan Digital Systems Limited
+*(http://www.elandigitalsystems.com)
+*
+* Author and Maintainer - Tony Olech - Elan Digital Systems
+*(tony.olech@elandigitalsystems.com)
+*
+* This program is free software;you can redistribute it and/or
+* modify it under the terms of the GNU General Public License as
+* published by the Free Software Foundation, version 2.
+*
+*
+* The driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
+* based on various USB client drivers in the 2.6.15 linux kernel
+* with constant reference to the 3rd Edition of Linux Device Drivers
+* published by O'Reilly
+*
+* The U132 adapter is a USB to CardBus adapter specifically designed
+* for PC cards that contain an OHCI host controller. Typical PC cards
+* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
+*
+* The U132 adapter will *NOT *work with PC cards that do not contain
+* an OHCI controller. A simple way to test whether a PC card has an
+* OHCI controller as an interface is to insert the PC card directly
+* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
+* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
+* then there is a good chance that the U132 adapter will support the
+* PC card.(you also need the specific client driver for the PC card)
+*
+* Please inform the Author and Maintainer about any PC cards that
+* contain OHCI Host Controller and work when directly connected to
+* an embedded CardBus slot but do not work when they are connected
+* via an ELAN U132 adapter.
+*
+* The driver consists of two modules, the "ftdi-u132" module is
+* a USB client driver that interfaces to the FTDI chip within
+* the U132 adapter manufactured by Elan Digital Systems, and the
+* "u132-hcd" module is a USB host controller driver that talks
+* to the OHCI controller within CardBus card that are inserted
+* in the U132 adapter.
+*
+* The "ftdi-u132" module should be loaded automatically by the
+* hot plug system when the U132 adapter is plugged in. The module
+* initialises the adapter which mostly consists of synchronising
+* the FTDI chip, before continuously polling the adapter to detect
+* PC card insertions. As soon as a PC card containing a recognised
+* OHCI controller is seen the "ftdi-u132" module explicitly requests
+* the kernel to load the "u132-hcd" module.
+*
+* The "ftdi-u132" module provides the interface to the inserted
+* PC card and the "u132-hcd" module uses the API to send and recieve
+* data. The API features call-backs, so that part of the "u132-hcd"
+* module code will run in the context of one of the kernel threads
+* of the "ftdi-u132" module.
+*
+*/
+int ftdi_elan_switch_on_diagnostics(int number);
+void ftdi_elan_gone_away(struct platform_device *pdev);
+void start_usb_lock_device_tracing(void);
+struct u132_platform_data {
+ u16 vendor;
+ u16 device;
+ u8 potpg;
+ void (*port_power) (struct device *dev, int is_on);
+ void (*reset) (struct device *dev);
+};
+int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
+ void *endp);
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index c82c402285a..dbaca9f1efa 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -200,10 +200,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- retval = -ENOMEM;
- goto error;
- }
+ if (!urb)
+ return -ENOMEM;
buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
if (!buf) {
@@ -241,7 +239,7 @@ error:
return retval;
}
-static struct file_operations lcd_fops = {
+static const struct file_operations lcd_fops = {
.owner = THIS_MODULE,
.read = lcd_read,
.write = lcd_write,
@@ -292,9 +290,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->bulk_in_endpointAddr &&
- (endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
@@ -307,9 +303,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
}
if (!dev->bulk_out_endpointAddr &&
- !(endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index f441964132c..49c5c5c4c43 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -109,22 +108,34 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "Out of memory\n");
- goto error;
+ goto error_mem;
}
dev->udev = usb_get_dev(udev);
usb_set_intfdata (interface, dev);
- device_create_file(&interface->dev, &dev_attr_blue);
- device_create_file(&interface->dev, &dev_attr_red);
- device_create_file(&interface->dev, &dev_attr_green);
+ retval = device_create_file(&interface->dev, &dev_attr_blue);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_red);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_green);
+ if (retval)
+ goto error;
dev_info(&interface->dev, "USB LED device now attached\n");
return 0;
error:
+ device_remove_file(&interface->dev, &dev_attr_blue);
+ device_remove_file(&interface->dev, &dev_attr_red);
+ device_remove_file(&interface->dev, &dev_attr_green);
+ usb_set_intfdata (interface, NULL);
+ usb_put_dev(dev->udev);
kfree(dev);
+error_mem:
return retval;
}
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 81ba14c73dc..983e104dd45 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -1243,11 +1242,12 @@ done:
static int ctrl_out (struct usbtest_dev *dev,
unsigned count, unsigned length, unsigned vary)
{
- unsigned i, j, len, retval;
+ unsigned i, j, len;
+ int retval;
u8 *buf;
char *what = "?";
struct usb_device *udev;
-
+
if (length < 1 || length > 0xffff || vary >= length)
return -EINVAL;
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 275a66f8305..394bbf2f68d 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -265,7 +265,6 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
ubus->mon_bus = NULL;
mbus->u_bus = NULL;
mb();
- // usb_bus_put(ubus);
}
/*
@@ -297,12 +296,12 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
INIT_LIST_HEAD(&mbus->r_list);
/*
- * This usb_bus_get here is superfluous, because we receive
- * a notification if usb_bus is about to be removed.
+ * We don't need to take a reference to ubus, because we receive
+ * a notification if the bus is about to be removed.
*/
- // usb_bus_get(ubus);
mbus->u_bus = ubus;
ubus->mon_bus = mbus;
+ mbus->uses_dma = ubus->uses_dma;
rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
if (rc <= 0 || rc >= NAMESZ)
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
index 1fe01d994a7..f6d1491256c 100644
--- a/drivers/usb/mon/mon_stat.c
+++ b/drivers/usb/mon/mon_stat.c
@@ -28,7 +28,7 @@ static int mon_stat_open(struct inode *inode, struct file *file)
if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
return -ENOMEM;
- mbus = inode->u.generic_ip;
+ mbus = inode->i_private;
sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
"nreaders %d events %u text_lost %u\n",
@@ -62,7 +62,7 @@ static int mon_stat_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations mon_fops_stat = {
+const struct file_operations mon_fops_stat = {
.owner = THIS_MODULE,
.open = mon_stat_open,
.llseek = no_llseek,
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index e02c1a30c4c..7a2346c5328 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -64,7 +64,6 @@ struct mon_reader_text {
};
static void mon_text_ctor(void *, kmem_cache_t *, unsigned long);
-static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
/*
* mon_text_submit
@@ -76,13 +75,13 @@ static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
*/
static inline char mon_text_get_setup(struct mon_event_text *ep,
- struct urb *urb, char ev_type)
+ struct urb *urb, char ev_type, struct mon_bus *mbus)
{
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
return '-';
- if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -92,7 +91,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
}
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
- int len, char ev_type)
+ int len, char ev_type, struct mon_bus *mbus)
{
int pipe = urb->pipe;
@@ -118,7 +117,7 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
- if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+ if (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
return mon_dmapeek(ep->data, urb->transfer_dma, len);
if (urb->transfer_buffer == NULL)
@@ -162,8 +161,9 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
/* Collecting status makes debugging sense for submits, too */
ep->status = urb->status;
- ep->setup_flag = mon_text_get_setup(ep, urb, ev_type);
- ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
+ ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus);
+ ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type,
+ rp->r.m_bus);
rp->nevents++;
list_add_tail(&ep->e_link, &rp->e_list);
@@ -239,7 +239,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
int rc;
mutex_lock(&mon_lock);
- mbus = inode->u.generic_ip;
+ mbus = inode->i_private;
ubus = mbus->u_bus;
rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
@@ -268,7 +268,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
(long)rp);
rp->e_slab = kmem_cache_create(rp->slab_name,
sizeof(struct mon_event_text), sizeof(long), 0,
- mon_text_ctor, mon_text_dtor);
+ mon_text_ctor, NULL);
if (rp->e_slab == NULL) {
rc = -ENOMEM;
goto err_slab;
@@ -402,7 +402,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
struct mon_event_text *ep;
mutex_lock(&mon_lock);
- mbus = inode->u.generic_ip;
+ mbus = inode->i_private;
if (mbus->nreaders <= 0) {
printk(KERN_ERR TAG ": consistency error on close\n");
@@ -436,7 +436,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations mon_fops_text = {
+const struct file_operations mon_fops_text = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
@@ -459,7 +459,3 @@ static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags)
memset(mem, 0xe5, sizeof(struct mon_event_text));
}
-static void mon_text_dtor(void *mem, kmem_cache_t *slab, unsigned long sflags)
-{
- ;
-}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index 33678c24ebe..ab9d02d5df7 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -20,6 +20,7 @@ struct mon_bus {
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
struct usb_bus *u_bus;
+ int uses_dma;
/* Ref */
int nreaders; /* Under mon_lock AND mbus->lock */
@@ -53,7 +54,7 @@ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
extern struct mutex mon_lock;
-extern struct file_operations mon_fops_text;
-extern struct file_operations mon_fops_stat;
+extern const struct file_operations mon_fops_text;
+extern const struct file_operations mon_fops_stat;
#endif /* __USB_MON_H */
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 37111acec87..9c0eacf7055 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -1,7 +1,8 @@
/*
* ASIX AX8817X based USB 2.0 Ethernet Devices
- * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
* Copyright (c) 2002-2003 TiVo Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -22,7 +23,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/sched.h>
@@ -37,6 +37,9 @@
#include "usbnet.h"
+#define DRIVER_VERSION "14-Jun-2006"
+static const char driver_name [] = "asix";
+
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
#define AX_CMD_SET_SW_MII 0x06
@@ -47,23 +50,25 @@
#define AX_CMD_WRITE_EEPROM 0x0c
#define AX_CMD_WRITE_ENABLE 0x0d
#define AX_CMD_WRITE_DISABLE 0x0e
+#define AX_CMD_READ_RX_CTL 0x0f
#define AX_CMD_WRITE_RX_CTL 0x10
#define AX_CMD_READ_IPG012 0x11
#define AX_CMD_WRITE_IPG0 0x12
#define AX_CMD_WRITE_IPG1 0x13
+#define AX_CMD_READ_NODE_ID 0x13
#define AX_CMD_WRITE_IPG2 0x14
#define AX_CMD_WRITE_MULTI_FILTER 0x16
-#define AX_CMD_READ_NODE_ID 0x17
+#define AX88172_CMD_READ_NODE_ID 0x17
#define AX_CMD_READ_PHY_ID 0x19
#define AX_CMD_READ_MEDIUM_STATUS 0x1a
#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
#define AX_CMD_READ_MONITOR_MODE 0x1c
#define AX_CMD_WRITE_MONITOR_MODE 0x1d
+#define AX_CMD_READ_GPIOS 0x1e
#define AX_CMD_WRITE_GPIOS 0x1f
#define AX_CMD_SW_RESET 0x20
#define AX_CMD_SW_PHY_STATUS 0x21
#define AX_CMD_SW_PHY_SELECT 0x22
-#define AX88772_CMD_READ_NODE_ID 0x13
#define AX_MONITOR_MODE 0x01
#define AX_MONITOR_LINK 0x02
@@ -71,15 +76,15 @@
#define AX_MONITOR_HSFS 0x10
/* AX88172 Medium Status Register values */
-#define AX_MEDIUM_FULL_DUPLEX 0x02
-#define AX_MEDIUM_TX_ABORT_ALLOW 0x04
-#define AX_MEDIUM_FLOW_CONTROL_EN 0x10
+#define AX88172_MEDIUM_FD 0x02
+#define AX88172_MEDIUM_TX 0x04
+#define AX88172_MEDIUM_FC 0x10
+#define AX88172_MEDIUM_DEFAULT \
+ ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )
#define AX_MCAST_FILTER_SIZE 8
#define AX_MAX_MCAST 64
-#define AX_EEPROM_LEN 0x40
-
#define AX_SWRESET_CLEAR 0x00
#define AX_SWRESET_RR 0x01
#define AX_SWRESET_RT 0x02
@@ -93,23 +98,78 @@
#define AX88772_IPG1_DEFAULT 0x0c
#define AX88772_IPG2_DEFAULT 0x12
-#define AX88772_MEDIUM_FULL_DUPLEX 0x0002
-#define AX88772_MEDIUM_RESERVED 0x0004
-#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010
-#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020
-#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080
-#define AX88772_MEDIUM_RX_ENABLE 0x0100
-#define AX88772_MEDIUM_100MB 0x0200
-#define AX88772_MEDIUM_DEFAULT \
- (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
- AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
- AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
+/* AX88772 & AX88178 Medium Mode Register */
+#define AX_MEDIUM_PF 0x0080
+#define AX_MEDIUM_JFE 0x0040
+#define AX_MEDIUM_TFC 0x0020
+#define AX_MEDIUM_RFC 0x0010
+#define AX_MEDIUM_ENCK 0x0008
+#define AX_MEDIUM_AC 0x0004
+#define AX_MEDIUM_FD 0x0002
+#define AX_MEDIUM_GM 0x0001
+#define AX_MEDIUM_SM 0x1000
+#define AX_MEDIUM_SBP 0x0800
+#define AX_MEDIUM_PS 0x0200
+#define AX_MEDIUM_RE 0x0100
+
+#define AX88178_MEDIUM_DEFAULT \
+ (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
+ AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
+ AX_MEDIUM_RE )
-#define AX_EEPROM_MAGIC 0xdeadbeef
+#define AX88772_MEDIUM_DEFAULT \
+ (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
+ AX_MEDIUM_TFC | AX_MEDIUM_PS | \
+ AX_MEDIUM_AC | AX_MEDIUM_RE )
+
+/* AX88772 & AX88178 RX_CTL values */
+#define AX_RX_CTL_SO 0x0080
+#define AX_RX_CTL_AP 0x0020
+#define AX_RX_CTL_AM 0x0010
+#define AX_RX_CTL_AB 0x0008
+#define AX_RX_CTL_SEP 0x0004
+#define AX_RX_CTL_AMALL 0x0002
+#define AX_RX_CTL_PRO 0x0001
+#define AX_RX_CTL_MFB_2048 0x0000
+#define AX_RX_CTL_MFB_4096 0x0100
+#define AX_RX_CTL_MFB_8192 0x0200
+#define AX_RX_CTL_MFB_16384 0x0300
+
+#define AX_DEFAULT_RX_CTL \
+ (AX_RX_CTL_SO | AX_RX_CTL_AB )
+
+/* GPIO 0 .. 2 toggles */
+#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
+#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */
+#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */
+#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */
+#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
+#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
+#define AX_GPIO_RESERVED 0x40 /* Reserved */
+#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
+
+#define AX_EEPROM_MAGIC 0xdeadbeef
+#define AX88172_EEPROM_LEN 0x40
+#define AX88772_EEPROM_LEN 0xff
+
+#define PHY_MODE_MARVELL 0x0000
+#define MII_MARVELL_LED_CTRL 0x0018
+#define MII_MARVELL_STATUS 0x001b
+#define MII_MARVELL_CTRL 0x0014
+
+#define MARVELL_LED_MANUAL 0x0019
+
+#define MARVELL_STATUS_HWCFG 0x0004
+
+#define MARVELL_CTRL_TXDELAY 0x0002
+#define MARVELL_CTRL_RXDELAY 0x0080
/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
struct asix_data {
u8 multi_filter[AX_MCAST_FILTER_SIZE];
+ u8 phymode;
+ u8 ledmode;
+ u8 eeprom_len;
};
struct ax88172_int_data {
@@ -123,6 +183,8 @@ struct ax88172_int_data {
static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
+ devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
+ cmd, value, index, size);
return usb_control_msg(
dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
@@ -138,6 +200,8 @@ static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
+ devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
+ cmd, value, index, size);
return usb_control_msg(
dev->udev,
usb_sndctrlpipe(dev->udev, 0),
@@ -162,12 +226,167 @@ static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
usb_free_urb(urb);
}
+static void
+asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ struct usb_ctrlrequest *req;
+ int status;
+ struct urb *urb;
+
+ devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
+ cmd, value, index, size);
+ if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
+ deverr(dev, "Error allocating URB in write_cmd_async!");
+ return;
+ }
+
+ if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = cmd;
+ req->wValue = value;
+ req->wIndex = index;
+ req->wLength = size;
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, size,
+ asix_async_cmd_callback, req);
+
+ if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u8 *head;
+ u32 header;
+ char *packet;
+ struct sk_buff *ax_skb;
+ u16 size;
+
+ head = (u8 *) skb->data;
+ memcpy(&header, head, sizeof(header));
+ le32_to_cpus(&header);
+ packet = head + sizeof(header);
+
+ skb_pull(skb, 4);
+
+ while (skb->len > 0) {
+ if ((short)(header & 0x0000ffff) !=
+ ~((short)((header & 0xffff0000) >> 16))) {
+ deverr(dev,"asix_rx_fixup() Bad Header Length");
+ }
+ /* get the packet length */
+ size = (u16) (header & 0x0000ffff);
+
+ if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+ return 2;
+ if (size > ETH_FRAME_LEN) {
+ deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);
+ return 0;
+ }
+ ax_skb = skb_clone(skb, GFP_ATOMIC);
+ if (ax_skb) {
+ ax_skb->len = size;
+ ax_skb->data = packet;
+ ax_skb->tail = packet + size;
+ usbnet_skb_return(dev, ax_skb);
+ } else {
+ return 0;
+ }
+
+ skb_pull(skb, (size + 1) & 0xfffe);
+
+ if (skb->len == 0)
+ break;
+
+ head = (u8 *) skb->data;
+ memcpy(&header, head, sizeof(header));
+ le32_to_cpus(&header);
+ packet = head + sizeof(header);
+ skb_pull(skb, 4);
+ }
+
+ if (skb->len < 0) {
+ deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len);
+ return 0;
+ }
+ return 1;
+}
+
+static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int padlen;
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+ u32 packet_len;
+ u32 padbytes = 0xffff0000;
+
+ padlen = ((skb->len + 4) % 512) ? 0 : 4;
+
+ if ((!skb_cloned(skb))
+ && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data, skb->len);
+ skb->tail = skb->data + skb->len;
+ }
+ } else {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ skb_push(skb, 4);
+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+ memcpy(skb->data, &packet_len, sizeof(packet_len));
+
+ if ((skb->len % 512) == 0) {
+ memcpy( skb->tail, &padbytes, sizeof(padbytes));
+ skb_put(skb, sizeof(padbytes));
+ }
+ return skb;
+}
+
+static void asix_status(struct usbnet *dev, struct urb *urb)
+{
+ struct ax88172_int_data *event;
+ int link;
+
+ if (urb->actual_length < 8)
+ return;
+
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ usbnet_defer_kevent (dev, EVENT_LINK_RESET );
+ } else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "Link Status is: %d", link);
+ }
+}
+
static inline int asix_set_sw_mii(struct usbnet *dev)
{
int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
if (ret < 0)
- devdbg(dev, "Failed to enable software MII access");
+ deverr(dev, "Failed to enable software MII access");
return ret;
}
@@ -176,24 +395,27 @@ static inline int asix_set_hw_mii(struct usbnet *dev)
int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
if (ret < 0)
- devdbg(dev, "Failed to enable hardware MII access");
+ deverr(dev, "Failed to enable hardware MII access");
return ret;
}
-static inline int asix_get_phyid(struct usbnet *dev)
+static inline int asix_get_phy_addr(struct usbnet *dev)
{
int ret = 0;
void *buf;
+ devdbg(dev, "asix_get_phy_addr()");
+
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
goto out1;
if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID,
0, 0, 2, buf)) < 2) {
- devdbg(dev, "Error reading PHYID register: %02x", ret);
+ deverr(dev, "Error reading PHYID register: %02x", ret);
goto out2;
}
+ devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((u16 *)buf));
ret = *((u8 *)buf + 1);
out2:
kfree(buf);
@@ -207,91 +429,109 @@ static int asix_sw_reset(struct usbnet *dev, u8 flags)
ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
if (ret < 0)
- devdbg(dev,"Failed to send software reset: %02x", ret);
+ deverr(dev,"Failed to send software reset: %02x", ret);
return ret;
}
+static u16 asix_read_rx_ctl(struct usbnet *dev)
+{
+ u16 ret = 0;
+ void *buf;
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ goto out1;
+
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL,
+ 0, 0, 2, buf)) < 2) {
+ deverr(dev, "Error reading RX_CTL register: %02x", ret);
+ goto out2;
+ }
+ ret = le16_to_cpu(*((u16 *)buf));
+out2:
+ kfree(buf);
+out1:
+ return ret;
+}
+
static int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
{
int ret;
+ devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode);
ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
if (ret < 0)
- devdbg(dev, "Failed to write RX_CTL mode: %02x", ret);
+ deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x",
+ mode, ret);
return ret;
}
-static void asix_status(struct usbnet *dev, struct urb *urb)
+static u16 asix_read_medium_status(struct usbnet *dev)
{
- struct ax88172_int_data *event;
- int link;
+ u16 ret = 0;
+ void *buf;
- if (urb->actual_length < 8)
- return;
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ goto out1;
- event = urb->transfer_buffer;
- link = event->link & 0x01;
- if (netif_carrier_ok(dev->net) != link) {
- if (link) {
- netif_carrier_on(dev->net);
- usbnet_defer_kevent (dev, EVENT_LINK_RESET );
- } else
- netif_carrier_off(dev->net);
- devdbg(dev, "Link Status is: %d", link);
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS,
+ 0, 0, 2, buf)) < 2) {
+ deverr(dev, "Error reading Medium Status register: %02x", ret);
+ goto out2;
}
+ ret = le16_to_cpu(*((u16 *)buf));
+out2:
+ kfree(buf);
+out1:
+ return ret;
}
-static void
-asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
- u16 size, void *data)
+static int asix_write_medium_mode(struct usbnet *dev, u16 mode)
{
- struct usb_ctrlrequest *req;
- int status;
- struct urb *urb;
+ int ret;
- if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
- devdbg(dev, "Error allocating URB in write_cmd_async!");
- return;
- }
+ devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ if (ret < 0)
+ deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x",
+ mode, ret);
- if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
- deverr(dev, "Failed to allocate memory for control request");
- usb_free_urb(urb);
- return;
- }
+ return ret;
+}
- req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- req->bRequest = cmd;
- req->wValue = cpu_to_le16(value);
- req->wIndex = cpu_to_le16(index);
- req->wLength = cpu_to_le16(size);
+static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
+{
+ int ret;
- usb_fill_control_urb(urb, dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- (void *)req, data, size,
- asix_async_cmd_callback, req);
+ devdbg(dev,"asix_write_gpio() - value = 0x%04x", value);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+ if (ret < 0)
+ deverr(dev, "Failed to write GPIO value 0x%04x: %02x",
+ value, ret);
- if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- deverr(dev, "Error submitting the control message: status=%d",
- status);
- kfree(req);
- usb_free_urb(urb);
- }
+ if (sleep)
+ msleep(sleep);
+
+ return ret;
}
+/*
+ * AX88772 & AX88178 have a 16-bit RX_CTL value
+ */
static void asix_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct asix_data *data = (struct asix_data *)&dev->data;
- u8 rx_ctl = 0x8c;
+ u16 rx_ctl = AX_DEFAULT_RX_CTL;
if (net->flags & IFF_PROMISC) {
- rx_ctl |= 0x01;
+ rx_ctl |= AX_RX_CTL_PRO;
} else if (net->flags & IFF_ALLMULTI
|| net->mc_count > AX_MAX_MCAST) {
- rx_ctl |= 0x02;
+ rx_ctl |= AX_RX_CTL_AMALL;
} else if (net->mc_count == 0) {
/* just broadcast and directed */
} else {
@@ -318,7 +558,7 @@ static void asix_set_multicast(struct net_device *net)
asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
AX_MCAST_FILTER_SIZE, data->multi_filter);
- rx_ctl |= 0x10;
+ rx_ctl |= AX_RX_CTL_AM;
}
asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
@@ -334,50 +574,43 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
(__u16)loc, 2, (u16 *)&res);
asix_set_hw_mii(dev);
- return res & 0xffff;
-}
+ devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff));
-/* same as above, but converts resulting value to cpu byte order */
-static int asix_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
-{
- return le16_to_cpu(asix_mdio_read(netdev,phy_id, loc));
+ return le16_to_cpu(res & 0xffff);
}
static void
asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
- u16 res = val;
+ u16 res = cpu_to_le16(val);
+ devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);
asix_set_sw_mii(dev);
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
asix_set_hw_mii(dev);
}
-/* same as above, but converts new value to le16 byte order before writing */
-static void
-asix_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
+static u32 asix_get_phyid(struct usbnet *dev)
{
- asix_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
-}
+ int phy_reg;
+ u32 phy_id;
-static int ax88172_link_reset(struct usbnet *dev)
-{
- u16 lpa;
- u16 adv;
- u16 res;
- u8 mode;
+ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
+ if (phy_reg < 0)
+ return 0;
- mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
- lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
- adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
- res = mii_nway_result(lpa|adv);
- if (res & LPA_DUPLEX)
- mode |= AX_MEDIUM_FULL_DUPLEX;
- asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ phy_id = (phy_reg & 0xffff) << 16;
- return 0;
+ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
+ if (phy_reg < 0)
+ return 0;
+
+ phy_id |= (phy_reg & 0xffff);
+
+ return phy_id;
}
static void
@@ -424,7 +657,10 @@ asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
static int asix_get_eeprom_len(struct net_device *net)
{
- return AX_EEPROM_LEN;
+ struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ return data->eeprom_len;
}
static int asix_get_eeprom(struct net_device *net,
@@ -454,9 +690,14 @@ static int asix_get_eeprom(struct net_device *net,
static void asix_get_drvinfo (struct net_device *net,
struct ethtool_drvinfo *info)
{
+ struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
- info->eedump_len = 0x3e;
+ strncpy (info->driver, driver_name, sizeof info->driver);
+ strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+ info->eedump_len = data->eeprom_len;
}
static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
@@ -469,8 +710,34 @@ static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
{
struct usbnet *dev = netdev_priv(net);
+ int res = mii_ethtool_sset(&dev->mii,cmd);
+
+ /* link speed/duplex might have changed */
+ if (dev->driver_info->link_reset)
+ dev->driver_info->link_reset(dev);
+
+ return res;
+}
+
+static int asix_nway_reset(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return mii_nway_restart(&dev->mii);
+}
+
+static u32 asix_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
- return mii_ethtool_sset(&dev->mii,cmd);
+ return mii_link_ok(&dev->mii);
+}
+
+static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
/* We need to override some ethtool_ops so we require our
@@ -478,7 +745,8 @@ static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
devices that may be connected at the same time. */
static struct ethtool_ops ax88172_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
- .get_link = ethtool_op_get_link,
+ .get_link = asix_get_link,
+ .nway_reset = asix_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
@@ -489,11 +757,66 @@ static struct ethtool_ops ax88172_ethtool_ops = {
.set_settings = asix_set_settings,
};
-static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+static void ax88172_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u8 rx_ctl = 0x8c;
- return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= 0x01;
+ } else if (net->flags & IFF_ALLMULTI
+ || net->mc_count > AX_MAX_MCAST) {
+ rx_ctl |= 0x02;
+ } else if (net->mc_count == 0) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later */
+ struct dev_mc_list *mc_list = net->mc_list;
+ u32 crc_bits;
+ int i;
+
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+
+ /* Build the multicast hash filter. */
+ for (i = 0; i < net->mc_count; i++) {
+ crc_bits =
+ ether_crc(ETH_ALEN,
+ mc_list->dmi_addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ mc_list = mc_list->next;
+ }
+
+ asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+ AX_MCAST_FILTER_SIZE, data->multi_filter);
+
+ rx_ctl |= 0x10;
+ }
+
+ asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int ax88172_link_reset(struct usbnet *dev)
+{
+ u8 mode;
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = AX88172_MEDIUM_DEFAULT;
+
+ if (ecmd.duplex != DUPLEX_FULL)
+ mode |= ~AX88172_MEDIUM_FD;
+
+ devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+
+ asix_write_medium_mode(dev, mode);
+
+ return 0;
}
static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -502,6 +825,9 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
void *buf;
int i;
unsigned long gpio_bits = dev->driver_info->data;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ data->eeprom_len = AX88172_EEPROM_LEN;
usbnet_get_endpoints(dev,intf);
@@ -520,12 +846,12 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
msleep(5);
}
- if ((ret = asix_write_rx_ctl(dev,0x80)) < 0)
+ if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0)
goto out2;
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
0, 0, 6, buf)) < 0) {
dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
goto out2;
@@ -538,14 +864,14 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.mdio_write = asix_mdio_write;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phyid(dev);
+ dev->mii.phy_id = asix_get_phy_addr(dev);
dev->net->do_ioctl = asix_ioctl;
- dev->net->set_multicast_list = asix_set_multicast;
+ dev->net->set_multicast_list = ax88172_set_multicast;
dev->net->ethtool_ops = &ax88172_ethtool_ops;
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart(&dev->mii);
@@ -558,7 +884,8 @@ out1:
static struct ethtool_ops ax88772_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
- .get_link = ethtool_op_get_link,
+ .get_link = asix_get_link,
+ .nway_reset = asix_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
@@ -569,10 +896,37 @@ static struct ethtool_ops ax88772_ethtool_ops = {
.set_settings = asix_set_settings,
};
+static int ax88772_link_reset(struct usbnet *dev)
+{
+ u16 mode;
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = AX88772_MEDIUM_DEFAULT;
+
+ if (ecmd.speed != SPEED_100)
+ mode &= ~AX_MEDIUM_PS;
+
+ if (ecmd.duplex != DUPLEX_FULL)
+ mode &= ~AX_MEDIUM_FD;
+
+ devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+
+ asix_write_medium_mode(dev, mode);
+
+ return 0;
+}
+
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
void *buf;
+ u16 rx_ctl;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u32 phyid;
+
+ data->eeprom_len = AX88772_EEPROM_LEN;
usbnet_get_endpoints(dev,intf);
@@ -583,13 +937,12 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
goto out1;
}
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
- 0x00B0, 0, 0, buf)) < 0)
+ if ((ret = asix_write_gpio(dev,
+ AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)
goto out2;
- msleep(5);
if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
- 0x0001, 0, 0, buf)) < 0) {
+ 0x0000, 0, 0, buf)) < 0) {
dbg("Select PHY #1 failed: %d", ret);
goto out2;
}
@@ -606,36 +959,34 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
goto out2;
msleep(150);
- if ((ret = asix_write_rx_ctl(dev, 0x00)) < 0)
+ rx_ctl = asix_read_rx_ctl(dev);
+ dbg("RX_CTL is 0x%04x after software reset", rx_ctl);
+ if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0)
goto out2;
+ rx_ctl = asix_read_rx_ctl(dev);
+ dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
+
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
- if ((ret = asix_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
0, 0, ETH_ALEN, buf)) < 0) {
dbg("Failed to read MAC address: %d", ret);
goto out2;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
- if ((ret = asix_set_sw_mii(dev)) < 0)
- goto out2;
-
- if (((ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG,
- 0x0010, 2, 2, buf)) < 0)
- || (*((u16 *)buf) != 0x003b)) {
- dbg("Read PHY register 2 must be 0x3b00: %d", ret);
- goto out2;
- }
-
/* Initialize MII structure */
dev->mii.dev = dev->net;
dev->mii.mdio_read = asix_mdio_read;
dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0xff;
- dev->mii.reg_num_mask = 0xff;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
dev->net->do_ioctl = asix_ioctl;
- dev->mii.phy_id = asix_get_phyid(dev);
+ dev->mii.phy_id = asix_get_phy_addr(dev);
+
+ phyid = asix_get_phyid(dev);
+ dbg("PHYID=0x%08x", phyid);
if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0)
goto out2;
@@ -650,16 +1001,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->set_multicast_list = asix_set_multicast;
dev->net->ethtool_ops = &ax88772_ethtool_ops;
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA);
mii_nway_restart(&dev->mii);
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
- AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) {
- dbg("Write medium mode register: %d", ret);
+ if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0)
goto out2;
- }
if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
@@ -667,13 +1015,17 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
goto out2;
}
- if ((ret = asix_set_hw_mii(dev)) < 0)
- goto out2;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
- if ((ret = asix_write_rx_ctl(dev, 0x0088)) < 0)
+ if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
goto out2;
+ rx_ctl = asix_read_rx_ctl(dev);
+ dbg("RX_CTL is 0x%04x after all initializations", rx_ctl);
+
+ rx_ctl = asix_read_medium_status(dev);
+ dbg("Medium Status is 0x%04x after all initializations", rx_ctl);
+
kfree(buf);
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
@@ -691,120 +1043,285 @@ out1:
return ret;
}
-static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+static struct ethtool_ops ax88178_ethtool_ops = {
+ .get_drvinfo = asix_get_drvinfo,
+ .get_link = asix_get_link,
+ .nway_reset = asix_nway_reset,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = asix_get_wol,
+ .set_wol = asix_set_wol,
+ .get_eeprom_len = asix_get_eeprom_len,
+ .get_eeprom = asix_get_eeprom,
+ .get_settings = asix_get_settings,
+ .set_settings = asix_set_settings,
+};
+
+static int marvell_phy_init(struct usbnet *dev)
{
- u8 *head;
- u32 header;
- char *packet;
- struct sk_buff *ax_skb;
- u16 size;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u16 reg;
- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
+ devdbg(dev,"marvell_phy_init()");
- skb_pull(skb, 4);
+ reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS);
+ devdbg(dev,"MII_MARVELL_STATUS = 0x%04x", reg);
- while (skb->len > 0) {
- if ((short)(header & 0x0000ffff) !=
- ~((short)((header & 0xffff0000) >> 16))) {
- devdbg(dev,"header length data is error");
- }
- /* get the packet length */
- size = (u16) (header & 0x0000ffff);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL,
+ MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
- if ((skb->len) - ((size + 1) & 0xfffe) == 0)
- return 2;
- if (size > ETH_FRAME_LEN) {
- devdbg(dev,"invalid rx length %d", size);
- return 0;
- }
- ax_skb = skb_clone(skb, GFP_ATOMIC);
- if (ax_skb) {
- ax_skb->len = size;
- ax_skb->data = packet;
- ax_skb->tail = packet + size;
- usbnet_skb_return(dev, ax_skb);
- } else {
- return 0;
- }
+ if (data->ledmode) {
+ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
+ MII_MARVELL_LED_CTRL);
+ devdbg(dev,"MII_MARVELL_LED_CTRL (1) = 0x%04x", reg);
- skb_pull(skb, (size + 1) & 0xfffe);
+ reg &= 0xf8ff;
+ reg |= (1 + 0x0100);
+ asix_mdio_write(dev->net, dev->mii.phy_id,
+ MII_MARVELL_LED_CTRL, reg);
- if (skb->len == 0)
- break;
+ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
+ MII_MARVELL_LED_CTRL);
+ devdbg(dev,"MII_MARVELL_LED_CTRL (2) = 0x%04x", reg);
+ reg &= 0xfc0f;
+ }
- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
- skb_pull(skb, 4);
+ return 0;
+}
+
+static int marvell_led_status(struct usbnet *dev, u16 speed)
+{
+ u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
+
+ devdbg(dev, "marvell_led_status() read 0x%04x", reg);
+
+ /* Clear out the center LED bits - 0x03F0 */
+ reg &= 0xfc0f;
+
+ switch (speed) {
+ case SPEED_1000:
+ reg |= 0x03e0;
+ break;
+ case SPEED_100:
+ reg |= 0x03b0;
+ break;
+ default:
+ reg |= 0x02f0;
}
- if (skb->len < 0) {
- devdbg(dev,"invalid rx length %d", skb->len);
- return 0;
+ devdbg(dev, "marvell_led_status() writing 0x%04x", reg);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg);
+
+ return 0;
+}
+
+static int ax88178_link_reset(struct usbnet *dev)
+{
+ u16 mode;
+ struct ethtool_cmd ecmd;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ devdbg(dev,"ax88178_link_reset()");
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = AX88178_MEDIUM_DEFAULT;
+
+ if (ecmd.speed == SPEED_1000)
+ mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK;
+ else if (ecmd.speed == SPEED_100)
+ mode |= AX_MEDIUM_PS;
+ else
+ mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
+
+ if (ecmd.duplex == DUPLEX_FULL)
+ mode |= AX_MEDIUM_FD;
+ else
+ mode &= ~AX_MEDIUM_FD;
+
+ devdbg(dev, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+
+ asix_write_medium_mode(dev, mode);
+
+ if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
+ marvell_led_status(dev, ecmd.speed);
+
+ return 0;
+}
+
+static void ax88178_set_mfb(struct usbnet *dev)
+{
+ u16 mfb = AX_RX_CTL_MFB_16384;
+ u16 rxctl;
+ u16 medium;
+ int old_rx_urb_size = dev->rx_urb_size;
+
+ if (dev->hard_mtu < 2048) {
+ dev->rx_urb_size = 2048;
+ mfb = AX_RX_CTL_MFB_2048;
+ } else if (dev->hard_mtu < 4096) {
+ dev->rx_urb_size = 4096;
+ mfb = AX_RX_CTL_MFB_4096;
+ } else if (dev->hard_mtu < 8192) {
+ dev->rx_urb_size = 8192;
+ mfb = AX_RX_CTL_MFB_8192;
+ } else if (dev->hard_mtu < 16384) {
+ dev->rx_urb_size = 16384;
+ mfb = AX_RX_CTL_MFB_16384;
}
- return 1;
+
+ rxctl = asix_read_rx_ctl(dev);
+ asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb);
+
+ medium = asix_read_medium_status(dev);
+ if (dev->net->mtu > 1500)
+ medium |= AX_MEDIUM_JFE;
+ else
+ medium &= ~AX_MEDIUM_JFE;
+ asix_write_medium_mode(dev, medium);
+
+ if (dev->rx_urb_size > old_rx_urb_size)
+ usbnet_unlink_rx_urbs(dev);
}
-static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
- gfp_t flags)
+static int ax88178_change_mtu(struct net_device *net, int new_mtu)
{
- int padlen;
- int headroom = skb_headroom(skb);
- int tailroom = skb_tailroom(skb);
- u32 packet_len;
- u32 padbytes = 0xffff0000;
+ struct usbnet *dev = netdev_priv(net);
+ int ll_mtu = new_mtu + net->hard_header_len + 4;
- padlen = ((skb->len + 4) % 512) ? 0 : 4;
+ devdbg(dev, "ax88178_change_mtu() new_mtu=%d", new_mtu);
- if ((!skb_cloned(skb))
- && ((headroom + tailroom) >= (4 + padlen))) {
- if ((headroom < 4) || (tailroom < padlen)) {
- skb->data = memmove(skb->head + 4, skb->data, skb->len);
- skb->tail = skb->data + skb->len;
- }
+ if (new_mtu <= 0 || ll_mtu > 16384)
+ return -EINVAL;
+
+ if ((ll_mtu % dev->maxpacket) == 0)
+ return -EDOM;
+
+ net->mtu = new_mtu;
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+ ax88178_set_mfb(dev);
+
+ return 0;
+}
+
+static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ int ret;
+ void *buf;
+ u16 eeprom;
+ int gpio0 = 0;
+ u32 phyid;
+
+ usbnet_get_endpoints(dev,intf);
+
+ buf = kmalloc(6, GFP_KERNEL);
+ if(!buf) {
+ dbg ("Cannot allocate memory for buffer");
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ eeprom = 0;
+ asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &eeprom);
+ dbg("GPIO Status: 0x%04x", eeprom);
+
+ asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
+ asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
+ asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
+
+ dbg("EEPROM index 0x17 is 0x%04x", eeprom);
+
+ if (eeprom == 0xffff) {
+ data->phymode = PHY_MODE_MARVELL;
+ data->ledmode = 0;
+ gpio0 = 1;
} else {
- struct sk_buff *skb2;
- skb2 = skb_copy_expand(skb, 4, padlen, flags);
- dev_kfree_skb_any(skb);
- skb = skb2;
- if (!skb)
- return NULL;
+ data->phymode = eeprom & 7;
+ data->ledmode = eeprom >> 8;
+ gpio0 = (eeprom & 0x80) ? 0 : 1;
}
+ dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
- skb_push(skb, 4);
- packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
- memcpy(skb->data, &packet_len, sizeof(packet_len));
+ asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
+ if ((eeprom >> 8) != 1) {
+ asix_write_gpio(dev, 0x003c, 30);
+ asix_write_gpio(dev, 0x001c, 300);
+ asix_write_gpio(dev, 0x003c, 30);
+ } else {
+ dbg("gpio phymode == 1 path");
+ asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
+ asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
+ }
- if ((skb->len % 512) == 0) {
- memcpy( skb->tail, &padbytes, sizeof(padbytes));
- skb_put(skb, sizeof(padbytes));
+ asix_sw_reset(dev, 0);
+ msleep(150);
+
+ asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
+ msleep(150);
+
+ asix_write_rx_ctl(dev, 0);
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ 0, 0, ETH_ALEN, buf)) < 0) {
+ dbg("Failed to read MAC address: %d", ret);
+ goto out2;
}
- return skb;
-}
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
-static int ax88772_link_reset(struct usbnet *dev)
-{
- u16 lpa;
- u16 adv;
- u16 res;
- u16 mode;
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = asix_mdio_read;
+ dev->mii.mdio_write = asix_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0xff;
+ dev->mii.supports_gmii = 1;
+ dev->net->do_ioctl = asix_ioctl;
+ dev->mii.phy_id = asix_get_phy_addr(dev);
+ dev->net->set_multicast_list = asix_set_multicast;
+ dev->net->ethtool_ops = &ax88178_ethtool_ops;
+ dev->net->change_mtu = &ax88178_change_mtu;
- mode = AX88772_MEDIUM_DEFAULT;
- lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
- adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
- res = mii_nway_result(lpa|adv);
+ phyid = asix_get_phyid(dev);
+ dbg("PHYID=0x%08x", phyid);
+
+ if (data->phymode == PHY_MODE_MARVELL) {
+ marvell_phy_init(dev);
+ msleep(60);
+ }
+
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
+ BMCR_RESET | BMCR_ANENABLE);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
+ ADVERTISE_1000FULL);
+
+ mii_nway_restart(&dev->mii);
+
+ if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0)
+ goto out2;
- if ((res & LPA_DUPLEX) == 0)
- mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
- if ((res & LPA_100) == 0)
- mode &= ~AX88772_MEDIUM_100MB;
- asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
+ goto out2;
+
+ kfree(buf);
+
+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
+ /* hard_mtu is still the default - the device does not support
+ jumbo eth frames */
+ dev->rx_urb_size = 2048;
+ }
return 0;
+
+out2:
+ kfree(buf);
+out1:
+ return ret;
}
static const struct driver_info ax8817x_info = {
@@ -854,8 +1371,19 @@ static const struct driver_info ax88772_info = {
.link_reset = ax88772_link_reset,
.reset = ax88772_link_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX,
- .rx_fixup = ax88772_rx_fixup,
- .tx_fixup = ax88772_tx_fixup,
+ .rx_fixup = asix_rx_fixup,
+ .tx_fixup = asix_tx_fixup,
+};
+
+static const struct driver_info ax88178_info = {
+ .description = "ASIX AX88178 USB 2.0 Ethernet",
+ .bind = ax88178_bind,
+ .status = asix_status,
+ .link_reset = ax88178_link_reset,
+ .reset = ax88178_link_reset,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = asix_rx_fixup,
+ .tx_fixup = asix_tx_fixup,
};
static const struct usb_device_id products [] = {
@@ -914,7 +1442,7 @@ static const struct usb_device_id products [] = {
}, {
// ASIX AX88178 10/100/1000
USB_DEVICE (0x0b95, 0x1780),
- .driver_info = (unsigned long) &ax88772_info,
+ .driver_info = (unsigned long) &ax88178_info,
}, {
// Linksys USB200M Rev 2
USB_DEVICE (0x13b1, 0x0018),
@@ -923,6 +1451,18 @@ static const struct usb_device_id products [] = {
// 0Q0 cable ethernet
USB_DEVICE (0x1557, 0x7720),
.driver_info = (unsigned long) &ax88772_info,
+}, {
+ // DLink DUB-E100 H/W Ver B1
+ USB_DEVICE (0x07d1, 0x3c05),
+ .driver_info = (unsigned long) &ax88772_info,
+}, {
+ // DLink DUB-E100 H/W Ver B1 Alternate
+ USB_DEVICE (0x2001, 0x3c05),
+ .driver_info = (unsigned long) &ax88772_info,
+}, {
+ // Linksys USB1000
+ USB_DEVICE (0x1737, 0x0039),
+ .driver_info = (unsigned long) &ax88178_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index efd195b5912..82ce0358d9a 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -20,7 +20,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
diff --git a/drivers/usb/net/cdc_subset.c b/drivers/usb/net/cdc_subset.c
index ec801e8bb1b..e2fae85851a 100644
--- a/drivers/usb/net/cdc_subset.c
+++ b/drivers/usb/net/cdc_subset.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/sched.h>
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index faf1e86be68..3155f25f1d4 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -21,7 +21,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index def3bb8e229..544d41fe9b9 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -165,6 +165,7 @@ static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
+ { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */
{ USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
{} /* Null terminator */
};
diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c
index 78e6a43b108..301baa72bac 100644
--- a/drivers/usb/net/net1080.c
+++ b/drivers/usb/net/net1080.c
@@ -20,7 +20,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
@@ -499,25 +498,24 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
static struct sk_buff *
net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
- int padlen;
struct sk_buff *skb2;
struct nc_header *header = NULL;
struct nc_trailer *trailer = NULL;
+ int padlen = sizeof (struct nc_trailer);
int len = skb->len;
- padlen = ((len + sizeof (struct nc_header)
- + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
+ if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
+ padlen++;
if (!skb_cloned(skb)) {
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
- if ((padlen + sizeof (struct nc_trailer)) <= tailroom
- && sizeof (struct nc_header) <= headroom)
+ if (padlen <= tailroom &&
+ sizeof(struct nc_header) <= headroom)
/* There's enough head and tail room */
goto encapsulate;
- if ((sizeof (struct nc_header) + padlen
- + sizeof (struct nc_trailer)) <
+ if ((sizeof (struct nc_header) + padlen) <
(headroom + tailroom)) {
/* There's enough total room, so just readjust */
skb->data = memmove(skb->head
@@ -531,7 +529,7 @@ net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
/* Create a new skb to use with the correct size */
skb2 = skb_copy_expand(skb,
sizeof (struct nc_header),
- sizeof (struct nc_trailer) + padlen,
+ padlen,
flags);
dev_kfree_skb_any(skb);
if (!skb2)
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index ab21f960d25..918cf5a77c0 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -45,7 +45,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.6.13 (2005/11/13)"
+#define DRIVER_VERSION "v0.6.14 (2006/09/27)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
@@ -339,7 +339,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
}
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return ret;
}
@@ -376,7 +376,7 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return -ETIMEDOUT;
}
@@ -413,7 +413,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return -ETIMEDOUT;
}
@@ -461,7 +461,7 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
return ret;
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return -ETIMEDOUT;
}
#endif /* PEGASUS_WRITE_EEPROM */
@@ -481,8 +481,12 @@ static void set_ethernet_addr(pegasus_t * pegasus)
{
__u8 node_id[6];
- get_node_id(pegasus, node_id);
- set_registers(pegasus, EthID, sizeof (node_id), node_id);
+ if (pegasus->features & PEGASUS_II) {
+ get_registers(pegasus, 0x10, sizeof(node_id), node_id);
+ } else {
+ get_node_id(pegasus, node_id);
+ set_registers(pegasus, EthID, sizeof (node_id), node_id);
+ }
memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
}
@@ -619,7 +623,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
switch (urb->status) {
case 0:
break;
- case -ETIMEDOUT:
+ case -ETIME:
if (netif_msg_rx_err(pegasus))
pr_debug("%s: reset MAC\n", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY;
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index a54752ce149..006438069b6 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -131,6 +131,7 @@ struct usb_eth_dev {
#define VENDOR_COREGA 0x07aa
#define VENDOR_DLINK 0x2001
#define VENDOR_ELCON 0x0db7
+#define VENDOR_ELECOM 0x056e
#define VENDOR_ELSA 0x05cc
#define VENDOR_GIGABYTE 0x1044
#define VENDOR_HAWKING 0x0e66
@@ -233,6 +234,8 @@ PEGASUS_DEV( "D-Link DSB-650", VENDOR_DLINK, 0xabc1,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "GOLDPFEIL USB Adapter", VENDOR_ELCON, 0x0002,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
+PEGASUS_DEV( "ELECOM USB Ethernet LD-USB20", VENDOR_ELECOM, 0x4010,
+ DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "EasiDock Ethernet", VENDOR_MOBILITY, 0x0304,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
diff --git a/drivers/usb/net/plusb.c b/drivers/usb/net/plusb.c
index 4fe863389cb..5d17cdfc7ba 100644
--- a/drivers/usb/net/plusb.c
+++ b/drivers/usb/net/plusb.c
@@ -20,7 +20,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index f551546d752..c2a28d88ef3 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -20,7 +20,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 1bbbae283c0..2364c209938 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -6,7 +6,6 @@
* version 2 as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/signal.h>
@@ -129,11 +128,13 @@
#define VENDOR_ID_MELCO 0x0411
#define VENDOR_ID_MICRONET 0x3980
#define VENDOR_ID_LONGSHINE 0x07b8
+#define VENDOR_ID_ZYXEL 0x0586
#define PRODUCT_ID_RTL8150 0x8150
#define PRODUCT_ID_LUAKTX 0x0012
#define PRODUCT_ID_LCS8138TX 0x401a
#define PRODUCT_ID_SP128AR 0x0003
+#define PRODUCT_ID_PRESTIGE 0x401a
#undef EEPROM_WRITE
@@ -143,6 +144,7 @@ static struct usb_device_id rtl8150_table[] = {
{USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
{USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
{USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
+ {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
{}
};
@@ -173,6 +175,8 @@ static inline struct sk_buff *pull_skb(rtl8150_t *);
static void rtl8150_disconnect(struct usb_interface *intf);
static int rtl8150_probe(struct usb_interface *intf,
const struct usb_device_id *id);
+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtl8150_resume(struct usb_interface *intf);
static const char driver_name [] = "rtl8150";
@@ -181,6 +185,8 @@ static struct usb_driver rtl8150_driver = {
.probe = rtl8150_probe,
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
+ .suspend = rtl8150_suspend,
+ .resume = rtl8150_resume
};
/*
@@ -236,9 +242,11 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
usb_fill_control_urb(dev->ctrl_urb, dev->udev,
usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
&dev->rx_creg, size, ctrl_callback, dev);
- if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
+ if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
+ if (ret == -ENODEV)
+ netif_device_detach(dev->netdev);
err("control request submission failed: %d", ret);
- else
+ } else
set_bit(RX_REG_SET, &dev->flags);
return ret;
@@ -414,6 +422,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
struct sk_buff *skb;
struct net_device *netdev;
u16 rx_stat;
+ int status;
dev = urb->context;
if (!dev)
@@ -429,7 +438,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
break;
case -ENOENT:
return; /* the urb is in unlink state */
- case -ETIMEDOUT:
+ case -ETIME:
warn("may be reset is needed?..");
goto goon;
default:
@@ -463,7 +472,10 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
goon:
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
- if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+ if (status == -ENODEV)
+ netif_device_detach(dev->netdev);
+ else if (status) {
set_bit(RX_URB_FAIL, &dev->flags);
goto resched;
} else {
@@ -479,6 +491,7 @@ static void rx_fixup(unsigned long data)
{
rtl8150_t *dev;
struct sk_buff *skb;
+ int status;
dev = (rtl8150_t *)data;
@@ -497,10 +510,13 @@ static void rx_fixup(unsigned long data)
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
try_again:
- if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+ status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+ if (status == -ENODEV) {
+ netif_device_detach(dev->netdev);
+ } else if (status) {
set_bit(RX_URB_FAIL, &dev->flags);
goto tlsched;
- } else {
+ } else {
clear_bit(RX_URB_FAIL, &dev->flags);
}
@@ -572,12 +588,43 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
resubmit:
status = usb_submit_urb (urb, SLAB_ATOMIC);
- if (status)
+ if (status == -ENODEV)
+ netif_device_detach(dev->netdev);
+ else if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
dev->udev->bus->bus_name,
dev->udev->devpath, status);
}
+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ rtl8150_t *dev = usb_get_intfdata(intf);
+
+ netif_device_detach(dev->netdev);
+
+ if (netif_running(dev->netdev)) {
+ usb_kill_urb(dev->rx_urb);
+ usb_kill_urb(dev->intr_urb);
+ }
+ return 0;
+}
+
+static int rtl8150_resume(struct usb_interface *intf)
+{
+ rtl8150_t *dev = usb_get_intfdata(intf);
+
+ netif_device_attach(dev->netdev);
+ if (netif_running(dev->netdev)) {
+ dev->rx_urb->status = 0;
+ dev->rx_urb->actual_length = 0;
+ read_bulk_callback(dev->rx_urb, NULL);
+
+ dev->intr_urb->status = 0;
+ dev->intr_urb->actual_length = 0;
+ intr_callback(dev->intr_urb, NULL);
+ }
+ return 0;
+}
/*
**
@@ -688,9 +735,14 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
skb->data, count, write_bulk_callback, dev);
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
- warn("failed tx_urb %d\n", res);
- dev->stats.tx_errors++;
- netif_start_queue(netdev);
+ /* Can we get/handle EPIPE here? */
+ if (res == -ENODEV)
+ netif_device_detach(dev->netdev);
+ else {
+ warn("failed tx_urb %d\n", res);
+ dev->stats.tx_errors++;
+ netif_start_queue(netdev);
+ }
} else {
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
@@ -727,16 +779,25 @@ static int rtl8150_open(struct net_device *netdev)
usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
- if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
+ if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
+ if (res == -ENODEV)
+ netif_device_detach(dev->netdev);
warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+ return res;
+ }
usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
dev->intr_buff, INTBUFSIZE, intr_callback,
dev, dev->intr_interval);
- if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
+ if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
+ if (res == -ENODEV)
+ netif_device_detach(dev->netdev);
warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
- netif_start_queue(netdev);
+ usb_kill_urb(dev->rx_urb);
+ return res;
+ }
enable_net_traffic(dev);
set_carrier(netdev);
+ netif_start_queue(netdev);
return res;
}
@@ -911,6 +972,7 @@ static void rtl8150_disconnect(struct usb_interface *intf)
if (dev) {
set_bit(RTL8150_UNPLUG, &dev->flags);
tasklet_disable(&dev->tl);
+ tasklet_kill(&dev->tl);
unregister_netdev(dev->netdev);
unlink_all_urbs(dev);
free_all_urbs(dev);
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 362d6907c9b..98a522f1e26 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -33,7 +33,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
@@ -62,8 +61,11 @@
* let the USB host controller be busy for 5msec or more before an irq
* is required, under load. Jumbograms change the equation.
*/
-#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
-#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
+#define RX_MAX_QUEUE_MEMORY (60 * 1518)
+#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+ (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
+#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+ (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
// reawaken network queue this soon after stopping; else watchdog barks
#define TX_TIMEOUT_JIFFIES (5*HZ)
@@ -228,13 +230,23 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
{
struct usbnet *dev = netdev_priv(net);
int ll_mtu = new_mtu + net->hard_header_len;
+ int old_hard_mtu = dev->hard_mtu;
+ int old_rx_urb_size = dev->rx_urb_size;
- if (new_mtu <= 0 || ll_mtu > dev->hard_mtu)
+ if (new_mtu <= 0)
return -EINVAL;
// no second zero-length packet read wanted after mtu-sized packets
if ((ll_mtu % dev->maxpacket) == 0)
return -EDOM;
net->mtu = new_mtu;
+
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+ if (dev->rx_urb_size == old_hard_mtu) {
+ dev->rx_urb_size = dev->hard_mtu;
+ if (dev->rx_urb_size > old_rx_urb_size)
+ usbnet_unlink_rx_urbs(dev);
+ }
+
return 0;
}
@@ -413,9 +425,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// we get controller i/o faults during khubd disconnect() delays.
// throttle down resubmits, to avoid log floods; just temporarily,
// so we still recover when the fault isn't a khubd delay.
- case -EPROTO: // ehci
- case -ETIMEDOUT: // ohci
- case -EILSEQ: // uhci
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
dev->stats.rx_errors++;
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
@@ -522,6 +534,17 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
return count;
}
+// Flush all pending rx urbs
+// minidrivers may need to do this when the MTU changes
+
+void usbnet_unlink_rx_urbs(struct usbnet *dev)
+{
+ if (netif_running(dev->net)) {
+ (void) unlink_urbs (dev, &dev->rxq);
+ tasklet_schedule(&dev->bh);
+ }
+}
+EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
/*-------------------------------------------------------------------------*/
@@ -630,7 +653,7 @@ static int usbnet_open (struct net_device *net)
devinfo (dev, "open: enable queueing "
"(rx %d, tx %d) mtu %d %s framing",
- RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu,
+ (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu,
framing);
}
@@ -798,9 +821,9 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
// like rx, tx gets controller i/o faults during khubd delays
// and so it uses the same throttling mechanism.
- case -EPROTO: // ehci
- case -ETIMEDOUT: // ohci
- case -EILSEQ: // uhci
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay,
jiffies + THROTTLE_JIFFIES);
diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h
index 89fc4958eec..c0746f0454a 100644
--- a/drivers/usb/net/usbnet.h
+++ b/drivers/usb/net/usbnet.h
@@ -166,6 +166,7 @@ struct skb_data { /* skb->cb is one of these */
extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
extern void usbnet_defer_kevent (struct usbnet *, int);
extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
+extern void usbnet_unlink_rx_urbs(struct usbnet *);
extern u32 usbnet_get_msglevel (struct net_device *);
extern void usbnet_set_msglevel (struct net_device *, u32);
diff --git a/drivers/usb/net/zaurus.c b/drivers/usb/net/zaurus.c
index 813e470d060..144566bda58 100644
--- a/drivers/usb/net/zaurus.c
+++ b/drivers/usb/net/zaurus.c
@@ -20,7 +20,6 @@
// #define DEBUG // error path messages, extra info
// #define VERBOSE // more; success messages
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/init.h>
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 8bd44fda5ea..5076b9d9705 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -53,6 +53,15 @@ config USB_SERIAL_GENERIC
support" be compiled as a module for this driver to be used
properly.
+config USB_SERIAL_AIRCABLE
+ tristate "AIRcable USB Bluetooth Dongle Driver (EXPERIMENTAL)"
+ depends on USB_SERIAL && EXPERIMENTAL
+ help
+ Say Y here if you want to use AIRcable USB Bluetoot Dongle.
+
+ To compile this driver as a module, choose M here: the module
+ will be called aircable.
+
config USB_SERIAL_AIRPRIME
tristate "USB AirPrime CDMA Wireless Driver"
depends on USB_SERIAL
@@ -62,15 +71,6 @@ config USB_SERIAL_AIRPRIME
To compile this driver as a module, choose M here: the
module will be called airprime.
-config USB_SERIAL_ANYDATA
- tristate "USB AnyData CDMA Wireless Driver"
- depends on USB_SERIAL
- help
- Say Y here if you want to use a AnyData CDMA device.
-
- To compile this driver as a module, choose M here: the
- module will be called anydata.
-
config USB_SERIAL_ARK3116
tristate "USB ARK Micro 3116 USB Serial Driver (EXPERIMENTAL)"
depends on USB_SERIAL && EXPERIMENTAL
@@ -422,6 +422,21 @@ config USB_SERIAL_MCT_U232
To compile this driver as a module, choose M here: the
module will be called mct_u232.
+config USB_SERIAL_MOS7840
+ tristate "USB Moschip 7840/7820 USB Serial Driver"
+ depends on USB_SERIAL
+ ---help---
+ Say Y here if you want to use a MCS7840 Quad-Serial or MCS7820
+ Dual-Serial port device from MosChip Semiconductor.
+
+ The MCS7840 and MCS7820 have been developed to connect a wide range
+ of standard serial devices to a USB host. The MCS7840 has a USB
+ device controller connected to four (4) individual UARTs while the
+ MCS7820 controller connects to two (2) individual UARTs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mos7840. If unsure, choose N.
+
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
depends on USB_SERIAL
@@ -456,6 +471,17 @@ config USB_SERIAL_SAFE_PADDED
bool "USB Secure Encapsulated Driver - Padded"
depends on USB_SERIAL_SAFE
+config USB_SERIAL_SIERRAWIRELESS
+ tristate "USB Sierra Wireless Driver"
+ depends on USB_SERIAL
+ help
+ Say M here if you want to use a Sierra Wireless device (if
+ using an PC 5220 or AC580 please use the Airprime driver
+ instead).
+
+ To compile this driver as a module, choose M here: the
+ module will be called sierra.
+
config USB_SERIAL_TI
tristate "USB TI 3410/5052 Serial Driver"
depends on USB_SERIAL
@@ -491,15 +517,18 @@ config USB_SERIAL_XIRCOM
module will be called keyspan_pda.
config USB_SERIAL_OPTION
- tristate "USB driver for GSM modems"
+ tristate "USB driver for GSM and CDMA modems"
depends on USB_SERIAL
help
- Say Y here if you have an "Option" GSM PCMCIA card
- (or an OEM version: branded Huawei, Audiovox, or Novatel).
+ Say Y here if you have a GSM or CDMA modem that's connected to USB.
- These cards feature a built-in OHCI-USB adapter and an
- internally-connected GSM modem. The USB bus is not
- accessible externally.
+ This driver also supports several PCMCIA cards which have a
+ built-in OHCI-USB adapter and an internally-connected GSM modem.
+ The USB bus on these cards is not accessible externally.
+
+ Supported devices include (some of?) those made by:
+ Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
+ Anydata.
To compile this driver as a module, choose M here: the
module will be called option.
@@ -521,5 +550,6 @@ config USB_EZUSB
depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
default y
+
endmenu
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 5a0960fc9d3..8dce83340e3 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -11,8 +11,8 @@ usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o
usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
+obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
-obj-$(CONFIG_USB_SERIAL_ANYDATA) += anydata.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o
@@ -34,11 +34,13 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
+obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o
obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o
+obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o
obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o
obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o
obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
new file mode 100644
index 00000000000..2ccd9ded52a
--- /dev/null
+++ b/drivers/usb/serial/aircable.c
@@ -0,0 +1,625 @@
+/*
+ * AIRcable USB Bluetooth Dongle Driver.
+ *
+ * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel@gmail.com)
+ * 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.
+ *
+ * The device works as an standard CDC device, it has 2 interfaces, the first
+ * one is for firmware access and the second is the serial one.
+ * The protocol is very simply, there are two posibilities reading or writing.
+ * When writting the first urb must have a Header that starts with 0x20 0x29 the
+ * next two bytes must say how much data will be sended.
+ * When reading the process is almost equal except that the header starts with
+ * 0x00 0x20.
+ *
+ * The device simply need some stuff to understand data comming from the usb
+ * buffer: The First and Second byte is used for a Header, the Third and Fourth
+ * tells the device the amount of information the package holds.
+ * Packages are 60 bytes long Header Stuff.
+ * When writting to the device the first two bytes of the header are 0x20 0x29
+ * When reading the bytes are 0x00 0x20, or 0x00 0x10, there is an strange
+ * situation, when too much data arrives to the device because it sends the data
+ * but with out the header. I will use a simply hack to override this situation,
+ * if there is data coming that does not contain any header, then that is data
+ * that must go directly to the tty, as there is no documentation about if there
+ * is any other control code, I will simply check for the first
+ * one.
+ *
+ * The driver registers himself with the USB-serial core and the USB Core. I had
+ * to implement a probe function agains USB-serial, because other way, the
+ * driver was attaching himself to both interfaces. I have tryed with different
+ * configurations of usb_serial_driver with out exit, only the probe function
+ * could handle this correctly.
+ *
+ * I have taken some info from a Greg Kroah-Hartman article:
+ * http://www.linuxjournal.com/article/6573
+ * And from Linux Device Driver Kit CD, which is a great work, the authors taken
+ * the work to recompile lots of information an knowladge in drivers development
+ * and made it all avaible inside a cd.
+ * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/
+ *
+ */
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/circ_buf.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static int debug;
+
+/* Vendor and Product ID */
+#define AIRCABLE_VID 0x16CA
+#define AIRCABLE_USB_PID 0x1502
+
+/* write buffer size defines */
+#define AIRCABLE_BUF_SIZE 2048
+
+/* Protocol Stuff */
+#define HCI_HEADER_LENGTH 0x4
+#define TX_HEADER_0 0x20
+#define TX_HEADER_1 0x29
+#define RX_HEADER_0 0x00
+#define RX_HEADER_1 0x20
+#define MAX_HCI_FRAMESIZE 60
+#define HCI_COMPLETE_FRAME 64
+
+/* rx_flags */
+#define THROTTLED 0x01
+#define ACTUALLY_THROTTLED 0x02
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0b2"
+#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>"
+#define DRIVER_DESC "AIRcable USB Driver"
+
+/* ID table that will be registered with USB core */
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+
+/* Internal Structure */
+struct aircable_private {
+ spinlock_t rx_lock; /* spinlock for the receive lines */
+ struct circ_buf *tx_buf; /* write buffer */
+ struct circ_buf *rx_buf; /* read buffer */
+ int rx_flags; /* for throttilng */
+ struct work_struct rx_work; /* work cue for the receiving line */
+};
+
+/* Private methods */
+
+/* Circular Buffer Methods, code from ti_usb_3410_5052 used */
+/*
+ * serial_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void serial_buf_clear(struct circ_buf *cb)
+{
+ cb->head = cb->tail = 0;
+}
+
+/*
+ * serial_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static struct circ_buf *serial_buf_alloc(void)
+{
+ struct circ_buf *cb;
+ cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
+ if (cb == NULL)
+ return NULL;
+ cb->buf = kmalloc(AIRCABLE_BUF_SIZE, GFP_KERNEL);
+ if (cb->buf == NULL) {
+ kfree(cb);
+ return NULL;
+ }
+ serial_buf_clear(cb);
+ return cb;
+}
+
+/*
+ * serial_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void serial_buf_free(struct circ_buf *cb)
+{
+ kfree(cb->buf);
+ kfree(cb);
+}
+
+/*
+ * serial_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+static int serial_buf_data_avail(struct circ_buf *cb)
+{
+ return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
+}
+
+/*
+ * serial_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
+{
+ int c, ret = 0;
+ while (1) {
+ c = CIRC_SPACE_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(cb->buf + cb->head, buf, c);
+ cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
+ buf += c;
+ count -= c;
+ ret= c;
+ }
+ return ret;
+}
+
+/*
+ * serial_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
+{
+ int c, ret = 0;
+ while (1) {
+ c = CIRC_CNT_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(buf, cb->buf + cb->tail, c);
+ cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
+ buf += c;
+ count -= c;
+ ret= c;
+ }
+ return ret;
+}
+
+/* End of circula buffer methods */
+
+static void aircable_send(struct usb_serial_port *port)
+{
+ int count, result;
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ unsigned char* buf;
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ if (port->write_urb_busy)
+ return;
+
+ count = min(serial_buf_data_avail(priv->tx_buf), MAX_HCI_FRAMESIZE);
+ if (count == 0)
+ return;
+
+ buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC);
+ if (!buf) {
+ err("%s- kzalloc(%d) failed.", __FUNCTION__,
+ count + HCI_HEADER_LENGTH);
+ return;
+ }
+
+ buf[0] = TX_HEADER_0;
+ buf[1] = TX_HEADER_1;
+ buf[2] = (unsigned char)count;
+ buf[3] = (unsigned char)(count >> 8);
+ serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
+
+ memcpy(port->write_urb->transfer_buffer, buf,
+ count + HCI_HEADER_LENGTH);
+
+ kfree(buf);
+ port->write_urb_busy = 1;
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ count + HCI_HEADER_LENGTH,
+ port->write_urb->transfer_buffer);
+ port->write_urb->transfer_buffer_length = count + HCI_HEADER_LENGTH;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+
+ if (result) {
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __FUNCTION__, result);
+ port->write_urb_busy = 0;
+ }
+
+ schedule_work(&port->work);
+}
+
+static void aircable_read(void *params)
+{
+ struct usb_serial_port *port = params;
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned char *data;
+ int count;
+ if (priv->rx_flags & THROTTLED){
+ if (priv->rx_flags & ACTUALLY_THROTTLED)
+ schedule_work(&priv->rx_work);
+ return;
+ }
+
+ /* By now I will flush data to the tty in packages of no more than
+ * 64 bytes, to ensure I do not get throttled.
+ * Ask USB mailing list for better aproach.
+ */
+ tty = port->tty;
+
+ if (!tty)
+ schedule_work(&priv->rx_work);
+
+ count = min(64, serial_buf_data_avail(priv->rx_buf));
+
+ if (count <= 0)
+ return; //We have finished sending everything.
+
+ tty_prepare_flip_string(tty, &data, count);
+ if (!data){
+ err("%s- kzalloc(%d) failed.", __FUNCTION__, count);
+ return;
+ }
+
+ serial_buf_get(priv->rx_buf, data, count);
+
+ tty_flip_buffer_push(tty);
+
+ if (serial_buf_data_avail(priv->rx_buf))
+ schedule_work(&priv->rx_work);
+
+ return;
+}
+/* End of private methods */
+
+static int aircable_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ int num_bulk_out=0;
+ int i;
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found our bulk out endpoint */
+ dbg("found bulk out on endpoint %d", i);
+ ++num_bulk_out;
+ }
+ }
+
+ if (num_bulk_out == 0) {
+ dbg("Invalid interface, discarding");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int aircable_attach (struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct aircable_private *priv;
+
+ priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
+ if (!priv){
+ err("%s- kmalloc(%Zd) failed.", __FUNCTION__,
+ sizeof(struct aircable_private));
+ return -ENOMEM;
+ }
+
+ /* Allocation of Circular Buffers */
+ priv->tx_buf = serial_buf_alloc();
+ if (priv->tx_buf == NULL) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->rx_buf = serial_buf_alloc();
+ if (priv->rx_buf == NULL) {
+ kfree(priv->tx_buf);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
+ INIT_WORK(&priv->rx_work, aircable_read, port);
+
+ usb_set_serial_port_data(serial->port[0], priv);
+
+ return 0;
+}
+
+static void aircable_shutdown(struct usb_serial *serial)
+{
+
+ struct usb_serial_port *port = serial->port[0];
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s", __FUNCTION__);
+
+ if (priv) {
+ serial_buf_free(priv->tx_buf);
+ serial_buf_free(priv->rx_buf);
+ usb_set_serial_port_data(port, NULL);
+ kfree(priv);
+ }
+}
+
+static int aircable_write_room(struct usb_serial_port *port)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ return serial_buf_data_avail(priv->tx_buf);
+}
+
+static int aircable_write(struct usb_serial_port *port,
+ const unsigned char *source, int count)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ int temp;
+
+ dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, source);
+
+ if (!count){
+ dbg("%s - write request of 0 bytes", __FUNCTION__);
+ return count;
+ }
+
+ temp = serial_buf_put(priv->tx_buf, source, count);
+
+ aircable_send(port);
+
+ if (count > AIRCABLE_BUF_SIZE)
+ count = AIRCABLE_BUF_SIZE;
+
+ return count;
+
+}
+
+static void aircable_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_serial_port *port = urb->context;
+ int result;
+
+ dbg("%s - urb->status: %d", __FUNCTION__ , urb->status);
+
+ /* This has been taken from cypress_m8.c cypress_write_int_callback */
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
+ port->write_urb_busy = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __FUNCTION__);
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting write urb, error %d\n",
+ __FUNCTION__, result);
+ else
+ return;
+ }
+
+ port->write_urb_busy = 0;
+
+ aircable_send(port);
+}
+
+static void aircable_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_serial_port *port = urb->context;
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned long no_packages, remaining, package_length, i;
+ int result, shift = 0;
+ unsigned char *temp;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ if (!port->open_count) {
+ dbg("%s - port is closed, exiting.", __FUNCTION__);
+ return;
+ }
+ if (urb->status == -EPROTO) {
+ dbg("%s - caught -EPROTO, resubmitting the urb",
+ __FUNCTION__);
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
+
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
+ return;
+ }
+ dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
+ return;
+ }
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ urb->actual_length,urb->transfer_buffer);
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ if (urb->actual_length <= 2) {
+ /* This is an incomplete package */
+ serial_buf_put(priv->rx_buf, urb->transfer_buffer,
+ urb->actual_length);
+ } else {
+ temp = urb->transfer_buffer;
+ if (temp[0] == RX_HEADER_0)
+ shift = HCI_HEADER_LENGTH;
+
+ remaining = urb->actual_length;
+ no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
+
+ if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
+ no_packages+=1;
+
+ for (i = 0; i < no_packages ;i++) {
+ if (remaining > (HCI_COMPLETE_FRAME))
+ package_length = HCI_COMPLETE_FRAME;
+ else
+ package_length = remaining;
+ remaining -= package_length;
+
+ serial_buf_put(priv->rx_buf,
+ urb->transfer_buffer + shift +
+ (HCI_COMPLETE_FRAME) * (i),
+ package_length - shift);
+ }
+ }
+ aircable_read(port);
+ }
+
+ /* Schedule the next read _if_ we are still open */
+ if (port->open_count) {
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
+
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
+ }
+
+ return;
+}
+
+/* Based on ftdi_sio.c throttle */
+static void aircable_throttle(struct usb_serial_port *port)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ priv->rx_flags |= THROTTLED;
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+}
+
+/* Based on ftdi_sio.c unthrottle */
+static void aircable_unthrottle(struct usb_serial_port *port)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ int actually_throttled;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
+ priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+
+ if (actually_throttled)
+ schedule_work(&priv->rx_work);
+}
+
+static struct usb_serial_driver aircable_device = {
+ .description = "aircable",
+ .id_table = id_table,
+ .num_ports = 1,
+ .attach = aircable_attach,
+ .probe = aircable_probe,
+ .shutdown = aircable_shutdown,
+ .write = aircable_write,
+ .write_room = aircable_write_room,
+ .write_bulk_callback = aircable_write_bulk_callback,
+ .read_bulk_callback = aircable_read_bulk_callback,
+ .throttle = aircable_throttle,
+ .unthrottle = aircable_unthrottle,
+};
+
+static struct usb_driver aircable_driver = {
+ .name = "aircable",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+};
+
+static int __init aircable_init (void)
+{
+ int retval;
+ retval = usb_serial_register(&aircable_device);
+ if (retval)
+ goto failed_serial_register;
+ retval = usb_register(&aircable_driver);
+ if (retval)
+ goto failed_usb_register;
+ return 0;
+
+failed_serial_register:
+ usb_serial_deregister(&aircable_device);
+failed_usb_register:
+ return retval;
+}
+
+static void __exit aircable_exit (void)
+{
+ usb_deregister(&aircable_driver);
+ usb_serial_deregister(&aircable_device);
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_init(aircable_init);
+module_exit(aircable_exit);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 94b9ba0ff87..6e1a84a858d 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -1,7 +1,7 @@
/*
* AirPrime CDMA Wireless Serial USB driver
*
- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
@@ -11,26 +11,264 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
- { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
- { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
+ { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
{ USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
+#define URB_TRANSFER_BUFFER_SIZE 4096
+#define NUM_READ_URBS 4
+#define NUM_WRITE_URBS 4
+#define NUM_BULK_EPS 3
+#define MAX_BULK_EPS 6
+
+/* if overridden by the user, then use their value for the size of the
+ * read and write urbs, and the number of endpoints */
+static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
+static int endpoints = NUM_BULK_EPS;
+static int debug;
+struct airprime_private {
+ spinlock_t lock;
+ int outstanding_urbs;
+ int throttled;
+ struct urb *read_urbp[NUM_READ_URBS];
+};
+
+static void airprime_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ struct tty_struct *tty;
+ int result;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (urb->status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, urb->status);
+ /* something happened, so free up the memory for this urb */
+ if (urb->transfer_buffer) {
+ kfree (urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ }
+ return;
+ }
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ tty_insert_flip_string (tty, data, urb->actual_length);
+ tty_flip_buffer_push (tty);
+ }
+
+ result = usb_submit_urb (urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
+ return;
+}
+
+static void airprime_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_serial_port *port = urb->context;
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* free up the transfer buffer, as usb_free_urb() does not do this */
+ kfree (urb->transfer_buffer);
+
+ if (urb->status)
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ spin_lock_irqsave(&priv->lock, flags);
+ --priv->outstanding_urbs;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ usb_serial_port_softint(port);
+}
+
+static int airprime_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ struct urb *urb;
+ char *buffer = NULL;
+ int i;
+ int result = 0;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* initialize our private data structure if it isn't already created */
+ if (!priv) {
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ result = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&priv->lock);
+ usb_set_serial_port_data(port, priv);
+ }
+
+ for (i = 0; i < NUM_READ_URBS; ++i) {
+ buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&port->dev, "%s - out of memory.\n",
+ __FUNCTION__);
+ result = -ENOMEM;
+ goto errout;
+ }
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&port->dev, "%s - no more urbs?\n",
+ __FUNCTION__);
+ result = -ENOMEM;
+ goto errout;
+ }
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ buffer, buffer_size,
+ airprime_read_bulk_callback, port);
+ result = usb_submit_urb(urb, GFP_KERNEL);
+ if (result) {
+ dev_err(&port->dev,
+ "%s - failed submitting read urb %d for port %d, error %d\n",
+ __FUNCTION__, i, port->number, result);
+ goto errout;
+ }
+ /* remember this urb so we can kill it when the port is closed */
+ priv->read_urbp[i] = urb;
+ }
+ goto out;
+
+ errout:
+ /* some error happened, cancel any submitted urbs and clean up anything that
+ got allocated successfully */
+
+ for ( ; i >= 0; --i) {
+ urb = priv->read_urbp[i];
+ if (urb) {
+ /* This urb was submitted successfully. So we have to
+ cancel it.
+ Unlinking the urb will invoke read_bulk_callback()
+ with an error status, so its transfer buffer will
+ be freed there */
+ if (usb_unlink_urb (urb) != -EINPROGRESS) {
+ /* comments in drivers/usb/core/urb.c say this
+ can only happen if the urb was never submitted,
+ or has completed already.
+ Either way we may have to free the transfer
+ buffer here. */
+ if (urb->transfer_buffer) {
+ kfree (urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ }
+ }
+ usb_free_urb (urb);
+ }
+ }
+
+ out:
+ return result;
+}
+
+static void airprime_close(struct usb_serial_port *port, struct file * filp)
+{
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ int i;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* killing the urb will invoke read_bulk_callback() with an error status,
+ so the transfer buffer will be freed there */
+ for (i = 0; i < NUM_READ_URBS; ++i) {
+ usb_kill_urb (priv->read_urbp[i]);
+ usb_free_urb (priv->read_urbp[i]);
+ }
+
+ /* free up private structure */
+ kfree (priv);
+ usb_set_serial_port_data(port, NULL);
+}
+
+static int airprime_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ struct urb *urb;
+ unsigned char *buffer;
+ unsigned long flags;
+ int status;
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->outstanding_urbs > NUM_WRITE_URBS) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ dbg("%s - write limit hit\n", __FUNCTION__);
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ buffer = kmalloc(count, GFP_ATOMIC);
+ if (!buffer) {
+ dev_err(&port->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ dev_err(&port->dev, "no more free urbs\n");
+ kfree (buffer);
+ return -ENOMEM;
+ }
+ memcpy (buffer, buf, count);
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ buffer, count,
+ airprime_write_bulk_callback, port);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&port->dev,
+ "%s - usb_submit_urb(write bulk) failed with status = %d\n",
+ __FUNCTION__, status);
+ count = status;
+ kfree (buffer);
+ } else {
+ spin_lock_irqsave(&priv->lock, flags);
+ ++priv->outstanding_urbs;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ /* we are done with this urb, so let the host driver
+ * really free it when it is finished with it */
+ usb_free_urb (urb);
+ return count;
+}
+
static struct usb_driver airprime_driver = {
.name = "airprime",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
+ .no_dynamic_id = 1,
};
static struct usb_serial_driver airprime_device = {
@@ -42,13 +280,17 @@ static struct usb_serial_driver airprime_device = {
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
- .num_ports = 1,
+ .open = airprime_open,
+ .close = airprime_close,
+ .write = airprime_write,
};
static int __init airprime_init(void)
{
int retval;
+ airprime_device.num_ports =
+ (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
retval = usb_serial_register(&airprime_device);
if (retval)
return retval;
@@ -60,6 +302,8 @@ static int __init airprime_init(void)
static void __exit airprime_exit(void)
{
+ dbg("%s", __FUNCTION__);
+
usb_deregister(&airprime_driver);
usb_serial_deregister(&airprime_device);
}
@@ -67,3 +311,10 @@ static void __exit airprime_exit(void)
module_init(airprime_init);
module_exit(airprime_exit);
MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled");
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+module_param(endpoints, int, 0);
+MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
diff --git a/drivers/usb/serial/anydata.c b/drivers/usb/serial/anydata.c
deleted file mode 100644
index 343f6f22822..00000000000
--- a/drivers/usb/serial/anydata.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * AnyData CDMA Serial USB driver
- *
- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/tty.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include "usb-serial.h"
-
-static struct usb_device_id id_table [] = {
- { USB_DEVICE(0x16d5, 0x6501) }, /* AirData CDMA device */
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-/* if overridden by the user, then use their value for the size of the
- * read and write urbs */
-static int buffer_size;
-static int debug;
-
-static struct usb_driver anydata_driver = {
- .name = "anydata",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
- .no_dynamic_id = 1,
-};
-
-static int anydata_open(struct usb_serial_port *port, struct file *filp)
-{
- char *buffer;
- int result = 0;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- if (buffer_size) {
- /* override the default buffer sizes */
- buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer) {
- dev_err(&port->dev, "%s - out of memory.\n",
- __FUNCTION__);
- return -ENOMEM;
- }
- kfree (port->read_urb->transfer_buffer);
- port->read_urb->transfer_buffer = buffer;
- port->read_urb->transfer_buffer_length = buffer_size;
-
- buffer = kmalloc(buffer_size, GFP_KERNEL);
- if (!buffer) {
- dev_err(&port->dev, "%s - out of memory.\n",
- __FUNCTION__);
- return -ENOMEM;
- }
- kfree (port->write_urb->transfer_buffer);
- port->write_urb->transfer_buffer = buffer;
- port->write_urb->transfer_buffer_length = buffer_size;
- port->bulk_out_size = buffer_size;
- }
-
- /* Start reading from the device */
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- usb_serial_generic_write_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __FUNCTION__, result);
-
- return result;
-}
-
-static struct usb_serial_driver anydata_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "anydata",
- },
- .id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 1,
- .open = anydata_open,
-};
-
-static int __init anydata_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&anydata_device);
- if (retval)
- return retval;
- retval = usb_register(&anydata_driver);
- if (retval)
- usb_serial_deregister(&anydata_device);
- return retval;
-}
-
-static void __exit anydata_exit(void)
-{
- usb_deregister(&anydata_driver);
- usb_serial_deregister(&anydata_device);
-}
-
-module_init(anydata_init);
-module_exit(anydata_exit);
-MODULE_LICENSE("GPL");
-
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 8dec796222a..ca52f12f0e2 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2006
+ * Simon Schulz (ark3116_driver <at> auctionant.de)
+ *
* ark3116
* - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547,
* productid=0x0232) (used in a datacable called KQ-U8A)
@@ -8,8 +11,6 @@
*
* - based on logs created by usbsnoopy
*
- * Author : Simon Schulz [ark3116_driver<AT>auctionant.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
@@ -21,7 +22,9 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+#include <asm/uaccess.h>
static int debug;
@@ -43,10 +46,10 @@ static inline void ARK3116_SND(struct usb_serial *serial, int seq,
{
int result;
result = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev,0),
+ usb_sndctrlpipe(serial->dev, 0),
request, requesttype, value, index,
- NULL,0x00, 1000);
- dbg("%03d > ok",seq);
+ NULL, 0x00, 1000);
+ dbg("%03d > ok", seq);
}
static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
@@ -56,27 +59,25 @@ static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
{
int result;
result = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev,0),
- request, requesttype, value, index,
- buf, 0x0000001, 1000);
+ usb_rcvctrlpipe(serial->dev, 0),
+ request, requesttype, value, index,
+ buf, 0x0000001, 1000);
if (result)
- dbg("%03d < %d bytes [0x%02X]",seq, result, buf[0]);
+ dbg("%03d < %d bytes [0x%02X]", seq, result, buf[0]);
else
dbg("%03d < 0 bytes", seq);
}
-
static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
__u8 request, __u8 requesttype,
__u16 value, __u16 index, char *buf)
{
usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev,0),
+ usb_rcvctrlpipe(serial->dev, 0),
request, requesttype, value, index,
buf, 0x0000001, 1000);
}
-
static int ark3116_attach(struct usb_serial *serial)
{
char *buf;
@@ -84,10 +85,10 @@ static int ark3116_attach(struct usb_serial *serial)
int i;
for (i = 0; i < serial->num_ports; ++i) {
- priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL);
+ priv = kmalloc(sizeof (struct ark3116_private), GFP_KERNEL);
if (!priv)
goto cleanup;
- memset (priv, 0x00, sizeof (struct ark3116_private));
+ memset(priv, 0x00, sizeof (struct ark3116_private));
spin_lock_init(&priv->lock);
usb_set_serial_port_data(serial->port[i], priv);
@@ -95,63 +96,62 @@ static int ark3116_attach(struct usb_serial *serial)
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
- dbg("error kmalloc -> out of mem ?");
+ dbg("error kmalloc -> out of mem?");
goto cleanup;
}
/* 3 */
- ARK3116_SND(serial, 3,0xFE,0x40,0x0008,0x0002);
- ARK3116_SND(serial, 4,0xFE,0x40,0x0008,0x0001);
- ARK3116_SND(serial, 5,0xFE,0x40,0x0000,0x0008);
- ARK3116_SND(serial, 6,0xFE,0x40,0x0000,0x000B);
+ ARK3116_SND(serial, 3, 0xFE, 0x40, 0x0008, 0x0002);
+ ARK3116_SND(serial, 4, 0xFE, 0x40, 0x0008, 0x0001);
+ ARK3116_SND(serial, 5, 0xFE, 0x40, 0x0000, 0x0008);
+ ARK3116_SND(serial, 6, 0xFE, 0x40, 0x0000, 0x000B);
/* <-- seq7 */
- ARK3116_RCV(serial, 7,0xFE,0xC0,0x0000,0x0003, 0x00, buf);
- ARK3116_SND(serial, 8,0xFE,0x40,0x0080,0x0003);
- ARK3116_SND(serial, 9,0xFE,0x40,0x001A,0x0000);
- ARK3116_SND(serial,10,0xFE,0x40,0x0000,0x0001);
- ARK3116_SND(serial,11,0xFE,0x40,0x0000,0x0003);
+ ARK3116_RCV(serial, 7, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
+ ARK3116_SND(serial, 8, 0xFE, 0x40, 0x0080, 0x0003);
+ ARK3116_SND(serial, 9, 0xFE, 0x40, 0x001A, 0x0000);
+ ARK3116_SND(serial, 10, 0xFE, 0x40, 0x0000, 0x0001);
+ ARK3116_SND(serial, 11, 0xFE, 0x40, 0x0000, 0x0003);
/* <-- seq12 */
- ARK3116_RCV(serial,12,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
- ARK3116_SND(serial,13,0xFE,0x40,0x0000,0x0004);
+ ARK3116_RCV(serial, 12, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
+ ARK3116_SND(serial, 13, 0xFE, 0x40, 0x0000, 0x0004);
/* 14 */
- ARK3116_RCV(serial,14,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
- ARK3116_SND(serial,15,0xFE,0x40,0x0000,0x0004);
+ ARK3116_RCV(serial, 14, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
+ ARK3116_SND(serial, 15, 0xFE, 0x40, 0x0000, 0x0004);
/* 16 */
- ARK3116_RCV(serial,16,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ ARK3116_RCV(serial, 16, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
/* --> seq17 */
- ARK3116_SND(serial,17,0xFE,0x40,0x0001,0x0004);
+ ARK3116_SND(serial, 17, 0xFE, 0x40, 0x0001, 0x0004);
/* <-- seq18 */
- ARK3116_RCV(serial,18,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
+ ARK3116_RCV(serial, 18, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
/* --> seq19 */
- ARK3116_SND(serial,19,0xFE,0x40,0x0003,0x0004);
-
+ ARK3116_SND(serial, 19, 0xFE, 0x40, 0x0003, 0x0004);
/* <-- seq20 */
- /* seems like serial port status info (RTS, CTS,...) */
- /* returns modem control line status ?! */
- ARK3116_RCV(serial,20,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
-
- /* set 9600 baud & do some init ?! */
- ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
- ARK3116_SND(serial,148,0xFE,0x40,0x0038,0x0000);
- ARK3116_SND(serial,149,0xFE,0x40,0x0001,0x0001);
- ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
- ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
- ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
- ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
- ARK3116_SND(serial,154,0xFE,0x40,0x0003,0x0003);
+ /* seems like serial port status info (RTS, CTS, ...) */
+ /* returns modem control line status?! */
+ ARK3116_RCV(serial, 20, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
+
+ /* set 9600 baud & do some init?! */
+ ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
+ ARK3116_SND(serial, 148, 0xFE, 0x40, 0x0038, 0x0000);
+ ARK3116_SND(serial, 149, 0xFE, 0x40, 0x0001, 0x0001);
+ ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
+ ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
+ ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
+ ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
+ ARK3116_SND(serial, 154, 0xFE, 0x40, 0x0003, 0x0003);
kfree(buf);
- return(0);
+ return 0;
cleanup:
- for (--i; i>=0; --i)
+ for (--i; i >= 0; --i)
usb_set_serial_port_data(serial->port[i], NULL);
return -ENOMEM;
}
@@ -180,7 +180,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
- port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ port->tty->termios->c_cflag = B9600 | CS8
+ | CREAD | HUPCL | CLOCAL;
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -204,8 +205,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
}
/* set data bit count (8/7/6/5) */
- if (cflag & CSIZE){
- switch (cflag & CSIZE){
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
case CS5:
config |= 0x00;
dbg("setting CS5");
@@ -219,7 +220,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("setting CS7");
break;
default:
- err ("CSIZE was set but not CS5-CS8, using CS8!");
+ err("CSIZE was set but not CS5-CS8, using CS8!");
+ /* fall through */
case CS8:
config |= 0x03;
dbg("setting CS8");
@@ -227,8 +229,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
}
}
- /* set parity (NONE,EVEN,ODD) */
- if (cflag & PARENB){
+ /* set parity (NONE/EVEN/ODD) */
+ if (cflag & PARENB) {
if (cflag & PARODD) {
config |= 0x08;
dbg("setting parity to ODD");
@@ -240,20 +242,19 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("setting parity to NONE");
}
- /* SET STOPBIT (1/2) */
+ /* set stop bit (1/2) */
if (cflag & CSTOPB) {
config |= 0x04;
- dbg ("setting 2 stop bits");
+ dbg("setting 2 stop bits");
} else {
- dbg ("setting 1 stop bit");
+ dbg("setting 1 stop bit");
}
-
- /* set baudrate: */
+ /* set baudrate */
baud = 0;
- switch (cflag & CBAUD){
+ switch (cflag & CBAUD) {
case B0:
- err("can't set 0baud, using 9600 instead");
+ err("can't set 0 baud, using 9600 instead");
break;
case B75: baud = 75; break;
case B150: baud = 150; break;
@@ -285,38 +286,40 @@ static void ark3116_set_termios(struct usb_serial_port *port,
*/
if (baud == 460800)
/* strange, for 460800 the formula is wrong
- * (dont use round(), then 9600baud is wrong) */
+ * if using round() then 9600baud is wrong) */
ark3116_baud = 7;
else
ark3116_baud = 3000000 / baud;
/* ? */
- ARK3116_RCV(serial,0,0xFE,0xC0,0x0000,0x0003, 0x03, buf);
+ ARK3116_RCV(serial, 0, 0xFE, 0xC0, 0x0000, 0x0003, 0x03, buf);
+
/* offset = buf[0]; */
/* offset = 0x03; */
- /* dbg("using 0x%04X as target for 0x0003:",0x0080+offset); */
-
+ /* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */
/* set baudrate */
- dbg("setting baudrate to %d (->reg=%d)",baud,ark3116_baud);
- ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
- ARK3116_SND(serial,148,0xFE,0x40,(ark3116_baud & 0x00FF) ,0x0000);
- ARK3116_SND(serial,149,0xFE,0x40,(ark3116_baud & 0xFF00)>>8,0x0001);
- ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
+ dbg("setting baudrate to %d (->reg=%d)", baud, ark3116_baud);
+ ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
+ ARK3116_SND(serial, 148, 0xFE, 0x40,
+ (ark3116_baud & 0x00FF), 0x0000);
+ ARK3116_SND(serial, 149, 0xFE, 0x40,
+ (ark3116_baud & 0xFF00) >> 8, 0x0001);
+ ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
/* ? */
- ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
- ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
+ ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
+ ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
/* set data bit count, stop bit count & parity: */
dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config);
- ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
- ARK3116_SND(serial,154,0xFE,0x40,config,0x0003);
+ ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
+ ARK3116_SND(serial, 154, 0xFE, 0x40, config, 0x0003);
if (cflag & CRTSCTS)
- dbg("CRTSCTS not supported by chipset ?!");
+ dbg("CRTSCTS not supported by chipset?!");
- /* TEST ARK3116_SND(154,0xFE,0x40,0xFFFF, 0x0006); */
+ /* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
kfree(buf);
return;
@@ -329,11 +332,11 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
char *buf;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
- dbg("error kmalloc -> out of mem ?");
+ dbg("error kmalloc -> out of mem?");
return -ENOMEM;
}
@@ -342,44 +345,68 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
return result;
/* open */
- ARK3116_RCV(serial,111,0xFE,0xC0,0x0000,0x0003, 0x02, buf);
+ ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
- ARK3116_SND(serial,112,0xFE,0x40,0x0082,0x0003);
- ARK3116_SND(serial,113,0xFE,0x40,0x001A,0x0000);
- ARK3116_SND(serial,114,0xFE,0x40,0x0000,0x0001);
- ARK3116_SND(serial,115,0xFE,0x40,0x0002,0x0003);
+ ARK3116_SND(serial, 112, 0xFE, 0x40, 0x0082, 0x0003);
+ ARK3116_SND(serial, 113, 0xFE, 0x40, 0x001A, 0x0000);
+ ARK3116_SND(serial, 114, 0xFE, 0x40, 0x0000, 0x0001);
+ ARK3116_SND(serial, 115, 0xFE, 0x40, 0x0002, 0x0003);
- ARK3116_RCV(serial,116,0xFE,0xC0,0x0000,0x0004, 0x03, buf);
- ARK3116_SND(serial,117,0xFE,0x40,0x0002,0x0004);
+ ARK3116_RCV(serial, 116, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
+ ARK3116_SND(serial, 117, 0xFE, 0x40, 0x0002, 0x0004);
- ARK3116_RCV(serial,118,0xFE,0xC0,0x0000,0x0004, 0x02, buf);
- ARK3116_SND(serial,119,0xFE,0x40,0x0000,0x0004);
+ ARK3116_RCV(serial, 118, 0xFE, 0xC0, 0x0000, 0x0004, 0x02, buf);
+ ARK3116_SND(serial, 119, 0xFE, 0x40, 0x0000, 0x0004);
- ARK3116_RCV(serial,120,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ ARK3116_RCV(serial, 120, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
- ARK3116_SND(serial,121,0xFE,0x40,0x0001,0x0004);
+ ARK3116_SND(serial, 121, 0xFE, 0x40, 0x0001, 0x0004);
- ARK3116_RCV(serial,122,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
+ ARK3116_RCV(serial, 122, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
- ARK3116_SND(serial,123,0xFE,0x40,0x0003,0x0004);
+ ARK3116_SND(serial, 123, 0xFE, 0x40, 0x0003, 0x0004);
- /* returns different values (control lines ?!) */
- ARK3116_RCV(serial,124,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
+ /* returns different values (control lines?!) */
+ ARK3116_RCV(serial, 124, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
- /* initialise termios: */
+ /* initialise termios */
if (port->tty)
ark3116_set_termios(port, &tmp_termios);
kfree(buf);
return result;
-
}
static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
- dbg("ioctl not supported yet...");
+ struct serial_struct serstruct;
+ void __user *user_arg = (void __user *)arg;
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ /* XXX: Some of these values are probably wrong. */
+ memset(&serstruct, 0, sizeof (serstruct));
+ serstruct.type = PORT_16654;
+ serstruct.line = port->serial->minor;
+ serstruct.port = port->number;
+ serstruct.custom_divisor = 0;
+ serstruct.baud_base = 460800;
+
+ if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
+ return -EFAULT;
+
+ return 0;
+ case TIOCSSERIAL:
+ if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
+ return -EFAULT;
+ return 0;
+ default:
+ dbg("%s cmd 0x%04x not supported", __FUNCTION__, cmd);
+ break;
+ }
+
return -ENOIOCTLCMD;
}
@@ -389,7 +416,7 @@ static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file)
char *buf;
char temp;
- /* seems like serial port status info (RTS, CTS,...) is stored
+ /* seems like serial port status info (RTS, CTS, ...) is stored
* in reg(?) 0x0006
* pcb connection point 11 = GND -> sets bit4 of response
* pcb connection point 7 = GND -> sets bit6 of response
@@ -401,16 +428,16 @@ static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file)
return -ENOMEM;
}
- /* read register: */
- ARK3116_RCV_QUIET(serial,0xFE,0xC0,0x0000,0x0006,buf);
+ /* read register */
+ ARK3116_RCV_QUIET(serial, 0xFE, 0xC0, 0x0000, 0x0006, buf);
temp = buf[0];
kfree(buf);
- /* i do not really know if bit4=CTS and bit6=DSR... was just a
- * quick guess !!
+ /* i do not really know if bit4=CTS and bit6=DSR... just a
+ * quick guess!
*/
- return (temp & (1<<4) ? TIOCM_CTS : 0) |
- (temp & (1<<6) ? TIOCM_DSR : 0);
+ return (temp & (1<<4) ? TIOCM_CTS : 0)
+ | (temp & (1<<6) ? TIOCM_DSR : 0);
}
static struct usb_driver ark3116_driver = {
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 4144777ea18..70ece9e01ce 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -63,7 +63,6 @@
* UsbSnoop on Windows2000 and from examining the other USB drivers.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -75,7 +74,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "belkin_sa.h"
static int debug;
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index e9f9f4bafa1..6542f220468 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -8,13 +8,12 @@
* 2 as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
index f3404e10afb..3a9073dbfe6 100644
--- a/drivers/usb/serial/console.c
+++ b/drivers/usb/serial/console.c
@@ -11,18 +11,16 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
static int debug;
-#include "usb-serial.h"
-
struct usbcons_info {
int magic;
int break_flag;
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index f8c0cb28773..486c7411b9a 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -27,7 +26,7 @@
#include <linux/moduleparam.h>
#include <linux/usb.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/*
* Version Information
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 1fd5c5a9f2e..d954ec34b01 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -28,7 +28,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -40,7 +39,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#define CYBERJACK_LOCAL_BUF_SIZE 32
@@ -215,14 +214,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
return (0);
}
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
spin_lock_irqsave(&priv->lock, flags);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 5de76efe1b3..e1173c1aee3 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -48,7 +48,6 @@
/* Code originates and was built up from ftdi_sio, belkin, pl2303 and others. */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -60,11 +59,11 @@
#include <linux/moduleparam.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <linux/serial.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
#include "cypress_m8.h"
@@ -130,6 +129,9 @@ struct cypress_private {
int cmd_ctrl; /* always set this to 1 before issuing a command */
struct cypress_buf *buf; /* write buffer */
int write_urb_in_use; /* write urb in use indicator */
+ int write_urb_interval; /* interval to use for write urb */
+ int read_urb_interval; /* interval to use for read urb */
+ int comm_is_ok; /* true if communication is (still) ok */
int termios_initialized;
__u8 line_control; /* holds dtr / rts value */
__u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
@@ -169,6 +171,7 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
static int cypress_chars_in_buffer (struct usb_serial_port *port);
static void cypress_throttle (struct usb_serial_port *port);
static void cypress_unthrottle (struct usb_serial_port *port);
+static void cypress_set_dead (struct usb_serial_port *port);
static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs);
static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs);
/* baud helper functions */
@@ -289,6 +292,9 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
priv = usb_get_serial_port_data(port);
+ if (!priv->comm_is_ok)
+ return -ENODEV;
+
switch(cypress_request_type) {
case CYPRESS_SET_CONFIG:
@@ -366,13 +372,12 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
if (tries++ >= 3)
break;
- if (retval == EPIPE)
- usb_clear_halt(port->serial->dev, 0x00);
- } while (retval != 8 && retval != ENODEV);
+ } while (retval != 8 && retval != -ENODEV);
- if (retval != 8)
+ if (retval != 8) {
err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
- else {
+ cypress_set_dead(port);
+ } else {
spin_lock_irqsave(&priv->lock, flags);
priv->baud_rate = new_baudrate;
priv->cbr_mask = baud_mask;
@@ -393,12 +398,11 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
if (tries++ >= 3)
break;
- if (retval == EPIPE)
- usb_clear_halt(port->serial->dev, 0x00);
- } while (retval != 5 && retval != ENODEV);
+ } while (retval != 5 && retval != -ENODEV);
if (retval != 5) {
err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval);
+ cypress_set_dead(port);
return retval;
} else {
spin_lock_irqsave(&priv->lock, flags);
@@ -420,6 +424,24 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
} /* cypress_serial_control */
+static void cypress_set_dead(struct usb_serial_port *port)
+{
+ struct cypress_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->comm_is_ok) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+ priv->comm_is_ok = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ err("cypress_m8 suspending failing port %d - interval might be too short",
+ port->number);
+}
+
+
/* given a baud mask, it will return integer baud on success */
static int mask_to_rate (unsigned mask)
{
@@ -473,13 +495,15 @@ static unsigned rate_to_mask (int rate)
static int generic_startup (struct usb_serial *serial)
{
struct cypress_private *priv;
+ struct usb_serial_port *port = serial->port[0];
- dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->comm_is_ok = !0;
spin_lock_init(&priv->lock);
priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
if (priv->buf == NULL) {
@@ -490,13 +514,24 @@ static int generic_startup (struct usb_serial *serial)
usb_reset_configuration (serial->dev);
- interval = 1;
priv->cmd_ctrl = 0;
priv->line_control = 0;
priv->termios_initialized = 0;
priv->rx_flags = 0;
priv->cbr_mask = B300;
- usb_set_serial_port_data(serial->port[0], priv);
+ if (interval > 0) {
+ priv->write_urb_interval = interval;
+ priv->read_urb_interval = interval;
+ dbg("%s - port %d read & write intervals forced to %d",
+ __FUNCTION__,port->number,interval);
+ } else {
+ priv->write_urb_interval = port->interrupt_out_urb->interval;
+ priv->read_urb_interval = port->interrupt_in_urb->interval;
+ dbg("%s - port %d intervals: read=%d write=%d",
+ __FUNCTION__,port->number,
+ priv->read_urb_interval,priv->write_urb_interval);
+ }
+ usb_set_serial_port_data(port, priv);
return 0;
}
@@ -586,6 +621,9 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number);
+ if (!priv->comm_is_ok)
+ return -EIO;
+
/* clear halts before open */
usb_clear_halt(serial->dev, 0x81);
usb_clear_halt(serial->dev, 0x02);
@@ -625,11 +663,12 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
- cypress_read_int_callback, port, interval);
+ cypress_read_int_callback, port, priv->read_urb_interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result){
dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ cypress_set_dead(port);
}
return result;
@@ -734,6 +773,9 @@ static void cypress_send(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
+ if (!priv->comm_is_ok)
+ return;
+
dbg("%s - port %d", __FUNCTION__, port->number);
dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
@@ -807,14 +849,16 @@ send:
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
port->interrupt_out_urb->transfer_buffer);
- port->interrupt_out_urb->transfer_buffer_length = actual_size;
- port->interrupt_out_urb->dev = port->serial->dev;
- port->interrupt_out_urb->interval = interval;
+ usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
+ usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
+ port->interrupt_out_buffer, port->interrupt_out_size,
+ cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
result);
priv->write_urb_in_use = 0;
+ cypress_set_dead(port);
}
spin_lock_irqsave(&priv->lock, flags);
@@ -1215,13 +1259,18 @@ static void cypress_unthrottle (struct usb_serial_port *port)
priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags);
+ if (!priv->comm_is_ok)
+ return;
+
if (actually_throttled) {
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, "
"error %d\n", __FUNCTION__, result);
+ cypress_set_dead(port);
+ }
}
}
@@ -1241,9 +1290,22 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read status received: %d", __FUNCTION__,
- urb->status);
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* precursor to disconnect so just go away */
+ return;
+ case -EPIPE:
+ usb_clear_halt(port->serial->dev,0x81);
+ break;
+ default:
+ /* something ugly is going on... */
+ dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
+ __FUNCTION__,urb->status);
+ cypress_set_dead(port);
return;
}
@@ -1344,18 +1406,20 @@ continue_read:
/* Continue trying to always read... unless the port has closed. */
- if (port->open_count > 0) {
+ if (port->open_count > 0 && priv->comm_is_ok) {
usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
usb_rcvintpipe(port->serial->dev,
port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer,
port->interrupt_in_urb->transfer_buffer_length,
- cypress_read_int_callback, port, interval);
+ cypress_read_int_callback, port, priv->read_urb_interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&urb->dev->dev, "%s - failed resubmitting "
"read urb, error %d\n", __FUNCTION__,
result);
+ cypress_set_dead(port);
+ }
}
return;
@@ -1381,20 +1445,26 @@ static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
priv->write_urb_in_use = 0;
return;
- case -EPIPE: /* no break needed */
+ case -EPIPE: /* no break needed; clear halt and resubmit */
+ if (!priv->comm_is_ok)
+ break;
usb_clear_halt(port->serial->dev, 0x02);
- default:
/* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __FUNCTION__);
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
port->interrupt_out_urb->transfer_buffer_length = 1;
port->interrupt_out_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
- __FUNCTION__, result);
- else
+ if (!result)
return;
+ dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
+ __FUNCTION__, result);
+ cypress_set_dead(port);
+ break;
+ default:
+ dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
+ __FUNCTION__,urb->status);
+ cypress_set_dead(port);
+ break;
}
priv->write_urb_in_use = 0;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index b3f776a90c9..9b225183fc7 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -233,7 +233,6 @@
* $Id: digi_acceleport.c,v 1.80.1.2 2000/11/02 05:45:08 root Exp $
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -247,7 +246,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/wait.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/* Defines */
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index afca1eae5fb..daafe405d86 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -51,7 +51,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -63,7 +62,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c
index 1e419c8d739..5169c2d154a 100644
--- a/drivers/usb/serial/ezusb.c
+++ b/drivers/usb/serial/ezusb.c
@@ -8,7 +8,6 @@
* 2 as published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -16,7 +15,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/* EZ-USB Control and Status Register. Bit 0 controls 8051 reset */
#define CPUCS_REG 0x7F92
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index b2bfea7c815..e774a27c6c9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -245,7 +245,6 @@
/* to talk to the device */
/* Thanx to gkh and the rest of the usb dev group for all code I have assimilated :-) */
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -258,7 +257,7 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
#include <linux/serial.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "ftdi_sio.h"
/*
@@ -307,6 +306,8 @@ static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
static struct usb_device_id id_table_combined [] = {
+ { USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
@@ -314,6 +315,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
{ USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
@@ -337,10 +339,12 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
@@ -501,6 +505,12 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(PAPOUCH_VID, PAPOUCH_TMU_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACG_HFDUAL_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_YEI_SERVOCENTER31_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
+ { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -549,11 +559,17 @@ struct ftdi_private {
spinlock_t rx_lock; /* spinlock for receive state */
struct work_struct rx_work;
int rx_processed;
+ unsigned long rx_bytes;
__u16 interface; /* FT2232C port interface (0 for FT232/245) */
int force_baud; /* if non-zero, force the baud rate to this value */
int force_rtscts; /* if non-zero, force RTS-CTS to always be enabled */
+
+ spinlock_t tx_lock; /* spinlock for transmit state */
+ unsigned long tx_bytes;
+ unsigned long tx_outstanding_bytes;
+ unsigned long tx_outstanding_urbs;
};
/* Used for TIOCMIWAIT */
@@ -627,6 +643,9 @@ static struct usb_serial_driver ftdi_sio_device = {
#define HIGH 1
#define LOW 0
+/* number of outstanding urbs to prevent userspace DoS from happening */
+#define URB_UPPER_LIMIT 42
+
/*
* ***************************************************************************
* Utlity functions
@@ -1086,25 +1105,29 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);
static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
-static void create_sysfs_attrs(struct usb_serial *serial)
-{
+static int create_sysfs_attrs(struct usb_serial *serial)
+{
struct ftdi_private *priv;
struct usb_device *udev;
+ int retval = 0;
dbg("%s",__FUNCTION__);
-
+
priv = usb_get_serial_port_data(serial->port[0]);
udev = serial->dev;
-
+
/* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */
if (priv->chip_type != SIO) {
dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
- device_create_file(&udev->dev, &dev_attr_event_char);
- if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
- device_create_file(&udev->dev, &dev_attr_latency_timer);
+ retval = device_create_file(&udev->dev, &dev_attr_event_char);
+ if ((!retval) &&
+ (priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
+ retval = device_create_file(&udev->dev,
+ &dev_attr_latency_timer);
}
}
+ return retval;
}
static void remove_sysfs_attrs(struct usb_serial *serial)
@@ -1147,7 +1170,8 @@ static int ftdi_sio_attach (struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv;
struct ftdi_sio_quirk *quirk;
-
+ int retval;
+
dbg("%s",__FUNCTION__);
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
@@ -1157,6 +1181,7 @@ static int ftdi_sio_attach (struct usb_serial *serial)
}
spin_lock_init(&priv->rx_lock);
+ spin_lock_init(&priv->tx_lock);
init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather
than queue a task to deliver them */
@@ -1187,15 +1212,18 @@ static int ftdi_sio_attach (struct usb_serial *serial)
usb_set_serial_port_data(serial->port[0], priv);
ftdi_determine_type (serial->port[0]);
- create_sysfs_attrs(serial);
+ retval = create_sysfs_attrs(serial);
+ if (retval)
+ dev_err(&serial->dev->dev, "Error creating sysfs files, "
+ "continuing\n");
/* Check for device requiring special set up. */
quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
if (quirk && quirk->setup) {
quirk->setup(serial);
}
-
- return (0);
+
+ return 0;
} /* ftdi_sio_attach */
@@ -1271,6 +1299,13 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
dbg("%s", __FUNCTION__);
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ priv->tx_bytes = 0;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ priv->rx_bytes = 0;
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+
if (port->tty)
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -1373,6 +1408,7 @@ static int ftdi_write (struct usb_serial_port *port,
int data_offset ; /* will be 1 for the SIO and 0 otherwise */
int status;
int transfer_size;
+ unsigned long flags;
dbg("%s port %d, %d bytes", __FUNCTION__, port->number, count);
@@ -1380,6 +1416,13 @@ static int ftdi_write (struct usb_serial_port *port,
dbg("write request of 0 bytes");
return 0;
}
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ dbg("%s - write limit hit\n", __FUNCTION__);
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
@@ -1446,6 +1489,12 @@ static int ftdi_write (struct usb_serial_port *port,
err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
count = status;
kfree (buffer);
+ } else {
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ ++priv->tx_outstanding_urbs;
+ priv->tx_outstanding_bytes += count;
+ priv->tx_bytes += count;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
}
/* we are done with this urb, so let the host driver
@@ -1461,7 +1510,11 @@ static int ftdi_write (struct usb_serial_port *port,
static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
+ unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+ struct ftdi_private *priv;
+ int data_offset; /* will be 1 for the SIO and 0 otherwise */
+ unsigned long countback;
/* free up the transfer buffer, as usb_free_urb() does not do this */
kfree (urb->transfer_buffer);
@@ -1473,34 +1526,67 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
+ priv = usb_get_serial_port_data(port);
+ if (!priv) {
+ dbg("%s - bad port private data pointer - exiting", __FUNCTION__);
+ return;
+ }
+ /* account for transferred data */
+ countback = urb->actual_length;
+ data_offset = priv->write_offset;
+ if (data_offset > 0) {
+ /* Subtract the control bytes */
+ countback -= (data_offset * ((countback + (PKTSZ - 1)) / PKTSZ));
+ }
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ --priv->tx_outstanding_urbs;
+ priv->tx_outstanding_bytes -= countback;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+
usb_serial_port_softint(port);
} /* ftdi_write_bulk_callback */
static int ftdi_write_room( struct usb_serial_port *port )
{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int room;
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
- /*
- * We really can take anything the user throws at us
- * but let's pick a nice big number to tell the tty
- * layer that we have lots of free space
- */
- return 2048;
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ if (priv->tx_outstanding_urbs < URB_UPPER_LIMIT) {
+ /*
+ * We really can take anything the user throws at us
+ * but let's pick a nice big number to tell the tty
+ * layer that we have lots of free space
+ */
+ room = 2048;
+ } else {
+ room = 0;
+ }
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ return room;
} /* ftdi_write_room */
static int ftdi_chars_in_buffer (struct usb_serial_port *port)
{ /* ftdi_chars_in_buffer */
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ int buffered;
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
- /*
- * We can't really account for how much data we
- * have sent out, but hasn't made it through to the
- * device, so just tell the tty layer that everything
- * is flushed.
- */
- return 0;
+ spin_lock_irqsave(&priv->tx_lock, flags);
+ buffered = (int)priv->tx_outstanding_bytes;
+ spin_unlock_irqrestore(&priv->tx_lock, flags);
+ if (buffered < 0) {
+ err("%s outstanding tx bytes is negative!", __FUNCTION__);
+ buffered = 0;
+ }
+ return buffered;
} /* ftdi_chars_in_buffer */
@@ -1510,6 +1596,8 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty;
struct ftdi_private *priv;
+ unsigned long countread;
+ unsigned long flags;
if (urb->number_of_packets > 0) {
err("%s transfer_buffer_length %d actual_length %d number of packets %d",__FUNCTION__,
@@ -1544,6 +1632,13 @@ static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
+ /* count data bytes, but not status bytes */
+ countread = urb->actual_length;
+ countread -= 2 * ((countread + (PKTSZ - 1)) / PKTSZ);
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ priv->rx_bytes += countread;
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+
ftdi_process_read(port);
} /* ftdi_read_bulk_callback */
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 6ab2ac845bd..f0edb87d2dd 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -32,10 +32,19 @@
#define FTDI_NF_RIC_PID 0x0001 /* Product Id */
+/* www.canusb.com Lawicel CANUSB device */
+#define FTDI_CANUSB_PID 0xFFA8 /* Product Id */
+
+/* AlphaMicro Components AMC-232USB01 device */
+#define FTDI_AMC232_PID 0xFF00 /* Product Id */
+
/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
#define FTDI_ACTZWAVE_PID 0xF2D0
+/* www.starting-point-systems.com µChameleon device */
+#define FTDI_MICRO_CHAMELEON_PID 0xCAA0 /* Product Id */
+
/* www.irtrans.de device */
#define FTDI_IRTRANS_PID 0xFC60 /* Product Id */
@@ -102,6 +111,7 @@
#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
+#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
@@ -179,6 +189,10 @@
/* http://home.earthlink.net/~jrhees/USBUIRT/index.htm */
#define FTDI_USB_UIRT_PID 0xF850 /* Product Id */
+/* TNC-X USB-to-packet-radio adapter, versions prior to 3.0 (DLP module) */
+
+#define FTDI_TNC_X_PID 0xEBE0
+
/*
* ELV USB devices submitted by Christian Abt of ELV (www.elv.de).
* All of these devices use FTDI's vendor ID (0x0403).
@@ -442,6 +456,32 @@
*/
#define FTDI_YEI_SERVOCENTER31_PID 0xE050 /* YEI ServoCenter3.1 USB */
+/*
+ * ThorLabs USB motor drivers
+ */
+#define FTDI_THORLABS_PID 0xfaf0 /* ThorLabs USB motor drivers */
+
+/*
+ * Testo products (http://www.testo.com/)
+ * Submitted by Colin Leroy
+ */
+#define TESTO_VID 0x128D
+#define TESTO_USB_INTERFACE_PID 0x0001
+
+/*
+ * Gamma Scout (http://gamma-scout.com/). Submitted by rsc@runtux.com.
+ */
+#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
+
+/*
+ * Tactrix OpenPort (ECU) devices.
+ * OpenPort 1.3M submitted by Donour Sizemore.
+ * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
+ */
+#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
+#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
+#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 803721b97e2..77b977206a8 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -13,7 +13,7 @@
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1404, 0xcddc) },
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 04767759cf8..4b1196a8b09 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1,7 +1,7 @@
/*
* Garmin GPS driver
*
- * Copyright (C) 2004 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006 Hermann Kneissel herkne@users.sourceforge.net
*
* The latest version of the driver can be found at
* http://sourceforge.net/projects/garmin-gps/
@@ -23,7 +23,6 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -36,6 +35,9 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+#include <linux/version.h>
/* the mode to be set when the port ist opened */
static int initial_mode = 1;
@@ -43,8 +45,6 @@ static int initial_mode = 1;
/* debug flag */
static int debug = 0;
-#include "usb-serial.h"
-
#define GARMIN_VENDOR_ID 0x091E
/*
@@ -52,7 +52,7 @@ static int debug = 0;
*/
#define VERSION_MAJOR 0
-#define VERSION_MINOR 23
+#define VERSION_MINOR 28
#define _STR(s) #s
#define _DRIVER_VERSION(a,b) "v" _STR(a) "." _STR(b)
@@ -166,7 +166,8 @@ struct garmin_data {
#define FLAGS_SESSION_REPLY1_SEEN 0x0080
#define FLAGS_SESSION_REPLY2_SEEN 0x0040
#define FLAGS_BULK_IN_ACTIVE 0x0020
-#define FLAGS_THROTTLED 0x0010
+#define FLAGS_BULK_IN_RESTART 0x0010
+#define FLAGS_THROTTLED 0x0008
#define CLEAR_HALT_REQUIRED 0x0001
#define FLAGS_QUEUING 0x0100
@@ -226,7 +227,7 @@ static struct usb_driver garmin_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
+ .no_dynamic_id = 1,
};
@@ -272,7 +273,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
static void send_to_tty(struct usb_serial_port *port,
- char *data, unsigned int actual_length)
+ char *data, unsigned int actual_length)
{
struct tty_struct *tty = port->tty;
@@ -296,15 +297,15 @@ static void send_to_tty(struct usb_serial_port *port,
* queue a received (usb-)packet for later processing
*/
static int pkt_add(struct garmin_data * garmin_data_p,
- unsigned char *data, unsigned int data_length)
+ unsigned char *data, unsigned int data_length)
{
+ int state = 0;
int result = 0;
unsigned long flags;
struct garmin_packet *pkt;
/* process only packets containg data ... */
if (data_length) {
- garmin_data_p->flags |= FLAGS_QUEUING;
pkt = kmalloc(sizeof(struct garmin_packet)+data_length,
GFP_ATOMIC);
if (pkt == NULL) {
@@ -315,14 +316,16 @@ static int pkt_add(struct garmin_data * garmin_data_p,
memcpy(pkt->data, data, data_length);
spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_QUEUING;
result = list_empty(&garmin_data_p->pktlist);
pkt->seq = garmin_data_p->seq_counter++;
list_add_tail(&pkt->list, &garmin_data_p->pktlist);
+ state = garmin_data_p->state;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* in serial mode, if someone is waiting for data from
the device, iconvert and send the next packet to tty. */
- if (result && (garmin_data_p->state == STATE_GSP_WAIT_DATA)) {
+ if (result && (state == STATE_GSP_WAIT_DATA)) {
gsp_next_packet(garmin_data_p);
}
}
@@ -372,9 +375,9 @@ static void pkt_clear(struct garmin_data * garmin_data_p)
static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
{
__u8 pkt[10];
- __u8 cksum = 0;
- __u8 *ptr = pkt;
- unsigned l = 0;
+ __u8 cksum = 0;
+ __u8 *ptr = pkt;
+ unsigned l = 0;
dbg("%s - pkt-id: 0x%X.", __FUNCTION__, 0xFF & pkt_id);
@@ -418,7 +421,7 @@ static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
{
const __u8* recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET;
- __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
+ __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
int cksum = 0;
int n = 0;
@@ -449,11 +452,11 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
n++;
}
- if ((0xff & (cksum + *recpkt)) != 0) {
- dbg("%s - invalid checksum, expected %02x, got %02x",
- __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
- return -EINVPKT;
- }
+ if ((0xff & (cksum + *recpkt)) != 0) {
+ dbg("%s - invalid checksum, expected %02x, got %02x",
+ __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
+ return -EINVPKT;
+ }
usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL);
usbdata[1] = __cpu_to_le32(pktid);
@@ -493,20 +496,28 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
*/
static int gsp_receive(struct garmin_data * garmin_data_p,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
int offs = 0;
int ack_or_nak_seen = 0;
int i = 0;
- __u8 *dest = garmin_data_p->inbuffer;
- int size = garmin_data_p->insize;
+ __u8 *dest;
+ int size;
// dleSeen: set if last byte read was a DLE
- int dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
+ int dleSeen;
// skip: if set, skip incoming data until possible start of
// new packet
- int skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
+ int skip;
__u8 data;
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ dest = garmin_data_p->inbuffer;
+ size = garmin_data_p->insize;
+ dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
+ skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
dbg("%s - dle=%d skip=%d size=%d count=%d",
__FUNCTION__, dleSeen, skip, size, count);
@@ -574,6 +585,8 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
}
}
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+
garmin_data_p->insize = size;
// copy flags back to structure
@@ -589,6 +602,11 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
if (ack_or_nak_seen) {
garmin_data_p->state = STATE_GSP_WAIT_DATA;
+ }
+
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ if (ack_or_nak_seen) {
gsp_next_packet(garmin_data_p);
}
@@ -678,7 +696,7 @@ static int gsp_send(struct garmin_data * garmin_data_p,
src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH;
if (k > (GARMIN_PKTHDR_LENGTH-2)) {
/* can't add stuffing DLEs in place, move data to end
- of buffer ... */
+ of buffer ... */
dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen;
memcpy(dst, src, datalen);
src = dst;
@@ -757,8 +775,9 @@ static void gsp_next_packet(struct garmin_data * garmin_data_p)
* or even incomplete packets
*/
static int nat_receive(struct garmin_data * garmin_data_p,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
__u8 * dest;
int offs = 0;
int result = count;
@@ -805,7 +824,9 @@ static int nat_receive(struct garmin_data * garmin_data_p,
/* if this was an abort-transfer command,
flush all queued data. */
if (isAbortTrfCmnd(garmin_data_p->inbuffer)) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_DROP_DATA;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
pkt_clear(garmin_data_p);
}
}
@@ -841,12 +862,15 @@ static void priv_status_resp(struct usb_serial_port *port)
static int process_resetdev_request(struct usb_serial_port *port)
{
+ unsigned long flags;
int status;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED);
garmin_data_p->state = STATE_RESET;
garmin_data_p->serial_num = 0;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
usb_kill_urb (port->interrupt_in_urb);
dbg("%s - usb_reset_device", __FUNCTION__ );
@@ -864,6 +888,7 @@ static int process_resetdev_request(struct usb_serial_port *port)
*/
static int garmin_clear(struct garmin_data * garmin_data_p)
{
+ unsigned long flags;
int status = 0;
struct usb_serial_port *port = garmin_data_p->port;
@@ -877,8 +902,10 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
/* flush all queued data */
pkt_clear(garmin_data_p);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->insize = 0;
garmin_data_p->outsize = 0;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
return status;
}
@@ -890,6 +917,7 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
static int garmin_init_session(struct usb_serial_port *port)
{
+ unsigned long flags;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
int status = 0;
@@ -915,7 +943,9 @@ static int garmin_init_session(struct usb_serial_port *port)
if (status >= 0) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts++;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* not needed, but the win32 driver does it too ... */
status = garmin_write_bulk(port,
@@ -923,7 +953,9 @@ static int garmin_init_session(struct usb_serial_port *port)
sizeof(GARMIN_START_SESSION_REQ2));
if (status >= 0) {
status = 0;
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts++;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
}
}
@@ -937,6 +969,7 @@ static int garmin_init_session(struct usb_serial_port *port)
static int garmin_open (struct usb_serial_port *port, struct file *filp)
{
+ unsigned long flags;
int status = 0;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -950,9 +983,11 @@ static int garmin_open (struct usb_serial_port *port, struct file *filp)
if (port->tty)
port->tty->low_latency = 1;
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->mode = initial_mode;
garmin_data_p->count = 0;
garmin_data_p->flags = 0;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* shutdown any bulk reads that might be going on */
usb_kill_urb (port->write_urb);
@@ -998,6 +1033,7 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
+ unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -1009,7 +1045,9 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
usb_serial_port_softint(port);
@@ -1017,8 +1055,9 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
static int garmin_write_bulk (struct usb_serial_port *port,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
struct urb *urb;
@@ -1028,7 +1067,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
dbg("%s - port %d, state %d", __FUNCTION__, port->number,
garmin_data_p->state);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_DROP_DATA;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
buffer = kmalloc (count, GFP_ATOMIC);
if (!buffer) {
@@ -1055,7 +1096,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
urb->transfer_flags |= URB_ZERO_PACKET;
if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
pkt_clear(garmin_data_p);
garmin_data_p->state = STATE_GSP_WAIT_DATA;
@@ -1089,8 +1132,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
static int garmin_write (struct usb_serial_port *port,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
int pktid, pktsiz, len;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
__le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
@@ -1141,7 +1185,9 @@ static int garmin_write (struct usb_serial_port *port,
break;
case PRIV_PKTID_RESET_REQ:
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
break;
case PRIV_PKTID_SET_DEF_MODE:
@@ -1157,6 +1203,8 @@ static int garmin_write (struct usb_serial_port *port,
}
}
+ garmin_data_p->ignorePkts = 0;
+
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
return gsp_receive(garmin_data_p, buf, count);
} else { /* MODE_NATIVE */
@@ -1179,10 +1227,10 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
{
/*
* Report back the number of bytes currently in our input buffer.
- * Will this lock up the driver - the buffer contains an incomplete
- * package which will not be written to the device until it
- * has been completed ?
- */
+ * Will this lock up the driver - the buffer contains an incomplete
+ * package which will not be written to the device until it
+ * has been completed ?
+ */
//struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
//return garmin_data_p->insize;
return 0;
@@ -1192,6 +1240,8 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
static void garmin_read_process(struct garmin_data * garmin_data_p,
unsigned char *data, unsigned data_length)
{
+ unsigned long flags;
+
if (garmin_data_p->flags & FLAGS_DROP_DATA) {
/* abort-transfer cmd is actice */
dbg("%s - pkt dropped", __FUNCTION__);
@@ -1202,11 +1252,14 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
if a reset is required or not when closing
the device */
if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
- sizeof(GARMIN_APP_LAYER_REPLY)))
+ sizeof(GARMIN_APP_LAYER_REPLY))) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_APP_RESP_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
/* if throttling is active or postprecessing is required
- put the received data in th input queue, otherwise
+ put the received data in the input queue, otherwise
send it directly to the tty port */
if (garmin_data_p->flags & FLAGS_QUEUING) {
pkt_add(garmin_data_p, data, data_length);
@@ -1223,6 +1276,7 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
+ unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -1247,19 +1301,30 @@ static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
garmin_read_process(garmin_data_p, data, urb->actual_length);
- /* Continue trying to read until nothing more is received */
- if (urb->actual_length > 0) {
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- garmin_read_bulk_callback, port);
+ if (urb->actual_length == 0 &&
+ 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (status)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
__FUNCTION__, status);
+ } else if (urb->actual_length > 0) {
+ /* Continue trying to read until nothing more is received */
+ if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, status);
+ }
+ } else {
+ dbg("%s - end of bulk data", __FUNCTION__);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
return;
}
@@ -1267,6 +1332,7 @@ static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
{
+ unsigned long flags;
int status;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
@@ -1299,25 +1365,41 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
dbg("%s - bulk data available.", __FUNCTION__);
- /* bulk data available */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- garmin_read_bulk_callback, port);
- status = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (status) {
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __FUNCTION__, status);
+ if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+
+ /* bulk data available */
+ usb_fill_bulk_urb (port->read_urb, serial->dev,
+ usb_rcvbulkpipe (serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ garmin_read_bulk_callback, port);
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __FUNCTION__, status);
+ } else {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
+ /* do not send this packet to the user */
+ garmin_data_p->ignorePkts = 1;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+ } else {
+ /* bulk-in transfer still active */
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_BULK_IN_RESTART;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
} else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY))
&& 0 == memcmp(data, GARMIN_START_SESSION_REPLY,
sizeof(GARMIN_START_SESSION_REPLY))) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* save the serial number */
garmin_data_p->serial_num
@@ -1332,7 +1414,9 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
ignore it. */
dbg("%s - pkt ignored (%d)",
__FUNCTION__, garmin_data_p->ignorePkts);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts--;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
} else {
garmin_read_process(garmin_data_p, data, urb->actual_length);
}
@@ -1353,18 +1437,20 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
*/
static int garmin_flush_queue(struct garmin_data * garmin_data_p)
{
+ unsigned long flags;
struct garmin_packet *pkt;
if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) {
pkt = pkt_pop(garmin_data_p);
if (pkt != NULL) {
-
send_to_tty(garmin_data_p->port, pkt->data, pkt->size);
kfree(pkt);
mod_timer(&garmin_data_p->timer, (1)+jiffies);
} else {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_QUEUING;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
}
return 0;
@@ -1373,26 +1459,41 @@ static int garmin_flush_queue(struct garmin_data * garmin_data_p)
static void garmin_throttle (struct usb_serial_port *port)
{
+ unsigned long flags;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
dbg("%s - port %d", __FUNCTION__, port->number);
/* set flag, data received will be put into a queue
for later processing */
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
static void garmin_unthrottle (struct usb_serial_port *port)
{
+ unsigned long flags;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ int status;
dbg("%s - port %d", __FUNCTION__, port->number);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_THROTTLED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* in native mode send queued data to tty, in
serial mode nothing needs to be done here */
if (garmin_data_p->mode == MODE_NATIVE)
garmin_flush_queue(garmin_data_p);
+
+ if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, status);
+ }
}
@@ -1422,11 +1523,12 @@ static int garmin_attach (struct usb_serial *serial)
dbg("%s", __FUNCTION__);
- garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
+ garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL);
if (garmin_data_p == NULL) {
dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
return -ENOMEM;
}
+ memset (garmin_data_p, 0, sizeof(struct garmin_data));
init_timer(&garmin_data_p->timer);
spin_lock_init(&garmin_data_p->lock);
INIT_LIST_HEAD(&garmin_data_p->pktlist);
@@ -1461,10 +1563,10 @@ static void garmin_shutdown (struct usb_serial *serial)
/* All of the device info needed */
static struct usb_serial_driver garmin_device = {
.driver = {
- .owner = THIS_MODULE,
- .name = "garmin_gps",
+ .owner = THIS_MODULE,
+ .name = "garmin_gps",
},
- .description = "Garmin GPS usb/tty",
+ .description = "Garmin GPS usb/tty",
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -1485,6 +1587,7 @@ static struct usb_serial_driver garmin_device = {
};
+
static int __init garmin_init (void)
{
int retval;
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 07a478c59fb..21cbaa0fb96 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -9,7 +9,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -18,8 +17,8 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
static int debug;
@@ -176,14 +175,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
@@ -286,6 +285,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *reg
if (result)
dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
}
+EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
{
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index e9719da2aca..ebcac701b06 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -12,13 +12,12 @@
* See Documentation/usb/usb-serial.txt for more information on using this driver
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/*
* Version Information
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index b85d2156dfd..c49976c3ad5 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -29,7 +29,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
@@ -45,7 +44,7 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "io_edgeport.h"
#include "io_ionsp.h" /* info for the iosp messages */
#include "io_16654.h" /* 16654 UART defines */
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 8e1e2253748..17c5b1d2311 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -24,7 +24,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
@@ -40,8 +39,8 @@
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
-#include "usb-serial.h"
#include "io_16654.h"
#include "io_usbvend.h"
#include "io_ti.h"
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 9da6d2a8f2b..cbc725a6c58 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -44,7 +44,6 @@
* Thanks to info from Heath Robinson and Arieh Davidoff.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -56,7 +55,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "ipaq.h"
#define KP_RETRIES 100
@@ -71,6 +70,8 @@
static __u16 product, vendor;
static int debug;
+static int connect_retries = KP_RETRIES;
+static int initial_wait;
/* Function prototypes for an ipaq */
static int ipaq_open (struct usb_serial_port *port, struct file *filp);
@@ -249,6 +250,9 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */
{ USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */
{ USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */
+ { USB_DEVICE(0x04DD, 0x9102) }, /* SHARP WS003SH USB Modem */
+ { USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
+ { USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -475,6 +479,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */
{ USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */
{ USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */
+ { USB_DEVICE(0x0BB4, 0x0BCE) }, /* "High Tech Computer Corp" */
{ USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */
{ USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */
{ USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
@@ -583,7 +588,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
struct ipaq_private *priv;
struct ipaq_packet *pkt;
int i, result = 0;
- int retries = KP_RETRIES;
+ int retries = connect_retries;
dbg("%s - port %d", __FUNCTION__, port->number);
@@ -647,16 +652,7 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
port->read_urb->transfer_buffer_length = URBDATA_SIZE;
port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
- /* Start reading from the device */
- usb_fill_bulk_urb(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ipaq_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
- goto error;
- }
+ msleep(1000*initial_wait);
/*
* Send out control message observed in win98 sniffs. Not sure what
@@ -670,12 +666,31 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
0x1, 0, NULL, 0, 100);
- if (result == 0) {
- return 0;
- }
+ if (!result)
+ break;
+
+ msleep(1000);
}
- err("%s - failed doing control urb, error %d", __FUNCTION__, result);
- goto error;
+
+ if (!retries && result) {
+ err("%s - failed doing control urb, error %d", __FUNCTION__,
+ result);
+ goto error;
+ }
+
+ /* Start reading from the device */
+ usb_fill_bulk_urb(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ipaq_read_bulk_callback, port);
+
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result) {
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ goto error;
+ }
+
+ return 0;
enomem:
result = -ENOMEM;
@@ -855,6 +870,7 @@ static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ return;
}
spin_lock_irqsave(&write_list_lock, flags);
@@ -967,3 +983,9 @@ MODULE_PARM_DESC(vendor, "User specified USB idVendor");
module_param(product, ushort, 0);
MODULE_PARM_DESC(product, "User specified USB idProduct");
+
+module_param(connect_retries, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)");
+
+module_param(initial_wait, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(initial_wait, "Time to wait before attempting a connection (in seconds)");
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index a4a0bfeaab0..812bc213a96 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -46,8 +46,8 @@
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <asm/uaccess.h>
-#include "usb-serial.h"
/*
* Version Information
@@ -373,6 +373,8 @@ static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s", __FUNCTION__);
+ port->write_urb_busy = 0;
+
if (urb->status)
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
@@ -392,14 +394,14 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
return 0;
}
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 9432c730227..1b348df388e 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -46,7 +46,6 @@
* initial version released.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -58,7 +57,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/*
* Version Information
@@ -343,14 +342,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
if (count == 0)
return 0;
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
transfer_buffer = port->write_urb->transfer_buffer;
transfer_size = min(count, port->bulk_out_size - 1);
@@ -453,8 +452,7 @@ static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
tty = port->tty;
/*
- * FIXME: must not do this in IRQ context,
- * must honour TTY_DONT_FLIP
+ * FIXME: must not do this in IRQ context
*/
tty->ldisc.receive_buf(
tty,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 2cf6ade704e..015ad6cc1bb 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -95,7 +95,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
@@ -108,7 +107,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "keyspan.h"
static int debug;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index b0441c35f98..59e777f1e8f 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -66,7 +66,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -79,6 +78,7 @@
#include <linux/workqueue.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
static int debug;
@@ -108,8 +108,6 @@ struct ezusb_hex_record {
#include "xircom_pgs_fw.h"
#endif
-#include "usb-serial.h"
-
/*
* Version Information
*/
@@ -520,13 +518,13 @@ static int keyspan_pda_write(struct usb_serial_port *port,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy || priv->tx_throttled) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
/* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 65d79f630fa..2a2f3e2da05 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -45,7 +45,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -56,7 +55,7 @@
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "kl5kusb105.h"
static int debug;
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 87dfcd89ffa..d50dce03495 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -35,7 +35,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -47,8 +46,8 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
#include <linux/ioctl.h>
-#include "usb-serial.h"
#include "kobil_sct.h"
static int debug;
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 35bd29b6c40..f4d4305c2c0 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -64,7 +64,6 @@
* (via linux-usb-devel).
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -76,7 +75,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "mct_u232.h"
/*
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
new file mode 100644
index 00000000000..95bf57166c5
--- /dev/null
+++ b/drivers/usb/serial/mos7840.c
@@ -0,0 +1,2962 @@
+/*
+ * 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
+ *
+ * Clean ups from Moschip version and a few ioctl implementations by:
+ * Paul B Schroeder <pschroeder "at" uplogix "dot" com>
+ *
+ * Originally based on drivers/usb/serial/io_edgeport.c which is:
+ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.3.1"
+#define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver"
+
+/*
+ * 16C50 UART register defines
+ */
+
+#define LCR_BITS_5 0x00 /* 5 bits/char */
+#define LCR_BITS_6 0x01 /* 6 bits/char */
+#define LCR_BITS_7 0x02 /* 7 bits/char */
+#define LCR_BITS_8 0x03 /* 8 bits/char */
+#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
+
+#define LCR_STOP_1 0x00 /* 1 stop bit */
+#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
+#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
+#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
+
+#define LCR_PAR_NONE 0x00 /* No parity */
+#define LCR_PAR_ODD 0x08 /* Odd parity */
+#define LCR_PAR_EVEN 0x18 /* Even parity */
+#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
+#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
+#define LCR_PAR_MASK 0x38 /* Mask for parity field */
+
+#define LCR_SET_BREAK 0x40 /* Set Break condition */
+#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
+
+#define MCR_DTR 0x01 /* Assert DTR */
+#define MCR_RTS 0x02 /* Assert RTS */
+#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
+#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
+#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
+#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
+
+#define MOS7840_MSR_CTS 0x10 /* Current state of CTS */
+#define MOS7840_MSR_DSR 0x20 /* Current state of DSR */
+#define MOS7840_MSR_RI 0x40 /* Current state of RI */
+#define MOS7840_MSR_CD 0x80 /* Current state of CD */
+
+/*
+ * Defines used for sending commands to port
+ */
+
+#define WAIT_FOR_EVER (HZ * 0 ) /* timeout urb is wait for ever */
+#define MOS_WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+#define MOS_PORT1 0x0200
+#define MOS_PORT2 0x0300
+#define MOS_VENREG 0x0000
+#define MOS_MAX_PORT 0x02
+#define MOS_WRITE 0x0E
+#define MOS_READ 0x0D
+
+/* Requests */
+#define MCS_RD_RTYPE 0xC0
+#define MCS_WR_RTYPE 0x40
+#define MCS_RDREQ 0x0D
+#define MCS_WRREQ 0x0E
+#define MCS_CTRL_TIMEOUT 500
+#define VENDOR_READ_LENGTH (0x01)
+
+#define MAX_NAME_LEN 64
+
+#define ZLP_REG1 0x3A //Zero_Flag_Reg1 58
+#define ZLP_REG5 0x3E //Zero_Flag_Reg5 62
+
+/* For higher baud Rates use TIOCEXBAUD */
+#define TIOCEXBAUD 0x5462
+
+/* vendor id and device id defines */
+
+#define USB_VENDOR_ID_MOSCHIP 0x9710
+#define MOSCHIP_DEVICE_ID_7840 0x7840
+#define MOSCHIP_DEVICE_ID_7820 0x7820
+
+/* Interrupt Rotinue Defines */
+
+#define SERIAL_IIR_RLS 0x06
+#define SERIAL_IIR_MS 0x00
+
+/*
+ * Emulation of the bit mask on the LINE STATUS REGISTER.
+ */
+#define SERIAL_LSR_DR 0x0001
+#define SERIAL_LSR_OE 0x0002
+#define SERIAL_LSR_PE 0x0004
+#define SERIAL_LSR_FE 0x0008
+#define SERIAL_LSR_BI 0x0010
+
+#define MOS_MSR_DELTA_CTS 0x10
+#define MOS_MSR_DELTA_DSR 0x20
+#define MOS_MSR_DELTA_RI 0x40
+#define MOS_MSR_DELTA_CD 0x80
+
+// Serial Port register Address
+#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
+#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
+#define LINE_CONTROL_REGISTER ((__u16)(0x03))
+#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
+#define LINE_STATUS_REGISTER ((__u16)(0x05))
+#define MODEM_STATUS_REGISTER ((__u16)(0x06))
+#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
+#define DIVISOR_LATCH_LSB ((__u16)(0x00))
+#define DIVISOR_LATCH_MSB ((__u16)(0x01))
+
+#define CLK_MULTI_REGISTER ((__u16)(0x02))
+#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
+
+#define SERIAL_LCR_DLAB ((__u16)(0x0080))
+
+/*
+ * URB POOL related defines
+ */
+#define NUM_URBS 16 /* URB Count */
+#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
+
+
+static struct usb_device_id moschip_port_id_table[] = {
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+ {} /* terminating entry */
+};
+
+static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+ {} /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
+
+/* This structure holds all of the local port information */
+
+struct moschip_port {
+ int port_num; /*Actual port number in the device(1,2,etc) */
+ struct urb *write_urb; /* write URB for this port */
+ struct urb *read_urb; /* read URB for this port */
+ __u8 shadowLCR; /* last LCR value received */
+ __u8 shadowMCR; /* last MCR value received */
+ char open;
+ wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
+ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
+ int delta_msr_cond;
+ struct async_icount icount;
+ struct usb_serial_port *port; /* loop back to the owner of this object */
+
+ /*Offsets */
+ __u8 SpRegOffset;
+ __u8 ControlRegOffset;
+ __u8 DcrRegOffset;
+ //for processing control URBS in interrupt context
+ struct urb *control_urb;
+ char *ctrl_buf;
+ int MsrLsr;
+
+ struct urb *write_urb_pool[NUM_URBS];
+};
+
+
+static int debug;
+static int mos7840_num_ports; //this says the number of ports in the device
+static int mos7840_num_open_ports;
+
+
+/*
+ * mos7840_set_reg_sync
+ * To set the Control register by calling usb_fill_control_urb function
+ * by passing usb_sndctrlpipe function as parameter.
+ */
+
+static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg,
+ __u16 val)
+{
+ struct usb_device *dev = port->serial->dev;
+ val = val & 0x00ff;
+ dbg("mos7840_set_reg_sync offset is %x, value %x\n", reg, val);
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, val, reg, NULL, 0,
+ MOS_WDR_TIMEOUT);
+}
+
+/*
+ * mos7840_get_reg_sync
+ * To set the Uart register by calling usb_fill_control_urb function by
+ * passing usb_rcvctrlpipe function as parameter.
+ */
+
+static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
+ __u16 * val)
+{
+ struct usb_device *dev = port->serial->dev;
+ int ret = 0;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
+ MOS_WDR_TIMEOUT);
+ dbg("mos7840_get_reg_sync offset is %x, return val %x\n", reg, *val);
+ *val = (*val) & 0x00ff;
+ return ret;
+}
+
+/*
+ * mos7840_set_uart_reg
+ * To set the Uart register by calling usb_fill_control_urb function by
+ * passing usb_sndctrlpipe function as parameter.
+ */
+
+static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
+ __u16 val)
+{
+
+ struct usb_device *dev = port->serial->dev;
+ val = val & 0x00ff;
+ // For the UART control registers, the application number need to be Or'ed
+ if (mos7840_num_ports == 4) {
+ val |=
+ (((__u16) port->number - (__u16) (port->serial->minor)) +
+ 1) << 8;
+ dbg("mos7840_set_uart_reg application number is %x\n", val);
+ } else {
+ if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
+ val |=
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 1) << 8;
+ dbg("mos7840_set_uart_reg application number is %x\n",
+ val);
+ } else {
+ val |=
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 2) << 8;
+ dbg("mos7840_set_uart_reg application number is %x\n",
+ val);
+ }
+ }
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, val, reg, NULL, 0,
+ MOS_WDR_TIMEOUT);
+
+}
+
+/*
+ * mos7840_get_uart_reg
+ * To set the Control register by calling usb_fill_control_urb function
+ * by passing usb_rcvctrlpipe function as parameter.
+ */
+static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
+ __u16 * val)
+{
+ struct usb_device *dev = port->serial->dev;
+ int ret = 0;
+ __u16 Wval;
+
+ //dbg("application number is %4x \n",(((__u16)port->number - (__u16)(port->serial->minor))+1)<<8);
+ /*Wval is same as application number */
+ if (mos7840_num_ports == 4) {
+ Wval =
+ (((__u16) port->number - (__u16) (port->serial->minor)) +
+ 1) << 8;
+ dbg("mos7840_get_uart_reg application number is %x\n", Wval);
+ } else {
+ if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
+ Wval =
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 1) << 8;
+ dbg("mos7840_get_uart_reg application number is %x\n",
+ Wval);
+ } else {
+ Wval =
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 2) << 8;
+ dbg("mos7840_get_uart_reg application number is %x\n",
+ Wval);
+ }
+ }
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, Wval, reg, val, VENDOR_READ_LENGTH,
+ MOS_WDR_TIMEOUT);
+ *val = (*val) & 0x00ff;
+ return ret;
+}
+
+static void mos7840_dump_serial_port(struct moschip_port *mos7840_port)
+{
+
+ dbg("***************************************\n");
+ dbg("SpRegOffset is %2x\n", mos7840_port->SpRegOffset);
+ dbg("ControlRegOffset is %2x \n", mos7840_port->ControlRegOffset);
+ dbg("DCRRegOffset is %2x \n", mos7840_port->DcrRegOffset);
+ dbg("***************************************\n");
+
+}
+
+/************************************************************************/
+/************************************************************************/
+/* I N T E R F A C E F U N C T I O N S */
+/* I N T E R F A C E F U N C T I O N S */
+/************************************************************************/
+/************************************************************************/
+
+static inline void mos7840_set_port_private(struct usb_serial_port *port,
+ struct moschip_port *data)
+{
+ usb_set_serial_port_data(port, (void *)data);
+}
+
+static inline struct moschip_port *mos7840_get_port_private(struct
+ usb_serial_port
+ *port)
+{
+ return (struct moschip_port *)usb_get_serial_port_data(port);
+}
+
+static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
+{
+ struct moschip_port *mos7840_port;
+ struct async_icount *icount;
+ mos7840_port = port;
+ icount = &mos7840_port->icount;
+ if (new_msr &
+ (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
+ MOS_MSR_DELTA_CD)) {
+ icount = &mos7840_port->icount;
+
+ /* update input line counters */
+ if (new_msr & MOS_MSR_DELTA_CTS) {
+ icount->cts++;
+ }
+ if (new_msr & MOS_MSR_DELTA_DSR) {
+ icount->dsr++;
+ }
+ if (new_msr & MOS_MSR_DELTA_CD) {
+ icount->dcd++;
+ }
+ if (new_msr & MOS_MSR_DELTA_RI) {
+ icount->rng++;
+ }
+ }
+
+ return 0;
+}
+
+static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
+{
+ struct async_icount *icount;
+
+ dbg("%s - %02x", __FUNCTION__, new_lsr);
+
+ if (new_lsr & SERIAL_LSR_BI) {
+ //
+ // Parity and Framing errors only count if they
+ // occur exclusive of a break being
+ // received.
+ //
+ new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
+ }
+
+ /* update input line counters */
+ icount = &port->icount;
+ if (new_lsr & SERIAL_LSR_BI) {
+ icount->brk++;
+ }
+ if (new_lsr & SERIAL_LSR_OE) {
+ icount->overrun++;
+ }
+ if (new_lsr & SERIAL_LSR_PE) {
+ icount->parity++;
+ }
+ if (new_lsr & SERIAL_LSR_FE) {
+ icount->frame++;
+ }
+
+ return 0;
+}
+
+/************************************************************************/
+/************************************************************************/
+/* U S B C A L L B A C K F U N C T I O N S */
+/* U S B C A L L B A C K F U N C T I O N S */
+/************************************************************************/
+/************************************************************************/
+
+static void mos7840_control_callback(struct urb *urb, struct pt_regs *regs)
+{
+ unsigned char *data;
+ struct moschip_port *mos7840_port;
+ __u8 regval = 0x0;
+
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
+ goto exit;
+ }
+
+ mos7840_port = (struct moschip_port *)urb->context;
+
+ dbg("%s urb buffer size is %d\n", __FUNCTION__, urb->actual_length);
+ dbg("%s mos7840_port->MsrLsr is %d port %d\n", __FUNCTION__,
+ mos7840_port->MsrLsr, mos7840_port->port_num);
+ data = urb->transfer_buffer;
+ regval = (__u8) data[0];
+ dbg("%s data is %x\n", __FUNCTION__, regval);
+ if (mos7840_port->MsrLsr == 0)
+ mos7840_handle_new_msr(mos7840_port, regval);
+ else if (mos7840_port->MsrLsr == 1)
+ mos7840_handle_new_lsr(mos7840_port, regval);
+
+ exit:
+ return;
+}
+
+static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
+ __u16 * val)
+{
+ struct usb_device *dev = mcs->port->serial->dev;
+ struct usb_ctrlrequest *dr = NULL;
+ unsigned char *buffer = NULL;
+ int ret = 0;
+ buffer = (__u8 *) mcs->ctrl_buf;
+
+// dr=(struct usb_ctrlrequest *)(buffer);
+ dr = (void *)(buffer + 2);
+ dr->bRequestType = MCS_RD_RTYPE;
+ dr->bRequest = MCS_RDREQ;
+ dr->wValue = cpu_to_le16(Wval); //0;
+ dr->wIndex = cpu_to_le16(reg);
+ dr->wLength = cpu_to_le16(2);
+
+ usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0),
+ (unsigned char *)dr, buffer, 2,
+ mos7840_control_callback, mcs);
+ mcs->control_urb->transfer_buffer_length = 2;
+ ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+ return ret;
+}
+
+/*****************************************************************************
+ * mos7840_interrupt_callback
+ * this is the callback function for when we have received data on the
+ * interrupt endpoint.
+ *****************************************************************************/
+
+static void mos7840_interrupt_callback(struct urb *urb, struct pt_regs *regs)
+{
+ int result;
+ int length;
+ struct moschip_port *mos7840_port;
+ struct usb_serial *serial;
+ __u16 Data;
+ unsigned char *data;
+ __u8 sp[5], st;
+ int i;
+ __u16 wval;
+
+ dbg("%s", " : Entering\n");
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
+ goto exit;
+ }
+
+ length = urb->actual_length;
+ data = urb->transfer_buffer;
+
+ serial = (struct usb_serial *)urb->context;
+
+ /* Moschip get 5 bytes
+ * Byte 1 IIR Port 1 (port.number is 0)
+ * Byte 2 IIR Port 2 (port.number is 1)
+ * Byte 3 IIR Port 3 (port.number is 2)
+ * Byte 4 IIR Port 4 (port.number is 3)
+ * Byte 5 FIFO status for both */
+
+ if (length && length > 5) {
+ dbg("%s \n", "Wrong data !!!");
+ return;
+ }
+
+ sp[0] = (__u8) data[0];
+ sp[1] = (__u8) data[1];
+ sp[2] = (__u8) data[2];
+ sp[3] = (__u8) data[3];
+ st = (__u8) data[4];
+
+ for (i = 0; i < serial->num_ports; i++) {
+ mos7840_port = mos7840_get_port_private(serial->port[i]);
+ wval =
+ (((__u16) serial->port[i]->number -
+ (__u16) (serial->minor)) + 1) << 8;
+ if (mos7840_port->open) {
+ if (sp[i] & 0x01) {
+ dbg("SP%d No Interrupt !!!\n", i);
+ } else {
+ switch (sp[i] & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port %d: Receiver status error or ", i);
+ dbg("address bit detected in 9-bit mode\n");
+ mos7840_port->MsrLsr = 1;
+ mos7840_get_reg(mos7840_port, wval,
+ LINE_STATUS_REGISTER,
+ &Data);
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port %d: Modem status change\n", i);
+ mos7840_port->MsrLsr = 0;
+ mos7840_get_reg(mos7840_port, wval,
+ MODEM_STATUS_REGISTER,
+ &Data);
+ break;
+ }
+ }
+ }
+ }
+ exit:
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result) {
+ dev_err(&urb->dev->dev,
+ "%s - Error %d submitting interrupt urb\n",
+ __FUNCTION__, result);
+ }
+
+ return;
+
+}
+
+static int mos7840_port_paranoia_check(struct usb_serial_port *port,
+ const char *function)
+{
+ if (!port) {
+ dbg("%s - port == NULL", function);
+ return -1;
+ }
+ if (!port->serial) {
+ dbg("%s - port->serial == NULL", function);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static int mos7840_serial_paranoia_check(struct usb_serial *serial,
+ const char *function)
+{
+ if (!serial) {
+ dbg("%s - serial == NULL", function);
+ return -1;
+ }
+ if (!serial->type) {
+ dbg("%s - serial->type == NULL!", function);
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
+ const char *function)
+{
+ /* if no port was specified, or it fails a paranoia check */
+ if (!port ||
+ mos7840_port_paranoia_check(port, function) ||
+ mos7840_serial_paranoia_check(port->serial, function)) {
+ /* then say that we don't have a valid usb_serial thing, which will * end up genrating -ENODEV return values */
+ return NULL;
+ }
+
+ return port->serial;
+}
+
+/*****************************************************************************
+ * mos7840_bulk_in_callback
+ * this is the callback function for when we have received data on the
+ * bulk in endpoint.
+ *****************************************************************************/
+
+static void mos7840_bulk_in_callback(struct urb *urb, struct pt_regs *regs)
+{
+ int status;
+ unsigned char *data;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ mos7840_port = (struct moschip_port *)urb->context;
+ if (!mos7840_port) {
+ dbg("%s", "NULL mos7840_port pointer \n");
+ return;
+ }
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ if (!serial) {
+ dbg("%s\n", "Bad serial pointer ");
+ return;
+ }
+
+ dbg("%s\n", "Entering... \n");
+
+ data = urb->transfer_buffer;
+
+ dbg("%s", "Entering ........... \n");
+
+ if (urb->actual_length) {
+ tty = mos7840_port->port->tty;
+ if (tty) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ dbg(" %s \n", data);
+ tty_flip_buffer_push(tty);
+ }
+ mos7840_port->icount.rx += urb->actual_length;
+ dbg("mos7840_port->icount.rx is %d:\n",
+ mos7840_port->icount.rx);
+ }
+
+ if (!mos7840_port->read_urb) {
+ dbg("%s", "URB KILLED !!!\n");
+ return;
+ }
+
+ if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ mos7840_port->read_urb->dev = serial->dev;
+
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+
+ if (status) {
+ dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ }
+}
+
+/*****************************************************************************
+ * mos7840_bulk_out_data_callback
+ * this is the callback function for when we have finished sending serial data
+ * on the bulk out endpoint.
+ *****************************************************************************/
+
+static void mos7840_bulk_out_data_callback(struct urb *urb,
+ struct pt_regs *regs)
+{
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received:%d\n", urb->status);
+ return;
+ }
+
+ mos7840_port = (struct moschip_port *)urb->context;
+ if (!mos7840_port) {
+ dbg("%s", "NULL mos7840_port pointer \n");
+ return;
+ }
+
+ if (mos7840_port_paranoia_check(mos7840_port->port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ dbg("%s \n", "Entering .........");
+
+ tty = mos7840_port->port->tty;
+
+ if (tty && mos7840_port->open) {
+ /* let the tty driver wakeup if it has a special *
+ * write_wakeup function */
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup) {
+ (tty->ldisc.write_wakeup) (tty);
+ }
+
+ /* tell the tty driver that something has changed */
+ wake_up_interruptible(&tty->write_wait);
+ }
+
+}
+
+/************************************************************************/
+/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
+/************************************************************************/
+#ifdef MCSSerialProbe
+static int mos7840_serial_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+
+ /*need to implement the mode_reg reading and updating\
+ structures usb_serial_ device_type\
+ (i.e num_ports, num_bulkin,bulkout etc) */
+ /* Also we can update the changes attach */
+ return 1;
+}
+#endif
+
+/*****************************************************************************
+ * mos7840_open
+ * this function is called by the tty driver when a port is opened
+ * If successful, we return 0
+ * Otherwise we return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_open(struct usb_serial_port *port, struct file *filp)
+{
+ int response;
+ int j;
+ struct usb_serial *serial;
+ struct urb *urb;
+ __u16 Data;
+ int status;
+ struct moschip_port *mos7840_port;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return -ENODEV;
+ }
+
+ mos7840_num_open_ports++;
+ serial = port->serial;
+
+ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return -ENODEV;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return -ENODEV;
+
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ /* Initialising the write urb pool */
+ for (j = 0; j < NUM_URBS; ++j) {
+ urb = usb_alloc_urb(0, SLAB_ATOMIC);
+ mos7840_port->write_urb_pool[j] = urb;
+
+ if (urb == NULL) {
+ err("No more urbs???");
+ continue;
+ }
+
+ urb->transfer_buffer = NULL;
+ urb->transfer_buffer =
+ kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("%s-out of memory for urb buffers.", __FUNCTION__);
+ continue;
+ }
+ }
+
+/*****************************************************************************
+ * Initialize MCS7840 -- Write Init values to corresponding Registers
+ *
+ * Register Index
+ * 1 : IER
+ * 2 : FCR
+ * 3 : LCR
+ * 4 : MCR
+ *
+ * 0x08 : SP1/2 Control Reg
+ *****************************************************************************/
+
+//NEED to check the following Block
+
+ status = 0;
+ Data = 0x0;
+ status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
+ if (status < 0) {
+ dbg("Reading Spreg failed\n");
+ return -1;
+ }
+ Data |= 0x80;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ if (status < 0) {
+ dbg("writing Spreg failed\n");
+ return -1;
+ }
+
+ Data &= ~0x80;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ if (status < 0) {
+ dbg("writing Spreg failed\n");
+ return -1;
+ }
+//End of block to be checked
+
+ status = 0;
+ Data = 0x0;
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
+ if (status < 0) {
+ dbg("Reading Controlreg failed\n");
+ return -1;
+ }
+ Data |= 0x08; //Driver done bit
+ Data |= 0x20; //rx_disable
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+ if (status < 0) {
+ dbg("writing Controlreg failed\n");
+ return -1;
+ }
+ //do register settings here
+ // Set all regs to the device default values.
+ ////////////////////////////////////
+ // First Disable all interrupts.
+ ////////////////////////////////////
+
+ Data = 0x00;
+ status = 0;
+ status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+ if (status < 0) {
+ dbg("disableing interrupts failed\n");
+ return -1;
+ }
+ // Set FIFO_CONTROL_REGISTER to the default value
+ Data = 0x00;
+ status = 0;
+ status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing FIFO_CONTROL_REGISTER failed\n");
+ return -1;
+ }
+
+ Data = 0xcf;
+ status = 0;
+ status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing FIFO_CONTROL_REGISTER failed\n");
+ return -1;
+ }
+
+ Data = 0x03;
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+ mos7840_port->shadowLCR = Data;
+
+ Data = 0x0b;
+ status = 0;
+ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ mos7840_port->shadowMCR = Data;
+
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
+ mos7840_port->shadowLCR = Data;
+
+ Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ Data = 0x0c;
+ status = 0;
+ status = mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
+
+ Data = 0x0;
+ status = 0;
+ status = mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
+
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
+
+ Data = Data & ~SERIAL_LCR_DLAB;
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+ mos7840_port->shadowLCR = Data;
+
+ //clearing Bulkin and Bulkout Fifo
+ Data = 0x0;
+ status = 0;
+ status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
+
+ Data = Data | 0x0c;
+ status = 0;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+
+ Data = Data & ~0x0c;
+ status = 0;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ //Finally enable all interrupts
+ Data = 0x0;
+ Data = 0x0c;
+ status = 0;
+ status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ //clearing rx_disable
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
+ Data = Data & ~0x20;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+
+ // rx_negate
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
+ Data = Data | 0x10;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+
+ /* force low_latency on so that our tty_push actually forces *
+ * the data through,otherwise it is scheduled, and with *
+ * high data rates (like with OHCI) data can get lost. */
+
+ if (port->tty)
+ port->tty->low_latency = 1;
+/* Check to see if we've set up our endpoint info yet *
+ * (can't set it up in mos7840_startup as the structures *
+ * were not set up at that time.) */
+ if (mos7840_num_open_ports == 1) {
+ if (serial->port[0]->interrupt_in_buffer == NULL) {
+
+ /* set up interrupt urb */
+
+ usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
+ serial->dev,
+ usb_rcvintpipe(serial->dev,
+ serial->port[0]->
+ interrupt_in_endpointAddress),
+ serial->port[0]->interrupt_in_buffer,
+ serial->port[0]->interrupt_in_urb->
+ transfer_buffer_length,
+ mos7840_interrupt_callback,
+ serial,
+ serial->port[0]->interrupt_in_urb->
+ interval);
+
+ /* start interrupt read for mos7840 *
+ * will continue as long as mos7840 is connected */
+
+ response =
+ usb_submit_urb(serial->port[0]->interrupt_in_urb,
+ GFP_KERNEL);
+ if (response) {
+ err("%s - Error %d submitting interrupt urb",
+ __FUNCTION__, response);
+ }
+
+ }
+
+ }
+
+ /* see if we've set up our endpoint info yet *
+ * (can't set it up in mos7840_startup as the *
+ * structures were not set up at that time.) */
+
+ dbg("port number is %d \n", port->number);
+ dbg("serial number is %d \n", port->serial->minor);
+ dbg("Bulkin endpoint is %d \n", port->bulk_in_endpointAddress);
+ dbg("BulkOut endpoint is %d \n", port->bulk_out_endpointAddress);
+ dbg("Interrupt endpoint is %d \n", port->interrupt_in_endpointAddress);
+ dbg("port's number in the device is %d\n", mos7840_port->port_num);
+ mos7840_port->read_urb = port->read_urb;
+
+ /* set up our bulk in urb */
+
+ usb_fill_bulk_urb(mos7840_port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer,
+ mos7840_port->read_urb->transfer_buffer_length,
+ mos7840_bulk_in_callback, mos7840_port);
+
+ dbg("mos7840_open: bulkin endpoint is %d\n",
+ port->bulk_in_endpointAddress);
+ response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
+ if (response) {
+ err("%s - Error %d submitting control urb", __FUNCTION__,
+ response);
+ }
+
+ /* initialize our wait queues */
+ init_waitqueue_head(&mos7840_port->wait_chase);
+ init_waitqueue_head(&mos7840_port->delta_msr_wait);
+
+ /* initialize our icount structure */
+ memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
+
+ /* initialize our port settings */
+ mos7840_port->shadowMCR = MCR_MASTER_IE; /* Must set to enable ints! */
+ /* send a open port command */
+ mos7840_port->open = 1;
+ //mos7840_change_port_settings(mos7840_port,old_termios);
+ mos7840_port->icount.tx = 0;
+ mos7840_port->icount.rx = 0;
+
+ dbg("\n\nusb_serial serial:%x mos7840_port:%x\n usb_serial_port port:%x\n\n", (unsigned int)serial, (unsigned int)mos7840_port, (unsigned int)port);
+
+ return 0;
+
+}
+
+/*****************************************************************************
+ * mos7840_chars_in_buffer
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we currently have outstanding in the port (data that has
+ * been written, but hasn't made it out the port yet)
+ * If successful, we return the number of bytes left to be written in the
+ * system,
+ * Otherwise we return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_chars_in_buffer(struct usb_serial_port *port)
+{
+ int i;
+ int chars = 0;
+ struct moschip_port *mos7840_port;
+
+ dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ if (mos7840_port == NULL) {
+ dbg("%s \n", "mos7840_break:leaving ...........");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7840_port->write_urb_pool[i]->status == -EINPROGRESS) {
+ chars += URB_TRANSFER_BUFFER_SIZE;
+ }
+ }
+ dbg("%s - returns %d", __FUNCTION__, chars);
+ return (chars);
+
+}
+
+/************************************************************************
+ *
+ * mos7840_block_until_tx_empty
+ *
+ * This function will block the close until one of the following:
+ * 1. TX count are 0
+ * 2. The mos7840 has stopped
+ * 3. A timout of 3 seconds without activity has expired
+ *
+ ************************************************************************/
+static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
+{
+ int timeout = HZ / 10;
+ int wait = 30;
+ int count;
+
+ while (1) {
+
+ count = mos7840_chars_in_buffer(mos7840_port->port);
+
+ /* Check for Buffer status */
+ if (count <= 0) {
+ return;
+ }
+
+ /* Block the thread for a while */
+ interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
+ timeout);
+
+ /* No activity.. count down section */
+ wait--;
+ if (wait == 0) {
+ dbg("%s - TIMEOUT", __FUNCTION__);
+ return;
+ } else {
+ /* Reset timout value back to seconds */
+ wait = 30;
+ }
+ }
+}
+
+/*****************************************************************************
+ * mos7840_close
+ * this function is called by the tty driver when a port is closed
+ *****************************************************************************/
+
+static void mos7840_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial;
+ struct moschip_port *mos7840_port;
+ int j;
+ __u16 Data;
+
+ dbg("%s\n", "mos7840_close:entering...");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ if (!serial) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL) {
+ return;
+ }
+
+ for (j = 0; j < NUM_URBS; ++j)
+ usb_kill_urb(mos7840_port->write_urb_pool[j]);
+
+ /* Freeing Write URBs */
+ for (j = 0; j < NUM_URBS; ++j) {
+ if (mos7840_port->write_urb_pool[j]) {
+ if (mos7840_port->write_urb_pool[j]->transfer_buffer)
+ kfree(mos7840_port->write_urb_pool[j]->
+ transfer_buffer);
+
+ usb_free_urb(mos7840_port->write_urb_pool[j]);
+ }
+ }
+
+ if (serial->dev) {
+ /* flush and block until tx is empty */
+ mos7840_block_until_tx_empty(mos7840_port);
+ }
+
+ /* While closing port, shutdown all bulk read, write *
+ * and interrupt read if they exists */
+ if (serial->dev) {
+
+ if (mos7840_port->write_urb) {
+ dbg("%s", "Shutdown bulk write\n");
+ usb_kill_urb(mos7840_port->write_urb);
+ }
+
+ if (mos7840_port->read_urb) {
+ dbg("%s", "Shutdown bulk read\n");
+ usb_kill_urb(mos7840_port->read_urb);
+ }
+ if ((&mos7840_port->control_urb)) {
+ dbg("%s", "Shutdown control read\n");
+ // usb_kill_urb (mos7840_port->control_urb);
+
+ }
+ }
+// if(mos7840_port->ctrl_buf != NULL)
+// kfree(mos7840_port->ctrl_buf);
+ mos7840_num_open_ports--;
+ dbg("mos7840_num_open_ports in close%d:in port%d\n",
+ mos7840_num_open_ports, port->number);
+ if (mos7840_num_open_ports == 0) {
+ if (serial->port[0]->interrupt_in_urb) {
+ dbg("%s", "Shutdown interrupt_in_urb\n");
+ }
+ }
+
+ if (mos7840_port->write_urb) {
+ /* if this urb had a transfer buffer already (old tx) free it */
+
+ if (mos7840_port->write_urb->transfer_buffer != NULL) {
+ kfree(mos7840_port->write_urb->transfer_buffer);
+ }
+ usb_free_urb(mos7840_port->write_urb);
+ }
+
+ Data = 0x0;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+
+ Data = 0x00;
+ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ mos7840_port->open = 0;
+
+ dbg("%s \n", "Leaving ............");
+}
+
+/************************************************************************
+ *
+ * mos7840_block_until_chase_response
+ *
+ * This function will block the close until one of the following:
+ * 1. Response to our Chase comes from mos7840
+ * 2. A timout of 10 seconds without activity has expired
+ * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
+ *
+ ************************************************************************/
+
+static void mos7840_block_until_chase_response(struct moschip_port
+ *mos7840_port)
+{
+ int timeout = 1 * HZ;
+ int wait = 10;
+ int count;
+
+ while (1) {
+ count = mos7840_chars_in_buffer(mos7840_port->port);
+
+ /* Check for Buffer status */
+ if (count <= 0) {
+ return;
+ }
+
+ /* Block the thread for a while */
+ interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
+ timeout);
+ /* No activity.. count down section */
+ wait--;
+ if (wait == 0) {
+ dbg("%s - TIMEOUT", __FUNCTION__);
+ return;
+ } else {
+ /* Reset timout value back to seconds */
+ wait = 10;
+ }
+ }
+
+}
+
+/*****************************************************************************
+ * mos7840_break
+ * this function sends a break to the port
+ *****************************************************************************/
+static void mos7840_break(struct usb_serial_port *port, int break_state)
+{
+ unsigned char data;
+ struct usb_serial *serial;
+ struct moschip_port *mos7840_port;
+
+ dbg("%s \n", "Entering ...........");
+ dbg("mos7840_break: Start\n");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ if (!serial) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL) {
+ return;
+ }
+
+ if (serial->dev) {
+
+ /* flush and block until tx is empty */
+ mos7840_block_until_chase_response(mos7840_port);
+ }
+
+ if (break_state == -1) {
+ data = mos7840_port->shadowLCR | LCR_SET_BREAK;
+ } else {
+ data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
+ }
+
+ mos7840_port->shadowLCR = data;
+ dbg("mcs7840_break mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
+ mos7840_port->shadowLCR);
+
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_write_room
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we can accept for a specific port.
+ * If successful, we return the amount of room that we have for this port
+ * Otherwise we return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_write_room(struct usb_serial_port *port)
+{
+ int i;
+ int room = 0;
+ struct moschip_port *mos7840_port;
+
+ dbg("%s \n", " mos7840_write_room:entering ...........");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ dbg("%s \n", " mos7840_write_room:leaving ...........");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ if (mos7840_port == NULL) {
+ dbg("%s \n", "mos7840_break:leaving ...........");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
+ room += URB_TRANSFER_BUFFER_SIZE;
+ }
+ }
+
+ dbg("%s - returns %d", __FUNCTION__, room);
+ return (room);
+
+}
+
+/*****************************************************************************
+ * mos7840_write
+ * this function is called by the tty driver when data should be written to
+ * the port.
+ * If successful, we return the number of bytes written, otherwise we
+ * return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_write(struct usb_serial_port *port,
+ const unsigned char *data, int count)
+{
+ int status;
+ int i;
+ int bytes_sent = 0;
+ int transfer_size;
+ int from_user = 0;
+
+ struct moschip_port *mos7840_port;
+ struct usb_serial *serial;
+ struct urb *urb;
+ //__u16 Data;
+ const unsigned char *current_position = data;
+ unsigned char *data1;
+ dbg("%s \n", "entering ...........");
+ //dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",mos7840_port->shadowLCR);
+
+#ifdef NOTMOS7840
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
+ mos7840_port->shadowLCR = Data;
+ dbg("mos7840_write: LINE_CONTROL_REGISTER is %x\n", Data);
+ dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+
+ //Data = 0x03;
+ //status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data);
+ //mos7840_port->shadowLCR=Data;//Need to add later
+
+ Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ //Data = 0x0c;
+ //status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data);
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
+ dbg("mos7840_write:DLL value is %x\n", Data);
+
+ Data = 0x0;
+ status = 0;
+ status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
+ dbg("mos7840_write:DLM value is %x\n", Data);
+
+ Data = Data & ~SERIAL_LCR_DLAB;
+ dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+#endif
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return -1;
+ }
+
+ serial = port->serial;
+ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ if (mos7840_port == NULL) {
+ dbg("%s", "mos7840_port is NULL\n");
+ return -1;
+ }
+
+ /* try to find a free urb in the list */
+ urb = NULL;
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = mos7840_port->write_urb_pool[i];
+ dbg("\nURB:%d", i);
+ break;
+ }
+ }
+
+ if (urb == NULL) {
+ dbg("%s - no more free urbs", __FUNCTION__);
+ goto exit;
+ }
+
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer =
+ kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+
+ if (urb->transfer_buffer == NULL) {
+ err("%s no more kernel memory...", __FUNCTION__);
+ goto exit;
+ }
+ }
+ transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
+
+ if (from_user) {
+ if (copy_from_user
+ (urb->transfer_buffer, current_position, transfer_size)) {
+ bytes_sent = -EFAULT;
+ goto exit;
+ }
+ } else {
+ memcpy(urb->transfer_buffer, current_position, transfer_size);
+ }
+
+ /* fill urb with data and submit */
+ usb_fill_bulk_urb(urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer,
+ transfer_size,
+ mos7840_bulk_out_data_callback, mos7840_port);
+
+ data1 = urb->transfer_buffer;
+ dbg("\nbulkout endpoint is %d", port->bulk_out_endpointAddress);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (status) {
+ err("%s - usb_submit_urb(write bulk) failed with status = %d",
+ __FUNCTION__, status);
+ bytes_sent = status;
+ goto exit;
+ }
+ bytes_sent = transfer_size;
+ mos7840_port->icount.tx += transfer_size;
+ dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
+ exit:
+
+ return bytes_sent;
+
+}
+
+/*****************************************************************************
+ * mos7840_throttle
+ * this function is called by the tty driver when it wants to stop the data
+ * being read from the port.
+ *****************************************************************************/
+
+static void mos7840_throttle(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+ int status;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ dbg("- port %d\n", port->number);
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return;
+
+ if (!mos7840_port->open) {
+ dbg("%s\n", "port not opened");
+ return;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the stop character */
+ if (I_IXOFF(tty)) {
+ unsigned char stop_char = STOP_CHAR(tty);
+ status = mos7840_write(port, &stop_char, 1);
+ if (status <= 0) {
+ return;
+ }
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7840_port->shadowMCR &= ~MCR_RTS;
+ status = 0;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
+ mos7840_port->shadowMCR);
+
+ if (status < 0) {
+ return;
+ }
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_unthrottle
+ * this function is called by the tty driver when it wants to resume the data
+ * being read from the port (called after SerialThrottle is called)
+ *****************************************************************************/
+static void mos7840_unthrottle(struct usb_serial_port *port)
+{
+ struct tty_struct *tty;
+ int status;
+ struct moschip_port *mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ if (mos7840_port == NULL)
+ return;
+
+ if (!mos7840_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the start character */
+ if (I_IXOFF(tty)) {
+ unsigned char start_char = START_CHAR(tty);
+ status = mos7840_write(port, &start_char, 1);
+ if (status <= 0) {
+ return;
+ }
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7840_port->shadowMCR |= MCR_RTS;
+ status = 0;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
+ mos7840_port->shadowMCR);
+ if (status < 0) {
+ return;
+ }
+ }
+
+ return;
+}
+
+static int mos7840_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct moschip_port *mos7840_port;
+ unsigned int result;
+ __u16 msr;
+ __u16 mcr;
+ int status = 0;
+ mos7840_port = mos7840_get_port_private(port);
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (mos7840_port == NULL)
+ return -ENODEV;
+
+ status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
+ status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
+ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
+ | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
+ | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
+ | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0)
+ | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0)
+ | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
+ | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
+
+ dbg("%s - 0x%04X", __FUNCTION__, result);
+
+ return result;
+}
+
+static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct moschip_port *mos7840_port;
+ unsigned int mcr;
+ unsigned int status;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return -ENODEV;
+
+ mcr = mos7840_port->shadowMCR;
+ if (clear & TIOCM_RTS)
+ mcr &= ~MCR_RTS;
+ if (clear & TIOCM_DTR)
+ mcr &= ~MCR_DTR;
+ if (clear & TIOCM_LOOP)
+ mcr &= ~MCR_LOOPBACK;
+
+ if (set & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ if (set & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (set & TIOCM_LOOP)
+ mcr |= MCR_LOOPBACK;
+
+ mos7840_port->shadowMCR = mcr;
+
+ status = 0;
+ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
+ if (status < 0) {
+ dbg("setting MODEM_CONTROL_REGISTER Failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_calc_baud_rate_divisor
+ * this function calculates the proper baud rate divisor for the specified
+ * baud rate.
+ *****************************************************************************/
+static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
+ __u16 * clk_sel_val)
+{
+
+ dbg("%s - %d", __FUNCTION__, baudRate);
+
+ if (baudRate <= 115200) {
+ *divisor = 115200 / baudRate;
+ *clk_sel_val = 0x0;
+ }
+ if ((baudRate > 115200) && (baudRate <= 230400)) {
+ *divisor = 230400 / baudRate;
+ *clk_sel_val = 0x10;
+ } else if ((baudRate > 230400) && (baudRate <= 403200)) {
+ *divisor = 403200 / baudRate;
+ *clk_sel_val = 0x20;
+ } else if ((baudRate > 403200) && (baudRate <= 460800)) {
+ *divisor = 460800 / baudRate;
+ *clk_sel_val = 0x30;
+ } else if ((baudRate > 460800) && (baudRate <= 806400)) {
+ *divisor = 806400 / baudRate;
+ *clk_sel_val = 0x40;
+ } else if ((baudRate > 806400) && (baudRate <= 921600)) {
+ *divisor = 921600 / baudRate;
+ *clk_sel_val = 0x50;
+ } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
+ *divisor = 1572864 / baudRate;
+ *clk_sel_val = 0x60;
+ } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
+ *divisor = 3145728 / baudRate;
+ *clk_sel_val = 0x70;
+ }
+ return 0;
+
+#ifdef NOTMCS7840
+
+ for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
+ if (mos7840_divisor_table[i].BaudRate == baudrate) {
+ *divisor = mos7840_divisor_table[i].Divisor;
+ return 0;
+ }
+ }
+
+ /* After trying for all the standard baud rates *
+ * Try calculating the divisor for this baud rate */
+
+ if (baudrate > 75 && baudrate < 230400) {
+ /* get the divisor */
+ custom = (__u16) (230400L / baudrate);
+
+ /* Check for round off */
+ round1 = (__u16) (2304000L / baudrate);
+ round = (__u16) (round1 - (custom * 10));
+ if (round > 4) {
+ custom++;
+ }
+ *divisor = custom;
+
+ dbg(" Baud %d = %d\n", baudrate, custom);
+ return 0;
+ }
+
+ dbg("%s\n", " Baud calculation Failed...");
+ return -1;
+#endif
+}
+
+/*****************************************************************************
+ * mos7840_send_cmd_write_baud_rate
+ * this function sends the proper command to change the baud rate of the
+ * specified port.
+ *****************************************************************************/
+
+static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
+ int baudRate)
+{
+ int divisor = 0;
+ int status;
+ __u16 Data;
+ unsigned char number;
+ __u16 clk_sel_val;
+ struct usb_serial_port *port;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
+ dbg("%s", "Invalid Serial \n");
+ return -1;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ number = mos7840_port->port->number - mos7840_port->port->serial->minor;
+
+ dbg("%s - port = %d, baud = %d", __FUNCTION__,
+ mos7840_port->port->number, baudRate);
+ //reset clk_uart_sel in spregOffset
+ if (baudRate > 115200) {
+#ifdef HW_flow_control
+ //NOTE: need to see the pther register to modify
+ //setting h/w flow control bit to 1;
+ status = 0;
+ Data = 0x2b;
+ mos7840_port->shadowMCR = Data;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing spreg failed in set_serial_baud\n");
+ return -1;
+ }
+#endif
+
+ } else {
+#ifdef HW_flow_control
+ //setting h/w flow control bit to 0;
+ status = 0;
+ Data = 0xb;
+ mos7840_port->shadowMCR = Data;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing spreg failed in set_serial_baud\n");
+ return -1;
+ }
+#endif
+
+ }
+
+ if (1) //baudRate <= 115200)
+ {
+ clk_sel_val = 0x0;
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_calc_baud_rate_divisor(baudRate, &divisor,
+ &clk_sel_val);
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
+ &Data);
+ if (status < 0) {
+ dbg("reading spreg failed in set_serial_baud\n");
+ return -1;
+ }
+ Data = (Data & 0x8f) | clk_sel_val;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ if (status < 0) {
+ dbg("Writing spreg failed in set_serial_baud\n");
+ return -1;
+ }
+ /* Calculate the Divisor */
+
+ if (status) {
+ err("%s - bad baud rate", __FUNCTION__);
+ dbg("%s\n", "bad baud rate");
+ return status;
+ }
+ /* Enable access to divisor latch */
+ Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB;
+ mos7840_port->shadowLCR = Data;
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ /* Write the divisor */
+ Data = (unsigned char)(divisor & 0xff);
+ dbg("set_serial_baud Value to write DLL is %x\n", Data);
+ mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
+
+ Data = (unsigned char)((divisor & 0xff00) >> 8);
+ dbg("set_serial_baud Value to write DLM is %x\n", Data);
+ mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
+
+ /* Disable access to divisor latch */
+ Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB;
+ mos7840_port->shadowLCR = Data;
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ }
+
+ return status;
+}
+
+/*****************************************************************************
+ * mos7840_change_port_settings
+ * This routine is called to set the UART on the device to match
+ * the specified new settings.
+ *****************************************************************************/
+
+static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
+ struct termios *old_termios)
+{
+ struct tty_struct *tty;
+ int baud;
+ unsigned cflag;
+ unsigned iflag;
+ __u8 lData;
+ __u8 lParity;
+ __u8 lStop;
+ int status;
+ __u16 Data;
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+
+ if (mos7840_port == NULL)
+ return;
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
+ dbg("%s", "Invalid Serial \n");
+ return;
+ }
+
+ serial = port->serial;
+
+ dbg("%s - port %d", __FUNCTION__, mos7840_port->port->number);
+
+ if (!mos7840_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ tty = mos7840_port->port->tty;
+
+ if ((!tty) || (!tty->termios)) {
+ dbg("%s - no tty structures", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ lData = LCR_BITS_8;
+ lStop = LCR_STOP_1;
+ lParity = LCR_PAR_NONE;
+
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
+
+ /* Change the number of bits */
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5:
+ lData = LCR_BITS_5;
+ break;
+
+ case CS6:
+ lData = LCR_BITS_6;
+ break;
+
+ case CS7:
+ lData = LCR_BITS_7;
+ break;
+ default:
+ case CS8:
+ lData = LCR_BITS_8;
+ break;
+ }
+ }
+ /* Change the Parity bit */
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ lParity = LCR_PAR_ODD;
+ dbg("%s - parity = odd", __FUNCTION__);
+ } else {
+ lParity = LCR_PAR_EVEN;
+ dbg("%s - parity = even", __FUNCTION__);
+ }
+
+ } else {
+ dbg("%s - parity = none", __FUNCTION__);
+ }
+
+ if (cflag & CMSPAR) {
+ lParity = lParity | 0x20;
+ }
+
+ /* Change the Stop bit */
+ if (cflag & CSTOPB) {
+ lStop = LCR_STOP_2;
+ dbg("%s - stop bits = 2", __FUNCTION__);
+ } else {
+ lStop = LCR_STOP_1;
+ dbg("%s - stop bits = 1", __FUNCTION__);
+ }
+
+ /* Update the LCR with the correct value */
+ mos7840_port->shadowLCR &=
+ ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+ mos7840_port->shadowLCR |= (lData | lParity | lStop);
+
+ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+ /* Disable Interrupts */
+ Data = 0x00;
+ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ Data = 0x00;
+ mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+
+ Data = 0xcf;
+ mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+
+ /* Send the updated LCR value to the mos7840 */
+ Data = mos7840_port->shadowLCR;
+
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ Data = 0x00b;
+ mos7840_port->shadowMCR = Data;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ Data = 0x00b;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+
+ /* set up the MCR register and send it to the mos7840 */
+
+ mos7840_port->shadowMCR = MCR_MASTER_IE;
+ if (cflag & CBAUD) {
+ mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS);
+ }
+
+ if (cflag & CRTSCTS) {
+ mos7840_port->shadowMCR |= (MCR_XON_ANY);
+
+ } else {
+ mos7840_port->shadowMCR &= ~(MCR_XON_ANY);
+ }
+
+ Data = mos7840_port->shadowMCR;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(tty);
+
+ if (!baud) {
+ /* pick a default, any default... */
+ dbg("%s\n", "Picked default baud...");
+ baud = 9600;
+ }
+
+ dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
+
+ /* Enable Interrupts */
+ Data = 0x0c;
+ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ mos7840_port->read_urb->dev = serial->dev;
+
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+
+ if (status) {
+ dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ }
+ wake_up(&mos7840_port->delta_msr_wait);
+ mos7840_port->delta_msr_cond = 1;
+ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x\n",
+ mos7840_port->shadowLCR);
+
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_set_termios
+ * this function is called by the tty driver when it wants to change
+ * the termios structure
+ *****************************************************************************/
+
+static void mos7840_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ int status;
+ unsigned int cflag;
+ struct usb_serial *serial;
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+ dbg("mos7840_set_termios: START\n");
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ serial = port->serial;
+
+ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ dbg("%s", "Invalid Serial \n");
+ return;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return;
+
+ tty = port->tty;
+
+ if (!port->tty || !port->tty->termios) {
+ dbg("%s - no tty or termios", __FUNCTION__);
+ return;
+ }
+
+ if (!mos7840_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s\n", "setting termios - ");
+
+ cflag = tty->termios->c_cflag;
+
+ if (!cflag) {
+ dbg("%s %s\n", __FUNCTION__, "cflag is NULL");
+ return;
+ }
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("%s\n", "Nothing to change");
+ return;
+ }
+ }
+
+ dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
+
+ if (old_termios) {
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
+ }
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* change the port settings to the new ones specified */
+
+ mos7840_change_port_settings(mos7840_port, old_termios);
+
+ if (!mos7840_port->read_urb) {
+ dbg("%s", "URB KILLED !!!!!\n");
+ return;
+ }
+
+ if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ mos7840_port->read_urb->dev = serial->dev;
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+ if (status) {
+ dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ }
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ *****************************************************************************/
+
+static int mos7840_get_lsr_info(struct moschip_port *mos7840_port,
+ unsigned int *value)
+{
+ int count;
+ unsigned int result = 0;
+
+ count = mos7840_chars_in_buffer(mos7840_port->port);
+ if (count == 0) {
+ dbg("%s -- Empty", __FUNCTION__);
+ result = TIOCSER_TEMT;
+ }
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_get_bytes_avail - get number of bytes available
+ *
+ * Purpose: Let user call ioctl to get the count of number of bytes available.
+ *****************************************************************************/
+
+static int mos7840_get_bytes_avail(struct moschip_port *mos7840_port,
+ unsigned int *value)
+{
+ unsigned int result = 0;
+ struct tty_struct *tty = mos7840_port->port->tty;
+
+ if (!tty)
+ return -ENOIOCTLCMD;
+
+ result = tty->read_cnt;
+
+ dbg("%s(%d) = %d", __FUNCTION__, mos7840_port->port->number, result);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+
+ return -ENOIOCTLCMD;
+}
+
+/*****************************************************************************
+ * mos7840_set_modem_info
+ * function to set modem info
+ *****************************************************************************/
+
+static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
+ unsigned int cmd, unsigned int *value)
+{
+ unsigned int mcr;
+ unsigned int arg;
+ __u16 Data;
+ int status;
+ struct usb_serial_port *port;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ mcr = mos7840_port->shadowMCR;
+
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr |= MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr |= MCR_LOOPBACK;
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ mcr &= ~MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr &= ~MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr &= ~MCR_LOOPBACK;
+ break;
+
+ case TIOCMSET:
+ /* turn off the RTS and DTR and LOOPBACK
+ * and then only turn on what was asked to */
+ mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
+ mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
+ mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
+ mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
+ break;
+ }
+
+ mos7840_port->shadowMCR = mcr;
+
+ Data = mos7840_port->shadowMCR;
+ status = 0;
+ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("setting MODEM_CONTROL_REGISTER Failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_get_modem_info
+ * function to get modem info
+ *****************************************************************************/
+
+static int mos7840_get_modem_info(struct moschip_port *mos7840_port,
+ unsigned int *value)
+{
+ unsigned int result = 0;
+ __u16 msr;
+ unsigned int mcr = mos7840_port->shadowMCR;
+ int status = 0;
+ status =
+ mos7840_get_uart_reg(mos7840_port->port, MODEM_STATUS_REGISTER,
+ &msr);
+ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */
+ |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */
+ |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
+ |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */
+ |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
+ |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
+
+ dbg("%s -- %x", __FUNCTION__, result);
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_get_serial_info
+ * function to get information about serial port
+ *****************************************************************************/
+
+static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
+ struct serial_struct *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ tmp.type = PORT_16550A;
+ tmp.line = mos7840_port->port->serial->minor;
+ tmp.port = mos7840_port->port->number;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+ tmp.baud_base = 9600;
+ tmp.close_delay = 5 * HZ;
+ tmp.closing_wait = 30 * HZ;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+/*****************************************************************************
+ * SerialIoctl
+ * this function handles any ioctl calls to the driver
+ *****************************************************************************/
+
+static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+
+ struct async_icount cnow;
+ struct async_icount cprev;
+ struct serial_icounter_struct icount;
+ int mosret = 0;
+ int retval;
+ struct tty_ldisc *ld;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ tty = mos7840_port->port->tty;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+
+ switch (cmd) {
+ /* return number of bytes available */
+
+ case TIOCINQ:
+ dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
+ return mos7840_get_bytes_avail(mos7840_port,
+ (unsigned int *)arg);
+ break;
+
+ case TIOCOUTQ:
+ dbg("%s (%d) TIOCOUTQ", __FUNCTION__, port->number);
+ return put_user(tty->driver->chars_in_buffer ?
+ tty->driver->chars_in_buffer(tty) : 0,
+ (int __user *)arg);
+ break;
+
+ case TCFLSH:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ ld = tty_ldisc_ref(tty);
+ switch (arg) {
+ case TCIFLUSH:
+ if (ld && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ break;
+ case TCIOFLUSH:
+ if (ld && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ /* fall through */
+ case TCOFLUSH:
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ break;
+ default:
+ tty_ldisc_deref(ld);
+ return -EINVAL;
+ }
+ tty_ldisc_deref(ld);
+ return 0;
+
+ case TCGETS:
+ if (kernel_termios_to_user_termios
+ ((struct termios __user *)arg, tty->termios))
+ return -EFAULT;
+ return 0;
+
+ case TIOCSERGETLSR:
+ dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ return mos7840_get_lsr_info(mos7840_port, (unsigned int *)arg);
+ return 0;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+ port->number);
+ mosret =
+ mos7840_set_modem_info(mos7840_port, cmd,
+ (unsigned int *)arg);
+ return mosret;
+
+ case TIOCMGET:
+ dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+ return mos7840_get_modem_info(mos7840_port,
+ (unsigned int *)arg);
+
+ case TIOCGSERIAL:
+ dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ return mos7840_get_serial_info(mos7840_port,
+ (struct serial_struct *)arg);
+
+ case TIOCSSERIAL:
+ dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ break;
+
+ case TIOCMIWAIT:
+ dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ cprev = mos7840_port->icount;
+ while (1) {
+ //interruptible_sleep_on(&mos7840_port->delta_msr_wait);
+ mos7840_port->delta_msr_cond = 0;
+ wait_event_interruptible(mos7840_port->delta_msr_wait,
+ (mos7840_port->
+ delta_msr_cond == 1));
+
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ cnow = mos7840_port->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ break;
+
+ case TIOCGICOUNT:
+ cnow = mos7840_port->icount;
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ port->number, icount.rx, icount.tx);
+ if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+ return -EFAULT;
+ return 0;
+
+ case TIOCEXBAUD:
+ return 0;
+ default:
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+
+ dbg("numberofendpoints: %d \n",
+ (int)serial->interface->cur_altsetting->desc.bNumEndpoints);
+ dbg("numberofendpoints: %d \n",
+ (int)serial->interface->altsetting->desc.bNumEndpoints);
+ if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
+ mos7840_num_ports = 2;
+ serial->type->num_ports = 2;
+ } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) {
+ mos7840_num_ports = 4;
+ serial->type->num_bulk_in = 4;
+ serial->type->num_bulk_out = 4;
+ serial->type->num_ports = 4;
+ }
+
+ return mos7840_num_ports;
+}
+
+/****************************************************************************
+ * mos7840_startup
+ ****************************************************************************/
+
+static int mos7840_startup(struct usb_serial *serial)
+{
+ struct moschip_port *mos7840_port;
+ struct usb_device *dev;
+ int i, status;
+
+ __u16 Data;
+ dbg("%s \n", " mos7840_startup :entering..........");
+
+ if (!serial) {
+ dbg("%s\n", "Invalid Handler");
+ return -1;
+ }
+
+ dev = serial->dev;
+
+ dbg("%s\n", "Entering...");
+
+ /* we set up the pointers to the endpoints in the mos7840_open *
+ * function, as the structures aren't created yet. */
+
+ /* set up port private structures */
+ for (i = 0; i < serial->num_ports; ++i) {
+ mos7840_port = kmalloc(sizeof(struct moschip_port), GFP_KERNEL);
+ if (mos7840_port == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ return -ENOMEM;
+ }
+ memset(mos7840_port, 0, sizeof(struct moschip_port));
+
+ /* Initialize all port interrupt end point to port 0 int endpoint *
+ * Our device has only one interrupt end point comman to all port */
+
+ mos7840_port->port = serial->port[i];
+ mos7840_set_port_private(serial->port[i], mos7840_port);
+
+ mos7840_port->port_num = ((serial->port[i]->number -
+ (serial->port[i]->serial->minor)) +
+ 1);
+
+ if (mos7840_port->port_num == 1) {
+ mos7840_port->SpRegOffset = 0x0;
+ mos7840_port->ControlRegOffset = 0x1;
+ mos7840_port->DcrRegOffset = 0x4;
+ } else if ((mos7840_port->port_num == 2)
+ && (mos7840_num_ports == 4)) {
+ mos7840_port->SpRegOffset = 0x8;
+ mos7840_port->ControlRegOffset = 0x9;
+ mos7840_port->DcrRegOffset = 0x16;
+ } else if ((mos7840_port->port_num == 2)
+ && (mos7840_num_ports == 2)) {
+ mos7840_port->SpRegOffset = 0xa;
+ mos7840_port->ControlRegOffset = 0xb;
+ mos7840_port->DcrRegOffset = 0x19;
+ } else if ((mos7840_port->port_num == 3)
+ && (mos7840_num_ports == 4)) {
+ mos7840_port->SpRegOffset = 0xa;
+ mos7840_port->ControlRegOffset = 0xb;
+ mos7840_port->DcrRegOffset = 0x19;
+ } else if ((mos7840_port->port_num == 4)
+ && (mos7840_num_ports == 4)) {
+ mos7840_port->SpRegOffset = 0xc;
+ mos7840_port->ControlRegOffset = 0xd;
+ mos7840_port->DcrRegOffset = 0x1c;
+ }
+ mos7840_dump_serial_port(mos7840_port);
+
+ mos7840_set_port_private(serial->port[i], mos7840_port);
+
+ //enable rx_disable bit in control register
+
+ status =
+ mos7840_get_reg_sync(serial->port[i],
+ mos7840_port->ControlRegOffset, &Data);
+ if (status < 0) {
+ dbg("Reading ControlReg failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("ControlReg Reading success val is %x, status%d\n",
+ Data, status);
+ Data |= 0x08; //setting driver done bit
+ Data |= 0x04; //sp1_bit to have cts change reflect in modem status reg
+
+ //Data |= 0x20; //rx_disable bit
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ mos7840_port->ControlRegOffset, Data);
+ if (status < 0) {
+ dbg("Writing ControlReg failed(rx_disable) status-0x%x\n", status);
+ break;
+ } else
+ dbg("ControlReg Writing success(rx_disable) status%d\n",
+ status);
+
+ //Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 and 0x24 in DCR3
+ Data = 0x01;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ (__u16) (mos7840_port->DcrRegOffset +
+ 0), Data);
+ if (status < 0) {
+ dbg("Writing DCR0 failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("DCR0 Writing success status%d\n", status);
+
+ Data = 0x05;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ (__u16) (mos7840_port->DcrRegOffset +
+ 1), Data);
+ if (status < 0) {
+ dbg("Writing DCR1 failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("DCR1 Writing success status%d\n", status);
+
+ Data = 0x24;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ (__u16) (mos7840_port->DcrRegOffset +
+ 2), Data);
+ if (status < 0) {
+ dbg("Writing DCR2 failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("DCR2 Writing success status%d\n", status);
+
+ // write values in clkstart0x0 and clkmulti 0x20
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ CLK_START_VALUE_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status);
+
+ Data = 0x20;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER,
+ Data);
+ if (status < 0) {
+ dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n",
+ status);
+ break;
+ } else
+ dbg("CLK_MULTI_REGISTER Writing success status%d\n",
+ status);
+
+ //write value 0x0 to scratchpad register
+ Data = 0x00;
+ status = 0;
+ status =
+ mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER,
+ Data);
+ if (status < 0) {
+ dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n",
+ status);
+ break;
+ } else
+ dbg("SCRATCH_PAD_REGISTER Writing success status%d\n",
+ status);
+
+ //Zero Length flag register
+ if ((mos7840_port->port_num != 1)
+ && (mos7840_num_ports == 2)) {
+
+ Data = 0xff;
+ status = 0;
+ status = mos7840_set_reg_sync(serial->port[i],
+ (__u16) (ZLP_REG1 +
+ ((__u16)
+ mos7840_port->
+ port_num)),
+ Data);
+ dbg("ZLIP offset%x\n",
+ (__u16) (ZLP_REG1 +
+ ((__u16) mos7840_port->port_num)));
+ if (status < 0) {
+ dbg("Writing ZLP_REG%d failed status-0x%x\n",
+ i + 2, status);
+ break;
+ } else
+ dbg("ZLP_REG%d Writing success status%d\n",
+ i + 2, status);
+ } else {
+ Data = 0xff;
+ status = 0;
+ status = mos7840_set_reg_sync(serial->port[i],
+ (__u16) (ZLP_REG1 +
+ ((__u16)
+ mos7840_port->
+ port_num) -
+ 0x1), Data);
+ dbg("ZLIP offset%x\n",
+ (__u16) (ZLP_REG1 +
+ ((__u16) mos7840_port->port_num) - 0x1));
+ if (status < 0) {
+ dbg("Writing ZLP_REG%d failed status-0x%x\n",
+ i + 1, status);
+ break;
+ } else
+ dbg("ZLP_REG%d Writing success status%d\n",
+ i + 1, status);
+
+ }
+ mos7840_port->control_urb = usb_alloc_urb(0, SLAB_ATOMIC);
+ mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
+
+ }
+
+ //Zero Length flag enable
+ Data = 0x0f;
+ status = 0;
+ status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
+ if (status < 0) {
+ dbg("Writing ZLP_REG5 failed status-0x%x\n", status);
+ return -1;
+ } else
+ dbg("ZLP_REG5 Writing success status%d\n", status);
+
+ /* setting configuration feature to one */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ (__u8) 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 5 * HZ);
+ return 0;
+}
+
+/****************************************************************************
+ * mos7840_shutdown
+ * This function is called whenever the device is removed from the usb bus.
+ ****************************************************************************/
+
+static void mos7840_shutdown(struct usb_serial *serial)
+{
+ int i;
+ struct moschip_port *mos7840_port;
+ dbg("%s \n", " shutdown :entering..........");
+
+ if (!serial) {
+ dbg("%s", "Invalid Handler \n");
+ return;
+ }
+
+ /* check for the ports to be closed,close the ports and disconnect */
+
+ /* free private structure allocated for serial port *
+ * stop reads and writes on all ports */
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ mos7840_port = mos7840_get_port_private(serial->port[i]);
+ kfree(mos7840_port->ctrl_buf);
+ usb_kill_urb(mos7840_port->control_urb);
+ kfree(mos7840_port);
+ mos7840_set_port_private(serial->port[i], NULL);
+ }
+
+ dbg("%s\n", "Thank u :: ");
+
+}
+
+static struct usb_serial_driver moschip7840_4port_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mos7840",
+ },
+ .description = DRIVER_DESC,
+ .id_table = moschip_port_id_table,
+ .num_interrupt_in = 1, //NUM_DONT_CARE,//1,
+#ifdef check
+ .num_bulk_in = 4,
+ .num_bulk_out = 4,
+ .num_ports = 4,
+#endif
+ .open = mos7840_open,
+ .close = mos7840_close,
+ .write = mos7840_write,
+ .write_room = mos7840_write_room,
+ .chars_in_buffer = mos7840_chars_in_buffer,
+ .throttle = mos7840_throttle,
+ .unthrottle = mos7840_unthrottle,
+ .calc_num_ports = mos7840_calc_num_ports,
+#ifdef MCSSerialProbe
+ .probe = mos7840_serial_probe,
+#endif
+ .ioctl = mos7840_ioctl,
+ .set_termios = mos7840_set_termios,
+ .break_ctl = mos7840_break,
+ .tiocmget = mos7840_tiocmget,
+ .tiocmset = mos7840_tiocmset,
+ .attach = mos7840_startup,
+ .shutdown = mos7840_shutdown,
+ .read_bulk_callback = mos7840_bulk_in_callback,
+ .read_int_callback = mos7840_interrupt_callback,
+};
+
+static struct usb_driver io_driver = {
+ .name = "mos7840",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_id_table_combined,
+};
+
+/****************************************************************************
+ * moschip7840_init
+ * This is called by the module subsystem, or on startup to initialize us
+ ****************************************************************************/
+static int __init moschip7840_init(void)
+{
+ int retval;
+
+ dbg("%s \n", " mos7840_init :entering..........");
+
+ /* Register with the usb serial */
+ retval = usb_serial_register(&moschip7840_4port_device);
+
+ if (retval)
+ goto failed_port_device_register;
+
+ dbg("%s\n", "Entring...");
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ /* Register with the usb */
+ retval = usb_register(&io_driver);
+
+ if (retval)
+ goto failed_usb_register;
+
+ if (retval == 0) {
+ dbg("%s\n", "Leaving...");
+ return 0;
+ }
+
+ failed_usb_register:
+ usb_serial_deregister(&moschip7840_4port_device);
+
+ failed_port_device_register:
+
+ return retval;
+}
+
+/****************************************************************************
+ * moschip7840_exit
+ * Called when the driver is about to be unloaded.
+ ****************************************************************************/
+static void __exit moschip7840_exit(void)
+{
+
+ dbg("%s \n", " mos7840_exit :entering..........");
+
+ usb_deregister(&io_driver);
+
+ usb_serial_deregister(&moschip7840_4port_device);
+
+ dbg("%s\n", "Entring...");
+}
+
+module_init(moschip7840_init);
+module_exit(moschip7840_exit);
+
+/* Module information */
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 7f544081032..ac3f8b5d2c4 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -14,7 +14,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 6dcdb5f598b..a764ff4e326 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -35,7 +35,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -47,7 +46,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
static int debug;
@@ -257,14 +256,14 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
return (0);
}
- spin_lock(&wport->lock);
+ spin_lock_bh(&wport->lock);
if (wport->write_urb_busy) {
- spin_unlock(&wport->lock);
+ spin_unlock_bh(&wport->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
wport->write_urb_busy = 1;
- spin_unlock(&wport->lock);
+ spin_unlock_bh(&wport->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index b0861b61bba..c856e6f40e2 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -9,39 +9,14 @@
Portions copied from the Keyspan driver by Hugh Blemings <hugh@blemings.org>
- History:
-
- 2005-05-19 v0.1 Initial version, based on incomplete docs
- and analysis of misbehavior with the standard driver
- 2005-05-20 v0.2 Extended the input buffer to avoid losing
- random 64-byte chunks of data
- 2005-05-21 v0.3 implemented chars_in_buffer()
- turned on low_latency
- simplified the code somewhat
- 2005-05-24 v0.4 option_write() sometimes deadlocked under heavy load
- removed some dead code
- added sponsor notice
- coding style clean-up
- 2005-06-20 v0.4.1 add missing braces :-/
- killed end-of-line whitespace
- 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2
- 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard
- 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes
- wants to send >2000 bytes.
- 2006-04-10 v0.5 fixed two array overrun errors :-/
- 2006-04-21 v0.5.1 added support for Sierra Wireless MC8755
- 2006-05-15 v0.6 re-enable multi-port support
- 2006-06-01 v0.6.1 add COBRA
- 2006-06-01 v0.6.2 add backwards-compatibility stuff
- 2006-06-01 v0.6.3 add Novatel Wireless
- 2006-06-01 v0.7 Option => GSM
+ History: see the git log.
Work sponsored by: Sigos GmbH, Germany <info@sigos.de>
This driver exists because the "normal" serial driver doesn't work too well
with GSM modems. Issues:
- data loss -- one single Receive URB is not nearly enough
- - nonstandard flow (Option devices) and multiplex (Sierra) control
+ - nonstandard flow (Option devices) control
- controlling the baud rate doesn't make sense
This driver is named "option" because the most common device it's
@@ -53,11 +28,10 @@
device features.
*/
-#define DRIVER_VERSION "v0.7.0"
+#define DRIVER_VERSION "v0.7.1"
#define DRIVER_AUTHOR "Matthias Urlichs <smurf@smurf.noris.de>"
#define DRIVER_DESC "USB Driver for GSM modems"
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/errno.h>
@@ -65,7 +39,7 @@
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
/* Function prototypes */
static int option_open(struct usb_serial_port *port, struct file *filp);
@@ -96,27 +70,29 @@ static int option_send_setup(struct usb_serial_port *port);
#define OPTION_VENDOR_ID 0x0AF0
#define HUAWEI_VENDOR_ID 0x12D1
#define AUDIOVOX_VENDOR_ID 0x0F3D
-#define SIERRAWIRELESS_VENDOR_ID 0x1199
#define NOVATELWIRELESS_VENDOR_ID 0x1410
+#define ANYDATA_VENDOR_ID 0x16d5
#define OPTION_PRODUCT_OLD 0x5000
#define OPTION_PRODUCT_FUSION 0x6000
#define OPTION_PRODUCT_FUSION2 0x6300
#define OPTION_PRODUCT_COBRA 0x6500
+#define OPTION_PRODUCT_COBRA2 0x6600
#define HUAWEI_PRODUCT_E600 0x1001
#define AUDIOVOX_PRODUCT_AIRCARD 0x0112
-#define SIERRAWIRELESS_PRODUCT_MC8755 0x6802
#define NOVATELWIRELESS_PRODUCT_U740 0x1400
+#define ANYDATA_PRODUCT_ID 0x6501
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
- { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -125,13 +101,11 @@ static struct usb_device_id option_ids1[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) },
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA) },
+ { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COBRA2) },
{ USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) },
{ USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID,NOVATELWIRELESS_PRODUCT_U740) },
- { } /* Terminating entry */
-};
-static struct usb_device_id option_ids3[] = {
- { USB_DEVICE(SIERRAWIRELESS_VENDOR_ID, SIERRAWIRELESS_PRODUCT_MC8755) },
+ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ID) },
{ } /* Terminating entry */
};
@@ -148,37 +122,11 @@ static struct usb_driver option_driver = {
/* The card has three separate interfaces, which the serial driver
* recognizes separately, thus num_port=1.
*/
-static struct usb_serial_driver option_3port_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "option",
- },
- .description = "GSM modem (3-port)",
- .id_table = option_ids3,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 3,
- .open = option_open,
- .close = option_close,
- .write = option_write,
- .write_room = option_write_room,
- .chars_in_buffer = option_chars_in_buffer,
- .throttle = option_rx_throttle,
- .unthrottle = option_rx_unthrottle,
- .set_termios = option_set_termios,
- .break_ctl = option_break_ctl,
- .tiocmget = option_tiocmget,
- .tiocmset = option_tiocmset,
- .attach = option_startup,
- .shutdown = option_shutdown,
- .read_int_callback = option_instat_callback,
-};
static struct usb_serial_driver option_1port_device = {
.driver = {
.owner = THIS_MODULE,
- .name = "option",
+ .name = "option1",
},
.description = "GSM modem (1-port)",
.id_table = option_ids1,
@@ -242,9 +190,6 @@ static int __init option_init(void)
retval = usb_serial_register(&option_1port_device);
if (retval)
goto failed_1port_device_register;
- retval = usb_serial_register(&option_3port_device);
- if (retval)
- goto failed_3port_device_register;
retval = usb_register(&option_driver);
if (retval)
goto failed_driver_register;
@@ -254,8 +199,6 @@ static int __init option_init(void)
return 0;
failed_driver_register:
- usb_serial_deregister (&option_3port_device);
-failed_3port_device_register:
usb_serial_deregister (&option_1port_device);
failed_1port_device_register:
return retval;
@@ -264,7 +207,6 @@ failed_1port_device_register:
static void __exit option_exit(void)
{
usb_deregister (&option_driver);
- usb_serial_deregister (&option_3port_device);
usb_serial_deregister (&option_1port_device);
}
@@ -653,7 +595,6 @@ static void option_setup_urbs(struct usb_serial *serial)
dbg("%s", __FUNCTION__);
-
for (i = 0; i < serial->num_ports; i++) {
port = serial->port[i];
portdata = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index d8870438720..9c18173e33f 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -14,7 +14,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -28,7 +27,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "pl2303.h"
/*
@@ -53,6 +52,7 @@ struct pl2303_buf {
static struct usb_device_id id_table [] = {
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
+ { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ3) },
{ USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_PHAROS) },
{ USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) },
@@ -79,11 +79,14 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SAGEM_VENDOR_ID, SAGEM_PRODUCT_ID) },
{ USB_DEVICE(LEADTEK_VENDOR_ID, LEADTEK_9531_PRODUCT_ID) },
{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
- { USB_DEVICE(OTI_VENDOR_ID, OTI_PRODUCT_ID) },
+ { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
+ { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
+ { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_driver pl2303_driver = {
.name = "pl2303",
@@ -126,65 +129,6 @@ static struct usb_driver pl2303_driver = {
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
-/* function prototypes for a PL2303 serial converter */
-static int pl2303_open (struct usb_serial_port *port, struct file *filp);
-static void pl2303_close (struct usb_serial_port *port, struct file *filp);
-static void pl2303_set_termios (struct usb_serial_port *port,
- struct termios *old);
-static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg);
-static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);
-static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static int pl2303_write (struct usb_serial_port *port,
- const unsigned char *buf, int count);
-static void pl2303_send (struct usb_serial_port *port);
-static int pl2303_write_room(struct usb_serial_port *port);
-static int pl2303_chars_in_buffer(struct usb_serial_port *port);
-static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
-static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
-static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
- unsigned int set, unsigned int clear);
-static int pl2303_startup (struct usb_serial *serial);
-static void pl2303_shutdown (struct usb_serial *serial);
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
-static void pl2303_buf_free(struct pl2303_buf *pb);
-static void pl2303_buf_clear(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
- unsigned int count);
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
- unsigned int count);
-
-
-/* All of the device info needed for the PL2303 SIO serial converter */
-static struct usb_serial_driver pl2303_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "pl2303",
- },
- .id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = pl2303_open,
- .close = pl2303_close,
- .write = pl2303_write,
- .ioctl = pl2303_ioctl,
- .break_ctl = pl2303_break_ctl,
- .set_termios = pl2303_set_termios,
- .tiocmget = pl2303_tiocmget,
- .tiocmset = pl2303_tiocmset,
- .read_bulk_callback = pl2303_read_bulk_callback,
- .read_int_callback = pl2303_read_int_callback,
- .write_bulk_callback = pl2303_write_bulk_callback,
- .write_room = pl2303_write_room,
- .chars_in_buffer = pl2303_chars_in_buffer,
- .attach = pl2303_startup,
- .shutdown = pl2303_shutdown,
-};
enum pl2303_type {
type_0, /* don't know the difference between type 0 and */
@@ -203,8 +147,166 @@ struct pl2303_private {
enum pl2303_type type;
};
+/*
+ * pl2303_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+{
+ struct pl2303_buf *pb;
+
+ if (size == 0)
+ return NULL;
+
+ pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ if (pb == NULL)
+ return NULL;
+
+ pb->buf_buf = kmalloc(size, GFP_KERNEL);
+ if (pb->buf_buf == NULL) {
+ kfree(pb);
+ return NULL;
+ }
+
+ pb->buf_size = size;
+ pb->buf_get = pb->buf_put = pb->buf_buf;
-static int pl2303_startup (struct usb_serial *serial)
+ return pb;
+}
+
+/*
+ * pl2303_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void pl2303_buf_free(struct pl2303_buf *pb)
+{
+ if (pb) {
+ kfree(pb->buf_buf);
+ kfree(pb);
+ }
+}
+
+/*
+ * pl2303_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void pl2303_buf_clear(struct pl2303_buf *pb)
+{
+ if (pb != NULL)
+ pb->buf_get = pb->buf_put;
+ /* equivalent to a get of all data available */
+}
+
+/*
+ * pl2303_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+{
+ if (pb == NULL)
+ return 0;
+
+ return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
+}
+
+/*
+ * pl2303_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+{
+ if (pb == NULL)
+ return 0;
+
+ return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
+}
+
+/*
+ * pl2303_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_space_avail(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_put;
+ if (count > len) {
+ memcpy(pb->buf_put, buf, len);
+ memcpy(pb->buf_buf, buf+len, count - len);
+ pb->buf_put = pb->buf_buf + count - len;
+ } else {
+ memcpy(pb->buf_put, buf, count);
+ if (count < len)
+ pb->buf_put += count;
+ else /* count == len */
+ pb->buf_put = pb->buf_buf;
+ }
+
+ return count;
+}
+
+/*
+ * pl2303_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_data_avail(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_get;
+ if (count > len) {
+ memcpy(buf, pb->buf_get, len);
+ memcpy(buf+len, pb->buf_buf, count - len);
+ pb->buf_get = pb->buf_buf + count - len;
+ } else {
+ memcpy(buf, pb->buf_get, count);
+ if (count < len)
+ pb->buf_get += count;
+ else /* count == len */
+ pb->buf_get = pb->buf_buf;
+ }
+
+ return count;
+}
+
+static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_private *priv;
enum pl2303_type type = type_0;
@@ -246,36 +348,17 @@ cleanup:
return -ENOMEM;
}
-static int set_control_lines (struct usb_device *dev, u8 value)
+static int set_control_lines(struct usb_device *dev, u8 value)
{
int retval;
- retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
- SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
- value, 0, NULL, 0, 100);
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
+ value, 0, NULL, 0, 100);
dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
return retval;
}
-static int pl2303_write (struct usb_serial_port *port, const unsigned char *buf, int count)
-{
- struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
-
- dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
-
- if (!count)
- return count;
-
- spin_lock_irqsave(&priv->lock, flags);
- count = pl2303_buf_put(priv->buf, buf, count);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- pl2303_send(port);
-
- return count;
-}
-
static void pl2303_send(struct usb_serial_port *port)
{
int count, result;
@@ -292,7 +375,7 @@ static void pl2303_send(struct usb_serial_port *port)
}
count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
- port->bulk_out_size);
+ port->bulk_out_size);
if (count == 0) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -303,13 +386,15 @@ static void pl2303_send(struct usb_serial_port *port)
spin_unlock_irqrestore(&priv->lock, flags);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
+ port->write_urb->transfer_buffer);
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting write urb,"
+ " error %d\n", __FUNCTION__, result);
priv->write_urb_in_use = 0;
// TODO: reschedule pl2303_send
}
@@ -317,6 +402,26 @@ static void pl2303_send(struct usb_serial_port *port)
usb_serial_port_softint(port);
}
+static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
+ int count)
+{
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+
+ if (!count)
+ return count;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ count = pl2303_buf_put(priv->buf, buf, count);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ pl2303_send(port);
+
+ return count;
+}
+
static int pl2303_write_room(struct usb_serial_port *port)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -349,7 +454,8 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port)
return chars;
}
-static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void pl2303_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -370,7 +476,8 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
- port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
+ HUPCL | CLOCAL;
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -379,24 +486,24 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("%s - nothing to change...", __FUNCTION__);
+ return;
}
}
- buf = kzalloc (7, GFP_KERNEL);
+ buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return;
}
-
- i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CSIZE) {
switch (cflag & CSIZE) {
@@ -428,7 +535,8 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
default:
- dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n");
+ dev_err(&port->dev, "pl2303 driver does not support"
+ " the baudrate requested (fix it)\n");
break;
}
dbg("%s - baud = %d", __FUNCTION__, baud);
@@ -468,10 +576,10 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
dbg("%s - parity = none", __FUNCTION__);
}
- i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
- SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dbg ("0x21:0x20:0:0 %d", i);
+ i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ dbg("0x21:0x20:0:0 %d", i);
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
@@ -487,13 +595,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
-
+
buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
- i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CRTSCTS) {
@@ -502,18 +610,82 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
index = 0x61;
else
index = 0x41;
- i = usb_control_msg(serial->dev,
+ i = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST,
VENDOR_WRITE_REQUEST_TYPE,
0x0, index, NULL, 0, 100);
- dbg ("0x40:0x1:0x0:0x%x %d", index, i);
+ dbg("0x40:0x1:0x0:0x%x %d", index, i);
+ }
+
+ kfree(buf);
+}
+
+static void pl2303_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int c_cflag;
+ int bps;
+ long timeout;
+ wait_queue_t wait;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* wait for data to drain from the buffer */
+ spin_lock_irqsave(&priv->lock, flags);
+ timeout = PL2303_CLOSING_WAIT;
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&port->tty->write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (pl2303_buf_data_avail(priv->buf) == 0 ||
+ timeout == 0 || signal_pending(current) ||
+ !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ break;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irqsave(&priv->lock, flags);
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->tty->write_wait, &wait);
+ /* clear out any remaining data in the buffer */
+ pl2303_buf_clear(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wait for characters to drain from the device */
+ /* (this is long enough for the entire 256 byte */
+ /* pl2303 hardware buffer to drain with no flow */
+ /* control for data rates of 1200 bps or more, */
+ /* for lower rates we should really know how much */
+ /* data is in the buffer to compute a delay */
+ /* that is not unnecessarily long) */
+ bps = tty_get_baud_rate(port->tty);
+ if (bps > 1200)
+ timeout = max((HZ*2560)/bps,HZ/10);
+ else
+ timeout = 2*HZ;
+ schedule_timeout_interruptible(timeout);
- kfree (buf);
+ /* shutdown our urbs */
+ dbg("%s - shutting down urbs", __FUNCTION__);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+
+ if (port->tty) {
+ c_cflag = port->tty->termios->c_cflag;
+ if (c_cflag & HUPCL) {
+ /* drop DTR and RTS */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_control = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_control_lines(port->serial->dev, 0);
+ }
+ }
}
-static int pl2303_open (struct usb_serial_port *port, struct file *filp)
+static int pl2303_open(struct usb_serial_port *port, struct file *filp)
{
struct termios tmp_termios;
struct usb_serial *serial = port->serial;
@@ -567,98 +739,35 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
/* Setup termios */
if (port->tty) {
- pl2303_set_termios (port, &tmp_termios);
+ pl2303_set_termios(port, &tmp_termios);
}
//FIXME: need to assert RTS and DTR if CRTSCTS off
dbg("%s - submitting read urb", __FUNCTION__);
port->read_urb->dev = serial->dev;
- result = usb_submit_urb (port->read_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
- pl2303_close (port, NULL);
+ dev_err(&port->dev, "%s - failed submitting read urb,"
+ " error %d\n", __FUNCTION__, result);
+ pl2303_close(port, NULL);
return -EPROTO;
}
dbg("%s - submitting interrupt urb", __FUNCTION__);
port->interrupt_in_urb->dev = serial->dev;
- result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
- dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result);
- pl2303_close (port, NULL);
+ dev_err(&port->dev, "%s - failed submitting interrupt urb,"
+ " error %d\n", __FUNCTION__, result);
+ pl2303_close(port, NULL);
return -EPROTO;
}
return 0;
}
-
-static void pl2303_close (struct usb_serial_port *port, struct file *filp)
-{
- struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int c_cflag;
- int bps;
- long timeout;
- wait_queue_t wait;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- /* wait for data to drain from the buffer */
- spin_lock_irqsave(&priv->lock, flags);
- timeout = PL2303_CLOSING_WAIT;
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&port->tty->write_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (pl2303_buf_data_avail(priv->buf) == 0
- || timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
- break;
- spin_unlock_irqrestore(&priv->lock, flags);
- timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&priv->lock, flags);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&port->tty->write_wait, &wait);
- /* clear out any remaining data in the buffer */
- pl2303_buf_clear(priv->buf);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* wait for characters to drain from the device */
- /* (this is long enough for the entire 256 byte */
- /* pl2303 hardware buffer to drain with no flow */
- /* control for data rates of 1200 bps or more, */
- /* for lower rates we should really know how much */
- /* data is in the buffer to compute a delay */
- /* that is not unnecessarily long) */
- bps = tty_get_baud_rate(port->tty);
- if (bps > 1200)
- timeout = max((HZ*2560)/bps,HZ/10);
- else
- timeout = 2*HZ;
- schedule_timeout_interruptible(timeout);
-
- /* shutdown our urbs */
- dbg("%s - shutting down urbs", __FUNCTION__);
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
-
- if (port->tty) {
- c_cflag = port->tty->termios->c_cflag;
- if (c_cflag & HUPCL) {
- /* drop DTR and RTS */
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_control = 0;
- spin_unlock_irqrestore (&priv->lock, flags);
- set_control_lines (port->serial->dev, 0);
- }
- }
-}
-
-static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
- unsigned int set, unsigned int clear)
+static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
@@ -667,7 +776,7 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
if (set & TIOCM_DTR)
@@ -677,12 +786,12 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR;
control = priv->line_control;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
- return set_control_lines (port->serial->dev, control);
+ return set_control_lines(port->serial->dev, control);
}
-static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
+static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
@@ -695,10 +804,10 @@ static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
@@ -720,22 +829,22 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
unsigned int status;
unsigned int changed;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
prevstatus = priv->line_status;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
interruptible_sleep_on(&priv->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
-
- spin_lock_irqsave (&priv->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
status = priv->line_status;
- spin_unlock_irqrestore (&priv->lock, flags);
-
+ spin_unlock_irqrestore(&priv->lock, flags);
+
changed=prevstatus^status;
-
+
if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
((arg & TIOCM_CD) && (changed & UART_DCD)) ||
@@ -748,7 +857,8 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
return 0;
}
-static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
+static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
@@ -765,7 +875,7 @@ static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsign
return -ENOIOCTLCMD;
}
-static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
+static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
{
struct usb_serial *serial = port->serial;
u16 state;
@@ -779,15 +889,14 @@ static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
state = BREAK_ON;
dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
- result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
- BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
- 0, NULL, 0, 100);
+ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
+ 0, NULL, 0, 100);
if (result)
dbg("%s - error sending break = %d", __FUNCTION__, result);
}
-
-static void pl2303_shutdown (struct usb_serial *serial)
+static void pl2303_shutdown(struct usb_serial *serial)
{
int i;
struct pl2303_private *priv;
@@ -801,7 +910,7 @@ static void pl2303_shutdown (struct usb_serial *serial)
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
- }
+ }
}
static void pl2303_update_line_status(struct usb_serial_port *port,
@@ -813,29 +922,33 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
unsigned long flags;
u8 status_idx = UART_STATE;
u8 length = UART_STATE + 1;
+ u16 idv, idp;
+
+ idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
+ idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
- if ((le16_to_cpu(port->serial->dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
- (le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X65 ||
- le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_SX1 ||
- le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X75)) {
- length = 1;
- status_idx = 0;
+
+ if (idv == SIEMENS_VENDOR_ID) {
+ if (idp == SIEMENS_PRODUCT_ID_X65 ||
+ idp == SIEMENS_PRODUCT_ID_SX1 ||
+ idp == SIEMENS_PRODUCT_ID_X75) {
+
+ length = 1;
+ status_idx = 0;
+ }
}
if (actual_length < length)
- goto exit;
+ return;
/* Save off the uart status for others to look at */
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = data[status_idx];
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible (&priv->delta_msr_wait);
-
-exit:
- return;
+ wake_up_interruptible(&priv->delta_msr_wait);
}
-static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void pl2303_read_int_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -852,25 +965,29 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
goto exit;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ urb->actual_length, urb->transfer_buffer);
+
pl2303_update_line_status(port, data, actual_length);
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
- dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
+ dev_err(&urb->dev->dev,
+ "%s - usb_submit_urb failed with result %d\n",
__FUNCTION__, status);
}
-
-static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void pl2303_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -891,20 +1008,25 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
if (urb->status == -EPROTO) {
- /* PL2303 mysteriously fails with -EPROTO reschedule the read */
- dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
+ /* PL2303 mysteriously fails with -EPROTO reschedule
+ * the read */
+ dbg("%s - caught -EPROTO, resubmitting the urb",
+ __FUNCTION__);
urb->status = 0;
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed"
+ " resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
return;
}
dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ urb->actual_length, data);
/* get tty_flag from status */
tty_flag = TTY_NORMAL;
@@ -913,7 +1035,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible (&priv->delta_msr_wait);
+ wake_up_interruptible(&priv->delta_msr_wait);
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
@@ -932,8 +1054,8 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
if (status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
for (i = 0; i < urb->actual_length; ++i)
- tty_insert_flip_char (tty, data[i], tty_flag);
- tty_flip_buffer_push (tty);
+ tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_flip_buffer_push(tty);
}
/* Schedule the next read _if_ we are still open */
@@ -941,15 +1063,14 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed resubmitting"
+ " read urb, error %d\n", __FUNCTION__, result);
}
return;
}
-
-
-static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void pl2303_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -965,18 +1086,21 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
priv->write_urb_in_use = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
dbg("%s - Overflow in write", __FUNCTION__);
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
+ urb->status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed resubmitting write"
+ " urb, error %d\n", __FUNCTION__, result);
else
return;
}
@@ -987,191 +1111,38 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
pl2303_send(port);
}
+/* All of the device info needed for the PL2303 SIO serial converter */
+static struct usb_serial_driver pl2303_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pl2303",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = pl2303_open,
+ .close = pl2303_close,
+ .write = pl2303_write,
+ .ioctl = pl2303_ioctl,
+ .break_ctl = pl2303_break_ctl,
+ .set_termios = pl2303_set_termios,
+ .tiocmget = pl2303_tiocmget,
+ .tiocmset = pl2303_tiocmset,
+ .read_bulk_callback = pl2303_read_bulk_callback,
+ .read_int_callback = pl2303_read_int_callback,
+ .write_bulk_callback = pl2303_write_bulk_callback,
+ .write_room = pl2303_write_room,
+ .chars_in_buffer = pl2303_chars_in_buffer,
+ .attach = pl2303_startup,
+ .shutdown = pl2303_shutdown,
+};
-/*
- * pl2303_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
-{
-
- struct pl2303_buf *pb;
-
-
- if (size == 0)
- return NULL;
-
- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
- if (pb == NULL)
- return NULL;
-
- pb->buf_buf = kmalloc(size, GFP_KERNEL);
- if (pb->buf_buf == NULL) {
- kfree(pb);
- return NULL;
- }
-
- pb->buf_size = size;
- pb->buf_get = pb->buf_put = pb->buf_buf;
-
- return pb;
-
-}
-
-
-/*
- * pl2303_buf_free
- *
- * Free the buffer and all associated memory.
- */
-
-static void pl2303_buf_free(struct pl2303_buf *pb)
-{
- if (pb) {
- kfree(pb->buf_buf);
- kfree(pb);
- }
-}
-
-
-/*
- * pl2303_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-
-static void pl2303_buf_clear(struct pl2303_buf *pb)
-{
- if (pb != NULL)
- pb->buf_get = pb->buf_put;
- /* equivalent to a get of all data available */
-}
-
-
-/*
- * pl2303_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
-{
- if (pb != NULL)
- return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
- else
- return 0;
-}
-
-
-/*
- * pl2303_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
-{
- if (pb != NULL)
- return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
- else
- return 0;
-}
-
-
-/*
- * pl2303_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
- unsigned int count)
-{
-
- unsigned int len;
-
-
- if (pb == NULL)
- return 0;
-
- len = pl2303_buf_space_avail(pb);
- if (count > len)
- count = len;
-
- if (count == 0)
- return 0;
-
- len = pb->buf_buf + pb->buf_size - pb->buf_put;
- if (count > len) {
- memcpy(pb->buf_put, buf, len);
- memcpy(pb->buf_buf, buf+len, count - len);
- pb->buf_put = pb->buf_buf + count - len;
- } else {
- memcpy(pb->buf_put, buf, count);
- if (count < len)
- pb->buf_put += count;
- else /* count == len */
- pb->buf_put = pb->buf_buf;
- }
-
- return count;
-
-}
-
-
-/*
- * pl2303_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
- unsigned int count)
-{
-
- unsigned int len;
-
-
- if (pb == NULL)
- return 0;
-
- len = pl2303_buf_data_avail(pb);
- if (count > len)
- count = len;
-
- if (count == 0)
- return 0;
-
- len = pb->buf_buf + pb->buf_size - pb->buf_get;
- if (count > len) {
- memcpy(buf, pb->buf_get, len);
- memcpy(buf+len, pb->buf_buf, count - len);
- pb->buf_get = pb->buf_buf + count - len;
- } else {
- memcpy(buf, pb->buf_get, count);
- if (count < len)
- pb->buf_get += count;
- else /* count == len */
- pb->buf_get = pb->buf_buf;
- }
-
- return count;
-
-}
-
-static int __init pl2303_init (void)
+static int __init pl2303_init(void)
{
int retval;
+
retval = usb_serial_register(&pl2303_device);
if (retval)
goto failed_usb_serial_register;
@@ -1186,14 +1157,12 @@ failed_usb_serial_register:
return retval;
}
-
-static void __exit pl2303_exit (void)
+static void __exit pl2303_exit(void)
{
- usb_deregister (&pl2303_driver);
- usb_serial_deregister (&pl2303_device);
+ usb_deregister(&pl2303_driver);
+ usb_serial_deregister(&pl2303_device);
}
-
module_init(pl2303_init);
module_exit(pl2303_exit);
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 7f29e81d3e3..65a5039665e 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -10,6 +10,7 @@
#define PL2303_VENDOR_ID 0x067b
#define PL2303_PRODUCT_ID 0x2303
#define PL2303_PRODUCT_ID_RSAQ2 0x04bb
+#define PL2303_PRODUCT_ID_DCU11 0x1234
#define PL2303_PRODUCT_ID_PHAROS 0xaaa0
#define PL2303_PRODUCT_ID_RSAQ3 0xaaa2
@@ -81,6 +82,18 @@
#define SPEEDDRAGON_VENDOR_ID 0x0e55
#define SPEEDDRAGON_PRODUCT_ID 0x110b
-/* Ours Technology Inc DKU-5 clone, chipset: Prolific Technology Inc */
-#define OTI_VENDOR_ID 0x0ea0
-#define OTI_PRODUCT_ID 0x6858
+/* DATAPILOT Universal-2 Phone Cable */
+#define DATAPILOT_U2_VENDOR_ID 0x0731
+#define DATAPILOT_U2_PRODUCT_ID 0x2003
+
+/* Belkin "F5U257" Serial Adapter */
+#define BELKIN_VENDOR_ID 0x050d
+#define BELKIN_PRODUCT_ID 0x0257
+
+/* Alcor Micro Corp. USB 2.0 TO RS-232 */
+#define ALCOR_VENDOR_ID 0x058F
+#define ALCOR_PRODUCT_ID 0x9720
+
+/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
+#define HUAWEI_VENDOR_ID 0x12d1
+#define HUAWEI_PRODUCT_ID 0x1001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index f0215f850d2..1e07dfad685 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -60,7 +60,6 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -72,7 +71,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#ifndef CONFIG_USB_SAFE_PADDED
@@ -299,14 +298,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
dbg ("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
packet_length = port->bulk_out_size; // get max packetsize
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
new file mode 100644
index 00000000000..d29638daa98
--- /dev/null
+++ b/drivers/usb/serial/sierra.c
@@ -0,0 +1,75 @@
+/*
+ * Sierra Wireless CDMA Wireless Serial USB driver
+ *
+ * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com>
+ * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ /* Following devices are supported in the airprime.c driver */
+ /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */
+ /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver sierra_driver = {
+ .name = "sierra_wireless",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+};
+
+static struct usb_serial_driver sierra_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "Sierra_Wireless",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = NUM_DONT_CARE,
+ .num_bulk_out = NUM_DONT_CARE,
+ .num_ports = 3,
+};
+
+static int __init sierra_init(void)
+{
+ int retval;
+
+ retval = usb_serial_register(&sierra_device);
+ if (retval)
+ return retval;
+ retval = usb_register(&sierra_driver);
+ if (retval)
+ usb_serial_deregister(&sierra_device);
+ return retval;
+}
+
+static void __exit sierra_exit(void)
+{
+ usb_deregister(&sierra_driver);
+ usb_serial_deregister(&sierra_device);
+}
+
+module_init(sierra_init);
+module_exit(sierra_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index c3a2071b802..ac9b8ee52d4 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -68,7 +68,6 @@
* fi
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -84,8 +83,8 @@
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <linux/usb.h>
+#include <linux/usb/serial.h>
-#include "usb-serial.h"
#include "ti_usb_3410_5052.h"
#include "ti_fw_3410.h" /* firmware image for 3410 */
#include "ti_fw_5052.h" /* firmware image for 5052 */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index a30135c7cfe..0222d92842b 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -16,7 +16,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -32,7 +31,7 @@
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "pl2303.h"
/*
@@ -41,6 +40,8 @@
#define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
#define DRIVER_DESC "USB Serial Driver core"
+static void port_free(struct usb_serial_port *port);
+
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
.name = "usbserial",
@@ -147,23 +148,10 @@ static void destroy_serial(struct kref *kref)
port = serial->port[i];
if (!port)
continue;
- usb_kill_urb(port->read_urb);
- usb_free_urb(port->read_urb);
- usb_kill_urb(port->write_urb);
- usb_free_urb(port->write_urb);
- usb_kill_urb(port->interrupt_in_urb);
- usb_free_urb(port->interrupt_in_urb);
- usb_kill_urb(port->interrupt_out_urb);
- usb_free_urb(port->interrupt_out_urb);
- kfree(port->bulk_in_buffer);
- kfree(port->bulk_out_buffer);
- kfree(port->interrupt_in_buffer);
- kfree(port->interrupt_out_buffer);
+ port_free(port);
}
}
- flush_scheduled_work(); /* port->work */
-
usb_put_dev(serial->dev);
/* free up any memory that we allocated */
@@ -476,8 +464,10 @@ static int serial_read_proc (char *page, char **start, off_t off, int count, int
length += sprintf (page+length, " path:%s", tmp);
length += sprintf (page+length, "\n");
- if ((length + begin) > (off + count))
+ if ((length + begin) > (off + count)) {
+ usb_serial_put(serial);
goto done;
+ }
if ((length + begin) < off) {
begin += length;
length = 0;
@@ -565,6 +555,11 @@ static void port_release(struct device *dev)
struct usb_serial_port *port = to_usb_serial_port(dev);
dbg ("%s - %s", __FUNCTION__, dev->bus_id);
+ port_free(port);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
usb_kill_urb(port->read_urb);
usb_free_urb(port->read_urb);
usb_kill_urb(port->write_urb);
@@ -577,6 +572,7 @@ static void port_release(struct device *dev)
kfree(port->bulk_out_buffer);
kfree(port->interrupt_in_buffer);
kfree(port->interrupt_out_buffer);
+ flush_scheduled_work(); /* port->work */
kfree(port);
}
@@ -680,33 +676,29 @@ int usb_serial_probe(struct usb_interface *interface,
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+
+ if (usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
dbg("found bulk in on endpoint %d", i);
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+ if (usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dbg("found bulk out on endpoint %d", i);
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
+
+ if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in on endpoint %d", i);
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
+ if (usb_endpoint_is_int_out(endpoint)) {
/* we found an interrupt out endpoint */
dbg("found interrupt out on endpoint %d", i);
interrupt_out_endpoint[num_interrupt_out] = endpoint;
@@ -720,14 +712,15 @@ int usb_serial_probe(struct usb_interface *interface,
if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
(le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID))) {
+ (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
+ ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
if (interface != dev->actconfig->interface[0]) {
/* check out the endpoints of the other interface*/
iface_desc = dev->actconfig->interface[0]->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
+ if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in for Prolific device on separate interface");
interrupt_in_endpoint[num_interrupt_in] = endpoint;
@@ -941,7 +934,10 @@ int usb_serial_probe(struct usb_interface *interface,
snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
- device_register (&port->dev);
+ retval = device_register(&port->dev);
+ if (retval)
+ dev_err(&port->dev, "Error registering port device, "
+ "continuing\n");
}
usb_serial_console_init (debug, minor);
@@ -1059,13 +1055,12 @@ static int __init usb_serial_init(void)
usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial";
- usb_serial_tty_driver->devfs_name = "usb/tts/";
usb_serial_tty_driver->name = "ttyUSB";
usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
usb_serial_tty_driver->minor_start = 0;
usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
- usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
+ usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
usb_serial_tty_driver->init_termios = tty_std_termios;
usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
tty_set_operations(usb_serial_tty_driver, &serial_ops);
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
deleted file mode 100644
index d53ea9b11e8..00000000000
--- a/drivers/usb/serial/usb-serial.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * USB Serial Converter driver
- *
- * Copyright (C) 1999 - 2005
- * Greg Kroah-Hartman (greg@kroah.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.
- *
- */
-
-
-#ifndef __LINUX_USB_SERIAL_H
-#define __LINUX_USB_SERIAL_H
-
-#include <linux/config.h>
-#include <linux/kref.h>
-#include <linux/mutex.h>
-
-#define SERIAL_TTY_MAJOR 188 /* Nice legal number now */
-#define SERIAL_TTY_MINORS 255 /* loads of devices :) */
-
-#define MAX_NUM_PORTS 8 /* The maximum number of ports one device can grab at once */
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-/**
- * usb_serial_port: structure for the specific ports of a device.
- * @serial: pointer back to the struct usb_serial owner of this port.
- * @tty: pointer to the corresponding tty for this port.
- * @lock: spinlock to grab when updating portions of this structure.
- * @mutex: mutex used to synchronize serial_open() and serial_close()
- * access for this port.
- * @number: the number of the port (the minor number).
- * @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
- * @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
- * @interrupt_in_endpointAddress: endpoint address for the interrupt in pipe
- * for this port.
- * @interrupt_out_buffer: pointer to the interrupt out buffer for this port.
- * @interrupt_out_size: the size of the interrupt_out_buffer, in bytes.
- * @interrupt_out_urb: pointer to the interrupt out struct urb for this port.
- * @interrupt_out_endpointAddress: endpoint address for the interrupt out pipe
- * for this port.
- * @bulk_in_buffer: pointer to the bulk in buffer for this port.
- * @read_urb: pointer to the bulk in struct urb for this port.
- * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
- * port.
- * @bulk_out_buffer: pointer to the bulk out buffer for this port.
- * @bulk_out_size: the size of the bulk_out_buffer, in bytes.
- * @write_urb: pointer to the bulk out struct urb for this port.
- * @bulk_out_endpointAddress: endpoint address for the bulk out pipe for this
- * port.
- * @write_wait: a wait_queue_head_t used by the port.
- * @work: work queue entry for the line discipline waking up.
- * @open_count: number of times this port has been opened.
- *
- * This structure is used by the usb-serial core and drivers for the specific
- * ports of a device.
- */
-struct usb_serial_port {
- struct usb_serial * serial;
- struct tty_struct * tty;
- spinlock_t lock;
- struct mutex mutex;
- unsigned char number;
-
- unsigned char * interrupt_in_buffer;
- struct urb * interrupt_in_urb;
- __u8 interrupt_in_endpointAddress;
-
- unsigned char * interrupt_out_buffer;
- int interrupt_out_size;
- struct urb * interrupt_out_urb;
- __u8 interrupt_out_endpointAddress;
-
- unsigned char * bulk_in_buffer;
- int bulk_in_size;
- struct urb * read_urb;
- __u8 bulk_in_endpointAddress;
-
- unsigned char * bulk_out_buffer;
- int bulk_out_size;
- struct urb * write_urb;
- int write_urb_busy;
- __u8 bulk_out_endpointAddress;
-
- wait_queue_head_t write_wait;
- struct work_struct work;
- int open_count;
- struct device dev;
-};
-#define to_usb_serial_port(d) container_of(d, struct usb_serial_port, dev)
-
-/* get and set the port private data pointer helper functions */
-static inline void *usb_get_serial_port_data (struct usb_serial_port *port)
-{
- return dev_get_drvdata(&port->dev);
-}
-
-static inline void usb_set_serial_port_data (struct usb_serial_port *port, void *data)
-{
- dev_set_drvdata(&port->dev, data);
-}
-
-/**
- * usb_serial - structure used by the usb-serial core for a device
- * @dev: pointer to the struct usb_device for this device
- * @type: pointer to the struct usb_serial_driver for this device
- * @interface: pointer to the struct usb_interface for this device
- * @minor: the starting minor number for this device
- * @num_ports: the number of ports this device has
- * @num_interrupt_in: number of interrupt in endpoints we have
- * @num_interrupt_out: number of interrupt out endpoints we have
- * @num_bulk_in: number of bulk in endpoints we have
- * @num_bulk_out: number of bulk out endpoints we have
- * @port: array of struct usb_serial_port structures for the different ports.
- * @private: place to put any driver specific information that is needed. The
- * usb-serial driver is required to manage this data, the usb-serial core
- * will not touch this. Use usb_get_serial_data() and
- * usb_set_serial_data() to access this.
- */
-struct usb_serial {
- struct usb_device * dev;
- struct usb_serial_driver * type;
- struct usb_interface * interface;
- unsigned char minor;
- unsigned char num_ports;
- unsigned char num_port_pointers;
- char num_interrupt_in;
- char num_interrupt_out;
- char num_bulk_in;
- char num_bulk_out;
- struct usb_serial_port * port[MAX_NUM_PORTS];
- struct kref kref;
- void * private;
-};
-#define to_usb_serial(d) container_of(d, struct usb_serial, kref)
-
-#define NUM_DONT_CARE (-1)
-
-/* get and set the serial private data pointer helper functions */
-static inline void *usb_get_serial_data (struct usb_serial *serial)
-{
- return serial->private;
-}
-
-static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
-{
- serial->private = data;
-}
-
-/**
- * usb_serial_driver - describes a usb serial driver
- * @description: pointer to a string that describes this driver. This string used
- * in the syslog messages when a device is inserted or removed.
- * @id_table: pointer to a list of usb_device_id structures that define all
- * of the devices this structure can support.
- * @num_interrupt_in: the number of interrupt in endpoints this device will
- * have.
- * @num_interrupt_out: the number of interrupt out endpoints this device will
- * have.
- * @num_bulk_in: the number of bulk in endpoints this device will have.
- * @num_bulk_out: the number of bulk out endpoints this device will have.
- * @num_ports: the number of different ports this device will have.
- * @calc_num_ports: pointer to a function to determine how many ports this
- * device has dynamically. It will be called after the probe()
- * callback is called, but before attach()
- * @probe: pointer to the driver's probe function.
- * This will be called when the device is inserted into the system,
- * but before the device has been fully initialized by the usb_serial
- * subsystem. Use this function to download any firmware to the device,
- * or any other early initialization that might be needed.
- * Return 0 to continue on with the initialization sequence. Anything
- * else will abort it.
- * @attach: pointer to the driver's attach function.
- * This will be called when the struct usb_serial structure is fully set
- * set up. Do any local initialization of the device, or any private
- * memory structure allocation at this point in time.
- * @shutdown: pointer to the driver's shutdown function. This will be
- * called when the device is removed from the system.
- *
- * This structure is defines a USB Serial driver. It provides all of
- * the information that the USB serial core code needs. If the function
- * pointers are defined, then the USB serial core code will call them when
- * the corresponding tty port functions are called. If they are not
- * called, the generic serial function will be used instead.
- *
- * The driver.owner field should be set to the module owner of this driver.
- * The driver.name field should be set to the name of this driver (remember
- * it will show up in sysfs, so it needs to be short and to the point.
- * Useing the module name is a good idea.)
- */
-struct usb_serial_driver {
- const char *description;
- const struct usb_device_id *id_table;
- char num_interrupt_in;
- char num_interrupt_out;
- char num_bulk_in;
- char num_bulk_out;
- char num_ports;
-
- struct list_head driver_list;
- struct device_driver driver;
-
- int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
- int (*attach) (struct usb_serial *serial);
- int (*calc_num_ports) (struct usb_serial *serial);
-
- void (*shutdown) (struct usb_serial *serial);
-
- int (*port_probe) (struct usb_serial_port *port);
- int (*port_remove) (struct usb_serial_port *port);
-
- /* serial function calls */
- int (*open) (struct usb_serial_port *port, struct file * filp);
- void (*close) (struct usb_serial_port *port, struct file * filp);
- int (*write) (struct usb_serial_port *port, const unsigned char *buf, int count);
- int (*write_room) (struct usb_serial_port *port);
- int (*ioctl) (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
- void (*set_termios) (struct usb_serial_port *port, struct termios * old);
- void (*break_ctl) (struct usb_serial_port *port, int break_state);
- int (*chars_in_buffer) (struct usb_serial_port *port);
- void (*throttle) (struct usb_serial_port *port);
- void (*unthrottle) (struct usb_serial_port *port);
- int (*tiocmget) (struct usb_serial_port *port, struct file *file);
- int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
-
- void (*read_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
-};
-#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
-
-extern int usb_serial_register(struct usb_serial_driver *driver);
-extern void usb_serial_deregister(struct usb_serial_driver *driver);
-extern void usb_serial_port_softint(struct usb_serial_port *port);
-
-extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
-extern void usb_serial_disconnect(struct usb_interface *iface);
-
-extern int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *data, int length, __u8 bRequest);
-extern int ezusb_set_reset (struct usb_serial *serial, unsigned char reset_bit);
-
-/* USB Serial console functions */
-#ifdef CONFIG_USB_SERIAL_CONSOLE
-extern void usb_serial_console_init (int debug, int minor);
-extern void usb_serial_console_exit (void);
-extern void usb_serial_console_disconnect(struct usb_serial *serial);
-#else
-static inline void usb_serial_console_init (int debug, int minor) { }
-static inline void usb_serial_console_exit (void) { }
-static inline void usb_serial_console_disconnect(struct usb_serial *serial) {}
-#endif
-
-/* Functions needed by other parts of the usbserial core */
-extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
-extern void usb_serial_put(struct usb_serial *serial);
-extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigned char *buf, int count);
-extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
-extern int usb_serial_generic_write_room (struct usb_serial_port *port);
-extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
-extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-extern void usb_serial_generic_shutdown (struct usb_serial *serial);
-extern int usb_serial_generic_register (int debug);
-extern void usb_serial_generic_deregister (void);
-
-extern int usb_serial_bus_register (struct usb_serial_driver *device);
-extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
-
-extern struct usb_serial_driver usb_serial_generic_device;
-extern struct bus_type usb_serial_bus_type;
-extern struct tty_driver *usb_serial_tty_driver;
-
-static inline void usb_serial_debug_data(int debug,
- struct device *dev,
- const char *function, int size,
- const unsigned char *data)
-{
- int i;
-
- if (debug) {
- dev_printk(KERN_DEBUG, dev, "%s - length = %d, data = ", function, size);
- for (i = 0; i < size; ++i)
- printk ("%.2x ", data[i]);
- printk ("\n");
- }
-}
-
-/* Use our own dbg macro */
-#undef dbg
-#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg); } while (0)
-
-
-
-#endif /* ifdef __LINUX_USB_SERIAL_H */
-
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 9e89b8d54f7..88949f7884c 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -13,7 +13,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -26,7 +25,7 @@
#include <linux/spinlock.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "visor.h"
/*
@@ -303,7 +302,6 @@ static int visor_open (struct usb_serial_port *port, struct file *filp)
spin_lock_irqsave(&priv->lock, flags);
priv->bytes_in = 0;
priv->bytes_out = 0;
- priv->outstanding_urbs = 0;
priv->throttled = 0;
spin_unlock_irqrestore(&priv->lock, flags);
@@ -436,13 +434,25 @@ static int visor_write (struct usb_serial_port *port, const unsigned char *buf,
static int visor_write_room (struct usb_serial_port *port)
{
+ struct visor_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
dbg("%s - port %d", __FUNCTION__, port->number);
/*
* We really can take anything the user throws at us
* but let's pick a nice big number to tell the tty
- * layer that we have lots of free space
+ * layer that we have lots of free space, unless we don't.
*/
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ dbg("%s - write limit hit\n", __FUNCTION__);
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
return 2048;
}
@@ -759,15 +769,22 @@ static int visor_calc_num_ports (struct usb_serial *serial)
static int generic_startup(struct usb_serial *serial)
{
+ struct usb_serial_port **ports = serial->port;
struct visor_private *priv;
int i;
for (i = 0; i < serial->num_ports; ++i) {
priv = kzalloc (sizeof(*priv), GFP_KERNEL);
- if (!priv)
+ if (!priv) {
+ while (i-- != 0) {
+ priv = usb_get_serial_port_data(ports[i]);
+ usb_set_serial_port_data(ports[i], NULL);
+ kfree(priv);
+ }
return -ENOMEM;
+ }
spin_lock_init(&priv->lock);
- usb_set_serial_port_data(serial->port[i], priv);
+ usb_set_serial_port_data(ports[i], priv);
}
return 0;
}
@@ -877,7 +894,18 @@ static int clie_5_attach (struct usb_serial *serial)
static void visor_shutdown (struct usb_serial *serial)
{
+ struct visor_private *priv;
+ int i;
+
dbg("%s", __FUNCTION__);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ if (priv) {
+ usb_set_serial_port_data(serial->port[i], NULL);
+ kfree(priv);
+ }
+ }
}
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5b06fa36609..6e6c7934be3 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -65,7 +65,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -80,7 +79,7 @@
#include <linux/usb.h>
#include <linux/serial_reg.h>
#include <linux/serial.h>
-#include "usb-serial.h"
+#include <linux/usb/serial.h>
#include "whiteheat_fw.h" /* firmware for the ConnectTech WhiteHEAT device */
#include "whiteheat.h" /* WhiteHEAT specific commands */
@@ -686,19 +685,16 @@ static void whiteheat_close(struct usb_serial_port *port, struct file * filp)
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
usb_kill_urb(urb);
- list_del(tmp);
- list_add(tmp, &info->rx_urbs_free);
- }
- list_for_each_safe(tmp, tmp2, &info->rx_urb_q) {
- list_del(tmp);
- list_add(tmp, &info->rx_urbs_free);
+ list_move(tmp, &info->rx_urbs_free);
}
+ list_for_each_safe(tmp, tmp2, &info->rx_urb_q)
+ list_move(tmp, &info->rx_urbs_free);
+
list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) {
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
usb_kill_urb(urb);
- list_del(tmp);
- list_add(tmp, &info->tx_urbs_free);
+ list_move(tmp, &info->tx_urbs_free);
}
spin_unlock_irqrestore(&info->lock, flags);
@@ -1080,8 +1076,7 @@ static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs)
err("%s - Not my urb!", __FUNCTION__);
return;
}
- list_del(&wrap->list);
- list_add(&wrap->list, &info->tx_urbs_free);
+ list_move(&wrap->list, &info->tx_urbs_free);
spin_unlock(&info->lock);
if (urb->status) {
@@ -1371,8 +1366,7 @@ static int start_port_read(struct usb_serial_port *port)
wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
urb = wrap->urb;
usb_kill_urb(urb);
- list_del(tmp);
- list_add(tmp, &info->rx_urbs_free);
+ list_move(tmp, &info->rx_urbs_free);
}
break;
}
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index be9eec22574..86e48c42d6a 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -135,6 +135,18 @@ config USB_STORAGE_ONETOUCH
this input in any keybinding software. (e.g. gnome's keyboard short-
cuts)
+config USB_STORAGE_KARMA
+ bool "Support for Rio Karma music player"
+ depends on USB_STORAGE
+ help
+ Say Y here to include additional code to support the Rio Karma
+ USB interface.
+
+ This code places the Rio Karma into mass storage mode, enabling
+ it to be mounted as an ordinary filesystem. Performing an eject
+ on the resulting scsi device node returns the Karma to normal
+ operation.
+
config USB_LIBUSUAL
bool "The shared table of common (or usual) storage devices"
depends on USB
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 8cbba22508a..023969b4385 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -20,6 +20,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)
diff --git a/drivers/usb/storage/debug.h b/drivers/usb/storage/debug.h
index cd2096acc72..77e244a8c37 100644
--- a/drivers/usb/storage/debug.h
+++ b/drivers/usb/storage/debug.h
@@ -44,7 +44,6 @@
#ifndef _DEBUG_H_
#define _DEBUG_H_
-#include <linux/config.h>
#include <linux/kernel.h>
#define USB_STORAGE "usb-storage: "
diff --git a/drivers/usb/storage/dpcm.c b/drivers/usb/storage/dpcm.c
index 92b69e4c804..1628cb25856 100644
--- a/drivers/usb/storage/dpcm.c
+++ b/drivers/usb/storage/dpcm.c
@@ -29,7 +29,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 30e96050fe0..88aa59ab756 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -28,7 +28,6 @@
* (http://www.freecom.de/)
*/
-#include <linux/config.h>
#include <linux/hdreg.h>
#include <scsi/scsi.h>
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index ab173b30076..5b06f9240d0 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -45,12 +45,6 @@
#include "debug.h"
#include "transport.h"
-#define RIO_MSC 0x08
-#define RIOP_INIT "RIOP\x00\x01\x08"
-#define RIOP_INIT_LEN 7
-#define RIO_SEND_LEN 40
-#define RIO_RECV_LEN 0x200
-
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
* mode */
int usb_stor_euscsi_init(struct us_data *us)
@@ -97,70 +91,3 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
return (res ? -1 : 0);
}
-
-/* Place the Rio Karma into mass storage mode.
- *
- * The initialization begins by sending 40 bytes starting
- * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte
- * packet with the high four bits set and everything else null.
- *
- * Next, we send RIOP\x80\x00\x08\x00. Each time, a 512 byte response
- * must be read, but we must loop until byte 5 in the response is 0x08,
- * indicating success. */
-int rio_karma_init(struct us_data *us)
-{
- int result, partial;
- char *recv;
- unsigned long timeout;
-
- // us->iobuf is big enough to hold cmd but not receive
- if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL)))
- goto die_nomem;
-
- US_DEBUGP("Initializing Karma...\n");
-
- memset(us->iobuf, 0, RIO_SEND_LEN);
- memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN);
-
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
- us->iobuf, RIO_SEND_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
- recv, RIO_RECV_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- us->iobuf[4] = 0x80;
- us->iobuf[5] = 0;
- timeout = jiffies + msecs_to_jiffies(3000);
- for (;;) {
- US_DEBUGP("Sending init command\n");
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
- us->iobuf, RIO_SEND_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
- recv, RIO_RECV_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- if (recv[5] == RIO_MSC)
- break;
- if (time_after(jiffies, timeout))
- goto die;
- msleep(10);
- }
- US_DEBUGP("Karma initialized.\n");
- kfree(recv);
- return 0;
-
-die:
- kfree(recv);
-die_nomem:
- US_DEBUGP("Could not initialize karma.\n");
- return USB_STOR_TRANSPORT_FAILED;
-}
-
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index f9907a5cf12..e2967a4d48a 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -37,7 +37,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include "usb.h"
#include "transport.h"
@@ -48,4 +47,3 @@ int usb_stor_euscsi_init(struct us_data *us);
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
-int rio_karma_init(struct us_data *us);
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
new file mode 100644
index 00000000000..0d79ae5683f
--- /dev/null
+++ b/drivers/usb/storage/karma.c
@@ -0,0 +1,155 @@
+/* Driver for Rio Karma
+ *
+ * (c) 2006 Bob Copeland <me@bobcopeland.com>
+ * (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk>
+ *
+ * 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, 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 <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "debug.h"
+#include "karma.h"
+
+#define RIO_PREFIX "RIOP\x00"
+#define RIO_PREFIX_LEN 5
+#define RIO_SEND_LEN 40
+#define RIO_RECV_LEN 0x200
+
+#define RIO_ENTER_STORAGE 0x1
+#define RIO_LEAVE_STORAGE 0x2
+#define RIO_RESET 0xC
+
+extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data *);
+
+struct karma_data {
+ int in_storage;
+ char *recv;
+};
+
+/*
+ * Send commands to Rio Karma.
+ *
+ * For each command we send 40 bytes starting 'RIOP\0' followed by
+ * the command number and a sequence number, which the device will ack
+ * with a 512-byte packet with the high four bits set and everything
+ * else null. Then we send 'RIOP\x80' followed by a zero and the
+ * sequence number, until byte 5 in the response repeats the sequence
+ * number.
+ */
+static int rio_karma_send_command(char cmd, struct us_data *us)
+{
+ int result, partial;
+ unsigned long timeout;
+ static unsigned char seq = 1;
+ struct karma_data *data = (struct karma_data *) us->extra;
+
+ US_DEBUGP("karma: sending command %04x\n", cmd);
+ memset(us->iobuf, 0, RIO_SEND_LEN);
+ memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
+ us->iobuf[5] = cmd;
+ us->iobuf[6] = seq;
+
+ timeout = jiffies + msecs_to_jiffies(6000);
+ for (;;) {
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ us->iobuf, RIO_SEND_LEN, &partial);
+ if (result != USB_STOR_XFER_GOOD)
+ goto err;
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data->recv, RIO_RECV_LEN, &partial);
+ if (result != USB_STOR_XFER_GOOD)
+ goto err;
+
+ if (data->recv[5] == seq)
+ break;
+
+ if (time_after(jiffies, timeout))
+ goto err;
+
+ us->iobuf[4] = 0x80;
+ us->iobuf[5] = 0;
+ msleep(50);
+ }
+
+ seq++;
+ if (seq == 0)
+ seq = 1;
+
+ US_DEBUGP("karma: sent command %04x\n", cmd);
+ return 0;
+err:
+ US_DEBUGP("karma: command %04x failed\n", cmd);
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Trap START_STOP and READ_10 to leave/re-enter storage mode.
+ * Everything else is propagated to the normal bulk layer.
+ */
+int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int ret;
+ struct karma_data *data = (struct karma_data *) us->extra;
+
+ if (srb->cmnd[0] == READ_10 && !data->in_storage) {
+ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+ if (ret)
+ return ret;
+
+ data->in_storage = 1;
+ return usb_stor_Bulk_transport(srb, us);
+ } else if (srb->cmnd[0] == START_STOP) {
+ ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us);
+ if (ret)
+ return ret;
+
+ data->in_storage = 0;
+ return rio_karma_send_command(RIO_RESET, us);
+ }
+ return usb_stor_Bulk_transport(srb, us);
+}
+
+static void rio_karma_destructor(void *extra)
+{
+ struct karma_data *data = (struct karma_data *) extra;
+ kfree(data->recv);
+}
+
+int rio_karma_init(struct us_data *us)
+{
+ int ret = 0;
+ struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
+ if (!data)
+ goto out;
+
+ data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
+ if (!data->recv) {
+ kfree(data);
+ goto out;
+ }
+
+ us->extra = data;
+ us->extra_destructor = rio_karma_destructor;
+ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+ data->in_storage = (ret == 0);
+out:
+ return ret;
+}
diff --git a/drivers/usb/storage/karma.h b/drivers/usb/storage/karma.h
new file mode 100644
index 00000000000..8a60972af8c
--- /dev/null
+++ b/drivers/usb/storage/karma.h
@@ -0,0 +1,7 @@
+#ifndef _KARMA_USB_H
+#define _KARMA_USB_H
+
+extern int rio_karma_init(struct us_data *us);
+extern int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index b1ec4a71854..599ad10a761 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -8,6 +8,7 @@
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/vmalloc.h>
+#include <linux/kthread.h>
/*
*/
@@ -117,7 +118,7 @@ static int usu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
unsigned long type;
- int rc;
+ struct task_struct* task;
unsigned long flags;
type = USB_US_TYPE(id->driver_info);
@@ -132,8 +133,9 @@ static int usu_probe(struct usb_interface *intf,
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
- rc = kernel_thread(usu_probe_thread, (void*)type, CLONE_VM);
- if (rc < 0) {
+ task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
+ if (IS_ERR(task)) {
+ int rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
"Unable to start the thread for %s: %d\n",
bias_names[type], rc);
@@ -175,8 +177,6 @@ static int usu_probe_thread(void *arg)
int rc;
unsigned long flags;
- daemonize("libusual_%d", type); /* "usb-storage" is kinda too long */
-
/* A completion does not work here because it's counted. */
down(&usu_init_notify);
up(&usu_init_notify);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 026a587eb8d..f843a0bcf10 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -28,7 +28,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/init.h>
@@ -136,6 +135,7 @@ int onetouch_connect_input(struct us_data *ss)
struct usb_onetouch *onetouch;
struct input_dev *input_dev;
int pipe, maxp;
+ int error = -ENOMEM;
interface = ss->pusb_intf->cur_altsetting;
@@ -212,15 +212,18 @@ int onetouch_connect_input(struct us_data *ss)
ss->suspend_resume_hook = usb_onetouch_pm_hook;
#endif
- input_register_device(onetouch->dev);
+ error = input_register_device(onetouch->dev);
+ if (error)
+ goto fail3;
return 0;
+ fail3: usb_free_urb(onetouch->irq);
fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN,
onetouch->data, onetouch->data_dma);
fail1: kfree(onetouch);
input_free_device(input_dev);
- return -ENOMEM;
+ return error;
}
void onetouch_release_input(void *onetouch_)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 5715291ba54..e1072d52d64 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -72,12 +72,27 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_alloc (struct scsi_device *sdev)
{
+ struct us_data *us = host_to_us(sdev->host);
+
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
* less than 36 bytes.
*/
sdev->inquiry_len = 36;
+
+ /*
+ * The UFI spec treates the Peripheral Qualifier bits in an
+ * INQUIRY result as reserved and requires devices to set them
+ * to 0. However the SCSI spec requires these bits to be set
+ * to 3 to indicate when a LUN is not present.
+ *
+ * Let the scanning code know if this target merely sets
+ * Peripheral Device Type to 0x1f to indicate no LUN.
+ */
+ if (us->subclass == US_SC_UFI)
+ sdev->sdev_target->pdt_1f_for_no_lun = 1;
+
return 0;
}
@@ -112,13 +127,11 @@ static int slave_configure(struct scsi_device *sdev)
if (sdev->scsi_level < SCSI_2)
sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
- /* According to the technical support people at Genesys Logic,
- * devices using their chips have problems transferring more than
- * 32 KB at a time. In practice people have found that 64 KB
- * works okay and that's what Windows does. But we'll be
- * conservative; people can always use the sysfs interface to
- * increase max_sectors. */
- if (le16_to_cpu(us->pusb_dev->descriptor.idVendor) == USB_VENDOR_ID_GENESYS &&
+ /* Many devices have trouble transfering more than 32KB at a time,
+ * while others have trouble with more than 64K. At this time we
+ * are limiting both to 32K (64 sectores).
+ */
+ if ((us->flags & US_FL_MAX_SECTORS_64) &&
sdev->request_queue->max_sectors > 64)
blk_queue_max_sectors(sdev->request_queue, 64);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 19b25c5cafd..f23514c4e64 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -45,7 +45,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/slab.h>
@@ -181,7 +180,7 @@ static int usb_stor_msg_common(struct us_data *us, int timeout)
if (timeleft <= 0) {
US_DEBUGP("%s -- cancelling URB\n",
timeleft == 0 ? "Timeout" : "Signal");
- usb_unlink_urb(us->current_urb);
+ usb_kill_urb(us->current_urb);
}
/* return the URB status */
@@ -295,11 +294,6 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
- /* timeout or excessively long NAK */
- case -ETIMEDOUT:
- US_DEBUGP("-- timeout or NAK\n");
- return USB_STOR_XFER_ERROR;
-
/* babble - the device tried to send more than we wanted to read */
case -EOVERFLOW:
US_DEBUGP("-- babble\n");
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 543244d421c..c9a8d50106d 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -31,7 +31,6 @@
* the following thing for it to work:
* The macro UNUSUAL_DEV() must be defined before this file is included
*/
-#include <linux/config.h>
/* If you edit this file, please try to keep it sorted first by VendorID,
* then by ProductID.
@@ -113,6 +112,19 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x0113,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* Submitted by Ernestas Vaiciukevicius <ernisv@gmail.com> */
+UNUSUAL_DEV( 0x0419, 0x0100, 0x0100, 0x0100,
+ "Samsung Info. Systems America, Inc.",
+ "MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Orgad Shaneh <orgads@gmail.com> */
+UNUSUAL_DEV( 0x0419, 0xaace, 0x0100, 0x0100,
+ "Samsung", "MP3 Player",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Reported by Christian Leber <christian@leber.de> */
UNUSUAL_DEV( 0x0419, 0xaaf5, 0x0100, 0x0100,
"TrekStor",
@@ -133,6 +145,28 @@ UNUSUAL_DEV( 0x0420, 0x0001, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Mario Rettig <mariorettig@web.de> */
+UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
+ "Nokia",
+ "Nokia 3250",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
+/* Reported by Jon Hart <Jon.Hart@web.de> */
+UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100,
+ "Nokia",
+ "E60",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
+/* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and
+ * Einar Th. Einarsson <einarthered@gmail.com> */
+UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100,
+ "Nokia",
+ "N91",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
/* Reported by Jiri Slaby <jirislaby@gmail.com> and
* Rene C. Castberg <Rene@Castberg.org> */
UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100,
@@ -141,6 +175,13 @@ UNUSUAL_DEV( 0x0421, 0x0446, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+/* Reported by Matthew Bloch <matthew@bytemark.co.uk> */
+UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
+ "Nokia",
+ "E61",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+
/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
"SMSC",
@@ -184,10 +225,12 @@ UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_NOT_LOCKABLE ),
+#ifdef CONFIG_USB_STORAGE_KARMA
UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
"Rio",
"Rio Karma",
- US_SC_SCSI, US_PR_BULK, rio_karma_init, 0),
+ US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0),
+#endif
/* Patch submitted by Philipp Friedrich <philipp@void.at> */
UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
@@ -207,16 +250,6 @@ UNUSUAL_DEV( 0x0482, 0x0103, 0x0100, 0x0100,
"Finecam S5",
US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_INQUIRY),
-/* Patch for Kyocera Finecam L3
- * Submitted by Michael Krauth <michael.krauth@web.de>
- * and Alessandro Fracchetti <al.fracchetti@tin.it>
- */
-UNUSUAL_DEV( 0x0482, 0x0105, 0x0100, 0x0100,
- "Kyocera",
- "Finecam L3",
- US_SC_SCSI, US_PR_BULK, NULL,
- US_FL_FIX_INQUIRY),
-
/* Reported by Paul Stewart <stewart@wetlogic.net>
* This entry is needed because the device reports Sub=ff */
UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x0001,
@@ -474,10 +507,11 @@ UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0450,
US_SC_SCSI, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN | US_FL_NOT_LOCKABLE | US_FL_NO_WP_DETECT ),
-/* This entry is needed because the device reports Sub=ff */
-UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0600,
+/* Submitted by Lars Jacob <jacob.lars@googlemail.com>
+ * This entry is needed because the device reports Sub=ff */
+UNUSUAL_DEV( 0x054c, 0x0010, 0x0500, 0x0610,
"Sony",
- "DSC-T1/T5",
+ "DSC-T1/T5/H5",
US_SC_8070, US_PR_DEVICE, NULL,
US_FL_SINGLE_LUN ),
@@ -564,6 +598,13 @@ UNUSUAL_DEV( 0x054c, 0x0099, 0x0000, 0x9999,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
+/* floppy reports multiple luns */
+UNUSUAL_DEV( 0x055d, 0x2020, 0x0000, 0x0210,
+ "SAMSUNG",
+ "SFD-321U [FW 0C]",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_SINGLE_LUN ),
+
UNUSUAL_DEV( 0x057b, 0x0000, 0x0000, 0x0299,
"Y-E Data",
@@ -599,17 +640,12 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
"Digital Camera EX-20 DSC",
US_SC_8070, US_PR_DEVICE, NULL, 0 ),
-/* The entry was here before I took over, and had US_SC_RBC. It turns
- * out that isn't needed. Additionally, Torsten Eriksson
- * <Torsten.Eriksson@bergianska.se> is able to use his device fine
- * without this entry at all - but I don't suspect that will be true
- * for all users (the protocol is likely needed), so is staying at
- * this time. - Phil Dibowitz <phil@ipom.com>
- */
-UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
+/* Reported by <Hendryk.Pfeiffer@gmx.de> */
+UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000,
"LaCie",
- "USB Hard Disk",
- US_SC_DEVICE, US_PR_CB, NULL, 0 ),
+ "DVD+-RW",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_GO_SLOW ),
/* Submitted by Joel Bourquard <numlock@freesurf.ch>
* Some versions of this device need the SubClass and Protocol overrides
@@ -709,18 +745,22 @@ UNUSUAL_DEV( 0x05dc, 0xb002, 0x0000, 0x0113,
* They were originally reported by Alexander Oltu
* <alexander@all-2.com> and Peter Marks <peter.marks@turner.com>
* respectively.
+ *
+ * US_FL_GO_SLOW and US_FL_MAX_SECTORS_64 added by Phil Dibowitz
+ * <phil@ipom.com> as these flags were made and hard-coded
+ * special-cases were pulled from scsiglue.c.
*/
UNUSUAL_DEV( 0x05e3, 0x0701, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Optical",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_GO_SLOW ),
+ US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
UNUSUAL_DEV( 0x05e3, 0x0702, 0x0000, 0xffff,
"Genesys Logic",
"USB to IDE Disk",
US_SC_DEVICE, US_PR_DEVICE, NULL,
- US_FL_GO_SLOW ),
+ US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
/* Reported by Hanno Boeck <hanno@gmx.de>
* Taken from the Lycoris Kernel */
@@ -1074,7 +1114,15 @@ UNUSUAL_DEV( 0x0a17, 0x006, 0x0000, 0xffff,
"Optio S/S4",
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY ),
-
+
+/* This is a virtual windows driver CD, which the zd1211rw driver automatically
+ * converts into a WLAN device. */
+UNUSUAL_DEV( 0x0ace, 0x2011, 0x0101, 0x0101,
+ "ZyXEL",
+ "G-220F USB-WLAN Install",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_DEVICE ),
+
#ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110,
"ATI",
@@ -1197,6 +1245,24 @@ UNUSUAL_DEV( 0x0ea0, 0x6828, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Benjamin Schiller <sbenni@gmx.de>
+ * It is also sold by Easylite as DJ 20 */
+UNUSUAL_DEV( 0x0ed1, 0x7636, 0x0103, 0x0103,
+ "Typhoon",
+ "My DJ 1820",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE | US_FL_GO_SLOW | US_FL_MAX_SECTORS_64),
+
+/* David Kuehling <dvdkhlng@gmx.de>:
+ * for MP3-Player AVOX WSX-300ER (bought in Japan). Reports lots of SCSI
+ * errors when trying to write.
+ */
+UNUSUAL_DEV( 0x0f19, 0x0105, 0x0100, 0x0100,
+ "C-MEX",
+ "A-VOX",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_IGNORE_RESIDUE ),
+
/* Reported by Michael Stattmann <michael@stattmann.com> */
UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
"Sony Ericsson",
@@ -1204,11 +1270,32 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_NO_WP_DETECT ),
+/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P990i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
+/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
+UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "M600i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
+/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P990i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
*/
-UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x9999,
+UNUSUAL_DEV( 0x1019, 0x0c55, 0x0110, 0x0110,
"Desknote",
"UCR-61S2B",
US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init,
@@ -1228,6 +1315,15 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* patch submitted by Davide Perini <perini.davide@dpsoftware.org>
+ * and Renato Perini <rperini@email.it>
+ */
+UNUSUAL_DEV( 0x22b8, 0x3010, 0x0001, 0x0001,
+ "Motorola",
+ "RAZR V3x",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
/* Reported by Radovan Garabik <garabik@kassiopeia.juls.savba.sk> */
UNUSUAL_DEV( 0x2735, 0x100b, 0x0000, 0x9999,
"MPIO",
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index e232c7c8990..b8d6031b097 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -47,7 +47,6 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/suspend.h>
@@ -56,6 +55,7 @@
#include <linux/slab.h>
#include <linux/kthread.h>
#include <linux/mutex.h>
+#include <linux/utsrelease.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -98,6 +98,9 @@
#ifdef CONFIG_USB_STORAGE_ALAUDA
#include "alauda.h"
#endif
+#ifdef CONFIG_USB_STORAGE_KARMA
+#include "karma.h"
+#endif
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -374,8 +377,12 @@ static int usb_stor_control_thread(void * __us)
/* lock access to the state */
scsi_lock(host);
+ /* did the command already complete because of a disconnect? */
+ if (!us->srb)
+ ; /* nothing to do */
+
/* indicate that the command is done */
- if (us->srb->result != DID_ABORT << 16) {
+ else if (us->srb->result != DID_ABORT << 16) {
US_DEBUGP("scsi cmd done, result=0x%x\n",
us->srb->result);
us->srb->scsi_done(us->srb);
@@ -479,7 +486,7 @@ static struct us_unusual_dev *find_unusual(const struct usb_device_id *id)
}
/* Get the unusual_devs entries and the string descriptors */
-static void get_device_info(struct us_data *us, const struct usb_device_id *id)
+static int get_device_info(struct us_data *us, const struct usb_device_id *id)
{
struct usb_device *dev = us->pusb_dev;
struct usb_interface_descriptor *idesc =
@@ -496,6 +503,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id)
unusual_dev->useTransport;
us->flags = USB_US_ORIG_FLAGS(id->driver_info);
+ if (us->flags & US_FL_IGNORE_DEVICE) {
+ printk(KERN_INFO USB_STORAGE "device ignored\n");
+ return -ENODEV;
+ }
+
/*
* This flag is only needed when we're in high-speed, so let's
* disable it if we're in full-speed
@@ -525,7 +537,8 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id)
if (msg >= 0 && !(us->flags & US_FL_NEED_OVERRIDE))
printk(KERN_NOTICE USB_STORAGE "This device "
"(%04x,%04x,%04x S %02x P %02x)"
- " has %s in unusual_devs.h\n"
+ " has %s in unusual_devs.h (kernel"
+ " %s)\n"
" Please send a copy of this message to "
"<linux-usb-devel@lists.sourceforge.net>\n",
le16_to_cpu(ddesc->idVendor),
@@ -533,8 +546,11 @@ static void get_device_info(struct us_data *us, const struct usb_device_id *id)
le16_to_cpu(ddesc->bcdDevice),
idesc->bInterfaceSubClass,
idesc->bInterfaceProtocol,
- msgs[msg]);
+ msgs[msg],
+ UTS_RELEASE);
}
+
+ return 0;
}
/* Get the transport settings */
@@ -633,6 +649,14 @@ static int get_transport(struct us_data *us)
break;
#endif
+#ifdef CONFIG_USB_STORAGE_KARMA
+ case US_PR_KARMA:
+ us->transport_name = "Rio Karma/Bulk";
+ us->transport = rio_karma_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+ break;
+#endif
+
default:
return -EIO;
}
@@ -837,32 +861,34 @@ static void dissociate_dev(struct us_data *us)
* the host */
static void quiesce_and_remove_host(struct us_data *us)
{
+ struct Scsi_Host *host = us_to_host(us);
+
/* Prevent new USB transfers, stop the current command, and
* interrupt a SCSI-scan or device-reset delay */
+ scsi_lock(host);
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
+ scsi_unlock(host);
usb_stor_stop_transport(us);
wake_up(&us->delay_wait);
/* It doesn't matter if the SCSI-scanning thread is still running.
* The thread will exit when it sees the DISCONNECTING flag. */
- /* Wait for the current command to finish, then remove the host */
- mutex_lock(&us->dev_mutex);
- mutex_unlock(&us->dev_mutex);
-
/* queuecommand won't accept any new commands and the control
* thread won't execute a previously-queued command. If there
* is such a command pending, complete it with an error. */
+ mutex_lock(&us->dev_mutex);
if (us->srb) {
us->srb->result = DID_NO_CONNECT << 16;
- scsi_lock(us_to_host(us));
+ scsi_lock(host);
us->srb->scsi_done(us->srb);
us->srb = NULL;
- scsi_unlock(us_to_host(us));
+ scsi_unlock(host);
}
+ mutex_unlock(&us->dev_mutex);
/* Now we own no commands so it's safe to remove the SCSI host */
- scsi_remove_host(us_to_host(us));
+ scsi_remove_host(host);
}
/* Second stage of disconnect processing: deallocate all resources */
@@ -961,7 +987,9 @@ static int storage_probe(struct usb_interface *intf,
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
- get_device_info(us, id);
+ result = get_device_info(us, id);
+ if (result)
+ goto BadDevice;
/* Get the transport, protocol, and pipe settings */
result = get_transport(us);
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index 009fb0953a5..21f3ddbc908 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -160,10 +160,10 @@ struct us_data {
};
/* Convert between us_data and the corresponding Scsi_Host */
-static struct Scsi_Host inline *us_to_host(struct us_data *us) {
+static inline struct Scsi_Host *us_to_host(struct us_data *us) {
return container_of((void *) us, struct Scsi_Host, hostdata);
}
-static struct us_data inline *host_to_us(struct Scsi_Host *host) {
+static inline struct us_data *host_to_us(struct Scsi_Host *host) {
return (struct us_data *) host->hostdata;
}
@@ -176,8 +176,4 @@ extern void fill_inquiry_response(struct us_data *us,
#define scsi_unlock(host) spin_unlock_irq(host->host_lock)
#define scsi_lock(host) spin_lock_irq(host->host_lock)
-
-/* Vendor ID list for devices that require special handling */
-#define USB_VENDOR_ID_GENESYS 0x05e3 /* Genesys Logic */
-
#endif
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 4de9fb56ebf..1b51d3187a9 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -1,5 +1,5 @@
/*
- * USB Skeleton driver - 2.0
+ * USB Skeleton driver - 2.2
*
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
*
@@ -7,13 +7,11 @@
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
- * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
- * but has been rewritten to be easy to read and use, as no locks are now
- * needed anymore.
+ * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
+ * but has been rewritten to be easier to read and use.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -22,6 +20,7 @@
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/mutex.h>
/* Define these values to match your devices */
@@ -33,38 +32,39 @@ static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, skel_table);
+MODULE_DEVICE_TABLE(usb, skel_table);
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
/* our private defines. if this grows any larger, use your own .h file */
-#define MAX_TRANSFER ( PAGE_SIZE - 512 )
+#define MAX_TRANSFER (PAGE_SIZE - 512)
#define WRITES_IN_FLIGHT 8
/* Structure to hold all of our device specific stuff */
struct usb_skel {
- struct usb_device * udev; /* the usb device for this device */
- struct usb_interface * interface; /* the interface for this device */
+ struct usb_device *dev; /* the usb device for this device */
+ struct usb_interface *interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
- unsigned char * bulk_in_buffer; /* the buffer to receive data */
+ unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
struct kref kref;
+ struct mutex io_mutex; /* synchronize I/O with disconnect */
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
static struct usb_driver skel_driver;
static void skel_delete(struct kref *kref)
-{
+{
struct usb_skel *dev = to_skel_dev(kref);
usb_put_dev(dev->udev);
- kfree (dev->bulk_in_buffer);
- kfree (dev);
+ kfree(dev->bulk_in_buffer);
+ kfree(dev);
}
static int skel_open(struct inode *inode, struct file *file)
@@ -90,6 +90,11 @@ static int skel_open(struct inode *inode, struct file *file)
goto exit;
}
+ /* prevent the device from being autosuspended */
+ retval = usb_autopm_get_interface(interface);
+ if (retval)
+ goto exit;
+
/* increment our usage count for the device */
kref_get(&dev->kref);
@@ -108,6 +113,12 @@ static int skel_release(struct inode *inode, struct file *file)
if (dev == NULL)
return -ENODEV;
+ /* allow the device to be autosuspended */
+ mutex_lock(&dev->io_mutex);
+ if (dev->interface)
+ usb_autopm_put_interface(dev->interface);
+ mutex_unlock(&dev->io_mutex);
+
/* decrement the count on our device */
kref_put(&dev->kref, skel_delete);
return 0;
@@ -116,11 +127,17 @@ static int skel_release(struct inode *inode, struct file *file)
static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
- int retval = 0;
+ int retval;
int bytes_read;
dev = (struct usb_skel *)file->private_data;
-
+
+ mutex_lock(&dev->io_mutex);
+ if (!dev->interface) { /* disconnect() was called */
+ retval = -ENODEV;
+ goto exit;
+ }
+
/* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
@@ -136,6 +153,8 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *
retval = bytes_read;
}
+exit:
+ mutex_unlock(&dev->io_mutex);
return retval;
}
@@ -146,16 +165,16 @@ static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
dev = (struct usb_skel *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
+ if (urb->status &&
+ !(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
- dbg("%s - nonzero write bulk status received: %d",
+ err("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}
/* free up our allocated buffer */
- usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
up(&dev->limit_sem);
}
@@ -180,6 +199,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
goto exit;
}
+ mutex_lock(&dev->io_mutex);
+ if (!dev->interface) { /* disconnect() was called */
+ retval = -ENODEV;
+ goto error;
+ }
+
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
@@ -214,17 +239,22 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb);
-exit:
+ mutex_unlock(&dev->io_mutex);
return writesize;
error:
- usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
- usb_free_urb(urb);
+ if (urb) {
+ usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+ mutex_unlock(&dev->io_mutex);
up(&dev->limit_sem);
+
+exit:
return retval;
}
-static struct file_operations skel_fops = {
+static const struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
@@ -232,7 +262,7 @@ static struct file_operations skel_fops = {
.release = skel_release,
};
-/*
+/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
@@ -244,7 +274,7 @@ static struct usb_class_driver skel_class = {
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
- struct usb_skel *dev = NULL;
+ struct usb_skel *dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
@@ -253,12 +283,13 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
+ if (!dev) {
err("Out of memory");
goto error;
}
kref_init(&dev->kref);
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
+ mutex_init(&dev->io_mutex);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
@@ -270,10 +301,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->bulk_in_endpointAddr &&
- ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
@@ -286,10 +314,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
}
if (!dev->bulk_out_endpointAddr &&
- ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
@@ -335,6 +360,11 @@ static void skel_disconnect(struct usb_interface *interface)
/* give back our minor */
usb_deregister_dev(interface, &skel_class);
+ /* prevent more I/O from starting */
+ mutex_lock(&dev->io_mutex);
+ dev->interface = NULL;
+ mutex_unlock(&dev->io_mutex);
+
unlock_kernel();
/* decrement our usage count */
@@ -368,7 +398,7 @@ static void __exit usb_skel_exit(void)
usb_deregister(&skel_driver);
}
-module_init (usb_skel_init);
-module_exit (usb_skel_exit);
+module_init(usb_skel_init);
+module_exit(usb_skel_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c
index 78488bb41ae..0dda73da862 100644
--- a/drivers/video/68328fb.c
+++ b/drivers/video/68328fb.c
@@ -32,7 +32,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 60c6773eaac..e0ef3328942 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,6 +4,21 @@
menu "Graphics support"
+config FIRMWARE_EDID
+ bool "Enable firmware EDID"
+ default y
+ ---help---
+ This enables access to the EDID transferred from the firmware.
+ On the i386, this is from the Video BIOS. Enable this if DDC/I2C
+ transfers do not work for your driver and if you are using
+ nvidiafb, i810fb or savagefb.
+
+ In general, choosing Y for this option is safe. If you
+ experience extremely long delays while booting before you get
+ something on your display, try setting this to N. Matrox cards in
+ combination with certain motherboards and monitors are known to
+ suffer from this problem.
+
config FB
tristate "Support for frame buffer devices"
---help---
@@ -70,21 +85,12 @@ config FB_MACMODES
depends on FB
default n
-config FB_FIRMWARE_EDID
- bool "Enable firmware EDID"
- depends on FB
- default y
- ---help---
- This enables access to the EDID transferred from the firmware.
- On the i386, this is from the Video BIOS. Enable this if DDC/I2C
- transfers do not work for your driver and if you are using
- nvidiafb, i810fb or savagefb.
-
- In general, choosing Y for this option is safe. If you
- experience extremely long delays while booting before you get
- something on your display, try setting this to N. Matrox cards in
- combination with certain motherboards and monitors are known to
- suffer from this problem.
+config FB_BACKLIGHT
+ bool
+ depends on FB
+ select BACKLIGHT_LCD_SUPPORT
+ select BACKLIGHT_CLASS_DEVICE
+ default n
config FB_MODE_HELPERS
bool "Enable Video Mode Handling Helpers"
@@ -416,7 +422,7 @@ config FB_OF
config FB_CONTROL
bool "Apple \"control\" display support"
- depends on (FB = y) && PPC_PMAC
+ depends on (FB = y) && PPC_PMAC && PPC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -427,7 +433,7 @@ config FB_CONTROL
config FB_PLATINUM
bool "Apple \"platinum\" display support"
- depends on (FB = y) && PPC_PMAC
+ depends on (FB = y) && PPC_PMAC && PPC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -438,7 +444,7 @@ config FB_PLATINUM
config FB_VALKYRIE
bool "Apple \"valkyrie\" display support"
- depends on (FB = y) && (MAC || PPC_PMAC)
+ depends on (FB = y) && (MAC || (PPC_PMAC && PPC32))
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -449,7 +455,7 @@ config FB_VALKYRIE
config FB_CT65550
bool "Chips 65550 display support"
- depends on (FB = y) && PPC
+ depends on (FB = y) && PPC32
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -546,10 +552,14 @@ config FB_VESA
You will get a boot time penguin logo at no additional cost. Please
read <file:Documentation/fb/vesafb.txt>. If unsure, say Y.
-config VIDEO_SELECT
- bool
- depends on FB_VESA
- default y
+config FB_IMAC
+ bool "Intel-based Macintosh Framebuffer Support"
+ depends on (FB = y) && X86 && EFI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ This is the frame buffer device driver for the Intel-based Macintosh
config FB_HGA
tristate "Hercules mono graphics support"
@@ -573,12 +583,6 @@ config FB_HGA_ACCEL
This will compile the Hercules mono graphics with
acceleration functions.
-
-config VIDEO_SELECT
- bool
- depends on (FB = y) && X86
- default y
-
config FB_SGIVW
tristate "SGI Visual Workstation framebuffer support"
depends on FB && X86_VISWS
@@ -717,6 +721,14 @@ config FB_NVIDIA_I2C
independently validate video mode parameters, you should say Y
here.
+config FB_NVIDIA_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_NVIDIA && PMAC_BACKLIGHT
+ select FB_BACKLIGHT
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_RIVA
tristate "nVidia Riva support"
depends on FB && PCI
@@ -755,6 +767,14 @@ config FB_RIVA_DEBUG
of debugging informations to provide to the maintainer when
something goes wrong.
+config FB_RIVA_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_RIVA && PMAC_BACKLIGHT
+ select FB_BACKLIGHT
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_I810
tristate "Intel 810/815 support (EXPERIMENTAL)"
depends on FB && EXPERIMENTAL && PCI && X86_32
@@ -1011,6 +1031,7 @@ config FB_RADEON
There is a product page at
http://apps.ati.com/ATIcompare/
+
config FB_RADEON_I2C
bool "DDC/I2C for ATI Radeon support"
depends on FB_RADEON
@@ -1018,6 +1039,14 @@ config FB_RADEON_I2C
help
Say Y here if you want DDC/I2C support for your Radeon board.
+config FB_RADEON_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_RADEON && PMAC_BACKLIGHT
+ select FB_BACKLIGHT
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_RADEON_DEBUG
bool "Lots of debug output from Radeon driver"
depends on FB_RADEON
@@ -1042,6 +1071,14 @@ config FB_ATY128
To compile this driver as a module, choose M here: the
module will be called aty128fb.
+config FB_ATY128_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_ATY128 && PMAC_BACKLIGHT
+ select FB_BACKLIGHT
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_ATY
tristate "ATI Mach64 display support" if PCI || ATARI
depends on FB && !SPARC32
@@ -1084,6 +1121,14 @@ config FB_ATY_GX
is at
<http://support.ati.com/products/pc/mach64/graphics_xpression.html>.
+config FB_ATY_BACKLIGHT
+ bool "Support for backlight control"
+ depends on FB_ATY && PMAC_BACKLIGHT
+ select FB_BACKLIGHT
+ default y
+ help
+ Say Y here if you want to control the backlight of your display.
+
config FB_S3TRIO
bool "S3 Trio display support"
depends on (FB = y) && PPC && BROKEN
@@ -1483,6 +1528,26 @@ config FB_PXA_PARAMETERS
<file:Documentation/fb/pxafb.txt> describes the available parameters.
+config FB_MBX
+ tristate "2700G LCD framebuffer support"
+ depends on FB && ARCH_PXA
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Framebuffer driver for the Intel 2700G (Marathon) Graphics
+ Accelerator
+
+config FB_MBX_DEBUG
+ bool "Enable debugging info via debugfs"
+ depends on FB_MBX && DEBUG_FS
+ default n
+ ---help---
+ Enable this if you want debugging information using the debug
+ filesystem (debugfs)
+
+ If unsure, say N.
+
config FB_W100
tristate "W100 frame buffer support"
depends on FB && PXA_SHARPSL
@@ -1522,6 +1587,21 @@ config FB_S3C2410_DEBUG
Turn on debugging messages. Note that you can set/unset at run time
through sysfs
+config FB_PNX4008_DUM
+ tristate "Display Update Module support on Philips PNX4008 board"
+ depends on FB && ARCH_PNX4008
+ ---help---
+ Say Y here to enable support for PNX4008 Display Update Module (DUM)
+
+config FB_PNX4008_DUM_RGB
+ tristate "RGB Framebuffer support on Philips PNX4008 board"
+ depends on FB_PNX4008_DUM
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Say Y here to enable support for PNX4008 RGB Framebuffer
+
config FB_VIRTUAL
tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)"
depends on FB
@@ -1550,7 +1630,7 @@ if FB || SGI_NEWPORT_CONSOLE
source "drivers/video/logo/Kconfig"
endif
-if FB && SYSFS
+if SYSFS
source "drivers/video/backlight/Kconfig"
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 23de3b2c785..481c6c9695f 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -4,15 +4,16 @@
# Each configuration option enables a list of files.
-obj-$(CONFIG_VT) += console/
-obj-$(CONFIG_LOGO) += logo/
-obj-$(CONFIG_SYSFS) += backlight/
-
+obj-y += fb_notify.o
obj-$(CONFIG_FB) += fb.o
fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \
modedb.o fbcvt.o
fb-objs := $(fb-y)
+obj-$(CONFIG_VT) += console/
+obj-$(CONFIG_LOGO) += logo/
+obj-$(CONFIG_SYSFS) += backlight/
+
obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
@@ -38,6 +39,7 @@ obj-$(CONFIG_FB_SIS) += sis/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
+obj-$(CONFIG_FB_MBX) += mbx/
obj-$(CONFIG_FB_I810) += vgastate.o
obj-$(CONFIG_FB_NEOMAGIC) += neofb.o vgastate.o
obj-$(CONFIG_FB_VIRGE) += virgefb.o
@@ -94,9 +96,12 @@ obj-$(CONFIG_FB_TX3912) += tx3912fb.o
obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o
obj-$(CONFIG_FB_IMX) += imxfb.o
obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
+obj-$(CONFIG_FB_PNX4008_DUM) += pnx4008/
+obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnx4008/
# Platform or fallback drivers go here
obj-$(CONFIG_FB_VESA) += vesafb.o
+obj-$(CONFIG_FB_IMAC) += imacfb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o vgastate.o
obj-$(CONFIG_FB_OF) += offb.o
diff --git a/drivers/video/S3triofb.c b/drivers/video/S3triofb.c
index 455fda990ff..397005eb392 100644
--- a/drivers/video/S3triofb.c
+++ b/drivers/video/S3triofb.c
@@ -23,13 +23,11 @@
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -351,30 +349,30 @@ static void __init s3triofb_of_init(struct device_node *dp)
s3trio_name[sizeof(s3trio_name)-1] = '\0';
strcpy(fb_fix.id, s3trio_name);
- if((pp = (int *)get_property(dp, "vendor-id", &len)) != NULL
+ if((pp = get_property(dp, "vendor-id", &len)) != NULL
&& *pp!=PCI_VENDOR_ID_S3) {
printk("%s: can't find S3 Trio board\n", dp->full_name);
return;
}
- if((pp = (int *)get_property(dp, "device-id", &len)) != NULL
+ if((pp = get_property(dp, "device-id", &len)) != NULL
&& *pp!=PCI_DEVICE_ID_S3_TRIO) {
printk("%s: can't find S3 Trio board\n", dp->full_name);
return;
}
- if ((pp = (int *)get_property(dp, "depth", &len)) != NULL
+ if ((pp = get_property(dp, "depth", &len)) != NULL
&& len == sizeof(int) && *pp != 8) {
printk("%s: can't use depth = %d\n", dp->full_name, *pp);
return;
}
- if ((pp = (int *)get_property(dp, "width", &len)) != NULL
+ if ((pp = get_property(dp, "width", &len)) != NULL
&& len == sizeof(int))
fb_var.xres = fb_var.xres_virtual = *pp;
- if ((pp = (int *)get_property(dp, "height", &len)) != NULL
+ if ((pp = get_property(dp, "height", &len)) != NULL
&& len == sizeof(int))
fb_var.yres = fb_var.yres_virtual = *pp;
- if ((pp = (int *)get_property(dp, "linebytes", &len)) != NULL
+ if ((pp = get_property(dp, "linebytes", &len)) != NULL
&& len == sizeof(int))
fb_fix.line_length = *pp;
else
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 98baecccb3f..61a8bf159cb 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -17,7 +17,6 @@
* - Blanking 8bpp displays with VIDC
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 3033c72dea2..f1ba54f4fc3 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -45,10 +45,8 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index 466042808da..70dd8115a4d 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -39,7 +39,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -561,7 +560,7 @@ static int __init arcfb_probe(struct platform_device *dev)
platform_set_drvdata(dev, info);
if (irq) {
par->irq = irq;
- if (request_irq(par->irq, &arcfb_interrupt, SA_SHIRQ,
+ if (request_irq(par->irq, &arcfb_interrupt, IRQF_SHARED,
"arcfb", info)) {
printk(KERN_INFO
"arcfb: Failed req IRQ %d\n", par->irq);
diff --git a/drivers/video/asiliantfb.c b/drivers/video/asiliantfb.c
index 29f9f0dfe3b..1fd22f460b0 100644
--- a/drivers/video/asiliantfb.c
+++ b/drivers/video/asiliantfb.c
@@ -29,13 +29,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index e69ab65f784..5831893bf7a 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -53,7 +53,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/aty/Makefile b/drivers/video/aty/Makefile
index 18521397a6e..a6cc0e9ec79 100644
--- a/drivers/video/aty/Makefile
+++ b/drivers/video/aty/Makefile
@@ -10,5 +10,6 @@ atyfb-objs := $(atyfb-y)
radeonfb-y := radeon_base.o radeon_pm.o radeon_monitor.o radeon_accel.o
radeonfb-$(CONFIG_FB_RADEON_I2C) += radeon_i2c.o
+radeonfb-$(CONFIG_FB_RADEON_BACKLIGHT) += radeon_backlight.o
radeonfb-objs := $(radeonfb-y)
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index f7bbff4ddc6..276a21530b9 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -46,14 +46,12 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -64,6 +62,7 @@
#include <linux/pci.h>
#include <linux/ioport.h>
#include <linux/console.h>
+#include <linux/backlight.h>
#include <asm/io.h>
#ifdef CONFIG_PPC_PMAC
@@ -99,7 +98,7 @@
#ifndef CONFIG_PPC_PMAC
/* default mode */
-static struct fb_var_screeninfo default_var __initdata = {
+static struct fb_var_screeninfo default_var __devinitdata = {
/* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */
640, 480, 640, 480, 0, 0, 8, 0,
{0, 8, 0}, {0, 8, 0}, {0, 8, 0}, {0, 0, 0},
@@ -122,7 +121,7 @@ static struct fb_var_screeninfo default_var = {
/* default modedb mode */
/* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */
-static struct fb_videomode defaultmode __initdata = {
+static struct fb_videomode defaultmode __devinitdata = {
.refresh = 60,
.xres = 640,
.yres = 480,
@@ -334,7 +333,7 @@ static const struct aty128_meminfo sdr_sgram =
static const struct aty128_meminfo ddr_sgram =
{ 4, 4, 3, 3, 2, 3, 1, 16, 31, 16, "64-bit DDR SGRAM" };
-static struct fb_fix_screeninfo aty128fb_fix __initdata = {
+static struct fb_fix_screeninfo aty128fb_fix __devinitdata = {
.id = "ATY Rage128",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
@@ -344,15 +343,15 @@ static struct fb_fix_screeninfo aty128fb_fix __initdata = {
.accel = FB_ACCEL_ATI_RAGE128,
};
-static char *mode_option __initdata = NULL;
+static char *mode_option __devinitdata = NULL;
#ifdef CONFIG_PPC_PMAC
-static int default_vmode __initdata = VMODE_1024_768_60;
-static int default_cmode __initdata = CMODE_8;
+static int default_vmode __devinitdata = VMODE_1024_768_60;
+static int default_cmode __devinitdata = CMODE_8;
#endif
-static int default_crt_on __initdata = 0;
-static int default_lcd_on __initdata = 1;
+static int default_crt_on __devinitdata = 0;
+static int default_lcd_on __devinitdata = 1;
#ifdef CONFIG_MTRR
static int mtrr = 1;
@@ -444,9 +443,9 @@ static int aty128_encode_var(struct fb_var_screeninfo *var,
static int aty128_decode_var(struct fb_var_screeninfo *var,
struct aty128fb_par *par);
#if 0
-static void __init aty128_get_pllinfo(struct aty128fb_par *par,
+static void __devinit aty128_get_pllinfo(struct aty128fb_par *par,
void __iomem *bios);
-static void __init __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
+static void __devinit __iomem *aty128_map_ROM(struct pci_dev *pdev, const struct aty128fb_par *par);
#endif
static void aty128_timings(struct aty128fb_par *par);
static void aty128_init_engine(struct aty128fb_par *par);
@@ -457,6 +456,10 @@ static void wait_for_fifo(u16 entries, struct aty128fb_par *par);
static void wait_for_idle(struct aty128fb_par *par);
static u32 depth_to_dst(u32 depth);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+static void aty128_bl_set_power(struct fb_info *info, int power);
+#endif
+
#define BIOS_IN8(v) (readb(bios + (v)))
#define BIOS_IN16(v) (readb(bios + (v)) | \
(readb(bios + (v) + 1) << 8))
@@ -480,16 +483,6 @@ static struct fb_ops aty128fb_ops = {
.fb_imageblit = cfb_imageblit,
};
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int aty128_set_backlight_enable(int on, int level, void* data);
-static int aty128_set_backlight_level(int level, void* data);
-
-static struct backlight_controller aty128_backlight_controller = {
- aty128_set_backlight_enable,
- aty128_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
/*
* Functions to read from/write to the mmio registers
* - endian conversions may possibly be avoided by
@@ -582,7 +575,7 @@ static void aty_pll_writeupdate(const struct aty128fb_par *par)
/* write to the scratch register to test r/w functionality */
-static int __init register_test(const struct aty128fb_par *par)
+static int __devinit register_test(const struct aty128fb_par *par)
{
u32 val;
int flag = 0;
@@ -781,7 +774,7 @@ static u32 depth_to_dst(u32 depth)
#ifndef __sparc__
-static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
+static void __iomem * __devinit aty128_map_ROM(const struct aty128fb_par *par, struct pci_dev *dev)
{
u16 dptr;
u8 rom_type;
@@ -865,7 +858,7 @@ static void __iomem * __init aty128_map_ROM(const struct aty128fb_par *par, stru
return NULL;
}
-static void __init aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
+static void __devinit aty128_get_pllinfo(struct aty128fb_par *par, unsigned char __iomem *bios)
{
unsigned int bios_hdr;
unsigned int bios_pll;
@@ -912,7 +905,7 @@ static void __iomem * __devinit aty128_find_mem_vbios(struct aty128fb_par *par)
#endif /* ndef(__sparc__) */
/* fill in known card constants if pll_block is not available */
-static void __init aty128_timings(struct aty128fb_par *par)
+static void __devinit aty128_timings(struct aty128fb_par *par)
{
#ifdef CONFIG_PPC_OF
/* instead of a table lookup, assume OF has properly
@@ -1258,19 +1251,21 @@ static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
{
u32 reg;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+#endif
if (on) {
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION;
reg &= ~LVDS_DISPLAY_DIS;
aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef CONFIG_PMAC_BACKLIGHT
- aty128_set_backlight_enable(get_backlight_enable(),
- get_backlight_level(), par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_set_power(info, FB_BLANK_UNBLANK);
#endif
} else {
-#ifdef CONFIG_PMAC_BACKLIGHT
- aty128_set_backlight_enable(0, 0, par);
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_set_power(info, FB_BLANK_POWERDOWN);
#endif
reg = aty_ld_le32(LVDS_GEN_CNTL);
reg |= LVDS_DISPLAY_DIS;
@@ -1638,7 +1633,7 @@ static int aty128fb_sync(struct fb_info *info)
}
#ifndef MODULE
-static int __init aty128fb_setup(char *options)
+static int __devinit aty128fb_setup(char *options)
{
char *this_opt;
@@ -1691,6 +1686,211 @@ static int __init aty128fb_setup(char *options)
}
#endif /* MODULE */
+/* Backlight */
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+#define MAX_LEVEL 0xFF
+
+static struct backlight_properties aty128_bl_data;
+
+/* Call with fb_info->bl_mutex held */
+static int aty128_bl_get_level_brightness(struct aty128fb_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int atylevel;
+
+ /* Get and convert the value */
+ atylevel = MAX_LEVEL -
+ (info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL);
+
+ if (atylevel < 0)
+ atylevel = 0;
+ else if (atylevel > MAX_LEVEL)
+ atylevel = MAX_LEVEL;
+
+ return atylevel;
+}
+
+/* We turn off the LCD completely instead of just dimming the backlight.
+ * This provides greater power saving and the display is useless without
+ * backlight anyway
+ */
+#define BACKLIGHT_LVDS_OFF
+/* That one prevents proper CRT output with LCD off */
+#undef BACKLIGHT_DAC_OFF
+
+/* Call with fb_info->bl_mutex held */
+static int __aty128_bl_update_status(struct backlight_device *bd)
+{
+ struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+ unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK ||
+ !par->lcd_on)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ reg |= LVDS_BL_MOD_EN | LVDS_BLON;
+ if (level > 0) {
+ reg |= LVDS_DIGION;
+ if (!(reg & LVDS_ON)) {
+ reg &= ~LVDS_BLON;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ aty_ld_le32(LVDS_GEN_CNTL);
+ mdelay(10);
+ reg |= LVDS_BLON;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ }
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (aty128_bl_get_level_brightness(par, level) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+ reg |= LVDS_ON | LVDS_EN;
+ reg &= ~LVDS_DISPLAY_DIS;
+#endif
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
+#endif
+ } else {
+ reg &= ~LVDS_BL_MOD_LEVEL_MASK;
+ reg |= (aty128_bl_get_level_brightness(par, 0) << LVDS_BL_MOD_LEVEL_SHIFT);
+#ifdef BACKLIGHT_LVDS_OFF
+ reg |= LVDS_DISPLAY_DIS;
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+ aty_ld_le32(LVDS_GEN_CNTL);
+ udelay(10);
+ reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
+#endif
+ aty_st_le32(LVDS_GEN_CNTL, reg);
+#ifdef BACKLIGHT_DAC_OFF
+ aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
+#endif
+ }
+
+ return 0;
+}
+
+static int aty128_bl_update_status(struct backlight_device *bd)
+{
+ struct aty128fb_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __aty128_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
+static int aty128_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties aty128_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = aty128_bl_get_brightness,
+ .update_status = aty128_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+static void aty128_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __aty128_bl_update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+
+ mutex_unlock(&info->bl_mutex);
+}
+
+static void aty128_bl_init(struct aty128fb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+ /* Could be extended to Rage128Pro LVDS output too */
+ if (par->chip_gen != rage_M3)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "aty128bl%d", info->node);
+
+ bd = backlight_device_register(name, par, &aty128_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk(KERN_WARNING "aty128: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 63 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 219 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ down(&bd->sem);
+ bd->props->brightness = aty128_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ up(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("aty128: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void aty128_bl_exit(struct aty128fb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+ info->bl_dev = NULL;
+
+ printk("aty128: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#endif /* CONFIG_FB_ATY128_BACKLIGHT */
/*
* Initialisation
@@ -1708,7 +1908,7 @@ static void aty128_early_resume(void *data)
}
#endif /* CONFIG_PPC_PMAC */
-static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit aty128_init(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct aty128fb_par *par = info->par;
@@ -1717,9 +1917,6 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
u8 chip_rev;
u32 dac;
- if (!par->vram_size) /* may have already been probed */
- par->vram_size = aty_ld_le32(CONFIG_MEMSIZE) & 0x03FFFFFF;
-
/* Get the chip revision */
chip_rev = (aty_ld_le32(CONFIG_CNTL) >> 16) & 0x1F;
@@ -1832,20 +2029,18 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
aty128_init_engine(par);
- if (register_framebuffer(info) < 0)
- return 0;
-
-#ifdef CONFIG_PMAC_BACKLIGHT
- /* Could be extended to Rage128Pro LVDS output too */
- if (par->chip_gen == rage_M3)
- register_backlight_controller(&aty128_backlight_controller, par, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
par->pm_reg = pci_find_capability(pdev, PCI_CAP_ID_PM);
par->pdev = pdev;
par->asleep = 0;
par->lock_blank = 0;
-
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_init(par);
+#endif
+
+ if (register_framebuffer(info) < 0)
+ return 0;
+
printk(KERN_INFO "fb%d: %s frame buffer device on %s\n",
info->node, info->fix.id, video_card);
@@ -1854,7 +2049,7 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
#ifdef CONFIG_PCI
/* register a card ++ajoshi */
-static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit aty128_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned long fb_addr, reg_addr;
struct aty128fb_par *par;
@@ -1895,7 +2090,6 @@ static int __init aty128_probe(struct pci_dev *pdev, const struct pci_device_id
par = info->par;
info->pseudo_palette = par->pseudo_palette;
- info->fix = aty128fb_fix;
/* Virtualize mmio region */
info->fix.mmio_start = reg_addr;
@@ -1981,6 +2175,10 @@ static void __devexit aty128_remove(struct pci_dev *pdev)
par = info->par;
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
+ aty128_bl_exit(par);
+#endif
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
@@ -2011,10 +2209,10 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
if (machine_is(powermac) && blank)
- set_backlight_enable(0);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ aty128_bl_set_power(fb, FB_BLANK_POWERDOWN);
+#endif
if (blank & FB_BLANK_VSYNC_SUSPEND)
state |= 2;
@@ -2029,10 +2227,12 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
aty128_set_crt_enable(par, par->crt_on && !blank);
aty128_set_lcd_enable(par, par->lcd_on && !blank);
}
-#ifdef CONFIG_PMAC_BACKLIGHT
+
+#ifdef CONFIG_FB_ATY128_BACKLIGHT
if (machine_is(powermac) && !blank)
- set_backlight_enable(1);
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ aty128_bl_set_power(fb, FB_BLANK_UNBLANK);
+#endif
+
return 0;
}
@@ -2138,73 +2338,6 @@ static int aty128fb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -EINVAL;
}
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int backlight_conv[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides greater power saving and the display is useless without
- * backlight anyway
- */
-#define BACKLIGHT_LVDS_OFF
-/* That one prevents proper CRT output with LCD off */
-#undef BACKLIGHT_DAC_OFF
-
-static int aty128_set_backlight_enable(int on, int level, void *data)
-{
- struct aty128fb_par *par = data;
- unsigned int reg = aty_ld_le32(LVDS_GEN_CNTL);
-
- if (!par->lcd_on)
- on = 0;
- reg |= LVDS_BL_MOD_EN | LVDS_BLON;
- if (on && level > BACKLIGHT_OFF) {
- reg |= LVDS_DIGION;
- if (!(reg & LVDS_ON)) {
- reg &= ~LVDS_BLON;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- (void)aty_ld_le32(LVDS_GEN_CNTL);
- mdelay(10);
- reg |= LVDS_BLON;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- }
- reg &= ~LVDS_BL_MOD_LEVEL_MASK;
- reg |= (backlight_conv[level] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
- reg |= LVDS_ON | LVDS_EN;
- reg &= ~LVDS_DISPLAY_DIS;
-#endif
- aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) & (~DAC_PDWN));
-#endif
- } else {
- reg &= ~LVDS_BL_MOD_LEVEL_MASK;
- reg |= (backlight_conv[0] << LVDS_BL_MOD_LEVEL_SHIFT);
-#ifdef BACKLIGHT_LVDS_OFF
- reg |= LVDS_DISPLAY_DIS;
- aty_st_le32(LVDS_GEN_CNTL, reg);
- (void)aty_ld_le32(LVDS_GEN_CNTL);
- udelay(10);
- reg &= ~(LVDS_ON | LVDS_EN | LVDS_BLON | LVDS_DIGION);
-#endif
- aty_st_le32(LVDS_GEN_CNTL, reg);
-#ifdef BACKLIGHT_DAC_OFF
- aty_st_le32(DAC_CNTL, aty_ld_le32(DAC_CNTL) | DAC_PDWN);
-#endif
- }
-
- return 0;
-}
-
-static int aty128_set_backlight_level(int level, void* data)
-{
- return aty128_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
#if 0
/*
* Accelerated functions
@@ -2428,7 +2561,7 @@ static int aty128_pci_resume(struct pci_dev *pdev)
}
-static int __init aty128fb_init(void)
+static int __devinit aty128fb_init(void)
{
#ifndef MODULE
char *option = NULL;
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index e9b7a64c1ac..55fb8b04489 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -2,7 +2,6 @@
* ATI Frame Buffer Device Driver Core Definitions
*/
-#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
/*
@@ -151,6 +150,7 @@ struct atyfb_par {
int lock_blank;
unsigned long res_start;
unsigned long res_size;
+ struct pci_dev *pdev;
#ifdef __sparc__
struct pci_mmap_map *mmap_map;
u8 mmaped;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index eb6aa42be60..19a71f04578 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -49,7 +49,6 @@
******************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -66,6 +65,7 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/wait.h>
+#include <linux/backlight.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -315,12 +315,12 @@ static int vram;
static int pll;
static int mclk;
static int xclk;
-static int comp_sync __initdata = -1;
+static int comp_sync __devinitdata = -1;
static char *mode;
#ifdef CONFIG_PPC
-static int default_vmode __initdata = VMODE_CHOOSE;
-static int default_cmode __initdata = CMODE_CHOOSE;
+static int default_vmode __devinitdata = VMODE_CHOOSE;
+static int default_cmode __devinitdata = CMODE_CHOOSE;
module_param_named(vmode, default_vmode, int, 0);
MODULE_PARM_DESC(vmode, "int: video mode for mac");
@@ -329,10 +329,10 @@ MODULE_PARM_DESC(cmode, "int: color mode for mac");
#endif
#ifdef CONFIG_ATARI
-static unsigned int mach64_count __initdata = 0;
-static unsigned long phys_vmembase[FB_MAX] __initdata = { 0, };
-static unsigned long phys_size[FB_MAX] __initdata = { 0, };
-static unsigned long phys_guiregbase[FB_MAX] __initdata = { 0, };
+static unsigned int mach64_count __devinitdata = 0;
+static unsigned long phys_vmembase[FB_MAX] __devinitdata = { 0, };
+static unsigned long phys_size[FB_MAX] __devinitdata = { 0, };
+static unsigned long phys_guiregbase[FB_MAX] __devinitdata = { 0, };
#endif
/* top -> down is an evolution of mach64 chipset, any corrections? */
@@ -582,7 +582,7 @@ static u32 atyfb_get_pixclock(struct fb_var_screeninfo *var, struct atyfb_par *p
* Apple monitor sense
*/
-static int __init read_aty_sense(const struct atyfb_par *par)
+static int __devinit read_aty_sense(const struct atyfb_par *par)
{
int sense, i;
@@ -1280,6 +1280,14 @@ static int atyfb_set_par(struct fb_info *info)
par->accel_flags = var->accel_flags; /* hack */
+ if (var->accel_flags) {
+ info->fbops->fb_sync = atyfb_sync;
+ info->flags &= ~FBINFO_HWACCEL_DISABLED;
+ } else {
+ info->fbops->fb_sync = NULL;
+ info->flags |= FBINFO_HWACCEL_DISABLED;
+ }
+
if (par->blitter_may_be_busy)
wait_for_idle(par);
@@ -1559,7 +1567,7 @@ static int aty_enable_irq(struct atyfb_par *par, int reenable)
u32 int_cntl;
if (!test_and_set_bit(0, &par->irq_flags)) {
- if (request_irq(par->irq, aty_irq, SA_SHIRQ, "atyfb", par)) {
+ if (request_irq(par->irq, aty_irq, IRQF_SHARED, "atyfb", par)) {
clear_bit(0, &par->irq_flags);
return -EINVAL;
}
@@ -2115,47 +2123,171 @@ static int atyfb_pci_resume(struct pci_dev *pdev)
#endif /* defined(CONFIG_PM) && defined(CONFIG_PCI) */
-#ifdef CONFIG_PMAC_BACKLIGHT
+/* Backlight */
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+#define MAX_LEVEL 0xFF
- /*
- * LCD backlight control
- */
+static struct backlight_properties aty_bl_data;
-static int backlight_conv[] = {
- 0x00, 0x3f, 0x4c, 0x59, 0x66, 0x73, 0x80, 0x8d,
- 0x9a, 0xa7, 0xb4, 0xc1, 0xcf, 0xdc, 0xe9, 0xff
-};
+/* Call with fb_info->bl_mutex held */
+static int aty_bl_get_level_brightness(struct atyfb_par *par, int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int atylevel;
+
+ /* Get and convert the value */
+ atylevel = info->bl_curve[level] * FB_BACKLIGHT_MAX / MAX_LEVEL;
+
+ if (atylevel < 0)
+ atylevel = 0;
+ else if (atylevel > MAX_LEVEL)
+ atylevel = MAX_LEVEL;
-static int aty_set_backlight_enable(int on, int level, void *data)
+ return atylevel;
+}
+
+/* Call with fb_info->bl_mutex held */
+static int __aty_bl_update_status(struct backlight_device *bd)
{
- struct fb_info *info = (struct fb_info *) data;
- struct atyfb_par *par = (struct atyfb_par *) info->par;
+ struct atyfb_par *par = class_get_devdata(&bd->class_dev);
unsigned int reg = aty_ld_lcd(LCD_MISC_CNTL, par);
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
reg |= (BLMOD_EN | BIASMOD_EN);
- if (on && level > BACKLIGHT_OFF) {
+ if (level > 0) {
reg &= ~BIAS_MOD_LEVEL_MASK;
- reg |= (backlight_conv[level] << BIAS_MOD_LEVEL_SHIFT);
+ reg |= (aty_bl_get_level_brightness(par, level) << BIAS_MOD_LEVEL_SHIFT);
} else {
reg &= ~BIAS_MOD_LEVEL_MASK;
- reg |= (backlight_conv[0] << BIAS_MOD_LEVEL_SHIFT);
+ reg |= (aty_bl_get_level_brightness(par, 0) << BIAS_MOD_LEVEL_SHIFT);
}
aty_st_lcd(LCD_MISC_CNTL, reg, par);
+
return 0;
}
-static int aty_set_backlight_level(int level, void *data)
+static int aty_bl_update_status(struct backlight_device *bd)
{
- return aty_set_backlight_enable(1, level, data);
+ struct atyfb_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __aty_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
}
-static struct backlight_controller aty_backlight_controller = {
- aty_set_backlight_enable,
- aty_set_backlight_level
+static int aty_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties aty_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = aty_bl_get_brightness,
+ .update_status = aty_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-static void __init aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
+static void aty_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __aty_bl_update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+
+ mutex_unlock(&info->bl_mutex);
+}
+
+static void aty_bl_init(struct atyfb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "atybl%d", info->node);
+
+ bd = backlight_device_register(name, par, &aty_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk(KERN_WARNING "aty: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x3F * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0xFF * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ down(&bd->sem);
+ bd->props->brightness = aty_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ up(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("aty: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void aty_bl_exit(struct atyfb_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("aty: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+
+#endif /* CONFIG_FB_ATY_BACKLIGHT */
+
+static void __devinit aty_calc_mem_refresh(struct atyfb_par *par, int xclk)
{
const int ragepro_tbl[] = {
44, 50, 55, 66, 75, 80, 100
@@ -2215,7 +2347,7 @@ static int __devinit atyfb_get_timings_from_lcd(struct atyfb_par *par,
}
#endif /* defined(__i386__) && defined(CONFIG_FB_ATY_GENERIC_LCD) */
-static int __init aty_init(struct fb_info *info, const char *name)
+static int __devinit aty_init(struct fb_info *info, const char *name)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
const char *ramname = NULL, *xtal;
@@ -2296,12 +2428,15 @@ static int __init aty_init(struct fb_info *info, const char *name)
break;
}
switch (clk_type) {
+#ifdef CONFIG_ATARI
case CLK_ATI18818_1:
par->pll_ops = &aty_pll_ati18818_1;
break;
+#else
case CLK_IBMRGB514:
par->pll_ops = &aty_pll_ibm514;
break;
+#endif
#if 0 /* dead code */
case CLK_STG1703:
par->pll_ops = &aty_pll_stg1703;
@@ -2506,16 +2641,24 @@ static int __init aty_init(struct fb_info *info, const char *name)
info->fbops = &atyfb_ops;
info->pseudo_palette = pseudo_palette;
- info->flags = FBINFO_FLAG_DEFAULT;
+ info->flags = FBINFO_DEFAULT |
+ FBINFO_HWACCEL_IMAGEBLIT |
+ FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_COPYAREA |
+ FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_PMAC_BACKLIGHT
if (M64_HAS(G3_PB_1_1) && machine_is_compatible("PowerBook1,1")) {
/* these bits let the 101 powerbook wake up from sleep -- paulus */
aty_st_lcd(POWER_MANAGEMENT, aty_ld_lcd(POWER_MANAGEMENT, par)
| (USE_F32KHZ | TRISTATE_MEM_EN), par);
- } else if (M64_HAS(MOBIL_BUS))
- register_backlight_controller(&aty_backlight_controller, info, "ati");
-#endif /* CONFIG_PMAC_BACKLIGHT */
+ } else
+#endif
+ if (M64_HAS(MOBIL_BUS)) {
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ aty_bl_init (par);
+#endif
+ }
memset(&var, 0, sizeof(var));
#ifdef CONFIG_PPC
@@ -2631,7 +2774,7 @@ aty_init_exit:
}
#ifdef CONFIG_ATARI
-static int __init store_video_par(char *video_str, unsigned char m64_num)
+static int __devinit store_video_par(char *video_str, unsigned char m64_num)
{
char *p;
unsigned long vmembase, size, guiregbase;
@@ -2673,9 +2816,9 @@ static int atyfb_blank(int blank, struct fb_info *info)
if (par->lock_blank || par->asleep)
return 0;
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_ATY_BACKLIGHT
if (machine_is(powermac) && blank > FB_BLANK_NORMAL)
- set_backlight_enable(0);
+ aty_bl_set_power(info, FB_BLANK_POWERDOWN);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank > FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2705,9 +2848,9 @@ static int atyfb_blank(int blank, struct fb_info *info)
}
aty_st_le32(CRTC_GEN_CNTL, gen_cntl, par);
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_ATY_BACKLIGHT
if (machine_is(powermac) && blank <= FB_BLANK_NORMAL)
- set_backlight_enable(1);
+ aty_bl_set_power(info, FB_BLANK_UNBLANK);
#elif defined(CONFIG_FB_ATY_GENERIC_LCD)
if (par->lcd_table && blank <= FB_BLANK_NORMAL &&
(aty_ld_lcd(LCD_GEN_CNTL, par) & LCD_ON)) {
@@ -2966,7 +3109,7 @@ static int __devinit atyfb_setup_sparc(struct pci_dev *pdev,
}
pcp = pdev->sysdata;
- if (node == pcp->prom_node) {
+ if (node == pcp->prom_node->node) {
struct fb_var_screeninfo *var = &default_var;
unsigned int N, P, Q, M, T, R;
u32 v_total, h_total;
@@ -3440,6 +3583,7 @@ static int __devinit atyfb_pci_probe(struct pci_dev *pdev, const struct pci_devi
par->res_start = res_start;
par->res_size = res_size;
par->irq = pdev->irq;
+ par->pdev = pdev;
/* Setup "info" structure */
#ifdef __sparc__
@@ -3571,6 +3715,11 @@ static void __devexit atyfb_remove(struct fb_info *info)
aty_set_crtc(par, &saved_crtc);
par->pll_ops->set_pll(info, &saved_pll);
+#ifdef CONFIG_FB_ATY_BACKLIGHT
+ if (M64_HAS(MOBIL_BUS))
+ aty_bl_exit(par);
+#endif
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
@@ -3640,7 +3789,7 @@ static struct pci_driver atyfb_driver = {
#endif /* CONFIG_PCI */
#ifndef MODULE
-static int __init atyfb_setup(char *options)
+static int __devinit atyfb_setup(char *options)
{
char *this_opt;
@@ -3712,7 +3861,7 @@ static int __init atyfb_setup(char *options)
}
#endif /* MODULE */
-static int __init atyfb_init(void)
+static int __devinit atyfb_init(void)
{
#ifndef MODULE
char *option = NULL;
diff --git a/drivers/video/aty/mach64_accel.c b/drivers/video/aty/mach64_accel.c
index c98f4a44213..1490e5e1c23 100644
--- a/drivers/video/aty/mach64_accel.c
+++ b/drivers/video/aty/mach64_accel.c
@@ -200,8 +200,6 @@ void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
if (!area->width || !area->height)
return;
if (!par->accel_flags) {
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
cfb_copyarea(info, area);
return;
}
@@ -248,8 +246,6 @@ void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
if (!rect->width || !rect->height)
return;
if (!par->accel_flags) {
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
cfb_fillrect(info, rect);
return;
}
@@ -288,14 +284,10 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
return;
if (!par->accel_flags ||
(image->depth != 1 && info->var.bits_per_pixel != image->depth)) {
- if (par->blitter_may_be_busy)
- wait_for_idle(par);
-
cfb_imageblit(info, image);
return;
}
- wait_for_idle(par);
pix_width = pix_width_save = aty_ld_le32(DP_PIX_WIDTH, par);
host_cntl = aty_ld_le32(HOST_CNTL, par) | HOST_BYTE_ALIGN;
@@ -425,8 +417,6 @@ void atyfb_imageblit(struct fb_info *info, const struct fb_image *image)
}
}
- wait_for_idle(par);
-
/* restore pix_width */
wait_for_fifo(1, par);
aty_st_le32(DP_PIX_WIDTH, pix_width_save, par);
diff --git a/drivers/video/aty/mach64_cursor.c b/drivers/video/aty/mach64_cursor.c
index ad8b7496f85..2a7f381c330 100644
--- a/drivers/video/aty/mach64_cursor.c
+++ b/drivers/video/aty/mach64_cursor.c
@@ -66,11 +66,6 @@ static const u8 cursor_bits_lookup[16] = {
0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
};
-static const u8 cursor_mask_lookup[16] = {
- 0xaa, 0x2a, 0x8a, 0x0a, 0xa2, 0x22, 0x82, 0x02,
- 0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
-};
-
static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
struct atyfb_par *par = (struct atyfb_par *) info->par;
@@ -130,13 +125,13 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
fg_idx = cursor->image.fg_color;
bg_idx = cursor->image.bg_color;
- fg = (info->cmap.red[fg_idx] << 24) |
- (info->cmap.green[fg_idx] << 16) |
- (info->cmap.blue[fg_idx] << 8) | 15;
+ fg = ((info->cmap.red[fg_idx] & 0xff) << 24) |
+ ((info->cmap.green[fg_idx] & 0xff) << 16) |
+ ((info->cmap.blue[fg_idx] & 0xff) << 8) | 0xff;
- bg = (info->cmap.red[bg_idx] << 24) |
- (info->cmap.green[bg_idx] << 16) |
- (info->cmap.blue[bg_idx] << 8);
+ bg = ((info->cmap.red[bg_idx] & 0xff) << 24) |
+ ((info->cmap.green[bg_idx] & 0xff) << 16) |
+ ((info->cmap.blue[bg_idx] & 0xff) << 8);
wait_for_fifo(2, par);
aty_st_le32(CUR_CLR0, bg, par);
@@ -166,19 +161,17 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
switch (cursor->rop) {
case ROP_XOR:
// Upper 4 bits of mask data
- fb_writeb(cursor_mask_lookup[m >> 4 ] |
- cursor_bits_lookup[(b ^ m) >> 4], dst++);
+ fb_writeb(cursor_bits_lookup[(b ^ m) >> 4], dst++);
// Lower 4 bits of mask
- fb_writeb(cursor_mask_lookup[m & 0x0f ] |
- cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+ fb_writeb(cursor_bits_lookup[(b ^ m) & 0x0f],
+ dst++);
break;
case ROP_COPY:
// Upper 4 bits of mask data
- fb_writeb(cursor_mask_lookup[m >> 4 ] |
- cursor_bits_lookup[(b & m) >> 4], dst++);
+ fb_writeb(cursor_bits_lookup[(b & m) >> 4], dst++);
// Lower 4 bits of mask
- fb_writeb(cursor_mask_lookup[m & 0x0f ] |
- cursor_bits_lookup[(b & m) & 0x0f], dst++);
+ fb_writeb(cursor_bits_lookup[(b & m) & 0x0f],
+ dst++);
break;
}
}
@@ -194,7 +187,7 @@ static int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
return 0;
}
-int __init aty_init_cursor(struct fb_info *info)
+int __devinit aty_init_cursor(struct fb_info *info)
{
unsigned long addr;
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
new file mode 100644
index 00000000000..585eb7b9e63
--- /dev/null
+++ b/drivers/video/aty/radeon_backlight.c
@@ -0,0 +1,247 @@
+/*
+ * Backlight code for ATI Radeon based graphic cards
+ *
+ * Copyright (c) 2000 Ani Joshi <ajoshi@kernel.crashing.org>
+ * Copyright (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "radeonfb.h"
+#include <linux/backlight.h>
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#endif
+
+#define MAX_RADEON_LEVEL 0xFF
+
+static struct backlight_properties radeon_bl_data;
+
+struct radeon_bl_privdata {
+ struct radeonfb_info *rinfo;
+ uint8_t negative;
+};
+
+static int radeon_bl_get_level_brightness(struct radeon_bl_privdata *pdata,
+ int level)
+{
+ struct fb_info *info = pdata->rinfo->info;
+ int rlevel;
+
+ mutex_lock(&info->bl_mutex);
+
+ /* Get and convert the value */
+ rlevel = pdata->rinfo->info->bl_curve[level] *
+ FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL;
+
+ mutex_unlock(&info->bl_mutex);
+
+ if (rlevel < 0)
+ rlevel = 0;
+ else if (rlevel > MAX_RADEON_LEVEL)
+ rlevel = MAX_RADEON_LEVEL;
+
+ if (pdata->negative)
+ rlevel = MAX_RADEON_LEVEL - rlevel;
+
+ return rlevel;
+}
+
+static int radeon_bl_update_status(struct backlight_device *bd)
+{
+ struct radeon_bl_privdata *pdata = class_get_devdata(&bd->class_dev);
+ struct radeonfb_info *rinfo = pdata->rinfo;
+ u32 lvds_gen_cntl, tmpPixclksCntl;
+ int level;
+
+ if (rinfo->mon1_type != MT_LCD)
+ return 0;
+
+ /* We turn off the LCD completely instead of just dimming the
+ * backlight. This provides some greater power saving and the display
+ * is useless without backlight anyway.
+ */
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ del_timer_sync(&rinfo->lvds_timer);
+ radeon_engine_idle();
+
+ lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
+ if (level > 0) {
+ lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
+ if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
+ lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
+ lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |=
+ (radeon_bl_get_level_brightness(pdata, level) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_ON;
+ lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
+ rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ } else {
+ lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
+ lvds_gen_cntl |=
+ (radeon_bl_get_level_brightness(pdata, level) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ }
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
+ & LVDS_STATE_MASK;
+ } else {
+ /* Asic bug, when turning off LVDS_ON, we have to make sure
+ RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+ */
+ tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
+ lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
+ lvds_gen_cntl |= (radeon_bl_get_level_brightness(pdata, 0) <<
+ LVDS_BL_MOD_LEVEL_SHIFT);
+ lvds_gen_cntl |= LVDS_DISPLAY_DIS;
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ udelay(100);
+ lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
+ OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
+ lvds_gen_cntl &= ~(LVDS_DIGON);
+ rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
+ mod_timer(&rinfo->lvds_timer,
+ jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
+ if (rinfo->is_mobility || rinfo->is_IGP)
+ OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
+ }
+ rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
+ rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
+
+ return 0;
+}
+
+static int radeon_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties radeon_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = radeon_bl_get_brightness,
+ .update_status = radeon_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void radeonfb_bl_init(struct radeonfb_info *rinfo)
+{
+ struct backlight_device *bd;
+ struct radeon_bl_privdata *pdata;
+ char name[12];
+
+ if (rinfo->mon1_type != MT_LCD)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!pmac_has_backlight_type("ati") &&
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ pdata = kmalloc(sizeof(struct radeon_bl_privdata), GFP_KERNEL);
+ if (!pdata) {
+ printk("radeonfb: Memory allocation failed\n");
+ goto error;
+ }
+
+ snprintf(name, sizeof(name), "radeonbl%d", rinfo->info->node);
+
+ bd = backlight_device_register(name, pdata, &radeon_bl_data);
+ if (IS_ERR(bd)) {
+ rinfo->info->bl_dev = NULL;
+ printk("radeonfb: Backlight registration failed\n");
+ goto error;
+ }
+
+ pdata->rinfo = rinfo;
+
+ /* Pardon me for that hack... maybe some day we can figure out in what
+ * direction backlight should work on a given panel?
+ */
+ pdata->negative =
+ (rinfo->family != CHIP_FAMILY_RV200 &&
+ rinfo->family != CHIP_FAMILY_RV250 &&
+ rinfo->family != CHIP_FAMILY_RV280 &&
+ rinfo->family != CHIP_FAMILY_RV350);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ pdata->negative = pdata->negative ||
+ machine_is_compatible("PowerBook4,3") ||
+ machine_is_compatible("PowerBook6,3") ||
+ machine_is_compatible("PowerBook6,5");
+#endif
+
+ mutex_lock(&rinfo->info->bl_mutex);
+ rinfo->info->bl_dev = bd;
+ fb_bl_default_curve(rinfo->info, 0,
+ 63 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL,
+ 217 * FB_BACKLIGHT_MAX / MAX_RADEON_LEVEL);
+ mutex_unlock(&rinfo->info->bl_mutex);
+
+ down(&bd->sem);
+ bd->props->brightness = radeon_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ up(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("radeonfb: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ kfree(pdata);
+ return;
+}
+
+void radeonfb_bl_exit(struct radeonfb_info *rinfo)
+{
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&rinfo->info->bl_mutex);
+ if (rinfo->info->bl_dev) {
+ struct radeon_bl_privdata *pdata;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == rinfo->info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ pdata = class_get_devdata(&rinfo->info->bl_dev->class_dev);
+ backlight_device_unregister(rinfo->info->bl_dev);
+ kfree(pdata);
+ rinfo->info->bl_dev = NULL;
+
+ printk("radeonfb: Backlight unloaded\n");
+ }
+ mutex_unlock(&rinfo->info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 387a18a47ac..0ed577e7cc2 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -52,14 +52,12 @@
#define RADEON_VERSION "0.2.0"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/time.h>
@@ -78,10 +76,6 @@
#include <asm/pci-bridge.h>
#include "../macmodes.h"
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
#ifdef CONFIG_BOOTX_TEXT
#include <asm/btext.h>
#endif
@@ -272,25 +266,13 @@ static int force_measure_pll = 0;
#ifdef CONFIG_MTRR
static int nomtrr = 0;
#endif
+static int force_sleep;
+static int ignore_devlist;
/*
* prototypes
*/
-
-#ifdef CONFIG_PPC_OF
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int radeon_set_backlight_enable(int on, int level, void *data);
-static int radeon_set_backlight_level(int level, void *data);
-static struct backlight_controller radeon_backlight_controller = {
- radeon_set_backlight_enable,
- radeon_set_backlight_level
-};
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-#endif /* CONFIG_PPC_OF */
-
static void radeon_unmap_ROM(struct radeonfb_info *rinfo, struct pci_dev *dev)
{
if (!rinfo->bios_seg)
@@ -431,11 +413,11 @@ static int __devinit radeon_find_mem_vbios(struct radeonfb_info *rinfo)
static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
{
struct device_node *dp = rinfo->of_node;
- u32 *val;
+ const u32 *val;
if (dp == NULL)
return -ENODEV;
- val = (u32 *) get_property(dp, "ATY,RefCLK", NULL);
+ val = get_property(dp, "ATY,RefCLK", NULL);
if (!val || !*val) {
printk(KERN_WARNING "radeonfb: No ATY,RefCLK property !\n");
return -EINVAL;
@@ -443,11 +425,11 @@ static int __devinit radeon_read_xtal_OF (struct radeonfb_info *rinfo)
rinfo->pll.ref_clk = (*val) / 10;
- val = (u32 *) get_property(dp, "ATY,SCLK", NULL);
+ val = get_property(dp, "ATY,SCLK", NULL);
if (val && *val)
rinfo->pll.sclk = (*val) / 10;
- val = (u32 *) get_property(dp, "ATY,MCLK", NULL);
+ val = get_property(dp, "ATY,MCLK", NULL);
if (val && *val)
rinfo->pll.mclk = (*val) / 10;
@@ -1913,116 +1895,6 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
return 0;
}
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-/* TODO: Dbl check these tables, we don't go up to full ON backlight
- * in these, possibly because we noticed MacOS doesn't, but I'd prefer
- * having some more official numbers from ATI
- */
-static int backlight_conv_m6[] = {
- 0xff, 0xc0, 0xb5, 0xaa, 0x9f, 0x94, 0x89, 0x7e,
- 0x73, 0x68, 0x5d, 0x52, 0x47, 0x3c, 0x31, 0x24
-};
-static int backlight_conv_m7[] = {
- 0x00, 0x3f, 0x4a, 0x55, 0x60, 0x6b, 0x76, 0x81,
- 0x8c, 0x97, 0xa2, 0xad, 0xb8, 0xc3, 0xce, 0xd9
-};
-
-#define BACKLIGHT_LVDS_OFF
-#undef BACKLIGHT_DAC_OFF
-
-/* We turn off the LCD completely instead of just dimming the backlight.
- * This provides some greater power saving and the display is useless
- * without backlight anyway.
- */
-static int radeon_set_backlight_enable(int on, int level, void *data)
-{
- struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
- u32 lvds_gen_cntl, tmpPixclksCntl;
- int* conv_table;
-
- if (rinfo->mon1_type != MT_LCD)
- return 0;
-
- /* Pardon me for that hack... maybe some day we can figure
- * out in what direction backlight should work on a given
- * panel ?
- */
- if ((rinfo->family == CHIP_FAMILY_RV200 ||
- rinfo->family == CHIP_FAMILY_RV250 ||
- rinfo->family == CHIP_FAMILY_RV280 ||
- rinfo->family == CHIP_FAMILY_RV350) &&
- !machine_is_compatible("PowerBook4,3") &&
- !machine_is_compatible("PowerBook6,3") &&
- !machine_is_compatible("PowerBook6,5"))
- conv_table = backlight_conv_m7;
- else
- conv_table = backlight_conv_m6;
-
- del_timer_sync(&rinfo->lvds_timer);
- radeon_engine_idle();
-
- lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
- if (on && (level > BACKLIGHT_OFF)) {
- lvds_gen_cntl &= ~LVDS_DISPLAY_DIS;
- if (!(lvds_gen_cntl & LVDS_BLON) || !(lvds_gen_cntl & LVDS_ON)) {
- lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_DIGON);
- lvds_gen_cntl |= LVDS_BLON | LVDS_EN;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (conv_table[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_ON;
- lvds_gen_cntl |= (rinfo->init_state.lvds_gen_cntl & LVDS_BL_MOD_EN);
- rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
- } else {
- lvds_gen_cntl &= ~LVDS_BL_MOD_LEVEL_MASK;
- lvds_gen_cntl |= (conv_table[level] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- }
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= rinfo->pending_lvds_gen_cntl
- & LVDS_STATE_MASK;
- } else {
- /* Asic bug, when turning off LVDS_ON, we have to make sure
- RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
- */
- tmpPixclksCntl = INPLL(PIXCLKS_CNTL);
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLLP(PIXCLKS_CNTL, 0, ~PIXCLK_LVDS_ALWAYS_ONb);
- lvds_gen_cntl &= ~(LVDS_BL_MOD_LEVEL_MASK | LVDS_BL_MOD_EN);
- lvds_gen_cntl |= (conv_table[0] <<
- LVDS_BL_MOD_LEVEL_SHIFT);
- lvds_gen_cntl |= LVDS_DISPLAY_DIS;
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- udelay(100);
- lvds_gen_cntl &= ~(LVDS_ON | LVDS_EN);
- OUTREG(LVDS_GEN_CNTL, lvds_gen_cntl);
- lvds_gen_cntl &= ~(LVDS_DIGON);
- rinfo->pending_lvds_gen_cntl = lvds_gen_cntl;
- mod_timer(&rinfo->lvds_timer,
- jiffies + msecs_to_jiffies(rinfo->panel_info.pwr_delay));
- if (rinfo->is_mobility || rinfo->is_IGP)
- OUTPLL(PIXCLKS_CNTL, tmpPixclksCntl);
- }
- rinfo->init_state.lvds_gen_cntl &= ~LVDS_STATE_MASK;
- rinfo->init_state.lvds_gen_cntl |= (lvds_gen_cntl & LVDS_STATE_MASK);
-
- return 0;
-}
-
-
-static int radeon_set_backlight_level(int level, void *data)
-{
- return radeon_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-
/*
* This reconfigure the card's internal memory map. In theory, we'd like
* to setup the card's memory at the same address as it's PCI bus address,
@@ -2457,9 +2329,9 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
/* -2 is special: means ON on mobility chips and do not
* change on others
*/
- radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1);
+ radeonfb_pm_init(rinfo, rinfo->is_mobility ? 1 : -1, ignore_devlist, force_sleep);
} else
- radeonfb_pm_init(rinfo, default_dynclk);
+ radeonfb_pm_init(rinfo, default_dynclk, ignore_devlist, force_sleep);
pci_set_drvdata(pdev, info);
@@ -2477,14 +2349,7 @@ static int __devinit radeonfb_pci_register (struct pci_dev *pdev,
MTRR_TYPE_WRCOMB, 1);
#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (rinfo->mon1_type == MT_LCD) {
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "ati");
- register_backlight_controller(&radeon_backlight_controller,
- rinfo, "mnca");
- }
-#endif
+ radeonfb_bl_init(rinfo);
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
@@ -2514,7 +2379,6 @@ err_release_pci0:
err_release_fb:
framebuffer_release(info);
err_disable:
- pci_disable_device(pdev);
err_out:
return ret;
}
@@ -2528,7 +2392,8 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
if (!rinfo)
return;
-
+
+ radeonfb_bl_exit(rinfo);
radeonfb_pm_exit(rinfo);
if (rinfo->mon1_EDID)
@@ -2570,7 +2435,6 @@ static void __devexit radeonfb_pci_unregister (struct pci_dev *pdev)
#endif
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
- pci_disable_device(pdev);
}
@@ -2615,6 +2479,12 @@ static int __init radeonfb_setup (char *options)
force_measure_pll = 1;
} else if (!strncmp(this_opt, "ignore_edid", 11)) {
ignore_edid = 1;
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+ } else if (!strncmp(this_opt, "force_sleep", 11)) {
+ force_sleep = 1;
+ } else if (!strncmp(this_opt, "ignore_devlist", 14)) {
+ ignore_devlist = 1;
+#endif
} else
mode_option = this_opt;
}
@@ -2670,3 +2540,9 @@ module_param(panel_yres, int, 0);
MODULE_PARM_DESC(panel_yres, "int: set panel yres");
module_param(mode_option, charp, 0);
MODULE_PARM_DESC(mode_option, "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+module_param(force_sleep, bool, 0);
+MODULE_PARM_DESC(force_sleep, "bool: force D2 sleep mode on all hardware");
+module_param(ignore_devlist, bool, 0);
+MODULE_PARM_DESC(ignore_devlist, "bool: ignore workarounds for bugs in specific laptops");
+#endif
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index a9d0414e465..9aaca58c074 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/video/aty/radeon_monitor.c b/drivers/video/aty/radeon_monitor.c
index 98c05bc0de4..ea531a6f45d 100644
--- a/drivers/video/aty/radeon_monitor.c
+++ b/drivers/video/aty/radeon_monitor.c
@@ -64,13 +64,13 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
{
static char *propnames[] = { "DFP,EDID", "LCD,EDID", "EDID",
"EDID1", "EDID2", NULL };
- u8 *pedid = NULL;
- u8 *pmt = NULL;
+ const u8 *pedid = NULL;
+ const u8 *pmt = NULL;
u8 *tmp;
int i, mt = MT_NONE;
RTRACE("analyzing OF properties...\n");
- pmt = (u8 *)get_property(dp, "display-type", NULL);
+ pmt = get_property(dp, "display-type", NULL);
if (!pmt)
return MT_NONE;
RTRACE("display-type: %s\n", pmt);
@@ -89,7 +89,7 @@ static int __devinit radeon_parse_montype_prop(struct device_node *dp, u8 **out_
}
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = (u8 *)get_property(dp, propnames[i], NULL);
+ pedid = get_property(dp, propnames[i], NULL);
if (pedid != NULL)
break;
}
@@ -124,14 +124,14 @@ static int __devinit radeon_probe_OF_head(struct radeonfb_info *rinfo, int head_
return MT_NONE;
if (rinfo->has_CRTC2) {
- char *pname;
+ const char *pname;
int len, second = 0;
dp = dp->child;
do {
if (!dp)
return MT_NONE;
- pname = (char *)get_property(dp, "name", NULL);
+ pname = get_property(dp, "name", NULL);
if (!pname)
return MT_NONE;
len = strlen(pname);
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index c7091761cef..365de5dcc88 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -27,6 +27,99 @@
#include "ati_ids.h"
+static void radeon_reinitialize_M10(struct radeonfb_info *rinfo);
+
+/*
+ * Workarounds for bugs in PC laptops:
+ * - enable D2 sleep in some IBM Thinkpads
+ * - special case for Samsung P35
+ *
+ * Whitelist by subsystem vendor/device because
+ * its the subsystem vendor's fault!
+ */
+
+#if defined(CONFIG_PM) && defined(CONFIG_X86)
+struct radeon_device_id {
+ const char *ident; /* (arbitrary) Name */
+ const unsigned short subsystem_vendor; /* Subsystem Vendor ID */
+ const unsigned short subsystem_device; /* Subsystem Device ID */
+ const enum radeon_pm_mode pm_mode_modifier; /* modify pm_mode */
+ const reinit_function_ptr new_reinit_func; /* changed reinit_func */
+};
+
+#define BUGFIX(model, sv, sd, pm, fn) { \
+ .ident = model, \
+ .subsystem_vendor = sv, \
+ .subsystem_device = sd, \
+ .pm_mode_modifier = pm, \
+ .new_reinit_func = fn \
+}
+
+static struct radeon_device_id radeon_workaround_list[] = {
+ BUGFIX("IBM Thinkpad R32",
+ PCI_VENDOR_ID_IBM, 0x1905,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R40",
+ PCI_VENDOR_ID_IBM, 0x0526,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R40",
+ PCI_VENDOR_ID_IBM, 0x0527,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R50/R51/T40/T41",
+ PCI_VENDOR_ID_IBM, 0x0531,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad R51/T40/T41/T42",
+ PCI_VENDOR_ID_IBM, 0x0530,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T30",
+ PCI_VENDOR_ID_IBM, 0x0517,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T40p",
+ PCI_VENDOR_ID_IBM, 0x054d,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad T42",
+ PCI_VENDOR_ID_IBM, 0x0550,
+ radeon_pm_d2, NULL),
+ BUGFIX("IBM Thinkpad X31/X32",
+ PCI_VENDOR_ID_IBM, 0x052f,
+ radeon_pm_d2, NULL),
+ BUGFIX("Samsung P35",
+ PCI_VENDOR_ID_SAMSUNG, 0xc00c,
+ radeon_pm_off, radeon_reinitialize_M10),
+ { .ident = NULL }
+};
+
+static int radeon_apply_workarounds(struct radeonfb_info *rinfo)
+{
+ struct radeon_device_id *id;
+
+ for (id = radeon_workaround_list; id->ident != NULL; id++ )
+ if ((id->subsystem_vendor == rinfo->pdev->subsystem_vendor ) &&
+ (id->subsystem_device == rinfo->pdev->subsystem_device )) {
+
+ /* we found a device that requires workaround */
+ printk(KERN_DEBUG "radeonfb: %s detected"
+ ", enabling workaround\n", id->ident);
+
+ rinfo->pm_mode |= id->pm_mode_modifier;
+
+ if (id->new_reinit_func != NULL)
+ rinfo->reinit_func = id->new_reinit_func;
+
+ return 1;
+ }
+ return 0; /* not found */
+}
+
+#else /* defined(CONFIG_PM) && defined(CONFIG_X86) */
+static inline int radeon_apply_workarounds(struct radeonfb_info *rinfo)
+{
+ return 0;
+}
+#endif /* defined(CONFIG_PM) && defined(CONFIG_X86) */
+
+
+
static void radeon_pm_disable_dynamic_mode(struct radeonfb_info *rinfo)
{
u32 tmp;
@@ -852,18 +945,26 @@ static void radeon_pm_setup_for_suspend(struct radeonfb_info *rinfo)
/* because both INPLL and OUTPLL take the same lock, that's why. */
tmp = INPLL( pllMCLK_MISC) | MCLK_MISC__EN_MCLK_TRISTATE_IN_SUSPEND;
OUTPLL( pllMCLK_MISC, tmp);
-
- /* AGP PLL control */
- if (rinfo->family <= CHIP_FAMILY_RV280) {
- OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
- OUTREG(BUS_CNTL1,
- (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
- | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
- } else {
- OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
- OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+ /* BUS_CNTL1__MOBILE_PLATORM_SEL setting is northbridge chipset
+ * and radeon chip dependent. Thus we only enable it on Mac for
+ * now (until we get more info on how to compute the correct
+ * value for various X86 bridges).
+ */
+#ifdef CONFIG_PPC_PMAC
+ if (machine_is(powermac)) {
+ /* AGP PLL control */
+ if (rinfo->family <= CHIP_FAMILY_RV280) {
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1) | BUS_CNTL1__AGPCLK_VALID);
+ OUTREG(BUS_CNTL1,
+ (INREG(BUS_CNTL1) & ~BUS_CNTL1__MOBILE_PLATFORM_SEL_MASK)
+ | (2<<BUS_CNTL1__MOBILE_PLATFORM_SEL__SHIFT)); // 440BX
+ } else {
+ OUTREG(BUS_CNTL1, INREG(BUS_CNTL1));
+ OUTREG(BUS_CNTL1, (INREG(BUS_CNTL1) & ~0x4000) | 0x8000);
+ }
}
+#endif
OUTREG(CRTC_OFFSET_CNTL, (INREG(CRTC_OFFSET_CNTL)
& ~CRTC_OFFSET_CNTL__CRTC_STEREO_SYNC_OUT_EN));
@@ -1167,7 +1268,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
0x21320032, 0xa1320032, 0x21320032, 0xffffffff,
0x31320032 };
- u32 *mrtable = default_mrtable;
+ const u32 *mrtable = default_mrtable;
int i, mrtable_size = ARRAY_SIZE(default_mrtable);
mdelay(30);
@@ -1186,7 +1287,7 @@ static void radeon_pm_full_reset_sdram(struct radeonfb_info *rinfo)
if (rinfo->of_node != NULL) {
int size;
- mrtable = (u32 *)get_property(rinfo->of_node, "ATY,MRT", &size);
+ mrtable = get_property(rinfo->of_node, "ATY,MRT", &size);
if (mrtable)
mrtable_size = size >> 2;
else
@@ -2520,25 +2621,28 @@ static int radeon_restore_pci_cfg(struct radeonfb_info *rinfo)
}
-int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
{
struct fb_info *info = pci_get_drvdata(pdev);
struct radeonfb_info *rinfo = info->par;
int i;
- if (state.event == pdev->dev.power.power_state.event)
+ if (mesg.event == pdev->dev.power.power_state.event)
return 0;
- printk(KERN_DEBUG "radeonfb (%s): suspending to state: %d...\n",
- pci_name(pdev), state.event);
+ printk(KERN_DEBUG "radeonfb (%s): suspending for event: %d...\n",
+ pci_name(pdev), mesg.event);
/* For suspend-to-disk, we cheat here. We don't suspend anything and
* let fbcon continue drawing until we are all set. That shouldn't
* really cause any problem at this point, provided that the wakeup
* code knows that any state in memory may not match the HW
*/
- if (state.event == PM_EVENT_FREEZE)
+ switch (mesg.event) {
+ case PM_EVENT_FREEZE: /* about to take snapshot */
+ case PM_EVENT_PRETHAW: /* before restoring snapshot */
goto done;
+ }
acquire_console_sem();
@@ -2605,7 +2709,7 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
release_console_sem();
done:
- pdev->dev.power.power_state = state;
+ pdev->dev.power.power_state = mesg;
return 0;
}
@@ -2713,7 +2817,7 @@ static void radeonfb_early_resume(void *data)
#endif /* CONFIG_PM */
-void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
+void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep)
{
/* Find PM registers in config space if any*/
rinfo->pm_reg = pci_find_capability(rinfo->pdev, PCI_CAP_ID_PM);
@@ -2729,22 +2833,13 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
}
#if defined(CONFIG_PM)
+#if defined(CONFIG_PPC_PMAC)
/* Check if we can power manage on suspend/resume. We can do
* D2 on M6, M7 and M9, and we can resume from D3 cold a few other
* "Mac" cards, but that's all. We need more infos about what the
* BIOS does tho. Right now, all this PM stuff is pmac-only for that
* reason. --BenH
*/
- /* Special case for Samsung P35 laptops
- */
- if ((rinfo->pdev->vendor == PCI_VENDOR_ID_ATI) &&
- (rinfo->pdev->device == PCI_CHIP_RV350_NP) &&
- (rinfo->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG) &&
- (rinfo->pdev->subsystem_device == 0xc00c)) {
- rinfo->reinit_func = radeon_reinitialize_M10;
- rinfo->pm_mode |= radeon_pm_off;
- }
-#if defined(CONFIG_PPC_PMAC)
if (machine_is(powermac) && rinfo->of_node) {
if (rinfo->is_mobility && rinfo->pm_reg &&
rinfo->family <= CHIP_FAMILY_RV250)
@@ -2790,6 +2885,18 @@ void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk)
}
#endif /* defined(CONFIG_PPC_PMAC) */
#endif /* defined(CONFIG_PM) */
+
+ if (ignore_devlist)
+ printk(KERN_DEBUG
+ "radeonfb: skipping test for device workarounds\n");
+ else
+ radeon_apply_workarounds(rinfo);
+
+ if (force_sleep) {
+ printk(KERN_DEBUG
+ "radeonfb: forcefully enabling D2 sleep mode\n");
+ rinfo->pm_mode |= radeon_pm_d2;
+ }
}
void radeonfb_pm_exit(struct radeonfb_info *rinfo)
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index 217e00ab4a2..d5ff224a625 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -1,7 +1,6 @@
#ifndef __RADEONFB_H__
#define __RADEONFB_H__
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -274,6 +273,8 @@ enum radeon_pm_mode {
radeon_pm_off = 0x00000002, /* Can resume from D3 cold */
};
+typedef void (*reinit_function_ptr)(struct radeonfb_info *rinfo);
+
struct radeonfb_info {
struct fb_info *info;
@@ -339,7 +340,7 @@ struct radeonfb_info {
int dynclk;
int no_schedule;
enum radeon_pm_mode pm_mode;
- void (*reinit_func)(struct radeonfb_info *rinfo);
+ reinit_function_ptr reinit_func;
/* Lock on register access */
spinlock_t reg_lock;
@@ -382,7 +383,7 @@ struct radeonfb_info {
/* Note about this function: we have some rare cases where we must not schedule,
* this typically happen with our special "wake up early" hook which allows us to
* wake up the graphic chip (and thus get the console back) before everything else
- * on some machines that support that mecanism. At this point, interrupts are off
+ * on some machines that support that mechanism. At this point, interrupts are off
* and scheduling is not permitted
*/
static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
@@ -601,7 +602,7 @@ extern int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8
/* PM Functions */
extern int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t state);
extern int radeonfb_pci_resume(struct pci_dev *pdev);
-extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk);
+extern void radeonfb_pm_init(struct radeonfb_info *rinfo, int dynclk, int ignore_devlist, int force_sleep);
extern void radeonfb_pm_exit(struct radeonfb_info *rinfo);
/* Monitor probe functions */
@@ -625,4 +626,13 @@ extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_
extern void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
int reg_only);
+/* Backlight functions */
+#ifdef CONFIG_FB_RADEON_BACKLIGHT
+extern void radeonfb_bl_init(struct radeonfb_info *rinfo);
+extern void radeonfb_bl_exit(struct radeonfb_info *rinfo);
+#else
+static inline void radeonfb_bl_init(struct radeonfb_info *rinfo) {}
+static inline void radeonfb_bl_exit(struct radeonfb_info *rinfo) {}
+#endif
+
#endif /* __RADEONFB_H__ */
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index 789450bb0bc..f25d5d64833 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -7,6 +7,8 @@
* Karl Lessard <klessard@sunrisetelecom.com>
* <c.pellegrin@exadron.com>
*
+ * PM support added by Rodolfo Giometti <giometti@linux.it>
+ *
* Copyright 2002 MontaVista Software
* Author: MontaVista Software, Inc.
* ppopov@mvista.com or source@mvista.com
@@ -38,7 +40,6 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@@ -155,7 +156,7 @@ int au1100fb_setmode(struct au1100fb_device *fbdev)
info->fix.visual = FB_VISUAL_TRUECOLOR;
info->fix.line_length = info->var.xres_virtual << 1; /* depth=16 */
- }
+ }
} else {
/* mono */
info->fix.visual = FB_VISUAL_MONO10;
@@ -163,20 +164,16 @@ int au1100fb_setmode(struct au1100fb_device *fbdev)
}
info->screen_size = info->fix.line_length * info->var.yres_virtual;
+ info->var.rotate = ((fbdev->panel->control_base&LCD_CONTROL_SM_MASK) \
+ >> LCD_CONTROL_SM_BIT) * 90;
/* Determine BPP mode and format */
- fbdev->regs->lcd_control = fbdev->panel->control_base |
- ((info->var.rotate/90) << LCD_CONTROL_SM_BIT);
-
- fbdev->regs->lcd_intenable = 0;
- fbdev->regs->lcd_intstatus = 0;
-
+ fbdev->regs->lcd_control = fbdev->panel->control_base;
fbdev->regs->lcd_horztiming = fbdev->panel->horztiming;
-
fbdev->regs->lcd_verttiming = fbdev->panel->verttiming;
-
fbdev->regs->lcd_clkcontrol = fbdev->panel->clkcontrol_base;
-
+ fbdev->regs->lcd_intenable = 0;
+ fbdev->regs->lcd_intstatus = 0;
fbdev->regs->lcd_dmaaddr0 = LCD_DMA_SA_N(fbdev->fb_phys);
if (panel_is_dual(fbdev->panel)) {
@@ -205,6 +202,8 @@ int au1100fb_setmode(struct au1100fb_device *fbdev)
/* Resume controller */
fbdev->regs->lcd_control |= LCD_CONTROL_GO;
+ mdelay(10);
+ au1100fb_fb_blank(VESA_NO_BLANKING, info);
return 0;
}
@@ -602,17 +601,52 @@ int au1100fb_drv_remove(struct device *dev)
return 0;
}
+#ifdef CONFIG_PM
+static u32 sys_clksrc;
+static struct au1100fb_regs fbregs;
+
int au1100fb_drv_suspend(struct device *dev, pm_message_t state)
{
- /* TODO */
+ struct au1100fb_device *fbdev = dev_get_drvdata(dev);
+
+ if (!fbdev)
+ return 0;
+
+ /* Save the clock source state */
+ sys_clksrc = au_readl(SYS_CLKSRC);
+
+ /* Blank the LCD */
+ au1100fb_fb_blank(VESA_POWERDOWN, &fbdev->info);
+
+ /* Stop LCD clocking */
+ au_writel(sys_clksrc & ~SYS_CS_ML_MASK, SYS_CLKSRC);
+
+ memcpy(&fbregs, fbdev->regs, sizeof(struct au1100fb_regs));
+
return 0;
}
int au1100fb_drv_resume(struct device *dev)
{
- /* TODO */
+ struct au1100fb_device *fbdev = dev_get_drvdata(dev);
+
+ if (!fbdev)
+ return 0;
+
+ memcpy(fbdev->regs, &fbregs, sizeof(struct au1100fb_regs));
+
+ /* Restart LCD clocking */
+ au_writel(sys_clksrc, SYS_CLKSRC);
+
+ /* Unblank the LCD */
+ au1100fb_fb_blank(VESA_NO_BLANKING, &fbdev->info);
+
return 0;
}
+#else
+#define au1100fb_drv_suspend NULL
+#define au1100fb_drv_resume NULL
+#endif
static struct device_driver au1100fb_driver = {
.name = "au1100-lcd",
@@ -706,8 +740,7 @@ void __exit au1100fb_cleanup(void)
{
driver_unregister(&au1100fb_driver);
- if (drv_info.opt_mode)
- kfree(drv_info.opt_mode);
+ kfree(drv_info.opt_mode);
}
module_init(au1100fb_init);
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index 600d3e0e08b..c6a5f0ccc10 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1694,7 +1694,7 @@ static int au1200fb_drv_probe(struct device *dev)
/* Now hook interrupt too */
if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq,
- SA_INTERRUPT | SA_SHIRQ, "lcd", (void *)dev)) < 0) {
+ IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) {
print_err("fail to request interrupt line %d (err: %d)",
AU1200_LCD_INT, ret);
goto failed;
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index b895eaaa73f..02f15297a02 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -50,6 +50,14 @@ config BACKLIGHT_CORGI
If you have a Sharp Zaurus SL-C7xx, SL-Cxx00 or SL-6000x say y to enable the
backlight driver.
+config BACKLIGHT_LOCOMO
+ tristate "Sharp LOCOMO LCD/Backlight Driver"
+ depends on BACKLIGHT_DEVICE && SHARP_LOCOMO
+ default y
+ help
+ If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to
+ enable the LCD/backlight driver.
+
config BACKLIGHT_HP680
tristate "HP Jornada 680 Backlight Driver"
depends on BACKLIGHT_DEVICE && SH_HP6XX
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 744210c38e7..65e5553fc84 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -4,4 +4,4 @@ obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o
obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
-obj-$(CONFIG_SHARP_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index a71e984c93d..fe1488374f6 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -20,14 +20,14 @@
#include <asm/cpu/dac.h>
#include <asm/hp6xx/hp6xx.h>
-#include <asm/hd64461/hd64461.h>
+#include <asm/hd64461.h>
#define HP680_MAX_INTENSITY 255
#define HP680_DEFAULT_INTENSITY 10
static int hp680bl_suspended;
static int current_intensity = 0;
-static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(bl_lock);
static struct backlight_device *hp680_backlight_device;
static void hp680bl_send_intensity(struct backlight_device *bd)
@@ -163,6 +163,6 @@ static void __exit hp680bl_exit(void)
module_init(hp680bl_init);
module_exit(hp680bl_exit);
-MODULE_AUTHOR("Andriy Skulysh <askulysh@image.kiev.ua>");
+MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 60831bb2368..628571c63ba 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -11,12 +11,13 @@
*/
/* LCD power functions */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/backlight.h>
#include <asm/hardware/locomo.h>
#include <asm/irq.h>
@@ -25,23 +26,26 @@
#include "../../../arch/arm/mach-sa1100/generic.h"
+static struct backlight_device *locomolcd_bl_device;
static struct locomo_dev *locomolcd_dev;
+static unsigned long locomolcd_flags;
+#define LOCOMOLCD_SUSPENDED 0x01
static void locomolcd_on(int comadj)
{
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1);
mdelay(2);
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1);
mdelay(2);
locomo_m62332_senddata(locomolcd_dev, comadj, 0);
mdelay(5);
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1);
mdelay(10);
/* TFTCRST | CPSOUT=0 | CPSEN */
@@ -54,8 +58,8 @@ static void locomolcd_on(int comadj)
locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
mdelay(10);
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1);
}
static void locomolcd_off(int comadj)
@@ -64,16 +68,16 @@ static void locomolcd_off(int comadj)
locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
mdelay(1);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
mdelay(110);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
mdelay(700);
/* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
}
void locomolcd_power(int on)
@@ -89,12 +93,10 @@ void locomolcd_power(int on)
}
/* read comadj */
- if (comadj == -1) {
- if (machine_is_poodle())
- comadj = 118;
- if (machine_is_collie())
- comadj = 128;
- }
+ if (comadj == -1 && machine_is_collie())
+ comadj = 128;
+ if (comadj == -1 && machine_is_poodle())
+ comadj = 118;
if (on)
locomolcd_on(comadj);
@@ -105,26 +107,100 @@ void locomolcd_power(int on)
}
EXPORT_SYMBOL(locomolcd_power);
-static int poodle_lcd_probe(struct locomo_dev *dev)
+
+static int current_intensity;
+
+static int locomolcd_set_intensity(struct backlight_device *bd)
+{
+ int intensity = bd->props->brightness;
+
+ if (bd->props->power != FB_BLANK_UNBLANK)
+ intensity = 0;
+ if (bd->props->fb_blank != FB_BLANK_UNBLANK)
+ intensity = 0;
+ if (locomolcd_flags & LOCOMOLCD_SUSPENDED)
+ intensity = 0;
+
+ switch (intensity) {
+ /* AC and non-AC are handled differently, but produce same results in sharp code? */
+ case 0: locomo_frontlight_set(locomolcd_dev, 0, 0, 161); break;
+ case 1: locomo_frontlight_set(locomolcd_dev, 117, 0, 161); break;
+ case 2: locomo_frontlight_set(locomolcd_dev, 163, 0, 148); break;
+ case 3: locomo_frontlight_set(locomolcd_dev, 194, 0, 161); break;
+ case 4: locomo_frontlight_set(locomolcd_dev, 194, 1, 161); break;
+
+ default:
+ return -ENODEV;
+ }
+ current_intensity = intensity;
+ return 0;
+}
+
+static int locomolcd_get_intensity(struct backlight_device *bd)
+{
+ return current_intensity;
+}
+
+static struct backlight_properties locomobl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = locomolcd_get_intensity,
+ .update_status = locomolcd_set_intensity,
+ .max_brightness = 4,
+};
+
+#ifdef CONFIG_PM
+static int locomolcd_suspend(struct locomo_dev *dev, pm_message_t state)
+{
+ locomolcd_flags |= LOCOMOLCD_SUSPENDED;
+ locomolcd_set_intensity(locomolcd_bl_device);
+ return 0;
+}
+
+static int locomolcd_resume(struct locomo_dev *dev)
+{
+ locomolcd_flags &= ~LOCOMOLCD_SUSPENDED;
+ locomolcd_set_intensity(locomolcd_bl_device);
+ return 0;
+}
+#else
+#define locomolcd_suspend NULL
+#define locomolcd_resume NULL
+#endif
+
+static int locomolcd_probe(struct locomo_dev *ldev)
{
unsigned long flags;
local_irq_save(flags);
- locomolcd_dev = dev;
+ locomolcd_dev = ldev;
+
+ locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
/* the poodle_lcd_power function is called for the first time
* from fs_initcall, which is before locomo is activated.
* We need to recall poodle_lcd_power here*/
-#ifdef CONFIG_MACH_POODLE
- locomolcd_power(1);
-#endif
+ if (machine_is_poodle())
+ locomolcd_power(1);
+
local_irq_restore(flags);
+
+ locomolcd_bl_device = backlight_device_register("locomo-bl", NULL, &locomobl_data);
+
+ if (IS_ERR (locomolcd_bl_device))
+ return PTR_ERR (locomolcd_bl_device);
+
+ /* Set up frontlight so that screen is readable */
+ locomobl_data.brightness = 2;
+ locomolcd_set_intensity(locomolcd_bl_device);
+
return 0;
}
-static int poodle_lcd_remove(struct locomo_dev *dev)
+static int locomolcd_remove(struct locomo_dev *dev)
{
unsigned long flags;
+
+ backlight_device_unregister(locomolcd_bl_device);
local_irq_save(flags);
locomolcd_dev = NULL;
local_irq_restore(flags);
@@ -136,19 +212,33 @@ static struct locomo_driver poodle_lcd_driver = {
.name = "locomo-backlight",
},
.devid = LOCOMO_DEVID_BACKLIGHT,
- .probe = poodle_lcd_probe,
- .remove = poodle_lcd_remove,
+ .probe = locomolcd_probe,
+ .remove = locomolcd_remove,
+ .suspend = locomolcd_suspend,
+ .resume = locomolcd_resume,
};
-static int __init poodle_lcd_init(void)
+
+static int __init locomolcd_init(void)
{
int ret = locomo_driver_register(&poodle_lcd_driver);
- if (ret) return ret;
+ if (ret)
+ return ret;
#ifdef CONFIG_SA1100_COLLIE
sa1100fb_lcd_power = locomolcd_power;
#endif
return 0;
}
-device_initcall(poodle_lcd_init);
+static void __exit locomolcd_exit(void)
+{
+ locomo_driver_unregister(&poodle_lcd_driver);
+}
+
+module_init(locomolcd_init);
+module_exit(locomolcd_exit);
+
+MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@suse.cz>");
+MODULE_DESCRIPTION("Collie LCD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 6577fdfdfc1..c66e3d52cbf 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -1,6 +1,6 @@
/* bw2.c: BWTWO frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -19,14 +19,11 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
-#ifdef CONFIG_SPARC32
-#include <asm/sun4paddr.h>
-#endif
-
#include "sbuslib.h"
/*
@@ -59,30 +56,30 @@ static struct fb_ops bw2_ops = {
#define BWTWO_REGISTER_OFFSET 0x400000
struct bt_regs {
- volatile u32 addr;
- volatile u32 color_map;
- volatile u32 control;
- volatile u32 cursor;
+ u32 addr;
+ u32 color_map;
+ u32 control;
+ u32 cursor;
};
struct bw2_regs {
struct bt_regs cmap;
- volatile u8 control;
- volatile u8 status;
- volatile u8 cursor_start;
- volatile u8 cursor_end;
- volatile u8 h_blank_start;
- volatile u8 h_blank_end;
- volatile u8 h_sync_start;
- volatile u8 h_sync_end;
- volatile u8 comp_sync_end;
- volatile u8 v_blank_start_high;
- volatile u8 v_blank_start_low;
- volatile u8 v_blank_end;
- volatile u8 v_sync_start;
- volatile u8 v_sync_end;
- volatile u8 xfer_holdoff_start;
- volatile u8 xfer_holdoff_end;
+ u8 control;
+ u8 status;
+ u8 cursor_start;
+ u8 cursor_end;
+ u8 h_blank_start;
+ u8 h_blank_end;
+ u8 h_sync_start;
+ u8 h_sync_end;
+ u8 comp_sync_end;
+ u8 v_blank_start_high;
+ u8 v_blank_start_low;
+ u8 v_blank_end;
+ u8 v_sync_start;
+ u8 v_sync_end;
+ u8 xfer_holdoff_start;
+ u8 xfer_holdoff_end;
};
/* Status Register Constants */
@@ -117,9 +114,8 @@ struct bw2_par {
#define BW2_FLAG_BLANKED 0x00000001
unsigned long physbase;
+ unsigned long which_io;
unsigned long fbsize;
-
- struct sbus_dev *sdev;
};
/**
@@ -174,9 +170,7 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
return sbusfb_mmap_helper(bw2_mmap_map,
par->physbase, par->fbsize,
- (par->sdev ?
- par->sdev->reg_addrs[0].which_io :
- 0),
+ par->which_io,
vma);
}
@@ -288,139 +282,124 @@ static void bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
struct all_info {
struct fb_info info;
struct bw2_par par;
- struct list_head list;
};
-static LIST_HEAD(bw2_list);
-static void bw2_init_one(struct sbus_dev *sdev)
+static int __devinit bw2_init_one(struct of_device *op)
{
+ struct device_node *dp = op->node;
struct all_info *all;
- struct resource *resp;
-#ifdef CONFIG_SUN4
- struct resource res;
-#endif
- int linebytes;
+ int linebytes, err;
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "bw2: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
-
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- all->par.sdev = sdev;
-
-#ifdef CONFIG_SUN4
- if (!sdev) {
- all->par.physbase = sun4_bwtwo_physaddr;
- res.start = sun4_bwtwo_physaddr;
- res.end = res.start + BWTWO_REGISTER_OFFSET + sizeof(struct bw2_regs) - 1;
- res.flags = IORESOURCE_IO;
- resp = &res;
- all->info.var.xres = all->info.var.xres_virtual = 1152;
- all->info.var.yres = all->info.var.yres_virtual = 900;
- all->info.var.bits_per_pixel = 1;
- linebytes = 1152 / 8;
- } else
-#else
- {
- BUG_ON(!sdev);
- all->par.physbase = sdev->reg_addrs[0].phys_addr;
- resp = &sdev->resource[0];
- sbusfb_fill_var(&all->info.var, (sdev ? sdev->prom_node : 0), 1);
- linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
- all->info.var.xres);
- }
-#endif
+
+ all->par.physbase = op->resource[0].start;
+ all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+
+ sbusfb_fill_var(&all->info.var, dp->node, 1);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
+
all->info.var.red.length = all->info.var.green.length =
all->info.var.blue.length = all->info.var.bits_per_pixel;
all->info.var.red.offset = all->info.var.green.offset =
all->info.var.blue.offset = 0;
- all->par.regs = sbus_ioremap(resp, BWTWO_REGISTER_OFFSET,
- sizeof(struct bw2_regs), "bw2 regs");
+ all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
+ sizeof(struct bw2_regs), "bw2 regs");
- if (sdev && !prom_getbool(sdev->prom_node, "width"))
+ if (!of_find_property(dp, "width", NULL))
bw2_do_default_mode(&all->par, &all->info, &linebytes);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
all->info.flags = FBINFO_DEFAULT;
all->info.fbops = &bw2_ops;
-#if defined(CONFIG_SPARC32)
- if (sdev)
- all->info.screen_base = (char __iomem *)
- prom_getintdefault(sdev->prom_node, "address", 0);
-#endif
- if (!all->info.screen_base)
- all->info.screen_base =
- sbus_ioremap(resp, 0, all->par.fbsize, "bw2 ram");
+
+ all->info.screen_base =
+ sbus_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram");
all->info.par = &all->par;
bw2_blank(0, &all->info);
bw2_init_fix(&all->info, linebytes);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "bw2: Could not register framebuffer.\n");
+ err= register_framebuffer(&all->info);
+ if (err < 0) {
+ of_iounmap(all->par.regs, sizeof(struct bw2_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &bw2_list);
+ dev_set_drvdata(&op->dev, all);
+
+ printk("%s: bwtwo at %lx:%lx\n",
+ dp->full_name,
+ all->par.which_io, all->par.physbase);
- printk("bw2: bwtwo at %lx:%lx\n",
- (long) (sdev ? sdev->reg_addrs[0].which_io : 0),
- (long) all->par.physbase);
+ return 0;
}
-int __init bw2_init(void)
+static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("bw2fb", NULL))
- return -ENODEV;
+ return bw2_init_one(op);
+}
-#ifdef CONFIG_SUN4
- bw2_init_one(NULL);
-#endif
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "bwtwo"))
- bw2_init_one(sdev);
- }
+static int __devexit bw2_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+
+ of_iounmap(all->par.regs, sizeof(struct bw2_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit bw2_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id bw2_match[] = {
+ {
+ .name = "bwtwo",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bw2_match);
- list_for_each_safe(pos, tmp, &bw2_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver bw2_driver = {
+ .name = "bw2",
+ .match_table = bw2_match,
+ .probe = bw2_probe,
+ .remove = __devexit_p(bw2_remove),
+};
- unregister_framebuffer(&all->info);
- kfree(all);
- }
+static int __init bw2_init(void)
+{
+ if (fb_get_options("bw2fb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&bw2_driver, &of_bus_type);
}
-int __init
-bw2_setup(char *arg)
+static void __exit bw2_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ return of_unregister_driver(&bw2_driver);
}
-module_init(bw2_init);
-#ifdef MODULE
+module_init(bw2_init);
module_exit(bw2_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/cfbcopyarea.c b/drivers/video/cfbcopyarea.c
index 74415325b01..6faea4034e3 100644
--- a/drivers/video/cfbcopyarea.c
+++ b/drivers/video/cfbcopyarea.c
@@ -24,7 +24,6 @@
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
diff --git a/drivers/video/cfbfillrect.c b/drivers/video/cfbfillrect.c
index e5ff62e9cfb..f00b50aab60 100644
--- a/drivers/video/cfbfillrect.c
+++ b/drivers/video/cfbfillrect.c
@@ -17,7 +17,6 @@
* the native cpu endians. I also need to deal with MSB position in the word.
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/cfbimgblt.c b/drivers/video/cfbimgblt.c
index 8ba6152db2f..51d35386a94 100644
--- a/drivers/video/cfbimgblt.c
+++ b/drivers/video/cfbimgblt.c
@@ -29,7 +29,6 @@
* Also need to add code to deal with cards endians that are different than
* the native cpu endians. I also need to deal with MSB position in the word.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
@@ -230,6 +229,7 @@ static inline void fast_imageblit(const struct fb_image *image, struct fb_info *
tab = cfb_tab16;
break;
case 32:
+ default:
tab = cfb_tab32;
break;
}
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c
index 63b6c79c8a0..7f926c619b6 100644
--- a/drivers/video/cg14.c
+++ b/drivers/video/cg14.c
@@ -1,6 +1,6 @@
/* cg14.c: CGFOURTEEN frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
*
@@ -18,8 +18,8 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -99,73 +99,73 @@ static struct fb_ops cg14_ops = {
#define CG14_MCR_PIXMODE_32 3
struct cg14_regs{
- volatile u8 mcr; /* Master Control Reg */
- volatile u8 ppr; /* Packed Pixel Reg */
- volatile u8 tms[2]; /* Test Mode Status Regs */
- volatile u8 msr; /* Master Status Reg */
- volatile u8 fsr; /* Fault Status Reg */
- volatile u8 rev; /* Revision & Impl */
- volatile u8 ccr; /* Clock Control Reg */
- volatile u32 tmr; /* Test Mode Read Back */
- volatile u8 mod; /* Monitor Operation Data Reg */
- volatile u8 acr; /* Aux Control */
+ u8 mcr; /* Master Control Reg */
+ u8 ppr; /* Packed Pixel Reg */
+ u8 tms[2]; /* Test Mode Status Regs */
+ u8 msr; /* Master Status Reg */
+ u8 fsr; /* Fault Status Reg */
+ u8 rev; /* Revision & Impl */
+ u8 ccr; /* Clock Control Reg */
+ u32 tmr; /* Test Mode Read Back */
+ u8 mod; /* Monitor Operation Data Reg */
+ u8 acr; /* Aux Control */
u8 xxx0[6];
- volatile u16 hct; /* Hor Counter */
- volatile u16 vct; /* Vert Counter */
- volatile u16 hbs; /* Hor Blank Start */
- volatile u16 hbc; /* Hor Blank Clear */
- volatile u16 hss; /* Hor Sync Start */
- volatile u16 hsc; /* Hor Sync Clear */
- volatile u16 csc; /* Composite Sync Clear */
- volatile u16 vbs; /* Vert Blank Start */
- volatile u16 vbc; /* Vert Blank Clear */
- volatile u16 vss; /* Vert Sync Start */
- volatile u16 vsc; /* Vert Sync Clear */
- volatile u16 xcs;
- volatile u16 xcc;
- volatile u16 fsa; /* Fault Status Address */
- volatile u16 adr; /* Address Registers */
+ u16 hct; /* Hor Counter */
+ u16 vct; /* Vert Counter */
+ u16 hbs; /* Hor Blank Start */
+ u16 hbc; /* Hor Blank Clear */
+ u16 hss; /* Hor Sync Start */
+ u16 hsc; /* Hor Sync Clear */
+ u16 csc; /* Composite Sync Clear */
+ u16 vbs; /* Vert Blank Start */
+ u16 vbc; /* Vert Blank Clear */
+ u16 vss; /* Vert Sync Start */
+ u16 vsc; /* Vert Sync Clear */
+ u16 xcs;
+ u16 xcc;
+ u16 fsa; /* Fault Status Address */
+ u16 adr; /* Address Registers */
u8 xxx1[0xce];
- volatile u8 pcg[0x100]; /* Pixel Clock Generator */
- volatile u32 vbr; /* Frame Base Row */
- volatile u32 vmcr; /* VBC Master Control */
- volatile u32 vcr; /* VBC refresh */
- volatile u32 vca; /* VBC Config */
+ u8 pcg[0x100]; /* Pixel Clock Generator */
+ u32 vbr; /* Frame Base Row */
+ u32 vmcr; /* VBC Master Control */
+ u32 vcr; /* VBC refresh */
+ u32 vca; /* VBC Config */
};
#define CG14_CCR_ENABLE 0x04
#define CG14_CCR_SELECT 0x02 /* HW/Full screen */
struct cg14_cursor {
- volatile u32 cpl0[32]; /* Enable plane 0 */
- volatile u32 cpl1[32]; /* Color selection plane */
- volatile u8 ccr; /* Cursor Control Reg */
+ u32 cpl0[32]; /* Enable plane 0 */
+ u32 cpl1[32]; /* Color selection plane */
+ u8 ccr; /* Cursor Control Reg */
u8 xxx0[3];
- volatile u16 cursx; /* Cursor x,y position */
- volatile u16 cursy; /* Cursor x,y position */
- volatile u32 color0;
- volatile u32 color1;
+ u16 cursx; /* Cursor x,y position */
+ u16 cursy; /* Cursor x,y position */
+ u32 color0;
+ u32 color1;
u32 xxx1[0x1bc];
- volatile u32 cpl0i[32]; /* Enable plane 0 autoinc */
- volatile u32 cpl1i[32]; /* Color selection autoinc */
+ u32 cpl0i[32]; /* Enable plane 0 autoinc */
+ u32 cpl1i[32]; /* Color selection autoinc */
};
struct cg14_dac {
- volatile u8 addr; /* Address Register */
+ u8 addr; /* Address Register */
u8 xxx0[255];
- volatile u8 glut; /* Gamma table */
+ u8 glut; /* Gamma table */
u8 xxx1[255];
- volatile u8 select; /* Register Select */
+ u8 select; /* Register Select */
u8 xxx2[255];
- volatile u8 mode; /* Mode Register */
+ u8 mode; /* Mode Register */
};
struct cg14_xlut{
- volatile u8 x_xlut [256];
- volatile u8 x_xlutd [256];
+ u8 x_xlut [256];
+ u8 x_xlutd [256];
u8 xxx0[0x600];
- volatile u8 x_xlut_inc [256];
- volatile u8 x_xlutd_inc [256];
+ u8 x_xlut_inc [256];
+ u8 x_xlutd_inc [256];
};
/* Color look up table (clut) */
@@ -204,7 +204,6 @@ struct cg14_par {
int mode;
int ramsize;
- struct sbus_dev *sdev;
};
static void __cg14_reset(struct cg14_par *par)
@@ -355,14 +354,9 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
* Initialisation
*/
-static void cg14_init_fix(struct fb_info *info, int linebytes)
+static void cg14_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
{
- struct cg14_par *par = (struct cg14_par *)info->par;
- const char *name;
-
- name = "cgfourteen";
- if (par->sdev)
- name = par->sdev->prom_name;
+ const char *name = dp->name;
strlcpy(info->fix.id, name, sizeof(info->fix.id));
@@ -456,98 +450,81 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __initdata = {
struct all_info {
struct fb_info info;
struct cg14_par par;
- struct list_head list;
};
-static LIST_HEAD(cg14_list);
-static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
+static void cg14_unmap_regs(struct all_info *all)
{
- struct all_info *all;
- unsigned long phys, rphys;
- u32 bases[6];
- int is_8mb, linebytes, i;
-
- if (!sdev) {
- if (prom_getproperty(node, "address",
- (char *) &bases[0], sizeof(bases)) <= 0
- || !bases[0]) {
- printk(KERN_ERR "cg14: Device is not mapped.\n");
- return;
- }
- if (__get_iospace(bases[0]) != __get_iospace(bases[1])) {
- printk(KERN_ERR "cg14: I/O spaces don't match.\n");
- return;
- }
- }
+ if (all->par.regs)
+ of_iounmap(all->par.regs, sizeof(struct cg14_regs));
+ if (all->par.clut)
+ of_iounmap(all->par.clut, sizeof(struct cg14_clut));
+ if (all->par.cursor)
+ of_iounmap(all->par.cursor, sizeof(struct cg14_cursor));
+ if (all->info.screen_base)
+ of_iounmap(all->info.screen_base, all->par.fbsize);
+}
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "cg14: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
+static int __devinit cg14_init_one(struct of_device *op)
+{
+ struct device_node *dp = op->node;
+ struct all_info *all;
+ int is_8mb, linebytes, i, err;
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- sbusfb_fill_var(&all->info.var, node, 8);
+ sbusfb_fill_var(&all->info.var, dp->node, 8);
all->info.var.red.length = 8;
all->info.var.green.length = 8;
all->info.var.blue.length = 8;
- linebytes = prom_getintdefault(node, "linebytes",
- all->info.var.xres);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
- all->par.sdev = sdev;
- if (sdev) {
- rphys = sdev->reg_addrs[0].phys_addr;
- all->par.physbase = phys = sdev->reg_addrs[1].phys_addr;
- all->par.iospace = sdev->reg_addrs[0].which_io;
-
- all->par.regs = sbus_ioremap(&sdev->resource[0], 0,
- sizeof(struct cg14_regs),
- "cg14 regs");
- all->par.clut = sbus_ioremap(&sdev->resource[0], CG14_CLUT1,
- sizeof(struct cg14_clut),
- "cg14 clut");
- all->par.cursor = sbus_ioremap(&sdev->resource[0], CG14_CURSORREGS,
- sizeof(struct cg14_cursor),
- "cg14 cursor");
- all->info.screen_base = sbus_ioremap(&sdev->resource[1], 0,
- all->par.fbsize, "cg14 ram");
+ if (!strcmp(dp->parent->name, "sbus") ||
+ !strcmp(dp->parent->name, "sbi")) {
+ all->par.physbase = op->resource[0].start;
+ all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
} else {
- rphys = __get_phys(bases[0]);
- all->par.physbase = phys = __get_phys(bases[1]);
- all->par.iospace = __get_iospace(bases[0]);
- all->par.regs = (struct cg14_regs __iomem *)(unsigned long)bases[0];
- all->par.clut = (struct cg14_clut __iomem *)((unsigned long)bases[0] +
- CG14_CLUT1);
- all->par.cursor =
- (struct cg14_cursor __iomem *)((unsigned long)bases[0] +
- CG14_CURSORREGS);
-
- all->info.screen_base = (char __iomem *)(unsigned long)bases[1];
+ all->par.physbase = op->resource[1].start;
+ all->par.iospace = op->resource[0].flags & IORESOURCE_BITS;
}
- prom_getproperty(node, "reg", (char *) &bases[0], sizeof(bases));
- is_8mb = (bases[5] == 0x800000);
+ all->par.regs = of_ioremap(&op->resource[0], 0,
+ sizeof(struct cg14_regs), "cg14 regs");
+ all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1,
+ sizeof(struct cg14_clut), "cg14 clut");
+ all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS,
+ sizeof(struct cg14_cursor), "cg14 cursor");
- if (sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)) {
- extern void __cg14_mmap_sized_wrongly(void);
+ all->info.screen_base = of_ioremap(&op->resource[1], 0,
+ all->par.fbsize, "cg14 ram");
- __cg14_mmap_sized_wrongly();
- }
+ if (!all->par.regs || !all->par.clut || !all->par.cursor ||
+ !all->info.screen_base)
+ cg14_unmap_regs(all);
+
+ is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) ==
+ (8 * 1024 * 1024));
+
+ BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map));
- memcpy(&all->par.mmap_map, &__cg14_mmap_map, sizeof(all->par.mmap_map));
+ memcpy(&all->par.mmap_map, &__cg14_mmap_map,
+ sizeof(all->par.mmap_map));
+
for (i = 0; i < CG14_MMAP_ENTRIES; i++) {
struct sbus_mmap_map *map = &all->par.mmap_map[i];
if (!map->size)
break;
if (map->poff & 0x80000000)
- map->poff = (map->poff & 0x7fffffff) + rphys - phys;
+ map->poff = (map->poff & 0x7fffffff) +
+ (op->resource[0].start -
+ op->resource[1].start);
if (is_8mb &&
map->size >= 0x100000 &&
map->size <= 0x400000)
@@ -564,84 +541,87 @@ static void cg14_init_one(struct sbus_dev *sdev, int node, int parent_node)
__cg14_reset(&all->par);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "cg14: Could not allocate color map.\n");
+ cg14_unmap_regs(all);
kfree(all);
- return;
+ return -ENOMEM;
}
fb_set_cmap(&all->info.cmap, &all->info);
- cg14_init_fix(&all->info, linebytes);
+ cg14_init_fix(&all->info, linebytes, dp);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "cg14: Could not register framebuffer.\n");
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
+ cg14_unmap_regs(all);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &cg14_list);
+ dev_set_drvdata(&op->dev, all);
- printk("cg14: cgfourteen at %lx:%lx, %dMB\n",
- all->par.iospace, all->par.physbase, all->par.ramsize >> 20);
+ printk("%s: cgfourteen at %lx:%lx, %dMB\n",
+ dp->full_name,
+ all->par.iospace, all->par.physbase,
+ all->par.ramsize >> 20);
+ return 0;
}
-int __init cg14_init(void)
+static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("cg14fb", NULL))
- return -ENODEV;
+ return cg14_init_one(op);
+}
-#ifdef CONFIG_SPARC32
- {
- int root, node;
-
- root = prom_getchild(prom_root_node);
- root = prom_searchsiblings(root, "obio");
- if (root) {
- node = prom_searchsiblings(prom_getchild(root),
- "cgfourteen");
- if (node)
- cg14_init_one(NULL, node, root);
- }
- }
-#endif
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "cgfourteen"))
- cg14_init_one(sdev, sdev->prom_node, sbus->prom_node);
- }
+static int __devexit cg14_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+
+ cg14_unmap_regs(all);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit cg14_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id cg14_match[] = {
+ {
+ .name = "cgfourteen",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cg14_match);
- list_for_each_safe(pos, tmp, &cg14_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver cg14_driver = {
+ .name = "cg14",
+ .match_table = cg14_match,
+ .probe = cg14_probe,
+ .remove = __devexit_p(cg14_remove),
+};
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+int __init cg14_init(void)
+{
+ if (fb_get_options("cg14fb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&cg14_driver, &of_bus_type);
}
-int __init
-cg14_setup(char *arg)
+void __exit cg14_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&cg14_driver);
}
module_init(cg14_init);
-
-#ifdef MODULE
module_exit(cg14_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for CGfourteen chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 3de6e1b5ab2..9c8c753ef45 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -1,6 +1,6 @@
/* cg3.c: CGTHREE frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
@@ -19,8 +19,9 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -80,30 +81,30 @@ enum cg3_type {
};
struct bt_regs {
- volatile u32 addr;
- volatile u32 color_map;
- volatile u32 control;
- volatile u32 cursor;
+ u32 addr;
+ u32 color_map;
+ u32 control;
+ u32 cursor;
};
struct cg3_regs {
struct bt_regs cmap;
- volatile u8 control;
- volatile u8 status;
- volatile u8 cursor_start;
- volatile u8 cursor_end;
- volatile u8 h_blank_start;
- volatile u8 h_blank_end;
- volatile u8 h_sync_start;
- volatile u8 h_sync_end;
- volatile u8 comp_sync_end;
- volatile u8 v_blank_start_high;
- volatile u8 v_blank_start_low;
- volatile u8 v_blank_end;
- volatile u8 v_sync_start;
- volatile u8 v_sync_end;
- volatile u8 xfer_holdoff_start;
- volatile u8 xfer_holdoff_end;
+ u8 control;
+ u8 status;
+ u8 cursor_start;
+ u8 cursor_end;
+ u8 h_blank_start;
+ u8 h_blank_end;
+ u8 h_sync_start;
+ u8 h_sync_end;
+ u8 comp_sync_end;
+ u8 v_blank_start_high;
+ u8 v_blank_start_low;
+ u8 v_blank_end;
+ u8 v_sync_start;
+ u8 v_sync_end;
+ u8 xfer_holdoff_start;
+ u8 xfer_holdoff_end;
};
/* Offset of interesting structures in the OBIO space */
@@ -120,9 +121,8 @@ struct cg3_par {
#define CG3_FLAG_RDI 0x00000002
unsigned long physbase;
+ unsigned long which_io;
unsigned long fbsize;
-
- struct sbus_dev *sdev;
};
/**
@@ -235,7 +235,7 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma)
return sbusfb_mmap_helper(cg3_mmap_map,
par->physbase, par->fbsize,
- par->sdev->reg_addrs[0].which_io,
+ par->which_io,
vma);
}
@@ -252,11 +252,9 @@ static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
*/
static void
-cg3_init_fix(struct fb_info *info, int linebytes)
+cg3_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
{
- struct cg3_par *par = (struct cg3_par *)info->par;
-
- strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+ strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -267,16 +265,15 @@ cg3_init_fix(struct fb_info *info, int linebytes)
}
static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,
- struct sbus_dev *sdev)
+ struct device_node *dp)
{
- char buffer[40];
+ char *params;
char *p;
int ww, hh;
- *buffer = 0;
- prom_getstring(sdev->prom_node, "params", buffer, sizeof(buffer));
- if (*buffer) {
- ww = simple_strtoul(buffer, &p, 10);
+ params = of_get_property(dp, "params", NULL);
+ if (params) {
+ ww = simple_strtoul(params, &p, 10);
if (ww && *p == 'x') {
hh = simple_strtoul(p + 1, &p, 10);
if (hh && *p == '-') {
@@ -348,11 +345,11 @@ static void cg3_do_default_mode(struct cg3_par *par)
sbus_writeb(p[1], regp);
}
for (p = cg3_dacvals; *p; p += 2) {
- volatile u8 __iomem *regp;
+ u8 __iomem *regp;
- regp = (volatile u8 __iomem *)&par->regs->cmap.addr;
+ regp = (u8 __iomem *)&par->regs->cmap.addr;
sbus_writeb(p[0], regp);
- regp = (volatile u8 __iomem *)&par->regs->cmap.control;
+ regp = (u8 __iomem *)&par->regs->cmap.control;
sbus_writeb(p[1], regp);
}
}
@@ -360,129 +357,137 @@ static void cg3_do_default_mode(struct cg3_par *par)
struct all_info {
struct fb_info info;
struct cg3_par par;
- struct list_head list;
};
-static LIST_HEAD(cg3_list);
-static void cg3_init_one(struct sbus_dev *sdev)
+static int __devinit cg3_init_one(struct of_device *op)
{
+ struct device_node *dp = op->node;
struct all_info *all;
- int linebytes;
-
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "cg3: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
+ int linebytes, err;
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- all->par.sdev = sdev;
- all->par.physbase = sdev->reg_addrs[0].phys_addr;
+ all->par.physbase = op->resource[0].start;
+ all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+ sbusfb_fill_var(&all->info.var, dp->node, 8);
all->info.var.red.length = 8;
all->info.var.green.length = 8;
all->info.var.blue.length = 8;
- if (!strcmp(sdev->prom_name, "cgRDI"))
+ if (!strcmp(dp->name, "cgRDI"))
all->par.flags |= CG3_FLAG_RDI;
if (all->par.flags & CG3_FLAG_RDI)
- cg3_rdi_maybe_fixup_var(&all->info.var, sdev);
+ cg3_rdi_maybe_fixup_var(&all->info.var, dp);
- linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
- all->info.var.xres);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
- all->par.regs = sbus_ioremap(&sdev->resource[0], CG3_REGS_OFFSET,
- sizeof(struct cg3_regs), "cg3 regs");
+ all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,
+ sizeof(struct cg3_regs), "cg3 regs");
all->info.flags = FBINFO_DEFAULT;
all->info.fbops = &cg3_ops;
-#ifdef CONFIG_SPARC32
- all->info.screen_base = (char __iomem *)
- prom_getintdefault(sdev->prom_node, "address", 0);
-#endif
- if (!all->info.screen_base)
- all->info.screen_base =
- sbus_ioremap(&sdev->resource[0], CG3_RAM_OFFSET,
- all->par.fbsize, "cg3 ram");
+ all->info.screen_base =
+ of_ioremap(&op->resource[0], CG3_RAM_OFFSET,
+ all->par.fbsize, "cg3 ram");
all->info.par = &all->par;
cg3_blank(0, &all->info);
- if (!prom_getbool(sdev->prom_node, "width"))
+ if (!of_find_property(dp, "width", NULL))
cg3_do_default_mode(&all->par);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "cg3: Could not allocate color map.\n");
+ of_iounmap(all->par.regs, sizeof(struct cg3_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
kfree(all);
- return;
+ return -ENOMEM;
}
fb_set_cmap(&all->info.cmap, &all->info);
- cg3_init_fix(&all->info, linebytes);
+ cg3_init_fix(&all->info, linebytes, dp);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "cg3: Could not register framebuffer.\n");
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
+ of_iounmap(all->par.regs, sizeof(struct cg3_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &cg3_list);
+ dev_set_drvdata(&op->dev, all);
+
+ printk("%s: cg3 at %lx:%lx\n",
+ dp->full_name, all->par.which_io, all->par.physbase);
- printk("cg3: %s at %lx:%lx\n",
- sdev->prom_name,
- (long) sdev->reg_addrs[0].which_io,
- (long) sdev->reg_addrs[0].phys_addr);
+ return 0;
}
-int __init cg3_init(void)
+static int __devinit cg3_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("cg3fb", NULL))
- return -ENODEV;
+ return cg3_init_one(op);
+}
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "cgthree") ||
- !strcmp(sdev->prom_name, "cgRDI"))
- cg3_init_one(sdev);
- }
+static int __devexit cg3_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+
+ of_iounmap(all->par.regs, sizeof(struct cg3_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit cg3_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id cg3_match[] = {
+ {
+ .name = "cgthree",
+ },
+ {
+ .name = "cgRDI",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cg3_match);
- list_for_each_safe(pos, tmp, &cg3_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver cg3_driver = {
+ .name = "cg3",
+ .match_table = cg3_match,
+ .probe = cg3_probe,
+ .remove = __devexit_p(cg3_remove),
+};
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+static int __init cg3_init(void)
+{
+ if (fb_get_options("cg3fb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&cg3_driver, &of_bus_type);
}
-int __init
-cg3_setup(char *arg)
+static void __exit cg3_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&cg3_driver);
}
module_init(cg3_init);
-
-#ifdef MODULE
module_exit(cg3_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index 7aab91ead68..64146be2eeb 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -1,6 +1,6 @@
/* cg6.c: CGSIX (GX, GXplus, TGX) frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
@@ -19,8 +19,8 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -164,89 +164,89 @@ static struct fb_ops cg6_ops = {
/* The contents are unknown */
struct cg6_tec {
- volatile int tec_matrix;
- volatile int tec_clip;
- volatile int tec_vdc;
+ int tec_matrix;
+ int tec_clip;
+ int tec_vdc;
};
struct cg6_thc {
- uint thc_pad0[512];
- volatile uint thc_hs; /* hsync timing */
- volatile uint thc_hsdvs;
- volatile uint thc_hd;
- volatile uint thc_vs; /* vsync timing */
- volatile uint thc_vd;
- volatile uint thc_refresh;
- volatile uint thc_misc;
- uint thc_pad1[56];
- volatile uint thc_cursxy; /* cursor x,y position (16 bits each) */
- volatile uint thc_cursmask[32]; /* cursor mask bits */
- volatile uint thc_cursbits[32]; /* what to show where mask enabled */
+ u32 thc_pad0[512];
+ u32 thc_hs; /* hsync timing */
+ u32 thc_hsdvs;
+ u32 thc_hd;
+ u32 thc_vs; /* vsync timing */
+ u32 thc_vd;
+ u32 thc_refresh;
+ u32 thc_misc;
+ u32 thc_pad1[56];
+ u32 thc_cursxy; /* cursor x,y position (16 bits each) */
+ u32 thc_cursmask[32]; /* cursor mask bits */
+ u32 thc_cursbits[32]; /* what to show where mask enabled */
};
struct cg6_fbc {
- u32 xxx0[1];
- volatile u32 mode;
- volatile u32 clip;
- u32 xxx1[1];
- volatile u32 s;
- volatile u32 draw;
- volatile u32 blit;
- volatile u32 font;
- u32 xxx2[24];
- volatile u32 x0, y0, z0, color0;
- volatile u32 x1, y1, z1, color1;
- volatile u32 x2, y2, z2, color2;
- volatile u32 x3, y3, z3, color3;
- volatile u32 offx, offy;
- u32 xxx3[2];
- volatile u32 incx, incy;
- u32 xxx4[2];
- volatile u32 clipminx, clipminy;
- u32 xxx5[2];
- volatile u32 clipmaxx, clipmaxy;
- u32 xxx6[2];
- volatile u32 fg;
- volatile u32 bg;
- volatile u32 alu;
- volatile u32 pm;
- volatile u32 pixelm;
- u32 xxx7[2];
- volatile u32 patalign;
- volatile u32 pattern[8];
- u32 xxx8[432];
- volatile u32 apointx, apointy, apointz;
- u32 xxx9[1];
- volatile u32 rpointx, rpointy, rpointz;
- u32 xxx10[5];
- volatile u32 pointr, pointg, pointb, pointa;
- volatile u32 alinex, aliney, alinez;
- u32 xxx11[1];
- volatile u32 rlinex, rliney, rlinez;
- u32 xxx12[5];
- volatile u32 liner, lineg, lineb, linea;
- volatile u32 atrix, atriy, atriz;
- u32 xxx13[1];
- volatile u32 rtrix, rtriy, rtriz;
- u32 xxx14[5];
- volatile u32 trir, trig, trib, tria;
- volatile u32 aquadx, aquady, aquadz;
- u32 xxx15[1];
- volatile u32 rquadx, rquady, rquadz;
- u32 xxx16[5];
- volatile u32 quadr, quadg, quadb, quada;
- volatile u32 arectx, arecty, arectz;
- u32 xxx17[1];
- volatile u32 rrectx, rrecty, rrectz;
- u32 xxx18[5];
- volatile u32 rectr, rectg, rectb, recta;
+ u32 xxx0[1];
+ u32 mode;
+ u32 clip;
+ u32 xxx1[1];
+ u32 s;
+ u32 draw;
+ u32 blit;
+ u32 font;
+ u32 xxx2[24];
+ u32 x0, y0, z0, color0;
+ u32 x1, y1, z1, color1;
+ u32 x2, y2, z2, color2;
+ u32 x3, y3, z3, color3;
+ u32 offx, offy;
+ u32 xxx3[2];
+ u32 incx, incy;
+ u32 xxx4[2];
+ u32 clipminx, clipminy;
+ u32 xxx5[2];
+ u32 clipmaxx, clipmaxy;
+ u32 xxx6[2];
+ u32 fg;
+ u32 bg;
+ u32 alu;
+ u32 pm;
+ u32 pixelm;
+ u32 xxx7[2];
+ u32 patalign;
+ u32 pattern[8];
+ u32 xxx8[432];
+ u32 apointx, apointy, apointz;
+ u32 xxx9[1];
+ u32 rpointx, rpointy, rpointz;
+ u32 xxx10[5];
+ u32 pointr, pointg, pointb, pointa;
+ u32 alinex, aliney, alinez;
+ u32 xxx11[1];
+ u32 rlinex, rliney, rlinez;
+ u32 xxx12[5];
+ u32 liner, lineg, lineb, linea;
+ u32 atrix, atriy, atriz;
+ u32 xxx13[1];
+ u32 rtrix, rtriy, rtriz;
+ u32 xxx14[5];
+ u32 trir, trig, trib, tria;
+ u32 aquadx, aquady, aquadz;
+ u32 xxx15[1];
+ u32 rquadx, rquady, rquadz;
+ u32 xxx16[5];
+ u32 quadr, quadg, quadb, quada;
+ u32 arectx, arecty, arectz;
+ u32 xxx17[1];
+ u32 rrectx, rrecty, rrectz;
+ u32 xxx18[5];
+ u32 rectr, rectg, rectb, recta;
};
struct bt_regs {
- volatile u32 addr;
- volatile u32 color_map;
- volatile u32 control;
- volatile u32 cursor;
+ u32 addr;
+ u32 color_map;
+ u32 control;
+ u32 cursor;
};
struct cg6_par {
@@ -255,15 +255,14 @@ struct cg6_par {
struct cg6_fbc __iomem *fbc;
struct cg6_thc __iomem *thc;
struct cg6_tec __iomem *tec;
- volatile u32 __iomem *fhc;
+ u32 __iomem *fhc;
u32 flags;
#define CG6_FLAG_BLANKED 0x00000001
unsigned long physbase;
+ unsigned long which_io;
unsigned long fbsize;
-
- struct sbus_dev *sdev;
};
static int cg6_sync(struct fb_info *info)
@@ -529,8 +528,7 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma)
return sbusfb_mmap_helper(cg6_mmap_map,
par->physbase, par->fbsize,
- par->sdev->reg_addrs[0].which_io,
- vma);
+ par->which_io, vma);
}
static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
@@ -658,62 +656,75 @@ static void cg6_chip_init(struct fb_info *info)
struct all_info {
struct fb_info info;
struct cg6_par par;
- struct list_head list;
};
-static LIST_HEAD(cg6_list);
-static void cg6_init_one(struct sbus_dev *sdev)
+static void cg6_unmap_regs(struct all_info *all)
{
- struct all_info *all;
- int linebytes;
+ if (all->par.fbc)
+ of_iounmap(all->par.fbc, 4096);
+ if (all->par.tec)
+ of_iounmap(all->par.tec, sizeof(struct cg6_tec));
+ if (all->par.thc)
+ of_iounmap(all->par.thc, sizeof(struct cg6_thc));
+ if (all->par.bt)
+ of_iounmap(all->par.bt, sizeof(struct bt_regs));
+ if (all->par.fhc)
+ of_iounmap(all->par.fhc, sizeof(u32));
+
+ if (all->info.screen_base)
+ of_iounmap(all->info.screen_base, all->par.fbsize);
+}
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "cg6: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
+static int __devinit cg6_init_one(struct of_device *op)
+{
+ struct device_node *dp = op->node;
+ struct all_info *all;
+ int linebytes, err;
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- all->par.sdev = sdev;
- all->par.physbase = sdev->reg_addrs[0].phys_addr;
+ all->par.physbase = op->resource[0].start;
+ all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+ sbusfb_fill_var(&all->info.var, dp->node, 8);
all->info.var.red.length = 8;
all->info.var.green.length = 8;
all->info.var.blue.length = 8;
- linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
- all->info.var.xres);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
- if (prom_getbool(sdev->prom_node, "dblbuf"))
+ if (of_find_property(dp, "dblbuf", NULL))
all->par.fbsize *= 4;
- all->par.fbc = sbus_ioremap(&sdev->resource[0], CG6_FBC_OFFSET,
- 4096, "cgsix fbc");
- all->par.tec = sbus_ioremap(&sdev->resource[0], CG6_TEC_OFFSET,
- sizeof(struct cg6_tec), "cgsix tec");
- all->par.thc = sbus_ioremap(&sdev->resource[0], CG6_THC_OFFSET,
- sizeof(struct cg6_thc), "cgsix thc");
- all->par.bt = sbus_ioremap(&sdev->resource[0], CG6_BROOKTREE_OFFSET,
- sizeof(struct bt_regs), "cgsix dac");
- all->par.fhc = sbus_ioremap(&sdev->resource[0], CG6_FHC_OFFSET,
- sizeof(u32), "cgsix fhc");
+ all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET,
+ 4096, "cgsix fbc");
+ all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET,
+ sizeof(struct cg6_tec), "cgsix tec");
+ all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET,
+ sizeof(struct cg6_thc), "cgsix thc");
+ all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET,
+ sizeof(struct bt_regs), "cgsix dac");
+ all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET,
+ sizeof(u32), "cgsix fhc");
all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT |
FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT;
all->info.fbops = &cg6_ops;
-#ifdef CONFIG_SPARC32
- all->info.screen_base = (char __iomem *)
- prom_getintdefault(sdev->prom_node, "address", 0);
-#endif
- if (!all->info.screen_base)
- all->info.screen_base =
- sbus_ioremap(&sdev->resource[0], CG6_RAM_OFFSET,
- all->par.fbsize, "cgsix ram");
+
+ all->info.screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET,
+ all->par.fbsize, "cgsix ram");
+ if (!all->par.fbc || !all->par.tec || !all->par.thc ||
+ !all->par.bt || !all->par.fhc || !all->info.screen_base) {
+ cg6_unmap_regs(all);
+ kfree(all);
+ return -ENOMEM;
+ }
+
all->info.par = &all->par;
all->info.var.accel_flags = FB_ACCELF_TEXT;
@@ -723,72 +734,90 @@ static void cg6_init_one(struct sbus_dev *sdev)
cg6_blank(0, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "cg6: Could not allocate color map.\n");
+ cg6_unmap_regs(all);
kfree(all);
- return;
+ return -ENOMEM;
}
fb_set_cmap(&all->info.cmap, &all->info);
cg6_init_fix(&all->info, linebytes);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "cg6: Could not register framebuffer.\n");
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
+ cg6_unmap_regs(all);
fb_dealloc_cmap(&all->info.cmap);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &cg6_list);
+ dev_set_drvdata(&op->dev, all);
- printk("cg6: CGsix [%s] at %lx:%lx\n",
+ printk("%s: CGsix [%s] at %lx:%lx\n",
+ dp->full_name,
all->info.fix.id,
- (long) sdev->reg_addrs[0].which_io,
- (long) sdev->reg_addrs[0].phys_addr);
+ all->par.which_io, all->par.physbase);
+
+ return 0;
}
-int __init cg6_init(void)
+static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("cg6fb", NULL))
- return -ENODEV;
+ return cg6_init_one(op);
+}
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "cgsix") ||
- !strcmp(sdev->prom_name, "cgthree+"))
- cg6_init_one(sdev);
- }
+static int __devexit cg6_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+
+ cg6_unmap_regs(all);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit cg6_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id cg6_match[] = {
+ {
+ .name = "cgsix",
+ },
+ {
+ .name = "cgthree+",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, cg6_match);
- list_for_each_safe(pos, tmp, &cg6_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver cg6_driver = {
+ .name = "cg6",
+ .match_table = cg6_match,
+ .probe = cg6_probe,
+ .remove = __devexit_p(cg6_remove),
+};
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+static int __init cg6_init(void)
+{
+ if (fb_get_options("cg6fb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&cg6_driver, &of_bus_type);
}
-int __init
-cg6_setup(char *arg)
+static void __exit cg6_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&cg6_driver);
}
module_init(cg6_init);
-
-#ifdef MODULE
module_exit(cg6_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for CGsix chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 72ff6bf75e5..73cb426bf2d 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -14,13 +14,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -148,9 +146,23 @@ static int chipsfb_set_par(struct fb_info *info)
static int chipsfb_blank(int blank, struct fb_info *info)
{
#ifdef CONFIG_PMAC_BACKLIGHT
- // used to disable backlight only for blank > 1, but it seems
- // useful at blank = 1 too (saves battery, extends backlight life)
- set_backlight_enable(!blank);
+ mutex_lock(&pmac_backlight_mutex);
+
+ if (pmac_backlight) {
+ /* used to disable backlight only for blank > 1, but it seems
+ * useful at blank = 1 too (saves battery, extends backlight
+ * life)
+ */
+ down(&pmac_backlight->sem);
+ if (blank)
+ pmac_backlight->props->power = FB_BLANK_POWERDOWN;
+ else
+ pmac_backlight->props->power = FB_BLANK_UNBLANK;
+ pmac_backlight->props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
+ }
+
+ mutex_unlock(&pmac_backlight_mutex);
#endif /* CONFIG_PMAC_BACKLIGHT */
return 1; /* get fb_blank to set the colormap to all black */
@@ -401,7 +413,14 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
#ifdef CONFIG_PMAC_BACKLIGHT
/* turn on the backlight */
- set_backlight_enable(1);
+ mutex_lock(&pmac_backlight_mutex);
+ if (pmac_backlight) {
+ down(&pmac_backlight->sem);
+ pmac_backlight->props->power = FB_BLANK_UNBLANK;
+ pmac_backlight->props->update_status(pmac_backlight);
+ up(&pmac_backlight->sem);
+ }
+ mutex_unlock(&pmac_backlight_mutex);
#endif /* CONFIG_PMAC_BACKLIGHT */
#ifdef CONFIG_PPC
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index 1103010af54..daf43f535a0 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -36,13 +36,11 @@
#define CIRRUSFB_VERSION "2.0-pre2"
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -2227,7 +2225,6 @@ static void cirrusfb_pci_unmap (struct cirrusfb_info *cinfo)
release_region(0x3C0, 32);
pci_release_regions(pdev);
framebuffer_release(cinfo->info);
- pci_disable_device(pdev);
}
#endif /* CONFIG_PCI */
@@ -2458,7 +2455,6 @@ err_release_regions:
err_release_fb:
framebuffer_release(info);
err_disable:
- pci_disable_device(pdev);
err_out:
return ret;
}
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 4444bef68fb..aa3935df852 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -6,7 +6,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EMBEDDED || !X86
- depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE
+ depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH
default y
help
Saying Y here will allow you to use Linux in text mode through a
diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c
index eea422eb1ab..308850df16f 100644
--- a/drivers/video/console/bitblit.c
+++ b/drivers/video/console/bitblit.c
@@ -10,7 +10,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index 1ecda91e5a9..d9315d99445 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -7,9 +7,9 @@
#include <linux/types.h>
#include <linux/kdev_t.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/vt_kern.h>
+#include <linux/screen_info.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -22,7 +22,6 @@
#define DUMMY_ROWS ORIG_VIDEO_LINES
#elif defined(__hppa__)
/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
-#include <linux/config.h>
#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS
#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
#else
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 47ba1a79adc..1b4f75d1f8a 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -58,14 +58,12 @@
#undef FBCONDEBUG
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/delay.h> /* MSch: for IRQ probe */
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
@@ -125,6 +123,8 @@ static int softback_lines;
static int first_fb_vc;
static int last_fb_vc = MAX_NR_CONSOLES - 1;
static int fbcon_is_default = 1;
+static int fbcon_has_exited;
+
/* font data */
static char fontname[40];
@@ -140,7 +140,6 @@ static const struct consw fb_con;
#define advance_row(p, delta) (unsigned short *)((unsigned long)(p) + (delta) * vc->vc_size_row)
-static void fbcon_free_font(struct display *);
static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
@@ -194,6 +193,9 @@ 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);
+static void fbcon_start(void);
+static void fbcon_exit(void);
+static struct class_device *fbcon_class_device;
#ifdef CONFIG_MAC
/*
@@ -252,7 +254,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
if (!ops || ops->currcon < 0 || rotate > 3)
return;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
registered_fb[con2fb_map[i]] != info)
@@ -389,15 +391,18 @@ static void fb_flashcursor(void *private)
int c;
int mode;
- if (ops->currcon != -1)
+ acquire_console_sem();
+ if (ops && ops->currcon != -1)
vc = vc_cons[ops->currcon].d;
if (!vc || !CON_IS_VISIBLE(vc) ||
fbcon_is_inactive(vc, info) ||
registered_fb[con2fb_map[vc->vc_num]] != info ||
- vc_cons[ops->currcon].d->vc_deccm != 1)
+ vc_cons[ops->currcon].d->vc_deccm != 1) {
+ release_console_sem();
return;
- acquire_console_sem();
+ }
+
p = &fb_display[vc->vc_num];
c = scr_readw((u16 *) vc->vc_pos);
mode = (!ops->cursor_flash || ops->cursor_state.enable) ?
@@ -528,7 +533,7 @@ static int search_fb_in_map(int idx)
{
int i, retval = 0;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] == idx)
retval = 1;
}
@@ -539,7 +544,7 @@ static int search_for_mapped_con(void)
{
int i, retval = 0;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] != -1)
retval = 1;
}
@@ -561,6 +566,7 @@ static int fbcon_takeover(int show_logo)
err = take_over_console(&fb_con, first_fb_vc, last_fb_vc,
fbcon_is_default);
+
if (err) {
for (i = first_fb_vc; i <= last_fb_vc; i++) {
con2fb_map[i] = -1;
@@ -795,8 +801,8 @@ static int set_con2fb_map(int unit, int newidx, int user)
if (oldidx == newidx)
return 0;
- if (!info)
- err = -EINVAL;
+ if (!info || fbcon_has_exited)
+ return -EINVAL;
if (!err && !search_for_mapped_con()) {
info_idx = newidx;
@@ -832,6 +838,9 @@ static int set_con2fb_map(int unit, int newidx, int user)
con2fb_init_display(vc, info, unit, show_logo);
}
+ if (!search_fb_in_map(info_idx))
+ info_idx = newidx;
+
release_console_sem();
return err;
}
@@ -1034,6 +1043,7 @@ static const char *fbcon_startup(void)
#endif /* CONFIG_MAC */
fbcon_add_cursor_timer(info);
+ fbcon_has_exited = 0;
return display_desc;
}
@@ -1061,17 +1071,36 @@ static void fbcon_init(struct vc_data *vc, int init)
/* If we are not the first console on this
fb, copy the font from that console */
- t = &fb_display[svc->vc_num];
- if (!vc->vc_font.data) {
- vc->vc_font.data = (void *)(p->fontdata = t->fontdata);
- vc->vc_font.width = (*default_mode)->vc_font.width;
- vc->vc_font.height = (*default_mode)->vc_font.height;
- p->userfont = t->userfont;
- if (p->userfont)
- REFCOUNT(p->fontdata)++;
+ t = &fb_display[fg_console];
+ if (!p->fontdata) {
+ if (t->fontdata) {
+ struct vc_data *fvc = vc_cons[fg_console].d;
+
+ vc->vc_font.data = (void *)(p->fontdata =
+ fvc->vc_font.data);
+ vc->vc_font.width = fvc->vc_font.width;
+ vc->vc_font.height = fvc->vc_font.height;
+ p->userfont = t->userfont;
+
+ if (p->userfont)
+ REFCOUNT(p->fontdata)++;
+ } else {
+ const struct font_desc *font = NULL;
+
+ if (!fontname[0] || !(font = find_font(fontname)))
+ font = get_default_font(info->var.xres,
+ info->var.yres);
+ vc->vc_font.width = font->width;
+ vc->vc_font.height = font->height;
+ vc->vc_font.data = (void *)(p->fontdata = font->data);
+ vc->vc_font.charcount = 256; /* FIXME Need to
+ support more fonts */
+ }
}
+
if (p->userfont)
charcnt = FNTCHARCNT(p->fontdata);
+
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) {
@@ -1145,13 +1174,47 @@ static void fbcon_init(struct vc_data *vc, int init)
ops->p = &fb_display[fg_console];
}
+static void fbcon_free_font(struct display *p)
+{
+ if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
+ kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
+ p->fontdata = NULL;
+ p->userfont = 0;
+}
+
static void fbcon_deinit(struct vc_data *vc)
{
struct display *p = &fb_display[vc->vc_num];
+ struct fb_info *info;
+ struct fbcon_ops *ops;
+ int idx;
- if (info_idx != -1)
- return;
fbcon_free_font(p);
+ idx = con2fb_map[vc->vc_num];
+
+ if (idx == -1)
+ goto finished;
+
+ info = registered_fb[idx];
+
+ if (!info)
+ goto finished;
+
+ ops = info->fbcon_par;
+
+ if (!ops)
+ goto finished;
+
+ if (CON_IS_VISIBLE(vc))
+ fbcon_del_cursor_timer(info);
+
+ ops->flags &= ~FBCON_FLAGS_INIT;
+finished:
+
+ if (!con_is_bound(&fb_con))
+ fbcon_exit();
+
+ return;
}
/* ====================================================================== */
@@ -2099,12 +2162,11 @@ static int fbcon_switch(struct vc_data *vc)
if (info->fbops->fb_set_par)
info->fbops->fb_set_par(info);
- if (old_info != info) {
+ if (old_info != info)
fbcon_del_cursor_timer(old_info);
- fbcon_add_cursor_timer(info);
- }
}
+ fbcon_add_cursor_timer(info);
set_blitting_type(vc, info);
ops->cursor_reset = 1;
@@ -2222,14 +2284,6 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
return 0;
}
-static void fbcon_free_font(struct display *p)
-{
- if (p->userfont && p->fontdata && (--REFCOUNT(p->fontdata) == 0))
- kfree(p->fontdata - FONT_EXTRA_WORDS * sizeof(int));
- p->fontdata = NULL;
- p->userfont = 0;
-}
-
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
{
u8 *fontdata = vc->vc_font.data;
@@ -2443,7 +2497,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne
FNTSUM(new_data) = csum;
/* Check if the same font is on some other console already */
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
struct vc_data *tmp = vc_cons[i].d;
if (fb_display[i].userfont &&
@@ -2768,7 +2822,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
if (!ops || ops->currcon < 0)
return;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
registered_fb[con2fb_map[i]] != info)
@@ -2830,22 +2884,57 @@ static int fbcon_mode_deleted(struct fb_info *info,
return found;
}
+static int fbcon_fb_unregistered(int idx)
+{
+ int i;
+
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map[i] == idx)
+ con2fb_map[i] = -1;
+ }
+
+ if (idx == info_idx) {
+ info_idx = -1;
+
+ for (i = 0; i < FB_MAX; i++) {
+ if (registered_fb[i] != NULL) {
+ info_idx = i;
+ break;
+ }
+ }
+ }
+
+ if (info_idx != -1) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map[i] == -1)
+ con2fb_map[i] = info_idx;
+ }
+ }
+
+ if (!num_registered_fb)
+ unregister_con_driver(&fb_con);
+
+ return 0;
+}
+
static int fbcon_fb_registered(int idx)
{
int ret = 0, i;
if (info_idx == -1) {
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map_boot[i] == idx) {
info_idx = idx;
break;
}
}
+
if (info_idx != -1)
ret = fbcon_takeover(1);
} else {
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- if (con2fb_map_boot[i] == idx)
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
+ if (con2fb_map_boot[i] == idx &&
+ con2fb_map[i] == -1)
set_con2fb_map(i, idx, 0);
}
}
@@ -2882,7 +2971,7 @@ static void fbcon_new_modelist(struct fb_info *info)
struct fb_var_screeninfo var;
struct fb_videomode *mode;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (registered_fb[con2fb_map[i]] != info)
continue;
if (!fb_display[i].mode)
@@ -2910,6 +2999,14 @@ static int fbcon_event_notify(struct notifier_block *self,
struct fb_con2fbmap *con2fb;
int ret = 0;
+ /*
+ * ignore all events except driver registration and deregistration
+ * if fbcon is not active
+ */
+ if (fbcon_has_exited && !(action == FB_EVENT_FB_REGISTERED ||
+ action == FB_EVENT_FB_UNREGISTERED))
+ goto done;
+
switch(action) {
case FB_EVENT_SUSPEND:
fbcon_suspended(info);
@@ -2930,6 +3027,9 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_FB_REGISTERED:
ret = fbcon_fb_registered(info->node);
break;
+ case FB_EVENT_FB_UNREGISTERED:
+ ret = fbcon_fb_unregistered(info->node);
+ break;
case FB_EVENT_SET_CONSOLE_MAP:
con2fb = event->data;
ret = set_con2fb_map(con2fb->console - 1,
@@ -2945,16 +3045,9 @@ 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);
}
+done:
return ret;
}
@@ -2992,27 +3085,181 @@ static struct notifier_block fbcon_event_notifier = {
.notifier_call = fbcon_event_notify,
};
-static int __init fb_console_init(void)
+static ssize_t store_rotate(struct class_device *class_device,
+ const char *buf, size_t count)
{
- int i;
+ struct fb_info *info;
+ int rotate, idx;
+ char **last = NULL;
+
+ if (fbcon_has_exited)
+ return count;
acquire_console_sem();
- fb_register_client(&fbcon_event_notifier);
+ idx = con2fb_map[fg_console];
+
+ if (idx == -1 || registered_fb[idx] == NULL)
+ goto err;
+
+ info = registered_fb[idx];
+ rotate = simple_strtoul(buf, last, 0);
+ fbcon_rotate(info, rotate);
+err:
release_console_sem();
+ return count;
+}
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- con2fb_map[i] = -1;
+static ssize_t store_rotate_all(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct fb_info *info;
+ int rotate, idx;
+ char **last = NULL;
+
+ if (fbcon_has_exited)
+ return count;
+
+ acquire_console_sem();
+ idx = con2fb_map[fg_console];
+
+ if (idx == -1 || registered_fb[idx] == NULL)
+ goto err;
+ info = registered_fb[idx];
+ rotate = simple_strtoul(buf, last, 0);
+ fbcon_rotate_all(info, rotate);
+err:
+ release_console_sem();
+ return count;
+}
+
+static ssize_t show_rotate(struct class_device *class_device, char *buf)
+{
+ struct fb_info *info;
+ int rotate = 0, idx;
+
+ if (fbcon_has_exited)
+ return 0;
+
+ acquire_console_sem();
+ idx = con2fb_map[fg_console];
+
+ if (idx == -1 || registered_fb[idx] == NULL)
+ goto err;
+
+ info = registered_fb[idx];
+ rotate = fbcon_get_rotate(info);
+err:
+ release_console_sem();
+ return snprintf(buf, PAGE_SIZE, "%d\n", rotate);
+}
+
+static struct class_device_attribute class_device_attrs[] = {
+ __ATTR(rotate, S_IRUGO|S_IWUSR, show_rotate, store_rotate),
+ __ATTR(rotate_all, S_IWUSR, NULL, store_rotate_all),
+};
+
+static int fbcon_init_class_device(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_create_file(fbcon_class_device,
+ &class_device_attrs[i]);
+ return 0;
+}
+
+static void fbcon_start(void)
+{
if (num_registered_fb) {
+ int i;
+
+ acquire_console_sem();
+
for (i = 0; i < FB_MAX; i++) {
if (registered_fb[i] != NULL) {
info_idx = i;
break;
}
}
+
+ release_console_sem();
fbcon_takeover(0);
}
+}
+
+static void fbcon_exit(void)
+{
+ struct fb_info *info;
+ int i, j, mapped;
+
+ if (fbcon_has_exited)
+ return;
+
+#ifdef CONFIG_ATARI
+ free_irq(IRQ_AUTO_4, fb_vbl_handler);
+#endif
+#ifdef CONFIG_MAC
+ if (MACH_IS_MAC && vbl_detected)
+ free_irq(IRQ_MAC_VBL, fb_vbl_handler);
+#endif
+
+ kfree((void *)softback_buf);
+ softback_buf = 0UL;
+
+ for (i = 0; i < FB_MAX; i++) {
+ mapped = 0;
+ info = registered_fb[i];
+
+ if (info == NULL)
+ continue;
+
+ for (j = first_fb_vc; j <= last_fb_vc; j++) {
+ if (con2fb_map[j] == i)
+ mapped = 1;
+ }
+
+ if (mapped) {
+ if (info->fbops->fb_release)
+ info->fbops->fb_release(info, 0);
+ module_put(info->fbops->owner);
+
+ if (info->fbcon_par) {
+ fbcon_del_cursor_timer(info);
+ kfree(info->fbcon_par);
+ info->fbcon_par = NULL;
+ }
+ if (info->queue.func == fb_flashcursor)
+ info->queue.func = NULL;
+ }
+ }
+
+ fbcon_has_exited = 1;
+}
+
+static int __init fb_console_init(void)
+{
+ int i;
+
+ acquire_console_sem();
+ fb_register_client(&fbcon_event_notifier);
+ fbcon_class_device =
+ class_device_create(fb_class, NULL, MKDEV(0, 0), NULL, "fbcon");
+
+ if (IS_ERR(fbcon_class_device)) {
+ printk(KERN_WARNING "Unable to create class_device "
+ "for fbcon; errno = %ld\n",
+ PTR_ERR(fbcon_class_device));
+ fbcon_class_device = NULL;
+ } else
+ fbcon_init_class_device();
+
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ con2fb_map[i] = -1;
+
+ release_console_sem();
+ fbcon_start();
return 0;
}
@@ -3020,12 +3267,24 @@ module_init(fb_console_init);
#ifdef MODULE
+static void __exit fbcon_deinit_class_device(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_remove_file(fbcon_class_device,
+ &class_device_attrs[i]);
+}
+
static void __exit fb_console_exit(void)
{
acquire_console_sem();
fb_unregister_client(&fbcon_event_notifier);
+ fbcon_deinit_class_device();
+ class_device_destroy(fb_class, MKDEV(0, 0));
+ fbcon_exit();
release_console_sem();
- give_up_console(&fb_con);
+ unregister_con_driver(&fb_con);
}
module_exit(fb_console_exit);
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index c38c3d8e7a7..f244ad066d6 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -11,7 +11,6 @@
#ifndef _VIDEO_FBCON_H
#define _VIDEO_FBCON_H
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/vt_buffer.h>
#include <linux/vt_kern.h>
@@ -175,6 +174,7 @@ 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);
+extern struct class *fb_class;
#define FBCON_ATTRIBUTE_UNDERLINE 1
#define FBCON_ATTRIBUTE_REVERSE 2
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
index 990289a69b7..4481c80b8b2 100644
--- a/drivers/video/console/fbcon_ccw.c
+++ b/drivers/video/console/fbcon_ccw.c
@@ -8,7 +8,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index d44c5fa515f..7f92c06afea 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -8,7 +8,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/fbcon_rotate.c b/drivers/video/console/fbcon_rotate.c
index 2dc091fbd5c..00884e013f0 100644
--- a/drivers/video/console/fbcon_rotate.c
+++ b/drivers/video/console/fbcon_rotate.c
@@ -8,7 +8,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
index f56ed068a5b..ab91005e64d 100644
--- a/drivers/video/console/fbcon_ud.c
+++ b/drivers/video/console/fbcon_ud.c
@@ -8,7 +8,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c
index 2d2e39632e2..40f3d4eeb19 100644
--- a/drivers/video/console/font_acorn_8x8.c
+++ b/drivers/video/console/font_acorn_8x8.c
@@ -1,6 +1,5 @@
/* Acorn-like font definition, with PC graphics characters */
-#include <linux/config.h>
#include <linux/font.h>
static const unsigned char acorndata_8x8[] = {
diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c
index 0cc1bfda76a..c960728b7e8 100644
--- a/drivers/video/console/fonts.c
+++ b/drivers/video/console/fonts.c
@@ -12,7 +12,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 7f939d066a5..eb4d03fa539 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -31,7 +31,6 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
@@ -198,7 +197,7 @@ static int __init mdacon_setup(char *str)
__setup("mdacon=", mdacon_setup);
#endif
-static int __init mda_detect(void)
+static int mda_detect(void)
{
int count=0;
u16 *p, p_save;
@@ -283,7 +282,7 @@ static int __init mda_detect(void)
return 1;
}
-static void __init mda_initialize(void)
+static void mda_initialize(void)
{
write_mda_b(97, 0x00); /* horizontal total */
write_mda_b(80, 0x01); /* horizontal displayed */
@@ -308,7 +307,7 @@ static void __init mda_initialize(void)
outb_p(0x00, mda_gfx_port);
}
-static const char __init *mdacon_startup(void)
+static const char *mdacon_startup(void)
{
mda_num_columns = 80;
mda_num_lines = 25;
diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c
index e99fe30e568..7fa1afeae8d 100644
--- a/drivers/video/console/newport_con.c
+++ b/drivers/video/console/newport_con.c
@@ -12,7 +12,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/tty.h>
#include <linux/kd.h>
#include <linux/selection.h>
#include <linux/console.h>
@@ -51,6 +50,7 @@ static int topscan;
static int xcurs_correction = 29;
static int newport_xsize;
static int newport_ysize;
+static int newport_has_init;
static int newport_set_def_font(int unit, struct console_font *op);
@@ -283,6 +283,15 @@ static void newport_get_revisions(void)
xcurs_correction = 21;
}
+static void newport_exit(void)
+{
+ int i;
+
+ /* free memory used by user font */
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ newport_set_def_font(i, NULL);
+}
+
/* Can't be __init, take_over_console may call it later */
static const char *newport_startup(void)
{
@@ -290,8 +299,10 @@ static const char *newport_startup(void)
if (!sgi_gfxaddr)
return NULL;
- npregs = (struct newport_regs *) /* ioremap cannot fail */
- ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+
+ if (!npregs)
+ npregs = (struct newport_regs *)/* ioremap cannot fail */
+ ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
npregs->cset.config = NPORT_CFG_GD0;
if (newport_wait(npregs))
@@ -307,11 +318,11 @@ static const char *newport_startup(void)
newport_reset();
newport_get_revisions();
newport_get_screensize();
+ newport_has_init = 1;
return "SGI Newport";
out_unmap:
- iounmap((void *)npregs);
return NULL;
}
@@ -324,11 +335,10 @@ static void newport_init(struct vc_data *vc, int init)
static void newport_deinit(struct vc_data *c)
{
- int i;
-
- /* free memory used by user font */
- for (i = 0; i < MAX_NR_CONSOLES; i++)
- newport_set_def_font(i, NULL);
+ if (!con_is_bound(&newport_con) && newport_has_init) {
+ newport_exit();
+ newport_has_init = 0;
+ }
}
static void newport_clear(struct vc_data *vc, int sy, int sx, int height,
@@ -728,16 +738,23 @@ const struct consw newport_con = {
#ifdef MODULE
static int __init newport_console_init(void)
{
+
+ if (!sgi_gfxaddr)
+ return NULL;
+
+ if (!npregs)
+ npregs = (struct newport_regs *)/* ioremap cannot fail */
+ ioremap(sgi_gfxaddr, sizeof(struct newport_regs));
+
return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1);
}
+module_init(newport_console_init);
static void __exit newport_console_exit(void)
{
give_up_console(&newport_con);
iounmap((void *)npregs);
}
-
-module_init(newport_console_init);
module_exit(newport_console_exit);
#endif
diff --git a/drivers/video/console/promcon.c b/drivers/video/console/promcon.c
index 04f42fcaac5..b78eac63459 100644
--- a/drivers/video/console/promcon.c
+++ b/drivers/video/console/promcon.c
@@ -5,13 +5,11 @@
* Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/console.h>
@@ -109,7 +107,7 @@ promcon_end(struct vc_data *conp, char *b)
return b - p;
}
-const char __init *promcon_startup(void)
+const char *promcon_startup(void)
{
const char *display_desc = "PROM";
int node;
@@ -133,7 +131,7 @@ const char __init *promcon_startup(void)
return display_desc;
}
-static void __init
+static void
promcon_init_unimap(struct vc_data *conp)
{
mm_segment_t old_fs = get_fs();
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index 3957fc7523e..557c563e4ae 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -10,7 +10,6 @@
#include <linux/module.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index fd5940f4127..45586aaabd1 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -37,7 +37,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/vt_kern.h>
@@ -75,7 +74,7 @@ static inline void cursor_undrawn(void)
cursor_drawn = 0;
}
-static const char *__init sticon_startup(void)
+static const char *sticon_startup(void)
{
return "STI console";
}
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 74ac2acaf72..88e7038eab8 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -13,7 +13,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c
index 153352ca946..d981fe4d86c 100644
--- a/drivers/video/console/tileblit.c
+++ b/drivers/video/console/tileblit.c
@@ -8,7 +8,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index e64d42e2449..0a2c10a1abf 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -33,13 +33,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
-#include <linux/tty.h>
#include <linux/console.h>
#include <linux/string.h>
#include <linux/kd.h>
@@ -49,6 +47,7 @@
#include <linux/spinlock.h>
#include <linux/ioport.h>
#include <linux/init.h>
+#include <linux/screen_info.h>
#include <linux/smp_lock.h>
#include <video/vga.h>
#include <asm/io.h>
@@ -114,6 +113,7 @@ static int vga_512_chars;
static int vga_video_font_height;
static int vga_scan_lines;
static unsigned int vga_rolled_over = 0;
+static int vga_init_done;
static int __init no_scroll(char *str)
{
@@ -190,7 +190,7 @@ static void vgacon_scrollback_init(int pitch)
}
}
-static void __init vgacon_scrollback_startup(void)
+static void vgacon_scrollback_startup(void)
{
vgacon_scrollback = alloc_bootmem(CONFIG_VGACON_SOFT_SCROLLBACK_SIZE
* 1024);
@@ -355,7 +355,7 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines)
}
#endif /* CONFIG_VGACON_SOFT_SCROLLBACK */
-static const char __init *vgacon_startup(void)
+static const char *vgacon_startup(void)
{
const char *display_desc = NULL;
u16 saved1, saved2;
@@ -389,7 +389,7 @@ static const char __init *vgacon_startup(void)
vga_video_port_val = VGA_CRT_DM;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10) {
static struct resource ega_console_resource =
- { "ega", 0x3B0, 0x3BF };
+ { .name = "ega", .start = 0x3B0, .end = 0x3BF };
vga_video_type = VIDEO_TYPE_EGAM;
vga_vram_size = 0x8000;
display_desc = "EGA+";
@@ -397,9 +397,9 @@ static const char __init *vgacon_startup(void)
&ega_console_resource);
} else {
static struct resource mda1_console_resource =
- { "mda", 0x3B0, 0x3BB };
+ { .name = "mda", .start = 0x3B0, .end = 0x3BB };
static struct resource mda2_console_resource =
- { "mda", 0x3BF, 0x3BF };
+ { .name = "mda", .start = 0x3BF, .end = 0x3BF };
vga_video_type = VIDEO_TYPE_MDA;
vga_vram_size = 0x2000;
display_desc = "*MDA";
@@ -422,14 +422,14 @@ static const char __init *vgacon_startup(void)
if (!ORIG_VIDEO_ISVGA) {
static struct resource ega_console_resource
- = { "ega", 0x3C0, 0x3DF };
+ = { .name = "ega", .start = 0x3C0, .end = 0x3DF };
vga_video_type = VIDEO_TYPE_EGAC;
display_desc = "EGA";
request_resource(&ioport_resource,
&ega_console_resource);
} else {
static struct resource vga_console_resource
- = { "vga+", 0x3C0, 0x3DF };
+ = { .name = "vga+", .start = 0x3C0, .end = 0x3DF };
vga_video_type = VIDEO_TYPE_VGAC;
display_desc = "VGA+";
request_resource(&ioport_resource,
@@ -473,7 +473,7 @@ static const char __init *vgacon_startup(void)
}
} else {
static struct resource cga_console_resource =
- { "cga", 0x3D4, 0x3D5 };
+ { .name = "cga", .start = 0x3D4, .end = 0x3D5 };
vga_video_type = VIDEO_TYPE_CGA;
vga_vram_size = 0x2000;
display_desc = "*CGA";
@@ -523,7 +523,12 @@ static const char __init *vgacon_startup(void)
vgacon_xres = ORIG_VIDEO_COLS * VGA_FONTWIDTH;
vgacon_yres = vga_scan_lines;
- vgacon_scrollback_startup();
+
+ if (!vga_init_done) {
+ vgacon_scrollback_startup();
+ vga_init_done = 1;
+ }
+
return display_desc;
}
@@ -531,10 +536,20 @@ static void vgacon_init(struct vc_data *c, int init)
{
unsigned long p;
- /* We cannot be loaded as a module, therefore init is always 1 */
+ /*
+ * We cannot be loaded as a module, therefore init is always 1,
+ * but vgacon_init can be called more than once, and init will
+ * not be 1.
+ */
c->vc_can_do_color = vga_can_do_color;
- c->vc_cols = vga_video_num_columns;
- c->vc_rows = vga_video_num_lines;
+
+ /* set dimensions manually if init != 0 since vc_resize() will fail */
+ if (init) {
+ c->vc_cols = vga_video_num_columns;
+ c->vc_rows = vga_video_num_lines;
+ } else
+ vc_resize(c, vga_video_num_columns, vga_video_num_lines);
+
c->vc_scan_lines = vga_scan_lines;
c->vc_font.height = vga_video_font_height;
c->vc_complement_mask = 0x7700;
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 655301a8671..8cc6c0e2d27 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -31,13 +31,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index 55a3514157e..aae6d9c26e8 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -36,13 +36,11 @@
* (which, incidentally, is about the same saving as a 2.5in hard disk
* entering standby mode.)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/cyber2000fb.h b/drivers/video/cyber2000fb.h
index bd7e1c04078..de4fc43e51c 100644
--- a/drivers/video/cyber2000fb.h
+++ b/drivers/video/cyber2000fb.h
@@ -9,7 +9,6 @@
*
* Integraphics Cyber2000 frame buffer device
*/
-#include <linux/config.h>
/*
* Internal CyberPro sizes and offsets.
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
index a3e189f90a7..c40e72dafb0 100644
--- a/drivers/video/cyberfb.c
+++ b/drivers/video/cyberfb.c
@@ -81,7 +81,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/zorro.h>
diff --git a/drivers/video/cyblafb.c b/drivers/video/cyblafb.c
index 0ae0a97b0fe..94a66c2d2cf 100644
--- a/drivers/video/cyblafb.c
+++ b/drivers/video/cyblafb.c
@@ -14,7 +14,6 @@
#define CYBLAFB_PIXMAPSIZE 8192
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fb.h>
diff --git a/drivers/video/dnfb.c b/drivers/video/dnfb.c
index 5abd3cb0067..b083ea7e9c6 100644
--- a/drivers/video/dnfb.c
+++ b/drivers/video/dnfb.c
@@ -2,7 +2,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/epson1355fb.c b/drivers/video/epson1355fb.c
index 082759447bf..737257d278f 100644
--- a/drivers/video/epson1355fb.c
+++ b/drivers/video/epson1355fb.c
@@ -48,7 +48,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -605,11 +604,6 @@ static void clearfb16(struct fb_info *info)
fb_writeb(0, dst);
}
-static void epson1355fb_platform_release(struct device *device)
-{
- dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
-}
-
static int epson1355fb_remove(struct platform_device *dev)
{
struct fb_info *info = platform_get_drvdata(dev);
@@ -733,13 +727,7 @@ static struct platform_driver epson1355fb_driver = {
},
};
-static struct platform_device epson1355fb_device = {
- .name = "epson1355fb",
- .id = 0,
- .dev = {
- .release = epson1355fb_platform_release,
- }
-};
+static struct platform_device *epson1355fb_device;
int __init epson1355fb_init(void)
{
@@ -749,11 +737,21 @@ int __init epson1355fb_init(void)
return -ENODEV;
ret = platform_driver_register(&epson1355fb_driver);
+
if (!ret) {
- ret = platform_device_register(&epson1355fb_device);
- if (ret)
+ epson1355fb_device = platform_device_alloc("epson1355fb", 0);
+
+ if (epson1355fb_device)
+ ret = platform_device_add(epson1355fb_device);
+ else
+ ret = -ENOMEM;
+
+ if (ret) {
+ platform_device_put(epson1355fb_device);
platform_driver_unregister(&epson1355fb_driver);
+ }
}
+
return ret;
}
@@ -762,7 +760,7 @@ module_init(epson1355fb_init);
#ifdef MODULE
static void __exit epson1355fb_exit(void)
{
- platform_device_unregister(&epson1355fb_device);
+ platform_device_unregister(epson1355fb_device);
platform_driver_unregister(&epson1355fb_driver);
}
diff --git a/drivers/video/fb_notify.c b/drivers/video/fb_notify.c
new file mode 100644
index 00000000000..8c020389e4f
--- /dev/null
+++ b/drivers/video/fb_notify.c
@@ -0,0 +1,46 @@
+/*
+ * linux/drivers/video/fb_notify.c
+ *
+ * Copyright (C) 2006 Antonino Daplas <adaplas@pol.net>
+ *
+ * 2001 - Documented with DocBook
+ * - Brad Douglas <brad@neruo.com>
+ *
+ * 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/fb.h>
+#include <linux/notifier.h>
+
+static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
+
+/**
+ * fb_register_client - register a client notifier
+ * @nb: notifier block to callback on events
+ */
+int fb_register_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&fb_notifier_list, nb);
+}
+EXPORT_SYMBOL(fb_register_client);
+
+/**
+ * fb_unregister_client - unregister a client notifier
+ * @nb: notifier block to callback on events
+ */
+int fb_unregister_client(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
+}
+EXPORT_SYMBOL(fb_unregister_client);
+
+/**
+ * fb_notifier_call_chain - notify clients of fb_events
+ *
+ */
+int fb_notifier_call_chain(unsigned long val, void *v)
+{
+ return blocking_notifier_call_chain(&fb_notifier_list, val, v);
+}
+EXPORT_SYMBOL_GPL(fb_notifier_call_chain);
diff --git a/drivers/video/fbcmap.c b/drivers/video/fbcmap.c
index 1f98392a43b..e8b135f3d80 100644
--- a/drivers/video/fbcmap.c
+++ b/drivers/video/fbcmap.c
@@ -13,7 +13,6 @@
#include <linux/string.h>
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/slab.h>
diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c
index ac90883dc3a..b5498999c4e 100644
--- a/drivers/video/fbcvt.c
+++ b/drivers/video/fbcvt.c
@@ -376,4 +376,3 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb)
return 0;
}
-EXPORT_SYMBOL(fb_find_mode_cvt);
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 372aa177682..17961e3ecaa 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -11,7 +11,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/compat.h>
@@ -24,7 +23,7 @@
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/mman.h>
-#include <linux/tty.h>
+#include <linux/vt.h>
#include <linux/init.h>
#include <linux/linux_logo.h>
#include <linux/proc_fs.h>
@@ -32,9 +31,7 @@
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
-#include <linux/devfs_fs_kernel.h>
#include <linux/err.h>
-#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/efi.h>
@@ -55,7 +52,6 @@
#define FBPIXMAPSIZE (1024 * 8)
-static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);
struct fb_info *registered_fb[FB_MAX];
int num_registered_fb;
@@ -162,7 +158,6 @@ char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size
}
#ifdef CONFIG_LOGO
-#include <linux/linux_logo.h>
static inline unsigned safe_shift(unsigned d, int n)
{
@@ -336,11 +331,11 @@ static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height)
static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height)
{
- int i, j, w = width - 1;
+ int i, j, h = height - 1;
for (i = 0; i < height; i++)
for (j = 0; j < width; j++)
- out[height * j + w - i] = *in++;
+ out[height * j + h - i] = *in++;
}
static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height)
@@ -358,24 +353,24 @@ static void fb_rotate_logo(struct fb_info *info, u8 *dst,
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);
+ image->dx = info->var.xres - image->width;
+ image->dy = info->var.yres - 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;
+ image->dx = info->var.xres - image->width;
+ } else if (rotate == FB_ROTATE_CCW) {
fb_rotate_logo_ccw(image->data, dst, image->width,
image->height);
+ tmp = image->width;
+ image->width = image->height;
+ image->height = tmp;
+ image->dy = info->var.yres - image->height;
}
image->data = dst;
@@ -435,7 +430,7 @@ int fb_prepare_logo(struct fb_info *info, int rotate)
depth = info->var.green.length;
}
- if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR) {
+ if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) {
/* assume console colormap */
depth = 4;
}
@@ -795,8 +790,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
event.info = info;
event.data = &mode1;
- ret = blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_MODE_DELETE, &event);
+ ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
}
if (!ret)
@@ -841,8 +835,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
info->flags &= ~FBINFO_MISC_USEREVENT;
event.info = info;
- blocking_notifier_call_chain(&fb_notifier_list,
- evnt, &event);
+ fb_notifier_call_chain(evnt, &event);
}
}
}
@@ -865,8 +858,7 @@ fb_blank(struct fb_info *info, int blank)
event.info = info;
event.data = &blank;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_BLANK, &event);
+ fb_notifier_call_chain(FB_EVENT_BLANK, &event);
}
return ret;
@@ -937,8 +929,7 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
con2fb.framebuffer = -1;
event.info = info;
event.data = &con2fb;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_GET_CONSOLE_MAP, &event);
+ fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
return copy_to_user(argp, &con2fb,
sizeof(con2fb)) ? -EFAULT : 0;
case FBIOPUT_CON2FBMAP:
@@ -956,9 +947,8 @@ fb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
return -EINVAL;
event.info = info;
event.data = &con2fb;
- return blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_SET_CONSOLE_MAP,
- &event);
+ return fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP,
+ &event);
case FBIOBLANK:
acquire_console_sem();
info->flags |= FBINFO_MISC_USEREVENT;
@@ -1278,8 +1268,8 @@ static struct file_operations fb_fops = {
#endif
};
-static struct class *fb_class;
-
+struct class *fb_class;
+EXPORT_SYMBOL(fb_class);
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
@@ -1333,11 +1323,8 @@ register_framebuffer(struct fb_info *fb_info)
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info;
- devfs_mk_cdev(MKDEV(FB_MAJOR, i),
- S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
event.info = fb_info;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_FB_REGISTERED, &event);
+ fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
return 0;
}
@@ -1355,42 +1342,27 @@ register_framebuffer(struct fb_info *fb_info)
int
unregister_framebuffer(struct fb_info *fb_info)
{
+ struct fb_event event;
int i;
i = fb_info->node;
if (!registered_fb[i])
return -EINVAL;
- devfs_remove("fb/%d", i);
- if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
+ if (fb_info->pixmap.addr &&
+ (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT))
kfree(fb_info->pixmap.addr);
fb_destroy_modelist(&fb_info->modelist);
registered_fb[i]=NULL;
num_registered_fb--;
fb_cleanup_class_device(fb_info);
class_device_destroy(fb_class, MKDEV(FB_MAJOR, i));
+ event.info = fb_info;
+ fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
return 0;
}
/**
- * fb_register_client - register a client notifier
- * @nb: notifier block to callback on events
- */
-int fb_register_client(struct notifier_block *nb)
-{
- return blocking_notifier_chain_register(&fb_notifier_list, nb);
-}
-
-/**
- * fb_unregister_client - unregister a client notifier
- * @nb: notifier block to callback on events
- */
-int fb_unregister_client(struct notifier_block *nb)
-{
- return blocking_notifier_chain_unregister(&fb_notifier_list, nb);
-}
-
-/**
* fb_set_suspend - low level driver signals suspend
* @info: framebuffer affected
* @state: 0 = resuming, !=0 = suspending
@@ -1405,13 +1377,11 @@ void fb_set_suspend(struct fb_info *info, int state)
event.info = info;
if (state) {
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_SUSPEND, &event);
+ fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
info->state = FBINFO_STATE_SUSPENDED;
} else {
info->state = FBINFO_STATE_RUNNING;
- blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_RESUME, &event);
+ fb_notifier_call_chain(FB_EVENT_RESUME, &event);
}
}
@@ -1429,7 +1399,6 @@ fbmem_init(void)
{
create_proc_read_entry("fb", 0, NULL, fbmem_read_proc, NULL);
- devfs_mk_dir("fb");
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
@@ -1483,36 +1452,12 @@ int fb_new_modelist(struct fb_info *info)
if (!list_empty(&info->modelist)) {
event.info = info;
- err = blocking_notifier_call_chain(&fb_notifier_list,
- FB_EVENT_NEW_MODELIST,
- &event);
+ err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
}
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 blocking_notifier_call_chain(&fb_notifier_list, event, &evnt);
-}
-EXPORT_SYMBOL(fb_con_duit);
-
static char *video_options[FB_MAX];
static int ofonly;
@@ -1619,9 +1564,6 @@ EXPORT_SYMBOL(fb_blank);
EXPORT_SYMBOL(fb_pan_display);
EXPORT_SYMBOL(fb_get_buffer_offset);
EXPORT_SYMBOL(fb_set_suspend);
-EXPORT_SYMBOL(fb_register_client);
-EXPORT_SYMBOL(fb_unregister_client);
EXPORT_SYMBOL(fb_get_options);
-EXPORT_SYMBOL(fb_new_modelist);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 53beeb4a999..de93139ccbb 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -26,12 +26,11 @@
* for more details.
*
*/
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <video/edid.h>
#ifdef CONFIG_PPC_OF
-#include <linux/pci.h>
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#endif
@@ -605,6 +604,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
DPRINTK(" Monitor Operating Limits: ");
+
for (i = 0; i < 4; i++, block += DETAILED_TIMING_DESCRIPTION_SIZE) {
if (edid_is_limits_block(block)) {
specs->hfmin = H_MIN_RATE * 1000;
@@ -618,11 +618,12 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
break;
}
}
-
+
/* estimate monitor limits based on modes supported */
if (retval) {
- struct fb_videomode *modes;
+ struct fb_videomode *modes, *mode;
int num_modes, i, hz, hscan, pixclock;
+ int vtotal, htotal;
modes = fb_create_modedb(edid, &num_modes);
if (!modes) {
@@ -632,20 +633,38 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
retval = 0;
for (i = 0; i < num_modes; i++) {
- hz = modes[i].refresh;
+ mode = &modes[i];
pixclock = PICOS2KHZ(modes[i].pixclock) * 1000;
- hscan = (modes[i].yres * 105 * hz + 5000)/100;
+ htotal = mode->xres + mode->right_margin + mode->hsync_len
+ + mode->left_margin;
+ vtotal = mode->yres + mode->lower_margin + mode->vsync_len
+ + mode->upper_margin;
+
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ vtotal /= 2;
+
+ if (mode->vmode & FB_VMODE_DOUBLE)
+ vtotal *= 2;
+
+ hscan = (pixclock + htotal / 2) / htotal;
+ hscan = (hscan + 500) / 1000 * 1000;
+ hz = (hscan + vtotal / 2) / vtotal;
if (specs->dclkmax == 0 || specs->dclkmax < pixclock)
specs->dclkmax = pixclock;
+
if (specs->dclkmin == 0 || specs->dclkmin > pixclock)
specs->dclkmin = pixclock;
+
if (specs->hfmax == 0 || specs->hfmax < hscan)
specs->hfmax = hscan;
+
if (specs->hfmin == 0 || specs->hfmin > hscan)
specs->hfmin = hscan;
+
if (specs->vfmax == 0 || specs->vfmax < hz)
specs->vfmax = hz;
+
if (specs->vfmin == 0 || specs->vfmin > hz)
specs->vfmin = hz;
}
@@ -1281,8 +1300,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info)
-EINVAL : 0;
}
-#if defined(CONFIG_FB_FIRMWARE_EDID) && defined(__i386__)
-#include <linux/pci.h>
+#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
/*
* We need to ensure that the EDID block is only returned for
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 34e07399756..c151dcf6878 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/fb.h>
#include <linux/console.h>
+#include <linux/module.h>
/**
* framebuffer_alloc - creates a new frame buffer info structure
@@ -55,6 +56,10 @@ struct fb_info *framebuffer_alloc(size_t size, struct device *dev)
info->device = dev;
+#ifdef CONFIG_FB_BACKLIGHT
+ mutex_init(&info->bl_mutex);
+#endif
+
return info;
#undef PADDING
#undef BYTES_PER_LONG
@@ -95,13 +100,22 @@ static int mode_string(char *buf, unsigned int offset,
const struct fb_videomode *mode)
{
char m = 'U';
+ char v = 'p';
+
if (mode->flag & FB_MODE_IS_DETAILED)
m = 'D';
if (mode->flag & FB_MODE_IS_VESA)
m = 'V';
if (mode->flag & FB_MODE_IS_STANDARD)
m = 'S';
- return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d-%d\n", m, mode->xres, mode->yres, mode->refresh);
+
+ if (mode->vmode & FB_VMODE_INTERLACED)
+ v = 'i';
+ if (mode->vmode & FB_VMODE_DOUBLE)
+ v = 'd';
+
+ return snprintf(&buf[offset], PAGE_SIZE - offset, "%c:%dx%d%c-%d\n",
+ m, mode->xres, mode->yres, v, mode->refresh);
}
static ssize_t store_mode(struct class_device *class_device, const char * buf,
@@ -233,45 +247,6 @@ static ssize_t show_rotate(struct class_device *class_device, char *buf)
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)
{
@@ -414,6 +389,77 @@ static ssize_t show_fbstate(struct class_device *class_device, char *buf)
return snprintf(buf, PAGE_SIZE, "%d\n", fb_info->state);
}
+#ifdef CONFIG_FB_BACKLIGHT
+static ssize_t store_bl_curve(struct class_device *class_device,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ u8 tmp_curve[FB_BACKLIGHT_LEVELS];
+ unsigned int i;
+
+ /* Some drivers don't use framebuffer_alloc(), but those also
+ * don't have backlights.
+ */
+ if (!fb_info || !fb_info->bl_dev)
+ return -ENODEV;
+
+ if (count != (FB_BACKLIGHT_LEVELS / 8 * 24))
+ return -EINVAL;
+
+ for (i = 0; i < (FB_BACKLIGHT_LEVELS / 8); ++i)
+ if (sscanf(&buf[i * 24],
+ "%2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx %2hhx\n",
+ &tmp_curve[i * 8 + 0],
+ &tmp_curve[i * 8 + 1],
+ &tmp_curve[i * 8 + 2],
+ &tmp_curve[i * 8 + 3],
+ &tmp_curve[i * 8 + 4],
+ &tmp_curve[i * 8 + 5],
+ &tmp_curve[i * 8 + 6],
+ &tmp_curve[i * 8 + 7]) != 8)
+ return -EINVAL;
+
+ /* If there has been an error in the input data, we won't
+ * reach this loop.
+ */
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; ++i)
+ fb_info->bl_curve[i] = tmp_curve[i];
+ mutex_unlock(&fb_info->bl_mutex);
+
+ return count;
+}
+
+static ssize_t show_bl_curve(struct class_device *class_device, char *buf)
+{
+ struct fb_info *fb_info = class_get_devdata(class_device);
+ ssize_t len = 0;
+ unsigned int i;
+
+ /* Some drivers don't use framebuffer_alloc(), but those also
+ * don't have backlights.
+ */
+ if (!fb_info || !fb_info->bl_dev)
+ return -ENODEV;
+
+ mutex_lock(&fb_info->bl_mutex);
+ for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8)
+ len += snprintf(&buf[len], PAGE_SIZE,
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ fb_info->bl_curve[i + 0],
+ fb_info->bl_curve[i + 1],
+ fb_info->bl_curve[i + 2],
+ fb_info->bl_curve[i + 3],
+ fb_info->bl_curve[i + 4],
+ fb_info->bl_curve[i + 5],
+ fb_info->bl_curve[i + 6],
+ fb_info->bl_curve[i + 7]);
+ mutex_unlock(&fb_info->bl_mutex);
+
+ return len;
+}
+#endif
+
/* When cmap is added back in it should be a binary attribute
* not a text one. Consideration should also be given to converting
* fbdev to use configfs instead of sysfs */
@@ -429,9 +475,10 @@ static struct class_device_attribute class_device_attrs[] = {
__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),
__ATTR(state, S_IRUGO|S_IWUSR, show_fbstate, store_fbstate),
+#ifdef CONFIG_FB_BACKLIGHT
+ __ATTR(bl_curve, S_IRUGO|S_IWUSR, show_bl_curve, store_bl_curve),
+#endif
};
int fb_init_class_device(struct fb_info *fb_info)
@@ -454,4 +501,25 @@ void fb_cleanup_class_device(struct fb_info *fb_info)
&class_device_attrs[i]);
}
+#ifdef CONFIG_FB_BACKLIGHT
+/* This function generates a linear backlight curve
+ *
+ * 0: off
+ * 1-7: min
+ * 8-127: linear from min to max
+ */
+void fb_bl_default_curve(struct fb_info *fb_info, u8 off, u8 min, u8 max)
+{
+ unsigned int i, flat, count, range = (max - min);
+ fb_info->bl_curve[0] = off;
+
+ for (flat = 1; flat < (FB_BACKLIGHT_LEVELS / 16); ++flat)
+ fb_info->bl_curve[flat] = min;
+
+ count = FB_BACKLIGHT_LEVELS * 15 / 16;
+ for (i = 0; i < count; ++i)
+ fb_info->bl_curve[flat + i] = min + (range * (i + 1) / count);
+}
+EXPORT_SYMBOL_GPL(fb_bl_default_curve);
+#endif
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 7633e41adda..2a0e8210d39 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -1,6 +1,6 @@
/* ffb.c: Creator/Elite3D frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
*
* Driver layout based loosely on tgafb.c, see that file for credits.
@@ -19,7 +19,8 @@
#include <asm/io.h>
#include <asm/upa.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -184,161 +185,161 @@ static struct fb_ops ffb_ops = {
struct ffb_fbc {
/* Next vertex registers */
- u32 xxx1[3];
- volatile u32 alpha;
- volatile u32 red;
- volatile u32 green;
- volatile u32 blue;
- volatile u32 depth;
- volatile u32 y;
- volatile u32 x;
- u32 xxx2[2];
- volatile u32 ryf;
- volatile u32 rxf;
- u32 xxx3[2];
+ u32 xxx1[3];
+ u32 alpha;
+ u32 red;
+ u32 green;
+ u32 blue;
+ u32 depth;
+ u32 y;
+ u32 x;
+ u32 xxx2[2];
+ u32 ryf;
+ u32 rxf;
+ u32 xxx3[2];
- volatile u32 dmyf;
- volatile u32 dmxf;
- u32 xxx4[2];
- volatile u32 ebyi;
- volatile u32 ebxi;
- u32 xxx5[2];
- volatile u32 by;
- volatile u32 bx;
- u32 dy;
- u32 dx;
- volatile u32 bh;
- volatile u32 bw;
- u32 xxx6[2];
+ u32 dmyf;
+ u32 dmxf;
+ u32 xxx4[2];
+ u32 ebyi;
+ u32 ebxi;
+ u32 xxx5[2];
+ u32 by;
+ u32 bx;
+ u32 dy;
+ u32 dx;
+ u32 bh;
+ u32 bw;
+ u32 xxx6[2];
- u32 xxx7[32];
+ u32 xxx7[32];
/* Setup unit vertex state register */
- volatile u32 suvtx;
- u32 xxx8[63];
+ u32 suvtx;
+ u32 xxx8[63];
/* Control registers */
- volatile u32 ppc;
- volatile u32 wid;
- volatile u32 fg;
- volatile u32 bg;
- volatile u32 consty;
- volatile u32 constz;
- volatile u32 xclip;
- volatile u32 dcss;
- volatile u32 vclipmin;
- volatile u32 vclipmax;
- volatile u32 vclipzmin;
- volatile u32 vclipzmax;
- volatile u32 dcsf;
- volatile u32 dcsb;
- volatile u32 dczf;
- volatile u32 dczb;
+ u32 ppc;
+ u32 wid;
+ u32 fg;
+ u32 bg;
+ u32 consty;
+ u32 constz;
+ u32 xclip;
+ u32 dcss;
+ u32 vclipmin;
+ u32 vclipmax;
+ u32 vclipzmin;
+ u32 vclipzmax;
+ u32 dcsf;
+ u32 dcsb;
+ u32 dczf;
+ u32 dczb;
- u32 xxx9;
- volatile u32 blendc;
- volatile u32 blendc1;
- volatile u32 blendc2;
- volatile u32 fbramitc;
- volatile u32 fbc;
- volatile u32 rop;
- volatile u32 cmp;
- volatile u32 matchab;
- volatile u32 matchc;
- volatile u32 magnab;
- volatile u32 magnc;
- volatile u32 fbcfg0;
- volatile u32 fbcfg1;
- volatile u32 fbcfg2;
- volatile u32 fbcfg3;
+ u32 xxx9;
+ u32 blendc;
+ u32 blendc1;
+ u32 blendc2;
+ u32 fbramitc;
+ u32 fbc;
+ u32 rop;
+ u32 cmp;
+ u32 matchab;
+ u32 matchc;
+ u32 magnab;
+ u32 magnc;
+ u32 fbcfg0;
+ u32 fbcfg1;
+ u32 fbcfg2;
+ u32 fbcfg3;
- u32 ppcfg;
- volatile u32 pick;
- volatile u32 fillmode;
- volatile u32 fbramwac;
- volatile u32 pmask;
- volatile u32 xpmask;
- volatile u32 ypmask;
- volatile u32 zpmask;
- volatile u32 clip0min;
- volatile u32 clip0max;
- volatile u32 clip1min;
- volatile u32 clip1max;
- volatile u32 clip2min;
- volatile u32 clip2max;
- volatile u32 clip3min;
- volatile u32 clip3max;
+ u32 ppcfg;
+ u32 pick;
+ u32 fillmode;
+ u32 fbramwac;
+ u32 pmask;
+ u32 xpmask;
+ u32 ypmask;
+ u32 zpmask;
+ u32 clip0min;
+ u32 clip0max;
+ u32 clip1min;
+ u32 clip1max;
+ u32 clip2min;
+ u32 clip2max;
+ u32 clip3min;
+ u32 clip3max;
/* New 3dRAM III support regs */
- volatile u32 rawblend2;
- volatile u32 rawpreblend;
- volatile u32 rawstencil;
- volatile u32 rawstencilctl;
- volatile u32 threedram1;
- volatile u32 threedram2;
- volatile u32 passin;
- volatile u32 rawclrdepth;
- volatile u32 rawpmask;
- volatile u32 rawcsrc;
- volatile u32 rawmatch;
- volatile u32 rawmagn;
- volatile u32 rawropblend;
- volatile u32 rawcmp;
- volatile u32 rawwac;
- volatile u32 fbramid;
+ u32 rawblend2;
+ u32 rawpreblend;
+ u32 rawstencil;
+ u32 rawstencilctl;
+ u32 threedram1;
+ u32 threedram2;
+ u32 passin;
+ u32 rawclrdepth;
+ u32 rawpmask;
+ u32 rawcsrc;
+ u32 rawmatch;
+ u32 rawmagn;
+ u32 rawropblend;
+ u32 rawcmp;
+ u32 rawwac;
+ u32 fbramid;
- volatile u32 drawop;
- u32 xxx10[2];
- volatile u32 fontlpat;
- u32 xxx11;
- volatile u32 fontxy;
- volatile u32 fontw;
- volatile u32 fontinc;
- volatile u32 font;
- u32 xxx12[3];
- volatile u32 blend2;
- volatile u32 preblend;
- volatile u32 stencil;
- volatile u32 stencilctl;
-
- u32 xxx13[4];
- volatile u32 dcss1;
- volatile u32 dcss2;
- volatile u32 dcss3;
- volatile u32 widpmask;
- volatile u32 dcs2;
- volatile u32 dcs3;
- volatile u32 dcs4;
- u32 xxx14;
- volatile u32 dcd2;
- volatile u32 dcd3;
- volatile u32 dcd4;
- u32 xxx15;
+ u32 drawop;
+ u32 xxx10[2];
+ u32 fontlpat;
+ u32 xxx11;
+ u32 fontxy;
+ u32 fontw;
+ u32 fontinc;
+ u32 font;
+ u32 xxx12[3];
+ u32 blend2;
+ u32 preblend;
+ u32 stencil;
+ u32 stencilctl;
+
+ u32 xxx13[4];
+ u32 dcss1;
+ u32 dcss2;
+ u32 dcss3;
+ u32 widpmask;
+ u32 dcs2;
+ u32 dcs3;
+ u32 dcs4;
+ u32 xxx14;
+ u32 dcd2;
+ u32 dcd3;
+ u32 dcd4;
+ u32 xxx15;
- volatile u32 pattern[32];
+ u32 pattern[32];
- u32 xxx16[256];
+ u32 xxx16[256];
- volatile u32 devid;
- u32 xxx17[63];
+ u32 devid;
+ u32 xxx17[63];
- volatile u32 ucsr;
- u32 xxx18[31];
+ u32 ucsr;
+ u32 xxx18[31];
- volatile u32 mer;
+ u32 mer;
};
struct ffb_dac {
- volatile u32 type;
- volatile u32 value;
- volatile u32 type2;
- volatile u32 value2;
+ u32 type;
+ u32 value;
+ u32 type2;
+ u32 value2;
};
struct ffb_par {
spinlock_t lock;
- struct ffb_fbc *fbc;
- struct ffb_dac *dac;
+ struct ffb_fbc __iomem *fbc;
+ struct ffb_dac __iomem *dac;
u32 flags;
#define FFB_FLAG_AFB 0x00000001
@@ -353,16 +354,13 @@ struct ffb_par {
unsigned long physbase;
unsigned long fbsize;
- char name[64];
- int prom_node;
- int prom_parent_node;
int dac_rev;
int board_type;
};
static void FFBFifo(struct ffb_par *par, int n)
{
- struct ffb_fbc *fbc;
+ struct ffb_fbc __iomem *fbc;
int cache = par->fifo_cache;
if (cache - n < 0) {
@@ -375,7 +373,7 @@ static void FFBFifo(struct ffb_par *par, int n)
static void FFBWait(struct ffb_par *par)
{
- struct ffb_fbc *fbc;
+ struct ffb_fbc __iomem *fbc;
int limit = 10000;
fbc = par->fbc;
@@ -408,8 +406,8 @@ static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
static void ffb_switch_from_graph(struct ffb_par *par)
{
- struct ffb_fbc *fbc = par->fbc;
- struct ffb_dac *dac = par->dac;
+ struct ffb_fbc __iomem *fbc = par->fbc;
+ struct ffb_dac __iomem *dac = par->dac;
unsigned long flags;
spin_lock_irqsave(&par->lock, flags);
@@ -462,7 +460,7 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
{
struct ffb_par *par = (struct ffb_par *) info->par;
- struct ffb_fbc *fbc = par->fbc;
+ struct ffb_fbc __iomem *fbc = par->fbc;
unsigned long flags;
u32 fg;
@@ -505,7 +503,7 @@ static void
ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
{
struct ffb_par *par = (struct ffb_par *) info->par;
- struct ffb_fbc *fbc = par->fbc;
+ struct ffb_fbc __iomem *fbc = par->fbc;
unsigned long flags;
if (area->dx != area->sx ||
@@ -541,7 +539,7 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct ffb_par *par = (struct ffb_par *) info->par;
- struct ffb_fbc *fbc = par->fbc;
+ struct ffb_fbc __iomem *fbc = par->fbc;
const u8 *data = image->data;
unsigned long flags;
u32 fg, bg, xy;
@@ -664,7 +662,7 @@ static int
ffb_blank(int blank, struct fb_info *info)
{
struct ffb_par *par = (struct ffb_par *) info->par;
- struct ffb_dac *dac = par->dac;
+ struct ffb_dac __iomem *dac = par->dac;
unsigned long flags;
u32 tmp;
@@ -883,78 +881,42 @@ ffb_init_fix(struct fb_info *info)
info->fix.accel = FB_ACCEL_SUN_CREATOR;
}
-static int ffb_apply_upa_parent_ranges(int parent,
- struct linux_prom64_registers *regs)
-{
- struct linux_prom64_ranges ranges[PROMREG_MAX];
- char name[128];
- int len, i;
-
- prom_getproperty(parent, "name", name, sizeof(name));
- if (strcmp(name, "upa") != 0)
- return 0;
-
- len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
- if (len <= 0)
- return 1;
-
- len /= sizeof(struct linux_prom64_ranges);
- for (i = 0; i < len; i++) {
- struct linux_prom64_ranges *rng = &ranges[i];
- u64 phys_addr = regs->phys_addr;
-
- if (phys_addr >= rng->ot_child_base &&
- phys_addr < (rng->ot_child_base + rng->or_size)) {
- regs->phys_addr -= rng->ot_child_base;
- regs->phys_addr += rng->ot_parent_base;
- return 0;
- }
- }
-
- return 1;
-}
-
struct all_info {
struct fb_info info;
struct ffb_par par;
u32 pseudo_palette[256];
- struct list_head list;
};
-static LIST_HEAD(ffb_list);
-static void ffb_init_one(int node, int parent)
+static int ffb_init_one(struct of_device *op)
{
- struct linux_prom64_registers regs[2*PROMREG_MAX];
- struct ffb_fbc *fbc;
- struct ffb_dac *dac;
+ struct device_node *dp = op->node;
+ struct ffb_fbc __iomem *fbc;
+ struct ffb_dac __iomem *dac;
struct all_info *all;
+ int err;
- if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) {
- printk("ffb: Cannot get reg device node property.\n");
- return;
- }
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
- if (ffb_apply_upa_parent_ranges(parent, &regs[0])) {
- printk("ffb: Cannot apply parent ranges to regs.\n");
- return;
+ spin_lock_init(&all->par.lock);
+ all->par.fbc = of_ioremap(&op->resource[2], 0,
+ sizeof(struct ffb_fbc), "ffb fbc");
+ if (!all->par.fbc) {
+ kfree(all);
+ return -ENOMEM;
}
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "ffb: Cannot allocate memory.\n");
- return;
+ all->par.dac = of_ioremap(&op->resource[1], 0,
+ sizeof(struct ffb_dac), "ffb dac");
+ if (!all->par.dac) {
+ of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
+ kfree(all);
+ return -ENOMEM;
}
- memset(all, 0, sizeof(*all));
-
- INIT_LIST_HEAD(&all->list);
- spin_lock_init(&all->par.lock);
- all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
- all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
all->par.rop_cache = FFB_ROP_NEW;
- all->par.physbase = regs[0].phys_addr;
- all->par.prom_node = node;
- all->par.prom_parent_node = parent;
+ all->par.physbase = op->resource[0].start;
/* Don't mention copyarea, so SCROLL_REDRAW is always
* used. It is the fastest on this chip.
@@ -968,7 +930,7 @@ static void ffb_init_one(int node, int parent)
all->info.par = &all->par;
all->info.pseudo_palette = all->pseudo_palette;
- sbusfb_fill_var(&all->info.var, all->par.prom_node, 32);
+ sbusfb_fill_var(&all->info.var, dp->node, 32);
all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
all->info.var.yres *
4);
@@ -976,14 +938,13 @@ static void ffb_init_one(int node, int parent)
all->info.var.accel_flags = FB_ACCELF_TEXT;
- prom_getstring(node, "name", all->par.name, sizeof(all->par.name));
- if (!strcmp(all->par.name, "SUNW,afb"))
+ if (!strcmp(dp->name, "SUNW,afb"))
all->par.flags |= FFB_FLAG_AFB;
- all->par.board_type = prom_getintdefault(node, "board_type", 0);
+ all->par.board_type = of_getintprop_default(dp, "board_type", 0);
fbc = all->par.fbc;
- if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
+ if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
ffb_switch_from_graph(&all->par);
@@ -1008,81 +969,88 @@ static void ffb_init_one(int node, int parent)
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
printk(KERN_ERR "ffb: Could not allocate color map.\n");
kfree(all);
- return;
+ return -ENOMEM;
}
ffb_init_fix(&all->info);
- if (register_framebuffer(&all->info) < 0) {
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
printk(KERN_ERR "ffb: Could not register framebuffer.\n");
fb_dealloc_cmap(&all->info.cmap);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &ffb_list);
+ dev_set_drvdata(&op->dev, all);
- printk("ffb: %s at %016lx type %d DAC %d\n",
+ printk("%s: %s at %016lx, type %d, DAC revision %d\n",
+ dp->full_name,
((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
- regs[0].phys_addr, all->par.board_type, all->par.dac_rev);
+ all->par.physbase, all->par.board_type, all->par.dac_rev);
+
+ return 0;
}
-static void ffb_scan_siblings(int root)
+static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match)
{
- int node, child;
-
- child = prom_getchild(root);
- for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
- node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
- ffb_init_one(node, root);
- for (node = prom_searchsiblings(child, "SUNW,afb"); node;
- node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
- ffb_init_one(node, root);
+ struct of_device *op = to_of_device(&dev->dev);
+
+ return ffb_init_one(op);
}
-int __init ffb_init(void)
+static int __devexit ffb_remove(struct of_device *dev)
{
- int root;
+ struct all_info *all = dev_get_drvdata(&dev->dev);
- if (fb_get_options("ffb", NULL))
- return -ENODEV;
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
- ffb_scan_siblings(prom_root_node);
+ of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
+ of_iounmap(all->par.dac, sizeof(struct ffb_dac));
- root = prom_getchild(prom_root_node);
- for (root = prom_searchsiblings(root, "upa"); root;
- root = prom_searchsiblings(prom_getsibling(root), "upa"))
- ffb_scan_siblings(root);
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit ffb_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id ffb_match[] = {
+ {
+ .name = "SUNW,ffb",
+ },
+ {
+ .name = "SUNW,afb",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ffb_match);
+
+static struct of_platform_driver ffb_driver = {
+ .name = "ffb",
+ .match_table = ffb_match,
+ .probe = ffb_probe,
+ .remove = __devexit_p(ffb_remove),
+};
- list_for_each_safe(pos, tmp, &ffb_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+int __init ffb_init(void)
+{
+ if (fb_get_options("ffb", NULL))
+ return -ENODEV;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+ return of_register_driver(&ffb_driver, &of_bus_type);
}
-int __init
-ffb_setup(char *arg)
+void __exit ffb_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&ffb_driver);
}
module_init(ffb_init);
-
-#ifdef MODULE
module_exit(ffb_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/g364fb.c b/drivers/video/g364fb.c
index 605d1a13202..1b981b63567 100644
--- a/drivers/video/g364fb.c
+++ b/drivers/video/g364fb.c
@@ -21,7 +21,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 5e25b986019..bf0e60b5a3b 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -9,7 +9,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/video/geode/gx1fb_core.c b/drivers/video/geode/gx1fb_core.c
index 20e69156d72..bcf9cea54d8 100644
--- a/drivers/video/geode/gx1fb_core.c
+++ b/drivers/video/geode/gx1fb_core.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -376,8 +375,6 @@ static int __init gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *
release_mem_region(gx1_gx_base() + 0x8300, 0x100);
}
- pci_disable_device(pdev);
-
if (info)
framebuffer_release(info);
return ret;
@@ -399,7 +396,6 @@ static void gx1fb_remove(struct pci_dev *pdev)
iounmap(par->dc_regs);
release_mem_region(gx1_gx_base() + 0x8300, 0x100);
- pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
framebuffer_release(info);
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 89c34b15f5d..0d3643fc629 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -25,7 +25,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -354,8 +353,6 @@ static int __init gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *i
pci_release_region(pdev, 2);
}
- pci_disable_device(pdev);
-
if (info)
framebuffer_release(info);
return ret;
@@ -377,7 +374,6 @@ static void gxfb_remove(struct pci_dev *pdev)
iounmap(par->dc_regs);
pci_release_region(pdev, 2);
- pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
framebuffer_release(info);
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index 4e39035cf33..fb9e6722854 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -36,7 +36,6 @@
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index f04ca721f94..3afb472763c 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -4,36 +4,32 @@
* (C) 1999 Mihai Spatar
* (C) 2000 YAEGASHI Takeshi
* (C) 2003, 2004 Paul Mundt
- * (C) 2003, 2004 Andriy Skulysh
+ * (C) 2003, 2004, 2006 Andriy Skulysh
*
* 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/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/fb.h>
#include <asm/machvec.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/hd64461/hd64461.h>
-
-#ifdef MACH_HP600
+#include <asm/hd64461.h>
#include <asm/cpu/dac.h>
#include <asm/hp6xx/hp6xx.h>
-#endif
#define WIDTH 640
@@ -47,7 +43,6 @@ static struct fb_var_screeninfo hitfb_var __initdata = {
static struct fb_fix_screeninfo hitfb_fix __initdata = {
.id = "Hitachi HD64461",
.type = FB_TYPE_PACKED_PIXELS,
- .ypanstep = 8,
.accel = FB_ACCEL_NONE,
};
@@ -75,26 +70,14 @@ static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy,
if (truecolor)
saddr <<= 1;
- fb_writew(width, HD64461_BBTDWR);
- fb_writew(height, HD64461_BBTDHR);
+ fb_writew(width-1, HD64461_BBTDWR);
+ fb_writew(height-1, HD64461_BBTDHR);
fb_writew(saddr & 0xffff, HD64461_BBTDSARL);
fb_writew(saddr >> 16, HD64461_BBTDSARH);
}
-static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy,
- u16 width, u16 height, u16 color)
-{
- hitfb_accel_set_dest(truecolor, dx, dy, width, height);
-
- fb_writew(0x00f0, HD64461_BBTROPR);
- fb_writew(16, HD64461_BBTMDR);
- fb_writew(color, HD64461_GRSCR);
-
- hitfb_accel_start(truecolor);
-}
-
static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
u16 dy, u16 width, u16 height, u16 rop,
u32 mask_addr)
@@ -102,6 +85,8 @@ static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
u32 saddr, daddr;
u32 maddr = 0;
+ height--;
+ width--;
fb_writew(rop, HD64461_BBTROPR);
if ((sy < dy) || ((sy == dy) && (sx <= dx))) {
saddr = WIDTH * (sy + height) + sx + width;
@@ -148,6 +133,7 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
if (rect->rop != ROP_COPY)
cfb_fillrect(p, rect);
else {
+ hitfb_accel_wait();
fb_writew(0x00f0, HD64461_BBTROPR);
fb_writew(16, HD64461_BBTMDR);
@@ -163,16 +149,15 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
rect->height);
hitfb_accel_start(0);
}
- hitfb_accel_wait();
}
}
static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
+ hitfb_accel_wait();
hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy,
area->dx, area->dy, area->width, area->height,
0x00cc, 0);
- hitfb_accel_wait();
}
static int hitfb_pan_display(struct fb_var_screeninfo *var,
@@ -184,7 +169,7 @@ static int hitfb_pan_display(struct fb_var_screeninfo *var,
if (xoffset != 0)
return -EINVAL;
- fb_writew(yoffset, HD64461_LCDCBAR);
+ fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR);
return 0;
}
@@ -194,12 +179,6 @@ int hitfb_blank(int blank_mode, struct fb_info *info)
unsigned short v;
if (blank_mode) {
-#ifdef MACH_HP600
- sh_dac_disable(DAC_LCD_BRIGHTNESS);
- v = fb_readw(HD64461_GPBDR);
- v |= HD64461_GPBDR_LCDOFF;
- fb_writew(v, HD64461_GPBDR);
-#endif
v = fb_readw(HD64461_LDR1);
v &= ~HD64461_LDR1_DON;
fb_writew(v, HD64461_LDR1);
@@ -215,19 +194,18 @@ int hitfb_blank(int blank_mode, struct fb_info *info)
v = fb_readw(HD64461_STBCR);
v &= ~HD64461_STBCR_SLCDST;
fb_writew(v, HD64461_STBCR);
-#ifdef MACH_HP600
- sh_dac_enable(DAC_LCD_BRIGHTNESS);
- v = fb_readw(HD64461_GPBDR);
- v &= ~HD64461_GPBDR_LCDOFF;
- fb_writew(v, HD64461_GPBDR);
-#endif
- v = fb_readw(HD64461_LDR1);
- v |= HD64461_LDR1_DON;
- fb_writew(v, HD64461_LDR1);
v = fb_readw(HD64461_LCDCCR);
- v &= ~HD64461_LCDCCR_MOFF;
+ v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ);
fb_writew(v, HD64461_LCDCCR);
+
+ do {
+ v = fb_readw(HD64461_LCDCCR);
+ } while(v&HD64461_LCDCCR_STBACK);
+
+ v = fb_readw(HD64461_LDR1);
+ v |= HD64461_LDR1_DON;
+ fb_writew(v, HD64461_LDR1);
}
return 0;
}
@@ -235,7 +213,7 @@ int hitfb_blank(int blank_mode, struct fb_info *info)
static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info)
{
- if (regno >= info->cmap.len)
+ if (regno >= 256)
return 1;
switch (info->var.bits_per_pixel) {
@@ -246,6 +224,8 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
fb_writew(blue >> 10, HD64461_CPTWDR);
break;
case 16:
+ if (regno >= 16)
+ return 1;
((u32 *) (info->pseudo_palette))[regno] =
((red & 0xf800)) |
((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
@@ -254,26 +234,113 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+static int hitfb_sync(struct fb_info *info)
+{
+ hitfb_accel_wait();
+
+ return 0;
+}
+
+static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int maxy;
+
+ var->xres = info->var.xres;
+ var->xres_virtual = info->var.xres;
+ var->yres = info->var.yres;
+
+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16))
+ var->bits_per_pixel = info->var.bits_per_pixel;
+
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ maxy = info->fix.smem_len / var->xres;
+
+ if (var->bits_per_pixel == 16)
+ maxy /= 2;
+
+ if (var->yres_virtual > maxy)
+ var->yres_virtual = maxy;
+
+ var->xoffset = 0;
+ var->yoffset = 0;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 16: /* RGB 565 */
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int hitfb_set_par(struct fb_info *info)
+{
+ unsigned short ldr3;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->fix.line_length = info->var.xres;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 16;
+ break;
+ case 16:
+ info->fix.line_length = info->var.xres*2;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.ypanstep = 8;
+ break;
+ }
+
+ fb_writew(info->fix.line_length, HD64461_LCDCLOR);
+ ldr3 = fb_readw(HD64461_LDR3);
+ ldr3 &= ~15;
+ ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8;
+ fb_writew(ldr3, HD64461_LDR3);
+ return 0;
+}
+
static struct fb_ops hitfb_ops = {
.owner = THIS_MODULE,
+ .fb_check_var = hitfb_check_var,
+ .fb_set_par = hitfb_set_par,
.fb_setcolreg = hitfb_setcolreg,
.fb_blank = hitfb_blank,
+ .fb_sync = hitfb_sync,
.fb_pan_display = hitfb_pan_display,
.fb_fillrect = hitfb_fillrect,
.fb_copyarea = hitfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
-int __init hitfb_init(void)
+static int __init hitfb_probe(struct platform_device *dev)
{
unsigned short lcdclor, ldr3, ldvndr;
- int size;
if (fb_get_options("hitfb", NULL))
return -ENODEV;
+ hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000;
+ hitfb_fix.mmio_len = 0x1000;
hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
- hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024;
+ hitfb_fix.smem_len = 512 * 1024;
lcdclor = fb_readw(HD64461_LCDCLOR);
ldvndr = fb_readw(HD64461_LDVNDR);
@@ -323,12 +390,12 @@ int __init hitfb_init(void)
fb_info.var = hitfb_var;
fb_info.fix = hitfb_fix;
fb_info.pseudo_palette = pseudo_palette;
- fb_info.flags = FBINFO_DEFAULT;
+ fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+ FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
fb_info.screen_base = (void *)hitfb_fix.smem_start;
- size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
- fb_alloc_cmap(&fb_info.cmap, size, 0);
+ fb_alloc_cmap(&fb_info.cmap, 256, 0);
if (register_framebuffer(&fb_info) < 0)
return -EINVAL;
@@ -338,9 +405,75 @@ int __init hitfb_init(void)
return 0;
}
+static int __devexit hitfb_remove(struct platform_device *dev)
+{
+ return unregister_framebuffer(&fb_info);
+}
+
+#ifdef CONFIG_PM
+static int hitfb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ u16 v;
+
+ hitfb_blank(1,0);
+ v = fb_readw(HD64461_STBCR);
+ v |= HD64461_STBCR_SLCKE_IST;
+ fb_writew(v, HD64461_STBCR);
+
+ return 0;
+}
+
+static int hitfb_resume(struct platform_device *dev)
+{
+ u16 v;
+
+ v = fb_readw(HD64461_STBCR);
+ v &= ~HD64461_STBCR_SLCKE_OST;
+ msleep(100);
+ v = fb_readw(HD64461_STBCR);
+ v &= ~HD64461_STBCR_SLCKE_IST;
+ fb_writew(v, HD64461_STBCR);
+ hitfb_blank(0,0);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver hitfb_driver = {
+ .probe = hitfb_probe,
+ .remove = __devexit_p(hitfb_remove),
+#ifdef CONFIG_PM
+ .suspend = hitfb_suspend,
+ .resume = hitfb_resume,
+#endif
+ .driver = {
+ .name = "hitfb",
+ },
+};
+
+static struct platform_device hitfb_device = {
+ .name = "hitfb",
+ .id = -1,
+};
+
+static int __init hitfb_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&hitfb_driver);
+ if (!ret) {
+ ret = platform_device_register(&hitfb_device);
+ if (ret)
+ platform_driver_unregister(&hitfb_driver);
+ }
+ return ret;
+}
+
+
static void __exit hitfb_exit(void)
{
- unregister_framebuffer(&fb_info);
+ platform_device_unregister(&hitfb_device);
+ platform_driver_unregister(&hitfb_driver);
}
module_init(hitfb_init);
diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c
index abd920a663a..91cf3b577d1 100644
--- a/drivers/video/hpfb.c
+++ b/drivers/video/hpfb.c
@@ -11,7 +11,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
index 3fe3ae1aff1..7d06b38e80a 100644
--- a/drivers/video/i810/i810-i2c.c
+++ b/drivers/video/i810/i810-i2c.c
@@ -8,7 +8,6 @@
* 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/kernel.h>
#include <linux/sched.h>
@@ -99,7 +98,6 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
chan->algo.getsda = i810i2c_getsda;
chan->algo.getscl = i810i2c_getscl;
chan->algo.udelay = 10;
- chan->algo.mdelay = 10;
chan->algo.timeout = (HZ/2);
chan->algo.data = chan;
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index 44aa2ffff97..d42edaccb84 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -29,12 +29,10 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/init.h>
@@ -1556,15 +1554,17 @@ static struct fb_ops i810fb_ops __devinitdata = {
/***********************************************************************
* Power Management *
***********************************************************************/
-static int i810fb_suspend(struct pci_dev *dev, pm_message_t state)
+static int i810fb_suspend(struct pci_dev *dev, pm_message_t mesg)
{
struct fb_info *info = pci_get_drvdata(dev);
struct i810fb_par *par = info->par;
- par->cur_state = state.event;
+ par->cur_state = mesg.event;
- if (state.event == PM_EVENT_FREEZE) {
- dev->dev.power.power_state = state;
+ switch (mesg.event) {
+ case PM_EVENT_FREEZE:
+ case PM_EVENT_PRETHAW:
+ dev->dev.power.power_state = mesg;
return 0;
}
@@ -1580,7 +1580,7 @@ static int i810fb_suspend(struct pci_dev *dev, pm_message_t state)
pci_save_state(dev);
pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
+ pci_set_power_state(dev, pci_choose_state(dev, mesg));
release_console_sem();
return 0;
@@ -2110,9 +2110,6 @@ static void i810fb_release_resource(struct fb_info *info,
if (par->res_flags & MMIO_REQ)
release_mem_region(par->mmio_start_phys, MMIO_SIZE);
- if (par->res_flags & PCI_DEVICE_ENABLED)
- pci_disable_device(par->dev);
-
framebuffer_release(info);
}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 6b88050d21b..67f384f8675 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -33,7 +33,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -232,9 +231,6 @@ static int igafb_mmap(struct fb_info *info,
size = vma->vm_end - vma->vm_start;
- /* To stop the swapper from even considering these pages. */
- vma->vm_flags |= (VM_SHM | VM_LOCKED);
-
/* Each page, see which map applies */
for (page = 0; page < size; ) {
map_size = 0;
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
new file mode 100644
index 00000000000..18ea4a54910
--- /dev/null
+++ b/drivers/video/imacfb.c
@@ -0,0 +1,380 @@
+/*
+ * framebuffer driver for Intel Based Mac's
+ *
+ * (c) 2006 Edgar Hucek <gimli@dark-green.com>
+ * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fb.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/screen_info.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/dmi.h>
+#include <linux/efi.h>
+
+#include <asm/io.h>
+
+#include <video/vga.h>
+
+typedef enum _MAC_TYPE {
+ M_I17,
+ M_I20,
+ M_MINI,
+ M_MACBOOK,
+ M_UNKNOWN
+} MAC_TYPE;
+
+/* --------------------------------------------------------------------- */
+
+static struct fb_var_screeninfo imacfb_defined __initdata = {
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .right_margin = 32,
+ .upper_margin = 16,
+ .lower_margin = 4,
+ .vsync_len = 4,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+
+static struct fb_fix_screeninfo imacfb_fix __initdata = {
+ .id = "IMAC VGA",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .accel = FB_ACCEL_NONE,
+ .visual = FB_VISUAL_TRUECOLOR,
+};
+
+static int inverse;
+static int model = M_UNKNOWN;
+static int manual_height;
+static int manual_width;
+
+static int set_system(struct dmi_system_id *id)
+{
+ printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
+ id->ident, (long)id->driver_data);
+
+ model = (long)id->driver_data;
+
+ return 0;
+}
+
+static struct dmi_system_id __initdata dmi_system_table[] = {
+ { set_system, "iMac4,1", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME,"iMac4,1") }, (void*)M_I17},
+ { set_system, "MacBookPro1,1", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro1,1") }, (void*)M_I17},
+ { set_system, "MacBook1,1", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK},
+ { set_system, "Macmini1,1", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME,"Macmini1,1")}, (void *)M_MINI},
+ {},
+};
+
+#define DEFAULT_FB_MEM 1024*1024*16
+
+/* --------------------------------------------------------------------- */
+
+static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ /*
+ * Set a single color register. The values supplied are
+ * already rounded down to the hardware's capabilities
+ * (according to the entries in the `var' structure). Return
+ * != 0 for invalid regno.
+ */
+
+ if (regno >= info->cmap.len)
+ return 1;
+
+ if (regno < 16) {
+ red >>= 8;
+ green >>= 8;
+ blue >>= 8;
+ ((u32 *)(info->pseudo_palette))[regno] =
+ (red << info->var.red.offset) |
+ (green << info->var.green.offset) |
+ (blue << info->var.blue.offset);
+ }
+ return 0;
+}
+
+static struct fb_ops imacfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_setcolreg = imacfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int __init imacfb_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt) continue;
+
+ if (!strcmp(this_opt, "inverse"))
+ inverse = 1;
+ else if (!strcmp(this_opt, "i17"))
+ model = M_I17;
+ else if (!strcmp(this_opt, "i20"))
+ model = M_I20;
+ else if (!strcmp(this_opt, "mini"))
+ model = M_MINI;
+ else if (!strcmp(this_opt, "macbook"))
+ model = M_MACBOOK;
+ else if (!strncmp(this_opt, "height:", 7))
+ manual_height = simple_strtoul(this_opt+7, NULL, 0);
+ else if (!strncmp(this_opt, "width:", 6))
+ manual_width = simple_strtoul(this_opt+6, NULL, 0);
+ }
+ return 0;
+}
+
+static int __init imacfb_probe(struct platform_device *dev)
+{
+ struct fb_info *info;
+ int err;
+ unsigned int size_vmode;
+ unsigned int size_remap;
+ unsigned int size_total;
+
+ screen_info.lfb_depth = 32;
+ screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
+ screen_info.pages=1;
+ screen_info.blue_size = 8;
+ screen_info.blue_pos = 0;
+ screen_info.green_size = 8;
+ screen_info.green_pos = 8;
+ screen_info.red_size = 8;
+ screen_info.red_pos = 16;
+ screen_info.rsvd_size = 8;
+ screen_info.rsvd_pos = 24;
+
+ switch (model) {
+ case M_I17:
+ screen_info.lfb_width = 1440;
+ screen_info.lfb_height = 900;
+ screen_info.lfb_linelength = 1472 * 4;
+ screen_info.lfb_base = 0x80010000;
+ break;
+ case M_I20:
+ screen_info.lfb_width = 1680;
+ screen_info.lfb_height = 1050;
+ screen_info.lfb_linelength = 1728 * 4;
+ screen_info.lfb_base = 0x80010000;
+ break;
+ case M_MINI:
+ screen_info.lfb_width = 1024;
+ screen_info.lfb_height = 768;
+ screen_info.lfb_linelength = 2048 * 4;
+ screen_info.lfb_base = 0x80000000;
+ break;
+ case M_MACBOOK:
+ screen_info.lfb_width = 1280;
+ screen_info.lfb_height = 800;
+ screen_info.lfb_linelength = 2048 * 4;
+ screen_info.lfb_base = 0x80000000;
+ break;
+ }
+
+ /* if the user wants to manually specify height/width,
+ we will override the defaults */
+ /* TODO: eventually get auto-detection working */
+ if (manual_height > 0)
+ screen_info.lfb_height = manual_height;
+ if (manual_width > 0)
+ screen_info.lfb_width = manual_width;
+
+ imacfb_fix.smem_start = screen_info.lfb_base;
+ imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
+ imacfb_defined.xres = screen_info.lfb_width;
+ imacfb_defined.yres = screen_info.lfb_height;
+ imacfb_fix.line_length = screen_info.lfb_linelength;
+
+ /* size_vmode -- that is the amount of memory needed for the
+ * used video mode, i.e. the minimum amount of
+ * memory we need. */
+ size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
+
+ /* size_total -- all video memory we have. Used for
+ * entries, ressource allocation and bounds
+ * checking. */
+ size_total = screen_info.lfb_size * 65536;
+ if (size_total < size_vmode)
+ size_total = size_vmode;
+
+ /* size_remap -- the amount of video memory we are going to
+ * use for imacfb. With modern cards it is no
+ * option to simply use size_total as that
+ * wastes plenty of kernel address space. */
+ size_remap = size_vmode * 2;
+ if (size_remap < size_vmode)
+ size_remap = size_vmode;
+ if (size_remap > size_total)
+ size_remap = size_total;
+ imacfb_fix.smem_len = size_remap;
+
+#ifndef __i386__
+ screen_info.imacpm_seg = 0;
+#endif
+
+ if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
+ printk(KERN_WARNING
+ "imacfb: cannot reserve video memory at 0x%lx\n",
+ imacfb_fix.smem_start);
+ /* We cannot make this fatal. Sometimes this comes from magic
+ spaces our resource handlers simply don't know about */
+ }
+
+ info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
+ if (!info) {
+ err = -ENOMEM;
+ goto err_release_mem;
+ }
+ info->pseudo_palette = info->par;
+ info->par = NULL;
+
+ info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
+ if (!info->screen_base) {
+ printk(KERN_ERR "imacfb: abort, cannot ioremap video memory "
+ "0x%x @ 0x%lx\n",
+ imacfb_fix.smem_len, imacfb_fix.smem_start);
+ err = -EIO;
+ goto err_unmap;
+ }
+
+ printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
+ "using %dk, total %dk\n",
+ imacfb_fix.smem_start, info->screen_base,
+ size_remap/1024, size_total/1024);
+ printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
+ imacfb_defined.xres, imacfb_defined.yres,
+ imacfb_defined.bits_per_pixel, imacfb_fix.line_length,
+ screen_info.pages);
+
+ imacfb_defined.xres_virtual = imacfb_defined.xres;
+ imacfb_defined.yres_virtual = imacfb_fix.smem_len /
+ imacfb_fix.line_length;
+ printk(KERN_INFO "imacfb: scrolling: redraw\n");
+ imacfb_defined.yres_virtual = imacfb_defined.yres;
+
+ /* some dummy values for timing to make fbset happy */
+ imacfb_defined.pixclock = 10000000 / imacfb_defined.xres *
+ 1000 / imacfb_defined.yres;
+ imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8;
+ imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8;
+
+ imacfb_defined.red.offset = screen_info.red_pos;
+ imacfb_defined.red.length = screen_info.red_size;
+ imacfb_defined.green.offset = screen_info.green_pos;
+ imacfb_defined.green.length = screen_info.green_size;
+ imacfb_defined.blue.offset = screen_info.blue_pos;
+ imacfb_defined.blue.length = screen_info.blue_size;
+ imacfb_defined.transp.offset = screen_info.rsvd_pos;
+ imacfb_defined.transp.length = screen_info.rsvd_size;
+
+ printk(KERN_INFO "imacfb: %s: "
+ "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
+ "Truecolor",
+ screen_info.rsvd_size,
+ screen_info.red_size,
+ screen_info.green_size,
+ screen_info.blue_size,
+ screen_info.rsvd_pos,
+ screen_info.red_pos,
+ screen_info.green_pos,
+ screen_info.blue_pos);
+
+ imacfb_fix.ypanstep = 0;
+ imacfb_fix.ywrapstep = 0;
+
+ /* request failure does not faze us, as vgacon probably has this
+ * region already (FIXME) */
+ request_region(0x3c0, 32, "imacfb");
+
+ info->fbops = &imacfb_ops;
+ info->var = imacfb_defined;
+ info->fix = imacfb_fix;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
+ err = -ENOMEM;
+ goto err_unmap;
+ }
+ if (register_framebuffer(info)<0) {
+ err = -EINVAL;
+ goto err_fb_dealoc;
+ }
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+ return 0;
+
+err_fb_dealoc:
+ fb_dealloc_cmap(&info->cmap);
+err_unmap:
+ iounmap(info->screen_base);
+ framebuffer_release(info);
+err_release_mem:
+ release_mem_region(imacfb_fix.smem_start, size_total);
+ return err;
+}
+
+static struct platform_driver imacfb_driver = {
+ .probe = imacfb_probe,
+ .driver = {
+ .name = "imacfb",
+ },
+};
+
+static struct platform_device imacfb_device = {
+ .name = "imacfb",
+};
+
+static int __init imacfb_init(void)
+{
+ int ret;
+ char *option = NULL;
+
+ if (!efi_enabled)
+ return -ENODEV;
+ if (!dmi_check_system(dmi_system_table))
+ return -ENODEV;
+ if (model == M_UNKNOWN)
+ return -ENODEV;
+
+ if (fb_get_options("imacfb", &option))
+ return -ENODEV;
+
+ imacfb_setup(option);
+ ret = platform_driver_register(&imacfb_driver);
+
+ if (!ret) {
+ ret = platform_device_register(&imacfb_device);
+ if (ret)
+ platform_driver_unregister(&imacfb_driver);
+ }
+ return ret;
+}
+module_init(imacfb_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index f73c642b50c..5715b8ad0dd 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -16,13 +16,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c
index 1718baaeed2..0f9b2fdc28b 100644
--- a/drivers/video/imxfb.c
+++ b/drivers/video/imxfb.c
@@ -18,7 +18,6 @@
//#define DEBUG 1
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index f6e30b3d108..6f9de04193d 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -108,13 +108,11 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -123,6 +121,7 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
+#include <linux/screen_info.h>
#include <asm/io.h>
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index bbd82fffc3f..f887f1efd3f 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -19,13 +19,11 @@
/* $DHD: intelfb/intelfbhw.c,v 1.9 2003/06/27 15:06:25 dawes Exp $ */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/kyro/fbdev.c b/drivers/video/kyro/fbdev.c
index 477ad297de4..f0d614a80f1 100644
--- a/drivers/video/kyro/fbdev.c
+++ b/drivers/video/kyro/fbdev.c
@@ -9,7 +9,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -17,7 +16,6 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioctl.h>
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index a23cfdb9d82..f3a24338d9a 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -1,6 +1,6 @@
/* leo.c: LEO frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz)
*
@@ -18,8 +18,8 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -80,10 +80,10 @@ static struct fb_ops leo_ops = {
struct leo_cursor {
u8 xxx0[16];
- volatile u32 cur_type;
- volatile u32 cur_misc;
- volatile u32 cur_cursxy;
- volatile u32 cur_data;
+ u32 cur_type;
+ u32 cur_misc;
+ u32 cur_cursxy;
+ u32 cur_data;
};
#define LEO_KRN_TYPE_CLUT0 0x00001000
@@ -99,27 +99,27 @@ struct leo_cursor {
#define LEO_KRN_CSR_UNK2 0x00000001
struct leo_lx_krn {
- volatile u32 krn_type;
- volatile u32 krn_csr;
- volatile u32 krn_value;
+ u32 krn_type;
+ u32 krn_csr;
+ u32 krn_value;
};
struct leo_lc_ss0_krn {
- volatile u32 misc;
+ u32 misc;
u8 xxx0[0x800-4];
- volatile u32 rev;
+ u32 rev;
};
struct leo_lc_ss0_usr {
- volatile u32 csr;
- volatile u32 addrspace;
- volatile u32 fontmsk;
- volatile u32 fontt;
- volatile u32 extent;
- volatile u32 src;
+ u32 csr;
+ u32 addrspace;
+ u32 fontmsk;
+ u32 fontt;
+ u32 extent;
+ u32 src;
u32 dst;
- volatile u32 copy;
- volatile u32 fill;
+ u32 copy;
+ u32 fill;
};
struct leo_lc_ss1_krn {
@@ -132,47 +132,47 @@ struct leo_lc_ss1_usr {
struct leo_ld {
u8 xxx0[0xe00];
- volatile u32 csr;
- volatile u32 wid;
- volatile u32 wmask;
- volatile u32 widclip;
- volatile u32 vclipmin;
- volatile u32 vclipmax;
- volatile u32 pickmin; /* SS1 only */
- volatile u32 pickmax; /* SS1 only */
- volatile u32 fg;
- volatile u32 bg;
- volatile u32 src; /* Copy/Scroll (SS0 only) */
- volatile u32 dst; /* Copy/Scroll/Fill (SS0 only) */
- volatile u32 extent; /* Copy/Scroll/Fill size (SS0 only) */
+ u32 csr;
+ u32 wid;
+ u32 wmask;
+ u32 widclip;
+ u32 vclipmin;
+ u32 vclipmax;
+ u32 pickmin; /* SS1 only */
+ u32 pickmax; /* SS1 only */
+ u32 fg;
+ u32 bg;
+ u32 src; /* Copy/Scroll (SS0 only) */
+ u32 dst; /* Copy/Scroll/Fill (SS0 only) */
+ u32 extent; /* Copy/Scroll/Fill size (SS0 only) */
u32 xxx1[3];
- volatile u32 setsem; /* SS1 only */
- volatile u32 clrsem; /* SS1 only */
- volatile u32 clrpick; /* SS1 only */
- volatile u32 clrdat; /* SS1 only */
- volatile u32 alpha; /* SS1 only */
+ u32 setsem; /* SS1 only */
+ u32 clrsem; /* SS1 only */
+ u32 clrpick; /* SS1 only */
+ u32 clrdat; /* SS1 only */
+ u32 alpha; /* SS1 only */
u8 xxx2[0x2c];
- volatile u32 winbg;
- volatile u32 planemask;
- volatile u32 rop;
- volatile u32 z;
- volatile u32 dczf; /* SS1 only */
- volatile u32 dczb; /* SS1 only */
- volatile u32 dcs; /* SS1 only */
- volatile u32 dczs; /* SS1 only */
- volatile u32 pickfb; /* SS1 only */
- volatile u32 pickbb; /* SS1 only */
- volatile u32 dcfc; /* SS1 only */
- volatile u32 forcecol; /* SS1 only */
- volatile u32 door[8]; /* SS1 only */
- volatile u32 pick[5]; /* SS1 only */
+ u32 winbg;
+ u32 planemask;
+ u32 rop;
+ u32 z;
+ u32 dczf; /* SS1 only */
+ u32 dczb; /* SS1 only */
+ u32 dcs; /* SS1 only */
+ u32 dczs; /* SS1 only */
+ u32 pickfb; /* SS1 only */
+ u32 pickbb; /* SS1 only */
+ u32 dcfc; /* SS1 only */
+ u32 forcecol; /* SS1 only */
+ u32 door[8]; /* SS1 only */
+ u32 pick[5]; /* SS1 only */
};
#define LEO_SS1_MISC_ENABLE 0x00000001
#define LEO_SS1_MISC_STEREO 0x00000002
struct leo_ld_ss1 {
- u8 xxx0[0xef4];
- volatile u32 ss1_misc;
+ u8 xxx0[0xef4];
+ u32 ss1_misc;
};
struct leo_ld_gbl {
@@ -193,9 +193,8 @@ struct leo_par {
#define LEO_FLAG_BLANKED 0x00000001
unsigned long physbase;
+ unsigned long which_io;
unsigned long fbsize;
-
- struct sbus_dev *sdev;
};
static void leo_wait(struct leo_lx_krn __iomem *lx_krn)
@@ -368,8 +367,7 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma)
return sbusfb_mmap_helper(leo_mmap_map,
par->physbase, par->fbsize,
- par->sdev->reg_addrs[0].which_io,
- vma);
+ par->which_io, vma);
}
static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
@@ -385,11 +383,9 @@ static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
*/
static void
-leo_init_fix(struct fb_info *info)
+leo_init_fix(struct fb_info *info, struct device_node *dp)
{
- struct leo_par *par = (struct leo_par *)info->par;
-
- strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+ strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_TRUECOLOR;
@@ -532,60 +528,74 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var)
struct all_info {
struct fb_info info;
struct leo_par par;
- struct list_head list;
};
-static LIST_HEAD(leo_list);
-static void leo_init_one(struct sbus_dev *sdev)
+static void leo_unmap_regs(struct all_info *all)
{
- struct all_info *all;
- int linebytes;
+ if (all->par.lc_ss0_usr)
+ of_iounmap(all->par.lc_ss0_usr, 0x1000);
+ if (all->par.ld_ss0)
+ of_iounmap(all->par.ld_ss0, 0x1000);
+ if (all->par.ld_ss1)
+ of_iounmap(all->par.ld_ss1, 0x1000);
+ if (all->par.lx_krn)
+ of_iounmap(all->par.lx_krn, 0x1000);
+ if (all->par.cursor)
+ of_iounmap(all->par.cursor, sizeof(struct leo_cursor));
+ if (all->info.screen_base)
+ of_iounmap(all->info.screen_base, 0x800000);
+}
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "leo: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
+static int __devinit leo_init_one(struct of_device *op)
+{
+ struct device_node *dp = op->node;
+ struct all_info *all;
+ int linebytes, err;
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- all->par.sdev = sdev;
- all->par.physbase = sdev->reg_addrs[0].phys_addr;
+ all->par.physbase = op->resource[0].start;
+ all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, sdev->prom_node, 32);
+ sbusfb_fill_var(&all->info.var, dp->node, 32);
leo_fixup_var_rgb(&all->info.var);
- linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
- all->info.var.xres);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
-#ifdef CONFIG_SPARC32
- all->info.screen_base = (char __iomem *)
- prom_getintdefault(sdev->prom_node, "address", 0);
-#endif
- if (!all->info.screen_base)
- all->info.screen_base =
- sbus_ioremap(&sdev->resource[0], LEO_OFF_SS0,
- 0x800000, "leo ram");
-
all->par.lc_ss0_usr =
- sbus_ioremap(&sdev->resource[0], LEO_OFF_LC_SS0_USR,
- 0x1000, "leolc ss0usr");
+ of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR,
+ 0x1000, "leolc ss0usr");
all->par.ld_ss0 =
- sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS0,
- 0x1000, "leold ss0");
+ of_ioremap(&op->resource[0], LEO_OFF_LD_SS0,
+ 0x1000, "leold ss0");
all->par.ld_ss1 =
- sbus_ioremap(&sdev->resource[0], LEO_OFF_LD_SS1,
- 0x1000, "leold ss1");
+ of_ioremap(&op->resource[0], LEO_OFF_LD_SS1,
+ 0x1000, "leold ss1");
all->par.lx_krn =
- sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_KRN,
- 0x1000, "leolx krn");
+ of_ioremap(&op->resource[0], LEO_OFF_LX_KRN,
+ 0x1000, "leolx krn");
all->par.cursor =
- sbus_ioremap(&sdev->resource[0], LEO_OFF_LX_CURSOR,
- sizeof(struct leo_cursor), "leolx cursor");
+ of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR,
+ sizeof(struct leo_cursor), "leolx cursor");
+ all->info.screen_base =
+ of_ioremap(&op->resource[0], LEO_OFF_SS0,
+ 0x800000, "leo ram");
+ if (!all->par.lc_ss0_usr ||
+ !all->par.ld_ss0 ||
+ !all->par.ld_ss1 ||
+ !all->par.lx_krn ||
+ !all->par.cursor ||
+ !all->info.screen_base) {
+ leo_unmap_regs(all);
+ kfree(all);
+ return -ENOMEM;
+ }
all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
all->info.fbops = &leo_ops;
@@ -597,69 +607,85 @@ static void leo_init_one(struct sbus_dev *sdev)
leo_blank(0, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "leo: Could not allocate color map.\n");
+ leo_unmap_regs(all);
kfree(all);
- return;
+ return -ENOMEM;;
}
- leo_init_fix(&all->info);
+ leo_init_fix(&all->info, dp);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "leo: Could not register framebuffer.\n");
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
+ leo_unmap_regs(all);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &leo_list);
+ dev_set_drvdata(&op->dev, all);
+
+ printk("%s: leo at %lx:%lx\n",
+ dp->full_name,
+ all->par.which_io, all->par.physbase);
- printk("leo: %s at %lx:%lx\n",
- sdev->prom_name,
- (long) sdev->reg_addrs[0].which_io,
- (long) sdev->reg_addrs[0].phys_addr);
+ return 0;
}
-int __init leo_init(void)
+static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("leofb", NULL))
- return -ENODEV;
+ return leo_init_one(op);
+}
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "leo"))
- leo_init_one(sdev);
- }
+static int __devexit leo_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+
+ leo_unmap_regs(all);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit leo_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id leo_match[] = {
+ {
+ .name = "leo",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, leo_match);
+
+static struct of_platform_driver leo_driver = {
+ .name = "leo",
+ .match_table = leo_match,
+ .probe = leo_probe,
+ .remove = __devexit_p(leo_remove),
+};
- list_for_each_safe(pos, tmp, &leo_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static int __init leo_init(void)
+{
+ if (fb_get_options("leofb", NULL))
+ return -ENODEV;
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+ return of_register_driver(&leo_driver, &of_bus_type);
}
-int __init
-leo_setup(char *arg)
+static void __exit leo_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&leo_driver);
}
module_init(leo_init);
-#ifdef MODULE
module_exit(leo_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for LEO chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 788fa812c87..80c03618eb5 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -9,7 +9,6 @@
* Copyright (C) 2003 Geert Uytterhoeven <geert@linux-m68k.org>
*/
-#include <linux/config.h>
#include <linux/linux_logo.h>
#include <linux/stddef.h>
#include <linux/module.h>
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index e6cbd9de944..80a04380716 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -24,7 +24,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/nubus.h>
diff --git a/drivers/video/macmodes.c b/drivers/video/macmodes.c
index c0385c6f7db..ab2149531a0 100644
--- a/drivers/video/macmodes.c
+++ b/drivers/video/macmodes.c
@@ -15,7 +15,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/string.h>
@@ -327,7 +326,6 @@ int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
}
return -EINVAL;
}
-EXPORT_SYMBOL(mac_var_to_vmode);
/**
* mac_map_monitor_sense - Convert monitor sense to vmode
@@ -371,8 +369,9 @@ EXPORT_SYMBOL(mac_map_monitor_sense);
*
*/
-int __init mac_find_mode(struct fb_var_screeninfo *var, struct fb_info *info,
- const char *mode_option, unsigned int default_bpp)
+int __devinit mac_find_mode(struct fb_var_screeninfo *var,
+ struct fb_info *info, const char *mode_option,
+ unsigned int default_bpp)
{
const struct fb_videomode *db = NULL;
unsigned int dbsize = 0;
diff --git a/drivers/video/macmodes.h b/drivers/video/macmodes.h
index 232f5a09a49..babeb81f467 100644
--- a/drivers/video/macmodes.h
+++ b/drivers/video/macmodes.h
@@ -55,9 +55,10 @@ extern int mac_vmode_to_var(int vmode, int cmode,
extern int mac_var_to_vmode(const struct fb_var_screeninfo *var, int *vmode,
int *cmode);
extern int mac_map_monitor_sense(int sense);
-extern int __init mac_find_mode(struct fb_var_screeninfo *var,
- struct fb_info *info, const char *mode_option,
- unsigned int default_bpp);
+extern int __devinit mac_find_mode(struct fb_var_screeninfo *var,
+ struct fb_info *info,
+ const char *mode_option,
+ unsigned int default_bpp);
/*
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
index 440272ad10e..7c76e079ca7 100644
--- a/drivers/video/matrox/g450_pll.c
+++ b/drivers/video/matrox/g450_pll.c
@@ -331,7 +331,15 @@ static int __g450_setclk(WPMINFO unsigned int fout, unsigned int pll,
tmp |= M1064_XPIXCLKCTRL_PLL_UP;
}
matroxfb_DAC_out(PMINFO M1064_XPIXCLKCTRL, tmp);
+#ifdef __powerpc__
+ /* This is necessary to avoid jitter on PowerPC
+ * (OpenFirmware) systems, but apparently
+ * introduces jitter, at least on a x86-64
+ * using DVI.
+ * A simple workaround is disable for non-PPC.
+ */
matroxfb_DAC_out(PMINFO M1064_XDVICLKCTRL, 0);
+#endif /* __powerpc__ */
matroxfb_DAC_out(PMINFO M1064_XPWRCTRL, xpwrctrl);
matroxfb_DAC_unlock_irqrestore(flags);
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index 57abbae5520..795c1a99a68 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -95,12 +95,12 @@ static struct i2c_adapter matrox_i2c_adapter_template =
static struct i2c_algo_bit_data matrox_i2c_algo_template =
{
- NULL,
- matroxfb_gpio_setsda,
- matroxfb_gpio_setscl,
- matroxfb_gpio_getsda,
- matroxfb_gpio_getscl,
- 10, 10, 100,
+ .setsda = matroxfb_gpio_setsda,
+ .setscl = matroxfb_gpio_setscl,
+ .getsda = matroxfb_gpio_getsda,
+ .getscl = matroxfb_gpio_getscl,
+ .udelay = 10,
+ .timeout = 100,
};
static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
diff --git a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c
index a456e67a5b0..c4b570b4a4d 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.c
+++ b/drivers/video/matrox/matroxfb_DAC1064.c
@@ -12,7 +12,6 @@
*
*/
-#include <linux/config.h>
#include "matroxfb_DAC1064.h"
#include "matroxfb_misc.h"
diff --git a/drivers/video/matrox/matroxfb_DAC1064.h b/drivers/video/matrox/matroxfb_DAC1064.h
index 56513a5d220..df39c319373 100644
--- a/drivers/video/matrox/matroxfb_DAC1064.h
+++ b/drivers/video/matrox/matroxfb_DAC1064.h
@@ -1,7 +1,6 @@
#ifndef __MATROXFB_DAC1064_H__
#define __MATROXFB_DAC1064_H__
-#include <linux/config.h>
#include "matroxfb_base.h"
diff --git a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c
index 23ebad0a12d..a5690a5f29d 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.c
+++ b/drivers/video/matrox/matroxfb_Ti3026.c
@@ -78,7 +78,6 @@
*
*/
-#include <linux/config.h>
#include "matroxfb_Ti3026.h"
#include "matroxfb_misc.h"
diff --git a/drivers/video/matrox/matroxfb_Ti3026.h b/drivers/video/matrox/matroxfb_Ti3026.h
index 536e5f69de9..27872aaa0a1 100644
--- a/drivers/video/matrox/matroxfb_Ti3026.h
+++ b/drivers/video/matrox/matroxfb_Ti3026.h
@@ -1,7 +1,6 @@
#ifndef __MATROXFB_TI3026_H__
#define __MATROXFB_TI3026_H__
-#include <linux/config.h>
#include "matroxfb_base.h"
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 23c1827b2d0..4a57dabb77d 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -99,9 +99,10 @@
*
*/
-#include <linux/config.h>
#include <linux/version.h>
+#define __OLD_VIDIOC_
+
#include "matroxfb_base.h"
#include "matroxfb_misc.h"
#include "matroxfb_accel.h"
@@ -158,9 +159,9 @@ static void update_crtc2(WPMINFO unsigned int pos) {
/* Make sure that displays are compatible */
if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
- && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
- && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
- ) {
+ && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
+ && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
+ ) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
case 16:
case 32:
@@ -224,7 +225,7 @@ static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
int matroxfb_enable_irq(WPMINFO int reenable) {
u_int32_t bm;
-
+
if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
bm = 0x220;
else
@@ -232,7 +233,7 @@ int matroxfb_enable_irq(WPMINFO int reenable) {
if (!test_and_set_bit(0, &ACCESS_FBINFO(irq_flags))) {
if (request_irq(ACCESS_FBINFO(pcidev)->irq, matrox_irq,
- SA_SHIRQ, "matroxfb", MINFO)) {
+ IRQF_SHARED, "matroxfb", MINFO)) {
clear_bit(0, &ACCESS_FBINFO(irq_flags));
return -EINVAL;
}
@@ -241,7 +242,7 @@ int matroxfb_enable_irq(WPMINFO int reenable) {
mga_outl(M_IEN, mga_inl(M_IEN) | bm);
} else if (reenable) {
u_int32_t ien;
-
+
ien = mga_inl(M_IEN);
if ((ien & bm) != bm) {
printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
@@ -347,7 +348,7 @@ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) {
mga_setr(M_EXTVGA_INDEX, 0x00, p2);
}
matroxfb_DAC_unlock_irqrestore(flags);
-
+
update_crtc2(PMINFO pos);
CRITEND
@@ -390,7 +391,7 @@ static void matroxfb_remove(WPMINFO int dummy) {
static int matroxfb_open(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
-
+
DBG_LOOP(__FUNCTION__)
if (ACCESS_FBINFO(dead)) {
@@ -406,7 +407,7 @@ static int matroxfb_open(struct fb_info *info, int user)
static int matroxfb_release(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
-
+
DBG_LOOP(__FUNCTION__)
if (user) {
@@ -854,7 +855,7 @@ static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank)
vblank->flags |= FB_VBLANK_VBLANKING;
if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
vblank->flags |= FB_VBLANK_HAVE_COUNT;
- /* Only one writer, aligned int value...
+ /* Only one writer, aligned int value...
it should work without lock and without atomic_t */
vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
}
@@ -870,7 +871,7 @@ static int matroxfb_ioctl(struct fb_info *info,
{
void __user *argp = (void __user *)arg;
MINFO_FROM_INFO(info);
-
+
DBG(__FUNCTION__)
if (ACCESS_FBINFO(dead)) {
@@ -1081,7 +1082,7 @@ static int matroxfb_ioctl(struct fb_info *info,
case VIDIOC_QUERYCAP:
{
struct v4l2_capability r;
-
+
memset(&r, 0, sizeof(r));
strcpy(r.driver, "matroxfb");
strcpy(r.card, "Matrox");
@@ -1091,7 +1092,7 @@ static int matroxfb_ioctl(struct fb_info *info,
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
return 0;
-
+
}
case VIDIOC_QUERYCTRL:
{
@@ -1690,8 +1691,8 @@ static int initMatrox2(WPMINFO struct board* b){
pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
mga_option |= MX_OPTION_BSWAP;
- /* disable palette snooping */
- cmd &= ~PCI_COMMAND_VGA_PALETTE;
+ /* disable palette snooping */
+ cmd &= ~PCI_COMMAND_VGA_PALETTE;
if (pci_dev_present(intel_82437)) {
if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
@@ -1809,12 +1810,12 @@ static int initMatrox2(WPMINFO struct board* b){
if (fv) {
tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
- + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+ + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
if ((tmp < fh) || (fh == 0)) fh = tmp;
}
if (fh) {
tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
- + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+ + vesafb_defined.right_margin + vesafb_defined.hsync_len);
if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
}
tmp = (maxclk + 499) / 500;
@@ -1890,14 +1891,14 @@ static int initMatrox2(WPMINFO struct board* b){
/* there is no console on this fb... but we have to initialize hardware
* until someone tells me what is proper thing to do */
- if (!ACCESS_FBINFO(initialized)) {
- printk(KERN_INFO "fb%d: initializing hardware\n",
- ACCESS_FBINFO(fbcon.node));
- /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
- * already before, so register_framebuffer works correctly. */
- vesafb_defined.activate |= FB_ACTIVATE_FORCE;
- fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
- }
+ if (!ACCESS_FBINFO(initialized)) {
+ printk(KERN_INFO "fb%d: initializing hardware\n",
+ ACCESS_FBINFO(fbcon.node));
+ /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+ * already before, so register_framebuffer works correctly. */
+ vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
+ }
return 0;
failVideoIO:;
@@ -2356,7 +2357,7 @@ static int __init matroxfb_setup(char *options) {
else if (!strncmp(this_opt, "dfp:", 4)) {
dfp_type = simple_strtoul(this_opt+4, NULL, 0);
dfp = 1;
- }
+ }
#ifdef CONFIG_PPC_PMAC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
diff --git a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h
index b71737178d0..9c25c2f7966 100644
--- a/drivers/video/matrox/matroxfb_base.h
+++ b/drivers/video/matrox/matroxfb_base.h
@@ -25,13 +25,11 @@
/* Guard accelerator accesses with spin_lock_irqsave... */
#undef MATROXFB_USE_SPINLOCKS
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 263d801ef78..18886b629cb 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -84,7 +84,6 @@
*
*/
-#include <linux/config.h>
#include "matroxfb_misc.h"
#include <linux/interrupt.h>
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
index f85421bf7cb..38c8d38de4f 100644
--- a/drivers/video/maxinefb.c
+++ b/drivers/video/maxinefb.c
@@ -29,7 +29,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/mbx/Makefile b/drivers/video/mbx/Makefile
new file mode 100644
index 00000000000..16c1165cf9c
--- /dev/null
+++ b/drivers/video/mbx/Makefile
@@ -0,0 +1,4 @@
+# Makefile for the 2700G controller driver.
+
+obj-$(CONFIG_FB_MBX) += mbxfb.o
+obj-$(CONFIG_FB_MBX_DEBUG) += mbxfbdebugfs.o
diff --git a/drivers/video/mbx/mbxdebugfs.c b/drivers/video/mbx/mbxdebugfs.c
new file mode 100644
index 00000000000..84aab3ad024
--- /dev/null
+++ b/drivers/video/mbx/mbxdebugfs.c
@@ -0,0 +1,188 @@
+#include <linux/debugfs.h>
+
+#define BIG_BUFFER_SIZE (1024)
+
+static char big_buffer[BIG_BUFFER_SIZE];
+
+struct mbxfb_debugfs_data {
+ struct dentry *dir;
+ struct dentry *sysconf;
+ struct dentry *clock;
+ struct dentry *display;
+ struct dentry *gsctl;
+};
+
+static int open_file_generic(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->u.generic_ip;
+ return 0;
+}
+
+static ssize_t write_file_dummy(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+static ssize_t sysconf_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "SYSCFG = %08lx\n", SYSCFG);
+ s += sprintf(s, "PFBASE = %08lx\n", PFBASE);
+ s += sprintf(s, "PFCEIL = %08lx\n", PFCEIL);
+ s += sprintf(s, "POLLFLAG = %08lx\n", POLLFLAG);
+ s += sprintf(s, "SYSRST = %08lx\n", SYSRST);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+
+static ssize_t gsctl_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "GSCTRL = %08lx\n", GSCTRL);
+ s += sprintf(s, "VSCTRL = %08lx\n", VSCTRL);
+ s += sprintf(s, "GBBASE = %08lx\n", GBBASE);
+ s += sprintf(s, "VBBASE = %08lx\n", VBBASE);
+ s += sprintf(s, "GDRCTRL = %08lx\n", GDRCTRL);
+ s += sprintf(s, "VCMSK = %08lx\n", VCMSK);
+ s += sprintf(s, "GSCADR = %08lx\n", GSCADR);
+ s += sprintf(s, "VSCADR = %08lx\n", VSCADR);
+ s += sprintf(s, "VUBASE = %08lx\n", VUBASE);
+ s += sprintf(s, "VVBASE = %08lx\n", VVBASE);
+ s += sprintf(s, "GSADR = %08lx\n", GSADR);
+ s += sprintf(s, "VSADR = %08lx\n", VSADR);
+ s += sprintf(s, "HCCTRL = %08lx\n", HCCTRL);
+ s += sprintf(s, "HCSIZE = %08lx\n", HCSIZE);
+ s += sprintf(s, "HCPOS = %08lx\n", HCPOS);
+ s += sprintf(s, "HCBADR = %08lx\n", HCBADR);
+ s += sprintf(s, "HCCKMSK = %08lx\n", HCCKMSK);
+ s += sprintf(s, "GPLUT = %08lx\n", GPLUT);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t display_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "DSCTRL = %08lx\n", DSCTRL);
+ s += sprintf(s, "DHT01 = %08lx\n", DHT01);
+ s += sprintf(s, "DHT02 = %08lx\n", DHT02);
+ s += sprintf(s, "DHT03 = %08lx\n", DHT03);
+ s += sprintf(s, "DVT01 = %08lx\n", DVT01);
+ s += sprintf(s, "DVT02 = %08lx\n", DVT02);
+ s += sprintf(s, "DVT03 = %08lx\n", DVT03);
+ s += sprintf(s, "DBCOL = %08lx\n", DBCOL);
+ s += sprintf(s, "BGCOLOR = %08lx\n", BGCOLOR);
+ s += sprintf(s, "DINTRS = %08lx\n", DINTRS);
+ s += sprintf(s, "DINTRE = %08lx\n", DINTRE);
+ s += sprintf(s, "DINTRCNT = %08lx\n", DINTRCNT);
+ s += sprintf(s, "DSIG = %08lx\n", DSIG);
+ s += sprintf(s, "DMCTRL = %08lx\n", DMCTRL);
+ s += sprintf(s, "CLIPCTRL = %08lx\n", CLIPCTRL);
+ s += sprintf(s, "SPOCTRL = %08lx\n", SPOCTRL);
+ s += sprintf(s, "SVCTRL = %08lx\n", SVCTRL);
+ s += sprintf(s, "DLSTS = %08lx\n", DLSTS);
+ s += sprintf(s, "DLLCTRL = %08lx\n", DLLCTRL);
+ s += sprintf(s, "DVLNUM = %08lx\n", DVLNUM);
+ s += sprintf(s, "DUCTRL = %08lx\n", DUCTRL);
+ s += sprintf(s, "DVECTRL = %08lx\n", DVECTRL);
+ s += sprintf(s, "DHDET = %08lx\n", DHDET);
+ s += sprintf(s, "DVDET = %08lx\n", DVDET);
+ s += sprintf(s, "DODMSK = %08lx\n", DODMSK);
+ s += sprintf(s, "CSC01 = %08lx\n", CSC01);
+ s += sprintf(s, "CSC02 = %08lx\n", CSC02);
+ s += sprintf(s, "CSC03 = %08lx\n", CSC03);
+ s += sprintf(s, "CSC04 = %08lx\n", CSC04);
+ s += sprintf(s, "CSC05 = %08lx\n", CSC05);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static ssize_t clock_read_file(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ char * s = big_buffer;
+
+ s += sprintf(s, "SYSCLKSRC = %08lx\n", SYSCLKSRC);
+ s += sprintf(s, "PIXCLKSRC = %08lx\n", PIXCLKSRC);
+ s += sprintf(s, "CLKSLEEP = %08lx\n", CLKSLEEP);
+ s += sprintf(s, "COREPLL = %08lx\n", COREPLL);
+ s += sprintf(s, "DISPPLL = %08lx\n", DISPPLL);
+ s += sprintf(s, "PLLSTAT = %08lx\n", PLLSTAT);
+ s += sprintf(s, "VOVRCLK = %08lx\n", VOVRCLK);
+ s += sprintf(s, "PIXCLK = %08lx\n", PIXCLK);
+ s += sprintf(s, "MEMCLK = %08lx\n", MEMCLK);
+ s += sprintf(s, "M24CLK = %08lx\n", M24CLK);
+ s += sprintf(s, "MBXCLK = %08lx\n", MBXCLK);
+ s += sprintf(s, "SDCLK = %08lx\n", SDCLK);
+ s += sprintf(s, "PIXCLKDIV = %08lx\n", PIXCLKDIV);
+
+ return simple_read_from_buffer(userbuf, count, ppos,
+ big_buffer, s-big_buffer);
+}
+
+static struct file_operations sysconf_fops = {
+ .read = sysconf_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations clock_fops = {
+ .read = clock_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations display_fops = {
+ .read = display_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+static struct file_operations gsctl_fops = {
+ .read = gsctl_read_file,
+ .write = write_file_dummy,
+ .open = open_file_generic,
+};
+
+
+static void __devinit mbxfb_debugfs_init(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ struct mbxfb_debugfs_data *dbg;
+
+ dbg = kzalloc(sizeof(struct mbxfb_debugfs_data), GFP_KERNEL);
+ mfbi->debugfs_data = dbg;
+
+ dbg->dir = debugfs_create_dir("mbxfb", NULL);
+ dbg->sysconf = debugfs_create_file("sysconf", 0444, dbg->dir,
+ fbi, &sysconf_fops);
+ dbg->clock = debugfs_create_file("clock", 0444, dbg->dir,
+ fbi, &clock_fops);
+ dbg->display = debugfs_create_file("display", 0444, dbg->dir,
+ fbi, &display_fops);
+ dbg->gsctl = debugfs_create_file("gsctl", 0444, dbg->dir,
+ fbi, &gsctl_fops);
+}
+
+static void __devexit mbxfb_debugfs_remove(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ struct mbxfb_debugfs_data *dbg = mfbi->debugfs_data;
+
+ debugfs_remove(dbg->gsctl);
+ debugfs_remove(dbg->display);
+ debugfs_remove(dbg->clock);
+ debugfs_remove(dbg->sysconf);
+ debugfs_remove(dbg->dir);
+}
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
new file mode 100644
index 00000000000..6849ab75d40
--- /dev/null
+++ b/drivers/video/mbx/mbxfb.c
@@ -0,0 +1,683 @@
+/*
+ * linux/drivers/video/mbx/mbxfb.c
+ *
+ * Copyright (C) 2006 Compulab, Ltd.
+ * Mike Rapoport <mike@compulab.co.il>
+ *
+ * Based on pxafb.c
+ *
+ * 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.
+ *
+ * Intel 2700G (Marathon) Graphics Accelerator Frame Buffer Driver
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <video/mbxfb.h>
+
+#include "regs.h"
+#include "reg_bits.h"
+
+static unsigned long virt_base_2700;
+
+#define MIN_XRES 16
+#define MIN_YRES 16
+#define MAX_XRES 2048
+#define MAX_YRES 2048
+
+#define MAX_PALETTES 16
+
+/* FIXME: take care of different chip revisions with different sizes
+ of ODFB */
+#define MEMORY_OFFSET 0x60000
+
+struct mbxfb_info {
+ struct device *dev;
+
+ struct resource *fb_res;
+ struct resource *fb_req;
+
+ struct resource *reg_res;
+ struct resource *reg_req;
+
+ void __iomem *fb_virt_addr;
+ unsigned long fb_phys_addr;
+
+ void __iomem *reg_virt_addr;
+ unsigned long reg_phys_addr;
+
+ int (*platform_probe) (struct fb_info * fb);
+ int (*platform_remove) (struct fb_info * fb);
+
+ u32 pseudo_palette[MAX_PALETTES];
+#ifdef CONFIG_FB_MBX_DEBUG
+ void *debugfs_data;
+#endif
+
+};
+
+static struct fb_var_screeninfo mbxfb_default __devinitdata = {
+ .xres = 640,
+ .yres = 480,
+ .xres_virtual = 640,
+ .yres_virtual = 480,
+ .bits_per_pixel = 16,
+ .red = {11, 5, 0},
+ .green = {5, 6, 0},
+ .blue = {0, 5, 0},
+ .activate = FB_ACTIVATE_TEST,
+ .height = -1,
+ .width = -1,
+ .pixclock = 40000,
+ .left_margin = 48,
+ .right_margin = 16,
+ .upper_margin = 33,
+ .lower_margin = 10,
+ .hsync_len = 96,
+ .vsync_len = 2,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct fb_fix_screeninfo mbxfb_fix __devinitdata = {
+ .id = "MBX",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+struct pixclock_div {
+ u8 m;
+ u8 n;
+ u8 p;
+};
+
+static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
+ struct pixclock_div *div)
+{
+ u8 m, n, p;
+ unsigned int err = 0;
+ unsigned int min_err = ~0x0;
+ unsigned int clk;
+ unsigned int best_clk = 0;
+ unsigned int ref_clk = 13000; /* FIXME: take from platform data */
+ unsigned int pixclock;
+
+ /* convert pixclock to KHz */
+ pixclock = PICOS2KHZ(pixclock_ps);
+
+ for (m = 1; m < 64; m++) {
+ for (n = 1; n < 8; n++) {
+ for (p = 0; p < 8; p++) {
+ clk = (ref_clk * m) / (n * (1 << p));
+ err = (clk > pixclock) ? (clk - pixclock) :
+ (pixclock - clk);
+ if (err < min_err) {
+ min_err = err;
+ best_clk = clk;
+ div->m = m;
+ div->n = n;
+ div->p = p;
+ }
+ }
+ }
+ }
+ return KHZ2PICOS(best_clk);
+}
+
+static int mbxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ u32 val, ret = 1;
+
+ if (regno < MAX_PALETTES) {
+ u32 *pal = info->pseudo_palette;
+
+ val = (red & 0xf800) | ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ pal[regno] = val;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int mbxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct pixclock_div div;
+
+ var->pixclock = mbxfb_get_pixclock(var->pixclock, &div);
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+ if (var->xres > MAX_XRES)
+ return -EINVAL;
+ if (var->yres > MAX_YRES)
+ return -EINVAL;
+ var->xres_virtual = max(var->xres_virtual, var->xres);
+ var->yres_virtual = max(var->yres_virtual, var->yres);
+
+ switch (var->bits_per_pixel) {
+ /* 8 bits-per-pixel is not supported yet */
+ case 8:
+ return -EINVAL;
+ case 16:
+ var->green.length = (var->green.length == 5) ? 5 : 6;
+ var->red.length = 5;
+ var->blue.length = 5;
+ var->transp.length = 6 - var->green.length;
+ var->blue.offset = 0;
+ var->green.offset = 5;
+ var->red.offset = 5 + var->green.length;
+ var->transp.offset = (5 + var->red.offset) & 15;
+ break;
+ case 24: /* RGB 888 */
+ case 32: /* RGBA 8888 */
+ var->red.offset = 16;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.length = var->bits_per_pixel - 24;
+ var->transp.offset = (var->transp.length) ? 24 : 0;
+ break;
+ }
+ var->red.msb_right = 0;
+ var->green.msb_right = 0;
+ var->blue.msb_right = 0;
+ var->transp.msb_right = 0;
+
+ return 0;
+}
+
+static int mbxfb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct pixclock_div div;
+ ushort hbps, ht, hfps, has;
+ ushort vbps, vt, vfps, vas;
+ u32 gsctrl = readl(GSCTRL);
+ u32 gsadr = readl(GSADR);
+
+ info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+ /* setup color mode */
+ gsctrl &= ~(FMsk(GSCTRL_GPIXFMT));
+ /* FIXME: add *WORKING* support for 8-bits per color */
+ if (info->var.bits_per_pixel == 8) {
+ return -EINVAL;
+ } else {
+ fb_dealloc_cmap(&info->cmap);
+ gsctrl &= ~GSCTRL_LUT_EN;
+
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ switch (info->var.bits_per_pixel) {
+ case 16:
+ if (info->var.green.length == 5)
+ gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
+ else
+ gsctrl |= GSCTRL_GPIXFMT_RGB565;
+ break;
+ case 24:
+ gsctrl |= GSCTRL_GPIXFMT_RGB888;
+ break;
+ case 32:
+ gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
+ break;
+ }
+ }
+
+ /* setup resolution */
+ gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
+ gsctrl |= Gsctrl_Width(info->var.xres - 1) |
+ Gsctrl_Height(info->var.yres - 1);
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+
+ gsadr &= ~(FMsk(GSADR_SRCSTRIDE));
+ gsadr |= Gsadr_Srcstride(info->var.xres * info->var.bits_per_pixel /
+ (8 * 16) - 1);
+ writel(gsadr, GSADR);
+ udelay(1000);
+
+ /* setup timings */
+ var->pixclock = mbxfb_get_pixclock(info->var.pixclock, &div);
+
+ writel((Disp_Pll_M(div.m) | Disp_Pll_N(div.n) |
+ Disp_Pll_P(div.p) | DISP_PLL_EN), DISPPLL);
+
+ hbps = var->hsync_len;
+ has = hbps + var->left_margin;
+ hfps = has + var->xres;
+ ht = hfps + var->right_margin;
+
+ vbps = var->vsync_len;
+ vas = vbps + var->upper_margin;
+ vfps = vas + var->yres;
+ vt = vfps + var->lower_margin;
+
+ writel((Dht01_Hbps(hbps) | Dht01_Ht(ht)), DHT01);
+ writel((Dht02_Hlbs(has) | Dht02_Has(has)), DHT02);
+ writel((Dht03_Hfps(hfps) | Dht03_Hrbs(hfps)), DHT03);
+ writel((Dhdet_Hdes(has) | Dhdet_Hdef(hfps)), DHDET);
+
+ writel((Dvt01_Vbps(vbps) | Dvt01_Vt(vt)), DVT01);
+ writel((Dvt02_Vtbs(vas) | Dvt02_Vas(vas)), DVT02);
+ writel((Dvt03_Vfps(vfps) | Dvt03_Vbbs(vfps)), DVT03);
+ writel((Dvdet_Vdes(vas) | Dvdet_Vdef(vfps)), DVDET);
+ writel((Dvectrl_Vevent(vfps) | Dvectrl_Vfetch(vbps)), DVECTRL);
+
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+
+ return 0;
+}
+
+static int mbxfb_blank(int blank, struct fb_info *info)
+{
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ writel((readl(DSCTRL) & ~DSCTRL_SYNCGEN_EN), DSCTRL);
+ udelay(1000);
+ writel((readl(PIXCLK) & ~PIXCLK_EN), PIXCLK);
+ udelay(1000);
+ writel((readl(VOVRCLK) & ~VOVRCLK_EN), VOVRCLK);
+ udelay(1000);
+ break;
+ case FB_BLANK_UNBLANK:
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ udelay(1000);
+ writel((readl(PIXCLK) | PIXCLK_EN), PIXCLK);
+ udelay(1000);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops mbxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = mbxfb_check_var,
+ .fb_set_par = mbxfb_set_par,
+ .fb_setcolreg = mbxfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = mbxfb_blank,
+};
+
+/*
+ Enable external SDRAM controller. Assume that all clocks are active
+ by now.
+*/
+static void __devinit setup_memc(struct fb_info *fbi)
+{
+ struct mbxfb_info *mfbi = fbi->par;
+ unsigned long tmp;
+ int i;
+
+ /* FIXME: use platfrom specific parameters */
+ /* setup SDRAM controller */
+ writel((LMCFG_LMC_DS | LMCFG_LMC_TS | LMCFG_LMD_TS |
+ LMCFG_LMA_TS),
+ LMCFG);
+ udelay(1000);
+
+ writel(LMPWR_MC_PWR_ACT, LMPWR);
+ udelay(1000);
+
+ /* setup SDRAM timings */
+ writel((Lmtim_Tras(7) | Lmtim_Trp(3) | Lmtim_Trcd(3) |
+ Lmtim_Trc(9) | Lmtim_Tdpl(2)),
+ LMTIM);
+ udelay(1000);
+ /* setup SDRAM refresh rate */
+ writel(0xc2b, LMREFRESH);
+ udelay(1000);
+ /* setup SDRAM type parameters */
+ writel((LMTYPE_CASLAT_3 | LMTYPE_BKSZ_2 | LMTYPE_ROWSZ_11 |
+ LMTYPE_COLSZ_8),
+ LMTYPE);
+ udelay(1000);
+ /* enable memory controller */
+ writel(LMPWR_MC_PWR_ACT, LMPWR);
+ udelay(1000);
+
+ /* perform dummy reads */
+ for ( i = 0; i < 16; i++ ) {
+ tmp = readl(fbi->screen_base);
+ }
+}
+
+static void enable_clocks(struct fb_info *fbi)
+{
+ /* enable clocks */
+ writel(SYSCLKSRC_PLL_2, SYSCLKSRC);
+ udelay(1000);
+ writel(PIXCLKSRC_PLL_1, PIXCLKSRC);
+ udelay(1000);
+ writel(0x00000000, CLKSLEEP);
+ udelay(1000);
+ writel((Core_Pll_M(0x17) | Core_Pll_N(0x3) | Core_Pll_P(0x0) |
+ CORE_PLL_EN),
+ COREPLL);
+ udelay(1000);
+ writel((Disp_Pll_M(0x1b) | Disp_Pll_N(0x7) | Disp_Pll_P(0x1) |
+ DISP_PLL_EN),
+ DISPPLL);
+
+ writel(0x00000000, VOVRCLK);
+ udelay(1000);
+ writel(PIXCLK_EN, PIXCLK);
+ udelay(1000);
+ writel(MEMCLK_EN, MEMCLK);
+ udelay(1000);
+ writel(0x00000006, M24CLK);
+ udelay(1000);
+ writel(0x00000006, MBXCLK);
+ udelay(1000);
+ writel(SDCLK_EN, SDCLK);
+ udelay(1000);
+ writel(0x00000001, PIXCLKDIV);
+ udelay(1000);
+}
+
+static void __devinit setup_graphics(struct fb_info *fbi)
+{
+ unsigned long gsctrl;
+
+ gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres - 1) |
+ Gsctrl_Height(fbi->var.yres - 1);
+ switch (fbi->var.bits_per_pixel) {
+ case 16:
+ if (fbi->var.green.length == 5)
+ gsctrl |= GSCTRL_GPIXFMT_ARGB1555;
+ else
+ gsctrl |= GSCTRL_GPIXFMT_RGB565;
+ break;
+ case 24:
+ gsctrl |= GSCTRL_GPIXFMT_RGB888;
+ break;
+ case 32:
+ gsctrl |= GSCTRL_GPIXFMT_ARGB8888;
+ break;
+ }
+
+ writel(gsctrl, GSCTRL);
+ udelay(1000);
+ writel(0x00000000, GBBASE);
+ udelay(1000);
+ writel(0x00ffffff, GDRCTRL);
+ udelay(1000);
+ writel((GSCADR_STR_EN | Gscadr_Gbase_Adr(0x6000)), GSCADR);
+ udelay(1000);
+ writel(0x00000000, GPLUT);
+ udelay(1000);
+}
+
+static void __devinit setup_display(struct fb_info *fbi)
+{
+ unsigned long dsctrl = 0;
+
+ dsctrl = DSCTRL_BLNK_POL;
+ if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
+ dsctrl |= DSCTRL_HS_POL;
+ if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
+ dsctrl |= DSCTRL_VS_POL;
+ writel(dsctrl, DSCTRL);
+ udelay(1000);
+ writel(0xd0303010, DMCTRL);
+ udelay(1000);
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+}
+
+static void __devinit enable_controller(struct fb_info *fbi)
+{
+ writel(SYSRST_RST, SYSRST);
+ udelay(1000);
+
+
+ enable_clocks(fbi);
+ setup_memc(fbi);
+ setup_graphics(fbi);
+ setup_display(fbi);
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int mbxfb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* make frame buffer memory enter self-refresh mode */
+ writel(LMPWR_MC_PWR_SRM, LMPWR);
+ while (LMPWRSTAT != LMPWRSTAT_MC_PWR_SRM)
+ ; /* empty statement */
+
+ /* reset the device, since it's initial state is 'mostly sleeping' */
+ writel(SYSRST_RST, SYSRST);
+ return 0;
+}
+
+static int mbxfb_resume(struct platform_device *dev)
+{
+ struct fb_info *fbi = platform_get_drvdata(dev);
+
+ enable_clocks(fbi);
+/* setup_graphics(fbi); */
+/* setup_display(fbi); */
+
+ writel((readl(DSCTRL) | DSCTRL_SYNCGEN_EN), DSCTRL);
+ return 0;
+}
+#else
+#define mbxfb_suspend NULL
+#define mbxfb_resume NULL
+#endif
+
+/* debugfs entries */
+#ifndef CONFIG_FB_MBX_DEBUG
+#define mbxfb_debugfs_init(x) do {} while(0)
+#define mbxfb_debugfs_remove(x) do {} while(0)
+#endif
+
+#define res_size(_r) (((_r)->end - (_r)->start) + 1)
+
+static int __devinit mbxfb_probe(struct platform_device *dev)
+{
+ int ret;
+ struct fb_info *fbi;
+ struct mbxfb_info *mfbi;
+ struct mbxfb_platform_data *pdata;
+
+ dev_dbg(dev, "mbxfb_probe\n");
+
+ fbi = framebuffer_alloc(sizeof(struct mbxfb_info), &dev->dev);
+ if (fbi == NULL) {
+ dev_err(&dev->dev, "framebuffer_alloc failed\n");
+ return -ENOMEM;
+ }
+
+ mfbi = fbi->par;
+ fbi->pseudo_palette = mfbi->pseudo_palette;
+ pdata = dev->dev.platform_data;
+ if (pdata->probe)
+ mfbi->platform_probe = pdata->probe;
+ if (pdata->remove)
+ mfbi->platform_remove = pdata->remove;
+
+ mfbi->fb_res = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ mfbi->reg_res = platform_get_resource(dev, IORESOURCE_MEM, 1);
+
+ if (!mfbi->fb_res || !mfbi->reg_res) {
+ dev_err(&dev->dev, "no resources found\n");
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ mfbi->fb_req = request_mem_region(mfbi->fb_res->start,
+ res_size(mfbi->fb_res), dev->name);
+ if (mfbi->fb_req == NULL) {
+ dev_err(&dev->dev, "failed to claim framebuffer memory\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+ mfbi->fb_phys_addr = mfbi->fb_res->start;
+
+ mfbi->reg_req = request_mem_region(mfbi->reg_res->start,
+ res_size(mfbi->reg_res), dev->name);
+ if (mfbi->reg_req == NULL) {
+ dev_err(&dev->dev, "failed to claim Marathon registers\n");
+ ret = -EINVAL;
+ goto err2;
+ }
+ mfbi->reg_phys_addr = mfbi->reg_res->start;
+
+ mfbi->reg_virt_addr = ioremap_nocache(mfbi->reg_phys_addr,
+ res_size(mfbi->reg_req));
+ if (!mfbi->reg_virt_addr) {
+ dev_err(&dev->dev, "failed to ioremap Marathon registers\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+ virt_base_2700 = (unsigned long)mfbi->reg_virt_addr;
+
+ mfbi->fb_virt_addr = ioremap_nocache(mfbi->fb_phys_addr,
+ res_size(mfbi->fb_req));
+ if (!mfbi->reg_virt_addr) {
+ dev_err(&dev->dev, "failed to ioremap frame buffer\n");
+ ret = -EINVAL;
+ goto err4;
+ }
+
+ /* FIXME: get from platform */
+ fbi->screen_base = (char __iomem *)(mfbi->fb_virt_addr + 0x60000);
+ fbi->screen_size = 8 * 1024 * 1024; /* 8 Megs */
+ fbi->fbops = &mbxfb_ops;
+
+ fbi->var = mbxfb_default;
+ fbi->fix = mbxfb_fix;
+ fbi->fix.smem_start = mfbi->fb_phys_addr + 0x60000;
+ fbi->fix.smem_len = 8 * 1024 * 1024;
+ fbi->fix.line_length = 640 * 2;
+
+ ret = fb_alloc_cmap(&fbi->cmap, 256, 0);
+ if (ret < 0) {
+ dev_err(&dev->dev, "fb_alloc_cmap failed\n");
+ ret = -EINVAL;
+ goto err5;
+ }
+
+ platform_set_drvdata(dev, fbi);
+
+ printk(KERN_INFO "fb%d: mbx frame buffer device\n", fbi->node);
+
+ if (mfbi->platform_probe)
+ mfbi->platform_probe(fbi);
+
+ enable_controller(fbi);
+
+ mbxfb_debugfs_init(fbi);
+
+ ret = register_framebuffer(fbi);
+ if (ret < 0) {
+ dev_err(&dev->dev, "register_framebuffer failed\n");
+ ret = -EINVAL;
+ goto err6;
+ }
+
+ return 0;
+
+err6:
+ fb_dealloc_cmap(&fbi->cmap);
+err5:
+ iounmap(mfbi->fb_virt_addr);
+err4:
+ iounmap(mfbi->reg_virt_addr);
+err3:
+ release_mem_region(mfbi->reg_res->start, res_size(mfbi->reg_res));
+err2:
+ release_mem_region(mfbi->fb_res->start, res_size(mfbi->fb_res));
+err1:
+ framebuffer_release(fbi);
+
+ return ret;
+}
+
+static int __devexit mbxfb_remove(struct platform_device *dev)
+{
+ struct fb_info *fbi = platform_get_drvdata(dev);
+
+ writel(SYSRST_RST, SYSRST);
+ udelay(1000);
+
+ mbxfb_debugfs_remove(fbi);
+
+ if (fbi) {
+ struct mbxfb_info *mfbi = fbi->par;
+
+ unregister_framebuffer(fbi);
+ if (mfbi) {
+ if (mfbi->platform_remove)
+ mfbi->platform_remove(fbi);
+
+ if (mfbi->fb_virt_addr)
+ iounmap(mfbi->fb_virt_addr);
+ if (mfbi->reg_virt_addr)
+ iounmap(mfbi->reg_virt_addr);
+ if (mfbi->reg_req)
+ release_mem_region(mfbi->reg_req->start,
+ res_size(mfbi->reg_req));
+ if (mfbi->fb_req)
+ release_mem_region(mfbi->fb_req->start,
+ res_size(mfbi->fb_req));
+ }
+ framebuffer_release(fbi);
+ }
+
+ return 0;
+}
+
+static struct platform_driver mbxfb_driver = {
+ .probe = mbxfb_probe,
+ .remove = mbxfb_remove,
+ .suspend = mbxfb_suspend,
+ .resume = mbxfb_resume,
+ .driver = {
+ .name = "mbx-fb",
+ },
+};
+
+int __devinit mbxfb_init(void)
+{
+ return platform_driver_register(&mbxfb_driver);
+}
+
+static void __devexit mbxfb_exit(void)
+{
+ platform_driver_unregister(&mbxfb_driver);
+}
+
+module_init(mbxfb_init);
+module_exit(mbxfb_exit);
+
+MODULE_DESCRIPTION("loadable framebuffer driver for Marathon device");
+MODULE_AUTHOR("Mike Rapoport, Compulab");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/mbx/reg_bits.h b/drivers/video/mbx/reg_bits.h
new file mode 100644
index 00000000000..c226a8e4531
--- /dev/null
+++ b/drivers/video/mbx/reg_bits.h
@@ -0,0 +1,418 @@
+#ifndef __REG_BITS_2700G_
+#define __REG_BITS_2700G_
+
+/* use defines from asm-arm/arch-pxa/bitfields.h for bit fields access */
+#define UData(Data) ((unsigned long) (Data))
+#define Fld(Size, Shft) (((Size) << 16) + (Shft))
+#define FSize(Field) ((Field) >> 16)
+#define FShft(Field) ((Field) & 0x0000FFFF)
+#define FMsk(Field) (((UData (1) << FSize (Field)) - 1) << FShft (Field))
+#define FAlnMsk(Field) ((UData (1) << FSize (Field)) - 1)
+#define F1stBit(Field) (UData (1) << FShft (Field))
+
+#define SYSRST_RST (1 << 0)
+
+/* SYSCLKSRC - SYSCLK Source Control Register */
+#define SYSCLKSRC_SEL Fld(2,0)
+#define SYSCLKSRC_REF ((0x0) << FShft(SYSCLKSRC_SEL))
+#define SYSCLKSRC_PLL_1 ((0x1) << FShft(SYSCLKSRC_SEL))
+#define SYSCLKSRC_PLL_2 ((0x2) << FShft(SYSCLKSRC_SEL))
+
+/* PIXCLKSRC - PIXCLK Source Control Register */
+#define PIXCLKSRC_SEL Fld(2,0)
+#define PIXCLKSRC_REF ((0x0) << FShft(PIXCLKSRC_SEL))
+#define PIXCLKSRC_PLL_1 ((0x1) << FShft(PIXCLKSRC_SEL))
+#define PIXCLKSRC_PLL_2 ((0x2) << FShft(PIXCLKSRC_SEL))
+
+/* Clock Disable Register */
+#define CLKSLEEP_SLP (1 << 0)
+
+/* Core PLL Control Register */
+#define CORE_PLL_M Fld(6,7)
+#define Core_Pll_M(x) ((x) << FShft(CORE_PLL_M))
+#define CORE_PLL_N Fld(3,4)
+#define Core_Pll_N(x) ((x) << FShft(CORE_PLL_N))
+#define CORE_PLL_P Fld(3,1)
+#define Core_Pll_P(x) ((x) << FShft(CORE_PLL_P))
+#define CORE_PLL_EN (1 << 0)
+
+/* Display PLL Control Register */
+#define DISP_PLL_M Fld(6,7)
+#define Disp_Pll_M(x) ((x) << FShft(DISP_PLL_M))
+#define DISP_PLL_N Fld(3,4)
+#define Disp_Pll_N(x) ((x) << FShft(DISP_PLL_N))
+#define DISP_PLL_P Fld(3,1)
+#define Disp_Pll_P(x) ((x) << FShft(DISP_PLL_P))
+#define DISP_PLL_EN (1 << 0)
+
+/* PLL status register */
+#define PLLSTAT_CORE_PLL_LOST_L (1 << 3)
+#define PLLSTAT_CORE_PLL_LSTS (1 << 2)
+#define PLLSTAT_DISP_PLL_LOST_L (1 << 1)
+#define PLLSTAT_DISP_PLL_LSTS (1 << 0)
+
+/* Video and scale clock control register */
+#define VOVRCLK_EN (1 << 0)
+
+/* Pixel clock control register */
+#define PIXCLK_EN (1 << 0)
+
+/* Memory clock control register */
+#define MEMCLK_EN (1 << 0)
+
+/* MBX clock control register */
+#define MBXCLK_DIV Fld(2,2)
+#define MBXCLK_DIV_1 ((0x0) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_2 ((0x1) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_3 ((0x2) << FShft(MBXCLK_DIV))
+#define MBXCLK_DIV_4 ((0x3) << FShft(MBXCLK_DIV))
+#define MBXCLK_EN Fld(2,0)
+#define MBXCLK_EN_NONE ((0x0) << FShft(MBXCLK_EN))
+#define MBXCLK_EN_2D ((0x1) << FShft(MBXCLK_EN))
+#define MBXCLK_EN_BOTH ((0x2) << FShft(MBXCLK_EN))
+
+/* M24 clock control register */
+#define M24CLK_DIV Fld(2,1)
+#define M24CLK_DIV_1 ((0x0) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_2 ((0x1) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_3 ((0x2) << FShft(M24CLK_DIV))
+#define M24CLK_DIV_4 ((0x3) << FShft(M24CLK_DIV))
+#define M24CLK_EN (1 << 0)
+
+/* SDRAM clock control register */
+#define SDCLK_EN (1 << 0)
+
+/* PixClk Divisor Register */
+#define PIXCLKDIV_PD Fld(9,0)
+#define Pixclkdiv_Pd(x) ((x) << FShft(PIXCLKDIV_PD))
+
+/* LCD Config control register */
+#define LCDCFG_IN_FMT Fld(3,28)
+#define Lcdcfg_In_Fmt(x) ((x) << FShft(LCDCFG_IN_FMT))
+#define LCDCFG_LCD1DEN_POL (1 << 27)
+#define LCDCFG_LCD1FCLK_POL (1 << 26)
+#define LCDCFG_LCD1LCLK_POL (1 << 25)
+#define LCDCFG_LCD1D_POL (1 << 24)
+#define LCDCFG_LCD2DEN_POL (1 << 23)
+#define LCDCFG_LCD2FCLK_POL (1 << 22)
+#define LCDCFG_LCD2LCLK_POL (1 << 21)
+#define LCDCFG_LCD2D_POL (1 << 20)
+#define LCDCFG_LCD1_TS (1 << 19)
+#define LCDCFG_LCD1D_DS (1 << 18)
+#define LCDCFG_LCD1C_DS (1 << 17)
+#define LCDCFG_LCD1_IS_IN (1 << 16)
+#define LCDCFG_LCD2_TS (1 << 3)
+#define LCDCFG_LCD2D_DS (1 << 2)
+#define LCDCFG_LCD2C_DS (1 << 1)
+#define LCDCFG_LCD2_IS_IN (1 << 0)
+
+/* On-Die Frame Buffer Power Control Register */
+#define ODFBPWR_SLOW (1 << 2)
+#define ODFBPWR_MODE Fld(2,0)
+#define ODFBPWR_MODE_ACT ((0x0) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_ACT_LP ((0x1) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_SLEEP ((0x2) << FShft(ODFBPWR_MODE))
+#define ODFBPWR_MODE_SHUTD ((0x3) << FShft(ODFBPWR_MODE))
+
+/* On-Die Frame Buffer Power State Status Register */
+#define ODFBSTAT_ACT (1 << 2)
+#define ODFBSTAT_SLP (1 << 1)
+#define ODFBSTAT_SDN (1 << 0)
+
+/* LMRST - Local Memory (SDRAM) Reset */
+#define LMRST_MC_RST (1 << 0)
+
+/* LMCFG - Local Memory (SDRAM) Configuration Register */
+#define LMCFG_LMC_DS (1 << 5)
+#define LMCFG_LMD_DS (1 << 4)
+#define LMCFG_LMA_DS (1 << 3)
+#define LMCFG_LMC_TS (1 << 2)
+#define LMCFG_LMD_TS (1 << 1)
+#define LMCFG_LMA_TS (1 << 0)
+
+/* LMPWR - Local Memory (SDRAM) Power Control Register */
+#define LMPWR_MC_PWR_CNT Fld(2,0)
+#define LMPWR_MC_PWR_ACT ((0x0) << FShft(LMPWR_MC_PWR_CNT)) /* Active */
+#define LMPWR_MC_PWR_SRM ((0x1) << FShft(LMPWR_MC_PWR_CNT)) /* Self-refresh */
+#define LMPWR_MC_PWR_DPD ((0x3) << FShft(LMPWR_MC_PWR_CNT)) /* deep power down */
+
+/* LMPWRSTAT - Local Memory (SDRAM) Power Status Register */
+#define LMPWRSTAT_MC_PWR_CNT Fld(2,0)
+#define LMPWRSTAT_MC_PWR_ACT ((0x0) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Active */
+#define LMPWRSTAT_MC_PWR_SRM ((0x1) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* Self-refresh */
+#define LMPWRSTAT_MC_PWR_DPD ((0x3) << FShft(LMPWRSTAT_MC_PWR_CNT)) /* deep power down */
+
+/* LMTYPE - Local Memory (SDRAM) Type Register */
+#define LMTYPE_CASLAT Fld(3,10)
+#define LMTYPE_CASLAT_1 ((0x1) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_CASLAT_2 ((0x2) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_CASLAT_3 ((0x3) << FShft(LMTYPE_CASLAT))
+#define LMTYPE_BKSZ Fld(2,8)
+#define LMTYPE_BKSZ_1 ((0x1) << FShft(LMTYPE_BKSZ))
+#define LMTYPE_BKSZ_2 ((0x2) << FShft(LMTYPE_BKSZ))
+#define LMTYPE_ROWSZ Fld(4,4)
+#define LMTYPE_ROWSZ_11 ((0xb) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_ROWSZ_12 ((0xc) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_ROWSZ_13 ((0xd) << FShft(LMTYPE_ROWSZ))
+#define LMTYPE_COLSZ Fld(4,0)
+#define LMTYPE_COLSZ_7 ((0x7) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_8 ((0x8) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_9 ((0x9) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_10 ((0xa) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_11 ((0xb) << FShft(LMTYPE_COLSZ))
+#define LMTYPE_COLSZ_12 ((0xc) << FShft(LMTYPE_COLSZ))
+
+/* LMTIM - Local Memory (SDRAM) Timing Register */
+#define LMTIM_TRAS Fld(4,16)
+#define Lmtim_Tras(x) ((x) << FShft(LMTIM_TRAS))
+#define LMTIM_TRP Fld(4,12)
+#define Lmtim_Trp(x) ((x) << FShft(LMTIM_TRP))
+#define LMTIM_TRCD Fld(4,8)
+#define Lmtim_Trcd(x) ((x) << FShft(LMTIM_TRCD))
+#define LMTIM_TRC Fld(4,4)
+#define Lmtim_Trc(x) ((x) << FShft(LMTIM_TRC))
+#define LMTIM_TDPL Fld(4,0)
+#define Lmtim_Tdpl(x) ((x) << FShft(LMTIM_TDPL))
+
+/* LMREFRESH - Local Memory (SDRAM) tREF Control Register */
+#define LMREFRESH_TREF Fld(2,0)
+#define Lmrefresh_Tref(x) ((x) << FShft(LMREFRESH_TREF))
+
+/* GSCTRL - Graphics surface control register */
+#define GSCTRL_LUT_EN (1 << 31)
+#define GSCTRL_GPIXFMT Fld(4,27)
+#define GSCTRL_GPIXFMT_INDEXED ((0x0) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB4444 ((0x4) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB1555 ((0x5) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_RGB888 ((0x6) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_RGB565 ((0x7) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GPIXFMT_ARGB8888 ((0x8) << FShft(GSCTRL_GPIXFMT))
+#define GSCTRL_GAMMA_EN (1 << 26)
+
+#define GSCTRL_GSWIDTH Fld(11,11)
+#define Gsctrl_Width(Pixel) /* Display Width [1..2048 pix.] */ \
+ (((Pixel) - 1) << FShft(GSCTRL_GSWIDTH))
+
+#define GSCTRL_GSHEIGHT Fld(11,0)
+#define Gsctrl_Height(Pixel) /* Display Height [1..2048 pix.] */ \
+ (((Pixel) - 1) << FShft(GSCTRL_GSHEIGHT))
+
+/* GBBASE fileds */
+#define GBBASE_GLALPHA Fld(8,24)
+#define Gbbase_Glalpha(x) ((x) << FShft(GBBASE_GLALPHA))
+
+#define GBBASE_COLKEY Fld(24,0)
+#define Gbbase_Colkey(x) ((x) << FShft(GBBASE_COLKEY))
+
+/* GDRCTRL fields */
+#define GDRCTRL_PIXDBL (1 << 31)
+#define GDRCTRL_PIXHLV (1 << 30)
+#define GDRCTRL_LNDBL (1 << 29)
+#define GDRCTRL_LNHLV (1 << 28)
+#define GDRCTRL_COLKEYM Fld(24,0)
+#define Gdrctrl_Colkeym(x) ((x) << FShft(GDRCTRL_COLKEYM))
+
+/* GSCADR graphics stream control address register fields */
+#define GSCADR_STR_EN (1 << 31)
+#define GSCADR_COLKEY_EN (1 << 30)
+#define GSCADR_COLKEYSCR (1 << 29)
+#define GSCADR_BLEND_M Fld(2,27)
+#define GSCADR_BLEND_NONE ((0x0) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_INV ((0x1) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_GLOB ((0x2) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_PIX ((0x3) << FShft(GSCADR_BLEND_M))
+#define GSCADR_BLEND_POS Fld(2,24)
+#define GSCADR_BLEND_GFX ((0x0) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_BLEND_VID ((0x1) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_BLEND_CUR ((0x2) << FShft(GSCADR_BLEND_POS))
+#define GSCADR_GBASE_ADR Fld(23,0)
+#define Gscadr_Gbase_Adr(x) ((x) << FShft(GSCADR_GBASE_ADR))
+
+/* GSADR graphics stride address register fields */
+#define GSADR_SRCSTRIDE Fld(10,22)
+#define Gsadr_Srcstride(x) ((x) << FShft(GSADR_SRCSTRIDE))
+#define GSADR_XSTART Fld(11,11)
+#define Gsadr_Xstart(x) ((x) << FShft(GSADR_XSTART))
+#define GSADR_YSTART Fld(11,0)
+#define Gsadr_Ystart(y) ((y) << FShft(GSADR_YSTART))
+
+/* GPLUT graphics palette register fields */
+#define GPLUT_LUTADR Fld(8,24)
+#define Gplut_Lutadr(x) ((x) << FShft(GPLUT_LUTADR))
+#define GPLUT_LUTDATA Fld(24,0)
+#define Gplut_Lutdata(x) ((x) << FShft(GPLUT_LUTDATA))
+
+/* HCCTRL - Hardware Cursor Register fields */
+#define HCCTRL_CUR_EN (1 << 31)
+#define HCCTRL_COLKEY_EN (1 << 29)
+#define HCCTRL_COLKEYSRC (1 << 28)
+#define HCCTRL_BLEND_M Fld(2,26)
+#define HCCTRL_BLEND_NONE ((0x0) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_INV ((0x1) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_GLOB ((0x2) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_BLEND_PIX ((0x3) << FShft(HCCTRL_BLEND_M))
+#define HCCTRL_CPIXFMT Fld(3,23)
+#define HCCTRL_CPIXFMT_RGB332 ((0x3) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CPIXFMT_ARGB4444 ((0x4) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CPIXFMT_ARGB1555 ((0x5) << FShft(HCCTRL_CPIXFMT))
+#define HCCTRL_CBASE_ADR Fld(23,0)
+#define Hcctrl_Cbase_Adr(x) ((x) << FShft(HCCTRL_CBASE_ADR))
+
+/* HCSIZE Hardware Cursor Size Register fields */
+#define HCSIZE_BLEND_POS Fld(2,29)
+#define HCSIZE_BLEND_GFX ((0x0) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_BLEND_VID ((0x1) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_BLEND_CUR ((0x2) << FShft(HCSIZE_BLEND_POS))
+#define HCSIZE_CWIDTH Fld(3,16)
+#define Hcsize_Cwidth(x) ((x) << FShft(HCSIZE_CWIDTH))
+#define HCSIZE_CHEIGHT Fld(3,0)
+#define Hcsize_Cheight(x) ((x) << FShft(HCSIZE_CHEIGHT))
+
+/* HCPOS Hardware Cursor Position Register fields */
+#define HCPOS_SWITCHSRC (1 << 30)
+#define HCPOS_CURBLINK Fld(6,24)
+#define Hcpos_Curblink(x) ((x) << FShft(HCPOS_CURBLINK))
+#define HCPOS_XSTART Fld(12,12)
+#define Hcpos_Xstart(x) ((x) << FShft(HCPOS_XSTART))
+#define HCPOS_YSTART Fld(12,0)
+#define Hcpos_Ystart(y) ((y) << FShft(HCPOS_YSTART))
+
+/* HCBADR Hardware Cursor Blend Address Register */
+#define HCBADR_GLALPHA Fld(8,24)
+#define Hcbadr_Glalpha(x) ((x) << FShft(HCBADR_GLALPHA))
+#define HCBADR_COLKEY Fld(24,0)
+#define Hcbadr_Colkey(x) ((x) << FShft(HCBADR_COLKEY))
+
+/* HCCKMSK - Hardware Cursor Color Key Mask Register */
+#define HCCKMSK_COLKEY_M Fld(24,0)
+#define Hcckmsk_Colkey_M(x) ((x) << FShft(HCCKMSK_COLKEY_M))
+
+/* DSCTRL - Display sync control register */
+#define DSCTRL_SYNCGEN_EN (1 << 31)
+#define DSCTRL_DPL_RST (1 << 29)
+#define DSCTRL_PWRDN_M (1 << 28)
+#define DSCTRL_UPDSYNCCNT (1 << 26)
+#define DSCTRL_UPDINTCNT (1 << 25)
+#define DSCTRL_UPDCNT (1 << 24)
+#define DSCTRL_UPDWAIT Fld(4,16)
+#define Dsctrl_Updwait(x) ((x) << FShft(DSCTRL_UPDWAIT))
+#define DSCTRL_CLKPOL (1 << 11)
+#define DSCTRL_CSYNC_EN (1 << 10)
+#define DSCTRL_VS_SLAVE (1 << 7)
+#define DSCTRL_HS_SLAVE (1 << 6)
+#define DSCTRL_BLNK_POL (1 << 5)
+#define DSCTRL_BLNK_DIS (1 << 4)
+#define DSCTRL_VS_POL (1 << 3)
+#define DSCTRL_VS_DIS (1 << 2)
+#define DSCTRL_HS_POL (1 << 1)
+#define DSCTRL_HS_DIS (1 << 0)
+
+/* DHT01 - Display horizontal timing register 01 */
+#define DHT01_HBPS Fld(12,16)
+#define Dht01_Hbps(x) ((x) << FShft(DHT01_HBPS))
+#define DHT01_HT Fld(12,0)
+#define Dht01_Ht(x) ((x) << FShft(DHT01_HT))
+
+/* DHT02 - Display horizontal timing register 02 */
+#define DHT02_HAS Fld(12,16)
+#define Dht02_Has(x) ((x) << FShft(DHT02_HAS))
+#define DHT02_HLBS Fld(12,0)
+#define Dht02_Hlbs(x) ((x) << FShft(DHT02_HLBS))
+
+/* DHT03 - Display horizontal timing register 03 */
+#define DHT03_HFPS Fld(12,16)
+#define Dht03_Hfps(x) ((x) << FShft(DHT03_HFPS))
+#define DHT03_HRBS Fld(12,0)
+#define Dht03_Hrbs(x) ((x) << FShft(DHT03_HRBS))
+
+/* DVT01 - Display vertical timing register 01 */
+#define DVT01_VBPS Fld(12,16)
+#define Dvt01_Vbps(x) ((x) << FShft(DVT01_VBPS))
+#define DVT01_VT Fld(12,0)
+#define Dvt01_Vt(x) ((x) << FShft(DVT01_VT))
+
+/* DVT02 - Display vertical timing register 02 */
+#define DVT02_VAS Fld(12,16)
+#define Dvt02_Vas(x) ((x) << FShft(DVT02_VAS))
+#define DVT02_VTBS Fld(12,0)
+#define Dvt02_Vtbs(x) ((x) << FShft(DVT02_VTBS))
+
+/* DVT03 - Display vertical timing register 03 */
+#define DVT03_VFPS Fld(12,16)
+#define Dvt03_Vfps(x) ((x) << FShft(DVT03_VFPS))
+#define DVT03_VBBS Fld(12,0)
+#define Dvt03_Vbbs(x) ((x) << FShft(DVT03_VBBS))
+
+/* DVECTRL - display vertical event control register */
+#define DVECTRL_VEVENT Fld(12,16)
+#define Dvectrl_Vevent(x) ((x) << FShft(DVECTRL_VEVENT))
+#define DVECTRL_VFETCH Fld(12,0)
+#define Dvectrl_Vfetch(x) ((x) << FShft(DVECTRL_VFETCH))
+
+/* DHDET - display horizontal DE timing register */
+#define DHDET_HDES Fld(12,16)
+#define Dhdet_Hdes(x) ((x) << FShft(DHDET_HDES))
+#define DHDET_HDEF Fld(12,0)
+#define Dhdet_Hdef(x) ((x) << FShft(DHDET_HDEF))
+
+/* DVDET - display vertical DE timing register */
+#define DVDET_VDES Fld(12,16)
+#define Dvdet_Vdes(x) ((x) << FShft(DVDET_VDES))
+#define DVDET_VDEF Fld(12,0)
+#define Dvdet_Vdef(x) ((x) << FShft(DVDET_VDEF))
+
+/* DODMSK - display output data mask register */
+#define DODMSK_MASK_LVL (1 << 31)
+#define DODMSK_BLNK_LVL (1 << 30)
+#define DODMSK_MASK_B Fld(8,16)
+#define Dodmsk_Mask_B(x) ((x) << FShft(DODMSK_MASK_B))
+#define DODMSK_MASK_G Fld(8,8)
+#define Dodmsk_Mask_G(x) ((x) << FShft(DODMSK_MASK_G))
+#define DODMSK_MASK_R Fld(8,0)
+#define Dodmsk_Mask_R(x) ((x) << FShft(DODMSK_MASK_R))
+
+/* DBCOL - display border color control register */
+#define DBCOL_BORDCOL Fld(24,0)
+#define Dbcol_Bordcol(x) ((x) << FShft(DBCOL_BORDCOL))
+
+/* DVLNUM - display vertical line number register */
+#define DVLNUM_VLINE Fld(12,0)
+#define Dvlnum_Vline(x) ((x) << FShft(DVLNUM_VLINE))
+
+/* DMCTRL - Display Memory Control Register */
+#define DMCTRL_MEM_REF Fld(2,30)
+#define DMCTRL_MEM_REF_ACT ((0x0) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_HB ((0x1) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_VB ((0x2) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_MEM_REF_BOTH ((0x3) << FShft(DMCTRL_MEM_REF))
+#define DMCTRL_UV_THRHLD Fld(6,24)
+#define Dmctrl_Uv_Thrhld(x) ((x) << FShft(DMCTRL_UV_THRHLD))
+#define DMCTRL_V_THRHLD Fld(7,16)
+#define Dmctrl_V_Thrhld(x) ((x) << FShft(DMCTRL_V_THRHLD))
+#define DMCTRL_D_THRHLD Fld(7,8)
+#define Dmctrl_D_Thrhld(x) ((x) << FShft(DMCTRL_D_THRHLD))
+#define DMCTRL_BURSTLEN Fld(6,0)
+#define Dmctrl_Burstlen(x) ((x) << FShft(DMCTRL_BURSTLEN))
+
+
+/* DLSTS - display load status register */
+#define DLSTS_RLD_ADONE (1 << 23)
+/* #define DLSTS_RLD_ADOUT Fld(23,0) */
+
+/* DLLCTRL - display list load control register */
+#define DLLCTRL_RLD_ADRLN Fld(8,24)
+#define Dllctrl_Rld_Adrln(x) ((x) << FShft(DLLCTRL_RLD_ADRLN))
+
+/* SPOCTRL - Scale Pitch/Order Control Register */
+#define SPOCTRL_H_SC_BP (1 << 31)
+#define SPOCTRL_V_SC_BP (1 << 30)
+#define SPOCTRL_HV_SC_OR (1 << 29)
+#define SPOCTRL_VS_UR_C (1 << 27)
+#define SPOCTRL_VORDER Fld(2,16)
+#define SPOCTRL_VORDER_1TAP ((0x0) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VORDER_2TAP ((0x1) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VORDER_4TAP ((0x3) << FShft(SPOCTRL_VORDER))
+#define SPOCTRL_VPITCH Fld(16,0)
+#define Spoctrl_Vpitch(x) ((x) << FShft(SPOCTRL_VPITCH))
+
+#endif /* __REG_BITS_2700G_ */
diff --git a/drivers/video/mbx/regs.h b/drivers/video/mbx/regs.h
new file mode 100644
index 00000000000..ad20be07666
--- /dev/null
+++ b/drivers/video/mbx/regs.h
@@ -0,0 +1,195 @@
+#ifndef __REGS_2700G_
+#define __REGS_2700G_
+
+/* extern unsigned long virt_base_2700; */
+/* #define __REG_2700G(x) (*(volatile unsigned long*)((x)+virt_base_2700)) */
+#define __REG_2700G(x) ((x)+virt_base_2700)
+
+/* System Configuration Registers (0x0000_0000 0x0000_0010) */
+#define SYSCFG __REG_2700G(0x00000000)
+#define PFBASE __REG_2700G(0x00000004)
+#define PFCEIL __REG_2700G(0x00000008)
+#define POLLFLAG __REG_2700G(0x0000000c)
+#define SYSRST __REG_2700G(0x00000010)
+
+/* Interrupt Control Registers (0x0000_0014 0x0000_002F) */
+#define NINTPW __REG_2700G(0x00000014)
+#define MINTENABLE __REG_2700G(0x00000018)
+#define MINTSTAT __REG_2700G(0x0000001c)
+#define SINTENABLE __REG_2700G(0x00000020)
+#define SINTSTAT __REG_2700G(0x00000024)
+#define SINTCLR __REG_2700G(0x00000028)
+
+/* Clock Control Registers (0x0000_002C 0x0000_005F) */
+#define SYSCLKSRC __REG_2700G(0x0000002c)
+#define PIXCLKSRC __REG_2700G(0x00000030)
+#define CLKSLEEP __REG_2700G(0x00000034)
+#define COREPLL __REG_2700G(0x00000038)
+#define DISPPLL __REG_2700G(0x0000003c)
+#define PLLSTAT __REG_2700G(0x00000040)
+#define VOVRCLK __REG_2700G(0x00000044)
+#define PIXCLK __REG_2700G(0x00000048)
+#define MEMCLK __REG_2700G(0x0000004c)
+#define M24CLK __REG_2700G(0x00000054)
+#define MBXCLK __REG_2700G(0x00000054)
+#define SDCLK __REG_2700G(0x00000058)
+#define PIXCLKDIV __REG_2700G(0x0000005c)
+
+/* LCD Port Control Register (0x0000_0060 0x0000_006F) */
+#define LCD_CONFIG __REG_2700G(0x00000060)
+
+/* On-Die Frame Buffer Registers (0x0000_0064 0x0000_006B) */
+#define ODFBPWR __REG_2700G(0x00000064)
+#define ODFBSTAT __REG_2700G(0x00000068)
+
+/* GPIO Registers (0x0000_006C 0x0000_007F) */
+#define GPIOCGF __REG_2700G(0x0000006c)
+#define GPIOHI __REG_2700G(0x00000070)
+#define GPIOLO __REG_2700G(0x00000074)
+#define GPIOSTAT __REG_2700G(0x00000078)
+
+/* Pulse Width Modulator (PWM) Registers (0x0000_0200 0x0000_02FF) */
+#define PWMRST __REG_2700G(0x00000200)
+#define PWMCFG __REG_2700G(0x00000204)
+#define PWM0DIV __REG_2700G(0x00000210)
+#define PWM0DUTY __REG_2700G(0x00000214)
+#define PWM0PER __REG_2700G(0x00000218)
+#define PWM1DIV __REG_2700G(0x00000220)
+#define PWM1DUTY __REG_2700G(0x00000224)
+#define PWM1PER __REG_2700G(0x00000228)
+
+/* Identification (ID) Registers (0x0000_0300 0x0000_0FFF) */
+#define ID __REG_2700G(0x00000FF0)
+
+/* Local Memory (SDRAM) Interface Registers (0x0000_1000 0x0000_1FFF) */
+#define LMRST __REG_2700G(0x00001000)
+#define LMCFG __REG_2700G(0x00001004)
+#define LMPWR __REG_2700G(0x00001008)
+#define LMPWRSTAT __REG_2700G(0x0000100c)
+#define LMCEMR __REG_2700G(0x00001010)
+#define LMTYPE __REG_2700G(0x00001014)
+#define LMTIM __REG_2700G(0x00001018)
+#define LMREFRESH __REG_2700G(0x0000101c)
+#define LMPROTMIN __REG_2700G(0x00001020)
+#define LMPROTMAX __REG_2700G(0x00001024)
+#define LMPROTCFG __REG_2700G(0x00001028)
+#define LMPROTERR __REG_2700G(0x0000102c)
+
+/* Plane Controller Registers (0x0000_2000 0x0000_2FFF) */
+#define GSCTRL __REG_2700G(0x00002000)
+#define VSCTRL __REG_2700G(0x00002004)
+#define GBBASE __REG_2700G(0x00002020)
+#define VBBASE __REG_2700G(0x00002024)
+#define GDRCTRL __REG_2700G(0x00002040)
+#define VCMSK __REG_2700G(0x00002044)
+#define GSCADR __REG_2700G(0x00002060)
+#define VSCADR __REG_2700G(0x00002064)
+#define VUBASE __REG_2700G(0x00002084)
+#define VVBASE __REG_2700G(0x000020a4)
+#define GSADR __REG_2700G(0x000020c0)
+#define VSADR __REG_2700G(0x000020c4)
+#define HCCTRL __REG_2700G(0x00002100)
+#define HCSIZE __REG_2700G(0x00002110)
+#define HCPOS __REG_2700G(0x00002120)
+#define HCBADR __REG_2700G(0x00002130)
+#define HCCKMSK __REG_2700G(0x00002140)
+#define GPLUT __REG_2700G(0x00002150)
+#define DSCTRL __REG_2700G(0x00002154)
+#define DHT01 __REG_2700G(0x00002158)
+#define DHT02 __REG_2700G(0x0000215c)
+#define DHT03 __REG_2700G(0x00002160)
+#define DVT01 __REG_2700G(0x00002164)
+#define DVT02 __REG_2700G(0x00002168)
+#define DVT03 __REG_2700G(0x0000216c)
+#define DBCOL __REG_2700G(0x00002170)
+#define BGCOLOR __REG_2700G(0x00002174)
+#define DINTRS __REG_2700G(0x00002178)
+#define DINTRE __REG_2700G(0x0000217c)
+#define DINTRCNT __REG_2700G(0x00002180)
+#define DSIG __REG_2700G(0x00002184)
+#define DMCTRL __REG_2700G(0x00002188)
+#define CLIPCTRL __REG_2700G(0x0000218c)
+#define SPOCTRL __REG_2700G(0x00002190)
+#define SVCTRL __REG_2700G(0x00002194)
+
+/* 0x0000_2198 */
+/* 0x0000_21A8 VSCOEFF[0:4] Video Scalar Vertical Coefficient [0:4] 4.14.5 */
+#define VSCOEFF0 __REG_2700G(0x00002198)
+#define VSCOEFF1 __REG_2700G(0x0000219c)
+#define VSCOEFF2 __REG_2700G(0x000021a0)
+#define VSCOEFF3 __REG_2700G(0x000021a4)
+#define VSCOEFF4 __REG_2700G(0x000021a8)
+
+#define SHCTRL __REG_2700G(0x000021b0)
+
+/* 0x0000_21B4 */
+/* 0x0000_21D4 HSCOEFF[0:8] Video Scalar Horizontal Coefficient [0:8] 4.14.7 */
+#define HSCOEFF0 __REG_2700G(0x000021b4)
+#define HSCOEFF1 __REG_2700G(0x000021b8)
+#define HSCOEFF2 __REG_2700G(0x000021bc)
+#define HSCOEFF3 __REG_2700G(0x000021b0)
+#define HSCOEFF4 __REG_2700G(0x000021c4)
+#define HSCOEFF5 __REG_2700G(0x000021c8)
+#define HSCOEFF6 __REG_2700G(0x000021cc)
+#define HSCOEFF7 __REG_2700G(0x000021d0)
+#define HSCOEFF8 __REG_2700G(0x000021d4)
+
+#define SSSIZE __REG_2700G(0x000021D8)
+
+/* 0x0000_2200 */
+/* 0x0000_2240 VIDGAM[0:16] Video Gamma LUT Index [0:16] 4.15.2 */
+#define VIDGAM0 __REG_2700G(0x00002200)
+#define VIDGAM1 __REG_2700G(0x00002204)
+#define VIDGAM2 __REG_2700G(0x00002208)
+#define VIDGAM3 __REG_2700G(0x0000220c)
+#define VIDGAM4 __REG_2700G(0x00002210)
+#define VIDGAM5 __REG_2700G(0x00002214)
+#define VIDGAM6 __REG_2700G(0x00002218)
+#define VIDGAM7 __REG_2700G(0x0000221c)
+#define VIDGAM8 __REG_2700G(0x00002220)
+#define VIDGAM9 __REG_2700G(0x00002224)
+#define VIDGAM10 __REG_2700G(0x00002228)
+#define VIDGAM11 __REG_2700G(0x0000222c)
+#define VIDGAM12 __REG_2700G(0x00002230)
+#define VIDGAM13 __REG_2700G(0x00002234)
+#define VIDGAM14 __REG_2700G(0x00002238)
+#define VIDGAM15 __REG_2700G(0x0000223c)
+#define VIDGAM16 __REG_2700G(0x00002240)
+
+/* 0x0000_2250 */
+/* 0x0000_2290 GFXGAM[0:16] Graphics Gamma LUT Index [0:16] 4.15.3 */
+#define GFXGAM0 __REG_2700G(0x00002250)
+#define GFXGAM1 __REG_2700G(0x00002254)
+#define GFXGAM2 __REG_2700G(0x00002258)
+#define GFXGAM3 __REG_2700G(0x0000225c)
+#define GFXGAM4 __REG_2700G(0x00002260)
+#define GFXGAM5 __REG_2700G(0x00002264)
+#define GFXGAM6 __REG_2700G(0x00002268)
+#define GFXGAM7 __REG_2700G(0x0000226c)
+#define GFXGAM8 __REG_2700G(0x00002270)
+#define GFXGAM9 __REG_2700G(0x00002274)
+#define GFXGAM10 __REG_2700G(0x00002278)
+#define GFXGAM11 __REG_2700G(0x0000227c)
+#define GFXGAM12 __REG_2700G(0x00002280)
+#define GFXGAM13 __REG_2700G(0x00002284)
+#define GFXGAM14 __REG_2700G(0x00002288)
+#define GFXGAM15 __REG_2700G(0x0000228c)
+#define GFXGAM16 __REG_2700G(0x00002290)
+
+#define DLSTS __REG_2700G(0x00002300)
+#define DLLCTRL __REG_2700G(0x00002304)
+#define DVLNUM __REG_2700G(0x00002308)
+#define DUCTRL __REG_2700G(0x0000230c)
+#define DVECTRL __REG_2700G(0x00002310)
+#define DHDET __REG_2700G(0x00002314)
+#define DVDET __REG_2700G(0x00002318)
+#define DODMSK __REG_2700G(0x0000231c)
+#define CSC01 __REG_2700G(0x00002330)
+#define CSC02 __REG_2700G(0x00002334)
+#define CSC03 __REG_2700G(0x00002338)
+#define CSC04 __REG_2700G(0x0000233c)
+#define CSC05 __REG_2700G(0x00002340)
+
+#define FB_MEMORY_START __REG_2700G(0x00060000)
+
+#endif /* __REGS_2700G_ */
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 26a1c618a20..d1267904c28 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -12,7 +12,6 @@
*/
#include <linux/module.h>
-#include <linux/tty.h>
#include <linux/fb.h>
#include <linux/sched.h>
@@ -259,6 +258,10 @@ static const struct fb_videomode modedb[] = {
/* 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
+ }, {
+ /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */
+ NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5,
+ 0, FB_VMODE_NONINTERLACED
},
};
@@ -787,8 +790,9 @@ struct fb_videomode *fb_find_best_mode(struct fb_var_screeninfo *var,
if (diff > d) {
diff = d;
best = mode;
- } else if (diff == d && mode->refresh > best->refresh)
- best = mode;
+ } else if (diff == d && best &&
+ mode->refresh > best->refresh)
+ best = mode;
}
}
return best;
@@ -1016,8 +1020,6 @@ EXPORT_SYMBOL(fb_videomode_to_var);
EXPORT_SYMBOL(fb_var_to_videomode);
EXPORT_SYMBOL(fb_mode_is_equal);
EXPORT_SYMBOL(fb_add_videomode);
-EXPORT_SYMBOL(fb_delete_videomode);
-EXPORT_SYMBOL(fb_destroy_modelist);
EXPORT_SYMBOL(fb_match_mode);
EXPORT_SYMBOL(fb_find_best_mode);
EXPORT_SYMBOL(fb_find_nearest_mode);
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 24b12f71d5a..59a6f5fa5ae 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -54,13 +54,11 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -1333,17 +1331,22 @@ static int neofb_blank(int blank_mode, struct fb_info *info)
* run "setterm -powersave powerdown" to take advantage
*/
struct neofb_par *par = info->par;
- int seqflags, lcdflags, dpmsflags, reg;
-
+ int seqflags, lcdflags, dpmsflags, reg, tmpdisp;
/*
- * Reload the value stored in the register, if sensible. It might have
- * been changed via FN keystroke.
+ * Read back the register bits related to display configuration. They might
+ * have been changed underneath the driver via Fn key stroke.
+ */
+ neoUnlock();
+ tmpdisp = vga_rgfx(NULL, 0x20) & 0x03;
+ neoLock(&par->state);
+
+ /* In case we blank the screen, we want to store the possibly new
+ * configuration in the driver. During un-blank, we re-apply this setting,
+ * since the LCD bit will be cleared in order to switch off the backlight.
*/
if (par->PanelDispCntlRegRead) {
- neoUnlock();
- par->PanelDispCntlReg1 = vga_rgfx(NULL, 0x20) & 0x03;
- neoLock(&par->state);
+ par->PanelDispCntlReg1 = tmpdisp;
}
par->PanelDispCntlRegRead = !blank_mode;
@@ -1378,12 +1381,21 @@ static int neofb_blank(int blank_mode, struct fb_info *info)
break;
case FB_BLANK_NORMAL: /* just blank screen (backlight stays on) */
seqflags = VGA_SR01_SCREEN_OFF; /* Disable sequencer */
- lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+ /*
+ * During a blank operation with the LID shut, we might store "LCD off"
+ * by mistake. Due to timing issues, the BIOS may switch the lights
+ * back on, and we turn it back off once we "unblank".
+ *
+ * So here is an attempt to implement ">=" - if we are in the process
+ * of unblanking, and the LCD bit is unset in the driver but set in the
+ * register, we must keep it.
+ */
+ lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
dpmsflags = 0x00; /* no hsync/vsync suppression */
break;
case FB_BLANK_UNBLANK: /* unblank */
seqflags = 0; /* Enable sequencer */
- lcdflags = par->PanelDispCntlReg1 & 0x02; /* LCD normal */
+ lcdflags = ((par->PanelDispCntlReg1 | tmpdisp) & 0x02); /* LCD normal */
dpmsflags = 0x00; /* no hsync/vsync suppression */
#ifdef CONFIG_TOSHIBA
/* Do we still need this ? */
diff --git a/drivers/video/nvidia/Makefile b/drivers/video/nvidia/Makefile
index 690d37e8de5..ca47432113e 100644
--- a/drivers/video/nvidia/Makefile
+++ b/drivers/video/nvidia/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_FB_NVIDIA) += nvidiafb.o
nvidiafb-y := nvidia.o nv_hw.o nv_setup.o \
nv_accel.o
nvidiafb-$(CONFIG_FB_NVIDIA_I2C) += nv_i2c.o
+nvidiafb-$(CONFIG_FB_NVIDIA_BACKLIGHT) += nv_backlight.o
nvidiafb-$(CONFIG_PPC_OF) += nv_of.o
-nvidiafb-objs := $(nvidiafb-y) \ No newline at end of file
+nvidiafb-objs := $(nvidiafb-y)
diff --git a/drivers/video/nvidia/nv_backlight.c b/drivers/video/nvidia/nv_backlight.c
new file mode 100644
index 00000000000..5b75ae4e945
--- /dev/null
+++ b/drivers/video/nvidia/nv_backlight.c
@@ -0,0 +1,203 @@
+/*
+ * Backlight code for nVidia based graphic cards
+ *
+ * Copyright 2004 Antonino Daplas <adaplas@pol.net>
+ * Copyright (c) 2006 Michael Hanselmann <linux-kernel@hansmi.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include "nv_local.h"
+#include "nv_type.h"
+#include "nv_proto.h"
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+#include <asm/backlight.h>
+#include <asm/machdep.h>
+#endif
+
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
+
+static struct backlight_properties nvidia_bl_data;
+
+/* Call with fb_info->bl_mutex held */
+static int nvidia_bl_get_level_brightness(struct nvidia_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ int nlevel;
+
+ /* Get and convert the value */
+ nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
+
+ if (nlevel < 0)
+ nlevel = 0;
+ else if (nlevel < MIN_LEVEL)
+ nlevel = MIN_LEVEL;
+ else if (nlevel > MAX_LEVEL)
+ nlevel = MAX_LEVEL;
+
+ return nlevel;
+}
+
+/* Call with fb_info->bl_mutex held */
+static int __nvidia_bl_update_status(struct backlight_device *bd)
+{
+ struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+ u32 tmp_pcrt, tmp_pmc, fpcontrol;
+ int level;
+
+ if (!par->FlatPanel)
+ return 0;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
+ tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
+ fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
+
+ if (level > 0) {
+ tmp_pcrt |= 0x1;
+ tmp_pmc |= (1 << 31); /* backlight bit */
+ tmp_pmc |= nvidia_bl_get_level_brightness(par, level) << 16;
+ fpcontrol |= par->fpSyncs;
+ } else
+ fpcontrol |= 0x20000022;
+
+ NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
+ NV_WR32(par->PMC, 0x10F0, tmp_pmc);
+ NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
+
+ return 0;
+}
+
+static int nvidia_bl_update_status(struct backlight_device *bd)
+{
+ struct nvidia_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ int ret;
+
+ mutex_lock(&info->bl_mutex);
+ ret = __nvidia_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
+static int nvidia_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties nvidia_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = nvidia_bl_get_brightness,
+ .update_status = nvidia_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
+};
+
+void nvidia_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __nvidia_bl_update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+
+ mutex_unlock(&info->bl_mutex);
+}
+
+void nvidia_bl_init(struct nvidia_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+ struct backlight_device *bd;
+ char name[12];
+
+ if (!par->FlatPanel)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!machine_is(powermac) ||
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "nvidiabl%d", info->node);
+
+ bd = backlight_device_register(name, par, &nvidia_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk(KERN_WARNING "nvidia: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ down(&bd->sem);
+ bd->props->brightness = nvidia_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ up(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("nvidia: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+void nvidia_bl_exit(struct nvidia_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pci_dev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("nvidia: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
diff --git a/drivers/video/nvidia/nv_hw.c b/drivers/video/nvidia/nv_hw.c
index 99c3a8e6a23..9ed640d3572 100644
--- a/drivers/video/nvidia/nv_hw.c
+++ b/drivers/video/nvidia/nv_hw.c
@@ -886,7 +886,10 @@ void NVCalcStateExt(struct nvidia_par *par,
case NV_ARCH_20:
case NV_ARCH_30:
default:
- if (((par->Chipset & 0xffff) == 0x01A0) ||
+ if ((par->Chipset & 0xfff0) == 0x0240) {
+ state->arbitration0 = 256;
+ state->arbitration1 = 0x0480;
+ } else if (((par->Chipset & 0xffff) == 0x01A0) ||
((par->Chipset & 0xffff) == 0x01f0)) {
nForceUpdateArbitrationSettings(VClk,
pixelDepth * 8,
@@ -1235,6 +1238,7 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
break;
case 0x0160:
case 0x01D0:
+ case 0x0240:
NV_WR32(par->PMC, 0x1700,
NV_RD32(par->PFB, 0x020C));
NV_WR32(par->PMC, 0x1704, 0);
@@ -1359,7 +1363,9 @@ void NVLoadStateExt(struct nvidia_par *par, RIVA_HW_STATE * state)
if(((par->Chipset & 0xfff0)
!= 0x0160) &&
((par->Chipset & 0xfff0)
- != 0x0220))
+ != 0x0220) &&
+ ((par->Chipset & 0xfff0)
+ != 0x240))
NV_WR32(par->PGRAPH,
0x6900 + i*4,
NV_RD32(par->PFB,
diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c
index 1edb1c432b7..19eef3a0902 100644
--- a/drivers/video/nvidia/nv_i2c.c
+++ b/drivers/video/nvidia/nv_i2c.c
@@ -10,7 +10,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/video/nvidia/nv_of.c b/drivers/video/nvidia/nv_of.c
index 7a03d040b1a..d9af88c2b58 100644
--- a/drivers/video/nvidia/nv_of.c
+++ b/drivers/video/nvidia/nv_of.c
@@ -10,7 +10,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -33,7 +32,7 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
{
struct nvidia_par *par = info->par;
struct device_node *parent, *dp;
- unsigned char *pedid = NULL;
+ const unsigned char *pedid = NULL;
static char *propnames[] = {
"DFP,EDID", "LCD,EDID", "EDID", "EDID1",
"EDID,B", "EDID,A", NULL };
@@ -43,20 +42,19 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
if (parent == NULL)
return -1;
if (par->twoHeads) {
- char *pname;
+ const char *pname;
int len;
for (dp = NULL;
(dp = of_get_next_child(parent, dp)) != NULL;) {
- pname = (char *)get_property(dp, "name", NULL);
+ pname = get_property(dp, "name", NULL);
if (!pname)
continue;
len = strlen(pname);
if ((pname[len-1] == 'A' && conn == 1) ||
(pname[len-1] == 'B' && conn == 2)) {
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = (unsigned char *)
- get_property(dp, propnames[i],
+ pedid = get_property(dp, propnames[i],
NULL);
if (pedid != NULL)
break;
@@ -68,8 +66,7 @@ int nvidia_probe_of_connector(struct fb_info *info, int conn, u8 **out_edid)
}
if (pedid == NULL) {
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = (unsigned char *)
- get_property(parent, propnames[i], NULL);
+ pedid = get_property(parent, propnames[i], NULL);
if (pedid != NULL)
break;
}
diff --git a/drivers/video/nvidia/nv_proto.h b/drivers/video/nvidia/nv_proto.h
index b149a690ee0..86127101765 100644
--- a/drivers/video/nvidia/nv_proto.h
+++ b/drivers/video/nvidia/nv_proto.h
@@ -63,4 +63,16 @@ extern void nvidiafb_imageblit(struct fb_info *info,
const struct fb_image *image);
extern int nvidiafb_sync(struct fb_info *info);
extern u8 byte_rev[256];
+
+/* in nv_backlight.h */
+#ifdef CONFIG_FB_NVIDIA_BACKLIGHT
+extern void nvidia_bl_init(struct nvidia_par *par);
+extern void nvidia_bl_exit(struct nvidia_par *par);
+extern void nvidia_bl_set_power(struct fb_info *info, int power);
+#else
+static inline void nvidia_bl_init(struct nvidia_par *par) {}
+static inline void nvidia_bl_exit(struct nvidia_par *par) {}
+static inline void nvidia_bl_set_power(struct fb_info *info, int power) {}
+#endif
+
#endif /* __NV_PROTO_H__ */
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index 093ab9977c7..f8cd4c519ae 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -9,19 +9,18 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/console.h>
+#include <linux/backlight.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
@@ -29,20 +28,12 @@
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#endif
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/machdep.h>
-#include <asm/backlight.h>
-#endif
#include "nv_local.h"
#include "nv_type.h"
#include "nv_proto.h"
#include "nv_dma.h"
-#ifndef CONFIG_PCI /* sanity check */
-#error This driver requires PCI support.
-#endif
-
#undef CONFIG_FB_NVIDIA_DEBUG
#ifdef CONFIG_FB_NVIDIA_DEBUG
#define NVTRACE printk
@@ -70,359 +61,10 @@
#define MAX_CURS 32
static struct pci_device_id nvidiafb_pci_tbl[] = {
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UTNT2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_VTNT2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_UVTNT2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_ITNT2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_IGEFORCE2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE3_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_DDC,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6600,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0252,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0313,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0316,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0317,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x031D,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x031E,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x031F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0329,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x032F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0345,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0349,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x034B,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x034F,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x00c0,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_6800A_LE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_GO1400,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x00cd,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_QUADRO_FX_1400,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0142,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0143,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0144,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0145,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0146,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0147,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0148,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0149,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x014b,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x14c,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x014d,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0160,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0162,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0163,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0165,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0169,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x016b,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x016c,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x016d,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x016e,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0210,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x021d,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x021e,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0220,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0221,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0222,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {PCI_VENDOR_ID_NVIDIA, 0x0228,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- {0,} /* terminate list */
+ {PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
+ PCI_BASE_CLASS_DISPLAY << 16, 0xff0000, 0},
+ { 0, }
};
-
MODULE_DEVICE_TABLE(pci, nvidiafb_pci_tbl);
/* command line data, set in nvidiafb_setup() */
@@ -470,75 +112,6 @@ static struct fb_var_screeninfo __devinitdata nvidiafb_default_var = {
.vmode = FB_VMODE_NONINTERLACED
};
-/*
- * Backlight control
- */
-#ifdef CONFIG_PMAC_BACKLIGHT
-
-static int nvidia_backlight_levels[] = {
- 0x158,
- 0x192,
- 0x1c6,
- 0x200,
- 0x234,
- 0x268,
- 0x2a2,
- 0x2d6,
- 0x310,
- 0x344,
- 0x378,
- 0x3b2,
- 0x3e6,
- 0x41a,
- 0x454,
- 0x534,
-};
-
-/* ------------------------------------------------------------------------- *
- *
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-static int nvidia_set_backlight_enable(int on, int level, void *data)
-{
- struct nvidia_par *par = data;
- u32 tmp_pcrt, tmp_pmc, fpcontrol;
-
- tmp_pmc = NV_RD32(par->PMC, 0x10F0) & 0x0000FFFF;
- tmp_pcrt = NV_RD32(par->PCRTC0, 0x081C) & 0xFFFFFFFC;
- fpcontrol = NV_RD32(par->PRAMDAC, 0x0848) & 0xCFFFFFCC;
-
- if (on && (level > BACKLIGHT_OFF)) {
- tmp_pcrt |= 0x1;
- tmp_pmc |= (1 << 31); // backlight bit
- tmp_pmc |= nvidia_backlight_levels[level - 1] << 16;
- }
-
- if (on)
- fpcontrol |= par->fpSyncs;
- else
- fpcontrol |= 0x20000022;
-
- NV_WR32(par->PCRTC0, 0x081C, tmp_pcrt);
- NV_WR32(par->PMC, 0x10F0, tmp_pmc);
- NV_WR32(par->PRAMDAC, 0x848, fpcontrol);
-
- return 0;
-}
-
-static int nvidia_set_backlight_level(int level, void *data)
-{
- return nvidia_set_backlight_enable(1, level, data);
-}
-
-static struct backlight_controller nvidia_backlight_controller = {
- nvidia_set_backlight_enable,
- nvidia_set_backlight_level
-};
-
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
static void nvidiafb_load_cursor_image(struct nvidia_par *par, u8 * data8,
u16 bg, u16 fg, u32 w, u32 h)
{
@@ -1355,11 +928,7 @@ static int nvidiafb_blank(int blank, struct fb_info *info)
NVWriteSeq(par, 0x01, tmp);
NVWriteCrtc(par, 0x1a, vesa);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (par->FlatPanel && machine_is(powermac)) {
- set_backlight_enable(!blank);
- }
-#endif
+ nvidia_bl_set_power(info, blank);
NVTRACE_LEAVE();
@@ -1381,24 +950,25 @@ static struct fb_ops nvidia_fb_ops = {
};
#ifdef CONFIG_PM
-static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t state)
+static int nvidiafb_suspend(struct pci_dev *dev, pm_message_t mesg)
{
struct fb_info *info = pci_get_drvdata(dev);
struct nvidia_par *par = info->par;
+ if (mesg.event == PM_EVENT_PRETHAW)
+ mesg.event = PM_EVENT_FREEZE;
acquire_console_sem();
- par->pm_state = state.event;
+ par->pm_state = mesg.event;
- if (state.event == PM_EVENT_FREEZE) {
- dev->dev.power.power_state = state;
- } else {
+ if (mesg.event == PM_EVENT_SUSPEND) {
fb_set_suspend(info, 1);
nvidiafb_blank(FB_BLANK_POWERDOWN, info);
nvidia_write_regs(par, &par->SavedReg);
pci_save_state(dev);
pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
+ pci_set_power_state(dev, pci_choose_state(dev, mesg));
}
+ dev->dev.power.power_state = mesg;
release_console_sem();
return 0;
@@ -1532,10 +1102,10 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info)
struct nvidia_par *par = info->par;
u32 id = (par->pci_dev->vendor << 16) | par->pci_dev->device;
- printk("nvidiafb: PCI id - %x\n", id);
+ printk(KERN_INFO PFX "Device ID: %x \n", id);
+
if ((id & 0xfff0) == 0x00f0) {
/* pci-e */
- printk("nvidiafb: PCI-E card\n");
id = NV_RD32(par->REGS, 0x1800);
if ((id & 0x0000ffff) == 0x000010DE)
@@ -1543,9 +1113,9 @@ static u32 __devinit nvidia_get_chipset(struct fb_info *info)
else if ((id & 0xffff0000) == 0xDE100000) /* wrong endian */
id = 0x10DE0000 | ((id << 8) & 0x0000ff00) |
((id >> 8) & 0x000000ff);
+ printk(KERN_INFO PFX "Subsystem ID: %x \n", id);
}
- printk("nvidiafb: Actual id - %x\n", id);
return id;
}
@@ -1587,6 +1157,7 @@ static u32 __devinit nvidia_get_arch(struct fb_info *info)
case 0x0210:
case 0x0220:
case 0x0230:
+ case 0x0240:
case 0x0290:
case 0x0390:
arch = NV_ARCH_40;
@@ -1634,7 +1205,7 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
if (pci_request_regions(pd, "nvidiafb")) {
printk(KERN_ERR PFX "cannot request PCI regions\n");
- goto err_out_request;
+ goto err_out_enable;
}
par->FlatPanel = flatpanel;
@@ -1663,7 +1234,6 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
}
par->Chipset = nvidia_get_chipset(info);
- printk(KERN_INFO PFX "nVidia device/chipset %X\n", par->Chipset);
par->Architecture = nvidia_get_arch(info);
if (par->Architecture == 0) {
@@ -1730,22 +1300,19 @@ static int __devinit nvidiafb_probe(struct pci_dev *pd,
nvidia_save_vga(par, &par->SavedReg);
+ pci_set_drvdata(pd, info);
+ nvidia_bl_init(par);
if (register_framebuffer(info) < 0) {
printk(KERN_ERR PFX "error registering nVidia framebuffer\n");
goto err_out_iounmap_fb;
}
- pci_set_drvdata(pd, info);
printk(KERN_INFO PFX
"PCI nVidia %s framebuffer (%dMB @ 0x%lX)\n",
info->fix.id,
par->FbMapSize / (1024 * 1024), info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (par->FlatPanel && machine_is(powermac))
- register_backlight_controller(&nvidia_backlight_controller,
- par, "mnca");
-#endif
+
NVTRACE_LEAVE();
return 0;
@@ -1756,10 +1323,8 @@ err_out_free_base1:
nvidia_delete_i2c_busses(par);
err_out_arch:
iounmap(par->REGS);
-err_out_free_base0:
+ err_out_free_base0:
pci_release_regions(pd);
-err_out_request:
- pci_disable_device(pd);
err_out_enable:
kfree(info->pixmap.addr);
err_out_kfree:
@@ -1775,6 +1340,8 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
+ nvidia_bl_exit(par);
+
unregister_framebuffer(info);
#ifdef CONFIG_MTRR
if (par->mtrr.vram_valid)
@@ -1787,7 +1354,6 @@ static void __exit nvidiafb_remove(struct pci_dev *pd)
nvidia_delete_i2c_busses(par);
iounmap(par->REGS);
pci_release_regions(pd);
- pci_disable_device(pd);
kfree(info->pixmap.addr);
framebuffer_release(info);
pci_set_drvdata(pd, NULL);
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index ad1434e3f22..bad0e98fb3b 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -12,13 +12,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -64,8 +62,6 @@ struct offb_par default_par;
* Interface used by the world
*/
-int offb_init(void);
-
static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static int offb_blank(int blank, struct fb_info *info);
@@ -74,11 +70,6 @@ static int offb_blank(int blank, struct fb_info *info);
extern boot_infos_t *boot_infos;
#endif
-static void offb_init_nodriver(struct device_node *);
-static void offb_init_fb(const char *name, const char *full_name,
- int width, int height, int depth, int pitch,
- unsigned long address, struct device_node *dp);
-
static struct fb_ops offb_ops = {
.owner = THIS_MODULE,
.fb_setcolreg = offb_setcolreg,
@@ -98,14 +89,43 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
struct offb_par *par = (struct offb_par *) info->par;
+ int i, depth;
+ u32 *pal = info->pseudo_palette;
- if (!par->cmap_adr || regno > 255)
+ depth = info->var.bits_per_pixel;
+ if (depth == 16)
+ depth = (info->var.green.length == 5) ? 15 : 16;
+
+ if (regno > 255 ||
+ (depth == 16 && regno > 63) ||
+ (depth == 15 && regno > 31))
return 1;
+ if (regno < 16) {
+ switch (depth) {
+ case 15:
+ pal[regno] = (regno << 10) | (regno << 5) | regno;
+ break;
+ case 16:
+ pal[regno] = (regno << 11) | (regno << 5) | regno;
+ break;
+ case 24:
+ pal[regno] = (regno << 16) | (regno << 8) | regno;
+ break;
+ case 32:
+ i = (regno << 8) | regno;
+ pal[regno] = (i << 16) | i;
+ break;
+ }
+ }
+
red >>= 8;
green >>= 8;
blue >>= 8;
+ if (!par->cmap_adr)
+ return 0;
+
switch (par->cmap_type) {
case cmap_m64:
writeb(regno, par->cmap_adr);
@@ -142,20 +162,6 @@ static int offb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
break;
}
- if (regno < 16)
- switch (info->var.bits_per_pixel) {
- case 16:
- ((u16 *) (info->pseudo_palette))[regno] =
- (regno << 10) | (regno << 5) | regno;
- break;
- case 32:
- {
- int i = (regno << 8) | regno;
- ((u32 *) (info->pseudo_palette))[regno] =
- (i << 16) | i;
- break;
- }
- }
return 0;
}
@@ -216,196 +222,17 @@ static int offb_blank(int blank, struct fb_info *info)
return 0;
}
- /*
- * Initialisation
- */
-int __init offb_init(void)
+static void __iomem *offb_map_reg(struct device_node *np, int index,
+ unsigned long offset, unsigned long size)
{
- struct device_node *dp = NULL, *boot_disp = NULL;
-
-#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
- struct device_node *macos_display = NULL;
-#endif
- if (fb_get_options("offb", NULL))
- return -ENODEV;
-
-#if defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32)
- /* If we're booted from BootX... */
- if (boot_infos != 0) {
- unsigned long addr =
- (unsigned long) boot_infos->dispDeviceBase;
- u32 *addrp;
- u64 daddr, dsize;
- unsigned int flags;
-
- /* find the device node corresponding to the macos display */
- while ((dp = of_find_node_by_type(dp, "display"))) {
- int i;
-
- /*
- * Look for an AAPL,address property first.
- */
- unsigned int na;
- unsigned int *ap =
- (unsigned int *)get_property(dp, "AAPL,address",
- &na);
- if (ap != 0) {
- for (na /= sizeof(unsigned int); na > 0;
- --na, ++ap)
- if (*ap <= addr &&
- addr < *ap + 0x1000000) {
- macos_display = dp;
- goto foundit;
- }
- }
-
- /*
- * See if the display address is in one of the address
- * ranges for this display.
- */
- i = 0;
- for (;;) {
- addrp = of_get_address(dp, i++, &dsize, &flags);
- if (addrp == NULL)
- break;
- if (!(flags & IORESOURCE_MEM))
- continue;
- daddr = of_translate_address(dp, addrp);
- if (daddr == OF_BAD_ADDR)
- continue;
- if (daddr <= addr && addr < (daddr + dsize)) {
- macos_display = dp;
- goto foundit;
- }
- }
- foundit:
- if (macos_display) {
- printk(KERN_INFO "MacOS display is %s\n",
- dp->full_name);
- break;
- }
- }
-
- /* initialize it */
- offb_init_fb(macos_display ? macos_display->
- name : "MacOS display",
- macos_display ? macos_display->
- full_name : "MacOS display",
- boot_infos->dispDeviceRect[2],
- boot_infos->dispDeviceRect[3],
- boot_infos->dispDeviceDepth,
- boot_infos->dispDeviceRowBytes, addr, NULL);
- }
-#endif /* defined(CONFIG_BOOTX_TEXT) && defined(CONFIG_PPC32) */
-
- for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
- if (get_property(dp, "linux,opened", NULL) &&
- get_property(dp, "linux,boot-display", NULL)) {
- boot_disp = dp;
- offb_init_nodriver(dp);
- }
- }
- for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
- if (get_property(dp, "linux,opened", NULL) &&
- dp != boot_disp)
- offb_init_nodriver(dp);
- }
-
- return 0;
-}
-
-
-static void __init offb_init_nodriver(struct device_node *dp)
-{
- int *pp, i;
- unsigned int len;
- int width = 640, height = 480, depth = 8, pitch;
- unsigned int flags, rsize, *up;
- u64 address = OF_BAD_ADDR;
- u32 *addrp;
- u64 asize;
-
- if ((pp = (int *) get_property(dp, "depth", &len)) != NULL
- && len == sizeof(int))
- depth = *pp;
- if ((pp = (int *) get_property(dp, "width", &len)) != NULL
- && len == sizeof(int))
- width = *pp;
- if ((pp = (int *) get_property(dp, "height", &len)) != NULL
- && len == sizeof(int))
- height = *pp;
- if ((pp = (int *) get_property(dp, "linebytes", &len)) != NULL
- && len == sizeof(int)) {
- pitch = *pp;
- if (pitch == 1)
- pitch = 0x1000;
- } else
- pitch = width;
-
- rsize = (unsigned long)pitch * (unsigned long)height *
- (unsigned long)(depth / 8);
-
- /* Try to match device to a PCI device in order to get a properly
- * translated address rather then trying to decode the open firmware
- * stuff in various incorrect ways
- */
-#ifdef CONFIG_PCI
- /* First try to locate the PCI device if any */
- {
- struct pci_dev *pdev = NULL;
-
- for_each_pci_dev(pdev) {
- if (dp == pci_device_to_OF_node(pdev))
- break;
- }
- if (pdev) {
- for (i = 0; i < 6 && address == OF_BAD_ADDR; i++) {
- if ((pci_resource_flags(pdev, i) &
- IORESOURCE_MEM) &&
- (pci_resource_len(pdev, i) >= rsize))
- address = pci_resource_start(pdev, i);
- }
- pci_dev_put(pdev);
- }
- }
-#endif /* CONFIG_PCI */
-
- /* This one is dodgy, we may drop it ... */
- if (address == OF_BAD_ADDR &&
- (up = (unsigned *) get_property(dp, "address", &len)) != NULL &&
- len == sizeof(unsigned int))
- address = (u64) * up;
-
- if (address == OF_BAD_ADDR) {
- for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
- != NULL; i++) {
- if (!(flags & IORESOURCE_MEM))
- continue;
- if (asize >= pitch * height * depth / 8)
- break;
- }
- if (addrp == NULL) {
- printk(KERN_ERR
- "no framebuffer address found for %s\n",
- dp->full_name);
- return;
- }
- address = of_translate_address(dp, addrp);
- if (address == OF_BAD_ADDR) {
- printk(KERN_ERR
- "can't translate framebuffer address for %s\n",
- dp->full_name);
- return;
- }
-
- /* kludge for valkyrie */
- if (strcmp(dp->name, "valkyrie") == 0)
- address += 0x1000;
- }
- offb_init_fb(dp->name, dp->full_name, width, height, depth,
- pitch, address, dp);
+ struct resource r;
+ if (of_address_to_resource(np, index, &r))
+ return 0;
+ if ((r.start + offset + size) > r.end)
+ return 0;
+ return ioremap(r.start + offset, size);
}
static void __init offb_init_fb(const char *name, const char *full_name,
@@ -413,7 +240,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
int pitch, unsigned long address,
struct device_node *dp)
{
- unsigned long res_size = pitch * height * depth / 8;
+ unsigned long res_size = pitch * height * (depth + 7) / 8;
struct offb_par *par = &default_par;
unsigned long res_start = address;
struct fb_fix_screeninfo *fix;
@@ -427,7 +254,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
printk(KERN_INFO
"Using unsupported %dx%d %s at %lx, depth=%d, pitch=%d\n",
width, height, name, address, depth, pitch);
- if (depth != 8 && depth != 16 && depth != 32) {
+ if (depth != 8 && depth != 15 && depth != 16 && depth != 32) {
printk(KERN_ERR "%s: can't use depth = %d\n", full_name,
depth);
release_mem_region(res_start, res_size);
@@ -462,48 +289,41 @@ static void __init offb_init_fb(const char *name, const char *full_name,
par->cmap_type = cmap_unknown;
if (depth == 8) {
-
/* Palette hacks disabled for now */
-#if 0
if (dp && !strncmp(name, "ATY,Rage128", 11)) {
- unsigned long regbase = dp->addrs[2].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_r128;
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_r128;
} else if (dp && (!strncmp(name, "ATY,RageM3pA", 12)
|| !strncmp(name, "ATY,RageM3p12A", 14))) {
- unsigned long regbase =
- dp->parent->addrs[2].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_M3A;
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_M3A;
} else if (dp && !strncmp(name, "ATY,RageM3pB", 12)) {
- unsigned long regbase =
- dp->parent->addrs[2].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_M3B;
+ par->cmap_adr = offb_map_reg(dp, 2, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_M3B;
} else if (dp && !strncmp(name, "ATY,Rage6", 9)) {
- unsigned long regbase = dp->addrs[1].address;
- par->cmap_adr = ioremap(regbase, 0x1FFF);
- par->cmap_type = cmap_radeon;
+ par->cmap_adr = offb_map_reg(dp, 1, 0, 0x1fff);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_radeon;
} else if (!strncmp(name, "ATY,", 4)) {
unsigned long base = address & 0xff000000UL;
par->cmap_adr =
ioremap(base + 0x7ff000, 0x1000) + 0xcc0;
par->cmap_data = par->cmap_adr + 1;
par->cmap_type = cmap_m64;
- } else if (device_is_compatible(dp, "pci1014,b7")) {
- unsigned long regbase = dp->addrs[0].address;
- par->cmap_adr = ioremap(regbase + 0x6000, 0x1000);
- par->cmap_type = cmap_gxt2000;
+ } else if (dp && device_is_compatible(dp, "pci1014,b7")) {
+ par->cmap_adr = offb_map_reg(dp, 0, 0x6000, 0x1000);
+ if (par->cmap_adr)
+ par->cmap_type = cmap_gxt2000;
}
-#endif
- fix->visual = par->cmap_adr ? FB_VISUAL_PSEUDOCOLOR
- : FB_VISUAL_STATIC_PSEUDOCOLOR;
+ fix->visual = (par->cmap_type != cmap_unknown) ?
+ FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR;
} else
- fix->visual = /* par->cmap_adr ? FB_VISUAL_DIRECTCOLOR
- : */ FB_VISUAL_TRUECOLOR;
+ fix->visual = FB_VISUAL_TRUECOLOR;
var->xoffset = var->yoffset = 0;
- var->bits_per_pixel = depth;
switch (depth) {
case 8:
var->bits_per_pixel = 8;
@@ -516,7 +336,7 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var->transp.offset = 0;
var->transp.length = 0;
break;
- case 16: /* RGB 555 */
+ case 15: /* RGB 555 */
var->bits_per_pixel = 16;
var->red.offset = 10;
var->red.length = 5;
@@ -527,6 +347,17 @@ static void __init offb_init_fb(const char *name, const char *full_name,
var->transp.offset = 0;
var->transp.length = 0;
break;
+ case 16: /* RGB 565 */
+ var->bits_per_pixel = 16;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
case 32: /* RGB 888 */
var->bits_per_pixel = 32;
var->red.offset = 16;
@@ -570,5 +401,139 @@ static void __init offb_init_fb(const char *name, const char *full_name,
info->node, full_name);
}
+
+static void __init offb_init_nodriver(struct device_node *dp, int no_real_node)
+{
+ unsigned int len;
+ int i, width = 640, height = 480, depth = 8, pitch = 640;
+ unsigned int flags, rsize, addr_prop = 0;
+ unsigned long max_size = 0;
+ u64 rstart, address = OF_BAD_ADDR;
+ const u32 *pp, *addrp, *up;
+ u64 asize;
+
+ pp = get_property(dp, "linux,bootx-depth", &len);
+ if (pp == NULL)
+ pp = get_property(dp, "depth", &len);
+ if (pp && len == sizeof(u32))
+ depth = *pp;
+
+ pp = get_property(dp, "linux,bootx-width", &len);
+ if (pp == NULL)
+ pp = get_property(dp, "width", &len);
+ if (pp && len == sizeof(u32))
+ width = *pp;
+
+ pp = get_property(dp, "linux,bootx-height", &len);
+ if (pp == NULL)
+ pp = get_property(dp, "height", &len);
+ if (pp && len == sizeof(u32))
+ height = *pp;
+
+ pp = get_property(dp, "linux,bootx-linebytes", &len);
+ if (pp == NULL)
+ pp = get_property(dp, "linebytes", &len);
+ if (pp && len == sizeof(u32))
+ pitch = *pp;
+ else
+ pitch = width * ((depth + 7) / 8);
+
+ rsize = (unsigned long)pitch * (unsigned long)height;
+
+ /* Ok, now we try to figure out the address of the framebuffer.
+ *
+ * Unfortunately, Open Firmware doesn't provide a standard way to do
+ * so. All we can do is a dodgy heuristic that happens to work in
+ * practice. On most machines, the "address" property contains what
+ * we need, though not on Matrox cards found in IBM machines. What I've
+ * found that appears to give good results is to go through the PCI
+ * ranges and pick one that is both big enough and if possible encloses
+ * the "address" property. If none match, we pick the biggest
+ */
+ up = get_property(dp, "linux,bootx-addr", &len);
+ if (up == NULL)
+ up = get_property(dp, "address", &len);
+ if (up && len == sizeof(u32))
+ addr_prop = *up;
+
+ /* Hack for when BootX is passing us */
+ if (no_real_node)
+ goto skip_addr;
+
+ for (i = 0; (addrp = of_get_address(dp, i, &asize, &flags))
+ != NULL; i++) {
+ int match_addrp = 0;
+
+ if (!(flags & IORESOURCE_MEM))
+ continue;
+ if (asize < rsize)
+ continue;
+ rstart = of_translate_address(dp, addrp);
+ if (rstart == OF_BAD_ADDR)
+ continue;
+ if (addr_prop && (rstart <= addr_prop) &&
+ ((rstart + asize) >= (addr_prop + rsize)))
+ match_addrp = 1;
+ if (match_addrp) {
+ address = addr_prop;
+ break;
+ }
+ if (rsize > max_size) {
+ max_size = rsize;
+ address = OF_BAD_ADDR;
+ }
+
+ if (address == OF_BAD_ADDR)
+ address = rstart;
+ }
+ skip_addr:
+ if (address == OF_BAD_ADDR && addr_prop)
+ address = (u64)addr_prop;
+ if (address != OF_BAD_ADDR) {
+ /* kludge for valkyrie */
+ if (strcmp(dp->name, "valkyrie") == 0)
+ address += 0x1000;
+ offb_init_fb(no_real_node ? "bootx" : dp->name,
+ no_real_node ? "display" : dp->full_name,
+ width, height, depth, pitch, address,
+ no_real_node ? dp : NULL);
+ }
+}
+
+static int __init offb_init(void)
+{
+ struct device_node *dp = NULL, *boot_disp = NULL;
+
+ if (fb_get_options("offb", NULL))
+ return -ENODEV;
+
+ /* Check if we have a MacOS display without a node spec */
+ if (get_property(of_chosen, "linux,bootx-noscreen", NULL) != NULL) {
+ /* The old code tried to work out which node was the MacOS
+ * display based on the address. I'm dropping that since the
+ * lack of a node spec only happens with old BootX versions
+ * (users can update) and with this code, they'll still get
+ * a display (just not the palette hacks).
+ */
+ offb_init_nodriver(of_chosen, 1);
+ }
+
+ for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
+ if (get_property(dp, "linux,opened", NULL) &&
+ get_property(dp, "linux,boot-display", NULL)) {
+ boot_disp = dp;
+ offb_init_nodriver(dp, 0);
+ }
+ }
+ for (dp = NULL; (dp = of_find_node_by_type(dp, "display"));) {
+ if (get_property(dp, "linux,opened", NULL) &&
+ dp != boot_disp)
+ offb_init_nodriver(dp, 0);
+ }
+
+ return 0;
+}
+
+
module_init(offb_init);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index 0d195750535..56ac51d6a7f 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -1,6 +1,6 @@
/* p9100.c: P9100 frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright 1999 Derrick J Brashear (shadow@dementia.org)
*
* Driver layout based loosely on tgafb.c, see that file for credits.
@@ -17,8 +17,8 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -72,60 +72,60 @@ static struct fb_ops p9100_ops = {
struct p9100_regs {
/* Registers for the system control */
- volatile u32 sys_base;
- volatile u32 sys_config;
- volatile u32 sys_intr;
- volatile u32 sys_int_ena;
- volatile u32 sys_alt_rd;
- volatile u32 sys_alt_wr;
- volatile u32 sys_xxx[58];
+ u32 sys_base;
+ u32 sys_config;
+ u32 sys_intr;
+ u32 sys_int_ena;
+ u32 sys_alt_rd;
+ u32 sys_alt_wr;
+ u32 sys_xxx[58];
/* Registers for the video control */
- volatile u32 vid_base;
- volatile u32 vid_hcnt;
- volatile u32 vid_htotal;
- volatile u32 vid_hsync_rise;
- volatile u32 vid_hblank_rise;
- volatile u32 vid_hblank_fall;
- volatile u32 vid_hcnt_preload;
- volatile u32 vid_vcnt;
- volatile u32 vid_vlen;
- volatile u32 vid_vsync_rise;
- volatile u32 vid_vblank_rise;
- volatile u32 vid_vblank_fall;
- volatile u32 vid_vcnt_preload;
- volatile u32 vid_screenpaint_addr;
- volatile u32 vid_screenpaint_timectl1;
- volatile u32 vid_screenpaint_qsfcnt;
- volatile u32 vid_screenpaint_timectl2;
- volatile u32 vid_xxx[15];
+ u32 vid_base;
+ u32 vid_hcnt;
+ u32 vid_htotal;
+ u32 vid_hsync_rise;
+ u32 vid_hblank_rise;
+ u32 vid_hblank_fall;
+ u32 vid_hcnt_preload;
+ u32 vid_vcnt;
+ u32 vid_vlen;
+ u32 vid_vsync_rise;
+ u32 vid_vblank_rise;
+ u32 vid_vblank_fall;
+ u32 vid_vcnt_preload;
+ u32 vid_screenpaint_addr;
+ u32 vid_screenpaint_timectl1;
+ u32 vid_screenpaint_qsfcnt;
+ u32 vid_screenpaint_timectl2;
+ u32 vid_xxx[15];
/* Registers for the video control */
- volatile u32 vram_base;
- volatile u32 vram_memcfg;
- volatile u32 vram_refresh_pd;
- volatile u32 vram_refresh_cnt;
- volatile u32 vram_raslo_max;
- volatile u32 vram_raslo_cur;
- volatile u32 pwrup_cfg;
- volatile u32 vram_xxx[25];
+ u32 vram_base;
+ u32 vram_memcfg;
+ u32 vram_refresh_pd;
+ u32 vram_refresh_cnt;
+ u32 vram_raslo_max;
+ u32 vram_raslo_cur;
+ u32 pwrup_cfg;
+ u32 vram_xxx[25];
/* Registers for IBM RGB528 Palette */
- volatile u32 ramdac_cmap_wridx;
- volatile u32 ramdac_palette_data;
- volatile u32 ramdac_pixel_mask;
- volatile u32 ramdac_palette_rdaddr;
- volatile u32 ramdac_idx_lo;
- volatile u32 ramdac_idx_hi;
- volatile u32 ramdac_idx_data;
- volatile u32 ramdac_idx_ctl;
- volatile u32 ramdac_xxx[1784];
+ u32 ramdac_cmap_wridx;
+ u32 ramdac_palette_data;
+ u32 ramdac_pixel_mask;
+ u32 ramdac_palette_rdaddr;
+ u32 ramdac_idx_lo;
+ u32 ramdac_idx_hi;
+ u32 ramdac_idx_data;
+ u32 ramdac_idx_ctl;
+ u32 ramdac_xxx[1784];
};
struct p9100_cmd_parameng {
- volatile u32 parameng_status;
- volatile u32 parameng_bltcmd;
- volatile u32 parameng_quadcmd;
+ u32 parameng_status;
+ u32 parameng_bltcmd;
+ u32 parameng_quadcmd;
};
struct p9100_par {
@@ -136,9 +136,8 @@ struct p9100_par {
#define P9100_FLAG_BLANKED 0x00000001
unsigned long physbase;
+ unsigned long which_io;
unsigned long fbsize;
-
- struct sbus_dev *sdev;
};
/**
@@ -227,8 +226,7 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
return sbusfb_mmap_helper(p9100_mmap_map,
par->physbase, par->fbsize,
- par->sdev->reg_addrs[0].which_io,
- vma);
+ par->which_io, vma);
}
static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
@@ -245,12 +243,9 @@ static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
* Initialisation
*/
-static void
-p9100_init_fix(struct fb_info *info, int linebytes)
+static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
{
- struct p9100_par *par = (struct p9100_par *)info->par;
-
- strlcpy(info->fix.id, par->sdev->prom_name, sizeof(info->fix.id));
+ strlcpy(info->fix.id, dp->name, sizeof(info->fix.id));
info->fix.type = FB_TYPE_PACKED_PIXELS;
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
@@ -263,121 +258,137 @@ p9100_init_fix(struct fb_info *info, int linebytes)
struct all_info {
struct fb_info info;
struct p9100_par par;
- struct list_head list;
};
-static LIST_HEAD(p9100_list);
-static void p9100_init_one(struct sbus_dev *sdev)
+static int __devinit p9100_init_one(struct of_device *op)
{
+ struct device_node *dp = op->node;
struct all_info *all;
- int linebytes;
-
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "p9100: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
+ int linebytes, err;
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- all->par.sdev = sdev;
/* This is the framebuffer and the only resource apps can mmap. */
- all->par.physbase = sdev->reg_addrs[2].phys_addr;
+ all->par.physbase = op->resource[2].start;
+ all->par.which_io = op->resource[2].flags & IORESOURCE_BITS;
- sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+ sbusfb_fill_var(&all->info.var, dp->node, 8);
all->info.var.red.length = 8;
all->info.var.green.length = 8;
all->info.var.blue.length = 8;
- linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
- all->info.var.xres);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
- all->par.regs = sbus_ioremap(&sdev->resource[0], 0,
- sizeof(struct p9100_regs), "p9100 regs");
+ all->par.regs = of_ioremap(&op->resource[0], 0,
+ sizeof(struct p9100_regs), "p9100 regs");
+ if (!all->par.regs) {
+ kfree(all);
+ return -ENOMEM;
+ }
all->info.flags = FBINFO_DEFAULT;
all->info.fbops = &p9100_ops;
-#ifdef CONFIG_SPARC32
- all->info.screen_base = (char __iomem *)
- prom_getintdefault(sdev->prom_node, "address", 0);
-#endif
- if (!all->info.screen_base)
- all->info.screen_base = sbus_ioremap(&sdev->resource[2], 0,
- all->par.fbsize, "p9100 ram");
+ all->info.screen_base = of_ioremap(&op->resource[2], 0,
+ all->par.fbsize, "p9100 ram");
+ if (!all->info.screen_base) {
+ of_iounmap(all->par.regs, sizeof(struct p9100_regs));
+ kfree(all);
+ return -ENOMEM;
+ }
all->info.par = &all->par;
p9100_blank(0, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "p9100: Could not allocate color map.\n");
+ of_iounmap(all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
kfree(all);
- return;
+ return -ENOMEM;
}
- p9100_init_fix(&all->info, linebytes);
+ p9100_init_fix(&all->info, linebytes, dp);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "p9100: Could not register framebuffer.\n");
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
+ of_iounmap(all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
kfree(all);
- return;
+ return err;
}
fb_set_cmap(&all->info.cmap, &all->info);
- list_add(&all->list, &p9100_list);
+ dev_set_drvdata(&op->dev, all);
+
+ printk("%s: p9100 at %lx:%lx\n",
+ dp->full_name,
+ all->par.which_io, all->par.physbase);
- printk("p9100: %s at %lx:%lx\n",
- sdev->prom_name,
- (long) sdev->reg_addrs[0].which_io,
- (long) sdev->reg_addrs[0].phys_addr);
+ return 0;
}
-int __init p9100_init(void)
+static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("p9100fb", NULL))
- return -ENODEV;
+ return p9100_init_one(op);
+}
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "p9100"))
- p9100_init_one(sdev);
- }
+static int __devexit p9100_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+
+ of_iounmap(all->par.regs, sizeof(struct p9100_regs));
+ of_iounmap(all->info.screen_base, all->par.fbsize);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit p9100_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id p9100_match[] = {
+ {
+ .name = "p9100",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, p9100_match);
- list_for_each_safe(pos, tmp, &p9100_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver p9100_driver = {
+ .name = "p9100",
+ .match_table = p9100_match,
+ .probe = p9100_probe,
+ .remove = __devexit_p(p9100_remove),
+};
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+static int __init p9100_init(void)
+{
+ if (fb_get_options("p9100fb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&p9100_driver, &of_bus_type);
}
-int __init
-p9100_setup(char *arg)
+static void __exit p9100_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&p9100_driver);
}
module_init(p9100_init);
-
-#ifdef MODULE
module_exit(p9100_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 335e3746555..983be3ec234 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -17,13 +17,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c
index 4e963930b50..a560a222382 100644
--- a/drivers/video/pm2fb.c
+++ b/drivers/video/pm2fb.c
@@ -27,14 +27,12 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c
index 52c18a35fb4..1d81ef47efd 100644
--- a/drivers/video/pm3fb.c
+++ b/drivers/video/pm3fb.c
@@ -52,13 +52,11 @@
* Wed Feb 21 14:47:06 CET 2001, v 1.0.0: First working version
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c
index d92f352211e..68ca3cc4077 100644
--- a/drivers/video/pmag-aa-fb.c
+++ b/drivers/video/pmag-aa-fb.c
@@ -29,7 +29,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
diff --git a/drivers/video/pnx4008/Makefile b/drivers/video/pnx4008/Makefile
new file mode 100644
index 00000000000..636aaccf01f
--- /dev/null
+++ b/drivers/video/pnx4008/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the new PNX4008 framebuffer device driver
+#
+
+obj-$(CONFIG_FB_PNX4008_DUM) += sdum.o
+obj-$(CONFIG_FB_PNX4008_DUM_RGB) += pnxrgbfb.o
+
diff --git a/drivers/video/pnx4008/dum.h b/drivers/video/pnx4008/dum.h
new file mode 100644
index 00000000000..d80a614d89e
--- /dev/null
+++ b/drivers/video/pnx4008/dum.h
@@ -0,0 +1,211 @@
+/*
+ * linux/drivers/video/pnx4008/dum.h
+ *
+ * Internal header for SDUM
+ *
+ * 2005 (c) Koninklijke Philips N.V. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#ifndef __PNX008_DUM_H__
+#define __PNX008_DUM_H__
+
+#include <asm/arch/platform.h>
+
+#define PNX4008_DUMCONF_VA_BASE IO_ADDRESS(PNX4008_DUMCONF_BASE)
+#define PNX4008_DUM_MAIN_VA_BASE IO_ADDRESS(PNX4008_DUM_MAINCFG_BASE)
+
+/* DUM CFG ADDRESSES */
+#define DUM_CH_BASE_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
+#define DUM_CH_MIN_ADR (PNX4008_DUMCONF_VA_BASE + 0x00)
+#define DUM_CH_MAX_ADR (PNX4008_DUMCONF_VA_BASE + 0x04)
+#define DUM_CH_CONF_ADR (PNX4008_DUMCONF_VA_BASE + 0x08)
+#define DUM_CH_STAT_ADR (PNX4008_DUMCONF_VA_BASE + 0x0C)
+#define DUM_CH_CTRL_ADR (PNX4008_DUMCONF_VA_BASE + 0x10)
+
+#define CH_MARG (0x100 / sizeof(u32))
+#define DUM_CH_MIN(i) (*((volatile u32 *)DUM_CH_MIN_ADR + (i) * CH_MARG))
+#define DUM_CH_MAX(i) (*((volatile u32 *)DUM_CH_MAX_ADR + (i) * CH_MARG))
+#define DUM_CH_CONF(i) (*((volatile u32 *)DUM_CH_CONF_ADR + (i) * CH_MARG))
+#define DUM_CH_STAT(i) (*((volatile u32 *)DUM_CH_STAT_ADR + (i) * CH_MARG))
+#define DUM_CH_CTRL(i) (*((volatile u32 *)DUM_CH_CTRL_ADR + (i) * CH_MARG))
+
+#define DUM_CONF_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x00)
+#define DUM_CTRL_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x04)
+#define DUM_STAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x08)
+#define DUM_DECODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x0C)
+#define DUM_COM_BASE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x10)
+#define DUM_SYNC_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x14)
+#define DUM_CLK_DIV_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x18)
+#define DUM_DIRTY_LOW_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x20)
+#define DUM_DIRTY_HIGH_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x24)
+#define DUM_FORMAT_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x28)
+#define DUM_WTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x30)
+#define DUM_RTCFG1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x34)
+#define DUM_WTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x38)
+#define DUM_RTCFG2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x3C)
+#define DUM_TCFG_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x40)
+#define DUM_OUTP_FORMAT1_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x44)
+#define DUM_OUTP_FORMAT2_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x48)
+#define DUM_SYNC_MODE_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x4C)
+#define DUM_SYNC_OUT_C_ADR (PNX4008_DUM_MAIN_VA_BASE + 0x50)
+
+#define DUM_CONF (*(volatile u32 *)(DUM_CONF_ADR))
+#define DUM_CTRL (*(volatile u32 *)(DUM_CTRL_ADR))
+#define DUM_STAT (*(volatile u32 *)(DUM_STAT_ADR))
+#define DUM_DECODE (*(volatile u32 *)(DUM_DECODE_ADR))
+#define DUM_COM_BASE (*(volatile u32 *)(DUM_COM_BASE_ADR))
+#define DUM_SYNC_C (*(volatile u32 *)(DUM_SYNC_C_ADR))
+#define DUM_CLK_DIV (*(volatile u32 *)(DUM_CLK_DIV_ADR))
+#define DUM_DIRTY_LOW (*(volatile u32 *)(DUM_DIRTY_LOW_ADR))
+#define DUM_DIRTY_HIGH (*(volatile u32 *)(DUM_DIRTY_HIGH_ADR))
+#define DUM_FORMAT (*(volatile u32 *)(DUM_FORMAT_ADR))
+#define DUM_WTCFG1 (*(volatile u32 *)(DUM_WTCFG1_ADR))
+#define DUM_RTCFG1 (*(volatile u32 *)(DUM_RTCFG1_ADR))
+#define DUM_WTCFG2 (*(volatile u32 *)(DUM_WTCFG2_ADR))
+#define DUM_RTCFG2 (*(volatile u32 *)(DUM_RTCFG2_ADR))
+#define DUM_TCFG (*(volatile u32 *)(DUM_TCFG_ADR))
+#define DUM_OUTP_FORMAT1 (*(volatile u32 *)(DUM_OUTP_FORMAT1_ADR))
+#define DUM_OUTP_FORMAT2 (*(volatile u32 *)(DUM_OUTP_FORMAT2_ADR))
+#define DUM_SYNC_MODE (*(volatile u32 *)(DUM_SYNC_MODE_ADR))
+#define DUM_SYNC_OUT_C (*(volatile u32 *)(DUM_SYNC_OUT_C_ADR))
+
+/* DUM SLAVE ADDRESSES */
+#define DUM_SLAVE_WRITE_ADR (PNX4008_DUM_MAINCFG_BASE + 0x0000000)
+#define DUM_SLAVE_READ1_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000000)
+#define DUM_SLAVE_READ1_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000004)
+#define DUM_SLAVE_READ2_I_ADR (PNX4008_DUM_MAINCFG_BASE + 0x1000008)
+#define DUM_SLAVE_READ2_R_ADR (PNX4008_DUM_MAINCFG_BASE + 0x100000C)
+
+#define DUM_SLAVE_WRITE_W ((volatile u32 *)(DUM_SLAVE_WRITE_ADR))
+#define DUM_SLAVE_WRITE_HW ((volatile u16 *)(DUM_SLAVE_WRITE_ADR))
+#define DUM_SLAVE_READ1_I ((volatile u8 *)(DUM_SLAVE_READ1_I_ADR))
+#define DUM_SLAVE_READ1_R ((volatile u16 *)(DUM_SLAVE_READ1_R_ADR))
+#define DUM_SLAVE_READ2_I ((volatile u8 *)(DUM_SLAVE_READ2_I_ADR))
+#define DUM_SLAVE_READ2_R ((volatile u16 *)(DUM_SLAVE_READ2_R_ADR))
+
+/* Sony display register addresses */
+#define DISP_0_REG (0x00)
+#define DISP_1_REG (0x01)
+#define DISP_CAL_REG (0x20)
+#define DISP_ID_REG (0x2A)
+#define DISP_XMIN_L_REG (0x30)
+#define DISP_XMIN_H_REG (0x31)
+#define DISP_YMIN_REG (0x32)
+#define DISP_XMAX_L_REG (0x34)
+#define DISP_XMAX_H_REG (0x35)
+#define DISP_YMAX_REG (0x36)
+#define DISP_SYNC_EN_REG (0x38)
+#define DISP_SYNC_RISE_L_REG (0x3C)
+#define DISP_SYNC_RISE_H_REG (0x3D)
+#define DISP_SYNC_FALL_L_REG (0x3E)
+#define DISP_SYNC_FALL_H_REG (0x3F)
+#define DISP_PIXEL_REG (0x0B)
+#define DISP_DUMMY1_REG (0x28)
+#define DISP_DUMMY2_REG (0x29)
+#define DISP_TIMING_REG (0x98)
+#define DISP_DUMP_REG (0x99)
+
+/* Sony display constants */
+#define SONY_ID1 (0x22)
+#define SONY_ID2 (0x23)
+
+/* Philips display register addresses */
+#define PH_DISP_ORIENT_REG (0x003)
+#define PH_DISP_YPOINT_REG (0x200)
+#define PH_DISP_XPOINT_REG (0x201)
+#define PH_DISP_PIXEL_REG (0x202)
+#define PH_DISP_YMIN_REG (0x406)
+#define PH_DISP_YMAX_REG (0x407)
+#define PH_DISP_XMIN_REG (0x408)
+#define PH_DISP_XMAX_REG (0x409)
+
+/* Misc constants */
+#define NO_VALID_DISPLAY_FOUND (0)
+#define DISPLAY2_IS_NOT_CONNECTED (0)
+
+/* register values */
+#define V_BAC_ENABLE (BIT(0))
+#define V_BAC_DISABLE_IDLE (BIT(1))
+#define V_BAC_DISABLE_TRIG (BIT(2))
+#define V_DUM_RESET (BIT(3))
+#define V_MUX_RESET (BIT(4))
+#define BAC_ENABLED (BIT(0))
+#define BAC_DISABLED 0
+
+/* Sony LCD commands */
+#define V_LCD_STANDBY_OFF ((BIT(25)) | (0 << 16) | DISP_0_REG)
+#define V_LCD_USE_9BIT_BUS ((BIT(25)) | (2 << 16) | DISP_1_REG)
+#define V_LCD_SYNC_RISE_L ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_L_REG)
+#define V_LCD_SYNC_RISE_H ((BIT(25)) | (0 << 16) | DISP_SYNC_RISE_H_REG)
+#define V_LCD_SYNC_FALL_L ((BIT(25)) | (160 << 16) | DISP_SYNC_FALL_L_REG)
+#define V_LCD_SYNC_FALL_H ((BIT(25)) | (0 << 16) | DISP_SYNC_FALL_H_REG)
+#define V_LCD_SYNC_ENABLE ((BIT(25)) | (128 << 16) | DISP_SYNC_EN_REG)
+#define V_LCD_DISPLAY_ON ((BIT(25)) | (64 << 16) | DISP_0_REG)
+
+enum {
+ PAD_NONE,
+ PAD_512,
+ PAD_1024
+};
+
+enum {
+ RGB888,
+ RGB666,
+ RGB565,
+ BGR565,
+ ARGB1555,
+ ABGR1555,
+ ARGB4444,
+ ABGR4444
+};
+
+struct dum_setup {
+ int sync_neg_edge;
+ int round_robin;
+ int mux_int;
+ int synced_dirty_flag_int;
+ int dirty_flag_int;
+ int error_int;
+ int pf_empty_int;
+ int sf_empty_int;
+ int bac_dis_int;
+ u32 dirty_base_adr;
+ u32 command_base_adr;
+ u32 sync_clk_div;
+ int sync_output;
+ u32 sync_restart_val;
+ u32 set_sync_high;
+ u32 set_sync_low;
+};
+
+struct dum_ch_setup {
+ int disp_no;
+ u32 xmin;
+ u32 ymin;
+ u32 xmax;
+ u32 ymax;
+ int xmirror;
+ int ymirror;
+ int rotate;
+ u32 minadr;
+ u32 maxadr;
+ u32 dirtybuffer;
+ int pad;
+ int format;
+ int hwdirty;
+ int slave_trans;
+};
+
+struct disp_window {
+ u32 xmin_l;
+ u32 xmin_h;
+ u32 ymin;
+ u32 xmax_l;
+ u32 xmax_h;
+ u32 ymax;
+};
+
+#endif /* #ifndef __PNX008_DUM_H__ */
diff --git a/drivers/video/pnx4008/fbcommon.h b/drivers/video/pnx4008/fbcommon.h
new file mode 100644
index 00000000000..4ebc87dafaf
--- /dev/null
+++ b/drivers/video/pnx4008/fbcommon.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2005 Philips Semiconductors
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
+*/
+
+#define QCIF_W (176)
+#define QCIF_H (144)
+
+#define CIF_W (352)
+#define CIF_H (288)
+
+#define LCD_X_RES 208
+#define LCD_Y_RES 320
+#define LCD_X_PAD 256
+#define LCD_BBP 4 /* Bytes Per Pixel */
+
+#define DISP_MAX_X_SIZE (320)
+#define DISP_MAX_Y_SIZE (208)
+
+#define RETURNVAL_BASE (0x400)
+
+enum fb_ioctl_returntype {
+ ENORESOURCESLEFT = RETURNVAL_BASE,
+ ERESOURCESNOTFREED,
+ EPROCNOTOWNER,
+ EFBNOTOWNER,
+ ECOPYFAILED,
+ EIOREMAPFAILED,
+};
diff --git a/drivers/video/pnx4008/pnxrgbfb.c b/drivers/video/pnx4008/pnxrgbfb.c
new file mode 100644
index 00000000000..7d9453c91a4
--- /dev/null
+++ b/drivers/video/pnx4008/pnxrgbfb.c
@@ -0,0 +1,213 @@
+/*
+ * drivers/video/pnx4008/pnxrgbfb.c
+ *
+ * PNX4008's framebuffer support
+ *
+ * Author: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
+ * Based on Philips Semiconductors's code
+ *
+ * Copyrght (c) 2005 MontaVista Software, Inc.
+ * Copyright (c) 2005 Philips Semiconductors
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/uaccess.h>
+#include "sdum.h"
+#include "fbcommon.h"
+
+static u32 colreg[16];
+
+static struct fb_var_screeninfo rgbfb_var __initdata = {
+ .xres = LCD_X_RES,
+ .yres = LCD_Y_RES,
+ .xres_virtual = LCD_X_RES,
+ .yres_virtual = LCD_Y_RES,
+ .bits_per_pixel = 32,
+ .red.offset = 16,
+ .red.length = 8,
+ .green.offset = 8,
+ .green.length = 8,
+ .blue.offset = 0,
+ .blue.length = 8,
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .vmode = FB_VMODE_NONINTERLACED,
+};
+static struct fb_fix_screeninfo rgbfb_fix __initdata = {
+ .id = "RGBFB",
+ .line_length = LCD_X_RES * LCD_BBP,
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+ .accel = FB_ACCEL_NONE,
+};
+
+static int channel_owned;
+
+static int no_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ return 0;
+}
+
+static int rgbfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int transp, struct fb_info *info)
+{
+ if (regno > 15)
+ return 1;
+
+ colreg[regno] = ((red & 0xff00) << 8) | (green & 0xff00) |
+ ((blue & 0xff00) >> 8);
+ return 0;
+}
+
+static int rgbfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+ return pnx4008_sdum_mmap(info, vma, NULL);
+}
+
+static struct fb_ops rgbfb_ops = {
+ .fb_mmap = rgbfb_mmap,
+ .fb_setcolreg = rgbfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+};
+
+static int rgbfb_remove(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+
+ if (info) {
+ unregister_framebuffer(info);
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
+ platform_set_drvdata(pdev, NULL);
+ kfree(info);
+ }
+
+ pnx4008_free_dum_channel(channel_owned, pdev->id);
+ pnx4008_set_dum_exit_notification(pdev->id);
+
+ return 0;
+}
+
+static int __devinit rgbfb_probe(struct platform_device *pdev)
+{
+ struct fb_info *info;
+ struct dumchannel_uf chan_uf;
+ int ret;
+ char *option;
+
+ info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
+ if (!info) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ pnx4008_get_fb_addresses(FB_TYPE_RGB, (void **)&info->screen_base,
+ (dma_addr_t *) &rgbfb_fix.smem_start,
+ &rgbfb_fix.smem_len);
+
+ if ((ret = pnx4008_alloc_dum_channel(pdev->id)) < 0)
+ goto err0;
+ else {
+ channel_owned = ret;
+ chan_uf.channelnr = channel_owned;
+ chan_uf.dirty = (u32 *) NULL;
+ chan_uf.source = (u32 *) rgbfb_fix.smem_start;
+ chan_uf.x_offset = 0;
+ chan_uf.y_offset = 0;
+ chan_uf.width = LCD_X_RES;
+ chan_uf.height = LCD_Y_RES;
+
+ if ((ret = pnx4008_put_dum_channel_uf(chan_uf, pdev->id))< 0)
+ goto err1;
+
+ if ((ret =
+ pnx4008_set_dum_channel_sync(channel_owned, CONF_SYNC_ON,
+ pdev->id)) < 0)
+ goto err1;
+
+ if ((ret =
+ pnx4008_set_dum_channel_dirty_detect(channel_owned,
+ CONF_DIRTYDETECTION_ON,
+ pdev->id)) < 0)
+ goto err1;
+ }
+
+ if (!fb_get_options("pnxrgbfb", &option) && !strcmp(option, "nocursor"))
+ rgbfb_ops.fb_cursor = no_cursor;
+
+ info->node = -1;
+ info->flags = FBINFO_FLAG_DEFAULT;
+ info->fbops = &rgbfb_ops;
+ info->fix = rgbfb_fix;
+ info->var = rgbfb_var;
+ info->screen_size = rgbfb_fix.smem_len;
+ info->pseudo_palette = info->par;
+ info->par = NULL;
+
+ ret = fb_alloc_cmap(&info->cmap, 256, 0);
+ if (ret < 0)
+ goto err2;
+
+ ret = register_framebuffer(info);
+ if (ret < 0)
+ goto err3;
+ platform_set_drvdata(pdev, info);
+
+ return 0;
+
+err3:
+ fb_dealloc_cmap(&info->cmap);
+err2:
+ framebuffer_release(info);
+err1:
+ pnx4008_free_dum_channel(channel_owned, pdev->id);
+err0:
+ kfree(info);
+err:
+ return ret;
+}
+
+static struct platform_driver rgbfb_driver = {
+ .driver = {
+ .name = "rgbfb",
+ },
+ .probe = rgbfb_probe,
+ .remove = rgbfb_remove,
+};
+
+static int __init rgbfb_init(void)
+{
+ return platform_driver_register(&rgbfb_driver);
+}
+
+static void __exit rgbfb_exit(void)
+{
+ platform_driver_unregister(&rgbfb_driver);
+}
+
+module_init(rgbfb_init);
+module_exit(rgbfb_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pnx4008/sdum.c b/drivers/video/pnx4008/sdum.c
new file mode 100644
index 00000000000..51f0ecc2a51
--- /dev/null
+++ b/drivers/video/pnx4008/sdum.c
@@ -0,0 +1,872 @@
+/*
+ * drivers/video/pnx4008/sdum.c
+ *
+ * Display Update Master support
+ *
+ * Authors: Grigory Tolstolytkin <gtolstolytkin@ru.mvista.com>
+ * Vitaly Wool <vitalywool@gmail.com>
+ * Based on Philips Semiconductors's code
+ *
+ * Copyrght (c) 2005-2006 MontaVista Software, Inc.
+ * Copyright (c) 2005 Philips Semiconductors
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+#include <asm/uaccess.h>
+#include <asm/arch/gpio.h>
+
+#include "sdum.h"
+#include "fbcommon.h"
+#include "dum.h"
+
+/* Framebuffers we have */
+
+static struct pnx4008_fb_addr {
+ int fb_type;
+ long addr_offset;
+ long fb_length;
+} fb_addr[] = {
+ [0] = {
+ FB_TYPE_YUV, 0, 0xB0000
+ },
+ [1] = {
+ FB_TYPE_RGB, 0xB0000, 0x50000
+ },
+};
+
+static struct dum_data {
+ u32 lcd_phys_start;
+ u32 lcd_virt_start;
+ u32 slave_phys_base;
+ u32 *slave_virt_base;
+ int fb_owning_channel[MAX_DUM_CHANNELS];
+ struct dumchannel_uf chan_uf_store[MAX_DUM_CHANNELS];
+} dum_data;
+
+/* Different local helper functions */
+
+static u32 nof_pixels_dx(struct dum_ch_setup *ch_setup)
+{
+ return (ch_setup->xmax - ch_setup->xmin + 1);
+}
+
+static u32 nof_pixels_dy(struct dum_ch_setup *ch_setup)
+{
+ return (ch_setup->ymax - ch_setup->ymin + 1);
+}
+
+static u32 nof_pixels_dxy(struct dum_ch_setup *ch_setup)
+{
+ return (nof_pixels_dx(ch_setup) * nof_pixels_dy(ch_setup));
+}
+
+static u32 nof_bytes(struct dum_ch_setup *ch_setup)
+{
+ u32 r = nof_pixels_dxy(ch_setup);
+ switch (ch_setup->format) {
+ case RGB888:
+ case RGB666:
+ r *= 4;
+ break;
+
+ default:
+ r *= 2;
+ break;
+ }
+ return r;
+}
+
+static u32 build_command(int disp_no, u32 reg, u32 val)
+{
+ return ((disp_no << 26) | BIT(25) | (val << 16) | (disp_no << 10) |
+ (reg << 0));
+}
+
+static u32 build_double_index(int disp_no, u32 val)
+{
+ return ((disp_no << 26) | (val << 16) | (disp_no << 10) | (val << 0));
+}
+
+static void build_disp_window(struct dum_ch_setup * ch_setup, struct disp_window * dw)
+{
+ dw->ymin = ch_setup->ymin;
+ dw->ymax = ch_setup->ymax;
+ dw->xmin_l = ch_setup->xmin & 0xFF;
+ dw->xmin_h = (ch_setup->xmin & BIT(8)) >> 8;
+ dw->xmax_l = ch_setup->xmax & 0xFF;
+ dw->xmax_h = (ch_setup->xmax & BIT(8)) >> 8;
+}
+
+static int put_channel(struct dumchannel chan)
+{
+ int i = chan.channelnr;
+
+ if (i < 0 || i > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else {
+ DUM_CH_MIN(i) = chan.dum_ch_min;
+ DUM_CH_MAX(i) = chan.dum_ch_max;
+ DUM_CH_CONF(i) = chan.dum_ch_conf;
+ DUM_CH_CTRL(i) = chan.dum_ch_ctrl;
+ }
+
+ return 0;
+}
+
+static void clear_channel(int channr)
+{
+ struct dumchannel chan;
+
+ chan.channelnr = channr;
+ chan.dum_ch_min = 0;
+ chan.dum_ch_max = 0;
+ chan.dum_ch_conf = 0;
+ chan.dum_ch_ctrl = 0;
+
+ put_channel(chan);
+}
+
+static int put_cmd_string(struct cmdstring cmds)
+{
+ u16 *cmd_str_virtaddr;
+ u32 *cmd_ptr0_virtaddr;
+ u32 cmd_str_physaddr;
+
+ int i = cmds.channelnr;
+
+ if (i < 0 || i > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if ((cmd_ptr0_virtaddr =
+ (int *)ioremap_nocache(DUM_COM_BASE,
+ sizeof(int) * MAX_DUM_CHANNELS)) ==
+ NULL)
+ return -EIOREMAPFAILED;
+ else {
+ cmd_str_physaddr = ioread32(&cmd_ptr0_virtaddr[cmds.channelnr]);
+ if ((cmd_str_virtaddr =
+ (u16 *) ioremap_nocache(cmd_str_physaddr,
+ sizeof(cmds))) == NULL) {
+ iounmap(cmd_ptr0_virtaddr);
+ return -EIOREMAPFAILED;
+ } else {
+ int t;
+ for (t = 0; t < 8; t++)
+ iowrite16(*((u16 *)&cmds.prestringlen + t),
+ cmd_str_virtaddr + t);
+
+ for (t = 0; t < cmds.prestringlen / 2; t++)
+ iowrite16(*((u16 *)&cmds.precmd + t),
+ cmd_str_virtaddr + t + 8);
+
+ for (t = 0; t < cmds.poststringlen / 2; t++)
+ iowrite16(*((u16 *)&cmds.postcmd + t),
+ cmd_str_virtaddr + t + 8 +
+ cmds.prestringlen / 2);
+
+ iounmap(cmd_ptr0_virtaddr);
+ iounmap(cmd_str_virtaddr);
+ }
+ }
+
+ return 0;
+}
+
+static u32 dum_ch_setup(int ch_no, struct dum_ch_setup * ch_setup)
+{
+ struct cmdstring cmds_c;
+ struct cmdstring *cmds = &cmds_c;
+ struct disp_window dw;
+ int standard;
+ u32 orientation = 0;
+ struct dumchannel chan = { 0 };
+ int ret;
+
+ if ((ch_setup->xmirror) || (ch_setup->ymirror) || (ch_setup->rotate)) {
+ standard = 0;
+
+ orientation = BIT(1); /* always set 9-bit-bus */
+ if (ch_setup->xmirror)
+ orientation |= BIT(4);
+ if (ch_setup->ymirror)
+ orientation |= BIT(3);
+ if (ch_setup->rotate)
+ orientation |= BIT(0);
+ } else
+ standard = 1;
+
+ cmds->channelnr = ch_no;
+
+ /* build command string header */
+ if (standard) {
+ cmds->prestringlen = 32;
+ cmds->poststringlen = 0;
+ } else {
+ cmds->prestringlen = 48;
+ cmds->poststringlen = 16;
+ }
+
+ cmds->format =
+ (u16) ((ch_setup->disp_no << 4) | (BIT(3)) | (ch_setup->format));
+ cmds->reserved = 0x0;
+ cmds->startaddr_low = (ch_setup->minadr & 0xFFFF);
+ cmds->startaddr_high = (ch_setup->minadr >> 16);
+
+ if ((ch_setup->minadr == 0) && (ch_setup->maxadr == 0)
+ && (ch_setup->xmin == 0)
+ && (ch_setup->ymin == 0) && (ch_setup->xmax == 0)
+ && (ch_setup->ymax == 0)) {
+ cmds->pixdatlen_low = 0;
+ cmds->pixdatlen_high = 0;
+ } else {
+ u32 nbytes = nof_bytes(ch_setup);
+ cmds->pixdatlen_low = (nbytes & 0xFFFF);
+ cmds->pixdatlen_high = (nbytes >> 16);
+ }
+
+ if (ch_setup->slave_trans)
+ cmds->pixdatlen_high |= BIT(15);
+
+ /* build pre-string */
+ build_disp_window(ch_setup, &dw);
+
+ if (standard) {
+ cmds->precmd[0] =
+ build_command(ch_setup->disp_no, DISP_XMIN_L_REG, 0x99);
+ cmds->precmd[1] =
+ build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
+ dw.xmin_l);
+ cmds->precmd[2] =
+ build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
+ dw.xmin_h);
+ cmds->precmd[3] =
+ build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
+ cmds->precmd[4] =
+ build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
+ dw.xmax_l);
+ cmds->precmd[5] =
+ build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
+ dw.xmax_h);
+ cmds->precmd[6] =
+ build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
+ cmds->precmd[7] =
+ build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
+ } else {
+ if (dw.xmin_l == ch_no)
+ cmds->precmd[0] =
+ build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
+ 0x99);
+ else
+ cmds->precmd[0] =
+ build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
+ ch_no);
+
+ cmds->precmd[1] =
+ build_command(ch_setup->disp_no, DISP_XMIN_L_REG,
+ dw.xmin_l);
+ cmds->precmd[2] =
+ build_command(ch_setup->disp_no, DISP_XMIN_H_REG,
+ dw.xmin_h);
+ cmds->precmd[3] =
+ build_command(ch_setup->disp_no, DISP_YMIN_REG, dw.ymin);
+ cmds->precmd[4] =
+ build_command(ch_setup->disp_no, DISP_XMAX_L_REG,
+ dw.xmax_l);
+ cmds->precmd[5] =
+ build_command(ch_setup->disp_no, DISP_XMAX_H_REG,
+ dw.xmax_h);
+ cmds->precmd[6] =
+ build_command(ch_setup->disp_no, DISP_YMAX_REG, dw.ymax);
+ cmds->precmd[7] =
+ build_command(ch_setup->disp_no, DISP_1_REG, orientation);
+ cmds->precmd[8] =
+ build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
+ cmds->precmd[9] =
+ build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
+ cmds->precmd[0xA] =
+ build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
+ cmds->precmd[0xB] =
+ build_double_index(ch_setup->disp_no, DISP_PIXEL_REG);
+ cmds->postcmd[0] =
+ build_command(ch_setup->disp_no, DISP_1_REG, BIT(1));
+ cmds->postcmd[1] =
+ build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 1);
+ cmds->postcmd[2] =
+ build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 2);
+ cmds->postcmd[3] =
+ build_command(ch_setup->disp_no, DISP_DUMMY1_REG, 3);
+ }
+
+ if ((ret = put_cmd_string(cmds_c)) != 0) {
+ return ret;
+ }
+
+ chan.channelnr = cmds->channelnr;
+ chan.dum_ch_min = ch_setup->dirtybuffer + ch_setup->minadr;
+ chan.dum_ch_max = ch_setup->dirtybuffer + ch_setup->maxadr;
+ chan.dum_ch_conf = 0x002;
+ chan.dum_ch_ctrl = 0x04;
+
+ put_channel(chan);
+
+ return 0;
+}
+
+static u32 display_open(int ch_no, int auto_update, u32 * dirty_buffer,
+ u32 * frame_buffer, u32 xpos, u32 ypos, u32 w, u32 h)
+{
+
+ struct dum_ch_setup k;
+ int ret;
+
+ /* keep width & height within display area */
+ if ((xpos + w) > DISP_MAX_X_SIZE)
+ w = DISP_MAX_X_SIZE - xpos;
+
+ if ((ypos + h) > DISP_MAX_Y_SIZE)
+ h = DISP_MAX_Y_SIZE - ypos;
+
+ /* assume 1 display only */
+ k.disp_no = 0;
+ k.xmin = xpos;
+ k.ymin = ypos;
+ k.xmax = xpos + (w - 1);
+ k.ymax = ypos + (h - 1);
+
+ /* adjust min and max values if necessary */
+ if (k.xmin > DISP_MAX_X_SIZE - 1)
+ k.xmin = DISP_MAX_X_SIZE - 1;
+ if (k.ymin > DISP_MAX_Y_SIZE - 1)
+ k.ymin = DISP_MAX_Y_SIZE - 1;
+
+ if (k.xmax > DISP_MAX_X_SIZE - 1)
+ k.xmax = DISP_MAX_X_SIZE - 1;
+ if (k.ymax > DISP_MAX_Y_SIZE - 1)
+ k.ymax = DISP_MAX_Y_SIZE - 1;
+
+ k.xmirror = 0;
+ k.ymirror = 0;
+ k.rotate = 0;
+ k.minadr = (u32) frame_buffer;
+ k.maxadr = (u32) frame_buffer + (((w - 1) << 10) | ((h << 2) - 2));
+ k.pad = PAD_1024;
+ k.dirtybuffer = (u32) dirty_buffer;
+ k.format = RGB888;
+ k.hwdirty = 0;
+ k.slave_trans = 0;
+
+ ret = dum_ch_setup(ch_no, &k);
+
+ return ret;
+}
+
+static void lcd_reset(void)
+{
+ u32 *dum_pio_base = (u32 *)IO_ADDRESS(PNX4008_PIO_BASE);
+
+ udelay(1);
+ iowrite32(BIT(19), &dum_pio_base[2]);
+ udelay(1);
+ iowrite32(BIT(19), &dum_pio_base[1]);
+ udelay(1);
+}
+
+static int dum_init(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ /* enable DUM clock */
+ clk = clk_get(&pdev->dev, "dum_ck");
+ if (IS_ERR(clk)) {
+ printk(KERN_ERR "pnx4008_dum: Unable to access DUM clock\n");
+ return PTR_ERR(clk);
+ }
+
+ clk_set_rate(clk, 1);
+ clk_put(clk);
+
+ DUM_CTRL = V_DUM_RESET;
+
+ /* set priority to "round-robin". All other params to "false" */
+ DUM_CONF = BIT(9);
+
+ /* Display 1 */
+ DUM_WTCFG1 = PNX4008_DUM_WT_CFG;
+ DUM_RTCFG1 = PNX4008_DUM_RT_CFG;
+ DUM_TCFG = PNX4008_DUM_T_CFG;
+
+ return 0;
+}
+
+static void dum_chan_init(void)
+{
+ int i = 0, ch = 0;
+ u32 *cmdptrs;
+ u32 *cmdstrings;
+
+ DUM_COM_BASE =
+ CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS;
+
+ if ((cmdptrs =
+ (u32 *) ioremap_nocache(DUM_COM_BASE,
+ sizeof(u32) * NR_OF_CMDSTRINGS)) == NULL)
+ return;
+
+ for (ch = 0; ch < NR_OF_CMDSTRINGS; ch++)
+ iowrite32(CMDSTRING_BASEADDR + BYTES_PER_CMDSTRING * ch,
+ cmdptrs + ch);
+
+ for (ch = 0; ch < MAX_DUM_CHANNELS; ch++)
+ clear_channel(ch);
+
+ /* Clear the cmdstrings */
+ cmdstrings =
+ (u32 *)ioremap_nocache(*cmdptrs,
+ BYTES_PER_CMDSTRING * NR_OF_CMDSTRINGS);
+
+ if (!cmdstrings)
+ goto out;
+
+ for (i = 0; i < NR_OF_CMDSTRINGS * BYTES_PER_CMDSTRING / sizeof(u32);
+ i++)
+ iowrite32(0, cmdstrings + i);
+
+ iounmap((u32 *)cmdstrings);
+
+out:
+ iounmap((u32 *)cmdptrs);
+}
+
+static void lcd_init(void)
+{
+ lcd_reset();
+
+ DUM_OUTP_FORMAT1 = 0; /* RGB666 */
+
+ udelay(1);
+ iowrite32(V_LCD_STANDBY_OFF, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_USE_9BIT_BUS, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_SYNC_RISE_L, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_SYNC_RISE_H, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_SYNC_FALL_L, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_SYNC_FALL_H, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_SYNC_ENABLE, dum_data.slave_virt_base);
+ udelay(1);
+ iowrite32(V_LCD_DISPLAY_ON, dum_data.slave_virt_base);
+ udelay(1);
+}
+
+/* Interface exported to framebuffer drivers */
+
+int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
+ dma_addr_t *phys_addr, int *fb_length)
+{
+ int i;
+ int ret = -1;
+ for (i = 0; i < ARRAY_SIZE(fb_addr); i++)
+ if (fb_addr[i].fb_type == fb_type) {
+ *virt_addr = (void *)(dum_data.lcd_virt_start +
+ fb_addr[i].addr_offset);
+ *phys_addr =
+ dum_data.lcd_phys_start + fb_addr[i].addr_offset;
+ *fb_length = fb_addr[i].fb_length;
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+EXPORT_SYMBOL(pnx4008_get_fb_addresses);
+
+int pnx4008_alloc_dum_channel(int dev_id)
+{
+ int i = 0;
+
+ while ((i < MAX_DUM_CHANNELS) && (dum_data.fb_owning_channel[i] != -1))
+ i++;
+
+ if (i == MAX_DUM_CHANNELS)
+ return -ENORESOURCESLEFT;
+ else {
+ dum_data.fb_owning_channel[i] = dev_id;
+ return i;
+ }
+}
+
+EXPORT_SYMBOL(pnx4008_alloc_dum_channel);
+
+int pnx4008_free_dum_channel(int channr, int dev_id)
+{
+ if (channr < 0 || channr > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if (dum_data.fb_owning_channel[channr] != dev_id)
+ return -EFBNOTOWNER;
+ else {
+ clear_channel(channr);
+ dum_data.fb_owning_channel[channr] = -1;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_free_dum_channel);
+
+int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id)
+{
+ int i = chan_uf.channelnr;
+ int ret;
+
+ if (i < 0 || i > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if (dum_data.fb_owning_channel[i] != dev_id)
+ return -EFBNOTOWNER;
+ else if ((ret =
+ display_open(chan_uf.channelnr, 0, chan_uf.dirty,
+ chan_uf.source, chan_uf.y_offset,
+ chan_uf.x_offset, chan_uf.height,
+ chan_uf.width)) != 0)
+ return ret;
+ else {
+ dum_data.chan_uf_store[i].dirty = chan_uf.dirty;
+ dum_data.chan_uf_store[i].source = chan_uf.source;
+ dum_data.chan_uf_store[i].x_offset = chan_uf.x_offset;
+ dum_data.chan_uf_store[i].y_offset = chan_uf.y_offset;
+ dum_data.chan_uf_store[i].width = chan_uf.width;
+ dum_data.chan_uf_store[i].height = chan_uf.height;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_put_dum_channel_uf);
+
+int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id)
+{
+ if (channr < 0 || channr > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if (dum_data.fb_owning_channel[channr] != dev_id)
+ return -EFBNOTOWNER;
+ else {
+ if (val == CONF_SYNC_ON) {
+ DUM_CH_CONF(channr) |= CONF_SYNCENABLE;
+ DUM_CH_CONF(channr) |= DUM_CHANNEL_CFG_SYNC_MASK |
+ DUM_CHANNEL_CFG_SYNC_MASK_SET;
+ } else if (val == CONF_SYNC_OFF)
+ DUM_CH_CONF(channr) &= ~CONF_SYNCENABLE;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_set_dum_channel_sync);
+
+int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id)
+{
+ if (channr < 0 || channr > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if (dum_data.fb_owning_channel[channr] != dev_id)
+ return -EFBNOTOWNER;
+ else {
+ if (val == CONF_DIRTYDETECTION_ON)
+ DUM_CH_CONF(channr) |= CONF_DIRTYENABLE;
+ else if (val == CONF_DIRTYDETECTION_OFF)
+ DUM_CH_CONF(channr) &= ~CONF_DIRTYENABLE;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_set_dum_channel_dirty_detect);
+
+#if 0 /* Functions not used currently, but likely to be used in future */
+
+static int get_channel(struct dumchannel *p_chan)
+{
+ int i = p_chan->channelnr;
+
+ if (i < 0 || i > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else {
+ p_chan->dum_ch_min = DUM_CH_MIN(i);
+ p_chan->dum_ch_max = DUM_CH_MAX(i);
+ p_chan->dum_ch_conf = DUM_CH_CONF(i);
+ p_chan->dum_ch_stat = DUM_CH_STAT(i);
+ p_chan->dum_ch_ctrl = 0; /* WriteOnly control register */
+ }
+
+ return 0;
+}
+
+int pnx4008_get_dum_channel_uf(struct dumchannel_uf *p_chan_uf, int dev_id)
+{
+ int i = p_chan_uf->channelnr;
+
+ if (i < 0 || i > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if (dum_data.fb_owning_channel[i] != dev_id)
+ return -EFBNOTOWNER;
+ else {
+ p_chan_uf->dirty = dum_data.chan_uf_store[i].dirty;
+ p_chan_uf->source = dum_data.chan_uf_store[i].source;
+ p_chan_uf->x_offset = dum_data.chan_uf_store[i].x_offset;
+ p_chan_uf->y_offset = dum_data.chan_uf_store[i].y_offset;
+ p_chan_uf->width = dum_data.chan_uf_store[i].width;
+ p_chan_uf->height = dum_data.chan_uf_store[i].height;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_get_dum_channel_uf);
+
+int pnx4008_get_dum_channel_config(int channr, int dev_id)
+{
+ int ret;
+ struct dumchannel chan;
+
+ if (channr < 0 || channr > MAX_DUM_CHANNELS)
+ return -EINVAL;
+ else if (dum_data.fb_owning_channel[channr] != dev_id)
+ return -EFBNOTOWNER;
+ else {
+ chan.channelnr = channr;
+ if ((ret = get_channel(&chan)) != 0)
+ return ret;
+ }
+
+ return (chan.dum_ch_conf & DUM_CHANNEL_CFG_MASK);
+}
+
+EXPORT_SYMBOL(pnx4008_get_dum_channel_config);
+
+int pnx4008_force_update_dum_channel(int channr, int dev_id)
+{
+ if (channr < 0 || channr > MAX_DUM_CHANNELS)
+ return -EINVAL;
+
+ else if (dum_data.fb_owning_channel[channr] != dev_id)
+ return -EFBNOTOWNER;
+ else
+ DUM_CH_CTRL(channr) = CTRL_SETDIRTY;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_force_update_dum_channel);
+
+#endif
+
+int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma,
+ struct device *dev)
+{
+ unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
+
+ if (off < info->fix.smem_len) {
+ vma->vm_pgoff += 1;
+ return dma_mmap_writecombine(dev, vma,
+ (void *)dum_data.lcd_virt_start,
+ dum_data.lcd_phys_start,
+ FB_DMA_SIZE);
+ }
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL(pnx4008_sdum_mmap);
+
+int pnx4008_set_dum_exit_notification(int dev_id)
+{
+ int i;
+
+ for (i = 0; i < MAX_DUM_CHANNELS; i++)
+ if (dum_data.fb_owning_channel[i] == dev_id)
+ return -ERESOURCESNOTFREED;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(pnx4008_set_dum_exit_notification);
+
+/* Platform device driver for DUM */
+
+static int sdum_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int retval = 0;
+ struct clk *clk;
+
+ clk = clk_get(0, "dum_ck");
+ if (!IS_ERR(clk)) {
+ clk_set_rate(clk, 0);
+ clk_put(clk);
+ } else
+ retval = PTR_ERR(clk);
+
+ /* disable BAC */
+ DUM_CTRL = V_BAC_DISABLE_IDLE;
+
+ /* LCD standby & turn off display */
+ lcd_reset();
+
+ return retval;
+}
+
+static int sdum_resume(struct platform_device *pdev)
+{
+ int retval = 0;
+ struct clk *clk;
+
+ clk = clk_get(0, "dum_ck");
+ if (!IS_ERR(clk)) {
+ clk_set_rate(clk, 1);
+ clk_put(clk);
+ } else
+ retval = PTR_ERR(clk);
+
+ /* wait for BAC disable */
+ DUM_CTRL = V_BAC_DISABLE_TRIG;
+
+ while (DUM_CTRL & BAC_ENABLED)
+ udelay(10);
+
+ /* re-init LCD */
+ lcd_init();
+
+ /* enable BAC and reset MUX */
+ DUM_CTRL = V_BAC_ENABLE;
+ udelay(1);
+ DUM_CTRL = V_MUX_RESET;
+ return 0;
+}
+
+static int __devinit sdum_probe(struct platform_device *pdev)
+{
+ int ret = 0, i = 0;
+
+ /* map frame buffer */
+ dum_data.lcd_virt_start = (u32) dma_alloc_writecombine(&pdev->dev,
+ FB_DMA_SIZE,
+ &dum_data.lcd_phys_start,
+ GFP_KERNEL);
+
+ if (!dum_data.lcd_virt_start) {
+ ret = -ENOMEM;
+ goto out_3;
+ }
+
+ /* map slave registers */
+ dum_data.slave_phys_base = PNX4008_DUM_SLAVE_BASE;
+ dum_data.slave_virt_base =
+ (u32 *) ioremap_nocache(dum_data.slave_phys_base, sizeof(u32));
+
+ if (dum_data.slave_virt_base == NULL) {
+ ret = -ENOMEM;
+ goto out_2;
+ }
+
+ /* initialize DUM and LCD display */
+ ret = dum_init(pdev);
+ if (ret)
+ goto out_1;
+
+ dum_chan_init();
+ lcd_init();
+
+ DUM_CTRL = V_BAC_ENABLE;
+ udelay(1);
+ DUM_CTRL = V_MUX_RESET;
+
+ /* set decode address and sync clock divider */
+ DUM_DECODE = dum_data.lcd_phys_start & DUM_DECODE_MASK;
+ DUM_CLK_DIV = PNX4008_DUM_CLK_DIV;
+
+ for (i = 0; i < MAX_DUM_CHANNELS; i++)
+ dum_data.fb_owning_channel[i] = -1;
+
+ /*setup wakeup interrupt */
+ start_int_set_rising_edge(SE_DISP_SYNC_INT);
+ start_int_ack(SE_DISP_SYNC_INT);
+ start_int_umask(SE_DISP_SYNC_INT);
+
+ return 0;
+
+out_1:
+ iounmap((void *)dum_data.slave_virt_base);
+out_2:
+ dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
+ (void *)dum_data.lcd_virt_start,
+ dum_data.lcd_phys_start);
+out_3:
+ return ret;
+}
+
+static int sdum_remove(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ start_int_mask(SE_DISP_SYNC_INT);
+
+ clk = clk_get(0, "dum_ck");
+ if (!IS_ERR(clk)) {
+ clk_set_rate(clk, 0);
+ clk_put(clk);
+ }
+
+ iounmap((void *)dum_data.slave_virt_base);
+
+ dma_free_writecombine(&pdev->dev, FB_DMA_SIZE,
+ (void *)dum_data.lcd_virt_start,
+ dum_data.lcd_phys_start);
+
+ return 0;
+}
+
+static struct platform_driver sdum_driver = {
+ .driver = {
+ .name = "sdum",
+ },
+ .probe = sdum_probe,
+ .remove = sdum_remove,
+ .suspend = sdum_suspend,
+ .resume = sdum_resume,
+};
+
+int __init sdum_init(void)
+{
+ return platform_driver_register(&sdum_driver);
+}
+
+static void __exit sdum_exit(void)
+{
+ platform_driver_unregister(&sdum_driver);
+};
+
+module_init(sdum_init);
+module_exit(sdum_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/pnx4008/sdum.h b/drivers/video/pnx4008/sdum.h
new file mode 100644
index 00000000000..e8c5dcdd881
--- /dev/null
+++ b/drivers/video/pnx4008/sdum.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2005 Philips Semiconductors
+ *
+ * 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, 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA, or http://www.gnu.org/licenses/gpl.html
+*/
+
+#define MAX_DUM_CHANNELS 64
+
+#define RGB_MEM_WINDOW(x) (0x10000000 + (x)*0x00100000)
+
+#define QCIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x30000: -1)
+#define CIF_OFFSET(x) (((x) == 0) ? 0x00000: ((x) == 1) ? 0x60000: -1)
+
+#define CTRL_SETDIRTY (0x00000001)
+#define CONF_DIRTYENABLE (0x00000020)
+#define CONF_SYNCENABLE (0x00000004)
+
+#define DIRTY_ENABLED(conf) ((conf) & 0x0020)
+#define SYNC_ENABLED(conf) ((conf) & 0x0004)
+
+/* Display 1 & 2 Write Timing Configuration */
+#define PNX4008_DUM_WT_CFG 0x00372000
+
+/* Display 1 & 2 Read Timing Configuration */
+#define PNX4008_DUM_RT_CFG 0x00003A47
+
+/* DUM Transit State Timing Configuration */
+#define PNX4008_DUM_T_CFG 0x1D /* 29 HCLK cycles */
+
+/* DUM Sync count clock divider */
+#define PNX4008_DUM_CLK_DIV 0x02DD
+
+/* Memory size for framebuffer, allocated through dma_alloc_writecombine().
+ * Must be PAGE aligned
+ */
+#define FB_DMA_SIZE (PAGE_ALIGN(SZ_1M + PAGE_SIZE))
+
+#define OFFSET_RGBBUFFER (0xB0000)
+#define OFFSET_YUVBUFFER (0x00000)
+
+#define YUVBUFFER (lcd_video_start + OFFSET_YUVBUFFER)
+#define RGBBUFFER (lcd_video_start + OFFSET_RGBBUFFER)
+
+#define CMDSTRING_BASEADDR (0x00C000) /* iram */
+#define BYTES_PER_CMDSTRING (0x80)
+#define NR_OF_CMDSTRINGS (64)
+
+#define MAX_NR_PRESTRINGS (0x40)
+#define MAX_NR_POSTSTRINGS (0x40)
+
+/* various mask definitions */
+#define DUM_CLK_ENABLE 0x01
+#define DUM_CLK_DISABLE 0
+#define DUM_DECODE_MASK 0x1FFFFFFF
+#define DUM_CHANNEL_CFG_MASK 0x01FF
+#define DUM_CHANNEL_CFG_SYNC_MASK 0xFFFE00FF
+#define DUM_CHANNEL_CFG_SYNC_MASK_SET 0x0CA00
+
+#define SDUM_RETURNVAL_BASE (0x500)
+
+#define CONF_SYNC_OFF (0x602)
+#define CONF_SYNC_ON (0x603)
+
+#define CONF_DIRTYDETECTION_OFF (0x600)
+#define CONF_DIRTYDETECTION_ON (0x601)
+
+/* Set the corresponding bit. */
+#define BIT(n) (0x1U << (n))
+
+struct dumchannel_uf {
+ int channelnr;
+ u32 *dirty;
+ u32 *source;
+ u32 x_offset;
+ u32 y_offset;
+ u32 width;
+ u32 height;
+};
+
+enum {
+ FB_TYPE_YUV,
+ FB_TYPE_RGB
+};
+
+struct cmdstring {
+ int channelnr;
+ uint16_t prestringlen;
+ uint16_t poststringlen;
+ uint16_t format;
+ uint16_t reserved;
+ uint16_t startaddr_low;
+ uint16_t startaddr_high;
+ uint16_t pixdatlen_low;
+ uint16_t pixdatlen_high;
+ u32 precmd[MAX_NR_PRESTRINGS];
+ u32 postcmd[MAX_NR_POSTSTRINGS];
+
+};
+
+struct dumchannel {
+ int channelnr;
+ int dum_ch_min;
+ int dum_ch_max;
+ int dum_ch_conf;
+ int dum_ch_stat;
+ int dum_ch_ctrl;
+};
+
+int pnx4008_alloc_dum_channel(int dev_id);
+int pnx4008_free_dum_channel(int channr, int dev_id);
+
+int pnx4008_get_dum_channel_uf(struct dumchannel_uf *pChan_uf, int dev_id);
+int pnx4008_put_dum_channel_uf(struct dumchannel_uf chan_uf, int dev_id);
+
+int pnx4008_set_dum_channel_sync(int channr, int val, int dev_id);
+int pnx4008_set_dum_channel_dirty_detect(int channr, int val, int dev_id);
+
+int pnx4008_force_dum_update_channel(int channr, int dev_id);
+
+int pnx4008_get_dum_channel_config(int channr, int dev_id);
+
+int pnx4008_sdum_mmap(struct fb_info *info, struct vm_area_struct *vma, struct device *dev);
+int pnx4008_set_dum_exit_notification(int dev_id);
+
+int pnx4008_get_fb_addresses(int fb_type, void **virt_addr,
+ dma_addr_t * phys_addr, int *fb_length);
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index ec4bacf9dd2..78dc59a1751 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -53,10 +53,8 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
-#include <linux/config.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
@@ -189,7 +187,7 @@ static short do_blank = 0; /* (Un)Blank the screen */
static unsigned int is_blanked = 0; /* Is the screen blanked? */
#ifdef CONFIG_SH_STORE_QUEUES
-static struct sq_mapping *pvr2fb_map;
+static unsigned long pvr2fb_map;
#endif
#ifdef CONFIG_SH_DMA
@@ -215,15 +213,17 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
static int pvr2_init_cable(void);
static int pvr2_get_param(const struct pvr2_params *p, const char *s,
int val, int size);
+#ifdef CONFIG_SH_DMA
static ssize_t pvr2fb_write(struct file *file, const char *buf,
size_t count, loff_t *ppos);
+#endif
static struct fb_ops pvr2fb_ops = {
- .owner = THIS_MODULE,
- .fb_setcolreg = pvr2fb_setcolreg,
- .fb_blank = pvr2fb_blank,
- .fb_check_var = pvr2fb_check_var,
- .fb_set_par = pvr2fb_set_par,
+ .owner = THIS_MODULE,
+ .fb_setcolreg = pvr2fb_setcolreg,
+ .fb_blank = pvr2fb_blank,
+ .fb_check_var = pvr2fb_check_var,
+ .fb_set_par = pvr2fb_set_par,
#ifdef CONFIG_SH_DMA
.fb_write = pvr2fb_write,
#endif
@@ -785,7 +785,7 @@ static int __init pvr2fb_common_init(void)
goto out_err;
}
- fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len);
+ fb_memset(fb_info->screen_base, 0, pvr2_fix.smem_len);
pvr2_fix.ypanstep = nopan ? 0 : 1;
pvr2_fix.ywrapstep = nowrap ? 0 : 1;
@@ -822,7 +822,7 @@ static int __init pvr2fb_common_init(void)
modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10));
printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n",
fb_info->node, fb_info->var.xres, fb_info->var.yres,
- fb_info->var.bits_per_pixel,
+ fb_info->var.bits_per_pixel,
get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
(char *)pvr2_get_param(cables, NULL, cable_type, 3),
(char *)pvr2_get_param(outputs, NULL, video_output, 3));
@@ -831,10 +831,10 @@ static int __init pvr2fb_common_init(void)
printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
- fb_info->fix.id);
+ fb_info->fix.id, pgprot_val(PAGE_SHARED));
printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
- fb_info->node, pvr2fb_map->sq_addr);
+ fb_info->node, pvr2fb_map);
#endif
return 0;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 809fc5eefc1..bbb07106cd5 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -22,7 +22,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -1335,7 +1334,7 @@ int __init pxafb_probe(struct platform_device *dev)
goto failed;
}
- ret = request_irq(IRQ_LCD, pxafb_handle_irq, SA_INTERRUPT, "LCD", fbi);
+ ret = request_irq(IRQ_LCD, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
if (ret) {
dev_err(&dev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
diff --git a/drivers/video/q40fb.c b/drivers/video/q40fb.c
index fc91dbf896d..48536c3e58a 100644
--- a/drivers/video/q40fb.c
+++ b/drivers/video/q40fb.c
@@ -14,7 +14,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
index 5e2c64f622c..cf41ff17764 100644
--- a/drivers/video/retz3fb.c
+++ b/drivers/video/retz3fb.c
@@ -25,7 +25,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 3e9308f0f16..4acde4f7dbf 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -29,18 +29,17 @@
* doublescan modes are broken
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/backlight.h>
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#endif
@@ -272,34 +271,183 @@ static const struct riva_regs reg_template = {
/*
* Backlight control
*/
-#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_FB_RIVA_BACKLIGHT
+/* We do not have any information about which values are allowed, thus
+ * we used safe values.
+ */
+#define MIN_LEVEL 0x158
+#define MAX_LEVEL 0x534
+#define LEVEL_STEP ((MAX_LEVEL - MIN_LEVEL) / FB_BACKLIGHT_MAX)
-static int riva_backlight_levels[] = {
- 0x158,
- 0x192,
- 0x1c6,
- 0x200,
- 0x234,
- 0x268,
- 0x2a2,
- 0x2d6,
- 0x310,
- 0x344,
- 0x378,
- 0x3b2,
- 0x3e6,
- 0x41a,
- 0x454,
- 0x534,
-};
+static struct backlight_properties riva_bl_data;
+
+/* Call with fb_info->bl_mutex held */
+static int riva_bl_get_level_brightness(struct riva_par *par,
+ int level)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int nlevel;
+
+ /* Get and convert the value */
+ nlevel = MIN_LEVEL + info->bl_curve[level] * LEVEL_STEP;
+
+ if (nlevel < 0)
+ nlevel = 0;
+ else if (nlevel < MIN_LEVEL)
+ nlevel = MIN_LEVEL;
+ else if (nlevel > MAX_LEVEL)
+ nlevel = MAX_LEVEL;
+
+ return nlevel;
+}
+
+/* Call with fb_info->bl_mutex held */
+static int __riva_bl_update_status(struct backlight_device *bd)
+{
+ struct riva_par *par = class_get_devdata(&bd->class_dev);
+ U032 tmp_pcrt, tmp_pmc;
+ int level;
+
+ if (bd->props->power != FB_BLANK_UNBLANK ||
+ bd->props->fb_blank != FB_BLANK_UNBLANK)
+ level = 0;
+ else
+ level = bd->props->brightness;
+
+ tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
+ tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
+ if(level > 0) {
+ tmp_pcrt |= 0x1;
+ tmp_pmc |= (1 << 31); /* backlight bit */
+ tmp_pmc |= riva_bl_get_level_brightness(par, level) << 16; /* level */
+ }
+ par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
+ par->riva.PMC[0x10F0/4] = tmp_pmc;
+
+ return 0;
+}
+
+static int riva_bl_update_status(struct backlight_device *bd)
+{
+ struct riva_par *par = class_get_devdata(&bd->class_dev);
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ int ret;
-static int riva_set_backlight_enable(int on, int level, void *data);
-static int riva_set_backlight_level(int level, void *data);
-static struct backlight_controller riva_backlight_controller = {
- riva_set_backlight_enable,
- riva_set_backlight_level
+ mutex_lock(&info->bl_mutex);
+ ret = __riva_bl_update_status(bd);
+ mutex_unlock(&info->bl_mutex);
+
+ return ret;
+}
+
+static int riva_bl_get_brightness(struct backlight_device *bd)
+{
+ return bd->props->brightness;
+}
+
+static struct backlight_properties riva_bl_data = {
+ .owner = THIS_MODULE,
+ .get_brightness = riva_bl_get_brightness,
+ .update_status = riva_bl_update_status,
+ .max_brightness = (FB_BACKLIGHT_LEVELS - 1),
};
-#endif /* CONFIG_PMAC_BACKLIGHT */
+
+static void riva_bl_set_power(struct fb_info *info, int power)
+{
+ mutex_lock(&info->bl_mutex);
+
+ if (info->bl_dev) {
+ down(&info->bl_dev->sem);
+ info->bl_dev->props->power = power;
+ __riva_bl_update_status(info->bl_dev);
+ up(&info->bl_dev->sem);
+ }
+
+ mutex_unlock(&info->bl_mutex);
+}
+
+static void riva_bl_init(struct riva_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+ struct backlight_device *bd;
+ char name[12];
+
+ if (!par->FlatPanel)
+ return;
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (!machine_is(powermac) ||
+ !pmac_has_backlight_type("mnca"))
+ return;
+#endif
+
+ snprintf(name, sizeof(name), "rivabl%d", info->node);
+
+ bd = backlight_device_register(name, par, &riva_bl_data);
+ if (IS_ERR(bd)) {
+ info->bl_dev = NULL;
+ printk(KERN_WARNING "riva: Backlight registration failed\n");
+ goto error;
+ }
+
+ mutex_lock(&info->bl_mutex);
+ info->bl_dev = bd;
+ fb_bl_default_curve(info, 0,
+ 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ mutex_unlock(&info->bl_mutex);
+
+ down(&bd->sem);
+ bd->props->brightness = riva_bl_data.max_brightness;
+ bd->props->power = FB_BLANK_UNBLANK;
+ bd->props->update_status(bd);
+ up(&bd->sem);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+ if (!pmac_backlight)
+ pmac_backlight = bd;
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+
+ printk("riva: Backlight initialized (%s)\n", name);
+
+ return;
+
+error:
+ return;
+}
+
+static void riva_bl_exit(struct riva_par *par)
+{
+ struct fb_info *info = pci_get_drvdata(par->pdev);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_lock(&pmac_backlight_mutex);
+#endif
+
+ mutex_lock(&info->bl_mutex);
+ if (info->bl_dev) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+ if (pmac_backlight == info->bl_dev)
+ pmac_backlight = NULL;
+#endif
+
+ backlight_device_unregister(info->bl_dev);
+
+ printk("riva: Backlight unloaded\n");
+ }
+ mutex_unlock(&info->bl_mutex);
+
+#ifdef CONFIG_PMAC_BACKLIGHT
+ mutex_unlock(&pmac_backlight_mutex);
+#endif
+}
+#else
+static inline void riva_bl_init(struct riva_par *par) {}
+static inline void riva_bl_exit(struct riva_par *par) {}
+static inline void riva_bl_set_power(struct fb_info *info, int power) {}
+#endif /* CONFIG_FB_RIVA_BACKLIGHT */
/* ------------------------------------------------------------------------- *
*
@@ -973,36 +1121,6 @@ static int riva_get_cmap_len(const struct fb_var_screeninfo *var)
/* ------------------------------------------------------------------------- *
*
- * Backlight operations
- *
- * ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-static int riva_set_backlight_enable(int on, int level, void *data)
-{
- struct riva_par *par = data;
- U032 tmp_pcrt, tmp_pmc;
-
- tmp_pmc = par->riva.PMC[0x10F0/4] & 0x0000FFFF;
- tmp_pcrt = par->riva.PCRTC0[0x081C/4] & 0xFFFFFFFC;
- if(on && (level > BACKLIGHT_OFF)) {
- tmp_pcrt |= 0x1;
- tmp_pmc |= (1 << 31); // backlight bit
- tmp_pmc |= riva_backlight_levels[level-1] << 16; // level
- }
- par->riva.PCRTC0[0x081C/4] = tmp_pcrt;
- par->riva.PMC[0x10F0/4] = tmp_pmc;
- return 0;
-}
-
-static int riva_set_backlight_level(int level, void *data)
-{
- return riva_set_backlight_enable(1, level, data);
-}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-
-/* ------------------------------------------------------------------------- *
- *
* framebuffer operations
*
* ------------------------------------------------------------------------- */
@@ -1247,11 +1365,7 @@ static int rivafb_blank(int blank, struct fb_info *info)
SEQout(par, 0x01, tmp);
CRTCout(par, 0x1a, vesa);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if ( par->FlatPanel && machine_is(powermac)) {
- set_backlight_enable(!blank);
- }
-#endif
+ riva_bl_set_power(info, blank);
NVTRACE_LEAVE();
@@ -1712,8 +1826,8 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
{
struct riva_par *par = info->par;
struct device_node *dp;
- unsigned char *pedid = NULL;
- unsigned char *disptype = NULL;
+ const unsigned char *pedid = NULL;
+ const unsigned char *disptype = NULL;
static char *propnames[] = {
"DFP,EDID", "LCD,EDID", "EDID", "EDID1", "EDID,B", "EDID,A", NULL };
int i;
@@ -1721,14 +1835,13 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
NVTRACE_ENTER();
dp = pci_device_to_OF_node(pd);
for (; dp != NULL; dp = dp->child) {
- disptype = (unsigned char *)get_property(dp, "display-type", NULL);
+ disptype = get_property(dp, "display-type", NULL);
if (disptype == NULL)
continue;
if (strncmp(disptype, "LCD", 3) != 0)
continue;
for (i = 0; propnames[i] != NULL; ++i) {
- pedid = (unsigned char *)
- get_property(dp, propnames[i], NULL);
+ pedid = get_property(dp, propnames[i], NULL);
if (pedid != NULL) {
par->EDID = pedid;
NVTRACE("LCD found.\n");
@@ -2022,6 +2135,9 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
fb_destroy_modedb(info->monspecs.modedb);
info->monspecs.modedb = NULL;
+
+ pci_set_drvdata(pd, info);
+ riva_bl_init(info->par);
ret = register_framebuffer(info);
if (ret < 0) {
printk(KERN_ERR PFX
@@ -2029,19 +2145,13 @@ static int __devinit rivafb_probe(struct pci_dev *pd,
goto err_iounmap_screen_base;
}
- pci_set_drvdata(pd, info);
-
printk(KERN_INFO PFX
"PCI nVidia %s framebuffer ver %s (%dMB @ 0x%lX)\n",
info->fix.id,
RIVAFB_VERSION,
info->fix.smem_len / (1024 * 1024),
info->fix.smem_start);
-#ifdef CONFIG_PMAC_BACKLIGHT
- if (default_par->FlatPanel && machine_is(powermac))
- register_backlight_controller(&riva_backlight_controller,
- default_par, "mnca");
-#endif
+
NVTRACE_LEAVE();
return 0;
@@ -2058,7 +2168,6 @@ err_iounmap_ctrl_base:
err_release_region:
pci_release_regions(pd);
err_disable_device:
- pci_disable_device(pd);
err_free_pixmap:
kfree(info->pixmap.addr);
err_framebuffer_release:
@@ -2074,6 +2183,8 @@ static void __exit rivafb_remove(struct pci_dev *pd)
NVTRACE_ENTER();
+ riva_bl_exit(par);
+
#ifdef CONFIG_FB_RIVA_I2C
riva_delete_i2c_busses(par);
kfree(par->EDID);
@@ -2091,7 +2202,6 @@ static void __exit rivafb_remove(struct pci_dev *pd)
if (par->riva.Architecture == NV_ARCH_03)
iounmap(par->riva.PRAMIN);
pci_release_regions(pd);
- pci_disable_device(pd);
kfree(info->pixmap.addr);
framebuffer_release(info);
pci_set_drvdata(pd, NULL);
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 8b1967fc116..9751c37c0bf 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -12,7 +12,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
diff --git a/drivers/video/riva/rivafb.h b/drivers/video/riva/rivafb.h
index 440ff445689..7fa13fc9c41 100644
--- a/drivers/video/riva/rivafb.h
+++ b/drivers/video/riva/rivafb.h
@@ -1,7 +1,6 @@
#ifndef __RIVAFB_H
#define __RIVAFB_H
-#include <linux/config.h>
#include <linux/fb.h>
#include <video/vga.h>
#include <linux/i2c.h>
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index feec47bdd47..a5333c19078 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -28,7 +28,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index 9451932fbaf..ad3bdd6f1ac 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -76,7 +76,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -641,6 +640,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
int ret;
int irq;
int i;
+ u32 lcdcon1;
mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
@@ -672,6 +672,11 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
memcpy(&info->regs, &mach_info->regs, sizeof(info->regs));
+ /* Stop the video and unset ENVID if set */
+ info->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
+ lcdcon1 = readl(S3C2410_LCDCON1);
+ writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+
info->mach_info = pdev->dev.platform_data;
fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
@@ -729,7 +734,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev)
dprintk("got LCD region\n");
- ret = request_irq(irq, s3c2410fb_irq, SA_INTERRUPT, pdev->name, info);
+ ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
if (ret) {
dev_err(&pdev->dev, "cannot get irq %d - err %d\n", irq, ret);
ret = -EBUSY;
@@ -794,15 +799,14 @@ dealloc_fb:
* shutdown the lcd controller
*/
-static void s3c2410fb_stop_lcd(void)
+static void s3c2410fb_stop_lcd(struct s3c2410fb_info *fbi)
{
unsigned long flags;
- unsigned long tmp;
local_irq_save(flags);
- tmp = readl(S3C2410_LCDCON1);
- writel(tmp & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+ fbi->regs.lcdcon1 &= ~S3C2410_LCDCON1_ENVID;
+ writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
local_irq_restore(flags);
}
@@ -816,7 +820,7 @@ static int s3c2410fb_remove(struct platform_device *pdev)
struct s3c2410fb_info *info = fbinfo->par;
int irq;
- s3c2410fb_stop_lcd();
+ s3c2410fb_stop_lcd(info);
msleep(1);
s3c2410fb_unmap_video_memory(info);
@@ -844,7 +848,7 @@ static int s3c2410fb_suspend(struct platform_device *dev, pm_message_t state)
struct fb_info *fbinfo = platform_get_drvdata(dev);
struct s3c2410fb_info *info = fbinfo->par;
- s3c2410fb_stop_lcd();
+ s3c2410fb_stop_lcd(info);
/* sleep before disabling the clock, we need to ensure
* the LCD DMA engine is not going to get back on the bus
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index d9831fd4234..a2e6e7205d7 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -160,7 +160,6 @@
* - Add patch 681/1 and clean up stork definitions.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -1473,7 +1472,7 @@ static int __init sa1100fb_probe(struct platform_device *pdev)
if (ret)
goto failed;
- ret = request_irq(irq, sa1100fb_handle_irq, SA_INTERRUPT,
+ ret = request_irq(irq, sa1100fb_handle_irq, IRQF_DISABLED,
"LCD", fbi);
if (ret) {
printk(KERN_ERR "sa1100fb: request_irq failed: %d\n", ret);
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index 21debed863a..d7d810dbf0b 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -10,7 +10,6 @@
* for more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -149,7 +148,6 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pcidev->dev;
chan->algo.udelay = 40;
- chan->algo.mdelay = 5;
chan->algo.timeout = 20;
chan->algo.data = chan;
diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h
index 58cfdfb4183..e648a6c0f6d 100644
--- a/drivers/video/savage/savagefb.h
+++ b/drivers/video/savage/savagefb.h
@@ -147,7 +147,27 @@ struct xtimings {
int interlaced;
};
+struct savage_reg {
+ unsigned char MiscOutReg; /* Misc */
+ unsigned char CRTC[25]; /* Crtc Controller */
+ unsigned char Sequencer[5]; /* Video Sequencer */
+ unsigned char Graphics[9]; /* Video Graphics */
+ unsigned char Attribute[21]; /* Video Atribute */
+ unsigned int mode, refresh;
+ unsigned char SR08, SR0E, SR0F;
+ unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30;
+ unsigned char SR54[8];
+ unsigned char Clock;
+ unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
+ unsigned char CR40, CR41, CR42, CR43, CR45;
+ unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E;
+ unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F;
+ unsigned char CR86, CR88;
+ unsigned char CR90, CR91, CRB0;
+ unsigned int STREAMS[22]; /* yuck, streams regs */
+ unsigned int MMPR0, MMPR1, MMPR2, MMPR3;
+};
/* --------------------------------------------------------------------- */
#define NR_PALETTE 256
@@ -167,6 +187,8 @@ struct savagefb_par {
struct pci_dev *pcidev;
savage_chipset chip;
struct savagefb_i2c_chan chan;
+ struct savage_reg state;
+ struct savage_reg save;
unsigned char *edid;
u32 pseudo_palette[16];
int paletteEnabled;
@@ -179,6 +201,7 @@ struct savagefb_par {
int minClock;
int numClocks;
int clock[4];
+ int MCLK, REFCLK, LCDclk;
struct {
u8 __iomem *vbase;
u32 pbase;
@@ -196,7 +219,6 @@ struct savagefb_par {
volatile u32 __iomem *bci_base;
unsigned int bci_ptr;
-
u32 cob_offset;
u32 cob_size;
int cob_index;
@@ -204,7 +226,6 @@ struct savagefb_par {
void (*SavageWaitIdle) (struct savagefb_par *par);
void (*SavageWaitFifo) (struct savagefb_par *par, int space);
- int MCLK, REFCLK, LCDclk;
int HorizScaleFactor;
/* Panels size */
@@ -217,26 +238,6 @@ struct savagefb_par {
int depth;
int vwidth;
-
- unsigned char MiscOutReg; /* Misc */
- unsigned char CRTC[25]; /* Crtc Controller */
- unsigned char Sequencer[5]; /* Video Sequencer */
- unsigned char Graphics[9]; /* Video Graphics */
- unsigned char Attribute[21]; /* Video Atribute */
-
- unsigned int mode, refresh;
- unsigned char SR08, SR0E, SR0F;
- unsigned char SR10, SR11, SR12, SR13, SR15, SR18, SR29, SR30;
- unsigned char SR54[8];
- unsigned char Clock;
- unsigned char CR31, CR32, CR33, CR34, CR36, CR3A, CR3B, CR3C;
- unsigned char CR40, CR41, CR42, CR43, CR45;
- unsigned char CR50, CR51, CR53, CR55, CR58, CR5B, CR5D, CR5E;
- unsigned char CR60, CR63, CR65, CR66, CR67, CR68, CR69, CR6D, CR6F;
- unsigned char CR86, CR88;
- unsigned char CR90, CR91, CRB0;
- unsigned int STREAMS[22]; /* yuck, streams regs */
- unsigned int MMPR0, MMPR1, MMPR2, MMPR3;
};
#define BCI_BD_BW_DISABLE 0x10000000
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 0da624e6524..82b3deaae02 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -41,13 +41,11 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -86,15 +84,15 @@ MODULE_DESCRIPTION("FBDev driver for S3 Savage PCI/AGP Chips");
/* --------------------------------------------------------------------- */
-static void vgaHWSeqReset (struct savagefb_par *par, int start)
+static void vgaHWSeqReset(struct savagefb_par *par, int start)
{
if (start)
- VGAwSEQ (0x00, 0x01, par); /* Synchronous Reset */
+ VGAwSEQ(0x00, 0x01, par); /* Synchronous Reset */
else
- VGAwSEQ (0x00, 0x03, par); /* End Reset */
+ VGAwSEQ(0x00, 0x03, par); /* End Reset */
}
-static void vgaHWProtect (struct savagefb_par *par, int on)
+static void vgaHWProtect(struct savagefb_par *par, int on)
{
unsigned char tmp;
@@ -102,10 +100,10 @@ static void vgaHWProtect (struct savagefb_par *par, int on)
/*
* Turn off screen and disable sequencer.
*/
- tmp = VGArSEQ (0x01, par);
+ tmp = VGArSEQ(0x01, par);
- vgaHWSeqReset (par, 1); /* start synchronous reset */
- VGAwSEQ (0x01, tmp | 0x20, par);/* disable the display */
+ vgaHWSeqReset(par, 1); /* start synchronous reset */
+ VGAwSEQ(0x01, tmp | 0x20, par);/* disable the display */
VGAenablePalette(par);
} else {
@@ -113,75 +111,76 @@ static void vgaHWProtect (struct savagefb_par *par, int on)
* Reenable sequencer, then turn on screen.
*/
- tmp = VGArSEQ (0x01, par);
+ tmp = VGArSEQ(0x01, par);
- VGAwSEQ (0x01, tmp & ~0x20, par);/* reenable display */
- vgaHWSeqReset (par, 0); /* clear synchronous reset */
+ VGAwSEQ(0x01, tmp & ~0x20, par);/* reenable display */
+ vgaHWSeqReset(par, 0); /* clear synchronous reset */
VGAdisablePalette(par);
}
}
-static void vgaHWRestore (struct savagefb_par *par)
+static void vgaHWRestore(struct savagefb_par *par, struct savage_reg *reg)
{
int i;
- VGAwMISC (par->MiscOutReg, par);
+ VGAwMISC(reg->MiscOutReg, par);
for (i = 1; i < 5; i++)
- VGAwSEQ (i, par->Sequencer[i], par);
+ VGAwSEQ(i, reg->Sequencer[i], par);
/* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 or
CRTC[17] */
- VGAwCR (17, par->CRTC[17] & ~0x80, par);
+ VGAwCR(17, reg->CRTC[17] & ~0x80, par);
for (i = 0; i < 25; i++)
- VGAwCR (i, par->CRTC[i], par);
+ VGAwCR(i, reg->CRTC[i], par);
for (i = 0; i < 9; i++)
- VGAwGR (i, par->Graphics[i], par);
+ VGAwGR(i, reg->Graphics[i], par);
VGAenablePalette(par);
for (i = 0; i < 21; i++)
- VGAwATTR (i, par->Attribute[i], par);
+ VGAwATTR(i, reg->Attribute[i], par);
VGAdisablePalette(par);
}
-static void vgaHWInit (struct fb_var_screeninfo *var,
- struct savagefb_par *par,
- struct xtimings *timings)
+static void vgaHWInit(struct fb_var_screeninfo *var,
+ struct savagefb_par *par,
+ struct xtimings *timings,
+ struct savage_reg *reg)
{
- par->MiscOutReg = 0x23;
+ reg->MiscOutReg = 0x23;
if (!(timings->sync & FB_SYNC_HOR_HIGH_ACT))
- par->MiscOutReg |= 0x40;
+ reg->MiscOutReg |= 0x40;
if (!(timings->sync & FB_SYNC_VERT_HIGH_ACT))
- par->MiscOutReg |= 0x80;
+ reg->MiscOutReg |= 0x80;
/*
* Time Sequencer
*/
- par->Sequencer[0x00] = 0x00;
- par->Sequencer[0x01] = 0x01;
- par->Sequencer[0x02] = 0x0F;
- par->Sequencer[0x03] = 0x00; /* Font select */
- par->Sequencer[0x04] = 0x0E; /* Misc */
+ reg->Sequencer[0x00] = 0x00;
+ reg->Sequencer[0x01] = 0x01;
+ reg->Sequencer[0x02] = 0x0F;
+ reg->Sequencer[0x03] = 0x00; /* Font select */
+ reg->Sequencer[0x04] = 0x0E; /* Misc */
/*
* CRTC Controller
*/
- par->CRTC[0x00] = (timings->HTotal >> 3) - 5;
- par->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
- par->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
- par->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80;
- par->CRTC[0x04] = (timings->HSyncStart >> 3);
- par->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
+ reg->CRTC[0x00] = (timings->HTotal >> 3) - 5;
+ reg->CRTC[0x01] = (timings->HDisplay >> 3) - 1;
+ reg->CRTC[0x02] = (timings->HSyncStart >> 3) - 1;
+ reg->CRTC[0x03] = (((timings->HSyncEnd >> 3) - 1) & 0x1f) | 0x80;
+ reg->CRTC[0x04] = (timings->HSyncStart >> 3);
+ reg->CRTC[0x05] = ((((timings->HSyncEnd >> 3) - 1) & 0x20) << 2) |
(((timings->HSyncEnd >> 3)) & 0x1f);
- par->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
- par->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
+ reg->CRTC[0x06] = (timings->VTotal - 2) & 0xFF;
+ reg->CRTC[0x07] = (((timings->VTotal - 2) & 0x100) >> 8) |
(((timings->VDisplay - 1) & 0x100) >> 7) |
((timings->VSyncStart & 0x100) >> 6) |
(((timings->VSyncStart - 1) & 0x100) >> 5) |
@@ -189,27 +188,27 @@ static void vgaHWInit (struct fb_var_screeninfo *var,
(((timings->VTotal - 2) & 0x200) >> 4) |
(((timings->VDisplay - 1) & 0x200) >> 3) |
((timings->VSyncStart & 0x200) >> 2);
- par->CRTC[0x08] = 0x00;
- par->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
+ reg->CRTC[0x08] = 0x00;
+ reg->CRTC[0x09] = (((timings->VSyncStart - 1) & 0x200) >> 4) | 0x40;
if (timings->dblscan)
- par->CRTC[0x09] |= 0x80;
-
- par->CRTC[0x0a] = 0x00;
- par->CRTC[0x0b] = 0x00;
- par->CRTC[0x0c] = 0x00;
- par->CRTC[0x0d] = 0x00;
- par->CRTC[0x0e] = 0x00;
- par->CRTC[0x0f] = 0x00;
- par->CRTC[0x10] = timings->VSyncStart & 0xff;
- par->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
- par->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
- par->CRTC[0x13] = var->xres_virtual >> 4;
- par->CRTC[0x14] = 0x00;
- par->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
- par->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
- par->CRTC[0x17] = 0xc3;
- par->CRTC[0x18] = 0xff;
+ reg->CRTC[0x09] |= 0x80;
+
+ reg->CRTC[0x0a] = 0x00;
+ reg->CRTC[0x0b] = 0x00;
+ reg->CRTC[0x0c] = 0x00;
+ reg->CRTC[0x0d] = 0x00;
+ reg->CRTC[0x0e] = 0x00;
+ reg->CRTC[0x0f] = 0x00;
+ reg->CRTC[0x10] = timings->VSyncStart & 0xff;
+ reg->CRTC[0x11] = (timings->VSyncEnd & 0x0f) | 0x20;
+ reg->CRTC[0x12] = (timings->VDisplay - 1) & 0xff;
+ reg->CRTC[0x13] = var->xres_virtual >> 4;
+ reg->CRTC[0x14] = 0x00;
+ reg->CRTC[0x15] = (timings->VSyncStart - 1) & 0xff;
+ reg->CRTC[0x16] = (timings->VSyncEnd - 1) & 0xff;
+ reg->CRTC[0x17] = 0xc3;
+ reg->CRTC[0x18] = 0xff;
/*
* are these unnecessary?
@@ -220,38 +219,38 @@ static void vgaHWInit (struct fb_var_screeninfo *var,
/*
* Graphics Display Controller
*/
- par->Graphics[0x00] = 0x00;
- par->Graphics[0x01] = 0x00;
- par->Graphics[0x02] = 0x00;
- par->Graphics[0x03] = 0x00;
- par->Graphics[0x04] = 0x00;
- par->Graphics[0x05] = 0x40;
- par->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */
- par->Graphics[0x07] = 0x0F;
- par->Graphics[0x08] = 0xFF;
-
-
- par->Attribute[0x00] = 0x00; /* standard colormap translation */
- par->Attribute[0x01] = 0x01;
- par->Attribute[0x02] = 0x02;
- par->Attribute[0x03] = 0x03;
- par->Attribute[0x04] = 0x04;
- par->Attribute[0x05] = 0x05;
- par->Attribute[0x06] = 0x06;
- par->Attribute[0x07] = 0x07;
- par->Attribute[0x08] = 0x08;
- par->Attribute[0x09] = 0x09;
- par->Attribute[0x0a] = 0x0A;
- par->Attribute[0x0b] = 0x0B;
- par->Attribute[0x0c] = 0x0C;
- par->Attribute[0x0d] = 0x0D;
- par->Attribute[0x0e] = 0x0E;
- par->Attribute[0x0f] = 0x0F;
- par->Attribute[0x10] = 0x41;
- par->Attribute[0x11] = 0xFF;
- par->Attribute[0x12] = 0x0F;
- par->Attribute[0x13] = 0x00;
- par->Attribute[0x14] = 0x00;
+ reg->Graphics[0x00] = 0x00;
+ reg->Graphics[0x01] = 0x00;
+ reg->Graphics[0x02] = 0x00;
+ reg->Graphics[0x03] = 0x00;
+ reg->Graphics[0x04] = 0x00;
+ reg->Graphics[0x05] = 0x40;
+ reg->Graphics[0x06] = 0x05; /* only map 64k VGA memory !!!! */
+ reg->Graphics[0x07] = 0x0F;
+ reg->Graphics[0x08] = 0xFF;
+
+
+ reg->Attribute[0x00] = 0x00; /* standard colormap translation */
+ reg->Attribute[0x01] = 0x01;
+ reg->Attribute[0x02] = 0x02;
+ reg->Attribute[0x03] = 0x03;
+ reg->Attribute[0x04] = 0x04;
+ reg->Attribute[0x05] = 0x05;
+ reg->Attribute[0x06] = 0x06;
+ reg->Attribute[0x07] = 0x07;
+ reg->Attribute[0x08] = 0x08;
+ reg->Attribute[0x09] = 0x09;
+ reg->Attribute[0x0a] = 0x0A;
+ reg->Attribute[0x0b] = 0x0B;
+ reg->Attribute[0x0c] = 0x0C;
+ reg->Attribute[0x0d] = 0x0D;
+ reg->Attribute[0x0e] = 0x0E;
+ reg->Attribute[0x0f] = 0x0F;
+ reg->Attribute[0x10] = 0x41;
+ reg->Attribute[0x11] = 0xFF;
+ reg->Attribute[0x12] = 0x0F;
+ reg->Attribute[0x13] = 0x00;
+ reg->Attribute[0x14] = 0x00;
}
/* -------------------- Hardware specific routines ------------------------- */
@@ -304,15 +303,15 @@ savage2000_waitidle(struct savagefb_par *par)
while ((savage_in32(0x48C60, par) & 0x009fffff));
}
-
+#ifdef CONFIG_FB_SAVAGE_ACCEL
static void
-SavageSetup2DEngine (struct savagefb_par *par)
+SavageSetup2DEngine(struct savagefb_par *par)
{
unsigned long GlobalBitmapDescriptor;
GlobalBitmapDescriptor = 1 | 8 | BCI_BD_BW_DISABLE;
- BCI_BD_SET_BPP (GlobalBitmapDescriptor, par->depth);
- BCI_BD_SET_STRIDE (GlobalBitmapDescriptor, par->vwidth);
+ BCI_BD_SET_BPP(GlobalBitmapDescriptor, par->depth);
+ BCI_BD_SET_STRIDE(GlobalBitmapDescriptor, par->vwidth);
switch(par->chip) {
case S3_SAVAGE3D:
@@ -361,32 +360,48 @@ SavageSetup2DEngine (struct savagefb_par *par)
vga_out8(0x3d5, 0x0c, par);
/* Set stride to use GBD. */
- vga_out8 (0x3d4, 0x50, par);
- vga_out8 (0x3d5, vga_in8(0x3d5, par) | 0xC1, par);
+ vga_out8(0x3d4, 0x50, par);
+ vga_out8(0x3d5, vga_in8(0x3d5, par) | 0xC1, par);
/* Enable 2D engine. */
- vga_out8 (0x3d4, 0x40, par);
- vga_out8 (0x3d5, 0x01, par);
+ vga_out8(0x3d4, 0x40, par);
+ vga_out8(0x3d5, 0x01, par);
- savage_out32 (MONO_PAT_0, ~0, par);
- savage_out32 (MONO_PAT_1, ~0, par);
+ savage_out32(MONO_PAT_0, ~0, par);
+ savage_out32(MONO_PAT_1, ~0, par);
/* Setup plane masks */
- savage_out32 (0x8128, ~0, par); /* enable all write planes */
- savage_out32 (0x812C, ~0, par); /* enable all read planes */
- savage_out16 (0x8134, 0x27, par);
- savage_out16 (0x8136, 0x07, par);
+ savage_out32(0x8128, ~0, par); /* enable all write planes */
+ savage_out32(0x812C, ~0, par); /* enable all read planes */
+ savage_out16(0x8134, 0x27, par);
+ savage_out16(0x8136, 0x07, par);
/* Now set the GBD */
par->bci_ptr = 0;
- par->SavageWaitFifo (par, 4);
+ par->SavageWaitFifo(par, 4);
- BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD1 );
- BCI_SEND( 0 );
- BCI_SEND( BCI_CMD_SETREG | (1 << 16) | BCI_GBD2 );
- BCI_SEND( GlobalBitmapDescriptor );
+ BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD1);
+ BCI_SEND(0);
+ BCI_SEND(BCI_CMD_SETREG | (1 << 16) | BCI_GBD2);
+ BCI_SEND(GlobalBitmapDescriptor);
}
+static void savagefb_set_clip(struct fb_info *info)
+{
+ struct savagefb_par *par = info->par;
+ int cmd;
+
+ cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
+ par->bci_ptr = 0;
+ par->SavageWaitFifo(par,3);
+ BCI_SEND(cmd);
+ BCI_SEND(BCI_CLIP_TL(0, 0));
+ BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
+}
+#else
+static void SavageSetup2DEngine(struct savagefb_par *par) {}
+
+#endif
static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
int min_n2, int max_n2, long freq_min,
@@ -398,11 +413,11 @@ static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
if (freq < freq_min / (1 << max_n2)) {
- printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+ printk(KERN_ERR "invalid frequency %ld Khz\n", freq);
freq = freq_min / (1 << max_n2);
}
if (freq > freq_max / (1 << min_n2)) {
- printk (KERN_ERR "invalid frequency %ld Khz\n", freq);
+ printk(KERN_ERR "invalid frequency %ld Khz\n", freq);
freq = freq_max / (1 << min_n2);
}
@@ -453,12 +468,12 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
BASE_FREQ;
if (m < min_m + 2 || m > 127+2)
continue;
- if((m * BASE_FREQ >= freq_min * n1) &&
- (m * BASE_FREQ <= freq_max * n1)) {
+ if ((m * BASE_FREQ >= freq_min * n1) &&
+ (m * BASE_FREQ <= freq_max * n1)) {
diff = freq * (1 << n2) * n1 - BASE_FREQ * m;
- if(diff < 0)
+ if (diff < 0)
diff = -diff;
- if(diff < best_diff) {
+ if (diff < best_diff) {
best_diff = diff;
best_m = m;
best_n1 = n1;
@@ -468,7 +483,7 @@ static int common_calc_clock(long freq, int min_m, int min_n1, int max_n1,
}
}
- if(max_n1 == 63)
+ if (max_n1 == 63)
*ndiv = (best_n1 - 2) | (best_n2 << 6);
else
*ndiv = (best_n1 - 2) | (best_n2 << 5);
@@ -488,23 +503,23 @@ static void SavagePrintRegs(void)
int vgaCRReg = 0x3d5;
printk(KERN_DEBUG "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE "
- "xF" );
+ "xF");
- for( i = 0; i < 0x70; i++ ) {
- if( !(i % 16) )
- printk(KERN_DEBUG "\nSR%xx ", i >> 4 );
- vga_out8( 0x3c4, i, par);
- printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par) );
+ for (i = 0; i < 0x70; i++) {
+ if (!(i % 16))
+ printk(KERN_DEBUG "\nSR%xx ", i >> 4);
+ vga_out8(0x3c4, i, par);
+ printk(KERN_DEBUG " %02x", vga_in8(0x3c5, par));
}
printk(KERN_DEBUG "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC "
- "xD xE xF" );
+ "xD xE xF");
- for( i = 0; i < 0xB7; i++ ) {
- if( !(i % 16) )
- printk(KERN_DEBUG "\nCR%xx ", i >> 4 );
- vga_out8( vgaCRIndex, i, par);
- printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par) );
+ for (i = 0; i < 0xB7; i++) {
+ if (!(i % 16))
+ printk(KERN_DEBUG "\nCR%xx ", i >> 4);
+ vga_out8(vgaCRIndex, i, par);
+ printk(KERN_DEBUG " %02x", vga_in8(vgaCRReg, par));
}
printk(KERN_DEBUG "\n\n");
@@ -513,156 +528,309 @@ static void SavagePrintRegs(void)
/* --------------------------------------------------------------------- */
-static void savage_get_default_par(struct savagefb_par *par)
+static void savage_get_default_par(struct savagefb_par *par, struct savage_reg *reg)
{
unsigned char cr3a, cr53, cr66;
- vga_out16 (0x3d4, 0x4838, par);
- vga_out16 (0x3d4, 0xa039, par);
- vga_out16 (0x3c4, 0x0608, par);
-
- vga_out8 (0x3d4, 0x66, par);
- cr66 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr66 | 0x80, par);
- vga_out8 (0x3d4, 0x3a, par);
- cr3a = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr3a | 0x80, par);
- vga_out8 (0x3d4, 0x53, par);
- cr53 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr53 & 0x7f, par);
-
- vga_out8 (0x3d4, 0x66, par);
- vga_out8 (0x3d5, cr66, par);
- vga_out8 (0x3d4, 0x3a, par);
- vga_out8 (0x3d5, cr3a, par);
-
- vga_out8 (0x3d4, 0x66, par);
- vga_out8 (0x3d5, cr66, par);
- vga_out8 (0x3d4, 0x3a, par);
- vga_out8 (0x3d5, cr3a, par);
+ vga_out16(0x3d4, 0x4838, par);
+ vga_out16(0x3d4, 0xa039, par);
+ vga_out16(0x3c4, 0x0608, par);
+
+ vga_out8(0x3d4, 0x66, par);
+ cr66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr66 | 0x80, par);
+ vga_out8(0x3d4, 0x3a, par);
+ cr3a = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr3a | 0x80, par);
+ vga_out8(0x3d4, 0x53, par);
+ cr53 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr53 & 0x7f, par);
+
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
+
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
/* unlock extended seq regs */
- vga_out8 (0x3c4, 0x08, par);
- par->SR08 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c5, 0x06, par);
+ vga_out8(0x3c4, 0x08, par);
+ reg->SR08 = vga_in8(0x3c5, par);
+ vga_out8(0x3c5, 0x06, par);
/* now save all the extended regs we need */
- vga_out8 (0x3d4, 0x31, par);
- par->CR31 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x32, par);
- par->CR32 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x34, par);
- par->CR34 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x36, par);
- par->CR36 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x3a, par);
- par->CR3A = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x40, par);
- par->CR40 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x42, par);
- par->CR42 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x45, par);
- par->CR45 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x50, par);
- par->CR50 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x51, par);
- par->CR51 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x53, par);
- par->CR53 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x58, par);
- par->CR58 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x60, par);
- par->CR60 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x66, par);
- par->CR66 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x67, par);
- par->CR67 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x68, par);
- par->CR68 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x69, par);
- par->CR69 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x6f, par);
- par->CR6F = vga_in8 (0x3d5, par);
-
- vga_out8 (0x3d4, 0x33, par);
- par->CR33 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x86, par);
- par->CR86 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x88, par);
- par->CR88 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x90, par);
- par->CR90 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x91, par);
- par->CR91 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0xb0, par);
- par->CRB0 = vga_in8 (0x3d5, par) | 0x80;
+ vga_out8(0x3d4, 0x31, par);
+ reg->CR31 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x32, par);
+ reg->CR32 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x34, par);
+ reg->CR34 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x36, par);
+ reg->CR36 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x3a, par);
+ reg->CR3A = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x40, par);
+ reg->CR40 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x42, par);
+ reg->CR42 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x45, par);
+ reg->CR45 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x50, par);
+ reg->CR50 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x51, par);
+ reg->CR51 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x53, par);
+ reg->CR53 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x58, par);
+ reg->CR58 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x60, par);
+ reg->CR60 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x66, par);
+ reg->CR66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x67, par);
+ reg->CR67 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x68, par);
+ reg->CR68 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x69, par);
+ reg->CR69 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x6f, par);
+ reg->CR6F = vga_in8(0x3d5, par);
+
+ vga_out8(0x3d4, 0x33, par);
+ reg->CR33 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x86, par);
+ reg->CR86 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x88, par);
+ reg->CR88 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x90, par);
+ reg->CR90 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x91, par);
+ reg->CR91 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0xb0, par);
+ reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
+
+ /* extended mode timing regs */
+ vga_out8(0x3d4, 0x3b, par);
+ reg->CR3B = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x3c, par);
+ reg->CR3C = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x43, par);
+ reg->CR43 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x5d, par);
+ reg->CR5D = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x5e, par);
+ reg->CR5E = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x65, par);
+ reg->CR65 = vga_in8(0x3d5, par);
+
+ /* save seq extended regs for DCLK PLL programming */
+ vga_out8(0x3c4, 0x0e, par);
+ reg->SR0E = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x0f, par);
+ reg->SR0F = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x10, par);
+ reg->SR10 = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x11, par);
+ reg->SR11 = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x12, par);
+ reg->SR12 = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x13, par);
+ reg->SR13 = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x29, par);
+ reg->SR29 = vga_in8(0x3c5, par);
+
+ vga_out8(0x3c4, 0x15, par);
+ reg->SR15 = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x30, par);
+ reg->SR30 = vga_in8(0x3c5, par);
+ vga_out8(0x3c4, 0x18, par);
+ reg->SR18 = vga_in8(0x3c5, par);
+
+ /* Save flat panel expansion regsters. */
+ if (par->chip == S3_SAVAGE_MX) {
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ vga_out8(0x3c4, 0x54+i, par);
+ reg->SR54[i] = vga_in8(0x3c5, par);
+ }
+ }
+
+ vga_out8(0x3d4, 0x66, par);
+ cr66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr66 | 0x80, par);
+ vga_out8(0x3d4, 0x3a, par);
+ cr3a = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr3a | 0x80, par);
+
+ /* now save MIU regs */
+ if (par->chip != S3_SAVAGE_MX) {
+ reg->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);
+ reg->MMPR1 = savage_in32(MIU_CONTROL_REG, par);
+ reg->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);
+ reg->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);
+ }
+
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
+}
+
+static void savage_set_default_par(struct savagefb_par *par,
+ struct savage_reg *reg)
+{
+ unsigned char cr3a, cr53, cr66;
+
+ vga_out16(0x3d4, 0x4838, par);
+ vga_out16(0x3d4, 0xa039, par);
+ vga_out16(0x3c4, 0x0608, par);
+
+ vga_out8(0x3d4, 0x66, par);
+ cr66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr66 | 0x80, par);
+ vga_out8(0x3d4, 0x3a, par);
+ cr3a = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr3a | 0x80, par);
+ vga_out8(0x3d4, 0x53, par);
+ cr53 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr53 & 0x7f, par);
+
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
+
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
+
+ /* unlock extended seq regs */
+ vga_out8(0x3c4, 0x08, par);
+ vga_out8(0x3c5, reg->SR08, par);
+ vga_out8(0x3c5, 0x06, par);
+
+ /* now restore all the extended regs we need */
+ vga_out8(0x3d4, 0x31, par);
+ vga_out8(0x3d5, reg->CR31, par);
+ vga_out8(0x3d4, 0x32, par);
+ vga_out8(0x3d5, reg->CR32, par);
+ vga_out8(0x3d4, 0x34, par);
+ vga_out8(0x3d5, reg->CR34, par);
+ vga_out8(0x3d4, 0x36, par);
+ vga_out8(0x3d5,reg->CR36, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, reg->CR3A, par);
+ vga_out8(0x3d4, 0x40, par);
+ vga_out8(0x3d5, reg->CR40, par);
+ vga_out8(0x3d4, 0x42, par);
+ vga_out8(0x3d5, reg->CR42, par);
+ vga_out8(0x3d4, 0x45, par);
+ vga_out8(0x3d5, reg->CR45, par);
+ vga_out8(0x3d4, 0x50, par);
+ vga_out8(0x3d5, reg->CR50, par);
+ vga_out8(0x3d4, 0x51, par);
+ vga_out8(0x3d5, reg->CR51, par);
+ vga_out8(0x3d4, 0x53, par);
+ vga_out8(0x3d5, reg->CR53, par);
+ vga_out8(0x3d4, 0x58, par);
+ vga_out8(0x3d5, reg->CR58, par);
+ vga_out8(0x3d4, 0x60, par);
+ vga_out8(0x3d5, reg->CR60, par);
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, reg->CR66, par);
+ vga_out8(0x3d4, 0x67, par);
+ vga_out8(0x3d5, reg->CR67, par);
+ vga_out8(0x3d4, 0x68, par);
+ vga_out8(0x3d5, reg->CR68, par);
+ vga_out8(0x3d4, 0x69, par);
+ vga_out8(0x3d5, reg->CR69, par);
+ vga_out8(0x3d4, 0x6f, par);
+ vga_out8(0x3d5, reg->CR6F, par);
+
+ vga_out8(0x3d4, 0x33, par);
+ vga_out8(0x3d5, reg->CR33, par);
+ vga_out8(0x3d4, 0x86, par);
+ vga_out8(0x3d5, reg->CR86, par);
+ vga_out8(0x3d4, 0x88, par);
+ vga_out8(0x3d5, reg->CR88, par);
+ vga_out8(0x3d4, 0x90, par);
+ vga_out8(0x3d5, reg->CR90, par);
+ vga_out8(0x3d4, 0x91, par);
+ vga_out8(0x3d5, reg->CR91, par);
+ vga_out8(0x3d4, 0xb0, par);
+ vga_out8(0x3d5, reg->CRB0, par);
/* extended mode timing regs */
- vga_out8 (0x3d4, 0x3b, par);
- par->CR3B = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x3c, par);
- par->CR3C = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x43, par);
- par->CR43 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x5d, par);
- par->CR5D = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x5e, par);
- par->CR5E = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x65, par);
- par->CR65 = vga_in8 (0x3d5, par);
+ vga_out8(0x3d4, 0x3b, par);
+ vga_out8(0x3d5, reg->CR3B, par);
+ vga_out8(0x3d4, 0x3c, par);
+ vga_out8(0x3d5, reg->CR3C, par);
+ vga_out8(0x3d4, 0x43, par);
+ vga_out8(0x3d5, reg->CR43, par);
+ vga_out8(0x3d4, 0x5d, par);
+ vga_out8(0x3d5, reg->CR5D, par);
+ vga_out8(0x3d4, 0x5e, par);
+ vga_out8(0x3d5, reg->CR5E, par);
+ vga_out8(0x3d4, 0x65, par);
+ vga_out8(0x3d5, reg->CR65, par);
/* save seq extended regs for DCLK PLL programming */
- vga_out8 (0x3c4, 0x0e, par);
- par->SR0E = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x0f, par);
- par->SR0F = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x10, par);
- par->SR10 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x11, par);
- par->SR11 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x12, par);
- par->SR12 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x13, par);
- par->SR13 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x29, par);
- par->SR29 = vga_in8 (0x3c5, par);
-
- vga_out8 (0x3c4, 0x15, par);
- par->SR15 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x30, par);
- par->SR30 = vga_in8 (0x3c5, par);
- vga_out8 (0x3c4, 0x18, par);
- par->SR18 = vga_in8 (0x3c5, par);
+ vga_out8(0x3c4, 0x0e, par);
+ vga_out8(0x3c5, reg->SR0E, par);
+ vga_out8(0x3c4, 0x0f, par);
+ vga_out8(0x3c5, reg->SR0F, par);
+ vga_out8(0x3c4, 0x10, par);
+ vga_out8(0x3c5, reg->SR10, par);
+ vga_out8(0x3c4, 0x11, par);
+ vga_out8(0x3c5, reg->SR11, par);
+ vga_out8(0x3c4, 0x12, par);
+ vga_out8(0x3c5, reg->SR12, par);
+ vga_out8(0x3c4, 0x13, par);
+ vga_out8(0x3c5, reg->SR13, par);
+ vga_out8(0x3c4, 0x29, par);
+ vga_out8(0x3c5, reg->SR29, par);
+
+ vga_out8(0x3c4, 0x15, par);
+ vga_out8(0x3c5, reg->SR15, par);
+ vga_out8(0x3c4, 0x30, par);
+ vga_out8(0x3c5, reg->SR30, par);
+ vga_out8(0x3c4, 0x18, par);
+ vga_out8(0x3c5, reg->SR18, par);
/* Save flat panel expansion regsters. */
if (par->chip == S3_SAVAGE_MX) {
int i;
for (i = 0; i < 8; i++) {
- vga_out8 (0x3c4, 0x54+i, par);
- par->SR54[i] = vga_in8 (0x3c5, par);
+ vga_out8(0x3c4, 0x54+i, par);
+ vga_out8(0x3c5, reg->SR54[i], par);
}
}
- vga_out8 (0x3d4, 0x66, par);
- cr66 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr66 | 0x80, par);
- vga_out8 (0x3d4, 0x3a, par);
- cr3a = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr3a | 0x80, par);
+ vga_out8(0x3d4, 0x66, par);
+ cr66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr66 | 0x80, par);
+ vga_out8(0x3d4, 0x3a, par);
+ cr3a = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr3a | 0x80, par);
/* now save MIU regs */
if (par->chip != S3_SAVAGE_MX) {
- par->MMPR0 = savage_in32(FIFO_CONTROL_REG, par);
- par->MMPR1 = savage_in32(MIU_CONTROL_REG, par);
- par->MMPR2 = savage_in32(STREAMS_TIMEOUT_REG, par);
- par->MMPR3 = savage_in32(MISC_TIMEOUT_REG, par);
+ savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par);
+ savage_out32(MIU_CONTROL_REG, reg->MMPR1, par);
+ savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par);
+ savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par);
}
- vga_out8 (0x3d4, 0x3a, par);
- vga_out8 (0x3d5, cr3a, par);
- vga_out8 (0x3d4, 0x66, par);
- vga_out8 (0x3d5, cr66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
}
static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode *modedb)
@@ -683,8 +851,8 @@ static void savage_update_var(struct fb_var_screeninfo *var, struct fb_videomode
var->vmode = modedb->vmode;
}
-static int savagefb_check_var (struct fb_var_screeninfo *var,
- struct fb_info *info)
+static int savagefb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
struct savagefb_par *par = info->par;
int memlen, vramlen, mode_valid = 0;
@@ -750,10 +918,10 @@ static int savagefb_check_var (struct fb_var_screeninfo *var,
if (par->SavagePanelWidth &&
(var->xres > par->SavagePanelWidth ||
var->yres > par->SavagePanelHeight)) {
- printk (KERN_INFO "Mode (%dx%d) larger than the LCD panel "
- "(%dx%d)\n", var->xres, var->yres,
- par->SavagePanelWidth,
- par->SavagePanelHeight);
+ printk(KERN_INFO "Mode (%dx%d) larger than the LCD panel "
+ "(%dx%d)\n", var->xres, var->yres,
+ par->SavagePanelWidth,
+ par->SavagePanelHeight);
return -1;
}
@@ -788,8 +956,9 @@ static int savagefb_check_var (struct fb_var_screeninfo *var,
}
-static int savagefb_decode_var (struct fb_var_screeninfo *var,
- struct savagefb_par *par)
+static int savagefb_decode_var(struct fb_var_screeninfo *var,
+ struct savagefb_par *par,
+ struct savage_reg *reg)
{
struct xtimings timings;
int width, dclk, i, j; /*, refresh; */
@@ -799,7 +968,7 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var,
DBG("savagefb_decode_var");
- memset (&timings, 0, sizeof(timings));
+ memset(&timings, 0, sizeof(timings));
if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */
timings.Clock = 1000000000 / pixclock;
@@ -831,39 +1000,39 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var,
* This will allocate the datastructure and initialize all of the
* generic VGA registers.
*/
- vgaHWInit (var, par, &timings);
+ vgaHWInit(var, par, &timings, reg);
/* We need to set CR67 whether or not we use the BIOS. */
dclk = timings.Clock;
- par->CR67 = 0x00;
+ reg->CR67 = 0x00;
- switch( var->bits_per_pixel ) {
+ switch(var->bits_per_pixel) {
case 8:
- if( (par->chip == S3_SAVAGE2000) && (dclk >= 230000) )
- par->CR67 = 0x10; /* 8bpp, 2 pixels/clock */
+ if ((par->chip == S3_SAVAGE2000) && (dclk >= 230000))
+ reg->CR67 = 0x10; /* 8bpp, 2 pixels/clock */
else
- par->CR67 = 0x00; /* 8bpp, 1 pixel/clock */
+ reg->CR67 = 0x00; /* 8bpp, 1 pixel/clock */
break;
case 15:
- if ( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
- ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
- par->CR67 = 0x30; /* 15bpp, 2 pixel/clock */
+ if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+ ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
+ reg->CR67 = 0x30; /* 15bpp, 2 pixel/clock */
else
- par->CR67 = 0x20; /* 15bpp, 1 pixels/clock */
+ reg->CR67 = 0x20; /* 15bpp, 1 pixels/clock */
break;
case 16:
- if( S3_SAVAGE_MOBILE_SERIES(par->chip) ||
- ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)) )
- par->CR67 = 0x50; /* 16bpp, 2 pixel/clock */
+ if (S3_SAVAGE_MOBILE_SERIES(par->chip) ||
+ ((par->chip == S3_SAVAGE2000) && (dclk >= 230000)))
+ reg->CR67 = 0x50; /* 16bpp, 2 pixel/clock */
else
- par->CR67 = 0x40; /* 16bpp, 1 pixels/clock */
+ reg->CR67 = 0x40; /* 16bpp, 1 pixels/clock */
break;
case 24:
- par->CR67 = 0x70;
+ reg->CR67 = 0x70;
break;
case 32:
- par->CR67 = 0xd0;
+ reg->CR67 = 0xd0;
break;
}
@@ -872,61 +1041,61 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var,
* match. Fall back to traditional register-crunching.
*/
- vga_out8 (0x3d4, 0x3a, par);
- tmp = vga_in8 (0x3d5, par);
+ vga_out8(0x3d4, 0x3a, par);
+ tmp = vga_in8(0x3d5, par);
if (1 /*FIXME:psav->pci_burst*/)
- par->CR3A = (tmp & 0x7f) | 0x15;
+ reg->CR3A = (tmp & 0x7f) | 0x15;
else
- par->CR3A = tmp | 0x95;
+ reg->CR3A = tmp | 0x95;
- par->CR53 = 0x00;
- par->CR31 = 0x8c;
- par->CR66 = 0x89;
+ reg->CR53 = 0x00;
+ reg->CR31 = 0x8c;
+ reg->CR66 = 0x89;
- vga_out8 (0x3d4, 0x58, par);
- par->CR58 = vga_in8 (0x3d5, par) & 0x80;
- par->CR58 |= 0x13;
+ vga_out8(0x3d4, 0x58, par);
+ reg->CR58 = vga_in8(0x3d5, par) & 0x80;
+ reg->CR58 |= 0x13;
- par->SR15 = 0x03 | 0x80;
- par->SR18 = 0x00;
- par->CR43 = par->CR45 = par->CR65 = 0x00;
+ reg->SR15 = 0x03 | 0x80;
+ reg->SR18 = 0x00;
+ reg->CR43 = reg->CR45 = reg->CR65 = 0x00;
- vga_out8 (0x3d4, 0x40, par);
- par->CR40 = vga_in8 (0x3d5, par) & ~0x01;
+ vga_out8(0x3d4, 0x40, par);
+ reg->CR40 = vga_in8(0x3d5, par) & ~0x01;
- par->MMPR0 = 0x010400;
- par->MMPR1 = 0x00;
- par->MMPR2 = 0x0808;
- par->MMPR3 = 0x08080810;
+ reg->MMPR0 = 0x010400;
+ reg->MMPR1 = 0x00;
+ reg->MMPR2 = 0x0808;
+ reg->MMPR3 = 0x08080810;
- SavageCalcClock (dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
+ SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000, &m, &n, &r);
/* m = 107; n = 4; r = 2; */
if (par->MCLK <= 0) {
- par->SR10 = 255;
- par->SR11 = 255;
+ reg->SR10 = 255;
+ reg->SR11 = 255;
} else {
- common_calc_clock (par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
- &par->SR11, &par->SR10);
- /* par->SR10 = 80; // MCLK == 286000 */
- /* par->SR11 = 125; */
+ common_calc_clock(par->MCLK, 1, 1, 31, 0, 3, 135000, 270000,
+ &reg->SR11, &reg->SR10);
+ /* reg->SR10 = 80; // MCLK == 286000 */
+ /* reg->SR11 = 125; */
}
- par->SR12 = (r << 6) | (n & 0x3f);
- par->SR13 = m & 0xff;
- par->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
+ reg->SR12 = (r << 6) | (n & 0x3f);
+ reg->SR13 = m & 0xff;
+ reg->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
if (var->bits_per_pixel < 24)
- par->MMPR0 -= 0x8000;
+ reg->MMPR0 -= 0x8000;
else
- par->MMPR0 -= 0x4000;
+ reg->MMPR0 -= 0x4000;
if (timings.interlaced)
- par->CR42 = 0x20;
+ reg->CR42 = 0x20;
else
- par->CR42 = 0x00;
+ reg->CR42 = 0x00;
- par->CR34 = 0x10; /* display fifo */
+ reg->CR34 = 0x10; /* display fifo */
i = ((((timings.HTotal >> 3) - 5) & 0x100) >> 8) |
((((timings.HDisplay >> 3) - 1) & 0x100) >> 7) |
@@ -938,77 +1107,77 @@ static int savagefb_decode_var (struct fb_var_screeninfo *var,
if ((timings.HSyncEnd >> 3) - (timings.HSyncStart >> 3) > 32)
i |= 0x20;
- j = (par->CRTC[0] + ((i & 0x01) << 8) +
- par->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
+ j = (reg->CRTC[0] + ((i & 0x01) << 8) +
+ reg->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
- if (j - (par->CRTC[4] + ((i & 0x10) << 4)) < 4) {
- if (par->CRTC[4] + ((i & 0x10) << 4) + 4 <=
- par->CRTC[0] + ((i & 0x01) << 8))
- j = par->CRTC[4] + ((i & 0x10) << 4) + 4;
+ if (j - (reg->CRTC[4] + ((i & 0x10) << 4)) < 4) {
+ if (reg->CRTC[4] + ((i & 0x10) << 4) + 4 <=
+ reg->CRTC[0] + ((i & 0x01) << 8))
+ j = reg->CRTC[4] + ((i & 0x10) << 4) + 4;
else
- j = par->CRTC[0] + ((i & 0x01) << 8) + 1;
+ j = reg->CRTC[0] + ((i & 0x01) << 8) + 1;
}
- par->CR3B = j & 0xff;
+ reg->CR3B = j & 0xff;
i |= (j & 0x100) >> 2;
- par->CR3C = (par->CRTC[0] + ((i & 0x01) << 8)) / 2;
- par->CR5D = i;
- par->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
+ reg->CR3C = (reg->CRTC[0] + ((i & 0x01) << 8)) / 2;
+ reg->CR5D = i;
+ reg->CR5E = (((timings.VTotal - 2) & 0x400) >> 10) |
(((timings.VDisplay - 1) & 0x400) >> 9) |
(((timings.VSyncStart) & 0x400) >> 8) |
(((timings.VSyncStart) & 0x400) >> 6) | 0x40;
width = (var->xres_virtual * ((var->bits_per_pixel+7) / 8)) >> 3;
- par->CR91 = par->CRTC[19] = 0xff & width;
- par->CR51 = (0x300 & width) >> 4;
- par->CR90 = 0x80 | (width >> 8);
- par->MiscOutReg |= 0x0c;
+ reg->CR91 = reg->CRTC[19] = 0xff & width;
+ reg->CR51 = (0x300 & width) >> 4;
+ reg->CR90 = 0x80 | (width >> 8);
+ reg->MiscOutReg |= 0x0c;
/* Set frame buffer description. */
if (var->bits_per_pixel <= 8)
- par->CR50 = 0;
+ reg->CR50 = 0;
else if (var->bits_per_pixel <= 16)
- par->CR50 = 0x10;
+ reg->CR50 = 0x10;
else
- par->CR50 = 0x30;
+ reg->CR50 = 0x30;
if (var->xres_virtual <= 640)
- par->CR50 |= 0x40;
+ reg->CR50 |= 0x40;
else if (var->xres_virtual == 800)
- par->CR50 |= 0x80;
+ reg->CR50 |= 0x80;
else if (var->xres_virtual == 1024)
- par->CR50 |= 0x00;
+ reg->CR50 |= 0x00;
else if (var->xres_virtual == 1152)
- par->CR50 |= 0x01;
+ reg->CR50 |= 0x01;
else if (var->xres_virtual == 1280)
- par->CR50 |= 0xc0;
+ reg->CR50 |= 0xc0;
else if (var->xres_virtual == 1600)
- par->CR50 |= 0x81;
+ reg->CR50 |= 0x81;
else
- par->CR50 |= 0xc1; /* Use GBD */
+ reg->CR50 |= 0xc1; /* Use GBD */
- if( par->chip == S3_SAVAGE2000 )
- par->CR33 = 0x08;
+ if (par->chip == S3_SAVAGE2000)
+ reg->CR33 = 0x08;
else
- par->CR33 = 0x20;
+ reg->CR33 = 0x20;
- par->CRTC[0x17] = 0xeb;
+ reg->CRTC[0x17] = 0xeb;
- par->CR67 |= 1;
+ reg->CR67 |= 1;
vga_out8(0x3d4, 0x36, par);
- par->CR36 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x68, par);
- par->CR68 = vga_in8 (0x3d5, par);
- par->CR69 = 0;
- vga_out8 (0x3d4, 0x6f, par);
- par->CR6F = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x86, par);
- par->CR86 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d4, 0x88, par);
- par->CR88 = vga_in8 (0x3d5, par) | 0x08;
- vga_out8 (0x3d4, 0xb0, par);
- par->CRB0 = vga_in8 (0x3d5, par) | 0x80;
+ reg->CR36 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x68, par);
+ reg->CR68 = vga_in8(0x3d5, par);
+ reg->CR69 = 0;
+ vga_out8(0x3d4, 0x6f, par);
+ reg->CR6F = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x86, par);
+ reg->CR86 = vga_in8(0x3d5, par);
+ vga_out8(0x3d4, 0x88, par);
+ reg->CR88 = vga_in8(0x3d5, par) | 0x08;
+ vga_out8(0x3d4, 0xb0, par);
+ reg->CRB0 = vga_in8(0x3d5, par) | 0x80;
return 0;
}
@@ -1037,11 +1206,11 @@ static int savagefb_setcolreg(unsigned regno,
switch (info->var.bits_per_pixel) {
case 8:
- vga_out8 (0x3c8, regno, par);
+ vga_out8(0x3c8, regno, par);
- vga_out8 (0x3c9, red >> 10, par);
- vga_out8 (0x3c9, green >> 10, par);
- vga_out8 (0x3c9, blue >> 10, par);
+ vga_out8(0x3c9, red >> 10, par);
+ vga_out8(0x3c9, green >> 10, par);
+ vga_out8(0x3c9, blue >> 10, par);
break;
case 16:
@@ -1075,21 +1244,21 @@ static int savagefb_setcolreg(unsigned regno,
return 0;
}
-static void savagefb_set_par_int (struct savagefb_par *par)
+static void savagefb_set_par_int(struct savagefb_par *par, struct savage_reg *reg)
{
unsigned char tmp, cr3a, cr66, cr67;
- DBG ("savagefb_set_par_int");
+ DBG("savagefb_set_par_int");
- par->SavageWaitIdle (par);
+ par->SavageWaitIdle(par);
- vga_out8 (0x3c2, 0x23, par);
+ vga_out8(0x3c2, 0x23, par);
- vga_out16 (0x3d4, 0x4838, par);
- vga_out16 (0x3d4, 0xa539, par);
- vga_out16 (0x3c4, 0x0608, par);
+ vga_out16(0x3d4, 0x4838, par);
+ vga_out16(0x3d4, 0xa539, par);
+ vga_out16(0x3c4, 0x0608, par);
- vgaHWProtect (par, 1);
+ vgaHWProtect(par, 1);
/*
* Some Savage/MX and /IX systems go nuts when trying to exit the
@@ -1099,203 +1268,202 @@ static void savagefb_set_par_int (struct savagefb_par *par)
*/
VerticalRetraceWait(par);
- vga_out8 (0x3d4, 0x67, par);
- cr67 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */
+ vga_out8(0x3d4, 0x67, par);
+ cr67 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr67/*par->CR67*/ & ~0x0c, par); /* no STREAMS yet */
- vga_out8 (0x3d4, 0x23, par);
- vga_out8 (0x3d5, 0x00, par);
- vga_out8 (0x3d4, 0x26, par);
- vga_out8 (0x3d5, 0x00, par);
+ vga_out8(0x3d4, 0x23, par);
+ vga_out8(0x3d5, 0x00, par);
+ vga_out8(0x3d4, 0x26, par);
+ vga_out8(0x3d5, 0x00, par);
/* restore extended regs */
- vga_out8 (0x3d4, 0x66, par);
- vga_out8 (0x3d5, par->CR66, par);
- vga_out8 (0x3d4, 0x3a, par);
- vga_out8 (0x3d5, par->CR3A, par);
- vga_out8 (0x3d4, 0x31, par);
- vga_out8 (0x3d5, par->CR31, par);
- vga_out8 (0x3d4, 0x32, par);
- vga_out8 (0x3d5, par->CR32, par);
- vga_out8 (0x3d4, 0x58, par);
- vga_out8 (0x3d5, par->CR58, par);
- vga_out8 (0x3d4, 0x53, par);
- vga_out8 (0x3d5, par->CR53 & 0x7f, par);
-
- vga_out16 (0x3c4, 0x0608, par);
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, reg->CR66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, reg->CR3A, par);
+ vga_out8(0x3d4, 0x31, par);
+ vga_out8(0x3d5, reg->CR31, par);
+ vga_out8(0x3d4, 0x32, par);
+ vga_out8(0x3d5, reg->CR32, par);
+ vga_out8(0x3d4, 0x58, par);
+ vga_out8(0x3d5, reg->CR58, par);
+ vga_out8(0x3d4, 0x53, par);
+ vga_out8(0x3d5, reg->CR53 & 0x7f, par);
+
+ vga_out16(0x3c4, 0x0608, par);
/* Restore DCLK registers. */
- vga_out8 (0x3c4, 0x0e, par);
- vga_out8 (0x3c5, par->SR0E, par);
- vga_out8 (0x3c4, 0x0f, par);
- vga_out8 (0x3c5, par->SR0F, par);
- vga_out8 (0x3c4, 0x29, par);
- vga_out8 (0x3c5, par->SR29, par);
- vga_out8 (0x3c4, 0x15, par);
- vga_out8 (0x3c5, par->SR15, par);
+ vga_out8(0x3c4, 0x0e, par);
+ vga_out8(0x3c5, reg->SR0E, par);
+ vga_out8(0x3c4, 0x0f, par);
+ vga_out8(0x3c5, reg->SR0F, par);
+ vga_out8(0x3c4, 0x29, par);
+ vga_out8(0x3c5, reg->SR29, par);
+ vga_out8(0x3c4, 0x15, par);
+ vga_out8(0x3c5, reg->SR15, par);
/* Restore flat panel expansion regsters. */
- if( par->chip == S3_SAVAGE_MX ) {
+ if (par->chip == S3_SAVAGE_MX) {
int i;
- for( i = 0; i < 8; i++ ) {
- vga_out8 (0x3c4, 0x54+i, par);
- vga_out8 (0x3c5, par->SR54[i], par);
+ for (i = 0; i < 8; i++) {
+ vga_out8(0x3c4, 0x54+i, par);
+ vga_out8(0x3c5, reg->SR54[i], par);
}
}
- vgaHWRestore (par);
+ vgaHWRestore (par, reg);
/* extended mode timing registers */
- vga_out8 (0x3d4, 0x53, par);
- vga_out8 (0x3d5, par->CR53, par);
- vga_out8 (0x3d4, 0x5d, par);
- vga_out8 (0x3d5, par->CR5D, par);
- vga_out8 (0x3d4, 0x5e, par);
- vga_out8 (0x3d5, par->CR5E, par);
- vga_out8 (0x3d4, 0x3b, par);
- vga_out8 (0x3d5, par->CR3B, par);
- vga_out8 (0x3d4, 0x3c, par);
- vga_out8 (0x3d5, par->CR3C, par);
- vga_out8 (0x3d4, 0x43, par);
- vga_out8 (0x3d5, par->CR43, par);
- vga_out8 (0x3d4, 0x65, par);
- vga_out8 (0x3d5, par->CR65, par);
+ vga_out8(0x3d4, 0x53, par);
+ vga_out8(0x3d5, reg->CR53, par);
+ vga_out8(0x3d4, 0x5d, par);
+ vga_out8(0x3d5, reg->CR5D, par);
+ vga_out8(0x3d4, 0x5e, par);
+ vga_out8(0x3d5, reg->CR5E, par);
+ vga_out8(0x3d4, 0x3b, par);
+ vga_out8(0x3d5, reg->CR3B, par);
+ vga_out8(0x3d4, 0x3c, par);
+ vga_out8(0x3d5, reg->CR3C, par);
+ vga_out8(0x3d4, 0x43, par);
+ vga_out8(0x3d5, reg->CR43, par);
+ vga_out8(0x3d4, 0x65, par);
+ vga_out8(0x3d5, reg->CR65, par);
/* restore the desired video mode with cr67 */
- vga_out8 (0x3d4, 0x67, par);
+ vga_out8(0x3d4, 0x67, par);
/* following part not present in X11 driver */
- cr67 = vga_in8 (0x3d5, par) & 0xf;
- vga_out8 (0x3d5, 0x50 | cr67, par);
- udelay (10000);
- vga_out8 (0x3d4, 0x67, par);
+ cr67 = vga_in8(0x3d5, par) & 0xf;
+ vga_out8(0x3d5, 0x50 | cr67, par);
+ udelay(10000);
+ vga_out8(0x3d4, 0x67, par);
/* end of part */
- vga_out8 (0x3d5, par->CR67 & ~0x0c, par);
+ vga_out8(0x3d5, reg->CR67 & ~0x0c, par);
/* other mode timing and extended regs */
- vga_out8 (0x3d4, 0x34, par);
- vga_out8 (0x3d5, par->CR34, par);
- vga_out8 (0x3d4, 0x40, par);
- vga_out8 (0x3d5, par->CR40, par);
- vga_out8 (0x3d4, 0x42, par);
- vga_out8 (0x3d5, par->CR42, par);
- vga_out8 (0x3d4, 0x45, par);
- vga_out8 (0x3d5, par->CR45, par);
- vga_out8 (0x3d4, 0x50, par);
- vga_out8 (0x3d5, par->CR50, par);
- vga_out8 (0x3d4, 0x51, par);
- vga_out8 (0x3d5, par->CR51, par);
+ vga_out8(0x3d4, 0x34, par);
+ vga_out8(0x3d5, reg->CR34, par);
+ vga_out8(0x3d4, 0x40, par);
+ vga_out8(0x3d5, reg->CR40, par);
+ vga_out8(0x3d4, 0x42, par);
+ vga_out8(0x3d5, reg->CR42, par);
+ vga_out8(0x3d4, 0x45, par);
+ vga_out8(0x3d5, reg->CR45, par);
+ vga_out8(0x3d4, 0x50, par);
+ vga_out8(0x3d5, reg->CR50, par);
+ vga_out8(0x3d4, 0x51, par);
+ vga_out8(0x3d5, reg->CR51, par);
/* memory timings */
- vga_out8 (0x3d4, 0x36, par);
- vga_out8 (0x3d5, par->CR36, par);
- vga_out8 (0x3d4, 0x60, par);
- vga_out8 (0x3d5, par->CR60, par);
- vga_out8 (0x3d4, 0x68, par);
- vga_out8 (0x3d5, par->CR68, par);
- vga_out8 (0x3d4, 0x69, par);
- vga_out8 (0x3d5, par->CR69, par);
- vga_out8 (0x3d4, 0x6f, par);
- vga_out8 (0x3d5, par->CR6F, par);
-
- vga_out8 (0x3d4, 0x33, par);
- vga_out8 (0x3d5, par->CR33, par);
- vga_out8 (0x3d4, 0x86, par);
- vga_out8 (0x3d5, par->CR86, par);
- vga_out8 (0x3d4, 0x88, par);
- vga_out8 (0x3d5, par->CR88, par);
- vga_out8 (0x3d4, 0x90, par);
- vga_out8 (0x3d5, par->CR90, par);
- vga_out8 (0x3d4, 0x91, par);
- vga_out8 (0x3d5, par->CR91, par);
+ vga_out8(0x3d4, 0x36, par);
+ vga_out8(0x3d5, reg->CR36, par);
+ vga_out8(0x3d4, 0x60, par);
+ vga_out8(0x3d5, reg->CR60, par);
+ vga_out8(0x3d4, 0x68, par);
+ vga_out8(0x3d5, reg->CR68, par);
+ vga_out8(0x3d4, 0x69, par);
+ vga_out8(0x3d5, reg->CR69, par);
+ vga_out8(0x3d4, 0x6f, par);
+ vga_out8(0x3d5, reg->CR6F, par);
+
+ vga_out8(0x3d4, 0x33, par);
+ vga_out8(0x3d5, reg->CR33, par);
+ vga_out8(0x3d4, 0x86, par);
+ vga_out8(0x3d5, reg->CR86, par);
+ vga_out8(0x3d4, 0x88, par);
+ vga_out8(0x3d5, reg->CR88, par);
+ vga_out8(0x3d4, 0x90, par);
+ vga_out8(0x3d5, reg->CR90, par);
+ vga_out8(0x3d4, 0x91, par);
+ vga_out8(0x3d5, reg->CR91, par);
if (par->chip == S3_SAVAGE4) {
- vga_out8 (0x3d4, 0xb0, par);
- vga_out8 (0x3d5, par->CRB0, par);
+ vga_out8(0x3d4, 0xb0, par);
+ vga_out8(0x3d5, reg->CRB0, par);
}
- vga_out8 (0x3d4, 0x32, par);
- vga_out8 (0x3d5, par->CR32, par);
+ vga_out8(0x3d4, 0x32, par);
+ vga_out8(0x3d5, reg->CR32, par);
/* unlock extended seq regs */
- vga_out8 (0x3c4, 0x08, par);
- vga_out8 (0x3c5, 0x06, par);
+ vga_out8(0x3c4, 0x08, par);
+ vga_out8(0x3c5, 0x06, par);
/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates
* that we should leave the default SR10 and SR11 values there.
*/
- if (par->SR10 != 255) {
- vga_out8 (0x3c4, 0x10, par);
- vga_out8 (0x3c5, par->SR10, par);
- vga_out8 (0x3c4, 0x11, par);
- vga_out8 (0x3c5, par->SR11, par);
+ if (reg->SR10 != 255) {
+ vga_out8(0x3c4, 0x10, par);
+ vga_out8(0x3c5, reg->SR10, par);
+ vga_out8(0x3c4, 0x11, par);
+ vga_out8(0x3c5, reg->SR11, par);
}
/* restore extended seq regs for dclk */
- vga_out8 (0x3c4, 0x0e, par);
- vga_out8 (0x3c5, par->SR0E, par);
- vga_out8 (0x3c4, 0x0f, par);
- vga_out8 (0x3c5, par->SR0F, par);
- vga_out8 (0x3c4, 0x12, par);
- vga_out8 (0x3c5, par->SR12, par);
- vga_out8 (0x3c4, 0x13, par);
- vga_out8 (0x3c5, par->SR13, par);
- vga_out8 (0x3c4, 0x29, par);
- vga_out8 (0x3c5, par->SR29, par);
-
- vga_out8 (0x3c4, 0x18, par);
- vga_out8 (0x3c5, par->SR18, par);
+ vga_out8(0x3c4, 0x0e, par);
+ vga_out8(0x3c5, reg->SR0E, par);
+ vga_out8(0x3c4, 0x0f, par);
+ vga_out8(0x3c5, reg->SR0F, par);
+ vga_out8(0x3c4, 0x12, par);
+ vga_out8(0x3c5, reg->SR12, par);
+ vga_out8(0x3c4, 0x13, par);
+ vga_out8(0x3c5, reg->SR13, par);
+ vga_out8(0x3c4, 0x29, par);
+ vga_out8(0x3c5, reg->SR29, par);
+ vga_out8(0x3c4, 0x18, par);
+ vga_out8(0x3c5, reg->SR18, par);
/* load new m, n pll values for dclk & mclk */
- vga_out8 (0x3c4, 0x15, par);
- tmp = vga_in8 (0x3c5, par) & ~0x21;
+ vga_out8(0x3c4, 0x15, par);
+ tmp = vga_in8(0x3c5, par) & ~0x21;
- vga_out8 (0x3c5, tmp | 0x03, par);
- vga_out8 (0x3c5, tmp | 0x23, par);
- vga_out8 (0x3c5, tmp | 0x03, par);
- vga_out8 (0x3c5, par->SR15, par);
- udelay (100);
+ vga_out8(0x3c5, tmp | 0x03, par);
+ vga_out8(0x3c5, tmp | 0x23, par);
+ vga_out8(0x3c5, tmp | 0x03, par);
+ vga_out8(0x3c5, reg->SR15, par);
+ udelay(100);
- vga_out8 (0x3c4, 0x30, par);
- vga_out8 (0x3c5, par->SR30, par);
- vga_out8 (0x3c4, 0x08, par);
- vga_out8 (0x3c5, par->SR08, par);
+ vga_out8(0x3c4, 0x30, par);
+ vga_out8(0x3c5, reg->SR30, par);
+ vga_out8(0x3c4, 0x08, par);
+ vga_out8(0x3c5, reg->SR08, par);
/* now write out cr67 in full, possibly starting STREAMS */
VerticalRetraceWait(par);
- vga_out8 (0x3d4, 0x67, par);
- vga_out8 (0x3d5, par->CR67, par);
+ vga_out8(0x3d4, 0x67, par);
+ vga_out8(0x3d5, reg->CR67, par);
- vga_out8 (0x3d4, 0x66, par);
- cr66 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr66 | 0x80, par);
- vga_out8 (0x3d4, 0x3a, par);
- cr3a = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr3a | 0x80, par);
+ vga_out8(0x3d4, 0x66, par);
+ cr66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr66 | 0x80, par);
+ vga_out8(0x3d4, 0x3a, par);
+ cr3a = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr3a | 0x80, par);
if (par->chip != S3_SAVAGE_MX) {
VerticalRetraceWait(par);
- savage_out32 (FIFO_CONTROL_REG, par->MMPR0, par);
- par->SavageWaitIdle (par);
- savage_out32 (MIU_CONTROL_REG, par->MMPR1, par);
- par->SavageWaitIdle (par);
- savage_out32 (STREAMS_TIMEOUT_REG, par->MMPR2, par);
- par->SavageWaitIdle (par);
- savage_out32 (MISC_TIMEOUT_REG, par->MMPR3, par);
+ savage_out32(FIFO_CONTROL_REG, reg->MMPR0, par);
+ par->SavageWaitIdle(par);
+ savage_out32(MIU_CONTROL_REG, reg->MMPR1, par);
+ par->SavageWaitIdle(par);
+ savage_out32(STREAMS_TIMEOUT_REG, reg->MMPR2, par);
+ par->SavageWaitIdle(par);
+ savage_out32(MISC_TIMEOUT_REG, reg->MMPR3, par);
}
- vga_out8 (0x3d4, 0x66, par);
- vga_out8 (0x3d5, cr66, par);
- vga_out8 (0x3d4, 0x3a, par);
- vga_out8 (0x3d5, cr3a, par);
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66, par);
+ vga_out8(0x3d4, 0x3a, par);
+ vga_out8(0x3d5, cr3a, par);
- SavageSetup2DEngine (par);
- vgaHWProtect (par, 0);
+ SavageSetup2DEngine(par);
+ vgaHWProtect(par, 0);
}
-static void savagefb_update_start (struct savagefb_par *par,
- struct fb_var_screeninfo *var)
+static void savagefb_update_start(struct savagefb_par *par,
+ struct fb_var_screeninfo *var)
{
int base;
@@ -1305,8 +1473,8 @@ static void savagefb_update_start (struct savagefb_par *par,
/* now program the start address registers */
vga_out16(0x3d4, (base & 0x00ff00) | 0x0c, par);
vga_out16(0x3d4, ((base & 0x00ff) << 8) | 0x0d, par);
- vga_out8 (0x3d4, 0x69, par);
- vga_out8 (0x3d5, (base & 0x7f0000) >> 16, par);
+ vga_out8(0x3d4, 0x69, par);
+ vga_out8(0x3d5, (base & 0x7f0000) >> 16, par);
}
@@ -1325,29 +1493,14 @@ static void savagefb_set_fix(struct fb_info *info)
}
-#if defined(CONFIG_FB_SAVAGE_ACCEL)
-static void savagefb_set_clip(struct fb_info *info)
-{
- struct savagefb_par *par = info->par;
- int cmd;
-
- cmd = BCI_CMD_NOP | BCI_CMD_CLIP_NEW;
- par->bci_ptr = 0;
- par->SavageWaitFifo(par,3);
- BCI_SEND(cmd);
- BCI_SEND(BCI_CLIP_TL(0, 0));
- BCI_SEND(BCI_CLIP_BR(0xfff, 0xfff));
-}
-#endif
-
-static int savagefb_set_par (struct fb_info *info)
+static int savagefb_set_par(struct fb_info *info)
{
struct savagefb_par *par = info->par;
struct fb_var_screeninfo *var = &info->var;
int err;
DBG("savagefb_set_par");
- err = savagefb_decode_var (var, par);
+ err = savagefb_decode_var(var, par, &par->state);
if (err)
return err;
@@ -1366,8 +1519,8 @@ static int savagefb_set_par (struct fb_info *info)
par->maxClock = par->dacSpeedBpp;
par->minClock = 10000;
- savagefb_set_par_int (par);
- fb_set_cmap (&info->cmap, info);
+ savagefb_set_par_int(par, &par->state);
+ fb_set_cmap(&info->cmap, info);
savagefb_set_fix(info);
savagefb_set_clip(info);
@@ -1378,12 +1531,12 @@ static int savagefb_set_par (struct fb_info *info)
/*
* Pan or Wrap the Display
*/
-static int savagefb_pan_display (struct fb_var_screeninfo *var,
- struct fb_info *info)
+static int savagefb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
struct savagefb_par *par = info->par;
- savagefb_update_start (par, var);
+ savagefb_update_start(par, var);
return 0;
}
@@ -1440,6 +1593,22 @@ static int savagefb_blank(int blank, struct fb_info *info)
return (blank == FB_BLANK_NORMAL) ? 1 : 0;
}
+static void savagefb_save_state(struct fb_info *info)
+{
+ struct savagefb_par *par = info->par;
+
+ savage_get_default_par(par, &par->save);
+}
+
+static void savagefb_restore_state(struct fb_info *info)
+{
+ struct savagefb_par *par = info->par;
+
+ savagefb_blank(FB_BLANK_POWERDOWN, info);
+ savage_set_default_par(par, &par->save);
+ savagefb_blank(FB_BLANK_UNBLANK, info);
+}
+
static struct fb_ops savagefb_ops = {
.owner = THIS_MODULE,
.fb_check_var = savagefb_check_var,
@@ -1447,6 +1616,8 @@ static struct fb_ops savagefb_ops = {
.fb_setcolreg = savagefb_setcolreg,
.fb_pan_display = savagefb_pan_display,
.fb_blank = savagefb_blank,
+ .fb_save_state = savagefb_save_state,
+ .fb_restore_state = savagefb_restore_state,
#if defined(CONFIG_FB_SAVAGE_ACCEL)
.fb_fillrect = savagefb_fillrect,
.fb_copyarea = savagefb_copyarea,
@@ -1479,59 +1650,59 @@ static struct fb_var_screeninfo __devinitdata savagefb_var800x600x8 = {
.vmode = FB_VMODE_NONINTERLACED
};
-static void savage_enable_mmio (struct savagefb_par *par)
+static void savage_enable_mmio(struct savagefb_par *par)
{
unsigned char val;
- DBG ("savage_enable_mmio\n");
+ DBG("savage_enable_mmio\n");
- val = vga_in8 (0x3c3, par);
- vga_out8 (0x3c3, val | 0x01, par);
- val = vga_in8 (0x3cc, par);
- vga_out8 (0x3c2, val | 0x01, par);
+ val = vga_in8(0x3c3, par);
+ vga_out8(0x3c3, val | 0x01, par);
+ val = vga_in8(0x3cc, par);
+ vga_out8(0x3c2, val | 0x01, par);
if (par->chip >= S3_SAVAGE4) {
- vga_out8 (0x3d4, 0x40, par);
- val = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, val | 1, par);
+ vga_out8(0x3d4, 0x40, par);
+ val = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, val | 1, par);
}
}
-static void savage_disable_mmio (struct savagefb_par *par)
+static void savage_disable_mmio(struct savagefb_par *par)
{
unsigned char val;
- DBG ("savage_disable_mmio\n");
+ DBG("savage_disable_mmio\n");
- if(par->chip >= S3_SAVAGE4 ) {
- vga_out8 (0x3d4, 0x40, par);
- val = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, val | 1, par);
+ if (par->chip >= S3_SAVAGE4) {
+ vga_out8(0x3d4, 0x40, par);
+ val = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, val | 1, par);
}
}
-static int __devinit savage_map_mmio (struct fb_info *info)
+static int __devinit savage_map_mmio(struct fb_info *info)
{
struct savagefb_par *par = info->par;
- DBG ("savage_map_mmio");
+ DBG("savage_map_mmio");
- if (S3_SAVAGE3D_SERIES (par->chip))
- par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+ if (S3_SAVAGE3D_SERIES(par->chip))
+ par->mmio.pbase = pci_resource_start(par->pcidev, 0) +
SAVAGE_NEWMMIO_REGBASE_S3;
else
- par->mmio.pbase = pci_resource_start (par->pcidev, 0) +
+ par->mmio.pbase = pci_resource_start(par->pcidev, 0) +
SAVAGE_NEWMMIO_REGBASE_S4;
par->mmio.len = SAVAGE_NEWMMIO_REGSIZE;
- par->mmio.vbase = ioremap (par->mmio.pbase, par->mmio.len);
+ par->mmio.vbase = ioremap(par->mmio.pbase, par->mmio.len);
if (!par->mmio.vbase) {
- printk ("savagefb: unable to map memory mapped IO\n");
+ printk("savagefb: unable to map memory mapped IO\n");
return -ENOMEM;
} else
- printk (KERN_INFO "savagefb: mapped io at %p\n",
+ printk(KERN_INFO "savagefb: mapped io at %p\n",
par->mmio.vbase);
info->fix.mmio_start = par->mmio.pbase;
@@ -1540,15 +1711,15 @@ static int __devinit savage_map_mmio (struct fb_info *info)
par->bci_base = (u32 __iomem *)(par->mmio.vbase + BCI_BUFFER_OFFSET);
par->bci_ptr = 0;
- savage_enable_mmio (par);
+ savage_enable_mmio(par);
return 0;
}
-static void savage_unmap_mmio (struct fb_info *info)
+static void savage_unmap_mmio(struct fb_info *info)
{
struct savagefb_par *par = info->par;
- DBG ("savage_unmap_mmio");
+ DBG("savage_unmap_mmio");
savage_disable_mmio(par);
@@ -1558,46 +1729,46 @@ static void savage_unmap_mmio (struct fb_info *info)
}
}
-static int __devinit savage_map_video (struct fb_info *info,
- int video_len)
+static int __devinit savage_map_video(struct fb_info *info,
+ int video_len)
{
struct savagefb_par *par = info->par;
int resource;
DBG("savage_map_video");
- if (S3_SAVAGE3D_SERIES (par->chip))
+ if (S3_SAVAGE3D_SERIES(par->chip))
resource = 0;
else
resource = 1;
- par->video.pbase = pci_resource_start (par->pcidev, resource);
+ par->video.pbase = pci_resource_start(par->pcidev, resource);
par->video.len = video_len;
- par->video.vbase = ioremap (par->video.pbase, par->video.len);
+ par->video.vbase = ioremap(par->video.pbase, par->video.len);
if (!par->video.vbase) {
- printk ("savagefb: unable to map screen memory\n");
+ printk("savagefb: unable to map screen memory\n");
return -ENOMEM;
} else
- printk (KERN_INFO "savagefb: mapped framebuffer at %p, "
- "pbase == %x\n", par->video.vbase, par->video.pbase);
+ printk(KERN_INFO "savagefb: mapped framebuffer at %p, "
+ "pbase == %x\n", par->video.vbase, par->video.pbase);
info->fix.smem_start = par->video.pbase;
info->fix.smem_len = par->video.len - par->cob_size;
info->screen_base = par->video.vbase;
#ifdef CONFIG_MTRR
- par->video.mtrr = mtrr_add (par->video.pbase, video_len,
- MTRR_TYPE_WRCOMB, 1);
+ par->video.mtrr = mtrr_add(par->video.pbase, video_len,
+ MTRR_TYPE_WRCOMB, 1);
#endif
/* Clear framebuffer, it's all white in memory after boot */
- memset_io (par->video.vbase, 0, par->video.len);
+ memset_io(par->video.vbase, 0, par->video.len);
return 0;
}
-static void savage_unmap_video (struct fb_info *info)
+static void savage_unmap_video(struct fb_info *info)
{
struct savagefb_par *par = info->par;
@@ -1605,16 +1776,16 @@ static void savage_unmap_video (struct fb_info *info)
if (par->video.vbase) {
#ifdef CONFIG_MTRR
- mtrr_del (par->video.mtrr, par->video.pbase, par->video.len);
+ mtrr_del(par->video.mtrr, par->video.pbase, par->video.len);
#endif
- iounmap (par->video.vbase);
+ iounmap(par->video.vbase);
par->video.vbase = NULL;
info->screen_base = NULL;
}
}
-static int savage_init_hw (struct savagefb_par *par)
+static int savage_init_hw(struct savagefb_par *par)
{
unsigned char config1, m, n, n1, n2, sr8, cr3f, cr66 = 0, tmp;
@@ -1656,7 +1827,7 @@ static int savage_init_hw (struct savagefb_par *par)
switch (par->chip) {
case S3_SAVAGE3D:
- videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
+ videoRam = RamSavage3D[(config1 & 0xC0) >> 6 ] * 1024;
break;
case S3_SAVAGE4:
@@ -1667,22 +1838,22 @@ static int savage_init_hw (struct savagefb_par *par)
* can do it different...
*/
vga_out8(0x3d4, 0x68, par); /* memory control 1 */
- if( (vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6) )
+ if ((vga_in8(0x3d5, par) & 0xC0) == (0x01 << 6))
RamSavage4[1] = 8;
/*FALLTHROUGH*/
case S3_SAVAGE2000:
- videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
+ videoRam = RamSavage4[(config1 & 0xE0) >> 5] * 1024;
break;
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
- videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
+ videoRam = RamSavageMX[(config1 & 0x0E) >> 1] * 1024;
break;
case S3_PROSAVAGE:
- videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
+ videoRam = RamSavageNB[(config1 & 0xE0) >> 5] * 1024;
break;
default:
@@ -1693,31 +1864,31 @@ static int savage_init_hw (struct savagefb_par *par)
videoRambytes = videoRam * 1024;
- printk (KERN_INFO "savagefb: probed videoram: %dk\n", videoRam);
+ printk(KERN_INFO "savagefb: probed videoram: %dk\n", videoRam);
/* reset graphics engine to avoid memory corruption */
- vga_out8 (0x3d4, 0x66, par);
- cr66 = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr66 | 0x02, par);
- udelay (10000);
+ vga_out8(0x3d4, 0x66, par);
+ cr66 = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr66 | 0x02, par);
+ udelay(10000);
- vga_out8 (0x3d4, 0x66, par);
- vga_out8 (0x3d5, cr66 & ~0x02, par); /* clear reset flag */
- udelay (10000);
+ vga_out8(0x3d4, 0x66, par);
+ vga_out8(0x3d5, cr66 & ~0x02, par); /* clear reset flag */
+ udelay(10000);
/*
* reset memory interface, 3D engine, AGP master, PCI master,
* master engine unit, motion compensation/LPB
*/
- vga_out8 (0x3d4, 0x3f, par);
- cr3f = vga_in8 (0x3d5, par);
- vga_out8 (0x3d5, cr3f | 0x08, par);
- udelay (10000);
+ vga_out8(0x3d4, 0x3f, par);
+ cr3f = vga_in8(0x3d5, par);
+ vga_out8(0x3d5, cr3f | 0x08, par);
+ udelay(10000);
- vga_out8 (0x3d4, 0x3f, par);
- vga_out8 (0x3d5, cr3f & ~0x08, par); /* clear reset flags */
- udelay (10000);
+ vga_out8(0x3d4, 0x3f, par);
+ vga_out8(0x3d5, cr3f & ~0x08, par); /* clear reset flags */
+ udelay(10000);
/* Savage ramdac speeds */
par->numClocks = 4;
@@ -1740,7 +1911,7 @@ static int savage_init_hw (struct savagefb_par *par)
n1 = n & 0x1f;
n2 = (n >> 5) & 0x03;
par->MCLK = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
- printk (KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
+ printk(KERN_INFO "savagefb: Detected current MCLK value of %d kHz\n",
par->MCLK);
/* check for DVI/flat panel */
@@ -1769,12 +1940,12 @@ static int savage_init_hw (struct savagefb_par *par)
/* Check LCD panel parrmation */
if (par->display_type == DISP_LCD) {
- unsigned char cr6b = VGArCR( 0x6b, par);
+ unsigned char cr6b = VGArCR(0x6b, par);
- int panelX = (VGArSEQ (0x61, par) +
- ((VGArSEQ (0x66, par) & 0x02) << 7) + 1) * 8;
- int panelY = (VGArSEQ (0x69, par) +
- ((VGArSEQ (0x6e, par) & 0x70) << 4) + 1);
+ int panelX = (VGArSEQ(0x61, par) +
+ ((VGArSEQ(0x66, par) & 0x02) << 7) + 1) * 8;
+ int panelY = (VGArSEQ(0x69, par) +
+ ((VGArSEQ(0x6e, par) & 0x70) << 4) + 1);
char * sTechnology = "Unknown";
@@ -1796,26 +1967,26 @@ static int savage_init_hw (struct savagefb_par *par)
ActiveDUO = 0x80
};
- if ((VGArSEQ (0x39, par) & 0x03) == 0) {
+ if ((VGArSEQ(0x39, par) & 0x03) == 0) {
sTechnology = "TFT";
- } else if ((VGArSEQ (0x30, par) & 0x01) == 0) {
+ } else if ((VGArSEQ(0x30, par) & 0x01) == 0) {
sTechnology = "DSTN";
} else {
sTechnology = "STN";
}
- printk (KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
- panelX, panelY, sTechnology,
- cr6b & ActiveLCD ? "and active" : "but not active");
+ printk(KERN_INFO "savagefb: %dx%d %s LCD panel detected %s\n",
+ panelX, panelY, sTechnology,
+ cr6b & ActiveLCD ? "and active" : "but not active");
- if( cr6b & ActiveLCD ) {
+ if (cr6b & ActiveLCD) {
/*
* If the LCD is active and panel expansion is enabled,
* we probably want to kill the HW cursor.
*/
- printk (KERN_INFO "savagefb: Limiting video mode to "
- "%dx%d\n", panelX, panelY );
+ printk(KERN_INFO "savagefb: Limiting video mode to "
+ "%dx%d\n", panelX, panelY);
par->SavagePanelWidth = panelX;
par->SavagePanelHeight = panelY;
@@ -1824,9 +1995,10 @@ static int savage_init_hw (struct savagefb_par *par)
par->display_type = DISP_CRT;
}
- savage_get_default_par (par);
+ savage_get_default_par(par, &par->state);
+ par->save = par->state;
- if( S3_SAVAGE4_SERIES(par->chip) ) {
+ if (S3_SAVAGE4_SERIES(par->chip)) {
/*
* The Savage4 and ProSavage have COB coherency bugs which
* render the buffer useless. We disable it.
@@ -1845,9 +2017,9 @@ static int savage_init_hw (struct savagefb_par *par)
return videoRambytes;
}
-static int __devinit savage_init_fb_info (struct fb_info *info,
- struct pci_dev *dev,
- const struct pci_device_id *id)
+static int __devinit savage_init_fb_info(struct fb_info *info,
+ struct pci_dev *dev,
+ const struct pci_device_id *id)
{
struct savagefb_par *par = info->par;
int err = 0;
@@ -1863,63 +2035,63 @@ static int __devinit savage_init_fb_info (struct fb_info *info,
switch (info->fix.accel) {
case FB_ACCEL_SUPERSAVAGE:
par->chip = S3_SUPERSAVAGE;
- snprintf (info->fix.id, 16, "SuperSavage");
+ snprintf(info->fix.id, 16, "SuperSavage");
break;
case FB_ACCEL_SAVAGE4:
par->chip = S3_SAVAGE4;
- snprintf (info->fix.id, 16, "Savage4");
+ snprintf(info->fix.id, 16, "Savage4");
break;
case FB_ACCEL_SAVAGE3D:
par->chip = S3_SAVAGE3D;
- snprintf (info->fix.id, 16, "Savage3D");
+ snprintf(info->fix.id, 16, "Savage3D");
break;
case FB_ACCEL_SAVAGE3D_MV:
par->chip = S3_SAVAGE3D;
- snprintf (info->fix.id, 16, "Savage3D-MV");
+ snprintf(info->fix.id, 16, "Savage3D-MV");
break;
case FB_ACCEL_SAVAGE2000:
par->chip = S3_SAVAGE2000;
- snprintf (info->fix.id, 16, "Savage2000");
+ snprintf(info->fix.id, 16, "Savage2000");
break;
case FB_ACCEL_SAVAGE_MX_MV:
par->chip = S3_SAVAGE_MX;
- snprintf (info->fix.id, 16, "Savage/MX-MV");
+ snprintf(info->fix.id, 16, "Savage/MX-MV");
break;
case FB_ACCEL_SAVAGE_MX:
par->chip = S3_SAVAGE_MX;
- snprintf (info->fix.id, 16, "Savage/MX");
+ snprintf(info->fix.id, 16, "Savage/MX");
break;
case FB_ACCEL_SAVAGE_IX_MV:
par->chip = S3_SAVAGE_MX;
- snprintf (info->fix.id, 16, "Savage/IX-MV");
+ snprintf(info->fix.id, 16, "Savage/IX-MV");
break;
case FB_ACCEL_SAVAGE_IX:
par->chip = S3_SAVAGE_MX;
- snprintf (info->fix.id, 16, "Savage/IX");
+ snprintf(info->fix.id, 16, "Savage/IX");
break;
case FB_ACCEL_PROSAVAGE_PM:
par->chip = S3_PROSAVAGE;
- snprintf (info->fix.id, 16, "ProSavagePM");
+ snprintf(info->fix.id, 16, "ProSavagePM");
break;
case FB_ACCEL_PROSAVAGE_KM:
par->chip = S3_PROSAVAGE;
- snprintf (info->fix.id, 16, "ProSavageKM");
+ snprintf(info->fix.id, 16, "ProSavageKM");
break;
case FB_ACCEL_S3TWISTER_P:
par->chip = S3_PROSAVAGE;
- snprintf (info->fix.id, 16, "TwisterP");
+ snprintf(info->fix.id, 16, "TwisterP");
break;
case FB_ACCEL_S3TWISTER_K:
par->chip = S3_PROSAVAGE;
- snprintf (info->fix.id, 16, "TwisterK");
+ snprintf(info->fix.id, 16, "TwisterK");
break;
case FB_ACCEL_PROSAVAGE_DDR:
par->chip = S3_PROSAVAGE;
- snprintf (info->fix.id, 16, "ProSavageDDR");
+ snprintf(info->fix.id, 16, "ProSavageDDR");
break;
case FB_ACCEL_PROSAVAGE_DDRK:
par->chip = S3_PROSAVAGE;
- snprintf (info->fix.id, 16, "ProSavage8");
+ snprintf(info->fix.id, 16, "ProSavage8");
break;
}
@@ -1960,7 +2132,7 @@ static int __devinit savage_init_fb_info (struct fb_info *info,
info->pixmap.buf_align = 4;
info->pixmap.access_align = 32;
- err = fb_alloc_cmap (&info->cmap, NR_PALETTE, 0);
+ err = fb_alloc_cmap(&info->cmap, NR_PALETTE, 0);
if (!err)
info->flags |= FBINFO_HWACCEL_COPYAREA |
FBINFO_HWACCEL_FILLRECT |
@@ -1972,8 +2144,8 @@ static int __devinit savage_init_fb_info (struct fb_info *info,
/* --------------------------------------------------------------------- */
-static int __devinit savagefb_probe (struct pci_dev* dev,
- const struct pci_device_id* id)
+static int __devinit savagefb_probe(struct pci_dev* dev,
+ const struct pci_device_id* id)
{
struct fb_info *info;
struct savagefb_par *par;
@@ -2085,12 +2257,12 @@ static int __devinit savagefb_probe (struct pci_dev* dev,
fb_destroy_modedb(info->monspecs.modedb);
info->monspecs.modedb = NULL;
- err = register_framebuffer (info);
+ err = register_framebuffer(info);
if (err < 0)
goto failed;
- printk (KERN_INFO "fb: S3 %s frame buffer device\n",
- info->fix.id);
+ printk(KERN_INFO "fb: S3 %s frame buffer device\n",
+ info->fix.id);
/*
* Our driver data
@@ -2103,10 +2275,10 @@ static int __devinit savagefb_probe (struct pci_dev* dev,
#ifdef CONFIG_FB_SAVAGE_I2C
savagefb_delete_i2c_busses(info);
#endif
- fb_alloc_cmap (&info->cmap, 0, 0);
+ fb_alloc_cmap(&info->cmap, 0, 0);
savage_unmap_video(info);
failed_video:
- savage_unmap_mmio (info);
+ savage_unmap_mmio(info);
failed_mmio:
kfree(info->pixmap.addr);
failed_init:
@@ -2117,7 +2289,7 @@ static int __devinit savagefb_probe (struct pci_dev* dev,
return err;
}
-static void __devexit savagefb_remove (struct pci_dev *dev)
+static void __devexit savagefb_remove(struct pci_dev *dev)
{
struct fb_info *info = pci_get_drvdata(dev);
@@ -2129,16 +2301,16 @@ static void __devexit savagefb_remove (struct pci_dev *dev)
* we will be leaving hooks that could cause
* oopsen laying around.
*/
- if (unregister_framebuffer (info))
- printk (KERN_WARNING "savagefb: danger danger! "
- "Oopsen imminent!\n");
+ if (unregister_framebuffer(info))
+ printk(KERN_WARNING "savagefb: danger danger! "
+ "Oopsen imminent!\n");
#ifdef CONFIG_FB_SAVAGE_I2C
savagefb_delete_i2c_busses(info);
#endif
- fb_alloc_cmap (&info->cmap, 0, 0);
- savage_unmap_video (info);
- savage_unmap_mmio (info);
+ fb_alloc_cmap(&info->cmap, 0, 0);
+ savage_unmap_video(info);
+ savage_unmap_mmio(info);
kfree(info->pixmap.addr);
pci_release_regions(dev);
framebuffer_release(info);
@@ -2151,24 +2323,24 @@ static void __devexit savagefb_remove (struct pci_dev *dev)
}
}
-static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
+static int savagefb_suspend(struct pci_dev *dev, pm_message_t mesg)
{
struct fb_info *info = pci_get_drvdata(dev);
struct savagefb_par *par = info->par;
DBG("savagefb_suspend");
-
- par->pm_state = state.event;
+ if (mesg.event == PM_EVENT_PRETHAW)
+ mesg.event = PM_EVENT_FREEZE;
+ par->pm_state = mesg.event;
+ dev->dev.power.power_state = mesg;
/*
* For PM_EVENT_FREEZE, do not power down so the console
* can remain active.
*/
- if (state.event == PM_EVENT_FREEZE) {
- dev->dev.power.power_state = state;
+ if (mesg.event == PM_EVENT_FREEZE)
return 0;
- }
acquire_console_sem();
fb_set_suspend(info, 1);
@@ -2177,16 +2349,17 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
info->fbops->fb_sync(info);
savagefb_blank(FB_BLANK_POWERDOWN, info);
+ savage_set_default_par(par, &par->save);
savage_disable_mmio(par);
pci_save_state(dev);
pci_disable_device(dev);
- pci_set_power_state(dev, pci_choose_state(dev, state));
+ pci_set_power_state(dev, pci_choose_state(dev, mesg));
release_console_sem();
return 0;
}
-static int savagefb_resume (struct pci_dev* dev)
+static int savagefb_resume(struct pci_dev* dev)
{
struct fb_info *info = pci_get_drvdata(dev);
struct savagefb_par *par = info->par;
@@ -2210,15 +2383,15 @@ static int savagefb_resume (struct pci_dev* dev)
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- if(pci_enable_device(dev))
+ if (pci_enable_device(dev))
DBG("err");
pci_set_master(dev);
savage_enable_mmio(par);
savage_init_hw(par);
- savagefb_set_par (info);
+ savagefb_set_par(info);
+ fb_set_suspend(info, 0);
savagefb_blank(FB_BLANK_UNBLANK, info);
- fb_set_suspend (info, 0);
release_console_sem();
return 0;
@@ -2311,10 +2484,10 @@ static struct pci_driver savagefb_driver = {
/* **************************** exit-time only **************************** */
-static void __exit savage_done (void)
+static void __exit savage_done(void)
{
DBG("savage_done");
- pci_unregister_driver (&savagefb_driver);
+ pci_unregister_driver(&savagefb_driver);
}
@@ -2345,7 +2518,7 @@ static int __init savagefb_init(void)
return -ENODEV;
savagefb_setup(option);
- return pci_register_driver (&savagefb_driver);
+ return pci_register_driver(&savagefb_driver);
}
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index 2e6df1fcb2b..ebb6756aea0 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -9,7 +9,6 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -23,6 +22,8 @@
#include <asm/io.h>
#include <asm/mtrr.h>
+#include <setup_arch.h>
+
#define INCLUDE_TIMING_TABLE_DATA
#define DBE_REG_BASE par->regs
#include <video/sgivw.h>
@@ -42,10 +43,6 @@ struct sgivw_par {
* The default can be overridden if the driver is compiled as a module
*/
-/* set by arch/i386/kernel/setup.c */
-extern unsigned long sgivwfb_mem_phys;
-extern unsigned long sgivwfb_mem_size;
-
static int ypan = 0;
static int ywrap = 0;
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
index 634c0a9d219..7ecab87cef0 100644
--- a/drivers/video/sis/init.h
+++ b/drivers/video/sis/init.h
@@ -73,7 +73,6 @@
#ifdef SIS_CP
#undef SIS_CP
#endif
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/types.h>
#include <asm/io.h>
diff --git a/drivers/video/sis/init301.c b/drivers/video/sis/init301.c
index c3e070a6eff..f13faddc618 100644
--- a/drivers/video/sis/init301.c
+++ b/drivers/video/sis/init301.c
@@ -8043,8 +8043,8 @@ SiS_SetCHTVReg(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short
SiS_SetCH700x(SiS_Pr,0x01,0x28);
/* Set video bandwidth
- High bandwith Luma composite video filter(S0=1)
- low bandwith Luma S-video filter (S2-1=00)
+ High bandwidth Luma composite video filter(S0=1)
+ low bandwidth Luma S-video filter (S2-1=00)
disable peak filter in S-video channel (S3=0)
high bandwidth Chroma Filter (S5-4=11)
=00110001=0x31
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
index f475b21a85c..bc321dc57e9 100644
--- a/drivers/video/sis/init301.h
+++ b/drivers/video/sis/init301.h
@@ -67,7 +67,6 @@
#ifdef SIS_CP
#undef SIS_CP
#endif
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/types.h>
#include <asm/io.h>
diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
index cc856d90903..09f5d758b6c 100644
--- a/drivers/video/sis/initextlfb.c
+++ b/drivers/video/sis/initextlfb.c
@@ -30,7 +30,6 @@
#include "vgatypes.h"
#include "vstruct.h"
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/fb.h>
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
index 841ca3190cd..f59568020eb 100644
--- a/drivers/video/sis/osdef.h
+++ b/drivers/video/sis/osdef.h
@@ -90,7 +90,6 @@
/**********************************************************************/
#ifdef SIS_LINUX_KERNEL
-#include <linux/config.h>
#include <linux/version.h>
#ifdef CONFIG_FB_SIS_300
diff --git a/drivers/video/sis/sis.h b/drivers/video/sis/sis.h
index 0b6e625d733..a259446ca7f 100644
--- a/drivers/video/sis/sis.h
+++ b/drivers/video/sis/sis.h
@@ -24,7 +24,6 @@
#ifndef _SIS_H_
#define _SIS_H_
-#include <linux/config.h>
#include <linux/version.h>
#include "osdef.h"
diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c
index bab933e6c6a..3b7ce032e2e 100644
--- a/drivers/video/sis/sis_accel.c
+++ b/drivers/video/sis/sis_accel.c
@@ -28,7 +28,6 @@
* for more information and updates)
*/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 8adf5bf91ee..895ebda7d9e 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -33,7 +33,6 @@
*
*/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
@@ -45,7 +44,13 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
#include <linux/tty.h>
+#else
+#include <linux/screen_info.h>
+#endif
+
#include <linux/slab.h>
#include <linux/fb.h>
#include <linux/selection.h>
@@ -275,7 +280,7 @@ sisfb_search_mode(char *name, BOOLEAN quiet)
static void __devinit
sisfb_get_vga_mode_from_kernel(void)
{
-#if (defined(__i386__) || defined(__x86_64__)) && defined(CONFIG_VIDEO_SELECT)
+#ifdef CONFIG_X86
char mymode[32];
int mydepth = screen_info.lfb_depth;
diff --git a/drivers/video/skeletonfb.c b/drivers/video/skeletonfb.c
index 9b707771d75..bb96cb65fda 100644
--- a/drivers/video/skeletonfb.c
+++ b/drivers/video/skeletonfb.c
@@ -47,7 +47,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
@@ -906,11 +905,6 @@ static void __exit xxxfb_exit(void)
}
#endif
-MODULE_LICENSE("GPL");
-module_init(xxxfb_init);
-module_exit(xxxfb_exit);
-
-
/*
* Setup
*/
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index c44de90ca12..dad54e73147 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -82,7 +82,6 @@
* Includes
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 4a292aae6eb..3e16e2d9d55 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -54,7 +54,6 @@
#undef DEBUG_STIFB_REGS /* debug sti register accesses */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/video/sun3fb.c b/drivers/video/sun3fb.c
index 9b36b9df535..f80356dfa8e 100644
--- a/drivers/video/sun3fb.c
+++ b/drivers/video/sun3fb.c
@@ -25,13 +25,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index 95b918229d9..6990ab11cd0 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -1,6 +1,6 @@
/* tcx.c: TCX frame buffer driver
*
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
* Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
@@ -19,8 +19,8 @@
#include <linux/mm.h>
#include <asm/io.h>
-#include <asm/sbus.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
#include <asm/fbio.h>
#include "sbuslib.h"
@@ -77,32 +77,32 @@ static struct fb_ops tcx_ops = {
/* The contents are unknown */
struct tcx_tec {
- volatile u32 tec_matrix;
- volatile u32 tec_clip;
- volatile u32 tec_vdc;
+ u32 tec_matrix;
+ u32 tec_clip;
+ u32 tec_vdc;
};
struct tcx_thc {
- volatile u32 thc_rev;
+ u32 thc_rev;
u32 thc_pad0[511];
- volatile u32 thc_hs; /* hsync timing */
- volatile u32 thc_hsdvs;
- volatile u32 thc_hd;
- volatile u32 thc_vs; /* vsync timing */
- volatile u32 thc_vd;
- volatile u32 thc_refresh;
- volatile u32 thc_misc;
+ u32 thc_hs; /* hsync timing */
+ u32 thc_hsdvs;
+ u32 thc_hd;
+ u32 thc_vs; /* vsync timing */
+ u32 thc_vd;
+ u32 thc_refresh;
+ u32 thc_misc;
u32 thc_pad1[56];
- volatile u32 thc_cursxy; /* cursor x,y position (16 bits each) */
- volatile u32 thc_cursmask[32]; /* cursor mask bits */
- volatile u32 thc_cursbits[32]; /* what to show where mask enabled */
+ u32 thc_cursxy; /* cursor x,y position (16 bits each) */
+ u32 thc_cursmask[32]; /* cursor mask bits */
+ u32 thc_cursbits[32]; /* what to show where mask enabled */
};
struct bt_regs {
- volatile u32 addr;
- volatile u32 color_map;
- volatile u32 control;
- volatile u32 cursor;
+ u32 addr;
+ u32 color_map;
+ u32 control;
+ u32 cursor;
};
#define TCX_MMAP_ENTRIES 14
@@ -112,24 +112,23 @@ struct tcx_par {
struct bt_regs __iomem *bt;
struct tcx_thc __iomem *thc;
struct tcx_tec __iomem *tec;
- volatile u32 __iomem *cplane;
+ u32 __iomem *cplane;
u32 flags;
#define TCX_FLAG_BLANKED 0x00000001
unsigned long physbase;
+ unsigned long which_io;
unsigned long fbsize;
struct sbus_mmap_map mmap_map[TCX_MMAP_ENTRIES];
int lowdepth;
-
- struct sbus_dev *sdev;
};
/* Reset control plane so that WID is 8-bit plane. */
static void __tcx_set_control_plane (struct tcx_par *par)
{
- volatile u32 __iomem *p, *pend;
+ u32 __iomem *p, *pend;
if (par->lowdepth)
return;
@@ -307,8 +306,7 @@ static int tcx_mmap(struct fb_info *info, struct vm_area_struct *vma)
return sbusfb_mmap_helper(par->mmap_map,
par->physbase, par->fbsize,
- par->sdev->reg_addrs[0].which_io,
- vma);
+ par->which_io, vma);
}
static int tcx_ioctl(struct fb_info *info, unsigned int cmd,
@@ -350,48 +348,71 @@ tcx_init_fix(struct fb_info *info, int linebytes)
struct all_info {
struct fb_info info;
struct tcx_par par;
- struct list_head list;
};
-static LIST_HEAD(tcx_list);
-static void tcx_init_one(struct sbus_dev *sdev)
+static void tcx_unmap_regs(struct all_info *all)
{
- struct all_info *all;
- int linebytes, i;
+ if (all->par.tec)
+ of_iounmap(all->par.tec, sizeof(struct tcx_tec));
+ if (all->par.thc)
+ of_iounmap(all->par.thc, sizeof(struct tcx_thc));
+ if (all->par.bt)
+ of_iounmap(all->par.bt, sizeof(struct bt_regs));
+ if (all->par.cplane)
+ of_iounmap(all->par.cplane, all->par.fbsize * sizeof(u32));
+ if (all->info.screen_base)
+ of_iounmap(all->info.screen_base, all->par.fbsize);
+}
- all = kmalloc(sizeof(*all), GFP_KERNEL);
- if (!all) {
- printk(KERN_ERR "tcx: Cannot allocate memory.\n");
- return;
- }
- memset(all, 0, sizeof(*all));
+static int __devinit tcx_init_one(struct of_device *op)
+{
+ struct device_node *dp = op->node;
+ struct all_info *all;
+ int linebytes, i, err;
- INIT_LIST_HEAD(&all->list);
+ all = kzalloc(sizeof(*all), GFP_KERNEL);
+ if (!all)
+ return -ENOMEM;
spin_lock_init(&all->par.lock);
- all->par.sdev = sdev;
- all->par.lowdepth = prom_getbool(sdev->prom_node, "tcx-8-bit");
+ all->par.lowdepth =
+ (of_find_property(dp, "tcx-8-bit", NULL) != NULL);
- sbusfb_fill_var(&all->info.var, sdev->prom_node, 8);
+ sbusfb_fill_var(&all->info.var, dp->node, 8);
all->info.var.red.length = 8;
all->info.var.green.length = 8;
all->info.var.blue.length = 8;
- linebytes = prom_getintdefault(sdev->prom_node, "linebytes",
- all->info.var.xres);
+ linebytes = of_getintprop_default(dp, "linebytes",
+ all->info.var.xres);
all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres);
- all->par.tec = sbus_ioremap(&sdev->resource[7], 0,
- sizeof(struct tcx_tec), "tcx tec");
- all->par.thc = sbus_ioremap(&sdev->resource[9], 0,
- sizeof(struct tcx_thc), "tcx thc");
- all->par.bt = sbus_ioremap(&sdev->resource[8], 0,
- sizeof(struct bt_regs), "tcx dac");
+ all->par.tec = of_ioremap(&op->resource[7], 0,
+ sizeof(struct tcx_tec), "tcx tec");
+ all->par.thc = of_ioremap(&op->resource[9], 0,
+ sizeof(struct tcx_thc), "tcx thc");
+ all->par.bt = of_ioremap(&op->resource[8], 0,
+ sizeof(struct bt_regs), "tcx dac");
+ all->info.screen_base = of_ioremap(&op->resource[0], 0,
+ all->par.fbsize, "tcx ram");
+ if (!all->par.tec || !all->par.thc ||
+ !all->par.bt || !all->info.screen_base) {
+ tcx_unmap_regs(all);
+ kfree(all);
+ return -ENOMEM;
+ }
+
memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map));
if (!all->par.lowdepth) {
- all->par.cplane = sbus_ioremap(&sdev->resource[4], 0,
- all->par.fbsize * sizeof(u32), "tcx cplane");
+ all->par.cplane = of_ioremap(&op->resource[4], 0,
+ all->par.fbsize * sizeof(u32),
+ "tcx cplane");
+ if (!all->par.cplane) {
+ tcx_unmap_regs(all);
+ kfree(all);
+ return -ENOMEM;
+ }
} else {
all->par.mmap_map[1].size = SBUS_MMAP_EMPTY;
all->par.mmap_map[4].size = SBUS_MMAP_EMPTY;
@@ -400,6 +421,8 @@ static void tcx_init_one(struct sbus_dev *sdev)
}
all->par.physbase = 0;
+ all->par.which_io = op->resource[0].flags & IORESOURCE_BITS;
+
for (i = 0; i < TCX_MMAP_ENTRIES; i++) {
int j;
@@ -416,18 +439,11 @@ static void tcx_init_one(struct sbus_dev *sdev)
j = i;
break;
};
- all->par.mmap_map[i].poff = sdev->reg_addrs[j].phys_addr;
+ all->par.mmap_map[i].poff = op->resource[j].start;
}
all->info.flags = FBINFO_DEFAULT;
all->info.fbops = &tcx_ops;
-#ifdef CONFIG_SPARC32
- all->info.screen_base = (char __iomem *)
- prom_getintdefault(sdev->prom_node, "address", 0);
-#endif
- if (!all->info.screen_base)
- all->info.screen_base = sbus_ioremap(&sdev->resource[0], 0,
- all->par.fbsize, "tcx ram");
all->info.par = &all->par;
/* Initialize brooktree DAC. */
@@ -445,72 +461,88 @@ static void tcx_init_one(struct sbus_dev *sdev)
tcx_blank(FB_BLANK_UNBLANK, &all->info);
if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
- printk(KERN_ERR "tcx: Could not allocate color map.\n");
+ tcx_unmap_regs(all);
kfree(all);
- return;
+ return -ENOMEM;
}
fb_set_cmap(&all->info.cmap, &all->info);
tcx_init_fix(&all->info, linebytes);
- if (register_framebuffer(&all->info) < 0) {
- printk(KERN_ERR "tcx: Could not register framebuffer.\n");
+ err = register_framebuffer(&all->info);
+ if (err < 0) {
fb_dealloc_cmap(&all->info.cmap);
+ tcx_unmap_regs(all);
kfree(all);
- return;
+ return err;
}
- list_add(&all->list, &tcx_list);
+ dev_set_drvdata(&op->dev, all);
- printk("tcx: %s at %lx:%lx, %s\n",
- sdev->prom_name,
- (long) sdev->reg_addrs[0].which_io,
- (long) sdev->reg_addrs[0].phys_addr,
+ printk("%s: TCX at %lx:%lx, %s\n",
+ dp->full_name,
+ all->par.which_io,
+ op->resource[0].start,
all->par.lowdepth ? "8-bit only" : "24-bit depth");
+
+ return 0;
}
-int __init tcx_init(void)
+static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match)
{
- struct sbus_bus *sbus;
- struct sbus_dev *sdev;
+ struct of_device *op = to_of_device(&dev->dev);
- if (fb_get_options("tcxfb", NULL))
- return -ENODEV;
+ return tcx_init_one(op);
+}
- for_all_sbusdev(sdev, sbus) {
- if (!strcmp(sdev->prom_name, "SUNW,tcx"))
- tcx_init_one(sdev);
- }
+static int __devexit tcx_remove(struct of_device *dev)
+{
+ struct all_info *all = dev_get_drvdata(&dev->dev);
+
+ unregister_framebuffer(&all->info);
+ fb_dealloc_cmap(&all->info.cmap);
+
+ tcx_unmap_regs(all);
+
+ kfree(all);
+
+ dev_set_drvdata(&dev->dev, NULL);
return 0;
}
-void __exit tcx_exit(void)
-{
- struct list_head *pos, *tmp;
+static struct of_device_id tcx_match[] = {
+ {
+ .name = "SUNW,tcx",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tcx_match);
- list_for_each_safe(pos, tmp, &tcx_list) {
- struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver tcx_driver = {
+ .name = "tcx",
+ .match_table = tcx_match,
+ .probe = tcx_probe,
+ .remove = __devexit_p(tcx_remove),
+};
- unregister_framebuffer(&all->info);
- fb_dealloc_cmap(&all->info.cmap);
- kfree(all);
- }
+int __init tcx_init(void)
+{
+ if (fb_get_options("tcxfb", NULL))
+ return -ENODEV;
+
+ return of_register_driver(&tcx_driver, &of_bus_type);
}
-int __init
-tcx_setup(char *arg)
+void __exit tcx_exit(void)
{
- /* No cmdline options yet... */
- return 0;
+ of_unregister_driver(&tcx_driver);
}
module_init(tcx_init);
-
-#ifdef MODULE
module_exit(tcx_exit);
-#endif
MODULE_DESCRIPTION("framebuffer driver for TCX chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 5e5328d682d..689ce0270b8 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -58,13 +58,11 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 7398bd48ba6..94fde625a6c 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -17,7 +17,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -26,7 +25,6 @@
#include <linux/selection.h>
#include <asm/io.h>
#include <video/tgafb.h>
-#include <linux/selection.h>
/*
* Local functions.
diff --git a/drivers/video/tridentfb.c b/drivers/video/tridentfb.c
index 9ac2d317118..14175cdb9c9 100644
--- a/drivers/video/tridentfb.c
+++ b/drivers/video/tridentfb.c
@@ -15,7 +15,6 @@
* TGUI acceleration
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/fb.h>
#include <linux/init.h>
@@ -551,7 +550,7 @@ static inline void enable_mmio(void)
#define crtc_unlock() write3X4(CRTVSyncEnd, read3X4(CRTVSyncEnd) & 0x7F)
/* Return flat panel's maximum x resolution */
-static int __init get_nativex(void)
+static int __devinit get_nativex(void)
{
int x,y,tmp;
@@ -658,7 +657,7 @@ static void set_number_of_lines(int lines)
* If we see that FP is active we assume we have one.
* Otherwise we have a CRT display.User can override.
*/
-static unsigned int __init get_displaytype(void)
+static unsigned int __devinit get_displaytype(void)
{
if (fp)
return DISPLAY_FP;
@@ -668,7 +667,7 @@ static unsigned int __init get_displaytype(void)
}
/* Try detecting the video memory size */
-static unsigned int __init get_memsize(void)
+static unsigned int __devinit get_memsize(void)
{
unsigned char tmp, tmp2;
unsigned int k;
diff --git a/drivers/video/tx3912fb.c b/drivers/video/tx3912fb.c
index d904da44e1a..07389ba01ef 100644
--- a/drivers/video/tx3912fb.c
+++ b/drivers/video/tx3912fb.c
@@ -14,7 +14,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/init.h>
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 2bdeb4baa95..47f27924a7d 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -39,13 +39,11 @@
* more details.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index b0b9acfdd43..2196448396e 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -13,13 +13,13 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/screen_info.h>
#include <video/vga.h>
#include <asm/io.h>
@@ -51,7 +51,7 @@ static int inverse = 0;
static int mtrr = 0; /* disable mtrr */
static int vram_remap __initdata = 0; /* Set amount of memory to be used */
static int vram_total __initdata = 0; /* Set total amount of memory */
-static int pmi_setpal = 0; /* pmi for palette changes ??? */
+static int pmi_setpal = 1; /* pmi for palette changes ??? */
static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */
static unsigned short *pmi_base = NULL;
static void (*pmi_start)(void);
@@ -80,15 +80,30 @@ static int vesafb_pan_display(struct fb_var_screeninfo *var,
return 0;
}
-static void vesa_setpalette(int regno, unsigned red, unsigned green,
+static int vesa_setpalette(int regno, unsigned red, unsigned green,
unsigned blue)
{
int shift = 16 - depth;
+ int err = -EINVAL;
+
+/*
+ * Try VGA registers first...
+ */
+ if (vga_compat) {
+ outb_p(regno, dac_reg);
+ outb_p(red >> shift, dac_val);
+ outb_p(green >> shift, dac_val);
+ outb_p(blue >> shift, dac_val);
+ err = 0;
+ }
#ifdef __i386__
- struct { u_char blue, green, red, pad; } entry;
+/*
+ * Fallback to the PMI....
+ */
+ if (err && pmi_setpal) {
+ struct { u_char blue, green, red, pad; } entry;
- if (pmi_setpal) {
entry.red = red >> shift;
entry.green = green >> shift;
entry.blue = blue >> shift;
@@ -102,26 +117,19 @@ static void vesa_setpalette(int regno, unsigned red, unsigned green,
"d" (regno), /* EDX */
"D" (&entry), /* EDI */
"S" (&pmi_pal)); /* ESI */
- return;
+ err = 0;
}
#endif
-/*
- * without protected mode interface and if VGA compatible,
- * try VGA registers...
- */
- if (vga_compat) {
- outb_p(regno, dac_reg);
- outb_p(red >> shift, dac_val);
- outb_p(green >> shift, dac_val);
- outb_p(blue >> shift, dac_val);
- }
+ return err;
}
static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
{
+ int err = 0;
+
/*
* Set a single color register. The values supplied are
* already rounded down to the hardware's capabilities
@@ -133,7 +141,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 1;
if (info->var.bits_per_pixel == 8)
- vesa_setpalette(regno,red,green,blue);
+ err = vesa_setpalette(regno,red,green,blue);
else if (regno < 16) {
switch (info->var.bits_per_pixel) {
case 16:
@@ -164,7 +172,7 @@ static int vesafb_setcolreg(unsigned regno, unsigned red, unsigned green,
}
}
- return 0;
+ return err;
}
static struct fb_ops vesafb_ops = {
@@ -460,9 +468,7 @@ static struct platform_driver vesafb_driver = {
},
};
-static struct platform_device vesafb_device = {
- .name = "vesafb",
-};
+static struct platform_device *vesafb_device;
static int __init vesafb_init(void)
{
@@ -475,10 +481,19 @@ static int __init vesafb_init(void)
ret = platform_driver_register(&vesafb_driver);
if (!ret) {
- ret = platform_device_register(&vesafb_device);
- if (ret)
+ vesafb_device = platform_device_alloc("vesafb", 0);
+
+ if (vesafb_device)
+ ret = platform_device_add(vesafb_device);
+ else
+ ret = -ENOMEM;
+
+ if (ret) {
+ platform_device_put(vesafb_device);
platform_driver_unregister(&vesafb_driver);
+ }
}
+
return ret;
}
module_init(vesafb_init);
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 77eed1fd994..a9b99b01bd8 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
@@ -398,12 +397,6 @@ static int __init vfb_setup(char *options)
* Initialisation
*/
-static void vfb_platform_release(struct device *device)
-{
- // This is called when the reference count goes to zero.
- dev_err(device, "This driver is broken, please bug the authors so they will fix it.\n");
-}
-
static int __init vfb_probe(struct platform_device *dev)
{
struct fb_info *info;
@@ -482,13 +475,7 @@ static struct platform_driver vfb_driver = {
},
};
-static struct platform_device vfb_device = {
- .name = "vfb",
- .id = 0,
- .dev = {
- .release = vfb_platform_release,
- }
-};
+static struct platform_device *vfb_device;
static int __init vfb_init(void)
{
@@ -508,10 +495,19 @@ static int __init vfb_init(void)
ret = platform_driver_register(&vfb_driver);
if (!ret) {
- ret = platform_device_register(&vfb_device);
- if (ret)
+ vfb_device = platform_device_alloc("vfb", 0);
+
+ if (vfb_device)
+ ret = platform_device_add(vfb_device);
+ else
+ ret = -ENOMEM;
+
+ if (ret) {
+ platform_device_put(vfb_device);
platform_driver_unregister(&vfb_driver);
+ }
}
+
return ret;
}
@@ -520,7 +516,7 @@ module_init(vfb_init);
#ifdef MODULE
static void __exit vfb_exit(void)
{
- platform_device_unregister(&vfb_device);
+ platform_device_unregister(vfb_device);
platform_driver_unregister(&vfb_driver);
}
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 4fd2a272e03..43d5a6d9c4a 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -15,13 +15,13 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/fb.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/screen_info.h>
#include <asm/io.h>
#include <video/vga.h>
@@ -1334,9 +1334,8 @@ static int vga16fb_setup(char *options)
}
#endif
-static int __init vga16fb_probe(struct device *device)
+static int __init vga16fb_probe(struct platform_device *dev)
{
- struct platform_device *dev = to_platform_device(device);
struct fb_info *info;
struct vga16fb_par *par;
int i;
@@ -1403,7 +1402,7 @@ static int __init vga16fb_probe(struct device *device)
printk(KERN_INFO "fb%d: %s frame buffer device\n",
info->node, info->fix.id);
- dev_set_drvdata(device, info);
+ platform_set_drvdata(dev, info);
return 0;
@@ -1417,9 +1416,9 @@ static int __init vga16fb_probe(struct device *device)
return ret;
}
-static int vga16fb_remove(struct device *device)
+static int vga16fb_remove(struct platform_device *dev)
{
- struct fb_info *info = dev_get_drvdata(device);
+ struct fb_info *info = platform_get_drvdata(dev);
if (info) {
unregister_framebuffer(info);
@@ -1432,16 +1431,15 @@ static int vga16fb_remove(struct device *device)
return 0;
}
-static struct device_driver vga16fb_driver = {
- .name = "vga16fb",
- .bus = &platform_bus_type,
+static struct platform_driver vga16fb_driver = {
.probe = vga16fb_probe,
.remove = vga16fb_remove,
+ .driver = {
+ .name = "vga16fb",
+ },
};
-static struct platform_device vga16fb_device = {
- .name = "vga16fb",
-};
+static struct platform_device *vga16fb_device;
static int __init vga16fb_init(void)
{
@@ -1454,12 +1452,20 @@ static int __init vga16fb_init(void)
vga16fb_setup(option);
#endif
- ret = driver_register(&vga16fb_driver);
+ ret = platform_driver_register(&vga16fb_driver);
if (!ret) {
- ret = platform_device_register(&vga16fb_device);
- if (ret)
- driver_unregister(&vga16fb_driver);
+ vga16fb_device = platform_device_alloc("vga16fb", 0);
+
+ if (vga16fb_device)
+ ret = platform_device_add(vga16fb_device);
+ else
+ ret = -ENOMEM;
+
+ if (ret) {
+ platform_device_put(vga16fb_device);
+ platform_driver_unregister(&vga16fb_driver);
+ }
}
return ret;
@@ -1467,8 +1473,8 @@ static int __init vga16fb_init(void)
static void __exit vga16fb_exit(void)
{
- platform_device_unregister(&vga16fb_device);
- driver_unregister(&vga16fb_driver);
+ platform_device_unregister(vga16fb_device);
+ platform_driver_unregister(&vga16fb_driver);
}
MODULE_LICENSE("GPL");
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index 15179ec6233..d94efafc77b 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -13,7 +13,6 @@
* archive for more details.
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/fb.h>
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index 5ea2345dab9..64378959dd7 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -39,7 +39,6 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/zorro.h>
diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c
index af492cc48db..d93eb626b2f 100644
--- a/drivers/w1/masters/ds2482.c
+++ b/drivers/w1/masters/ds2482.c
@@ -218,7 +218,7 @@ static int ds2482_wait_1wire_idle(struct ds2482_data *pdev)
do {
temp = i2c_smbus_read_byte(&pdev->client);
} while ((temp >= 0) && (temp & DS2482_REG_STS_1WB) &&
- (++retries > DS2482_WAIT_IDLE_TIMEOUT));
+ (++retries < DS2482_WAIT_IDLE_TIMEOUT));
}
if (retries > DS2482_WAIT_IDLE_TIMEOUT)
diff --git a/drivers/zorro/names.c b/drivers/zorro/names.c
index 0dd532d3a5d..e8517c3d8e8 100644
--- a/drivers/zorro/names.c
+++ b/drivers/zorro/names.c
@@ -9,7 +9,6 @@
* David Mosberger-Tang, Martin Mares
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>